[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2.1\norbs:\n  win: circleci/windows@5.0.0\n  aws-cli: circleci/aws-cli@3.1.1\n\nexecutors:\n  telegraf-ci:\n    working_directory: '/go/src/github.com/influxdata/telegraf'\n    resource_class: large\n    docker:\n      - image: 'quay.io/influxdb/telegraf-ci:1.25.7'\n    environment:\n      GOFLAGS: -p=4\n  mac:\n    working_directory: '~/go/src/github.com/influxdata/telegraf'\n    resource_class: m4pro.medium\n    macos:\n      xcode: 15.4.0\n    environment:\n      HOMEBREW_NO_AUTO_UPDATE: 1\n      GOFLAGS: -p=4\n\ncommands:\n  check-changed-files-or-halt:\n    steps:\n      - run: ./scripts/check-file-changes.sh\n  test-go:\n    parameters:\n      os:\n        type: string\n        default: \"linux\"\n      arch:\n        type: string\n        default: \"amd64\"\n      gotestsum:\n        type: string\n        default: \"gotestsum\"\n    steps:\n      - run: ./scripts/install_gotestsum.sh << parameters.os >> << parameters.gotestsum >>\n      - unless:\n          condition:\n            equal: [ \"386\", << parameters.arch >> ]\n          steps:\n      # Disable -race on Windows due to issues with CGO in the test-go-windows CI job.\n      # See https://github.com/influxdata/telegraf/pull/17789\n      #      - run: echo 'export RACE=\"-race\"' >> $BASH_ENV\n            - unless:\n                condition:\n                  equal: [ windows, << parameters.os >> ]\n                steps:\n                  - run: echo 'export RACE=\"-race\"' >> $BASH_ENV\n\n      # Disable CGO on Windows for the same reason as above.\n      #- when:\n      #    condition:\n      #      equal: [ windows, << parameters.os >> ]\n      #    steps:\n      #      - run: echo 'export CGO_ENABLED=1' >> $BASH_ENV\n      - when:\n          condition:\n            equal: [ darwin, << parameters.os >> ]\n          steps:\n            - run: echo 'export RACE=\"$RACE -ldflags=-extldflags=-Wl,-ld_classic\"' >> $BASH_ENV\n      - run: |\n          GOARCH=<< parameters.arch >> ./<< parameters.gotestsum >> -- ${RACE} -short \"$(./scripts/check-plugin-changes.sh)\"\n  package-build:\n    parameters:\n      type:\n        type: string\n        default: \"\"\n      nightly:\n        type: boolean\n        default: false\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - attach_workspace:\n          at: '/go'\n      - when:\n          condition:\n            equal: [ windows, << parameters.type >> ]\n          steps:\n            - run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0\n      - when:\n          condition: << parameters.nightly >>\n          steps:\n            - run:\n                command: 'NIGHTLY=1 make package include_packages=\"$(make << parameters.type >>)\"'\n                no_output_timeout: 30m\n      - unless:\n          condition:\n            or:\n              - << parameters.nightly >>\n          steps:\n            - run:\n                command: 'make package include_packages=\"$(make << parameters.type >>)\"'\n                no_output_timeout: 30m\n      - store_artifacts:\n          path: './build/dist'\n          destination: 'build/dist'\n      - persist_to_workspace:\n          root: './build'\n          paths:\n            - 'dist'\njobs:\n  lint-linux:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - run: ./scripts/make_docs.sh\n      - check-changed-files-or-halt\n      - run: 'make deps'\n      - run: 'make tidy'\n      - run: 'make check'\n      - run: 'make check-deps'\n      - run:\n          name: \"Install golangci-lint\"\n          command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2\n      - run:\n          name: \"golangci-lint/Linux\"\n          # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number\n          # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest).\n          command: GOGC=80 GOMEMLIMIT=6144MiB /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4\n          no_output_timeout: 30m\n  lint-macos:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run:\n          name: \"Install golangci-lint\"\n          command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2\n      - run:\n          name: \"golangci-lint/macOS\"\n          # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number\n          # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest).\n          command: GOGC=80 GOMEMLIMIT=6144MiB GOOS=darwin /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4\n          no_output_timeout: 30m\n  lint-windows:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run:\n          name: \"Install golangci-lint\"\n          command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2\n      - run:\n          name: \"golangci-lint/Windows\"\n          # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number\n          # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest).\n          command: GOGC=80 GOMEMLIMIT=6144MiB GOOS=windows /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4\n          no_output_timeout: 30m\n  test-go-linux:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - test-go\n  test-go-linux-386:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run: 'GOARCH=386 make deps'\n      - run: 'GOARCH=386 make tidy'\n      - run: 'GOARCH=386 make check'\n      - test-go:\n          arch: \"386\"\n  test-integration:\n    machine:\n      image: ubuntu-2204:current\n    resource_class: large\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run: 'sh ./scripts/installgo_linux.sh'\n      - run: 'make deps'\n      - run:\n          name: \"Run integration tests\"\n          command: make test-integration\n          environment:\n            AZURE_EVENT_HUBS_EMULATOR_ACCEPT_EULA: yes\n  test-go-mac:\n    executor: mac\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run: 'sh ./scripts/installgo_mac.sh'\n      - test-go:\n          os: darwin\n          arch: arm64\n  test-go-windows:\n    executor:\n        name: win/default\n        shell: bash.exe\n        size: large\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run: git config --system core.longpaths true\n      - run: choco feature enable -n allowGlobalConfirmation\n      - run: 'sh ./scripts/installgo_windows.sh'\n      - run: choco install mingw\n      - run: echo 'export PATH=\"$PATH:/c/ProgramData/mingw64/mingw64/bin\"' >> $BASH_ENV\n      - test-go:\n          os: windows\n          gotestsum: \"gotestsum.exe\"\n  test-licenses:\n    executor: telegraf-ci\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run: 'make build_tools'\n      - run: './tools/license_checker/license_checker -whitelist ./tools/license_checker/data/whitelist'\n  windows-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: windows\n          nightly: << parameters.nightly >>\n  darwin-amd64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: darwin-amd64\n          nightly: << parameters.nightly >>\n  darwin-arm64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: darwin-arm64\n          nightly: << parameters.nightly >>\n  i386-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: i386\n          nightly: << parameters.nightly >>\n  ppc64le-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: ppc64le\n          nightly: << parameters.nightly >>\n  riscv64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: riscv64\n          nightly: << parameters.nightly >>\n  loong64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: loong64\n          nightly: << parameters.nightly >>\n  s390x-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: s390x\n          nightly: << parameters.nightly >>\n  armel-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: armel\n          nightly: << parameters.nightly >>\n  amd64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: amd64\n          nightly: << parameters.nightly >>\n  arm64-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: arm64\n          nightly: << parameters.nightly >>\n  mipsel-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: mipsel\n          nightly: << parameters.nightly >>\n  mips-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: mips\n          nightly: << parameters.nightly >>\n  armhf-package:\n    parameters:\n      nightly:\n        type: boolean\n        default: false\n    executor: telegraf-ci\n    steps:\n      - package-build:\n          type: armhf\n          nightly: << parameters.nightly >>\n  nightly:\n    executor: telegraf-ci\n    steps:\n      - attach_workspace:\n          at: '/build'\n      - run:\n          command: |\n            aws s3 sync /build/dist s3://dl.influxdata.com/telegraf/nightlies/ \\\n              --exclude \"*\" \\\n              --include \"*.tar.gz\" \\\n              --include \"*.deb\" \\\n              --include \"*.rpm\" \\\n              --include \"*.zip\" \\\n              --acl public-read\n  release:\n    executor: telegraf-ci\n    steps:\n      - attach_workspace:\n          at: '/build'\n      - run:\n          command: |\n            aws s3 sync /build/dist s3://dl.influxdata.com/telegraf/releases/ \\\n              --exclude \"*\" \\\n              --include \"telegraf*.DIGESTS\" \\\n              --include \"telegraf*.digests\" \\\n              --include \"telegraf*.asc\" \\\n              --include \"telegraf*.deb\" \\\n              --include \"telegraf*.dmg\" \\\n              --include \"telegraf*.rpm\" \\\n              --include \"telegraf*.tar.gz\" \\\n              --include \"telegraf*.zip\" \\\n              --acl public-read\n  docker-nightly:\n    machine:\n      image: ubuntu-2204:current\n    steps:\n      - run:\n          name: login to quay.io\n          command: docker login --username=\"${QUAY_USER}\" --password=\"${QUAY_PASS}\" quay.io\n      - run:\n          name: clone influxdata/influxdata-docker\n          command: git clone https://github.com/influxdata/influxdata-docker\n      - run:\n          name: build and push telegraf:nightly\n          command: |\n            cd influxdata-docker/telegraf/nightly\n            docker build -t telegraf .\n            docker tag telegraf quay.io/influxdb/telegraf-nightly:latest\n            docker image ls\n            docker push quay.io/influxdb/telegraf-nightly:latest\n      - run:\n          name: build and push telegraf:nightly-alpine\n          command: |\n            cd influxdata-docker/telegraf/nightly/alpine\n            docker build -t telegraf-alpine .\n            docker tag telegraf-alpine quay.io/influxdb/telegraf-nightly:alpine\n            docker image ls\n            docker push quay.io/influxdb/telegraf-nightly:alpine\n  amd64-package-test-nightly:\n    machine:\n      image: ubuntu-2204:current\n    steps:\n      - checkout\n      - attach_workspace:\n          at: '.'\n      - run: sh ./scripts/installgo_linux.sh\n      - run: ./scripts/install_incus.sh\n      - run: cd tools/package_incus_test && go build\n      - run: sudo ./tools/package_incus_test/package_incus_test --package $(find ./dist -name \"*_amd64.deb\")\n      - run: sudo ./tools/package_incus_test/package_incus_test --package $(find ./dist -name \"*.x86_64.rpm\")\n  package-sign-windows:\n    machine:\n      image: ubuntu-2204:current\n    resource_class: medium\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - attach_workspace:\n          at: '.'\n      - run:\n          name: \"Sign Windows Executables\"\n          command: ./scripts/sign-windows.sh\n      - persist_to_workspace:\n          root: '.'\n          paths:\n            - 'dist'\n  package-sign-mac:\n    executor: mac\n    working_directory: /Users/distiller/project\n    environment:\n      FL_OUTPUT_DIR: output\n      FASTLANE_LANE: test\n    shell: /bin/bash --login -o pipefail\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - attach_workspace:\n          at: '.'\n      - run:\n          command: |\n            sh ./scripts/mac-signing.sh\n      - persist_to_workspace:\n          root: './build'\n          paths:\n            - 'dist'\n  package-consolidate:\n    docker:\n     - image: alpine\n    steps:\n      - attach_workspace:\n          at: '.'\n      - run:\n          command: |\n            cd dist && find . -type f -name '._*' -delete\n      - store_artifacts:\n          path: './dist'\n          destination: 'build/dist'\n      - run:\n          command: |\n            echo \"This job contains all the final artifacts.\"\n  share-artifacts:\n    executor: aws-cli/default\n    steps:\n      - checkout\n      - check-changed-files-or-halt\n      - run:\n          command: |\n            PR=${CIRCLE_PULL_REQUEST##*/}\n            printf -v payload '{ \"pullRequestNumber\": \"%s\" }' \"$PR\"\n            curl -X POST \"https://182c7jdgog.execute-api.us-east-1.amazonaws.com/prod/shareArtifacts\" --data \"$payload\"\n  package-sign:\n    circleci_ip_ranges: true\n    docker:\n      - image: quay.io/influxdb/rsign:latest\n        auth:\n          username: $QUAY_RSIGN_USERNAME\n          password: $QUAY_RSIGN_PASSWORD\n    steps:\n      - add_ssh_keys:\n          fingerprints:\n            - 3b:c0:fe:a0:8a:93:33:69:de:22:ac:20:a6:ed:6b:e5\n      - attach_workspace:\n          at: .\n      - run: |\n          cd dist\n\n          # Generate the *.DIGESTS files. This must be done before the signing\n          # step so that the *.DIGEST files are also signed.\n          for target in *\n          do\n            sha256sum \"${target}\" > \"${target}.DIGESTS\"\n          done\n\n          for target in *\n          do\n            case \"${target}\"\n            in\n              # rsign is shipped on Alpine Linux which uses \"busybox ash\" instead\n              # of bash. ash is somewhat more posix compliant and is missing some\n              # extensions and niceties from bash.\n              *.deb|*.dmg|*.rpm|*.tar.gz|*.zip|*.DIGESTS)\n                rsign \"${target}\"\n              ;;\n            esac\n          done\n\n          for target in *\n          do\n            case \"${target}\"\n            in\n              *.deb|*.dmg|*.rpm|*.tar.gz|*.zip)\n                # Print sha256 hash and target for artifacts all in one file\n                # for use later during the release.\n                cat \"${target}.DIGESTS\" >> \"telegraf-${CIRCLE_TAG}.DIGESTS\"\n              ;;\n            esac\n          done\n      - persist_to_workspace:\n          root: ./\n          paths:\n            - dist\n      - store_artifacts:\n          path: ./dist\n\nworkflows:\n  version: 2\n  check:\n    when:\n      not:\n        equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]\n    jobs:\n      - 'lint-linux':\n          filters:\n            tags:\n              only: /.*/\n      - 'lint-macos':\n          filters:\n            tags:\n              only: /.*/\n      - 'lint-windows':\n          filters:\n            tags:\n              only: /.*/\n      - 'test-go-linux':\n          filters:\n            tags:\n              only: /.*/\n      - 'test-go-linux-386':\n          filters:\n            tags:\n              only: /.*/\n      - 'test-go-mac':\n          filters:\n            tags: # only runs on tags if you specify this filter\n              only: /.*/\n      - 'test-go-windows':\n          filters:\n            tags:\n              only: /.*/\n      - 'test-integration':\n          filters:\n            tags:\n              only: /.*/\n      - 'windows-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            tags:\n              only: /.*/\n      - 'darwin-amd64-package':\n          requires:\n            - 'test-go-mac'\n          filters:\n            tags:\n              only: /.*/\n      - 'darwin-arm64-package':\n          requires:\n            - 'test-go-mac'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'i386-package':\n          requires:\n            - 'test-go-linux-386'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'ppc64le-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'riscv64-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'loong64-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - /.*/\n            tags:\n              only: /.*/\n      - 's390x-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'armel-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'amd64-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            tags:\n              only: /.*/\n      - 'arm64-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'armhf-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'mipsel-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'mips-package':\n          requires:\n            - 'test-go-linux'\n          filters:\n            branches:\n              ignore:\n                - master\n            tags:\n              only: /.*/\n      - 'share-artifacts':\n          requires:\n            - 'i386-package'\n            - 'ppc64le-package'\n            - 'riscv64-package'\n            - 's390x-package'\n            - 'armel-package'\n            - 'amd64-package'\n            - 'mipsel-package'\n            - 'mips-package'\n            - 'loong64-package'\n            - 'darwin-amd64-package'\n            - 'darwin-arm64-package'\n            - 'windows-package'\n            - 'arm64-package'\n            - 'armhf-package'\n          filters:\n            branches:\n              ignore:\n                - master\n                - release.*\n            tags:\n              ignore: /.*/\n      - 'package-sign-windows':\n          requires:\n            - 'windows-package'\n          filters:\n              tags:\n                only: /.*/\n              branches:\n                ignore: /.*/\n      - 'package-sign-mac':\n           requires:\n            - 'darwin-amd64-package'\n            - 'darwin-arm64-package'\n           filters:\n              tags:\n                only: /.*/\n              branches:\n                ignore: /.*/\n      - 'package-sign':\n          requires:\n            - 'i386-package'\n            - 'ppc64le-package'\n            - 'riscv64-package'\n            - 's390x-package'\n            - 'armel-package'\n            - 'amd64-package'\n            - 'mipsel-package'\n            - 'mips-package'\n            - 'loong64-package'\n            - 'arm64-package'\n            - 'armhf-package'\n            - 'package-sign-mac'\n            - 'package-sign-windows'\n          filters:\n            tags:\n              only: /.*/\n            branches:\n              ignore: /.*/\n      - 'package-consolidate':\n           requires:\n            - 'i386-package'\n            - 'ppc64le-package'\n            - 's390x-package'\n            - 'armel-package'\n            - 'amd64-package'\n            - 'mipsel-package'\n            - 'mips-package'\n            - 'arm64-package'\n            - 'armhf-package'\n            - 'riscv64-package'\n            - 'loong64-package'\n            - 'package-sign-mac'\n            - 'package-sign-windows'\n            - 'package-sign'\n           filters:\n            tags:\n              only: /.*/\n            branches:\n              ignore: /.*/\n      - 'release':\n          requires:\n            - 'package-consolidate'\n          filters:\n            tags:\n              only: /.*/\n            branches:\n              ignore: /.*/\n  nightly:\n    when:\n      equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]\n    jobs:\n      - 'lint-linux'\n      - 'lint-macos'\n      - 'lint-windows'\n      - 'test-go-linux'\n      - 'test-go-linux-386'\n      - 'test-go-mac'\n      - 'test-go-windows'\n      - 'test-licenses'\n      - 'windows-package':\n          name: 'windows-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-windows'\n      - 'darwin-amd64-package':\n          name: 'darwin-amd64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-mac'\n      - 'darwin-arm64-package':\n          name: 'darwin-arm64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-mac'\n      - 'i386-package':\n          name: 'i386-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux-386'\n      - 'ppc64le-package':\n          name: 'ppc64le-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'riscv64-package':\n          name: 'riscv64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'loong64-package':\n          name: 'loong64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 's390x-package':\n          name: 's390x-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'armel-package':\n          name: 'armel-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'amd64-package':\n          name: 'amd64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'arm64-package':\n          name: 'arm64-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'armhf-package':\n          name: 'armhf-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'mipsel-package':\n          name: 'mipsel-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'mips-package':\n          name: 'mips-package-nightly'\n          nightly: true\n          requires:\n            - 'test-go-linux'\n      - 'package-sign-windows':\n          requires:\n            - 'windows-package-nightly'\n      - 'package-sign-mac':\n           requires:\n            - 'darwin-amd64-package-nightly'\n            - 'darwin-arm64-package-nightly'\n      - nightly:\n          requires:\n            - 'amd64-package-test-nightly'\n            - 'arm64-package-nightly'\n            - 'armel-package-nightly'\n            - 'armhf-package-nightly'\n            - 'darwin-amd64-package-nightly'\n            - 'darwin-arm64-package-nightly'\n            - 'i386-package-nightly'\n            - 'mips-package-nightly'\n            - 'mipsel-package-nightly'\n            - 'loong64-package-nightly'\n            - 'ppc64le-package-nightly'\n            - 'riscv64-package-nightly'\n            - 's390x-package-nightly'\n            - 'windows-package-nightly'\n      - docker-nightly:\n          requires:\n            - 'nightly'\n      - amd64-package-test-nightly:\n          requires:\n            - 'amd64-package-nightly'\n"
  },
  {
    "path": ".gitattributes",
    "content": "CHANGELOG.md merge=union\nREADME.md merge=union\ngo.sum merge=union\nplugins/inputs/all/all.go merge=union\nplugins/outputs/all/all.go merge=union\n\n# Always check-out / check-in files with LF line endings.\n* text=auto eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.yml",
    "content": "name: Bug Report\ndescription: Create a bug report to help us improve\nlabels: [\"bug\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking time to fill out this bug report! We reserve Telegraf issues for bugs for reproducible problems.\n        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.\n  - type: textarea\n    id: config\n    attributes:\n      label: Relevant telegraf.conf\n      description: Place config in the toml code section. This will be automatically formatted into toml, so no need for backticks.\n      render: toml\n    validations:\n      required: true\n  - type: textarea\n    id: logs\n    attributes:\n      label: Logs from Telegraf\n      description: Please include the Telegraf logs, ideally with `--debug` used.\n      render: text\n    validations:\n      required: true\n  - type: input\n    id: system-info\n    attributes:\n      label: System info\n      description: Include Telegraf version, operating system, and other relevant details\n      placeholder: ex. Telegraf 1.20.0, Ubuntu 20.04, Docker 20.10.8\n    validations:\n      required: true\n  - type: textarea\n    id: docker\n    attributes:\n      label: Docker\n      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.\n    validations:\n      required: false\n  - type: textarea\n    id: reproduce\n    attributes:\n      label: Steps to reproduce\n      description: Describe the steps to reproduce the bug.\n      value: |\n        1.\n        2.\n        3.\n        ...\n    validations:\n      required: true\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      description: Describe what you expected to happen when you performed the above steps.\n    validations:\n      required: true\n  - type: textarea\n    id: actual-behavior\n    attributes:\n      label: Actual behavior\n      description: Describe what actually happened when you performed the above steps.\n    validations:\n      required: true\n  - type: textarea\n    id: additional-info\n    attributes:\n      label: Additional info\n      description: Include gist of relevant config, logs, etc.\n    validations:\n      required: false\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml",
    "content": "name: Feature request\ndescription: Create a feature request to make Telegraf more awesome\nlabels: [\"feature request\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        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.\n  - type: textarea\n    id: use-case\n    attributes:\n      label: Use Case\n      description: Describe how you plan to use this feature. \n    validations:\n      required: true\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      description: Describe what you expected to happen when you performed the above steps.\n    validations:\n      required: true\n  - type: textarea\n    id: actual-behavior\n    attributes:\n      label: Actual behavior\n      description: Describe what actually happened when you performed the above steps.\n    validations:\n      required: true\n  - type: textarea\n    id: additional-info\n    attributes:\n      label: Additional info\n      description: Include gist of relevant config, logs, etc.\n    validations:\n      required: false\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/SUPPORT.yml",
    "content": "name: Support request\ndescription: Open a support request\nlabels: [\"support\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        WOAH, hold up. This isn't the best place for support questions. \n        You can get a faster response on slack or forums:\n\n        Please redirect any QUESTIONS about Telegraf usage to \n        - InfluxData Slack Channel: https://www.influxdata.com/slack \n        - InfluxData Community Site: https://community.influxdata.com\n\n        Check the documentation for the related plugin including the troubleshooting\n        section if available.\n\n        https://docs.influxdata.com/telegraf\n        https://github.com/influxdata/telegraf/tree/master/docs\n  - type: textarea\n    attributes:\n      label: \"Please direct all support questions to Slack or the forums. Thank you.\"\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## Summary\n<!-- Mandatory\nExplain here the why, the rationale and motivation, for the changes.\n-->\n\n## Checklist\n<!-- Mandatory\nPlease confirm at least ONE of the following by replacing the space with an \"x\"\nbetween the []:\n-->\n\n- [ ] No AI generated code was used in this PR\n- [ ] AI generated code used in this PR follows the [InfluxData Policy on AI-Generated Code Contributions][policy]\n\n[policy]: https://www.influxdata.com/ai-generated-code-contributions-policy\n\n## Related issues\n<!-- Mandatory\nAll PRs should resolve an issue, if one does not exist, please open one.\n-->\n\nresolves #\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    open-pull-requests-limit: 25\n    labels:\n      - \"dependencies\"\n  - package-ecosystem: \"gomod\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    open-pull-requests-limit: 25\n    ignore:\n      # Dependabot isn't able to update this packages that do not match the\n      # source, so anything with a version\n      - dependency-name: \"*.v*\"\n    labels:\n      - \"dependencies\"\n    groups:\n      aws-sdk-go-v2:\n        applies-to: version-updates\n        patterns:\n          - \"github.com/aws/aws-sdk-go-v2*\"\n"
  },
  {
    "path": ".github/workflows/linter.yml",
    "content": "---\n#################################\n#################################\n## Super Linter GitHub Actions ##\n#################################\n#################################\nname: Lint Code Base\n\n#\n# Documentation:\n# https://help.github.com/en/articles/workflow-syntax-for-github-actions\n#\n\n#############################\n# Start the job on all push #\n#############################\non:\n  push:\n    branches-ignore: [master, main]\n    # Remove the line above to run when pushing to master\n  pull_request:\n    branches: [master, main]\n\n###############\n# Set the Job #\n###############\npermissions: {}\n\njobs:\n  build:\n    # Name the Job\n    permissions:\n      contents: read # to fetch code (actions/checkout)\n      statuses: write # to mark status of each linter run (github/super-linter)\n\n    name: Lint Code Base\n    # Set the agent to run on\n    runs-on: ubuntu-latest\n\n    ##################\n    # Load all steps #\n    ##################\n    steps:\n      ##########################\n      # Checkout the code base #\n      ##########################\n      - name: Checkout Code\n        uses: actions/checkout@v6\n        with:\n          # Full git history is needed to get a proper list of changed files within `super-linter`\n          fetch-depth: 0\n\n      ################################\n      # Run Linter against code base #\n      ################################\n      - name: Lint Code Base\n        uses: super-linter/super-linter@v8.5.0\n        env:\n          VALIDATE_ALL_CODEBASE: false\n          DEFAULT_BRANCH: master\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          LINTER_RULES_PATH: '.'\n          MARKDOWN_CONFIG_FILE: .markdownlint.jsonc\n          VALIDATE_MARKDOWN: true\n          VALIDATE_BASH: true\n"
  },
  {
    "path": ".github/workflows/milestones.yml",
    "content": "name: Milestones\non:\n  pull_request_target:\n    types:\n      - closed\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  milestone_job:\n    if: github.event.pull_request.merged == true\n    runs-on: ubuntu-latest\n    name: Assign milestones to PRs\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n      - name: Assign milestone to PR\n        uses: srebhan/label-milestone-action@v1.0.2\n        id: assign-milestone\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n          bugfix-labels: 'fix,chore,docs,test'\n          minor-labels: 'feat'\n          major-labels: 'breaking change'\n          fallback: 'minor'\n      - name: Show milestone\n        run: echo \"Assigned milestone is ${{ steps.assign-milestone.outputs.milestone }}\"\n"
  },
  {
    "path": ".github/workflows/pr-target-branch.yml",
    "content": "name: Target Branch\non:\n  pull_request:\n    types:\n      - opened\n      - reopened\n      - synchronize\n      - edited\n\njobs:\n  check-target-master:\n    name: master\n    runs-on: ubuntu-latest\n    steps:\n      - name: debug\n        run: echo Target is ${{ github.event.pull_request.base.ref }}\n      - name: success\n        if: github.event.pull_request.base.ref == 'master'\n        run: exit 0\n      - name: error\n        if: github.event.pull_request.base.ref != 'master'\n        run: |\n          echo \"Pull-request is not based on master, please rebase\"\n          exit 1\n"
  },
  {
    "path": ".github/workflows/readme-linter.yml",
    "content": "name: Lint plugin readmes\non:\n#  push:\n#    branches-ignore: master\n  pull_request:\n    branches: # Names of target branches, not source branches\n      - master\njobs:\n  run-readme-linter:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/setup-go@v6\n        with:\n          go-version: '1.25.7'\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - name: Get changed files\n        id: changed-files\n        uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5\n        with:\n          base_sha: ${{ github.event.pull_request.base.sha }}\n          files: ./plugins/**/README.md\n      - name: Run readme linter on changed files\n        if: steps.changed-files.outputs.any_changed == 'true'\n        run: go run ./tools/readme_linter ${{ steps.changed-files.outputs.all_changed_files }}\n"
  },
  {
    "path": ".github/workflows/semantic.yml",
    "content": "---\nname: \"Semantic PR and Commit Messages\"\n\non:\n  pull_request:\n    types: [opened, reopened, synchronize, edited]\n    branches:\n      - master\n\njobs:\n  semantic:\n    uses: influxdata/validate-semantic-github-messages/.github/workflows/semantic.yml@main\n    with:\n      COMMITS_HISTORY: 0\n\n"
  },
  {
    "path": ".gitignore",
    "content": "/.idea\n/build\n/etc/telegraf.conf\n/telegraf\n/telegraf.exe\n/telegraf.gz\n/tools/package_lxd_test/package_lxd_test\n/tools/license_checker/license_checker*\n/tools/readme_config_includer/generator\n/tools/readme_config_includer/generator.exe\n/tools/config_includer/generator\n/tools/config_includer/generator.exe\n/tools/readme_linter/readme_linter*\n/tools/custom_builder/custom_builder*\n/vendor\n.DS_Store\nprocess.yml\n/.vscode\n/*.toml\n/*.conf\nresource.syso\nversioninfo.json\n.uuid\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\n\nlinters:\n  # Default set of linters.\n  # The value can be:\n  # - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default\n  # - `all`: enables all linters by default.\n  # - `none`: disables all linters by default.\n  # - `fast`: enables only linters considered as \"fast\" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).\n  # Default: standard\n  default: none\n\n  # Enable specific linter.\n  enable:\n    - asasalint\n    - asciicheck\n    - bidichk\n    - bodyclose\n    - copyloopvar\n    - depguard\n    - dogsled\n    - errcheck\n    - errname\n    - errorlint\n    - gocheckcompilerdirectives\n    - gocritic\n    - goprintffuncname\n    - gosec\n    - govet\n    - ineffassign\n    - interfacebloat\n    - lll\n    - makezero\n    - mirror\n    - nakedret\n    - nilerr\n    - nolintlint\n    - perfsprint\n    - prealloc\n    - predeclared\n    - revive\n    - sqlclosecheck\n    - staticcheck\n    - testifylint\n    - tparallel\n    - unconvert\n    - unparam\n    - unused\n    - usetesting\n\n  # All available settings of specific linters.\n  settings:\n    depguard:\n      # Rules to apply.\n      #\n      # Variables:\n      # - File Variables\n      #   Use an exclamation mark `!` to negate a variable.\n      #   Example: `!$test` matches any file that is not a go test file.\n      #\n      #   `$all` - matches all go files\n      #   `$test` - matches all go test files\n      #\n      # - Package Variables\n      #\n      #   `$gostd` - matches all of go's standard library (Pulled from `GOROOT`)\n      #\n      # Default (applies if no custom rules are defined): Only allow $gostd in all files.\n      rules:\n        # Name of a rule.\n        main:\n          # List of file globs that will match this list of settings to compare against.\n          # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed.\n          # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`.\n          # The placeholder '${config-path}' is substituted with a path relative to the configuration file.\n          # Default: $all\n          files:\n            - '!**/agent/**'\n            - '!**/cmd/**'\n            - '!**/config/**'\n            - '!**/filter/**'\n            - '!**/internal/**'\n            - '!**/logger/**'\n            - '!**/metric/**'\n            - '!**/models/**'\n            - '!**/plugins/serializers/**'\n            - '!**/scripts/**'\n            - '!**/selfstat/**'\n            - '!**/testutil/**'\n            - '!**/tools/**'\n            - '!**/*_test.go'\n          # List of packages that are not allowed.\n          # Entries can be a variable (starting with $), a string prefix, or an exact match (if ending with $).\n          # Default: []\n          deny:\n            - pkg: log\n              desc: 'Use injected telegraf.Logger instead'\n\n    errcheck:\n      # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`.\n      # Such cases aren't reported by default.\n      # Default: false\n      check-blank: true\n\n      # List of functions to exclude from checking, where each entry is a single function to exclude.\n      # See https://github.com/kisielk/errcheck#excluding-functions for details.\n      exclude-functions:\n        - '(*hash/maphash.Hash).Write'\n        - '(*hash/maphash.Hash).WriteByte'\n        - '(*hash/maphash.Hash).WriteString'\n        - '(*github.com/influxdata/telegraf/plugins/outputs/postgresql/sqltemplate.Template).UnmarshalText'\n\n    gocritic:\n      # Disable all checks.\n      # Default: false\n      disable-all: true\n      # Which checks should be enabled in addition to default checks; can't be combined with 'disabled-checks'.\n      # By default, list of stable checks is used (https://go-critic.com/overview#checks-overview).\n      # To see which checks are enabled run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic`.\n      enabled-checks:\n        # diagnostic\n        - argOrder\n        - badCall\n        - badCond\n        - badLock\n        - badRegexp\n        - badSorting\n        - badSyncOnceFunc\n        - builtinShadowDecl\n        - caseOrder\n        - codegenComment\n        - commentedOutCode\n        - deferInLoop\n        - deprecatedComment\n        - dupArg\n        - dupBranchBody\n        - dupCase\n        - dupSubExpr\n        - dynamicFmtString\n        - emptyDecl\n        - evalOrder\n        - exitAfterDefer\n        - externalErrorReassign\n        - filepathJoin\n        - flagName\n        - mapKey\n        - nilValReturn\n        - offBy1\n        - regexpPattern\n        - sloppyLen\n        - sloppyReassign\n        - sloppyTypeAssert\n        - sortSlice\n        - sprintfQuotedString\n        - sqlQuery\n        - syncMapLoadAndDelete\n        - truncateCmp\n        - uncheckedInlineErr\n        - unnecessaryDefer\n        - weakCond\n        # performance\n        - appendCombine\n        - equalFold\n        - hugeParam\n        - indexAlloc\n        - preferDecodeRune\n        - preferFprint\n        - preferStringWriter\n        - preferWriteByte\n        - rangeExprCopy\n        - rangeValCopy\n        - sliceClear\n        - stringXbytes\n\n      # Settings passed to gocritic.\n      # The settings key is the name of a supported gocritic checker.\n      # The list of supported checkers can be found at https://go-critic.com/overview.\n      settings:\n        hugeParam:\n          # Size in bytes that makes the warning trigger.\n          # Default: 80\n          sizeThreshold: 512\n        rangeValCopy:\n          # Size in bytes that makes the warning trigger.\n          # Default: 128\n          sizeThreshold: 512\n\n    gosec:\n      # To select a subset of rules to run.\n      # Available rules: https://github.com/securego/gosec#available-rules\n      # Default: [] - means include all rules\n      includes:\n        - G101 # Look for hard coded credentials\n        - G102 # Bind to all interfaces\n        - G103 # Audit the use of unsafe block\n        - G106 # Audit the use of ssh.InsecureIgnoreHostKey\n        - G107 # Url provided to HTTP request as taint input\n        - G108 # Profiling endpoint automatically exposed on /debug/pprof\n        - G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32\n        - G110 # Potential DoS vulnerability via decompression bomb\n        - G111 # Potential directory traversal\n        - G112 # Potential slowloris attack\n        - G114 # Use of net/http serve function that has no support for setting timeouts\n        - G201 # SQL query construction using format string\n        - G202 # SQL query construction using string concatenation\n        - G203 # Use of unescaped data in HTML templates\n        - G301 # Poor file permissions used when creating a directory\n        - G302 # Poor file permissions used with chmod\n        - G303 # Creating tempfile using a predictable path\n        - G305 # File traversal when extracting zip/tar archive\n        - G306 # Poor file permissions used when writing to a new file\n        - G401 # Detect the usage of MD5 or SHA1\n        - G403 # Ensure minimum RSA key length of 2048 bits\n        - G404 # Insecure random number source (rand)\n        - G405 # Detect the usage of DES or RC4\n        - G406 # Detect the usage of MD4 or RIPEMD160\n        - G501 # Import blocklist: crypto/md5\n        - G502 # Import blocklist: crypto/des\n        - G503 # Import blocklist: crypto/rc4\n        - G505 # Import blocklist: crypto/sha1\n        - G506 # Import blocklist: golang.org/x/crypto/md4\n        - G507 # Import blocklist: golang.org/x/crypto/ripemd160\n        - G601 # Implicit memory aliasing of items from a range statement\n        - G602 # Slice access out of bounds\n      # G104, G105, G113, G204, G304, G307, G402, G504 were not enabled intentionally\n      # TODO: review G115 when reporting false positives is fixed (https://github.com/securego/gosec/issues/1212)\n\n      # To specify the configuration of rules.\n      config:\n        # Maximum allowed permissions mode for os.OpenFile and os.Chmod\n        # Default: \"0600\"\n        G302: \"0640\"\n        # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile\n        # Default: \"0600\"\n        G306: \"0640\"\n\n    govet:\n      # Settings per analyzer.\n      settings:\n        # Analyzer name, run `go tool vet help` to see all analyzers.\n        printf:\n          # Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`).\n          # Default: []\n          funcs:\n            - (github.com/influxdata/telegraf.Logger).Tracef\n            - (github.com/influxdata/telegraf.Logger).Debugf\n            - (github.com/influxdata/telegraf.Logger).Infof\n            - (github.com/influxdata/telegraf.Logger).Warnf\n            - (github.com/influxdata/telegraf.Logger).Errorf\n            - (github.com/influxdata/telegraf.Logger).Trace\n            - (github.com/influxdata/telegraf.Logger).Debug\n            - (github.com/influxdata/telegraf.Logger).Info\n            - (github.com/influxdata/telegraf.Logger).Warn\n            - (github.com/influxdata/telegraf.Logger).Error\n\n    lll:\n      # Max line length, lines longer will be reported.\n      # '\\t' is counted as 1 character by default, and can be changed with the tab-width option.\n      # Default: 120.\n      line-length: 160\n      # Tab width in spaces.\n      # Default: 1\n      tab-width: 4\n\n    nakedret:\n      # Make an issue if func has more lines of code than this setting, and it has naked returns.\n      # Default: 30\n      max-func-lines: 1\n\n    nolintlint:\n      # Enable to require an explanation of nonzero length after each nolint directive.\n      # Default: false\n      require-explanation: true\n      # Enable to require nolint directives to mention the specific linter being suppressed.\n      # Default: false\n      require-specific: true\n\n    prealloc:\n      # Report pre-allocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.\n      # Default: true\n      simple: false\n\n    revive:\n      # Sets the default severity.\n      # See https://github.com/mgechev/revive#configuration\n      # Default: warning\n      severity: error\n\n      # Run `GL_DEBUG=revive golangci-lint run --enable-only=revive` to see default, all available rules, and enabled rules.\n      rules:\n        - name: argument-limit\n          arguments: [ 6 ]\n        - name: atomic\n        - name: bare-return\n        - name: blank-imports\n        - name: bool-literal-in-expr\n        - name: call-to-gc\n        - name: comment-spacings\n        - name: confusing-naming\n        - name: confusing-results\n        - name: constant-logical-expr\n        - name: context-as-argument\n        - name: context-keys-type\n        - name: datarace\n        - name: deep-exit\n        - name: defer\n        - name: dot-imports\n        - name: duplicated-imports\n        - name: early-return\n        - name: empty-block\n        - name: empty-lines\n        - name: enforce-map-style\n          exclude: [ \"TEST\" ]\n          arguments:\n            - \"make\"\n        - name: enforce-repeated-arg-type-style\n          arguments:\n            - \"short\"\n        - name: enforce-slice-style\n          arguments:\n            - \"make\"\n        - name: error-naming\n        - name: error-return\n        - name: error-strings\n        - name: errorf\n        - name: exported\n          exclude:\n            - \"**/accumulator.go\"\n            - \"**/agent/**\"\n            - \"**/cmd/**\"\n            - \"**/config/**\"\n            - \"**/filter/**\"\n            - \"**/internal/**\"\n            - \"**/logger/**\"\n            - \"**/logger.go\"\n            - \"**/metric/**\"\n            - \"**/metric.go\"\n            - \"**/migrations/**\"\n            - \"**/models/**\"\n            - \"**/persister/**\"\n            - \"**/metric.go\"\n            - \"**/parser.go\"\n            - \"**/plugin.go\"\n            - \"**/plugins/common/**\"\n            - \"**/plugins/outputs/**\"\n            - \"**/plugins/parsers/**\"\n            - \"**/selfstat/**\"\n            - \"**/serializer.go\"\n            - \"**/testutil/**\"\n            - \"**/tools/**\"\n          arguments:\n            - \"check-private-receivers\"\n            - \"say-repetitive-instead-of-stutters\"\n            - \"check-public-interface\"\n            - \"disable-checks-on-types\"\n        - name: function-result-limit\n          arguments: [ 3 ]\n        - name: get-return\n        - name: identical-branches\n        - name: if-return\n        - name: import-alias-naming\n          arguments:\n            - \"^[a-z][a-z0-9_]*[a-z0-9]+$\"\n        - name: import-shadowing\n        - name: increment-decrement\n        - name: indent-error-flow\n        - name: max-public-structs\n          arguments: [ 5 ]\n          exclude: [ \"TEST\" ]\n        - name: modifies-parameter\n        - name: modifies-value-receiver\n        - name: optimize-operands-order\n        - name: package-comments\n        - name: range\n        - name: range-val-address\n        - name: range-val-in-closure\n        - name: receiver-naming\n        - name: redefines-builtin-id\n        - name: redundant-import-alias\n        - name: string-format\n          arguments:\n            - - 'fmt.Errorf[0],errors.New[0]'\n              - '/^([^A-Z]|$)/'\n              - 'Error string must not start with a capital letter.'\n            - - 'fmt.Errorf[0],errors.New[0]'\n              - '/(^|[^\\.!?])$/'\n              - 'Error string must not end in punctuation.'\n            - - 'panic'\n              - '/^[^\\n]*$/'\n              - 'Must not contain line breaks.'\n        - name: string-of-int\n        - name: struct-tag\n        - name: superfluous-else\n        - name: time-equal\n        - name: time-naming\n        - name: unconditional-recursion\n        - name: unexported-naming\n        - name: unnecessary-stmt\n        - name: unreachable-code\n        - name: unused-parameter\n        - name: unused-receiver\n        - name: var-declaration\n        - name: var-naming\n          arguments:\n            - [ ] # AllowList\n            - [ \"ID\", \"DB\", \"TS\" ] # DenyList\n        - name: waitgroup-by-value\n\n    staticcheck:\n      # SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks\n      # Example (to disable some checks): [ \"all\", \"-SA1000\", \"-SA1001\"]\n      # Run `GL_DEBUG=staticcheck golangci-lint run --enable=staticcheck` to see all available checks and enabled by config checks.\n      # Default: [\"all\", \"-ST1000\", \"-ST1003\", \"-ST1016\", \"-ST1020\", \"-ST1021\", \"-ST1022\"]\n      checks:\n        - all\n        # Poorly chosen identifier.\n        # https://staticcheck.dev/docs/checks/#ST1003\n        - -ST1003\n        # Apply De Morgan's law.\n        # https://staticcheck.dev/docs/checks/#QF1001\n        - -QF1001\n        # Convert if/else-if chain to tagged switch.\n        # https://staticcheck.dev/docs/checks/#QF1003\n        - -QF1003\n        # Use 'strings.ReplaceAll' instead of 'strings.Replace' with 'n == -1'.\n        # https://staticcheck.dev/docs/checks/#QF1004\n        - -QF1004\n        # Lift 'if'+'break' into loop condition.\n        # https://staticcheck.dev/docs/checks/#QF1006\n        - -QF1006\n        # Merge conditional assignment into variable declaration.\n        # https://staticcheck.dev/docs/checks/#QF1007\n        - -QF1007\n        # Omit embedded fields from selector expression.\n        # https://staticcheck.dev/docs/checks/#QF1008\n        - -QF1008\n        # Use 'time.Time.Equal' instead of '==' operator.\n        # https://staticcheck.dev/docs/checks/#QF1009\n        - -QF1009\n\n    testifylint:\n      # Disable all checkers (https://github.com/Antonboom/testifylint#checkers).\n      # Default: false\n      disable-all: true\n      # Enable checkers by name\n      enable:\n        - blank-import\n        - bool-compare\n        - compares\n        - contains\n        - empty\n        - encoded-compare\n        - error-is-as\n        - error-nil\n        - expected-actual\n        - float-compare\n        - formatter\n        - go-require\n        - len\n        - negative-positive\n        - nil-compare\n        - regexp\n        - require-error\n        - suite-broken-parallel\n        - suite-dont-use-pkg\n        - suite-extra-assert-call\n        - suite-subtest-run\n        - suite-thelper\n        - useless-assert\n\n    usetesting:\n      # Enable/disable `os.TempDir()` detections.\n      # Default: false\n      os-temp-dir: true\n\n  # Defines a set of rules to ignore issues.\n  # It does not skip the analysis, and so does not ignore \"typecheck\" errors.\n  exclusions:\n    # Mode of the generated files analysis.\n    #\n    # - `strict`: sources are excluded by strictly following the Go generated file convention.\n    #    Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\\.$`\n    #    This line must appear before the first non-comment, non-blank text in the file.\n    #    https://go.dev/s/generatedcode\n    # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.\n    # - `disable`: disable the generated files exclusion.\n    #\n    # Default: strict\n    generated: lax\n\n    # Excluding configuration per-path, per-linter, per-text and per-source.\n    rules:\n      # errcheck\n      - path: cmd/telegraf/(main|printer|cmd_plugins).go\n        text: \"Error return value of `outputBuffer.Write` is not checked\"\n\n      - path: plugins/inputs/win_perf_counters/pdh.go\n        linters:\n          - errcheck\n\n      # gosec:G101\n      - path: _test\\.go\n        text: \"Potential hardcoded credentials\"\n\n      # gosec:G404\n      - path: _test\\.go\n        text: \"Use of weak random number generator\"\n\n      # revive:max-public-structs\n      - path-except: ^plugins/(aggregators|inputs|outputs|parsers|processors|serializers)/...\n        text: \"max-public-structs: you have exceeded the maximum number\"\n\n      # revive:var-naming\n      - path: (.+)\\.go$\n        text: don't use an underscore in package name\n\n      # revive:var-naming\n      - path: (.*)\\.go$\n        text: avoid meaningless package names\n\n      # revive:var-naming: Exclude mixed-caps packages in migrations, as these migrations are fixing the issues from before.\n      - path: migrations/.*\\.go$\n        text: don't use MixedCaps in package name\n\n      # revive:var-naming: Exclude check for package names that conflict with standard library package names (e.g., \"net\", \"json\", \"http\", \"os\")\n      - path: (.*)\\.go$\n        text: conflict with Go standard library package names\n\n      # revive:exported\n      - path: (.+)\\.go$\n        text: exported method .*\\.(Init |SampleConfig |Gather |Start |Stop |GetState |SetState |SetParser |SetParserFunc |SetTranslator |Probe |Add |Push |Reset |Serialize |SerializeBatch |Get |Set |List |GetResolver |Apply |SetSerializer )should have comment or be unexported\n\n      # EXC0001 errcheck: Almost all programs ignore errors on these functions, and in most cases it's ok\n      - path: (.+)\\.go$\n        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\n\n      # EXC0013 revive: Annoying issue about not having a comment. The rare codebase has such comments\n      - path: (.+)\\.go$\n        text: package comment should be of the form \"(.+)...\n\n      # EXC0015 revive: Annoying issue about not having a comment. The rare codebase has such comments\n      - path: (.+)\\.go$\n        text: should have a package comment\n\n    # Which file paths to exclude: they will be analyzed, but issues from them won't be reported.\n    # \"/\" will be replaced by the current OS file path separator to properly work on Windows.\n    # Default: []\n    paths:\n      - plugins/parsers/influx/machine.go*\n\nformatters:\n  # Enable specific formatter.\n  # Default: [] (uses standard Go formatting)\n  enable:\n    - gci\n\n  # Formatters settings.\n  settings:\n    gci:\n      # Section configuration to compare against.\n      # Section names are case-insensitive and may contain parameters in ().\n      # The default order of sections is `standard > default > custom > blank > dot > alias > localmodule`.\n      # If `custom-order` is `true`, it follows the order of `sections` option.\n      # Default: [\"standard\", \"default\"]\n      sections:\n        - standard                       # Standard section: captures all standard packages.\n        - default                        # Default section: contains all imports that could not be matched to another section type.\n        - localmodule                    # Local module section: contains all local packages. This section is not present unless explicitly enabled.\n\n  exclusions:\n    # Mode of the generated files analysis.\n    #\n    # - `strict`: sources are excluded by strictly following the Go generated file convention.\n    #    Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\\.$`\n    #    This line must appear before the first non-comment, non-blank text in the file.\n    #    https://go.dev/s/generatedcode\n    # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.\n    # - `disable`: disable the generated files exclusion.\n    #\n    # Default: lax\n    generated: lax\n\nissues:\n  # Maximum issues count per one linter.\n  # Set to 0 to disable.\n  # Default: 50\n  max-issues-per-linter: 0\n\n  # Maximum count of issues with the same text.\n  # Set to 0 to disable.\n  # Default: 3\n  max-same-issues: 0\n\n  # Make issues output unique by line.\n  # Default: true\n  uniq-by-line: false\n\n# Output configuration options.\noutput:\n  # The formats used to render issues.\n  formats:\n    # Prints issues in columns representation separated by tabulations.\n    tab:\n      # Output path can be either `stdout`, `stderr` or path to the file to write to.\n      # Default: stdout\n      path: stdout\n\n  # Order to use when sorting results.\n  # Possible values: `file`, `linter`, and `severity`.\n  #\n  # If the severity values are inside the following list, they are ordered in this order:\n  #   1. error\n  #   2. warning\n  #   3. high\n  #   4. medium\n  #   5. low\n  # Either they are sorted alphabetically.\n  #\n  # Default: [\"linter\", \"file\"]\n  sort-order:\n    - file # filepath, line, and column.\n    - linter\n\n  # Show statistics per linter.\n  # Default: true\n  show-stats: true\n\nseverity:\n  # Set the default severity for issues.\n  #\n  # If severity rules are defined and the issues do not match or no severity is provided to the rule\n  # this will be the default severity applied.\n  # Severities should match the supported severity names of the selected out format.\n  # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity\n  # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#SeverityLevel\n  # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message\n  # - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance\n  #\n  # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...)\n  #\n  # Default: \"\"\n  default: error\n"
  },
  {
    "path": ".markdownlint.jsonc",
    "content": "{\n  \"MD013\": {\n    \"code_blocks\": false,\n    \"tables\": false,\n    \"heading_line_length\": 90\n  },\n  \"MD033\": {\n    \"allowed_elements\": [\n      \"br\"\n    ]\n  }\n}\n"
  },
  {
    "path": ".markdownlintignore",
    "content": ".github/PULL_REQUEST_TEMPLATE.md\ndocs/includes/*\n"
  },
  {
    "path": "CHANGELOG-1.13.md",
    "content": "<!-- markdownlint-disable MD013 MD024 -->\n# Changelog v1.13 and Earlier\n\n## v1.13.4 [2020-02-25]\n\n### Release Notes\n\n- Official packages now built with Go 1.13.8.\n\n### Bug Fixes\n\n- [#6988](https://github.com/influxdata/telegraf/issues/6988): Parse NaN values from summary types in prometheus input.\n- [#6820](https://github.com/influxdata/telegraf/issues/6820): Fix pgbouncer input when used with newer pgbouncer versions.\n- [#6913](https://github.com/influxdata/telegraf/issues/6913): Support up to 8192 stats in the ethtool input.\n- [#7060](https://github.com/influxdata/telegraf/issues/7060): Fix perf counters collection on named instances in sqlserver input.\n- [#6926](https://github.com/influxdata/telegraf/issues/6926): Use add time for prometheus expiration calculation.\n- [#7057](https://github.com/influxdata/telegraf/issues/7057): Fix inconsistency with input error counting in internal input.\n- [#7063](https://github.com/influxdata/telegraf/pull/7063): Use the same timestamp per call if no time is provided in prometheus input.\n\n## v1.13.3 [2020-02-04]\n\n### Bug Fixes\n\n- [#5744](https://github.com/influxdata/telegraf/issues/5744): Fix kibana input with Kibana versions greater than 6.4.\n- [#6960](https://github.com/influxdata/telegraf/issues/6960): Fix duplicate TrackingIDs can be returned in queue consumer plugins.\n- [#6913](https://github.com/influxdata/telegraf/issues/6913): Support up to 4096 stats in the ethtool input.\n- [#6973](https://github.com/influxdata/telegraf/issues/6973): Expire metrics on query in addition to on add.\n\n## v1.13.2 [2020-01-21]\n\n### Bug Fixes\n\n- [#2652](https://github.com/influxdata/telegraf/issues/2652): Warn without error when processes input is started on Windows.\n- [#6890](https://github.com/influxdata/telegraf/issues/6890): Only parse certificate blocks in x509_cert input.\n- [#6883](https://github.com/influxdata/telegraf/issues/6883): Add custom attributes for all resource types in vsphere input.\n- [#6899](https://github.com/influxdata/telegraf/pull/6899): Fix URL agent address form with udp in snmp input.\n- [#6619](https://github.com/influxdata/telegraf/issues/6619): Change logic to allow recording of device fields when attributes is false.\n- [#6903](https://github.com/influxdata/telegraf/issues/6903): Do not add invalid timestamps to kafka messages.\n- [#6906](https://github.com/influxdata/telegraf/issues/6906): Fix json_strict option and set default of true.\n\n## v1.13.1 [2020-01-08]\n\n### Bug Fixes\n\n- [#6788](https://github.com/influxdata/telegraf/issues/6788): Fix ServerProperty query stops working on Azure after failover.\n- [#6803](https://github.com/influxdata/telegraf/pull/6803): Add leading period to OID in SNMP v1 generic traps.\n- [#6823](https://github.com/influxdata/telegraf/pull/6823): Fix missing config fields in prometheus serializer.\n- [#6694](https://github.com/influxdata/telegraf/issues/6694): Fix panic on connection loss with undelivered messages in mqtt_consumer.\n- [#6679](https://github.com/influxdata/telegraf/issues/6679): Encode query hash fields as hex strings in sqlserver input.\n- [#6345](https://github.com/influxdata/telegraf/issues/6345): Invalidate diskio cache if the metadata mtime has changed.\n- [#6800](https://github.com/influxdata/telegraf/issues/6800): Show platform not supported warning only on plugin creation.\n- [#6814](https://github.com/influxdata/telegraf/issues/6814): Fix rabbitmq cannot complete gather after request error.\n- [#6846](https://github.com/influxdata/telegraf/issues/6846): Fix /sbin/init --version executed on Telegraf startup.\n- [#6847](https://github.com/influxdata/telegraf/issues/6847): Use last path element as field key if path fully specified in cisco_telemetry_gnmi input.\n\n## v1.13 [2019-12-12]\n\n### Release Notes\n\n- Official packages built with Go 1.13.5.  This affects the minimum supported\n  version on several platforms, most notably requiring Windows 7 (2008 R2) or\n  later.  For details, check the release notes for Go\n  [ports](https://golang.org/doc/go1.13#ports).\n- The `prometheus` input and `prometheus_client` output have a new mapping to\n  and from Telegraf metrics, which can be enabled by setting `metric_version = 2`.\n  The original mapping is deprecated.  When both plugins have the same setting,\n  passthrough metrics will be unchanged.  Refer to the `prometheus` input for\n  details about the mapping.\n\n### New Inputs\n\n- [azure_storage_queue](/plugins/inputs/azure_storage_queue/README.md) - Contributed by @mjiderhamn\n- [ethtool](/plugins/inputs/ethtool/README.md) - Contributed by @philippreston\n- [snmp_trap](/plugins/inputs/snmp_trap/README.md) - Contributed by @influxdata\n- [suricata](/plugins/inputs/suricata/README.md) - Contributed by @satta\n- [synproxy](/plugins/inputs/synproxy/README.md) - Contributed by @rfrenayworldstream\n- [systemd_units](/plugins/inputs/systemd_units/README.md) - Contributed by @benschweizer\n\n### New Processors\n\n- [clone](/plugins/processors/clone/README.md) - Contributed by @adrianlzt\n\n### New Aggregators\n\n- [merge](/plugins/aggregators/merge/README.md) - Contributed by @influxdata\n\n### Features\n\n- [#6326](https://github.com/influxdata/telegraf/pull/5842): Add per node memory stats to rabbitmq input.\n- [#6361](https://github.com/influxdata/telegraf/pull/6361): Add ability to read query from file to postgresql_extensible input.\n- [#5921](https://github.com/influxdata/telegraf/pull/5921): Add replication metrics to the redis input.\n- [#6177](https://github.com/influxdata/telegraf/pull/6177): Support NX-OS telemetry extensions in cisco_telemetry_mdt.\n- [#6415](https://github.com/influxdata/telegraf/pull/6415): Allow graphite parser to create Inf and NaN values.\n- [#6434](https://github.com/influxdata/telegraf/pull/6434): Use prefix base detection for ints in grok parser.\n- [#6465](https://github.com/influxdata/telegraf/pull/6465): Add more performance counter metrics to sqlserver input.\n- [#6476](https://github.com/influxdata/telegraf/pull/6476): Add millisecond unix time support to grok parser.\n- [#6473](https://github.com/influxdata/telegraf/pull/6473): Add container id as optional source tag to docker and docker_log input.\n- [#6504](https://github.com/influxdata/telegraf/pull/6504): Add lang parameter to OpenWeathermap input plugin.\n- [#6540](https://github.com/influxdata/telegraf/pull/6540): Log file open errors at debug level in tail input.\n- [#6553](https://github.com/influxdata/telegraf/pull/6553): Add timeout option to cloudwatch input.\n- [#6549](https://github.com/influxdata/telegraf/pull/6549): Support custom success codes in http input.\n- [#6530](https://github.com/influxdata/telegraf/pull/6530): Improve ipvs input error strings and logging.\n- [#6532](https://github.com/influxdata/telegraf/pull/6532): Add strict mode to JSON parser that can be disable to ignore invalid items.\n- [#6543](https://github.com/influxdata/telegraf/pull/6543): Add support for Kubernetes 1.16 and remove deprecated API usage.\n- [#6283](https://github.com/influxdata/telegraf/pull/6283): Add gathering of RabbitMQ federation link metrics.\n- [#6356](https://github.com/influxdata/telegraf/pull/6356): Add bearer token defaults for Kubernetes plugins.\n- [#5870](https://github.com/influxdata/telegraf/pull/5870): Add support for SNMP over TCP.\n- [#6603](https://github.com/influxdata/telegraf/pull/6603): Add support for per output flush jitter.\n- [#6650](https://github.com/influxdata/telegraf/pull/6650): Add a nameable file tag to file input plugin.\n- [#6640](https://github.com/influxdata/telegraf/pull/6640): Add Splunk MultiMetric support.\n- [#6680](https://github.com/influxdata/telegraf/pull/6668): Add support for sending HTTP Basic Auth in influxdb input\n- [#5767](https://github.com/influxdata/telegraf/pull/5767): Add ability to configure the url tag in the prometheus input.\n- [#5767](https://github.com/influxdata/telegraf/pull/5767): Add prometheus metric_version=2 mapping to internal metrics/line protocol.\n- [#6703](https://github.com/influxdata/telegraf/pull/6703): Add prometheus metric_version=2 support to prometheus_client output.\n- [#6660](https://github.com/influxdata/telegraf/pull/6660): Add content_encoding compression support to socket_listener.\n- [#6689](https://github.com/influxdata/telegraf/pull/6689): Add high resolution metrics support to CloudWatch output.\n- [#6716](https://github.com/influxdata/telegraf/pull/6716): Add SReclaimable and SUnreclaim to mem input.\n- [#6695](https://github.com/influxdata/telegraf/pull/6695): Allow multiple certificates per file in x509_cert input.\n- [#6686](https://github.com/influxdata/telegraf/pull/6686): Add additional tags to the x509 input.\n- [#6703](https://github.com/influxdata/telegraf/pull/6703): Add batch data format support to file output.\n- [#6688](https://github.com/influxdata/telegraf/pull/6688): Support partition assignment strategy configuration in kafka_consumer.\n- [#6731](https://github.com/influxdata/telegraf/pull/6731): Add node type tag to mongodb input.\n- [#6669](https://github.com/influxdata/telegraf/pull/6669): Add uptime_ns field to mongodb input.\n- [#6735](https://github.com/influxdata/telegraf/pull/6735): Support resolution of symlinks in filecount input.\n- [#6746](https://github.com/influxdata/telegraf/pull/6746): Set message timestamp to the metric time in kafka output.\n- [#6740](https://github.com/influxdata/telegraf/pull/6740): Add base64decode operation to string processor.\n- [#6790](https://github.com/influxdata/telegraf/pull/6790): Add option to control collecting global variables to mysql input.\n\n### Bug Fixes\n\n- [#6484](https://github.com/influxdata/telegraf/issues/6484): Show correct default settings in mysql sample config.\n- [#6583](https://github.com/influxdata/telegraf/issues/6583): Use 1h or 3h rain values as appropriate in openweathermap input.\n- [#6573](https://github.com/influxdata/telegraf/issues/6573): Fix not a valid field error in Windows with nvidia input.\n- [#6614](https://github.com/influxdata/telegraf/issues/6614): Fix influxdb output serialization on connection closed.\n- [#6690](https://github.com/influxdata/telegraf/issues/6690): Fix ping skips remaining hosts after dns lookup error.\n- [#6684](https://github.com/influxdata/telegraf/issues/6684): Log mongodb oplog auth errors at debug level.\n- [#6705](https://github.com/influxdata/telegraf/issues/6705): Remove trailing underscore trimming from json flattener.\n- [#6421](https://github.com/influxdata/telegraf/issues/6421): Revert change causing cpu usage to be capped at 100 percent.\n- [#6523](https://github.com/influxdata/telegraf/issues/6523): Accept any media type in the prometheus input.\n- [#6769](https://github.com/influxdata/telegraf/issues/6769): Fix unix socket dial arguments in uwsgi input.\n- [#6757](https://github.com/influxdata/telegraf/issues/6757): Replace colon chars in prometheus output labels with metric_version=1.\n- [#6773](https://github.com/influxdata/telegraf/issues/6773): Set TrimLeadingSpace when TrimSpace is on in csv parser.\n\n## v1.12.6 [2019-11-19]\n\n### Bug Fixes\n\n- [#6666](https://github.com/influxdata/telegraf/issues/6666): Fix many plugin errors are logged at debug logging level.\n- [#6652](https://github.com/influxdata/telegraf/issues/6652): Use nanosecond precision in docker_log input.\n- [#6642](https://github.com/influxdata/telegraf/issues/6642): Fix interface option with method = native in ping input.\n- [#6680](https://github.com/influxdata/telegraf/pull/6680): Fix panic in mongodb input if shard connection pool stats are unreadable.\n\n## v1.12.5 [2019-11-12]\n\n### Bug Fixes\n\n- [#6576](https://github.com/influxdata/telegraf/issues/6576): Fix incorrect results in ping input plugin.\n- [#6610](https://github.com/influxdata/telegraf/pull/6610): Add missing character replacement to sql_instance tag.\n- [#6337](https://github.com/influxdata/telegraf/issues/6337): Change no metric error message to debug level in cloudwatch input.\n- [#6602](https://github.com/influxdata/telegraf/issues/6602): Add missing ServerProperties query to sqlserver input docs.\n- [#6643](https://github.com/influxdata/telegraf/pull/6643): Fix mongodb connections_total_created field loading.\n- [#6627](https://github.com/influxdata/telegraf/issues/6578): Fix metric creation when node is offline in jenkins input.\n- [#6649](https://github.com/influxdata/telegraf/issues/6615): Fix docker uptime_ns calculation when container has been restarted.\n- [#6647](https://github.com/influxdata/telegraf/issues/6646): Fix mysql field type conflict in conversion of gtid_mode to an integer.\n- [#5529](https://github.com/influxdata/telegraf/issues/5529): Fix mysql field type conflict with ssl_verify_depth and ssl_ctx_verify_depth.\n\n## v1.12.4 [2019-10-23]\n\n### Release Notes\n\n- Official packages built with Go 1.12.12.\n\n### Bug Fixes\n\n- [#6521](https://github.com/influxdata/telegraf/issues/6521): Fix metric generation with ping input native method.\n- [#6541](https://github.com/influxdata/telegraf/issues/6541): Exclude alias tag if unset from plugin internal stats.\n- [#6564](https://github.com/influxdata/telegraf/issues/6564): Fix socket_mode option in powerdns_recursor input.\n\n## v1.12.3 [2019-10-07]\n\n### Bug Fixes\n\n- [#6445](https://github.com/influxdata/telegraf/issues/6445): Use batch serialization format in exec output.\n- [#6455](https://github.com/influxdata/telegraf/issues/6455): Build official packages with Go 1.12.10.\n- [#6464](https://github.com/influxdata/telegraf/pull/6464): Use case insensitive serial number match in smart input.\n- [#6469](https://github.com/influxdata/telegraf/pull/6469): Add auth header only when env var is set.\n- [#6468](https://github.com/influxdata/telegraf/pull/6468): Fix running multiple mysql and sqlserver plugin instances.\n- [#6471](https://github.com/influxdata/telegraf/issues/6471): Fix database routing on retry with exclude_database_tag.\n- [#6488](https://github.com/influxdata/telegraf/issues/6488): Fix logging panic in exec input with nagios data format.\n\n## v1.12.2 [2019-09-24]\n\n### Bug Fixes\n\n- [#6386](https://github.com/influxdata/telegraf/issues/6386): Fix detection of layout timestamps in csv and json parser.\n- [#6394](https://github.com/influxdata/telegraf/issues/6394): Fix parsing of BATTDATE in apcupsd input.\n- [#6398](https://github.com/influxdata/telegraf/issues/6398): Keep boolean values listed in json_string_fields.\n- [#6393](https://github.com/influxdata/telegraf/issues/6393): Disable Go plugin support in official builds.\n- [#6391](https://github.com/influxdata/telegraf/issues/6391): Fix path handling issues in cisco_telemetry_gnmi.\n\n## v1.12.1 [2019-09-10]\n\n### Bug Fixes\n\n- [#6344](https://github.com/influxdata/telegraf/issues/6344): Fix depends on GLIBC_2.14 symbol version.\n- [#6329](https://github.com/influxdata/telegraf/issues/6329): Fix filecount for paths with trailing slash.\n- [#6331](https://github.com/influxdata/telegraf/issues/6331): Convert check state to an integer in icinga2 input.\n- [#6354](https://github.com/influxdata/telegraf/issues/6354): Fix could not mark message delivered error in kafka_consumer.\n- [#6362](https://github.com/influxdata/telegraf/issues/6362): Skip collection stats when disabled in mongodb input.\n- [#6366](https://github.com/influxdata/telegraf/issues/6366): Fix error reading closed response body on redirect in http_response.\n- [#6373](https://github.com/influxdata/telegraf/issues/6373): Fix apcupsd documentation to reflect plugin.\n- [#6375](https://github.com/influxdata/telegraf/issues/6375): Display retry log message only when retry after is received.\n\n## v1.12 [2019-09-03]\n\n### Release Notes\n\n- The cluster health related fields in the elasticsearch input have been split\n  out from the `elasticsearch_indices` measurement into the new\n  `elasticsearch_cluster_health_indices` measurement as they were originally\n  combined by error.\n\n### New Inputs\n\n- [apcupsd](/plugins/inputs/apcupsd/README.md) - Contributed by @jonaz\n- [docker_log](/plugins/inputs/docker_log/README.md) - Contributed by @prashanthjbabu\n- [fireboard](/plugins/inputs/fireboard/README.md) - Contributed by @ronnocol\n- [logstash](/plugins/inputs/logstash/README.md) - Contributed by @lkmcs @dmitryilyin @arkady-emelyanov\n- [marklogic](/plugins/inputs/marklogic/README.md) - Contributed by @influxdata\n- [openntpd](/plugins/inputs/openntpd/README.md) - Contributed by @aromeyer\n- [uwsgi](/plugins/inputs/uwsgi/README.md) - Contributed by @blaggacao\n\n### New Parsers\n\n- [form_urlencoded](/plugins/parsers/form_urlencoded/README.md) - Contributed by @byonchev\n\n### New Processors\n\n- [date](/plugins/processors/date/README.md) - Contributed by @influxdata\n- [pivot](/plugins/processors/pivot/README.md) - Contributed by @influxdata\n- [tag_limit](/plugins/processors/tag_limit/README.md) - Contributed by @memory\n- [unpivot](/plugins/processors/unpivot/README.md) - Contributed by @influxdata\n\n### New Outputs\n\n- [exec](/plugins/outputs/exec/README.md) - Contributed by @Jaeyo\n\n### Features\n\n- [#5842](https://github.com/influxdata/telegraf/pull/5842): Improve performance of wavefront serializer.\n- [#5863](https://github.com/influxdata/telegraf/pull/5863): Allow regex processor to append tag values.\n- [#5997](https://github.com/influxdata/telegraf/pull/5997): Add starttime field to phpfpm input.\n- [#5998](https://github.com/influxdata/telegraf/pull/5998): Add cluster name tag to elasticsearch indices.\n- [#6006](https://github.com/influxdata/telegraf/pull/6006): Add support for interface field in http_response input plugin.\n- [#5996](https://github.com/influxdata/telegraf/pull/5996): Add container uptime_ns in docker input plugin.\n- [#6016](https://github.com/influxdata/telegraf/pull/6016): Add better user-facing errors for API timeouts in docker input.\n- [#6027](https://github.com/influxdata/telegraf/pull/6027): Add TLS mutual auth support to jti_openconfig_telemetry input.\n- [#6053](https://github.com/influxdata/telegraf/pull/6053): Add support for ES 7.x to elasticsearch output.\n- [#6062](https://github.com/influxdata/telegraf/pull/6062): Add basic auth to prometheus input plugin.\n- [#6064](https://github.com/influxdata/telegraf/pull/6064): Add node roles tag to elasticsearch input.\n- [#5572](https://github.com/influxdata/telegraf/pull/5572): Support floats in statsd percentiles.\n- [#6050](https://github.com/influxdata/telegraf/pull/6050): Add native Go ping method to ping input plugin.\n- [#6074](https://github.com/influxdata/telegraf/pull/6074): Resume from last known offset in tail inputwhen reloading Telegraf.\n- [#6111](https://github.com/influxdata/telegraf/pull/6111): Add improved support for Azure SQL Database to sqlserver input.\n- [#6079](https://github.com/influxdata/telegraf/pull/6079): Add extra attributes for NVMe devices to smart input.\n- [#6084](https://github.com/influxdata/telegraf/pull/6084): Add docker_devicemapper measurement to docker input plugin.\n- [#6122](https://github.com/influxdata/telegraf/pull/6122): Add basic auth support to elasticsearch input.\n- [#6102](https://github.com/influxdata/telegraf/pull/6102): Support string field glob matching in json parser.\n- [#6101](https://github.com/influxdata/telegraf/pull/6101): Update gjson to allow multipath syntax in json parser.\n- [#6144](https://github.com/influxdata/telegraf/pull/6144): Add support for collecting SQL Requests to identify waits and blocking to sqlserver input.\n- [#6105](https://github.com/influxdata/telegraf/pull/6105): Collect k8s endpoints, ingress, and services in kube_inventory plugin.\n- [#6129](https://github.com/influxdata/telegraf/pull/6129): Add support for field/tag keys to strings processor.\n- [#6143](https://github.com/influxdata/telegraf/pull/6143): Add certificate verification status to x509_cert input.\n- [#6163](https://github.com/influxdata/telegraf/pull/6163): Support percentage value parsing in redis input.\n- [#6024](https://github.com/influxdata/telegraf/pull/6024): Load external Go plugins from --plugin-directory.\n- [#6184](https://github.com/influxdata/telegraf/pull/6184): Add ability to exclude db/bucket tag from influxdb outputs.\n- [#6137](https://github.com/influxdata/telegraf/pull/6137): Gather per collections stats in mongodb input plugin.\n- [#6195](https://github.com/influxdata/telegraf/pull/6195): Add TLS & credentials configuration for nats_consumer input plugin.\n- [#6194](https://github.com/influxdata/telegraf/pull/6194): Add support for enterprise repos to github plugin.\n- [#6060](https://github.com/influxdata/telegraf/pull/6060): Add Indices stats to elasticsearch input.\n- [#6189](https://github.com/influxdata/telegraf/pull/6189): Add left function to string processor.\n- [#6049](https://github.com/influxdata/telegraf/pull/6049): Add grace period for metrics late for aggregation.\n- [#4435](https://github.com/influxdata/telegraf/pull/4435): Add diff and non_negative_diff to basicstats aggregator.\n- [#6201](https://github.com/influxdata/telegraf/pull/6201): Add device tags to smart_attributes.\n- [#5719](https://github.com/influxdata/telegraf/pull/5719): Collect framework_offers and allocator metrics in mesos input.\n- [#6216](https://github.com/influxdata/telegraf/pull/6216): Add telegraf and go version to the internal input plugin.\n- [#6214](https://github.com/influxdata/telegraf/pull/6214): Update the number of logical CPUs dynamically in system plugin.\n- [#6259](https://github.com/influxdata/telegraf/pull/6259): Add darwin (macOS) builds to the release.\n- [#6241](https://github.com/influxdata/telegraf/pull/6241): Add configurable timeout setting to smart input.\n- [#6249](https://github.com/influxdata/telegraf/pull/6249): Add memory_usage field to procstat input plugin.\n- [#5971](https://github.com/influxdata/telegraf/pull/5971): Add support for custom attributes to vsphere input.\n- [#5926](https://github.com/influxdata/telegraf/pull/5926): Add cmdstat metrics to redis input.\n- [#6261](https://github.com/influxdata/telegraf/pull/6261): Add content_length metric to http_response input plugin.\n- [#6257](https://github.com/influxdata/telegraf/pull/6257): Add database_tag option to influxdb_listener to add database from query string.\n- [#6246](https://github.com/influxdata/telegraf/pull/6246): Add capability to limit TLS versions and cipher suites.\n- [#6266](https://github.com/influxdata/telegraf/pull/6266): Add topic_tag option to mqtt_consumer.\n- [#6207](https://github.com/influxdata/telegraf/pull/6207): Add ability to label inputs for logging.\n- [#6300](https://github.com/influxdata/telegraf/pull/6300): Add TLS support to nginx_plus, nginx_plus_api and nginx_vts.\n\n### Bug Fixes\n\n- [#5692](https://github.com/influxdata/telegraf/issues/5692): Fix sensor read error stops reporting of all sensors in temp input.\n- [#4356](https://github.com/influxdata/telegraf/issues/4356): Fix double pct replacement in sysstat input.\n- [#6004](https://github.com/influxdata/telegraf/issues/6004): Fix race in master node detection in elasticsearch input.\n- [#6100](https://github.com/influxdata/telegraf/issues/6100): Fix SSPI authentication not working in sqlserver input.\n- [#6142](https://github.com/influxdata/telegraf/issues/6142): Fix memory error panic in mqtt input.\n- [#6136](https://github.com/influxdata/telegraf/issues/6136): Support Kafka 2.3.0 consumer groups.\n- [#6232](https://github.com/influxdata/telegraf/issues/6232): Fix persistent session in mqtt_consumer.\n- [#6235](https://github.com/influxdata/telegraf/issues/6235): Fix finder inconsistencies in vsphere input.\n- [#6138](https://github.com/influxdata/telegraf/issues/6138): Fix parsing multiple metrics on the first line of tailed file.\n- [#2526](https://github.com/influxdata/telegraf/issues/2526): Send TERM to exec processes before sending KILL signal.\n- [#5326](https://github.com/influxdata/telegraf/issues/5326): Query oplog only when connected to a replica set.\n- [#6317](https://github.com/influxdata/telegraf/pull/6317): Use environment variables to locate Program Files on Windows.\n\n## v1.11.5 [2019-08-27]\n\n### Bug Fixes\n\n- [#6250](https://github.com/influxdata/telegraf/pull/6250): Update go-sql-driver/mysql driver to 1.4.1 to address auth issues.\n- [#6279](https://github.com/influxdata/telegraf/issues/6279): Return error status from --test if input plugins produce an error.\n- [#6309](https://github.com/influxdata/telegraf/issues/6309): Fix with multiple instances only last configuration is used in smart input.\n- [#6303](https://github.com/influxdata/telegraf/pull/6303): Build official packages with Go 1.12.9.\n- [#6234](https://github.com/influxdata/telegraf/issues/6234): Split out -w argument in iptables input.\n- [#6270](https://github.com/influxdata/telegraf/issues/6270): Add support for parked process state on Linux.\n- [#6287](https://github.com/influxdata/telegraf/issues/6287): Remove leading slash from rcon command.\n- [#6313](https://github.com/influxdata/telegraf/pull/6313): Allow jobs with dashes in the name in lustre2 input.\n\n## v1.11.4 [2019-08-06]\n\n### Bug Fixes\n\n- [#6200](https://github.com/influxdata/telegraf/pull/6200): Correct typo in kubernetes logsfs_available_bytes field.\n- [#6191](https://github.com/influxdata/telegraf/issues/6191): Skip floats that are NaN or Inf in Datadog output.\n- [#6209](https://github.com/influxdata/telegraf/issues/6209): Fix reload panic in socket_listener input plugin.\n\n## v1.11.3 [2019-07-23]\n\n### Bug Fixes\n\n- [#6054](https://github.com/influxdata/telegraf/issues/6054): Fix unable to reconnect after vCenter reboot in vsphere input.\n- [#6073](https://github.com/influxdata/telegraf/issues/6073): Handle unknown error in nvidia-smi output.\n- [#6121](https://github.com/influxdata/telegraf/pull/6121): Fix panic in statd input when processing datadog events.\n- [#6125](https://github.com/influxdata/telegraf/issues/6125): Treat empty array as successful parse in json parser.\n- [#6094](https://github.com/influxdata/telegraf/issues/6094): Add missing rcode and zonestat to bind input.\n- [#6114](https://github.com/influxdata/telegraf/issues/6114): Fix lustre2 input plugin config parse regression.\n- [#5894](https://github.com/influxdata/telegraf/issues/5894): Fix template pattern partial wildcard matching.\n- [#6151](https://github.com/influxdata/telegraf/issues/6151): Fix panic in github input.\n\n## v1.11.2 [2019-07-09]\n\n### Bug Fixes\n\n- [#6056](https://github.com/influxdata/telegraf/pull/6056): Fix source address ping flag on BSD.\n- [#6059](https://github.com/influxdata/telegraf/issues/6059): Fix value out of range error on 32-bit systems in bind input.\n- [#3573](https://github.com/influxdata/telegraf/issues/3573): Fix tail and logparser stop working after reload.\n- [#6077](https://github.com/influxdata/telegraf/pull/6077): Fix filecount path separator handling in Windows.\n- [#6075](https://github.com/influxdata/telegraf/issues/6075): Fix panic with empty datadog tag string.\n- [#6069](https://github.com/influxdata/telegraf/issues/6069): Apply topic filter to partition metrics in burrow input.\n\n## v1.11.1 [2019-06-25]\n\n### Bug Fixes\n\n- [#5980](https://github.com/influxdata/telegraf/issues/5980): Cannot set mount_points option in disk input.\n- [#5983](https://github.com/influxdata/telegraf/issues/5983): Omit keys when creating measurement names for GNMI telemetry.\n- [#5972](https://github.com/influxdata/telegraf/issues/5972): Don't consider pid of 0 when using systemd lookup in procstat.\n- [#5807](https://github.com/influxdata/telegraf/issues/5807): Skip 404 error reporting in nginx_plus_api input.\n- [#5999](https://github.com/influxdata/telegraf/issues/5999): Fix panic if pool_mode column does not exist.\n- [#6019](https://github.com/influxdata/telegraf/issues/6019): Add missing container_id field to docker_container_status metrics.\n- [#5742](https://github.com/influxdata/telegraf/issues/5742): Ignore error when utmp is missing in system input.\n- [#6032](https://github.com/influxdata/telegraf/issues/6032): Add device, serial_no, and wwn tags to synthetic attributes.\n- [#6012](https://github.com/influxdata/telegraf/issues/6012): Fix parsing of remote tcp address in statsd input.\n\n## v1.11 [2019-06-11]\n\n### Release Notes\n\n- The `uptime_format` field in the system input has been deprecated, use the\n  `uptime` field instead.\n- The `cloudwatch` input has been updated to use a more efficient API, it now\n  requires `GetMetricData` permissions instead of `GetMetricStatistics`.  The\n  `units` tag is not available from this API and is no longer collected.\n\n### New Inputs\n\n- [bind](/plugins/inputs/bind/README.md) - Contributed by @dswarbrick & @danielllek\n- [cisco_telemetry_gnmi](/plugins/inputs/cisco_telemetry_gnmi/README.md) - Contributed by @sbyx\n- [cisco_telemetry_mdt](/plugins/inputs/cisco_telemetry_mdt/README.md) - Contributed by @sbyx\n- [ecs](/plugins/inputs/ecs/README.md) - Contributed by @rbtr\n- [github](/plugins/inputs/github/README.md) - Contributed by @influxdata\n- [openweathermap](/plugins/inputs/openweathermap/README.md) - Contributed by @regel\n- [powerdns_recursor](/plugins/inputs/powerdns_recursor/README.md) - Contributed by @dupondje\n\n### New Aggregators\n\n- [final](/plugins/aggregators/final/README.md) - Contributed by @oplehto\n\n### New Outputs\n\n- [syslog](/plugins/outputs/syslog/README.md) - Contributed by @javicrespo\n- [health](/plugins/outputs/health/README.md) - Contributed by @influxdata\n\n### New Serializers\n\n- [wavefront](/plugins/serializers/wavefront/README.md) - Contributed by @puckpuck\n\n### Features\n\n- [#5556](https://github.com/influxdata/telegraf/pull/5556): Add TTL field to ping input.\n- [#5569](https://github.com/influxdata/telegraf/pull/5569): Add hexadecimal string to integer conversion to converter processor.\n- [#5601](https://github.com/influxdata/telegraf/pull/5601): Add support for multiple line text and perfdata to nagios parser.\n- [#5648](https://github.com/influxdata/telegraf/pull/5648): Allow env vars ${} expansion syntax in configuration file.\n- [#5641](https://github.com/influxdata/telegraf/pull/5641): Add option to reset buckets on flush to histogram aggregator.\n- [#5664](https://github.com/influxdata/telegraf/pull/5664): Add option to use strict sanitization rules to wavefront output.\n- [#5697](https://github.com/influxdata/telegraf/pull/5697): Add namespace restriction to prometheus input plugin.\n- [#5681](https://github.com/influxdata/telegraf/pull/5681): Add cmdline tag to procstat input.\n- [#5704](https://github.com/influxdata/telegraf/pull/5704): Support verbose query param in ping endpoint of influxdb_listener.\n- [#5713](https://github.com/influxdata/telegraf/pull/5713): Enhance HTTP connection options for phpfpm input plugin.\n- [#5544](https://github.com/influxdata/telegraf/pull/5544): Use more efficient GetMetricData API to collect cloudwatch metrics.\n- [#5544](https://github.com/influxdata/telegraf/pull/5544): Allow selection of collected statistic types in cloudwatch input.\n- [#5757](https://github.com/influxdata/telegraf/pull/5757): Speed up interface stat collection in net input.\n- [#5769](https://github.com/influxdata/telegraf/pull/5769): Add pagefault data to procstat input plugin.\n- [#5760](https://github.com/influxdata/telegraf/pull/5760): Add option to set permissions for unix domain sockets to socket_listener.\n- [#5585](https://github.com/influxdata/telegraf/pull/5585): Add cli support for outputting sections of the config.\n- [#5770](https://github.com/influxdata/telegraf/pull/5770): Add service-display-name option for use with Windows service.\n- [#5778](https://github.com/influxdata/telegraf/pull/5778): Add support for log rotation.\n- [#5765](https://github.com/influxdata/telegraf/pull/5765): Support more drive types in smart input.\n- [#5829](https://github.com/influxdata/telegraf/pull/5829): Add support for HTTP basic auth to solr input.\n- [#5791](https://github.com/influxdata/telegraf/pull/5791): Add support for datadog events to statsd input.\n- [#5817](https://github.com/influxdata/telegraf/pull/5817): Allow devices option to match against devlinks.\n- [#5855](https://github.com/influxdata/telegraf/pull/5855): Support tags in enum processor.\n- [#5830](https://github.com/influxdata/telegraf/pull/5830): Add support for gzip compression to amqp plugins.\n- [#5831](https://github.com/influxdata/telegraf/pull/5831): Support passive queue declaration in amqp_consumer.\n- [#5901](https://github.com/influxdata/telegraf/pull/5901): Set user agent in stackdriver output.\n- [#5885](https://github.com/influxdata/telegraf/pull/5885): Extend metrics collected from Nvidia GPUs.\n- [#5547](https://github.com/influxdata/telegraf/pull/5547): Add file rotation support to the file output.\n- [#5955](https://github.com/influxdata/telegraf/pull/5955): Add source tag to hddtemp plugin.\n\n### Bug Fixes\n\n- [#5692](https://github.com/influxdata/telegraf/pull/5692): Temperature input plugin stops working when WiFi is turned off.\n- [#5631](https://github.com/influxdata/telegraf/pull/5631): Create Windows service only when specified or in service manager.\n- [#5730](https://github.com/influxdata/telegraf/pull/5730): Don't start telegraf when stale pidfile found.\n- [#5477](https://github.com/influxdata/telegraf/pull/5477): Support Minecraft server 1.13 and newer in minecraft input.\n- [#4098](https://github.com/influxdata/telegraf/issues/4098): Fix inline table support in configuration file.\n- [#1598](https://github.com/influxdata/telegraf/issues/1598): Fix multi-line basic strings support in configuration file.\n- [#5746](https://github.com/influxdata/telegraf/issues/5746): Verify a process passed by pid_file exists in procstat input.\n- [#5455](https://github.com/influxdata/telegraf/issues/5455): Fix unsupported pkt type error in pgbouncer.\n- [#5771](https://github.com/influxdata/telegraf/pull/5771): Fix only one job per storage target reported in lustre2 input.\n- [#5796](https://github.com/influxdata/telegraf/issues/5796): Set default timeout of 5s in fibaro input.\n- [#5835](https://github.com/influxdata/telegraf/issues/5835): Fix docker input does not parse image name correctly.\n- [#5661](https://github.com/influxdata/telegraf/issues/5661): Fix direct exchange routing key in amqp output.\n- [#5819](https://github.com/influxdata/telegraf/issues/5819): Fix scale set resource id with azure_monitor output.\n- [#5883](https://github.com/influxdata/telegraf/issues/5883): Skip invalid power times in apex_neptune input.\n- [#3485](https://github.com/influxdata/telegraf/issues/3485): Fix sqlserver connection closing on error.\n- [#5917](https://github.com/influxdata/telegraf/issues/5917): Fix toml option name in nginx_upstream_check.\n- [#5920](https://github.com/influxdata/telegraf/issues/5920): Fixed datastore name mapping in vsphere input.\n- [#5879](https://github.com/influxdata/telegraf/issues/5879): Fix multiple SIGHUP causes Telegraf to shutdown.\n- [#5891](https://github.com/influxdata/telegraf/issues/5891): Fix connection leak in influxdb outputs on reload.\n- [#5858](https://github.com/influxdata/telegraf/issues/5858): Fix batch fails when single metric is unserializable.\n- [#5536](https://github.com/influxdata/telegraf/issues/5536): Log a warning on write if the metric buffer has overflowed.\n\n## v1.10.4 [2019-05-14]\n\n### Bug Fixes\n\n- [#5764](https://github.com/influxdata/telegraf/pull/5764): Fix race condition in the Wavefront parser.\n- [#5783](https://github.com/influxdata/telegraf/pull/5783): Create telegraf user in pre-install rpm scriptlet.\n- [#5792](https://github.com/influxdata/telegraf/pull/5792): Don't discard metrics on forbidden error in influxdb_v2 output.\n- [#5803](https://github.com/influxdata/telegraf/issues/5803): Fix http output cannot set Host header.\n- [#5619](https://github.com/influxdata/telegraf/issues/5619): Fix interval estimation in vsphere input.\n- [#5782](https://github.com/influxdata/telegraf/pull/5782): Skip lines with missing refid in ntpq input.\n- [#5755](https://github.com/influxdata/telegraf/issues/5755): Add support for hex values to ipmi_sensor input.\n- [#5824](https://github.com/influxdata/telegraf/issues/5824): Fix parse of unix timestamp with more than ns precision.\n- [#5836](https://github.com/influxdata/telegraf/issues/5836): Restore field name case in interrupts input.\n\n## v1.10.3 [2019-04-16]\n\n### Bug Fixes\n\n- [#5680](https://github.com/influxdata/telegraf/pull/5680): Allow colons in metric names in prometheus_client output.\n- [#5716](https://github.com/influxdata/telegraf/pull/5716): Set log directory attributes in rpm spec.\n\n## v1.10.2 [2019-04-02]\n\n### Release Notes\n\n- String fields no longer have leading and trailing quotation marks removed in\n  the grok parser.  If you are capturing quoted strings you may need to update\n  the patterns.\n\n### Bug Fixes\n\n- [#5612](https://github.com/influxdata/telegraf/pull/5612): Fix deadlock when Telegraf is aligning aggregators.\n- [#5523](https://github.com/influxdata/telegraf/issues/5523): Fix missing cluster stats in ceph input.\n- [#5566](https://github.com/influxdata/telegraf/pull/5566): Fix reading major and minor block devices identifiers in diskio input.\n- [#5607](https://github.com/influxdata/telegraf/pull/5607): Add owned directories to rpm package spec.\n- [#4998](https://github.com/influxdata/telegraf/issues/4998): Fix last character removed from string field in grok parser.\n- [#5632](https://github.com/influxdata/telegraf/pull/5632): Fix drop tracking of metrics removed with aggregator drop_original.\n- [#5540](https://github.com/influxdata/telegraf/pull/5540): Fix open file error handling in file output.\n- [#5626](https://github.com/influxdata/telegraf/issues/5626): Fix plugin name in influxdb_v2 output logging.\n- [#5621](https://github.com/influxdata/telegraf/issues/5621): Fix basedir check and parent dir extraction in filecount input.\n- [#5618](https://github.com/influxdata/telegraf/issues/5618): Listen before leaving start in statsd.\n- [#5595](https://github.com/influxdata/telegraf/issues/5595): Fix aggregator window alignment.\n- [#5637](https://github.com/influxdata/telegraf/issues/5637): Fix panic during shutdown of multiple aggregators.\n- [#5642](https://github.com/influxdata/telegraf/issues/5642): Fix parsing of kube config certificate-authority-data in prometheus input.\n- [#5636](https://github.com/influxdata/telegraf/issues/5636): Fix tags applied to wrong metric on parse error.\n- [#5522](https://github.com/influxdata/telegraf/issues/5522): Remove tags that would create invalid label names in prometheus output.\n\n## v1.10.1 [2019-03-19]\n\n### Bug Fixes\n\n- [#5448](https://github.com/influxdata/telegraf/issues/5448): Show error when TLS configuration cannot be loaded.\n- [#5543](https://github.com/influxdata/telegraf/pull/5543): Add Base64-encoding/decoding for Google Cloud PubSub plugins.\n- [#5565](https://github.com/influxdata/telegraf/issues/5565): Fix type compatibility in vsphere plugin with use_int_samples option.\n- [#5492](https://github.com/influxdata/telegraf/issues/5492): Fix vsphere input shows failed task in vCenter.\n- [#5530](https://github.com/influxdata/telegraf/issues/5530): Fix invalid measurement name and skip column in csv parser.\n- [#5589](https://github.com/influxdata/telegraf/issues/5589): Fix system input causing high cpu usage on Raspbian.\n- [#5575](https://github.com/influxdata/telegraf/issues/5575): Don't add empty healthcheck tags to consul input.\n\n## v1.10 [2019-03-05]\n\n### New Inputs\n\n- [cloud_pubsub](/plugins/inputs/cloud_pubsub/README.md) - Contributed by @emilymye\n- [cloud_pubsub_push](/plugins/inputs/cloud_pubsub_push/README.md) - Contributed by @influxdata\n- [kinesis_consumer](/plugins/inputs/kinesis_consumer/README.md) - Contributed by @influxdata\n- [kube_inventory](/plugins/inputs/kube_inventory/README.md) - Contributed by @influxdata\n- [neptune_apex](/plugins/inputs/neptune_apex/README.md) - Contributed by @MaxRenaud\n- [nginx_upstream_check](/plugins/inputs/nginx_upstream_check/README.md) - Contributed by @dmitryilyin\n- [multifile](/plugins/inputs/multifile/README.md) - Contributed by @martin2250\n- [stackdriver](/plugins/inputs/stackdriver/README.md) - Contributed by @WuHan0608\n\n### New Outputs\n\n- [cloud_pubsub](/plugins/outputs/cloud_pubsub/README.md) - Contributed by @emilymye\n\n### New Serializers\n\n- [nowmetric](/plugins/serializers/nowmetric/README.md) - Contributed by @JefMuller\n- [carbon2](/plugins/serializers/carbon2/README.md) - Contributed by @frankreno\n\n### Features\n\n- [#4345](https://github.com/influxdata/telegraf/pull/4345): Allow for force gathering ES cluster stats.\n- [#5047](https://github.com/influxdata/telegraf/pull/5047): Add support for unix and unix_ms timestamps to csv parser.\n- [#5038](https://github.com/influxdata/telegraf/pull/5038): Add ability to tag metrics with topic in kafka_consumer.\n- [#5024](https://github.com/influxdata/telegraf/pull/5024): Add option to store cpu as a tag in interrupts input.\n- [#5074](https://github.com/influxdata/telegraf/pull/5074): Add support for sending a request body to http input.\n- [#5069](https://github.com/influxdata/telegraf/pull/5069): Add running field to procstat_lookup.\n- [#5116](https://github.com/influxdata/telegraf/pull/5116): Include DEVLINKS in available diskio udev properties.\n- [#5149](https://github.com/influxdata/telegraf/pull/5149): Add micro and nanosecond unix timestamp support to JSON parser.\n- [#5160](https://github.com/influxdata/telegraf/pull/5160): Add support for basic auth to couchdb input.\n- [#5161](https://github.com/influxdata/telegraf/pull/5161): Add support in wavefront output for the Wavefront Direct Ingestion API.\n- [#5168](https://github.com/influxdata/telegraf/pull/5168): Allow counting float values in valuecounter aggregator.\n- [#5177](https://github.com/influxdata/telegraf/pull/5177): Add log send and redo queue fields to sqlserver input.\n- [#5113](https://github.com/influxdata/telegraf/pull/5113): Improve scalability of vsphere input.\n- [#5210](https://github.com/influxdata/telegraf/pull/5210): Add read and write op per second fields to ceph input.\n- [#5214](https://github.com/influxdata/telegraf/pull/5214): Add configurable timeout to varnish input.\n- [#5273](https://github.com/influxdata/telegraf/pull/5273): Add flush_total_time_ns and additional wired tiger fields to mongodb input.\n- [#5295](https://github.com/influxdata/telegraf/pull/5295): Support passing bearer token directly in k8s input.\n- [#5294](https://github.com/influxdata/telegraf/pull/5294): Support passing bearer token directly in prometheus input.\n- [#5292](https://github.com/influxdata/telegraf/pull/5292): Add option to report input timestamp in prometheus output.\n- [#5234](https://github.com/influxdata/telegraf/pull/5234): Add Linux mipsle packages.\n- [#5382](https://github.com/influxdata/telegraf/pull/5382): Support unix_us and unix_ns timestamp format in csv parser.\n- [#5391](https://github.com/influxdata/telegraf/pull/5391): Add resource type and resource label support to stackdriver output.\n- [#5396](https://github.com/influxdata/telegraf/pull/5396): Add internal metric for line too long in influxdb_listener.\n- [#4892](https://github.com/influxdata/telegraf/pull/4892): Add option to set retain flag on messages to mqtt output.\n- [#5165](https://github.com/influxdata/telegraf/pull/5165): Add resource path based filtering to vsphere input.\n- [#5417](https://github.com/influxdata/telegraf/pull/5417): Add rcode tag and field to dns_query input.\n- [#5453](https://github.com/influxdata/telegraf/pull/5453): Support Azure Sovereign Environments with endpoint_url option.\n- [#5472](https://github.com/influxdata/telegraf/pull/5472): Support configuring a default timezone in JSON parser.\n- [#5482](https://github.com/influxdata/telegraf/pull/5482): Add ceph_health metrics to ceph input.\n- [#5488](https://github.com/influxdata/telegraf/pull/5488): Add option to disable unique timestamp adjustment in grok parser.\n- [#5473](https://github.com/influxdata/telegraf/pull/5473): Add mutual TLS support to prometheus_client output.\n- [#4308](https://github.com/influxdata/telegraf/pull/4308): Add additional metrics to rabbitmq input.\n- [#5388](https://github.com/influxdata/telegraf/pull/5388): Add multicast support to socket_listener input.\n- [#5490](https://github.com/influxdata/telegraf/pull/5490): Add tag based routing in influxdb/influxdb_v2 outputs.\n- [#5533](https://github.com/influxdata/telegraf/pull/5533): Allow grok parser to produce metrics with no fields.\n\n### Bug Fixes\n\n- [#4610](https://github.com/influxdata/telegraf/pull/4610): Fix initscript removes pidfile of restarted Telegraf process.\n- [#5320](https://github.com/influxdata/telegraf/pull/5320): Use datacenter option spelling in consul input.\n- [#5316](https://github.com/influxdata/telegraf/pull/5316): Remove auth from /ping route in influxdb_listener.\n- [#5304](https://github.com/influxdata/telegraf/issues/5304): Fix x509_cert input stops checking certs after first error.\n- [#5404](https://github.com/influxdata/telegraf/issues/5404): Group stackdriver requests to send one point per timeseries.\n- [#5449](https://github.com/influxdata/telegraf/issues/5449): Log permission error and ignore in filecount input.\n- [#5497](https://github.com/influxdata/telegraf/pull/5497): Create log file in append mode.\n- [#5325](https://github.com/influxdata/telegraf/issues/5325): Ignore tracking for metrics added to aggregator.\n- [#5514](https://github.com/influxdata/telegraf/issues/5514): Fix panic when rejecting empty batch.\n- [#5518](https://github.com/influxdata/telegraf/pull/5518): Fix conversion from string float to integer.\n- [#5431](https://github.com/influxdata/telegraf/pull/5431): Sort metrics by timestamp in prometheus output.\n\n## v1.9.5 [2019-02-26]\n\n### Bug Fixes\n\n- [#5315](https://github.com/influxdata/telegraf/issues/5315): Skip string fields when writing to stackdriver output.\n- [#5364](https://github.com/influxdata/telegraf/issues/5364): Send metrics in ascending time order in stackdriver output.\n- [#5117](https://github.com/influxdata/telegraf/issues/5117): Use systemd in Amazon Linux 2 rpm.\n- [#4988](https://github.com/influxdata/telegraf/issues/4988): Set deadlock priority in sqlserver input.\n- [#5403](https://github.com/influxdata/telegraf/issues/5403): Remove error log when snmp6 directory does not exists with nstat input.\n- [#5437](https://github.com/influxdata/telegraf/issues/5437): Host not added when using custom arguments in ping plugin.\n- [#5438](https://github.com/influxdata/telegraf/issues/5438): Fix InfluxDB output UDP line splitting.\n- [#5456](https://github.com/influxdata/telegraf/issues/5456): Disable results by row in azuredb query.\n- [#5277](https://github.com/influxdata/telegraf/issues/5277): Add backwards compatibility fields in ceph usage and pool stats.\n\n## v1.9.4 [2019-02-05]\n\n### Bug Fixes\n\n- [#5334](https://github.com/influxdata/telegraf/issues/5334): Fix skip_rows and skip_columns options in csv parser.\n- [#5181](https://github.com/influxdata/telegraf/issues/5181): Always send basic auth in jenkins input.\n- [#5346](https://github.com/influxdata/telegraf/pull/5346): Build official packages with Go 1.11.5.\n- [#5368](https://github.com/influxdata/telegraf/issues/5368): Fix definition of multiple syslog plugins.\n\n## v1.9.3 [2019-01-22]\n\n### Bug Fixes\n\n- [#5261](https://github.com/influxdata/telegraf/pull/5261):  Fix arithmetic overflow in sqlserver input.\n- [#5194](https://github.com/influxdata/telegraf/issues/5194): Fix latest metrics not sent first when output fails.\n- [#5285](https://github.com/influxdata/telegraf/issues/5285): Fix amqp_consumer stops consuming when it receives unparsable messages.\n- [#5281](https://github.com/influxdata/telegraf/issues/5281): Fix prometheus input not detecting added and removed pods.\n- [#5215](https://github.com/influxdata/telegraf/issues/5215): Remove userinfo from cluster tag in couchbase.\n- [#5298](https://github.com/influxdata/telegraf/issues/5298): Fix internal_write buffer_size not reset on timed writes.\n\n## v1.9.2 [2019-01-08]\n\n### Bug Fixes\n\n- [#5130](https://github.com/influxdata/telegraf/pull/5130): Increase varnishstat timeout.\n- [#5135](https://github.com/influxdata/telegraf/pull/5135): Remove storage calculation for non Azure managed instances and add server version.\n- [#5083](https://github.com/influxdata/telegraf/pull/5083): Fix error sending empty tag value in azure_monitor output.\n- [#5143](https://github.com/influxdata/telegraf/issues/5143): Fix panic with prometheus input plugin on shutdown.\n- [#4482](https://github.com/influxdata/telegraf/issues/4482): Support non-transparent framing of syslog messages.\n- [#5151](https://github.com/influxdata/telegraf/issues/5151): Apply global and plugin level metric modifications before filtering.\n- [#5167](https://github.com/influxdata/telegraf/pull/5167): Fix num_remapped_pgs field in ceph plugin.\n- [#5179](https://github.com/influxdata/telegraf/issues/5179): Add PDH_NO_DATA to known counter error codes in win_perf_counters.\n- [#5170](https://github.com/influxdata/telegraf/issues/5170): Fix amqp_consumer stops consuming on empty message.\n- [#4906](https://github.com/influxdata/telegraf/issues/4906): Fix multiple replace tables not working in strings processor.\n- [#5219](https://github.com/influxdata/telegraf/issues/5219): Allow non local udp connections in net_response.\n- [#5218](https://github.com/influxdata/telegraf/issues/5218): Fix toml option names in parser processor.\n- [#5225](https://github.com/influxdata/telegraf/issues/5225): Fix panic in docker input with bad endpoint.\n- [#5209](https://github.com/influxdata/telegraf/issues/5209): Fix original metric modified by aggregator filters.\n\n## v1.9.1 [2018-12-11]\n\n### Bug Fixes\n\n- [#5006](https://github.com/influxdata/telegraf/issues/5006): Fix boolean handling in splunkmetric serializer.\n- [#5046](https://github.com/influxdata/telegraf/issues/5046): Set default config values in jenkins input.\n- [#4664](https://github.com/influxdata/telegraf/issues/4664): Fix server connection and document stats in mongodb input.\n- [#5010](https://github.com/influxdata/telegraf/issues/5010): Add X-Requested-By header to graylog input.\n- [#5052](https://github.com/influxdata/telegraf/issues/5052): Fix metric memory not freed from the metric buffer on write.\n- [#3817](https://github.com/influxdata/telegraf/issues/3817): Add support for client tls certificates in postgresql inputs.\n- [#5082](https://github.com/influxdata/telegraf/issues/5082): Prevent panic when marking the offset in kafka_consumer.\n- [#5084](https://github.com/influxdata/telegraf/issues/5084): Add early metrics to aggregator and honor drop_original setting.\n- [#5112](https://github.com/influxdata/telegraf/pull/5112): Use -W flag on bsd variants in ping input.\n- [#5114](https://github.com/influxdata/telegraf/issues/5114): Allow delta metrics in wavefront parser.\n\n## v1.9 [2018-11-20]\n\n### Release Notes\n\n- The `http_listener` input plugin has been renamed to `influxdb_listener` and\n  use of the original name is deprecated.  The new name better describes the\n  intended use of the plugin as a InfluxDB relay.  For general purpose\n  transfer of metrics in any format via HTTP, it is recommended to use\n  `http_listener_v2` instead.\n\n- Input plugins are no longer limited from adding metrics when the output is\n  writing, and new metrics will move into the metric buffer as needed.  This\n  will provide more robust degradation and recovery when writing to a slow\n  output at high throughput.\n\n  To avoid over consumption when reading from queue consumers: `kafka_consumer`,\n  `amqp_consumer`, `mqtt_consumer`, `nats_consumer`, and `nsq_consumer` use\n  the new option `max_undelivered_messages` to limit the number of outstanding\n  unwritten metrics.\n\n### New Inputs\n\n- [http_listener_v2](/plugins/inputs/http_listener_v2/README.md) - Contributed by @jul1u5\n- [ipvs](/plugins/inputs/ipvs/README.md) - Contributed by @amoghe\n- [jenkins](/plugins/inputs/jenkins/README.md) - Contributed by @influxdata & @lpic10\n- [nginx_plus_api](/plugins/inputs/nginx_plus_api/README.md) - Contributed by @Bugagazavr\n- [nginx_vts](/plugins/inputs/nginx_vts/README.md) - Contributed by @monder\n- [wireless](/plugins/inputs/wireless/README.md) - Contributed by @jamesmaidment\n\n### New Outputs\n\n- [stackdriver](/plugins/outputs/stackdriver/README.md) - Contributed by @jamesmaidment\n\n### Features\n\n- [#4686](https://github.com/influxdata/telegraf/pull/4686): Add replace function to strings processor.\n- [#4754](https://github.com/influxdata/telegraf/pull/4754): Query servers in parallel in dns_query input.\n- [#4753](https://github.com/influxdata/telegraf/pull/4753): Add ability to define a custom service name when installing as a Windows service.\n- [#4703](https://github.com/influxdata/telegraf/pull/4703): Add support for IPv6 in the ping plugin.\n- [#4781](https://github.com/influxdata/telegraf/pull/4781): Add new config for csv column explicit type conversion.\n- [#4800](https://github.com/influxdata/telegraf/pull/4800): Add an option to specify a custom datadog URL.\n- [#4803](https://github.com/influxdata/telegraf/pull/4803): Use non-allocating field and tag accessors in datadog output.\n- [#4752](https://github.com/influxdata/telegraf/pull/4752): Add per-directory file counts in the filecount input.\n- [#4811](https://github.com/influxdata/telegraf/pull/4811): Add windows service name lookup to procstat input.\n- [#4807](https://github.com/influxdata/telegraf/pull/4807): Add entity-body compression to http output.\n- [#4838](https://github.com/influxdata/telegraf/pull/4838): Add telegraf version to User-Agent header.\n- [#4864](https://github.com/influxdata/telegraf/pull/4864): Use DescribeStreamSummary in place of ListStreams in kinesis output.\n- [#4852](https://github.com/influxdata/telegraf/pull/4852): Add ability to specify bytes options as strings with units.\n- [#3903](https://github.com/influxdata/telegraf/pull/3903): Add support for TLS configuration in NSQ input.\n- [#4914](https://github.com/influxdata/telegraf/pull/4914): Collect additional stats in memcached input.\n- [#3847](https://github.com/influxdata/telegraf/pull/3847): Add wireless input plugin.\n- [#4934](https://github.com/influxdata/telegraf/pull/4934): Add LUN to datasource translation in vsphere input.\n- [#4798](https://github.com/influxdata/telegraf/pull/4798): Allow connecting to prometheus via unix socket.\n- [#4920](https://github.com/influxdata/telegraf/pull/4920): Add scraping for Prometheus endpoint in Kubernetes.\n- [#4938](https://github.com/influxdata/telegraf/pull/4938): Add per output flush_interval, metric_buffer_limit and metric_batch_size.\n\n### Bug Fixes\n\n- [#4950](https://github.com/influxdata/telegraf/pull/4950): Remove the time_key from the field values in JSON parser.\n- [#3968](https://github.com/influxdata/telegraf/issues/3968): Fix input time rounding when using a custom interval.\n- [#4938](https://github.com/influxdata/telegraf/pull/4938): Fix potential deadlock or leaked resources on restart/reload.\n- [#2919](https://github.com/influxdata/telegraf/pull/2919): Fix outputs block inputs when batch size is reached.\n- [#4789](https://github.com/influxdata/telegraf/issues/4789): Fix potential missing datastore metrics in vSphere plugin.\n- [#4982](https://github.com/influxdata/telegraf/issues/4982): Log warning when wireless plugin is used on unsupported platform.\n- [#4965](https://github.com/influxdata/telegraf/issues/4965): Handle non-tls columns for mysql input.\n- [#4983](https://github.com/influxdata/telegraf/issues/4983): Fix panic in influxdb_listener when using gzip encoding.\n\n## v1.8.3 [2018-10-30]\n\n### Bug Fixes\n\n- [#4873](https://github.com/influxdata/telegraf/pull/4873): Add DN attributes as tags in x509_cert input to avoid series overwrite.\n- [#4921](https://github.com/influxdata/telegraf/issues/4921): Prevent connection leak by closing unused connections in amqp output.\n- [#4904](https://github.com/influxdata/telegraf/issues/4904): Use default partition key when tag does not exist in kinesis output.\n- [#4901](https://github.com/influxdata/telegraf/pull/4901): Log the correct error in jti_openconfig.\n- [#4937](https://github.com/influxdata/telegraf/pull/4937): Handle panic when ipmi_sensor input gets bad input.\n- [#4930](https://github.com/influxdata/telegraf/pull/4930): Don't add unserializable fields to jolokia2 input.\n- [#4866](https://github.com/influxdata/telegraf/pull/4866): Fix version check in postgresql_extensible.\n\n## v1.8.2 [2018-10-17]\n\n### Bug Fixes\n\n- [#4844](https://github.com/influxdata/telegraf/pull/4844): Update write path to match updated InfluxDB v2 API.\n- [#4840](https://github.com/influxdata/telegraf/pull/4840): Fix missing timeouts in vsphere input.\n- [#4851](https://github.com/influxdata/telegraf/pull/4851): Support uint fields in aerospike input.\n- [#4854](https://github.com/influxdata/telegraf/pull/4854): Use container name from list if no name in container stats.\n- [#4850](https://github.com/influxdata/telegraf/pull/4850): Prevent panic in filecount input on error in file stat.\n- [#4846](https://github.com/influxdata/telegraf/pull/4846): Fix mqtt_consumer connect and reconnect.\n- [#4849](https://github.com/influxdata/telegraf/pull/4849): Fix panic in logparser input.\n- [#4869](https://github.com/influxdata/telegraf/pull/4869): Lower authorization errors to debug level in mongodb input.\n- [#4875](https://github.com/influxdata/telegraf/pull/4875): Return correct response code on ping input.\n- [#4874](https://github.com/influxdata/telegraf/pull/4874): Fix segfault in x509_cert input.\n\n## v1.8.1 [2018-10-03]\n\n### Bug Fixes\n\n- [#4750](https://github.com/influxdata/telegraf/pull/4750): Fix hardware_type may be truncated in sqlserver input.\n- [#4723](https://github.com/influxdata/telegraf/issues/4723): Improve performance in basicstats aggregator.\n- [#4747](https://github.com/influxdata/telegraf/pull/4747): Add hostname to TLS config for SNI support.\n- [#4675](https://github.com/influxdata/telegraf/issues/4675): Don't add tags with empty values to opentsdb output.\n- [#4765](https://github.com/influxdata/telegraf/pull/4765): Fix panic during network error in vsphere input.\n- [#4766](https://github.com/influxdata/telegraf/pull/4766): Unify http_listener error response with InfluxDB.\n- [#4769](https://github.com/influxdata/telegraf/pull/4769): Add UUID to VMs in vSphere input.\n- [#4758](https://github.com/influxdata/telegraf/issues/4758): Skip tags with empty values in cloudwatch output.\n- [#4783](https://github.com/influxdata/telegraf/issues/4783): Fix missing non-realtime samples in vSphere input.\n- [#4799](https://github.com/influxdata/telegraf/pull/4799): Fix case of timezone/grok_timezone options.\n\n## v1.8 [2018-09-21]\n\n### New Inputs\n\n- [activemq](./plugins/inputs/activemq/README.md) - Contributed by @mlabouardy\n- [beanstalkd](./plugins/inputs/beanstalkd/README.md) - Contributed by @44px\n- [filecount](./plugins/inputs/filecount/README.md) - Contributed by @sometimesfood\n- [file](./plugins/inputs/file/README.md) - Contributed by @maxunt\n- [icinga2](./plugins/inputs/icinga2/README.md) - Contributed by @mlabouardy\n- [kibana](./plugins/inputs/kibana/README.md) - Contributed by @lpic10\n- [pgbouncer](./plugins/inputs/pgbouncer/README.md) - Contributed by @nerzhul\n- [temp](./plugins/inputs/temp/README.md) - Contributed by @pytimer\n- [tengine](./plugins/inputs/tengine/README.md) - Contributed by @ertaoxu\n- [vsphere](./plugins/inputs/vsphere/README.md) - Contributed by @prydin\n- [x509_cert](./plugins/inputs/x509_cert/README.md) - Contributed by @jtyr\n\n### New Processors\n\n- [enum](./plugins/processors/enum/README.md) - Contributed by @KarstenSchnitter\n- [parser](./plugins/processors/parser/README.md) - Contributed by @Ayrdrie & @maxunt\n- [rename](./plugins/processors/rename/README.md) - Contributed by @goldibex\n- [strings](./plugins/processors/strings/README.md) - Contributed by @bsmaldon\n\n### New Aggregators\n\n- [valuecounter](./plugins/aggregators/valuecounter/README.md) - Contributed by @piotr1212\n\n### New Outputs\n\n- [azure_monitor](./plugins/outputs/azure_monitor/README.md) - Contributed by @influxdata\n- [influxdb_v2](./plugins/outputs/influxdb_v2/README.md) - Contributed by @influxdata\n\n### New Parsers\n\n- [csv](/plugins/parsers/csv/README.md) - Contributed by @maxunt\n- [grok](/plugins/parsers/grok/README.md) - Contributed by @maxunt\n- [logfmt](/plugins/parsers/logfmt/README.md) - Contributed by @Ayrdrie & @maxunt\n- [wavefront](/plugins/parsers/wavefront/README.md) - Contributed by @puckpuck\n\n### New Serializers\n\n- [splunkmetric](/plugins/serializers/splunkmetric/README.md) - Contributed by @ronnocol\n\n### Features\n\n- [#4236](https://github.com/influxdata/telegraf/pull/4236): Add SSL/TLS support to redis input.\n- [#4160](https://github.com/influxdata/telegraf/pull/4160): Add tengine input plugin.\n- [#4262](https://github.com/influxdata/telegraf/pull/4262): Add power draw field to nvidia_smi plugin.\n- [#4271](https://github.com/influxdata/telegraf/pull/4271): Add support for solr 7 to the solr input.\n- [#4281](https://github.com/influxdata/telegraf/pull/4281): Add owner tag on partitions in burrow input.\n- [#4259](https://github.com/influxdata/telegraf/pull/4259): Add container status tag to docker input.\n- [#3523](https://github.com/influxdata/telegraf/pull/3523): Add valuecounter aggregator plugin.\n- [#4307](https://github.com/influxdata/telegraf/pull/4307): Add new measurement with results of pgrep lookup to procstat input.\n- [#4311](https://github.com/influxdata/telegraf/pull/4311): Add support for comma in logparser timestamp format.\n- [#4292](https://github.com/influxdata/telegraf/pull/4292): Add path tag to tail input plugin.\n- [#4322](https://github.com/influxdata/telegraf/pull/4322): Add log message when tail is added or removed from a file.\n- [#4267](https://github.com/influxdata/telegraf/pull/4267): Add option to use of counter time in win perf counters.\n- [#4343](https://github.com/influxdata/telegraf/pull/4343): Add energy and power field and device id tag to fibaro input.\n- [#4347](https://github.com/influxdata/telegraf/pull/4347): Add http path configuration for OpenTSDB output.\n- [#4352](https://github.com/influxdata/telegraf/pull/4352): Gather IPMI metrics concurrently.\n- [#4362](https://github.com/influxdata/telegraf/pull/4362): Add mongo document and connection metrics.\n- [#3772](https://github.com/influxdata/telegraf/pull/3772): Add enum processor plugin.\n- [#4386](https://github.com/influxdata/telegraf/pull/4386): Add user tag to procstat input.\n- [#4403](https://github.com/influxdata/telegraf/pull/4403): Add support for multivalue metrics to collectd parser.\n- [#4418](https://github.com/influxdata/telegraf/pull/4418): Add support for setting kafka client id.\n- [#4332](https://github.com/influxdata/telegraf/pull/4332): Add file input plugin and grok parser.\n- [#4320](https://github.com/influxdata/telegraf/pull/4320): Improve cloudwatch output performance.\n- [#3768](https://github.com/influxdata/telegraf/pull/3768): Add x509_cert input plugin.\n- [#4471](https://github.com/influxdata/telegraf/pull/4471): Add IPSIpAddress syntax to ipaddr conversion in snmp plugin.\n- [#4363](https://github.com/influxdata/telegraf/pull/4363): Add filecount input plugin.\n- [#4485](https://github.com/influxdata/telegraf/pull/4485): Add support for configuring an AWS endpoint_url.\n- [#4491](https://github.com/influxdata/telegraf/pull/4491): Send all messages before waiting for results in kafka output.\n- [#4492](https://github.com/influxdata/telegraf/pull/4492): Add support for lz4 compression to kafka output.\n- [#4450](https://github.com/influxdata/telegraf/pull/4450): Split multiple sensor keys in ipmi input.\n- [#4364](https://github.com/influxdata/telegraf/pull/4364): Support StatisticValues in cloudwatch output plugin.\n- [#4431](https://github.com/influxdata/telegraf/pull/4431): Add ip restriction for the prometheus_client output.\n- [#3918](https://github.com/influxdata/telegraf/pull/3918): Add pgbouncer input plugin.\n- [#2689](https://github.com/influxdata/telegraf/pull/2689): Add ActiveMQ input plugin.\n- [#4402](https://github.com/influxdata/telegraf/pull/4402): Add wavefront parser plugin.\n- [#4528](https://github.com/influxdata/telegraf/pull/4528): Add rename processor plugin.\n- [#4537](https://github.com/influxdata/telegraf/pull/4537): Add message 'max_bytes' configuration to kafka input.\n- [#4546](https://github.com/influxdata/telegraf/pull/4546): Add gopsutil meminfo fields to mem plugin.\n- [#4285](https://github.com/influxdata/telegraf/pull/4285): Document how to parse telegraf logs.\n- [#4542](https://github.com/influxdata/telegraf/pull/4542): Use dep v0.5.0.\n- [#4433](https://github.com/influxdata/telegraf/pull/4433): Add ability to set measurement from matched text in grok parser.\n- [#4565](https://github.com/influxdata/telegraf/pull/4465): Drop message batches in kafka output if too large.\n- [#4579](https://github.com/influxdata/telegraf/pull/4579): Add support for static and random routing keys in kafka output.\n- [#4539](https://github.com/influxdata/telegraf/pull/4539): Add logfmt parser plugin.\n- [#4551](https://github.com/influxdata/telegraf/pull/4551): Add parser processor plugin.\n- [#4559](https://github.com/influxdata/telegraf/pull/4559): Add Icinga2 input plugin.\n- [#4351](https://github.com/influxdata/telegraf/pull/4351): Add name, time, path and string field options to JSON parser.\n- [#4571](https://github.com/influxdata/telegraf/pull/4571): Add forwarded records to sqlserver input.\n- [#4585](https://github.com/influxdata/telegraf/pull/4585): Add Kibana input plugin.\n- [#4439](https://github.com/influxdata/telegraf/pull/4439): Add csv parser plugin.\n- [#4598](https://github.com/influxdata/telegraf/pull/4598): Add read_buffer_size option to statsd input.\n- [#4089](https://github.com/influxdata/telegraf/pull/4089): Add azure_monitor output plugin.\n- [#4628](https://github.com/influxdata/telegraf/pull/4628): Add queue_durability parameter to amqp_consumer input.\n- [#4476](https://github.com/influxdata/telegraf/pull/4476): Add strings processor.\n- [#4536](https://github.com/influxdata/telegraf/pull/4536): Add OAuth2 support to HTTP output plugin.\n- [#4633](https://github.com/influxdata/telegraf/pull/4633): Add Unix epoch timestamp support for JSON parser.\n- [#4657](https://github.com/influxdata/telegraf/pull/4657): Add options for basic auth to haproxy input.\n- [#4411](https://github.com/influxdata/telegraf/pull/4411): Add temp input plugin.\n- [#4272](https://github.com/influxdata/telegraf/pull/4272): Add Beanstalkd input plugin.\n- [#4669](https://github.com/influxdata/telegraf/pull/4669): Add means to specify server password for redis input.\n- [#4339](https://github.com/influxdata/telegraf/pull/4339): Add Splunk Metrics serializer.\n- [#4141](https://github.com/influxdata/telegraf/pull/4141): Add input plugin for VMware vSphere.\n- [#4667](https://github.com/influxdata/telegraf/pull/4667): Align metrics window to interval in cloudwatch input.\n- [#4642](https://github.com/influxdata/telegraf/pull/4642): Improve Azure Managed Instance support + more in sqlserver input.\n- [#4682](https://github.com/influxdata/telegraf/pull/4682): Allow alternate binaries for iptables input plugin.\n- [#4645](https://github.com/influxdata/telegraf/pull/4645): Add influxdb_v2 output plugin.\n\n### Bug Fixes\n\n- [#3438](https://github.com/influxdata/telegraf/issues/3438): Fix divide by zero in logparser input.\n- [#4499](https://github.com/influxdata/telegraf/issues/4499): Fix instance and object name in performance counters with backslashes.\n- [#4646](https://github.com/influxdata/telegraf/issues/4646): Reset/flush saved contents from bad metric.\n- [#4520](https://github.com/influxdata/telegraf/issues/4520): Document all supported cli arguments.\n- [#4674](https://github.com/influxdata/telegraf/pull/4674): Log access denied opening a service at debug level in win_services.\n- [#4588](https://github.com/influxdata/telegraf/issues/4588): Add support for Kafka 2.0.\n- [#4087](https://github.com/influxdata/telegraf/issues/4087): Fix nagios parser does not support ranges in performance data.\n- [#4088](https://github.com/influxdata/telegraf/issues/4088): Fix nagios parser does not strip quotes from performance data.\n- [#4688](https://github.com/influxdata/telegraf/issues/4688): Fix null value crash in postgresql_extensible input.\n- [#4681](https://github.com/influxdata/telegraf/pull/4681): Remove the startup authentication check from the cloudwatch output.\n- [#4644](https://github.com/influxdata/telegraf/issues/4644): Support tailing files created after startup in tail input.\n- [#4706](https://github.com/influxdata/telegraf/issues/4706): Fix csv format configuration loading.\n\n## v1.7.4 [2018-08-29]\n\n### Bug Fixes\n\n- [#4534](https://github.com/influxdata/telegraf/pull/4534): Skip unserializable metric in influxDB UDP output.\n- [#4554](https://github.com/influxdata/telegraf/pull/4554): Fix powerdns input tests.\n- [#4584](https://github.com/influxdata/telegraf/pull/4584): Fix burrow_group offset calculation for burrow input.\n- [#4550](https://github.com/influxdata/telegraf/pull/4550): Add result_code value for errors running ping command.\n- [#4605](https://github.com/influxdata/telegraf/pull/4605): Remove timeout deadline for udp syslog input.\n- [#4601](https://github.com/influxdata/telegraf/issues/4601): Ensure channel closed if an error occurs in cgroup input.\n- [#4544](https://github.com/influxdata/telegraf/issues/4544): Fix sending of basic auth credentials in http output.\n- [#4526](https://github.com/influxdata/telegraf/issues/4526): Use the correct GOARM value in the armel package.\n\n## v1.7.3 [2018-08-07]\n\n### Bug Fixes\n\n- [#4434](https://github.com/influxdata/telegraf/issues/4434): Reduce required docker API version.\n- [#4498](https://github.com/influxdata/telegraf/pull/4498): Keep leading whitespace for messages in syslog input.\n- [#4470](https://github.com/influxdata/telegraf/issues/4470): Skip bad entries on interrupt input.\n- [#4501](https://github.com/influxdata/telegraf/issues/4501): Preserve metric type when using filters in output plugins.\n- [#3794](https://github.com/influxdata/telegraf/issues/3794): Fix error message if URL is unparsable in influxdb output.\n- [#4059](https://github.com/influxdata/telegraf/issues/4059): Use explicit zpool properties to fix parse error on FreeBSD 11.2.\n- [#4514](https://github.com/influxdata/telegraf/pull/4514): Lock buffer when adding metrics.\n\n## v1.7.2 [2018-07-18]\n\n### Bug Fixes\n\n- [#4381](https://github.com/influxdata/telegraf/issues/4381): Use localhost as default server tag in zookeeper input.\n- [#4374](https://github.com/influxdata/telegraf/issues/4374): Don't set values when pattern doesn't match in regex processor.\n- [#4416](https://github.com/influxdata/telegraf/issues/4416): Fix output format of printer processor.\n- [#4422](https://github.com/influxdata/telegraf/issues/4422): Fix metric can have duplicate field.\n- [#4389](https://github.com/influxdata/telegraf/issues/4389): Return error if NewRequest fails in http output.\n- [#4335](https://github.com/influxdata/telegraf/issues/4335): Reset read deadline for syslog input.\n- [#4375](https://github.com/influxdata/telegraf/issues/4375): Exclude cached memory on docker input plugin.\n\n## v1.7.1 [2018-07-03]\n\n### Bug Fixes\n\n- [#4277](https://github.com/influxdata/telegraf/pull/4277): Treat sigterm as a clean shutdown signal.\n- [#4284](https://github.com/influxdata/telegraf/pull/4284): Fix selection of tags under nested objects in the JSON parser.\n- [#4135](https://github.com/influxdata/telegraf/issues/4135): Fix postfix input handling multi-level queues.\n- [#4334](https://github.com/influxdata/telegraf/pull/4334): Fix syslog timestamp parsing with single digit day of month.\n- [#2910](https://github.com/influxdata/telegraf/issues/2910): Handle mysql input variations in the user_statistics collecting.\n- [#4293](https://github.com/influxdata/telegraf/issues/4293): Fix minmax and basicstats aggregators to use uint64.\n- [#4290](https://github.com/influxdata/telegraf/issues/4290): Document swap input plugin.\n- [#4316](https://github.com/influxdata/telegraf/issues/4316): Fix incorrect precision being applied to metric in http_listener.\n\n## v1.7 [2018-06-12]\n\n### Release Notes\n\n- The `cassandra` input plugin has been deprecated in favor of the `jolokia2`\n  input plugin which is much more configurable and more performant.  There is\n  an [example configuration](./plugins/inputs/jolokia2/examples) to help you\n  get started.\n\n- For plugins supporting TLS, you can now specify the certificate and keys\n  using `tls_ca`, `tls_cert`, `tls_key`.  These options behave the same as\n  the, now deprecated, `ssl` forms.\n\n### New Inputs\n\n- [aurora](./plugins/inputs/aurora/README.md) - Contributed by @influxdata\n- [burrow](./plugins/inputs/burrow/README.md) - Contributed by @arkady-emelyanov\n- [fibaro](./plugins/inputs/fibaro/README.md) - Contributed by @dynek\n- [jti_openconfig_telemetry](./plugins/inputs/jti_openconfig_telemetry/README.md) - Contributed by @ajhai\n- [mcrouter](./plugins/inputs/mcrouter/README.md) - Contributed by @cthayer\n- [nvidia_smi](./plugins/inputs/nvidia_smi/README.md) - Contributed by @jackzampolin\n- [syslog](./plugins/inputs/syslog/README.md) - Contributed by @influxdata\n\n### New Processors\n\n- [converter](./plugins/processors/converter/README.md) - Contributed by @influxdata\n- [regex](./plugins/processors/regex/README.md) - Contributed by @44px\n- [topk](./plugins/processors/topk/README.md) - Contributed by @mirath\n\n### New Outputs\n\n- [http](./plugins/outputs/http/README.md) - Contributed by @Dark0096\n- [application_insights](./plugins/outputs/application_insights/README.md): Contribute by @karolz-ms\n\n### Features\n\n- [#3964](https://github.com/influxdata/telegraf/pull/3964): Add repl_oplog_window_sec metric to mongodb input.\n- [#3819](https://github.com/influxdata/telegraf/pull/3819): Add per-host shard metrics in mongodb input.\n- [#3999](https://github.com/influxdata/telegraf/pull/3999): Skip files with leading `..` in config directory.\n- [#4021](https://github.com/influxdata/telegraf/pull/4021): Add TLS support to socket_writer and socket_listener plugins.\n- [#4025](https://github.com/influxdata/telegraf/pull/4025): Add snmp input option to strip non fixed length index suffixes.\n- [#4035](https://github.com/influxdata/telegraf/pull/4035): Add server version tag to docker input.\n- [#4044](https://github.com/influxdata/telegraf/pull/4044): Add support for LeoFS 1.4 to leofs input.\n- [#4068](https://github.com/influxdata/telegraf/pull/4068): Add parameter to force the interval of gather for sysstat.\n- [#3877](https://github.com/influxdata/telegraf/pull/3877): Support busybox ping in the ping input.\n- [#4077](https://github.com/influxdata/telegraf/pull/4077): Add input plugin for McRouter.\n- [#4096](https://github.com/influxdata/telegraf/pull/4096): Add topk processor plugin.\n- [#4114](https://github.com/influxdata/telegraf/pull/4114): Add cursor metrics to mongodb input.\n- [#3455](https://github.com/influxdata/telegraf/pull/3455): Add tag/integer pair for result to net_response.\n- [#4010](https://github.com/influxdata/telegraf/pull/3455): Add application_insights output plugin.\n- [#4167](https://github.com/influxdata/telegraf/pull/4167): Added several important elasticsearch cluster health metrics.\n- [#4094](https://github.com/influxdata/telegraf/pull/4094): Add batch mode to mqtt output.\n- [#4158](https://github.com/influxdata/telegraf/pull/4158): Add aurora input plugin.\n- [#3839](https://github.com/influxdata/telegraf/pull/3839): Add regex processor plugin.\n- [#4165](https://github.com/influxdata/telegraf/pull/4165): Add support for Graphite 1.1 tags.\n- [#4162](https://github.com/influxdata/telegraf/pull/4162): Add timeout option to sensors input.\n- [#3489](https://github.com/influxdata/telegraf/pull/3489): Add burrow input plugin.\n- [#3969](https://github.com/influxdata/telegraf/pull/3969): Add option to unbound module to use threads as tags.\n- [#4183](https://github.com/influxdata/telegraf/pull/4183): Add support for TLS and username/password auth to aerospike input.\n- [#4190](https://github.com/influxdata/telegraf/pull/4190): Add special syslog timestamp parser to grok parser that uses current year.\n- [#4181](https://github.com/influxdata/telegraf/pull/4181): Add syslog input plugin.\n- [#4212](https://github.com/influxdata/telegraf/pull/4212): Print the enabled aggregator and processor plugins on startup.\n- [#3994](https://github.com/influxdata/telegraf/pull/3994): Add static routing_key option to amqp output.\n- [#3995](https://github.com/influxdata/telegraf/pull/3995): Add passive mode exchange declaration option to amqp consumer input.\n- [#4216](https://github.com/influxdata/telegraf/pull/4216): Add counter fields to pf input.\n\n### Bug Fixes\n\n- [#4018](https://github.com/influxdata/telegraf/pull/4018): Write to working file outputs if any files are not writeable.\n- [#4036](https://github.com/influxdata/telegraf/pull/4036): Add all win_perf_counters fields for a series in a single metric.\n- [#4118](https://github.com/influxdata/telegraf/pull/4118): Report results of dns_query instead of 0ms on timeout.\n- [#4155](https://github.com/influxdata/telegraf/pull/4155): Add consul service tags to metric.\n- [#2879](https://github.com/influxdata/telegraf/issues/2879): Fix wildcards and multi instance processes in win_perf_counters.\n- [#2468](https://github.com/influxdata/telegraf/issues/2468): Fix crash on 32-bit Windows in win_perf_counters.\n- [#4198](https://github.com/influxdata/telegraf/issues/4198): Fix win_perf_counters not collecting at every interval.\n- [#4227](https://github.com/influxdata/telegraf/issues/4227): Use same flags for all BSD family ping variants.\n- [#4266](https://github.com/influxdata/telegraf/issues/4266): Remove tags with empty values from Wavefront output.\n\n## v1.6.4 [2018-06-05]\n\n### Bug Fixes\n\n- [#4203](https://github.com/influxdata/telegraf/issues/4203): Fix snmp overriding of auto-configured table fields.\n- [#4218](https://github.com/influxdata/telegraf/issues/4218): Fix uint support in cloudwatch output.\n- [#4188](https://github.com/influxdata/telegraf/pull/4188): Fix documentation of instance_name option in varnish input.\n- [#4195](https://github.com/influxdata/telegraf/pull/4195): Revert to previous aerospike library version due to memory leak.\n\n## v1.6.3 [2018-05-21]\n\n### Bug Fixes\n\n- [#4127](https://github.com/influxdata/telegraf/issues/4127): Fix intermittent panic in aerospike input.\n- [#4130](https://github.com/influxdata/telegraf/issues/4130): Fix connection leak in jolokia2_agent.\n- [#4136](https://github.com/influxdata/telegraf/pull/4130): Fix jolokia2 timeout parsing.\n- [#4142](https://github.com/influxdata/telegraf/pull/4142): Fix error parsing dropwizard metrics.\n- [#4149](https://github.com/influxdata/telegraf/issues/4149): Fix librato output support for uint and bool.\n- [#4176](https://github.com/influxdata/telegraf/pull/4176): Fix waitgroup deadlock if url is incorrect in apache input.\n\n## v1.6.2 [2018-05-08]\n\n### Bug Fixes\n\n- [#4078](https://github.com/influxdata/telegraf/pull/4078): Use same timestamp for fields in system input.\n- [#4091](https://github.com/influxdata/telegraf/pull/4091): Fix handling of uint64 in datadog output.\n- [#4099](https://github.com/influxdata/telegraf/pull/4099): Ignore UTF8 BOM in JSON parser.\n- [#4104](https://github.com/influxdata/telegraf/issues/4104): Fix case for slave metrics in mysql input.\n- [#4110](https://github.com/influxdata/telegraf/issues/4110): Fix uint support in cratedb output.\n\n## v1.6.1 [2018-04-23]\n\n### Bug Fixes\n\n- [#3835](https://github.com/influxdata/telegraf/issues/3835): Report mem input fields as gauges instead counters.\n- [#4030](https://github.com/influxdata/telegraf/issues/4030): Fix graphite outputs unsigned integers in wrong format.\n- [#4043](https://github.com/influxdata/telegraf/issues/4043): Report available fields if utmp is unreadable.\n- [#4039](https://github.com/influxdata/telegraf/issues/4039): Fix potential \"no fields\" error writing to outputs.\n- [#4037](https://github.com/influxdata/telegraf/issues/4037): Fix uptime reporting in system input when ran inside docker.\n- [#3750](https://github.com/influxdata/telegraf/issues/3750): Fix mem input \"cannot allocate memory\" error on FreeBSD based systems.\n- [#4056](https://github.com/influxdata/telegraf/pull/4056): Fix duplicate tags when overriding an existing tag.\n- [#4062](https://github.com/influxdata/telegraf/pull/4062): Add server argument as first argument in unbound input.\n- [#4063](https://github.com/influxdata/telegraf/issues/4063): Fix handling of floats with multiple leading zeroes.\n- [#4064](https://github.com/influxdata/telegraf/issues/4064): Return errors in mongodb SSL/TLS configuration.\n\n## v1.6 [2018-04-16]\n\n### Release Notes\n\n- The `mysql` input plugin has been updated fix a number of type conversion\n  issues.  This may cause a `field type error` when inserting into InfluxDB due\n  the change of types.\n\n  To address this we have introduced a new `metric_version` option to control\n  enabling the new format.  For in depth recommendations on upgrading please\n  reference the [mysql plugin documentation](./plugins/inputs/mysql/README.md#metric-version).\n\n  It is encouraged to migrate to the new model when possible as the old version\n  is deprecated and will be removed in a future version.\n\n- The `postgresql` plugins now defaults to using a persistent connection to the database.\n  In environments where TCP connections are terminated the `max_lifetime`\n  setting should be set less than the collection `interval` to prevent errors.\n\n- The `sqlserver` input plugin has a new query and data model that can be enabled\n  by setting `query_version = 2`.  It is encouraged to migrate to the new\n  model when possible as the old version is deprecated and will be removed in\n  a future version.\n\n- An option has been added to the `openldap` input plugin that reverses metric\n  name to improve grouping.  This change is enabled when `reverse_metric_names = true`\n  is set.  It is encouraged to enable this option when possible as the old\n  ordering is deprecated.\n\n- The new `http` input configured with `data_format = \"json\"` can perform the\n  same task as the, now deprecated, `httpjson` input.\n\n### New Inputs\n\n- [http](./plugins/inputs/http/README.md) - Thanks to @grange74\n- [ipset](./plugins/inputs/ipset/README.md) - Thanks to @sajoupa\n- [nats](./plugins/inputs/nats/README.md) - Thanks to @mjs & @levex\n\n### New Processors\n\n- [override](./plugins/processors/override/README.md) - Thanks to @KarstenSchnitter\n\n### New Parsers\n\n- [dropwizard](./docs/DATA_FORMATS_INPUT.md#dropwizard) - Thanks to @atzoum\n\n### Features\n\n- [#3551](https://github.com/influxdata/telegraf/pull/3551): Add health status mapping from string to int in elasticsearch input.\n- [#3580](https://github.com/influxdata/telegraf/pull/3580): Add control over which stats to gather in basicstats aggregator.\n- [#3596](https://github.com/influxdata/telegraf/pull/3596): Add messages_delivered_get to rabbitmq input.\n- [#3632](https://github.com/influxdata/telegraf/pull/3632): Add wired field to mem input.\n- [#3619](https://github.com/influxdata/telegraf/pull/3619): Add support for gathering exchange metrics to the rabbitmq input.\n- [#3565](https://github.com/influxdata/telegraf/pull/3565): Add support for additional metrics on Linux in zfs input.\n- [#3524](https://github.com/influxdata/telegraf/pull/3524): Add available_entropy field to kernel input plugin.\n- [#3643](https://github.com/influxdata/telegraf/pull/3643): Add user privilege level setting to IPMI sensors.\n- [#2701](https://github.com/influxdata/telegraf/pull/2701): Use persistent connection to postgresql database.\n- [#2846](https://github.com/influxdata/telegraf/pull/2846): Add support for dropwizard input format.\n- [#3666](https://github.com/influxdata/telegraf/pull/3666): Add container health metrics to docker input.\n- [#3687](https://github.com/influxdata/telegraf/pull/3687): Add support for using globs in devices list of diskio input plugin.\n- [#2754](https://github.com/influxdata/telegraf/pull/2754): Allow running as console application on Windows.\n- [#3703](https://github.com/influxdata/telegraf/pull/3703): Add listener counts and node running status to rabbitmq input.\n- [#3674](https://github.com/influxdata/telegraf/pull/3674): Add NATS Monitoring Input Plugin.\n- [#3702](https://github.com/influxdata/telegraf/pull/3702): Add ability to select which queues will be gathered in rabbitmq input.\n- [#3726](https://github.com/influxdata/telegraf/pull/3726): Add support for setting bsd source address to the ping input.\n- [#3346](https://github.com/influxdata/telegraf/pull/3346): Add Ipset input plugin.\n- [#3719](https://github.com/influxdata/telegraf/pull/3719): Add TLS and HTTP basic auth to prometheus_client output.\n- [#3618](https://github.com/influxdata/telegraf/pull/3618): Add new sqlserver output data model.\n- [#3559](https://github.com/influxdata/telegraf/pull/3559): Add native Go method for finding pids to procstat.\n- [#3722](https://github.com/influxdata/telegraf/pull/3722): Add additional metrics and reverse metric names option to openldap.\n- [#3769](https://github.com/influxdata/telegraf/pull/3769): Add TLS support to the mesos input plugin.\n- [#3546](https://github.com/influxdata/telegraf/pull/3546): Add http input plugin.\n- [#3781](https://github.com/influxdata/telegraf/pull/3781): Add keep alive support to the TCP mode of statsd.\n- [#3783](https://github.com/influxdata/telegraf/pull/3783): Support deadline in ping plugin.\n- [#3765](https://github.com/influxdata/telegraf/pull/3765): Add option to disable labels in prometheus output for string fields.\n- [#3808](https://github.com/influxdata/telegraf/pull/3808): Add shard server stats to the mongodb input plugin.\n- [#3713](https://github.com/influxdata/telegraf/pull/3713): Add server option to unbound plugin.\n- [#3804](https://github.com/influxdata/telegraf/pull/3804): Convert boolean metric values to float in datadog output.\n- [#3799](https://github.com/influxdata/telegraf/pull/3799): Add Solr 3 compatibility.\n- [#3797](https://github.com/influxdata/telegraf/pull/3797): Add sum stat to basicstats aggregator.\n- [#3626](https://github.com/influxdata/telegraf/pull/3626): Add ability to override proxy from environment in http response.\n- [#3853](https://github.com/influxdata/telegraf/pull/3853): Add host to ping timeout log message.\n- [#3773](https://github.com/influxdata/telegraf/pull/3773): Add override processor.\n- [#3814](https://github.com/influxdata/telegraf/pull/3814): Add status_code and result tags and result_type field to http_response input.\n- [#3880](https://github.com/influxdata/telegraf/pull/3880): Added config flag to skip collection of network protocol metrics.\n- [#3927](https://github.com/influxdata/telegraf/pull/3927): Add TLS support to kapacitor input.\n- [#3496](https://github.com/influxdata/telegraf/pull/3496): Add HTTP basic auth support to the http_listener input.\n- [#3452](https://github.com/influxdata/telegraf/issues/3452): Tags in output InfluxDB Line Protocol are now sorted.\n- [#3631](https://github.com/influxdata/telegraf/issues/3631): InfluxDB Line Protocol parser now accepts DOS line endings.\n- [#2496](https://github.com/influxdata/telegraf/issues/2496): An option has been added to skip database creation in the InfluxDB output.\n- [#3366](https://github.com/influxdata/telegraf/issues/3366): Add support for connecting to InfluxDB over a unix domain socket.\n- [#3946](https://github.com/influxdata/telegraf/pull/3946): Add optional unsigned integer support to the influx data format.\n- [#3811](https://github.com/influxdata/telegraf/pull/3811): Add TLS support to zookeeper input.\n- [#2737](https://github.com/influxdata/telegraf/issues/2737): Add filters for container state to docker input.\n\n### Bug Fixes\n\n- [#1896](https://github.com/influxdata/telegraf/issues/1896): Fix various mysql data type conversions.\n- [#3810](https://github.com/influxdata/telegraf/issues/3810): Fix metric buffer limit in internal plugin after reload.\n- [#3801](https://github.com/influxdata/telegraf/issues/3801): Fix panic in http_response on invalid regex.\n- [#3973](https://github.com/influxdata/telegraf/issues/3873): Fix socket_listener setting ReadBufferSize on tcp sockets.\n- [#1575](https://github.com/influxdata/telegraf/issues/1575): Add tag for target url to phpfpm input.\n- [#3868](https://github.com/influxdata/telegraf/issues/3868): Fix cannot unmarshal object error in DC/OS input.\n- [#3648](https://github.com/influxdata/telegraf/issues/3648): Fix InfluxDB output not able to reconnect when server address changes.\n- [#3957](https://github.com/influxdata/telegraf/issues/3957): Fix parsing of dos line endings in the smart input.\n- [#3754](https://github.com/influxdata/telegraf/issues/3754): Fix precision truncation when no timestamp included.\n- [#3655](https://github.com/influxdata/telegraf/issues/3655): Fix SNMPv3 connection with Cisco ASA 5515 in snmp input.\n- [#3981](https://github.com/influxdata/telegraf/pull/3981): Export all vars defined in /etc/default/telegraf.\n- [#4004](https://github.com/influxdata/telegraf/issues/4004): Allow grok pattern to contain newlines.\n\n## v1.5.3 [2018-03-14]\n\n### Bug Fixes\n\n- [#3729](https://github.com/influxdata/telegraf/issues/3729): Set path to / if HOST_MOUNT_PREFIX matches full path.\n- [#3739](https://github.com/influxdata/telegraf/issues/3739): Remove userinfo from url tag in prometheus input.\n- [#3778](https://github.com/influxdata/telegraf/issues/3778): Fix ping plugin not reporting zero durations.\n- [#3697](https://github.com/influxdata/telegraf/issues/3697): Disable keepalive in mqtt output to prevent deadlock.\n- [#3786](https://github.com/influxdata/telegraf/pull/3786): Fix collation difference in sqlserver input.\n- [#3871](https://github.com/influxdata/telegraf/pull/3871): Fix uptime metric in passenger input plugin.\n- [#3851](https://github.com/influxdata/telegraf/issues/3851): Add output of stderr in case of error to exec log message.\n\n## v1.5.2 [2018-01-30]\n\n### Bug Fixes\n\n- [#3684](https://github.com/influxdata/telegraf/pull/3684): Ignore empty lines in Graphite plaintext.\n- [#3604](https://github.com/influxdata/telegraf/issues/3604): Fix index out of bounds error in solr input plugin.\n- [#3680](https://github.com/influxdata/telegraf/pull/3680): Reconnect before sending graphite metrics if disconnected.\n- [#3693](https://github.com/influxdata/telegraf/pull/3693): Align aggregator period with internal ticker to avoid skipping metrics.\n- [#3629](https://github.com/influxdata/telegraf/issues/3629): Fix a potential deadlock when using aggregators.\n- [#3697](https://github.com/influxdata/telegraf/issues/3697): Limit wait time for writes in mqtt output.\n- [#3698](https://github.com/influxdata/telegraf/issues/3698): Revert change in graphite output where dot in field key was replaced by underscore.\n- [#3710](https://github.com/influxdata/telegraf/issues/3710): Add timeout to wavefront output write.\n- [#3725](https://github.com/influxdata/telegraf/issues/3725): Exclude master_replid fields from redis input.\n\n## v1.5.1 [2018-01-10]\n\n### Bug Fixes\n\n- [#3624](https://github.com/influxdata/telegraf/pull/3624): Fix name error in jolokia2_agent sample config.\n- [#3625](https://github.com/influxdata/telegraf/pull/3625): Fix DC/OS login expiration time.\n- [#3593](https://github.com/influxdata/telegraf/pull/3593): Set Content-Type charset in influxdb output and allow it be overridden.\n- [#3594](https://github.com/influxdata/telegraf/pull/3594): Document permissions setup for postfix input.\n- [#3633](https://github.com/influxdata/telegraf/pull/3633): Fix deliver_get field in rabbitmq input.\n- [#3607](https://github.com/influxdata/telegraf/issues/3607): Escape environment variables during config toml parsing.\n\n## v1.5 [2017-12-14]\n\n### New Plugins\n\n- [basicstats](./plugins/aggregators/basicstats/README.md) - Thanks to @toni-moreno\n- [bond](./plugins/inputs/bond/README.md) - Thanks to @ildarsv\n- [cratedb](./plugins/outputs/cratedb/README.md) - Thanks to @felixge\n- [dcos](./plugins/inputs/dcos/README.md) - Thanks to @influxdata\n- [jolokia2](./plugins/inputs/jolokia2/README.md) - Thanks to @dylanmei\n- [nginx_plus](./plugins/inputs/nginx_plus/README.md) - Thanks to @mplonka & @poblahblahblah\n- [opensmtpd](./plugins/inputs/opensmtpd/README.md) - Thanks to @aromeyer\n- [particle](./plugins/inputs/webhooks/particle/README.md) - Thanks to @davidgs\n- [pf](./plugins/inputs/pf/README.md) - Thanks to @nferch\n- [postfix](./plugins/inputs/postfix/README.md) - Thanks to @phemmer\n- [smart](./plugins/inputs/smart/README.md) - Thanks to @rickard-von-essen\n- [solr](./plugins/inputs/solr/README.md) - Thanks to @ljagiello\n- [teamspeak](./plugins/inputs/teamspeak/README.md) - Thanks to @p4ddy1\n- [unbound](./plugins/inputs/unbound/README.md) - Thanks to @aromeyer\n- [wavefront](./plugins/outputs/wavefront/README.md) - Thanks to @puckpuck\n\n### Release Notes\n\n- In the `kinesis` output, use of the `partition_key` and\n  `use_random_partitionkey` options has been deprecated in favor of the\n  `partition` subtable.  This allows for more flexible methods to set the\n  partition key such as by metric name or by tag.\n\n- With the release of the new improved `jolokia2` input, the legacy `jolokia`\n  plugin is deprecated and will be removed in a future release.  Users of this\n  plugin are encouraged to update to the new `jolokia2` plugin.\n\n- In the `postgresql` and `postgresql_extensible` plugins, the type of the oid\n  data type has changed from string to integer.  It is recommended to drop\n  affected fields until a new shard is started. For details on how to\n  workaround this issue please see [#3622](https://github.com/influxdata/telegraf/issues/3622).\n\n### Features\n\n- [#3170](https://github.com/influxdata/telegraf/pull/3170): Add support for sharding based on metric name.\n- [#3196](https://github.com/influxdata/telegraf/pull/3196): Add Kafka output plugin topic_suffix option.\n- [#3027](https://github.com/influxdata/telegraf/pull/3027): Include mount mode option in disk metrics.\n- [#3191](https://github.com/influxdata/telegraf/pull/3191): TLS and MTLS enhancements to HTTPListener input plugin.\n- [#3213](https://github.com/influxdata/telegraf/pull/3213): Add polling method to logparser and tail inputs.\n- [#3211](https://github.com/influxdata/telegraf/pull/3211): Add timeout option for kubernetes input.\n- [#3234](https://github.com/influxdata/telegraf/pull/3234): Add support for timing sums in statsd input.\n- [#2617](https://github.com/influxdata/telegraf/issues/2617): Add resource limit monitoring to procstat.\n- [#3236](https://github.com/influxdata/telegraf/pull/3236): Add support for k8s service DNS discovery to prometheus input.\n- [#3245](https://github.com/influxdata/telegraf/pull/3245): Add configurable metrics endpoint to prometheus output.\n- [#3214](https://github.com/influxdata/telegraf/pull/3214): Add new nginx_plus input plugin.\n- [#3215](https://github.com/influxdata/telegraf/pull/3215): Add support for NSQLookupd to nsq_consumer.\n- [#2278](https://github.com/influxdata/telegraf/pull/2278): Add redesigned Jolokia input plugin.\n- [#3106](https://github.com/influxdata/telegraf/pull/3106): Add configurable separator for metrics and fields in opentsdb output.\n- [#1692](https://github.com/influxdata/telegraf/pull/1692): Add support for the rollbar occurrence webhook event.\n- [#3160](https://github.com/influxdata/telegraf/pull/3160): Add Wavefront output plugin.\n- [#3281](https://github.com/influxdata/telegraf/pull/3281): Add extra wired tiger cache metrics to mongodb input.\n- [#3141](https://github.com/influxdata/telegraf/pull/3141): Collect Docker Swarm service metrics in docker input plugin.\n- [#2449](https://github.com/influxdata/telegraf/pull/2449): Add smart input plugin for collecting S.M.A.R.T. data.\n- [#3269](https://github.com/influxdata/telegraf/pull/3269): Add cluster health level configuration to elasticsearch input.\n- [#3304](https://github.com/influxdata/telegraf/pull/3304): Add ability to limit node stats in elasticsearch input.\n- [#2167](https://github.com/influxdata/telegraf/pull/2167): Add new basicstats aggregator.\n- [#3344](https://github.com/influxdata/telegraf/pull/3344): Add UDP IPv6 support to statsd input.\n- [#3350](https://github.com/influxdata/telegraf/pull/3350): Use labels in prometheus output for string fields.\n- [#3358](https://github.com/influxdata/telegraf/pull/3358): Add support for decimal timestamps to ts-epoch modifier.\n- [#3337](https://github.com/influxdata/telegraf/pull/3337): Add histogram and summary types and use in prometheus plugins.\n- [#3365](https://github.com/influxdata/telegraf/pull/3365): Gather concurrently from snmp agents.\n- [#3333](https://github.com/influxdata/telegraf/issues/3333): Perform DNS lookup before ping and report result.\n- [#3398](https://github.com/influxdata/telegraf/issues/3398): Add instance name option to varnish plugin.\n- [#3406](https://github.com/influxdata/telegraf/pull/3406):  Add support for SSL settings to ElasticSearch output plugin.\n- [#3315](https://github.com/influxdata/telegraf/pull/3315): Add Teamspeak 3 input plugin.\n- [#3305](https://github.com/influxdata/telegraf/pull/3305): Add modification_time field to filestat input plugin.\n- [#2019](https://github.com/influxdata/telegraf/pull/2019): Add Solr input plugin.\n- [#3210](https://github.com/influxdata/telegraf/pull/3210): Add CrateDB output plugin.\n- [#3459](https://github.com/influxdata/telegraf/pull/3459): Add systemd unit pid and cgroup matching to procstat.\n- [#3477](https://github.com/influxdata/telegraf/pull/3477): Add Particle Webhook Plugin.\n- [#3471](https://github.com/influxdata/telegraf/pull/3471): Use MAX() instead of SUM() for latency measurements in sqlserver.\n- [#3490](https://github.com/influxdata/telegraf/pull/3490): Add index by week number to Elasticsearch output.\n- [#3434](https://github.com/influxdata/telegraf/pull/3434): Add unbound input plugin.\n- [#3449](https://github.com/influxdata/telegraf/pull/3449): Add opensmtpd input plugin.\n- [#3470](https://github.com/influxdata/telegraf/pull/3470): Add support for tags in the index name in elasticsearch output.\n- [#2553](https://github.com/influxdata/telegraf/pull/2553): Add postfix input plugin.\n- [#3424](https://github.com/influxdata/telegraf/pull/3424): Add bond input plugin.\n- [#3518](https://github.com/influxdata/telegraf/pull/3518): Add slab to mem plugin.\n- [#3519](https://github.com/influxdata/telegraf/pull/3519): Add input plugin for DC/OS.\n- [#3140](https://github.com/influxdata/telegraf/pull/3140): Add support for glob patterns in net input plugin.\n- [#3405](https://github.com/influxdata/telegraf/pull/3405): Add input plugin for OpenBSD/FreeBSD pf.\n- [#3528](https://github.com/influxdata/telegraf/pull/3528): Add option to amqp output to publish persistent messages.\n- [#3530](https://github.com/influxdata/telegraf/pull/3530): Support I (idle) process state on procfs+Linux.\n\n### Bug Fixes\n\n- [#3136](https://github.com/influxdata/telegraf/issues/3136): Fix webhooks input address in use during reload.\n- [#3258](https://github.com/influxdata/telegraf/issues/3258): Unlock Statsd when stopping to prevent deadlock.\n- [#3319](https://github.com/influxdata/telegraf/issues/3319): Fix cloudwatch output requires unneeded permissions.\n- [#3351](https://github.com/influxdata/telegraf/issues/3351): Fix prometheus passthrough for existing value types.\n- [#3430](https://github.com/influxdata/telegraf/issues/3430): Always ignore autofs filesystems in disk input.\n- [#3326](https://github.com/influxdata/telegraf/issues/3326): Fail metrics parsing on unescaped quotes.\n- [#3473](https://github.com/influxdata/telegraf/pull/3473): Whitelist allowed char classes for graphite output.\n- [#3488](https://github.com/influxdata/telegraf/pull/3488): Use hexadecimal ids and lowercase names in zipkin input.\n- [#3263](https://github.com/influxdata/telegraf/issues/3263): Fix snmp-tools output parsing with Windows EOLs.\n- [#3447](https://github.com/influxdata/telegraf/issues/3447): Add shadow-utils dependency to rpm package.\n- [#3448](https://github.com/influxdata/telegraf/issues/3448): Use deb-systemd-invoke to restart service.\n- [#3553](https://github.com/influxdata/telegraf/issues/3553): Fix kafka_consumer outside range of offsets error.\n- [#3568](https://github.com/influxdata/telegraf/issues/3568): Fix separation of multiple prometheus_client outputs.\n- [#3577](https://github.com/influxdata/telegraf/issues/3577): Don't add system input uptime_format as a counter.\n\n## v1.4.5 [2017-12-01]\n\n### Bug Fixes\n\n- [#3500](https://github.com/influxdata/telegraf/issues/3500): Fix global variable collection when using interval_slow option in mysql input.\n- [#3486](https://github.com/influxdata/telegraf/issues/3486): Fix error getting net connections info in netstat input.\n- [#3529](https://github.com/influxdata/telegraf/issues/3529): Fix HOST_MOUNT_PREFIX in docker with disk input.\n\n## v1.4.4 [2017-11-08]\n\n### Bug Fixes\n\n- [#3401](https://github.com/influxdata/telegraf/pull/3401): Use schema specified in mqtt_consumer input.\n- [#3419](https://github.com/influxdata/telegraf/issues/3419): Redact datadog API key in log output.\n- [#3311](https://github.com/influxdata/telegraf/issues/3311): Fix error getting pids in netstat input.\n- [#3339](https://github.com/influxdata/telegraf/issues/3339): Support HOST_VAR envvar to locate /var in system input.\n- [#3383](https://github.com/influxdata/telegraf/issues/3383): Use current time if docker container read time is zero value.\n\n## v1.4.3 [2017-10-25]\n\n### Bug Fixes\n\n- [#3327](https://github.com/influxdata/telegraf/issues/3327): Fix container name filters in docker input.\n- [#3321](https://github.com/influxdata/telegraf/issues/3321): Fix snmpwalk address format in leofs input.\n- [#3329](https://github.com/influxdata/telegraf/issues/3329): Fix case sensitivity issue in sqlserver query.\n- [#3342](https://github.com/influxdata/telegraf/pull/3342): Fix CPU input plugin stuck after suspend on Linux.\n- [#3013](https://github.com/influxdata/telegraf/issues/3013): Fix mongodb input panic when restarting mongodb.\n- [#3224](https://github.com/influxdata/telegraf/pull/3224): Preserve url path prefix in influx output.\n- [#3354](https://github.com/influxdata/telegraf/pull/3354): Fix TELEGRAF_OPTS expansion in systemd service unit.\n- [#3357](https://github.com/influxdata/telegraf/issues/3357): Remove warning when JSON contains null value.\n- [#3375](https://github.com/influxdata/telegraf/issues/3375): Fix ACL token usage in consul input plugin.\n- [#3369](https://github.com/influxdata/telegraf/issues/3369): Fix unquoting error with Tomcat 6.\n- [#3373](https://github.com/influxdata/telegraf/issues/3373): Fix syscall panic in diskio on some Linux systems.\n\n## v1.4.2 [2017-10-10]\n\n### Bug Fixes\n\n- [#3259](https://github.com/influxdata/telegraf/issues/3259): Fix error if int larger than 32-bit in /proc/vmstat.\n- [#3265](https://github.com/influxdata/telegraf/issues/3265): Fix parsing of JSON with a UTF8 BOM in httpjson.\n- [#2887](https://github.com/influxdata/telegraf/issues/2887): Allow JSON data format to contain zero metrics.\n- [#3284](https://github.com/influxdata/telegraf/issues/3284): Fix format of connection_timeout in mqtt_consumer.\n- [#3081](https://github.com/influxdata/telegraf/issues/3081): Fix case sensitivity error in sqlserver input.\n- [#3297](https://github.com/influxdata/telegraf/issues/3297): Add support for proxy environment variables to http_response.\n- [#1588](https://github.com/influxdata/telegraf/issues/1588): Add support for standard proxy env vars in outputs.\n- [#3282](https://github.com/influxdata/telegraf/issues/3282): Fix panic in cpu input if number of cpus changes.\n- [#2854](https://github.com/influxdata/telegraf/issues/2854): Use chunked transfer encoding in InfluxDB output.\n\n## v1.4.1 [2017-09-26]\n\n### Bug Fixes\n\n- [#3167](https://github.com/influxdata/telegraf/issues/3167): Fix MQTT input exits if Broker is not available on startup.\n- [#3217](https://github.com/influxdata/telegraf/issues/3217): Fix optional field value conversions in fluentd input.\n- [#3227](https://github.com/influxdata/telegraf/issues/3227): Whitelist allowed char classes for opentsdb output.\n- [#3232](https://github.com/influxdata/telegraf/issues/3232): Fix counter and gauge metric types.\n- [#3235](https://github.com/influxdata/telegraf/issues/3235): Fix skipped line with empty target in iptables.\n- [#3175](https://github.com/influxdata/telegraf/issues/3175): Fix duplicate keys in perf counters sqlserver query.\n- [#3230](https://github.com/influxdata/telegraf/issues/3230): Fix panic in statsd p100 calculation.\n- [#3242](https://github.com/influxdata/telegraf/issues/3242): Fix arm64 packages contain 32-bit executable.\n\n## v1.4 [2017-09-05]\n\n### Release Notes\n\n- The `kafka_consumer` input has been updated to support Kafka 0.9 and\n  above style consumer offset handling.  The previous version of this plugin\n  supporting Kafka 0.8 and below is available as the `kafka_consumer_legacy`\n  plugin.\n\n- In the `aerospike` input the `node_name` field has been changed to be a tag\n  for both the `aerospike_node` and `aerospike_namespace` measurements.\n\n- The default prometheus_client port has been changed to 9273.\n\n### New Plugins\n\n- [fail2ban](./plugins/inputs/fail2ban/README.md) - Thanks to @grugrut\n- [fluentd](./plugins/inputs/fluentd/README.md) - Thanks to @DanKans\n- [histogram](./plugins/aggregators/histogram/README.md) - Thanks to @vlamug\n- [minecraft](./plugins/inputs/minecraft/README.md) - Thanks to @adamperlin & @Ayrdrie\n- [openldap](./plugins/inputs/openldap/README.md) - Thanks to @cobaugh\n- [salesforce](./plugins/inputs/salesforce/README.md) - Thanks to @rody\n- [tomcat](./plugins/inputs/tomcat/README.md) - Thanks to @mlindes\n- [win_services](./plugins/inputs/win_services/README.md) - Thanks to @vlastahajek\n- [zipkin](./plugins/inputs/zipkin/README.md) - Thanks to @adamperlin & @Ayrdrie\n\n### Features\n\n- [#2487](https://github.com/influxdata/telegraf/pull/2487): Add Kafka 0.9+ consumer support\n- [#2773](https://github.com/influxdata/telegraf/pull/2773): Add support for self-signed certs to InfluxDB input plugin\n- [#2293](https://github.com/influxdata/telegraf/pull/2293): Add TCP listener for statsd input\n- [#2581](https://github.com/influxdata/telegraf/pull/2581): Add Docker container environment variables as tags. Only whitelisted\n- [#2817](https://github.com/influxdata/telegraf/pull/2817): Add timeout option to IPMI sensor plugin\n- [#2883](https://github.com/influxdata/telegraf/pull/2883): Add support for an optional SSL/TLS configuration to nginx input plugin\n- [#2882](https://github.com/influxdata/telegraf/pull/2882): Add timezone support for logparser timestamps.\n- [#2814](https://github.com/influxdata/telegraf/pull/2814): Add result_type field for http_response input.\n- [#2734](https://github.com/influxdata/telegraf/pull/2734): Add include/exclude filters for docker containers.\n- [#2602](https://github.com/influxdata/telegraf/pull/2602): Add secure connection support to graphite output.\n- [#2908](https://github.com/influxdata/telegraf/pull/2908): Add min/max response time on linux/darwin to ping.\n- [#2929](https://github.com/influxdata/telegraf/pull/2929): Add HTTP Proxy support to influxdb output.\n- [#2933](https://github.com/influxdata/telegraf/pull/2933): Add standard SSL options to mysql input.\n- [#2875](https://github.com/influxdata/telegraf/pull/2875): Add input plugin for fail2ban.\n- [#2924](https://github.com/influxdata/telegraf/pull/2924): Support HOST_PROC in processes and linux_sysctl_fs inputs.\n- [#2960](https://github.com/influxdata/telegraf/pull/2960): Add Minecraft input plugin.\n- [#2963](https://github.com/influxdata/telegraf/pull/2963): Add support for RethinkDB 1.0 handshake protocol.\n- [#2943](https://github.com/influxdata/telegraf/pull/2943): Add optional usage_active and time_active CPU metrics.\n- [#2973](https://github.com/influxdata/telegraf/pull/2973): Change default prometheus_client port.\n- [#2661](https://github.com/influxdata/telegraf/pull/2661): Add fluentd input plugin.\n- [#2990](https://github.com/influxdata/telegraf/pull/2990): Add result_type field to net_response input plugin.\n- [#2571](https://github.com/influxdata/telegraf/pull/2571): Add read timeout to socket_listener\n- [#2612](https://github.com/influxdata/telegraf/pull/2612): Add input plugin for OpenLDAP.\n- [#3042](https://github.com/influxdata/telegraf/pull/3042): Add network option to dns_query.\n- [#3054](https://github.com/influxdata/telegraf/pull/3054): Add redis_version field to redis input.\n- [#3063](https://github.com/influxdata/telegraf/pull/3063): Add tls options to docker input.\n- [#2387](https://github.com/influxdata/telegraf/pull/2387): Add histogram aggregator plugin.\n- [#3080](https://github.com/influxdata/telegraf/pull/3080): Add zipkin input plugin.\n- [#3023](https://github.com/influxdata/telegraf/pull/3023): Add Windows Services input plugin.\n- [#3098](https://github.com/influxdata/telegraf/pull/3098): Add path tag to logparser containing path of logfile.\n- [#3075](https://github.com/influxdata/telegraf/pull/3075): Add salesforce input plugin.\n- [#3097](https://github.com/influxdata/telegraf/pull/3097): Add option to run varnish under sudo.\n- [#3119](https://github.com/influxdata/telegraf/pull/3119): Add weighted_io_time to diskio input.\n- [#2978](https://github.com/influxdata/telegraf/pull/2978): Add gzip content-encoding support to influxdb output.\n- [#3127](https://github.com/influxdata/telegraf/pull/3127): Allow using system plugin in Windows.\n- [#3112](https://github.com/influxdata/telegraf/pull/3112): Add tomcat input plugin.\n- [#3182](https://github.com/influxdata/telegraf/pull/3182): HTTP headers can be added to InfluxDB output.\n\n### Bug Fixes\n\n- [#2607](https://github.com/influxdata/telegraf/issues/2607): Improve logging of errors in Cassandra input.\n- [#2819](https://github.com/influxdata/telegraf/pull/2819): [enh] set db_version at 0 if query version fails\n- [#2749](https://github.com/influxdata/telegraf/pull/2749): Fixed sqlserver input to work with case sensitive server collation.\n- [#2716](https://github.com/influxdata/telegraf/pull/2716): Systemd does not see all shutdowns as failures\n- [#2782](https://github.com/influxdata/telegraf/pull/2782): Reuse transports in input plugins\n- [#2815](https://github.com/influxdata/telegraf/issues/2815): Inputs processes fails with \"no such process\".\n- [#1137](https://github.com/influxdata/telegraf/issues/1137): Fix multiple plugin loading in win_perf_counters.\n- [#2855](https://github.com/influxdata/telegraf/pull/2855):  MySQL input: log and continue on field parse error.\n- [#2885](https://github.com/influxdata/telegraf/pull/2885): Fix timeout option in Windows ping input sample configuration.\n- [#2911](https://github.com/influxdata/telegraf/issues/2911): Fix Kinesis output plugin in govcloud.\n- [#2917](https://github.com/influxdata/telegraf/issues/2917): Fix Aerospike input adds all nodes to a single series.\n- [#2452](https://github.com/influxdata/telegraf/pull/2452): Improve Prometheus Client output documentation.\n- [#2984](https://github.com/influxdata/telegraf/pull/2984): Display error message if prometheus output fails to listen.\n- [#2997](https://github.com/influxdata/telegraf/issues/2997): Fix elasticsearch output content type detection warning.\n- [#2914](https://github.com/influxdata/telegraf/issues/2914): Prevent possible deadlock when using aggregators.\n- [#2860](https://github.com/influxdata/telegraf/issues/2860): Fix combined tagdrop/tagpass filtering.\n- [#3036](https://github.com/influxdata/telegraf/pull/3036): Fix filtering when both pass and drop match an item.\n- [#2964](https://github.com/influxdata/telegraf/issues/2964): Only report cpu usage for online cpus in docker input.\n- [#3050](https://github.com/influxdata/telegraf/pull/3050): Start first aggregator period at startup time.\n- [#2906](https://github.com/influxdata/telegraf/issues/2906): Fix panic in logparser if file cannot be opened.\n- [#2886](https://github.com/influxdata/telegraf/issues/2886): Default to localhost if zookeeper has no servers set.\n- [#2457](https://github.com/influxdata/telegraf/issues/2457): Fix docker memory and cpu reporting in Windows.\n- [#3058](https://github.com/influxdata/telegraf/issues/3058): Allow iptable entries with trailing text.\n- [#1680](https://github.com/influxdata/telegraf/issues/1680): Sanitize password from couchbase metric.\n- [#3104](https://github.com/influxdata/telegraf/issues/3104): Converge to typed value in prometheus output.\n- [#2899](https://github.com/influxdata/telegraf/issues/2899): Skip compilation of logparser and tail on solaris.\n- [#2951](https://github.com/influxdata/telegraf/issues/2951): Discard logging from tail library.\n- [#3126](https://github.com/influxdata/telegraf/pull/3126): Remove log message on ping timeout.\n- [#3144](https://github.com/influxdata/telegraf/issues/3144): Don't retry points beyond retention policy.\n- [#3015](https://github.com/influxdata/telegraf/issues/3015): Don't start Telegraf on install in Amazon Linux.\n- [#3153](https://github.com/influxdata/telegraf/issues/3053): Enable hddtemp input on all platforms.\n- [#3142](https://github.com/influxdata/telegraf/issues/3142): Escape backslash within string fields.\n- [#3162](https://github.com/influxdata/telegraf/issues/3162): Fix parsing of SHM remotes in ntpq input\n- [#3149](https://github.com/influxdata/telegraf/issues/3149): Don't fail parsing zpool stats if pool health is UNAVAIL on FreeBSD.\n- [#2672](https://github.com/influxdata/telegraf/issues/2672): Fix NSQ input plugin when used with version 1.0.0-compat.\n- [#2523](https://github.com/influxdata/telegraf/issues/2523): Added CloudWatch metric constraint validation.\n- [#3179](https://github.com/influxdata/telegraf/issues/3179): Skip non-numerical values in graphite format.\n- [#3187](https://github.com/influxdata/telegraf/issues/3187): Fix panic when handling string fields with escapes.\n\n## v1.3.5 [2017-07-26]\n\n### Bug Fixes\n\n- [#3049](https://github.com/influxdata/telegraf/issues/3049): Fix prometheus output cannot be reloaded.\n- [#3037](https://github.com/influxdata/telegraf/issues/3037): Fix filestat reporting exists when cannot list directory.\n- [#2386](https://github.com/influxdata/telegraf/issues/2386): Fix ntpq parse issue when using dns_lookup.\n- [#2554](https://github.com/influxdata/telegraf/issues/2554): Fix panic when agent.interval = \"0s\".\n\n## v1.3.4 [2017-07-12]\n\n### Bug Fixes\n\n- [#3001](https://github.com/influxdata/telegraf/issues/3001): Fix handling of escape characters within fields.\n- [#2988](https://github.com/influxdata/telegraf/issues/2988): Fix chrony plugin does not track system time offset.\n- [#3004](https://github.com/influxdata/telegraf/issues/3004): Do not allow metrics with trailing slashes.\n- [#3011](https://github.com/influxdata/telegraf/issues/3011): Prevent Write from being called concurrently.\n\n## v1.3.3 [2017-06-28]\n\n### Bug Fixes\n\n- [#2915](https://github.com/influxdata/telegraf/issues/2915): Allow dos line endings in tail and logparser.\n- [#2937](https://github.com/influxdata/telegraf/issues/2937): Remove label value sanitization in prometheus output.\n- [#2948](https://github.com/influxdata/telegraf/issues/2948): Fix bug parsing default timestamps with modified precision.\n- [#2954](https://github.com/influxdata/telegraf/issues/2954): Fix panic in elasticsearch input if cannot determine master.\n\n## v1.3.2 [2017-06-14]\n\n### Bug Fixes\n\n- [#2862](https://github.com/influxdata/telegraf/issues/2862): Fix InfluxDB UDP metric splitting.\n- [#2888](https://github.com/influxdata/telegraf/issues/2888): Fix mongodb/leofs urls without scheme.\n- [#2822](https://github.com/influxdata/telegraf/issues/2822): Fix inconsistent label dimensions in prometheus output.\n\n## v1.3.1 [2017-05-31]\n\n### Bug Fixes\n\n- [#2749](https://github.com/influxdata/telegraf/pull/2749): Fixed sqlserver input to work with case sensitive server collation.\n- [#2782](https://github.com/influxdata/telegraf/pull/2782): Reuse transports in input plugins\n- [#2815](https://github.com/influxdata/telegraf/issues/2815): Inputs processes fails with \"no such process\".\n- [#2851](https://github.com/influxdata/telegraf/pull/2851): Fix InfluxDB output database quoting.\n- [#2856](https://github.com/influxdata/telegraf/issues/2856): Fix net input on older Linux kernels.\n- [#2848](https://github.com/influxdata/telegraf/pull/2848): Fix panic in mongo input.\n- [#2869](https://github.com/influxdata/telegraf/pull/2869): Fix length calculation of split metric buffer.\n\n## v1.3 [2017-05-15]\n\n### Release Notes\n\n- Users of the windows `ping` plugin will need to drop or migrate their\nmeasurements in order to continue using the plugin. The reason for this is that\nthe windows plugin was outputting a different type than the linux plugin. This\nmade it impossible to use the `ping` plugin for both windows and linux\nmachines.\n\n- Ceph: the `ceph_pgmap_state` metric content has been modified to use a unique field `count`, with each state expressed as a `state` tag.\n\nTelegraf < 1.3:\n\n```text\n# field_name             value\nactive+clean             123\nactive+clean+scrubbing   3\n```\n\nTelegraf >= 1.3:\n\n```text\n# field_name    value       tag\ncount           123         state=active+clean\ncount           3           state=active+clean+scrubbing\n```\n\n- The [Riemann output plugin](./plugins/outputs/riemann) has been rewritten\nand the previous riemann plugin is _incompatible_ with the new one. The reasons\nfor this are outlined in issue [#1878](https://github.com/influxdata/telegraf/issues/1878).\nThe previous riemann output will still be available using\n`outputs.riemann_legacy` if needed, but that will eventually be deprecated.\nIt is highly recommended that all users migrate to the new riemann output plugin.\n\n- Generic [socket_listener](./plugins/inputs/socket_listener) and\n[socket_writer](./plugins/outputs/socket_writer) plugins have been implemented\nfor receiving and sending UDP, TCP, unix, & unix-datagram data. These plugins\nwill replace udp_listener and tcp_listener, which are still available but will\nbe deprecated eventually.\n\n### Features\n\n- [#2721](https://github.com/influxdata/telegraf/pull/2721): Added SASL options for kafka output plugin.\n- [#2723](https://github.com/influxdata/telegraf/pull/2723): Added SSL configuration for input haproxy.\n- [#2494](https://github.com/influxdata/telegraf/pull/2494): Add interrupts input plugin.\n- [#2094](https://github.com/influxdata/telegraf/pull/2094): Add generic socket listener & writer.\n- [#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.\n- [#2137](https://github.com/influxdata/telegraf/pull/2137): Added userstats to mysql input plugin.\n- [#2179](https://github.com/influxdata/telegraf/pull/2179): Added more InnoDB metric to MySQL plugin.\n- [#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.\n- [#2251](https://github.com/influxdata/telegraf/pull/2251): InfluxDB output: use own client for improved through-put and less allocations.\n- [#2330](https://github.com/influxdata/telegraf/pull/2330): Keep -config-directory when running as Windows service.\n- [#1900](https://github.com/influxdata/telegraf/pull/1900): Riemann plugin rewrite.\n- [#1453](https://github.com/influxdata/telegraf/pull/1453): diskio: add support for name templates and udev tags.\n- [#2277](https://github.com/influxdata/telegraf/pull/2277): add integer metrics for Consul check health state.\n- [#2201](https://github.com/influxdata/telegraf/pull/2201): Add lock option to the IPtables input plugin.\n- [#2244](https://github.com/influxdata/telegraf/pull/2244): Support ipmi_sensor plugin querying local ipmi sensors.\n- [#2339](https://github.com/influxdata/telegraf/pull/2339): Increment gather_errors for all errors emitted by inputs.\n- [#2071](https://github.com/influxdata/telegraf/issues/2071): Use official docker SDK.\n- [#1678](https://github.com/influxdata/telegraf/pull/1678): Add AMQP consumer input plugin\n- [#2512](https://github.com/influxdata/telegraf/pull/2512): Added pprof tool.\n- [#2501](https://github.com/influxdata/telegraf/pull/2501): Support DEAD(X) state in system input plugin.\n- [#2522](https://github.com/influxdata/telegraf/pull/2522): Add support for mongodb client certificates.\n- [#1948](https://github.com/influxdata/telegraf/pull/1948): Support adding SNMP table indexes as tags.\n- [#2332](https://github.com/influxdata/telegraf/pull/2332): Add Elasticsearch 5.x output\n- [#2587](https://github.com/influxdata/telegraf/pull/2587): Add json timestamp units configurability\n- [#2597](https://github.com/influxdata/telegraf/issues/2597): Add support for Linux sysctl-fs metrics.\n- [#2425](https://github.com/influxdata/telegraf/pull/2425): Support to include/exclude docker container labels as tags\n- [#1667](https://github.com/influxdata/telegraf/pull/1667): dmcache input plugin\n- [#2637](https://github.com/influxdata/telegraf/issues/2637): Add support for precision in http_listener\n- [#2636](https://github.com/influxdata/telegraf/pull/2636): Add `message_len_max` option to `kafka_consumer` input\n- [#1100](https://github.com/influxdata/telegraf/issues/1100): Add collectd parser\n- [#1820](https://github.com/influxdata/telegraf/issues/1820): easier plugin testing without outputs\n- [#2493](https://github.com/influxdata/telegraf/pull/2493): Check signature in the GitHub webhook plugin\n- [#2038](https://github.com/influxdata/telegraf/issues/2038): Add papertrail support to webhooks\n- [#2253](https://github.com/influxdata/telegraf/pull/2253): Change jolokia plugin to use bulk requests.\n- [#2575](https://github.com/influxdata/telegraf/issues/2575) Add diskio input for Darwin\n- [#2705](https://github.com/influxdata/telegraf/pull/2705): Kinesis output: add use_random_partitionkey option\n- [#2635](https://github.com/influxdata/telegraf/issues/2635): add tcp keep-alive to socket_listener & socket_writer\n- [#2031](https://github.com/influxdata/telegraf/pull/2031): Add Kapacitor input plugin\n- [#2732](https://github.com/influxdata/telegraf/pull/2732): Use go 1.8.1\n- [#2712](https://github.com/influxdata/telegraf/issues/2712): Documentation for rabbitmq input plugin\n- [#2141](https://github.com/influxdata/telegraf/pull/2141): Logparser handles newly-created files.\n\n### Bug Fixes\n\n- [#2633](https://github.com/influxdata/telegraf/pull/2633): ipmi_sensor: allow @ symbol in password\n- [#2077](https://github.com/influxdata/telegraf/issues/2077): SQL Server Input - Arithmetic overflow error converting numeric to data type int.\n- [#2262](https://github.com/influxdata/telegraf/issues/2262): Flush jitter can inhibit metric collection.\n- [#2318](https://github.com/influxdata/telegraf/issues/2318): haproxy input - Add missing fields.\n- [#2287](https://github.com/influxdata/telegraf/issues/2287): Kubernetes input: Handle null startTime for stopped pods.\n- [#2356](https://github.com/influxdata/telegraf/issues/2356): cpu input panic when /proc/stat is empty.\n- [#2341](https://github.com/influxdata/telegraf/issues/2341): telegraf swallowing panics in --test mode.\n- [#2358](https://github.com/influxdata/telegraf/pull/2358): Create pidfile with 644 permissions & defer file deletion.\n- [#2360](https://github.com/influxdata/telegraf/pull/2360): Fixed install/remove of telegraf on non-systemd Debian/Ubuntu systems\n- [#2282](https://github.com/influxdata/telegraf/issues/2282): Reloading telegraf freezes prometheus output.\n- [#2390](https://github.com/influxdata/telegraf/issues/2390): Empty tag value causes error on InfluxDB output.\n- [#2380](https://github.com/influxdata/telegraf/issues/2380): buffer_size field value is negative number from \"internal\" plugin.\n- [#2414](https://github.com/influxdata/telegraf/issues/2414): Missing error handling in the MySQL plugin leads to segmentation violation.\n- [#2462](https://github.com/influxdata/telegraf/pull/2462): Fix type conflict in windows ping plugin.\n- [#2178](https://github.com/influxdata/telegraf/issues/2178): logparser: regexp with lookahead.\n- [#2466](https://github.com/influxdata/telegraf/issues/2466): Telegraf can crash in LoadDirectory on 0600 files.\n- [#2215](https://github.com/influxdata/telegraf/issues/2215): Iptables input: document better that rules without a comment are ignored.\n- [#2483](https://github.com/influxdata/telegraf/pull/2483): Fix win_perf_counters capping values at 100.\n- [#2498](https://github.com/influxdata/telegraf/pull/2498): Exporting Ipmi.Path to be set by config.\n- [#2500](https://github.com/influxdata/telegraf/pull/2500): Remove warning if parse empty content\n- [#2520](https://github.com/influxdata/telegraf/pull/2520): Update default value for Cloudwatch rate limit\n- [#2513](https://github.com/influxdata/telegraf/issues/2513): create /etc/telegraf/telegraf.d directory in tarball.\n- [#2541](https://github.com/influxdata/telegraf/issues/2541): Return error on unsupported serializer data format.\n- [#1827](https://github.com/influxdata/telegraf/issues/1827): Fix Windows Performance Counters multi instance identifier\n- [#2576](https://github.com/influxdata/telegraf/pull/2576): Add write timeout to Riemann output\n- [#2596](https://github.com/influxdata/telegraf/pull/2596): fix timestamp parsing on prometheus plugin\n- [#2610](https://github.com/influxdata/telegraf/pull/2610): Fix deadlock when output cannot write\n- [#2410](https://github.com/influxdata/telegraf/issues/2410): Fix connection leak in postgresql.\n- [#2628](https://github.com/influxdata/telegraf/issues/2628): Set default measurement name for snmp input.\n- [#2649](https://github.com/influxdata/telegraf/pull/2649): Improve performance of diskio with many disks\n- [#2671](https://github.com/influxdata/telegraf/issues/2671): The internal input plugin uses the wrong units for `heap_objects`\n- [#2684](https://github.com/influxdata/telegraf/pull/2684): Fix ipmi_sensor config is shared between all plugin instances\n- [#2450](https://github.com/influxdata/telegraf/issues/2450): Network statistics not collected when system has alias interfaces\n- [#1911](https://github.com/influxdata/telegraf/issues/1911): Sysstat plugin needs LANG=C or similar locale\n- [#2528](https://github.com/influxdata/telegraf/issues/2528): File output closes standard streams on reload.\n- [#2603](https://github.com/influxdata/telegraf/issues/2603): AMQP output disconnect blocks all outputs\n- [#2706](https://github.com/influxdata/telegraf/issues/2706): Improve documentation for redis input plugin\n\n## v1.2.1 [2017-02-01]\n\n### Bug Fixes\n\n- [#2317](https://github.com/influxdata/telegraf/issues/2317): Fix segfault on nil metrics with influxdb output.\n- [#2324](https://github.com/influxdata/telegraf/issues/2324): Fix negative number handling.\n\n### Features\n\n- [#2348](https://github.com/influxdata/telegraf/pull/2348): Go version 1.7.4 -> 1.7.5\n\n## v1.2 [2017-01-00]\n\n### Release Notes\n\n- The StatsD plugin will now default all \"delete_\" config options to \"true\". This\nwill change te default behavior for users who were not specifying these parameters\nin their config file.\n\n- The StatsD plugin will also no longer save it's state on a service reload.\nEssentially we have reverted PR [#887](https://github.com/influxdata/telegraf/pull/887).\nThe reason for this is that saving the state in a global variable is not\nthread-safe (see [#1975](https://github.com/influxdata/telegraf/issues/1975) & [#2102](https://github.com/influxdata/telegraf/issues/2102)),\nand this creates issues if users want to define multiple instances\nof the statsd plugin. Saving state on reload may be considered in the future,\nbut this would need to be implemented at a higher level and applied to all\nplugins, not just statsd.\n\n### Features\n\n- [#2123](https://github.com/influxdata/telegraf/pull/2123): Fix improper calculation of CPU percentages\n- [#1564](https://github.com/influxdata/telegraf/issues/1564): Use RFC3339 timestamps in log output.\n- [#1997](https://github.com/influxdata/telegraf/issues/1997): Non-default HTTP timeouts for RabbitMQ plugin.\n- [#2074](https://github.com/influxdata/telegraf/pull/2074): \"discard\" output plugin added, primarily for testing purposes.\n- [#1965](https://github.com/influxdata/telegraf/pull/1965): The JSON parser can now parse an array of objects using the same configuration.\n- [#1807](https://github.com/influxdata/telegraf/pull/1807): Option to use device name rather than path for reporting disk stats.\n- [#1348](https://github.com/influxdata/telegraf/issues/1348): Telegraf \"internal\" plugin for collecting stats on itself.\n- [#2127](https://github.com/influxdata/telegraf/pull/2127): Update Go version to 1.7.4.\n- [#2126](https://github.com/influxdata/telegraf/pull/2126): Support a metric.Split function.\n- [#2026](https://github.com/influxdata/telegraf/pull/2065): elasticsearch \"shield\" (basic auth) support doc.\n- [#1885](https://github.com/influxdata/telegraf/pull/1885): Fix over-querying of cloudwatch metrics\n- [#1913](https://github.com/influxdata/telegraf/pull/1913): OpenTSDB basic auth support.\n- [#1908](https://github.com/influxdata/telegraf/pull/1908): RabbitMQ Connection metrics.\n- [#1937](https://github.com/influxdata/telegraf/pull/1937): HAProxy session limit metric.\n- [#2068](https://github.com/influxdata/telegraf/issues/2068): Accept strings for StatsD sets.\n- [#1893](https://github.com/influxdata/telegraf/issues/1893): Change StatsD default \"reset\" behavior.\n- [#2079](https://github.com/influxdata/telegraf/pull/2079): Enable setting ClientID in MQTT output.\n- [#2001](https://github.com/influxdata/telegraf/pull/2001): MongoDB input plugin: Improve state data.\n- [#2078](https://github.com/influxdata/telegraf/pull/2078): Ping input: add standard deviation field.\n- [#2121](https://github.com/influxdata/telegraf/pull/2121): Add GC pause metric to InfluxDB input plugin.\n- [#2006](https://github.com/influxdata/telegraf/pull/2006): Added response_timeout property to prometheus input plugin.\n- [#1763](https://github.com/influxdata/telegraf/issues/1763): Pulling github.com/lxn/win's pdh wrapper into telegraf.\n- [#1898](https://github.com/influxdata/telegraf/issues/1898): Support negative statsd counters.\n- [#1921](https://github.com/influxdata/telegraf/issues/1921): Elasticsearch cluster stats support.\n- [#1942](https://github.com/influxdata/telegraf/pull/1942): Change Amazon Kinesis output plugin to use the built-in serializer plugins.\n- [#1980](https://github.com/influxdata/telegraf/issues/1980): Hide username/password from elasticsearch error log messages.\n- [#2097](https://github.com/influxdata/telegraf/issues/2097): Configurable HTTP timeouts in Jolokia plugin\n- [#2255](https://github.com/influxdata/telegraf/pull/2255): Allow changing jolokia attribute delimiter\n\n### Bug Fixes\n\n- [#2049](https://github.com/influxdata/telegraf/pull/2049): Fix the Value data format not trimming null characters from input.\n- [#1949](https://github.com/influxdata/telegraf/issues/1949): Fix windows `net` plugin.\n- [#1775](https://github.com/influxdata/telegraf/issues/1775): Cache & expire metrics for delivery to prometheus\n- [#1775](https://github.com/influxdata/telegraf/issues/1775): Cache & expire metrics for delivery to prometheus.\n- [#2146](https://github.com/influxdata/telegraf/issues/2146): Fix potential panic in aggregator plugin metric maker.\n- [#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.\n- [#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.\n- [#2061](https://github.com/influxdata/telegraf/issues/2061): Fix panic when file stat info cannot be collected due to permissions or other issue(s).\n- [#2045](https://github.com/influxdata/telegraf/issues/2045): Graylog output should set short_message field.\n- [#1904](https://github.com/influxdata/telegraf/issues/1904): Hddtemp always put the value in the field temperature.\n- [#1693](https://github.com/influxdata/telegraf/issues/1693): Properly collect nested jolokia struct data.\n- [#1917](https://github.com/influxdata/telegraf/pull/1917): fix puppetagent inputs plugin to support string for config variable.\n- [#1987](https://github.com/influxdata/telegraf/issues/1987): fix docker input plugin tags when registry has port.\n- [#2089](https://github.com/influxdata/telegraf/issues/2089): Fix tail input when reading from a pipe.\n- [#1449](https://github.com/influxdata/telegraf/issues/1449): MongoDB plugin always shows 0 replication lag.\n- [#1825](https://github.com/influxdata/telegraf/issues/1825): Consul plugin: add check_id as a tag in metrics to avoid overwrites.\n- [#1973](https://github.com/influxdata/telegraf/issues/1973): Partial fix: logparser CLF pattern with IPv6 addresses.\n- [#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.\n- [#2027](https://github.com/influxdata/telegraf/issues/2027): docker input: interface conversion panic fix.\n- [#1814](https://github.com/influxdata/telegraf/issues/1814): snmp: ensure proper context is present on error messages.\n- [#2299](https://github.com/influxdata/telegraf/issues/2299): opentsdb: add tcp:// prefix if no scheme provided.\n- [#2297](https://github.com/influxdata/telegraf/issues/2297): influx parser: parse line-protocol without newlines.\n- [#2245](https://github.com/influxdata/telegraf/issues/2245): influxdb output: fix field type conflict blocking output buffer.\n\n## v1.1.2 [2016-12-12]\n\n### Bug Fixes\n\n- [#2007](https://github.com/influxdata/telegraf/issues/2007): Make snmptranslate not required when using numeric OID.\n- [#2104](https://github.com/influxdata/telegraf/issues/2104): Add a global snmp translation cache.\n\n## v1.1.1 [2016-11-14]\n\n### Bug Fixes\n\n- [#2023](https://github.com/influxdata/telegraf/issues/2023): Fix issue parsing toml durations with single quotes.\n\n## v1.1.0 [2016-11-07]\n\n### Release Notes\n\n- Telegraf now supports two new types of plugins: processors & aggregators.\n\n- On systemd Telegraf will no longer redirect it's stdout to /var/log/telegraf/telegraf.log.\nOn most systems, the logs will be directed to the systemd journal and can be\naccessed by `journalctl -u telegraf.service`. Consult the systemd journal\ndocumentation for configuring journald. There is also a [`logfile` config option](https://github.com/influxdata/telegraf/blob/master/etc/telegraf.conf#L70)\navailable in 1.1, which will allow users to easily configure telegraf to\ncontinue sending logs to /var/log/telegraf/telegraf.log.\n\n### Features\n\n- [#1726](https://github.com/influxdata/telegraf/issues/1726): Processor & Aggregator plugin support.\n- [#1861](https://github.com/influxdata/telegraf/pull/1861): adding the tags in the graylog output plugin\n- [#1732](https://github.com/influxdata/telegraf/pull/1732): Telegraf systemd service, log to journal.\n- [#1782](https://github.com/influxdata/telegraf/pull/1782): Allow numeric and non-string values for tag_keys.\n- [#1694](https://github.com/influxdata/telegraf/pull/1694): Adding Gauge and Counter metric types.\n- [#1606](https://github.com/influxdata/telegraf/pull/1606): Remove carraige returns from exec plugin output on Windows\n- [#1674](https://github.com/influxdata/telegraf/issues/1674): elasticsearch input: configurable timeout.\n- [#1607](https://github.com/influxdata/telegraf/pull/1607): Massage metric names in Instrumental output plugin\n- [#1572](https://github.com/influxdata/telegraf/pull/1572): mesos improvements.\n- [#1513](https://github.com/influxdata/telegraf/issues/1513): Add Ceph Cluster Performance Statistics\n- [#1650](https://github.com/influxdata/telegraf/issues/1650): Ability to configure response_timeout in httpjson input.\n- [#1685](https://github.com/influxdata/telegraf/issues/1685): Add additional redis metrics.\n- [#1539](https://github.com/influxdata/telegraf/pull/1539): Added capability to send metrics through Http API for OpenTSDB.\n- [#1471](https://github.com/influxdata/telegraf/pull/1471): iptables input plugin.\n- [#1542](https://github.com/influxdata/telegraf/pull/1542): Add filestack webhook plugin.\n- [#1599](https://github.com/influxdata/telegraf/pull/1599): Add server hostname for each docker measurements.\n- [#1697](https://github.com/influxdata/telegraf/pull/1697): Add NATS output plugin.\n- [#1407](https://github.com/influxdata/telegraf/pull/1407) & [#1915](https://github.com/influxdata/telegraf/pull/1915): HTTP service listener input plugin.\n- [#1699](https://github.com/influxdata/telegraf/pull/1699): Add database blacklist option for Postgresql\n- [#1791](https://github.com/influxdata/telegraf/pull/1791): Add Docker container state metrics to Docker input plugin output\n- [#1755](https://github.com/influxdata/telegraf/issues/1755): Add support to SNMP for IP & MAC address conversion.\n- [#1729](https://github.com/influxdata/telegraf/issues/1729): Add support to SNMP for OID index suffixes.\n- [#1813](https://github.com/influxdata/telegraf/pull/1813): Change default arguments for SNMP plugin.\n- [#1686](https://github.com/influxdata/telegraf/pull/1686): Mesos input plugin: very high-cardinality mesos-task metrics removed.\n- [#1838](https://github.com/influxdata/telegraf/pull/1838): Logging overhaul to centralize the logger & log levels, & provide a logfile config option.\n- [#1700](https://github.com/influxdata/telegraf/pull/1700): HAProxy plugin socket glob matching.\n- [#1847](https://github.com/influxdata/telegraf/pull/1847): Add Kubernetes plugin for retrieving pod metrics.\n\n### Bug Fixes\n\n- [#1955](https://github.com/influxdata/telegraf/issues/1955): Fix NATS plug-ins reconnection logic.\n- [#1936](https://github.com/influxdata/telegraf/issues/1936): Set required default values in udp_listener & tcp_listener.\n- [#1926](https://github.com/influxdata/telegraf/issues/1926): Fix toml unmarshal panic in Duration objects.\n- [#1746](https://github.com/influxdata/telegraf/issues/1746): Fix handling of non-string values for JSON keys listed in tag_keys.\n- [#1628](https://github.com/influxdata/telegraf/issues/1628): Fix mongodb input panic on version 2.2.\n- [#1733](https://github.com/influxdata/telegraf/issues/1733): Fix statsd scientific notation parsing\n- [#1716](https://github.com/influxdata/telegraf/issues/1716): Sensors plugin strconv.ParseFloat: parsing \"\": invalid syntax\n- [#1530](https://github.com/influxdata/telegraf/issues/1530): Fix prometheus_client reload panic\n- [#1764](https://github.com/influxdata/telegraf/issues/1764): Fix kafka consumer panic when nil error is returned down errs channel.\n- [#1768](https://github.com/influxdata/telegraf/pull/1768): Speed up statsd parsing.\n- [#1751](https://github.com/influxdata/telegraf/issues/1751): Fix powerdns integer parse error handling.\n- [#1752](https://github.com/influxdata/telegraf/issues/1752): Fix varnish plugin defaults not being used.\n- [#1517](https://github.com/influxdata/telegraf/issues/1517): Fix windows glob paths.\n- [#1137](https://github.com/influxdata/telegraf/issues/1137): Fix issue loading config directory on windows.\n- [#1772](https://github.com/influxdata/telegraf/pull/1772): Windows remote management interactive service fix.\n- [#1702](https://github.com/influxdata/telegraf/issues/1702): sqlserver, fix issue when case sensitive collation is activated.\n- [#1823](https://github.com/influxdata/telegraf/issues/1823): Fix huge allocations in http_listener when dealing with huge payloads.\n- [#1833](https://github.com/influxdata/telegraf/issues/1833): Fix translating SNMP fields not in MIB.\n- [#1835](https://github.com/influxdata/telegraf/issues/1835): Fix SNMP emitting empty fields.\n- [#1854](https://github.com/influxdata/telegraf/pull/1853): SQL Server waitstats truncation bug.\n- [#1810](https://github.com/influxdata/telegraf/issues/1810): Fix logparser common log format: numbers in ident.\n- [#1793](https://github.com/influxdata/telegraf/pull/1793): Fix JSON Serialization in OpenTSDB output.\n- [#1731](https://github.com/influxdata/telegraf/issues/1731): Fix Graphite template ordering, use most specific.\n- [#1836](https://github.com/influxdata/telegraf/pull/1836): Fix snmp table field initialization for non-automatic table.\n- [#1724](https://github.com/influxdata/telegraf/issues/1724): cgroups path being parsed as metric.\n- [#1886](https://github.com/influxdata/telegraf/issues/1886): Fix phpfpm fcgi client panic when URL does not exist.\n- [#1344](https://github.com/influxdata/telegraf/issues/1344): Fix config file parse error logging.\n- [#1771](https://github.com/influxdata/telegraf/issues/1771): Delete nil fields in the metric maker.\n- [#870](https://github.com/influxdata/telegraf/issues/870): Fix MySQL special characters in DSN parsing.\n- [#1742](https://github.com/influxdata/telegraf/issues/1742): Ping input odd timeout behavior.\n- [#1950](https://github.com/influxdata/telegraf/pull/1950): Switch to github.com/kballard/go-shellquote.\n\n## v1.0.1 [2016-09-26]\n\n### Bug Fixes\n\n- [#1775](https://github.com/influxdata/telegraf/issues/1775): Prometheus output: Fix bug with multi-batch writes.\n- [#1738](https://github.com/influxdata/telegraf/issues/1738): Fix unmarshal of influxdb metrics with null tags.\n- [#1773](https://github.com/influxdata/telegraf/issues/1773): Add configurable timeout to influxdb input plugin.\n- [#1785](https://github.com/influxdata/telegraf/pull/1785): Fix statsd no default value panic.\n\n## v1.0 [2016-09-08]\n\n### Release Notes\n\n**Breaking Change** The SNMP plugin is being deprecated in it's current form.\nThere is a [new SNMP plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/snmp)\nwhich fixes many of the issues and confusions\nof its predecessor. For users wanting to continue to use the deprecated SNMP\nplugin, you will need to change your config file from `[[inputs.snmp]]` to\n`[[inputs.snmp_legacy]]`. The configuration of the new SNMP plugin is _not_\nbackwards-compatible.\n\n**Breaking Change**: Aerospike main server node measurements have been renamed\naerospike_node. Aerospike namespace measurements have been renamed to\naerospike_namespace. They will also now be tagged with the node_name\nthat they correspond to. This has been done to differentiate measurements\nthat pertain to node vs. namespace statistics.\n\n**Breaking Change**: users of github_webhooks must change to the new\n`[[inputs.webhooks]]` plugin.\n\nThis means that the default github_webhooks config:\n\n```toml\n# A Github Webhook Event collector\n[[inputs.github_webhooks]]\n  ## Address and port to host Webhook listener on\n  service_address = \":1618\"\n```\n\nshould now look like:\n\n```toml\n# A Webhooks Event collector\n[[inputs.webhooks]]\n  ## Address and port to host Webhook listener on\n  service_address = \":1618\"\n\n  [inputs.webhooks.github]\n    path = \"/\"\n```\n\n- Telegraf now supports being installed as an official windows service,\nwhich can be installed via\n`> C:\\Program Files\\Telegraf\\telegraf.exe --service install`\n\n- `flush_jitter` behavior has been changed. The random jitter will now be\nevaluated at every flush interval, rather than once at startup. This makes it\nconsistent with the behavior of `collection_jitter`.\n\n- postgresql plugins now handle oid and name typed columns seamlessly, previously they were ignored/skipped.\n\n### Features\n\n- [#1617](https://github.com/influxdata/telegraf/pull/1617): postgresql_extensible now handles name and oid types correctly.\n- [#1413](https://github.com/influxdata/telegraf/issues/1413): Separate container_version from container_image tag.\n- [#1525](https://github.com/influxdata/telegraf/pull/1525): Support setting per-device and total metrics for Docker network and blockio.\n- [#1466](https://github.com/influxdata/telegraf/pull/1466): MongoDB input plugin: adding per DB stats from db.stats()\n- [#1503](https://github.com/influxdata/telegraf/pull/1503): Add tls support for certs to RabbitMQ input plugin\n- [#1289](https://github.com/influxdata/telegraf/pull/1289): webhooks input plugin. Thanks @francois2metz and @cduez!\n- [#1247](https://github.com/influxdata/telegraf/pull/1247): rollbar webhook plugin.\n- [#1408](https://github.com/influxdata/telegraf/pull/1408): mandrill webhook plugin.\n- [#1402](https://github.com/influxdata/telegraf/pull/1402): docker-machine/boot2docker no longer required for unit tests.\n- [#1350](https://github.com/influxdata/telegraf/pull/1350): cgroup input plugin.\n- [#1369](https://github.com/influxdata/telegraf/pull/1369): Add input plugin for consuming metrics from NSQD.\n- [#1369](https://github.com/influxdata/telegraf/pull/1480): add ability to read redis from a socket.\n- [#1387](https://github.com/influxdata/telegraf/pull/1387): **Breaking Change** - Redis `role` tag renamed to `replication_role` to avoid global_tags override\n- [#1437](https://github.com/influxdata/telegraf/pull/1437): Fetching Galera status metrics in MySQL\n- [#1500](https://github.com/influxdata/telegraf/pull/1500): Aerospike plugin refactored to use official client lib.\n- [#1434](https://github.com/influxdata/telegraf/pull/1434): Add measurement name arg to logparser plugin.\n- [#1479](https://github.com/influxdata/telegraf/pull/1479): logparser: change resp_code from a field to a tag.\n- [#1411](https://github.com/influxdata/telegraf/pull/1411): Implement support for fetching hddtemp data\n- [#1340](https://github.com/influxdata/telegraf/issues/1340): statsd: do not log every dropped metric.\n- [#1368](https://github.com/influxdata/telegraf/pull/1368): Add precision rounding to all metrics on collection.\n- [#1390](https://github.com/influxdata/telegraf/pull/1390): Add support for Tengine\n- [#1320](https://github.com/influxdata/telegraf/pull/1320): Logparser input plugin for parsing grok-style log patterns.\n- [#1397](https://github.com/influxdata/telegraf/issues/1397): ElasticSearch: now supports connecting to ElasticSearch via SSL\n- [#1262](https://github.com/influxdata/telegraf/pull/1261): Add graylog input plugin.\n- [#1294](https://github.com/influxdata/telegraf/pull/1294): consul input plugin. Thanks @harnash\n- [#1164](https://github.com/influxdata/telegraf/pull/1164): conntrack input plugin. Thanks @robinpercy!\n- [#1165](https://github.com/influxdata/telegraf/pull/1165): vmstat input plugin. Thanks @jshim-xm!\n- [#1208](https://github.com/influxdata/telegraf/pull/1208): Standardized AWS credentials evaluation & wildcard CloudWatch dimensions. Thanks @johnrengelman!\n- [#1264](https://github.com/influxdata/telegraf/pull/1264): Add SSL config options to http_response plugin.\n- [#1272](https://github.com/influxdata/telegraf/pull/1272): graphite parser: add ability to specify multiple tag keys, for consistency with influxdb parser.\n- [#1265](https://github.com/influxdata/telegraf/pull/1265): Make dns lookups for chrony configurable. Thanks @zbindenren!\n- [#1275](https://github.com/influxdata/telegraf/pull/1275): Allow wildcard filtering of varnish stats.\n- [#1142](https://github.com/influxdata/telegraf/pull/1142): Support for glob patterns in exec plugin commands configuration.\n- [#1278](https://github.com/influxdata/telegraf/pull/1278): RabbitMQ input: made url parameter optional by using DefaultURL `http://localhost:15672` if not specified\n- [#1197](https://github.com/influxdata/telegraf/pull/1197): Limit AWS GetMetricStatistics requests to 10 per second.\n- [#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\n- [#1296](https://github.com/influxdata/telegraf/issues/1296): Refactor of flush_jitter argument.\n- [#1213](https://github.com/influxdata/telegraf/issues/1213): Add inactive & active memory to mem plugin.\n- [#1543](https://github.com/influxdata/telegraf/pull/1543): Official Windows service.\n- [#1414](https://github.com/influxdata/telegraf/pull/1414): Forking sensors command to remove C package dependency.\n- [#1389](https://github.com/influxdata/telegraf/pull/1389): Add a new SNMP plugin.\n\n### Bug Fixes\n\n- [#1619](https://github.com/influxdata/telegraf/issues/1619): Fix `make windows` build target\n- [#1519](https://github.com/influxdata/telegraf/pull/1519): Fix error race conditions and partial failures.\n- [#1477](https://github.com/influxdata/telegraf/issues/1477): nstat: fix inaccurate config panic.\n- [#1481](https://github.com/influxdata/telegraf/issues/1481): jolokia: fix handling multiple multi-dimensional attributes.\n- [#1430](https://github.com/influxdata/telegraf/issues/1430): Fix prometheus character sanitizing. Sanitize more win_perf_counters characters.\n- [#1534](https://github.com/influxdata/telegraf/pull/1534): Add diskio io_time to FreeBSD & report timing metrics as ms (as linux does).\n- [#1379](https://github.com/influxdata/telegraf/issues/1379): Fix covering Amazon Linux for post remove flow.\n- [#1584](https://github.com/influxdata/telegraf/issues/1584): procstat missing fields: read/write bytes & count\n- [#1472](https://github.com/influxdata/telegraf/pull/1472): diskio input plugin: set 'skip_serial_number = true' by default to avoid high cardinality.\n- [#1426](https://github.com/influxdata/telegraf/pull/1426): nil metrics panic fix.\n- [#1384](https://github.com/influxdata/telegraf/pull/1384): Fix datarace in apache input plugin.\n- [#1399](https://github.com/influxdata/telegraf/issues/1399): Add `read_repairs` statistics to riak plugin.\n- [#1405](https://github.com/influxdata/telegraf/issues/1405): Fix memory/connection leak in prometheus input plugin.\n- [#1378](https://github.com/influxdata/telegraf/issues/1378): Trim BOM from config file for Windows support.\n- [#1339](https://github.com/influxdata/telegraf/issues/1339): Prometheus client output panic on service reload.\n- [#1461](https://github.com/influxdata/telegraf/pull/1461): Prometheus parser, protobuf format header fix.\n- [#1334](https://github.com/influxdata/telegraf/issues/1334): Prometheus output, metric refresh and caching fixes.\n- [#1432](https://github.com/influxdata/telegraf/issues/1432): Panic fix for multiple graphite outputs under very high load.\n- [#1412](https://github.com/influxdata/telegraf/pull/1412): Instrumental output has better reconnect behavior\n- [#1460](https://github.com/influxdata/telegraf/issues/1460): Remove PID from procstat plugin to fix cardinality issues.\n- [#1427](https://github.com/influxdata/telegraf/issues/1427): Cassandra input: version 2.x \"column family\" fix.\n- [#1463](https://github.com/influxdata/telegraf/issues/1463): Shared WaitGroup in Exec plugin\n- [#1436](https://github.com/influxdata/telegraf/issues/1436): logparser: honor modifiers in \"pattern\" config.\n- [#1418](https://github.com/influxdata/telegraf/issues/1418): logparser: error and exit on file permissions/missing errors.\n- [#1499](https://github.com/influxdata/telegraf/pull/1499): Make the user able to specify full path for HAproxy stats\n- [#1521](https://github.com/influxdata/telegraf/pull/1521): Fix Redis url, an extra \"tcp://\" was added.\n- [#1330](https://github.com/influxdata/telegraf/issues/1330): Fix exec plugin panic when using single binary.\n- [#1336](https://github.com/influxdata/telegraf/issues/1336): Fixed incorrect prometheus metrics source selection.\n- [#1112](https://github.com/influxdata/telegraf/issues/1112): Set default Zookeeper chroot to empty string.\n- [#1335](https://github.com/influxdata/telegraf/issues/1335): Fix overall ping timeout to be calculated based on per-ping timeout.\n- [#1374](https://github.com/influxdata/telegraf/pull/1374): Change \"default\" retention policy to \"\".\n- [#1377](https://github.com/influxdata/telegraf/issues/1377): Graphite output mangling '%' character.\n- [#1396](https://github.com/influxdata/telegraf/pull/1396): Prometheus input plugin now supports x509 certs authentication\n- [#1252](https://github.com/influxdata/telegraf/pull/1252) & [#1279](https://github.com/influxdata/telegraf/pull/1279): Fix systemd service. Thanks @zbindenren & @PierreF!\n- [#1221](https://github.com/influxdata/telegraf/pull/1221): Fix influxdb n_shards counter.\n- [#1258](https://github.com/influxdata/telegraf/pull/1258): Fix potential kernel plugin integer parse error.\n- [#1268](https://github.com/influxdata/telegraf/pull/1268): Fix potential influxdb input type assertion panic.\n- [#1283](https://github.com/influxdata/telegraf/pull/1283): Still send processes metrics if a process exited during metric collection.\n- [#1297](https://github.com/influxdata/telegraf/issues/1297): disk plugin panic when usage grab fails.\n- [#1316](https://github.com/influxdata/telegraf/pull/1316): Removed leaked \"database\" tag on redis metrics. Thanks @PierreF!\n- [#1323](https://github.com/influxdata/telegraf/issues/1323): Processes plugin: fix potential error with /proc/net/stat directory.\n- [#1322](https://github.com/influxdata/telegraf/issues/1322): Fix rare RHEL 5.2 panic in gopsutil diskio gathering function.\n- [#1586](https://github.com/influxdata/telegraf/pull/1586): Remove IF NOT EXISTS from influxdb output database creation.\n- [#1600](https://github.com/influxdata/telegraf/issues/1600): Fix quoting with text values in postgresql_extensible plugin.\n- [#1425](https://github.com/influxdata/telegraf/issues/1425): Fix win_perf_counter \"index out of range\" panic.\n- [#1634](https://github.com/influxdata/telegraf/issues/1634): Fix ntpq panic when field is missing.\n- [#1637](https://github.com/influxdata/telegraf/issues/1637): Sanitize graphite output field names.\n- [#1695](https://github.com/influxdata/telegraf/pull/1695): Fix MySQL plugin not sending 0 value fields.\n\n## v0.13.1 [2016-05-24]\n\n### Release Notes\n\n- net_response and http_response plugins timeouts will now accept duration\nstrings, ie, \"2s\" or \"500ms\".\n- Input plugin Gathers will no longer be logged by default, but a Gather for\n_each_ plugin will be logged in Debug mode.\n- Debug mode will no longer print every point added to the accumulator. This\nfunctionality can be duplicated using the `file` output plugin and printing\nto \"stdout\".\n\n### Features\n\n- [#1173](https://github.com/influxdata/telegraf/pull/1173): varnish input plugin. Thanks @sfox-xmatters!\n- [#1138](https://github.com/influxdata/telegraf/pull/1138): nstat input plugin. Thanks @Maksadbek!\n- [#1139](https://github.com/influxdata/telegraf/pull/1139): instrumental output plugin. Thanks @jasonroelofs!\n- [#1172](https://github.com/influxdata/telegraf/pull/1172): Ceph storage stats. Thanks @robinpercy!\n- [#1233](https://github.com/influxdata/telegraf/pull/1233): Updated golint gopsutil dependency.\n- [#1238](https://github.com/influxdata/telegraf/pull/1238): chrony input plugin. Thanks @zbindenren!\n- [#479](https://github.com/influxdata/telegraf/issues/479): per-plugin execution time added to debug output.\n- [#1249](https://github.com/influxdata/telegraf/issues/1249): influxdb output: added write_consistency argument.\n\n### Bug Fixes\n\n- [#1195](https://github.com/influxdata/telegraf/pull/1195): Docker panic on timeout. Thanks @zstyblik!\n- [#1211](https://github.com/influxdata/telegraf/pull/1211): mongodb input. Fix possible panic. Thanks @kols!\n- [#1215](https://github.com/influxdata/telegraf/pull/1215): Fix for possible gopsutil-dependent plugin hangs.\n- [#1228](https://github.com/influxdata/telegraf/pull/1228): Fix service plugin host tag overwrite.\n- [#1198](https://github.com/influxdata/telegraf/pull/1198): http_response: override request Host header properly\n- [#1230](https://github.com/influxdata/telegraf/issues/1230): Fix Telegraf process hangup due to a single plugin hanging.\n- [#1214](https://github.com/influxdata/telegraf/issues/1214): Use TCP timeout argument in net_response plugin.\n- [#1243](https://github.com/influxdata/telegraf/pull/1243): Logfile not created on systemd.\n\n## v0.13 [2016-05-11]\n\n### Release Notes\n\n- **Breaking change** in jolokia plugin. See the\n[jolokia README](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/jolokia/README.md)\nfor updated configuration. The plugin will now support proxy mode and will make\nPOST requests.\n\n- New [agent] configuration option: `metric_batch_size`. This option tells\ntelegraf the maximum batch size to allow to accumulate before sending a flush\nto the configured outputs. `metric_buffer_limit` now refers to the absolute\nmaximum number of metrics that will accumulate before metrics are dropped.\n\n- There is no longer an option to\n`flush_buffer_when_full`, this is now the default and only behavior of telegraf.\n\n- **Breaking Change**: docker plugin tags. The cont_id tag no longer exists, it\nwill now be a field, and be called container_id. Additionally, cont_image and\ncont_name are being renamed to container_image and container_name.\n\n- **Breaking Change**: docker plugin measurements. The `docker_cpu`, `docker_mem`,\n`docker_blkio` and `docker_net` measurements are being renamed to\n`docker_container_cpu`, `docker_container_mem`, `docker_container_blkio` and\n`docker_container_net`. Why? Because these metrics are\nspecifically tracking per-container stats. The problem with per-container stats,\nin some use-cases, is that if containers are short-lived AND names are not\nkept consistent, then the series cardinality will balloon very quickly.\nSo adding \"container\" to each metric will:\n(1) make it more clear that these metrics are per-container, and\n(2) allow users to easily drop per-container metrics if cardinality is an\nissue (`namedrop = [\"docker_container_*\"]`)\n\n- `tagexclude` and `taginclude` are now available, which can be used to remove\ntags from measurements on inputs and outputs. See\n[the configuration doc](https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md)\nfor more details.\n\n- **Measurement filtering:** All measurement filters now match based on glob\nonly. Previously there was an undocumented behavior where filters would match\nbased on _prefix_ in addition to globs. This means that a filter like\n`fielddrop = [\"time_\"]` will need to be changed to `fielddrop = [\"time_*\"]`\n\n- **datadog**: measurement and field names will no longer have `_` replaced by `.`\n\n- The following plugins have changed their tags to _not_ overwrite the host tag:\n  - cassandra: `host -> cassandra_host`\n  - disque: `host -> disque_host`\n  - rethinkdb: `host -> rethinkdb_host`\n\n- **Breaking Change**: The `win_perf_counters` input has been changed to\nsanitize field names, replacing `/Sec` and `/sec` with `_persec`, as well as\nspaces with underscores. This is needed because Graphite doesn't like slashes\nand spaces, and was failing to accept metrics that had them.\nThe `/[sS]ec` -> `_persec` is just to make things clearer and uniform.\n\n- **Breaking Change**: snmp plugin. The `host` tag of the snmp plugin has been\nchanged to the `snmp_host` tag.\n\n- The `disk` input plugin can now be configured with the `HOST_MOUNT_PREFIX` environment variable.\nThis value is prepended to any mountpaths discovered before retrieving stats.\nIt is not included on the report path. This is necessary for reporting host disk stats when running from within a container.\n\n### Features\n\n- [#1031](https://github.com/influxdata/telegraf/pull/1031): Jolokia plugin proxy mode. Thanks @saiello!\n- [#1017](https://github.com/influxdata/telegraf/pull/1017): taginclude and tagexclude arguments.\n- [#1015](https://github.com/influxdata/telegraf/pull/1015): Docker plugin schema refactor.\n- [#889](https://github.com/influxdata/telegraf/pull/889): Improved MySQL plugin. Thanks @maksadbek!\n- [#1060](https://github.com/influxdata/telegraf/pull/1060): TTL metrics added to MongoDB input plugin\n- [#1056](https://github.com/influxdata/telegraf/pull/1056): Don't allow inputs to overwrite host tags.\n- [#1035](https://github.com/influxdata/telegraf/issues/1035): Add `user`, `exe`, `pidfile` tags to procstat plugin.\n- [#1041](https://github.com/influxdata/telegraf/issues/1041): Add `n_cpus` field to the system plugin.\n- [#1072](https://github.com/influxdata/telegraf/pull/1072): New Input Plugin: filestat.\n- [#1066](https://github.com/influxdata/telegraf/pull/1066): Replication lag metrics for MongoDB input plugin\n- [#1086](https://github.com/influxdata/telegraf/pull/1086): Ability to specify AWS keys in config file. Thanks @johnrengelman!\n- [#1096](https://github.com/influxdata/telegraf/pull/1096): Performance refactor of running output buffers.\n- [#967](https://github.com/influxdata/telegraf/issues/967): Buffer logging improvements.\n- [#1107](https://github.com/influxdata/telegraf/issues/1107): Support lustre2 job stats. Thanks @hanleyja!\n- [#1122](https://github.com/influxdata/telegraf/pull/1122): Support setting config path through env variable and default paths.\n- [#1128](https://github.com/influxdata/telegraf/pull/1128): MongoDB jumbo chunks metric for MongoDB input plugin\n- [#1146](https://github.com/influxdata/telegraf/pull/1146): HAProxy socket support. Thanks weshmashian!\n\n### Bug Fixes\n\n- [#1050](https://github.com/influxdata/telegraf/issues/1050): jolokia plugin - do not overwrite host tag. Thanks @saiello!\n- [#921](https://github.com/influxdata/telegraf/pull/921): mqtt_consumer stops gathering metrics. Thanks @chaton78!\n- [#1013](https://github.com/influxdata/telegraf/pull/1013): Close dead riemann output connections. Thanks @echupriyanov!\n- [#1012](https://github.com/influxdata/telegraf/pull/1012): Set default tags in test accumulator.\n- [#1024](https://github.com/influxdata/telegraf/issues/1024): Don't replace `.` with `_` in datadog output.\n- [#1058](https://github.com/influxdata/telegraf/issues/1058): Fix possible leaky TCP connections in influxdb output.\n- [#1044](https://github.com/influxdata/telegraf/pull/1044): Fix SNMP OID possible collisions. Thanks @relip\n- [#1022](https://github.com/influxdata/telegraf/issues/1022): Dont error deb/rpm install on systemd errors.\n- [#1078](https://github.com/influxdata/telegraf/issues/1078): Use default AWS credential chain.\n- [#1070](https://github.com/influxdata/telegraf/issues/1070): SQL Server input. Fix datatype conversion.\n- [#1089](https://github.com/influxdata/telegraf/issues/1089): Fix leaky TCP connections in phpfpm plugin.\n- [#914](https://github.com/influxdata/telegraf/issues/914): Telegraf can drop metrics on full buffers.\n- [#1098](https://github.com/influxdata/telegraf/issues/1098): Sanitize invalid OpenTSDB characters.\n- [#1110](https://github.com/influxdata/telegraf/pull/1110): Sanitize * to - in graphite serializer. Thanks @goodeggs!\n- [#1118](https://github.com/influxdata/telegraf/pull/1118): Sanitize Counter names for `win_perf_counters` input.\n- [#1125](https://github.com/influxdata/telegraf/pull/1125): Wrap all exec command runners with a timeout, so hung os processes don't halt Telegraf.\n- [#1113](https://github.com/influxdata/telegraf/pull/1113): Set MaxRetry and RequiredAcks defaults in Kafka output.\n- [#1090](https://github.com/influxdata/telegraf/issues/1090): [agent] and [global_tags] config sometimes not getting applied.\n- [#1133](https://github.com/influxdata/telegraf/issues/1133): Use a timeout for docker list & stat cmds.\n- [#1052](https://github.com/influxdata/telegraf/issues/1052): Docker panic fix when decode fails.\n- [#1136](https://github.com/influxdata/telegraf/pull/1136): \"DELAYED\" Inserts were deprecated in MySQL 5.6.6. Thanks @PierreF\n\n## v0.12.1 [2016-04-14]\n\n### Release Notes\n\n- Breaking change in the dovecot input plugin. See Features section below.\n- Graphite output templates are now supported. See the\n[Output Formats README](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md#graphite)\n- Possible breaking change for the librato and graphite outputs. Telegraf will\nno longer insert field names when the field is simply named `value`. This is\nbecause the `value` field is redundant in the graphite/librato context.\n\n### Features\n\n- [#1009](https://github.com/influxdata/telegraf/pull/1009): Cassandra input plugin. Thanks @subhachandrachandra!\n- [#976](https://github.com/influxdata/telegraf/pull/976): Reduce allocations in the UDP and statsd inputs.\n- [#979](https://github.com/influxdata/telegraf/pull/979): Reduce allocations in the TCP listener.\n- [#992](https://github.com/influxdata/telegraf/pull/992): Refactor allocations in TCP/UDP listeners.\n- [#935](https://github.com/influxdata/telegraf/pull/935): AWS Cloudwatch input plugin. Thanks @joshhardy & @ljosa!\n- [#943](https://github.com/influxdata/telegraf/pull/943): http_response input plugin. Thanks @Lswith!\n- [#939](https://github.com/influxdata/telegraf/pull/939): sysstat input plugin. Thanks @zbindenren!\n- [#998](https://github.com/influxdata/telegraf/pull/998): **breaking change** enabled global, user and ip queries in dovecot plugin. Thanks @mikif70!\n- [#1001](https://github.com/influxdata/telegraf/pull/1001): Graphite serializer templates.\n- [#1008](https://github.com/influxdata/telegraf/pull/1008): Adding memstats metrics to the influxdb plugin.\n\n### Bug Fixes\n\n- [#968](https://github.com/influxdata/telegraf/issues/968): Processes plugin gets unknown state when spaces are in (command name)\n- [#969](https://github.com/influxdata/telegraf/pull/969): ipmi_sensors: allow : in password. Thanks @awaw!\n- [#972](https://github.com/influxdata/telegraf/pull/972): dovecot: remove extra newline in dovecot command. Thanks @mrannanj!\n- [#645](https://github.com/influxdata/telegraf/issues/645): docker plugin i/o error on closed pipe. Thanks @tripledes!\n\n## v0.12.0 [2016-04-05]\n\n### Features\n\n- [#951](https://github.com/influxdata/telegraf/pull/951): Parse environment variables in the config file.\n- [#948](https://github.com/influxdata/telegraf/pull/948): Cleanup config file and make default package version include all plugins (but commented).\n- [#927](https://github.com/influxdata/telegraf/pull/927): Adds parsing of tags to the statsd input when using DataDog's dogstatsd extension\n- [#863](https://github.com/influxdata/telegraf/pull/863): AMQP output: allow external auth. Thanks @ekini!\n- [#707](https://github.com/influxdata/telegraf/pull/707): Improved prometheus plugin. Thanks @titilambert!\n- [#878](https://github.com/influxdata/telegraf/pull/878): Added json serializer. Thanks @ch3lo!\n- [#880](https://github.com/influxdata/telegraf/pull/880): Add the ability to specify the bearer token to the prometheus plugin. Thanks @jchauncey!\n- [#882](https://github.com/influxdata/telegraf/pull/882): Fixed SQL Server Plugin issues\n- [#849](https://github.com/influxdata/telegraf/issues/849): Adding ability to parse single values as an input data type.\n- [#844](https://github.com/influxdata/telegraf/pull/844): postgres_extensible plugin added. Thanks @menardorama!\n- [#866](https://github.com/influxdata/telegraf/pull/866): couchbase input plugin. Thanks @ljosa!\n- [#789](https://github.com/influxdata/telegraf/pull/789): Support multiple field specification and `field*` in graphite templates. Thanks @chrusty!\n- [#762](https://github.com/influxdata/telegraf/pull/762): Nagios parser for the exec plugin. Thanks @titilambert!\n- [#848](https://github.com/influxdata/telegraf/issues/848): Provide option to omit host tag from telegraf agent.\n- [#928](https://github.com/influxdata/telegraf/pull/928): Deprecating the statsd \"convert_names\" options, expose separator config.\n- [#919](https://github.com/influxdata/telegraf/pull/919): ipmi_sensor input plugin. Thanks @ebookbug!\n- [#945](https://github.com/influxdata/telegraf/pull/945): KAFKA output: codec, acks, and retry configuration. Thanks @framiere!\n\n### Bug Fixes\n\n- [#890](https://github.com/influxdata/telegraf/issues/890): Create TLS config even if only ssl_ca is provided.\n- [#884](https://github.com/influxdata/telegraf/issues/884): Do not call write method if there are 0 metrics to write.\n- [#898](https://github.com/influxdata/telegraf/issues/898): Put database name in quotes, fixes special characters in the database name.\n- [#656](https://github.com/influxdata/telegraf/issues/656): No longer run `lsof` on linux to get netstat data, fixes permissions issue.\n- [#907](https://github.com/influxdata/telegraf/issues/907): Fix prometheus invalid label/measurement name key.\n- [#841](https://github.com/influxdata/telegraf/issues/841): Fix memcached unix socket panic.\n- [#873](https://github.com/influxdata/telegraf/issues/873): Fix SNMP plugin sometimes not returning metrics. Thanks @titilambert!\n- [#934](https://github.com/influxdata/telegraf/pull/934): phpfpm: Fix fcgi uri path. Thanks @rudenkovk!\n- [#805](https://github.com/influxdata/telegraf/issues/805): Kafka consumer stops gathering after i/o timeout.\n- [#959](https://github.com/influxdata/telegraf/pull/959): reduce mongodb & prometheus collection timeouts. Thanks @PierreF!\n\n## v0.11.1 [2016-03-17]\n\n### Release Notes\n\n- Primarily this release was cut to fix [#859](https://github.com/influxdata/telegraf/issues/859)\n\n### Features\n\n- [#747](https://github.com/influxdata/telegraf/pull/747): Start telegraf on install & remove on uninstall. Thanks @PierreF!\n- [#794](https://github.com/influxdata/telegraf/pull/794): Add service reload ability. Thanks @entertainyou!\n\n### Bug Fixes\n\n- [#852](https://github.com/influxdata/telegraf/issues/852): Windows zip package fix\n- [#859](https://github.com/influxdata/telegraf/issues/859): httpjson plugin panic\n\n## v0.11.0 [2016-03-15]\n\n### Features\n\n- [#692](https://github.com/influxdata/telegraf/pull/770): Support InfluxDB retention policies\n- [#771](https://github.com/influxdata/telegraf/pull/771): Default timeouts for input plugns. Thanks @PierreF!\n- [#758](https://github.com/influxdata/telegraf/pull/758): UDP Listener input plugin, thanks @whatyouhide!\n- [#769](https://github.com/influxdata/telegraf/issues/769): httpjson plugin: allow specifying SSL configuration.\n- [#735](https://github.com/influxdata/telegraf/pull/735): SNMP Table feature. Thanks @titilambert!\n- [#754](https://github.com/influxdata/telegraf/pull/754): docker plugin: adding `docker info` metrics to output. Thanks @titilambert!\n- [#788](https://github.com/influxdata/telegraf/pull/788): -input-list and -output-list command-line options. Thanks @ebookbug!\n- [#778](https://github.com/influxdata/telegraf/pull/778): Adding a TCP input listener.\n- [#797](https://github.com/influxdata/telegraf/issues/797): Provide option for persistent MQTT consumer client sessions.\n- [#799](https://github.com/influxdata/telegraf/pull/799): Add number of threads for procstat input plugin. Thanks @titilambert!\n- [#776](https://github.com/influxdata/telegraf/pull/776): Add Zookeeper chroot option to kafka_consumer. Thanks @prune998!\n- [#811](https://github.com/influxdata/telegraf/pull/811): Add processes plugin for classifying total procs on system. Thanks @titilambert!\n- [#235](https://github.com/influxdata/telegraf/issues/235): Add number of users to the `system` input plugin.\n- [#826](https://github.com/influxdata/telegraf/pull/826): \"kernel\" linux plugin for /proc/stat metrics (context switches, interrupts, etc.)\n- [#847](https://github.com/influxdata/telegraf/pull/847): `ntpq`: Input plugin for running ntp query executable and gathering metrics.\n\n### Bug Fixes\n\n- [#748](https://github.com/influxdata/telegraf/issues/748): Fix sensor plugin split on \":\"\n- [#722](https://github.com/influxdata/telegraf/pull/722): Librato output plugin fixes. Thanks @chrusty!\n- [#745](https://github.com/influxdata/telegraf/issues/745): Fix Telegraf toml parse panic on large config files. Thanks @titilambert!\n- [#781](https://github.com/influxdata/telegraf/pull/781): Fix mqtt_consumer username not being set. Thanks @chaton78!\n- [#786](https://github.com/influxdata/telegraf/pull/786): Fix mqtt output username not being set. Thanks @msangoi!\n- [#773](https://github.com/influxdata/telegraf/issues/773): Fix duplicate measurements in snmp plugin. Thanks @titilambert!\n- [#708](https://github.com/influxdata/telegraf/issues/708): packaging: build ARM package\n- [#713](https://github.com/influxdata/telegraf/issues/713): packaging: insecure permissions error on log directory\n- [#816](https://github.com/influxdata/telegraf/issues/816): Fix phpfpm panic if fcgi endpoint unreachable.\n- [#828](https://github.com/influxdata/telegraf/issues/828): fix net_response plugin overwriting host tag.\n- [#821](https://github.com/influxdata/telegraf/issues/821): Remove postgres password from server tag. Thanks @menardorama!\n\n## v0.10.4.1\n\n### Release Notes\n\n- Bug in the build script broke deb and rpm packages.\n\n### Bug Fixes\n\n- [#750](https://github.com/influxdata/telegraf/issues/750): deb package broken\n- [#752](https://github.com/influxdata/telegraf/issues/752): rpm package broken\n\n## v0.10.4 [2016-02-24]\n\n### Release Notes\n\n- The pass/drop parameters have been renamed to fielddrop/fieldpass parameters,\nto more accurately indicate their purpose.\n- There are also now namedrop/namepass parameters for passing/dropping based\non the metric _name_.\n- Experimental windows builds now available.\n\n### Features\n\n- [#727](https://github.com/influxdata/telegraf/pull/727): riak input, thanks @jcoene!\n- [#694](https://github.com/influxdata/telegraf/pull/694): DNS Query input, thanks @mjasion!\n- [#724](https://github.com/influxdata/telegraf/pull/724): username matching for procstat input, thanks @zorel!\n- [#736](https://github.com/influxdata/telegraf/pull/736): Ignore dummy filesystems from disk plugin. Thanks @PierreF!\n- [#737](https://github.com/influxdata/telegraf/pull/737): Support multiple fields for statsd input. Thanks @mattheath!\n\n### Bug Fixes\n\n- [#701](https://github.com/influxdata/telegraf/pull/701): output write count shouldnt print in quiet mode.\n- [#746](https://github.com/influxdata/telegraf/pull/746): httpjson plugin: Fix HTTP GET parameters.\n\n## v0.10.3 [2016-02-18]\n\n### Release Notes\n\n- Users of the `exec` and `kafka_consumer` (and the new `nats_consumer`\nand `mqtt_consumer` plugins) can now specify the incoming data\nformat that they would like to parse. Currently supports: \"json\", \"influx\", and\n\"graphite\"\n- Users of message broker and file output plugins can now choose what data format\nthey would like to output. Currently supports: \"influx\" and \"graphite\"\n- For more info on parsing _incoming_ data formats see the\n  [documentation](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md)\n- For more info on serializing _outgoing_ data formats see the\n  [documentation](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md)\n- Telegraf now has an option `flush_buffer_when_full` that will flush the\nmetric buffer whenever it fills up for each output, rather than dropping\npoints and only flushing on a set time interval. This will default to `true`\nand is in the `[agent]` config section.\n\n### Features\n\n- [#652](https://github.com/influxdata/telegraf/pull/652): CouchDB Input Plugin. Thanks @codehate!\n- [#655](https://github.com/influxdata/telegraf/pull/655): Support parsing arbitrary data formats. Currently limited to kafka_consumer and exec inputs.\n- [#671](https://github.com/influxdata/telegraf/pull/671): Dovecot input plugin. Thanks @mikif70!\n- [#680](https://github.com/influxdata/telegraf/pull/680): NATS consumer input plugin. Thanks @netixen!\n- [#676](https://github.com/influxdata/telegraf/pull/676): MQTT consumer input plugin.\n- [#683](https://github.com/influxdata/telegraf/pull/683): PostGRES input plugin: add pg_stat_bgwriter. Thanks @menardorama!\n- [#679](https://github.com/influxdata/telegraf/pull/679): File/stdout output plugin.\n- [#679](https://github.com/influxdata/telegraf/pull/679): Support for arbitrary output data formats.\n- [#695](https://github.com/influxdata/telegraf/pull/695): raindrops input plugin. Thanks @burdandrei!\n- [#650](https://github.com/influxdata/telegraf/pull/650): net_response input plugin. Thanks @titilambert!\n- [#699](https://github.com/influxdata/telegraf/pull/699): Flush based on buffer size rather than time.\n- [#682](https://github.com/influxdata/telegraf/pull/682): Mesos input plugin. Thanks @tripledes!\n\n### Bug Fixes\n\n- [#443](https://github.com/influxdata/telegraf/issues/443): Fix Ping command timeout parameter on Linux.\n- [#662](https://github.com/influxdata/telegraf/pull/667): Change `[tags]` to `[global_tags]` to fix multiple-plugin tags bug.\n- [#642](https://github.com/influxdata/telegraf/issues/642): Riemann output plugin issues.\n- [#394](https://github.com/influxdata/telegraf/issues/394): Support HTTP POST. Thanks @gabelev!\n- [#715](https://github.com/influxdata/telegraf/pull/715): Fix influxdb precision config panic. Thanks @netixen!\n\n## v0.10.2 [2016-02-04]\n\n### Release Notes\n\n- Statsd timing measurements are now aggregated into a single measurement with\nfields.\n- Graphite output now inserts tags into the bucket in alphabetical order.\n- Normalized TLS/SSL support for output plugins: MQTT, AMQP, Kafka\n- `verify_ssl` config option was removed from Kafka because it was actually\ndoing the opposite of what it claimed to do (yikes). It's been replaced by\n`insecure_skip_verify`\n\n### Features\n\n- [#575](https://github.com/influxdata/telegraf/pull/575): Support for collecting Windows Performance Counters. Thanks @TheFlyingCorpse!\n- [#564](https://github.com/influxdata/telegraf/issues/564): features for plugin writing simplification. Internal metric data type.\n- [#603](https://github.com/influxdata/telegraf/pull/603): Aggregate statsd timing measurements into fields. Thanks @marcinbunsch!\n- [#601](https://github.com/influxdata/telegraf/issues/601): Warn when overwriting cached metrics.\n- [#614](https://github.com/influxdata/telegraf/pull/614): PowerDNS input plugin. Thanks @Kasen!\n- [#617](https://github.com/influxdata/telegraf/pull/617): exec plugin: parse influx line protocol in addition to JSON.\n- [#628](https://github.com/influxdata/telegraf/pull/628): Windows perf counters: pre-vista support\n\n### Bug Fixes\n\n- [#595](https://github.com/influxdata/telegraf/issues/595): graphite output should include tags to separate duplicate measurements.\n- [#599](https://github.com/influxdata/telegraf/issues/599): datadog plugin tags not working.\n- [#600](https://github.com/influxdata/telegraf/issues/600): datadog measurement/field name parsing is wrong.\n- [#602](https://github.com/influxdata/telegraf/issues/602): Fix statsd field name templating.\n- [#612](https://github.com/influxdata/telegraf/pull/612): Docker input panic fix if stats received are nil.\n- [#634](https://github.com/influxdata/telegraf/pull/634): Properly set host headers in httpjson. Thanks @reginaldosousa!\n\n## v0.10.1 [2016-01-27]\n\n### Release Notes\n\n- Telegraf now keeps a fixed-length buffer of metrics per-output. This buffer\ndefaults to 10,000 metrics, and is adjustable. The buffer is cleared when a\nsuccessful write to that output occurs.\n- The docker plugin has been significantly overhauled to add more metrics\nand allow for docker-machine (incl OSX) support.\n[See the readme](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/docker/README.md)\nfor the latest measurements, fields, and tags. There is also now support for\nspecifying a docker endpoint to get metrics from.\n\n### Features\n\n- [#509](https://github.com/influxdata/telegraf/pull/509): Flatten JSON arrays with indices. Thanks @psilva261!\n- [#512](https://github.com/influxdata/telegraf/pull/512): Python 3 build script, add lsof dep to package. Thanks @Ormod!\n- [#475](https://github.com/influxdata/telegraf/pull/475): Add response time to httpjson plugin. Thanks @titilambert!\n- [#519](https://github.com/influxdata/telegraf/pull/519): Added a sensors input based on lm-sensors. Thanks @md14454!\n- [#467](https://github.com/influxdata/telegraf/issues/467): Add option to disable statsd measurement name conversion.\n- [#534](https://github.com/influxdata/telegraf/pull/534): NSQ input plugin. Thanks @allingeek!\n- [#494](https://github.com/influxdata/telegraf/pull/494): Graphite output plugin. Thanks @titilambert!\n- AMQP SSL support. Thanks @ekini!\n- [#539](https://github.com/influxdata/telegraf/pull/539): Reload config on SIGHUP. Thanks @titilambert!\n- [#522](https://github.com/influxdata/telegraf/pull/522): Phusion passenger input plugin. Thanks @kureikain!\n- [#541](https://github.com/influxdata/telegraf/pull/541): Kafka output TLS cert support. Thanks @Ormod!\n- [#551](https://github.com/influxdata/telegraf/pull/551): Statsd UDP read packet size now defaults to 1500 bytes, and is configurable.\n- [#552](https://github.com/influxdata/telegraf/pull/552): Support for collection interval jittering.\n- [#484](https://github.com/influxdata/telegraf/issues/484): Include usage percent with procstat metrics.\n- [#553](https://github.com/influxdata/telegraf/pull/553): Amazon CloudWatch output. thanks @skwong2!\n- [#503](https://github.com/influxdata/telegraf/pull/503): Support docker endpoint configuration.\n- [#563](https://github.com/influxdata/telegraf/pull/563): Docker plugin overhaul.\n- [#285](https://github.com/influxdata/telegraf/issues/285): Fixed-size buffer of points.\n- [#546](https://github.com/influxdata/telegraf/pull/546): SNMP Input plugin. Thanks @titilambert!\n- [#589](https://github.com/influxdata/telegraf/pull/589): Microsoft SQL Server input plugin. Thanks @zensqlmonitor!\n- [#573](https://github.com/influxdata/telegraf/pull/573): Github webhooks consumer input. Thanks @jackzampolin!\n- [#471](https://github.com/influxdata/telegraf/pull/471): httpjson request headers. Thanks @asosso!\n\n### Bug Fixes\n\n- [#506](https://github.com/influxdata/telegraf/pull/506): Ping input doesn't return response time metric when timeout. Thanks @titilambert!\n- [#508](https://github.com/influxdata/telegraf/pull/508): Fix prometheus cardinality issue with the `net` plugin\n- [#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!\n- [#543](https://github.com/influxdata/telegraf/issues/543): Statsd Packet size sometimes truncated.\n- [#440](https://github.com/influxdata/telegraf/issues/440): Don't query filtered devices for disk stats.\n- [#463](https://github.com/influxdata/telegraf/issues/463): Docker plugin not working on AWS Linux\n- [#568](https://github.com/influxdata/telegraf/issues/568): Multiple output race condition.\n- [#585](https://github.com/influxdata/telegraf/pull/585): Log stack trace and continue on Telegraf panic. Thanks @wutaizeng!\n\n## v0.10.0 [2016-01-12]\n\n### Release Notes\n\n- Linux packages have been taken out of `opt`, the binary is now in `/usr/bin`\nand configuration files are in `/etc/telegraf`\n- **breaking change** `plugins` have been renamed to `inputs`. This was done because\n`plugins` is too generic, as there are now also \"output plugins\", and will likely\nbe \"aggregator plugins\" and \"filter plugins\" in the future. Additionally,\n`inputs/` and `outputs/` directories have been placed in the root-level `plugins/`\ndirectory.\n- **breaking change** the `io` plugin has been renamed `diskio`\n- **breaking change** plugin measurements aggregated into a single measurement.\n- **breaking change** `jolokia` plugin: must use global tag/drop/pass parameters\nfor configuration.\n- **breaking change** `twemproxy` plugin: `prefix` option removed.\n- **breaking change** `procstat` cpu measurements are now prepended with `cpu_time_`\ninstead of only `cpu_`\n- **breaking change** some command-line flags have been renamed to separate words.\n`-configdirectory` -> `-config-directory`, `-filter` -> `-input-filter`,\n`-outputfilter` -> `-output-filter`\n- The prometheus plugin schema has not been changed (measurements have not been\naggregated).\n\n### Packaging change note\n\nRHEL/CentOS users upgrading from 0.2.x to 0.10.0 will probably have their\nconfigurations overwritten by the upgrade. There is a backup stored at\n/etc/telegraf/telegraf.conf.$(date +%s).backup.\n\n### Features\n\n- Plugin measurements aggregated into a single measurement.\n- Added ability to specify per-plugin tags\n- Added ability to specify per-plugin measurement suffix and prefix.\n(`name_prefix` and `name_suffix`)\n- Added ability to override base plugin measurement name. (`name_override`)\n\n### Bug Fixes\n\n## v0.2.5 [unreleased]\n\n### Features\n\n- [#427](https://github.com/influxdata/telegraf/pull/427): zfs plugin: pool stats added. Thanks @allenpetersen!\n- [#428](https://github.com/influxdata/telegraf/pull/428): Amazon Kinesis output. Thanks @jimmystewpot!\n- [#449](https://github.com/influxdata/telegraf/pull/449): influxdb plugin, thanks @mark-rushakoff\n\n### Bug Fixes\n\n- [#430](https://github.com/influxdata/telegraf/issues/430): Network statistics removed in elasticsearch 2.1. Thanks @jipperinbham!\n- [#452](https://github.com/influxdata/telegraf/issues/452): Elasticsearch open file handles error. Thanks @jipperinbham!\n\n## v0.2.4 [2015-12-08]\n\n### Features\n\n- [#412](https://github.com/influxdata/telegraf/pull/412): Additional memcached stats. Thanks @mgresser!\n- [#410](https://github.com/influxdata/telegraf/pull/410): Additional redis metrics. Thanks @vlaadbrain!\n- [#414](https://github.com/influxdata/telegraf/issues/414): Jolokia plugin auth parameters\n- [#415](https://github.com/influxdata/telegraf/issues/415): memcached plugin: support unix sockets\n- [#418](https://github.com/influxdata/telegraf/pull/418): memcached plugin additional unit tests.\n- [#408](https://github.com/influxdata/telegraf/pull/408): MailChimp plugin.\n- [#382](https://github.com/influxdata/telegraf/pull/382): Add system wide network protocol stats to `net` plugin.\n- [#401](https://github.com/influxdata/telegraf/pull/401): Support pass/drop/tagpass/tagdrop for outputs. Thanks @oldmantaiter!\n\n### Bug Fixes\n\n- [#405](https://github.com/influxdata/telegraf/issues/405): Prometheus output cardinality issue\n- [#388](https://github.com/influxdata/telegraf/issues/388): Fix collection hangup when cpu times decrement.\n\n## v0.2.3 [2015-11-30]\n\n### Release Notes\n\n- **breaking change** The `kafka` plugin has been renamed to `kafka_consumer`.\nand most of the config option names have changed.\nThis only affects the kafka consumer _plugin_ (not the\noutput). There were a number of problems with the kafka plugin that led to it\nonly collecting data once at startup, so the kafka plugin was basically non-\nfunctional.\n- Plugins can now be specified as a list, and multiple plugin instances of the\nsame type can be specified, like this:\n\n```toml\n[[inputs.cpu]]\n  percpu = false\n  totalcpu = true\n\n[[inputs.cpu]]\n  percpu = true\n  totalcpu = false\n  drop = [\"cpu_time\"]\n```\n\n- Riemann output added\n- Aerospike plugin: tag changed from `host` -> `aerospike_host`\n\n### Features\n\n- [#379](https://github.com/influxdata/telegraf/pull/379): Riemann output, thanks @allenj!\n- [#375](https://github.com/influxdata/telegraf/pull/375): kafka_consumer service plugin.\n- [#392](https://github.com/influxdata/telegraf/pull/392): Procstat plugin can now accept pgrep -f pattern, thanks @ecarreras!\n- [#383](https://github.com/influxdata/telegraf/pull/383): Specify plugins as a list.\n- [#354](https://github.com/influxdata/telegraf/pull/354): Add ability to specify multiple metrics in one statsd line. Thanks @MerlinDMC!\n\n### Bug Fixes\n\n- [#371](https://github.com/influxdata/telegraf/issues/371): Kafka consumer plugin not functioning.\n- [#389](https://github.com/influxdata/telegraf/issues/389): NaN value panic\n\n## v0.2.2 [2015-11-18]\n\n### Release Notes\n\n- 0.2.1 has a bug where all lists within plugins get duplicated, this includes\nlists of servers/URLs. 0.2.2 is being released solely to fix that bug\n\n### Bug Fixes\n\n- [#377](https://github.com/influxdata/telegraf/pull/377): Fix for duplicate slices in inputs.\n\n## v0.2.1 [2015-11-16]\n\n### Release Notes\n\n- Telegraf will no longer use docker-compose for \"long\" unit test, it has been\nchanged to just run docker commands in the Makefile. See `make docker-run` and\n`make docker-kill`. `make test` will still run all unit tests with docker.\n- Long unit tests are now run in CircleCI, with docker & race detector\n- Redis plugin tag has changed from `host` to `server`\n- HAProxy plugin tag has changed from `host` to `server`\n- UDP output now supported\n- Telegraf will now compile on FreeBSD\n- Users can now specify outputs as lists, specifying multiple outputs of the\nsame type.\n\n### Features\n\n- [#325](https://github.com/influxdata/telegraf/pull/325): NSQ output. Thanks @jrxFive!\n- [#318](https://github.com/influxdata/telegraf/pull/318): Prometheus output. Thanks @oldmantaiter!\n- [#338](https://github.com/influxdata/telegraf/pull/338): Restart Telegraf on package upgrade. Thanks @linsomniac!\n- [#337](https://github.com/influxdata/telegraf/pull/337): Jolokia plugin, thanks @saiello!\n- [#350](https://github.com/influxdata/telegraf/pull/350): Amon output.\n- [#365](https://github.com/influxdata/telegraf/pull/365): Twemproxy plugin by @codeb2cc\n- [#317](https://github.com/influxdata/telegraf/issues/317): ZFS plugin, thanks @cornerot!\n- [#364](https://github.com/influxdata/telegraf/pull/364): Support InfluxDB UDP output.\n- [#370](https://github.com/influxdata/telegraf/pull/370): Support specifying multiple outputs, as lists.\n- [#372](https://github.com/influxdata/telegraf/pull/372): Remove gosigar and update go-dockerclient for FreeBSD support. Thanks @MerlinDMC!\n\n### Bug Fixes\n\n- [#331](https://github.com/influxdata/telegraf/pull/331): Dont overwrite host tag in redis plugin.\n- [#336](https://github.com/influxdata/telegraf/pull/336): Mongodb plugin should take 2 measurements.\n- [#351](https://github.com/influxdata/telegraf/issues/317): Fix continual \"CREATE DATABASE\" in writes\n- [#360](https://github.com/influxdata/telegraf/pull/360): Apply prefix before ShouldPass check. Thanks @sotfo!\n\n## v0.2.0 [2015-10-27]\n\n### Release Notes\n\n- The -test flag will now only output 2 collections for plugins that need it\n- There is a new agent configuration option: `flush_interval`. This option tells\nTelegraf how often to flush data to InfluxDB and other output sinks. For example,\nusers can set `interval = \"2s\"` and `flush_interval = \"60s\"` for Telegraf to\ncollect data every 2 seconds, and flush every 60 seconds.\n- `precision` and `utc` are no longer valid agent config values. `precision` has\nmoved to the `influxdb` output config, where it will continue to default to \"s\"\n- debug and test output will now print the raw line-protocol string\n- Telegraf will now, by default, round the collection interval to the nearest\neven interval. This means that `interval=\"10s\"` will collect every :00, :10, etc.\nTo ease scale concerns, flushing will be \"jittered\" by a random amount so that\nall Telegraf instances do not flush at the same time. Both of these options can\nbe controlled via the `round_interval` and `flush_jitter` config options.\n- Telegraf will now retry metric flushes twice\n\n### Features\n\n- [#205](https://github.com/influxdata/telegraf/issues/205): Include per-db redis keyspace info\n- [#226](https://github.com/influxdata/telegraf/pull/226): Add timestamps to points in Kafka/AMQP outputs. Thanks @ekini\n- [#90](https://github.com/influxdata/telegraf/issues/90): Add Docker labels to tags in docker plugin\n- [#223](https://github.com/influxdata/telegraf/pull/223): Add port tag to nginx plugin. Thanks @neezgee!\n- [#227](https://github.com/influxdata/telegraf/pull/227): Add command intervals to exec plugin. Thanks @jpalay!\n- [#241](https://github.com/influxdata/telegraf/pull/241): MQTT Output. Thanks @shirou!\n- Memory plugin: cached and buffered measurements re-added\n- Logging: additional logging for each collection interval, track the number\nof metrics collected and from how many inputs.\n- [#240](https://github.com/influxdata/telegraf/pull/240): procstat plugin, thanks @ranjib!\n- [#244](https://github.com/influxdata/telegraf/pull/244): netstat plugin, thanks @shirou!\n- [#262](https://github.com/influxdata/telegraf/pull/262): zookeeper plugin, thanks @jrxFive!\n- [#237](https://github.com/influxdata/telegraf/pull/237): statsd service plugin, thanks @sparrc\n- [#273](https://github.com/influxdata/telegraf/pull/273): puppet agent plugin, thats @jrxFive!\n- [#280](https://github.com/influxdata/telegraf/issues/280): Use InfluxDB client v2.\n- [#281](https://github.com/influxdata/telegraf/issues/281): Eliminate need to deep copy Batch Points.\n- [#286](https://github.com/influxdata/telegraf/issues/286): bcache plugin, thanks @cornerot!\n- [#287](https://github.com/influxdata/telegraf/issues/287): Batch AMQP output, thanks @ekini!\n- [#301](https://github.com/influxdata/telegraf/issues/301): Collect on even intervals\n- [#298](https://github.com/influxdata/telegraf/pull/298): Support retrying output writes\n- [#300](https://github.com/influxdata/telegraf/issues/300): aerospike plugin. Thanks @oldmantaiter!\n- [#322](https://github.com/influxdata/telegraf/issues/322): Librato output. Thanks @jipperinbham!\n\n### Bug Fixes\n\n- [#228](https://github.com/influxdata/telegraf/pull/228): New version of package will replace old one. Thanks @ekini!\n- [#232](https://github.com/influxdata/telegraf/pull/232): Fix bashism run during deb package installation. Thanks @yankcrime!\n- [#261](https://github.com/influxdata/telegraf/issues/260): RabbitMQ panics if wrong credentials given. Thanks @ekini!\n- [#245](https://github.com/influxdata/telegraf/issues/245): Document Exec plugin example. Thanks @ekini!\n- [#264](https://github.com/influxdata/telegraf/issues/264): logrotate config file fixes. Thanks @linsomniac!\n- [#290](https://github.com/influxdata/telegraf/issues/290): Fix some plugins sending their values as strings.\n- [#289](https://github.com/influxdata/telegraf/issues/289): Fix accumulator panic on nil tags.\n- [#302](https://github.com/influxdata/telegraf/issues/302): Fix `[tags]` getting applied, thanks @gotyaoi!\n\n## v0.1.9 [2015-09-22]\n\n### Release Notes\n\n- InfluxDB output config change: `url` is now `urls`, and is a list. Config files\nwill still be backwards compatible if only `url` is specified.\n- The -test flag will now output two metric collections\n- Support for filtering telegraf outputs on the CLI -- Telegraf will now\nallow filtering of output sinks on the command-line using the `-outputfilter`\nflag, much like how the `-filter` flag works for inputs.\n- Support for filtering on config-file creation -- Telegraf now supports\nfiltering to -sample-config command. You can now run\n`telegraf -sample-config -filter cpu -outputfilter influxdb` to get a config\nfile with only the cpu plugin defined, and the influxdb output defined.\n- **Breaking Change**: The CPU collection plugin has been refactored to fix some\nbugs and outdated dependency issues. At the same time, I also decided to fix\na naming consistency issue, so cpu_percentageIdle will become cpu_usage_idle.\nAlso, all CPU time measurements now have it indicated in their name, so cpu_idle\nwill become cpu_time_idle. Additionally, cpu_time measurements are going to be\ndropped in the default config.\n- **Breaking Change**: The memory plugin has been refactored and some measurements\nhave been renamed for consistency. Some measurements have also been removed from being outputted. They are still being collected by gopsutil, and could easily be\nre-added in a \"verbose\" mode if there is demand for it.\n\n### Features\n\n- [#143](https://github.com/influxdata/telegraf/issues/143): InfluxDB clustering support\n- [#181](https://github.com/influxdata/telegraf/issues/181): Makefile GOBIN support. Thanks @Vye!\n- [#203](https://github.com/influxdata/telegraf/pull/200): AMQP output. Thanks @ekini!\n- [#182](https://github.com/influxdata/telegraf/pull/182): OpenTSDB output. Thanks @rplessl!\n- [#187](https://github.com/influxdata/telegraf/pull/187): Retry output sink connections on startup.\n- [#220](https://github.com/influxdata/telegraf/pull/220): Add port tag to apache plugin. Thanks @neezgee!\n- [#217](https://github.com/influxdata/telegraf/pull/217): Add filtering for output sinks\nand filtering when specifying a config file.\n\n### Bug Fixes\n\n- [#170](https://github.com/influxdata/telegraf/issues/170): Systemd support\n- [#175](https://github.com/influxdata/telegraf/issues/175): Set write precision before gathering metrics\n- [#178](https://github.com/influxdata/telegraf/issues/178): redis plugin, multiple server thread hang bug\n- Fix net plugin on darwin\n- [#84](https://github.com/influxdata/telegraf/issues/84): Fix docker plugin on CentOS. Thanks @neezgee!\n- [#189](https://github.com/influxdata/telegraf/pull/189): Fix mem_used_perc. Thanks @mced!\n- [#192](https://github.com/influxdata/telegraf/issues/192): Increase compatibility of postgresql plugin. Now supports versions 8.1+\n- [#203](https://github.com/influxdata/telegraf/issues/203): EL5 rpm support. Thanks @ekini!\n- [#206](https://github.com/influxdata/telegraf/issues/206): CPU steal/guest values wrong on linux.\n- [#212](https://github.com/influxdata/telegraf/issues/212): Add hashbang to postinstall script. Thanks @ekini!\n- [#212](https://github.com/influxdata/telegraf/issues/212): Fix makefile warning. Thanks @ekini!\n\n## v0.1.8 [2015-09-04]\n\n### Release Notes\n\n- Telegraf will now write data in UTC at second precision by default\n- Now using Go 1.5 to build telegraf\n\n### Features\n\n- [#150](https://github.com/influxdata/telegraf/pull/150): Add Host Uptime metric to system plugin\n- [#158](https://github.com/influxdata/telegraf/pull/158): Apache Plugin. Thanks @KPACHbIuLLIAnO4\n- [#159](https://github.com/influxdata/telegraf/pull/159): Use second precision for InfluxDB writes\n- [#165](https://github.com/influxdata/telegraf/pull/165): Add additional metrics to mysql plugin. Thanks @nickscript0\n- [#162](https://github.com/influxdata/telegraf/pull/162): Write UTC by default, provide option\n- [#166](https://github.com/influxdata/telegraf/pull/166): Upload binaries to S3\n- [#169](https://github.com/influxdata/telegraf/pull/169): Ping plugin\n\n### Bug Fixes\n\n## v0.1.7 [2015-08-28]\n\n### Features\n\n- [#38](https://github.com/influxdata/telegraf/pull/38): Kafka output producer.\n- [#133](https://github.com/influxdata/telegraf/pull/133): Add plugin.Gather error logging. Thanks @nickscript0!\n- [#136](https://github.com/influxdata/telegraf/issues/136): Add a -usage flag for printing usage of a single plugin.\n- [#137](https://github.com/influxdata/telegraf/issues/137): Memcached: fix when a value contains a space\n- [#138](https://github.com/influxdata/telegraf/issues/138): MySQL server address tag.\n- [#142](https://github.com/influxdata/telegraf/pull/142): Add Description and SampleConfig funcs to output interface\n- Indent the toml config file for readability\n\n### Bug Fixes\n\n- [#128](https://github.com/influxdata/telegraf/issues/128): system_load measurement missing.\n- [#129](https://github.com/influxdata/telegraf/issues/129): Latest pkg url fix.\n- [#131](https://github.com/influxdata/telegraf/issues/131): Fix memory reporting on linux & darwin. Thanks @subhachandrachandra!\n- [#140](https://github.com/influxdata/telegraf/issues/140): Memory plugin prec->perc typo fix. Thanks @brunoqc!\n\n## v0.1.6 [2015-08-20]\n\n### Features\n\n- [#112](https://github.com/influxdata/telegraf/pull/112): Datadog output. Thanks @jipperinbham!\n- [#116](https://github.com/influxdata/telegraf/pull/116): Use godep to vendor all dependencies\n- [#120](https://github.com/influxdata/telegraf/pull/120): Httpjson plugin. Thanks @jpalay & @alvaromorales!\n\n### Bug Fixes\n\n- [#113](https://github.com/influxdata/telegraf/issues/113): Update README with Telegraf/InfluxDB compatibility\n- [#118](https://github.com/influxdata/telegraf/pull/118): Fix for disk usage stats in Windows. Thanks @srfraser!\n- [#122](https://github.com/influxdata/telegraf/issues/122): Fix for DiskUsage segv fault. Thanks @srfraser!\n- [#126](https://github.com/influxdata/telegraf/issues/126): Nginx plugin not catching net.SplitHostPort error\n\n## v0.1.5 [2015-08-13]\n\n### Features\n\n- [#54](https://github.com/influxdata/telegraf/pull/54): MongoDB plugin. Thanks @jipperinbham!\n- [#55](https://github.com/influxdata/telegraf/pull/55): Elasticsearch plugin. Thanks @brocaar!\n- [#71](https://github.com/influxdata/telegraf/pull/71): HAProxy plugin. Thanks @kureikain!\n- [#72](https://github.com/influxdata/telegraf/pull/72): Adding TokuDB metrics to MySQL. Thanks vadimtk!\n- [#73](https://github.com/influxdata/telegraf/pull/73): RabbitMQ plugin. Thanks @ianunruh!\n- [#77](https://github.com/influxdata/telegraf/issues/77): Automatically create database.\n- [#79](https://github.com/influxdata/telegraf/pull/56): Nginx plugin. Thanks @codeb2cc!\n- [#86](https://github.com/influxdata/telegraf/pull/86): Lustre2 plugin. Thanks srfraser!\n- [#91](https://github.com/influxdata/telegraf/pull/91): Unit testing\n- [#92](https://github.com/influxdata/telegraf/pull/92): Exec plugin. Thanks @alvaromorales!\n- [#98](https://github.com/influxdata/telegraf/pull/98): LeoFS plugin. Thanks @mocchira!\n- [#103](https://github.com/influxdata/telegraf/pull/103): Filter by metric tags. Thanks @srfraser!\n- [#106](https://github.com/influxdata/telegraf/pull/106): Options to filter plugins on startup. Thanks @zepouet!\n- [#107](https://github.com/influxdata/telegraf/pull/107): Multiple outputs beyond influxdb. Thanks @jipperinbham!\n- [#108](https://github.com/influxdata/telegraf/issues/108): Support setting per-CPU and total-CPU gathering.\n- [#111](https://github.com/influxdata/telegraf/pull/111): Report CPU Usage in cpu plugin. Thanks @jpalay!\n\n### Bug Fixes\n\n- [#85](https://github.com/influxdata/telegraf/pull/85): Fix GetLocalHost testutil function for mac users\n- [#89](https://github.com/influxdata/telegraf/pull/89): go fmt fixes\n- [#94](https://github.com/influxdata/telegraf/pull/94): Fix for issue #93, explicitly call sarama.v1 -> sarama\n- [#101](https://github.com/influxdata/telegraf/issues/101): switch back from master branch if building locally\n- [#99](https://github.com/influxdata/telegraf/issues/99): update integer output to new InfluxDB line protocol format\n\n## v0.1.4 [2015-07-09]\n\n### Features\n\n- [#56](https://github.com/influxdata/telegraf/pull/56): Update README for Kafka plugin. Thanks @EmilS!\n\n### Bug Fixes\n\n- [#50](https://github.com/influxdata/telegraf/pull/50): Fix init.sh script to use telegraf directory. Thanks @jseriff!\n- [#52](https://github.com/influxdata/telegraf/pull/52): Update CHANGELOG to reference updated directory. Thanks @benfb!\n\n## v0.1.3 [2015-07-05]\n\n### Features\n\n- [#35](https://github.com/influxdata/telegraf/pull/35): Add Kafka plugin. Thanks @EmilS!\n- [#47](https://github.com/influxdata/telegraf/pull/47): Add RethinkDB plugin. Thanks @jipperinbham!\n\n### Bug Fixes\n\n- [#45](https://github.com/influxdata/telegraf/pull/45): Skip disk tags that don't have a value. Thanks @jhofeditz!\n- [#43](https://github.com/influxdata/telegraf/pull/43): Fix bug in MySQL plugin. Thanks @marcosnils!\n\n## v0.1.2 [2015-07-01]\n\n### Features\n\n- [#12](https://github.com/influxdata/telegraf/pull/12): Add Linux/ARM to the list of built binaries. Thanks @voxxit!\n- [#14](https://github.com/influxdata/telegraf/pull/14): Clarify the S3 buckets that Telegraf is pushed to.\n- [#16](https://github.com/influxdata/telegraf/pull/16): Convert Redis to use URI, support Redis AUTH. Thanks @jipperinbham!\n- [#21](https://github.com/influxdata/telegraf/pull/21): Add memcached plugin. Thanks @Yukki!\n\n### Bug Fixes\n\n- [#13](https://github.com/influxdata/telegraf/pull/13): Fix the packaging script.\n- [#19](https://github.com/influxdata/telegraf/pull/19): Add host name to metric tags. Thanks @sherifzain!\n- [#20](https://github.com/influxdata/telegraf/pull/20): Fix race condition with accumulator mutex. Thanks @nkatsaros!\n- [#23](https://github.com/influxdata/telegraf/pull/23): Change name of folder for packages. Thanks @colinrymer!\n- [#32](https://github.com/influxdata/telegraf/pull/32): Fix spelling of memoory -> memory. Thanks @tylernisonoff!\n\n## v0.1.1 [2015-06-19]\n\n### Release Notes\n\nThis is the initial release of Telegraf.\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "<!-- markdownlint-disable MD013 MD024 -->\n# Changelog\n\n## v1.38.1 [2026-03-16]\n\n### Bugfixes\n\n- [#18491](https://github.com/influxdata/telegraf/pull/18491) `inputs.diskio` Sanitize newline characters in serial tag\n- [#18453](https://github.com/influxdata/telegraf/pull/18453) `inputs.docker` Emit status metrics for non-running containers\n- [#18513](https://github.com/influxdata/telegraf/pull/18513) `inputs.exec` Log stderr messages\n- [#18469](https://github.com/influxdata/telegraf/pull/18469) `inputs.mem` Use vm.Cached as vm.Buffers on OpenBSD\n- [#18455](https://github.com/influxdata/telegraf/pull/18455) `inputs.ping` Warn on using timeout parameter for native method\n- [#18471](https://github.com/influxdata/telegraf/pull/18471) `internal` Extract go version even more robustly\n- [#18509](https://github.com/influxdata/telegraf/pull/18509) `outputs.influxdb_v3` Remove duplicate timeout setting\n\n### Dependency Updates\n\n- [#18486](https://github.com/influxdata/telegraf/pull/18486) `deps` Bump github.com/SAP/go-hdb from 1.15.1 to 1.15.2\n- [#18477](https://github.com/influxdata/telegraf/pull/18477) `deps` Bump github.com/alitto/pond/v2 from 2.6.2 to 2.7.0\n- [#18488](https://github.com/influxdata/telegraf/pull/18488) `deps` Bump github.com/apache/arrow-go/v18 from 18.5.1 to 18.5.2\n- [#18487](https://github.com/influxdata/telegraf/pull/18487) `deps` Bump github.com/emiago/sipgo from 1.2.0 to 1.2.1\n- [#18475](https://github.com/influxdata/telegraf/pull/18475) `deps` Bump github.com/gophercloud/gophercloud/v2 from 2.10.0 to 2.11.0\n- [#18481](https://github.com/influxdata/telegraf/pull/18481) `deps` Bump github.com/nats-io/nats-server/v2 from 2.12.4 to 2.12.5\n- [#18075](https://github.com/influxdata/telegraf/pull/18075) `deps` Bump go.opentelemetry.io/collector/pdata from 1.46.0 to 1.53.0\n- [#18483](https://github.com/influxdata/telegraf/pull/18483) `deps` Bump go.opentelemetry.io/proto/otlp from 1.9.0 to 1.10.0\n- [#18485](https://github.com/influxdata/telegraf/pull/18485) `deps` Bump go.opentelemetry.io/proto/otlp/collector/profiles/v1development from 0.2.0 to 0.3.0\n- [#18478](https://github.com/influxdata/telegraf/pull/18478) `deps` Bump golang.org/x/oauth2 from 0.35.0 to 0.36.0\n- [#18484](https://github.com/influxdata/telegraf/pull/18484) `deps` Bump golang.org/x/sync from 0.19.0 to 0.20.0\n- [#18480](https://github.com/influxdata/telegraf/pull/18480) `deps` Bump google.golang.org/api from 0.269.0 to 0.270.0\n- [#18490](https://github.com/influxdata/telegraf/pull/18490) `deps` Bump google.golang.org/grpc from 1.79.1 to 1.79.2\n- [#18474](https://github.com/influxdata/telegraf/pull/18474) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n- [#18473](https://github.com/influxdata/telegraf/pull/18473) `deps` Bump tj-actions/changed-files from 47.0.4 to 47.0.5\n\n## v1.38.0 [2026-03-09]\n\n### Important Changes\n\n- PR [#17961](https://github.com/influxdata/telegraf/pull/17961) makes the\n **strict environment variable handling the default**! In case you need the old\n behavior you can opt-out using the `--non-strict-env-handling` flag.\n\n### New Plugins\n\n- [#18183](https://github.com/influxdata/telegraf/pull/18183) `inputs.sip` Add plugin\n- [#18223](https://github.com/influxdata/telegraf/pull/18223) `outputs.influxdb_v3` Add plugin\n\n### Features\n\n- [#18086](https://github.com/influxdata/telegraf/pull/18086) `agent` Optimise disk buffer strategy\n- [#18232](https://github.com/influxdata/telegraf/pull/18232) `common.opcua` Add string configuration option for node ID\n- [#18411](https://github.com/influxdata/telegraf/pull/18411) `common.opcua` Add support for datetime arrays\n- [#18181](https://github.com/influxdata/telegraf/pull/18181) `inputs.docker` Implement startup error behavior options\n- [#18425](https://github.com/influxdata/telegraf/pull/18425) `inputs.gnmi` Allow to emit delete metrics\n- [#18466](https://github.com/influxdata/telegraf/pull/18466) `inputs.mqtt_consumer` Add option for maximum reconnect interval\n- [#18063](https://github.com/influxdata/telegraf/pull/18063) `inputs.mysql` Add replication latency fields\n- [#18117](https://github.com/influxdata/telegraf/pull/18117) `inputs.mysql` Add wsrep provider options fields\n- [#18272](https://github.com/influxdata/telegraf/pull/18272) `inputs.mysql` Support encryption algorithm statistics if present\n- [#18134](https://github.com/influxdata/telegraf/pull/18134) `inputs.nftables` Monitor set element counts\n- [#18246](https://github.com/influxdata/telegraf/pull/18246) `inputs.nftables` Support named counters\n- [#18259](https://github.com/influxdata/telegraf/pull/18259) `inputs.statsd` Add support for Datadog service checks\n- [#18393](https://github.com/influxdata/telegraf/pull/18393) `outputs.health` Add option for setting default status\n- [#18415](https://github.com/influxdata/telegraf/pull/18415) `outputs.heartbeat` Add logging information\n- [#17577](https://github.com/influxdata/telegraf/pull/17577) `outputs.heartbeat` Add status evaluation\n- [#18305](https://github.com/influxdata/telegraf/pull/18305) `outputs.influxdb_v2` Add trace logging for write request timing\n- [#18422](https://github.com/influxdata/telegraf/pull/18422) `outputs.mongodb` Allow writing metrics in batches\n- [#17997](https://github.com/influxdata/telegraf/pull/17997) `outputs.opentelemetry` Support http protocol\n- [#18337](https://github.com/influxdata/telegraf/pull/18337) `outputs.redistimeseries` Add option to expire values\n- [#18339](https://github.com/influxdata/telegraf/pull/18339) `outputs.stackdriver` Add credentials file support for stackdriver output plugin\n- [#18341](https://github.com/influxdata/telegraf/pull/18341) `prometheus` Add UTF-8 metric and label name sanitization\n\n### Bugfixes\n\n- [#18429](https://github.com/influxdata/telegraf/pull/18429) `common.opcua` Use configured timestamp format for datetime arrays\n- [#18381](https://github.com/influxdata/telegraf/pull/18381) `inputs.fibaro` Handle numeric value2 field from HC3 devices\n- [#18424](https://github.com/influxdata/telegraf/pull/18424) `inputs.http` Close gzip request body on early failures\n- [#18412](https://github.com/influxdata/telegraf/pull/18412) `inputs.internet_speed` Fix server_id_include filter logic\n- [#18452](https://github.com/influxdata/telegraf/pull/18452) `inputs.mqtt_consumer` Rely on paho auto-reconnect to restore message flow after network disruption\n- [#18392](https://github.com/influxdata/telegraf/pull/18392) `inputs.opcua_listener` Prevent panic on events with empty fields\n- [#18387](https://github.com/influxdata/telegraf/pull/18387) `inputs.smart` Include NVMe SMART data in smart_device measurement\n- [#18416](https://github.com/influxdata/telegraf/pull/18416) `outputs.influxdb` Prevent goroutine leak on gzip write failure\n- [#18418](https://github.com/influxdata/telegraf/pull/18418) `outputs.opentelemetry` Prevent goroutine leak on gzip write failure\n\n### Dependency Updates\n\n- [#18436](https://github.com/influxdata/telegraf/pull/18436) `deps` Bump cloud.google.com/go/bigquery from 1.73.1 to 1.74.0\n- [#18444](https://github.com/influxdata/telegraf/pull/18444) `deps` Bump github.com/IBM/sarama from 1.46.3 to 1.47.0\n- [#18449](https://github.com/influxdata/telegraf/pull/18449) `deps` Bump github.com/SAP/go-hdb from 1.15.0 to 1.15.1\n- [#18398](https://github.com/influxdata/telegraf/pull/18398) `deps` Bump github.com/antchfx/xpath from 1.3.5 to 1.3.6\n- [#18442](https://github.com/influxdata/telegraf/pull/18442) `deps` Bump github.com/aws/smithy-go from 1.24.1 to 1.24.2\n- [#18400](https://github.com/influxdata/telegraf/pull/18400) `deps` Bump github.com/hashicorp/consul/api from 1.33.2 to 1.33.3\n- [#18438](https://github.com/influxdata/telegraf/pull/18438) `deps` Bump github.com/hashicorp/consul/api from 1.33.3 to 1.33.4\n- [#18446](https://github.com/influxdata/telegraf/pull/18446) `deps` Bump github.com/lxc/incus/v6 from 6.21.0 to 6.22.0\n- [#18441](https://github.com/influxdata/telegraf/pull/18441) `deps` Bump github.com/microsoft/go-mssqldb from 1.9.6 to 1.9.8\n- [#18404](https://github.com/influxdata/telegraf/pull/18404) `deps` Bump github.com/nats-io/nats.go from 1.48.0 to 1.49.0\n- [#18439](https://github.com/influxdata/telegraf/pull/18439) `deps` Bump github.com/prometheus/procfs from 0.19.2 to 0.20.1\n- [#18440](https://github.com/influxdata/telegraf/pull/18440) `deps` Bump github.com/shirou/gopsutil/v4 from 4.26.1 to 4.26.2\n- [#18402](https://github.com/influxdata/telegraf/pull/18402) `deps` Bump github.com/vmware/govmomi from 0.52.0 to 0.53.0\n- [#18399](https://github.com/influxdata/telegraf/pull/18399) `deps` Bump go.step.sm/crypto from 0.76.0 to 0.76.2\n- [#18450](https://github.com/influxdata/telegraf/pull/18450) `deps` Bump golang.org/x/net from 0.50.0 to 0.51.0\n- [#18437](https://github.com/influxdata/telegraf/pull/18437) `deps` Bump google.golang.org/api from 0.266.0 to 0.269.0\n- [#18448](https://github.com/influxdata/telegraf/pull/18448) `deps` Bump k8s.io/api from 0.35.1 to 0.35.2\n- [#18447](https://github.com/influxdata/telegraf/pull/18447) `deps` Bump k8s.io/apimachinery from 0.35.1 to 0.35.2\n- [#18443](https://github.com/influxdata/telegraf/pull/18443) `deps` Bump k8s.io/client-go from 0.35.1 to 0.35.2\n- [#18403](https://github.com/influxdata/telegraf/pull/18403) `deps` Bump modernc.org/sqlite from 1.45.0 to 1.46.1\n- [#18397](https://github.com/influxdata/telegraf/pull/18397) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n- [#18435](https://github.com/influxdata/telegraf/pull/18435) `deps` Bump the aws-sdk-go-v2 group with 2 updates\n- [#18396](https://github.com/influxdata/telegraf/pull/18396) `deps` Bump tj-actions/changed-files from 47.0.2 to 47.0.4\n\n## v1.37.3 [2026-02-23]\n\n### Bugfixes\n\n- [#18195](https://github.com/influxdata/telegraf/pull/18195) `common.jolokia2` Add Jolokia 2.x compatibility for proxy target tag\n- [#18378](https://github.com/influxdata/telegraf/pull/18378) `common.opcua` Include node ID in duplicate metric check\n- [#18335](https://github.com/influxdata/telegraf/pull/18335) `inputs.disk` Preserve device tag for virtual filesystems\n- [#18374](https://github.com/influxdata/telegraf/pull/18374) `inputs.docker` Remove pre-filtering of states\n- [#18383](https://github.com/influxdata/telegraf/pull/18383) `inputs.docker_log` Remove pre-filtering of states\n- [#18347](https://github.com/influxdata/telegraf/pull/18347) `inputs.jenkins` Report all concurrent builds\n- [#18377](https://github.com/influxdata/telegraf/pull/18377) `inputs.prometheus` Add thread safety and proper cleanup for shared informer factories\n- [#18304](https://github.com/influxdata/telegraf/pull/18304) `inputs.prometheus` Cleanup shared informers on stop\n- [#18367](https://github.com/influxdata/telegraf/pull/18367) `inputs.upsd` Stop silently dropping mandatory variables from additional_fields\n- [#18386](https://github.com/influxdata/telegraf/pull/18386) `serializers.template` Unwrap tracking metrics\n\n### Dependency Updates\n\n- [#18354](https://github.com/influxdata/telegraf/pull/18354) `deps` Bump cloud.google.com/go/auth from 0.18.1 to 0.18.2\n- [#18324](https://github.com/influxdata/telegraf/pull/18324) `deps` Bump cloud.google.com/go/bigquery from 1.72.0 to 1.73.1\n- [#18319](https://github.com/influxdata/telegraf/pull/18319) `deps` Bump cloud.google.com/go/pubsub/v2 from 2.3.0 to 2.4.0\n- [#18298](https://github.com/influxdata/telegraf/pull/18298) `deps` Bump cloud.google.com/go/storage from 1.59.1 to 1.59.2\n- [#18361](https://github.com/influxdata/telegraf/pull/18361) `deps` Bump cloud.google.com/go/storage from 1.59.2 to 1.60.0\n- [#18376](https://github.com/influxdata/telegraf/pull/18376) `deps` Bump filippo.io/edwards25519 from 1.1.0 to 1.1.1\n- [#18292](https://github.com/influxdata/telegraf/pull/18292) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.42.0 to 2.43.0\n- [#18295](https://github.com/influxdata/telegraf/pull/18295) `deps` Bump github.com/IBM/nzgo/v12 from 12.0.10 to 12.0.11\n- [#18297](https://github.com/influxdata/telegraf/pull/18297) `deps` Bump github.com/SAP/go-hdb from 1.14.18 to 1.14.19\n- [#18328](https://github.com/influxdata/telegraf/pull/18328) `deps` Bump github.com/SAP/go-hdb from 1.14.19 to 1.14.22\n- [#18364](https://github.com/influxdata/telegraf/pull/18364) `deps` Bump github.com/SAP/go-hdb from 1.14.22 to 1.15.0\n- [#18358](https://github.com/influxdata/telegraf/pull/18358) `deps` Bump github.com/alitto/pond/v2 from 2.6.0 to 2.6.2\n- [#18289](https://github.com/influxdata/telegraf/pull/18289) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.282.0 to 1.285.0\n- [#18362](https://github.com/influxdata/telegraf/pull/18362) `deps` Bump github.com/coocood/freecache from 1.2.4 to 1.2.5\n- [#18299](https://github.com/influxdata/telegraf/pull/18299) `deps` Bump github.com/coreos/go-systemd/v22 from 22.6.0 to 22.7.0\n- [#18294](https://github.com/influxdata/telegraf/pull/18294) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.3.0 to 5.3.1\n- [#18291](https://github.com/influxdata/telegraf/pull/18291) `deps` Bump github.com/google/cel-go from 0.26.1 to 0.27.0\n- [#18330](https://github.com/influxdata/telegraf/pull/18330) `deps` Bump github.com/klauspost/compress from 1.18.3 to 1.18.4\n- [#18268](https://github.com/influxdata/telegraf/pull/18268) `deps` Bump github.com/lxc/incus/v6 from 6.20.0 to 6.21.0\n- [#18296](https://github.com/influxdata/telegraf/pull/18296) `deps` Bump github.com/nats-io/nats-server/v2 from 2.12.3 to 2.12.4\n- [#18356](https://github.com/influxdata/telegraf/pull/18356) `deps` Bump github.com/p4lang/p4runtime from 1.4.1 to 1.5.0\n- [#18326](https://github.com/influxdata/telegraf/pull/18326) `deps` Bump github.com/prometheus-community/pro-bing from 0.7.0 to 0.8.0\n- [#18355](https://github.com/influxdata/telegraf/pull/18355) `deps` Bump github.com/redis/go-redis/v9 from 9.17.3 to 9.18.0\n- [#18293](https://github.com/influxdata/telegraf/pull/18293) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.11 to 4.26.1\n- [#18331](https://github.com/influxdata/telegraf/pull/18331) `deps` Bump github.com/snowflakedb/gosnowflake from 1.18.1 to 1.19.0\n- [#18323](https://github.com/influxdata/telegraf/pull/18323) `deps` Bump github.com/vertica/vertica-sql-go from 1.3.4 to 1.3.5\n- [#18290](https://github.com/influxdata/telegraf/pull/18290) `deps` Bump go.mongodb.org/mongo-driver from 1.17.7 to 1.17.8\n- [#18332](https://github.com/influxdata/telegraf/pull/18332) `deps` Bump go.mongodb.org/mongo-driver from 1.17.8 to 1.17.9\n- [#18318](https://github.com/influxdata/telegraf/pull/18318) `deps` Bump golang.org/x/mod from 0.32.0 to 0.33.0\n- [#18322](https://github.com/influxdata/telegraf/pull/18322) `deps` Bump golang.org/x/net from 0.49.0 to 0.50.0\n- [#18333](https://github.com/influxdata/telegraf/pull/18333) `deps` Bump golang.org/x/term from 0.39.0 to 0.40.0\n- [#18329](https://github.com/influxdata/telegraf/pull/18329) `deps` Bump golang.org/x/text from 0.33.0 to 0.34.0\n- [#18300](https://github.com/influxdata/telegraf/pull/18300) `deps` Bump google.golang.org/api from 0.262.0 to 0.264.0\n- [#18317](https://github.com/influxdata/telegraf/pull/18317) `deps` Bump google.golang.org/api from 0.264.0 to 0.265.0\n- [#18357](https://github.com/influxdata/telegraf/pull/18357) `deps` Bump google.golang.org/grpc from 1.78.0 to 1.79.1\n- [#18363](https://github.com/influxdata/telegraf/pull/18363) `deps` Bump k8s.io/client-go from 0.35.0 to 0.35.1\n- [#18327](https://github.com/influxdata/telegraf/pull/18327) `deps` Bump modernc.org/sqlite from 1.44.3 to 1.45.0\n- [#18288](https://github.com/influxdata/telegraf/pull/18288) `deps` Bump super-linter/super-linter from 8.3.2 to 8.4.0\n- [#18315](https://github.com/influxdata/telegraf/pull/18315) `deps` Bump super-linter/super-linter from 8.4.0 to 8.5.0\n- [#18353](https://github.com/influxdata/telegraf/pull/18353) `deps` Bump the aws-sdk-go-v2 group with 2 updates\n- [#18316](https://github.com/influxdata/telegraf/pull/18316) `deps` Bump the aws-sdk-go-v2 group with 2 updates\n- [#18314](https://github.com/influxdata/telegraf/pull/18314) `deps` Bump tj-actions/changed-files from 47.0.1 to 47.0.2\n- [#18372](https://github.com/influxdata/telegraf/pull/18372) `deps` Update github.com/pion/dtls from v2 to v3\n\n## v1.37.2 [2026-02-02]\n\n### Bugfixes\n\n- [#18254](https://github.com/influxdata/telegraf/pull/18254) `inputs.cisco_telemetry_mdt` Handle DME events correctly\n- [#18177](https://github.com/influxdata/telegraf/pull/18177) `inputs.nftables` Handle named counter references in JSON output\n- [#18233](https://github.com/influxdata/telegraf/pull/18233) `inputs.procstat` Handle newer versions of systemd correctly\n- [#18225](https://github.com/influxdata/telegraf/pull/18225) `inputs.statsd` Handle negative lengths\n- [#18278](https://github.com/influxdata/telegraf/pull/18278) `parsers.dropwizard` Correct sample config setting name for tag path\n\n### Dependency Updates\n\n- [#18204](https://github.com/influxdata/telegraf/pull/18204) `deps` Bump aws-sdk-go-v2 group with 11 updates\n- [#18260](https://github.com/influxdata/telegraf/pull/18260) `deps` Bump aws-sdk-go-v2 group with 2 updates\n- [#18265](https://github.com/influxdata/telegraf/pull/18265) `deps` Bump cloud.google.com/go/auth from 0.18.0 to 0.18.1\n- [#18212](https://github.com/influxdata/telegraf/pull/18212) `deps` Bump cloud.google.com/go/storage from 1.58.0 to 1.59.0\n- [#18243](https://github.com/influxdata/telegraf/pull/18243) `deps` Bump cloud.google.com/go/storage from 1.59.0 to 1.59.1\n- [#18237](https://github.com/influxdata/telegraf/pull/18237) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.20.0 to 1.21.0\n- [#18216](https://github.com/influxdata/telegraf/pull/18216) `deps` Bump github.com/SAP/go-hdb from 1.14.16 to 1.14.17\n- [#18236](https://github.com/influxdata/telegraf/pull/18236) `deps` Bump github.com/SAP/go-hdb from 1.14.17 to 1.14.18\n- [#18270](https://github.com/influxdata/telegraf/pull/18270) `deps` Bump github.com/apache/arrow-go/v18 from 18.5.0 to 18.5.1\n- [#18235](https://github.com/influxdata/telegraf/pull/18235) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.279.1 to 1.279.2\n- [#18206](https://github.com/influxdata/telegraf/pull/18206) `deps` Bump github.com/gosnmp/gosnmp from 1.43.1 to 1.43.2\n- [#18240](https://github.com/influxdata/telegraf/pull/18240) `deps` Bump github.com/hashicorp/consul/api from 1.33.0 to 1.33.2\n- [#18242](https://github.com/influxdata/telegraf/pull/18242) `deps` Bump github.com/klauspost/compress from 1.18.2 to 1.18.3\n- [#18266](https://github.com/influxdata/telegraf/pull/18266) `deps` Bump github.com/linkedin/goavro/v2 from 2.14.1 to 2.15.0\n- [#18239](https://github.com/influxdata/telegraf/pull/18239) `deps` Bump github.com/microsoft/go-mssqldb from 1.9.5 to 1.9.6\n- [#18210](https://github.com/influxdata/telegraf/pull/18210) `deps` Bump github.com/miekg/dns from 1.1.69 to 1.1.70\n- [#18264](https://github.com/influxdata/telegraf/pull/18264) `deps` Bump github.com/miekg/dns from 1.1.70 to 1.1.72\n- [#18271](https://github.com/influxdata/telegraf/pull/18271) `deps` Bump github.com/redis/go-redis/v9 from 9.17.2 to 9.17.3\n- [#18244](https://github.com/influxdata/telegraf/pull/18244) `deps` Bump github.com/sirupsen/logrus from 1.9.3 to 1.9.4\n- [#18262](https://github.com/influxdata/telegraf/pull/18262) `deps` Bump github.com/tdrn-org/go-tr064 from 0.2.2 to 0.2.3\n- [#18267](https://github.com/influxdata/telegraf/pull/18267) `deps` Bump go.mongodb.org/mongo-driver from 1.17.6 to 1.17.7\n- [#18269](https://github.com/influxdata/telegraf/pull/18269) `deps` Bump go.step.sm/crypto from 0.75.0 to 0.76.0\n- [#18215](https://github.com/influxdata/telegraf/pull/18215) `deps` Bump golang.org/x/crypto from 0.46.0 to 0.47.0\n- [#18208](https://github.com/influxdata/telegraf/pull/18208) `deps` Bump golang.org/x/mod from 0.31.0 to 0.32.0\n- [#18207](https://github.com/influxdata/telegraf/pull/18207) `deps` Bump golang.org/x/net from 0.48.0 to 0.49.0\n- [#18217](https://github.com/influxdata/telegraf/pull/18217) `deps` Bump gonum.org/v1/gonum from 0.16.0 to 0.17.0\n- [#18261](https://github.com/influxdata/telegraf/pull/18261) `deps` Bump google.golang.org/api from 0.257.0 to 0.262.0\n- [#18213](https://github.com/influxdata/telegraf/pull/18213) `deps` Bump modernc.org/sqlite from 1.42.2 to 1.43.0\n- [#18241](https://github.com/influxdata/telegraf/pull/18241) `deps` Bump modernc.org/sqlite from 1.43.0 to 1.44.2\n- [#18263](https://github.com/influxdata/telegraf/pull/18263) `deps` Bump modernc.org/sqlite from 1.44.2 to 1.44.3\n\n## v1.37.1 [2026-01-12]\n\n### Bugfixes\n\n- [#18138](https://github.com/influxdata/telegraf/pull/18138) `config` Add missing validation for labels in plugins\n- [#18108](https://github.com/influxdata/telegraf/pull/18108) `config` Make labels and selectors conform to specification\n- [#18144](https://github.com/influxdata/telegraf/pull/18144) `inputs.procstat` Isolate process cache per filter to fix tag collision\n- [#18191](https://github.com/influxdata/telegraf/pull/18191) `outputs.sql` Populate column cache for existing tables\n\n### Dependency Updates\n\n- [#18125](https://github.com/influxdata/telegraf/pull/18125) `deps` Bump cloud.google.com/go/auth from 0.17.0 to 0.18.0\n- [#18140](https://github.com/influxdata/telegraf/pull/18140) `deps` Bump cloud.google.com/go/auth from 0.17.0 to 0.18.0\n- [#18094](https://github.com/influxdata/telegraf/pull/18094) `deps` Bump cloud.google.com/go/storage from 1.57.2 to 1.58.0\n- [#18157](https://github.com/influxdata/telegraf/pull/18157) `deps` Bump github.com/BurntSushi/toml from 1.5.0 to 1.6.0\n- [#18124](https://github.com/influxdata/telegraf/pull/18124) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.41.0 to 2.42.0\n- [#18101](https://github.com/influxdata/telegraf/pull/18101) `deps` Bump github.com/SAP/go-hdb from 1.14.13 to 1.14.14\n- [#18153](https://github.com/influxdata/telegraf/pull/18153) `deps` Bump github.com/SAP/go-hdb from 1.14.14 to 1.14.15\n- [#18199](https://github.com/influxdata/telegraf/pull/18199) `deps` Bump github.com/SAP/go-hdb from 1.14.15 to 1.14.16\n- [#18123](https://github.com/influxdata/telegraf/pull/18123) `deps` Bump github.com/apache/arrow-go/v18 from 18.4.1 to 18.5.0\n- [#18200](https://github.com/influxdata/telegraf/pull/18200) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.6 to 1.0.7\n- [#18197](https://github.com/influxdata/telegraf/pull/18197) `deps` Bump github.com/gophercloud/gophercloud/v2 from 2.9.0 to 2.10.0\n- [#18198](https://github.com/influxdata/telegraf/pull/18198) `deps` Bump github.com/gosnmp/gosnmp from 1.42.1 to 1.43.1\n- [#18132](https://github.com/influxdata/telegraf/pull/18132) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.7.5 to 6.7.7\n- [#18169](https://github.com/influxdata/telegraf/pull/18169) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.7.7 to 6.7.8\n- [#18189](https://github.com/influxdata/telegraf/pull/18189) `deps` Bump github.com/likexian/whois from 1.15.6 to 1.15.7\n- [#18187](https://github.com/influxdata/telegraf/pull/18187) `deps` Bump github.com/likexian/whois-parser from 1.24.20 to 1.24.21\n- [#18150](https://github.com/influxdata/telegraf/pull/18150) `deps` Bump github.com/lxc/incus/v6 from 6.19.1 to 6.20.0\n- [#18130](https://github.com/influxdata/telegraf/pull/18130) `deps` Bump github.com/miekg/dns from 1.1.68 to 1.1.69\n- [#18149](https://github.com/influxdata/telegraf/pull/18149) `deps` Bump github.com/nats-io/nats-server/v2 from 2.12.2 to 2.12.3\n- [#18147](https://github.com/influxdata/telegraf/pull/18147) `deps` Bump github.com/nats-io/nats.go from 1.47.0 to 1.48.0\n- [#18172](https://github.com/influxdata/telegraf/pull/18172) `deps` Bump github.com/netsampler/goflow2/v2 from 2.2.3 to 2.2.6\n- [#18190](https://github.com/influxdata/telegraf/pull/18190) `deps` Bump github.com/prometheus/common from 0.67.4 to 0.67.5\n- [#18102](https://github.com/influxdata/telegraf/pull/18102) `deps` Bump github.com/prometheus/prometheus from 0.307.3 to 0.308.0\n- [#18155](https://github.com/influxdata/telegraf/pull/18155) `deps` Bump github.com/prometheus/prometheus from 0.308.0 to 0.308.1\n- [#18129](https://github.com/influxdata/telegraf/pull/18129) `deps` Bump github.com/snowflakedb/gosnowflake from 1.18.0 to 1.18.1\n- [#18103](https://github.com/influxdata/telegraf/pull/18103) `deps` Bump github.com/tinylib/msgp from 1.5.0 to 1.6.1\n- [#18188](https://github.com/influxdata/telegraf/pull/18188) `deps` Bump github.com/tinylib/msgp from 1.6.1 to 1.6.3\n- [#18186](https://github.com/influxdata/telegraf/pull/18186) `deps` Bump github.com/yuin/goldmark from 1.7.13 to 1.7.15\n- [#18201](https://github.com/influxdata/telegraf/pull/18201) `deps` Bump github.com/yuin/goldmark from 1.7.15 to 1.7.16\n- [#18092](https://github.com/influxdata/telegraf/pull/18092) `deps` Bump go.step.sm/crypto from 0.74.0 to 0.75.0\n- [#18098](https://github.com/influxdata/telegraf/pull/18098) `deps` Bump golang.org/x/crypto from 0.45.0 to 0.46.0\n- [#18100](https://github.com/influxdata/telegraf/pull/18100) `deps` Bump golang.org/x/mod from 0.30.0 to 0.31.0\n- [#18127](https://github.com/influxdata/telegraf/pull/18127) `deps` Bump golang.org/x/net from 0.47.0 to 0.48.0\n- [#18095](https://github.com/influxdata/telegraf/pull/18095) `deps` Bump golang.org/x/oauth2 from 0.33.0 to 0.34.0\n- [#18093](https://github.com/influxdata/telegraf/pull/18093) `deps` Bump golang.org/x/sync from 0.18.0 to 0.19.0\n- [#18096](https://github.com/influxdata/telegraf/pull/18096) `deps` Bump golang.org/x/sys from 0.38.0 to 0.39.0\n- [#18099](https://github.com/influxdata/telegraf/pull/18099) `deps` Bump golang.org/x/term from 0.37.0 to 0.38.0\n- [#18097](https://github.com/influxdata/telegraf/pull/18097) `deps` Bump golang.org/x/text from 0.31.0 to 0.32.0\n- [#18104](https://github.com/influxdata/telegraf/pull/18104) `deps` Bump google.golang.org/api from 0.256.0 to 0.257.0\n- [#18173](https://github.com/influxdata/telegraf/pull/18173) `deps` Bump google.golang.org/grpc from 1.77.0 to 1.78.0\n- [#18131](https://github.com/influxdata/telegraf/pull/18131) `deps` Bump google.golang.org/protobuf from 1.36.10 to 1.36.11\n- [#18128](https://github.com/influxdata/telegraf/pull/18128) `deps` Bump k8s.io/api from 0.34.2 to 0.34.3\n- [#18148](https://github.com/influxdata/telegraf/pull/18148) `deps` Bump k8s.io/apimachinery from 0.34.3 to 0.35.0\n- [#18126](https://github.com/influxdata/telegraf/pull/18126) `deps` Bump k8s.io/client-go from 0.34.2 to 0.34.3\n- [#18154](https://github.com/influxdata/telegraf/pull/18154) `deps` Bump k8s.io/client-go from 0.34.3 to 0.35.0\n- [#18152](https://github.com/influxdata/telegraf/pull/18152) `deps` Bump modernc.org/sqlite from 1.40.1 to 1.41.0\n- [#18171](https://github.com/influxdata/telegraf/pull/18171) `deps` Bump modernc.org/sqlite from 1.41.0 to 1.42.2\n- [#18170](https://github.com/influxdata/telegraf/pull/18170) `deps` Bump software.sslmate.com/src/go-pkcs12 from 0.6.0 to 0.7.0\n- [#18158](https://github.com/influxdata/telegraf/pull/18158) `deps` Bump super-linter/super-linter from 8.3.0 to 8.3.1\n- [#18174](https://github.com/influxdata/telegraf/pull/18174) `deps` Bump super-linter/super-linter from 8.3.1 to 8.3.2\n- [#18091](https://github.com/influxdata/telegraf/pull/18091) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n- [#18146](https://github.com/influxdata/telegraf/pull/18146) `deps` Bump the aws-sdk-go-v2 group with 3 updates\n- [#18121](https://github.com/influxdata/telegraf/pull/18121) `deps` Bump the aws-sdk-go-v2 group with 8 updates\n- [#18120](https://github.com/influxdata/telegraf/pull/18120) `deps` Bump tj-actions/changed-files from 47.0.0 to 47.0.1\n- [#18115](https://github.com/influxdata/telegraf/pull/18115) `deps` Update golangci-lint to 2.7.2\n\n## v1.37.0 [2025-12-08]\n\n### Important Changes\n\n- PR [#17966](https://github.com/influxdata/telegraf/pull/17966) introduced the strict handling of environment variables\n  to prevent security issues. However, strict handling prevents using environment variables for non-string settings as\n  the configuration before replacing the variables must be TOML conform. To provide security-by-default, we will change\n  the **default behavior of Telegraf to the strict environment variable handling with v1.38.0**!\n  Please make sure your configuration works in the now conditions by using the `--strict-env-handling` flag! If your\n  configuration works in strict mode or you are not using environment variables, **do not** add the flag as it will be\n  removed later and ignore the new warning at startup. In case you need the current behavior please add\n  `--non-strict-env-handling` when starting Telegraf to prepare for the upcoming change!\n\n### New Plugins\n\n- [#17993](https://github.com/influxdata/telegraf/pull/17993) `inputs.logql` Add plugin\n- [#17604](https://github.com/influxdata/telegraf/pull/17604) `inputs.nftables` Add plugin\n- [#17701](https://github.com/influxdata/telegraf/pull/17701) `inputs.promql` Add plugin\n- [#17831](https://github.com/influxdata/telegraf/pull/17831) `inputs.timex` Add plugin\n- [#17875](https://github.com/influxdata/telegraf/pull/17875) `outputs.arc` Add plugin\n- [#17998](https://github.com/influxdata/telegraf/pull/17998) `outputs.heartbeat` Add plugin\n- [#17921](https://github.com/influxdata/telegraf/pull/17921) `secretstores.googlecloud` Add plugin\n- [#17844](https://github.com/influxdata/telegraf/pull/17844) `secretstores.vault` Add plugin\n\n### Features\n\n- [#18084](https://github.com/influxdata/telegraf/pull/18084) `config` Allow specifying env-handling mode for config check\n- [#17753](https://github.com/influxdata/telegraf/pull/17753) `config` Remove deprecated options\n- [#17915](https://github.com/influxdata/telegraf/pull/17915) `config` Store loaded sources\n- [#17080](https://github.com/influxdata/telegraf/pull/17080) `internal` Add support for parsing a timestamp in a TimeZone\n- [#17916](https://github.com/influxdata/telegraf/pull/17916) `logging` Allow registering callbacks for logging events\n- [#17749](https://github.com/influxdata/telegraf/pull/17749) `models` Implement collection of plugin-internal statistics for all types\n- [#18044](https://github.com/influxdata/telegraf/pull/18044) `common.socket` Add option to specify source IP restrictions\n- [#17760](https://github.com/influxdata/telegraf/pull/17760) `inputs.aerospike` Remove deprecated options\n- [#17759](https://github.com/influxdata/telegraf/pull/17759) `inputs.cpu` Add number of physical CPUs\n- [#17761](https://github.com/influxdata/telegraf/pull/17761) `inputs.gnmi` Remove deprecated options\n- [#17732](https://github.com/influxdata/telegraf/pull/17732) `inputs.influxdb_v2_listener` Implement ping endpoint\n- [#17733](https://github.com/influxdata/telegraf/pull/17733) `inputs.influxdb_v2_listener` Migrate to selfstat collector\n- [#17965](https://github.com/influxdata/telegraf/pull/17965) `inputs.ldap` Support external SASL bind (#17477)\n- [#17478](https://github.com/influxdata/telegraf/pull/17478) `inputs.ldap` Support ldapi protocol\n- [#17743](https://github.com/influxdata/telegraf/pull/17743) `inputs.modbus` Remove deprecated plugin option values\n- [#17762](https://github.com/influxdata/telegraf/pull/17762) `inputs.mongodb` Remove deprecated options\n- [#17792](https://github.com/influxdata/telegraf/pull/17792) `inputs.nats_consumer` Acknowledge messages on delivery\n- [#17710](https://github.com/influxdata/telegraf/pull/17710) `inputs.nats_consumer` Allow configuring Jetstream stream\n- [#17742](https://github.com/influxdata/telegraf/pull/17742) `inputs.net` Remove deprecated plugin option value\n- [#17624](https://github.com/influxdata/telegraf/pull/17624) `inputs.netflow` Add datatypes to PEN mapping\n- [#17697](https://github.com/influxdata/telegraf/pull/17697) `inputs.netflow` Add support for float32 datatype\n- [#17906](https://github.com/influxdata/telegraf/pull/17906) `inputs.opcua` Add namespace URI support\n- [#17825](https://github.com/influxdata/telegraf/pull/17825) `inputs.opcua` Add remote certificate trust configuration\n- [#17752](https://github.com/influxdata/telegraf/pull/17752) `inputs.opcua` Remove deprecated options\n- [#17991](https://github.com/influxdata/telegraf/pull/17991) `inputs.opcua` Support persistent self-signed client certificates\n- [#17633](https://github.com/influxdata/telegraf/pull/17633) `inputs.rabbitmq` Add type tag to queues\n- [#18080](https://github.com/influxdata/telegraf/pull/18080) `inputs.s7comm` Add option idle_timeout\n- [#17550](https://github.com/influxdata/telegraf/pull/17550) `inputs.smart` Parse vendor specific ratio values\n- [#17948](https://github.com/influxdata/telegraf/pull/17948) `inputs.snmp` Add option to stop polling on first error\n- [#17375](https://github.com/influxdata/telegraf/pull/17375) `inputs.sql` Add Vertica support\n- [#17924](https://github.com/influxdata/telegraf/pull/17924) `inputs.sqlserver` Add support for LPC and named-pipe protocols\n- [#17796](https://github.com/influxdata/telegraf/pull/17796) `inputs.sqlserver` Set pool size and idle connection\n- [#17872](https://github.com/influxdata/telegraf/pull/17872) `inputs.statsd` Improve performance\n- [#17763](https://github.com/influxdata/telegraf/pull/17763) `inputs.win_perf_counters` Remove deprecated options\n- [#17751](https://github.com/influxdata/telegraf/pull/17751) `inputs.zookeeper` Remove deprecated option\n- [#17950](https://github.com/influxdata/telegraf/pull/17950) `outputs.amon` Deprecate plugin\n- [#18062](https://github.com/influxdata/telegraf/pull/18062) `outputs.heartbeat` Add configuration information\n- [#18050](https://github.com/influxdata/telegraf/pull/18050) `outputs.heartbeat` Add optional statistics output\n- [#17869](https://github.com/influxdata/telegraf/pull/17869) `outputs.mongodb` Add PLAIN authentication support and validation\n- [#17755](https://github.com/influxdata/telegraf/pull/17755) `outputs.mqtt` Remove deprecated option\n- [#18048](https://github.com/influxdata/telegraf/pull/18048) `outputs.nats` Add secret-support for credentials\n- [#18007](https://github.com/influxdata/telegraf/pull/18007) `outputs.nats` Support nkey seed authentication\n- [#17409](https://github.com/influxdata/telegraf/pull/17409) `outputs.remotefile` Add compression for remotefile plugin\n- [#17764](https://github.com/influxdata/telegraf/pull/17764) `parsers.binary` Remove deprecated options\n- [#17754](https://github.com/influxdata/telegraf/pull/17754) `parsers.xpath` Remove deprecated options\n- [#17576](https://github.com/influxdata/telegraf/pull/17576) `processors.execd` Add log prefixing\n- [#17741](https://github.com/influxdata/telegraf/pull/17741) `processors.template` Remove deprecated template syntax\n\n### Bugfixes\n\n- [#18064](https://github.com/influxdata/telegraf/pull/18064) `common.opcua` Skip file permission check on Windows\n- [#18012](https://github.com/influxdata/telegraf/pull/18012) `inputs.docker_log` Remove hard-coded API version\n- [#17960](https://github.com/influxdata/telegraf/pull/17960) `inputs.opcua` Add private key for certificate-based user authentication\n- [#18036](https://github.com/influxdata/telegraf/pull/18036) `inputs.procstat` Make port conversion more robust\n- [#18014](https://github.com/influxdata/telegraf/pull/18014) `outputs.influxdb_v2` Correct calculation of amount of batches for concurrent writes\n\n### Dependency Updates\n\n- [#18051](https://github.com/influxdata/telegraf/pull/18051) `deps` Bump actions/checkout from 5 to 6\n- [#18021](https://github.com/influxdata/telegraf/pull/18021) `deps` Bump cloud.google.com/go/storage from 1.57.1 to 1.57.2\n- [#18055](https://github.com/influxdata/telegraf/pull/18055) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.40.3 to 2.41.0\n- [#18019](https://github.com/influxdata/telegraf/pull/18019) `deps` Bump github.com/SAP/go-hdb from 1.14.12 to 1.14.13\n- [#18076](https://github.com/influxdata/telegraf/pull/18076) `deps` Bump github.com/alitto/pond/v2 from 2.5.0 to 2.6.0\n- [#18074](https://github.com/influxdata/telegraf/pull/18074) `deps` Bump github.com/aws/smithy-go from 1.23.2 to 1.24.0\n- [#18020](https://github.com/influxdata/telegraf/pull/18020) `deps` Bump github.com/gophercloud/gophercloud/v2 from 2.8.0 to 2.9.0\n- [#17887](https://github.com/influxdata/telegraf/pull/17887) `deps` Bump github.com/hashicorp/consul/api from 1.32.4 to 1.33.0\n- [#18024](https://github.com/influxdata/telegraf/pull/18024) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.7.1 to 6.7.2\n- [#18056](https://github.com/influxdata/telegraf/pull/18056) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.7.2 to 6.7.5\n- [#18072](https://github.com/influxdata/telegraf/pull/18072) `deps` Bump github.com/klauspost/compress from 1.18.1 to 1.18.2\n- [#18071](https://github.com/influxdata/telegraf/pull/18071) `deps` Bump github.com/lxc/incus/v6 from 6.18.0 to 6.19.1\n- [#18018](https://github.com/influxdata/telegraf/pull/18018) `deps` Bump github.com/microsoft/go-mssqldb from 1.9.3 to 1.9.4\n- [#18017](https://github.com/influxdata/telegraf/pull/18017) `deps` Bump github.com/nats-io/nats-server/v2 from 2.12.1 to 2.12.2\n- [#18054](https://github.com/influxdata/telegraf/pull/18054) `deps` Bump github.com/prometheus/common from 0.67.2 to 0.67.4\n- [#18053](https://github.com/influxdata/telegraf/pull/18053) `deps` Bump github.com/redis/go-redis/v9 from 9.16.0 to 9.17.0\n- [#18073](https://github.com/influxdata/telegraf/pull/18073) `deps` Bump github.com/redis/go-redis/v9 from 9.17.0 to 9.17.2\n- [#18027](https://github.com/influxdata/telegraf/pull/18027) `deps` Bump github.com/safchain/ethtool from 0.6.2 to 0.7.0\n- [#18070](https://github.com/influxdata/telegraf/pull/18070) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.10 to 4.25.11\n- [#18057](https://github.com/influxdata/telegraf/pull/18057) `deps` Bump github.com/snowflakedb/gosnowflake from 1.17.0 to 1.18.0\n- [#17815](https://github.com/influxdata/telegraf/pull/17815) `deps` Bump github.com/vertica/vertica-sql-go from 1.3.3 to 1.3.4\n- [#18031](https://github.com/influxdata/telegraf/pull/18031) `deps` Bump go.opentelemetry.io/collector/pdata from 1.45.0 to 1.46.0\n- [#18043](https://github.com/influxdata/telegraf/pull/18043) `deps` Bump golang.org/x/crypto from 0.44.0 to 0.45.0\n- [#18023](https://github.com/influxdata/telegraf/pull/18023) `deps` Bump golang.org/x/mod from 0.29.0 to 0.30.0\n- [#18029](https://github.com/influxdata/telegraf/pull/18029) `deps` Bump golang.org/x/net from 0.46.0 to 0.47.0\n- [#18025](https://github.com/influxdata/telegraf/pull/18025) `deps` Bump google.golang.org/api from 0.255.0 to 0.256.0\n- [#18058](https://github.com/influxdata/telegraf/pull/18058) `deps` Bump google.golang.org/grpc from 1.76.0 to 1.77.0\n- [#18033](https://github.com/influxdata/telegraf/pull/18033) `deps` Bump k8s.io/client-go from 0.34.1 to 0.34.2\n- [#18030](https://github.com/influxdata/telegraf/pull/18030) `deps` Bump modernc.org/sqlite from 1.40.0 to 1.40.1\n- [#18069](https://github.com/influxdata/telegraf/pull/18069) `deps` Bump super-linter/super-linter from 8.2.1 to 8.3.0\n- [#18052](https://github.com/influxdata/telegraf/pull/18052) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n- [#18015](https://github.com/influxdata/telegraf/pull/18015) `deps` Bump the aws-sdk-go-v2 group with 9 updates\n\n## v1.36.4 [2025-11-17]\n\n### Bugfixes\n\n- [#17873](https://github.com/influxdata/telegraf/pull/17873) `common.kafka` Avoid API version requests for SASLv0 handshakes\n- [#17966](https://github.com/influxdata/telegraf/pull/17966) `config` Implement strict envvar handling to prevent insecure text replacement\n- [#17877](https://github.com/influxdata/telegraf/pull/17877) `inputs.kinesis_consumer` Ignore expired parent shards\n- [#17908](https://github.com/influxdata/telegraf/pull/17908) `inputs.tail` Handle missing read permissions for directory globbing\n- [#17968](https://github.com/influxdata/telegraf/pull/17968) `inputs.turbostat` Allow floating point intervals\n- [#17953](https://github.com/influxdata/telegraf/pull/17953) `inputs.zfs` Avoid panic by handling explicitly empty kstat metrics\n- [#17949](https://github.com/influxdata/telegraf/pull/17949) `outputs.influxdb_v2` Handle serialization errors correctly\n- [#17920](https://github.com/influxdata/telegraf/pull/17920) `outputs.loki` Sanitize colons in label names\n- [#17990](https://github.com/influxdata/telegraf/pull/17990) `outputs.sql` Mark table as found during initial existence check\n\n### Dependency Updates\n\n- [#17935](https://github.com/influxdata/telegraf/pull/17935) `deps` Bump cloud.google.com/go/bigquery from 1.71.0 to 1.72.0\n- [#17897](https://github.com/influxdata/telegraf/pull/17897) `deps` Bump cloud.google.com/go/pubsub/v2 from 2.2.1 to 2.3.0\n- [#17943](https://github.com/influxdata/telegraf/pull/17943) `deps` Bump cloud.google.com/go/storage from 1.57.0 to 1.57.1\n- [#17970](https://github.com/influxdata/telegraf/pull/17970) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.19.1 to 1.20.0\n- [#17973](https://github.com/influxdata/telegraf/pull/17973) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.13.0 to 1.13.1\n- [#17901](https://github.com/influxdata/telegraf/pull/17901) `deps` Bump github.com/IBM/sarama from 1.46.2 to 1.46.3\n- [#17889](https://github.com/influxdata/telegraf/pull/17889) `deps` Bump github.com/SAP/go-hdb from 1.14.7 to 1.14.9\n- [#17977](https://github.com/influxdata/telegraf/pull/17977) `deps` Bump github.com/SAP/go-hdb from 1.14.9 to 1.14.12\n- [#17981](https://github.com/influxdata/telegraf/pull/17981) `deps` Bump github.com/apache/iotdb-client-go from 1.3.4 to 1.3.5\n- [#17900](https://github.com/influxdata/telegraf/pull/17900) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.39.3 to 1.39.4\n- [#17899](https://github.com/influxdata/telegraf/pull/17899) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.31.13 to 1.31.15\n- [#17898](https://github.com/influxdata/telegraf/pull/17898) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.51.2 to 1.51.4\n- [#17858](https://github.com/influxdata/telegraf/pull/17858) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.58.2 to 1.58.3\n- [#17892](https://github.com/influxdata/telegraf/pull/17892) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.58.3 to 1.58.5\n- [#17854](https://github.com/influxdata/telegraf/pull/17854) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.51.0 to 1.51.1\n- [#17890](https://github.com/influxdata/telegraf/pull/17890) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.51.1 to 1.52.2\n- [#17855](https://github.com/influxdata/telegraf/pull/17855) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.255.0 to 1.257.2\n- [#17886](https://github.com/influxdata/telegraf/pull/17886) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.257.2 to 1.258.1\n- [#17883](https://github.com/influxdata/telegraf/pull/17883) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.40.6 to 1.41.0\n- [#17847](https://github.com/influxdata/telegraf/pull/17847) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.35.5 to 1.35.6\n- [#17891](https://github.com/influxdata/telegraf/pull/17891) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.35.6 to 1.35.7\n- [#17944](https://github.com/influxdata/telegraf/pull/17944) `deps` Bump github.com/aws/smithy-go from 1.23.1 to 1.23.2\n- [#17978](https://github.com/influxdata/telegraf/pull/17978) `deps` Bump github.com/docker/docker from 28.5.1+incompatible to 28.5.2+incompatible\n- [#18009](https://github.com/influxdata/telegraf/pull/18009) `deps` Bump github.com/dvsekhvalnov/jose2go from 1.6.0 to 1.7.0\n- [#17941](https://github.com/influxdata/telegraf/pull/17941) `deps` Bump github.com/gofrs/uuid/v5 from 5.3.2 to 5.4.0\n- [#17927](https://github.com/influxdata/telegraf/pull/17927) `deps` Bump github.com/gopacket/gopacket from 1.4.0 to 1.5.0\n- [#17988](https://github.com/influxdata/telegraf/pull/17988) `deps` Bump github.com/influxdata/toml from v0.0.0-20190415235208-270119a8ce65 to v0.0.0-20251106153700-c381e153d076\n- [#17932](https://github.com/influxdata/telegraf/pull/17932) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.6.8 to 6.6.9\n- [#17979](https://github.com/influxdata/telegraf/pull/17979) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.6.9 to 6.7.1\n- [#17896](https://github.com/influxdata/telegraf/pull/17896) `deps` Bump github.com/linkedin/goavro/v2 from 2.14.0 to 2.14.1\n- [#17942](https://github.com/influxdata/telegraf/pull/17942) `deps` Bump github.com/lxc/incus/v6 from 6.17.0 to 6.18.0\n- [#17937](https://github.com/influxdata/telegraf/pull/17937) `deps` Bump github.com/prometheus/common from 0.67.1 to 0.67.2\n- [#17885](https://github.com/influxdata/telegraf/pull/17885) `deps` Bump github.com/prometheus/procfs from 0.17.0 to 0.19.1\n- [#17930](https://github.com/influxdata/telegraf/pull/17930) `deps` Bump github.com/prometheus/procfs from 0.19.1 to 0.19.2\n- [#17894](https://github.com/influxdata/telegraf/pull/17894) `deps` Bump github.com/prometheus/prometheus from 0.307.1 to 0.307.2\n- [#17928](https://github.com/influxdata/telegraf/pull/17928) `deps` Bump github.com/prometheus/prometheus from 0.307.2 to 0.307.3\n- [#17895](https://github.com/influxdata/telegraf/pull/17895) `deps` Bump github.com/redis/go-redis/v9 from 9.14.1 to 9.16.0\n- [#17939](https://github.com/influxdata/telegraf/pull/17939) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.9 to 4.25.10\n- [#17976](https://github.com/influxdata/telegraf/pull/17976) `deps` Bump github.com/testcontainers/testcontainers-go from 0.39.0 to 0.40.0\n- [#17983](https://github.com/influxdata/telegraf/pull/17983) `deps` Bump github.com/testcontainers/testcontainers-go/modules/azure from 0.39.0 to 0.40.0\n- [#17972](https://github.com/influxdata/telegraf/pull/17972) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.39.0 to 0.40.0\n- [#17893](https://github.com/influxdata/telegraf/pull/17893) `deps` Bump github.com/tinylib/msgp from 1.4.0 to 1.5.0\n- [#17934](https://github.com/influxdata/telegraf/pull/17934) `deps` Bump go.mongodb.org/mongo-driver from 1.17.4 to 1.17.6\n- [#17865](https://github.com/influxdata/telegraf/pull/17865) `deps` Bump go.opentelemetry.io/collector/pdata from 1.43.0 to 1.44.0\n- [#17945](https://github.com/influxdata/telegraf/pull/17945) `deps` Bump go.opentelemetry.io/collector/pdata from 1.44.0 to 1.45.0\n- [#17933](https://github.com/influxdata/telegraf/pull/17933) `deps` Bump go.opentelemetry.io/proto/otlp from 1.8.0 to 1.9.0\n- [#17938](https://github.com/influxdata/telegraf/pull/17938) `deps` Bump go.opentelemetry.io/proto/otlp/collector/profiles/v1development from 0.1.0 to 0.2.0\n- [#17936](https://github.com/influxdata/telegraf/pull/17936) `deps` Bump go.step.sm/crypto from 0.72.0 to 0.73.0\n- [#17974](https://github.com/influxdata/telegraf/pull/17974) `deps` Bump go.step.sm/crypto from 0.73.0 to 0.74.0\n- [#17984](https://github.com/influxdata/telegraf/pull/17984) `deps` Bump golang.org/x/oauth2 from 0.32.0 to 0.33.0\n- [#17980](https://github.com/influxdata/telegraf/pull/17980) `deps` Bump golang.org/x/sync from 0.17.0 to 0.18.0\n- [#17971](https://github.com/influxdata/telegraf/pull/17971) `deps` Bump golang.org/x/sys from 0.37.0 to 0.38.0\n- [#17884](https://github.com/influxdata/telegraf/pull/17884) `deps` Bump google.golang.org/api from 0.252.0 to 0.253.0\n- [#17929](https://github.com/influxdata/telegraf/pull/17929) `deps` Bump google.golang.org/api from 0.253.0 to 0.254.0\n- [#17975](https://github.com/influxdata/telegraf/pull/17975) `deps` Bump google.golang.org/api from 0.254.0 to 0.255.0\n- [#17931](https://github.com/influxdata/telegraf/pull/17931) `deps` Bump modernc.org/sqlite from 1.39.1 to 1.40.0\n- [#17926](https://github.com/influxdata/telegraf/pull/17926) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n- [#17969](https://github.com/influxdata/telegraf/pull/17969) `deps` Bump the aws-sdk-go-v2 group with 11 updates\n\n## v1.36.3 [2025-10-21]\n\n### Bugfixes\n\n- [#17765](https://github.com/influxdata/telegraf/pull/17765) `inputs.chrony` Prevent race condition in concurrent gather calls\n- [#17634](https://github.com/influxdata/telegraf/pull/17634) `inputs.docker` Fix incorrect CPU usage_percent for Podman containers\n- [#17740](https://github.com/influxdata/telegraf/pull/17740) `inputs.kube_inventory` Prevent panic in endpoints' ready flag\n- [#17483](https://github.com/influxdata/telegraf/pull/17483) `inputs.smart` Correct exit_status for active vs standby drives\n- [#17617](https://github.com/influxdata/telegraf/pull/17617) `inputs.zfs` Parse field values according to provided type\n- [#17787](https://github.com/influxdata/telegraf/pull/17787) `outputs.nats` Unwrap wrapped metrics to avoid panic on missing Field method\n- [#17573](https://github.com/influxdata/telegraf/pull/17573) `parsers.csv` Support concurrent usage\n- [#17738](https://github.com/influxdata/telegraf/pull/17738) `secretstores.systemd` Handle dash version separator correctly\n\n### Dependency Updates\n\n- [#17770](https://github.com/influxdata/telegraf/pull/17770) `deps` Bump cloud.google.com/go/bigquery from 1.70.0 to 1.71.0\n- [#17821](https://github.com/influxdata/telegraf/pull/17821) `deps` Bump cloud.google.com/go/monitoring from 1.24.2 to 1.24.3\n- [#17777](https://github.com/influxdata/telegraf/pull/17777) `deps` Bump cloud.google.com/go/pubsub/v2 from 2.0.0 to 2.2.0\n- [#17846](https://github.com/influxdata/telegraf/pull/17846) `deps` Bump cloud.google.com/go/pubsub/v2 from 2.2.0 to 2.2.1\n- [#17718](https://github.com/influxdata/telegraf/pull/17718) `deps` Bump cloud.google.com/go/storage from 1.56.2 to 1.57.0\n- [#17805](https://github.com/influxdata/telegraf/pull/17805) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.12.0 to 1.13.0\n- [#17784](https://github.com/influxdata/telegraf/pull/17784) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs from 1.4.0 to 2.0.0\n- [#17810](https://github.com/influxdata/telegraf/pull/17810) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs/v2 from 2.0.0 to 2.0.1\n- [#17804](https://github.com/influxdata/telegraf/pull/17804) `deps` Bump github.com/IBM/sarama from 1.46.1 to 1.46.2\n- [#17724](https://github.com/influxdata/telegraf/pull/17724) `deps` Bump github.com/SAP/go-hdb from 1.14.4 to 1.14.5\n- [#17808](https://github.com/influxdata/telegraf/pull/17808) `deps` Bump github.com/SAP/go-hdb from 1.14.5 to 1.14.6\n- [#17866](https://github.com/influxdata/telegraf/pull/17866) `deps` Bump github.com/SAP/go-hdb from 1.14.6 to 1.14.7\n- [#17822](https://github.com/influxdata/telegraf/pull/17822) `deps` Bump github.com/antchfx/xmlquery from 1.4.4 to 1.5.0\n- [#17868](https://github.com/influxdata/telegraf/pull/17868) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.31.12 to 1.31.13\n- [#17730](https://github.com/influxdata/telegraf/pull/17730) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.31.9 to 1.31.12\n- [#17719](https://github.com/influxdata/telegraf/pull/17719) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.50.1 to 1.51.1\n- [#17863](https://github.com/influxdata/telegraf/pull/17863) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.51.1 to 1.51.2\n- [#17716](https://github.com/influxdata/telegraf/pull/17716) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.58.0 to 1.58.2\n- [#17715](https://github.com/influxdata/telegraf/pull/17715) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.50.3 to 1.50.5\n- [#17772](https://github.com/influxdata/telegraf/pull/17772) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.50.5 to 1.51.0\n- [#17714](https://github.com/influxdata/telegraf/pull/17714) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.253.0 to 1.254.1\n- [#17814](https://github.com/influxdata/telegraf/pull/17814) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.254.1 to 1.255.0\n- [#17728](https://github.com/influxdata/telegraf/pull/17728) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.40.3 to 1.40.5\n- [#17848](https://github.com/influxdata/telegraf/pull/17848) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.40.5 to 1.40.6\n- [#17723](https://github.com/influxdata/telegraf/pull/17723) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.35.3 to 1.35.5\n- [#17864](https://github.com/influxdata/telegraf/pull/17864) `deps` Bump github.com/aws/smithy-go from 1.23.0 to 1.23.1\n- [#17849](https://github.com/influxdata/telegraf/pull/17849) `deps` Bump github.com/bluenviron/gomavlib/v3 from 3.2.1 to 3.3.0\n- [#17774](https://github.com/influxdata/telegraf/pull/17774) `deps` Bump github.com/docker/docker from 28.4.0+incompatible to 28.5.0+incompatible\n- [#17816](https://github.com/influxdata/telegraf/pull/17816) `deps` Bump github.com/docker/docker from 28.5.0+incompatible to 28.5.1+incompatible\n- [#17769](https://github.com/influxdata/telegraf/pull/17769) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.11 to 3.4.12\n- [#17775](https://github.com/influxdata/telegraf/pull/17775) `deps` Bump github.com/go-logfmt/logfmt from 0.6.0 to 0.6.1\n- [#17727](https://github.com/influxdata/telegraf/pull/17727) `deps` Bump github.com/hashicorp/consul/api from 1.32.3 to 1.32.4\n- [#17862](https://github.com/influxdata/telegraf/pull/17862) `deps` Bump github.com/klauspost/compress from 1.18.0 to 1.18.1\n- [#17773](https://github.com/influxdata/telegraf/pull/17773) `deps` Bump github.com/leodido/go-syslog/v4 from 4.2.1-0.20250421191238-de2e76af1251 to 4.3.0\n- [#17729](https://github.com/influxdata/telegraf/pull/17729) `deps` Bump github.com/lxc/incus/v6 from 6.16.0 to 6.17.0\n- [#17860](https://github.com/influxdata/telegraf/pull/17860) `deps` Bump github.com/nats-io/nats-server/v2 from 2.12.0 to 2.12.1\n- [#17766](https://github.com/influxdata/telegraf/pull/17766) `deps` Bump github.com/nats-io/nats.go from 1.46.0 to 1.46.1\n- [#17851](https://github.com/influxdata/telegraf/pull/17851) `deps` Bump github.com/nats-io/nats.go from 1.46.1 to 1.47.0\n- [#17813](https://github.com/influxdata/telegraf/pull/17813) `deps` Bump github.com/prometheus/common from 0.66.1 to 0.67.1\n- [#17867](https://github.com/influxdata/telegraf/pull/17867) `deps` Bump github.com/prometheus/prometheus from 0.306.0 to 0.307.1\n- [#17861](https://github.com/influxdata/telegraf/pull/17861) `deps` Bump github.com/redis/go-redis/v9 from 9.14.0 to 9.14.1\n- [#17767](https://github.com/influxdata/telegraf/pull/17767) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.8 to 4.25.9\n- [#17725](https://github.com/influxdata/telegraf/pull/17725) `deps` Bump github.com/snowflakedb/gosnowflake from 0.0.0-20250911095445-20c4d105d9a0 to 1.17.0\n- [#17776](https://github.com/influxdata/telegraf/pull/17776) `deps` Bump go.opentelemetry.io/collector/pdata from 1.42.0 to 1.43.0\n- [#17817](https://github.com/influxdata/telegraf/pull/17817) `deps` Bump go.step.sm/crypto from 0.70.0 to 0.71.0\n- [#17857](https://github.com/influxdata/telegraf/pull/17857) `deps` Bump go.step.sm/crypto from 0.71.0 to 0.72.0\n- [#17820](https://github.com/influxdata/telegraf/pull/17820) `deps` Bump golang.org/x/crypto from 0.42.0 to 0.43.0\n- [#17806](https://github.com/influxdata/telegraf/pull/17806) `deps` Bump golang.org/x/mod from 0.28.0 to 0.29.0\n- [#17819](https://github.com/influxdata/telegraf/pull/17819) `deps` Bump golang.org/x/net from 0.44.0 to 0.46.0\n- [#17818](https://github.com/influxdata/telegraf/pull/17818) `deps` Bump golang.org/x/oauth2 from 0.31.0 to 0.32.0\n- [#17823](https://github.com/influxdata/telegraf/pull/17823) `deps` Bump golang.org/x/sys from 0.36.0 to 0.37.0\n- [#17717](https://github.com/influxdata/telegraf/pull/17717) `deps` Bump google.golang.org/api from 0.249.0 to 0.250.0\n- [#17778](https://github.com/influxdata/telegraf/pull/17778) `deps` Bump google.golang.org/api from 0.250.0 to 0.251.0\n- [#17807](https://github.com/influxdata/telegraf/pull/17807) `deps` Bump google.golang.org/api from 0.251.0 to 0.252.0\n- [#17771](https://github.com/influxdata/telegraf/pull/17771) `deps` Bump google.golang.org/grpc from 1.75.1 to 1.76.0\n- [#17768](https://github.com/influxdata/telegraf/pull/17768) `deps` Bump google.golang.org/protobuf from 1.36.9 to 1.36.10\n- [#17811](https://github.com/influxdata/telegraf/pull/17811) `deps` Bump modernc.org/sqlite from 1.39.0 to 1.39.1\n- [#17779](https://github.com/influxdata/telegraf/pull/17779) `deps` Bump super-linter/super-linter from 8.1.0 to 8.2.0\n- [#17853](https://github.com/influxdata/telegraf/pull/17853) `deps` Bump super-linter/super-linter from 8.2.0 to 8.2.1\n- [#17610](https://github.com/influxdata/telegraf/pull/17610) `deps` Switch to maintained yaml library\n- [#17794](https://github.com/influxdata/telegraf/pull/17794) `deps` Update golangci-lint to 2.5.0\n\n## v1.36.2 [2025-09-29]\n\n### Bugfixes\n\n- [#17609](https://github.com/influxdata/telegraf/pull/17609) `filter` Handle multiple conditions correctly\n- [#17552](https://github.com/influxdata/telegraf/pull/17552) `inputs.procstat` Use correct values for disk_read_bytes, disk_write_bytes on Linux\n- [#17613](https://github.com/influxdata/telegraf/pull/17613) `inputs.tail` Fix data race when cleaning up unused tailers\n\n### Dependency Updates\n\n- [#17599](https://github.com/influxdata/telegraf/pull/17599) `deps` Bump actions/setup-go from 5 to 6\n- [#17650](https://github.com/influxdata/telegraf/pull/17650) `deps` Bump cloud.google.com/go/bigquery from 1.69.0 to 1.70.0\n- [#17654](https://github.com/influxdata/telegraf/pull/17654) `deps` Bump cloud.google.com/go/storage from 1.56.1 to 1.56.2\n- [#17688](https://github.com/influxdata/telegraf/pull/17688) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.19.0 to 1.19.1\n- [#17683](https://github.com/influxdata/telegraf/pull/17683) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.11.0 to 1.12.0\n- [#17644](https://github.com/influxdata/telegraf/pull/17644) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.40.1 to 2.40.3\n- [#17522](https://github.com/influxdata/telegraf/pull/17522) `deps` Bump github.com/IBM/sarama from 1.45.2 to 1.46.0\n- [#17682](https://github.com/influxdata/telegraf/pull/17682) `deps` Bump github.com/IBM/sarama from 1.46.0 to 1.46.1\n- [#17636](https://github.com/influxdata/telegraf/pull/17636) `deps` Bump github.com/SAP/go-hdb from 1.14.0 to 1.14.3\n- [#17677](https://github.com/influxdata/telegraf/pull/17677) `deps` Bump github.com/SAP/go-hdb from 1.14.3 to 1.14.4\n- [#17647](https://github.com/influxdata/telegraf/pull/17647) `deps` Bump github.com/apache/arrow-go/v18 from 18.4.0 to 18.4.1\n- [#17587](https://github.com/influxdata/telegraf/pull/17587) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.5 to 1.0.6\n- [#17642](https://github.com/influxdata/telegraf/pull/17642) `deps` Bump github.com/awnumar/memguard from 0.22.5 to 0.23.0\n- [#17693](https://github.com/influxdata/telegraf/pull/17693) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.31.4 to 1.31.9\n- [#17588](https://github.com/influxdata/telegraf/pull/17588) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.18.5 to 1.18.7\n- [#17641](https://github.com/influxdata/telegraf/pull/17641) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.48.2 to 1.50.1\n- [#17656](https://github.com/influxdata/telegraf/pull/17656) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.57.0 to 1.57.4\n- [#17690](https://github.com/influxdata/telegraf/pull/17690) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.57.4 to 1.58.0\n- [#17596](https://github.com/influxdata/telegraf/pull/17596) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.49.1 to 1.50.2\n- [#17649](https://github.com/influxdata/telegraf/pull/17649) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.50.2 to 1.50.3\n- [#17583](https://github.com/influxdata/telegraf/pull/17583) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.246.0 to 1.251.1\n- [#17640](https://github.com/influxdata/telegraf/pull/17640) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.251.1 to 1.251.2\n- [#17681](https://github.com/influxdata/telegraf/pull/17681) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.251.2 to 1.253.0\n- [#17595](https://github.com/influxdata/telegraf/pull/17595) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.39.1 to 1.40.2\n- [#17646](https://github.com/influxdata/telegraf/pull/17646) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.40.2 to 1.40.3\n- [#17638](https://github.com/influxdata/telegraf/pull/17638) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.38.1 to 1.38.4\n- [#17582](https://github.com/influxdata/telegraf/pull/17582) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.34.2 to 1.35.2\n- [#17658](https://github.com/influxdata/telegraf/pull/17658) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.35.2 to 1.35.3\n- [#17673](https://github.com/influxdata/telegraf/pull/17673) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.16.1 to 2.16.2\n- [#17601](https://github.com/influxdata/telegraf/pull/17601) `deps` Bump github.com/docker/docker from 28.3.3+incompatible to 28.4.0+incompatible\n- [#17653](https://github.com/influxdata/telegraf/pull/17653) `deps` Bump github.com/eclipse/paho.golang from 0.22.0 to 0.23.0\n- [#17680](https://github.com/influxdata/telegraf/pull/17680) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.5.0 to 1.5.1\n- [#17597](https://github.com/influxdata/telegraf/pull/17597) `deps` Bump github.com/google/cel-go from 0.26.0 to 0.26.1\n- [#17689](https://github.com/influxdata/telegraf/pull/17689) `deps` Bump github.com/hashicorp/consul/api from 1.32.1 to 1.32.3\n- [#17651](https://github.com/influxdata/telegraf/pull/17651) `deps` Bump github.com/lxc/incus/v6 from 6.15.0 to 6.16.0\n- [#17635](https://github.com/influxdata/telegraf/pull/17635) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.8 to 2.11.9\n- [#17670](https://github.com/influxdata/telegraf/pull/17670) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.9 to 2.12.0\n- [#17675](https://github.com/influxdata/telegraf/pull/17675) `deps` Bump github.com/nats-io/nats.go from 1.45.0 to 1.46.0\n- [#17674](https://github.com/influxdata/telegraf/pull/17674) `deps` Bump github.com/peterbourgon/unixtransport from 0.0.6 to 0.0.7\n- [#17593](https://github.com/influxdata/telegraf/pull/17593) `deps` Bump github.com/prometheus/client_golang from 1.23.0 to 1.23.2\n- [#17585](https://github.com/influxdata/telegraf/pull/17585) `deps` Bump github.com/prometheus/common from 0.65.0 to 0.66.1\n- [#17685](https://github.com/influxdata/telegraf/pull/17685) `deps` Bump github.com/prometheus/prometheus from 0.305.0 to 0.306.0\n- [#17329](https://github.com/influxdata/telegraf/pull/17329) `deps` Bump github.com/prometheus/prometheus from 0.54.1 to 0.305.0\n- [#17645](https://github.com/influxdata/telegraf/pull/17645) `deps` Bump github.com/redis/go-redis/v9 from 9.12.1 to 9.14.0\n- [#17567](https://github.com/influxdata/telegraf/pull/17567) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.7 to 4.25.8\n- [#17699](https://github.com/influxdata/telegraf/pull/17699) `deps` Bump github.com/snowflakedb/gosnowflake from 1.16.0 to 0.0.0-20250911095445-20c4d105d9a0\n- [#17590](https://github.com/influxdata/telegraf/pull/17590) `deps` Bump github.com/stretchr/testify from 1.10.0 to 1.11.1\n- [#17687](https://github.com/influxdata/telegraf/pull/17687) `deps` Bump github.com/testcontainers/testcontainers-go from 0.38.0 to 0.39.0\n- [#17676](https://github.com/influxdata/telegraf/pull/17676) `deps` Bump github.com/testcontainers/testcontainers-go/modules/azure from 0.38.0 to 0.39.0\n- [#17671](https://github.com/influxdata/telegraf/pull/17671) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.38.0 to 0.39.0\n- [#17584](https://github.com/influxdata/telegraf/pull/17584) `deps` Bump github.com/tidwall/wal from 1.2.0 to 1.2.1\n- [#17581](https://github.com/influxdata/telegraf/pull/17581) `deps` Bump github.com/tinylib/msgp from 1.3.0 to 1.4.0\n- [#17591](https://github.com/influxdata/telegraf/pull/17591) `deps` Bump go.opentelemetry.io/collector/pdata from 1.39.0 to 1.41.0\n- [#17686](https://github.com/influxdata/telegraf/pull/17686) `deps` Bump go.opentelemetry.io/collector/pdata from 1.41.0 to 1.42.0\n- [#17602](https://github.com/influxdata/telegraf/pull/17602) `deps` Bump go.opentelemetry.io/proto/otlp from 1.7.0 to 1.8.0\n- [#17652](https://github.com/influxdata/telegraf/pull/17652) `deps` Bump golang.org/x/crypto from 0.41.0 to 0.42.0\n- [#17691](https://github.com/influxdata/telegraf/pull/17691) `deps` Bump golang.org/x/mod from 0.27.0 to 0.28.0\n- [#17655](https://github.com/influxdata/telegraf/pull/17655) `deps` Bump golang.org/x/oauth2 from 0.30.0 to 0.31.0\n- [#17589](https://github.com/influxdata/telegraf/pull/17589) `deps` Bump golang.org/x/sync from 0.16.0 to 0.17.0\n- [#17580](https://github.com/influxdata/telegraf/pull/17580) `deps` Bump golang.org/x/term from 0.34.0 to 0.35.0\n- [#17679](https://github.com/influxdata/telegraf/pull/17679) `deps` Bump google.golang.org/api from 0.248.0 to 0.249.0\n- [#17639](https://github.com/influxdata/telegraf/pull/17639) `deps` Bump google.golang.org/grpc from 1.75.0 to 1.75.1\n- [#17643](https://github.com/influxdata/telegraf/pull/17643) `deps` Bump google.golang.org/protobuf from 1.36.8 to 1.36.9\n- [#17598](https://github.com/influxdata/telegraf/pull/17598) `deps` Bump k8s.io/api from 0.33.4 to 0.34.0\n- [#17692](https://github.com/influxdata/telegraf/pull/17692) `deps` Bump k8s.io/client-go from 0.34.0 to 0.34.1\n- [#17657](https://github.com/influxdata/telegraf/pull/17657) `deps` Bump modernc.org/sqlite from 1.38.2 to 1.39.0\n- [#17648](https://github.com/influxdata/telegraf/pull/17648) `deps` Bump tj-actions/changed-files from 46.0.5 to 47.0.0\n- [#17707](https://github.com/influxdata/telegraf/pull/17707) `deps` Remove collectd replacement\n\n## v1.36.1 [2025-09-08]\n\n### Bugfixes\n\n- [#17605](https://github.com/influxdata/telegraf/pull/17605) `outputs.influxdb` Fix crash on init\n\n## v1.36.0 [2025-09-08]\n\n### Important Changes\n\n- PR [#17355](https://github.com/influxdata/telegraf/pull/17355) changes the `profiles` support\n  of `inputs.opentelemetry` from the `v1 experimental` to the `v1 development` as this experimental API\n  is updated upstream. This will change the metric by for example removing the no-longer reported\n  `frame_type`, `stack_trace_id`, `build_id`, and `build_id_type` fields. Also, the value format of other fields\n  or tags might have changed. Please refer to the\n  [OpenTelemetry documentation](https://opentelemetry.io/docs/) for more details.\n\n### New Plugins\n\n- [#17368](https://github.com/influxdata/telegraf/pull/17368) `inputs.turbostat` Add plugin\n- [#17078](https://github.com/influxdata/telegraf/pull/17078) `processors.round` Add plugin\n\n### Features\n\n- [#16705](https://github.com/influxdata/telegraf/pull/16705) `agent` Introduce labels and selectors to enable and disable plugins\n- [#17547](https://github.com/influxdata/telegraf/pull/17547) `inputs.influxdb_v2_listener` Add `/health` route\n- [#17312](https://github.com/influxdata/telegraf/pull/17312) `inputs.internal` Allow to collect statistics per plugin instance\n- [#17024](https://github.com/influxdata/telegraf/pull/17024) `inputs.lvm` Add sync_percent for lvm_logical_vol\n- [#17355](https://github.com/influxdata/telegraf/pull/17355) `inputs.opentelemetry` Upgrade otlp proto module\n- [#17156](https://github.com/influxdata/telegraf/pull/17156) `inputs.syslog` Add support for RFC3164 over TCP\n- [#17543](https://github.com/influxdata/telegraf/pull/17543) `inputs.syslog` Allow limiting message size in octet counting mode\n- [#17539](https://github.com/influxdata/telegraf/pull/17539) `inputs.x509_cert` Add support for Windows certificate stores\n- [#17244](https://github.com/influxdata/telegraf/pull/17244) `output.nats` Allow disabling stream creation for externally managed streams\n- [#17474](https://github.com/influxdata/telegraf/pull/17474) `outputs.elasticsearch` Support array headers and preserve commas in values\n- [#17548](https://github.com/influxdata/telegraf/pull/17548) `outputs.influxdb` Add internal statistics for written bytes\n- [#17213](https://github.com/influxdata/telegraf/pull/17213) `outputs.nats` Allow providing a subject layout\n- [#17346](https://github.com/influxdata/telegraf/pull/17346) `outputs.nats` Enable batch serialization with use_batch_format\n- [#17249](https://github.com/influxdata/telegraf/pull/17249) `outputs.sql` Allow sending batches of metrics in transactions\n- [#17510](https://github.com/influxdata/telegraf/pull/17510) `parsers.avro` Support record arrays at root level\n- [#17365](https://github.com/influxdata/telegraf/pull/17365) `plugins.snmp` Allow debug logging in gosnmp\n- [#17345](https://github.com/influxdata/telegraf/pull/17345) `selfstat` Implement collection of plugin-internal statistics\n\n### Bugfixes\n\n- [#17411](https://github.com/influxdata/telegraf/pull/17411) `inputs.diskio` Handle counter wrapping in io fields\n- [#17551](https://github.com/influxdata/telegraf/pull/17551) `inputs.s7comm` Use correct value for string length with 'extra' parameter\n- [#17579](https://github.com/influxdata/telegraf/pull/17579) `internal` Extract go version more robustly\n- [#17566](https://github.com/influxdata/telegraf/pull/17566) `outputs` Retrigger batch-available-events only if at least one metric was written successfully\n- [#17381](https://github.com/influxdata/telegraf/pull/17381) `packaging` Rename rpm from loong64 to loongarch64\n\n### Dependency Updates\n\n- [#17519](https://github.com/influxdata/telegraf/pull/17519) `deps` Bump cloud.google.com/go/storage from 1.56.0 to 1.56.1\n- [#17532](https://github.com/influxdata/telegraf/pull/17532) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.18.2 to 1.19.0\n- [#17494](https://github.com/influxdata/telegraf/pull/17494) `deps` Bump github.com/SAP/go-hdb from 1.13.12 to 1.14.0\n- [#17488](https://github.com/influxdata/telegraf/pull/17488) `deps` Bump github.com/antchfx/xpath from 1.3.4 to 1.3.5\n- [#17540](https://github.com/influxdata/telegraf/pull/17540) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.31.0 to 1.31.2\n- [#17538](https://github.com/influxdata/telegraf/pull/17538) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.18.4 to 1.18.6\n- [#17517](https://github.com/influxdata/telegraf/pull/17517) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.18.3 to 1.18.4\n- [#17528](https://github.com/influxdata/telegraf/pull/17528) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.48.0 to 1.48.2\n- [#17536](https://github.com/influxdata/telegraf/pull/17536) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.56.0 to 1.57.0\n- [#17524](https://github.com/influxdata/telegraf/pull/17524) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.46.0 to 1.49.1\n- [#17493](https://github.com/influxdata/telegraf/pull/17493) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.242.0 to 1.244.0\n- [#17527](https://github.com/influxdata/telegraf/pull/17527) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.244.0 to 1.246.0\n- [#17530](https://github.com/influxdata/telegraf/pull/17530) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.38.0 to 1.39.1\n- [#17534](https://github.com/influxdata/telegraf/pull/17534) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.37.0 to 1.38.0\n- [#17513](https://github.com/influxdata/telegraf/pull/17513) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.34.0 to 1.34.2\n- [#17514](https://github.com/influxdata/telegraf/pull/17514) `deps` Bump github.com/coreos/go-systemd/v22 from 22.5.0 to 22.6.0\n- [#17563](https://github.com/influxdata/telegraf/pull/17563) `deps` Bump github.com/facebook/time from 0.0.0-20240626113945-18207c5d8ddc to 0.0.0-20250903103710-a5911c32cdb9\n- [#17526](https://github.com/influxdata/telegraf/pull/17526) `deps` Bump github.com/gophercloud/gophercloud/v2 from 2.7.0 to 2.8.0\n- [#17537](https://github.com/influxdata/telegraf/pull/17537) `deps` Bump github.com/microsoft/go-mssqldb from 1.9.2 to 1.9.3\n- [#17490](https://github.com/influxdata/telegraf/pull/17490) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.7 to 2.11.8\n- [#17523](https://github.com/influxdata/telegraf/pull/17523) `deps` Bump github.com/nats-io/nats.go from 1.44.0 to 1.45.0\n- [#17492](https://github.com/influxdata/telegraf/pull/17492) `deps` Bump github.com/safchain/ethtool from 0.5.10 to 0.6.2\n- [#17486](https://github.com/influxdata/telegraf/pull/17486) `deps` Bump github.com/snowflakedb/gosnowflake from 1.15.0 to 1.16.0\n- [#17541](https://github.com/influxdata/telegraf/pull/17541) `deps` Bump github.com/tidwall/wal from 1.1.8 to 1.2.0\n- [#17529](https://github.com/influxdata/telegraf/pull/17529) `deps` Bump github.com/vmware/govmomi from 0.51.0 to 0.52.0\n- [#17496](https://github.com/influxdata/telegraf/pull/17496) `deps` Bump go.opentelemetry.io/collector/pdata from 1.36.1 to 1.38.0\n- [#17533](https://github.com/influxdata/telegraf/pull/17533) `deps` Bump go.opentelemetry.io/collector/pdata from 1.38.0 to 1.39.0\n- [#17516](https://github.com/influxdata/telegraf/pull/17516) `deps` Bump go.step.sm/crypto from 0.69.0 to 0.70.0\n- [#17499](https://github.com/influxdata/telegraf/pull/17499) `deps` Bump golang.org/x/mod from 0.26.0 to 0.27.0\n- [#17497](https://github.com/influxdata/telegraf/pull/17497) `deps` Bump golang.org/x/net from 0.42.0 to 0.43.0\n- [#17487](https://github.com/influxdata/telegraf/pull/17487) `deps` Bump google.golang.org/api from 0.246.0 to 0.247.0\n- [#17531](https://github.com/influxdata/telegraf/pull/17531) `deps` Bump google.golang.org/api from 0.247.0 to 0.248.0\n- [#17520](https://github.com/influxdata/telegraf/pull/17520) `deps` Bump google.golang.org/grpc from 1.74.2 to 1.75.0\n- [#17518](https://github.com/influxdata/telegraf/pull/17518) `deps` Bump google.golang.org/protobuf from 1.36.7 to 1.36.8\n- [#17498](https://github.com/influxdata/telegraf/pull/17498) `deps` Bump k8s.io/client-go from 0.33.3 to 0.33.4\n- [#17515](https://github.com/influxdata/telegraf/pull/17515) `deps` Bump super-linter/super-linter from 8.0.0 to 8.1.0\n\n## v1.35.4 [2025-08-18]\n\n### Bugfixes\n\n- [#17451](https://github.com/influxdata/telegraf/pull/17451) `agent` Update help message for CLI flag --test\n- [#17413](https://github.com/influxdata/telegraf/pull/17413) `inputs.gnmi` Handle empty updates in gnmi notification response\n- [#17445](https://github.com/influxdata/telegraf/pull/17445) `inputs.redfish` Log correct address on HTTP error\n\n### Dependency Updates\n\n- [#17454](https://github.com/influxdata/telegraf/pull/17454) `deps` Bump actions/checkout from 4 to 5\n- [#17404](https://github.com/influxdata/telegraf/pull/17404) `deps` Bump cloud.google.com/go/storage from 1.55.0 to 1.56.0\n- [#17428](https://github.com/influxdata/telegraf/pull/17428) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.18.1 to 1.18.2\n- [#17455](https://github.com/influxdata/telegraf/pull/17455) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.10.1 to 1.11.0\n- [#17383](https://github.com/influxdata/telegraf/pull/17383) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.37.2 to 2.39.0\n- [#17435](https://github.com/influxdata/telegraf/pull/17435) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.39.0 to 2.40.1\n- [#17393](https://github.com/influxdata/telegraf/pull/17393) `deps` Bump github.com/apache/arrow-go/v18 from 18.3.1 to 18.4.0\n- [#17439](https://github.com/influxdata/telegraf/pull/17439) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.3 to 1.0.5\n- [#17437](https://github.com/influxdata/telegraf/pull/17437) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.37.0 to 1.37.2\n- [#17402](https://github.com/influxdata/telegraf/pull/17402) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.29.17 to 1.30.0\n- [#17458](https://github.com/influxdata/telegraf/pull/17458) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.30.1 to 1.31.0\n- [#17391](https://github.com/influxdata/telegraf/pull/17391) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.70 to 1.18.0\n- [#17436](https://github.com/influxdata/telegraf/pull/17436) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.18.1 to 1.18.3\n- [#17434](https://github.com/influxdata/telegraf/pull/17434) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.18.0 to 1.18.2\n- [#17461](https://github.com/influxdata/telegraf/pull/17461) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.45.3 to 1.48.0\n- [#17392](https://github.com/influxdata/telegraf/pull/17392) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.51.0 to 1.54.0\n- [#17440](https://github.com/influxdata/telegraf/pull/17440) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.54.0 to 1.55.0\n- [#17473](https://github.com/influxdata/telegraf/pull/17473) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.55.0 to 1.56.0\n- [#17431](https://github.com/influxdata/telegraf/pull/17431) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.44.0 to 1.46.0\n- [#17470](https://github.com/influxdata/telegraf/pull/17470) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.231.0 to 1.242.0\n- [#17397](https://github.com/influxdata/telegraf/pull/17397) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.35.3 to 1.36.0\n- [#17430](https://github.com/influxdata/telegraf/pull/17430) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.36.0 to 1.37.0\n- [#17469](https://github.com/influxdata/telegraf/pull/17469) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.37.0 to 1.38.0\n- [#17432](https://github.com/influxdata/telegraf/pull/17432) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.35.0 to 1.36.0\n- [#17401](https://github.com/influxdata/telegraf/pull/17401) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.31.2 to 1.32.0\n- [#17421](https://github.com/influxdata/telegraf/pull/17421) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.32.0 to 1.33.0\n- [#17464](https://github.com/influxdata/telegraf/pull/17464) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.33.0 to 1.34.0\n- [#17457](https://github.com/influxdata/telegraf/pull/17457) `deps` Bump github.com/clarify/clarify-go from 0.4.0 to 0.4.1\n- [#17407](https://github.com/influxdata/telegraf/pull/17407) `deps` Bump github.com/docker/docker from 28.3.2+incompatible to 28.3.3+incompatible\n- [#17463](https://github.com/influxdata/telegraf/pull/17463) `deps` Bump github.com/docker/go-connections from 0.5.0 to 0.6.0\n- [#17394](https://github.com/influxdata/telegraf/pull/17394) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.2.2 to 5.2.3\n- [#17423](https://github.com/influxdata/telegraf/pull/17423) `deps` Bump github.com/gopacket/gopacket from 1.3.1 to 1.4.0\n- [#17399](https://github.com/influxdata/telegraf/pull/17399) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.6.7 to 6.6.8\n- [#17422](https://github.com/influxdata/telegraf/pull/17422) `deps` Bump github.com/lxc/incus/v6 from 6.14.0 to 6.15.0\n- [#17429](https://github.com/influxdata/telegraf/pull/17429) `deps` Bump github.com/miekg/dns from 1.1.67 to 1.1.68\n- [#17433](https://github.com/influxdata/telegraf/pull/17433) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.6 to 2.11.7\n- [#17426](https://github.com/influxdata/telegraf/pull/17426) `deps` Bump github.com/nats-io/nats.go from 1.43.0 to 1.44.0\n- [#17456](https://github.com/influxdata/telegraf/pull/17456) `deps` Bump github.com/redis/go-redis/v9 from 9.11.0 to 9.12.1\n- [#17420](https://github.com/influxdata/telegraf/pull/17420) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.6 to 4.25.7\n- [#17388](https://github.com/influxdata/telegraf/pull/17388) `deps` Bump github.com/testcontainers/testcontainers-go/modules/azure from 0.37.0 to 0.38.0\n- [#17382](https://github.com/influxdata/telegraf/pull/17382) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.37.0 to 0.38.0\n- [#17427](https://github.com/influxdata/telegraf/pull/17427) `deps` Bump github.com/yuin/goldmark from 1.7.12 to 1.7.13\n- [#17386](https://github.com/influxdata/telegraf/pull/17386) `deps` Bump go.opentelemetry.io/collector/pdata from 1.36.0 to 1.36.1\n- [#17425](https://github.com/influxdata/telegraf/pull/17425) `deps` Bump go.step.sm/crypto from 0.67.0 to 0.68.0\n- [#17462](https://github.com/influxdata/telegraf/pull/17462) `deps` Bump go.step.sm/crypto from 0.68.0 to 0.69.0\n- [#17460](https://github.com/influxdata/telegraf/pull/17460) `deps` Bump golang.org/x/crypto from 0.40.0 to 0.41.0\n- [#17424](https://github.com/influxdata/telegraf/pull/17424) `deps` Bump google.golang.org/api from 0.243.0 to 0.244.0\n- [#17459](https://github.com/influxdata/telegraf/pull/17459) `deps` Bump google.golang.org/api from 0.244.0 to 0.246.0\n- [#17465](https://github.com/influxdata/telegraf/pull/17465) `deps` Bump google.golang.org/protobuf from 1.36.6 to 1.36.7\n- [#17384](https://github.com/influxdata/telegraf/pull/17384) `deps` Bump k8s.io/apimachinery from 0.33.2 to 0.33.3\n- [#17389](https://github.com/influxdata/telegraf/pull/17389) `deps` Bump k8s.io/client-go from 0.33.2 to 0.33.3\n- [#17396](https://github.com/influxdata/telegraf/pull/17396) `deps` Bump modernc.org/sqlite from 1.38.0 to 1.38.1\n- [#17385](https://github.com/influxdata/telegraf/pull/17385) `deps` Bump software.sslmate.com/src/go-pkcs12 from 0.5.0 to 0.6.0\n- [#17390](https://github.com/influxdata/telegraf/pull/17390) `deps` Bump super-linter/super-linter from 7.4.0 to 8.0.0\n- [#17448](https://github.com/influxdata/telegraf/pull/17448) `deps` Fix collectd dependency not resolving\n- [#17410](https://github.com/influxdata/telegraf/pull/17410) `deps` Migrate from cloud.google.com/go/pubsub to v2\n\n## v1.35.3 [2025-07-28]\n\n### Bugfixes\n\n- [#17373](https://github.com/influxdata/telegraf/pull/17373) `agent` Handle nil timer on telegraf reload when no debounce is specified\n- [#17340](https://github.com/influxdata/telegraf/pull/17340) `agent` Make Windows service install more robust\n- [#17310](https://github.com/influxdata/telegraf/pull/17310) `outputs.sql` Add timestamp to derived datatypes\n- [#17349](https://github.com/influxdata/telegraf/pull/17349) `outputs` Retrigger batch-available-events only for non-failing writes\n- [#17293](https://github.com/influxdata/telegraf/pull/17293) `parsers.json_v2` Respect string type for objects and arrays\n- [#17367](https://github.com/influxdata/telegraf/pull/17367) `plugins.snmp` Update gosnmp to prevent panic in snmp agents\n- [#17292](https://github.com/influxdata/telegraf/pull/17292) `processors.snmp_lookup` Avoid re-enqueing updates after plugin stopped\n- [#17369](https://github.com/influxdata/telegraf/pull/17369) `processors.snmp_lookup` Prevent deadlock during plugin shutdown\n\n### Dependency Updates\n\n- [#17320](https://github.com/influxdata/telegraf/pull/17320) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.18.0 to 1.18.1\n- [#17328](https://github.com/influxdata/telegraf/pull/17328) `deps` Bump github.com/SAP/go-hdb from 1.13.11 to 1.13.12\n- [#17301](https://github.com/influxdata/telegraf/pull/17301) `deps` Bump github.com/SAP/go-hdb from 1.13.9 to 1.13.11\n- [#17326](https://github.com/influxdata/telegraf/pull/17326) `deps` Bump github.com/alitto/pond/v2 from 2.4.0 to 2.5.0\n- [#17295](https://github.com/influxdata/telegraf/pull/17295) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.227.0 to 1.230.0\n- [#17332](https://github.com/influxdata/telegraf/pull/17332) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.230.0 to 1.231.0\n- [#17300](https://github.com/influxdata/telegraf/pull/17300) `deps` Bump github.com/docker/docker from 28.3.0+incompatible to 28.3.1+incompatible\n- [#17334](https://github.com/influxdata/telegraf/pull/17334) `deps` Bump github.com/docker/docker from 28.3.1+incompatible to 28.3.2+incompatible\n- [#17327](https://github.com/influxdata/telegraf/pull/17327) `deps` Bump github.com/google/cel-go from 0.25.0 to 0.26.0\n- [#17331](https://github.com/influxdata/telegraf/pull/17331) `deps` Bump github.com/miekg/dns from 1.1.66 to 1.1.67\n- [#17297](https://github.com/influxdata/telegraf/pull/17297) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.5 to 2.11.6\n- [#17321](https://github.com/influxdata/telegraf/pull/17321) `deps` Bump github.com/openconfig/goyang from 1.6.2 to 1.6.3\n- [#17298](https://github.com/influxdata/telegraf/pull/17298) `deps` Bump github.com/prometheus/procfs from 0.16.1 to 0.17.0\n- [#17296](https://github.com/influxdata/telegraf/pull/17296) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.5 to 4.25.6\n- [#17299](https://github.com/influxdata/telegraf/pull/17299) `deps` Bump github.com/snowflakedb/gosnowflake from 1.14.1 to 1.15.0\n- [#17323](https://github.com/influxdata/telegraf/pull/17323) `deps` Bump go.opentelemetry.io/collector/pdata from 1.35.0 to 1.36.0\n- [#17091](https://github.com/influxdata/telegraf/pull/17091) `deps` Bump go.step.sm/crypto from 0.64.0 to 0.67.0\n- [#17330](https://github.com/influxdata/telegraf/pull/17330) `deps` Bump golang.org/x/crypto from 0.39.0 to 0.40.0\n- [#17322](https://github.com/influxdata/telegraf/pull/17322) `deps` Bump golang.org/x/mod from 0.25.0 to 0.26.0\n- [#17336](https://github.com/influxdata/telegraf/pull/17336) `deps` Bump golang.org/x/net from 0.41.0 to 0.42.0\n- [#17337](https://github.com/influxdata/telegraf/pull/17337) `deps` Bump golang.org/x/sys from 0.33.0 to 0.34.0\n- [#17335](https://github.com/influxdata/telegraf/pull/17335) `deps` Bump golang.org/x/term from 0.32.0 to 0.33.0\n- [#17294](https://github.com/influxdata/telegraf/pull/17294) `deps` Bump google.golang.org/api from 0.239.0 to 0.240.0\n- [#17325](https://github.com/influxdata/telegraf/pull/17325) `deps` Bump google.golang.org/api from 0.240.0 to 0.241.0\n- [#17138](https://github.com/influxdata/telegraf/pull/17138) `deps` Bump modernc.org/sqlite from 1.37.0 to 1.38.0\n\n## v1.35.2 [2025-07-07]\n\n### Bugfixes\n\n- [#17248](https://github.com/influxdata/telegraf/pull/17248) `agent` Add missing config flags for migrate command\n- [#17240](https://github.com/influxdata/telegraf/pull/17240) `disk-buffer` Correctly reset the mask after adding to an empty buffer\n- [#17284](https://github.com/influxdata/telegraf/pull/17284) `disk-buffer` Expire metric tracking information in the right place\n- [#17257](https://github.com/influxdata/telegraf/pull/17257) `disk-buffer` Mask old tracking metrics on restart\n- [#17247](https://github.com/influxdata/telegraf/pull/17247) `disk-buffer` Remove empty buffer on close\n- [#17285](https://github.com/influxdata/telegraf/pull/17285) `inputs.gnmi` Avoid interpreting path elements with multiple colons as namespace\n- [#17278](https://github.com/influxdata/telegraf/pull/17278) `inputs.gnmi` Handle base64 encoded IEEE-754 floats correctly\n- [#17258](https://github.com/influxdata/telegraf/pull/17258) `inputs.kibana` Support Kibana 8.x status API format change\n- [#17214](https://github.com/influxdata/telegraf/pull/17214) `inputs.ntpq` Fix ntpq field misalignment parsing errors\n- [#17234](https://github.com/influxdata/telegraf/pull/17234) `outputs.microsoft_fabric` Correct app name\n- [#17291](https://github.com/influxdata/telegraf/pull/17291) `outputs.nats` Avoid initializing Jetstream unconditionally\n- [#17246](https://github.com/influxdata/telegraf/pull/17246) `outputs` Retrigger batch-available-events correctly\n\n### Dependency Updates\n\n- [#17217](https://github.com/influxdata/telegraf/pull/17217) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs from 1.3.2 to 1.4.0\n- [#17226](https://github.com/influxdata/telegraf/pull/17226) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.37.0 to 2.37.1\n- [#17265](https://github.com/influxdata/telegraf/pull/17265) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.37.1 to 2.37.2\n- [#17268](https://github.com/influxdata/telegraf/pull/17268) `deps` Bump github.com/Masterminds/semver/v3 from 3.3.1 to 3.4.0\n- [#17271](https://github.com/influxdata/telegraf/pull/17271) `deps` Bump github.com/SAP/go-hdb from 1.13.7 to 1.13.9\n- [#17232](https://github.com/influxdata/telegraf/pull/17232) `deps` Bump github.com/alitto/pond/v2 from 2.3.4 to 2.4.0\n- [#17231](https://github.com/influxdata/telegraf/pull/17231) `deps` Bump github.com/apache/arrow-go/v18 from 18.3.0 to 18.3.1\n- [#17223](https://github.com/influxdata/telegraf/pull/17223) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.29.15 to 1.29.17\n- [#17220](https://github.com/influxdata/telegraf/pull/17220) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.69 to 1.17.70\n- [#17227](https://github.com/influxdata/telegraf/pull/17227) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.50.3 to 1.51.0\n- [#17262](https://github.com/influxdata/telegraf/pull/17262) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.43.4 to 1.44.0\n- [#17224](https://github.com/influxdata/telegraf/pull/17224) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.225.1 to 1.225.2\n- [#17260](https://github.com/influxdata/telegraf/pull/17260) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.226.0 to 1.227.0\n- [#17264](https://github.com/influxdata/telegraf/pull/17264) `deps` Bump github.com/docker/docker from 28.2.2+incompatible to 28.3.0+incompatible\n- [#17256](https://github.com/influxdata/telegraf/pull/17256) `deps` Bump github.com/lxc/incus/v6 from 6.13.0 to 6.14.0\n- [#17272](https://github.com/influxdata/telegraf/pull/17272) `deps` Bump github.com/microsoft/go-mssqldb from 1.8.2 to 1.9.2\n- [#17261](https://github.com/influxdata/telegraf/pull/17261) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.4 to 2.11.5\n- [#17266](https://github.com/influxdata/telegraf/pull/17266) `deps` Bump github.com/peterbourgon/unixtransport from 0.0.5 to 0.0.6\n- [#17229](https://github.com/influxdata/telegraf/pull/17229) `deps` Bump github.com/prometheus/common from 0.64.0 to 0.65.0\n- [#17267](https://github.com/influxdata/telegraf/pull/17267) `deps` Bump github.com/redis/go-redis/v9 from 9.10.0 to 9.11.0\n- [#17273](https://github.com/influxdata/telegraf/pull/17273) `deps` Bump go.opentelemetry.io/collector/pdata from 1.34.0 to 1.35.0\n- [#17219](https://github.com/influxdata/telegraf/pull/17219) `deps` Bump google.golang.org/api from 0.237.0 to 0.238.0\n- [#17263](https://github.com/influxdata/telegraf/pull/17263) `deps` Bump google.golang.org/api from 0.238.0 to 0.239.0\n- [#17218](https://github.com/influxdata/telegraf/pull/17218) `deps` Bump k8s.io/api from 0.33.1 to 0.33.2\n- [#17228](https://github.com/influxdata/telegraf/pull/17228) `deps` Bump k8s.io/client-go from 0.33.1 to 0.33.2\n\n## v1.35.1 [2025-06-23]\n\n### Bugfixes\n\n- [#17178](https://github.com/influxdata/telegraf/pull/17178) `inputs.procstat` Fix user filter conditional logic\n- [#17210](https://github.com/influxdata/telegraf/pull/17210) `processors.strings` Add explicit TOML tags on struct fields\n\n### Dependency Updates\n\n- [#17194](https://github.com/influxdata/telegraf/pull/17194) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.10.0 to 1.10.1\n- [#17189](https://github.com/influxdata/telegraf/pull/17189) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.36.0 to 2.37.0\n- [#17186](https://github.com/influxdata/telegraf/pull/17186) `deps` Bump github.com/SAP/go-hdb from 1.13.6 to 1.13.7\n- [#17188](https://github.com/influxdata/telegraf/pull/17188) `deps` Bump github.com/alitto/pond/v2 from 2.3.2 to 2.3.4\n- [#17180](https://github.com/influxdata/telegraf/pull/17180) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.68 to 1.17.69\n- [#17185](https://github.com/influxdata/telegraf/pull/17185) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.45.1 to 1.45.2\n- [#17187](https://github.com/influxdata/telegraf/pull/17187) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.50.1 to 1.50.2\n- [#17183](https://github.com/influxdata/telegraf/pull/17183) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.43.2 to 1.43.3\n- [#17182](https://github.com/influxdata/telegraf/pull/17182) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.225.0 to 1.225.1\n- [#17190](https://github.com/influxdata/telegraf/pull/17190) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.35.1 to 1.35.2\n- [#17193](https://github.com/influxdata/telegraf/pull/17193) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.31.0 to 1.31.1\n- [#17195](https://github.com/influxdata/telegraf/pull/17195) `deps` Bump github.com/aws/smithy-go from 1.22.3 to 1.22.4\n- [#17196](https://github.com/influxdata/telegraf/pull/17196) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.16.0 to 2.16.1\n- [#17212](https://github.com/influxdata/telegraf/pull/17212) `deps` Bump github.com/go-chi/chi/v5 from 5.2.1 to 5.2.2\n- [#17191](https://github.com/influxdata/telegraf/pull/17191) `deps` Bump github.com/go-sql-driver/mysql from 1.9.2 to 1.9.3\n- [#17192](https://github.com/influxdata/telegraf/pull/17192) `deps` Bump github.com/peterbourgon/unixtransport from 0.0.4 to 0.0.5\n- [#17181](https://github.com/influxdata/telegraf/pull/17181) `deps` Bump github.com/redis/go-redis/v9 from 9.9.0 to 9.10.0\n- [#17197](https://github.com/influxdata/telegraf/pull/17197) `deps` Bump github.com/urfave/cli/v2 from 2.27.6 to 2.27.7\n- [#17198](https://github.com/influxdata/telegraf/pull/17198) `deps` Bump go.opentelemetry.io/collector/pdata from 1.33.0 to 1.34.0\n- [#17184](https://github.com/influxdata/telegraf/pull/17184) `deps` Bump google.golang.org/api from 0.236.0 to 0.237.0\n\n## v1.35.0 [2025-06-16]\n\n### Deprecation Removals\n\nThis release removes the following deprecated plugin aliases:\n\n- `inputs.cisco_telemetry_gnmi` in [#17101](https://github.com/influxdata/telegraf/pull/17101)\n- `inputs.http_listener` in [#17102](https://github.com/influxdata/telegraf/pull/17102)\n- `inputs.KNXListener` in [#17168](https://github.com/influxdata/telegraf/pull/17168)\n- `inputs.logparser` in [#17170](https://github.com/influxdata/telegraf/pull/17170)\n\nFurthermore, the following deprecated plugin options are removed:\n\n- `ssl_ca`, `ssl_cert` and `ssl_key` of common TLS settings in [#17119](https://github.com/influxdata/telegraf/pull/17119)\n- `url` of `inputs.amqp_consumer` in [#17149](https://github.com/influxdata/telegraf/pull/17149)\n- `namespace` of `inputs.cloudwatch` in [#17123](https://github.com/influxdata/telegraf/pull/17123)\n- `datacentre` of `inputs.consul` in [#17150](https://github.com/influxdata/telegraf/pull/17150)\n- `container_names`, `perdevice` and `total` of `inputs.docker` in [#17148](https://github.com/influxdata/telegraf/pull/17148)\n- `http_timeout` of `inputs.elasticsearch` in [#17124](https://github.com/influxdata/telegraf/pull/17124)\n- `directory` of `inputs.filecount` in [#17152](https://github.com/influxdata/telegraf/pull/17152)\n- `guess_path_tag` and `enable_tls` of `inputs.gnmi` in [#17151](https://github.com/influxdata/telegraf/pull/17151)\n- `bearer_token` of `inputs.http` in [#17153](https://github.com/influxdata/telegraf/pull/17153)\n- `path` and `port` of `inputs.http_listener_v2` in [#17158](https://github.com/influxdata/telegraf/pull/17158)\n- `address` of `inputs.http_response` in [#17157](https://github.com/influxdata/telegraf/pull/17157)\n- `object_type` of `inputs.icinga2` in [#17163](https://github.com/influxdata/telegraf/pull/17163)\n- `max_line_size` of `inputs.influxdb_listener` in [#17162](https://github.com/influxdata/telegraf/pull/17162)\n- `enable_file_download` of `inputs.internet_speed` in [#17165](https://github.com/influxdata/telegraf/pull/17165)\n- `bearer_token_string` of `inputs.kube_inventory` in [#17110](https://github.com/influxdata/telegraf/pull/17110)\n- `bearer_token_string` of `inputs.kubernetes` in [#17109](https://github.com/influxdata/telegraf/pull/17109)\n- `server` of `inputs.nsq_consumer` in [#17166](https://github.com/influxdata/telegraf/pull/17166)\n- `dns_lookup` of `inputs.ntpq` in [#17159](https://github.com/influxdata/telegraf/pull/17159)\n- `ssl` of `inputs.openldap` in [#17103](https://github.com/influxdata/telegraf/pull/17103)\n- `name` and `queues` of `inputs.rabbitmq` in [#17105](https://github.com/influxdata/telegraf/pull/17105)\n- `path` of `inputs.smart` in [#17113](https://github.com/influxdata/telegraf/pull/17113)\n- `azuredb` and `query_version` of `inputs.sqlserver` in [#17112](https://github.com/influxdata/telegraf/pull/17112)\n- `parse_data_dog_tags` and `udp_packet_size` of `inputs.statsd` in [#17171](https://github.com/influxdata/telegraf/pull/17171)\n- `force_discover_on_init` of `inputs.vsphere` in [#17169](https://github.com/influxdata/telegraf/pull/17169)\n- `database`, `precision`, `retention_policy` and `url` of `outputs.amqp` in [#16950](https://github.com/influxdata/telegraf/pull/16950)\n- `precision` of `outputs.influxdb` in [#17160](https://github.com/influxdata/telegraf/pull/17160)\n- `partitionkey` and `use_random_partitionkey` of `outputs.kinesis` in [#17167](https://github.com/influxdata/telegraf/pull/17167)\n- `source_tag` of `outputs.librato` in [#17174](https://github.com/influxdata/telegraf/pull/17174)\n- `batch` and `topic_prefix` of `outputs.mqtt` in [#17176](https://github.com/influxdata/telegraf/pull/17176)\n- `trace` of `outputs.remotefile` in [#17173](https://github.com/influxdata/telegraf/pull/17173)\n- `host`, `port` and `string_to_number` of `outputs.wavefront` in [#17172](https://github.com/influxdata/telegraf/pull/17172)\n\nReplacements do exist, so please migrate your configuration in case you are\nstill using one of those plugins or options. The `telegraf config migrate`\ncommand might be able to assist with the procedure.\n\n### New Plugins\n\n- [#16390](https://github.com/influxdata/telegraf/pull/16390) `inputs.fritzbox` Add plugin\n- [#16780](https://github.com/influxdata/telegraf/pull/16780) `inputs.mavlink` Add plugin\n- [#16509](https://github.com/influxdata/telegraf/pull/16509) `inputs.whois` Add plugin\n- [#16211](https://github.com/influxdata/telegraf/pull/16211) `outputs.inlong` Add plugin\n- [#16827](https://github.com/influxdata/telegraf/pull/16827) `outputs.microsoft_fabric` Add plugin\n- [#16629](https://github.com/influxdata/telegraf/pull/16629) `processors.cumulative_sum` Add plugin\n\n### Features\n\n- [#17048](https://github.com/influxdata/telegraf/pull/17048) `agent` Add debounce for watch events\n- [#16524](https://github.com/influxdata/telegraf/pull/16524) `common.kafka` Add AWS-MSK-IAM SASL authentication\n- [#16867](https://github.com/influxdata/telegraf/pull/16867) `common.ratelimiter` Implement means to reserve memory for concurrent use\n- [#16148](https://github.com/influxdata/telegraf/pull/16148) `common.shim` Add batch to shim\n- [#17121](https://github.com/influxdata/telegraf/pull/17121) `inputs.amqp_consumer` Allow string values in queue arguments\n- [#17051](https://github.com/influxdata/telegraf/pull/17051) `inputs.opcua` Allow forcing reconnection on every gather cycle\n- [#16532](https://github.com/influxdata/telegraf/pull/16532) `inputs.opcua_listener` Allow to subscribe to OPCUA events\n- [#16882](https://github.com/influxdata/telegraf/pull/16882) `inputs.prometheus` Add HTTP service discovery support\n- [#16999](https://github.com/influxdata/telegraf/pull/16999) `inputs.s7comm` Add support for LREAL and LINT data types\n- [#16452](https://github.com/influxdata/telegraf/pull/16452) `inputs.unbound` Collect histogram statistics\n- [#16700](https://github.com/influxdata/telegraf/pull/16700) `inputs.whois` Support IDN domains\n- [#17119](https://github.com/influxdata/telegraf/pull/17119) `migrations` Add migration for common.tls ssl options\n- [#17101](https://github.com/influxdata/telegraf/pull/17101) `migrations` Add migration for inputs.cisco_telemetry_gnmi\n- [#17123](https://github.com/influxdata/telegraf/pull/17123) `migrations` Add migration for inputs.cloudwatch\n- [#17148](https://github.com/influxdata/telegraf/pull/17148) `migrations` Add migration for inputs.docker\n- [#17124](https://github.com/influxdata/telegraf/pull/17124) `migrations` Add migration for inputs.elasticsearch\n- [#17102](https://github.com/influxdata/telegraf/pull/17102) `migrations` Add migration for inputs.http_listener\n- [#17162](https://github.com/influxdata/telegraf/pull/17162) `migrations` Add migration for inputs.influxdb_listener\n- [#17110](https://github.com/influxdata/telegraf/pull/17110) `migrations` Add migration for inputs.kube_inventory\n- [#17109](https://github.com/influxdata/telegraf/pull/17109) `migrations` Add migration for inputs.kubernetes\n- [#17103](https://github.com/influxdata/telegraf/pull/17103) `migrations` Add migration for inputs.openldap\n- [#17105](https://github.com/influxdata/telegraf/pull/17105) `migrations` Add migration for inputs.rabbitmq\n- [#17113](https://github.com/influxdata/telegraf/pull/17113) `migrations` Add migration for inputs.smart\n- [#17112](https://github.com/influxdata/telegraf/pull/17112) `migrations` Add migration for inputs.sqlserver\n- [#16950](https://github.com/influxdata/telegraf/pull/16950) `migrations` Add migration for outputs.amqp\n- [#17160](https://github.com/influxdata/telegraf/pull/17160) `migrations` Add migration for outputs.influxdb\n- [#17149](https://github.com/influxdata/telegraf/pull/17149) `migrations` Add migration for inputs.amqp_consumer\n- [#17150](https://github.com/influxdata/telegraf/pull/17150) `migrations` Add migration for inputs.consul\n- [#17152](https://github.com/influxdata/telegraf/pull/17152) `migrations` Add migration for inputs.filecount\n- [#17151](https://github.com/influxdata/telegraf/pull/17151) `migrations` Add migration for inputs.gnmi\n- [#17153](https://github.com/influxdata/telegraf/pull/17153) `migrations` Add migration for inputs.http\n- [#17158](https://github.com/influxdata/telegraf/pull/17158) `migrations` Add migration for inputs.http_listener_v2\n- [#17157](https://github.com/influxdata/telegraf/pull/17157) `migrations` Add migration for inputs.http_response\n- [#17163](https://github.com/influxdata/telegraf/pull/17163) `migrations` Add migration for inputs.icinga2\n- [#17165](https://github.com/influxdata/telegraf/pull/17165) `migrations` Add migration for inputs.internet_speed\n- [#17166](https://github.com/influxdata/telegraf/pull/17166) `migrations` Add migration for inputs.nsq_consumer\n- [#17159](https://github.com/influxdata/telegraf/pull/17159) `migrations` Add migration for inputs.ntpq\n- [#17171](https://github.com/influxdata/telegraf/pull/17171) `migrations` Add migration for inputs.statsd\n- [#17169](https://github.com/influxdata/telegraf/pull/17169) `migrations` Add migration for inputs.vsphere\n- [#17167](https://github.com/influxdata/telegraf/pull/17167) `migrations` Add migration for outputs.kinesis\n- [#17174](https://github.com/influxdata/telegraf/pull/17174) `migrations` Add migration for outputs.librato\n- [#17176](https://github.com/influxdata/telegraf/pull/17176) `migrations` Add migration for outputs.mqtt\n- [#17173](https://github.com/influxdata/telegraf/pull/17173) `migrations` Add migration for outputs.remotefile\n- [#17172](https://github.com/influxdata/telegraf/pull/17172) `migrations` Add migration for outputs.wavefront\n- [#17168](https://github.com/influxdata/telegraf/pull/17168) `migrations` Add migration for inputs.KNXListener\n- [#17170](https://github.com/influxdata/telegraf/pull/17170) `migrations` Add migration for inputs.logparser\n- [#16646](https://github.com/influxdata/telegraf/pull/16646) `outputs.health` Add max time between metrics check\n- [#16597](https://github.com/influxdata/telegraf/pull/16597) `outputs.http` Include body sample in non-retryable error logs\n- [#16741](https://github.com/influxdata/telegraf/pull/16741) `outputs.influxdb_v2` Implement concurrent writes\n- [#16746](https://github.com/influxdata/telegraf/pull/16746) `outputs.influxdb_v2` Support secrets in http_headers values\n- [#16582](https://github.com/influxdata/telegraf/pull/16582) `outputs.nats` Allow asynchronous publishing for Jetstream\n- [#16544](https://github.com/influxdata/telegraf/pull/16544) `outputs.sql` Add option to automate table schema updates\n- [#16678](https://github.com/influxdata/telegraf/pull/16678) `outputs.sql` Support secret for dsn\n- [#16583](https://github.com/influxdata/telegraf/pull/16583) `outputs.stackdriver` Ensure quota is charged to configured project\n- [#16717](https://github.com/influxdata/telegraf/pull/16717) `processors.defaults` Add support for specifying default tags\n- [#16701](https://github.com/influxdata/telegraf/pull/16701) `processors.enum` Add multiple tag mapping\n- [#16030](https://github.com/influxdata/telegraf/pull/16030) `processors.enum` Allow mapping to be applied to multiple fields\n- [#16494](https://github.com/influxdata/telegraf/pull/16494) `serializer.prometheusremotewrite` Allow sending native histograms\n\n### Bugfixes\n\n- [#17044](https://github.com/influxdata/telegraf/pull/17044) `inputs.opcua` Fix integration test\n- [#16986](https://github.com/influxdata/telegraf/pull/16986) `inputs.procstat` Resolve remote usernames on Posix systems\n- [#16699](https://github.com/influxdata/telegraf/pull/16699) `inputs.win_wmi` Free resources to avoid leaks\n- [#17118](https://github.com/influxdata/telegraf/pull/17118) `migrations` Update table content for general plugin migrations\n\n### Dependency Updates\n\n- [#17089](https://github.com/influxdata/telegraf/pull/17089) `deps` Bump cloud.google.com/go/bigquery from 1.68.0 to 1.69.0\n- [#17026](https://github.com/influxdata/telegraf/pull/17026) `deps` Bump cloud.google.com/go/storage from 1.53.0 to 1.54.0\n- [#17095](https://github.com/influxdata/telegraf/pull/17095) `deps` Bump cloud.google.com/go/storage from 1.54.0 to 1.55.0\n- [#17034](https://github.com/influxdata/telegraf/pull/17034) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.9.0 to 1.10.0\n- [#17065](https://github.com/influxdata/telegraf/pull/17065) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.34.0 to 2.35.0\n- [#17145](https://github.com/influxdata/telegraf/pull/17145) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.35.0 to 2.36.0\n- [#17062](https://github.com/influxdata/telegraf/pull/17062) `deps` Bump github.com/IBM/nzgo/v12 from 12.0.9 to 12.0.10\n- [#17083](https://github.com/influxdata/telegraf/pull/17083) `deps` Bump github.com/IBM/sarama from 1.45.1 to 1.45.2\n- [#17040](https://github.com/influxdata/telegraf/pull/17040) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.0 to 1.0.1\n- [#17060](https://github.com/influxdata/telegraf/pull/17060) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.1 to 1.0.2\n- [#17127](https://github.com/influxdata/telegraf/pull/17127) `deps` Bump github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang from 1.0.2 to 1.0.3\n- [#17061](https://github.com/influxdata/telegraf/pull/17061) `deps` Bump github.com/apache/thrift from 0.21.0 to 0.22.0\n- [#16954](https://github.com/influxdata/telegraf/pull/16954) `deps` Bump github.com/aws/aws-msk-iam-sasl-signer-go from 1.0.1 to 1.0.3\n- [#17041](https://github.com/influxdata/telegraf/pull/17041) `deps` Bump github.com/aws/aws-msk-iam-sasl-signer-go from 1.0.3 to 1.0.4\n- [#17128](https://github.com/influxdata/telegraf/pull/17128) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.29.14 to 1.29.15\n- [#17129](https://github.com/influxdata/telegraf/pull/17129) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.67 to 1.17.68\n- [#17057](https://github.com/influxdata/telegraf/pull/17057) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.44.3 to 1.45.0\n- [#17132](https://github.com/influxdata/telegraf/pull/17132) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.45.0 to 1.45.1\n- [#17029](https://github.com/influxdata/telegraf/pull/17029) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.49.0 to 1.50.0\n- [#17131](https://github.com/influxdata/telegraf/pull/17131) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.50.0 to 1.50.1\n- [#17143](https://github.com/influxdata/telegraf/pull/17143) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.43.1 to 1.43.2\n- [#17037](https://github.com/influxdata/telegraf/pull/17037) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.218.0 to 1.219.0\n- [#17067](https://github.com/influxdata/telegraf/pull/17067) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.220.0 to 1.222.0\n- [#17093](https://github.com/influxdata/telegraf/pull/17093) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.222.0 to 1.224.0\n- [#17136](https://github.com/influxdata/telegraf/pull/17136) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.224.0 to 1.225.0\n- [#17139](https://github.com/influxdata/telegraf/pull/17139) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.35.0 to 1.35.1\n- [#16996](https://github.com/influxdata/telegraf/pull/16996) `deps` Bump github.com/bluenviron/gomavlib/v3 from 3.1.0 to 3.2.1\n- [#16987](https://github.com/influxdata/telegraf/pull/16987) `deps` Bump github.com/creack/goselect from 0.1.2 to 0.1.3\n- [#17097](https://github.com/influxdata/telegraf/pull/17097) `deps` Bump github.com/docker/docker from 28.1.1+incompatible to 28.2.2+incompatible\n- [#17133](https://github.com/influxdata/telegraf/pull/17133) `deps` Bump github.com/gosnmp/gosnmp from 1.40.0 to 1.41.0\n- [#17126](https://github.com/influxdata/telegraf/pull/17126) `deps` Bump github.com/linkedin/goavro/v2 from 2.13.1 to 2.14.0\n- [#17087](https://github.com/influxdata/telegraf/pull/17087) `deps` Bump github.com/lxc/incus/v6 from 6.12.0 to 6.13.0\n- [#17085](https://github.com/influxdata/telegraf/pull/17085) `deps` Bump github.com/microsoft/go-mssqldb from 1.8.1 to 1.8.2\n- [#17064](https://github.com/influxdata/telegraf/pull/17064) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.3 to 2.11.4\n- [#17140](https://github.com/influxdata/telegraf/pull/17140) `deps` Bump github.com/nats-io/nats.go from 1.42.0 to 1.43.0\n- [#17134](https://github.com/influxdata/telegraf/pull/17134) `deps` Bump github.com/netsampler/goflow2/v2 from 2.2.2 to 2.2.3\n- [#17028](https://github.com/influxdata/telegraf/pull/17028) `deps` Bump github.com/prometheus/common from 0.63.0 to 0.64.0\n- [#17066](https://github.com/influxdata/telegraf/pull/17066) `deps` Bump github.com/rclone/rclone from 1.69.2 to 1.69.3\n- [#17096](https://github.com/influxdata/telegraf/pull/17096) `deps` Bump github.com/redis/go-redis/v9 from 9.8.0 to 9.9.0\n- [#17088](https://github.com/influxdata/telegraf/pull/17088) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.4 to 4.25.5\n- [#17135](https://github.com/influxdata/telegraf/pull/17135) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.24 to 2.9.0\n- [#17094](https://github.com/influxdata/telegraf/pull/17094) `deps` Bump github.com/snowflakedb/gosnowflake from 1.14.0 to 1.14.1\n- [#17035](https://github.com/influxdata/telegraf/pull/17035) `deps` Bump github.com/tinylib/msgp from 1.2.5 to 1.3.0\n- [#17054](https://github.com/influxdata/telegraf/pull/17054) `deps` Bump github.com/vmware/govmomi from 0.50.0 to 0.51.0\n- [#17039](https://github.com/influxdata/telegraf/pull/17039) `deps` Bump github.com/yuin/goldmark from 1.7.11 to 1.7.12\n- [#17130](https://github.com/influxdata/telegraf/pull/17130) `deps` Bump go.mongodb.org/mongo-driver from 1.17.3 to 1.17.4\n- [#17056](https://github.com/influxdata/telegraf/pull/17056) `deps` Bump go.opentelemetry.io/collector/pdata from 1.31.0 to 1.33.0\n- [#17058](https://github.com/influxdata/telegraf/pull/17058) `deps` Bump go.step.sm/crypto from 0.63.0 to 0.64.0\n- [#17141](https://github.com/influxdata/telegraf/pull/17141) `deps` Bump golang.org/x/crypto from 0.38.0 to 0.39.0\n- [#17144](https://github.com/influxdata/telegraf/pull/17144) `deps` Bump golang.org/x/mod from 0.24.0 to 0.25.0\n- [#17033](https://github.com/influxdata/telegraf/pull/17033) `deps` Bump google.golang.org/api from 0.232.0 to 0.233.0\n- [#17055](https://github.com/influxdata/telegraf/pull/17055) `deps` Bump google.golang.org/api from 0.233.0 to 0.234.0\n- [#17086](https://github.com/influxdata/telegraf/pull/17086) `deps` Bump google.golang.org/api from 0.234.0 to 0.235.0\n- [#17036](https://github.com/influxdata/telegraf/pull/17036) `deps` Bump google.golang.org/grpc from 1.72.0 to 1.72.1\n- [#17059](https://github.com/influxdata/telegraf/pull/17059) `deps` Bump google.golang.org/grpc from 1.72.1 to 1.72.2\n- [#17137](https://github.com/influxdata/telegraf/pull/17137) `deps` Bump google.golang.org/grpc from 1.72.2 to 1.73.0\n- [#17031](https://github.com/influxdata/telegraf/pull/17031) `deps` Bump k8s.io/api from 0.33.0 to 0.33.1\n- [#17038](https://github.com/influxdata/telegraf/pull/17038) `deps` Bump k8s.io/apimachinery from 0.33.0 to 0.33.1\n- [#17030](https://github.com/influxdata/telegraf/pull/17030) `deps` Bump k8s.io/client-go from 0.33.0 to 0.33.1\n- [#17025](https://github.com/influxdata/telegraf/pull/17025) `deps` Bump super-linter/super-linter from 7.3.0 to 7.4.0\n\n## v1.34.4 [2025-05-19]\n\n### Bugfixes\n\n- [#17009](https://github.com/influxdata/telegraf/pull/17009) `inputs.cloudwatch` Restore filtering to match all dimensions\n- [#16978](https://github.com/influxdata/telegraf/pull/16978) `inputs.nfsclient` Handle errors during mountpoint filtering\n- [#17021](https://github.com/influxdata/telegraf/pull/17021) `inputs.opcua` Fix type mismatch in unit test\n- [#16854](https://github.com/influxdata/telegraf/pull/16854) `inputs.opcua` Handle session invalidation between gather cycles\n- [#16879](https://github.com/influxdata/telegraf/pull/16879) `inputs.tail` Prevent leaking file descriptors\n- [#16815](https://github.com/influxdata/telegraf/pull/16815) `inputs.win_eventlog` Handle large events to avoid they get dropped silently\n- [#16878](https://github.com/influxdata/telegraf/pull/16878) `parsers.json_v2` Handle measurements with multiple objects correctly\n\n### Dependency Updates\n\n- [#16991](https://github.com/influxdata/telegraf/pull/16991) `deps` Bump cloud.google.com/go/bigquery from 1.67.0 to 1.68.0\n- [#16963](https://github.com/influxdata/telegraf/pull/16963) `deps` Bump cloud.google.com/go/storage from 1.52.0 to 1.53.0\n- [#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\n- [#16989](https://github.com/influxdata/telegraf/pull/16989) `deps` Bump github.com/SAP/go-hdb from 1.13.5 to 1.13.6\n- [#16998](https://github.com/influxdata/telegraf/pull/16998) `deps` Bump github.com/apache/arrow-go/v18 from 18.2.0 to 18.3.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#17013](https://github.com/influxdata/telegraf/pull/17013) `deps` Bump github.com/ebitengine/purego from 0.8.2 to 0.8.3\n- [#16972](https://github.com/influxdata/telegraf/pull/16972) `deps` Bump github.com/hashicorp/consul/api from 1.32.0 to 1.32.1\n- [#16992](https://github.com/influxdata/telegraf/pull/16992) `deps` Bump github.com/microsoft/go-mssqldb from 1.8.0 to 1.8.1\n- [#16990](https://github.com/influxdata/telegraf/pull/16990) `deps` Bump github.com/miekg/dns from 1.1.65 to 1.1.66\n- [#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\n- [#16967](https://github.com/influxdata/telegraf/pull/16967) `deps` Bump github.com/nats-io/nats.go from 1.41.2 to 1.42.0\n- [#16964](https://github.com/influxdata/telegraf/pull/16964) `deps` Bump github.com/rclone/rclone from 1.69.1 to 1.69.2\n- [#16973](https://github.com/influxdata/telegraf/pull/16973) `deps` Bump github.com/redis/go-redis/v9 from 9.7.3 to 9.8.0\n- [#16962](https://github.com/influxdata/telegraf/pull/16962) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.3 to 4.25.4\n- [#16969](https://github.com/influxdata/telegraf/pull/16969) `deps` Bump github.com/snowflakedb/gosnowflake from 1.13.3 to 1.14.0\n- [#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\n- [#16958](https://github.com/influxdata/telegraf/pull/16958) `deps` Bump go.step.sm/crypto from 0.62.0 to 0.63.0\n- [#16960](https://github.com/influxdata/telegraf/pull/16960) `deps` Bump golang.org/x/crypto from 0.37.0 to 0.38.0\n- [#16966](https://github.com/influxdata/telegraf/pull/16966) `deps` Bump golang.org/x/net from 0.39.0 to 0.40.0\n- [#16957](https://github.com/influxdata/telegraf/pull/16957) `deps` Bump google.golang.org/api from 0.230.0 to 0.231.0\n- [#16853](https://github.com/influxdata/telegraf/pull/16853) `deps` Switch to maintained azure testcontainer module\n\n## v1.34.3 [2025-05-05]\n\n### Bugfixes\n\n- [#16697](https://github.com/influxdata/telegraf/pull/16697) `agent` Correctly truncate the disk buffer\n- [#16868](https://github.com/influxdata/telegraf/pull/16868) `common.ratelimiter` Only grow the buffer but never shrink\n- [#16812](https://github.com/influxdata/telegraf/pull/16812) `inputs.cloudwatch` Handle metric includes/excludes correctly to prevent panic\n- [#16911](https://github.com/influxdata/telegraf/pull/16911) `inputs.lustre2` Skip empty files\n- [#16594](https://github.com/influxdata/telegraf/pull/16594) `inputs.opcua` Handle node array values\n- [#16782](https://github.com/influxdata/telegraf/pull/16782) `inputs.win_wmi` Replace hard-coded class-name with correct config setting\n- [#16781](https://github.com/influxdata/telegraf/pull/16781) `inputs.win_wmi` Restrict threading model to APARTMENTTHREADED\n- [#16857](https://github.com/influxdata/telegraf/pull/16857) `outputs.quix` Allow empty certificate for new cloud managed instances\n\n### Dependency Updates\n\n- [#16804](https://github.com/influxdata/telegraf/pull/16804) `deps` Bump cloud.google.com/go/bigquery from 1.66.2 to 1.67.0\n- [#16835](https://github.com/influxdata/telegraf/pull/16835) `deps` Bump cloud.google.com/go/monitoring from 1.24.0 to 1.24.2\n- [#16785](https://github.com/influxdata/telegraf/pull/16785) `deps` Bump cloud.google.com/go/pubsub from 1.48.0 to 1.49.0\n- [#16897](https://github.com/influxdata/telegraf/pull/16897) `deps` Bump cloud.google.com/go/storage from 1.51.0 to 1.52.0\n- [#16840](https://github.com/influxdata/telegraf/pull/16840) `deps` Bump github.com/BurntSushi/toml from 1.4.0 to 1.5.0\n- [#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\n- [#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\n- [#16789](https://github.com/influxdata/telegraf/pull/16789) `deps` Bump github.com/antchfx/xpath from 1.3.3 to 1.3.4\n- [#16807](https://github.com/influxdata/telegraf/pull/16807) `deps` Bump github.com/apache/arrow-go/v18 from 18.1.0 to 18.2.0\n- [#16844](https://github.com/influxdata/telegraf/pull/16844) `deps` Bump github.com/apache/iotdb-client-go from 1.3.3 to 1.3.4\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#16802](https://github.com/influxdata/telegraf/pull/16802) `deps` Bump github.com/clarify/clarify-go from 0.3.1 to 0.4.0\n- [#16849](https://github.com/influxdata/telegraf/pull/16849) `deps` Bump github.com/docker/docker from 28.0.4+incompatible to 28.1.1+incompatible\n- [#16830](https://github.com/influxdata/telegraf/pull/16830) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.10 to 3.4.11\n- [#16801](https://github.com/influxdata/telegraf/pull/16801) `deps` Bump github.com/go-sql-driver/mysql from 1.8.1 to 1.9.2\n- [#16806](https://github.com/influxdata/telegraf/pull/16806) `deps` Bump github.com/gofrs/uuid/v5 from 5.3.0 to 5.3.2\n- [#16895](https://github.com/influxdata/telegraf/pull/16895) `deps` Bump github.com/google/cel-go from 0.24.1 to 0.25.0\n- [#16797](https://github.com/influxdata/telegraf/pull/16797) `deps` Bump github.com/gopcua/opcua from 0.7.1 to 0.7.4\n- [#16894](https://github.com/influxdata/telegraf/pull/16894) `deps` Bump github.com/gopcua/opcua from 0.7.4 to 0.8.0\n- [#16660](https://github.com/influxdata/telegraf/pull/16660) `deps` Bump github.com/gosmnp/gosnmp from 1.39.0 to 1.40.0\n- [#16902](https://github.com/influxdata/telegraf/pull/16902) `deps` Bump github.com/gosnmp/gosnmp from 1.39.0 to 1.40.0\n- [#16841](https://github.com/influxdata/telegraf/pull/16841) `deps` Bump github.com/hashicorp/consul/api from 1.31.2 to 1.32.0\n- [#16891](https://github.com/influxdata/telegraf/pull/16891) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.6.5 to 6.6.7\n- [#16892](https://github.com/influxdata/telegraf/pull/16892) `deps` Bump github.com/lxc/incus/v6 from 6.11.0 to 6.12.0\n- [#16786](https://github.com/influxdata/telegraf/pull/16786) `deps` Bump github.com/microsoft/go-mssqldb from 1.7.2 to 1.8.0\n- [#16851](https://github.com/influxdata/telegraf/pull/16851) `deps` Bump github.com/miekg/dns from 1.1.64 to 1.1.65\n- [#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\n- [#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\n- [#16909](https://github.com/influxdata/telegraf/pull/16909) `deps` Bump github.com/nats-io/nats.go from 1.41.1 to 1.41.2\n- [#16790](https://github.com/influxdata/telegraf/pull/16790) `deps` Bump github.com/openconfig/gnmi from 0.11.0 to 0.14.1\n- [#16799](https://github.com/influxdata/telegraf/pull/16799) `deps` Bump github.com/openconfig/goyang from 1.6.0 to 1.6.2\n- [#16848](https://github.com/influxdata/telegraf/pull/16848) `deps` Bump github.com/prometheus-community/pro-bing from 0.4.1 to 0.7.0\n- [#16795](https://github.com/influxdata/telegraf/pull/16795) `deps` Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0\n- [#16845](https://github.com/influxdata/telegraf/pull/16845) `deps` Bump github.com/prometheus/client_model from 0.6.1 to 0.6.2\n- [#16901](https://github.com/influxdata/telegraf/pull/16901) `deps` Bump github.com/prometheus/procfs from 0.16.0 to 0.16.1\n- [#16792](https://github.com/influxdata/telegraf/pull/16792) `deps` Bump github.com/safchain/ethtool from 0.3.0 to 0.5.10\n- [#16791](https://github.com/influxdata/telegraf/pull/16791) `deps` Bump github.com/seancfoley/ipaddress-go from 1.7.0 to 1.7.1\n- [#16794](https://github.com/influxdata/telegraf/pull/16794) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.1 to 4.25.3\n- [#16828](https://github.com/influxdata/telegraf/pull/16828) `deps` Bump github.com/snowflakedb/gosnowflake from 1.11.2 to 1.13.1\n- [#16904](https://github.com/influxdata/telegraf/pull/16904) `deps` Bump github.com/snowflakedb/gosnowflake from 1.13.1 to 1.13.3\n- [#16787](https://github.com/influxdata/telegraf/pull/16787) `deps` Bump github.com/srebhan/cborquery from 1.0.3 to 1.0.4\n- [#16837](https://github.com/influxdata/telegraf/pull/16837) `deps` Bump github.com/srebhan/protobufquery from 1.0.1 to 1.0.4\n- [#16893](https://github.com/influxdata/telegraf/pull/16893) `deps` Bump github.com/testcontainers/testcontainers-go from 0.36.0 to 0.37.0\n- [#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\n- [#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\n- [#16850](https://github.com/influxdata/telegraf/pull/16850) `deps` Bump github.com/vmware/govmomi from 0.49.0 to 0.50.0\n- [#16784](https://github.com/influxdata/telegraf/pull/16784) `deps` Bump github.com/yuin/goldmark from 1.7.8 to 1.7.9\n- [#16896](https://github.com/influxdata/telegraf/pull/16896) `deps` Bump github.com/yuin/goldmark from 1.7.9 to 1.7.11\n- [#16832](https://github.com/influxdata/telegraf/pull/16832) `deps` Bump go.mongodb.org/mongo-driver from 1.17.0 to 1.17.3\n- [#16800](https://github.com/influxdata/telegraf/pull/16800) `deps` Bump go.opentelemetry.io/collector/pdata from 1.29.0 to 1.30.0\n- [#16907](https://github.com/influxdata/telegraf/pull/16907) `deps` Bump go.opentelemetry.io/collector/pdata from 1.30.0 to 1.31.0\n- [#16831](https://github.com/influxdata/telegraf/pull/16831) `deps` Bump go.step.sm/crypto from 0.60.0 to 0.61.0\n- [#16886](https://github.com/influxdata/telegraf/pull/16886) `deps` Bump go.step.sm/crypto from 0.61.0 to 0.62.0\n- [#16816](https://github.com/influxdata/telegraf/pull/16816) `deps` Bump golangci-lint from v2.0.2 to v2.1.2\n- [#16852](https://github.com/influxdata/telegraf/pull/16852) `deps` Bump gonum.org/v1/gonum from 0.15.1 to 0.16.0\n- [#16805](https://github.com/influxdata/telegraf/pull/16805) `deps` Bump google.golang.org/api from 0.228.0 to 0.229.0\n- [#16898](https://github.com/influxdata/telegraf/pull/16898) `deps` Bump google.golang.org/api from 0.229.0 to 0.230.0\n- [#16834](https://github.com/influxdata/telegraf/pull/16834) `deps` Bump google.golang.org/grpc from 1.71.1 to 1.72.0\n- [#16889](https://github.com/influxdata/telegraf/pull/16889) `deps` Bump k8s.io/client-go from 0.32.3 to 0.33.0\n- [#16843](https://github.com/influxdata/telegraf/pull/16843) `deps` Bump modernc.org/sqlite from 1.36.2 to 1.37.0\n\n## v1.34.2 [2025-04-14]\n\n### Bugfixes\n\n- [#16375](https://github.com/influxdata/telegraf/pull/16375) `aggregators` Handle time drift when calculating aggregation windows\n\n### Dependency Updates\n\n- [#16689](https://github.com/influxdata/telegraf/pull/16689) `deps` Bump cloud.google.com/go/pubsub from 1.45.3 to 1.48.0\n- [#16769](https://github.com/influxdata/telegraf/pull/16769) `deps` Bump cloud.google.com/go/storage from 1.50.0 to 1.51.0\n- [#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\n- [#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\n- [#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\n- [#16777](https://github.com/influxdata/telegraf/pull/16777) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.30.3 to 2.34.0\n- [#16707](https://github.com/influxdata/telegraf/pull/16707) `deps` Bump github.com/IBM/sarama from v1.43.3 to v1.45.1\n- [#16739](https://github.com/influxdata/telegraf/pull/16739) `deps` Bump github.com/SAP/go-hdb from 1.9.10 to 1.13.5\n- [#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\n- [#16767](https://github.com/influxdata/telegraf/pull/16767) `deps` Bump github.com/antchfx/jsonquery from 1.3.3 to 1.3.6\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#16711](https://github.com/influxdata/telegraf/pull/16711) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.15.2 to 2.16.0\n- [#16687](https://github.com/influxdata/telegraf/pull/16687) `deps` Bump github.com/google/cel-go from 0.23.0 to 0.24.1\n- [#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\n- [#16738](https://github.com/influxdata/telegraf/pull/16738) `deps` Bump github.com/gorcon/rcon from 1.3.5 to 1.4.0\n- [#16737](https://github.com/influxdata/telegraf/pull/16737) `deps` Bump github.com/gosnmp/gosnmp from 1.38.0 to 1.39.0\n- [#16752](https://github.com/influxdata/telegraf/pull/16752) `deps` Bump github.com/lxc/incus/v6 from 6.9.0 to 6.11.0\n- [#16761](https://github.com/influxdata/telegraf/pull/16761) `deps` Bump github.com/nats-io/nats.go from 1.39.1 to 1.41.1\n- [#16753](https://github.com/influxdata/telegraf/pull/16753) `deps` Bump github.com/netsampler/goflow2/v2 from 2.2.1 to 2.2.2\n- [#16760](https://github.com/influxdata/telegraf/pull/16760) `deps` Bump github.com/p4lang/p4runtime from 1.4.0 to 1.4.1\n- [#16766](https://github.com/influxdata/telegraf/pull/16766) `deps` Bump github.com/prometheus/common from 0.62.0 to 0.63.0\n- [#16686](https://github.com/influxdata/telegraf/pull/16686) `deps` Bump github.com/rclone/rclone from 1.68.2 to 1.69.1\n- [#16770](https://github.com/influxdata/telegraf/pull/16770) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.22 to 2.8.24\n- [#16709](https://github.com/influxdata/telegraf/pull/16709) `deps` Bump github.com/testcontainers/testcontainers-go from 0.35.0 to 0.36.0\n- [#16763](https://github.com/influxdata/telegraf/pull/16763) `deps` Bump github.com/tinylib/msgp from 1.2.0 to 1.2.5\n- [#16757](https://github.com/influxdata/telegraf/pull/16757) `deps` Bump github.com/urfave/cli/v2 from 2.27.2 to 2.27.6\n- [#16724](https://github.com/influxdata/telegraf/pull/16724) `deps` Bump github.com/vmware/govmomi from v0.45.1 to v0.49.0\n- [#16768](https://github.com/influxdata/telegraf/pull/16768) `deps` Bump go.opentelemetry.io/collector/pdata from 1.25.0 to 1.29.0\n- [#16765](https://github.com/influxdata/telegraf/pull/16765) `deps` Bump go.step.sm/crypto from 0.59.1 to 0.60.0\n- [#16756](https://github.com/influxdata/telegraf/pull/16756) `deps` Bump golang.org/x/crypto from 0.36.0 to 0.37.0\n- [#16683](https://github.com/influxdata/telegraf/pull/16683) `deps` Bump golangci-lint from v1.64.5 to v2.0.2\n- [#16759](https://github.com/influxdata/telegraf/pull/16759) `deps` Bump google.golang.org/api from 0.224.0 to 0.228.0\n- [#16755](https://github.com/influxdata/telegraf/pull/16755) `deps` Bump k8s.io/client-go from 0.32.1 to 0.32.3\n- [#16684](https://github.com/influxdata/telegraf/pull/16684) `deps` Bump tj-actions/changed-files from 46.0.1 to 46.0.3\n- [#16736](https://github.com/influxdata/telegraf/pull/16736) `deps` Bump tj-actions/changed-files from 46.0.3 to 46.0.4\n- [#16751](https://github.com/influxdata/telegraf/pull/16751) `deps` Bump tj-actions/changed-files from 46.0.4 to 46.0.5\n\n## v1.34.1 [2025-03-24]\n\n### Bugfixes\n\n- [#16638](https://github.com/influxdata/telegraf/pull/16638) `agent` Condense plugin source information table when multiple plugins in same file\n- [#16674](https://github.com/influxdata/telegraf/pull/16674) `inputs.tail` Do not seek on pipes\n- [#16643](https://github.com/influxdata/telegraf/pull/16643) `inputs.tail` Use correct initial_read_offset persistent offset naming in the code\n- [#16628](https://github.com/influxdata/telegraf/pull/16628) `outputs.influxdb_v2` Use dynamic token secret\n- [#16625](https://github.com/influxdata/telegraf/pull/16625) `outputs.sql` Allow to disable timestamp column\n- [#16682](https://github.com/influxdata/telegraf/pull/16682) `secrets` Make 'insufficient lockable memory' warning work on BSDs\n\n### Dependency Updates\n\n- [#16612](https://github.com/influxdata/telegraf/pull/16612) `deps` Bump github.com/PaesslerAG/gval from 1.2.2 to 1.2.4\n- [#16650](https://github.com/influxdata/telegraf/pull/16650) `deps` Bump github.com/aws/smithy-go from 1.22.2 to 1.22.3\n- [#16680](https://github.com/influxdata/telegraf/pull/16680) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2\n- [#16679](https://github.com/influxdata/telegraf/pull/16679) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2\n- [#16610](https://github.com/influxdata/telegraf/pull/16610) `deps` Bump github.com/golang/snappy from 0.0.4 to 1.0.0\n- [#16652](https://github.com/influxdata/telegraf/pull/16652) `deps` Bump github.com/hashicorp/consul/api from 1.29.2 to 1.31.2\n- [#16651](https://github.com/influxdata/telegraf/pull/16651) `deps` Bump github.com/leodido/go-syslog/v4 from 4.1.0 to 4.2.0\n- [#16613](https://github.com/influxdata/telegraf/pull/16613) `deps` Bump github.com/linkedin/goavro/v2 from 2.13.0 to 2.13.1\n- [#16671](https://github.com/influxdata/telegraf/pull/16671) `deps` Bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.3\n- [#16611](https://github.com/influxdata/telegraf/pull/16611) `deps` Bump go.step.sm/crypto from 0.54.0 to 0.59.1\n- [#16640](https://github.com/influxdata/telegraf/pull/16640) `deps` Bump golang.org/x/crypto from 0.35.0 to 0.36.0\n- [#16620](https://github.com/influxdata/telegraf/pull/16620) `deps` Bump golang.org/x/net from 0.35.0 to 0.36.0\n- [#16639](https://github.com/influxdata/telegraf/pull/16639) `deps` Bump golang.org/x/oauth2 from 0.26.0 to 0.28.0\n- [#16653](https://github.com/influxdata/telegraf/pull/16653) `deps` Bump k8s.io/api from 0.32.1 to 0.32.3\n- [#16659](https://github.com/influxdata/telegraf/pull/16659) `deps` Bump tj-actions/changed-files from v45 to v46.0.1\n\n## v1.34.0 [2025-03-10]\n\n### New Plugins\n\n- [#15988](https://github.com/influxdata/telegraf/pull/15988) `inputs.firehose` Add new plugin\n- [#16352](https://github.com/influxdata/telegraf/pull/16352) `inputs.huebridge` Add plugin\n- [#16392](https://github.com/influxdata/telegraf/pull/16392) `inputs.nsdp` Add plugin\n\n### Features\n\n- [#16333](https://github.com/influxdata/telegraf/pull/16333) `agent` Add support for input probing\n- [#16270](https://github.com/influxdata/telegraf/pull/16270) `agent` Print plugins source information\n- [#16474](https://github.com/influxdata/telegraf/pull/16474) `inputs.cgroup` Support more cgroup v2 formats\n- [#16337](https://github.com/influxdata/telegraf/pull/16337) `inputs.cloudwatch` Allow wildcards for namespaces\n- [#16292](https://github.com/influxdata/telegraf/pull/16292) `inputs.docker` Support swarm jobs\n- [#16501](https://github.com/influxdata/telegraf/pull/16501) `inputs.exec` Allow to get untruncated errors in debug mode\n- [#16480](https://github.com/influxdata/telegraf/pull/16480) `inputs.gnmi` Add support for `depth` extension\n- [#16336](https://github.com/influxdata/telegraf/pull/16336) `inputs.infiniband` Add support for RDMA counters\n- [#16124](https://github.com/influxdata/telegraf/pull/16124) `inputs.ipset` Add metric for number of entries and individual IPs\n- [#16579](https://github.com/influxdata/telegraf/pull/16579) `inputs.nvidia_smi` Add new power-draw fields for v12 scheme\n- [#16305](https://github.com/influxdata/telegraf/pull/16305) `inputs.nvidia_smi` Implement probing\n- [#16105](https://github.com/influxdata/telegraf/pull/16105) `inputs.procstat` Add child level tag\n- [#16066](https://github.com/influxdata/telegraf/pull/16066) `inputs.proxmox` Allow to add VM-id and status as tag\n- [#16287](https://github.com/influxdata/telegraf/pull/16287) `inputs.systemd_units` Add active_enter_timestamp_us field\n- [#16342](https://github.com/influxdata/telegraf/pull/16342) `inputs.tail` Add `initial_read_offset` config for controlling read behavior\n- [#16355](https://github.com/influxdata/telegraf/pull/16355) `inputs.webhooks` Add support for GitHub workflow events\n- [#16508](https://github.com/influxdata/telegraf/pull/16508) `inputs.x509_cert` Add support for JKS and PKCS#12 keystores\n- [#16491](https://github.com/influxdata/telegraf/pull/16491) `outputs.mqtt` Add sprig for topic name generator for homie layout\n- [#16570](https://github.com/influxdata/telegraf/pull/16570) `outputs.nats` Use Jetstream publisher when using Jetstream\n- [#16566](https://github.com/influxdata/telegraf/pull/16566) `outputs.prometheus_client` Allow adding custom headers\n- [#16272](https://github.com/influxdata/telegraf/pull/16272) `parsers.avro` Allow union fields to be specified as tags\n- [#16493](https://github.com/influxdata/telegraf/pull/16493) `parsers.prometheusremotewrite` Add dense metric version to better support histograms\n- [#16214](https://github.com/influxdata/telegraf/pull/16214) `processors.converter` Add support for base64 encoded IEEE floats\n- [#16497](https://github.com/influxdata/telegraf/pull/16497) `processors.template` Add sprig function for templates\n\n### Bugfixes\n\n- [#16542](https://github.com/influxdata/telegraf/pull/16542) `inputs.gnmi` Handle path elements without name but with keys correctly\n- [#16606](https://github.com/influxdata/telegraf/pull/16606) `inputs.huebridge` Cleanup and fix linter issues\n- [#16580](https://github.com/influxdata/telegraf/pull/16580) `inputs.net` Skip checks in containerized environments\n- [#16555](https://github.com/influxdata/telegraf/pull/16555) `outputs.opensearch` Use correct pipeline name while creating bulk-indexers\n- [#16557](https://github.com/influxdata/telegraf/pull/16557) `serializers.prometheus` Use legacy validation for metric name\n\n### Dependency Updates\n\n- [#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\n- [#16553](https://github.com/influxdata/telegraf/pull/16553) `deps` Bump github.com/Azure/go-autorest/autorest from 0.11.29 to 0.11.30\n- [#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\n- [#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\n- [#16574](https://github.com/influxdata/telegraf/pull/16574) `deps` Bump github.com/gopcua/opcua from 0.5.3 to 0.7.1\n- [#16551](https://github.com/influxdata/telegraf/pull/16551) `deps` Bump github.com/nats-io/nats.go from 1.39.0 to 1.39.1\n- [#16575](https://github.com/influxdata/telegraf/pull/16575) `deps` Bump github.com/tidwall/wal from 1.1.7 to 1.1.8\n- [#16578](https://github.com/influxdata/telegraf/pull/16578) `deps` Bump super-linter/super-linter from 7.2.1 to 7.3.0\n\n## v1.33.3 [2025-02-25]\n\n### Important Changes\n\n- PR [#16507](https://github.com/influxdata/telegraf/pull/16507) adds the\n  `enforce_first_namespace_as_origin` to the GNMI input plugin. This option\n  allows to disable mangling of the response `path` tag by _not_ using namespaces\n  as origin. It is highly recommended to disable the option.\n  However, disabling the behavior might change the `path` tag and\n  thus might break existing queries. Furthermore, the tag modification might\n  increase cardinality in your database.\n\n### Bugfixes\n\n- [#16546](https://github.com/influxdata/telegraf/pull/16546) `agent` Add authorization and user-agent when watching remote configs\n- [#16507](https://github.com/influxdata/telegraf/pull/16507) `inputs.gnmi` Allow to disable using first namespace as origin\n- [#16511](https://github.com/influxdata/telegraf/pull/16511) `inputs.proxmox` Allow search domain to be empty\n- [#16530](https://github.com/influxdata/telegraf/pull/16530) `internal` Fix plural acronyms in SnakeCase function\n- [#16539](https://github.com/influxdata/telegraf/pull/16539) `logging` Handle closing correctly and fix tests\n- [#16535](https://github.com/influxdata/telegraf/pull/16535) `processors.execd` Detect line-protocol parser correctly\n\n### Dependency Updates\n\n- [#16506](https://github.com/influxdata/telegraf/pull/16506) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.30.1 to 2.30.3\n- [#16502](https://github.com/influxdata/telegraf/pull/16502) `deps` Bump github.com/antchfx/xmlquery from 1.4.1 to 1.4.4\n- [#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\n- [#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\n- [#16522](https://github.com/influxdata/telegraf/pull/16522) `deps` Bump github.com/nats-io/nats.go from 1.37.0 to 1.39.0\n- [#16505](https://github.com/influxdata/telegraf/pull/16505) `deps` Bump github.com/srebhan/cborquery from 1.0.1 to 1.0.3\n- [#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\n- [#16521](https://github.com/influxdata/telegraf/pull/16521) `deps` Bump go.opentelemetry.io/collector/pdata from 1.12.0 to 1.25.0\n- [#16504](https://github.com/influxdata/telegraf/pull/16504) `deps` Bump golang.org/x/net from 0.34.0 to 0.35.0\n- [#16512](https://github.com/influxdata/telegraf/pull/16512) `deps` Bump golangci-lint from v1.63.4 to v1.64.5\n\n## v1.33.2 [2025-02-10]\n\n### Important Changes\n\n- PR [#16423](https://github.com/influxdata/telegraf/pull/16423) converts the ClickHouse drivers to the v2 version.\n  This new version also requires a\n  [new format for the DSN](https://github.com/ClickHouse/clickhouse-go/tree/v2.30.2?tab=readme-ov-file#dsn). The plugin\n  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\n  your log file and convert to the new format as soon as possible.\n- PR [#16403](https://github.com/influxdata/telegraf/pull/16403) ensures consistency of the NetFlow plugin's\n  `ip_version` field type by enforcing \"IPv4\", \"IPv6\", or \"unknown\" string values. Previously the `ip_version` could\n  become an (unsigned) integer when parsing raw-packets' headers especially with SFlow v5 input. Please watch\n  out for type-conflicts on the output side!\n\n### Bugfixes\n\n- [#16477](https://github.com/influxdata/telegraf/pull/16477) `agent` Avoid panic by checking for skip_processors_after_aggregators\n- [#16489](https://github.com/influxdata/telegraf/pull/16489) `agent` Set `godebug x509negativeserial=1` as a workaround\n- [#16403](https://github.com/influxdata/telegraf/pull/16403) `inputs.netflow` Ensure type consistency for sFlow&#39;s IP version field\n- [#16447](https://github.com/influxdata/telegraf/pull/16447) `inputs.x509_cert` Add config to left-pad serial number to 128-bits\n- [#16448](https://github.com/influxdata/telegraf/pull/16448) `outputs.azure_monitor` Prevent infinite send loop for outdated metrics\n- [#16472](https://github.com/influxdata/telegraf/pull/16472) `outputs.sql` Fix insert into ClickHouse\n- [#16454](https://github.com/influxdata/telegraf/pull/16454) `service` Set address to prevent orphaned dbus-session processes\n\n### Dependency Updates\n\n- [#16442](https://github.com/influxdata/telegraf/pull/16442) `deps` Bump cloud.google.com/go/storage from 1.47.0 to 1.50.0\n- [#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\n- [#16416](https://github.com/influxdata/telegraf/pull/16416) `deps` Bump github.com/apache/iotdb-client-go from 1.3.2 to 1.3.3\n- [#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\n- [#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\n- [#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\n- [#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\n- [#16395](https://github.com/influxdata/telegraf/pull/16395) `deps` Bump github.com/eclipse/paho.golang from 0.21.0 to 0.22.0\n- [#16470](https://github.com/influxdata/telegraf/pull/16470) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.8 to 3.4.10\n- [#16440](https://github.com/influxdata/telegraf/pull/16440) `deps` Bump github.com/google/cel-go from 0.21.0 to 0.23.0\n- [#16445](https://github.com/influxdata/telegraf/pull/16445) `deps` Bump github.com/lxc/incus/v6 from 6.6.0 to 6.9.0\n- [#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\n- [#16453](https://github.com/influxdata/telegraf/pull/16453) `deps` Bump github.com/prometheus/common from 0.61.0 to 0.62.0\n- [#16417](https://github.com/influxdata/telegraf/pull/16417) `deps` Bump github.com/shirou/gopsutil/v4 from 4.24.10 to 4.24.12\n- [#16369](https://github.com/influxdata/telegraf/pull/16369) `deps` Bump github.com/shirou/gopsutil/v4 from v4.24.10 to v4.24.12\n- [#16397](https://github.com/influxdata/telegraf/pull/16397) `deps` Bump github.com/showwin/speedtest-go from 1.7.9 to 1.7.10\n- [#16467](https://github.com/influxdata/telegraf/pull/16467) `deps` Bump github.com/yuin/goldmark from 1.6.0 to 1.7.8\n- [#16360](https://github.com/influxdata/telegraf/pull/16360) `deps` Bump golangci-lint from v1.62.2 to v1.63.4\n- [#16469](https://github.com/influxdata/telegraf/pull/16469) `deps` Bump google.golang.org/api from 0.214.0 to 0.219.0\n- [#16396](https://github.com/influxdata/telegraf/pull/16396) `deps` Bump k8s.io/api from 0.31.3 to 0.32.1\n- [#16482](https://github.com/influxdata/telegraf/pull/16482) `deps` Update Apache arrow from 0.0-20240716144821-cf5d7c7ec3cf to 18.1.0\n- [#16423](https://github.com/influxdata/telegraf/pull/16423) `deps` Update ClickHouse SQL driver from 1.5.4 to to 2.30.1\n\n## v1.33.1 [2025-01-10]\n\n### Important Changes\n\n- The default value of `skip_processors_after_aggregators` will change to `true`\n  with Telegraf `v1.40.0`, skip running the processors again after aggregators!\n  If you need the current default behavior, please explicitly set the option to\n  `false`! To silence the warning and use the future default behavior, please\n  explicitly set the option to `true`.\n\n### Bugfixes\n\n- [#16290](https://github.com/influxdata/telegraf/pull/16290) `agent` Skip initialization of second processor state if requested\n- [#16377](https://github.com/influxdata/telegraf/pull/16377) `inputs.intel_powerstat` Fix option removal version\n- [#16310](https://github.com/influxdata/telegraf/pull/16310) `inputs.mongodb` Do not dereference nil pointer if gathering database stats fails\n- [#16383](https://github.com/influxdata/telegraf/pull/16383) `outputs.influxdb_v2` Allow overriding auth and agent headers\n- [#16388](https://github.com/influxdata/telegraf/pull/16388) `outputs.influxdb_v2` Fix panic and API error handling\n- [#16289](https://github.com/influxdata/telegraf/pull/16289) `outputs.remotefile` Handle tracking metrics correctly\n\n### Dependency Updates\n\n- [#16344](https://github.com/influxdata/telegraf/pull/16344) `deps` Bump cloud.google.com/go/bigquery from 1.64.0 to 1.65.0\n- [#16283](https://github.com/influxdata/telegraf/pull/16283) `deps` Bump cloud.google.com/go/monitoring from 1.21.1 to 1.22.0\n- [#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\n- [#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\n- [#16346](https://github.com/influxdata/telegraf/pull/16346) `deps` Bump github.com/Masterminds/semver/v3 from 3.3.0 to 3.3.1\n- [#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\n- [#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\n- [#16317](https://github.com/influxdata/telegraf/pull/16317) `deps` Bump github.com/fatih/color from 1.17.0 to 1.18.0\n- [#16345](https://github.com/influxdata/telegraf/pull/16345) `deps` Bump github.com/gopacket/gopacket from 1.3.0 to 1.3.1\n- [#16282](https://github.com/influxdata/telegraf/pull/16282) `deps` Bump github.com/nats-io/nats.go from 1.36.0 to 1.37.0\n- [#16318](https://github.com/influxdata/telegraf/pull/16318) `deps` Bump github.com/prometheus/common from 0.60.0 to 0.61.0\n- [#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\n- [#16297](https://github.com/influxdata/telegraf/pull/16297) `deps` Bump golang.org/x/crypto from 0.29.0 to 0.31.0\n- [#16281](https://github.com/influxdata/telegraf/pull/16281) `deps` Bump k8s.io/client-go from 0.30.1 to 0.31.3\n- [#16313](https://github.com/influxdata/telegraf/pull/16313) `deps` Bump super-linter/super-linter from 7.2.0 to 7.2.1\n\n## v1.33.0 [2024-12-09]\n\n### New Plugins\n\n- [#15754](https://github.com/influxdata/telegraf/pull/15754) `inputs.neoom_beaam` Add new plugin\n- [#15869](https://github.com/influxdata/telegraf/pull/15869) `processors.batch` Add batch processor\n- [#16144](https://github.com/influxdata/telegraf/pull/16144) `outputs.quix` Add plugin\n\n### Features\n\n- [#16010](https://github.com/influxdata/telegraf/pull/16010) `agent` Add --watch-interval option for polling config changes\n- [#15948](https://github.com/influxdata/telegraf/pull/15948) `aggregators.basicstats` Add first field\n- [#15891](https://github.com/influxdata/telegraf/pull/15891) `common.socket` Allow parallel parsing with a pool of workers\n- [#16141](https://github.com/influxdata/telegraf/pull/16141) `inputs.amqp_consumer` Allow specification of queue arguments\n- [#15950](https://github.com/influxdata/telegraf/pull/15950) `inputs.diskio` Add field io await and util\n- [#15919](https://github.com/influxdata/telegraf/pull/15919) `inputs.kafka_consumer` Implement startup error behavior options\n- [#15910](https://github.com/influxdata/telegraf/pull/15910) `inputs.memcached` Add support for external-store metrics\n- [#15990](https://github.com/influxdata/telegraf/pull/15990) `inputs.mock` Add sine phase\n- [#16040](https://github.com/influxdata/telegraf/pull/16040) `inputs.modbus` Allow grouping across register types\n- [#15865](https://github.com/influxdata/telegraf/pull/15865) `inputs.prometheus` Allow to use secrets for credentials\n- [#16230](https://github.com/influxdata/telegraf/pull/16230) `inputs.smart` Add Power on Hours and Cycle Count\n- [#15935](https://github.com/influxdata/telegraf/pull/15935) `inputs.snmp` Add displayhint conversion\n- [#16027](https://github.com/influxdata/telegraf/pull/16027) `inputs.snmp` Convert uneven bytes to int\n- [#15976](https://github.com/influxdata/telegraf/pull/15976) `inputs.socket_listener` Use reception time as timestamp\n- [#15853](https://github.com/influxdata/telegraf/pull/15853) `inputs.statsd` Allow reporting sets and timings count as floats\n- [#11591](https://github.com/influxdata/telegraf/pull/11591) `inputs.vsphere` Add VM memory configuration\n- [#16109](https://github.com/influxdata/telegraf/pull/16109) `inputs.vsphere` Add cpu temperature field\n- [#15917](https://github.com/influxdata/telegraf/pull/15917) `inputs` Add option to choose the metric time source\n- [#16242](https://github.com/influxdata/telegraf/pull/16242) `logging` Allow overriding message key for structured logging\n- [#15742](https://github.com/influxdata/telegraf/pull/15742) `outputs.influxdb_v2` Add rate limit implementation\n- [#15943](https://github.com/influxdata/telegraf/pull/15943) `outputs.mqtt` Add sprig functions for topic name generator\n- [#16041](https://github.com/influxdata/telegraf/pull/16041) `outputs.postgresql` Allow limiting of column name length\n- [#16258](https://github.com/influxdata/telegraf/pull/16258) `outputs` Add rate-limiting infrastructure\n- [#16146](https://github.com/influxdata/telegraf/pull/16146) `outputs` Implement partial write errors\n- [#15883](https://github.com/influxdata/telegraf/pull/15883) `outputs` Only copy metric if its not filtered out\n- [#15893](https://github.com/influxdata/telegraf/pull/15893) `serializers.prometheusremotewrite` Log metric conversion errors\n\n### Bugfixes\n\n- [#16248](https://github.com/influxdata/telegraf/pull/16248) `inputs.netflow` Decode flags in TCP and IP headers correctly\n- [#16257](https://github.com/influxdata/telegraf/pull/16257) `inputs.procstat` Handle running processes correctly across multiple filters\n- [#16219](https://github.com/influxdata/telegraf/pull/16219) `logging` Add Close() func for redirectLogger\n- [#16255](https://github.com/influxdata/telegraf/pull/16255) `logging` Clean up extra empty spaces when redirectLogger is used\n- [#16274](https://github.com/influxdata/telegraf/pull/16274) `logging` Fix duplicated prefix and attrMsg in log message when redirectLogger is used\n\n### Dependency Updates\n\n- [#16232](https://github.com/influxdata/telegraf/pull/16232) `deps` Bump cloud.google.com/go/bigquery from 1.63.1 to 1.64.0\n- [#16235](https://github.com/influxdata/telegraf/pull/16235) `deps` Bump cloud.google.com/go/storage from 1.43.0 to 1.47.0\n- [#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\n- [#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\n- [#16201](https://github.com/influxdata/telegraf/pull/16201) `deps` Bump github.com/intel/powertelemetry from 1.0.1 to 1.0.2\n- [#16200](https://github.com/influxdata/telegraf/pull/16200) `deps` Bump github.com/rclone/rclone from 1.68.1 to 1.68.2\n- [#16199](https://github.com/influxdata/telegraf/pull/16199) `deps` Bump github.com/vishvananda/netns from 0.0.4 to 0.0.5\n- [#16236](https://github.com/influxdata/telegraf/pull/16236) `deps` Bump golang.org/x/net from 0.30.0 to 0.31.0\n- [#16250](https://github.com/influxdata/telegraf/pull/16250) `deps` Bump golangci-lint from v1.62.0 to v1.62.2\n- [#16233](https://github.com/influxdata/telegraf/pull/16233) `deps` Bump google.golang.org/grpc from 1.67.1 to 1.68.0\n- [#16202](https://github.com/influxdata/telegraf/pull/16202) `deps` Bump modernc.org/sqlite from 1.33.1 to 1.34.1\n- [#16203](https://github.com/influxdata/telegraf/pull/16203) `deps` Bump super-linter/super-linter from 7.1.0 to 7.2.0\n\n## v1.32.3 [2024-11-18]\n\n### Important Changes\n\n- PR [#16015](https://github.com/influxdata/telegraf/pull/16015) changes the\n  internal counters of the Bind plugin to unsigned integers matching the server\n  implementation. We keep backward compatibility by setting\n  `report_counters_as_int` to `true` by default to avoid type conflicts on the\n  output side. However, you should change this setting to `false` as soon as\n  possible to avoid invalid values and parsing errors with the v3 XML\n  statistics.\n\n### Bugfixes\n\n- [#16123](https://github.com/influxdata/telegraf/pull/16123) `agent` Restore setup order of stateful plugins to Init() then SetState()\n- [#16111](https://github.com/influxdata/telegraf/pull/16111) `common.socket` Make sure the scanner buffer matches the read-buffer size\n- [#16156](https://github.com/influxdata/telegraf/pull/16156) `common.socket` Use read buffer size config setting as a datagram reader buffer size\n- [#16015](https://github.com/influxdata/telegraf/pull/16015) `inputs.bind` Convert counters to uint64\n- [#16171](https://github.com/influxdata/telegraf/pull/16171) `inputs.gnmi` Register connection statistics before creating client\n- [#16197](https://github.com/influxdata/telegraf/pull/16197) `inputs.netflow` Cast TCP ports to uint16\n- [#16110](https://github.com/influxdata/telegraf/pull/16110) `inputs.ntpq` Avoid panic on empty lines and make sure -p is present\n- [#16155](https://github.com/influxdata/telegraf/pull/16155) `inputs.snmp` Fix crash when trying to format fields from unknown OIDs\n- [#16145](https://github.com/influxdata/telegraf/pull/16145) `inputs.snmp_trap` Remove timeout deprecation\n- [#16108](https://github.com/influxdata/telegraf/pull/16108) `logger` Avoid setting the log-format default too early\n\n### Dependency Updates\n\n- [#16093](https://github.com/influxdata/telegraf/pull/16093) `deps` Bump cloud.google.com/go/pubsub from 1.42.0 to 1.45.1\n- [#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\n- [#16096](https://github.com/influxdata/telegraf/pull/16096) `deps` Bump github.com/gofrs/uuid/v5 from 5.2.0 to 5.3.0\n- [#16136](https://github.com/influxdata/telegraf/pull/16136) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1\n- [#16094](https://github.com/influxdata/telegraf/pull/16094) `deps` Bump github.com/gopacket/gopacket from 1.2.0 to 1.3.0\n- [#16133](https://github.com/influxdata/telegraf/pull/16133) `deps` Bump github.com/jackc/pgtype from 1.14.3 to 1.14.4\n- [#16131](https://github.com/influxdata/telegraf/pull/16131) `deps` Bump github.com/openconfig/gnmi from 0.10.0 to 0.11.0\n- [#16092](https://github.com/influxdata/telegraf/pull/16092) `deps` Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5\n- [#16178](https://github.com/influxdata/telegraf/pull/16178) `deps` Bump github.com/rclone/rclone from 1.67.0 to 1.68.1\n- [#16132](https://github.com/influxdata/telegraf/pull/16132) `deps` Bump github.com/shirou/gopsutil/v4 from 4.24.9 to 4.24.10\n- [#16176](https://github.com/influxdata/telegraf/pull/16176) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.19 to 2.8.22\n- [#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\n- [#16174](https://github.com/influxdata/telegraf/pull/16174) `deps` Bump github.com/tidwall/gjson from 1.17.1 to 1.18.0\n- [#16135](https://github.com/influxdata/telegraf/pull/16135) `deps` Bump github.com/vmware/govmomi from 0.39.0 to 0.45.1\n- [#16095](https://github.com/influxdata/telegraf/pull/16095) `deps` Bump golang.org/x/sys from 0.25.0 to 0.26.0\n- [#16177](https://github.com/influxdata/telegraf/pull/16177) `deps` Bump golang.org/x/text from 0.19.0 to 0.20.0\n- [#16172](https://github.com/influxdata/telegraf/pull/16172) `deps` Bump golangci-lint from v1.61.0 to v1.62.0\n\n## v1.32.2 [2024-10-28]\n\n### Bugfixes\n\n- [#15966](https://github.com/influxdata/telegraf/pull/15966) `agent` Use a unique WAL file for plugin instances of the same type\n- [#16074](https://github.com/influxdata/telegraf/pull/16074) `inputs.kafka_consumer` Fix deadlock\n- [#16009](https://github.com/influxdata/telegraf/pull/16009) `inputs.netflow` Cast complex types to field compatible ones\n- [#16026](https://github.com/influxdata/telegraf/pull/16026) `inputs.opcua` Allow to retry reads on invalid sessions\n- [#16060](https://github.com/influxdata/telegraf/pull/16060) `inputs.procstat` Correctly use systemd-unit setting for finding them\n- [#16008](https://github.com/influxdata/telegraf/pull/16008) `inputs.win_eventlog` Handle XML data fields' filtering the same way as event fields\n- [#15968](https://github.com/influxdata/telegraf/pull/15968) `outputs.remotefile` Create a new serializer instance per output file\n- [#16014](https://github.com/influxdata/telegraf/pull/16014) `outputs.syslog` Trim field-names belonging to explicit SDIDs correctly\n\n### Dependency Updates\n\n- [#15992](https://github.com/influxdata/telegraf/pull/15992) `deps` Bump cloud.google.com/go/bigquery from 1.62.0 to 1.63.1\n- [#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\n- [#16021](https://github.com/influxdata/telegraf/pull/16021) `deps` Bump github.com/IBM/sarama from 1.43.2 to 1.43.3\n- [#16019](https://github.com/influxdata/telegraf/pull/16019) `deps` Bump github.com/alitto/pond from 1.9.0 to 1.9.2\n- [#16018](https://github.com/influxdata/telegraf/pull/16018) `deps` Bump github.com/apache/thrift from 0.20.0 to 0.21.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#16022](https://github.com/influxdata/telegraf/pull/16022) `deps` Bump github.com/docker/docker from 27.1.1+incompatible to 27.3.1+incompatible\n- [#15993](https://github.com/influxdata/telegraf/pull/15993) `deps` Bump github.com/gosnmp/gosnmp from 1.37.0 to 1.38.0\n- [#15947](https://github.com/influxdata/telegraf/pull/15947) `deps` Bump github.com/gwos/tcg/sdk from v8.7.2 to v8.8.0\n- [#16053](https://github.com/influxdata/telegraf/pull/16053) `deps` Bump github.com/lxc/incus/v6 from 6.2.0 to 6.6.0\n- [#15994](https://github.com/influxdata/telegraf/pull/15994) `deps` Bump github.com/signalfx/golib/v3 from 3.3.53 to 3.3.54\n- [#15995](https://github.com/influxdata/telegraf/pull/15995) `deps` Bump github.com/snowflakedb/gosnowflake from 1.11.1 to 1.11.2\n- [#16020](https://github.com/influxdata/telegraf/pull/16020) `deps` Bump go.step.sm/crypto from 0.51.1 to 0.54.0\n- [#16023](https://github.com/influxdata/telegraf/pull/16023) `deps` Bump github.com/shirou/gopsutil from v3.24.4 to v4.24.9\n\n## v1.32.1 [2024-10-07]\n\n### Important Changes\n\n- PR [#15796](https://github.com/influxdata/telegraf/pull/15796) changes the\n  delivery state update of un-parseable messages from `ACK` to `NACK` without\n  requeueing. This way, those messages are not lost and can optionally be\n  handled using a dead-letter exchange by other means.\n- Removal of old-style serializer creation. This should not directly affect\n  users as it is an API change. All serializers in Telegraf are already ported\n  to the new framework. If you experience any issues with not being able to\n  create serializers let us know!\n\n### Bugfixes\n\n- [#15969](https://github.com/influxdata/telegraf/pull/15969) `agent` Fix buffer not flushing if all metrics are written\n- [#15937](https://github.com/influxdata/telegraf/pull/15937) `config` Correctly print removal version info\n- [#15900](https://github.com/influxdata/telegraf/pull/15900) `common.http` Keep timeout after creating oauth client\n- [#15796](https://github.com/influxdata/telegraf/pull/15796) `inputs.amqp_consumer` NACKing messages on non-delivery related errors\n- [#15923](https://github.com/influxdata/telegraf/pull/15923) `inputs.cisco_telemetry_mdt` Handle NXOS DME subtree telemetry format\n- [#15907](https://github.com/influxdata/telegraf/pull/15907) `inputs.consul` Move config checking to Init method\n- [#15982](https://github.com/influxdata/telegraf/pull/15982) `inputs.influxdb_v2_listener` Fix concurrent read/write dict\n- [#15960](https://github.com/influxdata/telegraf/pull/15960) `inputs.vsphere` Add tags to VSAN ESA disks\n- [#15921](https://github.com/influxdata/telegraf/pull/15921) `parsers.avro` Add mutex to cache access\n- [#15965](https://github.com/influxdata/telegraf/pull/15965) `processors.aws_ec2` Remove leading slash and cancel worker only if it exists\n\n### Dependency Updates\n\n- [#15932](https://github.com/influxdata/telegraf/pull/15932) `deps` Bump cloud.google.com/go/monitoring from 1.20.2 to 1.21.1\n- [#15863](https://github.com/influxdata/telegraf/pull/15863) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.3 to 0.16.1\n- [#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\n- [#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\n- [#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\n- [#15931](https://github.com/influxdata/telegraf/pull/15931) `deps` Bump github.com/boschrexroth/ctrlx-datalayer-golang from 1.3.0 to 1.3.1\n- [#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\n- [#15904](https://github.com/influxdata/telegraf/pull/15904) `deps` Bump github.com/netsampler/goflow2/v2 from 2.1.5 to 2.2.1\n- [#15903](https://github.com/influxdata/telegraf/pull/15903) `deps` Bump github.com/p4lang/p4runtime from 1.3.0 to 1.4.0\n- [#15905](https://github.com/influxdata/telegraf/pull/15905) `deps` Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3\n- [#15930](https://github.com/influxdata/telegraf/pull/15930) `deps` Bump github.com/prometheus/client_golang from 1.20.3 to 1.20.4\n- [#15962](https://github.com/influxdata/telegraf/pull/15962) `deps` Bump github.com/prometheus/common from 0.55.0 to 0.60.0\n- [#15860](https://github.com/influxdata/telegraf/pull/15860) `deps` Bump github.com/snowflakedb/gosnowflake from 1.10.0 to 1.11.1\n- [#15954](https://github.com/influxdata/telegraf/pull/15954) `deps` Bump github.com/srebhan/protobufquery from 0.0.0-20230803132024-ae4c0d878e55 to 1.0.1\n- [#15929](https://github.com/influxdata/telegraf/pull/15929) `deps` Bump go.mongodb.org/mongo-driver from 1.16.0 to 1.17.0\n- [#15902](https://github.com/influxdata/telegraf/pull/15902) `deps` Bump golang.org/x/mod from 0.19.0 to 0.21.0\n- [#15955](https://github.com/influxdata/telegraf/pull/15955) `deps` Bump golang.org/x/oauth2 from 0.21.0 to 0.23.0\n- [#15861](https://github.com/influxdata/telegraf/pull/15861) `deps` Bump golang.org/x/term from 0.23.0 to 0.24.0\n- [#15856](https://github.com/influxdata/telegraf/pull/15856) `deps` Bump golangci-lint from v1.60.3 to v1.61.0\n- [#15933](https://github.com/influxdata/telegraf/pull/15933) `deps` Bump k8s.io/apimachinery from 0.30.1 to 0.31.1\n- [#15901](https://github.com/influxdata/telegraf/pull/15901) `deps` Bump modernc.org/sqlite from 1.32.0 to 1.33.1\n\n## v1.32.0 [2024-09-09]\n\n### Important Changes\n\n- This release contains a logging overhaul as well as some new features for\n  logging (see PRs [#15556](https://github.com/influxdata/telegraf/pull/15556),\n  [#15629](https://github.com/influxdata/telegraf/pull/15629),\n  [#15677](https://github.com/influxdata/telegraf/pull/15677),\n  [#15695](https://github.com/influxdata/telegraf/pull/15695) and\n  [#15751](https://github.com/influxdata/telegraf/pull/15751)).\n  As a consequence the redunant `logtarget` setting is deprecated, `stderr` is\n  used if no `logfile` is provided, otherwise messages are logged to the given\n  file. For using the Windows `eventlog` set `logformat = \"eventlog\"`!\n- This release contains a change in json_v2 parser config parsing -\n  if the config is empty (not define any rules), initialization will fail\n  (see PR [#15844](https://github.com/influxdata/telegraf/pull/15844)).\n- This release contains a feature for a disk-backed metric buffer under the\n  `buffer_strategy` agent config (see\n  PR [#15564](https://github.com/influxdata/telegraf/pull/15564)).\n  Please note, this feature is **experimental**, please give it a test and\n  report any issues you encounter.\n\n### New Plugins\n\n- [#15700](https://github.com/influxdata/telegraf/pull/15700) `inputs.slurm` SLURM workload manager\n- [#15602](https://github.com/influxdata/telegraf/pull/15602) `outputs.parquet` Parquet file writer\n- [#15569](https://github.com/influxdata/telegraf/pull/15569) `outputs.remotefile` Output to remote location like S3\n\n### Features\n\n- [#15732](https://github.com/influxdata/telegraf/pull/15732) `agent` Add config check sub-command\n- [#15564](https://github.com/influxdata/telegraf/pull/15564) `agent` Add metric disk buffer\n- [#15645](https://github.com/influxdata/telegraf/pull/15645) `agent` Enable watching for new configuration files\n- [#15644](https://github.com/influxdata/telegraf/pull/15644) `agent` Watch for deleted files\n- [#15695](https://github.com/influxdata/telegraf/pull/15695) `logging` Add 'trace' log-level\n- [#15677](https://github.com/influxdata/telegraf/pull/15677) `logging` Allow to override log-level per plugin\n- [#15751](https://github.com/influxdata/telegraf/pull/15751) `logging` Implement structured logging\n- [#15640](https://github.com/influxdata/telegraf/pull/15640) `common.cookie` Allow usage of secrets in headers\n- [#15636](https://github.com/influxdata/telegraf/pull/15636) `common.shim` Enable metric tracking within external plugins\n- [#15570](https://github.com/influxdata/telegraf/pull/15570) `common.tls` Allow group aliases for cipher-suites\n- [#15628](https://github.com/influxdata/telegraf/pull/15628) `inputs.amd_rocm_smi` Parse newer ROCm versions\n- [#15519](https://github.com/influxdata/telegraf/pull/15519) `inputs.azure_monitor` Add client options parameter\n- [#15544](https://github.com/influxdata/telegraf/pull/15544) `inputs.elasticsearch` Add support for custom headers\n- [#15688](https://github.com/influxdata/telegraf/pull/15688) `inputs.elasticsearch` Gather enrich stats\n- [#15834](https://github.com/influxdata/telegraf/pull/15834) `inputs.execd` Allow to provide logging prefixes on stderr\n- [#15764](https://github.com/influxdata/telegraf/pull/15764) `inputs.http_listener_v2` Add unix socket mode\n- [#15495](https://github.com/influxdata/telegraf/pull/15495) `inputs.ipmi_sensor` Collect additional commands\n- [#15790](https://github.com/influxdata/telegraf/pull/15790) `inputs.kafka_consumer` Allow to select the metric time source\n- [#15648](https://github.com/influxdata/telegraf/pull/15648) `inputs.modbus` Allow reading single bits of input and holding registers\n- [#15528](https://github.com/influxdata/telegraf/pull/15528) `inputs.mqtt_consumer` Add variable length topic parsing\n- [#15486](https://github.com/influxdata/telegraf/pull/15486) `inputs.mqtt_consumer` Implement startup error behaviors\n- [#15749](https://github.com/influxdata/telegraf/pull/15749) `inputs.mysql` Add support for replica status\n- [#15521](https://github.com/influxdata/telegraf/pull/15521) `inputs.netflow` Add more fields for sFlow extended gateway packets\n- [#15396](https://github.com/influxdata/telegraf/pull/15396) `inputs.netflow` Add support for sFlow drop notification packets\n- [#15468](https://github.com/influxdata/telegraf/pull/15468) `inputs.openstack` Allow collection without admin privileges\n- [#15637](https://github.com/influxdata/telegraf/pull/15637) `inputs.opentelemetry` Add profiles support\n- [#15423](https://github.com/influxdata/telegraf/pull/15423) `inputs.procstat` Add ability to collect per-process socket statistics\n- [#15655](https://github.com/influxdata/telegraf/pull/15655) `inputs.s7comm` Implement startup-error behavior settings\n- [#15600](https://github.com/influxdata/telegraf/pull/15600) `inputs.sql` Add SAP HANA SQL driver\n- [#15424](https://github.com/influxdata/telegraf/pull/15424) `inputs.sqlserver` Introduce user specified ID parameter for ADD logins\n- [#15687](https://github.com/influxdata/telegraf/pull/15687) `inputs.statsd` Expose allowed_pending_messages as internal stat\n- [#15458](https://github.com/influxdata/telegraf/pull/15458) `inputs.systemd_units` Support user scoped units\n- [#15702](https://github.com/influxdata/telegraf/pull/15702) `outputs.datadog` Add support for submitting alongside dd-agent\n- [#15668](https://github.com/influxdata/telegraf/pull/15668) `outputs.dynatrace` Report metrics as a delta counter using regular expression\n- [#15471](https://github.com/influxdata/telegraf/pull/15471) `outputs.elasticsearch` Allow custom template index settings\n- [#15613](https://github.com/influxdata/telegraf/pull/15613) `outputs.elasticsearch` Support data streams\n- [#15722](https://github.com/influxdata/telegraf/pull/15722) `outputs.kafka` Add option to add metric name as record header\n- [#15689](https://github.com/influxdata/telegraf/pull/15689) `outputs.kafka` Add option to set producer message timestamp\n- [#15787](https://github.com/influxdata/telegraf/pull/15787) `outputs.syslog` Implement startup error behavior options\n- [#15697](https://github.com/influxdata/telegraf/pull/15697) `parsers.value` Add base64 datatype\n- [#15795](https://github.com/influxdata/telegraf/pull/15795) `processors.aws_ec2` Allow to use instance metadata\n\n### Bugfixes\n\n- [#15661](https://github.com/influxdata/telegraf/pull/15661) `agent` Fix buffer directory config and document\n- [#15788](https://github.com/influxdata/telegraf/pull/15788) `inputs.kinesis_consumer` Honor the configured endpoint\n- [#15791](https://github.com/influxdata/telegraf/pull/15791) `inputs.mysql` Enforce float for all known floating-point information\n- [#15743](https://github.com/influxdata/telegraf/pull/15743) `inputs.snmp` Avoid sending a nil to gosmi's GetEnumBitsFormatted\n- [#15815](https://github.com/influxdata/telegraf/pull/15815) `logger` Handle trace level for standard log\n- [#15781](https://github.com/influxdata/telegraf/pull/15781) `outputs.kinesis` Honor the configured endpoint\n- [#15615](https://github.com/influxdata/telegraf/pull/15615) `outputs.remotefile` Resolve linter not checking error\n- [#15740](https://github.com/influxdata/telegraf/pull/15740) `serializers.template` Unwrap metrics if required\n\n### Dependency Updates\n\n- [#15829](https://github.com/influxdata/telegraf/pull/15829) `deps` Bump github.com/BurntSushi/toml from 1.3.2 to 1.4.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#15737](https://github.com/influxdata/telegraf/pull/15737) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.3 to 1.5.0\n- [#15734](https://github.com/influxdata/telegraf/pull/15734) `deps` Bump github.com/google/cel-go from 0.20.1 to 0.21.0\n- [#15777](https://github.com/influxdata/telegraf/pull/15777) `deps` Bump github.com/miekg/dns from 1.1.59 to 1.1.62\n- [#15828](https://github.com/influxdata/telegraf/pull/15828) `deps` Bump github.com/openconfig/goyang from 1.5.0 to 1.6.0\n- [#15735](https://github.com/influxdata/telegraf/pull/15735) `deps` Bump github.com/pion/dtls/v2 from 2.2.11 to 2.2.12\n- [#15779](https://github.com/influxdata/telegraf/pull/15779) `deps` Bump github.com/prometheus/client_golang from 1.19.1 to 1.20.2\n- [#15831](https://github.com/influxdata/telegraf/pull/15831) `deps` Bump github.com/prometheus/prometheus from 0.53.1 to 0.54.1\n- [#15736](https://github.com/influxdata/telegraf/pull/15736) `deps` Bump github.com/redis/go-redis/v9 from 9.5.1 to 9.6.1\n- [#15830](https://github.com/influxdata/telegraf/pull/15830) `deps` Bump github.com/seancfoley/ipaddress-go from 1.6.0 to 1.7.0\n- [#15842](https://github.com/influxdata/telegraf/pull/15842) `deps` Bump github.com/showwin/speedtest-go from 1.7.7 to 1.7.9\n- [#15778](https://github.com/influxdata/telegraf/pull/15778) `deps` Bump go.step.sm/crypto from 0.50.0 to 0.51.1\n- [#15776](https://github.com/influxdata/telegraf/pull/15776) `deps` Bump golang.org/x/net from 0.27.0 to 0.28.0\n- [#15757](https://github.com/influxdata/telegraf/pull/15757) `deps` Bump golang.org/x/sync from 0.7.0 to 0.8.0\n- [#15759](https://github.com/influxdata/telegraf/pull/15759) `deps` Bump gonum.org/v1/gonum from 0.15.0 to 0.15.1\n- [#15758](https://github.com/influxdata/telegraf/pull/15758) `deps` Bump modernc.org/sqlite from 1.30.0 to 1.32.0\n- [#15756](https://github.com/influxdata/telegraf/pull/15756) `deps` Bump super-linter/super-linter from 6.8.0 to 7.0.0\n- [#15826](https://github.com/influxdata/telegraf/pull/15826) `deps` Bump super-linter/super-linter from 7.0.0 to 7.1.0\n- [#15780](https://github.com/influxdata/telegraf/pull/15780) `deps` Bump tj-actions/changed-files from 44 to 45\n\n## v1.31.3 [2024-08-12]\n\n### Bugfixes\n\n- [#15552](https://github.com/influxdata/telegraf/pull/15552) `inputs.chrony` Use DGRAM for the unix socket\n- [#15667](https://github.com/influxdata/telegraf/pull/15667) `inputs.diskio` Print warnings once, add details to messages\n- [#15670](https://github.com/influxdata/telegraf/pull/15670) `inputs.mqtt_consumer` Restore trace logging option\n- [#15696](https://github.com/influxdata/telegraf/pull/15696) `inputs.opcua` Reconnect if closed connection\n- [#15724](https://github.com/influxdata/telegraf/pull/15724) `inputs.smartctl` Use --scan-open instead of --scan to provide correct device type info\n- [#15649](https://github.com/influxdata/telegraf/pull/15649) `inputs.tail` Prevent deadlock when closing and max undelivered lines hit\n\n### Dependency Updates\n\n- [#15720](https://github.com/influxdata/telegraf/pull/15720) `deps` Bump Go from v1.22.5 to v1.22.6\n- [#15683](https://github.com/influxdata/telegraf/pull/15683) `deps` Bump cloud.google.com/go/bigquery from 1.61.0 to 1.62.0\n- [#15654](https://github.com/influxdata/telegraf/pull/15654) `deps` Bump cloud.google.com/go/monitoring from 1.19.0 to 1.20.2\n- [#15679](https://github.com/influxdata/telegraf/pull/15679) `deps` Bump cloud.google.com/go/monitoring from 1.20.2 to 1.20.3\n- [#15626](https://github.com/influxdata/telegraf/pull/15626) `deps` Bump github.com/antchfx/xmlquery from 1.4.0 to 1.4.1\n- [#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\n- [#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\n- [#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\n- [#15681](https://github.com/influxdata/telegraf/pull/15681) `deps` Bump github.com/docker/docker from 25.0.5-incompatible to 27.1.1-incompatible\n- [#15650](https://github.com/influxdata/telegraf/pull/15650) `deps` Bump github.com/gofrs/uuid/v5 from 5.0.0 to 5.2.0\n- [#15705](https://github.com/influxdata/telegraf/pull/15705) `deps` Bump github.com/gorilla/websocket from 1.5.1 to 1.5.3\n- [#15708](https://github.com/influxdata/telegraf/pull/15708) `deps` Bump github.com/multiplay/go-ts3 from 1.1.0 to 1.2.0\n- [#15707](https://github.com/influxdata/telegraf/pull/15707) `deps` Bump github.com/prometheus-community/pro-bing from 0.4.0 to 0.4.1\n- [#15709](https://github.com/influxdata/telegraf/pull/15709) `deps` Bump github.com/prometheus/prometheus from 0.48.1 to 0.53.1\n- [#15680](https://github.com/influxdata/telegraf/pull/15680) `deps` Bump github.com/vmware/govmomi from 0.37.2 to 0.39.0\n- [#15682](https://github.com/influxdata/telegraf/pull/15682) `deps` Bump go.mongodb.org/mongo-driver from 1.14.0 to 1.16.0\n- [#15652](https://github.com/influxdata/telegraf/pull/15652) `deps` Bump go.step.sm/crypto from 0.47.1 to 0.50.0\n- [#15653](https://github.com/influxdata/telegraf/pull/15653) `deps` Bump google.golang.org/grpc from 1.64.1 to 1.65.0\n- [#15704](https://github.com/influxdata/telegraf/pull/15704) `deps` Bump super-linter/super-linter from 6.7.0 to 6.8.0\n\n## v1.31.2 [2024-07-22]\n\n### Bugfixes\n\n- [#15589](https://github.com/influxdata/telegraf/pull/15589) `common.socket` Switch to context to simplify closing\n- [#15601](https://github.com/influxdata/telegraf/pull/15601) `inputs.ping` Check addr length to avoid crash\n- [#15618](https://github.com/influxdata/telegraf/pull/15618) `inputs.snmp` Translate field correctly when not in table\n- [#15586](https://github.com/influxdata/telegraf/pull/15586) `parsers.xpath` Allow resolving extensions\n- [#15630](https://github.com/influxdata/telegraf/pull/15630) `tools.custom_builder` Handle multiple instances of the same plugin correctly\n\n### Dependency Updates\n\n- [#15582](https://github.com/influxdata/telegraf/pull/15582) `deps` Bump cloud.google.com/go/storage from 1.41.0 to 1.42.0\n- [#15623](https://github.com/influxdata/telegraf/pull/15623) `deps` Bump cloud.google.com/go/storage from 1.42.0 to 1.43.0\n- [#15607](https://github.com/influxdata/telegraf/pull/15607) `deps` Bump github.com/alitto/pond from 1.8.3 to 1.9.0\n- [#15625](https://github.com/influxdata/telegraf/pull/15625) `deps` Bump github.com/antchfx/xpath from 1.3.0 to 1.3.1\n- [#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\n- [#15606](https://github.com/influxdata/telegraf/pull/15606) `deps` Bump github.com/hashicorp/consul/api from 1.26.1 to 1.29.1\n- [#15604](https://github.com/influxdata/telegraf/pull/15604) `deps` Bump github.com/jackc/pgx/v4 from 4.18.2 to 4.18.3\n- [#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\n- [#15603](https://github.com/influxdata/telegraf/pull/15603) `deps` Bump github.com/openconfig/goyang from 1.0.0 to 1.5.0\n- [#15624](https://github.com/influxdata/telegraf/pull/15624) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.4 to 2.8.19\n- [#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\n- [#15605](https://github.com/influxdata/telegraf/pull/15605) `deps` Bump github.com/tinylib/msgp from 1.1.9 to 1.2.0\n- [#15584](https://github.com/influxdata/telegraf/pull/15584) `deps` Bump github.com/urfave/cli/v2 from 2.27.1 to 2.27.2\n- [#15614](https://github.com/influxdata/telegraf/pull/15614) `deps` Bump google.golang.org/grpc from 1.64.0 to 1.64.1\n- [#15608](https://github.com/influxdata/telegraf/pull/15608) `deps` Bump super-linter/super-linter from 6.6.0 to 6.7.0\n\nFor versions earlier than v1.13 and earlier see\n[CHANGELOG-1.13.md](CHANGELOG-1.13.md).\n\n## v1.31.1 [2024-07-01]\n\n### Bugfixes\n\n- [#15488](https://github.com/influxdata/telegraf/pull/15488) `agent` Ignore startup-errors in test mode\n- [#15568](https://github.com/influxdata/telegraf/pull/15568) `inputs.chrony` Handle ServerStats4 response\n- [#15551](https://github.com/influxdata/telegraf/pull/15551) `inputs.chrony` Support local (reference) sources\n- [#15565](https://github.com/influxdata/telegraf/pull/15565) `inputs.gnmi` Handle YANG namespaces in paths correctly\n- [#15496](https://github.com/influxdata/telegraf/pull/15496) `inputs.http_response` Fix for IPv4 and IPv6 addresses when interface is set\n- [#15493](https://github.com/influxdata/telegraf/pull/15493) `inputs.mysql` Handle custom TLS configs correctly\n- [#15514](https://github.com/influxdata/telegraf/pull/15514) `logging` Add back constants for backward compatibility\n- [#15531](https://github.com/influxdata/telegraf/pull/15531) `secretstores.oauth2` Ensure endpoint params is not nil\n\n### Dependency Updates\n\n- [#15483](https://github.com/influxdata/telegraf/pull/15483) `deps` Bump cloud.google.com/go/monitoring from 1.18.1 to 1.19.0\n- [#15559](https://github.com/influxdata/telegraf/pull/15559) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.2 to 0.15.3\n- [#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\n- [#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\n- [#15480](https://github.com/influxdata/telegraf/pull/15480) `deps` Bump github.com/IBM/sarama from 1.43.1 to 1.43.2\n- [#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\n- [#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\n- [#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\n- [#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\n- [#15557](https://github.com/influxdata/telegraf/pull/15557) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.6 to 3.4.8\n- [#15523](https://github.com/influxdata/telegraf/pull/15523) `deps` Bump github.com/linkedin/goavro/v2 from 2.12.0 to 2.13.0\n- [#15484](https://github.com/influxdata/telegraf/pull/15484) `deps` Bump github.com/microsoft/go-mssqldb from 1.7.0 to 1.7.2\n- [#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\n- [#15524](https://github.com/influxdata/telegraf/pull/15524) `deps` Bump github.com/prometheus/common from 0.53.0 to 0.54.0\n- [#15481](https://github.com/influxdata/telegraf/pull/15481) `deps` Bump github.com/prometheus/procfs from 0.15.0 to 0.15.1\n- [#15482](https://github.com/influxdata/telegraf/pull/15482) `deps` Bump github.com/rabbitmq/amqp091-go from 1.9.0 to 1.10.0\n- [#15525](https://github.com/influxdata/telegraf/pull/15525) `deps` Bump go.step.sm/crypto from 0.44.1 to 0.47.1\n- [#15479](https://github.com/influxdata/telegraf/pull/15479) `deps` Bump super-linter/super-linter from 6.5.1 to 6.6.0\n\n## v1.31.0 [2024-06-10]\n\n### Important Changes\n\n- [PR #15186](https://github.com/influxdata/telegraf/pull/15186) changes the\n  meaning of `inputs.procstat` fields `read_bytes` and `write_bytes` on Linux\n  to now contain _all_ I/O operations for consistency with other\n  operating-systems. The previous values are output as `disk_read_bytes` and\n  `disk_write_bytes` measuring _only_ the I/O on the storage layer.\n\n### New Plugins\n\n- [#15066](https://github.com/influxdata/telegraf/pull/15066) `inputs.smartctl` smartctl\n- [#15298](https://github.com/influxdata/telegraf/pull/15298) `parsers.openmetrics` OpenMetrics\n- [#15008](https://github.com/influxdata/telegraf/pull/15008) `parsers.parquet` Apache Parquet\n- [#15094](https://github.com/influxdata/telegraf/pull/15094) `processors.timestamp` Timestamp\n\n### Features\n\n- [#15433](https://github.com/influxdata/telegraf/pull/15433) `agent` Add uint support in cli test output\n- [#15377](https://github.com/influxdata/telegraf/pull/15377) `agent` Introduce CLI option to set config URL retry attempts\n- [#15388](https://github.com/influxdata/telegraf/pull/15388) `agent` Introduce CLI option to reload remote URL configs on change\n- [#15030](https://github.com/influxdata/telegraf/pull/15030) `aggregators.basicstats` Add last field\n- [#15268](https://github.com/influxdata/telegraf/pull/15268) `aggregators.final` Add option to disable appending _final\n- [#15319](https://github.com/influxdata/telegraf/pull/15319) `aggregators.merge` Allow to round metric timestamps\n- [#15426](https://github.com/influxdata/telegraf/pull/15426) `cli` List available parsers and serializers\n- [#15341](https://github.com/influxdata/telegraf/pull/15341) `common.opcua` Add session timeout as configuration option\n- [#15395](https://github.com/influxdata/telegraf/pull/15395) `input.azure_monitor` Use default Azure credentials chain when no secret provided\n- [#15233](https://github.com/influxdata/telegraf/pull/15233) `inputs.ceph` Use perf schema to determine metric type\n- [#14992](https://github.com/influxdata/telegraf/pull/14992) `inputs.dns_query` Allow ignoring errors of specific types\n- [#15400](https://github.com/influxdata/telegraf/pull/15400) `inputs.exec` Add option to ignore return code\n- [#15271](https://github.com/influxdata/telegraf/pull/15271) `inputs.execd` Add option to not restart program on error\n- [#15330](https://github.com/influxdata/telegraf/pull/15330) `inputs.file` Add tag with absolute path of file\n- [#15171](https://github.com/influxdata/telegraf/pull/15171) `inputs.gnmi` Add keepalive settings\n- [#15278](https://github.com/influxdata/telegraf/pull/15278) `inputs.gnmi` Add option to create more descriptive tags\n- [#15173](https://github.com/influxdata/telegraf/pull/15173) `inputs.gnmi` Add secret store support for username and password\n- [#15201](https://github.com/influxdata/telegraf/pull/15201) `inputs.gnmi` Add yang-model decoding of JSON IETF payloads\n- [#15256](https://github.com/influxdata/telegraf/pull/15256) `inputs.gnmi` Allow to pass accepted cipher suites\n- [#15454](https://github.com/influxdata/telegraf/pull/15454) `inputs.http_listener` Allow setting custom success return code\n- [#15110](https://github.com/influxdata/telegraf/pull/15110) `inputs.http_response` Add cookie authentication\n- [#15438](https://github.com/influxdata/telegraf/pull/15438) `inputs.influxdb` Add metrics for build, crypto and commandline\n- [#15361](https://github.com/influxdata/telegraf/pull/15361) `inputs.influxdb_v2_listener` Add support for rate limiting\n- [#15407](https://github.com/influxdata/telegraf/pull/15407) `inputs.influxdb_v2_listener` Support secret store for token\n- [#15329](https://github.com/influxdata/telegraf/pull/15329) `inputs.internet_speed` Introduce packet loss field\n- [#15368](https://github.com/influxdata/telegraf/pull/15368) `inputs.kafka_consumer` Add resolve canonical bootstrap server option\n- [#15169](https://github.com/influxdata/telegraf/pull/15169) `inputs.knx_listener` Add support for string data type\n- [#15069](https://github.com/influxdata/telegraf/pull/15069) `inputs.knx_listener` Allow usage of DPT string representation\n- [#15049](https://github.com/influxdata/telegraf/pull/15049) `inputs.kubernetes` Add option to node metric name\n- [#15044](https://github.com/influxdata/telegraf/pull/15044) `inputs.lustre2` Add eviction_count field\n- [#15042](https://github.com/influxdata/telegraf/pull/15042) `inputs.lustre2` Add health-check metric\n- [#14813](https://github.com/influxdata/telegraf/pull/14813) `inputs.lustre2` Add support for bulk read/write stats\n- [#15045](https://github.com/influxdata/telegraf/pull/15045) `inputs.lustre2` Skip brw_stats in case of insufficient permissions\n- [#15270](https://github.com/influxdata/telegraf/pull/15270) `inputs.mock` Add baseline option to sine\n- [#15314](https://github.com/influxdata/telegraf/pull/15314) `inputs.netflow` Add support for IPFIX option packets\n- [#15180](https://github.com/influxdata/telegraf/pull/15180) `inputs.netflow` Add support for netflow v9 option packets\n- [#15282](https://github.com/influxdata/telegraf/pull/15282) `inputs.nvidia_smi` Add power-limit field for v12 scheme\n- [#15460](https://github.com/influxdata/telegraf/pull/15460) `inputs.openstack` Use service catalog from v3 authentication if available\n- [#15231](https://github.com/influxdata/telegraf/pull/15231) `inputs.opentelemetry` Add option to set max receive message size\n- [#15299](https://github.com/influxdata/telegraf/pull/15299) `inputs.procstat` Add option to select properties to collect\n- [#14948](https://github.com/influxdata/telegraf/pull/14948) `inputs.procstat` Allow multiple selection criteria\n- [#15186](https://github.com/influxdata/telegraf/pull/15186) `inputs.procstat` Report consistent I/O on Linux\n- [#14981](https://github.com/influxdata/telegraf/pull/14981) `inputs.radius` Provide setting to set request IP address\n- [#15293](https://github.com/influxdata/telegraf/pull/15293) `inputs.redis` Add latency percentiles metric\n- [#15000](https://github.com/influxdata/telegraf/pull/15000) `inputs.s7comm`  Add optional connection type setting\n- [#15439](https://github.com/influxdata/telegraf/pull/15439) `inputs.snmp` Convert octet string with invalid data to hex\n- [#15137](https://github.com/influxdata/telegraf/pull/15137) `inputs.sqlserver` Add persistent version store metrics\n- [#15380](https://github.com/influxdata/telegraf/pull/15380) `inputs.statsd` Add support for DogStatsD v1.2\n- [#15371](https://github.com/influxdata/telegraf/pull/15371) `inputs.statsd` Allow counters to report as float\n- [#15306](https://github.com/influxdata/telegraf/pull/15306) `inputs.win_eventlog` Add option to define event batch-size\n- [#14973](https://github.com/influxdata/telegraf/pull/14973) `inputs.win_wmi` Add support for remote queries\n- [#15300](https://github.com/influxdata/telegraf/pull/15300) `inputs.win_wmi` Allow to invoke methods\n- [#15145](https://github.com/influxdata/telegraf/pull/15145) `inputs` Add framework to retry on startup errors\n- [#15065](https://github.com/influxdata/telegraf/pull/15065) `outputs.cratedb` Allow configuration of startup error handling\n- [#15477](https://github.com/influxdata/telegraf/pull/15477) `outputs.elasticsearch` Allow settings extra headers for elasticsearch output\n- [#15225](https://github.com/influxdata/telegraf/pull/15225) `outputs.influxdb` Add option to define local address\n- [#15228](https://github.com/influxdata/telegraf/pull/15228) `outputs.influxdb_v2` Add option to set local address\n- [#15475](https://github.com/influxdata/telegraf/pull/15475) `outputs.influxdb_v2` Preserve custom query parameters on write\n- [#15429](https://github.com/influxdata/telegraf/pull/15429) `outputs.mqtt` Add client trace logging, resolve MQTT5 reconnect login\n- [#15041](https://github.com/influxdata/telegraf/pull/15041) `outputs.postgresql` Add secret store support\n- [#15073](https://github.com/influxdata/telegraf/pull/15073) `outputs.postgresql` Allow configuration of startup error handling\n- [#14884](https://github.com/influxdata/telegraf/pull/14884) `outputs` Add framework to retry on startup errors\n- [#14952](https://github.com/influxdata/telegraf/pull/14952) `parser.prometheusremotewrite` Parse and generate histogram buckets\n- [#14961](https://github.com/influxdata/telegraf/pull/14961) `parsers.binary` Allow base64-encoded input data\n- [#15328](https://github.com/influxdata/telegraf/pull/15328) `processors.parser` Add base64 decode for fields\n- [#15434](https://github.com/influxdata/telegraf/pull/15434) `processors.printer` Embed Influx serializer options\n- [#15170](https://github.com/influxdata/telegraf/pull/15170) `processors.starlark` Allow persistence of global state\n- [#15220](https://github.com/influxdata/telegraf/pull/15220) `serializers.influx` Add option to omit timestamp\n- [#14975](https://github.com/influxdata/telegraf/pull/14975) `snmp` Add secret support for auth_password and priv_password\n\n### Bugfixes\n\n- [#15402](https://github.com/influxdata/telegraf/pull/15402) `agent` Warn on multiple agent configuration tables seen\n- [#15440](https://github.com/influxdata/telegraf/pull/15440) `inputs.cloudwatch` Add accounts when enabled\n- [#15428](https://github.com/influxdata/telegraf/pull/15428) `inputs.cloudwatch` Ensure account list is larger than index\n- [#15456](https://github.com/influxdata/telegraf/pull/15456) `inputs.ecs` Check for nil pointer before use\n- [#15401](https://github.com/influxdata/telegraf/pull/15401) `inputs.postgresql_extensible` Use same timestamp for each gather\n- [#15260](https://github.com/influxdata/telegraf/pull/15260) `inputs.procstat` Do not report dead processes as running for orphan PID files\n- [#15332](https://github.com/influxdata/telegraf/pull/15332) `inputs.smartctl` Add additional fields\n- [#15466](https://github.com/influxdata/telegraf/pull/15466) `processors.snmp_lookup` Return empty tag-map on error to avoid panic\n\n### Dependency Updates\n\n- [#15385](https://github.com/influxdata/telegraf/pull/15385) `deps` Bump cloud.google.com/go/storage from 1.40.0 to 1.41.0\n- [#15446](https://github.com/influxdata/telegraf/pull/15446) `deps` Bump github.com/awnumar/memguard from 0.22.4 to 0.22.5\n- [#15413](https://github.com/influxdata/telegraf/pull/15413) `deps` Bump github.com/fatih/color from 1.16.0 to 1.17.0\n- [#15410](https://github.com/influxdata/telegraf/pull/15410) `deps` Bump github.com/jhump/protoreflect from 1.15.6 to 1.16.0\n- [#15441](https://github.com/influxdata/telegraf/pull/15441) `deps` Bump github.com/lxc/incus v0.4.0 to v6.2.0\n- [#15381](https://github.com/influxdata/telegraf/pull/15381) `deps` Bump github.com/miekg/dns from 1.1.58 to 1.1.59\n- [#15444](https://github.com/influxdata/telegraf/pull/15444) `deps` Bump github.com/openzipkin/zipkin-go from 0.4.2 to 0.4.3\n- [#15412](https://github.com/influxdata/telegraf/pull/15412) `deps` Bump github.com/prometheus/common from 0.52.2 to 0.53.0\n- [#15362](https://github.com/influxdata/telegraf/pull/15362) `deps` Bump github.com/showwin/speedtest-go from 1.7.5 to 1.7.6\n- [#15382](https://github.com/influxdata/telegraf/pull/15382) `deps` Bump github.com/showwin/speedtest-go from 1.7.6 to 1.7.7\n- [#15384](https://github.com/influxdata/telegraf/pull/15384) `deps` Bump github.com/snowflakedb/gosnowflake from 1.7.2 to 1.10.0\n- [#15470](https://github.com/influxdata/telegraf/pull/15470) `deps` Bump go from v1.22.3 to v1.22.4\n- [#15411](https://github.com/influxdata/telegraf/pull/15411) `deps` Bump golang.org/x/crypto from 0.22.0 to 0.23.0\n- [#15447](https://github.com/influxdata/telegraf/pull/15447) `deps` Bump golang.org/x/net from 0.24.0 to 0.25.0\n- [#15383](https://github.com/influxdata/telegraf/pull/15383) `deps` Bump k8s.io/* from 0.29.3 to 0.30.1\n- [#15445](https://github.com/influxdata/telegraf/pull/15445) `deps` Bump modernc.org/sqlite from 1.29.10 to 1.30.0\n- [#15409](https://github.com/influxdata/telegraf/pull/15409) `deps` Bump modernc.org/sqlite from 1.29.5 to 1.29.10\n- [#15386](https://github.com/influxdata/telegraf/pull/15386) `deps` Bump super-linter/super-linter from 6.4.1 to 6.5.0\n- [#15408](https://github.com/influxdata/telegraf/pull/15408) `deps` Bump super-linter/super-linter from 6.5.0 to 6.5.1\n- [#15393](https://github.com/influxdata/telegraf/pull/15393) `deps` Switch to github.com/leodido/go-syslog\n- [#15403](https://github.com/influxdata/telegraf/pull/15403) `deps` Update OpenTelemetry dependencies\n\n## v1.30.3 [2024-05-20]\n\n### Bugfixes\n\n- [#15213](https://github.com/influxdata/telegraf/pull/15213) `http` Stop plugins from leaking file descriptors on telegraf reload\n- [#15312](https://github.com/influxdata/telegraf/pull/15312) `input.redis` Discard invalid errorstat lines\n- [#15317](https://github.com/influxdata/telegraf/pull/15317) `inputs.cloudwatch` Option to produce dense metrics\n- [#15259](https://github.com/influxdata/telegraf/pull/15259) `inputs.gnmi` Ensure path contains elements to avoid panic\n- [#15239](https://github.com/influxdata/telegraf/pull/15239) `inputs.http_listener_v2` Wrap timestamp parsing error messages\n- [#15323](https://github.com/influxdata/telegraf/pull/15323) `inputs.netflow` Log unknown fields only once\n- [#15212](https://github.com/influxdata/telegraf/pull/15212) `inputs.sysstat` Prevent default sadc_interval from increasing on reload\n- [#15223](https://github.com/influxdata/telegraf/pull/15223) `makefile` Use go's dependency checker for per platform builds\n- [#15224](https://github.com/influxdata/telegraf/pull/15224) `outputs.graphite` Handle local address without port correctly\n- [#15277](https://github.com/influxdata/telegraf/pull/15277) `outputs.loki` Option to sanitize label names\n- [#15346](https://github.com/influxdata/telegraf/pull/15346) `windows` Make sure to log the final error message on exit\n\n### Dependency Updates\n\n- [#15262](https://github.com/influxdata/telegraf/pull/15262) `deps` Bump cloud.google.com/go/bigquery from 1.59.1 to 1.61.0\n- [#15308](https://github.com/influxdata/telegraf/pull/15308) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.0 to 0.15.2\n- [#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\n- [#15349](https://github.com/influxdata/telegraf/pull/15349) `deps` Bump github.com/antchfx/xmlquery from 1.3.18 to 1.4.0\n- [#15263](https://github.com/influxdata/telegraf/pull/15263) `deps` Bump github.com/antchfx/xpath from 1.2.5 to 1.3.0\n- [#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\n- [#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\n- [#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\n- [#15307](https://github.com/influxdata/telegraf/pull/15307) `deps` Bump github.com/coocood/freecache from 1.2.3 to 1.2.4\n- [#15205](https://github.com/influxdata/telegraf/pull/15205) `deps` Bump github.com/google/cel-go from 0.18.1 to 0.20.1\n- [#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\n- [#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\n- [#15310](https://github.com/influxdata/telegraf/pull/15310) `deps` Bump github.com/pion/dtls/v2 from 2.2.10 to 2.2.11\n- [#15265](https://github.com/influxdata/telegraf/pull/15265) `deps` Bump github.com/prometheus/procfs from 0.13.0 to 0.14.0\n- [#15272](https://github.com/influxdata/telegraf/pull/15272) `deps` Bump github.com/shirou/gopsutil/v3 from v3.24.3 to v3.24.4\n- [#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\n- [#15351](https://github.com/influxdata/telegraf/pull/15351) `deps` Bump github.com/vmware/govmomi from 0.37.0 to 0.37.2\n- [#15327](https://github.com/influxdata/telegraf/pull/15327) `deps` Bump go from v1.22.2 to v1.22.3\n- [#15206](https://github.com/influxdata/telegraf/pull/15206) `deps` Bump golang.org/x/mod from 0.16.0 to 0.17.0\n- [#15266](https://github.com/influxdata/telegraf/pull/15266) `deps` Bump golang.org/x/sync from 0.6.0 to 0.7.0\n- [#15303](https://github.com/influxdata/telegraf/pull/15303) `deps` Bump golangci-lint from v1.57.2 to v1.58.0\n- [#15309](https://github.com/influxdata/telegraf/pull/15309) `deps` Bump google.golang.org/api from 0.171.0 to 0.177.0\n- [#15207](https://github.com/influxdata/telegraf/pull/15207) `deps` Bump super-linter/super-linter from 6.3.1 to 6.4.1\n- [#15316](https://github.com/influxdata/telegraf/pull/15316) `deps` Migrate to maintained gopacket library\n\n## v1.30.2 [2024-04-22]\n\n### Important Changes\n\n- [PR #15108](https://github.com/influxdata/telegraf/pull/15108) reverts the\n  behavior of `inputs.systemd_units` back to pre-v1.30.0 to only collect units\n  already loaded by systemd, i.e. not collecting disabled or static units. This\n  was necessary because using unspecific filters will cause significant load on\n  the system as systemd needs to read all unit-files matching the pattern in\n  each gather cycle. If you use specific patterns and want to collect non-loaded\n  units, please set the `collect_disabled_units` option to `true`.\n\n### Bugfixes\n\n- [#15054](https://github.com/influxdata/telegraf/pull/15054) `agent` Ensure import of required package for pprof support\n- [#15155](https://github.com/influxdata/telegraf/pull/15155) `inputs.diskio` Update path from /sys/block to /sys/class/block\n- [#15146](https://github.com/influxdata/telegraf/pull/15146) `inputs.modbus` Avoid overflow when calculating with uint16 addresses\n- [#15144](https://github.com/influxdata/telegraf/pull/15144) `inputs.nvidia` Include power limit field for v11\n- [#15178](https://github.com/influxdata/telegraf/pull/15178) `inputs.opcua` Make sure to always create a request\n- [#15176](https://github.com/influxdata/telegraf/pull/15176) `inputs.phpfpm` Check for error before continue processing\n- [#15195](https://github.com/influxdata/telegraf/pull/15195) `inputs.prometheus` Correctly handle host header\n- [#15078](https://github.com/influxdata/telegraf/pull/15078) `inputs.prometheus` Remove duplicate response_timeout option\n- [#15154](https://github.com/influxdata/telegraf/pull/15154) `inputs.sqlserver` Honor timezone on backup metrics\n- [#15129](https://github.com/influxdata/telegraf/pull/15129) `inputs.systemd_units` Reconnect if connection is lost\n- [#15108](https://github.com/influxdata/telegraf/pull/15108) `inputs.systemd_units` Revert to only gather loaded units by default\n- [#15132](https://github.com/influxdata/telegraf/pull/15132) `inputs.win_eventlog` Handle empty query correctly\n- [#15157](https://github.com/influxdata/telegraf/pull/15157) `outputs.opensearch` Correctly error during failures or disconnect\n- [#15196](https://github.com/influxdata/telegraf/pull/15196) `outputs.sql` Enable the use of krb5 with mssql driver\n- [#15168](https://github.com/influxdata/telegraf/pull/15168) `systemd` Remove 5 second timeout, use default (90 seconds)\n\n### Dependency Updates\n\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#15162](https://github.com/influxdata/telegraf/pull/15162) `deps` Bump github.com/go-sql-driver/mysql from 1.7.1 to 1.8.1\n- [#15084](https://github.com/influxdata/telegraf/pull/15084) `deps` Bump github.com/gophercloud/gophercloud from 1.9.0 to 1.11.0\n- [#15126](https://github.com/influxdata/telegraf/pull/15126) `deps` Bump github.com/jackc/pgtype from 1.14.2 to 1.14.3\n- [#15100](https://github.com/influxdata/telegraf/pull/15100) `deps` Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0\n- [#15127](https://github.com/influxdata/telegraf/pull/15127) `deps` Bump github.com/redis/go-redis/v9 from 9.2.1 to 9.5.1\n- [#15082](https://github.com/influxdata/telegraf/pull/15082) `deps` Bump github.com/shirou/gopsutil from v3.23.11 to v3.24.3\n- [#15085](https://github.com/influxdata/telegraf/pull/15085) `deps` Bump github.com/testcontainers/testcontainers-go from 0.27.0 to 0.29.1\n- [#15160](https://github.com/influxdata/telegraf/pull/15160) `deps` Bump github.com/vmware/govmomi from 0.33.1 to 0.37.0\n- [#15193](https://github.com/influxdata/telegraf/pull/15193) `deps` Bump golang.org/x/net from 0.22.0 to 0.23.0\n- [#15128](https://github.com/influxdata/telegraf/pull/15128) `deps` Bump golang.org/x/oauth2 from 0.18.0 to 0.19.0\n- [#15124](https://github.com/influxdata/telegraf/pull/15124) `deps` Bump k8s.io/client-go from 0.29.2 to 0.29.3\n- [#15123](https://github.com/influxdata/telegraf/pull/15123) `deps` Bump super-linter/super-linter from 6.3.0 to 6.3.1\n- [#15083](https://github.com/influxdata/telegraf/pull/15083) `deps` Bump tj-actions/changed-files from 43 to 44\n\n## v1.30.1 [2024-04-01]\n\n### Bugfixes\n\n- [#14966](https://github.com/influxdata/telegraf/pull/14966) `inputs.chrony` Remove chronyc dependency in documentation\n- [#15003](https://github.com/influxdata/telegraf/pull/15003) `inputs.diskio` Add missing udev properties\n- [#14979](https://github.com/influxdata/telegraf/pull/14979) `inputs.dns_query` Fill out additional record fields\n- [#15025](https://github.com/influxdata/telegraf/pull/15025) `inputs.dns_query` Include the canonical CNAME target\n- [#15007](https://github.com/influxdata/telegraf/pull/15007) `inputs.knx_listener` Ignore GroupValueRead requests\n- [#14959](https://github.com/influxdata/telegraf/pull/14959) `inputs.knx_listener` Reconnect after connection loss\n- [#15063](https://github.com/influxdata/telegraf/pull/15063) `inputs.mysql` Parse boolean values in metric v1 correctly\n- [#15012](https://github.com/influxdata/telegraf/pull/15012) `inputs.mysql` Use correct column-types for Percona 8 user stats\n- [#15023](https://github.com/influxdata/telegraf/pull/15023) `inputs.nvidia_smi` Add process info metrics\n- [#14977](https://github.com/influxdata/telegraf/pull/14977) `inputs.openstack` Resolve regression in block storage and server info\n- [#15036](https://github.com/influxdata/telegraf/pull/15036) `inputs.phpfpm` Add timeout for fcgi\n- [#15011](https://github.com/influxdata/telegraf/pull/15011) `inputs.ping` Add option to force ipv4\n- [#15021](https://github.com/influxdata/telegraf/pull/15021) `inputs.prometheus` Initialize logger of parser\n- [#14996](https://github.com/influxdata/telegraf/pull/14996) `inputs.smart` Improve regexp to support flags with a plus\n- [#14987](https://github.com/influxdata/telegraf/pull/14987) `inputs.systemd_units` Handle disabled multi-instance units correctly\n- [#14958](https://github.com/influxdata/telegraf/pull/14958) `outputs.bigquery` Add scope to bigquery and remove timeout context\n- [#14991](https://github.com/influxdata/telegraf/pull/14991) `secrets` Avoid count underflow by only counting initialized secrets\n- [#15040](https://github.com/influxdata/telegraf/pull/15040) `windows` Ensure watch-config is passed to Windows service\n\n### Dependency Updates\n\n- [#15071](https://github.com/influxdata/telegraf/pull/15071) `deps` Bump github.com/IBM/sarama from v1.42.2 to v1.43.1\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#15029](https://github.com/influxdata/telegraf/pull/15029) `deps` Bump github.com/docker/docker from 25.0.0+incompatible to 25.0.5+incompatible\n- [#15016](https://github.com/influxdata/telegraf/pull/15016) `deps` Bump github.com/jackc/pgtype from 1.14.0 to 1.14.2\n- [#14978](https://github.com/influxdata/telegraf/pull/14978) `deps` Bump github.com/jackc/pgx/v4 from 4.18.1 to 4.18.2\n- [#14968](https://github.com/influxdata/telegraf/pull/14968) `deps` Bump github.com/klauspost/compress from 1.17.6 to 1.17.7\n- [#14967](https://github.com/influxdata/telegraf/pull/14967) `deps` Bump github.com/pion/dtls/v2 from 2.2.8 to 2.2.10\n- [#15059](https://github.com/influxdata/telegraf/pull/15059) `deps` Bump github.com/prometheus-community/pro-bing from 0.3.0 to 0.4.0\n- [#14970](https://github.com/influxdata/telegraf/pull/14970) `deps` Bump github.com/prometheus/procfs from 0.12.0 to 0.13.0\n- [#15009](https://github.com/influxdata/telegraf/pull/15009) `deps` Bump github.com/stretchr/testify v1.8.4 to v1.9.0\n- [#15061](https://github.com/influxdata/telegraf/pull/15061) `deps` Bump go.step.sm/crypto from 0.43.0 to 0.44.1\n- [#15018](https://github.com/influxdata/telegraf/pull/15018) `deps` Bump golang.org/x/crypto from 0.20.0 to 0.21.0\n- [#15015](https://github.com/influxdata/telegraf/pull/15015) `deps` Bump gonum.org/v1/gonum from 0.14.0 to 0.15.0\n- [#15057](https://github.com/influxdata/telegraf/pull/15057) `deps` Bump google.golang.org/api from 0.165.0 to 0.171.0\n- [#14989](https://github.com/influxdata/telegraf/pull/14989) `deps` Bump google.golang.org/protobuf from 1.32.0 to 1.33.0\n- [#15013](https://github.com/influxdata/telegraf/pull/15013) `deps` Bump tj-actions/changed-files from 42 to 43\n\n## v1.30.0 [2024-03-11]\n\n### Deprecation Removals\n\nThis release removes the following deprecated plugins:\n\n- `inputs.cassandra` in [#14859](https://github.com/influxdata/telegraf/pull/14859)\n- `inputs.httpjson` in [#14860](https://github.com/influxdata/telegraf/pull/14860)\n- `inputs.io` in [#14861](https://github.com/influxdata/telegraf/pull/14861)\n- `inputs.jolokia` in [#14862](https://github.com/influxdata/telegraf/pull/14862)\n- `inputs.kafka_consumer_legacy` in [#14863](https://github.com/influxdata/telegraf/pull/14863)\n- `inputs.snmp_legacy` in [#14864](https://github.com/influxdata/telegraf/pull/14864)\n- `inputs.tcp_listener` in [#14865](https://github.com/influxdata/telegraf/pull/14865)\n- `inputs.udp_listener` in [#14866](https://github.com/influxdata/telegraf/pull/14866)\n- `outputs.riemann_legacy` in [#14867](https://github.com/influxdata/telegraf/pull/14867)\n\nFurthermore, the following deprecated plugin options are removed:\n\n- `mountpoints` of `inputs.disk` in [#14913](https://github.com/influxdata/telegraf/pull/14913)\n- `metric_buffer` of `inputs.mqtt_consumer` in [#14914](https://github.com/influxdata/telegraf/pull/14914)\n- `metric_buffer` of `inputs.nats_consumer` in [#14915](https://github.com/influxdata/telegraf/pull/14915)\n- `url` of `outputs.influxdb` in [#14916](https://github.com/influxdata/telegraf/pull/14916)\n\nReplacements do exist, so please migrate your configuration in case you are\nstill using one of those plugins. The `telegraf config migrate` command might\nbe able to assist with the procedure.\n\n### Important Changes\n\n- The default read-timeout of `inputs.syslog` of five seconds is not a sensible\n  default as the plugin will close the connection if the time between\n  consecutive messages exceeds the timeout.\n  [#14837](https://github.com/influxdata/telegraf/pull/14828) sets the timeout\n  to infinite (i.e zero) as this is the expected behavior.\n- With correctly sanitizing PostgreSQL addresses ([PR #14829](https://github.com/influxdata/telegraf/pull/14829))\n  the `server` tag value for a URI-format address might change in case it\n  contains spaces, backslashes or single-quotes in non-redacted parameters.\n\n### New Plugins\n\n- [#13739](https://github.com/influxdata/telegraf/pull/13739) `outputs.zabbix` Add Zabbix plugin\n- [#14474](https://github.com/influxdata/telegraf/pull/14474) `serializers.binary` Add binary serializer\n- [#14223](https://github.com/influxdata/telegraf/pull/14223) `processors.snmp_lookup` Add SNMP lookup processor\n\n### Features\n\n- [#14491](https://github.com/influxdata/telegraf/pull/14491) Add loongarch64 nightly and release builds\n- [#14882](https://github.com/influxdata/telegraf/pull/14882) `agent` Add option to skip re-running processors after aggregators\n- [#14676](https://github.com/influxdata/telegraf/pull/14676) `common.opcua` Add debug info for nodes not in server namespace\n- [#14743](https://github.com/influxdata/telegraf/pull/14743) `http` Allow secrets in headers\n- [#14806](https://github.com/influxdata/telegraf/pull/14806) `inputs.aerospike` Deprecate plugin\n- [#14872](https://github.com/influxdata/telegraf/pull/14872) `inputs.amd_rocm_smi` Add startup_error_behavior config option\n- [#14673](https://github.com/influxdata/telegraf/pull/14673) `inputs.chrony` Allow to collect additional metrics\n- [#14629](https://github.com/influxdata/telegraf/pull/14629) `inputs.chrony` Remove chronyc dependency\n- [#14585](https://github.com/influxdata/telegraf/pull/14585) `inputs.kafka_consumer` Mark messages that failed parsing\n- [#14507](https://github.com/influxdata/telegraf/pull/14507) `inputs.kernel` Add Pressure Stall Information\n- [#14764](https://github.com/influxdata/telegraf/pull/14764) `inputs.modbus` Add workaround for unusual string-byte locations\n- [#14625](https://github.com/influxdata/telegraf/pull/14625) `inputs.net` Add speed metric\n- [#14680](https://github.com/influxdata/telegraf/pull/14680) `inputs.nvidia_smi` Add startup_error_behavior config option\n- [#14424](https://github.com/influxdata/telegraf/pull/14424) `inputs.prometheus` Add internal metrics\n- [#14661](https://github.com/influxdata/telegraf/pull/14661) `inputs.prometheus` Add option to limit body length\n- [#14702](https://github.com/influxdata/telegraf/pull/14702) `inputs.redfish` Allow secrets for username/password configuration\n- [#14613](https://github.com/influxdata/telegraf/pull/14613) `inputs.smart` Add a device_type tag to differentiate disks behind a RAID controller\n- [#14792](https://github.com/influxdata/telegraf/pull/14792) `inputs.sqlserver` Add stolen target memory ratio\n- [#14814](https://github.com/influxdata/telegraf/pull/14814) `inputs.systemd_units` Allow to query unloaded/disabled units\n- [#14539](https://github.com/influxdata/telegraf/pull/14539) `inputs.systemd_units` Introduce show subcommand for additional data\n- [#14684](https://github.com/influxdata/telegraf/pull/14684) `inputs.win_services` Make service selection case-insensitive\n- [#14628](https://github.com/influxdata/telegraf/pull/14628) `outputs.graphite` Allow to set the local address to bind\n- [#14236](https://github.com/influxdata/telegraf/pull/14236) `outputs.nats` Introduce NATS Jetstream option\n- [#14658](https://github.com/influxdata/telegraf/pull/14658) `outputs.nebius_cloud_monitoring` Add service configuration setting\n- [#14836](https://github.com/influxdata/telegraf/pull/14836) `outputs.websocket` Allow specifying secrets in headers\n- [#14870](https://github.com/influxdata/telegraf/pull/14870) `serializers.csv` Allow specifying fixed column order\n\n### Bugfixes\n\n- [#14840](https://github.com/influxdata/telegraf/pull/14840) `agent` Catch panics in inputs goroutine\n- [#14858](https://github.com/influxdata/telegraf/pull/14858) `config` Reword error message about missing config option\n- [#14874](https://github.com/influxdata/telegraf/pull/14874) `inputs.docker_log` Use correct name when matching container\n- [#14951](https://github.com/influxdata/telegraf/pull/14951) `inputs.gnmi` Add option to guess path tag from subscription\n- [#14953](https://github.com/influxdata/telegraf/pull/14953) `inputs.gnmi` Handle canonical field-name correctly\n- [#14910](https://github.com/influxdata/telegraf/pull/14910) `inputs.netflow` Fallback to IPFIX mappings for Netflow v9\n- [#14852](https://github.com/influxdata/telegraf/pull/14852) `inputs.phpfpm` Continue despite erroneous sockets\n- [#14871](https://github.com/influxdata/telegraf/pull/14871) `inputs.prometheus` List namespaces only when filtering by namespace\n- [#14606](https://github.com/influxdata/telegraf/pull/14606) `parsers.prometheus` Do not touch input data for protocol-buffers\n- [#14880](https://github.com/influxdata/telegraf/pull/14880) `processors.override` Correct TOML tag name\n- [#14937](https://github.com/influxdata/telegraf/pull/14937) `statefile` Ensure valid statefile in package\n\n### Dependency Updates\n\n- [#14931](https://github.com/influxdata/telegraf/pull/14931) `deps` Bump all github.com/aws/aws-sdk-go-v2 dependencies\n- [#14894](https://github.com/influxdata/telegraf/pull/14894) `deps` Bump cloud.google.com/go/bigquery from 1.58.0 to 1.59.1\n- [#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\n- [#14949](https://github.com/influxdata/telegraf/pull/14949) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.15.0 to 2.15.2\n- [#14929](https://github.com/influxdata/telegraf/pull/14929) `deps` Bump github.com/eclipse/paho.golang from 0.20.0 to 0.21.0\n- [#14892](https://github.com/influxdata/telegraf/pull/14892) `deps` Bump github.com/microsoft/go-mssqldb from 1.6.0 to 1.7.0\n- [#14923](https://github.com/influxdata/telegraf/pull/14923) `deps` Bump github.com/netsampler/goflow2 from v1.3.6 to v2.1.2\n- [#14895](https://github.com/influxdata/telegraf/pull/14895) `deps` Bump github.com/peterbourgon/unixtransport from 0.0.3 to 0.0.4\n- [#14933](https://github.com/influxdata/telegraf/pull/14933) `deps` Bump github.com/prometheus/client_model from 0.5.0 to 0.6.0\n- [#14857](https://github.com/influxdata/telegraf/pull/14857) `deps` Bump github.com/srebhan/cborquery from v0.0.0-20230626165538-38be85b82316 to v1.0.1\n- [#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\n- [#14893](https://github.com/influxdata/telegraf/pull/14893) `deps` Bump go.mongodb.org/mongo-driver from 1.13.1 to 1.14.0\n- [#14891](https://github.com/influxdata/telegraf/pull/14891) `deps` Bump golang.org/x/crypto from 0.19.0 to 0.20.0\n- [#14930](https://github.com/influxdata/telegraf/pull/14930) `deps` Bump modernc.org/sqlite from 1.28.0 to 1.29.2\n- [#14897](https://github.com/influxdata/telegraf/pull/14897) `deps` Bump super-linter/super-linter from 6.1.1 to 6.2.0\n- [#14934](https://github.com/influxdata/telegraf/pull/14934) `deps` Bump super-linter/super-linter from 6.2.0 to 6.3.0\n\n## v1.29.5 [2024-02-20]\n\n### Bugfixes\n\n- [#14669](https://github.com/influxdata/telegraf/pull/14669) `inputs.filecount` Respect symlink files with FollowSymLinks\n- [#14838](https://github.com/influxdata/telegraf/pull/14838) `inputs.gnmi` Normalize path for inline origin handling\n- [#14679](https://github.com/influxdata/telegraf/pull/14679) `inputs.kafka_consumer` Fix typo of msg_headers_as_tags\n- [#14707](https://github.com/influxdata/telegraf/pull/14707) `inputs.postgresql_extensible` Add support for bool tags\n- [#14659](https://github.com/influxdata/telegraf/pull/14659) `inputs.redfish` Resolve iLO4 fan data\n- [#14665](https://github.com/influxdata/telegraf/pull/14665) `inputs.snmp_trap` Enable SHA ciphers\n- [#14635](https://github.com/influxdata/telegraf/pull/14635) `inputs.vsphere` Use guest.guestId value if set for guest name\n- [#14752](https://github.com/influxdata/telegraf/pull/14752) `outputs.mqtt` Retry metrics for server timeout\n- [#14770](https://github.com/influxdata/telegraf/pull/14770) `processors.execd` Accept tracking metrics instead of dropping them\n- [#14832](https://github.com/influxdata/telegraf/pull/14832) `processors.unpivot` Handle tracking metrics correctly\n- [#14654](https://github.com/influxdata/telegraf/pull/14654) `rpm` Ensure telegraf is installed after useradd\n\n### Dependency Updates\n\n- [#14690](https://github.com/influxdata/telegraf/pull/14690) `deps` Bump cloud.google.com/go/bigquery from 1.57.1 to 1.58.0\n- [#14772](https://github.com/influxdata/telegraf/pull/14772) `deps` Bump cloud.google.com/go/pubsub from 1.33.0 to 1.36.1\n- [#14819](https://github.com/influxdata/telegraf/pull/14819) `deps` Bump cloud.google.com/go/storage from 1.36.0 to 1.38.0\n- [#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\n- [#14845](https://github.com/influxdata/telegraf/pull/14845) `deps` Bump github.com/DATA-DOG/go-sqlmock from 1.5.0 to 1.5.2\n- [#14820](https://github.com/influxdata/telegraf/pull/14820) `deps` Bump github.com/IBM/sarama from 1.42.1 to 1.42.2\n- [#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\n- [#14687](https://github.com/influxdata/telegraf/pull/14687) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.14.0 to 2.15.0\n- [#14769](https://github.com/influxdata/telegraf/pull/14769) `deps` Bump github.com/eclipse/paho.golang from 0.11.0 to 0.20.0\n- [#14775](https://github.com/influxdata/telegraf/pull/14775) `deps` Bump github.com/google/uuid from 1.5.0 to 1.6.0\n- [#14686](https://github.com/influxdata/telegraf/pull/14686) `deps` Bump github.com/gopcua/opcua from 0.4.0 to 0.5.3\n- [#14848](https://github.com/influxdata/telegraf/pull/14848) `deps` Bump github.com/gophercloud/gophercloud from 1.7.0 to 1.9.0\n- [#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\n- [#14816](https://github.com/influxdata/telegraf/pull/14816) `deps` Bump github.com/jhump/protoreflect from 1.15.4 to 1.15.6\n- [#14773](https://github.com/influxdata/telegraf/pull/14773) `deps` Bump github.com/klauspost/compress from 1.17.4 to 1.17.6\n- [#14817](https://github.com/influxdata/telegraf/pull/14817) `deps` Bump github.com/miekg/dns from 1.1.57 to 1.1.58\n- [#14766](https://github.com/influxdata/telegraf/pull/14766) `deps` Bump github.com/showwin/speedtest-go from 1.6.7 to 1.6.10\n- [#14765](https://github.com/influxdata/telegraf/pull/14765) `deps` Bump github.com/urfave/cli/v2 from 2.25.7 to 2.27.1\n- [#14818](https://github.com/influxdata/telegraf/pull/14818) `deps` Bump go.opentelemetry.io/collector/pdata from 1.0.1 to 1.1.0\n- [#14768](https://github.com/influxdata/telegraf/pull/14768) `deps` Bump golang.org/x/oauth2 from 0.16.0 to 0.17.0\n- [#14849](https://github.com/influxdata/telegraf/pull/14849) `deps` Bump google.golang.org/api from 0.162.0 to 0.165.0\n- [#14847](https://github.com/influxdata/telegraf/pull/14847) `deps` Bump google.golang.org/grpc from 1.61.0 to 1.61.1\n- [#14689](https://github.com/influxdata/telegraf/pull/14689) `deps` Bump k8s.io/apimachinery from 0.29.0 to 0.29.1\n- [#14767](https://github.com/influxdata/telegraf/pull/14767) `deps` Bump k8s.io/client-go from 0.29.0 to 0.29.1\n- [#14846](https://github.com/influxdata/telegraf/pull/14846) `deps` Bump k8s.io/client-go from 0.29.1 to 0.29.2\n- [#14850](https://github.com/influxdata/telegraf/pull/14850) `deps` Bump super-linter/super-linter from 6.0.0 to 6.1.1\n- [#14771](https://github.com/influxdata/telegraf/pull/14771) `deps` Bump tj-actions/changed-files from 41 to 42\n- [#14757](https://github.com/influxdata/telegraf/pull/14757) `deps` Get rid of golang.org/x/exp and use stable versions instead\n- [#14753](https://github.com/influxdata/telegraf/pull/14753) `deps` Use github.com/coreos/go-systemd/v22 instead of git version\n\n## v1.29.4 [2024-01-31]\n\n### Bugfixes\n\n- [#14619](https://github.com/influxdata/telegraf/pull/14619) `inputs.snmp_trap` Handle octet strings\n- [#14649](https://github.com/influxdata/telegraf/pull/14649) `inputs.temp` Fix regression in metric formats\n- [#14655](https://github.com/influxdata/telegraf/pull/14655) `processors.parser` Drop tracking metrics when not carried forward\n\n### Dependency Updates\n\n- [#14651](https://github.com/influxdata/telegraf/pull/14651) `deps` Bump all AWS dependencies\n- [#14642](https://github.com/influxdata/telegraf/pull/14642) `deps` Bump github.com/compose-spec/compose-go from 1.20.0 to 1.20.2\n- [#14641](https://github.com/influxdata/telegraf/pull/14641) `deps` Bump github.com/gosnmp/gosnmp from 1.36.1 to 1.37.0\n- [#14643](https://github.com/influxdata/telegraf/pull/14643) `deps` Bump github.com/microsoft/go-mssqldb from 1.5.0 to 1.6.0\n- [#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\n- [#14640](https://github.com/influxdata/telegraf/pull/14640) `deps` Bump github.com/yuin/goldmark from 1.5.6 to 1.6.0\n\n## v1.29.3 [2024-01-29]\n\n### Bugfixes\n\n- [#14627](https://github.com/influxdata/telegraf/pull/14627) `common.encoding` Remove locally-defined errors and use upstream ones\n- [#14553](https://github.com/influxdata/telegraf/pull/14553) `inputs.gnmi` Refactor alias handling to prevent clipping\n- [#14575](https://github.com/influxdata/telegraf/pull/14575) `inputs.temp` Recover pre-v1.22.4 temperature sensor readings\n- [#14526](https://github.com/influxdata/telegraf/pull/14526) `inputs.win_perf_counters` Check errors post-collection for skip\n- [#14570](https://github.com/influxdata/telegraf/pull/14570) `inputs.win_perf_counters` Ignore PdhCstatusNoInstance as well\n- [#14519](https://github.com/influxdata/telegraf/pull/14519) `outputs.iotdb` Handle paths that contain illegal characters\n- [#14604](https://github.com/influxdata/telegraf/pull/14604) `outputs.loki` Do not close body before reading it\n- [#14582](https://github.com/influxdata/telegraf/pull/14582) `outputs.mqtt` Preserve leading slash in topic\n\n### Dependency Updates\n\n- [#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\n- [#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\n- [#14577](https://github.com/influxdata/telegraf/pull/14577) `deps` Bump github.com/clarify/clarify-go from 0.2.4 to 0.3.1\n- [#14607](https://github.com/influxdata/telegraf/pull/14607) `deps` Bump github.com/docker/docker from 24.0.7+incompatible to 25.0.0+incompatible\n- [#14545](https://github.com/influxdata/telegraf/pull/14545) `deps` Bump github.com/docker/go-connections from 0.4.0 to 0.5.0\n- [#14609](https://github.com/influxdata/telegraf/pull/14609) `deps` Bump github.com/fatih/color from 1.15.0 to 1.16.0\n- [#14546](https://github.com/influxdata/telegraf/pull/14546) `deps` Bump github.com/gorilla/mux from 1.8.0 to 1.8.1\n- [#14562](https://github.com/influxdata/telegraf/pull/14562) `deps` Bump github.com/intel/powertelemetry from 1.0.0 to 1.0.1\n- [#14611](https://github.com/influxdata/telegraf/pull/14611) `deps` Bump github.com/nats-io/nats.go from 1.31.0 to 1.32.0\n- [#14544](https://github.com/influxdata/telegraf/pull/14544) `deps` Bump github.com/prometheus/common from 0.44.0 to 0.45.0\n- [#14608](https://github.com/influxdata/telegraf/pull/14608) `deps` Bump github.com/testcontainers/testcontainers-go from 0.26.0 to 0.27.0\n- [#14573](https://github.com/influxdata/telegraf/pull/14573) `deps` Bump github.com/vapourismo/knx-go from v0.0.0-20220829185957-fb5458a5389d to 20240107135439-816b70397a00\n- [#14574](https://github.com/influxdata/telegraf/pull/14574) `deps` Bump go.opentelemetry.io/collector/pdata from 1.0.0-rcv0016 to 1.0.1\n- [#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\n- [#14543](https://github.com/influxdata/telegraf/pull/14543) `deps` Bump k8s.io/client-go from 0.28.3 to 0.29.0\n- [#14610](https://github.com/influxdata/telegraf/pull/14610) `deps` Bump modernc.org/sqlite from 1.24.0 to 1.28.0\n\n## v1.29.2 [2024-01-08]\n\n### Bugfixes\n\n- [#14522](https://github.com/influxdata/telegraf/pull/14522) `common.kafka` Correctly set gssapi username/password\n- [#14462](https://github.com/influxdata/telegraf/pull/14462) `inputs.phpfpm` Add pid field to differentiate metrics\n- [#14489](https://github.com/influxdata/telegraf/pull/14489) `inputs.phpfpm` Use logger without causing panic\n- [#14493](https://github.com/influxdata/telegraf/pull/14493) `inputs.procstat` Correctly set tags on procstat_lookup\n- [#14447](https://github.com/influxdata/telegraf/pull/14447) `inputs.upsd` Add additional fields to upsd from NUT\n- [#14463](https://github.com/influxdata/telegraf/pull/14463) `inputs.vsphere` Resolve occasional serverFault\n- [#14458](https://github.com/influxdata/telegraf/pull/14458) `outputs.bigquery` Ignore fields containing NaN or infinity\n- [#14481](https://github.com/influxdata/telegraf/pull/14481) `outputs.influxdb` Support setting Host header\n- [#14481](https://github.com/influxdata/telegraf/pull/14481) `outputs.influxdb_v2` Support setting Host header\n- [#14471](https://github.com/influxdata/telegraf/pull/14471) `outputs.prometheus_client` Always default to TCP\n- [#14460](https://github.com/influxdata/telegraf/pull/14460) `processors.filter` Rename processors.Filter -> processors.filter\n- [#14523](https://github.com/influxdata/telegraf/pull/14523) `processors.starlark` Use tracking ID to identify tracking metrics\n- [#14517](https://github.com/influxdata/telegraf/pull/14517) `systemd` Allow notify access from all\n\n### Dependency Updates\n\n- [#14525](https://github.com/influxdata/telegraf/pull/14525) `deps` Bump collectd.org from v0.5.0 to v0.6.0\n- [#14506](https://github.com/influxdata/telegraf/pull/14506) `deps` Bump github.com/Azure/azure-kusto-go from 0.13.1 to 0.15.0\n- [#14483](https://github.com/influxdata/telegraf/pull/14483) `deps` Bump github.com/containerd/containerd from 1.7.7 to 1.7.11\n- [#14476](https://github.com/influxdata/telegraf/pull/14476) `deps` Bump github.com/djherbis/times from 1.5.0 to 1.6.0\n- [#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\n- [#14478](https://github.com/influxdata/telegraf/pull/14478) `deps` Bump github.com/google/uuid from 1.4.0 to 1.5.0\n- [#14477](https://github.com/influxdata/telegraf/pull/14477) `deps` Bump github.com/jhump/protoreflect from 1.15.3 to 1.15.4\n- [#14504](https://github.com/influxdata/telegraf/pull/14504) `deps` Bump github.com/pion/dtls/v2 from 2.2.7 to 2.2.8\n- [#14503](https://github.com/influxdata/telegraf/pull/14503) `deps` Bump github.com/prometheus/prometheus from 0.48.0 to 0.48.1\n- [#14515](https://github.com/influxdata/telegraf/pull/14515) `deps` Bump github.com/sijms/go-ora/v2 from 2.7.18 to 2.8.4\n- [#14475](https://github.com/influxdata/telegraf/pull/14475) `deps` Bump go.mongodb.org/mongo-driver from 1.12.1 to 1.13.1\n- [#14480](https://github.com/influxdata/telegraf/pull/14480) `deps` Bump golang.org/x/crypto from 0.16.0 to 0.17.0\n- [#14479](https://github.com/influxdata/telegraf/pull/14479) `deps` Bump golang.org/x/net from 0.17.0 to 0.19.0\n- [#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\n\n## v1.29.1 [2023-12-13]\n\n### Bugfixes\n\n- [#14443](https://github.com/influxdata/telegraf/pull/14443) `inputs.clickhouse` Omit zookeeper metrics on clickhouse cloud\n- [#14430](https://github.com/influxdata/telegraf/pull/14430) `inputs.php-fpm` Parse JSON output\n- [#14440](https://github.com/influxdata/telegraf/pull/14440) `inputs.procstat` Revert unintended renaming of systemd_unit option\n\n### Dependency Updates\n\n- [#14435](https://github.com/influxdata/telegraf/pull/14435) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.5 to 3.4.6\n- [#14433](https://github.com/influxdata/telegraf/pull/14433) `deps` Bump github.com/klauspost/compress from 1.17.3 to 1.17.4\n- [#14432](https://github.com/influxdata/telegraf/pull/14432) `deps` Bump github.com/openzipkin/zipkin-go from 0.4.1 to 0.4.2\n- [#14431](https://github.com/influxdata/telegraf/pull/14431) `deps` Bump github.com/tidwall/gjson from 1.14.4 to 1.17.0\n- [#14441](https://github.com/influxdata/telegraf/pull/14441) `deps` Update all github.com/aws/aws-sdk-go-v2 dependencies\n\n## v1.29.0 [2023-12-11]\n\n### Important Changes\n\n- Removed useless, all-zero fields in `inputs.procstat`. Up to now, Telegraf\n  reports the fields `cpu_time_guest`, `cpu_time_guest_nice`, `cpu_time_idle`,\n  `cpu_time_irq`, `cpu_time_nice`, `cpu_time_soft_irq` and `cpu_time_steal`\n  which are never set by the underlying library. As a consequence those fields\n  were always zero. [#14224](https://github.com/influxdata/telegraf/pull/14224)\n  removes those useless fields. In case you reference them, please adapt your\n  queries!\n\n### New Plugins\n\n- [#13995](https://github.com/influxdata/telegraf/pull/13995) `inputs.ldap` Add LDAP input plugin supporting OpenLDAP and 389ds\n- [#11958](https://github.com/influxdata/telegraf/pull/11958) `outputs.opensearch` Add OpenSearch output plugin\n- [#14330](https://github.com/influxdata/telegraf/pull/14330) `processors.filter` Add filter processor plugin\n- [#13657](https://github.com/influxdata/telegraf/pull/13657) `secretstores` Add systemd-credentials plugin\n\n### Features\n\n- [#14361](https://github.com/influxdata/telegraf/pull/14361) `agent` Allow separators for namepass and namedrop filters\n- [#14062](https://github.com/influxdata/telegraf/pull/14062) `aggregators.final` Allow to specify output strategy\n- [#14103](https://github.com/influxdata/telegraf/pull/14103) `common.http` Add support for connecting over unix-socket\n- [#14345](https://github.com/influxdata/telegraf/pull/14345) `common.opcua` Add option to include OPC-UA DataType as a field\n- [#14012](https://github.com/influxdata/telegraf/pull/14012) `config` Deprecate `fieldpass` and `fielddrop` modifiers\n- [#14004](https://github.com/influxdata/telegraf/pull/14004) `input.intel_pmt` Add pci_bdf tag to uniquely identify GPUs and other peripherals\n- [#14001](https://github.com/influxdata/telegraf/pull/14001) `inputs.amqp_consumer` Add secretstore support for username and password\n- [#13894](https://github.com/influxdata/telegraf/pull/13894) `inputs.docker` Add disk usage\n- [#14308](https://github.com/influxdata/telegraf/pull/14308) `inputs.dpdk` Add options to customize error-behavior and metric layout\n- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.elasticsearch` Use HTTPClientConfig struct\n- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.elasticsearch_query` Use HTTPClientConfig struct\n- [#14091](https://github.com/influxdata/telegraf/pull/14091) `inputs.gnmi` Rework plugin\n- [#14189](https://github.com/influxdata/telegraf/pull/14189) `inputs.http_response` Add body form config option\n- [#14363](https://github.com/influxdata/telegraf/pull/14363) `inputs.intel_powerstat` Extract business logic to external library\n- [#13924](https://github.com/influxdata/telegraf/pull/13924) `inputs.kafka_consumer` Add message headers as metric tags\n- [#14320](https://github.com/influxdata/telegraf/pull/14320) `inputs.kafka_consumer` Add option to set metric name from message header\n- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.kibana` Use HTTPClientConfig struct\n- [#13993](https://github.com/influxdata/telegraf/pull/13993) `inputs.kube_inventory` Support filtering pods and nodes by node name\n- [#13996](https://github.com/influxdata/telegraf/pull/13996) `inputs.kube_inventory` Support using kubelet to get pods data\n- [#14092](https://github.com/influxdata/telegraf/pull/14092) `inputs.ldap` Collect additional fields\n- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.logstash` Use HTTPClientConfig struct\n- [#14145](https://github.com/influxdata/telegraf/pull/14145) `inputs.modbus` Add support for string fields\n- [#14375](https://github.com/influxdata/telegraf/pull/14375) `inputs.nats_consumer` Add nkey-seed-file authentication\n- [#13923](https://github.com/influxdata/telegraf/pull/13923) `inputs.opcua_listener` Add monitoring params\n- [#14214](https://github.com/influxdata/telegraf/pull/14214) `inputs.openweathermap` Add per-city query scheme for current weather\n- [#13417](https://github.com/influxdata/telegraf/pull/13417) `inputs.procstat` Obtain process information through supervisor\n- [#13991](https://github.com/influxdata/telegraf/pull/13991) `inputs.rabbitmq` Add secretstore support for username and password\n- [#14143](https://github.com/influxdata/telegraf/pull/14143) `inputs.redfish` Allow specifying which metrics to collect\n- [#14111](https://github.com/influxdata/telegraf/pull/14111) `inputs.snmp` Hint to use source tag\n- [#14172](https://github.com/influxdata/telegraf/pull/14172) `inputs.socket_listener` Add vsock support to socket listener and writer\n- [#13978](https://github.com/influxdata/telegraf/pull/13978) `inputs.sql` Add Oracle driver\n- [#14200](https://github.com/influxdata/telegraf/pull/14200) `inputs.sql` Add IBM Netezza driver\n- [#14073](https://github.com/influxdata/telegraf/pull/14073) `inputs.win_service` Reduce required rights to GENERIC_READ\n- [#14401](https://github.com/influxdata/telegraf/pull/14401) `migrations` Add migration for fieldpass and fielddrop\n- [#14114](https://github.com/influxdata/telegraf/pull/14114) `migrations` Add migration for inputs.jolokia\n- [#14122](https://github.com/influxdata/telegraf/pull/14122) `migrations` Add migration for inputs.kafka_consumer_legacy\n- [#14123](https://github.com/influxdata/telegraf/pull/14123) `migrations` Add migration for inputs.snmp_legacy\n- [#14119](https://github.com/influxdata/telegraf/pull/14119) `migrations` Add migration for inputs.tcp_listener\n- [#14120](https://github.com/influxdata/telegraf/pull/14120) `migrations` Add migration for inputs.udp_listener\n- [#14121](https://github.com/influxdata/telegraf/pull/14121) `migrations` Add migration for outputs.riemann_legacy\n- [#14141](https://github.com/influxdata/telegraf/pull/14141) `migrations` Add option migration for inputs.disk\n- [#14233](https://github.com/influxdata/telegraf/pull/14233) `migrations` Add option migration for inputs.mqtt_consumer\n- [#14234](https://github.com/influxdata/telegraf/pull/14234) `migrations` Add option migration for inputs.nats_consumer\n- [#14341](https://github.com/influxdata/telegraf/pull/14341) `migrations` Add option migration for outputs.influxdb\n- [#14047](https://github.com/influxdata/telegraf/pull/14047) `outputs.azure_data_explorer` Set user agent string\n- [#14342](https://github.com/influxdata/telegraf/pull/14342) `outputs.bigquery` Allow to add metrics in one compact table\n- [#14086](https://github.com/influxdata/telegraf/pull/14086) `outputs.bigquery` Make project no longer a required field\n- [#13672](https://github.com/influxdata/telegraf/pull/13672) `outputs.exec` Add ability to exec command once per metric\n- [#14108](https://github.com/influxdata/telegraf/pull/14108) `outputs.prometheus_client` Support listening on vsock\n- [#14172](https://github.com/influxdata/telegraf/pull/14172) `outputs.socket_writer` Add vsock support to socket listener and writer\n- [#14017](https://github.com/influxdata/telegraf/pull/14017) `outputs.stackdriver` Add metric type config options\n- [#14275](https://github.com/influxdata/telegraf/pull/14275) `outputs.stackdriver` Enable histogram support\n- [#14136](https://github.com/influxdata/telegraf/pull/14136) `outputs.wavefront` Use common/http to configure http client\n- [#13903](https://github.com/influxdata/telegraf/pull/13903) `parsers.avro` Allow connection to https schema registry\n- [#13914](https://github.com/influxdata/telegraf/pull/13914) `parsers.avro` Get metric name from the message field\n- [#13945](https://github.com/influxdata/telegraf/pull/13945) `parsers.avro` Support multiple modes for union handling\n- [#14065](https://github.com/influxdata/telegraf/pull/14065) `processors.dedup` Add state persistence between runs\n- [#13971](https://github.com/influxdata/telegraf/pull/13971) `processors.regex` Allow batch transforms using named groups\n- [#13998](https://github.com/influxdata/telegraf/pull/13998) `secrets` Add unprotected secret implementation\n\n### Bugfixes\n\n- [#14331](https://github.com/influxdata/telegraf/pull/14331) `common.oauth` Initialize EndpointParams to avoid panic with audience settings\n- [#14350](https://github.com/influxdata/telegraf/pull/14350) `inputs.http` Use correct token variable\n- [#14420](https://github.com/influxdata/telegraf/pull/14420) `inputs.intel_powerstat` Fix unit tests to work on every CPU/platform\n- [#14388](https://github.com/influxdata/telegraf/pull/14388) `inputs.modbus` Split large request correctly at field borders\n- [#14373](https://github.com/influxdata/telegraf/pull/14373) `inputs.netflow` Handle malformed inputs gracefully\n- [#14394](https://github.com/influxdata/telegraf/pull/14394) `inputs.s7comm` Reconnect if query fails\n- [#14357](https://github.com/influxdata/telegraf/pull/14357) `inputs.tail` Retry opening file after permission denied\n- [#14419](https://github.com/influxdata/telegraf/pull/14419) `license` Correct spelling of jmhodges/clock license\n- [#14416](https://github.com/influxdata/telegraf/pull/14416) `outputs.bigquery` Correct use of auto-detected project ID\n- [#14340](https://github.com/influxdata/telegraf/pull/14340) `outputs.opensearch` Expose TLS setting correctly\n- [#14021](https://github.com/influxdata/telegraf/pull/14021) `outputs.opensearch` Migrate to new secrets API\n- [#14232](https://github.com/influxdata/telegraf/pull/14232) `outputs.prometheus_client` Ensure v1 collector data expires promptly\n- [#13961](https://github.com/influxdata/telegraf/pull/13961) `parsers.avro` Clean up Warnf error wrapping error\n- [#13939](https://github.com/influxdata/telegraf/pull/13939) `parsers.avro` Attempt to read CA cert file only if filename is not empty string\n- [#14351](https://github.com/influxdata/telegraf/pull/14351) `parsers.json v2` Correct wrong name of config option\n- [#14344](https://github.com/influxdata/telegraf/pull/14344) `parsers.json_v2` Reset state before parsing\n- [#14395](https://github.com/influxdata/telegraf/pull/14395) `processors.starlark` Avoid negative refcounts for tracking metrics\n- [#14137](https://github.com/influxdata/telegraf/pull/14137) `processors.starlark` Maintain tracking information post-apply\n\n### Dependency Updates\n\n- [#14352](https://github.com/influxdata/telegraf/pull/14352) `deps` Bump cloud.google.com/go/bigquery from 1.56.0 to 1.57.1\n- [#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\n- [#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\n- [#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\n- [#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\n- [#14382](https://github.com/influxdata/telegraf/pull/14382) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.0.0 to 5.2.0\n- [#14385](https://github.com/influxdata/telegraf/pull/14385) `deps` Bump github.com/IBM/sarama from 1.41.3 to 1.42.1\n- [#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\n- [#14383](https://github.com/influxdata/telegraf/pull/14383) `deps` Bump github.com/jackc/pgconn from 1.14.0 to 1.14.1\n- [#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\n- [#14321](https://github.com/influxdata/telegraf/pull/14321) `deps` Bump github.com/prometheus/prometheus from 0.46.0 to 0.48.0\n- [#14325](https://github.com/influxdata/telegraf/pull/14325) `deps` Bump github.com/vmware/govmomi from 0.32.0 to 0.33.1\n- [#14353](https://github.com/influxdata/telegraf/pull/14353) `deps` Bump golang.org/x/text from 0.13.0 to 0.14.0\n- [#14322](https://github.com/influxdata/telegraf/pull/14322) `deps` Bump k8s.io/api from 0.28.3 to 0.28.4\n- [#14349](https://github.com/influxdata/telegraf/pull/14349) `deps` Point kafka dependency to IBM organization\n\n## v1.28.5 [2023-11-15]\n\n### Bugfixes\n\n- [#14294](https://github.com/influxdata/telegraf/pull/14294) `inputs.ecs` Correct v4 metadata URLs\n- [#14274](https://github.com/influxdata/telegraf/pull/14274) `inputs.intel_rdt` Do not fail on missing PIDs\n- [#14283](https://github.com/influxdata/telegraf/pull/14283) `inputs.s7comm` Truncate strings to reported length\n- [#14296](https://github.com/influxdata/telegraf/pull/14296) `parsers.json_v2` Log inner errors\n\n### Dependency Updates\n\n- [#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\n- [#14286](https://github.com/influxdata/telegraf/pull/14286) `deps` Bump github.com/Masterminds/semver/v3 from 3.2.0 to 3.2.1\n- [#14285](https://github.com/influxdata/telegraf/pull/14285) `deps` Bump golang.org/x/sync from 0.4.0 to 0.5.0\n- [#14289](https://github.com/influxdata/telegraf/pull/14289) `deps` Bump golang.org/x/mod from 0.13.0 to 0.14.0\n- [#14288](https://github.com/influxdata/telegraf/pull/14288) `deps` Bump google.golang.org/api from 0.149.0 to 0.150.0\n\n## v1.28.4 [2023-11-13]\n\n### Bugfixes\n\n- [#14240](https://github.com/influxdata/telegraf/pull/14240) `config` Fix comment removal in TOML files\n- [#14187](https://github.com/influxdata/telegraf/pull/14187) `inputs.cgroup` Escape backslashes in path\n- [#14267](https://github.com/influxdata/telegraf/pull/14267) `inputs.disk` Add inodes_used_percent field\n- [#14197](https://github.com/influxdata/telegraf/pull/14197) `inputs.ecs` Fix cgroupv2 CPU metrics\n- [#14194](https://github.com/influxdata/telegraf/pull/14194) `inputs.ecs` Test for v4 metadata endpoint\n- [#14262](https://github.com/influxdata/telegraf/pull/14262) `inputs.ipset` Parse lines with timeout\n- [#14243](https://github.com/influxdata/telegraf/pull/14243) `inputs.mqtt_consumer` Resolve could not mark message delivered\n- [#14195](https://github.com/influxdata/telegraf/pull/14195) `inputs.netflow` Fix sFlow metric timestamp\n- [#14191](https://github.com/influxdata/telegraf/pull/14191) `inputs.prometheus` Read bearer token from file every time\n- [#14068](https://github.com/influxdata/telegraf/pull/14068) `inputs.s7comm` Fix bit queries\n- [#14241](https://github.com/influxdata/telegraf/pull/14241) `inputs.win_perf_counter` Do not rely on returned buffer size\n- [#14176](https://github.com/influxdata/telegraf/pull/14176) `inputs.zfs` Parse metrics correctly on FreeBSD 14\n- [#14280](https://github.com/influxdata/telegraf/pull/14280) `inputs.zfs` Support gathering metrics on zfs 2.2.0 and later\n- [#14115](https://github.com/influxdata/telegraf/pull/14115) `outputs.elasticsearch` Print error status value\n- [#14213](https://github.com/influxdata/telegraf/pull/14213) `outputs.timestream` Clip uint64 values\n- [#14149](https://github.com/influxdata/telegraf/pull/14149) `parsers.json_v2` Prevent race condition in parse function\n\n### Dependency Updates\n\n- [#14253](https://github.com/influxdata/telegraf/pull/14253) `deps` Bump cloud.google.com/go/storage from 1.30.1 to 1.34.1\n- [#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\n- [#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\n- [#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\n- [#14166](https://github.com/influxdata/telegraf/pull/14166) `deps` Bump github.com/antchfx/xmlquery from 1.3.17 to 1.3.18\n- [#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\n- [#14219](https://github.com/influxdata/telegraf/pull/14219) `deps` Bump github.com/benbjohnson/clock from 1.3.3 to 1.3.5\n- [#14216](https://github.com/influxdata/telegraf/pull/14216) `deps` Bump github.com/compose-spec/compose-go from 1.16.0 to 1.20.0\n- [#14211](https://github.com/influxdata/telegraf/pull/14211) `deps` Bump github.com/docker/docker from 24.0.6 to 24.0.7\n- [#14164](https://github.com/influxdata/telegraf/pull/14164) `deps` Bump github.com/hashicorp/consul/api from 1.24.0 to 1.25.1\n- [#14251](https://github.com/influxdata/telegraf/pull/14251) `deps` Bump github.com/hashicorp/consul/api from 1.25.1 to 1.26.1\n- [#14225](https://github.com/influxdata/telegraf/pull/14225) `deps` Bump github.com/nats-io/nkeys from 0.4.5 to 0.4.6\n- [#14168](https://github.com/influxdata/telegraf/pull/14168) `deps` Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0\n- [#14252](https://github.com/influxdata/telegraf/pull/14252) `deps` Bump github.com/rabbitmq/amqp091-go from 1.8.1 to 1.9.0\n- [#14250](https://github.com/influxdata/telegraf/pull/14250) `deps` Bump github.com/showwin/speedtest-go from 1.6.6 to 1.6.7\n- [#14192](https://github.com/influxdata/telegraf/pull/14192) `deps` Bump google.golang.org/grpc from 1.58.2 to 1.58.3\n- [#14165](https://github.com/influxdata/telegraf/pull/14165) `deps` Bump k8s.io/client-go from 0.28.2 to 0.28.3\n\n## v1.28.3 [2023-10-23]\n\n### Bugfixes\n\n- [#14049](https://github.com/influxdata/telegraf/pull/14049) `inputs.infiniband` Handle devices without counters\n- [#14105](https://github.com/influxdata/telegraf/pull/14105) `inputs.jenkins` Filter after searching sub-folders\n- [#14132](https://github.com/influxdata/telegraf/pull/14132) `inputs.jolokia2_agent` Trim quotes around tags\n- [#14041](https://github.com/influxdata/telegraf/pull/14041) `inputs.mqtt` Reference correct password variable\n- [#14010](https://github.com/influxdata/telegraf/pull/14010) `inputs.postgresql_extensible` Restore default db name\n- [#14045](https://github.com/influxdata/telegraf/pull/14045) `inputs.s7comm` Allow PDU-size to be set as config option\n- [#14153](https://github.com/influxdata/telegraf/pull/14153) `inputs.vault` Use http client to handle redirects correctly\n- [#14131](https://github.com/influxdata/telegraf/pull/14131) `metricpass` Use correct logic expression in benchmark\n- [#14154](https://github.com/influxdata/telegraf/pull/14154) `outputs.kafka` Simplify send-error handling\n- [#14135](https://github.com/influxdata/telegraf/pull/14135) `outputs.nebius_cloud_monitoring` Use correct endpoint\n- [#14060](https://github.com/influxdata/telegraf/pull/14060) `outputs.redistimeseries` Handle string fields correctly\n- [#14150](https://github.com/influxdata/telegraf/pull/14150) `serializers.json` Append newline for batch-serialization\n\n### Dependency Updates\n\n- [#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\n- [#14125](https://github.com/influxdata/telegraf/pull/14125) `deps` Bump github.com/google/cel-go from 0.14.1-git to 0.18.1\n- [#14127](https://github.com/influxdata/telegraf/pull/14127) `deps` Bump github.com/google/go-cmp from 0.5.9 to 0.6.0\n- [#14085](https://github.com/influxdata/telegraf/pull/14085) `deps` Bump github.com/jhump/protoreflect from 1.15.1 to 1.15.3\n- [#14039](https://github.com/influxdata/telegraf/pull/14039) `deps` Bump github.com/klauspost/compress from 1.16.7 to 1.17.0\n- [#14077](https://github.com/influxdata/telegraf/pull/14077) `deps` Bump github.com/miekg/dns from 1.1.55 to 1.1.56\n- [#14124](https://github.com/influxdata/telegraf/pull/14124) `deps` Bump github.com/nats-io/nats.go from 1.28.0 to 1.31.0\n- [#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\n- [#14037](https://github.com/influxdata/telegraf/pull/14037) `deps` Bump github.com/netsampler/goflow2 from 1.3.3 to 1.3.6\n- [#14040](https://github.com/influxdata/telegraf/pull/14040) `deps` Bump github.com/signalfx/golib/v3 from 3.3.50 to 3.3.53\n- [#14076](https://github.com/influxdata/telegraf/pull/14076) `deps` Bump github.com/testcontainers/testcontainers-go from 0.22.0 to 0.25.0\n- [#14038](https://github.com/influxdata/telegraf/pull/14038) `deps` Bump github.com/yuin/goldmark from 1.5.4 to 1.5.6\n- [#14075](https://github.com/influxdata/telegraf/pull/14075) `deps` Bump golang.org/x/mod from 0.12.0 to 0.13.0\n- [#14095](https://github.com/influxdata/telegraf/pull/14095) `deps` Bump golang.org/x/net from 0.15.0 to 0.17.0\n- [#14074](https://github.com/influxdata/telegraf/pull/14074) `deps` Bump golang.org/x/oauth2 from 0.11.0 to 0.13.0\n- [#14078](https://github.com/influxdata/telegraf/pull/14078) `deps` Bump gonum.org/v1/gonum from 0.13.0 to 0.14.0\n- [#14126](https://github.com/influxdata/telegraf/pull/14126) `deps` Bump google.golang.org/api from 0.139.0 to 0.147.0\n\n## v1.28.2 [2023-10-02]\n\n### Bugfixes\n\n- [#13963](https://github.com/influxdata/telegraf/pull/13963) `inputs.cisco_telemetry_mdt` Print string message on decode failure\n- [#13937](https://github.com/influxdata/telegraf/pull/13937) `inputs.exec` Clean up grandchildren processes\n- [#13977](https://github.com/influxdata/telegraf/pull/13977) `inputs.intel_pmt` Handle telem devices without numa_node attribute\n- [#13958](https://github.com/influxdata/telegraf/pull/13958) `inputs.jti_openconfig_telemetry` Do not block gRPC dial\n- [#13997](https://github.com/influxdata/telegraf/pull/13997) `inputs.mock` Align plugin with documentation\n- [#13982](https://github.com/influxdata/telegraf/pull/13982) `inputs.nfsclient` Avoid panics, better error messages\n- [#13962](https://github.com/influxdata/telegraf/pull/13962) `inputs.nvidia_smi` Add legacy power readings to v12 schema\n- [#14011](https://github.com/influxdata/telegraf/pull/14011) `inputs.openstack` Handle dependencies between enabled services and available endpoints\n- [#13972](https://github.com/influxdata/telegraf/pull/13972) `inputs.postgresql_extensible` Restore outputaddress behavior\n- [#13927](https://github.com/influxdata/telegraf/pull/13927) `inputs.smart` Remove parsing error message\n- [#13915](https://github.com/influxdata/telegraf/pull/13915) `inputs.systemd_units` Add missing upstream states\n- [#13930](https://github.com/influxdata/telegraf/pull/13930) `outputs.cloudwatch` Increase number of metrics per write\n- [#14009](https://github.com/influxdata/telegraf/pull/14009) `outputs.stackdriver` Do not shallow copy map\n- [#13931](https://github.com/influxdata/telegraf/pull/13931) `outputs.stackdriver` Drop metrics on InvalidArgument gRPC error\n- [#14008](https://github.com/influxdata/telegraf/pull/14008) `parsers.json_v2` Handle optional fields properly\n- [#13947](https://github.com/influxdata/telegraf/pull/13947) `processors.template` Handle tracking metrics correctly\n\n### Dependency Updates\n\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#13985](https://github.com/influxdata/telegraf/pull/13985) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.2 to 1.4.3\n- [#13989](https://github.com/influxdata/telegraf/pull/13989) `deps` Bump github.com/google/uuid from 1.3.0 to 1.3.1\n- [#13942](https://github.com/influxdata/telegraf/pull/13942) `deps` Bump github.com/shirou/gopsutil/v3 from 3.23.6 to 3.23.8\n- [#14022](https://github.com/influxdata/telegraf/pull/14022) `deps` Bump github.com/vmware/govmomi from 0.28.0 to 0.32.0\n- [#13940](https://github.com/influxdata/telegraf/pull/13940) `deps` Bump golang.org/x/net from 0.14.0 to 0.15.0\n- [#13944](https://github.com/influxdata/telegraf/pull/13944) `deps` Bump k8s.io/api from 0.28.1 to 0.28.2\n\n## v1.28.1 [2023-09-12]\n\n### Bugfixes\n\n- [#13909](https://github.com/influxdata/telegraf/pull/13909) `packaging` Revert permission change on package configs\n- [#13910](https://github.com/influxdata/telegraf/pull/13910) `inputs.redis` Fix password typo\n- [#13907](https://github.com/influxdata/telegraf/pull/13907) `inputs.vsphere` Fix config name typo in example\n\n## v1.28.0 [2023-09-11]\n\n### Important Changes\n\n- [#13791](https://github.com/influxdata/telegraf/pull/13791) `metricpass`\nRemoved the Python compatibility support for \"not\", \"and\", and \"or\" keywords.\nThis support was incorrectly removing these keywords from actual data. Users\nshould instead use the standard \"!\", \"&&\", and \"||\" operators.\n- [#13856](https://github.com/influxdata/telegraf/pull/13856) `parsers.avro`\nThe avro processor will no longer create a timestamp field by default unless\nexplicitly provided in the parser config.\n- [#13778](https://github.com/influxdata/telegraf/pull/13778) `packaging`\nThe default permissions on `/etc/telegraf/telegraf.conf` and\n`/etc/telegraf/telegraf.d` on new installs will drop read access for other.\nUpdates and upgrades do not change permissions.\n\n### New Plugins\n\n- [#13801](https://github.com/influxdata/telegraf/pull/13801) `inputs.intel_pmt` Intel PMT\n- [#13731](https://github.com/influxdata/telegraf/pull/13731) `inputs.s7comm` S7comm\n- [#12747](https://github.com/influxdata/telegraf/pull/12747) `inputs.tacacs` Tacacs\n- [#13785](https://github.com/influxdata/telegraf/pull/13785) `processors.split` Split metrics\n- [#13621](https://github.com/influxdata/telegraf/pull/13621) `secretstores.oauth2` OAuth2 services\n- [#13656](https://github.com/influxdata/telegraf/pull/13656) `serializers.template` Template based serializer\n\n### Features\n\n- [#13605](https://github.com/influxdata/telegraf/pull/13605) `agent` Add option to avoid filtering of global tags\n- [#13774](https://github.com/influxdata/telegraf/pull/13774) `agent` Watch default config files if none specified\n- [#13787](https://github.com/influxdata/telegraf/pull/13787) `cli` Add plugins subcommand to list available and deprecated\n- [#13496](https://github.com/influxdata/telegraf/pull/13496) `inputs.amqp_consumer` Add support to rabbitmq stream queue\n- [#13877](https://github.com/influxdata/telegraf/pull/13877) `inputs.cisco_telemetry_mdt` Add microbust support\n- [#13825](https://github.com/influxdata/telegraf/pull/13825) `inputs.couchbase` Add failover metrics\n- [#13452](https://github.com/influxdata/telegraf/pull/13452) `inputs.fail2ban` Allow specification of socket\n- [#13754](https://github.com/influxdata/telegraf/pull/13754) `inputs.fibaro` Support HC3 device types\n- [#13622](https://github.com/influxdata/telegraf/pull/13622) `inputs.http` Rework token options\n- [#13610](https://github.com/influxdata/telegraf/pull/13610) `inputs.influxdb_listener` Add token based authentication\n- [#13793](https://github.com/influxdata/telegraf/pull/13793) `inputs.internal` Add Go metric collection option\n- [#13649](https://github.com/influxdata/telegraf/pull/13649) `inputs.jenkins` Add option for node labels as tag\n- [#13709](https://github.com/influxdata/telegraf/pull/13709) `inputs.jti_openconfig_telemetry` Add keep-alive setting\n- [#13728](https://github.com/influxdata/telegraf/pull/13728) `inputs.kernel` Collect KSM metrics\n- [#13507](https://github.com/influxdata/telegraf/pull/13507) `inputs.modbus` Add per-metric configuration style\n- [#13733](https://github.com/influxdata/telegraf/pull/13733) `inputs.nvidia_smi` Add Nvidia DCGM MIG usage values\n- [#13783](https://github.com/influxdata/telegraf/pull/13783) `inputs.nvidia_smi` Add additional fields\n- [#13678](https://github.com/influxdata/telegraf/pull/13678) `inputs.nvidia_smi` Support newer data schema versions\n- [#13443](https://github.com/influxdata/telegraf/pull/13443) `inputs.openstack` Gather cinder services\n- [#13846](https://github.com/influxdata/telegraf/pull/13846) `inputs.opentelemetry` Add configurable log record dimensions\n- [#13436](https://github.com/influxdata/telegraf/pull/13436) `inputs.pgbouncer` Add show_commands to select the collected pgbouncer metrics\n- [#13620](https://github.com/influxdata/telegraf/pull/13620) `inputs.postgresql_extensible` Introduce max_version for query\n- [#13505](https://github.com/influxdata/telegraf/pull/13505) `inputs.procstat` Add status field\n- [#13624](https://github.com/influxdata/telegraf/pull/13624) `inputs.prometheus` Always apply kubernetes label and field selectors\n- [#13433](https://github.com/influxdata/telegraf/pull/13433) `inputs.ravendb` Add new disk metrics fields\n- [#13727](https://github.com/influxdata/telegraf/pull/13727) `inputs.redfish` Add additional chassis tags\n- [#13866](https://github.com/influxdata/telegraf/pull/13866) `inputs.redis` Add additional commandstat fields\n- [#13723](https://github.com/influxdata/telegraf/pull/13723) `inputs.redis` Support of redis 6.2 ERRORSTATS\n- [#13864](https://github.com/influxdata/telegraf/pull/13864) `inputs.redis_sentinel` Allow username and password\n- [#13699](https://github.com/influxdata/telegraf/pull/13699) `inputs.solr` Support version 7.x to 9.3\n- [#13448](https://github.com/influxdata/telegraf/pull/13448) `inputs.sqlserver` Add IsHadrEnabled server property\n- [#13890](https://github.com/influxdata/telegraf/pull/13890) `inputs.vsphere` Allow to set vSAN sampling interval\n- [#13720](https://github.com/influxdata/telegraf/pull/13720) `inputs.vsphere` Support explicit proxy setting\n- [#13471](https://github.com/influxdata/telegraf/pull/13471) `internal` Add gather_timeouts metric\n- [#13423](https://github.com/influxdata/telegraf/pull/13423) `internal` Add zstd to internal content_coding\n- [#13411](https://github.com/influxdata/telegraf/pull/13411) `kafka` Set and send SASL extensions\n- [#13532](https://github.com/influxdata/telegraf/pull/13532) `migrations` Add migration for inputs.httpjson\n- [#13536](https://github.com/influxdata/telegraf/pull/13536) `migrations` Add migration for inputs.io\n- [#13673](https://github.com/influxdata/telegraf/pull/13673) `outputs.execd` Add option for batch format\n- [#13245](https://github.com/influxdata/telegraf/pull/13245) `outputs.file` Add compression\n- [#13651](https://github.com/influxdata/telegraf/pull/13651) `outputs.http` Allow PATCH method\n- [#13763](https://github.com/influxdata/telegraf/pull/13763) `outputs.postgresql` Add option to create time column with timezone\n- [#13750](https://github.com/influxdata/telegraf/pull/13750) `outputs.postgresql` Add option to rename time column\n- [#13899](https://github.com/influxdata/telegraf/pull/13899) `outputs.prometheus_client` Add secretstore support for basic_password\n- [#13857](https://github.com/influxdata/telegraf/pull/13857) `outputs.wavefront` Add more auth options and update SDK\n- [#13607](https://github.com/influxdata/telegraf/pull/13607) `parsers.avro` Add support for JSON format\n- [#13419](https://github.com/influxdata/telegraf/pull/13419) `parsers.influx` Allow a user to set the timestamp precision\n- [#13506](https://github.com/influxdata/telegraf/pull/13506) `parsers.value` Add support for automatic fallback for numeric types\n- [#13480](https://github.com/influxdata/telegraf/pull/13480) `parsers.xpath` Add Concise Binary Object Representation parser\n- [#13690](https://github.com/influxdata/telegraf/pull/13690) `parsers.xpath` Add option to store fields as base64\n- [#13553](https://github.com/influxdata/telegraf/pull/13553) `processors.parser` Allow also non-string fields\n- [#13606](https://github.com/influxdata/telegraf/pull/13606) `processors.template` Unify template metric\n- [#13874](https://github.com/influxdata/telegraf/pull/13874) `prometheus` Allow to specify metric type\n\n### Bugfixes\n\n- [#13849](https://github.com/influxdata/telegraf/pull/13849) Change the systemd KillMode from control-group to mixed\n- [#13777](https://github.com/influxdata/telegraf/pull/13777) `inputs.amqp_consumer` Print error on connection failure\n- [#13886](https://github.com/influxdata/telegraf/pull/13886) `inputs.kafka_consumer` Use per-message parser to avoid races\n- [#13840](https://github.com/influxdata/telegraf/pull/13840) `inputs.opcua` Verify groups or root nodes included in config\n- [#13602](https://github.com/influxdata/telegraf/pull/13602) `inputs.postgresql` Fix default database definition\n- [#13779](https://github.com/influxdata/telegraf/pull/13779) `inputs.procstat` Collect swap via /proc/$pid/smaps\n- [#13870](https://github.com/influxdata/telegraf/pull/13870) `inputs.sqlserver` Cast max_size to bigint\n- [#13833](https://github.com/influxdata/telegraf/pull/13833) `inputs.sysstat` Remove tmpfile to avoid file-descriptor leak\n- [#13791](https://github.com/influxdata/telegraf/pull/13791) `metricpass` Remove python logic compatibility\n- [#13875](https://github.com/influxdata/telegraf/pull/13875) `outputs.sql` Move conversion_style config option to the right place\n- [#13856](https://github.com/influxdata/telegraf/pull/13856) `parsers.avro` Do not force addition of timestamp as a field\n- [#13855](https://github.com/influxdata/telegraf/pull/13855) `parsers.avro` Handle timestamp format checking correctly\n- [#13865](https://github.com/influxdata/telegraf/pull/13865) `sql` Allow sqlite on Windows (amd64 and arm64)\n\n### Dependency Updates\n\n- [#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\n- [#13811](https://github.com/influxdata/telegraf/pull/13811) `deps` Bump github.com/hashicorp/consul/api from 1.20.0 to 1.24.0\n- [#13809](https://github.com/influxdata/telegraf/pull/13809) `deps` Bump github.com/nats-io/nats.go from 1.27.0 to 1.28.0\n- [#13765](https://github.com/influxdata/telegraf/pull/13765) `deps` Bump github.com/prometheus/prometheus from 0.42.0 to 0.46.0\n- [#13895](https://github.com/influxdata/telegraf/pull/13895) `deps` Bump github.com/showwin/speedtest-go from 1.6.2 to 1.6.6\n- [#13810](https://github.com/influxdata/telegraf/pull/13810) `deps` Bump k8s.io/api from 0.27.4 to 0.28.1\n\n## v1.27.4 [2023-08-21]\n\n### Bugfixes\n\n- [#13693](https://github.com/influxdata/telegraf/pull/13693) `inputs.cisco_telemetry_mdt` Fix MDT source field overwrite\n- [#13682](https://github.com/influxdata/telegraf/pull/13682) `inputs.opcua` Register node IDs again on reconnect\n- [#13742](https://github.com/influxdata/telegraf/pull/13742) `inputs.opcua_listener` Avoid segfault when subscription was not successful\n- [#13745](https://github.com/influxdata/telegraf/pull/13745) `outputs.stackdriver` Regenerate time interval for unknown metrics\n- [#13719](https://github.com/influxdata/telegraf/pull/13719) `parsers.xpath` Handle protobuf maps correctly\n- [#13722](https://github.com/influxdata/telegraf/pull/13722) `serializers.nowmetric` Add option for JSONv2 format\n\n### Dependency Updates\n\n- [#13766](https://github.com/influxdata/telegraf/pull/13766) `deps` Bump cloud.google.com/go/pubsub from 1.32.0 to 1.33.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#13735](https://github.com/influxdata/telegraf/pull/13735) `deps` Bump github.com/gophercloud/gophercloud from 1.2.0 to 1.5.0\n- [#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\n- [#13768](https://github.com/influxdata/telegraf/pull/13768) `deps` Bump github.com/miekg/dns from 1.1.51 to 1.1.55\n- [#13706](https://github.com/influxdata/telegraf/pull/13706) `deps` Bump github.com/openconfig/gnmi from 0.9.1 to 0.10.0\n- [#13705](https://github.com/influxdata/telegraf/pull/13705) `deps` Bump github.com/santhosh-tekuri/jsonschema/v5 from 5.3.0 to 5.3.1\n- [#13736](https://github.com/influxdata/telegraf/pull/13736) `deps` Bump go.mongodb.org/mongo-driver from 1.11.6 to 1.12.1\n- [#13738](https://github.com/influxdata/telegraf/pull/13738) `deps` Bump golang.org/x/oauth2 from 0.10.0 to 0.11.0\n- [#13704](https://github.com/influxdata/telegraf/pull/13704) `deps` Bump google.golang.org/api from 0.129.0 to 0.134.0\n\n## v1.27.3 [2023-07-31]\n\n### Bugfixes\n\n- [#13614](https://github.com/influxdata/telegraf/pull/13614) `agent` Respect processor order in file\n- [#13675](https://github.com/influxdata/telegraf/pull/13675) `config` Handle escaping and quotation correctly\n- [#13671](https://github.com/influxdata/telegraf/pull/13671) `config` Setup logger for secret-stores\n- [#13646](https://github.com/influxdata/telegraf/pull/13646) `inputs.docker` Add restart count\n- [#13647](https://github.com/influxdata/telegraf/pull/13647) `inputs.jti_openconfig_telemetry` Reauthenticate connection on reconnect\n- [#13663](https://github.com/influxdata/telegraf/pull/13663) `inputs.mqtt_consumer` Add client trace logs via option\n- [#13629](https://github.com/influxdata/telegraf/pull/13629) `inputs.prometheus` Do not collect metrics from finished pods\n- [#13627](https://github.com/influxdata/telegraf/pull/13627) `inputs.prometheus` Fix missing metrics when multiple plugin instances specified\n- [#13597](https://github.com/influxdata/telegraf/pull/13597) `outputs.nebius_cloud_monitoring` Replace reserved label names\n- [#13292](https://github.com/influxdata/telegraf/pull/13292) `outputs.opentelemetry` Group metrics by age and timestamp\n- [#13575](https://github.com/influxdata/telegraf/pull/13575) `outputs.stackdriver` Add tag as resource label option\n- [#13662](https://github.com/influxdata/telegraf/pull/13662) `parsers.xpath` Ensure precedence of explicitly defined tags and fields\n- [#13665](https://github.com/influxdata/telegraf/pull/13665) `parsers.xpath` Fix field-names for arrays of simple types\n- [#13660](https://github.com/influxdata/telegraf/pull/13660) `parsers.xpath` Improve handling of complex-type nodes\n- [#13604](https://github.com/influxdata/telegraf/pull/13604) `tools.custom_builder` Ignore non-plugin sections during configuration\n\n### Dependency Updates\n\n- [#13668](https://github.com/influxdata/telegraf/pull/13668) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go 1.62.389 to 1.62.470\n- [#13640](https://github.com/influxdata/telegraf/pull/13640) `deps` Bump github.com/antchfx/jsonquery from 1.3.1 to 1.3.2\n- [#13639](https://github.com/influxdata/telegraf/pull/13639) `deps` Bump github.com/antchfx/xmlquery from 1.3.15 to 1.3.17\n- [#13679](https://github.com/influxdata/telegraf/pull/13679) `deps` Bump github.com/antchfx/xpath from v1.2.4 to latest master\n- [#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\n- [#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\n- [#13670](https://github.com/influxdata/telegraf/pull/13670) `deps` Bump github.com/eclipse/paho.golang from 0.10.0 to 0.11.0\n- [#13588](https://github.com/influxdata/telegraf/pull/13588) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.4 to 3.4.5\n- [#13603](https://github.com/influxdata/telegraf/pull/13603) `deps` Bump github.com/jaegertracing/jaeger from 1.38.0 to 1.47.0\n- [#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\n- [#13585](https://github.com/influxdata/telegraf/pull/13585) `deps` Bump github.com/prometheus-community/pro-bing from 0.2.0 to 0.3.0\n- [#13666](https://github.com/influxdata/telegraf/pull/13666) `deps` Bump github.com/shirou/gopsutil/v3 from 3.23.5 to 3.23.6\n- [#13638](https://github.com/influxdata/telegraf/pull/13638) `deps` Bump github.com/thomasklein94/packer-plugin-libvirt from 0.3.4 to 0.5.0\n- [#13667](https://github.com/influxdata/telegraf/pull/13667) `deps` Bump k8s.io/api from 0.27.2 to 0.27.4\n- [#13587](https://github.com/influxdata/telegraf/pull/13587) `deps` Bump k8s.io/apimachinery from 0.27.2 to 0.27.3\n- [#13641](https://github.com/influxdata/telegraf/pull/13641) `deps` Bump modernc.org/sqlite from 1.23.1 to 1.24.0\n\n## v1.27.2 [2023-07-10]\n\n### Bugfixes\n\n- [#13570](https://github.com/influxdata/telegraf/pull/13570) `config` Replace environment variables if existing but empty\n- [#13525](https://github.com/influxdata/telegraf/pull/13525) `inputs.cloud_pubsub` Properly lock for decompression\n- [#13517](https://github.com/influxdata/telegraf/pull/13517) `inputs.gnmi` Add option to explicitly trim field-names\n- [#13497](https://github.com/influxdata/telegraf/pull/13497) `inputs.internet_speed` Add location as a field\n- [#13485](https://github.com/influxdata/telegraf/pull/13485) `inputs.modbus` Check number of register for datatype\n- [#13486](https://github.com/influxdata/telegraf/pull/13486) `inputs.modbus` Fix optimization of overlapping requests and add warning\n- [#13478](https://github.com/influxdata/telegraf/pull/13478) `inputs.mqtt_consumer` Correctly handle semaphores on messages\n- [#13574](https://github.com/influxdata/telegraf/pull/13574) `inputs.mqtt_consumer` Print warning on no metrics generated\n- [#13514](https://github.com/influxdata/telegraf/pull/13514) `inputs.opcua` Ensure connection after reconnect\n- [#13495](https://github.com/influxdata/telegraf/pull/13495) `inputs.phpfpm` Check address length to avoid crash\n- [#13542](https://github.com/influxdata/telegraf/pull/13542) `inputs.snmp_trap` Copy GoSNMP global defaults to prevent side-effects\n- [#13557](https://github.com/influxdata/telegraf/pull/13557) `inputs.vpshere` Compare versions as a string\n- [#13527](https://github.com/influxdata/telegraf/pull/13527) `outputs.graphite` Rework connection handling\n- [#13562](https://github.com/influxdata/telegraf/pull/13562) `outputs.influxdb_v2` Expose HTTP/2 client timeouts\n- [#13454](https://github.com/influxdata/telegraf/pull/13454) `outputs.stackdriver` Options to use official path and types\n- [#13522](https://github.com/influxdata/telegraf/pull/13522) `outputs.sumologic` Unwrap serializer for type check\n- [#13547](https://github.com/influxdata/telegraf/pull/13547) `parsers.binary` Fix binary parser example in README.md\n- [#13526](https://github.com/influxdata/telegraf/pull/13526) `parsers.grok` Use UTC as the default timezone\n- [#13550](https://github.com/influxdata/telegraf/pull/13550) `parsers.xpath` Handle explicitly defined fields correctly\n- [#13564](https://github.com/influxdata/telegraf/pull/13564) `processors.printer` Convert output to string\n- [#13489](https://github.com/influxdata/telegraf/pull/13489) `secretstores` Skip dbus connection with kwallet\n- [#13511](https://github.com/influxdata/telegraf/pull/13511) `serializers.splunkmetric` Fix TOML option name for multi-metric\n- [#13563](https://github.com/influxdata/telegraf/pull/13563) `tools.custom_builder` Error out for unknown plugins in configuration\n\n### Dependency Updates\n\n- [#13524](https://github.com/influxdata/telegraf/pull/13524) Replace github.com/denisenkom/go-mssqldb with github.com/microsoft/go-mssqldb\n- [#13501](https://github.com/influxdata/telegraf/pull/13501) `deps` Bump cloud.google.com/go/bigquery from 1.51.1 to 1.52.0\n- [#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\n- [#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\n- [#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\n- [#13509](https://github.com/influxdata/telegraf/pull/13509) `deps` Bump github.com/gopcua/opcua from 0.3.7 to 0.4.0\n- [#13502](https://github.com/influxdata/telegraf/pull/13502) `deps` Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0\n- [#13544](https://github.com/influxdata/telegraf/pull/13544) `deps` Bump github.com/snowflakedb/gosnowflake from 1.6.13 to 1.6.22\n- [#13541](https://github.com/influxdata/telegraf/pull/13541) `deps` Bump github.com/urfave/cli/v2 from 2.25.5 to 2.25.7\n- [#13538](https://github.com/influxdata/telegraf/pull/13538) `deps` Bump golang.org/x/text from 0.9.0 to 0.10.0\n- [#13554](https://github.com/influxdata/telegraf/pull/13554) `deps` Bump golang.org/x/text from 0.10.0 to 0.11.0\n- [#13540](https://github.com/influxdata/telegraf/pull/13540) `deps` Bump google.golang.org/api from 0.126.0 to 0.129.0\n\n## v1.27.1 [2023-06-21]\n\n### Bugfixes\n\n- [#13434](https://github.com/influxdata/telegraf/pull/13434) Handle compression level correctly for different algorithms\n- [#13457](https://github.com/influxdata/telegraf/pull/13457) `config` Restore old environment var behavior with option\n- [#13446](https://github.com/influxdata/telegraf/pull/13446) `custom_builder` Correctly handle serializers and parsers\n\n### Dependency Updates\n\n- [#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\n- [#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\n- [#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\n- [#13466](https://github.com/influxdata/telegraf/pull/13466) `deps` Bump github.com/go-sql-driver/mysql from 1.6.0 to 1.7.1\n- [#13427](https://github.com/influxdata/telegraf/pull/13427) `deps` Bump github.com/jackc/pgx/v4 from 4.17.1 to 4.18.1\n- [#13429](https://github.com/influxdata/telegraf/pull/13429) `deps` Bump github.com/nats-io/nats.go from 1.24.0 to 1.27.0\n- [#13467](https://github.com/influxdata/telegraf/pull/13467) `deps` Bump github.com/prometheus-community/pro-bing from 0.1.0 to 0.2.0\n- [#13428](https://github.com/influxdata/telegraf/pull/13428) `deps` Bump golang.org/x/crypto from 0.8.0 to 0.9.0\n- [#13431](https://github.com/influxdata/telegraf/pull/13431) `deps` Bump golang.org/x/term from 0.8.0 to 0.9.0\n- [#13430](https://github.com/influxdata/telegraf/pull/13430) `deps` Bump modernc.org/sqlite from 1.21.0 to 1.23.1\n\n## v1.27.0 [2023-06-12]\n\n### Important Changes\n\n- Fix parsing of timezone abbreviations such as `MST`. Up to now, when parsing\n  times with abbreviated timezones (i.e. the format ) the timezone information\n  is ignored completely and the _timestamp_ is located in UTC. This is a golang\n  issue (see [#9617](https://github.com/golang/go/issues/9617) or\n  [#56528](https://github.com/golang/go/issues/56528)). If you worked around\n  that issue, please remove the workaround before using v1.27+. In case you\n  experience issues with abbreviated timezones please file an issue!\n- Removal of old-style parser creation. This should not directly affect users as\n  it is an API change. All parsers in Telegraf are already ported to the new\n  framework. If you experience any issues with not being able to create parsers\n  let us know!\n\n### New Plugins\n\n- [#11155](https://github.com/influxdata/telegraf/pull/11155) `inputs.ctrlx_datalayer` ctrlX Data Layer\n- [#13397](https://github.com/influxdata/telegraf/pull/13397) `inputs.intel_baseband` Intel Baseband Accelerator\n- [#13220](https://github.com/influxdata/telegraf/pull/13220) `outputs.clarify` Clarify\n- [#13379](https://github.com/influxdata/telegraf/pull/13379) `outputs.nebius_cloud_monitoring` Nebius Cloud Monitoring\n- [#13061](https://github.com/influxdata/telegraf/pull/13061) `processors.scale` Scale\n- [#13035](https://github.com/influxdata/telegraf/pull/13035) `secretstores.docker` Docker Store\n- [#13150](https://github.com/influxdata/telegraf/pull/13150) `secretstores.http` HTTP Store\n- [#13224](https://github.com/influxdata/telegraf/pull/13224) `serializers.cloudevents` CloudEvents\n\n### Features\n\n- [#13144](https://github.com/influxdata/telegraf/pull/13144) Add common expression language metric filtering\n- [#13364](https://github.com/influxdata/telegraf/pull/13364) `agent` Add option to avoid filtering of explicit plugin tags\n- [#13118](https://github.com/influxdata/telegraf/pull/13118) `aggregators.basicstats` Add percentage change\n- [#13094](https://github.com/influxdata/telegraf/pull/13094) `cloud_pubsub` Add support for gzip compression\n- [#12863](https://github.com/influxdata/telegraf/pull/12863) `common.opcua` Add support for secret-store secrets\n- [#13262](https://github.com/influxdata/telegraf/pull/13262) `common.tls` Add support for passphrase-protected private key\n- [#13377](https://github.com/influxdata/telegraf/pull/13377) `config` Add framework for migrating deprecated plugins\n- [#13229](https://github.com/influxdata/telegraf/pull/13229) `config` Support shell like syntax for environment variable substitution\n- [#12448](https://github.com/influxdata/telegraf/pull/12448) `inputs.cloudwatch` Add support for cross account observability\n- [#13089](https://github.com/influxdata/telegraf/pull/13089) `inputs.directory_monitor` Improve internal stats\n- [#13163](https://github.com/influxdata/telegraf/pull/13163) `inputs.filecount` Add oldestFileTimestamp and newestFileTimestamp\n- [#13326](https://github.com/influxdata/telegraf/pull/13326) `inputs.gnmi` Allow canonical field names\n- [#13116](https://github.com/influxdata/telegraf/pull/13116) `inputs.gnmi` Support Juniper GNMI Extension Header\n- [#12797](https://github.com/influxdata/telegraf/pull/12797) `inputs.internet_speed` Support multi-server test\n- [#11831](https://github.com/influxdata/telegraf/pull/11831) `inputs.kafka_consumer` Add regular expression support for topics\n- [#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\n- [#13293](https://github.com/influxdata/telegraf/pull/13293) `inputs.nats_consumer` Add receiver subject as tag\n- [#13047](https://github.com/influxdata/telegraf/pull/13047) `inputs.netflow` Add sFlow decoder\n- [#13360](https://github.com/influxdata/telegraf/pull/13360) `inputs.netflow` Allow custom PEN field mappings\n- [#13133](https://github.com/influxdata/telegraf/pull/13133) `inputs.nvidia_smi` Add additional memory related fields\n- [#13404](https://github.com/influxdata/telegraf/pull/13404) `inputs.opentelemetry` Add configurable span dimensions\n- [#12851](https://github.com/influxdata/telegraf/pull/12851) `inputs.prometheus` Control which pod metadata is added as tags\n- [#13289](https://github.com/influxdata/telegraf/pull/13289) `inputs.sql` Add disconnected_servers_behavior field in the configuration\n- [#13091](https://github.com/influxdata/telegraf/pull/13091) `inputs.sql` Add FlightSQL support\n- [#13261](https://github.com/influxdata/telegraf/pull/13261) `inputs.sqlserver` Add Azure Arc-enabled SQL MI support\n- [#13284](https://github.com/influxdata/telegraf/pull/13284) `inputs.sqlserver` Check SQL Server encryptionEnforce with xp_instance_regread\n- [#13087](https://github.com/influxdata/telegraf/pull/13087) `inputs.statsd` Add optional temporality and start_time tag for statsd metrics\n- [#13048](https://github.com/influxdata/telegraf/pull/13048) `inputs.suricata` Add ability to parse drop or rejected\n- [#11955](https://github.com/influxdata/telegraf/pull/11955) `inputs.vsphere` Add vSAN extension\n- [#13316](https://github.com/influxdata/telegraf/pull/13316) `internal` Add additional faster compression options\n- [#13157](https://github.com/influxdata/telegraf/pull/13157) `outputs.loki` Add option for metric name label\n- [#13349](https://github.com/influxdata/telegraf/pull/13349) `outputs.wavefront` Add TLS and HTTP Timeout configuration fields\n- [#13167](https://github.com/influxdata/telegraf/pull/13167) `parsers.opentsdb` Add OpenTSDB data format parser\n- [#13075](https://github.com/influxdata/telegraf/pull/13075) `processors.aws_ec2` Add caching of imds and ec2 tags\n- [#13147](https://github.com/influxdata/telegraf/pull/13147) `processors.parser` Add merge with timestamp option\n- [#13227](https://github.com/influxdata/telegraf/pull/13227) `processors.scale`  Add scaling by factor and offset\n- [#13253](https://github.com/influxdata/telegraf/pull/13253) `processors.template` Allow `tag` to be a template\n- [#12971](https://github.com/influxdata/telegraf/pull/12971) `serializer.prometheusremote` Improve performance\n- [#13275](https://github.com/influxdata/telegraf/pull/13275) `test` Allow to capture all messages during test\n\n### Bugfixes\n\n- [#13238](https://github.com/influxdata/telegraf/pull/13238) `inputs.cloud_pubsub` Fix gzip decompression\n- [#13304](https://github.com/influxdata/telegraf/pull/13304) `inputs.gnmi` Allow optional origin for update path\n- [#13332](https://github.com/influxdata/telegraf/pull/13332) `inputs.gnmi` Handle canonical field-name correctly for non-explicit subscriptions\n- [#13350](https://github.com/influxdata/telegraf/pull/13350) `inputs.mqtt` ACK messages when persistence is enabled\n- [#13361](https://github.com/influxdata/telegraf/pull/13361) `inputs.mysql` Update MariaDB Dialect regex version check\n- [#13325](https://github.com/influxdata/telegraf/pull/13325) `inputs.netflow` Fix field mappings\n- [#13320](https://github.com/influxdata/telegraf/pull/13320) `inputs.netflow` Handle PEN messages correctly\n- [#13231](https://github.com/influxdata/telegraf/pull/13231) `inputs.prometheus` Avoid race when creating informer factory\n- [#13288](https://github.com/influxdata/telegraf/pull/13288) `inputs.socket_listener` Avoid noisy logs on closed connection\n- [#13307](https://github.com/influxdata/telegraf/pull/13307) `inputs.temp` Ignore warnings and instead return only errors\n- [#13412](https://github.com/influxdata/telegraf/pull/13412) `inputs.upsd` Handle float battery.runtime value\n- [#13363](https://github.com/influxdata/telegraf/pull/13363) `internal` Fix time parsing for abbreviated timezones\n- [#13408](https://github.com/influxdata/telegraf/pull/13408) `outputs.sql` Use config.duration to correctly to parse toml config\n- [#13252](https://github.com/influxdata/telegraf/pull/13252) `outputs.wavefront` Flush metric buffer before reaching overflow\n- [#13301](https://github.com/influxdata/telegraf/pull/13301) `processors.lookup` Do not strip tracking info\n- [#13164](https://github.com/influxdata/telegraf/pull/13164) `serializers.influx` Restore disabled uint support by default\n- [#13394](https://github.com/influxdata/telegraf/pull/13394) `tests` Replace last 'cat' instance in tests\n\n### Dependency Updates\n\n- [#13359](https://github.com/influxdata/telegraf/pull/13359) `deps` Bump cloud.google.com/go/monitoring from 1.13.0 to 1.14.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#13314](https://github.com/influxdata/telegraf/pull/13314) `deps` Bump github.com/Azure/go-autorest/autorest from 0.11.28 to 0.11.29\n- [#13265](https://github.com/influxdata/telegraf/pull/13265) `deps` Bump github.com/influxdata/influxdb-observability libraries from 0.3.3 to 0.3.15\n- [#13311](https://github.com/influxdata/telegraf/pull/13311) `deps` Bump github.com/jackc/pgconn from 1.13.0 to 1.14.0\n- [#13357](https://github.com/influxdata/telegraf/pull/13357) `deps` Bump github.com/jackc/pgtype from 1.12.0 to 1.14.0\n- [#13392](https://github.com/influxdata/telegraf/pull/13392) `deps` Bump github.com/Mellanox/rdmamap to 1.1.0\n- [#13356](https://github.com/influxdata/telegraf/pull/13356) `deps` Bump github.com/pion/dtls/v2 from 2.2.6 to 2.2.7\n- [#13389](https://github.com/influxdata/telegraf/pull/13389) `deps` Bump github.com/prometheus/common from 0.43.0 to 0.44.0\n- [#13355](https://github.com/influxdata/telegraf/pull/13355) `deps` Bump github.com/rabbitmq/amqp091-go from 1.8.0 to 1.8.1\n- [#13396](https://github.com/influxdata/telegraf/pull/13396) `deps` Bump github.com/shirou/gopsutil from 3.23.4 to 3.23.5\n- [#13369](https://github.com/influxdata/telegraf/pull/13369) `deps` Bump github.com/showwin/speedtest-go from 1.5.2 to 1.6.2\n- [#13388](https://github.com/influxdata/telegraf/pull/13388) `deps` Bump github.com/urfave/cli/v2 from 2.23.5 to 2.25.5\n- [#13315](https://github.com/influxdata/telegraf/pull/13315) `deps` Bump k8s.io/client-go from 0.26.2 to 0.27.2\n\n## v1.26.3 [2023-05-22]\n\n### Bugfixes\n\n- [#13149](https://github.com/influxdata/telegraf/pull/13149) `inputs.gnmi` Create selfstat to track connection state\n- [#13139](https://github.com/influxdata/telegraf/pull/13139) `inputs.intel_pmu` Fix handling of the json perfmon format\n- [#13056](https://github.com/influxdata/telegraf/pull/13056) `inputs.socket_listener` Fix loss of connection tracking\n- [#13300](https://github.com/influxdata/telegraf/pull/13300) `inputs.socket_listener` Fix race in tests\n- [#13286](https://github.com/influxdata/telegraf/pull/13286) `inputs.vsphere` Specify the correct option for disconnected_servers_behavior\n- [#13239](https://github.com/influxdata/telegraf/pull/13239) `outputs.graphite` Fix logic to reconnect with servers that were not up on agent startup\n- [#13169](https://github.com/influxdata/telegraf/pull/13169) `outputs.prometheus_client` Fix export_timestamp for v1 metric type\n- [#13168](https://github.com/influxdata/telegraf/pull/13168) `outputs.stackdriver` Allow for custom metric type prefix\n- [#12994](https://github.com/influxdata/telegraf/pull/12994) `outputs.stackdriver` Group batches by timestamp\n- [#13126](https://github.com/influxdata/telegraf/pull/13126) `outputs.warp10` Support Infinity/-Infinity/NaN values\n- [#13156](https://github.com/influxdata/telegraf/pull/13156) `processors.starlark` Do not reject tracking metrics twice\n\n### Dependency Updates\n\n- [#13256](https://github.com/influxdata/telegraf/pull/13256) `deps` Bump cloud.google.com/go/pubsub from 1.30.0 to 1.30.1\n- [#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\n- [#13242](https://github.com/influxdata/telegraf/pull/13242) `deps` Bump github.com/antchfx/xpath to latest master for string-join()\n- [#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\n- [#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\n- [#13254](https://github.com/influxdata/telegraf/pull/13254) `deps` Bump github.com/benbjohnson/clock from 1.3.0 to 1.3.3\n- [#13269](https://github.com/influxdata/telegraf/pull/13269) `deps` Bump github.com/docker/distribution from 2.8.1 to 2.8.2\n- [#13216](https://github.com/influxdata/telegraf/pull/13216) `deps` Bump github.com/fatih/color from 1.13.0 to 1.15.0\n- [#13104](https://github.com/influxdata/telegraf/pull/13104) `deps` Bump github.com/netsampler/goflow2 from 1.1.1 to 1.3.3\n- [#13138](https://github.com/influxdata/telegraf/pull/13138) `deps` Bump github.com/yuin/goldmark from 1.5.3 to 1.5.4\n- [#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\n- [#13137](https://github.com/influxdata/telegraf/pull/13137) `deps` Bump golang.org/x/net from 0.8.0 to 0.9.0\n- [#13276](https://github.com/influxdata/telegraf/pull/13276) `deps` Bump golang.org/x/net from 0.9.0 to 0.10.0\n- [#13217](https://github.com/influxdata/telegraf/pull/13217) `deps` Bump golang.org/x/oauth2 from 0.5.0 to 0.7.0\n- [#13170](https://github.com/influxdata/telegraf/pull/13170) `deps` Bump google.golang.org/api from 0.106.0 to 0.120.0\n- [#13223](https://github.com/influxdata/telegraf/pull/13223) `deps` Bump govulncheck-action from 0.10.0 to 0.10.1\n- [#13225](https://github.com/influxdata/telegraf/pull/13225) `deps` Bump prometheus from v1.8.2 to v2.42.0\n- [#13230](https://github.com/influxdata/telegraf/pull/13230) `deps` Bump signalfx/golib from 3.3.46 to 3.3.50\n\n## v1.26.2 [2023-04-24]\n\n### Bugfixes\n\n- [#13020](https://github.com/influxdata/telegraf/pull/13020) `agent` Pass quiet flag earlier\n- [#13063](https://github.com/influxdata/telegraf/pull/13063) `inputs.prometheus` Add namespace option in k8s informer factory\n- [#13059](https://github.com/influxdata/telegraf/pull/13059) `inputs.socket_listener` Fix tracking of unix sockets\n- [#13078](https://github.com/influxdata/telegraf/pull/13078) `parsers.grok` Fix nil metric for multiline inputs\n- [#13092](https://github.com/influxdata/telegraf/pull/13092) `processors.lookup` Fix tracking metrics\n\n### Dependency Updates\n\n- [#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\n- [#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\n- [#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\n- [#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\n- [#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\n- [#13105](https://github.com/influxdata/telegraf/pull/13105) `deps` Bump github.com/docker/docker from 23.0.0 to 23.0.4\n- [#13024](https://github.com/influxdata/telegraf/pull/13024) `deps` Bump github.com/openconfig/gnmi from 0.0.0-20220920173703-480bf53a74d2 to 0.9.1\n- [#13026](https://github.com/influxdata/telegraf/pull/13026) `deps` Bump github.com/prometheus/common from 0.41.0 to 0.42.0\n- [#13025](https://github.com/influxdata/telegraf/pull/13025) `deps` Bump github.com/safchain/ethtool from 0.2.0 to 0.3.0\n- [#13023](https://github.com/influxdata/telegraf/pull/13023) `deps` Bump github.com/tinylib/msgp from 1.1.6 to 1.1.8\n- [#13071](https://github.com/influxdata/telegraf/pull/13071) `deps` Bump github.com/vishvananda/netns from 0.0.2 to 0.0.4\n- [#13070](https://github.com/influxdata/telegraf/pull/13070) `deps` Bump github.com/wavefronthq/wavefront-sdk-go from 0.11.0 to 0.12.0\n\n## v1.26.1 [2023-04-03]\n\n### Bugfixes\n\n- [#12880](https://github.com/influxdata/telegraf/pull/12880) `config` Return error on order set as string\n- [#12867](https://github.com/influxdata/telegraf/pull/12867) `inputs.ethtool` Check for nil\n- [#12935](https://github.com/influxdata/telegraf/pull/12935) `inputs.execd` Add option to set buffer size\n- [#12877](https://github.com/influxdata/telegraf/pull/12877) `inputs.internet_speed` Rename host tag to source\n- [#12918](https://github.com/influxdata/telegraf/pull/12918) `inputs.kubernetes` Apply timeout for the whole HTTP request\n- [#13006](https://github.com/influxdata/telegraf/pull/13006) `inputs.netflow` Use correct name in the build tag\n- [#13015](https://github.com/influxdata/telegraf/pull/13015) `inputs.procstat` Return tags of pids if lookup_error\n- [#12864](https://github.com/influxdata/telegraf/pull/12864) `inputs.prometheus` Correctly set timeout param\n- [#12907](https://github.com/influxdata/telegraf/pull/12907) `inputs.prometheus` Use set over add for custom headers\n- [#12961](https://github.com/influxdata/telegraf/pull/12961) `inputs.upsd` Include ups.real_power\n- [#12908](https://github.com/influxdata/telegraf/pull/12908) `outputs.graphite` Add custom regex to outputs\n- [#13012](https://github.com/influxdata/telegraf/pull/13012) `secrets` Add function to set a secret\n- [#13002](https://github.com/influxdata/telegraf/pull/13002) `secrets` Minimize secret holding time\n- [#12993](https://github.com/influxdata/telegraf/pull/12993) `secrets` Warn if OS limit for locked memory is too low\n- [#12919](https://github.com/influxdata/telegraf/pull/12919) `secrets` Handle array of secrets correctly\n- [#12835](https://github.com/influxdata/telegraf/pull/12835) `serializers.graphite` Allow for specifying regex to sanitize\n- [#12990](https://github.com/influxdata/telegraf/pull/12990) `systemd` Increase lock memory for service to 8192kb\n\n### Dependency Updates\n\n- [#12857](https://github.com/influxdata/telegraf/pull/12857) `deps` Bump github.com/antchfx/xpath from 1.2.3 to 1.2.4\n- [#12909](https://github.com/influxdata/telegraf/pull/12909) `deps` Bump github.com/apache/thrift from 0.16.0 to 0.18.1\n- [#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\n- [#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\n- [#12964](https://github.com/influxdata/telegraf/pull/12964) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.4.2 to 4.5.0\n- [#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\n- [#12855](https://github.com/influxdata/telegraf/pull/12855) `deps` Bump github.com/nats-io/nats.go from 1.19.0 to 1.24.0\n- [#12981](https://github.com/influxdata/telegraf/pull/12981) `deps` Bump github.com/opencontainers/runc from 1.1.4 to 1.1.5\n- [#12913](https://github.com/influxdata/telegraf/pull/12913) `deps` Bump github.com/pion/dtls/v2 from 2.2.4 to 2.2.6\n- [#12968](https://github.com/influxdata/telegraf/pull/12968) `deps` Bump github.com/rabbitmq/amqp091-go from 1.7.0 to 1.8.0\n- [#13017](https://github.com/influxdata/telegraf/pull/13017) `deps` Bump github.com/shirou/gopsutil from 3.23.2 to 3.23.3\n- [#12853](https://github.com/influxdata/telegraf/pull/12853) `deps` Bump github.com/Shopify/sarama from 1.37.2 to 1.38.1\n- [#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\n- [#12911](https://github.com/influxdata/telegraf/pull/12911) `deps` Bump github.com/tidwall/gjson from 1.14.3 to 1.14.4\n- [#12912](https://github.com/influxdata/telegraf/pull/12912) `deps` Bump golang.org/x/net from 0.7.0 to 0.8.0\n- [#12910](https://github.com/influxdata/telegraf/pull/12910) `deps` Bump modernc.org/sqlite from 1.19.2 to 1.21.0\n\n## v1.26.0 [2023-03-13]\n\n### Important Changes\n\n- Static Builds: Linux builds are now statically built. Other operating systems\n  were cross-built in the past and as a result, already static. Users should\n  not notice any change in behavior. The `_static` specific Linux binary is no\n  longer produced as a result.\n- telegraf.d Behavior: The default behavior of reading\n  `/etc/telegraf/telegraf.conf` now includes any .conf files under\n  `/etc/telegraf/telegraf.d/`. This change will apply to the official Telegraf\n  Docker image as well. This will simplify docker usage when using multiple\n  configuration files.\n- Default Configuration: The `telegraf config` command and default config file\n  provided by Telegraf now includes all plugins and produces the same output\n  across all operating systems. Plugin comments specify what platforms are\n  supported or not.\n- State Persistence: State persistence is now available in select plugins. This\n  will allow plugins to start collecting data, where they left off. A\n  configuration with state persistence cannot change or it will not be able to\n  recover.\n\n### New Plugins\n\n- [#12393](https://github.com/influxdata/telegraf/pull/12393) `inputs.opensearch_query` Opensearch Query\n- [#12473](https://github.com/influxdata/telegraf/pull/12473) `inputs.p4runtime` P4Runtime\n- [#12736](https://github.com/influxdata/telegraf/pull/12736) `inputs.radius` Radius Auth Response Time\n- [#11250](https://github.com/influxdata/telegraf/pull/11250) `inputs.win_wmi` Windows Management Instrumentation (WMI)\n- [#12809](https://github.com/influxdata/telegraf/pull/12809) `processors.lookup` Lookup\n\n### Features\n\n- [#12600](https://github.com/influxdata/telegraf/pull/12600) Always disable cgo support (static builds)\n- [#12166](https://github.com/influxdata/telegraf/pull/12166) Plugin state-persistence\n- [#12608](https://github.com/influxdata/telegraf/pull/12608) `agent` Add /etc/telegraf/telegraf.d to default config locations\n- [#12827](https://github.com/influxdata/telegraf/pull/12827) `agent` Print loaded configs\n- [#12821](https://github.com/influxdata/telegraf/pull/12821) `common.oauth` Add audience parameter\n- [#12727](https://github.com/influxdata/telegraf/pull/12727) `common.tls` Add enable flag\n- [#12579](https://github.com/influxdata/telegraf/pull/12579) `config` Accept durations given in days (e.g. 7d)\n- [#12798](https://github.com/influxdata/telegraf/pull/12798) `inputs.cgroup` Added support for cpu.stat\n- [#12345](https://github.com/influxdata/telegraf/pull/12345) `inputs.cisco_telemetry_mdt` Include delete field\n- [#12696](https://github.com/influxdata/telegraf/pull/12696) `inputs.disk` Add label as tag\n- [#12519](https://github.com/influxdata/telegraf/pull/12519) `inputs.dns_query` Add IP field(s)\n- [#12775](https://github.com/influxdata/telegraf/pull/12775) `inputs.docker_log` Add state-persistence capabilities\n- [#12814](https://github.com/influxdata/telegraf/pull/12814) `inputs.ethtool` Add support for link speed, duplex, etc.\n- [#12550](https://github.com/influxdata/telegraf/pull/12550) `inputs.example` Add secret-store sample code\n- [#12495](https://github.com/influxdata/telegraf/pull/12495) `inputs.gnmi` Set max gRPC message size\n- [#12680](https://github.com/influxdata/telegraf/pull/12680) `inputs.haproxy` Add support for tcp endpoints in haproxy plugin\n- [#12645](https://github.com/influxdata/telegraf/pull/12645) `inputs.http_listener_v2` Add custom server http headers\n- [#12506](https://github.com/influxdata/telegraf/pull/12506) `inputs.icinga2` Support collecting hosts, services, and endpoint metrics\n- [#12493](https://github.com/influxdata/telegraf/pull/12493) `inputs.influxdb` Collect uptime statistics\n- [#12452](https://github.com/influxdata/telegraf/pull/12452) `inputs.intel_powerstat` Add CPU base frequency metric and add support for new platforms\n- [#12707](https://github.com/influxdata/telegraf/pull/12707) `inputs.internet_speed` Add the best server selection via latency and jitter field\n- [#12617](https://github.com/influxdata/telegraf/pull/12617) `inputs.internet_speed` Server ID include and exclude filter\n- [#12730](https://github.com/influxdata/telegraf/pull/12730) `inputs.jti_openconfig_telemetry` Set timestamp from data\n- [#12786](https://github.com/influxdata/telegraf/pull/12786) `inputs.modbus` Add RS485 specific config options\n- [#12408](https://github.com/influxdata/telegraf/pull/12408) `inputs.modbus` Add workaround to enforce reads from zero for coil registers\n- [#12825](https://github.com/influxdata/telegraf/pull/12825) `inputs.modbus` Allow to convert coil and discrete registers to boolean\n- [#12591](https://github.com/influxdata/telegraf/pull/12591) `inputs.mysql` Add secret-store support\n- [#12466](https://github.com/influxdata/telegraf/pull/12466) `inputs.openweathermap` Add snow parameter\n- [#12628](https://github.com/influxdata/telegraf/pull/12628) `inputs.processes` Add use_sudo option for BSD\n- [#12777](https://github.com/influxdata/telegraf/pull/12777) `inputs.prometheus` Use namespace annotations to filter pods to be scraped\n- [#12496](https://github.com/influxdata/telegraf/pull/12496) `inputs.redfish` Add power control metric\n- [#12400](https://github.com/influxdata/telegraf/pull/12400) `inputs.sqlserver` Get database pages performance counter\n- [#12377](https://github.com/influxdata/telegraf/pull/12377) `inputs.stackdriver` Allow filtering by resource metadata labels\n- [#12318](https://github.com/influxdata/telegraf/pull/12318) `inputs.statsd` Add pending messages stat and allow to configure number of threads\n- [#12828](https://github.com/influxdata/telegraf/pull/12828) `inputs.vsphere` Flag for more lenient behavior when connect fails on startup\n- [#12790](https://github.com/influxdata/telegraf/pull/12790) `inputs.win_eventlog` Add state-persistence capabilities\n- [#12556](https://github.com/influxdata/telegraf/pull/12556) `inputs.win_perf_counters` Add remote system support\n- [#12729](https://github.com/influxdata/telegraf/pull/12729) `inputs.wireguard` Add allowed_peer_cidr field\n- [#12444](https://github.com/influxdata/telegraf/pull/12444) `inputs.x509_cert` Add OCSP stapling information for leaf certificates (#10550)\n- [#12656](https://github.com/influxdata/telegraf/pull/12656) `inputs.x509_cert` Add tag for certificate type-classification\n- [#12697](https://github.com/influxdata/telegraf/pull/12697) `outputs.mqtt` Add option to specify topic layouts\n- [#12678](https://github.com/influxdata/telegraf/pull/12678) `outputs.mqtt` Add support for MQTT 5 publish properties\n- [#12224](https://github.com/influxdata/telegraf/pull/12224) `outputs.mqtt` Enhance routing capabilities\n- [#11816](https://github.com/influxdata/telegraf/pull/11816) `parsers.avro` Add Apache Avro parser\n- [#12820](https://github.com/influxdata/telegraf/pull/12820) `parsers.xpath` Add timezone handling\n- [#12767](https://github.com/influxdata/telegraf/pull/12767) `processors.converter` Convert tag or field as metric timestamp\n- [#12659](https://github.com/influxdata/telegraf/pull/12659) `processors.unpivot` Add mode to create new metrics\n- [#12812](https://github.com/influxdata/telegraf/pull/12812) `secretstores` Add command-line option to specify password\n- [#12067](https://github.com/influxdata/telegraf/pull/12067) `secretstores` Add support for additional input plugins\n- [#12497](https://github.com/influxdata/telegraf/pull/12497) `secretstores` Convert many output plugins\n\n### Bugfixes\n\n- [#12781](https://github.com/influxdata/telegraf/pull/12781) `agent` Allow graceful shutdown on interrupt (e.g. Ctrl-C)\n- [#12740](https://github.com/influxdata/telegraf/pull/12740) `agent` Only rotate log on SIGHUP if needed\n- [#12818](https://github.com/influxdata/telegraf/pull/12818) `inputs.amqp_consumer` Avoid deprecations when handling defaults\n- [#12817](https://github.com/influxdata/telegraf/pull/12817) `inputs.amqp_consumer` Fix panic on Stop() if not connected successfully\n- [#12815](https://github.com/influxdata/telegraf/pull/12815) `inputs.ethtool` Close namespace file to prevent crash\n- [#12778](https://github.com/influxdata/telegraf/pull/12778) `inputs.statsd` On close, verify listener is not nil\n\n### Dependency Updates\n\n- [#12805](https://github.com/influxdata/telegraf/pull/12805) `deps` Bump cloud.google.com/go/storage from 1.28.1 to 1.29.0\n- [#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\n- [#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\n- [#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\n- [#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\n- [#12754](https://github.com/influxdata/telegraf/pull/12754) `deps` Bump github.com/coocood/freecache from 1.2.2 to 1.2.3\n- [#12852](https://github.com/influxdata/telegraf/pull/12852) `deps` Bump github.com/opencontainers/runc from 1.1.3 to 1.1.4\n- [#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\n- [#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\n- [#12755](https://github.com/influxdata/telegraf/pull/12755) `deps` Bump github.com/rabbitmq/amqp091-go from 1.5.0 to 1.7.0\n- [#12822](https://github.com/influxdata/telegraf/pull/12822) `deps` Bump github.com/shirou/gopsutil from v3.22.12 to v3.23.2\n- [#12807](https://github.com/influxdata/telegraf/pull/12807) `deps` Bump github.com/stretchr/testify from 1.8.1 to 1.8.2\n- [#12840](https://github.com/influxdata/telegraf/pull/12840) `deps` Bump OpenTelemetry from 0.3.1 to 0.3.3\n- [#12801](https://github.com/influxdata/telegraf/pull/12801) `deps` Downgrade github.com/karrick/godirwalk from v1.17.0 to v1.16.2\n\n## v1.25.3 [2023-02-27]\n\n### Bugfixes\n\n- [#12721](https://github.com/influxdata/telegraf/pull/12721) `agent` Fix reload config on config update/SIGHUP\n- [#12462](https://github.com/influxdata/telegraf/pull/12462) `inputs.bond` Reset slave stats for each interface\n- [#12677](https://github.com/influxdata/telegraf/pull/12677) `inputs.cloudwatch` Verify endpoint is not nil\n- [#12725](https://github.com/influxdata/telegraf/pull/12725) `inputs.lvm` Add options to specify path to binaries\n- [#12724](https://github.com/influxdata/telegraf/pull/12724) `parsers.xpath` Fix panic for JSON name expansion\n- [#12735](https://github.com/influxdata/telegraf/pull/12735) `serializers.json` Fix stateful transformations\n\n### Dependency Updates\n\n- [#12714](https://github.com/influxdata/telegraf/pull/12714) `deps` Bump cloud.google.com/go/pubsub from 1.27.1 to 1.28.0\n- [#12693](https://github.com/influxdata/telegraf/pull/12693) `deps` Bump github.com/containerd/containerd from 1.6.8 to 1.6.18\n- [#12715](https://github.com/influxdata/telegraf/pull/12715) `deps` Bump github.com/go-logfmt/logfmt from 0.5.1 to 0.6.0\n- [#12668](https://github.com/influxdata/telegraf/pull/12668) `deps` Bump github.com/gofrs/uuid from 4.3.1 to 5.0.0\n- [#12712](https://github.com/influxdata/telegraf/pull/12712) `deps` Bump github.com/gophercloud/gophercloud from 1.0.0 to 1.2.0\n- [#12667](https://github.com/influxdata/telegraf/pull/12667) `deps` Bump github.com/pion/dtls/v2 from 2.1.5 to 2.2.4\n- [#12699](https://github.com/influxdata/telegraf/pull/12699) `deps` Bump golang.org/x/net from 0.5.0 to 0.7.0\n- [#12670](https://github.com/influxdata/telegraf/pull/12670) `deps` Bump golang.org/x/sys from 0.4.0 to 0.5.0\n- [#12713](https://github.com/influxdata/telegraf/pull/12713) `deps` Bump google.golang.org/grpc from 1.52.3 to 1.53.0\n- [#12669](https://github.com/influxdata/telegraf/pull/12669) `deps` Bump k8s.io/apimachinery from 0.25.3 to 0.25.6\n- [#12698](https://github.com/influxdata/telegraf/pull/12698) `deps` Bump testcontainers from 0.14.0 to 0.18.0\n\n## v1.25.2 [2023-02-13]\n\n### Bugfixes\n\n- [#12607](https://github.com/influxdata/telegraf/pull/12607) `agent` Only read the config once\n- [#12586](https://github.com/influxdata/telegraf/pull/12586) `docs` Fix link to license for Google flatbuffers\n- [#12637](https://github.com/influxdata/telegraf/pull/12637) `inputs.cisco_telemetry_mdt` Check subfield sizes to avoid panics\n- [#12657](https://github.com/influxdata/telegraf/pull/12657) `inputs.cloudwatch` Enable custom endpoint support\n- [#12603](https://github.com/influxdata/telegraf/pull/12603) `inputs.conntrack` Resolve segfault when setting collect field\n- [#12512](https://github.com/influxdata/telegraf/pull/12512) `inputs.gnmi` Handle both new-style `tag_subscription` and old-style `tag_only`\n- [#12599](https://github.com/influxdata/telegraf/pull/12599) `inputs.mongodb` Improve error logging\n- [#12604](https://github.com/influxdata/telegraf/pull/12604) `inputs.mongodb` SIGSEGV when restarting MongoDB node\n- [#12576](https://github.com/influxdata/telegraf/pull/12576) `inputs.mysql` Avoid side-effects for TLS between plugin instances\n- [#12626](https://github.com/influxdata/telegraf/pull/12626) `inputs.prometheus` Deprecate and rename the timeout variable\n- [#12648](https://github.com/influxdata/telegraf/pull/12648) `inputs.tail` Fix typo in the README\n- [#12543](https://github.com/influxdata/telegraf/pull/12543) `inputs.upsd` Add additional fields\n- [#12629](https://github.com/influxdata/telegraf/pull/12629) `inputs.x509_cert` Fix Windows path handling\n- [#12560](https://github.com/influxdata/telegraf/pull/12560) `outputs.prometheus_client` Expire with ticker, not add/collect\n- [#12644](https://github.com/influxdata/telegraf/pull/12644) `secretstores` Check store id format and presence\n\n### Dependency Updates\n\n- [#12630](https://github.com/influxdata/telegraf/pull/12630) `deps` Bump cloud.google.com/go/bigquery from 1.44.0 to 1.45.0\n- [#12568](https://github.com/influxdata/telegraf/pull/12568) `deps` Bump github.com/99designs/keyring from 1.2.1 to 1.2.2\n- [#12634](https://github.com/influxdata/telegraf/pull/12634) `deps` Bump github.com/antchfx/xmlquery from 1.3.12 to 1.3.15\n- [#12633](https://github.com/influxdata/telegraf/pull/12633) `deps` Bump github.com/antchfx/xpath from 1.2.2 to 1.2.3\n- [#12571](https://github.com/influxdata/telegraf/pull/12571) `deps` Bump github.com/coreos/go-semver from 0.3.0 to 0.3.1\n- [#12632](https://github.com/influxdata/telegraf/pull/12632) `deps` Bump github.com/moby/ipvs from 1.0.2 to 1.1.0\n- [#12572](https://github.com/influxdata/telegraf/pull/12572) `deps` Bump github.com/multiplay/go-ts3 from 1.0.1 to 1.1.0\n- [#12581](https://github.com/influxdata/telegraf/pull/12581) `deps` Bump github.com/prometheus/client_golang from 1.13.1 to 1.14.0\n- [#12580](https://github.com/influxdata/telegraf/pull/12580) `deps` Bump github.com/shirou/gopsutil from 3.22.9 to 3.22.12\n- [#12570](https://github.com/influxdata/telegraf/pull/12570) `deps` Bump go.mongodb.org/mongo-driver from 1.11.0 to 1.11.1\n- [#12582](https://github.com/influxdata/telegraf/pull/12582) `deps` Bump golang/x dependencies\n- [#12583](https://github.com/influxdata/telegraf/pull/12583) `deps` Bump google.golang.org/grpc from 1.51.0 to 1.52.0\n- [#12631](https://github.com/influxdata/telegraf/pull/12631) `deps` Bump google.golang.org/grpc from 1.52.0 to 1.52.3\n\n## v1.25.1 [2023-01-30]\n\n### Bugfixes\n\n- [#12549](https://github.com/influxdata/telegraf/pull/12549) `agent` Catch non-existing commands and error out\n- [#12453](https://github.com/influxdata/telegraf/pull/12453) `agent` Correctly reload configuration files\n- [#12491](https://github.com/influxdata/telegraf/pull/12491) `agent` Handle float time with fractions of seconds correctly\n- [#12457](https://github.com/influxdata/telegraf/pull/12457) `agent` Only set default snmp after reading all configs\n- [#12515](https://github.com/influxdata/telegraf/pull/12515) `common.cookie` Allow any 2xx status code\n- [#12459](https://github.com/influxdata/telegraf/pull/12459) `common.kafka` Add keep-alive period setting for input and output\n- [#12240](https://github.com/influxdata/telegraf/pull/12240) `inputs.cisco_telemetry_mdt` Add operation-metric and class-policy prefix\n- [#12533](https://github.com/influxdata/telegraf/pull/12533) `inputs.exec` Restore pre-v1.21 behavior for CSV data_format\n- [#12415](https://github.com/influxdata/telegraf/pull/12415) `inputs.gnmi` Update configuration documentation\n- [#12536](https://github.com/influxdata/telegraf/pull/12536) `inputs.logstash` Collect opensearch specific stats\n- [#12409](https://github.com/influxdata/telegraf/pull/12409) `inputs.mysql` Revert slice declarations with non-zero initial length\n- [#12529](https://github.com/influxdata/telegraf/pull/12529) `inputs.opcua` Fix opcua and opcua-listener for servers using password-based auth\n- [#12522](https://github.com/influxdata/telegraf/pull/12522) `inputs.prometheus` Correctly track deleted pods\n- [#12559](https://github.com/influxdata/telegraf/pull/12559) `inputs.prometheus` Set the timeout for slow running API endpoints correctly\n- [#12384](https://github.com/influxdata/telegraf/pull/12384) `inputs.sqlserver` Add more precise version check\n- [#12387](https://github.com/influxdata/telegraf/pull/12387) `inputs.sqlserver` Added own SPID filter\n- [#12386](https://github.com/influxdata/telegraf/pull/12386) `inputs.sqlserver` SqlRequests include sleeping sessions with open transactions\n- [#12528](https://github.com/influxdata/telegraf/pull/12528) `inputs.sqlserver` Suppress error on secondary replicas\n- [#12516](https://github.com/influxdata/telegraf/pull/12516) `inputs.upsd` Always convert to float\n- [#12486](https://github.com/influxdata/telegraf/pull/12486) `inputs.upsd` Ensure firmware is always a string\n- [#12375](https://github.com/influxdata/telegraf/pull/12375) `inputs.win_eventlog` Handle remote events more robustly\n- [#12404](https://github.com/influxdata/telegraf/pull/12404) `inputs.x509_cert` Fix off-by-one when adding intermediate certificates\n- [#12399](https://github.com/influxdata/telegraf/pull/12399) `outputs.loki` Return response body on error\n- [#12440](https://github.com/influxdata/telegraf/pull/12440) `parsers.json_v2` In case of invalid json, log message to debug log\n- [#12401](https://github.com/influxdata/telegraf/pull/12401) `secretstores` Cleanup duplicate printing\n- [#12468](https://github.com/influxdata/telegraf/pull/12468) `secretstores` Fix handling of \"id\" and print failing secret-store\n- [#12490](https://github.com/influxdata/telegraf/pull/12490) `secretstores` Fix handling of TOML strings\n\n### Dependency Updates\n\n- [#12385](https://github.com/influxdata/telegraf/pull/12385) `deps` Bump cloud.google.com/go/storage from 1.23.0 to 1.28.1\n- [#12511](https://github.com/influxdata/telegraf/pull/12511) `deps` Bump github.com/antchfx/jsonquery from 1.3.0 to 1.3.1\n- [#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\n- [#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\n- [#12476](https://github.com/influxdata/telegraf/pull/12476) `deps` Bump github.com/denisenkom/go-mssqldb from 0.12.0 to 0.12.3\n- [#12378](https://github.com/influxdata/telegraf/pull/12378) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.1 to 1.4.2\n- [#12381](https://github.com/influxdata/telegraf/pull/12381) `deps` Bump github.com/hashicorp/consul/api from 1.15.2 to 1.18.0\n- [#12417](https://github.com/influxdata/telegraf/pull/12417) `deps` Bump github.com/karrick/godirwalk from 1.16.1 to 1.17.0\n- [#12418](https://github.com/influxdata/telegraf/pull/12418) `deps` Bump github.com/kardianos/service from 1.2.1 to 1.2.2\n- [#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\n\n## v1.25.0 [2022-12-12]\n\n### New Plugins\n\n- [#10103](https://github.com/influxdata/telegraf/pull/10103) `inputs.azure_monitor` Azure Monitor\n- [#8413](https://github.com/influxdata/telegraf/pull/8413) `inputs.gcs` Google Cloud Storage\n- [#11824](https://github.com/influxdata/telegraf/pull/11824) `inputs.intel_dlb` Intel DLB\n- [#11814](https://github.com/influxdata/telegraf/pull/11814) `inputs.libvirt` libvirt\n- [#12108](https://github.com/influxdata/telegraf/pull/12108) `inputs.netflow` netflow v5, v9, and IPFIX\n- [#11786](https://github.com/influxdata/telegraf/pull/11786) `inputs.opcua_listener` OPC UA Event subscriptions\n\n### Features\n\n- [#12130](https://github.com/influxdata/telegraf/pull/12130) Add arm64 Windows builds to nightly and CI\n- [#11987](https://github.com/influxdata/telegraf/pull/11987) `agent` Add method to inform of deprecated plugin option values\n- [#11232](https://github.com/influxdata/telegraf/pull/11232) `agent` Secret-store implementation\n- [#12358](https://github.com/influxdata/telegraf/pull/12358) `agent` Deprecate active usage of netsnmp translator\n- [#12302](https://github.com/influxdata/telegraf/pull/12302) `agent.tls` Allow setting renegotiation method\n- [#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\n- [#11860](https://github.com/influxdata/telegraf/pull/11860) `inputs.amqp_consumer` Determine content encoding automatically\n- [#12014](https://github.com/influxdata/telegraf/pull/12014) `inputs.apcupsd` Add new fields\n- [#12342](https://github.com/influxdata/telegraf/pull/12342) `inputs.cgroups` Do not abort on first error, print message once\n- [#8958](https://github.com/influxdata/telegraf/pull/8958) `inputs.conntrack` Parse conntrack stats\n- [#11703](https://github.com/influxdata/telegraf/pull/11703) `inputs.diskio` Allow selecting devices by ID\n- [#11895](https://github.com/influxdata/telegraf/pull/11895) `inputs.ethtool` Gather statistics from namespaces\n- [#12087](https://github.com/influxdata/telegraf/pull/12087) `inputs.ethtool` Possibility to skip gathering metrics for downed interfaces\n- [#12324](https://github.com/influxdata/telegraf/pull/12324) `inputs.http_response` Add User-Agent header\n- [#12304](https://github.com/influxdata/telegraf/pull/12304) `inputs.kafka_consumer` Add sarama debug logs\n- [#11783](https://github.com/influxdata/telegraf/pull/11783) `inputs.knx_listener` Support TCP as transport protocol\n- [#12301](https://github.com/influxdata/telegraf/pull/12301) `inputs.kubernetes` Allow fetching kublet metrics remotely\n\n- [#12255](https://github.com/influxdata/telegraf/pull/12255) `inputs.modbus` Add 8-bit integer types\n- [#11983](https://github.com/influxdata/telegraf/pull/11983) `inputs.modbus` Add config option to pause after connect\n- [#12340](https://github.com/influxdata/telegraf/pull/12340) `inputs.modbus` Add support for half-precision float (float16)\n- [#11106](https://github.com/influxdata/telegraf/pull/11106) `inputs.modbus` Optimize grouped requests\n- [#11273](https://github.com/influxdata/telegraf/pull/11273) `inputs.modbus` Optimize requests\n- [#11630](https://github.com/influxdata/telegraf/pull/11630) `inputs.opcua` Add use regular reads workaround\n- [#9633](https://github.com/influxdata/telegraf/pull/9633) `inputs.powerdns_recursor` Support for new PowerDNS recursor control protocol\n- [#12050](https://github.com/influxdata/telegraf/pull/12050) `inputs.prometheus` Add support for custom header\n- [#11962](https://github.com/influxdata/telegraf/pull/11962) `inputs.prometheus` Allow explicit scrape configuration without annotations\n- [#11729](https://github.com/influxdata/telegraf/pull/11729) `inputs.prometheus` Use system wide proxy settings\n- [#12329](https://github.com/influxdata/telegraf/pull/12329) `inputs.smart` Add additional SMART metrics that indicate/predict device failure\n- [#11872](https://github.com/influxdata/telegraf/pull/11872) `inputs.snmp` Convert enum values\n- [#12187](https://github.com/influxdata/telegraf/pull/12187) `inputs.socket_ listener` Allow to specify message separator for streams\n- [#12351](https://github.com/influxdata/telegraf/pull/12351) `inputs.sqlserver` Add @@SERVICENAME and SERVERPROPERTY(IsClustered) in measurement sqlserver_server_properties\n- [#12126](https://github.com/influxdata/telegraf/pull/12126) `inputs.sqlserver` Add data and log used space metrics for Azure SQL DB\n- [#12292](https://github.com/influxdata/telegraf/pull/12292) `inputs.sqlserver` Add metric available_physical_memory_kb in sqlserver_server_properties\n- [#12319](https://github.com/influxdata/telegraf/pull/12319) `inputs.sqlserver` Introduce timeout for query execution\n- [#12147](https://github.com/influxdata/telegraf/pull/12147) `inputs.system` Collect unique user count logged in\n- [#12281](https://github.com/influxdata/telegraf/pull/12281) `inputs.tail` Add option to preserve newlines for multiline data\n- [#11762](https://github.com/influxdata/telegraf/pull/11762) `inputs.tail` Allow handling of quoted strings spanning multiple lines\n- [#12170](https://github.com/influxdata/telegraf/pull/12170) `inputs.tomcat` Add source tag\n- [#11874](https://github.com/influxdata/telegraf/pull/11874) `outputs.azure_data_explorer` Add support for streaming ingestion for ADX output plugin\n- [#11991](https://github.com/influxdata/telegraf/pull/11991) `outputs.event_hubs` Expose max message size batch option\n- [#11950](https://github.com/influxdata/telegraf/pull/11950) `outputs.graylog` Implement optional connection retries\n- [#11385](https://github.com/influxdata/telegraf/pull/11385) `outputs.timestream` Support ingesting multi-measures\n- [#12232](https://github.com/influxdata/telegraf/pull/12232) `parsers.binary` Handle hex-encoded inputs\n- [#12008](https://github.com/influxdata/telegraf/pull/12008) `parsers.csv` Add option for overwrite tags\n- [#12247](https://github.com/influxdata/telegraf/pull/12247) `parsers.csv` Support null delimiters\n- [#12320](https://github.com/influxdata/telegraf/pull/12320) `parsers.grok` Add option to allow multiline messages\n- [#11933](https://github.com/influxdata/telegraf/pull/11933) `parsers.xpath` Add option to skip (header) bytes\n- [#11999](https://github.com/influxdata/telegraf/pull/11999) `parsers.xpath` Allow to specify byte-array fields to encode in HEX\n- [#11552](https://github.com/influxdata/telegraf/pull/11552) `parsers` Add binary parser\n- [#12260](https://github.com/influxdata/telegraf/pull/12260) `serializers.json` Support serializing JSON nested in string fields\n\n### Bugfixes\n\n- [#12113](https://github.com/influxdata/telegraf/pull/12113) `agent` Run processors in config order\n- [#12127](https://github.com/influxdata/telegraf/pull/12127) `agent` Watch for changes in configuration files in config directories\n- [#12062](https://github.com/influxdata/telegraf/pull/12062) `inputs.conntrack` Skip gather tests if conntrack kernel module is not loaded\n- [#12295](https://github.com/influxdata/telegraf/pull/12295) `inputs.filecount` Revert library version\n- [#12284](https://github.com/influxdata/telegraf/pull/12284) `inputs.kube_inventory` Change default token path, use in-cluster config by default\n- [#12235](https://github.com/influxdata/telegraf/pull/12235) `inputs.modbus` Add workaround to read field in separate requests\n- [#12339](https://github.com/influxdata/telegraf/pull/12339) `inputs.modbus` Fix Windows COM-port path\n- [#12367](https://github.com/influxdata/telegraf/pull/12367) `inputs.modbus` Fix default value of transmission mode\n- [#12330](https://github.com/influxdata/telegraf/pull/12330) `inputs.mongodb` Fix connection leak triggered by config reload\n- [#12101](https://github.com/influxdata/telegraf/pull/12101) `inputs.opcua` Add support for opcua datetime values\n- [#12376](https://github.com/influxdata/telegraf/pull/12376) `inputs.opcua` Parse full range of status codes with uint32\n- [#12278](https://github.com/influxdata/telegraf/pull/12278) `inputs.promethes` Respect selectors when scraping pods\n- [#12323](https://github.com/influxdata/telegraf/pull/12323) `inputs.sql` Cast measurement_column to string\n- [#12259](https://github.com/influxdata/telegraf/pull/12259) `inputs.vsphere` Eliminated duplicate samples\n- [#12307](https://github.com/influxdata/telegraf/pull/12307) `inputs.zfs` Unbreak datasets stats gathering in case listsnaps is enabled on a zfs pool\n- [#12291](https://github.com/influxdata/telegraf/pull/12291) `outputs.azure_data_explorer` Update test call to NewSerializer\n- [#12357](https://github.com/influxdata/telegraf/pull/12357) `processors.parser` Handle empty metric names correctly\n\n### Dependency Updates\n\n- [#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\n- [#12355](https://github.com/influxdata/telegraf/pull/12355) `deps` Update github.com/gosnmp/gosnmp from 1.34.0 to 1.35.0\n- [#12372](https://github.com/influxdata/telegraf/pull/12372) `deps` Update OpenTelemetry from 0.2.30 to 0.2.33\n\n## v1.24.4 [2022-11-29]\n\n### Bugfixes\n\n- [#12177](https://github.com/influxdata/telegraf/pull/12177) `inputs.cloudwatch` Correctly handle multiple namespaces\n- [#12294](https://github.com/influxdata/telegraf/pull/12294) `inputs.directory_monitor` Close input file before removal\n- [#12140](https://github.com/influxdata/telegraf/pull/12140) `inputs.gnmi` Handle decimal_val as per gnmi v0.8.0\n- [#12275](https://github.com/influxdata/telegraf/pull/12275) `inputs.gnmi` Do not provide empty prefix for subscription request\n- [#12258](https://github.com/influxdata/telegraf/pull/12258) `inputs.gnmi` Fix empty name for Sonic devices\n- [#12171](https://github.com/influxdata/telegraf/pull/12171) `inputs.ping` Avoid -x/-X on FreeBSD 13 and newer with ping6\n- [#12282](https://github.com/influxdata/telegraf/pull/12282) `inputs.prometheus` Correctly default to port 9102\n- [#12229](https://github.com/influxdata/telegraf/pull/12229) `input.redis_sentinel` Fix sentinel and replica stats gathering\n- [#12280](https://github.com/influxdata/telegraf/pull/12280) `inputs.socket_listener` Ensure closed connection\n- [#12201](https://github.com/influxdata/telegraf/pull/12201) `output.datadog` Log response in case of non 2XX response from API\n- [#12160](https://github.com/influxdata/telegraf/pull/12160) `outputs.prometheus` Expire metrics correctly during adds\n- [#12156](https://github.com/influxdata/telegraf/pull/12156) `outputs.yandex_cloud_monitoring` Catch int64 values\n\n### Dependency Updates\n\n- [#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\n- [#12197](https://github.com/influxdata/telegraf/pull/12197) `deps` Bump github.com/prometheus/client_golang from 1.13.0 to 1.13.1\n- [#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\n- [#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\n- [#12236](https://github.com/influxdata/telegraf/pull/12236) `deps` Bump github.com/gofrs/uuid from v4.3.0 to v4.3.1\n- [#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\n- [#12238](https://github.com/influxdata/telegraf/pull/12238) `deps` Bump github.com/urfave/cli/v2 from 2.16.3 to 2.23.5\n- [#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\n- [#12248](https://github.com/influxdata/telegraf/pull/12248) `deps` Bump github.com/showwin/speedtest-go from 1.1.5 to 1.2.1\n- [#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\n- [#12268](https://github.com/influxdata/telegraf/pull/12268) `deps` Bump github.com/yuin/goldmark from 1.5.2 to 1.5.3\n- [#12267](https://github.com/influxdata/telegraf/pull/12267) `deps` Bump cloud.google.com/go/pubsub from 1.25.1 to 1.26.0\n- [#12266](https://github.com/influxdata/telegraf/pull/12266) `deps` Bump go.mongodb.org/mongo-driver from 1.10.2 to 1.11.0\n\n## v1.24.3 [2022-11-02]\n\n### Bugfixes\n\n- [#12063](https://github.com/influxdata/telegraf/pull/12063) Restore warning on unused config option(s)\n- [#11941](https://github.com/influxdata/telegraf/pull/11941) Setting `enable_tls` has incorrect default value\n- [#12093](https://github.com/influxdata/telegraf/pull/12093) Update systemd unit description\n- [#12077](https://github.com/influxdata/telegraf/pull/12077) `agent` Fix panic due to tickers slice was off-by-one in size\n- [#12076](https://github.com/influxdata/telegraf/pull/12076) `config` Set default parser\n- [#12124](https://github.com/influxdata/telegraf/pull/12124) `inputs.directory_monitor` Allow cross filesystem directories\n- [#12064](https://github.com/influxdata/telegraf/pull/12064) `inputs.kafka` Switch to sarama's new consumer group rebalance strategy setting\n- [#12038](https://github.com/influxdata/telegraf/pull/12038) `inputs.modbus` Add slave id to failing connection\n- [#12109](https://github.com/influxdata/telegraf/pull/12109) `inputs.modbus` Handle field-measurement definitions correctly on duplicate field check\n- [#11912](https://github.com/influxdata/telegraf/pull/11912) `inputs.modbus` Improve duplicate field checks\n- [#11993](https://github.com/influxdata/telegraf/pull/11993) `inputs.opcua` Add metric tags to node\n- [#11997](https://github.com/influxdata/telegraf/pull/11997) `inputs.syslog` Print error when no error or message given\n- [#12023](https://github.com/influxdata/telegraf/pull/12023) `inputs.zookeeper` Add the ability to parse floats as floats\n- [#11926](https://github.com/influxdata/telegraf/pull/11926) `parsers.json_v2` Remove BOM before parsing\n- [#12116](https://github.com/influxdata/telegraf/pull/12116) `processors.parser` Keep name of original metric if parser doesn't return one\n- [#12081](https://github.com/influxdata/telegraf/pull/12081) `processors` Correctly setup processors\n- [#12016](https://github.com/influxdata/telegraf/pull/12016) `regression` Fixes problem with metrics not exposed by plugins.\n- [#12024](https://github.com/influxdata/telegraf/pull/12024) `serializers.splunkmetric` Provide option to remove event metric tag\n\n### Features\n\n- [#12075](https://github.com/influxdata/telegraf/pull/12075) `tools` Allow to markdown includes for sections\n\n### Dependency Updates\n\n- [#11886](https://github.com/influxdata/telegraf/pull/11886) `deps` Bump github.com/snowflakedb/gosnowflake from 1.6.2 to 1.6.13\n- [#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\n- [#11935](https://github.com/influxdata/telegraf/pull/11935) `deps` Bump github.com/gofrs/uuid from 4.2.0& to 4.3.0\n- [#11894](https://github.com/influxdata/telegraf/pull/11894) `deps` Bump github.com/hashicorp/consul/api from 1.14.0 to 1.15.2\n- [#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\n- [#11972](https://github.com/influxdata/telegraf/pull/11972) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch\n- [#11979](https://github.com/influxdata/telegraf/pull/11979) `deps` Bump github.com/aws/aws-sdk-go-v2/config\n- [#11938](https://github.com/influxdata/telegraf/pull/11938) `deps` Bump k8s.io/apimachinery from 0.25.1 to 0.25.2\n- [#12001](https://github.com/influxdata/telegraf/pull/12001) `deps` Bump k8s.io/api from 0.25.0 to 0.25.2\n- [#12029](https://github.com/influxdata/telegraf/pull/12029) `deps` Bump k8s.io/api from 0.25.2 to 0.25.3\n- [#12030](https://github.com/influxdata/telegraf/pull/12030) `deps` Bump modernc.org/sqlite from 1.17.3 to 1.19.2\n- [#12034](https://github.com/influxdata/telegraf/pull/12034) `deps` Bump github.com/signalfx/golib/v3 from 3.3.45 to 3.3.46\n- [#12035](https://github.com/influxdata/telegraf/pull/12035) `deps` Bump github.com/yuin/goldmark from 1.4.13 to 1.5.2\n- [#11937](https://github.com/influxdata/telegraf/pull/11937) `deps` Bump cloud.google.com/go/bigquery from 1.40.0 to 1.42.0\n- [#12037](https://github.com/influxdata/telegraf/pull/12037) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis\n- [#12036](https://github.com/influxdata/telegraf/pull/12036) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go\n- [#11980](https://github.com/influxdata/telegraf/pull/11980) `deps` Bump github.com/Shopify/sarama from 1.36.0 to 1.37.2\n- [#12039](https://github.com/influxdata/telegraf/pull/12039) `deps` Bump testcontainers-go from 0.13.0 to 0.14.0 and address breaking change\n- [#12090](https://github.com/influxdata/telegraf/pull/12090) `deps` Bump modernc.org/libc from v1.20.3 to v1.21.2\n- [#12098](https://github.com/influxdata/telegraf/pull/12098) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb\n- [#12096](https://github.com/influxdata/telegraf/pull/12096) `deps` Bump google.golang.org/api from 0.95.0 to 0.100.0\n- [#12095](https://github.com/influxdata/telegraf/pull/12095) `deps` Bump github.com/gopcua/opcua from 0.3.3 to 0.3.7\n- [#12097](https://github.com/influxdata/telegraf/pull/12097) `deps` Bump github.com/prometheus/client_model from 0.2.0 to 0.3.0\n- [#12135](https://github.com/influxdata/telegraf/pull/12135) `deps` Bump cloud.google.com/go/monitoring from 1.5.0 to 1.7.0\n- [#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\n\n## v1.24.2 [2022-10-03]\n\n### Bugfixes\n\n- [#11806](https://github.com/influxdata/telegraf/pull/11806) Re-allow specifying the influx parser type\n- [#11896](https://github.com/influxdata/telegraf/pull/11896) `cli` Support old style of filtering sample configs\n- [#11519](https://github.com/influxdata/telegraf/pull/11519) `common.kafka` Enable TLS in Kafka plugins without custom config\n- [#11866](https://github.com/influxdata/telegraf/pull/11866) `inputs.influxdb_listener` Error on invalid precision\n- [#11877](https://github.com/influxdata/telegraf/pull/11877) `inputs.internet_speed` Rename enable_file_download to match upstream intent\n- [#11849](https://github.com/influxdata/telegraf/pull/11849) `inputs.mongodb` Start plugin correctly\n- [#10696](https://github.com/influxdata/telegraf/pull/10696) `inputs.mqtt_consumer` Rework connection and message tracking\n- [#11696](https://github.com/influxdata/telegraf/pull/11696) `internal.ethtool` Avoid internal name conflict with aws\n- [#11875](https://github.com/influxdata/telegraf/pull/11875) `parser.xpath` Handle floating-point times correctly\n\n### Dependency Updates\n\n- [#11861](https://github.com/influxdata/telegraf/pull/11861) Update dependencies for OpenBSD support\n- [#11840](https://github.com/influxdata/telegraf/pull/11840) `deps` Bump k8s.io/apimachinery from 0.25.0 to 0.25.1\n- [#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\n- [#11839](https://github.com/influxdata/telegraf/pull/11839) `deps` Bump github.com/nats-io/nats.go from 1.16.0 to 1.17.0\n- [#11836](https://github.com/influxdata/telegraf/pull/11836) `deps` Replace go-ping by pro-bing\n- [#11887](https://github.com/influxdata/telegraf/pull/11887) `deps` Bump go.mongodb.org/mongo-driver from 1.10.1 to 1.10.2\n- [#11890](https://github.com/influxdata/telegraf/pull/11890) `deps` Bump github.com/aws/smithy-go from 1.13.2 to 1.13.3\n- [#11891](https://github.com/influxdata/telegraf/pull/11891) `deps` Bump github.com/rabbitmq/amqp091-go from 1.4.0 to 1.5.0\n- [#11893](https://github.com/influxdata/telegraf/pull/11893) `deps` Bump github.com/docker/distribution from v2.7.1 to v2.8.1\n\n## v1.24.1 [2022-09-19]\n\n### Bugfixes\n\n- [#11787](https://github.com/influxdata/telegraf/pull/11787) Clear error message when provided config is not a text file\n- [#11835](https://github.com/influxdata/telegraf/pull/11835) Enable global confirmation for installing mingw\n- [#10797](https://github.com/influxdata/telegraf/pull/10797) `inputs.ceph` Modernize Ceph input plugin metrics\n- [#11785](https://github.com/influxdata/telegraf/pull/11785) `inputs.modbus` Do not fail if a single slave reports errors\n- [#11827](https://github.com/influxdata/telegraf/pull/11827) `inputs.ntpq` Handle pools with &#34;-&#34; when\n- [#11825](https://github.com/influxdata/telegraf/pull/11825) `parsers.csv` Remove direct checks for the parser type\n- [#11781](https://github.com/influxdata/telegraf/pull/11781) `parsers.xpath` Add array index when expanding names.\n- [#11815](https://github.com/influxdata/telegraf/pull/11815) `parsers` Memory leak for plugins using ParserFunc.\n- [#11826](https://github.com/influxdata/telegraf/pull/11826) `parsers` Unwrap parser and remove some special handling\n\n### Features\n\n- [#11228](https://github.com/influxdata/telegraf/pull/11228) `processors.parser` Add option to parse tags\n\n### Dependency Updates\n\n- [#11788](https://github.com/influxdata/telegraf/pull/11788) `deps` Bump cloud.google.com/go/pubsub from 1.24.0 to 1.25.1\n- [#11794](https://github.com/influxdata/telegraf/pull/11794) `deps` Bump github.com/urfave/cli/v2 from 2.14.1 to 2.16.3\n- [#11789](https://github.com/influxdata/telegraf/pull/11789) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2\n- [#11799](https://github.com/influxdata/telegraf/pull/11799) `deps` Bump github.com/wavefronthq/wavefront-sdk-go\n- [#11796](https://github.com/influxdata/telegraf/pull/11796) `deps` Bump cloud.google.com/go/bigquery from 1.33.0 to 1.40.0\n\n## v1.24.0 [2022-09-12]\n\n### Bugfixes\n\n- [#11779](https://github.com/influxdata/telegraf/pull/11779) Add missing entry json_transformation to missingTomlField\n- [#11288](https://github.com/influxdata/telegraf/pull/11288) Add reset-mode flag for CSV parser\n- [#11512](https://github.com/influxdata/telegraf/pull/11512) Add version number to MacOS packages\n- [#11489](https://github.com/influxdata/telegraf/pull/11489) Backport sync sample.conf and README.md files\n- [#11777](https://github.com/influxdata/telegraf/pull/11777) Do not error out for parsing errors in datadog mode\n- [#11521](https://github.com/influxdata/telegraf/pull/11521) Make docs & go.mod cleanup post-redis merge\n- [#11656](https://github.com/influxdata/telegraf/pull/11656) Refactor telegraf version\n- [#11563](https://github.com/influxdata/telegraf/pull/11563) Remove shell execution for license-checker\n- [#11755](https://github.com/influxdata/telegraf/pull/11755) Sort labels in prometheusremotewrite serializer\n- [#11440](https://github.com/influxdata/telegraf/pull/11440) Update prometheus parser to be a new style parser plugin\n- [#11456](https://github.com/influxdata/telegraf/pull/11456) Update prometheusremotewrite parser to be a new style parser plugin\n- [#10570](https://github.com/influxdata/telegraf/pull/10570) Use os-agnositc systemd detection, remove sysv in RPM packaging\n- [#11615](https://github.com/influxdata/telegraf/pull/11615) `agent` Add flushBatch method\n- [#11692](https://github.com/influxdata/telegraf/pull/11692) `inputs.jolokia2` Add optional origin header\n- [#11629](https://github.com/influxdata/telegraf/pull/11629) `inputs.mongodb` Add an option to bypass connection errors on start\n- [#11723](https://github.com/influxdata/telegraf/pull/11723) `inputs.opcua` Assign node id correctly\n- [#11673](https://github.com/influxdata/telegraf/pull/11673) `inputs.prometheus` Plugin run outside k8s cluster error\n- [#11701](https://github.com/influxdata/telegraf/pull/11701) `inputs.sqlserver` Fixing wrong filtering for sqlAzureMIRequests and sqlAzureDBRequests\n- [#11471](https://github.com/influxdata/telegraf/pull/11471) `inputs.upsd` Move to new sample.conf style\n- [#11613](https://github.com/influxdata/telegraf/pull/11613) `inputs.x509` Multiple sources with non-overlapping DNS entries\n- [#11767](https://github.com/influxdata/telegraf/pull/11767) `outputs.execd` Fixing the execd behavior to not throw error when partially unserializable metrics are written\n- [#11560](https://github.com/influxdata/telegraf/pull/11560) `outputs.wavefront` Update wavefront sdk and use non-deprecated APIs\n\n### Features\n\n- [#11307](https://github.com/influxdata/telegraf/pull/11307) `serializers.csv` Add CSV serializer\n- [#11054](https://github.com/influxdata/telegraf/pull/11054) `outputs.redistimeseries` Add RedisTimeSeries plugin\n- [#7995](https://github.com/influxdata/telegraf/pull/7995) `outputs.stomp` Add Stomp (Active MQ) output plugin\n- [#11300](https://github.com/influxdata/telegraf/pull/11300) Add default appType as config option to groundwork output\n- [#11398](https://github.com/influxdata/telegraf/pull/11398) Add license checking tool\n- [#11399](https://github.com/influxdata/telegraf/pull/11399) Add proxy support for outputs/cloudwatch\n- [#11516](https://github.com/influxdata/telegraf/pull/11516) Added metrics for member and replica-set avg health of MongoDB\n- [#11233](https://github.com/influxdata/telegraf/pull/11233) Adding aws metric streams input plugin\n- [#9717](https://github.com/influxdata/telegraf/pull/9717) Allow collecting node-level metrics for Couchbase buckets\n- [#11282](https://github.com/influxdata/telegraf/pull/11282) Make the command config a subcommand\n- [#11367](https://github.com/influxdata/telegraf/pull/11367) Migrate collectd parser to new style\n- [#11371](https://github.com/influxdata/telegraf/pull/11371) Migrate dropwizard parser to new style\n- [#11381](https://github.com/influxdata/telegraf/pull/11381) Migrate form_urlencoded parser to new style\n- [#11405](https://github.com/influxdata/telegraf/pull/11405) Migrate graphite parser to new style\n- [#11408](https://github.com/influxdata/telegraf/pull/11408) Migrate grok to new parser style\n- [#11432](https://github.com/influxdata/telegraf/pull/11432) Migrate influx and influx_upstream parsers to new style\n- [#11226](https://github.com/influxdata/telegraf/pull/11226) Migrate json parser to new style\n- [#11343](https://github.com/influxdata/telegraf/pull/11343) Migrate json_v2 parser to new style\n- [#11366](https://github.com/influxdata/telegraf/pull/11366) Migrate logfmt parser to new style\n- [#11402](https://github.com/influxdata/telegraf/pull/11402) Migrate nagios parser to new style\n- [#11700](https://github.com/influxdata/telegraf/pull/11700) Migrate to urfave/cli\n- [#11407](https://github.com/influxdata/telegraf/pull/11407) Migrate value parser to new style\n- [#11374](https://github.com/influxdata/telegraf/pull/11374) Migrate wavefront parser to new style\n- [#11373](https://github.com/influxdata/telegraf/pull/11373) `inputs.nats_consumer` Add simple support for jetstream subjects\n- [#9015](https://github.com/influxdata/telegraf/pull/9015) `inputs.supervisor` Add Supervisord input plugin\n- [#11524](https://github.com/influxdata/telegraf/pull/11524) Tool to build custom Telegraf builds\n- [#11493](https://github.com/influxdata/telegraf/pull/11493) `common.tls` Implement minimum TLS version for clients\n- [#11619](https://github.com/influxdata/telegraf/pull/11619) `external` Add nsdp external plugin\n- [#9890](https://github.com/influxdata/telegraf/pull/9890) `inputs.upsd` Add upsd implementation\n- [#11458](https://github.com/influxdata/telegraf/pull/11458) `inputs.cisco_telemetry_mdt` Add GRPC Keepalive/timeout config options\n- [#11784](https://github.com/influxdata/telegraf/pull/11784) `inputs.directory_monitor` Support paths for files_to_ignore and files_to_monitor\n- [#11773](https://github.com/influxdata/telegraf/pull/11773) `inputs.directory_monitor` Traverse sub-directories\n- [#11220](https://github.com/influxdata/telegraf/pull/11220) `inputs.kafka_consumer` Option to set default fetch message bytes\n- [#8988](https://github.com/influxdata/telegraf/pull/8988) `inputs.linux_cpu` Add plugin to collect CPU metrics on Linux\n- [#9185](https://github.com/influxdata/telegraf/pull/9185) `inputs.logstash` Record number of failures\n- [#11469](https://github.com/influxdata/telegraf/pull/11469) `inputs.modbus` Error out on requests with no fields defined\n- [#11426](https://github.com/influxdata/telegraf/pull/11426) `inputs.mqtt_consumer` Add incoming mqtt message size calculation\n- [#10874](https://github.com/influxdata/telegraf/pull/10874) `inputs.nginx_plus_api` Gather limit_reqs metrics\n- [#11593](https://github.com/influxdata/telegraf/pull/11593) `inputs.ntpq` Add option to specify command flags\n- [#11592](https://github.com/influxdata/telegraf/pull/11592) `inputs.ntpq` Add possibility to query remote servers\n- [#11594](https://github.com/influxdata/telegraf/pull/11594) `inputs.ntpq` Allow to specify `reach` output format\n- [#11572](https://github.com/influxdata/telegraf/pull/11572) `inputs.openstack` Add allow_reauth config option for openstack client\n- [#11391](https://github.com/influxdata/telegraf/pull/11391) `inputs.smart` Collect SSD endurance information where available in smartctl\n- [#11688](https://github.com/influxdata/telegraf/pull/11688) `inputs.sqlserver` Add db name to io stats for MI\n- [#11709](https://github.com/influxdata/telegraf/pull/11709) `inputs.sqlserver` Improved filtering for active requests\n- [#11518](https://github.com/influxdata/telegraf/pull/11518) `inputs.statsd` Add median timing calculation to statsd input plugin\n- [#9440](https://github.com/influxdata/telegraf/pull/9440) `inputs.syslog` Log remote host as source tag\n- [#11271](https://github.com/influxdata/telegraf/pull/11271) `inputs.x509_cert` Add smtp protocol\n- [#11284](https://github.com/influxdata/telegraf/pull/11284) `output.mqtt` Add support for MQTT protocol version 5\n- [#11649](https://github.com/influxdata/telegraf/pull/11649) `outputs.amqp` Add proxy support\n- [#11439](https://github.com/influxdata/telegraf/pull/11439) `outputs.graphite` Retry connecting to servers with failed send attempts\n- [#11443](https://github.com/influxdata/telegraf/pull/11443) `outputs.groundwork` Improve metric parsing to extend output\n- [#11557](https://github.com/influxdata/telegraf/pull/11557) `outputs.iotdb` Add new output plugin to support Apache IoTDB\n- [#11672](https://github.com/influxdata/telegraf/pull/11672) `outputs.postgresql` Add Postgresql output\n- [#11529](https://github.com/influxdata/telegraf/pull/11529) `outputs.redistimeseries` Add integration test\n- [#11551](https://github.com/influxdata/telegraf/pull/11551) `outputs.sql` Add settings for go sql.DB settings\n- [#11251](https://github.com/influxdata/telegraf/pull/11251) `parsers.json` Allow JSONata based transformations in JSON serializer\n- [#11558](https://github.com/influxdata/telegraf/pull/11558) `parsers.xpath` Add support for returning underlying data-types\n- [#11306](https://github.com/influxdata/telegraf/pull/11306) `processors.starlark` Add starlark benchmark for tag-concatenation\n- [#11475](https://github.com/influxdata/telegraf/pull/11475) `inputs.rabbitmq` Add support for head_message_timestamp metric\n- [#9333](https://github.com/influxdata/telegraf/pull/9333) `inputs.redis` Add Redis 6 ACL auth support\n- [#11690](https://github.com/influxdata/telegraf/pull/11690) `serializers.prometheus` Provide option to reduce payload size by removing HELP from payload\n- [#9319](https://github.com/influxdata/telegraf/pull/9319) `proxy.x509_cert` Add proxy support\n\n### Dependency Updates\n\n- [#11671](https://github.com/influxdata/telegraf/pull/11671) Update github.com/jackc/pgx/v4 from 4.16.1 to 4.17.0\n- [#11669](https://github.com/influxdata/telegraf/pull/11669) Update github.com/Azure/go-autorest/autorest from 0.11.24 to 0.11.28\n- [#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\n- [#11675](https://github.com/influxdata/telegraf/pull/11675) Update github.com/urfave/cli/v2 from 2.3.0 to 2.11.2\n- [#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\n- [#11695](https://github.com/influxdata/telegraf/pull/11695) Update github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1695 to 1.61.1727\n- [#11676](https://github.com/influxdata/telegraf/pull/11676) Update go.mongodb.org/mongo-driver from 1.9.1 to 1.10.1\n- [#11710](https://github.com/influxdata/telegraf/pull/11710) Update github.com/wavefronthq/wavefront-sdk-go from 0.10.1 to 0.10.2\n- [#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\n- [#11716](https://github.com/influxdata/telegraf/pull/11716) Update github.com/aerospike/aerospike-client-go/v5 from 5.7.0 to 5.9.0\n- [#11717](https://github.com/influxdata/telegraf/pull/11717) Update github.com/hashicorp/consul/api from 1.13.1 to 1.14.0\n- [#11721](https://github.com/influxdata/telegraf/pull/11721) Update github.com/tidwall/gjson from 1.14.1 to 1.14.3\n- [#11699](https://github.com/influxdata/telegraf/pull/11699) Update github.com/rabbitmq/amqp091-go from 1.3.4 to 1.4.0\n- [#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\n- [#11744](https://github.com/influxdata/telegraf/pull/11744) Update github.com/gophercloud/gophercloud from 0.25.0 to 1.0.0\n- [#11745](https://github.com/influxdata/telegraf/pull/11745) Update k8s.io/client-go from 0.24.3 to 0.25.0\n- [#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\n- [#11763](https://github.com/influxdata/telegraf/pull/11763) Update github.com/urfave/cli/v2 from 2.11.2 to 2.14.1\n- [#11764](https://github.com/influxdata/telegraf/pull/11764) Update gonum.org/v1/gonum from 0.11.0 to 0.12.0\n- [#11770](https://github.com/influxdata/telegraf/pull/11770) Update github.com/Azure/azure-kusto-go from 0.7.0 to 0.8.0\n- [#11746](https://github.com/influxdata/telegraf/pull/11746) Update google.golang.org/grpc from 1.48.0 to 1.49.0\n\n### BREAKING CHANGES\n\n- [#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\n\n## v1.23.4 [2022-08-16]\n\n### Bugfixes\n\n- [#11647](https://github.com/influxdata/telegraf/pull/11647) Bump github.com/lxc/lxd to be able to run tests\n- [#11664](https://github.com/influxdata/telegraf/pull/11664) Sync sql output and input build constraints to handle loong64 in go1.19.\n- [#10841](https://github.com/influxdata/telegraf/pull/10841) Updating credentials file to not use endpoint_url parameter\n- [#10851](https://github.com/influxdata/telegraf/pull/10851) `inputs.cloudwatch` Customizable batch size when querying\n- [#11577](https://github.com/influxdata/telegraf/pull/11577) `inputs.kube_inventory` Send file location to enable token auto-refresh\n- [#11578](https://github.com/influxdata/telegraf/pull/11578) `inputs.kubernetes` Refresh token from file at each read\n- [#11635](https://github.com/influxdata/telegraf/pull/11635) `inputs.mongodb` Update version check for newer versions\n- [#11539](https://github.com/influxdata/telegraf/pull/11539) `inputs.opcua` Return an error with mismatched types\n- [#11548](https://github.com/influxdata/telegraf/pull/11548) `inputs.sqlserver` Set lower deadlock priority\n- [#11556](https://github.com/influxdata/telegraf/pull/11556) `inputs.stackdriver` Handle when no buckets available\n- [#11576](https://github.com/influxdata/telegraf/pull/11576) `inputs` Linter issues\n- [#11595](https://github.com/influxdata/telegraf/pull/11595) `outputs` Linter issues\n- [#11607](https://github.com/influxdata/telegraf/pull/11607) `parsers` Linter issues\n\n### Features\n\n- [#11622](https://github.com/influxdata/telegraf/pull/11622) Add coralogix dialect to opentelemetry\n\n### Dependency Updates\n\n- [#11412](https://github.com/influxdata/telegraf/pull/11412) `deps` Bump github.com/testcontainers/testcontainers-go from 0.12.0 to 0.13.0\n- [#11565](https://github.com/influxdata/telegraf/pull/11565) `deps` Bump github.com/apache/thrift from 0.15.0 to 0.16.0\n- [#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\n- [#11494](https://github.com/influxdata/telegraf/pull/11494) `deps` Update all go.opentelemetry.io dependencies\n- [#11569](https://github.com/influxdata/telegraf/pull/11569) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.1 to 3.4.4\n- [#11574](https://github.com/influxdata/telegraf/pull/11574) `deps` Bump github.com/karrick/godirwalk from 1.16.1 to 1.17.0\n- [#11568](https://github.com/influxdata/telegraf/pull/11568) `deps` Bump github.com/vmware/govmomi from 0.28.0 to 0.29.0\n- [#11347](https://github.com/influxdata/telegraf/pull/11347) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.3.5 to 1.4.1\n- [#11580](https://github.com/influxdata/telegraf/pull/11580) `deps` Bump github.com/shirou/gopsutil/v3 from 3.22.4 to 3.22.7\n- [#11582](https://github.com/influxdata/telegraf/pull/11582) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs\n- [#11583](https://github.com/influxdata/telegraf/pull/11583) `deps` Bump github.com/Azure/go-autorest/autorest/adal\n- [#11581](https://github.com/influxdata/telegraf/pull/11581) `deps` Bump github.com/pion/dtls/v2 from 2.0.13 to 2.1.5\n- [#11590](https://github.com/influxdata/telegraf/pull/11590) `deps` Bump github.com/Azure/azure-event-hubs-go/v3\n- [#11586](https://github.com/influxdata/telegraf/pull/11586) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch\n- [#11585](https://github.com/influxdata/telegraf/pull/11585) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis\n- [#11584](https://github.com/influxdata/telegraf/pull/11584) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb\n- [#11598](https://github.com/influxdata/telegraf/pull/11598) `deps` Bump github.com/signalfx/golib/v3 from 3.3.43 to 3.3.45\n- [#11605](https://github.com/influxdata/telegraf/pull/11605) `deps` Update github.com/BurntSushi/toml from 0.4.1 to 1.2.0\n- [#11604](https://github.com/influxdata/telegraf/pull/11604) `deps` Update cloud.google.com/go/pubsub from 1.23.0 to 1.24.0\n- [#11602](https://github.com/influxdata/telegraf/pull/11602) `deps` Update k8s.io/apimachinery from 0.24.2 to 0.24.3\n- [#11603](https://github.com/influxdata/telegraf/pull/11603) `deps` Update github.com/Shopify/sarama from 1.34.1 to 1.35.0\n- [#11616](https://github.com/influxdata/telegraf/pull/11616) `deps` Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0\n- [#11636](https://github.com/influxdata/telegraf/pull/11636) `deps` Bump github.com/emicklei/go-restful from v2.9.5+incompatible to v3.8.0\n- [#11641](https://github.com/influxdata/telegraf/pull/11641) `deps` Bump github.com/hashicorp/consul/api from 1.12.0 to 1.13.1\n- [#11640](https://github.com/influxdata/telegraf/pull/11640) `deps` Bump github.com/prometheus/client_golang from 1.12.2 to 1.13.0\n- [#11643](https://github.com/influxdata/telegraf/pull/11643) `deps` Bump google.golang.org/api from 0.85.0 to 0.91.0\n- [#11644](https://github.com/influxdata/telegraf/pull/11644) `deps` Bump github.com/antchfx/xmlquery from 1.3.9 to 1.3.12\n- [#11651](https://github.com/influxdata/telegraf/pull/11651) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2\n- [#11652](https://github.com/influxdata/telegraf/pull/11652) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds\n- [#11653](https://github.com/influxdata/telegraf/pull/11653) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs\n\n## v1.23.3 [2022-07-25]\n\n### Bugfixes\n\n- [#11481](https://github.com/influxdata/telegraf/pull/11481) `inputs.openstack` Use v3 volume library\n- [#11482](https://github.com/influxdata/telegraf/pull/11482) `common.cookie` Use reader over readcloser, regen cookie-jar at reauth\n- [#11527](https://github.com/influxdata/telegraf/pull/11527) `inputs.mqtt_consumer` Topic parsing error when topic having prefix '/'\n- [#11534](https://github.com/influxdata/telegraf/pull/11534) `inputs.snmp_trap` Nil map panic when use snmp_trap with netsnmp translator\n- [#11522](https://github.com/influxdata/telegraf/pull/11522) `inputs.sqlserver` Set lower deadlock priority on queries\n- [#11486](https://github.com/influxdata/telegraf/pull/11486) `parsers.prometheus` Histogram infinity bucket must be always present\n\n### Dependency Updates\n\n- [#11461](https://github.com/influxdata/telegraf/pull/11461) Bump github.com/antchfx/jsonquery from 1.1.5 to 1.2.0\n\n## v1.23.2 [2022-07-11]\n\n### Bugfixes\n\n- [#11460](https://github.com/influxdata/telegraf/pull/11460) Deprecation warnings for non-deprecated packages\n- [#11472](https://github.com/influxdata/telegraf/pull/11472) `common.http` Allow 201 for cookies, update header docs\n- [#11448](https://github.com/influxdata/telegraf/pull/11448) `inputs.sqlserver` Use bigint for backupsize in sqlserver\n- [#11011](https://github.com/influxdata/telegraf/pull/11011) `inputs.gnmi` Refactor tag-only subs for complex keys\n- [#10331](https://github.com/influxdata/telegraf/pull/10331) `inputs.snmp` Snmp UseUnconnectedUDPSocket when using udp\n\n### Dependency Updates\n\n- [#11438](https://github.com/influxdata/telegraf/pull/11438) Bump github.com/docker/docker from 20.10.14 to 20.10.17\n\n## v1.23.1 [2022-07-05]\n\n### Bugfixes\n\n- [#11335](https://github.com/influxdata/telegraf/pull/11335) Bring back old xpath section names\n- [#9315](https://github.com/influxdata/telegraf/pull/9315) `inputs.rabbitmq` Don't require listeners to be present in overview\n- [#11280](https://github.com/influxdata/telegraf/pull/11280) Filter out views in mongodb lookup\n- [#11311](https://github.com/influxdata/telegraf/pull/11311) Fix race condition in configuration and prevent concurrent map writes to c.UnusedFields\n- [#11397](https://github.com/influxdata/telegraf/pull/11397) Resolve jolokia2 panic on null response\n- [#11276](https://github.com/influxdata/telegraf/pull/11276) Restore sample configurations broken during initial migration\n- [#11413](https://github.com/influxdata/telegraf/pull/11413) Sync back sample.confs for inputs.couchbase and outputs.groundwork.\n\n### Dependency Updates\n\n- [#11295](https://github.com/influxdata/telegraf/pull/11295) Bump cloud.google.com/go/monitoring from 1.2.0 to 1.5.0\n- [#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\n- [#11318](https://github.com/influxdata/telegraf/pull/11318) Bump google.golang.org/grpc from 1.46.2 to 1.47.0\n- [#11223](https://github.com/influxdata/telegraf/pull/11223) Bump k8s.io/client-go from 0.23.3 to 0.24.1\n- [#11299](https://github.com/influxdata/telegraf/pull/11299) Bump github.com/go-logfmt/logfmt from 0.5.0 to 0.5.1\n- [#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\n- [#11320](https://github.com/influxdata/telegraf/pull/11320) Bump go.mongodb.org/mongo-driver from 1.9.0 to 1.9.1\n- [#11321](https://github.com/influxdata/telegraf/pull/11321) Bump github.com/gophercloud/gophercloud from 0.24.0 to 0.25.0\n- [#11338](https://github.com/influxdata/telegraf/pull/11338) Bump google.golang.org/api from 0.74.0 to 0.84.0\n- [#11340](https://github.com/influxdata/telegraf/pull/11340) Bump github.com/fatih/color from 1.10.0 to 1.13.0\n- [#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\n- [#11319](https://github.com/influxdata/telegraf/pull/11319) Bump github.com/Shopify/sarama from 1.32.0 to 1.34.1\n- [#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\n- [#11339](https://github.com/influxdata/telegraf/pull/11339) Bump github.com/nats-io/nats.go from 1.15.0 to 1.16.0\n- [#11349](https://github.com/influxdata/telegraf/pull/11349) Bump cloud.google.com/go/pubsub from 1.18.0 to 1.22.2\n- [#11369](https://github.com/influxdata/telegraf/pull/11369) Bump go.opentelemetry.io/collector/pdata from 0.52.0 to 0.54.0\n- [#11346](https://github.com/influxdata/telegraf/pull/11346) Bump github.com/jackc/pgx/v4 from 4.15.0 to 4.16.1\n- [#11379](https://github.com/influxdata/telegraf/pull/11379) Bump cloud.google.com/go/bigquery from 1.8.0 to 1.33.0\n- [#11378](https://github.com/influxdata/telegraf/pull/11378) Bump github.com/Azure/azure-kusto-go from 0.6.0 to 0.7.0\n- [#11394](https://github.com/influxdata/telegraf/pull/11394) Bump cloud.google.com/go/pubsub from 1.22.2 to 1.23.0\n- [#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\n- [#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\n- [#11395](https://github.com/influxdata/telegraf/pull/11395) Bump github.com/golang-jwt/jwt/v4 from 4.4.1 to 4.4.2\n- [#11396](https://github.com/influxdata/telegraf/pull/11396) Bump github.com/vmware/govmomi from 0.27.3 to 0.28.0\n- [#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\n- [#11416](https://github.com/influxdata/telegraf/pull/11416) Bump github.com/influxdata/influxdb-observability/otel2influx from 0.2.21 to 0.2.22\n- [#11434](https://github.com/influxdata/telegraf/pull/11434) Bump k8s.io/api from 0.24.1 to 0.24.2\n- [#11437](https://github.com/influxdata/telegraf/pull/11437) Bump github.com/prometheus/client_golang from 1.12.1 to 1.12.2\n\n## v1.23.0 [2022-06-13]\n\n### Bugfixes\n\n- [#11272](https://github.com/influxdata/telegraf/pull/11272) Add missing build constraints for sqlite\n- [#11253](https://github.com/influxdata/telegraf/pull/11253) Always build README-embedder for host-architecture\n- [#11140](https://github.com/influxdata/telegraf/pull/11140) Avoid calling sadc with invalid 0 interval\n- [#11093](https://github.com/influxdata/telegraf/pull/11093) Check net.Listen() error in tests\n- [#11181](https://github.com/influxdata/telegraf/pull/11181) Convert slab plugin to new sample.conf.\n- [#10979](https://github.com/influxdata/telegraf/pull/10979) Datadog count metrics\n- [#11044](https://github.com/influxdata/telegraf/pull/11044) Deprecate useless database config option\n- [#11150](https://github.com/influxdata/telegraf/pull/11150) Doc interval setting for internet speed plugin\n- [#11120](https://github.com/influxdata/telegraf/pull/11120) Elasticsearch output float handling test\n- [#11151](https://github.com/influxdata/telegraf/pull/11151) Improve slab testing without sudo.\n- [#10995](https://github.com/influxdata/telegraf/pull/10995) Log instance name in skip warnings\n- [#11069](https://github.com/influxdata/telegraf/pull/11069) Output erroneous namespace and continue instead of error out\n- [#11237](https://github.com/influxdata/telegraf/pull/11237) Re-add event to splunk serializer\n- [#11143](https://github.com/influxdata/telegraf/pull/11143) Redis plugin goroutine leak triggered by auto reload config mechanism\n- [#11082](https://github.com/influxdata/telegraf/pull/11082) Remove any content type from prometheus accept header\n- [#11261](https://github.com/influxdata/telegraf/pull/11261) Remove full access permissions\n- [#11179](https://github.com/influxdata/telegraf/pull/11179) Search services file in /etc/services and fall back to /usr/etc/services\n- [#11217](https://github.com/influxdata/telegraf/pull/11217) Update sample.conf for prometheus\n- [#11241](https://github.com/influxdata/telegraf/pull/11241) Upgrade xpath and fix code\n- [#11083](https://github.com/influxdata/telegraf/pull/11083) Use readers over closers in http input\n- [#11149](https://github.com/influxdata/telegraf/pull/11149) `inputs.burrow` Move Dialer to variable and run `make fmt`\n- [#10812](https://github.com/influxdata/telegraf/pull/10812) `outputs.sql` Table existence cache\n\n### Features\n\n- [#10880](https://github.com/influxdata/telegraf/pull/10880) Add ANSI color filter for tail input plugin\n- [#11188](https://github.com/influxdata/telegraf/pull/11188) Add constant &#39;algorithm&#39; to the mock plugin\n- [#11159](https://github.com/influxdata/telegraf/pull/11159) Add external huebridge input plugin\n- [#11076](https://github.com/influxdata/telegraf/pull/11076) Add field key option to set event partition key\n- [#10818](https://github.com/influxdata/telegraf/pull/10818) Add fritzbox as external plugin\n- [#11037](https://github.com/influxdata/telegraf/pull/11037) Add influx semantic commits checker, checks only last commit.\n- [#11039](https://github.com/influxdata/telegraf/pull/11039) Add mount option filtering to disk plugin\n- [#11075](https://github.com/influxdata/telegraf/pull/11075) Add slab metrics input plugin\n- [#11056](https://github.com/influxdata/telegraf/pull/11056) Allow other fluentd metrics apart from retry_count, buffer_queu…\n- [#10918](https://github.com/influxdata/telegraf/pull/10918) Artifactory Webhook Receiver\n- [#11000](https://github.com/influxdata/telegraf/pull/11000) Create and push nightly docker images to quay.io\n- [#11102](https://github.com/influxdata/telegraf/pull/11102) Do not error if no nodes found for current config with xpath parser\n- [#10886](https://github.com/influxdata/telegraf/pull/10886) Generate the plugins sample config\n- [#11084](https://github.com/influxdata/telegraf/pull/11084) Google API Auth\n- [#10607](https://github.com/influxdata/telegraf/pull/10607) In Lustre input plugin, support collecting per-client stats.\n- [#10912](https://github.com/influxdata/telegraf/pull/10912) Migrate aggregator plugins to new sample config format\n- [#10924](https://github.com/influxdata/telegraf/pull/10924) Migrate input plugins to new sample config format (A-L)\n- [#10926](https://github.com/influxdata/telegraf/pull/10926) Migrate input plugins to new sample config format (M-Z)\n- [#10910](https://github.com/influxdata/telegraf/pull/10910) Migrate output plugins to new sample config format\n- [#10913](https://github.com/influxdata/telegraf/pull/10913) Migrate processor plugins to new sample config format\n- [#11218](https://github.com/influxdata/telegraf/pull/11218) Migrate xpath parser to new style\n- [#10885](https://github.com/influxdata/telegraf/pull/10885) Update etc/telegraf.conf and etc/telegraf_windows.conf\n- [#6948](https://github.com/influxdata/telegraf/pull/6948) `inputs.burrow` fill more http transport parameters\n- [#11141](https://github.com/influxdata/telegraf/pull/11141) `inputs.cpu` Add tags with core id or physical id to cpus\n- [#7896](https://github.com/influxdata/telegraf/pull/7896) `inputs.mongodb` Add metrics about files currently open and currently active data handles\n- [#10448](https://github.com/influxdata/telegraf/pull/10448) `inputs.nginx_plus_api` Gather slab metrics\n- [#11216](https://github.com/influxdata/telegraf/pull/11216) `inputs.sqlserver` Update query store and latch performance counters\n- [#10574](https://github.com/influxdata/telegraf/pull/10574) `inputs.vsphere` Collect resource pools metrics and add resource pool tag in VM metrics\n- [#11035](https://github.com/influxdata/telegraf/pull/11035) `inputs.intel_powerstat` Add Max Turbo Frequency and introduce improvements\n- [#11254](https://github.com/influxdata/telegraf/pull/11254) `inputs.intel_powerstat` Add uncore frequency metrics\n- [#10954](https://github.com/influxdata/telegraf/pull/10954) `outputs.http` Support configuration of `MaxIdleConns` and `MaxIdleConnsPerHost`\n- [#10853](https://github.com/influxdata/telegraf/pull/10853) `outputs.elasticsearch` Add healthcheck timeout\n\n### Dependency Updates\n\n- [#10970](https://github.com/influxdata/telegraf/pull/10970) Update github.com/wavefronthq/wavefront-sdk-go from 0.9.10 to 0.9.11\n- [#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\n- [#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\n- [#11088](https://github.com/influxdata/telegraf/pull/11088) Update go.opentelemetry.io/otel/metric from 0.28.0 to 0.30.0\n- [#11221](https://github.com/influxdata/telegraf/pull/11221) Update github.com/nats-io/nats-server/v2 from 2.7.4 to 2.8.4\n- [#11191](https://github.com/influxdata/telegraf/pull/11191) Update golangci-lint from v1.45.2 to v1.46.2\n- [#11107](https://github.com/influxdata/telegraf/pull/11107) Update gopsutil from v3.22.3 to v3.22.4 to allow for HOST_PROC_MOUNTINFO.\n- [#11242](https://github.com/influxdata/telegraf/pull/11242) Update moby/ipvs dependency from v1.0.1 to v1.0.2\n- [#11260](https://github.com/influxdata/telegraf/pull/11260) Update modernc.org/sqlite from v1.10.8 to v1.17.3\n- [#11266](https://github.com/influxdata/telegraf/pull/11266) Update github.com/containerd/containerd from v1.5.11 to v1.5.13\n- [#11264](https://github.com/influxdata/telegraf/pull/11264) Update github.com/tidwall/gjson from 1.10.2 to 1.14.1\n\n## v1.22.4 [2022-05-16]\n\n### Bugfixes\n\n- [#11045](https://github.com/influxdata/telegraf/pull/11045) `inputs.couchbase` Do not assume metrics will all be of the same length\n- [#11043](https://github.com/influxdata/telegraf/pull/11043) `inputs.statsd` Do not error when closing statsd network connection\n- [#11030](https://github.com/influxdata/telegraf/pull/11030) `outputs.azure_monitor` Re-init azure monitor http client on context deadline error\n- [#11078](https://github.com/influxdata/telegraf/pull/11078) `outputs.wavefront` If no \"host\" tag is provided do not add \"telegraf.host\" tag\n- [#11042](https://github.com/influxdata/telegraf/pull/11042) Have telegraf service wait for network up in systemd packaging\n\n### Dependency Updates\n\n- [#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\n- [#11085](https://github.com/influxdata/telegraf/pull/11085) Update OpenTelemetry plugins to v0.51.0\n\n## v1.22.3 [2022-04-28]\n\n### Bugfixes\n\n- [#10961](https://github.com/influxdata/telegraf/pull/10961) Update Go to 1.18.1\n- [#10976](https://github.com/influxdata/telegraf/pull/10976) `inputs.influxdb_listener` Remove duplicate influxdb listener writes with upstream parser\n- [#11024](https://github.com/influxdata/telegraf/pull/11024) `inputs.gnmi` Use external xpath parser for gnmi\n- [#10925](https://github.com/influxdata/telegraf/pull/10925) `inputs.system` Reduce log level in disk plugin back to original level\n\n## v1.22.2 [2022-04-25]\n\n### Bugfixes\n\n- [#11008](https://github.com/influxdata/telegraf/pull/11008) `inputs.gnmi` Add mutex to gnmi lookup map\n- [#11010](https://github.com/influxdata/telegraf/pull/11010) `inputs.gnmi` Use sprint to cast to strings in gnmi\n- [#11001](https://github.com/influxdata/telegraf/pull/11001) `inputs.consul_agent` Use correct auth token with consul_agent\n- [#10486](https://github.com/influxdata/telegraf/pull/10486) `inputs.mysql` Add mariadb_dialect to address the MariaDB differences in INNODB_METRICS\n- [#10923](https://github.com/influxdata/telegraf/pull/10923) `inputs.smart` Correctly parse various numeric forms\n- [#10850](https://github.com/influxdata/telegraf/pull/10850) `inputs.aliyuncms` Ensure aliyuncms metrics accept array, fix discovery\n- [#10930](https://github.com/influxdata/telegraf/pull/10930) `inputs.aerospike` Statistics query bug\n- [#10947](https://github.com/influxdata/telegraf/pull/10947) `inputs.cisco_telemetry_mdt` Align the default value for msg size\n- [#10959](https://github.com/influxdata/telegraf/pull/10959) `inputs.cisco_telemetry_mdt` Remove overly verbose info message from cisco mdt\n- [#10958](https://github.com/influxdata/telegraf/pull/10958) `outputs.influxdb_v2` Improve influxdb_v2 error message\n- [#10932](https://github.com/influxdata/telegraf/pull/10932) `inputs.prometheus` Moved from watcher to informer\n- [#11013](https://github.com/influxdata/telegraf/pull/11013) Also allow 0 outputs when using test-wait parameter\n- [#11015](https://github.com/influxdata/telegraf/pull/11015) Allow Makefile to work on Windows\n\n### Dependency Updates\n\n- [#10966](https://github.com/influxdata/telegraf/pull/10966) Update github.com/Azure/azure-kusto-go from 0.5.0 to 0.60\n- [#10963](https://github.com/influxdata/telegraf/pull/10963) Update opentelemetry from v0.2.10 to v0.2.17\n- [#10984](https://github.com/influxdata/telegraf/pull/10984) Update go.opentelemetry.io/collector/pdata from v0.48.0 to v0.49.0\n- [#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\n- [#10997](https://github.com/influxdata/telegraf/pull/10997) Update github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs\n- [#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\n- [#10981](https://github.com/influxdata/telegraf/pull/10981) Update github.com/containerd/containerd from v1.5.9 to v1.5.11\n- [#10973](https://github.com/influxdata/telegraf/pull/10973) Update github.com/miekg/dns from 1.1.46 to 1.1.48\n- [#10974](https://github.com/influxdata/telegraf/pull/10974) Update github.com/gopcua/opcua from v0.3.1 to v0.3.3\n- [#10972](https://github.com/influxdata/telegraf/pull/10972) Update github.com/aws/aws-sdk-go-v2/service/dynamodb\n- [#10773](https://github.com/influxdata/telegraf/pull/10773) Update github.com/xdg/scram from 1.0.3 to 1.0.5\n- [#10971](https://github.com/influxdata/telegraf/pull/10971) Update go.mongodb.org/mongo-driver from 1.8.3 to 1.9.0\n- [#10940](https://github.com/influxdata/telegraf/pull/10940) Update starlark 7a1108eaa012->d1966c6b9fcd\n\n## v1.22.1 [2022-04-06]\n\n### Bugfixes\n\n- [#10937](https://github.com/influxdata/telegraf/pull/10937) Update gonum.org/v1/gonum from 0.9.3 to 0.11.0\n- [#10906](https://github.com/influxdata/telegraf/pull/10906) Update github.com/golang-jwt/jwt/v4 from 4.2.0 to 4.4.1\n- [#10931](https://github.com/influxdata/telegraf/pull/10931) Update gopsutil and associated dependencies for improved OpenBSD support\n- [#10553](https://github.com/influxdata/telegraf/pull/10553) `inputs.sqlserver` Fix inconsistencies in sql*Requests queries\n- [#10883](https://github.com/influxdata/telegraf/pull/10883) `agent` Fix default value for logfile rotation interval\n- [#10871](https://github.com/influxdata/telegraf/pull/10871) `inputs.zfs` Fix redundant zfs pool tag\n- [#10903](https://github.com/influxdata/telegraf/pull/10903) `inputs.vsphere` Update vsphere info message to debug\n- [#10866](https://github.com/influxdata/telegraf/pull/10866) `outputs.azure_monitor` Include body in error message\n- [#10830](https://github.com/influxdata/telegraf/pull/10830) `processors.topk` Clarify the k and fields topk params\n- [#10858](https://github.com/influxdata/telegraf/pull/10858) `outputs.http` Switch HTTP 100 test case values\n- [#10859](https://github.com/influxdata/telegraf/pull/10859) `inputs.intel_pmu` Fix slow running intel-pmu test\n- [#10860](https://github.com/influxdata/telegraf/pull/10860) `inputs.cloud_pubsub` Skip longer/integration tests on -short mode\n- [#10861](https://github.com/influxdata/telegraf/pull/10861) `inputs.cloud_pubsub_push` Reduce timeouts and sleeps\n\n### New External Plugins\n\n- [#10462](https://github.com/influxdata/telegraf/pull/10462) `external.psi` Add psi plugin\n\n## v1.22.0\n\n### Influx Line Protocol Parser\n\nThere is an option to use a faster, more memory-efficient\nimplementation of the Influx Line Protocol parser.\n\n### SNMP Translator\n\nThis version introduces an agent setting to select the method of\ntranslating SNMP objects. The agent setting \"snmp_translator\" can be\n\"netsnmp\" which translates by calling external programs snmptranslate\nand snmptable, or \"gosmi\" which translates using the built-in gosmi\nlibrary.\n\nBefore version 1.21.0, Telegraf only used the netsnmp method. Versions\n1.21.0 through 1.21.4 only used the gosmi method. Since the\ntranslation method is now configurable and \"netsnmp\" is the default,\nusers who wish to continue using \"gosmi\" must add `snmp_translator =\n\"gosmi\"` in the agent section of their config file. See\n[#10802](https://github.com/influxdata/telegraf/pull/10802).\n\n### New Input Plugins\n\n- [#3649](https://github.com/influxdata/telegraf/pull/3649) `inputs.socketstat` Add socketstat input plugin\n- [#9697](https://github.com/influxdata/telegraf/pull/9697) `inputs.xtremio` Add xtremio input\n- [#9782](https://github.com/influxdata/telegraf/pull/9782) `inputs.mock` Add mock input plugin\n- [#10042](https://github.com/influxdata/telegraf/pull/10042) `inputs.redis_sentinel` Add redis sentinel input plugin\n- [#10106](https://github.com/influxdata/telegraf/pull/10106) `inputs.nomad` Add nomad input plugin\n- [#10198](https://github.com/influxdata/telegraf/pull/10198) `inputs.vault` Add vault input plugin\n- [#10258](https://github.com/influxdata/telegraf/pull/10258) `inputs.consul_agent` Add consul agent input plugin\n- [#10763](https://github.com/influxdata/telegraf/pull/10763) `inputs.hugepages` Add hugepages input plugin\n\n### New Processor Plugins\n\n- [#10057](https://github.com/influxdata/telegraf/pull/10057) `processors.noise` Add noise processor plugin\n\n### Features\n\n- [#9332](https://github.com/influxdata/telegraf/pull/9332) `agent` HTTP basic auth for webhooks\n- [#10307](https://github.com/influxdata/telegraf/pull/10307) `agent` Improve error logging on plugin initialization\n- [#10341](https://github.com/influxdata/telegraf/pull/10341) `agent` Check TLSConfig early to catch missing certificates\n- [#10404](https://github.com/influxdata/telegraf/pull/10404) `agent` Support headers for http plugin with cookie auth\n- [#10545](https://github.com/influxdata/telegraf/pull/10545) `agent` Add a collection offset implementation\n- [#10559](https://github.com/influxdata/telegraf/pull/10559) `agent` Add autorestart and restartdelay flags to Windows service\n- [#10515](https://github.com/influxdata/telegraf/pull/10515) `aggregators.histogram` Add config option to push only updated values\n- [#10520](https://github.com/influxdata/telegraf/pull/10520) `aggregators.histogram` Add expiration option\n- [#10137](https://github.com/influxdata/telegraf/pull/10137) `inputs.bond` Add additional stats to bond collector\n- [#10382](https://github.com/influxdata/telegraf/pull/10382) `inputs.docker` Update docker client API version\n- [#10575](https://github.com/influxdata/telegraf/pull/10575) `inputs.file` Allow for stateful parser handling\n- [#7484](https://github.com/influxdata/telegraf/pull/7484) `inputs.gnmi` add dynamic tagging to gnmi plugin\n- [#10220](https://github.com/influxdata/telegraf/pull/10220) `inputs.graylog` Add timeout setting option\n- [#10530](https://github.com/influxdata/telegraf/pull/10530) `inputs.internet_speed` Add caching to internet_speed\n- [#10243](https://github.com/influxdata/telegraf/pull/10243) `inputs.kibana` Add heap_size_limit field\n- [#10641](https://github.com/influxdata/telegraf/pull/10641) `inputs.memcached` gather additional stats from memcached\n- [#10642](https://github.com/influxdata/telegraf/pull/10642) `inputs.memcached` Support client TLS origination\n- [#9279](https://github.com/influxdata/telegraf/pull/9279) `inputs.modbus` Support multiple slaves with gateway\n- [#10231](https://github.com/influxdata/telegraf/pull/10231) `inputs.modbus` Add per-request tags\n- [#10625](https://github.com/influxdata/telegraf/pull/10625) `inputs.mongodb` Add FsTotalSize and FsUsedSize fields\n- [#10787](https://github.com/influxdata/telegraf/pull/10787) `inputs.nfsclient` Add new rtt per op field\n- [#10705](https://github.com/influxdata/telegraf/pull/10705) `inputs.openweathermap` Add feels_like field\n- [#9710](https://github.com/influxdata/telegraf/pull/9710) `inputs.postgresql` Add option to disable prepared statements for PostgreSQL\n- [#10339](https://github.com/influxdata/telegraf/pull/10339) `inputs.snmp_trap` Deprecate unused snmp_trap timeout configuration option\n- [#9671](https://github.com/influxdata/telegraf/pull/9671) `inputs.sql` Add ClickHouse driver to sql inputs/outputs plugins\n- [#10466](https://github.com/influxdata/telegraf/pull/10466) `inputs.statsd` Add option to sanitize collected metric names\n- [#9432](https://github.com/influxdata/telegraf/pull/9432) `inputs.varnish` Create option to reduce potentially high cardinality\n- [#6501](https://github.com/influxdata/telegraf/pull/6501) `inputs.win_perf_counters` Implemented support for reading raw values, added tests and doc\n- [#10535](https://github.com/influxdata/telegraf/pull/10535) `inputs.win_perf_counters` Allow errors to be ignored\n- [#9822](https://github.com/influxdata/telegraf/pull/9822) `inputs.x509_cert` Add exclude_root_certs option to x509_cert plugin\n- [#9963](https://github.com/influxdata/telegraf/pull/9963) `outputs.datadog` Add the option to use compression\n- [#10505](https://github.com/influxdata/telegraf/pull/10505) `outputs.elasticsearch` Add elastic pipeline flags\n- [#10499](https://github.com/influxdata/telegraf/pull/10499) `outputs.groundwork` Process group tags\n- [#10186](https://github.com/influxdata/telegraf/pull/10186) `outputs.http` Add optional list of non retryable http status codes\n- [#10202](https://github.com/influxdata/telegraf/pull/10202) `outputs.http` Support AWS managed service for prometheus\n- [#8192](https://github.com/influxdata/telegraf/pull/8192) `outputs.kafka` Add socks5 proxy support\n- [#10673](https://github.com/influxdata/telegraf/pull/10673) `outputs.sql` Add unsigned style config option\n- [#10672](https://github.com/influxdata/telegraf/pull/10672) `outputs.websocket` Add socks5 proxy support\n- [#10267](https://github.com/influxdata/telegraf/pull/10267) `parsers.csv` Add option to skip errors during parsing\n- [#10749](https://github.com/influxdata/telegraf/pull/10749) `parsers.influx` Add new influx line protocol parser via feature flag\n- [#10585](https://github.com/influxdata/telegraf/pull/10585) `parsers.xpath` Add tag batch-processing to XPath parser\n- [#10316](https://github.com/influxdata/telegraf/pull/10316) `processors.template` Add more functionality to template processor\n- [#10252](https://github.com/influxdata/telegraf/pull/10252) `serializers.wavefront` Add option to disable Wavefront prefix conversion\n\n### Bugfixes\n\n- [#10803](https://github.com/influxdata/telegraf/pull/10803) `agent` Update parsing logic of config.Duration to correctly require time and duration\n- [#10814](https://github.com/influxdata/telegraf/pull/10814) `agent` Update the precision parameter default value\n- [#10872](https://github.com/influxdata/telegraf/pull/10872) `agent` Change name of agent snmp translator setting\n- [#10876](https://github.com/influxdata/telegraf/pull/10876) `inputs.consul_agent` Rename consul_metrics -> consul_agent\n- [#10711](https://github.com/influxdata/telegraf/pull/10711) `inputs.docker` Keep data type of tasks_desired field consistent\n- [#10083](https://github.com/influxdata/telegraf/pull/10083) `inputs.http` Add metadata support to CSV parser plugin\n- [#10701](https://github.com/influxdata/telegraf/pull/10701) `inputs.mdstat` Fix parsing output when when sync is less than 10%\n- [#10385](https://github.com/influxdata/telegraf/pull/10385) `inputs.modbus` Re-enable OpenBSD modbus support\n- [#10790](https://github.com/influxdata/telegraf/pull/10790) `inputs.ntpq` Correctly read ntpq long poll output with extra characters\n- [#10384](https://github.com/influxdata/telegraf/pull/10384) `inputs.opcua` Accept non-standard OPC UA OK status by implementing a configurable workaround\n- [#10465](https://github.com/influxdata/telegraf/pull/10465) `inputs.opcua` Add additional data to error messages\n- [#10735](https://github.com/influxdata/telegraf/pull/10735) `inputs.snmp` Log err when loading mibs\n- [#10748](https://github.com/influxdata/telegraf/pull/10748) `inputs.snmp` Use the correct path when evaluating symlink\n- [#10802](https://github.com/influxdata/telegraf/pull/10802) `inputs.snmp` Add option to select translator\n- [#10527](https://github.com/influxdata/telegraf/pull/10527) `inputs.system` Remove verbose logging from disk input plugin\n- [#10706](https://github.com/influxdata/telegraf/pull/10706) `outputs.influxdb_v2` Include influxdb bucket name in error messages\n- [#10623](https://github.com/influxdata/telegraf/pull/10623) `outputs.groundwork` Set NextCheckTime to LastCheckTime to avoid GroundWork to invent a value\n- [#10749](https://github.com/influxdata/telegraf/pull/10749) `parsers.influx` Add new influx line protocol parser via feature flag\n- [#10777](https://github.com/influxdata/telegraf/pull/10777) `parsers.json_v2` Allow multiple optional objects\n- [#10799](https://github.com/influxdata/telegraf/pull/10799) `parsers.json_v2` Check if gpath exists and support optional in fields/tags\n- [#10798](https://github.com/influxdata/telegraf/pull/10798) `parsers.xpath` Correctly handling imports in protocol-buffer definitions\n- [#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\n- [#10604](https://github.com/influxdata/telegraf/pull/10604) Update github.com/aerospike/aerospike-client-go from 1.27.0 to 5.7.0\n- [#10686](https://github.com/influxdata/telegraf/pull/10686) Update github.com/sleepinggenius2/gosmi from v0.4.3 to v0.4.4\n- [#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\n- [#10693](https://github.com/influxdata/telegraf/pull/10693) Update github.com/gophercloud/gophercloud from 0.16.0 to 0.24.0\n- [#10702](https://github.com/influxdata/telegraf/pull/10702) Update github.com/jackc/pgx/v4 from 4.14.1 to 4.15.0\n- [#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\n- [#10713](https://github.com/influxdata/telegraf/pull/10713) Update k8s.io/api from 0.23.3 to 0.23.4\n- [#10714](https://github.com/influxdata/telegraf/pull/10714) Update cloud.google.com/go/pubsub from 1.17.1 to 1.18.0\n- [#10715](https://github.com/influxdata/telegraf/pull/10715) Update github.com/newrelic/newrelic-telemetry-sdk-go from 0.5.1 to 0.8.1\n- [#10717](https://github.com/influxdata/telegraf/pull/10717) Update github.com/ClickHouse/clickhouse-go from 1.5.1 to 1.5.4\n- [#10718](https://github.com/influxdata/telegraf/pull/10718) Update github.com/wavefronthq/wavefront-sdk-go from 0.9.9 to 0.9.10\n- [#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\n- [#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\n- [#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\n- [#10728](https://github.com/influxdata/telegraf/pull/10728) Update github.com/testcontainers/testcontainers-go from 0.11.1 to 0.12.0\n- [#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\n- [#10752](https://github.com/influxdata/telegraf/pull/10752) Update github.com/nats-io/nats-server/v2 from 2.7.2 to 2.7.3\n- [#10757](https://github.com/influxdata/telegraf/pull/10757) Update github.com/miekg/dns from 1.1.43 to 1.1.46\n- [#10758](https://github.com/influxdata/telegraf/pull/10758) Update github.com/shirou/gopsutil/v3 from 3.21.12 to 3.22.2\n- [#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\n- [#10772](https://github.com/influxdata/telegraf/pull/10772) Update github.com/Shopify/sarama from 1.29.1 to 1.32.0\n- [#10807](https://github.com/influxdata/telegraf/pull/10807) Update github.com/nats-io/nats-server/v2 from 2.7.3 to 2.7.4\n\n## v1.21.4 [2022-02-16]\n\n### Bugfixes\n\n- [#10491](https://github.com/influxdata/telegraf/pull/10491) `inputs.docker` Update docker memory usage calculation\n- [#10636](https://github.com/influxdata/telegraf/pull/10636) `inputs.ecs` Use current time as timestamp\n- [#10551](https://github.com/influxdata/telegraf/pull/10551) `inputs.snmp` Ensure folders do not get loaded more than once\n- [#10579](https://github.com/influxdata/telegraf/pull/10579) `inputs.win_perf_counters` Add deprecated warning and version to win_perf_counters option\n- [#10635](https://github.com/influxdata/telegraf/pull/10635) `outputs.amqp` Check for nil client before closing in amqp\n- [#10179](https://github.com/influxdata/telegraf/pull/10179) `outputs.azure_data_explorer` Lower RAM usage\n- [#10513](https://github.com/influxdata/telegraf/pull/10513) `outputs.elasticsearch` Add scheme to fix error in sniffing option\n- [#10657](https://github.com/influxdata/telegraf/pull/10657) `parsers.json_v2` Fix timestamp change during execution of json_v2 parser\n- [#10618](https://github.com/influxdata/telegraf/pull/10618) `parsers.json_v2` Fix incorrect handling of json_v2 timestamp_path\n- [#10468](https://github.com/influxdata/telegraf/pull/10468) `parsers.json_v2` Allow optional paths and handle wrong paths correctly\n- [#10547](https://github.com/influxdata/telegraf/pull/10547) `serializers.prometheusremotewrite` Use the correct timestamp unit\n- [#10647](https://github.com/influxdata/telegraf/pull/10647) Update all go.opentelemetry.io from 0.24.0 to 0.27.0\n- [#10652](https://github.com/influxdata/telegraf/pull/10652) Update github.com/signalfx/golib/v3 from 3.3.38 to 3.3.43\n- [#10653](https://github.com/influxdata/telegraf/pull/10653) Update github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1004 to 1.61.1483\n- [#10503](https://github.com/influxdata/telegraf/pull/10503) Update github.com/denisenkom/go-mssqldb from 0.10.0 to 0.12.0\n- [#10626](https://github.com/influxdata/telegraf/pull/10626) Update github.com/gopcua/opcua from 0.2.3 to 0.3.1\n- [#10638](https://github.com/influxdata/telegraf/pull/10638) Update github.com/nats-io/nats-server/v2 from 2.6.5 to 2.7.2\n- [#10589](https://github.com/influxdata/telegraf/pull/10589) Update k8s.io/client-go from 0.22.2 to 0.23.3\n- [#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\n- [#10588](https://github.com/influxdata/telegraf/pull/10588) Update github.com/benbjohnson/clock from 1.1.0 to 1.3.0\n- [#10598](https://github.com/influxdata/telegraf/pull/10598) Update github.com/Azure/azure-kusto-go from 0.5.0 to 0.5.2\n- [#10571](https://github.com/influxdata/telegraf/pull/10571) Update github.com/vmware/govmomi from 0.27.2 to 0.27.3\n- [#10572](https://github.com/influxdata/telegraf/pull/10572) Update github.com/prometheus/client_golang from 1.11.0 to 1.12.1\n- [#10564](https://github.com/influxdata/telegraf/pull/10564) Update go.mongodb.org/mongo-driver from 1.7.3 to 1.8.3\n- [#10563](https://github.com/influxdata/telegraf/pull/10563) Update github.com/google/go-cmp from 0.5.6 to 0.5.7\n- [#10562](https://github.com/influxdata/telegraf/pull/10562) Update go.opentelemetry.io/collector/model from 0.39.0 to 0.43.2\n- [#10538](https://github.com/influxdata/telegraf/pull/10538) Update github.com/multiplay/go-ts3 from 1.0.0 to 1.0.1\n- [#10454](https://github.com/influxdata/telegraf/pull/10454) Update cloud.google.com/go/monitoring from 0.2.0 to 1.2.0\n- [#10536](https://github.com/influxdata/telegraf/pull/10536) Update github.com/vmware/govmomi from 0.26.0 to 0.27.2\n\n### New External Plugins\n\n- [apt](https://github.com/x70b1/telegraf-apt) - contributed by @x70b1\n- [knot](https://github.com/x70b1/telegraf-knot) - contributed by @x70b1\n\n## v1.21.3 [2022-01-27]\n\n### Bugfixes\n\n- [#10430](https://github.com/influxdata/telegraf/pull/10430) `inputs.snmp_trap` Fix translation of partially resolved OIDs\n- [#10529](https://github.com/influxdata/telegraf/pull/10529) Update deprecation notices\n- [#10525](https://github.com/influxdata/telegraf/pull/10525) Update grpc module to v1.44.0\n- [#10434](https://github.com/influxdata/telegraf/pull/10434) Update google.golang.org/api module from 0.54.0 to 0.65.0\n- [#10507](https://github.com/influxdata/telegraf/pull/10507) Update antchfx/xmlquery module from 1.3.6 to 1.3.9\n- [#10521](https://github.com/influxdata/telegraf/pull/10521) Update nsqio/go-nsq module from 1.0.8 to 1.1.0\n- [#10506](https://github.com/influxdata/telegraf/pull/10506) Update prometheus/common module from 0.31.1 to 0.32.1\n- [#10474](https://github.com/influxdata/telegraf/pull/10474) `inputs.ipset` Fix panic when command not found\n- [#10504](https://github.com/influxdata/telegraf/pull/10504) Update cloud.google.com/go/pubsub module from 1.17.0 to 1.17.1\n- [#10432](https://github.com/influxdata/telegraf/pull/10432) Update influxdata/influxdb-observability/influx2otel module from 0.2.8 to 0.2.10\n- [#10478](https://github.com/influxdata/telegraf/pull/10478) `inputs.opcua` Remove duplicate fields\n- [#10473](https://github.com/influxdata/telegraf/pull/10473) `parsers.nagios` Log correct errors when executing commands\n- [#10463](https://github.com/influxdata/telegraf/pull/10463) `inputs.execd` Add newline in execd for prometheus parsing\n- [#10451](https://github.com/influxdata/telegraf/pull/10451) Update shirou/gopsutil/v3 module from 3.21.10 to 3.21.12\n- [#10453](https://github.com/influxdata/telegraf/pull/10453) Update jackc/pgx/v4 module from 4.6.0 to 4.14.1\n- [#10449](https://github.com/influxdata/telegraf/pull/10449) Update Azure/azure-event-hubs-go/v3 module from 3.3.13 to 3.3.17\n- [#10450](https://github.com/influxdata/telegraf/pull/10450) Update gosnmp/gosnmp module from 1.33.0 to 1.34.0\n- [#10442](https://github.com/influxdata/telegraf/pull/10442) `parsers.wavefront` Add missing setting wavefront_disable_prefix_conversion\n- [#10435](https://github.com/influxdata/telegraf/pull/10435) Update hashicorp/consul/api module from 1.9.1 to 1.12.0\n- [#10436](https://github.com/influxdata/telegraf/pull/10436) Update antchfx/xpath module from 1.1.11 to 1.2.0\n- [#10433](https://github.com/influxdata/telegraf/pull/10433) Update antchfx/jsonquery module from 1.1.4 to 1.1.5\n- [#10414](https://github.com/influxdata/telegraf/pull/10414) Update prometheus/procfs module from 0.6.0 to 0.7.3\n- [#10354](https://github.com/influxdata/telegraf/pull/10354) `inputs.snmp` Fix panic when mibs folder doesn't exist (#10346)\n- [#10393](https://github.com/influxdata/telegraf/pull/10393) `outputs.syslog` Correctly set ASCII trailer for syslog output\n- [#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\n- [#10416](https://github.com/influxdata/telegraf/pull/10416) Update kardianos/service module from 1.0.0 to 1.2.1\n- [#10396](https://github.com/influxdata/telegraf/pull/10396) `inputs.http` Allow empty http body\n- [#10417](https://github.com/influxdata/telegraf/pull/10417) Update couchbase/go-couchbase module from 0.1.0 to 0.1.1\n- [#10413](https://github.com/influxdata/telegraf/pull/10413) `parsers.json_v2` Fix timestamp precision when using unix_ns format\n- [#10418](https://github.com/influxdata/telegraf/pull/10418) Update pion/dtls/v2 module from 2.0.9 to 2.0.13\n- [#10402](https://github.com/influxdata/telegraf/pull/10402) Update containerd/containerd module to 1.5.9\n- [#8947](https://github.com/influxdata/telegraf/pull/8947) `outputs.timestream` Fix batching logic with write records and introduce concurrent requests\n- [#10360](https://github.com/influxdata/telegraf/pull/10360) `outputs.amqp` Avoid connection leak when writing error\n- [#10097](https://github.com/influxdata/telegraf/pull/10097) `outputs.stackdriver` Send correct interval start times for counters\n\n## v1.21.2 [2022-01-05]\n\n### Release Notes\n\nHappy New Year!\n\n### Features\n\n- Added arm64 MacOS builds\n- Added riscv64 Linux builds\n- Numerous changes to CircleCI config to ensure more timely completion and more clear execution flow\n\n### Bugfixes\n\n- [#10318](https://github.com/influxdata/telegraf/pull/10318) `inputs.disk` Fix missing storage in containers\n- [#10324](https://github.com/influxdata/telegraf/pull/10324) `inputs.dpdk` Add note about dpdk and socket availability\n- [#10296](https://github.com/influxdata/telegraf/pull/10296) `inputs.logparser` Resolve panic in logparser due to missing Log\n- [#10322](https://github.com/influxdata/telegraf/pull/10322) `inputs.snmp` Ensure module load order to avoid snmp marshal error\n- [#10321](https://github.com/influxdata/telegraf/pull/10321) `inputs.snmp` Do not require networking during tests\n- [#10303](https://github.com/influxdata/telegraf/pull/10303) `inputs.snmp` Resolve SNMP panic due to no gosmi module\n- [#10295](https://github.com/influxdata/telegraf/pull/10295) `inputs.snmp` Grab MIB table columns more accurately\n- [#10299](https://github.com/influxdata/telegraf/pull/10299) `inputs.snmp` Check index before assignment when floating :: exists to avoid panic\n- [#10301](https://github.com/influxdata/telegraf/pull/10301) `inputs.snmp` Fix panic if no mibs folder is found\n- [#10373](https://github.com/influxdata/telegraf/pull/10373) `inputs.snmp_trap` Document deprecation of timeout parameter\n- [#10377](https://github.com/influxdata/telegraf/pull/10377) `parsers.csv` empty import tzdata for Windows binaries to correctly set timezone\n- [#10332](https://github.com/influxdata/telegraf/pull/10332) Update github.com/djherbis/times module from v1.2.0 to v1.5.0\n- [#10343](https://github.com/influxdata/telegraf/pull/10343) Update github.com/go-ldap/ldap/v3 module from v3.1.0 to v3.4.1\n- [#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\n\n## v1.21.1 [2021-12-16]\n\n### Bugfixes\n\n- [#10288](https://github.com/influxdata/telegraf/pull/10288) Fix panic in parsers due to missing Log for all plugins using SetParserFunc.\n- [#10288](https://github.com/influxdata/telegraf/pull/10288) Fix panic in parsers due to missing Log for all plugins using SetParserFunc\n- [#10247](https://github.com/influxdata/telegraf/pull/10247) Update go-sensu module to v2.12.0\n- [#10284](https://github.com/influxdata/telegraf/pull/10284) `inputs.openstack` Fix typo in openstack neutron input plugin (newtron)\n\n### Features\n\n- [#10239](https://github.com/influxdata/telegraf/pull/10239) Enable Darwin arm64 build\n- [#10150](https://github.com/influxdata/telegraf/pull/10150) `inputs.smart` Add SMART plugin concurrency configuration option, nvme-cli v1.14+ support and lint fixes.\n- [#10150](https://github.com/influxdata/telegraf/pull/10150) `inputs.smart` Add SMART plugin concurrency configuration option, nvme-cli v1.14+ support and lint fixes\n\n## v1.21.0 [2021-12-15]\n\n### Release Notes\n\nThe 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).\n\nThank you to @zak-pawel for lots of linter fixes!\n\n### Bugfixes\n\n- [#10268](https://github.com/influxdata/telegraf/pull/10268) `inputs.snmp` Update snmp plugin to respect number of retries configured\n- [#10225](https://github.com/influxdata/telegraf/pull/10225) `outputs.wavefront` Flush wavefront output sender on error to clean up broken connections\n- [#9970](https://github.com/influxdata/telegraf/pull/9970) Restart Telegraf service if it is already running and upgraded via RPM\n- [#10188](https://github.com/influxdata/telegraf/pull/10188) `parsers.xpath` Handle duplicate registration of protocol-buffer files gracefully\n- [#10132](https://github.com/influxdata/telegraf/pull/10132) `inputs.http_listener_v2` Fix panic on close to check that Telegraf is closing\n- [#10196](https://github.com/influxdata/telegraf/pull/10196) `outputs.elasticsearch` Implement NaN and inf handling for elasticsearch output\n- [#10205](https://github.com/influxdata/telegraf/pull/10205) Print loaded plugins and deprecations for once and test flags\n- [#10214](https://github.com/influxdata/telegraf/pull/10214) `processors.ifname` Eliminate MIB dependency for ifname processor\n- [#10206](https://github.com/influxdata/telegraf/pull/10206) `inputs.snmp` Optimize locking for SNMP MIBs loading\n- [#9975](https://github.com/influxdata/telegraf/pull/9975) `inputs.kube_inventory` Set TLS server name config properly\n- [#10230](https://github.com/influxdata/telegraf/pull/10230) Sudden close of Telegraf caused by OPC UA input plugin\n- [#9913](https://github.com/influxdata/telegraf/pull/9913) Update eclipse/paho.mqtt.golang module from 1.3.0 to 1.3.5\n- [#10221](https://github.com/influxdata/telegraf/pull/10221) `parsers.json_v2` Parser timestamp setting order\n- [#10209](https://github.com/influxdata/telegraf/pull/10209) `outputs.graylog` Ensure graylog spec fields not prefixed with _\n- [#10099](https://github.com/influxdata/telegraf/pull/10099) `inputs.zfs` Pool detection and metrics gathering for ZFS >= 2.1.x\n- [#10007](https://github.com/influxdata/telegraf/pull/10007) `processors.ifname` Parallelism fix for ifname processor\n- [#10208](https://github.com/influxdata/telegraf/pull/10208) `inputs.mqtt_consumer` Mqtt topic extracting no longer requires all three fields\n- [#9616](https://github.com/influxdata/telegraf/pull/9616) Windows Service - graceful shutdown of telegraf\n- [#10203](https://github.com/influxdata/telegraf/pull/10203) Revert unintended corruption of the Makefile\n- [#10112](https://github.com/influxdata/telegraf/pull/10112) `inputs.cloudwatch` Cloudwatch metrics collection\n- [#10178](https://github.com/influxdata/telegraf/pull/10178) `outputs.all` Register bigquery to output plugins\n- [#10165](https://github.com/influxdata/telegraf/pull/10165) `inputs.sysstat` Sysstat to use unique temp file vs hard-coded\n- [#10046](https://github.com/influxdata/telegraf/pull/10046) Update nats-sever to support openbsd\n- [#10091](https://github.com/influxdata/telegraf/pull/10091) `inputs.prometheus` Check error before defer in prometheus k8s\n- [#10101](https://github.com/influxdata/telegraf/pull/10101) `inputs.win_perf_counters` Add setting to win_perf_counters input to ignore localization\n- [#10136](https://github.com/influxdata/telegraf/pull/10136) `inputs.snmp_trap` Remove snmptranslate from readme and fix default path\n- [#10116](https://github.com/influxdata/telegraf/pull/10116) `inputs.statsd` Input plugin statsd parse error\n- [#10131](https://github.com/influxdata/telegraf/pull/10131) Skip knxlistener when writing the sample config\n- [#10119](https://github.com/influxdata/telegraf/pull/10119) `inputs.cpu` Update shirou/gopsutil from v2 to v3\n- [#10074](https://github.com/influxdata/telegraf/pull/10074) `outputs.graylog` Failing test due to port already in use\n- [#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\n- [#9862](https://github.com/influxdata/telegraf/pull/9862) `outputs.graylog` Graylog plugin TLS support and message format\n- [#9908](https://github.com/influxdata/telegraf/pull/9908) `parsers.json_v2` Remove dead code\n- [#9881](https://github.com/influxdata/telegraf/pull/9881) `outputs.graylog` Mute graylog UDP/TCP tests by marking them as integration\n- [#9751](https://github.com/influxdata/telegraf/pull/9751)  Update google.golang.org/grpc module from 1.39.1 to 1.40.0\n\n### Features\n\n- [#10200](https://github.com/influxdata/telegraf/pull/10200) `aggregators.deprecations.go` Implement deprecation infrastructure\n- [#9518](https://github.com/influxdata/telegraf/pull/9518) `inputs.snmp` Snmp to use gosmi\n- [#10130](https://github.com/influxdata/telegraf/pull/10130) `outputs.influxdb_v2` Add retry to 413 errors with InfluxDB output\n- [#10144](https://github.com/influxdata/telegraf/pull/10144) `inputs.win_services` Add exclude filter\n- [#9995](https://github.com/influxdata/telegraf/pull/9995) `inputs.mqtt_consumer` Enable extracting tag values from MQTT topics\n- [#9419](https://github.com/influxdata/telegraf/pull/9419) `aggregators.all` Add support of aggregator as Starlark script\n- [#9561](https://github.com/influxdata/telegraf/pull/9561) `processors.regex` Extend regexp processor do allow renaming of measurements, tags and fields\n- [#8184](https://github.com/influxdata/telegraf/pull/8184) `outputs.http` Add use_batch_format for HTTP output plugin\n- [#9988](https://github.com/influxdata/telegraf/pull/9988) `inputs.kafka_consumer` Add max_processing_time config to Kafka Consumer input\n- [#9841](https://github.com/influxdata/telegraf/pull/9841) `inputs.sqlserver` Add additional metrics to support elastic pool (sqlserver plugin)\n- [#9910](https://github.com/influxdata/telegraf/pull/9910) `common.tls` Filter client certificates by DNS names\n- [#9942](https://github.com/influxdata/telegraf/pull/9942) `outputs.azure_data_explorer` Add option to skip table creation in azure data explorer output\n- [#9984](https://github.com/influxdata/telegraf/pull/9984) `processors.ifname` Add more details to logmessages\n- [#9833](https://github.com/influxdata/telegraf/pull/9833) `common.kafka` Add metadata full to config\n- [#9876](https://github.com/influxdata/telegraf/pull/9876) Update etc/telegraf.conf and etc/telegraf_windows.conf\n- [#9256](https://github.com/influxdata/telegraf/pull/9256) `inputs.modbus` Modbus connection settings (serial)\n- [#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\n- [#9740](https://github.com/influxdata/telegraf/pull/9740) `inputs.prometheus` Add ignore_timestamp option\n- [#9513](https://github.com/influxdata/telegraf/pull/9513) `processors.starlark` Starlark processor example for processing sparkplug_b messages\n- [#9449](https://github.com/influxdata/telegraf/pull/9449) `parsers.json_v2` Support defining field/tag tables within an object table\n- [#9827](https://github.com/influxdata/telegraf/pull/9827) `inputs.elasticsearch_query` Add debug query output to elasticsearch_query\n- [#9241](https://github.com/influxdata/telegraf/pull/9241) `inputs.snmp` Telegraf to merge tables with different indexes\n- [#9013](https://github.com/influxdata/telegraf/pull/9013) `inputs.opcua` Allow user to select the source for the metric timestamp.\n- [#9706](https://github.com/influxdata/telegraf/pull/9706) `inputs.puppetagent` Add measurements from puppet 5\n- [#9644](https://github.com/influxdata/telegraf/pull/9644) `outputs.graylog` Add graylog plugin TCP support\n- [#8229](https://github.com/influxdata/telegraf/pull/8229) `outputs.azure_data_explorer` Add json_timestamp_layout option\n\n### New Input Plugins\n\n- [#9724](https://github.com/influxdata/telegraf/pull/9724) Add intel_pmu plugin\n- [#9771](https://github.com/influxdata/telegraf/pull/9771) Add Linux Volume Manager input plugin\n- [#9236](https://github.com/influxdata/telegraf/pull/9236) Openstack input plugin\n\n### New Output Plugins\n\n- [#9891](https://github.com/influxdata/telegraf/pull/9891)  Add new groundwork output plugin\n- [#9923](https://github.com/influxdata/telegraf/pull/9923)  Add mongodb output plugin\n- [#9346](https://github.com/influxdata/telegraf/pull/9346)  Azure Event Hubs output plugin\n\n## v1.20.4 [2021-11-17]\n\n### Release Notes\n\n- [#10073](https://github.com/influxdata/telegraf/pull/10073) Update go version from 1.17.2 to 1.17.3\n- [#10100](https://github.com/influxdata/telegraf/pull/10100) Update deprecated plugin READMEs to better indicate deprecation\n\nThank you to @zak-pawel for lots of linter fixes!\n\n- [#9986](https://github.com/influxdata/telegraf/pull/9986) Linter fixes for plugins/inputs/[h-j]*\n- [#9999](https://github.com/influxdata/telegraf/pull/9999) Linter fixes for plugins/inputs/[k-l]*\n- [#10006](https://github.com/influxdata/telegraf/pull/10006) Linter fixes for plugins/inputs/m*\n- [#10011](https://github.com/influxdata/telegraf/pull/10011) Linter fixes for plugins/inputs/[n-o]*\n\n### Bugfixes\n\n- [#10089](https://github.com/influxdata/telegraf/pull/10089) Update BurntSushi/toml from 0.3.1 to 0.4.1\n- [#10075](https://github.com/influxdata/telegraf/pull/10075) `inputs.mongodb` Update readme with correct connection URI\n- [#10076](https://github.com/influxdata/telegraf/pull/10076) Update gosnmp module from 1.32 to 1.33\n- [#9966](https://github.com/influxdata/telegraf/pull/9966) `inputs.mysql` Fix type conversion follow-up\n- [#10068](https://github.com/influxdata/telegraf/pull/10068) `inputs.proxmox` Changed VM ID from string to int\n- [#10047](https://github.com/influxdata/telegraf/pull/10047) `inputs.modbus` Do not build modbus on openbsd\n- [#10019](https://github.com/influxdata/telegraf/pull/10019) `inputs.cisco_telemetry_mdt` Move to new protobuf library\n- [#10001](https://github.com/influxdata/telegraf/pull/10001) `outputs.loki` Add metric name with label \"__name\"\n- [#9980](https://github.com/influxdata/telegraf/pull/9980) `inputs.nvidia_smi` Set the default path correctly\n- [#10010](https://github.com/influxdata/telegraf/pull/10010) Update go.opentelemetry.io/otel from v0.23.0 to v0.24.0\n- [#10044](https://github.com/influxdata/telegraf/pull/10044) `inputs.sqlserver` Add elastic pool in supported versions in sqlserver\n- [#10029](https://github.com/influxdata/telegraf/pull/10029) `inputs.influxdb` Update influxdb input schema docs\n- [#10026](https://github.com/influxdata/telegraf/pull/10026) `inputs.intel_rdt` Correct timezone handling\n\n## v1.20.3 [2021-10-27]\n\n### Release Notes\n\n- [#9873](https://github.com/influxdata/telegraf/pull/9873) Update go to 1.17.2\n\n### Bugfixes\n\n- [#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\n- [#9997](https://github.com/influxdata/telegraf/pull/9997) `inputs.ipmi_sensor` Redact IPMI password in logs\n- [#9978](https://github.com/influxdata/telegraf/pull/9978) `inputs.kube_inventory` Do not skip resources with zero s/ns timestamps\n- [#9998](https://github.com/influxdata/telegraf/pull/9998) Update gjson module to v1.10.2\n- [#9973](https://github.com/influxdata/telegraf/pull/9973) `inputs.procstat` Revert and fix tag creation\n- [#9943](https://github.com/influxdata/telegraf/pull/9943) `inputs.sqlserver` Add sqlserver plugin integration tests\n- [#9647](https://github.com/influxdata/telegraf/pull/9647) `inputs.cloudwatch` Use the AWS SDK v2 library\n- [#9954](https://github.com/influxdata/telegraf/pull/9954) `processors.starlark` Starlark pop operation for non-existing keys\n- [#9956](https://github.com/influxdata/telegraf/pull/9956) `inputs.zfs` Check return code of zfs command for FreeBSD\n- [#9585](https://github.com/influxdata/telegraf/pull/9585) `inputs.kube_inventory` Fix segfault in ingress, persistentvolumeclaim, statefulset in kube_inventory\n- [#9901](https://github.com/influxdata/telegraf/pull/9901) `inputs.ethtool` Add normalization of tags for ethtool input plugin\n- [#9957](https://github.com/influxdata/telegraf/pull/9957) `inputs.internet_speed` Resolve missing latency field\n- [#9662](https://github.com/influxdata/telegraf/pull/9662) `inputs.prometheus` Decode Prometheus scrape path from Kubernetes labels\n- [#9933](https://github.com/influxdata/telegraf/pull/9933) `inputs.procstat` Correct conversion of int with specific bit size\n- [#9940](https://github.com/influxdata/telegraf/pull/9940) `inputs.webhooks` Provide more fields for papertrail event webhook\n- [#9892](https://github.com/influxdata/telegraf/pull/9892) `inputs.mongodb` Solve compatibility issue for mongodb inputs when using 5.x relicaset\n- [#9768](https://github.com/influxdata/telegraf/pull/9768) Update github.com/Azure/azure-kusto-go module from 0.3.2 to 0.4.0\n- [#9904](https://github.com/influxdata/telegraf/pull/9904) Update github.com/golang-jwt/jwt/v4 module from 4.0.0 to 4.1.0\n- [#9921](https://github.com/influxdata/telegraf/pull/9921) Update github.com/apache/thrift module from 0.14.2 to 0.15.0\n- [#9403](https://github.com/influxdata/telegraf/pull/9403) `inputs.mysql`Fix inconsistent metric types in mysql\n- [#9905](https://github.com/influxdata/telegraf/pull/9905) Update github.com/docker/docker module from 20.10.7+incompatible to 20.10.9+incompatible\n- [#9920](https://github.com/influxdata/telegraf/pull/9920) `inputs.prometheus` Move err check to correct place\n- [#9869](https://github.com/influxdata/telegraf/pull/9869) Update github.com/prometheus/common module from 0.26.0 to 0.31.1\n- [#9866](https://github.com/influxdata/telegraf/pull/9866) Update snowflake database driver module to 1.6.2\n- [#9527](https://github.com/influxdata/telegraf/pull/9527) `inputs.intel_rdt` Allow sudo usage\n- [#9893](https://github.com/influxdata/telegraf/pull/9893) Update github.com/jaegertracing/jaeger module from 1.15.1 to 1.26.0\n\n### New External Plugins\n\n- [IBM DB2](https://github.com/bonitoo-io/telegraf-input-db2) - contributed by @sranka\n- [Oracle Database](https://github.com/bonitoo-io/telegraf-input-oracle) - contributed by @sranka\n\n## v1.20.2 [2021-10-07]\n\n### Bugfixes\n\n- [#9878](https://github.com/influxdata/telegraf/pull/9878) `inputs.cloudwatch` Use new session API\n- [#9872](https://github.com/influxdata/telegraf/pull/9872) `parsers.json_v2` Duplicate line_protocol when using object and fields\n- [#9787](https://github.com/influxdata/telegraf/pull/9787) `parsers.influx` Fix memory leak in influx parser\n- [#9880](https://github.com/influxdata/telegraf/pull/9880) `inputs.stackdriver` Migrate to cloud.google.com/go/monitoring/apiv3/v2\n- [#9887](https://github.com/influxdata/telegraf/pull/9887) Fix makefile typo that prevented i386 tar and rpm packages from being built\n\n## v1.20.1 [2021-10-06]\n\n### Bugfixes\n\n- [#9776](https://github.com/influxdata/telegraf/pull/9776) Update k8s.io/apimachinery module from 0.21.1 to 0.22.2\n- [#9864](https://github.com/influxdata/telegraf/pull/9864) Update containerd module to v1.5.7\n- [#9863](https://github.com/influxdata/telegraf/pull/9863) Update consul module to v1.11.0\n- [#9846](https://github.com/influxdata/telegraf/pull/9846) `inputs.mongodb` Fix panic due to nil dereference\n- [#9850](https://github.com/influxdata/telegraf/pull/9850) `inputs.intel_rdt` Prevent timeout when logging\n- [#9848](https://github.com/influxdata/telegraf/pull/9848) `outputs.loki` Update http_headers setting to match sample config\n- [#9808](https://github.com/influxdata/telegraf/pull/9808) `inputs.procstat` Add missing tags\n- [#9803](https://github.com/influxdata/telegraf/pull/9803) `outputs.mqtt` Add keep alive config option and documentation around issue with eclipse/mosquitto version\n- [#9800](https://github.com/influxdata/telegraf/pull/9800) Fix output buffer never completely flushing\n- [#9458](https://github.com/influxdata/telegraf/pull/9458) `inputs.couchbase` Fix insecure certificate validation\n- [#9797](https://github.com/influxdata/telegraf/pull/9797) `inputs.opentelemetry` Fix error returned to OpenTelemetry client\n- [#9789](https://github.com/influxdata/telegraf/pull/9789) Update github.com/testcontainers/testcontainers-go module from 0.11.0 to 0.11.1\n- [#9791](https://github.com/influxdata/telegraf/pull/9791) Update github.com/Azure/go-autorest/autorest/adal module\n- [#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\n- [#9769](https://github.com/influxdata/telegraf/pull/9769) Update cloud.google.com/go/pubsub module from 1.15.0 to 1.17.0\n- [#9770](https://github.com/influxdata/telegraf/pull/9770) Update github.com/aws/smithy-go module from 1.3.1 to 1.8.0\n\n### Features\n\n- [#9838](https://github.com/influxdata/telegraf/pull/9838) `inputs.elasticsearch_query` Add custom time/date format field\n\n## v1.20.0 [2021-09-17]\n\n### Release Notes\n\n- [#9642](https://github.com/influxdata/telegraf/pull/9642) Build with Golang 1.17\n\n### Bugfixes\n\n- [#9700](https://github.com/influxdata/telegraf/pull/9700) Update thrift module to 0.14.2 and zipkin-go-opentracing to 0.4.5\n- [#9587](https://github.com/influxdata/telegraf/pull/9587) `outputs.opentelemetry` Use headers config in grpc requests\n- [#9713](https://github.com/influxdata/telegraf/pull/9713) Update runc module to v1.0.0-rc95 to address CVE-2021-30465\n- [#9699](https://github.com/influxdata/telegraf/pull/9699) Migrate dgrijalva/jwt-go to golang-jwt/jwt/v4\n- [#9139](https://github.com/influxdata/telegraf/pull/9139) `serializers.prometheus` Update timestamps and expiration time as new data arrives\n- [#9625](https://github.com/influxdata/telegraf/pull/9625) `outputs.graylog` Output timestamp with fractional seconds\n- [#9655](https://github.com/influxdata/telegraf/pull/9655) Update cloud.google.com/go/pubsub module from 1.2.0 to 1.15.0\n- [#9674](https://github.com/influxdata/telegraf/pull/9674) `inputs.mongodb` Change command based on server version\n- [#9676](https://github.com/influxdata/telegraf/pull/9676) `outputs.dynatrace` Remove hardcoded int value\n- [#9619](https://github.com/influxdata/telegraf/pull/9619) `outputs.influxdb_v2` Increase accepted retry-after header values.\n- [#9652](https://github.com/influxdata/telegraf/pull/9652) Update tinylib/msgp module from 1.1.5 to 1.1.6\n- [#9471](https://github.com/influxdata/telegraf/pull/9471) `inputs.sql` Make timeout apply to single query\n- [#9760](https://github.com/influxdata/telegraf/pull/9760) Update shirou/gopsutil module to 3.21.8\n- [#9707](https://github.com/influxdata/telegraf/pull/9707) `inputs.logstash` Add additional logstash output plugin stats\n- [#9656](https://github.com/influxdata/telegraf/pull/9656) Update miekg/dns module from 1.1.31 to 1.1.43\n- [#9750](https://github.com/influxdata/telegraf/pull/9750) Update antchfx/xmlquery module from 1.3.5 to 1.3.6\n- [#9757](https://github.com/influxdata/telegraf/pull/9757) `parsers.registry.go` Fix panic for non-existing metric names\n- [#9677](https://github.com/influxdata/telegraf/pull/9677) Update Azure/azure-event-hubs-go/v3 module from 3.2.0 to 3.3.13\n- [#9653](https://github.com/influxdata/telegraf/pull/9653) Update prometheus/client_golang module from 1.7.1 to 1.11.0\n- [#9693](https://github.com/influxdata/telegraf/pull/9693) `inputs.cloudwatch` Fix pagination error\n- [#9727](https://github.com/influxdata/telegraf/pull/9727) `outputs.http` Add error message logging\n- [#9718](https://github.com/influxdata/telegraf/pull/9718) Update influxdata/influxdb-observability module from 0.2.4 to 0.2.7\n- [#9560](https://github.com/influxdata/telegraf/pull/9560) Update gopcua/opcua module\n- [#9544](https://github.com/influxdata/telegraf/pull/9544) `inputs.couchbase` Fix memory leak\n- [#9588](https://github.com/influxdata/telegraf/pull/9588) `outputs.opentelemetry` Use attributes setting\n\n### Features\n\n- [#9665](https://github.com/influxdata/telegraf/pull/9665) `inputs.systemd_units` feat(plugins/inputs/systemd_units): add pattern support\n- [#9598](https://github.com/influxdata/telegraf/pull/9598) `outputs.sql` Add bool datatype\n- [#9386](https://github.com/influxdata/telegraf/pull/9386) `inputs.cloudwatch` Pull metrics from multiple AWS CloudWatch namespaces\n- [#9411](https://github.com/influxdata/telegraf/pull/9411) `inputs.cloudwatch` Support AWS Web Identity Provider\n- [#9570](https://github.com/influxdata/telegraf/pull/9570) `inputs.modbus` Add support for RTU over TCP\n- [#9488](https://github.com/influxdata/telegraf/pull/9488) `inputs.procstat` Support cgroup globs and include systemd unit children\n- [#9322](https://github.com/influxdata/telegraf/pull/9322) `inputs.suricata` Support alert event type\n- [#5464](https://github.com/influxdata/telegraf/pull/5464) `inputs.prometheus` Add ability to query Consul Service catalog\n- [#8641](https://github.com/influxdata/telegraf/pull/8641) `outputs.prometheus_client` Add Landing page\n- [#9529](https://github.com/influxdata/telegraf/pull/9529) `inputs.http_listener_v2` Allows multiple paths and add path_tag\n- [#9395](https://github.com/influxdata/telegraf/pull/9395) Add cookie authentication to HTTP input and output plugins\n- [#8454](https://github.com/influxdata/telegraf/pull/8454) `inputs.syslog` Add RFC3164 support\n- [#9351](https://github.com/influxdata/telegraf/pull/9351) `inputs.jenkins` Add option to include nodes by name\n- [#9277](https://github.com/influxdata/telegraf/pull/9277) Add JSON, MessagePack, and Protocol-buffers format support to the XPath parser\n- [#9343](https://github.com/influxdata/telegraf/pull/9343) `inputs.snmp_trap` Improve MIB lookup performance\n- [#9342](https://github.com/influxdata/telegraf/pull/9342) `outputs.newrelic` Add option to override metric_url\n- [#9306](https://github.com/influxdata/telegraf/pull/9306) `inputs.smart` Add power mode status\n- [#9762](https://github.com/influxdata/telegraf/pull/9762) `inputs.bond` Add count of bonded slaves (for easier alerting)\n- [#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\n\n### New Input Plugins\n\n- [#9602](https://github.com/influxdata/telegraf/pull/9602) Add rocm_smi input to monitor AMD GPUs\n- [#9101](https://github.com/influxdata/telegraf/pull/9101) Add mdstat input to gather from /proc/mdstat collection\n- [#3536](https://github.com/influxdata/telegraf/pull/3536) Add Elasticsearch query input\n- [#9623](https://github.com/influxdata/telegraf/pull/9623) Add internet Speed Monitor Input Plugin\n\n### New Output Plugins\n\n- [#9228](https://github.com/influxdata/telegraf/pull/9228) Add OpenTelemetry output\n- [#9426](https://github.com/influxdata/telegraf/pull/9426) Add Azure Data Explorer(ADX) output\n\n## v1.19.3 [2021-08-18]\n\n### Bugfixes\n\n- [#9639](https://github.com/influxdata/telegraf/pull/9639) Update sirupsen/logrus module from 1.7.0 to 1.8.1\n- [#9638](https://github.com/influxdata/telegraf/pull/9638) Update testcontainers/testcontainers-go module from 0.11.0 to 0.11.1\n- [#9637](https://github.com/influxdata/telegraf/pull/9637) Update golang/snappy module from 0.0.3 to 0.0.4\n- [#9636](https://github.com/influxdata/telegraf/pull/9636) Update aws/aws-sdk-go-v2 module from 1.3.2 to 1.8.0\n- [#9605](https://github.com/influxdata/telegraf/pull/9605) `inputs.prometheus` Fix prometheus kubernetes pod discovery\n- [#9606](https://github.com/influxdata/telegraf/pull/9606) `inputs.redis` Improve redis commands documentation\n- [#9566](https://github.com/influxdata/telegraf/pull/9566) `outputs.cratedb` Replace dots in tag keys with underscores\n- [#9401](https://github.com/influxdata/telegraf/pull/9401) `inputs.clickhouse` Fix panic, improve handling empty result set\n- [#9583](https://github.com/influxdata/telegraf/pull/9583) `inputs.opcua` Avoid closing session on a closed connection\n- [#9576](https://github.com/influxdata/telegraf/pull/9576) `processors.aws` Refactor ec2 init for config-api\n- [#9571](https://github.com/influxdata/telegraf/pull/9571) `outputs.loki` Sort logs by timestamp before writing to Loki\n- [#9524](https://github.com/influxdata/telegraf/pull/9524) `inputs.opcua` Fix reconnection regression introduced in 1.19.1\n- [#9581](https://github.com/influxdata/telegraf/pull/9581) `inputs.kube_inventory` Fix k8s nodes and pods parsing error\n- [#9577](https://github.com/influxdata/telegraf/pull/9577) Update sensu/go module to v2.9.0\n- [#9554](https://github.com/influxdata/telegraf/pull/9554) `inputs.postgresql` Normalize unix socket path\n- [#9565](https://github.com/influxdata/telegraf/pull/9565) Update hashicorp/consul/api module to 1.9.1\n- [#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\n- [#9550](https://github.com/influxdata/telegraf/pull/9550) `inputs.opcua` Do not skip good quality nodes after a bad quality node is encountered\n\n## v1.19.2 [2021-07-28]\n\n### Release Notes\n\n- [#9542](https://github.com/influxdata/telegraf/pull/9542) Update Go to v1.16.6\n\n### Bugfixes\n\n- [#9363](https://github.com/influxdata/telegraf/pull/9363) `outputs.dynatrace` Update dynatrace output to allow optional default dimensions\n- [#9526](https://github.com/influxdata/telegraf/pull/9526) `outputs.influxdb` Fix metrics reported as written but not actually written\n- [#9549](https://github.com/influxdata/telegraf/pull/9549) `inputs.kube_inventory` Prevent segfault in persistent volume claims\n- [#9503](https://github.com/influxdata/telegraf/pull/9503) `inputs.nsq_consumer` Fix connection error when not using server setting\n- [#9540](https://github.com/influxdata/telegraf/pull/9540) `inputs.sql` Fix handling bool column\n- [#9387](https://github.com/influxdata/telegraf/pull/9387) Linter fixes for plugins/inputs/[fg]*\n- [#9438](https://github.com/influxdata/telegraf/pull/9438) `inputs.kubernetes` Attach the pod labels to kubernetes_pod_volume and kubernetes_pod_network metrics\n- [#9519](https://github.com/influxdata/telegraf/pull/9519) `processors.ifname` Fix SNMP empty metric name\n- [#8587](https://github.com/influxdata/telegraf/pull/8587) `inputs.sqlserver` Add tempdb troubleshooting stats and missing V2 query metrics\n- [#9323](https://github.com/influxdata/telegraf/pull/9323) `inputs.x509_cert` Prevent x509_cert from hanging on UDP connection\n- [#9504](https://github.com/influxdata/telegraf/pull/9504) `parsers.json_v2` Simplify how nesting is handled\n- [#9493](https://github.com/influxdata/telegraf/pull/9493) `inputs.mongodb` Switch to official mongo-go-driver module to fix SSL auth failure\n- [#9491](https://github.com/influxdata/telegraf/pull/9491) `outputs.dynatrace` Fix panic caused by uninitialized loggedMetrics map\n- [#9497](https://github.com/influxdata/telegraf/pull/9497) `inputs.prometheus` Fix prometheus cadvisor authentication\n- [#9520](https://github.com/influxdata/telegraf/pull/9520) `parsers.json_v2` Add support for large uint64 and int64 numbers\n- [#9447](https://github.com/influxdata/telegraf/pull/9447) `inputs.statsd` Fix regression that didn't allow integer percentiles\n- [#9466](https://github.com/influxdata/telegraf/pull/9466) `inputs.sqlserver` Provide detailed error message in telegraf log\n- [#9399](https://github.com/influxdata/telegraf/pull/9399) Update dynatrace-metric-utils-go module to v0.2.0\n- [#8108](https://github.com/influxdata/telegraf/pull/8108) `inputs.cgroup` Allow multiple keys when parsing cgroups\n- [#9479](https://github.com/influxdata/telegraf/pull/9479) `parsers.json_v2` Fix json_v2 parser to handle nested objects in arrays properly\n\n### Features\n\n- [#9485](https://github.com/influxdata/telegraf/pull/9485) Add option to automatically reload settings when config file is modified\n\n## v1.19.1 [2021-07-07]\n\n### Bugfixes\n\n- [#9388](https://github.com/influxdata/telegraf/pull/9388) `inputs.sqlserver` Require authentication method to be specified\n- [#9456](https://github.com/influxdata/telegraf/pull/9456) `inputs.kube_inventory` Fix segfault in kube_inventory\n- [#9448](https://github.com/influxdata/telegraf/pull/9448) `inputs.couchbase` Fix panic\n- [#9444](https://github.com/influxdata/telegraf/pull/9444) `inputs.knx_listener` Fix nil pointer panic\n- [#9446](https://github.com/influxdata/telegraf/pull/9446) `inputs.procstat` Update gopsutil module to fix panic\n- [#9443](https://github.com/influxdata/telegraf/pull/9443) `inputs.rabbitmq` Fix JSON unmarshall regression\n- [#9369](https://github.com/influxdata/telegraf/pull/9369) Update nat-server module to v2.2.6\n- [#9429](https://github.com/influxdata/telegraf/pull/9429) `inputs.dovecot` Exclude read-timeout from being an error\n- [#9423](https://github.com/influxdata/telegraf/pull/9423) `inputs.statsd` Don't stop parsing after parsing error\n- [#9370](https://github.com/influxdata/telegraf/pull/9370) Update apimachinary module to v0.21.1\n- [#9373](https://github.com/influxdata/telegraf/pull/9373) Update jwt module to v1.2.2 and jwt-go module to v3.2.3\n- [#9412](https://github.com/influxdata/telegraf/pull/9412) Update couchbase Module to v0.1.0\n- [#9366](https://github.com/influxdata/telegraf/pull/9366) `inputs.snmp` Add a check for oid and name to prevent empty metrics\n- [#9413](https://github.com/influxdata/telegraf/pull/9413) `outputs.http` Fix toml error when parsing insecure_skip_verify\n- [#9400](https://github.com/influxdata/telegraf/pull/9400) `inputs.x509_cert` Fix 'source' tag for https\n- [#9375](https://github.com/influxdata/telegraf/pull/9375) Update signalfx module to v3.3.34\n- [#9406](https://github.com/influxdata/telegraf/pull/9406) `parsers.json_v2` Don't require tags to be added to included_keys\n- [#9289](https://github.com/influxdata/telegraf/pull/9289) `inputs.x509_cert` Fix SNI support\n- [#9372](https://github.com/influxdata/telegraf/pull/9372) Update gjson module to v1.8.0\n- [#9379](https://github.com/influxdata/telegraf/pull/9379) Linter fixes for plugins/inputs/[de]*\n\n## v1.19.0 [2021-06-17]\n\n### Release Notes\n\n- Many linter fixes - thanks @zak-pawel and all!\n- [#9331](https://github.com/influxdata/telegraf/pull/9331) Update Go to 1.16.5\n\n### Bugfixes\n\n- [#9182](https://github.com/influxdata/telegraf/pull/9182) Update pgx to v4\n- [#9275](https://github.com/influxdata/telegraf/pull/9275) Fix reading config files starting with http:\n- [#9196](https://github.com/influxdata/telegraf/pull/9196) `serializers.prometheusremotewrite` Update dependency and remove tags with empty values\n- [#9051](https://github.com/influxdata/telegraf/pull/9051) `outputs.kafka` Don't prevent telegraf from starting when there's a connection error\n- [#8795](https://github.com/influxdata/telegraf/pull/8795) `parsers.prometheusremotewrite` Update prometheus dependency to v2.21.0\n- [#9295](https://github.com/influxdata/telegraf/pull/9295) `outputs.dynatrace` Use dynatrace-metric-utils\n- [#9368](https://github.com/influxdata/telegraf/pull/9368) `parsers.json_v2` Update json_v2 parser to handle null types\n- [#9359](https://github.com/influxdata/telegraf/pull/9359) `inputs.sql` Fix import of sqlite and ignore it on all platforms that require CGO.\n- [#9329](https://github.com/influxdata/telegraf/pull/9329) `inputs.kube_inventory` Fix connecting to the wrong url\n- [#9358](https://github.com/influxdata/telegraf/pull/9358) upgrade denisenkom go-mssql to v0.10.0\n- [#9283](https://github.com/influxdata/telegraf/pull/9283) `processors.parser` Fix segfault\n- [#9243](https://github.com/influxdata/telegraf/pull/9243) `inputs.docker` Close all idle connections\n- [#9338](https://github.com/influxdata/telegraf/pull/9338) `inputs.suricata` Support new JSON format\n- [#9296](https://github.com/influxdata/telegraf/pull/9296) `outputs.influxdb` Fix endless retries\n\n### Features\n\n- [#8987](https://github.com/influxdata/telegraf/pull/8987) Config file environment variable can be a URL\n- [#9297](https://github.com/influxdata/telegraf/pull/9297) `outputs.datadog` Add HTTP proxy to datadog output\n- [#9087](https://github.com/influxdata/telegraf/pull/9087) Add named timestamp formats\n- [#9276](https://github.com/influxdata/telegraf/pull/9276) `inputs.vsphere` Add config option for the historical interval duration\n- [#9274](https://github.com/influxdata/telegraf/pull/9274) `inputs.ping` Add an option to specify packet size\n- [#9007](https://github.com/influxdata/telegraf/pull/9007) Allow multiple \"--config\" and \"--config-directory\" flags\n- [#9249](https://github.com/influxdata/telegraf/pull/9249) `outputs.graphite` Allow more characters in graphite tags\n- [#8351](https://github.com/influxdata/telegraf/pull/8351) `inputs.sqlserver` Added login_name\n- [#9223](https://github.com/influxdata/telegraf/pull/9223) `inputs.dovecot` Add support for unix domain sockets\n- [#9118](https://github.com/influxdata/telegraf/pull/9118) `processors.strings` Add UTF-8 sanitizer\n- [#9156](https://github.com/influxdata/telegraf/pull/9156) `inputs.aliyuncms` Add config option list of regions to query\n- [#9138](https://github.com/influxdata/telegraf/pull/9138) `common.http` Add OAuth2 to HTTP input\n- [#8822](https://github.com/influxdata/telegraf/pull/8822) `inputs.sqlserver` Enable Azure Active Directory (AAD) authentication support\n- [#9136](https://github.com/influxdata/telegraf/pull/9136) `inputs.cloudwatch` Add wildcard support in dimensions configuration\n- [#5517](https://github.com/influxdata/telegraf/pull/5517) `inputs.mysql` Gather all mysql channels\n- [#8911](https://github.com/influxdata/telegraf/pull/8911) `processors.enum` Support float64\n- [#9105](https://github.com/influxdata/telegraf/pull/9105) `processors.starlark` Support nanosecond resolution timestamp\n- [#9080](https://github.com/influxdata/telegraf/pull/9080) `inputs.logstash` Add support for version 7 queue stats\n- [#9074](https://github.com/influxdata/telegraf/pull/9074) `parsers.prometheusremotewrite` Add starlark script for renaming metrics\n- [#9032](https://github.com/influxdata/telegraf/pull/9032) `inputs.couchbase` Add ~200 more Couchbase metrics via Buckets endpoint\n- [#8596](https://github.com/influxdata/telegraf/pull/8596) `inputs.sqlserver` input/sqlserver: Add service and save connection pools\n- [#9042](https://github.com/influxdata/telegraf/pull/9042) `processors.starlark` Add math module\n- [#6952](https://github.com/influxdata/telegraf/pull/6952) `inputs.x509_cert` Wildcard support for cert filenames\n- [#9004](https://github.com/influxdata/telegraf/pull/9004) `processors.starlark` Add time module\n- [#8891](https://github.com/influxdata/telegraf/pull/8891) `inputs.kinesis_consumer` Add content_encoding option with gzip and zlib support\n- [#8996](https://github.com/influxdata/telegraf/pull/8996) `processors.starlark` Add an example showing how to obtain IOPS from diskio input\n- [#8966](https://github.com/influxdata/telegraf/pull/8966) `inputs.http_listener_v2` Add support for snappy compression\n- [#8661](https://github.com/influxdata/telegraf/pull/8661) `inputs.cisco_telemetry_mdt` Add support for events and class based query\n- [#8861](https://github.com/influxdata/telegraf/pull/8861) `inputs.mongodb` Optionally collect top stats\n- [#8979](https://github.com/influxdata/telegraf/pull/8979) `parsers.value` Add custom field name config option\n- [#8544](https://github.com/influxdata/telegraf/pull/8544) `inputs.sqlserver` Add an optional health metric\n\n### New Input Plugins\n\n- [Alibaba CloudMonitor Service (Aliyun)](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/aliyuncms) - contributed by @i-prudnikov\n- [OpenTelemetry](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opentelemetry) - contributed by @jacobmarble\n- [Intel Data Plane Development Kit (DPDK)](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/dpdk) - contributed by @p-zak\n- [KNX](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/knx_listener) - contributed by @DocLambda\n- [SQL](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/sql) - contributed by @srebhan\n\n### New Output Plugins\n\n- [Websocket](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/websocket) - contributed by @FZambia\n- [SQL](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/sql) - contributed by @illuusio\n- [AWS Cloudwatch logs](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/cloudwatch_logs) - contributed by @i-prudnikov\n\n### New Parser Plugins\n\n- [Prometheus Remote Write](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/prometheusremotewrite) - contributed by @helenosheaa\n- [JSON V2](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/json_v2) - contributed by @sspaink\n\n### New External Plugins\n\n- [ldap_org and ds389](https://github.com/falon/CSI-telegraf-plugins) - contributed by @falon\n- [x509_crl](https://github.com/jcgonnard/telegraf-input-x590crl) - contributed by @jcgonnard\n- [dnsmasq](https://github.com/machinly/dnsmasq-telegraf-plugin) - contributed by @machinly\n- [Big Blue Button](https://github.com/bigblueswarm/bigbluebutton-telegraf-plugin) - contributed by @SLedunois\n\n## v1.18.3 [2021-05-20]\n\n### Release Notes\n\n- Added FreeBSD armv7 build\n\n### Bugfixes\n\n- [#9271](https://github.com/influxdata/telegraf/pull/9271) `inputs.prometheus` Set user agent when scraping prom metrics\n- [#9203](https://github.com/influxdata/telegraf/pull/9203) Migrate from soniah/gosnmp to gosnmp/gosnmp and update to 1.32.0\n- [#9169](https://github.com/influxdata/telegraf/pull/9169) `inputs.kinesis_consumer` Fix repeating parser error\n- [#9130](https://github.com/influxdata/telegraf/pull/9130) `inputs.sqlserver` Remove disallowed whitespace from sqlServerRingBufferCPU query\n- [#9238](https://github.com/influxdata/telegraf/pull/9238) Update hashicorp/consul/api module to v1.8.1\n- [#9235](https://github.com/influxdata/telegraf/pull/9235) Migrate from docker/libnetwork/ipvs to moby/ipvs\n- [#9224](https://github.com/influxdata/telegraf/pull/9224) Update shirou/gopsutil to 3.21.3\n- [#9209](https://github.com/influxdata/telegraf/pull/9209) Update microsoft/ApplicationInsights-Go to 0.4.4\n- [#9190](https://github.com/influxdata/telegraf/pull/9190) Update gogo/protobuf to 1.3.2\n- [#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\n- [#8745](https://github.com/influxdata/telegraf/pull/8745) Update collectd.org to 0.5.0\n- [#8716](https://github.com/influxdata/telegraf/pull/8716) Update nats-io/nats.go 1.10.0\n- [#9039](https://github.com/influxdata/telegraf/pull/9039) Update golang/protobuf to v1.5.1\n- [#8937](https://github.com/influxdata/telegraf/pull/8937) Migrate from ericchiang/k8s to kubernetes/client-go\n\n### Features\n\n- [#8913](https://github.com/influxdata/telegraf/pull/8913) `outputs.elasticsearch` Add ability to enable gzip compression\n\n## v1.18.2 [2021-04-28]\n\n### Bugfixes\n\n- [#9160](https://github.com/influxdata/telegraf/pull/9160) `processors.converter` Add support for large hexadecimal strings\n- [#9195](https://github.com/influxdata/telegraf/pull/9195) `inputs.apcupsd` Fix apcupsd 'ALARMDEL' bug via forked repo\n- [#9110](https://github.com/influxdata/telegraf/pull/9110) `parsers.json` Make JSON format compatible with nulls\n- [#9128](https://github.com/influxdata/telegraf/pull/9128) `inputs.nfsclient` Fix nfsclient ops map to allow collection of metrics other than read and write\n- [#8917](https://github.com/influxdata/telegraf/pull/8917) `inputs.snmp` Log snmpv3 auth failures\n- [#8892](https://github.com/influxdata/telegraf/pull/8892) `common.shim` Accept larger inputs from scanner\n- [#9045](https://github.com/influxdata/telegraf/pull/9045) `inputs.vsphere` Add MetricLookback setting to handle reporting delays in vCenter 6.7 and later\n- [#9026](https://github.com/influxdata/telegraf/pull/9026) `outputs.sumologic` Carbon2 serializer: sanitize metric name\n- [#9086](https://github.com/influxdata/telegraf/pull/9086) `inputs.opcua` Fix error handling\n\n## v1.18.1 [2021-04-07]\n\n### Bugfixes\n\n- [#9082](https://github.com/influxdata/telegraf/pull/9082) `inputs.mysql` Fix 'binary logs' query for MySQL 8\n- [#9069](https://github.com/influxdata/telegraf/pull/9069) `inputs.tail` Add configurable option for the 'path' tag override\n- [#9067](https://github.com/influxdata/telegraf/pull/9067) `inputs.nfsclient` Fix integer overflow in fields from mountstat\n- [#9050](https://github.com/influxdata/telegraf/pull/9050) `inputs.snmp` Fix init when no mibs are installed\n- [#9072](https://github.com/influxdata/telegraf/pull/9072) `inputs.ping` Always call SetPrivileged(true) in native mode\n- [#9043](https://github.com/influxdata/telegraf/pull/9043) `processors.ifname` Get interface name more efficiently\n- [#9056](https://github.com/influxdata/telegraf/pull/9056) `outputs.yandex_cloud_monitoring` Use correct compute metadata URL to get folder-id\n- [#9048](https://github.com/influxdata/telegraf/pull/9048) `outputs.azure_monitor` Handle error when initializing the auth object\n- [#8549](https://github.com/influxdata/telegraf/pull/8549) `inputs.sqlserver` Fix sqlserver_process_cpu calculation\n- [#9035](https://github.com/influxdata/telegraf/pull/9035) `inputs.ipmi_sensor` Fix panic\n- [#9009](https://github.com/influxdata/telegraf/pull/9009) `inputs.docker` Fix panic when parsing container stats\n- [#8333](https://github.com/influxdata/telegraf/pull/8333) `inputs.exec` Don't truncate messages in debug mode\n- [#8769](https://github.com/influxdata/telegraf/pull/8769) `agent` Close running outputs when reloadinlg\n\n## v1.18.0 [2021-03-17]\n\n### Release Notes\n\n- Support Go version 1.16.2\n- Added support for code signing in Windows\n\n### Bugfixes\n\n- [#7312](https://github.com/influxdata/telegraf/pull/7312) `inputs.docker` CPU stats respect perdevice\n- [#8397](https://github.com/influxdata/telegraf/pull/8397) `outputs.dynatrace` Dynatrace Plugin: Make conversion to counters possible / Changed large bulk handling\n- [#8655](https://github.com/influxdata/telegraf/pull/8655) `inputs.sqlserver` SqlServer - fix for default server list\n- [#8703](https://github.com/influxdata/telegraf/pull/8703) `inputs.docker` Use consistent container name in docker input plugin\n- [#8902](https://github.com/influxdata/telegraf/pull/8902) `inputs.snmp` Fix max_repetitions signedness issues\n- [#8817](https://github.com/influxdata/telegraf/pull/8817) `outputs.kinesis` outputs.kinesis - log record error count\n- [#8833](https://github.com/influxdata/telegraf/pull/8833) `inputs.sqlserver` Bug Fix - SQL Server HADR queries for SQL Versions\n- [#8628](https://github.com/influxdata/telegraf/pull/8628) `inputs.modbus` fix: reading multiple holding registers in modbus input plugin\n- [#8885](https://github.com/influxdata/telegraf/pull/8885) `inputs.statsd` Fix statsd concurrency bug\n- [#8393](https://github.com/influxdata/telegraf/pull/8393) `inputs.sqlserver` SQL Perfmon counters - synced queries from v2 to all db types\n- [#8873](https://github.com/influxdata/telegraf/pull/8873) `processors.ifname` Fix mutex locking around ifname cache\n- [#8720](https://github.com/influxdata/telegraf/pull/8720) `parsers.influx` fix: remove ambiguity on '\\v' from line-protocol parser\n- [#8678](https://github.com/influxdata/telegraf/pull/8678) `inputs.redis` Fix Redis output field type inconsistencies\n- [#8953](https://github.com/influxdata/telegraf/pull/8953) `agent` Reset the flush interval timer when flush is requested or batch is ready.\n- [#8954](https://github.com/influxdata/telegraf/pull/8954) `common.kafka` Fix max open requests to one if idempotent writes is set to true\n- [#8721](https://github.com/influxdata/telegraf/pull/8721) `inputs.kube_inventory` Set $HOSTIP in default URL\n- [#8995](https://github.com/influxdata/telegraf/pull/8995) `inputs.sflow` fix segfaults in sflow plugin by checking if protocol headers are set\n- [#8986](https://github.com/influxdata/telegraf/pull/8986) `outputs.nats` nats_output: use the configured credentials file\n\n### Features\n\n- [#8887](https://github.com/influxdata/telegraf/pull/8887) `inputs.procstat` Add PPID field to procstat input plugin\n- [#8852](https://github.com/influxdata/telegraf/pull/8852) `processors.starlark` Add Starlark script for estimating Line Protocol cardinality\n- [#8915](https://github.com/influxdata/telegraf/pull/8915) `inputs.cloudwatch` add proxy\n- [#8910](https://github.com/influxdata/telegraf/pull/8910) `agent` Display error message on badly formatted config string array (eg. namepass)\n- [#8785](https://github.com/influxdata/telegraf/pull/8785) `inputs.diskio` Non systemd support with unittest\n- [#8850](https://github.com/influxdata/telegraf/pull/8850) `inputs.snmp` Support more snmpv3 authentication protocols\n- [#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\n- [#8613](https://github.com/influxdata/telegraf/pull/8613) `inputs.phpfpm` Support exclamation mark to create non-matching list in tail plugin\n- [#8179](https://github.com/influxdata/telegraf/pull/8179) `inputs.statsd` Add support for datadog distributions metric\n- [#8803](https://github.com/influxdata/telegraf/pull/8803) `agent` Add default retry for load config via url\n- [#8816](https://github.com/influxdata/telegraf/pull/8816) Code Signing for Windows\n- [#8772](https://github.com/influxdata/telegraf/pull/8772) `processors.starlark` Allow to provide constants to a starlark script\n- [#8749](https://github.com/influxdata/telegraf/pull/8749) `outputs.newrelic` Add HTTP proxy setting to New Relic output plugin\n- [#8543](https://github.com/influxdata/telegraf/pull/8543) `inputs.elasticsearch` Add configurable number of 'most recent' date-stamped indices to gather in Elasticsearch input\n- [#8675](https://github.com/influxdata/telegraf/pull/8675) `processors.starlark` Add Starlark parsing example of nested JSON\n- [#8762](https://github.com/influxdata/telegraf/pull/8762) `inputs.prometheus` Optimize for bigger kubernetes clusters (500+ pods)\n- [#8950](https://github.com/influxdata/telegraf/pull/8950) `inputs.teamspeak` Teamspeak input plugin query clients\n- [#8849](https://github.com/influxdata/telegraf/pull/8849) `inputs.sqlserver` Filter data out from system databases for Azure SQL DB only\n\n### New Inputs\n\n- [Beat Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/beat) - Contributed by @nferch\n- [CS:GO Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/csgo) - Contributed by @oofdog\n- [Directory Monitoring Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/directory_monitor) - Contributed by @InfluxData\n- [RavenDB Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/ravendb) - Contributed by @ml054 and @bartoncasey\n- [NFS Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nfsclient) - Contributed by @pmoranga\n\n### New Outputs\n\n- [Grafana Loki Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/loki) - Contributed by @Eraac\n- [Google BigQuery Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/loki) - Contributed by @gkatzioura\n- [Sensu Output Plugin](https://github.com/influxdata/telegraf/blob/master/plugins/outputs/sensu) - Contributed by @calebhailey\n- [SignalFX Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/signalfx) - Contributed by @keitwb\n\n### New Aggregators\n\n- [Derivative Aggregator Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/aggregators/derivative) - Contributed by @KarstenSchnitter\n- [Quantile Aggregator Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/aggregators/quantile) - Contributed by @srebhan\n\n### New Processors\n\n- [AWS EC2 Metadata Processor Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/processors/aws/ec2) - Contributed by @pmalek-sumo\n\n### New Parsers\n\n- [XML Parser Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/xml) - Contributed by @srebhan\n\n### New Serializers\n\n- [MessagePack Serializer Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/serializers/msgpack) - Contributed by @dialogbox\n\n### New External Plugins\n\n- [GeoIP Processor Plugin](https://github.com/a-bali/telegraf-geoip) - Contributed by @a-bali\n- [Plex Webhook Input Plugin](https://github.com/russorat/telegraf-webhooks-plex) - Contributed by @russorat\n- [SMCIPMITool Input Plugin](https://github.com/jhpope/smc_ipmi) - Contributed by @jhpope\n\n## v1.17.3 [2021-02-17]\n\n### Bugfixes\n\n- [#7316](https://github.com/influxdata/telegraf/pull/7316) `inputs.filestat` plugins/filestat: Skip missing files\n- [#8868](https://github.com/influxdata/telegraf/pull/8868) Update to Go 1.15.8\n- [#8744](https://github.com/influxdata/telegraf/pull/8744) Bump github.com/gopcua/opcua from 0.1.12 to 0.1.13\n- [#8657](https://github.com/influxdata/telegraf/pull/8657) `outputs.warp10` outputs/warp10: url encode comma in tags value\n- [#8824](https://github.com/influxdata/telegraf/pull/8824) `inputs.x509_cert` inputs.x509_cert: Fix timeout issue\n- [#8821](https://github.com/influxdata/telegraf/pull/8821) `inputs.mqtt_consumer` Fix reconnection issues mqtt\n- [#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\n- [#8804](https://github.com/influxdata/telegraf/pull/8804) `inputs.snmp` Expose v4/v6-only connection-schemes through GosnmpWrapper\n- [#8838](https://github.com/influxdata/telegraf/pull/8838) `agent` fix issue with reading flush_jitter output from config\n- [#8839](https://github.com/influxdata/telegraf/pull/8839) `inputs.ping` fixes Sort and timeout around deadline\n- [#8787](https://github.com/influxdata/telegraf/pull/8787) `inputs.ping` Update README for inputs.ping with correct cmd for native ping on Linux\n- [#8771](https://github.com/influxdata/telegraf/pull/8771) Update go-ping to latest version\n\n## v1.17.2 [2021-01-28]\n\n### Bugfixes\n\n- [#8770](https://github.com/influxdata/telegraf/pull/8770) `inputs.ping` Set interface for native\n- [#8764](https://github.com/influxdata/telegraf/pull/8764) `inputs.ping` Resolve regression, re-add missing function\n\n## v1.17.1 [2021-01-27]\n\n### Release Notes\n\nIncluded a few more changes that add configuration options to plugins as it's been while since the last release\n\n- [#8335](https://github.com/influxdata/telegraf/pull/8335) `inputs.ipmi_sensor` Add setting to enable caching in ipmitool\n- [#8616](https://github.com/influxdata/telegraf/pull/8616) Add Event Log support for Windows\n- [#8602](https://github.com/influxdata/telegraf/pull/8602) `inputs.postgresql_extensible` Add timestamp column support to postgresql_extensible\n- [#8627](https://github.com/influxdata/telegraf/pull/8627) `parsers.csv` Added ability to define skip values in csv parser\n- [#8055](https://github.com/influxdata/telegraf/pull/8055) `outputs.http` outputs/http: add option to control idle connection timeout\n- [#7897](https://github.com/influxdata/telegraf/pull/7897) `common.tls` common/tls: Allow specifying SNI hostnames\n- [#8541](https://github.com/influxdata/telegraf/pull/8541) `inputs.snmp` Extended the internal snmp wrapper to support AES192, AES192C, AES256, and AES256C\n- [#6165](https://github.com/influxdata/telegraf/pull/6165) `inputs.procstat` Provide method to include core count when reporting cpu_usage in procstat input\n- [#8287](https://github.com/influxdata/telegraf/pull/8287) `inputs.jenkins` Add support for an inclusive job list in Jenkins plugin\n- [#8524](https://github.com/influxdata/telegraf/pull/8524) `inputs.ipmi_sensor` Add hex_key parameter for IPMI input plugin connection\n\n### Bugfixes\n\n- [#8662](https://github.com/influxdata/telegraf/pull/8662) `outputs.influxdb_v2` [outputs.influxdb_v2] add exponential backoff, and respect client error responses\n- [#8748](https://github.com/influxdata/telegraf/pull/8748) `outputs.elasticsearch` Fix issue with elasticsearch output being really noisy about some errors\n- [#7533](https://github.com/influxdata/telegraf/pull/7533) `inputs.zookeeper` improve mntr regex to match user specific keys.\n- [#7967](https://github.com/influxdata/telegraf/pull/7967) `inputs.lustre2` Fix crash in lustre2 input plugin, when field name and value\n- [#8673](https://github.com/influxdata/telegraf/pull/8673) Update grok-library to v1.0.1 with dots and dash-patterns fixed.\n- [#8679](https://github.com/influxdata/telegraf/pull/8679) `inputs.ping` Use go-ping for \"native\" execution in Ping plugin\n- [#8741](https://github.com/influxdata/telegraf/pull/8741) `inputs.x509_cert` fix x509 cert timeout issue\n- [#8714](https://github.com/influxdata/telegraf/pull/8714) Bump github.com/nsqio/go-nsq from 1.0.7 to 1.0.8\n- [#8715](https://github.com/influxdata/telegraf/pull/8715) Bump github.com/Shopify/sarama from 1.27.1 to 1.27.2\n- [#8712](https://github.com/influxdata/telegraf/pull/8712) Bump github.com/newrelic/newrelic-telemetry-sdk-go from 0.2.0 to 0.5.1\n- [#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.\n- [#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.\n- [#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.\n- [#8391](https://github.com/influxdata/telegraf/pull/8391) `aggregators.merge` Optimize SeriesGrouper & aggregators.merge\n- [#8545](https://github.com/influxdata/telegraf/pull/8545) `inputs.prometheus` Using mime-type in prometheus parser to handle protocol-buffer responses\n- [#8588](https://github.com/influxdata/telegraf/pull/8588) `inputs.snmp` Input SNMP plugin - upgrade gosnmp library to version 1.29.0\n- [#8502](https://github.com/influxdata/telegraf/pull/8502) `inputs.http_listener_v2` Fix Stop() bug when plugin fails to start\n\n### New External Plugins\n\n- [#8646](https://github.com/influxdata/telegraf/pull/8646) [Open Hardware Monitoring](https://github.com/marianob85/open_hardware_monitor-telegraf-plugin) Input Plugin\n\n## v1.17.0 [2020-12-18]\n\n### Release Notes\n\n- 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.\n- New input plugins: Riemann-Protobuff Listener, Intel PowerStat\n- New output plugins: Yandex.Cloud monitoring, Logz.io\n- New parser plugin: Prometheus\n- New serializer: Prometheus remote write\n\n### Bugfixes\n\n- [#8505](https://github.com/influxdata/telegraf/pull/8505) `inputs.vsphere` Fixed misspelled check for datacenter\n- [#8499](https://github.com/influxdata/telegraf/pull/8499) `processors.execd` Adding support for new lines in influx line protocol fields.\n- [#8254](https://github.com/influxdata/telegraf/pull/8254) `serializers.carbon2` Fix carbon2 tests\n- [#8498](https://github.com/influxdata/telegraf/pull/8498) `inputs.http_response` fixed network test\n- [#8414](https://github.com/influxdata/telegraf/pull/8414) `inputs.bcache` Fix tests for Windows - part 1\n- [#8577](https://github.com/influxdata/telegraf/pull/8577) `inputs.ping` fix potential issue with race condition\n- [#8562](https://github.com/influxdata/telegraf/pull/8562) `inputs.mqtt_consumer` fix issue with mqtt concurrent map write\n- [#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\n- [#8551](https://github.com/influxdata/telegraf/pull/8551) `inputs.socket_listener` fix crash when socket_listener receiving invalid data\n- [#8564](https://github.com/influxdata/telegraf/pull/8564) `parsers.graphite` Graphite tags parser\n- [#8472](https://github.com/influxdata/telegraf/pull/8472) `inputs.kube_inventory` Fixing issue with missing metrics when pod has only pending containers\n- [#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\n- [#8512](https://github.com/influxdata/telegraf/pull/8512) `inputs.kube_inventory` Update string parsing of allocatable cpu cores in kube_inventory\n\n### Features\n\n- [#8038](https://github.com/influxdata/telegraf/pull/8038) `inputs.jenkins` feat: add build number field to jenkins_job measurement\n- [#7345](https://github.com/influxdata/telegraf/pull/7345) `inputs.ping` Add percentiles to the ping plugin\n- [#8369](https://github.com/influxdata/telegraf/pull/8369) `inputs.sqlserver` Added tags for monitoring readable secondaries for Azure SQL MI\n- [#8379](https://github.com/influxdata/telegraf/pull/8379) `inputs.sqlserver` SQL Server HA/DR Availability Group queries\n- [#8520](https://github.com/influxdata/telegraf/pull/8520) Add initialization example to mock-plugin.\n- [#8426](https://github.com/influxdata/telegraf/pull/8426) `inputs.snmp` Add support to convert snmp hex strings to integers\n- [#8509](https://github.com/influxdata/telegraf/pull/8509) `inputs.statsd` Add configurable Max TTL duration for statsd input plugin entries\n- [#8508](https://github.com/influxdata/telegraf/pull/8508) `inputs.bind` Add configurable timeout to bind input plugin http call\n- [#8368](https://github.com/influxdata/telegraf/pull/8368) `inputs.sqlserver` Added is_primary_replica for monitoring readable secondaries for Azure SQL DB\n- [#8462](https://github.com/influxdata/telegraf/pull/8462) `inputs.sqlserver` sqlAzureMIRequests - remove duplicate column [session_db_name]\n- [#8464](https://github.com/influxdata/telegraf/pull/8464) `inputs.sqlserver` Add column measurement_db_type to output of all queries if not empty\n- [#8389](https://github.com/influxdata/telegraf/pull/8389) `inputs.opcua` Add node groups to opcua input plugin\n- [#8432](https://github.com/influxdata/telegraf/pull/8432) add support for linux/ppc64le\n- [#8474](https://github.com/influxdata/telegraf/pull/8474) `inputs.modbus` Add FLOAT64-IEEE support to inputs.modbus (#8361) (by @Nemecsek)\n- [#8447](https://github.com/influxdata/telegraf/pull/8447) `processors.starlark` Add the shared state to the global scope to get previous data\n- [#8383](https://github.com/influxdata/telegraf/pull/8383) `inputs.zfs` Add dataset metrics to zfs input\n- [#8429](https://github.com/influxdata/telegraf/pull/8429) `outputs.nats` Added \"name\" parameter to NATS output plugin\n- [#8477](https://github.com/influxdata/telegraf/pull/8477) `inputs.http` proxy support for http input\n- [#8466](https://github.com/influxdata/telegraf/pull/8466) `inputs.snmp` Translate snmp field values\n- [#8435](https://github.com/influxdata/telegraf/pull/8435) `common.kafka` Enable kafka zstd compression and idempotent writes\n- [#8056](https://github.com/influxdata/telegraf/pull/8056) `inputs.monit` Add response_time to monit plugin\n- [#8446](https://github.com/influxdata/telegraf/pull/8446) update to go 1.15.5\n- [#8428](https://github.com/influxdata/telegraf/pull/8428) `aggregators.basicstats` Add rate and interval to the basicstats aggregator plugin\n- [#8575](https://github.com/influxdata/telegraf/pull/8575) `inputs.win_services` Added Glob pattern matching for \"Windows Services\" plugin\n- [#6132](https://github.com/influxdata/telegraf/pull/6132) `inputs.mysql` Add per user metrics to mysql input\n- [#8500](https://github.com/influxdata/telegraf/pull/8500) `inputs.github` [inputs.github] Add query of pull-request statistics\n- [#8598](https://github.com/influxdata/telegraf/pull/8598) `processors.enum` Allow globs (wildcards) in config for tags/fields in enum processor\n- [#8590](https://github.com/influxdata/telegraf/pull/8590) `inputs.ethtool` [ethtool] interface_up field added\n- [#8579](https://github.com/influxdata/telegraf/pull/8579) `parsers.json` Add wildcard tags json parser support\n\n### New Parser Plugins\n\n- [#7778](https://github.com/influxdata/telegraf/pull/7778) `parsers.prometheus` Add a parser plugin for prometheus\n\n### New Serializer Plugins\n\n- [#8360](https://github.com/influxdata/telegraf/pull/8360) `serializers.prometheusremotewrite` Add prometheus remote write serializer\n\n### New Input Plugins\n\n- [#8163](https://github.com/influxdata/telegraf/pull/8163) `inputs.riemann` Support Riemann-Protobuff Listener\n- [#8488](https://github.com/influxdata/telegraf/pull/8488) `inputs.intel_powerstat` New Intel PowerStat input plugin\n\n### New Output Plugins\n\n- [#8296](https://github.com/influxdata/telegraf/pull/8296) `outputs.yandex_cloud_monitoring` #8295 Initial Yandex.Cloud monitoring\n- [#8202](https://github.com/influxdata/telegraf/pull/8202) `outputs.logzio` A new Logz.io output plugin\n\n## v1.16.3 [2020-12-01]\n\n### Bugfixes\n\n- [#8483](https://github.com/influxdata/telegraf/pull/8483) `inputs.gnmi` Log SubscribeResponse_Error message and code. #8482\n- [#7987](https://github.com/influxdata/telegraf/pull/7987) update godirwalk to v1.16.1\n- [#8438](https://github.com/influxdata/telegraf/pull/8438) `processors.starlark` Starlark example dropbytype\n- [#8468](https://github.com/influxdata/telegraf/pull/8468) `inputs.sqlserver` Fix typo in column name\n- [#8461](https://github.com/influxdata/telegraf/pull/8461) `inputs.phpfpm` [php-fpm] Fix possible \"index out of range\"\n- [#8444](https://github.com/influxdata/telegraf/pull/8444) `inputs.apcupsd` Update mdlayher/apcupsd dependency\n- [#8439](https://github.com/influxdata/telegraf/pull/8439) `processors.starlark` Show how to return a custom error with the Starlark processor\n- [#8440](https://github.com/influxdata/telegraf/pull/8440) `parsers.csv` keep field name as is for csv timestamp column\n- [#8436](https://github.com/influxdata/telegraf/pull/8436) `inputs.nvidia_smi` Add DriverVersion and CUDA Version to output\n- [#8423](https://github.com/influxdata/telegraf/pull/8423) `processors.starlark` Show how to return several metrics with the Starlark processor\n- [#8408](https://github.com/influxdata/telegraf/pull/8408) `processors.starlark` Support logging in starlark\n- [#8315](https://github.com/influxdata/telegraf/pull/8315) add kinesis output to external plugins list\n- [#8406](https://github.com/influxdata/telegraf/pull/8406) `outputs.wavefront` #8405 add non-retryable debug logging\n- [#8404](https://github.com/influxdata/telegraf/pull/8404) `outputs.wavefront` Wavefront output should distinguish between retryable and non-retryable errors\n- [#8401](https://github.com/influxdata/telegraf/pull/8401) `processors.starlark` Allow to catch errors that occur in the apply function\n\n## v1.16.2 [2020-11-13]\n\n### Bugfixes\n\n- [#8400](https://github.com/influxdata/telegraf/pull/8400) `parsers.csv` Fix parsing of multiple files with different headers (#6318).\n- [#8326](https://github.com/influxdata/telegraf/pull/8326) `inputs.proxmox` proxmox: ignore QEMU templates and iron out a few bugs\n- [#7991](https://github.com/influxdata/telegraf/pull/7991) `inputs.systemd_units` systemd_units: add --plain to command invocation (#7990)\n- [#8307](https://github.com/influxdata/telegraf/pull/8307) fix links in external plugins readme\n- [#8370](https://github.com/influxdata/telegraf/pull/8370) `inputs.redis` Fix minor typos in readmes\n- [#8374](https://github.com/influxdata/telegraf/pull/8374) `inputs.smart` Fix SMART plugin to recognize all devices from config\n- [#8288](https://github.com/influxdata/telegraf/pull/8288) `inputs.redfish` Add OData-Version header to requests\n- [#8357](https://github.com/influxdata/telegraf/pull/8357) `inputs.vsphere` Prydin issue 8169\n- [#8356](https://github.com/influxdata/telegraf/pull/8356) `inputs.sqlserver` On-prem fix for #8324\n- [#8165](https://github.com/influxdata/telegraf/pull/8165) `outputs.wavefront` [output.wavefront] Introduced \"immediate_flush\" flag\n- [#7938](https://github.com/influxdata/telegraf/pull/7938) `inputs.gnmi` added support for bytes encoding\n- [#8337](https://github.com/influxdata/telegraf/pull/8337) `inputs.dcos` Update jwt-go module to address CVE-2020-26160\n- [#8350](https://github.com/influxdata/telegraf/pull/8350) `inputs.ras` fix plugins/input/ras test\n- [#8329](https://github.com/influxdata/telegraf/pull/8329) `outputs.dynatrace` #8328 Fixed a bug with the state map in Dynatrace Plugin\n\n## v1.16.1 [2020-10-28]\n\n### Release Notes\n\n- [#8318](https://github.com/influxdata/telegraf/pull/8318) `common.kafka` kafka sasl-mechanism auth support for SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI\n\n### Bugfixes\n\n- [#8331](https://github.com/influxdata/telegraf/pull/8331) `inputs.sqlserver` SQL Server Azure PerfCounters Fix\n- [#8325](https://github.com/influxdata/telegraf/pull/8325) `inputs.sqlserver` SQL Server - PerformanceCounters - removed synthetic counters\n- [#8324](https://github.com/influxdata/telegraf/pull/8324) `inputs.sqlserver` SQL Server - server_properties added sql_version_desc\n- [#8317](https://github.com/influxdata/telegraf/pull/8317) `inputs.ras` Disable RAS input plugin on specific Linux architectures: mips64, mips64le, ppc64le, riscv64\n- [#8309](https://github.com/influxdata/telegraf/pull/8309) `inputs.processes` processes: fix issue with stat no such file/dir\n- [#8308](https://github.com/influxdata/telegraf/pull/8308) `inputs.win_perf_counters` fix issue with PDH_CALC_NEGATIVE_DENOMINATOR error\n- [#8306](https://github.com/influxdata/telegraf/pull/8306) `inputs.ras` RAS plugin - fix for too many open files handlers\n\n## v1.16.0 [2020-10-21]\n\n### Release Notes\n\n- New [code examples](/plugins/processors/starlark/testdata) for the [Starlark processor](/plugins/processors/starlark/README.md)\n- [#7920](https://github.com/influxdata/telegraf/pull/7920) `inputs.rabbitmq` remove deprecated healthcheck\n- [#7953](https://github.com/influxdata/telegraf/pull/7953) Add details to connect to InfluxDB OSS 2 and Cloud 2\n- [#8054](https://github.com/influxdata/telegraf/pull/8054) add guidelines run to external plugins with execd\n- [#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\n- [starlark](https://github.com/influxdata/telegraf/tree/release-1.16/plugins/processors/starlark/testdata) `processors.starlark` add various code examples for the Starlark processor\n\n### Features\n\n- [#7814](https://github.com/influxdata/telegraf/pull/7814) `agent` Send metrics in FIFO order\n- [#7869](https://github.com/influxdata/telegraf/pull/7869) `inputs.modbus` extend support of fixed point values on input\n- [#7870](https://github.com/influxdata/telegraf/pull/7870) `inputs.mongodb` Added new metric \"pages written from cache\"\n- [#7875](https://github.com/influxdata/telegraf/pull/7875) `inputs.consul` input consul - added metric_version flag\n- [#7894](https://github.com/influxdata/telegraf/pull/7894) `inputs.cloudwatch` Implement AWS CloudWatch Input Plugin ListMetrics API calls to use Active Metric Filter\n- [#7904](https://github.com/influxdata/telegraf/pull/7904) `inputs.clickhouse` add additional metrics to clickhouse input plugin\n- [#7934](https://github.com/influxdata/telegraf/pull/7934) `inputs.sqlserver` Database_type config to Split up sql queries by engine type\n- [#8018](https://github.com/influxdata/telegraf/pull/8018) `processors.ifname` Add addTag debugging in ifname plugin\n- [#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\n- [#8025](https://github.com/influxdata/telegraf/pull/8025) `inputs.aerospike` Add set, and histogram reporting to aerospike telegraf plugin\n- [#8082](https://github.com/influxdata/telegraf/pull/8082) `inputs.snmp` Add agent host tag configuration option\n- [#8113](https://github.com/influxdata/telegraf/pull/8113) `inputs.smart` Add more missing NVMe attributes to smart plugin\n- [#8120](https://github.com/influxdata/telegraf/pull/8120) `inputs.sqlserver` Added more performance counters to SqlServer input plugin\n- [#8127](https://github.com/influxdata/telegraf/pull/8127) `agent` Sort plugin name lists for output\n- [#8132](https://github.com/influxdata/telegraf/pull/8132) `outputs.sumologic` Sumo Logic output plugin: carbon2 default to include field in metric\n- [#8133](https://github.com/influxdata/telegraf/pull/8133) `inputs.influxdb_v2_listener` influxdb_v2_listener - add /ready route\n- [#8168](https://github.com/influxdata/telegraf/pull/8168) `processors.starlark` add json parsing support to starlark\n- [#8186](https://github.com/influxdata/telegraf/pull/8186) `inputs.sqlserver` New sql server queries (Azure)\n- [#8189](https://github.com/influxdata/telegraf/pull/8189) `inputs.snmp_trap` If the community string is available, add it as a tag\n- [#8190](https://github.com/influxdata/telegraf/pull/8190) `inputs.tail` Semigroupoid multiline (#8167)\n- [#8196](https://github.com/influxdata/telegraf/pull/8196) `inputs.redis` add functionality to get values from redis commands\n- [#8220](https://github.com/influxdata/telegraf/pull/8220) `build` update to Go 1.15\n- [#8032](https://github.com/influxdata/telegraf/pull/8032) `inputs.http_response` http_response: match on status code\n- [#8172](https://github.com/influxdata/telegraf/pull/8172) `inputs.sqlserver` New sql server queries (on-prem) - refactoring and formatting\n\n### Bugfixes\n\n- [#7816](https://github.com/influxdata/telegraf/pull/7816) `shim` fix bug with loading plugins in shim with no config\n- [#7818](https://github.com/influxdata/telegraf/pull/7818) `build` Fix darwin package build flags\n- [#7819](https://github.com/influxdata/telegraf/pull/7819) `inputs.tail` Close file to ensure it has been flushed\n- [#7853](https://github.com/influxdata/telegraf/pull/7853) Initialize aggregation processors\n- [#7865](https://github.com/influxdata/telegraf/pull/7865) `common.shim` shim logger improvements\n- [#7867](https://github.com/influxdata/telegraf/pull/7867) `inputs.execd` fix issue with execd restart_delay being ignored\n- [#7872](https://github.com/influxdata/telegraf/pull/7872) `inputs.gnmi` Recv next message after send returns EOF\n- [#7877](https://github.com/influxdata/telegraf/pull/7877) Fix arch name in deb/rpm builds\n- [#7909](https://github.com/influxdata/telegraf/pull/7909) fixes issue with rpm /var/log/telegraf permissions\n- [#7918](https://github.com/influxdata/telegraf/pull/7918) `inputs.net` fix broken link to proc.c\n- [#7927](https://github.com/influxdata/telegraf/pull/7927) `inputs.tail` Fix tail following on EOF\n- [#8005](https://github.com/influxdata/telegraf/pull/8005) Fix docker-image make target\n- [#8039](https://github.com/influxdata/telegraf/pull/8039) `serializers.splunkmetric` Remove Event field as it is causing issues with pre-trained source types\n- [#8048](https://github.com/influxdata/telegraf/pull/8048) `inputs.jenkins` Multiple escaping occurs on Jenkins URLs at certain folder depth\n- [#8071](https://github.com/influxdata/telegraf/pull/8071) `inputs.kubernetes` add missing error check for HTTP req failure\n- [#8145](https://github.com/influxdata/telegraf/pull/8145) `processors.execd` Increased the maximum serialized metric size in line protocol\n- [#8159](https://github.com/influxdata/telegraf/pull/8159) `outputs.dynatrace` Dynatrace Output: change handling of monotonic counters\n- [#8176](https://github.com/influxdata/telegraf/pull/8176) fix panic on streaming processers using logging\n- [#8177](https://github.com/influxdata/telegraf/pull/8177) `parsers.influx` fix: plugins/parsers/influx: avoid ParseError.Error panic\n- [#8199](https://github.com/influxdata/telegraf/pull/8199) `inputs.docker` Fix vulnerabilities found in BDBA scan\n- [#8200](https://github.com/influxdata/telegraf/pull/8200) `inputs.sqlserver` Fixed Query mapping\n- [#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\n- [#8210](https://github.com/influxdata/telegraf/pull/8210) update gopsutil: fix procstat performance regression\n- [#8162](https://github.com/influxdata/telegraf/pull/8162) Fix bool serialization when using carbon2\n- [#8240](https://github.com/influxdata/telegraf/pull/8240) Fix bugs found by LGTM analysis platform\n- [#8251](https://github.com/influxdata/telegraf/pull/8251) `outputs.dynatrace` Dynatrace Output Plugin: Fixed behaviour when state map is cleared\n- [#8274](https://github.com/influxdata/telegraf/pull/8274) `common.shim` fix issue with loading processor config from execd\n\n### New Input Plugins\n\n- [influxdb_v2_listener](/plugins/inputs/influxdb_v2_listener/README.md) Influxdb v2 listener - Contributed by @magichair\n- [intel_rdt](/plugins/inputs/intel_rdt/README.md) New input plugin for Intel RDT (Intel Resource Director Technology) - Contributed by @p-zak\n- [nsd](/plugins/inputs/nsd/README.md) add nsd input plugin - Contributed by @gearnode\n- [opcua](/plugins/inputs/opcua/README.md) Add OPC UA input plugin - Contributed by InfluxData\n- [proxmox](/plugins/inputs/proxmox/README.md) Proxmox plugin - Contributed by @effitient\n- [ras](/plugins/inputs/ras/README.md) New input plugin for RAS (Reliability, Availability and Serviceability) - Contributed by @p-zak\n- [win_eventlog](/plugins/inputs/win_eventlog/README.md) Windows eventlog input plugin - Contributed by @simnv\n\n### New Output Plugins\n\n- [dynatrace](/plugins/outputs/dynatrace/README.md) Dynatrace output plugin - Contributed by @thschue\n- [sumologic](/plugins/outputs/sumologic/README.md) Sumo Logic output plugin - Contributed by @pmalek-sumo\n- [timestream](/plugins/outputs/timestream) Timestream Output Plugin - Contributed by @piotrwest\n\n### New External Plugins\n\nSee [EXTERNAL_PLUGINS.md](/EXTERNAL_PLUGINS.md) for a full list of external plugins\n\n- [awsalarms](https://github.com/vipinvkmenon/awsalarms) - Simple plugin to gather/monitor alarms generated  in AWS.\n- [youtube-telegraf-plugin](https://github.com/inabagumi/youtube-telegraf-plugin) - Gather view and subscriber stats from your youtube videos\n- [octoprint](https://github.com/BattleBas/octoprint-telegraf-plugin) - Gather 3d print information from the octoprint API.\n- [systemd-timings](https://github.com/pdmorrow/telegraf-execd-systemd-timings) - Gather systemd boot and unit timestamp metrics.\n\n## v1.15.4 [2020-10-20]\n\n### Bugfixes\n\n- [#8274](https://github.com/influxdata/telegraf/pull/8274) `common.shim` fix issue with loading processor config from execd\n- [#8176](https://github.com/influxdata/telegraf/pull/8176) `agent` fix panic on streaming processers using logging\n\n## v1.15.3 [2020-09-11]\n\n### Release Notes\n\n- Many documentation updates\n- 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)\n\n### Bugfixes\n\n- [#7999](https://github.com/influxdata/telegraf/pull/7999) `agent` fix minor agent error message race condition\n- [#8051](https://github.com/influxdata/telegraf/pull/8051) `build` fix docker build. update dockerfiles to Go 1.14\n- [#8052](https://github.com/influxdata/telegraf/pull/8052) `shim` fix bug in shim logger affecting AddError\n- [#7996](https://github.com/influxdata/telegraf/pull/7996) `shim` fix issue with shim use of config.Duration\n- [#8006](https://github.com/influxdata/telegraf/pull/8006) `inputs.eventhub_consumer` Fix string to int conversion in eventhub consumer\n- [#7986](https://github.com/influxdata/telegraf/pull/7986) `inputs.http_listener_v2` make http header tags case insensitive\n- [#7869](https://github.com/influxdata/telegraf/pull/7869) `inputs.modbus` extend support of fixed point values on input\n- [#7861](https://github.com/influxdata/telegraf/pull/7861) `inputs.ping` Fix Ping Input plugin for FreeBSD's ping6\n- [#7808](https://github.com/influxdata/telegraf/pull/7808) `inputs.sqlserver` added new counter - Lock Timeouts (timeout > 0)/sec\n- [#8026](https://github.com/influxdata/telegraf/pull/8026) `inputs.vsphere` vSphere Fixed missing clustername issue 7878\n- [#8020](https://github.com/influxdata/telegraf/pull/8020) `processors.starlark` improve the quality of starlark docs by executing them as tests\n- [#7976](https://github.com/influxdata/telegraf/pull/7976) `processors.starlark` add pivot example for starlark processor\n- [#7134](https://github.com/influxdata/telegraf/pull/7134) `outputs.application_insights` Added the ability to set the endpoint url\n- [#7908](https://github.com/influxdata/telegraf/pull/7908) `outputs.opentsdb` fix JSON handling of values NaN and Inf\n\n## v1.15.2 [2020-07-31]\n\n### Bug Fixes\n\n- [#7905](https://github.com/influxdata/telegraf/issues/7905): Fix RPM /var/log/telegraf permissions\n- [#7880](https://github.com/influxdata/telegraf/issues/7880): Fix tail following on EOF\n\n## v1.15.1 [2020-07-22]\n\n### Bug Fixes\n\n- [#7877](https://github.com/influxdata/telegraf/pull/7877): Fix architecture in non-amd64 deb and rpm packages.\n\n## v1.15.0 [2020-07-22]\n\n### Release Notes\n\n- The `logparser` input is deprecated, use the `tail` input with `data_format =\n  \"grok\"` as a replacement.\n\n- The `cisco_telemetry_gnmi` input has been renamed to `gnmi` to better reflect\n  its general support for gNMI devices.\n\n- Several fields used primarily for debugging have been removed from the\n  `splunkmetric` serializer, if you are making use of these fields they can be\n  added back with the `tag` option.\n\n- Telegraf's `--test` mode now runs processors and aggregators before printing\n  metrics.\n\n- Official packages now built with Go 1.14.5.\n\n- When updating the Debian package you will no longer be prompted to merge the\n  telegraf.conf file, instead the new version will be installed to\n  `/etc/telegraf/telegraf.conf.sample`.  The tar and zip packages now include\n  the version in the top level directory.\n\n### New Inputs\n\n- [nginx_sts](/plugins/inputs/nginx_sts/README.md) - Contributed by @zdmytriv\n- [redfish](/plugins/inputs/redfish/README.md) - Contributed by @sarvanikonda\n\n### New Processors\n\n- [defaults](/plugins/processors/defaults/README.md) - Contributed by @jregistr\n- [execd](/plugins/processors/execd/README.md) - Contributed by @influxdata\n- [filepath](/plugins/processors/filepath/README.md) - Contributed by @kir4h\n- [ifname](/plugins/processors/ifname/README.md) - Contributed by @influxdata\n- [port_name](/plugins/processors/port_name/README.md) - Contributed by @influxdata\n- [reverse_dns](/plugins/processors/reverse_dns/README.md) - Contributed by @influxdata\n- [starlark](/plugins/processors/starlark/README.md) - Contributed by @influxdata\n\n### New Outputs\n\n- [newrelic](/plugins/outputs/newrelic/README.md) - Contributed by @hsinghkalsi\n- [execd](/plugins/outputs/execd/README.md) - Contributed by @influxdata\n\n### Features\n\n- [#7634](https://github.com/influxdata/telegraf/pull/7634): Add support for streaming processors.\n- [#6905](https://github.com/influxdata/telegraf/pull/6905): Add commands stats to mongodb input plugin.\n- [#7193](https://github.com/influxdata/telegraf/pull/7193): Add additional concurrent transaction information.\n- [#7223](https://github.com/influxdata/telegraf/pull/7223): Add ability to specify HTTP Headers in http_listener_v2 which will added as tags.\n- [#7140](https://github.com/influxdata/telegraf/pull/7140): Apply ping deadline to dns lookup.\n- [#7225](https://github.com/influxdata/telegraf/pull/7225): Add support for 64-bit integer types to modbus input.\n- [#7231](https://github.com/influxdata/telegraf/pull/7231): Add possibility to specify measurement per register.\n- [#7136](https://github.com/influxdata/telegraf/pull/7136): Support multiple templates for graphite serializers.\n- [#7250](https://github.com/influxdata/telegraf/pull/7250): Deploy telegraf configuration as a \"non config\" file.\n- [#7214](https://github.com/influxdata/telegraf/pull/7214): Add VolumeSpace query for sqlserver input with metric_version 2.\n- [#7304](https://github.com/influxdata/telegraf/pull/7304): Add reading bearer token from a file to http input.\n- [#7366](https://github.com/influxdata/telegraf/pull/7366): add support for SIGUSR1 to trigger flush.\n- [#7271](https://github.com/influxdata/telegraf/pull/7271): Add retry when slave is busy to modbus input.\n- [#7356](https://github.com/influxdata/telegraf/pull/7356): Add option to save retention policy as tag in influxdb_listener.\n- [#6915](https://github.com/influxdata/telegraf/pull/6915): Add support for MDS and RGW sockets to ceph input.\n- [#7391](https://github.com/influxdata/telegraf/pull/7391): Extract target as a tag for each rule in iptables input.\n- [#7434](https://github.com/influxdata/telegraf/pull/7434): Use docker log timestamp as metric time.\n- [#7359](https://github.com/influxdata/telegraf/pull/7359): Add cpu query to sqlserver input.\n- [#7464](https://github.com/influxdata/telegraf/pull/7464): Add field creation to date processor and integer unix time support.\n- [#7483](https://github.com/influxdata/telegraf/pull/7483): Add integer mapping support to enum processor.\n- [#7321](https://github.com/influxdata/telegraf/pull/7321): Add additional fields to mongodb input.\n- [#7491](https://github.com/influxdata/telegraf/pull/7491): Add authentication support to the http_response input plugin.\n- [#7503](https://github.com/influxdata/telegraf/pull/7503): Add truncate_tags setting to wavefront output.\n- [#7545](https://github.com/influxdata/telegraf/pull/7545): Add configurable separator graphite serializer and output.\n- [#7489](https://github.com/influxdata/telegraf/pull/7489): Add cluster state integer to mongodb input.\n- [#7515](https://github.com/influxdata/telegraf/pull/7515): Add option to disable mongodb cluster status.\n- [#7319](https://github.com/influxdata/telegraf/pull/7319): Add support for battery level monitoring to the fibaro input.\n- [#7405](https://github.com/influxdata/telegraf/pull/7405): Allow collection of HTTP Headers in http_response input.\n- [#7540](https://github.com/influxdata/telegraf/pull/7540): Add processor to look up service name by port.\n- [#7474](https://github.com/influxdata/telegraf/pull/7474): Add new once mode that write to outputs and exits.\n- [#7474](https://github.com/influxdata/telegraf/pull/7474): Run processors and aggregators during test mode.\n- [#7294](https://github.com/influxdata/telegraf/pull/7294): Add SNMPv3 trap support to snmp_trap input.\n- [#7646](https://github.com/influxdata/telegraf/pull/7646): Add video codec stats to nvidia-smi.\n- [#7651](https://github.com/influxdata/telegraf/pull/7651): Fix source field for icinga2 plugin and add tag for server hostname.\n- [#7619](https://github.com/influxdata/telegraf/pull/7619): Add timezone configuration to csv input data format.\n- [#7596](https://github.com/influxdata/telegraf/pull/7596): Add ability to collect response body as field with http_response.\n- [#7267](https://github.com/influxdata/telegraf/pull/7267): Add ability to add selectors as tags in kube_inventory.\n- [#7712](https://github.com/influxdata/telegraf/pull/7712): Add counter type to sqlserver perfmon collector.\n- [#7575](https://github.com/influxdata/telegraf/pull/7575): Add missing nvme attributes to smart plugin.\n- [#7726](https://github.com/influxdata/telegraf/pull/7726): Add laundry to mem plugin on FreeBSD.\n- [#7762](https://github.com/influxdata/telegraf/pull/7762): Allow per input overriding of collection_jitter and precision.\n- [#7686](https://github.com/influxdata/telegraf/pull/7686): Improve performance of procstat: Up to 40/120x better performance.\n- [#7677](https://github.com/influxdata/telegraf/pull/7677): Expand execd shim support for processor and outputs.\n- [#7154](https://github.com/influxdata/telegraf/pull/7154): Add v3 metadata support to ecs input.\n- [#7792](https://github.com/influxdata/telegraf/pull/7792): Support utf-16 in file and tail inputs.\n\n### Bug Fixes\n\n- [#7371](https://github.com/influxdata/telegraf/issues/7371): Fix unable to write metrics to CloudWatch with IMDSv1 disabled.\n- [#7233](https://github.com/influxdata/telegraf/issues/7233): Fix vSphere 6.7 missing data issue.\n- [#7448](https://github.com/influxdata/telegraf/issues/7448): Remove debug fields from splunkmetric serializer.\n- [#7446](https://github.com/influxdata/telegraf/issues/7446): Fix gzip support in socket_listener with tcp sockets.\n- [#7390](https://github.com/influxdata/telegraf/issues/7390): Fix interval drift when round_interval is set in agent.\n- [#7524](https://github.com/influxdata/telegraf/pull/7524): Fix typo in total_elapsed_time_ms field of sqlserver input.\n- [#7203](https://github.com/influxdata/telegraf/issues/7203): Exclude csv_timestamp_column and csv_measurement_column from fields.\n- [#7018](https://github.com/influxdata/telegraf/issues/7018): Fix incorrect uptime when clock is adjusted.\n- [#6807](https://github.com/influxdata/telegraf/issues/6807): Fix memory leak when using procstat on Windows.\n- [#7495](https://github.com/influxdata/telegraf/issues/7495): Improve sqlserver input compatibility with older server versions.\n- [#7558](https://github.com/influxdata/telegraf/issues/7558): Remove trailing backslash from tag keys/values in influx serializer.\n- [#7715](https://github.com/influxdata/telegraf/issues/7715): Fix incorrect Azure SQL DB server properties.\n- [#7431](https://github.com/influxdata/telegraf/issues/7431): Fix json unmarshal error in the kibana input.\n- [#5633](https://github.com/influxdata/telegraf/issues/5633): Send metrics in FIFO order.\n\n## v1.14.5 [2020-06-30]\n\n### Bug Fixes\n\n- [#7686](https://github.com/influxdata/telegraf/pull/7686): Improve the performance of the procstat input.\n- [#7658](https://github.com/influxdata/telegraf/pull/7658): Fix ping exit code handling on non-Linux.\n- [#7718](https://github.com/influxdata/telegraf/pull/7718): Skip overs errors in the output of the sensors command.\n- [#7748](https://github.com/influxdata/telegraf/issues/7748): Prevent startup when tags have incorrect type in configuration file.\n- [#7699](https://github.com/influxdata/telegraf/issues/7699): Fix panic with GJSON multiselect query in json parser.\n- [#7754](https://github.com/influxdata/telegraf/issues/7754): Allow any key usage type on x509 certificate.\n- [#7705](https://github.com/influxdata/telegraf/issues/7705): Allow histograms and summary types without buckets or quantiles in prometheus_client output.\n\n## v1.14.4 [2020-06-09]\n\n### Bug Fixes\n\n- [#7325](https://github.com/influxdata/telegraf/issues/7325): Fix \"cannot insert the value NULL error\" with PerformanceCounters query.\n- [#7579](https://github.com/influxdata/telegraf/pull/7579): Fix numeric to bool conversion in converter processor.\n- [#7551](https://github.com/influxdata/telegraf/issues/7551): Fix typo in name of gc_cpu_fraction field of the influxdb input.\n- [#7617](https://github.com/influxdata/telegraf/issues/7617): Fix issue with influx stream parser blocking when data is in buffer.\n\n## v1.14.3 [2020-05-19]\n\n### Bug Fixes\n\n- [#7412](https://github.com/influxdata/telegraf/pull/7412): Use same timestamp for all objects in arrays in the json parser.\n- [#7343](https://github.com/influxdata/telegraf/issues/7343): Handle multiple metrics with the same timestamp in dedup processor.\n- [#5905](https://github.com/influxdata/telegraf/issues/5905): Fix reconnection of timed out HTTP2 connections influxdb outputs.\n- [#7468](https://github.com/influxdata/telegraf/issues/7468): Fix negative value parsing in impi_sensor input.\n\n## v1.14.2 [2020-04-28]\n\n### Bug Fixes\n\n- [#7241](https://github.com/influxdata/telegraf/issues/7241): Trim whitespace from instance tag in sqlserver input.\n- [#7322](https://github.com/influxdata/telegraf/issues/7322): Use increased AWS Cloudwatch GetMetricData limit of 500 metrics per call.\n- [#7318](https://github.com/influxdata/telegraf/issues/7318): Fix dimension limit on azure_monitor output.\n- [#7407](https://github.com/influxdata/telegraf/pull/7407): Fix 64-bit integer to string conversion in snmp input.\n- [#7327](https://github.com/influxdata/telegraf/issues/7327): Fix shard indices reporting in elasticsearch input.\n- [#7388](https://github.com/influxdata/telegraf/issues/7388): Ignore fields with NaN or Inf floats in the JSON serializer.\n- [#7402](https://github.com/influxdata/telegraf/issues/7402): Fix typo in name of gc_cpu_fraction field of the kapacitor input.\n- [#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.\n- [#7406](https://github.com/influxdata/telegraf/issues/7406): Allow CR and FF inside of string fields in influx parser.\n\n## v1.14.1 [2020-04-14]\n\n### Bug Fixes\n\n- [#7236](https://github.com/influxdata/telegraf/issues/7236): Fix PerformanceCounter query performance degradation in sqlserver input.\n- [#7257](https://github.com/influxdata/telegraf/issues/7257): Fix error when using the Name field in template processor.\n- [#7289](https://github.com/influxdata/telegraf/pull/7289): Fix export timestamp not working for prometheus on v2.\n- [#7310](https://github.com/influxdata/telegraf/issues/7310): Fix exclude database and retention policy tags is shared.\n- [#7262](https://github.com/influxdata/telegraf/issues/7262): Fix status path when using globs in phpfpm.\n\n## v1.14 [2020-03-26]\n\n### Release Notes\n\n- In the `sqlserver` input, the `sqlserver_azurestats` measurement has been\n  renamed to `sqlserver_azure_db_resource_stats` due to an issue where numeric\n  metrics were previously being reported incorrectly as strings.\n\n- The `date` processor now uses the UTC timezone when creating its tag.  In\n  previous versions the local time was used.\n\n### New Inputs\n\n- [clickhouse](/plugins/inputs/clickhouse/README.md) - Contributed by @kshvakov\n- [execd](/plugins/inputs/execd/README.md) - Contributed by @jgraichen\n- [eventhub_consumer](/plugins/inputs/eventhub_consumer/README.md) - Contributed by @R290\n- [infiniband](/plugins/inputs/infiniband/README.md) - Contributed by @willfurnell\n- [lanz](/plugins/inputs/lanz/README.md): Contributed by @timhughes\n- [modbus](/plugins/inputs/modbus/README.md) - Contributed by @garciaolais\n- [monit](/plugins/inputs/monit/README.md) - Contributed by @SirishaGopigiri\n- [sflow](/plugins/inputs/sflow/README.md) - Contributed by @influxdata\n- [wireguard](/plugins/inputs/wireguard/README.md) - Contributed by @LINKIWI\n\n### New Processors\n\n- [dedup](/plugins/processors/dedup/README.md) - Contributed by @igomura\n- [template](/plugins/processors/template/README.md) - Contributed by @RobMalvern\n- [s2geo](/plugins/processors/s2geo/README.md) - Contributed by @alespour\n\n### New Outputs\n\n- [warp10](/plugins/outputs/warp10/README.md) - Contributed by @aurrelhebert\n\n### Features\n\n- [#6730](https://github.com/influxdata/telegraf/pull/6730): Add page_faults for mongodb wired tiger.\n- [#6798](https://github.com/influxdata/telegraf/pull/6798): Add use_sudo option to ipmi_sensor input.\n- [#6764](https://github.com/influxdata/telegraf/pull/6764): Add ability to collect pod labels to kubernetes input.\n- [#6770](https://github.com/influxdata/telegraf/pull/6770): Expose unbound-control config file option.\n- [#6508](https://github.com/influxdata/telegraf/pull/6508): Add support for new nginx plus api endpoints.\n- [#6342](https://github.com/influxdata/telegraf/pull/6342): Add kafka SASL version control to support Azure Event Hub.\n- [#6869](https://github.com/influxdata/telegraf/pull/6869): Add RBPEX IO statistics to DatabaseIO query in sqlserver input.\n- [#6869](https://github.com/influxdata/telegraf/pull/6869): Add space on disk for each file to DatabaseIO query in the sqlserver input.\n- [#6869](https://github.com/influxdata/telegraf/pull/6869): Calculate DB Name instead of GUID in physical_db_name in the sqlserver input.\n- [#6733](https://github.com/influxdata/telegraf/pull/6733): Add latency stats to mongo input.\n- [#6844](https://github.com/influxdata/telegraf/pull/6844): Add source and port tags to jenkins_job metrics.\n- [#6886](https://github.com/influxdata/telegraf/pull/6886): Add date offset and timezone options to date processor.\n- [#6859](https://github.com/influxdata/telegraf/pull/6859): Exclude resources by inventory path in vsphere input.\n- [#6700](https://github.com/influxdata/telegraf/pull/6700): Allow a user defined field to be used as the graylog short_message.\n- [#6917](https://github.com/influxdata/telegraf/pull/6917): Add server_name override for x509_cert plugin.\n- [#6921](https://github.com/influxdata/telegraf/pull/6921): Add udp internal metrics for the statsd input.\n- [#6914](https://github.com/influxdata/telegraf/pull/6914): Add replica set tag to mongodb input.\n- [#6935](https://github.com/influxdata/telegraf/pull/6935): Add counters for merged reads and writes to diskio input.\n- [#6982](https://github.com/influxdata/telegraf/pull/6982): Add support for titlecase transformation to strings processor.\n- [#6993](https://github.com/influxdata/telegraf/pull/6993): Add support for MDB database information to openldap input.\n- [#6957](https://github.com/influxdata/telegraf/pull/6957): Add new fields for Jenkins total and busy executors.\n- [#7035](https://github.com/influxdata/telegraf/pull/7035): Fix dash to underscore replacement when handling embedded tags in Cisco MDT.\n- [#7039](https://github.com/influxdata/telegraf/pull/7039): Add process created_at time to procstat input.\n- [#7022](https://github.com/influxdata/telegraf/pull/7022): Add support for credentials file to nats_consumer and nats output.\n- [#7065](https://github.com/influxdata/telegraf/pull/7065): Add additional tags and fields to apcupsd.\n- [#7084](https://github.com/influxdata/telegraf/pull/7084): Add RabbitMQ slave_nodes and synchronized_slave_nodes metrics.\n- [#7089](https://github.com/influxdata/telegraf/pull/7089): Allow globs in FPM unix socket paths.\n- [#7071](https://github.com/influxdata/telegraf/pull/7071): Add non-cumulative histogram to histogram aggregator.\n- [#6969](https://github.com/influxdata/telegraf/pull/6969): Add label and field selectors to prometheus input k8s discovery.\n- [#7049](https://github.com/influxdata/telegraf/pull/7049): Add support for converting tag or field to measurement in converter processor.\n- [#7103](https://github.com/influxdata/telegraf/pull/7103): Add volume_mount_point to DatabaseIO query in sqlserver input.\n- [#7142](https://github.com/influxdata/telegraf/pull/7142): Add topic tag options to kafka output.\n- [#7141](https://github.com/influxdata/telegraf/pull/7141): Add support for setting InfluxDB retention policy using tag.\n- [#7163](https://github.com/influxdata/telegraf/pull/7163): Add Database IO Tempdb per Azure DB to sqlserver input.\n- [#7150](https://github.com/influxdata/telegraf/pull/7150): Add option for explicitly including queries in sqlserver input.\n- [#7173](https://github.com/influxdata/telegraf/pull/7173): Add support for GNMI DecimalVal type to cisco_telemetry_gnmi.\n\n### Bug Fixes\n\n- [#6397](https://github.com/influxdata/telegraf/issues/6397): Fix conversion to floats in AzureDBResourceStats query in the sqlserver input.\n- [#6867](https://github.com/influxdata/telegraf/issues/6867): Fix case sensitive collation in sqlserver input.\n- [#7005](https://github.com/influxdata/telegraf/pull/7005): Search for chronyc only when chrony input plugin is enabled.\n- [#2280](https://github.com/influxdata/telegraf/issues/2280): Fix request to InfluxDB Listener failing with EOF.\n- [#6124](https://github.com/influxdata/telegraf/issues/6124): Fix InfluxDB listener to continue parsing after error.\n- [#7133](https://github.com/influxdata/telegraf/issues/7133): Fix log rotation to use actual file size instead of bytes written.\n- [#7103](https://github.com/influxdata/telegraf/pull/7103): Fix several issues with DatabaseIO query in sqlserver input.\n- [#7119](https://github.com/influxdata/telegraf/pull/7119): Fix internal metrics for output split into multiple lines.\n- [#7021](https://github.com/influxdata/telegraf/pull/7021): Fix schedulers query compatibility with pre SQL-2016.\n- [#7182](https://github.com/influxdata/telegraf/pull/7182): Set headers on influxdb_listener ping URL.\n- [#7165](https://github.com/influxdata/telegraf/issues/7165): Fix url encoding of job names in jenkins input plugin.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n`community@influxdata.com`.\n\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\n[version 2.1][v2.1].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Telegraf\n\nThere are many ways to get involved in the Telegraf project! From opening\nissues, creating pull requests, to joining the conversation in Slack. We would\nlove to see you contribute your expertise and join our community. To get started\nreview this document to learn best practices.\n\n![tiger](assets/GopherAndTiger.png \"tiger\")\n\n## Opening Issues\n\n### Bug reports\n\nBefore you file an issue, please search existing issues in case it has already\nbeen filed, or perhaps even fixed. If you file an issue, please ensure you\ninclude all the requested details (e.g. Telegraf config, logs, platform, etc.)\n\nPlease note that issues are not the place to file general support requests such\nas \"How do I use the mongoDB plugin?\" Questions of this nature should be sent\nto the [Community Slack][slack] or [Community Page][forum], not filed as issues.\n\n[slack]: https://influxdata.com/slack\n[forum]: https://community.influxdata.com/\n\n### Feature requests\n\nWe really like to receive feature requests as it helps us prioritize our work.\nBefore you file a feature request, please search existing issues, you can filter\nissues that have the label `feature request`. Please be clear about your\nrequirements and goals, help us to understand what you would like to see added\nto Telegraf with examples and the reasons why it is important to you. If you\nfind your feature request already exists as a Github issue please indicate your\nsupport for that feature by using the \"thumbs up\" reaction.\n\n### Support questions\n\nWe recommend posting support questions in our [Community Slack][slack] or\n[Community Page][forum], we have a lot of talented community members there who\ncould help answer your question more quickly.\n\n## Contributing code\n\n### AI Generated Code\n\nWe currently cannot accept AI generated code contributions. Code contributed\nshould be your own per the CLA.\n\n### Creating a pull request\n\n1. [Sign the CLA][cla].\n2. Open a [new issue][] to discuss the changes you would like to make.  This is\n   not strictly required but it may help reduce the amount of rework you need\n   to do later.\n3. Make changes or write plugin using the guidelines in the following\n   documents:\n   - [Input Plugins][inputs]\n   - [Processor Plugins][processors]\n   - [Aggregator Plugins][aggregators]\n   - [Output Plugins][outputs]\n4. Ensure you have added proper unit tests and documentation.\n5. Open a new [pull request][].\n6. The pull request title needs to follow [conventional commit format][semcommit]\n\n> [!NOTE]\n> If you have a pull request with only one commit, then that commit needs to\n> follow the conventional commit format or the `Semantic Pull Request` check\n> will fail. This is because github will use the pull request title if there are\n> multiple commits, but if there is only one commit it will use it instead.\n\n[semcommit]: https://www.conventionalcommits.org/en/v1.0.0/#summary\n\n### When will your contribution get released?\n\nWe have two kinds of releases: patch releases, which happen every few weeks, and\nfeature releases, which happen once a quarter. If your fix is a bug fix, it will\nbe released in the next patch release after it is merged to master. If your\nrelease is a new plugin or other feature, it will be released in the next\nquarterly release after it is merged to master. Quarterly releases are on the\nthird Wednesday of March, June, September, and December.\n\n### Contributing an External Plugin\n\nInput, output, and processor plugins written for internal Telegraf can be run as\nexternally-compiled plugins through the [Execd Input](/plugins/inputs/execd),\n[Execd Output](/plugins/outputs/execd), and\n[Execd Processor](/plugins/processors/execd) Plugins without having to change\nthe plugin code.\n\nFollow the guidelines of how to integrate your plugin with the\n[Execd Go Shim](/plugins/common/shim) to easily compile it as a separate app and\nrun it with the respective `execd` plugin.\nCheck out our [guidelines](/docs/EXTERNAL_PLUGINS.md#external-plugin-guidelines)\non how to build and set up your external plugins to run with `execd`.\n\n## Security Vulnerability Reporting\n\nInfluxData takes security and our users' trust very seriously. If you believe\nyou have found a security issue in any of our open source projects, please\nresponsibly disclose it by contacting `security@influxdata.com`. More details\nabout security vulnerability reporting, including our GPG key,\n[can be found here][gpg_key].\n\n[gpg_key]: https://www.influxdata.com/how-to-report-security-vulnerabilities/\n\n## Common development tasks\n\n**Adding a dependency:**\n\nTelegraf uses Go modules. Assuming you can already build the project, run this\nin the telegraf directory:\n\n1. `go get github.com/[dependency]/[new-package]`\n\n**Before opening a PR:**\n\nBefore opening a pull request you should run the following checks locally to\nmake sure the CI will pass.\n\n```shell\nmake lint\nmake check\nmake check-deps\nmake test\nmake docs\n```\n\n**Execute integration tests:**\n\n(Optional)\n\nTo run only the integration tests use:\n\n```shell\nmake test-integration\n```\n\nTo run the full test suite use:\n\n```shell\nmake test-all\n```\n\n### For more developer resources\n\n- [Code Style][codestyle]\n- [Deprecation][deprecation]\n- [Logging][logging]\n- [Metric Format Changes][metricformat]\n- [Packaging][packaging]\n- [Profiling][profiling]\n- [Reviews][reviews]\n- [Sample Config][sample config]\n- [Code of Conduct][code of conduct]\n\n[cla]: https://www.influxdata.com/legal/cla/\n[new issue]: https://github.com/influxdata/telegraf/issues/new/choose\n[pull request]: https://github.com/influxdata/telegraf/compare\n[inputs]: /docs/INPUTS.md\n[processors]: /docs/PROCESSORS.md\n[aggregators]: /docs/AGGREGATORS.md\n[outputs]: /docs/OUTPUTS.md\n[codestyle]: /docs/developers/CODE_STYLE.md\n[deprecation]: /docs/developers/DEPRECATION.md\n[logging]: /docs/developers/LOGGING.md\n[metricformat]: /docs/developers/METRIC_FORMAT_CHANGES.md\n[packaging]: /docs/developers/PACKAGING.md\n[profiling]: /docs/developers/PROFILING.md\n[reviews]: /docs/developers/REVIEWS.md\n[sample config]: /docs/developers/SAMPLE_CONFIG.md\n[code of conduct]: /CODE_OF_CONDUCT.md\n"
  },
  {
    "path": "EXTERNAL_PLUGINS.md",
    "content": "<!-- markdownlint-disable MD013 -->\n# External Plugins\n\nThis is a list of plugins that can be compiled outside of Telegraf and used via\nthe `execd` [input](/plugins/inputs/execd), [output](/plugins/outputs/execd), or\n[processor](/plugins/processors/execd).\nCheck out the [external plugin documentation](/docs/EXTERNAL_PLUGINS.md) for\nmore information on writing and contributing a plugin.\n\nPull requests welcome.\n\n## Inputs\n\n- [awsalarms](https://github.com/vipinvkmenon/awsalarms) - Simple plugin to gather/monitor alarms generated  in AWS.\n- [octoprint](https://github.com/BattleBas/octoprint-telegraf-plugin) - Gather 3d print information from the octoprint API.\n- [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.\n- [open-hardware-monitor](https://github.com/marianob85/open_hardware_monitor-telegraf-plugin) - Gather sensors data provided by [Open Hardware Monitor](http://openhardwaremonitor.org)\n- [plex](https://github.com/russorat/telegraf-webhooks-plex) - Listens for events from Plex Media Server [Webhooks](https://support.plex.tv/articles/115002267687-webhooks/).\n- [rand](https://github.com/ssoroka/rand) - Generate random numbers\n- [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/).\n- [systemd-timings](https://github.com/pdmorrow/telegraf-execd-systemd-timings) - Gather systemd boot and unit timestamp metrics.\n- [twitter](https://github.com/inabagumi/twitter-telegraf-plugin) - Gather account information from Twitter accounts\n- [youtube](https://github.com/inabagumi/youtube-telegraf-plugin) - Gather account information from YouTube channels\n- [Big Blue Button](https://github.com/bigblueswarm/bigbluebutton-telegraf-plugin) - Gather meetings information from [Big Blue Button](https://bigbluebutton.org/) server\n- [dnsmasq](https://github.com/machinly/dnsmasq-telegraf-plugin) - Gather dnsmasq statistics from dnsmasq\n- [ldap_org and ds389](https://github.com/falon/CSI-telegraf-plugins) - Gather statistics from 389ds and from LDAP trees.\n- [x509_crl](https://github.com/jcgonnard/telegraf-input-x590crl) - Gather information from your X509 CRL files\n- [s7comm](https://github.com/nicolasme/s7comm) - Gather information from Siemens PLC\n- [net_irtt](https://github.com/iAnatoly/telegraf-input-net_irtt) - Gather information from IRTT network test\n- [dht_sensor](https://github.com/iAnatoly/telegraf-input-dht_sensor) - Gather temperature and humidity from DHTXX sensors\n- [oracle](https://github.com/bonitoo-io/telegraf-input-oracle) - Gather the statistic data from Oracle RDBMS\n- [db2](https://github.com/bonitoo-io/telegraf-input-db2) - Gather the statistic data from DB2 RDBMS\n- [apt](https://github.com/x70b1/telegraf-apt) - Check Debian for package updates.\n- [knot](https://github.com/x70b1/telegraf-knot) - Collect stats from Knot DNS.\n- [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\n- [hwinfo](https://github.com/zachstence/hwinfo-telegraf-plugin) - Gather Windows system hardware information from [HWiNFO](https://www.hwinfo.com/)\n- [libvirt](https://gitlab.com/warrenio/tools/telegraf-input-libvirt) - Gather libvirt domain stats, based on a historical Telegraf implementation [libvirt](https://libvirt.org/)\n- [bacnet](https://github.com/JurajMarcin/telegraf-bacnet) - Gather statistics from BACnet devices, with support for device discovery and Change of Value subscriptions\n- [tado](https://github.com/zoeimogen/tado-telegraf-plugin) - Gather zone temperature settings and current temperature/humidity readings from Tado\n- [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\n\n## Outputs\n\n- [kinesis](https://github.com/morfien101/telegraf-output-kinesis) - Aggregation and compression of metrics to send Amazon Kinesis.\n- [firehose](https://github.com/muhlba91/telegraf-output-kinesis-data-firehose) - Sends metrics in batches to Amazon Kinesis Data Firehose.\n- [playfab](https://github.com/dgkanatsios/telegraftoplayfab) - Sends metrics to [Azure PlayFab](https://learn.microsoft.com/en-us/gaming/playfab/).\n\n## Processors\n\n- [geoip](https://github.com/a-bali/telegraf-geoip) - Add GeoIP information to IP addresses.\n- [metadata](https://github.com/lawdt/metadata) - Appends metadata gathered from Openstack to metrics.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-2025 InfluxData Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "ifneq (,$(filter $(OS),Windows_NT Windows))\n\tEXEEXT=.exe\nendif\n\ncat := $(if $(filter $(OS),sh.exe),type,cat)\nnext_version := $(shell $(cat) build_version.txt)\ntag := $(shell git describe --exact-match --tags 2>/dev/null)\n\nbranch := $(shell git rev-parse --abbrev-ref HEAD)\ncommit := $(shell git rev-parse --short=8 HEAD)\n\nifdef NIGHTLY\n\tversion := $(next_version)\n\trpm_version := nightly\n\trpm_iteration := 0\n\tdeb_version := nightly\n\tdeb_iteration := 0\n\ttar_version := nightly\nelse ifeq ($(tag),)\n\tversion := $(next_version)\n\trpm_version := $(version)~$(commit)-0\n\trpm_iteration := 0\n\tdeb_version := $(version)~$(commit)-0\n\tdeb_iteration := 0\n\ttar_version := $(version)~$(commit)\nelse ifneq ($(findstring -rc,$(tag)),)\n\tversion := $(word 1,$(subst -, ,$(tag)))\n\tversion := $(version:v%=%)\n\trc := $(word 2,$(subst -, ,$(tag)))\n\trpm_version := $(version)-0.$(rc)\n\trpm_iteration := 0.$(subst rc,,$(rc))\n\tdeb_version := $(version)~$(rc)-1\n\tdeb_iteration := 0\n\ttar_version := $(version)~$(rc)\nelse\n\tversion := $(tag:v%=%)\n\trpm_version := $(version)-1\n\trpm_iteration := 1\n\tdeb_version := $(version)-1\n\tdeb_iteration := 1\n\ttar_version := $(version)\nendif\n\nMAKEFLAGS += --no-print-directory\nGOOS ?= $(shell go env GOOS)\nGOARCH ?= $(shell go env GOARCH)\nHOSTGO := env -u GOOS -u GOARCH -u GOARM -- go\nINTERNAL_PKG=github.com/influxdata/telegraf/internal\nLDFLAGS := $(LDFLAGS) -X $(INTERNAL_PKG).Commit=$(commit) -X $(INTERNAL_PKG).Branch=$(branch)\nifneq ($(tag),)\n\tLDFLAGS += -X $(INTERNAL_PKG).Version=$(version)\nelse\n\tLDFLAGS += -X $(INTERNAL_PKG).Version=$(version)-$(commit)\nendif\n\n# Go built-in race detector works only for 64 bits architectures.\nifneq ($(GOARCH), 386)\n\t# Resolve macOS issue with Xcode 15 when running in race detector mode\n\t# https://github.com/golang/go/issues/61229\n\tifeq ($(GOOS), darwin)\n\t\trace_detector := -race -ldflags=-extldflags=-Wl,-ld_classic\n\telse\n\t\trace_detector := -race\n\tendif\nendif\n\n\nGOFILES ?= $(shell git ls-files '*.go')\nGOFMT ?= $(shell gofmt -l -s $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)))\n\nprefix ?= /usr/local\nbindir ?= $(prefix)/bin\nsysconfdir ?= $(prefix)/etc\nlocalstatedir ?= $(prefix)/var\npkgdir ?= build/dist\n\n.PHONY: all\nall: deps docs telegraf\n\n.PHONY: help\nhelp:\n\t@echo 'Targets:'\n\t@echo '  all          - download dependencies and compile telegraf binary'\n\t@echo '  config       - generate the config from current repo state'\n\t@echo '  deps         - download dependencies'\n\t@echo '  docs         - embed sample-configurations into READMEs'\n\t@echo '  telegraf     - compile telegraf binary'\n\t@echo '  test         - run short unit tests'\n\t@echo '  fmt          - format source files'\n\t@echo '  tidy         - tidy go modules'\n\t@echo '  lint         - run linter'\n\t@echo '  lint-branch  - run linter on changes in current branch since master'\n\t@echo '  lint-install - install linter'\n\t@echo '  check-deps   - check docs/LICENSE_OF_DEPENDENCIES.md'\n\t@echo '  clean        - delete build artifacts'\n\t@echo '  package      - build all supported packages, override include_packages to only build a subset'\n\t@echo '                 e.g.: make package include_packages=\"amd64.deb\"'\n\t@echo ''\n\t@echo 'Possible values for include_packages variable'\n\t@$(foreach package,$(include_packages),echo \"  $(package)\";)\n\t@echo ''\n\t@echo 'Resulting package name format (where arch will be the arch of the package):'\n\t@echo '   telegraf_$(deb_version)_arch.deb'\n\t@echo '   telegraf-$(rpm_version).arch.rpm'\n\t@echo '   telegraf-$(tar_version)_arch.tar.gz'\n\t@echo '   telegraf-$(tar_version)_arch.zip'\n\n\n.PHONY: deps\ndeps:\n\tgo mod download -x\n\n.PHONY: version\nversion:\n\t@echo $(version)-$(commit)\n\nbuild_tools:\n\t$(HOSTGO) build -o ./tools/custom_builder/custom_builder$(EXEEXT) ./tools/custom_builder\n\t$(HOSTGO) build -o ./tools/license_checker/license_checker$(EXEEXT) ./tools/license_checker\n\t$(HOSTGO) build -o ./tools/readme_config_includer/generator$(EXEEXT) ./tools/readme_config_includer/generator.go\n\t$(HOSTGO) build -o ./tools/config_includer/generator$(EXEEXT) ./tools/config_includer/generator.go\n\t$(HOSTGO) build -o ./tools/readme_linter/readme_linter$(EXEEXT) ./tools/readme_linter\n\nembed_readme_%:\n\tgo generate -run=\"tools/config_includer/generator\" ./plugins/$*/...\n\tgo generate -run=\"tools/readme_config_includer/generator\" ./plugins/$*/...\n\n.PHONY: config\nconfig:\n\t@echo \"generating default config\"\n\tgo run ./cmd/telegraf config > etc/telegraf.conf\n\n.PHONY: docs\ndocs: build_tools embed_readme_common embed_readme_inputs embed_readme_outputs embed_readme_processors embed_readme_aggregators embed_readme_secretstores\n\n.PHONY: build\nbuild:\n\tCGO_ENABLED=0 go build -tags \"$(BUILDTAGS)\" -ldflags \"$(LDFLAGS)\" ./cmd/telegraf\n\n.PHONY: telegraf\ntelegraf: build\n\n# Used by dockerfile builds\n.PHONY: go-install\ngo-install:\n\tgo install -mod=mod -ldflags \"-w -s $(LDFLAGS)\" ./cmd/telegraf\n\n.PHONY: test\ntest:\n\tgo test -short $(race_detector) ./...\n\n.PHONY: test-integration\ntest-integration:\n\tgo test -run Integration $(race_detector) ./...\n\n.PHONY: fmt\nfmt:\n\t@gofmt -s -w $(filter-out plugins/parsers/influx/machine.go, $(GOFILES))\n\n.PHONY: fmtcheck\nfmtcheck:\n\t@if [ ! -z \"$(GOFMT)\" ]; then \\\n\t\techo \"[ERROR] gofmt has found errors in the following files:\"  ; \\\n\t\techo \"$(GOFMT)\" ; \\\n\t\techo \"\" ;\\\n\t\techo \"Run make fmt to fix them.\" ; \\\n\t\texit 1 ;\\\n\tfi\n\n.PHONY: vet\nvet:\n\t@echo 'go vet $$(go list ./... | grep -v ./plugins/parsers/influx)'\n\t@go vet $$(go list ./... | grep -v ./plugins/parsers/influx) ; if [ $$? -ne 0 ]; then \\\n\t\techo \"\"; \\\n\t\techo \"go vet has found suspicious constructs. Please remediate any reported errors\"; \\\n\t\techo \"to fix them before submitting code for review.\"; \\\n\t\texit 1; \\\n\tfi\n\n.PHONY: lint-install\nlint-install:\n\t@echo \"Installing golangci-lint\"\n\tgo install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2\n\n\t@echo \"Installing markdownlint\"\n\tnpm install -g markdownlint-cli\n\n.PHONY: lint\nlint:\n\t@which golangci-lint >/dev/null 2>&1 || { \\\n\t\techo \"golangci-lint not found, please run: make lint-install\"; \\\n\t\texit 1; \\\n\t}\n\tgolangci-lint run\n\n\t@which markdownlint >/dev/null 2>&1 || { \\\n\t\techo \"markdownlint not found, please run: make lint-install\"; \\\n\t\texit 1; \\\n\t}\n\tmarkdownlint .\n\n.PHONY: lint-branch\nlint-branch:\n\t@which golangci-lint >/dev/null 2>&1 || { \\\n\t\techo \"golangci-lint not found, please run: make lint-install\"; \\\n\t\texit 1; \\\n\t}\n\tgolangci-lint run\n\n.PHONY: vuln-install\nvuln-install:\n\t@echo \"Installing govulncheck\"\n\tgo install golang.org/x/vuln/cmd/govulncheck@latest\n\n.PHONY: vuln\nvuln:\n\t@which govulncheck >/dev/null 2>&1 || { \\\n\t\techo \"govulncheck not found, please run: make vuln-install\"; \\\n\t\texit 1; \\\n\t}\n\tgovulncheck ./...\n\n.PHONY: tidy\ntidy:\n\tgo mod verify\n\tgo mod tidy\n\t@if ! git diff --quiet go.mod go.sum; then \\\n\t\techo \"please run go mod tidy and check in changes, you might have to use the same version of Go as the CI\"; \\\n\t\texit 1; \\\n\tfi\n\n.PHONY: check\ncheck: fmtcheck vet\n\n.PHONY: test-all\ntest-all: fmtcheck vet\n\tgo test $(race_detector) ./...\n\n.PHONY: check-deps\ncheck-deps:\n\t./scripts/check-deps.sh\n\n.PHONY: clean\nclean:\n\trm -f telegraf\n\trm -f telegraf.exe\n\trm -f etc/telegraf.conf\n\trm -rf build\n\trm -rf cmd/telegraf/resource.syso\n\trm -rf cmd/telegraf/versioninfo.json\n\trm -rf tools/config_includer/generator\n\trm -rf tools/config_includer/generator.exe\n\trm -rf tools/custom_builder/custom_builder\n\trm -rf tools/custom_builder/custom_builder.exe\n\trm -rf tools/license_checker/license_checker\n\trm -rf tools/license_checker/license_checker.exe\n\trm -rf tools/package_incus_test/package_incus_test\n\trm -rf tools/package_incus_test/package_incus_test.exe\n\trm -rf tools/readme_config_includer/generator\n\trm -rf tools/readme_config_includer/generator.exe\n\trm -rf tools/readme_linter/readme_linter\n\trm -rf tools/readme_linter/readme_linter.exe\n\n.PHONY: docker-image\ndocker-image:\n\tdocker build -f scripts/buster.docker -t \"telegraf:$(commit)\" .\n\nplugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl\n\tragel -Z -G2 $^ -o $@\n\n.PHONY: ci\nci:\n\tdocker build -t quay.io/influxdb/telegraf-ci:1.25.7 - < scripts/ci.docker\n\tdocker push quay.io/influxdb/telegraf-ci:1.25.7\n\n.PHONY: install\ninstall: $(buildbin)\n\t@mkdir -pv $(DESTDIR)$(bindir)\n\t@mkdir -pv $(DESTDIR)$(sysconfdir)\n\t@mkdir -pv $(DESTDIR)$(localstatedir)\n\t@if [ $(GOOS) != \"windows\" ]; then mkdir -pv $(DESTDIR)$(sysconfdir)/logrotate.d; fi\n\t@if [ $(GOOS) != \"windows\" ]; then mkdir -pv $(DESTDIR)$(localstatedir)/log/telegraf; fi\n\t@if [ $(GOOS) != \"windows\" ]; then mkdir -pv $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d; fi\n\t@cp -fv $(buildbin) $(DESTDIR)$(bindir)\n\t@if [ $(GOOS) != \"windows\" ]; then cp -fv etc/telegraf.conf $(DESTDIR)$(sysconfdir)/telegraf/telegraf.conf$(conf_suffix); fi\n\t@if [ $(GOOS) != \"windows\" ]; then cp -fv etc/logrotate.d/telegraf $(DESTDIR)$(sysconfdir)/logrotate.d; fi\n\t@if [ $(GOOS) = \"windows\" ]; then cp -fv etc/telegraf.conf $(DESTDIR)/telegraf.conf; fi\n\t@if [ $(GOOS) = \"linux\" ]; then mkdir -pv $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi\n\t@if [ $(GOOS) = \"linux\" ]; then cp -fv scripts/telegraf.service $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi\n\t@if [ $(GOOS) = \"linux\" ]; then cp -fv scripts/init.sh $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi\n\n# Telegraf build per platform.  This improves package performance by sharing\n# the bin between deb/rpm/tar packages over building directly into the package\n# directory.\n.PHONY: $(buildbin)\n$(buildbin):\n\techo $(GOOS)\n\t@mkdir -pv $(dir $@)\n\tCGO_ENABLED=0 go build -o $(dir $@) -tags \"$(BUILDTAGS)\" -ldflags \"$(LDFLAGS)\" ./cmd/telegraf\n\n# Define packages Telegraf supports, organized by architecture with a rule to echo the list to limit include_packages\n# e.g. make package include_packages=\"$(make amd64)\"\nmips += linux_mips.tar.gz mips.deb\n.PHONY: mips\nmips:\n\t@ echo $(mips)\nmipsel += mipsel.deb linux_mipsel.tar.gz\n.PHONY: mipsel\nmipsel:\n\t@ echo $(mipsel)\nloong64 += linux_loong64.tar.gz loong64.deb loongarch64.rpm\n.PHONY: loong64\nloong64:\n\t@ echo $(loong64)\narm64 += linux_arm64.tar.gz arm64.deb aarch64.rpm\n.PHONY: arm64\narm64:\n\t@ echo $(arm64)\namd64 += freebsd_amd64.tar.gz linux_amd64.tar.gz amd64.deb x86_64.rpm\n.PHONY: amd64\namd64:\n\t@ echo $(amd64)\narmel += linux_armel.tar.gz armel.rpm armel.deb\n.PHONY: armel\narmel:\n\t@ echo $(armel)\narmhf += linux_armhf.tar.gz freebsd_armv7.tar.gz armhf.deb armv6hl.rpm\n.PHONY: armhf\narmhf:\n\t@ echo $(armhf)\ns390x += linux_s390x.tar.gz s390x.deb s390x.rpm\n.PHONY: riscv64\nriscv64:\n\t@ echo $(riscv64)\nriscv64 += linux_riscv64.tar.gz riscv64.rpm riscv64.deb\n.PHONY: s390x\ns390x:\n\t@ echo $(s390x)\nppc64le += linux_ppc64le.tar.gz ppc64le.rpm ppc64el.deb\n.PHONY: ppc64le\nppc64le:\n\t@ echo $(ppc64le)\ni386 += freebsd_i386.tar.gz i386.deb linux_i386.tar.gz i386.rpm\n.PHONY: i386\ni386:\n\t@ echo $(i386)\nwindows += windows_i386.zip windows_amd64.zip windows_arm64.zip\n.PHONY: windows\nwindows:\n\t@ echo $(windows)\ndarwin-amd64 += darwin_amd64.tar.gz\n.PHONY: darwin-amd64\ndarwin-amd64:\n\t@ echo $(darwin-amd64)\n\ndarwin-arm64 += darwin_arm64.tar.gz\n.PHONY: darwin-arm64\ndarwin-arm64:\n\t@ echo $(darwin-arm64)\n\ninclude_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(armel) $(armhf) $(riscv64) $(loong64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64)\n\n.PHONY: package\npackage: docs config $(include_packages)\n\n.PHONY: $(include_packages)\n$(include_packages):\n\tif [ \"$(suffix $@)\" = \".zip\" ]; then go generate cmd/telegraf/telegraf_windows.go; fi\n\n\t@$(MAKE) install\n\t@mkdir -p $(pkgdir)\n\n\t@if [ \"$(suffix $@)\" = \".rpm\" ]; then \\\n\t\techo \"# DO NOT EDIT OR REMOVE\" > $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d/.ignore; \\\n\t\techo \"# This file prevents the rpm from changing permissions on this directory\" >> $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d/.ignore; \\\n\t\tfpm --force \\\n\t\t\t--log info \\\n\t\t\t--architecture $(basename $@) \\\n\t\t\t--input-type dir \\\n\t\t\t--output-type rpm \\\n\t\t\t--vendor InfluxData \\\n\t\t\t--url https://github.com/influxdata/telegraf \\\n\t\t\t--license MIT \\\n\t\t\t--maintainer support@influxdb.com \\\n\t\t\t--config-files /etc/telegraf/telegraf.conf \\\n\t\t\t--config-files /etc/telegraf/telegraf.d/.ignore \\\n\t\t\t--config-files /etc/logrotate.d/telegraf \\\n\t\t\t--after-install scripts/rpm/post-install.sh \\\n\t\t\t--before-install scripts/rpm/pre-install.sh \\\n\t\t\t--after-remove scripts/rpm/post-remove.sh \\\n\t\t\t--description \"Plugin-driven server agent for reporting metrics into InfluxDB.\" \\\n\t\t\t--depends coreutils \\\n\t\t\t--rpm-digest sha256 \\\n\t\t\t--rpm-posttrans scripts/rpm/post-install.sh \\\n\t\t\t--rpm-os ${GOOS} \\\n\t\t\t--rpm-tag \"Requires(pre): /usr/sbin/useradd\" \\\n\t\t\t--rpm-tag \"Recommends: influxdata-archive-keyring\" \\\n\t\t\t--name telegraf \\\n\t\t\t--version $(version) \\\n\t\t\t--iteration $(rpm_iteration) \\\n\t\t\t--chdir $(DESTDIR) \\\n\t\t\t--package $(pkgdir)/telegraf-$(rpm_version).$@ ;\\\n\telif [ \"$(suffix $@)\" = \".deb\" ]; then \\\n\t\tfpm --force \\\n\t\t\t--log info \\\n\t\t\t--architecture $(basename $@) \\\n\t\t\t--input-type dir \\\n\t\t\t--output-type deb \\\n\t\t\t--vendor InfluxData \\\n\t\t\t--url https://github.com/influxdata/telegraf \\\n\t\t\t--license MIT \\\n\t\t\t--maintainer support@influxdb.com \\\n\t\t\t--config-files /etc/telegraf/telegraf.conf.sample \\\n\t\t\t--config-files /etc/logrotate.d/telegraf \\\n\t\t\t--after-install scripts/deb/post-install.sh \\\n\t\t\t--before-install scripts/deb/pre-install.sh \\\n\t\t\t--after-remove scripts/deb/post-remove.sh \\\n\t\t\t--before-remove scripts/deb/pre-remove.sh \\\n\t\t\t--description \"Plugin-driven server agent for reporting metrics into InfluxDB.\" \\\n\t\t\t--deb-recommends \"influxdata-archive-keyring\" \\\n\t\t\t--name telegraf \\\n\t\t\t--version $(version) \\\n\t\t\t--iteration $(deb_iteration) \\\n\t\t\t--chdir $(DESTDIR) \\\n\t\t\t--package $(pkgdir)/telegraf_$(deb_version)_$@\t;\\\n\telif [ \"$(suffix $@)\" = \".zip\" ]; then \\\n\t\t(cd $(dir $(DESTDIR)) && zip -r - ./*) > $(pkgdir)/telegraf-$(tar_version)_$@ ;\\\n\telif [ \"$(suffix $@)\" = \".gz\" ]; then \\\n\t\ttar --owner 0 --group 0 -czvf $(pkgdir)/telegraf-$(tar_version)_$@ -C $(dir $(DESTDIR)) . ;\\\n\tfi\n\namd64.deb x86_64.rpm linux_amd64.tar.gz: export GOOS := linux\namd64.deb x86_64.rpm linux_amd64.tar.gz: export GOARCH := amd64\n\ni386.deb i386.rpm linux_i386.tar.gz: export GOOS := linux\ni386.deb i386.rpm linux_i386.tar.gz: export GOARCH := 386\n\narmel.deb armel.rpm linux_armel.tar.gz: export GOOS := linux\narmel.deb armel.rpm linux_armel.tar.gz: export GOARCH := arm\narmel.deb armel.rpm linux_armel.tar.gz: export GOARM := 5\n\narmhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOOS := linux\narmhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOARCH := arm\narmhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOARM := 6\n\narm64.deb aarch64.rpm linux_arm64.tar.gz: export GOOS := linux\narm64.deb aarch64.rpm linux_arm64.tar.gz: export GOARCH := arm64\narm64.deb aarch64.rpm linux_arm64.tar.gz: export GOARM := 7\n\nmips.deb linux_mips.tar.gz: export GOOS := linux\nmips.deb linux_mips.tar.gz: export GOARCH := mips\n\nmipsel.deb linux_mipsel.tar.gz: export GOOS := linux\nmipsel.deb linux_mipsel.tar.gz: export GOARCH := mipsle\n\nriscv64.deb riscv64.rpm linux_riscv64.tar.gz: export GOOS := linux\nriscv64.deb riscv64.rpm linux_riscv64.tar.gz: export GOARCH := riscv64\n\nloong64.deb loongarch64.rpm linux_loong64.tar.gz: export GOOS := linux\nloong64.deb loongarch64.rpm linux_loong64.tar.gz: export GOARCH := loong64\n\ns390x.deb s390x.rpm linux_s390x.tar.gz: export GOOS := linux\ns390x.deb s390x.rpm linux_s390x.tar.gz: export GOARCH := s390x\n\nppc64el.deb ppc64le.rpm linux_ppc64le.tar.gz: export GOOS := linux\nppc64el.deb ppc64le.rpm linux_ppc64le.tar.gz: export GOARCH := ppc64le\n\nfreebsd_amd64.tar.gz: export GOOS := freebsd\nfreebsd_amd64.tar.gz: export GOARCH := amd64\n\nfreebsd_i386.tar.gz: export GOOS := freebsd\nfreebsd_i386.tar.gz: export GOARCH := 386\n\nfreebsd_armv7.tar.gz: export GOOS := freebsd\nfreebsd_armv7.tar.gz: export GOARCH := arm\nfreebsd_armv7.tar.gz: export GOARM := 7\n\nwindows_amd64.zip: export GOOS := windows\nwindows_amd64.zip: export GOARCH := amd64\n\nwindows_arm64.zip: export GOOS := windows\nwindows_arm64.zip: export GOARCH := arm64\n\ndarwin_amd64.tar.gz: export GOOS := darwin\ndarwin_amd64.tar.gz: export GOARCH := amd64\n\ndarwin_arm64.tar.gz: export GOOS := darwin\ndarwin_arm64.tar.gz: export GOARCH := arm64\n\nwindows_i386.zip: export GOOS := windows\nwindows_i386.zip: export GOARCH := 386\n\nwindows_i386.zip windows_amd64.zip windows_arm64.zip: export prefix =\nwindows_i386.zip windows_amd64.zip windows_arm64.zip: export bindir = $(prefix)\nwindows_i386.zip windows_amd64.zip windows_arm64.zip: export sysconfdir = $(prefix)\nwindows_i386.zip windows_amd64.zip windows_arm64.zip: export localstatedir = $(prefix)\nwindows_i386.zip windows_amd64.zip windows_arm64.zip: export EXEEXT := .exe\n\n%.deb: export pkg := deb\n%.deb: export prefix := /usr\n%.deb: export conf_suffix := .sample\n%.deb: export sysconfdir := /etc\n%.deb: export localstatedir := /var\n%.rpm: export pkg := rpm\n%.rpm: export prefix := /usr\n%.rpm: export sysconfdir := /etc\n%.rpm: export localstatedir := /var\n%.tar.gz: export pkg := tar\n%.tar.gz: export prefix := /usr\n%.tar.gz: export sysconfdir := /etc\n%.tar.gz: export localstatedir := /var\n%.zip: export pkg := zip\n%.zip: export prefix := /\n\n%.deb %.rpm %.tar.gz %.zip: export DESTDIR = build/$(GOOS)-$(GOARCH)$(GOARM)-$(pkg)/telegraf-$(version)\n%.deb %.rpm %.tar.gz %.zip: export buildbin = build/$(GOOS)-$(GOARCH)$(GOARM)/telegraf$(EXEEXT)\n%.deb %.rpm %.tar.gz %.zip: export LDFLAGS = -w -s\n"
  },
  {
    "path": "README.md",
    "content": "# ![tiger](assets/TelegrafTigerSmall.png \"tiger\") Telegraf\n\n[![GoDoc](https://img.shields.io/badge/doc-reference-00ADD8.svg?logo=go)](https://godoc.org/github.com/influxdata/telegraf)\n[![Docker pulls](https://img.shields.io/docker/pulls/library/telegraf.svg)](https://hub.docker.com/_/telegraf/)\n[![Go Report Card](https://goreportcard.com/badge/github.com/influxdata/telegraf)](https://goreportcard.com/report/github.com/influxdata/telegraf)\n[![Circle CI](https://circleci.com/gh/influxdata/telegraf.svg?style=svg)](https://circleci.com/gh/influxdata/telegraf)\n\nTelegraf is an agent for collecting, processing, aggregating, and writing\nmetrics, logs, and other arbitrary data.\n\n* Offers a comprehensive suite of over 300 plugins, covering a wide range of\n  functionalities including system monitoring, cloud services, and message\n  passing\n* Enables the integration of user-defined code to collect, transform, and\n  transmit data efficiently\n* Compiles into a standalone static binary without any external dependencies,\n  ensuring a streamlined deployment process\n* Utilizes TOML for configuration, providing a user-friendly and unambiguous\n  setup experience\n* Developed with contributions from a diverse community of over 1,200\n  contributors\n\nUsers can choose plugins from a wide range of topics, including but not limited\nto:\n\n* Devices: [OPC UA][], [Modbus][]\n* Logs: [File][], [Tail][], [Directory Monitor][]\n* Messaging: [AMQP][], [Kafka][], [MQTT][]\n* Monitoring: [OpenTelemetry][], [Prometheus][]\n* Networking: [Cisco TelemetryMDT][], [gNMI][]\n* System monitoring: [CPU][], [Memory][], [Disk][], [Network][], [SMART][],\n  [Docker][], [Nvidia SMI][], etc.\n* Universal: [Exec][], [HTTP][], [HTTP Listener][], [SNMP][], [SQL][]\n* Windows: [Event Log][], [Management Instrumentation][],\n  [Performance Counters][]\n\n## 🔨 Installation\n\nFor binary builds, Docker images, RPM & DEB packages, and other builds of\nTelegraf, please see the [install guide](/docs/INSTALL_GUIDE.md).\n\nSee the [releases documentation](/docs/RELEASES.md) for details on versioning\nand when releases are made.\n\n## 💻 Usage\n\nUsers define a TOML configuration with the plugins and settings they wish to\nuse, then pass that configuration to Telegraf. The Telegraf agent then\ncollects data from inputs at each interval and sends data to outputs at each\nflush interval.\n\nFor a basic walkthrough see [quick start](/docs/QUICK_START.md).\n\n## 📖 Documentation\n\nFor a full list of documentation including tutorials, reference and other\nmaterial, start with the [/docs directory](/docs/README.md).\n\nAdditionally, each plugin has its own README that includes details about how to\nconfigure, use, and sometimes debug or troubleshoot. Look under the\n[/plugins directory](/plugins/) for specific plugins.\n\nHere are some commonly used documents:\n\n* [Changelog](/CHANGELOG.md)\n* [Configuration](/docs/CONFIGURATION.md)\n* [FAQ](/docs/FAQ.md)\n* [Releases](https://github.com/influxdata/telegraf/releases)\n* [Security](/SECURITY.md)\n\n## ❤️ Contribute\n\n[![Contribute](https://img.shields.io/badge/contribute-to_telegraf-blue.svg?logo=influxdb)](https://github.com/influxdata/telegraf/blob/master/CONTRIBUTING.md)\n\nWe love our community of over 1,200 contributors! Many of the plugins included\nin Telegraf were originally contributed by community members. Check out\nour [contributing guide](CONTRIBUTING.md) if you are interested in helping out.\nAlso, join us on our [Community Slack](https://influxdata.com/slack) or\n[Community Forums](https://community.influxdata.com/) if you have questions or\ncomments for our engineering teams.\n\nIf you are completely new to Telegraf and InfluxDB, you can also enroll for free\nat [InfluxDB university](https://www.influxdata.com/university/) to take courses\nto learn more.\n\n## ℹ️ Support\n\n[![Slack](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack)](https://www.influxdata.com/slack)\n[![Forums](https://img.shields.io/badge/discourse-join_forums-blue.svg?logo=discourse)](https://community.influxdata.com/)\n\nPlease use the [Community Slack](https://influxdata.com/slack) or\n[Community Forums](https://community.influxdata.com/) if you have questions or\ncomments for our engineering teams. GitHub issues are limited to actual issues\nand feature requests only.\n\n## 📜 License\n\n[![MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/influxdata/telegraf/blob/master/LICENSE)\n\n[OPC UA]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opcua\n[Modbus]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/modbus\n[File]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/file\n[Tail]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/tail\n[Directory Monitor]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/directory_monitor\n[AMQP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/amqp_consumer\n[Kafka]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kafka_consumer\n[MQTT]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mqtt_consumer\n[OpenTelemetry]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opentelemetry\n[Prometheus]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/prometheus\n[Cisco TelemetryMDT]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/cisco_telemetry_mdt\n[gNMI]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/gnmi\n[CPU]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/cpu\n[Memory]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mem\n[Disk]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/disk\n[Network]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/net\n[SMART]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/smartctl\n[Docker]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/docker\n[Nvidia SMI]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nvidia_smi\n[Exec]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/exec\n[HTTP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/http\n[HTTP Listener]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/http_listener_v2\n[SNMP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/snmp\n[SQL]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/sql\n[Event Log]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_eventlog\n[Management Instrumentation]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_wmi\n[Performance Counters]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_perf_counters\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Reporting a Vulnerability\n\nInfluxData takes security and our users' trust seriously. If you believe you\nhave found a security issue in any of our open source projects, please\nresponsibly disclose it by contacting `security@influxdata.com`. More details\nabout security vulnerability reporting can be found on the\n[InfluxData How to Report Vulnerabilities page][InfluxData Security].\n\n[InfluxData Security]: https://www.influxdata.com/how-to-report-security-vulnerabilities/\n"
  },
  {
    "path": "accumulator.go",
    "content": "package telegraf\n\nimport (\n\t\"time\"\n)\n\n// Accumulator allows adding metrics to the processing flow.\ntype Accumulator interface {\n\t// AddFields adds a metric to the accumulator with the given measurement\n\t// name, fields, and tags (and timestamp). If a timestamp is not provided,\n\t// then the accumulator sets it to \"now\".\n\tAddFields(measurement string,\n\t\tfields map[string]interface{},\n\t\ttags map[string]string,\n\t\tt ...time.Time)\n\n\t// AddGauge is the same as AddFields, but will add the metric as a \"Gauge\" type\n\tAddGauge(measurement string,\n\t\tfields map[string]interface{},\n\t\ttags map[string]string,\n\t\tt ...time.Time)\n\n\t// AddCounter is the same as AddFields, but will add the metric as a \"Counter\" type\n\tAddCounter(measurement string,\n\t\tfields map[string]interface{},\n\t\ttags map[string]string,\n\t\tt ...time.Time)\n\n\t// AddSummary is the same as AddFields, but will add the metric as a \"Summary\" type\n\tAddSummary(measurement string,\n\t\tfields map[string]interface{},\n\t\ttags map[string]string,\n\t\tt ...time.Time)\n\n\t// AddHistogram is the same as AddFields, but will add the metric as a \"Histogram\" type\n\tAddHistogram(measurement string,\n\t\tfields map[string]interface{},\n\t\ttags map[string]string,\n\t\tt ...time.Time)\n\n\t// AddMetric adds a metric to the accumulator.\n\tAddMetric(Metric)\n\n\t// SetPrecision sets the timestamp rounding precision. All metrics\n\t// added to the accumulator will have their timestamp rounded to the\n\t// nearest multiple of precision.\n\tSetPrecision(precision time.Duration)\n\n\t// Report an error.\n\tAddError(err error)\n\n\t// Upgrade to a TrackingAccumulator with space for maxTracked\n\t// metrics/batches.\n\tWithTracking(maxTracked int) TrackingAccumulator\n}\n\n// TrackingID uniquely identifies a tracked metric group\ntype TrackingID uint64\n\ntype TrackingData interface {\n\t// ID is the TrackingID\n\tID() TrackingID\n\n\t// RefCount is the number of tracking metrics still persistent and referencing this tracking ID\n\tRefCount() int32\n}\n\n// DeliveryInfo provides the results of a delivered metric group.\ntype DeliveryInfo interface {\n\t// ID is the TrackingID\n\tID() TrackingID\n\n\t// Delivered returns true if the metric was processed successfully.\n\tDelivered() bool\n}\n\n// TrackingAccumulator is an Accumulator that provides a signal when the\n// metric has been fully processed.  Sending more metrics than the accumulator\n// has been allocated for without reading status from the Accepted or Rejected\n// channels is an error.\ntype TrackingAccumulator interface {\n\tAccumulator\n\n\t// Add the Metric and arrange for tracking feedback after processing.\n\tAddTrackingMetric(m Metric) TrackingID\n\n\t// Add a group of Metrics and arrange for a signal when the group has been\n\t// processed.\n\tAddTrackingMetricGroup(group []Metric) TrackingID\n\n\t// Delivered returns a channel that will contain the tracking results.\n\tDelivered() <-chan DeliveryInfo\n}\n"
  },
  {
    "path": "agent/README.md",
    "content": "# Agent\n\nFor a complete list of configuration options and details about the agent, please\nsee the [configuration][] document's agent section.\n\n[configuration]: ../docs/CONFIGURATION.md#agent\n"
  },
  {
    "path": "agent/accumulator.go",
    "content": "package agent\n\nimport (\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\ntype MetricMaker interface {\n\tLogName() string\n\tMakeMetric(m telegraf.Metric) telegraf.Metric\n\tLog() telegraf.Logger\n}\n\ntype accumulator struct {\n\tmaker     MetricMaker\n\tmetrics   chan<- telegraf.Metric\n\tprecision time.Duration\n}\n\nfunc NewAccumulator(\n\tmaker MetricMaker,\n\tmetrics chan<- telegraf.Metric,\n) telegraf.Accumulator {\n\tacc := accumulator{\n\t\tmaker:     maker,\n\t\tmetrics:   metrics,\n\t\tprecision: time.Nanosecond,\n\t}\n\treturn &acc\n}\n\nfunc (ac *accumulator) AddFields(\n\tmeasurement string,\n\tfields map[string]interface{},\n\ttags map[string]string,\n\tt ...time.Time,\n) {\n\tac.addMeasurement(measurement, tags, fields, telegraf.Untyped, t...)\n}\n\nfunc (ac *accumulator) AddGauge(\n\tmeasurement string,\n\tfields map[string]interface{},\n\ttags map[string]string,\n\tt ...time.Time,\n) {\n\tac.addMeasurement(measurement, tags, fields, telegraf.Gauge, t...)\n}\n\nfunc (ac *accumulator) AddCounter(\n\tmeasurement string,\n\tfields map[string]interface{},\n\ttags map[string]string,\n\tt ...time.Time,\n) {\n\tac.addMeasurement(measurement, tags, fields, telegraf.Counter, t...)\n}\n\nfunc (ac *accumulator) AddSummary(\n\tmeasurement string,\n\tfields map[string]interface{},\n\ttags map[string]string,\n\tt ...time.Time,\n) {\n\tac.addMeasurement(measurement, tags, fields, telegraf.Summary, t...)\n}\n\nfunc (ac *accumulator) AddHistogram(\n\tmeasurement string,\n\tfields map[string]interface{},\n\ttags map[string]string,\n\tt ...time.Time,\n) {\n\tac.addMeasurement(measurement, tags, fields, telegraf.Histogram, t...)\n}\n\nfunc (ac *accumulator) AddMetric(m telegraf.Metric) {\n\tm.SetTime(m.Time().Round(ac.precision))\n\tif m := ac.maker.MakeMetric(m); m != nil {\n\t\tac.metrics <- m\n\t}\n}\n\nfunc (ac *accumulator) addMeasurement(\n\tmeasurement string,\n\ttags map[string]string,\n\tfields map[string]interface{},\n\ttp telegraf.ValueType,\n\tt ...time.Time,\n) {\n\tm := metric.New(measurement, tags, fields, ac.getTime(t), tp)\n\tif m := ac.maker.MakeMetric(m); m != nil {\n\t\tac.metrics <- m\n\t}\n}\n\n// AddError passes a runtime error to the accumulator.\n// The error will be tagged with the plugin name and written to the log.\nfunc (ac *accumulator) AddError(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\tac.maker.Log().Errorf(\"Error in plugin: %v\", err)\n}\n\nfunc (ac *accumulator) SetPrecision(precision time.Duration) {\n\tac.precision = precision\n}\n\nfunc (ac *accumulator) getTime(t []time.Time) time.Time {\n\tvar timestamp time.Time\n\tif len(t) > 0 {\n\t\ttimestamp = t[0]\n\t} else {\n\t\ttimestamp = time.Now()\n\t}\n\treturn timestamp.Round(ac.precision)\n}\n\nfunc (ac *accumulator) WithTracking(maxTracked int) telegraf.TrackingAccumulator {\n\treturn &trackingAccumulator{\n\t\tAccumulator: ac,\n\t\tdelivered:   make(chan telegraf.DeliveryInfo, maxTracked),\n\t}\n}\n\ntype trackingAccumulator struct {\n\ttelegraf.Accumulator\n\tdelivered chan telegraf.DeliveryInfo\n}\n\nfunc (a *trackingAccumulator) AddTrackingMetric(m telegraf.Metric) telegraf.TrackingID {\n\tdm, id := metric.WithTracking(m, a.onDelivery)\n\ta.AddMetric(dm)\n\treturn id\n}\n\nfunc (a *trackingAccumulator) AddTrackingMetricGroup(group []telegraf.Metric) telegraf.TrackingID {\n\tdb, id := metric.WithGroupTracking(group, a.onDelivery)\n\tfor _, m := range db {\n\t\ta.AddMetric(m)\n\t}\n\treturn id\n}\n\nfunc (a *trackingAccumulator) Delivered() <-chan telegraf.DeliveryInfo {\n\treturn a.delivered\n}\n\nfunc (a *trackingAccumulator) onDelivery(info telegraf.DeliveryInfo) {\n\tselect {\n\tcase a.delivered <- info:\n\tdefault:\n\t\t// This is a programming error in the input.  More items were sent for\n\t\t// tracking than space requested.\n\t\tpanic(\"channel is full\")\n\t}\n}\n"
  },
  {
    "path": "agent/accumulator_test.go",
    "content": "package agent\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAddFields(t *testing.T) {\n\tmetrics := make(chan telegraf.Metric, 10)\n\tdefer close(metrics)\n\ta := NewAccumulator(&TestMetricMaker{}, metrics)\n\n\ttags := map[string]string{\"foo\": \"bar\"}\n\tfields := map[string]interface{}{\n\t\t\"usage\": float64(99),\n\t}\n\tnow := time.Now()\n\ta.AddCounter(\"acctest\", fields, tags, now)\n\n\ttestm := <-metrics\n\n\trequire.Equal(t, \"acctest\", testm.Name())\n\tactual, ok := testm.GetField(\"usage\")\n\n\trequire.True(t, ok)\n\trequire.InDelta(t, float64(99), actual, testutil.DefaultDelta)\n\n\tactual, ok = testm.GetTag(\"foo\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"bar\", actual)\n\n\ttm := testm.Time()\n\t// okay if monotonic clock differs\n\trequire.True(t, now.Equal(tm))\n\n\ttp := testm.Type()\n\trequire.Equal(t, telegraf.Counter, tp)\n}\n\nfunc TestAccAddError(t *testing.T) {\n\terrBuf := bytes.NewBuffer(nil)\n\tlogger.RedirectLogging(errBuf)\n\tdefer logger.RedirectLogging(os.Stderr)\n\n\tmetrics := make(chan telegraf.Metric, 10)\n\tdefer close(metrics)\n\ta := NewAccumulator(&TestMetricMaker{}, metrics)\n\n\ta.AddError(errors.New(\"foo\"))\n\ta.AddError(errors.New(\"bar\"))\n\ta.AddError(errors.New(\"baz\"))\n\n\terrs := bytes.Split(errBuf.Bytes(), []byte{'\\n'})\n\trequire.Len(t, errs, 4) // 4 because of trailing newline\n\trequire.Contains(t, string(errs[0]), \"TestPlugin\")\n\trequire.Contains(t, string(errs[0]), \"foo\")\n\trequire.Contains(t, string(errs[1]), \"TestPlugin\")\n\trequire.Contains(t, string(errs[1]), \"bar\")\n\trequire.Contains(t, string(errs[2]), \"TestPlugin\")\n\trequire.Contains(t, string(errs[2]), \"baz\")\n}\n\nfunc TestSetPrecision(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tunset     bool\n\t\tprecision time.Duration\n\t\ttimestamp time.Time\n\t\texpected  time.Time\n\t}{\n\t\t{\n\t\t\tname:      \"default precision is nanosecond\",\n\t\t\tunset:     true,\n\t\t\ttimestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC),\n\t\t\texpected:  time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC),\n\t\t},\n\t\t{\n\t\t\tname:      \"second interval\",\n\t\t\tprecision: time.Second,\n\t\t\ttimestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC),\n\t\t\texpected:  time.Date(2006, time.February, 10, 12, 0, 0, 0, time.UTC),\n\t\t},\n\t\t{\n\t\t\tname:      \"microsecond interval\",\n\t\t\tprecision: time.Microsecond,\n\t\t\ttimestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC),\n\t\t\texpected:  time.Date(2006, time.February, 10, 12, 0, 0, 82913000, time.UTC),\n\t\t},\n\t\t{\n\t\t\tname:      \"2 second precision\",\n\t\t\tprecision: 2 * time.Second,\n\t\t\ttimestamp: time.Date(2006, time.February, 10, 12, 0, 2, 4, time.UTC),\n\t\t\texpected:  time.Date(2006, time.February, 10, 12, 0, 2, 0, time.UTC),\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tmetrics := make(chan telegraf.Metric, 10)\n\n\t\t\ta := NewAccumulator(&TestMetricMaker{}, metrics)\n\t\t\tif !tt.unset {\n\t\t\t\ta.SetPrecision(tt.precision)\n\t\t\t}\n\n\t\t\ta.AddFields(\"acctest\",\n\t\t\t\tmap[string]interface{}{\"value\": float64(101)},\n\t\t\t\tmap[string]string{},\n\t\t\t\ttt.timestamp,\n\t\t\t)\n\n\t\t\ttestm := <-metrics\n\t\t\trequire.Equal(t, tt.expected, testm.Time())\n\n\t\t\tclose(metrics)\n\t\t})\n\t}\n}\n\nfunc TestAddTrackingMetricGroupEmpty(t *testing.T) {\n\tch := make(chan telegraf.Metric, 10)\n\tmetrics := make([]telegraf.Metric, 0)\n\tacc := NewAccumulator(&TestMetricMaker{}, ch).WithTracking(1)\n\n\tid := acc.AddTrackingMetricGroup(metrics)\n\n\tselect {\n\tcase tracking := <-acc.Delivered():\n\t\trequire.Equal(t, tracking.ID(), id)\n\tdefault:\n\t\tt.Fatal(\"empty group should be delivered immediately\")\n\t}\n}\n\ntype TestMetricMaker struct {\n}\n\nfunc (*TestMetricMaker) Name() string {\n\treturn \"TestPlugin\"\n}\n\nfunc (tm *TestMetricMaker) LogName() string {\n\treturn tm.Name()\n}\n\nfunc (*TestMetricMaker) MakeMetric(metric telegraf.Metric) telegraf.Metric {\n\treturn metric\n}\n\nfunc (*TestMetricMaker) Log() telegraf.Logger {\n\treturn logger.New(\"TestPlugin\", \"test\", \"\")\n}\n"
  },
  {
    "path": "agent/agent.go",
    "content": "package agent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/clock\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/influx\"\n)\n\n// Agent runs a set of plugins.\ntype Agent struct {\n\tConfig *config.Config\n}\n\n// NewAgent returns an Agent for the given Config.\nfunc NewAgent(cfg *config.Config) *Agent {\n\ta := &Agent{\n\t\tConfig: cfg,\n\t}\n\treturn a\n}\n\n// inputUnit is a group of input plugins and the shared channel they write to.\n//\n// ┌───────┐\n// │ Input │───┐\n// └───────┘   │\n// ┌───────┐   │     ______\n// │ Input │───┼──▶ ()_____)\n// └───────┘   │\n// ┌───────┐   │\n// │ Input │───┘\n// └───────┘\ntype inputUnit struct {\n\tdst    chan<- telegraf.Metric\n\tinputs []*models.RunningInput\n}\n\n//  ______     ┌───────────┐     ______\n// ()_____)──▶ │ Processor │──▶ ()_____)\n//             └───────────┘\n\ntype processorUnit struct {\n\tsrc       <-chan telegraf.Metric\n\tdst       chan<- telegraf.Metric\n\tprocessor *models.RunningProcessor\n}\n\n// aggregatorUnit is a group of Aggregators and their source and sink channels.\n// Typically, the aggregators write to a processor channel and pass the original\n// metrics to the output channel.  The sink channels may be the same channel.\n\n//                 ┌────────────┐\n//            ┌──▶ │ Aggregator │───┐\n//            │    └────────────┘   │\n//  ______    │    ┌────────────┐   │     ______\n// ()_____)───┼──▶ │ Aggregator │───┼──▶ ()_____)\n//            │    └────────────┘   │\n//            │    ┌────────────┐   │\n//            ├──▶ │ Aggregator │───┘\n//            │    └────────────┘\n//            │                           ______\n//            └────────────────────────▶ ()_____)\n\ntype aggregatorUnit struct {\n\tsrc         <-chan telegraf.Metric\n\taggC        chan<- telegraf.Metric\n\toutputC     chan<- telegraf.Metric\n\taggregators []*models.RunningAggregator\n}\n\n// outputUnit is a group of Outputs and their source channel.  Metrics on the\n// channel are written to all outputs.\n\n//                            ┌────────┐\n//                       ┌──▶ │ Output │\n//                       │    └────────┘\n//  ______     ┌─────┐   │    ┌────────┐\n// ()_____)──▶ │ Fan │───┼──▶ │ Output │\n//             └─────┘   │    └────────┘\n//                       │    ┌────────┐\n//                       └──▶ │ Output │\n//                            └────────┘\n\ntype outputUnit struct {\n\tsrc     <-chan telegraf.Metric\n\toutputs []*models.RunningOutput\n}\n\n// Run starts and runs the Agent until the context is done.\nfunc (a *Agent) Run(ctx context.Context) error {\n\tlog.Printf(\"I! [agent] Config: Interval:%s, Quiet:%#v, Hostname:%#v, \"+\n\t\t\"Flush Interval:%s\",\n\t\ttime.Duration(a.Config.Agent.Interval), a.Config.Agent.Quiet,\n\t\ta.Config.Agent.Hostname, time.Duration(a.Config.Agent.FlushInterval))\n\n\t// Set the default for processor skipping\n\tif a.Config.Agent.SkipProcessorsAfterAggregators == nil {\n\t\tmsg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! `\n\t\tmsg += `If you need the current default behavior, please explicitly set the option to 'false'!`\n\t\tlog.Print(\"W! [agent] \", color.YellowString(msg))\n\t\tskipProcessorsAfterAggregators := false\n\t\ta.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators\n\t}\n\n\tlog.Printf(\"D! [agent] Initializing plugins\")\n\tif err := a.InitPlugins(); err != nil {\n\t\treturn err\n\t}\n\n\tif a.Config.Persister != nil {\n\t\tlog.Printf(\"D! [agent] Initializing plugin states\")\n\t\tif err := a.initPersister(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := a.Config.Persister.Load(); err != nil {\n\t\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Print(\"I! [agent] State file does not exist... Skip restoring states...\")\n\t\t}\n\t}\n\n\tstartTime := time.Now()\n\n\tlog.Printf(\"D! [agent] Connecting outputs\")\n\tnext, ou, err := a.startOutputs(ctx, a.Config.Outputs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar apu []*processorUnit\n\tvar au *aggregatorUnit\n\tif len(a.Config.Aggregators) != 0 {\n\t\taggC := next\n\t\tif len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators {\n\t\t\taggC, apu, err = a.startProcessors(next, a.Config.AggProcessors)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tnext, au = a.startAggregators(aggC, next, a.Config.Aggregators)\n\t}\n\n\tvar pu []*processorUnit\n\tif len(a.Config.Processors) != 0 {\n\t\tnext, pu, err = a.startProcessors(next, a.Config.Processors)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tiu, err := a.startInputs(next, a.Config.Inputs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ta.runOutputs(ou)\n\t}()\n\n\tif au != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(apu)\n\t\t}()\n\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runAggregators(startTime, au)\n\t\t}()\n\t}\n\n\tif pu != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(pu)\n\t\t}()\n\t}\n\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ta.runInputs(ctx, startTime, iu)\n\t}()\n\n\twg.Wait()\n\n\tif a.Config.Persister != nil {\n\t\tlog.Printf(\"D! [agent] Persisting plugin states\")\n\t\tif err := a.Config.Persister.Store(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tlog.Printf(\"D! [agent] Stopped Successfully\")\n\treturn err\n}\n\n// InitPlugins runs the Init function on plugins.\nfunc (a *Agent) InitPlugins() error {\n\tfor _, input := range a.Config.Inputs {\n\t\t// Share the snmp translator setting with plugins that need it.\n\t\tif tp, ok := input.Input.(snmp.TranslatorPlugin); ok {\n\t\t\ttp.SetTranslator(a.Config.Agent.SnmpTranslator)\n\t\t}\n\t\terr := input.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not initialize input %s: %w\", input.LogName(), err)\n\t\t}\n\t}\n\tfor _, processor := range a.Config.Processors {\n\t\terr := processor.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not initialize processor %s: %w\", processor.LogName(), err)\n\t\t}\n\t}\n\tfor _, aggregator := range a.Config.Aggregators {\n\t\terr := aggregator.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not initialize aggregator %s: %w\", aggregator.LogName(), err)\n\t\t}\n\t}\n\tif !*a.Config.Agent.SkipProcessorsAfterAggregators {\n\t\tfor _, processor := range a.Config.AggProcessors {\n\t\t\terr := processor.Init()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"could not initialize processor %s: %w\", processor.LogName(), err)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, output := range a.Config.Outputs {\n\t\terr := output.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not initialize output %s: %w\", output.LogName(), err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// initPersister initializes the persister and registers the plugins.\nfunc (a *Agent) initPersister() error {\n\tif err := a.Config.Persister.Init(); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, input := range a.Config.Inputs {\n\t\tplugin, ok := input.Input.(telegraf.StatefulPlugin)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := input.LogName()\n\t\tid := input.ID()\n\t\tif err := a.Config.Persister.Register(id, plugin); err != nil {\n\t\t\treturn fmt.Errorf(\"could not register input %s: %w\", name, err)\n\t\t}\n\t}\n\n\tfor _, processor := range a.Config.Processors {\n\t\tvar plugin telegraf.StatefulPlugin\n\t\tif p, ok := processor.Processor.(processors.HasUnwrap); ok {\n\t\t\tplugin, ok = p.Unwrap().(telegraf.StatefulPlugin)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\tplugin, ok = processor.Processor.(telegraf.StatefulPlugin)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tname := processor.LogName()\n\t\tid := processor.ID()\n\t\tif err := a.Config.Persister.Register(id, plugin); err != nil {\n\t\t\treturn fmt.Errorf(\"could not register processor %s: %w\", name, err)\n\t\t}\n\t}\n\n\tfor _, aggregator := range a.Config.Aggregators {\n\t\tplugin, ok := aggregator.Aggregator.(telegraf.StatefulPlugin)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := aggregator.LogName()\n\t\tid := aggregator.ID()\n\t\tif err := a.Config.Persister.Register(id, plugin); err != nil {\n\t\t\treturn fmt.Errorf(\"could not register aggregator %s: %w\", name, err)\n\t\t}\n\t}\n\n\tfor _, processor := range a.Config.AggProcessors {\n\t\tplugin, ok := processor.Processor.(telegraf.StatefulPlugin)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := processor.LogName()\n\t\tid := processor.ID()\n\t\tif err := a.Config.Persister.Register(id, plugin); err != nil {\n\t\t\treturn fmt.Errorf(\"could not register aggregating processor %s: %w\", name, err)\n\t\t}\n\t}\n\n\tfor _, output := range a.Config.Outputs {\n\t\tplugin, ok := output.Output.(telegraf.StatefulPlugin)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := output.LogName()\n\t\tid := output.ID()\n\t\tif err := a.Config.Persister.Register(id, plugin); err != nil {\n\t\t\treturn fmt.Errorf(\"could not register output %s: %w\", name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (*Agent) startInputs(dst chan<- telegraf.Metric, inputs []*models.RunningInput) (*inputUnit, error) {\n\tlog.Printf(\"D! [agent] Starting service inputs\")\n\n\tunit := &inputUnit{\n\t\tdst: dst,\n\t}\n\n\tfor _, input := range inputs {\n\t\t// Service input plugins are not normally subject to timestamp\n\t\t// rounding except for when precision is set on the input plugin.\n\t\t//\n\t\t// This only applies to the accumulator passed to Start(), the\n\t\t// Gather() accumulator does apply rounding according to the\n\t\t// precision and interval agent/plugin settings.\n\t\tvar interval time.Duration\n\t\tvar precision time.Duration\n\t\tif input.Config.Precision != 0 {\n\t\t\tprecision = input.Config.Precision\n\t\t}\n\n\t\tacc := NewAccumulator(input, dst)\n\t\tacc.SetPrecision(getPrecision(precision, interval))\n\n\t\tif err := input.Start(acc); err != nil {\n\t\t\t// If the model tells us to remove the plugin we do so without error\n\t\t\tvar fatalErr *internal.FatalError\n\t\t\tif errors.As(err, &fatalErr) {\n\t\t\t\tlog.Printf(\"I! [agent] Failed to start %s, shutting down plugin: %s\", input.LogName(), err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstopRunningInputs(unit.inputs)\n\n\t\t\treturn nil, fmt.Errorf(\"starting input %s: %w\", input.LogName(), err)\n\t\t}\n\t\tif err := input.Probe(); err != nil {\n\t\t\t// Probe failures are non-fatal to the agent but should only remove the plugin\n\t\t\tlog.Printf(\"I! [agent] Failed to probe %s, shutting down plugin: %s\", input.LogName(), err)\n\t\t\tinput.Stop()\n\t\t\tcontinue\n\t\t}\n\t\tunit.inputs = append(unit.inputs, input)\n\t}\n\n\treturn unit, nil\n}\n\n// runInputs starts and triggers the periodic gather for Inputs.\n//\n// When the context is done the timers are stopped and this function returns\n// after all ongoing Gather calls complete.\nfunc (a *Agent) runInputs(ctx context.Context, startTime time.Time, unit *inputUnit) {\n\tvar wg sync.WaitGroup\n\tvar options []clock.Option\n\n\t// Initialize time rounding\n\tif a.Config.Agent.RoundInterval {\n\t\toptions = append(options, clock.WithAlignment(startTime))\n\t}\n\n\ttickers := make([]*clock.Ticker, 0, len(unit.inputs))\n\tfor _, input := range unit.inputs {\n\t\t// Overwrite agent interval if this plugin has its own.\n\t\tinterval := time.Duration(a.Config.Agent.Interval)\n\t\tif input.Config.Interval != 0 {\n\t\t\tinterval = input.Config.Interval\n\t\t}\n\n\t\t// Overwrite agent precision if this plugin has its own.\n\t\tprecision := time.Duration(a.Config.Agent.Precision)\n\t\tif input.Config.Precision != 0 {\n\t\t\tprecision = input.Config.Precision\n\t\t}\n\n\t\t// Overwrite agent collection_jitter if this plugin has its own.\n\t\tjitter := time.Duration(a.Config.Agent.CollectionJitter)\n\t\tif input.Config.CollectionJitter != 0 {\n\t\t\tjitter = input.Config.CollectionJitter\n\t\t}\n\n\t\t// Overwrite agent collection_offset if this plugin has its own.\n\t\toffset := time.Duration(a.Config.Agent.CollectionOffset)\n\t\tif input.Config.CollectionOffset != 0 {\n\t\t\toffset = input.Config.CollectionOffset\n\t\t}\n\n\t\tticker := clock.NewTicker(interval, jitter, offset, options...)\n\t\ttickers = append(tickers, ticker)\n\n\t\tacc := NewAccumulator(input, unit.dst)\n\t\tacc.SetPrecision(getPrecision(precision, interval))\n\n\t\twg.Add(1)\n\t\tgo func(input *models.RunningInput) {\n\t\t\tdefer wg.Done()\n\t\t\ta.gatherLoop(ctx, acc, input, ticker, interval)\n\t\t}(input)\n\t}\n\tdefer stopTickers(tickers)\n\twg.Wait()\n\n\tlog.Printf(\"D! [agent] Stopping service inputs\")\n\tstopRunningInputs(unit.inputs)\n\n\tclose(unit.dst)\n\tlog.Printf(\"D! [agent] Input channel closed\")\n}\n\n// testStartInputs is a variation of startInputs for use in --test and --once mode.\n// It differs by logging Start errors and returning only plugins successfully started.\nfunc (*Agent) testStartInputs(dst chan<- telegraf.Metric, inputs []*models.RunningInput) *inputUnit {\n\tlog.Printf(\"D! [agent] Starting service inputs\")\n\n\tunit := &inputUnit{\n\t\tdst: dst,\n\t}\n\n\tfor _, input := range inputs {\n\t\t// Service input plugins are not subject to timestamp rounding.\n\t\t// This only applies to the accumulator passed to Start(), the\n\t\t// Gather() accumulator does apply rounding according to the\n\t\t// precision agent setting.\n\t\tacc := NewAccumulator(input, dst)\n\t\tacc.SetPrecision(time.Nanosecond)\n\n\t\tif err := input.Start(acc); err != nil {\n\t\t\tlog.Printf(\"E! [agent] Starting input %s: %v\", input.LogName(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\tunit.inputs = append(unit.inputs, input)\n\t}\n\n\treturn unit\n}\n\n// testRunInputs is a variation of runInputs for use in --test and --once mode.\n// Instead of using a ticker to run the inputs they are called once immediately.\nfunc (a *Agent) testRunInputs(\n\tctx context.Context,\n\twait time.Duration,\n\tunit *inputUnit,\n) {\n\tvar wg sync.WaitGroup\n\n\tnul := make(chan telegraf.Metric)\n\tgo func() {\n\t\t//nolint:revive // empty block needed here\n\t\tfor range nul {\n\t\t}\n\t}()\n\n\tfor _, input := range unit.inputs {\n\t\twg.Add(1)\n\t\tgo func(input *models.RunningInput) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// Overwrite agent interval if this plugin has its own.\n\t\t\tinterval := time.Duration(a.Config.Agent.Interval)\n\t\t\tif input.Config.Interval != 0 {\n\t\t\t\tinterval = input.Config.Interval\n\t\t\t}\n\n\t\t\t// Overwrite agent precision if this plugin has its own.\n\t\t\tprecision := time.Duration(a.Config.Agent.Precision)\n\t\t\tif input.Config.Precision != 0 {\n\t\t\t\tprecision = input.Config.Precision\n\t\t\t}\n\n\t\t\t// Run plugins that require multiple gathers to calculate rate\n\t\t\t// and delta metrics twice.\n\t\t\tswitch input.Config.Name {\n\t\t\tcase \"cpu\", \"mongodb\", \"procstat\":\n\t\t\t\tnulAcc := NewAccumulator(input, nul)\n\t\t\t\tnulAcc.SetPrecision(getPrecision(precision, interval))\n\t\t\t\tif err := input.Input.Gather(nulAcc); err != nil {\n\t\t\t\t\tnulAcc.AddError(err)\n\t\t\t\t}\n\n\t\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\t}\n\n\t\t\tacc := NewAccumulator(input, unit.dst)\n\t\t\tacc.SetPrecision(getPrecision(precision, interval))\n\n\t\t\tif err := input.Input.Gather(acc); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(input)\n\t}\n\twg.Wait()\n\n\tif err := internal.SleepContext(ctx, wait); err != nil {\n\t\tlog.Printf(\"E! [agent] SleepContext finished with: %v\", err)\n\t}\n\n\tlog.Printf(\"D! [agent] Stopping service inputs\")\n\tstopRunningInputs(unit.inputs)\n\n\tclose(unit.dst)\n\tlog.Printf(\"D! [agent] Input channel closed\")\n}\n\n// stopRunningInputs stops all service inputs.\nfunc stopRunningInputs(inputs []*models.RunningInput) {\n\tfor _, input := range inputs {\n\t\tinput.Stop()\n\t}\n}\n\n// stopRunningOutputs stops all running outputs.\nfunc stopRunningOutputs(outputs []*models.RunningOutput) {\n\tfor _, output := range outputs {\n\t\toutput.Close()\n\t}\n}\n\n// gather runs an input's gather function periodically until the context is\n// done.\nfunc (a *Agent) gatherLoop(\n\tctx context.Context,\n\tacc telegraf.Accumulator,\n\tinput *models.RunningInput,\n\tticker *clock.Ticker,\n\tinterval time.Duration,\n) {\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\terr := a.gatherOnce(acc, input, ticker, interval)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// gatherOnce runs the input's Gather function once, logging a warning each interval it fails to complete before.\nfunc (*Agent) gatherOnce(acc telegraf.Accumulator, input *models.RunningInput, ticker *clock.Ticker, interval time.Duration) error {\n\tdone := make(chan error)\n\tgo func() {\n\t\tdefer panicRecover(input)\n\t\tdone <- input.Gather(acc)\n\t}()\n\n\t// Only warn after interval seconds, even if the interval is started late.\n\t// Intervals can start late if the previous interval went over or due to\n\t// clock changes.\n\tslowWarning := time.NewTicker(interval)\n\tdefer slowWarning.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase err := <-done:\n\t\t\treturn err\n\t\tcase <-slowWarning.C:\n\t\t\tlog.Printf(\"W! [%s] Collection took longer than expected; not complete after interval of %s\",\n\t\t\t\tinput.LogName(), interval)\n\t\t\tinput.IncrGatherTimeouts()\n\t\tcase <-ticker.C:\n\t\t\tlog.Printf(\"D! [%s] Previous collection has not completed; scheduled collection skipped\",\n\t\t\t\tinput.LogName())\n\t\t}\n\t}\n}\n\n// startProcessors sets up the processor chain and calls Start on all processors.  If an error occurs any started processors are Stopped.\nfunc (*Agent) startProcessors(dst chan<- telegraf.Metric, runningProcessors models.RunningProcessors) (chan<- telegraf.Metric, []*processorUnit, error) {\n\tvar src chan telegraf.Metric\n\tunits := make([]*processorUnit, 0, len(runningProcessors))\n\t// The processor chain is constructed from the output side starting from\n\t// the output(s) and walking the way back to the input(s). However, the\n\t// processor-list is sorted by order and/or by appearance in the config,\n\t// i.e. in input-to-output direction. Therefore, reverse the processor list\n\t// to reflect the order/definition order in the processing chain.\n\tfor i := len(runningProcessors) - 1; i >= 0; i-- {\n\t\tprocessor := runningProcessors[i]\n\n\t\tsrc = make(chan telegraf.Metric, 100)\n\t\tacc := NewAccumulator(processor, dst)\n\n\t\terr := processor.Start(acc)\n\t\tif err != nil {\n\t\t\tfor _, u := range units {\n\t\t\t\tu.processor.Stop()\n\t\t\t\tclose(u.dst)\n\t\t\t}\n\t\t\treturn nil, nil, fmt.Errorf(\"starting processor %s: %w\", processor.LogName(), err)\n\t\t}\n\n\t\tunits = append(units, &processorUnit{\n\t\t\tsrc:       src,\n\t\t\tdst:       dst,\n\t\t\tprocessor: processor,\n\t\t})\n\n\t\tdst = src\n\t}\n\n\treturn src, units, nil\n}\n\n// runProcessors begins processing metrics and runs until the source channel is closed and all metrics have been written.\nfunc (*Agent) runProcessors(units []*processorUnit) {\n\tvar wg sync.WaitGroup\n\tfor _, unit := range units {\n\t\twg.Add(1)\n\t\tgo func(unit *processorUnit) {\n\t\t\tdefer wg.Done()\n\n\t\t\tacc := NewAccumulator(unit.processor, unit.dst)\n\t\t\tfor m := range unit.src {\n\t\t\t\tif err := unit.processor.Add(m, acc); err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tm.Drop()\n\t\t\t\t}\n\t\t\t}\n\t\t\tunit.processor.Stop()\n\t\t\tclose(unit.dst)\n\t\t\tlog.Printf(\"D! [agent] Processor channel closed\")\n\t\t}(unit)\n\t}\n\twg.Wait()\n}\n\n// startAggregators sets up the aggregator unit and returns the source channel.\nfunc (*Agent) startAggregators(aggC, outputC chan<- telegraf.Metric, aggregators []*models.RunningAggregator) (chan<- telegraf.Metric, *aggregatorUnit) {\n\tsrc := make(chan telegraf.Metric, 100)\n\tunit := &aggregatorUnit{\n\t\tsrc:         src,\n\t\taggC:        aggC,\n\t\toutputC:     outputC,\n\t\taggregators: aggregators,\n\t}\n\treturn src, unit\n}\n\n// runAggregators beings aggregating metrics and runs until the source channel\n// is closed and all metrics have been written.\nfunc (a *Agent) runAggregators(\n\tstartTime time.Time,\n\tunit *aggregatorUnit,\n) {\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// Before calling Add, initialize the aggregation window.  This ensures\n\t// that any metric created after start time will be aggregated.\n\tfor _, agg := range a.Config.Aggregators {\n\t\tsince, until := updateWindow(startTime, a.Config.Agent.RoundInterval, agg.Period())\n\t\tagg.UpdateWindow(since, until)\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor metric := range unit.src {\n\t\t\tvar dropOriginal bool\n\t\t\tfor _, agg := range a.Config.Aggregators {\n\t\t\t\tif ok := agg.Add(metric); ok {\n\t\t\t\t\tdropOriginal = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !dropOriginal {\n\t\t\t\tunit.outputC <- metric // keep original.\n\t\t\t} else {\n\t\t\t\tmetric.Drop()\n\t\t\t}\n\t\t}\n\t\tcancel()\n\t}()\n\n\tfor _, agg := range a.Config.Aggregators {\n\t\twg.Add(1)\n\t\tgo func(agg *models.RunningAggregator) {\n\t\t\tdefer wg.Done()\n\n\t\t\tinterval := time.Duration(a.Config.Agent.Interval)\n\t\t\tprecision := time.Duration(a.Config.Agent.Precision)\n\n\t\t\tacc := NewAccumulator(agg, unit.aggC)\n\t\t\tacc.SetPrecision(getPrecision(precision, interval))\n\t\t\ta.push(ctx, agg, acc)\n\t\t}(agg)\n\t}\n\n\twg.Wait()\n\n\t// In the case that there are no processors, both aggC and outputC are the\n\t// same channel.  If there are processors, we close the aggC and the\n\t// processor chain will close the outputC when it finishes processing.\n\tclose(unit.aggC)\n\tlog.Printf(\"D! [agent] Aggregator channel closed\")\n}\n\nfunc updateWindow(start time.Time, roundInterval bool, period time.Duration) (since, until time.Time) {\n\tif roundInterval {\n\t\tuntil = internal.AlignTime(start, period)\n\t\tif until.Equal(start) {\n\t\t\tuntil = internal.AlignTime(start.Add(time.Nanosecond), period)\n\t\t}\n\t} else {\n\t\tuntil = start.Add(period)\n\t}\n\n\tsince = until.Add(-period)\n\n\treturn since, until\n}\n\n// push runs the push for a single aggregator every period.\nfunc (*Agent) push(ctx context.Context, aggregator *models.RunningAggregator, acc telegraf.Accumulator) {\n\tfor {\n\t\t// Ensures that Push will be called for each period, even if it has\n\t\t// already elapsed before this function is called.  This is guaranteed\n\t\t// because so long as only Push updates the EndPeriod.  This method\n\t\t// also avoids drift by not using a ticker.\n\t\tuntil := time.Until(aggregator.EndPeriod())\n\n\t\tselect {\n\t\tcase <-time.After(until):\n\t\t\taggregator.Push(acc)\n\t\tcase <-ctx.Done():\n\t\t\taggregator.Push(acc)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// startOutputs calls Connect on all outputs and returns the source channel.\n// If an error occurs calling Connect, all started plugins have Close called.\nfunc (a *Agent) startOutputs(\n\tctx context.Context,\n\toutputs []*models.RunningOutput,\n) (chan<- telegraf.Metric, *outputUnit, error) {\n\tsrc := make(chan telegraf.Metric, 100)\n\tunit := &outputUnit{src: src}\n\tfor _, output := range outputs {\n\t\tif err := a.connectOutput(ctx, output); err != nil {\n\t\t\tvar fatalErr *internal.FatalError\n\t\t\tif errors.As(err, &fatalErr) {\n\t\t\t\t// If the model tells us to remove the plugin we do so without error\n\t\t\t\tlog.Printf(\"I! [agent] Failed to connect to [%s], error was %q;  shutting down plugin...\", output.LogName(), err)\n\t\t\t\toutput.Close()\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, unitOutput := range unit.outputs {\n\t\t\t\tunitOutput.Close()\n\t\t\t}\n\t\t\treturn nil, nil, fmt.Errorf(\"connecting output %s: %w\", output.LogName(), err)\n\t\t}\n\n\t\tunit.outputs = append(unit.outputs, output)\n\t}\n\n\treturn src, unit, nil\n}\n\n// connectOutput connects to all outputs.\nfunc (*Agent) connectOutput(ctx context.Context, output *models.RunningOutput) error {\n\tlog.Printf(\"D! [agent] Attempting connection to [%s]\", output.LogName())\n\tif err := output.Connect(); err != nil {\n\t\tlog.Printf(\"E! [agent] Failed to connect to [%s], retrying in 15s, error was %q\", output.LogName(), err)\n\n\t\tif err := internal.SleepContext(ctx, 15*time.Second); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = output.Connect(); err != nil {\n\t\t\treturn fmt.Errorf(\"error connecting to output %q: %w\", output.LogName(), err)\n\t\t}\n\t}\n\tlog.Printf(\"D! [agent] Successfully connected to %s\", output.LogName())\n\treturn nil\n}\n\n// runOutputs begins processing metrics and returns until the source channel is\n// closed and all metrics have been written.  On shutdown metrics will be\n// written one last time and dropped if unsuccessful.\nfunc (a *Agent) runOutputs(\n\tunit *outputUnit,\n) {\n\tvar wg sync.WaitGroup\n\n\t// Start flush loop\n\tinterval := time.Duration(a.Config.Agent.FlushInterval)\n\tjitter := time.Duration(a.Config.Agent.FlushJitter)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\tfor _, output := range unit.outputs {\n\t\tinterval := interval\n\t\t// Overwrite agent flush_interval if this plugin has its own.\n\t\tif output.Config.FlushInterval != 0 {\n\t\t\tinterval = output.Config.FlushInterval\n\t\t}\n\n\t\tjitter := jitter\n\t\t// Overwrite agent flush_jitter if this plugin has its own.\n\t\tif output.Config.FlushJitter != 0 {\n\t\t\tjitter = output.Config.FlushJitter\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(output *models.RunningOutput) {\n\t\t\tdefer wg.Done()\n\n\t\t\ttimer := clock.NewTimer(interval, jitter)\n\t\t\tdefer timer.Stop()\n\n\t\t\ta.flushLoop(ctx, output, timer)\n\t\t}(output)\n\t}\n\n\tfor metric := range unit.src {\n\t\tfor i, output := range unit.outputs {\n\t\t\tif i == len(unit.outputs)-1 {\n\t\t\t\toutput.AddMetricNoCopy(metric)\n\t\t\t} else {\n\t\t\t\toutput.AddMetric(metric)\n\t\t\t}\n\t\t}\n\t}\n\n\tlog.Println(\"I! [agent] Hang on, flushing any cached metrics before shutdown\")\n\tcancel()\n\twg.Wait()\n\n\tlog.Println(\"I! [agent] Stopping running outputs\")\n\tstopRunningOutputs(unit.outputs)\n}\n\n// flushLoop runs an output's flush function periodically until the context is\n// done.\nfunc (a *Agent) flushLoop(ctx context.Context, output *models.RunningOutput, timer *clock.Timer) {\n\tlogError := func(err error) {\n\t\tif err != nil {\n\t\t\tlog.Printf(\"E! [agent] Error writing to %s: %v\", output.LogName(), err)\n\t\t}\n\t}\n\n\t// watch for flush requests\n\tflushRequested := make(chan os.Signal, 1)\n\twatchForFlushSignal(flushRequested)\n\tdefer stopListeningForFlushSignal(flushRequested)\n\n\tfor {\n\t\t// Favor shutdown over other methods.\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlogError(a.flushOnce(output, timer, output.Write))\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlogError(a.flushOnce(output, timer, output.Write))\n\t\t\treturn\n\t\tcase <-timer.C:\n\t\t\tlogError(a.flushOnce(output, timer, output.Write))\n\t\tcase <-flushRequested:\n\t\t\tlogError(a.flushOnce(output, timer, output.Write))\n\t\tcase <-output.BatchReady:\n\t\t\tlogError(a.flushBatch(output, output.WriteBatch))\n\t\t}\n\t}\n}\n\n// flushOnce runs the output's Write function once, logging a warning each interval it fails to complete before the flush interval elapses.\nfunc (*Agent) flushOnce(output *models.RunningOutput, timer *clock.Timer, writeFunc func() error) error {\n\tdone := make(chan error)\n\tgo func() {\n\t\tdone <- writeFunc()\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase err := <-done:\n\t\t\toutput.LogBufferStatus()\n\t\t\treturn err\n\t\tcase <-timer.C:\n\t\t\tlog.Printf(\"W! [agent] [%q] did not complete within its flush interval\",\n\t\t\t\toutput.LogName())\n\t\t\toutput.LogBufferStatus()\n\t\t}\n\t}\n}\n\n// flushBatch runs the output's Write function once Unlike flushOnce the interval elapsing is not considered during these flushes.\nfunc (*Agent) flushBatch(output *models.RunningOutput, writeFunc func() error) error {\n\terr := writeFunc()\n\toutput.LogBufferStatus()\n\treturn err\n}\n\n// Test runs the inputs, processors and aggregators for a single gather and\n// writes the metrics to stdout.\nfunc (a *Agent) Test(ctx context.Context, wait time.Duration) error {\n\tsrc := make(chan telegraf.Metric, 100)\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ts := &influx.Serializer{SortFields: true, UintSupport: true}\n\t\tfor metric := range src {\n\t\t\toctets, err := s.Serialize(metric)\n\t\t\tif err == nil {\n\t\t\t\tfmt.Print(\"> \", string(octets))\n\t\t\t}\n\t\t\tmetric.Reject()\n\t\t}\n\t}()\n\n\terr := a.runTest(ctx, wait, src)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\twg.Wait()\n\n\tif models.GlobalGatherErrors.Get() != 0 {\n\t\treturn fmt.Errorf(\"input plugins recorded %d errors\", models.GlobalGatherErrors.Get())\n\t}\n\treturn nil\n}\n\n// runTest runs the agent and performs a single gather sending output to the\n// outputC. After gathering pauses for the wait duration to allow service\n// inputs to run.\nfunc (a *Agent) runTest(ctx context.Context, wait time.Duration, outputC chan<- telegraf.Metric) error {\n\t// Set the default for processor skipping\n\tif a.Config.Agent.SkipProcessorsAfterAggregators == nil {\n\t\tmsg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! `\n\t\tmsg += `If you need the current default behavior, please explicitly set the option to 'false'!`\n\t\tlog.Print(\"W! [agent] \", color.YellowString(msg))\n\t\tskipProcessorsAfterAggregators := false\n\t\ta.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators\n\t}\n\n\tlog.Printf(\"D! [agent] Initializing plugins\")\n\tif err := a.InitPlugins(); err != nil {\n\t\treturn err\n\t}\n\n\tstartTime := time.Now()\n\n\tnext := outputC\n\n\tvar apu []*processorUnit\n\tvar au *aggregatorUnit\n\tif len(a.Config.Aggregators) != 0 {\n\t\tprocC := next\n\t\tif len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators {\n\t\t\tvar err error\n\t\t\tprocC, apu, err = a.startProcessors(next, a.Config.AggProcessors)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tnext, au = a.startAggregators(procC, next, a.Config.Aggregators)\n\t}\n\n\tvar pu []*processorUnit\n\tif len(a.Config.Processors) != 0 {\n\t\tvar err error\n\t\tnext, pu, err = a.startProcessors(next, a.Config.Processors)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tiu := a.testStartInputs(next, a.Config.Inputs)\n\n\tvar wg sync.WaitGroup\n\tif au != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(apu)\n\t\t}()\n\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runAggregators(startTime, au)\n\t\t}()\n\t}\n\n\tif pu != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(pu)\n\t\t}()\n\t}\n\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ta.testRunInputs(ctx, wait, iu)\n\t}()\n\n\twg.Wait()\n\n\tlog.Printf(\"D! [agent] Stopped Successfully\")\n\n\treturn nil\n}\n\n// Once runs the full agent for a single gather.\nfunc (a *Agent) Once(ctx context.Context, wait time.Duration) error {\n\terr := a.runOnce(ctx, wait)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif models.GlobalGatherErrors.Get() != 0 {\n\t\treturn fmt.Errorf(\"input plugins recorded %d errors\", models.GlobalGatherErrors.Get())\n\t}\n\n\tunsent := 0\n\tfor _, output := range a.Config.Outputs {\n\t\tunsent += output.BufferLength()\n\t}\n\tif unsent != 0 {\n\t\treturn fmt.Errorf(\"output plugins unable to send %d metrics\", unsent)\n\t}\n\treturn nil\n}\n\n// runOnce runs the agent and performs a single gather sending output to the\n// outputC. After gathering pauses for the wait duration to allow service\n// inputs to run.\nfunc (a *Agent) runOnce(ctx context.Context, wait time.Duration) error {\n\t// Set the default for processor skipping\n\tif a.Config.Agent.SkipProcessorsAfterAggregators == nil {\n\t\tmsg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! `\n\t\tmsg += `If you need the current default behavior, please explicitly set the option to 'false'!`\n\t\tlog.Print(\"W! [agent] \", color.YellowString(msg))\n\t\tskipProcessorsAfterAggregators := false\n\t\ta.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators\n\t}\n\n\tlog.Printf(\"D! [agent] Initializing plugins\")\n\tif err := a.InitPlugins(); err != nil {\n\t\treturn err\n\t}\n\n\tstartTime := time.Now()\n\n\tlog.Printf(\"D! [agent] Connecting outputs\")\n\tnext, ou, err := a.startOutputs(ctx, a.Config.Outputs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar apu []*processorUnit\n\tvar au *aggregatorUnit\n\tif len(a.Config.Aggregators) != 0 {\n\t\tprocC := next\n\t\tif len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators {\n\t\t\tprocC, apu, err = a.startProcessors(next, a.Config.AggProcessors)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tnext, au = a.startAggregators(procC, next, a.Config.Aggregators)\n\t}\n\n\tvar pu []*processorUnit\n\tif len(a.Config.Processors) != 0 {\n\t\tnext, pu, err = a.startProcessors(next, a.Config.Processors)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tiu := a.testStartInputs(next, a.Config.Inputs)\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ta.runOutputs(ou)\n\t}()\n\n\tif au != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(apu)\n\t\t}()\n\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runAggregators(startTime, au)\n\t\t}()\n\t}\n\n\tif pu != nil {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\ta.runProcessors(pu)\n\t\t}()\n\t}\n\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\ta.testRunInputs(ctx, wait, iu)\n\t}()\n\n\twg.Wait()\n\n\tlog.Printf(\"D! [agent] Stopped Successfully\")\n\n\treturn nil\n}\n\n// Returns the rounding precision for metrics.\nfunc getPrecision(precision, interval time.Duration) time.Duration {\n\tif precision > 0 {\n\t\treturn precision\n\t}\n\n\tswitch {\n\tcase interval >= time.Second:\n\t\treturn time.Second\n\tcase interval >= time.Millisecond:\n\t\treturn time.Millisecond\n\tcase interval >= time.Microsecond:\n\t\treturn time.Microsecond\n\tdefault:\n\t\treturn time.Nanosecond\n\t}\n}\n\n// panicRecover displays an error if an input panics.\nfunc panicRecover(input *models.RunningInput) {\n\t//nolint:revive // recover is called inside a deferred function\n\tif err := recover(); err != nil {\n\t\ttrace := make([]byte, 2048)\n\t\truntime.Stack(trace, true)\n\t\tlog.Printf(\"E! FATAL: [%s] panicked: %s, Stack:\\n%s\",\n\t\t\tinput.LogName(), err, trace)\n\t\tlog.Fatalln(\"E! PLEASE REPORT THIS PANIC ON GITHUB with \" +\n\t\t\t\"stack trace, configuration, and OS information: \" +\n\t\t\t\"https://github.com/influxdata/telegraf/issues/new/choose\")\n\t}\n}\n\nfunc stopTickers(tickers []*clock.Ticker) {\n\tfor _, ticker := range tickers {\n\t\tticker.Stop()\n\t}\n}\n"
  },
  {
    "path": "agent/agent_posix.go",
    "content": "//go:build !windows\n\npackage agent\n\nimport (\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nconst flushSignal = syscall.SIGUSR1\n\nfunc watchForFlushSignal(flushRequested chan os.Signal) {\n\tsignal.Notify(flushRequested, flushSignal)\n}\n\nfunc stopListeningForFlushSignal(flushRequested chan os.Signal) {\n\tsignal.Stop(flushRequested)\n}\n"
  },
  {
    "path": "agent/agent_test.go",
    "content": "package agent\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/models\"\n\t_ \"github.com/influxdata/telegraf/plugins/aggregators/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/all\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t_ \"github.com/influxdata/telegraf/plugins/processors/all\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAgent_OmitHostname(t *testing.T) {\n\tc := config.NewConfig()\n\tc.Agent.OmitHostname = true\n\t_ = NewAgent(c)\n\trequire.NotContains(t, c.Tags, \"host\")\n}\n\nfunc TestAgent_LoadPlugin(t *testing.T) {\n\tc := config.NewConfig()\n\tc.InputFilters = []string{\"mysql\"}\n\terr := c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta := NewAgent(c)\n\trequire.Len(t, a.Config.Inputs, 1)\n\n\tc = config.NewConfig()\n\tc.InputFilters = []string{\"foo\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Empty(t, a.Config.Inputs)\n\n\tc = config.NewConfig()\n\tc.InputFilters = []string{\"mysql\", \"foo\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Inputs, 1)\n\n\tc = config.NewConfig()\n\tc.InputFilters = []string{\"mysql\", \"redis\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Inputs, 2)\n\n\tc = config.NewConfig()\n\tc.InputFilters = []string{\"mysql\", \"foo\", \"redis\", \"bar\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Inputs, 2)\n}\n\nfunc TestAgent_LoadOutput(t *testing.T) {\n\tc := config.NewConfig()\n\tc.OutputFilters = []string{\"influxdb\"}\n\terr := c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta := NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 2)\n\n\tc = config.NewConfig()\n\tc.OutputFilters = []string{\"kafka\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 1)\n\n\tc = config.NewConfig()\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 3)\n\n\tc = config.NewConfig()\n\tc.OutputFilters = []string{\"foo\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Empty(t, a.Config.Outputs)\n\n\tc = config.NewConfig()\n\tc.OutputFilters = []string{\"influxdb\", \"foo\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 2)\n\n\tc = config.NewConfig()\n\tc.OutputFilters = []string{\"influxdb\", \"kafka\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Outputs, 3)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 3)\n\n\tc = config.NewConfig()\n\tc.OutputFilters = []string{\"influxdb\", \"foo\", \"kafka\", \"bar\"}\n\terr = c.LoadConfig(\"../config/testdata/telegraf-agent.toml\")\n\trequire.NoError(t, err)\n\ta = NewAgent(c)\n\trequire.Len(t, a.Config.Outputs, 3)\n}\n\nfunc TestWindow(t *testing.T) {\n\tparse := func(s string) time.Time {\n\t\ttm, err := time.Parse(time.RFC3339, s)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn tm\n\t}\n\n\ttests := []struct {\n\t\tname          string\n\t\tstart         time.Time\n\t\troundInterval bool\n\t\tperiod        time.Duration\n\t\tsince         time.Time\n\t\tuntil         time.Time\n\t}{\n\t\t{\n\t\t\tname:          \"round with exact alignment\",\n\t\t\tstart:         parse(\"2018-03-27T00:00:00Z\"),\n\t\t\troundInterval: true,\n\t\t\tperiod:        30 * time.Second,\n\t\t\tsince:         parse(\"2018-03-27T00:00:00Z\"),\n\t\t\tuntil:         parse(\"2018-03-27T00:00:30Z\"),\n\t\t},\n\t\t{\n\t\t\tname:          \"round with alignment needed\",\n\t\t\tstart:         parse(\"2018-03-27T00:00:05Z\"),\n\t\t\troundInterval: true,\n\t\t\tperiod:        30 * time.Second,\n\t\t\tsince:         parse(\"2018-03-27T00:00:00Z\"),\n\t\t\tuntil:         parse(\"2018-03-27T00:00:30Z\"),\n\t\t},\n\t\t{\n\t\t\tname:          \"no round with exact alignment\",\n\t\t\tstart:         parse(\"2018-03-27T00:00:00Z\"),\n\t\t\troundInterval: false,\n\t\t\tperiod:        30 * time.Second,\n\t\t\tsince:         parse(\"2018-03-27T00:00:00Z\"),\n\t\t\tuntil:         parse(\"2018-03-27T00:00:30Z\"),\n\t\t},\n\t\t{\n\t\t\tname:          \"no found with alignment needed\",\n\t\t\tstart:         parse(\"2018-03-27T00:00:05Z\"),\n\t\t\troundInterval: false,\n\t\t\tperiod:        30 * time.Second,\n\t\t\tsince:         parse(\"2018-03-27T00:00:05Z\"),\n\t\t\tuntil:         parse(\"2018-03-27T00:00:35Z\"),\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tsince, until := updateWindow(tt.start, tt.roundInterval, tt.period)\n\t\t\trequire.Equal(t, tt.since, since, \"since\")\n\t\t\trequire.Equal(t, tt.until, until, \"until\")\n\t\t})\n\t}\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Make sure tests contains data\n\trequire.NotEmpty(t, folders)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfname := f.Name()\n\t\ttestdataPath := filepath.Join(\"testcases\", fname)\n\t\tconfigFilename := filepath.Join(testdataPath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testdataPath, \"expected.out\")\n\n\t\tt.Run(fname, func(t *testing.T) {\n\t\t\t// Get parser to parse input and expected output\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\texpected, err := testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, expected)\n\n\t\t\t// Load the config and inject the mock output to be able to verify\n\t\t\t// the resulting metrics\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadAll(configFilename))\n\t\t\trequire.Empty(t, cfg.Outputs, \"No output(s) allowed in the config!\")\n\n\t\t\t// Setup the agent and run the agent in \"once\" mode\n\t\t\tagent := NewAgent(cfg)\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\t\t\tdefer cancel()\n\t\t\tactual, err := collect(ctx, agent, 0)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Process expected metrics and compare with resulting metrics\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTags(\"host\"),\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\n// Implement a \"test-mode\" like call but collect the metrics\nfunc collect(ctx context.Context, a *Agent, wait time.Duration) ([]telegraf.Metric, error) {\n\tvar received []telegraf.Metric\n\tvar mu sync.Mutex\n\n\tsrc := make(chan telegraf.Metric, 100)\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor m := range src {\n\t\t\tmu.Lock()\n\t\t\treceived = append(received, m)\n\t\t\tmu.Unlock()\n\t\t\tm.Reject()\n\t\t}\n\t}()\n\n\tif err := a.runTest(ctx, wait, src); err != nil {\n\t\treturn nil, err\n\t}\n\twg.Wait()\n\n\tif models.GlobalGatherErrors.Get() != 0 {\n\t\treturn received, fmt.Errorf(\"input plugins recorded %d errors\", models.GlobalGatherErrors.Get())\n\t}\n\treturn received, nil\n}\n"
  },
  {
    "path": "agent/agent_windows.go",
    "content": "//go:build windows\n\npackage agent\n\nimport \"os\"\n\nfunc watchForFlushSignal(_ chan os.Signal) {\n\t// not supported\n}\n\nfunc stopListeningForFlushSignal(_ chan os.Signal) {\n\t// not supported\n}\n"
  },
  {
    "path": "agent/testcases/aggregators-rerun-processors/expected.out",
    "content": "metric value=420\nmetric value_min=4200,value_max=4200\n"
  },
  {
    "path": "agent/testcases/aggregators-rerun-processors/input.influx",
    "content": "metric value=42.0\n"
  },
  {
    "path": "agent/testcases/aggregators-rerun-processors/telegraf.conf",
    "content": "# Test for not skipping processors after running aggregators\n[agent]\n  omit_hostname = true\n  skip_processors_after_aggregators = false\n\n[[inputs.file]]\n  files = [\"testcases/aggregators-rerun-processors/input.influx\"]\n  data_format = \"influx\"\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"float\":\n            metric.fields[k] = v * 10\n    return metric\n'''\n\n[[aggregators.minmax]]\n  period = \"1s\"\n  drop_original = false\n\n"
  },
  {
    "path": "agent/testcases/aggregators-skip-processors/expected.out",
    "content": "metric value=420\nmetric value_min=420,value_max=420\n"
  },
  {
    "path": "agent/testcases/aggregators-skip-processors/input.influx",
    "content": "metric value=42.0\n"
  },
  {
    "path": "agent/testcases/aggregators-skip-processors/telegraf.conf",
    "content": "# Test for skipping processors after running aggregators\n[agent]\n  omit_hostname = true\n  skip_processors_after_aggregators = true\n\n[[inputs.file]]\n  files = [\"testcases/aggregators-skip-processors/input.influx\"]\n  data_format = \"influx\"\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"float\":\n            metric.fields[k] = v * 10\n    return metric\n'''\n\n[[aggregators.minmax]]\n  period = \"1s\"\n  drop_original = false\n\n"
  },
  {
    "path": "agent/testcases/processor-order-appearance/expected.out",
    "content": "new_metric_from_starlark,foo=bar baz=42i,timestamp=\"2023-07-13T12:53:54.197709713Z\" 1689252834197709713\nold_metric_from_mock,mood=good value=23i,timestamp=\"2023-07-13T13:10:34Z\" 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-appearance/input.influx",
    "content": "old_metric_from_mock,mood=good value=23i 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-appearance/telegraf.conf",
    "content": "# Test for using the appearance order in the file for processor order\n[[inputs.file]]\n  files = [\"testcases/processor-order-appearance/input.influx\"]\n  data_format = \"influx\"\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n  metrics = []\n\n  m = Metric(\"new_metric_from_starlark\")\n  m.tags[\"foo\"] = \"bar\"\n  m.fields[\"baz\"] = 42\n  m.time = 1689252834197709713\n  metrics.append(m)\n  metrics.append(metric)\n\n  return metrics\n'''\n\n[[processors.date]]\n  field_key = \"timestamp\"\n  date_format = \"2006-01-02T15:04:05.999999999Z\"\n  timezone = \"UTC\"\n\n\n"
  },
  {
    "path": "agent/testcases/processor-order-explicit/expected.out",
    "content": "new_metric_from_starlark,foo=bar baz=42i,timestamp=\"2023-07-13T12:53:54.197709713Z\" 1689252834197709713\nold_metric_from_mock,mood=good value=23i,timestamp=\"2023-07-13T13:10:34Z\" 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-explicit/input.influx",
    "content": "old_metric_from_mock,mood=good value=23i 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-explicit/telegraf.conf",
    "content": "# Test for specifying an explicit processor order\n[[inputs.file]]\n  files = [\"testcases/processor-order-explicit/input.influx\"]\n  data_format = \"influx\"\n\n\n[[processors.date]]\n  field_key = \"timestamp\"\n  date_format = \"2006-01-02T15:04:05.999999999Z\"\n  timezone = \"UTC\"\n  order = 2\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n  metrics = []\n\n  m = Metric(\"new_metric_from_starlark\")\n  m.tags[\"foo\"] = \"bar\"\n  m.fields[\"baz\"] = 42\n  m.time = 1689252834197709713\n  metrics.append(m)\n  metrics.append(metric)\n\n  return metrics\n'''\n  order = 1\n"
  },
  {
    "path": "agent/testcases/processor-order-mixed/expected.out",
    "content": "new_metric_from_starlark,foo=bar baz=42i,timestamp=\"2023-07-13T12:53:54.197709713Z\" 1689252834197709713\nold_metric_from_mock,mood=good value=23i,timestamp=\"2023-07-13T13:10:34Z\" 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-mixed/input.influx",
    "content": "old_metric_from_mock,mood=good value=23i 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-mixed/telegraf.conf",
    "content": "# Test for using the appearance order in the file for processor order\n[[inputs.file]]\n  files = [\"testcases/processor-order-appearance/input.influx\"]\n  data_format = \"influx\"\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n  metrics = []\n\n  m = Metric(\"new_metric_from_starlark\")\n  m.tags[\"foo\"] = \"bar\"\n  m.fields[\"baz\"] = 42\n  m.time = 1689252834197709713\n  metrics.append(m)\n  metrics.append(metric)\n\n  return metrics\n'''\n\n[[processors.date]]\n  field_key = \"timestamp\"\n  date_format = \"2006-01-02T15:04:05.999999999Z\"\n  timezone = \"UTC\"\n  order = 1\n"
  },
  {
    "path": "agent/testcases/processor-order-no-starlark/expected.out",
    "content": "new_metric_from_starlark,foo=bar baz=42i 1689252834197709713\nold_metric_from_mock,mood=good value=23i,timestamp=\"2023-07-13T13:10:34Z\" 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-no-starlark/input.influx",
    "content": "old_metric_from_mock,mood=good value=23i 1689253834000000000\n"
  },
  {
    "path": "agent/testcases/processor-order-no-starlark/telegraf.conf",
    "content": "# Test for using the appearance order in the file for processor order.\n# This will not add the \"timestamp\" field as the starlark processor runs _after_\n# the date processor.\n[[inputs.file]]\n  files = [\"testcases/processor-order-no-starlark/input.influx\"]\n  data_format = \"influx\"\n\n[[processors.date]]\n  field_key = \"timestamp\"\n  date_format = \"2006-01-02T15:04:05.999999999Z\"\n  timezone = \"UTC\"\n\n[[processors.starlark]]\n  source = '''\ndef apply(metric):\n  metrics = []\n\n  m = Metric(\"new_metric_from_starlark\")\n  m.tags[\"foo\"] = \"bar\"\n  m.fields[\"baz\"] = 42\n  m.time = 1689252834197709713\n  metrics.append(m)\n  metrics.append(metric)\n\n  return metrics\n'''\n"
  },
  {
    "path": "aggregator.go",
    "content": "package telegraf\n\n// Aggregator is an interface for implementing an Aggregator plugin.\n// the RunningAggregator wraps this interface and guarantees that\n// Add, Push, and Reset can not be called concurrently, so locking is not\n// required when implementing an Aggregator plugin.\ntype Aggregator interface {\n\tPluginDescriber\n\n\t// Add the metric to the aggregator.\n\tAdd(in Metric)\n\n\t// Push pushes the current aggregates to the accumulator.\n\tPush(acc Accumulator)\n\n\t// Reset resets the aggregators caches and aggregates.\n\tReset()\n}\n"
  },
  {
    "path": "build_version.txt",
    "content": "1.39.0"
  },
  {
    "path": "cmd/telegraf/agent.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  ## Message key for structured logs, to override the default of \"msg\".\n  ## Ignored if `logformat` is not \"structured\".\n  # structured_log_message_key = \"message\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "cmd/telegraf/cmd_config.go",
    "content": "// Command handling for configuration \"config\" command\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/urfave/cli/v2\"\n\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nfunc getConfigCommands(configHandlingFlags []cli.Flag, outputBuffer io.Writer) []*cli.Command {\n\treturn []*cli.Command{\n\t\t{\n\t\t\tName:  \"config\",\n\t\t\tUsage: \"commands for generating and migrating configurations\",\n\t\t\tFlags: configHandlingFlags,\n\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t// The sub_Filters are populated when the filter flags are set after the subcommand config\n\t\t\t\t// e.g. telegraf config --section-filter inputs\n\t\t\t\tfilters := processFilterFlags(cCtx)\n\n\t\t\t\tprintSampleConfig(outputBuffer, filters)\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t{\n\t\t\t\t\tName:  \"check\",\n\t\t\t\t\tUsage: \"check configuration file(s) for issues\",\n\t\t\t\t\tDescription: `\n\t\tThe 'check' command reads the configuration files specified via '--config' or\n\t\t'--config-directory' and tries to initialize, but not start, the plugins.\n\t\tSyntax and semantic errors detectable without starting the plugins will\n\t\tbe reported.\n\t\tIf no configuration file is\texplicitly specified the command reads the\n\t\tdefault locations and uses those configuration files.\n\n\t\tTo check the file 'mysettings.conf' use\n\n\t\t> telegraf config check --config mysettings.conf\n\t\t`,\n\t\t\t\t\tFlags: configHandlingFlags,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t// Setup logging\n\t\t\t\t\t\tlogConfig := &logger.Config{Debug: cCtx.Bool(\"debug\")}\n\t\t\t\t\t\tif err := logger.SetupLogging(logConfig); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Set the environment variables handling mode\n\t\t\t\t\t\tif cCtx.Bool(\"strict-env-handling\") && cCtx.Bool(\"non-strict-env-handling\") {\n\t\t\t\t\t\t\treturn errors.New(\"flags --strict-env-handling and --non-strict-env-handling cannot be used together\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif !cCtx.Bool(\"strict-env-handling\") && !cCtx.Bool(\"non-strict-env-handling\") {\n\t\t\t\t\t\t\tmsg := \"Strict environment variable handling will be the new default starting with v1.38.0! \" +\n\t\t\t\t\t\t\t\t\"If your configuration works with strict handling or you don't use environment variables it is safe \" +\n\t\t\t\t\t\t\t\t\"to ignore this warning. Otherwise please explicitly add the --non-strict-env-handling flag!\"\n\t\t\t\t\t\t\tlog.Println(\"W! \" + color.YellowString(msg))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconfig.NonStrictEnvVarHandling = !cCtx.Bool(\"strict-env-handling\")\n\n\t\t\t\t\t\t// Collect the given configuration files\n\t\t\t\t\t\tconfigFiles := cCtx.StringSlice(\"config\")\n\t\t\t\t\t\tconfigDir := cCtx.StringSlice(\"config-directory\")\n\t\t\t\t\t\tfor _, fConfigDirectory := range configDir {\n\t\t\t\t\t\t\tfiles, err := config.WalkDirectory(fConfigDirectory)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfigFiles = append(configFiles, files...)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If no \"config\" or \"config-directory\" flag(s) was\n\t\t\t\t\t\t// provided we should load default configuration files\n\t\t\t\t\t\tif len(configFiles) == 0 {\n\t\t\t\t\t\t\tpaths, err := config.GetDefaultConfigPath()\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfigFiles = paths\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Load the config and try to initialize the plugins\n\t\t\t\t\t\tc := config.NewConfig()\n\t\t\t\t\t\tc.Agent.Quiet = cCtx.Bool(\"quiet\")\n\t\t\t\t\t\tif err := c.LoadAll(configFiles...); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tag := agent.NewAgent(c)\n\n\t\t\t\t\t\t// Set the default for processor skipping\n\t\t\t\t\t\tif c.Agent.SkipProcessorsAfterAggregators == nil {\n\t\t\t\t\t\t\tmsg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! `\n\t\t\t\t\t\t\tmsg += `If you need the current default behavior, please explicitly set the option to 'false'!`\n\t\t\t\t\t\t\tlog.Print(\"W! [agent] \", color.YellowString(msg))\n\t\t\t\t\t\t\tskipProcessorsAfterAggregators := false\n\t\t\t\t\t\t\tc.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn ag.InitPlugins()\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"create\",\n\t\t\t\t\tUsage: \"create a full sample configuration and show it\",\n\t\t\t\t\tDescription: `\nThe 'create' produces a full configuration containing all plugins as an example\nand shows it on the console. You may apply 'section' or 'plugin' filtering\nto reduce the output to the plugins you need\n\nCreate the full configuration\n\n> telegraf config create\n\nTo produce a configuration only containing a Modbus input plugin and an\nInfluxDB v2 output plugin use\n\n> telegraf config create --section-filter \"inputs:outputs\" --input-filter \"modbus\" --output-filter \"influxdb_v2\"\n`,\n\t\t\t\t\tFlags: configHandlingFlags,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tfilters := processFilterFlags(cCtx)\n\n\t\t\t\t\t\tprintSampleConfig(outputBuffer, filters)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"migrate\",\n\t\t\t\t\tUsage: \"migrate deprecated plugins and options of the configuration(s)\",\n\t\t\t\t\tDescription: `\nThe 'migrate' command reads the configuration files specified via '--config' or\n'--config-directory' and tries to migrate plugins or options that are currently\ndeprecated using the recommended replacements. If no configuration file is\nexplicitly specified the command reads the default locations and uses those\nconfiguration files. Migrated files are stored with a '.migrated' suffix at the\nlocation of the  inputs. If you are migrating remote configurations the migrated\nconfigurations is stored in the current directory using the filename of the URL\nwith a '.migrated' suffix.\nIt is highly recommended to test those migrated configurations before using\nthose files unattended!\n\nTo migrate the file 'mysettings.conf' use\n\n> telegraf config migrate --config mysettings.conf\n`,\n\t\t\t\t\tFlags: append(configHandlingFlags,\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"force\",\n\t\t\t\t\t\t\tUsage: \"forces overwriting of an existing migration file\",\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t// Setup logging\n\t\t\t\t\t\tlogConfig := &logger.Config{Debug: cCtx.Bool(\"debug\")}\n\t\t\t\t\t\tif err := logger.SetupLogging(logConfig); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if we have migrations at all. There might be\n\t\t\t\t\t\t// none if you run a custom build without migrations\n\t\t\t\t\t\t// enabled.\n\t\t\t\t\t\tmigrationsGeneral := len(migrations.GeneralMigrations) + len(migrations.GlobalMigrations)\n\t\t\t\t\t\tmigrationsPlugins := len(migrations.PluginMigrations)\n\t\t\t\t\t\tmigrationsOptions := len(migrations.PluginOptionMigrations)\n\t\t\t\t\t\tif migrationsGeneral+migrationsPlugins+migrationsOptions == 0 {\n\t\t\t\t\t\t\treturn errors.New(\"no migrations available\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlog.Printf(\n\t\t\t\t\t\t\t\"%d general, %d plugin and %d plugin-option migrations available\",\n\t\t\t\t\t\t\tmigrationsGeneral, migrationsPlugins, migrationsOptions,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\t// Collect the given configuration files\n\t\t\t\t\t\tconfigFiles := cCtx.StringSlice(\"config\")\n\t\t\t\t\t\tconfigDir := cCtx.StringSlice(\"config-directory\")\n\t\t\t\t\t\tfor _, fConfigDirectory := range configDir {\n\t\t\t\t\t\t\tfiles, err := config.WalkDirectory(fConfigDirectory)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfigFiles = append(configFiles, files...)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If no \"config\" or \"config-directory\" flag(s) was\n\t\t\t\t\t\t// provided we should load default configuration files\n\t\t\t\t\t\tif len(configFiles) == 0 {\n\t\t\t\t\t\t\tpaths, err := config.GetDefaultConfigPath()\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfigFiles = paths\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor _, fn := range configFiles {\n\t\t\t\t\t\t\tlog.Printf(\"D! Trying to migrate %q...\", fn)\n\n\t\t\t\t\t\t\t// Read and parse the config file\n\t\t\t\t\t\t\tdata, remote, err := config.LoadConfigFile(fn)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"opening input %q failed: %w\", fn, err)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tout, applied, err := config.ApplyMigrations(data)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Do not write a migration file if nothing was done\n\t\t\t\t\t\t\tif applied == 0 {\n\t\t\t\t\t\t\t\tlog.Printf(\"I! No migration applied for %q\", fn)\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Construct the output filename\n\t\t\t\t\t\t\t// For remote locations we just save the filename\n\t\t\t\t\t\t\t// with the migrated suffix.\n\t\t\t\t\t\t\toutfn := fn + \".migrated\"\n\t\t\t\t\t\t\tif remote {\n\t\t\t\t\t\t\t\tu, err := url.Parse(fn)\n\t\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"parsing remote config URL %q failed: %w\", fn, err)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\toutfn = filepath.Base(u.Path) + \".migrated\"\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlog.Printf(\"I! %d migration applied for %q, writing result as %q\", applied, fn, outfn)\n\n\t\t\t\t\t\t\t// Make sure the file does not exist yet if we should not overwrite\n\t\t\t\t\t\t\tif !cCtx.Bool(\"force\") {\n\t\t\t\t\t\t\t\tif _, err := os.Stat(outfn); !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"output file %q already exists\", outfn)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Write the output file\n\t\t\t\t\t\t\tif err := os.WriteFile(outfn, out, 0640); err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"writing output %q failed: %w\", outfn, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "cmd/telegraf/cmd_plugins.go",
    "content": "// Command handling for configuration \"plugins\" command\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/urfave/cli/v2\"\n\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/secretstores\"\n\t\"github.com/influxdata/telegraf/plugins/serializers\"\n)\n\nfunc pluginNames[M ~map[string]V, V any](m M, prefix string) []byte {\n\tnames := make([]string, 0, len(m))\n\tfor k := range m {\n\t\tnames = append(names, fmt.Sprintf(\"%s.%s\\n\", prefix, k))\n\t}\n\tsort.Strings(names)\n\treturn []byte(strings.Join(names, \"\"))\n}\n\nfunc getPluginCommands(outputBuffer io.Writer) []*cli.Command {\n\treturn []*cli.Command{\n\t\t{\n\t\t\tName:  \"plugins\",\n\t\t\tUsage: \"commands for printing available plugins\",\n\t\t\tFlags: []cli.Flag{\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\toutputBuffer.Write(pluginNames(inputs.Deprecations, \"inputs\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(outputs.Deprecations, \"outputs\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(processors.Deprecations, \"processors\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(aggregators.Deprecations, \"aggregators\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(secretstores.Deprecations, \"secretstores\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(parsers.Deprecations, \"parsers\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(serializers.Deprecations, \"serializers\"))\n\t\t\t\t} else {\n\t\t\t\t\toutputBuffer.Write(pluginNames(inputs.Inputs, \"inputs\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(outputs.Outputs, \"outputs\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(processors.Processors, \"processors\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(aggregators.Aggregators, \"aggregators\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(secretstores.SecretStores, \"secretstores\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(parsers.Parsers, \"parsers\"))\n\t\t\t\t\toutputBuffer.Write(pluginNames(serializers.Serializers, \"serializers\"))\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t{\n\t\t\t\t\tName:  \"inputs\",\n\t\t\t\t\tUsage: \"Print available input plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(inputs.Deprecations, \"inputs\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(inputs.Inputs, \"inputs\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"outputs\",\n\t\t\t\t\tUsage: \"Print available output plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(outputs.Deprecations, \"outputs\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(outputs.Outputs, \"outputs\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"processors\",\n\t\t\t\t\tUsage: \"Print available processor plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(processors.Deprecations, \"processors\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(processors.Processors, \"processors\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"aggregators\",\n\t\t\t\t\tUsage: \"Print available aggregator plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(aggregators.Deprecations, \"aggregators\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(aggregators.Aggregators, \"aggregators\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"secretstores\",\n\t\t\t\t\tUsage: \"Print available secretstore plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(secretstores.Deprecations, \"secretstores\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(secretstores.SecretStores, \"secretstores\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"parsers\",\n\t\t\t\t\tUsage: \"Print available parser plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(parsers.Deprecations, \"parsers\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(parsers.Parsers, \"parsers\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"serializers\",\n\t\t\t\t\tUsage: \"Print available serializer plugins\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"deprecated\",\n\t\t\t\t\t\t\tUsage: \"print only deprecated plugins\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tif cCtx.Bool(\"deprecated\") {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(serializers.Deprecations, \"serializers\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\toutputBuffer.Write(pluginNames(serializers.Serializers, \"serializers\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "cmd/telegraf/cmd_secretstore.go",
    "content": "// Command handling for secret-stores' \"secrets\" command\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/awnumar/memguard\"\n\t\"github.com/urfave/cli/v2\"\n\t\"golang.org/x/term\"\n)\n\nfunc processFilterOnlySecretStoreFlags(ctx *cli.Context) Filters {\n\tsectionFilters := []string{\"inputs\", \"outputs\", \"processors\", \"aggregators\"}\n\tinputFilters := []string{\"-\"}\n\toutputFilters := []string{\"-\"}\n\tprocessorFilters := []string{\"-\"}\n\taggregatorFilters := []string{\"-\"}\n\n\t// Only load the secret-stores\n\tvar secretstore string\n\tif len(ctx.Lineage()) >= 2 {\n\t\tparent := ctx.Lineage()[1] // ancestor contexts in order from child to parent\n\t\tsecretstore = parent.String(\"secretstore-filter\")\n\t}\n\n\t// If both the parent and command filters are defined, append them together\n\tsecretstore = appendFilter(secretstore, ctx.String(\"secretstore-filter\"))\n\tsecretstoreFilters := deleteEmpty(strings.Split(secretstore, \":\"))\n\treturn Filters{sectionFilters, inputFilters, outputFilters, aggregatorFilters, processorFilters, secretstoreFilters}\n}\n\nfunc getSecretStoreCommands(m App) []*cli.Command {\n\treturn []*cli.Command{\n\t\t{\n\t\t\tName:  \"secrets\",\n\t\t\tUsage: \"commands for listing, adding and removing secrets on all known secret-stores\",\n\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t{\n\t\t\t\t\tName:  \"list\",\n\t\t\t\t\tUsage: \"list known secrets and secret-stores\",\n\t\t\t\t\tDescription: `\nThe 'list' command requires passing in your configuration file\ncontaining the secret-store definitions you want to access. To get a\nlist of available secret-store plugins, please have a look at\nhttps://github.com/influxdata/telegraf/tree/master/plugins/secretstores.\n\nFor help on how to define secret-stores, check the documentation of the\ndifferent plugins.\n\nAssuming you use the default configuration file location, you can run\nthe following command to list the keys of all known secrets in ALL\navailable stores\n\n> telegraf secrets list\n\nTo get the keys of all known secrets in a particular store, you can run\n\n> telegraf secrets list mystore\n\nTo also reveal the actual secret, i.e. the value, you can pass the\n'--reveal-secret' flag.\n`,\n\t\t\t\t\tArgsUsage: \"[secret-store ID]...[secret-store ID]\",\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"reveal-secret\",\n\t\t\t\t\t\t\tUsage: \"also print the secret value\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t// Only load the secret-stores\n\t\t\t\t\t\tfilters := processFilterOnlySecretStoreFlags(cCtx)\n\t\t\t\t\t\tg := GlobalFlags{\n\t\t\t\t\t\t\tconfig:     cCtx.StringSlice(\"config\"),\n\t\t\t\t\t\t\tconfigDir:  cCtx.StringSlice(\"config-directory\"),\n\t\t\t\t\t\t\tplugindDir: cCtx.String(\"plugin-directory\"),\n\t\t\t\t\t\t\tpassword:   cCtx.String(\"password\"),\n\t\t\t\t\t\t\tdebug:      cCtx.Bool(\"debug\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t\tw := WindowFlags{}\n\t\t\t\t\t\tm.Init(nil, filters, g, w)\n\n\t\t\t\t\t\targs := cCtx.Args()\n\t\t\t\t\t\tvar storeIDs []string\n\t\t\t\t\t\tif args.Present() {\n\t\t\t\t\t\t\tstoreIDs = args.Slice()\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tids, err := m.ListSecretStores()\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to determine secret-store IDs: %w\", err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstoreIDs = ids\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsort.Strings(storeIDs)\n\n\t\t\t\t\t\treveal := cCtx.Bool(\"reveal-secret\")\n\t\t\t\t\t\tfor _, storeID := range storeIDs {\n\t\t\t\t\t\t\tstore, err := m.GetSecretStore(storeID)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get secret-store %q: %w\", storeID, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tkeys, err := store.List()\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get secrets from store %q: %w\", storeID, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsort.Strings(keys)\n\n\t\t\t\t\t\t\tfmt.Printf(\"Known secrets for store %q:\\n\", storeID)\n\t\t\t\t\t\t\tfor _, k := range keys {\n\t\t\t\t\t\t\t\tvar v []byte\n\t\t\t\t\t\t\t\tif reveal {\n\t\t\t\t\t\t\t\t\tif v, err = store.Get(k); err != nil {\n\t\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get value of secret %q from store %q: %w\", k, storeID, err)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfmt.Printf(\"    %-30s  %s\\n\", k, string(v))\n\t\t\t\t\t\t\t\tmemguard.WipeBytes(v)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"get\",\n\t\t\t\t\tUsage: \"retrieves value of given secret from given store\",\n\t\t\t\t\tDescription: `\nThe 'get' command requires passing in your configuration file\ncontaining the secret-store definitions you want to access. To get a\nlist of available secret-store plugins, please have a look at\nhttps://github.com/influxdata/telegraf/tree/master/plugins/secretstores.\nand use the 'secrets list' command to get the IDs of available stores and\nkey(s) of available secrets.\n\nFor help on how to define secret-stores, check the documentation of the\ndifferent plugins.\n\nAssuming you use the default configuration file location, you can run\nthe following command to retrieve a secret from a secret store\navailable stores\n\n> telegraf secrets get mystore mysecretkey\n\nThis will fetch the secret with the key 'mysecretkey' from the secret-store\nwith the ID 'mystore'.\n`,\n\t\t\t\t\tArgsUsage: \"<secret-store ID> <secret key>\",\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t// Only load the secret-stores\n\t\t\t\t\t\tfilters := processFilterOnlySecretStoreFlags(cCtx)\n\t\t\t\t\t\tg := GlobalFlags{\n\t\t\t\t\t\t\tconfig:     cCtx.StringSlice(\"config\"),\n\t\t\t\t\t\t\tconfigDir:  cCtx.StringSlice(\"config-directory\"),\n\t\t\t\t\t\t\tplugindDir: cCtx.String(\"plugin-directory\"),\n\t\t\t\t\t\t\tpassword:   cCtx.String(\"password\"),\n\t\t\t\t\t\t\tdebug:      cCtx.Bool(\"debug\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t\tw := WindowFlags{}\n\t\t\t\t\t\tm.Init(nil, filters, g, w)\n\n\t\t\t\t\t\targs := cCtx.Args()\n\t\t\t\t\t\tif !args.Present() || args.Len() != 2 {\n\t\t\t\t\t\t\treturn errors.New(\"invalid number of arguments\")\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstoreID := args.First()\n\t\t\t\t\t\tkey := args.Get(1)\n\n\t\t\t\t\t\tstore, err := m.GetSecretStore(storeID)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get secret-store: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalue, err := store.Get(key)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get secret: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Printf(\"%s:%s = %s\\n\", storeID, key, value)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"set\",\n\t\t\t\t\tUsage: \"create or modify a secret in the given store\",\n\t\t\t\t\tDescription: `\nThe 'set' command requires passing in your configuration file\ncontaining the secret-store definitions you want to access. To get a\nlist of available secret-store plugins, please have a look at\nhttps://github.com/influxdata/telegraf/tree/master/plugins/secretstores.\nand use the 'secrets list' command to get the IDs of available stores and keys.\n\nFor help on how to define secret-stores, check the documentation of the\ndifferent plugins.\n\nAssuming you use the default configuration file location, you can run\nthe following command to create a secret in anm available secret-store\n\n> telegraf secrets set mystore mysecretkey mysecretvalue\n\nThis will create a secret with the key 'mysecretkey' in the secret-store\nwith the ID 'mystore' with the value being set to 'mysecretvalue'. If a\nsecret with that key ('mysecretkey') already existed in that store, its\nvalue will be modified.\n\nWhen you leave out the value of the secret like\n\n> telegraf secrets set mystore mysecretkey\n\nyou will be prompted to enter the value of the secret.\n`,\n\t\t\t\t\tArgsUsage: \"<secret-store ID> <secret key>\",\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\t// Only load the secret-stores\n\t\t\t\t\t\tfilters := processFilterOnlySecretStoreFlags(cCtx)\n\t\t\t\t\t\tg := GlobalFlags{\n\t\t\t\t\t\t\tconfig:     cCtx.StringSlice(\"config\"),\n\t\t\t\t\t\t\tconfigDir:  cCtx.StringSlice(\"config-directory\"),\n\t\t\t\t\t\t\tplugindDir: cCtx.String(\"plugin-directory\"),\n\t\t\t\t\t\t\tpassword:   cCtx.String(\"password\"),\n\t\t\t\t\t\t\tdebug:      cCtx.Bool(\"debug\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t\tw := WindowFlags{}\n\t\t\t\t\t\tm.Init(nil, filters, g, w)\n\n\t\t\t\t\t\targs := cCtx.Args()\n\t\t\t\t\t\tif !args.Present() || args.Len() < 2 {\n\t\t\t\t\t\t\treturn errors.New(\"invalid number of arguments\")\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstoreID := args.First()\n\t\t\t\t\t\tkey := args.Get(1)\n\t\t\t\t\t\tvalue := args.Get(2)\n\t\t\t\t\t\tif value == \"\" {\n\t\t\t\t\t\t\tfmt.Printf(\"Enter secret value: \")\n\t\t\t\t\t\t\tb, err := term.ReadPassword(int(os.Stdin.Fd()))\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfmt.Println()\n\t\t\t\t\t\t\tvalue = string(b)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstore, err := m.GetSecretStore(storeID)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to get secret-store: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif err := store.Set(key, value); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unable to set secret: %w\", err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "cmd/telegraf/cmd_win_service.go",
    "content": "//go:build windows\n\n// Command handling for configuration \"service\" command\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/urfave/cli/v2\"\n\t\"golang.org/x/sys/windows\"\n)\n\nfunc cliFlags() []cli.Flag {\n\treturn []cli.Flag{\n\t\t&cli.StringFlag{\n\t\t\tName:  \"service\",\n\t\t\tUsage: \"operate on the service (windows only)\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"service-name\",\n\t\t\tValue: \"telegraf\",\n\t\t\tUsage: \"service name (windows only)\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"service-display-name\",\n\t\t\tValue: \"Telegraf Data Collector Service\",\n\t\t\tUsage: \"service display name (windows only)\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"service-restart-delay\",\n\t\t\tValue: \"5m\",\n\t\t},\n\t\t&cli.BoolFlag{\n\t\t\tName:  \"service-auto-restart\",\n\t\t\tUsage: \"auto restart service on failure (windows only)\",\n\t\t},\n\t\t&cli.BoolFlag{\n\t\t\tName:  \"console\",\n\t\t\tUsage: \"run as console application (windows only)\",\n\t\t},\n\t}\n}\n\nfunc getServiceCommands(outputBuffer io.Writer) []*cli.Command {\n\treturn []*cli.Command{\n\t\t{\n\t\t\tName:  \"service\",\n\t\t\tUsage: \"commands for operate on the Windows service\",\n\t\t\tFlags: nil,\n\t\t\tSubcommands: []*cli.Command{\n\t\t\t\t{\n\t\t\t\t\tName:  \"install\",\n\t\t\t\t\tUsage: \"install Telegraf as a Windows service\",\n\t\t\t\t\tDescription: `\nThe 'install' command with create a Windows service for automatically starting\nTelegraf with the specified configuration and service parameters. If no\nconfiguration(s) is specified the service will use the file in\n\"C:\\Program Files\\Telegraf\\telegraf.conf\".\n\nTo install Telegraf as a service use\n\n> telegraf service install\n\nIn case you are planning to start multiple Telegraf instances as a service,\nyou must use distinctive service-names for each instance. To install two\nservices with different configurations use\n\n> telegraf --config \"C:\\Program Files\\Telegraf\\telegraf-machine.conf\" --service-name telegraf-machine service install\n> telegraf --config \"C:\\Program Files\\Telegraf\\telegraf-service.conf\" --service-name telegraf-service service install\n`,\n\t\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\t\tName:  \"display-name\",\n\t\t\t\t\t\t\tValue: \"Telegraf Data Collector Service\",\n\t\t\t\t\t\t\tUsage: \"service name as displayed in the service manager\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\t\tName:  \"restart-delay\",\n\t\t\t\t\t\t\tValue: \"5m\",\n\t\t\t\t\t\t\tUsage: \"duration for delaying the service restart on failure\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\t\tName:  \"auto-restart\",\n\t\t\t\t\t\t\tUsage: \"enable automatic service restart on failure\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tcfg := &serviceConfig{\n\t\t\t\t\t\t\tdisplayName:  cCtx.String(\"display-name\"),\n\t\t\t\t\t\t\trestartDelay: cCtx.String(\"restart-delay\"),\n\t\t\t\t\t\t\tautoRestart:  cCtx.Bool(\"auto-restart\"),\n\n\t\t\t\t\t\t\tconfigs:    cCtx.StringSlice(\"config\"),\n\t\t\t\t\t\t\tconfigDirs: cCtx.StringSlice(\"config-directory\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t\tname := cCtx.String(\"service-name\")\n\t\t\t\t\t\tif err := installService(name, cfg); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Successfully installed service %q\\n\", name)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"uninstall\",\n\t\t\t\t\tUsage: \"remove the Telegraf Windows service\",\n\t\t\t\t\tDescription: `\nThe 'uninstall' command removes the Telegraf service with the given name. To\nremove a service use\n\n> telegraf service uninstall\n\nIn case you specified a custom service-name during install use\n\n> telegraf --service-name telegraf-machine service uninstall\n`,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tname := cCtx.String(\"service-name\")\n\t\t\t\t\t\tif err := uninstallService(name); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Successfully uninstalled service %q\\n\", name)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"start\",\n\t\t\t\t\tUsage: \"start the Telegraf Windows service\",\n\t\t\t\t\tDescription: `\nThe 'start' command triggers the start of the Windows service with the given\nname. To start the service either use the Windows service manager or run\n\n> telegraf service start\n\nIn case you specified a custom service-name during install use\n\n> telegraf --service-name telegraf-machine service start\n`,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tname := cCtx.String(\"service-name\")\n\t\t\t\t\t\tif err := startService(name); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Successfully started service %q\\n\", name)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"stop\",\n\t\t\t\t\tUsage: \"stop the Telegraf Windows service\",\n\t\t\t\t\tDescription: `\nThe 'stop' command triggers the stop of the Windows service with the given\nname and will wait until the service is actually stopped. To stop the service\neither use the Windows service manager or run\n\n> telegraf service stop\n\nIn case you specified a custom service-name during install use\n\n> telegraf --service-name telegraf-machine service stop\n`,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tname := cCtx.String(\"service-name\")\n\t\t\t\t\t\tif err := stopService(name); err != nil {\n\t\t\t\t\t\t\tif errors.Is(err, windows.ERROR_SERVICE_NOT_ACTIVE) {\n\t\t\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Service %q not started\\n\", name)\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Successfully stopped service %q\\n\", name)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"status\",\n\t\t\t\t\tUsage: \"query the Telegraf Windows service status\",\n\t\t\t\t\tDescription: `\nThe 'status' command queries the current state of the Windows service with the\ngiven name. To query the service either check the Windows service manager or run\n\n> telegraf service status\n\nIn case you specified a custom service-name during install use\n\n> telegraf --service-name telegraf-machine service status\n`,\n\t\t\t\t\tAction: func(cCtx *cli.Context) error {\n\t\t\t\t\t\tname := cCtx.String(\"service-name\")\n\t\t\t\t\t\tstatus, err := queryService(name)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Fprintf(outputBuffer, \"Service %q is in %q state\\n\", name, status)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "cmd/telegraf/cmd_win_service_notwindows.go",
    "content": "//go:build !windows\n\npackage main\n\nimport (\n\t\"io\"\n\n\t\"github.com/urfave/cli/v2\"\n)\n\nfunc cliFlags() []cli.Flag {\n\treturn make([]cli.Flag, 0)\n}\n\nfunc getServiceCommands(io.Writer) []*cli.Command {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/telegraf/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/awnumar/memguard\"\n\t\"github.com/fatih/color\"\n\t\"github.com/urfave/cli/v2\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/goplugin\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t_ \"github.com/influxdata/telegraf/plugins/aggregators/all\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/all\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/processors/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/secretstores/all\"\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/all\"\n)\n\ntype TelegrafConfig interface {\n\tCollectDeprecationInfos([]string, []string, []string, []string) map[string][]config.PluginDeprecationInfo\n\tPrintDeprecationList([]config.PluginDeprecationInfo)\n}\n\ntype Filters struct {\n\tsection     []string\n\tinput       []string\n\toutput      []string\n\taggregator  []string\n\tprocessor   []string\n\tsecretstore []string\n}\n\nfunc appendFilter(a, b string) string {\n\tif a != \"\" && b != \"\" {\n\t\treturn fmt.Sprintf(\"%s:%s\", a, b)\n\t}\n\tif a != \"\" {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc processFilterFlags(ctx *cli.Context) Filters {\n\tvar section, input, output, aggregator, processor, secretstore string\n\n\t// Support defining filters before and after the command\n\t// The old style was:\n\t// ./telegraf --section-filter inputs --input-filter cpu config >test.conf\n\t// The new style is:\n\t// ./telegraf config --section-filter inputs --input-filter cpu >test.conf\n\t// To support the old style, check if the parent context has the filter flags defined\n\tif len(ctx.Lineage()) >= 2 {\n\t\tparent := ctx.Lineage()[1] // ancestor contexts in order from child to parent\n\t\tsection = parent.String(\"section-filter\")\n\t\tinput = parent.String(\"input-filter\")\n\t\toutput = parent.String(\"output-filter\")\n\t\taggregator = parent.String(\"aggregator-filter\")\n\t\tprocessor = parent.String(\"processor-filter\")\n\t\tsecretstore = parent.String(\"secretstore-filter\")\n\t}\n\n\t// If both the parent and command filters are defined, append them together\n\tsection = appendFilter(section, ctx.String(\"section-filter\"))\n\tinput = appendFilter(input, ctx.String(\"input-filter\"))\n\toutput = appendFilter(output, ctx.String(\"output-filter\"))\n\taggregator = appendFilter(aggregator, ctx.String(\"aggregator-filter\"))\n\tprocessor = appendFilter(processor, ctx.String(\"processor-filter\"))\n\tsecretstore = appendFilter(secretstore, ctx.String(\"secretstore-filter\"))\n\n\tsectionFilters := deleteEmpty(strings.Split(section, \":\"))\n\tinputFilters := deleteEmpty(strings.Split(input, \":\"))\n\toutputFilters := deleteEmpty(strings.Split(output, \":\"))\n\taggregatorFilters := deleteEmpty(strings.Split(aggregator, \":\"))\n\tprocessorFilters := deleteEmpty(strings.Split(processor, \":\"))\n\tsecretstoreFilters := deleteEmpty(strings.Split(secretstore, \":\"))\n\treturn Filters{sectionFilters, inputFilters, outputFilters, aggregatorFilters, processorFilters, secretstoreFilters}\n}\n\nfunc deleteEmpty(s []string) []string {\n\tvar r []string\n\tfor _, str := range s {\n\t\tif str != \"\" {\n\t\t\tr = append(r, str)\n\t\t}\n\t}\n\treturn r\n}\n\n// runApp defines all the subcommands and flags for Telegraf\n// this abstraction is used for testing, so outputBuffer and args can be changed\nfunc runApp(args []string, outputBuffer io.Writer, pprof Server, c TelegrafConfig, m App) error {\n\tconfigHandlingFlags := []cli.Flag{\n\t\t&cli.StringSliceFlag{\n\t\t\tName:  \"config\",\n\t\t\tUsage: \"configuration file to load\",\n\t\t},\n\t\t&cli.StringSliceFlag{\n\t\t\tName:  \"config-directory\",\n\t\t\tUsage: \"directory containing additional *.conf files\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName: \"section-filter\",\n\t\t\tUsage: \"filter the sections to print, separator is ':'. \" +\n\t\t\t\t\"Valid values are 'agent', 'global_tags', 'outputs', 'processors', 'aggregators' and 'inputs'\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"input-filter\",\n\t\t\tUsage: \"filter the inputs to enable, separator is ':'\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"output-filter\",\n\t\t\tUsage: \"filter the outputs to enable, separator is ':'\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"aggregator-filter\",\n\t\t\tUsage: \"filter the aggregators to enable, separator is ':'\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"processor-filter\",\n\t\t\tUsage: \"filter the processors to enable, separator is ':'\",\n\t\t},\n\t\t&cli.StringFlag{\n\t\t\tName:  \"secretstore-filter\",\n\t\t\tUsage: \"filter the secret-stores to enable, separator is ':'\",\n\t\t},\n\t\t&cli.BoolFlag{\n\t\t\tName:  \"strict-env-handling\",\n\t\t\tUsage: \"enforces strict and secure handling of environment variables; will not work with non-string settings\",\n\t\t},\n\t\t&cli.BoolFlag{\n\t\t\tName:  \"non-strict-env-handling\",\n\t\t\tUsage: \"allow unsafe non-strict handling of environment variables to replace non-string settings\",\n\t\t},\n\t}\n\n\tmainFlags := append(configHandlingFlags, cliFlags()...)\n\n\t// This function is used when Telegraf is run with only flags\n\taction := func(cCtx *cli.Context) error {\n\t\t// We do not expect any arguments this is likely a misspelling of\n\t\t// a command...\n\t\tif cCtx.NArg() > 0 {\n\t\t\treturn fmt.Errorf(\"unknown command %q\", cCtx.Args().First())\n\t\t}\n\n\t\t// Deprecated: Use execd instead\n\t\t// Load external plugins, if requested.\n\t\tif cCtx.String(\"plugin-directory\") != \"\" {\n\t\t\tlog.Printf(\"I! Loading external plugins from: %s\", cCtx.String(\"plugin-directory\"))\n\t\t\tif err := goplugin.LoadExternalPlugins(cCtx.String(\"plugin-directory\")); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// switch for flags which just do something and exit immediately\n\t\tswitch {\n\t\t// print available input plugins\n\t\tcase cCtx.Bool(\"deprecation-list\"):\n\t\t\tfilters := processFilterFlags(cCtx)\n\t\t\tinfos := c.CollectDeprecationInfos(\n\t\t\t\tfilters.input, filters.output, filters.aggregator, filters.processor,\n\t\t\t)\n\t\t\toutputBuffer.Write([]byte(\"Deprecated Input Plugins:\\n\"))\n\t\t\tc.PrintDeprecationList(infos[\"inputs\"])\n\t\t\toutputBuffer.Write([]byte(\"Deprecated Output Plugins:\\n\"))\n\t\t\tc.PrintDeprecationList(infos[\"outputs\"])\n\t\t\toutputBuffer.Write([]byte(\"Deprecated Processor Plugins:\\n\"))\n\t\t\tc.PrintDeprecationList(infos[\"processors\"])\n\t\t\toutputBuffer.Write([]byte(\"Deprecated Aggregator Plugins:\\n\"))\n\t\t\tc.PrintDeprecationList(infos[\"aggregators\"])\n\t\t\treturn nil\n\t\t// print available output plugins\n\t\tcase cCtx.Bool(\"output-list\"):\n\t\t\toutputBuffer.Write([]byte(\"DEPRECATED: use telegraf plugins outputs\\n\"))\n\t\t\toutputBuffer.Write([]byte(\"Available Output Plugins:\\n\"))\n\t\t\tnames := make([]string, 0, len(outputs.Outputs))\n\t\t\tfor k := range outputs.Outputs {\n\t\t\t\tnames = append(names, k)\n\t\t\t}\n\t\t\tsort.Strings(names)\n\t\t\tfor _, k := range names {\n\t\t\t\tfmt.Fprintf(outputBuffer, \"  %s\\n\", k)\n\t\t\t}\n\t\t\treturn nil\n\t\t// print available input plugins\n\t\tcase cCtx.Bool(\"input-list\"):\n\t\t\toutputBuffer.Write([]byte(\"DEPRECATED: use telegraf plugins inputs\\n\"))\n\t\t\toutputBuffer.Write([]byte(\"Available Input Plugins:\\n\"))\n\t\t\tnames := make([]string, 0, len(inputs.Inputs))\n\t\t\tfor k := range inputs.Inputs {\n\t\t\t\tnames = append(names, k)\n\t\t\t}\n\t\t\tsort.Strings(names)\n\t\t\tfor _, k := range names {\n\t\t\t\tfmt.Fprintf(outputBuffer, \"  %s\\n\", k)\n\t\t\t}\n\t\t\treturn nil\n\t\t// print usage for a plugin, ie, 'telegraf --usage mysql'\n\t\tcase cCtx.String(\"usage\") != \"\":\n\t\t\terr := PrintInputConfig(cCtx.String(\"usage\"), outputBuffer)\n\t\t\terr2 := PrintOutputConfig(cCtx.String(\"usage\"), outputBuffer)\n\t\t\tif err != nil && err2 != nil {\n\t\t\t\treturn fmt.Errorf(\"%w and %w\", err, err2)\n\t\t\t}\n\t\t\treturn nil\n\t\t// DEPRECATED\n\t\tcase cCtx.Bool(\"version\"):\n\t\t\tfmt.Fprintf(outputBuffer, \"%s\\n\", internal.FormatFullVersion())\n\t\t\treturn nil\n\t\t// DEPRECATED\n\t\tcase cCtx.Bool(\"sample-config\"):\n\t\t\tfilters := processFilterFlags(cCtx)\n\n\t\t\tprintSampleConfig(outputBuffer, filters)\n\t\t\treturn nil\n\t\t}\n\n\t\tif cCtx.String(\"pprof-addr\") != \"\" {\n\t\t\tpprof.Start(cCtx.String(\"pprof-addr\"))\n\t\t}\n\n\t\tif cCtx.Bool(\"strict-env-handling\") && cCtx.Bool(\"non-strict-env-handling\") {\n\t\t\treturn errors.New(\"flags --strict-env-handling and --non-strict-env-handling cannot be used together\")\n\t\t}\n\t\tif !cCtx.Bool(\"strict-env-handling\") && !cCtx.Bool(\"non-strict-env-handling\") {\n\t\t\tmsg := \"Strict environment variable handling is the new default starting with v1.38.0! \" +\n\t\t\t\t\"If your configuration does not work with strict handling please explicitly add \" +\n\t\t\t\t\"the --non-strict-env-handling flag to switch to the previous behavior!\"\n\t\t\tlog.Println(\"W! \" + color.YellowString(msg))\n\t\t}\n\n\t\tif err := config.SetPluginLabelSelections(cCtx.StringSlice(\"select\")); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfilters := processFilterFlags(cCtx)\n\n\t\tg := GlobalFlags{\n\t\t\tconfig:                  cCtx.StringSlice(\"config\"),\n\t\t\tconfigDir:               cCtx.StringSlice(\"config-directory\"),\n\t\t\ttestWait:                cCtx.Int(\"test-wait\"),\n\t\t\tconfigURLRetryAttempts:  cCtx.Int(\"config-url-retry-attempts\"),\n\t\t\tconfigURLWatchInterval:  cCtx.Duration(\"config-url-watch-interval\"),\n\t\t\twatchConfig:             cCtx.String(\"watch-config\"),\n\t\t\twatchInterval:           cCtx.Duration(\"watch-interval\"),\n\t\t\twatchDebounceInterval:   cCtx.Duration(\"watch-debounce-interval\"),\n\t\t\tpidFile:                 cCtx.String(\"pidfile\"),\n\t\t\tplugindDir:              cCtx.String(\"plugin-directory\"),\n\t\t\tpassword:                cCtx.String(\"password\"),\n\t\t\toldEnvBehavior:          cCtx.Bool(\"old-env-behavior\"),\n\t\t\tnonStrictEnvVars:        cCtx.Bool(\"non-strict-env-handling\"),\n\t\t\tprintPluginConfigSource: cCtx.Bool(\"print-plugin-config-source\"),\n\t\t\ttest:                    cCtx.Bool(\"test\"),\n\t\t\tdebug:                   cCtx.Bool(\"debug\"),\n\t\t\tonce:                    cCtx.Bool(\"once\"),\n\t\t\tquiet:                   cCtx.Bool(\"quiet\"),\n\t\t\tunprotected:             cCtx.Bool(\"unprotected\"),\n\t\t}\n\n\t\tw := WindowFlags{\n\t\t\tservice:             cCtx.String(\"service\"),\n\t\t\tserviceName:         cCtx.String(\"service-name\"),\n\t\t\tserviceDisplayName:  cCtx.String(\"service-display-name\"),\n\t\t\tserviceRestartDelay: cCtx.String(\"service-restart-delay\"),\n\t\t\tserviceAutoRestart:  cCtx.Bool(\"service-auto-restart\"),\n\t\t\tconsole:             cCtx.Bool(\"console\"),\n\t\t}\n\n\t\tm.Init(pprof.ErrChan(), filters, g, w)\n\t\treturn m.Run()\n\t}\n\n\tcommands := append(\n\t\tgetConfigCommands(configHandlingFlags, outputBuffer),\n\t\tgetSecretStoreCommands(m)...,\n\t)\n\tcommands = append(commands, getPluginCommands(outputBuffer)...)\n\tcommands = append(commands, getServiceCommands(outputBuffer)...)\n\n\tapp := &cli.App{\n\t\tName:   \"Telegraf\",\n\t\tUsage:  \"The plugin-driven server agent for collecting & reporting metrics.\",\n\t\tWriter: outputBuffer,\n\t\tFlags: append(\n\t\t\t[]cli.Flag{\n\t\t\t\t// Int flags\n\t\t\t\t&cli.IntFlag{\n\t\t\t\t\tName:  \"test-wait\",\n\t\t\t\t\tUsage: \"wait up to this many seconds for service inputs to complete in test mode\",\n\t\t\t\t},\n\t\t\t\t&cli.IntFlag{\n\t\t\t\t\tName: \"config-url-retry-attempts\",\n\t\t\t\t\tUsage: \"Number of attempts to obtain a remote configuration via a URL during startup. \" +\n\t\t\t\t\t\t\"Set to -1 for unlimited attempts.\",\n\t\t\t\t\tDefaultText: \"3\",\n\t\t\t\t},\n\t\t\t\t//\n\t\t\t\t// String flags\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  \"usage\",\n\t\t\t\t\tUsage: \"print usage for a plugin, ie, 'telegraf --usage mysql'\",\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  \"pprof-addr\",\n\t\t\t\t\tUsage: \"pprof host/IP and port to listen on (e.g. 'localhost:6060')\",\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName: \"watch-config\",\n\t\t\t\t\tUsage: \"monitoring config changes [notify, poll] of --config and --config-directory options. \" +\n\t\t\t\t\t\t\"Notify supports linux, *bsd, and macOS. Poll is required for Windows and checks every 250ms.\",\n\t\t\t\t},\n\t\t\t\t&cli.DurationFlag{\n\t\t\t\t\tName:        \"watch-debounce-interval\",\n\t\t\t\t\tUsage:       \"Time duration to wait after a config change before reloading\",\n\t\t\t\t\tDefaultText: \"0s\",\n\t\t\t\t\tValue:       0,\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  \"pidfile\",\n\t\t\t\t\tUsage: \"file to write our pid to\",\n\t\t\t\t},\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  \"password\",\n\t\t\t\t\tUsage: \"password to unlock secret-stores\",\n\t\t\t\t},\n\t\t\t\t//\n\t\t\t\t// Bool flags\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"old-env-behavior\",\n\t\t\t\t\tUsage: \"switch back to pre v1.27 environment replacement behavior\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"print-plugin-config-source\",\n\t\t\t\t\tUsage: \"print the source for a given plugin\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"once\",\n\t\t\t\t\tUsage: \"run one gather and exit\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"debug\",\n\t\t\t\t\tUsage: \"turn on debug logging\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"quiet\",\n\t\t\t\t\tUsage: \"run in quiet mode\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"unprotected\",\n\t\t\t\t\tUsage: \"do not protect secrets in memory\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tUsage: \"enable test mode: gather metrics, print them out, and exit. \" +\n\t\t\t\t\t\t\"Note: Test mode only runs inputs, processors, and aggregators, but not outputs\",\n\t\t\t\t},\n\t\t\t\t&cli.StringSliceFlag{\n\t\t\t\t\tName: \"select\",\n\t\t\t\t\tUsage: \"enable only plugins with labels matching the given key-value selection. \" +\n\t\t\t\t\t\t\"If no selectors are provided, all plugins are enabled. Multiple key-value pairs \" +\n\t\t\t\t\t\t\"in an option will be combined by AND, multiple options are combined by OR. \" +\n\t\t\t\t\t\t\"Key and value are separated by an equal sign, multiple pairs are separated by \" +\n\t\t\t\t\t\t\"semi-colon, values do accept wildcards.\",\n\t\t\t\t},\n\t\t\t\t//\n\t\t\t\t// Duration flags\n\t\t\t\t&cli.DurationFlag{\n\t\t\t\t\tName: \"watch-interval\",\n\t\t\t\t\tUsage: \"Time duration to check for updates to config files specified by --config and \" +\n\t\t\t\t\t\t\"--config-directory options. Use with '--watch-config poll'\",\n\t\t\t\t\tDefaultText: \"disabled\",\n\t\t\t\t},\n\t\t\t\t&cli.DurationFlag{\n\t\t\t\t\tName:        \"config-url-watch-interval\",\n\t\t\t\t\tUsage:       \"Time duration to check for updates to URL based configuration files\",\n\t\t\t\t\tDefaultText: \"disabled\",\n\t\t\t\t},\n\t\t\t\t// TODO: Change \"deprecation-list, input-list, output-list\" flags to become a subcommand \"list\" that takes\n\t\t\t\t// \"input,output,aggregator,processor, deprecated\" as parameters\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"deprecation-list\",\n\t\t\t\t\tUsage: \"print all deprecated plugins or plugin options\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"input-list\",\n\t\t\t\t\tUsage: \"print available input plugins\",\n\t\t\t\t},\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"output-list\",\n\t\t\t\t\tUsage: \"print available output plugins\",\n\t\t\t\t},\n\t\t\t\t//\n\t\t\t\t// !!! The following flags are DEPRECATED !!!\n\t\t\t\t// Already covered with the subcommand `./telegraf version`\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"version\",\n\t\t\t\t\tUsage: \"DEPRECATED: display the version and exit\",\n\t\t\t\t},\n\t\t\t\t// Already covered with the subcommand `./telegraf config`\n\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\tName:  \"sample-config\",\n\t\t\t\t\tUsage: \"DEPRECATED: print out full sample configuration\",\n\t\t\t\t},\n\t\t\t\t// Using execd plugin to add external plugins is preferred (less size impact, easier for end user)\n\t\t\t\t&cli.StringFlag{\n\t\t\t\t\tName:  \"plugin-directory\",\n\t\t\t\t\tUsage: \"DEPRECATED: path to directory containing external plugins\",\n\t\t\t\t},\n\t\t\t\t// !!!\n\t\t\t}, mainFlags...),\n\t\tAction: action,\n\t\tCommands: append([]*cli.Command{\n\t\t\t{\n\t\t\t\tName:  \"version\",\n\t\t\t\tUsage: \"print current version to stdout\",\n\t\t\t\tAction: func(*cli.Context) error {\n\t\t\t\t\tfmt.Fprintf(outputBuffer, \"%s\\n\", internal.FormatFullVersion())\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t}, commands...),\n\t}\n\n\t// Make sure we safely erase secrets\n\tdefer memguard.Purge()\n\tdefer logger.CloseLogging()\n\n\tif err := app.Run(args); err != nil {\n\t\tlog.Printf(\"E! %s\", err)\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc main() {\n\t// #13481: disables gh:99designs/keyring kwallet.go from connecting to dbus\n\tos.Setenv(\"DISABLE_KWALLET\", \"1\")\n\n\tagent := Telegraf{}\n\tpprof := NewPprofServer()\n\tc := config.NewConfig()\n\tif err := runApp(os.Args, os.Stdout, pprof, c, &agent); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "cmd/telegraf/main_test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n)\n\nvar secrets = map[string]map[string][]byte{\n\t\"yoda\": {\n\t\t\"episode1\": []byte(\"member\"),\n\t\t\"episode2\": []byte(\"member\"),\n\t\t\"episode3\": []byte(\"member\"),\n\t},\n\t\"mace_windu\": {\n\t\t\"episode1\": []byte(\"member\"),\n\t\t\"episode2\": []byte(\"member\"),\n\t\t\"episode3\": []byte(\"member\"),\n\t},\n\t\"oppo_rancisis\": {\n\t\t\"episode1\": []byte(\"member\"),\n\t\t\"episode2\": []byte(\"member\"),\n\t},\n\t\"coleman_kcaj\": {\n\t\t\"episode3\": []byte(\"member\"),\n\t},\n}\n\ntype MockTelegraf struct {\n\tGlobalFlags\n\tWindowFlags\n}\n\nfunc NewMockTelegraf() *MockTelegraf {\n\treturn &MockTelegraf{}\n}\n\nfunc (m *MockTelegraf) Init(_ <-chan error, _ Filters, g GlobalFlags, w WindowFlags) {\n\tm.GlobalFlags = g\n\tm.WindowFlags = w\n}\n\nfunc (*MockTelegraf) Run() error {\n\treturn nil\n}\n\nfunc (*MockTelegraf) ListSecretStores() ([]string, error) {\n\tids := make([]string, 0, len(secrets))\n\tfor k := range secrets {\n\t\tids = append(ids, k)\n\t}\n\treturn ids, nil\n}\n\nfunc (*MockTelegraf) GetSecretStore(id string) (telegraf.SecretStore, error) {\n\tv, found := secrets[id]\n\tif !found {\n\t\treturn nil, errors.New(\"unknown secret store\")\n\t}\n\ts := &MockSecretStore{Secrets: v}\n\treturn s, nil\n}\n\ntype MockSecretStore struct {\n\tSecrets map[string][]byte\n}\n\nfunc (*MockSecretStore) Init() error {\n\treturn nil\n}\n\nfunc (*MockSecretStore) SampleConfig() string {\n\treturn \"I'm just a dummy\"\n}\n\nfunc (s *MockSecretStore) Get(key string) ([]byte, error) {\n\tv, found := s.Secrets[key]\n\tif !found {\n\t\treturn nil, errors.New(\"not found\")\n\t}\n\treturn v, nil\n}\n\nfunc (s *MockSecretStore) Set(key, value string) error {\n\tif strings.HasPrefix(key, \"darth\") {\n\t\treturn errors.New(\"don't join the dark side\")\n\t}\n\ts.Secrets[key] = []byte(value)\n\treturn nil\n}\nfunc (s *MockSecretStore) List() ([]string, error) {\n\tkeys := make([]string, 0, len(s.Secrets))\n\tfor k := range s.Secrets {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys, nil\n}\n\nfunc (s *MockSecretStore) GetResolver(key string) (telegraf.ResolveFunc, error) {\n\treturn func() ([]byte, bool, error) {\n\t\tv, err := s.Get(key)\n\t\treturn v, false, err\n\t}, nil\n}\n\ntype MockConfig struct {\n\tBuffer                    io.Writer\n\tExpectedDeprecatedPlugins map[string][]config.PluginDeprecationInfo\n}\n\nfunc NewMockConfig(buffer io.Writer) *MockConfig {\n\treturn &MockConfig{\n\t\tBuffer: buffer,\n\t}\n}\n\nfunc (m *MockConfig) CollectDeprecationInfos(_, _, _, _ []string) map[string][]config.PluginDeprecationInfo {\n\treturn m.ExpectedDeprecatedPlugins\n}\n\nfunc (m *MockConfig) PrintDeprecationList(plugins []config.PluginDeprecationInfo) {\n\tfor _, p := range plugins {\n\t\tfmt.Fprintf(m.Buffer, \"plugin name: %s\\n\", p.Name)\n\t}\n}\n\ntype MockServer struct {\n\tAddress string\n}\n\nfunc NewMockServer() *MockServer {\n\treturn &MockServer{}\n}\n\nfunc (m *MockServer) Start(_ string) {\n\tm.Address = \"localhost:6060\"\n}\n\nfunc (*MockServer) ErrChan() <-chan error {\n\treturn nil\n}\n\nfunc TestUsageFlag(t *testing.T) {\n\ttests := []struct {\n\t\tPluginName     string\n\t\tExpectedError  string\n\t\tExpectedOutput string\n\t}{\n\t\t{\n\t\t\tPluginName:    \"example\",\n\t\t\tExpectedError: \"input example not found and output example not found\",\n\t\t},\n\t\t{\n\t\t\tPluginName: \"temp\",\n\t\t\tExpectedOutput: `\n# Read metrics about temperature\n[[inputs.temp]]\n  ## Desired output format (Linux only)\n  ## Available values are\n  ##   v1 -- use pre-v1.22.4 sensor naming, e.g. coretemp_core0_input\n  ##   v2 -- use v1.22.4+ sensor naming, e.g. coretemp_core_0_input\n  # metric_format = \"v2\"\n\n  ## Add device tag to distinguish devices with the same name (Linux only)\n  # add_device_tag = false\n\n`,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tbuf := new(bytes.Buffer)\n\t\targs := os.Args[0:1]\n\t\targs = append(args, \"--usage\", test.PluginName)\n\t\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\t\tif test.ExpectedError != \"\" {\n\t\t\trequire.ErrorContains(t, err, test.ExpectedError)\n\t\t\tcontinue\n\t\t}\n\t\trequire.NoError(t, err)\n\t\t// To run this test on windows and linux, remove windows carriage return\n\t\to := strings.Replace(buf.String(), \"\\r\", \"\", -1)\n\t\trequire.Equal(t, test.ExpectedOutput, o)\n\t}\n}\n\nfunc TestInputListFlag(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, \"--input-list\")\n\ttemp := inputs.Inputs\n\tinputs.Inputs = map[string]inputs.Creator{\n\t\t\"test\": func() telegraf.Input { return nil },\n\t}\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\trequire.NoError(t, err)\n\texpectedOutput := `DEPRECATED: use telegraf plugins inputs\nAvailable Input Plugins:\n  test\n`\n\trequire.Equal(t, expectedOutput, buf.String())\n\tinputs.Inputs = temp\n}\n\nfunc TestOutputListFlag(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, \"--output-list\")\n\ttemp := outputs.Outputs\n\toutputs.Outputs = map[string]outputs.Creator{\n\t\t\"test\": func() telegraf.Output { return nil },\n\t}\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\trequire.NoError(t, err)\n\texpectedOutput := `DEPRECATED: use telegraf plugins outputs\nAvailable Output Plugins:\n  test\n`\n\trequire.Equal(t, expectedOutput, buf.String())\n\toutputs.Outputs = temp\n}\n\nfunc TestDeprecationListFlag(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, \"--deprecation-list\")\n\tmS := NewMockServer()\n\tmC := NewMockConfig(buf)\n\tmC.ExpectedDeprecatedPlugins = make(map[string][]config.PluginDeprecationInfo)\n\tmC.ExpectedDeprecatedPlugins[\"inputs\"] = []config.PluginDeprecationInfo{\n\t\t{\n\t\t\tDeprecationInfo: config.DeprecationInfo{\n\t\t\t\tName: \"test\",\n\t\t\t},\n\t\t},\n\t}\n\terr := runApp(args, buf, mS, mC, NewMockTelegraf())\n\trequire.NoError(t, err)\n\texpectedOutput := `Deprecated Input Plugins:\nplugin name: test\nDeprecated Output Plugins:\nDeprecated Processor Plugins:\nDeprecated Aggregator Plugins:\n`\n\n\trequire.Equal(t, expectedOutput, buf.String())\n}\n\nfunc TestPprofAddressFlag(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\taddress := \"localhost:6060\"\n\targs = append(args, \"--pprof-addr\", address)\n\tm := NewMockServer()\n\terr := runApp(args, buf, m, NewMockConfig(buf), NewMockTelegraf())\n\trequire.NoError(t, err)\n\trequire.Equal(t, address, m.Address)\n}\n\n// !!! DEPRECATED !!!\n// TestPluginDirectoryFlag tests `--plugin-directory`\nfunc TestPluginDirectoryFlag(t *testing.T) {\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, \"--plugin-directory\", \".\")\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\trequire.ErrorContains(t, err, \"go plugin support is not enabled\")\n}\n\nfunc TestCommandConfig(t *testing.T) {\n\ttests := []struct {\n\t\tname            string\n\t\tcommands        []string\n\t\texpectedHeaders []string\n\t\tremovedHeaders  []string\n\t\texpectedPlugins []string\n\t\tremovedPlugins  []string\n\t}{\n\t\t{\n\t\t\tname:     \"deprecated flag --sample-config\",\n\t\t\tcommands: []string{\"--sample-config\"},\n\t\t\texpectedHeaders: []string{\n\t\t\t\toutputHeader,\n\t\t\t\tinputHeader,\n\t\t\t\taggregatorHeader,\n\t\t\t\tprocessorHeader,\n\t\t\t\tserviceInputHeader,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"no filters\",\n\t\t\tcommands: []string{\"config\"},\n\t\t\texpectedHeaders: []string{\n\t\t\t\toutputHeader,\n\t\t\t\tinputHeader,\n\t\t\t\taggregatorHeader,\n\t\t\t\tprocessorHeader,\n\t\t\t\tserviceInputHeader,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter sections for inputs\",\n\t\t\tcommands: []string{\"config\", \"--section-filter\", \"inputs\"},\n\t\t\texpectedHeaders: []string{\n\t\t\t\tinputHeader,\n\t\t\t},\n\t\t\tremovedHeaders: []string{\n\t\t\t\toutputHeader,\n\t\t\t\taggregatorHeader,\n\t\t\t\tprocessorHeader,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter sections for inputs,outputs\",\n\t\t\tcommands: []string{\"config\", \"--section-filter\", \"inputs:outputs\"},\n\t\t\texpectedHeaders: []string{\n\t\t\t\tinputHeader,\n\t\t\t\toutputHeader,\n\t\t\t},\n\t\t\tremovedHeaders: []string{\n\t\t\t\taggregatorHeader,\n\t\t\t\tprocessorHeader,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter input plugins\",\n\t\t\tcommands: []string{\"config\", \"--input-filter\", \"cpu:file\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[inputs.cpu]]\",\n\t\t\t\t\"[[inputs.file]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[inputs.disk]]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter output plugins\",\n\t\t\tcommands: []string{\"config\", \"--output-filter\", \"influxdb:http\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[outputs.influxdb]]\",\n\t\t\t\t\"[[outputs.http]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[outputs.file]]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter processor plugins\",\n\t\t\tcommands: []string{\"config\", \"--processor-filter\", \"date:enum\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[processors.date]]\",\n\t\t\t\t\"[[processors.enum]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[processors.parser]]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"filter aggregator plugins\",\n\t\t\tcommands: []string{\"config\", \"--aggregator-filter\", \"basicstats:starlark\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[aggregators.basicstats]]\",\n\t\t\t\t\"[[aggregators.starlark]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[aggregators.minmax]]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"test filters before config\",\n\t\t\tcommands: []string{\"--input-filter\", \"cpu:file\", \"config\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[inputs.cpu]]\",\n\t\t\t\t\"[[inputs.file]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[inputs.disk]]\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"test filters before and after config\",\n\t\t\tcommands: []string{\"--input-filter\", \"file\", \"config\", \"--input-filter\", \"cpu\"},\n\t\t\texpectedPlugins: []string{\n\t\t\t\t\"[[inputs.cpu]]\",\n\t\t\t\t\"[[inputs.file]]\",\n\t\t\t},\n\t\t\tremovedPlugins: []string{\n\t\t\t\t\"[[inputs.disk]]\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tbuf := new(bytes.Buffer)\n\t\t\targs := os.Args[0:1]\n\t\t\targs = append(args, test.commands...)\n\t\t\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\t\t\trequire.NoError(t, err)\n\t\t\toutput := buf.String()\n\t\t\tfor _, e := range test.expectedHeaders {\n\t\t\t\trequire.Contains(t, output, e, \"expected header not found\")\n\t\t\t}\n\t\t\tfor _, r := range test.removedHeaders {\n\t\t\t\trequire.NotContains(t, output, r, \"removed header found\")\n\t\t\t}\n\t\t\tfor _, e := range test.expectedPlugins {\n\t\t\t\trequire.Contains(t, output, e, \"expected plugin not found\")\n\t\t\t}\n\t\t\tfor _, r := range test.removedPlugins {\n\t\t\t\trequire.NotContains(t, output, r, \"removed plugin found\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCommandVersion(t *testing.T) {\n\ttests := []struct {\n\t\tVersion        string\n\t\tBranch         string\n\t\tCommit         string\n\t\tExpectedOutput string\n\t}{\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0\\n\",\n\t\t},\n\t\t{\n\t\t\tExpectedOutput: \"Telegraf unknown\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tBranch:         \"master\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: master@unknown)\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tBranch:         \"master\",\n\t\t\tCommit:         \"123\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: master@123)\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tCommit:         \"123\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: unknown@123)\\n\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tbuf := new(bytes.Buffer)\n\t\targs := os.Args[0:1]\n\t\targs = append(args, \"version\")\n\t\tinternal.Version = test.Version\n\t\tinternal.Branch = test.Branch\n\t\tinternal.Commit = test.Commit\n\t\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, test.ExpectedOutput, buf.String())\n\t}\n}\n\n// Users should use the version subcommand\nfunc TestFlagVersion(t *testing.T) {\n\ttests := []struct {\n\t\tVersion        string\n\t\tBranch         string\n\t\tCommit         string\n\t\tExpectedOutput string\n\t}{\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0\\n\",\n\t\t},\n\t\t{\n\t\t\tExpectedOutput: \"Telegraf unknown\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tBranch:         \"master\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: master@unknown)\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tBranch:         \"master\",\n\t\t\tCommit:         \"123\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: master@123)\\n\",\n\t\t},\n\t\t{\n\t\t\tVersion:        \"v2.0.0\",\n\t\t\tCommit:         \"123\",\n\t\t\tExpectedOutput: \"Telegraf v2.0.0 (git: unknown@123)\\n\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tbuf := new(bytes.Buffer)\n\t\targs := os.Args[0:1]\n\t\targs = append(args, \"--version\")\n\t\tinternal.Version = test.Version\n\t\tinternal.Branch = test.Branch\n\t\tinternal.Commit = test.Commit\n\t\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, test.ExpectedOutput, buf.String())\n\t}\n}\n\nfunc TestGlobablBoolFlags(t *testing.T) {\n\tcommands := []string{\n\t\t\"--debug\",\n\t\t\"--test\",\n\t\t\"--quiet\",\n\t\t\"--once\",\n\t}\n\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, commands...)\n\tm := NewMockTelegraf()\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m)\n\trequire.NoError(t, err)\n\n\trequire.True(t, m.debug)\n\trequire.True(t, m.test)\n\trequire.True(t, m.once)\n\trequire.True(t, m.quiet)\n}\n\nfunc TestFlagsAreSet(t *testing.T) {\n\texpectedInt := 1\n\texpectedString := \"test\"\n\n\tcommands := []string{\n\t\t\"--config\", expectedString,\n\t\t\"--config-directory\", expectedString,\n\t\t\"--debug\",\n\t\t\"--test\",\n\t\t\"--quiet\",\n\t\t\"--once\",\n\t\t\"--test-wait\", strconv.Itoa(expectedInt),\n\t\t\"--watch-config\", expectedString,\n\t\t\"--pidfile\", expectedString,\n\t}\n\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, commands...)\n\tm := NewMockTelegraf()\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, []string{expectedString}, m.config)\n\trequire.Equal(t, []string{expectedString}, m.configDir)\n\trequire.True(t, m.debug)\n\trequire.True(t, m.test)\n\trequire.True(t, m.once)\n\trequire.True(t, m.quiet)\n\trequire.Equal(t, expectedInt, m.testWait)\n\trequire.Equal(t, expectedString, m.watchConfig)\n\trequire.Equal(t, expectedString, m.pidFile)\n}\n"
  },
  {
    "path": "cmd/telegraf/main_win_test.go",
    "content": "//go:build windows\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestWindowsFlagsAreSet(t *testing.T) {\n\texpectedString := \"test\"\n\n\tcommands := []string{\n\t\t\"--service\", expectedString,\n\t\t\"--service-name\", expectedString,\n\t\t\"--service-display-name\", expectedString,\n\t\t\"--service-restart-delay\", expectedString,\n\t\t\"--service-auto-restart\",\n\t\t\"--console\",\n\t}\n\n\tbuf := new(bytes.Buffer)\n\targs := os.Args[0:1]\n\targs = append(args, commands...)\n\tm := NewMockTelegraf()\n\terr := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, expectedString, m.service)\n\trequire.Equal(t, expectedString, m.serviceName)\n\trequire.Equal(t, expectedString, m.serviceDisplayName)\n\trequire.Equal(t, expectedString, m.serviceRestartDelay)\n\trequire.True(t, m.serviceAutoRestart)\n\trequire.True(t, m.console)\n}\n"
  },
  {
    "path": "cmd/telegraf/pprof.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\" //nolint:gosec // Import for pprof, only enabled via CLI flag\n\t\"strings\"\n\t\"time\"\n)\n\ntype Server interface {\n\tStart(string)\n\tErrChan() <-chan error\n}\n\ntype PprofServer struct {\n\terr chan error\n}\n\nfunc NewPprofServer() *PprofServer {\n\treturn &PprofServer{\n\t\terr: make(chan error),\n\t}\n}\n\nfunc (p *PprofServer) Start(address string) {\n\tgo func() {\n\t\tpprofHostPort := address\n\t\tparts := strings.Split(pprofHostPort, \":\")\n\t\tif len(parts) == 2 && parts[0] == \"\" {\n\t\t\tpprofHostPort = \"localhost:\" + parts[1]\n\t\t}\n\t\tpprofHostPort = \"http://\" + pprofHostPort + \"/debug/pprof\"\n\n\t\tlog.Printf(\"I! Starting pprof HTTP server at: %s\", pprofHostPort)\n\n\t\tserver := &http.Server{\n\t\t\tAddr:         address,\n\t\t\tReadTimeout:  10 * time.Second,\n\t\t\tWriteTimeout: 10 * time.Second,\n\t\t}\n\n\t\tif err := server.ListenAndServe(); err != nil {\n\t\t\tp.err <- err\n\t\t}\n\t\tclose(p.err)\n\t}()\n}\n\nfunc (p *PprofServer) ErrChan() <-chan error {\n\treturn p.err\n}\n"
  },
  {
    "path": "cmd/telegraf/printer.go",
    "content": "package main\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/secretstores\"\n)\n\nvar (\n\t// Default sections\n\tsectionDefaults = []string{\"global_tags\", \"agent\", \"secretstores\", \"outputs\", \"processors\", \"aggregators\", \"inputs\"}\n\n\t// Default input plugins\n\tinputDefaults = []string{\"cpu\", \"mem\", \"swap\", \"system\", \"kernel\", \"processes\", \"disk\", \"diskio\"}\n\n\t// Default output plugins\n\toutputDefaults = make([]string, 0)\n)\n\nvar header = `# Telegraf Configuration\n#\n# Telegraf is entirely plugin driven. All metrics are gathered from the\n# declared inputs, and sent to the declared outputs.\n#\n# Plugins must be declared in here to be active.\n# To deactivate a plugin, comment out the name and any variables.\n#\n# Use 'telegraf -config telegraf.conf -test' to see what metrics a config\n# file would generate.\n#\n# Environment variables can be used anywhere in this config file, simply surround\n# them with ${}. For strings the variable must be within quotes (ie, \"${STR_VAR}\"),\n# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})\n\n`\nvar globalTagsConfig = `\n# Global tags can be specified here in key=\"value\" format.\n[global_tags]\n  # dc = \"us-east-1\" # will tag all metrics with dc=us-east-1\n  # rack = \"1a\"\n  ## Environment variables can be used as tags, and throughout the config file\n  # user = \"$USER\"\n\n`\n\n// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the agentConfig data.\n//\n//go:embed agent.conf\nvar agentConfig string\n\nvar secretstoreHeader = `\n###############################################################################\n#                            SECRETSTORE PLUGINS                              #\n###############################################################################\n\n`\n\nvar outputHeader = `\n###############################################################################\n#                            OUTPUT PLUGINS                                   #\n###############################################################################\n\n`\n\nvar processorHeader = `\n###############################################################################\n#                            PROCESSOR PLUGINS                                #\n###############################################################################\n\n`\n\nvar aggregatorHeader = `\n###############################################################################\n#                            AGGREGATOR PLUGINS                               #\n###############################################################################\n\n`\n\nvar inputHeader = `\n###############################################################################\n#                            INPUT PLUGINS                                    #\n###############################################################################\n\n`\n\nvar serviceInputHeader = `\n###############################################################################\n#                            SERVICE INPUT PLUGINS                            #\n###############################################################################\n\n`\n\n// printSampleConfig prints the sample config\nfunc printSampleConfig(outputBuffer io.Writer, filters Filters) {\n\tsectionFilters := filters.section\n\tinputFilters := filters.input\n\toutputFilters := filters.output\n\taggregatorFilters := filters.aggregator\n\tprocessorFilters := filters.processor\n\tsecretstoreFilters := filters.secretstore\n\n\t// print headers\n\toutputBuffer.Write([]byte(header))\n\n\tif len(sectionFilters) == 0 {\n\t\tsectionFilters = sectionDefaults\n\t}\n\tprintFilteredGlobalSections(sectionFilters, outputBuffer)\n\n\t// print secretstore plugins\n\tif choice.Contains(\"secretstores\", sectionFilters) {\n\t\tif len(secretstoreFilters) != 0 {\n\t\t\tif len(secretstoreFilters) >= 3 && secretstoreFilters[1] != \"none\" {\n\t\t\t\tfmt.Print(secretstoreHeader)\n\t\t\t}\n\t\t\tprintFilteredSecretstores(secretstoreFilters, false, outputBuffer)\n\t\t} else {\n\t\t\tfmt.Print(secretstoreHeader)\n\t\t\tsnames := make([]string, 0, len(secretstores.SecretStores))\n\t\t\tfor sname := range secretstores.SecretStores {\n\t\t\t\tsnames = append(snames, sname)\n\t\t\t}\n\t\t\tsort.Strings(snames)\n\t\t\tprintFilteredSecretstores(snames, true, outputBuffer)\n\t\t}\n\t}\n\n\t// print output plugins\n\tif choice.Contains(\"outputs\", sectionFilters) {\n\t\tif len(outputFilters) != 0 {\n\t\t\tif len(outputFilters) >= 3 && outputFilters[1] != \"none\" {\n\t\t\t\toutputBuffer.Write([]byte(outputHeader))\n\t\t\t}\n\t\t\tprintFilteredOutputs(outputFilters, false, outputBuffer)\n\t\t} else {\n\t\t\toutputBuffer.Write([]byte(outputHeader))\n\t\t\tprintFilteredOutputs(outputDefaults, false, outputBuffer)\n\t\t\t// Print non-default outputs, commented\n\t\t\tvar pnames []string\n\t\t\tfor pname := range outputs.Outputs {\n\t\t\t\tif !choice.Contains(pname, outputDefaults) {\n\t\t\t\t\tpnames = append(pnames, pname)\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintFilteredOutputs(pnames, true, outputBuffer)\n\t\t}\n\t}\n\n\t// print processor plugins\n\tif choice.Contains(\"processors\", sectionFilters) {\n\t\tif len(processorFilters) != 0 {\n\t\t\tif len(processorFilters) >= 3 && processorFilters[1] != \"none\" {\n\t\t\t\toutputBuffer.Write([]byte(processorHeader))\n\t\t\t}\n\t\t\tprintFilteredProcessors(processorFilters, false, outputBuffer)\n\t\t} else {\n\t\t\toutputBuffer.Write([]byte(processorHeader))\n\t\t\tpnames := make([]string, 0, len(processors.Processors))\n\t\t\tfor pname := range processors.Processors {\n\t\t\t\tpnames = append(pnames, pname)\n\t\t\t}\n\t\t\tprintFilteredProcessors(pnames, true, outputBuffer)\n\t\t}\n\t}\n\n\t// print aggregator plugins\n\tif choice.Contains(\"aggregators\", sectionFilters) {\n\t\tif len(aggregatorFilters) != 0 {\n\t\t\tif len(aggregatorFilters) >= 3 && aggregatorFilters[1] != \"none\" {\n\t\t\t\toutputBuffer.Write([]byte(aggregatorHeader))\n\t\t\t}\n\t\t\tprintFilteredAggregators(aggregatorFilters, false, outputBuffer)\n\t\t} else {\n\t\t\toutputBuffer.Write([]byte(aggregatorHeader))\n\t\t\tpnames := make([]string, 0, len(aggregators.Aggregators))\n\t\t\tfor pname := range aggregators.Aggregators {\n\t\t\t\tpnames = append(pnames, pname)\n\t\t\t}\n\t\t\tprintFilteredAggregators(pnames, true, outputBuffer)\n\t\t}\n\t}\n\n\t// print input plugins\n\tif choice.Contains(\"inputs\", sectionFilters) {\n\t\tif len(inputFilters) != 0 {\n\t\t\tif len(inputFilters) >= 3 && inputFilters[1] != \"none\" {\n\t\t\t\toutputBuffer.Write([]byte(inputHeader))\n\t\t\t}\n\t\t\tprintFilteredInputs(inputFilters, false, outputBuffer)\n\t\t} else {\n\t\t\toutputBuffer.Write([]byte(inputHeader))\n\t\t\tprintFilteredInputs(inputDefaults, false, outputBuffer)\n\t\t\t// Print non-default inputs, commented\n\t\t\tvar pnames []string\n\t\t\tfor pname := range inputs.Inputs {\n\t\t\t\tif !choice.Contains(pname, inputDefaults) {\n\t\t\t\t\tpnames = append(pnames, pname)\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintFilteredInputs(pnames, true, outputBuffer)\n\t\t}\n\t}\n}\n\nfunc printFilteredProcessors(processorFilters []string, commented bool, outputBuffer io.Writer) {\n\t// Filter processors\n\tvar pnames []string\n\tfor pname := range processors.Processors {\n\t\tif choice.Contains(pname, processorFilters) {\n\t\t\tpnames = append(pnames, pname)\n\t\t}\n\t}\n\tsort.Strings(pnames)\n\n\t// Print Outputs\n\tfor _, pname := range pnames {\n\t\tcreator := processors.Processors[pname]\n\t\toutput := creator()\n\t\tprintConfig(pname, output, \"processors\", commented, processors.Deprecations[pname], outputBuffer)\n\t}\n}\n\nfunc printFilteredAggregators(aggregatorFilters []string, commented bool, outputBuffer io.Writer) {\n\t// Filter outputs\n\tvar anames []string\n\tfor aname := range aggregators.Aggregators {\n\t\tif choice.Contains(aname, aggregatorFilters) {\n\t\t\tanames = append(anames, aname)\n\t\t}\n\t}\n\tsort.Strings(anames)\n\n\t// Print Outputs\n\tfor _, aname := range anames {\n\t\tcreator := aggregators.Aggregators[aname]\n\t\toutput := creator()\n\t\tprintConfig(aname, output, \"aggregators\", commented, aggregators.Deprecations[aname], outputBuffer)\n\t}\n}\n\nfunc printFilteredInputs(inputFilters []string, commented bool, outputBuffer io.Writer) {\n\t// Filter inputs\n\tvar pnames []string\n\tfor pname := range inputs.Inputs {\n\t\tif choice.Contains(pname, inputFilters) {\n\t\t\tpnames = append(pnames, pname)\n\t\t}\n\t}\n\tsort.Strings(pnames)\n\n\t// cache service inputs to print them at the end\n\tservInputs := make(map[string]telegraf.ServiceInput)\n\t// for alphabetical looping:\n\tservInputNames := make([]string, 0, len(pnames))\n\n\t// Print Inputs\n\tfor _, pname := range pnames {\n\t\t// Skip inputs that are registered twice for backward compatibility\n\t\tswitch pname {\n\t\tcase \"cisco_telemetry_gnmi\", \"http_listener\", \"io\":\n\t\t\tcontinue\n\t\t}\n\t\tcreator := inputs.Inputs[pname]\n\t\tinput := creator()\n\n\t\tif p, ok := input.(telegraf.ServiceInput); ok {\n\t\t\tservInputs[pname] = p\n\t\t\tservInputNames = append(servInputNames, pname)\n\t\t\tcontinue\n\t\t}\n\n\t\tprintConfig(pname, input, \"inputs\", commented, inputs.Deprecations[pname], outputBuffer)\n\t}\n\n\t// Print Service Inputs\n\tif len(servInputs) == 0 {\n\t\treturn\n\t}\n\tsort.Strings(servInputNames)\n\n\toutputBuffer.Write([]byte(serviceInputHeader))\n\tfor _, name := range servInputNames {\n\t\tprintConfig(name, servInputs[name], \"inputs\", commented, inputs.Deprecations[name], outputBuffer)\n\t}\n}\n\nfunc printFilteredOutputs(outputFilters []string, commented bool, outputBuffer io.Writer) {\n\t// Filter outputs\n\tvar onames []string\n\tvar influxdbV2 string\n\n\tfor oname := range outputs.Outputs {\n\t\tif choice.Contains(oname, outputFilters) {\n\t\t\t// Make influxdb_v2 the exception and have it be first in the list\n\t\t\t// Store it and add it later\n\t\t\tif oname == \"influxdb_v2\" {\n\t\t\t\tinfluxdbV2 = oname\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tonames = append(onames, oname)\n\t\t}\n\t}\n\tsort.Strings(onames)\n\n\tif influxdbV2 != \"\" {\n\t\tonames = append([]string{influxdbV2}, onames...)\n\t}\n\n\t// Print Outputs\n\tfor _, oname := range onames {\n\t\tcreator := outputs.Outputs[oname]\n\t\toutput := creator()\n\t\tprintConfig(oname, output, \"outputs\", commented, outputs.Deprecations[oname], outputBuffer)\n\t}\n}\n\nfunc printFilteredSecretstores(secretstoreFilters []string, commented bool, outputBuffer io.Writer) {\n\t// Filter secretstores\n\tvar snames []string\n\tfor sname := range secretstores.SecretStores {\n\t\tif choice.Contains(sname, secretstoreFilters) {\n\t\t\tsnames = append(snames, sname)\n\t\t}\n\t}\n\tsort.Strings(snames)\n\n\t// Print SecretStores\n\tfor _, sname := range snames {\n\t\tcreator := secretstores.SecretStores[sname]\n\t\tstore := creator(\"dummy\")\n\t\tprintConfig(sname, store, \"secretstores\", commented, secretstores.Deprecations[sname], outputBuffer)\n\t}\n}\n\nfunc printFilteredGlobalSections(sectionFilters []string, outputBuffer io.Writer) {\n\tif choice.Contains(\"global_tags\", sectionFilters) {\n\t\toutputBuffer.Write([]byte(globalTagsConfig))\n\t}\n\n\tif choice.Contains(\"agent\", sectionFilters) {\n\t\toutputBuffer.Write([]byte(agentConfig))\n\t}\n}\n\nfunc printConfig(name string, p telegraf.PluginDescriber, op string, commented bool, di telegraf.DeprecationInfo, outputBuffer io.Writer) {\n\tcomment := \"\"\n\tif commented {\n\t\tcomment = \"# \"\n\t}\n\n\tif di.Since != \"\" {\n\t\tremovalNote := \"\"\n\t\tif di.RemovalIn != \"\" {\n\t\t\tremovalNote = \" and will be removed in \" + di.RemovalIn\n\t\t}\n\t\tfmt.Fprintf(outputBuffer, \"\\n%s## DEPRECATED: The %q plugin is deprecated in version %s%s, %s.\",\n\t\t\tcomment, name, di.Since, removalNote, di.Notice)\n\t}\n\n\tsample := p.SampleConfig()\n\tif sample == \"\" {\n\t\tfmt.Fprintf(outputBuffer, \"\\n#[[%s.%s]]\", op, name)\n\t\tfmt.Fprintf(outputBuffer, \"\\n%s  # no configuration\\n\\n\", comment)\n\t} else {\n\t\tlines := strings.Split(sample, \"\\n\")\n\t\toutputBuffer.Write([]byte(\"\\n\"))\n\t\tfor i, line := range lines {\n\t\t\tif i == len(lines)-1 {\n\t\t\t\toutputBuffer.Write([]byte(\"\\n\"))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toutputBuffer.Write([]byte(strings.TrimRight(comment+line, \" \") + \"\\n\"))\n\t\t}\n\t}\n}\n\n// PrintInputConfig prints the config usage of a single input.\nfunc PrintInputConfig(name string, outputBuffer io.Writer) error {\n\tcreator, ok := inputs.Inputs[name]\n\tif !ok {\n\t\treturn fmt.Errorf(\"input %s not found\", name)\n\t}\n\n\tprintConfig(name, creator(), \"inputs\", false, inputs.Deprecations[name], outputBuffer)\n\treturn nil\n}\n\n// PrintOutputConfig prints the config usage of a single output.\nfunc PrintOutputConfig(name string, outputBuffer io.Writer) error {\n\tcreator, ok := outputs.Outputs[name]\n\tif !ok {\n\t\treturn fmt.Errorf(\"output %s not found\", name)\n\t}\n\n\tprintConfig(name, creator(), \"outputs\", false, outputs.Deprecations[name], outputBuffer)\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/telegraf/telegraf.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/coreos/go-systemd/v22/daemon\"\n\t\"github.com/fatih/color\"\n\t\"github.com/influxdata/tail/watch\"\n\t\"gopkg.in/tomb.v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/secretstores\"\n)\n\nvar stop chan struct{}\n\ntype GlobalFlags struct {\n\tconfig                  []string\n\tconfigDir               []string\n\ttestWait                int\n\tconfigURLRetryAttempts  int\n\tconfigURLWatchInterval  time.Duration\n\twatchConfig             string\n\twatchInterval           time.Duration\n\twatchDebounceInterval   time.Duration\n\tpidFile                 string\n\tplugindDir              string\n\tpassword                string\n\toldEnvBehavior          bool\n\tnonStrictEnvVars        bool\n\tprintPluginConfigSource bool\n\ttest                    bool\n\tdebug                   bool\n\tonce                    bool\n\tquiet                   bool\n\tunprotected             bool\n}\n\ntype WindowFlags struct {\n\tservice             string\n\tserviceName         string\n\tserviceDisplayName  string\n\tserviceRestartDelay string\n\tserviceAutoRestart  bool\n\tconsole             bool\n}\n\ntype App interface {\n\tInit(<-chan error, Filters, GlobalFlags, WindowFlags)\n\tRun() error\n\n\t// Secret store commands\n\tListSecretStores() ([]string, error)\n\tGetSecretStore(string) (telegraf.SecretStore, error)\n}\n\ntype Telegraf struct {\n\tpprofErr <-chan error\n\n\tinputFilters       []string\n\toutputFilters      []string\n\tconfigFiles        []string\n\tsecretstoreFilters []string\n\n\tcfg *config.Config\n\n\tGlobalFlags\n\tWindowFlags\n}\n\nfunc (t *Telegraf) Init(pprofErr <-chan error, f Filters, g GlobalFlags, w WindowFlags) {\n\tt.pprofErr = pprofErr\n\tt.inputFilters = f.input\n\tt.outputFilters = f.output\n\tt.secretstoreFilters = f.secretstore\n\tt.GlobalFlags = g\n\tt.WindowFlags = w\n\n\t// Disable secret protection before performing any other operation\n\tif g.unprotected {\n\t\tlog.Println(\"W! Running without secret protection!\")\n\t\tconfig.DisableSecretProtection()\n\t}\n\n\t// Set global password\n\tif g.password != \"\" {\n\t\tconfig.Password = config.NewSecret([]byte(g.password))\n\t}\n\n\t// Set environment replacement behavior\n\tconfig.OldEnvVarReplacement = g.oldEnvBehavior\n\tconfig.NonStrictEnvVarHandling = g.nonStrictEnvVars\n\tconfig.PrintPluginConfigSource = g.printPluginConfigSource\n}\n\nfunc (t *Telegraf) ListSecretStores() ([]string, error) {\n\tc, err := t.loadConfiguration()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tids := make([]string, 0, len(c.SecretStores))\n\tfor k := range c.SecretStores {\n\t\tids = append(ids, k)\n\t}\n\treturn ids, nil\n}\n\nfunc (t *Telegraf) GetSecretStore(id string) (telegraf.SecretStore, error) {\n\tt.quiet = true\n\tc, err := t.loadConfiguration()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstore, found := c.SecretStores[id]\n\tif !found {\n\t\treturn nil, errors.New(\"unknown secret store\")\n\t}\n\n\treturn store, nil\n}\n\nfunc (t *Telegraf) reloadLoop() error {\n\treloadConfig := false\n\treload := make(chan bool, 1)\n\treload <- true\n\tfor <-reload {\n\t\treload <- false\n\t\tctx, cancel := context.WithCancel(context.Background())\n\n\t\tsignals := make(chan os.Signal, 1)\n\t\tsignal.Notify(signals, os.Interrupt, syscall.SIGHUP,\n\t\t\tsyscall.SIGTERM, syscall.SIGINT)\n\t\tif t.watchConfig != \"\" {\n\t\t\tfor _, fConfig := range t.configFiles {\n\t\t\t\tif isURL(fConfig) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif _, err := os.Stat(fConfig); err != nil {\n\t\t\t\t\tlog.Printf(\"W! Cannot watch config %s: %s\", fConfig, err)\n\t\t\t\t} else {\n\t\t\t\t\tgo t.watchLocalConfig(ctx, signals, fConfig)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, fConfigDirectory := range t.configDir {\n\t\t\t\tif _, err := os.Stat(fConfigDirectory); err != nil {\n\t\t\t\t\tlog.Printf(\"W! Cannot watch config directory %s: %s\", fConfigDirectory, err)\n\t\t\t\t} else {\n\t\t\t\t\tgo t.watchLocalConfig(ctx, signals, fConfigDirectory)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif t.configURLWatchInterval > 0 {\n\t\t\tremoteConfigs := make([]string, 0)\n\t\t\tfor _, fConfig := range t.configFiles {\n\t\t\t\tif isURL(fConfig) {\n\t\t\t\t\tremoteConfigs = append(remoteConfigs, fConfig)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(remoteConfigs) > 0 {\n\t\t\t\tgo t.watchRemoteConfigs(ctx, signals, t.configURLWatchInterval, remoteConfigs)\n\t\t\t}\n\t\t}\n\t\tgo func() {\n\t\t\tselect {\n\t\t\tcase sig := <-signals:\n\t\t\t\tif sig == syscall.SIGHUP {\n\t\t\t\t\tlog.Println(\"I! Reloading Telegraf config\")\n\t\t\t\t\t// May need to update the list of known config files\n\t\t\t\t\t// if a delete or create occured. That way on the reload\n\t\t\t\t\t// we ensure we watch the correct files.\n\t\t\t\t\tif err := t.getConfigFiles(); err != nil {\n\t\t\t\t\t\tlog.Println(\"E! Error loading config files: \", err)\n\t\t\t\t\t}\n\t\t\t\t\t<-reload\n\t\t\t\t\treload <- true\n\t\t\t\t}\n\t\t\t\tcancel()\n\t\t\tcase err := <-t.pprofErr:\n\t\t\t\tlog.Printf(\"E! pprof server failed: %v\", err)\n\t\t\t\tcancel()\n\t\t\tcase <-stop:\n\t\t\t\tcancel()\n\t\t\t}\n\t\t}()\n\n\t\terr := t.runAgent(ctx, reloadConfig)\n\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\treturn fmt.Errorf(\"[telegraf] Error running agent: %w\", err)\n\t\t}\n\t\treloadConfig = true\n\t}\n\n\treturn nil\n}\n\nfunc (t *Telegraf) watchLocalConfig(ctx context.Context, signals chan os.Signal, fConfig string) {\n\tvar mytomb tomb.Tomb\n\tvar watcher watch.FileWatcher\n\tif t.watchConfig == \"poll\" {\n\t\tif t.watchInterval > 0 {\n\t\t\twatcher = watch.NewPollingFileWatcherWithDuration(fConfig, t.watchInterval)\n\t\t} else {\n\t\t\twatcher = watch.NewPollingFileWatcher(fConfig)\n\t\t}\n\t} else {\n\t\twatcher = watch.NewInotifyFileWatcher(fConfig)\n\t}\n\tchanges, err := watcher.ChangeEvents(&mytomb, 0)\n\tif err != nil {\n\t\tlog.Printf(\"E! Error watching config file/directory %q: %s\\n\", fConfig, err)\n\t\treturn\n\t}\n\tlog.Printf(\"I! Config watcher started for %s\\n\", fConfig)\n\n\t// Setup debounce timer\n\tvar reloadTimer *time.Timer\n\tvar reloadPending bool\n\n\tif t.watchDebounceInterval > 0 {\n\t\treloadTimer = time.NewTimer(t.watchDebounceInterval)\n\t\tif !reloadTimer.Stop() {\n\t\t\t<-reloadTimer.C // Drain if already fired\n\t\t}\n\t}\n\n\t// Update resetTimer function:\n\tresetTimer := func(reason string) {\n\t\tlog.Printf(\"%s\", reason)\n\n\t\tif t.watchDebounceInterval == 0 {\n\t\t\t// No debouncing - trigger immediately\n\t\t\tselect {\n\t\t\tcase signals <- syscall.SIGHUP:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif !reloadPending {\n\t\t\treloadPending = true\n\t\t}\n\n\t\t// Properly drain and reset timer\n\t\tif !reloadTimer.Stop() {\n\t\t\tselect {\n\t\t\tcase <-reloadTimer.C:\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t\treloadTimer.Reset(t.watchDebounceInterval)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tif reloadTimer != nil {\n\t\t\t\treloadTimer.Stop()\n\t\t\t}\n\t\t\tmytomb.Done()\n\t\t\treturn\n\n\t\tcase <-changes.Modified:\n\t\t\tresetTimer(fmt.Sprintf(\"I! Config file/directory %q modified\\n\", fConfig))\n\n\t\tcase <-changes.Deleted:\n\t\t\t// Use select with timeout instead of blocking wait\n\t\t\ttimer := time.NewTimer(time.Second)\n\t\t\tselect {\n\t\t\tcase <-timer.C:\n\t\t\t\t// Proceed with file existence check\n\t\t\tcase <-ctx.Done():\n\t\t\t\ttimer.Stop()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar reason string\n\t\t\tif _, err := os.Stat(fConfig); err == nil {\n\t\t\t\treason = fmt.Sprintf(\"I! Config file/directory %q overwritten\\n\", fConfig)\n\t\t\t} else {\n\t\t\t\treason = fmt.Sprintf(\"W! Config file/directory %q deleted\\n\", fConfig)\n\t\t\t}\n\t\t\tresetTimer(reason)\n\n\t\tcase <-changes.Truncated:\n\t\t\tresetTimer(fmt.Sprintf(\"I! Config file/directory %q truncated\\n\", fConfig))\n\n\t\tcase <-changes.Created:\n\t\t\tresetTimer(fmt.Sprintf(\"I! Config directory %q has new file(s)\\n\", fConfig))\n\n\t\tcase <-func() <-chan time.Time {\n\t\t\tif reloadTimer != nil {\n\t\t\t\treturn reloadTimer.C\n\t\t\t}\n\t\t\t// Return a channel that never fires when debouncing is disabled\n\t\t\treturn make(<-chan time.Time)\n\t\t}():\n\t\t\tif reloadPending {\n\t\t\t\tlog.Printf(\"I! Debounce period elapsed, triggering config reload for %q\\n\", fConfig)\n\t\t\t\tselect {\n\t\t\t\tcase signals <- syscall.SIGHUP:\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treloadPending = false\n\t\t\t}\n\n\t\tcase <-mytomb.Dying():\n\t\t\tif reloadTimer != nil {\n\t\t\t\treloadTimer.Stop()\n\t\t\t}\n\t\t\tlog.Printf(\"I! Config watcher %q ended\\n\", fConfig)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (*Telegraf) watchRemoteConfigs(ctx context.Context, signals chan os.Signal, interval time.Duration, remoteConfigs []string) {\n\tconfigs := strings.Join(remoteConfigs, \", \")\n\tlog.Printf(\"I! Remote config watcher started for: %s\\n\", configs)\n\n\tticker := time.NewTicker(interval)\n\tdefer ticker.Stop()\n\n\tlastModified := make(map[string]string, len(remoteConfigs))\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-signals:\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t\tfor _, configURL := range remoteConfigs {\n\t\t\t\treq, err := http.NewRequest(\"HEAD\", configURL, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"W! Creating request for fetching config from %q failed: %v\\n\", configURL, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif v, exists := os.LookupEnv(\"INFLUX_TOKEN\"); exists {\n\t\t\t\t\treq.Header.Add(\"Authorization\", \"Token \"+v)\n\t\t\t\t}\n\t\t\t\treq.Header.Set(\"User-Agent\", internal.ProductToken())\n\n\t\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"W! Fetching config from %q failed: %v\\n\", configURL, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tresp.Body.Close()\n\n\t\t\t\tmodified := resp.Header.Get(\"Last-Modified\")\n\t\t\t\tif modified == \"\" {\n\t\t\t\t\tlog.Printf(\"E! Last-Modified header not found, stopping the watcher for %s\\n\", configURL)\n\t\t\t\t\tdelete(lastModified, configURL)\n\t\t\t\t}\n\n\t\t\t\tif lastModified[configURL] == \"\" {\n\t\t\t\t\tlastModified[configURL] = modified\n\t\t\t\t} else if lastModified[configURL] != modified {\n\t\t\t\t\tlog.Printf(\"I! Remote config modified: %s\\n\", configURL)\n\t\t\t\t\tsignals <- syscall.SIGHUP\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (t *Telegraf) loadConfiguration() (*config.Config, error) {\n\t// If no other options are specified, load the config file and run.\n\tc := config.NewConfig()\n\tc.Agent.Quiet = t.quiet\n\tc.Agent.ConfigURLRetryAttempts = t.configURLRetryAttempts\n\tc.OutputFilters = t.outputFilters\n\tc.InputFilters = t.inputFilters\n\tc.SecretStoreFilters = t.secretstoreFilters\n\n\tif err := t.getConfigFiles(); err != nil {\n\t\treturn c, err\n\t}\n\tif err := c.LoadAll(t.configFiles...); err != nil {\n\t\treturn c, err\n\t}\n\treturn c, nil\n}\n\nfunc (t *Telegraf) getConfigFiles() error {\n\tvar configFiles []string\n\n\tconfigFiles = append(configFiles, t.config...)\n\tfor _, fConfigDirectory := range t.configDir {\n\t\tfiles, err := config.WalkDirectory(fConfigDirectory)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tconfigFiles = append(configFiles, files...)\n\t}\n\n\t// load default config paths if none are found\n\tif len(configFiles) == 0 {\n\t\tdefaultFiles, err := config.GetDefaultConfigPath()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to load default config paths: %w\", err)\n\t\t}\n\t\tconfigFiles = append(configFiles, defaultFiles...)\n\t}\n\n\tt.configFiles = configFiles\n\treturn nil\n}\n\nfunc (t *Telegraf) runAgent(ctx context.Context, reloadConfig bool) error {\n\tc := t.cfg\n\tvar err error\n\tif reloadConfig {\n\t\tif c, err = t.loadConfiguration(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !t.test && t.testWait == 0 && len(c.Outputs) == 0 {\n\t\treturn errors.New(\"no outputs found, probably invalid config file provided\")\n\t}\n\tif t.plugindDir == \"\" && len(c.Inputs) == 0 {\n\t\treturn errors.New(\"no inputs found, probably invalid config file provided\")\n\t}\n\n\tif int64(c.Agent.Interval) <= 0 {\n\t\treturn fmt.Errorf(\"agent interval must be positive, found %v\", c.Agent.Interval)\n\t}\n\n\tif int64(c.Agent.FlushInterval) <= 0 {\n\t\treturn fmt.Errorf(\"agent flush_interval must be positive; found %v\", c.Agent.Interval)\n\t}\n\n\t// Setup logging as configured.\n\tlogConfig := &logger.Config{\n\t\tDebug:                   c.Agent.Debug || t.debug,\n\t\tQuiet:                   c.Agent.Quiet || t.quiet,\n\t\tLogTarget:               c.Agent.LogTarget,\n\t\tLogFormat:               c.Agent.LogFormat,\n\t\tLogfile:                 c.Agent.Logfile,\n\t\tStructuredLogMessageKey: c.Agent.StructuredLogMessageKey,\n\t\tRotationInterval:        time.Duration(c.Agent.LogfileRotationInterval),\n\t\tRotationMaxSize:         int64(c.Agent.LogfileRotationMaxSize),\n\t\tRotationMaxArchives:     c.Agent.LogfileRotationMaxArchives,\n\t\tLogWithTimezone:         c.Agent.LogWithTimezone,\n\t}\n\n\tif err := logger.SetupLogging(logConfig); err != nil {\n\t\treturn err\n\t}\n\n\tlog.Printf(\"I! Starting Telegraf %s%s brought to you by InfluxData the makers of InfluxDB\", internal.Version, internal.Customized)\n\tlog.Printf(\"I! Available plugins: %d inputs, %d aggregators, %d processors, %d parsers, %d outputs, %d secret-stores\",\n\t\tlen(inputs.Inputs),\n\t\tlen(aggregators.Aggregators),\n\t\tlen(processors.Processors),\n\t\tlen(parsers.Parsers),\n\t\tlen(outputs.Outputs),\n\t\tlen(secretstores.SecretStores),\n\t)\n\tlog.Printf(\"I! Loaded inputs: %s\\n%s\", strings.Join(c.InputNames(), \" \"), c.InputNamesWithSources())\n\tlog.Printf(\"I! Loaded aggregators: %s\\n%s\", strings.Join(c.AggregatorNames(), \" \"), c.AggregatorNamesWithSources())\n\tlog.Printf(\"I! Loaded processors: %s\\n%s\", strings.Join(c.ProcessorNames(), \" \"), c.ProcessorNamesWithSources())\n\tlog.Printf(\"I! Loaded secretstores: %s\\n%s\", strings.Join(c.SecretstoreNames(), \" \"), c.SecretstoreNamesWithSources())\n\tif !t.once && (t.test || t.testWait != 0) {\n\t\tlog.Print(\"W! \" + color.RedString(\"Outputs are not used in testing mode!\"))\n\t} else {\n\t\tlog.Printf(\"I! Loaded outputs: %s\\n%s\", strings.Join(c.OutputNames(), \" \"), c.OutputNamesWithSources())\n\t}\n\tlog.Printf(\"I! Tags enabled: %s\", c.ListTags())\n\n\tif count, found := c.Deprecations[\"inputs\"]; found && (count[0] > 0 || count[1] > 0) {\n\t\tlog.Printf(\"W! Deprecated inputs: %d and %d options\", count[0], count[1])\n\t}\n\tif count, found := c.Deprecations[\"aggregators\"]; found && (count[0] > 0 || count[1] > 0) {\n\t\tlog.Printf(\"W! Deprecated aggregators: %d and %d options\", count[0], count[1])\n\t}\n\tif count, found := c.Deprecations[\"processors\"]; found && (count[0] > 0 || count[1] > 0) {\n\t\tlog.Printf(\"W! Deprecated processors: %d and %d options\", count[0], count[1])\n\t}\n\tif count, found := c.Deprecations[\"outputs\"]; found && (count[0] > 0 || count[1] > 0) {\n\t\tlog.Printf(\"W! Deprecated outputs: %d and %d options\", count[0], count[1])\n\t}\n\tif count, found := c.Deprecations[\"secretstores\"]; found && (count[0] > 0 || count[1] > 0) {\n\t\tlog.Printf(\"W! Deprecated secretstores: %d and %d options\", count[0], count[1])\n\t}\n\n\t// Compute the amount of locked memory needed for the secrets\n\tif !t.GlobalFlags.unprotected {\n\t\trequired := 3 * c.NumberSecrets * uint64(os.Getpagesize())\n\t\tavailable := getLockedMemoryLimit()\n\t\tif required > available {\n\t\t\trequired /= 1024\n\t\t\tavailable /= 1024\n\t\t\tlog.Printf(\"I! Found %d secrets...\", c.NumberSecrets)\n\t\t\tmsg := fmt.Sprintf(\"Insufficient lockable memory %dkb when %dkb is required.\", available, required)\n\t\t\tmsg += \" Please increase the limit for Telegraf in your Operating System!\"\n\t\t\tlog.Print(\"W! \" + color.RedString(msg))\n\t\t}\n\t}\n\tag := agent.NewAgent(c)\n\n\t// Notify systemd that telegraf is ready\n\t// SdNotify() only tries to notify if the NOTIFY_SOCKET environment is set, so it's safe to call when systemd isn't present.\n\t// Ignore the return values here because they're not valid for platforms that don't use systemd.\n\t// For platforms that use systemd, telegraf doesn't log if the notification failed.\n\t//nolint:errcheck // see above\n\tdaemon.SdNotify(false, daemon.SdNotifyReady)\n\n\tif t.once {\n\t\twait := time.Duration(t.testWait) * time.Second\n\t\treturn ag.Once(ctx, wait)\n\t}\n\n\tif t.test || t.testWait != 0 {\n\t\twait := time.Duration(t.testWait) * time.Second\n\t\treturn ag.Test(ctx, wait)\n\t}\n\n\tif t.pidFile != \"\" {\n\t\tf, err := os.OpenFile(t.pidFile, os.O_CREATE|os.O_WRONLY, 0640)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"E! Unable to create pidfile: %s\", err)\n\t\t} else {\n\t\t\tfmt.Fprintf(f, \"%d\\n\", os.Getpid())\n\n\t\t\terr = f.Close()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer func() {\n\t\t\t\terr := os.Remove(t.pidFile)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"E! Unable to remove pidfile: %s\", err)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\treturn ag.Run(ctx)\n}\n\n// isURL checks if string is valid url\nfunc isURL(str string) bool {\n\tu, err := url.Parse(str)\n\treturn err == nil && u.Scheme != \"\" && u.Host != \"\"\n}\n"
  },
  {
    "path": "cmd/telegraf/telegraf_posix.go",
    "content": "//go:build !windows\n\npackage main\n\nimport (\n\t\"log\"\n\t\"runtime\"\n\t\"syscall\"\n)\n\nfunc (t *Telegraf) Run() error {\n\tstop = make(chan struct{})\n\tdefer close(stop)\n\n\tcfg, err := t.loadConfiguration()\n\tif err != nil {\n\t\treturn err\n\t}\n\tt.cfg = cfg\n\treturn t.reloadLoop()\n}\n\nfunc getLockedMemoryLimit() uint64 {\n\tvar rLimitMemlock int\n\n\tswitch runtime.GOOS {\n\tcase \"dragonfly\", \"freebsd\", \"netbsd\", \"openbsd\":\n\t\t// From https://cgit.freebsd.org/src/tree/sys/sys/resource.h#n107\n\t\trLimitMemlock = 6\n\tdefault:\n\t\t// From https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/resource.h#L35\n\t\trLimitMemlock = 8\n\t}\n\n\tvar limit syscall.Rlimit\n\tif err := syscall.Getrlimit(rLimitMemlock, &limit); err != nil {\n\t\tlog.Printf(\"E! Cannot get limit for locked memory: %v\", err)\n\t\treturn 0\n\t}\n\t//nolint:unconvert // required for e.g. FreeBSD that has the field as int64\n\treturn uint64(limit.Max)\n}\n"
  },
  {
    "path": "cmd/telegraf/telegraf_windows.go",
    "content": "//go:build windows\n\n//go:generate ../../scripts/windows-gen-syso.sh $GOARCH\n\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/svc\"\n\t\"golang.org/x/sys/windows/svc/eventlog\"\n\t\"golang.org/x/sys/windows/svc/mgr\"\n)\n\nfunc getLockedMemoryLimit() uint64 {\n\thandle := windows.CurrentProcess()\n\n\tvar low, high uintptr\n\tvar flag uint32\n\twindows.GetProcessWorkingSetSizeEx(handle, &low, &high, &flag)\n\n\treturn uint64(high)\n}\n\nfunc (t *Telegraf) Run() error {\n\t// Process the service commands\n\tif t.service != \"\" {\n\t\tfmt.Println(\"The use of --service is deprecated, please use the 'service' command instead!\")\n\t\tswitch t.service {\n\t\tcase \"install\":\n\t\t\tcfg := &serviceConfig{\n\t\t\t\tdisplayName:  t.serviceDisplayName,\n\t\t\t\trestartDelay: t.serviceRestartDelay,\n\t\t\t\tautoRestart:  t.serviceAutoRestart,\n\t\t\t\tconfigs:      t.config,\n\t\t\t\tconfigDirs:   t.configDir,\n\t\t\t\twatchConfig:  t.watchConfig,\n\t\t\t}\n\t\t\tif err := installService(t.serviceName, cfg); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Successfully installed service %q\\n\", t.serviceName)\n\t\tcase \"uninstall\":\n\t\t\tif err := uninstallService(t.serviceName); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Successfully uninstalled service %q\\n\", t.serviceName)\n\t\tcase \"start\":\n\t\t\tif err := startService(t.serviceName); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Successfully started service %q\\n\", t.serviceName)\n\t\tcase \"stop\":\n\t\t\tif err := stopService(t.serviceName); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Successfully stopped service %q\\n\", t.serviceName)\n\t\tcase \"status\":\n\t\t\tstatus, err := queryService(t.serviceName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfmt.Printf(\"Service %q is in %q state\\n\", t.serviceName, status)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid service command %q\", t.service)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Determine if Telegraf is started as a Windows service.\n\tisWinService, err := svc.IsWindowsService()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot determine if run as Windows service: %w\", err)\n\t}\n\tif !t.console && isWinService {\n\t\treturn svc.Run(t.serviceName, t)\n\t}\n\n\t// Load the configuration file(s)\n\tcfg, err := t.loadConfiguration()\n\tif err != nil {\n\t\treturn err\n\t}\n\tt.cfg = cfg\n\n\tstop = make(chan struct{})\n\tdefer close(stop)\n\treturn t.reloadLoop()\n}\n\n// Execute is the handler for the Windows service framework\nfunc (t *Telegraf) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {\n\t// Mark the status as startup pending until we are fully started\n\tconst accepted = svc.AcceptStop | svc.AcceptShutdown\n\tchanges <- svc.Status{State: svc.StartPending}\n\tdefer func() {\n\t\tchanges <- svc.Status{State: svc.Stopped}\n\t}()\n\n\t// Create a eventlog logger for  all service related things\n\tsvclog, err := eventlog.Open(t.serviceName)\n\tif err != nil {\n\t\tlog.Printf(\"E! Initializing the service logger failed: %s\", err)\n\t\treturn true, 1\n\t}\n\tdefer svclog.Close()\n\n\t// Load the configuration file(s)\n\tcfg, err := t.loadConfiguration()\n\tif err != nil {\n\t\tif lerr := svclog.Error(100, err.Error()); lerr != nil {\n\t\t\tlog.Printf(\"E! Logging error %q failed: %s\", err, lerr)\n\t\t}\n\t\treturn true, 2\n\t}\n\tt.cfg = cfg\n\n\t// Actually start the processing loop in the background to be able to\n\t// react to service change requests\n\tloopErr := make(chan error)\n\tstop = make(chan struct{})\n\tdefer close(loopErr)\n\tdefer close(stop)\n\tgo func() {\n\t\tloopErr <- t.reloadLoop()\n\t}()\n\tchanges <- svc.Status{State: svc.Running, Accepts: accepted}\n\n\tfor {\n\t\tselect {\n\t\tcase err := <-loopErr:\n\t\t\tif err != nil {\n\t\t\t\tif lerr := svclog.Error(100, err.Error()); lerr != nil {\n\t\t\t\t\tlog.Printf(\"E! Logging error %q failed: %s\", err, lerr)\n\t\t\t\t}\n\t\t\t\treturn true, 3\n\t\t\t}\n\t\t\treturn false, 0\n\t\tcase c := <-r:\n\t\t\tswitch c.Cmd {\n\t\t\tcase svc.Interrogate:\n\t\t\t\tchanges <- c.CurrentStatus\n\t\t\t\t// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\tchanges <- c.CurrentStatus\n\t\t\tcase svc.Stop, svc.Shutdown:\n\t\t\t\tchanges <- svc.Status{State: svc.StopPending}\n\t\t\t\tvar empty struct{}\n\t\t\t\tstop <- empty // signal reloadLoop to finish (context cancel)\n\t\t\tdefault:\n\t\t\t\tmsg := fmt.Sprintf(\"Unexpected control request #%d\", c)\n\t\t\t\tif lerr := svclog.Error(100, msg); lerr != nil {\n\t\t\t\t\tlog.Printf(\"E! Logging error %q failed: %s\", msg, lerr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntype serviceConfig struct {\n\tdisplayName  string\n\trestartDelay string\n\tautoRestart  bool\n\n\t// Telegraf parameters\n\tconfigs     []string\n\tconfigDirs  []string\n\twatchConfig string\n}\n\nfunc installService(name string, cfg *serviceConfig) error {\n\t// Determine the executable to use in the service\n\texecutable, err := os.Executable()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"determining executable failed: %w\", err)\n\t}\n\n\t// Determine the program files directory name\n\tprogramFiles := os.Getenv(\"ProgramFiles\")\n\tif programFiles == \"\" { // Should never happen\n\t\tprogramFiles = \"C:\\\\Program Files\"\n\t}\n\n\t// Collect the command line arguments\n\targs := make([]string, 0, 2*(len(cfg.configs)+len(cfg.configDirs))+2)\n\tfor _, fn := range cfg.configs {\n\t\targs = append(args, \"--config\", fn)\n\t}\n\tfor _, dn := range cfg.configDirs {\n\t\targs = append(args, \"--config-directory\", dn)\n\t}\n\tif len(args) == 0 {\n\t\targs = append(args, \"--config\", filepath.Join(programFiles, \"Telegraf\", \"telegraf.conf\"))\n\t}\n\tif cfg.watchConfig != \"\" {\n\t\targs = append(args, \"--watch-config\", cfg.watchConfig)\n\t}\n\t// Pass the service name to the command line, to have a custom name when relaunching as a service\n\targs = append(args, \"--service-name\", name)\n\n\t// Create a configuration for the service\n\tsvccfg := mgr.Config{\n\t\tDisplayName: cfg.displayName,\n\t\tDescription: \"Collects, processes and publishes data using a series of plugins.\",\n\t\tStartType:   mgr.StartAutomatic,\n\t\tServiceType: windows.SERVICE_WIN32_OWN_PROCESS,\n\t}\n\n\t// Connect to the service manager and try to install the service if it\n\t// doesn't exist. Fail on existing service and stop installation.\n\tsvcmgr, err := mgr.Connect()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"connecting to service manager failed: %w\", err)\n\t}\n\tdefer svcmgr.Disconnect()\n\n\tif service, err := svcmgr.OpenService(name); err == nil {\n\t\tservice.Close()\n\t\treturn fmt.Errorf(\"service %q is already installed\", name)\n\t}\n\n\tservice, err := svcmgr.CreateService(name, executable, svccfg, args...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating service failed: %w\", err)\n\t}\n\tdefer service.Close()\n\n\t// Set the recovery strategy to restart with a fixed period of 10 seconds\n\t// and the user specified delay if requested\n\tif cfg.autoRestart {\n\t\tdelay, err := time.ParseDuration(cfg.restartDelay)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse restart delay %q: %w\", cfg.restartDelay, err)\n\t\t}\n\t\trecovery := []mgr.RecoveryAction{{Type: mgr.ServiceRestart, Delay: delay}}\n\t\tif err := service.SetRecoveryActions(recovery, 10); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Register the event as a source of eventlog events\n\tevents := uint32(eventlog.Error | eventlog.Warning | eventlog.Info)\n\tif err := eventlog.InstallAsEventCreate(name, events); err != nil && !strings.Contains(err.Error(), \"key already exists\") {\n\t\t//nolint:errcheck // Try to remove the service on best effort basis as we cannot handle any error here\n\t\tservice.Delete()\n\t\treturn fmt.Errorf(\"setting up eventlog source failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc uninstallService(name string) error {\n\t// Connect to the service manager and try to open the service. In case the\n\t// service is not installed, return with the corresponding error.\n\tsvcmgr, err := mgr.Connect()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"connecting to service manager failed: %w\", err)\n\t}\n\tdefer svcmgr.Disconnect()\n\n\tservice, err := svcmgr.OpenService(name)\n\tif err != nil {\n\t\tif !errors.Is(err, windows.ERROR_SERVICE_DOES_NOT_EXIST) {\n\t\t\treturn fmt.Errorf(\"opening service failed: %w\", err)\n\t\t}\n\t} else {\n\t\tdefer service.Close()\n\n\t\t// Uninstall the service\n\t\tif err := service.Delete(); err != nil {\n\t\t\treturn fmt.Errorf(\"uninstalling service failed: %w\", err)\n\t\t}\n\t}\n\n\t// Remove the eventlog source if there is any\n\tif err := eventlog.Remove(name); err != nil && !errors.Is(err, syscall.ERROR_FILE_NOT_FOUND) {\n\t\treturn fmt.Errorf(\"removing eventlog source failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc startService(name string) error {\n\tnameUTF16, err := syscall.UTF16PtrFromString(name)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"conversion of service name %q to UTF16 failed: %w\", name, err)\n\t}\n\n\t// Open the service manager and service with the least privileges required to start the service\n\tmgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening service manager failed: %w\", err)\n\t}\n\tdefer windows.CloseServiceHandle(mgrhandle)\n\n\tsvchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS|windows.SERVICE_START)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening service failed: %w\", err)\n\t}\n\tservice := &mgr.Service{Handle: svchandle, Name: name}\n\tdefer service.Close()\n\n\t// Check if the service is actually stopped\n\tstatus, err := service.Query()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying service state failed: %w\", err)\n\t}\n\tif status.State != svc.Stopped {\n\t\treturn fmt.Errorf(\"service is not stopped but in state %q\", stateDescription(status.State))\n\t}\n\n\treturn service.Start()\n}\n\nfunc stopService(name string) error {\n\tnameUTF16, err := syscall.UTF16PtrFromString(name)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"conversion of service name %q to UTF16 failed: %w\", name, err)\n\t}\n\n\t// Open the service manager and service with the least privileges required to start the service\n\tmgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening service manager failed: %w\", err)\n\t}\n\tdefer windows.CloseServiceHandle(mgrhandle)\n\n\tsvchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS|windows.SERVICE_STOP)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening service failed: %w\", err)\n\t}\n\tservice := &mgr.Service{Handle: svchandle, Name: name}\n\tdefer service.Close()\n\n\t// Stop the service and wait for it to finish\n\tstatus, err := service.Control(svc.Stop)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"stopping service failed: %w\", err)\n\t}\n\tfor status.State != svc.Stopped {\n\t\t// Wait for the hinted time, but clip it to prevent stalling operation\n\t\twait := time.Duration(status.WaitHint) * time.Millisecond\n\t\tif wait < 100*time.Millisecond {\n\t\t\twait = 100 * time.Millisecond\n\t\t} else if wait > 10*time.Second {\n\t\t\twait = 10 * time.Second\n\t\t}\n\t\ttime.Sleep(wait)\n\n\t\tstatus, err = service.Query()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"querying service state failed: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc queryService(name string) (string, error) {\n\tnameUTF16, err := syscall.UTF16PtrFromString(name)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"conversion of service name %q to UTF16 failed: %w\", name, err)\n\t}\n\n\t// Open the service manager and service with the least privileges required to start the service\n\tmgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"opening service manager failed: %w\", err)\n\t}\n\tdefer windows.CloseServiceHandle(mgrhandle)\n\n\tsvchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"opening service failed: %w\", err)\n\t}\n\tservice := &mgr.Service{Handle: svchandle, Name: name}\n\tdefer service.Close()\n\n\t// Query the service state and report it to the user\n\tstatus, err := service.Query()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"querying service state failed: %w\", err)\n\t}\n\n\treturn stateDescription(status.State), nil\n}\n\nfunc stateDescription(state svc.State) string {\n\tswitch state {\n\tcase svc.Stopped:\n\t\treturn \"stopped\"\n\tcase svc.StartPending:\n\t\treturn \"start pending\"\n\tcase svc.StopPending:\n\t\treturn \"stop pending\"\n\tcase svc.Running:\n\t\treturn \"running\"\n\tcase svc.ContinuePending:\n\t\treturn \"continue pending\"\n\tcase svc.PausePending:\n\t\treturn \"pause pending\"\n\tcase svc.Paused:\n\t\treturn \"paused\"\n\t}\n\treturn fmt.Sprintf(\"unknown %v\", state)\n}\n"
  },
  {
    "path": "config/config.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/coreos/go-semver/semver\"\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/persister\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/csv\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/secretstores\"\n\t\"github.com/influxdata/telegraf/plugins/serializers\"\n)\n\nvar (\n\thttpLoadConfigRetryInterval = 10 * time.Second\n\n\t// fetchURLRe is a regex to determine whether the requested file should\n\t// be fetched from a remote or read from the filesystem.\n\tfetchURLRe = regexp.MustCompile(`^\\w+://`)\n\n\t// oldVarRe is a regex to reproduce pre v1.27.0 environment variable\n\t// replacement behavior\n\toldVarRe = regexp.MustCompile(`\\$(?i:(?P<named>[_a-z][_a-z0-9]*)|{(?:(?P<braced>[_a-z][_a-z0-9]*(?::?[-+?](.*))?)}|(?P<invalid>)))`)\n\t// OldEnvVarReplacement is a switch to allow going back to pre v1.27.0\n\t// environment variable replacement behavior\n\tOldEnvVarReplacement = false\n\n\t// NonStrictEnvVarHandling allows to disable strict and safe environment\n\t// variables handling. Strict handling cannot replace non-string settings\n\t// so this option must be used in those use-cases.\n\tNonStrictEnvVarHandling = false\n\n\t// PrintPluginConfigSource is a switch to enable printing of plugin sources\n\tPrintPluginConfigSource = false\n\n\t// Password specified via command-line\n\tPassword Secret\n\n\t// telegrafVersion contains the parsed semantic Telegraf version\n\ttelegrafVersion *semver.Version = semver.New(\"0.0.0-unknown\")\n\n\t// List of (redacted) configuration Sources\n\tsources   []string\n\tsourcesMu sync.Mutex\n)\n\nconst EmptySourcePath string = \"\"\n\n// Config specifies the URL/user/password for the database that telegraf\n// will be logging to, as well as all the plugins that the user has\n// specified\ntype Config struct {\n\ttoml              *toml.Config\n\terrs              []error // config load errors.\n\tUnusedFields      map[string]bool\n\tunusedFieldsMutex *sync.Mutex\n\n\tTags               map[string]string\n\tInputFilters       []string\n\tOutputFilters      []string\n\tSecretStoreFilters []string\n\n\tSecretStores      map[string]telegraf.SecretStore\n\tsecretStoreSource map[string][]string\n\n\tAgent       *AgentConfig\n\tInputs      []*models.RunningInput\n\tOutputs     []*models.RunningOutput\n\tAggregators []*models.RunningAggregator\n\t// Processors have a slice wrapper type because they need to be sorted\n\tProcessors        models.RunningProcessors\n\tAggProcessors     models.RunningProcessors\n\tfileProcessors    OrderedPlugins\n\tfileAggProcessors OrderedPlugins\n\n\t// Parsers are created by their inputs during gather. Config doesn't keep track of them\n\t// like the other plugins because they need to be garbage collected (See issue #11809)\n\n\tDeprecations map[string][]int64\n\n\tPersister *persister.Persister\n\n\tNumberSecrets uint64\n\n\tseenAgentTable     bool\n\tseenAgentTableOnce sync.Once\n}\n\n// OrderedPlugin is used to keep the order in which they appear in a file\ntype OrderedPlugin struct {\n\tLine   int\n\tplugin any\n}\ntype OrderedPlugins []*OrderedPlugin\n\nfunc (op OrderedPlugins) Len() int           { return len(op) }\nfunc (op OrderedPlugins) Swap(i, j int)      { op[i], op[j] = op[j], op[i] }\nfunc (op OrderedPlugins) Less(i, j int) bool { return op[i].Line < op[j].Line }\n\n// NewConfig creates a new struct to hold the Telegraf config.\n// For historical reasons, It holds the actual instances of the running plugins\n// once the configuration is parsed.\nfunc NewConfig() *Config {\n\tc := &Config{\n\t\tUnusedFields:      make(map[string]bool),\n\t\tunusedFieldsMutex: &sync.Mutex{},\n\n\t\t// Agent defaults:\n\t\tAgent: &AgentConfig{\n\t\t\tInterval:                   Duration(10 * time.Second),\n\t\t\tRoundInterval:              true,\n\t\t\tFlushInterval:              Duration(10 * time.Second),\n\t\t\tLogfileRotationMaxArchives: 5,\n\t\t},\n\n\t\tTags:               make(map[string]string),\n\t\tInputs:             make([]*models.RunningInput, 0),\n\t\tOutputs:            make([]*models.RunningOutput, 0),\n\t\tProcessors:         make([]*models.RunningProcessor, 0),\n\t\tAggProcessors:      make([]*models.RunningProcessor, 0),\n\t\tSecretStores:       make(map[string]telegraf.SecretStore),\n\t\tsecretStoreSource:  make(map[string][]string),\n\t\tfileProcessors:     make([]*OrderedPlugin, 0),\n\t\tfileAggProcessors:  make([]*OrderedPlugin, 0),\n\t\tInputFilters:       make([]string, 0),\n\t\tOutputFilters:      make([]string, 0),\n\t\tSecretStoreFilters: make([]string, 0),\n\t\tDeprecations:       make(map[string][]int64),\n\t}\n\n\t// Handle unknown version\n\tif internal.Version != \"\" && internal.Version != \"unknown\" {\n\t\ttelegrafVersion = semver.New(internal.Version)\n\t}\n\n\ttomlCfg := &toml.Config{\n\t\tNormFieldName: toml.DefaultConfig.NormFieldName,\n\t\tFieldToKey:    toml.DefaultConfig.FieldToKey,\n\t\tMissingField:  c.missingTomlField,\n\t}\n\tc.toml = tomlCfg\n\n\t// Initialize the configuration source list\n\tsourcesMu.Lock()\n\tsources = make([]string, 0)\n\tsourcesMu.Unlock()\n\n\treturn c\n}\n\n// AgentConfig defines configuration that will be used by the Telegraf agent\ntype AgentConfig struct {\n\t// Interval at which to gather information\n\tInterval Duration\n\n\t// RoundInterval rounds collection interval to 'interval'.\n\t//     ie, if Interval=10s then always collect on :00, :10, :20, etc.\n\tRoundInterval bool\n\n\t// Collected metrics are rounded to the precision specified. Precision is\n\t// specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n\t// Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n\t//\n\t// By default, or when set to \"0s\", precision will be set to the same\n\t// timestamp order as the collection interval, with the maximum being 1s:\n\t//   ie, when interval = \"10s\", precision will be \"1s\"\n\t//       when interval = \"250ms\", precision will be \"1ms\"\n\t//\n\t// Precision will NOT be used for service inputs. It is up to each individual\n\t// service input to set the timestamp at the appropriate precision.\n\tPrecision Duration\n\n\t// CollectionJitter is used to jitter the collection by a random amount.\n\t// Each plugin will sleep for a random time within jitter before collecting.\n\t// This can be used to avoid many plugins querying things like sysfs at the\n\t// same time, which can have a measurable effect on the system.\n\tCollectionJitter Duration\n\n\t// CollectionOffset is used to shift the collection by the given amount.\n\t// This can be used to avoid many plugins querying constraint devices\n\t// at the same time by manually scheduling them in time.\n\tCollectionOffset Duration\n\n\t// FlushInterval is the Interval at which to flush data\n\tFlushInterval Duration\n\n\t// FlushJitter Jitters the flush interval by a random amount.\n\t// This is primarily to avoid large write spikes for users running a large\n\t// number of telegraf instances.\n\t// ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n\tFlushJitter Duration\n\n\t// MetricBatchSize is the maximum number of metrics that is written to an\n\t// output plugin in one call.\n\tMetricBatchSize int\n\n\t// MetricBufferLimit is the max number of metrics that each output plugin\n\t// will cache. The buffer is cleared when a successful write occurs. When\n\t// full, the oldest metrics will be overwritten. This number should be a\n\t// multiple of MetricBatchSize. Due to current implementation, this could\n\t// not be less than 2 times MetricBatchSize.\n\tMetricBufferLimit int\n\n\t// Debug is the option for running in debug mode\n\tDebug bool `toml:\"debug\"`\n\n\t// Quiet is the option for running in quiet mode\n\tQuiet bool `toml:\"quiet\"`\n\n\t// Log target controls the destination for logs and can be one of \"file\",\n\t// \"stderr\" or, on Windows, \"eventlog\". When set to \"file\", the output file\n\t// is determined by the \"logfile\" setting\n\tLogTarget string `toml:\"logtarget\" deprecated:\"1.32.0;1.40.0;use 'logformat' and 'logfile' instead\"`\n\n\t// Log format controls the way messages are logged and can be one of \"text\",\n\t// \"structured\" or, on Windows, \"eventlog\".\n\tLogFormat string `toml:\"logformat\"`\n\n\t// Name of the file to be logged to or stderr if empty. Ignored for \"eventlog\" format.\n\tLogfile string `toml:\"logfile\"`\n\n\t// Message key for structured logs, to override the default of \"msg\".\n\t// Ignored if \"logformat\" is not \"structured\".\n\tStructuredLogMessageKey string `toml:\"structured_log_message_key\"`\n\n\t// The file will be rotated after the time interval specified.  When set\n\t// to 0 no time based rotation is performed.\n\tLogfileRotationInterval Duration `toml:\"logfile_rotation_interval\"`\n\n\t// The logfile will be rotated when it becomes larger than the specified\n\t// size.  When set to 0 no size based rotation is performed.\n\tLogfileRotationMaxSize Size `toml:\"logfile_rotation_max_size\"`\n\n\t// Maximum number of rotated archives to keep, any older logs are deleted.\n\t// If set to -1, no archives are removed.\n\tLogfileRotationMaxArchives int `toml:\"logfile_rotation_max_archives\"`\n\n\t// Pick a timezone to use when logging or type 'local' for local time.\n\tLogWithTimezone string `toml:\"log_with_timezone\"`\n\n\tHostname     string\n\tOmitHostname bool\n\n\t// Method for translating SNMP objects. 'netsnmp' to call external programs,\n\t// 'gosmi' to use the built-in library.\n\tSnmpTranslator string `toml:\"snmp_translator\"`\n\n\t// Name of the file to load the state of plugins from and store the state to.\n\t// If uncommented and not empty, this file will be used to save the state of\n\t// stateful plugins on termination of Telegraf. If the file exists on start,\n\t// the state in the file will be restored for the plugins.\n\tStatefile string `toml:\"statefile\"`\n\n\t// Flag to always keep tags explicitly defined in the plugin itself and\n\t// ensure those tags always pass filtering.\n\tAlwaysIncludeLocalTags bool `toml:\"always_include_local_tags\"`\n\n\t// Flag to always keep tags explicitly defined in the global tags section\n\t// and ensure those tags always pass filtering.\n\tAlwaysIncludeGlobalTags bool `toml:\"always_include_global_tags\"`\n\n\t// Flag to skip running processors after aggregators\n\t// By default, processors are run a second time after aggregators. Changing\n\t// this setting to true will skip the second run of processors.\n\tSkipProcessorsAfterAggregators *bool `toml:\"skip_processors_after_aggregators\"`\n\n\t// Number of attempts to obtain a remote configuration via a URL during\n\t// startup. Set to -1 for unlimited attempts.\n\tConfigURLRetryAttempts int `toml:\"config_url_retry_attempts\"`\n\n\t// BufferStrategy is the metric buffer type to use for a given output plugin.\n\t// Supported types currently are \"memory\" and \"disk_write_through\" (alias: \"disk\").\n\tBufferStrategy string `toml:\"buffer_strategy\"`\n\n\t// BufferDirectory is the directory to store buffer files for serialized\n\t// to disk metrics when using the \"disk_write_through\" buffer strategy.\n\tBufferDirectory string `toml:\"buffer_directory\"`\n\n\t// BufferDiskSync controls writes durability when \"disk\" buffer strategy\n\t// is used. No sync offers better write performance at the risk of losing\n\t// metrics buffered in the last `flush_interval` in the event of a power\n\t// cut.\n\tBufferDiskSync *bool `toml:\"buffer_disk_sync\"`\n}\n\n// InputNames returns a list of strings of the configured inputs.\nfunc (c *Config) InputNames() []string {\n\tname := make([]string, 0, len(c.Inputs))\n\tfor _, input := range c.Inputs {\n\t\tname = append(name, input.Config.Name)\n\t}\n\treturn PluginNameCounts(name)\n}\n\n// InputNamesWithSources returns a table representation of input names and their sources.\nfunc (c *Config) InputNamesWithSources() string {\n\tplugins := make(pluginNames, 0, len(c.Inputs))\n\tfor _, input := range c.Inputs {\n\t\tplugins = append(plugins, pluginPrinter{\n\t\t\tname:   input.Config.Name,\n\t\t\tsource: input.Config.Source,\n\t\t})\n\t}\n\treturn getPluginSourcesTable(plugins)\n}\n\n// AggregatorNames returns a list of strings of the configured aggregators.\nfunc (c *Config) AggregatorNames() []string {\n\tname := make([]string, 0, len(c.Aggregators))\n\tfor _, aggregator := range c.Aggregators {\n\t\tname = append(name, aggregator.Config.Name)\n\t}\n\treturn PluginNameCounts(name)\n}\n\n// AggregatorNamesWithSources returns a table representation of aggregator names and their sources.\nfunc (c *Config) AggregatorNamesWithSources() string {\n\tplugins := make(pluginNames, 0, len(c.Aggregators))\n\tfor _, aggregator := range c.Aggregators {\n\t\tplugins = append(plugins, pluginPrinter{\n\t\t\tname:   aggregator.Config.Name,\n\t\t\tsource: aggregator.Config.Source,\n\t\t})\n\t}\n\treturn getPluginSourcesTable(plugins)\n}\n\n// ProcessorNames returns a list of strings of the configured processors.\nfunc (c *Config) ProcessorNames() []string {\n\tname := make([]string, 0, len(c.Processors))\n\tfor _, processor := range c.Processors {\n\t\tname = append(name, processor.Config.Name)\n\t}\n\treturn PluginNameCounts(name)\n}\n\n// ProcessorNamesWithSources returns a table representation of processor names and their sources.\nfunc (c *Config) ProcessorNamesWithSources() string {\n\tplugins := make(pluginNames, 0, len(c.Processors))\n\tfor _, processor := range c.Processors {\n\t\tplugins = append(plugins, pluginPrinter{\n\t\t\tname:   processor.Config.Name,\n\t\t\tsource: processor.Config.Source,\n\t\t})\n\t}\n\treturn getPluginSourcesTable(plugins)\n}\n\n// OutputNames returns a list of strings of the configured outputs.\nfunc (c *Config) OutputNames() []string {\n\tname := make([]string, 0, len(c.Outputs))\n\tfor _, output := range c.Outputs {\n\t\tname = append(name, output.Config.Name)\n\t}\n\treturn PluginNameCounts(name)\n}\n\n// OutputNamesWithSources returns a table representation of output names and their sources.\nfunc (c *Config) OutputNamesWithSources() string {\n\tplugins := make(pluginNames, 0, len(c.Outputs))\n\tfor _, output := range c.Outputs {\n\t\tplugins = append(plugins, pluginPrinter{\n\t\t\tname:   output.Config.Name,\n\t\t\tsource: output.Config.Source,\n\t\t})\n\t}\n\treturn getPluginSourcesTable(plugins)\n}\n\n// SecretstoreNames returns a list of strings of the configured secret-stores.\nfunc (c *Config) SecretstoreNames() []string {\n\tnames := make([]string, 0, len(c.SecretStores))\n\tfor name := range c.SecretStores {\n\t\tnames = append(names, name)\n\t}\n\treturn PluginNameCounts(names)\n}\n\n// SecretstoreNamesWithSources returns a table representation of secret store names and their sources.\nfunc (c *Config) SecretstoreNamesWithSources() string {\n\tplugins := make(pluginNames, 0, len(c.SecretStores))\n\tfor name, sources := range c.secretStoreSource {\n\t\tfor _, source := range sources {\n\t\t\tplugins = append(plugins, pluginPrinter{\n\t\t\t\tname:   name,\n\t\t\t\tsource: source,\n\t\t\t})\n\t\t}\n\t}\n\treturn getPluginSourcesTable(plugins)\n}\n\n// PluginNameCounts returns a string of plugin names and their counts.\n// PluginNameCounts returns a list of sorted plugin names and their count\nfunc PluginNameCounts(plugins []string) []string {\n\tnames := make(map[string]int)\n\tfor _, plugin := range plugins {\n\t\tnames[plugin]++\n\t}\n\n\tvar namecount []string\n\tfor name, count := range names {\n\t\tif count == 1 {\n\t\t\tnamecount = append(namecount, name)\n\t\t} else {\n\t\t\tnamecount = append(namecount, fmt.Sprintf(\"%s (%dx)\", name, count))\n\t\t}\n\t}\n\n\tsort.Strings(namecount)\n\treturn namecount\n}\n\n// ListTags returns a string of tags specified in the config,\n// line-protocol style\nfunc (c *Config) ListTags() string {\n\ttags := make([]string, 0, len(c.Tags))\n\tfor k, v := range c.Tags {\n\t\ttags = append(tags, fmt.Sprintf(\"%s=%s\", k, v))\n\t}\n\n\tsort.Strings(tags)\n\n\treturn strings.Join(tags, \" \")\n}\n\nfunc sliceContains(name string, list []string) bool {\n\tfor _, b := range list {\n\t\tif b == name {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// WalkDirectory collects all toml files that need to be loaded\nfunc WalkDirectory(path string) ([]string, error) {\n\tvar files []string\n\twalkfn := func(thispath string, info os.FileInfo, _ error) error {\n\t\tif info == nil {\n\t\t\tlog.Printf(\"W! Telegraf is not permitted to read %s\", thispath)\n\t\t\treturn nil\n\t\t}\n\n\t\tif info.IsDir() {\n\t\t\tif strings.HasPrefix(info.Name(), \"..\") {\n\t\t\t\t// skip Kubernetes mounts, preventing loading the same config twice\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t\tname := info.Name()\n\t\tif len(name) < 6 || name[len(name)-5:] != \".conf\" {\n\t\t\treturn nil\n\t\t}\n\t\tfiles = append(files, thispath)\n\t\treturn nil\n\t}\n\treturn files, filepath.Walk(path, walkfn)\n}\n\n// GetDefaultConfigPath will try to find a default config file at these locations (in order):\n//  1. $TELEGRAF_CONFIG_PATH\n//  2. $HOME/.telegraf/telegraf.conf\n//  3. /etc/telegraf/telegraf.conf and /etc/telegraf/telegraf.d/*.conf\nfunc GetDefaultConfigPath() ([]string, error) {\n\tenvfile := os.Getenv(\"TELEGRAF_CONFIG_PATH\")\n\thomefile := os.ExpandEnv(\"${HOME}/.telegraf/telegraf.conf\")\n\tetcfile := \"/etc/telegraf/telegraf.conf\"\n\tetcfolder := \"/etc/telegraf/telegraf.d\"\n\n\tif runtime.GOOS == \"windows\" {\n\t\tprogramFiles := os.Getenv(\"ProgramFiles\")\n\t\tif programFiles == \"\" { // Should never happen\n\t\t\tprogramFiles = `C:\\Program Files`\n\t\t}\n\t\tetcfile = programFiles + `\\Telegraf\\telegraf.conf`\n\t\tetcfolder = programFiles + `\\Telegraf\\telegraf.d\\`\n\t}\n\n\tfor _, path := range []string{envfile, homefile} {\n\t\tif isURL(path) {\n\t\t\treturn []string{path}, nil\n\t\t}\n\t\tif _, err := os.Stat(path); err == nil {\n\t\t\treturn []string{path}, nil\n\t\t}\n\t}\n\n\t// At this point we need to check if the files under /etc/telegraf are\n\t// populated and return them all.\n\tconfFiles := make([]string, 0)\n\tif _, err := os.Stat(etcfile); err == nil {\n\t\tconfFiles = append(confFiles, etcfile)\n\t}\n\tif _, err := os.Stat(etcfolder); err == nil {\n\t\tfiles, err := WalkDirectory(etcfolder)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"W! unable walk %q: %s\", etcfolder, err)\n\t\t}\n\t\tconfFiles = append(confFiles, files...)\n\t}\n\tif len(confFiles) > 0 {\n\t\treturn confFiles, nil\n\t}\n\n\t// if we got here, we didn't find a file in a default location\n\treturn nil, fmt.Errorf(\"no config file specified, and could not find one\"+\n\t\t\" in $TELEGRAF_CONFIG_PATH, %s, %s, or %s/*.conf\", homefile, etcfile, etcfolder)\n}\n\n// isURL checks if string is valid url\nfunc isURL(str string) bool {\n\tu, err := url.Parse(str)\n\treturn err == nil && u.Scheme != \"\" && u.Host != \"\"\n}\n\n// LoadConfig loads the given config files and applies it to c\nfunc (c *Config) LoadConfig(path string) error {\n\tif !c.Agent.Quiet {\n\t\tlog.Printf(\"I! Loading config: %s\", path)\n\t}\n\n\tdata, _, err := LoadConfigFileWithRetries(path, c.Agent.ConfigURLRetryAttempts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"loading config file %s failed: %w\", path, err)\n\t}\n\n\tif err = c.LoadConfigData(data, path); err != nil {\n\t\treturn fmt.Errorf(\"loading config file %s failed: %w\", path, err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) LoadAll(configFiles ...string) error {\n\tfor _, fConfig := range configFiles {\n\t\tif err := c.LoadConfig(fConfig); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Sort the processors according to their `order` setting while\n\t// using a stable sort to keep the file loading / file position order.\n\tsort.Stable(c.Processors)\n\tsort.Stable(c.AggProcessors)\n\n\t// Set snmp agent translator default\n\tif c.Agent.SnmpTranslator == \"\" {\n\t\tc.Agent.SnmpTranslator = \"netsnmp\"\n\t}\n\n\t// Check if there is enough lockable memory for the secret\n\tcount := secretCount.Load()\n\tif count < 0 {\n\t\tlog.Printf(\"E! Invalid secret count %d, please report this incident including your configuration!\", count)\n\t\tcount = 0\n\t}\n\tc.NumberSecrets = uint64(count)\n\n\t// Let's link all secrets to their secret-stores\n\treturn c.LinkSecrets()\n}\n\ntype cfgDataOptions struct {\n\tsourcePath string\n}\n\ntype cfgDataOption func(*cfgDataOptions)\n\nfunc WithSourcePath(path string) cfgDataOption {\n\treturn func(o *cfgDataOptions) {\n\t\to.sourcePath = path\n\t}\n}\n\n// LoadConfigData loads TOML-formatted config data\nfunc (c *Config) LoadConfigData(data []byte, path string) error {\n\ttbl, err := parseConfig(data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing data: %w\", err)\n\t}\n\n\t// Parse tags tables first:\n\tfor _, tableName := range []string{\"tags\", \"global_tags\"} {\n\t\tif val, ok := tbl.Fields[tableName]; ok {\n\t\t\tsubTable, ok := val.(*ast.Table)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"invalid configuration, bad table name %q\", tableName)\n\t\t\t}\n\t\t\tif err = c.toml.UnmarshalTable(subTable, c.Tags); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error parsing table name %q: %w\", tableName, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Parse agent table:\n\tif val, ok := tbl.Fields[\"agent\"]; ok {\n\t\tif c.seenAgentTable {\n\t\t\tc.seenAgentTableOnce.Do(func() {\n\t\t\t\tlog.Printf(\"W! Overlapping settings in multiple agent tables are not supported: may cause undefined behavior\")\n\t\t\t})\n\t\t}\n\t\tc.seenAgentTable = true\n\n\t\tsubTable, ok := val.(*ast.Table)\n\t\tif !ok {\n\t\t\treturn errors.New(\"invalid configuration, error parsing agent table\")\n\t\t}\n\t\tif err = c.toml.UnmarshalTable(subTable, c.Agent); err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing [agent]: %w\", err)\n\t\t}\n\t}\n\n\tif !c.Agent.OmitHostname {\n\t\tif c.Agent.Hostname == \"\" {\n\t\t\thostname, err := os.Hostname()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tc.Agent.Hostname = hostname\n\t\t}\n\n\t\tc.Tags[\"host\"] = c.Agent.Hostname\n\t}\n\n\t// Warn when explicitly setting the old snmp translator\n\tif c.Agent.SnmpTranslator == \"netsnmp\" {\n\t\tPrintOptionValueDeprecationNotice(\"agent\", \"snmp_translator\", \"netsnmp\", telegraf.DeprecationInfo{\n\t\t\tSince:     \"1.25.0\",\n\t\t\tRemovalIn: \"1.40.0\",\n\t\t\tNotice:    \"Use 'gosmi' instead\",\n\t\t})\n\t}\n\n\t// Set up the persister if requested\n\tif c.Agent.Statefile != \"\" {\n\t\tc.Persister = &persister.Persister{\n\t\t\tFilename: c.Agent.Statefile,\n\t\t}\n\t}\n\n\tif len(c.UnusedFields) > 0 {\n\t\treturn fmt.Errorf(\n\t\t\t\"line %d: configuration specified the fields %q, but they were not used; \"+\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t\ttbl.Line, keys(c.UnusedFields))\n\t}\n\n\t// Initialize the file-sorting slices\n\tc.fileProcessors = make(OrderedPlugins, 0)\n\tc.fileAggProcessors = make(OrderedPlugins, 0)\n\n\t// Parse all the rest of the plugins:\n\tfor name, val := range tbl.Fields {\n\t\tsubTable, ok := val.(*ast.Table)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"invalid configuration, error parsing field %q as table\", name)\n\t\t}\n\n\t\tswitch name {\n\t\tcase \"agent\", \"global_tags\", \"tags\":\n\t\tcase \"outputs\":\n\t\t\tfor pluginName, pluginVal := range subTable.Fields {\n\t\t\t\tswitch pluginSubTable := pluginVal.(type) {\n\t\t\t\t// legacy [outputs.influxdb] support\n\t\t\t\tcase *ast.Table:\n\t\t\t\t\tif err = c.addOutput(pluginName, path, pluginSubTable); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t}\n\t\t\t\tcase []*ast.Table:\n\t\t\t\t\tfor _, t := range pluginSubTable {\n\t\t\t\t\t\tif err = c.addOutput(pluginName, path, t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s array, %w\", pluginName, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unsupported config format: %s\",\n\t\t\t\t\t\tpluginName)\n\t\t\t\t}\n\t\t\t\tif len(c.UnusedFields) > 0 {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; \"+\n\t\t\t\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t\t\t\t\tname, pluginName, subTable.Line, keys(c.UnusedFields))\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"inputs\", \"plugins\":\n\t\t\tfor pluginName, pluginVal := range subTable.Fields {\n\t\t\t\tswitch pluginSubTable := pluginVal.(type) {\n\t\t\t\t// legacy [inputs.cpu] support\n\t\t\t\tcase *ast.Table:\n\t\t\t\t\tif err = c.addInput(pluginName, path, pluginSubTable); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t}\n\t\t\t\tcase []*ast.Table:\n\t\t\t\t\tfor _, t := range pluginSubTable {\n\t\t\t\t\t\tif err = c.addInput(pluginName, path, t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unsupported config format: %s\",\n\t\t\t\t\t\tpluginName)\n\t\t\t\t}\n\t\t\t\tif len(c.UnusedFields) > 0 {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; \"+\n\t\t\t\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t\t\t\t\tname, pluginName, subTable.Line, keys(c.UnusedFields))\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"processors\":\n\t\t\tfor pluginName, pluginVal := range subTable.Fields {\n\t\t\t\tswitch pluginSubTable := pluginVal.(type) {\n\t\t\t\tcase []*ast.Table:\n\t\t\t\t\tfor _, t := range pluginSubTable {\n\t\t\t\t\t\tif err = c.addProcessor(pluginName, path, t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unsupported config format: %s\",\n\t\t\t\t\t\tpluginName)\n\t\t\t\t}\n\t\t\t\tif len(c.UnusedFields) > 0 {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; \"+\n\t\t\t\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tpluginName,\n\t\t\t\t\t\tsubTable.Line,\n\t\t\t\t\t\tkeys(c.UnusedFields),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"aggregators\":\n\t\t\tfor pluginName, pluginVal := range subTable.Fields {\n\t\t\t\tswitch pluginSubTable := pluginVal.(type) {\n\t\t\t\tcase []*ast.Table:\n\t\t\t\t\tfor _, t := range pluginSubTable {\n\t\t\t\t\t\tif err = c.addAggregator(pluginName, path, t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unsupported config format: %s\",\n\t\t\t\t\t\tpluginName)\n\t\t\t\t}\n\t\t\t\tif len(c.UnusedFields) > 0 {\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; \"+\n\t\t\t\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t\t\t\t\tname, pluginName, subTable.Line, keys(c.UnusedFields))\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"secretstores\":\n\t\t\tfor pluginName, pluginVal := range subTable.Fields {\n\t\t\t\tswitch pluginSubTable := pluginVal.(type) {\n\t\t\t\tcase []*ast.Table:\n\t\t\t\t\tfor _, t := range pluginSubTable {\n\t\t\t\t\t\tif err = c.addSecretStore(pluginName, path, t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", pluginName, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unsupported config format: %s\", pluginName)\n\t\t\t\t}\n\t\t\t\tif len(c.UnusedFields) > 0 {\n\t\t\t\t\tmsg := \"plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; \" +\n\t\t\t\t\t\t\"this is either a typo or this config option does not exist in this version\"\n\t\t\t\t\treturn fmt.Errorf(msg, name, pluginName, subTable.Line, keys(c.UnusedFields))\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Assume it's an input for legacy config file support if no other\n\t\t// identifiers are present\n\t\tdefault:\n\t\t\tif err = c.addInput(name, path, subTable); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error parsing %s, %w\", name, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort the processor according to the order they appeared in this file\n\t// In a later stage, we sort them using the `order` option.\n\tsort.Sort(c.fileProcessors)\n\tfor _, op := range c.fileProcessors {\n\t\tc.Processors = append(c.Processors, op.plugin.(*models.RunningProcessor))\n\t}\n\n\tsort.Sort(c.fileAggProcessors)\n\tfor _, op := range c.fileAggProcessors {\n\t\tc.AggProcessors = append(c.AggProcessors, op.plugin.(*models.RunningProcessor))\n\t}\n\n\treturn nil\n}\n\n// trimBOM trims the Byte-Order-Marks from the beginning of the file.\n// this is for Windows compatibility only.\n// see https://github.com/influxdata/telegraf/issues/1378\nfunc trimBOM(f []byte) []byte {\n\treturn bytes.TrimPrefix(f, []byte(\"\\xef\\xbb\\xbf\"))\n}\n\n// LoadConfigFile loads the content of a configuration file and returns it\n// together with a flag denoting if the file is from a remote location such\n// as a web server.\nfunc LoadConfigFile(config string) ([]byte, bool, error) {\n\treturn LoadConfigFileWithRetries(config, 0)\n}\n\nfunc LoadConfigFileWithRetries(config string, urlRetryAttempts int) ([]byte, bool, error) {\n\tif fetchURLRe.MatchString(config) {\n\t\tu, err := url.Parse(config)\n\t\tif err != nil {\n\t\t\treturn nil, true, err\n\t\t}\n\n\t\tswitch u.Scheme {\n\t\tcase \"https\", \"http\":\n\t\t\tdata, err := fetchConfig(u, urlRetryAttempts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, true, err\n\t\t\t}\n\t\t\tsourcesMu.Lock()\n\t\t\tsources = append(sources, u.Redacted())\n\t\t\tsourcesMu.Unlock()\n\t\t\treturn data, true, nil\n\t\tdefault:\n\t\t\treturn nil, true, fmt.Errorf(\"scheme %q not supported\", u.Scheme)\n\t\t}\n\t}\n\n\t// If it isn't a https scheme, try it as a file\n\tbuffer, err := os.ReadFile(config)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tsourcesMu.Lock()\n\tsources = append(sources, config)\n\tsourcesMu.Unlock()\n\n\tmimeType := http.DetectContentType(buffer)\n\tif !strings.Contains(mimeType, \"text/plain\") {\n\t\treturn nil, false, fmt.Errorf(\"provided config is not a TOML file: %s\", config)\n\t}\n\n\treturn buffer, false, nil\n}\n\n// GetSources returns the redacted list of configuration sources\nfunc GetSources() []string {\n\tsourcesMu.Lock()\n\tdefer sourcesMu.Unlock()\n\treturn slices.Clone(sources)\n}\n\nfunc fetchConfig(u *url.URL, urlRetryAttempts int) ([]byte, error) {\n\treq, err := http.NewRequest(\"GET\", u.String(), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif v, exists := os.LookupEnv(\"INFLUX_TOKEN\"); exists {\n\t\treq.Header.Add(\"Authorization\", \"Token \"+v)\n\t}\n\treq.Header.Add(\"Accept\", \"application/toml\")\n\treq.Header.Set(\"User-Agent\", internal.ProductToken())\n\n\tvar totalAttempts int\n\tif urlRetryAttempts == -1 {\n\t\ttotalAttempts = -1\n\t\tlog.Printf(\"Using unlimited number of attempts to fetch HTTP config\")\n\t} else if urlRetryAttempts == 0 {\n\t\ttotalAttempts = 3\n\t} else if urlRetryAttempts > 0 {\n\t\ttotalAttempts = urlRetryAttempts\n\t} else {\n\t\treturn nil, fmt.Errorf(\"invalid number of attempts: %d\", urlRetryAttempts)\n\t}\n\n\tattempt := 0\n\tfor {\n\t\tbody, err := requestURLConfig(req)\n\t\tif err == nil {\n\t\t\treturn body, nil\n\t\t}\n\n\t\tlog.Printf(\"Error getting HTTP config (attempt %d of %d): %s\", attempt, totalAttempts, err)\n\t\tif urlRetryAttempts != -1 && attempt >= totalAttempts {\n\t\t\treturn nil, err\n\t\t}\n\n\t\ttime.Sleep(httpLoadConfigRetryInterval)\n\t\tattempt++\n\t}\n}\n\nfunc requestURLConfig(req *http.Request) ([]byte, error) {\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect to HTTP config server: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to fetch HTTP config: %s\", resp.Status)\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read response body: %w\", err)\n\t}\n\n\treturn body, nil\n}\n\n// parseConfig loads a TOML configuration from a provided path and\n// returns the AST produced from the TOML parser. When loading the file, it\n// will find environment variables and replace them.\nfunc parseConfig(contents []byte) (*ast.Table, error) {\n\tcontents = trimBOM(contents)\n\tvar err error\n\tcontents, err = removeComments(contents)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Use non-strict mode\n\tif NonStrictEnvVarHandling {\n\t\toutput, err := substituteEnvironmentNonStrict(contents, OldEnvVarReplacement)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn toml.Parse(output)\n\t}\n\n\t// Use strict mode (default)\n\treturn substituteEnvironmentStrict(contents, OldEnvVarReplacement)\n}\n\nfunc (c *Config) addAggregator(name, source string, table *ast.Table) error {\n\tenabled, err := c.matchesLabelSelection(table)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid label in plugin aggregators.%s: %w\", name, err)\n\t}\n\tif !enabled {\n\t\treturn nil\n\t}\n\n\tcreator, ok := aggregators.Aggregators[name]\n\tif !ok {\n\t\t// Handle removed, deprecated plugins\n\t\tif di, deprecated := aggregators.Deprecations[name]; deprecated {\n\t\t\tprintHistoricPluginDeprecationNotice(\"aggregators\", name, di)\n\t\t\treturn errors.New(\"plugin deprecated\")\n\t\t}\n\t\treturn fmt.Errorf(\"undefined but requested aggregator: %s\", name)\n\t}\n\taggregator := creator()\n\n\tconf, err := c.buildAggregator(name, source, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.toml.UnmarshalTable(table, aggregator); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.printUserDeprecation(\"aggregators\", name, aggregator); err != nil {\n\t\treturn err\n\t}\n\n\tc.Aggregators = append(c.Aggregators, models.NewRunningAggregator(aggregator, conf))\n\treturn nil\n}\n\nfunc (c *Config) addSecretStore(name, source string, table *ast.Table) error {\n\tif len(c.SecretStoreFilters) > 0 && !sliceContains(name, c.SecretStoreFilters) {\n\t\treturn nil\n\t}\n\n\tenabled, err := c.matchesLabelSelection(table)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid label in plugin secretstores.%s: %w\", name, err)\n\t}\n\tif !enabled {\n\t\treturn nil\n\t}\n\n\tstoreID := c.getFieldString(table, \"id\")\n\tif storeID == \"\" {\n\t\treturn fmt.Errorf(\"%q secret-store without ID\", name)\n\t}\n\tif !secretStorePattern.MatchString(storeID) {\n\t\treturn fmt.Errorf(\"invalid secret-store ID %q, must only contain letters, numbers or underscore\", storeID)\n\t}\n\n\ttags := map[string]string{\n\t\t\"_id\":         storeID,\n\t\t\"secretstore\": name,\n\t}\n\n\tcreator, ok := secretstores.SecretStores[name]\n\tif !ok {\n\t\t// Handle removed, deprecated plugins\n\t\tif di, deprecated := secretstores.Deprecations[name]; deprecated {\n\t\t\tprintHistoricPluginDeprecationNotice(\"secretstores\", name, di)\n\t\t\treturn errors.New(\"plugin deprecated\")\n\t\t}\n\t\treturn fmt.Errorf(\"undefined but requested secretstores: %s\", name)\n\t}\n\tstore := creator(storeID)\n\n\tif err := c.toml.UnmarshalTable(table, store); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.printUserDeprecation(\"secretstores\", name, store); err != nil {\n\t\treturn err\n\t}\n\n\tlogger := logging.New(\"secretstores\", name, \"\")\n\tmodels.SetLoggerOnPlugin(store, logger)\n\tmodels.SetStatisticsOnPlugin(store, logger, tags)\n\n\tif err := store.Init(); err != nil {\n\t\treturn fmt.Errorf(\"error initializing secret-store %q: %w\", storeID, err)\n\t}\n\n\tif _, found := c.SecretStores[storeID]; found {\n\t\treturn fmt.Errorf(\"duplicate ID %q for secretstore %q\", storeID, name)\n\t}\n\tc.SecretStores[storeID] = store\n\tif _, found := c.secretStoreSource[name]; !found {\n\t\tc.secretStoreSource[name] = make([]string, 0)\n\t}\n\tc.secretStoreSource[name] = append(c.secretStoreSource[name], source)\n\treturn nil\n}\n\nfunc (c *Config) LinkSecrets() error {\n\tfor _, s := range unlinkedSecrets {\n\t\tresolvers := make(map[string]telegraf.ResolveFunc)\n\t\tfor _, ref := range s.GetUnlinked() {\n\t\t\t// Split the reference and lookup the resolver\n\t\t\tstoreID, key := splitLink(ref)\n\t\t\tstore, found := c.SecretStores[storeID]\n\t\t\tif !found {\n\t\t\t\treturn fmt.Errorf(\"unknown secret-store for %q\", ref)\n\t\t\t}\n\t\t\tresolver, err := store.GetResolver(key)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"retrieving resolver for %q failed: %w\", ref, err)\n\t\t\t}\n\t\t\tresolvers[ref] = resolver\n\t\t}\n\t\t// Inject the resolver list into the secret\n\t\tif err := s.Link(resolvers); err != nil {\n\t\t\treturn fmt.Errorf(\"retrieving resolver failed: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *Config) probeParser(parentCategory, parentName string, table *ast.Table) bool {\n\tdataFormat := c.getFieldString(table, \"data_format\")\n\tif dataFormat == \"\" {\n\t\tdataFormat = setDefaultParser(parentCategory, parentName)\n\t}\n\n\tcreator, ok := parsers.Parsers[dataFormat]\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Try to parse the options to detect if any of them is misspelled\n\tparser := creator(\"\")\n\t//nolint:errcheck // We don't actually use the parser, so no need to check the error.\n\tc.toml.UnmarshalTable(table, parser)\n\n\treturn true\n}\n\nfunc (c *Config) addParser(parentcategory, parentname string, table *ast.Table) (*models.RunningParser, error) {\n\tconf := &models.ParserConfig{\n\t\tParent: parentname,\n\t}\n\n\tconf.DataFormat = c.getFieldString(table, \"data_format\")\n\tif conf.DataFormat == \"\" {\n\t\tconf.DataFormat = setDefaultParser(parentcategory, parentname)\n\t} else if conf.DataFormat == \"influx\" {\n\t\tinfluxParserType := c.getFieldString(table, \"influx_parser_type\")\n\t\tif influxParserType == \"upstream\" {\n\t\t\tconf.DataFormat = \"influx_upstream\"\n\t\t}\n\t}\n\tconf.LogLevel = c.getFieldString(table, \"log_level\")\n\n\tcreator, ok := parsers.Parsers[conf.DataFormat]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"undefined but requested parser: %s\", conf.DataFormat)\n\t}\n\tparser := creator(parentname)\n\n\t// Handle reset-mode of CSV parsers to stay backward compatible (see issue #12022)\n\tif conf.DataFormat == \"csv\" && parentcategory == \"inputs\" {\n\t\tif parentname == \"exec\" {\n\t\t\tcsvParser := parser.(*csv.Parser)\n\t\t\tcsvParser.ResetMode = \"always\"\n\t\t}\n\t}\n\n\tif err := c.toml.UnmarshalTable(table, parser); err != nil {\n\t\treturn nil, err\n\t}\n\n\trunning := models.NewRunningParser(parser, conf)\n\terr := running.Init()\n\treturn running, err\n}\n\nfunc (c *Config) probeSerializer(table *ast.Table) bool {\n\tdataFormat := c.getFieldString(table, \"data_format\")\n\tif dataFormat == \"\" {\n\t\tdataFormat = \"influx\"\n\t}\n\n\tcreator, ok := serializers.Serializers[dataFormat]\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Try to parse the options to detect if any of them is misspelled\n\tserializer := creator()\n\t//nolint:errcheck // We don't actually use the parser, so no need to check the error.\n\tc.toml.UnmarshalTable(table, serializer)\n\n\treturn true\n}\n\nfunc (c *Config) addSerializer(parentname string, table *ast.Table) (*models.RunningSerializer, error) {\n\tconf := &models.SerializerConfig{\n\t\tParent: parentname,\n\t}\n\tconf.DataFormat = c.getFieldString(table, \"data_format\")\n\tif conf.DataFormat == \"\" {\n\t\tconf.DataFormat = \"influx\"\n\t}\n\tconf.LogLevel = c.getFieldString(table, \"log_level\")\n\n\tcreator, ok := serializers.Serializers[conf.DataFormat]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"undefined but requested serializer: %s\", conf.DataFormat)\n\t}\n\tserializer := creator()\n\n\tif err := c.toml.UnmarshalTable(table, serializer); err != nil {\n\t\treturn nil, err\n\t}\n\n\trunning := models.NewRunningSerializer(serializer, conf)\n\terr := running.Init()\n\treturn running, err\n}\n\nfunc (c *Config) addProcessor(name, source string, table *ast.Table) error {\n\tenabled, err := c.matchesLabelSelection(table)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid label in plugin processors.%s: %w\", name, err)\n\t}\n\tif !enabled {\n\t\treturn nil\n\t}\n\tcreator, ok := processors.Processors[name]\n\tif !ok {\n\t\t// Handle removed, deprecated plugins\n\t\tif di, deprecated := processors.Deprecations[name]; deprecated {\n\t\t\tprintHistoricPluginDeprecationNotice(\"processors\", name, di)\n\t\t\treturn errors.New(\"plugin deprecated\")\n\t\t}\n\t\treturn fmt.Errorf(\"undefined but requested processor: %s\", name)\n\t}\n\n\t// For processors with parsers we need to compute the set of\n\t// options that is not covered by both, the parser and the processor.\n\t// We achieve this by keeping a local book of missing entries\n\t// that counts the number of misses. In case we have a parser\n\t// for the input both need to miss the entry. We count the\n\t// missing entries at the end.\n\tmissCount := make(map[string]int)\n\tmissCountThreshold := 0\n\tc.setLocalMissingTomlFieldTracker(missCount)\n\tdefer c.resetMissingTomlFieldTracker()\n\n\t// Set up the processor running before the aggregators\n\tprocessorBeforeConfig, err := c.buildProcessor(\"processors\", name, source, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprocessorBefore, count, err := c.setupProcessor(processorBeforeConfig.Name, creator, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\trf := models.NewRunningProcessor(processorBefore, processorBeforeConfig)\n\tc.fileProcessors = append(c.fileProcessors, &OrderedPlugin{table.Line, rf})\n\n\t// Setup another (new) processor instance running after the aggregator\n\tprocessorAfterConfig, err := c.buildProcessor(\"aggprocessors\", name, source, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprocessorAfter, _, err := c.setupProcessor(processorAfterConfig.Name, creator, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\trf = models.NewRunningProcessor(processorAfter, processorAfterConfig)\n\tc.fileAggProcessors = append(c.fileAggProcessors, &OrderedPlugin{table.Line, rf})\n\n\t// Check the number of misses against the threshold. We need to double\n\t// the count as the processor setup is executed twice.\n\tmissCountThreshold = 2 * count\n\tfor key, count := range missCount {\n\t\tif count <= missCountThreshold {\n\t\t\tcontinue\n\t\t}\n\t\tif err := c.missingTomlField(nil, key); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) setupProcessor(name string, creator processors.StreamingCreator, table *ast.Table) (telegraf.StreamingProcessor, int, error) {\n\tvar optionTestCount int\n\n\tstreamingProcessor := creator()\n\n\tvar processor interface{}\n\tif p, ok := streamingProcessor.(processors.HasUnwrap); ok {\n\t\tprocessor = p.Unwrap()\n\t} else {\n\t\tprocessor = streamingProcessor\n\t}\n\n\t// If the (underlying) processor has a SetParser or SetParserFunc function,\n\t// it can accept arbitrary data-formats, so build the requested parser and\n\t// set it.\n\tif t, ok := processor.(telegraf.ParserPlugin); ok {\n\t\tparser, err := c.addParser(\"processors\", name, table)\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"adding parser failed: %w\", err)\n\t\t}\n\t\tt.SetParser(parser)\n\t\toptionTestCount++\n\t}\n\n\tif t, ok := processor.(telegraf.ParserFuncPlugin); ok {\n\t\tif !c.probeParser(\"processors\", name, table) {\n\t\t\treturn nil, 0, errors.New(\"parser not found\")\n\t\t}\n\t\tt.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\treturn c.addParser(\"processors\", name, table)\n\t\t})\n\t\toptionTestCount++\n\t}\n\n\t// If the (underlying) processor has a SetSerializer function it can accept\n\t// arbitrary data-formats, so build the requested serializer and set it.\n\tif t, ok := processor.(telegraf.SerializerPlugin); ok {\n\t\tserializer, err := c.addSerializer(name, table)\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"adding serializer failed: %w\", err)\n\t\t}\n\t\tt.SetSerializer(serializer)\n\t\toptionTestCount++\n\t}\n\tif t, ok := processor.(telegraf.SerializerFuncPlugin); ok {\n\t\tif !c.probeSerializer(table) {\n\t\t\treturn nil, 0, errors.New(\"serializer not found\")\n\t\t}\n\t\tt.SetSerializerFunc(func() (telegraf.Serializer, error) {\n\t\t\treturn c.addSerializer(name, table)\n\t\t})\n\t\toptionTestCount++\n\t}\n\n\tif err := c.toml.UnmarshalTable(table, processor); err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"unmarshalling failed: %w\", err)\n\t}\n\n\terr := c.printUserDeprecation(\"processors\", name, processor)\n\treturn streamingProcessor, optionTestCount, err\n}\n\nfunc (c *Config) addOutput(name, source string, table *ast.Table) error {\n\tif len(c.OutputFilters) > 0 && !sliceContains(name, c.OutputFilters) {\n\t\treturn nil\n\t}\n\n\tenabled, err := c.matchesLabelSelection(table)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid label in plugin outputs.%s: %w\", name, err)\n\t}\n\tif !enabled {\n\t\treturn nil\n\t}\n\n\t// For outputs with serializers we need to compute the set of\n\t// options that is not covered by both, the serializer and the input.\n\t// We achieve this by keeping a local book of missing entries\n\t// that counts the number of misses. In case we have a parser\n\t// for the input both need to miss the entry. We count the\n\t// missing entries at the end.\n\tmissThreshold := 0\n\tmissCount := make(map[string]int)\n\tc.setLocalMissingTomlFieldTracker(missCount)\n\tdefer c.resetMissingTomlFieldTracker()\n\n\tcreator, ok := outputs.Outputs[name]\n\tif !ok {\n\t\t// Handle removed, deprecated plugins\n\t\tif di, deprecated := outputs.Deprecations[name]; deprecated {\n\t\t\tprintHistoricPluginDeprecationNotice(\"outputs\", name, di)\n\t\t\treturn errors.New(\"plugin deprecated\")\n\t\t}\n\t\treturn fmt.Errorf(\"undefined but requested output: %s\", name)\n\t}\n\toutput := creator()\n\n\t// If the output has a SetSerializer function, then this means it can write\n\t// arbitrary types of output, so build the serializer and set it.\n\tif t, ok := output.(telegraf.SerializerPlugin); ok {\n\t\tmissThreshold = 1\n\t\tserializer, err := c.addSerializer(name, table)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tt.SetSerializer(serializer)\n\t}\n\n\tif t, ok := output.(telegraf.SerializerFuncPlugin); ok {\n\t\tmissThreshold = 1\n\t\tif !c.probeSerializer(table) {\n\t\t\treturn errors.New(\"serializer not found\")\n\t\t}\n\t\tt.SetSerializerFunc(func() (telegraf.Serializer, error) {\n\t\t\treturn c.addSerializer(name, table)\n\t\t})\n\t}\n\n\toutputConfig, err := c.buildOutput(name, source, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.toml.UnmarshalTable(table, output); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.printUserDeprecation(\"outputs\", name, output); err != nil {\n\t\treturn err\n\t}\n\n\tif c, ok := interface{}(output).(interface{ TLSConfig() (*tls.Config, error) }); ok {\n\t\tif _, err := c.TLSConfig(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check the number of misses against the threshold\n\tfor key, count := range missCount {\n\t\tif count <= missThreshold {\n\t\t\tcontinue\n\t\t}\n\t\tif err := c.missingTomlField(nil, key); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tro := models.NewRunningOutput(output, outputConfig, c.Agent.MetricBatchSize, c.Agent.MetricBufferLimit)\n\tc.Outputs = append(c.Outputs, ro)\n\n\treturn nil\n}\n\nfunc (c *Config) addInput(name, source string, table *ast.Table) error {\n\tif len(c.InputFilters) > 0 && !sliceContains(name, c.InputFilters) {\n\t\treturn nil\n\t}\n\n\tenabled, err := c.matchesLabelSelection(table)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid label in plugin inputs.%s: %w\", name, err)\n\t}\n\tif !enabled {\n\t\treturn nil\n\t}\n\n\t// For inputs with parsers we need to compute the set of\n\t// options that is not covered by both, the parser and the input.\n\t// We achieve this by keeping a local book of missing entries\n\t// that counts the number of misses. In case we have a parser\n\t// for the input both need to miss the entry. We count the\n\t// missing entries at the end.\n\tmissCount := make(map[string]int)\n\tmissCountThreshold := 0\n\tc.setLocalMissingTomlFieldTracker(missCount)\n\tdefer c.resetMissingTomlFieldTracker()\n\n\tcreator, ok := inputs.Inputs[name]\n\tif !ok {\n\t\t// Handle removed, deprecated plugins\n\t\tif di, deprecated := inputs.Deprecations[name]; deprecated {\n\t\t\tprintHistoricPluginDeprecationNotice(\"inputs\", name, di)\n\t\t\treturn errors.New(\"plugin deprecated\")\n\t\t}\n\n\t\treturn fmt.Errorf(\"undefined but requested input: %s\", name)\n\t}\n\tinput := creator()\n\n\t// If the input has a SetParser or SetParserFunc function, it can accept\n\t// arbitrary data-formats, so build the requested parser and set it.\n\tif t, ok := input.(telegraf.ParserPlugin); ok {\n\t\tmissCountThreshold = 1\n\t\tparser, err := c.addParser(\"inputs\", name, table)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"adding parser failed: %w\", err)\n\t\t}\n\t\tt.SetParser(parser)\n\t}\n\n\tif t, ok := input.(telegraf.ParserFuncPlugin); ok {\n\t\tmissCountThreshold = 1\n\t\tif !c.probeParser(\"inputs\", name, table) {\n\t\t\treturn errors.New(\"parser not found\")\n\t\t}\n\t\tt.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\treturn c.addParser(\"inputs\", name, table)\n\t\t})\n\t}\n\n\tpluginConfig, err := c.buildInput(name, source, table)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.toml.UnmarshalTable(table, input); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.printUserDeprecation(\"inputs\", name, input); err != nil {\n\t\treturn err\n\t}\n\n\tif c, ok := interface{}(input).(interface{ TLSConfig() (*tls.Config, error) }); ok {\n\t\tif _, err := c.TLSConfig(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check the number of misses against the threshold\n\tfor key, count := range missCount {\n\t\tif count <= missCountThreshold {\n\t\t\tcontinue\n\t\t}\n\t\tif err := c.missingTomlField(nil, key); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\trp := models.NewRunningInput(input, pluginConfig)\n\trp.SetDefaultTags(c.Tags)\n\tc.Inputs = append(c.Inputs, rp)\n\n\treturn nil\n}\n\n// buildAggregator parses Aggregator specific items from the ast.Table,\n// builds the filter and returns a\n// models.AggregatorConfig to be inserted into models.RunningAggregator\nfunc (c *Config) buildAggregator(name, source string, tbl *ast.Table) (*models.AggregatorConfig, error) {\n\tconf := &models.AggregatorConfig{\n\t\tName:   name,\n\t\tSource: source,\n\t\tDelay:  time.Millisecond * 100,\n\t\tPeriod: time.Second * 30,\n\t\tGrace:  time.Second * 0,\n\t}\n\n\tif period, found := c.getFieldDuration(tbl, \"period\"); found {\n\t\tconf.Period = period\n\t}\n\tif delay, found := c.getFieldDuration(tbl, \"delay\"); found {\n\t\tconf.Delay = delay\n\t}\n\tif grace, found := c.getFieldDuration(tbl, \"grace\"); found {\n\t\tconf.Grace = grace\n\t}\n\n\tconf.DropOriginal = c.getFieldBool(tbl, \"drop_original\")\n\tconf.MeasurementPrefix = c.getFieldString(tbl, \"name_prefix\")\n\tconf.MeasurementSuffix = c.getFieldString(tbl, \"name_suffix\")\n\tconf.NameOverride = c.getFieldString(tbl, \"name_override\")\n\tconf.Alias = c.getFieldString(tbl, \"alias\")\n\tconf.LogLevel = c.getFieldString(tbl, \"log_level\")\n\n\tconf.Tags = make(map[string]string)\n\tif node, ok := tbl.Fields[\"tags\"]; ok {\n\t\tif subtbl, ok := node.(*ast.Table); ok {\n\t\t\tif err := c.toml.UnmarshalTable(subtbl, conf.Tags); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse tags for input %s\", name)\n\t\t\t}\n\t\t}\n\t}\n\n\tif c.hasErrs() {\n\t\treturn nil, c.firstErr()\n\t}\n\n\tvar err error\n\tconf.Filter, err = c.buildFilter(\"aggregators.\"+name, tbl)\n\tif err != nil {\n\t\treturn conf, err\n\t}\n\n\t// Generate an ID for the plugin\n\tconf.ID, err = generatePluginID(\"aggregators.\"+name, tbl)\n\treturn conf, err\n}\n\n// buildProcessor parses Processor specific items from the ast.Table,\n// builds the filter and returns a\n// models.ProcessorConfig to be inserted into models.RunningProcessor\nfunc (c *Config) buildProcessor(category, name, source string, tbl *ast.Table) (*models.ProcessorConfig, error) {\n\tconf := &models.ProcessorConfig{\n\t\tName:   name,\n\t\tSource: source,\n\t}\n\n\tconf.Order = c.getFieldInt64(tbl, \"order\")\n\tconf.Alias = c.getFieldString(tbl, \"alias\")\n\tconf.LogLevel = c.getFieldString(tbl, \"log_level\")\n\n\tif c.hasErrs() {\n\t\treturn nil, c.firstErr()\n\t}\n\n\tvar err error\n\tconf.Filter, err = c.buildFilter(category+\".\"+name, tbl)\n\tif err != nil {\n\t\treturn conf, err\n\t}\n\n\t// Generate an ID for the plugin\n\tconf.ID, err = generatePluginID(category+\".\"+name, tbl)\n\treturn conf, err\n}\n\n// buildFilter builds a Filter\n// (tags, fields, namepass, namedrop, metricpass) to\n// be inserted into the models.OutputConfig/models.InputConfig\n// to be used for glob filtering on tags and measurements\nfunc (c *Config) buildFilter(plugin string, tbl *ast.Table) (models.Filter, error) {\n\tf := models.Filter{}\n\n\tf.NamePass = c.getFieldStringSlice(tbl, \"namepass\")\n\tf.NamePassSeparators = c.getFieldString(tbl, \"namepass_separator\")\n\tf.NameDrop = c.getFieldStringSlice(tbl, \"namedrop\")\n\tf.NameDropSeparators = c.getFieldString(tbl, \"namedrop_separator\")\n\n\toldPass := c.getFieldStringSlice(tbl, \"pass\")\n\tif len(oldPass) > 0 {\n\t\tPrintOptionDeprecationNotice(plugin, \"pass\", telegraf.DeprecationInfo{\n\t\t\tSince:     \"0.10.4\",\n\t\t\tRemovalIn: \"1.35.0\",\n\t\t\tNotice:    \"use 'fieldinclude' instead\",\n\t\t})\n\t\tf.FieldInclude = append(f.FieldInclude, oldPass...)\n\t}\n\n\toldFieldPass := c.getFieldStringSlice(tbl, \"fieldpass\")\n\tif len(oldFieldPass) > 0 {\n\t\tPrintOptionDeprecationNotice(plugin, \"fieldpass\", telegraf.DeprecationInfo{\n\t\t\tSince:     \"1.29.0\",\n\t\t\tRemovalIn: \"1.40.0\",\n\t\t\tNotice:    \"use 'fieldinclude' instead\",\n\t\t})\n\t\tf.FieldInclude = append(f.FieldInclude, oldFieldPass...)\n\t}\n\n\tfieldInclude := c.getFieldStringSlice(tbl, \"fieldinclude\")\n\tif len(fieldInclude) > 0 {\n\t\tf.FieldInclude = append(f.FieldInclude, fieldInclude...)\n\t}\n\n\toldDrop := c.getFieldStringSlice(tbl, \"drop\")\n\tif len(oldDrop) > 0 {\n\t\tPrintOptionDeprecationNotice(plugin, \"drop\", telegraf.DeprecationInfo{\n\t\t\tSince:     \"0.10.4\",\n\t\t\tRemovalIn: \"1.35.0\",\n\t\t\tNotice:    \"use 'fieldexclude' instead\",\n\t\t})\n\t\tf.FieldExclude = append(f.FieldExclude, oldDrop...)\n\t}\n\n\toldFieldDrop := c.getFieldStringSlice(tbl, \"fielddrop\")\n\tif len(oldFieldDrop) > 0 {\n\t\tPrintOptionDeprecationNotice(plugin, \"fielddrop\", telegraf.DeprecationInfo{\n\t\t\tSince:     \"1.29.0\",\n\t\t\tRemovalIn: \"1.40.0\",\n\t\t\tNotice:    \"use 'fieldexclude' instead\",\n\t\t})\n\t\tf.FieldExclude = append(f.FieldExclude, oldFieldDrop...)\n\t}\n\n\tfieldExclude := c.getFieldStringSlice(tbl, \"fieldexclude\")\n\tif len(fieldExclude) > 0 {\n\t\tf.FieldExclude = append(f.FieldExclude, fieldExclude...)\n\t}\n\n\tf.TagPassFilters = c.getFieldTagFilter(tbl, \"tagpass\")\n\tf.TagDropFilters = c.getFieldTagFilter(tbl, \"tagdrop\")\n\n\tf.TagExclude = c.getFieldStringSlice(tbl, \"tagexclude\")\n\tf.TagInclude = c.getFieldStringSlice(tbl, \"taginclude\")\n\n\tf.MetricPass = c.getFieldString(tbl, \"metricpass\")\n\n\tif c.hasErrs() {\n\t\treturn f, c.firstErr()\n\t}\n\n\tif err := f.Compile(); err != nil {\n\t\treturn f, err\n\t}\n\n\treturn f, nil\n}\n\n// buildInput parses input specific items from the ast.Table,\n// builds the filter and returns a\n// models.InputConfig to be inserted into models.RunningInput\nfunc (c *Config) buildInput(name, source string, tbl *ast.Table) (*models.InputConfig, error) {\n\tcp := &models.InputConfig{\n\t\tName:                    name,\n\t\tSource:                  source,\n\t\tAlwaysIncludeLocalTags:  c.Agent.AlwaysIncludeLocalTags,\n\t\tAlwaysIncludeGlobalTags: c.Agent.AlwaysIncludeGlobalTags,\n\t}\n\tcp.Interval, _ = c.getFieldDuration(tbl, \"interval\")\n\tcp.Precision, _ = c.getFieldDuration(tbl, \"precision\")\n\tcp.CollectionJitter, _ = c.getFieldDuration(tbl, \"collection_jitter\")\n\tcp.CollectionOffset, _ = c.getFieldDuration(tbl, \"collection_offset\")\n\tcp.StartupErrorBehavior = c.getFieldString(tbl, \"startup_error_behavior\")\n\tcp.TimeSource = c.getFieldString(tbl, \"time_source\")\n\n\tcp.MeasurementPrefix = c.getFieldString(tbl, \"name_prefix\")\n\tcp.MeasurementSuffix = c.getFieldString(tbl, \"name_suffix\")\n\tcp.NameOverride = c.getFieldString(tbl, \"name_override\")\n\tcp.Alias = c.getFieldString(tbl, \"alias\")\n\tcp.LogLevel = c.getFieldString(tbl, \"log_level\")\n\n\tcp.Tags = make(map[string]string)\n\tif node, ok := tbl.Fields[\"tags\"]; ok {\n\t\tif subtbl, ok := node.(*ast.Table); ok {\n\t\t\tif err := c.toml.UnmarshalTable(subtbl, cp.Tags); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse tags for input %s\", name)\n\t\t\t}\n\t\t}\n\t}\n\n\tif c.hasErrs() {\n\t\treturn nil, c.firstErr()\n\t}\n\n\tvar err error\n\tcp.Filter, err = c.buildFilter(\"inputs.\"+name, tbl)\n\tif err != nil {\n\t\treturn cp, err\n\t}\n\n\t// Generate an ID for the plugin\n\tcp.ID, err = generatePluginID(\"inputs.\"+name, tbl)\n\treturn cp, err\n}\n\n// buildOutput parses output specific items from the ast.Table,\n// builds the filter and returns a\n// models.OutputConfig to be inserted into models.RunningInput\n// Note: error exists in the return for future calls that might require error\nfunc (c *Config) buildOutput(name, source string, tbl *ast.Table) (*models.OutputConfig, error) {\n\tfilter, err := c.buildFilter(\"outputs.\"+name, tbl)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbufferStrategy := c.Agent.BufferStrategy\n\tif bufferStrategy == \"disk\" {\n\t\tbufferStrategy = \"disk_write_through\"\n\t}\n\tbufferDiskSync := true\n\tif c.Agent.BufferDiskSync != nil {\n\t\tbufferDiskSync = *c.Agent.BufferDiskSync\n\t}\n\n\toc := &models.OutputConfig{\n\t\tName:            name,\n\t\tSource:          source,\n\t\tFilter:          filter,\n\t\tBufferStrategy:  bufferStrategy,\n\t\tBufferDirectory: c.Agent.BufferDirectory,\n\t\tBufferDiskSync:  bufferDiskSync,\n\t}\n\n\t// TODO: support FieldPass/FieldDrop on outputs\n\n\toc.FlushInterval, _ = c.getFieldDuration(tbl, \"flush_interval\")\n\toc.FlushJitter, _ = c.getFieldDuration(tbl, \"flush_jitter\")\n\toc.MetricBufferLimit = c.getFieldInt(tbl, \"metric_buffer_limit\")\n\toc.MetricBatchSize = c.getFieldInt(tbl, \"metric_batch_size\")\n\toc.Alias = c.getFieldString(tbl, \"alias\")\n\toc.NameOverride = c.getFieldString(tbl, \"name_override\")\n\toc.NameSuffix = c.getFieldString(tbl, \"name_suffix\")\n\toc.NamePrefix = c.getFieldString(tbl, \"name_prefix\")\n\toc.StartupErrorBehavior = c.getFieldString(tbl, \"startup_error_behavior\")\n\toc.LogLevel = c.getFieldString(tbl, \"log_level\")\n\n\tif c.hasErrs() {\n\t\treturn nil, c.firstErr()\n\t}\n\n\tif oc.BufferStrategy == \"disk_write_through\" {\n\t\tlog.Printf(\"W! Using disk-write-through buffer strategy for plugin outputs.%s, this is an experimental feature\", name)\n\t}\n\n\t// Generate an ID for the plugin\n\toc.ID, err = generatePluginID(\"outputs.\"+name, tbl)\n\treturn oc, err\n}\n\nfunc (c *Config) missingTomlField(_ reflect.Type, key string) error {\n\tswitch key {\n\t// General options to ignore\n\tcase \"alias\", \"always_include_local_tags\",\n\t\t\"buffer_strategy\", \"buffer_directory\", \"buffer_disk_sync\",\n\t\t\"collection_jitter\", \"collection_offset\",\n\t\t\"data_format\", \"delay\", \"drop\", \"drop_original\",\n\t\t\"fielddrop\", \"fieldexclude\", \"fieldinclude\", \"fieldpass\", \"flush_interval\", \"flush_jitter\",\n\t\t\"grace\",\n\t\t\"interval\",\n\t\t\"log_level\", \"lvm\", // What is this used for?\n\t\t\"metric_batch_size\", \"metric_buffer_limit\", \"metricpass\",\n\t\t\"name_override\", \"name_prefix\", \"name_suffix\", \"namedrop\", \"namedrop_separator\", \"namepass\", \"namepass_separator\",\n\t\t\"order\",\n\t\t\"pass\", \"period\", \"precision\",\n\t\t\"tagdrop\", \"tagexclude\", \"taginclude\", \"tagpass\", \"tags\", \"startup_error_behavior\", \"labels\":\n\n\t// Secret-store options to ignore\n\tcase \"id\":\n\n\t// Parser and serializer options to ignore\n\tcase \"data_type\", \"influx_parser_type\":\n\n\tdefault:\n\t\tc.unusedFieldsMutex.Lock()\n\t\tc.UnusedFields[key] = true\n\t\tc.unusedFieldsMutex.Unlock()\n\t}\n\treturn nil\n}\n\nfunc (c *Config) setLocalMissingTomlFieldTracker(counter map[string]int) {\n\tf := func(t reflect.Type, key string) error {\n\t\t// Check if we are in a root element that might share options among\n\t\t// each other. Those root elements are plugins of all types.\n\t\t// All other elements are subtables of their respective plugin and\n\t\t// should just be hit once anyway. Therefore, we mark them with a\n\t\t// high number to handle them correctly later.\n\t\tpt := reflect.PointerTo(t)\n\t\troot := pt.Implements(reflect.TypeOf((*telegraf.Input)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.ServiceInput)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.Output)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.Aggregator)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.Processor)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.StreamingProcessor)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.Parser)(nil)).Elem())\n\t\troot = root || pt.Implements(reflect.TypeOf((*telegraf.Serializer)(nil)).Elem())\n\n\t\tc, ok := counter[key]\n\t\tif !root {\n\t\t\tcounter[key] = 100\n\t\t} else if !ok {\n\t\t\tcounter[key] = 1\n\t\t} else {\n\t\t\tcounter[key] = c + 1\n\t\t}\n\t\treturn nil\n\t}\n\tc.toml.MissingField = f\n}\n\nfunc (c *Config) resetMissingTomlFieldTracker() {\n\tc.toml.MissingField = c.missingTomlField\n}\n\nfunc (*Config) getFieldString(tbl *ast.Table, fieldName string) string {\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tif str, ok := kv.Value.(*ast.String); ok {\n\t\t\t\treturn str.Value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc (c *Config) getFieldDuration(tbl *ast.Table, fieldName string) (time.Duration, bool) {\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tif str, ok := kv.Value.(*ast.String); ok {\n\t\t\t\td, err := time.ParseDuration(str.Value)\n\t\t\t\tif err != nil {\n\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"error parsing duration: %w\", err))\n\t\t\t\t\treturn 0, false\n\t\t\t\t}\n\t\t\t\treturn d, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\nfunc (c *Config) getFieldBool(tbl *ast.Table, fieldName string) bool {\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tswitch t := kv.Value.(type) {\n\t\t\tcase *ast.Boolean:\n\t\t\t\ttarget, err := t.Boolean()\n\t\t\t\tif err != nil {\n\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"unknown boolean value type %q, expecting boolean\", kv.Value))\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn target\n\t\t\tcase *ast.String:\n\t\t\t\ttarget, err := strconv.ParseBool(t.Value)\n\t\t\t\tif err != nil {\n\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"unknown boolean value type %q, expecting boolean\", kv.Value))\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn target\n\t\t\tdefault:\n\t\t\t\tc.addError(tbl, fmt.Errorf(\"unknown boolean value type %q, expecting boolean\", kv.Value.Source()))\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (c *Config) getFieldInt(tbl *ast.Table, fieldName string) int {\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tif iAst, ok := kv.Value.(*ast.Integer); ok {\n\t\t\t\ti, err := iAst.Int()\n\t\t\t\tif err != nil {\n\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"unexpected int type %q, expecting int\", iAst.Value))\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\t\t\t\treturn int(i)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0\n}\n\nfunc (c *Config) getFieldInt64(tbl *ast.Table, fieldName string) int64 {\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tif iAst, ok := kv.Value.(*ast.Integer); ok {\n\t\t\t\ti, err := iAst.Int()\n\t\t\t\tif err != nil {\n\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"unexpected int type %q, expecting int\", iAst.Value))\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\t\t\t\treturn i\n\t\t\t}\n\t\t\tc.addError(tbl, fmt.Errorf(\"found unexpected format while parsing %q, expecting int\", fieldName))\n\t\t\treturn 0\n\t\t}\n\t}\n\n\treturn 0\n}\n\nfunc (c *Config) getFieldStringSlice(tbl *ast.Table, fieldName string) []string {\n\tvar target []string\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif kv, ok := node.(*ast.KeyValue); ok {\n\t\t\tary, ok := kv.Value.(*ast.Array)\n\t\t\tif !ok {\n\t\t\t\tc.addError(tbl, fmt.Errorf(\"found unexpected format while parsing %q, expecting string array/slice format\", fieldName))\n\t\t\t\treturn target\n\t\t\t}\n\t\t\tfor _, elem := range ary.Value {\n\t\t\t\tif str, ok := elem.(*ast.String); ok {\n\t\t\t\t\ttarget = append(target, str.Value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn target\n}\n\nfunc (c *Config) getFieldTagFilter(tbl *ast.Table, fieldName string) []models.TagFilter {\n\tvar target []models.TagFilter\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif subTbl, ok := node.(*ast.Table); ok {\n\t\t\tfor name, val := range subTbl.Fields {\n\t\t\t\tif kv, ok := val.(*ast.KeyValue); ok {\n\t\t\t\t\tary, ok := kv.Value.(*ast.Array)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tc.addError(tbl, fmt.Errorf(\"found unexpected format while parsing %q, expecting string array/slice format on each entry\", fieldName))\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\ttagFilter := models.TagFilter{Name: name}\n\t\t\t\t\tfor _, elem := range ary.Value {\n\t\t\t\t\t\tif str, ok := elem.(*ast.String); ok {\n\t\t\t\t\t\t\ttagFilter.Values = append(tagFilter.Values, str.Value)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttarget = append(target, tagFilter)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn target\n}\n\nfunc (*Config) getFieldMap(tbl *ast.Table, fieldName string) map[string]string {\n\ttarget := make(map[string]string)\n\tif node, ok := tbl.Fields[fieldName]; ok {\n\t\tif subTbl, ok := node.(*ast.Table); ok {\n\t\t\tfor _, val := range subTbl.Fields {\n\t\t\t\tif kv, ok := val.(*ast.KeyValue); ok {\n\t\t\t\t\tif str, ok := kv.Value.(*ast.String); ok {\n\t\t\t\t\t\ttarget[kv.Key] = str.Value\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn target\n}\n\nfunc (c *Config) matchesLabelSelection(tbl *ast.Table) (bool, error) {\n\t// Get the label definitions for the plugin and check them\n\tlabels := c.getFieldMap(tbl, \"labels\")\n\tfor k, v := range labels {\n\t\tif err := CheckLabelKeyValuePairs(k, v); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\t// Match the selection statement against the labels\n\treturn pluginLabelSelector.matches(labels), nil\n}\n\nfunc keys(m map[string]bool) []string {\n\tresult := make([]string, 0, len(m))\n\tfor k := range m {\n\t\tresult = append(result, k)\n\t}\n\treturn result\n}\n\nfunc setDefaultParser(category, name string) string {\n\t// Legacy support, exec plugin originally parsed JSON by default.\n\tif category == \"inputs\" && name == \"exec\" {\n\t\treturn \"json\"\n\t}\n\n\treturn \"influx\"\n}\n\nfunc (c *Config) hasErrs() bool {\n\treturn len(c.errs) > 0\n}\n\nfunc (c *Config) firstErr() error {\n\tif len(c.errs) == 0 {\n\t\treturn nil\n\t}\n\treturn c.errs[0]\n}\n\nfunc (c *Config) addError(tbl *ast.Table, err error) {\n\tc.errs = append(c.errs, fmt.Errorf(\"line %d:%d: %w\", tbl.Line, tbl.Position, err))\n}\n"
  },
  {
    "path": "config/config_test.go",
    "content": "package config_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/persister\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers\"\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\" // Blank import to have all parsers for testing\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json_v2\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/plugins/serializers\"\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/all\" // Blank import to have all serializers for testing\n\tserializers_prometheus \"github.com/influxdata/telegraf/plugins/serializers/prometheus\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestReadBinaryFile(t *testing.T) {\n\t// Create a temporary binary file using the Telegraf tool custom_builder to pass as a config\n\tt.Chdir(\"..\")\n\ttmpdir := t.TempDir()\n\tbinaryFile := filepath.Join(tmpdir, \"custom_builder\")\n\tcmd := exec.Command(\"go\", \"build\", \"-o\", binaryFile, \"./tools/custom_builder\")\n\n\tvar outb, errb bytes.Buffer\n\tcmd.Stdout = &outb\n\tcmd.Stderr = &errb\n\trequire.NoErrorf(t, cmd.Run(), \"stdout: %s, stderr: %s\", outb.String(), errb.String())\n\n\tc := config.NewConfig()\n\trequire.ErrorContains(t, c.LoadConfig(binaryFile), \"provided config is not a TOML file\")\n}\n\nfunc TestConfig_LoadSingleInputWithEnvVars(t *testing.T) {\n\tc := config.NewConfig()\n\tt.Setenv(\"MY_TEST_SERVER\", \"192.168.1.1\")\n\tt.Setenv(\"TEST_INTERVAL\", \"10s\")\n\tconfFile := filepath.Join(\"testdata\", \"single_plugin_env_vars.toml\")\n\trequire.NoError(t, c.LoadConfig(confFile))\n\n\tinput := inputs.Inputs[\"memcached\"]().(*MockupInputPlugin)\n\tinput.Servers = []string{\"192.168.1.1\"}\n\tinput.Command = `Raw command which may or may not contain # in it\n# is unique`\n\n\tfilter := models.Filter{\n\t\tNameDrop:     []string{\"metricname2\"},\n\t\tNamePass:     []string{\"metricname1\", \"ip_192.168.1.1_name\"},\n\t\tFieldExclude: []string{\"other\", \"stuff\"},\n\t\tFieldInclude: []string{\"some\", \"strings\"},\n\t\tTagDropFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"badtag\",\n\t\t\t\tValues: []string{\"othertag\"},\n\t\t\t},\n\t\t},\n\t\tTagPassFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"goodtag\",\n\t\t\t\tValues: []string{\"mytag\", \"tagwith#value\", \"TagWithMultilineSyntax\"},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, filter.Compile())\n\tinputConfig := &models.InputConfig{\n\t\tName:     \"memcached\",\n\t\tSource:   confFile,\n\t\tFilter:   filter,\n\t\tInterval: 10 * time.Second,\n\t}\n\tinputConfig.Tags = make(map[string]string)\n\n\t// Ignore Log, Parser and ID\n\tc.Inputs[0].Input.(*MockupInputPlugin).Log = nil\n\tc.Inputs[0].Input.(*MockupInputPlugin).parser = nil\n\tc.Inputs[0].Config.ID = \"\"\n\trequire.Equal(t, input, c.Inputs[0].Input, \"Testdata did not produce a correct mockup struct.\")\n\trequire.Equal(t, inputConfig, c.Inputs[0].Config, \"Testdata did not produce correct input metadata.\")\n}\n\nfunc TestConfig_LoadSingleInput(t *testing.T) {\n\tc := config.NewConfig()\n\tconfFile := filepath.Join(\"testdata\", \"single_plugin.toml\")\n\trequire.NoError(t, c.LoadConfig(confFile))\n\n\tinput := inputs.Inputs[\"memcached\"]().(*MockupInputPlugin)\n\tinput.Servers = []string{\"localhost\"}\n\n\tfilter := models.Filter{\n\t\tNameDrop:     []string{\"metricname2\"},\n\t\tNamePass:     []string{\"metricname1\"},\n\t\tFieldExclude: []string{\"other\", \"stuff\"},\n\t\tFieldInclude: []string{\"some\", \"strings\"},\n\t\tTagDropFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"badtag\",\n\t\t\t\tValues: []string{\"othertag\"},\n\t\t\t},\n\t\t},\n\t\tTagPassFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"goodtag\",\n\t\t\t\tValues: []string{\"mytag\"},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, filter.Compile())\n\tinputConfig := &models.InputConfig{\n\t\tName:     \"memcached\",\n\t\tSource:   confFile,\n\t\tFilter:   filter,\n\t\tInterval: 5 * time.Second,\n\t}\n\tinputConfig.Tags = make(map[string]string)\n\n\t// Ignore Log, Parser and ID\n\tc.Inputs[0].Input.(*MockupInputPlugin).Log = nil\n\tc.Inputs[0].Input.(*MockupInputPlugin).parser = nil\n\tc.Inputs[0].Config.ID = \"\"\n\trequire.Equal(t, input, c.Inputs[0].Input, \"Testdata did not produce a correct memcached struct.\")\n\trequire.Equal(t, inputConfig, c.Inputs[0].Config, \"Testdata did not produce correct memcached metadata.\")\n}\n\nfunc TestConfig_LoadSingleInput_WithSeparators(t *testing.T) {\n\tc := config.NewConfig()\n\tconfFile := filepath.Join(\"testdata\", \"single_plugin_with_separators.toml\")\n\trequire.NoError(t, c.LoadConfig(confFile))\n\n\tinput := inputs.Inputs[\"memcached\"]().(*MockupInputPlugin)\n\tinput.Servers = []string{\"localhost\"}\n\n\tfilter := models.Filter{\n\t\tNameDrop:           []string{\"metricname2\"},\n\t\tNameDropSeparators: \".\",\n\t\tNamePass:           []string{\"metricname1\"},\n\t\tNamePassSeparators: \".\",\n\t\tFieldExclude:       []string{\"other\", \"stuff\"},\n\t\tFieldInclude:       []string{\"some\", \"strings\"},\n\t\tTagDropFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"badtag\",\n\t\t\t\tValues: []string{\"othertag\"},\n\t\t\t},\n\t\t},\n\t\tTagPassFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"goodtag\",\n\t\t\t\tValues: []string{\"mytag\"},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, filter.Compile())\n\tinputConfig := &models.InputConfig{\n\t\tName:     \"memcached\",\n\t\tSource:   confFile,\n\t\tFilter:   filter,\n\t\tInterval: 5 * time.Second,\n\t}\n\tinputConfig.Tags = make(map[string]string)\n\n\t// Ignore Log, Parser and ID\n\tc.Inputs[0].Input.(*MockupInputPlugin).Log = nil\n\tc.Inputs[0].Input.(*MockupInputPlugin).parser = nil\n\tc.Inputs[0].Config.ID = \"\"\n\trequire.Equal(t, input, c.Inputs[0].Input, \"Testdata did not produce a correct memcached struct.\")\n\trequire.Equal(t, inputConfig, c.Inputs[0].Config, \"Testdata did not produce correct memcached metadata.\")\n}\n\nfunc TestConfig_LoadSingleInput_WithCommentInArray(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/single_plugin_with_comment_in_array.toml\"))\n\trequire.Len(t, c.Inputs, 1)\n\n\tinput := c.Inputs[0].Input.(*MockupInputPlugin)\n\trequire.ElementsMatch(t, input.Servers, []string{\"localhost\"})\n}\n\nfunc TestConfig_LoadDirectory(t *testing.T) {\n\tc := config.NewConfig()\n\n\tfiles, err := config.WalkDirectory(\"./testdata/subconfig\")\n\tconfFile := filepath.Join(\"testdata\", \"single_plugin.toml\")\n\tfiles = append([]string{confFile}, files...)\n\trequire.NoError(t, err)\n\trequire.NoError(t, c.LoadAll(files...))\n\n\t// Create the expected data\n\texpectedPlugins := make([]*MockupInputPlugin, 4)\n\texpectedConfigs := make([]*models.InputConfig, 4)\n\n\texpectedPlugins[0] = inputs.Inputs[\"memcached\"]().(*MockupInputPlugin)\n\texpectedPlugins[0].Servers = []string{\"localhost\"}\n\n\tfilterMockup := models.Filter{\n\t\tNameDrop:     []string{\"metricname2\"},\n\t\tNamePass:     []string{\"metricname1\"},\n\t\tFieldExclude: []string{\"other\", \"stuff\"},\n\t\tFieldInclude: []string{\"some\", \"strings\"},\n\t\tTagDropFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"badtag\",\n\t\t\t\tValues: []string{\"othertag\"},\n\t\t\t},\n\t\t},\n\t\tTagPassFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"goodtag\",\n\t\t\t\tValues: []string{\"mytag\"},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, filterMockup.Compile())\n\texpectedConfigs[0] = &models.InputConfig{\n\t\tName:     \"memcached\",\n\t\tSource:   confFile,\n\t\tFilter:   filterMockup,\n\t\tInterval: 5 * time.Second,\n\t}\n\texpectedConfigs[0].Tags = make(map[string]string)\n\n\texpectedPlugins[1] = inputs.Inputs[\"exec\"]().(*MockupInputPlugin)\n\tparser := &json.Parser{\n\t\tMetricName: \"exec\",\n\t\tStrict:     true,\n\t}\n\trequire.NoError(t, parser.Init())\n\n\texpectedPlugins[1].SetParser(parser)\n\texpectedPlugins[1].Command = \"/usr/bin/myothercollector --foo=bar\"\n\texpectedConfigs[1] = &models.InputConfig{\n\t\tName:              \"exec\",\n\t\tSource:            filepath.Join(\"testdata\", \"subconfig\", \"exec.conf\"), // This is the source of the input\n\t\tMeasurementSuffix: \"_myothercollector\",\n\t}\n\texpectedConfigs[1].Tags = make(map[string]string)\n\n\texpectedPlugins[2] = inputs.Inputs[\"memcached\"]().(*MockupInputPlugin)\n\texpectedPlugins[2].Servers = []string{\"192.168.1.1\"}\n\n\tfilterMemcached := models.Filter{\n\t\tNameDrop:     []string{\"metricname2\"},\n\t\tNamePass:     []string{\"metricname1\"},\n\t\tFieldExclude: []string{\"other\", \"stuff\"},\n\t\tFieldInclude: []string{\"some\", \"strings\"},\n\t\tTagDropFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"badtag\",\n\t\t\t\tValues: []string{\"othertag\"},\n\t\t\t},\n\t\t},\n\t\tTagPassFilters: []models.TagFilter{\n\t\t\t{\n\t\t\t\tName:   \"goodtag\",\n\t\t\t\tValues: []string{\"mytag\"},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, filterMemcached.Compile())\n\texpectedConfigs[2] = &models.InputConfig{\n\t\tName:     \"memcached\",\n\t\tSource:   filepath.Join(\"testdata\", \"subconfig\", \"memcached.conf\"), // This is the source of the input\n\t\tFilter:   filterMemcached,\n\t\tInterval: 5 * time.Second,\n\t}\n\texpectedConfigs[2].Tags = make(map[string]string)\n\n\texpectedPlugins[3] = inputs.Inputs[\"procstat\"]().(*MockupInputPlugin)\n\texpectedPlugins[3].PidFile = \"/var/run/grafana-server.pid\"\n\texpectedConfigs[3] = &models.InputConfig{\n\t\tName:   \"procstat\",\n\t\tSource: filepath.Join(\"testdata\", \"subconfig\", \"procstat.conf\"), // This is the source of the input\n\t}\n\texpectedConfigs[3].Tags = make(map[string]string)\n\n\t// Check the generated plugins\n\trequire.Len(t, c.Inputs, len(expectedPlugins))\n\trequire.Len(t, c.Inputs, len(expectedConfigs))\n\tfor i, plugin := range c.Inputs {\n\t\tinput := plugin.Input.(*MockupInputPlugin)\n\t\t// Check the logger and ignore it for comparison\n\t\trequire.NotNil(t, input.Log)\n\t\tinput.Log = nil\n\n\t\t// Check the parsers if any\n\t\tif expectedPlugins[i].parser != nil {\n\t\t\trunningParser, ok := input.parser.(*models.RunningParser)\n\t\t\trequire.True(t, ok)\n\n\t\t\t// We only use the JSON parser here\n\t\t\tparser, ok := runningParser.Parser.(*json.Parser)\n\t\t\trequire.True(t, ok)\n\n\t\t\t// Prepare parser for comparison\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tparser.Log = nil\n\n\t\t\t// Compare the parser\n\t\t\trequire.Equalf(t, expectedPlugins[i].parser, parser, \"Plugin %d: incorrect parser produced\", i)\n\t\t}\n\n\t\t// Ignore the parsers for further comparisons\n\t\tinput.parser = nil\n\t\texpectedPlugins[i].parser = nil\n\n\t\t// Ignore the ID\n\t\tplugin.Config.ID = \"\"\n\n\t\trequire.Equalf(t, expectedPlugins[i], plugin.Input, \"Plugin %d: incorrect struct produced\", i)\n\t\trequire.Equalf(t, expectedConfigs[i], plugin.Config, \"Plugin %d: incorrect config produced\", i)\n\t}\n}\n\nfunc TestConfig_WrongCertPath(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.Error(t, c.LoadConfig(\"./testdata/wrong_cert_path.toml\"))\n}\n\nfunc TestConfig_DefaultParser(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/default_parser.toml\"))\n}\n\nfunc TestConfig_DefaultExecParser(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/default_parser_exec.toml\"))\n}\n\nfunc TestConfig_LoadSpecialTypes(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/special_types.toml\"))\n\trequire.Len(t, c.Inputs, 1)\n\n\tinput, ok := c.Inputs[0].Input.(*MockupInputPlugin)\n\trequire.True(t, ok)\n\t// Tests telegraf config.Duration parsing.\n\trequire.Equal(t, config.Duration(time.Second), input.WriteTimeout)\n\t// Tests telegraf size parsing.\n\trequire.Equal(t, config.Size(1024*1024), input.MaxBodySize)\n\t// Tests toml multiline basic strings on single line.\n\trequire.Equal(t, \"./testdata/special_types.pem\", input.TLSCert)\n\t// Tests toml multiline basic strings on single line.\n\trequire.Equal(t, \"./testdata/special_types.key\", input.TLSKey)\n\t// Tests toml multiline basic strings on multiple lines.\n\trequire.Equal(t, \"/path/\", strings.TrimRight(input.Paths[0], \"\\r\\n\"))\n}\n\nfunc TestConfig_DeprecatedFilters(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/deprecated_field_filter.toml\"))\n\n\trequire.Len(t, c.Inputs, 1)\n\trequire.Equal(t, []string{\"foo\", \"bar\", \"baz\"}, c.Inputs[0].Config.Filter.FieldInclude)\n\trequire.Equal(t, []string{\"foo\", \"bar\", \"baz\"}, c.Inputs[0].Config.Filter.FieldExclude)\n}\n\nfunc TestConfig_FieldNotDefined(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"in input plugin without parser\",\n\t\t\tfilename: \"./testdata/invalid_field.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in input plugin with parser\",\n\t\t\tfilename: \"./testdata/invalid_field_with_parser.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in input plugin with parser func\",\n\t\t\tfilename: \"./testdata/invalid_field_with_parserfunc.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in parser of input plugin\",\n\t\t\tfilename: \"./testdata/invalid_field_in_parser_table.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in parser of input plugin with parser-func\",\n\t\t\tfilename: \"./testdata/invalid_field_in_parserfunc_table.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in processor plugin without parser\",\n\t\t\tfilename: \"./testdata/invalid_field_processor.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in processor plugin with parser\",\n\t\t\tfilename: \"./testdata/invalid_field_processor_with_parser.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in processor plugin with parser func\",\n\t\t\tfilename: \"./testdata/invalid_field_processor_with_parserfunc.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in parser of processor plugin\",\n\t\t\tfilename: \"./testdata/invalid_field_processor_in_parser_table.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t\t{\n\t\t\tname:     \"in parser of processor plugin with parser-func\",\n\t\t\tfilename: \"./testdata/invalid_field_processor_in_parserfunc_table.toml\",\n\t\t\texpected: \"line 1: configuration specified the fields [\\\"not_a_field\\\"], but they were not used; \" +\n\t\t\t\t\"this is either a typo or this config option does not exist in this version\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := config.NewConfig()\n\t\t\terr := c.LoadConfig(tt.filename)\n\t\t\trequire.ErrorContains(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestConfig_WrongFieldType(t *testing.T) {\n\tc := config.NewConfig()\n\terr := c.LoadConfig(\"./testdata/wrong_field_type.toml\")\n\trequire.Error(t, err, \"invalid field type\")\n\trequire.ErrorContains(t, err, \"cannot unmarshal TOML string into int\")\n\n\tc = config.NewConfig()\n\terr = c.LoadConfig(\"./testdata/wrong_field_type2.toml\")\n\trequire.Error(t, err, \"invalid field type2\")\n\trequire.ErrorContains(t, err, \"cannot unmarshal TOML string into []string\")\n}\n\nfunc TestConfig_InlineTables(t *testing.T) {\n\t// #4098\n\tt.Setenv(\"TOKEN\", \"test\")\n\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/inline_table.toml\"))\n\trequire.Len(t, c.Outputs, 2)\n\n\toutput, ok := c.Outputs[1].Output.(*MockupOutputPlugin)\n\trequire.True(t, ok)\n\trequire.Equal(t, map[string]string{\"Authorization\": \"Token test\", \"Content-Type\": \"application/json\"}, output.Headers)\n\trequire.Equal(t, []string{\"org_id\"}, c.Outputs[0].Config.Filter.TagInclude)\n}\n\nfunc TestConfig_SliceComment(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/slice_comment.toml\"))\n\trequire.Len(t, c.Outputs, 1)\n\n\toutput, ok := c.Outputs[0].Output.(*MockupOutputPlugin)\n\trequire.True(t, ok)\n\trequire.Equal(t, []string{\"test\"}, output.Scopes)\n}\n\nfunc TestConfig_BadOrdering(t *testing.T) {\n\t// #3444: when not using inline tables, care has to be taken so subsequent configuration\n\t// doesn't become part of the table. This is not a bug, but TOML syntax.\n\tc := config.NewConfig()\n\terr := c.LoadConfig(\"./testdata/non_slice_slice.toml\")\n\trequire.Error(t, err, \"bad ordering\")\n\trequire.Equal(\n\t\tt,\n\t\t\"loading config file ./testdata/non_slice_slice.toml failed: error parsing http array, line 4: cannot unmarshal TOML array into string (need slice)\",\n\t\terr.Error(),\n\t)\n}\n\nfunc TestConfig_AzureMonitorNamespacePrefix(t *testing.T) {\n\t// #8256 Cannot use empty string as the namespace prefix\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/azure_monitor.toml\"))\n\trequire.Len(t, c.Outputs, 2)\n\n\texpectedPrefix := []string{\"Telegraf/\", \"\"}\n\tfor i, plugin := range c.Outputs {\n\t\toutput, ok := plugin.Output.(*MockupOutputPlugin)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, expectedPrefix[i], output.NamespacePrefix)\n\t}\n}\n\nfunc TestGetDefaultConfigPathFromEnvURL(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := w.Write([]byte(\"[agent]\\ndebug = true\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tc := config.NewConfig()\n\tt.Setenv(\"TELEGRAF_CONFIG_PATH\", ts.URL)\n\tconfigPath, err := config.GetDefaultConfigPath()\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{ts.URL}, configPath)\n\trequire.NoError(t, c.LoadConfig(configPath[0]))\n}\n\nfunc TestConfig_URLLikeFileName(t *testing.T) {\n\tc := config.NewConfig()\n\terr := c.LoadConfig(\"http:##www.example.com.conf\")\n\trequire.Error(t, err)\n\n\tif runtime.GOOS == \"windows\" {\n\t\t// The error file not found error message is different on Windows\n\t\trequire.Equal(\n\t\t\tt,\n\t\t\t\"loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: The system cannot find the file specified.\",\n\t\t\terr.Error(),\n\t\t)\n\t} else {\n\t\trequire.Equal(t, \"loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: no such file or directory\", err.Error())\n\t}\n}\n\nfunc TestConfig_Filtering(t *testing.T) {\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadAll(\"./testdata/filter_metricpass.toml\"))\n\trequire.Len(t, c.Processors, 1)\n\n\tin := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\"state\": \"on\"},\n\t\t\tmap[string]interface{}{\"value\": 42.0},\n\t\t\ttime.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\"state\": \"off\"},\n\t\t\tmap[string]interface{}{\"value\": 23.0},\n\t\t\ttime.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"temperature\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": 23.5},\n\t\t\ttime.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC),\n\t\t),\n\t}\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\n\t\t\t\t\"state\":     \"on\",\n\t\t\t\t\"processed\": \"yes\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": 42.0},\n\t\t\ttime.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\"state\": \"off\"},\n\t\t\tmap[string]interface{}{\"value\": 23.0},\n\t\t\ttime.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"temperature\",\n\t\t\tmap[string]string{\n\t\t\t\t\"processed\": \"yes\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": 23.5},\n\t\t\ttime.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC),\n\t\t),\n\t}\n\n\tplugin := c.Processors[0]\n\tvar acc testutil.Accumulator\n\tfor _, m := range in {\n\t\trequire.NoError(t, plugin.Add(m, &acc))\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n}\n\nfunc TestConfig_SerializerInterfaceNewFormat(t *testing.T) {\n\tformats := []string{\n\t\t\"carbon2\",\n\t\t\"csv\",\n\t\t\"graphite\",\n\t\t\"influx\",\n\t\t\"json\",\n\t\t\"msgpack\",\n\t\t\"nowmetric\",\n\t\t\"prometheus\",\n\t\t\"prometheusremotewrite\",\n\t\t\"splunkmetric\",\n\t\t\"wavefront\",\n\t}\n\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/serializers_new.toml\"))\n\trequire.Len(t, c.Outputs, len(formats))\n\n\toverride := map[string]struct {\n\t\tparam map[string]interface{}\n\t\tmask  []string\n\t}{}\n\n\texpected := make([]telegraf.Serializer, 0, len(formats))\n\tfor _, format := range formats {\n\t\tlogger := logging.New(\"serializers\", format, \"test\")\n\n\t\tvar serializer telegraf.Serializer\n\t\tif creator, found := serializers.Serializers[format]; found {\n\t\t\tt.Logf(\"new-style %q\", format)\n\t\t\tserializer = creator()\n\t\t}\n\n\t\tif settings, found := override[format]; found {\n\t\t\ts := reflect.Indirect(reflect.ValueOf(serializer))\n\t\t\tfor key, value := range settings.param {\n\t\t\t\tv := reflect.ValueOf(value)\n\t\t\t\ts.FieldByName(key).Set(v)\n\t\t\t}\n\t\t}\n\t\tmodels.SetLoggerOnPlugin(serializer, logger)\n\t\tif s, ok := serializer.(telegraf.Initializer); ok {\n\t\t\trequire.NoError(t, s.Init())\n\t\t}\n\t\texpected = append(expected, serializer)\n\t}\n\trequire.Len(t, expected, len(formats))\n\n\tactual := make([]interface{}, 0)\n\tfor _, plugin := range c.Outputs {\n\t\toutput, ok := plugin.Output.(*MockupOutputPluginSerializerNew)\n\t\trequire.True(t, ok)\n\t\t// Get the parser set with 'SetParser()'\n\t\tif p, ok := output.Serializer.(*models.RunningSerializer); ok {\n\t\t\tactual = append(actual, p.Serializer)\n\t\t} else {\n\t\t\tactual = append(actual, output.Serializer)\n\t\t}\n\t}\n\trequire.Len(t, actual, len(formats))\n\n\tfor i, format := range formats {\n\t\t// Determine the underlying type of the serializer\n\t\tstype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface()\n\t\t// Ignore all unexported fields and fields not relevant for functionality\n\t\toptions := []cmp.Option{\n\t\t\tcmpopts.IgnoreUnexported(stype),\n\t\t\tcmpopts.IgnoreUnexported(reflect.Indirect(reflect.ValueOf(serializers_prometheus.MetricTypes{})).Interface()),\n\t\t\tcmpopts.IgnoreTypes(sync.Mutex{}, regexp.Regexp{}),\n\t\t\tcmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}),\n\t\t}\n\t\tif settings, found := override[format]; found {\n\t\t\toptions = append(options, cmpopts.IgnoreFields(stype, settings.mask...))\n\t\t}\n\n\t\t// Do a manual comparison as require.EqualValues will also work on unexported fields\n\t\t// that cannot be cleared or ignored.\n\t\tdiff := cmp.Diff(expected[i], actual[i], options...)\n\t\trequire.Emptyf(t, diff, \"Difference in SetSerializer() for %q\", format)\n\t}\n}\n\nfunc TestConfig_ParserInterface(t *testing.T) {\n\tformats := []string{\n\t\t\"collectd\",\n\t\t\"csv\",\n\t\t\"dropwizard\",\n\t\t\"form_urlencoded\",\n\t\t\"graphite\",\n\t\t\"grok\",\n\t\t\"influx\",\n\t\t\"json\",\n\t\t\"json_v2\",\n\t\t\"logfmt\",\n\t\t\"nagios\",\n\t\t\"prometheus\",\n\t\t\"prometheusremotewrite\",\n\t\t\"value\",\n\t\t\"wavefront\",\n\t\t\"xml\", \"xpath_json\", \"xpath_msgpack\", \"xpath_protobuf\",\n\t}\n\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"./testdata/parsers_new.toml\"))\n\trequire.Len(t, c.Inputs, len(formats))\n\n\toverride := map[string]struct {\n\t\tparam map[string]interface{}\n\t\tmask  []string\n\t}{\n\t\t\"csv\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"HeaderRowCount\": 42,\n\t\t\t},\n\t\t\tmask: []string{\"TimeFunc\", \"ResetMode\"},\n\t\t},\n\t\t\"xpath_protobuf\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"ProtobufMessageDef\":  \"testdata/addressbook.proto\",\n\t\t\t\t\"ProtobufMessageType\": \"addressbook.AddressBook\",\n\t\t\t},\n\t\t},\n\t\t\"json_v2\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"Configs\": []json_v2.Config{{\n\t\t\t\t\tFields: []json_v2.DataSet{{\n\t\t\t\t\t\tPath:     \"\",\n\t\t\t\t\t\tType:     \"int\",\n\t\t\t\t\t\tRename:   \"\",\n\t\t\t\t\t\tOptional: false,\n\t\t\t\t\t}},\n\t\t\t\t}},\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := make([]telegraf.Parser, 0, len(formats))\n\tfor _, format := range formats {\n\t\tlogger := logging.New(\"parsers\", format, \"parser_test_new\")\n\n\t\tcreator, found := parsers.Parsers[format]\n\t\trequire.Truef(t, found, \"No parser for format %q\", format)\n\n\t\tparser := creator(\"parser_test_new\")\n\t\tif settings, found := override[format]; found {\n\t\t\ts := reflect.Indirect(reflect.ValueOf(parser))\n\t\t\tfor key, value := range settings.param {\n\t\t\t\tv := reflect.ValueOf(value)\n\t\t\t\ts.FieldByName(key).Set(v)\n\t\t\t}\n\t\t}\n\t\tmodels.SetLoggerOnPlugin(parser, logger)\n\t\tif p, ok := parser.(telegraf.Initializer); ok {\n\t\t\trequire.NoError(t, p.Init())\n\t\t}\n\t\texpected = append(expected, parser)\n\t}\n\trequire.Len(t, expected, len(formats))\n\n\tactual := make([]interface{}, 0)\n\tgenerated := make([]interface{}, 0)\n\tfor _, plugin := range c.Inputs {\n\t\tinput, ok := plugin.Input.(*MockupInputPluginParserNew)\n\t\trequire.True(t, ok)\n\t\t// Get the parser set with 'SetParser()'\n\t\tif p, ok := input.Parser.(*models.RunningParser); ok {\n\t\t\tactual = append(actual, p.Parser)\n\t\t} else {\n\t\t\tactual = append(actual, input.Parser)\n\t\t}\n\t\t// Get the parser set with 'SetParserFunc()'\n\t\tg, err := input.ParserFunc()\n\t\trequire.NoError(t, err)\n\t\tif rp, ok := g.(*models.RunningParser); ok {\n\t\t\tgenerated = append(generated, rp.Parser)\n\t\t} else {\n\t\t\tgenerated = append(generated, g)\n\t\t}\n\t}\n\trequire.Len(t, actual, len(formats))\n\n\tfor i, format := range formats {\n\t\t// Determine the underlying type of the parser\n\t\tstype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface()\n\t\t// Ignore all unexported fields and fields not relevant for functionality\n\t\toptions := []cmp.Option{\n\t\t\tcmpopts.IgnoreUnexported(stype),\n\t\t\tcmpopts.IgnoreTypes(sync.Mutex{}),\n\t\t\tcmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}),\n\t\t}\n\t\tif settings, found := override[format]; found {\n\t\t\toptions = append(options, cmpopts.IgnoreFields(stype, settings.mask...))\n\t\t}\n\n\t\t// Do a manual comparison as require.EqualValues will also work on unexported fields\n\t\t// that cannot be cleared or ignored.\n\t\tdiff := cmp.Diff(expected[i], actual[i], options...)\n\t\trequire.Emptyf(t, diff, \"Difference in SetParser() for %q\", format)\n\t\tdiff = cmp.Diff(expected[i], generated[i], options...)\n\t\trequire.Emptyf(t, diff, \"Difference in SetParserFunc() for %q\", format)\n\t}\n}\n\nfunc TestConfig_MultipleProcessorsOrder(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tfilename      []string\n\t\texpectedOrder []string\n\t}{\n\t\t{\n\t\t\tname:     \"Test the order of multiple unique processosr\",\n\t\t\tfilename: []string{\"multiple_processors.toml\"},\n\t\t\texpectedOrder: []string{\n\t\t\t\t\"processor\",\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Test using a single 'order' configuration\",\n\t\t\tfilename: []string{\"multiple_processors_simple_order.toml\"},\n\t\t\texpectedOrder: []string{\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"processor\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Test using multiple 'order' configurations\",\n\t\t\tfilename: []string{\"multiple_processors_messy_order.toml\"},\n\t\t\texpectedOrder: []string{\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"processor\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Test loading multiple configuration files\",\n\t\t\tfilename: []string{\n\t\t\t\t\"multiple_processors.toml\",\n\t\t\t\t\"multiple_processors_simple_order.toml\",\n\t\t\t},\n\t\t\texpectedOrder: []string{\n\t\t\t\t\"processor\",\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"processor\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Test loading multiple configuration files both with order\",\n\t\t\tfilename: []string{\n\t\t\t\t\"multiple_processors_simple_order.toml\",\n\t\t\t\t\"multiple_processors_messy_order.toml\",\n\t\t\t},\n\t\t\texpectedOrder: []string{\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"parser_test\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t\t\"processor\",\n\t\t\t\t\"processor\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parser\",\n\t\t\t\t\"processor_parserfunc\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tc := config.NewConfig()\n\t\t\tfilenames := make([]string, 0, len(test.filename))\n\t\t\tfor _, fn := range test.filename {\n\t\t\t\tfilenames = append(filenames, filepath.Join(\".\", \"testdata\", \"processor_order\", fn))\n\t\t\t}\n\t\t\trequire.NoError(t, c.LoadAll(filenames...))\n\n\t\t\trequire.Len(t, c.Processors, len(test.expectedOrder))\n\n\t\t\torder := make([]string, 0, len(c.Processors))\n\t\t\tfor _, p := range c.Processors {\n\t\t\t\torder = append(order, p.Config.Name)\n\t\t\t}\n\n\t\t\trequire.Equal(t, test.expectedOrder, order)\n\t\t})\n\t}\n}\n\nfunc TestConfig_ProcessorsWithParsers(t *testing.T) {\n\tformats := []string{\n\t\t\"collectd\",\n\t\t\"csv\",\n\t\t\"dropwizard\",\n\t\t\"form_urlencoded\",\n\t\t\"graphite\",\n\t\t\"grok\",\n\t\t\"influx\",\n\t\t\"json\",\n\t\t\"json_v2\",\n\t\t\"logfmt\",\n\t\t\"nagios\",\n\t\t\"prometheus\",\n\t\t\"prometheusremotewrite\",\n\t\t\"value\",\n\t\t\"wavefront\",\n\t\t\"xml\", \"xpath_json\", \"xpath_msgpack\", \"xpath_protobuf\",\n\t}\n\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadAll(\"./testdata/processors_with_parsers.toml\"))\n\trequire.Len(t, c.Processors, len(formats))\n\n\toverride := map[string]struct {\n\t\tparam map[string]interface{}\n\t\tmask  []string\n\t}{\n\t\t\"csv\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"HeaderRowCount\": 42,\n\t\t\t},\n\t\t\tmask: []string{\"TimeFunc\", \"ResetMode\"},\n\t\t},\n\t\t\"xpath_protobuf\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"ProtobufMessageDef\":  \"testdata/addressbook.proto\",\n\t\t\t\t\"ProtobufMessageType\": \"addressbook.AddressBook\",\n\t\t\t},\n\t\t},\n\t\t\"json_v2\": {\n\t\t\tparam: map[string]interface{}{\n\t\t\t\t\"Configs\": []json_v2.Config{{\n\t\t\t\t\tFields: []json_v2.DataSet{{\n\t\t\t\t\t\tPath:     \"\",\n\t\t\t\t\t\tType:     \"int\",\n\t\t\t\t\t\tRename:   \"\",\n\t\t\t\t\t\tOptional: false,\n\t\t\t\t\t}},\n\t\t\t\t}},\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := make([]telegraf.Parser, 0, len(formats))\n\tfor _, format := range formats {\n\t\tlogger := logging.New(\"parsers\", format, \"processors_with_parsers\")\n\n\t\tcreator, found := parsers.Parsers[format]\n\t\trequire.Truef(t, found, \"No parser for format %q\", format)\n\n\t\tparser := creator(\"parser_test\")\n\t\tif settings, found := override[format]; found {\n\t\t\ts := reflect.Indirect(reflect.ValueOf(parser))\n\t\t\tfor key, value := range settings.param {\n\t\t\t\tv := reflect.ValueOf(value)\n\t\t\t\ts.FieldByName(key).Set(v)\n\t\t\t}\n\t\t}\n\t\tmodels.SetLoggerOnPlugin(parser, logger)\n\t\tif p, ok := parser.(telegraf.Initializer); ok {\n\t\t\trequire.NoError(t, p.Init())\n\t\t}\n\t\texpected = append(expected, parser)\n\t}\n\trequire.Len(t, expected, len(formats))\n\n\tactual := make([]interface{}, 0)\n\tgenerated := make([]interface{}, 0)\n\tfor _, plugin := range c.Processors {\n\t\tvar processorIF telegraf.Processor\n\t\tif p, ok := plugin.Processor.(processors.HasUnwrap); ok {\n\t\t\tprocessorIF = p.Unwrap()\n\t\t} else {\n\t\t\tprocessorIF = plugin.Processor.(telegraf.Processor)\n\t\t}\n\t\trequire.NotNil(t, processorIF)\n\n\t\tprocessor, ok := processorIF.(*MockupProcessorPluginParser)\n\t\trequire.True(t, ok)\n\n\t\t// Get the parser set with 'SetParser()'\n\t\tif p, ok := processor.Parser.(*models.RunningParser); ok {\n\t\t\tactual = append(actual, p.Parser)\n\t\t} else {\n\t\t\tactual = append(actual, processor.Parser)\n\t\t}\n\t\t// Get the parser set with 'SetParserFunc()'\n\t\tif processor.ParserFunc != nil {\n\t\t\tg, err := processor.ParserFunc()\n\t\t\trequire.NoError(t, err)\n\t\t\tif rp, ok := g.(*models.RunningParser); ok {\n\t\t\t\tgenerated = append(generated, rp.Parser)\n\t\t\t} else {\n\t\t\t\tgenerated = append(generated, g)\n\t\t\t}\n\t\t} else {\n\t\t\tgenerated = append(generated, nil)\n\t\t}\n\t}\n\trequire.Len(t, actual, len(formats))\n\n\tfor i, format := range formats {\n\t\t// Determine the underlying type of the parser\n\t\tstype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface()\n\t\t// Ignore all unexported fields and fields not relevant for functionality\n\t\toptions := []cmp.Option{\n\t\t\tcmpopts.IgnoreUnexported(stype),\n\t\t\tcmpopts.IgnoreTypes(sync.Mutex{}),\n\t\t\tcmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}),\n\t\t}\n\t\tif settings, found := override[format]; found {\n\t\t\toptions = append(options, cmpopts.IgnoreFields(stype, settings.mask...))\n\t\t}\n\n\t\t// Do a manual comparison as require.EqualValues will also work on unexported fields\n\t\t// that cannot be cleared or ignored.\n\t\tdiff := cmp.Diff(expected[i], actual[i], options...)\n\t\trequire.Emptyf(t, diff, \"Difference in SetParser() for %q\", format)\n\t\tdiff = cmp.Diff(expected[i], generated[i], options...)\n\t\trequire.Emptyf(t, diff, \"Difference in SetParserFunc() for %q\", format)\n\t}\n}\n\nfunc TestConfigPluginIDsDifferent(t *testing.T) {\n\tc := config.NewConfig()\n\tc.Agent.Statefile = \"/dev/null\"\n\trequire.NoError(t, c.LoadConfig(\"./testdata/state_persistence_input_all_different.toml\"))\n\trequire.NotEmpty(t, c.Inputs)\n\n\t// Compare generated IDs\n\tfor i, pi := range c.Inputs {\n\t\trefid := pi.Config.ID\n\t\trequire.NotEmpty(t, refid)\n\n\t\t// Cross-comparison\n\t\tfor j, pj := range c.Inputs {\n\t\t\ttestid := pj.Config.ID\n\t\t\tif i == j {\n\t\t\t\trequire.Equal(t, refid, testid)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\trequire.NotEqualf(t, refid, testid, \"equal for %d, %d\", i, j)\n\t\t}\n\t}\n}\n\nfunc TestConfigPluginIDsSame(t *testing.T) {\n\tc := config.NewConfig()\n\tc.Agent.Statefile = \"/dev/null\"\n\trequire.NoError(t, c.LoadConfig(\"./testdata/state_persistence_input_all_same.toml\"))\n\trequire.NotEmpty(t, c.Inputs)\n\n\t// Compare generated IDs\n\tfor i, pi := range c.Inputs {\n\t\trefid := pi.Config.ID\n\t\trequire.NotEmpty(t, refid)\n\n\t\t// Cross-comparison\n\t\tfor j, pj := range c.Inputs {\n\t\t\ttestid := pj.Config.ID\n\t\t\trequire.Equal(t, refid, testid, \"not equal for %d, %d\", i, j)\n\t\t}\n\t}\n}\n\nfunc TestPersisterInputStoreLoad(t *testing.T) {\n\t// Reserve a temporary state file\n\tfile, err := os.CreateTemp(t.TempDir(), \"telegraf_state-*.json\")\n\trequire.NoError(t, err)\n\tfilename := file.Name()\n\trequire.NoError(t, file.Close())\n\n\t// Load the plugins\n\tcstore := config.NewConfig()\n\trequire.NoError(t, cstore.LoadConfig(\"testdata/state_persistence_input_store_load.toml\"))\n\n\t// Initialize the persister for storing the state\n\tpersisterStore := persister.Persister{\n\t\tFilename: filename,\n\t}\n\trequire.NoError(t, persisterStore.Init())\n\n\texpected := make(map[string]interface{})\n\tfor i, plugin := range cstore.Inputs {\n\t\trequire.NoError(t, plugin.Init())\n\n\t\t// Register\n\t\tp := plugin.Input.(*MockupStatePlugin)\n\t\trequire.NoError(t, persisterStore.Register(plugin.ID(), p))\n\n\t\t// Change the state\n\t\tp.state.Name += \"_\" + strings.Repeat(\"a\", i+1)\n\t\tp.state.Version++\n\t\tp.state.Offset += uint64(i + 1)\n\t\tp.state.Bits = append(p.state.Bits, len(p.state.Bits))\n\t\tp.state.Modified, err = time.Parse(time.RFC3339, \"2022-11-03T16:49:00+02:00\")\n\t\trequire.NoError(t, err)\n\n\t\t// Store the state for later comparison\n\t\texpected[plugin.ID()] = p.GetState()\n\t}\n\n\t// Write state\n\trequire.NoError(t, persisterStore.Store())\n\n\t// Load the plugins\n\tcload := config.NewConfig()\n\trequire.NoError(t, cload.LoadConfig(\"testdata/state_persistence_input_store_load.toml\"))\n\trequire.Len(t, cload.Inputs, len(expected))\n\n\t// Initialize the persister for loading the state\n\tpersisterLoad := persister.Persister{\n\t\tFilename: filename,\n\t}\n\trequire.NoError(t, persisterLoad.Init())\n\n\tfor _, plugin := range cload.Inputs {\n\t\trequire.NoError(t, plugin.Init())\n\n\t\t// Register\n\t\tp := plugin.Input.(*MockupStatePlugin)\n\t\trequire.NoError(t, persisterLoad.Register(plugin.ID(), p))\n\n\t\t// Check that the states are not yet restored\n\t\trequire.NotNil(t, expected[plugin.ID()])\n\t\trequire.NotEqual(t, expected[plugin.ID()], p.GetState())\n\t}\n\n\t// Restore states\n\trequire.NoError(t, persisterLoad.Load())\n\n\t// Check we got what we saved.\n\tfor _, plugin := range cload.Inputs {\n\t\tp := plugin.Input.(*MockupStatePlugin)\n\t\trequire.Equal(t, expected[plugin.ID()], p.GetState())\n\t}\n}\n\nfunc TestPersisterProcessorRegistration(t *testing.T) {\n\t// Load the plugins\n\tc := config.NewConfig()\n\trequire.NoError(t, c.LoadConfig(\"testdata/state_persistence_processors.toml\"))\n\trequire.NotEmpty(t, c.Processors)\n\trequire.NotEmpty(t, c.AggProcessors)\n\n\t// Initialize the persister for test\n\tdut := persister.Persister{\n\t\tFilename: \"/tmp/doesn_t_matter.json\",\n\t}\n\trequire.NoError(t, dut.Init())\n\n\t// Register the processors\n\tfor _, plugin := range c.Processors {\n\t\tunwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap()\n\n\t\tp := unwrapped.(*MockupProcessorPlugin)\n\t\trequire.NoError(t, dut.Register(plugin.ID(), p))\n\t}\n\n\t// Register the after-aggregator processors\n\tfor _, plugin := range c.AggProcessors {\n\t\tunwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap()\n\n\t\tp := unwrapped.(*MockupProcessorPlugin)\n\t\trequire.NoError(t, dut.Register(plugin.ID(), p))\n\t}\n}\n\nfunc TestConfigEnvVarsStrict(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfile     string\n\t\tenvvars  map[string]string\n\t\texpected *MockupInputPlugin\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tfile: \"envvar_valid.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tPort:    8080,\n\t\t\t\tCommand: `Raw command which may or may not contain # in it\n# is unique`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid multiline\",\n\t\t\tfile: \"envvar_valid_multiline.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t\t\"COMMAND\": `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tPort:    8080,\n\t\t\t\tCommand: \"    \" + `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t` + \"\\n  \",\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tname: \"malicious envvar\",\n\t\t\tfile: \"envvar_malicious.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"PORT\": \"8080\",\n\t\t\t\t\"PIDFILE\": `a pid\"\n\n\t\t\t[[inputs.memcached]]\n\t\t\t  command = \"evil`,\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"my.server.com\"},\n\t\t\t\tPort:    8080,\n\t\t\t\tCommand: `Raw command which may or may not contain # in it\n# is unique`,\n\t\t\t\tPidFile: `a pid\"\n\n\t\t\t[[inputs.memcached]]\n\t\t\t  command = \"evil`,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconfig.NonStrictEnvVarHandling = false\n\n\t\t\t// Export the environment variables\n\t\t\tfor k, v := range tt.envvars {\n\t\t\t\tt.Setenv(k, v)\n\t\t\t}\n\n\t\t\t// Load the config\n\t\t\tc := config.NewConfig()\n\t\t\tconfFile := filepath.Join(\"testdata\", tt.file)\n\t\t\trequire.NoError(t, c.LoadConfig(confFile))\n\n\t\t\t// Validate the loaded data\n\t\t\trequire.Len(t, c.Inputs, 1)\n\t\t\tplugin, ok := c.Inputs[0].Input.(*MockupInputPlugin)\n\t\t\trequire.Truef(t, ok, \"plugin is of wrong type %T\", c.Inputs[0].Input)\n\n\t\t\t// Ignore Log, Parser and ID\n\t\t\tplugin.Log = nil\n\t\t\tplugin.parser = nil\n\t\t\trequire.Equal(t, tt.expected, plugin)\n\t\t})\n\t}\n}\n\nfunc TestConfigEnvVarsStrictFailNonString(t *testing.T) {\n\tconfig.NonStrictEnvVarHandling = false\n\n\tenvvars := map[string]string{\n\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\"PORT\":           \"443\",\n\t}\n\n\t// Export the environment variables\n\tfor k, v := range envvars {\n\t\tt.Setenv(k, v)\n\t}\n\n\t// Load the config\n\tc := config.NewConfig()\n\tconfFile := filepath.Join(\"testdata\", \"envvar_non_string.conf\")\n\trequire.ErrorContains(t, c.LoadConfig(confFile), \"invalid TOML syntax\")\n}\n\nfunc TestConfigEnvVarsNonStrict(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfile     string\n\t\tenvvars  map[string]string\n\t\texpected *MockupInputPlugin\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tfile: \"envvar_valid.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tCommand: `Raw command which may or may not contain # in it\n# is unique`,\n\t\t\t\tPort: 8080,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"non-string\",\n\t\t\tfile: \"envvar_non_string.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t\t\"PORT\":           \"443\",\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tPort:    443,\n\t\t\t\tCommand: `Raw command which may or may not contain # in it\n# is unique`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid multiline\",\n\t\t\tfile: \"envvar_valid_multiline.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t\t\"COMMAND\": `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tPort:    8080,\n\t\t\t\tCommand: \"    \" + `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t` + \"\\n  \",\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tname: \"non-string multiline\",\n\t\t\tfile: \"envvar_non_string_multiline.conf\",\n\t\t\tenvvars: map[string]string{\n\t\t\t\t\"MY_TEST_SERVER\": \"192.168.1.1\",\n\t\t\t\t\"PORT\":           \"443\",\n\t\t\t\t\"COMMAND\": `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpected: &MockupInputPlugin{\n\t\t\t\tServers: []string{\"192.168.1.1\"},\n\t\t\t\tPort:    443,\n\t\t\t\tCommand: \"    \" + `\n\t\t\t\t\tRaw command potentially\n\t\t\t\t\twith multiple\n\t\t\t\t\tlines in it\n\t\t\t\t` + \"\\n  \",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconfig.NonStrictEnvVarHandling = true\n\t\t\tt.Cleanup(func() {\n\t\t\t\tconfig.NonStrictEnvVarHandling = false\n\t\t\t})\n\n\t\t\t// Export the environment variables\n\t\t\tfor k, v := range tt.envvars {\n\t\t\t\tt.Setenv(k, v)\n\t\t\t}\n\n\t\t\t// Load the config\n\t\t\tc := config.NewConfig()\n\t\t\tconfFile := filepath.Join(\"testdata\", tt.file)\n\t\t\trequire.NoError(t, c.LoadConfig(confFile))\n\n\t\t\t// Validate the loaded data\n\t\t\trequire.Len(t, c.Inputs, 1)\n\t\t\tplugin, ok := c.Inputs[0].Input.(*MockupInputPlugin)\n\t\t\trequire.Truef(t, ok, \"plugin is of wrong type %T\", c.Inputs[0].Input)\n\n\t\t\t// Ignore Log, Parser and ID\n\t\t\tplugin.Log = nil\n\t\t\tplugin.parser = nil\n\t\t\trequire.Equal(t, tt.expected, plugin)\n\t\t})\n\t}\n}\n\nfunc TestConfigEnvVarsNonStrictMalicious(t *testing.T) {\n\tenvvars := map[string]string{\n\t\t\"PORT\": \"8080\",\n\t\t\"PIDFILE\": `a pid\"\n\n\t\t\t[[inputs.memcached]]\n\t\t\t  command = \"evil`,\n\t}\n\n\tconfig.NonStrictEnvVarHandling = true\n\tt.Cleanup(func() {\n\t\tconfig.NonStrictEnvVarHandling = false\n\t})\n\n\t// Export the environment variables\n\tfor k, v := range envvars {\n\t\tt.Setenv(k, v)\n\t}\n\n\t// Load the config\n\tc := config.NewConfig()\n\tconfFile := filepath.Join(\"testdata\", \"envvar_malicious.conf\")\n\trequire.NoError(t, c.LoadConfig(confFile))\n\n\t// We expect too plugins due to malicious environment setting\n\trequire.Len(t, c.Inputs, 2)\n}\n\n// Mockup INPUT plugin for (new) parser testing to avoid cyclic dependencies\ntype MockupInputPluginParserNew struct {\n\tParser     telegraf.Parser\n\tParserFunc telegraf.ParserFunc\n}\n\nfunc (*MockupInputPluginParserNew) SampleConfig() string {\n\treturn \"Mockup old parser test plugin\"\n}\nfunc (*MockupInputPluginParserNew) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) {\n\tm.Parser = parser\n}\nfunc (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) {\n\tm.ParserFunc = f\n}\n\n// Mockup INPUT plugin for testing to avoid cyclic dependencies\ntype MockupInputPlugin struct {\n\tServers      []string        `toml:\"servers\"`\n\tMethods      []string        `toml:\"methods\"`\n\tTimeout      config.Duration `toml:\"timeout\"`\n\tReadTimeout  config.Duration `toml:\"read_timeout\"`\n\tWriteTimeout config.Duration `toml:\"write_timeout\"`\n\tMaxBodySize  config.Size     `toml:\"max_body_size\"`\n\tPaths        []string        `toml:\"paths\"`\n\tPort         int             `toml:\"port\"`\n\tPassword     config.Secret   `toml:\"password\"`\n\tCommand      string\n\tFiles        []string\n\tPidFile      string\n\tLog          telegraf.Logger `toml:\"-\"`\n\ttls.ServerConfig\n\n\tparser telegraf.Parser\n}\n\nfunc (*MockupInputPlugin) SampleConfig() string {\n\treturn \"Mockup test input plugin\"\n}\nfunc (*MockupInputPlugin) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupInputPlugin) SetParser(parser telegraf.Parser) {\n\tm.parser = parser\n}\n\n// Mockup INPUT plugin with ParserFunc interface\ntype MockupInputPluginParserFunc struct {\n\tparserFunc telegraf.ParserFunc\n}\n\nfunc (*MockupInputPluginParserFunc) SampleConfig() string {\n\treturn \"Mockup test input plugin\"\n}\nfunc (*MockupInputPluginParserFunc) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupInputPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) {\n\tm.parserFunc = pf\n}\n\n// Mockup INPUT plugin without ParserFunc interface\ntype MockupInputPluginParserOnly struct {\n\tparser telegraf.Parser\n}\n\nfunc (*MockupInputPluginParserOnly) SampleConfig() string {\n\treturn \"Mockup test input plugin\"\n}\nfunc (*MockupInputPluginParserOnly) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupInputPluginParserOnly) SetParser(p telegraf.Parser) {\n\tm.parser = p\n}\n\n// Mockup PROCESSOR plugin for testing to avoid cyclic dependencies\ntype MockupProcessorPluginParser struct {\n\tParser     telegraf.Parser\n\tParserFunc telegraf.ParserFunc\n}\n\nfunc (*MockupProcessorPluginParser) Start(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParser) Stop() {\n}\nfunc (*MockupProcessorPluginParser) SampleConfig() string {\n\treturn \"Mockup test processor plugin with parser\"\n}\nfunc (*MockupProcessorPluginParser) Apply(...telegraf.Metric) []telegraf.Metric {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParser) Add(telegraf.Metric, telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupProcessorPluginParser) SetParser(parser telegraf.Parser) {\n\tm.Parser = parser\n}\nfunc (m *MockupProcessorPluginParser) SetParserFunc(f telegraf.ParserFunc) {\n\tm.ParserFunc = f\n}\n\n// Mockup PROCESSOR plugin without parser\ntype MockupProcessorPlugin struct {\n\tOption string `toml:\"option\"`\n\tstate  []uint64\n}\n\nfunc (*MockupProcessorPlugin) SampleConfig() string {\n\treturn \"Mockup test processor plugin with parser\"\n}\nfunc (*MockupProcessorPlugin) Apply(in ...telegraf.Metric) []telegraf.Metric {\n\tout := make([]telegraf.Metric, 0, len(in))\n\tfor _, m := range in {\n\t\tm.AddTag(\"processed\", \"yes\")\n\t\tout = append(out, m)\n\t}\n\treturn out\n}\nfunc (m *MockupProcessorPlugin) GetState() interface{} {\n\treturn m.state\n}\nfunc (m *MockupProcessorPlugin) SetState(state interface{}) error {\n\ts, ok := state.([]uint64)\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid state type %T\", state)\n\t}\n\tm.state = s\n\n\treturn nil\n}\n\n// Mockup PROCESSOR plugin with parser\ntype MockupProcessorPluginParserOnly struct {\n\tParser telegraf.Parser\n}\n\nfunc (*MockupProcessorPluginParserOnly) Start(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParserOnly) Stop() {\n}\nfunc (*MockupProcessorPluginParserOnly) SampleConfig() string {\n\treturn \"Mockup test processor plugin with parser\"\n}\nfunc (*MockupProcessorPluginParserOnly) Apply(...telegraf.Metric) []telegraf.Metric {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParserOnly) Add(telegraf.Metric, telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupProcessorPluginParserOnly) SetParser(parser telegraf.Parser) {\n\tm.Parser = parser\n}\n\n// Mockup PROCESSOR plugin with parser-function\ntype MockupProcessorPluginParserFunc struct {\n\tParser telegraf.ParserFunc\n}\n\nfunc (*MockupProcessorPluginParserFunc) Start(telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParserFunc) Stop() {\n}\nfunc (*MockupProcessorPluginParserFunc) SampleConfig() string {\n\treturn \"Mockup test processor plugin with parser\"\n}\nfunc (*MockupProcessorPluginParserFunc) Apply(...telegraf.Metric) []telegraf.Metric {\n\treturn nil\n}\nfunc (*MockupProcessorPluginParserFunc) Add(telegraf.Metric, telegraf.Accumulator) error {\n\treturn nil\n}\nfunc (m *MockupProcessorPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) {\n\tm.Parser = pf\n}\n\n// Mockup OUTPUT plugin for testing to avoid cyclic dependencies\ntype MockupOutputPlugin struct {\n\tURL             string            `toml:\"url\"`\n\tHeaders         map[string]string `toml:\"headers\"`\n\tScopes          []string          `toml:\"scopes\"`\n\tNamespacePrefix string            `toml:\"namespace_prefix\"`\n\tLog             telegraf.Logger   `toml:\"-\"`\n\ttls.ClientConfig\n}\n\nfunc (*MockupOutputPlugin) Connect() error {\n\treturn nil\n}\nfunc (*MockupOutputPlugin) Close() error {\n\treturn nil\n}\nfunc (*MockupOutputPlugin) SampleConfig() string {\n\treturn \"Mockup test output plugin\"\n}\nfunc (*MockupOutputPlugin) Write([]telegraf.Metric) error {\n\treturn nil\n}\n\ntype MockupOutputPluginSerializerNew struct {\n\tSerializer telegraf.Serializer\n}\n\nfunc (m *MockupOutputPluginSerializerNew) SetSerializer(s telegraf.Serializer) {\n\tm.Serializer = s\n}\nfunc (*MockupOutputPluginSerializerNew) Connect() error {\n\treturn nil\n}\nfunc (*MockupOutputPluginSerializerNew) Close() error {\n\treturn nil\n}\nfunc (*MockupOutputPluginSerializerNew) SampleConfig() string {\n\treturn \"Mockup test output plugin\"\n}\nfunc (*MockupOutputPluginSerializerNew) Write(_ []telegraf.Metric) error {\n\treturn nil\n}\n\n// Mockup INPUT plugin with state for testing to avoid cyclic dependencies\ntype MockupState struct {\n\tName     string\n\tVersion  uint64\n\tOffset   uint64\n\tBits     []int\n\tModified time.Time\n}\n\ntype MockupStatePluginSettings struct {\n\tName     string  `toml:\"name\"`\n\tFactor   float64 `toml:\"factor\"`\n\tEnabled  bool    `toml:\"enabled\"`\n\tBitField []int   `toml:\"bits\"`\n}\n\ntype MockupStatePlugin struct {\n\tServers  []string                    `toml:\"servers\"`\n\tMethod   string                      `toml:\"method\"`\n\tSettings map[string]string           `toml:\"params\"`\n\tPort     int                         `toml:\"port\"`\n\tSetups   []MockupStatePluginSettings `toml:\"setup\"`\n\tstate    MockupState\n}\n\nfunc (m *MockupStatePlugin) Init() error {\n\tt0, err := time.Parse(time.RFC3339, \"2021-04-24T23:42:00+02:00\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tm.state = MockupState{\n\t\tName:     \"mockup\",\n\t\tModified: t0,\n\t}\n\n\treturn nil\n}\n\nfunc (m *MockupStatePlugin) GetState() interface{} {\n\treturn m.state\n}\n\nfunc (m *MockupStatePlugin) SetState(state interface{}) error {\n\ts, ok := state.(MockupState)\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid state type %T\", state)\n\t}\n\tm.state = s\n\n\treturn nil\n}\n\nfunc (*MockupStatePlugin) SampleConfig() string {\n\treturn \"Mockup test plugin\"\n}\n\nfunc (*MockupStatePlugin) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\n// Register the mockup plugin on loading\nfunc init() {\n\t// Register the mockup input plugin for the required names\n\tinputs.Add(\"parser_test_new\", func() telegraf.Input {\n\t\treturn &MockupInputPluginParserNew{}\n\t})\n\tinputs.Add(\"parser\", func() telegraf.Input {\n\t\treturn &MockupInputPluginParserOnly{}\n\t})\n\tinputs.Add(\"parser_func\", func() telegraf.Input {\n\t\treturn &MockupInputPluginParserFunc{}\n\t})\n\tinputs.Add(\"exec\", func() telegraf.Input {\n\t\treturn &MockupInputPlugin{Timeout: config.Duration(time.Second * 5)}\n\t})\n\tinputs.Add(\"file\", func() telegraf.Input {\n\t\treturn &MockupInputPlugin{}\n\t})\n\tinputs.Add(\"http_listener_v2\", func() telegraf.Input {\n\t\treturn &MockupInputPlugin{}\n\t})\n\tinputs.Add(\"memcached\", func() telegraf.Input {\n\t\treturn &MockupInputPlugin{}\n\t})\n\tinputs.Add(\"procstat\", func() telegraf.Input {\n\t\treturn &MockupInputPlugin{}\n\t})\n\tinputs.Add(\"statetest\", func() telegraf.Input {\n\t\treturn &MockupStatePlugin{}\n\t})\n\n\t// Register the mockup processor plugin for the required names\n\tprocessors.Add(\"parser_test\", func() telegraf.Processor {\n\t\treturn &MockupProcessorPluginParser{}\n\t})\n\tprocessors.Add(\"processor\", func() telegraf.Processor {\n\t\treturn &MockupProcessorPlugin{}\n\t})\n\tprocessors.Add(\"processor_parser\", func() telegraf.Processor {\n\t\treturn &MockupProcessorPluginParserOnly{}\n\t})\n\tprocessors.Add(\"processor_parserfunc\", func() telegraf.Processor {\n\t\treturn &MockupProcessorPluginParserFunc{}\n\t})\n\tprocessors.Add(\"statetest\", func() telegraf.Processor {\n\t\treturn &MockupProcessorPlugin{}\n\t})\n\n\t// Register the mockup output plugin for the required names\n\toutputs.Add(\"azure_monitor\", func() telegraf.Output {\n\t\treturn &MockupOutputPlugin{NamespacePrefix: \"Telegraf/\"}\n\t})\n\toutputs.Add(\"http\", func() telegraf.Output {\n\t\treturn &MockupOutputPlugin{}\n\t})\n\toutputs.Add(\"serializer_test_new\", func() telegraf.Output {\n\t\treturn &MockupOutputPluginSerializerNew{}\n\t})\n}\n"
  },
  {
    "path": "config/deprecation.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/coreos/go-semver/semver\"\n\t\"github.com/fatih/color\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n)\n\n// DeprecationInfo contains all important information to describe a deprecated entity\ntype DeprecationInfo struct {\n\t// Name of the plugin or plugin option\n\tName string\n\t// LogLevel is the level of deprecation which currently corresponds to a log-level\n\tlogLevel telegraf.LogLevel\n\tinfo     telegraf.DeprecationInfo\n}\n\nfunc (di *DeprecationInfo) determineEscalation() error {\n\tdi.logLevel = telegraf.None\n\tif di.info.Since == \"\" {\n\t\treturn nil\n\t}\n\n\tsince, err := semver.NewVersion(di.info.Since)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot parse 'since' version %q: %w\", di.info.Since, err)\n\t}\n\n\tvar removal *semver.Version\n\tif di.info.RemovalIn != \"\" {\n\t\tremoval, err = semver.NewVersion(di.info.RemovalIn)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse 'removal' version %q: %w\", di.info.RemovalIn, err)\n\t\t}\n\t} else {\n\t\tremoval = &semver.Version{Major: since.Major}\n\t\tremoval.BumpMajor()\n\t\tdi.info.RemovalIn = removal.String()\n\t}\n\n\t// Drop potential pre-release tags\n\tversion := semver.Version{\n\t\tMajor: telegrafVersion.Major,\n\t\tMinor: telegrafVersion.Minor,\n\t\tPatch: telegrafVersion.Patch,\n\t}\n\tif !version.LessThan(*removal) {\n\t\tdi.logLevel = telegraf.Error\n\t} else if !version.LessThan(*since) {\n\t\tdi.logLevel = telegraf.Warn\n\t}\n\treturn nil\n}\n\n// PluginDeprecationInfo holds all information about a deprecated plugin or it's options\ntype PluginDeprecationInfo struct {\n\tDeprecationInfo\n\n\t// Options deprecated for this plugin\n\tOptions []DeprecationInfo\n}\n\nfunc (c *Config) incrementPluginDeprecations(category string) {\n\tnewcounts := []int64{1, 0}\n\tif counts, found := c.Deprecations[category]; found {\n\t\tnewcounts = []int64{counts[0] + 1, counts[1]}\n\t}\n\tc.Deprecations[category] = newcounts\n}\n\nfunc (c *Config) incrementPluginOptionDeprecations(category string) {\n\tnewcounts := []int64{0, 1}\n\tif counts, found := c.Deprecations[category]; found {\n\t\tnewcounts = []int64{counts[0], counts[1] + 1}\n\t}\n\tc.Deprecations[category] = newcounts\n}\n\nfunc (c *Config) collectDeprecationInfo(category, name string, plugin interface{}, all bool) PluginDeprecationInfo {\n\tinfo := PluginDeprecationInfo{\n\t\tDeprecationInfo: DeprecationInfo{\n\t\t\tName:     category + \".\" + name,\n\t\t\tlogLevel: telegraf.None,\n\t\t},\n\t}\n\n\t// First check if the whole plugin is deprecated\n\tswitch category {\n\tcase \"aggregators\":\n\t\tif pi, deprecated := aggregators.Deprecations[name]; deprecated {\n\t\t\tinfo.DeprecationInfo.info = pi\n\t\t}\n\tcase \"inputs\":\n\t\tif pi, deprecated := inputs.Deprecations[name]; deprecated {\n\t\t\tinfo.DeprecationInfo.info = pi\n\t\t}\n\tcase \"outputs\":\n\t\tif pi, deprecated := outputs.Deprecations[name]; deprecated {\n\t\t\tinfo.DeprecationInfo.info = pi\n\t\t}\n\tcase \"processors\":\n\t\tif pi, deprecated := processors.Deprecations[name]; deprecated {\n\t\t\tinfo.DeprecationInfo.info = pi\n\t\t}\n\t}\n\tif err := info.determineEscalation(); err != nil {\n\t\tpanic(fmt.Errorf(\"plugin %q: %w\", info.Name, err))\n\t}\n\tif info.logLevel != telegraf.None {\n\t\tc.incrementPluginDeprecations(category)\n\t}\n\n\t// Allow checking for names only.\n\tif plugin == nil {\n\t\treturn info\n\t}\n\n\t// Check for deprecated options\n\twalkPluginStruct(reflect.ValueOf(plugin), func(field reflect.StructField, value reflect.Value) {\n\t\t// Try to report only those fields that are set\n\t\tif !all && value.IsZero() {\n\t\t\treturn\n\t\t}\n\n\t\ttags := strings.SplitN(field.Tag.Get(\"deprecated\"), \";\", 3)\n\t\tif len(tags) < 1 || tags[0] == \"\" {\n\t\t\treturn\n\t\t}\n\t\toptionInfo := DeprecationInfo{Name: field.Name}\n\t\toptionInfo.info.Since = tags[0]\n\n\t\tif len(tags) > 1 {\n\t\t\toptionInfo.info.Notice = tags[len(tags)-1]\n\t\t}\n\t\tif len(tags) > 2 {\n\t\t\toptionInfo.info.RemovalIn = tags[1]\n\t\t}\n\t\tif err := optionInfo.determineEscalation(); err != nil {\n\t\t\tpanic(fmt.Errorf(\"plugin %q option %q: %w\", info.Name, field.Name, err))\n\t\t}\n\n\t\tif optionInfo.logLevel != telegraf.None {\n\t\t\tc.incrementPluginOptionDeprecations(category)\n\t\t}\n\n\t\t// Get the toml field name\n\t\toption := field.Tag.Get(\"toml\")\n\t\tif option != \"\" {\n\t\t\toptionInfo.Name = option\n\t\t}\n\t\tinfo.Options = append(info.Options, optionInfo)\n\t})\n\n\treturn info\n}\n\nfunc (c *Config) printUserDeprecation(category, name string, plugin interface{}) error {\n\tinfo := c.collectDeprecationInfo(category, name, plugin, false)\n\tprintPluginDeprecationNotice(info.logLevel, info.Name, info.info)\n\n\tif info.logLevel == telegraf.Error {\n\t\treturn errors.New(\"plugin deprecated\")\n\t}\n\n\t// Print deprecated options\n\tdeprecatedOptions := make([]string, 0)\n\tfor _, option := range info.Options {\n\t\tPrintOptionDeprecationNotice(info.Name, option.Name, option.info)\n\t\tif option.logLevel == telegraf.Error {\n\t\t\tdeprecatedOptions = append(deprecatedOptions, option.Name)\n\t\t}\n\t}\n\n\tif len(deprecatedOptions) > 0 {\n\t\treturn fmt.Errorf(\"plugin options %q deprecated\", strings.Join(deprecatedOptions, \",\"))\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) CollectDeprecationInfos(inFilter, outFilter, aggFilter, procFilter []string) map[string][]PluginDeprecationInfo {\n\tinfos := make(map[string][]PluginDeprecationInfo)\n\n\tinfos[\"inputs\"] = make([]PluginDeprecationInfo, 0)\n\tfor name, creator := range inputs.Inputs {\n\t\tif len(inFilter) > 0 && !sliceContains(name, inFilter) {\n\t\t\tcontinue\n\t\t}\n\n\t\tplugin := creator()\n\t\tinfo := c.collectDeprecationInfo(\"inputs\", name, plugin, true)\n\n\t\tif info.logLevel != telegraf.None || len(info.Options) > 0 {\n\t\t\tinfos[\"inputs\"] = append(infos[\"inputs\"], info)\n\t\t}\n\t}\n\n\tinfos[\"outputs\"] = make([]PluginDeprecationInfo, 0)\n\tfor name, creator := range outputs.Outputs {\n\t\tif len(outFilter) > 0 && !sliceContains(name, outFilter) {\n\t\t\tcontinue\n\t\t}\n\n\t\tplugin := creator()\n\t\tinfo := c.collectDeprecationInfo(\"outputs\", name, plugin, true)\n\n\t\tif info.logLevel != telegraf.None || len(info.Options) > 0 {\n\t\t\tinfos[\"outputs\"] = append(infos[\"outputs\"], info)\n\t\t}\n\t}\n\n\tinfos[\"processors\"] = make([]PluginDeprecationInfo, 0)\n\tfor name, creator := range processors.Processors {\n\t\tif len(procFilter) > 0 && !sliceContains(name, procFilter) {\n\t\t\tcontinue\n\t\t}\n\n\t\tplugin := creator()\n\t\tinfo := c.collectDeprecationInfo(\"processors\", name, plugin, true)\n\n\t\tif info.logLevel != telegraf.None || len(info.Options) > 0 {\n\t\t\tinfos[\"processors\"] = append(infos[\"processors\"], info)\n\t\t}\n\t}\n\n\tinfos[\"aggregators\"] = make([]PluginDeprecationInfo, 0)\n\tfor name, creator := range aggregators.Aggregators {\n\t\tif len(aggFilter) > 0 && !sliceContains(name, aggFilter) {\n\t\t\tcontinue\n\t\t}\n\n\t\tplugin := creator()\n\t\tinfo := c.collectDeprecationInfo(\"aggregators\", name, plugin, true)\n\n\t\tif info.logLevel != telegraf.None || len(info.Options) > 0 {\n\t\t\tinfos[\"aggregators\"] = append(infos[\"aggregators\"], info)\n\t\t}\n\t}\n\n\treturn infos\n}\n\nfunc (*Config) PrintDeprecationList(plugins []PluginDeprecationInfo) {\n\tsort.Slice(plugins, func(i, j int) bool { return plugins[i].Name < plugins[j].Name })\n\n\tfor _, plugin := range plugins {\n\t\tswitch plugin.logLevel {\n\t\tcase telegraf.Warn, telegraf.Error:\n\t\t\tfmt.Printf(\n\t\t\t\t\"  %-40s %-5s since %-5s removal in %-5s %s\\n\",\n\t\t\t\tplugin.Name, plugin.logLevel, plugin.info.Since, plugin.info.RemovalIn, plugin.info.Notice,\n\t\t\t)\n\t\t}\n\n\t\tif len(plugin.Options) < 1 {\n\t\t\tcontinue\n\t\t}\n\t\tsort.Slice(plugin.Options, func(i, j int) bool { return plugin.Options[i].Name < plugin.Options[j].Name })\n\t\tfor _, option := range plugin.Options {\n\t\t\tfmt.Printf(\n\t\t\t\t\"  %-40s %-5s since %-5s removal in %-5s %s\\n\",\n\t\t\t\tplugin.Name+\"/\"+option.Name, option.logLevel, option.info.Since, option.info.RemovalIn, option.info.Notice,\n\t\t\t)\n\t\t}\n\t}\n}\n\nfunc printHistoricPluginDeprecationNotice(category, name string, info telegraf.DeprecationInfo) {\n\tprefix := \"E! \" + color.RedString(\"DeprecationError\")\n\tlog.Printf(\n\t\t\"%s: Plugin %q deprecated since version %s and removed: %s\",\n\t\tprefix, category+\".\"+name, info.Since, info.Notice,\n\t)\n}\n\n// walkPluginStruct iterates over the fields of a structure in depth-first search (to cover nested structures)\n// and calls the given function for every visited field.\nfunc walkPluginStruct(value reflect.Value, fn func(f reflect.StructField, fv reflect.Value)) {\n\tv := reflect.Indirect(value)\n\tt := v.Type()\n\n\t// Only works on structs\n\tif t.Kind() != reflect.Struct {\n\t\treturn\n\t}\n\n\t// Walk over the struct fields and call the given function. If we encounter more complex embedded\n\t// elements (structs, slices/arrays, maps) we need to descend into those elements as they might\n\t// contain structures nested in the current structure.\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tfield := t.Field(i)\n\t\tfieldValue := v.Field(i)\n\n\t\tif field.PkgPath != \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tswitch field.Type.Kind() {\n\t\tcase reflect.Struct:\n\t\t\twalkPluginStruct(fieldValue, fn)\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\tfor j := 0; j < fieldValue.Len(); j++ {\n\t\t\t\telement := fieldValue.Index(j)\n\t\t\t\t// The array might contain structs\n\t\t\t\twalkPluginStruct(element, fn)\n\t\t\t\tfn(field, element)\n\t\t\t}\n\t\tcase reflect.Map:\n\t\t\titer := fieldValue.MapRange()\n\t\t\tfor iter.Next() {\n\t\t\t\telement := iter.Value()\n\t\t\t\t// The map might contain structs\n\t\t\t\twalkPluginStruct(element, fn)\n\t\t\t\tfn(field, element)\n\t\t\t}\n\t\t}\n\t\tfn(field, fieldValue)\n\t}\n}\n\nfunc deprecationPrefix(level telegraf.LogLevel) string {\n\tswitch level {\n\tcase telegraf.Warn:\n\t\treturn \"W! \" + color.YellowString(\"DeprecationWarning\")\n\tcase telegraf.Error:\n\t\treturn \"E! \" + color.RedString(\"DeprecationError\")\n\t}\n\treturn \"\"\n}\n\nfunc printPluginDeprecationNotice(level telegraf.LogLevel, name string, info telegraf.DeprecationInfo) {\n\tswitch level {\n\tcase telegraf.Warn, telegraf.Error:\n\t\tprefix := deprecationPrefix(level)\n\t\tlog.Printf(\n\t\t\t\"%s: Plugin %q deprecated since version %s and will be removed in %s: %s\",\n\t\t\tprefix, name, info.Since, info.RemovalIn, info.Notice,\n\t\t)\n\t}\n}\n\nfunc PrintOptionDeprecationNotice(plugin, option string, info telegraf.DeprecationInfo) {\n\t// Determine the log-level\n\tdi := &DeprecationInfo{\n\t\tName: plugin,\n\t\tinfo: info,\n\t}\n\tif err := di.determineEscalation(); err != nil {\n\t\tlog.Printf(\"E! Determining log-level for option %s in plugin %s failed: %v\", option, plugin, err)\n\t\treturn\n\t}\n\n\tswitch di.logLevel {\n\tcase telegraf.Warn, telegraf.Error:\n\t\tprefix := deprecationPrefix(di.logLevel)\n\t\tlog.Printf(\n\t\t\t\"%s: Option %q of plugin %q deprecated since version %s and will be removed in %s: %s\",\n\t\t\tprefix, option, plugin, di.info.Since, di.info.RemovalIn, di.info.Notice,\n\t\t)\n\t}\n}\n\nfunc PrintOptionValueDeprecationNotice(plugin, option string, value interface{}, info telegraf.DeprecationInfo) {\n\t// Determine the log-level\n\tdi := &DeprecationInfo{\n\t\tName: plugin,\n\t\tinfo: info,\n\t}\n\tif err := di.determineEscalation(); err != nil {\n\t\tlog.Printf(\"E! Determining log-level for option %s in plugin %s failed: %v\", option, plugin, err)\n\t\treturn\n\t}\n\n\tswitch di.logLevel {\n\tcase telegraf.Warn, telegraf.Error:\n\t\tprefix := deprecationPrefix(di.logLevel)\n\t\tlog.Printf(\n\t\t\t`%s: Value \"%+v\" for option %q of plugin %q deprecated since version %s and will be removed in %s: %s`,\n\t\t\tprefix, value, option, plugin, di.info.Since, di.info.RemovalIn, di.info.Notice,\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "config/deprecation_test.go",
    "content": "package config\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/coreos/go-semver/semver\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc TestPluginDeprecation(t *testing.T) {\n\tinfo := telegraf.DeprecationInfo{\n\t\tSince:     \"1.23.0\",\n\t\tRemovalIn: \"2.0.0\",\n\t\tNotice:    \"please check\",\n\t}\n\tvar tests = []struct {\n\t\tname     string\n\t\tlevel    telegraf.LogLevel\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"Error level\",\n\t\t\tlevel:    telegraf.Error,\n\t\t\texpected: `Plugin \"test\" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`,\n\t\t},\n\t\t{\n\t\t\tname:     \"Warn level\",\n\t\t\tlevel:    telegraf.Warn,\n\t\t\texpected: `Plugin \"test\" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`,\n\t\t},\n\t\t{\n\t\t\tname:     \"None\",\n\t\t\tlevel:    telegraf.None,\n\t\t\texpected: ``,\n\t\t},\n\t}\n\n\t// Switch the logger to log to a buffer\n\tvar buf bytes.Buffer\n\tscanner := bufio.NewScanner(&buf)\n\n\tprevious := log.Writer()\n\tlog.SetOutput(&buf)\n\tdefer log.SetOutput(previous)\n\n\tmsg := make(chan string, 1)\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbuf.Reset()\n\t\t\tprintPluginDeprecationNotice(tt.level, \"test\", info)\n\n\t\t\t// Wait for a newline to arrive and timeout for cases where\n\t\t\t// we don't see a message.\n\t\t\tgo func() {\n\t\t\t\tscanner.Scan()\n\t\t\t\tmsg <- scanner.Text()\n\t\t\t}()\n\n\t\t\t// Reduce the timeout if we do not expect a message\n\t\t\ttimeout := 1 * time.Second\n\t\t\tif tt.expected == \"\" {\n\t\t\t\ttimeout = 100 * time.Microsecond\n\t\t\t}\n\n\t\t\tvar actual string\n\t\t\tselect {\n\t\t\tcase actual = <-msg:\n\t\t\tcase <-time.After(timeout):\n\t\t\t}\n\n\t\t\tif tt.expected != \"\" {\n\t\t\t\texpected := deprecationPrefix(tt.level) + \": \" + tt.expected\n\t\t\t\trequire.Equal(t, expected, actual)\n\t\t\t} else {\n\t\t\t\trequire.Empty(t, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPluginOptionDeprecation(t *testing.T) {\n\tvar tests = []struct {\n\t\tname          string\n\t\tsince         string\n\t\tremoval       string\n\t\texpected      string\n\t\texpectedLevel telegraf.LogLevel\n\t}{\n\t\t{\n\t\t\tname:          \"Error level\",\n\t\t\tsince:         \"1.23.0\",\n\t\t\tremoval:       \"1.29.0\",\n\t\t\texpectedLevel: telegraf.Error,\n\t\t\texpected:      `Option \"option\" of plugin \"test\" deprecated since version 1.23.0 and will be removed in 1.29.0: please check`,\n\t\t},\n\t\t{\n\t\t\tname:          \"Warn level\",\n\t\t\tsince:         \"1.23.0\",\n\t\t\tremoval:       \"2.0.0\",\n\t\t\texpectedLevel: telegraf.Warn,\n\t\t\texpected:      `Option \"option\" of plugin \"test\" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`,\n\t\t},\n\t\t{\n\t\t\tname:          \"No removal info\",\n\t\t\tsince:         \"1.23.0\",\n\t\t\texpectedLevel: telegraf.Warn,\n\t\t\texpected:      `Option \"option\" of plugin \"test\" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`,\n\t\t},\n\t\t{\n\t\t\tname:          \"None\",\n\t\t\texpectedLevel: telegraf.None,\n\t\t\texpected:      ``,\n\t\t},\n\t}\n\n\t// Fake telegraf's version\n\tversion, err := semver.NewVersion(\"1.30.0\")\n\trequire.NoError(t, err)\n\ttelegrafVersion = version\n\n\t// Switch the logger to log to a buffer\n\tvar buf bytes.Buffer\n\tscanner := bufio.NewScanner(&buf)\n\n\tprevious := log.Writer()\n\tlog.SetOutput(&buf)\n\tdefer log.SetOutput(previous)\n\n\tmsg := make(chan string, 1)\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbuf.Reset()\n\t\t\tinfo := telegraf.DeprecationInfo{\n\t\t\t\tSince:     tt.since,\n\t\t\t\tRemovalIn: tt.removal,\n\t\t\t\tNotice:    \"please check\",\n\t\t\t}\n\t\t\tPrintOptionDeprecationNotice(\"test\", \"option\", info)\n\t\t\t// Wait for a newline to arrive and timeout for cases where\n\t\t\t// we don't see a message.\n\t\t\tgo func() {\n\t\t\t\tscanner.Scan()\n\t\t\t\tmsg <- scanner.Text()\n\t\t\t}()\n\n\t\t\t// Reduce the timeout if we do not expect a message\n\t\t\ttimeout := 1 * time.Second\n\t\t\tif tt.expected == \"\" {\n\t\t\t\ttimeout = 100 * time.Microsecond\n\t\t\t}\n\n\t\t\tvar actual string\n\t\t\tselect {\n\t\t\tcase actual = <-msg:\n\t\t\tcase <-time.After(timeout):\n\t\t\t}\n\n\t\t\tif tt.expected != \"\" {\n\t\t\t\texpected := deprecationPrefix(tt.expectedLevel) + \": \" + tt.expected\n\t\t\t\trequire.Equal(t, expected, actual)\n\t\t\t} else {\n\t\t\t\trequire.Empty(t, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPluginOptionValueDeprecation(t *testing.T) {\n\tvar tests = []struct {\n\t\tname          string\n\t\tsince         string\n\t\tremoval       string\n\t\tvalue         interface{}\n\t\texpected      string\n\t\texpectedLevel telegraf.LogLevel\n\t}{\n\t\t{\n\t\t\tname:          \"Error level\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tremoval:       \"1.29.0\",\n\t\t\tvalue:         \"foobar\",\n\t\t\texpected:      `Value \"foobar\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`,\n\t\t\texpectedLevel: telegraf.Error,\n\t\t},\n\t\t{\n\t\t\tname:          \"Warn level\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tremoval:       \"2.0.0\",\n\t\t\tvalue:         \"foobar\",\n\t\t\texpected:      `Value \"foobar\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 2.0.0: please check`,\n\t\t\texpectedLevel: telegraf.Warn,\n\t\t},\n\t\t{\n\t\t\tname:          \"No removal info\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tvalue:         \"foobar\",\n\t\t\texpected:      `Value \"foobar\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 2.0.0: please check`,\n\t\t\texpectedLevel: telegraf.Warn,\n\t\t},\n\t\t{\n\t\t\tname:          \"None\",\n\t\t\texpected:      ``,\n\t\t\texpectedLevel: telegraf.None,\n\t\t},\n\t\t{\n\t\t\tname:          \"nil value\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tremoval:       \"1.29.0\",\n\t\t\tvalue:         nil,\n\t\t\texpected:      `Value \"<nil>\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`,\n\t\t\texpectedLevel: telegraf.Error,\n\t\t},\n\t\t{\n\t\t\tname:          \"Boolean value\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tremoval:       \"1.29.0\",\n\t\t\tvalue:         true,\n\t\t\texpected:      `Value \"true\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`,\n\t\t\texpectedLevel: telegraf.Error,\n\t\t},\n\t\t{\n\t\t\tname:          \"Integer value\",\n\t\t\tsince:         \"1.25.0\",\n\t\t\tremoval:       \"1.29.0\",\n\t\t\tvalue:         123,\n\t\t\texpected:      `Value \"123\" for option \"option\" of plugin \"test\" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`,\n\t\t\texpectedLevel: telegraf.Error,\n\t\t},\n\t}\n\n\t// Fake telegraf's version\n\tversion, err := semver.NewVersion(\"1.30.0\")\n\trequire.NoError(t, err)\n\ttelegrafVersion = version\n\n\t// Switch the logger to log to a buffer\n\tvar buf bytes.Buffer\n\tprevious := log.Writer()\n\tlog.SetOutput(&buf)\n\tdefer log.SetOutput(previous)\n\n\ttimeout := 1 * time.Second\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbuf.Reset()\n\n\t\t\tinfo := telegraf.DeprecationInfo{\n\t\t\t\tSince:     tt.since,\n\t\t\t\tRemovalIn: tt.removal,\n\t\t\t\tNotice:    \"please check\",\n\t\t\t}\n\t\t\tPrintOptionValueDeprecationNotice(\"test\", \"option\", tt.value, info)\n\n\t\t\tif tt.expected != \"\" {\n\t\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\t\treturn strings.HasSuffix(buf.String(), \"\\n\")\n\t\t\t\t}, timeout, 100*time.Millisecond)\n\n\t\t\t\t// Remove the time for comparison\n\t\t\t\tactual := strings.TrimSpace(buf.String())\n\t\t\t\texpected := deprecationPrefix(tt.expectedLevel) + \": \" + tt.expected\n\t\t\t\trequire.Equal(t, expected, actual)\n\t\t\t} else {\n\t\t\t\ttime.Sleep(timeout)\n\t\t\t\trequire.Empty(t, buf.String())\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "config/envvar.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/compose-spec/compose-go/template\"\n\t\"github.com/compose-spec/compose-go/utils\"\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n)\n\ntype trimmer struct {\n\tinput  *bytes.Reader\n\toutput bytes.Buffer\n}\n\nfunc removeComments(buf []byte) ([]byte, error) {\n\tt := &trimmer{\n\t\tinput:  bytes.NewReader(buf),\n\t\toutput: bytes.Buffer{},\n\t}\n\terr := t.process()\n\treturn t.output.Bytes(), err\n}\n\nfunc (t *trimmer) process() error {\n\tfor {\n\t\t// Read the next byte until EOF\n\t\tc, err := t.input.ReadByte()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\n\t\t// Switch states if we need to\n\t\tswitch c {\n\t\tcase '\\\\':\n\t\t\t//nolint:errcheck // next byte is known\n\t\t\tt.input.UnreadByte()\n\t\t\terr = t.escape()\n\t\tcase '\\'':\n\t\t\t//nolint:errcheck // next byte is known\n\t\t\tt.input.UnreadByte()\n\t\t\tif t.hasNQuotes(c, 3) {\n\t\t\t\terr = t.tripleSingleQuote()\n\t\t\t} else {\n\t\t\t\terr = t.singleQuote()\n\t\t\t}\n\t\tcase '\"':\n\t\t\t//nolint:errcheck // next byte is known\n\t\t\tt.input.UnreadByte()\n\t\t\tif t.hasNQuotes(c, 3) {\n\t\t\t\terr = t.tripleDoubleQuote()\n\t\t\t} else {\n\t\t\t\terr = t.doubleQuote()\n\t\t\t}\n\t\tcase '#':\n\t\t\terr = t.comment()\n\t\tdefault:\n\t\t\tt.output.WriteByte(c)\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (t *trimmer) hasNQuotes(ref byte, limit int64) bool {\n\tvar count int64\n\t// Look ahead check if the next characters are what we expect\n\tfor count = 0; count < limit; count++ {\n\t\tc, err := t.input.ReadByte()\n\t\tif err != nil || c != ref {\n\t\t\tbreak\n\t\t}\n\t}\n\t// We also need to unread the non-matching character\n\toffset := -count\n\tif count < limit {\n\t\toffset--\n\t}\n\t//nolint:errcheck // Unread the already matched characters\n\tt.input.Seek(offset, io.SeekCurrent)\n\treturn count >= limit\n}\n\nfunc (t *trimmer) readWriteByte() (byte, error) {\n\tc, err := t.input.ReadByte()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn c, t.output.WriteByte(c)\n}\n\nfunc (t *trimmer) escape() error {\n\t//nolint:errcheck // Consume the known starting backslash and quote\n\tt.readWriteByte()\n\n\t// Read the next character which is the escaped one and exit\n\t_, err := t.readWriteByte()\n\treturn err\n}\n\nfunc (t *trimmer) singleQuote() error {\n\t//nolint:errcheck // Consume the known starting quote\n\tt.readWriteByte()\n\n\t// Read bytes until EOF, line end or another single quote\n\tfor {\n\t\tif c, err := t.readWriteByte(); err != nil || c == '\\'' || c == '\\n' {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (t *trimmer) tripleSingleQuote() error {\n\tfor i := 0; i < 3; i++ {\n\t\t//nolint:errcheck // Consume the known starting quotes\n\t\tt.readWriteByte()\n\t}\n\n\t// Read bytes until EOF or another set of triple single quotes\n\tfor {\n\t\tc, err := t.readWriteByte()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif c == '\\'' && t.hasNQuotes('\\'', 2) {\n\t\t\t//nolint:errcheck // Consume the two additional ending quotes\n\t\t\tt.readWriteByte()\n\t\t\t//nolint:errcheck // Consume the two additional ending quotes\n\t\t\tt.readWriteByte()\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (t *trimmer) doubleQuote() error {\n\t//nolint:errcheck // Consume the known starting quote\n\tt.readWriteByte()\n\n\t// Read bytes until EOF, line end or another double quote\n\tfor {\n\t\tc, err := t.input.ReadByte()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch c {\n\t\tcase '\\\\':\n\t\t\t//nolint:errcheck // Consume the found escaped character\n\t\t\tt.input.UnreadByte()\n\t\t\tif err := t.escape(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\tcase '\"', '\\n':\n\t\t\t// Found terminator\n\t\t\treturn t.output.WriteByte(c)\n\t\t}\n\t\tt.output.WriteByte(c)\n\t}\n}\n\nfunc (t *trimmer) tripleDoubleQuote() error {\n\tfor i := 0; i < 3; i++ {\n\t\t//nolint:errcheck // Consume the known starting quotes\n\t\tt.readWriteByte()\n\t}\n\n\t// Read bytes until EOF or another set of triple double quotes\n\tfor {\n\t\tc, err := t.input.ReadByte()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch c {\n\t\tcase '\\\\':\n\t\t\t//nolint:errcheck // Consume the found escape character\n\t\t\tt.input.UnreadByte()\n\t\t\tif err := t.escape(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\tcase '\"':\n\t\t\tt.output.WriteByte(c)\n\t\t\tif t.hasNQuotes('\"', 2) {\n\t\t\t\t//nolint:errcheck // Consume the two additional ending quotes\n\t\t\t\tt.readWriteByte()\n\t\t\t\t//nolint:errcheck // Consume the two additional ending quotes\n\t\t\t\tt.readWriteByte()\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tt.output.WriteByte(c)\n\t}\n}\n\nfunc (t *trimmer) comment() error {\n\t// Read bytes until EOF or a line break\n\tfor {\n\t\tc, err := t.input.ReadByte()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif c == '\\n' {\n\t\t\treturn t.output.WriteByte(c)\n\t\t}\n\t}\n}\n\nfunc substituteEnvironmentStrict(contents []byte, oldReplacementBehavior bool) (*ast.Table, error) {\n\t// Parse the tree\n\ttree, err := toml.Parse(contents)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Prepare the environment-variable replacer\n\toptions := []template.Option{\n\t\ttemplate.WithReplacementFunction(func(s string, m template.Mapping, cfg *template.Config) (string, error) {\n\t\t\tresult, applied, err := template.DefaultReplacementAppliedFunc(s, m, cfg)\n\t\t\tif err == nil && !applied {\n\t\t\t\t// Keep undeclared environment-variable patterns to reproduce\n\t\t\t\t// pre-v1.27 behavior\n\t\t\t\treturn s, nil\n\t\t\t}\n\t\t\tif err != nil && strings.HasPrefix(err.Error(), \"Invalid template:\") {\n\t\t\t\t// Keep invalid template patterns to ignore regexp substitutions\n\t\t\t\t// like ${1}\n\t\t\t\treturn s, nil\n\t\t\t}\n\t\t\treturn result, err\n\t\t}),\n\t\ttemplate.WithoutLogging,\n\t}\n\tif oldReplacementBehavior {\n\t\toptions = append(options, template.WithPattern(oldVarRe))\n\t}\n\n\tenvMap := utils.GetAsEqualsMap(os.Environ())\n\n\t// Walk the AST and find string items to replace\n\tif err := walk(tree, func(n interface{}) error {\n\t\tv, ok := n.(*ast.String)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\treplacement, err := template.SubstituteWithOptions(v.Value, func(k string) (string, bool) {\n\t\t\tif v, ok := envMap[k]; ok {\n\t\t\t\treturn v, ok\n\t\t\t}\n\t\t\treturn \"\", false\n\t\t}, options...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tv.Value = replacement\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tree, nil\n}\n\nfunc walk(node interface{}, f func(interface{}) error) error {\n\tswitch n := node.(type) {\n\tcase *ast.Table:\n\t\tfor k, v := range n.Fields {\n\t\t\tif err := walk(v, f); err != nil {\n\t\t\t\treturn fmt.Errorf(\"processing field %q with value %v failed: %w\", k, v, err)\n\t\t\t}\n\t\t}\n\tcase []*ast.Table:\n\t\tfor _, v := range n {\n\t\t\tif err := walk(v, f); err != nil {\n\t\t\t\treturn fmt.Errorf(\"processing table %q failed: %w\", v.Name, err)\n\t\t\t}\n\t\t}\n\tcase *ast.Array:\n\t\tfor i, v := range n.Value {\n\t\t\tif err := walk(v, f); err != nil {\n\t\t\t\treturn fmt.Errorf(\"processing element %d with value %v failed: %w\", i+1, v, err)\n\t\t\t}\n\t\t}\n\tcase *ast.KeyValue:\n\t\tif err := walk(n.Value, f); err != nil {\n\t\t\treturn fmt.Errorf(\"processing value %v for key %q failed: %w\", n.Value, n.Key, err)\n\t\t}\n\t}\n\treturn f(node)\n}\n\nfunc substituteEnvironmentNonStrict(contents []byte, oldReplacementBehavior bool) ([]byte, error) {\n\toptions := []template.Option{\n\t\ttemplate.WithReplacementFunction(func(s string, m template.Mapping, cfg *template.Config) (string, error) {\n\t\t\tresult, applied, err := template.DefaultReplacementAppliedFunc(s, m, cfg)\n\t\t\tif err == nil && !applied {\n\t\t\t\t// Keep undeclared environment-variable patterns to reproduce\n\t\t\t\t// pre-v1.27 behavior\n\t\t\t\treturn s, nil\n\t\t\t}\n\t\t\tif err != nil && strings.HasPrefix(err.Error(), \"Invalid template:\") {\n\t\t\t\t// Keep invalid template patterns to ignore regexp substitutions\n\t\t\t\t// like ${1}\n\t\t\t\treturn s, nil\n\t\t\t}\n\t\t\treturn result, err\n\t\t}),\n\t\ttemplate.WithoutLogging,\n\t}\n\tif oldReplacementBehavior {\n\t\toptions = append(options, template.WithPattern(oldVarRe))\n\t}\n\n\tenvMap := utils.GetAsEqualsMap(os.Environ())\n\tretVal, err := template.SubstituteWithOptions(string(contents), func(k string) (string, bool) {\n\t\tif v, ok := envMap[k]; ok {\n\t\t\treturn v, ok\n\t\t}\n\t\treturn \"\", false\n\t}, options...)\n\treturn []byte(retVal), err\n}\n"
  },
  {
    "path": "config/internal_test.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEnvironmentSubstitution(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tsetEnv       func(*testing.T)\n\t\tcontents     string\n\t\texpected     string\n\t\twantErr      bool\n\t\terrSubstring string\n\t}{\n\t\t{\n\t\t\tname: \"Legacy with ${} and without {}\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"TEST_ENV1\", \"VALUE1\")\n\t\t\t\tt.Setenv(\"TEST_ENV2\", \"VALUE2\")\n\t\t\t},\n\t\t\tcontents: \"A string with ${TEST_ENV1}, $TEST_ENV2 and $TEST_ENV1 as repeated\",\n\t\t\texpected: \"A string with VALUE1, VALUE2 and VALUE1 as repeated\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Env not set\",\n\t\t\tcontents: \"Env variable ${NOT_SET} will be empty\",\n\t\t\texpected: \"Env variable ${NOT_SET} will be empty\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Env not set, fallback to default\",\n\t\t\tcontents: \"Env variable ${THIS_IS_ABSENT:-Fallback}\",\n\t\t\texpected: \"Env variable Fallback\",\n\t\t},\n\t\t{\n\t\t\tname: \"No fallback\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"MY_ENV1\", \"VALUE1\")\n\t\t\t},\n\t\t\tcontents: \"Env variable ${MY_ENV1:-Fallback}\",\n\t\t\texpected: \"Env variable VALUE1\",\n\t\t},\n\t\t{\n\t\t\tname: \"Mix and match\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"MY_VAR\", \"VALUE\")\n\t\t\t\tt.Setenv(\"MY_VAR2\", \"VALUE2\")\n\t\t\t},\n\t\t\tcontents: \"Env var ${MY_VAR} is set, with $MY_VAR syntax and default on this ${MY_VAR1:-Substituted}, no default on this ${MY_VAR2:-NoDefault}\",\n\t\t\texpected: \"Env var VALUE is set, with VALUE syntax and default on this Substituted, no default on this VALUE2\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty but set\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"EMPTY\", \"\")\n\t\t\t},\n\t\t\tcontents: \"Contains ${EMPTY} nothing\",\n\t\t\texpected: \"Contains  nothing\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Default has special chars\",\n\t\t\tcontents: `Not recommended but supported ${MY_VAR:-Default with special chars Supported#$\\\"}`,\n\t\t\texpected: `Not recommended but supported Default with special chars Supported#$\\\"`, // values are escaped\n\t\t},\n\t\t{\n\t\t\tname:         \"unset error\",\n\t\t\tcontents:     \"Contains ${THIS_IS_NOT_SET?unset-error}\",\n\t\t\twantErr:      true,\n\t\t\terrSubstring: \"unset-error\",\n\t\t},\n\t\t{\n\t\t\tname: \"env empty error\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"ENV_EMPTY\", \"\")\n\t\t\t},\n\t\t\tcontents:     \"Contains ${ENV_EMPTY:?empty-error}\",\n\t\t\twantErr:      true,\n\t\t\terrSubstring: \"empty-error\",\n\t\t},\n\t\t{\n\t\t\tname: \"Fallback as env variable\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"FALLBACK\", \"my-fallback\")\n\t\t\t},\n\t\t\tcontents: \"Should output ${NOT_SET:-${FALLBACK}}\",\n\t\t\texpected: \"Should output my-fallback\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.setEnv != nil {\n\t\t\t\ttt.setEnv(t)\n\t\t\t}\n\t\t\tactual, err := substituteEnvironmentNonStrict([]byte(tt.contents), false)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.ErrorContains(t, err, tt.errSubstring)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.EqualValues(t, tt.expected, string(actual))\n\t\t})\n\t}\n}\n\nfunc TestEnvironmentSubstitutionOldBehavior(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcontents string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"not defined no brackets\",\n\t\t\tcontents: `my-da$tabase`,\n\t\t\texpected: `my-da$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined brackets\",\n\t\t\tcontents: `my-da${ta}base`,\n\t\t\texpected: `my-da${ta}base`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined no brackets double dollar\",\n\t\t\tcontents: `my-da$$tabase`,\n\t\t\texpected: `my-da$$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined no brackets backslash\",\n\t\t\tcontents: `my-da\\$tabase`,\n\t\t\texpected: `my-da\\$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined brackets backslash\",\n\t\t\tcontents: `my-da\\${ta}base`,\n\t\t\texpected: `my-da\\${ta}base`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets and suffix\",\n\t\t\tcontents: `my-da$VARbase`,\n\t\t\texpected: `my-da$VARbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets\",\n\t\t\tcontents: `my-da$VAR`,\n\t\t\texpected: `my-dafoobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets\",\n\t\t\tcontents: `my-da${VAR}base`,\n\t\t\texpected: `my-dafoobarbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets double dollar\",\n\t\t\tcontents: `my-da$$VAR`,\n\t\t\texpected: `my-da$foobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets double dollar\",\n\t\t\tcontents: `my-da$${VAR}`,\n\t\t\texpected: `my-da$foobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets backslash\",\n\t\t\tcontents: `my-da\\$VAR`,\n\t\t\texpected: `my-da\\foobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets backslash\",\n\t\t\tcontents: `my-da\\${VAR}base`,\n\t\t\texpected: `my-da\\foobarbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"fallback\",\n\t\t\tcontents: `my-da${ta:-omg}base`,\n\t\t\texpected: `my-daomgbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"fallback env\",\n\t\t\tcontents: `my-da${ta:-${FALLBACK}}base`,\n\t\t\texpected: `my-dadefaultbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"regex substitution\",\n\t\t\tcontents: `${1}`,\n\t\t\texpected: `${1}`,\n\t\t},\n\t\t{\n\t\t\tname:     \"empty but set\",\n\t\t\tcontents: \"Contains ${EMPTY} nothing\",\n\t\t\texpected: \"Contains  nothing\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"VAR\", \"foobar\")\n\t\t\tt.Setenv(\"FALLBACK\", \"default\")\n\t\t\tt.Setenv(\"EMPTY\", \"\")\n\t\t\tactual, err := substituteEnvironmentNonStrict([]byte(tt.contents), true)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, string(actual))\n\t\t})\n\t}\n}\n\nfunc TestEnvironmentSubstitutionNewBehavior(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcontents string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"not defined no brackets\",\n\t\t\tcontents: `my-da$tabase`,\n\t\t\texpected: `my-da$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined brackets\",\n\t\t\tcontents: `my-da${ta}base`,\n\t\t\texpected: `my-da${ta}base`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined no brackets double dollar\",\n\t\t\tcontents: `my-da$$tabase`,\n\t\t\texpected: `my-da$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined no brackets backslash\",\n\t\t\tcontents: `my-da\\$tabase`,\n\t\t\texpected: `my-da\\$tabase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"not defined brackets backslash\",\n\t\t\tcontents: `my-da\\${ta}base`,\n\t\t\texpected: `my-da\\${ta}base`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets and suffix\",\n\t\t\tcontents: `my-da$VARbase`,\n\t\t\texpected: `my-da$VARbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets\",\n\t\t\tcontents: `my-da$VAR`,\n\t\t\texpected: `my-dafoobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets\",\n\t\t\tcontents: `my-da${VAR}base`,\n\t\t\texpected: `my-dafoobarbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets double dollar\",\n\t\t\tcontents: `my-da$$VAR`,\n\t\t\texpected: `my-da$VAR`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets double dollar\",\n\t\t\tcontents: `my-da$${VAR}`,\n\t\t\texpected: `my-da${VAR}`,\n\t\t},\n\t\t{\n\t\t\tname:     \"no brackets backslash\",\n\t\t\tcontents: `my-da\\$VAR`,\n\t\t\texpected: `my-da\\foobar`,\n\t\t},\n\t\t{\n\t\t\tname:     \"brackets backslash\",\n\t\t\tcontents: `my-da\\${VAR}base`,\n\t\t\texpected: `my-da\\foobarbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"fallback\",\n\t\t\tcontents: `my-da${ta:-omg}base`,\n\t\t\texpected: `my-daomgbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"fallback env\",\n\t\t\tcontents: `my-da${ta:-${FALLBACK}}base`,\n\t\t\texpected: `my-dadefaultbase`,\n\t\t},\n\t\t{\n\t\t\tname:     \"regex substitution\",\n\t\t\tcontents: `${1}`,\n\t\t\texpected: `${1}`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"VAR\", \"foobar\")\n\t\t\tt.Setenv(\"FALLBACK\", \"default\")\n\t\t\tactual, err := substituteEnvironmentNonStrict([]byte(tt.contents), false)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, string(actual))\n\t\t})\n\t}\n}\n\nfunc TestParseConfig(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tsetEnv   func(*testing.T)\n\t\tcontents string\n\t\texpected string\n\t\terrmsg   string\n\t}{\n\t\t{\n\t\t\tname: \"empty var name\",\n\t\t\tcontents: `\n# Environment variables can be used anywhere in this config file, simply surround\n# them with ${}. For strings the variable must be within quotes (ie, \"${STR_VAR}\"),\n# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})Should output ${NOT_SET:-${FALLBACK}}\n`,\n\t\t\texpected: \"\\n\\n\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"comment in command (issue #13643)\",\n\t\t\tcontents: `\n\t\t\t[[inputs.exec]]\n\t\t\t  commands = [\"echo \\\"abc#def\\\"\"]\n\t\t\t`,\n\t\t\texpected: `\n\t\t\t[[inputs.exec]]\n\t\t\t  commands = [\"echo \\\"abc#def\\\"\"]\n\t\t\t`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.setEnv != nil {\n\t\t\t\ttt.setEnv(t)\n\t\t\t}\n\t\t\ttbl, err := parseConfig([]byte(tt.contents))\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tif len(tt.expected) > 0 {\n\t\t\t\trequire.EqualValues(t, tt.expected, string(tbl.Data))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRemoveComments(t *testing.T) {\n\t// Read expectation\n\texpected, err := os.ReadFile(filepath.Join(\"testdata\", \"envvar_comments_expected.toml\"))\n\trequire.NoError(t, err)\n\n\t// Read the file and remove the comments\n\tbuf, err := os.ReadFile(filepath.Join(\"testdata\", \"envvar_comments.toml\"))\n\trequire.NoError(t, err)\n\tremoved, err := removeComments(buf)\n\trequire.NoError(t, err)\n\tlines := bytes.Split(removed, []byte{'\\n'})\n\tfor i, line := range lines {\n\t\tlines[i] = bytes.TrimRight(line, \" \\t\")\n\t}\n\tactual := bytes.Join(lines, []byte{'\\n'})\n\n\t// Do the comparison\n\trequire.Equal(t, string(expected), string(actual))\n}\n\nfunc TestURLRetries3Fails(t *testing.T) {\n\thttpLoadConfigRetryInterval = 0 * time.Second\n\tresponseCounter := 0\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t\tresponseCounter++\n\t}))\n\tdefer ts.Close()\n\n\texpected := fmt.Sprintf(\"loading config file %s failed: failed to fetch HTTP config: 404 Not Found\", ts.URL)\n\n\tc := NewConfig()\n\terr := c.LoadConfig(ts.URL)\n\trequire.Error(t, err)\n\trequire.Equal(t, expected, err.Error())\n\trequire.Equal(t, 4, responseCounter)\n}\n\nfunc TestURLRetries3FailsThenPasses(t *testing.T) {\n\thttpLoadConfigRetryInterval = 0 * time.Second\n\tresponseCounter := 0\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif responseCounter <= 2 {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}\n\t\tresponseCounter++\n\t}))\n\tdefer ts.Close()\n\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfig(ts.URL))\n\trequire.Equal(t, 4, responseCounter)\n}\n"
  },
  {
    "path": "config/migration.go",
    "content": "package config\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t_ \"github.com/influxdata/telegraf/migrations/all\" // register all migrations\n)\n\ntype section struct {\n\tname    string\n\tbegin   int\n\tcontent *ast.Table\n\traw     *bytes.Buffer\n}\n\nfunc splitToSections(root *ast.Table) ([]section, error) {\n\tvar sections []section\n\tfor name, elements := range root.Fields {\n\t\tswitch name {\n\t\tcase \"inputs\", \"outputs\", \"processors\", \"aggregators\":\n\t\t\tcategory, ok := elements.(*ast.Table)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is not a table (%T)\", name, category)\n\t\t\t}\n\n\t\t\tfor plugin, elements := range category.Fields {\n\t\t\t\ttbls, ok := elements.([]*ast.Table)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, fmt.Errorf(\"elements of \\\"%s.%s\\\" is not a list of tables (%T)\", name, plugin, elements)\n\t\t\t\t}\n\t\t\t\tfor _, tbl := range tbls {\n\t\t\t\t\ts := section{\n\t\t\t\t\t\tname:    name + \".\" + tbl.Name,\n\t\t\t\t\t\tbegin:   tbl.Line,\n\t\t\t\t\t\tcontent: tbl,\n\t\t\t\t\t\traw:     &bytes.Buffer{},\n\t\t\t\t\t}\n\t\t\t\t\tsections = append(sections, s)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\ttbl, ok := elements.(*ast.Table)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is not a table (%T)\", name, elements)\n\t\t\t}\n\t\t\ts := section{\n\t\t\t\tname:    name,\n\t\t\t\tbegin:   tbl.Line,\n\t\t\t\tcontent: tbl,\n\t\t\t\traw:     &bytes.Buffer{},\n\t\t\t}\n\t\t\tsections = append(sections, s)\n\t\t}\n\t}\n\n\t// Sort the TOML elements by begin (line-number)\n\tsort.SliceStable(sections, func(i, j int) bool { return sections[i].begin < sections[j].begin })\n\n\treturn sections, nil\n}\n\nfunc assignTextToSections(data []byte, sections []section) ([]section, error) {\n\t// Now assign the raw text to each section\n\tif sections[0].begin > 0 {\n\t\tsections = append([]section{{\n\t\t\tname:  \"header\",\n\t\t\tbegin: 0,\n\t\t\traw:   &bytes.Buffer{},\n\t\t}}, sections...)\n\t}\n\n\tvar lineno int\n\tscanner := bufio.NewScanner(bytes.NewBuffer(data))\n\tfor idx, next := range sections[1:] {\n\t\tvar buf bytes.Buffer\n\t\tfor lineno < next.begin-1 {\n\t\t\tif !scanner.Scan() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tlineno++\n\n\t\t\tline := strings.TrimSpace(scanner.Text())\n\t\t\tif strings.HasPrefix(line, \"#\") {\n\t\t\t\tbuf.Write(scanner.Bytes())\n\t\t\t\tbuf.WriteString(\"\\n\")\n\t\t\t\tcontinue\n\t\t\t} else if buf.Len() > 0 {\n\t\t\t\tif _, err := io.Copy(sections[idx].raw, &buf); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"copying buffer failed: %w\", err)\n\t\t\t\t}\n\t\t\t\tbuf.Reset()\n\t\t\t}\n\n\t\t\tsections[idx].raw.Write(scanner.Bytes())\n\t\t\tsections[idx].raw.WriteString(\"\\n\")\n\t\t}\n\t\tif err := scanner.Err(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"splitting by line failed: %w\", err)\n\t\t}\n\n\t\t// If a comment is directly in front of the next section, without\n\t\t// newline, the comment is assigned to the next section.\n\t\tif buf.Len() > 0 {\n\t\t\tif _, err := io.Copy(sections[idx+1].raw, &buf); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"copying buffer failed: %w\", err)\n\t\t\t}\n\t\t\tbuf.Reset()\n\t\t}\n\t}\n\t// Write the remaining to the last section\n\tfor scanner.Scan() {\n\t\tsections[len(sections)-1].raw.Write(scanner.Bytes())\n\t\tsections[len(sections)-1].raw.WriteString(\"\\n\")\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"splitting by line failed: %w\", err)\n\t}\n\treturn sections, nil\n}\n\nfunc ApplyMigrations(data []byte) ([]byte, uint64, error) {\n\troot, err := toml.Parse(data)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"parsing failed: %w\", err)\n\t}\n\n\t// Split the configuration into sections containing the location\n\t// in the file.\n\tsections, err := splitToSections(root)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"splitting to sections failed: %w\", err)\n\t}\n\tif len(sections) == 0 {\n\t\treturn nil, 0, errors.New(\"no TOML configuration found\")\n\t}\n\n\t// Assign the configuration text to the corresponding segments\n\tsections, err = assignTextToSections(data, sections)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"assigning text failed: %w\", err)\n\t}\n\n\tvar applied uint64\n\t// Do the actual global section migration(s)\n\tfor idx, s := range sections {\n\t\tif strings.Contains(s.name, \".\") {\n\t\t\tcontinue\n\t\t}\n\t\tlog.Printf(\"D!   applying global migrations to section %q in line %d...\", s.name, s.begin)\n\t\tfor _, migrate := range migrations.GlobalMigrations {\n\t\t\tresult, msg, err := migrate(s.name, s.content)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, migrations.ErrNotApplicable) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, 0, fmt.Errorf(\"migrating options of %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t\t}\n\t\t\tif msg != \"\" {\n\t\t\t\tlog.Printf(\"I! Global section %q in line %d: %s\", s.name, s.begin, msg)\n\t\t\t}\n\t\t\ts.raw = bytes.NewBuffer(result)\n\t\t\tapplied++\n\t\t}\n\t\tsections[idx] = s\n\t}\n\n\t// Do the actual plugin migration(s)\n\tfor idx, s := range sections {\n\t\tmigrate, found := migrations.PluginMigrations[s.name]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Printf(\"D!   migrating plugin %q in line %d...\", s.name, s.begin)\n\t\tresult, msg, err := migrate(s.content)\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"migrating %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t}\n\t\tif msg != \"\" {\n\t\t\tlog.Printf(\"I! Plugin %q in line %d: %s\", s.name, s.begin, msg)\n\t\t}\n\t\ts.raw = bytes.NewBuffer(result)\n\t\ttbl, err := toml.Parse(s.raw.Bytes())\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"reparsing migrated %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t}\n\t\ts.content = tbl\n\t\tsections[idx] = s\n\t\tapplied++\n\t}\n\n\t// Do general migrations applying to all plugins\n\tfor idx, s := range sections {\n\t\tparts := strings.Split(s.name, \".\")\n\t\tif len(parts) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tlog.Printf(\"D!   applying general migrations to plugin %q in line %d...\", s.name, s.begin)\n\t\tcategory, name := parts[0], parts[1]\n\t\tfor _, migrate := range migrations.GeneralMigrations {\n\t\t\tresult, msg, err := migrate(category, name, s.content)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, migrations.ErrNotApplicable) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, 0, fmt.Errorf(\"migrating options of %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t\t}\n\t\t\tif msg != \"\" {\n\t\t\t\tlog.Printf(\"I! Plugin %q in line %d: %s\", s.name, s.begin, msg)\n\t\t\t}\n\t\t\ts.raw = bytes.NewBuffer(result)\n\t\t\ttbl, err := toml.Parse(s.raw.Bytes())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, fmt.Errorf(\"reparsing migrated %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t\t}\n\t\t\tcatTbl := tbl.Fields[category].(*ast.Table)\n\t\t\ts.content = catTbl.Fields[name].([]*ast.Table)[0]\n\t\t\tapplied++\n\t\t}\n\t\tsections[idx] = s\n\t}\n\n\t// Do the actual plugin option migration(s)\n\tfor idx, s := range sections {\n\t\tmigrate, found := migrations.PluginOptionMigrations[s.name]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Printf(\"D!   migrating options of plugin %q in line %d...\", s.name, s.begin)\n\t\tresult, msg, err := migrate(s.content)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, migrations.ErrNotApplicable) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn nil, 0, fmt.Errorf(\"migrating options of %q (line %d) failed: %w\", s.name, s.begin, err)\n\t\t}\n\t\tif msg != \"\" {\n\t\t\tlog.Printf(\"I! Plugin %q in line %d: %s\", s.name, s.begin, msg)\n\t\t}\n\t\ts.raw = bytes.NewBuffer(result)\n\t\tsections[idx] = s\n\t\tapplied++\n\t}\n\n\t// Reconstruct the config file from the sections\n\tvar buf bytes.Buffer\n\tfor _, s := range sections {\n\t\t_, err = s.raw.WriteTo(&buf)\n\t\tif err != nil {\n\t\t\treturn nil, applied, fmt.Errorf(\"joining output failed: %w\", err)\n\t\t}\n\t}\n\n\treturn buf.Bytes(), applied, nil\n}\n"
  },
  {
    "path": "config/plugin_id.go",
    "content": "package config\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/influxdata/toml/ast\"\n)\n\ntype keyValuePair struct {\n\tKey   string\n\tValue string\n}\n\nfunc processTable(parent string, table *ast.Table) ([]keyValuePair, error) {\n\tvar prefix string\n\tvar options []keyValuePair\n\n\tif parent != \"\" {\n\t\tprefix = parent + \".\"\n\t}\n\n\tfor k, value := range table.Fields {\n\t\tswitch v := value.(type) {\n\t\tcase *ast.KeyValue:\n\t\t\tkey := prefix + k\n\t\t\toptions = append(options, keyValuePair{\n\t\t\t\tKey:   key,\n\t\t\t\tValue: v.Value.Source(),\n\t\t\t})\n\t\tcase *ast.Table:\n\t\t\tkey := prefix + k\n\t\t\tchildren, err := processTable(key, v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing table for %q failed: %w\", key, err)\n\t\t\t}\n\t\t\toptions = append(options, children...)\n\t\tcase []*ast.Table:\n\t\t\tfor i, t := range v {\n\t\t\t\tkey := fmt.Sprintf(\"%s#%d.%s\", prefix, i, k)\n\t\t\t\tchildren, err := processTable(key, t)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"parsing table for %q #%d failed: %w\", key, i, err)\n\t\t\t\t}\n\t\t\t\toptions = append(options, children...)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown node type %T in key %q\", value, prefix+k)\n\t\t}\n\t}\n\treturn options, nil\n}\n\nfunc generatePluginID(prefix string, table *ast.Table) (string, error) {\n\t// We need to ensure that identically configured plugins _always_\n\t// result in the same ID no matter which order the options are specified.\n\t// This is even more relevant as Golang does _not_ give any guarantee\n\t// on the ordering of maps.\n\t// So we flatten out the configuration options (also for nested objects)\n\t// and then sort the resulting array by the canonical key-name.\n\tcfg, err := processTable(\"\", table)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"processing AST failed: %w\", err)\n\t}\n\tsort.SliceStable(cfg, func(i, j int) bool { return cfg[i].Key < cfg[j].Key })\n\n\t// Hash the config options to get the ID. We also prefix the ID with\n\t// the plugin name to prevent overlap with other plugin types.\n\thash := sha256.New()\n\thash.Write(append([]byte(prefix), 0))\n\tfor _, kv := range cfg {\n\t\thash.Write([]byte(kv.Key + \":\" + kv.Value))\n\t\thash.Write([]byte{0})\n\t}\n\n\treturn hex.EncodeToString(hash.Sum(nil)), nil\n}\n"
  },
  {
    "path": "config/plugin_printer.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/jedib0t/go-pretty/v6/table\"\n)\n\nvar headers = []string{\"Name\", \"Source(s)\"}\n\ntype pluginPrinter struct {\n\tname   string\n\tsource string\n}\n\ntype pluginNames []pluginPrinter\n\nfunc getPluginSourcesTable(pluginNames []pluginPrinter) string {\n\tif !PrintPluginConfigSource {\n\t\treturn \"\"\n\t}\n\n\tif len(pluginNames) == 0 {\n\t\treturn \"\"\n\t}\n\n\tdata := make([][]any, 0, len(pluginNames))\n\trows := make(map[string][]string)\n\tfor _, plugin := range pluginNames {\n\t\tif _, ok := rows[plugin.name]; !ok {\n\t\t\trows[plugin.name] = make([]string, 0)\n\t\t}\n\t\trows[plugin.name] = append(rows[plugin.name], plugin.source)\n\t}\n\n\tfor name, sources := range rows {\n\t\tvar nameCountStr string\n\t\tif len(sources) > 1 {\n\t\t\tnameCountStr = fmt.Sprintf(\"%s (%dx)\", name, len(sources))\n\t\t} else {\n\t\t\tnameCountStr = name\n\t\t}\n\t\tdata = append(data, []any{nameCountStr, sources})\n\t}\n\tsort.Slice(data, func(i, j int) bool {\n\t\treturn len(data[i][1].([]string)) > len(data[j][1].([]string))\n\t})\n\treturn getTableString(headers, data)\n}\n\nfunc getTableString(headers []string, data [][]any) string {\n\tbuff := new(bytes.Buffer)\n\n\tt := table.NewWriter()\n\tt.SetOutputMirror(buff)\n\tt.AppendHeader(convertToRow(headers))\n\n\t// Append rows\n\tfor _, row := range data {\n\t\tprocessedRow := make([]interface{}, len(row))\n\t\tfor i, col := range row {\n\t\t\tswitch v := col.(type) {\n\t\t\tcase []string: // Convert slices to multi-line strings\n\t\t\t\tvar source map[string]int\n\t\t\t\tfor _, s := range v {\n\t\t\t\t\tif source == nil {\n\t\t\t\t\t\tsource = make(map[string]int)\n\t\t\t\t\t}\n\t\t\t\t\tsource[s]++\n\t\t\t\t}\n\t\t\t\t// sort the sources according to the count\n\t\t\t\tsources := make([]string, 0, len(source))\n\t\t\t\tfor s := range source {\n\t\t\t\t\tsources = append(sources, s)\n\t\t\t\t}\n\t\t\t\tsort.Slice(sources, func(i, j int) bool {\n\t\t\t\t\treturn source[sources[i]] > source[sources[j]]\n\t\t\t\t})\n\t\t\t\tfor i, s := range sources {\n\t\t\t\t\tif source[s] > 1 {\n\t\t\t\t\t\tsources[i] = fmt.Sprintf(\"%s (%dx)\", s, source[s])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tprocessedRow[i] = strings.Join(sources, \"\\n\")\n\t\t\tdefault:\n\t\t\t\tprocessedRow[i] = v\n\t\t\t}\n\t\t}\n\t\tt.AppendRow(processedRow)\n\t}\n\n\tt.Style().Options.SeparateRows = true\n\treturn t.Render()\n}\n\n// Helper function to convert headers to table.Row\nfunc convertToRow(data []string) table.Row {\n\trow := make(table.Row, len(data))\n\tfor i, val := range data {\n\t\trow[i] = val\n\t}\n\treturn row\n}\n"
  },
  {
    "path": "config/plugin_selector.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf/filter\"\n)\n\nconst (\n\tselectorSeparator = \";\"\n)\n\nvar (\n\t// keyRegex matches a non empty string with A-Z, a-z, 0-9, -, _, .\n\tkeyRegex = regexp.MustCompile(`^[A-Za-z0-9._-]+$`)\n\t// selectorValueRegex matches a non empty string A-Z, a-z, 0-9, -, _, ., *, ?\n\tselectorValueRegex = regexp.MustCompile(`^[A-Za-z0-9._\\-*?]+$`)\n\t// labelValueRegex matches a non empty string with A-Z, a-z, 0-9, -, _, .\n\tlabelValueRegex = regexp.MustCompile(`^[A-Za-z0-9._-]+$`)\n\n\tpluginLabelSelector labelSelector\n)\n\n// CheckSelectionKeyValuePairs checks the key and value of a selector.\nfunc CheckSelectionKeyValuePairs(k, v string) error {\n\tif !keyRegex.MatchString(k) {\n\t\treturn fmt.Errorf(\"invalid key %q\", k)\n\t}\n\tif !selectorValueRegex.MatchString(v) {\n\t\treturn fmt.Errorf(\"invalid value %q\", v)\n\t}\n\treturn nil\n}\n\n// CheckLabelKeyValuePairs checks the key and value of a label.\nfunc CheckLabelKeyValuePairs(k, v string) error {\n\tif !keyRegex.MatchString(k) {\n\t\treturn fmt.Errorf(\"invalid key %q\", k)\n\t}\n\tif !labelValueRegex.MatchString(v) {\n\t\treturn fmt.Errorf(\"invalid value %q\", v)\n\t}\n\treturn nil\n}\n\n// SetPluginLabelSelections initializes the plugin label selector with\n// the given different selection groups. Within a group selectors are\n// combined via logical AND. Different selector groups are combined via OR.\nfunc SetPluginLabelSelections(selections []string) error {\n\treturn pluginLabelSelector.setSelections(selections)\n}\n\ntype labelSelector struct {\n\tgroups []map[string]filter.Filter\n}\n\nfunc (l *labelSelector) setSelections(selections []string) error {\n\t// Pre-allocate the groups\n\tl.groups = make([]map[string]filter.Filter, 0, len(selections))\n\n\t// Within each group, the selector key-value pairs are separated by selector(semi-colon).\n\tfor _, selection := range selections {\n\t\tif err := l.addGroup(strings.Split(selection, selectorSeparator)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *labelSelector) addGroup(selection []string) error {\n\t// Skip empty selection\n\t// len(selection) can never be 0\n\tif len(selection) == 1 && selection[0] == \"\" {\n\t\treturn nil\n\t}\n\n\t// Parse the key-value pairs and create the corresponding filters\n\tgroup := make(map[string]filter.Filter, len(selection))\n\tfor _, s := range selection {\n\t\tk, v, found := strings.Cut(s, \"=\")\n\t\tif !found {\n\t\t\treturn fmt.Errorf(\"invalid selector %q: missing equal sign\", s)\n\t\t}\n\n\t\tk = strings.TrimSpace(k)\n\t\tif _, found := group[k]; found {\n\t\t\treturn fmt.Errorf(\"duplicate selector key %q within one statement\", k)\n\t\t}\n\n\t\tv = strings.TrimSpace(v)\n\t\tif err := CheckSelectionKeyValuePairs(k, v); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid selector %q: %w\", s, err)\n\t\t}\n\n\t\tf, err := filter.Compile([]string{v})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"compiling filter for selector %q failed: %w\", s, err)\n\t\t}\n\t\tgroup[k] = f\n\t}\n\n\t// Add the new group for logical OR combination\n\tl.groups = append(l.groups, group)\n\n\treturn nil\n}\n\nfunc (l *labelSelector) matches(labels map[string]string) bool {\n\t// Fallback to accepting all plugins without labels or if no select\n\t// statement specified via command line\n\tif len(labels) == 0 || len(l.groups) == 0 {\n\t\treturn true\n\t}\n\n\t// Iterate over the filter groups and combine all filters within a group via\n\t// logical AND and the different groups via logical OR.\n\treturn slices.ContainsFunc(l.groups, func(group map[string]filter.Filter) bool {\n\t\tfor k, f := range group {\n\t\t\tif label, found := labels[k]; !found || !f.Match(label) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n}\n"
  },
  {
    "path": "config/plugin_selector_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSetPluginLabelSelections(t *testing.T) {\n\ttests := []struct {\n\t\tname           string\n\t\tselections     []string\n\t\texpectedGroups []int // denotes the length of each group\n\t\twantErr        bool\n\t}{\n\t\t{\n\t\t\tname:           \"single selectors\",\n\t\t\tselections:     []string{\"env=prod\", \"region=dc-23\"},\n\t\t\texpectedGroups: []int{1, 1}, // two groups, each with one selector\n\t\t},\n\t\t{\n\t\t\tname:           \"multiple selectors\",\n\t\t\tselections:     []string{\"env=prod;region=dc-23\", \"env=dev;app=backend;policy=web\"},\n\t\t\texpectedGroups: []int{2, 3}, // two groups, one with two selectors and one with three\n\t\t},\n\t\t{\n\t\t\tname:       \"invalid selector syntax\",\n\t\t\tselections: []string{\"env=prod;region=dc-23\", \"invalid-selector\"},\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:           \"nil selectors\",\n\t\t\tselections:     nil,\n\t\t\texpectedGroups: []int{0},\n\t\t},\n\t\t{\n\t\t\tname:           \"empty selector\",\n\t\t\tselections:     []string{\"\"},\n\t\t\texpectedGroups: []int{0},\n\t\t},\n\t\t{\n\t\t\tname:           \"multiple empty selectors\",\n\t\t\tselections:     []string{\"\", \"app=web;env=prod*\", \"\"},\n\t\t\texpectedGroups: []int{2}, // only one valid group with 2 selectors\n\t\t},\n\t\t{\n\t\t\tname:       \"duplicate within group\",\n\t\t\tselections: []string{\"env=prod;app=web;env=staging\"},\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:       \"invalid key\",\n\t\t\tselections: []string{\"invalid$key=prod\", \"region=dc-23\"},\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:       \"invalid value\",\n\t\t\tselections: []string{\"env=prod;app=web;invalid=value&()\"},\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:       \"empty value\",\n\t\t\tselections: []string{\"env=prod;app=\"},\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:           \"contains only _,-,*,?\",\n\t\t\tselections:     []string{\"env=__-_*?\"},\n\t\t\texpectedGroups: []int{1},\n\t\t},\n\t\t{\n\t\t\tname:           \"regex check- character set\",\n\t\t\tselections:     []string{\"Env123=456prOd;123=*456?\", \"p0-p1_p2.=_?*Env234_-\"},\n\t\t\texpectedGroups: []int{2, 1},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar pluginSelector labelSelector\n\t\t\terr := pluginSelector.setSelections(tt.selections)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tfor i, group := range pluginSelector.groups {\n\t\t\t\trequire.Equal(t, len(group), tt.expectedGroups[i])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestKeyRegex(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twantErr bool\n\t}{\n\t\t// Valid\n\t\t{name: \"simple\", input: \"abc\"},\n\t\t{name: \"alphanumeric\", input: \"abc123\"},\n\t\t{name: \"with-dash\", input: \"abc-123\"},\n\t\t{name: \"with-dot\", input: \"abc.123\"},\n\t\t{name: \"with-underscore\", input: \"abc_123\"},\n\t\t{name: \"mixed\", input: \"A_z-9.X\"},\n\t\t{name: \"single-char\", input: \"a\"},\n\t\t{name: \"long-key\", input: \"abc.def-ghi_jkl.mno_123\"},\n\t\t{name: \"starts-with-dot\", input: \".abc\"},\n\t\t{name: \"ends-with-dot\", input: \"abc.\"},\n\t\t{name: \"two-dots\", input: \"a..b\"},\n\t\t// Invalid\n\t\t{name: \"empty\", input: \"\", wantErr: true},\n\t\t{name: \"wildcard-star\", input: \"abc*\", wantErr: true},\n\t\t{name: \"wildcard-question\", input: \"abc?\", wantErr: true},\n\t\t{name: \"space\", input: \"abc def\", wantErr: true},\n\t\t{name: \"unicode\", input: \"ümlaut\", wantErr: true},\n\t\t{name: \"symbols\", input: \"abc$\", wantErr: true},\n\t\t{name: \"slash\", input: \"abc/def\", wantErr: true},\n\t\t{name: \"colon\", input: \"abc:def\", wantErr: true},\n\t\t{name: \"comma\", input: \"abc,def\", wantErr: true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := CheckSelectionKeyValuePairs(tt.input, \"value\")\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSelectorValueRegex(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twantErr bool\n\t}{\n\t\t// Valid\n\t\t{name: \"simple\", input: \"abc\"},\n\t\t{name: \"with-wildcards\", input: \"a*b?c\"},\n\t\t{name: \"only-star\", input: \"*\"},\n\t\t{name: \"only-question\", input: \"?\"},\n\t\t{name: \"mixed-wildcards\", input: \"*a?b*c*\"},\n\t\t{name: \"alphanumeric\", input: \"abc123\"},\n\t\t{name: \"combo\", input: \"A_z-9.X*?foo\"},\n\t\t{name: \"dash-dot-underscore-wildcards\", input: \"a_b-c.d*?\"},\n\t\t{name: \"ends-with-wildcard\", input: \"abc*\"},\n\t\t{name: \"starts-with-wildcard\", input: \"*abc\"},\n\t\t{name: \"wildcard-middle\", input: \"ab*cd?ef\"},\n\t\t{name: \"long-value\", input: \"abc.def-ghi*jkl?mno_123\"},\n\n\t\t// Invalid\n\t\t{name: \"empty\", input: \"\", wantErr: true},\n\t\t{name: \"space\", input: \"abc def\", wantErr: true},\n\t\t{name: \"unicode\", input: \"ümlaut\", wantErr: true},\n\t\t{name: \"control-char\", input: \"abc\\x00def\", wantErr: true},\n\t\t{name: \"symbols\", input: \"abc$\", wantErr: true},\n\t\t{name: \"slash\", input: \"abc/def\", wantErr: true},\n\t\t{name: \"colon\", input: \"abc:def\", wantErr: true},\n\t\t{name: \"comma\", input: \"abc,def\", wantErr: true},\n\t\t{name: \"plus\", input: \"abc+def\", wantErr: true},\n\t\t{name: \"pipe\", input: \"abc|def\", wantErr: true},\n\t\t{name: \"caret\", input: \"abc^def\", wantErr: true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := CheckSelectionKeyValuePairs(\"key\", tt.input)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestLabelValueRegex(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twantErr bool\n\t}{\n\t\t// Valid\n\t\t{name: \"simple\", input: \"abc\"},\n\t\t{name: \"alphanumeric\", input: \"abc123\"},\n\t\t{name: \"with-dash\", input: \"abc-123\"},\n\t\t{name: \"with-dot\", input: \"abc.123\"},\n\t\t{name: \"with-underscore\", input: \"abc_123\"},\n\t\t{name: \"mixed\", input: \"A_z-9.X\"},\n\t\t{name: \"single-char\", input: \"a\"},\n\t\t{name: \"long\", input: \"abc.def-ghi_jkl.mno_123\"},\n\t\t{name: \"starts-with-dot\", input: \".abc\"},\n\t\t{name: \"ends-with-dot\", input: \"abc.\"},\n\t\t{name: \"two-dots\", input: \"a..b\"},\n\n\t\t// Invalid\n\t\t{name: \"empty\", input: \"\", wantErr: true},\n\t\t{name: \"wildcard-star\", input: \"abc*\", wantErr: true},\n\t\t{name: \"wildcard-question\", input: \"abc?\", wantErr: true},\n\t\t{name: \"space\", input: \"abc def\", wantErr: true},\n\t\t{name: \"unicode\", input: \"香港\", wantErr: true},\n\t\t{name: \"symbols\", input: \"abc$\", wantErr: true},\n\t\t{name: \"slash\", input: \"abc/def\", wantErr: true},\n\t\t{name: \"comma\", input: \"abc,def\", wantErr: true},\n\t\t{name: \"plus\", input: \"abc+def\", wantErr: true},\n\t\t{name: \"caret\", input: \"abc^def\", wantErr: true},\n\t\t{name: \"pipe\", input: \"abc|def\", wantErr: true},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := CheckLabelKeyValuePairs(\"key\", tt.input)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMatches(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tselectors []string\n\t\tlabels    map[string]string\n\t\texpected  bool\n\t}{\n\t\t{\n\t\t\tname:      \"[Backward Compatibility] No selectors, should run\",\n\t\t\tselectors: nil,\n\t\t\tlabels:    map[string]string{\"env\": \"prod\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"[Backward Compatibility] No labels, should run\",\n\t\t\tselectors: []string{\"env=prod\"},\n\t\t\tlabels:    nil,\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple exact match\",\n\t\t\tselectors: []string{\"env=prod\"},\n\t\t\tlabels:    map[string]string{\"env\": \"prod\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple mismatch\",\n\t\t\tselectors: []string{\"env=prod\"},\n\t\t\tlabels:    map[string]string{\"env\": \"dev\"},\n\t\t\texpected:  false,\n\t\t},\n\t\t{\n\t\t\tname:      \"extra labels ignored\",\n\t\t\tselectors: []string{\"env=prod\"},\n\t\t\tlabels:    map[string]string{\"env\": \"prod\", \"region\": \"us-east\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"AND inside selector (all match)\",\n\t\t\tselectors: []string{\"env=prod;region=dc-23\"},\n\t\t\tlabels:    map[string]string{\"env\": \"prod\", \"region\": \"dc-23\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"AND inside selector (partial match fail)\",\n\t\t\tselectors: []string{\"env=prod;region=dc-23\"},\n\t\t\tlabels:    map[string]string{\"env\": \"prod\", \"region\": \"dc-24\"},\n\t\t\texpected:  false,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple Wildcard match\",\n\t\t\tselectors: []string{\"region=dc-*\"},\n\t\t\tlabels:    map[string]string{\"region\": \"dc-23\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple Wildcard no match\",\n\t\t\tselectors: []string{\"region=us-*\"},\n\t\t\tlabels:    map[string]string{\"region\": \"eu-1\"},\n\t\t\texpected:  false,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple Wildcard match with ?\",\n\t\t\tselectors: []string{\"region=eu-dc-?-north\"},\n\t\t\tlabels:    map[string]string{\"region\": \"eu-dc-1-north\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Simple Wildcard mismatch with ?\",\n\t\t\tselectors: []string{\"region=eu-dc-?-north\"},\n\t\t\tlabels:    map[string]string{\"region\": \"eu-dc-fail-north\"},\n\t\t\texpected:  false,\n\t\t},\n\t\t{\n\t\t\tname:      \"Multiple selectors (OR logic) - First matches\",\n\t\t\tselectors: []string{\"app=web;env=prod\", \"region=eu-*\"},\n\t\t\tlabels:    map[string]string{\"app\": \"web\", \"env\": \"prod\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Multiple selectors (OR logic) - Second matches\",\n\t\t\tselectors: []string{\"app=web;env=prod\", \"region=eu-*\"},\n\t\t\tlabels:    map[string]string{\"app\": \"web\", \"env\": \"staging\", \"region\": \"eu-west\"},\n\t\t\texpected:  true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Multiple selectors (OR logic) - None matches\",\n\t\t\tselectors: []string{\"app=web;env=prod\", \"region=eu-*\", \"app=not-web\"},\n\t\t\tlabels:    map[string]string{\"app\": \"api\", \"env\": \"staging\", \"region\": \"us-east\"},\n\t\t\texpected:  false,\n\t\t},\n\t\t{\n\t\t\tname: \"Multiple labels and multiple selectors (AND logic)\",\n\t\t\tselectors: []string{\n\t\t\t\t\"env=prod-*-dc-*;region=eu-*456\", // this one should not match\n\t\t\t\t\"simple=match\",                   // this one should match\n\t\t\t}, // OR logic\n\t\t\tlabels: map[string]string{\n\t\t\t\t\"env\":    \"prod-23-dc-1something\",\n\t\t\t\t\"region\": \"eu-central-123\",\n\t\t\t\t\"simple\": \"match\",\n\t\t\t},\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:      \"Multiple labels and single selector(Selective AND)\",\n\t\t\tselectors: []string{\"env=prod\"},\n\t\t\tlabels: map[string]string{\n\t\t\t\t\"env\":    \"prod\",\n\t\t\t\t\"region\": \"dc-23\",\n\t\t\t\t\"extra\":  \"value\",\n\t\t\t\t\"extra2\": \"value2\",\n\t\t\t},\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:      \"complex charset match\",\n\t\t\tselectors: []string{\"Env-123=prOd456;Env_456=_123prOd-\", \"Env-123=?456*;Env_456=_???pr0D*\"},\n\t\t\tlabels: map[string]string{\n\t\t\t\t\"Env-123\": \"X456\",\n\t\t\t\t\"Env_456\": \"____pr0D123\",\n\t\t\t},\n\t\t\texpected: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tpls := labelSelector{}\n\t\t\trequire.NoError(t, pls.setSelections(tt.selectors))\n\t\t\trequire.Equal(t, tt.expected, pls.matches(tt.labels))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "config/secret.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync/atomic\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// unlinkedSecrets contains the list of secrets that contain\n// references not yet linked to their corresponding secret-store.\n// Those secrets must later (after reading the config) be linked\n// by the config to their respective secret-stores.\n// Secrets containing constant strings will not be found in this\n// list.\nvar unlinkedSecrets = make([]*Secret, 0)\n\n// secretStorePattern is a regex to validate secret-store IDs\nvar secretStorePattern = regexp.MustCompile(`^\\w+$`)\n\n// secretPattern is a regex to extract references to secrets store in a secret-store\nvar secretPattern = regexp.MustCompile(`@\\{(\\w+:\\w+)\\}`)\n\n// secretCandidatePattern is a regex to find secret candidates to warn users on invalid characters in references\nvar secretCandidatePattern = regexp.MustCompile(`@\\{.+?:.+?}`)\n\n// secretCount is the number of secrets use in Telegraf\nvar secretCount atomic.Int64\n\n// selectedImpl is the configured implementation for secrets\nvar selectedImpl secretImpl = &protectedSecretImpl{}\n\n// secretImpl represents an abstraction for different implementations of secrets\ntype secretImpl interface {\n\tContainer(secret []byte) secretContainer\n\tEmptyBuffer() SecretBuffer\n\tWipe(secret []byte)\n}\n\nfunc EnableSecretProtection() {\n\tselectedImpl = &protectedSecretImpl{}\n}\n\nfunc DisableSecretProtection() {\n\tselectedImpl = &unprotectedSecretImpl{}\n}\n\n// secretContainer represents an abstraction of the container holding the\n// actual secret value\ntype secretContainer interface {\n\tDestroy()\n\tEquals(ref []byte) (bool, error)\n\tBuffer() (SecretBuffer, error)\n\tAsBuffer(secret []byte) SecretBuffer\n\tReplace(secret []byte)\n}\n\n// SecretBuffer allows to access the content of the secret\ntype SecretBuffer interface {\n\t// Size returns the length of the buffer content\n\tSize() int\n\t// Grow will grow the capacity of the underlying buffer to the given size\n\tGrow(capacity int)\n\t// Bytes returns the content of the buffer as bytes.\n\t// NOTE: The returned bytes shall NOT be accessed after destroying the\n\t// buffer using 'Destroy()' as the underlying the memory area might be\n\t// wiped and invalid.\n\tBytes() []byte\n\t// TemporaryString returns the content of the buffer as a string.\n\t// NOTE: The returned String shall NOT be accessed after destroying the\n\t// buffer using 'Destroy()' as the underlying the memory area might be\n\t// wiped and invalid.\n\tTemporaryString() string\n\t// String returns a copy of the underlying buffer's content as string.\n\t// It is safe to use the returned value after destroying the buffer.\n\tString() string\n\t// Destroy will wipe the buffer's content and destroy the underlying\n\t// buffer. Do not access the buffer after destroying it.\n\tDestroy()\n}\n\n// Secret safely stores sensitive data such as a password or token\ntype Secret struct {\n\t// container is the implementation for holding the secret. It can be\n\t// protected or not depending on the concrete implementation.\n\tcontainer secretContainer\n\n\t// resolvers are the functions for resolving a given secret-id (key)\n\tresolvers map[string]telegraf.ResolveFunc\n\n\t// unlinked contains all references in the secret that are not yet\n\t// linked to the corresponding secret store.\n\tunlinked []string\n\n\t// notempty denotes if the secret is completely empty\n\tnotempty bool\n}\n\n// NewSecret creates a new secret from the given bytes\nfunc NewSecret(b []byte) Secret {\n\ts := Secret{}\n\ts.init(b)\n\treturn s\n}\n\n// UnmarshalText creates a secret from a toml value following the \"string\" rule.\nfunc (s *Secret) UnmarshalText(b []byte) error {\n\t// Unmarshal secret from TOML and put it into protected memory\n\ts.init(b)\n\n\t// Keep track of secrets that contain references to secret-stores\n\t// for later resolving by the config.\n\tif len(s.unlinked) > 0 && s.notempty {\n\t\tunlinkedSecrets = append(unlinkedSecrets, s)\n\t}\n\n\treturn nil\n}\n\n// Initialize the secret content\nfunc (s *Secret) init(secret []byte) {\n\t// Keep track of the number of secrets...\n\tsecretCount.Add(1)\n\n\t// Remember if the secret is completely empty\n\ts.notempty = len(secret) != 0\n\n\t// Find all secret candidates and check if they are really a valid\n\t// reference. Otherwise issue a warning to let the user know that there is\n\t// a potential issue with their secret instead of silently ignoring it.\n\tcandidates := secretCandidatePattern.FindAllString(string(secret), -1)\n\ts.unlinked = make([]string, 0, len(candidates))\n\tfor _, c := range candidates {\n\t\tif secretPattern.MatchString(c) {\n\t\t\ts.unlinked = append(s.unlinked, c)\n\t\t} else {\n\t\t\tlog.Printf(\"W! Secret %q contains invalid character(s), only letters, digits and underscores are allowed.\", c)\n\t\t}\n\t}\n\ts.resolvers = nil\n\n\t// Setup the container implementation\n\ts.container = selectedImpl.Container(secret)\n}\n\n// Destroy the secret content\nfunc (s *Secret) Destroy() {\n\ts.resolvers = nil\n\ts.unlinked = nil\n\ts.notempty = false\n\n\tif s.container != nil {\n\t\ts.container.Destroy()\n\t\ts.container = nil\n\n\t\t// Keep track of the number of used secrets...\n\t\tsecretCount.Add(-1)\n\t}\n}\n\n// Empty return if the secret is completely empty\nfunc (s *Secret) Empty() bool {\n\treturn !s.notempty\n}\n\n// EqualTo performs a constant-time comparison of the secret to the given reference\nfunc (s *Secret) EqualTo(ref []byte) (bool, error) {\n\tif s.container == nil {\n\t\treturn false, nil\n\t}\n\n\tif len(s.unlinked) > 0 {\n\t\treturn false, fmt.Errorf(\"unlinked parts in secret: %v\", strings.Join(s.unlinked, \";\"))\n\t}\n\n\treturn s.container.Equals(ref)\n}\n\n// Get return the string representation of the secret\nfunc (s *Secret) Get() (SecretBuffer, error) {\n\tif s.container == nil {\n\t\treturn selectedImpl.EmptyBuffer(), nil\n\t}\n\n\tif len(s.unlinked) > 0 {\n\t\treturn nil, fmt.Errorf(\"unlinked parts in secret: %v\", strings.Join(s.unlinked, \";\"))\n\t}\n\n\t// Decrypt the secret so we can return it\n\tbuffer, err := s.container.Buffer()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// We've got a static secret so simply return the buffer\n\tif len(s.resolvers) == 0 {\n\t\treturn buffer, nil\n\t}\n\tdefer buffer.Destroy()\n\n\treplaceErrs := make([]string, 0)\n\tnewsecret := secretPattern.ReplaceAllFunc(buffer.Bytes(), func(match []byte) []byte {\n\t\tresolver, found := s.resolvers[string(match)]\n\t\tif !found {\n\t\t\treplaceErrs = append(replaceErrs, fmt.Sprintf(\"no resolver for %q\", match))\n\t\t\treturn match\n\t\t}\n\t\treplacement, _, err := resolver()\n\t\tif err != nil {\n\t\t\treplaceErrs = append(replaceErrs, fmt.Sprintf(\"resolving %q failed: %v\", match, err))\n\t\t\treturn match\n\t\t}\n\n\t\treturn replacement\n\t})\n\tif len(replaceErrs) > 0 {\n\t\tselectedImpl.Wipe(newsecret)\n\t\treturn nil, fmt.Errorf(\"replacing secrets failed: %s\", strings.Join(replaceErrs, \";\"))\n\t}\n\n\treturn s.container.AsBuffer(newsecret), nil\n}\n\n// Set overwrites the secret's value with a new one. Please note, the secret\n// is not linked again, so only references to secret-stores can be used, e.g. by\n// adding more clear-text or reordering secrets.\nfunc (s *Secret) Set(value []byte) error {\n\t// Link the new value can be resolved\n\tsecret, res, replaceErrs := resolve(value, s.resolvers)\n\tif len(replaceErrs) > 0 {\n\t\treturn fmt.Errorf(\"linking new secrets failed: %s\", strings.Join(replaceErrs, \";\"))\n\t}\n\n\t// Set the new secret\n\ts.container.Replace(secret)\n\ts.resolvers = res\n\ts.notempty = len(value) > 0\n\n\treturn nil\n}\n\n// GetUnlinked return the parts of the secret that is not yet linked to a resolver\nfunc (s *Secret) GetUnlinked() []string {\n\treturn s.unlinked\n}\n\n// Link used the given resolver map to link the secret parts to their\n// secret-store resolvers.\nfunc (s *Secret) Link(resolvers map[string]telegraf.ResolveFunc) error {\n\t// Decrypt the secret so we can return it\n\tif s.container == nil {\n\t\treturn nil\n\t}\n\tbuffer, err := s.container.Buffer()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer buffer.Destroy()\n\n\t// Iterate through the parts and try to resolve them. For static parts\n\t// we directly replace them, while for dynamic ones we store the resolver.\n\tnewsecret, res, replaceErrs := resolve(buffer.Bytes(), resolvers)\n\tif len(replaceErrs) > 0 {\n\t\treturn fmt.Errorf(\"linking secrets failed: %s\", strings.Join(replaceErrs, \";\"))\n\t}\n\ts.resolvers = res\n\n\t// Store the secret if it has changed\n\tif buffer.TemporaryString() != string(newsecret) {\n\t\ts.container.Replace(newsecret)\n\t}\n\n\t// All linked now\n\ts.unlinked = nil\n\n\treturn nil\n}\n\nfunc resolve(secret []byte, resolvers map[string]telegraf.ResolveFunc) ([]byte, map[string]telegraf.ResolveFunc, []string) {\n\t// Iterate through the parts and try to resolve them. For static parts\n\t// we directly replace them, while for dynamic ones we store the resolver.\n\treplaceErrs := make([]string, 0)\n\tremaining := make(map[string]telegraf.ResolveFunc)\n\tnewsecret := secretPattern.ReplaceAllFunc(secret, func(match []byte) []byte {\n\t\tresolver, found := resolvers[string(match)]\n\t\tif !found {\n\t\t\treplaceErrs = append(replaceErrs, fmt.Sprintf(\"unlinked part %q\", match))\n\t\t\treturn match\n\t\t}\n\t\treplacement, dynamic, err := resolver()\n\t\tif err != nil {\n\t\t\treplaceErrs = append(replaceErrs, fmt.Sprintf(\"resolving %q failed: %v\", match, err))\n\t\t\treturn match\n\t\t}\n\n\t\t// Replace static parts right away\n\t\tif !dynamic {\n\t\t\treturn replacement\n\t\t}\n\n\t\t// Keep the resolver for dynamic secrets\n\t\tremaining[string(match)] = resolver\n\t\treturn match\n\t})\n\treturn newsecret, remaining, replaceErrs\n}\n\nfunc splitLink(s string) (storeID, key string) {\n\t// There should _ALWAYS_ be two parts due to the regular expression match\n\tparts := strings.SplitN(s[2:len(s)-1], \":\", 2)\n\treturn parts[0], parts[1]\n}\n"
  },
  {
    "path": "config/secret_protected.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/awnumar/memguard\"\n)\n\ntype protectedSecretImpl struct{}\n\nfunc (*protectedSecretImpl) Container(secret []byte) secretContainer {\n\treturn &protectedSecretContainer{\n\t\tenclave: memguard.NewEnclave(secret),\n\t}\n}\n\nfunc (*protectedSecretImpl) EmptyBuffer() SecretBuffer {\n\treturn &lockedBuffer{}\n}\n\nfunc (*protectedSecretImpl) Wipe(secret []byte) {\n\tmemguard.WipeBytes(secret)\n}\n\ntype lockedBuffer struct {\n\tbuf *memguard.LockedBuffer\n}\n\nfunc (lb *lockedBuffer) Size() int {\n\tif lb.buf == nil {\n\t\treturn 0\n\t}\n\treturn lb.buf.Size()\n}\n\nfunc (lb *lockedBuffer) Grow(capacity int) {\n\tsize := lb.Size()\n\tif capacity <= size {\n\t\treturn\n\t}\n\n\tbuf := memguard.NewBuffer(capacity)\n\tif lb.buf != nil {\n\t\tbuf.Copy(lb.buf.Bytes())\n\t}\n\tlb.buf.Destroy()\n\tlb.buf = buf\n}\n\nfunc (lb *lockedBuffer) Bytes() []byte {\n\tif lb.buf == nil {\n\t\treturn nil\n\t}\n\treturn lb.buf.Bytes()\n}\n\nfunc (lb *lockedBuffer) TemporaryString() string {\n\tif lb.buf == nil {\n\t\treturn \"\"\n\t}\n\treturn lb.buf.String()\n}\n\nfunc (lb *lockedBuffer) String() string {\n\tif lb.buf == nil {\n\t\treturn \"\"\n\t}\n\treturn string(lb.buf.Bytes())\n}\n\nfunc (lb *lockedBuffer) Destroy() {\n\tif lb.buf == nil {\n\t\treturn\n\t}\n\tlb.buf.Destroy()\n\tlb.buf = nil\n}\n\ntype protectedSecretContainer struct {\n\tenclave *memguard.Enclave\n}\n\nfunc (c *protectedSecretContainer) Destroy() {\n\tif c.enclave == nil {\n\t\treturn\n\t}\n\n\t// Wipe the secret from memory\n\tlockbuf, err := c.enclave.Open()\n\tif err == nil {\n\t\tlockbuf.Destroy()\n\t}\n\tc.enclave = nil\n}\n\nfunc (c *protectedSecretContainer) Equals(ref []byte) (bool, error) {\n\tif c.enclave == nil {\n\t\treturn false, nil\n\t}\n\n\t// Get a locked-buffer of the secret to perform the comparison\n\tlockbuf, err := c.enclave.Open()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"opening enclave failed: %w\", err)\n\t}\n\tdefer lockbuf.Destroy()\n\n\treturn lockbuf.EqualTo(ref), nil\n}\n\nfunc (c *protectedSecretContainer) Buffer() (SecretBuffer, error) {\n\tif c.enclave == nil {\n\t\treturn &lockedBuffer{}, nil\n\t}\n\n\t// Get a locked-buffer of the secret to perform the comparison\n\tlockbuf, err := c.enclave.Open()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"opening enclave failed: %w\", err)\n\t}\n\n\treturn &lockedBuffer{lockbuf}, nil\n}\n\nfunc (*protectedSecretContainer) AsBuffer(secret []byte) SecretBuffer {\n\treturn &lockedBuffer{memguard.NewBufferFromBytes(secret)}\n}\n\nfunc (c *protectedSecretContainer) Replace(secret []byte) {\n\tc.enclave = memguard.NewEnclave(secret)\n}\n"
  },
  {
    "path": "config/secret_test.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/awnumar/memguard\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/secretstores\"\n)\n\nfunc TestSecretConstantManually(t *testing.T) {\n\tmysecret := \"a wonderful test\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\tretrieved, err := s.Get()\n\trequire.NoError(t, err)\n\tdefer retrieved.Destroy()\n\trequire.EqualValues(t, mysecret, retrieved.TemporaryString())\n}\n\nfunc TestLinking(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\tresolvers := map[string]telegraf.ResolveFunc{\n\t\t\"@{referenced:secret}\": func() ([]byte, bool, error) {\n\t\t\treturn []byte(\"resolved secret\"), false, nil\n\t\t},\n\t}\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\trequire.NoError(t, s.Link(resolvers))\n\tretrieved, err := s.Get()\n\trequire.NoError(t, err)\n\tdefer retrieved.Destroy()\n\trequire.EqualValues(t, \"a resolved secret\", retrieved.TemporaryString())\n}\n\nfunc TestLinkingResolverError(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\tresolvers := map[string]telegraf.ResolveFunc{\n\t\t\"@{referenced:secret}\": func() ([]byte, bool, error) {\n\t\t\treturn nil, false, errors.New(\"broken\")\n\t\t},\n\t}\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\texpected := `linking secrets failed: resolving \"@{referenced:secret}\" failed: broken`\n\trequire.EqualError(t, s.Link(resolvers), expected)\n}\n\nfunc TestGettingUnlinked(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\t_, err := s.Get()\n\trequire.ErrorContains(t, err, \"unlinked parts in secret\")\n}\n\nfunc TestGettingMissingResolver(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\ts.unlinked = make([]string, 0)\n\ts.resolvers = map[string]telegraf.ResolveFunc{\n\t\t\"@{a:dummy}\": func() ([]byte, bool, error) {\n\t\t\treturn nil, false, nil\n\t\t},\n\t}\n\t_, err := s.Get()\n\texpected := `replacing secrets failed: no resolver for \"@{referenced:secret}\"`\n\trequire.EqualError(t, err, expected)\n}\n\nfunc TestGettingResolverError(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\ts.unlinked = make([]string, 0)\n\ts.resolvers = map[string]telegraf.ResolveFunc{\n\t\t\"@{referenced:secret}\": func() ([]byte, bool, error) {\n\t\t\treturn nil, false, errors.New(\"broken\")\n\t\t},\n\t}\n\t_, err := s.Get()\n\texpected := `replacing secrets failed: resolving \"@{referenced:secret}\" failed: broken`\n\trequire.EqualError(t, err, expected)\n}\n\nfunc TestUninitializedEnclave(t *testing.T) {\n\ts := Secret{}\n\tdefer s.Destroy()\n\trequire.NoError(t, s.Link(map[string]telegraf.ResolveFunc{}))\n\tretrieved, err := s.Get()\n\trequire.NoError(t, err)\n\tdefer retrieved.Destroy()\n\trequire.Empty(t, retrieved.Bytes())\n}\n\nfunc TestEnclaveOpenError(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\tmemguard.Purge()\n\terr := s.Link(map[string]telegraf.ResolveFunc{})\n\trequire.ErrorContains(t, err, \"opening enclave failed\")\n\n\ts.unlinked = make([]string, 0)\n\t_, err = s.Get()\n\trequire.ErrorContains(t, err, \"opening enclave failed\")\n}\n\nfunc TestMissingResolver(t *testing.T) {\n\tmysecret := \"a @{referenced:secret}\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\terr := s.Link(map[string]telegraf.ResolveFunc{})\n\trequire.ErrorContains(t, err, \"linking secrets failed: unlinked part\")\n}\n\nfunc TestSecretConstant(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcfg      []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"simple string\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t  secret = \"a secret\"\n\t\t\t`),\n\t\t\texpected: \"a secret\",\n\t\t},\n\t\t{\n\t\t\tname: \"mail address\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t  secret = \"someone@mock.org\"\n\t\t\t`),\n\t\t\texpected: \"someone@mock.org\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := NewConfig()\n\t\t\trequire.NoError(t, c.LoadConfigData(tt.cfg, EmptySourcePath))\n\t\t\trequire.Len(t, c.Inputs, 1)\n\n\t\t\t// Create a mockup secretstore\n\t\t\tstore := &MockupSecretStore{\n\t\t\t\tSecrets: map[string][]byte{\"mock\": []byte(\"fail\")},\n\t\t\t}\n\t\t\trequire.NoError(t, store.Init())\n\t\t\tc.SecretStores[\"mock\"] = store\n\t\t\trequire.NoError(t, c.LinkSecrets())\n\n\t\t\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\t\t\tsecret, err := plugin.Secret.Get()\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer secret.Destroy()\n\n\t\t\trequire.EqualValues(t, tt.expected, secret.TemporaryString())\n\t\t})\n\t}\n}\n\nfunc TestSecretUnquote(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tcfg  []byte\n\t}{\n\t\t{\n\t\t\tname: \"single quotes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = 'a secret'\n\t\t\t\t\texpected = 'a secret'\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"double quotes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"a secret\"\n\t\t\t\t\texpected = \"a secret\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"triple single quotes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = '''a secret'''\n\t\t\t\t\texpected = '''a secret'''\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"triple double quotes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"\"\"a secret\"\"\"\n\t\t\t\t\texpected = \"\"\"a secret\"\"\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"escaped double quotes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"\\\"a secret\\\"\"\n\t\t\t\t\texpected = \"\\\"a secret\\\"\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix double-single quotes (single)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"'a secret'\"\n\t\t\t\t\texpected = \"'a secret'\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix single-double quotes (single)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\tsecret = '\"a secret\"'\n\t\t\t\texpected = '\"a secret\"'\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix double-single quotes (triple-single)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"\"\"'a secret'\"\"\"\n\t\t\t\t\texpected = \"\"\"'a secret'\"\"\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix single-double quotes (triple-single)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = '''\"a secret\"'''\n\t\t\t\t\texpected = '''\"a secret\"'''\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix double-single quotes (triple)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"\"\"'''a secret'''\"\"\"\n\t\t\t\t\texpected = \"\"\"'''a secret'''\"\"\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"mix single-double quotes (triple)\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = '''\"\"\"a secret\"\"\"'''\n\t\t\t\t\texpected = '''\"\"\"a secret\"\"\"'''\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"single quotes with backslashes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = 'Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;'\n\t\t\t\t\texpected = 'Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;'\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"double quotes with backslashes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;\"\n\t\t\t\t\texpected = \"Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;\"\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"triple single quotes with backslashes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = '''Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;'''\n\t\t\t\t\texpected = '''Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;'''\n\t\t\t`),\n\t\t},\n\t\t{\n\t\t\tname: \"triple double quotes with backslashes\",\n\t\t\tcfg: []byte(`\n\t\t\t\t[[inputs.mockup]]\n\t\t\t\t\tsecret = \"\"\"Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;\"\"\"\n\t\t\t\t\texpected = \"\"\"Server=SQLTELEGRAF\\\\SQL2022;app name=telegraf;log=1;\"\"\"\n\t\t\t`),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := NewConfig()\n\t\t\trequire.NoError(t, c.LoadConfigData(tt.cfg, EmptySourcePath))\n\t\t\trequire.Len(t, c.Inputs, 1)\n\n\t\t\t// Create a mockup secretstore\n\t\t\tstore := &MockupSecretStore{\n\t\t\t\tSecrets: map[string][]byte{},\n\t\t\t}\n\t\t\trequire.NoError(t, store.Init())\n\t\t\tc.SecretStores[\"mock\"] = store\n\t\t\trequire.NoError(t, c.LinkSecrets())\n\n\t\t\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\t\t\tsecret, err := plugin.Secret.Get()\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer secret.Destroy()\n\n\t\t\trequire.EqualValues(t, plugin.Expected, secret.TemporaryString())\n\t\t})\n\t}\n}\n\nfunc TestSecretEnvironmentVariable(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.mockup]]\n\tsecret = \"$SOME_ENV_SECRET\"\n`)\n\tt.Setenv(\"SOME_ENV_SECRET\", \"an env secret\")\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{},\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\tsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer secret.Destroy()\n\n\trequire.EqualValues(t, \"an env secret\", secret.TemporaryString())\n}\n\nfunc TestSecretCount(t *testing.T) {\n\tsecretCount.Store(0)\n\tcfg := []byte(`\n[[inputs.mockup]]\n\n[[inputs.mockup]]\n  secret = \"a secret\"\n\n[[inputs.mockup]]\n  secret = \"another secret\"\n`)\n\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 3)\n\trequire.Equal(t, int64(2), secretCount.Load())\n\n\t// Remove all secrets and check\n\tfor _, ri := range c.Inputs {\n\t\tinput := ri.Input.(*MockupSecretPlugin)\n\t\tinput.Secret.Destroy()\n\t}\n\trequire.Equal(t, int64(0), secretCount.Load())\n}\n\nfunc TestSecretStoreStatic(t *testing.T) {\n\tcfg := []byte(\n\t\t`\n[[inputs.mockup]]\n\tsecret = \"@{mock:secret1}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:secret2}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:a_strange_secret}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:a_weird_secret}\"\n`)\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 4)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\n\t\t\t\"secret1\":          []byte(\"Ood Bnar\"),\n\t\t\t\"secret2\":          []byte(\"Thon\"),\n\t\t\t\"a_strange_secret\": []byte(\"Obi-Wan Kenobi\"),\n\t\t\t\"a_weird_secret\":   []byte(\"Arca Jeth\"),\n\t\t},\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\texpected := []string{\"Ood Bnar\", \"Thon\", \"Obi-Wan Kenobi\", \"Arca Jeth\"}\n\tfor i, input := range c.Inputs {\n\t\tplugin := input.Input.(*MockupSecretPlugin)\n\t\tsecret, err := plugin.Secret.Get()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected[i], secret.TemporaryString())\n\t\tsecret.Destroy()\n\t}\n}\n\nfunc TestSecretStoreInvalidKeys(t *testing.T) {\n\tcfg := []byte(\n\t\t`\n[[inputs.mockup]]\n\tsecret = \"@{mock:}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:wild?%go}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:a-strange-secret}\"\n[[inputs.mockup]]\n\tsecret = \"@{mock:a weird secret}\"\n`)\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 4)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\n\t\t\t\"\":                 []byte(\"Ood Bnar\"),\n\t\t\t\"wild?%go\":         []byte(\"Thon\"),\n\t\t\t\"a-strange-secret\": []byte(\"Obi-Wan Kenobi\"),\n\t\t\t\"a weird secret\":   []byte(\"Arca Jeth\"),\n\t\t},\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\texpected := []string{\n\t\t\"@{mock:}\",\n\t\t\"@{mock:wild?%go}\",\n\t\t\"@{mock:a-strange-secret}\",\n\t\t\"@{mock:a weird secret}\",\n\t}\n\tfor i, input := range c.Inputs {\n\t\tplugin := input.Input.(*MockupSecretPlugin)\n\t\tsecret, err := plugin.Secret.Get()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected[i], secret.TemporaryString())\n\t\tsecret.Destroy()\n\t}\n}\n\nfunc TestSecretStoreDeclarationMissingID(t *testing.T) {\n\tdefer func() { unlinkedSecrets = make([]*Secret, 0) }()\n\n\tcfg := []byte(`[[secretstores.mockup]]`)\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.ErrorContains(t, err, `error parsing mockup, \"mockup\" secret-store without ID`)\n}\n\nfunc TestSecretStoreDeclarationInvalidID(t *testing.T) {\n\tdefer func() { unlinkedSecrets = make([]*Secret, 0) }()\n\n\tinvalidIDs := []string{\"foo.bar\", \"dummy-123\", \"test!\", \"wohoo+\"}\n\ttmpl := `\n  [[secretstores.mockup]]\n    id = %q\n`\n\tfor _, id := range invalidIDs {\n\t\tt.Run(id, func(t *testing.T) {\n\t\t\tcfg := []byte(fmt.Sprintf(tmpl, id))\n\t\t\tc := NewConfig()\n\t\t\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\t\t\trequire.ErrorContains(t, err, `error parsing mockup, invalid secret-store ID`)\n\t\t})\n\t}\n}\n\nfunc TestSecretStoreDeclarationValidID(t *testing.T) {\n\tdefer func() { unlinkedSecrets = make([]*Secret, 0) }()\n\n\tvalidIDs := []string{\"foobar\", \"dummy123\", \"test_id\", \"W0Hoo_lala123\"}\n\ttmpl := `\n  [[secretstores.mockup]]\n    id = %q\n`\n\tfor _, id := range validIDs {\n\t\tt.Run(id, func(t *testing.T) {\n\t\t\tcfg := []byte(fmt.Sprintf(tmpl, id))\n\t\t\tc := NewConfig()\n\t\t\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\ntype SecretImplTestSuite struct {\n\tsuite.Suite\n\tprotected bool\n}\n\nfunc (tsuite *SecretImplTestSuite) SetupSuite() {\n\tif tsuite.protected {\n\t\tEnableSecretProtection()\n\t} else {\n\t\tDisableSecretProtection()\n\t}\n}\n\nfunc (*SecretImplTestSuite) TearDownSuite() {\n\tEnableSecretProtection()\n}\n\nfunc (*SecretImplTestSuite) TearDownTest() {\n\tunlinkedSecrets = make([]*Secret, 0)\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretEqualTo() {\n\tt := tsuite.T()\n\tmysecret := \"a wonderful test\"\n\ts := NewSecret([]byte(mysecret))\n\tdefer s.Destroy()\n\n\tequal, err := s.EqualTo([]byte(mysecret))\n\trequire.NoError(t, err)\n\trequire.True(t, equal)\n\n\tequal, err = s.EqualTo([]byte(\"some random text\"))\n\trequire.NoError(t, err)\n\trequire.False(t, equal)\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretStoreInvalidReference() {\n\tt := tsuite.T()\n\n\tcfg := []byte(\n\t\t`\n[[inputs.mockup]]\n\tsecret = \"@{mock:test}\"\n`)\n\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\"test\": []byte(\"Arca Jeth\")},\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"foo\"] = store\n\terr := c.LinkSecrets()\n\trequire.EqualError(t, err, `unknown secret-store for \"@{mock:test}\"`)\n\n\tfor _, input := range c.Inputs {\n\t\tplugin := input.Input.(*MockupSecretPlugin)\n\t\tsecret, err := plugin.Secret.Get()\n\t\trequire.EqualError(t, err, `unlinked parts in secret: @{mock:test}`)\n\t\trequire.Empty(t, secret)\n\t}\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretStoreStaticChanging() {\n\tt := tsuite.T()\n\n\tcfg := []byte(\n\t\t`\n[[inputs.mockup]]\n\tsecret = \"@{mock:secret}\"\n`)\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\"secret\": []byte(\"Ood Bnar\")},\n\t\tDynamic: false,\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\tsequence := []string{\"Ood Bnar\", \"Thon\", \"Obi-Wan Kenobi\", \"Arca Jeth\"}\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\tsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer secret.Destroy()\n\n\trequire.EqualValues(t, \"Ood Bnar\", secret.TemporaryString())\n\n\tfor _, v := range sequence {\n\t\tstore.Secrets[\"secret\"] = []byte(v)\n\t\tsecret, err := plugin.Secret.Get()\n\t\trequire.NoError(t, err)\n\n\t\t// The secret should not change as the store is marked non-dyamic!\n\t\trequire.EqualValues(t, \"Ood Bnar\", secret.TemporaryString())\n\t\tsecret.Destroy()\n\t}\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretStoreDynamic() {\n\tt := tsuite.T()\n\n\tcfg := []byte(\n\t\t`\n[[inputs.mockup]]\n\tsecret = \"@{mock:secret}\"\n`)\n\n\tc := NewConfig()\n\terr := c.LoadConfigData(cfg, EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\"secret\": []byte(\"Ood Bnar\")},\n\t\tDynamic: true,\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\tsequence := []string{\"Ood Bnar\", \"Thon\", \"Obi-Wan Kenobi\", \"Arca Jeth\"}\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\tfor _, v := range sequence {\n\t\tstore.Secrets[\"secret\"] = []byte(v)\n\t\tsecret, err := plugin.Secret.Get()\n\t\trequire.NoError(t, err)\n\n\t\t// The secret should not change as the store is marked non-dynamic!\n\t\trequire.EqualValues(t, v, secret.TemporaryString())\n\t\tsecret.Destroy()\n\t}\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretSet() {\n\tt := tsuite.T()\n\n\tcfg := []byte(`\n      [[inputs.mockup]]\n\t    secret = \"a secret\"\n\t`)\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 1)\n\trequire.NoError(t, c.LinkSecrets())\n\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\n\tsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer secret.Destroy()\n\trequire.EqualValues(t, \"a secret\", secret.TemporaryString())\n\n\trequire.NoError(t, plugin.Secret.Set([]byte(\"another secret\")))\n\tnewsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer newsecret.Destroy()\n\trequire.EqualValues(t, \"another secret\", newsecret.TemporaryString())\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretSetResolve() {\n\tt := tsuite.T()\n\tcfg := []byte(`\n      [[inputs.mockup]]\n\t    secret = \"@{mock:secret}\"\n\t`)\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\"secret\": []byte(\"Ood Bnar\")},\n\t\tDynamic: true,\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\n\tsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer secret.Destroy()\n\trequire.EqualValues(t, \"Ood Bnar\", secret.TemporaryString())\n\n\trequire.NoError(t, plugin.Secret.Set([]byte(\"@{mock:secret} is cool\")))\n\tnewsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer newsecret.Destroy()\n\trequire.EqualValues(t, \"Ood Bnar is cool\", newsecret.TemporaryString())\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretSetResolveInvalid() {\n\tt := tsuite.T()\n\n\tcfg := []byte(`\n      [[inputs.mockup]]\n\t    secret = \"@{mock:secret}\"\n\t`)\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 1)\n\n\t// Create a mockup secretstore\n\tstore := &MockupSecretStore{\n\t\tSecrets: map[string][]byte{\"secret\": []byte(\"Ood Bnar\")},\n\t\tDynamic: true,\n\t}\n\trequire.NoError(t, store.Init())\n\tc.SecretStores[\"mock\"] = store\n\trequire.NoError(t, c.LinkSecrets())\n\n\tplugin := c.Inputs[0].Input.(*MockupSecretPlugin)\n\n\tsecret, err := plugin.Secret.Get()\n\trequire.NoError(t, err)\n\tdefer secret.Destroy()\n\trequire.EqualValues(t, \"Ood Bnar\", secret.TemporaryString())\n\n\terr = plugin.Secret.Set([]byte(\"@{mock:another_secret}\"))\n\trequire.ErrorContains(t, err, `linking new secrets failed: unlinked part \"@{mock:another_secret}\"`)\n}\n\nfunc (tsuite *SecretImplTestSuite) TestSecretInvalidWarn() {\n\tt := tsuite.T()\n\n\t// Intercept the log output\n\tvar buf bytes.Buffer\n\tbackup := log.Writer()\n\tlog.SetOutput(&buf)\n\tdefer log.SetOutput(backup)\n\n\tcfg := []byte(`\n      [[inputs.mockup]]\n\t    secret = \"server=a user=@{mock:secret-with-invalid-chars} pass=@{mock:secret_pass}\"\n\t`)\n\tc := NewConfig()\n\trequire.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))\n\trequire.Len(t, c.Inputs, 1)\n\n\trequire.Contains(t, buf.String(), `W! Secret \"@{mock:secret-with-invalid-chars}\" contains invalid character(s)`)\n\trequire.NotContains(t, buf.String(), \"@{mock:secret_pass}\")\n}\n\nfunc TestSecretImplUnprotected(t *testing.T) {\n\timpl := &unprotectedSecretImpl{}\n\tcontainer := impl.Container([]byte(\"foobar\"))\n\trequire.NotNil(t, container)\n\tc, ok := container.(*unprotectedSecretContainer)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"foobar\", string(c.buf.content))\n\tbuf, err := container.Buffer()\n\trequire.NoError(t, err)\n\trequire.NotNil(t, buf)\n\trequire.Equal(t, []byte(\"foobar\"), buf.Bytes())\n\trequire.Equal(t, \"foobar\", buf.TemporaryString())\n\trequire.Equal(t, \"foobar\", buf.String())\n}\n\nfunc TestSecretImplTestSuiteUnprotected(t *testing.T) {\n\tsuite.Run(t, &SecretImplTestSuite{protected: false})\n}\n\nfunc TestSecretImplTestSuiteProtected(t *testing.T) {\n\tsuite.Run(t, &SecretImplTestSuite{protected: true})\n}\n\n// Mockup (input) plugin for testing to avoid cyclic dependencies\ntype MockupSecretPlugin struct {\n\tSecret   Secret `toml:\"secret\"`\n\tExpected string `toml:\"expected\"`\n}\n\nfunc (*MockupSecretPlugin) SampleConfig() string                { return \"Mockup test secret plugin\" }\nfunc (*MockupSecretPlugin) Gather(_ telegraf.Accumulator) error { return nil }\n\ntype MockupSecretStore struct {\n\tSecrets map[string][]byte\n\tDynamic bool\n}\n\nfunc (*MockupSecretStore) Init() error {\n\treturn nil\n}\nfunc (*MockupSecretStore) SampleConfig() string {\n\treturn \"Mockup test secret plugin\"\n}\n\nfunc (s *MockupSecretStore) Get(key string) ([]byte, error) {\n\tv, found := s.Secrets[key]\n\tif !found {\n\t\treturn nil, errors.New(\"not found\")\n\t}\n\treturn v, nil\n}\n\nfunc (s *MockupSecretStore) Set(key, value string) error {\n\ts.Secrets[key] = []byte(value)\n\treturn nil\n}\n\nfunc (s *MockupSecretStore) List() ([]string, error) {\n\tkeys := make([]string, 0, len(s.Secrets))\n\tfor k := range s.Secrets {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys, nil\n}\nfunc (s *MockupSecretStore) GetResolver(key string) (telegraf.ResolveFunc, error) {\n\treturn func() ([]byte, bool, error) {\n\t\tv, err := s.Get(key)\n\t\treturn v, s.Dynamic, err\n\t}, nil\n}\n\n// Register the mockup plugin on loading\nfunc init() {\n\t// Register the mockup input plugin for the required names\n\tinputs.Add(\"mockup\", func() telegraf.Input { return &MockupSecretPlugin{} })\n\tsecretstores.Add(\"mockup\", func(string) telegraf.SecretStore {\n\t\treturn &MockupSecretStore{}\n\t})\n}\n"
  },
  {
    "path": "config/secret_unprotected.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"unsafe\"\n)\n\ntype unprotectedSecretImpl struct{}\n\nfunc (*unprotectedSecretImpl) Container(secret []byte) secretContainer {\n\treturn &unprotectedSecretContainer{buf: newUnlockedBuffer(secret)}\n}\n\nfunc (*unprotectedSecretImpl) EmptyBuffer() SecretBuffer {\n\treturn &unlockedBuffer{}\n}\n\nfunc (*unprotectedSecretImpl) Wipe(secret []byte) {\n\tfor i := range secret {\n\t\tsecret[i] = 0\n\t}\n}\n\ntype unlockedBuffer struct {\n\tcontent []byte\n}\n\nfunc newUnlockedBuffer(secret []byte) *unlockedBuffer {\n\treturn &unlockedBuffer{bytes.Clone(secret)}\n}\n\nfunc (lb *unlockedBuffer) Size() int {\n\treturn len(lb.content)\n}\n\nfunc (*unlockedBuffer) Grow(int) {\n\t// The underlying byte-buffer will grow dynamically\n}\n\nfunc (lb *unlockedBuffer) Bytes() []byte {\n\treturn lb.content\n}\n\nfunc (lb *unlockedBuffer) TemporaryString() string {\n\t//nolint:gosec // G103: Valid use of unsafe call to cast underlying bytes to string\n\treturn unsafe.String(&lb.content[0], len(lb.content))\n}\n\nfunc (lb *unlockedBuffer) String() string {\n\treturn string(lb.content)\n}\n\nfunc (lb *unlockedBuffer) Destroy() {\n\tselectedImpl.Wipe(lb.content)\n\tlb.content = nil\n}\n\ntype unprotectedSecretContainer struct {\n\tbuf *unlockedBuffer\n}\n\nfunc (c *unprotectedSecretContainer) Destroy() {\n\tif c.buf == nil {\n\t\treturn\n\t}\n\n\t// Wipe the secret from memory\n\tc.buf.Destroy()\n\tc.buf = nil\n}\n\nfunc (c *unprotectedSecretContainer) Equals(ref []byte) (bool, error) {\n\tif c.buf == nil {\n\t\treturn false, nil\n\t}\n\n\treturn bytes.Equal(c.buf.content, ref), nil\n}\n\nfunc (c *unprotectedSecretContainer) Buffer() (SecretBuffer, error) {\n\tif c.buf == nil {\n\t\treturn &unlockedBuffer{}, nil\n\t}\n\n\treturn newUnlockedBuffer(c.buf.content), nil\n}\n\nfunc (*unprotectedSecretContainer) AsBuffer(secret []byte) SecretBuffer {\n\treturn &unlockedBuffer{secret}\n}\n\nfunc (c *unprotectedSecretContainer) Replace(secret []byte) {\n\tc.buf = newUnlockedBuffer(secret)\n}\n"
  },
  {
    "path": "config/testdata/addressbook.proto",
    "content": "syntax = \"proto3\";\n\npackage addressbook;\n\nmessage Person {\n  string name = 1;\n  int32 id = 2;  // Unique ID number for this person.\n  string email = 3;\n  uint32 age = 4;\n\n  enum PhoneType {\n    MOBILE = 0;\n    HOME = 1;\n    WORK = 2;\n  }\n\n  message PhoneNumber {\n    string number = 1;\n    PhoneType type = 2;\n  }\n\n  repeated PhoneNumber phones = 5;\n}\n\nmessage AddressBook {\n  repeated Person people = 1;\n  repeated string tags = 2;\n}\n"
  },
  {
    "path": "config/testdata/azure_monitor.toml",
    "content": "[[outputs.azure_monitor]]\n\n[[outputs.azure_monitor]]\n  namespace_prefix = \"\"\n"
  },
  {
    "path": "config/testdata/default_parser.toml",
    "content": "[[inputs.file]]\n   files = [\"metrics\"]\n"
  },
  {
    "path": "config/testdata/default_parser_exec.toml",
    "content": "[[inputs.exec]]\n  command = '/usr/bin/echo {\"value\": 42}'\n"
  },
  {
    "path": "config/testdata/deprecated_field_filter.toml",
    "content": "[[inputs.file]]\n  pass = [\"foo\"]\n  fieldpass = [\"bar\"]\n  fieldinclude = [\"baz\"]\n\n  drop = [\"foo\"]\n  fielddrop = [\"bar\"]\n  fieldexclude = [\"baz\"]\n"
  },
  {
    "path": "config/testdata/envvar_comments.toml",
    "content": "# Telegraf Configuration\n#\n# Telegraf is entirely plugin driven. All metrics are gathered from the\n# declared inputs, and sent to the declared outputs.\n#\n# Plugins must be declared in here to be active.\n# To deactivate a plugin, comment out the name and any variables.\n#\n# Use 'telegraf -config telegraf.conf -test' to see what metrics a config\n# file would generate.\n#\n# Environment variables can be used anywhere in this config file, simply surround\n# them with ${}. For strings the variable must be within quotes (ie, \"${STR_VAR}\"),\n# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})\n\n[global_tags]\n\n[agent]\ninterval = \"10s\"\nround_interval = true\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\ncollection_jitter = \"0s\"\nflush_interval = '10s'\nflush_jitter = \"0s\"\nprecision = \"\"\nhostname = ''\nomit_hostname = false\n\n[[outputs.influxdb]]\n  setting1 = '#'#test\n  setting2 = '''#'''#test\n  setting3 = \"#\"#test\n  setting4 = \"\"\"#\"\"\"#test\n  wicked1 = \"\\\"\"#test\n  wicked2 = \"\"\"\\\"\"\"\"#test\n\n[[inputs.cpu]]\n  percpu = true\n  #totalcpu = true\n  # collect_cpu_time = false\n  ## report_active = false\n\n[[a.plugin]]\n  mylist = [\n\t\"value 1\", # a good value\n        \"value 2\", # a better value\n\t\"value 3\", \"value 4\",\n  'value5', \"\"\"tagwith#value\"\"\",\n  ] # Should work\n\n[[some.stuff]]\n  a = 'not a #comment'\n  b = '''not a #comment'''\n  c = \"not a #comment\"\n  d = \"\"\"not a #comment\"\"\"\n  e = '''not a #comment containing \"quotes\"'''\n  f = '''not a #comment containing 'quotes'?'''\n  g = \"\"\"not a #comment containing \"quotes\"?\"\"\"\n\n# Issue #14237\n[[inputs.myplugin]]\nvalue = '''This isn't a #comment.'''\n\n[[processors.starlark]]\n  script = \"\"\"\n# Drop fields if they contain a string.\n#\n# Example Input:\n# measurement,host=hostname a=1,b=\"somestring\" 1597255410000000000\n#\n# Example Output:\n# measurement,host=hostname a=1 1597255410000000000\n\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"string\":\n            metric.fields.pop(k)\n\n    return metric\n\"\"\"\n\n[[processors.starlark]]\n  script = '''\n# Drop fields if they contain a string.\n#\n# Example Input:\n# measurement,host=hostname a=1,b=\"somestring\" 1597255410000000000\n#\n# Example Output:\n# measurement,host=hostname a=1 1597255410000000000\n\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"string\":\n            metric.fields.pop(k)\n\n    return metric\n'''\n"
  },
  {
    "path": "config/testdata/envvar_comments_expected.toml",
    "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n[global_tags]\n\n[agent]\ninterval = \"10s\"\nround_interval = true\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\ncollection_jitter = \"0s\"\nflush_interval = '10s'\nflush_jitter = \"0s\"\nprecision = \"\"\nhostname = ''\nomit_hostname = false\n\n[[outputs.influxdb]]\n  setting1 = '#'\n  setting2 = '''#'''\n  setting3 = \"#\"\n  setting4 = \"\"\"#\"\"\"\n  wicked1 = \"\\\"\"\n  wicked2 = \"\"\"\\\"\"\"\"\n\n[[inputs.cpu]]\n  percpu = true\n\n\n\n\n[[a.plugin]]\n  mylist = [\n\t\"value 1\",\n        \"value 2\",\n\t\"value 3\", \"value 4\",\n  'value5', \"\"\"tagwith#value\"\"\",\n  ]\n\n[[some.stuff]]\n  a = 'not a #comment'\n  b = '''not a #comment'''\n  c = \"not a #comment\"\n  d = \"\"\"not a #comment\"\"\"\n  e = '''not a #comment containing \"quotes\"'''\n  f = '''not a #comment containing 'quotes'?'''\n  g = \"\"\"not a #comment containing \"quotes\"?\"\"\"\n\n\n[[inputs.myplugin]]\nvalue = '''This isn't a #comment.'''\n\n[[processors.starlark]]\n  script = \"\"\"\n# Drop fields if they contain a string.\n#\n# Example Input:\n# measurement,host=hostname a=1,b=\"somestring\" 1597255410000000000\n#\n# Example Output:\n# measurement,host=hostname a=1 1597255410000000000\n\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"string\":\n            metric.fields.pop(k)\n\n    return metric\n\"\"\"\n\n[[processors.starlark]]\n  script = '''\n# Drop fields if they contain a string.\n#\n# Example Input:\n# measurement,host=hostname a=1,b=\"somestring\" 1597255410000000000\n#\n# Example Output:\n# measurement,host=hostname a=1 1597255410000000000\n\ndef apply(metric):\n    for k, v in metric.fields.items():\n        if type(v) == \"string\":\n            metric.fields.pop(k)\n\n    return metric\n'''\n"
  },
  {
    "path": "config/testdata/envvar_malicious.conf",
    "content": "[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"my.server.com\"]\n  port = 8080\n   ##### this input is provided to test multiline strings\n  command = \"\"\"\nRaw command which may or may not contain # in it\n# is unique\"\"\" # Multiline comment black starting with #\n  pidfile = \"${PIDFILE}\"\n"
  },
  {
    "path": "config/testdata/envvar_non_string.conf",
    "content": "[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"$MY_TEST_SERVER\"]\n  port = ${PORT}\n   ##### this input is provided to test multiline strings\n  command = \"\"\"\nRaw command which may or may not contain # in it\n# is unique\"\"\" # Multiline comment black starting with #\n"
  },
  {
    "path": "config/testdata/envvar_non_string_multiline.conf",
    "content": "[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"$MY_TEST_SERVER\"]\n  port = ${PORT}\n   ##### this input is provided to test multiline strings\n  command = '''\n    ${COMMAND}\n  '''\n"
  },
  {
    "path": "config/testdata/envvar_valid.conf",
    "content": "[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"$MY_TEST_SERVER\"]\n  port = 8080\n   ##### this input is provided to test multiline strings\n  command = \"\"\"\nRaw command which may or may not contain # in it\n# is unique\"\"\" # Multiline comment black starting with #\n"
  },
  {
    "path": "config/testdata/envvar_valid_multiline.conf",
    "content": "[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"$MY_TEST_SERVER\"]\n  port = 8080\n   ##### this input is provided to test multiline strings\n  command = '''\n    ${COMMAND}\n  '''\n"
  },
  {
    "path": "config/testdata/filter_metricpass.toml",
    "content": "[[processors.processor]]\n  metricpass = '(\"state\" in tags && tags.state == \"on\") || time > timestamp(\"2023-04-24T00:00:00Z\")'\n"
  },
  {
    "path": "config/testdata/inline_table.toml",
    "content": "[[outputs.http]]\n    headers = { Authorization = \"Token $TOKEN\",Content-Type = \"application/json\" }\n    taginclude = [\"org_id\"]\n\n[[outputs.http]]\n    headers = { Authorization = \"Token $TOKEN\",Content-Type = \"application/json\" }\n    taginclude = [\"org_id\"]\n"
  },
  {
    "path": "config/testdata/invalid_field.toml",
    "content": "[[inputs.http_listener_v2]]\n  not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_in_parser_table.toml",
    "content": "[[inputs.parser]]\n  data_format = \"xpath_json\"\n\n  [[inputs.parser.xpath]]\n    not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_in_parserfunc_table.toml",
    "content": "[[inputs.parser_func]]\n  data_format = \"xpath_json\"\n\n  [[inputs.parser_func.xpath]]\n    not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_processor.toml",
    "content": "[[processors.processor]]\n  not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_in_parser.toml",
    "content": "[[processors.processor_parser]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_in_parser_table.toml",
    "content": "[[processors.processor_parser]]\n  data_format = \"xpath_json\"\n\n  [[processors.processor_parser.xpath]]\n    not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_in_parserfunc.toml",
    "content": "[[processors.processor_parserfunc]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_in_parserfunc_table.toml",
    "content": "[[inputs.parser_func]]\n  data_format = \"xpath_json\"\n\n  [[inputs.parser_func.xpath]]\n    not_a_field = true\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_with_parser.toml",
    "content": "[[processors.processor_parser]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/invalid_field_processor_with_parserfunc.toml",
    "content": "[[processors.processor_parserfunc]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/invalid_field_with_parser.toml",
    "content": "[[inputs.parser]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/invalid_field_with_parserfunc.toml",
    "content": "[[inputs.parser_func]]\n  not_a_field = true\n  data_format = \"influx\"\n"
  },
  {
    "path": "config/testdata/non_slice_slice.toml",
    "content": "[[outputs.http]]\n  [outputs.http.headers]\n    Content-Type = \"application/json\"\n  taginclude = [\"org_id\"]\n"
  },
  {
    "path": "config/testdata/parsers_new.toml",
    "content": "[[inputs.parser_test_new]]\n  data_format = \"collectd\"\n\n[[inputs.parser_test_new]]\n  data_format = \"csv\"\n  csv_header_row_count = 42\n\n[[inputs.parser_test_new]]\n  data_format = \"dropwizard\"\n\n[[inputs.parser_test_new]]\n  data_format = \"form_urlencoded\"\n\n[[inputs.parser_test_new]]\n  data_format = \"graphite\"\n\n[[inputs.parser_test_new]]\n  data_format = \"grok\"\n  grok_patterns = [\"%{COMBINED_LOG_FORMAT}\"]\n\n[[inputs.parser_test_new]]\n  data_format = \"influx\"\n\n[[inputs.parser_test_new]]\n  data_format = \"json\"\n\n[[inputs.parser_test_new]]\n  data_format = \"json_v2\"\n[[inputs.parser_test_new.json_v2]]\n[[inputs.parser_test_new.json_v2.field]]\n  path = \"\"\n  rename = \"\"\n  type = \"int\"\n\n[[inputs.parser_test_new]]\n  data_format = \"logfmt\"\n\n[[inputs.parser_test_new]]\n  data_format = \"nagios\"\n\n[[inputs.parser_test_new]]\n  data_format = \"prometheus\"\n\n[[inputs.parser_test_new]]\n  data_format = \"prometheusremotewrite\"\n\n[[inputs.parser_test_new]]\n  data_format = \"value\"\n\n[[inputs.parser_test_new]]\n  data_format = \"wavefront\"\n\n[[inputs.parser_test_new]]\n  data_format = \"xml\"\n\n[[inputs.parser_test_new]]\n  data_format = \"xpath_json\"\n\n[[inputs.parser_test_new]]\n  data_format = \"xpath_msgpack\"\n\n[[inputs.parser_test_new]]\n  data_format = \"xpath_protobuf\"\n  xpath_protobuf_file = \"testdata/addressbook.proto\"\n  xpath_protobuf_type = \"addressbook.AddressBook\"\n"
  },
  {
    "path": "config/testdata/processor_order/multiple_processors.toml",
    "content": "[[processors.processor]]\n\n[[processors.parser_test]]\n\n[[processors.processor_parser]]\n\n[[processors.processor_parserfunc]]\n"
  },
  {
    "path": "config/testdata/processor_order/multiple_processors_messy_order.toml",
    "content": "[[processors.parser_test]]\n\n[[processors.processor_parser]]\n    order = 2\n\n[[processors.processor_parserfunc]]\n\n[[processors.processor]]\n    order = 1\n\n[[processors.processor_parser]]\n    order = 3\n\n[[processors.processor_parserfunc]]\n    order = 3\n\n"
  },
  {
    "path": "config/testdata/processor_order/multiple_processors_simple_order.toml",
    "content": "[[processors.parser_test]]\n\n[[processors.processor_parser]]\n\n[[processors.processor_parserfunc]]\n\n[[processors.processor]]\n    order = 1\n\n"
  },
  {
    "path": "config/testdata/processors_with_parsers.toml",
    "content": "[[processors.parser_test]]\n  data_format = \"collectd\"\n\n[[processors.parser_test]]\n  data_format = \"csv\"\n  csv_header_row_count = 42\n\n[[processors.parser_test]]\n  data_format = \"dropwizard\"\n\n[[processors.parser_test]]\n  data_format = \"form_urlencoded\"\n\n[[processors.parser_test]]\n  data_format = \"graphite\"\n\n[[processors.parser_test]]\n  data_format = \"grok\"\n  grok_patterns = [\"%{COMBINED_LOG_FORMAT}\"]\n\n[[processors.parser_test]]\n  data_format = \"influx\"\n\n[[processors.parser_test]]\n  data_format = \"json\"\n\n[[processors.parser_test]]\n  data_format = \"json_v2\"\n[[processors.parser_test.json_v2]]\n[[processors.parser_test.json_v2.field]]\n  path = \"\"\n  rename = \"\"\n  type = \"int\"\n\n[[processors.parser_test]]\n  data_format = \"logfmt\"\n\n[[processors.parser_test]]\n  data_format = \"nagios\"\n\n[[processors.parser_test]]\n  data_format = \"prometheus\"\n\n[[processors.parser_test]]\n  data_format = \"prometheusremotewrite\"\n\n[[processors.parser_test]]\n  data_format = \"value\"\n\n[[processors.parser_test]]\n  data_format = \"wavefront\"\n\n[[processors.parser_test]]\n  data_format = \"xml\"\n\n[[processors.parser_test]]\n  data_format = \"xpath_json\"\n\n[[processors.parser_test]]\n  data_format = \"xpath_msgpack\"\n\n[[processors.parser_test]]\n  data_format = \"xpath_protobuf\"\n  xpath_protobuf_file = \"testdata/addressbook.proto\"\n  xpath_protobuf_type = \"addressbook.AddressBook\"\n"
  },
  {
    "path": "config/testdata/serializers_new.toml",
    "content": "[[outputs.serializer_test_new]]\n  data_format = \"carbon2\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"csv\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"graphite\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"influx\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"json\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"msgpack\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"nowmetric\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"prometheus\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"prometheusremotewrite\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"splunkmetric\"\n\n[[outputs.serializer_test_new]]\n  data_format = \"wavefront\"\n"
  },
  {
    "path": "config/testdata/serializers_old.toml",
    "content": "[[outputs.serializer_test_old]]\n  data_format = \"carbon2\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"csv\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"graphite\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"influx\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"json\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"msgpack\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"nowmetric\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"prometheus\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"prometheusremotewrite\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"splunkmetric\"\n\n[[outputs.serializer_test_old]]\n  data_format = \"wavefront\"\n"
  },
  {
    "path": "config/testdata/single_plugin.toml",
    "content": "[[inputs.memcached]]\n  servers = [\"localhost\"]\n  namepass = [\"metricname1\"]\n  namedrop = [\"metricname2\"]\n  fieldinclude = [\"some\", \"strings\"]\n  fieldexclude = [\"other\", \"stuff\"]\n  interval = \"5s\"\n  [inputs.memcached.tagpass]\n    goodtag = [\"mytag\"]\n  [inputs.memcached.tagdrop]\n    badtag = [\"othertag\"]\n"
  },
  {
    "path": "config/testdata/single_plugin_env_vars.toml",
    "content": "# Telegraf Configuration\n#\n# Telegraf is entirely plugin driven. All metrics are gathered from the\n# declared inputs, and sent to the declared outputs.\n#\n# Plugins must be declared in here to be active.\n# To deactivate a plugin, comment out the name and any variables.\n#\n# Use 'telegraf -config telegraf.conf -test' to see what metrics a config\n# file would generate.\n#\n# Environment variables can be used anywhere in this config file, simply surround\n# them with ${}. For strings the variable must be within quotes (ie, \"${STR_VAR}\"),\n# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})\n\n[[inputs.memcached]]\n  # this comment line will be ignored by the parser\n  servers = [\"$MY_TEST_SERVER\"]\n  namepass = [\"metricname1\", \"ip_${MY_TEST_SERVER}_name\"] # this comment will be ignored as well\n  namedrop = [\"metricname2\"]\n  fieldinclude = [\"some\", \"strings\"]\n  fieldexclude = [\"other\", \"stuff\"]\n  interval = \"$TEST_INTERVAL\"\n   ##### this input is provided to test multiline strings\n  command = \"\"\"\nRaw command which may or may not contain # in it\n# is unique\"\"\" # Multiline comment black starting with #\n  [inputs.memcached.tagpass]\n    goodtag = [\"mytag\", \"\"\"tagwith#value\"\"\",\n      # comment in between array items\n      # should ignore \"quotes\" in comments\n      '''TagWithMultilineSyntax''', ## ignore this comment\n    ] # hastag\n  [inputs.memcached.tagdrop]\n    badtag = [\"othertag\"]\n"
  },
  {
    "path": "config/testdata/single_plugin_with_comment_in_array.toml",
    "content": "[[inputs.memcached]]\n  servers = [\n    # A comment in the array\n    \"localhost\"\n  ]\n"
  },
  {
    "path": "config/testdata/single_plugin_with_separators.toml",
    "content": "[[inputs.memcached]]\n  servers = [\"localhost\"]\n  namepass = [\"metricname1\"]\n  namepass_separator = \".\"\n  namedrop = [\"metricname2\"]\n  namedrop_separator = \".\"\n  fieldinclude = [\"some\", \"strings\"]\n  fieldexclude = [\"other\", \"stuff\"]\n  interval = \"5s\"\n  [inputs.memcached.tagpass]\n    goodtag = [\"mytag\"]\n  [inputs.memcached.tagdrop]\n    badtag = [\"othertag\"]\n"
  },
  {
    "path": "config/testdata/slice_comment.toml",
    "content": "[[outputs.http]]\n  scopes = [\n    # comment\n    \"test\" # comment\n  ]\n"
  },
  {
    "path": "config/testdata/special_types.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIFYI4Hm+jRW3OC3zvoWDaCig6E7X0Ql9l8elHPU3e5+toAoGCCqGSM49\nAwEHoUQDQgAEGOw1XQ84Ai3GTZJ5o5u1yTFgA3VLZTTT0oHol06LRj5Md3oRy0MQ\nQO5OhsAGGz16SYcPHf77aZmf2Of6ixYaLQ==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "config/testdata/special_types.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBjTCCATOgAwIBAgIRALJ1hlgDYCh5dWfr6tdrBEYwCgYIKoZIzj0EAwIwFDES\nMBAGA1UEAxMJbG9jYWxob3N0MB4XDTIyMDExMjA3NTgyMloXDTIyMDExMzA3NTgy\nMlowFDESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\nQgAEGOw1XQ84Ai3GTZJ5o5u1yTFgA3VLZTTT0oHol06LRj5Md3oRy0MQQO5OhsAG\nGz16SYcPHf77aZmf2Of6ixYaLaNmMGQwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQW\nMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUuKpGXAb1DaVSffJ/xuF6\nFE31CC8wFAYDVR0RBA0wC4IJbG9jYWxob3N0MAoGCCqGSM49BAMCA0gAMEUCIHCb\nm2phe189gftRke2Mo45lDsEAGaXsjA4lO/IOMo5lAiEA5k2X0bQfFhSfAcZPFtDI\niUwvC9SD3+CnzkP35O0jo+c=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "config/testdata/special_types.toml",
    "content": "[[inputs.http_listener_v2]]\n  write_timeout = \"1s\"\n  max_body_size = \"1MiB\"\n  paths = [ \"\"\"\n/path/\n\"\"\" ]\n  tls_cert = \"\"\"./testdata/special_types.pem\"\"\"\n  tls_key = '''./testdata/special_types.key'''\n"
  },
  {
    "path": "config/testdata/state_persistence_input_all_different.toml",
    "content": "[[inputs.statetest]]\n\n[[inputs.statetest]]\n  servers = [\"myserver.com\", \"myserver.org\"]\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 0\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n"
  },
  {
    "path": "config/testdata/state_persistence_input_all_same.toml",
    "content": "[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n\n[[inputs.statetest]]\n  ## What a wonderful world...\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  port = 80\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n\n[[inputs.statetest]]\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  method = \"strange\"\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    b = \"bar\"\n    a = \"foo\"\n\n[[inputs.statetest]]\n  method = \"strange\"\n  servers = [\"myserver.org\", \"myserver.com\"]\n  port = 80\n  setup = [\n    {name=\"alpha\", factor=3.1415, enabled=true, bits=[1,2,3]},\n    {name=\"beta\", factor=2.71828, enabled=true, bits=[1,2,3]}\n  ]\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n"
  },
  {
    "path": "config/testdata/state_persistence_input_store_load.toml",
    "content": "[[inputs.statetest]]\n  servers = [\"myserverA.org\"]\n  port = 42\n  method = \"strange\"\n\n[[inputs.statetest]]\n  servers = [\"myserverB.org\"]\n  port = 23\n  method = \"strange\"\n\n[[inputs.statetest]]\n  servers = [\"myserverC.org\"]\n  port = 80\n  method = \"strange\"\n  [inputs.statetest.params]\n    a = \"foo\"\n    b = \"bar\"\n"
  },
  {
    "path": "config/testdata/state_persistence_processors.toml",
    "content": "[[processors.statetest]]\n  option = \"foo\"\n\n[[processors.statetest]]\n  option = \"bar\"\n\n[[processors.statetest]]\n  option = \"captain obvious\"\n"
  },
  {
    "path": "config/testdata/subconfig/exec.conf",
    "content": "[[inputs.exec]]\n  # the command to run\n  command = \"/usr/bin/myothercollector --foo=bar\"\n  name_suffix = \"_myothercollector\"\n"
  },
  {
    "path": "config/testdata/subconfig/memcached.conf",
    "content": "[[inputs.memcached]]\n  servers = [\"192.168.1.1\"]\n  namepass = [\"metricname1\"]\n  namedrop = [\"metricname2\"]\n  pass = [\"some\", \"strings\"]\n  drop = [\"other\", \"stuff\"]\n  interval = \"5s\"\n  [inputs.memcached.tagpass]\n    goodtag = [\"mytag\"]\n  [inputs.memcached.tagdrop]\n    badtag = [\"othertag\"]\n"
  },
  {
    "path": "config/testdata/subconfig/procstat.conf",
    "content": "[[inputs.procstat]]\n  pid_file = \"/var/run/grafana-server.pid\"\n"
  },
  {
    "path": "config/testdata/telegraf-agent.toml",
    "content": "# Telegraf configuration\n\n# Telegraf is entirely plugin driven. All metrics are gathered from the\n# declared inputs.\n\n# Even if a plugin has no configuration, it must be declared in here\n# to be active. Declaring a plugin means just specifying the name\n# as a section with no variables. To deactivate a plugin, comment\n# out the name and any variables.\n\n# Use 'telegraf -config telegraf.toml -test' to see what metrics a config\n# file would generate.\n\n# One rule that plugins conform to is wherever a connection string\n# can be passed, the values '' and 'localhost' are treated specially.\n# They indicate to the plugin to use their own builtin configuration to\n# connect to the local system.\n\n# NOTE: The configuration has a few required parameters. They are marked\n# with 'required'. Be sure to edit those to make this configuration work.\n\n# Tags can also be specified via a normal map, but only one form at a time:\n[global_tags]\n  dc = \"us-east-1\"\n\n# Configuration for telegraf agent\n[agent]\n  # Default data collection interval for all plugins\n  interval = \"10s\"\n\n  # run telegraf in debug mode\n  debug = false\n\n  # Override default hostname, if empty use os.Hostname()\n  hostname = \"\"\n\n\n###############################################################################\n#                                  OUTPUTS                                    #\n###############################################################################\n\n# Configuration for influxdb server to send metrics to\n[[outputs.influxdb]]\n  # The full HTTP endpoint URL for your InfluxDB instance\n  # Multiple urls can be specified for InfluxDB cluster support. Server to\n  # write to will be randomly chosen each interval.\n  urls = [\"http://localhost:8086\"] # required.\n\n  # The target database for metrics. This database must already exist\n  database = \"telegraf\" # required.\n\n[[outputs.influxdb]]\n  urls = [\"udp://localhost:8089\"]\n  database = \"udp-telegraf\"\n\n# Configuration for the Kafka server to send metrics to\n[[outputs.kafka]]\n  # URLs of kafka brokers\n  brokers = [\"localhost:9092\"]\n  # Kafka topic for producer messages\n  topic = \"telegraf\"\n  # Telegraf tag to use as a routing key\n  #  ie, if this tag exists, its value will be used as the routing key\n  routing_tag = \"host\"\n\n\n###############################################################################\n#                                  PLUGINS                                    #\n###############################################################################\n\n# Read Apache status information (mod_status)\n[[inputs.apache]]\n  # An array of Apache status URI to gather stats.\n  urls = [\"http://localhost/server-status?auto\"]\n\n# Read metrics about cpu usage\n[[inputs.cpu]]\n  # Whether to report per-cpu stats or not\n  percpu = true\n  # Whether to report total system cpu stats or not\n  totalcpu = true\n  # Comment this line if you want the raw CPU time metrics\n  fieldexclude = [\"cpu_time\"]\n\n# Read metrics about disk usage by mount point\n[[inputs.diskio]]\n  # no configuration\n\n# Read metrics from one or many disque servers\n[[inputs.disque]]\n  # An array of URI to gather stats about. Specify an ip or hostname\n  # with optional port and password. ie disque://localhost, disque://10.10.3.33:18832,\n  # 10.0.0.1:10000, etc.\n  #\n  # If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n\n# Read stats from one or more Elasticsearch servers or clusters\n[[inputs.elasticsearch]]\n  # specify a list of one or more Elasticsearch servers\n  servers = [\"http://localhost:9200\"]\n\n  # set local to false when you want to read the indices stats from all nodes\n  # within the cluster\n  local = true\n\n# Read flattened metrics from one or more commands that output JSON to stdout\n[[inputs.exec]]\n  # the command to run\n  command = \"/usr/bin/mycollector --foo=bar\"\n  name_suffix = \"_mycollector\"\n\n# Read metrics of haproxy, via socket or csv stats page\n[[inputs.haproxy]]\n  # An array of address to gather stats about. Specify an ip on hostname\n  # with optional port. ie localhost, 10.10.3.33:1936, etc.\n  #\n  # If no servers are specified, then default to 127.0.0.1:1936\n  servers = [\"http://myhaproxy.com:1936\", \"http://anotherhaproxy.com:1936\"]\n  # Or you can also use local socket(not work yet)\n  # servers = [\"socket:/run/haproxy/admin.sock\"]\n\n# Read flattened metrics from one or more JSON HTTP endpoints\n[[inputs.http]]\n  # a name for the service being polled\n  name_override = \"webserver_stats\"\n\n  # URL of each server in the service's cluster\n  urls = [\n    \"http://localhost:9999/stats/\",\n    \"http://localhost:9998/stats/\",\n  ]\n\n  # HTTP method to use (case-sensitive)\n  # method = \"GET\"\n\n  data_format = \"json\"\n\n# Read metrics about disk IO by device\n[[inputs.diskio]]\n  # no configuration\n\n# read metrics from a Kafka 0.9+ topic\n[[inputs.kafka_consumer]]\n  ## kafka brokers\n  brokers = [\"localhost:9092\"]\n  ## topic(s) to consume\n  topics = [\"telegraf\"]\n  ## the name of the consumer group\n  consumer_group = \"telegraf_metrics_consumers\"\n  ## Offset (must be either \"oldest\" or \"newest\")\n  offset = \"oldest\"\n\n# Read metrics from a LeoFS Server via SNMP\n[[inputs.leofs]]\n  # An array of URI to gather stats about LeoFS.\n  # Specify an ip or hostname with port. ie 127.0.0.1:4020\n  #\n  # If no servers are specified, then 127.0.0.1 is used as the host and 4020 as the port.\n  servers = [\"127.0.0.1:4021\"]\n\n# Read metrics about memory usage\n[[inputs.mem]]\n  # no configuration\n\n# Read metrics from one or many memcached servers\n[[inputs.memcached]]\n  # An array of address to gather stats about. Specify an ip on hostname\n  # with optional port. ie localhost, 10.0.0.1:11211, etc.\n  #\n  # If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n\n# Telegraf plugin for gathering metrics from N Mesos masters\n[[inputs.mesos]]\n  # Timeout, in ms.\n  timeout = 100\n  # A list of Mesos masters, default value is localhost:5050.\n  masters = [\"localhost:5050\"]\n  # Metrics groups to be collected, by default, all enabled.\n  master_collections = [\"resources\",\"master\",\"system\",\"slaves\",\"frameworks\",\"messages\",\"evqueue\",\"registrar\"]\n\n# Read metrics from one or many MongoDB servers\n[[inputs.mongodb]]\n  # An array of URI to gather stats about. Specify an ip or hostname\n  # with optional port add password. ie mongodb://user:auth_key@10.10.3.30:27017,\n  # mongodb://10.10.3.33:18832, 10.0.0.1:10000, etc.\n  #\n  # If no servers are specified, then 127.0.0.1 is used as the host and 27107 as the port.\n  servers = [\"127.0.0.1:27017\"]\n\n# Read metrics from one or many mysql servers\n[[inputs.mysql]]\n  # specify servers via a url matching:\n  #  [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]]\n  #  e.g.\n  #    servers = [\"root:root@http://10.0.0.18/?tls=false\"]\n  #    servers = [\"root:passwd@tcp(127.0.0.1:3306)/\"]\n  #\n  # If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n\n# Read metrics about network interface usage\n[[inputs.net]]\n  # By default, telegraf gathers stats from any up interface (excluding loopback)\n  # Setting interfaces will tell it to gather these explicit interfaces,\n  # regardless of status.\n  #\n  # interfaces = [\"eth0\", ... ]\n\n# Read Nginx's basic status information (ngx_http_stub_status_module)\n[[inputs.nginx]]\n  # An array of Nginx stub_status URI to gather stats.\n  urls = [\"http://localhost/status\"]\n\n# Ping given url(s) and return statistics\n[[inputs.ping]]\n  # urls to ping\n  urls = [\"www.google.com\"] # required\n  # number of pings to send (ping -c <COUNT>)\n  count = 1 # required\n  # interval, in s, at which to ping. 0 == default (ping -i <PING_INTERVAL>)\n  ping_interval = 0.0\n  # ping timeout, in s. 0 == no timeout (ping -t <TIMEOUT>)\n  timeout = 0.0\n  # interface to send ping from (ping -I <INTERFACE>)\n  interface = \"\"\n\n# Read metrics from one or many postgresql servers\n[[inputs.postgresql]]\n  # specify address via a url matching:\n  #   postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full]\n  # or a simple string:\n  #   host=localhost user=pqgotest password=... sslmode=... dbname=app_production\n  #\n  # All connection parameters are optional. By default, the host is localhost\n  # and the user is the currently running user. For localhost, we default\n  # to sslmode=disable as well.\n  #\n  # Without the dbname parameter, the driver will default to a database\n  # with the same name as the user. This dbname is just for instantiating a\n  # connection with the server and doesn't restrict the databases we are trying\n  # to grab metrics for.\n  #\n\n  address = \"sslmode=disable\"\n\n  # A list of databases to pull metrics about. If not specified, metrics for all\n  # databases are gathered.\n\n  # databases = [\"app_production\", \"blah_testing\"]\n\n  # [[postgresql.servers]]\n  # address = \"influx@remoteserver\"\n\n# Read metrics from one or many prometheus clients\n[[inputs.prometheus]]\n  # An array of urls to scrape metrics from.\n  urls = [\"http://localhost:9100/metrics\"]\n\n# Read metrics from one or many RabbitMQ servers via the management API\n[[inputs.rabbitmq]]\n  # Specify servers via an array of tables\n  # name = \"rmq-server-1\" # optional tag\n  # url = \"http://localhost:15672\"\n  # username = \"guest\"\n  # password = \"guest\"\n\n  # A list of nodes to pull metrics about. If not specified, metrics for\n  # all nodes are gathered.\n  # nodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\n# Read metrics from one or many redis servers\n[[inputs.redis]]\n  # An array of URI to gather stats about. Specify an ip or hostname\n  # with optional port add password. ie redis://localhost, redis://10.10.3.33:18832,\n  # 10.0.0.1:10000, etc.\n  #\n  # If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n\n# Read metrics from one or many RethinkDB servers\n[[inputs.rethinkdb]]\n  # An array of URI to gather stats about. Specify an ip or hostname\n  # with optional port add password. ie rethinkdb://user:auth_key@10.10.3.30:28105,\n  # rethinkdb://10.10.3.33:18832, 10.0.0.1:10000, etc.\n  #\n  # If no servers are specified, then 127.0.0.1 is used as the host and 28015 as the port.\n  servers = [\"127.0.0.1:28015\"]\n\n# Read metrics about swap memory usage\n[[inputs.swap]]\n  # no configuration\n\n# Read metrics about system load & uptime\n[[inputs.system]]\n  # no configuration\n"
  },
  {
    "path": "config/testdata/wrong_cert_path.toml",
    "content": "[[inputs.http_listener_v2]]\n  write_timeout = \"1s\"\n  max_body_size = \"1MiB\"\n  tls_cert = \"invalid.pem\"\n  tls_key = \"invalid.key\"\n"
  },
  {
    "path": "config/testdata/wrong_field_type.toml",
    "content": "[[inputs.http_listener_v2]]\n  port = \"80\"\n"
  },
  {
    "path": "config/testdata/wrong_field_type2.toml",
    "content": "[[inputs.http_listener_v2]]\n  methods = \"POST\"\n"
  },
  {
    "path": "config/types.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/alecthomas/units\"\n)\n\n// Regexp for day specifications in durations\nvar durationDayRe = regexp.MustCompile(`(\\d+(?:\\.\\d+)?)d`)\n\n// Duration is a time.Duration\ntype Duration time.Duration\n\n// Size is an int64\ntype Size int64\n\n// UnmarshalText parses the duration from the Text config file\nfunc (d *Duration) UnmarshalText(b []byte) error {\n\t// convert to string\n\tdurStr := string(b)\n\n\t// Value is a TOML number (e.g. 3, 10, 3.5)\n\t// First try parsing as integer seconds\n\tsI, err := strconv.ParseInt(durStr, 10, 64)\n\tif err == nil {\n\t\tdur := time.Second * time.Duration(sI)\n\t\t*d = Duration(dur)\n\t\treturn nil\n\t}\n\t// Second try parsing as float seconds\n\tsF, err := strconv.ParseFloat(durStr, 64)\n\tif err == nil {\n\t\tdur := float64(time.Second) * sF\n\t\t*d = Duration(dur)\n\t\treturn nil\n\t}\n\n\t// Finally, try value is a TOML string (e.g. \"3s\", 3s) or literal (e.g. '3s')\n\tif durStr == \"\" {\n\t\t*d = Duration(0)\n\t\treturn nil\n\t}\n\n\t// Handle \"day\" intervals and replace them with the \"hours\" equivalent\n\tfor _, m := range durationDayRe.FindAllStringSubmatch(durStr, -1) {\n\t\tdays, err := strconv.ParseFloat(m[1], 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting %q to hours failed: %w\", durStr, err)\n\t\t}\n\t\thours := strconv.FormatFloat(days*24, 'f', -1, 64) + \"h\"\n\t\tdurStr = strings.Replace(durStr, m[0], hours, 1)\n\t}\n\n\tdur, err := time.ParseDuration(durStr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*d = Duration(dur)\n\treturn nil\n}\n\nfunc (s *Size) UnmarshalText(b []byte) error {\n\tif len(b) == 0 {\n\t\treturn nil\n\t}\n\n\tstr := string(b)\n\tval, err := strconv.ParseInt(str, 10, 64)\n\tif err == nil {\n\t\t*s = Size(val)\n\t\treturn nil\n\t}\n\tval, err = units.ParseStrictBytes(str)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*s = Size(val)\n\treturn nil\n}\n"
  },
  {
    "path": "config/types_test.go",
    "content": "package config_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/processors/reverse_dns\"\n)\n\nfunc TestConfigDuration(t *testing.T) {\n\tc := config.NewConfig()\n\terr := c.LoadConfigData([]byte(`\n[[processors.reverse_dns]]\n  cache_ttl = \"3h\"\n  lookup_timeout = \"17s\"\n  max_parallel_lookups = 13\n  ordered = true\n  [[processors.reverse_dns.lookup]]\n    field = \"source_ip\"\n    dest = \"source_name\"\n`), config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Processors, 1)\n\tp := c.Processors[0].Processor.(*reverse_dns.ReverseDNS)\n\trequire.EqualValues(t, 3*time.Hour, p.CacheTTL)\n\trequire.EqualValues(t, 17*time.Second, p.LookupTimeout)\n\trequire.Equal(t, 13, p.MaxParallelLookups)\n\trequire.True(t, p.Ordered)\n}\n\nfunc TestDuration(t *testing.T) {\n\tvar d config.Duration\n\n\td = config.Duration(0)\n\trequire.NoError(t, d.UnmarshalText([]byte(`1s`)))\n\trequire.Equal(t, time.Second, time.Duration(d))\n\n\td = config.Duration(0)\n\trequire.NoError(t, d.UnmarshalText([]byte(`10`)))\n\trequire.Equal(t, 10*time.Second, time.Duration(d))\n\n\td = config.Duration(0)\n\trequire.NoError(t, d.UnmarshalText([]byte(`1.5`)))\n\trequire.Equal(t, 1500*time.Millisecond, time.Duration(d))\n\n\td = config.Duration(0)\n\trequire.NoError(t, d.UnmarshalText([]byte(``)))\n\trequire.Equal(t, 0*time.Second, time.Duration(d))\n\n\trequire.Error(t, d.UnmarshalText([]byte(`\"1\"`)))  // string missing unit\n\trequire.Error(t, d.UnmarshalText([]byte(`'2'`)))  // string missing unit\n\trequire.Error(t, d.UnmarshalText([]byte(`'ns'`))) // string missing time\n\trequire.Error(t, d.UnmarshalText([]byte(`'us'`))) // string missing time\n}\n\nfunc TestSize(t *testing.T) {\n\tvar s config.Size\n\n\trequire.NoError(t, s.UnmarshalText([]byte(`1B`)))\n\trequire.Equal(t, int64(1), int64(s))\n\n\ts = config.Size(0)\n\trequire.NoError(t, s.UnmarshalText([]byte(`1`)))\n\trequire.Equal(t, int64(1), int64(s))\n\n\ts = config.Size(0)\n\trequire.NoError(t, s.UnmarshalText([]byte(`1GB`)))\n\trequire.Equal(t, int64(1000*1000*1000), int64(s))\n\n\ts = config.Size(0)\n\trequire.NoError(t, s.UnmarshalText([]byte(`12GiB`)))\n\trequire.Equal(t, int64(12*1024*1024*1024), int64(s))\n}\n\nfunc TestTOMLParsingStringDurations(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.typesmockup]]\n\tdurations = [\n\t\t\"1s\",\n\t\t'''1s''',\n\t\t'1s',\n\t\t\"1.5s\",\n\t\t\"\",\n\t\t'',\n\t\t\"2h\",\n\t\t\"42m\",\n\t\t\"100ms\",\n\t\t\"100us\",\n\t\t\"100ns\",\n\t\t\"1d\",\n\t\t\"7.5d\",\n\t\t\"7d8h15m\",\n\t\t\"3d7d\",\n\t\t\"15m8h3.5d\"\n\t]\n`)\n\n\texpected := []time.Duration{\n\t\t1 * time.Second,\n\t\t1 * time.Second,\n\t\t1 * time.Second,\n\t\t1500 * time.Millisecond,\n\t\t0,\n\t\t0,\n\t\t2 * time.Hour,\n\t\t42 * time.Minute,\n\t\t100 * time.Millisecond,\n\t\t100 * time.Microsecond,\n\t\t100 * time.Nanosecond,\n\t\t24 * time.Hour,\n\t\t7*24*time.Hour + 12*time.Hour,\n\t\t7*24*time.Hour + 8*time.Hour + 15*time.Minute,\n\t\t10 * 24 * time.Hour,\n\t\t3*24*time.Hour + 12*time.Hour + 8*time.Hour + 15*time.Minute,\n\t}\n\n\t// Load the data\n\tc := config.NewConfig()\n\terr := c.LoadConfigData(cfg, config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\tplugin := c.Inputs[0].Input.(*MockupTypesPlugin)\n\n\trequire.Empty(t, plugin.Sizes)\n\trequire.Len(t, plugin.Durations, len(expected))\n\tfor i, actual := range plugin.Durations {\n\t\trequire.EqualValuesf(t, expected[i], actual, \"case %d failed\", i)\n\t}\n}\n\nfunc TestTOMLParsingIntegerDurations(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.typesmockup]]\n\tdurations = [\n\t\t1,\n\t\t10,\n\t\t3601\n\t]\n`)\n\n\texpected := []time.Duration{\n\t\t1 * time.Second,\n\t\t10 * time.Second,\n\t\t3601 * time.Second,\n\t}\n\n\t// Load the data\n\tc := config.NewConfig()\n\terr := c.LoadConfigData(cfg, config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\tplugin := c.Inputs[0].Input.(*MockupTypesPlugin)\n\n\trequire.Empty(t, plugin.Sizes)\n\trequire.Len(t, plugin.Durations, len(expected))\n\tfor i, actual := range plugin.Durations {\n\t\trequire.EqualValuesf(t, expected[i], actual, \"case %d failed\", i)\n\t}\n}\n\nfunc TestTOMLParsingFloatDurations(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.typesmockup]]\n\tdurations = [\n\t\t42.0,\n\t\t1.5\n\t]\n`)\n\n\texpected := []time.Duration{\n\t\t42 * time.Second,\n\t\t1500 * time.Millisecond,\n\t}\n\n\t// Load the data\n\tc := config.NewConfig()\n\terr := c.LoadConfigData(cfg, config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\tplugin := c.Inputs[0].Input.(*MockupTypesPlugin)\n\n\trequire.Empty(t, plugin.Sizes)\n\trequire.Len(t, plugin.Durations, len(expected))\n\tfor i, actual := range plugin.Durations {\n\t\trequire.EqualValuesf(t, expected[i], actual, \"case %d failed\", i)\n\t}\n}\n\nfunc TestTOMLParsingStringSizes(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.typesmockup]]\n\tsizes = [\n\t\t\"1B\",\n\t\t\"1\",\n\t\t'1',\n\t\t'''15kB''',\n\t\t\"\"\"15KiB\"\"\",\n\t\t\"1GB\",\n\t\t\"12GiB\"\n\t]\n`)\n\n\texpected := []int64{\n\t\t1,\n\t\t1,\n\t\t1,\n\t\t15 * 1000,\n\t\t15 * 1024,\n\t\t1000 * 1000 * 1000,\n\t\t12 * 1024 * 1024 * 1024,\n\t}\n\n\t// Load the data\n\tc := config.NewConfig()\n\terr := c.LoadConfigData(cfg, config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\tplugin := c.Inputs[0].Input.(*MockupTypesPlugin)\n\n\trequire.Empty(t, plugin.Durations)\n\trequire.Len(t, plugin.Sizes, len(expected))\n\tfor i, actual := range plugin.Sizes {\n\t\trequire.EqualValuesf(t, expected[i], actual, \"case %d failed\", i)\n\t}\n}\n\nfunc TestTOMLParsingIntegerSizes(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.typesmockup]]\n\tsizes = [\n\t\t0,\n\t\t1,\n\t\t1000,\n\t\t1024\n\t]\n`)\n\n\texpected := []int64{\n\t\t0,\n\t\t1,\n\t\t1000,\n\t\t1024,\n\t}\n\n\t// Load the data\n\tc := config.NewConfig()\n\terr := c.LoadConfigData(cfg, config.EmptySourcePath)\n\trequire.NoError(t, err)\n\trequire.Len(t, c.Inputs, 1)\n\tplugin := c.Inputs[0].Input.(*MockupTypesPlugin)\n\n\trequire.Empty(t, plugin.Durations)\n\trequire.Len(t, plugin.Sizes, len(expected))\n\tfor i, actual := range plugin.Sizes {\n\t\trequire.EqualValuesf(t, expected[i], actual, \"case %d failed\", i)\n\t}\n}\n\n// Mockup (input) plugin for testing to avoid cyclic dependencies\ntype MockupTypesPlugin struct {\n\tDurations []config.Duration `toml:\"durations\"`\n\tSizes     []config.Size     `toml:\"sizes\"`\n}\n\nfunc (*MockupTypesPlugin) SampleConfig() string                { return \"Mockup test types plugin\" }\nfunc (*MockupTypesPlugin) Gather(_ telegraf.Accumulator) error { return nil }\n\n// Register the mockup plugin on loading\nfunc init() {\n\t// Register the mockup input plugin for the required names\n\tinputs.Add(\"typesmockup\", func() telegraf.Input { return &MockupTypesPlugin{} })\n}\n"
  },
  {
    "path": "docs/AGGREGATORS.md",
    "content": "# Aggregator Plugins\n\nThis section is for developers who want to create a new aggregator plugin.\n\n## Aggregator Plugin Guidelines\n\n* A aggregator must conform to the [telegraf.Aggregator][] interface.\n* Aggregators should call `aggregators.Add` in their `init` function to\n  register themselves.  See below for a quick example.\n* To be available within Telegraf itself, plugins must register themselves\n  using a file in `github.com/influxdata/telegraf/plugins/aggregators/all`\n  named according to the plugin name. Make sure you also add build-tags to\n  conditionally build the plugin.\n* Each plugin requires a file called `sample.conf` containing the sample\n  configuration for the plugin in TOML format. Please consult the\n  [Sample Config][] page for the latest style guidelines.\n* Each plugin `README.md` file should include the `sample.conf` file in a\n  section describing the configuration by specifying a `toml` section in the\n  form `toml @sample.conf`. The specified file(s) are then injected\n  automatically into the Readme.\n* The Aggregator plugin will need to keep caches of metrics that have passed\n  through it. This should be done using the builtin `HashID()` function of\n  each metric.\n* When the `Reset()` function is called, all caches should be cleared.\n* Follow the recommended [Code Style][].\n\n[telegraf.Aggregator]: https://godoc.org/github.com/influxdata/telegraf#Aggregator\n[Sample Config]: /docs/developers/SAMPLE_CONFIG.md\n[Code Style]: /docs/developers/CODE_STYLE.md\n\n### Aggregator Plugin Example\n\n### Registration\n\nRegistration of the plugin on `plugins/aggregators/all/min.go`:\n\n```go\n//go:build !custom || aggregators || aggregators.min\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/min\" // register plugin\n```\n\nThe _build-tags_ in the first line allow to selectively include/exclude your\nplugin when customizing Telegraf.\n\n### Plugin\n\nContent of your plugin file e.g. `min.go`\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage min\n\n// min.go\n\nimport (\n    _ \"embed\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Min struct {\n    // caches for metric fields, names, and tags\n    fieldCache map[uint64]map[string]float64\n    nameCache  map[uint64]string\n    tagCache   map[uint64]map[string]string\n}\n\nfunc NewMin() telegraf.Aggregator {\n    m := &Min{}\n    m.Reset()\n    return m\n}\n\nfunc (*Min) SampleConfig() string {\n    return sampleConfig\n}\n\nfunc (m *Min) Init() error {\n    return nil\n}\n\nfunc (m *Min) Add(in telegraf.Metric) {\n    id := in.HashID()\n    if _, ok := m.nameCache[id]; !ok {\n        // hit an uncached metric, create caches for first time:\n        m.nameCache[id] = in.Name()\n        m.tagCache[id] = in.Tags()\n        m.fieldCache[id] = make(map[string]float64)\n        for k, v := range in.Fields() {\n            if fv, ok := convert(v); ok {\n                m.fieldCache[id][k] = fv\n            }\n        }\n    } else {\n        for k, v := range in.Fields() {\n            if fv, ok := convert(v); ok {\n                if _, ok := m.fieldCache[id][k]; !ok {\n                    // hit an uncached field of a cached metric\n                    m.fieldCache[id][k] = fv\n                    continue\n                }\n                if fv < m.fieldCache[id][k] {\n                    // set new minimum\n                    m.fieldCache[id][k] = fv\n                }\n            }\n        }\n    }\n}\n\nfunc (m *Min) Push(acc telegraf.Accumulator) {\n    for id, _ := range m.nameCache {\n        fields := map[string]interface{}{}\n        for k, v := range m.fieldCache[id] {\n            fields[k+\"_min\"] = v\n        }\n        acc.AddFields(m.nameCache[id], fields, m.tagCache[id])\n    }\n}\n\nfunc (m *Min) Reset() {\n    m.fieldCache = make(map[uint64]map[string]float64)\n    m.nameCache = make(map[uint64]string)\n    m.tagCache = make(map[uint64]map[string]string)\n}\n\nfunc convert(in interface{}) (float64, bool) {\n    switch v := in.(type) {\n    case float64:\n        return v, true\n    case int64:\n        return float64(v), true\n    default:\n        return 0, false\n    }\n}\n\nfunc init() {\n    aggregators.Add(\"min\", func() telegraf.Aggregator {\n        return NewMin()\n    })\n}\n```\n"
  },
  {
    "path": "docs/AGGREGATORS_AND_PROCESSORS.md",
    "content": "# Aggregator & Processor Plugins\n\nTelegraf has the concept of aggregator and processor plugins, which sit between\ninputs and outputs. These plugins allow a user to do additional processing or\naggregation to collected metrics.\n\n```text\n┌───────────┐\n│           │\n│    CPU    │───┐\n│           │   │\n└───────────┘   │\n                │\n┌───────────┐   │                                              ┌───────────┐\n│           │   │                                              │           │\n│  Memory   │───┤                                          ┌──▶│ InfluxDB  │\n│           │   │                                          │   │           │\n└───────────┘   │    ┌─────────────┐     ┌─────────────┐   │   └───────────┘\n                │    │             │     │Aggregators  │   │\n┌───────────┐   │    │Processors   │     │ - mean      │   │   ┌───────────┐\n│           │   │    │ - transform │     │ - quantiles │   │   │           │\n│   MySQL   │───┼───▶│ - decorate  │────▶│ - min/max   │───┼──▶│   File    │\n│           │   │    │ - filter    │     │ - count     │   │   │           │\n└───────────┘   │    │             │     │             │   │   └───────────┘\n                │    └─────────────┘     └─────────────┘   │\n┌───────────┐   │                                          │   ┌───────────┐\n│           │   │                                          │   │           │\n│   SNMP    │───┤                                          └──▶│   Kafka   │\n│           │   │                                              │           │\n└───────────┘   │                                              └───────────┘\n                │\n┌───────────┐   │\n│           │   │\n│  Docker   │───┘\n│           │\n└───────────┘\n```\n\n## Ordering\n\nProcessors are run first, then aggregators, then processors a second time.\n\nAllowing processors to run again after aggregators gives users the opportunity\nto run a processor on any aggregated metrics. This behavior can be a bit\nsurprising to new users and may cause weird behavior in metrics. For example,\nif the user scales data, it could get scaled twice!\n\nTo disable this behavior set the `skip_processors_after_aggregators` agent\nconfiguration setting to true. Another option is to use metric filtering as\ndescribed below.\n\n## Metric Filtering\n\nUse [metric filtering][] to control which metrics are passed through a processor\nor aggregator.  If a metric is filtered out the metric bypasses the plugin and\nis passed downstream to the next plugin.\n\n[metric filtering]: CONFIGURATION.md#measurement-filtering\n\n## Processor\n\nProcessor plugins process metrics as they pass through and immediately emit\nresults based on the values they process. For example, this could be printing\nall metrics or adding a tag to all metrics that pass through.\n\nSee the [processors][] for a full list of processor plugins available.\n\n[processors]: https://github.com/influxdata/telegraf/tree/master/plugins/processors\n\n## Aggregator\n\nAggregator plugins, on the other hand, are a bit more complicated. Aggregators\nare typically for emitting new _aggregate_ metrics, such as a running mean,\nminimum, maximum, or standard deviation. For this reason, all _aggregator_\nplugins are configured with a `period`. The `period` is the size of the window\nof metrics that each _aggregate_ represents. In other words, the emitted\n_aggregate_ metric will be the aggregated value of the past `period` seconds.\n\nSince many users will only care about their aggregates and not every single\nmetric gathered, there is also a `drop_original` argument, which tells Telegraf\nto only emit the aggregates and not the original metrics.\n\nSince aggregates are created for each measurement, field, and unique tag\ncombination the plugin receives, you can make use of `taginclude` to group\naggregates by specific tags only.\n\nSee the [aggregators][] for a full list of aggregator plugins available.\n\n**Note:** Aggregator plugins only aggregate metrics within their periods\n(i.e. `now() - period`). Data with a timestamp earlier than `now() - period`\ncannot be included.\n\n[aggregators]: https://github.com/influxdata/telegraf/tree/master/plugins/aggregators\n"
  },
  {
    "path": "docs/APPARMOR.md",
    "content": "# AppArmor\n\nWhen running Telegraf under AppArmor users may see denial messages depending on\nthe Telegraf plugins used and the AppArmor profile applied. Telegraf does not\nhave control over the AppArmor profiles used. If users wish to address denials,\nthen they must understand the collections made by their choice of Telegraf\nplugins, the denial messages, and the impact of changes to their AppArmor\nprofiles.\n\n## Example Denial\n\nFor example, users might see denial messages such as:\n\n```s\ntype=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\"\n```\n\nIn this case, Telegraf will also need the ability to ptrace(read). User's will\nfirst need to analyze the denial message for the operation and requested mask.\nThen consider if the required changes make sense. There may be additional\ndenials even after initial changes.\n\nFor more details around AppArmor settings and configuration, users can check out\nthe `man 5 apparmor.d` man page on their system or the [AppArmor wiki][wiki].\n\n[wiki]: https://gitlab.com/apparmor/apparmor/-/wikis/home\n"
  },
  {
    "path": "docs/COMMANDS_AND_FLAGS.md",
    "content": "# Telegraf Commands & Flags\n\nThe following page describes some of the commands and flags available via the\nTelegraf command line interface.\n\n## Usage\n\nGeneral usage of Telegraf, requires passing in at least one config file with\nthe plugins the user wishes to use:\n\n```bash\ntelegraf --config config.toml\n```\n\n## Help\n\nTo get the full list of subcommands and flags run:\n\n```bash\ntelegraf help\n```\n\nHere are some commonly used flags that users should be aware of:\n\n* `--config-directory`: Read all config files from a directory\n* `--debug`: Enable additional debug logging\n* `--once`: Run one collection and flush interval then exit\n* `--test`: Run only inputs, output to stdout, and exit\n\nCheck out the full help out for more available flags and options.\n\n## Version\n\nWhile telegraf will print out the version when running, if a user is uncertain\nwhat version their binary is, run the version subcommand:\n\n```bash\ntelegraf version\n```\n\n## Config\n\nThe config subcommand allows users to print out a sample configuration to\nstdout. This subcommand can very quickly print out the default values for all\nor any of the plugins available in Telegraf.\n\nFor example to print the example config for all plugins run:\n\n```bash\ntelegraf config > telegraf.conf\n```\n\nIf a user only wanted certain inputs or outputs, then the filters can be used:\n\n```bash\ntelegraf config --input-filter cpu --output-filter influxdb\n```\n"
  },
  {
    "path": "docs/CONFIGURATION.md",
    "content": "<!-- markdownlint-disable MD024 -->\n\n# Configuration\n\nTelegraf's configuration file is written using [TOML][] and is composed of\nthree sections: [global tags][], [agent][] settings, and [plugins][].\n\n## Generating a Configuration File\n\nA default config file can be generated by telegraf:\n\n```sh\ntelegraf config > telegraf.conf\n```\n\nTo generate a file with specific inputs and outputs, you can use the\n--input-filter and --output-filter flags:\n\n```sh\ntelegraf config --input-filter cpu:mem:net:swap --output-filter influxdb:kafka\n```\n\n[View the full list][flags] of Telegraf commands and flags or by running\n`telegraf --help`.\n\n### Windows PowerShell v5 Encoding\n\nIn PowerShell 5, the default encoding is UTF-16LE and not UTF-8. Telegraf\nexpects a valid UTF-8 file. This is not an issue with PowerShell 6 or newer,\nas well as the Command Prompt or with using the Git Bash shell.\n\nAs such, users will need to specify the output encoding when generating a full\nconfiguration file:\n\n```sh\ntelegraf.exe config | Out-File -Encoding utf8 telegraf.conf\n```\n\nThis will generate a UTF-8 encoded file with a BOM. However, Telegraf can\nhandle the leading BOM.\n\n## Configuration Loading\n\nThe location of the configuration file can be set via the `--config` command\nline flag.\n\nWhen the `--config-directory` command line flag is used files ending with\n`.conf` in the specified directory will also be included in the Telegraf\nconfiguration.\n\nOn most systems, the default locations are `/etc/telegraf/telegraf.conf` for\nthe main configuration file and `/etc/telegraf/telegraf.d` for the directory of\nconfiguration files.\n\n## Environment Variables\n\nEnvironment variables can be used anywhere in the config file, simply surround\nthem with `${}`.  Replacement occurs before file parsing. For strings\nthe variable must be within quotes, e.g., `\"${STR_VAR}\"`, for numbers and booleans\nthey should be unquoted, e.g., `${INT_VAR}`, `${BOOL_VAR}`.\n\nUsers need to keep in mind that when using double quotes the user needs to\nescape any backslashes (e.g. `\"C:\\\\Program Files\"`) or other special characters.\nIf using an environment variable with a single backslash, then enclose the\nvariable in single quotes which signifies a string literal (e.g.\n`'C:\\Program Files'`).\n\nIn addition to this, Telegraf also supports Shell parameter expansion for\nenvironment variables which allows syntax such as:\n\n- `${VARIABLE:-default}` evaluates to default if VARIABLE is unset or empty in\n                         the environment.\n- `${VARIABLE-default}` evaluates to default only if VARIABLE is unset in the\n                        environment. Similarly, the following syntax allows you\n                        to specify mandatory variables:\n- `${VARIABLE:?err}` exits with an error message containing err if VARIABLE is\n                     unset or empty in the environment.\n- `${VARIABLE?err}` exits with an error message containing err if VARIABLE is\n                     unset in the environment.\n\nWhen using the `.deb` or `.rpm` packages, you can define environment variables\nin the `/etc/default/telegraf` file.\n\n**Example**:\n\n`/etc/default/telegraf`:\n\nFor InfluxDB 1.x:\n\n```shell\nUSER=\"alice\"\nINFLUX_URL=\"http://localhost:8086\"\nINFLUX_SKIP_DATABASE_CREATION=\"true\"\nINFLUX_PASSWORD=\"monkey123\"\n```\n\nFor InfluxDB OSS 2:\n\n```shell\nINFLUX_HOST=\"http://localhost:8086\" # used to be 9999\nINFLUX_TOKEN=\"replace_with_your_token\"\nINFLUX_ORG=\"your_username\"\nINFLUX_BUCKET=\"replace_with_your_bucket_name\"\n```\n\nFor InfluxDB Cloud 2:\n\n```shell\n# For AWS West (Oregon)\nINFLUX_HOST=\"https://us-west-2-1.aws.cloud2.influxdata.com\"\n# Other Cloud URLs at https://v2.docs.influxdata.com/v2.0/reference/urls/#influxdb-cloud-urls\nINFLUX_TOKEN=”replace_with_your_token”\nINFLUX_ORG=\"yourname@yourcompany.com\"\nINFLUX_BUCKET=\"replace_with_your_bucket_name\"\n```\n\n`/etc/telegraf.conf`:\n\n```toml\n[global_tags]\n  user = \"${USER}\"\n\n[[inputs.mem]]\n\n# For InfluxDB 1.x:\n[[outputs.influxdb]]\n  urls = [\"${INFLUX_URL}\"]\n  skip_database_creation = ${INFLUX_SKIP_DATABASE_CREATION}\n  password = \"${INFLUX_PASSWORD}\"\n\n# For InfluxDB OSS 2:\n[[outputs.influxdb_v2]]\n  urls = [\"${INFLUX_HOST}\"]\n  token = \"${INFLUX_TOKEN}\"\n  organization = \"${INFLUX_ORG}\"\n  bucket = \"${INFLUX_BUCKET}\"\n\n# For InfluxDB Cloud 2:\n[[outputs.influxdb_v2]]\n  urls = [\"${INFLUX_HOST}\"]\n  token = \"${INFLUX_TOKEN}\"\n  organization = \"${INFLUX_ORG}\"\n  bucket = \"${INFLUX_BUCKET}\"\n```\n\nThe above files will produce the following effective configuration file to be\nparsed:\n\n```toml\n[global_tags]\n  user = \"alice\"\n\n[[inputs.mem]]\n\n# For InfluxDB 1.x:\n[[outputs.influxdb]]\n  urls = \"http://localhost:8086\"\n  skip_database_creation = true\n  password = \"monkey123\"\n\n# For InfluxDB OSS 2:\n[[outputs.influxdb_v2]]\n  urls = [\"http://127.0.0.1:8086\"] # double check the port. could be 9999 if using OSS Beta\n  token = \"replace_with_your_token\"\n  organization = \"your_username\"\n  bucket = \"replace_with_your_bucket_name\"\n\n# For InfluxDB Cloud 2:\n[[outputs.influxdb_v2]]\n  # For AWS West (Oregon)\n  INFLUX_HOST=\"https://us-west-2-1.aws.cloud2.influxdata.com\"\n  # Other Cloud URLs at https://v2.docs.influxdata.com/v2.0/reference/urls/#influxdb-cloud-urls\n  token = \"replace_with_your_token\"\n  organization = \"yourname@yourcompany.com\"\n  bucket = \"replace_with_your_bucket_name\"\n```\n\n## Secret-store secrets\n\nAdditional or instead of environment variables, you can use secret-stores\nto fill in credentials or similar. To do so, you need to configure one or more\nsecret-store plugin(s) and then reference the secret in your plugin\nconfigurations. A reference to a secret is specified in form\n`@{<secret store id>:<secret name>}`, where the `secret store id` is the unique\nID you defined for your secret-store and `secret name` is the name of the secret\nto use.\n**NOTE:** Both, the `secret store id` as well as the `secret name` can only\nconsist of letters (both upper- and lowercase), numbers and underscores.\n\n**Example**:\n\nThis example illustrates the use of secret-store(s) in plugins\n\n```toml\n[global_tags]\n  user = \"alice\"\n\n[[secretstores.os]]\n  id = \"local_secrets\"\n\n[[secretstores.jose]]\n  id = \"cloud_secrets\"\n  path = \"/etc/telegraf/secrets\"\n  # Optional reference to another secret store to unlock this one.\n  password = \"@{local_secrets:cloud_store_passwd}\"\n\n[[inputs.http]]\n  urls = [\"http://server.company.org/metrics\"]\n  username = \"@{local_secrets:company_server_http_metric_user}\"\n  password = \"@{local_secrets:company_server_http_metric_pass}\"\n\n[[outputs.influxdb_v2]]\n  urls = [\"https://us-west-2-1.aws.cloud2.influxdata.com\"]\n  token = \"@{cloud_secrets:influxdb_token}\"\n  organization = \"yourname@yourcompany.com\"\n  bucket = \"replace_with_your_bucket_name\"\n```\n\n### Notes\n\nWhen using plugins supporting secrets, Telegraf locks the memory pages\ncontaining the secrets. Therefore, the locked memory limit has to be set to a\nsuitable value. Telegraf will check the limit and the number of used secrets at\nstartup and will warn if your limit is too low. In this case, please increase\nthe limit via `ulimit -l`.\n\nIf you are running Telegraf in an jail you might need to allow locked pages in\nthat jail by setting `allow.mlock = 1;` in your config.\n\n## Intervals\n\nIntervals are durations of time and can be specified for supporting settings by\ncombining an integer value and time unit as a string value.  Valid time units are\n`ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`.\n\n```toml\n[agent]\n  interval = \"10s\"\n```\n\n## Global Tags\n\nGlobal tags can be specified in the `[global_tags]` table in key=\"value\"\nformat. All metrics that are gathered will be tagged with the tags specified.\nGlobal tags are overridden by tags set by plugins.\n\n```toml\n[global_tags]\n  dc = \"us-east-1\"\n```\n\n## Agent\n\nThe agent table configures Telegraf and the defaults used across all plugins.\n\n- **interval**: Default data collection [interval][] for all inputs.\n\n- **round_interval**: Rounds collection interval to [interval][]\n  ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n\n- **metric_batch_size**:\n  Telegraf will send metrics to outputs in batches of at most\n  metric_batch_size metrics.\n  This controls the size of writes that Telegraf sends to output plugins.\n\n- **metric_buffer_limit**:\n  Maximum number of unwritten metrics per output.  Increasing this value\n  allows for longer periods of output downtime without dropping metrics at the\n  cost of higher maximum memory usage. Oldest metrics are overwritten in favor\n  of new ones when the buffer fills up.\n\n- **collection_jitter**:\n  Collection jitter is used to jitter the collection by a random [interval][].\n  Each plugin will sleep for a random time within jitter before collecting.\n  This can be used to avoid many plugins querying things like sysfs at the\n  same time, which can have a measurable effect on the system.\n\n- **collection_offset**:\n  Collection offset is used to shift the collection by the given [interval][].\n  This can be be used to avoid many plugins querying constraint devices\n  at the same time by manually scheduling them in time.\n\n- **flush_interval**:\n  Default flushing [interval][] for all outputs. Maximum flush_interval will be\n  flush_interval + flush_jitter.\n\n- **flush_jitter**:\n  Default flush jitter for all outputs. This jitters the flush [interval][]\n  by a random amount. This is primarily to avoid large write spikes for users\n  running a large number of telegraf instances. ie, a jitter of 5s and interval\n  10s means flushes will happen every 10-15s.\n\n- **precision**:\n  Collected metrics are rounded to the precision specified as an [interval][].\n\n  Precision will NOT be used for service inputs. It is up to each individual\n  service input to set the timestamp at the appropriate precision.\n\n- **debug**:\n  Log at debug level.\n\n- **quiet**:\n  Log only error level messages.\n\n- **logformat**:\n  Log format controls the way messages are logged and can be one of \"text\",\n  \"structured\" or, on Windows, \"eventlog\". The output file (if any) is\n  determined by the `logfile` setting.\n\n- **structured_log_message_key**:\n  Message key for structured logs, to override the default of \"msg\".\n  Ignored if `logformat` is not \"structured\".\n\n- **logfile**:\n  Name of the file to be logged to or stderr if unset or empty. This\n  setting is ignored for the \"eventlog\" format.\n\n- **logfile_rotation_interval**:\n  The logfile will be rotated after the time interval specified.  When set to\n  0 no time based rotation is performed.\n\n- **logfile_rotation_max_size**:\n  The logfile will be rotated when it becomes larger than the specified size.\n  When set to 0 no size based rotation is performed.\n\n- **logfile_rotation_max_archives**:\n  Maximum number of rotated archives to keep, any older logs are deleted.  If\n  set to -1, no archives are removed.\n\n- **log_with_timezone**:\n  Pick a timezone to use when logging or type 'local' for local time. Example: 'America/Chicago'.\n  [See this page for options/formats.](https://socketloop.com/tutorials/golang-display-list-of-timezones-with-gmt)\n\n- **hostname**:\n  Override default hostname, if empty use os.Hostname()\n\n- **omit_hostname**:\n  If set to true, do no set the \"host\" tag in the telegraf agent.\n\n- **snmp_translator**:\n  Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  translates by calling external programs `snmptranslate` and `snmptable`,\n  or \"gosmi\" which translates using the built-in gosmi library.\n\n- **statefile**:\n  Name of the file to load the states of plugins from and store the states to.\n  If uncommented and not empty, this file will be used to save the state of\n  stateful plugins on termination of Telegraf. If the file exists on start,\n  the state in the file will be restored for the plugins.\n\n- **always_include_local_tags**:\n  Ensure tags explicitly defined in a plugin will *always* pass tag-filtering\n  via `taginclude` or `tagexclude`. This removes the need to specify local tags\n  twice.\n\n- **always_include_global_tags**:\n  Ensure tags explicitly defined in the `global_tags` section will *always* pass\n  tag-filtering   via `taginclude` or `tagexclude`. This removes the need to\n  specify those tags twice.\n\n- **skip_processors_after_aggregators**:\n  By default, processors are run a second time after aggregators. Changing\n  this setting to true will skip the second run of processors.\n\n- **buffer_strategy**:\n  The type of buffer to use for telegraf output plugins. Supported modes are\n  `memory`, the default and original buffer type, and `disk`, an experimental\n  disk-backed buffer which will serialize all metrics to disk as needed to\n  improve data durability and reduce the chance for data loss. This is only\n  supported at the agent level.\n\n- **buffer_directory**:\n  The directory to use when in `disk` buffer mode. Each output plugin will make\n  another subdirectory in this directory with the output plugin's ID.\n\n- **buffer_disk_sync**:\n  Controls writes durability when \"disk\" buffer strategy is used.\n  No sync offers better write performance at the risk of losing metrics\n  buffered in the last `flush_interval` in the event of a power cut.\n  Defaults to 'true'.\n\n## Plugins\n\nTelegraf plugins are divided into 4 types: [inputs][], [outputs][],\n[processors][], and [aggregators][].\n\nUnlike the `global_tags` and `agent` tables, any plugin can be defined\nmultiple times and each instance will run independently.  This allows you to\nhave plugins defined with differing configurations as needed within a single\nTelegraf process.\n\nEach plugin has a unique set of configuration options, reference the\nsample configuration for details.  Additionally, several options are available\non any plugin depending on its type.\n\n### Input Plugins\n\nInput plugins gather and create metrics.  They support both polling and event\ndriven operation.\n\nParameters that can be used with any input plugin:\n\n- **alias**: Name an instance of a plugin.\n- **interval**:\n  Overrides the `interval` setting of the [agent][Agent] for the plugin.  How\n  often to gather this metric. Normal plugins use a single global interval, but\n  if one particular input should be run less or more often, you can configure\n  that here.\n- **precision**:\n  Overrides the `precision` setting of the [agent][Agent] for the plugin.\n  Collected metrics are rounded to the precision specified as an [interval][].\n\n  When this value is set on a service input, multiple events occurring at the\n  same timestamp may be merged by the output database.\n- **time_source**:\n  Specifies the source of the timestamp on metrics. Possible values are:\n  - `metric` will not alter the metric (default)\n  - `collection_start` sets the timestamp to when collection started\n  - `collection_end` set the timestamp to when collection finished\n\n  `time_source` will NOT be used for service inputs. It is up to each individual\n  service input to set the timestamp.\n- **collection_jitter**:\n  Overrides the `collection_jitter` setting of the [agent][Agent] for the\n  plugin.  Collection jitter is used to jitter the collection by a random\n  [interval][]. The value must be non-zero to override the agent setting.\n- **collection_offset**:\n  Overrides the `collection_offset` setting of the [agent][Agent] for the\n  plugin. Collection offset is used to shift the collection by the given\n  [interval][]. The value must be non-zero to override the agent setting.\n- **name_override**: Override the base name of the measurement.  (Default is\n  the name of the input).\n- **name_prefix**: Specifies a prefix to attach to the measurement name.\n- **name_suffix**: Specifies a suffix to attach to the measurement name.\n- **tags**: A map of tags to apply to a specific input's measurements.\n- **log_level**: Override the log-level for this plugin. Possible values are\n  `error`, `warn`, `info`, `debug` and `trace`.\n\nThe [metric filtering][] parameters can be used to limit what metrics are\nemitted from the input plugin.\n\n#### Examples\n\nUse the name_suffix parameter to emit measurements with the name `cpu_total`:\n\n```toml\n[[inputs.cpu]]\n  name_suffix = \"_total\"\n  percpu = false\n  totalcpu = true\n```\n\nUse the name_override parameter to emit measurements with the name `foobar`:\n\n```toml\n[[inputs.cpu]]\n  name_override = \"foobar\"\n  percpu = false\n  totalcpu = true\n```\n\nEmit measurements with two additional tags: `tag1=foo` and `tag2=bar`\n\n> **NOTE**: With TOML, order matters.  Parameters belong to the last defined\n> table header, place `[inputs.cpu.tags]` table at the *end* of the plugin\n> definition.\n\n```toml\n[[inputs.cpu]]\n  percpu = false\n  totalcpu = true\n  [inputs.cpu.tags]\n    tag1 = \"foo\"\n    tag2 = \"bar\"\n```\n\nAlternatively, when using the inline table syntax, the tags do not need\nto go at the end:\n\n```toml\n[[inputs.cpu]]\n  tags = {tag1 = \"foo\", tag2 = \"bar\"}\n  percpu = false\n  totalcpu = true\n```\n\nUtilize `name_override`, `name_prefix`, or `name_suffix` config options to\navoid measurement collisions when defining multiple plugins:\n\n```toml\n[[inputs.cpu]]\n  percpu = false\n  totalcpu = true\n\n[[inputs.cpu]]\n  percpu = true\n  totalcpu = false\n  name_override = \"percpu_usage\"\n  fieldexclude = [\"cpu_time*\"]\n```\n\n### Output Plugins\n\nOutput plugins write metrics to a location.  Outputs commonly write to\ndatabases, network services, and messaging systems.\n\nParameters that can be used with any output plugin:\n\n- **alias**: Name an instance of a plugin.\n- **flush_interval**: The maximum time between flushes.  Use this setting to\n  override the agent `flush_interval` on a per plugin basis.\n- **flush_jitter**: The amount of time to jitter the flush interval.  Use this\n  setting to override the agent `flush_jitter` on a per plugin basis. The value\n  must be non-zero to override the agent setting.\n- **metric_batch_size**: The maximum number of metrics to send at once.  Use\n  this setting to override the agent `metric_batch_size` on a per plugin basis.\n- **metric_buffer_limit**: The maximum number of unsent metrics to buffer.\n  Use this setting to override the agent `metric_buffer_limit` on a per plugin\n  basis.\n- **name_override**: Override the original name of the measurement.\n- **name_prefix**: Specifies a prefix to attach to the measurement name.\n- **name_suffix**: Specifies a suffix to attach to the measurement name.\n- **log_level**: Override the log-level for this plugin. Possible values are\n  `error`, `warn`, `info` and `debug`.\n\nThe [metric filtering][] parameters can be used to limit what metrics are\nemitted from the output plugin.\n\n#### Examples\n\nOverride flush parameters for a single output:\n\n```toml\n[agent]\n  flush_interval = \"10s\"\n  flush_jitter = \"5s\"\n  metric_batch_size = 1000\n\n[[outputs.influxdb]]\n  urls = [ \"http://example.org:8086\" ]\n  database = \"telegraf\"\n\n[[outputs.file]]\n  files = [ \"stdout\" ]\n  flush_interval = \"1s\"\n  flush_jitter = \"1s\"\n  metric_batch_size = 10\n```\n\n### Processor Plugins\n\nProcessor plugins perform processing tasks on metrics and are commonly used to\nrename or apply transformations to metrics.  Processors are applied after the\ninput plugins and before any aggregator plugins.\n\nParameters that can be used with any processor plugin:\n\n- **alias**: Name an instance of a plugin.\n- **order**: The order in which the processor(s) are executed. starting with 1.\n  If this is not specified then processor execution order will be the order in\n  the config. Processors without \"order\" will take precedence over those\n  with a defined order.\n- **log_level**: Override the log-level for this plugin. Possible values are\n  `error`, `warn`, `info` and `debug`.\n\nThe [metric filtering][] parameters can be used to limit what metrics are\nhandled by the processor.  Excluded metrics are passed downstream to the next\nprocessor.\n\n#### Examples\n\nIf the order processors are applied matters you must set order on all involved\nprocessors:\n\n```toml\n[[processors.rename]]\n  order = 1\n  [[processors.rename.replace]]\n    tag = \"path\"\n    dest = \"resource\"\n\n[[processors.strings]]\n  order = 2\n  [[processors.strings.trim_prefix]]\n    tag = \"resource\"\n    prefix = \"/api/\"\n```\n\n### Aggregator Plugins\n\nAggregator plugins produce new metrics after examining metrics over a time\nperiod, as the name suggests they are commonly used to produce new aggregates\nsuch as mean/max/min metrics.  Aggregators operate on metrics after any\nprocessors have been applied.\n\nParameters that can be used with any aggregator plugin:\n\n- **alias**: Name an instance of a plugin.\n- **period**: The period on which to flush & clear each aggregator. All\n  metrics that are sent with timestamps outside of this period will be ignored\n  by the aggregator.\n  The default period is set to 30 seconds.\n- **delay**: The delay before each aggregator is flushed. This is to control\n  how long for aggregators to wait before receiving metrics from input\n  plugins, in the case that aggregators are flushing and inputs are gathering\n  on the same interval.\n  The default delay is set to 100 ms.\n- **grace**: The duration when the metrics will still be aggregated\n  by the plugin, even though they're outside of the aggregation period. This\n  is needed in a situation when the agent is expected to receive late metrics\n  and it's acceptable to roll them up into next aggregation period.\n  The default grace duration is set to 0 s.\n- **drop_original**: If true, the original metric will be dropped by the\n  aggregator and will not get sent to the output plugins.\n- **name_override**: Override the base name of the measurement.  (Default is\n  the name of the input).\n- **name_prefix**: Specifies a prefix to attach to the measurement name.\n- **name_suffix**: Specifies a suffix to attach to the measurement name.\n- **tags**: A map of tags to apply to the measurement - behavior varies based on\n            aggregator.\n- **log_level**: Override the log-level for this plugin. Possible values are\n  `error`, `warn`, `info` and `debug`.\n\nThe [metric filtering][] parameters can be used to limit what metrics are\nhandled by the aggregator.  Excluded metrics are passed downstream to the next\naggregator.\n\n#### Examples\n\nCollect and emit the min/max of the system load1 metric every 30s, dropping\nthe originals.\n\n```toml\n[[inputs.system]]\n  fieldinclude = [\"load1\"] # collects system load1 metric.\n\n[[aggregators.minmax]]\n  period = \"30s\"        # send & clear the aggregate every 30s.\n  drop_original = true  # drop the original metrics.\n\n[[outputs.file]]\n  files = [\"stdout\"]\n```\n\nCollect and emit the min/max of the swap metrics every 30s, dropping the\noriginals. The aggregator will not be applied to the system load metrics due\nto the `namepass` parameter.\n\n```toml\n[[inputs.swap]]\n\n[[inputs.system]]\n  fieldinclude = [\"load1\"] # collects system load1 metric.\n\n[[aggregators.minmax]]\n  period = \"30s\"        # send & clear the aggregate every 30s.\n  drop_original = true  # drop the original metrics.\n  namepass = [\"swap\"]   # only \"pass\" swap metrics through the aggregator.\n\n[[outputs.file]]\n  files = [\"stdout\"]\n```\n\n## Metric Filtering\n\nMetric filtering can be configured per plugin on any input, output, processor,\nand aggregator plugin.  Filters fall under two categories: Selectors and\nModifiers.\n\n### Selectors\n\nSelector filters include or exclude entire metrics.  When a metric is excluded\nfrom a Input or an Output plugin, the metric is dropped.  If a metric is\nexcluded from a Processor or Aggregator plugin, it is skips the plugin and is\nsent onwards to the next stage of processing.\n\n- **namepass**:\nAn array of [glob pattern][] strings. Only metrics whose measurement name\nmatches a pattern in this list are emitted. Additionally, custom list of\nseparators can be specified using `namepass_separator`. These separators\nare excluded from wildcard glob pattern matching.\n\n- **namedrop**:\nThe inverse of `namepass`. If a match is found the metric is discarded. This\nis tested on metrics after they have passed the `namepass` test. Additionally,\ncustom list of separators can be specified using `namedrop_separator`. These\nseparators are excluded from wildcard glob pattern matching.\n\n- **tagpass**:\nA table mapping tag keys to arrays of [glob pattern][] strings.  Only metrics\nthat contain a tag key in the table and a tag value matching one of its\npatterns is emitted. This can either use the explicit table syntax (e.g.\na subsection using a `[...]` header) or inline table syntax (e.g like\na JSON table with `{...}`). Please see the below notes on specifying the table.\n\n- **tagdrop**:\nThe inverse of `tagpass`.  If a match is found the metric is discarded. This\nis tested on metrics after they have passed the `tagpass` test.\n\n> NOTE: Due to the way TOML is parsed, when using the explicit table\n> syntax (with `[...]`) for `tagpass` and `tagdrop` parameters, they\n> must be defined at the **end** of the plugin definition, otherwise subsequent\n> plugin config options will be interpreted as part of the tagpass/tagdrop\n> tables.\n> NOTE: When using the inline table syntax (e.g. `{...}`) the table must exist\n> in the main plugin definition and not in any sub-table (e.g.\n> `[[inputs.win_perf_counters.object]]`).\n\n- **metricpass**:\nA [\"Common Expression Language\"][CEL] (CEL) expression with boolean result where\n`true` will allow the metric to pass, otherwise the metric is discarded. This\nfilter expression is more general compared to e.g. `namepass` and also allows\nfor time-based filtering. Further details, such as available functions and\nexpressions, are provided in the [language definition][CEL lang] as well as in\nthe [extension documentation][CEL ext] or the\n[CEL language introduction][CEL intro].\n\nExpressions that may be valid and compile, but fail at runtime will result in\nthe expression reporting as `true`. The metrics will pass through as a result.\nAn example is when reading a non-existing field. If this happens, the\nevaluation is aborted, an error is logged, and the expression is reported as\n`true`, so the metric passes.\n\n> [!NOTE]\n> As CEL is an *interpreted* language, this type of filtering is much slower\n> compared to `namepass`/`namedrop` and friends. So consider to use the more\n> restricted filter options where possible in case of high-throughput scenarios.\n\n[CEL]:https://github.com/google/cel-go/tree/master\n[CEL intro]: https://codelabs.developers.google.com/codelabs/cel-go\n[CEL lang]: https://github.com/google/cel-spec/blob/master/doc/langdef.md\n[CEL ext]: https://github.com/google/cel-go/tree/master/ext#readme\n\n### Modifiers\n\nModifier filters remove tags and fields from a metric. If all fields are\nremoved the metric is removed and as result not passed through to the following\nprocessors or any output plugin. Tags and fields are modified before a metric is\npassed to a processor, aggregator, or output plugin. When used with an input\nplugin the filter applies after the input runs.\n\n- **fieldinclude**:\nAn array of [glob pattern][] strings.  Only fields whose field key matches a\npattern in this list are emitted.\n\n- **fieldexclude**:\nThe inverse of `fieldinclude`.  Fields with a field key matching one of the\npatterns will be discarded from the metric.  This is tested on metrics after\nthey have passed the `fieldinclude` test.\n\n- **taginclude**:\nAn array of [glob pattern][] strings.  Only tags with a tag key matching one of\nthe patterns are emitted.  In contrast to `tagpass`, which will pass an entire\nmetric based on its tag, `taginclude` removes all non matching tags from the\nmetric.  Any tag can be filtered including global tags and the agent `host`\ntag.\n\n- **tagexclude**:\nThe inverse of `taginclude`. Tags with a tag key matching one of the patterns\nwill be discarded from the metric.  Any tag can be filtered including global\ntags and the agent `host` tag.\n\n### Filtering Examples\n\n#### Using tagpass and tagdrop\n\n```toml\n[[inputs.cpu]]\n  percpu = true\n  totalcpu = false\n  fieldexclude = [\"cpu_time\"]\n  # Don't collect CPU data for cpu6 & cpu7\n  [inputs.cpu.tagdrop]\n    cpu = [ \"cpu6\", \"cpu7\" ]\n\n[[inputs.disk]]\n  [inputs.disk.tagpass]\n    # tagpass conditions are OR, not AND.\n    # If the (filesystem is ext4 or xfs) OR (the path is /opt or /home)\n    # then the metric passes\n    fstype = [ \"ext4\", \"xfs\" ]\n    # Globs can also be used on the tag values\n    path = [ \"/opt\", \"/home*\" ]\n\n[[inputs.win_perf_counters]]\n  [[inputs.win_perf_counters.object]]\n    ObjectName = \"Network Interface\"\n    Instances = [\"*\"]\n    Counters = [\n      \"Bytes Received/sec\",\n      \"Bytes Sent/sec\"\n    ]\n    Measurement = \"win_net\"\n  # Do not send metrics where the Windows interface name (instance) begins with\n  # 'isatap' or 'Local'\n  [inputs.win_perf_counters.tagdrop]\n    instance = [\"isatap*\", \"Local*\"]\n```\n\n#### Using fieldinclude and fieldexclude\n\n```toml\n# Drop all metrics for guest & steal CPU usage\n[[inputs.cpu]]\n  percpu = false\n  totalcpu = true\n  fieldexclude = [\"usage_guest\", \"usage_steal\"]\n\n# Only store inode related metrics for disks\n[[inputs.disk]]\n  fieldinclude = [\"inodes*\"]\n```\n\n#### Using namepass and namedrop\n\n```toml\n# Drop all metrics about containers for kubelet\n[[inputs.prometheus]]\n  urls = [\"http://kube-node-1:4194/metrics\"]\n  namedrop = [\"container_*\"]\n\n# Only store rest client related metrics for kubelet\n[[inputs.prometheus]]\n  urls = [\"http://kube-node-1:4194/metrics\"]\n  namepass = [\"rest_client_*\"]\n```\n\n#### Using namepass and namedrop with separators\n\n```toml\n# Pass all metrics of type 'A.C.B' and drop all others like 'A.C.D.B'\n[[inputs.socket_listener]]\n  data_format = \"graphite\"\n  templates = [\"measurement*\"]\n\n  namepass = [\"A.*.B\"]\n  namepass_separator = \".\"\n\n# Drop all metrics of type 'A.C.B' and pass all others like 'A.C.D.B'\n[[inputs.socket_listener]]\n  data_format = \"graphite\"\n  templates = [\"measurement*\"]\n\n  namedrop = [\"A.*.B\"]\n  namedrop_separator = \".\"\n```\n\n#### Using taginclude and tagexclude\n\n```toml\n# Only include the \"cpu\" tag in the measurements for the cpu plugin.\n[[inputs.cpu]]\n  percpu = true\n  totalcpu = true\n  taginclude = [\"cpu\"]\n\n# Exclude the \"fstype\" tag from the measurements for the disk plugin.\n[[inputs.disk]]\n  tagexclude = [\"fstype\"]\n```\n\n#### Metrics can be routed to different outputs using the metric name and tags\n\n```toml\n[[outputs.influxdb]]\n  urls = [ \"http://localhost:8086\" ]\n  database = \"telegraf\"\n  # Drop all measurements that start with \"aerospike\"\n  namedrop = [\"aerospike*\"]\n\n[[outputs.influxdb]]\n  urls = [ \"http://localhost:8086\" ]\n  database = \"telegraf-aerospike-data\"\n  # Only accept aerospike data:\n  namepass = [\"aerospike*\"]\n\n[[outputs.influxdb]]\n  urls = [ \"http://localhost:8086\" ]\n  database = \"telegraf-cpu0-data\"\n  # Only store measurements where the tag \"cpu\" matches the value \"cpu0\"\n  [outputs.influxdb.tagpass]\n    cpu = [\"cpu0\"]\n```\n\n#### Routing metrics to different outputs based on the input\n\nMetrics are tagged with `influxdb_database` in the input, which is then used to\nselect the output.  The tag is removed in the outputs before writing with `tagexclude`.\n\n```toml\n[[outputs.influxdb]]\n  urls = [\"http://influxdb.example.com\"]\n  database = \"db_default\"\n  [outputs.influxdb.tagdrop]\n    influxdb_database = [\"*\"]\n\n[[outputs.influxdb]]\n  urls = [\"http://influxdb.example.com\"]\n  database = \"db_other\"\n  tagexclude = [\"influxdb_database\"]\n  [outputs.influxdb.tagpass]\n    influxdb_database = [\"other\"]\n\n[[inputs.disk]]\n  [inputs.disk.tags]\n    influxdb_database = \"other\"\n```\n\n## Plugin selection via labels and selectors\n\nYou can control which plugin instances are enabled by decorating plugins with\nlabels in their config and passing one or more selectors on the command line.\n\n### Selectors\n\nProvide selectors with one or more `--select` flags when starting Telegraf. Each\n`--select` value is a semicolon-separated list of key=value pairs:\n\n```text\n<key>=<value>[;<key>=<value>]\n```\n\n- Pairs in a single `--select` value are combined with logical AND (all must\nmatch).\n- Multiple `--select` flags are combined with logical OR (a plugin is enabled if\nit matches any selector set).\n\nSelectors support simple glob patterns in values (for example `region=us-*`).\n\nExample:\n\n```console\ntelegraf --config config.conf --config-directory directory/ \\\n  --select=\"app=payments;region=us-*\" \\\n  --select=\"env=prod\" \\\n  --watch-config --print-plugin-config-source=true\n```\n\n### Labels\n\nAdd an optional `labels` table to a plugin, similar to `tags`. Keys and values\nare plain strings.\n\nExample:\n\n```toml\n[[inputs.cpu]]\n  [inputs.cpu.labels]\n    app = \"payments\"\n    region = \"us-east\"\n    env = \"prod\"\n```\n\nTelegraf matches the command-line selectors against a plugin's labels to decide\nwhether that plugin instance should be enabled. For more details on the syntax\nand matching criteria refer, [labels selectors spec][tsd010].\n\n## Transport Layer Security (TLS)\n\nReference the detailed [TLS][] documentation.\n\n[TOML]: https://github.com/toml-lang/toml#toml\n[global tags]: #global-tags\n[interval]: #intervals\n[agent]: #agent\n[plugins]: #plugins\n[inputs]: #input-plugins\n[outputs]: #output-plugins\n[processors]: #processor-plugins\n[aggregators]: #aggregator-plugins\n[metric filtering]: #metric-filtering\n[TLS]: /docs/TLS.md\n[glob pattern]: https://github.com/gobwas/glob#syntax\n[flags]: /docs/COMMANDS_AND_FLAGS.md\n[tsd010]: /docs/specs/tsd-010-labels-and-selectors.md\n"
  },
  {
    "path": "docs/CUSTOMIZATION.md",
    "content": "# Customization\n\nYou can build customized versions of Telegraf with a specific plugin set using\nthe [custom builder](/tools/custom_builder) tool or\n[build-tags](https://pkg.go.dev/cmd/go#hdr-Build_constraints).\nFor build tags, the plugins can be selected either category-wise, i.e.\n`inputs`, `outputs`,`processors`, `aggregators`, `parsers`, `secretstores`\nand `serializers` or individually, e.g. `inputs.modbus` or `outputs.influxdb`.\n\nUsually the build tags correspond to the plugin names used in the Telegraf\nconfiguration. To be sure, check the files in the corresponding\n`plugin/<category>/all` directory. Make sure to include all parsers you intend\nto use.\n\n__Note:__ You _always_ need to include the `custom` tag when customizing the\nbuild as otherwise _all_ plugins will be selected regardless of other tags.\n\n## Via make\n\nWhen using the project's makefile, the build can be customized via the\n`BUILDTAGS` environment variable containing a __comma-separated__ list of the\nselected plugins (or categories) __and__ the `custom` tag.\n\nFor example\n\n```shell\nBUILDTAGS=\"custom,inputs,outputs.influxdb_v2,parsers.json\" make\n```\n\nwill build a customized Telegraf including _all_ `inputs`, the InfluxDB v2\n`output` and the `json` parser.\n\n## Via `go build`\n\nIf you wish to build Telegraf using native go tools, you can use the `go build`\ncommand with the `-tags` option. Specify  a __comma-separated__ list of the\nselected plugins (or categories) __and__ the `custom` tag as argument.\n\nFor example\n\n```shell\ngo build -tags \"custom,inputs,outputs.influxdb_v2,parsers.json\" ./cmd/telegraf\n```\n\nwill build a customized Telegraf including _all_ `inputs`, the InfluxDB v2\n`output` and the `json` parser.\n"
  },
  {
    "path": "docs/DATA_FORMATS_INPUT.md",
    "content": "# Input Data Formats\n\nTelegraf contains many general purpose plugins that support parsing input data\nusing a configurable parser into [metrics][].  This allows, for example, the\n`kafka_consumer` input plugin to process messages in any of InfluxDB Line\nProtocol, JSON format, or Apache Avro format.\n\n- [Avro](/plugins/parsers/avro)\n- [Binary](/plugins/parsers/binary)\n- [Collectd](/plugins/parsers/collectd)\n- [CSV](/plugins/parsers/csv)\n- [Dropwizard](/plugins/parsers/dropwizard)\n- [Form URL Encoded](/plugins/parsers/form_urlencoded)\n- [Graphite](/plugins/parsers/graphite)\n- [Grok](/plugins/parsers/grok)\n- [InfluxDB Line Protocol](/plugins/parsers/influx)\n- [JSON](/plugins/parsers/json)\n- [JSON v2](/plugins/parsers/json_v2)\n- [Logfmt](/plugins/parsers/logfmt)\n- [Nagios](/plugins/parsers/nagios)\n- [OpenMetrics](/plugins/parsers/openmetrics)\n- [OpenTSDB](/plugins/parsers/opentsdb)\n- [Parquet](/plugins/parsers/parquet)\n- [Prometheus](/plugins/parsers/prometheus)\n- [PrometheusRemoteWrite](/plugins/parsers/prometheusremotewrite)\n- [Value](/plugins/parsers/value), ie: 45 or \"booyah\"\n- [Wavefront](/plugins/parsers/wavefront)\n- [XPath](/plugins/parsers/xpath) (supports XML, JSON, MessagePack, Protocol Buffers)\n\nAny input plugin containing the `data_format` option can use it to select the\ndesired parser:\n\n```toml\n[[inputs.exec]]\n  ## Commands array\n  commands = [\"/tmp/test.sh\", \"/usr/bin/mycollector --foo=bar\"]\n\n  ## measurement name suffix (for separating different commands)\n  name_suffix = \"_mycollector\"\n\n  ## Data format to consume.\n  data_format = \"json\"\n```\n\n[metrics]: /docs/METRICS.md\n"
  },
  {
    "path": "docs/DATA_FORMATS_OUTPUT.md",
    "content": "# Output Data Formats\n\nIn addition to output specific data formats, Telegraf supports a set of\nstandard data formats that may be selected from when configuring many output\nplugins.\n\n1. [InfluxDB Line Protocol](/plugins/serializers/influx)\n1. [Binary](/plugins/serializers/binary)\n1. [Carbon2](/plugins/serializers/carbon2)\n1. [CloudEvents](/plugins/serializers/cloudevents)\n1. [CSV](/plugins/serializers/csv)\n1. [Graphite](/plugins/serializers/graphite)\n1. [JSON](/plugins/serializers/json)\n1. [MessagePack](/plugins/serializers/msgpack)\n1. [Prometheus](/plugins/serializers/prometheus)\n1. [Prometheus Remote Write](/plugins/serializers/prometheusremotewrite)\n1. [ServiceNow Metrics](/plugins/serializers/nowmetric)\n1. [SplunkMetric](/plugins/serializers/splunkmetric)\n1. [Template](/plugins/serializers/template)\n1. [Wavefront](/plugins/serializers/wavefront)\n\nYou will be able to identify the plugins with support by the presence of a\n`data_format` config option, for example, in the `file` output plugin:\n\n```toml\n[[outputs.file]]\n  ## Files to write to, \"stdout\" is a specially handled file.\n  files = [\"stdout\"]\n\n  ## Data format to output.\n  data_format = \"influx\"\n```\n"
  },
  {
    "path": "docs/DOCKER.md",
    "content": "# Docker Images\n\nTelegraf is available as an [Official image][] on DockerHub. Official images\nare a curated set of Docker Images that also automatically get security updates\nfrom Docker, follow a set of best practices, and are available via a shortcut\nsyntax which omits the organization.\n\nInfluxData maintains Debian and Alpine based images across the last three\nminor releases. To pull the latest Telegraf images:\n\n```shell\n# latest Debian-based image\ndocker pull telegraf\n# latest Alpine-based image\ndocker pull telegraf:alpine\n```\n\nSee the [Telegraf DockerHub][] page for complete details on available images,\nversions, and tags.\n\n[official image]: https://docs.docker.com/trusted-content/official-images/\n[Telegraf DockerHub]: https://hub.docker.com/_/telegraf\n\n## Nightly Images\n\n[Nightly builds][] are available and are generated from the master branch each\nday at around midnight UTC. The artifacts include both binary packages, RPM &\nDEB packages, as well as nightly Docker images that are hosted on [quay.io][].\n\n[Nightly builds]: /docs/NIGHTLIES.md\n[quay.io]: https://quay.io/repository/influxdb/telegraf-nightly?tab=tags&tag=latest\n\n## Dockerfiles\n\nThe [Dockerfiles][] for these images are available for users to use as well.\n\n[Dockerfiles]: https://github.com/influxdata/influxdata-docker\n\n## Lockable Memory\n\nTelegraf does require the ability to use lockable memory when running by\ndefault. In some deployments for Docker a container may not have enough lockable\nmemory, which results in the following warning:\n\n```text\nW! Insufficient lockable memory 64kb when 72kb is required. Please increase the limit for Telegraf in your Operating System!\n```\n\nor this error:\n\n```text\npanic: could not acquire lock on 0x7f7a8890f000, limit reached? [Err: cannot allocate memory]\n```\n\nUsers have two options:\n\n1. Increase the ulimit in the container. The user does this with the `ulimit -l`\n  command. To both see and set the value. For docker, there is a `--ulimit` flag\n  that could be used, like `--ulimit memlock=8192:8192` as well.\n2. Add the `--unprotected` flag to the command arguments to not use locked\n  memory and instead store secrets in unprotected memory. This is less secure\n  as secrets could find their way into paged out memory and can be written to\n  disk unencrypted, therefore this is opt-in. For docker look at updating the\n  `CMD` used to include this flag.\n"
  },
  {
    "path": "docs/EXTERNAL_PLUGINS.md",
    "content": "# External Plugins\n\n[External plugins](/EXTERNAL_PLUGINS.md) are external programs that are built\noutside of Telegraf that can run through an `execd` plugin. These external\nplugins allow for more flexibility compared to internal Telegraf plugins.\n\n- External plugins can be written in any language (internal Telegraf plugins can\n  only be written in Go)\n- External plugins can access to libraries not written in Go\n- Utilize licensed software that is not available to the open source community\n- Can include large dependencies that would otherwise bloat Telegraf\n- You do not need to wait on the Telegraf team to publish the plugin and start\n  working with it.\n- Using the [shim](/plugins/common/shim) you can easily convert plugins between\n  internal and external use\n- Using 3rd-party libraries requiring CGO support\n\n## External Plugin Guidelines\n\nThe guidelines of writing external plugins would follow those for our general\n[input](/docs/INPUTS.md), [output](/docs/OUTPUTS.md),\n[processor](/docs/PROCESSORS.md), and [aggregator](/docs/AGGREGATORS.md)\nplugins. Please reference the documentation on how to create these plugins\nwritten in Go.\n\n_For listed [external plugins](/EXTERNAL_PLUGINS.md), the author of the external\nplugin is also responsible for the maintenance and feature development of\nexternal plugins. Expect to have users open plugin issues on its respective\nGitHub repository._\n\n### Execd Go Shim\n\nFor Go plugins, there is a [Execd Go Shim](/plugins/common/shim/) that will make\nit trivial to extract an internal input, processor, or output plugin from the\nmain Telegraf repo out to a stand-alone repo. This shim allows anyone to build\nand run it as a separate app using one of the `execd` plugins:\n\n- [inputs.execd](/plugins/inputs/execd)\n- [processors.execd](/plugins/processors/execd)\n- [outputs.execd](/plugins/outputs/execd)\n\nFollow the [Steps to externalize a plugin][] and\n[Steps to build and run your plugin][] to properly with the Execd Go Shim.\n\n[Steps to externalize a plugin]: /plugins/common/shim#steps-to-externalize-a-plugin\n[Steps to build and run your plugin]: /plugins/common/shim#steps-to-build-and-run-your-plugin\n\n## Step-by-Step guidelines\n\nThis is a guide to help you set up a plugin to use it with `execd`:\n\n1. Write a Telegraf plugin. Depending on the plugin, follow the guidelines on\n  how to create the plugin itself using InfluxData's best practices:\n   - [Input Plugins](/docs/INPUTS.md)\n   - [Processor Plugins](/docs/PROCESSORS.md)\n   - [Aggregator Plugins](/docs/AGGREGATORS.md)\n   - [Output Plugins](/docs/OUTPUTS.md)\n2. Move the project to an external repo, it is recommended to preserve the\n   path structure, but not strictly necessary. For example, if the plugin was\n   at `plugins/inputs/cpu`, it is recommended that it also be under\n   `plugins/inputs/cpu` in the new repo. For a further example of what this\n   might look like, take a look at [ssoroka/rand][] or\n   [danielnelson/telegraf-execd-openvpn][].\n3. Copy [main.go](/plugins/common/shim/example/cmd/main.go) into the project\n   under the `cmd` folder. This will be the entrypoint to the plugin when run as\n   a stand-alone program and it will call the shim code for you to make that\n   happen. It is recommended to have only one plugin per repo, as the shim is\n   not designed to run multiple plugins at the same time.\n4. Edit the main.go file to import the plugin. Within Telegraf this would have\n   been done in an all.go file, but here we do not split the two apart, and the\n   change just goes in the top of main.go. If you skip this step, the plugin\n   will do nothing.\n   > `_ \"github.com/me/my-plugin-telegraf/plugins/inputs/cpu\"`\n5. Optionally add a [plugin.conf](./example/cmd/plugin.conf) for configuration\n   specific to the plugin. Note that this config file **must be separate from\n   the rest of the config for Telegraf, and must not be in a shared directory\n   where Telegraf is expecting to load all configs**. If Telegraf reads this\n   config file it will not know which plugin it relates to. Telegraf instead\n   uses an execd config block to look for this plugin.\n6. Add usage and development instructions in the homepage of the repository\n   for running the plugin with its respective `execd` plugin. Please refer to\n   [openvpn install][] and [awsalarms install][] for examples. Include the\n   following steps:\n     1. How to download the release package for the platform or how to clone the\n        binary for the external plugin\n     1. The commands to build the binary\n     1. Location to edit the `telegraf.conf`\n     1. Configuration to run the external plugin with\n     [inputs.execd](/plugins/inputs/execd),\n     [processors.execd](/plugins/processors/execd), or\n     [outputs.execd](/plugins/outputs/execd)\n7. Submit the plugin by opening a PR to add the external plugin to the\n   [/EXTERNAL_PLUGINS.md](/EXTERNAL_PLUGINS.md) list. Please include the\n   plugin name, link to the plugin repository and a short description of the\n   plugin.\n\n[ssoroka/rand]: https://github.com/ssoroka/rand\n[danielnelson/telegraf-execd-openvpn]: https://github.com/danielnelson/telegraf-execd-openvpn\n[openvpn install]: https://github.com/danielnelson/telegraf-execd-openvpn#usage\n[awsalarms install]: https://github.com/vipinvkmenon/awsalarms#installation\n"
  },
  {
    "path": "docs/FAQ.md",
    "content": "# Frequently Asked Questions\n\n## When is the next release? When will my PR or fix get released?\n\nTelegraf has four minor releases a year in March, June, September, and\nDecember. In between each of those minor releases, there are 2-4 bug fix\nreleases that happen every 3 weeks.\n\nThis [Google Calendar][] is kept up to date for upcoming releases dates.\nAdditionally, users can look at the [GitHub milestones][] for the next minor\nand bug fix release.\n\nPRs that resolves issues are released in the next release. PRs that introduce\nnew features are held for the next minor release. Users can view what\n[GitHub milestones][] a PR belongs to to determine the release it will go out\nwith.\n\n[Google Calendar]: https://calendar.google.com/calendar/embed?src=c_03d981cefd8d6432894cb162da5c6186e393bc0f970ca6c371201aa05d30d763%40group.calendar.google.com\n[GitHub milestones]: https://github.com/influxdata/telegraf/milestones\n\n## How can I filter or select specific metrics?\n\nTelegraf has options to select certain metrics or tags as well as filter out\nspecific tags or fields:\n\n- **Selectors** allow a user to include or exclude entire metrics based on the\n  metric name or tag key/pair values.\n- **Modifiers** allow a user to remove tags and fields based on specific keys,\n  with glob support.\n\nFor more details and examples, see the [Metric Filtering][metric filtering]\nsection in the docs.\n\n## Could not find a usable config.yml, you may have revoked the CircleCI OAuth app\n\nThis is an error from CircleCI during test runs.\n\nTo resolve the error, you need to log back into CircleCI with your\nusername/password if that is how you log in or if you use GitHub log, re-create\nyour oauth/re-login with github.\n\nThat should regenerate your token and then allow you to push a commit or close\nand reopen this PR and tests should run.\n\n## What does \"Context Deadline exceeded (Client.Timeout while awaiting headers)\" mean?\n\nThis is a generic error received from Go's HTTP client. It is generally the\nresult of a network blip or hiccup as a result of a DNS, proxy, firewall,\nand/or other network issue.\n\nThe error should be temporary and Telegraf will recover shortly after without\nthe loss of data.\n\n## How do I set the timestamp format for parsing data?\n\nTelegraf's `timestamp_format` config option requires the use\n[Go's reference time][go ref time] to correctly translate the timestamp. For\nexample, if you have the time:\n\n```s\n2023-03-01T00:00:42.586+0800\n```\n\nA user needs the timestamp format:\n\n```s\n2006-01-02T15:04:05.000-0700\n```\n\nUser's can try this out in the [Go playground][playground].\n\n[go ref time]: https://pkg.go.dev/time#pkg-constants\n[playground]: https://goplay.tools/snippet/hi9GIOG_gVQ\n\n## Q: How can I monitor the Docker Engine Host from within a container?\n\nYou will need to setup several volume mounts as well as some environment\nvariables:\n\n```shell\ndocker run --name telegraf \\\n    -v /:/hostfs:ro \\\n    -e HOST_ETC=/hostfs/etc \\\n    -e HOST_PROC=/hostfs/proc \\\n    -e HOST_SYS=/hostfs/sys \\\n    -e HOST_VAR=/hostfs/var \\\n    -e HOST_RUN=/hostfs/run \\\n    -e HOST_MOUNT_PREFIX=/hostfs \\\n    telegraf\n```\n\n## Q: Why do I get a \"no such host\" error resolving hostnames that other programs can resolve?\n\nGo uses a pure Go resolver by default for [name resolution](https://golang.org/pkg/net/#hdr-Name_Resolution).\nThis resolver behaves differently than the C library functions but is more\nefficient when used with the Go runtime.\n\nIf you encounter problems or want to use more advanced name resolution methods\nthat are unsupported by the pure Go resolver, you can switch to the cgo\nresolver.\n\nIf running manually set:\n\n```shell\nexport GODEBUG=netdns=cgo\n```\n\nIf running as a service add the environment variable to `/etc/default/telegraf`:\n\n```shell\nGODEBUG=netdns=cgo\n```\n\n## Q: How can I manage series cardinality?\n\nHigh [series cardinality][], when not properly managed, can cause high load on\nyour database.  Telegraf attempts to avoid creating series with high\ncardinality, but some monitoring workloads such as tracking containers are are\ninherently high cardinality.  These workloads can still be monitored, but care\nmust be taken to manage cardinality growth.\n\nYou can use the following techniques to avoid cardinality issues:\n\n- Use [metric filtering][] options to exclude unneeded measurements and tags.\n- Write to a database with an appropriate [retention policy][].\n- Consider using the [Time Series Index][tsi].\n- Monitor your databases using the [show cardinality][] commands.\n- Consult the [InfluxDB documentation][influx docs] for the most up-to-date techniques.\n\n[series cardinality]: https://docs.influxdata.com/influxdb/v1.7/concepts/glossary/#series-cardinality\n[metric filtering]: https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md#metric-filtering\n[retention policy]: https://docs.influxdata.com/influxdb/latest/guides/downsampling_and_retention/\n[tsi]: https://docs.influxdata.com/influxdb/latest/concepts/time-series-index/\n[show cardinality]: https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality\n[influx docs]: https://docs.influxdata.com/influxdb/latest/\n"
  },
  {
    "path": "docs/INPUTS.md",
    "content": "# Input Plugins\n\nThis section is for developers who want to create new collection inputs.\nTelegraf is entirely plugin driven. This interface allows for operators to\npick and chose what is gathered and makes it easy for developers\nto create new ways of generating metrics.\n\nPlugin authorship is kept as simple as possible to promote people to develop\nand submit new inputs.\n\n## Input Plugin Guidelines\n\n- A plugin must conform to the [telegraf.Input][] interface.\n- Input Plugins should call `inputs.Add` in their `init` function to register\n  themselves.  See below for a quick example.\n- To be available within Telegraf itself, plugins must register themselves\n  using a file in `github.com/influxdata/telegraf/plugins/inputs/all` named\n  according to the plugin name. Make sure you also add build-tags to\n  conditionally build the plugin.\n- Each plugin requires a file called `sample.conf` containing the sample\n  configuration  for the plugin in TOML format.\n  Please consult the [Sample Config][] page for the latest style guidelines.\n- Each plugin `README.md` file should include the `sample.conf` file in a\n  section describing the configuration by specifying a `toml` section in the\n  form `toml @sample.conf`. The specified file(s) are then injected\n  automatically into the Readme.\n- Follow the recommended [Code Style][].\n\n[Sample Config]: /docs/developers/SAMPLE_CONFIG.md\n[Code Style]: /docs/developers/CODE_STYLE.md\n[telegraf.Input]: https://godoc.org/github.com/influxdata/telegraf#Input\n\n### Typed Metrics\n\nIn addition to the `AddFields` function, the accumulator also supports\nfunctions to add typed metrics: `AddGauge`, `AddCounter`, etc.  Metric types\nare ignored by the InfluxDB output, but can be used for other outputs, such as\n[prometheus][prom metric types].\n\n[prom metric types]: https://prometheus.io/docs/concepts/metric_types/\n\n### Data Formats\n\nSome input plugins, such as the [exec][] plugin, can accept any supported\n[input data formats][].\n\nIn order to enable this, you must specify a `SetParser(parser parsers.Parser)`\nfunction on the plugin object (see the exec plugin for an example), as well as\ndefining `parser` as a field of the object.\n\nYou can then utilize the parser internally in your plugin, parsing data as you\nsee fit. Telegraf's configuration layer will take care of instantiating and\ncreating the `Parser` object.\n\nAdd the following to the sample configuration in the README.md:\n\n```toml\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n[exec]: /plugins/inputs/exec\n[input data formats]: /docs/DATA_FORMATS_INPUT.md\n\n### Service Input Plugins\n\nThis section is for developers who want to create new \"service\" collection\ninputs. A service plugin differs from a regular plugin in that it operates a\nbackground service while Telegraf is running. One example would be the\n`statsd` plugin, which operates a statsd server.\n\nService Input Plugins are substantially more complicated than a regular\nplugin, as they will require threads and locks to verify data integrity.\nService Input Plugins should be avoided unless there is no way to create their\nbehavior with a regular plugin.\n\nTo create a Service Input implement the [telegraf.ServiceInput][] interface.\n\n[telegraf.ServiceInput]: https://godoc.org/github.com/influxdata/telegraf#ServiceInput\n\n### Metric Tracking\n\nMetric Tracking provides a system to be notified when metrics have been\nsuccessfully written to their outputs or otherwise discarded.  This allows\ninputs to be created that function as reliable queue consumers.\n\nPlease note that this process applies only to internal plugins. For external\nplugins, the metrics are acknowledged regardless of the actual output.\n\nTo get started with metric tracking begin by calling `WithTracking` on the\n[telegraf.Accumulator][].  Add metrics using the `AddTrackingMetricGroup`\nfunction on the returned [telegraf.TrackingAccumulator][] and store the\n`TrackingID`.  The `Delivered()` channel will return a type with information\nabout the final delivery status of the metric group.\n\nCheck the [amqp_consumer][] for an example implementation.\n\n[telegraf.Accumulator]: https://godoc.org/github.com/influxdata/telegraf#Accumulator\n[telegraf.TrackingAccumulator]: https://godoc.org/github.com/influxdata/telegraf#Accumulator\n[amqp_consumer]: /plugins/inputs/amqp_consumer\n\n### External Services\n\nPlugins that connect or require the use of external services should ensure that\nthose servers are active. When may depend on the type of input plugin:\n\nFor service input plugins, `Init` should be used to check for configuration\nissues (e.g. bad option) and for other non-recoverable errors. Then `Start`\nis used to create connections or other retry-able operations.\n\nFor normal inputs, `Init` should also be used to check for configuration issues\nas well as any other dependencies that the plugin will require. For example,\nany binaries that must exist for the plugin to function. If making a connection,\nthis should also take place in `Init`.\n\nDevelopers may find that they switch to using service input plugins more and\nmore to take advantage of the error on retry behavior features. This allows\nthe user to decide what to do on an error, like ignoring the plugin or retrying\nconstantly.\n\n## Input Plugin Example\n\nLet's say you've written a plugin that emits metrics about processes on the\ncurrent host.\n\n### Register Plugin\n\nRegistration of the plugin on `plugins/inputs/all/simple.go`:\n\n```go\n//go:build !custom || inputs || inputs.simple\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/simple\" // register plugin\n```\n\nThe _build-tags_ in the first line allow to selectively include/exclude your\nplugin when customizing Telegraf.\n\n### Plugin\n\nContent of your plugin file e.g. `simple.go`\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage simple\n\nimport (\n    _ \"embed\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Simple struct {\n    Ok  bool            `toml:\"ok\"`\n    Log telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Simple) SampleConfig() string {\n    return sampleConfig\n}\n\n// Init is for setup, and validating config.\nfunc (s *Simple) Init() error {\n    return nil\n}\n\nfunc (s *Simple) Gather(acc telegraf.Accumulator) error {\n    if s.Ok {\n        acc.AddFields(\"state\", map[string]interface{}{\"value\": \"pretty good\"}, nil)\n    } else {\n        acc.AddFields(\"state\", map[string]interface{}{\"value\": \"not great\"}, nil)\n    }\n\n    return nil\n}\n\nfunc init() {\n    inputs.Add(\"simple\", func() telegraf.Input { return &Simple{} })\n}\n```\n"
  },
  {
    "path": "docs/INSTALL_GUIDE.md",
    "content": "# Installation\n\nTelegraf compiles to a single static binary, which makes it easy to install.\nBoth InfluxData and the community provide for a wide range of methods to install\nTelegraf from. For details on each release, view the [changelog][] for the\nlatest updates and changes by version.\n\n[changelog]: /CHANGELOG.md\n\nThere are many places to obtain Telegraf from:\n\n* [Binary downloads](#binary-downloads)\n* [Homebrew](#homebrew)\n* [InfluxData Linux package repository](#influxdata-linux-package-repository)\n* [Official Docker images](#official-docker-images)\n* [Helm charts](#helm-charts)\n* [Nightly builds](#nightly-builds)\n* [Build from source](#build-from-source)\n* [Custom builder](#custom-builder)\n\n## Binary downloads\n\nBinary downloads for a wide range of architectures and operating systems are\navailable from the [InfluxData downloads][] page or from the\n[GitHub Releases][] page.\n\n[InfluxData downloads]: https://www.influxdata.com/downloads\n[GitHub Releases]: https://github.com/influxdata/telegraf/releases\n\n## Homebrew\n\nA [Homebrew Formula][] for Telegraf that updates after each release:\n\n```shell\nbrew update\nbrew install telegraf\n```\n\nNote that the Homebrew organization builds Telegraf itself and does not use\nbinaries built by InfluxData. This is important as Homebrew builds with CGO,\nwhich means there are some differences between the official binaries and those\nfound with Homebrew.\n\n[Homebrew Formula]: https://formulae.brew.sh/formula/telegraf\n\n## InfluxData Linux package repository\n\nInfluxData provides a package repo that contains both DEB and RPM packages.\n\n### DEB\n\nFor DEB-based platforms (e.g. Ubuntu and Debian) run the following to add the\nrepo GPG key and setup a new sources.list entry:\n\n```shell\n# influxdata-archive.key GPG fingerprint:\n#   Primary key fingerprint: 24C9 75CB A61A 024E E1B6  3178 7C3D 5715 9FC2 F927\n#   Subkey fingerprint:      9D53 9D90 D332 8DC7 D6C8  D3B9 D8FF 8E1F 7DF8 B07E\nwget -q https://repos.influxdata.com/influxdata-archive.key\ngpg --show-keys --with-fingerprint --with-colons ./influxdata-archive.key 2>&1 | grep -q '^fpr:\\+24C975CBA61A024EE1B631787C3D57159FC2F927:$' && cat influxdata-archive.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg > /dev/null\necho 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' | sudo tee /etc/apt/sources.list.d/influxdata.list\nsudo apt-get update && sudo apt-get install telegraf\n```\n\n### RPM\n\nFor RPM-based platforms (e.g. RHEL, CentOS) use the following to create a repo\nfile and install telegraf:\n\n```shell\n# influxdata-archive.key GPG fingerprint:\n#   Primary key fingerprint: 24C9 75CB A61A 024E E1B6  3178 7C3D 5715 9FC2 F927\n#   Subkey fingerprint:      9D53 9D90 D332 8DC7 D6C8  D3B9 D8FF 8E1F 7DF8 B07E\ncat <<EOF | sudo tee /etc/yum.repos.d/influxdata.repo\n[influxdata]\nname = InfluxData Repository - Stable\nbaseurl = https://repos.influxdata.com/stable/\\$basearch/main\nenabled = 1\ngpgcheck = 1\ngpgkey = https://repos.influxdata.com/influxdata-archive.key\nEOF\nsudo yum install telegraf\n```\n\n## Official Docker images\n\nTelegraf is available as an [Official image][] on DockerHub. Official images\nare a curated set of Docker Images that also automatically get security updates\nfrom Docker, follow a set of best practices, and are available via a shortcut\nsyntax which omits the organization.\n\nInfluxData maintains a Debian and Alpine based image across the last three\nminor releases. To pull the latest Telegraf images:\n\n```shell\n# latest Debian-based image\ndocker pull telegraf\n# latest Alpine-based image\ndocker pull telegraf:alpine\n```\n\nSee the [Telegraf DockerHub][] page for complete details on available images,\nversions, and tags.\n\n[official image]: https://docs.docker.com/trusted-content/official-images/\n[Telegraf DockerHub]: https://hub.docker.com/_/telegraf\n\n## Helm charts\n\nA community-supported [helm chart][] is also available:\n\n```shell\nhelm repo add influxdata https://helm.influxdata.com/\nhelm search repo influxdata\n```\n\n[helm chart]: https://github.com/influxdata/helm-charts/tree/master/charts/telegraf\n\n## Nightly builds\n\n[Nightly builds][] are available and are generated from the master branch each\nday at around midnight UTC. The artifacts include both binary packages, RPM &\nDEB packages, as well as nightly Docker images that are hosted on [quay.io][].\n\n[Nightly builds]: /docs/NIGHTLIES.md\n[quay.io]: https://quay.io/repository/influxdb/telegraf-nightly?tab=tags&tag=latest\n\n## Build from source\n\nTelegraf generally follows the latest version of Go and requires GNU make to use\nthe Makefile for builds.\n\nOn Windows, the makefile requires the use of a bash terminal to support all\nmakefile targets. An easy option to get bash for windows is using the version\nthat comes with [git for windows](https://gitforwindows.org/).\n\n1. [Install Go](https://golang.org/doc/install)\n2. Clone the Telegraf repository:\n\n   ```shell\n   git clone https://github.com/influxdata/telegraf.git\n   ```\n\n3. Run `make build` from the source directory\n\n   ```shell\n   cd telegraf\n   make build\n   ```\n\n## Custom builder\n\nTelegraf also provides a way of building a custom minimized binary using the\n[custom builder][]. This takes a user's configuration file(s), determines what\nplugins are required, and builds a binary with only those plugins. This greatly\nreduces the size of the Telegraf binary.\n\n[custom builder]: /tools/custom_builder\n"
  },
  {
    "path": "docs/INTEGRATION_TESTS.md",
    "content": "# Integration Tests\n\n## Running\n\nTo run all named integration tests:\n\n```shell\nmake test-integration\n```\n\nTo run all tests, including unit and integration tests:\n\n```shell\ngo test -count 1 -race ./...\n```\n\n## Developing\n\nTo run integration tests against a service the project uses\n[testcontainers][1]. The makes it very easy to create and cleanup\ncontainer-based tests.\n\nThe `testutil/container.go` has a `Container` type that wraps this project to\neasily create containers for testing in Telegraf. A typical test looks like\nthe following:\n\n```go\nservicePort := \"5432\"\n\ncontainer := testutil.Container{\n    Image:        \"postgres:alpine\",\n    ExposedPorts: []string{servicePort},\n    Env: map[string]string{\n        \"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n    },\n    WaitingFor: wait.ForAll(\n        wait.ForLog(\"database system is ready to accept connections\"),\n        wait.ForListeningPort(nat.Port(servicePort)),\n    ),\n}\n\nerr := container.Start()\nrequire.NoError(t, err, \"failed to start container\")\n\ndefer func() {\n    require.NoError(t, container.Terminate(), \"terminating container failed\")\n}()\n```\n\nUser's should start the container and then defer termination of the container.\n\nThe `test.Container` type requires at least an image, ports to expose, and a\nwait stanza. See the following to learn more:\n\n### Images\n\nImages are pulled from [DockerHub][2] by default. When looking for and\nselecting an image from DockerHub, please use the following priority order:\n\n1. [Official Images][3]: these images are generally produced by the publisher\n  themselves and are fully supported with great documentation. These images are\n  easy to spot as they do not have an author in the name (e.g. \"mysql\")\n2. Publisher produced: not all software has an entry in the above Official\n  Images. This may be due to the project being smaller or moving faster. In\n  this case, pull directly from the publisher's DockerHub whenever possible.\n3. Other images: If, and only if, none of the above images will work for a\n  particular use-case, then another image can be used. Be prepared to justify,\n  the use of these types of images.\n\n### Ports\n\nWhen the port is specified as a single value (e.g. `11211`) then testcontainers\nwill generate a random port for the service to start on. This way multiple\ntests can be run and prevent ports from conflicting.\n\nThe test container will expect an array of ports to expose for testing. For\nmost tests only a single port is used, but a user can specify more than one\nto allow for testing if another port is open for example.\n\nOn each container's DockerHub page, the README will usually specify what ports\nare used by the container by default. For many containers this port can be\nchanged or specified with an environment variable.\n\nIf no ports are specified, a user can view the image tag and view the various\nimage layers. Find an image layer with the `EXPOSE` keyword to determine what\nports are used by the container.\n\n### Wait Stanza\n\nThe wait stanza lays out what test containers will wait for to determine that\nthe container has started and is ready for use by the test. It is best to\nprovide not only a port, but also a log message. Ports can come up very early\nin the container, and the service may not be ready.\n\nTo find a good log message, it is suggested to launch the container manually\nand see what the final message is printed. Usually this is something to the\neffect of \"ready for connections\" or \"setup complete\". Also ensure that this\nmessage only shows up once, or the use of the\n\n### Other Parameters\n\nThere are other optional parameters that user can make use of for additional\nconfiguration of the test containers:\n\n- `BindMounts`: used to mount local test data into the container. The order is\n  location in the container as the key and the local file as the value.\n- `Entrypoint`: if a user wishes to override the entrypoint with a custom\n  command\n- `Env`: to pass environmental variables to the container similar to Docker\n  CLI's `--env` option\n- `Name`: if a container needs a hostname set or expects a certain name use\n  this option to set the containers hostname\n- `Networks`: if the user creates a custom network\n\n[1]: <https://golang.testcontainers.org/> \"testcontainers-go\"\n[2]: <https://hub.docker.com/> \"DockerHub\"\n[3]: <https://hub.docker.com/search?q=&type=image&image_filter=official> \"DockerHub Official Images\"\n\n## Network\n\nBy default the containers will use the bridge network where other containers\ncannot talk to each other.\n\nIf a custom network is required for running tests, for example if containers\ndo need to communicate, then users can set that up with the following code:\n\n```go\nnetworkName := \"test-network\"\nnet, err := testcontainers.GenericNetwork(ctx, testcontainers.GenericNetworkRequest{\n    NetworkRequest: testcontainers.NetworkRequest{\n        Name:           networkName,\n        Attachable:     true,\n        CheckDuplicate: true,\n    },\n})\nrequire.NoError(t, err)\ndefer func() {\n    require.NoError(t, net.Remove(ctx), \"terminating network failed\")\n}()\n```\n\nThen specify the network name in the container startup:\n\n```go\nzookeeper := testutil.Container{\n    Image:        \"wurstmeister/zookeeper\",\n    ExposedPorts: []string{\"2181:2181\"},\n    Networks:     []string{networkName},\n    WaitingFor:   wait.ForLog(\"binding to port\"),\n    Name:         \"telegraf-test-zookeeper\",\n}\n```\n\n## Contributing\n\nWhen adding integrations tests please do the following:\n\n- Add integration to the end of the test name\n- Use testcontainers when an external service is required\n- Use the testutil.Container to setup and configure testcontainers\n- Ensure the testcontainer wait stanza is well-tested\n"
  },
  {
    "path": "docs/LICENSE_OF_DEPENDENCIES.md",
    "content": "<!-- markdownlint-disable MD013 -->\n# Licenses of dependencies\n\nWhen distributed in a binary form, Telegraf may contain portions of the\nfollowing works:\n\n- cel.dev/expr [Apache License 2.0](https://github.com/google/cel-spec/blob/master/LICENSE)\n- cloud.google.com/go [Apache License 2.0](https://github.com/googleapis/google-cloud-go/blob/master/LICENSE)\n- code.cloudfoundry.org/clock [Apache License 2.0](https://github.com/cloudfoundry/clock/blob/master/LICENSE)\n- collectd.org [ISC License](https://github.com/collectd/go-collectd/blob/master/LICENSE)\n- dario.cat/mergo [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/imdario/mergo/blob/master/LICENSE)\n- filippo.io/edwards25519 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/FiloSottile/edwards25519/blob/main/LICENSE)\n- github.com/99designs/keyring [MIT License](https://github.com/99designs/keyring/blob/master/LICENSE)\n- github.com/Azure/azure-amqp-common-go [MIT License](https://github.com/Azure/azure-amqp-common-go/blob/master/LICENSE)\n- github.com/Azure/azure-event-hubs-go [MIT License](https://github.com/Azure/azure-event-hubs-go/blob/master/LICENSE)\n- github.com/Azure/azure-kusto-go [MIT License](https://github.com/Azure/azure-kusto-go/blob/master/LICENSE)\n- github.com/Azure/azure-pipeline-go [MIT License](https://github.com/Azure/azure-pipeline-go/blob/master/LICENSE)\n- github.com/Azure/azure-sdk-for-go [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/LICENSE.txt)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- github.com/Azure/azure-storage-queue-go [MIT License](https://github.com/Azure/azure-storage-queue-go/blob/master/LICENSE)\n- github.com/Azure/go-amqp [MIT License](https://github.com/Azure/go-amqp/blob/master/LICENSE)\n- github.com/Azure/go-ansiterm [MIT License](https://github.com/Azure/go-ansiterm/blob/master/LICENSE)\n- github.com/Azure/go-autorest [Apache License 2.0](https://github.com/Azure/go-autorest/blob/master/LICENSE)\n- github.com/Azure/go-ntlmssp [MIT License](https://github.com/Azure/go-ntlmssp/blob/master/LICENSE)\n- github.com/AzureAD/microsoft-authentication-library-for-go [MIT License](https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/main/LICENSE)\n- github.com/BurntSushi/toml [MIT License](https://github.com/BurntSushi/toml/blob/master/COPYING)\n- github.com/ClickHouse/ch-go [Apache License 2.0](https://github.com/ClickHouse/ch-go/blob/main/LICENSE)\n- github.com/ClickHouse/clickhouse-go [Apache License 2.0](https://github.com/ClickHouse/clickhouse-go/blob/master/LICENSE)\n- github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE)\n- github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE)\n- github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE)\n- github.com/IBM/nzgo [MIT License](https://github.com/IBM/nzgo/blob/master/LICENSE.md)\n- github.com/IBM/sarama [MIT License](https://github.com/IBM/sarama/blob/master/LICENSE.md)\n- github.com/Masterminds/goutils [Apache License 2.0](https://github.com/Masterminds/goutils/blob/master/LICENSE.txt)\n- github.com/Masterminds/semver [MIT License](https://github.com/Masterminds/semver/blob/master/LICENSE.txt)\n- github.com/Masterminds/sprig [MIT License](https://github.com/Masterminds/sprig/blob/master/LICENSE.txt)\n- github.com/Max-Sum/base32768 [MIT License](https://github.com/Max-Sum/base32768/blob/master/LICENSE)\n- github.com/Mellanox/rdmamap [Apache License 2.0](https://github.com/Mellanox/rdmamap/blob/master/LICENSE)\n- github.com/Microsoft/go-winio [MIT License](https://github.com/Microsoft/go-winio/blob/master/LICENSE)\n- github.com/PaesslerAG/gval [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/PaesslerAG/gval/blob/master/LICENSE)\n- github.com/SAP/go-hdb [Apache License 2.0](https://github.com/SAP/go-hdb/blob/main/LICENSE.md)\n- github.com/abbot/go-http-auth [Apache License 2.0](https://github.com/abbot/go-http-auth/blob/master/LICENSE)\n- github.com/aerospike/aerospike-client-go [Apache License 2.0](https://github.com/aerospike/aerospike-client-go/blob/master/LICENSE)\n- github.com/alecthomas/participle [MIT License](https://github.com/alecthomas/participle/blob/master/COPYING)\n- github.com/alecthomas/units [MIT License](https://github.com/alecthomas/units/blob/master/COPYING)\n- github.com/alitto/pond [MIT License](https://github.com/alitto/pond/blob/master/LICENSE)\n- github.com/aliyun/alibaba-cloud-sdk-go [Apache License 2.0](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/LICENSE)\n- github.com/amir/raidman [The Unlicense](https://github.com/amir/raidman/blob/master/UNLICENSE)\n- github.com/andybalholm/brotli [MIT License](https://github.com/andybalholm/brotli/blob/master/LICENSE)\n- github.com/antchfx/jsonquery [MIT License](https://github.com/antchfx/jsonquery/blob/master/LICENSE)\n- github.com/antchfx/xmlquery [MIT License](https://github.com/antchfx/xmlquery/blob/master/LICENSE)\n- github.com/antchfx/xpath [MIT License](https://github.com/antchfx/xpath/blob/master/LICENSE)\n- github.com/antithesishq/antithesis-sdk-go [MIT License](https://github.com/antithesishq/antithesis-sdk-go/blob/main/LICENSE)\n- github.com/antlr4-go/antlr [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/antlr/antlr4/blob/master/LICENSE.txt)\n- github.com/apache/arrow-go [Apache License 2.0](https://github.com/apache/arrow-go/blob/main/LICENSE.txt)\n- github.com/apache/arrow/go [Apache License 2.0](https://github.com/apache/arrow/blob/master/LICENSE.txt)\n- github.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang [Apache License 2.0](https://github.com/apache/inlong/blob/master/LICENSE)\n- github.com/apache/iotdb-client-go [Apache License 2.0](https://github.com/apache/iotdb-client-go/blob/main/LICENSE)\n- github.com/apache/thrift [Apache License 2.0](https://github.com/apache/thrift/blob/master/LICENSE)\n- github.com/apapsch/go-jsonmerge [MIT License](https://github.com/apapsch/go-jsonmerge/blob/master/LICENSE)\n- github.com/aristanetworks/glog [Apache License 2.0](https://github.com/aristanetworks/glog/blob/master/LICENSE)\n- github.com/aristanetworks/goarista [Apache License 2.0](https://github.com/aristanetworks/goarista/blob/master/COPYING)\n- github.com/armon/go-metrics [MIT License](https://github.com/armon/go-metrics/blob/master/LICENSE)\n- github.com/awnumar/memcall [Apache License 2.0](https://github.com/awnumar/memcall/blob/master/LICENSE)\n- github.com/awnumar/memguard [Apache License 2.0](https://github.com/awnumar/memguard/blob/master/LICENSE)\n- github.com/aws/aws-msk-iam-sasl-signer-go [Apache License 2.0](https://github.com/aws/aws-msk-iam-sasl-signer-go/blob/main/LICENSE)\n- github.com/aws/aws-sdk-go-v2 [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/LICENSE.txt)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- 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)\n- github.com/aws/aws-sdk-go-v2/service/signin [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/signin/LICENSE.txt)\n- 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)\n- 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)\n- 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)\n- 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)\n- github.com/aws/smithy-go [Apache License 2.0](https://github.com/aws/smithy-go/blob/main/LICENSE)\n- github.com/benbjohnson/clock [MIT License](https://github.com/benbjohnson/clock/blob/master/LICENSE)\n- github.com/beorn7/perks [MIT License](https://github.com/beorn7/perks/blob/master/LICENSE)\n- github.com/bluenviron/gomavlib [MIT License](https://github.com/bluenviron/gomavlib/blob/main/LICENSE)\n- github.com/blues/jsonata-go [MIT License](https://github.com/blues/jsonata-go/blob/main/LICENSE)\n- github.com/bmatcuk/doublestar [MIT License](https://github.com/bmatcuk/doublestar/blob/master/LICENSE)\n- github.com/boschrexroth/ctrlx-datalayer-golang [MIT License](https://github.com/boschrexroth/ctrlx-datalayer-golang/blob/main/LICENSE)\n- github.com/brutella/dnssd [MIT License](https://github.com/brutella/dnssd/blob/master/LICENSE)\n- github.com/bufbuild/protocompile [Apache License 2.0](https://github.com/bufbuild/protocompile/blob/main/LICENSE)\n- github.com/bwmarrin/snowflake [BSD 2-Clause \"Simplified\" License](https://github.com/bwmarrin/snowflake/blob/master/LICENSE)\n- github.com/caio/go-tdigest [MIT License](https://github.com/caio/go-tdigest/blob/master/LICENSE)\n- github.com/cenkalti/backoff [MIT License](https://github.com/cenkalti/backoff/blob/master/LICENSE)\n- github.com/cespare/xxhash [MIT License](https://github.com/cespare/xxhash/blob/master/LICENSE.txt)\n- github.com/cisco-ie/nx-telemetry-proto [Apache License 2.0](https://github.com/cisco-ie/nx-telemetry-proto/blob/master/LICENSE)\n- github.com/clarify/clarify-go [Apache License 2.0](https://github.com/clarify/clarify-go/blob/master/LICENSE)\n- github.com/clipperhouse/uax29 [MIT License](https://github.com/clipperhouse/uax29/blob/master/LICENSE)\n- github.com/cloudevents/sdk-go [Apache License 2.0](https://github.com/cloudevents/sdk-go/blob/main/LICENSE)\n- github.com/cncf/xds/go [Apache License 2.0](https://github.com/cncf/xds/blob/main/LICENSE)\n- github.com/compose-spec/compose-go [Apache License 2.0](https://github.com/compose-spec/compose-go/blob/master/LICENSE)\n- github.com/containerd/errdefs [Apache License 2.0](https://github.com/containerd/errdefs/blob/main/LICENSE)\n- github.com/containerd/errdefs/pkg [Apache License 2.0](https://github.com/containerd/errdefs/blob/main/LICENSE)\n- github.com/containerd/log [Apache License 2.0](https://github.com/containerd/log/blob/main/LICENSE)\n- github.com/containerd/platforms [Apache License 2.0](https://github.com/containerd/platforms/blob/main/LICENSE)\n- github.com/coocood/freecache [MIT License](https://github.com/coocood/freecache/blob/master/LICENSE)\n- github.com/coreos/go-semver [Apache License 2.0](https://github.com/coreos/go-semver/blob/main/LICENSE)\n- github.com/coreos/go-systemd [Apache License 2.0](https://github.com/coreos/go-systemd/blob/main/LICENSE)\n- github.com/couchbase/go-couchbase [MIT License](https://github.com/couchbase/go-couchbase/blob/master/LICENSE)\n- github.com/couchbase/gomemcached [MIT License](https://github.com/couchbase/gomemcached/blob/master/LICENSE)\n- github.com/couchbase/goutils [Apache License 2.0](https://github.com/couchbase/goutils/blob/master/LICENSE.md)\n- github.com/cpuguy83/dockercfg [MIT License](https://github.com/cpuguy83/dockercfg/blob/main/LICENSE)\n- github.com/cpuguy83/go-md2man [MIT License](https://github.com/cpuguy83/go-md2man/blob/master/LICENSE.md)\n- github.com/creack/goselect [MIT License](https://github.com/creack/goselect/blob/master/LICENSE)\n- github.com/danieljoos/wincred [MIT License](https://github.com/danieljoos/wincred/blob/master/LICENSE)\n- github.com/datadope-io/go-zabbix [MIT License](https://github.com/datadope-io/go-zabbix/blob/master/LICENSE)\n- github.com/davecgh/go-spew [ISC License](https://github.com/davecgh/go-spew/blob/master/LICENSE)\n- github.com/devigned/tab [MIT License](https://github.com/devigned/tab/blob/master/LICENSE)\n- github.com/dgryski/go-rendezvous [MIT License](https://github.com/dgryski/go-rendezvous/blob/master/LICENSE)\n- github.com/digitalocean/go-libvirt [Apache License 2.0](https://github.com/digitalocean/go-libvirt/blob/master/LICENSE.md)\n- github.com/dimchansky/utfbom [Apache License 2.0](https://github.com/dimchansky/utfbom/blob/master/LICENSE)\n- github.com/distribution/reference [Apache License 2.0](https://github.com/distribution/reference/blob/main/LICENSE)\n- github.com/djherbis/times [MIT License](https://github.com/djherbis/times/blob/master/LICENSE)\n- github.com/docker/docker [Apache License 2.0](https://github.com/docker/docker/blob/master/LICENSE)\n- github.com/docker/go-connections [Apache License 2.0](https://github.com/docker/go-connections/blob/master/LICENSE)\n- github.com/docker/go-units [Apache License 2.0](https://github.com/docker/go-units/blob/master/LICENSE)\n- github.com/dustin/go-humanize [MIT License](https://github.com/dustin/go-humanize/blob/master/LICENSE)\n- github.com/dvsekhvalnov/jose2go [MIT License](https://github.com/dvsekhvalnov/jose2go/blob/master/LICENSE)\n- github.com/dynatrace-oss/dynatrace-metric-utils-go [Apache License 2.0](https://github.com/dynatrace-oss/dynatrace-metric-utils-go/blob/master/LICENSE)\n- github.com/eapache/go-resiliency [MIT License](https://github.com/eapache/go-resiliency/blob/master/LICENSE)\n- github.com/eapache/queue [MIT License](https://github.com/eapache/queue/blob/master/LICENSE)\n- github.com/ebitengine/purego [Apache License 2.0](https://github.com/ebitengine/purego/blob/main/LICENSE)\n- github.com/eclipse/paho.golang [Eclipse Public License - v 2.0](https://github.com/eclipse/paho.golang/blob/master/LICENSE)\n- github.com/eclipse/paho.mqtt.golang [Eclipse Public License - v 2.0](https://github.com/eclipse/paho.mqtt.golang/blob/master/LICENSE)\n- github.com/elastic/go-sysinfo [Apache License 2.0](https://github.com/elastic/go-sysinfo/blob/main/LICENSE.txt)\n- github.com/elastic/go-windows [Apache License 2.0](https://github.com/elastic/go-windows/blob/main/LICENSE.txt)\n- github.com/emiago/sipgo [BSD 2-Clause \"Simplified\" License](https://github.com/emiago/sipgo/blob/main/LICENSE)\n- github.com/emicklei/go-restful [MIT License](https://github.com/emicklei/go-restful/blob/v3/LICENSE)\n- github.com/envoyproxy/go-control-plane/envoy [Apache License 2.0](https://github.com/envoyproxy/go-control-plane/blob/main/LICENSE)\n- github.com/envoyproxy/protoc-gen-validate [Apache License 2.0](https://github.com/bufbuild/protoc-gen-validate/blob/main/LICENSE)\n- github.com/facebook/time [Apache License 2.0](https://github.com/facebook/time/blob/main/LICENSE)\n- github.com/fatih/color [MIT License](https://github.com/fatih/color/blob/master/LICENSE.md)\n- github.com/felixge/httpsnoop [MIT License](https://github.com/felixge/httpsnoop/blob/master/LICENSE.txt)\n- github.com/fxamacker/cbor [MIT License](https://github.com/fxamacker/cbor/blob/master/LICENSE)\n- github.com/gabriel-vasile/mimetype [MIT License](https://github.com/gabriel-vasile/mimetype/blob/master/LICENSE)\n- github.com/go-asn1-ber/asn1-ber [MIT License](https://github.com/go-asn1-ber/asn1-ber/blob/v1.3/LICENSE)\n- github.com/go-chi/chi [MIT License](https://github.com/go-chi/chi/blob/master/LICENSE)\n- github.com/go-faster/city [MIT License](https://github.com/go-faster/city/blob/main/LICENSE)\n- github.com/go-faster/errors [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/go-faster/errors/blob/main/LICENSE)\n- github.com/go-git/go-billy [Apache License 2.0](https://github.com/go-git/go-billy/blob/master/LICENSE)\n- github.com/go-jose/go-jose [Apache License 2.0](https://github.com/go-jose/go-jose/blob/main/LICENSE)\n- github.com/go-ldap/ldap [MIT License](https://github.com/go-ldap/ldap/blob/v3.4.1/LICENSE)\n- github.com/go-logfmt/logfmt [MIT License](https://github.com/go-logfmt/logfmt/blob/master/LICENSE)\n- github.com/go-logr/logr [Apache License 2.0](https://github.com/go-logr/logr/blob/master/LICENSE)\n- github.com/go-logr/stdr [Apache License 2.0](https://github.com/go-logr/stdr/blob/master/LICENSE)\n- github.com/go-ole/go-ole [MIT License](https://github.com/go-ole/go-ole/blob/master/LICENSE)\n- github.com/go-openapi/jsonpointer [Apache License 2.0](https://github.com/go-openapi/jsonpointer/blob/master/LICENSE)\n- github.com/go-openapi/jsonreference [Apache License 2.0](https://github.com/go-openapi/jsonreference/blob/master/LICENSE)\n- github.com/go-openapi/swag [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/cmdutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/conv [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/fileutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/jsonname [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/jsonutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/loading [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/mangling [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/netutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/stringutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/typeutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-openapi/swag/yamlutils [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE)\n- github.com/go-redis/redis [BSD 2-Clause \"Simplified\" License](https://github.com/go-redis/redis/blob/master/LICENSE)\n- github.com/go-resty/resty [MIT License](https://github.com/go-resty/resty/blob/v2/LICENSE)\n- github.com/go-sql-driver/mysql [Mozilla Public License 2.0](https://github.com/go-sql-driver/mysql/blob/master/LICENSE)\n- github.com/go-stack/stack [MIT License](https://github.com/go-stack/stack/blob/master/LICENSE.md)\n- github.com/go-stomp/stomp [Apache License 2.0](https://github.com/go-stomp/stomp/blob/master/LICENSE.txt)\n- github.com/go-viper/mapstructure [MIT License](https://github.com/go-viper/mapstructure/blob/main/LICENSE)\n- github.com/gobwas/glob [MIT License](https://github.com/gobwas/glob/blob/master/LICENSE)\n- github.com/gobwas/httphead [MIT License](https://github.com/gobwas/httphead/blob/master/LICENSE)\n- github.com/gobwas/pool [MIT License](https://github.com/gobwas/pool/blob/master/LICENSE)\n- github.com/gobwas/ws [MIT License](https://github.com/gobwas/ws/blob/master/LICENSE)\n- github.com/goccy/go-json [MIT License](https://github.com/goccy/go-json/blob/master/LICENSE)\n- github.com/godbus/dbus [BSD 2-Clause \"Simplified\" License](https://github.com/godbus/dbus/blob/master/LICENSE)\n- github.com/gofrs/uuid [MIT License](https://github.com/gofrs/uuid/blob/master/LICENSE)\n- github.com/gogo/protobuf [BSD 3-Clause Clear License](https://github.com/gogo/protobuf/blob/master/LICENSE)\n- github.com/golang-jwt/jwt [MIT License](https://github.com/golang-jwt/jwt/blob/main/LICENSE)\n- github.com/golang-sql/civil [Apache License 2.0](https://github.com/golang-sql/civil/blob/master/LICENSE)\n- github.com/golang-sql/sqlexp [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/golang-sql/sqlexp/blob/master/LICENSE)\n- github.com/golang/geo [Apache License 2.0](https://github.com/golang/geo/blob/master/LICENSE)\n- github.com/golang/groupcache [Apache License 2.0](https://github.com/golang/groupcache/blob/master/LICENSE)\n- github.com/golang/protobuf [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/golang/protobuf/blob/master/LICENSE)\n- github.com/golang/snappy [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/golang/snappy/blob/master/LICENSE)\n- github.com/google/cel-go [Apache License 2.0](https://github.com/google/cel-go/blob/master/LICENSE)\n- github.com/google/flatbuffers [Apache License 2.0](https://github.com/google/flatbuffers/blob/master/LICENSE)\n- github.com/google/gnostic-models [Apache License 2.0](https://github.com/google/gnostic-models/blob/master/LICENSE)\n- github.com/google/gnxi [Apache License 2.0](https://github.com/google/gnxi/blob/master/LICENSE)\n- github.com/google/go-cmp [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/google/go-cmp/blob/master/LICENSE)\n- github.com/google/go-github [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/google/go-github/blob/master/LICENSE)\n- github.com/google/go-querystring [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/google/go-querystring/blob/master/LICENSE)\n- github.com/google/go-tpm [Apache License 2.0](https://github.com/google/go-tpm/blob/main/LICENSE)\n- github.com/google/s2a-go [Apache License 2.0](https://github.com/google/s2a-go/blob/main/LICENSE.md)\n- github.com/google/uuid [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/google/uuid/blob/master/LICENSE)\n- github.com/googleapis/enterprise-certificate-proxy [Apache License 2.0](https://github.com/googleapis/enterprise-certificate-proxy/blob/main/LICENSE)\n- github.com/googleapis/gax-go [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/googleapis/gax-go/blob/master/LICENSE)\n- github.com/gopacket/gopacket [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/gopacket/gopacket/blob/master/LICENSE)\n- github.com/gopcua/opcua [MIT License](https://github.com/gopcua/opcua/blob/master/LICENSE)\n- github.com/gophercloud/gophercloud [Apache License 2.0](https://github.com/gophercloud/gophercloud/blob/master/LICENSE)\n- github.com/gorcon/rcon [MIT License](https://github.com/gorcon/rcon/blob/master/LICENSE)\n- github.com/gorilla/mux [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/gorilla/mux/blob/master/LICENSE)\n- github.com/gorilla/websocket [BSD 2-Clause \"Simplified\" License](https://github.com/gorilla/websocket/blob/master/LICENSE)\n- github.com/gosnmp/gosnmp [BSD 2-Clause \"Simplified\" License](https://github.com/gosnmp/gosnmp/blob/master/LICENSE)\n- github.com/grafana/regexp [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/grafana/regexp/blob/main/LICENSE)\n- github.com/grid-x/modbus [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/grid-x/modbus/blob/master/LICENSE)\n- github.com/grid-x/serial [MIT License](https://github.com/grid-x/serial/blob/master/LICENSE)\n- github.com/grpc-ecosystem/grpc-gateway [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE)\n- github.com/gsterjov/go-libsecret [MIT License](https://github.com/gsterjov/go-libsecret/blob/master/LICENSE)\n- github.com/gwos/tcg/sdk [MIT License](https://github.com/gwos/tcg/blob/master/LICENSE)\n- github.com/hailocab/go-hostpool [MIT License](https://github.com/hailocab/go-hostpool/blob/master/LICENSE)\n- github.com/hashicorp/consul/api [Mozilla Public License 2.0](https://github.com/hashicorp/consul/blob/main/api/LICENSE)\n- github.com/hashicorp/errwrap [Mozilla Public License 2.0](https://github.com/hashicorp/errwrap/blob/master/LICENSE)\n- github.com/hashicorp/go-cleanhttp [Mozilla Public License 2.0](https://github.com/hashicorp/go-cleanhttp/blob/master/LICENSE)\n- github.com/hashicorp/go-hclog [MIT License](https://github.com/hashicorp/go-hclog/blob/main/LICENSE)\n- github.com/hashicorp/go-immutable-radix [Mozilla Public License 2.0](https://github.com/hashicorp/go-immutable-radix/blob/master/LICENSE)\n- github.com/hashicorp/go-multierror [Mozilla Public License 2.0](https://github.com/hashicorp/go-multierror/blob/master/LICENSE)\n- github.com/hashicorp/go-retryablehttp [Mozilla Public License 2.0](https://github.com/hashicorp/go-retryablehttp/blob/main/LICENSE)\n- github.com/hashicorp/go-rootcerts [Mozilla Public License 2.0](https://github.com/hashicorp/go-rootcerts/blob/master/LICENSE)\n- github.com/hashicorp/go-secure-stdlib/parseutil [Mozilla Public License 2.0](https://github.com/hashicorp/go-secure-stdlib/blob/main/parseutil/LICENSE)\n- github.com/hashicorp/go-secure-stdlib/strutil [Mozilla Public License 2.0](https://github.com/hashicorp/go-secure-stdlib/blob/main/strutil/LICENSE)\n- github.com/hashicorp/go-sockaddr [Mozilla Public License 2.0](https://github.com/hashicorp/go-sockaddr/blob/master/LICENSE)\n- github.com/hashicorp/go-uuid [Mozilla Public License 2.0](https://github.com/hashicorp/go-uuid/blob/master/LICENSE)\n- github.com/hashicorp/go-version [Mozilla Public License 2.0](https://github.com/hashicorp/go-version/blob/main/LICENSE)\n- github.com/hashicorp/golang-lru [Mozilla Public License 2.0](https://github.com/hashicorp/golang-lru/blob/master/LICENSE)\n- github.com/hashicorp/hcl [Mozilla Public License 2.0](https://github.com/hashicorp/hcl/blob/main/LICENSE)\n- github.com/hashicorp/packer-plugin-sdk [Mozilla Public License 2.0](https://github.com/hashicorp/packer-plugin-sdk/blob/main/LICENSE)\n- github.com/hashicorp/serf [Mozilla Public License 2.0](https://github.com/hashicorp/serf/blob/master/LICENSE)\n- github.com/hashicorp/vault/api [Mozilla Public License 2.0](https://github.com/hashicorp/vault/blob/main/api/LICENSE)\n- github.com/hashicorp/vault/api/auth/approle [Mozilla Public License 2.0](https://github.com/hashicorp/vault/blob/main/api/auth/approle/LICENSE)\n- github.com/huandu/xstrings [MIT License](https://github.com/huandu/xstrings/blob/master/LICENSE)\n- github.com/icholy/digest [MIT License](https://github.com/icholy/digest/blob/master/LICENSE)\n- github.com/imdario/mergo [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/imdario/mergo/blob/master/LICENSE)\n- github.com/influxdata/influxdb-observability/common [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE)\n- github.com/influxdata/influxdb-observability/influx2otel [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE)\n- github.com/influxdata/influxdb-observability/otel2influx [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE)\n- github.com/influxdata/line-protocol [MIT License](https://github.com/influxdata/line-protocol/blob/v2/LICENSE)\n- github.com/influxdata/tail [MIT License](https://github.com/influxdata/tail/blob/master/LICENSE.txt)\n- github.com/influxdata/toml [MIT License](https://github.com/influxdata/toml/blob/master/LICENSE)\n- github.com/intel/iaevents [Apache License 2.0](https://github.com/intel/iaevents/blob/main/LICENSE)\n- github.com/intel/powertelemetry [Apache License 2.0](https://github.com/intel/powertelemetry/blob/main/LICENSE)\n- github.com/jackc/chunkreader [MIT License](https://github.com/jackc/chunkreader/blob/master/LICENSE)\n- github.com/jackc/pgconn [MIT License](https://github.com/jackc/pgconn/blob/master/LICENSE)\n- github.com/jackc/pgio [MIT License](https://github.com/jackc/pgio/blob/master/LICENSE)\n- github.com/jackc/pgpassfile [MIT License](https://github.com/jackc/pgpassfile/blob/master/LICENSE)\n- github.com/jackc/pgproto3 [MIT License](https://github.com/jackc/pgproto3/blob/master/LICENSE)\n- github.com/jackc/pgservicefile [MIT License](https://github.com/jackc/pgservicefile/blob/master/LICENSE)\n- github.com/jackc/pgtype [MIT License](https://github.com/jackc/pgtype/blob/master/LICENSE)\n- github.com/jackc/pgx [MIT License](https://github.com/jackc/pgx/blob/master/LICENSE)\n- github.com/jackc/puddle [MIT License](https://github.com/jackc/puddle/blob/master/LICENSE)\n- github.com/jaegertracing/jaeger [Apache License 2.0](https://github.com/jaegertracing/jaeger/blob/master/LICENSE)\n- github.com/jcmturner/aescts [Apache License 2.0](https://github.com/jcmturner/aescts/blob/master/LICENSE)\n- github.com/jcmturner/dnsutils [Apache License 2.0](https://github.com/jcmturner/dnsutils/blob/master/LICENSE)\n- github.com/jcmturner/gofork [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/jcmturner/gofork/blob/master/LICENSE)\n- github.com/jcmturner/goidentity [Apache License 2.0](https://github.com/jcmturner/goidentity/blob/master/LICENSE)\n- github.com/jcmturner/gokrb5 [Apache License 2.0](https://github.com/jcmturner/gokrb5/blob/master/LICENSE)\n- github.com/jcmturner/rpc [Apache License 2.0](https://github.com/jcmturner/rpc/blob/master/LICENSE)\n- github.com/jedib0t/go-pretty [MIT License](https://github.com/jedib0t/go-pretty/blob/main/LICENSE)\n- github.com/jeremywohl/flatten [MIT License](https://github.com/jeremywohl/flatten/blob/master/LICENSE)\n- github.com/jmespath/go-jmespath [Apache License 2.0](https://github.com/jmespath/go-jmespath/blob/master/LICENSE)\n- github.com/jmhodges/clock [MIT License](https://github.com/jmhodges/clock/blob/main/LICENSE)\n- github.com/joeshaw/multierror [MIT License](https://github.com/joeshaw/multierror/blob/master/LICENSE)\n- github.com/josharian/intern [MIT License](https://github.com/josharian/intern/blob/master/LICENSE.md)\n- github.com/josharian/native [MIT License](https://github.com/josharian/native/blob/main/license)\n- github.com/jpillora/backoff [MIT License](https://github.com/jpillora/backoff/blob/master/LICENSE)\n- github.com/json-iterator/go [MIT License](https://github.com/json-iterator/go/blob/master/LICENSE)\n- github.com/jzelinskie/whirlpool [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/jzelinskie/whirlpool/blob/master/LICENSE)\n- github.com/karrick/godirwalk [BSD 2-Clause \"Simplified\" License](https://github.com/karrick/godirwalk/blob/master/LICENSE)\n- github.com/kballard/go-shellquote [MIT License](https://github.com/kballard/go-shellquote/blob/master/LICENSE)\n- github.com/klauspost/compress [BSD 3-Clause Clear License](https://github.com/klauspost/compress/blob/master/LICENSE)\n- github.com/klauspost/cpuid [MIT License](https://github.com/klauspost/cpuid/blob/master/LICENSE)\n- github.com/klauspost/pgzip [MIT License](https://github.com/klauspost/pgzip/blob/master/LICENSE)\n- github.com/kolo/xmlrpc [MIT License](https://github.com/kolo/xmlrpc/blob/master/LICENSE)\n- github.com/kr/fs [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/kr/fs/blob/main/LICENSE)\n- github.com/kylelemons/godebug [Apache License 2.0](https://github.com/kylelemons/godebug/blob/master/LICENSE)\n- github.com/leodido/go-syslog [MIT License](https://github.com/influxdata/go-syslog/blob/develop/LICENSE)\n- github.com/leodido/ragel-machinery [MIT License](https://github.com/leodido/ragel-machinery/blob/develop/LICENSE)\n- github.com/likexian/gokit [Apache License 2.0](https://github.com/likexian/gokit/blob/master/LICENSE)\n- github.com/likexian/whois [Apache License 2.0](https://github.com/likexian/whois/blob/master/LICENSE)\n- github.com/likexian/whois-parser [Apache License 2.0](https://github.com/likexian/whois-parser/blob/master/LICENSE)\n- github.com/linkedin/goavro [Apache License 2.0](https://github.com/linkedin/goavro/blob/master/LICENSE)\n- github.com/logzio/azure-monitor-metrics-receiver [MIT License](https://github.com/logzio/azure-monitor-metrics-receiver/blob/master/LICENSE)\n- github.com/magiconair/properties [BSD 2-Clause \"Simplified\" License](https://github.com/magiconair/properties/blob/main/LICENSE.md)\n- github.com/mailru/easyjson [MIT License](https://github.com/mailru/easyjson/blob/master/LICENSE)\n- github.com/mattn/go-colorable [MIT License](https://github.com/mattn/go-colorable/blob/master/LICENSE)\n- github.com/mattn/go-ieproxy [MIT License](https://github.com/mattn/go-ieproxy/blob/master/LICENSE)\n- github.com/mattn/go-isatty [MIT License](https://github.com/mattn/go-isatty/blob/master/LICENSE)\n- github.com/mattn/go-runewidth [MIT License](https://github.com/mattn/go-runewidth/blob/master/LICENSE)\n- github.com/mdlayher/apcupsd [MIT License](https://github.com/mdlayher/apcupsd/blob/master/LICENSE.md)\n- github.com/mdlayher/genetlink [MIT License](https://github.com/mdlayher/genetlink/blob/master/LICENSE.md)\n- github.com/mdlayher/netlink [MIT License](https://github.com/mdlayher/netlink/blob/master/LICENSE.md)\n- github.com/mdlayher/socket [MIT License](https://github.com/mdlayher/socket/blob/master/LICENSE.md)\n- github.com/mdlayher/vsock [MIT License](https://github.com/mdlayher/vsock/blob/main/LICENSE.md)\n- github.com/microsoft/ApplicationInsights-Go [MIT License](https://github.com/microsoft/ApplicationInsights-Go/blob/master/LICENSE)\n- github.com/microsoft/go-mssqldb [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/microsoft/go-mssqldb/blob/master/LICENSE.txt)\n- github.com/miekg/dns [BSD 3-Clause Clear License](https://github.com/miekg/dns/blob/master/LICENSE)\n- github.com/minio/highwayhash [Apache License 2.0](https://github.com/minio/highwayhash/blob/master/LICENSE)\n- github.com/mitchellh/copystructure [MIT License](https://github.com/mitchellh/copystructure/blob/master/LICENSE)\n- github.com/mitchellh/go-homedir [MIT License](https://github.com/mitchellh/go-homedir/blob/master/LICENSE)\n- github.com/mitchellh/mapstructure [MIT License](https://github.com/mitchellh/mapstructure/blob/master/LICENSE)\n- github.com/mitchellh/reflectwalk [MIT License](https://github.com/mitchellh/reflectwalk/blob/master/LICENSE)\n- github.com/moby/docker-image-spec [Apache License 2.0](https://github.com/moby/docker-image-spec/blob/main/LICENSE)\n- github.com/moby/go-archive [Apache License 2.0](https://github.com/moby/go-archive/blob/main/LICENSE)\n- github.com/moby/ipvs [Apache License 2.0](https://github.com/moby/ipvs/blob/master/LICENSE)\n- github.com/moby/patternmatcher [Apache License 2.0](https://github.com/moby/patternmatcher/blob/main/LICENSE)\n- github.com/moby/sys/sequential [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE)\n- github.com/moby/sys/user [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE)\n- github.com/moby/sys/userns [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE)\n- github.com/moby/term [Apache License 2.0](https://github.com/moby/term/blob/master/LICENSE)\n- github.com/modern-go/concurrent [Apache License 2.0](https://github.com/modern-go/concurrent/blob/master/LICENSE)\n- github.com/modern-go/reflect2 [Apache License 2.0](https://github.com/modern-go/reflect2/blob/master/LICENSE)\n- github.com/montanaflynn/stats [MIT License](https://github.com/montanaflynn/stats/blob/master/LICENSE)\n- github.com/morikuni/aec [MIT License](https://github.com/morikuni/aec/blob/master/LICENSE)\n- github.com/mtibben/percent [MIT License](https://github.com/mtibben/percent/blob/master/LICENSE)\n- github.com/multiplay/go-ts3 [BSD 2-Clause \"Simplified\" License](https://github.com/multiplay/go-ts3/blob/master/LICENSE)\n- github.com/munnerz/goautoneg [BSD 3-Clause Clear License](https://github.com/munnerz/goautoneg/blob/master/LICENSE)\n- github.com/mwitkow/go-conntrack [Apache License 2.0](https://github.com/mwitkow/go-conntrack/blob/master/LICENSE)\n- github.com/naoina/go-stringutil [MIT License](https://github.com/naoina/go-stringutil/blob/master/LICENSE)\n- github.com/nats-io/jwt [Apache License 2.0](https://github.com/nats-io/jwt/blob/master/LICENSE)\n- github.com/nats-io/nats-server [Apache License 2.0](https://github.com/nats-io/nats-server/blob/master/LICENSE)\n- github.com/nats-io/nats.go [Apache License 2.0](https://github.com/nats-io/nats.go/blob/master/LICENSE)\n- github.com/nats-io/nkeys [Apache License 2.0](https://github.com/nats-io/nkeys/blob/master/LICENSE)\n- github.com/nats-io/nuid [Apache License 2.0](https://github.com/nats-io/nuid/blob/master/LICENSE)\n- github.com/ncruces/go-strftime [MIT License](https://github.com/ncruces/go-strftime/blob/main/LICENSE)\n- github.com/ncw/swift [MIT License](https://github.com/ncw/swift/blob/master/COPYING)\n- github.com/netsampler/goflow2 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/netsampler/goflow2/blob/main/LICENSE)\n- github.com/newrelic/newrelic-telemetry-sdk-go [Apache License 2.0](https://github.com/newrelic/newrelic-telemetry-sdk-go/blob/master/LICENSE.md)\n- github.com/nsqio/go-nsq [MIT License](https://github.com/nsqio/go-nsq/blob/master/LICENSE)\n- github.com/nwaples/tacplus [BSD 2-Clause \"Simplified\" License](https://github.com/nwaples/tacplus/blob/master/LICENSE)\n- github.com/oapi-codegen/runtime [Apache License 2.0](https://github.com/oapi-codegen/runtime/blob/main/LICENSE)\n- github.com/olivere/elastic [MIT License](https://github.com/olivere/elastic/blob/release-branch.v7/LICENSE)\n- github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/LICENSE)\n- github.com/openconfig/gnmi [Apache License 2.0](https://github.com/openconfig/gnmi/blob/master/LICENSE)\n- github.com/openconfig/goyang [Apache License 2.0](https://github.com/openconfig/goyang/blob/master/LICENSE)\n- github.com/opencontainers/go-digest [Apache License 2.0](https://github.com/opencontainers/go-digest/blob/master/LICENSE)\n- github.com/opencontainers/image-spec [Apache License 2.0](https://github.com/opencontainers/image-spec/blob/master/LICENSE)\n- github.com/opensearch-project/opensearch-go [Apache License 2.0](https://github.com/opensearch-project/opensearch-go/blob/main/LICENSE.txt)\n- github.com/opentracing/opentracing-go [Apache License 2.0](https://github.com/opentracing/opentracing-go/blob/master/LICENSE)\n- github.com/oxtoacart/bpool [Apache License 2.0](https://github.com/oxtoacart/bpool/blob/master/LICENSE)\n- github.com/p4lang/p4runtime [Apache License 2.0](https://github.com/p4lang/p4runtime/blob/main/LICENSE)\n- github.com/panjf2000/ants [MIT License](https://github.com/panjf2000/ants/blob/dev/LICENSE)\n- github.com/panjf2000/gnet [Apache License 2.0](https://github.com/panjf2000/gnet/blob/dev/LICENSE)\n- github.com/paulmach/orb [MIT License](https://github.com/paulmach/orb/blob/master/LICENSE.md)\n- github.com/pavlo-v-chernykh/keystore-go [MIT License](https://github.com/pavlo-v-chernykh/keystore-go/blob/master/LICENSE)\n- github.com/pborman/ansi [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/pborman/ansi/blob/master/LICENSE)\n- github.com/pcolladosoto/goslurm [MIT License](https://github.com/pcolladosoto/goslurm/blob/main/LICENSE)\n- github.com/peterbourgon/unixtransport [Apache License 2.0](https://github.com/peterbourgon/unixtransport/blob/main/LICENSE)\n- github.com/philhofer/fwd [MIT License](https://github.com/philhofer/fwd/blob/master/LICENSE.md)\n- github.com/pierrec/lz4 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/pierrec/lz4/blob/master/LICENSE)\n- github.com/pion/dtls [MIT License](https://github.com/pion/dtls/blob/master/LICENSES/MIT.txt)\n- github.com/pion/logging [MIT License](https://github.com/pion/logging/blob/master/LICENSES/MIT.txt)\n- github.com/pion/transport [MIT License](https://github.com/pion/transport/blob/master/LICENSES/MIT.txt)\n- github.com/pkg/browser [BSD 2-Clause \"Simplified\" License](https://github.com/pkg/browser/blob/master/LICENSE)\n- github.com/pkg/errors [BSD 2-Clause \"Simplified\" License](https://github.com/pkg/errors/blob/master/LICENSE)\n- github.com/pkg/sftp [BSD 2-Clause \"Simplified\" License](https://github.com/pkg/sftp/blob/master/LICENSE)\n- github.com/pkg/xattr [BSD 2-Clause \"Simplified\" License](https://github.com/pkg/xattr/blob/master/LICENSE)\n- github.com/pmezard/go-difflib [BSD 3-Clause Clear License](https://github.com/pmezard/go-difflib/blob/master/LICENSE)\n- github.com/prometheus-community/pro-bing [MIT License](https://github.com/prometheus-community/pro-bing/blob/main/LICENSE)\n- github.com/prometheus/client_golang [Apache License 2.0](https://github.com/prometheus/client_golang/blob/master/LICENSE)\n- github.com/prometheus/client_model [Apache License 2.0](https://github.com/prometheus/client_model/blob/master/LICENSE)\n- github.com/prometheus/common [Apache License 2.0](https://github.com/prometheus/common/blob/master/LICENSE)\n- github.com/prometheus/procfs [Apache License 2.0](https://github.com/prometheus/procfs/blob/master/LICENSE)\n- github.com/prometheus/prometheus [Apache License 2.0](https://github.com/prometheus/prometheus/blob/master/LICENSE)\n- github.com/rabbitmq/amqp091-go [BSD 2-Clause \"Simplified\" License](https://github.com/rabbitmq/amqp091-go/blob/main/LICENSE)\n- github.com/rclone/rclone [MIT License](https://github.com/rclone/rclone/blob/master/COPYING)\n- github.com/rcrowley/go-metrics [BSD 2-Clause with views sentence](https://github.com/rcrowley/go-metrics/blob/master/LICENSE)\n- github.com/redis/go-redis [BSD 2-Clause \"Simplified\" License](https://github.com/redis/go-redis/blob/master/LICENSE)\n- github.com/remyoudompheng/bigfft [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/remyoudompheng/bigfft/blob/master/LICENSE)\n- github.com/rfjakob/eme [MIT License](https://github.com/rfjakob/eme/blob/master/LICENSE)\n- github.com/riemann/riemann-go-client [MIT License](https://github.com/riemann/riemann-go-client/blob/master/LICENSE)\n- github.com/robbiet480/go.nut [MIT License](https://github.com/robbiet480/go.nut/blob/master/LICENSE)\n- github.com/robinson/gos7 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/robinson/gos7/blob/master/LICENSE)\n- github.com/russross/blackfriday [BSD 2-Clause \"Simplified\" License](https://github.com/russross/blackfriday/blob/master/LICENSE.txt)\n- github.com/ryanuber/go-glob [MIT License](https://github.com/ryanuber/go-glob/blob/master/LICENSE)\n- github.com/safchain/ethtool [Apache License 2.0](https://github.com/safchain/ethtool/blob/master/LICENSE)\n- github.com/samber/lo [MIT License](https://github.com/samber/lo/blob/master/LICENSE)\n- github.com/seancfoley/bintree [Apache License 2.0](https://github.com/seancfoley/bintree/blob/master/LICENSE)\n- github.com/seancfoley/ipaddress-go [Apache License 2.0](https://github.com/seancfoley/ipaddress-go/blob/master/LICENSE)\n- github.com/segmentio/asm [MIT License](https://github.com/segmentio/asm/blob/main/LICENSE)\n- github.com/shirou/gopsutil [BSD 3-Clause Clear License](https://github.com/shirou/gopsutil/blob/master/LICENSE)\n- github.com/shopspring/decimal [MIT License](https://github.com/shopspring/decimal/blob/master/LICENSE)\n- github.com/showwin/speedtest-go [MIT License](https://github.com/showwin/speedtest-go/blob/master/LICENSE)\n- github.com/signalfx/com_signalfx_metrics_protobuf [Apache License 2.0](https://github.com/signalfx/com_signalfx_metrics_protobuf/blob/master/LICENSE)\n- github.com/signalfx/gohistogram [MIT License](https://github.com/signalfx/gohistogram/blob/master/LICENSE)\n- github.com/signalfx/golib [Apache License 2.0](https://github.com/signalfx/golib/blob/master/LICENSE)\n- github.com/signalfx/sapm-proto [Apache License 2.0](https://github.com/signalfx/sapm-proto/blob/master/LICENSE)\n- github.com/sijms/go-ora [MIT License](https://github.com/sijms/go-ora/blob/master/LICENSE)\n- github.com/sirupsen/logrus [MIT License](https://github.com/sirupsen/logrus/blob/master/LICENSE)\n- github.com/sleepinggenius2/gosmi [MIT License](https://github.com/sleepinggenius2/gosmi/blob/master/LICENSE)\n- github.com/snowflakedb/gosnowflake [Apache License 2.0](https://github.com/snowflakedb/gosnowflake/blob/master/LICENSE)\n- github.com/spf13/cast [MIT License](https://github.com/spf13/cast/blob/master/LICENSE)\n- github.com/spf13/pflag [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/spf13/pflag/blob/master/LICENSE)\n- github.com/spiffe/go-spiffe [Apache License 2.0](https://github.com/spiffe/go-spiffe/blob/main/LICENSE)\n- github.com/srebhan/cborquery [MIT License](https://github.com/srebhan/cborquery/blob/main/LICENSE)\n- github.com/srebhan/protobufquery [MIT License](https://github.com/srebhan/protobufquery/blob/master/LICENSE)\n- github.com/stretchr/objx [MIT License](https://github.com/stretchr/objx/blob/master/LICENSE)\n- github.com/stretchr/testify [MIT License](https://github.com/stretchr/testify/blob/master/LICENSE)\n- github.com/tdrn-org/go-hue [MIT License](https://github.com/tdrn-org/go-log/blob/main/LICENSE)\n- github.com/tdrn-org/go-nsdp [MIT License](https://github.com/tdrn-org/go-nsdp/blob/main/LICENSE)\n- github.com/tdrn-org/go-tr064 [Apache License 2.0](https://github.com/tdrn-org/go-tr064/blob/main/LICENSE)\n- github.com/testcontainers/testcontainers-go [MIT License](https://github.com/testcontainers/testcontainers-go/blob/main/LICENSE)\n- github.com/thomasklein94/packer-plugin-libvirt [Mozilla Public License 2.0](https://github.com/thomasklein94/packer-plugin-libvirt/blob/main/LICENSE)\n- github.com/tidwall/gjson [MIT License](https://github.com/tidwall/gjson/blob/master/LICENSE)\n- github.com/tidwall/match [MIT License](https://github.com/tidwall/match/blob/master/LICENSE)\n- github.com/tidwall/pretty [MIT License](https://github.com/tidwall/pretty/blob/master/LICENSE)\n- github.com/tidwall/tinylru [MIT License](https://github.com/tidwall/tinylru/blob/master/LICENSE)\n- github.com/tidwall/wal [MIT License](https://github.com/tidwall/wal/blob/master/LICENSE)\n- github.com/tinylib/msgp [MIT License](https://github.com/tinylib/msgp/blob/master/LICENSE)\n- github.com/tklauser/go-sysconf [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/tklauser/go-sysconf/blob/master/LICENSE)\n- github.com/tklauser/numcpus [Apache License 2.0](https://github.com/tklauser/numcpus/blob/master/LICENSE)\n- github.com/twmb/murmur3 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/twmb/murmur3/blob/master/LICENSE)\n- github.com/uber/jaeger-client-go [Apache License 2.0](https://github.com/jaegertracing/jaeger-client-go/blob/master/LICENSE)\n- github.com/uber/jaeger-lib [Apache License 2.0](https://github.com/jaegertracing/jaeger-lib/blob/main/LICENSE)\n- github.com/urfave/cli [MIT License](https://github.com/urfave/cli/blob/main/LICENSE)\n- github.com/valyala/bytebufferpool [MIT License](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)\n- github.com/vapourismo/knx-go [MIT License](https://github.com/vapourismo/knx-go/blob/master/LICENSE)\n- github.com/vertica/vertica-sql-go [Apache License 2.0](https://github.com/vertica/vertica-sql-go/blob/master/LICENSE)\n- github.com/vishvananda/netlink [Apache License 2.0](https://github.com/vishvananda/netlink/blob/master/LICENSE)\n- github.com/vishvananda/netns [Apache License 2.0](https://github.com/vishvananda/netns/blob/master/LICENSE)\n- github.com/vjeantet/grok [Apache License 2.0](https://github.com/vjeantet/grok/blob/master/LICENSE)\n- github.com/vmware/govmomi [Apache License 2.0](https://github.com/vmware/govmomi/blob/master/LICENSE.txt)\n- github.com/wavefronthq/wavefront-sdk-go [Apache License 2.0](https://github.com/wavefrontHQ/wavefront-sdk-go/blob/master/LICENSE)\n- github.com/x448/float16 [MIT License](https://github.com/x448/float16/blob/master/LICENSE)\n- github.com/xanzy/ssh-agent [Apache License 2.0](https://github.com/xanzy/ssh-agent/blob/main/LICENSE)\n- github.com/xdg-go/scram [Apache License 2.0](https://github.com/xdg-go/scram/blob/master/LICENSE)\n- github.com/xdg-go/stringprep [Apache License 2.0](https://github.com/xdg-go/stringprep/blob/master/LICENSE)\n- github.com/xdg/scram [Apache License 2.0](https://github.com/xdg-go/scram/blob/master/LICENSE)\n- github.com/xdg/stringprep [Apache License 2.0](https://github.com/xdg-go/stringprep/blob/master/LICENSE)\n- github.com/xrash/smetrics [MIT License](https://github.com/xrash/smetrics/blob/master/LICENSE)\n- github.com/youmark/pkcs8 [MIT License](https://github.com/youmark/pkcs8/blob/master/LICENSE)\n- github.com/yuin/gopher-lua [MIT License](https://github.com/yuin/gopher-lua/blob/master/LICENSE)\n- github.com/yusufpapurcu/wmi [MIT License](https://github.com/yusufpapurcu/wmi/blob/master/LICENSE)\n- github.com/zeebo/xxh3 [BSD 2-Clause \"Simplified\" License](https://github.com/zeebo/xxh3/blob/master/LICENSE)\n- github.com/zentures/cityhash [MIT License](https://github.com/zentures/cityhash/blob/master/LICENSE)\n- go.bug.st/serial [BSD 3-Clause License](https://github.com/bugst/go-serial/blob/master/LICENSE)\n- go.mongodb.org/mongo-driver [Apache License 2.0](https://github.com/mongodb/mongo-go-driver/blob/master/LICENSE)\n- go.opencensus.io [Apache License 2.0](https://github.com/census-instrumentation/opencensus-go/blob/master/LICENSE)\n- go.opentelemetry.io/auto/sdk [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-instrumentation/blob/main/sdk/LICENSE)\n- go.opentelemetry.io/collector/consumer/consumererror [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE)\n- go.opentelemetry.io/collector/featuregate [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE)\n- go.opentelemetry.io/collector/pdata [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE)\n- go.opentelemetry.io/collector/pdata/pprofile [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE)\n- go.opentelemetry.io/collector/semconv [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE)\n- go.opentelemetry.io/contrib/detectors/gcp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE)\n- 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)\n- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE)\n- go.opentelemetry.io/otel [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE)\n- go.opentelemetry.io/otel/metric [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE)\n- go.opentelemetry.io/otel/sdk [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE)\n- go.opentelemetry.io/otel/sdk/metric [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE)\n- go.opentelemetry.io/otel/trace [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE)\n- go.opentelemetry.io/proto/otlp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-proto-go/blob/main/LICENSE)\n- go.opentelemetry.io/proto/otlp/collector/profiles/v1development [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-proto-go/blob/main/LICENSE)\n- go.opentelemetry.io/proto/otlp/profiles/v1development [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-proto-go/blob/main/LICENSE)\n- go.starlark.net [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/google/starlark-go/blob/master/LICENSE)\n- go.step.sm/crypto [Apache License 2.0](https://github.com/smallstep/crypto/blob/master/LICENSE)\n- go.uber.org/atomic [MIT License](https://pkg.go.dev/go.uber.org/atomic?tab=licenses)\n- go.uber.org/multierr [MIT License](https://pkg.go.dev/go.uber.org/multierr?tab=licenses)\n- go.uber.org/zap [MIT License](https://pkg.go.dev/go.uber.org/zap?tab=licenses)\n- go.yaml.in/yaml [Apache License 2.0](https://github.com/yaml/go-yaml/blob/main/LICENSE)\n- golang.org/x/crypto [BSD 3-Clause Clear License](https://github.com/golang/crypto/blob/master/LICENSE)\n- golang.org/x/exp [BSD 3-Clause Clear License](https://github.com/golang/exp/blob/master/LICENSE)\n- golang.org/x/net [BSD 3-Clause Clear License](https://github.com/golang/net/blob/master/LICENSE)\n- golang.org/x/oauth2 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/golang/oauth2/blob/master/LICENSE)\n- golang.org/x/sync [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/golang/sync/blob/master/LICENSE)\n- golang.org/x/sys [BSD 3-Clause Clear License](https://github.com/golang/sys/blob/master/LICENSE)\n- golang.org/x/term [BSD 3-Clause License](https://pkg.go.dev/golang.org/x/term?tab=licenses)\n- golang.org/x/text [BSD 3-Clause Clear License](https://github.com/golang/text/blob/master/LICENSE)\n- golang.org/x/time [BSD 3-Clause Clear License](https://github.com/golang/time/blob/master/LICENSE)\n- golang.org/x/xerrors [BSD 3-Clause Clear License](https://github.com/golang/xerrors/blob/master/LICENSE)\n- golang.zx2c4.com/wireguard [MIT License](https://github.com/WireGuard/wgctrl-go/blob/master/LICENSE.md)\n- golang.zx2c4.com/wireguard/wgctrl [MIT License](https://github.com/WireGuard/wgctrl-go/blob/master/LICENSE.md)\n- gonum.org/v1/gonum [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/gonum/gonum/blob/master/LICENSE)\n- google.golang.org/api [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/googleapis/google-api-go-client/blob/master/LICENSE)\n- google.golang.org/genproto [Apache License 2.0](https://github.com/google/go-genproto/blob/master/LICENSE)\n- google.golang.org/genproto/googleapis/api [Apache License 2.0](https://pkg.go.dev/google.golang.org/genproto/googleapis/api?tab=licenses)\n- google.golang.org/genproto/googleapis/rpc [Apache License 2.0](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc?tab=licenses)\n- google.golang.org/grpc [Apache License 2.0](https://github.com/grpc/grpc-go/blob/master/LICENSE)\n- google.golang.org/protobuf [BSD 3-Clause \"New\" or \"Revised\" License](https://pkg.go.dev/google.golang.org/protobuf?tab=licenses)\n- gopkg.in/evanphx/json-patch.v4 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/evanphx/json-patch/blob/master/LICENSE)\n- gopkg.in/fatih/pool.v2 [MIT License](https://github.com/fatih/pool/blob/v2.0.0/LICENSE)\n- gopkg.in/fsnotify.v1 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/fsnotify/fsnotify/blob/v1.4.7/LICENSE)\n- gopkg.in/gorethink/gorethink.v3 [Apache License 2.0](https://github.com/rethinkdb/rethinkdb-go/blob/v3.0.5/LICENSE)\n- gopkg.in/inf.v0 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/go-inf/inf/blob/v0.9.1/LICENSE)\n- gopkg.in/ini.v1 [Apache License 2.0](https://github.com/go-ini/ini/blob/master/LICENSE)\n- gopkg.in/natefinch/lumberjack.v2 [MIT License](https://github.com/natefinch/lumberjack/blob/v2.0/LICENSE)\n- gopkg.in/olivere/elastic.v5 [MIT License](https://github.com/olivere/elastic/blob/v5.0.76/LICENSE)\n- gopkg.in/tomb.v1 [BSD 3-Clause Clear License](https://github.com/go-tomb/tomb/blob/v1/LICENSE)\n- gopkg.in/tomb.v2 [BSD 3-Clause Clear License](https://github.com/go-tomb/tomb/blob/v2/LICENSE)\n- gopkg.in/yaml.v2 [Apache License 2.0](https://github.com/go-yaml/yaml/blob/v2.2.2/LICENSE)\n- gopkg.in/yaml.v3 [MIT License](https://github.com/go-yaml/yaml/blob/v3/LICENSE)\n- howett.net/plist [BSD-2-Clause-Views, BSD-3-Clause](https://github.com/DHowett/go-plist/blob/main/LICENSE)\n- k8s.io/api [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- k8s.io/apimachinery [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- k8s.io/client-go [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- k8s.io/klog [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- k8s.io/kube-openapi [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- k8s.io/utils [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- layeh.com/radius [Mozilla Public License 2.0](https://github.com/layeh/radius/blob/master/LICENSE)\n- modernc.org/libc [BSD 3-Clause \"New\" or \"Revised\" License](https://gitlab.com/cznic/libc/-/blob/master/LICENSE)\n- modernc.org/mathutil [BSD 3-Clause \"New\" or \"Revised\" License](https://gitlab.com/cznic/mathutil/-/blob/master/LICENSE)\n- modernc.org/memory [BSD 3-Clause \"New\" or \"Revised\" License](https://gitlab.com/cznic/memory/-/blob/master/LICENSE)\n- modernc.org/sqlite [BSD 3-Clause \"New\" or \"Revised\" License](https://gitlab.com/cznic/sqlite/-/blob/master/LICENSE)\n- sigs.k8s.io/json [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- sigs.k8s.io/randfill [Apache License 2.0](https://github.com/kubernetes-sigs/randfill/blob/main/LICENSE)\n- sigs.k8s.io/structured-merge-diff [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- sigs.k8s.io/yaml [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE)\n- software.sslmate.com/src/go-pkcs12 [BSD 3-Clause \"New\" or \"Revised\" License](https://github.com/SSLMate/go-pkcs12/blob/master/LICENSE)\n\n## Telegraf used and modified code from these projects\n\n- github.com/DataDog/datadog-agent [Apache License 2.0](https://github.com/DataDog/datadog-agent/blob/main/LICENSE)\n"
  },
  {
    "path": "docs/METRICS.md",
    "content": "# Metrics\n\nTelegraf metrics are the internal representation used to model data during\nprocessing.  Metrics are closely based on InfluxDB's data model and contain\nfour main components:\n\n- **Measurement Name**: Description and namespace for the metric.\n- **Tags**: Key/Value string pairs and usually used to identify the\n  metric.\n- **Fields**: Key/Value pairs that are typed and usually contain the\n  metric data.\n- **Timestamp**: Date and time associated with the fields.\n\nThis metric type exists only in memory and must be converted to a concrete\nrepresentation in order to be transmitted or viewed.  To achieve this we\nprovide several [output data formats][] sometimes referred to as\n*serializers*.  Our default serializer converts to [InfluxDB Line\nProtocol][line protocol] which provides a high performance and one-to-one\ndirect mapping from Telegraf metrics.\n\n[output data formats]: /docs/DATA_FORMATS_OUTPUT.md\n[line protocol]: /plugins/serializers/influx\n\n## Tracking Metrics\n\nTracking metrics are metrics that ensure that data is passed from the input and\nhanded to an output before acknowledging the message back to the input. The\nuse case for these types of metrics is to ensure that the message makes it to\nthe destination before removing the metric from the input.\n\nFor example, if a configuration is reading from MQTT, Kafka, or an AMQP source\nTelegraf will read the message and wait till the metric is handed to the output\nbefore telling the metric source that the message was read. If Telegraf were to\nstop or the system running Telegraf to crash, this allows the messages that\nwere not completely delivered to an output to get re-read at a later date.\n\nPlease note that this process applies only to internal plugins. For external\nplugins, the metrics are acknowledged regardless of the actual output.\n\n### Undelivered Messages\n\nWhen an input uses tracking metrics, an additional setting,\n`max_undelivered_messages`, is available in that plugin. This setting\ndetermines how many metrics should be read in before reading additional\nmessages. In practice, this means that Telegraf may not read new messages from\nan input at every collection interval.\n\nUsers need to use caution with this setting. Setting the value too high may\nmean that Telegraf pushes constant batches to an output, ignoring the flush\ninterval.\n"
  },
  {
    "path": "docs/NIGHTLIES.md",
    "content": "\n# Nightly Builds\n\nThese builds are generated from the master branch at midnight UTC:\n\n| DEB             | RPM             | TAR GZ                        | ZIP |\n| --------------- | --------------- | ------------------------------| --- |\n| [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) |\n| [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) |\n| [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)   |\n| [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)   | |\n| [i386.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_i386.deb)       | [loongarch64.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.loongarch64.rpm) | [freebsd_i386.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_freebsd_i386.tar.gz)     | |\n| [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)       | |\n| [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)       | |\n| [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)       | |\n| [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)       | |\n| [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)         | |\n| [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)   | |\n|                                                                                          |                                                                                          | [linux_mips.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_mips.tar.gz)         | |\n|                                                                                          |                                                                                          | [linux_mipsel.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_mipsel.tar.gz)     | |\n|                                                                                          |                                                                                          | [linux_ppc64le.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_ppc64le.tar.gz)   | |\n|                                                                                          |                                                                                          | [linux_riscv64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_riscv64.tar.gz)   | |\n|                                                                                          |                                                                                          | [linux_s390x.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_s390x.tar.gz)       | |\n\nNightly docker images are available on [quay.io](https://quay.io/repository/influxdb/telegraf-nightly?tab=tags):\n\n```shell\n# Debian-based image\ndocker pull quay.io/influxdb/telegraf-nightly:latest\n# Alpine-based image\ndocker pull quay.io/influxdb/telegraf-nightly:alpine\n```\n"
  },
  {
    "path": "docs/OUTPUTS.md",
    "content": "# Output Plugins\n\nThis section is for developers who want to create a new output sink. Outputs\nare created in a similar manner as collection plugins, and their interface has\nsimilar constructs.\n\n## Output Plugin Guidelines\n\n- An output must conform to the [telegraf.Output][] interface.\n- Outputs should call `outputs.Add` in their `init` function to register\n  themselves.  See below for a quick example.\n- To be available within Telegraf itself, plugins must register themselves\n  using a file in `github.com/influxdata/telegraf/plugins/outputs/all` named\n  according to the plugin name. Make sure you also add build-tags to\n  conditionally build the plugin.\n- Each plugin requires a file called `sample.conf` containing the sample\n  configuration  for the plugin in TOML format.\n  Please consult the [Sample Config][] page for the latest style guidelines.\n- Each plugin `README.md` file should include the `sample.conf` file in a\n  section describing the configuration by specifying a `toml` section in the\n  form `toml @sample.conf`. The specified file(s) are then injected\n  automatically into the Readme.\n- Follow the recommended [Code Style][].\n\n[Sample Config]: /docs/developers/SAMPLE_CONFIG.md\n[Code Style]: /docs/developers/CODE_STYLE.md\n[telegraf.Output]: https://godoc.org/github.com/influxdata/telegraf#Output\n\n## Data Formats\n\nSome output plugins, such as the [file][] plugin, can write in any supported\n[output data formats][].\n\nIn order to enable this, you must specify a\n`SetSerializer(serializer serializers.Serializer)`\nfunction on the plugin object (see the file plugin for an example), as well as\ndefining `serializer` as a field of the object.\n\nYou can then utilize the serializer internally in your plugin, serializing data\nbefore it's written. Telegraf's configuration layer will take care of\ninstantiating and creating the `Serializer` object.\n\nYou should also add the following to your `SampleConfig()`:\n\n```toml\n  ## Data format to output.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n```\n\n[file]: /plugins/inputs/file\n[output data formats]: /docs/DATA_FORMATS_OUTPUT.md\n\n## Flushing Metrics to Outputs\n\nMetrics are flushed to outputs when any of the following events happen:\n\n- `flush_interval + rand(flush_jitter)` has elapsed since start or the last\n  flush interval\n- At least `metric_batch_size` count of metrics are waiting in the buffer\n- The telegraf process has received a SIGUSR1 signal\n\nNote that if the flush takes longer than the `agent.interval` to write the\nmetrics to the output, user will see a message saying the output:\n\n> did not complete within its flush interval\n\nThis may mean the output is not keeping up with the flow of metrics, and you may\nwant to look into enabling compression, reducing the size of your metrics or\ninvestigate other reasons why the writes might be taking longer than expected.\n\n## Output Plugin Example\n\n## Registration\n\nRegistration of the plugin on `plugins/outputs/all/simpleoutput.go`:\n\n```go\n//go:build !custom || outputs || outputs.simpleoutput\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/outputs/simpleoutput\" // register plugin\n\n```\n\nThe _build-tags_ in the first line allow to selectively include/exclude your\nplugin when customizing Telegraf.\n\n## Plugin\n\nContent of your plugin file e.g. `simpleoutput.go`\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage simpleoutput\n\n// simpleoutput.go\n\nimport (\n    _ \"embed\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/outputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Simple struct {\n    Ok  bool            `toml:\"ok\"`\n    Log telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Simple) SampleConfig() string {\n    return sampleConfig\n}\n\n// Init is for setup, and validating config.\nfunc (s *Simple) Init() error {\n    return nil\n}\n\nfunc (s *Simple) Connect() error {\n    // Make any connection required here\n    return nil\n}\n\nfunc (s *Simple) Close() error {\n    // Close any connections here.\n    // Write will not be called once Close is called, so there is no need to synchronize.\n    return nil\n}\n\n// Write should write immediately to the output, and not buffer writes\n// (Telegraf manages the buffer for you). Returning an error will fail this\n// batch of writes and the entire batch will be retried automatically.\nfunc (s *Simple) Write(metrics []telegraf.Metric) error {\n    for _, metric := range metrics {\n        // write `metric` to the output sink here\n    }\n    return nil\n}\n\nfunc init() {\n    outputs.Add(\"simpleoutput\", func() telegraf.Output { return &Simple{} })\n}\n```\n"
  },
  {
    "path": "docs/PARSING_DATA.md",
    "content": "# Parsing Data\n\nTelegraf has the ability to take data in a variety of formats. Telegraf requires\nconfiguration from the user in order to correctly parse, store, and send the\noriginal data. Telegraf does not take the raw data and maintain it internally.\n\nTelegraf uses an internal metric representation consisting of the metric name,\ntags, fields and a timestamp, very similar to [line protocol][]. This\nmeans that data needs to be broken up into a metric name, tags, fields, and a\ntimestamp. While none of these options are required, they are available to\nthe user and might be necessary to ensure the data is represented correctly.\n\n[line protocol]: https://docs.influxdata.com/influxdb/cloud/reference/syntax/line-protocol/\n\n## Parsers\n\nThe first step is to determine which parser to use. Look at the list of\n[parsers][] and find one that will work with the user's data. This is generally\nstraightforward as the data-type will only have one parser that is actually\napplicable to the data.\n\n[parsers]: https://github.com/influxdata/telegraf/tree/master/plugins/parsers\n\n### JSON parsers\n\nThere is an exception when it comes to JSON data. Instead of a single parser,\nthere are three different parsers capable of reading JSON data:\n\n* `json`: This parser is great for flat JSON data. If the JSON is more complex\n  and for example, has other objects or nested arrays, then do not use this and\n  look at the other two options.\n* `json_v2`: The v2 parser was created out of the need to parse JSON objects. It\n  can take on more advanced cases, at the cost of additional configuration.\n* `xpath_json`: The xpath parser is the most capable of the three options. While\n  the xpath name may imply XML data, it can parse a variety of data types using\n  XPath expressions.\n\n## Tags and fields\n\nThe next step is to look at the data and determine how the data needs to be\nsplit up between tags and fields. Tags are generally strings or values that a\nuser will want to search on. While fields are the raw data values, numeric\ntypes, etc. Generally, data is considered to be a field unless otherwise\nspecified as a tag.\n\n## Timestamp\n\nTo parse a timestamp, at the very least the users needs to specify which field\nhas the timestamp and what the format of the timestamp is. The format can either\nbe a predefined Unix timestamp or parsed using a custom format based on Go\nreference time.\n\nFor Unix timestamps Telegraf understands the following settings:\n\n| Timestamp             | Timestamp Format |\n| --------------------- | ---------------- |\n| `1709572232`          | `unix`           |\n| `1709572232123`       | `unix_ms`        |\n| `1709572232123456`    | `unix_us`        |\n| `1709572232123456789` | `unix_ns`        |\n\nThere are some named formats available as well:\n\n| Timestamp                             | Named Format  |\n| ------------------------------------- | ------------- |\n| `Mon Jan _2 15:04:05 2006`            | `ANSIC`       |\n| `Mon Jan _2 15:04:05 MST 2006`        | `UnixDate`    |\n| `Mon Jan 02 15:04:05 -0700 2006`      | `RubyDate`    |\n| `02 Jan 06 15:04 MST`                 | `RFC822`      |\n| `02 Jan 06 15:04 -0700`               | `RFC822Z`     |\n| `Monday, 02-Jan-06 15:04:05 MST`      | `RFC850`      |\n| `Mon, 02 Jan 2006 15:04:05 MST`       | `RFC1123`     |\n| `Mon, 02 Jan 2006 15:04:05 -0700`     | `RFC1123Z`    |\n| `2006-01-02T15:04:05Z07:00`           | `RFC3339`     |\n| `2006-01-02T15:04:05.999999999Z07:00` | `RFC3339Nano` |\n| `Jan _2 15:04:05`                     | `Stamp`       |\n| `Jan _2 15:04:05.000`                 | `StampMilli`  |\n| `Jan _2 15:04:05.000000`              | `StampMicro`  |\n| `Jan _2 15:04:05.000000000`           | `StampNano`   |\n\nIf the timestamp does not conform to any of the above, then the user can specify\na custom timestamp format, in which the user must provide the timestamp in\n[Go reference time][] notation. Here are a few example timestamps and their Go\nreference time equivalent:\n\n| Timestamp                     | Go reference time                |\n| ----------------------------- | -------------------------------- |\n| `2024-03-04T17:10:32`         | `2006-01-02T15:04:05`            |\n| `04 Mar 24 10:10 -0700`       | `02 Jan 06 15:04 -0700`          |\n| `2024-03-04T10:10:32Z07:00`   | `2006-01-02T15:04:05Z07:00`      |\n| `2024-03-04 17:10:32.123+00`  | `2006-01-02 15:04:05.999+00`     |\n| `2024-03-04T10:10:32.123456Z` | `2006-01-02T15:04:05.000000Z`    |\n| `2024-03-04T10:10:32.123456Z` | `2006-01-02T15:04:05.999999999Z` |\n\nNote for fractional second values, the user can use either a `9` or `0`. Using a\n`0` forces a certain length, but using `9`s do not.\n\nPlease note, that timezone abbreviations are ambiguous! For example `MST`, can\nstand for either Mountain Standard Time (UTC-07) or Malaysia Standard Time\n(UTC+08). As such, avoid abbreviated timezones if possible.\n\nUnix timestamps use UTC, there is no concept of a timezone for a Unix timestamp.\n\nSome devices report timestamp as a number, similar to Unix timestamp format,\nbut in local timezone not UTC.\nThe formats below provide support for these cases by means of computing\noffset between local time and UTC:\n\n| Timestamp             | Timestamp Format  |\n| --------------------- | ----------------- |\n| `1709572232`          | `timestamp_tz`    |\n| `1709572232123`       | `timestamp_tz_ms` |\n| `1709572232123456`    | `timestamp_tz_us` |\n| `1709572232123456789` | `timestamp_tz_ns` |\n\n[Go reference time]: https://pkg.go.dev/time#pkg-constants\n\n## Examples\n\nBelow are a few basic examples to get users started.\n\n### CSV\n\nGiven the following data:\n\n```csv\nnode,temp,humidity,alarm,time\nnode1,32.3,23,false,2023-03-06T16:52:23Z\nnode2,22.6,44,false,2023-03-06T16:52:23Z\nnode3,17.9,56,true,2023-03-06T16:52:23Z\n```\n\nHere is corresponding parser configuration and result:\n\n```toml\n[[inputs.file]]\nfiles = [\"test.csv\"]\ndata_format = \"csv\"\n\ncsv_header_row_count = 1\ncsv_column_names = [\"node\",\"temp\",\"humidity\",\"alarm\",\"time\"]\ncsv_tag_columns = [\"node\"]\ncsv_timestamp_column = \"time\"\ncsv_timestamp_format = \"2006-01-02T15:04:05Z\"\n```\n\n```text\nfile,node=node1 temp=32.3,humidity=23i,alarm=false 1678121543000000000\nfile,node=node2 temp=22.6,humidity=44i,alarm=false 1678121543000000000\nfile,node=node3 temp=17.9,humidity=56i,alarm=true 1678121543000000000\n```\n\n### CSV with Local Timestamp\n\nGiven the following data:\n\n```csv\nnode,temp,humidity,alarm,time\nnode1,32.3,23,false,1568338208\nnode2,22.6,44,false,1568338208\n```\n\nHere is corresponding parser configuration and result:\n\n```toml\n[[inputs.file]]\nfiles = [\"test.csv\"]\ndata_format = \"csv\"\n\ncsv_header_row_count = 1\ncsv_column_names = [\"node\",\"temp\",\"humidity\",\"alarm\",\"time\"]\ncsv_tag_columns = [\"node\"]\ncsv_timestamp_column = \"time\"\ncsv_timestamp_format = \"timestamp_tz\"\ncsv_timezone = \"Pacific/Fiji\"\n```\n\n```text\nfile,node=node1 temp=32.3,humidity=23i,alarm=false 1568295008000000000\nfile,node=node2 temp=22.6,humidity=44i,alarm=false 1568295008000000000\nfile,node=node3 temp=17.9,humidity=56i,alarm=true 1568295008000000000\n```\n\nPay attention that the timestamp in CSV is 12 hours later than the metrics timestamp\nbecause `Pacific/Fiji` is +12:00 Timezone.\n\n### JSON flat data\n\nGiven the following data:\n\n```json\n{ \"node\": \"node\", \"temp\": 32.3, \"humidity\": 23, \"alarm\": false, \"time\": \"1709572232123456789\"}\n```\n\nHere is corresponding parser configuration:\n\n```toml\n[[inputs.file]]\nfiles = [\"test.json\"]\nprecision = \"1ns\"\ndata_format = \"json\"\n\ntag_keys = [\"node\"]\njson_time_key = \"time\"\njson_time_format = \"unix_ns\"\n\n```\n\n```text\nfile,node=node temp=32.3,humidity=23 1709572232123456789\n```\n\n### JSON Objects\n\nGiven the following data:\n\n```json\n{\n    \"metrics\": [\n        { \"node\": \"node1\", \"temp\": 32.3, \"humidity\": 23, \"alarm\": \"false\", \"time\": \"1678121543\"},\n        { \"node\": \"node2\", \"temp\": 22.6, \"humidity\": 44, \"alarm\": \"false\", \"time\": \"1678121543\"},\n        { \"node\": \"node3\", \"temp\": 17.9, \"humidity\": 56, \"alarm\": \"true\", \"time\": \"1678121543\"}\n    ]\n}\n```\n\nHere is corresponding parser configuration:\n\n```toml\n[[inputs.file]]\nfiles = [\"test.json\"]\ndata_format = \"json_v2\"\n\n[[inputs.file.json_v2]]\n[[inputs.file.json_v2.object]]\n  path = \"metrics\"\n  timestamp_key = \"time\"\n  timestamp_format = \"unix\"\n  [[inputs.file.json_v2.object.tag]]\n    path = \"#.node\"\n  [[inputs.file.json_v2.object.field]]\n    path = \"#.temp\"\n    type = \"float\"\n  [[inputs.file.json_v2.object.field]]\n    path = \"#.humidity\"\n    type = \"int\"\n  [[inputs.file.json_v2.object.field]]\n    path = \"#.alarm\"\n    type = \"bool\"\n```\n\n```text\nfile,node=node1 temp=32.3,humidity=23i,alarm=false 1678121543000000000\nfile,node=node2 temp=22.6,humidity=44i,alarm=false 1678121543000000000\nfile,node=node3 temp=17.9,humidity=56i,alarm=true 1678121543000000000\n```\n\n### JSON Line Protocol\n\nGiven the following data:\n\n```json\n{\n  \"fields\": {\"temp\": 32.3, \"humidity\": 23, \"alarm\": false},\n  \"name\": \"measurement\",\n  \"tags\": {\"node\": \"node1\"},\n  \"time\": \"2024-03-04T10:10:32.123456Z\"\n}\n```\n\nHere is corresponding parser configuration:\n\n```toml\n[[inputs.file]]\nfiles = [\"test.json\"]\nprecision = \"1us\"\ndata_format = \"xpath_json\"\n\n[[inputs.file.xpath]]\n  metric_name = \"/name\"\n  field_selection = \"fields/*\"\n  tag_selection = \"tags/*\"\n  timestamp = \"/time\"\n  timestamp_format = \"2006-01-02T15:04:05.999999999Z\"\n```\n\n```text\nmeasurement,node=node1 alarm=\"false\",humidity=\"23\",temp=\"32.3\" 1709547032123456000\n```\n"
  },
  {
    "path": "docs/PROCESSORS.md",
    "content": "# Processor Plugins\n\nThis section is for developers who want to create a new processor plugin.\n\n## Processor Plugin Guidelines\n\n* A processor must conform to the [telegraf.Processor][] interface.\n* Processors should call `processors.Add` in their `init` function to register\n  themselves.  See below for a quick example.\n* To be available within Telegraf itself, plugins must register themselves\n  using a file in `github.com/influxdata/telegraf/plugins/processors/all`\n  named according to the plugin name. Make sure you also add build-tags to\n  conditionally build the plugin.\n* Each plugin requires a file called `sample.conf` containing the sample\n  configuration  for the plugin in TOML format.\n  Please consult the [Sample Config][] page for the latest style guidelines.\n* Each plugin `README.md` file should include the `sample.conf` file in a\n  section describing the configuration by specifying a `toml` section in the\n  form `toml @sample.conf`. The specified file(s) are then injected\n  automatically into the Readme.\n* Follow the recommended [Code Style][].\n\n[Sample Config]: /docs/developers/SAMPLE_CONFIG.md\n[Code Style]: /docs/developers/CODE_STYLE.md\n[telegraf.Processor]: https://godoc.org/github.com/influxdata/telegraf#Processor\n\n## Streaming Processors\n\nStreaming processors are a new processor type available to you. They are\nparticularly useful to implement processor types that use background processes\nor goroutines to process multiple metrics at the same time. Some examples of\nthis are the execd processor, which pipes metrics out to an external process\nover stdin and reads them back over stdout, and the reverse_dns processor, which\ndoes reverse dns lookups on IP addresses in fields. While both of these come\nwith a speed cost, it would be significantly worse if you had to process one\nmetric completely from start to finish before handling the next metric, and thus\nthey benefit significantly from a streaming-pipe approach.\n\nSome differences from classic Processors:\n\n* Streaming processors must conform to the [telegraf.StreamingProcessor][] interface.\n* Processors should call `processors.AddStreaming` in their `init` function to register\n  themselves.  See below for a quick example.\n\n[telegraf.StreamingProcessor]: https://godoc.org/github.com/influxdata/telegraf#StreamingProcessor\n\n## Processor Plugin Example\n\n### Registration\n\nRegistration of the plugin on `plugins/processors/all/printer.go`:\n\n```go\n//go:build !custom || processors || processors.printer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/processors/printer\" // register plugin\n```\n\nThe _build-tags_ in the first line allow to selectively include/exclude your\nplugin when customizing Telegraf.\n\n### Plugin\n\nContent of your plugin file e.g. `printer.go`\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage printer\n\nimport (\n    _ \"embed\"\n    \"fmt\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/processors\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Printer struct {\n    Log telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Printer) SampleConfig() string {\n    return sampleConfig\n}\n\n// Init is for setup, and validating config.\nfunc (p *Printer) Init() error {\n    return nil\n}\n\nfunc (p *Printer) Apply(in ...telegraf.Metric) []telegraf.Metric {\n    for _, metric := range in {\n        fmt.Println(metric.String())\n    }\n    return in\n}\n\nfunc init() {\n    processors.Add(\"printer\", func() telegraf.Processor {\n        return &Printer{}\n    })\n}\n```\n\n## Streaming Processor Example\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage printer\n\nimport (\n    _ \"embed\"\n    \"fmt\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/processors\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Printer struct {\n    Log telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Printer) SampleConfig() string {\n    return sampleConfig\n}\n\n// Init is for setup, and validating config.\nfunc (p *Printer) Init() error {\n    return nil\n}\n\n// Start is called once when the plugin starts; it is only called once per\n// plugin instance, and never in parallel.\n// Start should return once it is ready to receive metrics.\n// The passed in accumulator is the same as the one passed to Add(), so you\n// can choose to save it in the plugin, or use the one received from Add().\nfunc (p *Printer) Start(acc telegraf.Accumulator) error {\n}\n\n// Add is called for each metric to be processed. The Add() function does not\n// need to wait for the metric to be processed before returning, and it may\n// be acceptable to let background goroutine(s) handle the processing if you\n// have slow processing you need to do in parallel.\n// Keep in mind Add() should not spawn unbounded goroutines, so you may need\n// to use a semaphore or pool of workers (eg: reverse_dns plugin does this).\n// Metrics you don't want to pass downstream should have metric.Drop() called,\n// rather than simply omitting the acc.AddMetric() call\nfunc (p *Printer) Add(metric telegraf.Metric, acc telegraf.Accumulator) error {\n    // print!\n    fmt.Println(metric.String())\n    // pass the metric downstream, or metric.Drop() it.\n    // Metric will be dropped if this function returns an error.\n    acc.AddMetric(metric)\n\n    return nil\n}\n\n// Stop gives you an opportunity to gracefully shut down the processor.\n// Once Stop() is called, Add() will not be called any more. If you are using\n// goroutines, you should wait for any in-progress metrics to be processed\n// before returning from Stop().\n// When stop returns, you should no longer be writing metrics to the\n// accumulator.\nfunc (p *Printer) Stop() error {\n}\n\nfunc init() {\n    processors.AddStreaming(\"printer\", func() telegraf.StreamingProcessor {\n        return &Printer{}\n    })\n}\n```\n"
  },
  {
    "path": "docs/PROFILING.md",
    "content": "# Profiling\n\nTelegraf uses the standard package `net/http/pprof`. This package serves via\nits HTTP server runtime profiling data in the format expected by the pprof\nvisualization tool.\n\n## Enable profiling\n\nBy default, the profiling is turned off. To enable profiling users need to\nspecify the pprof address config parameter `pprof-addr`. For example:\n\n```shell\ntelegraf --config telegraf.conf --pprof-addr localhost:6060\n```\n\n## Profiles\n\nTo view all available profiles, open the URL specified in a browser. For\nexample, open `http://localhost:6060/debug/pprof/` in your browser.\n\nTo look at the heap profile:\n\n```shell\ngo tool pprof http://localhost:6060/debug/pprof/heap\n```\n\nTo look at a 30-second CPU profile:\n\n```shell\ngo tool pprof http://localhost:6060/debug/pprof/profile?seconds=30\n```\n\n## Generate heap image\n\nIt is very helpful to generate an image to visualize what heap memory is used.\nIt is best to capture an image a few moments after Telegraf starts and then at\nadditional periods (e.g. 1min, 5min, etc.).\n\nA user can capture the image with Go via:\n\n```shell\ngo tool pprof -png http://localhost:6060/debug/pprof/heap > heap.png\n```\n\nThe resulting image can be uploaded to a bug report.\n\n## References\n\nFor additional information on pprof see the following:\n\n* [net/http/pprof][]\n* [Julia Evans: Profiling Go programs with pprof][]\n* [Debugging Go Code][]\n\n[net/http/pprof]: https://pkg.go.dev/net/http/pprof\n[julia evans: profiling go programs with pprof]: https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/\n[Debugging Go Code]: https://www.infoq.com/articles/debugging-go-programs-pprof-trace/\n"
  },
  {
    "path": "docs/QUICK_START.md",
    "content": "# Quick Start\n\nThe following demos getting started with Telegraf quickly using Docker to\nmonitor the local system.\n\n## Install\n\nThis example will use Docker to launch a Telegraf container:\n\n```shell\ndocker pull telegraf\n```\n\nRefer to the [Install Guide][] for the full list of ways to install Telegraf.\n\n[Install Guide]: /docs/INSTALL_GUIDE.md\n\n## Configure\n\nTelegraf requires a configuration to start up. A configuration requires at least\none input to collect data from and one output to send data to. The configuration\nfile is a [TOML][] file.\n\n[TOML]: /docs/TOML.md\n\n```sh\n$ cat config.toml\n[[inputs.cpu]]\n[[inputs.mem]]\n[[outputs.file]]\n```\n\nThe above enables two inputs, CPU and Memory, and one output file. The inputs\nwill collect usage information about the CPU and Memory, while the file output\nis used to print the metrics to STDOUT.\n\nNote that defining plugins to use are a TOML array of tables. This means users\ncan define a plugin multiple times. This is more useful with other plugins that\nmay need to connect to different endpoints.\n\n## Launch\n\nWith the image downloaded and a config file created, launch the image:\n\n```sh\ndocker run --rm --volume $PWD/config.toml:/etc/telegraf/telegraf.conf telegraf\n```\n\nThe user will see some initial information print out about which config file was\nloaded, version information, and what plugins were loaded. After the initial few\nseconds metrics will start to print out.\n\n## Next steps\n\nTo go beyond this quick start, users should consider the following:\n\n1. Determine where you want to collect data or metrics from and look at the\n  available [input plugins][]\n2. Determine where you want to send metrics to and look at the available\n  [output plugins][]\n3. Look at the [install guide][] for the complete list of methods to deploy and\n  install Telegraf\n4. If parsing arbitrary data or sending metrics or logs to Telegraf, read\n  through the [parsing data][] guide.\n\n[input plugins]: /plugins/inputs\n[output plugins]: /plugins/outputs\n[parsing data]: /docs/PARSING_DATA.md\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Telegraf Documentation\n\n* [FAQ][]\n* [Install Guide][]\n* [Quick Start][]\n\n## Usage\n\n* [Commands and Flags][]\n* [Configuration][]\n* [Docker][]\n* [Windows Service][]\n* [Releases][]\n* [Supported Platforms][]\n\n## Plugins\n\n* [Aggregators][]\n* [External Plugins][]\n* [Inputs][]\n  * [SQL Drivers Input][]\n* [Parsers: Input Data Formats][]\n* [Outputs][]\n* [Secret Stores][]\n* [Serializers: Output Data Formats][]\n* [Processors][]\n\n## Developers\n\n* [Custom Builds][]\n* [Integration Tests][]\n* [License of Dependencies][]\n* [Nightlies][]\n* [Profiling][]\n\n## Reference\n\n* [Aggregators & Processors][]\n* [AppArmor][]\n* [Metrics][]\n* [Parsing Data][]\n* [Template Pattern][]\n* [TOML][]\n* [TLS][]\n\n## Blog Posts\n\n* [Common Expression Language][]\n* [Config Recommendations and Performance Monitoring][]\n* [Deploying Telegraf via Docker Compose][]\n* [Reduce Binary Size][]\n* [Storing Secrets][]\n\n[Aggregators & Processors]: /docs/AGGREGATORS_AND_PROCESSORS.md\n[Aggregators]: /docs/AGGREGATORS.md\n[AppArmor]: /docs/APPARMOR.md\n[Commands and Flags]: /docs/COMMANDS_AND_FLAGS.md\n[Configuration]: /docs/CONFIGURATION.md\n[Custom Builds]: /docs/CUSTOMIZATION.md\n[Parsers: Input Data Formats]: /docs/DATA_FORMATS_INPUT.md\n[Serializers: Output Data Formats]: /docs/DATA_FORMATS_OUTPUT.md\n[Docker]: /docs/DOCKER.md\n[External Plugins]: /docs/EXTERNAL_PLUGINS.md\n[FAQ]: /docs/FAQ.md\n[Inputs]: /docs/INPUTS.md\n[Install Guide]: /docs/INSTALL_GUIDE.md\n[Integration Tests]: /docs/INTEGRATION_TESTS.md\n[License of Dependencies]: /docs/LICENSE_OF_DEPENDENCIES.md\n[Metrics]: /docs/METRICS.md\n[Nightlies]: /docs/NIGHTLIES.md\n[Outputs]: /docs/OUTPUTS.md\n[Parsing Data]: /docs/PARSING_DATA.md\n[Processors]: /docs/PROCESSORS.md\n[Profiling]: /docs/PROFILING.md\n[Quick Start]: /docs/QUICK_START.md\n[Releases]: /docs/RELEASES.md\n[Secret Stores]: /docs/SECRETSTORES.md\n[SQL Drivers Input]: /docs/SQL_DRIVERS_INPUT.md\n[Supported Platforms]: /docs/SUPPORTED_PLATFORMS.md\n[Template Pattern]: /docs/TEMPLATE_PATTERN.md\n[TLS]: /docs/TLS.md\n[TOML]: /docs/TOML.md\n[Windows Service]: /docs/WINDOWS_SERVICE.md\n\n[Config Recommendations and Performance Monitoring]: https://www.influxdata.com/blog/telegraf-best-practices/\n[Deploying Telegraf via Docker Compose]: https://www.influxdata.com/blog/telegraf-deployment-strategies-docker-compose/\n[Common Expression Language]: https://www.influxdata.com/blog/using-common-expression-language-metric-filtering-telegraf/\n[Storing Secrets]: https://www.influxdata.com/blog/storing-secrets-telegraf/\n[Reduce Binary Size]: https://www.influxdata.com/blog/how-reduce-telegraf-binary-size/\n"
  },
  {
    "path": "docs/RELEASES.md",
    "content": "# Releases\n\nTelegraf has four minor releases a year in March, June, September, and\nDecember. In between each of those minor releases, there are 2-4 bug fix\nreleases that happen every 3 weeks.\n\nThis [Google Calendar][] is kept up to date for upcoming release dates.\nAdditionally, users can look at the [GitHub milestones][] for the next minor\nand bug fix releases.\n\n## Versioning\n\nTelegraf uses semantic versioning.\n\n## Minor vs Patch Release\n\nPRs that resolve issues are released in the next release. PRs that introduce\nnew features are held for the next minor release. Users can view what\n[GitHub milestones][] a PR belongs to when they want to determine the release\nit will go out with.\n\n[Google Calendar]: https://calendar.google.com/calendar/embed?src=c_03d981cefd8d6432894cb162da5c6186e393bc0f970ca6c371201aa05d30d763%40group.calendar.google.com\n[GitHub milestones]: https://github.com/influxdata/telegraf/milestones\n"
  },
  {
    "path": "docs/SECRETSTORES.md",
    "content": "# Secret Store Plugins\n\nThis section is for developers who want to create a new secret store plugin.\n\n## Secret Store Plugin Guidelines\n\n* A secret store must conform to the [telegraf.SecretStore][] interface.\n* Secret-stores should call `secretstores.Add` in their `init` function to register\n  themselves.  See below for a quick example.\n* To be available within Telegraf itself, plugins must register themselves\n  using a file in `github.com/influxdata/telegraf/plugins/secretstores/all`\n  named according to the plugin name. Make sure you also add build-tags to\n  conditionally build the plugin.\n* Each plugin requires a file called `sample.conf` containing the sample\n  configuration  for the plugin in TOML format. Please consult the\n  [Sample Config][] page for the latest style guidelines.\n* Each plugin `README.md` file should include the `sample.conf` file in a\n  section describing the configuration by specifying a `toml` section in the\n  form `toml @sample.conf`. The specified file(s) are then injected\n  automatically into the Readme.\n* Follow the recommended [Code Style][].\n\n[telegraf.SecretStore]: https://pkg.go.dev/github.com/influxdata/telegraf?utm_source=godoc#SecretStore\n[Sample Config]: https://github.com/influxdata/telegraf/blob/master/docs/developers/SAMPLE_CONFIG.md\n[Code Style]: https://github.com/influxdata/telegraf/blob/master/docs/developers/CODE_STYLE.md\n\n## Secret Store Plugin Example\n\n### Registration\n\nRegistration of the plugin on `plugins/secretstores/all/printer.go`:\n\n```go\n//go:build !custom || secretstores || secretstores.printer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/secretstores/printer\" // register plugin\n```\n\nThe _build-tags_ in the first line allow to selectively include/exclude your\nplugin when customizing Telegraf.\n\n### Plugin\n\n```go\n//go:generate ../../../tools/readme_config_includer/generator\npackage main\n\nimport (\n    _ \"embed\"\n    \"errors\"\n\n    \"github.com/influxdata/telegraf\"\n    \"github.com/influxdata/telegraf/plugins/secretstores\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Printer struct {\n    Log telegraf.Logger `toml:\"-\"`\n\n    cache map[string]string\n}\n\nfunc (p *Printer) SampleConfig() string {\n    return sampleConfig\n}\n\nfunc (p *Printer) Init() error {\n    return nil\n}\n\n// Get searches for the given key and return the secret\nfunc (p *Printer) Get(key string) ([]byte, error) {\n    v, found := p.cache[key]\n    if !found {\n        return nil, errors.New(\"not found\")\n    }\n\n    return []byte(v), nil\n}\n\n// Set sets the given secret for the given key\nfunc (p *Printer) Set(key, value string) error {\n    p.cache[key] = value\n    return nil\n}\n\n// List lists all known secret keys\nfunc (p *Printer) List() ([]string, error) {\n    keys := make([]string, 0, len(p.cache))\n    for k := range p.cache {\n        keys = append(keys, k)\n    }\n    return keys, nil\n}\n\n// GetResolver returns a function to resolve the given key.\nfunc (p *Printer) GetResolver(key string) (telegraf.ResolveFunc, error) {\n    resolver := func() ([]byte, bool, error) {\n        s, err := p.Get(key)\n        return s, false, err\n    }\n    return resolver, nil\n}\n\n// Register the secret-store on load.\nfunc init() {\n    secretstores.Add(\"printer\", func(string) telegraf.SecretStore {\n        return &Printer{}\n    })\n}\n```\n"
  },
  {
    "path": "docs/SQL_DRIVERS_INPUT.md",
    "content": "# Available SQL drivers for the SQL input plugin\n\nThis is a list of available drivers for the SQL input plugin. The\ndata-source-name (DSN) is driver specific and might change between versions.\nPlease check the driver documentation for available options and the format.\n\n| database             | driver                                                                                  | aliases         | example DSN                                                                                                      | comment                                                                                                                      |\n|----------------------|-----------------------------------------------------------------------------------------|-----------------|------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|\n| ClickHouse           | [clickhouse](https://github.com/ClickHouse/clickhouse-go)                               |                 | `tcp://host:port[?param1=value&...&paramN=value]\"`                                                               | see [clickhouse-go docs](https://github.com/ClickHouse/clickhouse-go#dsn) for more information                               |\n| CockroachDB          | [cockroach](https://github.com/jackc/pgx)                                               | postgres or pgx | see _postgres_ driver                                                                                            | uses PostgresQL driver                                                                                                       |\n| FlightSQL            | [flightsql](https://github.com/apache/arrow/tree/main/go/arrow/flight/flightsql/driver) |                 | `flightsql://[username[:password]@]host:port?timeout=10s[&token=TOKEN][&param1=value1&...&paramN=valueN]`        | see [driver docs](https://github.com/apache/arrow/blob/main/go/arrow/flight/flightsql/driver/README.md) for more information |\n| 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                                                       |\n| MariaDB              | [maria](https://github.com/go-sql-driver/mysql)                                         | mysql           | see _mysql_ driver                                                                                               | uses MySQL driver                                                                                                            |\n| Microsoft SQL Server | [sqlserver](https://github.com/microsoft/go-mssqldb)                                    | mssql           | `sqlserver://username:password@host/instance?param1=value&param2=value`                                          | uses newer _sqlserver_ driver                                                                                                |\n| MySQL                | [mysql](https://github.com/go-sql-driver/mysql)                                         |                 | `[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]`                           | see [driver docs](https://github.com/go-sql-driver/mysql) for more information                                               |\n| Oracle               | [oracle](https://github.com/sijms/go-ora)                                               | oracle          | `oracle://username:password@host:port/service?param1=value&param2=value`                                         | see [driver docs](https://github.com/sijms/go-ora/blob/master/README.md) for more information                                |\n| 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        |\n| 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                                                        |\n| SQLite               | [sqlite](https://gitlab.com/cznic/sqlite)                                               |                 | `filename`                                                                                                       | see [driver docs](https://pkg.go.dev/modernc.org/sqlite) for more information                                                |\n| TiDB                 | [tidb](https://github.com/go-sql-driver/mysql)                                          | mysql           | see _mysql_ driver                                                                                               | uses MySQL driver                                                                                                            |\n| Vertica              | [vertica](https://github.com/vertica/vertica-sql-go)                                    |                 | `vertica://(user):(password)@(host):(port)/(database)[?arg1=value&...&argN=valueN]`                              | see [driver docs](https://github.com/vertica/vertica-sql-go) for more information                                            |\n\n## Comments\n\n### Driver aliases\n\nSome database drivers are supported though another driver (e.g. CockroachDB).\nFor other databases we provide a more obvious name (e.g. postgres) compared to\nthe driver name. For all of those drivers you might use an _alias_ name during\nconfiguration.\n\n### Example data-source-name DSN\n\nThe given examples are just that, so please check the driver documentation for\nthe exact format and available options and parameters. Please note that the\nformat of a DSN might also change between driver version.\n\n### Type conversions\n\nTelegraf relies on type conversion of the database driver and/or the golang sql\nframework. In case you find any problem, please open an issue!\n\n## Help\n\nIf nothing seems to work, you might find help in the telegraf forum or in the\nchat.\n\n### The documentation is wrong\n\nPlease open an issue or even better send a pull-request!\n\n### I found a bug\n\nPlease open an issue or even better send a pull-request!\n\n### My database is not supported\n\nWe currently cannot support CGO drivers in telegraf! Please check if a\n**pure Go** driver for the [golang sql framework][go_sql] exists. If you found\nsuch a driver, please let us know by opening an issue or even better by sending\na pull-request!\n\n[go_sql]: https://golang.org/pkg/database/sql/\n"
  },
  {
    "path": "docs/SUPPORTED_PLATFORMS.md",
    "content": "# Supported Platforms\n\nThis doc helps define the platform support for Telegraf. See the\n[install guide][] for specific options for installing Telegraf.\n\nBug reports should be submitted only for supported platforms that are under\ngeneral support, not extended or paid support. In general, Telegraf supports\nLinux, macOS, Microsoft Windows, and FreeBSD.\n\nTelegraf is written in Go, which supports many operating systems. Golang.org\nhas a [table][go-table] of valid OS and architecture combinations and the Go\nWiki has more specific [minimum requirements][go-reqs] for Go itself. Telegraf\nmay work and produce builds for other operating systems and users are welcome to\nbuild their own binaries for them. Again, bug reports must be made on a\nsupported platform.\n\n[install guide]: /docs/INSTALL_GUIDE.md\n[go-table]: https://golang.org/doc/install/source#environment\n[go-reqs]: https://github.com/golang/go/wiki/MinimumRequirements#operating-systems\n\n## FreeBSD\n\nTelegraf supports releases under FreeBSD security support. See the\n[FreeBSD security page][] for specific versions.\n\n[FreeBSD security page]: https://www.freebsd.org/security/#sup\n\n## Linux\n\nTelegraf will support the latest generally supported versions of major linux\ndistributions. This does not include extended supported releases where customers\ncan pay for additional support.\n\nBelow are some of the major distributions and the intent to support:\n\n* [Debian][]: Releases supported by security and release teams\n* [Fedora][]: Releases currently supported by Fedora team\n* [Red Hat Enterprise Linux][]: Releases under full support\n* [Ubuntu][]: Releases, interim and LTS, releases in standard support\n\n[Debian]: https://wiki.debian.org/LTS\n[Fedora]: https://fedoraproject.org/wiki/Releases\n[Red Hat Enterprise Linux]: https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates\n[Ubuntu]: https://ubuntu.com/about/release-cycle\n\n## macOS\n\nTelegraf supports releases supported by Apple. Release history is available from\n[wikipedia][wp-macos].\n\n[wp-macos]: https://endoflife.date/macos\n\n## Microsoft Windows\n\nTelegraf intends to support current versions of [Windows][] and\n[Windows Server][]. The release must be under mainstream or generally supported\nand not under any paid or extended security support.\n\n[Windows]: https://learn.microsoft.com/en-us/lifecycle/faq/windows\n[Windows Server]: https://learn.microsoft.com/en-us/windows-server/get-started/windows-server-release-info\n"
  },
  {
    "path": "docs/TEMPLATE_PATTERN.md",
    "content": "# Template Patterns\n\nTemplate patterns are a mini language that describes how a dot delimited\nstring should be mapped to and from [metrics][].\n\nA template has the form:\n\n```text\n\"host.mytag.mytag.measurement.measurement.field*\"\n```\n\nWhere the following keywords can be set:\n\n1. `measurement`: specifies that this section of the graphite bucket corresponds\nto the measurement name. This can be specified multiple times.\n2. `field`: specifies that this section of the graphite bucket corresponds\nto the field name. This can be specified multiple times.\n3. `measurement*`: specifies that all remaining elements of the graphite bucket\ncorrespond to the measurement name.\n4. `field*`: specifies that all remaining elements of the graphite bucket\ncorrespond to the field name.\n\nAny part of the template that is not a keyword is treated as a tag key. This\ncan also be specified multiple times.\n\n**NOTE:** `measurement` must be specified in your template.\n**NOTE:** `field*` cannot be used in conjunction with `measurement*`.\n\n## Examples\n\n### Measurement & Tag Templates\n\nThe most basic template is to specify a single transformation to apply to all\nincoming metrics. So the following template:\n\n```toml\ntemplates = [\n    \"region.region.measurement*\"\n]\n```\n\nwould result in the following Graphite -> Telegraf transformation.\n\n```text\nus.west.cpu.load 100\n=> cpu.load,region=us.west value=100\n```\n\nMultiple templates can also be specified, but these should be differentiated\nusing _filters_ (see below for more details)\n\n```toml\ntemplates = [\n    \"*.*.* region.region.measurement\", # <- all 3-part measurements will match this one.\n    \"*.*.*.* region.region.host.measurement\", # <- all 4-part measurements will match this one.\n]\n```\n\n### Field Templates\n\nThe field keyword tells Telegraf to give the metric that field name.\nSo the following template:\n\n```toml\nseparator = \"_\"\ntemplates = [\n    \"measurement.measurement.field.field.region\"\n]\n```\n\nwould result in the following Graphite -> Telegraf transformation.\n\n```text\ncpu.usage.idle.percent.eu-east 100\n=> cpu_usage,region=eu-east idle_percent=100\n```\n\nThe field key can also be derived from all remaining elements of the graphite\nbucket by specifying `field*`:\n\n```toml\nseparator = \"_\"\ntemplates = [\n    \"measurement.measurement.region.field*\"\n]\n```\n\nwhich would result in the following Graphite -> Telegraf transformation.\n\n```text\ncpu.usage.eu-east.idle.percentage 100\n=> cpu_usage,region=eu-east idle_percentage=100\n```\n\n### Filter Templates\n\nUsers can also filter the template(s) to use based on the name of the bucket,\nusing glob matching, like so:\n\n```toml\ntemplates = [\n    \"cpu.* measurement.measurement.region\",\n    \"mem.* measurement.measurement.host\"\n]\n```\n\nwhich would result in the following transformation:\n\n```text\ncpu.load.eu-east 100\n=> cpu_load,region=eu-east value=100\n\nmem.cached.localhost 256\n=> mem_cached,host=localhost value=256\n```\n\n### Adding Tags\n\nAdditional tags can be added to a metric that don't exist on the received metric.\nYou can add additional tags by specifying them after the pattern.\nTags have the same format as the line protocol.\nMultiple tags are separated by commas.\n\n```toml\ntemplates = [\n    \"measurement.measurement.field.region datacenter=1a\"\n]\n```\n\nwould result in the following Graphite -> Telegraf transformation.\n\n```text\ncpu.usage.idle.eu-east 100\n=> cpu_usage,region=eu-east,datacenter=1a idle=100\n```\n\n[metrics]: /docs/METRICS.md\n"
  },
  {
    "path": "docs/TLS.md",
    "content": "# Transport Layer Security\n\nThere is an ongoing effort to standardize TLS options across plugins.  When\npossible, plugins will provide the standard settings described below.  With the\nexception of the advanced configuration available TLS settings will be\ndocumented in the sample configuration.\n\n## Client Configuration\n\nFor client TLS support we have the following options:\n\n```toml\n## Enable/disable TLS\n## Set to true/false to enforce TLS being enabled/disabled. If not set,\n## enable TLS only if any of the other options are specified.\n# tls_enable =\n\n## Root certificates for verifying server certificates encoded in PEM format.\n# tls_ca = \"/etc/telegraf/ca.pem\"\n\n## The public and private key pairs for the client encoded in PEM format.  May\n## contain intermediate certificates.\n# tls_cert = \"/etc/telegraf/cert.pem\"\n# tls_key = \"/etc/telegraf/key.pem\"\n# passphrase for encrypted private key, if it is in PKCS#8 format. Encrypted PKCS#1 private keys are not supported.\n# tls_key_pwd = \"changeme\"\n## Skip TLS verification.\n# insecure_skip_verify = false\n## Send the specified TLS server name via SNI.\n# tls_server_name = \"foo.example.com\"\n#\n```\n\n### Server Configuration\n\nThe server TLS configuration provides support for TLS mutual authentication:\n\n```toml\n## Set one or more allowed client CA certificate file names to\n## enable mutually authenticated TLS connections.\n# tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n## Set one or more allowed DNS name to enable a whitelist\n## to verify incoming client certificates.\n## It will go through all available SAN in the certificate,\n## if of them matches the request is accepted.\n# tls_allowed_dns_names = [\"client.example.org\"]\n\n## Add service certificate and key.\n# tls_cert = \"/etc/telegraf/cert.pem\"\n# tls_key = \"/etc/telegraf/key.pem\"\n# passphrase for encrypted private key, if it is in PKCS#8 format. Encrypted PKCS#1 private keys are not supported.\n# tls_key_pwd = \"changeme\"\n```\n\n#### Advanced Configuration\n\nFor plugins using the standard server configuration you can also set several\nadvanced settings. These options are not included in the sample configuration\nfor the interest of brevity.\n\n```toml\n## Define list of allowed ciphers suites.  If not defined the default ciphers\n## supported by Go will be used.\n##   ex: tls_cipher_suites = [\n##           \"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305\",\n##           \"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305\",\n##           \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\",\n##           \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\",\n##           \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\",\n##           \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\",\n##           \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\",\n##           \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\",\n##           \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\",\n##           \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\",\n##           \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\",\n##           \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\",\n##           \"TLS_RSA_WITH_AES_128_GCM_SHA256\",\n##           \"TLS_RSA_WITH_AES_256_GCM_SHA384\",\n##           \"TLS_RSA_WITH_AES_128_CBC_SHA256\",\n##           \"TLS_RSA_WITH_AES_128_CBC_SHA\",\n##           \"TLS_RSA_WITH_AES_256_CBC_SHA\"\n##       ]\n# tls_cipher_suites = []\n\n## Minimum TLS version that is acceptable.\n# tls_min_version = \"TLS10\"\n\n## Maximum SSL/TLS version that is acceptable.\n# tls_max_version = \"TLS13\"\n```\n\nCipher suites for use with `tls_cipher_suites`:\n\n- `TLS_RSA_WITH_RC4_128_SHA`\n- `TLS_RSA_WITH_3DES_EDE_CBC_SHA`\n- `TLS_RSA_WITH_AES_128_CBC_SHA`\n- `TLS_RSA_WITH_AES_256_CBC_SHA`\n- `TLS_RSA_WITH_AES_128_CBC_SHA256`\n- `TLS_RSA_WITH_AES_128_GCM_SHA256`\n- `TLS_RSA_WITH_AES_256_GCM_SHA384`\n- `TLS_ECDHE_ECDSA_WITH_RC4_128_SHA`\n- `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA`\n- `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA`\n- `TLS_ECDHE_RSA_WITH_RC4_128_SHA`\n- `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`\n- `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA`\n- `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`\n- `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256`\n- `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256`\n- `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`\n- `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`\n- `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`\n- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`\n- `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305`\n- `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305`\n- `TLS_AES_128_GCM_SHA256`\n- `TLS_AES_256_GCM_SHA384`\n- `TLS_CHACHA20_POLY1305_SHA256`\n\nTLS versions for use with `tls_min_version` or `tls_max_version`:\n\n- `TLS10`\n- `TLS11`\n- `TLS12`\n- `TLS13`\n"
  },
  {
    "path": "docs/TOML.md",
    "content": "# TOML\n\nTelegraf uses TOML as the configuration language. The following outlines a few\ncommon questions and issues that cause questions or confusion.\n\n## Reference and Validator\n\nFor all things TOML related, please consult the [TOML Spec][] and consider\nusing a TOML validator. In VSCode the [Even Better TOML][] extension or use the\n[TOML Lint][] website to validate your TOML config.\n\n[TOML Spec]: https://toml.io/en/v1.0.0\n[Even Better TOML]: https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml\n[TOML Lint]: https://www.toml-lint.com/\n\n## Multiple TOML Files\n\nTOML technically does not support multiple files, this is done as a convenience for\nusers.\n\nUsers should be aware that when Telegraf reads a user's config, if multiple\nfiles or directories are read in, each file at a time and all\nsettings are combined as if it were one big file.\n\n## Single Table vs Array of Tables\n\nTelegraf uses a single agent table (e.g. `[agent]`) to control high-level agent\nspecific configurations. This section can only be defined once for all config\nfiles and should be in the first file read in to take effect. This cannot be\ndefined per-config file.\n\nTelegraf also uses array of tables (e.g. `[[inputs.file]]`) to define multiple\nplugins. These can be specified as many times as a user wishes.\n\n## In-line Table vs Table\n\nIn some cases, a configuration option for a plugin may define a table of\nconfiguration options. Take for example, the ability to add arbitrary tags to\nan input plugin:\n\n```toml\n[[inputs.cpu]]\n  percpu = false\n  totalcpu = true\n  [inputs.cpu.tags]\n    tag1 = \"foo\"\n    tag2 = \"bar\"\n```\n\nUser's should understand that these tables *must* be at the end of the plugin\ndefinition, because any key-value pair is assumed to be part of that table. The\nfollowing demonstrates how this can cause confusion:\n\n```toml\n[[inputs.cpu]]\n  totalcpu = true\n  [inputs.cpu.tags]\n    tag1 = \"foo\"\n    tag2 = \"bar\"\n  percpu = false  # this is treated as a tag to add, not a config option\n```\n\nNote TOML does not care about how a user indents the config or whitespace, so\nthe `percpu` option is considered a tag.\n\nA far better approach to avoid this situation is to use inline table syntax:\n\n```toml\n[[inputs.cpu]]\n  tags = {tag1 = \"foo\", tag2 = \"bar\"}\n  percpu = false\n  totalcpu = true\n```\n\nThis way the tags value can go anywhere in the config and avoids possible\nconfusion.\n\n## Basic String vs String Literal\n\nIn basic strings, signified by double-quotes, certain characters like the\nbackslash and double quote contained in a basic string need to be escaped for\nthe string to be valid.\n\nFor example the following invalid TOML, includes a Windows path with\nunescaped backslashes:\n\n```toml\npath = \"C:\\Program Files\\\"  # this is invalid TOML\n```\n\nUser's can either escape the backslashes or use a literal string, which is\nsignified by single-quotes:\n\n```toml\npath = \"C:\\\\Program Files\\\\\"\npath = 'C:\\Program Files\\'\n```\n\nLiteral strings return exactly what you type. As there is no escaping in literal\nstrings you cannot have an apostrophe in a literal string.\n"
  },
  {
    "path": "docs/WINDOWS_SERVICE.md",
    "content": "# Running Telegraf as a Windows Service\n\nTelegraf natively supports running as a Windows Service. Outlined below is are\nthe general steps to set it up.\n\n1. Obtain the telegraf windows distribution\n2. Create the directory `C:\\Program Files\\Telegraf` or use a custom directory\n   if desired\n3. Place the telegraf.exe and the telegraf.conf config file into the directory,\n   either `C:\\Program Files\\Telegraf` or the custom directory of your choice.\n   If you install in a different location simply specify the `--config`\n   parameter with the desired location.\n4. To install the service into the Windows Service Manager, run the command\n   as administrator. Make sure to wrap parameters containing spaces in double\n   quotes:\n\n   ```shell\n   > \"C:\\Program Files\\Telegraf\\telegraf.exe\" service install\n   ```\n\n5. Edit the configuration file to meet your needs\n6. To check that it works, run:\n\n   ```shell\n   > \"C:\\Program Files\\Telegraf\\telegraf.exe\" --config \"C:\\Program Files\\Telegraf\\telegraf.conf\" --test\n   ```\n\n7. To start collecting data, run:\n\n   ```shell\n   > net start telegraf\n   ```\n\n   or\n\n   ```shell\n   > \"C:\\Program Files\\Telegraf\\telegraf.exe\" service start\n   ```\n\n   or use the Windows service manager to start the service\n\nPlease also check the Windows event log or your configured log-file for errors\nduring startup.\n\n## Config Directory\n\nYou can also specify a `--config-directory` for the service to use:\n\n1. Create a directory for config snippets: `C:\\Program Files\\Telegraf\\telegraf.d`\n2. Include the `--config-directory` option when registering the service:\n\n   ```shell\n   > \"C:\\Program Files\\Telegraf\\telegraf.exe\" --config C:\\\"Program Files\"\\Telegraf\\telegraf.conf --config-directory C:\\\"Program Files\"\\Telegraf\\telegraf.d service install\n   ```\n\n## Other supported operations\n\nTelegraf can manage its own service through the --service flag:\n\n| Command                          | Effect                                   |\n|----------------------------------|------------------------------------------|\n| `telegraf.exe service install`   | Install telegraf as a service            |\n| `telegraf.exe service uninstall` | Remove the telegraf service              |\n| `telegraf.exe service start`     | Start the telegraf service               |\n| `telegraf.exe service stop`      | Stop the telegraf service                |\n| `telegraf.exe service status`    | Query the status of the telegraf service |\n\n## Install multiple services\n\nRunning multiple instances of Telegraf is seldom needed, as you can run\nmultiple instances of each plugin and route metric flow using the metric\nfiltering options. However, if you do need to run multiple telegraf instances\non a single system, you can install the service with the `--service-name` and\n`--display-name` flags to give the services unique names:\n\n```shell\n> \"C:\\Program Files\\Telegraf\\telegraf.exe\" --service-name telegraf-1 service install --display-name \"Telegraf 1\"\n> \"C:\\Program Files\\Telegraf\\telegraf.exe\" --service-name telegraf-2 service install --display-name \"Telegraf 2\"\n```\n\n## Auto restart and restart delay\n\nBy default the service will not automatically restart on failure. Providing the\n`--auto-restart` flag during installation will always restart the service with\na default delay of 5 minutes. To modify this to for example 3 minutes,\nadditionally provide `--restart-delay 3m` flag. The delay can be any valid\n`time.Duration` string.\n\n## Troubleshooting\n\nWhen Telegraf runs as a Windows service, Telegraf logs all messages concerning\nthe service startup to the Windows event log. All messages and errors occuring\nduring runtime will be logged to the log-target you configured.\nCheck the event log for errors reported by the `telegraf` service (or the\nservice-name you configured) during service startup:\n`Event Viewer -> Windows Logs -> Application`\n\n### Common error #1067\n\nWhen installing as service in Windows, always double check to specify full path\nof the config file, otherwise windows service will fail to start. Use\n\n```shell\n> \"C:\\Program Files\\Telegraf\\telegraf.exe\" --config \"C:\\MyConfigs\\telegraf.conf\" service install\n```\n\ninstead of\n\n```shell\n> \"C:\\Program Files\\Telegraf\\telegraf.exe\" --config \"telegraf.conf\" service install\n```\n\n### Service is killed during shutdown\n\nWhen shuting down Windows the Telegraf service tries to cleanly stop when\nreceiving the corresponding notification from the Windows service manager. The\nexit process involves stopping all inputs, processors and aggregators and\nfinally to flush all remaining metrics to the output(s). In case many metrics\nare not yet flushed this final step might take some time. However, Windows will\nkill the service and the corresponding process after a predefined timeout\n(usually 5 seconds).\n\nYou can change that timeout in the registry under\n\n````text\nHKLM\\SYSTEM\\CurrentControlSet\\Control\\WaitToKillServiceTimeout\n```\n\n**NOTE:** The value is in milliseconds and applies to **all** services!\n"
  },
  {
    "path": "docs/developers/CODE_STYLE.md",
    "content": "# Code Style\n\nCode is required to be formatted using `gofmt`, this covers most code style\nrequirements.  It is also highly recommended to use `goimports` to\nautomatically order imports.\n\nPlease try to keep lines length under 80 characters, the exact number of\ncharacters is not strict but it generally helps with readability.\n"
  },
  {
    "path": "docs/developers/DEBUG.md",
    "content": "# Debug\n\nThe following describes how to use the [delve][1] debugger with telegraf\nduring development. Delve has many, very well documented [subcommands][2] and\noptions.\n\n[1]: https://github.com/go-delve/delve\n[2]: https://github.com/go-delve/delve/blob/master/Documentation/usage/README.md\n\n## CLI\n\nTo run telegraf manually, users can run:\n\n```bash\ngo run ./cmd/telegraf --config config.toml\n```\n\nTo attach delve with a similar config users can run the following. Note the\nadditional `--` to specify flags passed to telegraf. Additional flags need to\ngo after this double dash:\n\n```bash\n$ dlv debug ./cmd/telegraf -- --config config.toml\nType 'help' for list of commands.\n(dlv)\n```\n\nAt this point a user could set breakpoints and continue execution.\n\n## Visual Studio Code\n\nVisual Studio Code's [go language extension][20] includes the ability to easily\nmake use of [delve for debugging][21]. Check out this [full tutorial][22] from\nthe go extension's wiki.\n\nA basic config is all that is required along with additional arguments to tell\nTelegraf where the config is located:\n\n```json\n{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Launch Package\",\n            \"type\": \"go\",\n            \"request\": \"launch\",\n            \"mode\": \"auto\",\n            \"program\": \"${fileDirname}\",\n            \"args\": [\"--config\", \"/path/to/config\"]\n        }\n    ]\n}\n```\n\n[20]: https://code.visualstudio.com/docs/languages/go\n[21]: https://code.visualstudio.com/docs/languages/go#_debugging\n[22]: https://github.com/golang/vscode-go/wiki/debugging\n\n## GoLand\n\nJetBrains' [GoLand][30] also includes full featured [debugging][31] options.\n\nThe following is an example debug config to run Telegraf with a config:\n\n```xml\n<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"build &amp; run\" type=\"GoApplicationRunConfiguration\" factoryName=\"Go Application\">\n    <module name=\"telegraf\" />\n    <working_directory value=\"$PROJECT_DIR$\" />\n    <parameters value=\"--config telegraf.conf\" />\n    <kind value=\"DIRECTORY\" />\n    <package value=\"github.com/influxdata/telegraf\" />\n    <directory value=\"$PROJECT_DIR$/cmd/telegraf\" />\n    <filePath value=\"$PROJECT_DIR$\" />\n    <method v=\"2\" />\n  </configuration>\n</component>\n```\n\n[30]: https://www.jetbrains.com/go/\n[31]: https://www.jetbrains.com/help/go/debugging-code.html\n"
  },
  {
    "path": "docs/developers/DEPRECATION.md",
    "content": "# Deprecation\n\nDeprecation is the primary tool for making changes in Telegraf.  A deprecation\nindicates that the community should move away from using a feature, and\ndocuments that the feature will be removed in the next major update (2.0).\n\nKey to deprecation is that the feature remains in Telegraf and the behavior is\nnot changed.\n\nWe do not have a strict definition of a breaking change.  All code changes\nchange behavior, the decision to deprecate or make the change immediately is\ndecided based on the impact.\n\n## Deprecate plugins\n\nAdd an entry to the plugins deprecation list (e.g. in\n`plugins/inputs/deprecations.go`). Include the deprecation version and any\nreplacement, e.g.\n\n```golang\n  \"logparser\": {\n    Since:  \"1.15.0\",\n    Notice: \"use 'inputs.tail' with 'grok' data format instead\",\n  },\n```\n\nThe entry can contain an optional `RemovalIn` field specifying the planned\nversion for removal of the plugin.\n\nAlso add the deprecation warning to the plugin's README:\n\n```markdown\n# Logparser Input Plugin\n\n### **Deprecated in 1.10**: Please use the [tail][] plugin along with the\n`grok` [data format][].\n\n[tail]: /plugins/inputs/tail/README.md\n[data formats]: /docs/DATA_FORMATS_INPUT.md\n```\n\nTelegraf will automatically check if a deprecated plugin is configured and print\na warning\n\n```text\n2022-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\n```\n\n## Deprecate options\n\nMark the option as deprecated in the sample config, include the deprecation\nversion and any replacement.\n\n```toml\n  ## Broker to publish to.\n  ##   deprecated in 1.7; use the brokers option\n  # url = \"amqp://localhost:5672/influxdb\"\n```\n\nIn the plugins configuration struct, add a `deprecated` tag to the option:\n\n```go\ntype AMQP struct {\n    URL       string `toml:\"url\" deprecated:\"1.7.0;use 'brokers' instead\"`\n    Precision string `toml:\"precision\" deprecated:\"1.2.0;option is ignored\"`\n}\n```\n\nThe `deprecated` tag has the format `<since version>[;removal version];<notice>`\nwhere the `removal version` is optional. The specified deprecation info will\nautomatically displayed by Telegraf if the option is used in the config\n\n```text\n2022-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\n```\n\n### Option value\n\nIn the case a specific option value is being deprecated, the method\n`models.PrintOptionValueDeprecationNotice` needs to be called in the plugin's\n`Init` method.\n\n## Deprecate metrics\n\nIn the README document the metric as deprecated.  If there is a replacement\nfield, tag, or measurement then mention it.\n\n```markdown\n- system\n  - fields:\n    - uptime_format (string, deprecated in 1.10: use `uptime` field)\n```\n\nAdd filtering to the sample config, leave it commented out.\n\n```toml\n[[inputs.system]]\n  ## Uncomment to remove deprecated metrics.\n  # fieldexclude = [\"uptime_format\"]\n```\n"
  },
  {
    "path": "docs/developers/LOGGING.md",
    "content": "# Logging\n\n## Plugin Logging\n\nYou can access the Logger for a plugin by defining a field named `Log`.  This\n`Logger` is configured internally with the plugin name and alias so they do not\nneed to be specified for each log call.\n\n```go\ntype MyPlugin struct {\n    Log telegraf.Logger `toml:\"-\"`\n}\n```\n\nYou can then use this Logger in the plugin.  Use the method corresponding to\nthe log level of the message.\n\n```go\np.Log.Errorf(\"Unable to write to file: %v\", err)\n```\n\n## Agent Logging\n\nIn other sections of the code it is required to add the log level and module\nmanually:\n\n```go\nlog.Printf(\"E! [agent] Error writing to %s: %v\", output.LogName(), err)\n```\n\n## When to Log\n\nLog a message if an error occurs but the plugin can continue working.  For\nexample if the plugin handles several servers and only one of them has a fatal\nerror, it can be logged as an error.\n\nUse logging judiciously for debug purposes.  Since Telegraf does not currently\nsupport setting the log level on a per module basis, it is especially important\nto not over do it with debug logging.\n\nIf the plugin is listening on a socket, log a message with the address of the socket:\n\n```go\np.log.InfoF(\"Listening on %s://%s\", protocol, l.Addr())\n```\n\n## When not to Log\n\nDon't use logging to emit performance data or other meta data about the plugin,\ninstead use the `internal` plugin and the `selfstats` package.\n\nDon't log fatal errors in the plugin that require the plugin to return, instead\nreturn them from the function and Telegraf will handle the logging.\n\nDon't log for static configuration errors, check for them in a plugin `Init()`\nfunction and return an error there.\n\nDon't log a warning every time a plugin is called for situations that are\nnormal on some systems.\n\n## Log Level\n\nThe log level is indicated by a single character at the start of the log\nmessage.  Adding this prefix is not required when using the Plugin Logger.\n\n- `D!` Debug\n- `I!` Info\n- `W!` Warning\n- `E!` Error\n\n## Style\n\nLog messages should be capitalized and be a single line.\n\nIf it includes data received from another system or process, such as the text\nof an error message, the text should be quoted with `%q`.\n\nUse the `%v` format for the Go error type instead of `%s` to ensure a nil error\nis printed.\n"
  },
  {
    "path": "docs/developers/METRIC_FORMAT_CHANGES.md",
    "content": "# Metric Format Changes\n\nWhen making changes to an existing input plugin, care must be taken not to\nchange the metric format in ways that will cause trouble for existing users.\nThis document helps developers understand how to make metric format changes\nsafely.\n\n## Changes can cause incompatibilities\n\nIf the metric format changes, data collected in the new format can be\nincompatible with data in the old format. Database queries designed around the\nold format may not work with the new format. This can cause application failures.\n\nSome metric format changes don't cause incompatibilities. Also, some unsafe\nchanges are necessary. How do you know what changes are safe and what to do if\nyour change isn't safe?\n\n## Guidelines\n\nThe main guideline is just to keep compatibility in mind when making changes.\nOften developers are focused on making a change that fixes their particular\nproblem and they forget that many people use the existing code and will upgrade.\nWhen you're coding, keep existing users and applications in mind.\n\n### Renaming, removing, reusing\n\nDatabase queries refer to the metric and its tags and fields by name. Any\nTelegraf code change that changes those names has the potential to break an\nexisting query. Similarly, removing tags or fields can break queries.\n\nChanging the meaning of an existing tag value or field value or reusing an\nexisting one in a new way isn't safe. Although queries that use these tags/field\nmay not break, they will not work as they did before the change.\n\nAdding a field doesn't break existing queries. Queries that select all fields\nand/or tags (like \"select * from\") will return an extra series but this is often\nuseful.\n\n### Performance and storage\n\nTime series databases can store large amounts of data but many of them don't\nperform well on high cardinality data. If a metric format change includes a new\ntag that holds high cardinality data, database performance could be reduced\nenough to cause existing applications not to work as they previously did.\nMetric format changes that dramatically increase the number of tags or fields of\na metric can increase database storage requirements unexpectedly. Both of these\ntypes of changes are unsafe.\n\n### Make unsafe changes opt-in\n\nIf your change has the potential to seriously affect existing users, the change\nmust be opt-in. To do this, add a plugin configuration setting that lets the\nuser select the metric format. Make the setting's default value select the old\nmetric format. When new users add the plugin they can choose the new format and\nget its benefits. When existing users upgrade, their config files won't have the\nnew setting so the default will ensure that there is no change.\n\nWhen adding a setting, avoid using a boolean and consider instead a string or\nint for future flexibility. A boolean can only handle two formats but a string\ncan handle many. For example, compare `use_new_format=true` and\n`features=[\"enable_foo_fields\"]`; the latter is much easier to extend and still\nvery descriptive.\n\nIf you want to encourage existing users to use the new format you can log a\nwarning once on startup when the old format is selected. The warning should\ntell users in a gentle way that they can upgrade to a better metric format.\nIf it doesn't make sense to maintain multiple metric formats forever, you can\nchange the default on a major release or even remove the old format completely.\nSee [[Deprecation]] for details.\n\n### Utility\n\nChanges should be useful to many or most users. A change that is only useful for\na small number of users may not accepted, even if it's off by default.\n\n## Summary table\n\n|     | delete | rename | add |\n| ------- | ------ | ------ | --- |\n| metric | unsafe | unsafe | safe |\n| tag   | unsafe | unsafe | be careful with cardinality |\n| field  | unsafe | unsafe | ok as long as it's useful for existing users and is worth the added space |\n\n## References\n\nInfluxDB Documentation: \"Schema and data layout\"\n"
  },
  {
    "path": "docs/developers/PACKAGING.md",
    "content": "# Packaging\n\nBuilding the packages for Telegraf is automated using [Make][make]. Just running\n`make` will build a Telegraf binary for the operating system and architecture\nyou are using (if it is supported). If you need to build a different package\nthen you can run `make package` which will build all the supported packages. You\nwill most likely only want a subset, you can define a subset of packages to be\nbuilt by overriding the `include_packages` variable like so\n\n```shell\nmake package include_packages=\"amd64.deb\"\n```\n\nYou can also build all packages for a specific architecture like so\n\n```shell\nmake package include_packages=\"$(make amd64)\"\n```\n\nThe packaging steps require certain tools to be setup before hand to work.\nThese dependencies are listed in the ci.docker file which you can find in the\nscripts directory. Therefore it is recommended to use Docker to build the\nartifacts, see more details below.\n\n[make]: https://en.wikipedia.org/wiki/Make_(software)\n\n## Go Version\n\nTelegraf will be built using the latest version of Go whenever possible.\n\n### Update CI image\n\nIncrementing the version is maintained by the core Telegraf team because it\nrequires access to an internal docker repository that hosts the docker CI\nimages. When a new version is released, the following process is followed:\n\n1. Within the `Makefile`, `.circleci\\config.yml`, and `scripts/ci.docker` files\n  update the Go versions to the new version number\n2. Run `make ci`, this requires quay.io internal permissions\n3. The files `scripts\\installgo_linux.sh`, `scripts\\installgo_mac.sh`, and\n  `scripts\\installgo_windows.sh` need to be updated as well with the new Go\n  version and SHA\n4. Create a pull request with these new changes, and verify the CI passes and\n  uses the new docker image\n\nSee the [previous PRs](https://github.com/influxdata/telegraf/search?q=chore+update+go&type=commits)\nas examples.\n\n### Access to quay.io\n\nA member of the team needs to invite you to the quay.io organization.\nTo push new images, the user needs to do the following:\n\n1. Create a password if the user logged in using Google authentication\n2. Download an encrypted username/password from the quay.io user page\n3. Run `docker login quay.io` and enter in the encrypted username and password\n  from the previous step\n\n## Package using Docker\n\nThis packaging method uses the CI images, and is very similar to how the\nofficial packages are created on release.  This is the recommended method for\nbuilding the rpm/deb as it is less system dependent.\n\nPull the CI images from quay, the version corresponds to the version of Go\nthat is used to build the binary:\n\n```shell\ndocker pull quay.io/influxdb/telegraf-ci:1.9.7\n```\n\nStart a shell in the container:\n\n```shell\ndocker run -ti quay.io/influxdb/telegraf-ci:1.9.7 /bin/bash\n```\n\nFrom within the container:\n\n1. `go get -d github.com/influxdata/telegraf`\n2. `cd /go/src/github.com/influxdata/telegraf`\n3. `git checkout release-1.10`\n   * Replace tag `release-1.10` with the version of Telegraf you would like to\n   build\n4. `git reset --hard 1.10.2`\n5. `make deps`\n6. `make package include_packages=\"amd64.deb\"`\n    * Change `include_packages` to change what package you want, run `make help`\n    to see possible values\n\nFrom the host system, copy the build artifacts out of the container:\n\n```shell\ndocker cp romantic_ptolemy:/go/src/github.com/influxdata/telegraf/build/telegraf-1.10.2-1.x86_64.rpm .\n```\n"
  },
  {
    "path": "docs/developers/PROFILING.md",
    "content": "# Profiling\n\nThis article describes how to collect performance traces and memory profiles\nfrom Telegraf. If you are submitting this for an issue, please include the\nversion.txt generated below.\n\nUse the `--pprof-addr` option to enable the profiler, the easiest way to do\nthis may be to add this line to `/etc/default/telegraf`:\n\n```shell\nTELEGRAF_OPTS=\"--pprof-addr localhost:6060\"\n```\n\nRestart Telegraf to activate the profile address.\n\n## Trace Profile\n\nCollect a trace during the time where the performance issue is occurring.  This\nexample collects a 10 second trace and runs for 10 seconds:\n\n```shell\ncurl 'http://localhost:6060/debug/pprof/trace?seconds=10' > trace.bin\ntelegraf --version > version.txt\ngo env GOOS GOARCH >> version.txt\n```\n\nThe `trace.bin` and `version.txt` files can be sent in for analysis or, if\ndesired, you can analyze the trace with:\n\n```shell\ngo tool trace trace.bin\n```\n\n## Memory Profile\n\nCollect a heap memory profile:\n\n```shell\ncurl 'http://localhost:6060/debug/pprof/heap' > mem.prof\ntelegraf --version > version.txt\ngo env GOOS GOARCH >> version.txt\n```\n\nAnalyze:\n\n```shell\n$ go tool pprof mem.prof\n(pprof) top5\n```\n\n## CPU Profile\n\nCollect a 30s CPU profile:\n\n```shell\ncurl 'http://localhost:6060/debug/pprof/profile' > cpu.prof\ntelegraf --version > version.txt\ngo env GOOS GOARCH >> version.txt\n```\n\nAnalyze:\n\n```shell\ngo tool pprof cpu.prof\n(pprof) top5\n```\n"
  },
  {
    "path": "docs/developers/REVIEWS.md",
    "content": "# Reviews\n\nPull-requests require two approvals before being merged. Expect several rounds\nof back and forth on reviews, non-trivial changes are rarely accepted on the\nfirst pass. It might take some time until you see a first review so please be\npatient.\n\nAll pull requests should follow the style and best practices in the\n[CONTRIBUTING.md](https://github.com/influxdata/telegraf/blob/master/CONTRIBUTING.md)\ndocument.\n\n## Process\n\nThe review process is roughly structured as follows:\n\n1. Submit a pull request.\n   Please check that you signed the [CLA](https://www.influxdata.com/legal/cla/)\n   (and [Corporate CLA](https://www.influxdata.com/legal/ccla/) if you are\n   contributing code on as an employee of your company). Provide a short\n   description of your submission and reference issues that you potentially\n   close. Make sure the CI tests are all green and there are no linter-issues.\n1. Get feedback from a first reviewer and a `ready for final review` tag.\n   Please constructively work with the reviewer to get your code into a\n   mergeable state (see also [below](#reviewing-plugin-code)).\n1. Get a final review by one of the InfluxData maintainers. Please fix any issue\n   raised.\n1. Wait for the pull-request to be merged. It might take some time until your PR\n   gets merged, depending on the release cycle and the type of your pull-request\n   (bugfix, enhancement of existing code, new plugin, etc). Remember, it might\n   be necessary to rebase your code before merge to resolve conflicts.\n\nPlease read the review comments carefully, fix the related part of the code\nand/or respond in case there is anything unclear. Maintainers will add the\n`waiting for response` tag to PRs to make it clear we are waiting on the\nsubmitter for updates.\n__Once the tag is added, if there is no activity on a pull request or the\ncontributor does not respond, our bot will automatically close the PR after two\nweeks!__ If you expect a longer period of inactivity or you want to abandon a\npull request, please let us know.\n\nIn case you still want to continue with the PR, feel free to reopen it.\n\n## Reviewing Plugin Code\n\n- Avoid variables scoped to the package. Everything should be scoped to the\n  plugin struct, since multiple instances of the same plugin are allowed and\n  package-level variables will cause race conditions.\n- SampleConfig must match the readme, but not include the plugin name.\n- structs should include toml tags for fields that are expected to be editable\n  from the config. eg `toml:\"command\"` (snake_case)\n- plugins that want to log should declare the Telegraf logger, not use the log\n  package. eg:\n\n```Go\n  Log telegraf.Logger `toml:\"-\"`\n```\n\n(in tests, you can do `myPlugin.Log = testutil.Logger{}`)\n\n- Initialization and config checking should be done on the `Init() error`\n  function, not in the Connect, Gather, or Start functions.\n- `Init() error` should not contain connections to external services. If\n  anything fails in Init, Telegraf will consider it a configuration error and\n  refuse to start.\n- plugins should avoid synchronization code if they are not starting goroutines.\n  Plugin functions are never called in parallel.\n- avoid goroutines when you don't need them and removing them would simplify the\n  code\n- errors should almost always be checked.\n- avoid boolean fields when a string or enumerated type would be better for\n  future extension. Lots of boolean fields also make the code difficult to\n  maintain.\n- use config.Duration instead of internal.Duration\n- compose tls.ClientConfig as opposed to specifying all the TLS fields manually\n- http.Client should be declared once on `Init() error` and reused, (or better\n  yet, on the package if there's no client-specific configuration).\n  `http.Client` has built-in concurrency protection and reuses connections\n  transparently when possible.\n- avoid doing network calls in loops where possible, as this has a large\n  performance cost. This isn't always possible to avoid.\n- when processing batches of records with multiple network requests (some\n  outputs that need to partition writes do this), return an error when you want\n  the whole batch to be retried, log the error when you want the batch to\n  continue without the record\n- consider using the StreamingProcessor interface instead of the (legacy)\n  Processor interface\n- avoid network calls in processors when at all possible. If it's necessary,\n  it's possible, but complicated (see processor.reversedns).\n- avoid dependencies when:\n  - they require cgo\n  - they pull in massive projects instead of small libraries\n  - they could be replaced by a simple http call\n  - they seem unnecessary, superfluous, or gratuitous\n- consider adding build tags if plugins have OS-specific considerations\n- use the right logger log levels so that Telegraf is normally quiet eg\n `plugin.Log.Debugf()` only shows up when running Telegraf with `--debug`\n- consistent field types: dynamically setting the type of a field should be\n  strongly avoided as it causes problems that are difficult to solve later,\n  made worse by having to worry about backwards compatibility in future changes.\n  For example, if an numeric value comes from a string field and it is not clear\n  if the field can sometimes be a float, the author should pick either a float\n  or an int, and parse that field consistently every time. Better to sometimes\n  truncate a float, or to always store ints as floats, rather than changing the\n  field type, which causes downstream problems with output databases.\n- backwards compatibility: We work hard not to break existing configurations\n  during new changes. Upgrading Telegraf should be a seamless transition.\n  Possible tools to make this transition smooth are:\n  - enumerable type fields that allow you to customize behavior\n    (avoid boolean feature flags)\n  - version fields that can be used to opt in to newer changed behavior without\n    breaking old (see inputs.mysql for example)\n  - a new version of the plugin if it has changed significantly\n    (e.g. `outputs.influxdb` and `outputs.influxdb_v2`)\n  - Logger and README deprecation warnings\n  - changing the default value of a field can be okay, but will affect users who\n    have not specified the field and should be approached cautiously.\n  - The general rule here is \"don't surprise me\": users should not be caught\n    off-guard by unexpected or breaking changes.\n\n## Linting\n\nEach pull request will have the appropriate linters checking the files for any\ncommon mistakes. The github action Super Linter is used:\n[super-linter](https://github.com/github/super-linter). If it is failing you can\nclick on the action and read the logs to figure out the issue. You can also run\nthe github action locally by following these instructions:\n[run-linter-locally.md](https://github.com/github/super-linter/blob/main/docs/run-linter-locally.md).\nYou can find more information on each of the linters in the super linter readme.\n\n## Testing\n\nSufficient unit tests must be created.  New plugins must always contain\nsome unit tests.  Bug fixes and enhancements should include new tests, but\nthey can be allowed if the reviewer thinks it would not be worth the effort.\n\n[Table Driven Tests](https://github.com/golang/go/wiki/TableDrivenTests) are\nencouraged to reduce boiler plate in unit tests.\n\nThe [stretchr/testify](https://github.com/stretchr/testify) library should be\nused for assertions within the tests when possible, with preference towards\ngithub.com/stretchr/testify/require.\n\nPrimarily use the require package to avoid cascading errors:\n\n```go\nassert.Equal(t, lhs, rhs) # avoid\nrequire.Equal(t, lhs, rhs) # good\n```\n\n## Configuration\n\nThe config file is the primary interface and should be carefully scrutinized.\n\nEnsure the [[SampleConfig]] and\n[README](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/EXAMPLE_README.md)\nmatch with the current standards.\n\nREADMEs should:\n\n- be spaces, not tabs\n- be indented consistently, matching other READMEs\n- have two `#` for comments\n- have one `#` for defaults, which should always match the default value of the plugin\n- include all appropriate types as a list for enumerable field types\n- include a useful example, avoiding \"example\", \"test\", etc.\n- include tips for any common problems\n- include example output from the plugin, if input/processor/aggregator/parser/serializer\n\n## Metric Schema\n\nTelegraf metrics are heavily based on InfluxDB points, but have some\nextensions to support other outputs and metadata.\n\nNew metrics must follow the recommended\n[schema design](https://docs.influxdata.com/influxdb/latest/concepts/schema_and_data_layout/).\nEach metric should be evaluated for _series cardinality_, proper use of tags vs\nfields, and should use existing patterns for encoding metrics.\n\nMetrics use `snake_case` naming style.\n\n### Enumerations\n\nGenerally enumeration data should be encoded as a tag.  In some cases it may\nbe desirable to also include the data as an integer field:\n\n```shell\nnet_response,result=success result_code=0i\n```\n\n### Histograms\n\nUse tags for each range with the `le` tag, and `+Inf` for the values out of\nrange.  This format is inspired by the Prometheus project:\n\n```shell\ncpu,le=0.0 usage_idle_bucket=0i 1486998330000000000\ncpu,le=50.0 usage_idle_bucket=2i 1486998330000000000\ncpu,le=100.0 usage_idle_bucket=2i 1486998330000000000\ncpu,le=+Inf usage_idle_bucket=2i 1486998330000000000\n```\n\n### Lists\n\nLists are tricky, but the general technique is to encode using a tag, creating\none series be item in the list.\n\n### Counters\n\nCounters retrieved from other projects often are in one of two styles,\nmonotonically increasing without reset and reset on each interval.  No attempt\nshould be made to switch between these two styles but if given the option it\nis preferred to use the non-resetting variant.  This style is more resilient in\nthe face of downtime and does not contain a fixed time element.\n\n### Source tag\n\nWhen metrics are gathered from another host, the metric schema should have a tag\nnamed \"source\" that contains the other host's name. See [this feature\nrequest](https://github.com/influxdata/telegraf/issues/4413) for details.\n\nThe metric schema doesn't need to have a tag for the host running\ntelegraf. Telegraf agent code can add a tag named \"host\" and by default\ncontaining the hostname reported by the kernel. This can be configured through\nthe \"hostname\" and \"omit_hostname\" agent settings.\n\n## Go Best Practices\n\nIn general code should follow best practice describe in [Code Review\nComments](https://github.com/golang/go/wiki/CodeReviewComments).\n\n### Networking\n\nAll network operations should have appropriate timeouts.  The ability to\ncancel the option, preferably using a context, is desirable but not always\nworth the implementation complexity.\n\n### Channels\n\nChannels should be used in judiciously as they often complicate the design and\ncan easily be used improperly.  Only use them when they are needed.\n"
  },
  {
    "path": "docs/developers/SAMPLE_CONFIG.md",
    "content": "# Sample Configuration\n\nThe sample config file is generated from a results of the `SampleConfig()`\nfunctions of the plugin.\n\nYou can generate a full sample config:\n\n```shell\ntelegraf config\n```\n\nYou can also generate the config for a particular plugin using the `-usage`\noption:\n\n```shell\ntelegraf --usage influxdb\n```\n\n## Style\n\nIn the config file we use 2-space indention.  Since the config is\n[TOML](https://github.com/toml-lang/toml) the indention has no meaning.\n\nDocumentation is double commented, full sentences, and ends with a period.\n\n```toml\n  ## This text describes what an the exchange_type option does.\n  # exchange_type = \"topic\"\n```\n\nTry to give every parameter a default value whenever possible.  If a\nparameter does not have a default or must frequently be changed then have it\nuncommented.\n\n```toml\n  ## Brokers are the AMQP brokers to connect to.\n  brokers = [\"amqp://localhost:5672\"]\n```\n\nOptions where the default value is usually sufficient are normally commented\nout.  The commented out value is the default.\n\n```toml\n  ## What an exchange type is.\n  # exchange_type = \"topic\"\n```\n\nIf you want to show an example of a possible setting filled out that is\ndifferent from the default, show both:\n\n```toml\n  ## Static routing key.  Used when no routing_tag is set or as a fallback\n  ## when the tag specified in routing tag is not found.\n  ##   example: routing_key = \"telegraf\"\n  # routing_key = \"\"\n```\n\nUnless parameters are closely related, add a space between them.  Usually\nparameters is closely related have a single description.\n\n```toml\n  ## If true, queue will be declared as an exclusive queue.\n  # queue_exclusive = false\n\n  ## If true, queue will be declared as an auto deleted queue.\n  # queue_auto_delete = false\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n```\n\nParameters should usually be describable in a few sentences.  If it takes\nmuch more than this, try to provide a shorter explanation and provide a more\ncomplex description in the Configuration section of the plugins\n[README](/plugins/inputs/example)\n\nBoolean parameters should be used judiciously.  You should try to think of\nsomething better since they don't scale well, things are often not truly\nboolean, and frequently end up with implicit dependencies: this option does\nsomething if this and this are also set.\n"
  },
  {
    "path": "docs/developers/STATE_PERSISTENCE.md",
    "content": "# State-persistence for plugins\n\n## Purpose\n\nPlugin state-persistence allows a plugin to save its state across restarts of\nTelegraf. This might be necessary if data-input (or output) is stateful and\ndepends on the result of a previous operation.\n\nIf you for example query data from a service providing a `next` token, your\nplugin would need to know the last token received in order to make the next\nquery. However, this token is lost after a restart of Telegraf if not persisted\nand thus your only chance is to restart the query chain potentially resulting\nin handling redundant data producing unnecessary traffic.\n\nThis is where state-persistence comes into play. The state-persistence framework\nallows your plugin to store a _state_ on shutdown and load that _state_ again\non startup of Telegraf.\n\n## State format\n\nThe _state_ of a plugin can be any structure or datatype that is serializable\nusing Golang's JSON serializer. It can be a key-value map or a more complex\nstructure. E.g.\n\n```go\ntype MyState struct {\n    CurrentToken string\n    LastToken    string\n    NextToken    string\n    FilterIDs    []int64\n}\n```\n\nwould represent a valid state.\n\n## Implementation\n\nTo enable state-persistence in your plugin you need to implement the\n`StatefulPlugin` interface defined in `plugin.go`. The interface looks as\nfollows:\n\n```go\ntype StatefulPlugin interface {\n    GetState() interface{}\n    SetState(state interface{}) error\n}\n```\n\nThe `GetState()` function should return the current state of the plugin\n(see [state format](#state-format)). Please note that this function should\n_always_ succeed and should always be callable directly after `Init()`. So make\nsure your relevant data-structures are initialized in `Init` to prevent panics.\n\nTelegraf will call the `GetState()` function on shutdown and will then compile\nan overall Telegraf state from the information of all stateful plugins. This\nstate is then persisted to disk if (and only if) the `statefile` option in the\n`agent` section is set. You do _not_ need take care of any serialization or\nwriting, Telegraf will handle this for you.\n\nWhen starting Telegraf, the overall persisted Telegraf state will be restored,\nif `statefile` is set. To do so, the `SetState()` function is called with the\ndeserialized state of the plugin. Please note that this function is called\ndirectly _after_ the `Init()` function of your plugin. You need to make sure\nthat the given state is what you expect using a type-assertion! Make sure this\nwon't panic but rather return a meaningful error.\n\nTo assign the state to the correct plugin, Telegraf relies on a plugin ID.\nSee the [\"State assignment\" section](#state-assignment) for more details on\nthe procedure and [\"Plugin Identifier\" section](#plugin-identifier) for more\ndetails on ID generation.\n\n## State assignment\n\nWhen restoring the state on loading, Telegraf needs to ensure that each plugin\n_instance_ gets the correct state. To do so, a plugin ID is used. By default\nthis ID is generated automatically for each plugin instance but can be\noverwritten if necessary (see [Plugin Identifier](#plugin-identifier)).\n\nState assignment needs to be able to handle multiple instances of the same\nplugin type correctly, e.g. if the user has configured multiple instances of\nyour plugin with different `server` settings. Here, the state saved for\n`foo.example.com` needs to be restored to the plugin instance handling\n`foo.example.com` on next startup of Telegraf and should _not_ end up at server\n`bar.example.com`. So the plugin identifier used for the assignment should be\nconsistent over restarts of Telegraf.\n\nIn case plugin instances are added to the configuration between restarts, no\nstate is restored _for those instances_. Furthermore, all states referencing\nplugin identifier that are no-longer valid are dropped and will be ignored. This\ncan happen in case plugin instances are removed or changed in ID.\n\n## Plugin Identifier\n\nAs outlined above, the plugin identifier (plugin ID) is crucial when assigning\nstates to plugin instances. By default, Telegraf will automatically generate an\nidentifier for each plugin configured when starting up. The ID is consistent\nover restarts of Telegraf and is based on the _entire configuration_ of the\nplugin. This means for each plugin instance, all settings in the configuration\nwill be concatenated and hashed to derive the ID. The resulting ID will then be\nused in both save and restore operations making sure the state ends up in a\nplugin with _exactly_ the same configuration that created the state.\n\nHowever, this also means that the plugin identifier _is changing_ whenever _any_\nof the configuration setting is changed! For example if your plugin is defined\nas\n\n```go\ntype MyPlugin struct {\n    Server  string          `toml:\"server\"`\n    Token   string          `toml:\"token\"`\n    Timeout config.Duration `toml:\"timeout\"`\n\n    offset int\n}\n```\n\nwith `offset` being your state, the plugin ID will change if a user changes the\n`timeout` setting in the configuration file. As a consequence the state cannot\nbe restored. This might be undesirable for your plugin, therefore you can\noverwrite the ID generation by implementing the `PluginWithID` interface (see\n`plugin.go`). This interface defines a `ID() string` function returning the\nidentifier o the current plugin _instance_. When implementing this function you\nshould take the following criteria into account:\n\n1. The identifier has to be _unique_ for your plugin _instance_ (not only for\n   the plugin type) to make sure the state is assigned to the correct instance.\n1. The identifier has to be _consistent_ across startups/restarts of Telegraf\n   as otherwise the state cannot be restored. Make sure the order of\n   configuration settings doesn't matter.\n1. Make sure to _include all settings relevant for state assignment_. In\n   the example above, the plugin's `token` setting might or might not be\n   relevant to identify the plugin instance.\n1. Make sure to _leave out all settings irrelevant for state assignment_. In\n   the example above, the plugin's `timeout` setting likely is not relevant\n   for the state and can be left out.\n\nWhich settings are relevant for the state are plugin specific. For example, if\nthe `offset` is a property of the _server_ the `token` setting is irrelevant.\nHowever, if the `offset` is specific for a certain user suddenly the `token`\nsetting is relevant.\n\nAlternatively to generating an identifier automatically, the plugin can allow\nthe user to specify that ID directly in a configuration setting. However, please\nnot that this might lead to colliding IDs in larger setups and should thus be\navoided.\n"
  },
  {
    "path": "docs/includes/plugin_config.md",
    "content": "Plugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n"
  },
  {
    "path": "docs/includes/secret_usage.md",
    "content": "Secrets defined by a store are referenced with `@{<store-id>:<secret_key>}`\nthe Telegraf configuration. Only certain Telegraf plugins and options of\nsupport secret stores. To see which plugins and options support\nsecrets, see their respective documentation (e.g.\n`plugins/outputs/influxdb/README.md`). If the plugin's README has the\n`Secret-store support` section, it will detail which options support secret\nstore usage.\n"
  },
  {
    "path": "docs/includes/service_input.md",
    "content": "This plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n"
  },
  {
    "path": "docs/includes/startup_error_behavior.md",
    "content": "In addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  Telegraf will try to startup the plugin in every gather or write\n            cycle in case of startup errors. The plugin is disabled until\n            the startup succeeds.\n- `probe`:  Telegraf will probe the plugin's function (if possible) and disables\n            the plugin in case probing fails. If the plugin does not support\n            probing, Telegraf will behave as if `ignore` was set instead.\n"
  },
  {
    "path": "docs/specs/README.md",
    "content": "# Telegraf Specification Overview\n\n## Objective\n\nDefine and layout the Telegraf specification process.\n\n## Overview\n\nThe general goal of a spec is to detail the work that needs to get accomplished\nfor a new feature. A developer should be able to pick up a spec and have a\ndecent understanding of the objective, the steps required, and most of the\ngeneral design decisions.\n\nThe specs can then live in the Telegraf repository to share and involve the\ncommunity in the process of planning larger changes or new features. The specs\nalso serve as a public historical record for changes.\n\n## Process\n\nThe general workflow is for a user to put up a PR with a spec outlining the\ntask, have any discussion in the PR, reach consensus, and ultimately commit\nthe finished spec to the repo.\n\nWhile researching a new feature may involve an investment of time, writing the\nspec should be relatively quick. It should not take hours of time.\n\n## Spec naming\n\nPlease name the actual file prefixed with `tsd` and the next available\nnumber, for example:\n\n* tsd-001-agent-write-ahead-log.md\n* tsd-002-inputs-apache-increase-timeout.md\n* tsd-003-serializers-parquet.md\n\nAll lower-case and separated by hyphens.\n\n## What belongs in a spec\n\nA spec should involve the creation of a markdown file with at least an objective\nand overview:\n\n* Objective (required) - One sentence headline\n* Overview (required) - Explain the reasoning for the new feature and any\n  historical information. Answer the why this is needed.\n\nPlease feel free to make a copy the template.md and start with that.\n\nThe user is free to add additional sections or parts in order to express and\nconvey a new feature. For example this might include:\n\n* Keywords - Help identify what the spec is about\n* Is/Is-not - Explicitly state what this change includes and does not include\n* Prior Art - Point at existing or previous PRs, issues, or other works that\n  demonstrate the feature or need for it.\n* Open Questions - Section with open questions that can get captured in\n  updates to the PR\n\n## Changing existing specs\n\nSmall changes which are non-substantive, like grammar or formatting are gladly\naccepted.\n\nAfter a feature is complete it may make sense to come back and update a spec\nbased on the final result.\n\nOther changes that make substantive changes are entirely up to the maintainers\nwhether the edits to an existing RFC will be accepted. In general, finished\nspecs should be considered complete and done, however, priorities, details, or\nother situations may evolve over time and as such introduce the need to make\nupdates.\n"
  },
  {
    "path": "docs/specs/template.md",
    "content": "# Title\n\n## Objective\n\nOne sentence explanation of the feature.\n\n## Overview\n\nBackground and details about the feature.\n\n## Keywords\n\nA few items to specify what areas of Telegraf this spec affects (e.g. outputs,\ninputs, processors, aggregators, agent, packaging, etc.)\n\n## Is/Is-not\n\n## Prior art\n\n## Open questions\n"
  },
  {
    "path": "docs/specs/tsd-001-deprecation.md",
    "content": "# Plugin and Plugin Option Deprecation\n\n## Objective\n\nSpecifies the process of deprecating and removing plugins, plugin settings\nincluding values of those settings or features.\n\n## Keywords\n\nprocedure, removal, all plugins\n\n## Overview\n\nOver time the number of plugins, plugin options and plugin features grow and\nsome of those plugins or options are either not relevant anymore, have been\nsuperseded or subsumed by other plugins or options. To be able to remove those,\nthis specification defines a process to deprecate plugins, plugin options and\nplugin features including a timeline and minimal time-frames. Additionally, the\nspecification defines a framework to annotate deprecations in the code and\ninform users about such deprecations.\n\n## User experience\n\nIn the deprecation phase a warning will be shown at Telegraf startup with the\nfollowing content\n\n```text\nPlugin \"inputs.logparser\" deprecated since version 1.15.0 and will be removed in 1.40.0: use 'inputs.tail' with 'grok' data format instead\n```\n\nSimilar warnings will be shown when removing plugin options or option values.\nThis provides users with time to replace the deprecated plugin in their\nconfiguration file.\n\nAfter the shown release (`v1.40.0` in this case) the warning will be promoted\nto an error preventing Telegraf from starting. The user now has to adapt the\nconfiguration file to start Telegraf.\n\n## Time frames and considerations\n\nWhen deprecating parts of Telegraf, it is important to provide users with enough\ntime to migrate to alternative solutions before actually removing those parts.\n\nIn general, plugins, plugin options or option values should only be deprecated\nif a suitable alternative exists! In those cases, the deprecations should\npredate the removal by at least one and a half years. In current release terms\nthis corresponds to six minor-versions. However, there might be circumstances\nrequiring a prolonged time between deprecation and removal to ensure a smooth\ntransition for users.\n\nVersions between deprecation and removal of plugins, plugin options or option\nvalues, Telegraf must log a *warning* on startup including information about\nthe version introducing the deprecation, the version of removal and an\nuser-facing hint on suitable replacements. In this phase Telegraf should\noperate normally even with deprecated plugins, plugin options or option values\nbeing set in the configuration files.\n\nStarting from the removal version, Telegraf must show an *error* message for\ndeprecated plugins present in the configuration including all information listed\nabove. Removed plugin options and option values should be handled as invalid\nsettings in the configuration files and must lead to an error. In this phase,\nTelegraf should *stop running* until all deprecated plugins, plugin options and\noption values are removed from the configuration files.\n\n## Deprecation Process\n\nThe deprecation process comprises the following the steps below.\n\n### File issue\n\nIn the filed issue you should outline which plugin, plugin option or feature\nyou want to deprecate and *why*! Determine in which version the plugin should\nbe removed.\n\nTry to reach an agreement in the issue before continuing and get a sign off\nfrom the maintainers!\n\n### Submit deprecation pull-request\n\nSend a pull request adding deprecation information to the code and update the\nplugin's `README.md` file. Depending on what you want to deprecate this\ncomprises different locations and steps as detailed below.\n\nOnce the deprecation pull-request is merged and Telegraf is released, we have\nto wait for the targeted Telegraf version for actually removing the code.\n\n#### Deprecating a plugin\n\nWhen deprecating a plugin you need to add an entry to the `deprecation.go` file\nin the respective plugin category with the following format\n\n```golang\n    \"<plugin name>\": {\n        Since:     \"<x.y.z format version of the next minor release>\",\n        RemovalIn: \"<x.y.z format version of the plugin removal>\",\n        Notice:    \"<user-facing hint e.g. on replacements>\",\n    },\n```\n\nIf you for example want to remove the `inputs.logparser` plugin you should add\n\n```golang\n    \"logparser\": {\n        Since:     \"1.15.0\",\n        RemovalIn: \"1.40.0\"\n        Notice:    \"use 'inputs.tail' with 'grok' data format instead\",\n    },\n```\n\nto `plugins/inputs/deprecations.go`. By doing this, Telegraf will show a\ndeprecation warning to the user starting from version `1.15.0` including the\n`Notice` you provided. The plugin can then be remove in version `1.40.0`.\n\nAdditionally, you should update the plugin's `README.md` adding a paragraph\nmentioning since when the plugin is deprecated, when it will be removed and a\nhint to alternatives or replacements. The paragraph should look like this\n\n```text\n**Deprecated in version v1.15.0 and scheduled for removal in v1.40.0**:\nPlease use the [tail][] plugin with the [`grok` data format][grok parser]\ninstead!\n```\n\n#### Deprecating an option\n\nTo deprecate a plugin option, remove the option from the `sample.conf` file and\nadd the deprecation information to the structure field in the code. If you for\nfor example want to deprecate the `ssl_enabled` option in `inputs.example` you\nshould add\n\n```golang\ntype Example struct {\n    ...\n    SSLEnabled bool `toml:\"ssl_enabled\" deprecated:\"1.3.0;1.40.0;use 'tls_*' options instead\"`\n}\n```\n\nto schedule the setting for removal in version `1.40.0`. The last element of\nthe `deprecated` tag is a user-facing notice similar to plugin deprecation.\n\n#### Deprecating an option-value\n\nSometimes, certain option values become deprecated or superseded by other\noptions or values. To deprecate those option values, remove them from\n`sample.conf` and add the deprecation info in the code if the deprecated value\nis *actually used* via\n\n```golang\nfunc (e *Example) Init() error {\n    ...\n    if e.Mode == \"old\" {\n        models.PrintOptionDeprecationNotice(telegraf.Warn, \"inputs.example\", \"mode\", telegraf.DeprecationInfo{\n            Since:     \"1.23.1\",\n            RemovalIn: \"1.40.0\",\n            Notice:    \"use 'v1' instead\",\n        })\n    }\n    ...\n    return nil\n}\n```\n\nThis will show a warning if the deprecated `v1` value is used for the `mode`\nsetting in `inputs.example` with a user-facing notice.\n\n### Submit pull-request for removing code\n\nOnce the plugin, plugin option or option-value is deprecated, we have to wait\nfor the `RemovedIn` release to remove the code. In the examples above, this\nwould be version `1.40.0`. After all scheduled bugfix-releases are done, with\n`1.40.0` being the next release, you can create a pull-request to actually\nremove the deprecated code.\n\nPlease make sure, you remove the plugin, plugin option or option value and the\ncode referencing those. This might also comprise the `all` files of your plugin\ncategory, test-cases including those of other plugins, README files or other\ndocumentation. For removed plugins, please keep the deprecation info in\n`deprecations.go` so users can find a reference when switching from a really\nold version.\n\nMake sure you add an `Important Changes` sections to the `CHANGELOG.md` file\ndescribing the removal with a reference to your PR.\n"
  },
  {
    "path": "docs/specs/tsd-002-custom-builder.md",
    "content": "# Telegraf Custom-Builder\n\n## Objective\n\nProvide a tool to build a customized, smaller version of Telegraf with only\nthe required plugins included.\n\n## Keywords\n\ntool, binary size, customization\n\n## Overview\n\nThe Telegraf binary continues to grow as new plugins and features are added\nand dependencies are updated. Users running on resource constrained systems\nsuch as embedded-systems or inside containers might suffer from the growth.\n\nThis document specifies a tool to build a smaller Telegraf binary tailored to\nthe plugins configured and actually used, removing unnecessary and unused\nplugins. The implementation should be able to cope with configured parsers and\nserializers including defaults for those plugin categories. Valid Telegraf\nconfiguration files, including directories containing such files, are the input\nto the customization process.\n\nThe customization tool might not be available for older versions of Telegraf.\nFurthermore, the degree of customization and thus the effective size reduction\nmight vary across versions. The tool must create a single static Telegraf\nbinary. Distribution packages or containers are *not* targeted.\n\n## Prior art\n\n[PR #5809](https://github.com/influxdata/telegraf/pull/5809) and\n[telegraf-lite-builder](https://github.com/influxdata/telegraf/tree/telegraf-lite-builder/cmd/telegraf-lite-builder):\n\n- Uses docker\n- Uses browser:\n  - Generates a webpage to pick what options you want. User chooses plugins;\n    does not take a config file\n  - Build a binary, then minifies by stripping and compressing that binary\n- Does some steps that belong in makefile, not builder\n  - Special case for upx\n  - Makes gzip, zip, tar.gz\n- Uses gopkg.in?\n- Can also work from the command line\n\n[PR #8519](https://github.com/influxdata/telegraf/pull/8519)\n\n- User chooses plugins OR provides a config file\n\n[powers/telegraf-build](https://github.com/powersj/telegraf-build)\n\n- User chooses plugins OR provides a config file\n- Currently kept in separate repo\n- Undoes changes to all.go files\n\n[rawkode/bring-your-own-telegraf](https://github.com/rawkode/bring-your-own-telegraf)\n\n- Uses docker\n\n## Additional information\n\nYou might be able to further reduce the binary size of Telegraf by removing\ndebugging information. This is done by adding `-w` and `-s` to the linker flags\nbefore building `LDFLAGS=\"-w -s\"`.\n\nHowever, please note that this removes information helpful for debugging issues\nin Telegraf.\n\nAdditionally, you can use a binary packer such as [UPX](https://upx.github.io/)\nto reduce the required *disk* space. This compresses the binary and decompresses\nit again at runtime. However, this does not reduce memory footprint at runtime.\n"
  },
  {
    "path": "docs/specs/tsd-003-state-persistence.md",
    "content": "# Plugin State-Persistence\n\n## Objective\n\nRetain the state of stateful plugins across restarts of Telegraf.\n\n## Keywords\n\nframework, plugin, stateful, persistence\n\n## Overview\n\nTelegraf contains a number of plugins that hold an internal state while\nprocessing. For some of the plugins this state is important for efficient\nprocessing like the location when reading a large file or when continuously\nquerying data from a stateful peer requiring for example an offset or the last\nqueried timestamp. For those plugins it is important to persistent their\ninternal state over restarts of Telegraf.\n\nIt is intended to\n\n- allow for opt-in of plugins to store a state per plugin _instance_\n- restore the state for each plugin instances at startup\n- track the plugin instances over restarts to relate the stored state with a\n  corresponding plugin instance\n- automatically compute plugin instance IDs based on the plugin configuration\n- provide a way to manually specify instance IDs by the user\n- _not_ restore states if the plugin configuration changed between runs\n- make implementation easy for plugin developers\n- make no assumption on the state _content_\n\nThe persistence will use the following steps:\n\n- Compute an unique ID for each of the plugin _instances_\n- Startup Telegraf plugins calling `Init()`, etc.\n- Initialize persistence framework with the user specified `statefile` location\n  and load the state if present\n- Determine all stateful plugin instances by fulfilling the `StatefulPlugin`\n  interface\n- Restore plugin states (if any) for each plugin ID present in the state-file\n- Run data-collection etc...\n- On shutdown, stopping all Telegraf plugins calling `Stop()` or `Close()`\n  depending on the plugin type\n- Query the state of all registered stateful plugins state\n- Create an overall state-map with the plugin instance ID as a key and the\n  serialized plugin state as value.\n- Marshal the overall state-map and store to disk\n\nPotential users of this functionality are plugins continuously querying\nendpoints with information of a previous query (e.g. timestamps, offsets,\ntransaction tokens, etc.) The following plugins are known to have an internal\nstate. This is not a comprehensive list.\n\n- `inputs.win_eventlog` ([PR #8281](https://github.com/influxdata/telegraf/pull/8281))\n- `inputs.docker_log` ([PR #7749](https://github.com/influxdata/telegraf/pull/7749))\n- `inputs.tail` (file offset)\n- `inputs.cloudwatch` (`windowStart`/`windowEnd` parameters)\n- `inputs.stackdriver` (`prevEnd` parameter)\n\n### Plugin ID computation\n\nThe plugin ID is computed based on the configuration options specified for the\nplugin instance. To generate the ID all settings are extracted as `string`\nkey-value pairs with the option name being the key and the value being the\nconfiguration option setting. For nested configuration options, e.g. if the\nplugins has a sub-table, the options are flattened with a canonical key. The\ncanonical key elements must be concatenated with a dot (`.`) separator. In case\nthe sub-element is a list of tables, the key must include the index of each\ntable prefixed by a hash sign i.e. `<parent>#<index>.<child>`.\n\nThe resulting key-value pairs of configuration options are then sorted by the\nkey in lexical order to make the resulting ID invariant against changes in the\norder of configuration options. The key and the value of each pair are joined\nby a colon (`:`) to a single `string`.\n\nFinally, a SHA256 sum is computed across all key-value strings separated by a\n`null` byte. The HEX representation of the resulting SHA256 is used as the\nplugin instance ID.\n\n### State serialization format\n\nThe overall Telegraf state maps the plugin IDs (keys) to the serialized state\nof the corresponding plugin (values). The state data returned by stateful\nplugins is serialized to JSON. The resulting byte-sequence is used as the value\nfor the overall state. On-disk, the overall state of Telegraf is stored as JSON.\n\nTo restore the state of a plugin, the overall Telegraf state is first\ndeserialized from the on-disk JSON data and a lookup for the plugin ID is\nperformed in the resulting map. The value, if found, is then deserialized to the\nplugin's state data-structure and provided to the plugin after calling `Init()`.\n\n## Is / Is-not\n\n### Is\n\n- A framework to persist states over restarts of Telegraf\n- A simple local state store\n- A way to restore plugin states between restarts without configuration changes\n- A unified API for plugins to use when requiring persistence of a state\n\n### Is-Not\n\n- A remote storage framework\n- A way to store anything beyond fundamental plugin states\n- A data-store or database\n- A way to reassign plugin states if their configuration changes\n- A tool to interactively adding/removing/modifying states of plugins\n- A persistence guarantee beyond clean shutdown (i.e. no crash resistance)\n\n## Prior art\n\n- [PR #8281](https://github.com/influxdata/telegraf/pull/8281): Stores Windows\n  event-log bookmarks in the registry\n- [PR #7749](https://github.com/influxdata/telegraf/pull/7749): Stores container\n  ID and log offset to a file at a user-provided path\n- [PR #7537](https://github.com/influxdata/telegraf/pull/7537): Provides a\n  global state object and periodically queries plugin states to store the state\n  object to a JSON file. This approach does not provide a ID per plugin\n  _instance_ so it seems like there is only a single state for a plugin _type_\n- [PR #9476](https://github.com/influxdata/telegraf/pull/9476): Register\n  stateful plugins to persister and automatically assigns an ID to plugin\n  _instances_ based on the configuration. The approach also allows to overwrite\n  the automatic ID e.g. with user specified data. It uses the plugin instance ID\n  to store/restore state to the same plugin instance and queries the plugin\n  state on shutdown and write file (currently JSON).\n"
  },
  {
    "path": "docs/specs/tsd-004-configuration-migration.md",
    "content": "# Configuration Migration\n\n## Objective\n\nProvides a subcommand and framework to migrate configurations containing\ndeprecated settings to a corresponding recent configuration.\n\n## Keywords\n\nconfiguration, deprecation, telegraf command\n\n## Overview\n\nWith the deprecation framework of [TSD-001](tsd-001-deprecation.md) implemented\nwe see more and more plugins and options being scheduled for removal in the\nfuture. Furthermore, deprecations become visible to the user due to the warnings\nissued for removed plugins, plugin options and plugin option values.\n\nTo aid the user in mitigating deprecated configuration settings this\nspecifications proposes the implementation of a `migrate` sub-command to the\nTelegraf `config` command for automatically migrate the user's existing\nconfiguration files away from the deprecated settings to an equivalent, recent\nconfiguration. Furthermore, the specification describes the layout and\nfunctionality of a plugin-based migration framework to implement migrations.\n\n### `migrate` sub-command\n\nThe `migrate` sub-command of the `config` command should take a set of\nconfiguration files and configuration directories and apply available migrations\nto deprecated plugins, plugin options or plugin option-values in order to\ngenerate new configuration files that do not make use of deprecated options.\n\nIn the process, the migration procedure must ensure that only plugins with\napplicable migrations are modified. Existing configuration must be kept and not\nbe overwritten without manual confirmation of the user. This should be\naccomplished by storing modified configuration files with a `.migrated` suffix\nand leaving it to the user to overwrite the existing configuration with the\ngenerated counterparts. If no migration is applied in a configuration file, the\ncommand might not generate a new file and leave the original file untouched.\n\nDuring migration, the configuration, plugin behavior, resulting metrics and\ncomments should be kept on a best-effort basis. Telegraf must inform the user\nabout applied migrations and potential changes in the plugin behavior or\nresulting metrics. If a plugin cannot be automatically migrated but requires\nmanual intervention, Telegraf should inform the user.\n\n### Migration implementations\n\nTo implement migrations for deprecated plugins, plugin option or plugin option\nvalues, Telegraf must provide a plugin-based infrastructure to register and\napply implemented migrations based on the plugin-type. Only one migration per\nplugin-type must be registered.\n\nDevelopers must implement the required interfaces and register the migration\nto the mentioned framework. The developer must provide the possibility to\nexclude the migration at build-time according to\n[TSD-002](tsd-002-custom-builder.md). Existing migrations can be extended but\nmust be cumulative such that any previous configuration migration functionality\nis kept.\n\nResulting configurations should generate metrics equivalent to the previous\nsetup also making use of metric selection, renaming and filtering mechanisms.\nIn cases this is not possible, there must be a clear information to the user\nwhat to expect and which differences might occur.\nA migration can only be informative, i.e. notify the user that a plugin has to\nmanually be migrated and should point users to additional information.\n\nDeprecated plugins and plugin options must be removed from the migrated\nconfiguration.\n"
  },
  {
    "path": "docs/specs/tsd-005-output-buffer-strategy.md",
    "content": "# Telegraf Output Buffer Strategy\n\n## Objective\n\nIntroduce a new agent-level config option to choose a disk buffer strategy for\noutput plugin metric queues.\n\n## Overview\n\nCurrently, when a Telegraf output metric queue fills, either due to incoming\nmetrics being too fast or various issues with writing to the output, oldest\nmetrics are overwritten and never written to the output. This specification\ndefines a set of options to make this output queue more durable by persisting\npending metrics to disk rather than only an in-memory limited size queue.\n\n## Keywords\n\noutput plugins, agent configuration, persist to disk\n\n## Agent Configuration\n\nThe configuration is at the agent-level, with options for:\n\n- **Memory**, the current implementation, with no persistence to disk\n- **Disk-write-through**, all metrics are also written to disk using a\n  Write Ahead Log (WAL) file\n- **Disk-overflow**, when the memory buffer fills, metrics are flushed to a\n  WAL file to avoid dropping overflow metrics\n\nAs well as an option to specify a directory to store the WAL files on disk,\nwith a default value. These configurations are global, and no change means\nmemory only mode, retaining current behavior.\n\n## Metric Ordering and Tracking\n\nTracking metrics will be accepted on a successful write to the output\ndestination. Metrics will be written to their appropriate output in the order\nthey are received in the buffer regardless of which buffer strategy is chosen.\n\n## Disk Utilization and File Handling\n\nEach output plugin has its own in-memory output buffer, and therefore will\neach have their own WAL file for buffer persistence. This file may not exist\nif Telegraf is successfully able to write all of its metrics without filling\nthe in-memory buffer in disk-overflow mode, or not at all in memory mode.\nTelegraf should use one file per output plugin, and remove entries from the\nWAL file as they are written to the output.\n\nTelegraf will not make any attempt to limit the size on disk taken by these\nfiles beyond cleaning up WAL files for metrics that have successfully been\nflushed to their output destination. It is the user's responsibility to ensure\nthese files do not entirely fill the disk, both during Telegraf uptime and\nwith lingering files from previous instances of the program.\n\nIf WAL files exist for an output plugin from previous instances of Telegraf,\nthey will be picked up and flushed before any new metrics that are written\nto the output. This is to ensure that these metrics are not lost, and to\nensure that output write order remains consistent.\n\nTelegraf must additionally provide a way to manually flush WAL files via\nsome separate plugin or similar. This could be used as a way to ensure that\nWAL files are properly written in the event that the output plugin changes\nand the WAL file is unable to be detected by a new instance of Telegraf.\nThis plugin should not be required for use to allow the buffer strategy to\nwork.\n\n## Is/Is-not\n\n- Is a way to prevent metrics from being dropped due to a full memory buffer\n- Is not a way to guarantee data safety in the event of a crash or system failure\n- Is not a way to manage file system allocation size, file space will be used\n  until the disk is full\n\n## Prior art\n\n[Initial issue](https://github.com/influxdata/telegraf/issues/802)\n[Loose specification issue](https://github.com/influxdata/telegraf/issues/14805)\n"
  },
  {
    "path": "docs/specs/tsd-006-startup-error-behavior.md",
    "content": "# Startup Error Behavior\n\n## Objective\n\nUnified, configurable behavior on retriable startup errors.\n\n## Keywords\n\ninputs, outputs, startup, error, retry\n\n## Overview\n\nMany Telegraf plugins connect to an external service either on the same machine\nor via network. On automated startup of Telegraf (e.g. via service) there is no\nguarantee that those services are fully started yet, especially when they reside\non a remote host. More and more plugins implement mechanisms to retry reaching\ntheir related service if they failed to do so on startup.\n\nThis specification intends to unify the naming of configuration-options, the\nvalues of those options, and their semantic meaning. It describes the behavior\nfor the different options on handling startup-errors.\n\nStartup errors are all errors occurring in calls to `Start()` for inputs and\nservice-inputs or `Connect()` for outputs. The behaviors described below\nshould only be applied in cases where the plugin *explicitly* states that an\nstartup error is *retriable*. This includes for example network errors\nindicating that the host or service is not yet reachable or external\nresources, like a machine or file, which are not yet available, but might become\navailable later. To indicate a retriable startup error the plugin should return\na predefined error-type.\n\nIn cases where the error cannot be generally determined be retriable by\nthe plugin, the plugin might add configuration settings to let the user\nconfigure that property. For example, where an error code indicates a fatal,\nnon-recoverable error in one case but a non-fatal, recoverable error in another\ncase.\n\n## Configuration Options and Behaviors\n\nTelegraf must introduce a unified `startup_error_behavior` configuration option\nfor inputs and output plugins. The option is handled directly by the Telegraf\nagent and is not passed down to the plugins. The setting must be available on a\nper-plugin basis and defines how Telegraf behaves on startup errors.\n\nFor all config option values Telegraf might retry to start the plugin for a\nlimited number of times during the startup phase before actually processing\ndata. This corresponds to the current behavior of Telegraf to retry three times\nwith a fifteen second interval before continuing processing of the plugins.\n\n### `error` behavior\n\nThe `error` setting for the `startup_error_behavior` option causes Telegraf to\nfail and exit on startup errors. This must be the default behavior.\n\n### `retry` behavior\n\nThe `retry` setting for the `startup_error_behavior` option Telegraf must *not*\nfail on startup errors and should continue running. Telegraf must retry to\nstartup the failed plugin in each gather or write cycle, for inputs or for\noutputs respectively, for an unlimited number of times. Neither the\nplugin's `Gather()` nor `Write()` method is called as long as the startup did\nnot succeed. Metrics sent to an output plugin will be buffered until the plugin\nis actually started. If the metric-buffer limit is reached **metrics might be\ndropped**!\n\nIn case a plugin signals a partially successful startup, e.g. a subset of the\ngiven endpoints are reachable, Telegraf must try to fully startup the remaining\nendpoints by calling `Start()` or `Connect()`, respectively, until full startup\nis reached **and** trigger the plugin's `Gather()` nor `Write()` methods.\n\n### `ignore` behavior\n\nWhen using the `ignore` setting for the `startup_error_behavior` option Telegraf\nmust *not* fail on startup errors and should continue running. On startup error,\nTelegraf must ignore the plugin as-if it was not configured at all, i.e. the\nplugin must be completely removed from processing.\n\n### `probe` behavior\n\nWhen using the `probe` setting for the `startup_error_behavior` option Telegraf\nmust *not* fail on startup errors and should continue running. On startup error,\nTelegraf must ignore the plugin as-if it was not configured at all, i.e. the\nplugin must be completely removed from processing, similar to the `ignore`\nbehavior. Additionally, Telegraf must probe the plugin (as defined in\n[TSD-009][tsd_009]) after startup, if it implements the `ProbePlugin` interface.\nIf probing is available *and* returns an error Telegraf must *ignore* the\nplugin as-if it was not configured at all.\n\n[tsd_009]: /docs/specs/tsd-009-probe-on-startup.md\n\n## Plugin Requirements\n\nPlugins participating in handling startup errors must implement the `Start()`\nor `Connect()` method for inputs and outputs respectively. Those methods must be\nsafe to be called multiple times during retries without leaking resources or\ncausing issues in the service used.\n\nFurthermore, the `Close()` method of the plugins must be safe to be called for\ncases where the startup failed without causing panics.\n\nThe plugins should return a `nil` error during startup to indicate a successful\nstartup or a retriable error (via predefined error type) to enable the defined\nstartup error behaviors. A non-retriable error (via predefined error type) or\na generic error will bypass the startup error behaviors and Telegraf must fail\nand exit in the startup phase.\n\n## Related Issues\n\n- [#8586](https://github.com/influxdata/telegraf/issues/8586) `inputs.postgresql`\n- [#9778](https://github.com/influxdata/telegraf/issues/9778) `outputs.kafka`\n- [#13278](https://github.com/influxdata/telegraf/issues/13278) `outputs.cratedb`\n- [#13746](https://github.com/influxdata/telegraf/issues/13746) `inputs.amqp_consumer`\n- [#14365](https://github.com/influxdata/telegraf/issues/14365) `outputs.postgresql`\n- [#14603](https://github.com/influxdata/telegraf/issues/14603) `inputs.nvidia-smi`\n- [#14603](https://github.com/influxdata/telegraf/issues/14603) `inputs.rocm-smi`\n"
  },
  {
    "path": "docs/specs/tsd-007-url-config-behavior.md",
    "content": "# URL-Based Config Behavior\n\n## Objective\n\nDefine the retry and reload behavior of remote URLs that are passed as config to\nTelegraf. In terms of retry, currently Telegraf will attempt to load a remote\nURL three times and then exit. In terms of reload, Telegraf does not have the\ncapability to reload remote URL based configs. This spec seeks to allow for\noptions for the user to further these capabilities.\n\n## Keywords\n\nconfig, error, retry, reload\n\n## Overview\n\nTelegraf allows for loading configurations from local files, directories, and\nfiles via a URL. In order to allow situations where a configuration file is not\nyet available or due to a flaky network, the first proposal is to introduce a\nnew CLI flag: `--url-config-retry-attempts`. This flag would continue to default\nto three and would specify the number of retries to attempt to get a remote URL\nduring the initial startup of Telegraf.\n\n```sh\n--config-url-retry-attempts=3   Number of times to attempt to obtain a remote\n                                configuration via a URL during startup. Set to\n                                -1 for unlimited attempts.\n```\n\nThese attempts would block Telegraf from starting up completely until success or\nuntil we have run out of attempts and exit.\n\nOnce Telegraf is up and running, users can use the `--watch` flag to enable\nwatching local files for changes and if/when changes are made, then reload\nTelegraf with the new configuration. For remote URLs, I propose a new CLI flag:\n`--url-config-check-interval`. This flag would set an internal timer that when\nit goes off, would check for an update to a remote URL file.\n\n```sh\n--config-url-watch-interval=0s  Time duration to check for updates to URL based\n                                configuration files. Disabled by default.\n```\n\nAt each interval, Telegraf would send an HTTP HEAD request to the configuration\nURL, here is an example curl HEAD request and output:\n\n```sh\n$ curl --head http://localhost:8000/config.toml\nHTTP/1.0 200 OK\nServer: SimpleHTTP/0.6 Python/3.12.3\nDate: Mon, 29 Apr 2024 18:18:56 GMT\nContent-type: application/octet-stream\nContent-Length: 1336\nLast-Modified: Mon, 29 Apr 2024 11:44:19 GMT\n```\n\nThe proposal then is to store the last-modified value when we first obtain the\nfile and compare the value at each interval. No need to parse the value, just\nstore the raw string. If there is a difference, trigger a reload.\n\nIf anything other than 2xx response code is returned from the HEAD request,\nTelegraf would print a warning message and retry at the next interval. Telegraf\nwill continue to run the existing configuration with no change.\n\nIf the value of last-modified is empty, while very unlikely, then Telegraf would\nignore this configuration file. Telegraf will print a warning message once about\nthe missing field.\n\n## Relevant Issues\n\n* Configuration capabilities to retry for loading config via URL #[8854][]\n* Telegraf reloads URL-based/remote config on a specified interval #[8730][]\n\n[8854]: https://github.com/influxdata/telegraf/issues/8854\n[8730]: https://github.com/influxdata/telegraf/issues/8730\n"
  },
  {
    "path": "docs/specs/tsd-008-partial-write-error-handling.md",
    "content": "# Partial write error handling\n\n## Objective\n\nProvide a way to pass information about partial metric write errors from an\noutput to the output model.\n\n## Keywords\n\noutput plugins, write, error, output model, metric, buffer\n\n## Overview\n\nThe output model wrapping each output plugin buffers metrics to be able to batch\nthose metrics for more efficient sending. In each flush cycle, the model\ncollects a batch of metrics and hands it over to the output plugin for writing\nthrough the `Write` method. Currently, if writing succeeds (i.e. no error is\nreturned), _all metrics of the batch_ are removed from the buffer and are marked\nas __accepted__ both in terms of statistics as well as in tracking-metric terms.\nIf writing fails (i.e. any error is returned), _all metrics of the batch_ are\n__kept__ in the buffer for requeueing them in the next write cycle.\n\nIssues arise when an output plugin cannot write all metrics of a batch bit only\nsome to its service endpoint, e.g. due to the metrics being serializable or if\nmetrics are selectively rejected by the service on the server side. This might\nhappen when reaching submission limits, violating service constraints e.g.\nby out-of-order sends, or due to invalid characters in the serialited metric.\nIn those cases, an output currently is only able to accept or reject the\n_complete batch of metrics_ as there is no mechanism to inform the model (and\nin turn the buffer) that only _some_ of the metrics in the batch were failing.\n\nAs a consequence, outputs often _accept_ the batch to avoid a requeueing of the\nfailing metrics for the next flush interval. This distorts statistics of\naccepted metrics and causes misleading log messages saying all metrics were\nwritten sucessfully which is not true. Even worse, for outputs ending-up with\npartial writes, e.g. only the first half of the metrics can be written to the\nservice, there is no way of telling the model to selectively accept the actually\nwritten metrics and in turn those outputs must internally buffer the remaining,\nunwritten metrics leading to a duplication of buffering logic and adding to code\ncomplexity.\n\nThis specification aims at defining the handling of partially successful writes\nand introduces the concept of a special _partial write error_ type to reflect\npartial writes and partial serialization overcoming the aforementioned issues\nand limitations.\n\nTo do so, the _partial write error_ error type must contain a list of\nsuccessfully written metrics, to be marked __accepted__, both in terms of\nstatistics as well as in terms of metric tracking, and must be removed from the\nbuffer. Furthermore, the error must contain a list of metrics that cannot be\nsent or serialized and cannot be retried. These metrics must be marked as\n__rejected__, both in terms of statistics as well as in terms of metric\ntracking,  and must be removed from the buffer.\n\nThe error may contain a list of metrics not-yet written to be __kept__ for the\nnext write cylce. Those metrics must not be marked and must be kept in the\nbuffer. If the error does not contain the list of not-yet written metrics, this\nlist must be inferred using the accept and reject lists mentioned above.\n\nTo allow the model and the buffer to correctly handle tracking metrics ending up\nin the buffer and output the tracking information must be preserved during\ncommunication between the output plugin, the model and the buffer through the\nspecified error. To do so, all metric lists should be communicated as indices\ninto the batch to be able to handle tracking metrics correctly.\n\nFor backward compatibility and simplicity output plugins can return a `nil`\nerror to indicate that __all__ metrics of the batch are __accepted__. Similarly,\nreturing an error _not_ being a _partial write error_ indicates that __all__\nmetrics of the batch should be __kept__ in the buffer for the next write cycle.\n\n## Related Issues\n\n- [issue #11942](https://github.com/influxdata/telegraf/issues/11942) for\n  contradicting log messages\n- [issue #14802](https://github.com/influxdata/telegraf/issues/14802) for\n  rate-limiting multiple batch sends\n- [issue #15908](https://github.com/influxdata/telegraf/issues/15908) for\n  infinite loop if single metrics cannot be written\n"
  },
  {
    "path": "docs/specs/tsd-009-probe-on-startup.md",
    "content": "# Probing plugins after startup\n\n## Objective\n\nAllow Telegraf to probe plugins during startup to enable enhanced plugin error\ndetection like availability of hardware or services\n\n## Keywords\n\ninputs, outputs, startup, probe, error, ignore, behavior\n\n## Overview\n\nWhen plugins are first instantiated, Telegraf will call the plugin's `Start()`\nmethod (for inputs) or `Connect()` (for outputs) which will initialize its\nconfiguration based off of config options and the running environment. It is\nsometimes the case that while the initialization step succeeds, the upstream\nservice in which the plugin relies on is not actually running, or is not capable\nof being communicated with due to incorrect configuration or environmental\nproblems. In situations like this, Telegraf does not detect that the plugin's\nupstream service is not functioning properly, and thus it will continually call\nthe plugin during each `Gather()` iteration. This often has the effect of\npolluting journald and system logs with voluminous error messages, which creates\nissues for system administrators who rely on such logs to identify other\nunrelated system problems.\n\nMore background discussion on this option, including other possible avenues, can\nbe viewed in the [related issue][issue_16028].\n\n[issue_16028]: https://github.com/influxdata/telegraf/issues/16028\n\n## Probing\n\nProbing is an action whereby the plugin should ensure that the plugin will be\nfully functional on a best effort basis. This may comprise communicating with\nits external service, trying to access required devices, entities or executables\netc to ensure that the plugin will not produce errors during e.g. data\ncollection or data output. Probing must *not* produce, process or output any\nmetrics.\n\nPlugins that support probing must implement the `ProbePlugin` interface. Such\nplugins must behave in the following manner:\n\n1. Return an error if the external dependencies (hardware, services,\nexecutables, etc.) of the plugin are not available.\n2. Return an error if information cannot be gathered (in the case of inputs) or\nsent (in the case of outputs) due to unrecoverable issues. For example, invalid\nauthentication, missing permissions, or non-existent endpoints.\n3. Otherwise, return `nil` indicating the plugin will be fully functional.\n\n## Plugin Requirements\n\nPlugins that allow probing must implement the `ProbePlugin` interface. The\nexact implementation depends on the plugin's functionality and requirements,\nbut generally it should take the same actions as it would during normal\noperation e.g. calling `Gather()` or `Write()` and check if errors occur. If\nprobing fails, it must be safe to call the plugin's `Close()` method.\n\nInput plugins must *not* produce metrics, output plugins must *not* send any\nmetrics to the service. Plugins must *not* influence the later data processing\nor collection by modifying the internal state of the plugin or the external\nstate of the service or hardware. For example, file-offsets or other service\nstates must be reset to not lose data during the first gather or write cycle.\n\nPlugins must return `nil` upon successful probing or an error otherwise.\n\n## Related Issues\n\n- [#16028](https://github.com/influxdata/telegraf/issues/16028)\n- [#15916](https://github.com/influxdata/telegraf/pull/15916)\n- [#16001](https://github.com/influxdata/telegraf/pull/16001)\n"
  },
  {
    "path": "docs/specs/tsd-010-labels-and-selectors.md",
    "content": "# Labels and Selectors for Plugin Enablement\n\n## Objective\n\nIntroduce a label and selector system to enable or disable plugins dynamically\nin Telegraf.\n\n## Keywords\n\nconfiguration, dynamic plugin selection\n\n## Overview\n\nCurrently, managing plugin configurations across multiple Telegraf instances is\ncumbersome. Methods like commenting out plugins or renaming configuration files\nare not scalable. A label and selector system provides a more flexible and\nelegant solution.\n\nThis feature aims to simplify plugin management in Telegraf by introducing a\nlabel and selector system inspired by [Kubernetes][k8s_labels]. Selectors are\nkey-value pairs provided at runtime, and labels are defined in plugin\nconfigurations to match against these selectors. This approach allows to enable\na plugin dynamically at startup-time, making it easier to manage configurations\nin large-scale deployments where a single configuration is fetched from a\ncentralized configuration-source.\n\n[k8s_labels]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n\n## Command line flags\n\nThe Telegraf executable must accept one or more optional `--select` command-line\nflags. The passed value must be of the form:\n\n```text\n<key>=<value>[;<key>=<value>]\n```\n\nThe `key` part must be non-empty and must not contain any wildcard characters\nbut only contain alpha-numerical values (`[A-Za-z0-9]`), dots (`.`), dashes\n(`-`) or underscores (`_`).\n\nThe `value` part must be non-empty and might contain the wildcard characters\nasterix (`*`) for matching any number of characters or question mark (`?`) for\nmatching a single character. Furthermore, the value may contain alpha-numerical\nvalues (`[A-Za-z0-9]`), dots (`.`), dashes (`-`) or underscores (`_`).\n\nThe `key` and `value` parts of a selector are separated by an equal sign (`=`).\nMultiple key-value pairs in a single selector are separated by semicolons.\n\nFor example, users can start the telegraf instance with the following command\nline:\n\n```console\ntelegraf --config config.conf --config-directory directory/ --select=\"app=payments;region=us-*\" --select=\"env=prod\" --watch-config --print-plugin-config-source=true\n```\n\nSpecifying the same `key` multiple times within a single `--select` statement\ncauses an error at Telegraf startup.\nHowever, the same `key` can be used in _different_ `--select` statements.\n\n## Plugin Labels\n\nTelegraf must implement a new optional `labels` configuration setting. This\nsetting must be available in all input, output, aggregator and processor\nplugins. The `labels` configuration setting must accept a map where each entry\nis a single key-value pair.\n\nThe `key` part must be non-empty and must not contain any wildcard characters\nbut only alpha-numerical values (`[A-Za-z0-9]`), dots (`.`), dashes (`-`) or\nunderscores (`_`).\n\nThe `value` part must be non-empty and must not contain any wildcard characters\nbut only alpha-numerical values (`[A-Za-z0-9]`), dots (`.`), dashes (`-`) or\nunderscores (`_`).\n\n```toml\n[[inputs.cpu]]\n  [inputs.cpu.labels]\n    app = \"payments\"\n    region = \"us-east\"\n    env = \"prod\"\n```\n\nTelegraf must provide the setting without changes to existing or new plugins.\n\n> [!NOTE]\n> Due to limitations in the TOML format, maps must be defined _after_ top-level\n> plugin-settings e.g. at the end of the plugin configuration!\n\n## Selection matching\n\nTelegraf must match command-line selectors against the plugin labels to\ndetermine if a plugin should be enabled. The matching behavior is as follows:\n\nMultiple `--select` command-line parameters are treated as a logical **OR**\ncondition. If any select statement matches, the plugin will be enabled.\nWithin each `--select` command-line parameter, multiple key-value pairs,\nseparated by a semicolon, are treated as a logical **AND** condition. All\nconditions within that select statement must match for a plugin to be selected.\n\nSelectors support exact matching as well as wildcard matching\nusing `*` (multiple characters) and `?` (single character) in the selector\nvalues. The key part does not support wildcards.\n\n### Behavior Matrix\n\n| **Telegraf Run State** | **Label Present** | **Behavior**                                                                         |\n| ---------------------- | ----------------- | ------------------------------------------------------------------------------------ |\n| With `--select`        | Yes               | Plugin is selected if the selector matches the label. Otherwise, it is not selected. |\n| With `--select`        | No                | Plugin is selected (backward compatibility).                                         |\n| Without `--select`     | Yes               | Plugin is selected (no selector to compare against).                                 |\n| Without `--select`     | No                | Plugin is selected (current behavior).                                               |\n\n### Matching Examples\n\n| CLI Selectors (`--select`)                           | Plugin Labels                             | Matching Behavior                                                                                                        | Result   |\n| ---------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- |\n| `app=web`                                            | `app=\"web\"`                               | Selector requires `app=web`; plugin label has `app=web`, so it matches                                                   | Selected |\n| `app=web`                                            | `app=\"api\"`                               | Selector requires `app=web`, but plugin has `app=api`; no match                                                          | Skipped  |\n| `app=web`                                            | `app=\"web\", region=\"us-east\"`             | Selector only cares about `app=web`, which is present; extra labels are ignored                                          | Selected |\n| `app=web,region=us-east`                             | `app=\"web\", region=\"us-east\"`             | Selector requires both `app=web` and `region=us-east`; both are present                                                  | Selected |\n| `app=web,region=us-west`                             | `app=\"web\", region=\"us-east\"`             | Selector requires `region=us-west`, but plugin has `region=us-east`; mismatch                                            | Skipped  |\n| `env=prod*`                                          | `env=\"production\"`                        | Selector wants `env` starting with `prod`; `production` matches the wildcard                                             | Selected |\n| `env=prod*`                                          | `env=\"staging\"`                           | Selector wants `env` starting with `prod`, but `staging` doesn't match                                                   | Skipped  |\n| `env=*`                                              | `env=\"qa\"`                                | Wildcard `*` matches any value of `env`; `qa` satisfies it                                                               | Selected |\n| `app=web,env=prod`, `region=eu-*`                    | `app=\"web\", env=\"prod\"`                   | First selector requires `app=web` AND `env=prod`; both are present, second selector is ignored                           | Selected |\n| `app=web,env=prod`, `region=eu-*`                    | `app=\"web\", env=\"staging\", region=\"us\"`   | First selector fails due to `env=staging`; second selector fails due to `region=us`; no match                            | Skipped  |\n| `env=prod`, `env=staging`                            | `env=\"prod\"`                              | At least one selector (`env=prod`) matches label exactly                                                                 | Selected |\n| `env=prod`, `env=staging`                            | `env=\"qa\"`                                | Neither `env=prod` nor `env=staging` match `env=qa`                                                                      | Skipped  |\n| `app=web,env=prod`, `app=api,env=prod`               | `app=\"api\", env=\"prod\"`                   | Second selector requires `app=api` AND `env=prod`; both are present in plugin labels                                     | Selected |\n| `app=web,env=test*,region=eu-west`, `app=*,env=test` | `app=\"web\", env=\"test\"`                   | First selector requires `app=web` AND `env=test*` AND `region=eu-west`, but `region` is missing; second selector matches | Selected |\n\n## Related Issues\n\n- [issue #1317](https://github.com/influxdata/telegraf/issues/1317)\n  for allowing to enable/disable plugin instances\n- [issue #9304](https://github.com/influxdata/telegraf/issues/9304)\n  for partially enabling a config file\n- [issue #10543](https://github.com/influxdata/telegraf/issues/10543)\n  for allowing to enable/disable plugin instances\n"
  },
  {
    "path": "docs/specs/tsd-011-internal-plugin-statistics.md",
    "content": "# Internal plugin statistics collection\n\n## Objective\n\nProvide a way to report plugin-internal statistics for collection by the\n[`internal` input plugin][internal].\n\n[internal]: /plugins/inputs/internal/README.md\n\n## Keywords\n\nplugins, statistics\n\n## Overview\n\nThe [`internal` input plugin][internal] allows to collect statistics about\nactive plugins in Telegraf. These statistics are valuable indicators for\noperating and optimizing Telegraf setups and for detecting issues.\n\nStatistics are provided by plugin models and are then gathered by the\n[`internal` input plugin][internal] to be emitted through the normal plugin\npipeline. However, not all important statistics are known on the model level.\nSome are only known within the plugin instance itself such as the bytes written\nto an output or certain error types. Emitting those statistics through direct\nregistration of a statistics object will not pick-up tags defined using the\nglobal tags settings or aliases which are only known at the model level.\n\nTo overcome the mentioned limitation this specification defines a framework\nallowing to inject a _statistics collector_ object into the plugin allowing to\nregister statistics including the `alias` and tags definitions.\n\nTo provide plugin-internal statistics a plugin should export a `Statistics`\nmember in the plugin structure. This member must be a pointer type\n`*selfstat.Collector`. It is strongly recommended to define a `\"-\"` TOML tag\nin order to avoid collisions with setting the member through user configuration.\n\nThe Telegraf model code then must inject a `selfstat.Collector` instance into\nthe plugin's `Statistics` member _after_ instantiating the plugin but _before_\ncalling the plugin's `Init` function. The injected collector instance must add\nall relevant model-level information such as an optional `alias` setting or\n`tags` settings.\nThe plugin must use the collector as proxy to register, unregister, reset and\naccess statistics.\n\n## Related Issues\n\n- [issue #4889](https://github.com/influxdata/telegraf/issues/4889) for\n  emitting internal statistics for the InfluxDB output plugin\n- [issue #6965](https://github.com/influxdata/telegraf/issues/6965) for\n  emitting internal statistics of the Kafka output plugin\n- [issue #17275](https://github.com/influxdata/telegraf/issues/17275) for\n  emitting internal statistics for the InfluxDB v2 output plugin\n"
  },
  {
    "path": "etc/logrotate.d/telegraf",
    "content": "/var/log/telegraf/telegraf.log \n{\n    rotate 6\n    daily\n    missingok\n    dateext\n    copytruncate\n    notifempty\n    compress\n}\n\n"
  },
  {
    "path": "filter/filter.go",
    "content": "package filter\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gobwas/glob\"\n)\n\ntype Filter interface {\n\tMatch(string) bool\n}\n\n// Compile takes a list of string filters and returns a Filter interface\n// for matching a given string against the filter list. The filter list\n// supports glob matching with separators too, ie:\n//\n//\tf, err := Compile([]string{\"cpu\", \"mem\", \"net*\"})\n//\tf.Match(\"cpu\")     // true\n//\tf.Match(\"network\") // true\n//\tf.Match(\"memory\")  // false\n//\n// separators are only to be used for globbing filters, ie:\n//\n//\tf, err := Compile([]string{\"cpu.*.count\"}, '.')\n//\tf.Match(\"cpu.count\")     // false\n//\tf.Match(\"cpu.measurement.count\") // true\n//\tf.Match(\"cpu.field.measurement.count\")  // false\n//\n// Compile will return nil if the filter list is empty.\nfunc Compile(filters []string, separators ...rune) (Filter, error) {\n\t// return if there is nothing to compile\n\tif len(filters) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// check if we can compile a non-glob filter\n\twildcards := len(separators) != 0\n\tfor _, filter := range filters {\n\t\tif strings.ContainsAny(filter, \"*?[\") {\n\t\t\twildcards = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tswitch {\n\tcase !wildcards && len(filters) == 1:\n\t\treturn &filterSingle{s: filters[0]}, nil\n\tcase !wildcards && len(filters) != 1:\n\t\treturn newFilterNoGlob(filters), nil\n\tcase wildcards && len(filters) == 1:\n\t\treturn glob.Compile(filters[0], separators...)\n\tdefault:\n\t\treturn newFilterGlobMultiple(filters, separators...)\n\t}\n}\n\nfunc MustCompile(filters []string, separators ...rune) Filter {\n\tf, err := Compile(filters, separators...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn f\n}\n\ntype IncludeExcludeFilter struct {\n\tinclude        Filter\n\texclude        Filter\n\tincludeDefault bool\n\texcludeDefault bool\n}\n\nfunc NewIncludeExcludeFilter(include, exclude []string) (Filter, error) {\n\treturn NewIncludeExcludeFilterDefaults(include, exclude, true, false)\n}\n\nfunc NewIncludeExcludeFilterDefaults(include, exclude []string, includeDefault, excludeDefault bool) (Filter, error) {\n\tin, err := Compile(include)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tex, err := Compile(exclude)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &IncludeExcludeFilter{in, ex, includeDefault, excludeDefault}, nil\n}\n\nfunc (f *IncludeExcludeFilter) Match(s string) bool {\n\tif f.include != nil {\n\t\tif !f.include.Match(s) {\n\t\t\treturn false\n\t\t}\n\t} else if !f.includeDefault {\n\t\treturn false\n\t}\n\n\tif f.exclude != nil {\n\t\tif f.exclude.Match(s) {\n\t\t\treturn false\n\t\t}\n\t} else if f.excludeDefault {\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "filter/filter_test.go",
    "content": "package filter\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCompile(t *testing.T) {\n\tf, err := Compile(nil)\n\trequire.NoError(t, err)\n\trequire.Nil(t, f)\n\n\tf, err = Compile([]string{\"cpu\"})\n\trequire.NoError(t, err)\n\trequire.True(t, f.Match(\"cpu\"))\n\trequire.False(t, f.Match(\"cpu0\"))\n\trequire.False(t, f.Match(\"mem\"))\n\n\tf, err = Compile([]string{\"cpu*\"})\n\trequire.NoError(t, err)\n\trequire.True(t, f.Match(\"cpu\"))\n\trequire.True(t, f.Match(\"cpu0\"))\n\trequire.False(t, f.Match(\"mem\"))\n\n\tf, err = Compile([]string{\"cpu\", \"mem\"})\n\trequire.NoError(t, err)\n\trequire.True(t, f.Match(\"cpu\"))\n\trequire.False(t, f.Match(\"cpu0\"))\n\trequire.True(t, f.Match(\"mem\"))\n\n\tf, err = Compile([]string{\"cpu\", \"mem\", \"net*\"})\n\trequire.NoError(t, err)\n\trequire.True(t, f.Match(\"cpu\"))\n\trequire.False(t, f.Match(\"cpu0\"))\n\trequire.True(t, f.Match(\"mem\"))\n\trequire.True(t, f.Match(\"network\"))\n\n\tf, err = Compile([]string{\"cpu.*.count\"}, '.')\n\trequire.NoError(t, err)\n\trequire.False(t, f.Match(\"cpu.count\"))\n\trequire.True(t, f.Match(\"cpu.measurement.count\"))\n\trequire.False(t, f.Match(\"cpu.field.measurement.count\"))\n\n\tf, err = Compile([]string{\"cpu.*.count\"}, '.', ',')\n\trequire.NoError(t, err)\n\trequire.True(t, f.Match(\"cpu.measurement.count\"))\n\trequire.False(t, f.Match(\"cpu.,.count\")) // ',' is not considered under * as it is specified as a separator\n\trequire.False(t, f.Match(\"cpu.field,measurement.count\"))\n}\n\nfunc TestMultiple(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tpattern  []string\n\t\tvalue    string\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tname:     \"issue 9265\",\n\t\t\tpattern:  []string{\"*process32:*.exe:*.*\", \"otherWantedMetric*\"},\n\t\t\tvalue:    \"cpu.process32:testcase.exe:caserunner.2222\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"issue 9265\",\n\t\t\tpattern:  []string{\"*process32:*.exe:*.*\", \"otherWantedMetric*\"},\n\t\t\tvalue:    \"process32:testcase.exe:caserunner.2222\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"issue 9265\",\n\t\t\tpattern:  []string{\"*process32:*.exe:*.*\", \"otherWantedMetric*\"},\n\t\t\tvalue:    \"otherWantedMetric\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"issue 9265\",\n\t\t\tpattern:  []string{\"*process32:*.exe:*.*\", \"otherWantedMetric*\"},\n\t\t\tvalue:    \"otherWantedMetric.ABC\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"issue 9265\",\n\t\t\tpattern:  []string{\"*process32:*.exe:*.*\", \"otherWantedMetric*\"},\n\t\t\tvalue:    \"unwantedMetric\",\n\t\t\texpected: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name+\"-\"+tt.value, func(t *testing.T) {\n\t\t\tf, err := Compile(tt.pattern)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, f.Match(tt.value))\n\t\t})\n\t}\n}\n\nfunc TestIncludeExclude(t *testing.T) {\n\tlabels := []string{\"best\", \"com_influxdata\", \"timeseries\", \"com_influxdata_telegraf\", \"ever\"}\n\ttags := make([]string, 0, len(labels))\n\n\tfilter, err := NewIncludeExcludeFilter(nil, []string{\"com_influx*\"})\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to create include/exclude filter - %v\", err)\n\t}\n\n\tfor i := range labels {\n\t\tif filter.Match(labels[i]) {\n\t\t\ttags = append(tags, labels[i])\n\t\t}\n\t}\n\n\trequire.Equal(t, []string{\"best\", \"timeseries\", \"ever\"}, tags)\n}\n\nvar benchbool bool\n\nfunc BenchmarkFilterSingleNoGlobFalse(b *testing.B) {\n\tf, err := Compile([]string{\"cpu\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"network\")\n\t}\n\tbenchbool = tmp\n}\n\nfunc BenchmarkFilterSingleNoGlobTrue(b *testing.B) {\n\tf, err := Compile([]string{\"cpu\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"cpu\")\n\t}\n\tbenchbool = tmp\n}\n\nfunc BenchmarkFilter(b *testing.B) {\n\tf, err := Compile([]string{\"cpu\", \"mem\", \"net*\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"network\")\n\t}\n\tbenchbool = tmp\n}\n\nfunc BenchmarkFilterNoGlob(b *testing.B) {\n\tf, err := Compile([]string{\"cpu\", \"mem\", \"net\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"net\")\n\t}\n\tbenchbool = tmp\n}\n\nfunc BenchmarkFilter2(b *testing.B) {\n\tf, err := Compile([]string{\"aa\", \"bb\", \"c\", \"ad\", \"ar\", \"at\", \"aq\",\n\t\t\"aw\", \"az\", \"axxx\", \"ab\", \"cpu\", \"mem\", \"net*\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"network\")\n\t}\n\tbenchbool = tmp\n}\n\nfunc BenchmarkFilter2NoGlob(b *testing.B) {\n\tf, err := Compile([]string{\"aa\", \"bb\", \"c\", \"ad\", \"ar\", \"at\", \"aq\",\n\t\t\"aw\", \"az\", \"axxx\", \"ab\", \"cpu\", \"mem\", \"net\"})\n\trequire.NoError(b, err)\n\tvar tmp bool\n\tfor n := 0; n < b.N; n++ {\n\t\ttmp = f.Match(\"net\")\n\t}\n\tbenchbool = tmp\n}\n"
  },
  {
    "path": "filter/implementations.go",
    "content": "package filter\n\nimport \"github.com/gobwas/glob\"\n\ntype filterSingle struct {\n\ts string\n}\n\nfunc (f *filterSingle) Match(s string) bool {\n\treturn f.s == s\n}\n\ntype filterNoGlob struct {\n\tm map[string]struct{}\n}\n\nfunc newFilterNoGlob(filters []string) Filter {\n\tout := filterNoGlob{m: make(map[string]struct{})}\n\tfor _, filter := range filters {\n\t\tout.m[filter] = struct{}{}\n\t}\n\treturn &out\n}\n\nfunc (f *filterNoGlob) Match(s string) bool {\n\t_, ok := f.m[s]\n\treturn ok\n}\n\ntype filterGlobMultiple struct {\n\tset []glob.Glob\n}\n\nfunc newFilterGlobMultiple(filters []string, separators ...rune) (Filter, error) {\n\tf := &filterGlobMultiple{set: make([]glob.Glob, 0, len(filters))}\n\n\tfor _, pattern := range filters {\n\t\tg, err := glob.Compile(pattern, separators...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tf.set = append(f.set, g)\n\t}\n\n\treturn f, nil\n}\n\nfunc (f *filterGlobMultiple) Match(s string) bool {\n\tfor _, g := range f.set {\n\t\tif g.Match(s) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/influxdata/telegraf\n\ngo 1.25.7\n\ngodebug x509negativeserial=1\n\nrequire (\n\tcloud.google.com/go/auth v0.18.2\n\tcloud.google.com/go/bigquery v1.74.0\n\tcloud.google.com/go/monitoring v1.24.3\n\tcloud.google.com/go/pubsub/v2 v2.4.0\n\tcloud.google.com/go/storage v1.61.3\n\tcollectd.org v0.6.0\n\tgithub.com/99designs/keyring v1.2.2\n\tgithub.com/Azure/azure-event-hubs-go/v3 v3.6.2\n\tgithub.com/Azure/azure-kusto-go v0.16.1\n\tgithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1\n\tgithub.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs/v2 v2.0.2\n\tgithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1\n\tgithub.com/Azure/go-autorest/autorest v0.11.30\n\tgithub.com/Azure/go-autorest/autorest/adal v0.9.24\n\tgithub.com/Azure/go-autorest/autorest/azure/auth v0.5.13\n\tgithub.com/BurntSushi/toml v1.6.0\n\tgithub.com/ClickHouse/clickhouse-go/v2 v2.43.0\n\tgithub.com/DATA-DOG/go-sqlmock v1.5.2\n\tgithub.com/IBM/nzgo/v12 v12.0.11\n\tgithub.com/IBM/sarama v1.47.0\n\tgithub.com/Masterminds/semver/v3 v3.4.0\n\tgithub.com/Masterminds/sprig v2.22.0+incompatible\n\tgithub.com/Masterminds/sprig/v3 v3.3.0\n\tgithub.com/Mellanox/rdmamap v1.1.0\n\tgithub.com/PaesslerAG/gval v1.2.4\n\tgithub.com/SAP/go-hdb v1.16.1\n\tgithub.com/aerospike/aerospike-client-go/v5 v5.11.0\n\tgithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b\n\tgithub.com/alitto/pond v1.9.2\n\tgithub.com/alitto/pond/v2 v2.7.0\n\tgithub.com/aliyun/alibaba-cloud-sdk-go v1.63.107\n\tgithub.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9\n\tgithub.com/antchfx/jsonquery v1.3.6\n\tgithub.com/antchfx/xmlquery v1.5.0\n\tgithub.com/antchfx/xpath v1.3.6\n\tgithub.com/apache/arrow-go/v18 v18.5.2\n\tgithub.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang v1.0.7\n\tgithub.com/apache/iotdb-client-go v1.3.5\n\tgithub.com/apache/thrift v0.22.0\n\tgithub.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740\n\tgithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5\n\tgithub.com/awnumar/memguard v0.23.0\n\tgithub.com/aws/aws-msk-iam-sasl-signer-go v1.0.4\n\tgithub.com/aws/aws-sdk-go-v2 v1.41.3\n\tgithub.com/aws/aws-sdk-go-v2/config v1.32.11\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.19.11\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19\n\tgithub.com/aws/aws-sdk-go-v2/service/cloudwatch v1.55.1\n\tgithub.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.64.0\n\tgithub.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1\n\tgithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.0\n\tgithub.com/aws/aws-sdk-go-v2/service/kinesis v1.43.2\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.41.8\n\tgithub.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.18\n\tgithub.com/aws/smithy-go v1.24.2\n\tgithub.com/benbjohnson/clock v1.3.5\n\tgithub.com/bluenviron/gomavlib/v3 v3.3.0\n\tgithub.com/blues/jsonata-go v1.5.4\n\tgithub.com/bmatcuk/doublestar/v3 v3.0.0\n\tgithub.com/boschrexroth/ctrlx-datalayer-golang v1.3.1\n\tgithub.com/bufbuild/protocompile v0.14.1\n\tgithub.com/caio/go-tdigest v3.1.0+incompatible\n\tgithub.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df\n\tgithub.com/clarify/clarify-go v0.4.1\n\tgithub.com/cloudevents/sdk-go/v2 v2.16.2\n\tgithub.com/compose-spec/compose-go v1.20.2\n\tgithub.com/coocood/freecache v1.2.5\n\tgithub.com/coreos/go-semver v0.3.1\n\tgithub.com/coreos/go-systemd/v22 v22.7.0\n\tgithub.com/couchbase/go-couchbase v0.1.1\n\tgithub.com/datadope-io/go-zabbix/v2 v2.0.1\n\tgithub.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6\n\tgithub.com/dimchansky/utfbom v1.1.1\n\tgithub.com/djherbis/times v1.6.0\n\tgithub.com/docker/docker v28.5.2+incompatible\n\tgithub.com/docker/go-connections v0.6.0\n\tgithub.com/dustin/go-humanize v1.0.1\n\tgithub.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0\n\tgithub.com/eclipse/paho.golang v0.23.0\n\tgithub.com/eclipse/paho.mqtt.golang v1.5.1\n\tgithub.com/emiago/sipgo v1.2.1\n\tgithub.com/facebook/time v0.0.0-20250903103710-a5911c32cdb9\n\tgithub.com/fatih/color v1.18.0\n\tgithub.com/go-ldap/ldap/v3 v3.4.12\n\tgithub.com/go-logfmt/logfmt v0.6.1\n\tgithub.com/go-ole/go-ole v1.3.0\n\tgithub.com/go-redis/redis/v7 v7.4.1\n\tgithub.com/go-redis/redis/v8 v8.11.5\n\tgithub.com/go-sql-driver/mysql v1.9.3\n\tgithub.com/go-stomp/stomp v2.1.4+incompatible\n\tgithub.com/gobwas/glob v0.2.3\n\tgithub.com/gofrs/uuid/v5 v5.4.0\n\tgithub.com/gogo/protobuf v1.3.2\n\tgithub.com/golang-jwt/jwt/v5 v5.3.1\n\tgithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec\n\tgithub.com/golang/snappy v1.0.0\n\tgithub.com/google/cel-go v0.27.0\n\tgithub.com/google/gnxi v0.0.0-20231026134436-d82d9936af15\n\tgithub.com/google/go-cmp v0.7.0\n\tgithub.com/google/go-github/v32 v32.1.0\n\tgithub.com/google/licensecheck v0.3.1\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/gopacket/gopacket v1.5.0\n\tgithub.com/gopcua/opcua v0.8.0\n\tgithub.com/gophercloud/gophercloud/v2 v2.11.1\n\tgithub.com/gorcon/rcon v1.4.0\n\tgithub.com/gorilla/mux v1.8.1\n\tgithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674\n\tgithub.com/gosnmp/gosnmp v1.43.2\n\tgithub.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18\n\tgithub.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358\n\tgithub.com/hashicorp/consul/api v1.33.4\n\tgithub.com/hashicorp/go-uuid v1.0.3\n\tgithub.com/hashicorp/golang-lru/v2 v2.0.7\n\tgithub.com/hashicorp/vault/api v1.22.0\n\tgithub.com/hashicorp/vault/api/auth/approle v0.11.0\n\tgithub.com/influxdata/influxdb-observability/common v0.5.12\n\tgithub.com/influxdata/influxdb-observability/influx2otel v0.5.12\n\tgithub.com/influxdata/influxdb-observability/otel2influx v0.5.12\n\tgithub.com/influxdata/line-protocol/v2 v2.2.1\n\tgithub.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a\n\tgithub.com/influxdata/toml v0.0.0-20251106153700-c381e153d076\n\tgithub.com/intel/iaevents v1.1.0\n\tgithub.com/intel/powertelemetry v1.0.2\n\tgithub.com/jackc/pgconn v1.14.3\n\tgithub.com/jackc/pgio v1.0.0\n\tgithub.com/jackc/pgtype v1.14.4\n\tgithub.com/jackc/pgx/v4 v4.18.3\n\tgithub.com/jedib0t/go-pretty/v6 v6.7.8\n\tgithub.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4\n\tgithub.com/jmespath/go-jmespath v0.4.0\n\tgithub.com/karrick/godirwalk v1.16.2\n\tgithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51\n\tgithub.com/klauspost/compress v1.18.4\n\tgithub.com/klauspost/pgzip v1.2.6\n\tgithub.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b\n\tgithub.com/leodido/go-syslog/v4 v4.3.0\n\tgithub.com/likexian/whois v1.15.7\n\tgithub.com/likexian/whois-parser v1.24.21\n\tgithub.com/linkedin/goavro/v2 v2.15.0\n\tgithub.com/logzio/azure-monitor-metrics-receiver v1.1.0\n\tgithub.com/lxc/incus/v6 v6.22.0\n\tgithub.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a\n\tgithub.com/mdlayher/vsock v1.2.1\n\tgithub.com/microsoft/ApplicationInsights-Go v0.4.4\n\tgithub.com/microsoft/go-mssqldb v1.9.8\n\tgithub.com/miekg/dns v1.1.72\n\tgithub.com/moby/ipvs v1.1.0\n\tgithub.com/multiplay/go-ts3 v1.2.0\n\tgithub.com/nats-io/nats-server/v2 v2.12.5\n\tgithub.com/nats-io/nats.go v1.49.0\n\tgithub.com/netsampler/goflow2/v2 v2.2.6\n\tgithub.com/newrelic/newrelic-telemetry-sdk-go v0.8.1\n\tgithub.com/nsqio/go-nsq v1.1.0\n\tgithub.com/nwaples/tacplus v0.0.3\n\tgithub.com/olivere/elastic v6.2.37+incompatible\n\tgithub.com/openconfig/gnmi v0.14.1\n\tgithub.com/openconfig/goyang v1.6.3\n\tgithub.com/opensearch-project/opensearch-go/v2 v2.3.0\n\tgithub.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b\n\tgithub.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0\n\tgithub.com/openzipkin/zipkin-go v0.4.3\n\tgithub.com/p4lang/p4runtime v1.5.0\n\tgithub.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0\n\tgithub.com/pborman/ansi v1.0.0\n\tgithub.com/pcolladosoto/goslurm v0.1.0\n\tgithub.com/peterbourgon/unixtransport v0.0.7\n\tgithub.com/pion/dtls/v3 v3.1.2\n\tgithub.com/prometheus-community/pro-bing v0.8.0\n\tgithub.com/prometheus/client_golang v1.23.2\n\tgithub.com/prometheus/client_model v0.6.2\n\tgithub.com/prometheus/common v0.67.5\n\tgithub.com/prometheus/procfs v0.20.1\n\tgithub.com/prometheus/prometheus v0.310.0\n\tgithub.com/rabbitmq/amqp091-go v1.10.0\n\tgithub.com/rclone/rclone v1.69.3\n\tgithub.com/redis/go-redis/v9 v9.18.0\n\tgithub.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16\n\tgithub.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1\n\tgithub.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846\n\tgithub.com/safchain/ethtool v0.7.0\n\tgithub.com/santhosh-tekuri/jsonschema/v5 v5.3.1\n\tgithub.com/seancfoley/ipaddress-go v1.7.1\n\tgithub.com/sensu/sensu-go/api/core/v2 v2.16.0\n\tgithub.com/shirou/gopsutil/v4 v4.26.2\n\tgithub.com/showwin/speedtest-go v1.7.10\n\tgithub.com/signalfx/golib/v3 v3.3.54\n\tgithub.com/sijms/go-ora/v2 v2.9.0\n\tgithub.com/sirupsen/logrus v1.9.4\n\tgithub.com/sleepinggenius2/gosmi v0.4.4\n\tgithub.com/snowflakedb/gosnowflake v1.19.0\n\tgithub.com/srebhan/cborquery v1.0.4\n\tgithub.com/srebhan/protobufquery v1.0.4\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62\n\tgithub.com/tdrn-org/go-hue v0.3.0\n\tgithub.com/tdrn-org/go-nsdp v0.5.0\n\tgithub.com/tdrn-org/go-tr064 v0.2.3\n\tgithub.com/testcontainers/testcontainers-go v0.41.0\n\tgithub.com/testcontainers/testcontainers-go/modules/azure v0.40.0\n\tgithub.com/testcontainers/testcontainers-go/modules/kafka v0.40.0\n\tgithub.com/testcontainers/testcontainers-go/modules/vault v0.41.0\n\tgithub.com/thomasklein94/packer-plugin-libvirt v0.5.0\n\tgithub.com/tidwall/gjson v1.18.0\n\tgithub.com/tidwall/wal v1.2.1\n\tgithub.com/tinylib/msgp v1.6.3\n\tgithub.com/urfave/cli/v2 v2.27.7\n\tgithub.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11\n\tgithub.com/vertica/vertica-sql-go v1.3.5\n\tgithub.com/vishvananda/netlink v1.3.1\n\tgithub.com/vishvananda/netns v0.0.5\n\tgithub.com/vjeantet/grok v1.0.1\n\tgithub.com/vmware/govmomi v0.53.0\n\tgithub.com/wavefronthq/wavefront-sdk-go v0.15.0\n\tgithub.com/x448/float16 v0.8.4\n\tgithub.com/xdg/scram v1.0.5\n\tgithub.com/yuin/goldmark v1.7.16\n\tgo.mongodb.org/mongo-driver v1.17.9\n\tgo.opentelemetry.io/collector/pdata v1.53.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0\n\tgo.opentelemetry.io/otel/sdk/metric v1.41.0\n\tgo.opentelemetry.io/proto/otlp v1.10.0\n\tgo.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0\n\tgo.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0\n\tgo.starlark.net v0.0.0-20260210143700-b62fd896b91b\n\tgo.step.sm/crypto v0.76.2\n\tgo.yaml.in/yaml/v3 v3.0.4\n\tgolang.org/x/crypto v0.49.0\n\tgolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa\n\tgolang.org/x/mod v0.34.0\n\tgolang.org/x/net v0.52.0\n\tgolang.org/x/oauth2 v0.36.0\n\tgolang.org/x/sync v0.20.0\n\tgolang.org/x/sys v0.42.0\n\tgolang.org/x/term v0.41.0\n\tgolang.org/x/text v0.35.0\n\tgolang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671\n\tgonum.org/v1/gonum v0.17.0\n\tgoogle.golang.org/api v0.272.0\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d\n\tgoogle.golang.org/grpc v1.79.3\n\tgoogle.golang.org/protobuf v1.36.11\n\tgopkg.in/gorethink/gorethink.v3 v3.0.5\n\tgopkg.in/olivere/elastic.v5 v5.0.86\n\tgopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7\n\tk8s.io/api v0.35.2\n\tk8s.io/apimachinery v0.35.2\n\tk8s.io/client-go v0.35.2\n\tlayeh.com/radius v0.0.0-20221205141417-e7fbddd11d68\n\tmodernc.org/sqlite v1.46.2\n\tsoftware.sslmate.com/src/go-pkcs12 v0.7.0\n)\n\nrequire (\n\tcel.dev/expr v0.25.1 // indirect\n\tcloud.google.com/go v0.123.0 // indirect\n\tcloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect\n\tcloud.google.com/go/compute/metadata v0.9.0 // indirect\n\tcloud.google.com/go/iam v1.5.3 // indirect\n\tcode.cloudfoundry.org/clock v1.2.0 // indirect\n\tdario.cat/mergo v1.0.2 // indirect\n\tfilippo.io/edwards25519 v1.1.1 // indirect\n\tgithub.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect\n\tgithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect\n\tgithub.com/Azure/azure-amqp-common-go/v4 v4.2.0 // indirect\n\tgithub.com/Azure/azure-pipeline-go v0.2.3 // indirect\n\tgithub.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect\n\tgithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect\n\tgithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 // indirect\n\tgithub.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe // indirect\n\tgithub.com/Azure/go-amqp v1.5.0 // indirect\n\tgithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect\n\tgithub.com/Azure/go-autorest v14.2.0+incompatible // indirect\n\tgithub.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect\n\tgithub.com/Azure/go-autorest/autorest/date v0.3.0 // indirect\n\tgithub.com/Azure/go-autorest/autorest/to v0.4.0 // indirect\n\tgithub.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect\n\tgithub.com/Azure/go-autorest/logger v0.2.1 // indirect\n\tgithub.com/Azure/go-autorest/tracing v0.6.0 // indirect\n\tgithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect\n\tgithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect\n\tgithub.com/ClickHouse/ch-go v0.71.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect\n\tgithub.com/Masterminds/goutils v1.1.1 // indirect\n\tgithub.com/Masterminds/semver v1.5.0 // indirect\n\tgithub.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd // indirect\n\tgithub.com/Microsoft/go-winio v0.6.2 // indirect\n\tgithub.com/abbot/go-http-auth v0.4.0 // indirect\n\tgithub.com/alecthomas/participle v0.4.1 // indirect\n\tgithub.com/andybalholm/brotli v1.2.0 // indirect\n\tgithub.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.1 // indirect\n\tgithub.com/apache/arrow/go/v15 v15.0.2 // indirect\n\tgithub.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect\n\tgithub.com/apex/log v1.9.0 // indirect\n\tgithub.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3 // indirect\n\tgithub.com/armon/go-metrics v0.4.1 // indirect\n\tgithub.com/awnumar/memcall v0.4.0 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/signin v1.0.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.30.12 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/bitly/go-hostpool v0.1.0 // indirect\n\tgithub.com/blang/semver/v4 v4.0.0 // indirect\n\tgithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect\n\tgithub.com/brutella/dnssd v1.2.14 // indirect\n\tgithub.com/bwmarrin/snowflake v0.3.0 // indirect\n\tgithub.com/caio/go-tdigest/v4 v4.0.1 // indirect\n\tgithub.com/cenkalti/backoff v2.2.1+incompatible // indirect\n\tgithub.com/cenkalti/backoff/v4 v4.3.0 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/clipperhouse/uax29/v2 v2.7.0 // indirect\n\tgithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect\n\tgithub.com/containerd/errdefs v1.0.0 // indirect\n\tgithub.com/containerd/errdefs/pkg v0.3.0 // indirect\n\tgithub.com/containerd/log v0.1.0 // indirect\n\tgithub.com/containerd/platforms v0.2.1 // indirect\n\tgithub.com/couchbase/gomemcached v0.1.3 // indirect\n\tgithub.com/couchbase/goutils v0.1.0 // indirect\n\tgithub.com/cpuguy83/dockercfg v0.3.2 // indirect\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect\n\tgithub.com/creack/goselect v0.1.3 // indirect\n\tgithub.com/cyphar/filepath-securejoin v0.6.1 // indirect\n\tgithub.com/danieljoos/wincred v1.2.2 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/devigned/tab v0.1.1 // indirect\n\tgithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect\n\tgithub.com/distribution/reference v0.6.0 // indirect\n\tgithub.com/docker/go-units v0.5.0 // indirect\n\tgithub.com/dvsekhvalnov/jose2go v1.7.0 // indirect\n\tgithub.com/eapache/go-resiliency v1.7.0 // indirect\n\tgithub.com/eapache/queue v1.1.0 // indirect\n\tgithub.com/ebitengine/purego v0.10.0 // indirect\n\tgithub.com/echlebek/timeproxy v1.0.0 // indirect\n\tgithub.com/elastic/go-sysinfo v1.8.1 // indirect\n\tgithub.com/elastic/go-windows v1.0.0 // indirect\n\tgithub.com/emicklei/go-restful/v3 v3.12.2 // indirect\n\tgithub.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect\n\tgithub.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/fxamacker/cbor/v2 v2.9.0 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.13 // indirect\n\tgithub.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect\n\tgithub.com/go-chi/chi/v5 v5.2.5 // indirect\n\tgithub.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 // indirect\n\tgithub.com/go-faster/city v1.0.1 // indirect\n\tgithub.com/go-faster/errors v0.7.1 // indirect\n\tgithub.com/go-git/go-billy/v5 v5.6.0 // indirect\n\tgithub.com/go-jose/go-jose/v4 v4.1.3 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.22.4 // indirect\n\tgithub.com/go-openapi/jsonreference v0.21.4 // indirect\n\tgithub.com/go-openapi/swag v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/cmdutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/conv v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/fileutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/jsonname v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/jsonutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/loading v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/mangling v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/netutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/stringutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/typeutils v0.25.4 // indirect\n\tgithub.com/go-openapi/swag/yamlutils v0.25.4 // indirect\n\tgithub.com/go-resty/resty/v2 v2.17.1 // indirect\n\tgithub.com/go-stack/stack v1.8.1 // indirect\n\tgithub.com/go-viper/mapstructure/v2 v2.5.0 // indirect\n\tgithub.com/goburrow/modbus v0.1.0 // indirect\n\tgithub.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd // indirect\n\tgithub.com/gobwas/httphead v0.1.0 // indirect\n\tgithub.com/gobwas/pool v0.2.1 // indirect\n\tgithub.com/gobwas/ws v1.3.2 // indirect\n\tgithub.com/goccy/go-json v0.10.5 // indirect\n\tgithub.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect\n\tgithub.com/godbus/dbus/v5 v5.1.0 // indirect\n\tgithub.com/gofrs/uuid v4.4.0+incompatible // indirect\n\tgithub.com/golang-jwt/jwt/v4 v4.5.2 // indirect\n\tgithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect\n\tgithub.com/golang-sql/sqlexp v0.1.0 // indirect\n\tgithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/flatbuffers v25.12.19+incompatible // indirect\n\tgithub.com/google/gnostic-models v0.7.0 // indirect\n\tgithub.com/google/go-querystring v1.2.0 // indirect\n\tgithub.com/google/go-tpm v0.9.8 // indirect\n\tgithub.com/google/s2a-go v0.1.9 // indirect\n\tgithub.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect\n\tgithub.com/googleapis/gax-go/v2 v2.18.0 // indirect\n\tgithub.com/gorilla/securecookie v1.1.2 // indirect\n\tgithub.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 // indirect\n\tgithub.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect\n\tgithub.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect\n\tgithub.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-hclog v1.6.3 // indirect\n\tgithub.com/hashicorp/go-immutable-radix v1.3.1 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-retryablehttp v0.7.8 // indirect\n\tgithub.com/hashicorp/go-rootcerts v1.0.2 // indirect\n\tgithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect\n\tgithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect\n\tgithub.com/hashicorp/go-sockaddr v1.0.7 // indirect\n\tgithub.com/hashicorp/go-version v1.8.0 // indirect\n\tgithub.com/hashicorp/golang-lru v1.0.2 // indirect\n\tgithub.com/hashicorp/hcl v1.0.1-vault-7 // indirect\n\tgithub.com/hashicorp/packer-plugin-sdk v0.3.2 // indirect\n\tgithub.com/hashicorp/serf v0.10.1 // indirect\n\tgithub.com/huandu/xstrings v1.5.0 // indirect\n\tgithub.com/icholy/digest v1.1.0 // indirect\n\tgithub.com/imdario/mergo v0.3.16 // indirect\n\tgithub.com/jackc/chunkreader/v2 v2.0.1 // indirect\n\tgithub.com/jackc/pgpassfile v1.0.0 // indirect\n\tgithub.com/jackc/pgproto3/v2 v2.3.3 // indirect\n\tgithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect\n\tgithub.com/jackc/puddle v1.3.0 // indirect\n\tgithub.com/jaegertracing/jaeger v1.47.0 // indirect\n\tgithub.com/jcmturner/aescts/v2 v2.0.0 // indirect\n\tgithub.com/jcmturner/dnsutils/v2 v2.0.0 // indirect\n\tgithub.com/jcmturner/gofork v1.7.6 // indirect\n\tgithub.com/jcmturner/goidentity/v6 v6.0.1 // indirect\n\tgithub.com/jcmturner/gokrb5/v8 v8.4.4 // indirect\n\tgithub.com/jcmturner/rpc/v2 v2.0.3 // indirect\n\tgithub.com/jmhodges/clock v1.2.0 // indirect\n\tgithub.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/josharian/native v1.1.0 // indirect\n\tgithub.com/jpillora/backoff v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect\n\tgithub.com/klauspost/asmfmt v1.3.2 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/kr/fs v0.1.0 // indirect\n\tgithub.com/kylelemons/godebug v1.1.0 // indirect\n\tgithub.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect\n\tgithub.com/likexian/gokit v0.25.16 // indirect\n\tgithub.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mailru/easyjson v0.9.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-ieproxy v0.0.11 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.20 // indirect\n\tgithub.com/mdlayher/genetlink v1.2.0 // indirect\n\tgithub.com/mdlayher/netlink v1.7.2 // indirect\n\tgithub.com/mdlayher/socket v0.5.1 // indirect\n\tgithub.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect\n\tgithub.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect\n\tgithub.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect\n\tgithub.com/mitchellh/copystructure v1.2.0 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/moby/docker-image-spec v1.3.1 // indirect\n\tgithub.com/moby/go-archive v0.2.0 // indirect\n\tgithub.com/moby/patternmatcher v0.6.0 // indirect\n\tgithub.com/moby/sys/sequential v0.6.0 // indirect\n\tgithub.com/moby/sys/user v0.4.0 // indirect\n\tgithub.com/moby/sys/userns v0.1.0 // indirect\n\tgithub.com/moby/term v0.5.2 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect\n\tgithub.com/montanaflynn/stats v0.7.1 // indirect\n\tgithub.com/morikuni/aec v1.1.0 // indirect\n\tgithub.com/mtibben/percent v0.2.1 // indirect\n\tgithub.com/muhlemmer/gu v0.3.1 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect\n\tgithub.com/naoina/go-stringutil v0.1.0 // indirect\n\tgithub.com/nats-io/jwt/v2 v2.8.0 // indirect\n\tgithub.com/nats-io/nkeys v0.4.15 // indirect\n\tgithub.com/nats-io/nuid v1.0.1 // indirect\n\tgithub.com/ncruces/go-strftime v1.0.0 // indirect\n\tgithub.com/ncw/swift/v2 v2.0.3 // indirect\n\tgithub.com/oapi-codegen/runtime v1.1.1 // indirect\n\tgithub.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.145.0 // indirect\n\tgithub.com/opencontainers/go-digest v1.0.0 // indirect\n\tgithub.com/opencontainers/image-spec v1.1.1 // indirect\n\tgithub.com/opencontainers/runtime-spec v1.3.0 // indirect\n\tgithub.com/opencontainers/umoci v0.6.1-0.20251213054154-70fc5ee1f4df // indirect\n\tgithub.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect\n\tgithub.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect\n\tgithub.com/panjf2000/ants/v2 v2.11.3 // indirect\n\tgithub.com/panjf2000/gnet/v2 v2.9.7 // indirect\n\tgithub.com/paulmach/orb v0.12.0 // indirect\n\tgithub.com/philhofer/fwd v1.2.0 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.25 // indirect\n\tgithub.com/pion/logging v0.2.4 // indirect\n\tgithub.com/pion/transport/v2 v2.2.10 // indirect\n\tgithub.com/pion/transport/v4 v4.0.1 // indirect\n\tgithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/pkg/sftp v1.13.10 // indirect\n\tgithub.com/pkg/xattr v0.4.12 // indirect\n\tgithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect\n\tgithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect\n\tgithub.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/rfjakob/eme v1.1.2 // indirect\n\tgithub.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff // indirect\n\tgithub.com/robfig/cron/v3 v3.0.1 // indirect\n\tgithub.com/rootless-containers/proto/go-proto v0.0.0-20260207013450-f6ee952d53d9 // indirect\n\tgithub.com/russross/blackfriday/v2 v2.1.0 // indirect\n\tgithub.com/ryanuber/go-glob v1.0.0 // indirect\n\tgithub.com/samber/lo v1.47.0 // indirect\n\tgithub.com/seancfoley/bintree v1.3.1 // indirect\n\tgithub.com/segmentio/asm v1.2.1 // indirect\n\tgithub.com/shopspring/decimal v1.4.0 // indirect\n\tgithub.com/signalfx/com_signalfx_metrics_protobuf v0.0.3 // indirect\n\tgithub.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083 // indirect\n\tgithub.com/signalfx/sapm-proto v0.12.0 // indirect\n\tgithub.com/spf13/cast v1.10.0 // indirect\n\tgithub.com/spf13/pflag v1.0.10 // indirect\n\tgithub.com/spiffe/go-spiffe/v2 v2.6.0 // indirect\n\tgithub.com/stretchr/objx v0.5.2 // indirect\n\tgithub.com/tidwall/match v1.1.1 // indirect\n\tgithub.com/tidwall/pretty v1.2.1 // indirect\n\tgithub.com/tidwall/tinylru v1.2.1 // indirect\n\tgithub.com/tklauser/go-sysconf v0.3.16 // indirect\n\tgithub.com/tklauser/numcpus v0.11.0 // indirect\n\tgithub.com/twmb/murmur3 v1.1.7 // indirect\n\tgithub.com/uber/jaeger-client-go v2.30.0+incompatible // indirect\n\tgithub.com/uber/jaeger-lib v2.4.1+incompatible // indirect\n\tgithub.com/urfave/cli v1.22.17 // indirect\n\tgithub.com/valyala/bytebufferpool v1.0.0 // indirect\n\tgithub.com/vbatts/go-mtree v0.7.0 // indirect\n\tgithub.com/xanzy/ssh-agent v0.3.3 // indirect\n\tgithub.com/xdg-go/pbkdf2 v1.0.0 // indirect\n\tgithub.com/xdg-go/scram v1.2.0 // indirect\n\tgithub.com/xdg-go/stringprep v1.0.4 // indirect\n\tgithub.com/xdg/stringprep v1.0.3 // indirect\n\tgithub.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect\n\tgithub.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect\n\tgithub.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect\n\tgithub.com/yusufpapurcu/wmi v1.2.4 // indirect\n\tgithub.com/zeebo/assert v1.3.1 // indirect\n\tgithub.com/zeebo/xxh3 v1.1.0 // indirect\n\tgithub.com/zentures/cityhash v0.0.0-20131128155616-cdd6a94144ab // indirect\n\tgithub.com/zitadel/logging v0.7.0 // indirect\n\tgithub.com/zitadel/oidc/v3 v3.45.4 // indirect\n\tgithub.com/zitadel/schema v1.3.2 // indirect\n\tgo.bug.st/serial v1.6.4 // indirect\n\tgo.etcd.io/etcd/api/v3 v3.5.4 // indirect\n\tgo.opencensus.io v0.24.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/collector/consumer/consumererror v0.135.0 // indirect\n\tgo.opentelemetry.io/collector/featuregate v1.53.0 // indirect\n\tgo.opentelemetry.io/collector/internal/testutil v0.147.0 // indirect\n\tgo.opentelemetry.io/collector/pdata/pprofile v0.140.0 // indirect\n\tgo.opentelemetry.io/collector/semconv v0.128.0 // indirect\n\tgo.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect\n\tgo.opentelemetry.io/otel v1.41.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.41.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.41.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.41.0 // indirect\n\tgo.uber.org/atomic v1.11.0 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.1 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.3 // indirect\n\tgolang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect\n\tgolang.org/x/time v0.15.0 // indirect\n\tgolang.org/x/tools v0.42.0 // indirect\n\tgolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect\n\tgolang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect\n\tgopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect\n\tgopkg.in/fatih/pool.v2 v2.0.0 // indirect\n\tgopkg.in/fsnotify.v1 v1.4.7 // indirect\n\tgopkg.in/inf.v0 v0.9.1 // indirect\n\tgopkg.in/ini.v1 v1.67.1 // indirect\n\tgopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect\n\tgopkg.in/sourcemap.v1 v1.0.5 // indirect\n\tgopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\thonnef.co/go/tools v0.2.2 // indirect\n\thowett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect\n\tk8s.io/klog/v2 v2.130.1 // indirect\n\tk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect\n\tk8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect\n\tmodernc.org/libc v1.70.0 // indirect\n\tmodernc.org/mathutil v1.7.1 // indirect\n\tmodernc.org/memory v1.11.0 // indirect\n\tsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect\n\tsigs.k8s.io/randfill v1.0.0 // indirect\n\tsigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect\n\tsigs.k8s.io/yaml v1.6.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI=\nbou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA=\ncel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=\ncloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=\ncloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=\ncloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=\ncloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=\ncloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=\ncloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=\ncloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=\ncloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=\ncloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=\ncloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=\ncloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=\ncloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=\ncloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=\ncloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=\ncloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=\ncloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=\ncloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=\ncloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4=\ncloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=\ncloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E=\ncloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o=\ncloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE=\ncloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM=\ncloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ=\ncloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=\ncloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=\ncloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg=\ncloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ=\ncloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k=\ncloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw=\ncloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=\ncloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=\ncloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M=\ncloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE=\ncloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE=\ncloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk=\ncloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc=\ncloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8=\ncloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc=\ncloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04=\ncloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8=\ncloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY=\ncloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM=\ncloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc=\ncloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU=\ncloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI=\ncloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8=\ncloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno=\ncloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak=\ncloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84=\ncloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A=\ncloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E=\ncloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=\ncloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=\ncloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY=\ncloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k=\ncloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=\ncloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=\ncloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0=\ncloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc=\ncloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI=\ncloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ=\ncloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI=\ncloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08=\ncloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=\ncloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=\ncloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=\ncloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ=\ncloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY=\ncloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo=\ncloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg=\ncloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw=\ncloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=\ncloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=\ncloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=\ncloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=\ncloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=\ncloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=\ncloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=\ncloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=\ncloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=\ncloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=\ncloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM=\ncloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU=\ncloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc=\ncloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI=\ncloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss=\ncloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE=\ncloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE=\ncloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g=\ncloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4=\ncloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8=\ncloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM=\ncloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=\ncloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw=\ncloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc=\ncloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E=\ncloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac=\ncloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q=\ncloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU=\ncloud.google.com/go/bigquery v1.74.0 h1:Q6bAMv+eyvufOpIrfrYxhM46qq1D3ZQTdgUDQqKS+n8=\ncloud.google.com/go/bigquery v1.74.0/go.mod h1:iViO7Cx3A/cRKcHNRsHB3yqGAMInFBswrE9Pxazsc90=\ncloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=\ncloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=\ncloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=\ncloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y=\ncloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss=\ncloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc=\ncloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=\ncloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=\ncloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0=\ncloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk=\ncloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q=\ncloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg=\ncloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590=\ncloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8=\ncloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk=\ncloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk=\ncloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE=\ncloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU=\ncloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U=\ncloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA=\ncloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M=\ncloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg=\ncloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s=\ncloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM=\ncloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk=\ncloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA=\ncloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=\ncloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=\ncloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4=\ncloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI=\ncloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y=\ncloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs=\ncloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=\ncloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=\ncloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=\ncloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=\ncloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=\ncloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=\ncloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=\ncloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=\ncloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=\ncloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=\ncloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=\ncloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=\ncloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=\ncloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=\ncloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE=\ncloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=\ncloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=\ncloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=\ncloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=\ncloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=\ncloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=\ncloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=\ncloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=\ncloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=\ncloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg=\ncloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo=\ncloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4=\ncloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM=\ncloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA=\ncloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=\ncloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=\ncloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI=\ncloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s=\ncloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=\ncloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=\ncloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=\ncloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE=\ncloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM=\ncloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M=\ncloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0=\ncloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8=\ncloud.google.com/go/datacatalog v1.26.1 h1:bCRKA8uSQN8wGW3Tw0gwko4E9a64GRmbW1nCblhgC2k=\ncloud.google.com/go/datacatalog v1.26.1/go.mod h1:2Qcq8vsHNxMDgjgadRFmFG47Y+uuIVsyEGUrlrKEdrg=\ncloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=\ncloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=\ncloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE=\ncloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=\ncloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=\ncloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0=\ncloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA=\ncloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE=\ncloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38=\ncloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w=\ncloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8=\ncloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=\ncloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=\ncloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM=\ncloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA=\ncloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A=\ncloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ=\ncloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs=\ncloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s=\ncloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI=\ncloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4=\ncloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=\ncloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=\ncloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM=\ncloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c=\ncloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=\ncloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=\ncloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g=\ncloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4=\ncloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs=\ncloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww=\ncloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c=\ncloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s=\ncloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI=\ncloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ=\ncloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=\ncloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=\ncloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=\ncloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek=\ncloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0=\ncloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM=\ncloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4=\ncloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE=\ncloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM=\ncloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q=\ncloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4=\ncloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=\ncloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=\ncloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k=\ncloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4=\ncloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM=\ncloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs=\ncloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=\ncloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=\ncloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE=\ncloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=\ncloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=\ncloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc=\ncloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY=\ncloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=\ncloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI=\ncloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8=\ncloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M=\ncloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc=\ncloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw=\ncloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw=\ncloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY=\ncloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w=\ncloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=\ncloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs=\ncloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=\ncloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=\ncloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=\ncloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY=\ncloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08=\ncloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw=\ncloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA=\ncloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c=\ncloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=\ncloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=\ncloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w=\ncloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM=\ncloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0=\ncloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60=\ncloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo=\ncloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg=\ncloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=\ncloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=\ncloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw=\ncloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=\ncloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=\ncloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E=\ncloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw=\ncloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA=\ncloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI=\ncloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y=\ncloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=\ncloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM=\ncloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o=\ncloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo=\ncloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=\ncloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=\ncloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=\ncloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc=\ncloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=\ncloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=\ncloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY=\ncloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=\ncloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=\ncloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=\ncloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=\ncloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=\ncloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=\ncloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk=\ncloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo=\ncloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74=\ncloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=\ncloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY=\ncloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4=\ncloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs=\ncloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g=\ncloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o=\ncloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE=\ncloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=\ncloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=\ncloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=\ncloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg=\ncloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w=\ncloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24=\ncloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI=\ncloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=\ncloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=\ncloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=\ncloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8=\ncloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY=\ncloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=\ncloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=\ncloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo=\ncloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw=\ncloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=\ncloud.google.com/go/logging v1.13.2 h1:qqlHCBvieJT9Cdq4QqYx1KPadCQ2noD4FK02eNqHAjA=\ncloud.google.com/go/logging v1.13.2/go.mod h1:zaybliM3yun1J8mU2dVQ1/qDzjbOqEijZCn6hSBtKak=\ncloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE=\ncloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=\ncloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=\ncloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8=\ncloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk=\ncloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE=\ncloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM=\ncloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA=\ncloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI=\ncloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw=\ncloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY=\ncloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=\ncloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=\ncloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I=\ncloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=\ncloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=\ncloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA=\ncloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY=\ncloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM=\ncloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=\ncloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=\ncloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8=\ncloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI=\ncloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo=\ncloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk=\ncloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=\ncloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=\ncloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw=\ncloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=\ncloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=\ncloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=\ncloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=\ncloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=\ncloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8=\ncloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E=\ncloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM=\ncloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8=\ncloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4=\ncloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY=\ncloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=\ncloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=\ncloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k=\ncloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU=\ncloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=\ncloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=\ncloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA=\ncloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0=\ncloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE=\ncloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ=\ncloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4=\ncloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs=\ncloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI=\ncloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA=\ncloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk=\ncloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ=\ncloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE=\ncloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc=\ncloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc=\ncloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=\ncloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=\ncloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo=\ncloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw=\ncloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw=\ncloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=\ncloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=\ncloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70=\ncloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo=\ncloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs=\ncloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=\ncloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=\ncloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk=\ncloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg=\ncloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE=\ncloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw=\ncloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc=\ncloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=\ncloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=\ncloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg=\ncloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI=\ncloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0=\ncloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8=\ncloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4=\ncloud.google.com/go/pubsub/v2 v2.4.0 h1:oMKNiBQpXImRWnHYla9uSU66ZzByZwBSCJOEs/pTKVg=\ncloud.google.com/go/pubsub/v2 v2.4.0/go.mod h1:2lS/XQKq5qtOMs6kHBK+WX1ytUC36kLl2ig3zqsGUx8=\ncloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg=\ncloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k=\ncloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM=\ncloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=\ncloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=\ncloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=\ncloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=\ncloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE=\ncloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U=\ncloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA=\ncloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c=\ncloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=\ncloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=\ncloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac=\ncloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=\ncloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=\ncloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs=\ncloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70=\ncloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ=\ncloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=\ncloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=\ncloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA=\ncloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM=\ncloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ=\ncloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA=\ncloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0=\ncloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots=\ncloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo=\ncloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=\ncloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU=\ncloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg=\ncloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA=\ncloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=\ncloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=\ncloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc=\ncloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y=\ncloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14=\ncloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do=\ncloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo=\ncloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM=\ncloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg=\ncloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=\ncloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=\ncloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk=\ncloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44=\ncloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc=\ncloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc=\ncloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=\ncloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4=\ncloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4=\ncloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=\ncloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=\ncloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=\ncloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=\ncloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q=\ncloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA=\ncloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8=\ncloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0=\ncloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=\ncloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=\ncloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk=\ncloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk=\ncloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0=\ncloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag=\ncloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU=\ncloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s=\ncloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA=\ncloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc=\ncloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk=\ncloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=\ncloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=\ncloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4=\ncloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U=\ncloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY=\ncloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s=\ncloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco=\ncloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo=\ncloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc=\ncloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4=\ncloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E=\ncloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU=\ncloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec=\ncloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA=\ncloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4=\ncloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw=\ncloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A=\ncloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos=\ncloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk=\ncloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M=\ncloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=\ncloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=\ncloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0=\ncloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco=\ncloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0=\ncloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ncloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=\ncloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=\ncloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=\ncloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=\ncloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=\ncloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=\ncloud.google.com/go/storage v1.61.3 h1:VS//ZfBuPGDvakfD9xyPW1RGF1Vy3BWUoVZXgW1KMOg=\ncloud.google.com/go/storage v1.61.3/go.mod h1:JtqK8BBB7TWv0HVGHubtUdzYYrakOQIsMLffZ2Z/HWk=\ncloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=\ncloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=\ncloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4=\ncloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw=\ncloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=\ncloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=\ncloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM=\ncloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA=\ncloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c=\ncloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8=\ncloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4=\ncloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc=\ncloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ=\ncloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg=\ncloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM=\ncloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28=\ncloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=\ncloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA=\ncloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk=\ncloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=\ncloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=\ncloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs=\ncloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg=\ncloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0=\ncloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=\ncloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=\ncloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk=\ncloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw=\ncloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg=\ncloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk=\ncloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=\ncloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=\ncloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=\ncloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=\ncloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M=\ncloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU=\ncloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU=\ncloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=\ncloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=\ncloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=\ncloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY=\ncloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E=\ncloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY=\ncloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0=\ncloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE=\ncloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g=\ncloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc=\ncloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY=\ncloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208=\ncloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8=\ncloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY=\ncloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w=\ncloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8=\ncloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes=\ncloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=\ncloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=\ncloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc=\ncloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A=\ncloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg=\ncloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo=\ncloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ=\ncloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng=\ncloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=\ncloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=\ncloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M=\ncloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA=\ncloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw=\ncode.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=\ncode.cloudfoundry.org/clock v1.2.0 h1:1swXS7yPmQmhAdkTb1nJ2c0geOdf4LvibUleNCo2HjA=\ncode.cloudfoundry.org/clock v1.2.0/go.mod h1:foDbmVp5RIuIGlota90ot4FkJtx5m4+oKoWiVuu2FDg=\ncollectd.org v0.6.0 h1:wDTcB13Zork7m9bEHmU2sVL4z+hxBmm8EyeMjjxtW7s=\ncollectd.org v0.6.0/go.mod h1:fXcRZb1qBKshIHJa2T8qBS7Xew/I43iMutefnTdGeYo=\ndario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=\ndario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\nfilippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=\nfilippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=\ngioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=\ngit.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=\ngithub.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=\ngithub.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=\ngithub.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=\ngithub.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=\ngithub.com/Azure/azure-amqp-common-go/v4 v4.2.0 h1:q/jLx1KJ8xeI8XGfkOWMN9XrXzAfVTkyvCxPvHCjd2I=\ngithub.com/Azure/azure-amqp-common-go/v4 v4.2.0/go.mod h1:GD3m/WPPma+621UaU6KNjKEo5Hl09z86viKwQjTpV0Q=\ngithub.com/Azure/azure-event-hubs-go/v3 v3.6.2 h1:7rNj1/iqS/i3mUKokA2n2eMYO72TB7lO7OmpbKoakKY=\ngithub.com/Azure/azure-event-hubs-go/v3 v3.6.2/go.mod h1:n+ocYr9j2JCLYqUqz9eI+lx/TEAtL/g6rZzyTFSuIpc=\ngithub.com/Azure/azure-kusto-go v0.16.1 h1:vCBWcQghmC1qIErUUgVNWHxGhZVStu1U/hki6iBA14k=\ngithub.com/Azure/azure-kusto-go v0.16.1/go.mod h1:9F2zvXH8B6eWzgI1S4k1ZXAIufnBZ1bv1cW1kB1n3D0=\ngithub.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=\ngithub.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=\ngithub.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=\ngithub.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=\ngithub.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=\ngithub.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0 h1:NnE8y/opvxowwNcSNHubQUiSSEhfk3dmooLGAOmPuKs=\ngithub.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0/go.mod h1:GhHzPHiiHxZloo6WvKu9X7krmSAKTyGoIwoKMbrKTTA=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=\ngithub.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.0 h1:skbmKp8umb8jMxl4A4CwvYyfCblujU00XUB/ytUjEac=\ngithub.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.0/go.mod h1:nynTZqX7jGM6FQy6Y+7uFT7Y+LhaAeO3q3d48VZzH5E=\ngithub.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs/v2 v2.0.2 h1:EBiOwZYJUMsjLGJ9x0oNY6ADf+5915P/jhhVcn42KXc=\ngithub.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs/v2 v2.0.2/go.mod h1:NjuxmUsBJ0Ya9Xxjhjo06bj3/QB4C8z838I5S88UtQQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub v1.3.0 h1:4hGvxD72TluuFIXVr8f4XkKZfqAa7Pj61t0jmQ7+kes=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub v1.3.0/go.mod h1:TSH7DcFItwAufy0Lz+Ft2cyopExCpxbOxI5SkH4dRNo=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0 h1:Ds0KRF8ggpEGg4Vo42oX1cIt/IfOhHWJBikksZbVxeg=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0/go.mod h1:jj6P8ybImR+5topJ+eH6fgcemSFBmU6/6bFF8KkwuDI=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=\ngithub.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLBGeVB5f2MdcIVD3ELVAWpr+WD6MUe1i+tM/PA=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0 h1:mJVYrRyo7/ISs3MLMHphqssqbS1vLJ3uiwo1+fY8OUQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0/go.mod h1:QXy84HaR0FHLPWaGQDBrZZbdCPTshwGl3gQ64uR/Zrc=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1 h1:qvrrnQ2mIjwY7IVlQuNB0ma43Nr74+9ZTZJ60KlmlV4=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1/go.mod h1:FkF/Az07vR3S4sBdjCuisznWfFWOD8u6Ibm/g/oyDAk=\ngithub.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe h1:HGuouUM1533rBXmMtR7qh5pYNSSjUZG90b/MgJAnb/A=\ngithub.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe/go.mod h1:K6am8mT+5iFXgingS9LUc7TmbsW6XBw3nxaRyaMyWc8=\ngithub.com/Azure/go-amqp v1.5.0 h1:GRiQK1VhrNFbyx5VlmI6BsA1FCp27W5rb9kxOZScnTo=\ngithub.com/Azure/go-amqp v1.5.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=\ngithub.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=\ngithub.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=\ngithub.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=\ngithub.com/Azure/go-autorest/autorest v0.11.30 h1:iaZ1RGz/ALZtN5eq4Nr1SOFSlf2E4pDI3Tcsl+dZPVE=\ngithub.com/Azure/go-autorest/autorest v0.11.30/go.mod h1:t1kpPIOpIVX7annvothKvb0stsrXa37i7b+xpmBW8Fs=\ngithub.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=\ngithub.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=\ngithub.com/Azure/go-autorest/autorest/adal v0.9.24 h1:BHZfgGsGwdkHDyZdtQRQk1WeUdW0m2WPAwuHZwUi5i4=\ngithub.com/Azure/go-autorest/autorest/adal v0.9.24/go.mod h1:7T1+g0PYFmACYW5LlG2fcoPiPlFHjClyRGL7dRlP5c8=\ngithub.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM=\ngithub.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo=\ngithub.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc=\ngithub.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=\ngithub.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=\ngithub.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=\ngithub.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=\ngithub.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=\ngithub.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=\ngithub.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=\ngithub.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=\ngithub.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=\ngithub.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=\ngithub.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=\ngithub.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=\ngithub.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=\ngithub.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=\ngithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=\ngithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=\ngithub.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=\ngithub.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=\ngithub.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/ClickHouse/ch-go v0.71.0 h1:bUdZ/EZj/LcVHsMqaRUP2holqygrPWQKeMjc6nZoyRM=\ngithub.com/ClickHouse/ch-go v0.71.0/go.mod h1:NwbNc+7jaqfY58dmdDUbG4Jl22vThgx1cYjBw0vtgXw=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.43.0 h1:fUR05TrF1GyvLDa/mAQjkx7KbgwdLRffs2n9O3WobtE=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.43.0/go.mod h1:o6jf7JM/zveWC/PP277BLxjHy5KjnGX/jfljhM4s34g=\ngithub.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=\ngithub.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/Files-com/files-sdk-go/v3 v3.2.97 h1:c+mQoiES/21JrHDAxJLCYICJO+bu8Clv0ZDNZe7Ndyk=\ngithub.com/Files-com/files-sdk-go/v3 v3.2.97/go.mod h1:Y/bCHoPJNPKz2hw1ADXjQXJP378HODwK+g/5SR2gqfU=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=\ngithub.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=\ngithub.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=\ngithub.com/IBM/nzgo/v12 v12.0.11 h1:FZb1zMT1yjjgSP2gqmi3Mk0ihSFvTlSJZ2/y6yJHphc=\ngithub.com/IBM/nzgo/v12 v12.0.11/go.mod h1:4pvfEkfsrAdqlljsp8HNwv/uzNKy2fzoXBB1aRIssJg=\ngithub.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318=\ngithub.com/IBM/sarama v1.47.0/go.mod h1:7gLLIU97nznOmA6TX++Qds+DRxH89P2XICY2KAQUzAY=\ngithub.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=\ngithub.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=\ngithub.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=\ngithub.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=\ngithub.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=\ngithub.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=\ngithub.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=\ngithub.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=\ngithub.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=\ngithub.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE=\ngithub.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=\ngithub.com/Mellanox/rdmamap v1.1.0 h1:A/W1wAXw+6vm58f3VklrIylgV+eDJlPVIMaIKuxgUT4=\ngithub.com/Mellanox/rdmamap v1.1.0/go.mod h1:fN+/V9lf10ABnDCwTaXRjeeWijLt2iVLETnK+sx/LY8=\ngithub.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=\ngithub.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=\ngithub.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/PaesslerAG/gval v1.2.4 h1:rhX7MpjJlcxYwL2eTTYIOBUyEKZ+A96T9vQySWkVUiU=\ngithub.com/PaesslerAG/gval v1.2.4/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=\ngithub.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI=\ngithub.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=\ngithub.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs69zUkSzubzjBbL+cmOXgnmt9Fyd9ug=\ngithub.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo=\ngithub.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e h1:lCsqUUACrcMC83lg5rTo9Y0PnPItE61JSfvMyIcANwk=\ngithub.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=\ngithub.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=\ngithub.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=\ngithub.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=\ngithub.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=\ngithub.com/ProtonMail/gopenpgp/v2 v2.7.4 h1:Vz/8+HViFFnf2A6XX8JOvZMrA6F5puwNvvF21O1mRlo=\ngithub.com/ProtonMail/gopenpgp/v2 v2.7.4/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g=\ngithub.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=\ngithub.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=\ngithub.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=\ngithub.com/SAP/go-hdb v1.16.1 h1:mjVEhrtA712ySd7+0kP5Wm+t8G6lICLyiSho5K4eQ2U=\ngithub.com/SAP/go-hdb v1.16.1/go.mod h1:LNpXz+MoCtka8RqefdbjwXXCXpqngFcsF3qpARsCR3U=\ngithub.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 h1:hhdWprfSpFbN7lz3W1gM40vOgvSh1WCSMxYD6gGB4Hs=\ngithub.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3/go.mod h1:XaUnRxSCYgL3kkgX0QHIV0D+znljPIDImxlv2kbGv0Y=\ngithub.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=\ngithub.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=\ngithub.com/aerospike/aerospike-client-go/v5 v5.11.0 h1:z3ZmDSm3I10VMXXIIrsFCFq3IenwFqTCnLNyvnFVzrk=\ngithub.com/aerospike/aerospike-client-go/v5 v5.11.0/go.mod h1:e/zYeIoBg9We63fLKa+h+198+fT1GdoLfKa+Pu4QSpg=\ngithub.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=\ngithub.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=\ngithub.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=\ngithub.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=\ngithub.com/alecthomas/go-thrift v0.0.0-20170109061633-7914173639b2/go.mod h1:CxCgO+NdpMdi9SsTlGbc0W+/UNxO3I0AabOEJZ3w61w=\ngithub.com/alecthomas/kong v0.2.1/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=\ngithub.com/alecthomas/participle v0.4.1 h1:P2PJWzwrSpuCWXKnzqvw0b0phSfH1kJo4p2HvLynVsI=\ngithub.com/alecthomas/participle v0.4.1/go.mod h1:T8u4bQOSMwrkTWOSyt8/jSFPEnRtd0FKFMjVfYBlqPs=\ngithub.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=\ngithub.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=\ngithub.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=\ngithub.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=\ngithub.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=\ngithub.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs=\ngithub.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=\ngithub.com/alitto/pond/v2 v2.7.0 h1:c76L+yN916m/DRXjGCeUBHHu92uWnh/g1bwVk4zyyXg=\ngithub.com/alitto/pond/v2 v2.7.0/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.63.107 h1:qagvUyrgOnBIlVRQWOyCZGVKUIYbMBdGdJ104vBpRFU=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.63.107/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=\ngithub.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9 h1:FXrPTd8Rdlc94dKccl7KPmdmIbVh/OjelJ8/vgMRzcQ=\ngithub.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9/go.mod h1:eliMa/PW+RDr2QLWRmLH1R1ZA4RInpmvOzDDXtaIZkc=\ngithub.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=\ngithub.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=\ngithub.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=\ngithub.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=\ngithub.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=\ngithub.com/antchfx/jsonquery v1.3.6 h1:TaSfeAh7n6T11I74bsZ1FswreIfrbJ0X+OyLflx6mx4=\ngithub.com/antchfx/jsonquery v1.3.6/go.mod h1:fGzSGJn9Y826Qd3pC8Wx45avuUwpkePsACQJYy+58BU=\ngithub.com/antchfx/xmlquery v1.5.0 h1:uAi+mO40ZWfyU6mlUBxRVvL6uBNZ6LMU4M3+mQIBV4c=\ngithub.com/antchfx/xmlquery v1.5.0/go.mod h1:lJfWRXzYMK1ss32zm1GQV3gMIW/HFey3xDZmkP1SuNc=\ngithub.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=\ngithub.com/antchfx/xpath v1.3.5/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=\ngithub.com/antchfx/xpath v1.3.6 h1:s0y+ElRRtTQdfHP609qFu0+c6bglDv20pqOViQjjdPI=\ngithub.com/antchfx/xpath v1.3.6/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op h1:kpBdlEPbRvff0mDD1gk7o9BhI16b9p5yYAXRlidpqJE=\ngithub.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E=\ngithub.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=\ngithub.com/apache/arrow-go/v18 v18.5.2 h1:3uoHjoaEie5eVsxx/Bt64hKwZx4STb+beAkqKOlq/lY=\ngithub.com/apache/arrow-go/v18 v18.5.2/go.mod h1:yNoizNTT4peTciJ7V01d2EgOkE1d0fQ1vZcFOsVtFsw=\ngithub.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=\ngithub.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=\ngithub.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=\ngithub.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=\ngithub.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang v1.0.7 h1:r1BYC/OGaKcav2llg5drf1ha1wL93LelKP2iPftI330=\ngithub.com/apache/inlong/inlong-sdk/dataproxy-sdk-twins/dataproxy-sdk-golang v1.0.7/go.mod h1:FUTK5FZpCPgoZbuPeIEOd5v+CzJ6dXl6rEORxMras14=\ngithub.com/apache/iotdb-client-go v1.3.5 h1:UHWXC/0GWMw/u7/yUK9XA8vCsQj+6zHsHA4CKRZZCdE=\ngithub.com/apache/iotdb-client-go v1.3.5/go.mod h1:3D6QYkqRmASS/4HsjU+U/3fscyc5M9xKRfywZsKuoZY=\ngithub.com/apache/thrift v0.15.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=\ngithub.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=\ngithub.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=\ngithub.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=\ngithub.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=\ngithub.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=\ngithub.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=\ngithub.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=\ngithub.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=\ngithub.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=\ngithub.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=\ngithub.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er+LKDHDUfU5tRvFwxH0LjPpZN8OoG8Ll+liGU=\ngithub.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A=\ngithub.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3 h1:Bmjk+DjIi3tTAU0wxGaFbfjGUqlxxSXARq9A96Kgoos=\ngithub.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA=\ngithub.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740 h1:FD4/ikKOFxwP8muWDypbmBWc634+YcAs3eBrYAmRdZY=\ngithub.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=\ngithub.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=\ngithub.com/awnumar/memcall v0.4.0 h1:B7hgZYdfH6Ot1Goaz8jGne/7i8xD4taZie/PNSFZ29g=\ngithub.com/awnumar/memcall v0.4.0/go.mod h1:8xOx1YbfyuCg3Fy6TO8DK0kZUua3V42/goA5Ru47E8w=\ngithub.com/awnumar/memguard v0.23.0 h1:sJ3a1/SWlcuKIQ7MV+R9p0Pvo9CWsMbGZvcZQtmc68A=\ngithub.com/awnumar/memguard v0.23.0/go.mod h1:olVofBrsPdITtJ2HgxQKrEYEMyIBAIciVG4wNnZhW9M=\ngithub.com/aws/aws-msk-iam-sasl-signer-go v1.0.4 h1:2jAwFwA0Xgcx94dUId+K24yFabsKYDtAhCgyMit6OqE=\ngithub.com/aws/aws-msk-iam-sasl-signer-go v1.0.4/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI=\ngithub.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=\ngithub.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=\ngithub.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=\ngithub.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=\ngithub.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA=\ngithub.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=\ngithub.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.11 h1:ftxI5sgz8jZkckuUHXfC/wMUc8u3fG1vQS0plr2F2Zs=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.11/go.mod h1:twF11+6ps9aNRKEDimksp923o44w/Thk9+8YIlzWMmo=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.11 h1:NdV8cwCcAXrCWyxArt58BrvZJ9pZ9Fhf9w6Uh5W3Uyc=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.11/go.mod h1:30yY2zqkMPdrvxBqzI9xQCM+WrlrZKSOpSJEsylVU+8=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 h1:INUvJxmhdEbVulJYHI061k4TVuS3jzzthNvjqvVvTKM=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19/go.mod h1:FpZN2QISLdEBWkayloda+sZjVJL+e9Gl0k1SyTgcswU=\ngithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43 h1:iLdpkYZ4cXIQMO7ud+cqMWR1xK5ESbt1rvN77tRi1BY=\ngithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43/go.mod h1:OgbsKPAswXDd5kxnR4vZov69p3oYjbvUyIRBAAV0y9o=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 h1:/sECfyq2JTifMI2JPyZ4bdRN77zJmr6SrS1eL3augIA=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19/go.mod h1:dMf8A5oAqr9/oxOfLkC/c2LU/uMcALP0Rgn2BD5LWn0=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJe6qZoRSJo0WfUhsMdUKhoODXE=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 h1:r67ps7oHCYnflpgDy2LZU0MAQtQbYIOqNNnqGO6xQkE=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25/go.mod h1:GrGY+Q4fIokYLtjCVB/aFfCVL6hhGUFl8inD18fDalE=\ngithub.com/aws/aws-sdk-go-v2/service/cloudwatch v1.55.1 h1:s+ZS2lmYFeCISy20RkSerTmfMIzxlevj4LyWNuE3cfY=\ngithub.com/aws/aws-sdk-go-v2/service/cloudwatch v1.55.1/go.mod h1:xXUsqpyas4oCIPxrKoCeqvyvFBLEYSohybRVV0bHq9A=\ngithub.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.64.0 h1:6QLwTAIR2z3QmYxuHM8nfZkW/C/qn4cvhesHIE98/CE=\ngithub.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.64.0/go.mod h1:RCkMRCGlsyFwF9Accj7GsHQFCIR9s8iRbv4LPYOT9wY=\ngithub.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1 h1:EkW4NqA2mwCkL7YCDYh6OpA/bCMhKYbZgpRHt2FD2Ow=\ngithub.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1/go.mod h1:OQp5333OH1IjmJmJpTU4IwoaOoCMnDrThg0zIx169rE=\ngithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.0 h1:776KnBqePBBR6zEDi0bUIHXzUBOISa2WgAKEgckUF8M=\ngithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.0/go.mod h1:rB577GvkmJADVOFGY8/j9sPv/ewcsEtQNsd9Lrn7Zx0=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6 h1:HCpPsWqmYQieU7SS6E9HXfdAMSud0pteVXieJmcpIRI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6/go.mod h1:ngUiVRCco++u+soRRVBIvBZxSMMvOVMXA4PJ36JLfSw=\ngithub.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19 h1:jdCj9vbCXwzTcIJX+MVd2UdssFhRJFTrWlPZwZB8Hpk=\ngithub.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19/go.mod h1:Dgg2d5WGRr7YB8JJsELskBxLUhgwWppXPwlvmuQKhbc=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7suZk9UCJHE1Iw9GMZJJl0dAnKXXP1NaSDHwmw=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 h1:BbGDtTi0T1DYlmjBiCr/le3wzhA37O8QTC5/Ab8+EXk=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6/go.mod h1:hLMJt7Q8ePgViKupeymbqI0la+t9/iYFBjxQCFwuAwI=\ngithub.com/aws/aws-sdk-go-v2/service/kinesis v1.43.2 h1:WhTMEbudr8A351zRMU48WLERglge1qMzmb6BrlbekPg=\ngithub.com/aws/aws-sdk-go-v2/service/kinesis v1.43.2/go.mod h1:yDk2FJbvOCzH16j8Pa2FLGKh8MEH6/8/2Vqn3IKzmXE=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPxhtt4DcBIHyCnmw=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.12/go.mod h1:fEWYKTRGoZNl8tZ77i61/ccwOMJdGxwOhWCkp6TXAr0=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 h1:EnUdUqRP1CNzt2DkV67tJx6XDN4xlfBFm+bzeNOQVb0=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16/go.mod h1:Jic/xv0Rq/pFNCh3WwpH4BEqdbSAl+IyHro8LbibHD8=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nniYPZnO1D4Np761Oo=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI=\ngithub.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.18 h1:DBfY5W2ToKP7un6+yGXASdYizVPmd/5MbbHsw9V5pxw=\ngithub.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.18/go.mod h1:lLyc9054UJfVChPbErlh151Zybxw/BdqPO0CyNmRaZE=\ngithub.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=\ngithub.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=\ngithub.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=\ngithub.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=\ngithub.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=\ngithub.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=\ngithub.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=\ngithub.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=\ngithub.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=\ngithub.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=\ngithub.com/bluenviron/gomavlib/v3 v3.3.0 h1:ul1yiDslfvsqCjLs+by1eSdU8Oud5qwemoO5ZBpX/fs=\ngithub.com/bluenviron/gomavlib/v3 v3.3.0/go.mod h1:pPrXt2HspzeIKNlvSDCrPzwPSLPDXORfhWJ8vT8zEKk=\ngithub.com/blues/jsonata-go v1.5.4 h1:XCsXaVVMrt4lcpKeJw6mNJHqQpWU751cnHdCFUq3xd8=\ngithub.com/blues/jsonata-go v1.5.4/go.mod h1:uns2jymDrnI7y+UFYCqsRTEiAH22GyHnNXrkupAVFWI=\ngithub.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=\ngithub.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=\ngithub.com/bmatcuk/doublestar/v3 v3.0.0 h1:TQtVPlDnAYwcrVNB2JiGuMc++H5qzWZd9PhkNo5WyHI=\ngithub.com/bmatcuk/doublestar/v3 v3.0.0/go.mod h1:6PcTVMw80pCY1RVuoqu3V++99uQB3vsSYKPTd8AWA0k=\ngithub.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=\ngithub.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=\ngithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=\ngithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=\ngithub.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=\ngithub.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=\ngithub.com/boschrexroth/ctrlx-datalayer-golang v1.3.1 h1:7Se/SKFSyMfJh23QlebwmFJWku6ZAKNOgAWgOPWTfH0=\ngithub.com/boschrexroth/ctrlx-datalayer-golang v1.3.1/go.mod h1:i0ex6o3HhWHDSS0KEmRuHZOk3FVdJamzyk+tp3qmxkg=\ngithub.com/bradenaw/juniper v0.15.2 h1:0JdjBGEF2jP1pOxmlNIrPhAoQN7Ng5IMAY5D0PHMW4U=\ngithub.com/bradenaw/juniper v0.15.2/go.mod h1:UX4FX57kVSaDp4TPqvSjkAAewmRFAfXf27BOs5z9dq8=\ngithub.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=\ngithub.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=\ngithub.com/brutella/dnssd v1.2.14 h1:qLpTnRTm5peo2jA30hqMIbCuWn8x3sFg3e9o9ODOobw=\ngithub.com/brutella/dnssd v1.2.14/go.mod h1:tG4GE8orv6+irE5rdsNgb6MJSxm6cyMUKdC5jmD22gk=\ngithub.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=\ngithub.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=\ngithub.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=\ngithub.com/buengese/sgzip v0.1.1 h1:ry+T8l1mlmiWEsDrH/YHZnCVWD2S3im1KLsyO+8ZmTU=\ngithub.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzOS8VMas=\ngithub.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=\ngithub.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=\ngithub.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=\ngithub.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=\ngithub.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds=\ngithub.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI=\ngithub.com/caio/go-tdigest/v4 v4.0.1 h1:sx4ZxjmIEcLROUPs2j1BGe2WhOtHD6VSe6NNbBdKYh4=\ngithub.com/caio/go-tdigest/v4 v4.0.1/go.mod h1:Wsa+f0EZnV2gShdj1adgl0tQSoXRxtM0QioTgukFw8U=\ngithub.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo=\ngithub.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI=\ngithub.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=\ngithub.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=\ngithub.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=\ngithub.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=\ngithub.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 h1:z0uK8UQqjMVYzvk4tiiu3obv2B44+XBsvgEJREQfnO8=\ngithub.com/chilts/sid v0.0.0-20190607042430-660e94789ec9/go.mod h1:Jl2neWsQaDanWORdqZ4emBl50J4/aRBBS4FyyG9/PFo=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=\ngithub.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df h1:GmrltUp5Qf5XhT+LmqMDizsgm/6VHTSxPWRdrq21yRo=\ngithub.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df/go.mod h1:rJDd05J5hqWVU9MjJ+5jw1CuLn/jRhvU0xtFEzzqjwM=\ngithub.com/clarify/clarify-go v0.4.1 h1:T0ba573qXp4dkM1CbPimvku1lJKNyIC27bcGEOTGVfw=\ngithub.com/clarify/clarify-go v0.4.1/go.mod h1:iTdVABQ3Qu7JK9xhg+oOfhvxS4I5AP0bt9HJTlG/PPU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=\ngithub.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=\ngithub.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM=\ngithub.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg=\ngithub.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=\ngithub.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=\ngithub.com/cloudinary/cloudinary-go/v2 v2.9.0 h1:8C76QklmuV4qmKAC7cUnu9D68X9kCkFMuLspPikECCo=\ngithub.com/cloudinary/cloudinary-go/v2 v2.9.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo=\ngithub.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6 h1:mLY/79N73URZ2J/oRKTxmfhCgxThzBmjQ6XOjX5tYjI=\ngithub.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6/go.mod h1:0aLYPsmguHbok591y6hI5yAqU0drbUzrPEO10ZpgTTw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=\ngithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=\ngithub.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=\ngithub.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=\ngithub.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=\ngithub.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=\ngithub.com/colinmarc/hdfs/v2 v2.4.0 h1:v6R8oBx/Wu9fHpdPoJJjpGSUxo8NhHIwrwsfhFvU9W0=\ngithub.com/colinmarc/hdfs/v2 v2.4.0/go.mod h1:0NAO+/3knbMx6+5pCv+Hcbaz4xn/Zzbn9+WIib2rKVI=\ngithub.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ=\ngithub.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=\ngithub.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=\ngithub.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=\ngithub.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=\ngithub.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=\ngithub.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=\ngithub.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=\ngithub.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=\ngithub.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=\ngithub.com/coocood/freecache v1.2.5 h1:FmhRQ8cLLVq9zWhHVYODUEZ0xu6rTPrVeAnX1AEIf7I=\ngithub.com/coocood/freecache v1.2.5/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk=\ngithub.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=\ngithub.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=\ngithub.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=\ngithub.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=\ngithub.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk=\ngithub.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=\ngithub.com/couchbase/gomemcached v0.1.3 h1:HIc5qMYNbuhB7zNaiEtj61DCYkquAwrQlf64q7JzdEY=\ngithub.com/couchbase/gomemcached v0.1.3/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=\ngithub.com/couchbase/goutils v0.1.0 h1:0WLlKJilu7IBm98T8nS9+J36lBFVLRUSIUtyD/uWpAE=\ngithub.com/couchbase/goutils v0.1.0/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=\ngithub.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=\ngithub.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/creack/goselect v0.1.3 h1:MaGNMclRo7P2Jl21hBpR1Cn33ITSbKP6E49RtfblLKc=\ngithub.com/creack/goselect v0.1.3/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=\ngithub.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=\ngithub.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=\ngithub.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=\ngithub.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=\ngithub.com/cronokirby/saferith v0.33.0 h1:TgoQlfsD4LIwx71+ChfRcIpjkw+RPOapDEVxa+LhwLo=\ngithub.com/cronokirby/saferith v0.33.0/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA=\ngithub.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=\ngithub.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=\ngithub.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=\ngithub.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=\ngithub.com/datadope-io/go-zabbix/v2 v2.0.1 h1:kGlyzfFqbwhMph4Mo0hpYxxBHI14eHuV5TVy+7uNonE=\ngithub.com/datadope-io/go-zabbix/v2 v2.0.1/go.mod h1:hRbQWszykTUPoR6g5fJXfNwPFZpP3nDNSZ9HrEKuKCM=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/devigned/tab v0.1.1 h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA=\ngithub.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 h1:jk2z9emvvDmaTwTdVOvQCK3POtH6+fEvWUtqMBjvnq0=\ngithub.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6/go.mod h1:vumyuXRJJvjCdabRsu/BvoCirqGHC5bakkC9G0V3Mgw=\ngithub.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=\ngithub.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=\ngithub.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=\ngithub.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=\ngithub.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=\ngithub.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=\ngithub.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=\ngithub.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=\ngithub.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=\ngithub.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=\ngithub.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=\ngithub.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=\ngithub.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=\ngithub.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=\ngithub.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=\ngithub.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 h1:FT+t0UEDykcor4y3dMVKXIiWJETBpRgERYTGlmMd7HU=\ngithub.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5/go.mod h1:rSS3kM9XMzSQ6pw91Qgd6yB5jdt70N4OdtrAf74As5M=\ngithub.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9 h1:NAvZb7gqQfLSNBPzVsvI7eZMosXtg2g2kxXrei90CtU=\ngithub.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9/go.mod h1:glr97hP/JuXb+WMYCizc4PIFuzw1lCR97mwbe1VVXhQ=\ngithub.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=\ngithub.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo=\ngithub.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=\ngithub.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0 h1:wHGPJSXvwKQVf/XfhjUPyrhpcPKWNy8F3ikH+eiwoBg=\ngithub.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0/go.mod h1:PseHFo8Leko7J4A/TfZ6kkHdkzKBLUta6hRZR/OEbbc=\ngithub.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=\ngithub.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=\ngithub.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=\ngithub.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=\ngithub.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=\ngithub.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=\ngithub.com/echlebek/crock v1.0.1 h1:KbzamClMIfVIkkjq/GTXf+N16KylYBpiaTitO3f1ujg=\ngithub.com/echlebek/crock v1.0.1/go.mod h1:/kvwHRX3ZXHj/kHWJkjXDmzzRow54EJuHtQ/PapL/HI=\ngithub.com/echlebek/timeproxy v1.0.0 h1:V41/v8tmmMDNMA2GrBPI45nlXb3F7+OY+nJz1BqKsCk=\ngithub.com/echlebek/timeproxy v1.0.0/go.mod h1:0dg2Lnb8no/jFwoMQKMTU6iAivgoMptGqSTprhnrRtk=\ngithub.com/eclipse/paho.golang v0.23.0 h1:KHgl2wz6EJo7cMBmkuhpt7C576vP+kpPv7jjvSyR6Mk=\ngithub.com/eclipse/paho.golang v0.23.0/go.mod h1:nQRhTkoZv8EAiNs5UU0/WdQIx2NrnWUpL9nsGJTQN04=\ngithub.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE=\ngithub.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU=\ngithub.com/elastic/go-sysinfo v1.8.1 h1:4Yhj+HdV6WjbCRgGdZpPJ8lZQlXZLKDAeIkmQ/VRvi4=\ngithub.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM=\ngithub.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=\ngithub.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=\ngithub.com/emersion/go-message v0.18.0 h1:7LxAXHRpSeoO/Wom3ZApVZYG7c3d17yCScYce8WiXA8=\ngithub.com/emersion/go-message v0.18.0/go.mod h1:Zi69ACvzaoV/MBnrxfVBPV3xWEuCmC2nEN39oJF4B8A=\ngithub.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=\ngithub.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=\ngithub.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA=\ngithub.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=\ngithub.com/emiago/sipgo v1.2.1 h1:5JTwogbe3yQFA3sjBVueN2Q4WTU350tGeBwPYT8HMv0=\ngithub.com/emiago/sipgo v1.2.1/go.mod h1:DuwAxBZhKMqIzQFPGZb1MVAGU6Wuxj64oTOhd5dx/FY=\ngithub.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=\ngithub.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=\ngithub.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=\ngithub.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=\ngithub.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=\ngithub.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=\ngithub.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=\ngithub.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=\ngithub.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=\ngithub.com/facebook/time v0.0.0-20250903103710-a5911c32cdb9 h1:IghB0/AakzNKu4+KBY+RT7J4TiMXwmZ1DCzOTR+0wmQ=\ngithub.com/facebook/time v0.0.0-20250903103710-a5911c32cdb9/go.mod h1:bp0KsBqhjbum8LF5Canem6aGBHWk5EGZRRN7z3rMp0E=\ngithub.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=\ngithub.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=\ngithub.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4 h1:fP04zlkPjAGpsduG7xN3rRkxjAqkJaIQnnkNYYw/pAk=\ngithub.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4/go.mod h1:SBHk9aNQtiw4R4bEuzHjVmZikkUKCnO1v3lPQ21HZGk=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/flynn/noise v1.0.1 h1:vPp/jdQLXC6ppsXSj/pM3W1BIJ5FEHE2TulSJBpb43Y=\ngithub.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=\ngithub.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=\ngithub.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=\ngithub.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=\ngithub.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=\ngithub.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=\ngithub.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=\ngithub.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=\ngithub.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=\ngithub.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=\ngithub.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=\ngithub.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=\ngithub.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=\ngithub.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=\ngithub.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=\ngithub.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68=\ngithub.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo=\ngithub.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=\ngithub.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=\ngithub.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=\ngithub.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=\ngithub.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=\ngithub.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=\ngithub.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=\ngithub.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=\ngithub.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=\ngithub.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=\ngithub.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=\ngithub.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=\ngithub.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=\ngithub.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=\ngithub.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk=\ngithub.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=\ngithub.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=\ngithub.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=\ngithub.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=\ngithub.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=\ngithub.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=\ngithub.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=\ngithub.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=\ngithub.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=\ngithub.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=\ngithub.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=\ngithub.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=\ngithub.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=\ngithub.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=\ngithub.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=\ngithub.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=\ngithub.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=\ngithub.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=\ngithub.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=\ngithub.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=\ngithub.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=\ngithub.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=\ngithub.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=\ngithub.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=\ngithub.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=\ngithub.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=\ngithub.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=\ngithub.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=\ngithub.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=\ngithub.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=\ngithub.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=\ngithub.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=\ngithub.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=\ngithub.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=\ngithub.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=\ngithub.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=\ngithub.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=\ngithub.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=\ngithub.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=\ngithub.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=\ngithub.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4=\ngithub.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=\ngithub.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=\ngithub.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=\ngithub.com/go-stomp/stomp v2.1.4+incompatible h1:D3SheUVDOz9RsjVWkoh/1iCOwD0qWjyeTZMUZ0EXg2Y=\ngithub.com/go-stomp/stomp v2.1.4+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c=\ngithub.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=\ngithub.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=\ngithub.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=\ngithub.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=\ngithub.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=\ngithub.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=\ngithub.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=\ngithub.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/goburrow/modbus v0.1.0 h1:DejRZY73nEM6+bt5JSP6IsFolJ9dVcqxsYbpLbeW/ro=\ngithub.com/goburrow/modbus v0.1.0/go.mod h1:Kx552D5rLIS8E7TyUwQ/UdHEqvX5T8tyiGBTlzMcZBg=\ngithub.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd h1:qJthTC7IG7e/QYR4i2QHxcDmDdB72FXsaGo4CUQvsPo=\ngithub.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd/go.mod h1:sAiqG0nRVswsm1C97xsttiYCzSLBmUZ/VSlVLZJ8haA=\ngithub.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=\ngithub.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=\ngithub.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=\ngithub.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=\ngithub.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=\ngithub.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=\ngithub.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=\ngithub.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=\ngithub.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=\ngithub.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=\ngithub.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=\ngithub.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=\ngithub.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=\ngithub.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=\ngithub.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=\ngithub.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=\ngithub.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=\ngithub.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=\ngithub.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=\ngithub.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=\ngithub.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=\ngithub.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=\ngithub.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=\ngithub.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=\ngithub.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=\ngithub.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=\ngithub.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=\ngithub.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=\ngithub.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=\ngithub.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=\ngithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=\ngithub.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=\ngithub.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=\ngithub.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo=\ngithub.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw=\ngithub.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=\ngithub.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=\ngithub.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=\ngithub.com/google/gnxi v0.0.0-20231026134436-d82d9936af15 h1:EETGSLGKBReUUYZdztSp45EzTE6CHw2qMKIfyPrgp6c=\ngithub.com/google/gnxi v0.0.0-20231026134436-d82d9936af15/go.mod h1:w8XuCWhpJuVsGdFLU9bLN9CBLROXSDp9tO1SFgg2l+4=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=\ngithub.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=\ngithub.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=\ngithub.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=\ngithub.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=\ngithub.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=\ngithub.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=\ngithub.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=\ngithub.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=\ngithub.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=\ngithub.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20260202012954-cb029daf43ef h1:xpF9fUHpoIrrjX24DURVKiwHcFpw19ndIs+FwTSMbno=\ngithub.com/google/pprof v0.0.0-20260202012954-cb029daf43ef/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=\ngithub.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=\ngithub.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=\ngithub.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=\ngithub.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=\ngithub.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=\ngithub.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=\ngithub.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=\ngithub.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=\ngithub.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=\ngithub.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=\ngithub.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=\ngithub.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI=\ngithub.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE=\ngithub.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=\ngithub.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=\ngithub.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M=\ngithub.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME=\ngithub.com/gopcua/opcua v0.8.0 h1:nB9vDewEmuXmSQf1C9inCHPblFwsH21FeB2Kk6o6Y7U=\ngithub.com/gopcua/opcua v0.8.0/go.mod h1:Z6aellk0gIzznZd2UX+Syd/hUMBt65gRlTakpGo6se8=\ngithub.com/gophercloud/gophercloud/v2 v2.11.1 h1:jCs4vLH8sJgRqrPzqVfWgl7uI6JnIIlsgeIRM0uHjxY=\ngithub.com/gophercloud/gophercloud/v2 v2.11.1/go.mod h1:Rm0YvKQ4QYX2rY9XaDKnjRzSGwlG5ge4h6ABYnmkKQM=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=\ngithub.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorcon/rcon v1.4.0 h1:pYwZ8Rhcgfh/LhdPBncecuEo5thoFvPIuMSWovz1FME=\ngithub.com/gorcon/rcon v1.4.0/go.mod h1:M6v6sNmr/NET9YIf+2rq+cIjTBridoy62uzQ58WgC1I=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=\ngithub.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=\ngithub.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=\ngithub.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=\ngithub.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=\ngithub.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=\ngithub.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=\ngithub.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=\ngithub.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=\ngithub.com/gosnmp/gosnmp v1.43.2 h1:F9loz6uMCNtIQj0RNO5wz/mZ+FZt2WyNKJYOvw+Zosw=\ngithub.com/gosnmp/gosnmp v1.43.2/go.mod h1:smHIwoaqr1M+HTAEd7+mKkPs8lp3Lf/U+htPUql1Q3c=\ngithub.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7EAJ0BHIethd+J6LqxFNw5mSiI2bM=\ngithub.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=\ngithub.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18 h1:8V5xRtdD70kGC4/IHqFq+kcBSWr4k6nscAUgWwJ6A5k=\ngithub.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc=\ngithub.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa h1:Rsn6ARgNkXrsXJIzhkE4vQr5Gbx2LvtEMv4BJOK4LyU=\ngithub.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa/go.mod h1:kdOd86/VGFWRrtkNwf1MPk0u1gIjc4Y7R2j7nhwc7Rk=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=\ngithub.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=\ngithub.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=\ngithub.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358 h1:QmKzhYk6KMjUutu9Sy4DyOkRgj1Dv+iFnea4t8KrCZg=\ngithub.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358/go.mod h1:h40FJV0HuULqXSSKf7kfCbOxEcQAD74a5e2LC2+rYiQ=\ngithub.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=\ngithub.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/api v1.33.4 h1:AJkZp6qzgAYcMIU0+CjJ0Rb7+byfh0dazFK/gzlOcJk=\ngithub.com/hashicorp/consul/api v1.33.4/go.mod h1:BkH3WEUzsnWvJJaHoDqKqoe2Q2EIixx7Gjj6MTwYnOA=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/consul/sdk v0.17.2 h1:sC0jgNhJkZX3wo1DCrkG12r+1JlZQpWvk3AoL3yZE4Q=\ngithub.com/hashicorp/consul/sdk v0.17.2/go.mod h1:VjccKcw6YhMhjH84/ZhTXZ0OG4SUq+K25P6DiCV/Hvg=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=\ngithub.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=\ngithub.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=\ngithub.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=\ngithub.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=\ngithub.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=\ngithub.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=\ngithub.com/hashicorp/packer-plugin-sdk v0.3.2 h1:4Kqq7B8CRDMbfZmkloyz11t1hfqazJuBbW8ZFo4QlN4=\ngithub.com/hashicorp/packer-plugin-sdk v0.3.2/go.mod h1:XZRvL9kRqJJtB6rf9Lu2zWLJbf2/4ImWXDjp9O9UQGE=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=\ngithub.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=\ngithub.com/hashicorp/vault-client-go v0.4.3 h1:zG7STGVgn/VK6rnZc0k8PGbfv2x/sJExRKHSUg3ljWc=\ngithub.com/hashicorp/vault-client-go v0.4.3/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY=\ngithub.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0=\ngithub.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM=\ngithub.com/hashicorp/vault/api/auth/approle v0.11.0 h1:ViUvgqoSTqHkMi1L1Rr/LnQ+PWiRaGUBGvx4UPfmKOw=\ngithub.com/hashicorp/vault/api/auth/approle v0.11.0/go.mod h1:v8ZqBRw+GP264ikIw2sEBKF0VT72MEhLWnZqWt3xEG8=\ngithub.com/henrybear327/Proton-API-Bridge v1.0.0 h1:gjKAaWfKu++77WsZTHg6FUyPC5W0LTKWQciUm8PMZb0=\ngithub.com/henrybear327/Proton-API-Bridge v1.0.0/go.mod h1:gunH16hf6U74W2b9CGDaWRadiLICsoJ6KRkSt53zLts=\ngithub.com/henrybear327/go-proton-api v1.0.0 h1:zYi/IbjLwFAW7ltCeqXneUGJey0TN//Xo851a/BgLXw=\ngithub.com/henrybear327/go-proton-api v1.0.0/go.mod h1:w63MZuzufKcIZ93pwRgiOtxMXYafI8H74D77AxytOBc=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=\ngithub.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=\ngithub.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=\ngithub.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=\ngithub.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/influxdata/influxdb-observability/common v0.5.12 h1:4YwZ+vsodz6VfoiX+ZqVotmnyCa9vCCPksSBK/WLjBs=\ngithub.com/influxdata/influxdb-observability/common v0.5.12/go.mod h1:u+CABnGO/F1IK51pDlZQroh4+igJNo695XrbLGDBhVc=\ngithub.com/influxdata/influxdb-observability/influx2otel v0.5.12 h1:u0lNE3+63rILk4mtmCYsNyczH/1wEXnM+1aBzBe5akk=\ngithub.com/influxdata/influxdb-observability/influx2otel v0.5.12/go.mod h1:bM407XIJYnrJYJ9Q3q2ytDSOyFhiYmGm0Sz1Qf48RPk=\ngithub.com/influxdata/influxdb-observability/otel2influx v0.5.12 h1:t9gmVOOHbZyEAvIYSoO97Tde1KArVtiYdM0/0Dhmuio=\ngithub.com/influxdata/influxdb-observability/otel2influx v0.5.12/go.mod h1:YGsb8xYfjHvcr2y0+Nj7kOHMTw7fWDbAA4g/qJKkvaU=\ngithub.com/influxdata/line-protocol-corpus v0.0.0-20210519164801-ca6fa5da0184/go.mod h1:03nmhxzZ7Xk2pdG+lmMd7mHDfeVOYFyhOgwO61qWU98=\ngithub.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937 h1:MHJNQ+p99hFATQm6ORoLmpUCF7ovjwEFshs/NHzAbig=\ngithub.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937/go.mod h1:BKR9c0uHSmRgM/se9JhFHtTT7JTO67X23MtKMHtZcpo=\ngithub.com/influxdata/line-protocol/v2 v2.0.0-20210312151457-c52fdecb625a/go.mod h1:6+9Xt5Sq1rWx+glMgxhcg2c0DUaehK+5TDcPZ76GypY=\ngithub.com/influxdata/line-protocol/v2 v2.1.0/go.mod h1:QKw43hdUBg3GTk2iC3iyCxksNj7PX9aUSeYOYE/ceHY=\ngithub.com/influxdata/line-protocol/v2 v2.2.1 h1:EAPkqJ9Km4uAxtMRgUubJyqAr6zgWM0dznKMLRauQRE=\ngithub.com/influxdata/line-protocol/v2 v2.2.1/go.mod h1:DmB3Cnh+3oxmG6LOBIxce4oaL4CPj3OmMPgvauXh+tM=\ngithub.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a h1:IJBVizlP2eArwAurfli2Em5N7pTK1YCbDsdDtnou024=\ngithub.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a/go.mod h1:VeiWgI3qaGdJWust2fP27a6J+koITo/1c/UhxeOxgaM=\ngithub.com/influxdata/toml v0.0.0-20251106153700-c381e153d076 h1:FqEkdokbxeBpCtZix3tLcIu2/OClDLCoKlbKXFLOEwo=\ngithub.com/influxdata/toml v0.0.0-20251106153700-c381e153d076/go.mod h1:zApaNFpP/bTpQItGZNNUMISDMDAnTXu9UqJ4yT3ocz8=\ngithub.com/intel/iaevents v1.1.0 h1:FzxMBfXk/apG2EUXUCfaq3gUQ+q+TgZ1HNMjjUILUGE=\ngithub.com/intel/iaevents v1.1.0/go.mod h1:CyUUzXw0lHRCsmyyF7Pwco9Y7NiTNQUUlcJ7RJAazKs=\ngithub.com/intel/powertelemetry v1.0.2 h1:092xOflYu+YXzY3c/fQ2DpK1ePy9q9ulbm5yiNYrVkc=\ngithub.com/intel/powertelemetry v1.0.2/go.mod h1:+PHKI9RElL7J1sTjgg3DGxtscD+IiLNmUzV1MOSCZt4=\ngithub.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=\ngithub.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=\ngithub.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=\ngithub.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=\ngithub.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=\ngithub.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=\ngithub.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=\ngithub.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=\ngithub.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=\ngithub.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=\ngithub.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=\ngithub.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=\ngithub.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=\ngithub.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=\ngithub.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=\ngithub.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=\ngithub.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=\ngithub.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=\ngithub.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=\ngithub.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=\ngithub.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=\ngithub.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=\ngithub.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=\ngithub.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=\ngithub.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=\ngithub.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=\ngithub.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=\ngithub.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=\ngithub.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=\ngithub.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=\ngithub.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=\ngithub.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=\ngithub.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=\ngithub.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=\ngithub.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=\ngithub.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=\ngithub.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=\ngithub.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=\ngithub.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=\ngithub.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=\ngithub.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=\ngithub.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=\ngithub.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=\ngithub.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=\ngithub.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=\ngithub.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=\ngithub.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=\ngithub.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=\ngithub.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=\ngithub.com/jaegertracing/jaeger v1.47.0 h1:XXxTMO+GxX930gxKWsg90rFr6RswkCRIW0AgWFnTYsg=\ngithub.com/jaegertracing/jaeger v1.47.0/go.mod h1:mHU/OHFML51CijQql4+rLfgPOcIb9MhxOMn+RKQwrJc=\ngithub.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=\ngithub.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=\ngithub.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=\ngithub.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=\ngithub.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=\ngithub.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=\ngithub.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=\ngithub.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=\ngithub.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=\ngithub.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=\ngithub.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=\ngithub.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=\ngithub.com/jedib0t/go-pretty/v6 v6.7.8 h1:BVYrDy5DPBA3Qn9ICT+PokP9cvCv1KaHv2i+Hc8sr5o=\ngithub.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=\ngithub.com/jeremija/gosubmit v0.2.8 h1:mmSITBz9JxVtu8eqbN+zmmwX7Ij2RidQxhcwRVI4wqA=\ngithub.com/jeremija/gosubmit v0.2.8/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI=\ngithub.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4 h1:eA9wi6ZzpIRobvXkn/S2Lyw1hr2pc71zxzOPl7Xjs4w=\ngithub.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4/go.mod h1:s9g9Dfls+aEgucKXKW+i8MRZuLXT2MrD/WjYpMnWfOw=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3 h1:ZxO6Qr2GOXPdcW80Mcn3nemvilMPvpWqxrNfK2ZnNNs=\ngithub.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3/go.mod h1:dvLUr/8Fs9a2OBrEnCC5duphbkz/k/mSy5OkXg3PAgI=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=\ngithub.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=\ngithub.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=\ngithub.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=\ngithub.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=\ngithub.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=\ngithub.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=\ngithub.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=\ngithub.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7 h1:JcltaO1HXM5S2KYOYcKgAV7slU0xPy1OcvrVgn98sRQ=\ngithub.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7/go.mod h1:MEkhEPFwP3yudWO0lj6vfYpLIB+3eIcuIW+e0AZzUQk=\ngithub.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg=\ngithub.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c=\ngithub.com/karrick/godirwalk v1.16.2 h1:eY2INUWoB2ZfpF/kXasyjWJ3Ncuof6qZuNWYZFN3kAI=\ngithub.com/karrick/godirwalk v1.16.2/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=\ngithub.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=\ngithub.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=\ngithub.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=\ngithub.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=\ngithub.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=\ngithub.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=\ngithub.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=\ngithub.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=\ngithub.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=\ngithub.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 h1:CjEMN21Xkr9+zwPmZPaJJw+apzVbjGL5uK/6g9Q2jGU=\ngithub.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988/go.mod h1:/agobYum3uo/8V6yPVnq+R82pyVGCeuWW5arT4Txn8A=\ngithub.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 h1:FHVoZMOVRA+6/y4yRlbiR3WvsrOcKBd/f64H7YiWR2U=\ngithub.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6/go.mod h1:MRAz4Gsxd+OzrZ0owwrUHc0zLESL+1Y5syqK/sJxK2A=\ngithub.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4=\ngithub.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U=\ngithub.com/leodido/go-syslog/v4 v4.3.0 h1:bbSpI/41bYK9iSdlYzcwvlxuLOE8yi4VTFmedtnghdA=\ngithub.com/leodido/go-syslog/v4 v4.3.0/go.mod h1:eJ8rUfDN5OS6dOkCOBYlg2a+hbAg6pJa99QXXgMrd98=\ngithub.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0=\ngithub.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=\ngithub.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/likexian/gokit v0.25.16 h1:wwBeUIN/OdoPp6t00xTnZE8Di/+s969Bl5N2Kw6bzP8=\ngithub.com/likexian/gokit v0.25.16/go.mod h1:Wqd4f+iifV0qxA1N3MqePJTUsmRy/lpst9/yXriDx/4=\ngithub.com/likexian/whois v1.15.7 h1:sajjDhi2bVD71AHJhjV7jLYxN92H4AWhTwxM8hmj7c0=\ngithub.com/likexian/whois v1.15.7/go.mod h1:kdPQtYb+7SQVftBEbCblDadUkycN7Mg1k1/Li/rwvmc=\ngithub.com/likexian/whois-parser v1.24.21 h1:MxsrGRxDOiZIVp7q7N/yAIbKuN4QAkGjCpOtTDA5OsM=\ngithub.com/likexian/whois-parser v1.24.21/go.mod h1:o3DUruO65Pb8WXCJCTlSVkTbwuYVrBCeoMTw2q0mxY4=\ngithub.com/linkedin/goavro/v2 v2.15.0 h1:pDj1UrjUOO62iXhgBiE7jQkpNIc5/tA5eZsgolMjgVI=\ngithub.com/linkedin/goavro/v2 v2.15.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk=\ngithub.com/logzio/azure-monitor-metrics-receiver v1.1.0 h1:L2LU/jWTOFibZeSKUeEDBdPY6iFL1gkSE3A/9mnk/Ms=\ngithub.com/logzio/azure-monitor-metrics-receiver v1.1.0/go.mod h1:6J/ZJtFGAuv3XvLWOWTefbi1BBHvnawNjUTGcx2qUG4=\ngithub.com/loov/hrtime v1.0.1/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0=\ngithub.com/loov/hrtime v1.0.3/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0=\ngithub.com/loov/hrtime/hrplot v1.0.2/go.mod h1:9t65xYn4d42ntjv40Wt5lbU72/VC5S0zGDgjC8kD5BU=\ngithub.com/loov/plot v0.0.0-20200413101321-e09a6f01d2f5/go.mod h1:gSrhfSMoiPGG0CZ9E66kXjaHxFw0fzJhooyicOnz5z4=\ngithub.com/lpar/date v1.0.0 h1:bq/zVqFTUmsxvd/CylidY4Udqpr9BOFrParoP6p0x/I=\ngithub.com/lpar/date v1.0.0/go.mod h1:KjYe0dDyMQTgpqcUz4LEIeM5VZwhggjVx/V2dtc8NSo=\ngithub.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=\ngithub.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=\ngithub.com/lxc/incus/v6 v6.22.0 h1:/r6SPAczA4ICaSxYD/5wgdKWxbKCiY8TP+vW9aip2kM=\ngithub.com/lxc/incus/v6 v6.22.0/go.mod h1:I47u8wLmRKdYitDpOAD3I2xuuUfT3bHT8fp8Ybjg51U=\ngithub.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=\ngithub.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=\ngithub.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=\ngithub.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=\ngithub.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=\ngithub.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=\ngithub.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo=\ngithub.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=\ngithub.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a h1:JOlLsLUQnokTyWWwEvOVoKH3XUl6oDMP8jisO54l6J8=\ngithub.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a/go.mod h1:960H6oqSawdujauTeLX9BOx+ZdYX0TdG9xE9br5bino=\ngithub.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=\ngithub.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE=\ngithub.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=\ngithub.com/mdlayher/genetlink v1.1.0/go.mod h1:1cAHdejIIk9zbWfP3gW30vY1QUlwyuhaqfkyANVVf10=\ngithub.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU=\ngithub.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=\ngithub.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=\ngithub.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=\ngithub.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=\ngithub.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=\ngithub.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=\ngithub.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=\ngithub.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=\ngithub.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=\ngithub.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=\ngithub.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=\ngithub.com/mdlayher/netlink v1.4.2/go.mod h1:13VaingaArGUTUxFLf/iEovKxXji32JAtF858jZYEug=\ngithub.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=\ngithub.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=\ngithub.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=\ngithub.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=\ngithub.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=\ngithub.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=\ngithub.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=\ngithub.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=\ngithub.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=\ngithub.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=\ngithub.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc=\ngithub.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY=\ngithub.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U=\ngithub.com/microsoft/go-mssqldb v1.9.8 h1:d4IFMvF/o+HdpXUqbBfzHvn/NlFA75YGcfHUUvDFJEM=\ngithub.com/microsoft/go-mssqldb v1.9.8/go.mod h1:eGSRSGAW4hKMy5YcAenhCDjIRm2rhqIdmmwgciMzLus=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=\ngithub.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=\ngithub.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=\ngithub.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=\ngithub.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=\ngithub.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=\ngithub.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=\ngithub.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=\ngithub.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=\ngithub.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=\ngithub.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk=\ngithub.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=\ngithub.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=\ngithub.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY=\ngithub.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=\ngithub.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=\ngithub.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=\ngithub.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=\ngithub.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=\ngithub.com/moby/ipvs v1.1.0/go.mod h1:4VJMWuf098bsUMmZEiD4Tjk/O7mOn3l1PTD3s4OoYAs=\ngithub.com/moby/moby v24.0.6+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=\ngithub.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=\ngithub.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=\ngithub.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=\ngithub.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=\ngithub.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=\ngithub.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=\ngithub.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=\ngithub.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=\ngithub.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=\ngithub.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=\ngithub.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=\ngithub.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=\ngithub.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=\ngithub.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=\ngithub.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=\ngithub.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=\ngithub.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=\ngithub.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=\ngithub.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=\ngithub.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=\ngithub.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=\ngithub.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=\ngithub.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=\ngithub.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=\ngithub.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=\ngithub.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=\ngithub.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY=\ngithub.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0=\ngithub.com/multiplay/go-ts3 v1.2.0 h1:LaN6iz9TZjHXxhLwfU0gjUgDxX0Hq7BCbuyuRhYMl3U=\ngithub.com/multiplay/go-ts3 v1.2.0/go.mod h1:OdNmiO3uV++4SldaJDQTIGg8gNAu5MOiccZiAqVqUZA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=\ngithub.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=\ngithub.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=\ngithub.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=\ngithub.com/nats-io/nats-server/v2 v2.12.5 h1:EOHLbsLJgUHUwzkj9gBTOlubkX+dmSs0EYWMdBiHivU=\ngithub.com/nats-io/nats-server/v2 v2.12.5/go.mod h1:JQDAKcwdXs0NRhvYO31dzsXkzCyDkOBS7SKU3Nozu14=\ngithub.com/nats-io/nats.go v1.49.0 h1:yh/WvY59gXqYpgl33ZI+XoVPKyut/IcEaqtsiuTJpoE=\ngithub.com/nats-io/nats.go v1.49.0/go.mod h1:fDCn3mN5cY8HooHwE2ukiLb4p4G4ImmzvXyJt+tGwdw=\ngithub.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=\ngithub.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=\ngithub.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=\ngithub.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=\ngithub.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=\ngithub.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=\ngithub.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=\ngithub.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=\ngithub.com/netsampler/goflow2/v2 v2.2.6 h1:pm+UEykIYV+lGJzrunYLNehoQtHlipJTp3lFhBpUkj0=\ngithub.com/netsampler/goflow2/v2 v2.2.6/go.mod h1:sKVfADpYP0NvkEeMRMh8/vz6T1yq4z1JZqO+N0+RGqk=\ngithub.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU=\ngithub.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=\ngithub.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=\ngithub.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=\ngithub.com/nwaples/tacplus v0.0.3 h1:i3v/BUWWrbKq00BzFDrgcPksUF4HwAWvS8Zk63ezYXg=\ngithub.com/nwaples/tacplus v0.0.3/go.mod h1:y5ZA9N5V2JbmwO766S+ET9zuu5FtL1OtdfBCYrbTIgw=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=\ngithub.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=\ngithub.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=\ngithub.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=\ngithub.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4=\ngithub.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U=\ngithub.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8=\ngithub.com/olivere/elastic/v7 v7.0.12/go.mod h1:14rWX28Pnh3qCKYRVnSGXWLf9MbLonYS/4FDCY3LAPo=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=\ngithub.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=\ngithub.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=\ngithub.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=\ngithub.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=\ngithub.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=\ngithub.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=\ngithub.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.101.0 h1:TCQYvGS2MKTotOTQDnHUSd4ljEzXRzHXopdv71giKWU=\ngithub.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.101.0/go.mod h1:Nl2d4DSK/IbaWnnBxYyhMNUW6C9sb5/4idVZrSW/5Ps=\ngithub.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.145.0 h1:sB4yuYx45zig1ceQ+kmrEYy0xMZ+mGagwYIFtJkkU1w=\ngithub.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.145.0/go.mod h1:uLhceuH7ZtiVxk+B0MHI0vhJG2Y4aOzT/hrV6c5KjVU=\ngithub.com/openconfig/gnmi v0.0.0-20200414194230-1597cc0f2600/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A=\ngithub.com/openconfig/gnmi v0.0.0-20200508230933-d19cebf5e7be/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A=\ngithub.com/openconfig/gnmi v0.0.0-20220503232738-6eb133c65a13/go.mod h1:h365Ifq35G6kLZDQlRvrccTt2LKK90VpjZLMNGxJRYc=\ngithub.com/openconfig/gnmi v0.14.1 h1:qKMuFvhIRR2/xxCOsStPQ25aKpbMDdWr3kI+nP9bhMs=\ngithub.com/openconfig/gnmi v0.14.1/go.mod h1:whr6zVq9PCU8mV1D0K9v7Ajd3+swoN6Yam9n8OH3eT0=\ngithub.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU=\ngithub.com/openconfig/goyang v0.2.2/go.mod h1:vX61x01Q46AzbZUzG617vWqh/cB+aisc+RrNkXRd3W8=\ngithub.com/openconfig/goyang v1.0.0/go.mod h1:vX61x01Q46AzbZUzG617vWqh/cB+aisc+RrNkXRd3W8=\ngithub.com/openconfig/goyang v1.6.3 h1:9nWXBwd6b4+nZr8ni7O4zUXVhrVMXCLFz8os5YWFuo4=\ngithub.com/openconfig/goyang v1.6.3/go.mod h1:5WolITjek1NF8yrNERyVZ7jqjOClJTpO8p/+OwmETM4=\ngithub.com/openconfig/gribi v0.1.1-0.20210423184541-ce37eb4ba92f/go.mod h1:OoH46A2kV42cIXGyviYmAlGmn6cHjGduyC2+I9d/iVs=\ngithub.com/openconfig/grpctunnel v0.0.0-20210610163803-fde4a9dc048d/go.mod h1:x9tAZ4EwqCQ0jI8D6S8Yhw9Z0ee7/BxWQX0k0Uib5Q8=\ngithub.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs=\ngithub.com/openconfig/ygot v0.10.4/go.mod h1:oCQNdXnv7dWc8scTDgoFkauv1wwplJn5HspHcjlxSAQ=\ngithub.com/openconfig/ygot v0.20.0/go.mod h1:7ZiBFNc4n/1Hkv2v2dAEpxisqDznp0JVpLR13Toe4AY=\ngithub.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=\ngithub.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=\ngithub.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=\ngithub.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=\ngithub.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=\ngithub.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=\ngithub.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=\ngithub.com/opencontainers/umoci v0.6.1-0.20251213054154-70fc5ee1f4df h1:9hvwN64VeuL1L0Jgp8bxTPmd5IZQoHmeXGWrVqsEhN0=\ngithub.com/opencontainers/umoci v0.6.1-0.20251213054154-70fc5ee1f4df/go.mod h1:s6d/s4QJAZTF92hEU6ozuHjE0+VRc6kVe1QIWfvL7KY=\ngithub.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsrZjibvB3APXf2a1VwCmMQ=\ngithub.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8=\ngithub.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=\ngithub.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=\ngithub.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=\ngithub.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10Siffyepr6SvlKbUsjH5JpNCRi8=\ngithub.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY=\ngithub.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=\ngithub.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=\ngithub.com/oracle/oci-go-sdk/v65 v65.80.0 h1:Rr7QLMozd2DfDBKo6AB3DzLYQxAwuOG118+K5AAD5E8=\ngithub.com/oracle/oci-go-sdk/v65 v65.80.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=\ngithub.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=\ngithub.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=\ngithub.com/p4lang/p4runtime v1.5.0 h1:GSccPwIFfeRjyrUSDe19DmqsHia7tGsU8vFuH2JxPTU=\ngithub.com/p4lang/p4runtime v1.5.0/go.mod h1:exHLJdkEhs+S2DLCkdvHnLbw9uyJoIbAzwMmHUeD37Y=\ngithub.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=\ngithub.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=\ngithub.com/panjf2000/gnet/v2 v2.9.7 h1:6zW7Jl3oAfXwSuh1PxHLndoL2MQRWx0AJR6aaQjxUgA=\ngithub.com/panjf2000/gnet/v2 v2.9.7/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=\ngithub.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=\ngithub.com/paulmach/orb v0.12.0 h1:z+zOwjmG3MyEEqzv92UN49Lg1JFYx0L9GpGKNVDKk1s=\ngithub.com/paulmach/orb v0.12.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=\ngithub.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=\ngithub.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 h1:2nosf3P75OZv2/ZO/9Px5ZgZ5gbKrzA3joN1QMfOGMQ=\ngithub.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ=\ngithub.com/pborman/ansi v1.0.0 h1:OqjHMhvlSuCCV5JT07yqPuJPQzQl+WXsiZ14gZsqOrQ=\ngithub.com/pborman/ansi v1.0.0/go.mod h1:SgWzwMAx1X/Ez7i90VqF8LRiQtx52pWDiQP+x3iGnzw=\ngithub.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=\ngithub.com/pcolladosoto/goslurm v0.1.0 h1:d2KigvDfsIIeVeHHj/pTtajz2T0cHHqhGk9iJWUdGaM=\ngithub.com/pcolladosoto/goslurm v0.1.0/go.mod h1:eLuBFfN/tj4O/HDMrAJXb+3s3rGhdHQVZFcOUV1Sbbo=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=\ngithub.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU=\ngithub.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=\ngithub.com/peterbourgon/ff/v3 v3.3.1/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=\ngithub.com/peterbourgon/unixtransport v0.0.7 h1:HhN7nydIDwlXWFzB6mbzQLcl46UdZLHrmF2lFfAgvnY=\ngithub.com/peterbourgon/unixtransport v0.0.7/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU=\ngithub.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=\ngithub.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=\ngithub.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=\ngithub.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=\ngithub.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=\ngithub.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=\ngithub.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=\ngithub.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc=\ngithub.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo=\ngithub.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=\ngithub.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=\ngithub.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so=\ngithub.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=\ngithub.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=\ngithub.com/pion/transport/v3 v3.0.6 h1:k1mQU06bmmX143qSWgXFqSH1KUJceQvIUuVH/K5ELWw=\ngithub.com/pion/transport/v3 v3.0.6/go.mod h1:HvJr2N/JwNJAfipsRleqwFoR3t/pWyHeZUs89v3+t5s=\ngithub.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o=\ngithub.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=\ngithub.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=\ngithub.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=\ngithub.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=\ngithub.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=\ngithub.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=\ngithub.com/prometheus-community/pro-bing v0.8.0 h1:CEY/g1/AgERRDjxw5P32ikcOgmrSuXs7xon7ovx6mNc=\ngithub.com/prometheus-community/pro-bing v0.8.0/go.mod h1:Idyxz8raDO6TgkUN6ByiEGvWJNyQd40kN9ZUeho3lN0=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_golang/exp v0.0.0-20260108101519-fb0838f53562 h1:vwqZvuobg82U0gcG2eVrFH27806bUbNr32SvfRbvdsg=\ngithub.com/prometheus/client_golang/exp v0.0.0-20260108101519-fb0838f53562/go.mod h1:PmAYDB13uBFBG9qE1qxZZgZWhg7Rg6SfKM5DMK7hjyI=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=\ngithub.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=\ngithub.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=\ngithub.com/prometheus/prometheus v0.310.0 h1:iS0Uul/dHjy8ifBnqo3YEOhRxlTOWantRoDWwmIowwA=\ngithub.com/prometheus/prometheus v0.310.0/go.mod h1:rs6XoWKvgAStqxHxb2Twh1BR6rp7qw7fmUgW+gaXjbw=\ngithub.com/prometheus/sigv4 v0.4.1 h1:EIc3j+8NBea9u1iV6O5ZAN8uvPq2xOIUPcqCTivHuXs=\ngithub.com/prometheus/sigv4 v0.4.1/go.mod h1:eu+ZbRvsc5TPiHwqh77OWuCnWK73IdkETYY46P4dXOU=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8=\ngithub.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU=\ngithub.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=\ngithub.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=\ngithub.com/rclone/rclone v1.69.3 h1:UbNEc7pVYDYhoMzlj9+NG/vYjDKI4SSQgZCsWeSYZng=\ngithub.com/rclone/rclone v1.69.3/go.mod h1:5ryHJK+Y28R7SXpYOWv0mP85Fh4kSh2fZWLN5oPuc8Q=\ngithub.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=\ngithub.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=\ngithub.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=\ngithub.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=\ngithub.com/relvacode/iso8601 v1.3.0 h1:HguUjsGpIMh/zsTczGN3DVJFxTU/GX+MMmzcKoMO7ko=\ngithub.com/relvacode/iso8601 v1.3.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=\ngithub.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4=\ngithub.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Nyk1k=\ngithub.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16 h1:bGXoxRwUpPTCaQ86DRE+3wqE9vh3aH8W0HH5L/ygOFM=\ngithub.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16/go.mod h1:4rS0vfmzOMwfFPhi6Zve4k/59TsBepqd6WESNULE0ho=\ngithub.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1 h1:YmFqprZILGlF/X3tvMA4Rwn3ySxyE3hGUajBHkkaZbM=\ngithub.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1/go.mod h1:pL1huxuIlWub46MsMVJg4p7OXkzbPp/APxh9IH0eJjQ=\ngithub.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=\ngithub.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=\ngithub.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=\ngithub.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=\ngithub.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846 h1:CnAbtX0j07ZVR/TnD5V6ypFTrASJlfr+fc4OY2da9eg=\ngithub.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846/go.mod h1:AMHIeh1KJ7Xa2RVOMHdv9jXKrpw0D4EWGGQMHLb2doc=\ngithub.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=\ngithub.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/rootless-containers/proto/go-proto v0.0.0-20260207013450-f6ee952d53d9 h1:3w2GInbYbp08pUeQoM3qI1L4v8htpwHQN9AkfILlUSw=\ngithub.com/rootless-containers/proto/go-proto v0.0.0-20260207013450-f6ee952d53d9/go.mod h1:LLjEAc6zmycfeN7/1fxIphWQPjHpTt7ElqT7eVf8e4A=\ngithub.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=\ngithub.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=\ngithub.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=\ngithub.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=\ngithub.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=\ngithub.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=\ngithub.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=\ngithub.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=\ngithub.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=\ngithub.com/safchain/ethtool v0.7.0 h1:rlJzfDetsVvT61uz8x1YIcFn12akMfuPulHtZjtb7Is=\ngithub.com/safchain/ethtool v0.7.0/go.mod h1:MenQKEjXdfkjD3mp2QdCk8B/hwvkrlOTm/FD4gTpFxQ=\ngithub.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=\ngithub.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=\ngithub.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=\ngithub.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=\ngithub.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3EXGI=\ngithub.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU=\ngithub.com/seancfoley/ipaddress-go v1.7.1 h1:fDWryS+L8iaaH5RxIKbY0xB5Z+Zxk8xoXLN4S4eAPdQ=\ngithub.com/seancfoley/ipaddress-go v1.7.1/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw=\ngithub.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=\ngithub.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=\ngithub.com/sensu/sensu-go/api/core/v2 v2.16.0 h1:HOq4rFkQ1S5ZjxmMTLc5J5mAbECrnKWvtXXbMqr3j9s=\ngithub.com/sensu/sensu-go/api/core/v2 v2.16.0/go.mod h1:MjM7+MCGEyTAgaZ589SiGHwYiaYF7N/58dU0J070u/0=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=\ngithub.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=\ngithub.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=\ngithub.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=\ngithub.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=\ngithub.com/showwin/speedtest-go v1.7.10 h1:9o5zb7KsuzZKn+IE2//z5btLKJ870JwO6ETayUkqRFw=\ngithub.com/showwin/speedtest-go v1.7.10/go.mod h1:Ei7OCTmNPdWofMadzcfgq1rUO7mvJy9Jycj//G7vyfA=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/signalfx/com_signalfx_metrics_protobuf v0.0.3 h1:32k2QLgsKhcEs55q4REPKyIadvid5FPy2+VMgvbmKJ0=\ngithub.com/signalfx/com_signalfx_metrics_protobuf v0.0.3/go.mod h1:gJrXWi7wSGXfiC7+VheQaz+ypdCt5SmZNL+BRxUe7y4=\ngithub.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083 h1:WsShHmu12ZztYPfh9b+I+VjYD1o8iOHhB67WZCMEEE8=\ngithub.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083/go.mod h1:adPDS6s7WaajdFBV9mQ7i0dKfQ8xiDnF9ZNETVPpp7c=\ngithub.com/signalfx/golib/v3 v3.3.54 h1:jUwTnaIXLHT0I1+hXoX0cPLdICIwBjB3e5/NGnnjgJY=\ngithub.com/signalfx/golib/v3 v3.3.54/go.mod h1:KDQZIYpJ3yXPz/KysPQQEYooWdpq4eQZPsjwKR5secc=\ngithub.com/signalfx/sapm-proto v0.12.0 h1:OtOe+Jm8L61Ml8K6X8a89zc8/RlaaMRElCImeGKR/Ew=\ngithub.com/signalfx/sapm-proto v0.12.0/go.mod h1:wQEki8RNCYjkv19jw5aWDcmDMTQru0ckfUbgHI69U2E=\ngithub.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg=\ngithub.com/sijms/go-ora/v2 v2.9.0/go.mod h1:QgFInVi3ZWyqAiJwzBQA+nbKYKH77tdp1PYoCqhR2dU=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=\ngithub.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=\ngithub.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=\ngithub.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=\ngithub.com/sleepinggenius2/gosmi v0.4.4 h1:xgu+Mt7CptuB10IPt3SVXBAA9tARToT4B9xGzjjxQX8=\ngithub.com/sleepinggenius2/gosmi v0.4.4/go.mod h1:l8OniPmd3bJzw0MXP2/qh7AhP/e+bTY2CNivIhsnDT0=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=\ngithub.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=\ngithub.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=\ngithub.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=\ngithub.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=\ngithub.com/smartystreets/gunit v1.1.3/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=\ngithub.com/snowflakedb/gosnowflake v1.19.0 h1:Oy/w5/hXiSJV09kgG9zpFZFjNRNvF5Cet7r6vzd87OQ=\ngithub.com/snowflakedb/gosnowflake v1.19.0/go.mod h1:7D4+cLepOWrerVsH+tevW3zdMJ5/WrEN7ZceAC6xBv0=\ngithub.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=\ngithub.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=\ngithub.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=\ngithub.com/spacemonkeygo/monkit/v3 v3.0.22 h1:4/g8IVItBDKLdVnqrdHZrCVPpIrwDBzl1jrV0IHQHDU=\ngithub.com/spacemonkeygo/monkit/v3 v3.0.22/go.mod h1:XkZYGzknZwkD0AKUnZaSXhRiVTLCkq7CWVa3IsE72gA=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=\ngithub.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=\ngithub.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=\ngithub.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=\ngithub.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=\ngithub.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=\ngithub.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=\ngithub.com/srebhan/cborquery v1.0.4 h1:R+PZ/ZKpgf2z0d9jkr2aCP53GI0PCC9Ibz8iqX/Pluk=\ngithub.com/srebhan/cborquery v1.0.4/go.mod h1:667M4EgeI9mJPFV5Mhyxg8rAuRO0SIIrgGtgZcFLqpE=\ngithub.com/srebhan/protobufquery v1.0.4 h1:MLMo7nS02HSwux538Id3SCkf/FShA4MK3pppc9U/acY=\ngithub.com/srebhan/protobufquery v1.0.4/go.mod h1:qMuAoKJAsVFYmyLE4H0dQ8F9+gBBHw+LBMqAZ326uA4=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002 h1:jevGbwKzMmHLgHAaDaMJLQX3jpXUWjUvnsrPeMgkM7o=\ngithub.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002/go.mod h1:0Mv/XWQoRWF7d7jkc4DufsAJQg8xyZ5NtCkY59wECQY=\ngithub.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62 h1:Oj2e7Sae4XrOsk3ij21QjjEgAcVSeo9nkp0dI//cD2o=\ngithub.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62/go.mod h1:qUzPVlSj2UgxJkVbH0ZwuuiR46U8RBMDT5KLY78Ifpw=\ngithub.com/tdrn-org/go-hue v0.3.0 h1:ywIlfTx9lcDp+n9XyGNY/9mUihW82lsWUanTzvdfeMc=\ngithub.com/tdrn-org/go-hue v0.3.0/go.mod h1:KUnPy2lGoP43ygNoCg6jVEhf8h5fpRn0Esjxq9syCnU=\ngithub.com/tdrn-org/go-nsdp v0.5.0 h1:bOs8qABaP/BSQlWeziZx9gjGkC2ld9UQek9p5w6PvdY=\ngithub.com/tdrn-org/go-nsdp v0.5.0/go.mod h1:zp7CxiCPcyXHo+s6tn+wrNBr1qQe1G/hOh/FybM5xiM=\ngithub.com/tdrn-org/go-tr064 v0.2.3 h1:hTKavfSTiUqmy02UvhHrvTQv6tTTkmGjYnOKv37br10=\ngithub.com/tdrn-org/go-tr064 v0.2.3/go.mod h1:3MAciJ87LZgVVkvl9Ns+dYAaS6oa5zEbyyL+T2a154E=\ngithub.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=\ngithub.com/testcontainers/testcontainers-go v0.41.0 h1:mfpsD0D36YgkxGj2LrIyxuwQ9i2wCKAD+ESsYM1wais=\ngithub.com/testcontainers/testcontainers-go v0.41.0/go.mod h1:pdFrEIfaPl24zmBjerWTTYaY0M6UHsqA1YSvsoU40MI=\ngithub.com/testcontainers/testcontainers-go/modules/azure v0.40.0 h1:a4Qn4UEgL3uzpY1Hhuzh2c87u/CuSoTaV12timQfHQU=\ngithub.com/testcontainers/testcontainers-go/modules/azure v0.40.0/go.mod h1:047cjSoIxghqTQt8OVeLwLO918jOTrRnKYSEG5L6paQ=\ngithub.com/testcontainers/testcontainers-go/modules/kafka v0.40.0 h1:BW4CMO6rYLvJRC7UF4l0rudnwm7IX/kJPvGd9MCJM6I=\ngithub.com/testcontainers/testcontainers-go/modules/kafka v0.40.0/go.mod h1:O4U0SUR8blhkRLLfIFHQqNRKzee7fOxzya2H+rnl4OY=\ngithub.com/testcontainers/testcontainers-go/modules/vault v0.41.0 h1:Hx5n69IeJBhMkiQ7V3RBCq1iPUrWCv+KEwZCjoWRc3Y=\ngithub.com/testcontainers/testcontainers-go/modules/vault v0.41.0/go.mod h1:dEQvxqPf62AIxEzymv+rD8+4A5TIvTA0/Etoh7csZbE=\ngithub.com/thomasklein94/packer-plugin-libvirt v0.5.0 h1:aj2HLHZZM/ClGLIwVp9rrgh+2TOU/w4EiaZHAwCpOgs=\ngithub.com/thomasklein94/packer-plugin-libvirt v0.5.0/go.mod h1:GwN82FQ6KxCNKtS8LNUgLbwTZs90GGhBzCmTNkrTCrY=\ngithub.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=\ngithub.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=\ngithub.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=\ngithub.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8=\ngithub.com/tidwall/tinylru v1.2.1 h1:VgBr72c2IEr+V+pCdkPZUwiQ0KJknnWIYbhxAVkYfQk=\ngithub.com/tidwall/tinylru v1.2.1/go.mod h1:9bQnEduwB6inr2Y7AkBP7JPgCkyrhTV/ZpX0oOOpBI4=\ngithub.com/tidwall/wal v1.2.1 h1:xQvwnRF3e+xBC4NvFvl1mPGJHU0aH5zNzlUKnKGIImA=\ngithub.com/tidwall/wal v1.2.1/go.mod h1:r6lR1j27W9EPalgHiB7zLJDYu3mzW5BQP5KrzBpYY/E=\ngithub.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=\ngithub.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=\ngithub.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=\ngithub.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=\ngithub.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=\ngithub.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc=\ngithub.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=\ngithub.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=\ngithub.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=\ngithub.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=\ngithub.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=\ngithub.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=\ngithub.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/twmb/murmur3 v1.1.7 h1:ULWBiM04n/XoN3YMSJ6Z2pHDFLf+MeIVQU71ZPrvbWg=\ngithub.com/twmb/murmur3 v1.1.7/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=\ngithub.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=\ngithub.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=\ngithub.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=\ngithub.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=\ngithub.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=\ngithub.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/unknwon/goconfig v1.0.0 h1:rS7O+CmUdli1T+oDm7fYj1MwqNWtEJfNj+FqcUHML8U=\ngithub.com/unknwon/goconfig v1.0.0/go.mod h1:qu2ZQ/wcC/if2u32263HTVC39PeOQRSmidQk3DuDFQ8=\ngithub.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ=\ngithub.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=\ngithub.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=\ngithub.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=\ngithub.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11 h1:YzrpNqpAuAgUQ0vseiI3mAVz7zr0rM5LWdaGCCr6Ipc=\ngithub.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11/go.mod h1:+iC7aAxEwuJ4mvdKaY0zCGT0dpIC/AtHt4yv2jr5FOo=\ngithub.com/vbatts/go-mtree v0.7.0 h1:ytmOc3MTRidZiBi9VBCyZ2BHe4fZS47L5v7BVXDWW4E=\ngithub.com/vbatts/go-mtree v0.7.0/go.mod h1:EjdpFC+LZy1TXbRGNa1MKKgjQ+7ew3foMFJK8o4/TdY=\ngithub.com/vertica/vertica-sql-go v1.3.5 h1:IrfH2WIgzZ45yDHyjVFrXU2LuKNIjF5Nwi90a6cfgUI=\ngithub.com/vertica/vertica-sql-go v1.3.5/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4=\ngithub.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=\ngithub.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=\ngithub.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=\ngithub.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=\ngithub.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=\ngithub.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=\ngithub.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=\ngithub.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo=\ngithub.com/vmware/govmomi v0.53.0 h1:e1bZCotAq7wm4xy95ePN2uoWwz28pNp/ewZZhpBY7/4=\ngithub.com/vmware/govmomi v0.53.0/go.mod h1:EWfuzPfxT5NV+aS2we02SLFdhvJkgeY7t7+TszgBSMY=\ngithub.com/wavefronthq/wavefront-sdk-go v0.15.0 h1:po9E3vh/0y7kOx8D9EtFp7kbSLLLKbmu/w/s1xGJAQU=\ngithub.com/wavefronthq/wavefront-sdk-go v0.15.0/go.mod h1:V72c8e+bXuLK8HpA6ioW0ll5mK9IPD+4IHNNDY75ksA=\ngithub.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=\ngithub.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=\ngithub.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=\ngithub.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=\ngithub.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=\ngithub.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=\ngithub.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=\ngithub.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=\ngithub.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=\ngithub.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=\ngithub.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=\ngithub.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=\ngithub.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=\ngithub.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw=\ngithub.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=\ngithub.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4=\ngithub.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=\ngithub.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=\ngithub.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=\ngithub.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=\ngithub.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=\ngithub.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=\ngithub.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=\ngithub.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=\ngithub.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=\ngithub.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=\ngithub.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=\ngithub.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=\ngithub.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=\ngithub.com/yunify/qingstor-sdk-go/v3 v3.2.0 h1:9sB2WZMgjwSUNZhrgvaNGazVltoFUUfuS9f0uCWtTr8=\ngithub.com/yunify/qingstor-sdk-go/v3 v3.2.0/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=\ngithub.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=\ngithub.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngithub.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=\ngithub.com/zeebo/assert v1.3.1 h1:vukIABvugfNMZMQO1ABsyQDJDTVQbn+LWSMy1ol1h6A=\ngithub.com/zeebo/assert v1.3.1/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=\ngithub.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=\ngithub.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=\ngithub.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=\ngithub.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=\ngithub.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=\ngithub.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=\ngithub.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=\ngithub.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=\ngithub.com/zentures/cityhash v0.0.0-20131128155616-cdd6a94144ab h1:BD4YbH4Y0ysgbrP9jGuDB0BxkqyTRk6Y70o3D5Z5ayc=\ngithub.com/zentures/cityhash v0.0.0-20131128155616-cdd6a94144ab/go.mod h1:SvJE1nX57VqPOyqkQGEGcJPWZqeB3FCZ8s7a0uSlG+A=\ngithub.com/zitadel/logging v0.7.0 h1:eugftwMM95Wgqwftsvj81isL0JK/hoScVqp/7iA2adQ=\ngithub.com/zitadel/logging v0.7.0/go.mod h1:9A6h9feBF/3u0IhA4uffdzSDY7mBaf7RE78H5sFMINQ=\ngithub.com/zitadel/oidc/v3 v3.45.4 h1:GKyWaPRVQ8sCu9XgJ3NgNGtG52FzwVJpzXjIUG2+YrI=\ngithub.com/zitadel/oidc/v3 v3.45.4/go.mod h1:XALmFXS9/kSom9B6uWin1yJ2WTI/E4Ti5aXJdewAVEs=\ngithub.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI=\ngithub.com/zitadel/schema v1.3.2/go.mod h1:IZmdfF9Wu62Zu6tJJTH3UsArevs3Y4smfJIj3L8fzxw=\ngo.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=\ngo.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=\ngo.einride.tech/aip v0.79.0 h1:19zdPlZzlUvxOA8syAFw4LkdJdXepzyTl6gt9XEeqdU=\ngo.einride.tech/aip v0.79.0/go.mod h1:E8+wdTApA70odnpFzJgsGogHozC2JCIhFJBKPr8bVig=\ngo.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=\ngo.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=\ngo.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc=\ngo.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=\ngo.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=\ngo.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU=\ngo.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=\ngo.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/collector v0.81.0 h1:pF+sB8xNXlg/W0a0QTLz4mUWyool1a9toVj8LmLoFqg=\ngo.opentelemetry.io/collector/consumer/consumererror v0.135.0 h1:OTu0rLPWxWc03sqeYHdWGJFUA3W2DfgC1sHLZx8NMXI=\ngo.opentelemetry.io/collector/consumer/consumererror v0.135.0/go.mod h1:eGPILc8iMAnunFz4vxxSsGQ4wx7/XdAYagfsmNLdSp0=\ngo.opentelemetry.io/collector/featuregate v1.53.0 h1:cgjXdtl7jezWxq6V0eohe/JqjY4PBotZGb5+bTR2OJw=\ngo.opentelemetry.io/collector/featuregate v1.53.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g=\ngo.opentelemetry.io/collector/internal/testutil v0.147.0 h1:DFlRxBRp23/sZnpTITK25yqe0d56yNvK+63IaWc6OsU=\ngo.opentelemetry.io/collector/internal/testutil v0.147.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=\ngo.opentelemetry.io/collector/pdata v1.53.0 h1:DlYDbRwammEZaxDZHINx5v0n8SEOVNniPbi6FRTlVkA=\ngo.opentelemetry.io/collector/pdata v1.53.0/go.mod h1:LRSYGNjKXaUrZEwZv3Yl+8/zV2HmRGKXW62zB2bysms=\ngo.opentelemetry.io/collector/pdata/pprofile v0.140.0 h1:b9TZ6UnyzsT/ERQw2VKGi/NYLtKSmjG7cgQuc9wZt5s=\ngo.opentelemetry.io/collector/pdata/pprofile v0.140.0/go.mod h1:/2s/YBWGbu+r8MuKu5zas08iSqe+3P6xnbRpfE2DWAA=\ngo.opentelemetry.io/collector/pdata/testdata v0.135.0 h1:bp+9wKAifJcoYdS+qTwtgcKPM129wIKLUGAAxKY4lck=\ngo.opentelemetry.io/collector/pdata/testdata v0.135.0/go.mod h1:w0gTft2xsn/adYgUGNBhDDjVhKCvvA9fHTKIbh7rx0o=\ngo.opentelemetry.io/collector/semconv v0.128.0 h1:MzYOz7Vgb3Kf5D7b49pqqgeUhEmOCuT10bIXb/Cc+k4=\ngo.opentelemetry.io/collector/semconv v0.128.0/go.mod h1:OPXer4l43X23cnjLXIZnRj/qQOjSuq4TgBLI76P9hns=\ngo.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE=\ngo.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=\ngo.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=\ngo.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk=\ngo.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=\ngo.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=\ngo.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=\ngo.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=\ngo.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=\ngo.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y=\ngo.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=\ngo.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=\ngo.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=\ngo.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=\ngo.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=\ngo.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0 h1:AWBLtJn3ajH399gyOuJdqPsC9w152x3xGVVO/UK3vyM=\ngo.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0/go.mod h1:kCdbxyM9kfmv3v4ZQzZ2pACxoQ6lE0IsjP+UcZwQnr4=\ngo.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 h1:ZQs05qo3Yh4KUHeVH6v89xErwmsvgA/cLX2/w5Ikp+k=\ngo.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0/go.mod h1:3iiRVKaCfVo0UI1ZaSMm5WbCBbINRqVlD9SUmvyBNrY=\ngo.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE=\ngo.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI=\ngo.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8=\ngo.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0/go.mod h1:Gyb6Xe7FTi/6xBHwMmngGoHqL0w29Y4eW8TGFzpefGA=\ngo.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 h1:EiUYvtwu6PMrMHVjcPfnsG3v+ajPkbUeH+IL93+QYyk=\ngo.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0/go.mod h1:mUUHKFiN2SST3AhJ8XhJxEoeVW12oqfXog0Bo8W3Ec4=\ngo.starlark.net v0.0.0-20260210143700-b62fd896b91b h1:mDO9/2PuBcapqFbhiCmFcEQZvlQnk3ILEZR+a8NL1z4=\ngo.starlark.net v0.0.0-20260210143700-b62fd896b91b/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=\ngo.step.sm/crypto v0.76.2 h1:JJ/yMcs/rmcCAwlo+afrHjq74XBFRTJw5B2y4Q4Z4c4=\ngo.step.sm/crypto v0.76.2/go.mod h1:m6KlB/HzIuGFep0UWI5e0SYi38UxpoKeCg6qUaHV6/Q=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=\ngo.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=\ngo.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=\ngolang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=\ngolang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=\ngolang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=\ngolang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=\ngolang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=\ngolang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=\ngolang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=\ngolang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=\ngolang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=\ngolang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=\ngolang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=\ngolang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=\ngolang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=\ngolang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=\ngolang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=\ngolang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=\ngolang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=\ngolang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=\ngolang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=\ngolang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=\ngolang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=\ngolang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=\ngolang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=\ngolang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=\ngolang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=\ngolang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=\ngolang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=\ngolang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=\ngolang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=\ngolang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=\ngolang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=\ngolang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=\ngolang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=\ngolang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=\ngolang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=\ngolang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=\ngolang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211214234402-4825e8c3871d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=\ngolang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0=\ngolang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548=\ngolang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=\ngolang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=\ngolang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=\ngolang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=\ngolang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=\ngolang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=\ngolang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=\ngolang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=\ngolang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=\ngolang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=\ngolang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=\ngolang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=\ngolang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=\ngolang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=\ngolang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=\ngolang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=\ngolang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=\ngolang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=\ngolang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=\ngolang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=\ngolang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=\ngolang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=\ngolang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=\ngolang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=\ngolang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=\ngolang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg=\ngolang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=\ngolang.zx2c4.com/wireguard v0.0.0-20211129173154-2dd424e2d808/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI=\ngolang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434 h1:3zl8RkJNQ8wfPRomwv/6DBbH2Ut6dgMaWTxM0ZunWnE=\ngolang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI=\ngolang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671 h1:tJAYx7pB6b5bNqi7XatStqFT2zFAxhXcGDq1R6FqqjU=\ngolang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671/go.mod h1:Q2XNgour4QSkFj0BWCkVlW0HWJwQgNMsMahpSlI0Eno=\ngonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=\ngonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=\ngonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=\ngonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=\ngonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=\ngonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=\ngonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=\ngonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=\ngoogle.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=\ngoogle.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=\ngoogle.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=\ngoogle.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=\ngoogle.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=\ngoogle.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=\ngoogle.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=\ngoogle.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=\ngoogle.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=\ngoogle.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=\ngoogle.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=\ngoogle.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=\ngoogle.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=\ngoogle.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=\ngoogle.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=\ngoogle.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=\ngoogle.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08=\ngoogle.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=\ngoogle.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo=\ngoogle.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=\ngoogle.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=\ngoogle.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=\ngoogle.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=\ngoogle.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=\ngoogle.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=\ngoogle.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=\ngoogle.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA=\ngoogle.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=\ngoogle.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=\ngoogle.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=\ngoogle.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=\ngoogle.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=\ngoogle.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=\ngoogle.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=\ngoogle.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=\ngoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=\ngoogle.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=\ngoogle.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=\ngoogle.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=\ngoogle.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=\ngoogle.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=\ngoogle.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=\ngoogle.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=\ngoogle.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=\ngoogle.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=\ngoogle.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=\ngoogle.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=\ngoogle.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=\ngoogle.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=\ngoogle.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=\ngoogle.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=\ngoogle.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=\ngoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d h1:vsOm753cOAMkt76efriTCDKjpCbK18XGHMJHo0JUKhc=\ngoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:0oz9d7g9QLSdv9/lgbIjowW1JoxMbxmBVNe8i6tORJI=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=\ngoogle.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=\ngoogle.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=\ngoogle.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=\ngoogle.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=\ngoogle.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=\ngoogle.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=\ngoogle.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=\ngopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=\ngopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg=\ngopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=\ngopkg.in/fsnotify.v1 v1.2.1/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU=\ngopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=\ngopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=\ngopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=\ngopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=\ngopkg.in/olivere/elastic.v5 v5.0.86 h1:xFy6qRCGAmo5Wjx96srho9BitLhZl2fcnpuidPwduXM=\ngopkg.in/olivere/elastic.v5 v5.0.86/go.mod h1:M3WNlsF+WhYn7api4D87NIflwTV/c0iVs8cqfWhK+68=\ngopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=\ngopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=\ngopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=\ngopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=\ngopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=\ngopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=\ngopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=\ngopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=\ngotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=\ngotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nhonnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=\nhonnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk=\nhonnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=\nhowett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=\nhowett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=\nk8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=\nk8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=\nk8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=\nk8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=\nk8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=\nk8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=\nk8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=\nk8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=\nk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=\nk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=\nk8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=\nk8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=\nlayeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 h1:2NDro2Jzkrqfngy/sA5GVnChs7fx8EzcQKFi/lI2cfg=\nlayeh.com/radius v0.0.0-20221205141417-e7fbddd11d68/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A=\nlukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=\nlukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=\nmodernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=\nmodernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=\nmodernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=\nmodernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=\nmodernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=\nmodernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=\nmodernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=\nmodernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=\nmodernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=\nmodernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws=\nmodernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=\nmodernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=\nmodernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=\nmodernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=\nmodernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=\nmodernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=\nmodernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=\nmodernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=\nmodernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=\nmodernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=\nmodernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=\nmodernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=\nmodernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=\nmodernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=\nmodernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=\nmodernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=\nmodernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=\nmodernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=\nmodernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=\nmodernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=\nmodernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=\nmodernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=\nmodernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=\nmodernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=\nmodernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=\nmodernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=\nmodernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=\nmodernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=\nmodernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=\nmodernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=\nmodernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=\nmodernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=\nmodernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=\nmodernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=\nmodernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=\nmodernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=\nmodernc.org/sqlite v1.46.2 h1:gkXQ6R0+AjxFC/fTDaeIVLbNLNrRoOK7YYVz5BKhTcE=\nmodernc.org/sqlite v1.46.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=\nmodernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=\nmodernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=\nmodernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=\nmodernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=\nmodernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=\nmodernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=\nmodernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=\nmodernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=\nmodernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=\nmoul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=\nmoul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=\npgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=\npgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\nsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=\nsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=\nsigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=\nsigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=\nsigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=\nsigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=\nsigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=\nsigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=\nsoftware.sslmate.com/src/go-pkcs12 v0.7.0 h1:Db8W44cB54TWD7stUFFSWxdfpdn6fZVcDl0w3R4RVM0=\nsoftware.sslmate.com/src/go-pkcs12 v0.7.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=\nstorj.io/common v0.0.0-20240812101423-26b53789c348 h1:Urs3fX+1Fyb+CFKGw0mCJV3MPR499WM+Vs6osw4Rqtk=\nstorj.io/common v0.0.0-20240812101423-26b53789c348/go.mod h1:XMpwKxc04HCBl4H5IFCGv1ca5Dm0tvH4NL7Jx+JhxuA=\nstorj.io/drpc v0.0.35-0.20240709171858-0075ac871661 h1:hLvEV2RMTscX3JHPd+LSQCeTt8i1Q0Yt7U2EdfyMnaQ=\nstorj.io/drpc v0.0.35-0.20240709171858-0075ac871661/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg=\nstorj.io/eventkit v0.0.0-20240415002644-1d9596fee086 h1:TkytkGUI6zGtH5Qx/O0VxQCcYJqOOiwRq0oMi4uM5Tg=\nstorj.io/eventkit v0.0.0-20240415002644-1d9596fee086/go.mod h1:S6p41RzIBKoeGAdrziksWkiijnZXql9YcNsc23t0u+8=\nstorj.io/infectious v0.0.2 h1:rGIdDC/6gNYAStsxsZU79D/MqFjNyJc1tsyyj9sTl7Q=\nstorj.io/infectious v0.0.2/go.mod h1:QEjKKww28Sjl1x8iDsjBpOM4r1Yp8RsowNcItsZJ1Vs=\nstorj.io/picobuf v0.0.3 h1:xAUPB5ZUGfxkqd3bnw3zp01kkWb9wlhg4vtZWUs2S9A=\nstorj.io/picobuf v0.0.3/go.mod h1:4V4xelV1RSCck5GgmkL/Txw9l6IfX3XcBzegmL5Kudo=\nstorj.io/uplink v1.13.1 h1:C8RdW/upALoCyuF16Lod9XGCXEdbJAS+ABQy9JO/0pA=\nstorj.io/uplink v1.13.1/go.mod h1:x0MQr4UfFsQBwgVWZAtEsLpuwAn6dg7G0Mpne1r516E=\n"
  },
  {
    "path": "info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>telegraf_entry_mac</string>\n\t<key>CFBundleIconFile</key>\n\t<string>icon.icns</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>com.influxdata.telegraf</string>\n\t<key>NSHighResolutionCapable</key>\n\t<true/>\n\t<key>LSUIElement</key>\n\t<true/>\n</dict>\n</plist>"
  },
  {
    "path": "input.go",
    "content": "package telegraf\n\ntype Input interface {\n\tPluginDescriber\n\n\t// Gather takes in an accumulator and adds the metrics that the Input\n\t// gathers. This is called every agent.interval\n\tGather(Accumulator) error\n}\n\ntype ServiceInput interface {\n\tInput\n\n\t// Start the ServiceInput.  The Accumulator may be retained and used until\n\t// Stop returns.\n\tStart(Accumulator) error\n\n\t// Stop stops the services and closes any necessary channels and connections.\n\t// Metrics should not be written out to the accumulator once stop returns, so\n\t// Stop() should stop reading and wait for any in-flight metrics to write out\n\t// to the accumulator before returning.\n\tStop()\n}\n"
  },
  {
    "path": "internal/choice/choice.go",
    "content": "// Package choice provides basic functions for working with\n// plugin options that must be one of several values.\npackage choice\n\nimport \"fmt\"\n\n// Contains return true if the choice in the list of choices.\nfunc Contains(choice string, choices []string) bool {\n\tfor _, item := range choices {\n\t\tif item == choice {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Check returns an error if a choice is not one of\n// the available choices.\nfunc Check(choice string, available []string) error {\n\tif !Contains(choice, available) {\n\t\treturn fmt.Errorf(\"unknown choice %s\", choice)\n\t}\n\treturn nil\n}\n\n// CheckSlice returns an error if the choices is not a subset of\n// available.\nfunc CheckSlice(choices, available []string) error {\n\tfor _, choice := range choices {\n\t\terr := Check(choice, available)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/clock/options.go",
    "content": "package clock\n\nimport (\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n)\n\ntype config struct {\n\tclk   clock.Clock\n\tstart time.Time\n\talign bool\n\n\tnotifier chan bool\n}\n\ntype Option func(*config)\n\nfunc WithClock(clk clock.Clock) Option {\n\treturn func(c *config) {\n\t\tc.clk = clk\n\t}\n}\n\nfunc WithAlignment(start time.Time) Option {\n\treturn func(c *config) {\n\t\tc.start = start\n\t\tc.align = true\n\t}\n}\n\nfunc WithStartupNotification(notifier chan bool) Option {\n\treturn func(c *config) {\n\t\tc.notifier = notifier\n\t}\n}\n"
  },
  {
    "path": "internal/clock/ticker.go",
    "content": "package clock\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\ntype Ticker struct {\n\tC chan time.Time\n\n\tclk      clock.Clock\n\tschedule time.Time\n\tinterval time.Duration\n\tjitter   time.Duration\n\tcancel   context.CancelFunc\n\twg       sync.WaitGroup\n\n\tcfg *config\n}\n\nfunc NewTicker(interval, jitter, offset time.Duration, opt ...Option) *Ticker {\n\t// Apply the options\n\tcfg := &config{\n\t\tclk: clock.New(),\n\t}\n\tfor _, o := range opt {\n\t\to(cfg)\n\t}\n\n\tschedule := cfg.clk.Now()\n\n\t// Align the scheduled trigger time to interval borders\n\tif cfg.align {\n\t\t// Add minimum interval size to avoid scheduling exceptionally short\n\t\t// intervals. This avoids an issue that can occur where the previous\n\t\t// interval ends slightly early due to very minor clock changes.\n\t\tschedule = internal.AlignTime(cfg.start.Add(interval/100), interval)\n\t}\n\n\t// Compute the scheduled first tick by adding the offset. By doing so, we\n\t// do not need to take the offset into account later.\n\tschedule = schedule.Add(offset)\n\n\t// Initialize the ticker instance and start it\n\tt := &Ticker{\n\t\tC:        make(chan time.Time, 1),\n\t\tclk:      cfg.clk,\n\t\tschedule: schedule,\n\t\tinterval: interval,\n\t\tjitter:   jitter,\n\t\tcfg:      cfg,\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.cancel = cancel\n\n\tt.wg.Add(1)\n\tgo func() {\n\t\tdefer t.wg.Done()\n\t\tt.run(ctx)\n\t}()\n\n\treturn t\n}\n\nfunc (t *Ticker) Stop() {\n\tt.cancel()\n\tt.wg.Wait()\n}\n\nfunc (t *Ticker) run(ctx context.Context) {\n\t// Start with the first scheduled tick\n\ttimer := t.clk.Timer(t.clk.Until(t.schedule) + internal.RandomDuration(t.jitter))\n\tdefer timer.Stop()\n\n\tif t.cfg.notifier != nil {\n\t\tt.cfg.notifier <- true\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase ts := <-timer.C:\n\t\t\t// Compute the next scheduled interval by adding the interval and\n\t\t\t// randomizing the timing with the given jitter (if any). Note, we\n\t\t\t// need to remember the next scheduling without adding the ticker\n\t\t\t// to avoid drifting of the ticks by jitter/2 on average!\n\t\t\tt.schedule = t.schedule.Add(t.interval)\n\t\t\ttimer.Reset(t.clk.Until(t.schedule) + internal.RandomDuration(t.jitter))\n\n\t\t\t// Fire our event in a non-blocking fashion to avoid blocking the\n\t\t\t// ticker if the agent code did not read the channel yet\n\t\t\tselect {\n\t\t\tcase t.C <- ts:\n\t\t\tdefault:\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/clock/ticker_aligned_test.go",
    "content": "package clock\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAlignedTicker(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 0 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\tend := start.Add(60 * time.Second)\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\texpected := []time.Time{\n\t\ttime.Unix(10, 0).UTC(),\n\t\ttime.Unix(20, 0).UTC(),\n\t\ttime.Unix(30, 0).UTC(),\n\t\ttime.Unix(40, 0).UTC(),\n\t\ttime.Unix(50, 0).UTC(),\n\t\ttime.Unix(60, 0).UTC(),\n\t}\n\n\tactual := make([]time.Time, 0)\n\tclk.Add(10 * time.Second)\n\tfor !clk.Now().After(end) {\n\t\tts := <-ticker.C\n\t\tactual = append(actual, ts.UTC())\n\n\t\tclk.Add(10 * time.Second)\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestAlignedTickerJitter(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\tend := start.Add(61 * time.Second)\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\tlast := start\n\tfor !clk.Now().After(end) {\n\t\tselect {\n\t\tcase ts := <-ticker.C:\n\t\t\tdur := ts.Sub(last)\n\t\t\t// 10s interval + 5s jitter + up to 1s late firing.\n\t\t\trequire.LessOrEqual(t, dur, 16*time.Second, \"expected elapsed time to be less than 16 seconds, but was %s\", dur)\n\t\t\trequire.GreaterOrEqual(t, dur, 5*time.Second, \"expected elapsed time to be more than 5 seconds, but was %s\", dur)\n\t\t\tlast = last.Add(interval)\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n}\n\nfunc TestAlignedTickerOffset(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 0 * time.Second\n\toffset := 3 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\tend := start.Add(61 * time.Second)\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\texpected := []time.Time{\n\t\ttime.Unix(13, 0).UTC(),\n\t\ttime.Unix(23, 0).UTC(),\n\t\ttime.Unix(33, 0).UTC(),\n\t\ttime.Unix(43, 0).UTC(),\n\t\ttime.Unix(53, 0).UTC(),\n\t}\n\n\tactual := make([]time.Time, 0)\n\tclk.Add(10*time.Second + offset)\n\tfor !clk.Now().After(end) {\n\t\tts := <-ticker.C\n\t\tactual = append(actual, ts.UTC())\n\t\tclk.Add(10 * time.Second)\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestAlignedTickerMissedTick(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 0 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\t// Advance the time after we should have received two ticks but we did not\n\t// receive the first tick yet so the second one should be lost because the\n\t// channel is full.\n\t// NOTE: We need to use the range statement because the mock-clock\n\t//       implementation will stop the clock once a time is issued.\n\tfor range 25 {\n\t\tclk.Add(1 * time.Second)\n\t}\n\tts := <-ticker.C\n\trequire.Equal(t, time.Unix(10, 0).UTC(), ts.UTC())\n\n\t// Advance the time further until we receive another tick\n\tfor range 5 {\n\t\tclk.Add(1 * time.Second)\n\t}\n\tts = <-ticker.C\n\trequire.Equal(t, time.Unix(30, 0).UTC(), ts.UTC())\n}\n\n// TestAlignedTickerJitterBehavior shows that AlignedTicker has different behavior.\n// It realigns to interval boundaries, so jitter doesn't accumulate as drift.\n// However, the average interval is still affected by jitter.\n//\n// Scenario:\n//   - interval = 60s\n//   - jitter = 10s\n//   - start time = 12:02:22\n//\n// Behavior:\n//   - First trigger: next 60s boundary (12:03:00) + jitter = ~12:03:05\n//   - Second trigger: next 60s boundary (12:04:00) + jitter = ~12:04:07\n//   - The jitter variation averages out because of realignment\nfunc TestAlignedTickerJitterBehavior(t *testing.T) {\n\tinterval := 60 * time.Second\n\tjitter := 10 * time.Second\n\toffset := 0 * time.Second\n\n\t// Start at 12:02:22\n\tstart := time.Date(2024, 1, 1, 12, 2, 22, 0, time.UTC)\n\tclk := clock.NewMock()\n\tclk.Set(start)\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\t// Collect 60 ticks\n\tconst numTicks = 60\n\tvar triggers []time.Time\n\n\tfor len(triggers) < numTicks {\n\t\tselect {\n\t\tcase ts := <-ticker.C:\n\t\t\ttriggers = append(triggers, ts)\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\tfirstTrigger := triggers[0]\n\tlastTrigger := triggers[numTicks-1]\n\ttotalElapsed := lastTrigger.Sub(firstTrigger)\n\texpectedTime := time.Duration(numTicks-1) * interval\n\tdrift := totalElapsed - expectedTime\n\n\tt.Logf(\"=== AlignedTicker (realigns to boundaries) ===\")\n\tt.Logf(\"Start time:      %s\", start.Format(\"15:04:05\"))\n\tt.Logf(\"First trigger:   %s\", firstTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Last trigger:    %s\", lastTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Total elapsed:   %s\", totalElapsed)\n\tt.Logf(\"Expected:        %s\", expectedTime)\n\tt.Logf(\"Drift:           %s\", drift)\n\tt.Logf(\"Avg interval:    %.2fs\", totalElapsed.Seconds()/float64(numTicks-1))\n\n\t// AlignedTicker realigns to boundaries, so drift is minimal\n\t// The jitter variations cancel out over time\n\tif drift < 0 {\n\t\tdrift = -drift\n\t}\n\trequire.Less(t, drift, 1*time.Minute,\n\t\t\"AlignedTicker should have minimal drift due to boundary realignment\")\n}\n\n// Simulates running the Ticker for an hour and displays stats about the\n// operation.\nfunc TestAlignedTickerDistribution(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\tdist := simulatedTickerDist(ticker, clk)\n\tdist.print()\n\trequire.Less(t, 350, dist.count)\n\trequire.True(t, 9 < dist.mean() && dist.mean() < 11)\n}\n\nfunc TestAlignedTickerDistributionWithOffset(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\toffset := 3 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithAlignment(start))\n\tdefer ticker.Stop()\n\n\tdist := simulatedTickerDist(ticker, clk)\n\tdist.print()\n\trequire.Less(t, 350, dist.count)\n\trequire.True(t, 9 < dist.mean() && dist.mean() < 11)\n}\n"
  },
  {
    "path": "internal/clock/ticker_test.go",
    "content": "package clock\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n)\n\ntype distribution struct {\n\tbuckets  [60]int\n\tcount    int\n\twaittime float64\n}\n\nfunc simulatedTickerDist(ticker *Ticker, clk *clock.Mock) distribution {\n\tstart := clk.Now()\n\tend := start.Add(1 * time.Hour)\n\n\tvar dist distribution\n\n\tlast := clk.Now()\n\tfor !clk.Now().After(end) {\n\t\tselect {\n\t\tcase ts := <-ticker.C:\n\t\t\tdist.buckets[ts.Second()]++\n\t\t\tdist.count++\n\t\t\tdist.waittime += ts.Sub(last).Seconds()\n\t\t\tlast = ts\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\treturn dist\n}\n\nfunc (d *distribution) mean() float64 {\n\treturn d.waittime / float64(d.count)\n}\n\nfunc (d distribution) print() {\n\tfor i, count := range d.buckets {\n\t\tfmt.Printf(\"%2d %s\\n\", i, strings.Repeat(\"x\", count))\n\t}\n\tfmt.Printf(\"Average interval: %f\\n\", d.mean())\n\tfmt.Printf(\"Count: %d\\n\", d.count)\n}\n"
  },
  {
    "path": "internal/clock/ticker_unaligned_test.go",
    "content": "package clock\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestUnalignedTicker(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 0 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tclk.Add(1 * time.Second)\n\n\tstartup := make(chan bool, 1)\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk), WithStartupNotification(startup))\n\tdefer ticker.Stop()\n\n\texpected := []time.Time{\n\t\ttime.Unix(1, 0).UTC(),\n\t\ttime.Unix(11, 0).UTC(),\n\t\ttime.Unix(21, 0).UTC(),\n\t\ttime.Unix(31, 0).UTC(),\n\t\ttime.Unix(41, 0).UTC(),\n\t\ttime.Unix(51, 0).UTC(),\n\t\ttime.Unix(61, 0).UTC(),\n\t}\n\n\tactual := make([]time.Time, 0, len(expected))\n\n\t// Wait for the ticker to startup\n\t<-startup\n\n\t// The first tick fires immediately inside the Timer() constructor\n\t// (Timer(0) with deadline == now), so no clock advance is needed.\n\t// Blocking on each read ensures the ticker goroutine has called\n\t// timer.Reset() before the next clock advance, preventing the\n\t// race between clk.Add() and timer.Reset() that causes flaky\n\t// deadline shifts.\n\tactual = append(actual, (<-ticker.C).UTC())\n\tfor i := 1; i < len(expected); i++ {\n\t\tclk.Add(interval)\n\t\tactual = append(actual, (<-ticker.C).UTC())\n\t}\n\trequire.Equal(t, expected, actual)\n}\n\n// TestUnalignedTickerJitterBehavior shows UnalignedTicker behavior with jitter.\n// UnalignedTicker uses a fixed interval ticker internally, so jitter only adds\n// delay but doesn't cause cumulative drift.\nfunc TestUnalignedTickerJitterBehavior(t *testing.T) {\n\tinterval := 60 * time.Second\n\tjitter := 10 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk))\n\tdefer ticker.Stop()\n\n\t// Collect 60 ticks\n\tconst numTicks = 60\n\tvar triggers []time.Time\n\n\tfor len(triggers) < numTicks {\n\t\tselect {\n\t\tcase ts := <-ticker.C:\n\t\t\ttriggers = append(triggers, ts)\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\tfirstTrigger := triggers[0]\n\tlastTrigger := triggers[numTicks-1]\n\ttotalElapsed := lastTrigger.Sub(firstTrigger)\n\texpectedTime := time.Duration(numTicks-1) * interval\n\tdrift := totalElapsed - expectedTime\n\n\tt.Logf(\"=== UnalignedTicker (fixed ticker + jitter sleep) ===\")\n\tt.Logf(\"Start time:      %s\", start.Format(\"15:04:05\"))\n\tt.Logf(\"First trigger:   %s\", firstTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Last trigger:    %s\", lastTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Total elapsed:   %s\", totalElapsed)\n\tt.Logf(\"Expected:        %s\", expectedTime)\n\tt.Logf(\"Drift:           %s\", drift)\n\tt.Logf(\"Avg interval:    %.2fs\", totalElapsed.Seconds()/float64(numTicks-1))\n\n\t// UnalignedTicker uses clk.Ticker(interval) which fires at fixed intervals\n\t// The jitter is added as sleep AFTER each tick, but the ticker rhythm is fixed\n\t// So drift should be minimal (jitter variations average out)\n\tif drift < 0 {\n\t\tdrift = -drift\n\t}\n\trequire.Less(t, drift, 1*time.Minute, \"UnalignedTicker should have minimal drift due to fixed internal ticker\")\n}\n\n// Simulates running the Ticker for an hour and displays stats about the\n// operation.\nfunc TestUnalignedTickerDistribution(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\toffset := 0 * time.Second\n\n\tclk := clock.NewMock()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk))\n\tdefer ticker.Stop()\n\n\tdist := simulatedTickerDist(ticker, clk)\n\tdist.print()\n\trequire.Less(t, 350, dist.count)\n\trequire.True(t, 9 < dist.mean() && dist.mean() < 11)\n}\n\nfunc TestUnalignedTickerDistributionWithOffset(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\toffset := 3 * time.Second\n\n\tclk := clock.NewMock()\n\n\tticker := NewTicker(interval, jitter, offset, WithClock(clk))\n\tdefer ticker.Stop()\n\n\tdist := simulatedTickerDist(ticker, clk)\n\tdist.print()\n\trequire.Less(t, 350, dist.count)\n\trequire.True(t, 9 < dist.mean() && dist.mean() < 11)\n}\n"
  },
  {
    "path": "internal/clock/timer.go",
    "content": "package clock\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// Timer delivers ticks at regular but unaligned intervals.\n//\n// Because the next interval is scheduled based on the interval + jitter, you\n// are guaranteed at least interval seconds without missing a tick and ticks\n// will be evenly scheduled over time.\n//\n// On average you will have one collection each interval + (jitter/2).\n//\n// The first tick is emitted after interval+jitter seconds.\n//\n// Ticks are dropped for slow consumers.\ntype Timer struct {\n\tC        chan time.Time\n\tclk      clock.Clock\n\tinterval time.Duration\n\tjitter   time.Duration\n\tcancel   context.CancelFunc\n\twg       sync.WaitGroup\n\n\tcfg *config\n}\n\nfunc NewTimer(interval, jitter time.Duration, opt ...Option) *Timer {\n\t// Apply the options\n\tcfg := &config{\n\t\tclk: clock.New(),\n\t}\n\tfor _, o := range opt {\n\t\to(cfg)\n\t}\n\n\t// Initialize the timer instance and start it\n\tt := &Timer{\n\t\tC:        make(chan time.Time, 1),\n\t\tclk:      cfg.clk,\n\t\tinterval: interval,\n\t\tjitter:   jitter,\n\t\tcfg:      cfg,\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.cancel = cancel\n\n\tt.wg.Add(1)\n\tgo func() {\n\t\tdefer t.wg.Done()\n\t\tt.run(ctx)\n\t}()\n\n\treturn t\n}\n\nfunc (t *Timer) Stop() {\n\tt.cancel()\n\tt.wg.Wait()\n}\n\nfunc (t *Timer) run(ctx context.Context) {\n\ttimer := t.clk.Timer(t.interval + internal.RandomDuration(t.jitter))\n\tdefer timer.Stop()\n\n\tif t.cfg.notifier != nil {\n\t\tt.cfg.notifier <- true\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase ts := <-timer.C:\n\t\t\t// Compute the next tick by adding the interval and randomizing the\n\t\t\t// timing with the given jitter (if any). We don't ensure evenly\n\t\t\t// spaced ticks here but rather guarantee the minimum time between\n\t\t\t// ticks being 'interval' long. Note, on average the space between\n\t\t\t// ticks will be interval plus jitter/2!\n\t\t\ttimer.Reset(t.interval + internal.RandomDuration(t.jitter))\n\n\t\t\t// Fire our event in a non-blocking fashion to avoid blocking the\n\t\t\t// timer if the agent code did not read the channel yet\n\t\t\tselect {\n\t\t\tcase t.C <- ts:\n\t\t\tdefault:\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/clock/timer_test.go",
    "content": "package clock\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTimer(t *testing.T) {\n\tinterval := 10 * time.Second\n\tjitter := 0 * time.Second\n\n\tclk := clock.NewMock()\n\tclk.Add(1 * time.Second)\n\n\tstart := clk.Now()\n\tend := start.Add(60 * time.Second)\n\n\tstartup := make(chan bool, 1)\n\n\ttimer := NewTimer(interval, jitter, WithClock(clk), WithStartupNotification(startup))\n\tdefer timer.Stop()\n\n\texpected := []time.Time{\n\t\ttime.Unix(11, 0).UTC(),\n\t\ttime.Unix(21, 0).UTC(),\n\t\ttime.Unix(31, 0).UTC(),\n\t\ttime.Unix(41, 0).UTC(),\n\t\ttime.Unix(51, 0).UTC(),\n\t\ttime.Unix(61, 0).UTC(),\n\t}\n\n\t// Wait for the timer to startup\n\t<-startup\n\n\tactual := make([]time.Time, 0, len(expected))\n\tfor !clk.Now().After(end) {\n\t\tselect {\n\t\tcase ts := <-timer.C:\n\t\t\tactual = append(actual, ts.UTC())\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\n// TestTimerJitterDrift demonstrates that with a Timer, jitter causes drift\n// over time. Each tick = interval + random(0, jitter), so the\n// average tick distance is interval + jitter/2.\n//\n// Scenario from issue #17287:\n//   - interval = 60s\n//   - jitter = 10s\n//\n// Current behavior:\n//   - Each tick: interval + random(0-10s)\n//   - Average interval: 60s + 5s = 65s\n//   - After 60 ticks: expected 60min, actual ~65min (5min drift)\n//\n// This is intentional as Timer is used for flushing and there we want to\n// guarantee a minimum pause between flush cycles.\nfunc TestTimerJitterDrift(t *testing.T) {\n\tinterval := 60 * time.Second\n\tjitter := 10 * time.Second\n\n\tclk := clock.NewMock()\n\tstart := clk.Now()\n\n\ttimer := NewTimer(interval, jitter, WithClock(clk))\n\tdefer timer.Stop()\n\n\t// Collect 60 ticks\n\tconst numTicks = 60\n\tvar triggers []time.Time\n\n\tfor len(triggers) < numTicks {\n\t\tselect {\n\t\tcase ts := <-timer.C:\n\t\t\ttriggers = append(triggers, ts)\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\t// Calculate total elapsed time\n\tfirstTrigger := triggers[0]\n\tlastTrigger := triggers[numTicks-1]\n\ttotalElapsed := lastTrigger.Sub(firstTrigger)\n\n\t// Expected time for 59 intervals: 59 * 60s = 59 minutes\n\texpectedTime := time.Duration(numTicks-1) * interval\n\n\t// Calculate drift\n\tdrift := totalElapsed - expectedTime\n\n\tt.Logf(\"=== Timer (interval + jitter each tick) ===\")\n\tt.Logf(\"Start time:      %s\", start.Format(\"15:04:05\"))\n\tt.Logf(\"First trigger:   %s\", firstTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Last trigger:    %s\", lastTrigger.Format(\"15:04:05\"))\n\tt.Logf(\"Total elapsed:   %s\", totalElapsed)\n\tt.Logf(\"Expected:        %s (if no jitter drift)\", expectedTime)\n\tt.Logf(\"Drift:           %s\", drift)\n\tt.Logf(\"Avg interval:    %.2fs (expected ~65s with jitter)\", totalElapsed.Seconds()/float64(numTicks-1))\n\n\t// Current behavior: drift should be ~5 minutes (59 intervals * 5s avg jitter)\n\t// This confirms the bug from issue #17287\n\trequire.Greater(t, drift, 2*time.Minute,\n\t\t\"Expected significant drift with Timer jitter behavior\")\n\trequire.Less(t, drift, 10*time.Minute,\n\t\t\"Drift is larger than expected maximum\")\n}\n\n// Simulates running the Ticker for an hour and displays stats about the\n// operation.\nfunc TestTimerDistribution(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tinterval := 10 * time.Second\n\tjitter := 5 * time.Second\n\n\tclk := clock.NewMock()\n\n\ttimer := NewTimer(interval, jitter, WithClock(clk))\n\tdefer timer.Stop()\n\n\tdist := simulatedTimerDist(timer, clk)\n\tdist.print()\n\trequire.Less(t, 275, dist.count)\n\trequire.True(t, 12 < dist.mean() && 13 > dist.mean())\n}\n\nfunc simulatedTimerDist(timer *Timer, clk *clock.Mock) distribution {\n\tstart := clk.Now()\n\tend := start.Add(1 * time.Hour)\n\n\tvar dist distribution\n\n\tlast := clk.Now()\n\tfor !clk.Now().After(end) {\n\t\tselect {\n\t\tcase ts := <-timer.C:\n\t\t\tdist.buckets[ts.Second()]++\n\t\t\tdist.count++\n\t\t\tdist.waittime += ts.Sub(last).Seconds()\n\t\t\tlast = ts\n\t\tdefault:\n\t\t\tclk.Add(1 * time.Second)\n\t\t}\n\t}\n\n\treturn dist\n}\n"
  },
  {
    "path": "internal/content_coding.go",
    "content": "package internal\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/klauspost/compress/gzip\"\n\t\"github.com/klauspost/compress/zlib\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/klauspost/pgzip\"\n)\n\nconst defaultMaxDecompressionSize int64 = 500 * 1024 * 1024 // 500MB\n\n// DecodingOption provide methods to change the decoding from the standard\n// configuration.\ntype DecodingOption func(*decoderConfig)\n\ntype decoderConfig struct {\n\tmaxDecompressionSize int64\n}\n\nfunc WithMaxDecompressionSize(maxDecompressionSize int64) DecodingOption {\n\treturn func(cfg *decoderConfig) {\n\t\tcfg.maxDecompressionSize = maxDecompressionSize\n\t}\n}\n\ntype encoderConfig struct {\n\tlevel int\n}\n\n// EncodingOption provide methods to change the encoding from the standard\n// configuration.\ntype EncodingOption func(*encoderConfig)\n\nfunc WithCompressionLevel(level int) EncodingOption {\n\treturn func(cfg *encoderConfig) {\n\t\tcfg.level = level\n\t}\n}\n\n// NewStreamContentDecoder returns a reader that will decode the stream\n// according to the encoding type.\nfunc NewStreamContentDecoder(encoding string, r io.Reader) (io.Reader, error) {\n\tswitch encoding {\n\tcase \"gzip\":\n\t\treturn NewGzipReader(r)\n\tcase \"identity\", \"\":\n\t\treturn r, nil\n\tdefault:\n\t\treturn nil, errors.New(\"invalid value for content_encoding\")\n\t}\n}\n\n// GzipReader is similar to gzip.Reader but reads only a single gzip stream per read.\ntype GzipReader struct {\n\tr           io.Reader\n\tz           *pgzip.Reader\n\tendOfStream bool\n}\n\nfunc NewGzipReader(r io.Reader) (io.Reader, error) {\n\t// We need a read that implements ByteReader in order to line up the next\n\t// stream.\n\tbr := bufio.NewReader(r)\n\n\t// Reads the first gzip stream header.\n\tz, err := pgzip.NewReader(br)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Prevent future calls to Read from reading the following gzip header.\n\tz.Multistream(false)\n\n\treturn &GzipReader{r: br, z: z}, nil\n}\n\nfunc (r *GzipReader) Read(b []byte) (int, error) {\n\tif r.endOfStream {\n\t\t// Reads the next gzip header and prepares for the next stream.\n\t\terr := r.z.Reset(r.r)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tr.z.Multistream(false)\n\t\tr.endOfStream = false\n\t}\n\n\tn, err := r.z.Read(b)\n\n\t// Since multistream is disabled, io.EOF indicates the end of the gzip\n\t// sequence.  On the next read we must read the next gzip header.\n\tif errors.Is(err, io.EOF) {\n\t\tr.endOfStream = true\n\t\treturn n, nil\n\t}\n\treturn n, err\n}\n\n// NewContentEncoder returns a ContentEncoder for the encoding type.\nfunc NewContentEncoder(encoding string, options ...EncodingOption) (ContentEncoder, error) {\n\tswitch encoding {\n\tcase \"gzip\":\n\t\treturn NewGzipEncoder(options...)\n\tcase \"identity\", \"\":\n\t\treturn NewIdentityEncoder(options...)\n\tcase \"zlib\":\n\t\treturn NewZlibEncoder(options...)\n\tcase \"zstd\":\n\t\treturn NewZstdEncoder(options...)\n\tdefault:\n\t\treturn nil, errors.New(\"invalid value for content_encoding\")\n\t}\n}\n\ntype AutoDecoder struct {\n\tencoding string\n\tgzip     *GzipDecoder\n\tidentity *IdentityDecoder\n}\n\nfunc (a *AutoDecoder) SetEncoding(encoding string) {\n\ta.encoding = encoding\n}\n\nfunc (a *AutoDecoder) Decode(data []byte) ([]byte, error) {\n\tif a.encoding == \"gzip\" {\n\t\treturn a.gzip.Decode(data)\n\t}\n\treturn a.identity.Decode(data)\n}\n\nfunc NewAutoContentDecoder(options ...DecodingOption) *AutoDecoder {\n\tvar a AutoDecoder\n\n\ta.identity = NewIdentityDecoder(options...)\n\ta.gzip = NewGzipDecoder(options...)\n\treturn &a\n}\n\n// NewContentDecoder returns a ContentDecoder for the encoding type.\nfunc NewContentDecoder(encoding string, options ...DecodingOption) (ContentDecoder, error) {\n\tswitch encoding {\n\tcase \"auto\":\n\t\treturn NewAutoContentDecoder(options...), nil\n\tcase \"gzip\":\n\t\treturn NewGzipDecoder(options...), nil\n\tcase \"identity\", \"\":\n\t\treturn NewIdentityDecoder(options...), nil\n\tcase \"zlib\":\n\t\treturn NewZlibDecoder(options...), nil\n\tcase \"zstd\":\n\t\treturn NewZstdDecoder(options...)\n\tdefault:\n\t\treturn nil, errors.New(\"invalid value for content_encoding\")\n\t}\n}\n\n// ContentEncoder applies a wrapper encoding to byte buffers.\ntype ContentEncoder interface {\n\tEncode([]byte) ([]byte, error)\n}\n\n// GzipEncoder compresses the buffer using gzip at the default level.\ntype GzipEncoder struct {\n\tpwriter *pgzip.Writer\n\twriter  *gzip.Writer\n\tbuf     *bytes.Buffer\n}\n\nfunc NewGzipEncoder(options ...EncodingOption) (*GzipEncoder, error) {\n\tcfg := encoderConfig{level: gzip.DefaultCompression}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\t// Check if the compression level is supported\n\tswitch cfg.level {\n\tcase gzip.NoCompression, gzip.DefaultCompression, gzip.BestSpeed, gzip.BestCompression:\n\t\t// Do nothing as those are valid levels\n\tdefault:\n\t\treturn nil, errors.New(\"invalid compression level, only 0, 1 and 9 are supported\")\n\t}\n\n\tvar buf bytes.Buffer\n\tpw, err := pgzip.NewWriterLevel(&buf, cfg.level)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tw, err := gzip.NewWriterLevel(&buf, cfg.level)\n\treturn &GzipEncoder{\n\t\tpwriter: pw,\n\t\twriter:  w,\n\t\tbuf:     &buf,\n\t}, err\n}\n\nfunc (e *GzipEncoder) Encode(data []byte) ([]byte, error) {\n\t// Parallel Gzip is only faster for larger data chunks. According to the\n\t// project's documentation the trade-off size is at about 1MB, so we switch\n\t// to parallel Gzip if the data is larger and run the built-in version\n\t// otherwise.\n\tif len(data) > 1024*1024 {\n\t\treturn e.encodeBig(data)\n\t}\n\treturn e.encodeSmall(data)\n}\n\nfunc (e *GzipEncoder) encodeSmall(data []byte) ([]byte, error) {\n\te.buf.Reset()\n\te.writer.Reset(e.buf)\n\n\t_, err := e.writer.Write(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = e.writer.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn e.buf.Bytes(), nil\n}\n\nfunc (e *GzipEncoder) encodeBig(data []byte) ([]byte, error) {\n\te.buf.Reset()\n\te.pwriter.Reset(e.buf)\n\n\t_, err := e.pwriter.Write(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = e.pwriter.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn e.buf.Bytes(), nil\n}\n\ntype ZlibEncoder struct {\n\twriter *zlib.Writer\n\tbuf    *bytes.Buffer\n}\n\nfunc NewZlibEncoder(options ...EncodingOption) (*ZlibEncoder, error) {\n\tcfg := encoderConfig{level: zlib.DefaultCompression}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\tswitch cfg.level {\n\tcase zlib.NoCompression, zlib.DefaultCompression, zlib.BestSpeed, zlib.BestCompression:\n\t\t// Do nothing as those are valid levels\n\tdefault:\n\t\treturn nil, errors.New(\"invalid compression level, only 0, 1 and 9 are supported\")\n\t}\n\n\tvar buf bytes.Buffer\n\tw, err := zlib.NewWriterLevel(&buf, cfg.level)\n\treturn &ZlibEncoder{\n\t\twriter: w,\n\t\tbuf:    &buf,\n\t}, err\n}\n\nfunc (e *ZlibEncoder) Encode(data []byte) ([]byte, error) {\n\te.buf.Reset()\n\te.writer.Reset(e.buf)\n\n\t_, err := e.writer.Write(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = e.writer.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn e.buf.Bytes(), nil\n}\n\ntype ZstdEncoder struct {\n\tencoder *zstd.Encoder\n}\n\nfunc NewZstdEncoder(options ...EncodingOption) (*ZstdEncoder, error) {\n\tcfg := encoderConfig{level: 3}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\t// Map the levels\n\tvar level zstd.EncoderLevel\n\tswitch cfg.level {\n\tcase 1:\n\t\tlevel = zstd.SpeedFastest\n\tcase 3:\n\t\tlevel = zstd.SpeedDefault\n\tcase 7:\n\t\tlevel = zstd.SpeedBetterCompression\n\tcase 11:\n\t\tlevel = zstd.SpeedBestCompression\n\tdefault:\n\t\treturn nil, errors.New(\"invalid compression level, only 1, 3, 7 and 11 are supported\")\n\t}\n\n\te, err := zstd.NewWriter(nil, zstd.WithEncoderLevel(level))\n\treturn &ZstdEncoder{\n\t\tencoder: e,\n\t}, err\n}\n\nfunc (e *ZstdEncoder) Encode(data []byte) ([]byte, error) {\n\treturn e.encoder.EncodeAll(data, make([]byte, 0, len(data))), nil\n}\n\n// IdentityEncoder is a null encoder that applies no transformation.\ntype IdentityEncoder struct{}\n\nfunc NewIdentityEncoder(options ...EncodingOption) (*IdentityEncoder, error) {\n\tif len(options) > 0 {\n\t\treturn nil, errors.New(\"identity encoder does not support options\")\n\t}\n\n\treturn &IdentityEncoder{}, nil\n}\n\nfunc (*IdentityEncoder) Encode(data []byte) ([]byte, error) {\n\treturn data, nil\n}\n\n// ContentDecoder removes a wrapper encoding from byte buffers.\ntype ContentDecoder interface {\n\tSetEncoding(string)\n\tDecode([]byte) ([]byte, error)\n}\n\n// GzipDecoder decompresses buffers with gzip compression.\ntype GzipDecoder struct {\n\tpreader              *pgzip.Reader\n\treader               *gzip.Reader\n\tbuf                  *bytes.Buffer\n\tmaxDecompressionSize int64\n}\n\nfunc NewGzipDecoder(options ...DecodingOption) *GzipDecoder {\n\tcfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\treturn &GzipDecoder{\n\t\tpreader:              new(pgzip.Reader),\n\t\treader:               new(gzip.Reader),\n\t\tbuf:                  new(bytes.Buffer),\n\t\tmaxDecompressionSize: cfg.maxDecompressionSize,\n\t}\n}\n\nfunc (*GzipDecoder) SetEncoding(string) {}\n\nfunc (d *GzipDecoder) Decode(data []byte) ([]byte, error) {\n\t// Parallel Gzip is only faster for larger data chunks. According to the\n\t// project's documentation the trade-off size is at about 1MB, so we switch\n\t// to parallel Gzip if the data is larger and run the built-in version\n\t// otherwise.\n\tif len(data) > 1024*1024 {\n\t\treturn d.decodeBig(data)\n\t}\n\treturn d.decodeSmall(data)\n}\n\nfunc (d *GzipDecoder) decodeSmall(data []byte) ([]byte, error) {\n\terr := d.reader.Reset(bytes.NewBuffer(data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\td.buf.Reset()\n\n\tn, err := io.CopyN(d.buf, d.reader, d.maxDecompressionSize)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, err\n\t} else if n == d.maxDecompressionSize {\n\t\treturn nil, fmt.Errorf(\"size of decoded data exceeds allowed size %d\", d.maxDecompressionSize)\n\t}\n\n\terr = d.reader.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.buf.Bytes(), nil\n}\n\nfunc (d *GzipDecoder) decodeBig(data []byte) ([]byte, error) {\n\terr := d.preader.Reset(bytes.NewBuffer(data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\td.buf.Reset()\n\n\tn, err := io.CopyN(d.buf, d.preader, d.maxDecompressionSize)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, err\n\t} else if n == d.maxDecompressionSize {\n\t\treturn nil, fmt.Errorf(\"size of decoded data exceeds allowed size %d\", d.maxDecompressionSize)\n\t}\n\n\terr = d.preader.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.buf.Bytes(), nil\n}\n\ntype ZlibDecoder struct {\n\tbuf                  *bytes.Buffer\n\tmaxDecompressionSize int64\n}\n\nfunc NewZlibDecoder(options ...DecodingOption) *ZlibDecoder {\n\tcfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\treturn &ZlibDecoder{\n\t\tbuf:                  new(bytes.Buffer),\n\t\tmaxDecompressionSize: cfg.maxDecompressionSize,\n\t}\n}\n\nfunc (*ZlibDecoder) SetEncoding(string) {}\n\nfunc (d *ZlibDecoder) Decode(data []byte) ([]byte, error) {\n\td.buf.Reset()\n\n\tb := bytes.NewBuffer(data)\n\tr, err := zlib.NewReader(b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tn, err := io.CopyN(d.buf, r, d.maxDecompressionSize)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, err\n\t} else if n == d.maxDecompressionSize {\n\t\treturn nil, fmt.Errorf(\"size of decoded data exceeds allowed size %d\", d.maxDecompressionSize)\n\t}\n\n\terr = r.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.buf.Bytes(), nil\n}\n\ntype ZstdDecoder struct {\n\tdecoder *zstd.Decoder\n}\n\nfunc NewZstdDecoder(options ...DecodingOption) (*ZstdDecoder, error) {\n\tcfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize}\n\tfor _, o := range options {\n\t\to(&cfg)\n\t}\n\n\td, err := zstd.NewReader(nil, zstd.WithDecoderConcurrency(0), zstd.WithDecoderMaxWindow(uint64(cfg.maxDecompressionSize)))\n\treturn &ZstdDecoder{\n\t\tdecoder: d,\n\t}, err\n}\n\nfunc (*ZstdDecoder) SetEncoding(string) {}\n\nfunc (d *ZstdDecoder) Decode(data []byte) ([]byte, error) {\n\treturn d.decoder.DecodeAll(data, nil)\n}\n\n// IdentityDecoder is a null decoder that returns the input.\ntype IdentityDecoder struct {\n}\n\nfunc NewIdentityDecoder(_ ...DecodingOption) *IdentityDecoder {\n\treturn &IdentityDecoder{}\n}\n\nfunc (*IdentityDecoder) SetEncoding(string) {}\n\nfunc (*IdentityDecoder) Decode(data []byte) ([]byte, error) {\n\treturn data, nil\n}\n"
  },
  {
    "path": "internal/content_coding_test.go",
    "content": "package internal\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst maxDecompressionSize = 1024\n\nfunc TestGzipEncodeDecode(t *testing.T) {\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(t, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n}\n\nfunc TestGzipReuse(t *testing.T) {\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(t, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n\n\tpayload, err = enc.Encode([]byte(\"doody\"))\n\trequire.NoError(t, err)\n\n\tactual, err = dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"doody\", string(actual))\n}\n\nfunc TestZlibEncodeDecode(t *testing.T) {\n\tenc, err := NewZlibEncoder()\n\trequire.NoError(t, err)\n\tdec := NewZlibDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n}\n\nfunc TestZlibEncodeDecodeWithTooLargeMessage(t *testing.T) {\n\tenc, err := NewZlibEncoder()\n\trequire.NoError(t, err)\n\tdec := NewZlibDecoder(WithMaxDecompressionSize(3))\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\t_, err = dec.Decode(payload)\n\trequire.ErrorContains(t, err, \"size of decoded data exceeds allowed size 3\")\n}\n\nfunc TestZstdEncodeDecode(t *testing.T) {\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(t, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\trequire.NoError(t, err)\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n}\n\nfunc TestZstdReuse(t *testing.T) {\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(t, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\trequire.NoError(t, err)\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n\n\tpayload, err = enc.Encode([]byte(\"doody\"))\n\trequire.NoError(t, err)\n\n\tactual, err = dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"doody\", string(actual))\n}\n\nfunc TestIdentityEncodeDecode(t *testing.T) {\n\tdec := NewIdentityDecoder(WithMaxDecompressionSize(maxDecompressionSize))\n\tenc, err := NewIdentityEncoder()\n\trequire.NoError(t, err)\n\n\tpayload, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"howdy\", string(actual))\n}\n\nfunc TestStreamIdentityDecode(t *testing.T) {\n\tvar r bytes.Buffer\n\tn, err := r.WriteString(\"howdy\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, 5, n)\n\n\tdec, err := NewStreamContentDecoder(\"identity\", &r)\n\trequire.NoError(t, err)\n\n\tdata, err := io.ReadAll(dec)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, []byte(\"howdy\"), data)\n}\n\nfunc TestStreamGzipDecode(t *testing.T) {\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(t, err)\n\twritten, err := enc.Encode([]byte(\"howdy\"))\n\trequire.NoError(t, err)\n\n\tw := bytes.NewBuffer(written)\n\n\tdec, err := NewStreamContentDecoder(\"gzip\", w)\n\trequire.NoError(t, err)\n\n\tb := make([]byte, 10)\n\tn, err := dec.Read(b)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 5, n)\n\n\trequire.Equal(t, []byte(\"howdy\"), b[:n])\n}\n\nfunc TestCompressionLevel(t *testing.T) {\n\ttests := []struct {\n\t\talgorithm   string\n\t\tvalidLevels []int\n\t\terrormsg    string\n\t}{\n\t\t{\n\t\t\talgorithm:   \"gzip\",\n\t\t\tvalidLevels: []int{0, 1, 9},\n\t\t\terrormsg:    \"invalid compression level\",\n\t\t},\n\t\t{\n\t\t\talgorithm:   \"zlib\",\n\t\t\tvalidLevels: []int{0, 1, 9},\n\t\t\terrormsg:    \"invalid compression level\",\n\t\t},\n\t\t{\n\t\t\talgorithm:   \"zstd\",\n\t\t\tvalidLevels: []int{1, 3, 7, 11},\n\t\t\terrormsg:    \"invalid compression level\",\n\t\t},\n\t\t{\n\t\t\talgorithm: \"identity\",\n\t\t\terrormsg:  \"does not support options\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\t// Check default i.e. without specifying level\n\t\tt.Run(tt.algorithm+\" default\", func(t *testing.T) {\n\t\t\tenc, err := NewContentEncoder(tt.algorithm)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, enc)\n\t\t})\n\n\t\t// Check invalid level\n\t\tt.Run(tt.algorithm+\" invalid\", func(t *testing.T) {\n\t\t\t_, err := NewContentEncoder(tt.algorithm, WithCompressionLevel(12))\n\t\t\trequire.ErrorContains(t, err, tt.errormsg)\n\t\t})\n\n\t\t// Check known levels 0..9\n\t\tfor level := 0; level < 10; level++ {\n\t\t\tname := fmt.Sprintf(\"%s level %d\", tt.algorithm, level)\n\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\tvar valid bool\n\t\t\t\tfor _, l := range tt.validLevels {\n\t\t\t\t\tif l == level {\n\t\t\t\t\t\tvalid = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tenc, err := NewContentEncoder(tt.algorithm, WithCompressionLevel(level))\n\t\t\t\tif valid {\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.NotNil(t, enc)\n\t\t\t\t} else {\n\t\t\t\t\trequire.ErrorContains(t, err, tt.errormsg)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc BenchmarkGzipEncode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkGzipDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkGzipEncodeDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkGzipEncodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkGzipDecodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkGzipEncodeDecodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewGzipEncoder()\n\trequire.NoError(b, err)\n\tdec := NewGzipDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdEncode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdEncodeDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdEncodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdDecodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZstdEncodeDecodeBig(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 1024*1024))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZstdEncoder()\n\trequire.NoError(b, err)\n\tdec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen))\n\trequire.NoError(b, err)\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZlibEncode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZlibEncoder()\n\trequire.NoError(b, err)\n\tdec := NewZlibDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZlibDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZlibEncoder()\n\trequire.NoError(b, err)\n\tdec := NewZlibDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkZlibEncodeDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tenc, err := NewZlibEncoder()\n\trequire.NoError(b, err)\n\tdec := NewZlibDecoder(WithMaxDecompressionSize(dataLen))\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkIdentityEncodeDecode(b *testing.B) {\n\tdata := []byte(strings.Repeat(\"-howdy stranger-\", 64))\n\tdataLen := int64(len(data)) + 1\n\n\tdec := NewIdentityDecoder(WithMaxDecompressionSize(dataLen))\n\tenc, err := NewIdentityEncoder()\n\trequire.NoError(b, err)\n\n\tpayload, err := enc.Encode(data)\n\trequire.NoError(b, err)\n\tactual, err := dec.Decode(payload)\n\trequire.NoError(b, err)\n\trequire.Equal(b, data, actual)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tpayload, err := enc.Encode(data)\n\t\trequire.NoError(b, err)\n\n\t\t_, err = dec.Decode(payload)\n\t\trequire.NoError(b, err)\n\t}\n}\n"
  },
  {
    "path": "internal/customized_no.go",
    "content": "//go:build !custom\n\npackage internal\n\nconst Customized = \"\"\n"
  },
  {
    "path": "internal/customized_yes.go",
    "content": "//go:build custom\n\npackage internal\n\nconst Customized = \" (customized)\"\n"
  },
  {
    "path": "internal/docker/docker.go",
    "content": "package docker\n\nimport \"strings\"\n\n// ParseImage Adapts some of the logic from the actual Docker library's image parsing routines:\n// https://github.com/docker/distribution/blob/release/2.7/reference/normalize.go\nfunc ParseImage(image string) (imageName, imageVersion string) {\n\tdomain := \"\"\n\tremainder := \"\"\n\n\ti := strings.IndexRune(image, '/')\n\n\tif i == -1 || (!strings.ContainsAny(image[:i], \".:\") && image[:i] != \"localhost\") {\n\t\tremainder = image\n\t} else {\n\t\tdomain, remainder = image[:i], image[i+1:]\n\t}\n\n\timageVersion = \"unknown\"\n\ti = strings.LastIndex(remainder, \":\")\n\tif i > -1 {\n\t\timageVersion = remainder[i+1:]\n\t\timageName = remainder[:i]\n\t} else {\n\t\timageName = remainder\n\t}\n\n\tif domain != \"\" {\n\t\timageName = domain + \"/\" + imageName\n\t}\n\n\treturn imageName, imageVersion\n}\n"
  },
  {
    "path": "internal/docker/docker_test.go",
    "content": "package docker_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/internal/docker\"\n)\n\nfunc TestParseImage(t *testing.T) {\n\ttests := []struct {\n\t\timage         string\n\t\tparsedName    string\n\t\tparsedVersion string\n\t}{\n\t\t{\n\t\t\timage:         \"postgres\",\n\t\t\tparsedName:    \"postgres\",\n\t\t\tparsedVersion: \"unknown\",\n\t\t},\n\t\t{\n\t\t\timage:         \"postgres:latest\",\n\t\t\tparsedName:    \"postgres\",\n\t\t\tparsedVersion: \"latest\",\n\t\t},\n\t\t{\n\t\t\timage:         \"coreos/etcd\",\n\t\t\tparsedName:    \"coreos/etcd\",\n\t\t\tparsedVersion: \"unknown\",\n\t\t},\n\t\t{\n\t\t\timage:         \"coreos/etcd:latest\",\n\t\t\tparsedName:    \"coreos/etcd\",\n\t\t\tparsedVersion: \"latest\",\n\t\t},\n\t\t{\n\t\t\timage:         \"quay.io/postgres\",\n\t\t\tparsedName:    \"quay.io/postgres\",\n\t\t\tparsedVersion: \"unknown\",\n\t\t},\n\t\t{\n\t\t\timage:         \"quay.io:4443/coreos/etcd\",\n\t\t\tparsedName:    \"quay.io:4443/coreos/etcd\",\n\t\t\tparsedVersion: \"unknown\",\n\t\t},\n\t\t{\n\t\t\timage:         \"quay.io:4443/coreos/etcd:latest\",\n\t\t\tparsedName:    \"quay.io:4443/coreos/etcd\",\n\t\t\tparsedVersion: \"latest\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(\"parse name \"+tt.image, func(t *testing.T) {\n\t\t\timageName, imageVersion := docker.ParseImage(tt.image)\n\t\t\trequire.Equal(t, tt.parsedName, imageName)\n\t\t\trequire.Equal(t, tt.parsedVersion, imageVersion)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/env.go",
    "content": "package internal\n\nimport \"os\"\n\n// GetProcPath returns the path stored in HOST_PROC env variable, or /proc if HOST_PROC has not been set.\nfunc GetProcPath() string {\n\tif hostProc := os.Getenv(\"HOST_PROC\"); hostProc != \"\" {\n\t\treturn hostProc\n\t}\n\treturn \"/proc\"\n}\n\n// GetSysPath returns the path stored in HOST_SYS env variable, or /sys if HOST_SYS has not been set.\nfunc GetSysPath() string {\n\tif hostSys := os.Getenv(\"HOST_SYS\"); hostSys != \"\" {\n\t\treturn hostSys\n\t}\n\treturn \"/sys\"\n}\n"
  },
  {
    "path": "internal/errors.go",
    "content": "package internal\n\nimport \"errors\"\n\nvar (\n\tErrNotConnected     = errors.New(\"not connected\")\n\tErrSerialization    = errors.New(\"serialization of metric(s) failed\")\n\tErrSizeLimitReached = errors.New(\"size limit reached\")\n)\n\n// StartupError indicates an error that occurred during startup of a plugin\n// e.g. due to connectivity issues or resources being not yet available.\n// In case the 'Retry' flag is set, the startup of the plugin might be retried\n// depending on the configured startup-error-behavior. The 'RemovePlugin'\n// flag denotes if the agent should remove the plugin from further processing.\ntype StartupError struct {\n\tErr     error\n\tRetry   bool\n\tPartial bool\n}\n\nfunc (e *StartupError) Error() string {\n\treturn e.Err.Error()\n}\n\nfunc (e *StartupError) Unwrap() error {\n\treturn e.Err\n}\n\n// FatalError indicates a not-recoverable error in the plugin. The corresponding\n// plugin should be remove by the agent stopping any further processing for that\n// plugin instance.\ntype FatalError struct {\n\tErr error\n}\n\nfunc (e *FatalError) Error() string {\n\treturn e.Err.Error()\n}\n\nfunc (e *FatalError) Unwrap() error {\n\treturn e.Err\n}\n\n// PartialWriteError indicate that only a subset of the metrics were written\n// successfully (i.e. accepted). The rejected metrics should be removed from\n// the buffer without being successfully written. Please note: the metrics\n// are specified as indices into the batch to be able to reference tracking\n// metrics correctly.\ntype PartialWriteError struct {\n\tErr                 error\n\tMetricsAccept       []int\n\tMetricsReject       []int\n\tMetricsRejectErrors []error\n}\n\nfunc (e *PartialWriteError) Error() string {\n\treturn e.Err.Error()\n}\n\nfunc (e *PartialWriteError) Unwrap() error {\n\treturn e.Err\n}\n"
  },
  {
    "path": "internal/exec.go",
    "content": "package internal\n\nimport (\n\t\"bytes\"\n\t\"os/exec\"\n\t\"time\"\n)\n\n// CombinedOutputTimeout runs the given command with the given timeout and\n// returns the combined output of stdout and stderr.\n// If the command times out, it attempts to kill the process.\nfunc CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {\n\tvar b bytes.Buffer\n\tc.Stdout = &b\n\tc.Stderr = &b\n\tif err := c.Start(); err != nil {\n\t\treturn nil, err\n\t}\n\terr := WaitTimeout(c, timeout)\n\treturn b.Bytes(), err\n}\n\n// StdOutputTimeout runs the given command with the given timeout and\n// returns the output of stdout.\n// If the command times out, it attempts to kill the process.\nfunc StdOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {\n\tvar b bytes.Buffer\n\tc.Stdout = &b\n\tc.Stderr = nil\n\tif err := c.Start(); err != nil {\n\t\treturn nil, err\n\t}\n\terr := WaitTimeout(c, timeout)\n\treturn b.Bytes(), err\n}\n\n// RunTimeout runs the given command with the given timeout.\n// If the command times out, it attempts to kill the process.\nfunc RunTimeout(c *exec.Cmd, timeout time.Duration) error {\n\tif err := c.Start(); err != nil {\n\t\treturn err\n\t}\n\treturn WaitTimeout(c, timeout)\n}\n"
  },
  {
    "path": "internal/exec_unix.go",
    "content": "//go:build !windows\n\npackage internal\n\nimport (\n\t\"log\"\n\t\"os/exec\"\n\t\"syscall\"\n\t\"time\"\n)\n\n// KillGrace is the amount of time we allow a process to shutdown before\n// sending a SIGKILL.\nconst KillGrace = 5 * time.Second\n\n// WaitTimeout waits for the given command to finish with a timeout.\n// It assumes the command has already been started.\n// If the command times out, it attempts to kill the process.\nfunc WaitTimeout(c *exec.Cmd, timeout time.Duration) error {\n\tvar kill *time.Timer\n\tterm := time.AfterFunc(timeout, func() {\n\t\terr := syscall.Kill(-c.Process.Pid, syscall.SIGTERM)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"E! [agent] Error terminating process children: %s\", err)\n\t\t}\n\t\terr = c.Process.Signal(syscall.SIGTERM)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"E! [agent] Error terminating process: %s\", err)\n\t\t\treturn\n\t\t}\n\n\t\tkill = time.AfterFunc(KillGrace, func() {\n\t\t\terr := syscall.Kill(-c.Process.Pid, syscall.SIGKILL)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"E! [agent] Error terminating process children: %s\", err)\n\t\t\t}\n\t\t\terr = c.Process.Kill()\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"E! [agent] Error killing process: %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t})\n\n\terr := c.Wait()\n\n\t// Shutdown all timers\n\tif kill != nil {\n\t\tkill.Stop()\n\t}\n\ttermSent := !term.Stop()\n\n\t// If the process exited without error treat it as success.  This allows a\n\t// process to do a clean shutdown on signal.\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\t// If SIGTERM was sent then treat any process error as a timeout.\n\tif termSent {\n\t\treturn ErrTimeout\n\t}\n\n\t// Otherwise there was an error unrelated to termination.\n\treturn err\n}\n"
  },
  {
    "path": "internal/exec_windows.go",
    "content": "//go:build windows\n\npackage internal\n\nimport (\n\t\"log\"\n\t\"os/exec\"\n\t\"time\"\n)\n\n// WaitTimeout waits for the given command to finish with a timeout.\n// It assumes the command has already been started.\n// If the command times out, it attempts to kill the process.\nfunc WaitTimeout(c *exec.Cmd, timeout time.Duration) error {\n\ttimer := time.AfterFunc(timeout, func() {\n\t\terr := c.Process.Kill()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"E! [agent] Error killing process: %s\", err)\n\t\t\treturn\n\t\t}\n\t})\n\n\terr := c.Wait()\n\n\t// Shutdown all timers\n\ttermSent := !timer.Stop()\n\n\t// If the process exited without error treat it as success.  This allows a\n\t// process to do a clean shutdown on signal.\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\t// If SIGTERM was sent then treat any process error as a timeout.\n\tif termSent {\n\t\treturn ErrTimeout\n\t}\n\n\t// Otherwise there was an error unrelated to termination.\n\treturn err\n}\n"
  },
  {
    "path": "internal/fuzz/json.go",
    "content": "package fuzz\n\n// JSONDictionary from https://github.com/google/AFL/blob/master/dictionaries/json.dict\nvar JSONDictionary = []string{\n\t\"0\",\n\t\",0\",\n\t\":0\",\n\t\"0:\",\n\t\"-1.2e+3\",\n\t\"true\",\n\t\"false\",\n\t\"null\",\n\t\"\\\"\\\"\",\n\t\",\\\"\\\"\",\n\t\":\\\"\\\"\",\n\t\"\\\"\\\":\",\n\t\"{}\",\n\t\",{}\",\n\t\":{}\",\n\t\"{\\\"\\\":0}\",\n\t\"{{}}\",\n\t\"[]\",\n\t\",[]\",\n\t\":[]\",\n\t\"[0]\",\n\t\"[[]]\",\n\t\"''\",\n\t\"\\\\\",\n\t\"\\\\b\",\n\t\"\\\\f\",\n\t\"\\\\n\",\n\t\"\\\\r\",\n\t\"\\\\t\",\n\t\"\\\\u0000\",\n\t\"\\\\x00\",\n\t\"\\\\0\",\n\t\"\\\\uD800\\\\uDC00\",\n\t\"\\\\uDBFF\\\\uDFFF\",\n\t\"\\\"\\\":0\",\n\t\"//\",\n\t\"/**/\",\n}\n"
  },
  {
    "path": "internal/globpath/globpath.go",
    "content": "package globpath\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/bmatcuk/doublestar/v3\"\n\t\"github.com/gobwas/glob\"\n)\n\ntype GlobPath struct {\n\tpath         string\n\thasMeta      bool\n\tHasSuperMeta bool\n\trootGlob     string\n\tg            glob.Glob\n}\n\nfunc Compile(path string) (*GlobPath, error) {\n\tout := GlobPath{\n\t\thasMeta:      hasMeta(path),\n\t\tHasSuperMeta: hasSuperMeta(path),\n\t\tpath:         filepath.FromSlash(path),\n\t}\n\n\t// if there are no glob meta characters in the path, don't bother compiling\n\t// a glob object\n\tif !out.hasMeta || !out.HasSuperMeta {\n\t\treturn &out, nil\n\t}\n\n\t// find the root elements of the object path, the entry point for recursion\n\t// when you have a super-meta in your path (which are :\n\t// glob(/your/expression/until/first/star/of/super-meta))\n\tout.rootGlob = path[:strings.Index(path, \"**\")+1]\n\tvar err error\n\tif out.g, err = glob.Compile(path, os.PathSeparator); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &out, nil\n}\n\n// Match returns all files matching the expression.\n// If it's a static path, returns path.\n// All returned path will have the host platform separator.\nfunc (g *GlobPath) Match() []string {\n\t// This string replacement is for backwards compatibility support\n\t// The original implementation allowed **.txt but the double star package requires **/**.txt\n\tg.path = strings.ReplaceAll(g.path, \"**/**\", \"**\")\n\tg.path = strings.ReplaceAll(g.path, \"**\", \"**/**\")\n\n\t//nolint:errcheck // pattern is known\n\tfiles, _ := doublestar.Glob(g.path)\n\treturn files\n}\n\n// MatchString tests the path string against the glob.  The path should contain\n// the host platform separator.\nfunc (g *GlobPath) MatchString(path string) bool {\n\tif !g.HasSuperMeta {\n\t\t//nolint:errcheck // pattern is known\n\t\tres, _ := filepath.Match(g.path, path)\n\t\treturn res\n\t}\n\treturn g.g.Match(path)\n}\n\n// GetRoots returns a list of files and directories which should be optimal\n// prefixes of matching files when you have a super-meta in your expression :\n// - any directory under these roots may contain a matching file\n// - no file outside of these roots can match the pattern\n// Note that it returns both files and directories.\n// All returned path will have the host platform separator.\nfunc (g *GlobPath) GetRoots() []string {\n\tif !g.hasMeta {\n\t\treturn []string{g.path}\n\t}\n\tif !g.HasSuperMeta {\n\t\t//nolint:errcheck // pattern is known\n\t\tmatches, _ := filepath.Glob(g.path)\n\t\treturn matches\n\t}\n\t//nolint:errcheck // pattern is known\n\troots, _ := filepath.Glob(g.rootGlob)\n\treturn roots\n}\n\n// hasMeta reports whether path contains any magic glob characters.\nfunc hasMeta(path string) bool {\n\treturn strings.ContainsAny(path, \"*?[\")\n}\n\n// hasSuperMeta reports whether path contains any super magic glob characters (**).\nfunc hasSuperMeta(path string) bool {\n\treturn strings.Contains(path, \"**\")\n}\n"
  },
  {
    "path": "internal/globpath/globpath_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage globpath\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar (\n\ttestdataDir = getTestdataDir()\n)\n\nfunc TestCompileAndMatch(t *testing.T) {\n\ttype test struct {\n\t\tpath    string\n\t\tmatches int\n\t}\n\n\ttests := []test{\n\t\t// test super asterisk\n\t\t{path: filepath.Join(testdataDir, \"**\"), matches: 7},\n\t\t// test single asterisk\n\t\t{path: filepath.Join(testdataDir, \"*.log\"), matches: 3},\n\t\t// test no meta characters (file exists)\n\t\t{path: filepath.Join(testdataDir, \"log1.log\"), matches: 1},\n\t\t// test file that doesn't exist\n\t\t{path: filepath.Join(testdataDir, \"i_dont_exist.log\"), matches: 0},\n\t\t// test super asterisk that doesn't exist\n\t\t{path: filepath.Join(testdataDir, \"dir_doesnt_exist\", \"**\"), matches: 0},\n\t\t// test exclamation mark creates non-matching list with a range\n\t\t{path: filepath.Join(testdataDir, \"log[!1-2]*\"), matches: 1},\n\t\t// test caret creates non-matching list\n\t\t{path: filepath.Join(testdataDir, \"log[^1-2]*\"), matches: 1},\n\t\t// test exclamation mark creates non-matching list without a range\n\t\t{path: filepath.Join(testdataDir, \"log[!2]*\"), matches: 2},\n\t\t// test exclamation mark creates non-matching list without a range\n\t\t//nolint:gocritic // filepathJoin - '\\\\' used to escape in glob, not path separator\n\t\t{path: filepath.Join(testdataDir, \"log\\\\[!*\"), matches: 1},\n\t\t// test exclamation mark creates non-matching list without a range\n\t\t//nolint:gocritic // filepathJoin - '\\\\' used to escape in glob, not path separator\n\t\t{path: filepath.Join(testdataDir, \"log\\\\[^*\"), matches: 0},\n\t}\n\n\tfor _, tc := range tests {\n\t\tg, err := Compile(tc.path)\n\t\trequire.NoError(t, err)\n\t\tmatches := g.Match()\n\t\trequire.Len(t, matches, tc.matches)\n\t}\n}\n\nfunc TestRootGlob(t *testing.T) {\n\ttests := []struct {\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t{filepath.Join(testdataDir, \"**\"), filepath.Join(testdataDir, \"*\")},\n\t\t{filepath.Join(testdataDir, \"nested?\", \"**\"), filepath.Join(testdataDir, \"nested?\", \"*\")},\n\t\t{filepath.Join(testdataDir, \"ne**\", \"nest*\"), filepath.Join(testdataDir, \"ne*\")},\n\t\t{filepath.Join(testdataDir, \"nested?\", \"*\"), \"\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tactual, err := Compile(test.input)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, actual.rootGlob, test.output)\n\t}\n}\n\nfunc TestFindNestedTextFile(t *testing.T) {\n\t// test super asterisk\n\tg1, err := Compile(filepath.Join(testdataDir, \"**.txt\"))\n\trequire.NoError(t, err)\n\n\tmatches := g1.Match()\n\trequire.Len(t, matches, 1)\n}\n\nfunc TestMatch_ErrPermission(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected []string\n\t}{\n\t\t{\"/root/foo\", []string(nil)},\n\t\t{\"/root/f*\", []string(nil)},\n\t}\n\n\tfor _, test := range tests {\n\t\tglob, err := Compile(test.input)\n\t\trequire.NoError(t, err)\n\t\tactual := glob.Match()\n\t\trequire.Equal(t, test.expected, actual)\n\t}\n}\n\nfunc TestWindowsSeparator(t *testing.T) {\n\t//nolint:staticcheck // Silence linter for now as we plan to reenable tests for Windows later\n\tif runtime.GOOS != \"windows\" {\n\t\tt.Skip(\"Skipping Windows only test\")\n\t}\n\n\tglob, err := Compile(\"testdata/nested1\")\n\trequire.NoError(t, err)\n\tok := glob.MatchString(\"testdata\\\\nested1\")\n\trequire.True(t, ok)\n}\n\nfunc getTestdataDir() string {\n\tdir, err := os.Getwd()\n\tif err != nil {\n\t\t// if we cannot even establish the test directory, further progress is meaningless\n\t\tpanic(err)\n\t}\n\n\treturn filepath.Join(dir, \"testdata\")\n}\n"
  },
  {
    "path": "internal/globpath/testdata/log1.log",
    "content": ""
  },
  {
    "path": "internal/globpath/testdata/log2.log",
    "content": ""
  },
  {
    "path": "internal/globpath/testdata/log[!.log",
    "content": ""
  },
  {
    "path": "internal/globpath/testdata/nested1/nested2/nested.txt",
    "content": ""
  },
  {
    "path": "internal/globpath/testdata/test.conf",
    "content": "# this is a fake testing config file\n# for testing the filestat plugin\n\noption1 = \"foo\"\noption2 = \"bar\"\n"
  },
  {
    "path": "internal/goplugin/noplugin.go",
    "content": "//go:build !goplugin\n\npackage goplugin\n\nimport \"errors\"\n\nfunc LoadExternalPlugins(_ string) error {\n\treturn errors.New(\"go plugin support is not enabled\")\n}\n"
  },
  {
    "path": "internal/goplugin/plugin.go",
    "content": "//go:build goplugin\n\npackage goplugin\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"plugin\"\n\t\"strings\"\n)\n\n// loadExternalPlugins loads external plugins from shared libraries (.so, .dll, etc.)\n// in the specified directory.\nfunc LoadExternalPlugins(rootDir string) error {\n\treturn filepath.Walk(rootDir, func(pth string, info os.FileInfo, err error) error {\n\t\t// Stop if there was an error.\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Ignore directories.\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Ignore files that aren't shared libraries.\n\t\text := strings.ToLower(path.Ext(pth))\n\t\tif ext != \".so\" && ext != \".dll\" {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Load plugin.\n\t\t_, err = plugin.Open(pth)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error loading %s: %s\", pth, err)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/host_endianness_be.go",
    "content": "//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || sparc || sparc64\n\npackage internal\n\nimport \"encoding/binary\"\n\nvar HostEndianness = binary.BigEndian\n"
  },
  {
    "path": "internal/host_endianness_le.go",
    "content": "//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv || riscv64 || wasm\n\npackage internal\n\nimport \"encoding/binary\"\n\nvar HostEndianness = binary.LittleEndian\n"
  },
  {
    "path": "internal/http.go",
    "content": "package internal\n\nimport (\n\t\"crypto/subtle\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\ntype BasicAuthErrorFunc func(rw http.ResponseWriter)\n\n// JWTAuthHandler returns a http handler that requires the HTTP bearer auth\n// token to be valid and match the given user.\nfunc JWTAuthHandler(secret, username string, onError BasicAuthErrorFunc) func(h http.Handler) http.Handler {\n\treturn func(h http.Handler) http.Handler {\n\t\treturn &jwtAuthHandler{\n\t\t\tsecret:   []byte(secret),\n\t\t\tusername: []byte(username),\n\t\t\tonError:  onError,\n\t\t\tnext:     h,\n\t\t}\n\t}\n}\n\ntype jwtAuthHandler struct {\n\tsecret   []byte\n\tusername []byte\n\tonError  BasicAuthErrorFunc\n\tnext     http.Handler\n}\n\nfunc (h *jwtAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\tauthHeader := req.Header.Get(\"Authentication\")\n\tif !strings.HasPrefix(authHeader, \"Bearer \") {\n\t\th.onError(rw)\n\t\thttp.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)\n\t\treturn\n\t}\n\tbearer := strings.TrimPrefix(authHeader, \"Bearer \")\n\ttoken, err := jwt.Parse(bearer, func(t *jwt.Token) (interface{}, error) {\n\t\tif _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected signing method: %v\", t.Method)\n\t\t}\n\t\treturn h.secret, nil\n\t})\n\tif err != nil || !token.Valid {\n\t\th.onError(rw)\n\t\tif err != nil && errors.Is(err, jwt.ErrTokenExpired) {\n\t\t\thttp.Error(rw, \"token expired\", http.StatusUnauthorized)\n\t\t} else if err != nil {\n\t\t\thttp.Error(rw, \"invalid token: \"+err.Error(), http.StatusUnauthorized)\n\t\t} else {\n\t\t\thttp.Error(rw, \"invalid token\", http.StatusUnauthorized)\n\t\t}\n\t\treturn\n\t}\n\n\tclaims, ok := token.Claims.(jwt.MapClaims)\n\tif !ok {\n\t\th.onError(rw)\n\t\thttp.Error(rw, \"problem authenticating token\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tusername, ok := claims[\"username\"].(string)\n\tif !ok || username == \"\" {\n\t\th.onError(rw)\n\t\thttp.Error(rw, \"token must contain a string username\", http.StatusUnauthorized)\n\t\treturn\n\t}\n\tif subtle.ConstantTimeCompare([]byte(username), h.username) != 1 {\n\t\th.onError(rw)\n\t\thttp.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\th.next.ServeHTTP(rw, req)\n}\n\n// BasicAuthHandler returns a http handler that requires HTTP basic auth\n// credentials to match the given username and password.\nfunc BasicAuthHandler(username, password, realm string, onError BasicAuthErrorFunc) func(h http.Handler) http.Handler {\n\treturn func(h http.Handler) http.Handler {\n\t\treturn &basicAuthHandler{\n\t\t\tusername: username,\n\t\t\tpassword: password,\n\t\t\trealm:    realm,\n\t\t\tonError:  onError,\n\t\t\tnext:     h,\n\t\t}\n\t}\n}\n\ntype basicAuthHandler struct {\n\tusername string\n\tpassword string\n\trealm    string\n\tonError  BasicAuthErrorFunc\n\tnext     http.Handler\n}\n\nfunc (h *basicAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\tif h.username == \"\" && h.password == \"\" {\n\t\th.next.ServeHTTP(rw, req)\n\t\treturn\n\t}\n\n\tvar reqUsername, reqPassword string\n\tvar ok bool\n\tauthHeader := req.Header.Get(\"Authorization\")\n\tif strings.HasPrefix(authHeader, \"Token \") {\n\t\ttoken := strings.TrimPrefix(authHeader, \"Token \")\n\t\treqUsername, reqPassword, ok = strings.Cut(token, \":\")\n\t} else {\n\t\treqUsername, reqPassword, ok = req.BasicAuth()\n\t}\n\n\tif !ok ||\n\t\tsubtle.ConstantTimeCompare([]byte(reqUsername), []byte(h.username)) != 1 ||\n\t\tsubtle.ConstantTimeCompare([]byte(reqPassword), []byte(h.password)) != 1 {\n\t\trw.Header().Set(\"WWW-Authenticate\", \"Basic realm=\\\"\"+h.realm+\"\\\"\")\n\t\th.onError(rw)\n\t\thttp.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\th.next.ServeHTTP(rw, req)\n}\n\ntype GenericAuthErrorFunc func(rw http.ResponseWriter)\n\n// GenericAuthHandler returns a http handler that requires `Authorization: <credentials>`\nfunc GenericAuthHandler(credentials string, onError GenericAuthErrorFunc) func(h http.Handler) http.Handler {\n\treturn func(h http.Handler) http.Handler {\n\t\treturn &genericAuthHandler{\n\t\t\tcredentials: credentials,\n\t\t\tonError:     onError,\n\t\t\tnext:        h,\n\t\t}\n\t}\n}\n\n// Generic auth scheme handler - exact match on `Authorization: <credentials>`\ntype genericAuthHandler struct {\n\tcredentials string\n\tonError     GenericAuthErrorFunc\n\tnext        http.Handler\n}\n\nfunc (h *genericAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\tif h.credentials != \"\" {\n\t\t// Scheme checking\n\t\tauthorization := req.Header.Get(\"Authorization\")\n\t\tif subtle.ConstantTimeCompare([]byte(authorization), []byte(h.credentials)) != 1 {\n\t\t\th.onError(rw)\n\t\t\thttp.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t}\n\n\th.next.ServeHTTP(rw, req)\n}\n\n// ErrorFunc is a callback for writing an error response.\ntype ErrorFunc func(rw http.ResponseWriter, code int)\n\n// IPRangeHandler returns a http handler that requires the remote address to be\n// in the specified network.\nfunc IPRangeHandler(networks []*net.IPNet, onError ErrorFunc) func(h http.Handler) http.Handler {\n\treturn func(h http.Handler) http.Handler {\n\t\treturn &ipRangeHandler{\n\t\t\tnetworks: networks,\n\t\t\tonError:  onError,\n\t\t\tnext:     h,\n\t\t}\n\t}\n}\n\ntype ipRangeHandler struct {\n\tnetworks []*net.IPNet\n\tonError  ErrorFunc\n\tnext     http.Handler\n}\n\nfunc (h *ipRangeHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\tif len(h.networks) == 0 {\n\t\th.next.ServeHTTP(rw, req)\n\t\treturn\n\t}\n\n\tremoteIPString, _, err := net.SplitHostPort(req.RemoteAddr)\n\tif err != nil {\n\t\th.onError(rw, http.StatusForbidden)\n\t\treturn\n\t}\n\n\tremoteIP := net.ParseIP(remoteIPString)\n\tif remoteIP == nil {\n\t\th.onError(rw, http.StatusForbidden)\n\t\treturn\n\t}\n\n\tfor _, network := range h.networks {\n\t\tif network.Contains(remoteIP) {\n\t\t\th.next.ServeHTTP(rw, req)\n\t\t\treturn\n\t\t}\n\t}\n\n\th.onError(rw, http.StatusForbidden)\n}\n\nfunc OnClientError(client *http.Client, err error) {\n\t// Close connection after a timeout error. If this is a HTTP2\n\t// connection this ensures that next interval a new connection will be\n\t// used and name lookup will be performed.\n\t//   https://github.com/golang/go/issues/36026\n\tvar urlErr *url.Error\n\tif errors.As(err, &urlErr) && urlErr.Timeout() {\n\t\tclient.CloseIdleConnections()\n\t}\n}\n"
  },
  {
    "path": "internal/internal.go",
    "content": "package internal\n\nimport (\n\t\"bufio\"\n\t\"compress/gzip\"\n\t\"context\"\n\tcrypto_rand \"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math/big\"\n\t\"math/rand\"\n\t\"os\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n)\n\nconst alphanum string = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"\nconst NoMetricsCreatedMsg = \"No metrics were created from a message. Verify your parser settings. This message is only printed once.\"\n\nvar once sync.Once\n\nvar (\n\tErrTimeout        = errors.New(\"command timed out\")\n\tErrNotImplemented = errors.New(\"not implemented yet\")\n\n\t// Regexp for extracting the go version from runtime information\n\treGoVer = regexp.MustCompile(`go(\\d+\\.\\d+\\.\\d+).*`)\n)\n\n// Set via LDFLAGS -X\nvar (\n\tVersion = \"unknown\"\n\tBranch  = \"\"\n\tCommit  = \"\"\n)\n\ntype ReadWaitCloser struct {\n\tpipeReader *io.PipeReader\n\twg         sync.WaitGroup\n}\n\nfunc FormatFullVersion() string {\n\tvar parts = []string{\"Telegraf\"}\n\n\tif Version != \"\" {\n\t\tparts = append(parts, Version)\n\t} else {\n\t\tparts = append(parts, \"unknown\")\n\t}\n\n\tif Branch != \"\" || Commit != \"\" {\n\t\tif Branch == \"\" {\n\t\t\tBranch = \"unknown\"\n\t\t}\n\t\tif Commit == \"\" {\n\t\t\tCommit = \"unknown\"\n\t\t}\n\t\tgit := fmt.Sprintf(\"(git: %s@%s)\", Branch, Commit)\n\t\tparts = append(parts, git)\n\t}\n\n\treturn strings.Join(parts, \" \")\n}\n\n// ProductToken returns a tag for Telegraf that can be used in user agents.\nfunc ProductToken() string {\n\tgover := strings.TrimPrefix(runtime.Version(), \"go\")\n\tif g := reGoVer.FindStringSubmatch(runtime.Version()); len(g) == 2 {\n\t\tgover = g[1]\n\t}\n\n\treturn fmt.Sprintf(\"Telegraf/%s Go/%s\", Version, gover)\n}\n\n// ReadLines reads contents from a file and splits them by new lines.\nfunc ReadLines(filename string) ([]string, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\tdefer f.Close()\n\n\tvar ret []string\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tret = append(ret, scanner.Text())\n\t}\n\n\treturn ret, nil\n}\n\n// RandomString returns a random string of alphanumeric characters\nfunc RandomString(n int) (string, error) {\n\tvar bytes = make([]byte, n)\n\t_, err := crypto_rand.Read(bytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tfor i, b := range bytes {\n\t\tbytes[i] = alphanum[b%byte(len(alphanum))]\n\t}\n\treturn string(bytes), nil\n}\n\n// SnakeCase converts the given string to snake case following the Golang format:\n// acronyms are converted to lower-case and preceded by an underscore.\nfunc SnakeCase(in string) string {\n\trunes := []rune(in)\n\tlength := len(runes)\n\n\tvar out []rune\n\tfor i := 0; i < length; i++ {\n\t\tif i > 0 && unicode.IsUpper(runes[i]) {\n\t\t\tprevLower := unicode.IsLower(runes[i-1])\n\t\t\tnextLower := i+1 < length && unicode.IsLower(runes[i+1])\n\t\t\t// Special case for plural acronyms\n\t\t\tnextPlural := i+1 < length && runes[i+1] == 's'\n\n\t\t\tif prevLower || (nextLower && !nextPlural) {\n\t\t\t\tout = append(out, '_')\n\t\t\t}\n\t\t}\n\t\tout = append(out, unicode.ToLower(runes[i]))\n\t}\n\n\treturn string(out)\n}\n\n// RandomSleep will sleep for a random amount of time up to max.\n// If the shutdown channel is closed, it will return before it has finished sleeping.\nfunc RandomSleep(limit time.Duration, shutdown chan struct{}) {\n\tsleepDuration := RandomDuration(limit)\n\tif sleepDuration == 0 {\n\t\treturn\n\t}\n\n\tt := time.NewTimer(time.Nanosecond * sleepDuration)\n\tselect {\n\tcase <-t.C:\n\t\treturn\n\tcase <-shutdown:\n\t\tt.Stop()\n\t\treturn\n\t}\n}\n\n// RandomDuration returns a random duration between 0 and max.\nfunc RandomDuration(limit time.Duration) time.Duration {\n\tif limit == 0 {\n\t\treturn 0\n\t}\n\n\treturn time.Duration(rand.Int63n(limit.Nanoseconds())) //nolint:gosec // G404: not security critical\n}\n\n// SleepContext sleeps until the context is closed or the duration is reached.\nfunc SleepContext(ctx context.Context, duration time.Duration) error {\n\tif duration == 0 {\n\t\treturn nil\n\t}\n\n\tt := time.NewTimer(duration)\n\tselect {\n\tcase <-t.C:\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\tt.Stop()\n\t\treturn ctx.Err()\n\t}\n}\n\n// AlignDuration returns the duration until next aligned interval.\n// If the current time is aligned a 0 duration is returned.\nfunc AlignDuration(tm time.Time, interval time.Duration) time.Duration {\n\treturn AlignTime(tm, interval).Sub(tm)\n}\n\n// AlignTime returns the time of the next aligned interval.\n// If the current time is aligned the current time is returned.\nfunc AlignTime(tm time.Time, interval time.Duration) time.Time {\n\ttruncated := tm.Truncate(interval)\n\tif truncated.Equal(tm) {\n\t\treturn tm\n\t}\n\treturn truncated.Add(interval)\n}\n\n// ExitStatus takes the error from exec.Command\n// and returns the exit status and true\n// if error is not exit status, will return 0 and false\nfunc ExitStatus(err error) (int, bool) {\n\tvar exitErr *exec.ExitError\n\tif errors.As(err, &exitErr) {\n\t\tif status, ok := exitErr.Sys().(syscall.WaitStatus); ok {\n\t\t\treturn status.ExitStatus(), true\n\t\t}\n\t}\n\treturn 0, false\n}\n\nfunc (r *ReadWaitCloser) Close() error {\n\terr := r.pipeReader.Close()\n\tr.wg.Wait() // wait for the gzip goroutine finish\n\treturn err\n}\n\n// CompressWithGzip takes an io.Reader as input and pipes it through a\n// gzip.Writer returning an io.Reader containing the gzipped data.\n// Errors occurring during compression are returned to the instance reading\n// from the returned reader via through the corresponding read call\n// (e.g. io.Copy or io.ReadAll).\nfunc CompressWithGzip(data io.Reader) io.ReadCloser {\n\tpipeReader, pipeWriter := io.Pipe()\n\tgzipWriter := gzip.NewWriter(pipeWriter)\n\n\t// Start copying from the uncompressed reader to the output reader\n\t// in the background until the input reader is closed (or errors out).\n\tgo func() {\n\t\t// This copy will block until \"data\" reached EOF or an error occurs\n\t\t_, err := io.Copy(gzipWriter, data)\n\n\t\t// Close the compression writer and make sure we do not overwrite\n\t\t// the copy error if any.\n\t\tgzipErr := gzipWriter.Close()\n\t\tif err == nil {\n\t\t\terr = gzipErr\n\t\t}\n\n\t\t// Subsequent reads from the output reader (connected to \"pipeWriter\"\n\t\t// via pipe) will return the copy (or closing) error if any to the\n\t\t// instance reading from the reader returned by the CompressWithGzip\n\t\t// function. If \"err\" is nil, the below function will correctly report\n\t\t// io.EOF.\n\t\tpipeWriter.CloseWithError(err)\n\t}()\n\n\t// Return a reader which then can be read by the caller to collect the\n\t// compressed stream.\n\treturn pipeReader\n}\n\n// ParseTimestamp parses a Time according to the standard Telegraf options.\n// These are generally displayed in the toml similar to:\n//\n//\tjson_time_key= \"timestamp\"\n//\tjson_time_format = \"2006-01-02T15:04:05Z07:00\"\n//\tjson_timezone = \"America/Los_Angeles\"\n//\n// The format can be one of \"unix\", \"unix_ms\", \"unix_us\", \"unix_ns\", or a Go\n// time layout suitable for time.Parse.\n//\n// When using the \"unix\" format, an optional fractional component is allowed.\n// Specific unix time precisions cannot have a fractional component.\n//\n// Unix times may be an int64, float64, or string.  When using a Go format\n// string the timestamp must be a string.\n//\n// The location is a location string suitable for time.LoadLocation.  Unix\n// times do not use the location string, a unix time is always return in the\n// UTC location.\nfunc ParseTimestamp(format string, timestamp interface{}, location *time.Location, separator ...string) (time.Time, error) {\n\tswitch format {\n\tcase \"unix\", \"unix_ms\", \"unix_us\", \"unix_ns\":\n\t\tsep := []string{\",\", \".\"}\n\t\tif len(separator) > 0 {\n\t\t\tsep = separator\n\t\t}\n\t\treturn parseUnix(format, timestamp, sep)\n\tcase \"timestamp_tz\", \"timestamp_tz_ms\", \"timestamp_tz_us\", \"timestamp_tz_ns\":\n\t\tfmtUnix := \"unix\" + strings.TrimPrefix(format, \"timestamp_tz\")\n\t\tt, err := ParseTimestamp(fmtUnix, timestamp, location, separator...)\n\t\tif err != nil {\n\t\t\treturn t, err\n\t\t}\n\t\t_, offset := t.In(location).Zone()\n\t\treturn t.Add(-time.Duration(offset) * time.Second), nil\n\tdefault:\n\t\tv, ok := timestamp.(string)\n\t\tif !ok {\n\t\t\treturn time.Unix(0, 0), errors.New(\"unsupported type\")\n\t\t}\n\t\treturn parseTime(format, v, location)\n\t}\n}\n\n// parseTime parses a timestamp in unix format with different resolutions\nfunc parseUnix(format string, timestamp interface{}, separator []string) (time.Time, error) {\n\t// Extract the scaling factor to nanoseconds from \"format\"\n\tvar factor int64\n\tswitch format {\n\tcase \"unix\":\n\t\tfactor = int64(time.Second)\n\tcase \"unix_ms\":\n\t\tfactor = int64(time.Millisecond)\n\tcase \"unix_us\":\n\t\tfactor = int64(time.Microsecond)\n\tcase \"unix_ns\":\n\t\tfactor = int64(time.Nanosecond)\n\t}\n\n\tzero := time.Unix(0, 0)\n\n\t// Convert the representation to time\n\tswitch v := timestamp.(type) {\n\tcase int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:\n\t\tt, err := ToInt64(v)\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\t\treturn time.Unix(0, t*factor).UTC(), nil\n\tcase float32, float64:\n\t\tts, err := ToFloat64(v)\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\n\t\t// Parse the float as a precise fraction to avoid precision loss\n\t\tf := big.Rat{}\n\t\tif f.SetFloat64(ts) == nil {\n\t\t\treturn zero, errors.New(\"invalid number\")\n\t\t}\n\t\treturn timeFromFraction(&f, factor), nil\n\tcase string:\n\t\t// Sanitize the string to have no thousand separators and dot\n\t\t// as decimal separator to ease later parsing\n\t\tv = sanitizeTimestamp(v, separator)\n\n\t\t// Parse the string as a precise fraction to avoid precision loss\n\t\tf := big.Rat{}\n\t\tif _, ok := f.SetString(v); !ok {\n\t\t\treturn zero, errors.New(\"invalid number\")\n\t\t}\n\t\treturn timeFromFraction(&f, factor), nil\n\t}\n\n\treturn zero, errors.New(\"unsupported type\")\n}\n\nfunc timeFromFraction(f *big.Rat, factor int64) time.Time {\n\t// Extract the numerator and denominator and scale to nanoseconds\n\tnum := f.Num()\n\tdenom := f.Denom()\n\tnum.Mul(num, big.NewInt(factor))\n\n\t// Get the integer (non-fractional part) of the timestamp and convert\n\t// it into time\n\tt := big.Int{}\n\tt.Div(num, denom)\n\n\treturn time.Unix(0, t.Int64()).UTC()\n}\n\n// sanitizeTimestamp removes thousand separators and uses dot as\n// decimal separator. Returns also a boolean indicating success.\nfunc sanitizeTimestamp(timestamp string, decimalSeparator []string) string {\n\t// Remove thousand-separators that are not used for decimal separation\n\tsanitized := timestamp\n\tfor _, s := range []string{\" \", \",\", \".\"} {\n\t\tif !choice.Contains(s, decimalSeparator) {\n\t\t\tsanitized = strings.ReplaceAll(sanitized, s, \"\")\n\t\t}\n\t}\n\n\t// Replace decimal separators by dot to have a standard, parsable format\n\tfor _, s := range decimalSeparator {\n\t\t// Make sure we replace only the first occurrence of any separator.\n\t\tif strings.Contains(sanitized, s) {\n\t\t\treturn strings.Replace(sanitized, s, \".\", 1)\n\t\t}\n\t}\n\treturn sanitized\n}\n\n// parseTime parses a string timestamp according to the format string.\nfunc parseTime(format, timestamp string, location *time.Location) (time.Time, error) {\n\tloc := location\n\tif loc == nil {\n\t\tloc = time.UTC\n\t}\n\n\tswitch strings.ToLower(format) {\n\tcase \"ansic\":\n\t\tformat = time.ANSIC\n\tcase \"unixdate\":\n\t\tformat = time.UnixDate\n\tcase \"rubydate\":\n\t\tformat = time.RubyDate\n\tcase \"rfc822\":\n\t\tformat = time.RFC822\n\tcase \"rfc822z\":\n\t\tformat = time.RFC822Z\n\tcase \"rfc850\":\n\t\tformat = time.RFC850\n\tcase \"rfc1123\":\n\t\tformat = time.RFC1123\n\tcase \"rfc1123z\":\n\t\tformat = time.RFC1123Z\n\tcase \"rfc3339\":\n\t\tformat = time.RFC3339\n\tcase \"rfc3339nano\":\n\t\tformat = time.RFC3339Nano\n\tcase \"stamp\":\n\t\tformat = time.Stamp\n\tcase \"stampmilli\":\n\t\tformat = time.StampMilli\n\tcase \"stampmicro\":\n\t\tformat = time.StampMicro\n\tcase \"stampnano\":\n\t\tformat = time.StampNano\n\t}\n\n\tif !strings.Contains(format, \"MST\") {\n\t\treturn time.ParseInLocation(format, timestamp, loc)\n\t}\n\n\t// Golang does not parse times with ambiguous timezone abbreviations,\n\t// but only parses the time-fields and the timezone NAME with a zero\n\t// offset (see https://groups.google.com/g/golang-nuts/c/hDMdnm_jUFQ/m/yeL9IHOsAQAJ).\n\t// To handle those timezones correctly we can use the timezone-name and\n\t// force parsing the time in that timezone. This way we get the correct\n\t// time for the \"most probably\" of the ambiguous timezone-abbreviations.\n\tts, err := time.Parse(format, timestamp)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\tzone, offset := ts.Zone()\n\tif zone == \"UTC\" || offset != 0 {\n\t\treturn ts.In(loc), nil\n\t}\n\tonce.Do(func() {\n\t\tconst msg = `Your config is using abbreviated timezones and parsing was changed in v1.27.0!\n\t\tPlease see the change log, remove any workarounds in place, and carefully\n\t\tcheck your data timestamps! If case you experience any problems, please\n\t\tfile an issue on https://github.com/influxdata/telegraf/issues!`\n\t\tlog.Print(\"W! \" + msg)\n\t})\n\n\tabbrevLoc, err := time.LoadLocation(zone)\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"cannot resolve timezone abbreviation %q: %w\", zone, err)\n\t}\n\tts, err = time.ParseInLocation(format, timestamp, abbrevLoc)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\treturn ts.In(loc), nil\n}\n"
  },
  {
    "path": "internal/internal_test.go",
    "content": "package internal\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"crypto/rand\"\n\t\"io\"\n\t\"log\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype SnakeTest struct {\n\tinput  string\n\toutput string\n}\n\nvar tests = []SnakeTest{\n\t{\"a\", \"a\"},\n\t{\"snake\", \"snake\"},\n\t{\"A\", \"a\"},\n\t{\"ID\", \"id\"},\n\t{\"MOTD\", \"motd\"},\n\t{\"Snake\", \"snake\"},\n\t{\"SnakeTest\", \"snake_test\"},\n\t{\"APIResponse\", \"api_response\"},\n\t{\"SnakeID\", \"snake_id\"},\n\t{\"SnakeIDGoogle\", \"snake_id_google\"},\n\t{\"LinuxMOTD\", \"linux_motd\"},\n\t{\"OMGWTFBBQ\", \"omgwtfbbq\"},\n\t{\"omg_wtf_bbq\", \"omg_wtf_bbq\"},\n\t{\"ConsumedLCUs\", \"consumed_lcus\"},\n}\n\nfunc TestSnakeCase(t *testing.T) {\n\tfor _, test := range tests {\n\t\tt.Run(test.input, func(t *testing.T) {\n\t\t\trequire.Equal(t, test.output, SnakeCase(test.input))\n\t\t})\n\t}\n}\n\nfunc TestRunTimeout(t *testing.T) {\n\tt.Skip(\"Skipping test due to random failures & a data race when running test-all.\")\n\n\tsleepbin, err := exec.LookPath(\"sleep\")\n\tif err != nil || sleepbin == \"\" {\n\t\tt.Skip(\"'sleep' binary not available on OS, skipping.\")\n\t}\n\n\tcmd := exec.Command(sleepbin, \"10\")\n\tstart := time.Now()\n\terr = RunTimeout(cmd, time.Millisecond*20)\n\telapsed := time.Since(start)\n\n\trequire.Equal(t, ErrTimeout, err)\n\t// Verify that command gets killed in 20ms, with some breathing room\n\trequire.Less(t, elapsed, time.Millisecond*75)\n}\n\n// Verifies behavior of a command that doesn't get killed.\nfunc TestRunTimeoutFastExit(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping test due to random failures.\")\n\t}\n\techobin, err := exec.LookPath(\"echo\")\n\tif err != nil || echobin == \"\" {\n\t\tt.Skip(\"'echo' binary not available on OS, skipping.\")\n\t}\n\tcmd := exec.Command(echobin)\n\tstart := time.Now()\n\terr = RunTimeout(cmd, time.Millisecond*20)\n\tbuf := &bytes.Buffer{}\n\tlog.SetOutput(buf)\n\telapsed := time.Since(start)\n\n\trequire.NoError(t, err)\n\t// Verify that command gets killed in 20ms, with some breathing room\n\trequire.Less(t, elapsed, time.Millisecond*75)\n\n\t// Verify \"process already finished\" log doesn't occur.\n\ttime.Sleep(time.Millisecond * 75)\n\trequire.Empty(t, buf.String())\n}\n\nfunc TestCombinedOutputTimeout(t *testing.T) {\n\t// TODO: Fix this test\n\tt.Skip(\"Test failing too often, skip for now and revisit later.\")\n\tsleepbin, err := exec.LookPath(\"sleep\")\n\tif err != nil || sleepbin == \"\" {\n\t\tt.Skip(\"'sleep' binary not available on OS, skipping.\")\n\t}\n\tcmd := exec.Command(sleepbin, \"10\")\n\tstart := time.Now()\n\t_, err = CombinedOutputTimeout(cmd, time.Millisecond*20)\n\telapsed := time.Since(start)\n\n\trequire.Equal(t, ErrTimeout, err)\n\t// Verify that command gets killed in 20ms, with some breathing room\n\trequire.Less(t, elapsed, time.Millisecond*75)\n}\n\nfunc TestCombinedOutput(t *testing.T) {\n\techobin, err := exec.LookPath(\"echo\")\n\tif err != nil || echobin == \"\" {\n\t\tt.Skip(\"'echo' binary not available on OS, skipping.\")\n\t}\n\tcmd := exec.Command(echobin, \"foo\")\n\tout, err := CombinedOutputTimeout(cmd, time.Second)\n\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"foo\\n\", string(out))\n}\n\n// test that CombinedOutputTimeout and exec.Cmd.CombinedOutput return\n// the same output from a failed command.\nfunc TestCombinedOutputError(t *testing.T) {\n\tshell, err := exec.LookPath(\"sh\")\n\tif err != nil || shell == \"\" {\n\t\tt.Skip(\"'sh' binary not available on OS, skipping.\")\n\t}\n\tcmd := exec.Command(shell, \"-c\", \"false\")\n\texpected, err := cmd.CombinedOutput()\n\trequire.Error(t, err)\n\n\tcmd2 := exec.Command(shell, \"-c\", \"false\")\n\tactual, err := CombinedOutputTimeout(cmd2, time.Second)\n\n\trequire.Error(t, err)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunError(t *testing.T) {\n\tshell, err := exec.LookPath(\"sh\")\n\tif err != nil || shell == \"\" {\n\t\tt.Skip(\"'sh' binary not available on OS, skipping.\")\n\t}\n\tcmd := exec.Command(shell, \"-c\", \"false\")\n\terr = RunTimeout(cmd, time.Second)\n\n\trequire.Error(t, err)\n}\n\nfunc TestRandomSleep(t *testing.T) {\n\t// TODO: Fix this test\n\tt.Skip(\"Test failing too often, skip for now and revisit later.\")\n\t// test that zero max returns immediately\n\ts := time.Now()\n\tRandomSleep(time.Duration(0), make(chan struct{}))\n\telapsed := time.Since(s)\n\trequire.Less(t, elapsed, time.Millisecond)\n\n\t// test that max sleep is respected\n\ts = time.Now()\n\tRandomSleep(time.Millisecond*50, make(chan struct{}))\n\telapsed = time.Since(s)\n\trequire.Less(t, elapsed, time.Millisecond*100)\n\n\t// test that shutdown is respected\n\ts = time.Now()\n\tshutdown := make(chan struct{})\n\tgo func() {\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tclose(shutdown)\n\t}()\n\tRandomSleep(time.Second, shutdown)\n\telapsed = time.Since(s)\n\trequire.Less(t, elapsed, time.Millisecond*150)\n}\n\nfunc TestCompressWithGzip(t *testing.T) {\n\ttestData := \"the quick brown fox jumps over the lazy dog\"\n\tinputBuffer := bytes.NewBufferString(testData)\n\n\toutputBuffer := CompressWithGzip(inputBuffer)\n\tgzipReader, err := gzip.NewReader(outputBuffer)\n\trequire.NoError(t, err)\n\tdefer gzipReader.Close()\n\n\toutput, err := io.ReadAll(gzipReader)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, testData, string(output))\n}\n\ntype mockReader struct {\n\terr    error\n\tncalls uint64 // record the number of calls to Read\n\tmsg    []byte\n}\n\nfunc (r *mockReader) Read(p []byte) (n int, err error) {\n\tr.ncalls++\n\n\tif len(r.msg) > 0 {\n\t\tn, err = copy(p, r.msg), io.EOF\n\t} else {\n\t\tn, err = rand.Read(p)\n\t}\n\tif r.err == nil {\n\t\treturn n, err\n\t}\n\treturn n, r.err\n}\n\nfunc TestCompressWithGzipEarlyClose(t *testing.T) {\n\tmr := &mockReader{}\n\n\trc := CompressWithGzip(mr)\n\tn, err := io.CopyN(io.Discard, rc, 10000)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(10000), n)\n\n\tr1 := mr.ncalls\n\trequire.NoError(t, rc.Close())\n\n\tn, err = io.CopyN(io.Discard, rc, 10000)\n\trequire.ErrorIs(t, err, io.ErrClosedPipe)\n\trequire.Equal(t, int64(0), n)\n\n\tr2 := mr.ncalls\n\t// no more read to the source after closing\n\trequire.Equal(t, r1, r2)\n}\n\nfunc TestCompressWithGzipErrorPropagationCopy(t *testing.T) {\n\terrs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF}\n\tfor _, expected := range errs {\n\t\tr := &mockReader{msg: []byte(\"this is a test\"), err: expected}\n\n\t\trc := CompressWithGzip(r)\n\t\tn, err := io.Copy(io.Discard, rc)\n\t\trequire.Positive(t, n)\n\t\trequire.ErrorIs(t, err, expected)\n\t\trequire.NoError(t, rc.Close())\n\t}\n}\n\nfunc TestCompressWithGzipErrorPropagationReadAll(t *testing.T) {\n\terrs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF}\n\tfor _, expected := range errs {\n\t\tr := &mockReader{msg: []byte(\"this is a test\"), err: expected}\n\n\t\trc := CompressWithGzip(r)\n\t\tbuf, err := io.ReadAll(rc)\n\t\trequire.NotEmpty(t, buf)\n\t\trequire.ErrorIs(t, err, expected)\n\t\trequire.NoError(t, rc.Close())\n\t}\n}\n\nfunc TestAlignDuration(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tnow      time.Time\n\t\tinterval time.Duration\n\t\texpected time.Duration\n\t}{\n\t\t{\n\t\t\tname:     \"aligned\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC),\n\t\t\tinterval: 10 * time.Second,\n\t\t\texpected: 0 * time.Second,\n\t\t},\n\t\t{\n\t\t\tname:     \"standard interval\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC),\n\t\t\tinterval: 10 * time.Second,\n\t\t\texpected: 9 * time.Second,\n\t\t},\n\t\t{\n\t\t\tname:     \"odd interval\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC),\n\t\t\tinterval: 3 * time.Second,\n\t\t\texpected: 2 * time.Second,\n\t\t},\n\t\t{\n\t\t\tname:     \"sub second interval\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 1, 0, 5e8, time.UTC),\n\t\t\tinterval: 1 * time.Second,\n\t\t\texpected: 500 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:     \"non divisible not aligned on minutes\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 0, 0, 0, time.UTC),\n\t\t\tinterval: 1*time.Second + 100*time.Millisecond,\n\t\t\texpected: 400 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:     \"long interval\",\n\t\t\tnow:      time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC),\n\t\t\tinterval: 1 * time.Hour,\n\t\t\texpected: 59 * time.Minute,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual := AlignDuration(tt.now, tt.interval)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestAlignTime(t *testing.T) {\n\trfc3339 := func(value string) time.Time {\n\t\ttt, err := time.Parse(time.RFC3339, value)\n\t\trequire.NoError(t, err)\n\t\treturn tt\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\tnow      time.Time\n\t\tinterval time.Duration\n\t\texpected time.Time\n\t}{\n\t\t{\n\t\t\tname:     \"aligned\",\n\t\t\tnow:      rfc3339(\"2018-01-01T01:01:00Z\"),\n\t\t\tinterval: 10 * time.Second,\n\t\t\texpected: rfc3339(\"2018-01-01T01:01:00Z\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"aligned\",\n\t\t\tnow:      rfc3339(\"2018-01-01T01:01:01Z\"),\n\t\t\tinterval: 10 * time.Second,\n\t\t\texpected: rfc3339(\"2018-01-01T01:01:10Z\"),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual := AlignTime(tt.now, tt.interval)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestParseTimestamp(t *testing.T) {\n\trfc3339 := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.RFC3339Nano, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\tansic := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.ANSIC, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\trubydate := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.RubyDate, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\trfc822z := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.RFC822Z, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\trfc1123z := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.RFC1123Z, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\trfc3339nano := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.RFC3339Nano, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\tstamp := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.Stamp, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\tstampmilli := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.StampMilli, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\tstampmicro := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.StampMicro, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\tstampnano := func(value string) time.Time {\n\t\ttm, err := time.Parse(time.StampNano, value)\n\t\trequire.NoError(t, err)\n\t\treturn tm\n\t}\n\n\ttests := []struct {\n\t\tname      string\n\t\tformat    string\n\t\ttimestamp interface{}\n\t\tlocation  string\n\t\tseparator []string\n\t\texpected  time.Time\n\t}{\n\t\t{\n\t\t\tname:      \"parse layout string in utc\",\n\t\t\tformat:    \"2006-01-02 15:04:05\",\n\t\t\ttimestamp: \"2019-02-20 21:50:34\",\n\t\t\tlocation:  \"UTC\",\n\t\t\texpected:  rfc3339(\"2019-02-20T21:50:34Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"layout regression 6386\",\n\t\t\tformat:    \"02.01.2006 15:04:05\",\n\t\t\ttimestamp: \"09.07.2019 00:11:00\",\n\t\t\texpected:  rfc3339(\"2019-07-09T00:11:00Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"default location is utc\",\n\t\t\tformat:    \"2006-01-02 15:04:05\",\n\t\t\ttimestamp: \"2019-02-20 21:50:34\",\n\t\t\texpected:  rfc3339(\"2019-02-20T21:50:34Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds without fractional\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338208\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with fractional\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338208.500\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with fractional and comma decimal point\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338208,500\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds extra precision\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338208.00000050042\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand separator only (dot)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1.568.338.208\",\n\t\t\tseparator: []string{\",\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand separator only (comma)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1,568,338,208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand separator only (space)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1 568 338 208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand separator only (underscore)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1_568_338_208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand and decimal separator (US)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1,568,338,208.500\",\n\t\t\tseparator: []string{\".\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds with thousand and decimal separator (EU)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1.568.338.208,500\",\n\t\t\tseparator: []string{\",\"},\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds integer\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: int64(1568338208),\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds float\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: float64(1568338208.500),\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix seconds float exponential\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: float64(1.5683382085e+9),\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix milliseconds\",\n\t\t\tformat:    \"unix_ms\",\n\t\t\ttimestamp: \"1568338208500\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix milliseconds with fractional\",\n\t\t\tformat:    \"unix_ms\",\n\t\t\ttimestamp: \"1568338208500.42\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.50042Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix microseconds\",\n\t\t\tformat:    \"unix_us\",\n\t\t\ttimestamp: \"1568338208000500\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix nanoseconds\",\n\t\t\tformat:    \"unix_ns\",\n\t\t\ttimestamp: \"1568338208000000500\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"unix nanoseconds exponential\",\n\t\t\tformat:    \"unix_ns\",\n\t\t\ttimestamp: \"1.5683382080000005e+18\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500Z\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds without fractional\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1568338208\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with fractional\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1568338208.500\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with fractional and comma decimal point\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1568338208,500\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds extra precision\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1568338208.00000050042\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand separator only (dot)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1.568.338.208\",\n\t\t\tseparator: []string{\",\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand separator only (comma)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1,568,338,208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand separator only (space)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1 568 338 208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand separator only (underscore)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1_568_338_208\",\n\t\t\tseparator: []string{\".\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand and decimal separator (US)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1,568,338,208.500\",\n\t\t\tseparator: []string{\".\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds with thousand and decimal separator (EU)\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: \"1.568.338.208,500\",\n\t\t\tseparator: []string{\",\"},\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds integer\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: int64(1568338208),\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds float\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: float64(1568338208.500),\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone seconds float exponential\",\n\t\t\tformat:    \"timestamp_tz\",\n\t\t\ttimestamp: float64(1.5683382085e+9),\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone milliseconds\",\n\t\t\tformat:    \"timestamp_tz_ms\",\n\t\t\ttimestamp: \"1568338208500\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone milliseconds with fractional\",\n\t\t\tformat:    \"timestamp_tz_ms\",\n\t\t\ttimestamp: \"1568338208500.42\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.50042+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone microseconds\",\n\t\t\tformat:    \"timestamp_tz_us\",\n\t\t\ttimestamp: \"1568338208000500\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone nanoseconds\",\n\t\t\tformat:    \"timestamp_tz_ns\",\n\t\t\ttimestamp: \"1568338208000000500\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"timestamp with timezone nanoseconds exponential\",\n\t\t\tformat:    \"timestamp_tz_ns\",\n\t\t\ttimestamp: \"1.5683382080000005e+18\",\n\t\t\tlocation:  \"Pacific/Fiji\",\n\t\t\texpected:  rfc3339(\"2019-09-13T01:30:08.000000500+12:00\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"rfc339 test\",\n\t\t\tformat:    \"RFC3339\",\n\t\t\ttimestamp: \"2018-10-26T13:30:33Z\",\n\t\t\texpected:  rfc3339(\"2018-10-26T13:30:33Z\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"ANSIC\",\n\t\t\tformat:    \"ANSIC\",\n\t\t\ttimestamp: \"Mon Jan 2 15:04:05 2006\",\n\t\t\texpected:  ansic(\"Mon Jan 2 15:04:05 2006\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"UnixDate\",\n\t\t\tformat:    \"UnixDate\",\n\t\t\ttimestamp: \"Mon Jan 2 15:04:05 MST 2006\",\n\t\t\texpected:  time.Unix(1136239445, 0),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RubyDate\",\n\t\t\tformat:    \"RubyDate\",\n\t\t\ttimestamp: \"Mon Jan 02 15:04:05 -0700 2006\",\n\t\t\texpected:  rubydate(\"Mon Jan 02 15:04:05 -0700 2006\"),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC822\",\n\t\t\tformat:    \"RFC822\",\n\t\t\ttimestamp: \"02 Jan 06 15:04 MST\",\n\t\t\texpected:  time.Unix(1136239440, 0),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC822Z\",\n\t\t\tformat:    \"RFC822Z\",\n\t\t\ttimestamp: \"02 Jan 06 15:04 -0700\",\n\t\t\texpected:  rfc822z(\"02 Jan 06 15:04 -0700\"),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC850\",\n\t\t\tformat:    \"RFC850\",\n\t\t\ttimestamp: \"Monday, 02-Jan-06 15:04:05 MST\",\n\t\t\texpected:  time.Unix(1136239445, 0),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC1123\",\n\t\t\tformat:    \"RFC1123\",\n\t\t\ttimestamp: \"Mon, 02 Jan 2006 15:04:05 MST\",\n\t\t\texpected:  time.Unix(1136239445, 0),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC1123Z\",\n\t\t\tformat:    \"RFC1123Z\",\n\t\t\ttimestamp: \"Mon, 02 Jan 2006 15:04:05 -0700\",\n\t\t\texpected:  rfc1123z(\"Mon, 02 Jan 2006 15:04:05 -0700\"),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC3339Nano\",\n\t\t\tformat:    \"RFC3339Nano\",\n\t\t\ttimestamp: \"2006-01-02T15:04:05.999999999-07:00\",\n\t\t\texpected:  rfc3339nano(\"2006-01-02T15:04:05.999999999-07:00\"),\n\t\t\tlocation:  \"Local\",\n\t\t},\n\n\t\t{\n\t\t\tname:      \"Stamp\",\n\t\t\tformat:    \"Stamp\",\n\t\t\ttimestamp: \"Jan 2 15:04:05\",\n\t\t\texpected:  stamp(\"Jan 2 15:04:05\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"StampMilli\",\n\t\t\tformat:    \"StampMilli\",\n\t\t\ttimestamp: \"Jan 2 15:04:05.000\",\n\t\t\texpected:  stampmilli(\"Jan 2 15:04:05.000\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"StampMicro\",\n\t\t\tformat:    \"StampMicro\",\n\t\t\ttimestamp: \"Jan 2 15:04:05.000000\",\n\t\t\texpected:  stampmicro(\"Jan 2 15:04:05.000000\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"StampNano\",\n\t\t\tformat:    \"StampNano\",\n\t\t\ttimestamp: \"Jan 2 15:04:05.000000000\",\n\t\t\texpected:  stampnano(\"Jan 2 15:04:05.000000000\"),\n\t\t},\n\n\t\t{\n\t\t\tname:      \"RFC850\",\n\t\t\tformat:    \"RFC850\",\n\t\t\ttimestamp: \"Monday, 02-Jan-06 15:04:05 MST\",\n\t\t\texpected:  time.Unix(1136239445, 0),\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Ensure any one-time warnings are printed for each test\n\t\t\tonce = sync.Once{}\n\n\t\t\t// Ensure the warnings are captured and not to stdout\n\t\t\tvar buf bytes.Buffer\n\t\t\tbackup := log.Writer()\n\t\t\tlog.SetOutput(&buf)\n\t\t\tdefer log.SetOutput(backup)\n\n\t\t\tvar loc *time.Location\n\t\t\tif tt.location != \"\" {\n\t\t\t\tvar err error\n\t\t\t\tloc, err = time.LoadLocation(tt.location)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\ttm, err := ParseTimestamp(tt.format, tt.timestamp, loc, tt.separator...)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected.Unix(), tm.Unix())\n\t\t})\n\t}\n}\n\nfunc TestParseTimestampInvalid(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tformat    string\n\t\ttimestamp interface{}\n\t\texpected  string\n\t}{\n\t\t{\n\t\t\tname:      \"too few digits\",\n\t\t\tformat:    \"2006-01-02 15:04:05\",\n\t\t\ttimestamp: \"2019-02-20 21:50\",\n\t\t\texpected:  \"cannot parse \\\"\\\" as \\\":\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"invalid layout\",\n\t\t\tformat:    \"rfc3399\",\n\t\t\ttimestamp: \"09.07.2019 00:11:00\",\n\t\t\texpected:  \"cannot parse \\\"09.07.2019 00:11:00\\\" as \\\"rfc\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"layout not matching time\",\n\t\t\tformat:    \"rfc3339\",\n\t\t\ttimestamp: \"09.07.2019 00:11:00\",\n\t\t\texpected:  \"parsing time \\\"09.07.2019 00:11:00\\\" as \\\"2006-01-02T15:04:05Z07:00\\\": cannot parse\",\n\t\t},\n\t\t{\n\t\t\tname:      \"unix wrong type\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: true,\n\t\t\texpected:  \"unsupported type\",\n\t\t},\n\t\t{\n\t\t\tname:      \"unix multiple separators (dot)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338.208.500\",\n\t\t\texpected:  \"invalid number\",\n\t\t},\n\t\t{\n\t\t\tname:      \"unix multiple separators (comma)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1568338,208,500\",\n\t\t\texpected:  \"invalid number\",\n\t\t},\n\t\t{\n\t\t\tname:      \"unix multiple separators (mixed)\",\n\t\t\tformat:    \"unix\",\n\t\t\ttimestamp: \"1,568,338,208.500\",\n\t\t\texpected:  \"invalid number\",\n\t\t},\n\t\t{\n\t\t\tname:      \"invalid timezone abbreviation\",\n\t\t\tformat:    \"RFC850\",\n\t\t\ttimestamp: \"Monday, 02-Jan-06 15:04:05 CDT\",\n\t\t\texpected:  \"cannot resolve timezone abbreviation\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Ensure any one-time warnings are printed for each test\n\t\t\tonce = sync.Once{}\n\n\t\t\t// Ensure the warnings are captured and not to stdout\n\t\t\tvar buf bytes.Buffer\n\t\t\tbackup := log.Writer()\n\t\t\tlog.SetOutput(&buf)\n\t\t\tdefer log.SetOutput(backup)\n\n\t\t\t_, err := ParseTimestamp(tt.format, tt.timestamp, nil)\n\t\t\trequire.ErrorContains(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestTimestampAbbrevWarning(t *testing.T) {\n\t// Ensure any one-time warnings are printed for each test\n\tonce = sync.Once{}\n\n\t// Ensure the warnings are captured and not to stdout\n\tvar buf bytes.Buffer\n\tbackup := log.Writer()\n\tlog.SetOutput(&buf)\n\tdefer log.SetOutput(backup)\n\n\t// Try multiple timestamps with abbreviated timezones in case a user\n\t// is actually in one of the timezones.\n\tts, err := ParseTimestamp(\"RFC1123\", \"Mon, 02 Jan 2006 15:04:05 MST\", nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 1136239445, ts.Unix())\n\n\tts2, err := ParseTimestamp(\"RFC1123\", \"Mon, 02 Jan 2006 15:04:05 EST\", nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 1136232245, ts2.Unix())\n\n\trequire.Contains(t, buf.String(), \"Your config is using abbreviated timezones and parsing was changed in v1.27.0\")\n}\n\nfunc TestGoVersion(t *testing.T) {\n\ttests := []struct {\n\t\tversion  string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tversion:  \"go version go1.24.0 linux/amd64\",\n\t\t\texpected: \"1.24.0\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"go version go1.25.2 X:nodwarf5 linux/amd64\",\n\t\t\texpected: \"1.25.2\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"go version go1.26.1-X:nodwarf5 linux/amd64\",\n\t\t\texpected: \"1.26.1\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.version, func(t *testing.T) {\n\t\t\tmatch := reGoVer.FindStringSubmatch(tt.version)\n\t\t\trequire.Len(t, match, 2)\n\t\t\trequire.Equal(t, tt.expected, match[1])\n\t\t})\n\t}\n}\n\nfunc TestProductToken(t *testing.T) {\n\ttoken := ProductToken()\n\t// Telegraf version depends on the call to SetVersion, it cannot be set\n\t// multiple times and is not thread-safe.\n\tre := regexp.MustCompile(`^Telegraf/[^\\s]+ Go/\\d+.\\d+(.\\d+)?$`)\n\trequire.True(t, re.MatchString(token), token)\n}\n"
  },
  {
    "path": "internal/limiter/limiter.go",
    "content": "package limiter\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\n// NewRateLimiter returns a rate limiter that will emit from the C\n// channel only 'n' times every 'rate' seconds.\nfunc NewRateLimiter(n int, rate time.Duration) *rateLimiter {\n\tr := &rateLimiter{\n\t\tC:        make(chan bool),\n\t\trate:     rate,\n\t\tn:        n,\n\t\tshutdown: make(chan bool),\n\t}\n\tr.wg.Add(1)\n\tgo r.limiter()\n\treturn r\n}\n\ntype rateLimiter struct {\n\tC    chan bool\n\trate time.Duration\n\tn    int\n\n\tshutdown chan bool\n\twg       sync.WaitGroup\n}\n\nfunc (r *rateLimiter) Stop() {\n\tclose(r.shutdown)\n\tr.wg.Wait()\n\tclose(r.C)\n}\n\nfunc (r *rateLimiter) limiter() {\n\tdefer r.wg.Done()\n\tticker := time.NewTicker(r.rate)\n\tdefer ticker.Stop()\n\tcounter := 0\n\tfor {\n\t\tselect {\n\t\tcase <-r.shutdown:\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t\tcounter = 0\n\t\tdefault:\n\t\t\tif counter < r.n {\n\t\t\t\tselect {\n\t\t\t\tcase r.C <- true:\n\t\t\t\t\tcounter++\n\t\t\t\tcase <-r.shutdown:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/network.go",
    "content": "package internal\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc ResolveLocalTCPAddress(addr string) (*net.TCPAddr, error) {\n\t// Resolve the local address into IP address and the given port if any\n\thost, port, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\tif !strings.Contains(err.Error(), \"missing port\") {\n\t\t\treturn nil, fmt.Errorf(\"invalid local address: %w\", err)\n\t\t}\n\t\thost = addr\n\t}\n\tlocal, err := net.ResolveIPAddr(\"ip\", host)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot resolve local address: %w\", err)\n\t}\n\n\tvar portNo int\n\tif port != \"\" {\n\t\tp, err := strconv.ParseUint(port, 10, 16)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid port: %w\", err)\n\t\t}\n\t\tportNo = int(p)\n\t}\n\n\treturn &net.TCPAddr{IP: local.IP, Port: portNo, Zone: local.Zone}, nil\n}\n"
  },
  {
    "path": "internal/process/process.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Process is a long-running process manager that will restart processes if they stop.\ntype Process struct {\n\tCmd          *exec.Cmd\n\tStdin        io.WriteCloser\n\tStdout       io.ReadCloser\n\tStderr       io.ReadCloser\n\tReadStdoutFn func(io.Reader)\n\tReadStderrFn func(io.Reader)\n\tRestartDelay time.Duration\n\tStopOnError  bool\n\tLog          telegraf.Logger\n\n\tname       string\n\targs       []string\n\tenvs       []string\n\tpid        int32\n\tcancel     context.CancelFunc\n\tmainLoopWg sync.WaitGroup\n\n\tsync.Mutex\n}\n\n// New creates a new process wrapper\nfunc New(command, envs []string) (*Process, error) {\n\tif len(command) == 0 {\n\t\treturn nil, errors.New(\"no command\")\n\t}\n\n\tp := &Process{\n\t\tRestartDelay: 5 * time.Second,\n\t\tname:         command[0],\n\t\targs:         make([]string, 0),\n\t\tenvs:         envs,\n\t}\n\n\tif len(command) > 1 {\n\t\tp.args = command[1:]\n\t}\n\n\treturn p, nil\n}\n\n// Start the process. A &Process can only be started once. It will restart itself\n// as necessary.\nfunc (p *Process) Start() error {\n\tctx, cancel := context.WithCancel(context.Background())\n\tp.cancel = cancel\n\n\tif err := p.cmdStart(); err != nil {\n\t\treturn err\n\t}\n\n\tp.mainLoopWg.Add(1)\n\tgo func() {\n\t\tdefer p.mainLoopWg.Done()\n\t\tif err := p.cmdLoop(ctx); err != nil {\n\t\t\tp.Log.Errorf(\"Process quit with message: %v\", err)\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// Stop is called when the process isn't needed anymore\nfunc (p *Process) Stop() {\n\tif p.cancel != nil {\n\t\t// signal our intent to shut down and not restart the process\n\t\tp.cancel()\n\t}\n\t// close stdin so the app can shut down gracefully.\n\tif err := p.Stdin.Close(); err != nil && !errors.Is(err, os.ErrClosed) {\n\t\tp.Log.Errorf(\"Stdin closed with message: %v\", err)\n\t}\n\tp.mainLoopWg.Wait()\n}\n\nfunc (p *Process) Pid() int {\n\tpid := atomic.LoadInt32(&p.pid)\n\treturn int(pid)\n}\n\nfunc (p *Process) State() (state *os.ProcessState, running bool) {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\treturn p.Cmd.ProcessState, p.Cmd.ProcessState.ExitCode() == -1\n}\n\nfunc (p *Process) cmdStart() error {\n\tp.Cmd = exec.Command(p.name, p.args...)\n\n\tif len(p.envs) > 0 {\n\t\tp.Cmd.Env = append(os.Environ(), p.envs...)\n\t}\n\n\tvar err error\n\tp.Stdin, err = p.Cmd.StdinPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening stdin pipe: %w\", err)\n\t}\n\n\tp.Stdout, err = p.Cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening stdout pipe: %w\", err)\n\t}\n\n\tp.Stderr, err = p.Cmd.StderrPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening stderr pipe: %w\", err)\n\t}\n\n\tp.Log.Infof(\"Starting process: %s %s\", p.name, p.args)\n\n\tif err := p.Cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"error starting process: %w\", err)\n\t}\n\tatomic.StoreInt32(&p.pid, int32(p.Cmd.Process.Pid))\n\treturn nil\n}\n\n// cmdLoop watches an already running process, restarting it when appropriate.\nfunc (p *Process) cmdLoop(ctx context.Context) error {\n\tfor {\n\t\terr := p.cmdWait(ctx)\n\t\tif err != nil && p.StopOnError {\n\t\t\treturn err\n\t\t}\n\t\tif isQuitting(ctx) {\n\t\t\tp.Log.Infof(\"Process %s shut down\", p.Cmd.Path)\n\t\t\treturn nil\n\t\t}\n\n\t\tp.Log.Errorf(\"Process %s exited: %v\", p.Cmd.Path, err)\n\t\tp.Log.Infof(\"Restarting in %s...\", p.RestartDelay)\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-time.After(p.RestartDelay):\n\t\t\t// Continue the loop and restart the process\n\t\t\tif err := p.cmdStart(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n\n// cmdWait waits for the process to finish.\nfunc (p *Process) cmdWait(ctx context.Context) error {\n\tvar wg sync.WaitGroup\n\n\tif p.ReadStdoutFn == nil {\n\t\tp.ReadStdoutFn = defaultReadPipe\n\t}\n\tif p.ReadStderrFn == nil {\n\t\tp.ReadStderrFn = defaultReadPipe\n\t}\n\n\tprocessCtx, processCancel := context.WithCancel(context.Background())\n\tdefer processCancel()\n\n\twg.Add(1)\n\tgo func() {\n\t\tp.ReadStdoutFn(p.Stdout)\n\t\twg.Done()\n\t}()\n\n\twg.Add(1)\n\tgo func() {\n\t\tp.ReadStderrFn(p.Stderr)\n\t\twg.Done()\n\t}()\n\n\twg.Add(1)\n\tgo func() {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tp.gracefulStop(processCtx, p.Cmd, 5*time.Second)\n\t\tcase <-processCtx.Done():\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tp.Lock()\n\terr := p.Cmd.Wait()\n\tp.Unlock()\n\tprocessCancel()\n\twg.Wait()\n\treturn err\n}\n\nfunc isQuitting(ctx context.Context) bool {\n\treturn ctx.Err() != nil\n}\n\nfunc defaultReadPipe(r io.Reader) {\n\t//nolint:errcheck // Discarding the data, no need to handle an error\n\tio.Copy(io.Discard, r)\n}\n"
  },
  {
    "path": "internal/process/process_posix.go",
    "content": "//go:build !windows\n\npackage process\n\nimport (\n\t\"context\"\n\t\"os/exec\"\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc (p *Process) gracefulStop(ctx context.Context, cmd *exec.Cmd, timeout time.Duration) {\n\tselect {\n\tcase <-time.After(timeout):\n\t\tif err := cmd.Process.Signal(syscall.SIGTERM); err != nil {\n\t\t\tp.Log.Errorf(\"Error after sending SIGTERM signal to process: %v\", err)\n\t\t}\n\tcase <-ctx.Done():\n\t}\n\tselect {\n\tcase <-time.After(timeout):\n\t\tif err := cmd.Process.Kill(); err != nil {\n\t\t\tp.Log.Errorf(\"Error after killing process: %v\", err)\n\t\t}\n\tcase <-ctx.Done():\n\t}\n}\n"
  },
  {
    "path": "internal/process/process_test.go",
    "content": "//go:build !windows\n\npackage process\n\nimport (\n\t\"bufio\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// test that a restarting process resets pipes properly\nfunc TestRestartingRebindsPipes(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping long running test in short mode\")\n\t}\n\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\tp, err := New([]string{exe, \"-external\"}, []string{\"INTERNAL_PROCESS_MODE=application\"})\n\tp.RestartDelay = 100 * time.Nanosecond\n\tp.Log = testutil.Logger{}\n\trequire.NoError(t, err)\n\n\tlinesRead := int64(0)\n\tp.ReadStdoutFn = func(r io.Reader) {\n\t\tscanner := bufio.NewScanner(r)\n\n\t\tfor scanner.Scan() {\n\t\t\tatomic.AddInt64(&linesRead, 1)\n\t\t}\n\t}\n\n\trequire.NoError(t, p.Start())\n\n\tfor atomic.LoadInt64(&linesRead) < 1 {\n\t\ttime.Sleep(1 * time.Millisecond)\n\t}\n\n\trequire.NoError(t, syscall.Kill(p.Pid(), syscall.SIGKILL))\n\n\tfor atomic.LoadInt64(&linesRead) < 2 {\n\t\ttime.Sleep(1 * time.Millisecond)\n\t}\n\n\t// the mainLoopWg.Wait() call p.Stop() makes takes multiple seconds to complete\n\tp.Stop()\n}\n\nvar external = flag.Bool(\"external\", false,\n\t\"if true, run externalProcess instead of tests\")\n\nfunc TestMain(m *testing.M) {\n\tflag.Parse()\n\trunMode := os.Getenv(\"INTERNAL_PROCESS_MODE\")\n\tif *external && runMode == \"application\" {\n\t\texternalProcess()\n\t\tos.Exit(0)\n\t}\n\tcode := m.Run()\n\tos.Exit(code)\n}\n\n// externalProcess is an external \"misbehaving\" process that won't exit\n// cleanly.\nfunc externalProcess() {\n\twait := make(chan int)\n\tfmt.Fprintln(os.Stdout, \"started\")\n\t<-wait\n\tos.Exit(2) //nolint:revive // os.Exit called intentionally\n}\n"
  },
  {
    "path": "internal/process/process_windows.go",
    "content": "//go:build windows\n\npackage process\n\nimport (\n\t\"context\"\n\t\"os/exec\"\n\t\"time\"\n)\n\nfunc (p *Process) gracefulStop(ctx context.Context, cmd *exec.Cmd, timeout time.Duration) {\n\tselect {\n\tcase <-time.After(timeout):\n\t\tif err := cmd.Process.Kill(); err != nil {\n\t\t\tp.Log.Errorf(\"Error after killing process: %v\", err)\n\t\t}\n\tcase <-ctx.Done():\n\t}\n}\n"
  },
  {
    "path": "internal/rotate/file_writer.go",
    "content": "package rotate\n\n// Rotating things\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n// FilePerm defines the permissions that Writer will use for all\n// the files it creates.\nconst (\n\tFilePerm   = os.FileMode(0644)\n\tDateFormat = \"2006-01-02\"\n)\n\n// FileWriter implements the io.Writer interface and writes to the\n// filename specified.\n// Will rotate at the specified interval and/or when the current file size exceeds maxSizeInBytes\n// At rotation time, current file is renamed and a new file is created.\n// If the number of archives exceeds maxArchives, older files are deleted.\ntype FileWriter struct {\n\tfilename                 string\n\tfilenameRotationTemplate string\n\tcurrent                  *os.File\n\tinterval                 time.Duration\n\tmaxSizeInBytes           int64\n\tmaxArchives              int\n\texpireTime               time.Time\n\tbytesWritten             int64\n\tsync.Mutex\n}\n\n// NewFileWriter creates a new file writer.\nfunc NewFileWriter(filename string, interval time.Duration, maxSizeInBytes int64, maxArchives int) (io.WriteCloser, error) {\n\tif interval == 0 && maxSizeInBytes <= 0 {\n\t\t// No rotation needed so a basic io.Writer will do the trick\n\t\treturn openFile(filename)\n\t}\n\n\tw := &FileWriter{\n\t\tfilename:                 filename,\n\t\tinterval:                 interval,\n\t\tmaxSizeInBytes:           maxSizeInBytes,\n\t\tmaxArchives:              maxArchives,\n\t\tfilenameRotationTemplate: getFilenameRotationTemplate(filename),\n\t}\n\n\tif err := w.openCurrent(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn w, nil\n}\n\nfunc openFile(filename string) (*os.File, error) {\n\treturn os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, FilePerm)\n}\n\nfunc getFilenameRotationTemplate(filename string) string {\n\t// Extract the file extension\n\tfileExt := filepath.Ext(filename)\n\t// Remove the file extension from the filename (if any)\n\tstem := strings.TrimSuffix(filename, fileExt)\n\treturn stem + \".%s-%s\" + fileExt\n}\n\n// Write writes p to the current file, then checks to see if\n// rotation is necessary.\nfunc (w *FileWriter) Write(p []byte) (n int, err error) {\n\tw.Lock()\n\tdefer w.Unlock()\n\tif n, err = w.current.Write(p); err != nil {\n\t\treturn 0, err\n\t}\n\tw.bytesWritten += int64(n)\n\n\tif err := w.rotateIfNeeded(); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn n, nil\n}\n\n// Close closes the current file.  Writer is unusable after this\n// is called.\nfunc (w *FileWriter) Close() (err error) {\n\tw.Lock()\n\tdefer w.Unlock()\n\n\t// Rotate before closing\n\tif err := w.rotateIfNeeded(); err != nil {\n\t\treturn err\n\t}\n\n\t// Close the file if we did not rotate\n\tif err := w.current.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tw.current = nil\n\treturn nil\n}\n\nfunc (w *FileWriter) openCurrent() (err error) {\n\t// In case ModTime() fails, we use time.Now()\n\tw.expireTime = time.Now().Add(w.interval)\n\tw.bytesWritten = 0\n\tw.current, err = openFile(w.filename)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Goal here is to rotate old pre-existing files.\n\t// For that we use fileInfo.ModTime, instead of time.Now().\n\t// Example: telegraf is restarted every 23 hours and\n\t// the rotation interval is set to 24 hours.\n\t// With time.now() as a reference we'd never rotate the file.\n\tif fileInfo, err := w.current.Stat(); err == nil {\n\t\tw.expireTime = fileInfo.ModTime().Add(w.interval)\n\t\tw.bytesWritten = fileInfo.Size()\n\t}\n\n\treturn w.rotateIfNeeded()\n}\n\nfunc (w *FileWriter) rotateIfNeeded() error {\n\tif (w.interval > 0 && time.Now().After(w.expireTime)) ||\n\t\t(w.maxSizeInBytes > 0 && w.bytesWritten >= w.maxSizeInBytes) {\n\t\tif err := w.rotate(); err != nil {\n\t\t\t// Ignore rotation errors and keep the log open\n\t\t\tfmt.Printf(\"unable to rotate the file %q, %s\", w.filename, err.Error())\n\t\t}\n\t\treturn w.openCurrent()\n\t}\n\treturn nil\n}\n\nfunc (w *FileWriter) rotate() (err error) {\n\tif err := w.current.Close(); err != nil {\n\t\treturn err\n\t}\n\n\t// Use year-month-date for readability, unix time to make the file name unique with second precision\n\tnow := time.Now()\n\trotatedFilename := fmt.Sprintf(w.filenameRotationTemplate, now.Format(DateFormat), strconv.FormatInt(now.Unix(), 10))\n\tif err := os.Rename(w.filename, rotatedFilename); err != nil {\n\t\treturn err\n\t}\n\n\treturn w.purgeArchivesIfNeeded()\n}\n\nfunc (w *FileWriter) purgeArchivesIfNeeded() (err error) {\n\tif w.maxArchives == -1 {\n\t\t// Skip archiving\n\t\treturn nil\n\t}\n\n\tvar matches []string\n\tif matches, err = filepath.Glob(fmt.Sprintf(w.filenameRotationTemplate, \"*\", \"*\")); err != nil {\n\t\treturn err\n\t}\n\n\t// if there are more archives than the configured maximum, then purge older files\n\tif len(matches) > w.maxArchives {\n\t\t// sort files alphanumerically to delete older files first\n\t\tsort.Strings(matches)\n\t\tfor _, filename := range matches[:len(matches)-w.maxArchives] {\n\t\t\tif err := os.Remove(filename); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/rotate/file_writer_test.go",
    "content": "package rotate\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFileWriter_NoRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test\"), 0, 0, 0)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\t_, err = writer.Write([]byte(\"Hello World\"))\n\trequire.NoError(t, err)\n\t_, err = writer.Write([]byte(\"Hello World 2\"))\n\trequire.NoError(t, err)\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n}\n\nfunc TestFileWriter_TimeRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tinterval, err := time.ParseDuration(\"10ms\")\n\trequire.NoError(t, err)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test\"), interval, 0, -1)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\t_, err = writer.Write([]byte(\"Hello World\"))\n\trequire.NoError(t, err)\n\ttime.Sleep(interval)\n\t_, err = writer.Write([]byte(\"Hello World 2\"))\n\trequire.NoError(t, err)\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestFileWriter_ReopenTimeRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tinterval, err := time.ParseDuration(\"10ms\")\n\trequire.NoError(t, err)\n\tfilePath := filepath.Join(tempDir, \"test.log\")\n\terr = os.WriteFile(filePath, []byte(\"Hello World\"), 0640)\n\ttime.Sleep(interval)\n\trequire.NoError(t, err)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test.log\"), interval, 0, -1)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestFileWriter_SizeRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tmaxSize := int64(9)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test.log\"), 0, maxSize, -1)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\t_, err = writer.Write([]byte(\"Hello World\"))\n\trequire.NoError(t, err)\n\t_, err = writer.Write([]byte(\"World 2\"))\n\trequire.NoError(t, err)\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestFileWriter_ReopenSizeRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tmaxSize := int64(12)\n\tfilePath := filepath.Join(tempDir, \"test.log\")\n\terr := os.WriteFile(filePath, []byte(\"Hello World\"), 0640)\n\trequire.NoError(t, err)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test.log\"), 0, maxSize, -1)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\t_, err = writer.Write([]byte(\"Hello World Again\"))\n\trequire.NoError(t, err)\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestFileWriter_DeleteArchives(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping long test in short mode\")\n\t}\n\n\ttempDir := t.TempDir()\n\tmaxSize := int64(5)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test.log\"), 0, maxSize, 2)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { require.NoError(t, writer.Close()) })\n\n\t_, err = writer.Write([]byte(\"First file\"))\n\trequire.NoError(t, err)\n\t// File names include the date with second precision\n\t// So, to force rotation with different file names\n\t// we need to wait\n\ttime.Sleep(1 * time.Second)\n\t_, err = writer.Write([]byte(\"Second file\"))\n\trequire.NoError(t, err)\n\ttime.Sleep(1 * time.Second)\n\t_, err = writer.Write([]byte(\"Third file\"))\n\trequire.NoError(t, err)\n\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 3)\n\n\tfor _, tempFile := range files {\n\t\tvar bytes []byte\n\t\tvar err error\n\t\tpath := filepath.Join(tempDir, tempFile.Name())\n\t\tif bytes, err = os.ReadFile(path); err != nil {\n\t\t\tt.Error(err.Error())\n\t\t\treturn\n\t\t}\n\t\tcontents := string(bytes)\n\n\t\tif contents != \"\" && contents != \"Second file\" && contents != \"Third file\" {\n\t\t\tt.Error(\"Should have deleted the eldest log file\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestFileWriter_CloseDoesNotRotate(t *testing.T) {\n\ttempDir := t.TempDir()\n\tmaxSize := int64(9)\n\twriter, err := NewFileWriter(filepath.Join(tempDir, \"test.log\"), 0, maxSize, -1)\n\trequire.NoError(t, err)\n\trequire.NoError(t, writer.Close())\n\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Regexp(t, \"^test.log$\", files[0].Name())\n}\n"
  },
  {
    "path": "internal/templating/engine.go",
    "content": "package templating\n\nimport (\n\t\"sort\"\n\t\"strings\"\n)\n\nconst (\n\t// DefaultSeparator is the default separation character to use when separating template parts.\n\tDefaultSeparator = \".\"\n)\n\n// Engine uses a Matcher to retrieve the appropriate template and applies the template\n// to the input string\ntype Engine struct {\n\tjoiner  string\n\tmatcher *matcher\n}\n\n// Apply extracts the template fields from the given line and returns the measurement\n// name, tags and field name\n//\n//nolint:revive //function-result-limit conditionally 4 return results allowed\nfunc (e *Engine) Apply(line string) (measurementName string, tags map[string]string, field string, err error) {\n\treturn e.matcher.match(line).Apply(line, e.joiner)\n}\n\n// NewEngine creates a new templating engine\nfunc NewEngine(joiner string, defaultTemplate *Template, templates []string) (*Engine, error) {\n\tengine := Engine{\n\t\tjoiner:  joiner,\n\t\tmatcher: newMatcher(defaultTemplate),\n\t}\n\ttemplateSpecs := parseTemplateSpecs(templates)\n\n\tfor _, templateSpec := range templateSpecs {\n\t\tif err := engine.matcher.addSpec(templateSpec); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &engine, nil\n}\n\nfunc parseTemplateSpecs(templates []string) templateSpecs {\n\ttmplts := make(templateSpecs, 0, len(templates))\n\tfor _, pattern := range templates {\n\t\ttmplt := templateSpec{\n\t\t\tseparator: DefaultSeparator,\n\t\t}\n\n\t\t// Format is [separator] [filter] <template> [tag1=value1,tag2=value2]\n\t\tparts := strings.Fields(pattern)\n\t\tpartsLength := len(parts)\n\t\tif partsLength < 1 {\n\t\t\t// ignore\n\t\t\tcontinue\n\t\t}\n\t\tif partsLength == 1 {\n\t\t\ttmplt.template = pattern\n\t\t} else if partsLength == 4 {\n\t\t\ttmplt.separator = parts[0]\n\t\t\ttmplt.filter = parts[1]\n\t\t\ttmplt.template = parts[2]\n\t\t\ttmplt.tagstring = parts[3]\n\t\t} else {\n\t\t\thasTagstring := strings.Contains(parts[partsLength-1], \"=\")\n\t\t\tif hasTagstring {\n\t\t\t\ttmplt.tagstring = parts[partsLength-1]\n\t\t\t\ttmplt.template = parts[partsLength-2]\n\t\t\t\tif partsLength == 3 {\n\t\t\t\t\ttmplt.filter = parts[0]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttmplt.template = parts[partsLength-1]\n\t\t\t\tif partsLength == 2 {\n\t\t\t\t\ttmplt.filter = parts[0]\n\t\t\t\t} else { // length == 3\n\t\t\t\t\ttmplt.separator = parts[0]\n\t\t\t\t\ttmplt.filter = parts[1]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttmplts = append(tmplts, tmplt)\n\t}\n\tsort.Sort(tmplts)\n\treturn tmplts\n}\n"
  },
  {
    "path": "internal/templating/engine_test.go",
    "content": "package templating\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEngineAlternateSeparator(t *testing.T) {\n\tdefaultTemplate, err := NewDefaultTemplateWithPattern(\"measurement*\")\n\trequire.NoError(t, err)\n\tengine, err := NewEngine(\"_\", defaultTemplate, []string{\n\t\t\"/ /*/*/* /measurement/origin/measurement*\",\n\t})\n\trequire.NoError(t, err)\n\tname, tags, field, err := engine.Apply(\"/telegraf/host01/cpu\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"telegraf_cpu\", name)\n\trequire.Equal(t, map[string]string{\n\t\t\"origin\": \"host01\",\n\t}, tags)\n\trequire.Empty(t, field)\n}\n\nfunc TestEngineWithWildcardTemplate(t *testing.T) {\n\tvar (\n\t\tdefaultTmpl, err = NewDefaultTemplateWithPattern(\"measurement*\")\n\t\ttemplates        = []string{\n\t\t\t\"taskmanagerTask.alarm-detector.Assign.alarmDefinitionId metricsType.process.nodeId.x.alarmDefinitionId.measurement.field rule=1\",\n\t\t\t\"taskmanagerTask.*.*.*.*                                 metricsType.process.nodeId.measurement rule=2\",\n\t\t}\n\t)\n\trequire.NoError(t, err)\n\n\tengine, err := NewEngine(\".\", defaultTmpl, templates)\n\trequire.NoError(t, err)\n\n\tfor _, testCase := range []struct {\n\t\tline        string\n\t\tmeasurement string\n\t\tfield       string\n\t\ttags        map[string]string\n\t}{\n\t\t{\n\t\t\tline:        \"taskmanagerTask.alarm-detector.Assign.alarmDefinitionId.timeout_errors.duration.p75\",\n\t\t\tmeasurement: \"duration\",\n\t\t\tfield:       \"p75\",\n\t\t\ttags: map[string]string{\n\t\t\t\t\"metricsType\":       \"taskmanagerTask\",\n\t\t\t\t\"process\":           \"alarm-detector\",\n\t\t\t\t\"nodeId\":            \"Assign\",\n\t\t\t\t\"x\":                 \"alarmDefinitionId\",\n\t\t\t\t\"alarmDefinitionId\": \"timeout_errors\",\n\t\t\t\t\"rule\":              \"1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tline:        \"taskmanagerTask.alarm-detector.Assign.numRecordsInPerSecond.m5_rate\",\n\t\t\tmeasurement: \"numRecordsInPerSecond\",\n\t\t\ttags: map[string]string{\n\t\t\t\t\"metricsType\": \"taskmanagerTask\",\n\t\t\t\t\"process\":     \"alarm-detector\",\n\t\t\t\t\"nodeId\":      \"Assign\",\n\t\t\t\t\"rule\":        \"2\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(testCase.line, func(t *testing.T) {\n\t\t\tmeasurement, tags, field, err := engine.Apply(testCase.line)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, testCase.measurement, measurement)\n\t\t\trequire.Equal(t, testCase.field, field)\n\t\t\trequire.Equal(t, testCase.tags, tags)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/templating/matcher.go",
    "content": "package templating\n\nimport (\n\t\"strings\"\n)\n\n// matcher determines which template should be applied to a given metric\n// based on a filter tree.\ntype matcher struct {\n\troot            *node\n\tdefaultTemplate *Template\n}\n\n// newMatcher creates a new matcher.\nfunc newMatcher(defaultTemplate *Template) *matcher {\n\treturn &matcher{\n\t\troot:            &node{},\n\t\tdefaultTemplate: defaultTemplate,\n\t}\n}\n\nfunc (m *matcher) addSpec(tmplt templateSpec) error {\n\t// Parse out the default tags specific to this template\n\ttags := make(map[string]string)\n\tif tmplt.tagstring != \"\" {\n\t\tfor _, kv := range strings.Split(tmplt.tagstring, \",\") {\n\t\t\tparts := strings.Split(kv, \"=\")\n\t\t\ttags[parts[0]] = parts[1]\n\t\t}\n\t}\n\n\ttmpl, err := NewTemplate(tmplt.separator, tmplt.template, tags)\n\tif err != nil {\n\t\treturn err\n\t}\n\tm.add(tmplt.filter, tmpl)\n\treturn nil\n}\n\n// add inserts the template in the filter tree based the given filter\nfunc (m *matcher) add(filter string, template *Template) {\n\tif filter == \"\" {\n\t\tm.defaultTemplate = template\n\t\tm.root.separator = template.separator\n\t\treturn\n\t}\n\tm.root.insert(filter, template)\n}\n\n// match returns the template that matches the given measurement line.\n// If no template matches, the default template is returned.\nfunc (m *matcher) match(line string) *Template {\n\ttmpl := m.root.search(line)\n\tif tmpl != nil {\n\t\treturn tmpl\n\t}\n\treturn m.defaultTemplate\n}\n"
  },
  {
    "path": "internal/templating/node.go",
    "content": "package templating\n\nimport (\n\t\"sort\"\n\t\"strings\"\n)\n\n// node is an item in a sorted k-ary tree of filter parts. Each child is sorted by its part value.\n// The special value of \"*\", is always sorted last.\ntype node struct {\n\tseparator string\n\tvalue     string\n\tchildren  nodes\n\ttemplate  *Template\n}\n\n// insert inserts the given string template into the tree.  The filter string is separated\n// on the template separator and each part is used as the path in the tree.\nfunc (n *node) insert(filter string, template *Template) {\n\tn.separator = template.separator\n\tn.recursiveInsert(strings.Split(filter, n.separator), template)\n}\n\n// recursiveInsert does the actual recursive insertion\nfunc (n *node) recursiveInsert(values []string, template *Template) {\n\t// Add the end, set the template\n\tif len(values) == 0 {\n\t\tn.template = template\n\t\treturn\n\t}\n\n\t// See if the current element already exists in the tree. If so, insert the\n\t// into that sub-tree\n\tfor _, v := range n.children {\n\t\tif v.value == values[0] {\n\t\t\tv.recursiveInsert(values[1:], template)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// New element, add it to the tree and sort the children\n\tnewNode := &node{value: values[0]}\n\tn.children = append(n.children, newNode)\n\tsort.Sort(&n.children)\n\n\t// Now insert the rest of the tree into the new element\n\tnewNode.recursiveInsert(values[1:], template)\n}\n\n// search searches for a template matching the input string\nfunc (n *node) search(line string) *Template {\n\tseparator := n.separator\n\treturn n.recursiveSearch(strings.Split(line, separator))\n}\n\n// recursiveSearch performs the actual recursive search\nfunc (n *node) recursiveSearch(lineParts []string) *Template {\n\t// nothing to search\n\tif len(lineParts) == 0 || len(n.children) == 0 {\n\t\treturn n.template\n\t}\n\n\tvar (\n\t\thasWildcard bool\n\t\tlength      = len(n.children)\n\t)\n\n\t// exclude last child from search if it is a wildcard. sort.Search expects\n\t// a lexicographically sorted set of children and we have artificially sorted\n\t// wildcards to the end of the child set\n\t// wildcards will be searched separately if no exact match is found\n\tif hasWildcard = n.children[length-1].value == \"*\"; hasWildcard {\n\t\tlength--\n\t}\n\n\ti := sort.Search(length, func(i int) bool {\n\t\treturn n.children[i].value >= lineParts[0]\n\t})\n\n\t// given an exact match is found within children set\n\tif i < length && n.children[i].value == lineParts[0] {\n\t\t// descend into the matching node\n\t\tif tmpl := n.children[i].recursiveSearch(lineParts[1:]); tmpl != nil {\n\t\t\t// given a template is found return it\n\t\t\treturn tmpl\n\t\t}\n\t}\n\n\t// given no template is found and the last child is a wildcard\n\tif hasWildcard {\n\t\t// also search the wildcard child node\n\t\treturn n.children[length].recursiveSearch(lineParts[1:])\n\t}\n\n\t// fallback to returning template at this node\n\treturn n.template\n}\n\n// nodes is simply an array of nodes implementing the sorting interface.\ntype nodes []*node\n\n// Less returns a boolean indicating whether the filter at position j\n// is less than the filter at position k. Filters are order by string\n// comparison of each component parts.  A wildcard value \"*\" is never\n// less than a non-wildcard value.\n//\n// For example, the filters:\n//\n//\t\"*.*\"\n//\t\"servers.*\"\n//\t\"servers.localhost\"\n//\t\"*.localhost\"\n//\n// Would be sorted as:\n//\n//\t\"servers.localhost\"\n//\t\"servers.*\"\n//\t\"*.localhost\"\n//\t\"*.*\"\nfunc (n *nodes) Less(j, k int) bool {\n\tif (*n)[j].value == \"*\" && (*n)[k].value != \"*\" {\n\t\treturn false\n\t}\n\n\tif (*n)[j].value != \"*\" && (*n)[k].value == \"*\" {\n\t\treturn true\n\t}\n\n\treturn (*n)[j].value < (*n)[k].value\n}\n\n// Swap swaps two elements of the array\nfunc (n *nodes) Swap(i, j int) { (*n)[i], (*n)[j] = (*n)[j], (*n)[i] }\n\n// Len returns the length of the array\nfunc (n *nodes) Len() int { return len(*n) }\n"
  },
  {
    "path": "internal/templating/template.go",
    "content": "package templating\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Template represents a pattern and tags to map a metric string to an influxdb Point\ntype Template struct {\n\tseparator         string\n\tparts             []string\n\tdefaultTags       map[string]string\n\tgreedyField       bool\n\tgreedyMeasurement bool\n}\n\n// Apply extracts the template fields from the given line and returns the measurement\n// name, tags and field name\n//\n//nolint:revive //function-result-limit conditionally 4 return results allowed\nfunc (t *Template) Apply(line string, joiner string) (measurementName string, tags map[string]string, field string, err error) {\n\tallFields := strings.Split(line, t.separator)\n\tvar (\n\t\tmeasurements []string\n\t\ttagsMap      = make(map[string][]string)\n\t\tfields       []string\n\t)\n\n\t// Set any default tags\n\tfor k, v := range t.defaultTags {\n\t\ttagsMap[k] = append(tagsMap[k], v)\n\t}\n\n\t// See if an invalid combination has been specified in the template:\n\tfor _, tag := range t.parts {\n\t\tif tag == \"measurement*\" {\n\t\t\tt.greedyMeasurement = true\n\t\t} else if tag == \"field*\" {\n\t\t\tt.greedyField = true\n\t\t}\n\t}\n\tif t.greedyField && t.greedyMeasurement {\n\t\treturn \"\", nil, \"\",\n\t\t\tfmt.Errorf(\"either 'field*' or 'measurement*' can be used in each \"+\n\t\t\t\t\"template (but not both together): %q\",\n\t\t\t\tstrings.Join(t.parts, joiner))\n\t}\n\n\tfor i, tag := range t.parts {\n\t\tif i >= len(allFields) {\n\t\t\tcontinue\n\t\t}\n\t\tif tag == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch tag {\n\t\tcase \"measurement\":\n\t\t\tmeasurements = append(measurements, allFields[i])\n\t\tcase \"field\":\n\t\t\tfields = append(fields, allFields[i])\n\t\tcase \"field*\":\n\t\t\tfields = append(fields, allFields[i:]...)\n\t\tcase \"measurement*\":\n\t\t\tmeasurements = append(measurements, allFields[i:]...)\n\t\tdefault:\n\t\t\ttagsMap[tag] = append(tagsMap[tag], allFields[i])\n\t\t}\n\t}\n\n\t// Convert to map of strings.\n\ttags = make(map[string]string)\n\tfor k, values := range tagsMap {\n\t\ttags[k] = strings.Join(values, joiner)\n\t}\n\n\treturn strings.Join(measurements, joiner), tags, strings.Join(fields, joiner), nil\n}\n\nfunc NewDefaultTemplateWithPattern(pattern string) (*Template, error) {\n\treturn NewTemplate(DefaultSeparator, pattern, nil)\n}\n\n// NewTemplate returns a new template ensuring it has a measurement specified.\nfunc NewTemplate(separator, pattern string, defaultTags map[string]string) (*Template, error) {\n\tparts := strings.Split(pattern, separator)\n\thasMeasurement := false\n\ttemplate := &Template{\n\t\tseparator:   separator,\n\t\tparts:       parts,\n\t\tdefaultTags: defaultTags,\n\t}\n\n\tfor _, part := range parts {\n\t\tif strings.HasPrefix(part, \"measurement\") {\n\t\t\thasMeasurement = true\n\t\t}\n\t\tif part == \"measurement*\" {\n\t\t\ttemplate.greedyMeasurement = true\n\t\t} else if part == \"field*\" {\n\t\t\ttemplate.greedyField = true\n\t\t}\n\t}\n\n\tif !hasMeasurement {\n\t\treturn nil, fmt.Errorf(\"no measurement specified for template. %q\", pattern)\n\t}\n\n\treturn template, nil\n}\n\n// templateSpec is a template string split in its constituent parts\ntype templateSpec struct {\n\tseparator string\n\tfilter    string\n\ttemplate  string\n\ttagstring string\n}\n\n// templateSpecs is simply an array of template specs implementing the sorting interface\ntype templateSpecs []templateSpec\n\n// Less reports whether the element with\n// index j should sort before the element with index k.\nfunc (e templateSpecs) Less(j, k int) bool {\n\tjlen := len(e[j].filter)\n\tklen := len(e[k].filter)\n\tif jlen == 0 && klen != 0 {\n\t\treturn true\n\t}\n\tif klen == 0 && jlen != 0 {\n\t\treturn false\n\t}\n\treturn strings.Count(e[j].template, e[j].separator) <\n\t\tstrings.Count(e[k].template, e[k].separator)\n}\n\n// Swap swaps the elements with indexes i and j.\nfunc (e templateSpecs) Swap(i, j int) { e[i], e[j] = e[j], e[i] }\n\n// Len is the number of elements in the collection.\nfunc (e templateSpecs) Len() int { return len(e) }\n"
  },
  {
    "path": "internal/templating/template_test.go",
    "content": "package templating\n\nimport \"testing\"\n\nfunc BenchmarkTemplateLess(b *testing.B) {\n\ta := templateSpec{\n\t\ttemplate:  \"aa|bb|cc|dd|ee|ff\",\n\t\tseparator: \"|\",\n\t}\n\tspecs := templateSpecs{a, a}\n\tfor i := 0; i < b.N; i++ {\n\t\tspecs.Less(0, 1)\n\t}\n}\n"
  },
  {
    "path": "internal/type_conversions.go",
    "content": "package internal\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar ErrOutOfRange = strconv.ErrRange\n\nfunc ToFloat64(value interface{}) (float64, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn strconv.ParseFloat(v, 64)\n\tcase []byte:\n\t\treturn strconv.ParseFloat(string(v), 64)\n\tcase fmt.Stringer:\n\t\treturn strconv.ParseFloat(v.String(), 64)\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\treturn float64(v), nil\n\tcase int8:\n\t\treturn float64(v), nil\n\tcase int16:\n\t\treturn float64(v), nil\n\tcase int32:\n\t\treturn float64(v), nil\n\tcase int64:\n\t\treturn float64(v), nil\n\tcase uint:\n\t\treturn float64(v), nil\n\tcase uint8:\n\t\treturn float64(v), nil\n\tcase uint16:\n\t\treturn float64(v), nil\n\tcase uint32:\n\t\treturn float64(v), nil\n\tcase uint64:\n\t\treturn float64(v), nil\n\tcase float32:\n\t\treturn float64(v), nil\n\tcase float64:\n\t\treturn v, nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToFloat32(value interface{}) (float32, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tx, err := strconv.ParseFloat(v, 32)\n\t\treturn float32(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseFloat(string(v), 32)\n\t\treturn float32(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseFloat(v.String(), 32)\n\t\treturn float32(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\treturn float32(v), nil\n\tcase int8:\n\t\treturn float32(v), nil\n\tcase int16:\n\t\treturn float32(v), nil\n\tcase int32:\n\t\treturn float32(v), nil\n\tcase int64:\n\t\treturn float32(v), nil\n\tcase uint:\n\t\treturn float32(v), nil\n\tcase uint8:\n\t\treturn float32(v), nil\n\tcase uint16:\n\t\treturn float32(v), nil\n\tcase uint32:\n\t\treturn float32(v), nil\n\tcase uint64:\n\t\treturn float32(v), nil\n\tcase float32:\n\t\treturn v, nil\n\tcase float64:\n\t\tif v < -math.MaxFloat32 || v > math.MaxFloat32 {\n\t\t\treturn float32(v), ErrOutOfRange\n\t\t}\n\t\treturn float32(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToUint64(value interface{}) (uint64, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\treturn strconv.ParseUint(strings.TrimPrefix(v, \"0x\"), 16, 64)\n\t\t}\n\t\treturn strconv.ParseUint(v, 10, 64)\n\tcase []byte:\n\t\treturn strconv.ParseUint(string(v), 10, 64)\n\tcase fmt.Stringer:\n\t\treturn strconv.ParseUint(v.String(), 10, 64)\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\tif v < 0 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase int8:\n\t\tif v < 0 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase int16:\n\t\tif v < 0 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase int32:\n\t\tif v < 0 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase int64:\n\t\tif v < 0 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase uint:\n\t\treturn uint64(v), nil\n\tcase uint8:\n\t\treturn uint64(v), nil\n\tcase uint16:\n\t\treturn uint64(v), nil\n\tcase uint32:\n\t\treturn uint64(v), nil\n\tcase uint64:\n\t\treturn v, nil\n\tcase float32:\n\t\tif v < 0 || v > math.MaxUint64 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase float64:\n\t\tif v < 0 || v > math.MaxUint64 {\n\t\t\treturn uint64(v), ErrOutOfRange\n\t\t}\n\t\treturn uint64(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToUint32(value interface{}) (uint32, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseUint(strings.TrimPrefix(v, \"0x\"), 16, 32)\n\t\t\treturn uint32(x), err\n\t\t}\n\t\tx, err := strconv.ParseUint(v, 10, 32)\n\t\treturn uint32(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseUint(string(v), 10, 32)\n\t\treturn uint32(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseUint(v.String(), 10, 32)\n\t\treturn uint32(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\tif v < 0 || uint64(v) > math.MaxUint32 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase int8:\n\t\tif v < 0 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase int16:\n\t\tif v < 0 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase int32:\n\t\tif v < 0 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase int64:\n\t\tif v < 0 || v > math.MaxUint32 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase uint:\n\t\treturn uint32(v), nil\n\tcase uint8:\n\t\treturn uint32(v), nil\n\tcase uint16:\n\t\treturn uint32(v), nil\n\tcase uint32:\n\t\treturn v, nil\n\tcase uint64:\n\t\tif v > math.MaxUint32 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase float32:\n\t\tif v < 0 || v > math.MaxUint32 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase float64:\n\t\tif v < 0 || v > math.MaxUint32 {\n\t\t\treturn uint32(v), ErrOutOfRange\n\t\t}\n\t\treturn uint32(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToUint16(value interface{}) (uint16, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseUint(strings.TrimPrefix(v, \"0x\"), 16, 16)\n\t\t\treturn uint16(x), err\n\t\t}\n\t\tx, err := strconv.ParseUint(v, 10, 32)\n\t\treturn uint16(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseUint(string(v), 10, 32)\n\t\treturn uint16(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseUint(v.String(), 10, 32)\n\t\treturn uint16(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\tif v < 0 || v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase int8:\n\t\tif v < 0 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase int16:\n\t\tif v < 0 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase int32:\n\t\tif v < 0 || v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase int64:\n\t\tif v < 0 || v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase uint:\n\t\treturn uint16(v), nil\n\tcase uint8:\n\t\treturn uint16(v), nil\n\tcase uint16:\n\t\treturn v, nil\n\tcase uint32:\n\t\tif v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase uint64:\n\t\tif v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase float32:\n\t\tif v < 0 || v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase float64:\n\t\tif v < 0 || v > math.MaxUint16 {\n\t\t\treturn uint16(v), ErrOutOfRange\n\t\t}\n\t\treturn uint16(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToUint8(value interface{}) (uint8, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseUint(strings.TrimPrefix(v, \"0x\"), 16, 8)\n\t\t\treturn uint8(x), err\n\t\t}\n\t\tx, err := strconv.ParseUint(v, 10, 32)\n\t\treturn uint8(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseUint(string(v), 10, 32)\n\t\treturn uint8(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseUint(v.String(), 10, 32)\n\t\treturn uint8(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase int8:\n\t\tif v < 0 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase int16:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase int32:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase int64:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase uint:\n\t\treturn uint8(v), nil\n\tcase uint8:\n\t\treturn v, nil\n\tcase uint16:\n\t\tif v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase uint32:\n\t\tif v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase uint64:\n\t\tif v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase float32:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase float64:\n\t\tif v < 0 || v > math.MaxUint8 {\n\t\t\treturn uint8(v), ErrOutOfRange\n\t\t}\n\t\treturn uint8(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToInt64(value interface{}) (int64, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\treturn strconv.ParseInt(strings.TrimPrefix(v, \"0x\"), 16, 64)\n\t\t}\n\t\treturn strconv.ParseInt(v, 10, 64)\n\tcase []byte:\n\t\treturn strconv.ParseInt(string(v), 10, 64)\n\tcase fmt.Stringer:\n\t\treturn strconv.ParseInt(v.String(), 10, 64)\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\treturn int64(v), nil\n\tcase int8:\n\t\treturn int64(v), nil\n\tcase int16:\n\t\treturn int64(v), nil\n\tcase int32:\n\t\treturn int64(v), nil\n\tcase int64:\n\t\treturn v, nil\n\tcase uint:\n\t\tif uint64(v) > math.MaxInt64 {\n\t\t\treturn int64(v), ErrOutOfRange\n\t\t}\n\t\treturn int64(v), nil\n\tcase uint8:\n\t\treturn int64(v), nil\n\tcase uint16:\n\t\treturn int64(v), nil\n\tcase uint32:\n\t\treturn int64(v), nil\n\tcase uint64:\n\t\tif v > math.MaxInt64 {\n\t\t\treturn int64(v), ErrOutOfRange\n\t\t}\n\t\treturn int64(v), nil\n\tcase float32:\n\t\tif v < math.MinInt64 || v > math.MaxInt64 {\n\t\t\treturn int64(v), ErrOutOfRange\n\t\t}\n\t\treturn int64(v), nil\n\tcase float64:\n\t\tif v < math.MinInt64 || v > math.MaxInt64 {\n\t\t\treturn int64(v), ErrOutOfRange\n\t\t}\n\t\treturn int64(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToInt32(value interface{}) (int32, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseInt(strings.TrimPrefix(v, \"0x\"), 16, 32)\n\t\t\treturn int32(x), err\n\t\t}\n\t\tx, err := strconv.ParseInt(v, 10, 32)\n\t\treturn int32(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseInt(string(v), 10, 32)\n\t\treturn int32(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseInt(v.String(), 10, 32)\n\t\treturn int32(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\tif int64(v) < math.MinInt32 || int64(v) > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase int8:\n\t\treturn int32(v), nil\n\tcase int16:\n\t\treturn int32(v), nil\n\tcase int32:\n\t\treturn v, nil\n\tcase int64:\n\t\tif v < math.MinInt32 || v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase uint:\n\t\tif v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase uint8:\n\t\treturn int32(v), nil\n\tcase uint16:\n\t\treturn int32(v), nil\n\tcase uint32:\n\t\tif v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase uint64:\n\t\tif v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase float32:\n\t\tif v < math.MinInt32 || v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase float64:\n\t\tif v < math.MinInt32 || v > math.MaxInt32 {\n\t\t\treturn int32(v), ErrOutOfRange\n\t\t}\n\t\treturn int32(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToInt16(value interface{}) (int16, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseInt(strings.TrimPrefix(v, \"0x\"), 16, 16)\n\t\t\treturn int16(x), err\n\t\t}\n\t\tx, err := strconv.ParseInt(v, 10, 32)\n\t\treturn int16(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseInt(string(v), 10, 32)\n\t\treturn int16(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseInt(v.String(), 10, 32)\n\t\treturn int16(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\treturn int16(v), nil\n\tcase int8:\n\t\treturn int16(v), nil\n\tcase int16:\n\t\treturn v, nil\n\tcase int32:\n\t\tif v < math.MinInt16 || v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase int64:\n\t\tif v < math.MinInt16 || v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase uint:\n\t\tif v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase uint8:\n\t\treturn int16(v), nil\n\tcase uint16:\n\t\tif v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase uint32:\n\t\tif v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase uint64:\n\t\tif v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase float32:\n\t\tif v < math.MinInt16 || v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase float64:\n\t\tif v < math.MinInt16 || v > math.MaxInt16 {\n\t\t\treturn int16(v), ErrOutOfRange\n\t\t}\n\t\treturn int16(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToInt8(value interface{}) (int8, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif strings.HasPrefix(v, \"0x\") {\n\t\t\tx, err := strconv.ParseInt(strings.TrimPrefix(v, \"0x\"), 16, 8)\n\t\t\treturn int8(x), err\n\t\t}\n\t\tx, err := strconv.ParseInt(v, 10, 32)\n\t\treturn int8(x), err\n\tcase []byte:\n\t\tx, err := strconv.ParseInt(string(v), 10, 32)\n\t\treturn int8(x), err\n\tcase fmt.Stringer:\n\t\tx, err := strconv.ParseInt(v.String(), 10, 32)\n\t\treturn int8(x), err\n\tcase bool:\n\t\tif v {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase int:\n\t\treturn int8(v), nil\n\tcase int8:\n\t\treturn v, nil\n\tcase int16:\n\t\tif v < math.MinInt8 || v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase int32:\n\t\tif v < math.MinInt8 || v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase int64:\n\t\tif v < math.MinInt8 || v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase uint:\n\t\tif v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase uint8:\n\t\tif v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase uint16:\n\t\tif v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase uint32:\n\t\tif v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase uint64:\n\t\tif v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase float32:\n\t\tif v < math.MinInt8 || v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase float64:\n\t\tif v < math.MinInt8 || v > math.MaxInt8 {\n\t\t\treturn int8(v), ErrOutOfRange\n\t\t}\n\t\treturn int8(v), nil\n\tcase nil:\n\t\treturn 0, nil\n\t}\n\treturn 0, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToString(value interface{}) (string, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn v, nil\n\tcase []byte:\n\t\treturn string(v), nil\n\tcase int:\n\t\treturn strconv.FormatInt(int64(v), 10), nil\n\tcase int8:\n\t\treturn strconv.FormatInt(int64(v), 10), nil\n\tcase int16:\n\t\treturn strconv.FormatInt(int64(v), 10), nil\n\tcase int32:\n\t\treturn strconv.FormatInt(int64(v), 10), nil\n\tcase int64:\n\t\treturn strconv.FormatInt(v, 10), nil\n\tcase uint:\n\t\treturn strconv.FormatUint(uint64(v), 10), nil\n\tcase uint8:\n\t\treturn strconv.FormatUint(uint64(v), 10), nil\n\tcase uint16:\n\t\treturn strconv.FormatUint(uint64(v), 10), nil\n\tcase uint32:\n\t\treturn strconv.FormatUint(uint64(v), 10), nil\n\tcase uint64:\n\t\treturn strconv.FormatUint(v, 10), nil\n\tcase float32:\n\t\treturn strconv.FormatFloat(float64(v), 'f', -1, 32), nil\n\tcase float64:\n\t\treturn strconv.FormatFloat(v, 'f', -1, 64), nil\n\tcase bool:\n\t\treturn strconv.FormatBool(v), nil\n\tcase fmt.Stringer:\n\t\treturn v.String(), nil\n\tcase nil:\n\t\treturn \"\", nil\n\t}\n\treturn \"\", fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n\nfunc ToBool(value interface{}) (bool, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn strconv.ParseBool(v)\n\tcase []byte:\n\t\treturn strconv.ParseBool(string(v))\n\tcase fmt.Stringer:\n\t\treturn strconv.ParseBool(v.String())\n\tcase int:\n\t\treturn v > 0, nil\n\tcase int8:\n\t\treturn v > 0, nil\n\tcase int16:\n\t\treturn v > 0, nil\n\tcase int32:\n\t\treturn v > 0, nil\n\tcase int64:\n\t\treturn v > 0, nil\n\tcase uint:\n\t\treturn v > 0, nil\n\tcase uint8:\n\t\treturn v > 0, nil\n\tcase uint16:\n\t\treturn v > 0, nil\n\tcase uint32:\n\t\treturn v > 0, nil\n\tcase uint64:\n\t\treturn v > 0, nil\n\tcase float32:\n\t\treturn v > 0, nil\n\tcase float64:\n\t\treturn v > 0, nil\n\tcase bool:\n\t\treturn v, nil\n\tcase nil:\n\t\treturn false, nil\n\t}\n\treturn false, fmt.Errorf(\"type \\\"%T\\\" unsupported\", value)\n}\n"
  },
  {
    "path": "logger/event_logger.go",
    "content": "//go:build windows\n\npackage logger\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"golang.org/x/sys/windows/svc/eventlog\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nconst (\n\teidInfo    = 1\n\teidWarning = 2\n\teidError   = 3\n)\n\ntype eventLogger struct {\n\teventlog *eventlog.Log\n\terrlog   *log.Logger\n}\n\nfunc (l *eventLogger) Close() error {\n\tif l.eventlog == nil {\n\t\treturn nil\n\t}\n\tif err := l.eventlog.Close(); err != nil {\n\t\treturn err\n\t}\n\tl.eventlog = nil\n\treturn nil\n}\n\nfunc (l *eventLogger) Print(level telegraf.LogLevel, _ time.Time, prefix string, _ map[string]interface{}, args ...interface{}) {\n\t// Skip debug and beyond as they cannot be logged\n\tif level >= telegraf.Debug {\n\t\treturn\n\t}\n\n\tmsg := prefix + fmt.Sprint(args...)\n\n\tvar err error\n\tswitch level {\n\tcase telegraf.Error:\n\t\terr = l.eventlog.Error(eidError, msg)\n\tcase telegraf.Warn:\n\t\terr = l.eventlog.Warning(eidWarning, msg)\n\tcase telegraf.Info:\n\t\terr = l.eventlog.Info(eidInfo, msg)\n\t}\n\tif err != nil {\n\t\tl.errlog.Printf(\"E! Writing log message failed: %v\", err)\n\t}\n\n\t// TODO attributes...\n}\n\nfunc createEventLogger(cfg *Config) (sink, error) {\n\teventLog, err := eventlog.Open(cfg.InstanceName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tl := &eventLogger{\n\t\teventlog: eventLog,\n\t\terrlog:   log.New(os.Stderr, \"\", 0),\n\t}\n\n\treturn l, nil\n}\n\nfunc init() {\n\tadd(\"eventlog\", createEventLogger)\n}\n"
  },
  {
    "path": "logger/event_logger_test.go",
    "content": "//go:build windows\n\npackage logger\n\nimport (\n\t\"bytes\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"log\"\n\t\"os/exec\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype Levels int\n\nconst (\n\tInfo Levels = iota + 1\n\tWarning\n\tError\n)\n\ntype Event struct {\n\tMessage string `xml:\"EventData>Data\"`\n\tLevel   Levels `xml:\"System>EventID\"`\n}\n\nfunc getEventLog(t *testing.T, since time.Time) []Event {\n\ttimeStr := since.UTC().Format(time.RFC3339)\n\ttimeStr = timeStr[:19]\n\targs := []string{\n\t\t\"qe\",\n\t\t\"Application\",\n\t\t\"/rd:true\",\n\t\tfmt.Sprintf(\"/q:Event[System[TimeCreated[@SystemTime >= %q] and Provider[@Name='telegraf']]]\", timeStr)}\n\tcmd := exec.Command(\"wevtutil\", args...)\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\trequire.NoError(t, err)\n\txmlStr := \"<events>\" + out.String() + \"</events>\"\n\tvar events struct {\n\t\tEvents []Event `xml:\"Event\"`\n\t}\n\terr = xml.Unmarshal([]byte(xmlStr), &events)\n\trequire.NoError(t, err)\n\treturn events.Events\n}\n\nfunc TestEventLogIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\tconfig := &Config{\n\t\tLogFormat: \"eventlog\",\n\t\tLogfile:   \"\",\n\t}\n\trequire.NoError(t, SetupLogging(config))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tnow := time.Now()\n\tlog.Println(\"I! Info message\")\n\tlog.Println(\"W! Warn message\")\n\tlog.Println(\"E! Err message\")\n\tevents := getEventLog(t, now)\n\trequire.Len(t, events, 3)\n\trequire.Contains(t, events, Event{Message: \"Info message\", Level: Info})\n\trequire.Contains(t, events, Event{Message: \"Warn message\", Level: Warning})\n\trequire.Contains(t, events, Event{Message: \"Err message\", Level: Error})\n}\n\nfunc TestRestrictedEventLogIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in  short mode\")\n\t}\n\n\tconfig := &Config{\n\t\tLogFormat: \"eventlog\",\n\t\tQuiet:     true,\n\t}\n\trequire.NoError(t, SetupLogging(config))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\t// separate previous log messages by small delay\n\ttime.Sleep(time.Second)\n\tnow := time.Now()\n\tlog.Println(\"I! Info message\")\n\tlog.Println(\"W! Warning message\")\n\tlog.Println(\"E! Error message\")\n\tevents := getEventLog(t, now)\n\trequire.Len(t, events, 1)\n\trequire.Contains(t, events, Event{Message: \"Error message\", Level: Error})\n}\n"
  },
  {
    "path": "logger/handler.go",
    "content": "package logger\n\nimport (\n\t\"container/list\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype entry struct {\n\ttimestamp  time.Time\n\tlevel      telegraf.LogLevel\n\tprefix     string\n\tattributes map[string]interface{}\n\targs       []interface{}\n}\n\ntype handler struct {\n\tlevel    telegraf.LogLevel\n\ttimezone *time.Location\n\n\timpl      sink\n\tearlysink *log.Logger\n\tearlylogs *list.List\n\tsync.Mutex\n}\n\nfunc defaultHandler() *handler {\n\treturn &handler{\n\t\tlevel:     telegraf.Info,\n\t\ttimezone:  time.UTC,\n\t\tearlysink: log.New(os.Stderr, \"\", 0),\n\t\tearlylogs: list.New(),\n\t}\n}\n\nfunc redirectHandler(w io.Writer) *handler {\n\treturn &handler{\n\t\tlevel:     99,\n\t\ttimezone:  time.UTC,\n\t\timpl:      &redirectLogger{writer: w},\n\t\tearlysink: log.New(w, \"\", 0),\n\t\tearlylogs: list.New(),\n\t}\n}\n\nfunc (h *handler) switchSink(impl sink, level telegraf.LogLevel, tz *time.Location, skipEarlyLogs bool) {\n\t// Setup the new sink etc\n\th.impl = impl\n\th.level = level\n\th.timezone = tz\n\n\t// Use the new logger to output the early log-messages\n\th.Lock()\n\tif !skipEarlyLogs && h.earlylogs.Len() > 0 {\n\t\tcurrent := h.earlylogs.Front()\n\t\tfor current != nil {\n\t\t\te := current.Value.(*entry)\n\t\t\th.impl.Print(e.level, e.timestamp.In(h.timezone), e.prefix, e.attributes, e.args...)\n\t\t\tnext := current.Next()\n\t\t\th.earlylogs.Remove(current)\n\t\t\tcurrent = next\n\t\t}\n\t}\n\th.Unlock()\n}\n\nfunc (h *handler) add(level telegraf.LogLevel, ts time.Time, prefix string, attr map[string]interface{}, args ...interface{}) *entry {\n\te := &entry{\n\t\ttimestamp:  ts,\n\t\tlevel:      level,\n\t\tprefix:     prefix,\n\t\tattributes: attr,\n\t\targs:       args,\n\t}\n\n\th.Lock()\n\th.earlylogs.PushBack(e)\n\th.Unlock()\n\n\treturn e\n}\n\nfunc (h *handler) close() error {\n\tif h.impl == nil {\n\t\treturn nil\n\t}\n\n\th.Lock()\n\tcurrent := h.earlylogs.Front()\n\tfor current != nil {\n\t\th.earlylogs.Remove(current)\n\t\tcurrent = h.earlylogs.Front()\n\t}\n\th.Unlock()\n\n\tif l, ok := h.impl.(io.Closer); ok {\n\t\treturn l.Close()\n\t}\n\n\treturn nil\n}\n\n// Logger to redirect the logs to an arbitrary writer\ntype redirectLogger struct {\n\twriter io.Writer\n}\n\nfunc (l *redirectLogger) Print(level telegraf.LogLevel, ts time.Time, prefix string, attr map[string]interface{}, args ...interface{}) {\n\tvar attrMsg string\n\tif len(attr) > 0 {\n\t\tparts := make([]string, 0, len(attr))\n\t\tfor k, v := range attr {\n\t\t\tparts = append(parts, fmt.Sprintf(\"%s=%v\", k, v))\n\t\t}\n\t\tattrMsg = \"(\" + strings.Join(parts, \",\") + \")\"\n\t}\n\n\tmsg := []interface{}{ts.In(time.UTC).Format(time.RFC3339), level.Indicator()}\n\tif prefix+attrMsg != \"\" {\n\t\tmsg = append(msg, prefix+attrMsg)\n\t}\n\tmsg = append(msg, args...)\n\n\tfmt.Fprintln(l.writer, msg...)\n}\n\nfunc (l *redirectLogger) Close() error {\n\tif l.writer == os.Stderr {\n\t\treturn nil\n\t}\n\tif closer, ok := l.writer.(io.Closer); ok {\n\t\treturn closer.Close()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "logger/logger.go",
    "content": "package logger\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Central handler for the logs used by the logger to actually output the logs.\n// This is necessary to be able to dynamically switch the sink even though\n// plugins already instantiated a logger _before_ the final sink is set up.\nvar (\n\tinstance   *handler                // handler for the actual output\n\tcallbacks  map[string]CallbackFunc // logging callback registry\n\tcallbackMu sync.RWMutex\n\tonce       sync.Once // once token to initialize the handler only once\n)\n\n// CallbackFunc is a function to be called when printing messages\ntype CallbackFunc func(\n\tlevel telegraf.LogLevel,\n\ttimestamp time.Time,\n\tsource string,\n\tattributes map[string]interface{},\n\targuments ...interface{},\n)\n\n// sink interface that has to be implemented by a logging sink\ntype sink interface {\n\tPrint(telegraf.LogLevel, time.Time, string, map[string]interface{}, ...interface{})\n}\n\n// logger is the actual implementation of the telegraf logger interface\ntype logger struct {\n\tlevel    *telegraf.LogLevel\n\tcategory string\n\tname     string\n\talias    string\n\n\tsource     string\n\tprefix     string\n\tonError    []func()\n\tattributes map[string]interface{}\n}\n\n// New creates a new logging instance to be used in models\nfunc New(category, name, alias string) *logger {\n\tl := &logger{\n\t\tcategory:   category,\n\t\tname:       name,\n\t\talias:      alias,\n\t\tattributes: map[string]interface{}{\"category\": category, \"plugin\": name},\n\t}\n\tif alias != \"\" {\n\t\tl.attributes[\"alias\"] = alias\n\t}\n\n\t// Format the prefix\n\tl.source = l.category\n\n\tif l.source != \"\" && l.name != \"\" {\n\t\tl.source += \".\"\n\t}\n\tl.source += l.name\n\n\tif l.source != \"\" && l.alias != \"\" {\n\t\tl.source += \"::\"\n\t}\n\tl.source += l.alias\n\tif l.source != \"\" {\n\t\tl.prefix = \"[\" + l.source + \"] \"\n\t}\n\n\treturn l\n}\n\n// Level returns the current log-level of the logger\nfunc (l *logger) Level() telegraf.LogLevel {\n\tif l.level != nil {\n\t\treturn *l.level\n\t}\n\treturn instance.level\n}\n\n// AddAttribute allows to add a key-value attribute to the logging output\nfunc (l *logger) AddAttribute(key string, value interface{}) {\n\t// Do not allow to overwrite general keys\n\tswitch key {\n\tcase \"category\", \"plugin\", \"alias\":\n\tdefault:\n\t\tl.attributes[key] = value\n\t}\n}\n\n// Error logging including callbacks\nfunc (l *logger) Errorf(format string, args ...interface{}) {\n\tl.Error(fmt.Sprintf(format, args...))\n}\n\nfunc (l *logger) Error(args ...interface{}) {\n\tl.Print(telegraf.Error, time.Now(), args...)\n\tfor _, f := range l.onError {\n\t\tf()\n\t}\n}\n\n// Warning logging\nfunc (l *logger) Warnf(format string, args ...interface{}) {\n\tl.Warn(fmt.Sprintf(format, args...))\n}\n\nfunc (l *logger) Warn(args ...interface{}) {\n\tl.Print(telegraf.Warn, time.Now(), args...)\n}\n\n// Info logging\nfunc (l *logger) Infof(format string, args ...interface{}) {\n\tl.Info(fmt.Sprintf(format, args...))\n}\n\nfunc (l *logger) Info(args ...interface{}) {\n\tl.Print(telegraf.Info, time.Now(), args...)\n}\n\n// Debug logging, this is suppressed on console\nfunc (l *logger) Debugf(format string, args ...interface{}) {\n\tl.Debug(fmt.Sprintf(format, args...))\n}\n\nfunc (l *logger) Debug(args ...interface{}) {\n\tl.Print(telegraf.Debug, time.Now(), args...)\n}\n\n// Trace logging, this is suppressed on console\nfunc (l *logger) Tracef(format string, args ...interface{}) {\n\tl.Trace(fmt.Sprintf(format, args...))\n}\n\nfunc (l *logger) Trace(args ...interface{}) {\n\tl.Print(telegraf.Trace, time.Now(), args...)\n}\n\nfunc (l *logger) Print(level telegraf.LogLevel, ts time.Time, args ...interface{}) {\n\t// Check if we are in early logging state and store the message in this case\n\tif instance.impl == nil {\n\t\tinstance.add(level, ts, l.prefix, l.attributes, args...)\n\t}\n\n\t// Serve all registered callbacks before checking the log-level. This is\n\t// intentional to allow the callback to apply its own log-level filtering.\n\tcallbackMu.RLock()\n\tfor _, cb := range callbacks {\n\t\tcb(level, ts.UTC(), l.source, l.attributes, args...)\n\t}\n\tcallbackMu.RUnlock()\n\n\t// Skip all messages with insufficient log-levels\n\tif l.level != nil && !l.level.Includes(level) || l.level == nil && !instance.level.Includes(level) {\n\t\treturn\n\t}\n\tif instance.impl != nil {\n\t\tinstance.impl.Print(level, ts.In(instance.timezone), l.prefix, l.attributes, args...)\n\t} else {\n\t\tmsg := append([]interface{}{ts.In(instance.timezone).Format(time.RFC3339), \" \", level.Indicator(), \" \", l.prefix}, args...)\n\t\tinstance.earlysink.Print(msg...)\n\t}\n}\n\n// SetLevel overrides the current log-level of the logger\nfunc (l *logger) SetLevel(level telegraf.LogLevel) {\n\tl.level = &level\n}\n\n// SetLevel changes the log-level to the given one\nfunc (l *logger) SetLogLevel(name string) error {\n\tif name == \"\" {\n\t\treturn nil\n\t}\n\tlevel := telegraf.LogLevelFromString(name)\n\tif level == telegraf.None {\n\t\treturn fmt.Errorf(\"invalid log-level %q\", name)\n\t}\n\tl.SetLevel(level)\n\treturn nil\n}\n\n// Register a callback triggered when errors are about to be written to the log\nfunc (l *logger) RegisterErrorCallback(f func()) {\n\tl.onError = append(l.onError, f)\n}\n\ntype Config struct {\n\t// will set the log level to DEBUG\n\tDebug bool\n\t// will set the log level to ERROR\n\tQuiet bool\n\t// format and target of log messages\n\tLogTarget string\n\tLogFormat string\n\tLogfile   string\n\t// will rotate when current file at the specified time interval\n\tRotationInterval time.Duration\n\t// will rotate when current file size exceeds this parameter.\n\tRotationMaxSize int64\n\t// maximum rotated files to keep (older ones will be deleted)\n\tRotationMaxArchives int\n\t// pick a timezone to use when logging. or type 'local' for local time.\n\tLogWithTimezone string\n\t// Logger instance name\n\tInstanceName string\n\t// Structured logging message key\n\tStructuredLogMessageKey string\n\n\t// internal  log-level\n\tlogLevel telegraf.LogLevel\n}\n\n// SetupLogging configures the logging output.\nfunc SetupLogging(cfg *Config) error {\n\t// Issue deprecation warning for option\n\tswitch cfg.LogTarget {\n\tcase \"\":\n\t\t// Best-case no target set or file already migrated...\n\tcase \"stderr\":\n\t\tmsg := \"Agent setting %q is deprecated, please leave %q empty and remove this setting!\"\n\t\tdeprecation := \"The setting will be removed in v1.40.0.\"\n\t\tlog.Printf(\"W! \"+msg+\" \"+deprecation, \"logtarget\", \"logfile\")\n\t\tcfg.Logfile = \"\"\n\tcase \"file\":\n\t\tmsg := \"Agent setting %q is deprecated, please just set %q and remove this setting!\"\n\t\tdeprecation := \"The setting will be removed in v1.40.0.\"\n\t\tlog.Printf(\"W! \"+msg+\" \"+deprecation, \"logtarget\", \"logfile\")\n\tcase \"eventlog\":\n\t\tmsg := \"Agent setting %q is deprecated, please set %q to %q and remove this setting!\"\n\t\tdeprecation := \"The setting will be removed in v1.40.0.\"\n\t\tlog.Printf(\"W! \"+msg+\" \"+deprecation, \"logtarget\", \"logformat\", \"eventlog\")\n\t\tif cfg.LogFormat != \"\" && cfg.LogFormat != \"eventlog\" {\n\t\t\treturn errors.New(\"contradicting setting between 'logtarget' and 'logformat'\")\n\t\t}\n\t\tcfg.LogFormat = \"eventlog\"\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid deprecated 'logtarget' setting %q\", cfg.LogTarget)\n\t}\n\n\tif cfg.LogFormat == \"\" {\n\t\tcfg.LogFormat = \"text\"\n\t}\n\n\tif cfg.Debug {\n\t\tcfg.logLevel = telegraf.Debug\n\t}\n\tif cfg.Quiet {\n\t\tcfg.logLevel = telegraf.Error\n\t}\n\tif !cfg.Debug && !cfg.Quiet {\n\t\tcfg.logLevel = telegraf.Info\n\t}\n\n\tif cfg.InstanceName == \"\" {\n\t\tcfg.InstanceName = \"telegraf\"\n\t}\n\n\tif cfg.LogFormat == \"\" {\n\t\tcfg.LogFormat = \"text\"\n\t}\n\n\t// Get configured timezone\n\ttimezoneName := cfg.LogWithTimezone\n\tif strings.EqualFold(timezoneName, \"local\") {\n\t\ttimezoneName = \"Local\"\n\t}\n\ttz, err := time.LoadLocation(timezoneName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"setting logging timezone failed: %w\", err)\n\t}\n\n\t// Get the logging factory and create the root instance\n\tcreator, found := registry[cfg.LogFormat]\n\tif !found {\n\t\treturn fmt.Errorf(\"unsupported log-format: %s\", cfg.LogFormat)\n\t}\n\n\tl, err := creator(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Close the previous logger if possible\n\tif err := CloseLogging(); err != nil {\n\t\treturn err\n\t}\n\n\t// Update the logging instance\n\tskipEarlyLogs := cfg.LogFormat == \"text\" && cfg.Logfile == \"\"\n\tinstance.switchSink(l, cfg.logLevel, tz, skipEarlyLogs)\n\n\treturn nil\n}\n\nfunc RedirectLogging(w io.Writer) {\n\tinstance = redirectHandler(w)\n}\n\nfunc CloseLogging() error {\n\tif instance == nil {\n\t\treturn nil\n\t}\n\n\tif err := instance.close(); err != nil && !errors.Is(err, os.ErrClosed) {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// AddCallback adds the given callback function to the registry and returns an\n// ID that can be used for removing the callback later. Callback functions must\n// not block or take a lot of time!\nfunc AddCallback(callback CallbackFunc) (string, error) {\n\t// Create a cookie to be returned to the caller in order to be able to\n\t// remove the callback later\n\trawid, err := uuid.NewRandom()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tid := rawid.String()\n\n\tcallbackMu.Lock()\n\tcallbacks[id] = callback\n\tcallbackMu.Unlock()\n\n\treturn id, nil\n}\n\n// RemoveCallback removes the callback function with the given ID from the registry\nfunc RemoveCallback(id string) {\n\tcallbackMu.Lock()\n\tdefer callbackMu.Unlock()\n\tdelete(callbacks, id)\n}\n\nfunc init() {\n\tonce.Do(func() {\n\t\t// Create a special logging instance that additionally buffers all\n\t\t// messages logged before the final logger is up.\n\t\tinstance = defaultHandler()\n\n\t\t// Setup callback registry\n\t\tcallbacks = make(map[string]CallbackFunc)\n\n\t\t// Redirect the standard logger output to our logger instance\n\t\tlog.SetFlags(0)\n\t\tlog.SetOutput(&stdlogRedirector{})\n\t})\n}\n"
  },
  {
    "path": "logger/logger_test.go",
    "content": "package logger\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\nfunc TestTextLogTargetDefault(t *testing.T) {\n\tinstance = defaultHandler()\n\tcfg := &Config{\n\t\tQuiet: true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlogger, ok := instance.impl.(*textLogger)\n\trequire.Truef(t, ok, \"logging instance is not a default-logger but %T\", instance.impl)\n\trequire.Equal(t, logger.logger.Writer(), os.Stderr)\n}\n\nfunc TestErrorCounting(t *testing.T) {\n\treg := selfstat.Register(\n\t\t\"gather\",\n\t\t\"errors\",\n\t\tmap[string]string{\"input\": \"test\"},\n\t)\n\tiLog := New(\"inputs\", \"test\", \"\")\n\tiLog.RegisterErrorCallback(func() {\n\t\treg.Incr(1)\n\t})\n\tiLog.Error(\"something went wrong\")\n\tiLog.Errorf(\"something went wrong\")\n\n\trequire.Equal(t, int64(2), reg.Get())\n}\n"
  },
  {
    "path": "logger/registry.go",
    "content": "package logger\n\ntype creator func(cfg *Config) (sink, error)\n\nvar registry = make(map[string]creator)\n\nfunc add(name string, creator creator) {\n\tregistry[name] = creator\n}\n"
  },
  {
    "path": "logger/stdlog_redirector.go",
    "content": "package logger\n\nimport (\n\t\"bytes\"\n)\n\ntype stdlogRedirector struct {\n\tlog logger\n}\n\nfunc (s *stdlogRedirector) Write(b []byte) (n int, err error) {\n\tmsg := bytes.Trim(b, \" \\t\\r\\n\")\n\n\t// Check a potential log-level indicator  and log with the given level or\n\t// use info by default\n\tswitch {\n\tcase bytes.HasPrefix(msg, []byte(\"E! \")):\n\t\ts.log.Error(string(msg[3:]))\n\tcase bytes.HasPrefix(msg, []byte(\"W! \")):\n\t\ts.log.Warn(string(msg[3:]))\n\tcase bytes.HasPrefix(msg, []byte(\"I! \")):\n\t\ts.log.Info(string(msg[3:]))\n\tcase bytes.HasPrefix(msg, []byte(\"D! \")):\n\t\ts.log.Debug(string(msg[3:]))\n\tcase bytes.HasPrefix(msg, []byte(\"T! \")):\n\t\ts.log.Trace(string(msg[3:]))\n\tdefault:\n\t\ts.log.Info(string(msg))\n\t}\n\n\treturn len(b), nil\n}\n"
  },
  {
    "path": "logger/structured_logger.go",
    "content": "package logger\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"log/slog\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/rotate\"\n)\n\ntype structuredLogger struct {\n\thandler slog.Handler\n\toutput  io.Writer\n\n\terrlog *log.Logger\n}\n\nfunc (l *structuredLogger) Close() error {\n\t// Close the writer if possible and avoid closing stderr\n\tif l.output == os.Stderr {\n\t\treturn nil\n\t}\n\n\tif closer, ok := l.output.(io.Closer); ok {\n\t\treturn closer.Close()\n\t}\n\treturn nil\n}\n\nfunc (l *structuredLogger) Print(level telegraf.LogLevel, ts time.Time, _ string, attr map[string]interface{}, args ...interface{}) {\n\trecord := slog.Record{\n\t\tTime:    ts,\n\t\tMessage: fmt.Sprint(args...),\n\t\tLevel:   slog.Level(level),\n\t}\n\tfor k, v := range attr {\n\t\trecord.Add(k, v)\n\t}\n\tif err := l.handler.Handle(context.Background(), record); err != nil {\n\t\tl.errlog.Printf(\"E! Writing log message failed: %v\", err)\n\t}\n}\n\nvar defaultReplaceAttr = func(_ []string, attr slog.Attr) slog.Attr {\n\t// Translate the Telegraf log-levels to strings\n\tif attr.Key == slog.LevelKey {\n\t\tif level, ok := attr.Value.Any().(slog.Level); ok {\n\t\t\tattr.Value = slog.StringValue(telegraf.LogLevel(level).String())\n\t\t}\n\t}\n\treturn attr\n}\n\nvar defaultStructuredHandlerOptions = &slog.HandlerOptions{\n\tLevel:       slog.Level(-99),\n\tReplaceAttr: defaultReplaceAttr,\n}\n\nfunc init() {\n\tadd(\"structured\", func(cfg *Config) (sink, error) {\n\t\tvar writer io.Writer = os.Stderr\n\t\tif cfg.Logfile != \"\" {\n\t\t\tw, err := rotate.NewFileWriter(\n\t\t\t\tcfg.Logfile,\n\t\t\t\tcfg.RotationInterval,\n\t\t\t\tcfg.RotationMaxSize,\n\t\t\t\tcfg.RotationMaxArchives,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\twriter = w\n\t\t}\n\n\t\tstructuredHandlerOptions := defaultStructuredHandlerOptions\n\n\t\tif cfg.StructuredLogMessageKey != \"\" {\n\t\t\tstructuredHandlerOptions.ReplaceAttr = func(groups []string, attr slog.Attr) slog.Attr {\n\t\t\t\tif attr.Key == slog.MessageKey {\n\t\t\t\t\tattr.Key = cfg.StructuredLogMessageKey\n\t\t\t\t}\n\n\t\t\t\treturn defaultReplaceAttr(groups, attr)\n\t\t\t}\n\t\t}\n\n\t\treturn &structuredLogger{\n\t\t\thandler: slog.NewJSONHandler(writer, structuredHandlerOptions),\n\t\t\toutput:  writer,\n\t\t\terrlog:  log.New(os.Stderr, \"\", 0),\n\t\t}, nil\n\t})\n}\n"
  },
  {
    "path": "logger/structured_logger_test.go",
    "content": "package logger\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"log\"\n\t\"log/slog\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc TestStructuredStderr(t *testing.T) {\n\tinstance = defaultHandler()\n\tcfg := &Config{\n\t\tLogFormat: \"structured\",\n\t\tQuiet:     true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlogger, ok := instance.impl.(*structuredLogger)\n\trequire.Truef(t, ok, \"logging instance is not a structured-logger but %T\", instance.impl)\n\trequire.Equal(t, logger.output, os.Stderr)\n}\n\nfunc TestStructuredFile(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"I! TEST\")\n\tlog.Printf(\"D! TEST\") // <- should be ignored\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\": \"INFO\",\n\t\t\"msg\":   \"TEST\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredFileDebug(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"D! TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\": \"DEBUG\",\n\t\t\"msg\":   \"TEST\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredFileError(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tQuiet:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"E! TEST\")\n\tlog.Printf(\"I! TEST\") // <- should be ignored\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\n\texpected := map[string]interface{}{\n\t\t\"level\": \"ERROR\",\n\t\t\"msg\":   \"TEST\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredAddDefaultLogLevel(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\": \"INFO\",\n\t\t\"msg\":   \"TEST\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredDerivedLogger(t *testing.T) {\n\tinstance = defaultHandler()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tl := New(\"testing\", \"test\", \"\")\n\tl.Info(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\":    \"INFO\",\n\t\t\"msg\":      \"TEST\",\n\t\t\"category\": \"testing\",\n\t\t\"plugin\":   \"test\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredDerivedLoggerWithAttributes(t *testing.T) {\n\tinstance = defaultHandler()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tl := New(\"testing\", \"test\", \"myalias\")\n\tl.AddAttribute(\"alias\", \"foo\") // Should be ignored\n\tl.AddAttribute(\"device_id\", 123)\n\n\tl.Info(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\":     \"INFO\",\n\t\t\"msg\":       \"TEST\",\n\t\t\"category\":  \"testing\",\n\t\t\"plugin\":    \"test\",\n\t\t\"alias\":     \"myalias\",\n\t\t\"device_id\": float64(123),\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredWriteToTruncatedFile(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\": \"INFO\",\n\t\t\"msg\":   \"TEST\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n\n\trequire.NoError(t, os.Truncate(filename, 0))\n\n\tlog.Printf(\"SHOULD BE FIRST\")\n\n\tbuf, err = os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected = map[string]interface{}{\n\t\t\"level\": \"INFO\",\n\t\t\"msg\":   \"SHOULD BE FIRST\",\n\t}\n\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestStructuredWriteToFileInRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tcfg := &Config{\n\t\tLogfile:             filepath.Join(tempDir, \"test.log\"),\n\t\tLogFormat:           \"structured\",\n\t\tRotationMaxArchives: -1,\n\t\tRotationMaxSize:     70,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"I! TEST 1\") // Writes 70 bytes in structured format, will rotate\n\tlog.Printf(\"I! TEST\")   // Writes 68 bytes in structured format, no rotation expected\n\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestStructuredLogMessageKey(t *testing.T) {\n\tinstance = defaultHandler()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:                 filename,\n\t\tLogFormat:               \"structured\",\n\t\tRotationMaxArchives:     -1,\n\t\tDebug:                   true,\n\t\tStructuredLogMessageKey: \"message\",\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tl := New(\"testing\", \"test\", \"\")\n\tl.Info(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"level\":    \"INFO\",\n\t\t\"message\":  \"TEST\",\n\t\t\"category\": \"testing\",\n\t\t\"plugin\":   \"test\",\n\t}\n\n\tvar actual map[string]interface{}\n\trequire.NoError(t, json.Unmarshal(buf, &actual))\n\n\trequire.Contains(t, actual, \"time\")\n\trequire.NotEmpty(t, actual[\"time\"])\n\tdelete(actual, \"time\")\n\trequire.Equal(t, expected, actual)\n}\n\nfunc BenchmarkTelegrafStructuredLogWrite(b *testing.B) {\n\t// Discard all logging output\n\tl := &structuredLogger{\n\t\thandler: slog.NewJSONHandler(io.Discard, defaultStructuredHandlerOptions),\n\t\toutput:  io.Discard,\n\t\terrlog:  log.New(os.Stderr, \"\", 0),\n\t}\n\n\tts := time.Now()\n\tfor i := 0; i < b.N; i++ {\n\t\tl.Print(telegraf.Debug, ts, \"\", nil, \"test\")\n\t}\n}\n"
  },
  {
    "path": "logger/text_logger.go",
    "content": "package logger\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/rotate\"\n)\n\n// Keep those constants for backward compatibility even though they are not\n// used anywhere. See https://github.com/influxdata/telegraf/pull/15514 for\n// more details.\n//\n// Deprecated: Those constants are unused and deprecated. The removal is\n// scheduled for v1.45.0, if you use them please adapt your code!\nconst (\n\tLogTargetFile   = \"file\"\n\tLogTargetStderr = \"stderr\"\n)\n\ntype textLogger struct {\n\tlogger *log.Logger\n}\n\nfunc (l *textLogger) Close() error {\n\twriter := l.logger.Writer()\n\n\t// Close the writer if possible and avoid closing stderr\n\tif writer == os.Stderr {\n\t\treturn nil\n\t}\n\tif closer, ok := writer.(io.Closer); ok {\n\t\treturn closer.Close()\n\t}\n\n\treturn errors.New(\"the underlying writer cannot be closed\")\n}\n\nfunc (l *textLogger) Print(level telegraf.LogLevel, ts time.Time, prefix string, _ map[string]interface{}, args ...interface{}) {\n\tmsg := append([]interface{}{ts.Format(time.RFC3339), \" \", level.Indicator(), \" \", prefix}, args...)\n\tl.logger.Print(msg...)\n}\n\nfunc createTextLogger(cfg *Config) (sink, error) {\n\tvar writer io.Writer = os.Stderr\n\tif cfg.Logfile != \"\" {\n\t\tw, err := rotate.NewFileWriter(\n\t\t\tcfg.Logfile,\n\t\t\tcfg.RotationInterval,\n\t\t\tcfg.RotationMaxSize,\n\t\t\tcfg.RotationMaxArchives,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\twriter = w\n\t}\n\n\treturn &textLogger{logger: log.New(writer, \"\", 0)}, nil\n}\n\nfunc init() {\n\tadd(\"text\", createTextLogger)\n}\n"
  },
  {
    "path": "logger/text_logger_test.go",
    "content": "package logger\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc TestTextStderr(t *testing.T) {\n\tinstance = defaultHandler()\n\tcfg := &Config{\n\t\tLogFormat: \"text\",\n\t\tQuiet:     true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlogger, ok := instance.impl.(*textLogger)\n\trequire.Truef(t, ok, \"logging instance is not a text-logger but %T\", instance.impl)\n\trequire.Equal(t, logger.logger.Writer(), os.Stderr)\n}\n\nfunc TestTextFile(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"I! TEST\")\n\tlog.Printf(\"D! TEST\") // <- should be ignored\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z I! TEST\\n\", string(buf[19:]))\n}\n\nfunc TestTextFileDebug(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"D! TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z D! TEST\\n\", string(buf[19:]))\n}\n\nfunc TestTextFileError(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tQuiet:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"E! TEST\")\n\tlog.Printf(\"I! TEST\") // <- should be ignored\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z E! TEST\\n\", string(buf[19:]))\n}\n\nfunc TestTextAddDefaultLogLevel(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z I! TEST\\n\", string(buf[19:]))\n}\n\nfunc TestTextWriteToTruncatedFile(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z I! TEST\\n\", string(buf[19:]))\n\n\trequire.NoError(t, os.Truncate(filename, 0))\n\n\tlog.Printf(\"SHOULD BE FIRST\")\n\n\tbuf, err = os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"Z I! SHOULD BE FIRST\\n\", string(buf[19:]))\n}\n\nfunc TestTextWriteToFileInRotation(t *testing.T) {\n\ttempDir := t.TempDir()\n\tcfg := &Config{\n\t\tLogfile:             filepath.Join(tempDir, \"test.log\"),\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tRotationMaxSize:     30,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tlog.Printf(\"I! TEST 1\") // Writes 31 bytes, will rotate\n\tlog.Printf(\"I! TEST\")   // Writes 29 byes, no rotation expected\n\n\tfiles, err := os.ReadDir(tempDir)\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2)\n}\n\nfunc TestTextWriteDerivedLogger(t *testing.T) {\n\tinstance = defaultHandler()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tl := New(\"testing\", \"test\", \"\")\n\tl.Info(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z I! [testing.test] TEST\\n\", string(buf[19:]))\n}\n\nfunc TestTextWriteDerivedLoggerWithAttributes(t *testing.T) {\n\tinstance = defaultHandler()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpfile.Name())\n\n\tfilename := tmpfile.Name()\n\trequire.NoError(t, tmpfile.Close())\n\n\tcfg := &Config{\n\t\tLogfile:             filename,\n\t\tLogFormat:           \"text\",\n\t\tRotationMaxArchives: -1,\n\t\tDebug:               true,\n\t}\n\trequire.NoError(t, SetupLogging(cfg))\n\tdefer func() { require.NoError(t, CloseLogging()) }()\n\n\tl := New(\"testing\", \"test\", \"myalias\")\n\n\t// All attributes should be ignored\n\tl.AddAttribute(\"alias\", \"foo\")\n\tl.AddAttribute(\"device_id\", 123)\n\n\tl.Info(\"TEST\")\n\n\tbuf, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\trequire.Greater(t, len(buf), 19)\n\trequire.Equal(t, \"Z I! [testing.test::myalias] TEST\\n\", string(buf[19:]))\n}\n\nfunc BenchmarkTelegrafTextLogWrite(b *testing.B) {\n\tl, err := createTextLogger(&Config{})\n\trequire.NoError(b, err)\n\n\t// Discard all logging output\n\tdl := l.(*textLogger)\n\tdl.logger.SetOutput(io.Discard)\n\n\tts := time.Now()\n\tfor i := 0; i < b.N; i++ {\n\t\tdl.Print(telegraf.Debug, ts, \"\", nil, \"test\")\n\t}\n}\n"
  },
  {
    "path": "logger.go",
    "content": "package telegraf\n\n// LogLevel denotes the level for logging\ntype LogLevel int\n\nconst (\n\t// None means nothing is logged\n\tNone LogLevel = iota\n\t// Error will log error messages\n\tError\n\t// Warn will log error messages and warnings\n\tWarn\n\t// Info will log error messages, warnings and information messages\n\tInfo\n\t// Debug will log all of the above and debugging messages issued by plugins\n\tDebug\n\t// Trace will log all of the above and trace messages issued by plugins\n\tTrace\n)\n\nfunc LogLevelFromString(name string) LogLevel {\n\tswitch name {\n\tcase \"ERROR\", \"error\":\n\t\treturn Error\n\tcase \"WARN\", \"warn\":\n\t\treturn Warn\n\tcase \"INFO\", \"info\":\n\t\treturn Info\n\tcase \"DEBUG\", \"debug\":\n\t\treturn Debug\n\tcase \"TRACE\", \"trace\":\n\t\treturn Trace\n\t}\n\treturn None\n}\n\nfunc (e LogLevel) String() string {\n\tswitch e {\n\tcase Error:\n\t\treturn \"ERROR\"\n\tcase Warn:\n\t\treturn \"WARN\"\n\tcase Info:\n\t\treturn \"INFO\"\n\tcase Debug:\n\t\treturn \"DEBUG\"\n\tcase Trace:\n\t\treturn \"TRACE\"\n\t}\n\treturn \"NONE\"\n}\n\nfunc (e LogLevel) Indicator() string {\n\tswitch e {\n\tcase Error:\n\t\treturn \"E!\"\n\tcase Warn:\n\t\treturn \"W!\"\n\tcase Info:\n\t\treturn \"I!\"\n\tcase Debug:\n\t\treturn \"D!\"\n\tcase Trace:\n\t\treturn \"T!\"\n\t}\n\treturn \"U!\"\n}\n\nfunc (e LogLevel) Includes(level LogLevel) bool {\n\treturn e >= level\n}\n\n// Logger defines an plugin-related interface for logging.\ntype Logger interface { //nolint:interfacebloat // All functions are required\n\t// Level returns the configured log-level of the logger\n\tLevel() LogLevel\n\n\t// AddAttribute allows to add a key-value attribute to the logging output\n\tAddAttribute(key string, value interface{})\n\n\t// Errorf logs an error message, patterned after log.Printf.\n\tErrorf(format string, args ...interface{})\n\t// Error logs an error message, patterned after log.Print.\n\tError(args ...interface{})\n\t// Warnf logs a warning message, patterned after log.Printf.\n\tWarnf(format string, args ...interface{})\n\t// Warn logs a warning message, patterned after log.Print.\n\tWarn(args ...interface{})\n\t// Infof logs an information message, patterned after log.Printf.\n\tInfof(format string, args ...interface{})\n\t// Info logs an information message, patterned after log.Print.\n\tInfo(args ...interface{})\n\t// Debugf logs a debug message, patterned after log.Printf.\n\tDebugf(format string, args ...interface{})\n\t// Debug logs a debug message, patterned after log.Print.\n\tDebug(args ...interface{})\n\t// Tracef logs a trace message, patterned after log.Printf.\n\tTracef(format string, args ...interface{})\n\t// Trace logs a trace message, patterned after log.Print.\n\tTrace(args ...interface{})\n}\n"
  },
  {
    "path": "metric/deserialize.go",
    "content": "package metric\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// storage for tracking data that can't be serialized to disk\nvar (\n\t// grouped tracking metrics means that ID->Data association is not one to one,\n\t// many metrics could be associated with one tracking ID so we cannot just\n\t// clear this every time in FromBytes.\n\ttrackingStore = make(map[telegraf.TrackingID]telegraf.TrackingData)\n\tmu            = sync.Mutex{}\n\n\t// ErrSkipTracking indicates that tracking information could not be found after\n\t// deserializing a metric from bytes. In this case we should skip the metric\n\t// and continue as if it does not exist.\n\tErrSkipTracking = errors.New(\"metric tracking data not found\")\n)\n\ntype serializedMetric struct {\n\tM   telegraf.Metric\n\tTID telegraf.TrackingID\n}\n\nfunc ToBytes(m telegraf.Metric) ([]byte, error) {\n\tvar sm serializedMetric\n\tif um, ok := m.(telegraf.UnwrappableMetric); ok {\n\t\tsm.M = um.Unwrap()\n\t} else {\n\t\tsm.M = m\n\t}\n\n\tif tm, ok := m.(telegraf.TrackingMetric); ok {\n\t\tsm.TID = tm.TrackingID()\n\t\tmu.Lock()\n\t\ttrackingStore[sm.TID] = tm.TrackingData()\n\t\tmu.Unlock()\n\t}\n\n\tvar buf bytes.Buffer\n\tencoder := gob.NewEncoder(&buf)\n\tif err := encoder.Encode(&sm); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode metric to bytes: %w\", err)\n\t}\n\treturn buf.Bytes(), nil\n}\n\nfunc FromBytes(b []byte) (telegraf.Metric, error) {\n\tbuf := bytes.NewBuffer(b)\n\tdecoder := gob.NewDecoder(buf)\n\n\tvar sm *serializedMetric\n\tif err := decoder.Decode(&sm); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode metric from bytes: %w\", err)\n\t}\n\n\t// Not a tracking metric\n\tif sm.TID == 0 {\n\t\treturn sm.M, nil\n\t}\n\n\t// Try to lookup the tracking ID in the tracking-data store. If we cannot\n\t// find it, this is likely a left-ever from a previous read and we should\n\t// skip the tracking metric.\n\tmu.Lock()\n\tdefer mu.Unlock()\n\ttd, found := trackingStore[sm.TID]\n\tif !found {\n\t\treturn sm.M, ErrSkipTracking\n\t}\n\n\t// Add back the tracking information to the metric\n\treturn &trackingMetric{Metric: sm.M, d: td.(*trackingData)}, nil\n}\n"
  },
  {
    "path": "metric/init.go",
    "content": "package metric\n\nimport \"encoding/gob\"\n\nfunc Init() {\n\tgob.RegisterName(\"metric.metric\", &metric{})\n}\n"
  },
  {
    "path": "metric/metric.go",
    "content": "package metric\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype metric struct {\n\tMetricName   string\n\tMetricTags   []*telegraf.Tag\n\tMetricFields []*telegraf.Field\n\tMetricTime   time.Time\n\n\tMetricType telegraf.ValueType\n}\n\nfunc New(\n\tname string,\n\ttags map[string]string,\n\tfields map[string]interface{},\n\ttm time.Time,\n\ttp ...telegraf.ValueType,\n) telegraf.Metric {\n\tvar vtype telegraf.ValueType\n\tif len(tp) > 0 {\n\t\tvtype = tp[0]\n\t} else {\n\t\tvtype = telegraf.Untyped\n\t}\n\n\tm := &metric{\n\t\tMetricName:   name,\n\t\tMetricTags:   nil,\n\t\tMetricFields: nil,\n\t\tMetricTime:   tm,\n\t\tMetricType:   vtype,\n\t}\n\n\tif len(tags) > 0 {\n\t\tm.MetricTags = make([]*telegraf.Tag, 0, len(tags))\n\t\tfor k, v := range tags {\n\t\t\tm.MetricTags = append(m.MetricTags,\n\t\t\t\t&telegraf.Tag{Key: k, Value: v})\n\t\t}\n\t\tsort.Slice(m.MetricTags, func(i, j int) bool { return m.MetricTags[i].Key < m.MetricTags[j].Key })\n\t}\n\n\tif len(fields) > 0 {\n\t\tm.MetricFields = make([]*telegraf.Field, 0, len(fields))\n\t\tfor k, v := range fields {\n\t\t\tv := convertField(v)\n\t\t\tif v == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tm.MetricFields = append(m.MetricFields, &telegraf.Field{Key: k, Value: v})\n\t\t}\n\t}\n\n\treturn m\n}\n\n// FromMetric returns a deep copy of the metric with any tracking information\n// removed.\nfunc FromMetric(other telegraf.Metric) telegraf.Metric {\n\tm := &metric{\n\t\tMetricName:   other.Name(),\n\t\tMetricTags:   make([]*telegraf.Tag, len(other.TagList())),\n\t\tMetricFields: make([]*telegraf.Field, len(other.FieldList())),\n\t\tMetricTime:   other.Time(),\n\t\tMetricType:   other.Type(),\n\t}\n\n\tfor i, tag := range other.TagList() {\n\t\tm.MetricTags[i] = &telegraf.Tag{Key: tag.Key, Value: tag.Value}\n\t}\n\n\tfor i, field := range other.FieldList() {\n\t\tm.MetricFields[i] = &telegraf.Field{Key: field.Key, Value: field.Value}\n\t}\n\treturn m\n}\n\nfunc (m *metric) String() string {\n\treturn fmt.Sprintf(\"%s %v %v %d\", m.MetricName, m.Tags(), m.Fields(), m.MetricTime.UnixNano())\n}\n\nfunc (m *metric) Name() string {\n\treturn m.MetricName\n}\n\nfunc (m *metric) Tags() map[string]string {\n\ttags := make(map[string]string, len(m.MetricTags))\n\tfor _, tag := range m.MetricTags {\n\t\ttags[tag.Key] = tag.Value\n\t}\n\treturn tags\n}\n\nfunc (m *metric) TagList() []*telegraf.Tag {\n\treturn m.MetricTags\n}\n\nfunc (m *metric) Fields() map[string]interface{} {\n\tfields := make(map[string]interface{}, len(m.MetricFields))\n\tfor _, field := range m.MetricFields {\n\t\tfields[field.Key] = field.Value\n\t}\n\n\treturn fields\n}\n\nfunc (m *metric) FieldList() []*telegraf.Field {\n\treturn m.MetricFields\n}\n\nfunc (m *metric) Time() time.Time {\n\treturn m.MetricTime\n}\n\nfunc (m *metric) Type() telegraf.ValueType {\n\treturn m.MetricType\n}\n\nfunc (m *metric) SetName(name string) {\n\tm.MetricName = name\n}\n\nfunc (m *metric) AddPrefix(prefix string) {\n\tm.MetricName = prefix + m.MetricName\n}\n\nfunc (m *metric) AddSuffix(suffix string) {\n\tm.MetricName = m.MetricName + suffix\n}\n\nfunc (m *metric) AddTag(key, value string) {\n\tfor i, tag := range m.MetricTags {\n\t\tif key > tag.Key {\n\t\t\tcontinue\n\t\t}\n\n\t\tif key == tag.Key {\n\t\t\ttag.Value = value\n\t\t\treturn\n\t\t}\n\n\t\tm.MetricTags = append(m.MetricTags, nil)\n\t\tcopy(m.MetricTags[i+1:], m.MetricTags[i:])\n\t\tm.MetricTags[i] = &telegraf.Tag{Key: key, Value: value}\n\t\treturn\n\t}\n\n\tm.MetricTags = append(m.MetricTags, &telegraf.Tag{Key: key, Value: value})\n}\n\nfunc (m *metric) HasTag(key string) bool {\n\tfor _, tag := range m.MetricTags {\n\t\tif tag.Key == key {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (m *metric) GetTag(key string) (string, bool) {\n\tfor _, tag := range m.MetricTags {\n\t\tif tag.Key == key {\n\t\t\treturn tag.Value, true\n\t\t}\n\t}\n\treturn \"\", false\n}\n\nfunc (m *metric) Tag(key string) string {\n\tv, _ := m.GetTag(key)\n\treturn v\n}\n\nfunc (m *metric) RemoveTag(key string) {\n\tfor i, tag := range m.MetricTags {\n\t\tif tag.Key == key {\n\t\t\tcopy(m.MetricTags[i:], m.MetricTags[i+1:])\n\t\t\tm.MetricTags[len(m.MetricTags)-1] = nil\n\t\t\tm.MetricTags = m.MetricTags[:len(m.MetricTags)-1]\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (m *metric) AddField(key string, value interface{}) {\n\tfor i, field := range m.MetricFields {\n\t\tif key == field.Key {\n\t\t\tm.MetricFields[i] = &telegraf.Field{Key: key, Value: convertField(value)}\n\t\t\treturn\n\t\t}\n\t}\n\tm.MetricFields = append(m.MetricFields, &telegraf.Field{Key: key, Value: convertField(value)})\n}\n\nfunc (m *metric) HasField(key string) bool {\n\tfor _, field := range m.MetricFields {\n\t\tif field.Key == key {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (m *metric) GetField(key string) (interface{}, bool) {\n\tfor _, field := range m.MetricFields {\n\t\tif field.Key == key {\n\t\t\treturn field.Value, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc (m *metric) Field(key string) interface{} {\n\tif v, found := m.GetField(key); found {\n\t\treturn v\n\t}\n\treturn nil\n}\n\nfunc (m *metric) RemoveField(key string) {\n\tfor i, field := range m.MetricFields {\n\t\tif field.Key == key {\n\t\t\tcopy(m.MetricFields[i:], m.MetricFields[i+1:])\n\t\t\tm.MetricFields[len(m.MetricFields)-1] = nil\n\t\t\tm.MetricFields = m.MetricFields[:len(m.MetricFields)-1]\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (m *metric) SetTime(t time.Time) {\n\tm.MetricTime = t\n}\n\nfunc (m *metric) SetType(t telegraf.ValueType) {\n\tm.MetricType = t\n}\n\nfunc (m *metric) Copy() telegraf.Metric {\n\tm2 := &metric{\n\t\tMetricName:   m.MetricName,\n\t\tMetricTags:   make([]*telegraf.Tag, len(m.MetricTags)),\n\t\tMetricFields: make([]*telegraf.Field, len(m.MetricFields)),\n\t\tMetricTime:   m.MetricTime,\n\t\tMetricType:   m.MetricType,\n\t}\n\n\tfor i, tag := range m.MetricTags {\n\t\tm2.MetricTags[i] = &telegraf.Tag{Key: tag.Key, Value: tag.Value}\n\t}\n\n\tfor i, field := range m.MetricFields {\n\t\tm2.MetricFields[i] = &telegraf.Field{Key: field.Key, Value: field.Value}\n\t}\n\treturn m2\n}\n\nfunc (m *metric) HashID() uint64 {\n\th := fnv.New64a()\n\th.Write([]byte(m.MetricName))\n\th.Write([]byte(\"\\n\"))\n\tfor _, tag := range m.MetricTags {\n\t\th.Write([]byte(tag.Key))\n\t\th.Write([]byte(\"\\n\"))\n\t\th.Write([]byte(tag.Value))\n\t\th.Write([]byte(\"\\n\"))\n\t}\n\treturn h.Sum64()\n}\n\nfunc (m *metric) HashIDWithFieldsFiltered(excludedTags, excludedFields []string) uint64 {\n\th := fnv.New64a()\n\th.Write([]byte(m.MetricName))\n\th.Write([]byte(\"\\n\"))\n\tfor _, tag := range m.MetricTags {\n\t\tif slices.Contains(excludedTags, tag.Key) {\n\t\t\tcontinue\n\t\t}\n\t\th.Write([]byte(tag.Key))\n\t\th.Write([]byte(\"\\n\"))\n\t\th.Write([]byte(tag.Value))\n\t\th.Write([]byte(\"\\n\"))\n\t}\n\tkeys := make([]string, 0, len(m.MetricFields))\n\tfor _, field := range m.MetricFields {\n\t\tif slices.Contains(excludedFields, field.Key) {\n\t\t\tcontinue\n\t\t}\n\t\tkeys = append(keys, field.Key)\n\t}\n\tslices.Sort(keys)\n\th.Write([]byte(strings.Join(keys, \"\\n\")))\n\n\treturn h.Sum64()\n}\n\nfunc (*metric) Accept() {\n}\n\nfunc (*metric) Reject() {\n}\n\nfunc (*metric) Drop() {\n}\n\n// Convert field to a supported type or nil if inconvertible\nfunc convertField(v interface{}) interface{} {\n\tswitch v := v.(type) {\n\tcase float64:\n\t\treturn v\n\tcase int64:\n\t\treturn v\n\tcase string:\n\t\treturn v\n\tcase bool:\n\t\treturn v\n\tcase int:\n\t\treturn int64(v)\n\tcase uint:\n\t\treturn uint64(v)\n\tcase uint64:\n\t\treturn v\n\tcase []byte:\n\t\treturn string(v)\n\tcase int32:\n\t\treturn int64(v)\n\tcase int16:\n\t\treturn int64(v)\n\tcase int8:\n\t\treturn int64(v)\n\tcase uint32:\n\t\treturn uint64(v)\n\tcase uint16:\n\t\treturn uint64(v)\n\tcase uint8:\n\t\treturn uint64(v)\n\tcase float32:\n\t\treturn float64(v)\n\tcase *float64:\n\t\tif v != nil {\n\t\t\treturn *v\n\t\t}\n\tcase *int64:\n\t\tif v != nil {\n\t\t\treturn *v\n\t\t}\n\tcase *string:\n\t\tif v != nil {\n\t\t\treturn *v\n\t\t}\n\tcase *bool:\n\t\tif v != nil {\n\t\t\treturn *v\n\t\t}\n\tcase *int:\n\t\tif v != nil {\n\t\t\treturn int64(*v)\n\t\t}\n\tcase *uint:\n\t\tif v != nil {\n\t\t\treturn uint64(*v)\n\t\t}\n\tcase *uint64:\n\t\tif v != nil {\n\t\t\treturn *v\n\t\t}\n\tcase *[]byte:\n\t\tif v != nil {\n\t\t\treturn string(*v)\n\t\t}\n\tcase *int32:\n\t\tif v != nil {\n\t\t\treturn int64(*v)\n\t\t}\n\tcase *int16:\n\t\tif v != nil {\n\t\t\treturn int64(*v)\n\t\t}\n\tcase *int8:\n\t\tif v != nil {\n\t\t\treturn int64(*v)\n\t\t}\n\tcase *uint32:\n\t\tif v != nil {\n\t\t\treturn uint64(*v)\n\t\t}\n\tcase *uint16:\n\t\tif v != nil {\n\t\t\treturn uint64(*v)\n\t\t}\n\tcase *uint8:\n\t\tif v != nil {\n\t\t\treturn uint64(*v)\n\t\t}\n\tcase *float32:\n\t\tif v != nil {\n\t\t\treturn float64(*v)\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "metric/metric_test.go",
    "content": "package metric\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc TestNewMetric(t *testing.T) {\n\tnow := time.Now()\n\n\ttags := map[string]string{\n\t\t\"host\":       \"localhost\",\n\t\t\"datacenter\": \"us-east-1\",\n\t}\n\tfields := map[string]interface{}{\n\t\t\"usage_idle\": float64(99),\n\t\t\"usage_busy\": float64(1),\n\t}\n\tm := New(\"cpu\", tags, fields, now)\n\n\trequire.Equal(t, \"cpu\", m.Name())\n\trequire.Equal(t, tags, m.Tags())\n\trequire.Equal(t, fields, m.Fields())\n\trequire.Len(t, m.FieldList(), 2)\n\trequire.Equal(t, now, m.Time())\n}\n\n// cpu value=1\nfunc baseMetric() telegraf.Metric {\n\ttags := map[string]string{}\n\tfields := map[string]interface{}{\n\t\t\"value\": float64(1),\n\t}\n\tnow := time.Now()\n\n\tm := New(\"cpu\", tags, fields, now)\n\treturn m\n}\n\nfunc TestHasTag(t *testing.T) {\n\tm := baseMetric()\n\n\trequire.False(t, m.HasTag(\"host\"))\n\tm.AddTag(\"host\", \"localhost\")\n\trequire.True(t, m.HasTag(\"host\"))\n\tm.RemoveTag(\"host\")\n\trequire.False(t, m.HasTag(\"host\"))\n}\n\nfunc TestAddTagOverwrites(t *testing.T) {\n\tm := baseMetric()\n\n\tm.AddTag(\"host\", \"localhost\")\n\tm.AddTag(\"host\", \"example.org\")\n\n\tvalue, ok := m.GetTag(\"host\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"example.org\", value)\n\trequire.Len(t, m.TagList(), 1)\n}\n\nfunc TestRemoveTagNoEffectOnMissingTags(t *testing.T) {\n\tm := baseMetric()\n\n\tm.RemoveTag(\"foo\")\n\tm.AddTag(\"a\", \"x\")\n\tm.RemoveTag(\"foo\")\n\tm.RemoveTag(\"bar\")\n\tvalue, ok := m.GetTag(\"a\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"x\", value)\n}\n\nfunc TestGetTag(t *testing.T) {\n\tm := baseMetric()\n\n\t_, ok := m.GetTag(\"host\")\n\trequire.False(t, ok)\n\n\tm.AddTag(\"host\", \"localhost\")\n\n\tvalue, ok := m.GetTag(\"host\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"localhost\", value)\n\n\tm.RemoveTag(\"host\")\n\t_, ok = m.GetTag(\"host\")\n\trequire.False(t, ok)\n}\n\nfunc TestHasField(t *testing.T) {\n\tm := baseMetric()\n\n\trequire.False(t, m.HasField(\"x\"))\n\tm.AddField(\"x\", 42.0)\n\trequire.True(t, m.HasField(\"x\"))\n\tm.RemoveTag(\"x\")\n\trequire.False(t, m.HasTag(\"x\"))\n}\n\nfunc TestAddFieldOverwrites(t *testing.T) {\n\tm := baseMetric()\n\n\tm.AddField(\"value\", 1.0)\n\tm.AddField(\"value\", 42.0)\n\n\trequire.Len(t, m.FieldList(), 1)\n\n\tvalue, ok := m.GetField(\"value\")\n\trequire.True(t, ok)\n\trequire.InDelta(t, 42.0, value, 0.001)\n}\n\nfunc TestAddFieldChangesType(t *testing.T) {\n\tm := baseMetric()\n\n\tm.AddField(\"value\", 1.0)\n\tm.AddField(\"value\", \"xyzzy\")\n\n\trequire.Len(t, m.FieldList(), 1)\n\n\tvalue, ok := m.GetField(\"value\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"xyzzy\", value)\n}\n\nfunc TestRemoveFieldNoEffectOnMissingFields(t *testing.T) {\n\tm := baseMetric()\n\n\tm.RemoveField(\"foo\")\n\tm.AddField(\"a\", \"x\")\n\tm.RemoveField(\"foo\")\n\tm.RemoveField(\"bar\")\n\tvalue, ok := m.GetField(\"a\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"x\", value)\n}\n\nfunc TestGetField(t *testing.T) {\n\tm := baseMetric()\n\n\t_, ok := m.GetField(\"foo\")\n\trequire.False(t, ok)\n\n\tm.AddField(\"foo\", \"bar\")\n\n\tvalue, ok := m.GetField(\"foo\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"bar\", value)\n\n\tm.RemoveTag(\"foo\")\n\t_, ok = m.GetTag(\"foo\")\n\trequire.False(t, ok)\n}\n\nfunc TestTagList_Sorted(t *testing.T) {\n\tm := baseMetric()\n\n\tm.AddTag(\"b\", \"y\")\n\tm.AddTag(\"c\", \"z\")\n\tm.AddTag(\"a\", \"x\")\n\n\ttaglist := m.TagList()\n\trequire.Equal(t, \"a\", taglist[0].Key)\n\trequire.Equal(t, \"b\", taglist[1].Key)\n\trequire.Equal(t, \"c\", taglist[2].Key)\n}\n\nfunc TestEquals(t *testing.T) {\n\tnow := time.Now()\n\tm1 := New(\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"host\": \"localhost\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 42.0,\n\t\t},\n\t\tnow,\n\t)\n\n\tm2 := New(\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"host\": \"localhost\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 42.0,\n\t\t},\n\t\tnow,\n\t)\n\n\tlhs := m1.(*metric)\n\trequire.Equal(t, lhs, m2)\n\n\tm3 := m2.Copy()\n\trequire.Equal(t, lhs, m3)\n\tm3.AddTag(\"a\", \"x\")\n\trequire.NotEqual(t, lhs, m3)\n}\n\nfunc TestHashID(t *testing.T) {\n\tm := New(\n\t\t\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"datacenter\": \"us-east-1\",\n\t\t\t\"mytag\":      \"foo\",\n\t\t\t\"another\":    \"tag\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": float64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\thash := m.HashID()\n\n\t// adding a field doesn't change the hash:\n\tm.AddField(\"foo\", int64(100))\n\trequire.Equal(t, hash, m.HashID())\n\n\t// removing a non-existent tag doesn't change the hash:\n\tm.RemoveTag(\"no-op\")\n\trequire.Equal(t, hash, m.HashID())\n\n\t// adding a tag does change it:\n\tm.AddTag(\"foo\", \"bar\")\n\trequire.NotEqual(t, hash, m.HashID())\n\thash = m.HashID()\n\n\t// removing a tag also changes it:\n\tm.RemoveTag(\"mytag\")\n\trequire.NotEqual(t, hash, m.HashID())\n}\n\nfunc TestHashID_Consistency(t *testing.T) {\n\tm := New(\n\t\t\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"datacenter\": \"us-east-1\",\n\t\t\t\"mytag\":      \"foo\",\n\t\t\t\"another\":    \"tag\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": float64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\thash := m.HashID()\n\n\tm2 := New(\n\t\t\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"datacenter\": \"us-east-1\",\n\t\t\t\"mytag\":      \"foo\",\n\t\t\t\"another\":    \"tag\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": float64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\trequire.Equal(t, hash, m2.HashID())\n\n\tm3 := m.Copy()\n\trequire.Equal(t, m2.HashID(), m3.HashID())\n}\n\nfunc TestHashID_Delimiting(t *testing.T) {\n\tm1 := New(\n\t\t\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"x\",\n\t\t\t\"b\": \"y\",\n\t\t\t\"c\": \"z\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": float64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\tm2 := New(\n\t\t\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"xbycz\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": float64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\trequire.NotEqual(t, m1.HashID(), m2.HashID())\n}\n\nfunc TestSetName(t *testing.T) {\n\tm := baseMetric()\n\tm.SetName(\"foo\")\n\trequire.Equal(t, \"foo\", m.Name())\n}\n\nfunc TestAddPrefix(t *testing.T) {\n\tm := baseMetric()\n\tm.AddPrefix(\"foo_\")\n\trequire.Equal(t, \"foo_cpu\", m.Name())\n\tm.AddPrefix(\"foo_\")\n\trequire.Equal(t, \"foo_foo_cpu\", m.Name())\n}\n\nfunc TestAddSuffix(t *testing.T) {\n\tm := baseMetric()\n\tm.AddSuffix(\"_foo\")\n\trequire.Equal(t, \"cpu_foo\", m.Name())\n\tm.AddSuffix(\"_foo\")\n\trequire.Equal(t, \"cpu_foo_foo\", m.Name())\n}\n\nfunc TestValueType(t *testing.T) {\n\tnow := time.Now()\n\n\ttags := map[string]string{}\n\tfields := map[string]interface{}{\n\t\t\"value\": float64(42),\n\t}\n\tm := New(\"cpu\", tags, fields, now, telegraf.Gauge)\n\n\trequire.Equal(t, telegraf.Gauge, m.Type())\n}\n"
  },
  {
    "path": "metric/series_grouper.go",
    "content": "package metric\n\nimport (\n\t\"encoding/binary\"\n\t\"hash/maphash\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// NewSeriesGrouper returns a type that can be used to group fields by series\n// and time, so that fields which share these values will be combined into a\n// single telegraf.Metric.\n//\n// This is useful to build telegraf.Metric's when all fields for a series are\n// not available at once.\n//\n// ex:\n// - cpu,host=localhost usage_time=42\n// - cpu,host=localhost idle_time=42\n// + cpu,host=localhost idle_time=42,usage_time=42\nfunc NewSeriesGrouper() *SeriesGrouper {\n\treturn &SeriesGrouper{\n\t\tmetrics:  make(map[uint64]telegraf.Metric),\n\t\tordered:  make([]telegraf.Metric, 0),\n\t\thashSeed: maphash.MakeSeed(),\n\t}\n}\n\ntype SeriesGrouper struct {\n\tmetrics map[uint64]telegraf.Metric\n\tordered []telegraf.Metric\n\n\thashSeed maphash.Seed\n}\n\n// Add adds a field key and value to the series.\nfunc (g *SeriesGrouper) Add(\n\tmeasurement string,\n\ttags map[string]string,\n\ttm time.Time,\n\tfield string,\n\tfieldValue interface{},\n) {\n\ttaglist := make([]*telegraf.Tag, 0, len(tags))\n\tfor k, v := range tags {\n\t\ttaglist = append(taglist,\n\t\t\t&telegraf.Tag{Key: k, Value: v})\n\t}\n\tsort.Slice(taglist, func(i, j int) bool { return taglist[i].Key < taglist[j].Key })\n\n\tid := groupID(g.hashSeed, measurement, taglist, tm)\n\tm := g.metrics[id]\n\tif m == nil {\n\t\tm = New(measurement, tags, map[string]interface{}{field: fieldValue}, tm)\n\t\tg.metrics[id] = m\n\t\tg.ordered = append(g.ordered, m)\n\t} else {\n\t\tm.AddField(field, fieldValue)\n\t}\n}\n\n// AddMetric adds a metric to the series, merging with any previous matching metrics.\nfunc (g *SeriesGrouper) AddMetric(\n\tmetric telegraf.Metric,\n) {\n\tid := groupID(g.hashSeed, metric.Name(), metric.TagList(), metric.Time())\n\tm := g.metrics[id]\n\tif m == nil {\n\t\tm = metric.Copy()\n\t\tg.metrics[id] = m\n\t\tg.ordered = append(g.ordered, m)\n\t} else {\n\t\tfor _, f := range metric.FieldList() {\n\t\t\tm.AddField(f.Key, f.Value)\n\t\t}\n\t}\n}\n\n// Metrics returns the metrics grouped by series and time.\nfunc (g *SeriesGrouper) Metrics() []telegraf.Metric {\n\treturn g.ordered\n}\n\nfunc groupID(seed maphash.Seed, measurement string, taglist []*telegraf.Tag, tm time.Time) uint64 {\n\tvar mh maphash.Hash\n\tmh.SetSeed(seed)\n\n\tmh.WriteString(measurement)\n\tmh.WriteByte(0)\n\n\tfor _, tag := range taglist {\n\t\tmh.WriteString(tag.Key)\n\t\tmh.WriteByte(0)\n\t\tmh.WriteString(tag.Value)\n\t\tmh.WriteByte(0)\n\t}\n\tmh.WriteByte(0)\n\n\tvar tsBuf [8]byte\n\tbinary.BigEndian.PutUint64(tsBuf[:], uint64(tm.UnixNano()))\n\tmh.Write(tsBuf[:])\n\n\treturn mh.Sum64()\n}\n"
  },
  {
    "path": "metric/series_grouper_test.go",
    "content": "package metric\n\nimport (\n\t\"hash/maphash\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar m = New(\n\t\"mymetric\",\n\tmap[string]string{\n\t\t\"host\":        \"host.example.com\",\n\t\t\"mykey\":       \"myvalue\",\n\t\t\"another key\": \"another value\",\n\t},\n\tmap[string]interface{}{\n\t\t\"f1\": 1,\n\t\t\"f2\": 2,\n\t\t\"f3\": 3,\n\t\t\"f4\": 4,\n\t\t\"f5\": 5,\n\t\t\"f6\": 6,\n\t\t\"f7\": 7,\n\t\t\"f8\": 8,\n\t},\n\ttime.Now(),\n)\n\nvar result uint64\n\nvar hashSeed = maphash.MakeSeed()\n\nfunc BenchmarkGroupID(b *testing.B) {\n\tfor n := 0; n < b.N; n++ {\n\t\tresult = groupID(hashSeed, m.Name(), m.TagList(), m.Time())\n\t}\n}\n"
  },
  {
    "path": "metric/tracking.go",
    "content": "package metric\n\nimport (\n\t\"runtime\"\n\t\"sync/atomic\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// NotifyFunc is called when a tracking metric is done being processed with\n// the tracking information.\ntype NotifyFunc = func(track telegraf.DeliveryInfo)\n\n// WithTracking adds tracking to the metric and registers the notify function\n// to be called when processing is complete.\nfunc WithTracking(metric telegraf.Metric, fn NotifyFunc) (telegraf.Metric, telegraf.TrackingID) {\n\treturn newTrackingMetric(metric, fn)\n}\n\n// WithGroupTracking adds tracking to the metrics and registers the notify\n// function to be called when processing is complete.\nfunc WithGroupTracking(metric []telegraf.Metric, fn NotifyFunc) ([]telegraf.Metric, telegraf.TrackingID) {\n\treturn newTrackingMetricGroup(metric, fn)\n}\n\nvar (\n\tlastID    uint64\n\tfinalizer func(*trackingData)\n)\n\nfunc newTrackingID() telegraf.TrackingID {\n\treturn telegraf.TrackingID(atomic.AddUint64(&lastID, 1))\n}\n\ntype trackingData struct {\n\t//nolint:revive // method is already named ID\n\tId          telegraf.TrackingID\n\tRc          int32\n\tAcceptCount int32\n\tRejectCount int32\n\tnotifyFunc  NotifyFunc\n}\n\nfunc (d *trackingData) incr() {\n\tatomic.AddInt32(&d.Rc, 1)\n}\n\nfunc (d *trackingData) RefCount() int32 {\n\treturn d.Rc\n}\n\nfunc (d *trackingData) decr() int32 {\n\treturn atomic.AddInt32(&d.Rc, -1)\n}\n\nfunc (d *trackingData) accept() {\n\tatomic.AddInt32(&d.AcceptCount, 1)\n}\n\nfunc (d *trackingData) reject() {\n\tatomic.AddInt32(&d.RejectCount, 1)\n}\n\nfunc (d *trackingData) notify() {\n\td.notifyFunc(\n\t\t&deliveryInfo{\n\t\t\tid:       d.Id,\n\t\t\taccepted: int(d.AcceptCount),\n\t\t\trejected: int(d.RejectCount),\n\t\t},\n\t)\n}\n\ntype trackingMetric struct {\n\ttelegraf.Metric\n\td *trackingData\n}\n\nfunc newTrackingMetric(metric telegraf.Metric, fn NotifyFunc) (telegraf.Metric, telegraf.TrackingID) {\n\tm := &trackingMetric{\n\t\tMetric: metric,\n\t\td: &trackingData{\n\t\t\tId:          newTrackingID(),\n\t\t\tRc:          1,\n\t\t\tAcceptCount: 0,\n\t\t\tRejectCount: 0,\n\t\t\tnotifyFunc:  fn,\n\t\t},\n\t}\n\n\tif finalizer != nil {\n\t\truntime.SetFinalizer(m.d, finalizer)\n\t}\n\treturn m, m.d.Id\n}\n\nfunc newTrackingMetricGroup(group []telegraf.Metric, fn NotifyFunc) ([]telegraf.Metric, telegraf.TrackingID) {\n\td := &trackingData{\n\t\tId:          newTrackingID(),\n\t\tRc:          0,\n\t\tAcceptCount: 0,\n\t\tRejectCount: 0,\n\t\tnotifyFunc:  fn,\n\t}\n\n\tfor i, m := range group {\n\t\td.incr()\n\t\tdm := &trackingMetric{\n\t\t\tMetric: m,\n\t\t\td:      d,\n\t\t}\n\t\tgroup[i] = dm\n\t}\n\tif finalizer != nil {\n\t\truntime.SetFinalizer(d, finalizer)\n\t}\n\n\tif len(group) == 0 {\n\t\td.notify()\n\t}\n\n\treturn group, d.Id\n}\n\nfunc (m *trackingMetric) Copy() telegraf.Metric {\n\tm.d.incr()\n\treturn &trackingMetric{\n\t\tMetric: m.Metric.Copy(),\n\t\td:      m.d,\n\t}\n}\n\nfunc (m *trackingMetric) Accept() {\n\tm.d.accept()\n\tm.decr()\n}\n\nfunc (m *trackingMetric) Reject() {\n\tm.d.reject()\n\tm.decr()\n}\n\nfunc (m *trackingMetric) Drop() {\n\tm.decr()\n}\n\nfunc (m *trackingMetric) decr() {\n\tv := m.d.decr()\n\tif v < 0 {\n\t\tpanic(\"negative refcount\")\n\t}\n\n\tif v == 0 {\n\t\tm.d.notify()\n\t\tmu.Lock()\n\t\tdelete(trackingStore, m.d.Id)\n\t\tdefer mu.Unlock()\n\t}\n}\n\n// Unwrap allows to access the underlying metric directly e.g. for go-templates\nfunc (m *trackingMetric) TrackingID() telegraf.TrackingID {\n\treturn m.d.Id\n}\n\nfunc (m *trackingMetric) TrackingData() telegraf.TrackingData {\n\treturn m.d\n}\n\n// Unwrap allows to access the underlying metric directly e.g. for go-templates\nfunc (m *trackingMetric) Unwrap() telegraf.Metric {\n\treturn m.Metric\n}\n\ntype deliveryInfo struct {\n\tid       telegraf.TrackingID\n\taccepted int\n\trejected int\n}\n\nfunc (r *deliveryInfo) ID() telegraf.TrackingID {\n\treturn r.id\n}\n\nfunc (r *deliveryInfo) Delivered() bool {\n\treturn r.rejected == 0\n}\n\nfunc (d *trackingData) ID() telegraf.TrackingID {\n\treturn d.Id\n}\n"
  },
  {
    "path": "metric/tracking_test.go",
    "content": "package metric\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc mustMetric(\n\tname string,\n\ttags map[string]string,\n\tfields map[string]interface{},\n\ttm time.Time,\n\ttp ...telegraf.ValueType,\n) telegraf.Metric {\n\tm := New(name, tags, fields, tm, tp...)\n\treturn m\n}\n\ntype deliveries struct {\n\tInfo map[telegraf.TrackingID]telegraf.DeliveryInfo\n}\n\nfunc (d *deliveries) onDelivery(info telegraf.DeliveryInfo) {\n\td.Info[info.ID()] = info\n}\n\nfunc TestNewTrackingID(t *testing.T) {\n\tvar wg sync.WaitGroup\n\tvar a [100000]telegraf.TrackingID\n\tvar b [100000]telegraf.TrackingID\n\n\twg.Add(2)\n\tgo func() {\n\t\tfor i := 0; i < len(a); i++ {\n\t\t\ta[i] = newTrackingID()\n\t\t}\n\t\twg.Done()\n\t}()\n\tgo func() {\n\t\tfor i := 0; i < len(b); i++ {\n\t\t\tb[i] = newTrackingID()\n\t\t}\n\t\twg.Done()\n\t}()\n\twg.Wait()\n\n\t// Find any duplicate TrackingIDs in arrays a and b. Arrays must be sorted in increasing order.\n\tfor i, j := 0, 0; i < len(a) && j < len(b); {\n\t\tif a[i] == b[j] {\n\t\t\tt.Errorf(\"Duplicate TrackingID: a[%d]==%d and b[%d]==%d.\", i, a[i], j, b[j])\n\t\t\tbreak\n\t\t}\n\t\tif a[i] > b[j] {\n\t\t\tj++\n\t\t\tcontinue\n\t\t}\n\t\tif a[i] < b[j] {\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\t}\n}\n\nfunc TestTracking(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tmetric    telegraf.Metric\n\t\tactions   func(metric telegraf.Metric)\n\t\tdelivered bool\n\t}{\n\t\t{\n\t\t\tname: \"accept\",\n\t\t\tmetric: mustMetric(\n\t\t\t\t\"memory\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t\ttelegraf.Gauge,\n\t\t\t),\n\t\t\tactions: func(m telegraf.Metric) {\n\t\t\t\tm.Accept()\n\t\t\t},\n\t\t\tdelivered: true,\n\t\t},\n\t\t{\n\t\t\tname: \"reject\",\n\t\t\tmetric: mustMetric(\n\t\t\t\t\"memory\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t\ttelegraf.Gauge,\n\t\t\t),\n\t\t\tactions: func(m telegraf.Metric) {\n\t\t\t\tm.Reject()\n\t\t\t},\n\t\t\tdelivered: false,\n\t\t},\n\t\t{\n\t\t\tname: \"accept copy\",\n\t\t\tmetric: mustMetric(\n\t\t\t\t\"memory\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t\ttelegraf.Gauge,\n\t\t\t),\n\t\t\tactions: func(m telegraf.Metric) {\n\t\t\t\tm2 := m.Copy()\n\t\t\t\tm.Accept()\n\t\t\t\tm2.Accept()\n\t\t\t},\n\t\t\tdelivered: true,\n\t\t},\n\t\t{\n\t\t\tname: \"copy with accept and done\",\n\t\t\tmetric: mustMetric(\n\t\t\t\t\"memory\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t\ttelegraf.Gauge,\n\t\t\t),\n\t\t\tactions: func(m telegraf.Metric) {\n\t\t\t\tm2 := m.Copy()\n\t\t\t\tm.Accept()\n\t\t\t\tm2.Drop()\n\t\t\t},\n\t\t\tdelivered: true,\n\t\t},\n\t\t{\n\t\t\tname: \"copy with mixed delivery\",\n\t\t\tmetric: mustMetric(\n\t\t\t\t\"memory\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t\ttelegraf.Gauge,\n\t\t\t),\n\t\t\tactions: func(m telegraf.Metric) {\n\t\t\t\tm2 := m.Copy()\n\t\t\t\tm.Accept()\n\t\t\t\tm2.Reject()\n\t\t\t},\n\t\t\tdelivered: false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\td := &deliveries{\n\t\t\t\tInfo: make(map[telegraf.TrackingID]telegraf.DeliveryInfo),\n\t\t\t}\n\t\t\tmetric, id := WithTracking(tt.metric, d.onDelivery)\n\t\t\ttt.actions(metric)\n\n\t\t\tinfo := d.Info[id]\n\t\t\trequire.Equal(t, tt.delivered, info.Delivered())\n\t\t})\n\t}\n}\n\nfunc TestGroupTracking(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tmetrics   []telegraf.Metric\n\t\tactions   func(metrics []telegraf.Metric)\n\t\tdelivered bool\n\t}{\n\t\t{\n\t\t\tname: \"accept\",\n\t\t\tmetrics: []telegraf.Metric{\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\tactions: func(metrics []telegraf.Metric) {\n\t\t\t\tmetrics[0].Accept()\n\t\t\t\tmetrics[1].Accept()\n\t\t\t},\n\t\t\tdelivered: true,\n\t\t},\n\t\t{\n\t\t\tname: \"reject\",\n\t\t\tmetrics: []telegraf.Metric{\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\tactions: func(metrics []telegraf.Metric) {\n\t\t\t\tmetrics[0].Reject()\n\t\t\t\tmetrics[1].Reject()\n\t\t\t},\n\t\t\tdelivered: false,\n\t\t},\n\t\t{\n\t\t\tname: \"remove\",\n\t\t\tmetrics: []telegraf.Metric{\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\tactions: func(metrics []telegraf.Metric) {\n\t\t\t\tmetrics[0].Drop()\n\t\t\t\tmetrics[1].Drop()\n\t\t\t},\n\t\t\tdelivered: true,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\t\t\tmetrics: []telegraf.Metric{\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\tactions: func(metrics []telegraf.Metric) {\n\t\t\t\tmetrics[0].Accept()\n\t\t\t\tmetrics[1].Reject()\n\t\t\t},\n\t\t\tdelivered: false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\td := &deliveries{\n\t\t\t\tInfo: make(map[telegraf.TrackingID]telegraf.DeliveryInfo),\n\t\t\t}\n\t\t\tmetrics, id := WithGroupTracking(tt.metrics, d.onDelivery)\n\t\t\ttt.actions(metrics)\n\n\t\t\tinfo := d.Info[id]\n\t\t\trequire.Equal(t, tt.delivered, info.Delivered())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "metric.go",
    "content": "package telegraf\n\nimport (\n\t\"time\"\n)\n\n// ValueType is an enumeration of metric types that represent a simple value.\ntype ValueType int\n\n// Possible values for the ValueType enum.\nconst (\n\t_ ValueType = iota\n\tCounter\n\tGauge\n\tUntyped\n\tSummary\n\tHistogram\n)\n\n// Tag represents a single tag key and value.\ntype Tag struct {\n\tKey   string\n\tValue string\n}\n\n// Field represents a single field key and value.\ntype Field struct {\n\tKey   string\n\tValue interface{}\n}\n\n// Metric is the type of data that is processed by Telegraf.  Input plugins,\n// and to a lesser degree, Processor and Aggregator plugins create new Metrics\n// and Output plugins write them.\n//\n//nolint:interfacebloat // conditionally allow to contain more methods\ntype Metric interface {\n\t// Name is the primary identifier for the Metric and corresponds to the\n\t// measurement in the InfluxDB data model.\n\tName() string\n\n\t// Tags returns the tags as a map.  This method is deprecated, use TagList instead.\n\tTags() map[string]string\n\n\t// TagList returns the tags as a slice ordered by the tag key in lexical\n\t// bytewise ascending order.  The returned value should not be modified,\n\t// use the AddTag or RemoveTag methods instead.\n\tTagList() []*Tag\n\n\t// Fields returns the fields as a map.  This method is deprecated, use FieldList instead.\n\tFields() map[string]interface{}\n\n\t// FieldList returns the fields as a slice in an undefined order.  The\n\t// returned value should not be modified, use the AddField or RemoveField\n\t// methods instead.\n\tFieldList() []*Field\n\n\t// Time returns the timestamp of the metric.\n\tTime() time.Time\n\n\t// Type returns a general type for the entire metric that describes how you\n\t// might interpret, aggregate the values. Used by prometheus and statsd.\n\tType() ValueType\n\n\t// SetName sets the metric name.\n\tSetName(name string)\n\n\t// AddPrefix adds a string to the front of the metric name.  It is\n\t// equivalent to m.SetName(prefix + m.Name()).\n\t//\n\t// This method is deprecated, use SetName instead.\n\tAddPrefix(prefix string)\n\n\t// AddSuffix appends a string to the back of the metric name.  It is\n\t// equivalent to m.SetName(m.Name() + suffix).\n\t//\n\t// This method is deprecated, use SetName instead.\n\tAddSuffix(suffix string)\n\n\t// GetTag returns the value of a tag and a boolean to indicate if it was set.\n\tGetTag(key string) (string, bool)\n\n\t// HasTag returns true if the tag is set on the Metric.\n\tHasTag(key string) bool\n\n\t// AddTag sets the tag on the Metric.  If the Metric already has the tag\n\t// set then the current value is replaced.\n\tAddTag(key, value string)\n\n\t// RemoveTag removes the tag if it is set.\n\tRemoveTag(key string)\n\n\t// GetField returns the value of a field and a boolean to indicate if it was set.\n\tGetField(key string) (interface{}, bool)\n\n\t// HasField returns true if the field is set on the Metric.\n\tHasField(key string) bool\n\n\t// AddField sets the field on the Metric.  If the Metric already has the field\n\t// set then the current value is replaced.\n\tAddField(key string, value interface{})\n\n\t// RemoveField removes the field if it is set.\n\tRemoveField(key string)\n\n\t// SetTime sets the timestamp of the Metric.\n\tSetTime(t time.Time)\n\n\t// SetType sets the value-type of the Metric.\n\tSetType(t ValueType)\n\n\t// HashID returns a unique identifier for the series.\n\tHashID() uint64\n\n\t// HashIDWithFieldsFiltered returns a unique identifier for the metric\n\t// including the field keys while ignoring tags and fields with the\n\t// specified keys.\n\tHashIDWithFieldsFiltered(excludedTags, excludedFields []string) uint64\n\n\t// Copy returns a deep copy of the Metric.\n\tCopy() Metric\n\n\t// Accept marks the metric as processed successfully and written to an\n\t// output.\n\tAccept()\n\n\t// Reject marks the metric as processed unsuccessfully.\n\tReject()\n\n\t// Drop marks the metric as processed successfully without being written\n\t// to any output.\n\tDrop()\n}\n\n// TemplateMetric is an interface to use in templates (e.g text/template)\n// to generate complex strings from metric properties\n// e.g. '{{.Name}}-{{.Tag \"foo\"}}-{{.Field \"bar\"}}'\ntype TemplateMetric interface {\n\tName() string\n\tField(key string) interface{}\n\tFields() map[string]interface{}\n\tTag(key string) string\n\tTags() map[string]string\n\tTime() time.Time\n\tString() string\n}\n\ntype UnwrappableMetric interface {\n\t// Unwrap allows to access the underlying raw metric if an implementation\n\t// wraps it in the first place.\n\tUnwrap() Metric\n}\n\ntype TrackingMetric interface {\n\t// TrackingID returns the ID used for tracking the metric\n\tTrackingID() TrackingID\n\tTrackingData() TrackingData\n\tUnwrappableMetric\n}\n"
  },
  {
    "path": "migrations/all/all.go",
    "content": "package all\n"
  },
  {
    "path": "migrations/all/general_common_tls.go",
    "content": "//go:build !custom || migrations\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/general_common_tls\" // register migration\n"
  },
  {
    "path": "migrations/all/general_metricfilter.go",
    "content": "//go:build !custom || migrations\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/general_metricfilter\" // register migration\n"
  },
  {
    "path": "migrations/all/global_agent.go",
    "content": "//go:build !custom || migrations\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/global_agent\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs.nats_consumer.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.nats_consumer))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_nats_consumer\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_KNXListener.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.KNXListener))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_KNXListener\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_amqp_consumer",
    "content": "//go:build !custom || (migrations && (inputs || inputs.amqp_consumer))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_amqp_consumer\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_cassandra.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.cassandra))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_cassandra\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_cisco_telemetry_gnmi.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.cisco_telemetry_gnmi))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_cisco_telemetry_gnmi\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_cloudwatch.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.cloudwatch))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_cloudwatch\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_consul.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.consul))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_consul\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_disk.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.disk))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_disk\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_docker.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.docker))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_docker\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_elasticsearch.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.elasticsearch))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_elasticsearch\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_filecount.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.filecount))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_filecount\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_gnmi.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.gnmi))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_gnmi\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_http.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.http))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_http\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_http_listener.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.http_listener))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_http_listener\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_http_listener_v2.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.http_listener_v2))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_http_listener_v2\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_http_response.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.http_response))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_http_response\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_httpjson.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.httpjson))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_httpjson\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_icinga2.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.icinga2))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_icinga2\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_influxdb_listener.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.influxdb_listener))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_influxdb_listener\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_internet_speed.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.internet_speed))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_internet_speed\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_io.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.io || inputs.diskio))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_io\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_jolokia.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.jolokia))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_jolokia\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_kafka_consumer_legacy.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.kafka_consumer_legacy))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_kafka_consumer_legacy\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_kube_inventory.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.kube_inventory))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_kube_inventory\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_kubernetes.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.kubernetes))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_kubernetes\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_logparser.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.logparser))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_logparser\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_mqtt_consumer.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.mqtt_consumer))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_mqtt_consumer\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_nsq_consumer.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.nsq_consumer))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_nsq_consumer\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_ntpq.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.ntpq))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_ntpq\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_openldap.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.openldap))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_openldap\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_procstat.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.procstat))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_procstat\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_rabbitmq.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.rabbitmq))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_rabbitmq\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_sflow.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.sflow))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_sflow\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_smart.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.smart))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_smart\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_snmp_legacy.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.snmp_legacy))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_snmp_legacy\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_sqlserver.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.sqlserver))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_sqlserver\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_statsd.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.statsd))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_statsd\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_tcp_listener.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.tcp_listener))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_tcp_listener\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_udp_listener.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.udp_listener))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_udp_listener\" // register migration\n"
  },
  {
    "path": "migrations/all/inputs_vsphere.go",
    "content": "//go:build !custom || (migrations && (inputs || inputs.vsphere))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/inputs_vsphere\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_amqp.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.amqp))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_amqp\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_influxdb.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.influxdb))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_influxdb\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_kinesis.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.kinesis))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_kinesis\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_librato.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.librato))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_librato\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_mqtt.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.mqtt))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_mqtt\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_remotefile.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.remotefile))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_remotefile\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_riemann_legacy.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.riemann_legacy))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_riemann_legacy\" // register migration\n"
  },
  {
    "path": "migrations/all/outputs_wavefront.go",
    "content": "//go:build !custom || (migrations && (outputs || outputs.wavefront))\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/migrations/outputs_wavefront\" // register migration\n"
  },
  {
    "path": "migrations/common/filter_options.go",
    "content": "package common\n\ntype FilterOptions struct {\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldPassOld   []string            `toml:\"pass,omitempty\"`\n\tFieldPass      []string            `toml:\"fieldpass,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldDropOld   []string            `toml:\"drop,omitempty\"`\n\tFieldDrop      []string            `toml:\"fielddrop,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n"
  },
  {
    "path": "migrations/common/input_options.go",
    "content": "package common\n\ntype InputOptions struct {\n\t// General options\n\tInterval         string            `toml:\"interval,omitempty\"`\n\tPrecision        string            `toml:\"precision,omitempty\"`\n\tCollectionJitter string            `toml:\"collection_jitter,omitempty\"`\n\tCollectionOffset string            `toml:\"collection_offset,omitempty\"`\n\tNamePrefix       string            `toml:\"name_prefix,omitempty\"`\n\tNameSuffix       string            `toml:\"name_suffix,omitempty\"`\n\tNameOverride     string            `toml:\"name_override,omitempty\"`\n\tAlias            string            `toml:\"alias,omitempty\"`\n\tTags             map[string]string `toml:\"tags,omitempty\"`\n\n\t// Filter options\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldPassOld   []string            `toml:\"pass,omitempty\"`\n\tFieldPass      []string            `toml:\"fieldpass,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldDropOld   []string            `toml:\"drop,omitempty\"`\n\tFieldDrop      []string            `toml:\"fielddrop,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\nfunc (io *InputOptions) Migrate() {\n\tio.FieldInclude = append(io.FieldInclude, io.FieldPassOld...)\n\tio.FieldInclude = append(io.FieldInclude, io.FieldPass...)\n\n\tio.FieldPassOld = nil\n\tio.FieldPass = nil\n\n\tio.FieldExclude = append(io.FieldExclude, io.FieldDropOld...)\n\tio.FieldExclude = append(io.FieldExclude, io.FieldDrop...)\n\n\tio.FieldDropOld = nil\n\tio.FieldDrop = nil\n}\n"
  },
  {
    "path": "migrations/common/output_options.go",
    "content": "package common\n\ntype OutputOptions struct {\n\t// General options\n\tAlias string `toml:\"alias,omitempty\"`\n\n\t// Filter options\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldPassOld   []string            `toml:\"pass,omitempty\"`\n\tFieldPass      []string            `toml:\"fieldpass,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldDropOld   []string            `toml:\"drop,omitempty\"`\n\tFieldDrop      []string            `toml:\"fielddrop,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\nfunc (oo *OutputOptions) Migrate() {\n\too.FieldInclude = append(oo.FieldInclude, oo.FieldPassOld...)\n\too.FieldInclude = append(oo.FieldInclude, oo.FieldPass...)\n\n\too.FieldPassOld = nil\n\too.FieldPass = nil\n\n\too.FieldExclude = append(oo.FieldExclude, oo.FieldDropOld...)\n\too.FieldExclude = append(oo.FieldExclude, oo.FieldDrop...)\n\n\too.FieldDropOld = nil\n\too.FieldDrop = nil\n}\n"
  },
  {
    "path": "migrations/general_common_tls/migration.go",
    "content": "package general_common_tls\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(category, name string, tbl *ast.Table) ([]byte, string, error) {\n\t// Filter options can only be present in inputs, outputs, processors and\n\t// aggregators. Skip everything else...\n\tswitch category {\n\tcase \"inputs\", \"outputs\", \"processors\", \"aggregators\":\n\tdefault:\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\t// Option mapping to replace\n\tmapping := map[string]string{\n\t\t\"ssl_ca\":   \"tls_ca\",\n\t\t\"ssl_cert\": \"tls_cert\",\n\t\t\"ssl_key\":  \"tls_key\",\n\t}\n\n\t// Check if the old settings are present and set the new TLS settings. Warn\n\t// on conflicting settings where both the old and the new setting is\n\t// present.\n\tfor oldSetting, newSetting := range mapping {\n\t\trawOld, found := plugin[oldSetting]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\tvOld, ok := rawOld.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for %q\", rawOld, oldSetting)\n\t\t}\n\t\trawNew, present := plugin[newSetting]\n\t\tif present {\n\t\t\tif vNew, ok := rawNew.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for %q\", rawOld, newSetting)\n\t\t\t} else if vOld != vNew {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"contradicting setting for %q and %q\", oldSetting, newSetting)\n\t\t\t}\n\t\t} else {\n\t\t\tplugin[newSetting] = vOld\n\t\t}\n\t\tapplied = true\n\n\t\t// Remove the deprecated option\n\t\tdelete(plugin, oldSetting)\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(category, name)\n\tcfg.Add(category, name, plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddGeneralMigration(migrate)\n}\n"
  },
  {
    "path": "migrations/general_common_tls/migration_test.go",
    "content": "package general_common_tls_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/general_common_tls\" // register migration\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tcfg  string\n\t}{\n\t\t{\n\t\t\tname: \"input\",\n\t\t\tcfg: `\n# Dummy plugin\n[[inputs.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"output\",\n\t\t\tcfg: `\n# Dummy plugin\n[[output.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"processor\",\n\t\t\tcfg: `\n# Dummy plugin\n[[processor.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"aggregator\",\n\t\t\tcfg: `\n# Dummy plugin\n[[aggregator.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"no old setting\",\n\t\t\tcfg: `\n# Dummy plugin\n[[input.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  # TLS settings\n  tls_ca = \"/etc/ca.pem\"\n  tls_cert = \"/etc/cert.pem\"\n  tls_key = \"/etc/key\"\n\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcfg := []byte(tt.cfg)\n\n\t\t\t// Migrate and check that nothing changed\n\t\t\toutput, n, err := config.ApplyMigrations(cfg)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.Zero(t, n)\n\t\t\trequire.Equal(t, tt.cfg, string(output))\n\t\t})\n\t}\n}\n\nfunc TestConflict(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tcfg  string\n\t}{\n\t\t{\n\t\t\tname: \"ca\",\n\t\t\tcfg: `\n# Dummy plugin\n[[inputs.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n  tls_ca = \"foo.pem\"\n  ssl_ca = \"bar.pem\"\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"cert\",\n\t\t\tcfg: `\n# Dummy plugin\n[[inputs.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n  tls_cert = \"foo.pem\"\n  ssl_cert = \"bar.pem\"\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"key\",\n\t\t\tcfg: `\n# Dummy plugin\n[[inputs.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n  tls_key = \"foo.pem\"\n  ssl_key = \"bar.pem\"\n\n  ## A commented option\n  # timeout = \"10s\"\n`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcfg := []byte(tt.cfg)\n\n\t\t\t// Migrate and check that nothing changed\n\t\t\toutput, n, err := config.ApplyMigrations(cfg)\n\t\t\trequire.ErrorContains(t, err, \"contradicting setting\")\n\t\t\trequire.Empty(t, output)\n\t\t\trequire.Zero(t, n)\n\t\t})\n\t}\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tinputs.Add(\"dummy\", func() telegraf.Input { return &MockupInputPlugin{} })\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n\n// Implement a mock input plugin for testing\ntype MockupInputPlugin struct {\n\tServers []string        `toml:\"servers\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tcommon_tls.ClientConfig\n}\n\nfunc (*MockupInputPlugin) SampleConfig() string {\n\treturn \"Mockup test input plugin\"\n}\nfunc (*MockupInputPlugin) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n"
  },
  {
    "path": "migrations/general_common_tls/testcases/deprecated_ssl/dummy",
    "content": ""
  },
  {
    "path": "migrations/general_common_tls/testcases/deprecated_ssl/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\ntls_ca = \"../../testutil/pki/cacert.pem\"\ntls_cert = \"../../testutil/pki/client.pem\"\ntls_key = \"../../testutil/pki/clientkey.pem\""
  },
  {
    "path": "migrations/general_common_tls/testcases/deprecated_ssl/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Deprecated SSL options\n  ssl_ca = \"../../testutil/pki/cacert.pem\"\n  ssl_cert = \"../../testutil/pki/client.pem\"\n  ssl_key = \"../../testutil/pki/clientkey.pem\"\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n"
  },
  {
    "path": "migrations/general_metricfilter/migration.go",
    "content": "package general_metricfilter\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(category, name string, tbl *ast.Table) ([]byte, string, error) {\n\t// Filter options can only be present in inputs, outputs, processors and\n\t// aggregators. Skip everything else...\n\tswitch category {\n\tcase \"inputs\", \"outputs\", \"processors\", \"aggregators\":\n\tdefault:\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\t// Get the new field settings to be able to merge it with the deprecated\n\t// settings\n\tvar fieldinclude []string\n\tif newFieldInclude, found := plugin[\"fieldinclude\"]; found {\n\t\tvar err error\n\t\tfieldinclude, err = migrations.AsStringSlice(newFieldInclude)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'fieldinclude': %w\", err)\n\t\t}\n\t}\n\tfor _, option := range []string{\"pass\", \"fieldpass\"} {\n\t\tif rawOld, found := plugin[option]; found {\n\t\t\tapplied = true\n\n\t\t\told, err := migrations.AsStringSlice(rawOld)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting '%s': %w\", option, err)\n\t\t\t}\n\t\t\tfor _, o := range old {\n\t\t\t\tif !choice.Contains(o, fieldinclude) {\n\t\t\t\t\tfieldinclude = append(fieldinclude, o)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove the deprecated setting\n\t\t\tdelete(plugin, option)\n\t\t}\n\t}\n\t// Add the new option if it has data\n\tif len(fieldinclude) > 0 {\n\t\tplugin[\"fieldinclude\"] = fieldinclude\n\t}\n\n\tvar fieldexclude []string\n\tif newFieldExclude, found := plugin[\"fieldexclude\"]; found {\n\t\tvar err error\n\t\tfieldexclude, err = migrations.AsStringSlice(newFieldExclude)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'fieldexclude': %w\", err)\n\t\t}\n\t}\n\tfor _, option := range []string{\"drop\", \"fielddrop\"} {\n\t\tif rawOld, found := plugin[option]; found {\n\t\t\tapplied = true\n\n\t\t\told, err := migrations.AsStringSlice(rawOld)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting '%s': %w\", option, err)\n\t\t\t}\n\t\t\tfor _, o := range old {\n\t\t\t\tif !choice.Contains(o, fieldexclude) {\n\t\t\t\t\tfieldexclude = append(fieldexclude, o)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove the deprecated setting\n\t\t\tdelete(plugin, option)\n\t\t}\n\t}\n\t// Add the new option if it has data\n\tif len(fieldexclude) > 0 {\n\t\tplugin[\"fieldexclude\"] = fieldexclude\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(category, name)\n\tcfg.Add(category, name, plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddGeneralMigration(migrate)\n}\n"
  },
  {
    "path": "migrations/general_metricfilter/migration_test.go",
    "content": "package general_metricfilter_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/general_metricfilter\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tcfg := []byte(`\n# Dummy plugin\n[[inputs.dummy]]\n  ## A dummy server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## A commented option\n  # timeout = \"10s\"\n`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(cfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tinputs.Add(\"dummy\", func() telegraf.Input { return &MockupInputPlugin{} })\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n\n// Implement a mock input plugin for testing\ntype MockupInputPlugin struct {\n\tServers []string        `toml:\"servers\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n}\n\nfunc (*MockupInputPlugin) SampleConfig() string {\n\treturn \"Mockup test input plugin\"\n}\nfunc (*MockupInputPlugin) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_drop/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldexclude = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_drop/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated drop\n  drop = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_fielddrop/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldexclude = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_fielddrop/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated fielddrop\n  fielddrop = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_fieldpass/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldinclude = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_fieldpass/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated fieldpass\n  fieldpass = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_pass/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldinclude = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/deprecated_pass/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated pass\n  pass = [\"value\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_all_overlap/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldexclude = [\"bugA\", \"bugX\", \"bugB\", \"bugY\", \"bugC\"]\nfieldinclude = [\"valueA\", \"valueX\", \"valueB\", \"valueY\", \"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_all_overlap/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated field options\n  fieldinclude = [\"valueA\", \"valueX\"]\n  fieldexclude = [\"bugA\", \"bugX\"]\n  drop = [\"bugB\", \"bugX\", \"bugY\"]\n  pass = [\"valueB\", \"valueX\", \"valueY\"]\n  fieldpass = [\"valueY\", \"valueC\", \"valueX\"]\n  fielddrop = [\"bugY\", \"bugC\", \"bugX\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldexclude/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldexclude = [\"valueA\", \"valueB\", \"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldexclude/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated field-exclude options\n  fieldexclude = [\"valueA\"]\n  drop = [\"valueB\"]\n  fielddrop = [\"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldexclude_overlap/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldexclude = [\"valueA\", \"valueX\", \"valueB\", \"valueY\", \"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldexclude_overlap/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated field-exclude options\n  fieldexclude = [\"valueA\", \"valueX\"]\n  drop = [\"valueB\", \"valueX\", \"valueY\"]\n  fielddrop = [\"valueY\", \"valueC\", \"valueX\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldinclude/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldinclude = [\"valueA\", \"valueB\", \"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldinclude/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated field-include options\n  fieldinclude = [\"valueA\"]\n  pass = [\"valueB\"]\n  fieldpass = [\"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldinclude_overlap/expected.conf",
    "content": "[[inputs.dummy]]\nservers = [\"tcp://127.0.0.1:1883\"]\nfieldinclude = [\"valueA\", \"valueX\", \"valueB\", \"valueY\", \"valueC\"]\n"
  },
  {
    "path": "migrations/general_metricfilter/testcases/merge_fieldinclude_overlap/telegraf.conf",
    "content": "# A dummy plugin\n[[inputs.dummy]]\n  ## A server\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Default timestamp\n  # timestamp = \"10s\"\n\n  ## Deprecated field-include options\n  fieldinclude = [\"valueA\", \"valueX\"]\n  pass = [\"valueB\", \"valueX\", \"valueY\"]\n  fieldpass = [\"valueY\", \"valueC\", \"valueX\"]\n"
  },
  {
    "path": "migrations/global_agent/migration.go",
    "content": "package global_agent\n\nimport (\n\t\"errors\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(name string, tbl *ast.Table) ([]byte, string, error) {\n\t// Migrate the agent section only...\n\tif name != \"agent\" {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Decode the old data structure\n\tvar agent map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &agent); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\t// Migrate log settings\n\tvar logtarget string\n\tvar logtargetFound bool\n\tif raw, found := agent[\"logtarget\"]; found {\n\t\tif v, ok := raw.(string); ok {\n\t\t\tlogtarget = v\n\t\t\tlogtargetFound = true\n\t\t}\n\t}\n\n\tvar logformat string\n\tvar logformatFound bool\n\tif raw, found := agent[\"logformat\"]; found {\n\t\tif v, ok := raw.(string); ok {\n\t\t\tlogformat = v\n\t\t\tlogformatFound = true\n\t\t}\n\t}\n\n\tif logtargetFound {\n\t\tswitch logtarget {\n\t\tcase \"stderr\":\n\t\t\tdelete(agent, \"logfile\")\n\t\tcase \"file\":\n\t\tcase \"eventlog\":\n\t\t\tif logformatFound && logformat != \"eventlog\" {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'logtarget' and 'logformat'\")\n\t\t\t}\n\t\t\tagent[\"logformat\"] = \"eventlog\"\n\t\t\tdelete(agent, \"logfile\")\n\t\t}\n\t\tapplied = true\n\t\tdelete(agent, \"logtarget\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\toutput, err := toml.Marshal(map[string]map[string]interface{}{\"agent\": agent})\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddGlobalMigration(migrate)\n}\n"
  },
  {
    "path": "migrations/global_agent/migration_test.go",
    "content": "package global_agent_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/global_agent\" // register migration\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tfn := filepath.Join(\"testcases\", \"default.conf\")\n\n\t// Read the input data\n\tinput, remote, err := config.LoadConfigFile(fn)\n\trequire.NoError(t, err)\n\trequire.False(t, remote)\n\trequire.NotEmpty(t, input)\n\n\t// Expect the output to be equal to the input\n\texpectedBuffer, err := os.ReadFile(fn)\n\trequire.NoError(t, err)\n\texpected := config.NewConfig()\n\trequire.NoError(t, expected.LoadConfigData(expectedBuffer, config.EmptySourcePath))\n\trequire.NotNil(t, expected.Agent)\n\n\t// Migrate\n\toutput, n, err := config.ApplyMigrations(input)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\n\tactual := config.NewConfig()\n\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\trequire.NotNil(t, actual.Agent)\n\n\t// Test the output\n\trequire.EqualValues(t, expected.Agent, actual.Agent, string(output))\n\trequire.Equal(t, string(expectedBuffer), string(output))\n}\n\nfunc TestLogTargetEventlogCollision(t *testing.T) {\n\tfn := filepath.Join(\"testcases\", \"logtarget_eventlog_collision.conf\")\n\n\t// Read the input data\n\tinput, remote, err := config.LoadConfigFile(fn)\n\trequire.NoError(t, err)\n\trequire.False(t, remote)\n\trequire.NotEmpty(t, input)\n\n\t// Migrate\n\t_, n, err := config.ApplyMigrations(input)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'logtarget' and 'logformat'\")\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotNil(t, expected.Agent)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.Positive(t, n, \"expected migration application but none applied\")\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\t\t\trequire.NotNil(t, actual.Agent)\n\n\t\t\t// Test the output\n\t\t\trequire.EqualValues(t, expected.Agent, actual.Agent, string(output))\n\n\t\t\texpectedBuffer, err := os.ReadFile(expectedFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, string(expectedBuffer), string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/global_agent/testcases/default.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_eventlog/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nlogformat = \"eventlog\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_eventlog/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"eventlog\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_eventlog_collision.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  logformat = \"text\"\n\n  logtarget = \"eventlog\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_eventlog_with_logfile/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nlogformat = \"eventlog\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_eventlog_with_logfile/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"eventlog\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_file/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nlogfile = \"lala.log\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_file/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"file\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_file_no_logfile/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_file_no_logfile/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"file\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_stderr/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_stderr/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"stderr\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  # logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_stderr_with_logfile/expected.conf",
    "content": "[agent]\ncollection_jitter = \"0s\"\nflush_interval = \"10s\"\nflush_jitter = \"0s\"\ninterval = \"10s\"\nmetric_batch_size = 1000\nmetric_buffer_limit = 10000\nprecision = \"0s\"\nround_interval = true\n"
  },
  {
    "path": "migrations/global_agent/testcases/logtarget_stderr_with_logfile/telegraf.conf",
    "content": "# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Collection offset is used to shift the collection by the given amount.\n  ## This can be be used to avoid many plugins querying constraint devices\n  ## at the same time by manually scheduling them in time.\n  # collection_offset = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## Collected metrics are rounded to the precision specified. Precision is\n  ## specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s).\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  ##\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s:\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ##\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  precision = \"0s\"\n\n  ## Log at debug level.\n  # debug = false\n  ## Log only error level messages.\n  # quiet = false\n\n  ## Log format controls the way messages are logged and can be one of \"text\",\n  ## \"structured\" or, on Windows, \"eventlog\".\n  # logformat = \"text\"\n\n  logtarget = \"stderr\"\n\n  ## Name of the file to be logged to or stderr if unset or empty. This\n  ## setting is ignored for the \"eventlog\" format.\n  logfile = \"lala.log\"\n\n  ## The logfile will be rotated after the time interval specified.  When set\n  ## to 0 no time based rotation is performed.  Logs are rotated only when\n  ## written to, if there is no log activity rotation may be delayed.\n  # logfile_rotation_interval = \"0h\"\n\n  ## The logfile will be rotated when it becomes larger than the specified\n  ## size.  When set to 0 no size based rotation is performed.\n  # logfile_rotation_max_size = \"0MB\"\n\n  ## Maximum number of rotated archives to keep, any older logs are deleted.\n  ## If set to -1, no archives are removed.\n  # logfile_rotation_max_archives = 5\n\n  ## Pick a timezone to use when logging or type 'local' for local time.\n  ## Example: America/Chicago\n  # log_with_timezone = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  # hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  # omit_hostname = false\n\n  ## Method of translating SNMP objects. Can be \"netsnmp\" (deprecated) which\n  ## translates by calling external programs snmptranslate and snmptable,\n  ## or \"gosmi\" which translates using the built-in gosmi library.\n  # snmp_translator = \"netsnmp\"\n\n  ## Name of the file to load the state of plugins from and store the state to.\n  ## If uncommented and not empty, this file will be used to save the state of\n  ## stateful plugins on termination of Telegraf. If the file exists on start,\n  ## the state in the file will be restored for the plugins.\n  # statefile = \"\"\n\n  ## Flag to skip running processors after aggregators\n  ## By default, processors are run a second time after aggregators. Changing\n  ## this setting to true will skip the second run of processors.\n  # skip_processors_after_aggregators = false\n"
  },
  {
    "path": "migrations/inputs_KNXListener/migration.go",
    "content": "package inputs_KNXListener\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate KNXListener to knx_listener\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old plugin configuration\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create the new plugin configuration with the same settings\n\t// but under the \"knx_listener\" plugin name instead of \"KNXListener\"\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"knx_listener\")\n\tcfg.Add(\"inputs\", \"knx_listener\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the deprecated plugin\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.KNXListener\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_KNXListener/migration_test.go",
    "content": "package inputs_KNXListener_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_KNXListener\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/knx_listener\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\t// Test that configs without the deprecated plugin remain unchanged\n\tplugin := &knx_listener.KNXListener{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Replace knx_listener with KNXListener to test the reverse case\n\t// (configs that already use knx_listener should not be affected)\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n) // No migrations applied\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_KNXListener/testcases/expected.conf",
    "content": "# Listener capable of handling KNX bus messages provided through a KNX-IP Interface.\n[[inputs.knx_listener]]\n  ## Type of KNX-IP interface.\n  ## Can be either \"tunnel_udp\", \"tunnel_tcp\", \"tunnel\" (alias for tunnel_udp) or \"router\".\n  # service_type = \"tunnel\"\n\n  ## Address of the KNX-IP interface.\n  service_address = \"localhost:3671\"\n\n  ## Measurement definition(s)\n  # [[inputs.knx_listener.measurement]]\n  #   ## Name of the measurement\n  #   name = \"temperature\"\n  #   ## Datapoint-Type (DPT) of the KNX messages\n  #   dpt = \"9.001\"\n  #   ## Use the string representation instead of the numerical value for the\n  #   ## datapoint-type and the addresses below\n  #   # as_string = false\n  #   ## List of Group-Addresses (GAs) assigned to the measurement\n  #   addresses = [\"5/5/1\"]\n\n  # [[inputs.knx_listener.measurement]]\n  #   name = \"illumination\"\n  #   dpt = \"9.004\"\n  #   addresses = [\"5/5/3\"]\n"
  },
  {
    "path": "migrations/inputs_KNXListener/testcases/telegraf.conf",
    "content": "# Listener capable of handling KNX bus messages provided through a KNX-IP Interface.\n[[inputs.KNXListener]]\n  ## Type of KNX-IP interface.\n  ## Can be either \"tunnel_udp\", \"tunnel_tcp\", \"tunnel\" (alias for tunnel_udp) or \"router\".\n  # service_type = \"tunnel\"\n\n  ## Address of the KNX-IP interface.\n  service_address = \"localhost:3671\"\n\n  ## Measurement definition(s)\n  # [[inputs.knx_listener.measurement]]\n  #   ## Name of the measurement\n  #   name = \"temperature\"\n  #   ## Datapoint-Type (DPT) of the KNX messages\n  #   dpt = \"9.001\"\n  #   ## Use the string representation instead of the numerical value for the\n  #   ## datapoint-type and the addresses below\n  #   # as_string = false\n  #   ## List of Group-Addresses (GAs) assigned to the measurement\n  #   addresses = [\"5/5/1\"]\n\n  # [[inputs.knx_listener.measurement]]\n  #   name = \"illumination\"\n  #   dpt = \"9.004\"\n  #   addresses = [\"5/5/3\"]\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/migration.go",
    "content": "package inputs_amqp_consumer\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldURL, found := plugin[\"url\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldURL, ok := rawOldURL.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'url'\", rawOldURL)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar brokers []string\n\t\tif rawBrokers, found := plugin[\"brokers\"]; found {\n\t\t\tvar err error\n\t\t\tbrokers, err = migrations.AsStringSlice(rawBrokers)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'brokers' option: %w\", err)\n\t\t\t}\n\t\t}\n\t\tif !slices.Contains(brokers, oldURL) {\n\t\t\tbrokers = append(brokers, oldURL)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"url\")\n\t\tplugin[\"brokers\"] = brokers\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"amqp_consumer\")\n\tcfg.Add(\"inputs\", \"amqp_consumer\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.amqp_consumer\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/migration_test.go",
    "content": "package inputs_amqp_consumer_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_amqp_consumer\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/amqp_consumer\"      // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/influx\"          // register parser\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &amqp_consumer.AMQPConsumer{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url/expected.conf",
    "content": "[[inputs.amqp_consumer]]\nbrokers = [\"amqp://localhost:5672/influxdb\"]\nexchange = \"telegraf\"\nqueue = \"telegraf\"\nqueue_durability = \"durable\"\nbinding_key = \"#\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url/telegraf.conf",
    "content": "# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  url = \"amqp://localhost:5672/influxdb\"\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers/expected.conf",
    "content": "[[inputs.amqp_consumer]]\nbrokers = [\"amqp://localhost:5672/influxdb\", \"amqp://my_server:9999/\"]\nexchange = \"telegraf\"\nqueue = \"telegraf\"\nqueue_durability = \"durable\"\nbinding_key = \"#\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers/telegraf.conf",
    "content": "# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  url = \"amqp://my_server:9999/\"\n\n  ## Brokers to consume from.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\"]\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers_duplicate/deprecated_url_existing_brokers/expected.conf",
    "content": "[[inputs.amqp_consumer]]\nbrokers = [\"amqp://localhost:5672/influxdb\", \"amqp://my_server:9999/\"]\nexchange = \"telegraf\"\nqueue = \"telegraf\"\nqueue_durability = \"durable\"\nbinding_key = \"#\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers_duplicate/deprecated_url_existing_brokers/telegraf.conf",
    "content": "# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  url = \"amqp://my_server:9999/\"\n\n  ## Brokers to consume from.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\", \"amqp://my_server:9999/\"]\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers_duplicate/expected.conf",
    "content": "[[inputs.amqp_consumer]]\nbrokers = [\"amqp://localhost:5672/influxdb\", \"amqp://my_server:9999/\"]\nexchange = \"telegraf\"\nqueue = \"telegraf\"\nqueue_durability = \"durable\"\nbinding_key = \"#\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_amqp_consumer/testcases/deprecated_url_existing_brokers_duplicate/telegraf.conf",
    "content": "# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  url = \"amqp://my_server:9999/\"\n\n  ## Brokers to consume from.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\"]\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_cassandra/migration.go",
    "content": "package inputs_cassandra\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t\"github.com/influxdata/telegraf/migrations/common\"\n)\n\n// Define \"old\" data structure\ntype cassandra struct {\n\tContext string   `toml:\"context\"`\n\tServers []string `toml:\"servers\"`\n\tMetrics []string `toml:\"metrics\"`\n\tcommon.InputOptions\n}\n\n// Define \"new\" data structure(s)\ntype metricConfig struct {\n\tName        string   `toml:\"name\"`\n\tMbean       string   `toml:\"mbean\"`\n\tFieldPrefix *string  `toml:\"field_prefix,omitempty\"`\n\tTagKeys     []string `toml:\"tag_keys,omitempty\"`\n}\n\ntype jolokiaAgent struct {\n\tURLs     []string       `toml:\"urls\"`\n\tUsername string         `toml:\"username,omitempty\"`\n\tPassword string         `toml:\"password,omitempty\"`\n\tMetrics  []metricConfig `toml:\"metric\"`\n\n\t// Common options\n\tInterval         string            `toml:\"interval,omitempty\"`\n\tPrecision        string            `toml:\"precision,omitempty\"`\n\tCollectionJitter string            `toml:\"collection_jitter,omitempty\"`\n\tCollectionOffset string            `toml:\"collection_offset,omitempty\"`\n\tNamePrefix       string            `toml:\"name_prefix,omitempty\"`\n\tNameSuffix       string            `toml:\"name_suffix,omitempty\"`\n\tNameOverride     string            `toml:\"name_override,omitempty\"`\n\tAlias            string            `toml:\"alias,omitempty\"`\n\tTags             map[string]string `toml:\"tags,omitempty\"`\n\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old cassandra\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Collect servers that use the same credentials\n\tendpoints := make(map[string]jolokiaAgent)\n\tfor _, server := range old.Servers {\n\t\tu, err := url.Parse(\"http://\" + server)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"invalid url %q: %w\", server, err)\n\t\t}\n\t\tif u.Path != \"\" {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected path in %q: %w\", server, err)\n\t\t}\n\t\tif u.Hostname() == \"\" {\n\t\t\tu.Host = \"localhost:\" + u.Port()\n\t\t}\n\t\tuser := u.User.Username()\n\t\tpasswd, _ := u.User.Password()\n\t\tkey := user + \":\" + passwd\n\n\t\tendpoint, found := endpoints[key]\n\t\tif !found {\n\t\t\tendpoint = jolokiaAgent{\n\t\t\t\tUsername: user,\n\t\t\t\tPassword: passwd,\n\t\t\t}\n\t\t\tendpoint.fillCommon(old.InputOptions)\n\t\t}\n\t\tu.User = nil\n\t\tendpoint.URLs = append(endpoint.URLs, u.String())\n\t\tendpoints[key] = endpoint\n\t}\n\n\t// Create new-style metrics according to the old config\n\tvar javaMetrics []metricConfig\n\tvar cassandraMetrics []metricConfig\n\tfor _, metric := range old.Metrics {\n\t\tbean := strings.TrimPrefix(metric, \"/\")\n\n\t\tparams := make(map[string]string)\n\t\tparts := strings.SplitN(bean, \":\", 2)\n\t\tfor _, p := range strings.Split(parts[1], \",\") {\n\t\t\tx := strings.SplitN(p, \"=\", 2)\n\t\t\tparams[x[0]] = x[1]\n\t\t}\n\n\t\tname, found := params[\"type\"]\n\t\tif !found {\n\t\t\treturn nil, \"\", fmt.Errorf(\"cannot determine name for metric %q\", metric)\n\t\t}\n\t\tname = strings.SplitN(name, \"/\", 2)[0]\n\n\t\tvar tagKeys []string\n\t\tvar prefix *string\n\t\tfor k := range params {\n\t\t\tswitch k {\n\t\t\tcase \"name\", \"scope\", \"path\", \"keyspace\":\n\t\t\t\ttagKeys = append(tagKeys, k)\n\t\t\t}\n\t\t}\n\t\tsort.Strings(tagKeys)\n\t\tfor i, k := range tagKeys {\n\t\t\tif k == \"name\" {\n\t\t\t\tp := fmt.Sprintf(\"$%d_\", i+1)\n\t\t\t\tprefix = &p\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase strings.HasPrefix(bean, \"java.lang:\"):\n\t\t\tjavaMetrics = append(javaMetrics, metricConfig{\n\t\t\t\tName:        name,\n\t\t\t\tMbean:       bean,\n\t\t\t\tTagKeys:     tagKeys,\n\t\t\t\tFieldPrefix: prefix,\n\t\t\t})\n\t\tcase strings.HasPrefix(bean, \"org.apache.cassandra.metrics:\"):\n\t\t\tcassandraMetrics = append(cassandraMetrics, metricConfig{\n\t\t\t\tName:        name,\n\t\t\t\tMbean:       bean,\n\t\t\t\tTagKeys:     tagKeys,\n\t\t\t\tFieldPrefix: prefix,\n\t\t\t})\n\t\tdefault:\n\t\t\treturn nil, \"\", fmt.Errorf(\"unknown java metric %q\", metric)\n\t\t}\n\t}\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"jolokia2_agent\")\n\tfor _, endpoint := range endpoints {\n\t\tif len(javaMetrics) > 0 {\n\t\t\tplugin := jolokiaAgent{\n\t\t\t\tURLs:     endpoint.URLs,\n\t\t\t\tUsername: endpoint.Username,\n\t\t\t\tPassword: endpoint.Password,\n\t\t\t\tMetrics:  javaMetrics,\n\t\t\t}\n\t\t\tplugin.fillCommon(old.InputOptions)\n\t\t\tplugin.NamePrefix = \"java\"\n\t\t\tcfg.Add(\"inputs\", \"jolokia2_agent\", plugin)\n\t\t}\n\t\tif len(cassandraMetrics) > 0 {\n\t\t\tplugin := jolokiaAgent{\n\t\t\t\tURLs:     endpoint.URLs,\n\t\t\t\tUsername: endpoint.Username,\n\t\t\t\tPassword: endpoint.Password,\n\t\t\t\tMetrics:  cassandraMetrics,\n\t\t\t}\n\t\t\tplugin.fillCommon(old.InputOptions)\n\t\t\tplugin.NamePrefix = \"cassandra\"\n\n\t\t\tcfg.Add(\"inputs\", \"jolokia2_agent\", plugin)\n\t\t}\n\t}\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, \"\", nil\n}\n\nfunc (j *jolokiaAgent) fillCommon(o common.InputOptions) {\n\to.Migrate()\n\n\tj.Interval = o.Interval\n\tj.Precision = o.Precision\n\tj.CollectionJitter = o.CollectionJitter\n\tj.CollectionOffset = o.CollectionOffset\n\tj.NamePrefix = o.NamePrefix\n\tj.NameSuffix = o.NameSuffix\n\tj.NameOverride = o.NameOverride\n\tj.Alias = o.Alias\n\tif len(o.Tags) > 0 {\n\t\tj.Tags = make(map[string]string, len(o.Tags))\n\t\tfor k, v := range o.Tags {\n\t\t\tj.Tags[k] = v\n\t\t}\n\t}\n\n\tif len(o.NamePass) > 0 {\n\t\tj.NamePass = append(j.NamePass, o.NamePass...)\n\t}\n\tif len(o.NameDrop) > 0 {\n\t\tj.NameDrop = append(j.NameDrop, o.NameDrop...)\n\t}\n\tif len(o.FieldInclude) > 0 {\n\t\tj.FieldInclude = append(j.FieldInclude, o.FieldInclude...)\n\t}\n\tif len(o.FieldExclude) > 0 {\n\t\tj.FieldExclude = append(j.FieldExclude, o.FieldExclude...)\n\t}\n\tif len(o.TagPassFilters) > 0 {\n\t\tj.TagPassFilters = make(map[string][]string, len(o.TagPassFilters))\n\t\tfor k, v := range o.TagPassFilters {\n\t\t\tj.TagPassFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagDropFilters) > 0 {\n\t\tj.TagDropFilters = make(map[string][]string, len(o.TagDropFilters))\n\t\tfor k, v := range o.TagDropFilters {\n\t\t\tj.TagDropFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagExclude) > 0 {\n\t\tj.TagExclude = append(j.TagExclude, o.TagExclude...)\n\t}\n\tif len(o.TagInclude) > 0 {\n\t\tj.TagInclude = append(j.TagInclude, o.TagInclude...)\n\t}\n\tj.MetricPass = o.MetricPass\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.cassandra\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_cassandra/migration_test.go",
    "content": "package inputs_cassandra_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_cassandra\"   // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/jolokia2_agent\" // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/filter_options/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\nname_prefix = \"java\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[inputs.jolokia2_agent.tagdrop]\napp = [\"myapp\"]\nlocation = [\"e*\"]\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\nname_prefix = \"cassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n[inputs.jolokia2_agent.tagdrop]\napp = [\"myapp\"]\nlocation = [\"e*\"]\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\nname_prefix = \"java\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[inputs.jolokia2_agent.tagdrop]\napp = [\"myapp\"]\nlocation = [\"e*\"]\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\nname_prefix = \"cassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n[inputs.jolokia2_agent.tagdrop]\napp = [\"myapp\"]\nlocation = [\"e*\"]\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/filter_options/telegraf.conf",
    "content": "[[inputs.cassandra]]\n  context = \"/jolokia/read\"\n  servers = [\"myuser:mypassword@10.10.10.1:8778\",\"10.10.10.2:8778\",\":8778\"]\n  metrics  = [\n    \"/java.lang:type=Memory/HeapMemoryUsage\",\n    \"/org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\n  ]\n\n  [inputs.cassandra.tagdrop]\n    app = [\"myapp\"]\n    location = [\"e*\"]\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/general_options/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\ninterval = \"20s\"\nname_prefix = \"java\"\nalias = \"mycassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[inputs.jolokia2_agent.tags]\napp = \"myapp\"\nlocation = \"east\"\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\ninterval = \"20s\"\nname_prefix = \"cassandra\"\nalias = \"mycassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n[inputs.jolokia2_agent.tags]\napp = \"myapp\"\nlocation = \"east\"\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\ninterval = \"20s\"\nname_prefix = \"java\"\nalias = \"mycassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[inputs.jolokia2_agent.tags]\napp = \"myapp\"\nlocation = \"east\"\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\ninterval = \"20s\"\nname_prefix = \"cassandra\"\nalias = \"mycassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n[inputs.jolokia2_agent.tags]\napp = \"myapp\"\nlocation = \"east\"\n\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/general_options/telegraf.conf",
    "content": "[[inputs.cassandra]]\n  interval = \"20s\"\n  alias = \"mycassandra\"\n  context = \"/jolokia/read\"\n  servers = [\"myuser:mypassword@10.10.10.1:8778\",\"10.10.10.2:8778\",\":8778\"]\n  metrics  = [\n    \"/java.lang:type=Memory/HeapMemoryUsage\",\n    \"/org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\n  ]\n\n  [inputs.cassandra.tags]\n    app = \"myapp\"\n    location = \"east\"\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/simple/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\nname_prefix = \"java\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.1:8778\"]\nusername = \"myuser\"\npassword = \"mypassword\"\nname_prefix = \"cassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\nname_prefix = \"java\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Memory\"\nmbean = \"java.lang:type=Memory/HeapMemoryUsage\"\n\n[[inputs.jolokia2_agent]]\nurls = [\"http://10.10.10.2:8778\", \"http://localhost:8778\"]\nname_prefix = \"cassandra\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"Table\"\nmbean = \"org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\nfield_prefix = \"$2_\"\ntag_keys = [\"keyspace\", \"name\", \"scope\"]\n\n"
  },
  {
    "path": "migrations/inputs_cassandra/testcases/simple/telegraf.conf",
    "content": "[[inputs.cassandra]]\n  context = \"/jolokia/read\"\n  ## List of cassandra servers exposing jolokia read service\n  servers = [\"myuser:mypassword@10.10.10.1:8778\",\"10.10.10.2:8778\",\":8778\"]\n  ## List of metrics collected on above servers\n  ## Each metric consists of a jmx path.\n  ## This will collect all heap memory usage metrics from the jvm and\n  ## ReadLatency metrics for all keyspaces and tables.\n  ## \"type=Table\" in the query works with Cassandra3.0. Older versions might\n  ## need to use \"type=ColumnFamily\"\n  metrics  = [\n    \"/java.lang:type=Memory/HeapMemoryUsage\",\n    \"/org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency\"\n  ]\n"
  },
  {
    "path": "migrations/inputs_cisco_telemetry_gnmi/migration.go",
    "content": "package inputs_cisco_telemetry_gnmi\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate cisco_telemetry_gnmi to gnmi\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old plugin configuration\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create the new plugin configuration with the same settings\n\t// but under the \"gnmi\" plugin name instead of \"cisco_telemetry_gnmi\"\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"gnmi\")\n\tcfg.Add(\"inputs\", \"gnmi\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\tmessage := \"migrated from deprecated 'cisco_telemetry_gnmi' to 'gnmi'\"\n\treturn output, message, err\n}\n\n// Register the migration function for the deprecated plugin\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.cisco_telemetry_gnmi\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_cisco_telemetry_gnmi/migration_test.go",
    "content": "package inputs_cisco_telemetry_gnmi_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_cisco_telemetry_gnmi\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/gnmi\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\t// Test that configs without the deprecated plugin remain unchanged\n\tplugin := &gnmi.GNMI{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Replace gnmi with cisco_telemetry_gnmi to test the reverse case\n\t// (configs that already use gnmi should not be affected)\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n) // No migrations applied\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_cisco_telemetry_gnmi/testcases/deprecated_alias/expected.conf",
    "content": "# gNMI telemetry input plugin (migrated from cisco_telemetry_gnmi)\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Keepalive settings\n  ## See https://pkg.go.dev/google.golang.org/grpc/keepalive\n  ## The client will ping the server to see if the transport is still alive if it has\n  ## not see any activity for the given time.\n  ## If not set, none of the keep-alive setting (including those below) will be applied.\n  ## If set and set below 10 seconds, the gRPC library will apply a minimum value of 10s will be used instead.\n  # keepalive_time = \"\"\n\n  ## Timeout for seeing any activity after the keep-alive probe was\n  ## sent. If no activity is seen the connection is closed.\n  # keepalive_timeout = \"\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Subtree depth for depth extension (disables if < 1)\n  ## see https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-depth.md\n  # depth = 0\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Only receive updates for the state, also suppresses receiving the initial state\n  # updates_only = false\n\n  ## Enforces the namespace of the first element as origin for aliases and\n  ## response paths, required for backward compatibility.\n  ## NOTE: Set to 'false' if possible but be aware that this might change the path tag!\n  # enforce_first_namespace_as_origin = true\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## Supported values are\n  ##   none         -- do not add a 'path' tag\n  ##   common path  -- use the common path elements of all fields in an update\n  ##   subscription -- use the subscription path\n  # path_guessing_strategy = \"none\"\n\n  ## Prefix tags from path keys with the path element\n  # prefix_tag_key_with_path = false\n\n  ## Optional client-side TLS to authenticate the device\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## YANG model paths for decoding IETF JSON payloads\n  ## Model files are loaded recursively from the given directories. Disabled if\n  ## no models are specified.\n  # yang_model_paths = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]"
  },
  {
    "path": "migrations/inputs_cisco_telemetry_gnmi/testcases/deprecated_alias/telegraf.conf",
    "content": "# gNMI telemetry input plugin using deprecated alias\n[[inputs.cisco_telemetry_gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Keepalive settings\n  ## See https://pkg.go.dev/google.golang.org/grpc/keepalive\n  ## The client will ping the server to see if the transport is still alive if it has\n  ## not see any activity for the given time.\n  ## If not set, none of the keep-alive setting (including those below) will be applied.\n  ## If set and set below 10 seconds, the gRPC library will apply a minimum value of 10s will be used instead.\n  # keepalive_time = \"\"\n\n  ## Timeout for seeing any activity after the keep-alive probe was\n  ## sent. If no activity is seen the connection is closed.\n  # keepalive_timeout = \"\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Subtree depth for depth extension (disables if < 1)\n  ## see https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-depth.md\n  # depth = 0\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Only receive updates for the state, also suppresses receiving the initial state\n  # updates_only = false\n\n  ## Enforces the namespace of the first element as origin for aliases and\n  ## response paths, required for backward compatibility.\n  ## NOTE: Set to 'false' if possible but be aware that this might change the path tag!\n  # enforce_first_namespace_as_origin = true\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## Supported values are\n  ##   none         -- do not add a 'path' tag\n  ##   common path  -- use the common path elements of all fields in an update\n  ##   subscription -- use the subscription path\n  # path_guessing_strategy = \"none\"\n\n  ## Prefix tags from path keys with the path element\n  # prefix_tag_key_with_path = false\n\n  ## Optional client-side TLS to authenticate the device\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## YANG model paths for decoding IETF JSON payloads\n  ## Model files are loaded recursively from the given directories. Disabled if\n  ## no models are specified.\n  # yang_model_paths = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.cisco_telemetry_gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.cisco_telemetry_gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.cisco_telemetry_gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]"
  },
  {
    "path": "migrations/inputs_cloudwatch/migration.go",
    "content": "package inputs_cloudwatch\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated namespace option to namespaces\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tvar applied bool\n\n\t// Check if deprecated 'namespace' option exists\n\tif namespaceValue, found := plugin[\"namespace\"]; found {\n\t\tapplied = true\n\n\t\t// Get the namespace value as string\n\t\tnamespaceStr, ok := namespaceValue.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"namespace value is not a string: %T\", namespaceValue)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar namespaces []string\n\t\tif rawNewNamespaces, found := plugin[\"namespaces\"]; found {\n\t\t\tvar err error\n\t\t\tnamespaces, err = migrations.AsStringSlice(rawNewNamespaces)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'namespaces' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(namespaces, namespaceStr) {\n\t\t\tnamespaces = append(namespaces, namespaceStr)\n\t\t}\n\n\t\t// Update the plugin configuration\n\t\tplugin[\"namespaces\"] = namespaces\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"namespace\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"cloudwatch\")\n\tcfg.Add(\"inputs\", \"cloudwatch\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.cloudwatch\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_cloudwatch/migration_test.go",
    "content": "package inputs_cloudwatch_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_cloudwatch\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/cloudwatch\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &cloudwatch.CloudWatch{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/multiple_cloudwatch_instances/expected.conf",
    "content": "# Multiple CloudWatch instances with migrated namespaces\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespaces = [\"AWS/ELB\"]\n  period = \"5m\"\n  delay = \"5m\"\n\n[[inputs.cloudwatch]]\n  region = \"us-west-2\"\n  namespaces = [\"AWS/EC2\"]\n  period = \"5m\"\n  delay = \"5m\"\n\n[[inputs.cloudwatch]]\n  region = \"eu-west-1\"\n  namespaces = [\"AWS/Lambda\", \"AWS/RDS\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/multiple_cloudwatch_instances/telegraf.conf",
    "content": "# Multiple CloudWatch instances with different scenarios\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespace = \"AWS/ELB\"\n  period = \"5m\"\n  delay = \"5m\"\n\n[[inputs.cloudwatch]]\n  region = \"us-west-2\"\n  namespaces = [\"AWS/EC2\"]\n  period = \"5m\"\n  delay = \"5m\"\n\n[[inputs.cloudwatch]]\n  region = \"eu-west-1\"\n  namespace = \"AWS/RDS\"\n  namespaces = [\"AWS/Lambda\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_duplicate_in_namespaces/expected.conf",
    "content": "# CloudWatch with duplicate namespace removed\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespaces = [\"AWS/ELB\", \"AWS/EC2\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_duplicate_in_namespaces/telegraf.conf",
    "content": "# CloudWatch with namespace already in namespaces (duplicate case)\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespace = \"AWS/ELB\"\n  namespaces = [\"AWS/ELB\", \"AWS/EC2\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_merge_with_namespaces/expected.conf",
    "content": "# CloudWatch with merged namespaces\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespaces = [\"AWS/EC2\", \"AWS/RDS\", \"AWS/ELB\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_merge_with_namespaces/telegraf.conf",
    "content": "# CloudWatch with both namespace and namespaces (merge case)\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespace = \"AWS/ELB\"\n  namespaces = [\"AWS/EC2\", \"AWS/RDS\"]\n  period = \"5m\"\n  delay = \"5m\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_to_namespaces/expected.conf",
    "content": "# CloudWatch with migrated namespaces option\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespaces = [\"AWS/ELB\"]\n  period = \"5m\"\n  delay = \"5m\"\n  \n  [[inputs.cloudwatch.metrics]]\n    names = [\"Latency\", \"RequestCount\"]\n    \n    [[inputs.cloudwatch.metrics.dimensions]]\n      name = \"LoadBalancerName\"\n      value = \"p-example\""
  },
  {
    "path": "migrations/inputs_cloudwatch/testcases/namespace_to_namespaces/telegraf.conf",
    "content": "# CloudWatch with deprecated namespace option\n[[inputs.cloudwatch]]\n  region = \"us-east-1\"\n  namespace = \"AWS/ELB\"\n  period = \"5m\"\n  delay = \"5m\"\n\n  [[inputs.cloudwatch.metrics]]\n    names = [\"Latency\", \"RequestCount\"]\n\n    [[inputs.cloudwatch.metrics.dimensions]]\n      name = \"LoadBalancerName\"\n      value = \"p-example\""
  },
  {
    "path": "migrations/inputs_consul/migration.go",
    "content": "package inputs_consul\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldDatacentre, found := plugin[\"datacentre\"]; found {\n\t\t// Convert the options to the actual type\n\t\toldDatacentre, ok := rawOldDatacentre.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'datacentre'\", rawOldDatacentre)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are\n\t\t// conflicting.\n\t\tif rawNewDatacenter, found := plugin[\"datacenter\"]; found {\n\t\t\tif newDatacenter, ok := rawNewDatacenter.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'datacenter'\", rawNewDatacenter)\n\t\t\t} else if oldDatacentre != newDatacenter {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'datacentre' and 'datacenter'\")\n\t\t\t}\n\t\t}\n\t\tapplied = true\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"datacenter\"] = oldDatacentre\n\t\tdelete(plugin, \"datacentre\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"consul\")\n\tcfg.Add(\"inputs\", \"consul\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.consul\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_consul/migration_test.go",
    "content": "package inputs_consul_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_consul\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/consul\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &consul.Consul{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestDataCentreConflict(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.consul]]\n  address = \"localhost:8500\"\n  datacenter = \"us-est\"\n  datacentre = \"foobar\"\n\t`)\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'datacentre' and 'datacenter'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_consul/testcases/deprecated_centre_existing/expected.conf",
    "content": "[[inputs.consul]]\ndatacenter = \"foobar\"\n"
  },
  {
    "path": "migrations/inputs_consul/testcases/deprecated_centre_existing/telegraf.conf",
    "content": "# Gather health check statuses from services registered in Consul\n[[inputs.consul]]\n  ## Consul server address\n  # address = \"localhost:8500\"\n\n  ## URI scheme for the Consul server, one of \"http\", \"https\"\n  # scheme = \"http\"\n\n  ## Metric version controls the mapping from Consul metrics into\n  ## Telegraf metrics. Version 2 moved all fields with string values\n  ## to tags.\n  ##\n  ##   example: metric_version = 1; deprecated in 1.16\n  ##            metric_version = 2; recommended version\n  # metric_version = 1\n\n  ## ACL token used in every request\n  # token = \"\"\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Data center to query the health checks from\n  datacenter = \"foobar\"\n  datacentre = \"foobar\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Consul checks' tag splitting\n  # When tags are formatted like \"key:value\" with \":\" as a delimiter then\n  # they will be split and reported as proper key:value in Telegraf\n  # tag_delimiter = \":\"\n"
  },
  {
    "path": "migrations/inputs_consul/testcases/deprecated_datacentre/expected.conf",
    "content": "[[inputs.consul]]\ndatacenter = \"foobar\"\n"
  },
  {
    "path": "migrations/inputs_consul/testcases/deprecated_datacentre/telegraf.conf",
    "content": "# Gather health check statuses from services registered in Consul\n[[inputs.consul]]\n  ## Consul server address\n  # address = \"localhost:8500\"\n\n  ## URI scheme for the Consul server, one of \"http\", \"https\"\n  # scheme = \"http\"\n\n  ## Metric version controls the mapping from Consul metrics into\n  ## Telegraf metrics. Version 2 moved all fields with string values\n  ## to tags.\n  ##\n  ##   example: metric_version = 1; deprecated in 1.16\n  ##            metric_version = 2; recommended version\n  # metric_version = 1\n\n  ## ACL token used in every request\n  # token = \"\"\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Data center to query the health checks from\n  datacentre = \"foobar\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Consul checks' tag splitting\n  # When tags are formatted like \"key:value\" with \":\" as a delimiter then\n  # they will be split and reported as proper key:value in Telegraf\n  # tag_delimiter = \":\"\n"
  },
  {
    "path": "migrations/inputs_disk/migration.go",
    "content": "package inputs_disk\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawDeprecatedMountpoints, found := plugin[\"mountpoints\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\tdeprecatedMountpoints, err := migrations.AsStringSlice(rawDeprecatedMountpoints)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"'mountpoints' option: %w\", err)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar mountpoints []string\n\t\tif rawMountpoints, found := plugin[\"mount_points\"]; found {\n\t\t\tmountpoints, err = migrations.AsStringSlice(rawMountpoints)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'mount_points' option: %w\", err)\n\t\t\t}\n\t\t}\n\t\tfor _, dmp := range deprecatedMountpoints {\n\t\t\tif !choice.Contains(dmp, mountpoints) {\n\t\t\t\tmountpoints = append(mountpoints, dmp)\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"mountpoints\")\n\t\tplugin[\"mount_points\"] = mountpoints\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"disk\")\n\tcfg.Add(\"inputs\", \"disk\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.disk\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_disk/migration_test.go",
    "content": "package inputs_disk_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_disk\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/disk\"    // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tdefaultCfg := []byte(`\n# Read metrics about disk usage by mount point\n[[inputs.disk]]\n  ## By default stats will be gathered for all mount points.\n  ## Set mount_points will restrict the stats to only the specified mount points.\n  # mount_points = [\"/\"]\n\n  ## Ignore mount points by filesystem type.\n  ignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n\n  ## Ignore mount points by mount options.\n  ## The 'mount' command reports options of all mounts in parathesis.\n  ## Bind mounts can be ignored with the special 'bind' option.\n  # ignore_mount_opts = []\n`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_disk/testcases/deprecated_mountpoints/expected.conf",
    "content": "[[inputs.disk]]\nmount_points = [\"/mnt/disk\", \"/srv\", \"/mnt/others\"]\nignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n"
  },
  {
    "path": "migrations/inputs_disk/testcases/deprecated_mountpoints/telegraf.conf",
    "content": "# Read metrics about disk usage by mount point\n[[inputs.disk]]\n  ## Deprecated mountpoint option\n  mountpoints = [\"/mnt/disk\", \"/srv\", \"/mnt/others\"]\n\n  ## Ignore mount points by filesystem type.\n  ignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n"
  },
  {
    "path": "migrations/inputs_disk/testcases/deprecated_mountpoints_existing/expected.conf",
    "content": "[[inputs.disk]]\nmount_points = [\"/\", \"/srv\", \"/mnt/disk\", \"/mnt/others\"]\nignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n"
  },
  {
    "path": "migrations/inputs_disk/testcases/deprecated_mountpoints_existing/telegraf.conf",
    "content": "# Read metrics about disk usage by mount point\n[[inputs.disk]]\n  ## Deprecated mountpoint option\n  mountpoints = [\"/mnt/disk\", \"/srv\", \"/mnt/others\"]\n\n  ## By default stats will be gathered for all mount points.\n  ## Set mount_points will restrict the stats to only the specified mount points.\n  mount_points = [\"/\", \"/srv\"]\n\n  ## Ignore mount points by filesystem type.\n  ignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n"
  },
  {
    "path": "migrations/inputs_docker/migration.go",
    "content": "package inputs_docker\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate multiple deprecated Docker options\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tvar applied bool\n\n\t// 1. Migrate container_names -> container_name_include\n\tif rawContainerNames, found := plugin[\"container_names\"]; found {\n\t\tapplied = true\n\n\t\t// Convert to actual type\n\t\tcontainerNames, err := migrations.AsStringSlice(rawContainerNames)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'container_names': %w\", err)\n\t\t}\n\n\t\t// Check if container_name_include already exists\n\t\tvar includes []string\n\t\tif rawContainerNameInclude, found := plugin[\"container_name_include\"]; found {\n\t\t\t// Convert to actual type\n\t\t\tif includes, err = migrations.AsStringSlice(rawContainerNameInclude); err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'container_name_include': %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// Merge the options\n\t\tfor _, name := range containerNames {\n\t\t\tif !slices.Contains(includes, name) {\n\t\t\t\tincludes = append(includes, name)\n\t\t\t}\n\t\t}\n\n\t\t// Remove deprecated field and replace by the migrated one\n\t\tplugin[\"container_name_include\"] = includes\n\t\tdelete(plugin, \"container_names\")\n\t}\n\n\t// 2. Migrate perdevice -> perdevice_include\n\tif rawPerDevice, found := plugin[\"perdevice\"]; found {\n\t\tapplied = true\n\n\t\t// Check if it's a boolean\n\t\tperDevice, ok := rawPerDevice.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'perdevice'\", rawPerDevice)\n\t\t}\n\n\t\t// Get the existing include list for checking if set\n\t\tvar includes []string\n\t\tif rawPerDeviceInclude, found := plugin[\"perdevice_include\"]; found {\n\t\t\tvar err error\n\t\t\tif includes, err = migrations.AsStringSlice(rawPerDeviceInclude); err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'perdevice_include': %w\", err)\n\t\t\t}\n\t\t\tif perDevice {\n\t\t\t\tif !slices.Contains(includes, \"network\") {\n\t\t\t\t\tincludes = append(includes, \"network\")\n\t\t\t\t}\n\t\t\t\tif !slices.Contains(includes, \"blkio\") {\n\t\t\t\t\tincludes = append(includes, \"blkio\")\n\t\t\t\t}\n\t\t\t} else if slices.Contains(includes, \"network\") || slices.Contains(includes, \"blkio\") {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting settings for 'perdevice' and 'perdevice_include'\")\n\t\t\t}\n\t\t} else if perDevice {\n\t\t\tincludes = []string{\"cpu\", \"network\", \"blkio\"}\n\t\t}\n\n\t\t// Remove deprecated setting and add new one\n\t\tplugin[\"perdevice_include\"] = includes\n\t\tdelete(plugin, \"perdevice\")\n\t}\n\n\t// 3. Migrate total -> total_include\n\tif totalValue, found := plugin[\"total\"]; found {\n\t\t// Check if it's a boolean\n\t\ttotalBool, ok := totalValue.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"total value is not a boolean: %T\", totalValue)\n\t\t}\n\n\t\t// Always remove the deprecated field\n\t\tdelete(plugin, \"total\")\n\t\tapplied = true\n\n\t\t// Only modify total_include if total=false AND there's an existing total_include that needs modification\n\t\tif !totalBool {\n\t\t\tif existingInclude, exists := plugin[\"total_include\"]; exists {\n\t\t\t\t// total=false means only cpu (following plugin logic)\n\t\t\t\tvar existing []interface{}\n\t\t\t\tswitch v := existingInclude.(type) {\n\t\t\t\tcase []interface{}:\n\t\t\t\t\texisting = v\n\t\t\t\tcase []string:\n\t\t\t\t\tfor _, name := range v {\n\t\t\t\t\t\texisting = append(existing, name)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, \"\", fmt.Errorf(\"total_include value is not a slice: %T\", existingInclude)\n\t\t\t\t}\n\n\t\t\t\t// Keep only cpu if present, remove others\n\t\t\t\tvar cpuOnly []interface{}\n\t\t\t\tfor _, item := range existing {\n\t\t\t\t\tif str, ok := item.(string); ok && str == \"cpu\" {\n\t\t\t\t\t\tcpuOnly = append(cpuOnly, \"cpu\")\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tplugin[\"total_include\"] = cpuOnly\n\t\t\t}\n\t\t\t// Don't create total_include for total=false - let plugin handle defaults\n\t\t}\n\t\t// total=true is default behavior - no action needed\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"docker\")\n\tcfg.Add(\"inputs\", \"docker\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.docker\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_docker/migration_test.go",
    "content": "package inputs_docker_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_docker\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/docker\"    // register migration\n)\n\nfunc TestNoMigration(t *testing.T) {\n\t// Create a config without any deprecated fields to test no migration scenario\n\tcleanConfig := `[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  source_tag = false\n  container_name_include = []\n  container_name_exclude = []\n  timeout = \"5s\"\n  perdevice_include = [\"cpu\"]\n  total_include = [\"cpu\", \"blkio\", \"network\"]\n  docker_label_include = []\n  docker_label_exclude = []\n  tag_env = [\"JAVA_HOME\", \"HEAP_SIZE\"]\n`\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(cleanConfig))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, cleanConfig, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_docker/testcases/all_deprecated_options/expected.conf",
    "content": "# Docker with all options migrated\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = true\n  container_name_include = [\"web\", \"api\"]\n  perdevice_include = [\"cpu\", \"network\", \"blkio\"]\n  source_tag = true\n  timeout = \"10s\"\n  docker_label_include = [\"app\", \"version\"]\n  docker_label_exclude = [\"internal\"]\n  tag_env = [\"NODE_ENV\", \"PORT\"]\n\n  # TLS Configuration\n  #tls_ca = \"/etc/telegraf/ca.pem\"\n  #tls_cert = \"/etc/telegraf/cert.pem\"\n  #tls_key = \"/etc/telegraf/key.pem\"\n  insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_docker/testcases/all_deprecated_options/telegraf.conf",
    "content": "# Docker with all deprecated options\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = true\n  container_names = [\"web\", \"api\"]\n  perdevice = true\n  total = false\n  source_tag = true\n  timeout = \"10s\"\n  docker_label_include = [\"app\", \"version\"]\n  docker_label_exclude = [\"internal\"]\n  tag_env = [\"NODE_ENV\", \"PORT\"]\n\n  # TLS Configuration\n  #tls_ca = \"/etc/telegraf/ca.pem\"\n  #tls_cert = \"/etc/telegraf/cert.pem\"\n  #tls_key = \"/etc/telegraf/key.pem\"\n  insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_docker/testcases/conflict_resolution/expected.conf",
    "content": "# Docker with conflicts resolved (new options preserved, deprecated merged/removed)\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_name_include = [\"new1\", \"new2\", \"legacy1\", \"legacy2\"]\n  perdevice_include = [\"cpu\", \"network\", \"blkio\"]\n  total_include = [\"blkio\"]\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/conflict_resolution/telegraf.conf",
    "content": "# Docker with conflicts between old and new options\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_names = [\"legacy1\", \"legacy2\"]\n  container_name_include = [\"new1\", \"new2\"]\n  perdevice = true\n  perdevice_include = [\"cpu\"]\n  total = true\n  total_include = [\"blkio\"]\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/container_names_merge/expected.conf",
    "content": "# Docker with merged container_name_include\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_name_include = [\"app\", \"worker\", \"web\", \"database\"]\n  source_tag = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/container_names_merge/telegraf.conf",
    "content": "# Docker with both container_names and container_name_include (merge case)\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_names = [\"web\", \"database\"]\n  container_name_include = [\"app\", \"worker\"]\n  source_tag = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/container_names_migration/expected.conf",
    "content": "# Docker with migrated container_name_include option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_name_include = [\"web\", \"database\", \"cache\"]\n  source_tag = false\n  timeout = \"5s\"\n  docker_label_include = []\n  docker_label_exclude = []\n  tag_env = [\"JAVA_HOME\", \"HEAP_SIZE\"]"
  },
  {
    "path": "migrations/inputs_docker/testcases/container_names_migration/telegraf.conf",
    "content": "# Docker with deprecated container_names option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  container_names = [\"web\", \"database\", \"cache\"]\n  source_tag = false\n  timeout = \"5s\"\n  docker_label_include = []\n  docker_label_exclude = []\n  tag_env = [\"JAVA_HOME\", \"HEAP_SIZE\"]"
  },
  {
    "path": "migrations/inputs_docker/testcases/perdevice_false_migration/expected.conf",
    "content": "# Docker with perdevice=false removed (no migration needed as it's default behavior)\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  perdevice_include = []\n  gather_services = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/perdevice_false_migration/telegraf.conf",
    "content": "# Docker with deprecated perdevice=false option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  perdevice = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/perdevice_true_migration/expected.conf",
    "content": "# Docker with migrated perdevice_include option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  perdevice_include = [\"cpu\", \"network\", \"blkio\"]\n  timeout = \"5s\"\n  docker_label_include = []\n  docker_label_exclude = []"
  },
  {
    "path": "migrations/inputs_docker/testcases/perdevice_true_migration/telegraf.conf",
    "content": "# Docker with deprecated perdevice=true option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  perdevice = true\n  timeout = \"5s\"\n  docker_label_include = []\n  docker_label_exclude = []"
  },
  {
    "path": "migrations/inputs_docker/testcases/total_false_migration/expected.conf",
    "content": "# Docker with total=false removed (no migration needed as plugin handles this internally)\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/total_false_migration/telegraf.conf",
    "content": "# Docker with deprecated total=false option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  total = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/total_true_migration/expected.conf",
    "content": "# Docker with total=true removed (no migration needed as it's default behavior)\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_docker/testcases/total_true_migration/telegraf.conf",
    "content": "# Docker with deprecated total=true option\n[[inputs.docker]]\n  endpoint = \"unix:///var/run/docker.sock\"\n  gather_services = false\n  total = true\n  timeout = \"5s\""
  },
  {
    "path": "migrations/inputs_elasticsearch/migration.go",
    "content": "package inputs_elasticsearch\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate a deprecated http_timeout option to timeout\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tvar applied bool\n\n\t// Check if deprecated 'http_timeout' option exists\n\tif httpTimeoutValue, found := plugin[\"http_timeout\"]; found {\n\t\tapplied = true\n\n\t\t// Check if 'timeout' already exists\n\t\tif timeoutValue, exists := plugin[\"timeout\"]; exists {\n\t\t\t// Both exist - check for conflicts\n\t\t\tif httpTimeoutValue != timeoutValue {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"contradicting setting for 'http_timeout' (%v) and 'timeout' (%v)\", httpTimeoutValue, timeoutValue)\n\t\t\t}\n\t\t\t// Values are the same, just remove the deprecated one\n\t\t} else {\n\t\t\t// Only http_timeout exists - migrate it to timeout\n\t\t\tplugin[\"timeout\"] = httpTimeoutValue\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"http_timeout\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"elasticsearch\")\n\tcfg.Add(\"inputs\", \"elasticsearch\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.elasticsearch\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_elasticsearch/migration_test.go",
    "content": "package inputs_elasticsearch_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_elasticsearch\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/elasticsearch\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &elasticsearch.Elasticsearch{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestTimeoutConflict(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  http_timeout = \"10s\"\n  timeout = \"15s\"\n\t`)\n\n\t// Migrate and check that it fails with conflict error\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'http_timeout' (10s) and 'timeout' (15s)\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_to_timeout/expected.conf",
    "content": "# Elasticsearch with migrated timeout option\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = false\n  cluster_stats = false\n  timeout = \"10s\"\n  indices_include = [\"_all\"]\n  indices_level = \"shards\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_to_timeout/telegraf.conf",
    "content": "# Elasticsearch with deprecated http_timeout option\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = false\n  cluster_stats = false\n  http_timeout = \"10s\"\n  indices_include = [\"_all\"]\n  indices_level = \"shards\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_auth/expected.conf",
    "content": "# Elasticsearch with migrated timeout and authentication\n[[inputs.elasticsearch]]\n  servers = [\"http://user:password@localhost:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = true\n  cluster_stats_only_from_master = true\n  enrich_stats = false\n  timeout = \"30s\"\n  indices_include = [\"application-*\", \"system-*\"]\n  indices_level = \"shards\"\n  username = \"elastic\"\n  password = \"changeme\"\n\n  [inputs.elasticsearch.headers]\n    \"X-Custom-Header\" = \"telegraf\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_auth/telegraf.conf",
    "content": "# Elasticsearch with http_timeout and authentication\n[[inputs.elasticsearch]]\n  servers = [\"http://user:password@localhost:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = true\n  cluster_stats_only_from_master = true\n  enrich_stats = false\n  http_timeout = \"30s\"\n  indices_include = [\"application-*\", \"system-*\"]\n  indices_level = \"shards\"\n  username = \"elastic\"\n  password = \"changeme\"\n\n  [inputs.elasticsearch.headers]\n    \"X-Custom-Header\" = \"telegraf\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_existing_timeout/expected.conf",
    "content": "# Elasticsearch with conflict resolved (timeout preserved, http_timeout removed)\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = false\n  cluster_stats = false\n  timeout = \"15s\"\n  indices_include = [\"_all\"]\n  indices_level = \"shards\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_existing_timeout/telegraf.conf",
    "content": "# Elasticsearch with both http_timeout and timeout (same values - no conflict)\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = false\n  cluster_stats = false\n  http_timeout = \"15s\"\n  timeout = \"15s\"\n  indices_include = [\"_all\"]\n  indices_level = \"shards\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_tls/expected.conf",
    "content": "# Elasticsearch with migrated timeout and TLS configuration\n[[inputs.elasticsearch]]\n  servers = [\"https://elasticsearch.example.com:9200\"]\n  local = false\n  cluster_health = true\n  cluster_stats = true\n  cluster_health_level = \"cluster\"\n  timeout = \"45s\"\n  indices_include = [\"_all\"]\n  indices_level = \"cluster\"\n  node_stats = [\"jvm\", \"http\", \"process\"]\n  num_most_recent_indices = 5\n\n  # TLS Configuration\n  #tls_ca = \"/etc/telegraf/ca.pem\"\n  #tls_cert = \"/etc/telegraf/cert.pem\"\n  #tls_key = \"/etc/telegraf/key.pem\"\n  insecure_skip_verify = false\n\n  # Proxy Configuration\n  use_system_proxy = false\n  http_proxy_url = \"http://proxy.example.com:8080\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/http_timeout_with_tls/telegraf.conf",
    "content": "# Elasticsearch with http_timeout and TLS configuration\n[[inputs.elasticsearch]]\n  servers = [\"https://elasticsearch.example.com:9200\"]\n  local = false\n  cluster_health = true\n  cluster_stats = true\n  cluster_health_level = \"cluster\"\n  http_timeout = \"45s\"\n  indices_include = [\"_all\"]\n  indices_level = \"cluster\"\n  node_stats = [\"jvm\", \"http\", \"process\"]\n  num_most_recent_indices = 5\n\n  # TLS Configuration\n  #tls_ca = \"/etc/telegraf/ca.pem\"\n  #tls_cert = \"/etc/telegraf/cert.pem\"\n  #tls_key = \"/etc/telegraf/key.pem\"\n  insecure_skip_verify = false\n\n  # Proxy Configuration\n  use_system_proxy = false\n  http_proxy_url = \"http://proxy.example.com:8080\""
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/multiple_elasticsearch_instances/expected.conf",
    "content": "# Multiple Elasticsearch instances with migrated timeouts\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = false\n  timeout = \"5s\"\n  indices_include = [\"_all\"]\n\n[[inputs.elasticsearch]]\n  servers = [\"http://elasticsearch2:9200\"]\n  local = false\n  cluster_health = false\n  cluster_stats = true\n  timeout = \"20s\"\n  indices_include = [\"logs-*\"]\n\n[[inputs.elasticsearch]]\n  servers = [\"http://elasticsearch3:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = true\n  timeout = \"12s\"\n  indices_include = [\"metrics-*\"]"
  },
  {
    "path": "migrations/inputs_elasticsearch/testcases/multiple_elasticsearch_instances/telegraf.conf",
    "content": "# Multiple Elasticsearch instances with different scenarios\n[[inputs.elasticsearch]]\n  servers = [\"http://localhost:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = false\n  http_timeout = \"5s\"\n  indices_include = [\"_all\"]\n\n[[inputs.elasticsearch]]\n  servers = [\"http://elasticsearch2:9200\"]\n  local = false\n  cluster_health = false\n  cluster_stats = true\n  timeout = \"20s\"\n  indices_include = [\"logs-*\"]\n\n[[inputs.elasticsearch]]\n  servers = [\"http://elasticsearch3:9200\"]\n  local = true\n  cluster_health = true\n  cluster_stats = true\n  http_timeout = \"12s\"\n  timeout = \"12s\"\n  indices_include = [\"metrics-*\"]"
  },
  {
    "path": "migrations/inputs_filecount/migration.go",
    "content": "package inputs_filecount\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldDirectory, found := plugin[\"directory\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldDirectory, ok := rawOldDirectory.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'directory'\", rawOldDirectory)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar directories []string\n\t\tif rawNewDirectories, found := plugin[\"directories\"]; found {\n\t\t\tvar err error\n\t\t\tdirectories, err = migrations.AsStringSlice(rawNewDirectories)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'directories' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(directories, oldDirectory) {\n\t\t\tdirectories = append(directories, oldDirectory)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"directory\")\n\t\tplugin[\"directories\"] = directories\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"filecount\")\n\tcfg.Add(\"inputs\", \"filecount\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.filecount\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_filecount/migration_test.go",
    "content": "package inputs_filecount_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_filecount\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/filecount\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &filecount.FileCount{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory/expected.conf",
    "content": "[[inputs.filecount]]\ndirectories = [\"/tmp\"]\nname = \"*\"\nrecursive = true\nregular_only = true\nfollow_symlinks = false\nsize = \"0B\"\nmtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory/telegraf.conf",
    "content": "# Count files in a directory\n[[inputs.filecount]]\n  directory = \"/tmp\"\n\n  ## Only count files that match the name pattern. Defaults to \"*\".\n  name = \"*\"\n\n  ## Count files in subdirectories. Defaults to true.\n  recursive = true\n\n  ## Only count regular files. Defaults to true.\n  regular_only = true\n\n  ## Follow all symlinks while walking the directory tree. Defaults to false.\n  follow_symlinks = false\n\n  ## Only count files that are at least this size. If size is\n  ## a negative number, only count files that are smaller than the\n  ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...\n  ## Without quotes and units, interpreted as size in bytes.\n  size = \"0B\"\n\n  ## Only count files that have not been touched for at least this\n  ## duration. If mtime is negative, only count files that have been\n  ## touched in this duration. Defaults to \"0s\".\n  mtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory_duplicate/expected.conf",
    "content": "[[inputs.filecount]]\ndirectories = [\"/var/cache/apt\", \"/tmp\"]\nname = \"*\"\nrecursive = true\nregular_only = true\nfollow_symlinks = false\nsize = \"0B\"\nmtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory_duplicate/telegraf.conf",
    "content": "# Count files in a directory\n[[inputs.filecount]]\n  ## Directories to gather stats about.\n  ## This accept standard unit glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". ie:\n  ##   /var/log/**    -> recursively find all directories in /var/log and count files in each directories\n  ##   /var/log/*/*   -> find all directories with a parent dir in /var/log and count files in each directories\n  ##   /var/log       -> count all files in /var/log and all of its subdirectories\n  directories = [\"/var/cache/apt\", \"/tmp\"]\n  directory = \"/tmp\"\n\n  ## Only count files that match the name pattern. Defaults to \"*\".\n  name = \"*\"\n\n  ## Count files in subdirectories. Defaults to true.\n  recursive = true\n\n  ## Only count regular files. Defaults to true.\n  regular_only = true\n\n  ## Follow all symlinks while walking the directory tree. Defaults to false.\n  follow_symlinks = false\n\n  ## Only count files that are at least this size. If size is\n  ## a negative number, only count files that are smaller than the\n  ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...\n  ## Without quotes and units, interpreted as size in bytes.\n  size = \"0B\"\n\n  ## Only count files that have not been touched for at least this\n  ## duration. If mtime is negative, only count files that have been\n  ## touched in this duration. Defaults to \"0s\".\n  mtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory_existing/expected.conf",
    "content": "[[inputs.filecount]]\ndirectories = [\"/var/cache/apt\", \"/tmp\", \"/opt/foo\"]\nname = \"*\"\nrecursive = true\nregular_only = true\nfollow_symlinks = false\nsize = \"0B\"\nmtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_filecount/testcases/deprecated_directory_existing/telegraf.conf",
    "content": "# Count files in a directory\n[[inputs.filecount]]\n  ## Directories to gather stats about.\n  ## This accept standard unit glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". ie:\n  ##   /var/log/**    -> recursively find all directories in /var/log and count files in each directories\n  ##   /var/log/*/*   -> find all directories with a parent dir in /var/log and count files in each directories\n  ##   /var/log       -> count all files in /var/log and all of its subdirectories\n  directories = [\"/var/cache/apt\", \"/tmp\"]\n  directory = \"/opt/foo\"\n\n  ## Only count files that match the name pattern. Defaults to \"*\".\n  name = \"*\"\n\n  ## Count files in subdirectories. Defaults to true.\n  recursive = true\n\n  ## Only count regular files. Defaults to true.\n  regular_only = true\n\n  ## Follow all symlinks while walking the directory tree. Defaults to false.\n  follow_symlinks = false\n\n  ## Only count files that are at least this size. If size is\n  ## a negative number, only count files that are smaller than the\n  ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...\n  ## Without quotes and units, interpreted as size in bytes.\n  size = \"0B\"\n\n  ## Only count files that have not been touched for at least this\n  ## duration. If mtime is negative, only count files that have been\n  ## touched in this duration. Defaults to \"0s\".\n  mtime = \"0s\"\n"
  },
  {
    "path": "migrations/inputs_gnmi/migration.go",
    "content": "package inputs_gnmi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif raw, found := plugin[\"guess_path_tag\"]; found {\n\t\tapplied = true\n\n\t\tif v, ok := raw.(bool); ok && v {\n\t\t\tplugin[\"path_guessing_strategy\"] = \"common path\"\n\t\t}\n\n\t\t// Remove the ignored setting\n\t\tdelete(plugin, \"guess_path_tag\")\n\t}\n\n\tif rawOldEnableTLS, found := plugin[\"enable_tls\"]; found {\n\t\t// Convert the options to the actual type\n\t\toldEnableTLS, ok := rawOldEnableTLS.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'enable_tls'\", rawOldEnableTLS)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are\n\t\t// conflicting.\n\t\tif rawNewTLSEnable, found := plugin[\"tls_enable\"]; found {\n\t\t\tif newTLSEnable, ok := rawNewTLSEnable.(bool); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'tls_enable'\", rawNewTLSEnable)\n\t\t\t} else if oldEnableTLS != newTLSEnable {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'enable_tls' and 'tls_enable'\")\n\t\t\t}\n\t\t}\n\t\tapplied = true\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"tls_enable\"] = oldEnableTLS\n\t\tdelete(plugin, \"enable_tls\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"gnmi\")\n\tcfg.Add(\"inputs\", \"gnmi\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.gnmi\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_gnmi/migration_test.go",
    "content": "package inputs_gnmi_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_gnmi\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/gnmi\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &gnmi.GNMI{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestEnableTLSConflict(t *testing.T) {\n\tcfg := []byte(`\n\t\t[[inputs.gnmi]]\n\t\taddresses = [\"10.49.234.114:57777\"]\n\t\tusername = \"cisco\"\n\t\tpassword = \"cisco\"\n\t\tenable_tls = true\n\t\ttls_enable = false\n\t\t[[inputs.gnmi.subscription]]\n\t\t\tname = \"ifcounters\"\n\t\t\torigin = \"openconfig-interfaces\"\n\t\t\tpath = \"/interfaces/interface/state/counters\"\n\t\t\tsubscription_mode = \"sample\"\n\t\t\tsample_interval = \"10s\"\n\t`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'enable_tls' and 'tls_enable'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_enable_tls/expected.conf",
    "content": "[[inputs.gnmi]]\naddresses = [\"10.49.234.114:57777\"]\npassword = \"cisco\"\npath_guessing_strategy = \"common path\"\nusername = \"cisco\"\ntls_enable = true\n[[inputs.gnmi.subscription]]\nname = \"ifcounters\"\norigin = \"openconfig-interfaces\"\npath = \"/interfaces/interface/state/counters\"\nsubscription_mode = \"sample\"\nsample_interval = \"10s\"\n"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_enable_tls/telegraf.conf",
    "content": "# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## If enabled, the common-path of all elements in the update is used.\n  path_guessing_strategy = \"common path\"\n\n  ## enable client-side TLS and define CA to authenticate the device\n  enable_tls = true\n\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## define client-side TLS certificate & key to authenticate to the device\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_guess_path/expected.conf",
    "content": "[[inputs.gnmi]]\naddresses = [\"10.49.234.114:57777\"]\npassword = \"cisco\"\npath_guessing_strategy = \"common path\"\nusername = \"cisco\"\n[[inputs.gnmi.subscription]]\nname = \"ifcounters\"\norigin = \"openconfig-interfaces\"\npath = \"/interfaces/interface/state/counters\"\nsubscription_mode = \"sample\"\nsample_interval = \"10s\"\n"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_guess_path/telegraf.conf",
    "content": "# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## If enabled, the common-path of all elements in the update is used.\n  guess_path_tag = true\n\n  ## enable client-side TLS and define CA to authenticate the device\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## define client-side TLS certificate & key to authenticate to the device\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_guess_path_false/expected.conf",
    "content": "[[inputs.gnmi]]\naddresses = [\"10.49.234.114:57777\"]\npassword = \"cisco\"\nusername = \"cisco\"\n[[inputs.gnmi.subscription]]\nname = \"ifcounters\"\norigin = \"openconfig-interfaces\"\npath = \"/interfaces/interface/state/counters\"\nsubscription_mode = \"sample\"\nsample_interval = \"10s\"\n"
  },
  {
    "path": "migrations/inputs_gnmi/testcases/deprecated_guess_path_false/telegraf.conf",
    "content": "# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## If enabled, the common-path of all elements in the update is used.\n  guess_path_tag = false\n\n  ## enable client-side TLS and define CA to authenticate the device\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## define client-side TLS certificate & key to authenticate to the device\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]"
  },
  {
    "path": "migrations/inputs_http/migration.go",
    "content": "package inputs_http\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldBearerToken, found := plugin[\"bearer_token\"]; found {\n\t\t// Convert the options to the actual type\n\t\toldBearerToken, ok := rawOldBearerToken.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'bearer_token'\", rawOldBearerToken)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are\n\t\t// conflicting.\n\t\tif rawNewTokenFile, found := plugin[\"token_file\"]; found {\n\t\t\tif newTokenFile, ok := rawNewTokenFile.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'token_file'\", rawNewTokenFile)\n\t\t\t} else if oldBearerToken != newTokenFile {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'bearer_token' and 'token_file'\")\n\t\t\t}\n\t\t}\n\t\tapplied = true\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"token_file\"] = oldBearerToken\n\t\tdelete(plugin, \"bearer_token\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"http\")\n\tcfg.Add(\"inputs\", \"http\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.http\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_http/migration_test.go",
    "content": "package inputs_http_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_http\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/http\"      // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/influx\" // register parser\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &http.HTTP{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestBearerToken(t *testing.T) {\n\tcfg := []byte(`\n\t\t[[inputs.http]]\n\t\turls = [\n\t\t\t\"http://localhost/metrics\",\n\t\t\t\"http+unix:///run/user/420/podman/podman.sock:/d/v4.0.0/libpod/pods/json\"\n\t\t]\n\t\ttoken_file = \"/path/to/file\"\n\t\tbearer_token = \"/path/to/another/file\"\n  \t`)\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'bearer_token' and 'token_file'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_http/testcases/deprecated_bearer_token/expected.conf",
    "content": "[[inputs.http]]\n  urls = [\"http://localhost/metrics\"]\n  token_file = \"/path/to/file\"\n"
  },
  {
    "path": "migrations/inputs_http/testcases/deprecated_bearer_token/telegraf.conf",
    "content": "# Read formatted metrics from one or more HTTP endpoints\n[[inputs.http]]\n  ## One or more URLs from which to read formatted metrics.\n  urls = [\"http://localhost/metrics\"]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP entity-body to send with POST/PUT requests.\n  # body = \"\"\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## Optional Bearer token settings to use for the API calls.\n  ## Use either the token itself or the token file if you need a token.\n  # token = \"eyJhbGc...Qssw5c\"\n  # token_file = \"/path/to/file\"\n  bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## HTTP Proxy support\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## List of success status codes\n  # success_status_codes = [200]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http/testcases/deprecated_bearer_token_existing/expected.conf",
    "content": "[[inputs.http]]\n  urls = [\"http://localhost/metrics\"]\n  token_file = \"/path/to/another/file\"\n"
  },
  {
    "path": "migrations/inputs_http/testcases/deprecated_bearer_token_existing/telegraf.conf",
    "content": "# Read formatted metrics from one or more HTTP endpoints\n[[inputs.http]]\n  ## One or more URLs from which to read formatted metrics.\n  urls = [\"http://localhost/metrics\"]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP entity-body to send with POST/PUT requests.\n  # body = \"\"\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## Optional Bearer token settings to use for the API calls.\n  ## Use either the token itself or the token file if you need a token.\n  # token = \"eyJhbGc...Qssw5c\"\n  token_file = \"/path/to/another/file\"\n  bearer_token = \"/path/to/another/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## HTTP Proxy support\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## List of success status codes\n  # success_status_codes = [200]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener/migration.go",
    "content": "package inputs_http_listener\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate http_listener to influxdb_listener\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old plugin configuration\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create the new plugin configuration with the same settings\n\t// but under the \"influxdb_listener\" plugin name instead of \"http_listener\"\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"influxdb_listener\")\n\tcfg.Add(\"inputs\", \"influxdb_listener\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\tmessage := \"migrated from deprecated 'http_listener' to 'influxdb_listener'\"\n\treturn output, message, err\n}\n\n// Register the migration function for the deprecated plugin\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.http_listener\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_http_listener/migration_test.go",
    "content": "package inputs_http_listener_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_http_listener\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/influxdb_listener\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\t// Test that configs without the deprecated plugin remain unchanged\n\tplugin := &influxdb_listener.InfluxDBListener{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Replace influxdb_listener with http_listener to test the reverse case\n\t// (configs that already use influxdb_listener should not be affected)\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n) // No migrations applied\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_http_listener/testcases/deprecated_alias/expected.conf",
    "content": "# Accept metrics over InfluxDB 1.x HTTP API\n[[inputs.influxdb_listener]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8186\"\n\n  ## maximum duration before timing out read of the request\n  read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  max_body_size = 0\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional tag name used to store the database name.\n  ## If the write has a database in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  ## If you have a tag that is the same as the one specified below, and supply a database,\n  ## the tag will be overwritten with the database supplied.\n  # database_tag = \"\"\n\n  ## If set the retention policy specified in the write query will be added as\n  ## the value of this tag name.\n  # retention_policy_tag = \"\"\n\n  ## Optional username and password to accept for HTTP basic authentication\n  ## or authentication token.\n  ## You probably want to make sure you have TLS configured above for this.\n  ## Use these options for the authentication token in the form\n  ##   Authentication: Token <basic_username>:<basic_password>\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional JWT token authentication for HTTP requests\n  ## Please see the documentation at\n  ##   https://docs.influxdata.com/influxdb/v1.8/administration/authentication_and_authorization/#authenticate-using-jwt-tokens\n  ## for further details.\n  ## Please note: Token authentication and basic authentication cannot be used\n  ##              at the same time.\n  # token_shared_secret = \"\"\n  # token_username = \"\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n"
  },
  {
    "path": "migrations/inputs_http_listener/testcases/deprecated_alias/telegraf.conf",
    "content": "# Accept metrics over InfluxDB 1.x HTTP API\n[[inputs.http_listener]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8186\"\n\n  ## maximum duration before timing out read of the request\n  read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  max_body_size = 0\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional tag name used to store the database name.\n  ## If the write has a database in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  ## If you have a tag that is the same as the one specified below, and supply a database,\n  ## the tag will be overwritten with the database supplied.\n  # database_tag = \"\"\n\n  ## If set the retention policy specified in the write query will be added as\n  ## the value of this tag name.\n  # retention_policy_tag = \"\"\n\n  ## Optional username and password to accept for HTTP basic authentication\n  ## or authentication token.\n  ## You probably want to make sure you have TLS configured above for this.\n  ## Use these options for the authentication token in the form\n  ##   Authentication: Token <basic_username>:<basic_password>\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional JWT token authentication for HTTP requests\n  ## Please see the documentation at\n  ##   https://docs.influxdata.com/influxdb/v1.8/administration/authentication_and_authorization/#authenticate-using-jwt-tokens\n  ## for further details.\n  ## Please note: Token authentication and basic authentication cannot be used\n  ##              at the same time.\n  # token_shared_secret = \"\"\n  # token_username = \"\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/migration.go",
    "content": "package inputs_http_listener_v2\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\tif rawOldPath, found := plugin[\"path\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldPath, ok := rawOldPath.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'path'\", rawOldPath)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar paths []string\n\t\tif rawNewPaths, found := plugin[\"paths\"]; found {\n\t\t\tvar err error\n\t\t\tpaths, err = migrations.AsStringSlice(rawNewPaths)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'paths' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(paths, oldPath) {\n\t\t\tpaths = append(paths, oldPath)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"path\")\n\t\tplugin[\"paths\"] = paths\n\t}\n\n\tif rawOldPort, found := plugin[\"port\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldPort, ok := rawOldPort.(int64)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'port'\", rawOldPort)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are\n\t\t// conflicting.\n\t\tvar address string\n\t\tif rawNewServiceAddress, found := plugin[\"service_address\"]; found {\n\t\t\tnewServiceAddress, ok := rawNewServiceAddress.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'service_address'\", rawNewServiceAddress)\n\t\t\t}\n\t\t\taddress = newServiceAddress\n\t\t}\n\n\t\t// Check if the port of the service-address matches\n\t\tu, err := url.Parse(address)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"parsing 'service_address' failed: %w\", err)\n\t\t}\n\n\t\tif u.Scheme == \"\" {\n\t\t\tu.Scheme = \"tcp\"\n\t\t}\n\n\t\tif u.Port() != \"\" {\n\t\t\tnewPort, err := strconv.ParseInt(u.Port(), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"converting port of 'service_address' failed: %w\", err)\n\t\t\t}\n\t\t\tif newPort != oldPort {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'port' and port of 'service_address'\")\n\t\t\t}\n\t\t} else {\n\t\t\tu.Host = fmt.Sprintf(\"%s:%d\", u.Host, oldPort)\n\t\t\taddress = u.String()\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"port\")\n\t\tplugin[\"service_address\"] = address\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"http_listener_v2\")\n\tcfg.Add(\"inputs\", \"http_listener_v2\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.http_listener_v2\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/migration_test.go",
    "content": "package inputs_http_listener_v2_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_http_listener_v2\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/http_listener_v2\"      // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/influx\"             // register parser\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &http_listener_v2.HTTPListenerV2{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestPortConflict(t *testing.T) {\n\tcfg := []byte(`\n\t\t[[inputs.http_listener_v2]]\n\t\tservice_address = \"http://192.168.0.1:8080\"\n\t\tport = 443\n\t`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'port' and port of 'service_address'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path/expected.conf",
    "content": "[[inputs.http_listener_v2]]\nservice_address = \"tcp://:8080\"\npaths = [\"/telegraf\"]\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path/telegraf.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n  path = \"/telegraf\"\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path_duplicate/expected.conf",
    "content": "[[inputs.http_listener_v2]]\nservice_address = \"tcp://:8080\"\npaths = [\"/telegraf\", \"/somewhere\"]\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path_duplicate/telegraf.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  paths = [\"/telegraf\", \"/somewhere\"]\n  path = \"/somewhere\"\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path_existing/expected.conf",
    "content": "[[inputs.http_listener_v2]]\nservice_address = \"tcp://:8080\"\npaths = [\"/telegraf\", \"/somewhere\"]\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_path_existing/telegraf.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  paths = [\"/telegraf\"]\n  path = \"/somewhere\"\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_port/expected.conf",
    "content": "[[inputs.http_listener_v2]]\nservice_address = \"tcp://:443\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_port/telegraf.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  # service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n  port = 443\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_port_existing/expected.conf",
    "content": "[[inputs.http_listener_v2]]\nservice_address = \"http://192.168.0.1:8080\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_listener_v2/testcases/deprecated_port_existing/telegraf.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"http://192.168.0.1:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n  port = 8080\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_http_response/migration.go",
    "content": "package inputs_http_response\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldAddress, found := plugin[\"address\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldAddress, ok := rawOldAddress.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'address'\", rawOldAddress)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar urls []string\n\t\tif rawNewURLs, found := plugin[\"urls\"]; found {\n\t\t\tvar err error\n\t\t\turls, err = migrations.AsStringSlice(rawNewURLs)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'directories' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(urls, oldAddress) {\n\t\t\turls = append(urls, oldAddress)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"urls\"] = urls\n\t\tdelete(plugin, \"address\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"http_response\")\n\tcfg.Add(\"inputs\", \"http_response\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.http_response\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_http_response/migration_test.go",
    "content": "package inputs_http_response_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_http_response\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/http_response\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &http_response.HTTPResponse{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address/expected.conf",
    "content": "[[inputs.http_response]]\nurls = [\"https://myserver:443\"]\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address/telegraf.conf",
    "content": "# HTTP/HTTPS request given an address a method and a timeout\n[[inputs.http_response]]\n  ## List of urls to query.\n  # urls = [\"http://localhost\"]\n  address = \"https://myserver:443\"\n\n  ## Set http_proxy.\n  ## Telegraf uses the system wide proxy settings if it's is not set.\n  # http_proxy = \"http://localhost:8888\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## HTTP Request Method\n  # method = \"GET\"\n\n  ## Whether to follow redirects from the server (defaults to false)\n  # follow_redirects = false\n\n  ## Optional file with Bearer token\n  ## file content is added as an Authorization header\n  # bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional HTTP Request Body\n  # body = '''\n  # {'fake':'data'}\n  # '''\n\n  ## Optional HTTP Request Body Form\n  ## Key value pairs to encode and set at URL form. Can be used with the POST\n  ## method + application/x-www-form-urlencoded content type to replicate the\n  ## POSTFORM method.\n  # body_form = { \"key\": \"value\" }\n\n  ## Optional name of the field that will contain the body of the response.\n  ## By default it is set to an empty String indicating that the body's\n  ## content won't be added\n  # response_body_field = ''\n\n  ## Maximum allowed HTTP response body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  ## If the response body size exceeds this limit a \"body_read_error\" will\n  ## be raised.\n  # response_body_max_size = \"32MiB\"\n\n  ## Optional substring or regex match in body of the response (case sensitive)\n  # response_string_match = \"\\\"service_status\\\": \\\"up\\\"\"\n  # response_string_match = \"ok\"\n  # response_string_match = \"\\\".*_status\\\".?:.?\\\"up\\\"\"\n\n  ## Expected response status code.\n  ## The status code of the response is compared to this value. If they match,\n  ## the field \"response_status_code_match\" will be 1, otherwise it will be 0.\n  ## If the expected status code is 0, the check is disabled and the field\n  ## won't be added.\n  # response_status_code = 0\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"\"\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## HTTP Request Headers (all values must be strings)\n  # [inputs.http_response.headers]\n  #   Host = \"github.com\"\n\n  ## Optional setting to map response http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will\n  ## be added. If multiple instances of the http header are present, only the\n  ## first value will be used.\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Interface to use when dialing an address\n  # interface = \"eth0\"\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address_duplicate/expected.conf",
    "content": "[[inputs.http_response]]\nurls = [\"http://localhost\", \"https://myserver:443\"]\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address_duplicate/telegraf.conf",
    "content": "# HTTP/HTTPS request given an address a method and a timeout\n[[inputs.http_response]]\n  ## List of urls to query.\n  urls = [\"http://localhost\", \"https://myserver:443\"]\n  address = \"https://myserver:443\"\n\n  ## Set http_proxy.\n  ## Telegraf uses the system wide proxy settings if it's is not set.\n  # http_proxy = \"http://localhost:8888\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## HTTP Request Method\n  # method = \"GET\"\n\n  ## Whether to follow redirects from the server (defaults to false)\n  # follow_redirects = false\n\n  ## Optional file with Bearer token\n  ## file content is added as an Authorization header\n  # bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional HTTP Request Body\n  # body = '''\n  # {'fake':'data'}\n  # '''\n\n  ## Optional HTTP Request Body Form\n  ## Key value pairs to encode and set at URL form. Can be used with the POST\n  ## method + application/x-www-form-urlencoded content type to replicate the\n  ## POSTFORM method.\n  # body_form = { \"key\": \"value\" }\n\n  ## Optional name of the field that will contain the body of the response.\n  ## By default it is set to an empty String indicating that the body's\n  ## content won't be added\n  # response_body_field = ''\n\n  ## Maximum allowed HTTP response body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  ## If the response body size exceeds this limit a \"body_read_error\" will\n  ## be raised.\n  # response_body_max_size = \"32MiB\"\n\n  ## Optional substring or regex match in body of the response (case sensitive)\n  # response_string_match = \"\\\"service_status\\\": \\\"up\\\"\"\n  # response_string_match = \"ok\"\n  # response_string_match = \"\\\".*_status\\\".?:.?\\\"up\\\"\"\n\n  ## Expected response status code.\n  ## The status code of the response is compared to this value. If they match,\n  ## the field \"response_status_code_match\" will be 1, otherwise it will be 0.\n  ## If the expected status code is 0, the check is disabled and the field\n  ## won't be added.\n  # response_status_code = 0\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"\"\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## HTTP Request Headers (all values must be strings)\n  # [inputs.http_response.headers]\n  #   Host = \"github.com\"\n\n  ## Optional setting to map response http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will\n  ## be added. If multiple instances of the http header are present, only the\n  ## first value will be used.\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Interface to use when dialing an address\n  # interface = \"eth0\"\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address_existing/expected.conf",
    "content": "[[inputs.http_response]]\nurls = [\"http://localhost\", \"https://myserver:443\"]\n"
  },
  {
    "path": "migrations/inputs_http_response/testcases/deprecated_address_existing/telegraf.conf",
    "content": "# HTTP/HTTPS request given an address a method and a timeout\n[[inputs.http_response]]\n  ## List of urls to query.\n  urls = [\"http://localhost\"]\n  address = \"https://myserver:443\"\n\n  ## Set http_proxy.\n  ## Telegraf uses the system wide proxy settings if it's is not set.\n  # http_proxy = \"http://localhost:8888\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## HTTP Request Method\n  # method = \"GET\"\n\n  ## Whether to follow redirects from the server (defaults to false)\n  # follow_redirects = false\n\n  ## Optional file with Bearer token\n  ## file content is added as an Authorization header\n  # bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional HTTP Request Body\n  # body = '''\n  # {'fake':'data'}\n  # '''\n\n  ## Optional HTTP Request Body Form\n  ## Key value pairs to encode and set at URL form. Can be used with the POST\n  ## method + application/x-www-form-urlencoded content type to replicate the\n  ## POSTFORM method.\n  # body_form = { \"key\": \"value\" }\n\n  ## Optional name of the field that will contain the body of the response.\n  ## By default it is set to an empty String indicating that the body's\n  ## content won't be added\n  # response_body_field = ''\n\n  ## Maximum allowed HTTP response body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  ## If the response body size exceeds this limit a \"body_read_error\" will\n  ## be raised.\n  # response_body_max_size = \"32MiB\"\n\n  ## Optional substring or regex match in body of the response (case sensitive)\n  # response_string_match = \"\\\"service_status\\\": \\\"up\\\"\"\n  # response_string_match = \"ok\"\n  # response_string_match = \"\\\".*_status\\\".?:.?\\\"up\\\"\"\n\n  ## Expected response status code.\n  ## The status code of the response is compared to this value. If they match,\n  ## the field \"response_status_code_match\" will be 1, otherwise it will be 0.\n  ## If the expected status code is 0, the check is disabled and the field\n  ## won't be added.\n  # response_status_code = 0\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"\"\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## HTTP Request Headers (all values must be strings)\n  # [inputs.http_response.headers]\n  #   Host = \"github.com\"\n\n  ## Optional setting to map response http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will\n  ## be added. If multiple instances of the http header are present, only the\n  ## first value will be used.\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Interface to use when dialing an address\n  # interface = \"eth0\"\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/migration.go",
    "content": "package inputs_httpjson\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t\"github.com/influxdata/telegraf/migrations/common\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\nconst msg = `\n    Replacement 'inputs.http' will not report the 'response_time' field and the\n    'server' tag is replaced by the 'url' tag. Please adapt your queries!\n`\n\n// Define \"old\" data structure\ntype httpJSON struct {\n\tName            string `toml:\"name\"`\n\tServers         []string\n\tMethod          string\n\tTagKeys         []string\n\tResponseTimeout string\n\tParameters      map[string]string\n\tHeaders         map[string]string\n\ttls.ClientConfig\n\tcommon.InputOptions\n}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old httpJSON\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Fill common options\n\tplugin := make(map[string]interface{})\n\told.InputOptions.Migrate()\n\tgeneral, err := toml.Marshal(old.InputOptions)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"marshalling general options failed: %w\", err)\n\t}\n\tif err := toml.Unmarshal(general, &plugin); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"re-unmarshalling general options failed: %w\", err)\n\t}\n\n\t// Use a map for the new plugin and fill in the data\n\tplugin[\"urls\"] = old.Servers\n\tif old.Name != \"\" {\n\t\tif x, found := plugin[\"name_override\"]; found && x != old.Name {\n\t\t\treturn nil, \"\", fmt.Errorf(\"conflicting 'name' (%s) and 'name_override' (%s) setting\", old.Name, old.NameOverride)\n\t\t}\n\t\tplugin[\"name_override\"] = old.Name\n\t}\n\tif _, found := plugin[\"name_override\"]; !found {\n\t\tplugin[\"name_override\"] = \"httpjson\"\n\t}\n\tif old.Method != \"\" && old.Method != \"GET\" {\n\t\tplugin[\"method\"] = old.Method\n\t}\n\tif len(old.TagKeys) > 0 {\n\t\tplugin[\"tag_keys\"] = old.TagKeys\n\t}\n\tif old.ResponseTimeout != \"\" {\n\t\tplugin[\"timeout\"] = old.ResponseTimeout\n\t}\n\tif len(old.Headers) > 0 {\n\t\tplugin[\"headers\"] = old.Headers\n\t}\n\tif len(old.Parameters) > 0 {\n\t\turls := make([]string, 0, len(old.Servers))\n\t\tfor _, s := range old.Servers {\n\t\t\tu, err := url.Parse(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"parsing server %q failed: %w\", s, err)\n\t\t\t}\n\t\t\tq := u.Query()\n\t\t\tfor k, v := range old.Parameters {\n\t\t\t\tq.Add(k, v)\n\t\t\t}\n\t\t\tu.RawQuery = q.Encode()\n\t\t\turls = append(urls, u.String())\n\t\t}\n\t\tplugin[\"urls\"] = urls\n\t}\n\n\t// Convert TLS parameters\n\tif old.TLSCA != \"\" {\n\t\tplugin[\"tls_ca\"] = old.TLSCA\n\t}\n\tif old.TLSCert != \"\" {\n\t\tplugin[\"tls_cert\"] = old.TLSCert\n\t}\n\n\tif old.TLSKey != \"\" {\n\t\tplugin[\"tls_key\"] = old.TLSKey\n\t}\n\tif old.TLSKeyPwd != \"\" {\n\t\tplugin[\"tls_key_pwd\"] = old.TLSKeyPwd\n\t}\n\tif old.TLSMinVersion != \"\" {\n\t\tplugin[\"tls_min_version\"] = old.TLSMinVersion\n\t}\n\tif old.InsecureSkipVerify {\n\t\tplugin[\"insecure_skip_verify\"] = true\n\t}\n\tif old.ServerName != \"\" {\n\t\tplugin[\"tls_server_name\"] = old.ServerName\n\t}\n\tif old.RenegotiationMethod != \"\" {\n\t\tplugin[\"tls_renegotiation_method\"] = old.RenegotiationMethod\n\t}\n\tif old.Enable != nil {\n\t\tplugin[\"tls_enable\"] = *old.Enable\n\t}\n\n\t// Parser settings\n\tplugin[\"data_format\"] = \"json\"\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"http\")\n\tcfg.Add(\"inputs\", \"http\", plugin)\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.httpjson\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_httpjson/migration_test.go",
    "content": "package inputs_httpjson_test\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_httpjson\"   // register migration\n\thttpplugin \"github.com/influxdata/telegraf/plugins/inputs/http\" // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"          // register parsers\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatchf(t, expectedIDs, actualIDs, \"generated config: %s\", string(output))\n\t\t})\n\t}\n}\n\nfunc TestParsing(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFile := filepath.Join(testcasePath, \"expected.conf\")\n\t\tinputFile := filepath.Join(testcasePath, \"input.json\")\n\t\texpectedFile := filepath.Join(testcasePath, \"output.influx\")\n\n\t\t// Skip the testcase if it doesn't provide data\n\t\tif _, err := os.Stat(inputFile); errors.Is(err, os.ErrNotExist) {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFile))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\t\t\tplugin := cfg.Inputs[0].Input.(*httpplugin.HTTP)\n\n\t\t\t// Read the input data\n\t\t\tinput, err := os.ReadFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Read the expected output\n\t\t\texpected, err := testutil.ParseMetricsFromFile(expectedFile, parser)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, expected)\n\n\t\t\t// Start the test-server\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif r.URL.Path == \"/stats\" {\n\t\t\t\t\tif _, err = w.Write(input); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Point the plugin to the test-server and start the game\n\t\t\taddr := server.URL + \"/stats\"\n\t\t\tplugin.URLs = []string{addr}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\t// Prepare metrics for comparison\n\t\t\tfor i := range expected {\n\t\t\t\texpected[i].AddTag(\"url\", addr)\n\t\t\t}\n\t\t\traw := acc.GetTelegrafMetrics()\n\t\t\tactual := make([]telegraf.Metric, 0, len(raw))\n\t\t\tfor _, m := range raw {\n\t\t\t\tactual = append(actual, cfg.Inputs[0].MakeMetric(m))\n\t\t\t}\n\n\t\t\t// Compare\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t\ttestutil.IgnoreTags(\"host\"),\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/array/expected.conf",
    "content": "[[inputs.http]]\nname_override = \"httpjson\"\nurls = [\"http://localhost:9999/stats/\"]\ndata_format = \"json\"\ntag_keys = [\"service\"]\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/array/input.json",
    "content": "[\n    {\n        \"service\": \"service01\",\n        \"a\": 0.5,\n        \"b\": {\n            \"c\": \"some text\",\n            \"d\": 0.1,\n            \"e\": 5\n        }\n    },\n    {\n        \"service\": \"service02\",\n        \"a\": 0.6,\n        \"b\": {\n            \"c\": \"some text\",\n            \"d\": 0.2,\n            \"e\": 6\n        }\n    }\n]"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/array/output.influx",
    "content": "httpjson,url=http://localhost:9999/stats/,service=service01 a=0.5,b_d=0.1,b_e=5\nhttpjson,url=http://localhost:9999/stats/,service=service02 a=0.6,b_d=0.2,b_e=6"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/array/telegraf.conf",
    "content": "[[inputs.httpjson]]\n  servers = [\"http://localhost:9999/stats/\"]\n  tag_keys = [\"service\"]"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/filters/expected.conf",
    "content": "[[inputs.http]]\ndata_format = \"json\"\nfieldinclude = [\"a\"]\nname_override = \"httpjson\"\nurls = [\"http://localhost:9999/stats/\"]\n\n[inputs.http.tags]\nfoo = \"bar\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/filters/telegraf.conf",
    "content": "[[inputs.httpjson]]\n  servers = [\"http://localhost:9999/stats/\"]\n  fieldpass = [\"a\"]\n\n  [inputs.httpjson.tags]\n    foo = \"bar\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/headers/expected.conf",
    "content": "[[inputs.http]]\nname_override = \"httpjson\"\nmethod = \"POST\"\nurls = [\"http://localhost:9999/stats\"]\ndata_format = \"json\"\n[inputs.http.headers]\nX-Auth-Token = \"my-xauth-token\"\napiVersion = \"v1\""
  },
  {
    "path": "migrations/inputs_httpjson/testcases/headers/telegraf.conf",
    "content": "[[inputs.httpjson]]\n  servers = [\"http://localhost:9999/stats\"]\n  method = \"POST\"\n  [inputs.httpjson.headers]\n    X-Auth-Token = \"my-xauth-token\"\n    apiVersion = \"v1\""
  },
  {
    "path": "migrations/inputs_httpjson/testcases/params/expected.conf",
    "content": "[[inputs.http]]\nname_override = \"httpjson\"\nurls = [\"http://localhost:9999/stats?event_type=cpu_spike&threshold=0.75\"]\ndata_format = \"json\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/params/telegraf.conf",
    "content": "[[inputs.httpjson]]\n  servers = [\"http://localhost:9999/stats\"]\n  # HTTP Request Parameters (all values must be strings).  For \"GET\" requests, data\n  # will be included in the query.  For \"POST\" requests, data will be included\n  # in the request body as \"x-www-form-urlencoded\".\n  [inputs.httpjson.parameters]\n    event_type = \"cpu_spike\"\n    threshold = \"0.75\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/single/expected.conf",
    "content": "[[inputs.http]]\nname_override = \"webserver_stats\"\ntimeout = \"5s\"\nurls = [\"http://localhost:9999/stats/\", \"http://localhost:9998/stats/\"]\ndata_format = \"json\"\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/single/input.json",
    "content": "{\n    \"a\": 0.5,\n    \"b\": {\n        \"c\": \"some text\",\n        \"d\": 0.1,\n        \"e\": 5\n    },\n    \"service\": \"service01\"\n}"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/single/output.influx",
    "content": "webserver_stats,url=http://localhost:9999/stats/ b_d=0.1,a=0.5,b_e=5\n"
  },
  {
    "path": "migrations/inputs_httpjson/testcases/single/telegraf.conf",
    "content": "# Read flattened metrics from one or more JSON HTTP endpoints\n[[inputs.httpjson]]\n  ## NOTE This plugin only reads numerical measurements, strings and booleans\n  ## will be ignored.\n\n  ## Name for the service being polled.  Will be appended to the name of the\n  ## measurement e.g. \"httpjson_webserver_stats\".\n  ##\n  ## Deprecated (1.3.0): Use name_override, name_suffix, name_prefix instead.\n  name = \"webserver_stats\"\n\n  ## URL of each server in the service's cluster\n  servers = [\n    \"http://localhost:9999/stats/\",\n    \"http://localhost:9998/stats/\",\n  ]\n  ## Set response_timeout (default 5 seconds)\n  response_timeout = \"5s\"\n\n  ## HTTP method to use: GET or POST (case-sensitive)\n  method = \"GET\"\n\n  ## Tags to extract from top-level of JSON server response.\n  # tag_keys = [\n  #   \"my_tag_1\",\n  #   \"my_tag_2\"\n  # ]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP Request Parameters (all values must be strings).  For \"GET\" requests, data\n  ## will be included in the query.  For \"POST\" requests, data will be included\n  ## in the request body as \"x-www-form-urlencoded\".\n  # [inputs.httpjson.parameters]\n  #   event_type = \"cpu_spike\"\n  #   threshold = \"0.75\"\n\n  ## HTTP Request Headers (all values must be strings).\n  # [inputs.httpjson.headers]\n  #   X-Auth-Token = \"my-xauth-token\"\n  #   apiVersion = \"v1\""
  },
  {
    "path": "migrations/inputs_icinga2/migration.go",
    "content": "package inputs_icinga2\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldObjectType, found := plugin[\"object_type\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldObjectTypes, ok := rawOldObjectType.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'object_type'\", rawOldObjectType)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar objects []string\n\t\tif rawNewObjects, found := plugin[\"objects\"]; found {\n\t\t\tvar err error\n\t\t\tobjects, err = migrations.AsStringSlice(rawNewObjects)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'objects' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(objects, oldObjectTypes) {\n\t\t\tobjects = append(objects, oldObjectTypes)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"objects\"] = objects\n\t\tdelete(plugin, \"object_type\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"icinga2\")\n\tcfg.Add(\"inputs\", \"icinga2\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.icinga2\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_icinga2/migration_test.go",
    "content": "package inputs_icinga2_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_icinga2\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/icinga2\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &icinga2.Icinga2{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type/expected.conf",
    "content": "[[inputs.icinga2]]\nobjects = [\"hosts\"]\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type/telegraf.conf",
    "content": "# Gather Icinga2 status\n[[inputs.icinga2]]\n  ## Required Icinga2 server address\n  # server = \"https://localhost:5665\"\n\n  ## Collected Icinga2 objects (\"services\", \"hosts\")\n  ## Specify at least one object to collect from /v1/objects endpoint.\n  # objects = [\"services\"]\n  object_type = \"hosts\"\n\n  ## Collect metrics from /v1/status endpoint\n  ## Choose from:\n  ##     \"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"\n  # status = []\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type_duplicate/expected.conf",
    "content": "[[inputs.icinga2]]\nobjects = [\"services\", \"hosts\"]\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type_duplicate/telegraf.conf",
    "content": "# Gather Icinga2 status\n[[inputs.icinga2]]\n  ## Required Icinga2 server address\n  # server = \"https://localhost:5665\"\n\n  ## Collected Icinga2 objects (\"services\", \"hosts\")\n  ## Specify at least one object to collect from /v1/objects endpoint.\n  objects = [\"services\", \"hosts\"]\n  object_type = \"hosts\"\n\n  ## Collect metrics from /v1/status endpoint\n  ## Choose from:\n  ##     \"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"\n  # status = []\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type_existing/expected.conf",
    "content": "[[inputs.icinga2]]\nobjects = [\"services\", \"hosts\"]\n"
  },
  {
    "path": "migrations/inputs_icinga2/testcases/deprecated_object_type_existing/telegraf.conf",
    "content": "# Gather Icinga2 status\n[[inputs.icinga2]]\n  ## Required Icinga2 server address\n  # server = \"https://localhost:5665\"\n\n  ## Collected Icinga2 objects (\"services\", \"hosts\")\n  ## Specify at least one object to collect from /v1/objects endpoint.\n  objects = [\"services\"]\n  object_type = \"hosts\"\n\n  ## Collect metrics from /v1/status endpoint\n  ## Choose from:\n  ##     \"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"\n  # status = []\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "migrations/inputs_influxdb_listener/migration.go",
    "content": "package inputs_influxdb_listener\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated InfluxDB Listener options\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated options and migrate them\n\tvar applied bool\n\n\t// Remove the deprecated max_line_size option (parser now handles unlimited length)\n\tif _, found := plugin[\"max_line_size\"]; found {\n\t\tapplied = true\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"max_line_size\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"influxdb_listener\")\n\tcfg.Add(\"inputs\", \"influxdb_listener\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.influxdb_listener\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_influxdb_listener/migration_test.go",
    "content": "package inputs_influxdb_listener_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_influxdb_listener\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/influxdb_listener\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &influxdb_listener.InfluxDBListener{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_influxdb_listener/testcases/deprecated_max_line_size/expected.conf",
    "content": "[[inputs.influxdb_listener]]\n  service_address = \":8186\"\n  read_timeout = \"10s\"\n  write_timeout = \"10s\"\n  max_body_size = \"32MiB\"\n  basic_username = \"telegraf\"\n  basic_password = \"secret\"\n  database_tag = \"database\"\n  parser_type = \"internal\""
  },
  {
    "path": "migrations/inputs_influxdb_listener/testcases/deprecated_max_line_size/telegraf.conf",
    "content": "[[inputs.influxdb_listener]]\n  service_address = \":8186\"\n  read_timeout = \"10s\"\n  write_timeout = \"10s\"\n  max_body_size = \"32MiB\"\n  max_line_size = \"64KiB\"\n  basic_username = \"telegraf\"\n  basic_password = \"secret\"\n  database_tag = \"database\"\n  parser_type = \"internal\""
  },
  {
    "path": "migrations/inputs_internet_speed/migration.go",
    "content": "package inputs_internet_speed\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldEnableFileDownload, found := plugin[\"enable_file_download\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldEnableFileDownload, ok := rawOldEnableFileDownload.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'enable_file_download'\", rawOldEnableFileDownload)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tif rawNewMemorySavingMode, found := plugin[\"memory_saving_mode\"]; found {\n\t\t\tif newMemorySavingMode, ok := rawNewMemorySavingMode.(bool); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'memory_saving_mode'\", rawNewMemorySavingMode)\n\t\t\t} else if newMemorySavingMode != oldEnableFileDownload {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'enable_file_download' and 'memory_saving_mode'\")\n\t\t\t}\n\t\t} else if oldEnableFileDownload {\n\t\t\tplugin[\"memory_saving_mode\"] = true\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"enable_file_download\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"internet_speed\")\n\tcfg.Add(\"inputs\", \"internet_speed\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.internet_speed\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_internet_speed/migration_test.go",
    "content": "package inputs_internet_speed_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_internet_speed\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/internet_speed\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &internet_speed.InternetSpeed{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestEnableFileDownloadConflict(t *testing.T) {\n\tcfg := []byte(`\n\t\t[[inputs.internet_speed]]\n\t\tmemory_saving_mode = true\n\t\tenable_file_download = false\n\t`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'enable_file_download' and 'memory_saving_mode'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download/expected.conf",
    "content": "[[inputs.internet_speed]]\nmemory_saving_mode = true\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download/telegraf.conf",
    "content": "# Monitors internet speed using speedtest.net service\n[[inputs.internet_speed]]\n  ## This plugin downloads many MB of data each time it is run. As such\n  ## consider setting a higher interval for this plugin to reduce the\n  ## demand on your internet connection.\n  # interval = \"60m\"\n\n  ## Enable to reduce memory usage\n  # memory_saving_mode = false\n  enable_file_download = true\n\n  ## Caches the closest server location\n  # cache = false\n\n  ## Number of concurrent connections\n  ## By default or set to zero, the number of CPU cores is used. Use this to\n  ## reduce the impact on system performance or to increase the connections on\n  ## faster connections to ensure the fastest speed.\n  # connections = 0\n\n  ## Test mode\n  ## By default, a single sever is used for testing. This may work for most,\n  ## however, setting to \"multi\" will reach out to multiple servers in an\n  ## attempt to get closer to ideal internet speeds.\n  ## And \"multi\" will use all available servers to calculate average packet loss.\n  # test_mode = \"single\"\n\n  ## Server ID exclude filter\n  ## Allows the user to exclude or include specific server IDs received by\n  ## speedtest-go. Values in the exclude option will be skipped over. Values in\n  ## the include option are the only options that will be picked from.\n  ##\n  ## See the list of servers speedtest-go will return at:\n  ##     https://www.speedtest.net/api/js/servers?engine=js&limit=10\n  ##\n  # server_id_exclude = []\n  # server_id_include = []\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download_existing/expected.conf",
    "content": "[[inputs.internet_speed]]\nmemory_saving_mode = true\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download_existing/telegraf.conf",
    "content": "# Monitors internet speed using speedtest.net service\n[[inputs.internet_speed]]\n  ## This plugin downloads many MB of data each time it is run. As such\n  ## consider setting a higher interval for this plugin to reduce the\n  ## demand on your internet connection.\n  # interval = \"60m\"\n\n  ## Enable to reduce memory usage\n  memory_saving_mode = true\n  enable_file_download = true\n\n  ## Caches the closest server location\n  # cache = false\n\n  ## Number of concurrent connections\n  ## By default or set to zero, the number of CPU cores is used. Use this to\n  ## reduce the impact on system performance or to increase the connections on\n  ## faster connections to ensure the fastest speed.\n  # connections = 0\n\n  ## Test mode\n  ## By default, a single sever is used for testing. This may work for most,\n  ## however, setting to \"multi\" will reach out to multiple servers in an\n  ## attempt to get closer to ideal internet speeds.\n  ## And \"multi\" will use all available servers to calculate average packet loss.\n  # test_mode = \"single\"\n\n  ## Server ID exclude filter\n  ## Allows the user to exclude or include specific server IDs received by\n  ## speedtest-go. Values in the exclude option will be skipped over. Values in\n  ## the include option are the only options that will be picked from.\n  ##\n  ## See the list of servers speedtest-go will return at:\n  ##     https://www.speedtest.net/api/js/servers?engine=js&limit=10\n  ##\n  # server_id_exclude = []\n  # server_id_include = []\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download_false/expected.conf",
    "content": "[[inputs.internet_speed]]\n"
  },
  {
    "path": "migrations/inputs_internet_speed/testcases/deprecated_enable_file_download_false/telegraf.conf",
    "content": "# Monitors internet speed using speedtest.net service\n[[inputs.internet_speed]]\n  ## This plugin downloads many MB of data each time it is run. As such\n  ## consider setting a higher interval for this plugin to reduce the\n  ## demand on your internet connection.\n  # interval = \"60m\"\n\n  ## Enable to reduce memory usage\n  # memory_saving_mode = false\n  enable_file_download = false\n\n  ## Caches the closest server location\n  # cache = false\n\n  ## Number of concurrent connections\n  ## By default or set to zero, the number of CPU cores is used. Use this to\n  ## reduce the impact on system performance or to increase the connections on\n  ## faster connections to ensure the fastest speed.\n  # connections = 0\n\n  ## Test mode\n  ## By default, a single sever is used for testing. This may work for most,\n  ## however, setting to \"multi\" will reach out to multiple servers in an\n  ## attempt to get closer to ideal internet speeds.\n  ## And \"multi\" will use all available servers to calculate average packet loss.\n  # test_mode = \"single\"\n\n  ## Server ID exclude filter\n  ## Allows the user to exclude or include specific server IDs received by\n  ## speedtest-go. Values in the exclude option will be skipped over. Values in\n  ## the include option are the only options that will be picked from.\n  ##\n  ## See the list of servers speedtest-go will return at:\n  ##     https://www.speedtest.net/api/js/servers?engine=js&limit=10\n  ##\n  # server_id_exclude = []\n  # server_id_include = []\n"
  },
  {
    "path": "migrations/inputs_io/migration.go",
    "content": "package inputs_io\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Load the plugin config and directly encode it again as we do not want to\n\t// modify anything beyond the name.\n\n\t// Decode the old data structure\n\tvar plugin interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"diskio\")\n\tcfg.Add(\"inputs\", \"diskio\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.io\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_io/migration_test.go",
    "content": "package inputs_io_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_io\"  // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/diskio\" // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_io/testcases/empty/expected.conf",
    "content": "# Read metrics about disk IO by device\n[[inputs.diskio]]\n  ## By default, telegraf will gather stats for all devices including\n  ## disk partitions.\n  ## Setting devices will restrict the stats to the specified devices.\n  ## NOTE: Globbing expressions (e.g. asterix) are not supported for\n  ##       disk synonyms like '/dev/disk/by-id'.\n  # devices = [\"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  ## Uncomment the following line if you need disk serial numbers.\n  # skip_serial_number = false\n  #\n  ## On systems which support it, device metadata can be added in the form of\n  ## tags.\n  ## Currently only Linux is supported via udev properties. You can view\n  ## available properties for a device by running:\n  ## 'udevadm info -q property -n /dev/sda'\n  ## Note: Most, but not all, udev properties can be accessed this way. Properties\n  ## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.\n  # device_tags = [\"ID_FS_TYPE\", \"ID_FS_USAGE\"]\n  #\n  ## Using the same metadata source as device_tags, you can also customize the\n  ## name of the device via templates.\n  ## The 'name_templates' parameter is a list of templates to try and apply to\n  ## the device. The template may contain variables in the form of '$PROPERTY' or\n  ## '${PROPERTY}'. The first template which does not contain any variables not\n  ## present for the device is used as the device name tag.\n  ## The typical use case is for LVM volumes, to get the VG/LV name instead of\n  ## the near-meaningless DM-0 name.\n  # name_templates = [\"$ID_FS_LABEL\",\"$DM_VG_NAME/$DM_LV_NAME\"]"
  },
  {
    "path": "migrations/inputs_io/testcases/empty/telegraf.conf",
    "content": "# Read metrics about disk IO by device\n[[inputs.io]]\n  ## By default, telegraf will gather stats for all devices including\n  ## disk partitions.\n  ## Setting devices will restrict the stats to the specified devices.\n  ## NOTE: Globbing expressions (e.g. asterix) are not supported for\n  ##       disk synonyms like '/dev/disk/by-id'.\n  # devices = [\"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  ## Uncomment the following line if you need disk serial numbers.\n  # skip_serial_number = false\n  #\n  ## On systems which support it, device metadata can be added in the form of\n  ## tags.\n  ## Currently only Linux is supported via udev properties. You can view\n  ## available properties for a device by running:\n  ## 'udevadm info -q property -n /dev/sda'\n  ## Note: Most, but not all, udev properties can be accessed this way. Properties\n  ## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.\n  # device_tags = [\"ID_FS_TYPE\", \"ID_FS_USAGE\"]\n  #\n  ## Using the same metadata source as device_tags, you can also customize the\n  ## name of the device via templates.\n  ## The 'name_templates' parameter is a list of templates to try and apply to\n  ## the device. The template may contain variables in the form of '$PROPERTY' or\n  ## '${PROPERTY}'. The first template which does not contain any variables not\n  ## present for the device is used as the device name tag.\n  ## The typical use case is for LVM volumes, to get the VG/LV name instead of\n  ## the near-meaningless DM-0 name.\n  # name_templates = [\"$ID_FS_LABEL\",\"$DM_VG_NAME/$DM_LV_NAME\"]"
  },
  {
    "path": "migrations/inputs_io/testcases/full/expected.conf",
    "content": "# Read metrics about disk IO by device\n[[inputs.diskio]]\n  name_override = \"foo\"\n  devices = [\"nvme0n1\", \"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  skip_serial_number = true\n  device_tags = [\"ID_FS_TYPE\"]\n  name_templates = [\"$ID_FS_LABEL\", \"$DM_VG_NAME/$DM_LV_NAME\", \"test\"]\n\n  [[inputs.diskio.tags]]\n    should = \"work\""
  },
  {
    "path": "migrations/inputs_io/testcases/full/telegraf.conf",
    "content": "# Read metrics about disk IO by device\n[[inputs.io]]\n  name_override = \"foo\"\n\n  # By default, telegraf will gather stats for all devices including\n  # disk partitions.\n  # Setting devices will restrict the stats to the specified devices.\n  # NOTE: Globbing expressions (e.g. asterix) are not supported for\n  #       disk synonyms like '/dev/disk/by-id'.\n  devices = [\"nvme0n1\", \"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  # Uncomment the following line if you need disk serial numbers.\n  skip_serial_number = true\n\n  # On systems which support it, device metadata can be added in the form of\n  # tags.\n  # Currently only Linux is supported via udev properties. You can view\n  # available properties for a device by running:\n  # 'udevadm info -q property -n /dev/sda'\n  # Note: Most, but not all, udev properties can be accessed this way. Properties\n  # that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.\n  device_tags = [\"ID_FS_TYPE\"]\n\n  # Using the same metadata source as device_tags, you can also customize the\n  # name of the device via templates.\n  # The 'name_templates' parameter is a list of templates to try and apply to\n  # the device. The template may contain variables in the form of '$PROPERTY' or\n  # '${PROPERTY}'. The first template which does not contain any variables not\n  # present for the device is used as the device name tag.\n  # The typical use case is for LVM volumes, to get the VG/LV name instead of\n  # the near-meaningless DM-0 name.\n  name_templates = [\"$ID_FS_LABEL\",\"$DM_VG_NAME/$DM_LV_NAME\", \"test\"]\n\n  [[inputs.io.tags]]\n    should = \"work\""
  },
  {
    "path": "migrations/inputs_jolokia/README.md",
    "content": ""
  },
  {
    "path": "migrations/inputs_jolokia/migration.go",
    "content": "package inputs_jolokia\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t\"github.com/influxdata/telegraf/migrations/common\"\n)\n\n// Define \"old\" data structure\ntype jolokia struct {\n\tContext               string   `toml:\"context\"`\n\tMode                  string   `toml:\"mode\"`\n\tServers               []server `toml:\"servers\"`\n\tMetrics               []metric `toml:\"metrics\"`\n\tProxy                 server   `toml:\"proxy\"`\n\tDelimiter             string   `toml:\"delimiter\"`\n\tResponseHeaderTimeout string   `toml:\"response_header_timeout\"`\n\tClientTimeout         string   `toml:\"client_timeout\"`\n\tcommon.InputOptions\n}\ntype server struct {\n\tName     string `toml:\"name\"`\n\tHost     string `toml:\"host\"`\n\tUsername string `toml:\"username\"`\n\tPassword string `toml:\"password\"`\n\tPort     string `toml:\"port\"`\n}\n\ntype metric struct {\n\tName      string `toml:\"name\"`\n\tMbean     string `toml:\"mbean\"`\n\tAttribute string `toml:\"attribute\"`\n\tPath      string `toml:\"path\"`\n}\n\n// Define \"new\" data structure(s)\ntype jolokiaAgent struct {\n\tURLs                  []string       `toml:\"urls\"`\n\tUsername              string         `toml:\"username,omitempty\"`\n\tPassword              string         `toml:\"password,omitempty\"`\n\tMetrics               []metricConfig `toml:\"metric\"`\n\tDefaultFieldSeparator string         `toml:\"default_field_separator\"`\n\tResponseTimeout       string         `toml:\"response_timeout,omitempty\"`\n\n\t// Common options\n\tInterval         string            `toml:\"interval,omitempty\"`\n\tPrecision        string            `toml:\"precision,omitempty\"`\n\tCollectionJitter string            `toml:\"collection_jitter,omitempty\"`\n\tCollectionOffset string            `toml:\"collection_offset,omitempty\"`\n\tNamePrefix       string            `toml:\"name_prefix,omitempty\"`\n\tNameSuffix       string            `toml:\"name_suffix,omitempty\"`\n\tNameOverride     string            `toml:\"name_override,omitempty\"`\n\tAlias            string            `toml:\"alias,omitempty\"`\n\tTags             map[string]string `toml:\"tags,omitempty\"`\n\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\ntype jolokiaProxy struct {\n\tURL                   string         `toml:\"url\"`\n\tUsername              string         `toml:\"username,omitempty\"`\n\tPassword              string         `toml:\"password,omitempty\"`\n\tDefaultFieldSeparator string         `toml:\"default_field_separator\"`\n\tResponseTimeout       string         `toml:\"response_timeout,omitempty\"`\n\tTargets               []targetConfig `toml:\"target\"`\n\tMetrics               []metricConfig `toml:\"metric\"`\n\n\t// Common options\n\tInterval         string            `toml:\"interval,omitempty\"`\n\tPrecision        string            `toml:\"precision,omitempty\"`\n\tCollectionJitter string            `toml:\"collection_jitter,omitempty\"`\n\tCollectionOffset string            `toml:\"collection_offset,omitempty\"`\n\tNamePrefix       string            `toml:\"name_prefix,omitempty\"`\n\tNameSuffix       string            `toml:\"name_suffix,omitempty\"`\n\tNameOverride     string            `toml:\"name_override,omitempty\"`\n\tAlias            string            `toml:\"alias,omitempty\"`\n\tTags             map[string]string `toml:\"tags,omitempty\"`\n\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\ntype targetConfig struct {\n\tURL      string `toml:\"url\"`\n\tUsername string `toml:\"username,omitempty\"`\n\tPassword string `toml:\"password,omitempty\"`\n}\n\ntype metricConfig struct {\n\tName        string   `toml:\"name\"`\n\tMbean       string   `toml:\"mbean\"`\n\tPaths       []string `toml:\"paths\"`\n\tFieldPrefix *string  `toml:\"field_prefix,omitempty\"`\n\tTagKeys     []string `toml:\"tag_keys,omitempty\"`\n}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\tvar messages []string\n\n\t// Decode the old data structure\n\tvar old jolokia\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create new-style metrics according to the old config\n\tmetrics := make([]metricConfig, 0, len(old.Metrics))\n\tfor _, oldm := range old.Metrics {\n\t\tmbean := strings.SplitN(oldm.Mbean, \"/\", 2)\n\t\tm := metricConfig{\n\t\t\tName:  oldm.Name,\n\t\t\tMbean: mbean[0],\n\t\t}\n\n\t\t// Construct the new path from the old attribute/path setting\n\t\tcontained := len(mbean) <= 1\n\t\tif oldm.Attribute != \"\" {\n\t\t\tattributes := strings.Split(oldm.Attribute, \",\")\n\t\t\tfor _, a := range attributes {\n\t\t\t\tif !contained && a == mbean[1] {\n\t\t\t\t\tcontained = true\n\t\t\t\t}\n\t\t\t\tif oldm.Path != \"\" {\n\t\t\t\t\tm.Paths = append(m.Paths, a+\"/\"+oldm.Path)\n\t\t\t\t} else {\n\t\t\t\t\tm.Paths = append(m.Paths, a)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if oldm.Path != \"\" {\n\t\t\tm.Paths = append(m.Paths, oldm.Path)\n\t\t}\n\t\tif !contained {\n\t\t\tm.Paths = append(m.Paths, mbean[1])\n\t\t}\n\t\tmetrics = append(metrics, m)\n\t}\n\n\t// Setup the timeout if any\n\tvar timeout string\n\tif old.ClientTimeout != \"\" && old.ResponseHeaderTimeout != \"\" {\n\t\tmsg := \"both 'client_timeout' and 'response_header_timeout' are specified using the former\"\n\t\tmessages = append(messages, msg)\n\t\ttimeout = old.ClientTimeout\n\t} else if old.ClientTimeout != \"\" {\n\t\ttimeout = old.ClientTimeout\n\t} else if old.ResponseHeaderTimeout != \"\" {\n\t\ttimeout = old.ResponseHeaderTimeout\n\t}\n\n\t// Create the corresponding plugin configurations\n\tvar newcfg interface{}\n\tif old.Mode == \"proxy\" {\n\t\t// Create a new proxy setup\n\t\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"jolokia2_proxy\")\n\n\t\t// Create a new agent setup\n\t\tfor _, server := range old.Servers {\n\t\t\tproxy := \"http://\" + old.Proxy.Host + \":\" + old.Proxy.Port + strings.TrimRight(old.Context, \"/\")\n\t\t\tplugin := jolokiaProxy{\n\t\t\t\tURL:      proxy,\n\t\t\t\tUsername: old.Proxy.Username,\n\t\t\t\tPassword: old.Proxy.Password,\n\t\t\t\tTargets: []targetConfig{{\n\t\t\t\t\tURL:      fmt.Sprintf(\"service:jmx:rmi:///jndi/rmi://%s:%s/jmxrmi\", server.Host, server.Port),\n\t\t\t\t\tUsername: server.Username,\n\t\t\t\t\tPassword: server.Password,\n\t\t\t\t}},\n\t\t\t\tMetrics:               metrics,\n\t\t\t\tDefaultFieldSeparator: \"_\",\n\t\t\t\tResponseTimeout:       timeout,\n\t\t\t\tNameOverride:          \"jolokia\",\n\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\"jolokia_name\": server.Name,\n\t\t\t\t\t\"jolokia_port\": server.Port,\n\t\t\t\t\t\"jolokia_host\": server.Host,\n\t\t\t\t},\n\t\t\t}\n\t\t\tplugin.fillCommon(old.InputOptions)\n\t\t\tcfg.Add(\"inputs\", \"jolokia2_proxy\", plugin)\n\t\t}\n\t\tnewcfg = cfg\n\t} else {\n\t\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"jolokia2_agent\")\n\n\t\t// Create a new agent setup\n\t\tfor _, server := range old.Servers {\n\t\t\tendpoint := \"http://\" + server.Host + \":\" + server.Port + strings.TrimRight(old.Context, \"/\")\n\t\t\tplugin := jolokiaAgent{\n\t\t\t\tURLs:                  []string{endpoint},\n\t\t\t\tUsername:              server.Username,\n\t\t\t\tPassword:              server.Password,\n\t\t\t\tMetrics:               metrics,\n\t\t\t\tDefaultFieldSeparator: \"_\",\n\t\t\t\tResponseTimeout:       timeout,\n\t\t\t\tNameOverride:          \"jolokia\",\n\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\"jolokia_name\": server.Name,\n\t\t\t\t\t\"jolokia_port\": server.Port,\n\t\t\t\t\t\"jolokia_host\": server.Host,\n\t\t\t\t},\n\t\t\t}\n\t\t\tplugin.fillCommon(old.InputOptions)\n\t\t\tcfg.Add(\"inputs\", \"jolokia2_agent\", plugin)\n\t\t}\n\t\tnewcfg = cfg\n\t}\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(newcfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, strings.Join(messages, \";\"), nil\n}\n\nfunc (j *jolokiaAgent) fillCommon(o common.InputOptions) {\n\to.Migrate()\n\n\tj.Interval = o.Interval\n\tj.Precision = o.Precision\n\tj.CollectionJitter = o.CollectionJitter\n\tj.CollectionOffset = o.CollectionOffset\n\tj.NamePrefix = o.NamePrefix\n\tj.NameSuffix = o.NameSuffix\n\tif o.NameOverride != \"\" {\n\t\tj.NameOverride = o.NameOverride\n\t}\n\tj.Alias = o.Alias\n\tif len(o.Tags) > 0 {\n\t\tif j.Tags == nil {\n\t\t\tj.Tags = make(map[string]string, len(o.Tags))\n\t\t}\n\t\tfor k, v := range o.Tags {\n\t\t\tj.Tags[k] = v\n\t\t}\n\t}\n\n\tif len(o.NamePass) > 0 {\n\t\tj.NamePass = append(j.NamePass, o.NamePass...)\n\t}\n\tif len(o.NameDrop) > 0 {\n\t\tj.NameDrop = append(j.NameDrop, o.NameDrop...)\n\t}\n\tif len(o.FieldInclude) > 0 {\n\t\tj.FieldInclude = append(j.FieldInclude, o.FieldInclude...)\n\t}\n\tif len(o.FieldExclude) > 0 {\n\t\tj.FieldExclude = append(j.FieldExclude, o.FieldExclude...)\n\t}\n\tif len(o.TagPassFilters) > 0 {\n\t\tj.TagPassFilters = make(map[string][]string, len(o.TagPassFilters))\n\t\tfor k, v := range o.TagPassFilters {\n\t\t\tj.TagPassFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagDropFilters) > 0 {\n\t\tj.TagDropFilters = make(map[string][]string, len(o.TagDropFilters))\n\t\tfor k, v := range o.TagDropFilters {\n\t\t\tj.TagDropFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagExclude) > 0 {\n\t\tj.TagExclude = append(j.TagExclude, o.TagExclude...)\n\t}\n\tif len(o.TagInclude) > 0 {\n\t\tj.TagInclude = append(j.TagInclude, o.TagInclude...)\n\t}\n\tj.MetricPass = o.MetricPass\n}\n\nfunc (j *jolokiaProxy) fillCommon(o common.InputOptions) {\n\to.Migrate()\n\n\tj.Interval = o.Interval\n\tj.Precision = o.Precision\n\tj.CollectionJitter = o.CollectionJitter\n\tj.CollectionOffset = o.CollectionOffset\n\tj.NamePrefix = o.NamePrefix\n\tj.NameSuffix = o.NameSuffix\n\tif o.NameOverride != \"\" {\n\t\tj.NameOverride = o.NameOverride\n\t}\n\tj.Alias = o.Alias\n\tif len(o.Tags) > 0 {\n\t\tif j.Tags == nil {\n\t\t\tj.Tags = make(map[string]string, len(o.Tags))\n\t\t}\n\t\tfor k, v := range o.Tags {\n\t\t\tj.Tags[k] = v\n\t\t}\n\t}\n\n\tif len(o.NamePass) > 0 {\n\t\tj.NamePass = append(j.NamePass, o.NamePass...)\n\t}\n\tif len(o.NameDrop) > 0 {\n\t\tj.NameDrop = append(j.NameDrop, o.NameDrop...)\n\t}\n\tif len(o.FieldInclude) > 0 {\n\t\tj.FieldInclude = append(j.FieldInclude, o.FieldInclude...)\n\t}\n\tif len(o.FieldExclude) > 0 {\n\t\tj.FieldExclude = append(j.FieldExclude, o.FieldExclude...)\n\t}\n\tif len(o.TagPassFilters) > 0 {\n\t\tj.TagPassFilters = make(map[string][]string, len(o.TagPassFilters))\n\t\tfor k, v := range o.TagPassFilters {\n\t\t\tj.TagPassFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagDropFilters) > 0 {\n\t\tj.TagDropFilters = make(map[string][]string, len(o.TagDropFilters))\n\t\tfor k, v := range o.TagDropFilters {\n\t\t\tj.TagDropFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagExclude) > 0 {\n\t\tj.TagExclude = append(j.TagExclude, o.TagExclude...)\n\t}\n\tif len(o.TagInclude) > 0 {\n\t\tj.TagInclude = append(j.TagInclude, o.TagInclude...)\n\t}\n\tj.MetricPass = o.MetricPass\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.jolokia\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_jolokia/migration_test.go",
    "content": "package inputs_jolokia_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_jolokia\"     // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/jolokia2_agent\" // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/jolokia2_proxy\" // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatchf(t, expectedIDs, actualIDs, \"got\\n%s\", string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_default/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://127.0.0.1:8080/jolokia\"]\ndefault_field_separator = \"_\"\nname_override = \"jolokia\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"heap_memory_usage\"\nmbean = \"java.lang:type=Memory\"\npaths = [\"HeapMemoryUsage\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"thread_count\"\nmbean = \"java.lang:type=Threading\"\npaths = [\"TotalStartedThreadCount\", \"ThreadCount\", \"DaemonThreadCount\", \"PeakThreadCount\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"class_count\"\nmbean = \"java.lang:type=ClassLoading\"\npaths = [\"LoadedClassCount\", \"UnloadedClassCount\", \"TotalLoadedClassCount\"]\n\n[inputs.jolokia2_agent.tags]\njolokia_host = \"127.0.0.1\"\njolokia_name = \"as-server-01\"\njolokia_port = \"8080\"\n"
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_default/telegraf.conf",
    "content": "# Read JMX metrics through Jolokia\n[[inputs.jolokia]]\n  ## This is the context root used to compose the jolokia url\n  ## NOTE that Jolokia requires a trailing slash at the end of the context root\n  context = \"/jolokia/\"\n\n  ## This specifies the mode used\n  # mode = \"proxy\"\n  #\n  ## When in proxy mode this section is used to specify further\n  ## proxy address configurations.\n  ## Remember to change host address to fit your environment.\n  # [inputs.jolokia.proxy]\n  #   host = \"127.0.0.1\"\n  #   port = \"8080\"\n\n  ## Optional http timeouts\n  ##\n  ## response_header_timeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  # response_header_timeout = \"3s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  # client_timeout = \"4s\"\n\n  ## List of servers exposing jolokia read service\n  [[inputs.jolokia.servers]]\n    name = \"as-server-01\"\n    host = \"127.0.0.1\"\n    port = \"8080\"\n    # username = \"myuser\"\n    # password = \"mypassword\"\n\n  ## List of metrics collected on above servers\n  ## Each metric consists in a name, a jmx path and either\n  ## a pass or drop slice attribute.\n  ## This collect all heap memory usage metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"heap_memory_usage\"\n    mbean  = \"java.lang:type=Memory\"\n    attribute = \"HeapMemoryUsage\"\n\n  ## This collect thread counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"thread_count\"\n    mbean  = \"java.lang:type=Threading\"\n    attribute = \"TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount\"\n\n  ## This collect number of class loaded/unloaded counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"class_count\"\n    mbean  = \"java.lang:type=ClassLoading\"\n    attribute = \"LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount\""
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_more_complex/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://127.0.0.1:8080/jolokia\"]\nusername = \"myuser\"\npassword = \"mypassword\"\nresponse_timeout = \"4s\"\ndefault_field_separator = \"_\"\nname_override = \"jolokia\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"heap_memory_usage\"\nmbean = \"java.lang:type=Memory\"\npaths = [\"HeapMemoryUsage\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"thread_count\"\nmbean = \"java.lang:type=Threading\"\npaths = [\"TotalStartedThreadCount\", \"ThreadCount\", \"DaemonThreadCount\", \"PeakThreadCount\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"class_count\"\nmbean = \"java.lang:type=ClassLoading\"\npaths = [\"LoadedClassCount\", \"UnloadedClassCount\", \"TotalLoadedClassCount\"]\n\n[inputs.jolokia2_agent.tags]\njolokia_host = \"127.0.0.1\"\njolokia_name = \"as-server-01\"\njolokia_port = \"8080\"\n"
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_more_complex/telegraf.conf",
    "content": "# Read JMX metrics through Jolokia\n[[inputs.jolokia]]\n  ## This is the context root used to compose the jolokia url\n  ## NOTE that Jolokia requires a trailing slash at the end of the context root\n  context = \"/jolokia/\"\n\n  ## This specifies the mode used\n  # mode = \"proxy\"\n  #\n  ## When in proxy mode this section is used to specify further\n  ## proxy address configurations.\n  ## Remember to change host address to fit your environment.\n  # [inputs.jolokia.proxy]\n  #   host = \"127.0.0.1\"\n  #   port = \"8080\"\n\n  ## Optional http timeouts\n  ##\n  ## response_header_timeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  # response_header_timeout = \"3s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  client_timeout = \"4s\"\n\n  ## List of servers exposing jolokia read service\n  [[inputs.jolokia.servers]]\n    name = \"as-server-01\"\n    host = \"127.0.0.1\"\n    port = \"8080\"\n    username = \"myuser\"\n    password = \"mypassword\"\n\n  ## List of metrics collected on above servers\n  ## Each metric consists in a name, a jmx path and either\n  ## a pass or drop slice attribute.\n  ## This collect all heap memory usage metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"heap_memory_usage\"\n    mbean  = \"java.lang:type=Memory\"\n    attribute = \"HeapMemoryUsage\"\n\n  ## This collect thread counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"thread_count\"\n    mbean  = \"java.lang:type=Threading\"\n    attribute = \"TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount\"\n\n  ## This collect number of class loaded/unloaded counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"class_count\"\n    mbean  = \"java.lang:type=ClassLoading\"\n    attribute = \"LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount\""
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_response_timeout/expected.conf",
    "content": "[[inputs.jolokia2_agent]]\nurls = [\"http://127.0.0.1:8080/jolokia\"]\nresponse_timeout = \"10s\"\ndefault_field_separator = \"_\"\nname_override = \"jolokia\"\n\n[[inputs.jolokia2_agent.metric]]\nname = \"heap_memory_usage\"\nmbean = \"java.lang:type=Memory\"\npaths = [\"HeapMemoryUsage\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"thread_count\"\nmbean = \"java.lang:type=Threading\"\npaths = [\"TotalStartedThreadCount\", \"ThreadCount\", \"DaemonThreadCount\", \"PeakThreadCount\"]\n\n[[inputs.jolokia2_agent.metric]]\nname = \"class_count\"\nmbean = \"java.lang:type=ClassLoading\"\npaths = [\"LoadedClassCount\", \"UnloadedClassCount\", \"TotalLoadedClassCount\"]\n\n[inputs.jolokia2_agent.tags]\njolokia_host = \"127.0.0.1\"\njolokia_name = \"as-server-01\"\njolokia_port = \"8080\"\n"
  },
  {
    "path": "migrations/inputs_jolokia/testcases/agent_response_timeout/telegraf.conf",
    "content": "# Read JMX metrics through Jolokia\n[[inputs.jolokia]]\n  ## This is the context root used to compose the jolokia url\n  ## NOTE that Jolokia requires a trailing slash at the end of the context root\n  context = \"/jolokia/\"\n\n  ## This specifies the mode used\n  # mode = \"proxy\"\n  #\n  ## When in proxy mode this section is used to specify further\n  ## proxy address configurations.\n  ## Remember to change host address to fit your environment.\n  # [inputs.jolokia.proxy]\n  #   host = \"127.0.0.1\"\n  #   port = \"8080\"\n\n  ## Optional http timeouts\n  ##\n  ## response_header_timeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  response_header_timeout = \"10s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  # client_timeout = \"4s\"\n\n  ## List of servers exposing jolokia read service\n  [[inputs.jolokia.servers]]\n    name = \"as-server-01\"\n    host = \"127.0.0.1\"\n    port = \"8080\"\n    # username = \"myuser\"\n    # password = \"mypassword\"\n\n  ## List of metrics collected on above servers\n  ## Each metric consists in a name, a jmx path and either\n  ## a pass or drop slice attribute.\n  ## This collect all heap memory usage metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"heap_memory_usage\"\n    mbean  = \"java.lang:type=Memory\"\n    attribute = \"HeapMemoryUsage\"\n\n  ## This collect thread counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"thread_count\"\n    mbean  = \"java.lang:type=Threading\"\n    attribute = \"TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount\"\n\n  ## This collect number of class loaded/unloaded counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"class_count\"\n    mbean  = \"java.lang:type=ClassLoading\"\n    attribute = \"LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount\""
  },
  {
    "path": "migrations/inputs_jolokia/testcases/proxy_default/expected.conf",
    "content": "[[inputs.jolokia2_proxy]]\nurl = \"http://127.0.0.1:8080/jolokia\"\ndefault_field_separator = \"_\"\nname_override = \"jolokia\"\n\n[[inputs.jolokia2_proxy.target]]\nurl = \"service:jmx:rmi:///jndi/rmi://192.168.0.1:8080/jmxrmi\"\n\n[[inputs.jolokia2_proxy.metric]]\nname = \"heap_memory_usage\"\nmbean = \"java.lang:type=Memory\"\npaths = [\"HeapMemoryUsage\"]\n\n[[inputs.jolokia2_proxy.metric]]\nname = \"thread_count\"\nmbean = \"java.lang:type=Threading\"\npaths = [\"TotalStartedThreadCount\", \"ThreadCount\", \"DaemonThreadCount\", \"PeakThreadCount\"]\n\n[[inputs.jolokia2_proxy.metric]]\nname = \"class_count\"\nmbean = \"java.lang:type=ClassLoading\"\npaths = [\"LoadedClassCount\", \"UnloadedClassCount\", \"TotalLoadedClassCount\"]\n\n[inputs.jolokia2_proxy.tags]\njolokia_host = \"192.168.0.1\"\njolokia_name = \"as-server-01\"\njolokia_port = \"8080\"\n"
  },
  {
    "path": "migrations/inputs_jolokia/testcases/proxy_default/telegraf.conf",
    "content": "# Read JMX metrics through Jolokia\n[[inputs.jolokia]]\n  ## This is the context root used to compose the jolokia url\n  ## NOTE that Jolokia requires a trailing slash at the end of the context root\n  context = \"/jolokia/\"\n\n  ## This specifies the mode used\n  mode = \"proxy\"\n\n  ## When in proxy mode this section is used to specify further\n  ## proxy address configurations.\n  ## Remember to change host address to fit your environment.\n  [inputs.jolokia.proxy]\n    host = \"127.0.0.1\"\n    port = \"8080\"\n\n  ## Optional http timeouts\n  ##\n  ## response_header_timeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  # response_header_timeout = \"3s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  # client_timeout = \"4s\"\n\n  ## List of servers exposing jolokia read service\n  [[inputs.jolokia.servers]]\n    name = \"as-server-01\"\n    host = \"192.168.0.1\"\n    port = \"8080\"\n    # username = \"myuser\"\n    # password = \"mypassword\"\n\n  ## List of metrics collected on above servers\n  ## Each metric consists in a name, a jmx path and either\n  ## a pass or drop slice attribute.\n  ## This collect all heap memory usage metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"heap_memory_usage\"\n    mbean  = \"java.lang:type=Memory\"\n    attribute = \"HeapMemoryUsage\"\n\n  ## This collect thread counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"thread_count\"\n    mbean  = \"java.lang:type=Threading\"\n    attribute = \"TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount\"\n\n  ## This collect number of class loaded/unloaded counts metrics.\n  [[inputs.jolokia.metrics]]\n    name = \"class_count\"\n    mbean  = \"java.lang:type=ClassLoading\"\n    attribute = \"LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount\""
  },
  {
    "path": "migrations/inputs_kafka_consumer_legacy/README.md",
    "content": ""
  },
  {
    "path": "migrations/inputs_kafka_consumer_legacy/migration.go",
    "content": "package inputs_kafka_consumer_legacy\n\nimport (\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nconst msg = `\n    This plugin cannot be migrated automatically and requires manual intervention!\n`\n\n// Migration function\nfunc migrate(_ *ast.Table) ([]byte, string, error) {\n\treturn nil, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.kafka_consumer_legacy\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_kafka_consumer_legacy/migration_test.go",
    "content": "package inputs_kafka_consumer_legacy_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_kafka_consumer_legacy\" // register migration\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tinput := []byte(`\n[[inputs.kafka_consumer_legacy]]\n  topics = [\"telegraf\"]\n  zookeeper_peers = [\"localhost:2181\"]\n  zookeeper_chroot = \"\"\n  consumer_group = \"telegraf_metrics_consumers\"\n  offset = \"oldest\"\n  data_format = \"influx\"\n  max_message_len = 65536\n`)\n\n\toutput, n, err := config.ApplyMigrations(input)\n\trequire.NoError(t, err)\n\trequire.Empty(t, strings.TrimSpace(string(output)))\n\trequire.Equal(t, uint64(1), n)\n}\n"
  },
  {
    "path": "migrations/inputs_kube_inventory/migration.go",
    "content": "package inputs_kube_inventory\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated Kube Inventory bearer_token_string option\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated bearer_token_string option\n\tvar applied bool\n\tvar message string\n\n\tif _, found := plugin[\"bearer_token_string\"]; found {\n\t\tapplied = true\n\n\t\t// Only migrate if bearer_token is not already set (don't overwrite existing)\n\t\tif _, found := plugin[\"bearer_token\"]; !found {\n\t\t\tmessage = \"removed deprecated 'bearer_token_string' option; please save the token to a file and use the 'bearer_token' option instead\"\n\t\t}\n\n\t\t// Always remove the deprecated setting\n\t\tdelete(plugin, \"bearer_token_string\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"kube_inventory\")\n\tcfg.Add(\"inputs\", \"kube_inventory\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, message, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.kube_inventory\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_kube_inventory/migration_test.go",
    "content": "package inputs_kube_inventory_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_kube_inventory\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/kube_inventory\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &kube_inventory.KubernetesInventory{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_kube_inventory/testcases/bearer_token_string_only/expected.conf",
    "content": "[[inputs.kube_inventory]]\nnamespace = \"default\"\nresource_exclude = [\"deployments\", \"services\"]\nresponse_timeout = \"5s\"\nurl = \"https://kubernetes.default.svc\""
  },
  {
    "path": "migrations/inputs_kube_inventory/testcases/bearer_token_string_only/telegraf.conf",
    "content": "# Kube Inventory plugin with deprecated bearer_token_string\n[[inputs.kube_inventory]]\n  ## URL for the Kubernetes API\n  url = \"https://kubernetes.default.svc\"\n\n  ## Deprecated bearer_token_string option - should be migrated to bearer_token file\n  bearer_token_string = \"eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1In0...\"\n\n  ## Namespace to use. Set to \"\" to use all namespaces.\n  namespace = \"default\"\n\n  ## Use bearer token for authorization. ('bearer_token' takes priority)\n  ## If both of these are empty, we'll use the default serviceaccount:\n  ## at: /var/run/secrets/kubernetes.io/serviceaccount/token\n  # bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Set response_timeout (default 5 seconds)\n  response_timeout = \"5s\"\n\n  ## Optional Resources to exclude from gathering\n  ## Leave them with blank with try to gather everything available.\n  ## Values can be - \"daemonsets\", \"deployments\", \"endpoints\", \"ingress\",\n  ## \"nodes\", \"persistentvolumes\", \"persistentvolumeclaims\", \"pods\", \"services\",\n  ## \"statefulsets\"\n  resource_exclude = [ \"deployments\", \"services\" ]\n\n  ## Optional Resources to include when gathering\n  ## Overrides resource_exclude when both set.\n  # resource_include = [ \"deployments\", \"nodes\", \"pods\" ]\n\n  ## selectors to include and exclude as tags\n  # selector_include = [\"app\", \"release\"]\n  # selector_exclude = [\"*\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/path/to/cafile\"\n  # tls_cert = \"/path/to/certfile\"\n  # tls_key = \"/path/to/keyfile\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_kube_inventory/testcases/mixed_tokens/expected.conf",
    "content": "[[inputs.kube_inventory]]\nbearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\ninsecure_skip_verify = true\nnamespace = \"monitoring\"\nresource_exclude = [\"secrets\"]\nresource_include = [\"deployments\", \"nodes\", \"pods\", \"services\"]\nresponse_timeout = \"10s\"\nselector_exclude = [\"internal.*\"]\nselector_include = [\"app\", \"version\", \"component\"]\nurl = \"https://k8s-api.example.com:6443\""
  },
  {
    "path": "migrations/inputs_kube_inventory/testcases/mixed_tokens/telegraf.conf",
    "content": "# Kube Inventory plugin with both bearer token options\n[[inputs.kube_inventory]]\n  ## URL for the Kubernetes API\n  url = \"https://k8s-api.example.com:6443\"\n\n  ## User already has bearer_token configured - should be preserved\n  bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Deprecated bearer_token_string - should be removed but not override existing bearer_token\n  bearer_token_string = \"old_deprecated_token_456\"\n\n  ## Namespace to use\n  namespace = \"monitoring\"\n\n  ## Set response_timeout\n  response_timeout = \"10s\"\n\n  ## Optional Resources to exclude from gathering\n  resource_exclude = [ \"secrets\" ]\n\n  ## Optional Resources to include when gathering\n  resource_include = [ \"deployments\", \"nodes\", \"pods\", \"services\" ]\n\n  ## selectors to include and exclude as tags\n  selector_include = [\"app\", \"version\", \"component\"]\n  selector_exclude = [\"internal.*\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/ssl/certs/ca-certificates.crt\"\n  insecure_skip_verify = true"
  },
  {
    "path": "migrations/inputs_kubernetes/migration.go",
    "content": "package inputs_kubernetes\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated Kubernetes bearer_token_string option\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated bearer_token_string option\n\tvar applied bool\n\tvar message string\n\n\tif _, found := plugin[\"bearer_token_string\"]; found {\n\t\tapplied = true\n\n\t\t// Only migrate if bearer_token is not already set (don't overwrite existing)\n\t\tif _, found := plugin[\"bearer_token\"]; !found {\n\t\t\tmessage = \"removed deprecated 'bearer_token_string' option; please save the token to a file and use the 'bearer_token' option instead\"\n\t\t}\n\n\t\t// Always remove the deprecated setting\n\t\tdelete(plugin, \"bearer_token_string\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"kubernetes\")\n\tcfg.Add(\"inputs\", \"kubernetes\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, message, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.kubernetes\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_kubernetes/migration_test.go",
    "content": "package inputs_kubernetes_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_kubernetes\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/kubernetes\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &kubernetes.Kubernetes{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/bearer_token_string_only/expected.conf",
    "content": "# Kubernetes plugin with deprecated bearer_token_string removed\n[[inputs.kubernetes]]\n  ## URL for the kubelet\n  url = \"http://127.0.0.1:10255\"\n\n  ## Deprecated bearer_token_string removed - save token to file and use bearer_token instead\n  ## Example: bearer_token = \"/path/to/token/file\"\n\n  ## Kubernetes Node Metric Name\n  node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags\n  label_include = [\"app\", \"version\", \"env\"]\n  label_exclude = [\"*\"]\n\n  ## Set response_timeout\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/path/to/cafile\"\n  # tls_cert = \"/path/to/certfile\"\n  # tls_key = \"/path/to/keyfile\"\n  ## Use TLS but skip chain & host verification\n  insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/bearer_token_string_only/telegraf.conf",
    "content": "# Kubernetes plugin with deprecated bearer_token_string\n[[inputs.kubernetes]]\n  ## URL for the kubelet\n  url = \"http://127.0.0.1:10255\"\n\n  ## Deprecated bearer_token_string option - should be migrated to bearer_token file\n  bearer_token_string = \"abc_123_secret_token\"\n\n  ## Kubernetes Node Metric Name\n  node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags\n  label_include = [\"app\", \"version\", \"env\"]\n  label_exclude = [\"*\"]\n\n  ## Set response_timeout\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/path/to/cafile\"\n  # tls_cert = \"/path/to/certfile\"\n  # tls_key = \"/path/to/keyfile\"\n  ## Use TLS but skip chain & host verification\n  insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/default_case/expected.conf",
    "content": "# Kubernetes plugin with deprecated bearer_token_string removed\n[[inputs.kubernetes]]\n  ## URL for the kubelet (empty to read from all nodes)\n  # url = \"\"\n\n  ## Deprecated bearer_token_string removed - save token to file and use bearer_token instead\n  ## If no bearer_token is set, default service account token will be used\n\n  ## Kubernetes Node Metric Name\n  # node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags - exclude all by default\n  # label_include = []\n  label_exclude = [\"*\"]\n\n  ## Set response_timeout\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/default_case/telegraf.conf",
    "content": "# Kubernetes plugin with deprecated bearer_token_string and no bearer_token\n[[inputs.kubernetes]]\n  ## URL for the kubelet (empty to read from all nodes)\n  # url = \"\"\n\n  ## Deprecated bearer_token_string option\n  bearer_token_string = \"custom_service_account_token_456\"\n\n  ## Kubernetes Node Metric Name\n  # node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags - exclude all by default\n  # label_include = []\n  label_exclude = [\"*\"]\n\n  ## Set response_timeout\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/mixed_tokens/expected.conf",
    "content": "# Kubernetes plugin with preserved bearer_token\n[[inputs.kubernetes]]\n  ## URL for the kubelet\n  url = \"https://kubernetes.example.com:10250\"\n\n  ## Existing bearer_token preserved (deprecated bearer_token_string was removed)\n  bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Kubernetes Node Metric Name\n  node_metric_name = \"k8s_node\"\n\n  ## Pod labels to be added as tags\n  label_include = [\"app\", \"version\"]\n  label_exclude = [\"internal.*\"]\n\n  ## Set response_timeout\n  response_timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/ssl/certs/ca-certificates.crt\"\n  insecure_skip_verify = true"
  },
  {
    "path": "migrations/inputs_kubernetes/testcases/mixed_tokens/telegraf.conf",
    "content": "# Kubernetes plugin with both bearer token options\n[[inputs.kubernetes]]\n  ## URL for the kubelet\n  url = \"https://kubernetes.example.com:10250\"\n\n  ## User already has bearer_token configured - should be preserved\n  bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Deprecated bearer_token_string - should be removed but not override existing bearer_token\n  bearer_token_string = \"old_deprecated_token_123\"\n\n  ## Kubernetes Node Metric Name\n  node_metric_name = \"k8s_node\"\n\n  ## Pod labels to be added as tags\n  label_include = [\"app\", \"version\"]\n  label_exclude = [\"internal.*\"]\n\n  ## Set response_timeout\n  response_timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/ssl/certs/ca-certificates.crt\"\n  insecure_skip_verify = true"
  },
  {
    "path": "migrations/inputs_logparser/migration.go",
    "content": "package inputs_logparser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old inputs.logparser data structure\n\tvar logparserPlugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &logparserPlugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Initial tail plugin configuration\n\ttailPlugin := make(map[string]interface{})\n\ttailPlugin[\"data_format\"] = \"grok\"\n\n\t// Comments: 'inputs.logparser' -> 'inputs.tail'\n\n\t// 'files' ([]string) -> 'files' ([]string)\n\tif rawFiles, found := logparserPlugin[\"files\"]; found {\n\t\tfiles, err := migrations.AsStringSlice(rawFiles)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", err\n\t\t}\n\t\ttailPlugin[\"files\"] = files\n\t}\n\n\t// 'from_beginning' (bool) -> 'initial_read_offset' (string)\n\t// 'from_beginning: true' -> 'initial_read_offset: \"beginning\"'\n\t// 'from_beginning: false' -> 'initial_read_offset: \"saved-or-end\"'\n\tif rawFromBeginning, found := logparserPlugin[\"from_beginning\"]; found {\n\t\tfromBeginning, ok := rawFromBeginning.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'from_beginning'\", rawFromBeginning)\n\t\t}\n\t\tif fromBeginning {\n\t\t\ttailPlugin[\"initial_read_offset\"] = \"beginning\"\n\t\t} else {\n\t\t\ttailPlugin[\"initial_read_offset\"] = \"saved-or-end\"\n\t\t}\n\t} else {\n\t\t// Default if 'from_beginning' is not set, i.e. false\n\t\ttailPlugin[\"initial_read_offset\"] = \"saved-or-end\"\n\t}\n\n\t// 'watch_method' (string) -> 'watch_method' (string)\n\tif rawWatchMethod, found := logparserPlugin[\"watch_method\"]; found {\n\t\twatchMethod, ok := rawWatchMethod.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'watch_method'\", rawWatchMethod)\n\t\t}\n\t\ttailPlugin[\"watch_method\"] = watchMethod\n\t}\n\n\t// Get the 'grok' configuration\n\tgrok, err := getGrok(logparserPlugin)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tif grok != nil {\n\t\t// 'grok.patterns' ([]string) -> 'grok_patterns' ([]string)\n\t\tif rawPatterns, found := grok[\"patterns\"]; found {\n\t\t\tpatterns, err := migrations.AsStringSlice(rawPatterns)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", err\n\t\t\t}\n\t\t\ttailPlugin[\"grok_patterns\"] = patterns\n\t\t}\n\n\t\t// 'grok.measurement' (string) -> 'name_override' (string)\n\t\tif rawMeasurement, found := grok[\"measurement\"]; found {\n\t\t\tmeasurement, ok := rawMeasurement.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'grok.measurement'\", rawMeasurement)\n\t\t\t}\n\t\t\ttailPlugin[\"name_override\"] = measurement\n\t\t}\n\n\t\t// 'grok.custom_pattern_files' ([]string) -> 'grok_custom_pattern_files' ([]string)\n\t\tif rawCustomPatternFiles, found := grok[\"custom_pattern_files\"]; found {\n\t\t\tcustomPatternFiles, err := migrations.AsStringSlice(rawCustomPatternFiles)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", err\n\t\t\t}\n\t\t\ttailPlugin[\"grok_custom_pattern_files\"] = customPatternFiles\n\t\t}\n\n\t\t// 'grok.custom_patterns' (string) -> 'grok_custom_patterns' (string)\n\t\tif rawCustomPatterns, found := grok[\"custom_patterns\"]; found {\n\t\t\tcustomPatterns, ok := rawCustomPatterns.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'grok.custom_patterns'\", rawCustomPatterns)\n\t\t\t}\n\t\t\ttailPlugin[\"grok_custom_patterns\"] = customPatterns\n\t\t}\n\n\t\t// 'grok.timezone' (string) -> 'grok_timezone' (string)\n\t\tif rawTimezone, found := grok[\"timezone\"]; found {\n\t\t\ttimezone, ok := rawTimezone.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'grok.timezone'\", rawTimezone)\n\t\t\t}\n\t\t\ttailPlugin[\"grok_timezone\"] = timezone\n\t\t}\n\n\t\t// 'grok.unique_timestamp' (string) -> 'grok_unique_timestamp' (string)\n\t\tif rawUniqueTimestamp, found := grok[\"unique_timestamp\"]; found {\n\t\t\tuniqueTimestamp, ok := rawUniqueTimestamp.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'grok.unique_timestamp'\", rawUniqueTimestamp)\n\t\t\t}\n\t\t\ttailPlugin[\"grok_unique_timestamp\"] = uniqueTimestamp\n\t\t}\n\t}\n\n\t// Create the mew inputs.tail plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"tail\")\n\tcfg.Add(\"inputs\", \"tail\", tailPlugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\nfunc getGrok(logparserPlugin map[string]interface{}) (map[string]interface{}, error) {\n\trawGrok := logparserPlugin[\"grok\"]\n\tif rawGrok == nil {\n\t\treturn nil, nil\n\t}\n\n\tgrok, ok := rawGrok.(map[string]interface{})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected type %T for 'grok'\", rawGrok)\n\t}\n\n\treturn grok, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.logparser\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_logparser/migration_test.go",
    "content": "package inputs_logparser_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_logparser\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/tail\"         // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/grok\"        // register parser\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_logparser/testcases/full/expected.conf",
    "content": "[[inputs.tail]]\n  files = [\"/var/log/apache/access.log\"]\n  initial_read_offset = \"beginning\"\n  watch_method = \"poll\"\n  data_format = \"grok\"\n\n  grok_patterns = [\"%{COMBINED_LOG_FORMAT}\"]\n  name_override = \"apache_access_log\"\n  grok_custom_pattern_files = [\"some_file\"]\n  grok_custom_patterns = '''\nsome pattern\n'''\n  grok_timezone = \"Canada/Eastern\"\n  grok_unique_timestamp = \"auto\"\n"
  },
  {
    "path": "migrations/inputs_logparser/testcases/full/telegraf.conf",
    "content": "[[inputs.logparser]]\n  files = [\"/var/log/apache/access.log\"]\n  from_beginning = true\n  watch_method = \"poll\"\n\n  [inputs.logparser.grok]\n    patterns = [\"%{COMBINED_LOG_FORMAT}\"]\n    measurement = \"apache_access_log\"\n    custom_pattern_files = [\"some_file\"]\n    custom_patterns = '''\nsome pattern\n'''\n    timezone = \"Canada/Eastern\"\n    unique_timestamp = \"auto\""
  },
  {
    "path": "migrations/inputs_mqtt_consumer/migration.go",
    "content": "package inputs_mqtt_consumer\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif _, found := plugin[\"metric_buffer\"]; found {\n\t\tapplied = true\n\n\t\t// Remove the ignored setting\n\t\tdelete(plugin, \"metric_buffer\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"mqtt_consumer\")\n\tcfg.Add(\"inputs\", \"mqtt_consumer\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.mqtt_consumer\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_mqtt_consumer/migration_test.go",
    "content": "package inputs_mqtt_consumer_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_mqtt_consumer\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/mqtt_consumer\"    // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"             // register parsers\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tdefaultCfg := []byte(`\n  # Read metrics from MQTT topic(s)\n  [[inputs.mqtt_consumer]]\n  ## Broker URLs for the MQTT server or cluster.  To connect to multiple\n  ## clusters or standalone servers, use a separate plugin instance.\n  ##   example: servers = [\"tcp://localhost:1883\"]\n  ##            servers = [\"ssl://localhost:1883\"]\n  ##            servers = [\"ws://localhost:1883\"]\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Topics that will be subscribed to.\n  topics = [\n  \"telegraf/host01/cpu\",\n  \"telegraf/+/mem\",\n  \"sensors/#\",\n  ]\n\n  ## The message topic will be stored in a tag specified by this value.  If set\n  ## to the empty string no topic tag will be created.\n  # topic_tag = \"topic\"\n\n  ## QoS policy for messages\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  ##\n  ## When using a QoS of 1 or 2, you should enable persistent_session to allow\n  ## resuming unacknowledged messages.\n  # qos = 0\n\n  ## Connection timeout for initial connection in seconds\n  # connection_timeout = \"30s\"\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Persistent session disables clearing of the client session on connection.\n  ## In order for this option to work you must also set client_id to identify\n  ## the client.  To receive messages that arrived while the client is offline,\n  ## also set the qos option to 1 or 2 and don't forget to also set the QoS when\n  ## publishing.\n  # persistent_session = false\n\n  ## If unset, a random client ID will be generated.\n  # client_id = \"\"\n\n  ## Username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Enable extracting tag values from MQTT topics\n  ## _ denotes an ignored entry in the topic path\n  # [[inputs.mqtt_consumer.topic_parsing]]\n  #   topic = \"\"\n  #   measurement = \"\"\n  #   tags = \"\"\n  #   fields = \"\"\n  ## Value supported is int, float, unit\n  #   [[inputs.mqtt_consumer.topic.types]]\n  #      key = type\n`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer/expected.conf",
    "content": "[[inputs.mqtt_consumer]]\ndata_format = \"influx\"\nservers = [\"tcp://127.0.0.1:1883\"]\ntopics = [\"telegraf/host01/cpu\", \"telegraf/+/mem\", \"sensors/#\"]\n"
  },
  {
    "path": "migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer/telegraf.conf",
    "content": "# Read metrics from MQTT topic(s)\n[[inputs.mqtt_consumer]]\n  servers = [\"tcp://127.0.0.1:1883\"]\n  topics = [\n    \"telegraf/host01/cpu\",\n    \"telegraf/+/mem\",\n    \"sensors/#\",\n  ]\n  metric_buffer = 1024\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer_parser/expected.conf",
    "content": "[[inputs.mqtt_consumer]]\ndata_format = \"xpath_json\"\nservers = [\"tcp://127.0.0.1:1883\"]\ntopics = [\"telegraf/host01/cpu\", \"telegraf/+/mem\", \"sensors/#\"]\nxpath_native_types = true\n\n[[inputs.mqtt_consumer.xpath]]\nfield_selection = \"/fields/*\"\nmetric_name = \"/name\"\ntag_selection = \"/tags/*\"\ntimestamp = \"/timestamp\"\ntimestamp_format = \"unix_ms\""
  },
  {
    "path": "migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer_parser/telegraf.conf",
    "content": "# Read metrics from MQTT topic(s)\n[[inputs.mqtt_consumer]]\n  servers = [\"tcp://127.0.0.1:1883\"]\n  topics = [\n    \"telegraf/host01/cpu\",\n    \"telegraf/+/mem\",\n    \"sensors/#\",\n  ]\n  metric_buffer = 1024\n\n  data_format = \"xpath_json\"\n  xpath_native_types = true\n\n  # Configuration matching the first (ENERGY) message\n  [[inputs.mqtt_consumer.xpath]]\n    metric_name = \"/name\"\n    timestamp = \"/timestamp\"\n    timestamp_format = \"unix_ms\"\n    field_selection = \"/fields/*\"\n    tag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_nats_consumer/migration.go",
    "content": "package inputs_nats_consumer\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif _, found := plugin[\"metric_buffer\"]; found {\n\t\tapplied = true\n\n\t\t// Remove the ignored setting\n\t\tdelete(plugin, \"metric_buffer\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"nats_consumer\")\n\tcfg.Add(\"inputs\", \"nats_consumer\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.nats_consumer\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_nats_consumer/migration_test.go",
    "content": "package inputs_nats_consumer_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_nats_consumer\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/nats_consumer\"    // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"             // register parsers\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tdefaultCfg := []byte(`\n# Read metrics from NATS subject(s)\n  [[inputs.nats_consumer]]\n  ## urls of NATS servers\n  servers = [\"nats://localhost:4222\"]\n\n  ## subject(s) to consume\n  ## If you use jetstream you need to set the subjects\n  ## in jetstream_subjects\n  subjects = [\"telegraf\"]\n\n  ## jetstream subjects\n  ## jetstream is a streaming technology inside of nats.\n  ## With jetstream the nats-server persists messages and\n  ## a consumer can consume historical messages. This is\n  ## useful when telegraf needs to restart it don't miss a\n  ## message. You need to configure the nats-server.\n  ## https://docs.nats.io/nats-concepts/jetstream.\n  jetstream_subjects = [\"js_telegraf\"]\n\n  ## name a queue group\n  queue_group = \"telegraf_consumers\"\n\n  ## Optional credentials\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional NATS 2.0 and NATS NGS compatible user credentials\n  # credentials = \"/etc/telegraf/nats.creds\"\n\n  ## Use Transport Layer Security\n  # secure = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Sets the limits for pending msgs and bytes for each subscription\n  ## These shouldn't need to be adjusted except in very high throughput scenarios\n  # pending_message_limit = 65536\n  # pending_bytes_limit = 67108864\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer/expected.conf",
    "content": "[[inputs.nats_consumer]]\nservers = [\"nats://localhost:4222\"]\nsubjects = [\"telegraf\"]\njetstream_subjects = [\"js_telegraf\"]\nqueue_group = \"telegraf_consumers\"\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer/telegraf.conf",
    "content": "# Read metrics from NATS subject(s)\n[[inputs.nats_consumer]]\n  ## urls of NATS servers\n  servers = [\"nats://localhost:4222\"]\n\n  ## subject(s) to consume\n  subjects = [\"telegraf\"]\n\n  ## jetstream subjects\n  jetstream_subjects = [\"js_telegraf\"]\n\n  ## name a queue group\n  queue_group = \"telegraf_consumers\"\n\n  ## Input data format\n  data_format = \"influx\"\n\n  ## Number of metrics to buffer\n  metric_buffer = 1024\n"
  },
  {
    "path": "migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer_parser/expected.conf",
    "content": "[[inputs.nats_consumer]]\n  servers = [\"nats://localhost:4222\"]\n  subjects = [\"telegraf\"]\n  jetstream_subjects = [\"js_telegraf\"]\n  queue_group = \"telegraf_consumers\"\n  data_format = \"xpath_json\"\n  xpath_native_types = true\n\n  [[inputs.nats_consumer.xpath]]\n    metric_name = \"/name\"\n    timestamp = \"/timestamp\"\n    timestamp_format = \"unix_ms\"\n    field_selection = \"/fields/*\"\n    tag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer_parser/telegraf.conf",
    "content": "# Read metrics from NATS subject(s)\n[[inputs.nats_consumer]]\n  ## urls of NATS servers\n  servers = [\"nats://localhost:4222\"]\n\n  ## subject(s) to consume\n  subjects = [\"telegraf\"]\n\n  ## jetstream subjects\n  jetstream_subjects = [\"js_telegraf\"]\n\n  ## name a queue group\n  queue_group = \"telegraf_consumers\"\n\n  ## Number of metrics to buffer\n  metric_buffer = 1024\n\n  data_format = \"xpath_json\"\n  xpath_native_types = true\n\n  # Configuration matching the first (ENERGY) message\n  [[inputs.nats_consumer.xpath]]\n    metric_name = \"/name\"\n    timestamp = \"/timestamp\"\n    timestamp_format = \"unix_ms\"\n    field_selection = \"/fields/*\"\n    tag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_nsq_consumer/migration.go",
    "content": "package inputs_nsq_consumer\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldServer, found := plugin[\"server\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldServer, ok := rawOldServer.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'server'\", rawOldServer)\n\t\t}\n\n\t\t// Merge the option with the replacement\n\t\tvar nsqd []string\n\t\tif rawNewNSQD, found := plugin[\"nsqd\"]; found {\n\t\t\tvar err error\n\t\t\tnsqd, err = migrations.AsStringSlice(rawNewNSQD)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'nsqd' option: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif !slices.Contains(nsqd, oldServer) {\n\t\t\tnsqd = append(nsqd, oldServer)\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tplugin[\"nsqd\"] = nsqd\n\t\tdelete(plugin, \"server\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"nsq_consumer\")\n\tcfg.Add(\"inputs\", \"nsq_consumer\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.nsq_consumer\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/migration_test.go",
    "content": "package inputs_nsq_consumer_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_nsq_consumer\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/nsq_consumer\"      // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/influx\"         // register parser\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &nsq_consumer.NSQConsumer{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server/expected.conf",
    "content": "[[inputs.nsq_consumer]]\nnsqd = [\"myserver:4150\"]\nnsqlookupd = [\"localhost:4161\"]\ntopic = \"telegraf\"\nchannel = \"consumer\"\nmax_in_flight = 100\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server/telegraf.conf",
    "content": "# Read metrics from NSQD topic(s)\n[[inputs.nsq_consumer]]\n  ## An array representing the NSQD TCP HTTP Endpoints\n  # nsqd = [\"localhost:4150\"]\n  server = \"myserver:4150\"\n\n  ## An array representing the NSQLookupd HTTP Endpoints\n  nsqlookupd = [\"localhost:4161\"]\n  topic = \"telegraf\"\n  channel = \"consumer\"\n  max_in_flight = 100\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server_duplicate/expected.conf",
    "content": "[[inputs.nsq_consumer]]\nnsqd = [\"localhost:4150\", \"myserver:4150\"]\nnsqlookupd = [\"localhost:4161\"]\ntopic = \"telegraf\"\nchannel = \"consumer\"\nmax_in_flight = 100\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server_duplicate/telegraf.conf",
    "content": "# Read metrics from NSQD topic(s)\n[[inputs.nsq_consumer]]\n  ## An array representing the NSQD TCP HTTP Endpoints\n  nsqd = [\"localhost:4150\", \"myserver:4150\"]\n  server = \"myserver:4150\"\n\n  ## An array representing the NSQLookupd HTTP Endpoints\n  nsqlookupd = [\"localhost:4161\"]\n  topic = \"telegraf\"\n  channel = \"consumer\"\n  max_in_flight = 100\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server_existing/expected.conf",
    "content": "[[inputs.nsq_consumer]]\nnsqd = [\"localhost:4150\", \"myserver:4150\"]\nnsqlookupd = [\"localhost:4161\"]\ntopic = \"telegraf\"\nchannel = \"consumer\"\nmax_in_flight = 100\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_nsq_consumer/testcases/deprecated_server_existing/telegraf.conf",
    "content": "# Read metrics from NSQD topic(s)\n[[inputs.nsq_consumer]]\n  ## An array representing the NSQD TCP HTTP Endpoints\n  nsqd = [\"localhost:4150\"]\n  server = \"myserver:4150\"\n\n  ## An array representing the NSQLookupd HTTP Endpoints\n  nsqlookupd = [\"localhost:4161\"]\n  topic = \"telegraf\"\n  channel = \"consumer\"\n  max_in_flight = 100\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/migration.go",
    "content": "package inputs_ntpq\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\t\"github.com/kballard/go-shellquote\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldDNSLookup, found := plugin[\"dns_lookup\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldDNSLookup, ok := rawOldDNSLookup.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'dns_lookup'\", rawOldDNSLookup)\n\t\t}\n\n\t\t// Only insert options if dns_lookup was actually set to false\n\t\tif !oldDNSLookup {\n\t\t\t// Merge the option with the replacement\n\t\t\tvar options []string\n\t\t\tif rawOptions, found := plugin[\"options\"]; found {\n\t\t\t\topts, ok := rawOptions.(string)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'options'\", rawOptions)\n\t\t\t\t}\n\t\t\t\to, err := shellquote.Split(opts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, \"\", fmt.Errorf(\"splitting 'options' failed: %w\", err)\n\t\t\t\t}\n\t\t\t\toptions = o\n\t\t\t} else {\n\t\t\t\toptions = append(options, \"-p\")\n\t\t\t}\n\n\t\t\tif !slices.Contains(options, \"-n\") {\n\t\t\t\toptions = append(options, \"-n\")\n\t\t\t}\n\t\t\tplugin[\"options\"] = strings.Join(options, \" \")\n\t\t}\n\n\t\t// Remove the deprecated option\n\t\tdelete(plugin, \"dns_lookup\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"ntpq\")\n\tcfg.Add(\"inputs\", \"ntpq\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.ntpq\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_ntpq/migration_test.go",
    "content": "package inputs_ntpq_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_ntpq\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/ntpq\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &ntpq.NTPQ{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup/expected.conf",
    "content": "[[inputs.ntpq]]\noptions = \"-p -n\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup/telegraf.conf",
    "content": "# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## If false, set the -n ntpq flag. Can reduce metric gather time.\n  ## DEPRECATED since 1.24.0: add '-n' to 'options' instead to skip DNS lookup\n  dns_lookup = false\n\n  ## Options to pass to the ntpq command.\n  # options = \"-p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_duplicate/expected.conf",
    "content": "[[inputs.ntpq]]\noptions = \"-4 -n -p\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_duplicate/telegraf.conf",
    "content": "# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## If false, set the -n ntpq flag. Can reduce metric gather time.\n  ## DEPRECATED since 1.24.0: add '-n' to 'options' instead to skip DNS lookup\n  dns_lookup = false\n\n  ## Options to pass to the ntpq command.\n  options = \"-4 -n -p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_existing/expected.conf",
    "content": "[[inputs.ntpq]]\noptions = \"-4 -p -n\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_existing/telegraf.conf",
    "content": "# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## If false, set the -n ntpq flag. Can reduce metric gather time.\n  ## DEPRECATED since 1.24.0: add '-n' to 'options' instead to skip DNS lookup\n  dns_lookup = false\n\n  ## Options to pass to the ntpq command.\n  options = \"-4 -p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_true/expected.conf",
    "content": "[[inputs.ntpq]]\n"
  },
  {
    "path": "migrations/inputs_ntpq/testcases/deprecated_dns_lookup_true/telegraf.conf",
    "content": "# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## If false, set the -n ntpq flag. Can reduce metric gather time.\n  ## DEPRECATED since 1.24.0: add '-n' to 'options' instead to skip DNS lookup\n  dns_lookup = true\n\n  ## Options to pass to the ntpq command.\n  # options = \"-p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n"
  },
  {
    "path": "migrations/inputs_openldap/migration.go",
    "content": "package inputs_openldap\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated SSL options to TLS options\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated options and migrate them\n\tvar applied bool\n\n\t// Migrate ssl -> tls\n\tif rawOldValue, found := plugin[\"ssl\"]; found {\n\t\tapplied = true\n\n\t\t// Convert to the actual type\n\t\toldValue, ok := rawOldValue.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'ssl'\", rawOldValue)\n\t\t}\n\n\t\t// Check if the new option already exists and if it has a contradicting\n\t\t// value. If the new option is not present, migrate the old value.\n\t\tif rawNewValue, found := plugin[\"tls\"]; !found {\n\t\t\tplugin[\"tls\"] = oldValue\n\t\t} else {\n\t\t\tif newValue, ok := rawNewValue.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'tls'\", rawNewValue)\n\t\t\t} else if newValue != oldValue {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'tls' and 'ssl'\")\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"ssl\")\n\t}\n\n\t// Migrate ssl_ca -> tls_ca\n\tif rawOldValue, found := plugin[\"ssl_ca\"]; found {\n\t\tapplied = true\n\n\t\t// Convert to the actual type\n\t\toldValue, ok := rawOldValue.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'ssl_ca'\", rawOldValue)\n\t\t}\n\n\t\t// Check if the new option already exists and if it has a contradicting\n\t\t// value. If the new option is not present, migrate the old value.\n\t\tif rawNewValue, found := plugin[\"tls_ca\"]; !found {\n\t\t\tplugin[\"tls_ca\"] = oldValue\n\t\t} else {\n\t\t\tif newValue, ok := rawNewValue.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'tltls_cas'\", rawNewValue)\n\t\t\t} else if newValue != oldValue {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'tls_ca' and 'ssl_ca'\")\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"ssl_ca\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"openldap\")\n\tcfg.Add(\"inputs\", \"openldap\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.openldap\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_openldap/migration_test.go",
    "content": "package inputs_openldap_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_openldap\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/openldap\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &openldap.Openldap{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_openldap/testcases/ca_only/expected.conf",
    "content": "# OpenLDAP cn=Monitor plugin with migrated tls_ca option\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 389\n\n  # No ssl or tls option set\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Migrated from ssl_ca option\n  tls_ca = \"/path/to/ca-certificates.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"cn=readonly,dc=company,dc=org\"\n  bind_password = \"readonlypass\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = true"
  },
  {
    "path": "migrations/inputs_openldap/testcases/ca_only/telegraf.conf",
    "content": "# OpenLDAP cn=Monitor plugin with only ssl_ca deprecated option\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 389\n\n  # No ssl or tls option set\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Only ssl_ca is deprecated - should be migrated to tls_ca\n  ssl_ca = \"/path/to/ca-certificates.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"cn=readonly,dc=company,dc=org\"\n  bind_password = \"readonlypass\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = true"
  },
  {
    "path": "migrations/inputs_openldap/testcases/mixed_config/expected.conf",
    "content": "# OpenLDAP cn=Monitor plugin with preserved TLS options\n[[inputs.openldap]]\n  host = \"ldap.example.com\"\n  port = 389\n\n  # Existing tls option preserved (ssl option was removed)\n  tls = \"starttls\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = true\n\n  # Deprecated ssl_ca option was removed\n  tls_ca = \"/etc/ssl/myca.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = false"
  },
  {
    "path": "migrations/inputs_openldap/testcases/mixed_config/telegraf.conf",
    "content": "# OpenLDAP cn=Monitor plugin with mixed SSL/TLS options\n[[inputs.openldap]]\n  host = \"ldap.example.com\"\n  port = 389\n\n  # User already has configured tls so we should just delete the deprecated\n  # ssl setting\n  tls = \"starttls\"\n  ssl = \"starttls\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = true\n\n  # User already has tls_ca configured without contradiction\n  tls_ca = \"/etc/ssl/myca.pem\"\n  ssl_ca = \"/etc/ssl/myca.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = false"
  },
  {
    "path": "migrations/inputs_openldap/testcases/ssl_only/expected.conf",
    "content": "# OpenLDAP cn=Monitor plugin with migrated TLS options\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 636\n\n  # Migrated from ssl option\n  tls = \"ldaps\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Migrated from ssl_ca option\n  tls_ca = \"/etc/ssl/certs.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"cn=admin,dc=example,dc=com\"\n  bind_password = \"secret\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = true"
  },
  {
    "path": "migrations/inputs_openldap/testcases/ssl_only/telegraf.conf",
    "content": "# OpenLDAP cn=Monitor plugin with deprecated SSL options\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 636\n\n  # Deprecated ssl option - should be migrated to tls\n  ssl = \"ldaps\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Deprecated ssl_ca option - should be migrated to tls_ca\n  ssl_ca = \"/etc/ssl/certs.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"cn=admin,dc=example,dc=com\"\n  bind_password = \"secret\"\n\n  # reverse metric names so they sort more naturally\n  reverse_metric_names = true"
  },
  {
    "path": "migrations/inputs_procstat/migration.go",
    "content": "package inputs_procstat\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldUnits, found := plugin[\"supervisor_unit\"]; found {\n\t\tapplied = true\n\n\t\t// Check if the new option already exists and merge the two\n\t\tvar units []string\n\t\tif newUnits, found := plugin[\"supervisor_units\"]; found {\n\t\t\tvar err error\n\t\t\tunits, err = migrations.AsStringSlice(newUnits)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'supervisor_units': %w\", err)\n\t\t\t}\n\t\t}\n\t\toldUnits, err := migrations.AsStringSlice(rawOldUnits)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'supervisor_unit': %w\", err)\n\t\t}\n\t\tfor _, u := range oldUnits {\n\t\t\tif !choice.Contains(u, units) {\n\t\t\t\tunits = append(units, u)\n\t\t\t}\n\t\t}\n\t\tplugin[\"supervisor_units\"] = units\n\n\t\t// Remove deprecated setting\n\t\tdelete(plugin, \"supervisor_unit\")\n\t}\n\n\t// The tagging options both need the 'tag_with' setting\n\tvar tagwith []string\n\tif rawNewTagWith, found := plugin[\"tag_with\"]; found {\n\t\tvar err error\n\t\ttagwith, err = migrations.AsStringSlice(rawNewTagWith)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'tag_with': %w\", err)\n\t\t}\n\t}\n\n\t// Tagging with PID\n\tif oldPidTag, found := plugin[\"pid_tag\"]; found {\n\t\tapplied = true\n\n\t\tpt, ok := oldPidTag.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'pid_tag' has wrong type %T\", oldPidTag)\n\t\t}\n\n\t\t// Add the pid-tagging to 'tag_with' if requested\n\t\tif pt && !choice.Contains(\"pid\", tagwith) {\n\t\t\ttagwith = append(tagwith, \"pid\")\n\t\t\tplugin[\"tag_with\"] = tagwith\n\t\t}\n\n\t\t// Remove deprecated setting\n\t\tdelete(plugin, \"pid_tag\")\n\t}\n\n\t// Tagging with command-line\n\tif oldCmdlinedTag, found := plugin[\"cmdline_tag\"]; found {\n\t\tapplied = true\n\n\t\tct, ok := oldCmdlinedTag.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'cmdline_tag' has wrong type %T\", oldCmdlinedTag)\n\t\t}\n\n\t\t// Add the pid-tagging to 'tag_with' if requested\n\t\tif ct && !choice.Contains(\"cmdline\", tagwith) {\n\t\t\ttagwith = append(tagwith, \"cmdline\")\n\t\t\tplugin[\"tag_with\"] = tagwith\n\t\t}\n\n\t\t// Remove deprecated setting\n\t\tdelete(plugin, \"cmdline_tag\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"procstat\")\n\tcfg.Add(\"inputs\", \"procstat\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.procstat\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_procstat/migration_test.go",
    "content": "package inputs_procstat_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_procstat\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/procstat\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := procstat.Procstat{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_supervisor_unit/expected.conf",
    "content": "[[inputs.procstat]]\npid_file = \"/var/run/nginx.pid\"\nsupervisor_units = [\"webserver\", \"proxy\"]\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_supervisor_unit/telegraf.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  supervisor_unit = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## When true add the full cmdline as a tag.\n  # cmdline_tag = false\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the PID as a tag instead of as a field.  When collecting multiple\n  ## processes with otherwise matching tags this setting should be enabled to\n  ## ensure each process has a unique identity.\n  ##\n  ## Enabling this option may result in a large number of series, especially\n  ## when processes have a short lifetime.\n  # pid_tag = false\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_supervisor_unit merge/expected.conf",
    "content": "[[inputs.procstat]]\nsupervisor_units = [\"upsd\", \"webserver\", \"mail\", \"proxy\"]\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_supervisor_unit merge/telegraf.conf",
    "content": "[[inputs.procstat]]\n  supervisor_unit = [\"webserver\", \"proxy\"]\n  supervisor_units = [\"upsd\", \"webserver\", \"mail\"]\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_false/expected.conf",
    "content": "[[inputs.procstat]]\npid_file = \"/var/run/nginx.pid\"\nsupervisor_units = [\"webserver\", \"proxy\"]\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_false/telegraf.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  supervisor_unit = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## When true add the full cmdline as a tag.\n  cmdline_tag = false\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the PID as a tag instead of as a field.  When collecting multiple\n  ## processes with otherwise matching tags this setting should be enabled to\n  ## ensure each process has a unique identity.\n  ##\n  ## Enabling this option may result in a large number of series, especially\n  ## when processes have a short lifetime.\n  pid_tag = false\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true/expected.conf",
    "content": "[[inputs.procstat]]\npid_file = \"/var/run/nginx.pid\"\nsupervisor_units = [\"webserver\", \"proxy\"]\ntag_with = [\"pid\", \"cmdline\"]"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true/telegraf.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  supervisor_unit = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## When true add the full cmdline as a tag.\n  cmdline_tag = true\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the PID as a tag instead of as a field.  When collecting multiple\n  ## processes with otherwise matching tags this setting should be enabled to\n  ## ensure each process has a unique identity.\n  ##\n  ## Enabling this option may result in a large number of series, especially\n  ## when processes have a short lifetime.\n  pid_tag = true\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true_merge/expected.conf",
    "content": "[[inputs.procstat]]\npid_file = \"/var/run/nginx.pid\"\nsupervisor_units = [\"webserver\", \"proxy\"]\ntag_with = [\"ppid\", \"pid\", \"cmdline\"]"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true_merge/telegraf.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  supervisor_unit = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## When true add the full cmdline as a tag.\n  cmdline_tag = true\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the PID as a tag instead of as a field.  When collecting multiple\n  ## processes with otherwise matching tags this setting should be enabled to\n  ## ensure each process has a unique identity.\n  ##\n  ## Enabling this option may result in a large number of series, especially\n  ## when processes have a short lifetime.\n  pid_tag = true\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n\n  tag_with = [\"ppid\"]"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true_merge_overlap/expected.conf",
    "content": "[[inputs.procstat]]\npid_file = \"/var/run/nginx.pid\"\nsupervisor_units = [\"webserver\", \"proxy\"]\ntag_with = [\"ppid\", \"cmdline\", \"pid\"]"
  },
  {
    "path": "migrations/inputs_procstat/testcases/deprecated_tagging_true_merge_overlap/telegraf.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  supervisor_unit = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## When true add the full cmdline as a tag.\n  cmdline_tag = true\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the PID as a tag instead of as a field.  When collecting multiple\n  ## processes with otherwise matching tags this setting should be enabled to\n  ## ensure each process has a unique identity.\n  ##\n  ## Enabling this option may result in a large number of series, especially\n  ## when processes have a short lifetime.\n  pid_tag = true\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n\n  tag_with = [\"ppid\", \"cmdline\"]"
  },
  {
    "path": "migrations/inputs_rabbitmq/migration.go",
    "content": "package inputs_rabbitmq\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated RabbitMQ options\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated options and migrate them\n\tvar applied bool\n\tvar message string\n\n\t// Migrate the deprecated \"name\" option to tags\n\tif rawOldName, found := plugin[\"name\"]; found {\n\t\tapplied = true\n\n\t\toldName, ok := rawOldName.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'name'\", rawOldName)\n\t\t}\n\n\t\t// Merge with potentially existing tags\n\t\tvar tags map[string]interface{}\n\t\tif rawTags, found := plugin[\"tags\"]; found {\n\t\t\tif tags, ok = rawTags.(map[string]interface{}); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'tags'\", rawTags)\n\t\t\t} else if rawName, found := tags[\"name\"]; found {\n\t\t\t\tif name, ok := rawName.(string); !ok {\n\t\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'name' tag\", rawName)\n\t\t\t\t} else if name != oldName {\n\t\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'name' and 'name' tag\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttags[\"name\"] = oldName\n\t\t\t}\n\t\t} else {\n\t\t\ttags = map[string]interface{}{\"name\": oldName}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tplugin[\"tags\"] = tags\n\t\tdelete(plugin, \"name\")\n\t}\n\n\t// Migrate queues -> queue_name_include\n\tif rawOldQueues, found := plugin[\"queues\"]; found {\n\t\tapplied = true\n\n\t\toldQueues, err := migrations.AsStringSlice(rawOldQueues)\n\t\tif err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'queues': %w\", err)\n\t\t}\n\n\t\t// Merge with potentially existing setting\n\t\tvar includes []string\n\t\tif rawNewQueueNameInclude, found := plugin[\"queue_name_include\"]; found {\n\t\t\tif includes, err = migrations.AsStringSlice(rawNewQueueNameInclude); err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"setting 'queue_name_include': %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, q := range oldQueues {\n\t\t\tif !slices.Contains(includes, q) {\n\t\t\t\tincludes = append(includes, q)\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tplugin[\"queue_name_include\"] = includes\n\t\tdelete(plugin, \"queues\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"rabbitmq\")\n\tcfg.Add(\"inputs\", \"rabbitmq\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, message, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.rabbitmq\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/migration_test.go",
    "content": "package inputs_rabbitmq_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_rabbitmq\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/rabbitmq\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &rabbitmq.RabbitMQ{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestNameConflict(t *testing.T) {\n\tcfg := []byte(`\n\t\t[[inputs.rabbitmq]]\n\t\t\turl = \"http://rabbitmq.example.com:15672\"\n\t\t\tusername = \"admin\"\n\t\t\tpassword = \"secret\"\n\t\t\theader_timeout = \"3s\"\n\t\t\tclient_timeout = \"4s\"\n\t\t\tnodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\t\t\texchanges = [\"telegraf\", \"metrics\"]\n\t\t\tqueue_name_include = [\"important.*\", \"critical.*\"]\n\t\t\tqueue_name_exclude = [\"temp.*\"]\n\t\t\ttags = {\"name\" = \"foobar\"}\n\t\t\tname = \"production-rabbitmq\"\n\t`)\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'name' and 'name' tag\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/name/expected.conf",
    "content": "[[inputs.rabbitmq]]\nurl = \"http://rabbitmq.example.com:15672\"\nusername = \"admin\"\npassword = \"secret\"\nheader_timeout = \"3s\"\nclient_timeout = \"4s\"\nnodes = [\"rabbit@node1\", \"rabbit@node2\"]\nexchanges = [\"telegraf\", \"metrics\"]\nqueue_name_include = [\"important.*\", \"critical.*\"]\nqueue_name_exclude = [\"temp.*\"]\ntags = {\"name\" = \"production-rabbitmq\"}\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/name/telegraf.conf",
    "content": "# RabbitMQ plugin with deprecated name option\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://rabbitmq.example.com:15672\"\n\n  ## Deprecated name option - should be migrated to tags\n  name = \"production-rabbitmq\"\n\n  ## Credentials\n  username = \"admin\"\n  password = \"secret\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional request timeouts\n  header_timeout = \"3s\"\n  client_timeout = \"4s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement\n  nodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"telegraf\", \"metrics\"]\n\n  ## Queues to include and exclude. Globs accepted.\n  queue_name_include = [\"important.*\", \"critical.*\"]\n  queue_name_exclude = [\"temp.*\"]"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/name_duplicate/expected.conf",
    "content": "[[inputs.rabbitmq]]\nurl = \"http://rabbitmq.example.com:15672\"\nusername = \"admin\"\npassword = \"secret\"\nheader_timeout = \"3s\"\nclient_timeout = \"4s\"\nnodes = [\"rabbit@node1\", \"rabbit@node2\"]\nexchanges = [\"telegraf\", \"metrics\"]\nqueue_name_include = [\"important.*\", \"critical.*\"]\nqueue_name_exclude = [\"temp.*\"]\ntags = {\"name\" = \"production-rabbitmq\"}\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/name_duplicate/telegraf.conf",
    "content": "# RabbitMQ plugin with deprecated name option\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://rabbitmq.example.com:15672\"\n\n  ## Deprecated name option - should be migrated to tags\n  name = \"production-rabbitmq\"\n\n  ## Credentials\n  username = \"admin\"\n  password = \"secret\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional request timeouts\n  header_timeout = \"3s\"\n  client_timeout = \"4s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement\n  nodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"telegraf\", \"metrics\"]\n\n  ## Queues to include and exclude. Globs accepted.\n  queue_name_include = [\"important.*\", \"critical.*\"]\n  queue_name_exclude = [\"temp.*\"]\n\n  tags = {\"name\" = \"production-rabbitmq\"}\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues/expected.conf",
    "content": "# RabbitMQ plugin with migrated queue_name_include\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://localhost:15672\"\n\n  ## Credentials\n  username = \"guest\"\n  password = \"guest\"\n\n  ## Optional TLS Config\n  insecure_skip_verify = false\n\n  ## Optional request timeouts\n  header_timeout = \"5s\"\n  client_timeout = \"10s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement\n  nodes = [\"rabbit@localhost\"]\n\n  ## Migrated from queues option\n  queue_name_include = [\"app.events\", \"app.logs\", \"app.notifications\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"app.exchange\", \"logs.exchange\"]\n\n  ## Metrics to include and exclude. Globs accepted.\n  metric_include = [\"queue\", \"exchange\", \"overview\"]\n  metric_exclude = [\"federation\"]"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues/telegraf.conf",
    "content": "# RabbitMQ plugin with deprecated queues option\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://localhost:15672\"\n\n  ## Credentials\n  username = \"guest\"\n  password = \"guest\"\n\n  ## Optional TLS Config\n  insecure_skip_verify = false\n\n  ## Optional request timeouts\n  header_timeout = \"5s\"\n  client_timeout = \"10s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement\n  nodes = [\"rabbit@localhost\"]\n\n  ## Deprecated queues option - should be migrated to queue_name_include\n  queues = [\"app.events\", \"app.logs\", \"app.notifications\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"app.exchange\", \"logs.exchange\"]\n\n  ## Metrics to include and exclude. Globs accepted.\n  metric_include = [\"queue\", \"exchange\", \"overview\"]\n  metric_exclude = [\"federation\"]"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues_duplicate/expected.conf",
    "content": "[[inputs.rabbitmq]]\nurl = \"http://localhost:15672\"\nusername = \"guest\"\npassword = \"guest\"\nheader_timeout = \"3s\"\nclient_timeout = \"4s\"\nqueue_name_include = [\"existing.*\", \"important.*\", \"old.*\"]\nexchanges = [\"main\"]\nmetric_include = [\"queue\", \"overview\"]\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues_duplicate/telegraf.conf",
    "content": "# RabbitMQ plugin with deprecated options and existing new options\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://localhost:15672\"\n\n  ## Credentials\n  username = \"guest\"\n  password = \"guest\"\n\n  ## Optional request timeouts\n  header_timeout = \"3s\"\n  client_timeout = \"4s\"\n\n  ## User already has queue_name_include configured - should NOT be overwritten\n  queue_name_include = [\"existing.*\", \"important.*\"]\n\n  ## Deprecated queues option - should be removed but not override existing queue_name_include\n  queues = [\"important.*\", \"old.*\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"main\"]\n\n  ## Metrics to include and exclude\n  metric_include = [\"queue\", \"overview\"]"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues_existing/expected.conf",
    "content": "[[inputs.rabbitmq]]\nurl = \"http://localhost:15672\"\nusername = \"guest\"\npassword = \"guest\"\nheader_timeout = \"3s\"\nclient_timeout = \"4s\"\nqueue_name_include = [\"existing.*\", \"important.*\", \"deprecated.*\", \"old.*\"]\nexchanges = [\"main\"]\nmetric_include = [\"queue\", \"overview\"]\n"
  },
  {
    "path": "migrations/inputs_rabbitmq/testcases/queues_existing/telegraf.conf",
    "content": "# RabbitMQ plugin with deprecated options and existing new options\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  url = \"http://localhost:15672\"\n\n  ## Credentials\n  username = \"guest\"\n  password = \"guest\"\n\n  ## Optional request timeouts\n  header_timeout = \"3s\"\n  client_timeout = \"4s\"\n\n  ## User already has queue_name_include configured - should NOT be overwritten\n  queue_name_include = [\"existing.*\", \"important.*\"]\n\n  ## Deprecated queues option - should be removed but not override existing queue_name_include\n  queues = [\"deprecated.*\", \"old.*\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement\n  exchanges = [\"main\"]\n\n  ## Metrics to include and exclude\n  metric_include = [\"queue\", \"overview\"]"
  },
  {
    "path": "migrations/inputs_sflow/migration.go",
    "content": "package inputs_sflow\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t\"github.com/influxdata/telegraf/migrations/common\"\n)\n\nconst msg = `\n    Replacement 'inputs.netflow' will output a different metric format.\n\tPlease adapt your queries!\n`\n\n// Define \"old\" data structure\ntype sflow struct {\n\tServiceAddress string `toml:\"service_address\"`\n\tReadBufferSize string `toml:\"read_buffer_size\"`\n\tcommon.InputOptions\n}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old sflow\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Fill common options\n\tplugin := make(map[string]interface{})\n\told.InputOptions.Migrate()\n\tgeneral, err := toml.Marshal(old.InputOptions)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"marshalling general options failed: %w\", err)\n\t}\n\tif err := toml.Unmarshal(general, &plugin); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"re-unmarshalling general options failed: %w\", err)\n\t}\n\n\t// Use a map for the new plugin and fill in the data\n\tplugin[\"service_address\"] = old.ServiceAddress\n\tif old.ReadBufferSize != \"\" {\n\t\tplugin[\"read_buffer_size\"] = old.ReadBufferSize\n\t}\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"netflow\")\n\tcfg.Add(\"inputs\", \"netflow\", plugin)\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.sflow\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_sflow/migration_test.go",
    "content": "package inputs_sflow_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_sflow\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/netflow\"  // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/sflow\"    // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatchf(t, expectedIDs, actualIDs, \"generated config: %s\", string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/filters/expected.conf",
    "content": "[[inputs.netflow]]\nservice_address = \"udp://:6343\"\nread_buffer_size = \"32KiB\"\nfieldinclude = [\"a\"]\nname_override = \"foo\"\n[inputs.netflow.tags]\nfoo = \"bar\"\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/filters/telegraf.conf",
    "content": "[[inputs.sflow]]\n  service_address = \"udp://:6343\"\n  read_buffer_size = \"32KiB\"\n\n  name_override = \"foo\"\n  fieldpass = [\"a\"]\n  [inputs.sflow.tags]\n    foo = \"bar\"\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/minimal/expected.conf",
    "content": "[[inputs.netflow]]\nservice_address = \"udp://:6343\"\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/minimal/telegraf.conf",
    "content": "# SFlow V5 Protocol Listener\n[[inputs.sflow]]\n  ## Address to listen for sFlow packets.\n  ##   example: service_address = \"udp://:6343\"\n  ##            service_address = \"udp4://:6343\"\n  ##            service_address = \"udp6://:6343\"\n  service_address = \"udp://:6343\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  # read_buffer_size = \"\"\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/read_buffer_size/expected.conf",
    "content": "[[inputs.netflow]]\nservice_address = \"udp://:6343\"\nread_buffer_size = \"32KiB\"\n"
  },
  {
    "path": "migrations/inputs_sflow/testcases/read_buffer_size/telegraf.conf",
    "content": "# SFlow V5 Protocol Listener\n[[inputs.sflow]]\n  ## Address to listen for sFlow packets.\n  ##   example: service_address = \"udp://:6343\"\n  ##            service_address = \"udp4://:6343\"\n  ##            service_address = \"udp6://:6343\"\n  service_address = \"udp://:6343\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  read_buffer_size = \"32KiB\"\n"
  },
  {
    "path": "migrations/inputs_smart/migration.go",
    "content": "package inputs_smart\n\nimport (\n\t\"errors\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tvar applied bool\n\n\tif path, found := plugin[\"path\"]; found {\n\t\tif _, found := plugin[\"path_smartctl\"]; found {\n\t\t\treturn nil, \"\", errors.New(\"cannot migrate 'path' option, as 'path_smartctl' is already set\")\n\t\t}\n\t\tplugin[\"path_smartctl\"] = path\n\t\tdelete(plugin, \"path\")\n\t\tapplied = true\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"smart\")\n\tcfg.Add(\"inputs\", \"smart\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.smart\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_smart/migration_test.go",
    "content": "package inputs_smart_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_smart\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/smart\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &smart.Smart{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestPathConflict(t *testing.T) {\n\tcfg := []byte(`\n[[inputs.smart]]\n    path = \"/usr/bin/smartctl_path\"\n    path_smartctl = \"/usr/bin/smartctl_pathsmartctl\"\n\t`)\n\n\t// Migrate and check that it fails with conflict error\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"cannot migrate 'path' option, as 'path_smartctl' is already set\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatchf(t, expectedIDs, actualIDs, \"generated config: %s\", string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_smart/testcases/standard/expected.conf",
    "content": "[[inputs.smart]]\n    path_smartctl = \"/usr/bin/smartctl\"\n"
  },
  {
    "path": "migrations/inputs_smart/testcases/standard/telegraf.conf",
    "content": "[[inputs.smart]]\n    path = \"/usr/bin/smartctl\"\n"
  },
  {
    "path": "migrations/inputs_snmp_legacy/migration.go",
    "content": "package inputs_snmp_legacy\n\nimport (\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nconst msg = `\n    This plugin cannot be migrated automatically and requires manual intervention!\n`\n\n// Migration function\nfunc migrate(_ *ast.Table) ([]byte, string, error) {\n\treturn nil, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.snmp_legacy\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_snmp_legacy/migration_test.go",
    "content": "package inputs_snmp_legacy_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_snmp_legacy\" // register migration\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tinput := []byte(`\n[[inputs.snmp_legacy]]\n  address = \"192.168.2.2:161\"\n`)\n\n\toutput, n, err := config.ApplyMigrations(input)\n\trequire.NoError(t, err)\n\trequire.Empty(t, strings.TrimSpace(string(output)))\n\trequire.Equal(t, uint64(1), n)\n}\n"
  },
  {
    "path": "migrations/inputs_sqlserver/migration.go",
    "content": "package inputs_sqlserver\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function to migrate deprecated SQL Server options\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated options and migrate them\n\tvar applied bool\n\tvar message string\n\n\t// Check if database_type is already set - if so, don't override\n\t_, databaseTypeExists := plugin[\"database_type\"]\n\tvar foundAzureDB bool\n\n\t// Migrate azuredb -> database_type\n\tif azuredbValue, found := plugin[\"azuredb\"]; found {\n\t\tapplied = true\n\t\tfoundAzureDB = true\n\n\t\t// Only set database_type if it's not already set (don't overwrite existing)\n\t\tif !databaseTypeExists {\n\t\t\tif azuredb, ok := azuredbValue.(bool); ok && azuredb {\n\t\t\t\t// azuredb = true means Azure SQL Database\n\t\t\t\tplugin[\"database_type\"] = \"AzureSQLDB\"\n\t\t\t} else {\n\t\t\t\t// azuredb = false means on-premises SQL Server\n\t\t\t\tplugin[\"database_type\"] = \"SQLServer\"\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"azuredb\")\n\t}\n\n\t// Migrate query_version -> database_type (only if azuredb wasn't found)\n\tif _, found := plugin[\"query_version\"]; found {\n\t\tapplied = true\n\t\tif !foundAzureDB {\n\t\t\t// Only set database_type if it's not already set (don't overwrite existing)\n\t\t\tif !databaseTypeExists {\n\t\t\t\t// For query_version, default to SQLServer regardless of the version\n\t\t\t\tplugin[\"database_type\"] = \"SQLServer\"\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"query_version\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configuration\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"sqlserver\")\n\tcfg.Add(\"inputs\", \"sqlserver\", plugin)\n\toutput, err := toml.Marshal(cfg)\n\treturn output, message, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.sqlserver\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_sqlserver/migration_test.go",
    "content": "package inputs_sqlserver_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_sqlserver\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/sqlserver\"\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &sqlserver.SQLServer{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/azuredb_false/expected.conf",
    "content": "# SQL Server plugin with migrated database_type\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"SQLServer\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"5s\"\n  servers = [\"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/azuredb_false/telegraf.conf",
    "content": "# SQL Server plugin with deprecated azuredb option set to false\n[[inputs.sqlserver]]\n  servers = [\n    \"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  azuredb = false\n  query_timeout = \"5s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/azuredb_true/expected.conf",
    "content": "# SQL Server plugin with migrated database_type\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"AzureSQLDB\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"5s\"\n  servers = [\"Server=myazureserver.database.windows.net;Port=1433;User Id=myuser;Password=mypass;database=mydatabase;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/azuredb_true/telegraf.conf",
    "content": "# SQL Server plugin with deprecated azuredb option set to true\n[[inputs.sqlserver]]\n  servers = [\n    \"Server=myazureserver.database.windows.net;Port=1433;User Id=myuser;Password=mypass;database=mydatabase;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  azuredb = true\n  query_timeout = \"5s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/both_deprecated/expected.conf",
    "content": "# SQL Server plugin with migrated database_type\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"AzureSQLDB\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"5s\"\n  servers = [\"Server=myazureserver.database.windows.net;Port=1433;User Id=myuser;Password=mypass;database=mydatabase;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/both_deprecated/telegraf.conf",
    "content": "[[inputs.sqlserver]]\n  servers = [\n    \"Server=myazureserver.database.windows.net;Port=1433;User Id=myuser;Password=mypass;database=mydatabase;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  azuredb = true\n  query_version = 2\n  query_timeout = \"5s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/existing_database_type/expected.conf",
    "content": "# SQL Server plugin with preserved database_type and deprecated options removed\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"AzureSQLManagedInstance\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"5s\"\n  servers = [\"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/existing_database_type/telegraf.conf",
    "content": "# SQL Server plugin with existing database_type and deprecated options\n[[inputs.sqlserver]]\n  servers = [\n    \"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  database_type = \"AzureSQLManagedInstance\"\n  azuredb = true\n  query_version = 2\n  query_timeout = \"5s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/query_version_1/expected.conf",
    "content": "# SQL Server plugin with migrated database_type\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"SQLServer\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"10s\"\n  servers = [\"Server=onprem-sql.company.com;Port=1433;User Id=telegraf;Password=secret;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/query_version_1/telegraf.conf",
    "content": "# SQL Server plugin with deprecated query_version option set to 1\n[[inputs.sqlserver]]\n  servers = [\n    \"Server=onprem-sql.company.com;Port=1433;User Id=telegraf;Password=secret;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  query_version = 1\n  query_timeout = \"10s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/query_version_2/expected.conf",
    "content": "# SQL Server plugin with migrated database_type\n[[inputs.sqlserver]]\n  auth_method = \"connection_string\"\n  database_type = \"SQLServer\"\n  exclude_query = []\n  include_query = []\n  query_timeout = \"5s\"\n  servers = [\"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"]"
  },
  {
    "path": "migrations/inputs_sqlserver/testcases/query_version_2/telegraf.conf",
    "content": "# SQL Server plugin with deprecated query_version option\n[[inputs.sqlserver]]\n  servers = [\n    \"Server=192.168.1.10;Port=1433;User Id=myuser;Password=mypass;app name=telegraf;log=1;\"\n  ]\n  auth_method = \"connection_string\"\n  query_version = 2\n  query_timeout = \"5s\"\n  include_query = []\n  exclude_query = []"
  },
  {
    "path": "migrations/inputs_statsd/migration.go",
    "content": "package inputs_statsd\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\t// Remove option as it's being ignored\n\tif _, found := plugin[\"udp_packet_size\"]; found {\n\t\tapplied = true\n\t\tdelete(plugin, \"udp_packet_size\")\n\t}\n\n\tif rawOldParseDataDogTags, found := plugin[\"parse_data_dog_tags\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldParseDataDogTags, ok := rawOldParseDataDogTags.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'parse_data_dog_tags'\", rawOldParseDataDogTags)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are\n\t\t// conflicting.\n\t\tif rawNewDataDogExtensions, found := plugin[\"datadog_extensions\"]; found {\n\t\t\tif newDataDogExtensions, ok := rawNewDataDogExtensions.(bool); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'datadog_extensions'\", rawNewDataDogExtensions)\n\t\t\t} else if oldParseDataDogTags != newDataDogExtensions {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'parse_data_dog_tags' and 'datadog_extensions'\")\n\t\t\t}\n\t\t} else if oldParseDataDogTags {\n\t\t\t// Only set the option if it is not the default for the new option\n\t\t\tplugin[\"datadog_extensions\"] = true\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tdelete(plugin, \"parse_data_dog_tags\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"statsd\")\n\tcfg.Add(\"inputs\", \"statsd\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.statsd\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_statsd/migration_test.go",
    "content": "package inputs_statsd_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_statsd\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/statsd\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &statsd.Statsd{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_parse_data_dog_tags/expected.conf",
    "content": "[[inputs.statsd]]\nallowed_pending_messages = 10000\ndatadog_distributions = false\ndatadog_extensions = true\ndatadog_keep_container_tag = false\ndelete_counters = true\ndelete_gauges = true\ndelete_sets = true\ndelete_timings = true\nmax_tcp_connections = 250\nmetric_separator = \"_\"\npercentile_limit = 1000\nprotocol = \"udp\"\nservice_address = \":8125\"\ntcp_keep_alive = false\n"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_parse_data_dog_tags/telegraf.conf",
    "content": "# Statsd Server\n[[inputs.statsd]]\n  ## Protocol, must be \"tcp\", \"udp4\", \"udp6\" or \"udp\" (default=udp)\n  protocol = \"udp\"\n\n  ## MaxTCPConnection - applicable when protocol is set to tcp (default=250)\n  max_tcp_connections = 250\n\n  ## Enable TCP keep alive probes (default=false)\n  tcp_keep_alive = false\n\n  ## Specifies the keep-alive period for an active network connection.\n  ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false.\n  ## Defaults to the OS configuration.\n  # tcp_keep_alive_period = \"2h\"\n\n  ## Address and port to host UDP listener on\n  service_address = \":8125\"\n\n  ## The following configuration options control when telegraf clears it's cache\n  ## of previous values. If set to false, then telegraf will only clear it's\n  ## cache when the daemon is restarted.\n  ## Reset gauges every interval (default=true)\n  delete_gauges = true\n  ## Reset counters every interval (default=true)\n  delete_counters = true\n  ## Reset sets every interval (default=true)\n  delete_sets = true\n  ## Reset timings & histograms every interval (default=true)\n  delete_timings = true\n\n  ## Enable aggregation temporality adds temporality=delta or temporality=commulative tag, and\n  ## start_time field, which adds the start time of the metric accumulation.\n  ## You should use this when using OpenTelemetry output.\n  # enable_aggregation_temporality = false\n\n  ## Percentiles to calculate for timing & histogram stats.\n  # percentiles = [50.0, 90.0, 99.0, 99.9, 99.95, 100.0]\n\n  ## separator to use between elements of a statsd metric\n  metric_separator = \"_\"\n\n  ## Parses extensions to statsd in the datadog statsd format\n  ## currently supports metrics and datadog tags.\n  ## http://docs.datadoghq.com/guides/dogstatsd/\n  datadog_extensions = true\n\n  ## Parses distributions metric as specified in the datadog statsd format\n  ## https://docs.datadoghq.com/developers/metrics/types/?tab=distribution#definition\n  datadog_distributions = false\n\n  ## Keep or drop the container id as tag. Included as optional field\n  ## in DogStatsD protocol v1.2 if source is running in Kubernetes\n  ## https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v12\n  datadog_keep_container_tag = false\n\n  ## Statsd data translation templates, more info can be read here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/TEMPLATE_PATTERN.md\n  # templates = [\n  #     \"cpu.* measurement*\"\n  # ]\n\n  ## Number of UDP messages allowed to queue up, once filled,\n  ## the statsd server will start dropping packets\n  allowed_pending_messages = 10000\n\n  ## Number of worker threads used to parse the incoming messages.\n  # number_workers_threads = 5\n\n  ## Number of timing/histogram values to track per-measurement in the\n  ## calculation of percentiles. Raising this limit increases the accuracy\n  ## of percentiles but also increases the memory usage and cpu time.\n  percentile_limit = 1000\n\n  ## Maximum socket buffer size in bytes, once the buffer fills up, metrics\n  ## will start dropping.  Defaults to the OS default.\n  # read_buffer_size = 65535\n\n  ## Max duration (TTL) for each metric to stay cached/reported without being updated.\n  # max_ttl = \"10h\"\n\n  ## Sanitize name method\n  ## By default, telegraf will pass names directly as they are received.\n  ## However, upstream statsd now does sanitization of names which can be\n  ## enabled by using the \"upstream\" method option. This option will a) replace\n  ## white space with '_', replace '/' with '-', and remove characters not\n  ## matching 'a-zA-Z_\\-0-9\\.;='.\n  #sanitize_name_method = \"\"\n\n  ## Replace dots (.) with underscore (_) and dashes (-) with\n  ## double underscore (__) in metric names.\n  # convert_names = false\n\n  ## Convert all numeric counters to float\n  ## Enabling this would ensure that both counters and guages are both emitted\n  ## as floats.\n  # float_counters = false\n\n  ## Emit timings `metric_<name>_count` field as float, the same as all other\n  ## histogram fields\n  # float_timings = false\n\n  ## Emit sets as float\n  # float_sets = false\n\n  parse_data_dog_tags = true"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_parse_data_dog_tags_false/expected.conf",
    "content": "[[inputs.statsd]]\nprotocol = \"udp\"\nmax_tcp_connections = 250\ntcp_keep_alive = false\nservice_address = \":8125\"\ndelete_gauges = true\ndelete_counters = true\ndelete_sets = true\ndelete_timings = true\nmetric_separator = \"_\"\ndatadog_distributions = false\ndatadog_keep_container_tag = false\nallowed_pending_messages = 10000\npercentile_limit = 1000\n"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_parse_data_dog_tags_false/telegraf.conf",
    "content": "# Statsd Server\n[[inputs.statsd]]\n  ## Protocol, must be \"tcp\", \"udp4\", \"udp6\" or \"udp\" (default=udp)\n  protocol = \"udp\"\n\n  ## MaxTCPConnection - applicable when protocol is set to tcp (default=250)\n  max_tcp_connections = 250\n\n  ## Enable TCP keep alive probes (default=false)\n  tcp_keep_alive = false\n\n  ## Specifies the keep-alive period for an active network connection.\n  ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false.\n  ## Defaults to the OS configuration.\n  # tcp_keep_alive_period = \"2h\"\n\n  ## Address and port to host UDP listener on\n  service_address = \":8125\"\n\n  ## The following configuration options control when telegraf clears it's cache\n  ## of previous values. If set to false, then telegraf will only clear it's\n  ## cache when the daemon is restarted.\n  ## Reset gauges every interval (default=true)\n  delete_gauges = true\n  ## Reset counters every interval (default=true)\n  delete_counters = true\n  ## Reset sets every interval (default=true)\n  delete_sets = true\n  ## Reset timings & histograms every interval (default=true)\n  delete_timings = true\n\n  ## Enable aggregation temporality adds temporality=delta or temporality=commulative tag, and\n  ## start_time field, which adds the start time of the metric accumulation.\n  ## You should use this when using OpenTelemetry output.\n  # enable_aggregation_temporality = false\n\n  ## Percentiles to calculate for timing & histogram stats.\n  #percentiles = [50.0, 90.0, 99.0, 99.9, 99.95, 100.0]\n\n  ## separator to use between elements of a statsd metric\n  metric_separator = \"_\"\n\n  ## Parses extensions to statsd in the datadog statsd format\n  ## currently supports metrics and datadog tags.\n  ## http://docs.datadoghq.com/guides/dogstatsd/\n  # datadog_extensions = false\n\n  ## Parses distributions metric as specified in the datadog statsd format\n  ## https://docs.datadoghq.com/developers/metrics/types/?tab=distribution#definition\n  datadog_distributions = false\n\n  ## Keep or drop the container id as tag. Included as optional field\n  ## in DogStatsD protocol v1.2 if source is running in Kubernetes\n  ## https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v12\n  datadog_keep_container_tag = false\n\n  ## Statsd data translation templates, more info can be read here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/TEMPLATE_PATTERN.md\n  # templates = [\n  #     \"cpu.* measurement*\"\n  # ]\n\n  ## Number of UDP messages allowed to queue up, once filled,\n  ## the statsd server will start dropping packets\n  allowed_pending_messages = 10000\n\n  ## Number of worker threads used to parse the incoming messages.\n  # number_workers_threads = 5\n\n  ## Number of timing/histogram values to track per-measurement in the\n  ## calculation of percentiles. Raising this limit increases the accuracy\n  ## of percentiles but also increases the memory usage and cpu time.\n  percentile_limit = 1000\n\n  ## Maximum socket buffer size in bytes, once the buffer fills up, metrics\n  ## will start dropping.  Defaults to the OS default.\n  # read_buffer_size = 65535\n\n  ## Max duration (TTL) for each metric to stay cached/reported without being updated.\n  # max_ttl = \"10h\"\n\n  ## Sanitize name method\n  ## By default, telegraf will pass names directly as they are received.\n  ## However, upstream statsd now does sanitization of names which can be\n  ## enabled by using the \"upstream\" method option. This option will a) replace\n  ## white space with '_', replace '/' with '-', and remove characters not\n  ## matching 'a-zA-Z_\\-0-9\\.;='.\n  #sanitize_name_method = \"\"\n\n  ## Replace dots (.) with underscore (_) and dashes (-) with\n  ## double underscore (__) in metric names.\n  # convert_names = false\n\n  ## Convert all numeric counters to float\n  ## Enabling this would ensure that both counters and guages are both emitted\n  ## as floats.\n  # float_counters = false\n\n  ## Emit timings `metric_<name>_count` field as float, the same as all other\n  ## histogram fields\n  # float_timings = false\n\n  ## Emit sets as float\n  # float_sets = false\n\n  parse_data_dog_tags = false"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_udp_packet_size/expected.conf",
    "content": "[[inputs.statsd]]\nprotocol = \"udp\"\nmax_tcp_connections = 250\ntcp_keep_alive = false\nservice_address = \":8125\"\ndelete_gauges = true\ndelete_counters = true\ndelete_sets = true\ndelete_timings = true\nmetric_separator = \"_\"\ndatadog_extensions = false\ndatadog_distributions = false\ndatadog_keep_container_tag = false\nallowed_pending_messages = 10000\npercentile_limit = 1000\n"
  },
  {
    "path": "migrations/inputs_statsd/testcases/deprecated_udp_packet_size/telegraf.conf",
    "content": "# Statsd Server\n[[inputs.statsd]]\n  ## Protocol, must be \"tcp\", \"udp4\", \"udp6\" or \"udp\" (default=udp)\n  protocol = \"udp\"\n\n  ## MaxTCPConnection - applicable when protocol is set to tcp (default=250)\n  max_tcp_connections = 250\n\n  ## Enable TCP keep alive probes (default=false)\n  tcp_keep_alive = false\n\n  ## Specifies the keep-alive period for an active network connection.\n  ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false.\n  ## Defaults to the OS configuration.\n  # tcp_keep_alive_period = \"2h\"\n\n  ## Address and port to host UDP listener on\n  service_address = \":8125\"\n\n  ## The following configuration options control when telegraf clears it's cache\n  ## of previous values. If set to false, then telegraf will only clear it's\n  ## cache when the daemon is restarted.\n  ## Reset gauges every interval (default=true)\n  delete_gauges = true\n  ## Reset counters every interval (default=true)\n  delete_counters = true\n  ## Reset sets every interval (default=true)\n  delete_sets = true\n  ## Reset timings & histograms every interval (default=true)\n  delete_timings = true\n\n  ## Enable aggregation temporality adds temporality=delta or temporality=commulative tag, and\n  ## start_time field, which adds the start time of the metric accumulation.\n  ## You should use this when using OpenTelemetry output.\n  # enable_aggregation_temporality = false\n\n  ## Percentiles to calculate for timing & histogram stats.\n  # percentiles = [50.0, 90.0, 99.0, 99.9, 99.95, 100.0]\n\n  ## separator to use between elements of a statsd metric\n  metric_separator = \"_\"\n\n  ## Parses extensions to statsd in the datadog statsd format\n  ## currently supports metrics and datadog tags.\n  ## http://docs.datadoghq.com/guides/dogstatsd/\n  datadog_extensions = false\n\n  ## Parses distributions metric as specified in the datadog statsd format\n  ## https://docs.datadoghq.com/developers/metrics/types/?tab=distribution#definition\n  datadog_distributions = false\n\n  ## Keep or drop the container id as tag. Included as optional field\n  ## in DogStatsD protocol v1.2 if source is running in Kubernetes\n  ## https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v12\n  datadog_keep_container_tag = false\n\n  ## Statsd data translation templates, more info can be read here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/TEMPLATE_PATTERN.md\n  # templates = [\n  #     \"cpu.* measurement*\"\n  # ]\n\n  ## Number of UDP messages allowed to queue up, once filled,\n  ## the statsd server will start dropping packets\n  allowed_pending_messages = 10000\n\n  ## Number of worker threads used to parse the incoming messages.\n  # number_workers_threads = 5\n\n  ## Number of timing/histogram values to track per-measurement in the\n  ## calculation of percentiles. Raising this limit increases the accuracy\n  ## of percentiles but also increases the memory usage and cpu time.\n  percentile_limit = 1000\n\n  ## Maximum socket buffer size in bytes, once the buffer fills up, metrics\n  ## will start dropping.  Defaults to the OS default.\n  # read_buffer_size = 65535\n\n  ## Max duration (TTL) for each metric to stay cached/reported without being updated.\n  # max_ttl = \"10h\"\n\n  ## Sanitize name method\n  ## By default, telegraf will pass names directly as they are received.\n  ## However, upstream statsd now does sanitization of names which can be\n  ## enabled by using the \"upstream\" method option. This option will a) replace\n  ## white space with '_', replace '/' with '-', and remove characters not\n  ## matching 'a-zA-Z_\\-0-9\\.;='.\n  #sanitize_name_method = \"\"\n\n  ## Replace dots (.) with underscore (_) and dashes (-) with\n  ## double underscore (__) in metric names.\n  # convert_names = false\n\n  ## Convert all numeric counters to float\n  ## Enabling this would ensure that both counters and guages are both emitted\n  ## as floats.\n  # float_counters = false\n\n  ## Emit timings `metric_<name>_count` field as float, the same as all other\n  ## histogram fields\n  # float_timings = false\n\n  ## Emit sets as float\n  # float_sets = false\n\n  udp_packet_size = 65535"
  },
  {
    "path": "migrations/inputs_tcp_listener/README.md",
    "content": ""
  },
  {
    "path": "migrations/inputs_tcp_listener/migration.go",
    "content": "package inputs_tcp_listener\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nconst allowPendingMessagesMsg = `\n    Replacement 'inputs.socket_listener' does not allow to configure\n    'allowed_pending_messages' and thus the setting is dropped.\n`\n\n// Define \"old\" data structure\ntype tcpListener map[string]interface{}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old tcpListener\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Copy the setting except the special plugin ones to preserve\n\t// all parser settings of the existing (deprecated) config.\n\tvar msg string\n\tplugin := make(map[string]interface{}, len(old))\n\tfor k, v := range old {\n\t\tswitch k {\n\t\tcase \"service_address\":\n\t\t\taddr, ok := v.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"service_address is not a string but %T\", v)\n\t\t\t}\n\t\t\tplugin[\"service_address\"] = \"tcp://\" + addr\n\t\tcase \"allowed_pending_messages\":\n\t\t\tmsg = allowPendingMessagesMsg\n\t\tcase \"max_tcp_connections\":\n\t\t\tplugin[\"max_connections\"] = v\n\t\tdefault:\n\t\t\tplugin[k] = v\n\t\t}\n\t}\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"socket_listener\")\n\tcfg.Add(\"inputs\", \"socket_listener\", plugin)\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.tcp_listener\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_tcp_listener/migration_test.go",
    "content": "package inputs_tcp_listener_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_tcp_listener\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/socket_listener\" // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"            // register parsers\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/allow_pending_messages/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"tcp://127.0.0.1:8000\"\ndata_format = \"influx\""
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/allow_pending_messages/telegraf.conf",
    "content": "[[inputs.tcp_listener]]\n  service_address = \"127.0.0.1:8000\"\n  allowed_pending_messages = 1000\n\n  data_format = \"influx\""
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/parser/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"tcp://127.0.0.1:8000\"\ndata_format = \"xpath_json\"\nxpath_native_types = true\n[[inputs.socket_listener.xpath]]\nmetric_name = \"/name\"\ntimestamp = \"/timestamp\"\ntimestamp_format = \"unix_ms\"\nfield_selection = \"/fields/*\"\ntag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/parser/telegraf.conf",
    "content": "[[inputs.tcp_listener]]\n  service_address = \"127.0.0.1:8000\"\n\n  data_format = \"xpath_json\"\n  xpath_native_types = true\n\n  # Configuration matching the first (ENERGY) message\n  [[inputs.tcp_listener.xpath]]\n    metric_name = \"/name\"\n    timestamp = \"/timestamp\"\n    timestamp_format = \"unix_ms\"\n    field_selection = \"/fields/*\"\n    tag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/simple/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"tcp://127.0.0.1:8000\"\ndata_format = \"influx\""
  },
  {
    "path": "migrations/inputs_tcp_listener/testcases/simple/telegraf.conf",
    "content": "[[inputs.tcp_listener]]\n  service_address = \"127.0.0.1:8000\"\n\n  data_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/README.md",
    "content": ""
  },
  {
    "path": "migrations/inputs_udp_listener/migration.go",
    "content": "package inputs_udp_listener\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nconst allowPendingMessagesMsg = `\n    Replacement 'inputs.socket_listener' does not allow to configure\n    'allowed_pending_messages' and thus the setting will be dropped.\n`\n\nconst udpPacketSizeMsg = `\n    The deprecated 'udp_buffer_size' setting will be dropped.\n`\n\n// Define \"old\" data structure\ntype udpListener map[string]interface{}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old udpListener\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Copy the setting except the special plugin ones to preserve\n\t// all parser settings of the existing (deprecated) config.\n\tvar msg string\n\tplugin := make(map[string]interface{}, len(old))\n\tfor k, v := range old {\n\t\tswitch k {\n\t\tcase \"service_address\":\n\t\t\taddr, ok := v.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"service_address is not a string but %T\", v)\n\t\t\t}\n\t\t\tplugin[\"service_address\"] = \"udp://\" + addr\n\t\tcase \"allowed_pending_messages\":\n\t\t\tmsg += allowPendingMessagesMsg\n\t\tcase \"udp_packet_size\":\n\t\t\tmsg += udpPacketSizeMsg\n\t\tcase \"udp_buffer_size\":\n\t\t\tplugin[\"read_buffer_size\"] = v\n\t\tdefault:\n\t\t\tplugin[k] = v\n\t\t}\n\t}\n\n\t// Create the corresponding metric configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"socket_listener\")\n\tcfg.Add(\"inputs\", \"socket_listener\", plugin)\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, msg, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"inputs.udp_listener\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_udp_listener/migration_test.go",
    "content": "package inputs_udp_listener_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_udp_listener\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/inputs/socket_listener\" // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"            // register parsers\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/all_deprecated_messages/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"udp://127.0.0.1:8000\"\ndata_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/all_deprecated_messages/telegraf.conf",
    "content": "[[inputs.udp_listener]]\n  service_address = \"127.0.0.1:8000\"\n  allowed_pending_messages = 1000\n  udp_packet_size = 1024\n  data_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/allow_pending_messages/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"udp://127.0.0.1:8000\"\ndata_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/allow_pending_messages/telegraf.conf",
    "content": "[[inputs.udp_listener]]\n  service_address = \"127.0.0.1:8000\"\n  allowed_pending_messages = 1000\n\n  data_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/parser/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"udp://127.0.0.1:8000\"\ndata_format = \"xpath_json\"\nxpath_native_types = true\n[[inputs.socket_listener.xpath]]\nmetric_name = \"/name\"\ntimestamp = \"/timestamp\"\ntimestamp_format = \"unix_ms\"\nfield_selection = \"/fields/*\"\ntag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/parser/telegraf.conf",
    "content": "[[inputs.udp_listener]]\n  service_address = \"127.0.0.1:8000\"\n\n  data_format = \"xpath_json\"\n  xpath_native_types = true\n\n  # Configuration matching the first (ENERGY) message\n  [[inputs.udp_listener.xpath]]\n    metric_name = \"/name\"\n    timestamp = \"/timestamp\"\n    timestamp_format = \"unix_ms\"\n    field_selection = \"/fields/*\"\n    tag_selection = \"/tags/*\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/simple/expected.conf",
    "content": "[[inputs.socket_listener]]\nservice_address = \"udp://127.0.0.1:8000\"\ndata_format = \"influx\""
  },
  {
    "path": "migrations/inputs_udp_listener/testcases/simple/telegraf.conf",
    "content": "[[inputs.udp_listener]]\n  service_address = \"127.0.0.1:8000\"\n\n  data_format = \"influx\""
  },
  {
    "path": "migrations/inputs_vsphere/migration.go",
    "content": "package inputs_vsphere\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif _, found := plugin[\"force_discover_on_init\"]; found {\n\t\tapplied = true\n\n\t\t// Remove the deprecated option as it is ignored in the code\n\t\tdelete(plugin, \"force_discover_on_init\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"inputs\", \"vsphere\")\n\tcfg.Add(\"inputs\", \"vsphere\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"inputs.vsphere\", migrate)\n}\n"
  },
  {
    "path": "migrations/inputs_vsphere/migration_test.go",
    "content": "package inputs_vsphere_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/inputs_vsphere\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/inputs/vsphere\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &vsphere.VSphere{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Inputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/inputs_vsphere/testcases/deprecated_force_discover_on_init/expected.conf",
    "content": "[[inputs.vsphere]]\nhost_metric_include = [\"*\"]\npassword = \"secret\"\nusername = \"user@corp.local\"\nvcenters = [\"https://vcenter.local/sdk\"]\nvm_metric_include = [\"*\"]\n"
  },
  {
    "path": "migrations/inputs_vsphere/testcases/deprecated_force_discover_on_init/telegraf.conf",
    "content": "# Read metrics from one or many vCenters\n[[inputs.vsphere]]\n  ## List of vCenter URLs to be monitored. These three lines must be uncommented\n  ## and edited for the plugin to work.\n  vcenters = [ \"https://vcenter.local/sdk\" ]\n  username = \"user@corp.local\"\n  password = \"secret\"\n\n  ## VMs\n  ## Typical VM metrics (if omitted or empty, all metrics are collected)\n  # vm_include = [ \"/*/vm/**\"] # Inventory path to VMs to collect (by default all are collected)\n  # vm_exclude = [] # Inventory paths to exclude\n  vm_metric_include = [\"*\"]\n  # vm_metric_exclude = [] ## Nothing is excluded by default\n  # vm_instances = true ## true by default\n\n  ## Hosts\n  ## Typical host metrics (if omitted or empty, all metrics are collected)\n  # host_include = [ \"/*/host/**\"] # Inventory path to hosts to collect (by default all are collected)\n  # host_exclude [] # Inventory paths to exclude\n  host_metric_include = [\"*\"]\n    ## Collect IP addresses? Valid values are \"ipv4\" and \"ipv6\"\n  # ip_addresses = [\"ipv6\", \"ipv4\" ]\n\n  # host_metric_exclude = [] ## Nothing excluded by default\n  # host_instances = true ## true by default\n\n\n  ## Clusters\n  # cluster_include = [ \"/*/host/**\"] # Inventory path to clusters to collect (by default all are collected)\n  # cluster_exclude = [] # Inventory paths to exclude\n  # cluster_metric_include = [] ## if omitted or empty, all metrics are collected\n  # cluster_metric_exclude = [] ## Nothing excluded by default\n  # cluster_instances = false ## false by default\n\n  ## Resource Pools\n  # resource_pool_include = [ \"/*/host/**\"] # Inventory path to resource pools to collect (by default all are collected)\n  # resource_pool_exclude = [] # Inventory paths to exclude\n  # resource_pool_metric_include = [] ## if omitted or empty, all metrics are collected\n  # resource_pool_metric_exclude = [] ## Nothing excluded by default\n  # resource_pool_instances = false ## false by default\n\n  ## Datastores\n  # datastore_include = [ \"/*/datastore/**\"] # Inventory path to datastores to collect (by default all are collected)\n  # datastore_exclude = [] # Inventory paths to exclude\n  # datastore_metric_include = [] ## if omitted or empty, all metrics are collected\n  # datastore_metric_exclude = [] ## Nothing excluded by default\n  # datastore_instances = false ## false by default\n\n  ## Datacenters\n  # datacenter_include = [ \"/*/host/**\"] # Inventory path to clusters to collect (by default all are collected)\n  # datacenter_exclude = [] # Inventory paths to exclude\n  # datacenter_metric_include = [] ## if omitted or empty, all metrics are collected\n  # datacenter_metric_exclude = [ \"*\" ] ## Datacenters are not collected by default.\n  # datacenter_instances = false ## false by default\n\n  ## VSAN\n  # vsan_metric_include = [] ## if omitted or empty, all metrics are collected\n  # vsan_metric_exclude = [ \"*\" ] ## vSAN are not collected by default.\n  ## Whether to skip verifying vSAN metrics against the ones from GetSupportedEntityTypes API.\n  # vsan_metric_skip_verify = false ## false by default.\n\n  ## Interval for sampling vSAN performance metrics, can be reduced down to\n  ## 30 seconds for vSAN 8 U1.\n  # vsan_interval = \"5m\"\n\n  ## Plugin Settings\n  ## separator character to use for measurement and field names (default: \"_\")\n  # separator = \"_\"\n\n  ## number of objects to retrieve per query for realtime resources (vms and hosts)\n  ## set to 64 for vCenter 5.5 and 6.0 (default: 256)\n  # max_query_objects = 256\n\n  ## number of metrics to retrieve per query for non-realtime resources (clusters and datastores)\n  ## set to 64 for vCenter 5.5 and 6.0 (default: 256)\n  # max_query_metrics = 256\n\n  ## number of go routines to use for collection and discovery of objects and metrics\n  # collect_concurrency = 1\n  # discover_concurrency = 1\n\n  ## the interval before (re)discovering objects subject to metrics collection (default: 300s)\n  # object_discovery_interval = \"300s\"\n\n  ## timeout applies to any of the api request made to vcenter\n  # timeout = \"60s\"\n\n  ## When set to true, all samples are sent as integers. This makes the output\n  ## data types backwards compatible with Telegraf 1.9 or lower. Normally all\n  ## samples from vCenter, with the exception of percentages, are integer\n  ## values, but under some conditions, some averaging takes place internally in\n  ## the plugin. Setting this flag to \"false\" will send values as floats to\n  ## preserve the full precision when averaging takes place.\n  # use_int_samples = true\n\n  ## Custom attributes from vCenter can be very useful for queries in order to slice the\n  ## metrics along different dimension and for forming ad-hoc relationships. They are disabled\n  ## by default, since they can add a considerable amount of tags to the resulting metrics. To\n  ## enable, simply set custom_attribute_exclude to [] (empty set) and use custom_attribute_include\n  ## to select the attributes you want to include.\n  ## By default, since they can add a considerable amount of tags to the resulting metrics. To\n  ## enable, simply set custom_attribute_exclude to [] (empty set) and use custom_attribute_include\n  ## to select the attributes you want to include.\n  # custom_attribute_include = []\n  # custom_attribute_exclude = [\"*\"]\n\n  ## The number of vSphere 5 minute metric collection cycles to look back for non-realtime metrics. In\n  ## some versions (6.7, 7.0 and possible more), certain metrics, such as cluster metrics, may be reported\n  ## with a significant delay (>30min). If this happens, try increasing this number. Please note that increasing\n  ## it too much may cause performance issues.\n  # metric_lookback = 3\n\n  ## Optional SSL Config\n  # ssl_ca = \"/path/to/cafile\"\n  # ssl_cert = \"/path/to/certfile\"\n  # ssl_key = \"/path/to/keyfile\"\n  ## Use SSL but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## The Historical Interval value must match EXACTLY the interval in the daily\n  # \"Interval Duration\" found on the VCenter server under Configure > General > Statistics > Statistic intervals\n  # historical_interval = \"5m\"\n\n  ## Specifies plugin behavior regarding disconnected servers\n  ## Available choices :\n  ##   - error: telegraf will return an error on startup if one the servers is unreachable\n  ##   - ignore: telegraf will ignore unreachable servers on both startup and gather\n  # disconnected_servers_behavior = \"error\"\n\n  ## HTTP Proxy support\n  # use_system_proxy = true\n  # http_proxy_url = \"\"\n\n  force_discover_on_init = true"
  },
  {
    "path": "migrations/outputs_amqp/migration.go",
    "content": "package outputs_amqp\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\nconst messagePrefix = \"could not migrate one or more options from the 'outputs.amqp' plugin:\"\n\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tvar applied bool\n\tmessage := messagePrefix\n\n\tif db, found := plugin[\"database\"]; found {\n\t\theaders := getHeaders(plugin)\n\n\t\tif _, found := headers[\"database\"]; found {\n\t\t\tmessage += \" 'database' (already set in headers)\"\n\t\t} else {\n\t\t\theaders[\"database\"] = db.(string)\n\t\t\tdelete(plugin, \"database\")\n\t\t\tapplied = true\n\t\t}\n\t}\n\n\tif rp, found := plugin[\"retention_policy\"]; found {\n\t\theaders := getHeaders(plugin)\n\n\t\tif _, found := headers[\"retention_policy\"]; found {\n\t\t\tmessage += \" 'retention_policy' (already set in headers)\"\n\t\t} else {\n\t\t\theaders[\"retention_policy\"] = rp.(string)\n\t\t\tdelete(plugin, \"retention_policy\")\n\t\t\tapplied = true\n\t\t}\n\t}\n\n\t// Delete precision if it exists, as it is no longer used\n\tif _, found := plugin[\"precision\"]; found {\n\t\tapplied = true\n\t\tdelete(plugin, \"precision\")\n\t}\n\n\tif url, found := plugin[\"url\"]; found {\n\t\tbrokers := getBrokers(plugin)\n\t\tplugin[\"brokers\"] = append(brokers, url.(string))\n\t\tdelete(plugin, \"url\")\n\t\tapplied = true\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"amqp\")\n\tcfg.Add(\"outputs\", \"amqp\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\n\tif message == messagePrefix {\n\t\t// No options failed to migrate, so we can return an empty message\n\t\treturn output, \"\", err\n\t}\n\t// Some options failed to migrate, so we return the message\n\treturn output, message, err\n}\n\nfunc getHeaders(plugin map[string]interface{}) map[string]string {\n\tvar headers map[string]string\n\tif raw, found := plugin[\"headers\"]; found {\n\t\theaders = raw.(map[string]string)\n\t} else {\n\t\theaders = make(map[string]string, 1)\n\t\tplugin[\"headers\"] = headers\n\t}\n\treturn headers\n}\n\nfunc getBrokers(plugin map[string]interface{}) []interface{} {\n\tvar brokers []interface{}\n\tif raw, found := plugin[\"brokers\"]; found {\n\t\tbrokers = raw.([]interface{})\n\t} else {\n\t\tbrokers = make([]interface{}, 1)\n\t\tplugin[\"brokers\"] = brokers\n\t}\n\treturn brokers\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"outputs.amqp\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_amqp/migration_test.go",
    "content": "package outputs_amqp_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_amqp\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/amqp\"    // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/all\" // register serializers\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatchf(t, expectedIDs, actualIDs, \"generated config: %s\", string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_amqp/testcases/minimal/expected.conf",
    "content": "# Publishes metrics to an AMQP broker\n[[outputs.amqp]]\n  ## Brokers to publish to.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\"]\n\n  headers = {\"database\" = \"db\", \"retention_policy\" = \"rp\"}\n\n  ## Exchange to declare and publish to.\n  exchange = \"telegraf\""
  },
  {
    "path": "migrations/outputs_amqp/testcases/minimal/telegraf.conf",
    "content": "# Publishes metrics to an AMQP broker\n[[outputs.amqp]]\n  ## Brokers to publish to.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = []\n\n  url = \"amqp://localhost:5672/influxdb\"\n\n  precision = \"something\"\n\n  database = \"db\"\n  retention_policy = \"rp\"\n\n  ## Exchange to declare and publish to.\n  exchange = \"telegraf\""
  },
  {
    "path": "migrations/outputs_influxdb/migration.go",
    "content": "package outputs_influxdb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\n\t// Migrate url -> urls\n\tif oldURL, found := plugin[\"url\"]; found {\n\t\tapplied = true\n\n\t\tvar urls []string\n\t\t// Merge the old URL and the new URLs with deduplication\n\t\tif newURLs, found := plugin[\"urls\"]; found {\n\t\t\tvar err error\n\t\t\turls, err = migrations.AsStringSlice(newURLs)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"'urls' setting: %w\", err)\n\t\t\t}\n\t\t}\n\t\tou, ok := oldURL.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected 'url' entry %v (%T)\", ou, ou)\n\t\t}\n\n\t\tif !choice.Contains(ou, urls) {\n\t\t\turls = append(urls, ou)\n\t\t}\n\n\t\t// Update replacement and remove the deprecated setting\n\t\tplugin[\"urls\"] = urls\n\t\tdelete(plugin, \"url\")\n\t}\n\n\t// Remove the deprecated precision option (it has been ignored since 1.0.0)\n\tif _, found := plugin[\"precision\"]; found {\n\t\tapplied = true\n\t\t// Remove the deprecated setting\n\t\tdelete(plugin, \"precision\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"influxdb\")\n\tcfg.Add(\"outputs\", \"influxdb\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.influxdb\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_influxdb/migration_test.go",
    "content": "package outputs_influxdb_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_influxdb\" // register migration\n\t\"github.com/influxdata/telegraf/plugins/outputs/influxdb\"      // register plugin\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &influxdb.InfluxDB{}\n\tdefaultCfg := []byte(plugin.SampleConfig())\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(defaultCfg)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, string(defaultCfg), string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/convert_url/expected.conf",
    "content": "[[outputs.influxdb]]\nurls = [\"http://127.0.0.1:8086\"]\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/convert_url/telegraf.conf",
    "content": "# Configuration for sending metrics to InfluxDB\n[[outputs.influxdb]]\n  url = \"http://127.0.0.1:8086\"\n  ## The full HTTP or UDP URL for your InfluxDB instance.\n  ##\n  ## Multiple URLs can be specified for a single cluster, only ONE of the\n  ## urls will be written to each interval.\n  # urls = [\"unix:///var/run/influxdb.sock\"]\n  # urls = [\"udp://127.0.0.1:8089\"]\n  # urls = [\"http://127.0.0.1:8086\"]\n\n  ## The target database for metrics; will be created as needed.\n  ## For UDP url endpoint database needs to be configured on server side.\n  # database = \"telegraf\"\n\n  ## The value of this tag will be used to determine the database.  If this\n  ## tag is not set the 'database' option is used as the default.\n  # database_tag = \"\"\n\n  ## If true, the 'database_tag' will not be included in the written metric.\n  # exclude_database_tag = false\n\n  ## If true, no CREATE DATABASE queries will be sent.  Set to true when using\n  ## Telegraf with a user without permissions to create databases or when the\n  ## database already exists.\n  # skip_database_creation = false\n\n  ## Name of existing retention policy to write to.  Empty string writes to\n  ## the default retention policy.  Only takes effect when using HTTP.\n  # retention_policy = \"\"\n\n  ## The value of this tag will be used to determine the retention policy.  If this\n  ## tag is not set the 'retention_policy' option is used as the default.\n  # retention_policy_tag = \"\"\n\n  ## If true, the 'retention_policy_tag' will not be included in the written metric.\n  # exclude_retention_policy_tag = false\n\n  ## Write consistency (clusters only), can be: \"any\", \"one\", \"quorum\", \"all\".\n  ## Only takes effect when using HTTP.\n  # write_consistency = \"any\"\n\n  ## Timeout for HTTP messages.\n  # timeout = \"5s\"\n\n  ## HTTP Basic Auth\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## HTTP User-Agent\n  # user_agent = \"telegraf\"\n\n  ## UDP payload size is the maximum packet size to send.\n  # udp_payload = \"512B\"\n\n  ## Optional TLS Config for use on HTTP connections.\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP Proxy override, if unset values the standard proxy environment\n  ## variables are consulted to determine which proxy, if any, should be used.\n  # http_proxy = \"http://corporate.proxy:3128\"\n\n  ## Additional HTTP headers\n  # http_headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"gzip\"\n\n  ## When true, Telegraf will output unsigned integers as unsigned values,\n  ## i.e.: \"42u\".  You will need a version of InfluxDB supporting unsigned\n  ## integer values.  Enabling this option will result in field type errors if\n  ## existing data has been written.\n  # influx_uint_support = false\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/deprecated_precision/expected.conf",
    "content": "[[outputs.influxdb]]\n  urls = [\"http://localhost:8086\"]\n  database = \"telegraf\"\n  username = \"telegraf\"\n  password = \"metricsmetricsmetricsmetrics\"\n  timeout = \"5s\"\n  content_encoding = \"gzip\""
  },
  {
    "path": "migrations/outputs_influxdb/testcases/deprecated_precision/telegraf.conf",
    "content": "[[outputs.influxdb]]\n  urls = [\"http://localhost:8086\"]\n  database = \"telegraf\"\n  username = \"telegraf\"\n  password = \"metricsmetricsmetricsmetrics\"\n  precision = \"s\"\n  timeout = \"5s\"\n  content_encoding = \"gzip\""
  },
  {
    "path": "migrations/outputs_influxdb/testcases/merge_url/expected.conf",
    "content": "[[outputs.influxdb]]\nnamepass = [\"metrics\"]\nurls = [\"udp://127.0.0.1:8089\", \"http://127.0.0.1:8086\"]\ndatabase_tag = \"table\"\nskip_database_creation = true\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/merge_url/telegraf.conf",
    "content": "# Configuration for sending metrics to InfluxDB\n[[outputs.influxdb]]\n  namepass = [\"metrics\"]\n  url = \"http://127.0.0.1:8086\"\n  urls = [\"udp://127.0.0.1:8089\"]\n  database_tag = \"table\"\n  skip_database_creation = true\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/merge_url_overlap/expected.conf",
    "content": "[[outputs.influxdb]]\nnamepass = [\"metrics\"]\nurls = [\"http://127.0.0.1:8086\", \"udp://127.0.0.1:8089\"]\ndatabase_tag = \"table\"\nskip_database_creation = true\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/merge_url_overlap/telegraf.conf",
    "content": "# Configuration for sending metrics to InfluxDB\n[[outputs.influxdb]]\n  namepass = [\"metrics\"]\n  url = \"http://127.0.0.1:8086\"\n  urls = [\"http://127.0.0.1:8086\", \"udp://127.0.0.1:8089\"]\n  database_tag = \"table\"\n  skip_database_creation = true\n"
  },
  {
    "path": "migrations/outputs_influxdb/testcases/url_and_precision/expected.conf",
    "content": "[[outputs.influxdb]]\n  urls = [\"http://localhost:8086\"]\n  database = \"telegraf\"\n  username = \"telegraf\"\n  password = \"metricsmetricsmetricsmetrics\"\n  timeout = \"5s\"\n  content_encoding = \"gzip\""
  },
  {
    "path": "migrations/outputs_influxdb/testcases/url_and_precision/telegraf.conf",
    "content": "[[outputs.influxdb]]\n  url = \"http://localhost:8086\"\n  database = \"telegraf\"\n  username = \"telegraf\"\n  password = \"metricsmetricsmetricsmetrics\"\n  precision = \"ns\"\n  timeout = \"5s\"\n  content_encoding = \"gzip\""
  },
  {
    "path": "migrations/outputs_kinesis/migration.go",
    "content": "package outputs_kinesis\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Find the partition configuration\n\tnewPartition, err := getPartition(plugin)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawOldPartitionKey, found := plugin[\"partitionkey\"]; found {\n\t\t// Convert the options to the actual type\n\t\toldPartitionKey, ok := rawOldPartitionKey.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'partitionkey'\", rawOldPartitionKey)\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are conflicting.\n\t\tif rawNewPartitionKey, found := newPartition[\"key\"]; found {\n\t\t\tif newPartitionKey, ok := rawNewPartitionKey.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'partition.key'\", rawNewPartitionKey)\n\t\t\t} else if oldPartitionKey != newPartitionKey {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'partitionkey' and 'partition.key'\")\n\t\t\t}\n\t\t}\n\t\tapplied = true\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tnewPartition[\"key\"] = oldPartitionKey\n\t\tdelete(plugin, \"partitionkey\")\n\n\t\t// Check for 'use_random_partitionkey' option, which will only be set in a valid way if 'partitionkey' was set\n\t\tvar oldRandomKey bool\n\t\tif rawOldRandomKey, found := plugin[\"use_random_partitionkey\"]; found {\n\t\t\t// Convert the options to the actual type\n\t\t\toldRandomKey, ok = rawOldRandomKey.(bool)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'use_random_partitionkey'\", rawOldRandomKey)\n\t\t\t}\n\t\t} else {\n\t\t\t// If the option is not set, we assume the old value is false\n\t\t\toldRandomKey = false\n\t\t}\n\n\t\t// Check if the new setting is present and if so, check if the values are conflicting.\n\t\tif rawNewMethod, found := newPartition[\"method\"]; found {\n\t\t\tif newMethod, ok := rawNewMethod.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'datacenter'\", rawNewMethod)\n\t\t\t} else if (oldRandomKey && newMethod != \"random\") || (!oldRandomKey && newMethod != \"static\") {\n\t\t\t\t// If old random key is true, method is expected to be \"random\"\n\t\t\t\t// If old random key is false, method is expected to be \"static\"\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'use_random_partitionkey' and 'partition.method'\")\n\t\t\t}\n\t\t}\n\n\t\t// Remove the deprecated option and replace the modified one\n\t\tif oldRandomKey {\n\t\t\tnewPartition[\"method\"] = \"random\"\n\t\t} else {\n\t\t\tnewPartition[\"method\"] = \"static\"\n\t\t}\n\t\tdelete(plugin, \"use_random_partitionkey\")\n\t}\n\n\t// Just in case, check if 'use_random_partitionkey' is set without 'partitionkey' somehow\n\tif _, found := plugin[\"use_random_partitionkey\"]; found {\n\t\tdelete(plugin, \"use_random_partitionkey\")\n\t\tapplied = true\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"kinesis\")\n\tcfg.Add(\"outputs\", \"kinesis\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\nfunc getPartition(plugin map[string]interface{}) (map[string]interface{}, error) {\n\trawPartition := plugin[\"partition\"]\n\tif rawPartition == nil {\n\t\t// Create a new partition if it does not exist\n\t\tpartition := make(map[string]interface{})\n\t\tplugin[\"partition\"] = partition\n\t\treturn partition, nil\n\t}\n\n\tpartition, ok := rawPartition.(map[string]interface{})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected type %T for 'partition'\", rawPartition)\n\t}\n\n\treturn partition, nil\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.kinesis\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_kinesis/migration_test.go",
    "content": "package outputs_kinesis_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_kinesis\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/kinesis\"    // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/influx\" // register serializer\n)\n\nfunc TestPartitionKeyConflict(t *testing.T) {\n\tcfg := []byte(`\n[[outputs.kinesis]]\n  partitionkey = \"test_key\"\n  [outputs.kinesis.partition]\n    key = \"test_key2\"\n    method = \"static\"\n\t`)\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'partitionkey' and 'partition.key'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestPartitionMethodConflict(t *testing.T) {\n\tcfg := []byte(`\n[[outputs.kinesis]]\n  partitionkey = \"test_key\"\n  [outputs.kinesis.partition]\n    key = \"test_key\"\n    method = \"random\"\n\t`)\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.ErrorContains(t, err, \"contradicting setting for 'use_random_partitionkey' and 'partition.method'\")\n\trequire.Empty(t, output)\n\trequire.Zero(t, n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/only_randomkey_set/expected.conf",
    "content": "[[outputs.kinesis]]\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/only_randomkey_set/telegraf.conf",
    "content": "[[outputs.kinesis]]\n\n  use_random_partitionkey = true\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/randomkey_not_set/expected.conf",
    "content": "[[outputs.kinesis]]\n\n  [outputs.kinesis.partition]\n    key = \"some_key\"\n    method = \"static\"\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/randomkey_not_set/telegraf.conf",
    "content": "[[outputs.kinesis]]\n\n  partitionkey = \"some_key\"\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/randomkey_set/expected.conf",
    "content": "[[outputs.kinesis]]\n\n  [outputs.kinesis.partition]\n    key = \"some_key\"\n    method = \"random\"\n"
  },
  {
    "path": "migrations/outputs_kinesis/testcases/randomkey_set/telegraf.conf",
    "content": "[[outputs.kinesis]]\n\n  partitionkey = \"some_key\"\n  use_random_partitionkey = true\n"
  },
  {
    "path": "migrations/outputs_librato/migration.go",
    "content": "package outputs_librato\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawSourceTag, found := plugin[\"source_tag\"]; found {\n\t\t// Convert the options to the actual type\n\t\tsourceTag, ok := rawSourceTag.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'source_tag'\", rawSourceTag)\n\t\t}\n\n\t\tif rawTemplate, found := plugin[\"template\"]; found {\n\t\t\tif template, ok := rawTemplate.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'template'\", rawTemplate)\n\t\t\t} else if sourceTag != template {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'source_tag' and 'template'\")\n\t\t\t}\n\t\t}\n\n\t\tapplied = true\n\t\tplugin[\"template\"] = sourceTag\n\t\tdelete(plugin, \"source_tag\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"librato\")\n\tcfg.Add(\"outputs\", \"librato\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.librato\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_librato/migration_test.go",
    "content": "package outputs_librato_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_librato\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/librato\"    // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_librato/testcases/simple/expected.conf",
    "content": "[[outputs.librato]]\n  template = \"some_template\"\n"
  },
  {
    "path": "migrations/outputs_librato/testcases/simple/telegraf.conf",
    "content": "[[outputs.librato]]\n  source_tag = \"some_template\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/migration.go",
    "content": "package outputs_mqtt\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tvar message string\n\tif rawOldTopicPrefix, found := plugin[\"topic_prefix\"]; found {\n\t\tapplied = true\n\n\t\t// Convert the options to the actual type\n\t\toldTopicPrefix, ok := rawOldTopicPrefix.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'topic_prefix'\", rawOldTopicPrefix)\n\t\t}\n\n\t\t// Check if the prefix is already set, otherwise prepend it and inform\n\t\t// the users that we modified the topic to make them aware.\n\t\tif rawNewTopic, found := plugin[\"topic\"]; found {\n\t\t\tif newTopic, ok := rawNewTopic.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'topic'\", rawNewTopic)\n\t\t\t} else if !strings.HasPrefix(newTopic, oldTopicPrefix) && !strings.HasPrefix(newTopic, \"/\"+oldTopicPrefix) {\n\t\t\t\tplugin[\"topic\"] = oldTopicPrefix + \"/\" + newTopic\n\t\t\t\tmessage = \"added deprecated 'topic_prefix' to existing 'topic'; please check the new setting\"\n\t\t\t}\n\t\t} else {\n\t\t\tplugin[\"topic\"] = oldTopicPrefix\n\t\t}\n\n\t\t// Remove the deprecated option\n\t\tdelete(plugin, \"topic_prefix\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"mqtt\")\n\tcfg.Add(\"outputs\", \"mqtt\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, message, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.mqtt\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_mqtt/migration_test.go",
    "content": "package outputs_mqtt_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_mqtt\"    // register migration\n\t\"github.com/influxdata/telegraf/plugins/outputs/mqtt\"         // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/influx\" // register serializer\n)\n\nfunc TestNoMigration(t *testing.T) {\n\tplugin := &mqtt.MQTT{}\n\tdefaultCfg := plugin.SampleConfig()\n\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations([]byte(defaultCfg))\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, output)\n\trequire.Zero(t, n)\n\trequire.Equal(t, defaultCfg, string(output))\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Inputs, len(expected.Inputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Inputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Inputs))\n\t\t\tfor i := range actual.Inputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Inputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Inputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix/expected.conf",
    "content": "[[outputs.mqtt]]\nservers = [\"localhost:1883\"]\ntopic = 'telegraf'\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix/telegraf.conf",
    "content": "# Configuration for MQTT server to send metrics to\n[[outputs.mqtt]]\n  ## MQTT Brokers\n  ## The list of brokers should only include the hostname or IP address and the\n  ## port to the broker. This should follow the format `[{scheme}://]{host}:{port}`. For\n  ## example, `localhost:1883` or `mqtt://localhost:1883`.\n  ## Scheme can be any of the following: tcp://, mqtt://, tls://, mqtts://\n  ## non-TLS and TLS servers can not be mix-and-matched.\n  servers = [\"localhost:1883\", ] # or [\"mqtts://tls.example.com:1883\"]\n\n  ## Protocol can be `3.1.1` or `5`. Default is `3.1.1`\n  # protocol = \"3.1.1\"\n\n  ## MQTT Topic for Producer Messages\n  ## MQTT outputs send metrics to this topic format:\n  ## prefix/{{ .Tag \"host\" }}/{{ .Name }}/{{ .Tag \"tag_key\" }}\n  ## (e.g. prefix/web01.example.com/mem/some_tag_value)\n  ## Each path segment accepts either a template placeholder, an environment variable, or a tag key\n  ## of the form `{{.Tag \"tag_key_name\"}}`. All the functions provided by the Sprig library\n  ## (http://masterminds.github.io/sprig/) are available. Empty path elements as well as special MQTT\n  ## characters (such as `+` or `#`) are invalid to form the topic name and will lead to an error.\n  ## In case a tag is missing in the metric, that path segment omitted for the final topic.\n  topic_prefix = \"telegraf\"\n\n  ## QoS policy for messages\n  ## The mqtt QoS policy for sending messages.\n  ## See https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q029090_.htm\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  # qos = 2\n\n  ## Keep Alive\n  ## Defines the maximum length of time that the broker and client may not\n  ## communicate. Defaults to 0 which turns the feature off.\n  ##\n  ## For version v2.0.12 and later mosquitto there is a bug\n  ## (see https://github.com/eclipse/mosquitto/issues/2117), which requires\n  ## this to be non-zero. As a reference eclipse/paho.mqtt.golang defaults to 30.\n  # keep_alive = 0\n\n  ## username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## client ID\n  ## The unique client id to connect MQTT server. If this parameter is not set\n  ## then a random ID is generated.\n  # client_id = \"\"\n\n  ## Timeout for write operations. default: 5s\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## When true, metrics will be sent in one MQTT message per flush. Otherwise,\n  ## metrics are written one metric per MQTT message.\n  ## DEPRECATED: Use layout option instead\n  # batch = false\n\n  ## When true, metric will have RETAIN flag set, making broker cache entries until someone\n  ## actually reads it\n  # retain = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Layout of the topics published.\n  ## The following choices are available:\n  ##   non-batch -- send individual messages, one for each metric\n  ##   batch     -- send all metric as a single message per MQTT topic\n  ## NOTE: The following options will ignore the 'data_format' option and send single values\n  ##   field     -- send individual messages for each field, appending its name to the metric topic\n  ##   homie-v4  -- send metrics with fields and tags according to the 4.0.0 specs\n  ##                see https://homieiot.github.io/specification/\n  # layout = \"non-batch\"\n\n  ## HOMIE specific settings\n  ## The following options provide templates for setting the device name\n  ## and the node-ID for the topics. Both options are MANDATORY and can contain\n  ## {{ .Name }} (metric name), {{ .Tag \"key\"}} (tag reference to 'key') or\n  ## constant strings. The templates MAY NOT contain slashes!\n  # homie_device_name = \"\"\n  # homie_node_id = \"\"\n\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Optional MQTT 5 publish properties\n  ## These setting only apply if the \"protocol\" property is set to 5. This must\n  ## be defined at the end of the plugin settings, otherwise TOML will assume\n  ## anything else is part of this table. For more details on publish properties\n  ## see the spec:\n  ## https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109\n  # [outputs.mqtt.v5]\n  #   content_type = \"\"\n  #   response_topic = \"\"\n  #   message_expiry = \"0s\"\n  #   topic_alias = 0\n  # [outputs.mqtt.v5.user_properties]\n  #   \"key1\" = \"value 1\"\n  #   \"key2\" = \"value 2\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_duplicate/expected.conf",
    "content": "[[outputs.mqtt]]\nservers = [\"localhost:1883\"]\ntopic = 'telegraf/{{ .Tag \"host\" }}/{{ .Name }}'\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_duplicate/telegraf.conf",
    "content": "# Configuration for MQTT server to send metrics to\n[[outputs.mqtt]]\n  ## MQTT Brokers\n  ## The list of brokers should only include the hostname or IP address and the\n  ## port to the broker. This should follow the format `[{scheme}://]{host}:{port}`. For\n  ## example, `localhost:1883` or `mqtt://localhost:1883`.\n  ## Scheme can be any of the following: tcp://, mqtt://, tls://, mqtts://\n  ## non-TLS and TLS servers can not be mix-and-matched.\n  servers = [\"localhost:1883\", ] # or [\"mqtts://tls.example.com:1883\"]\n\n  ## Protocol can be `3.1.1` or `5`. Default is `3.1.1`\n  # protocol = \"3.1.1\"\n\n  ## MQTT Topic for Producer Messages\n  ## MQTT outputs send metrics to this topic format:\n  ## prefix/{{ .Tag \"host\" }}/{{ .Name }}/{{ .Tag \"tag_key\" }}\n  ## (e.g. prefix/web01.example.com/mem/some_tag_value)\n  ## Each path segment accepts either a template placeholder, an environment variable, or a tag key\n  ## of the form `{{.Tag \"tag_key_name\"}}`. All the functions provided by the Sprig library\n  ## (http://masterminds.github.io/sprig/) are available. Empty path elements as well as special MQTT\n  ## characters (such as `+` or `#`) are invalid to form the topic name and will lead to an error.\n  ## In case a tag is missing in the metric, that path segment omitted for the final topic.\n  topic = 'telegraf/{{ .Tag \"host\" }}/{{ .Name }}'\n  topic_prefix = \"telegraf\"\n\n  ## QoS policy for messages\n  ## The mqtt QoS policy for sending messages.\n  ## See https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q029090_.htm\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  # qos = 2\n\n  ## Keep Alive\n  ## Defines the maximum length of time that the broker and client may not\n  ## communicate. Defaults to 0 which turns the feature off.\n  ##\n  ## For version v2.0.12 and later mosquitto there is a bug\n  ## (see https://github.com/eclipse/mosquitto/issues/2117), which requires\n  ## this to be non-zero. As a reference eclipse/paho.mqtt.golang defaults to 30.\n  # keep_alive = 0\n\n  ## username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## client ID\n  ## The unique client id to connect MQTT server. If this parameter is not set\n  ## then a random ID is generated.\n  # client_id = \"\"\n\n  ## Timeout for write operations. default: 5s\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## When true, metrics will be sent in one MQTT message per flush. Otherwise,\n  ## metrics are written one metric per MQTT message.\n  ## DEPRECATED: Use layout option instead\n  # batch = false\n\n  ## When true, metric will have RETAIN flag set, making broker cache entries until someone\n  ## actually reads it\n  # retain = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Layout of the topics published.\n  ## The following choices are available:\n  ##   non-batch -- send individual messages, one for each metric\n  ##   batch     -- send all metric as a single message per MQTT topic\n  ## NOTE: The following options will ignore the 'data_format' option and send single values\n  ##   field     -- send individual messages for each field, appending its name to the metric topic\n  ##   homie-v4  -- send metrics with fields and tags according to the 4.0.0 specs\n  ##                see https://homieiot.github.io/specification/\n  # layout = \"non-batch\"\n\n  ## HOMIE specific settings\n  ## The following options provide templates for setting the device name\n  ## and the node-ID for the topics. Both options are MANDATORY and can contain\n  ## {{ .Name }} (metric name), {{ .Tag \"key\"}} (tag reference to 'key') or\n  ## constant strings. The templates MAY NOT contain slashes!\n  # homie_device_name = \"\"\n  # homie_node_id = \"\"\n\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Optional MQTT 5 publish properties\n  ## These setting only apply if the \"protocol\" property is set to 5. This must\n  ## be defined at the end of the plugin settings, otherwise TOML will assume\n  ## anything else is part of this table. For more details on publish properties\n  ## see the spec:\n  ## https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109\n  # [outputs.mqtt.v5]\n  #   content_type = \"\"\n  #   response_topic = \"\"\n  #   message_expiry = \"0s\"\n  #   topic_alias = 0\n  # [outputs.mqtt.v5.user_properties]\n  #   \"key1\" = \"value 1\"\n  #   \"key2\" = \"value 2\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_duplicate_slash/expected.conf",
    "content": "[[outputs.mqtt]]\nservers = [\"localhost:1883\"]\ntopic = '/telegraf/{{ .Tag \"host\" }}/{{ .Name }}'\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_duplicate_slash/telegraf.conf",
    "content": "# Configuration for MQTT server to send metrics to\n[[outputs.mqtt]]\n  ## MQTT Brokers\n  ## The list of brokers should only include the hostname or IP address and the\n  ## port to the broker. This should follow the format `[{scheme}://]{host}:{port}`. For\n  ## example, `localhost:1883` or `mqtt://localhost:1883`.\n  ## Scheme can be any of the following: tcp://, mqtt://, tls://, mqtts://\n  ## non-TLS and TLS servers can not be mix-and-matched.\n  servers = [\"localhost:1883\", ] # or [\"mqtts://tls.example.com:1883\"]\n\n  ## Protocol can be `3.1.1` or `5`. Default is `3.1.1`\n  # protocol = \"3.1.1\"\n\n  ## MQTT Topic for Producer Messages\n  ## MQTT outputs send metrics to this topic format:\n  ## prefix/{{ .Tag \"host\" }}/{{ .Name }}/{{ .Tag \"tag_key\" }}\n  ## (e.g. prefix/web01.example.com/mem/some_tag_value)\n  ## Each path segment accepts either a template placeholder, an environment variable, or a tag key\n  ## of the form `{{.Tag \"tag_key_name\"}}`. All the functions provided by the Sprig library\n  ## (http://masterminds.github.io/sprig/) are available. Empty path elements as well as special MQTT\n  ## characters (such as `+` or `#`) are invalid to form the topic name and will lead to an error.\n  ## In case a tag is missing in the metric, that path segment omitted for the final topic.\n  topic = '/telegraf/{{ .Tag \"host\" }}/{{ .Name }}'\n  topic_prefix = \"telegraf\"\n\n  ## QoS policy for messages\n  ## The mqtt QoS policy for sending messages.\n  ## See https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q029090_.htm\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  # qos = 2\n\n  ## Keep Alive\n  ## Defines the maximum length of time that the broker and client may not\n  ## communicate. Defaults to 0 which turns the feature off.\n  ##\n  ## For version v2.0.12 and later mosquitto there is a bug\n  ## (see https://github.com/eclipse/mosquitto/issues/2117), which requires\n  ## this to be non-zero. As a reference eclipse/paho.mqtt.golang defaults to 30.\n  # keep_alive = 0\n\n  ## username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## client ID\n  ## The unique client id to connect MQTT server. If this parameter is not set\n  ## then a random ID is generated.\n  # client_id = \"\"\n\n  ## Timeout for write operations. default: 5s\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## When true, metrics will be sent in one MQTT message per flush. Otherwise,\n  ## metrics are written one metric per MQTT message.\n  ## DEPRECATED: Use layout option instead\n  # batch = false\n\n  ## When true, metric will have RETAIN flag set, making broker cache entries until someone\n  ## actually reads it\n  # retain = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Layout of the topics published.\n  ## The following choices are available:\n  ##   non-batch -- send individual messages, one for each metric\n  ##   batch     -- send all metric as a single message per MQTT topic\n  ## NOTE: The following options will ignore the 'data_format' option and send single values\n  ##   field     -- send individual messages for each field, appending its name to the metric topic\n  ##   homie-v4  -- send metrics with fields and tags according to the 4.0.0 specs\n  ##                see https://homieiot.github.io/specification/\n  # layout = \"non-batch\"\n\n  ## HOMIE specific settings\n  ## The following options provide templates for setting the device name\n  ## and the node-ID for the topics. Both options are MANDATORY and can contain\n  ## {{ .Name }} (metric name), {{ .Tag \"key\"}} (tag reference to 'key') or\n  ## constant strings. The templates MAY NOT contain slashes!\n  # homie_device_name = \"\"\n  # homie_node_id = \"\"\n\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Optional MQTT 5 publish properties\n  ## These setting only apply if the \"protocol\" property is set to 5. This must\n  ## be defined at the end of the plugin settings, otherwise TOML will assume\n  ## anything else is part of this table. For more details on publish properties\n  ## see the spec:\n  ## https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109\n  # [outputs.mqtt.v5]\n  #   content_type = \"\"\n  #   response_topic = \"\"\n  #   message_expiry = \"0s\"\n  #   topic_alias = 0\n  # [outputs.mqtt.v5.user_properties]\n  #   \"key1\" = \"value 1\"\n  #   \"key2\" = \"value 2\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_existing/expected.conf",
    "content": "[[outputs.mqtt]]\nservers = [\"localhost:1883\"]\ntopic = 'telegraf/{{ .Tag \"host\" }}/{{ .Name }}'\ndata_format = \"influx\"\n"
  },
  {
    "path": "migrations/outputs_mqtt/testcases/deprecated_topic_prefix_existing/telegraf.conf",
    "content": "# Configuration for MQTT server to send metrics to\n[[outputs.mqtt]]\n  ## MQTT Brokers\n  ## The list of brokers should only include the hostname or IP address and the\n  ## port to the broker. This should follow the format `[{scheme}://]{host}:{port}`. For\n  ## example, `localhost:1883` or `mqtt://localhost:1883`.\n  ## Scheme can be any of the following: tcp://, mqtt://, tls://, mqtts://\n  ## non-TLS and TLS servers can not be mix-and-matched.\n  servers = [\"localhost:1883\", ] # or [\"mqtts://tls.example.com:1883\"]\n\n  ## Protocol can be `3.1.1` or `5`. Default is `3.1.1`\n  # protocol = \"3.1.1\"\n\n  ## MQTT Topic for Producer Messages\n  ## MQTT outputs send metrics to this topic format:\n  ## prefix/{{ .Tag \"host\" }}/{{ .Name }}/{{ .Tag \"tag_key\" }}\n  ## (e.g. prefix/web01.example.com/mem/some_tag_value)\n  ## Each path segment accepts either a template placeholder, an environment variable, or a tag key\n  ## of the form `{{.Tag \"tag_key_name\"}}`. All the functions provided by the Sprig library\n  ## (http://masterminds.github.io/sprig/) are available. Empty path elements as well as special MQTT\n  ## characters (such as `+` or `#`) are invalid to form the topic name and will lead to an error.\n  ## In case a tag is missing in the metric, that path segment omitted for the final topic.\n  topic = '{{ .Tag \"host\" }}/{{ .Name }}'\n  topic_prefix = \"telegraf\"\n\n  ## QoS policy for messages\n  ## The mqtt QoS policy for sending messages.\n  ## See https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q029090_.htm\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  # qos = 2\n\n  ## Keep Alive\n  ## Defines the maximum length of time that the broker and client may not\n  ## communicate. Defaults to 0 which turns the feature off.\n  ##\n  ## For version v2.0.12 and later mosquitto there is a bug\n  ## (see https://github.com/eclipse/mosquitto/issues/2117), which requires\n  ## this to be non-zero. As a reference eclipse/paho.mqtt.golang defaults to 30.\n  # keep_alive = 0\n\n  ## username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## client ID\n  ## The unique client id to connect MQTT server. If this parameter is not set\n  ## then a random ID is generated.\n  # client_id = \"\"\n\n  ## Timeout for write operations. default: 5s\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## When true, metrics will be sent in one MQTT message per flush. Otherwise,\n  ## metrics are written one metric per MQTT message.\n  ## DEPRECATED: Use layout option instead\n  # batch = false\n\n  ## When true, metric will have RETAIN flag set, making broker cache entries until someone\n  ## actually reads it\n  # retain = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Layout of the topics published.\n  ## The following choices are available:\n  ##   non-batch -- send individual messages, one for each metric\n  ##   batch     -- send all metric as a single message per MQTT topic\n  ## NOTE: The following options will ignore the 'data_format' option and send single values\n  ##   field     -- send individual messages for each field, appending its name to the metric topic\n  ##   homie-v4  -- send metrics with fields and tags according to the 4.0.0 specs\n  ##                see https://homieiot.github.io/specification/\n  # layout = \"non-batch\"\n\n  ## HOMIE specific settings\n  ## The following options provide templates for setting the device name\n  ## and the node-ID for the topics. Both options are MANDATORY and can contain\n  ## {{ .Name }} (metric name), {{ .Tag \"key\"}} (tag reference to 'key') or\n  ## constant strings. The templates MAY NOT contain slashes!\n  # homie_device_name = \"\"\n  # homie_node_id = \"\"\n\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Optional MQTT 5 publish properties\n  ## These setting only apply if the \"protocol\" property is set to 5. This must\n  ## be defined at the end of the plugin settings, otherwise TOML will assume\n  ## anything else is part of this table. For more details on publish properties\n  ## see the spec:\n  ## https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109\n  # [outputs.mqtt.v5]\n  #   content_type = \"\"\n  #   response_topic = \"\"\n  #   message_expiry = \"0s\"\n  #   topic_alias = 0\n  # [outputs.mqtt.v5.user_properties]\n  #   \"key1\" = \"value 1\"\n  #   \"key2\" = \"value 2\"\n"
  },
  {
    "path": "migrations/outputs_remotefile/migration.go",
    "content": "package outputs_remotefile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tif rawTrace, found := plugin[\"trace\"]; found {\n\t\t// Convert the options to the actual type\n\t\ttrace, ok := rawTrace.(bool)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'trace'\", rawTrace)\n\t\t}\n\n\t\tif rawLogLevel, found := plugin[\"log_level\"]; found {\n\t\t\tif logLevel, ok := rawLogLevel.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'log_level'\", rawLogLevel)\n\t\t\t} else if (trace && logLevel != \"trace\") || (!trace && logLevel == \"trace\") {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'trace' and 'log_level'\")\n\t\t\t}\n\t\t}\n\n\t\tapplied = true\n\t\tif trace {\n\t\t\tplugin[\"log_level\"] = \"trace\"\n\t\t}\n\t\tdelete(plugin, \"trace\")\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, \"\", migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"remotefile\")\n\tcfg.Add(\"outputs\", \"remotefile\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, \"\", err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.remotefile\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_remotefile/migration_test.go",
    "content": "package outputs_remotefile_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_remotefile\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/remotefile\"    // register plugin\n\t_ \"github.com/influxdata/telegraf/plugins/serializers/influx\"    // register serializer\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_remotefile/testcases/simple/expected.conf",
    "content": "[[outputs.remotefile]]\n  data_format = \"influx\"\n  log_level = \"trace\"\n"
  },
  {
    "path": "migrations/outputs_remotefile/testcases/simple/telegraf.conf",
    "content": "[[outputs.remotefile]]\n  data_format = \"influx\"\n  trace = true\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/README.md",
    "content": ""
  },
  {
    "path": "migrations/outputs_riemann_legacy/migration.go",
    "content": "package outputs_riemann_legacy\n\nimport (\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n\t\"github.com/influxdata/telegraf/migrations/common\"\n)\n\n// Define \"old\" data structure\ntype riemannLegacy struct {\n\tURL       string `toml:\"url\"`\n\tTransport string `toml:\"transport\"`\n\tSeparator string `toml:\"separator\"`\n\tcommon.OutputOptions\n}\n\n// Define \"new\" data structure(s)\ntype riemann struct {\n\tURL       string `toml:\"url\"`\n\tSeparator string `toml:\"separator\"`\n\n\t// Common options for outputs\n\tAlias          string              `toml:\"alias,omitempty\"`\n\tNamePass       []string            `toml:\"namepass,omitempty\"`\n\tNameDrop       []string            `toml:\"namedrop,omitempty\"`\n\tFieldInclude   []string            `toml:\"fieldinclude,omitempty\"`\n\tFieldExclude   []string            `toml:\"fieldexclude,omitempty\"`\n\tTagPassFilters map[string][]string `toml:\"tagpass,omitempty\"`\n\tTagDropFilters map[string][]string `toml:\"tagdrop,omitempty\"`\n\tTagExclude     []string            `toml:\"tagexclude,omitempty\"`\n\tTagInclude     []string            `toml:\"taginclude,omitempty\"`\n\tMetricPass     string              `toml:\"metricpass,omitempty\"`\n}\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar old riemannLegacy\n\tif err := toml.UnmarshalTable(tbl, &old); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Create new plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"riemann\")\n\tplugin := riemann{\n\t\tURL:       old.Transport + \"://\" + old.URL,\n\t\tSeparator: old.Separator,\n\t}\n\tplugin.fillCommon(old.OutputOptions)\n\tcfg.Add(\"outputs\", \"riemann\", plugin)\n\n\t// Marshal the new configuration\n\tbuf, err := toml.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tbuf = append(buf, []byte(\"\\n\")...)\n\n\t// Create the new content to output\n\treturn buf, \"\", nil\n}\n\nfunc (j *riemann) fillCommon(o common.OutputOptions) {\n\to.Migrate()\n\n\tj.Alias = o.Alias\n\n\tif len(o.NamePass) > 0 {\n\t\tj.NamePass = append(j.NamePass, o.NamePass...)\n\t}\n\tif len(o.NameDrop) > 0 {\n\t\tj.NameDrop = append(j.NameDrop, o.NameDrop...)\n\t}\n\tif len(o.FieldInclude) > 0 {\n\t\tj.FieldInclude = append(j.FieldInclude, o.FieldInclude...)\n\t}\n\tif len(o.FieldExclude) > 0 {\n\t\tj.FieldExclude = append(j.FieldExclude, o.FieldExclude...)\n\t}\n\tif len(o.TagPassFilters) > 0 {\n\t\tj.TagPassFilters = make(map[string][]string, len(o.TagPassFilters))\n\t\tfor k, v := range o.TagPassFilters {\n\t\t\tj.TagPassFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagDropFilters) > 0 {\n\t\tj.TagDropFilters = make(map[string][]string, len(o.TagDropFilters))\n\t\tfor k, v := range o.TagDropFilters {\n\t\t\tj.TagDropFilters[k] = v\n\t\t}\n\t}\n\tif len(o.TagExclude) > 0 {\n\t\tj.TagExclude = append(j.TagExclude, o.TagExclude...)\n\t}\n\tif len(o.TagInclude) > 0 {\n\t\tj.TagInclude = append(j.TagInclude, o.TagInclude...)\n\t}\n\tj.MetricPass = o.MetricPass\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginMigration(\"outputs.riemann_legacy\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/migration_test.go",
    "content": "package outputs_riemann_legacy_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_riemann_legacy\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/riemann\"           // register plugin\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/testcases/general_options/expected.conf",
    "content": "[[outputs.riemann]]\nurl = \"udp://localhost:5555\"\nseparator = \".\"\nnamepass = [\"foo\"]\nfieldinclude = [\"motor_*\"]\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/testcases/general_options/telegraf.conf",
    "content": "# Configuration for the Riemann server to send metrics to\n[[outputs.riemann_legacy]]\n  url = \"localhost:5555\"\n  transport = \"udp\"\n  separator = \".\"\n\n  ## Metric filtering\n  namepass = [\"foo\"]\n  fieldpass = [\"motor_*\"]\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/testcases/simple/expected.conf",
    "content": "[[outputs.riemann]]\nurl = \"tcp://localhost:5555\"\nseparator = \" \"\n"
  },
  {
    "path": "migrations/outputs_riemann_legacy/testcases/simple/telegraf.conf",
    "content": "# Configuration for the Riemann server to send metrics to\n[[outputs.riemann_legacy]]\n  ## URL of server\n  url = \"localhost:5555\"\n  ## transport protocol to use either tcp or udp\n  transport = \"tcp\"\n  ## separator to use between input name and field name in Riemann service name\n  separator = \" \""
  },
  {
    "path": "migrations/outputs_wavefront/migration.go",
    "content": "package outputs_wavefront\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\n\t\"github.com/influxdata/telegraf/migrations\"\n)\n\n// Migration function\nfunc migrate(tbl *ast.Table) ([]byte, string, error) {\n\t// Decode the old data structure\n\tvar plugin map[string]interface{}\n\tif err := toml.UnmarshalTable(tbl, &plugin); err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Check for deprecated option(s) and migrate them\n\tvar applied bool\n\tmsg := \"\"\n\n\trawHost, foundHost := plugin[\"host\"]\n\trawPort, foundPort := plugin[\"port\"]\n\n\tif foundHost {\n\t\thost, ok := rawHost.(string)\n\t\tif !ok {\n\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'host'\", rawHost)\n\t\t}\n\n\t\tvar newURL string\n\t\tif foundPort {\n\t\t\tport, ok := rawPort.(int64)\n\t\t\tif !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'port'\", rawPort)\n\t\t\t}\n\t\t\tnewURL = fmt.Sprintf(\"http://%s:%d\", host, port)\n\t\t} else {\n\t\t\tnewURL = \"http://%s\" + host\n\t\t}\n\n\t\tif rawURL, found := plugin[\"url\"]; found {\n\t\t\tif url, ok := rawURL.(string); !ok {\n\t\t\t\treturn nil, \"\", fmt.Errorf(\"unexpected type %T for 'url'\", rawURL)\n\t\t\t} else if url != newURL {\n\t\t\t\treturn nil, \"\", errors.New(\"contradicting setting for 'host' and 'port' with 'url'\")\n\t\t\t}\n\t\t}\n\n\t\tapplied = true\n\t\tdelete(plugin, \"host\")\n\t\tdelete(plugin, \"port\")\n\t\tplugin[\"url\"] = newURL\n\t}\n\n\t// Cannot automatically migrate 'string_to_number' option, give a message if it is set\n\tif _, found := plugin[\"string_to_number\"]; found {\n\t\tmsg = \"The 'string_to_number' cannot be migrated automatically and requires manual intervention!\"\n\t}\n\n\t// No options migrated so we can exit early\n\tif !applied {\n\t\treturn nil, msg, migrations.ErrNotApplicable\n\t}\n\n\t// Create the corresponding plugin configurations\n\tcfg := migrations.CreateTOMLStruct(\"outputs\", \"wavefront\")\n\tcfg.Add(\"outputs\", \"wavefront\", plugin)\n\n\toutput, err := toml.Marshal(cfg)\n\treturn output, msg, err\n}\n\n// Register the migration function for the plugin type\nfunc init() {\n\tmigrations.AddPluginOptionMigration(\"outputs.wavefront\", migrate)\n}\n"
  },
  {
    "path": "migrations/outputs_wavefront/migration_test.go",
    "content": "package outputs_wavefront_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t_ \"github.com/influxdata/telegraf/migrations/outputs_wavefront\" // register migration\n\t_ \"github.com/influxdata/telegraf/plugins/outputs/wavefront\"    // register plugin\n)\n\nfunc TestCannotMigrateStringToNumber(t *testing.T) {\n\tcfg := []byte(`\n[[outputs.wavefront]]\n  string_to_number = \"test_key\"\n`)\n\t// Migrate and check that nothing changed\n\toutput, n, err := config.ApplyMigrations(cfg)\n\trequire.NoError(t, err)\n\trequire.Equal(t, cfg, output)\n\trequire.Equal(t, uint64(0), n)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tinputFile := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\texpectedFile := filepath.Join(testcasePath, \"expected.conf\")\n\n\t\t\t// Read the expected output\n\t\t\texpected := config.NewConfig()\n\t\t\trequire.NoError(t, expected.LoadConfig(expectedFile))\n\t\t\trequire.NotEmpty(t, expected.Outputs)\n\n\t\t\t// Read the input data\n\t\t\tinput, remote, err := config.LoadConfigFile(inputFile)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, remote)\n\t\t\trequire.NotEmpty(t, input)\n\n\t\t\t// Migrate\n\t\t\toutput, n, err := config.ApplyMigrations(input)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, output)\n\t\t\trequire.GreaterOrEqual(t, n, uint64(1))\n\t\t\tactual := config.NewConfig()\n\t\t\trequire.NoError(t, actual.LoadConfigData(output, config.EmptySourcePath))\n\n\t\t\t// Test the output\n\t\t\trequire.Len(t, actual.Outputs, len(expected.Outputs))\n\t\t\tactualIDs := make([]string, 0, len(expected.Outputs))\n\t\t\texpectedIDs := make([]string, 0, len(expected.Outputs))\n\t\t\tfor i := range actual.Outputs {\n\t\t\t\tactualIDs = append(actualIDs, actual.Outputs[i].ID())\n\t\t\t\texpectedIDs = append(expectedIDs, expected.Outputs[i].ID())\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, expectedIDs, actualIDs, string(output))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "migrations/outputs_wavefront/testcases/host_port/expected.conf",
    "content": "[[outputs.wavefront]]\n  url = \"http://localhost:8080\"\n"
  },
  {
    "path": "migrations/outputs_wavefront/testcases/host_port/telegraf.conf",
    "content": "[[outputs.wavefront]]\n  host = \"localhost\"\n  port = 8080\n"
  },
  {
    "path": "migrations/registry.go",
    "content": "package migrations\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/toml/ast\"\n)\n\nvar ErrNotApplicable = errors.New(\"no migration applied\")\n\ntype PluginMigrationFunc func(*ast.Table) ([]byte, string, error)\n\nvar PluginMigrations = make(map[string]PluginMigrationFunc)\n\nfunc AddPluginMigration(name string, f PluginMigrationFunc) {\n\tif _, found := PluginMigrations[name]; found {\n\t\tpanic(fmt.Errorf(\"plugin migration function already registered for %q\", name))\n\t}\n\tPluginMigrations[name] = f\n}\n\ntype PluginOptionMigrationFunc PluginMigrationFunc\n\nvar PluginOptionMigrations = make(map[string]PluginOptionMigrationFunc)\n\nfunc AddPluginOptionMigration(name string, f PluginOptionMigrationFunc) {\n\tif _, found := PluginOptionMigrations[name]; found {\n\t\tpanic(fmt.Errorf(\"plugin option migration function already registered for %q\", name))\n\t}\n\tPluginOptionMigrations[name] = f\n}\n\ntype GeneralMigrationFunc func(string, string, *ast.Table) ([]byte, string, error)\n\nvar GeneralMigrations []GeneralMigrationFunc\n\nfunc AddGeneralMigration(f GeneralMigrationFunc) {\n\tGeneralMigrations = append(GeneralMigrations, f)\n}\n\ntype GlobalMigrationFunc func(string, *ast.Table) ([]byte, string, error)\n\nvar GlobalMigrations []GlobalMigrationFunc\n\nfunc AddGlobalMigration(f GlobalMigrationFunc) {\n\tGlobalMigrations = append(GlobalMigrations, f)\n}\n"
  },
  {
    "path": "migrations/utils.go",
    "content": "package migrations\n\nimport (\n\t\"fmt\"\n)\n\ntype pluginTOMLStruct map[string]map[string][]interface{}\n\nfunc CreateTOMLStruct(category, name string) pluginTOMLStruct {\n\treturn map[string]map[string][]interface{}{\n\t\tcategory: {\n\t\t\tname: make([]interface{}, 0),\n\t\t},\n\t}\n}\n\nfunc (p *pluginTOMLStruct) Add(category, name string, plugin interface{}) {\n\tcfg := map[string]map[string][]interface{}(*p)\n\tcfg[category][name] = append(cfg[category][name], plugin)\n}\n\nfunc AsStringSlice(raw interface{}) ([]string, error) {\n\trawList, ok := raw.([]interface{})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected type : %T\", raw)\n\t}\n\n\tconverted := make([]string, 0, len(rawList))\n\tfor _, rawElement := range rawList {\n\t\tel, ok := rawElement.(string)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected type for list element: %T\", rawElement)\n\t\t}\n\t\tconverted = append(converted, el)\n\t}\n\treturn converted, nil\n}\n"
  },
  {
    "path": "models/buffer.go",
    "content": "package models\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\nvar (\n\tAgentMetricsWritten  = selfstat.Register(\"agent\", \"metrics_written\", make(map[string]string))\n\tAgentMetricsRejected = selfstat.Register(\"agent\", \"metrics_rejected\", make(map[string]string))\n\tAgentMetricsDropped  = selfstat.Register(\"agent\", \"metrics_dropped\", make(map[string]string))\n\n\tregisterGob = sync.OnceFunc(func() { metric.Init() })\n)\n\ntype Transaction struct {\n\t// Batch of metrics to write\n\tBatch []telegraf.Metric\n\n\t// Accept denotes the indices of metrics that were successfully written\n\tAccept []int\n\t// Reject denotes the indices of metrics that were not written but should\n\t// not be requeued\n\tReject []int\n\n\t// Marks this transaction as valid\n\tvalid bool\n\n\t// Internal state that can be used by the buffer implementation\n\tstate interface{}\n}\n\nfunc (tx *Transaction) AcceptAll() {\n\ttx.Accept = make([]int, len(tx.Batch))\n\tfor i := range tx.Batch {\n\t\ttx.Accept[i] = i\n\t}\n}\n\nfunc (*Transaction) KeepAll() {}\n\nfunc (tx *Transaction) InferKeep() []int {\n\tused := make([]bool, len(tx.Batch))\n\tfor _, idx := range tx.Accept {\n\t\tused[idx] = true\n\t}\n\tfor _, idx := range tx.Reject {\n\t\tused[idx] = true\n\t}\n\n\tkeep := make([]int, 0, len(tx.Batch))\n\tfor i := range tx.Batch {\n\t\tif !used[i] {\n\t\t\tkeep = append(keep, i)\n\t\t}\n\t}\n\treturn keep\n}\n\ntype Buffer interface {\n\t// Len returns the number of metrics currently in the buffer.\n\tLen() int\n\n\t// Add adds metrics to the buffer and returns number of dropped metrics.\n\tAdd(metrics ...telegraf.Metric) int\n\n\t// Batch starts a transaction by returning a slice of metrics up to the\n\t// given batch-size starting from the oldest metric in the buffer. Metrics\n\t// are ordered from oldest to newest and must not be modified by the plugin.\n\tBeginTransaction(batchSize int) *Transaction\n\n\t// Flush ends a metric and persists the buffer state\n\tEndTransaction(*Transaction)\n\n\t// Stats returns the buffer statistics such as rejected, dropped and accepted metrics\n\tStats() BufferStats\n\n\t// Close finalizes the buffer and closes all open resources\n\tClose() error\n}\n\n// BufferStats holds common metrics used for buffer implementations.\n// Implementations of Buffer should embed this struct in them.\ntype BufferStats struct {\n\tMetricsAdded    selfstat.Stat\n\tMetricsWritten  selfstat.Stat\n\tMetricsRejected selfstat.Stat\n\tMetricsDropped  selfstat.Stat\n\tBufferSize      selfstat.Stat\n\tBufferLimit     selfstat.Stat\n}\n\n// NewBuffer returns a new empty Buffer with the given capacity.\n//\n//nolint:revive //will move to structs later\nfunc NewBuffer(name, id, alias string, capacity int, strategy, path string, diskSync bool) (Buffer, error) {\n\tregisterGob()\n\n\ttags := map[string]string{\n\t\t\"_id\":    id,\n\t\t\"output\": name,\n\t}\n\tif alias != \"\" {\n\t\ttags[\"alias\"] = alias\n\t}\n\tbs := NewBufferStats(tags, capacity)\n\n\tswitch strategy {\n\tcase \"\", \"memory\":\n\t\treturn NewMemoryBuffer(capacity, bs)\n\tcase \"disk_write_through\":\n\t\treturn NewDiskBuffer(id, path, bs, diskSync)\n\t}\n\treturn nil, fmt.Errorf(\"invalid buffer strategy %q\", strategy)\n}\n\nfunc NewBufferStats(tags map[string]string, capacity int) BufferStats {\n\tbs := BufferStats{\n\t\tMetricsAdded: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"metrics_added\",\n\t\t\ttags,\n\t\t),\n\t\tMetricsWritten: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"metrics_written\",\n\t\t\ttags,\n\t\t),\n\t\tMetricsRejected: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"metrics_rejected\",\n\t\t\ttags,\n\t\t),\n\t\tMetricsDropped: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"metrics_dropped\",\n\t\t\ttags,\n\t\t),\n\t\tBufferSize: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"buffer_size\",\n\t\t\ttags,\n\t\t),\n\t\tBufferLimit: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"buffer_limit\",\n\t\t\ttags,\n\t\t),\n\t}\n\tbs.BufferSize.Set(int64(0))\n\tbs.BufferLimit.Set(int64(capacity))\n\treturn bs\n}\n\nfunc (b *BufferStats) metricAdded(count int64) {\n\tb.MetricsAdded.Incr(count)\n}\n\nfunc (b *BufferStats) metricWritten(m telegraf.Metric) {\n\tAgentMetricsWritten.Incr(1)\n\tb.MetricsWritten.Incr(1)\n\tm.Accept()\n}\n\nfunc (b *BufferStats) metricRejected(m telegraf.Metric) {\n\tAgentMetricsRejected.Incr(1)\n\tb.MetricsRejected.Incr(1)\n\tm.Reject()\n}\n\nfunc (b *BufferStats) metricDropped(m telegraf.Metric) {\n\tAgentMetricsDropped.Incr(1)\n\tb.MetricsDropped.Incr(1)\n\tm.Reject()\n}\n"
  },
  {
    "path": "models/buffer_disk.go",
    "content": "package models\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/tidwall/wal\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\ntype DiskBuffer struct {\n\tBufferStats\n\tsync.Mutex\n\n\tfile *wal.Log\n\tpath string\n\n\tbatchFirst uint64 // Index of the first metric in the batch\n\tbatchSize  uint64 // Number of metrics currently in the batch\n\n\t// Ending point of metrics read from disk on telegraf launch.\n\t// Used to know whether to discard tracking metrics.\n\toriginalEnd uint64\n\n\t// The mask contains offsets of metric already removed during a previous\n\t// transaction. Metrics at those offsets should not be contained in new\n\t// batches.\n\tmask []int\n}\n\nfunc NewDiskBuffer(id, path string, stats BufferStats, diskSync bool) (*DiskBuffer, error) {\n\tfilePath := filepath.Join(path, id)\n\twalFile, err := wal.Open(filePath, &wal.Options{\n\t\tAllowEmpty: true,\n\t\tNoSync:     !diskSync,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open wal file: %w\", err)\n\t}\n\n\tbuf := &DiskBuffer{\n\t\tBufferStats: stats,\n\t\tfile:        walFile,\n\t\tpath:        filePath,\n\t}\n\tif buf.Len() > 0 {\n\t\tbuf.originalEnd = buf.writeIndex()\n\t}\n\treturn buf, nil\n}\n\nfunc (b *DiskBuffer) Len() int {\n\tb.Lock()\n\tdefer b.Unlock()\n\treturn b.length()\n}\n\nfunc (b *DiskBuffer) length() int {\n\treturn b.entries() - len(b.mask)\n}\n\nfunc (b *DiskBuffer) entries() int {\n\tif b.readIndex() == 0 {\n\t\treturn 0\n\t}\n\treturn int(b.writeIndex() - b.readIndex())\n}\n\n// readIndex is the first index to start reading metrics from, or the head of the buffer\nfunc (b *DiskBuffer) readIndex() uint64 {\n\tindex, err := b.file.FirstIndex()\n\tif err != nil {\n\t\tpanic(err) // can only occur with a corrupt or closed wal file\n\t}\n\treturn index\n}\n\n// writeIndex is the first index to start writing metrics to, or the tail of the buffer\nfunc (b *DiskBuffer) writeIndex() uint64 {\n\tindex, err := b.file.LastIndex()\n\tif err != nil {\n\t\tpanic(err) // can only occur with a corrupt or closed wal file\n\t}\n\treturn index + 1\n}\n\nfunc (b *DiskBuffer) Add(metrics ...telegraf.Metric) int {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\tvar batch wal.Batch\n\tidx := b.writeIndex()\n\tstartIdx := idx\n\tfor _, m := range metrics {\n\t\tdata, err := metric.ToBytes(m)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tbatch.Write(idx, data)\n\t\tidx++\n\t}\n\n\tif err := b.file.WriteBatch(&batch); err != nil {\n\t\t// This calculation assumes a single writer to the WAL, which is\n\t\t// guaranteed by the mutex and one WAL per buffer instance.\n\t\tdropped := uint64(len(metrics)) - (b.writeIndex() - startIdx)\n\t\treturn int(dropped)\n\t}\n\n\tb.metricAdded(int64(len(metrics)))\n\tb.BufferSize.Set(int64(b.length()))\n\treturn 0\n}\n\nfunc (b *DiskBuffer) BeginTransaction(batchSize int) *Transaction {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\tif b.length() == 0 {\n\t\treturn &Transaction{}\n\t}\n\tb.batchFirst = b.readIndex()\n\tb.batchSize = 0\n\n\tmetrics := make([]telegraf.Metric, 0, batchSize)\n\toffsets := make([]int, 0, batchSize)\n\treadIndex := b.batchFirst\n\tendIndex := b.writeIndex()\n\tfor offset := 0; batchSize > 0 && readIndex < endIndex; offset++ {\n\t\tdata, err := b.file.Read(readIndex)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treadIndex++\n\n\t\tif slices.Contains(b.mask, offset) {\n\t\t\t// Metric is masked by a previous write and is scheduled for removal\n\t\t\tcontinue\n\t\t}\n\n\t\t// Validate that a tracking metric is from this instance of telegraf and skip ones from older instances.\n\t\t// A tracking metric can be skipped here because metric.Accept() is only called once data is successfully\n\t\t// written to an output, so any tracking metrics from older instances can be dropped and reacquired to\n\t\t// have an accurate tracking information.\n\t\t// There are two primary cases here:\n\t\t// - ErrSkipTracking:  means that the tracking information was unable to be found for a tracking ID.\n\t\t// - Outside of range: means that the metric was guaranteed to be left over from the previous instance\n\t\t//                     as it was here when we opened the wal file in this instance.\n\t\tm, err := metric.FromBytes(data)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, metric.ErrSkipTracking) {\n\t\t\t\t// Could not look up tracking information for metric so skip\n\t\t\t\t// the metric and mask it so it is truncated later on.\n\t\t\t\tb.mask = append(b.mask, offset)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// non-recoverable error in deserialization, abort\n\t\t\tlog.Printf(\"E! raw metric data: %v\", data)\n\t\t\tpanic(err)\n\t\t}\n\t\tif _, ok := m.(telegraf.TrackingMetric); ok && readIndex < b.originalEnd {\n\t\t\t// This tracking metric is a left-over from a previous instance e.g.\n\t\t\t// after restarting Telegraf. Skip the metric and mask it so it is\n\t\t\t// trucated later on\n\t\t\tb.mask = append(b.mask, offset)\n\t\t\tcontinue\n\t\t}\n\n\t\tmetrics = append(metrics, m)\n\t\toffsets = append(offsets, offset)\n\t\tb.batchSize++\n\t\tbatchSize--\n\t}\n\treturn &Transaction{Batch: metrics, valid: true, state: offsets}\n}\n\nfunc (b *DiskBuffer) EndTransaction(tx *Transaction) {\n\tif len(tx.Batch) == 0 {\n\t\treturn\n\t}\n\n\t// Ignore invalid transactions and make sure they can only be finished once\n\tif !tx.valid {\n\t\treturn\n\t}\n\ttx.valid = false\n\n\t// Get the metric offsets from the transaction\n\toffsets := tx.state.([]int)\n\n\tb.Lock()\n\tdefer b.Unlock()\n\n\t// Mark metrics which should be removed in the internal mask\n\tremove := make([]int, 0, len(tx.Accept)+len(tx.Reject))\n\tfor _, idx := range tx.Accept {\n\t\tb.metricWritten(tx.Batch[idx])\n\t\tremove = append(remove, offsets[idx])\n\t}\n\tfor _, idx := range tx.Reject {\n\t\tb.metricRejected(tx.Batch[idx])\n\t\tremove = append(remove, offsets[idx])\n\t}\n\tb.mask = append(b.mask, remove...)\n\tsort.Ints(b.mask)\n\n\t// Remove the metrics that are marked for removal from the front of the\n\t// WAL file. All other metrics must be kept.\n\tif len(b.mask) == 0 || b.mask[0] != 0 {\n\t\t// Mask is empty or the first index is not the front of the file, so\n\t\t// exit early as there is nothing to remove\n\t\treturn\n\t}\n\n\t// Determine up to which index we can remove the entries from the WAL file\n\tvar correction int\n\tfor i, offset := range b.mask {\n\t\tif offset != i {\n\t\t\tbreak\n\t\t}\n\t\tcorrection = offset\n\t}\n\t// The 'correction' denotes the offset to subtract from the remaining mask\n\t// (if any) and the 'removalIdx' denotes the index to use when truncating\n\t// the file and mask. Keep them separate to be able to handle the special\n\t// \"the file cannot be empty\" property of the WAL file.\n\tremoveIdx := correction + 1\n\n\t// Remove the metrics in front from the WAL file\n\tif err := b.file.TruncateFront(b.batchFirst + uint64(removeIdx)); err != nil {\n\t\tlog.Printf(\"E! batch length: %d, first: %d, size: %d\", len(tx.Batch), b.batchFirst, b.batchSize)\n\t\tpanic(err)\n\t}\n\n\t// Truncate the mask and update the relative offsets\n\tb.mask = b.mask[removeIdx:]\n\tfor i := range b.mask {\n\t\tb.mask[i] -= correction\n\t}\n\n\t// check if the original end index is still valid, clear if not\n\tif b.originalEnd < b.readIndex() {\n\t\tb.originalEnd = 0\n\t}\n\n\tb.resetBatch()\n\tb.BufferSize.Set(int64(b.length()))\n}\n\nfunc (b *DiskBuffer) Stats() BufferStats {\n\treturn b.BufferStats\n}\n\nfunc (b *DiskBuffer) Close() error {\n\tif err := b.file.Close(); err != nil {\n\t\treturn fmt.Errorf(\"closing buffer failed: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (b *DiskBuffer) resetBatch() {\n\tb.batchFirst = 0\n\tb.batchSize = 0\n}\n"
  },
  {
    "path": "models/buffer_disk_test.go",
    "content": "package models\n\nimport (\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tidwall/wal\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// TestDiskBufferTruncate is a regression test for\n// https://github.com/influxdata/telegraf/issues/16696\nfunc TestDiskBufferTruncate(t *testing.T) {\n\t// Create a disk buffer\n\tbuf, err := NewBuffer(\"test\", \"id123\", \"\", 0, \"disk_write_through\", t.TempDir(), true)\n\trequire.NoError(t, err)\n\tdefer buf.Close()\n\tdiskBuf, ok := buf.(*DiskBuffer)\n\trequire.True(t, ok, \"buffer is not a disk buffer\")\n\n\t// Add some metrics to the buffer\n\texpected := make([]telegraf.Metric, 0, 10)\n\tfor i := range 10 {\n\t\tm := metric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": i}, time.Now())\n\t\tbuf.Add(m)\n\t\texpected = append(expected, m)\n\t}\n\n\t// Get a batch, test the metrics and acknowledge all metrics\n\ttx := buf.BeginTransaction(4)\n\ttestutil.RequireMetricsEqual(t, expected[:4], tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// The buffer must have been truncated on disk and the mask should be empty\n\trequire.Equal(t, 6, diskBuf.entries())\n\trequire.Empty(t, diskBuf.mask)\n\n\t// Get a second batch, test the metrics and acknowledge all metrics except\n\t// for the first one.\n\ttx = buf.BeginTransaction(4)\n\ttestutil.RequireMetricsEqual(t, expected[4:8], tx.Batch)\n\ttx.Accept = []int{1, 2, 3}\n\tbuf.EndTransaction(tx)\n\n\t// The buffer cannot be truncated on disk as the first metric must be kept.\n\t// However, the mask now must contain the accepted indices...\n\trequire.Equal(t, 6, diskBuf.entries())\n\trequire.Equal(t, []int{1, 2, 3}, diskBuf.mask)\n\n\t// Get a third batch with all the remaining metrics, test them and\n\t// acknowledge all\n\ttx = buf.BeginTransaction(4)\n\tremaining := append([]telegraf.Metric{expected[4]}, expected[8:]...)\n\ttestutil.RequireMetricsEqual(t, remaining, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Ensure the buffer was fully truncated on disk and the mask is consistent with that\n\trequire.Zero(t, diskBuf.entries())\n\trequire.Empty(t, diskBuf.mask)\n\n\t// We shouldn't get any metric when requesting a new batch\n\ttx = buf.BeginTransaction(4)\n\trequire.Empty(t, tx.Batch)\n}\n\n// TestDiskBufferEmptyReuse is a regression test for making sure all metrics are\n// output after being added to an fully drained (i.e. empty) buffer. Related to\n// https://github.com/influxdata/telegraf/issues/16981\nfunc TestDiskBufferEmptyReuse(t *testing.T) {\n\t// Create a disk buffer\n\tbuf, err := NewBuffer(\"test\", \"id123\", \"\", 0, \"disk_write_through\", t.TempDir(), true)\n\trequire.NoError(t, err)\n\tdefer buf.Close()\n\tdiskBuf, ok := buf.(*DiskBuffer)\n\trequire.True(t, ok, \"buffer is not a disk buffer\")\n\n\t// Add some metrics to the buffer\n\texpected := make([]telegraf.Metric, 0, 5)\n\tfor i := range 5 {\n\t\tm := metric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": i}, time.Now())\n\t\tbuf.Add(m)\n\t\texpected = append(expected, m)\n\t}\n\n\t// Read the complete set of metrics such that the buffer is empty again\n\ttx := buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(t, expected, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Ensure all storage elements of the buffer are consistent with it being empty\n\trequire.Zero(t, diskBuf.length())\n\trequire.Zero(t, diskBuf.entries())\n\trequire.Empty(t, diskBuf.mask)\n\n\t// Try to read the buffer again. This should return an empty transaction...\n\ttx = buf.BeginTransaction(5)\n\trequire.Empty(t, tx.Batch)\n\tbuf.EndTransaction(tx)\n\n\t// Now add another set of metrics and make sure we can read it\n\tm := metric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": 42}, time.Now())\n\tbuf.Add(m)\n\n\t// Read the complete set of metrics such that the buffer is empty again\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(t, []telegraf.Metric{m}, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n}\n\n// TestDiskBufferEmptyClose is a regression test for making sure that we do not\n// encounter any metrics in a reopened buffer if it was closed in an empty state.\n// This should be the normal case if all metrics are successfully written when\n// stopping Telegraf. On next startup the buffer should be empty. Related to\n// https://github.com/influxdata/telegraf/issues/16981\nfunc TestDiskBufferEmptyClose(t *testing.T) {\n\ttmpdir := t.TempDir()\n\n\t// Create a disk buffer\n\tbuf, err := NewBuffer(\"test\", \"id123\", \"\", 0, \"disk_write_through\", tmpdir, true)\n\trequire.NoError(t, err)\n\tdefer buf.Close()\n\tdiskBuf, ok := buf.(*DiskBuffer)\n\trequire.True(t, ok, \"buffer is not a disk buffer\")\n\n\t// Add some metrics to the buffer\n\texpected := make([]telegraf.Metric, 0, 5)\n\tfor i := range 5 {\n\t\tm := metric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": i}, time.Now())\n\t\tbuf.Add(m)\n\t\texpected = append(expected, m)\n\t}\n\n\t// Read the complete set of metrics such that the buffer is empty again\n\ttx := buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(t, expected, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Make sure the buffer was fully emptied\n\trequire.Zero(t, diskBuf.length())\n\trequire.Zero(t, diskBuf.entries())\n\n\t// Close the buffer to simulate stopping Telegraf in a normal shutdown\n\trequire.NoError(t, diskBuf.Close())\n\n\t// Reopen the buffer with the parameters above to see the same buffer\n\treopened, err := NewBuffer(\"test\", \"id123\", \"\", 0, \"disk_write_through\", tmpdir, true)\n\trequire.NoError(t, err)\n\tdefer reopened.Close()\n\t_, ok = reopened.(*DiskBuffer)\n\trequire.True(t, ok, \"reopened buffer is not a disk buffer\")\n\n\t// Try to read the buffer again. This should return an empty transaction...\n\ttx = reopened.BeginTransaction(5)\n\trequire.Empty(t, tx.Batch)\n\treopened.EndTransaction(tx)\n\n\t// However, adding a new metric to the buffer should work\n\t// Now add another set of metrics and make sure we can read it\n\tm := metric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": 42}, time.Now())\n\treopened.Add(m)\n\n\t// Read the complete set of metrics such that the buffer is empty again\n\ttx = reopened.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(t, []telegraf.Metric{m}, tx.Batch)\n\ttx.AcceptAll()\n\treopened.EndTransaction(tx)\n}\n\nfunc TestDiskBufferRetainsTrackingInformation(t *testing.T) {\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\n\tvar delivered int\n\tmm, _ := metric.WithTracking(m, func(telegraf.DeliveryInfo) { delivered++ })\n\n\tbuf, err := NewBuffer(\"test\", \"123\", \"\", 0, \"disk_write_through\", t.TempDir(), true)\n\trequire.NoError(t, err)\n\tbuf.Stats().MetricsAdded.Set(0)\n\tbuf.Stats().MetricsWritten.Set(0)\n\tbuf.Stats().MetricsDropped.Set(0)\n\tdefer buf.Close()\n\n\tbuf.Add(mm)\n\ttx := buf.BeginTransaction(1)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\trequire.Equal(t, 1, delivered)\n}\n\nfunc TestDiskBufferTrackingDroppedFromOldWal(t *testing.T) {\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\n\ttm, _ := metric.WithTracking(m, func(telegraf.DeliveryInfo) {})\n\tmetrics := []telegraf.Metric{\n\t\t// Basic metric with 1 field, 0 timestamp\n\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\t// Basic metric with 1 field, different timestamp\n\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 20.0}, time.Now()),\n\t\t// Metric with a field\n\t\tmetric.New(\"cpu\", map[string]string{\"x\": \"y\"}, map[string]interface{}{\"value\": 18.0}, time.Now()),\n\t\t// Tracking metric\n\t\ttm,\n\t\t// Metric with lots of tag types\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value_f64\":        20.0,\n\t\t\t\t\"value_uint64\":     uint64(10),\n\t\t\t\t\"value_int16\":      int16(5),\n\t\t\t\t\"value_string\":     \"foo\",\n\t\t\t\t\"value_boolean\":    true,\n\t\t\t\t\"value_byte_array\": []byte{1, 2, 3, 4, 5},\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\t// call manually so that we can properly use metric.ToBytes() without having initialized a buffer\n\tregisterGob()\n\n\t// Prefill the WAL file\n\tpath := t.TempDir()\n\twalfile, err := wal.Open(filepath.Join(path, \"123\"), &wal.Options{\n\t\tAllowEmpty: true,\n\t})\n\trequire.NoError(t, err)\n\tdefer walfile.Close()\n\tfor i, m := range metrics {\n\t\tdata, err := metric.ToBytes(m)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, walfile.Write(uint64(i+1), data))\n\t}\n\twalfile.Close()\n\n\t// Create a buffer\n\tbuf, err := NewBuffer(\"123\", \"123\", \"\", 0, \"disk_write_through\", path, true)\n\trequire.NoError(t, err)\n\tbuf.Stats().MetricsAdded.Set(0)\n\tbuf.Stats().MetricsWritten.Set(0)\n\tbuf.Stats().MetricsDropped.Set(0)\n\tdefer buf.Close()\n\n\ttx := buf.BeginTransaction(4)\n\n\t// Check that the tracking metric is skipped\n\texpected := []telegraf.Metric{\n\t\tmetrics[0], metrics[1], metrics[2], metrics[4],\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, tx.Batch)\n}\n\n// TestDiskBufferTrackingOnOutputOutage is a regression test for making sure\n// that we send all metrics if an output goes down and comes up again. In this\n// special test we use tracking metrics as e.g. used for Kafka or MQTT.\n// Related to https://github.com/influxdata/telegraf/issues/16981\nfunc TestDiskBufferTrackingOnOutputOutage(t *testing.T) {\n\t// Make sure we can serialize the metrics by manually registering the binary\n\t// serializer. In real-world this is done during setting up Telegraf.\n\tregisterGob()\n\n\t// Create some tracking metrics with a callback that records the accepted\n\t// metrics (or at least the tracking ID).\n\tconst count = 10\n\n\tvar mu sync.Mutex\n\n\tcreated := make([]telegraf.TrackingID, 0, count)\n\tdelivered := make([]telegraf.TrackingID, 0, count)\n\tinputs := make([]telegraf.Metric, 0, count)\n\texpected := make([]telegraf.Metric, 0, count)\n\tfor i := range count {\n\t\tm := metric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": i},\n\t\t\ttime.Unix(0, 0),\n\t\t)\n\t\ttm, tid := metric.WithTracking(m, func(di telegraf.DeliveryInfo) {\n\t\t\tmu.Lock()\n\t\t\tdefer mu.Unlock()\n\t\t\tt.Logf(\"delivered metric %v successfully: %v\", di.ID(), di.Delivered())\n\t\t\tdelivered = append(delivered, di.ID())\n\t\t})\n\t\tt.Logf(\"tracking metric %v\", tid)\n\t\tinputs = append(inputs, tm)\n\t\texpected = append(expected, tm)\n\t\tcreated = append(created, tid)\n\t}\n\n\t// Create a disk buffer\n\tbuf, err := NewBuffer(\"test\", \"id123\", \"\", 0, \"disk_write_through\", t.TempDir(), true)\n\trequire.NoError(t, err)\n\tdefer buf.Close()\n\tdiskBuf, ok := buf.(*DiskBuffer)\n\trequire.True(t, ok, \"buffer is not a disk buffer\")\n\n\t// Make sure the new buffer is fully empty\n\trequire.Zero(t, diskBuf.length())\n\trequire.Zero(t, diskBuf.entries())\n\n\t// Add a first metric and make sure we get it on transaction. Accept the\n\t// metric simulating that the buffer is up.\n\tt.Log(\"checking first accepted metric\")\n\trequire.Zero(t, buf.Add(inputs[0]))\n\ttx := buf.BeginTransaction(count)\n\ttestutil.RequireMetricsEqual(t, expected[:1], tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Add the remaining metrics except the last one\n\tmiddle := inputs[1 : count-1]\n\tmiddleExpected := expected[1 : count-1]\n\trequire.Zero(t, buf.Add(middle...))\n\n\t// Get the metrics into a batch and keep them to simulate the output was\n\t// not able to deliver the metrics.\n\tt.Log(\"checking rejected batch\")\n\ttx = buf.BeginTransaction(count)\n\ttestutil.RequireMetricsEqual(t, middleExpected, tx.Batch)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\t// Make sure we see the same, kept metrics again on next read\n\tt.Log(\"checking rejected batch a second time\")\n\ttx = buf.BeginTransaction(count)\n\ttestutil.RequireMetricsEqual(t, middleExpected, tx.Batch)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\t// Now read the metrics again but this time we accept the metric to simulate\n\t// the output is back up again.\n\tt.Log(\"checking rejected batch but now accept\")\n\ttx = buf.BeginTransaction(count)\n\ttestutil.RequireMetricsEqual(t, middleExpected, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Add the last metric to the buffer, read it into a batch and accept it\n\tt.Log(\"checking last accepted metric\")\n\trequire.Zero(t, buf.Add(inputs[count-1:]...))\n\ttx = buf.BeginTransaction(count)\n\ttestutil.RequireMetricsEqual(t, expected[count-1:], tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\t// Check that we got a delivery signal for all of the metrics\n\tmu.Lock()\n\tdefer mu.Unlock()\n\trequire.ElementsMatch(t, created, delivered, \"tracking information mismatch\")\n}\n"
  },
  {
    "path": "models/buffer_mem.go",
    "content": "package models\n\nimport (\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// MemoryBuffer stores metrics in a circular buffer.\ntype MemoryBuffer struct {\n\tsync.Mutex\n\tBufferStats\n\n\tbuf   []telegraf.Metric\n\tfirst int // index of the first/oldest metric\n\tlast  int // one after the index of the last/newest metric\n\tsize  int // number of metrics currently in the buffer\n\tcap   int // the capacity of the buffer\n\n\tbatchFirst int // index of the first metric in the batch\n\tbatchSize  int // number of metrics currently in the batch\n}\n\nfunc NewMemoryBuffer(capacity int, stats BufferStats) (*MemoryBuffer, error) {\n\treturn &MemoryBuffer{\n\t\tBufferStats: stats,\n\t\tbuf:         make([]telegraf.Metric, capacity),\n\t\tcap:         capacity,\n\t}, nil\n}\n\nfunc (b *MemoryBuffer) Len() int {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\treturn b.length()\n}\n\nfunc (b *MemoryBuffer) Add(metrics ...telegraf.Metric) int {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\tdropped := 0\n\tfor i := range metrics {\n\t\tif n := b.addMetric(metrics[i]); n != 0 {\n\t\t\tdropped += n\n\t\t}\n\t}\n\n\tb.BufferSize.Set(int64(b.length()))\n\treturn dropped\n}\n\nfunc (b *MemoryBuffer) BeginTransaction(batchSize int) *Transaction {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\toutLen := min(b.size, batchSize)\n\tif outLen == 0 {\n\t\treturn &Transaction{}\n\t}\n\n\tb.batchFirst = b.first\n\tb.batchSize = outLen\n\tbatchIndex := b.batchFirst\n\tbatch := make([]telegraf.Metric, outLen)\n\tfor i := range batch {\n\t\tbatch[i] = b.buf[batchIndex]\n\t\tb.buf[batchIndex] = nil\n\t\tbatchIndex = b.next(batchIndex)\n\t}\n\n\tb.first = b.nextby(b.first, b.batchSize)\n\tb.size -= outLen\n\treturn &Transaction{Batch: batch, valid: true}\n}\n\nfunc (b *MemoryBuffer) EndTransaction(tx *Transaction) {\n\tb.Lock()\n\tdefer b.Unlock()\n\n\t// Ignore invalid transactions and make sure they can only be finished once\n\tif !tx.valid {\n\t\treturn\n\t}\n\ttx.valid = false\n\n\t// Accept metrics\n\tfor _, idx := range tx.Accept {\n\t\tb.metricWritten(tx.Batch[idx])\n\t}\n\n\t// Reject metrics\n\tfor _, idx := range tx.Reject {\n\t\tb.metricRejected(tx.Batch[idx])\n\t}\n\n\t// Keep metrics\n\tkeep := tx.InferKeep()\n\tif len(keep) > 0 {\n\t\trestore := min(len(keep), b.cap-b.size)\n\t\tb.first = b.prevby(b.first, restore)\n\t\tb.size = min(b.size+restore, b.cap)\n\n\t\t// Restore the metrics that fit into the buffer\n\t\tcurrent := b.first\n\t\tfor i := 0; i < restore; i++ {\n\t\t\tb.buf[current] = tx.Batch[keep[i]]\n\t\t\tcurrent = b.next(current)\n\t\t}\n\n\t\t// Drop all remaining metrics\n\t\tfor i := restore; i < len(keep); i++ {\n\t\t\tb.metricDropped(tx.Batch[keep[i]])\n\t\t}\n\t}\n\n\tb.resetBatch()\n\tb.BufferSize.Set(int64(b.length()))\n}\n\nfunc (*MemoryBuffer) Close() error {\n\treturn nil\n}\n\nfunc (b *MemoryBuffer) Stats() BufferStats {\n\treturn b.BufferStats\n}\n\nfunc (b *MemoryBuffer) length() int {\n\treturn min(b.size+b.batchSize, b.cap)\n}\n\nfunc (b *MemoryBuffer) addMetric(m telegraf.Metric) int {\n\tdropped := 0\n\t// Check if Buffer is full\n\tif b.size == b.cap {\n\t\tb.metricDropped(b.buf[b.last])\n\t\tdropped++\n\n\t\tif b.batchSize > 0 {\n\t\t\tb.batchSize--\n\t\t\tb.batchFirst = b.next(b.batchFirst)\n\t\t}\n\t}\n\n\tb.metricAdded(1)\n\n\tb.buf[b.last] = m\n\tb.last = b.next(b.last)\n\n\tif b.size == b.cap {\n\t\tb.first = b.next(b.first)\n\t}\n\n\tb.size = min(b.size+1, b.cap)\n\treturn dropped\n}\n\n// next returns the next index with wrapping.\nfunc (b *MemoryBuffer) next(index int) int {\n\tindex++\n\tif index == b.cap {\n\t\treturn 0\n\t}\n\treturn index\n}\n\n// nextby returns the index that is count newer with wrapping.\nfunc (b *MemoryBuffer) nextby(index, count int) int {\n\tindex += count\n\tindex %= b.cap\n\treturn index\n}\n\n// prevby returns the index that is count older with wrapping.\nfunc (b *MemoryBuffer) prevby(index, count int) int {\n\tindex -= count\n\tfor index < 0 {\n\t\tindex += b.cap\n\t}\n\n\tindex %= b.cap\n\treturn index\n}\n\nfunc (b *MemoryBuffer) resetBatch() {\n\tb.batchFirst = 0\n\tb.batchSize = 0\n}\n"
  },
  {
    "path": "models/buffer_mem_test.go",
    "content": "package models\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nfunc TestMemoryBufferAcceptCallsMetricAccept(t *testing.T) {\n\tbuf, err := NewBuffer(\"test\", \"123\", \"\", 5, \"memory\", \"\", true)\n\trequire.NoError(t, err)\n\tbuf.Stats().MetricsAdded.Set(0)\n\tbuf.Stats().MetricsWritten.Set(0)\n\tbuf.Stats().MetricsDropped.Set(0)\n\tdefer buf.Close()\n\n\tvar accept int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tAcceptF: func() {\n\t\t\taccept++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm)\n\ttx := buf.BeginTransaction(2)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\trequire.Equal(t, 2, accept)\n}\n\nfunc BenchmarkMemoryBufferAddMetrics(b *testing.B) {\n\tbuf, err := NewBuffer(\"test\", \"123\", \"\", 10000, \"memory\", \"\", true)\n\trequire.NoError(b, err)\n\tbuf.Stats().MetricsAdded.Set(0)\n\tbuf.Stats().MetricsWritten.Set(0)\n\tbuf.Stats().MetricsDropped.Set(0)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tfor n := 0; n < b.N; n++ {\n\t\tbuf.Add(m)\n\t}\n}\n"
  },
  {
    "path": "models/buffer_suite_test.go",
    "content": "package models\n\nimport (\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype BufferSuiteTest struct {\n\tsuite.Suite\n\tbufferType string\n\tbufferPath string\n\n\thasMaxCapacity bool // whether the buffer type being tested supports a maximum metric capacity\n}\n\nfunc (s *BufferSuiteTest) SetupTest() {\n\tswitch s.bufferType {\n\tcase \"\", \"memory\":\n\t\ts.hasMaxCapacity = true\n\tcase \"disk_write_through\":\n\t\tpath, err := os.MkdirTemp(\"\", \"*-buffer-test\")\n\t\ts.Require().NoError(err)\n\t\ts.bufferPath = path\n\t\ts.hasMaxCapacity = false\n\t}\n}\n\nfunc (s *BufferSuiteTest) TearDownTest() {\n\tif s.bufferPath != \"\" {\n\t\ts.NoError(os.RemoveAll(s.bufferPath))\n\t\ts.bufferPath = \"\"\n\t}\n}\n\nfunc TestMemoryBufferSuite(t *testing.T) {\n\tsuite.Run(t, &BufferSuiteTest{bufferType: \"memory\"})\n}\n\nfunc TestDiskBufferSuite(t *testing.T) {\n\tsuite.Run(t, &BufferSuiteTest{bufferType: \"disk_write_through\"})\n}\n\nfunc (s *BufferSuiteTest) newTestBuffer(capacity int) Buffer {\n\ts.T().Helper()\n\tbuf, err := NewBuffer(\"test\", \"123\", \"\", capacity, s.bufferType, s.bufferPath, true)\n\ts.Require().NoError(err)\n\tbuf.Stats().MetricsAdded.Set(0)\n\tbuf.Stats().MetricsWritten.Set(0)\n\tbuf.Stats().MetricsRejected.Set(0)\n\tbuf.Stats().MetricsDropped.Set(0)\n\treturn buf\n}\n\nfunc (s *BufferSuiteTest) TestBufferLenEmpty() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\ts.Equal(0, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferLenOne() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m)\n\ts.Equal(1, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferLenFull() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ts.Equal(5, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferLenOverfill() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m, m)\n\ts.Equal(5, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenZero() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\ttx := buf.BeginTransaction(0)\n\ts.Empty(tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenBufferEmpty() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\ttx := buf.BeginTransaction(2)\n\ts.Empty(tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenUnderfill() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m)\n\ttx := buf.BeginTransaction(2)\n\ts.Len(tx.Batch, 1)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenFill() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ts.Len(tx.Batch, 2)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenExact() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m)\n\ttx := buf.BeginTransaction(2)\n\ts.Len(tx.Batch, 2)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLenLargerThanBuffer() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(6)\n\ts.Len(tx.Batch, 5)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchWrap() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\tbuf.Add(m, m)\n\ttx = buf.BeginTransaction(5)\n\ts.Len(tx.Batch, 5)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLatest() {\n\tbuf := s.newTestBuffer(4)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchLatestWrap() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(4)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\ttx := buf.BeginTransaction(2)\n\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferMultipleBatch() {\n\tbuf := s.newTestBuffer(10)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\ttx := buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t}, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)),\n\t\t}, tx.Batch)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectWithRoom() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectNothingNewFull() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\ttx := buf.BeginTransaction(2)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectNoRoom() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(3), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectRoomExact() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectRoomOverwriteOld() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(1)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(1), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectPartialRoom() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(2), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectNewMetricsWrapped() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\n\t// buffer: 1, 4, 5; batch: 2, 3\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get())\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(9, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(10, 0)))\n\n\t// buffer: 8, 9, 10, 6, 7; batch: 2, 3\n\ts.Equal(int64(3), buf.Stats().MetricsDropped.Get())\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(13, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(14, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(15, 0)))\n\t// buffer: 13, 14, 15, 11, 12; batch: 2, 3\n\ts.Equal(int64(8), buf.Stats().MetricsDropped.Get())\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(10), buf.Stats().MetricsDropped.Get())\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(13, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(14, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(15, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectWrapped() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)))\n\ttx := buf.BeginTransaction(3)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(9, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(10, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)))\n\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ttx = buf.BeginTransaction(5)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(9, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(10, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectAdjustFirst() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(10)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(3)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(4, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(5, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(6, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(7, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(8, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(9, 0)))\n\ttx = buf.BeginTransaction(3)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(10, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(13, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(14, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(15, 0)))\n\ttx = buf.BeginTransaction(3)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(16, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(17, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(18, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(19, 0)))\n\n\ttx = buf.BeginTransaction(10)\n\ttestutil.RequireMetricsEqual(s.T(),\n\t\t[]telegraf.Metric{\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(10, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(11, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(12, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(13, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(14, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(15, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(16, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(17, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(18, 0)),\n\t\t\tmetric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(19, 0)),\n\t\t}, tx.Batch)\n}\n\nfunc (s *BufferSuiteTest) TestBufferAddDropsOverwrittenMetrics() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\tbuf.Add(m, m, m, m, m)\n\n\ts.Equal(int64(5), buf.Stats().MetricsDropped.Get())\n\ts.Equal(int64(0), buf.Stats().MetricsWritten.Get())\n}\n\nfunc (s *BufferSuiteTest) TestBufferAcceptRemovesBatch() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(1, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectLeavesBatch() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(3, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferAcceptWritesOverwrittenBatch() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(5)\n\tbuf.Add(m, m, m, m, m)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get())\n\ts.Equal(int64(5), buf.Stats().MetricsWritten.Get())\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchRejectDropsOverwrittenBatch() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(5)\n\tbuf.Add(m, m, m, m, m)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\n\ts.Equal(int64(5), buf.Stats().MetricsDropped.Get())\n\ts.Equal(int64(0), buf.Stats().MetricsWritten.Get())\n}\n\nfunc (s *BufferSuiteTest) TestBufferMetricsOverwriteBatchAccept() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(3)\n\tbuf.Add(m, m, m)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get(), \"dropped\")\n\ts.Equal(int64(3), buf.Stats().MetricsWritten.Get(), \"written\")\n}\n\nfunc (s *BufferSuiteTest) TestBufferMetricsOverwriteBatchReject() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(3)\n\tbuf.Add(m, m, m)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(int64(3), buf.Stats().MetricsDropped.Get())\n\ts.Equal(int64(0), buf.Stats().MetricsWritten.Get())\n}\n\nfunc (s *BufferSuiteTest) TestBufferMetricsBatchAcceptRemoved() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(3)\n\tbuf.Add(m, m, m, m, m)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(int64(2), buf.Stats().MetricsDropped.Get())\n\ts.Equal(int64(3), buf.Stats().MetricsWritten.Get())\n}\n\nfunc (s *BufferSuiteTest) TestBufferWrapWithBatch() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m)\n\ttx := buf.BeginTransaction(3)\n\tbuf.Add(m, m, m, m, m, m)\n\ts.Equal(int64(1), buf.Stats().MetricsDropped.Get())\n\tbuf.EndTransaction(tx)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchNotRemoved() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ts.Equal(5, buf.Len())\n\tbuf.EndTransaction(tx)\n}\n\nfunc (s *BufferSuiteTest) TestBufferBatchRejectAcceptNoop() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\ttx := buf.BeginTransaction(2)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(5, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferAddCallsMetricRejectWhenNoBatch() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tvar reject int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tRejectF: func() {\n\t\t\treject++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm, mm, mm)\n\tbuf.Add(mm, mm)\n\ts.Equal(2, reject)\n}\n\nfunc (s *BufferSuiteTest) TestBufferAddCallsMetricRejectWhenNotInBatch() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tvar reject int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tRejectF: func() {\n\t\t\treject++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm, mm, mm)\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(2, reject)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(4, reject)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectCallsMetricRejectWithOverwritten() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tvar reject int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tRejectF: func() {\n\t\t\treject++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm, mm, mm)\n\ttx := buf.BeginTransaction(5)\n\tbuf.Add(mm, mm)\n\ts.Equal(0, reject)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(2, reject)\n}\n\nfunc (s *BufferSuiteTest) TestBufferAddOverwriteAndReject() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tvar reject int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tRejectF: func() {\n\t\t\treject++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm, mm, mm)\n\ttx := buf.BeginTransaction(5)\n\tbuf.Add(mm, mm, mm, mm, mm)\n\tbuf.Add(mm, mm, mm, mm, mm)\n\tbuf.Add(mm, mm, mm, mm, mm)\n\tbuf.Add(mm, mm, mm, mm, mm)\n\ts.Equal(15, reject)\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(20, reject)\n}\n\nfunc (s *BufferSuiteTest) TestBufferAddOverwriteAndRejectOffset() {\n\tif !s.hasMaxCapacity {\n\t\ts.T().Skip(\"tested buffer does not have a maximum capacity\")\n\t}\n\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tvar reject int\n\tvar accept int\n\tmm := &mockMetric{\n\t\tMetric: metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0)),\n\t\tRejectF: func() {\n\t\t\treject++\n\t\t},\n\t\tAcceptF: func() {\n\t\t\taccept++\n\t\t},\n\t}\n\tbuf.Add(mm, mm, mm)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(2, reject)\n\ttx := buf.BeginTransaction(5)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(2, reject)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(5, reject)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(9, reject)\n\tbuf.Add(mm, mm, mm, mm)\n\ts.Equal(13, reject)\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(13, reject)\n\ts.Equal(5, accept)\n}\n\nfunc (s *BufferSuiteTest) TestBufferRejectEmptyBatch() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\ttx := buf.BeginTransaction(2)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\ttx.KeepAll()\n\tbuf.EndTransaction(tx)\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\ttx = buf.BeginTransaction(2)\n\tfor _, m := range tx.Batch {\n\t\ts.NotNil(m)\n\t}\n\tbuf.EndTransaction(tx)\n}\n\nfunc (s *BufferSuiteTest) TestBufferFlushedPartial() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(3, 0)))\n\ttx := buf.BeginTransaction(2)\n\ts.Len(tx.Batch, 2)\n\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(1, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestBufferFlushedFull() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(1, 0)))\n\tbuf.Add(metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(2, 0)))\n\ttx := buf.BeginTransaction(2)\n\ts.Len(tx.Batch, 2)\n\n\ttx.AcceptAll()\n\tbuf.EndTransaction(tx)\n\ts.Equal(0, buf.Len())\n}\n\nfunc (s *BufferSuiteTest) TestPartialWriteBackToFront() {\n\tbuf := s.newTestBuffer(5)\n\tdefer buf.Close()\n\n\tm := metric.New(\"cpu\", map[string]string{}, map[string]interface{}{\"value\": 42.0}, time.Unix(0, 0))\n\tbuf.Add(m, m, m, m, m)\n\n\t// Get a batch of all metrics but only reject the last one\n\ttx := buf.BeginTransaction(5)\n\ts.Len(tx.Batch, 5)\n\ttx.Reject = []int{4}\n\tbuf.EndTransaction(tx)\n\ts.Equal(4, buf.Len())\n\n\t// Get the next batch which should miss the last metric\n\ttx = buf.BeginTransaction(5)\n\ts.Len(tx.Batch, 4)\n\ttx.Accept = []int{3}\n\tbuf.EndTransaction(tx)\n\ts.Equal(3, buf.Len())\n\n\t// Now get the next batch and reject the remaining metrics\n\ttx = buf.BeginTransaction(5)\n\ts.Len(tx.Batch, 3)\n\ttx.Accept = []int{0, 1, 2}\n\tbuf.EndTransaction(tx)\n\ts.Equal(0, buf.Len())\n\n\ts.Equal(int64(5), buf.Stats().MetricsAdded.Get(), \"metrics added\")\n\ts.Equal(int64(4), buf.Stats().MetricsWritten.Get(), \"metrics written\")\n\ts.Equal(int64(1), buf.Stats().MetricsRejected.Get(), \"metrics rejected\")\n\ts.Equal(int64(0), buf.Stats().MetricsDropped.Get(), \"metrics dropped\")\n}\n\ntype mockMetric struct {\n\ttelegraf.Metric\n\tAcceptF func()\n\tRejectF func()\n\tDropF   func()\n}\n\nfunc (m *mockMetric) Accept() {\n\tif m.AcceptF != nil {\n\t\tm.AcceptF()\n\t}\n}\n\nfunc (m *mockMetric) Reject() {\n\tif m.RejectF != nil {\n\t\tm.RejectF()\n\t}\n}\n\nfunc (m *mockMetric) Drop() {\n\tif m.DropF != nil {\n\t\tm.DropF()\n\t}\n}\n"
  },
  {
    "path": "models/common.go",
    "content": "package models\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n// logName returns the log-friendly name/type.\nfunc logName(pluginType, name, alias string) string {\n\tif alias == \"\" {\n\t\treturn pluginType + \".\" + name\n\t}\n\treturn pluginType + \".\" + name + \"::\" + alias\n}\n\nfunc SetLoggerOnPlugin(i interface{}, logger telegraf.Logger) {\n\tvalI := reflect.ValueOf(i)\n\n\tif valI.Type().Kind() != reflect.Ptr {\n\t\tvalI = reflect.New(reflect.TypeOf(i))\n\t}\n\n\tfield := valI.Elem().FieldByName(\"Log\")\n\tif !field.IsValid() {\n\t\treturn\n\t}\n\n\tif field.Type().String() != \"telegraf.Logger\" || !field.CanSet() {\n\t\tlogger.Debugf(\n\t\t\t\"Plugin %q defines a 'Log' field on its struct of an unexpected type %q. Expected telegraf.Logger\",\n\t\t\tvalI.Type().Name(), field.Type().String(),\n\t\t)\n\t\treturn\n\t}\n\n\tfield.Set(reflect.ValueOf(logger))\n}\n\nfunc SetStatisticsOnPlugin(plugin interface{}, logger telegraf.Logger, tags map[string]string) {\n\t// Find the statistics collector\n\tinstance := reflect.Indirect(reflect.ValueOf(plugin))\n\tfield := instance.FieldByName(\"Statistics\")\n\tif !field.IsValid() {\n\t\treturn\n\t}\n\n\t// Validate the type and make sure we can actually set the struct field\n\tif field.Type().String() != \"*selfstat.Collector\" || !field.CanSet() {\n\t\tlogger.Debugf(\n\t\t\t\"Plugin %q defines a 'Statistics' field on its struct of an unexpected type %q. Expected *selfstat.Collector\",\n\t\t\tinstance.Type().Name(), field.Type().String(),\n\t\t)\n\t\treturn\n\t}\n\n\t// Create a new collector and set it\n\tcollector := selfstat.NewCollector(tags)\n\tfield.Set(reflect.ValueOf(collector))\n}\n"
  },
  {
    "path": "models/filter.go",
    "content": "package models\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/google/cel-go/common/decls\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/google/cel-go/common/types/ref\"\n\t\"github.com/google/cel-go/ext\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n)\n\n// TagFilter is the name of a tag, and the values on which to filter\ntype TagFilter struct {\n\tName   string\n\tValues []string\n\tfilter filter.Filter\n}\n\nfunc (tf *TagFilter) Compile() error {\n\tf, err := filter.Compile(tf.Values)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttf.filter = f\n\treturn nil\n}\n\n// Filter containing drop/pass and include/exclude rules\ntype Filter struct {\n\tNameDrop           []string\n\tNameDropSeparators string\n\tnameDropFilter     filter.Filter\n\tNamePass           []string\n\tNamePassSeparators string\n\tnamePassFilter     filter.Filter\n\n\tFieldExclude       []string\n\tfieldExcludeFilter filter.Filter\n\tFieldInclude       []string\n\tfieldIncludeFilter filter.Filter\n\n\tTagDropFilters []TagFilter\n\tTagPassFilters []TagFilter\n\n\tTagExclude       []string\n\ttagExcludeFilter filter.Filter\n\tTagInclude       []string\n\ttagIncludeFilter filter.Filter\n\n\t// New metric-filtering interface\n\tMetricPass   string\n\tmetricFilter cel.Program\n\n\tselectActive bool\n\tmodifyActive bool\n\n\tisActive bool\n}\n\n// Compile all Filter lists into filter.Filter objects.\nfunc (f *Filter) Compile() error {\n\tf.selectActive = len(f.NamePass) > 0 || len(f.NameDrop) > 0\n\tf.selectActive = f.selectActive || len(f.TagPassFilters) > 0 || len(f.TagDropFilters) > 0\n\tf.selectActive = f.selectActive || f.MetricPass != \"\"\n\n\tf.modifyActive = len(f.FieldInclude) > 0 || len(f.FieldExclude) > 0\n\tf.modifyActive = f.modifyActive || len(f.TagInclude) > 0 || len(f.TagExclude) > 0\n\n\tf.isActive = f.selectActive || f.modifyActive\n\n\tif !f.isActive {\n\t\treturn nil\n\t}\n\n\tif f.selectActive {\n\t\tvar err error\n\t\tf.nameDropFilter, err = filter.Compile(f.NameDrop, []rune(f.NameDropSeparators)...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'namedrop', %w\", err)\n\t\t}\n\t\tf.namePassFilter, err = filter.Compile(f.NamePass, []rune(f.NamePassSeparators)...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'namepass', %w\", err)\n\t\t}\n\n\t\tfor i := range f.TagPassFilters {\n\t\t\tif err := f.TagPassFilters[i].Compile(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error compiling 'tagpass', %w\", err)\n\t\t\t}\n\t\t}\n\t\tfor i := range f.TagDropFilters {\n\t\t\tif err := f.TagDropFilters[i].Compile(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error compiling 'tagdrop', %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif f.modifyActive {\n\t\tvar err error\n\t\tf.fieldExcludeFilter, err = filter.Compile(f.FieldExclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'fieldexclude', %w\", err)\n\t\t}\n\t\tf.fieldIncludeFilter, err = filter.Compile(f.FieldInclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'fieldinclude', %w\", err)\n\t\t}\n\n\t\tf.tagExcludeFilter, err = filter.Compile(f.TagExclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'tagexclude', %w\", err)\n\t\t}\n\t\tf.tagIncludeFilter, err = filter.Compile(f.TagInclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'taginclude', %w\", err)\n\t\t}\n\t}\n\n\treturn f.compileMetricFilter()\n}\n\n// Select returns true if the metric matches according to the\n// namepass/namedrop, tagpass/tagdrop and metric filters.\n// The metric is not modified.\nfunc (f *Filter) Select(metric telegraf.Metric) (bool, error) {\n\tif !f.selectActive {\n\t\treturn true, nil\n\t}\n\n\tif !f.shouldNamePass(metric.Name()) {\n\t\treturn false, nil\n\t}\n\n\tif !f.shouldTagsPass(metric.TagList()) {\n\t\treturn false, nil\n\t}\n\n\tif f.metricFilter != nil {\n\t\tresult, _, err := f.metricFilter.Eval(map[string]interface{}{\n\t\t\t\"name\":   metric.Name(),\n\t\t\t\"tags\":   metric.Tags(),\n\t\t\t\"fields\": metric.Fields(),\n\t\t\t\"time\":   metric.Time(),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn true, err\n\t\t}\n\t\tif r, ok := result.Value().(bool); ok {\n\t\t\treturn r, nil\n\t\t}\n\t\treturn true, fmt.Errorf(\"invalid result type %T\", result.Value())\n\t}\n\n\treturn true, nil\n}\n\n// Modify removes any tags and fields from the metric according to the\n// fieldinclude/fieldexclude and taginclude/tagexclude filters.\nfunc (f *Filter) Modify(metric telegraf.Metric) {\n\tif !f.modifyActive {\n\t\treturn\n\t}\n\n\tf.filterFields(metric)\n\tf.filterTags(metric)\n}\n\n// IsActive checking if filter is active\nfunc (f *Filter) IsActive() bool {\n\treturn f.isActive\n}\n\n// shouldNamePass returns true if the metric should pass, false if it should drop\n// based on the drop/pass filter parameters\nfunc (f *Filter) shouldNamePass(key string) bool {\n\tpass := func(f *Filter) bool {\n\t\treturn f.namePassFilter.Match(key)\n\t}\n\n\tdrop := func(f *Filter) bool {\n\t\treturn !f.nameDropFilter.Match(key)\n\t}\n\n\tif f.namePassFilter != nil && f.nameDropFilter != nil {\n\t\treturn pass(f) && drop(f)\n\t} else if f.namePassFilter != nil {\n\t\treturn pass(f)\n\t} else if f.nameDropFilter != nil {\n\t\treturn drop(f)\n\t}\n\n\treturn true\n}\n\n// shouldTagsPass returns true if the metric should pass, false if it should drop\n// based on the tagdrop/tagpass filter parameters\nfunc (f *Filter) shouldTagsPass(tags []*telegraf.Tag) bool {\n\treturn ShouldTagsPass(f.TagPassFilters, f.TagDropFilters, tags)\n}\n\n// filterFields removes fields according to fieldinclude/fieldexclude.\nfunc (f *Filter) filterFields(metric telegraf.Metric) {\n\tfilterKeys := make([]string, 0, len(metric.FieldList()))\n\tfor _, field := range metric.FieldList() {\n\t\tif !ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field.Key) {\n\t\t\tfilterKeys = append(filterKeys, field.Key)\n\t\t}\n\t}\n\n\tfor _, key := range filterKeys {\n\t\tmetric.RemoveField(key)\n\t}\n}\n\n// filterTags removes tags according to taginclude/tagexclude.\nfunc (f *Filter) filterTags(metric telegraf.Metric) {\n\tfilterKeys := make([]string, 0, len(metric.TagList()))\n\tfor _, tag := range metric.TagList() {\n\t\tif !ShouldPassFilters(f.tagIncludeFilter, f.tagExcludeFilter, tag.Key) {\n\t\t\tfilterKeys = append(filterKeys, tag.Key)\n\t\t}\n\t}\n\n\tfor _, key := range filterKeys {\n\t\tmetric.RemoveTag(key)\n\t}\n}\n\n// Compile the metric filter\nfunc (f *Filter) compileMetricFilter() error {\n\t// Reset internal state\n\tf.metricFilter = nil\n\n\t// Initialize the expression\n\texpression := f.MetricPass\n\n\t// Check if we need to call into CEL at all and quit early\n\tif expression == \"\" {\n\t\treturn nil\n\t}\n\n\t// Declare the computation environment for the filter including custom functions\n\tenv, err := cel.NewEnv(\n\t\tcel.VariableDecls(\n\t\t\tdecls.NewVariable(\"name\", types.StringType),\n\t\t\tdecls.NewVariable(\"tags\", types.NewMapType(types.StringType, types.StringType)),\n\t\t\tdecls.NewVariable(\"fields\", types.NewMapType(types.StringType, types.DynType)),\n\t\t\tdecls.NewVariable(\"time\", types.TimestampType),\n\t\t),\n\t\tcel.Function(\n\t\t\t\"now\",\n\t\t\tcel.Overload(\"now\", nil, cel.TimestampType),\n\t\t\tcel.SingletonFunctionBinding(func(_ ...ref.Val) ref.Val { return types.Timestamp{Time: time.Now()} }),\n\t\t),\n\t\text.Encoders(),\n\t\text.Math(),\n\t\text.Strings(),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating environment failed: %w\", err)\n\t}\n\n\t// Compile the program\n\tast, issues := env.Compile(expression)\n\tif issues.Err() != nil {\n\t\treturn issues.Err()\n\t}\n\t// Check if we got a boolean expression needed for filtering\n\tif ast.OutputType() != cel.BoolType {\n\t\treturn errors.New(\"expression needs to return a boolean\")\n\t}\n\n\t// Get the final program\n\toptions := cel.EvalOptions(\n\t\tcel.OptOptimize,\n\t)\n\tf.metricFilter, err = env.Program(ast, options)\n\treturn err\n}\n\nfunc ShouldPassFilters(include, exclude filter.Filter, key string) bool {\n\tif include != nil && exclude != nil {\n\t\treturn include.Match(key) && !exclude.Match(key)\n\t} else if include != nil {\n\t\treturn include.Match(key)\n\t} else if exclude != nil {\n\t\treturn !exclude.Match(key)\n\t}\n\treturn true\n}\n\nfunc ShouldTagsPass(passFilters, dropFilters []TagFilter, tags []*telegraf.Tag) bool {\n\tpass := func(tpf []TagFilter) bool {\n\t\tfor _, pat := range tpf {\n\t\t\tif pat.filter == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, tag := range tags {\n\t\t\t\tif tag.Key == pat.Name {\n\t\t\t\t\tif pat.filter.Match(tag.Value) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\n\tdrop := func(tdf []TagFilter) bool {\n\t\tfor _, pat := range tdf {\n\t\t\tif pat.filter == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, tag := range tags {\n\t\t\t\tif tag.Key == pat.Name {\n\t\t\t\t\tif pat.filter.Match(tag.Value) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n\t// Add additional logic in case where both parameters are set.\n\t// see: https://github.com/influxdata/telegraf/issues/2860\n\tif passFilters != nil && dropFilters != nil {\n\t\t// return true only in case when tag pass and won't be dropped (true, true).\n\t\t// in case when the same tag should be passed and dropped it will be dropped (true, false).\n\t\treturn pass(passFilters) && drop(dropFilters)\n\t} else if passFilters != nil {\n\t\treturn pass(passFilters)\n\t} else if dropFilters != nil {\n\t\treturn drop(dropFilters)\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "models/filter_test.go",
    "content": "package models\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nfunc TestFilterApplyEmpty(t *testing.T) {\n\tf := Filter{}\n\trequire.NoError(t, f.Compile())\n\trequire.False(t, f.IsActive())\n\n\tm := metric.New(\"m\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\"value\": int64(1)},\n\t\ttime.Now())\n\tselected, err := f.Select(m)\n\trequire.NoError(t, err)\n\trequire.True(t, selected)\n}\n\nfunc TestFilterApplyTagsDontPass(t *testing.T) {\n\tfilters := []TagFilter{\n\t\t{\n\t\t\tName:   \"cpu\",\n\t\t\tValues: []string{\"cpu-*\"},\n\t\t},\n\t}\n\tf := Filter{\n\t\tTagDropFilters: filters,\n\t}\n\trequire.NoError(t, f.Compile())\n\trequire.NoError(t, f.Compile())\n\trequire.True(t, f.IsActive())\n\n\tm := metric.New(\"m\",\n\t\tmap[string]string{\"cpu\": \"cpu-total\"},\n\t\tmap[string]interface{}{\"value\": int64(1)},\n\t\ttime.Now())\n\tselected, err := f.Select(m)\n\trequire.NoError(t, err)\n\trequire.False(t, selected)\n}\n\nfunc TestFilterApplyDeleteFields(t *testing.T) {\n\tf := Filter{\n\t\tFieldExclude: []string{\"value\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\trequire.NoError(t, f.Compile())\n\trequire.True(t, f.IsActive())\n\n\tm := metric.New(\"m\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\":  int64(1),\n\t\t\t\"value2\": int64(2),\n\t\t},\n\t\ttime.Now())\n\tselected, err := f.Select(m)\n\trequire.NoError(t, err)\n\trequire.True(t, selected)\n\tf.Modify(m)\n\trequire.Equal(t, map[string]interface{}{\"value2\": int64(2)}, m.Fields())\n}\n\nfunc TestFilterApplyDeleteAllFields(t *testing.T) {\n\tf := Filter{\n\t\tFieldExclude: []string{\"value*\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\trequire.NoError(t, f.Compile())\n\trequire.True(t, f.IsActive())\n\n\tm := metric.New(\"m\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\":  int64(1),\n\t\t\t\"value2\": int64(2),\n\t\t},\n\t\ttime.Now())\n\tselected, err := f.Select(m)\n\trequire.NoError(t, err)\n\trequire.True(t, selected)\n\tf.Modify(m)\n\trequire.Empty(t, m.FieldList())\n}\n\nfunc TestFilterEmpty(t *testing.T) {\n\tf := Filter{}\n\n\tmeasurements := []string{\n\t\t\"foo\",\n\t\t\"bar\",\n\t\t\"barfoo\",\n\t\t\"foo_bar\",\n\t\t\"foo.bar\",\n\t\t\"foo-bar\",\n\t\t\"supercalifragilisticexpialidocious\",\n\t}\n\n\tfor _, measurement := range measurements {\n\t\tif !f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to pass\", measurement)\n\t\t}\n\t}\n}\n\nfunc TestFilterNamePass(t *testing.T) {\n\tf := Filter{\n\t\tNamePass: []string{\"foo*\", \"cpu_usage_idle\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tpasses := []string{\n\t\t\"foo\",\n\t\t\"foo_bar\",\n\t\t\"foo.bar\",\n\t\t\"foo-bar\",\n\t\t\"cpu_usage_idle\",\n\t}\n\n\tdrops := []string{\n\t\t\"bar\",\n\t\t\"barfoo\",\n\t\t\"bar_foo\",\n\t\t\"cpu_usage_busy\",\n\t}\n\n\tfor _, measurement := range passes {\n\t\tif !f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to pass\", measurement)\n\t\t}\n\t}\n\n\tfor _, measurement := range drops {\n\t\tif f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to drop\", measurement)\n\t\t}\n\t}\n}\n\nfunc TestFilterNamePass_WithSeparator(t *testing.T) {\n\tf := Filter{\n\t\tNamePass:           []string{\"foo.*.bar\", \"foo.*.abc.*.bar\"},\n\t\tNamePassSeparators: \".,\",\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tpasses := []string{\n\t\t\"foo..bar\",\n\t\t\"foo.abc.bar\",\n\t\t\"foo..abc..bar\",\n\t\t\"foo.xyz.abc.xyz-xyz.bar\",\n\t}\n\n\tdrops := []string{\n\t\t\"foo.bar\",\n\t\t\"foo.abc,.bar\", // \"abc,\" is not considered under * as ',' is specified as a separator\n\t\t\"foo..abc.bar\", // \".abc\" shall not be matched under * as '.' is specified as a separator\n\t\t\"foo.abc.abc.bar\",\n\t\t\"foo.xyz.abc.xyz.xyz.bar\",\n\t\t\"foo.xyz.abc.xyz,xyz.bar\",\n\t}\n\n\tfor _, measurement := range passes {\n\t\tif !f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to pass\", measurement)\n\t\t}\n\t}\n\n\tfor _, measurement := range drops {\n\t\tif f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to drop\", measurement)\n\t\t}\n\t}\n}\n\nfunc TestFilterNameDrop(t *testing.T) {\n\tf := Filter{\n\t\tNameDrop: []string{\"foo*\", \"cpu_usage_idle\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tdrops := []string{\n\t\t\"foo\",\n\t\t\"foo_bar\",\n\t\t\"foo.bar\",\n\t\t\"foo-bar\",\n\t\t\"cpu_usage_idle\",\n\t}\n\n\tpasses := []string{\n\t\t\"bar\",\n\t\t\"barfoo\",\n\t\t\"bar_foo\",\n\t\t\"cpu_usage_busy\",\n\t}\n\n\tfor _, measurement := range passes {\n\t\tif !f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to pass\", measurement)\n\t\t}\n\t}\n\n\tfor _, measurement := range drops {\n\t\tif f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to drop\", measurement)\n\t\t}\n\t}\n}\n\nfunc TestFilterNameDrop_WithSeparator(t *testing.T) {\n\tf := Filter{\n\t\tNameDrop:           []string{\"foo.*.bar\", \"foo.*.abc.*.bar\"},\n\t\tNameDropSeparators: \".,\",\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tdrops := []string{\n\t\t\"foo..bar\",\n\t\t\"foo.abc.bar\",\n\t\t\"foo..abc..bar\",\n\t\t\"foo.xyz.abc.xyz-xyz.bar\",\n\t}\n\n\tpasses := []string{\n\t\t\"foo.bar\",\n\t\t\"foo.abc,.bar\", // \"abc,\" is not considered under * as ',' is specified as a separator\n\t\t\"foo..abc.bar\", // \".abc\" shall not be matched under * as '.' is specified as a separator\n\t\t\"foo.abc.abc.bar\",\n\t\t\"foo.xyz.abc.xyz.xyz.bar\",\n\t\t\"foo.xyz.abc.xyz,xyz.bar\",\n\t}\n\n\tfor _, measurement := range passes {\n\t\tif !f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to pass\", measurement)\n\t\t}\n\t}\n\n\tfor _, measurement := range drops {\n\t\tif f.shouldNamePass(measurement) {\n\t\t\tt.Errorf(\"Expected measurement %s to drop\", measurement)\n\t\t}\n\t}\n}\n\nfunc TestFilterFieldInclude(t *testing.T) {\n\tf := Filter{\n\t\tFieldInclude: []string{\"foo*\", \"cpu_usage_idle\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tpasses := []string{\n\t\t\"foo\",\n\t\t\"foo_bar\",\n\t\t\"foo.bar\",\n\t\t\"foo-bar\",\n\t\t\"cpu_usage_idle\",\n\t}\n\n\tdrops := []string{\n\t\t\"bar\",\n\t\t\"barfoo\",\n\t\t\"bar_foo\",\n\t\t\"cpu_usage_busy\",\n\t}\n\n\tfor _, field := range passes {\n\t\trequire.Truef(t, ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field), \"Expected field %s to pass\", field)\n\t}\n\n\tfor _, field := range drops {\n\t\trequire.Falsef(t, ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field), \"Expected field %s to drop\", field)\n\t}\n}\n\nfunc TestFilterFieldExclude(t *testing.T) {\n\tf := Filter{\n\t\tFieldExclude: []string{\"foo*\", \"cpu_usage_idle\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tdrops := []string{\n\t\t\"foo\",\n\t\t\"foo_bar\",\n\t\t\"foo.bar\",\n\t\t\"foo-bar\",\n\t\t\"cpu_usage_idle\",\n\t}\n\n\tpasses := []string{\n\t\t\"bar\",\n\t\t\"barfoo\",\n\t\t\"bar_foo\",\n\t\t\"cpu_usage_busy\",\n\t}\n\n\tfor _, field := range passes {\n\t\trequire.Truef(t, ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field), \"Expected field %s to pass\", field)\n\t}\n\n\tfor _, field := range drops {\n\t\trequire.Falsef(t, ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field), \"Expected field %s to drop\", field)\n\t}\n}\n\nfunc TestFilterTagPass(t *testing.T) {\n\tfilters := []TagFilter{\n\t\t{\n\t\t\tName:   \"cpu\",\n\t\t\tValues: []string{\"cpu-*\"},\n\t\t},\n\t\t{\n\t\t\tName:   \"mem\",\n\t\t\tValues: []string{\"mem_free\"},\n\t\t}}\n\tf := Filter{\n\t\tTagPassFilters: filters,\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tpasses := [][]*telegraf.Tag{\n\t\t{{Key: \"cpu\", Value: \"cpu-total\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-0\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-1\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-2\"}},\n\t\t{{Key: \"mem\", Value: \"mem_free\"}},\n\t}\n\n\tdrops := [][]*telegraf.Tag{\n\t\t{{Key: \"cpu\", Value: \"cputotal\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu0\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu1\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu2\"}},\n\t\t{{Key: \"mem\", Value: \"mem_used\"}},\n\t}\n\n\tfor _, tags := range passes {\n\t\tif !f.shouldTagsPass(tags) {\n\t\t\tt.Errorf(\"Expected tags %v to pass\", tags)\n\t\t}\n\t}\n\n\tfor _, tags := range drops {\n\t\tif f.shouldTagsPass(tags) {\n\t\t\tt.Errorf(\"Expected tags %v to drop\", tags)\n\t\t}\n\t}\n}\n\nfunc TestFilterTagDrop(t *testing.T) {\n\tfilters := []TagFilter{\n\t\t{\n\t\t\tName:   \"cpu\",\n\t\t\tValues: []string{\"cpu-*\"},\n\t\t},\n\t\t{\n\t\t\tName:   \"mem\",\n\t\t\tValues: []string{\"mem_free\"},\n\t\t}}\n\tf := Filter{\n\t\tTagDropFilters: filters,\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tdrops := [][]*telegraf.Tag{\n\t\t{{Key: \"cpu\", Value: \"cpu-total\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-0\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-1\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu-2\"}},\n\t\t{{Key: \"mem\", Value: \"mem_free\"}},\n\t}\n\n\tpasses := [][]*telegraf.Tag{\n\t\t{{Key: \"cpu\", Value: \"cputotal\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu0\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu1\"}},\n\t\t{{Key: \"cpu\", Value: \"cpu2\"}},\n\t\t{{Key: \"mem\", Value: \"mem_used\"}},\n\t}\n\n\tfor _, tags := range passes {\n\t\tif !f.shouldTagsPass(tags) {\n\t\t\tt.Errorf(\"Expected tags %v to pass\", tags)\n\t\t}\n\t}\n\n\tfor _, tags := range drops {\n\t\tif f.shouldTagsPass(tags) {\n\t\t\tt.Errorf(\"Expected tags %v to drop\", tags)\n\t\t}\n\t}\n}\n\nfunc TestFilterTagsNoMatches(t *testing.T) {\n\tm := metric.New(\"m\",\n\t\tmap[string]string{\n\t\t\t\"host\":  \"localhost\",\n\t\t\t\"mytag\": \"foobar\",\n\t\t},\n\t\tmap[string]interface{}{\"value\": int64(1)},\n\t\ttime.Now())\n\tf := Filter{\n\t\tTagExclude: []string{\"nomatch\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tf.filterTags(m)\n\trequire.Equal(t, map[string]string{\n\t\t\"host\":  \"localhost\",\n\t\t\"mytag\": \"foobar\",\n\t}, m.Tags())\n\n\tf = Filter{\n\t\tTagInclude: []string{\"nomatch\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tf.filterTags(m)\n\trequire.Equal(t, map[string]string{}, m.Tags())\n}\n\nfunc TestFilterTagsMatches(t *testing.T) {\n\tm := metric.New(\"m\",\n\t\tmap[string]string{\n\t\t\t\"host\":  \"localhost\",\n\t\t\t\"mytag\": \"foobar\",\n\t\t},\n\t\tmap[string]interface{}{\"value\": int64(1)},\n\t\ttime.Now())\n\tf := Filter{\n\t\tTagExclude: []string{\"ho*\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tf.filterTags(m)\n\trequire.Equal(t, map[string]string{\n\t\t\"mytag\": \"foobar\",\n\t}, m.Tags())\n\n\tm = metric.New(\"m\",\n\t\tmap[string]string{\n\t\t\t\"host\":  \"localhost\",\n\t\t\t\"mytag\": \"foobar\",\n\t\t},\n\t\tmap[string]interface{}{\"value\": int64(1)},\n\t\ttime.Now())\n\tf = Filter{\n\t\tTagInclude: []string{\"my*\"},\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tf.filterTags(m)\n\trequire.Equal(t, map[string]string{\n\t\t\"mytag\": \"foobar\",\n\t}, m.Tags())\n}\n\n// TestFilter_FilterNamePassAndDrop used for check case when\n// both parameters were defined\n// see: https://github.com/influxdata/telegraf/issues/2860\nfunc TestFilterNamePassAndDrop(t *testing.T) {\n\tinputData := []string{\"name1\", \"name2\", \"name3\", \"name4\"}\n\texpectedResult := []bool{false, true, false, false}\n\n\tf := Filter{\n\t\tNamePass: []string{\"name1\", \"name2\"},\n\t\tNameDrop: []string{\"name1\", \"name3\"},\n\t}\n\n\trequire.NoError(t, f.Compile())\n\n\tfor i, name := range inputData {\n\t\trequire.Equal(t, f.shouldNamePass(name), expectedResult[i])\n\t}\n}\n\n// TestFilter_FieldIncludeAndExclude used for check case when\n// both parameters were defined\n// see: https://github.com/influxdata/telegraf/issues/2860\nfunc TestFilterFieldIncludeAndExclude(t *testing.T) {\n\tinputData := []string{\"field1\", \"field2\", \"field3\", \"field4\"}\n\texpectedResult := []bool{false, true, false, false}\n\n\tf := Filter{\n\t\tFieldInclude: []string{\"field1\", \"field2\"},\n\t\tFieldExclude: []string{\"field1\", \"field3\"},\n\t}\n\n\trequire.NoError(t, f.Compile())\n\n\tfor i, field := range inputData {\n\t\trequire.Equal(t, ShouldPassFilters(f.fieldIncludeFilter, f.fieldExcludeFilter, field), expectedResult[i])\n\t}\n}\n\n// TestFilter_FilterTagsPassAndDrop used for check case when\n// both parameters were defined\n// see: https://github.com/influxdata/telegraf/issues/2860\nfunc TestFilterTagsPassAndDrop(t *testing.T) {\n\tinputData := [][]*telegraf.Tag{\n\t\t{{Key: \"tag1\", Value: \"1\"}, {Key: \"tag2\", Value: \"3\"}},\n\t\t{{Key: \"tag1\", Value: \"1\"}, {Key: \"tag2\", Value: \"2\"}},\n\t\t{{Key: \"tag1\", Value: \"2\"}, {Key: \"tag2\", Value: \"1\"}},\n\t\t{{Key: \"tag1\", Value: \"4\"}, {Key: \"tag2\", Value: \"1\"}},\n\t}\n\n\texpectedResult := []bool{false, true, false, false}\n\n\tfilterPass := []TagFilter{\n\t\t{\n\t\t\tName:   \"tag1\",\n\t\t\tValues: []string{\"1\", \"4\"},\n\t\t},\n\t}\n\n\tfilterDrop := []TagFilter{\n\t\t{\n\t\t\tName:   \"tag1\",\n\t\t\tValues: []string{\"4\"},\n\t\t},\n\t\t{\n\t\t\tName:   \"tag2\",\n\t\t\tValues: []string{\"3\"},\n\t\t},\n\t}\n\n\tf := Filter{\n\t\tTagDropFilters: filterDrop,\n\t\tTagPassFilters: filterPass,\n\t}\n\trequire.NoError(t, f.Compile())\n\n\tfor i, tag := range inputData {\n\t\trequire.Equal(t, f.shouldTagsPass(tag), expectedResult[i])\n\t}\n}\n\nfunc TestFilterMetricPass(t *testing.T) {\n\tm := metric.New(\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"host\":   \"Hugin\",\n\t\t\t\"source\": \"myserver@mycompany.com\",\n\t\t\t\"status\": \"ok\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\":  15.0,\n\t\t\t\"id\":     \"24cxnwr3480k\",\n\t\t\t\"on\":     true,\n\t\t\t\"count\":  18,\n\t\t\t\"errors\": 29,\n\t\t\t\"total\":  129,\n\t\t},\n\t\ttime.Date(2023, time.April, 24, 23, 30, 15, 42, time.UTC),\n\t)\n\n\tvar tests = []struct {\n\t\tname       string\n\t\texpression string\n\t\texpected   bool\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:       \"exact name match (pass)\",\n\t\t\texpression: `name == \"cpu\"`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"exact name match (fail)\",\n\t\t\texpression: `name == \"test\"`,\n\t\t\texpected:   false,\n\t\t},\n\t\t{\n\t\t\tname:       \"case-insensitive tag match\",\n\t\t\texpression: `tags.host.lowerAscii() == \"hugin\"`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"regexp tag match\",\n\t\t\texpression: `tags.source.matches(\"^[0-9a-zA-z-_]+@mycompany.com$\")`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"match field value\",\n\t\t\texpression: `fields.count > 10`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"match timestamp year\",\n\t\t\texpression: `time.getFullYear() == 2023`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"now\",\n\t\t\texpression: `now() > time`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"arithmetic\",\n\t\t\texpression: `fields.count + fields.errors < fields.total`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"logical expression\",\n\t\t\texpression: `(name.startsWith(\"t\") || fields.on) && \"id\" in fields && fields.id.contains(\"nwr\")`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"time arithmetic\",\n\t\t\texpression: `time >= timestamp(\"2023-04-25T00:00:00Z\") - duration(\"24h\")`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"complex field filtering\",\n\t\t\texpression: `fields.exists(f, type(fields[f]) in [int, uint, double] && fields[f] > 20.0)`,\n\t\t\texpected:   true,\n\t\t},\n\t\t{\n\t\t\tname:       \"complex field filtering (exactly one)\",\n\t\t\texpression: `fields.exists_one(f, type(fields[f]) in [int, uint, double] && fields[f] > 20.0)`,\n\t\t\texpected:   false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tf := Filter{\n\t\t\t\tMetricPass: tt.expression,\n\t\t\t}\n\t\t\trequire.NoError(t, f.Compile())\n\t\t\tselected, err := f.Select(m)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, selected)\n\t\t})\n\t}\n}\n\nfunc BenchmarkFilter(b *testing.B) {\n\ttests := []struct {\n\t\tname   string\n\t\tfilter Filter\n\t\tmetric telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:   \"empty filter\",\n\t\t\tfilter: Filter{},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"namepass\",\n\t\t\tfilter: Filter{\n\t\t\t\tNamePass: []string{\"cpu\"},\n\t\t\t},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"metric filter exact name\",\n\t\t\tfilter: Filter{\n\t\t\t\tMetricPass: `name == \"cpu\"`,\n\t\t\t},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"metric filter regexp\",\n\t\t\tfilter: Filter{\n\t\t\t\tMetricPass: `name.matches(\"^c[a-z]*$\")`,\n\t\t\t},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"metric filter time\",\n\t\t\tfilter: Filter{\n\t\t\t\tMetricPass: `time >= timestamp(\"2023-04-25T00:00:00Z\") - duration(\"24h\")`,\n\t\t\t},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"metric filter complex\",\n\t\t\tfilter: Filter{\n\t\t\t\tMetricPass: `\"source\" in tags` +\n\t\t\t\t\t` && fields.exists(f, type(fields[f]) in [int, uint, double] && fields[f] > 20.0)` +\n\t\t\t\t\t` && time >= timestamp(\"2023-04-25T00:00:00Z\") - duration(\"24h\")`,\n\t\t\t},\n\t\t\tmetric: metric.New(\"cpu\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"value\": 42,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tb.Run(tt.name, func(b *testing.B) {\n\t\t\trequire.NoError(b, tt.filter.Compile())\n\t\t\tfor n := 0; n < b.N; n++ {\n\t\t\t\t_, err := tt.filter.Select(tt.metric)\n\t\t\t\trequire.NoError(b, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "models/makemetric.go",
    "content": "package models\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\n// makeMetric applies new metric plugin and agent measurement and tag settings.\nfunc makeMetric(metric telegraf.Metric, nameOverride, namePrefix, nameSuffix string, tags, globalTags map[string]string) telegraf.Metric {\n\tif len(nameOverride) != 0 {\n\t\tmetric.SetName(nameOverride)\n\t}\n\n\tif len(namePrefix) != 0 {\n\t\tmetric.AddPrefix(namePrefix)\n\t}\n\tif len(nameSuffix) != 0 {\n\t\tmetric.AddSuffix(nameSuffix)\n\t}\n\n\t// Apply plugin-wide tags\n\tfor k, v := range tags {\n\t\tif _, ok := metric.GetTag(k); !ok {\n\t\t\tmetric.AddTag(k, v)\n\t\t}\n\t}\n\t// Apply global tags\n\tfor k, v := range globalTags {\n\t\tif _, ok := metric.GetTag(k); !ok {\n\t\t\tmetric.AddTag(k, v)\n\t\t}\n\t}\n\n\treturn metric\n}\n"
  },
  {
    "path": "models/running_aggregator.go",
    "content": "package models\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\ntype RunningAggregator struct {\n\tsync.Mutex\n\tAggregator  telegraf.Aggregator\n\tConfig      *AggregatorConfig\n\tperiodStart time.Time\n\tperiodEnd   time.Time\n\tlog         telegraf.Logger\n\n\tMetricsPushed   selfstat.Stat\n\tMetricsFiltered selfstat.Stat\n\tMetricsDropped  selfstat.Stat\n\tPushTime        selfstat.Stat\n}\n\nfunc NewRunningAggregator(aggregator telegraf.Aggregator, config *AggregatorConfig) *RunningAggregator {\n\ttags := map[string]string{\n\t\t\"_id\":        config.ID,\n\t\t\"aggregator\": config.Name,\n\t}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\taggErrorsRegister := selfstat.Register(\"aggregate\", \"errors\", tags)\n\tlogger := logging.New(\"aggregators\", config.Name, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\taggErrorsRegister.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(aggregator, logger)\n\tSetStatisticsOnPlugin(aggregator, logger, tags)\n\n\treturn &RunningAggregator{\n\t\tAggregator: aggregator,\n\t\tConfig:     config,\n\t\tMetricsPushed: selfstat.Register(\n\t\t\t\"aggregate\",\n\t\t\t\"metrics_pushed\",\n\t\t\ttags,\n\t\t),\n\t\tMetricsFiltered: selfstat.Register(\n\t\t\t\"aggregate\",\n\t\t\t\"metrics_filtered\",\n\t\t\ttags,\n\t\t),\n\t\tMetricsDropped: selfstat.Register(\n\t\t\t\"aggregate\",\n\t\t\t\"metrics_dropped\",\n\t\t\ttags,\n\t\t),\n\t\tPushTime: selfstat.Register(\n\t\t\t\"aggregate\",\n\t\t\t\"push_time_ns\",\n\t\t\ttags,\n\t\t),\n\t\tlog: logger,\n\t}\n}\n\n// AggregatorConfig is the common config for all aggregators.\ntype AggregatorConfig struct {\n\tName         string\n\tSource       string\n\tAlias        string\n\tID           string\n\tDropOriginal bool\n\tPeriod       time.Duration\n\tDelay        time.Duration\n\tGrace        time.Duration\n\tLogLevel     string\n\n\tNameOverride      string\n\tMeasurementPrefix string\n\tMeasurementSuffix string\n\tTags              map[string]string\n\tFilter            Filter\n}\n\nfunc (r *RunningAggregator) LogName() string {\n\treturn logName(\"aggregators\", r.Config.Name, r.Config.Alias)\n}\n\nfunc (r *RunningAggregator) Init() error {\n\tif p, ok := r.Aggregator.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *RunningAggregator) ID() string {\n\tif p, ok := r.Aggregator.(telegraf.PluginWithID); ok {\n\t\treturn p.ID()\n\t}\n\treturn r.Config.ID\n}\n\nfunc (r *RunningAggregator) Period() time.Duration {\n\treturn r.Config.Period\n}\n\nfunc (r *RunningAggregator) EndPeriod() time.Time {\n\treturn r.periodEnd\n}\n\nfunc (r *RunningAggregator) UpdateWindow(start, until time.Time) {\n\tr.periodStart = start\n\tr.periodEnd = until\n\tr.log.Debugf(\"Updated aggregation range [%s, %s]\", start, until)\n}\n\nfunc (r *RunningAggregator) MakeMetric(telegrafMetric telegraf.Metric) telegraf.Metric {\n\tm := makeMetric(\n\t\ttelegrafMetric,\n\t\tr.Config.NameOverride,\n\t\tr.Config.MeasurementPrefix,\n\t\tr.Config.MeasurementSuffix,\n\t\tr.Config.Tags,\n\t\tnil)\n\n\tr.MetricsPushed.Incr(1)\n\n\treturn m\n}\n\n// Add a metric to the aggregator and return true if the original metric\n// should be dropped.\nfunc (r *RunningAggregator) Add(m telegraf.Metric) bool {\n\tok, err := r.Config.Filter.Select(m)\n\tif err != nil {\n\t\tr.log.Errorf(\"filtering failed: %v\", err)\n\t} else if !ok {\n\t\treturn false\n\t}\n\n\t// Make a copy of the metric but don't retain tracking.  We do not fail a\n\t// delivery due to the aggregation not being sent because we can't create\n\t// aggregations of historical data.  Additionally, waiting for the\n\t// aggregation to be pushed would introduce a hefty latency to delivery.\n\tm = metric.FromMetric(m)\n\n\tr.Config.Filter.Modify(m)\n\tif len(m.FieldList()) == 0 {\n\t\tr.MetricsFiltered.Incr(1)\n\t\treturn r.Config.DropOriginal\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tif m.Time().Before(r.periodStart.Add(-r.Config.Grace)) || m.Time().After(r.periodEnd.Add(r.Config.Delay)) {\n\t\tr.log.Debugf(\"Metric is outside aggregation window; discarding. %s: m: %s e: %s g: %s\",\n\t\t\tm.Time(), r.periodStart, r.periodEnd, r.Config.Grace)\n\t\tr.MetricsDropped.Incr(1)\n\t\treturn r.Config.DropOriginal\n\t}\n\n\tr.Aggregator.Add(m)\n\treturn r.Config.DropOriginal\n}\n\nfunc (r *RunningAggregator) Push(acc telegraf.Accumulator) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tsince := r.periodEnd\n\tuntil := r.periodEnd.Add(r.Config.Period)\n\n\t// Check if the next aggregation window will contain \"now\". This might\n\t// not be the case if the machine's clock was adjusted or the machine\n\t// hibernated as in those cases the clock might be advanced before or\n\t// after the initial aggregation window.\n\tnowWall := time.Now().Truncate(-1)\n\tif nowWall.Before(since.Truncate(-1)) || nowWall.After(until.Truncate(-1)) {\n\t\tsince = nowWall.Truncate(r.Config.Period)\n\t\tuntil = since.Add(r.Config.Period)\n\t}\n\n\tr.UpdateWindow(since, until)\n\n\tstart := time.Now()\n\tr.Aggregator.Push(acc)\n\telapsed := time.Since(start)\n\tr.PushTime.Incr(elapsed.Nanoseconds())\n\tr.Aggregator.Reset()\n}\n\nfunc (r *RunningAggregator) Log() telegraf.Logger {\n\treturn r.log\n}\n"
  },
  {
    "path": "models/running_aggregator_test.go",
    "content": "package models\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRunningAggregatorAdd(t *testing.T) {\n\ta := &mockAggregator{}\n\tra := NewRunningAggregator(a, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tNamePass: []string{\"*\"},\n\t\t},\n\t\tPeriod: time.Millisecond * 500,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\tacc := testutil.Accumulator{}\n\n\tnow := time.Now()\n\tra.UpdateWindow(now, now.Add(ra.Config.Period))\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\ttime.Now().Add(time.Millisecond*150),\n\t\ttelegraf.Untyped)\n\trequire.False(t, ra.Add(m))\n\tra.Push(&acc)\n\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, int64(101), acc.Metrics[0].Fields[\"sum\"])\n}\n\nfunc TestRunningAggregatorAddMetricsOutsideCurrentPeriod(t *testing.T) {\n\ta := &mockAggregator{}\n\tra := NewRunningAggregator(a, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tNamePass: []string{\"*\"},\n\t\t},\n\t\tPeriod: time.Millisecond * 500,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\tacc := testutil.Accumulator{}\n\tnow := time.Now()\n\tra.UpdateWindow(now, now.Add(ra.Config.Period))\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow.Add(-time.Hour),\n\t\ttelegraf.Untyped,\n\t)\n\trequire.False(t, ra.Add(m))\n\n\t// metric after current period\n\tm = metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow.Add(time.Hour),\n\t\ttelegraf.Untyped,\n\t)\n\trequire.False(t, ra.Add(m))\n\n\t// \"now\" metric\n\tm = metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\ttime.Now().Add(time.Millisecond*50),\n\t\ttelegraf.Untyped)\n\trequire.False(t, ra.Add(m))\n\n\tra.Push(&acc)\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, int64(101), acc.Metrics[0].Fields[\"sum\"])\n}\n\nfunc TestRunningAggregatorAddMetricsOutsideCurrentPeriodWithGrace(t *testing.T) {\n\ta := &mockAggregator{}\n\tra := NewRunningAggregator(a, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tNamePass: []string{\"*\"},\n\t\t},\n\t\tPeriod: time.Millisecond * 1500,\n\t\tGrace:  time.Millisecond * 500,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\tacc := testutil.Accumulator{}\n\tnow := time.Now()\n\tra.UpdateWindow(now, now.Add(ra.Config.Period))\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow.Add(-time.Hour),\n\t\ttelegraf.Untyped,\n\t)\n\trequire.False(t, ra.Add(m))\n\n\t// metric before current period (late)\n\tm = metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(100),\n\t\t},\n\t\tnow.Add(-time.Millisecond*1000),\n\t\ttelegraf.Untyped,\n\t)\n\trequire.False(t, ra.Add(m))\n\n\t// metric before current period, but within grace period (late)\n\tm = metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(102),\n\t\t},\n\t\tnow.Add(-time.Millisecond*200),\n\t\ttelegraf.Untyped,\n\t)\n\trequire.False(t, ra.Add(m))\n\n\t// \"now\" metric\n\tm = metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\ttime.Now().Add(time.Millisecond*50),\n\t\ttelegraf.Untyped)\n\trequire.False(t, ra.Add(m))\n\n\tra.Push(&acc)\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, int64(203), acc.Metrics[0].Fields[\"sum\"])\n}\n\nfunc TestRunningAggregatorAddAndPushOnePeriod(t *testing.T) {\n\ta := &mockAggregator{}\n\tra := NewRunningAggregator(a, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tNamePass: []string{\"*\"},\n\t\t},\n\t\tPeriod: time.Millisecond * 500,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\tacc := testutil.Accumulator{}\n\n\tnow := time.Now()\n\tra.UpdateWindow(now, now.Add(ra.Config.Period))\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\ttime.Now().Add(time.Millisecond*100),\n\t\ttelegraf.Untyped)\n\trequire.False(t, ra.Add(m))\n\n\tra.Push(&acc)\n\n\tacc.AssertContainsFields(t, \"TestMetric\", map[string]interface{}{\"sum\": int64(101)})\n}\n\nfunc TestRunningAggregatorAddDropOriginal(t *testing.T) {\n\tra := NewRunningAggregator(&mockAggregator{}, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tNamePass: []string{\"RI*\"},\n\t\t},\n\t\tDropOriginal: true,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\n\tnow := time.Now()\n\tra.UpdateWindow(now, now.Add(ra.Config.Period))\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\trequire.True(t, ra.Add(m))\n\n\t// this metric name doesn't match the filter, so Add will return false\n\tm2 := metric.New(\"foobar\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\trequire.False(t, ra.Add(m2))\n}\n\nfunc TestRunningAggregatorAddDoesNotModifyMetric(t *testing.T) {\n\tra := NewRunningAggregator(&mockAggregator{}, &AggregatorConfig{\n\t\tName: \"TestRunningAggregator\",\n\t\tFilter: Filter{\n\t\t\tFieldInclude: []string{\"a\"},\n\t\t},\n\t\tDropOriginal: true,\n\t})\n\trequire.NoError(t, ra.Config.Filter.Compile())\n\n\tnow := time.Now()\n\n\tm := metric.New(\n\t\t\"cpu\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"a\": int64(42),\n\t\t\t\"b\": int64(42),\n\t\t},\n\t\tnow)\n\texpected := m.Copy()\n\tra.Add(m)\n\n\ttestutil.RequireMetricEqual(t, expected, m)\n}\n\ntype mockAggregator struct {\n\tsum int64\n}\n\nfunc (*mockAggregator) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (t *mockAggregator) Reset() {\n\tt.sum = 0\n}\n\nfunc (t *mockAggregator) Push(acc telegraf.Accumulator) {\n\tacc.AddFields(\"TestMetric\",\n\t\tmap[string]interface{}{\"sum\": t.sum},\n\t\tmap[string]string{},\n\t)\n}\n\nfunc (t *mockAggregator) Add(in telegraf.Metric) {\n\tfor _, v := range in.Fields() {\n\t\tif vi, ok := v.(int64); ok {\n\t\t\tt.sum += vi\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "models/running_input.go",
    "content": "package models\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\nvar (\n\tGlobalMetricsGathered = selfstat.Register(\"agent\", \"metrics_gathered\", make(map[string]string))\n\tGlobalGatherErrors    = selfstat.Register(\"agent\", \"gather_errors\", make(map[string]string))\n\tGlobalGatherTimeouts  = selfstat.Register(\"agent\", \"gather_timeouts\", make(map[string]string))\n)\n\ntype RunningInput struct {\n\tInput  telegraf.Input\n\tConfig *InputConfig\n\n\tlog         telegraf.Logger\n\tdefaultTags map[string]string\n\n\tstartAcc    telegraf.Accumulator\n\tstarted     bool\n\tretries     uint64\n\tgatherStart time.Time\n\tgatherEnd   time.Time\n\n\tMetricsGathered selfstat.Stat\n\tGatherTime      selfstat.Stat\n\tGatherTimeouts  selfstat.Stat\n\tStartupErrors   selfstat.Stat\n}\n\nfunc NewRunningInput(input telegraf.Input, config *InputConfig) *RunningInput {\n\ttags := map[string]string{\n\t\t\"_id\":   config.ID,\n\t\t\"input\": config.Name,\n\t}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\tinputErrorsRegister := selfstat.Register(\"gather\", \"errors\", tags)\n\tlogger := logging.New(\"inputs\", config.Name, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\tinputErrorsRegister.Incr(1)\n\t\tGlobalGatherErrors.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(input, logger)\n\tSetStatisticsOnPlugin(input, logger, tags)\n\n\treturn &RunningInput{\n\t\tInput:  input,\n\t\tConfig: config,\n\t\tMetricsGathered: selfstat.Register(\n\t\t\t\"gather\",\n\t\t\t\"metrics_gathered\",\n\t\t\ttags,\n\t\t),\n\t\tGatherTime: selfstat.RegisterTiming(\n\t\t\t\"gather\",\n\t\t\t\"gather_time_ns\",\n\t\t\ttags,\n\t\t),\n\t\tGatherTimeouts: selfstat.Register(\n\t\t\t\"gather\",\n\t\t\t\"gather_timeouts\",\n\t\t\ttags,\n\t\t),\n\t\tStartupErrors: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"startup_errors\",\n\t\t\ttags,\n\t\t),\n\t\tlog: logger,\n\t}\n}\n\n// InputConfig is the common config for all inputs.\ntype InputConfig struct {\n\tName                 string\n\tSource               string\n\tAlias                string\n\tID                   string\n\tInterval             time.Duration\n\tCollectionJitter     time.Duration\n\tCollectionOffset     time.Duration\n\tPrecision            time.Duration\n\tTimeSource           string\n\tStartupErrorBehavior string\n\tLogLevel             string\n\n\tNameOverride            string\n\tMeasurementPrefix       string\n\tMeasurementSuffix       string\n\tTags                    map[string]string\n\tFilter                  Filter\n\tAlwaysIncludeLocalTags  bool\n\tAlwaysIncludeGlobalTags bool\n}\n\nfunc (*RunningInput) metricFiltered(metric telegraf.Metric) {\n\tmetric.Drop()\n}\n\nfunc (r *RunningInput) LogName() string {\n\treturn logName(\"inputs\", r.Config.Name, r.Config.Alias)\n}\n\nfunc (r *RunningInput) Init() error {\n\tswitch r.Config.StartupErrorBehavior {\n\tcase \"\", \"error\", \"retry\", \"ignore\", \"probe\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'startup_error_behavior' setting %q\", r.Config.StartupErrorBehavior)\n\t}\n\n\tswitch r.Config.TimeSource {\n\tcase \"\":\n\t\tr.Config.TimeSource = \"metric\"\n\tcase \"metric\", \"collection_start\", \"collection_end\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'time_source' setting %q\", r.Config.TimeSource)\n\t}\n\n\tif p, ok := r.Input.(telegraf.Initializer); ok {\n\t\treturn p.Init()\n\t}\n\treturn nil\n}\n\nfunc (r *RunningInput) Start(acc telegraf.Accumulator) error {\n\tplugin, ok := r.Input.(telegraf.ServiceInput)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\t// Try to start the plugin and exit early on success\n\tr.startAcc = acc\n\terr := plugin.Start(acc)\n\tif err == nil {\n\t\tr.started = true\n\t\treturn nil\n\t}\n\tr.StartupErrors.Incr(1)\n\n\t// Check if the plugin reports a retry-able error, otherwise we exit.\n\tvar serr *internal.StartupError\n\tif !errors.As(err, &serr) {\n\t\treturn err\n\t}\n\n\t// Handle the retry-able error depending on the configured behavior\n\tswitch r.Config.StartupErrorBehavior {\n\tcase \"\", \"error\": // fall-trough to return the actual error\n\tcase \"retry\":\n\t\tif !serr.Retry {\n\t\t\treturn err\n\t\t}\n\t\tr.log.Infof(\"Startup failed: %v; retrying...\", err)\n\t\treturn nil\n\tcase \"ignore\", \"probe\":\n\t\treturn &internal.FatalError{Err: serr}\n\tdefault:\n\t\tr.log.Errorf(\"Invalid 'startup_error_behavior' setting %q\", r.Config.StartupErrorBehavior)\n\t}\n\n\treturn err\n}\n\nfunc (r *RunningInput) Probe() error {\n\tp, ok := r.Input.(telegraf.ProbePlugin)\n\tif !ok || r.Config.StartupErrorBehavior != \"probe\" {\n\t\treturn nil\n\t}\n\treturn p.Probe()\n}\n\nfunc (r *RunningInput) Stop() {\n\tif plugin, ok := r.Input.(telegraf.ServiceInput); ok {\n\t\tplugin.Stop()\n\t}\n}\n\nfunc (r *RunningInput) ID() string {\n\tif p, ok := r.Input.(telegraf.PluginWithID); ok {\n\t\treturn p.ID()\n\t}\n\treturn r.Config.ID\n}\n\nfunc (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric {\n\tok, err := r.Config.Filter.Select(metric)\n\tif err != nil {\n\t\tr.log.Errorf(\"filtering failed: %v\", err)\n\t} else if !ok {\n\t\tr.metricFiltered(metric)\n\t\treturn nil\n\t}\n\n\tmakeMetric(\n\t\tmetric,\n\t\tr.Config.NameOverride,\n\t\tr.Config.MeasurementPrefix,\n\t\tr.Config.MeasurementSuffix,\n\t\tr.Config.Tags,\n\t\tr.defaultTags)\n\n\tr.Config.Filter.Modify(metric)\n\tif len(metric.FieldList()) == 0 {\n\t\tr.metricFiltered(metric)\n\t\treturn nil\n\t}\n\n\tif r.Config.AlwaysIncludeLocalTags || r.Config.AlwaysIncludeGlobalTags {\n\t\tvar local, global map[string]string\n\t\tif r.Config.AlwaysIncludeLocalTags {\n\t\t\tlocal = r.Config.Tags\n\t\t}\n\t\tif r.Config.AlwaysIncludeGlobalTags {\n\t\t\tglobal = r.defaultTags\n\t\t}\n\t\tmakeMetric(metric, \"\", \"\", \"\", local, global)\n\t}\n\n\tswitch r.Config.TimeSource {\n\tcase \"collection_start\":\n\t\tmetric.SetTime(r.gatherStart)\n\tcase \"collection_end\":\n\t\tmetric.SetTime(r.gatherEnd)\n\tdefault:\n\t}\n\n\tr.MetricsGathered.Incr(1)\n\tGlobalMetricsGathered.Incr(1)\n\treturn metric\n}\n\nfunc (r *RunningInput) Gather(acc telegraf.Accumulator) error {\n\t// Try to connect if we are not yet started up\n\tif plugin, ok := r.Input.(telegraf.ServiceInput); ok && !r.started {\n\t\tr.retries++\n\t\tif err := plugin.Start(r.startAcc); err != nil {\n\t\t\tvar serr *internal.StartupError\n\t\t\tif !errors.As(err, &serr) || !serr.Retry || !serr.Partial {\n\t\t\t\tr.StartupErrors.Incr(1)\n\t\t\t\treturn internal.ErrNotConnected\n\t\t\t}\n\t\t\tr.log.Debugf(\"Partially connected after %d attempts\", r.retries)\n\t\t} else {\n\t\t\tr.started = true\n\t\t\tr.log.Debugf(\"Successfully connected after %d attempts\", r.retries)\n\t\t}\n\t}\n\n\tr.gatherStart = time.Now()\n\terr := r.Input.Gather(acc)\n\tr.gatherEnd = time.Now()\n\n\tr.GatherTime.Incr(r.gatherEnd.Sub(r.gatherStart).Nanoseconds())\n\treturn err\n}\n\nfunc (r *RunningInput) SetDefaultTags(tags map[string]string) {\n\tr.defaultTags = tags\n}\n\nfunc (r *RunningInput) Log() telegraf.Logger {\n\treturn r.log\n}\n\nfunc (r *RunningInput) IncrGatherTimeouts() {\n\tGlobalGatherTimeouts.Incr(1)\n\tr.GatherTimeouts.Incr(1)\n}\n"
  },
  {
    "path": "models/running_input_test.go",
    "content": "package models\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRunningInputMakeMetricFilterAfterApplyingGlobalTags(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"b\"},\n\t\t},\n\t})\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\tri.SetDefaultTags(map[string]string{\"a\": \"x\", \"b\": \"y\"})\n\n\tm := metric.New(\"cpu\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 42,\n\t\t},\n\t\tnow)\n\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"cpu\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"y\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 42,\n\t\t},\n\t\tnow)\n\n\ttestutil.RequireMetricEqual(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricNoFields(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\trequire.Nil(t, actual)\n}\n\n// nil fields should get dropped\nfunc TestRunningInputMakeMetricNilFields(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t\t\"nil\":   nil,\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int(101),\n\t\t},\n\t\tnow,\n\t)\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithPluginTags(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricFilteredOut(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tFilter: Filter{NamePass: []string{\"foobar\"}},\n\t})\n\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\trequire.Nil(t, actual)\n}\n\nfunc TestRunningInputMakeMetricWithDaemonTags(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t})\n\tri.SetDefaultTags(map[string]string{\n\t\t\"foo\": \"bar\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricNameOverride(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:         \"TestRunningInput\",\n\t\tNameOverride: \"foobar\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\texpected := metric.New(\"foobar\",\n\t\tnil,\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricNamePrefix(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:              \"TestRunningInput\",\n\t\tMeasurementPrefix: \"foobar_\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\texpected := metric.New(\"foobar_RITest\",\n\t\tnil,\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricNameSuffix(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:              \"TestRunningInput\",\n\t\tMeasurementSuffix: \"_foobar\",\n\t})\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\texpected := metric.New(\"RITest_foobar\",\n\t\tnil,\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMetricErrorCounters(t *testing.T) {\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestMetricErrorCounters\",\n\t})\n\n\tgetGatherErrors := func() int64 {\n\t\tfor _, r := range selfstat.Metrics() {\n\t\t\ttag, hasTag := r.GetTag(\"input\")\n\t\t\tif r.Name() == \"internal_gather\" && hasTag && tag == \"TestMetricErrorCounters\" {\n\t\t\t\terrCount, ok := r.GetField(\"errors\")\n\t\t\t\tif !ok {\n\t\t\t\t\tt.Fatal(\"Expected error field\")\n\t\t\t\t}\n\t\t\t\treturn errCount.(int64)\n\t\t\t}\n\t\t}\n\t\treturn 0\n\t}\n\n\tbefore := getGatherErrors()\n\n\tri.Log().Error(\"Oh no\")\n\n\tafter := getGatherErrors()\n\n\trequire.Greater(t, after, before)\n\trequire.GreaterOrEqual(t, int64(1), GlobalGatherErrors.Get())\n}\n\nfunc TestRunningInputMakeMetricWithAlwaysKeepingPluginTagsDisabled(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"b\"},\n\t\t},\n\t})\n\tri.SetDefaultTags(map[string]string{\"logic\": \"rulez\"})\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"test\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"test\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithAlwaysKeepingLocalPluginTagsEnabled(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"b\"},\n\t\t},\n\t\tAlwaysIncludeLocalTags: true,\n\t})\n\tri.SetDefaultTags(map[string]string{\"logic\": \"rulez\"})\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"test\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\":   \"test\",\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithAlwaysKeepingGlobalPluginTagsEnabled(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"b\"},\n\t\t},\n\t\tAlwaysIncludeGlobalTags: true,\n\t})\n\tri.SetDefaultTags(map[string]string{\"logic\": \"rulez\"})\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"test\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\":     \"test\",\n\t\t\t\"logic\": \"rulez\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithAlwaysKeepingPluginTagsEnabled(t *testing.T) {\n\tnow := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName: \"TestRunningInput\",\n\t\tTags: map[string]string{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"b\"},\n\t\t},\n\t\tAlwaysIncludeLocalTags:  true,\n\t\tAlwaysIncludeGlobalTags: true,\n\t})\n\tri.SetDefaultTags(map[string]string{\"logic\": \"rulez\"})\n\trequire.NoError(t, ri.Config.Filter.Compile())\n\n\tm := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\": \"test\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(101),\n\t\t},\n\t\tnow,\n\t\ttelegraf.Untyped)\n\tactual := ri.MakeMetric(m)\n\n\texpected := metric.New(\"RITest\",\n\t\tmap[string]string{\n\t\t\t\"b\":     \"test\",\n\t\t\t\"foo\":   \"bar\",\n\t\t\t\"logic\": \"rulez\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": 101,\n\t\t},\n\t\tnow,\n\t)\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithGatherMetricTimeSource(t *testing.T) {\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:                    \"TestRunningInput\",\n\t\tTags:                    make(map[string]string),\n\t\tFilter:                  Filter{},\n\t\tAlwaysIncludeLocalTags:  false,\n\t\tAlwaysIncludeGlobalTags: false,\n\t\tTimeSource:              \"metric\",\n\t})\n\tstart := time.Now()\n\tri.gatherStart = start\n\tri.gatherEnd = start.Add(time.Second)\n\n\texpected := testutil.MockMetrics()[0]\n\n\tm := testutil.MockMetrics()[0]\n\tactual := ri.MakeMetric(m)\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithGatherStartTimeSource(t *testing.T) {\n\tstart := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:                    \"TestRunningInput\",\n\t\tTags:                    make(map[string]string),\n\t\tFilter:                  Filter{},\n\t\tAlwaysIncludeLocalTags:  false,\n\t\tAlwaysIncludeGlobalTags: false,\n\t\tTimeSource:              \"collection_start\",\n\t})\n\tri.gatherStart = start\n\n\texpected := testutil.MockMetrics()[0]\n\texpected.SetTime(start)\n\n\tm := testutil.MockMetrics()[0]\n\tactual := ri.MakeMetric(m)\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputMakeMetricWithGatherEndTimeSource(t *testing.T) {\n\tend := time.Now()\n\tri := NewRunningInput(&mockInput{}, &InputConfig{\n\t\tName:       \"TestRunningInput\",\n\t\tTimeSource: \"collection_end\",\n\t})\n\tri.gatherEnd = end\n\n\texpected := testutil.MockMetrics()[0]\n\texpected.SetTime(end)\n\n\tm := testutil.MockMetrics()[0]\n\tactual := ri.MakeMetric(m)\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestRunningInputProbingFailure(t *testing.T) {\n\tri := NewRunningInput(&mockInput{\n\t\tprobeReturn: errors.New(\"probing error\"),\n\t}, &InputConfig{\n\t\tName:                 \"TestRunningInput\",\n\t\tStartupErrorBehavior: \"probe\",\n\t})\n\tri.log = testutil.Logger{}\n\trequire.Error(t, ri.Probe())\n}\n\nfunc TestRunningInputProbingSuccess(t *testing.T) {\n\tprobeErr := errors.New(\"probing error\")\n\tfor _, tt := range []struct {\n\t\tname                 string\n\t\tinput                telegraf.Input\n\t\tstartupErrorBehavior string\n\t}{\n\t\t{\n\t\t\tname:                 \"non-probing plugin with probe value set\",\n\t\t\tinput:                &mockInput{},\n\t\t\tstartupErrorBehavior: \"probe\",\n\t\t},\n\t\t{\n\t\t\tname:                 \"non-probing plugin with probe value not set\",\n\t\t\tinput:                &mockInput{},\n\t\t\tstartupErrorBehavior: \"ignore\",\n\t\t},\n\t\t{\n\t\t\tname:                 \"probing plugin with probe value not set\",\n\t\t\tinput:                &mockInput{probeErr},\n\t\t\tstartupErrorBehavior: \"ignore\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tri := NewRunningInput(tt.input, &InputConfig{\n\t\t\t\tName:                 \"TestRunningInput\",\n\t\t\t\tStartupErrorBehavior: tt.startupErrorBehavior,\n\t\t\t})\n\t\t\tri.log = testutil.Logger{}\n\t\t\trequire.NoError(t, ri.Probe())\n\t\t})\n\t}\n}\n\ntype mockInput struct {\n\tprobeReturn error\n}\n\nfunc (*mockInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (m *mockInput) Probe() error {\n\treturn m.probeReturn\n}\n\nfunc (*mockInput) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n"
  },
  {
    "path": "models/running_output.go",
    "content": "package models\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\nconst (\n\t// Default size of metrics batch size.\n\tDefaultMetricBatchSize = 1000\n\n\t// Default number of metrics kept. It should be a multiple of batch size.\n\tDefaultMetricBufferLimit = 10000\n)\n\n// OutputConfig containing name and filter\ntype OutputConfig struct {\n\tName                 string\n\tSource               string\n\tAlias                string\n\tID                   string\n\tStartupErrorBehavior string\n\tFilter               Filter\n\n\tFlushInterval     time.Duration\n\tFlushJitter       time.Duration\n\tMetricBufferLimit int\n\tMetricBatchSize   int\n\n\tNameOverride string\n\tNamePrefix   string\n\tNameSuffix   string\n\n\tBufferStrategy  string\n\tBufferDirectory string\n\tBufferDiskSync  bool\n\n\tLogLevel string\n}\n\n// RunningOutput contains the output configuration\ntype RunningOutput struct {\n\t// Must be 64-bit aligned\n\tdroppedMetrics  atomic.Int64\n\twriteInFlight   atomic.Bool\n\tlastWriteFailed atomic.Bool\n\n\tOutput            telegraf.Output\n\tConfig            *OutputConfig\n\tMetricBufferLimit int\n\tMetricBatchSize   int\n\n\tMetricsFiltered selfstat.Stat\n\tWriteTime       selfstat.Stat\n\tStartupErrors   selfstat.Stat\n\n\tBatchReady chan time.Time\n\n\tbuffer Buffer\n\tlog    telegraf.Logger\n\n\tstarted bool\n\tretries uint64\n\n\taggMutex sync.Mutex\n}\n\nfunc NewRunningOutput(output telegraf.Output, config *OutputConfig, batchSize, bufferLimit int) *RunningOutput {\n\ttags := map[string]string{\n\t\t\"output\": config.Name,\n\t\t\"_id\":    config.ID,\n\t}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\twriteErrorsRegister := selfstat.Register(\"write\", \"errors\", tags)\n\tlogger := logging.New(\"outputs\", config.Name, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\twriteErrorsRegister.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(output, logger)\n\tSetStatisticsOnPlugin(output, logger, tags)\n\n\tif config.MetricBufferLimit > 0 {\n\t\tbufferLimit = config.MetricBufferLimit\n\t}\n\tif bufferLimit == 0 {\n\t\tbufferLimit = DefaultMetricBufferLimit\n\t}\n\tif config.MetricBatchSize > 0 {\n\t\tbatchSize = config.MetricBatchSize\n\t}\n\tif batchSize == 0 {\n\t\tbatchSize = DefaultMetricBatchSize\n\t}\n\n\tb, err := NewBuffer(config.Name, config.ID, config.Alias, bufferLimit, config.BufferStrategy, config.BufferDirectory, config.BufferDiskSync)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tro := &RunningOutput{\n\t\tbuffer:            b,\n\t\tBatchReady:        make(chan time.Time, 1),\n\t\tOutput:            output,\n\t\tConfig:            config,\n\t\tMetricBufferLimit: bufferLimit,\n\t\tMetricBatchSize:   batchSize,\n\t\tMetricsFiltered: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"metrics_filtered\",\n\t\t\ttags,\n\t\t),\n\t\tWriteTime: selfstat.RegisterTiming(\n\t\t\t\"write\",\n\t\t\t\"write_time_ns\",\n\t\t\ttags,\n\t\t),\n\t\tStartupErrors: selfstat.Register(\n\t\t\t\"write\",\n\t\t\t\"startup_errors\",\n\t\t\ttags,\n\t\t),\n\t\tlog: logger,\n\t}\n\n\treturn ro\n}\n\nfunc (r *RunningOutput) LogName() string {\n\treturn logName(\"outputs\", r.Config.Name, r.Config.Alias)\n}\n\nfunc (r *RunningOutput) metricFiltered(metric telegraf.Metric) {\n\tr.MetricsFiltered.Incr(1)\n\tmetric.Drop()\n}\n\nfunc (r *RunningOutput) ID() string {\n\tif p, ok := r.Output.(telegraf.PluginWithID); ok {\n\t\treturn p.ID()\n\t}\n\treturn r.Config.ID\n}\n\nfunc (r *RunningOutput) Init() error {\n\tswitch r.Config.StartupErrorBehavior {\n\tcase \"\", \"error\", \"retry\", \"ignore\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'startup_error_behavior' setting %q\", r.Config.StartupErrorBehavior)\n\t}\n\n\tif p, ok := r.Output.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *RunningOutput) Connect() error {\n\t// Try to connect and exit early on success\n\terr := r.Output.Connect()\n\tif err == nil {\n\t\tr.started = true\n\t\treturn nil\n\t}\n\tr.StartupErrors.Incr(1)\n\n\t// Check if the plugin reports a retry-able error, otherwise we exit.\n\tvar serr *internal.StartupError\n\tif !errors.As(err, &serr) || !serr.Retry {\n\t\treturn err\n\t}\n\n\t// Handle the retry-able error depending on the configured behavior\n\tswitch r.Config.StartupErrorBehavior {\n\tcase \"\", \"error\": // fall-trough to return the actual error\n\tcase \"retry\":\n\t\tr.log.Infof(\"Connect failed: %v; retrying...\", err)\n\t\treturn nil\n\tcase \"ignore\":\n\t\treturn &internal.FatalError{Err: serr}\n\tdefault:\n\t\tr.log.Errorf(\"Invalid 'startup_error_behavior' setting %q\", r.Config.StartupErrorBehavior)\n\t}\n\n\treturn err\n}\n\n// Close closes the output\nfunc (r *RunningOutput) Close() {\n\tif err := r.Output.Close(); err != nil {\n\t\tr.log.Errorf(\"Error closing output: %v\", err)\n\t}\n\n\tif err := r.buffer.Close(); err != nil {\n\t\tr.log.Errorf(\"Error closing output buffer: %v\", err)\n\t}\n}\n\n// AddMetric adds a metric to the output.\n// The given metric will be copied if the output selects the metric.\nfunc (r *RunningOutput) AddMetric(metric telegraf.Metric) {\n\tok, err := r.Config.Filter.Select(metric)\n\tif err != nil {\n\t\tr.log.Errorf(\"filtering failed: %v\", err)\n\t} else if !ok {\n\t\tr.MetricsFiltered.Incr(1)\n\t\treturn\n\t}\n\n\tr.add(metric.Copy())\n}\n\n// AddMetricNoCopy adds a metric to the output.\n// Takes ownership of metric regardless of whether the output selects it for outputting.\nfunc (r *RunningOutput) AddMetricNoCopy(metric telegraf.Metric) {\n\tok, err := r.Config.Filter.Select(metric)\n\tif err != nil {\n\t\tr.log.Errorf(\"filtering failed: %v\", err)\n\t} else if !ok {\n\t\tr.metricFiltered(metric)\n\t\treturn\n\t}\n\n\tr.add(metric)\n}\n\nfunc (r *RunningOutput) add(metric telegraf.Metric) {\n\tr.Config.Filter.Modify(metric)\n\tif len(metric.FieldList()) == 0 {\n\t\tr.metricFiltered(metric)\n\t\treturn\n\t}\n\n\tif output, ok := r.Output.(telegraf.AggregatingOutput); ok {\n\t\tr.aggMutex.Lock()\n\t\toutput.Add(metric)\n\t\tr.aggMutex.Unlock()\n\t\treturn\n\t}\n\n\tif len(r.Config.NameOverride) > 0 {\n\t\tmetric.SetName(r.Config.NameOverride)\n\t}\n\n\tif len(r.Config.NamePrefix) > 0 {\n\t\tmetric.AddPrefix(r.Config.NamePrefix)\n\t}\n\n\tif len(r.Config.NameSuffix) > 0 {\n\t\tmetric.AddSuffix(r.Config.NameSuffix)\n\t}\n\n\tr.droppedMetrics.Add(int64(r.buffer.Add(metric)))\n\n\tr.triggerBatchCheck()\n}\n\nfunc (r *RunningOutput) triggerBatchCheck() {\n\t// Make sure we trigger another batch-ready event in case we do have more\n\t// metrics than the batch-size in the buffer. We guard this trigger to not\n\t// be issued if a write is already ongoing to avoid event storms when adding\n\t// new metrics during write.\n\tif r.buffer.Len() >= r.MetricBatchSize && !r.lastWriteFailed.Load() {\n\t\t// Please note: We cannot merge this if into the one above because then\n\t\t// the compare-and-swap condition would always be evaluated and the\n\t\t// swap happens unconditionally from the buffer fullness.\n\t\tif r.writeInFlight.CompareAndSwap(false, true) {\n\t\t\tselect {\n\t\t\tcase r.BatchReady <- time.Now():\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Write writes all metrics to the output, stopping when all have been sent on\n// or error.\nfunc (r *RunningOutput) Write() error {\n\t// Try to connect if we are not yet started up\n\tif !r.started {\n\t\tr.retries++\n\t\tif err := r.Output.Connect(); err != nil {\n\t\t\tvar serr *internal.StartupError\n\t\t\tif !errors.As(err, &serr) || !serr.Retry || !serr.Partial {\n\t\t\t\tr.StartupErrors.Incr(1)\n\t\t\t\treturn internal.ErrNotConnected\n\t\t\t}\n\t\t\tr.log.Debugf(\"Partially connected after %d attempts\", r.retries)\n\t\t} else {\n\t\t\tr.started = true\n\t\t\tr.log.Debugf(\"Successfully connected after %d attempts\", r.retries)\n\t\t}\n\t}\n\n\t// Make sure we check for triggering another write based on buffer fullness\n\t// on exit. This is required to handle cases where a lot of metrics were\n\t// added during the time we are writing.\n\tdefer func() {\n\t\tr.writeInFlight.Store(false)\n\t\tr.triggerBatchCheck()\n\t}()\n\n\tif output, ok := r.Output.(telegraf.AggregatingOutput); ok {\n\t\tr.aggMutex.Lock()\n\t\tmetrics := output.Push()\n\t\tr.buffer.Add(metrics...)\n\t\toutput.Reset()\n\t\tr.aggMutex.Unlock()\n\t}\n\n\t// Only process the metrics in the buffer now. Metrics added while we are\n\t// writing will be sent on the next call. We can safely add one more write\n\t// because 'doTransaction' will abort early for empty batches.\n\tnBuffer := r.buffer.Len()\n\tnBatches := nBuffer/r.MetricBatchSize + 1\n\tfor i := 0; i < nBatches; i++ {\n\t\tif err := r.doTransaction(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// WriteBatch writes a single batch of metrics to the output.\nfunc (r *RunningOutput) WriteBatch() error {\n\t// Try to connect if we are not yet started up\n\tif !r.started {\n\t\tr.retries++\n\t\tif err := r.Output.Connect(); err != nil {\n\t\t\tr.StartupErrors.Incr(1)\n\t\t\treturn internal.ErrNotConnected\n\t\t}\n\t\tr.started = true\n\t\tr.log.Debugf(\"Successfully connected after %d attempts\", r.retries)\n\t}\n\n\t// Make sure we check for triggering another write based on buffer fullness\n\t// on exit. This is required to handle cases where a lot of metrics were\n\t// added during the time we are writing.\n\tdefer func() {\n\t\tr.writeInFlight.Store(false)\n\t\tr.triggerBatchCheck()\n\t}()\n\n\treturn r.doTransaction()\n}\n\nfunc (r *RunningOutput) doTransaction() error {\n\ttx := r.buffer.BeginTransaction(r.MetricBatchSize)\n\tif len(tx.Batch) == 0 {\n\t\treturn nil\n\t}\n\terr := r.writeMetrics(tx.Batch)\n\tr.updateTransaction(tx, err)\n\tr.buffer.EndTransaction(tx)\n\n\treturn err\n}\n\nfunc (r *RunningOutput) writeMetrics(metrics []telegraf.Metric) error {\n\tif dropped := r.droppedMetrics.Load(); dropped > 0 {\n\t\tr.log.Warnf(\"Metric buffer overflow; %d metrics have been dropped\", dropped)\n\t\tr.droppedMetrics.Add(-dropped)\n\t}\n\n\tstart := time.Now()\n\terr := r.Output.Write(metrics)\n\telapsed := time.Since(start)\n\tr.WriteTime.Incr(elapsed.Nanoseconds())\n\n\tif err == nil {\n\t\tr.log.Debugf(\"Wrote batch of %d metrics in %s\", len(metrics), elapsed)\n\t}\n\treturn err\n}\n\nfunc (r *RunningOutput) updateTransaction(tx *Transaction, err error) {\n\t// No error indicates all metrics were written successfully\n\tif err == nil {\n\t\tr.lastWriteFailed.Store(false)\n\t\ttx.AcceptAll()\n\t\treturn\n\t}\n\n\t// A non-partial-write-error indicated none of the metrics were written\n\t// successfully and we should keep them for the next write cycle\n\tvar writeErr *internal.PartialWriteError\n\tif !errors.As(err, &writeErr) {\n\t\tr.lastWriteFailed.Store(true)\n\t\ttx.KeepAll()\n\t\treturn\n\t}\n\n\t// Transfer the accepted and rejected indices based on the write error\n\t// values. Only allow to retrigger before the flush interval if at least\n\t// one metric was accepted in order to avoid\n\tr.lastWriteFailed.Store(len(writeErr.MetricsAccept) == 0)\n\ttx.Accept = writeErr.MetricsAccept\n\ttx.Reject = writeErr.MetricsReject\n}\n\nfunc (r *RunningOutput) LogBufferStatus() {\n\tnBuffer := r.buffer.Len()\n\tif r.Config.BufferStrategy == \"disk_write_through\" {\n\t\tr.log.Debugf(\"Buffer fullness: %d metrics\", nBuffer)\n\t} else {\n\t\tr.log.Debugf(\"Buffer fullness: %d / %d metrics\", nBuffer, r.MetricBufferLimit)\n\t}\n}\n\nfunc (r *RunningOutput) Log() telegraf.Logger {\n\treturn r.log\n}\n\nfunc (r *RunningOutput) BufferLength() int {\n\treturn r.buffer.Len()\n}\n"
  },
  {
    "path": "models/running_output_test.go",
    "content": "package models\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar first5 = []telegraf.Metric{\n\ttestutil.TestMetric(101, \"metric1\"),\n\ttestutil.TestMetric(101, \"metric2\"),\n\ttestutil.TestMetric(101, \"metric3\"),\n\ttestutil.TestMetric(101, \"metric4\"),\n\ttestutil.TestMetric(101, \"metric5\"),\n}\n\nvar next5 = []telegraf.Metric{\n\ttestutil.TestMetric(101, \"metric6\"),\n\ttestutil.TestMetric(101, \"metric7\"),\n\ttestutil.TestMetric(101, \"metric8\"),\n\ttestutil.TestMetric(101, \"metric9\"),\n\ttestutil.TestMetric(101, \"metric10\"),\n}\n\n// Test that NameDrop filters ger properly applied.\nfunc TestRunningOutputDropFilter(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tNameDrop: []string{\"metric1\", \"metric2\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 8)\n}\n\n// Test that NameDrop filters without a match do nothing.\nfunc TestRunningOutputPassFilter(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tNameDrop: []string{\"metric1000\", \"foo*\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 10)\n}\n\n// Test that tags are properly included\nfunc TestRunningOutputTagIncludeNoMatch(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"nothing*\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Empty(t, m.Metrics()[0].Tags())\n}\n\n// Test that tags are properly excluded\nfunc TestRunningOutputTagExcludeMatch(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tTagExclude: []string{\"tag*\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Empty(t, m.Metrics()[0].Tags())\n}\n\n// Test that tags are properly Excluded\nfunc TestRunningOutputTagExcludeNoMatch(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tTagExclude: []string{\"nothing*\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Len(t, m.Metrics()[0].Tags(), 1)\n}\n\n// Test that tags are properly included\nfunc TestRunningOutputTagIncludeMatch(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{\n\t\t\tTagInclude: []string{\"tag*\"},\n\t\t},\n\t}\n\trequire.NoError(t, conf.Filter.Compile())\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Len(t, m.Metrics()[0].Tags(), 1)\n}\n\n// Test that measurement name overriding correctly\nfunc TestRunningOutputNameOverride(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tNameOverride: \"new_metric_name\",\n\t}\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Equal(t, \"new_metric_name\", m.Metrics()[0].Name())\n}\n\n// Test that measurement name prefix is added correctly\nfunc TestRunningOutputNamePrefix(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tNamePrefix: \"prefix_\",\n\t}\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Equal(t, \"prefix_metric1\", m.Metrics()[0].Name())\n}\n\n// Test that measurement name suffix is added correctly\nfunc TestRunningOutputNameSuffix(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tNameSuffix: \"_suffix\",\n\t}\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 1)\n\trequire.Equal(t, \"metric1_suffix\", m.Metrics()[0].Name())\n}\n\n// Test that we can write metrics with simple default setup.\nfunc TestRunningOutputDefault(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tm := &mockOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\trequire.Empty(t, m.Metrics())\n\n\terr := ro.Write()\n\trequire.NoError(t, err)\n\trequire.Len(t, m.Metrics(), 10)\n}\n\nfunc TestRunningOutputWriteFail(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tm := &mockOutput{batchAcceptSize: -1}\n\tro := NewRunningOutput(m, conf, 4, 12)\n\n\t// Fill buffer to limit twice\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// manual write fails\n\terr := ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\tm.batchAcceptSize = 0\n\terr = ro.Write()\n\trequire.NoError(t, err)\n\n\trequire.Len(t, m.Metrics(), 10)\n}\n\n// Verify that the order of points is preserved during write failure.\nfunc TestRunningOutputWriteFailOrder(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tm := &mockOutput{batchAcceptSize: -1}\n\tro := NewRunningOutput(m, conf, 100, 1000)\n\n\t// add 5 metrics\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// Write fails\n\terr := ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\tm.batchAcceptSize = 0\n\n\t// add 5 more metrics\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\terr = ro.Write()\n\trequire.NoError(t, err)\n\n\t// Verify that 10 metrics were written\n\trequire.Len(t, m.Metrics(), 10)\n\t// Verify that they are in order\n\texpected := append(first5, next5...)\n\trequire.Equal(t, expected, m.Metrics())\n}\n\n// Verify that the order of points is preserved during many write failures.\nfunc TestRunningOutputWriteFailOrder2(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tm := &mockOutput{batchAcceptSize: -1}\n\tro := NewRunningOutput(m, conf, 5, 100)\n\n\t// add 5 metrics\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// Write fails\n\terr := ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// add 5 metrics\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// Write fails\n\terr = ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// add 5 metrics\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// Write fails\n\terr = ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// add 5 metrics\n\tfor _, mt := range next5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// Write fails\n\terr = ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\tm.batchAcceptSize = 0\n\terr = ro.Write()\n\trequire.NoError(t, err)\n\n\t// Verify that 20 metrics were written\n\trequire.Len(t, m.Metrics(), 20)\n\t// Verify that they are in order\n\texpected := append(first5, next5...)\n\texpected = append(expected, first5...)\n\texpected = append(expected, next5...)\n\trequire.Equal(t, expected, m.Metrics())\n}\n\n// Verify that the order of points is preserved when there is a remainder\n// of points for the batch.\nfunc TestRunningOutputWriteFailOrder3(t *testing.T) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tm := &mockOutput{batchAcceptSize: -1}\n\tro := NewRunningOutput(m, conf, 5, 1000)\n\n\t// add 5 metrics\n\tfor _, mt := range first5 {\n\t\tro.AddMetric(mt)\n\t}\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// Write fails\n\terr := ro.Write()\n\trequire.Error(t, err)\n\t// no successful flush yet\n\trequire.Empty(t, m.Metrics())\n\n\t// add and attempt to write a single metric:\n\tro.AddMetric(next5[0])\n\terr = ro.Write()\n\trequire.Error(t, err)\n\n\t// unset fail and write metrics\n\tm.batchAcceptSize = 0\n\n\terr = ro.Write()\n\trequire.NoError(t, err)\n\n\t// Verify that 6 metrics were written\n\trequire.Len(t, m.Metrics(), 6)\n\t// Verify that they are in order\n\texpected := []telegraf.Metric{first5[0], first5[1], first5[2], first5[3], first5[4], next5[0]}\n\trequire.Equal(t, expected, m.Metrics())\n}\n\nfunc TestRunningOutputBufferFullyDrained(t *testing.T) {\n\t// Setup output with a post-write hook to be able to block write until\n\t// we added more metrics\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\tvar shouldBlock atomic.Bool\n\tshouldBlock.Store(true)\n\taddMore := make(chan bool)\n\tdefer func() { close(addMore) }()\n\twaitForAddedMetrics := make(chan bool)\n\tdefer func() { close(waitForAddedMetrics) }()\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 0,\n\t\tpostWriteHook: func([]telegraf.Metric) error {\n\t\t\t// Wait for the first full write and block until the test code\n\t\t\t// added the new metrics\n\t\t\tif shouldBlock.CompareAndSwap(true, false) {\n\t\t\t\taddMore <- true\n\t\t\t\t<-waitForAddedMetrics\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\tconst batchSize = 5\n\tro := NewRunningOutput(plugin, conf, batchSize, 100)\n\n\t// Create a multiple of batch size many metrics beyond the batch size\n\tconst totalMetrics = 10 * batchSize\n\tinputs := make([]telegraf.Metric, 0, totalMetrics)\n\tfor i := range totalMetrics {\n\t\tinputs = append(inputs, testutil.TestMetric(i, \"test\"))\n\t}\n\n\t// Setup a event based writing loop similar to what the agent code does.\n\t// Remember the first write will block to allow us adding more metrics.\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\tvar wg sync.WaitGroup\n\tvar modelWriteErr error\n\twg.Add(1)\n\tgo func(cctx context.Context) {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-cctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ro.BatchReady:\n\t\t\t\tif modelWriteErr = ro.Write(); modelWriteErr != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ctx)\n\n\t// Add a few metrics, i.e. more than batch size\n\tfor _, m := range inputs[:20] {\n\t\tro.AddMetric(m)\n\t}\n\n\t// Wait for entering the actual output write and add the remaining metrics.\n\t// Afterwards unblock the writer.\n\t<-addMore\n\tfor _, m := range inputs[20:] {\n\t\tro.AddMetric(m)\n\t}\n\twaitForAddedMetrics <- true\n\n\t// Wait for writing to finish and stop the write loop\n\trequire.Eventually(t, func() bool {\n\t\treturn len(plugin.Metrics()) >= len(inputs)\n\t}, 3*time.Second, 100*time.Millisecond)\n\tcancel()\n\twg.Wait()\n\n\t// Check for writing errors and make sure all metrics were written,\n\t// including the ones added while writing took place\n\trequire.NoError(t, modelWriteErr)\n\trequire.Equal(t, 10, int(plugin.writes.Load()))\n\trequire.Len(t, plugin.Metrics(), totalMetrics)\n}\n\nfunc TestRunningOutputBufferImmediateRestartOnContinuousWrite(t *testing.T) {\n\t// Setup output with a post-write hook to be able to block write until\n\t// we added more metrics\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tconst batchSize = 5\n\tvar shouldBlock atomic.Bool\n\tshouldBlock.Store(true)\n\taddMore := make(chan bool)\n\tdefer func() { close(addMore) }()\n\twaitForAddedMetrics := make(chan bool)\n\tdefer func() { close(waitForAddedMetrics) }()\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 0,\n\t\tpreWriteHook: func(ms []telegraf.Metric) error {\n\t\t\t// Wait for the first non-full write and block until the test code\n\t\t\t// added the new metrics\n\t\t\tif len(ms) < batchSize && shouldBlock.CompareAndSwap(true, false) {\n\t\t\t\taddMore <- true\n\t\t\t\t<-waitForAddedMetrics\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\tro := NewRunningOutput(plugin, conf, batchSize, 100)\n\n\t// Create a multiple of batch size many metrics beyond the batch size\n\tconst totalMetrics = 10 * batchSize\n\tinputs := make([]telegraf.Metric, 0, totalMetrics)\n\tfor i := range totalMetrics {\n\t\tinputs = append(inputs, testutil.TestMetric(i, \"test\"))\n\t}\n\n\t// Add a few metrics but not a multiple of the batch size\n\tfor _, m := range inputs[:19] {\n\t\tro.AddMetric(m)\n\t}\n\n\t// Start writing and add new metrics as soon as the last non-full batch is\n\t// written. At this time add the remaining metrics to check if we are\n\t// immediately getting a new write signal.\n\tvar modelWriteErr error\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tmodelWriteErr = ro.Write()\n\t}()\n\n\t// Wait for the writer to see the non-full batch, add the remaining metrics\n\t// and unblock the writer\n\t<-addMore\n\tfor _, m := range inputs[19:] {\n\t\tro.AddMetric(m)\n\t}\n\twaitForAddedMetrics <- true\n\n\t// Wait for writing to finish\n\twg.Wait()\n\trequire.NoError(t, modelWriteErr)\n\n\t// Check for the new-batch-available trigger\n\trequire.Eventually(t, func() bool {\n\t\tselect {\n\t\tcase <-ro.BatchReady:\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Trigger the requested write and make sure all metrics were written,\n\t// including the ones added while writing took place\n\trequire.NoError(t, ro.Write())\n\trequire.Len(t, plugin.Metrics(), totalMetrics)\n}\n\nfunc TestRunningOutputNoRetriggerOnError(t *testing.T) {\n\t// Setup output with a post-write hook to be able to block write until\n\t// we added more metrics\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 0,\n\t\tpreWriteHook: func([]telegraf.Metric) error {\n\t\t\t// In this test we are handling a failing output\n\t\t\treturn errors.New(\"writing failed\")\n\t\t},\n\t}\n\tconst batchSize = 5\n\tro := NewRunningOutput(plugin, conf, batchSize, 100)\n\n\t// Create a multiple of batch size many metrics beyond the batch size\n\tconst totalMetrics = 10 * batchSize\n\tinputs := make([]telegraf.Metric, 0, totalMetrics)\n\tfor i := range totalMetrics {\n\t\tinputs = append(inputs, testutil.TestMetric(i, \"test\"))\n\t}\n\n\t// Add the metrics\n\tfor _, m := range inputs {\n\t\tro.AddMetric(m)\n\t}\n\n\t// Setup a event based writing loop similar to what the agent code does.\n\t// Remember the first write will block to allow us adding more metrics.\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second)\n\tdefer cancel()\n\n\tvar errCount atomic.Uint32\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func(cctx context.Context) {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-cctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ro.BatchReady:\n\t\t\t\tif err := ro.Write(); err != nil {\n\t\t\t\t\terrCount.Add(1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ctx)\n\n\t// Wait for the trigger loop to exit. This should happen latest after the\n\t// defined timeout.\n\twg.Wait()\n\n\t// Check for writing errors and make sure all metrics were written,\n\t// including the ones added while writing took place\n\trequire.Equal(t, errCount.Load(), plugin.writes.Load())\n\trequire.Equal(t, 1, int(plugin.writes.Load()))\n\trequire.Equal(t, totalMetrics, ro.buffer.Len())\n}\n\nfunc TestRunningOutputNoRetriggerOnSuccessfulPartialWriteError(t *testing.T) {\n\t// Setup output with a post-write hook to be able to block write until\n\t// we added more metrics\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 0,\n\t\tpreWriteHook: func(m []telegraf.Metric) error {\n\t\t\t// In this test we are handling a failing output\n\t\t\tdrop := make([]int, 0, len(m)-1)\n\t\t\tfor i := range len(m) - 1 {\n\t\t\t\tdrop = append(drop, i+1)\n\t\t\t}\n\t\t\treturn &internal.PartialWriteError{\n\t\t\t\tErr:           errors.New(\"writing failed\"),\n\t\t\t\tMetricsAccept: []int{0},\n\t\t\t\tMetricsReject: drop,\n\t\t\t}\n\t\t},\n\t}\n\tconst batchSize = 5\n\tro := NewRunningOutput(plugin, conf, batchSize, 100)\n\n\t// Create a multiple of batch size many metrics beyond the batch size\n\tconst batchCount = 10\n\tconst totalMetrics = batchCount * batchSize\n\tinputs := make([]telegraf.Metric, 0, totalMetrics)\n\tfor i := range totalMetrics {\n\t\tinputs = append(inputs, testutil.TestMetric(i, \"test\"))\n\t}\n\n\t// Add the metrics\n\tfor _, m := range inputs {\n\t\tro.AddMetric(m)\n\t}\n\n\t// Setup a event based writing loop similar to what the agent code does.\n\t// Remember the first write will block to allow us adding more metrics.\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\tvar triggerCount atomic.Uint32\n\tvar errCount atomic.Uint32\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func(cctx context.Context) {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-cctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ro.BatchReady:\n\t\t\t\ttriggerCount.Add(1)\n\t\t\t\tif err := ro.Write(); err != nil {\n\t\t\t\t\terrCount.Add(1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ctx)\n\n\t// Wait for the trigger loop to exit. This should happen latest after the\n\t// defined timeout.\n\trequire.Eventually(t, func() bool { return ro.buffer.Len() == 0 }, 3*time.Second, 100*time.Millisecond)\n\tcancel()\n\twg.Wait()\n\n\t// Check for writing errors and make sure all metrics were written,\n\t// including the ones added while writing took place\n\trequire.Equal(t, errCount.Load(), plugin.writes.Load())\n\trequire.Equal(t, triggerCount.Load(), plugin.writes.Load())\n\trequire.Equal(t, batchCount, int(plugin.writes.Load()))\n}\n\nfunc TestRunningOutputNoRetriggerOnUnsuccessfulPartialWriteError(t *testing.T) {\n\t// Setup output with a post-write hook to be able to block write until\n\t// we added more metrics\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 0,\n\t\tpreWriteHook: func([]telegraf.Metric) error {\n\t\t\treturn &internal.PartialWriteError{\n\t\t\t\tErr: errors.New(\"unable to connect\"),\n\t\t\t}\n\t\t},\n\t}\n\tconst batchSize = 5\n\tro := NewRunningOutput(plugin, conf, batchSize, 100)\n\n\t// Create a multiple of batch size many metrics beyond the batch size\n\tconst batchCount = 10\n\tconst totalMetrics = batchCount * batchSize\n\tinputs := make([]telegraf.Metric, 0, totalMetrics)\n\tfor i := range totalMetrics {\n\t\tinputs = append(inputs, testutil.TestMetric(i, \"test\"))\n\t}\n\n\t// Add the metrics\n\tfor _, m := range inputs {\n\t\tro.AddMetric(m)\n\t}\n\n\t// Setup a event based writing loop similar to what the agent code does.\n\t// Remember the first write will block to allow us adding more metrics.\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second)\n\tdefer cancel()\n\n\tvar triggerCount atomic.Uint32\n\tvar errCount atomic.Uint32\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func(cctx context.Context) {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-cctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ro.BatchReady:\n\t\t\t\ttriggerCount.Add(1)\n\t\t\t\tif err := ro.Write(); err != nil {\n\t\t\t\t\terrCount.Add(1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ctx)\n\n\t// Wait for the trigger loop to exit. This should happen latest after the\n\t// defined timeout.\n\twg.Wait()\n\tcancel()\n\n\t// Check for writing errors and make sure all metrics were written,\n\t// including the ones added while writing took place\n\trequire.Equal(t, 1, int(triggerCount.Load()))\n}\n\nfunc TestRunningOutputInternalMetrics(t *testing.T) {\n\t_ = NewRunningOutput(\n\t\t&mockOutput{},\n\t\t&OutputConfig{\n\t\t\tFilter: Filter{},\n\t\t\tName:   \"test_name\",\n\t\t\tAlias:  \"test_alias\",\n\t\t},\n\t\t5,\n\t\t10)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"internal_write\",\n\t\t\tmap[string]string{\n\t\t\t\t\"_id\":    \"\",\n\t\t\t\t\"output\": \"test_name\",\n\t\t\t\t\"alias\":  \"test_alias\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"buffer_limit\":     10,\n\t\t\t\t\"buffer_size\":      0,\n\t\t\t\t\"errors\":           0,\n\t\t\t\t\"metrics_added\":    0,\n\t\t\t\t\"metrics_rejected\": 0,\n\t\t\t\t\"metrics_dropped\":  0,\n\t\t\t\t\"metrics_filtered\": 0,\n\t\t\t\t\"metrics_written\":  0,\n\t\t\t\t\"write_time_ns\":    0,\n\t\t\t\t\"startup_errors\":   0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar actual []telegraf.Metric\n\tfor _, m := range selfstat.Metrics() {\n\t\toutput, _ := m.GetTag(\"output\")\n\t\tif m.Name() == \"internal_write\" && output == \"test_name\" {\n\t\t\tactual = append(actual, m)\n\t\t}\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestRunningOutputStartupBehaviorInvalid(t *testing.T) {\n\tro := NewRunningOutput(\n\t\t&mockOutput{},\n\t\t&OutputConfig{\n\t\t\tFilter:               Filter{},\n\t\t\tName:                 \"test_name\",\n\t\t\tAlias:                \"test_alias\",\n\t\t\tStartupErrorBehavior: \"foo\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.ErrorContains(t, ro.Init(), \"invalid 'startup_error_behavior'\")\n}\n\nfunc TestRunningOutputRetryableStartupBehaviorDefault(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:   errors.New(\"retryable err\"),\n\t\tRetry: true,\n\t}\n\tro := NewRunningOutput(\n\t\t&mockOutput{\n\t\t\tstartupErrorCount: 1,\n\t\t\tstartupError:      serr,\n\t\t},\n\t\t&OutputConfig{\n\t\t\tFilter: Filter{},\n\t\t\tName:   \"test_name\",\n\t\t\tAlias:  \"test_alias\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.NoError(t, ro.Init())\n\n\t// If Connect() fails, the agent will stop\n\trequire.ErrorIs(t, ro.Connect(), serr)\n\trequire.False(t, ro.started)\n}\n\nfunc TestRunningOutputRetryableStartupBehaviorError(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:   errors.New(\"retryable err\"),\n\t\tRetry: true,\n\t}\n\tro := NewRunningOutput(\n\t\t&mockOutput{\n\t\t\tstartupErrorCount: 1,\n\t\t\tstartupError:      serr,\n\t\t},\n\t\t&OutputConfig{\n\t\t\tFilter:               Filter{},\n\t\t\tName:                 \"test_name\",\n\t\t\tAlias:                \"test_alias\",\n\t\t\tStartupErrorBehavior: \"error\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.NoError(t, ro.Init())\n\n\t// If Connect() fails, the agent will stop\n\trequire.ErrorIs(t, ro.Connect(), serr)\n\trequire.False(t, ro.started)\n}\n\nfunc TestRunningOutputRetryableStartupBehaviorRetry(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:   errors.New(\"retryable err\"),\n\t\tRetry: true,\n\t}\n\tmo := &mockOutput{\n\t\tstartupErrorCount: 2,\n\t\tstartupError:      serr,\n\t}\n\tro := NewRunningOutput(\n\t\tmo,\n\t\t&OutputConfig{\n\t\t\tFilter:               Filter{},\n\t\t\tName:                 \"test_name\",\n\t\t\tAlias:                \"test_alias\",\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.NoError(t, ro.Init())\n\n\t// For retry, Connect() should succeed even though there is an error but\n\t// should return an error on Write() until we successfully connect.\n\trequire.NotErrorIs(t, ro.Connect(), serr)\n\trequire.False(t, ro.started)\n\n\tro.AddMetric(testutil.TestMetric(1))\n\trequire.ErrorIs(t, ro.Write(), internal.ErrNotConnected)\n\trequire.False(t, ro.started)\n\n\tro.AddMetric(testutil.TestMetric(2))\n\trequire.NoError(t, ro.Write())\n\trequire.True(t, ro.started)\n\trequire.Equal(t, 1, int(mo.writes.Load()))\n\n\tro.AddMetric(testutil.TestMetric(3))\n\trequire.NoError(t, ro.Write())\n\trequire.True(t, ro.started)\n\trequire.Equal(t, 2, int(mo.writes.Load()))\n}\n\nfunc TestRunningOutputRetryableStartupBehaviorIgnore(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:   errors.New(\"retryable err\"),\n\t\tRetry: true,\n\t}\n\tmo := &mockOutput{\n\t\tstartupErrorCount: 2,\n\t\tstartupError:      serr,\n\t}\n\tro := NewRunningOutput(\n\t\tmo,\n\t\t&OutputConfig{\n\t\t\tFilter:               Filter{},\n\t\t\tName:                 \"test_name\",\n\t\t\tAlias:                \"test_alias\",\n\t\t\tStartupErrorBehavior: \"ignore\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.NoError(t, ro.Init())\n\n\t// For ignore, Connect() should return a fatal error if connection fails.\n\t// This will force the agent to remove the plugin.\n\tvar fatalErr *internal.FatalError\n\trequire.ErrorAs(t, ro.Connect(), &fatalErr)\n\trequire.ErrorIs(t, fatalErr, serr)\n\trequire.False(t, ro.started)\n}\n\nfunc TestRunningOutputNonRetryableStartupBehaviorDefault(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:   errors.New(\"non-retryable err\"),\n\t\tRetry: false,\n\t}\n\n\tfor _, behavior := range []string{\"\", \"error\", \"retry\", \"ignore\"} {\n\t\tt.Run(behavior, func(t *testing.T) {\n\t\t\tmo := &mockOutput{\n\t\t\t\tstartupErrorCount: 2,\n\t\t\t\tstartupError:      serr,\n\t\t\t}\n\t\t\tro := NewRunningOutput(\n\t\t\t\tmo,\n\t\t\t\t&OutputConfig{\n\t\t\t\t\tFilter:               Filter{},\n\t\t\t\t\tName:                 \"test_name\",\n\t\t\t\t\tAlias:                \"test_alias\",\n\t\t\t\t\tStartupErrorBehavior: behavior,\n\t\t\t\t},\n\t\t\t\t5, 10,\n\t\t\t)\n\t\t\trequire.NoError(t, ro.Init())\n\n\t\t\t// Non-retryable error should pass through and in turn the agent\n\t\t\t// will stop and exit.\n\t\t\trequire.ErrorIs(t, ro.Connect(), serr)\n\t\t\trequire.False(t, ro.started)\n\t\t})\n\t}\n}\n\nfunc TestRunningOutputUntypedStartupBehaviorIgnore(t *testing.T) {\n\tserr := errors.New(\"untyped err\")\n\n\tfor _, behavior := range []string{\"\", \"error\", \"retry\", \"ignore\"} {\n\t\tt.Run(behavior, func(t *testing.T) {\n\t\t\tmo := &mockOutput{\n\t\t\t\tstartupErrorCount: 2,\n\t\t\t\tstartupError:      serr,\n\t\t\t}\n\t\t\tro := NewRunningOutput(\n\t\t\t\tmo,\n\t\t\t\t&OutputConfig{\n\t\t\t\t\tFilter:               Filter{},\n\t\t\t\t\tName:                 \"test_name\",\n\t\t\t\t\tAlias:                \"test_alias\",\n\t\t\t\t\tStartupErrorBehavior: behavior,\n\t\t\t\t},\n\t\t\t\t5, 10,\n\t\t\t)\n\t\t\trequire.NoError(t, ro.Init())\n\n\t\t\t// Untyped error should pass through and in turn the agent will\n\t\t\t// stop and exit.\n\t\t\trequire.ErrorIs(t, ro.Connect(), serr)\n\t\t\trequire.False(t, ro.started)\n\t\t})\n\t}\n}\n\nfunc TestRunningOutputPartiallyStarted(t *testing.T) {\n\tserr := &internal.StartupError{\n\t\tErr:     errors.New(\"partial err\"),\n\t\tRetry:   true,\n\t\tPartial: true,\n\t}\n\tmo := &mockOutput{\n\t\tstartupErrorCount: 2,\n\t\tstartupError:      serr,\n\t}\n\tro := NewRunningOutput(\n\t\tmo,\n\t\t&OutputConfig{\n\t\t\tFilter:               Filter{},\n\t\t\tName:                 \"test_name\",\n\t\t\tAlias:                \"test_alias\",\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t\t5, 10,\n\t)\n\trequire.NoError(t, ro.Init())\n\n\t// For retry, Connect() should succeed even though there is an error but\n\t// should return an error on Write() until we successfully connect.\n\trequire.NotErrorIs(t, ro.Connect(), serr)\n\trequire.False(t, ro.started)\n\n\tro.AddMetric(testutil.TestMetric(1))\n\trequire.NoError(t, ro.Write())\n\trequire.False(t, ro.started)\n\trequire.Equal(t, 1, int(mo.writes.Load()))\n\n\tro.AddMetric(testutil.TestMetric(2))\n\trequire.NoError(t, ro.Write())\n\trequire.True(t, ro.started)\n\trequire.Equal(t, 2, int(mo.writes.Load()))\n\n\tro.AddMetric(testutil.TestMetric(3))\n\trequire.NoError(t, ro.Write())\n\trequire.True(t, ro.started)\n\trequire.Equal(t, 3, int(mo.writes.Load()))\n}\n\nfunc TestRunningOutputWritePartialSuccess(t *testing.T) {\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 4,\n\t}\n\tmodel := NewRunningOutput(plugin, &OutputConfig{}, 5, 10)\n\trequire.NoError(t, model.Init())\n\trequire.NoError(t, model.Connect())\n\tdefer model.Close()\n\n\t// Fill buffer completely\n\tfor _, mt := range first5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\n\t// We no not expect any successful flush yet\n\trequire.Empty(t, plugin.Metrics())\n\trequire.Equal(t, 10, model.buffer.Len())\n\n\t// Write to the output. This should only partially succeed with the first\n\t// few metrics removed from buffer\n\trequire.ErrorIs(t, model.Write(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 4)\n\trequire.Equal(t, 6, model.buffer.Len())\n\n\t// The next write should remove the next metrics from the buffer\n\trequire.ErrorIs(t, model.Write(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 8)\n\trequire.Equal(t, 2, model.buffer.Len())\n\n\t// The last write should succeed straight away and all metrics should have\n\t// been received by the output\n\trequire.NoError(t, model.Write())\n\ttestutil.RequireMetricsEqual(t, append(first5, next5...), plugin.metrics)\n\trequire.Zero(t, model.buffer.Len())\n}\n\nfunc TestRunningOutputWritePartialSuccessAndLoss(t *testing.T) {\n\tlost := 0\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize:  4,\n\t\tmetricFatalIndex: &lost,\n\t}\n\tmodel := NewRunningOutput(plugin, &OutputConfig{}, 5, 10)\n\trequire.NoError(t, model.Init())\n\trequire.NoError(t, model.Connect())\n\tdefer model.Close()\n\n\t// Fill buffer completely\n\tfor _, mt := range first5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\texpected := []telegraf.Metric{\n\t\t/* fatal, */ first5[1], first5[2], first5[3],\n\t\t/* fatal, */ next5[0], next5[1], next5[2],\n\t\tnext5[3], next5[4],\n\t}\n\n\t// We no not expect any successful flush yet\n\trequire.Empty(t, plugin.Metrics())\n\trequire.Equal(t, 10, model.buffer.Len())\n\n\t// Write to the output. This should only partially succeed with the first\n\t// few metrics removed from buffer\n\trequire.ErrorIs(t, model.Write(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 3)\n\trequire.Equal(t, 6, model.buffer.Len())\n\n\t// The next write should remove the next metrics from the buffer\n\trequire.ErrorIs(t, model.Write(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 6)\n\trequire.Equal(t, 2, model.buffer.Len())\n\n\t// The last write should succeed straight away and all metrics should have\n\t// been received by the output\n\trequire.NoError(t, model.Write())\n\ttestutil.RequireMetricsEqual(t, expected, plugin.metrics)\n\trequire.Zero(t, model.buffer.Len())\n}\n\nfunc TestRunningOutputWriteBatchPartialSuccess(t *testing.T) {\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize: 4,\n\t}\n\tmodel := NewRunningOutput(plugin, &OutputConfig{}, 5, 10)\n\trequire.NoError(t, model.Init())\n\trequire.NoError(t, model.Connect())\n\tdefer model.Close()\n\n\t// Fill buffer completely\n\tfor _, mt := range first5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\n\t// We no not expect any successful flush yet\n\trequire.Empty(t, plugin.Metrics())\n\trequire.Equal(t, 10, model.buffer.Len())\n\n\t// Write to the output. This should only partially succeed with the first\n\t// few metrics removed from buffer\n\trequire.ErrorIs(t, model.WriteBatch(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 4)\n\trequire.Equal(t, 6, model.buffer.Len())\n\n\t// The next write should remove the next metrics from the buffer\n\trequire.ErrorIs(t, model.WriteBatch(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 8)\n\trequire.Equal(t, 2, model.buffer.Len())\n\n\t// The last write should succeed straight away and all metrics should have\n\t// been received by the output\n\trequire.NoError(t, model.WriteBatch())\n\ttestutil.RequireMetricsEqual(t, append(first5, next5...), plugin.metrics)\n\trequire.Zero(t, model.buffer.Len())\n}\n\nfunc TestRunningOutputWriteBatchPartialSuccessAndLoss(t *testing.T) {\n\tlost := 0\n\tplugin := &mockOutput{\n\t\tbatchAcceptSize:  4,\n\t\tmetricFatalIndex: &lost,\n\t}\n\tmodel := NewRunningOutput(plugin, &OutputConfig{}, 5, 10)\n\trequire.NoError(t, model.Init())\n\trequire.NoError(t, model.Connect())\n\tdefer model.Close()\n\n\t// Fill buffer completely\n\tfor _, mt := range first5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\tfor _, mt := range next5 {\n\t\tmodel.AddMetric(mt)\n\t}\n\texpected := []telegraf.Metric{\n\t\t/* fatal, */ first5[1], first5[2], first5[3],\n\t\t/* fatal, */ next5[0], next5[1], next5[2],\n\t\tnext5[3], next5[4],\n\t}\n\n\t// We no not expect any successful flush yet\n\trequire.Empty(t, plugin.Metrics())\n\trequire.Equal(t, 10, model.buffer.Len())\n\n\t// Write to the output. This should only partially succeed with the first\n\t// few metrics removed from buffer\n\trequire.ErrorIs(t, model.WriteBatch(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 3)\n\trequire.Equal(t, 6, model.buffer.Len())\n\n\t// The next write should remove the next metrics from the buffer\n\trequire.ErrorIs(t, model.WriteBatch(), internal.ErrSizeLimitReached)\n\trequire.Len(t, plugin.metrics, 6)\n\trequire.Equal(t, 2, model.buffer.Len())\n\n\t// The last write should succeed straight away and all metrics should have\n\t// been received by the output\n\trequire.NoError(t, model.WriteBatch())\n\ttestutil.RequireMetricsEqual(t, expected, plugin.metrics)\n\trequire.Zero(t, model.buffer.Len())\n}\n\n// Benchmark adding metrics.\nfunc BenchmarkRunningOutputAddWrite(b *testing.B) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\tm := &perfOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\t\tro.Write() //nolint:errcheck // skip checking err for benchmark tests\n\t}\n}\n\n// Benchmark adding metrics.\nfunc BenchmarkRunningOutputAddWriteEvery100(b *testing.B) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\tm := &perfOutput{}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\t\tif n%100 == 0 {\n\t\t\tro.Write() //nolint:errcheck // skip checking err for benchmark tests\n\t\t}\n\t}\n}\n\n// Benchmark adding metrics.\nfunc BenchmarkRunningOutputAddFailWrites(b *testing.B) {\n\tconf := &OutputConfig{\n\t\tFilter: Filter{},\n\t}\n\tm := &perfOutput{failWrite: true}\n\tro := NewRunningOutput(m, conf, 1000, 10000)\n\tfor n := 0; n < b.N; n++ {\n\t\tro.AddMetric(testutil.TestMetric(101, \"metric1\"))\n\t}\n}\n\ntype mockOutput struct {\n\tsync.Mutex\n\n\tmetrics []telegraf.Metric\n\n\t// Failing output simulation\n\tbatchAcceptSize  int\n\tmetricFatalIndex *int\n\n\t// Startup error simulation\n\tstartupError      error\n\tstartupErrorCount int\n\twrites            atomic.Uint32\n\n\t// Utility for getting notified about writes and also to manipulate\n\t// the write behavior\n\tpreWriteHook  func([]telegraf.Metric) error\n\tpostWriteHook func([]telegraf.Metric) error\n}\n\nfunc (m *mockOutput) Connect() error {\n\tif m.startupErrorCount == 0 {\n\t\treturn nil\n\t}\n\tif m.startupErrorCount > 0 {\n\t\tm.startupErrorCount--\n\t}\n\treturn m.startupError\n}\n\nfunc (*mockOutput) Close() error {\n\treturn nil\n}\n\nfunc (*mockOutput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (m *mockOutput) Write(metrics []telegraf.Metric) error {\n\tm.writes.Add(1)\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Execute hook if any\n\tif m.preWriteHook != nil {\n\t\tif err := m.preWriteHook(metrics); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Simulate a failed write\n\tif m.batchAcceptSize < 0 {\n\t\treturn errors.New(\"failed write\")\n\t}\n\n\t// Simulate a successful write\n\tvar resultErr error\n\tif m.batchAcceptSize == 0 || len(metrics) <= m.batchAcceptSize {\n\t\tm.metrics = append(m.metrics, metrics...)\n\t} else {\n\t\t// Simulate a partially successful write\n\t\twerr := &internal.PartialWriteError{Err: internal.ErrSizeLimitReached}\n\t\tfor i, x := range metrics {\n\t\t\tif m.metricFatalIndex != nil && i == *m.metricFatalIndex {\n\t\t\t\twerr.MetricsReject = append(werr.MetricsReject, i)\n\t\t\t} else if i < m.batchAcceptSize {\n\t\t\t\tm.metrics = append(m.metrics, x)\n\t\t\t\twerr.MetricsAccept = append(werr.MetricsAccept, i)\n\t\t\t}\n\t\t}\n\t\tresultErr = werr\n\t}\n\n\t// Execute hook if any\n\tif m.postWriteHook != nil {\n\t\tif err := m.postWriteHook(metrics); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn resultErr\n}\n\nfunc (m *mockOutput) Metrics() []telegraf.Metric {\n\tm.Lock()\n\tdefer m.Unlock()\n\treturn m.metrics\n}\n\ntype perfOutput struct {\n\t// if true, mock write failure\n\tfailWrite bool\n}\n\nfunc (*perfOutput) Connect() error {\n\treturn nil\n}\n\nfunc (*perfOutput) Close() error {\n\treturn nil\n}\n\nfunc (*perfOutput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (m *perfOutput) Write([]telegraf.Metric) error {\n\tif m.failWrite {\n\t\treturn errors.New(\"failed write\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "models/running_parsers.go",
    "content": "package models\n\nimport (\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\ntype RunningParser struct {\n\tParser telegraf.Parser\n\tConfig *ParserConfig\n\tlog    telegraf.Logger\n\n\tMetricsParsed selfstat.Stat\n\tParseTime     selfstat.Stat\n}\n\nfunc NewRunningParser(parser telegraf.Parser, config *ParserConfig) *RunningParser {\n\ttags := map[string]string{\"type\": config.DataFormat}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\tparserErrorsRegister := selfstat.Register(\"parser\", \"errors\", tags)\n\tlogger := logging.New(\"parsers\", config.DataFormat+\"::\"+config.Parent, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\tparserErrorsRegister.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(parser, logger)\n\tSetStatisticsOnPlugin(parser, logger, tags)\n\n\treturn &RunningParser{\n\t\tParser: parser,\n\t\tConfig: config,\n\t\tMetricsParsed: selfstat.Register(\n\t\t\t\"parser\",\n\t\t\t\"metrics_parsed\",\n\t\t\ttags,\n\t\t),\n\t\tParseTime: selfstat.Register(\n\t\t\t\"parser\",\n\t\t\t\"parse_time_ns\",\n\t\t\ttags,\n\t\t),\n\t\tlog: logger,\n\t}\n}\n\n// ParserConfig is the common config for all parsers.\ntype ParserConfig struct {\n\tParent      string\n\tAlias       string\n\tDataFormat  string\n\tDefaultTags map[string]string\n\tLogLevel    string\n}\n\nfunc (r *RunningParser) LogName() string {\n\treturn logName(\"parsers\", r.Config.DataFormat+\"::\"+r.Config.Parent, r.Config.Alias)\n}\n\nfunc (r *RunningParser) Init() error {\n\tif p, ok := r.Parser.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *RunningParser) Parse(buf []byte) ([]telegraf.Metric, error) {\n\tstart := time.Now()\n\tm, err := r.Parser.Parse(buf)\n\telapsed := time.Since(start)\n\tr.ParseTime.Incr(elapsed.Nanoseconds())\n\tr.MetricsParsed.Incr(int64(len(m)))\n\n\treturn m, err\n}\n\nfunc (r *RunningParser) ParseLine(line string) (telegraf.Metric, error) {\n\tstart := time.Now()\n\tm, err := r.Parser.ParseLine(line)\n\telapsed := time.Since(start)\n\tr.ParseTime.Incr(elapsed.Nanoseconds())\n\tr.MetricsParsed.Incr(1)\n\n\treturn m, err\n}\n\nfunc (r *RunningParser) SetDefaultTags(tags map[string]string) {\n\tr.Parser.SetDefaultTags(tags)\n}\n\nfunc (r *RunningParser) Log() telegraf.Logger {\n\treturn r.log\n}\n"
  },
  {
    "path": "models/running_processor.go",
    "content": "package models\n\nimport (\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\ntype RunningProcessor struct {\n\tsync.Mutex\n\tlog       telegraf.Logger\n\tProcessor telegraf.StreamingProcessor\n\tConfig    *ProcessorConfig\n}\n\ntype RunningProcessors []*RunningProcessor\n\nfunc (rp RunningProcessors) Len() int           { return len(rp) }\nfunc (rp RunningProcessors) Swap(i, j int)      { rp[i], rp[j] = rp[j], rp[i] }\nfunc (rp RunningProcessors) Less(i, j int) bool { return rp[i].Config.Order < rp[j].Config.Order }\n\n// ProcessorConfig containing a name and filter\ntype ProcessorConfig struct {\n\tName     string\n\tSource   string\n\tAlias    string\n\tID       string\n\tOrder    int64\n\tFilter   Filter\n\tLogLevel string\n}\n\nfunc NewRunningProcessor(processor telegraf.StreamingProcessor, config *ProcessorConfig) *RunningProcessor {\n\ttags := map[string]string{\n\t\t\"_id\":       config.ID,\n\t\t\"processor\": config.Name,\n\t}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\tprocessErrorsRegister := selfstat.Register(\"process\", \"errors\", tags)\n\tlogger := logging.New(\"processors\", config.Name, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\tprocessErrorsRegister.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(processor, logger)\n\tSetStatisticsOnPlugin(processor, logger, tags)\n\n\treturn &RunningProcessor{\n\t\tProcessor: processor,\n\t\tConfig:    config,\n\t\tlog:       logger,\n\t}\n}\n\nfunc (*RunningProcessor) metricFiltered(metric telegraf.Metric) {\n\tmetric.Drop()\n}\n\nfunc (rp *RunningProcessor) Init() error {\n\tif p, ok := rp.Processor.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (rp *RunningProcessor) ID() string {\n\tif p, ok := rp.Processor.(telegraf.PluginWithID); ok {\n\t\treturn p.ID()\n\t}\n\treturn rp.Config.ID\n}\n\nfunc (rp *RunningProcessor) Log() telegraf.Logger {\n\treturn rp.log\n}\n\nfunc (rp *RunningProcessor) LogName() string {\n\treturn logName(\"processors\", rp.Config.Name, rp.Config.Alias)\n}\n\nfunc (*RunningProcessor) MakeMetric(metric telegraf.Metric) telegraf.Metric {\n\treturn metric\n}\n\nfunc (rp *RunningProcessor) Start(acc telegraf.Accumulator) error {\n\treturn rp.Processor.Start(acc)\n}\n\nfunc (rp *RunningProcessor) Add(m telegraf.Metric, acc telegraf.Accumulator) error {\n\tok, err := rp.Config.Filter.Select(m)\n\tif err != nil {\n\t\trp.log.Errorf(\"filtering failed: %v\", err)\n\t} else if !ok {\n\t\t// pass downstream\n\t\tacc.AddMetric(m)\n\t\treturn nil\n\t}\n\n\trp.Config.Filter.Modify(m)\n\tif len(m.FieldList()) == 0 {\n\t\t// drop metric\n\t\trp.metricFiltered(m)\n\t\treturn nil\n\t}\n\n\treturn rp.Processor.Add(m, acc)\n}\n\nfunc (rp *RunningProcessor) Stop() {\n\trp.Processor.Stop()\n}\n"
  },
  {
    "path": "models/running_processor_test.go",
    "content": "package models_test\n\nimport (\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRunningProcessorInit(t *testing.T) {\n\tmock := mockProcessor{}\n\trp := &models.RunningProcessor{\n\t\tProcessor: processors.NewStreamingProcessorFromProcessor(&mock),\n\t}\n\trequire.NoError(t, rp.Init())\n\trequire.True(t, mock.hasBeenInit)\n}\n\nfunc TestRunningProcessorApply(t *testing.T) {\n\ttype args struct {\n\t\tProcessor telegraf.StreamingProcessor\n\t\tConfig    *models.ProcessorConfig\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\targs     args\n\t\tinput    []telegraf.Metric\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"inactive filter applies metrics\",\n\t\t\targs: args{\n\t\t\t\tProcessor: processors.NewStreamingProcessorFromProcessor(\n\t\t\t\t\t&mockProcessor{\n\t\t\t\t\t\tapplyF: func(in ...telegraf.Metric) []telegraf.Metric {\n\t\t\t\t\t\t\tfor _, m := range in {\n\t\t\t\t\t\t\t\tm.AddTag(\"apply\", \"true\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn in\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tConfig: &models.ProcessorConfig{\n\t\t\t\t\tFilter: models.Filter{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tinput: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"apply\": \"true\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"filter applies\",\n\t\t\targs: args{\n\t\t\t\tProcessor: processors.NewStreamingProcessorFromProcessor(\n\t\t\t\t\t&mockProcessor{\n\t\t\t\t\t\tapplyF: func(in ...telegraf.Metric) []telegraf.Metric {\n\t\t\t\t\t\t\tfor _, m := range in {\n\t\t\t\t\t\t\t\tm.AddTag(\"apply\", \"true\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn in\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tConfig: &models.ProcessorConfig{\n\t\t\t\t\tFilter: models.Filter{\n\t\t\t\t\t\tNamePass: []string{\"cpu\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tinput: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"apply\": \"true\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"filter doesn't apply\",\n\t\t\targs: args{\n\t\t\t\tProcessor: processors.NewStreamingProcessorFromProcessor(\n\t\t\t\t\t&mockProcessor{\n\t\t\t\t\t\tapplyF: func(in ...telegraf.Metric) []telegraf.Metric {\n\t\t\t\t\t\t\tfor _, m := range in {\n\t\t\t\t\t\t\t\tm.AddTag(\"apply\", \"true\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn in\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tConfig: &models.ProcessorConfig{\n\t\t\t\t\tFilter: models.Filter{\n\t\t\t\t\t\tNameDrop: []string{\"cpu\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tinput: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trp := &models.RunningProcessor{\n\t\t\t\tProcessor: tt.args.Processor,\n\t\t\t\tConfig:    tt.args.Config,\n\t\t\t}\n\t\t\terr := rp.Config.Filter.Compile()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc := testutil.Accumulator{}\n\t\t\terr = rp.Start(&acc)\n\t\t\trequire.NoError(t, err)\n\t\t\tfor _, m := range tt.input {\n\t\t\t\terr = rp.Add(m, &acc)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\trp.Stop()\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestRunningProcessorOrder(t *testing.T) {\n\trp1 := &models.RunningProcessor{\n\t\tConfig: &models.ProcessorConfig{\n\t\t\tOrder: 1,\n\t\t},\n\t}\n\trp2 := &models.RunningProcessor{\n\t\tConfig: &models.ProcessorConfig{\n\t\t\tOrder: 2,\n\t\t},\n\t}\n\trp3 := &models.RunningProcessor{\n\t\tConfig: &models.ProcessorConfig{\n\t\t\tOrder: 3,\n\t\t},\n\t}\n\n\tprocs := models.RunningProcessors{rp2, rp3, rp1}\n\tsort.Sort(procs)\n\trequire.Equal(t,\n\t\tmodels.RunningProcessors{rp1, rp2, rp3},\n\t\tprocs)\n}\n\n// mockProcessor is a processor with an overridable apply implementation.\ntype mockProcessor struct {\n\tapplyF      func(in ...telegraf.Metric) []telegraf.Metric\n\thasBeenInit bool\n}\n\nfunc (*mockProcessor) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (p *mockProcessor) Init() error {\n\tp.hasBeenInit = true\n\treturn nil\n}\n\nfunc (p *mockProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric {\n\treturn p.applyF(in...)\n}\n"
  },
  {
    "path": "models/running_serializer.go",
    "content": "package models\n\nimport (\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\tlogging \"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n// SerializerConfig is the common config for all serializers.\ntype SerializerConfig struct {\n\tParent      string\n\tAlias       string\n\tDataFormat  string\n\tDefaultTags map[string]string\n\tLogLevel    string\n}\n\ntype RunningSerializer struct {\n\tSerializer telegraf.Serializer\n\tConfig     *SerializerConfig\n\tlog        telegraf.Logger\n\n\tMetricsSerialized selfstat.Stat\n\tBytesSerialized   selfstat.Stat\n\tSerializationTime selfstat.Stat\n}\n\nfunc NewRunningSerializer(serializer telegraf.Serializer, config *SerializerConfig) *RunningSerializer {\n\ttags := map[string]string{\"type\": config.DataFormat}\n\tif config.Alias != \"\" {\n\t\ttags[\"alias\"] = config.Alias\n\t}\n\n\tserializerErrorsRegister := selfstat.Register(\"serializer\", \"errors\", tags)\n\tlogger := logging.New(\"serializers\", config.DataFormat+\"::\"+config.Parent, config.Alias)\n\tlogger.RegisterErrorCallback(func() {\n\t\tserializerErrorsRegister.Incr(1)\n\t})\n\tif err := logger.SetLogLevel(config.LogLevel); err != nil {\n\t\tlogger.Error(err)\n\t}\n\tSetLoggerOnPlugin(serializer, logger)\n\tSetStatisticsOnPlugin(serializer, logger, tags)\n\n\treturn &RunningSerializer{\n\t\tSerializer: serializer,\n\t\tConfig:     config,\n\t\tMetricsSerialized: selfstat.Register(\n\t\t\t\"serializer\",\n\t\t\t\"metrics_serialized\",\n\t\t\ttags,\n\t\t),\n\t\tBytesSerialized: selfstat.Register(\n\t\t\t\"serializer\",\n\t\t\t\"bytes_serialized\",\n\t\t\ttags,\n\t\t),\n\t\tSerializationTime: selfstat.Register(\n\t\t\t\"serializer\",\n\t\t\t\"serialization_time_ns\",\n\t\t\ttags,\n\t\t),\n\t\tlog: logger,\n\t}\n}\n\nfunc (r *RunningSerializer) LogName() string {\n\treturn logName(\"parsers\", r.Config.DataFormat+\"::\"+r.Config.Parent, r.Config.Alias)\n}\n\nfunc (r *RunningSerializer) Init() error {\n\tif p, ok := r.Serializer.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *RunningSerializer) Serialize(metric telegraf.Metric) ([]byte, error) {\n\tstart := time.Now()\n\tbuf, err := r.Serializer.Serialize(metric)\n\telapsed := time.Since(start)\n\tr.SerializationTime.Incr(elapsed.Nanoseconds())\n\tr.MetricsSerialized.Incr(1)\n\tr.BytesSerialized.Incr(int64(len(buf)))\n\n\treturn buf, err\n}\n\nfunc (r *RunningSerializer) SerializeBatch(metrics []telegraf.Metric) ([]byte, error) {\n\tstart := time.Now()\n\tbuf, err := r.Serializer.SerializeBatch(metrics)\n\telapsed := time.Since(start)\n\tr.SerializationTime.Incr(elapsed.Nanoseconds())\n\tr.MetricsSerialized.Incr(int64(len(metrics)))\n\tr.BytesSerialized.Incr(int64(len(buf)))\n\n\treturn buf, err\n}\n\nfunc (r *RunningSerializer) Log() telegraf.Logger {\n\treturn r.log\n}\n"
  },
  {
    "path": "output.go",
    "content": "package telegraf\n\ntype Output interface {\n\tPluginDescriber\n\n\t// Connect to the Output; connect is only called once when the plugin starts\n\tConnect() error\n\t// Close any connections to the Output. Close is called once when the output\n\t// is shutting down. Close will not be called until all writes have finished,\n\t// and Write() will not be called once Close() has been, so locking is not\n\t// necessary.\n\tClose() error\n\t// Write takes in group of points to be written to the Output\n\tWrite(metrics []Metric) error\n}\n\n// AggregatingOutput adds aggregating functionality to an Output.  May be used\n// if the Output only accepts a fixed set of aggregations over a time period.\n// These functions may be called concurrently to the Write function.\ntype AggregatingOutput interface {\n\tOutput\n\n\t// Add the metric to the aggregator\n\tAdd(in Metric)\n\t// Push returns the aggregated metrics and is called every flush interval.\n\tPush() []Metric\n\t// Reset signals that the aggregator period is completed.\n\tReset()\n}\n"
  },
  {
    "path": "parser.go",
    "content": "package telegraf\n\n// Parser is an interface defining functions that a parser plugin must satisfy.\ntype Parser interface {\n\t// Parse takes a byte buffer separated by newlines\n\t// ie, `cpu.usage.idle 90\\ncpu.usage.busy 10`\n\t// and parses it into telegraf metrics\n\t//\n\t// Must be thread-safe.\n\tParse(buf []byte) ([]Metric, error)\n\n\t// ParseLine takes a single string metric\n\t// ie, \"cpu.usage.idle 90\"\n\t// and parses it into a telegraf metric.\n\t//\n\t// Must be thread-safe.\n\tParseLine(line string) (Metric, error)\n\n\t// SetDefaultTags tells the parser to add all of the given tags\n\t// to each parsed metric.\n\t// NOTE: do _not_ modify the map after you've passed it here!!\n\tSetDefaultTags(tags map[string]string)\n}\n\n// ParserFunc is a function to create a new instance of a parser\ntype ParserFunc func() (Parser, error)\n\n// ParserPlugin is an interface for plugins that are able to parse\n// arbitrary data formats.\ntype ParserPlugin interface {\n\t// SetParser sets the parser function for the interface\n\tSetParser(parser Parser)\n}\n\n// ParserFuncPlugin is an interface for plugins that are able to parse\n// arbitrary data formats.\ntype ParserFuncPlugin interface {\n\t// SetParserFunc returns a new parser.\n\tSetParserFunc(fn ParserFunc)\n}\n"
  },
  {
    "path": "persister/persister.go",
    "content": "package persister\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Persister struct {\n\tFilename string\n\n\tregister map[string]telegraf.StatefulPlugin\n}\n\nfunc (p *Persister) Init() error {\n\tp.register = make(map[string]telegraf.StatefulPlugin)\n\n\treturn nil\n}\n\nfunc (p *Persister) Register(id string, plugin telegraf.StatefulPlugin) error {\n\tif _, found := p.register[id]; found {\n\t\treturn fmt.Errorf(\"plugin with ID %q already registered\", id)\n\t}\n\tp.register[id] = plugin\n\n\treturn nil\n}\n\nfunc (p *Persister) Load() error {\n\t// Read the states from disk\n\tin, err := os.ReadFile(p.Filename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading states file failed: %w\", err)\n\t}\n\n\t// Unmarshal the id to serialized states map\n\tvar states map[string][]byte\n\tif err := json.Unmarshal(in, &states); err != nil {\n\t\treturn fmt.Errorf(\"unmarshalling states failed: %w\", err)\n\t}\n\n\t// Get the initialized state as blueprint for unmarshalling\n\tfor id, serialized := range states {\n\t\t// Check if we have a plugin with that ID\n\t\tplugin, found := p.register[id]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create a new empty state of the \"state\"-type. As we need a pointer\n\t\t// of the state, we cannot dereference it here due to the unknown\n\t\t// nature of the state-type.\n\t\tnstate := reflect.New(reflect.TypeOf(plugin.GetState())).Interface()\n\t\tif err := json.Unmarshal(serialized, &nstate); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshalling state for %q failed: %w\", id, err)\n\t\t}\n\t\tstate := reflect.ValueOf(nstate).Elem().Interface()\n\n\t\t// Set the state in the plugin\n\t\tif err := plugin.SetState(state); err != nil {\n\t\t\treturn fmt.Errorf(\"setting state of %q failed: %w\", id, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Persister) Store() error {\n\tstates := make(map[string][]byte)\n\n\t// Collect the states and serialize the individual data chunks\n\t// to later serialize all items in the id / serialized-states map\n\tfor id, plugin := range p.register {\n\t\tstate, err := json.Marshal(plugin.GetState())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"marshalling state for id %q failed: %w\", id, err)\n\t\t}\n\t\tstates[id] = state\n\t}\n\n\t// Serialize the states\n\tserialized, err := json.Marshal(states)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshalling states failed: %w\", err)\n\t}\n\n\t// Write the states to disk\n\tf, err := os.Create(p.Filename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating states file %q failed: %w\", p.Filename, err)\n\t}\n\tdefer f.Close()\n\n\tif _, err := f.Write(serialized); err != nil {\n\t\treturn fmt.Errorf(\"writing states failed: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugin.go",
    "content": "package telegraf\n\n// DeprecationInfo contains information for marking a plugin deprecated.\ntype DeprecationInfo struct {\n\t// Since specifies the version since when the plugin is deprecated\n\tSince string\n\t// RemovalIn optionally specifies the version when the plugin is scheduled for removal\n\tRemovalIn string\n\t// Notice for the user on suggested replacements etc.\n\tNotice string\n}\n\n// Initializer is an interface that all plugin types: Inputs, Outputs,\n// Processors, and Aggregators can optionally implement to initialize the\n// plugin.\ntype Initializer interface {\n\t// Init performs one time setup of the plugin and returns an error if the\n\t// configuration is invalid.\n\tInit() error\n}\n\n// PluginDescriber contains the functions all plugins must implement to describe\n// themselves to Telegraf. Note that all plugins may define a logger that is\n// not part of the interface, but will receive an injected logger if it's set.\n// eg: Log telegraf.Logger `toml:\"-\"`\ntype PluginDescriber interface {\n\t// SampleConfig returns the default configuration of the Plugin\n\tSampleConfig() string\n}\n\n// PluginWithID allows a plugin to overwrite its identifier of the plugin\n// instance by a user specified value. By default the ID is generated\n// using the plugin's configuration.\ntype PluginWithID interface {\n\t// ID returns the ID of the plugin instance. This function has to be\n\t// callable directly after the plugin's Init() function if there is any!\n\tID() string\n}\n\n// StatefulPlugin contains the functions that plugins must implement to\n// persist an internal state across Telegraf runs.\n// Note that plugins may define a persister that is not part of the\n// interface, but can be used to trigger state updates by the plugin if\n// it exists in the plugin struct,\n// eg: Persister telegraf.StatePersister `toml:\"-\"`\ntype StatefulPlugin interface {\n\t// GetState returns the current state of the plugin to persist\n\t// The returned state can be of any time as long as it can be\n\t// serialized to JSON. The best choice is a structure defined in\n\t// your plugin.\n\t// Note: This function has to be callable directly after the\n\t// plugin's Init() function if there is any!\n\tGetState() interface{}\n\n\t// SetState is called by the Persister once after loading and\n\t// initialization (after Init() function).\n\tSetState(state interface{}) error\n}\n\n// ProbePlugin is an interface that all input/output plugins need to\n// implement in order to support the `probe` value of `startup_error_behavior`\ntype ProbePlugin interface {\n\tProbe() error\n}\n"
  },
  {
    "path": "plugins/aggregators/all/all.go",
    "content": "package all\n"
  },
  {
    "path": "plugins/aggregators/all/basicstats.go",
    "content": "//go:build !custom || aggregators || aggregators.basicstats\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/basicstats\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/derivative.go",
    "content": "//go:build !custom || aggregators || aggregators.derivative\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/derivative\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/final.go",
    "content": "//go:build !custom || aggregators || aggregators.final\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/final\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/histogram.go",
    "content": "//go:build !custom || aggregators || aggregators.histogram\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/histogram\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/merge.go",
    "content": "//go:build !custom || aggregators || aggregators.merge\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/merge\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/minmax.go",
    "content": "//go:build !custom || aggregators || aggregators.minmax\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/minmax\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/quantile.go",
    "content": "//go:build !custom || aggregators || aggregators.quantile\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/quantile\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/starlark.go",
    "content": "//go:build !custom || aggregators || aggregators.starlark\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/starlark\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/all/valuecounter.go",
    "content": "//go:build !custom || aggregators || aggregators.valuecounter\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/aggregators/valuecounter\" // register plugin\n"
  },
  {
    "path": "plugins/aggregators/basicstats/README.md",
    "content": "# Basic Statistics Aggregator Plugin\n\nThis plugin computes basic statistics such as counts, differences, minima,\nmaxima, mean values, non-negative differences etc. for a set of metrics and\nemits these statistical values every `period`.\n\n⭐ Telegraf v1.5.0\n🏷️ statistics\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Keep the aggregate basicstats of each metric passing through.\n[[aggregators.basicstats]]\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## Configures which basic stats to push as fields\n  # stats = [\"count\",\"min\",\"max\",\"mean\",\"variance\",\"stdev\"]\n```\n\n- stats\n  - If not specified, then `count`, `min`, `max`, `mean`, `stdev`, and `s2` are\n  aggregated and pushed as fields. Other fields are not aggregated by default\n  to maintain backwards compatibility.\n  - If empty array, no stats are aggregated\n\n## Measurements & Fields\n\n- measurement1\n  - field1_count\n  - field1_diff (difference)\n  - field1_rate (rate per second)\n  - field1_max\n  - field1_min\n  - field1_mean\n  - field1_non_negative_diff (non-negative difference)\n  - field1_non_negative_rate (non-negative rate per second)\n  - field1_percent_change\n  - field1_sum\n  - field1_s2 (variance)\n  - field1_stdev (standard deviation)\n  - field1_interval (interval in nanoseconds)\n  - field1_last (last aggregated value)\n  - field1_first (first aggregated value)\n\n## Tags\n\nNo tags are applied by this aggregator.\n\n## Example Output\n\n```text\nsystem,host=tars load1=1 1475583980000000000\nsystem,host=tars load1=1 1475583990000000000\nsystem,host=tars load1_count=2,load1_diff=0,load1_rate=0,load1_max=1,load1_min=1,load1_mean=1,load1_sum=2,load1_s2=0,load1_stdev=0,load1_interval=10000000000i,load1_last=1 1475584010000000000\nsystem,host=tars load1=1 1475584020000000000\nsystem,host=tars load1=3 1475584030000000000\nsystem,host=tars load1_count=2,load1_diff=2,load1_rate=0.2,load1_max=3,load1_min=1,load1_mean=2,load1_sum=4,load1_s2=2,load1_stdev=1.414162,load1_interval=10000000000i,load1_last=3,load1_first=3 1475584010000000000\n```\n"
  },
  {
    "path": "plugins/aggregators/basicstats/basicstats.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage basicstats\n\nimport (\n\t_ \"embed\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype BasicStats struct {\n\tStats []string        `toml:\"stats\"`\n\tLog   telegraf.Logger `toml:\"-\"`\n\n\tcache       map[uint64]aggregate\n\tstatsConfig *configuredStats\n}\n\ntype configuredStats struct {\n\tcount           bool\n\tmin             bool\n\tmax             bool\n\tmean            bool\n\tvariance        bool\n\tstdev           bool\n\tsum             bool\n\tdiff            bool\n\tnonNegativeDiff bool\n\trate            bool\n\tnonNegativeRate bool\n\tpercentChange   bool\n\tinterval        bool\n\tlast            bool\n\tfirst           bool\n}\n\ntype aggregate struct {\n\tfields map[string]basicstats\n\tname   string\n\ttags   map[string]string\n}\n\ntype basicstats struct {\n\tcount    float64\n\tmin      float64\n\tmax      float64\n\tsum      float64\n\tmean     float64\n\tdiff     float64\n\trate     float64\n\tinterval time.Duration\n\tlast     float64\n\tfirst    float64\n\tM2       float64   // intermediate value for variance/stdev\n\tPREVIOUS float64   // intermediate value for diff\n\tTIME     time.Time // intermediate value for rate\n}\n\nfunc (*BasicStats) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *BasicStats) Init() error {\n\tb.initConfiguredStats()\n\n\treturn nil\n}\n\nfunc (b *BasicStats) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\tif _, ok := b.cache[id]; !ok {\n\t\t// hit an uncached metric, create caches for first time:\n\t\ta := aggregate{\n\t\t\tname:   in.Name(),\n\t\t\ttags:   in.Tags(),\n\t\t\tfields: make(map[string]basicstats),\n\t\t}\n\t\tfor _, field := range in.FieldList() {\n\t\t\tif fv, ok := convert(field.Value); ok {\n\t\t\t\ta.fields[field.Key] = basicstats{\n\t\t\t\t\tcount:    1,\n\t\t\t\t\tmin:      fv,\n\t\t\t\t\tmax:      fv,\n\t\t\t\t\tmean:     fv,\n\t\t\t\t\tsum:      fv,\n\t\t\t\t\tdiff:     0.0,\n\t\t\t\t\trate:     0.0,\n\t\t\t\t\tlast:     fv,\n\t\t\t\t\tfirst:    fv,\n\t\t\t\t\tM2:       0.0,\n\t\t\t\t\tPREVIOUS: fv,\n\t\t\t\t\tTIME:     in.Time(),\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tb.cache[id] = a\n\t} else {\n\t\tfor _, field := range in.FieldList() {\n\t\t\tif fv, ok := convert(field.Value); ok {\n\t\t\t\tif _, ok := b.cache[id].fields[field.Key]; !ok {\n\t\t\t\t\t// hit an uncached field of a cached metric\n\t\t\t\t\tb.cache[id].fields[field.Key] = basicstats{\n\t\t\t\t\t\tcount:    1,\n\t\t\t\t\t\tmin:      fv,\n\t\t\t\t\t\tmax:      fv,\n\t\t\t\t\t\tmean:     fv,\n\t\t\t\t\t\tsum:      fv,\n\t\t\t\t\t\tdiff:     0.0,\n\t\t\t\t\t\trate:     0.0,\n\t\t\t\t\t\tinterval: 0,\n\t\t\t\t\t\tlast:     fv,\n\t\t\t\t\t\tfirst:    fv,\n\t\t\t\t\t\tM2:       0.0,\n\t\t\t\t\t\tPREVIOUS: fv,\n\t\t\t\t\t\tTIME:     in.Time(),\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ttmp := b.cache[id].fields[field.Key]\n\t\t\t\t// https://en.m.wikipedia.org/wiki/Algorithms_for_calculating_variance\n\t\t\t\t// variable initialization\n\t\t\t\tx := fv\n\t\t\t\tmean := tmp.mean\n\t\t\t\tm2 := tmp.M2\n\t\t\t\t// counter compute\n\t\t\t\tn := tmp.count + 1\n\t\t\t\ttmp.count = n\n\t\t\t\t// mean compute\n\t\t\t\tdelta := x - mean\n\t\t\t\tmean = mean + delta/n\n\t\t\t\ttmp.mean = mean\n\t\t\t\t// variance/stdev compute\n\t\t\t\tm2 = m2 + delta*(x-mean)\n\t\t\t\ttmp.M2 = m2\n\t\t\t\t// max/min compute\n\t\t\t\tif fv < tmp.min {\n\t\t\t\t\ttmp.min = fv\n\t\t\t\t} else if fv > tmp.max {\n\t\t\t\t\ttmp.max = fv\n\t\t\t\t}\n\t\t\t\t// sum compute\n\t\t\t\ttmp.sum += fv\n\t\t\t\t// diff compute\n\t\t\t\ttmp.diff = fv - tmp.PREVIOUS\n\t\t\t\t// interval compute\n\t\t\t\ttmp.interval = in.Time().Sub(tmp.TIME)\n\t\t\t\t// rate compute\n\t\t\t\tif !in.Time().Equal(tmp.TIME) {\n\t\t\t\t\ttmp.rate = tmp.diff / tmp.interval.Seconds()\n\t\t\t\t}\n\t\t\t\t// last compute\n\t\t\t\ttmp.last = fv\n\t\t\t\t// store final data\n\t\t\t\tb.cache[id].fields[field.Key] = tmp\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (b *BasicStats) Push(acc telegraf.Accumulator) {\n\tfor _, aggregate := range b.cache {\n\t\tfields := make(map[string]interface{})\n\t\tfor k, v := range aggregate.fields {\n\t\t\tif b.statsConfig.count {\n\t\t\t\tfields[k+\"_count\"] = v.count\n\t\t\t}\n\t\t\tif b.statsConfig.min {\n\t\t\t\tfields[k+\"_min\"] = v.min\n\t\t\t}\n\t\t\tif b.statsConfig.max {\n\t\t\t\tfields[k+\"_max\"] = v.max\n\t\t\t}\n\t\t\tif b.statsConfig.mean {\n\t\t\t\tfields[k+\"_mean\"] = v.mean\n\t\t\t}\n\t\t\tif b.statsConfig.sum {\n\t\t\t\tfields[k+\"_sum\"] = v.sum\n\t\t\t}\n\t\t\tif b.statsConfig.last {\n\t\t\t\tfields[k+\"_last\"] = v.last\n\t\t\t}\n\t\t\tif b.statsConfig.first {\n\t\t\t\tfields[k+\"_first\"] = v.first\n\t\t\t}\n\n\t\t\t// v.count always >=1\n\t\t\tif v.count > 1 {\n\t\t\t\tvariance := v.M2 / (v.count - 1)\n\n\t\t\t\tif b.statsConfig.variance {\n\t\t\t\t\tfields[k+\"_s2\"] = variance\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.stdev {\n\t\t\t\t\tfields[k+\"_stdev\"] = math.Sqrt(variance)\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.diff {\n\t\t\t\t\tfields[k+\"_diff\"] = v.diff\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.nonNegativeDiff && v.diff >= 0 {\n\t\t\t\t\tfields[k+\"_non_negative_diff\"] = v.diff\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.rate {\n\t\t\t\t\tfields[k+\"_rate\"] = v.rate\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.percentChange {\n\t\t\t\t\tfields[k+\"_percent_change\"] = v.diff / v.PREVIOUS * 100\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.nonNegativeRate && v.diff >= 0 {\n\t\t\t\t\tfields[k+\"_non_negative_rate\"] = v.rate\n\t\t\t\t}\n\t\t\t\tif b.statsConfig.interval {\n\t\t\t\t\tfields[k+\"_interval\"] = v.interval.Nanoseconds()\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if count == 1 StdDev = infinite => so I won't send data\n\t\t}\n\n\t\tif len(fields) > 0 {\n\t\t\tacc.AddFields(aggregate.name, fields, aggregate.tags)\n\t\t}\n\t}\n}\n\nfunc (b *BasicStats) Reset() {\n\tb.cache = make(map[uint64]aggregate)\n}\n\n// member function for logging.\nfunc (b *BasicStats) parseStats() *configuredStats {\n\tparsed := &configuredStats{}\n\n\tfor _, name := range b.Stats {\n\t\tswitch name {\n\t\tcase \"count\":\n\t\t\tparsed.count = true\n\t\tcase \"min\":\n\t\t\tparsed.min = true\n\t\tcase \"max\":\n\t\t\tparsed.max = true\n\t\tcase \"mean\":\n\t\t\tparsed.mean = true\n\t\tcase \"s2\":\n\t\t\tparsed.variance = true\n\t\tcase \"stdev\":\n\t\t\tparsed.stdev = true\n\t\tcase \"sum\":\n\t\t\tparsed.sum = true\n\t\tcase \"diff\":\n\t\t\tparsed.diff = true\n\t\tcase \"non_negative_diff\":\n\t\t\tparsed.nonNegativeDiff = true\n\t\tcase \"rate\":\n\t\t\tparsed.rate = true\n\t\tcase \"non_negative_rate\":\n\t\t\tparsed.nonNegativeRate = true\n\t\tcase \"percent_change\":\n\t\t\tparsed.percentChange = true\n\t\tcase \"interval\":\n\t\t\tparsed.interval = true\n\t\tcase \"last\":\n\t\t\tparsed.last = true\n\t\tcase \"first\":\n\t\t\tparsed.first = true\n\t\tdefault:\n\t\t\tb.Log.Warnf(\"Unrecognized basic stat %q, ignoring\", name)\n\t\t}\n\t}\n\n\treturn parsed\n}\n\nfunc (b *BasicStats) initConfiguredStats() {\n\tif b.Stats == nil {\n\t\tb.statsConfig = &configuredStats{\n\t\t\tcount:           true,\n\t\t\tmin:             true,\n\t\t\tmax:             true,\n\t\t\tmean:            true,\n\t\t\tvariance:        true,\n\t\t\tstdev:           true,\n\t\t\tsum:             false,\n\t\t\tdiff:            false,\n\t\t\tnonNegativeDiff: false,\n\t\t\trate:            false,\n\t\t\tnonNegativeRate: false,\n\t\t\tpercentChange:   false,\n\t\t\tinterval:        false,\n\t\t\tlast:            false,\n\t\t\tfirst:           false,\n\t\t}\n\t} else {\n\t\tb.statsConfig = b.parseStats()\n\t}\n}\n\nfunc convert(in interface{}) (float64, bool) {\n\tswitch v := in.(type) {\n\tcase float64:\n\t\treturn v, true\n\tcase int64:\n\t\treturn float64(v), true\n\tcase uint64:\n\t\treturn float64(v), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\nfunc newBasicStats() *BasicStats {\n\treturn &BasicStats{\n\t\tcache: make(map[uint64]aggregate),\n\t}\n}\n\nfunc init() {\n\taggregators.Add(\"basicstats\", func() telegraf.Aggregator {\n\t\treturn newBasicStats()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/basicstats/basicstats_test.go",
    "content": "package basicstats\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar m1 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\": int64(1),\n\t\t\"b\": int64(1),\n\t\t\"c\": float64(2),\n\t\t\"d\": float64(2),\n\t\t\"g\": int64(3),\n\t},\n\ttime.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),\n)\nvar m2 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\":        int64(1),\n\t\t\"b\":        int64(3),\n\t\t\"c\":        float64(4),\n\t\t\"d\":        float64(6),\n\t\t\"e\":        float64(200),\n\t\t\"f\":        uint64(200),\n\t\t\"ignoreme\": \"string\",\n\t\t\"andme\":    true,\n\t\t\"g\":        int64(1),\n\t},\n\ttime.Date(2000, 1, 1, 0, 0, 0, 1e6, time.UTC),\n)\n\nfunc BenchmarkApply(b *testing.B) {\n\tminmax := newBasicStats()\n\tminmax.Log = testutil.Logger{}\n\tminmax.initConfiguredStats()\n\n\tfor n := 0; n < b.N; n++ {\n\t\tminmax.Add(m1)\n\t\tminmax.Add(m2)\n\t}\n}\n\n// Test two metrics getting added.\nfunc TestBasicStatsWithPeriod(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax := newBasicStats()\n\tminmax.Log = testutil.Logger{}\n\tminmax.initConfiguredStats()\n\n\tminmax.Add(m1)\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_count\": float64(2), // a\n\t\t\"a_max\":   float64(1),\n\t\t\"a_min\":   float64(1),\n\t\t\"a_mean\":  float64(1),\n\t\t\"a_stdev\": float64(0),\n\t\t\"a_s2\":    float64(0),\n\t\t\"b_count\": float64(2), // b\n\t\t\"b_max\":   float64(3),\n\t\t\"b_min\":   float64(1),\n\t\t\"b_mean\":  float64(2),\n\t\t\"b_s2\":    float64(2),\n\t\t\"b_stdev\": math.Sqrt(2),\n\t\t\"c_count\": float64(2), // c\n\t\t\"c_max\":   float64(4),\n\t\t\"c_min\":   float64(2),\n\t\t\"c_mean\":  float64(3),\n\t\t\"c_s2\":    float64(2),\n\t\t\"c_stdev\": math.Sqrt(2),\n\t\t\"d_count\": float64(2), // d\n\t\t\"d_max\":   float64(6),\n\t\t\"d_min\":   float64(2),\n\t\t\"d_mean\":  float64(4),\n\t\t\"d_s2\":    float64(8),\n\t\t\"d_stdev\": math.Sqrt(8),\n\t\t\"e_count\": float64(1), // e\n\t\t\"e_max\":   float64(200),\n\t\t\"e_min\":   float64(200),\n\t\t\"e_mean\":  float64(200),\n\t\t\"f_count\": float64(1), // f\n\t\t\"f_max\":   float64(200),\n\t\t\"f_min\":   float64(200),\n\t\t\"f_mean\":  float64(200),\n\t\t\"g_count\": float64(2), // g\n\t\t\"g_max\":   float64(3),\n\t\t\"g_min\":   float64(1),\n\t\t\"g_mean\":  float64(2),\n\t\t\"g_s2\":    float64(2),\n\t\t\"g_stdev\": math.Sqrt(2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test two metrics getting added with a push/reset in between (simulates\n// getting added in different periods.)\nfunc TestBasicStatsDifferentPeriods(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax := newBasicStats()\n\tminmax.Stats = []string{\"count\", \"max\", \"min\", \"mean\", \"last\", \"first\"}\n\tminmax.Log = testutil.Logger{}\n\tminmax.initConfiguredStats()\n\n\tminmax.Add(m1)\n\tminmax.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"a_count\": float64(1), // a\n\t\t\"a_max\":   float64(1),\n\t\t\"a_min\":   float64(1),\n\t\t\"a_mean\":  float64(1),\n\t\t\"a_last\":  float64(1),\n\t\t\"a_first\": float64(1),\n\t\t\"b_count\": float64(1), // b\n\t\t\"b_max\":   float64(1),\n\t\t\"b_min\":   float64(1),\n\t\t\"b_mean\":  float64(1),\n\t\t\"b_last\":  float64(1),\n\t\t\"b_first\": float64(1),\n\t\t\"c_count\": float64(1), // c\n\t\t\"c_max\":   float64(2),\n\t\t\"c_min\":   float64(2),\n\t\t\"c_mean\":  float64(2),\n\t\t\"c_last\":  float64(2),\n\t\t\"c_first\": float64(2),\n\t\t\"d_count\": float64(1), // d\n\t\t\"d_max\":   float64(2),\n\t\t\"d_min\":   float64(2),\n\t\t\"d_mean\":  float64(2),\n\t\t\"d_last\":  float64(2),\n\t\t\"d_first\": float64(2),\n\t\t\"g_count\": float64(1), // g\n\t\t\"g_max\":   float64(3),\n\t\t\"g_min\":   float64(3),\n\t\t\"g_mean\":  float64(3),\n\t\t\"g_last\":  float64(3),\n\t\t\"g_first\": float64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n\n\tacc.ClearMetrics()\n\tminmax.Reset()\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\texpectedFields = map[string]interface{}{\n\t\t\"a_count\": float64(1), // a\n\t\t\"a_max\":   float64(1),\n\t\t\"a_min\":   float64(1),\n\t\t\"a_mean\":  float64(1),\n\t\t\"a_last\":  float64(1),\n\t\t\"a_first\": float64(1),\n\t\t\"b_count\": float64(1), // b\n\t\t\"b_max\":   float64(3),\n\t\t\"b_min\":   float64(3),\n\t\t\"b_mean\":  float64(3),\n\t\t\"b_last\":  float64(3),\n\t\t\"b_first\": float64(3),\n\t\t\"c_count\": float64(1), // c\n\t\t\"c_max\":   float64(4),\n\t\t\"c_min\":   float64(4),\n\t\t\"c_mean\":  float64(4),\n\t\t\"c_last\":  float64(4),\n\t\t\"c_first\": float64(4),\n\t\t\"d_count\": float64(1), // d\n\t\t\"d_max\":   float64(6),\n\t\t\"d_min\":   float64(6),\n\t\t\"d_mean\":  float64(6),\n\t\t\"d_last\":  float64(6),\n\t\t\"d_first\": float64(6),\n\t\t\"e_count\": float64(1), // e\n\t\t\"e_max\":   float64(200),\n\t\t\"e_min\":   float64(200),\n\t\t\"e_mean\":  float64(200),\n\t\t\"e_last\":  float64(200),\n\t\t\"e_first\": float64(200),\n\t\t\"f_count\": float64(1), // f\n\t\t\"f_max\":   float64(200),\n\t\t\"f_min\":   float64(200),\n\t\t\"f_mean\":  float64(200),\n\t\t\"f_last\":  float64(200),\n\t\t\"f_first\": float64(200),\n\t\t\"g_count\": float64(1), // g\n\t\t\"g_max\":   float64(1),\n\t\t\"g_min\":   float64(1),\n\t\t\"g_mean\":  float64(1),\n\t\t\"g_last\":  float64(1),\n\t\t\"g_first\": float64(1),\n\t}\n\texpectedTags = map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating count\nfunc TestBasicStatsWithOnlyCount(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"count\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_count\": float64(2),\n\t\t\"b_count\": float64(2),\n\t\t\"c_count\": float64(2),\n\t\t\"d_count\": float64(2),\n\t\t\"e_count\": float64(1),\n\t\t\"f_count\": float64(1),\n\t\t\"g_count\": float64(2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating minimum\nfunc TestBasicStatsWithOnlyMin(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"min\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_min\": float64(1),\n\t\t\"b_min\": float64(1),\n\t\t\"c_min\": float64(2),\n\t\t\"d_min\": float64(2),\n\t\t\"e_min\": float64(200),\n\t\t\"f_min\": float64(200),\n\t\t\"g_min\": float64(1),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating maximum\nfunc TestBasicStatsWithOnlyMax(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"max\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": float64(1),\n\t\t\"b_max\": float64(3),\n\t\t\"c_max\": float64(4),\n\t\t\"d_max\": float64(6),\n\t\t\"e_max\": float64(200),\n\t\t\"f_max\": float64(200),\n\t\t\"g_max\": float64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating mean\nfunc TestBasicStatsWithOnlyMean(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"mean\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_mean\": float64(1),\n\t\t\"b_mean\": float64(2),\n\t\t\"c_mean\": float64(3),\n\t\t\"d_mean\": float64(4),\n\t\t\"e_mean\": float64(200),\n\t\t\"f_mean\": float64(200),\n\t\t\"g_mean\": float64(2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating sum\nfunc TestBasicStatsWithOnlySum(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"sum\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_sum\": float64(2),\n\t\t\"b_sum\": float64(4),\n\t\t\"c_sum\": float64(6),\n\t\t\"d_sum\": float64(8),\n\t\t\"e_sum\": float64(200),\n\t\t\"f_sum\": float64(200),\n\t\t\"g_sum\": float64(4),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Verify that sum doesn't suffer from floating point errors.  Early\n// implementations of sum were calculated from mean and count, which\n// e.g. summed \"1, 1, 5, 1\" as \"7.999999...\" instead of 8.\nfunc TestBasicStatsWithOnlySumFloatingPointErrata(t *testing.T) {\n\tvar sum1 = metric.New(\"m1\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"a\": int64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\tvar sum2 = metric.New(\"m1\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"a\": int64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\tvar sum3 = metric.New(\"m1\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"a\": int64(5),\n\t\t},\n\t\ttime.Now(),\n\t)\n\tvar sum4 = metric.New(\"m1\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"a\": int64(1),\n\t\t},\n\t\ttime.Now(),\n\t)\n\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"sum\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(sum1)\n\taggregator.Add(sum2)\n\taggregator.Add(sum3)\n\taggregator.Add(sum4)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_sum\": float64(8),\n\t}\n\texpectedTags := map[string]string{}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating variance\nfunc TestBasicStatsWithOnlyVariance(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"s2\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_s2\": float64(0),\n\t\t\"b_s2\": float64(2),\n\t\t\"c_s2\": float64(2),\n\t\t\"d_s2\": float64(8),\n\t\t\"g_s2\": float64(2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating standard deviation\nfunc TestBasicStatsWithOnlyStandardDeviation(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"stdev\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_stdev\": float64(0),\n\t\t\"b_stdev\": math.Sqrt(2),\n\t\t\"c_stdev\": math.Sqrt(2),\n\t\t\"d_stdev\": math.Sqrt(8),\n\t\t\"g_stdev\": math.Sqrt(2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating minimum and maximum\nfunc TestBasicStatsWithMinAndMax(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"min\", \"max\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": float64(1), // a\n\t\t\"a_min\": float64(1),\n\t\t\"b_max\": float64(3), // b\n\t\t\"b_min\": float64(1),\n\t\t\"c_max\": float64(4), // c\n\t\t\"c_min\": float64(2),\n\t\t\"d_max\": float64(6), // d\n\t\t\"d_min\": float64(2),\n\t\t\"e_max\": float64(200), // e\n\t\t\"e_min\": float64(200),\n\t\t\"f_max\": float64(200), // f\n\t\t\"f_min\": float64(200),\n\t\t\"g_max\": float64(3), // g\n\t\t\"g_min\": float64(1),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating diff\nfunc TestBasicStatsWithDiff(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"diff\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_diff\": float64(0),\n\t\t\"b_diff\": float64(2),\n\t\t\"c_diff\": float64(2),\n\t\t\"d_diff\": float64(4),\n\t\t\"g_diff\": float64(-2),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc TestBasicStatsWithRate(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"rate\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"a_rate\": float64(0),\n\t\t\"b_rate\": float64(2000),\n\t\t\"c_rate\": float64(2000),\n\t\t\"d_rate\": float64(4000),\n\t\t\"g_rate\": float64(-2000),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc TestBasicStatsWithNonNegativeRate(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"non_negative_rate\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_non_negative_rate\": float64(0),\n\t\t\"b_non_negative_rate\": float64(2000),\n\t\t\"c_non_negative_rate\": float64(2000),\n\t\t\"d_non_negative_rate\": float64(4000),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc TestBasicStatsWithPctChange(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"percent_change\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"a_percent_change\": float64(0),\n\t\t\"b_percent_change\": float64(200),\n\t\t\"c_percent_change\": float64(100),\n\t\t\"d_percent_change\": float64(200),\n\t\t\"g_percent_change\": float64(-66.66666666666666),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc TestBasicStatsWithInterval(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"interval\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_interval\": int64(time.Millisecond),\n\t\t\"b_interval\": int64(time.Millisecond),\n\t\t\"c_interval\": int64(time.Millisecond),\n\t\t\"d_interval\": int64(time.Millisecond),\n\t\t\"g_interval\": int64(time.Millisecond),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test only aggregating non_negative_diff\nfunc TestBasicStatsWithNonNegativeDiff(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"non_negative_diff\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_non_negative_diff\": float64(0),\n\t\t\"b_non_negative_diff\": float64(2),\n\t\t\"c_non_negative_diff\": float64(2),\n\t\t\"d_non_negative_diff\": float64(4),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test aggregating with all stats\nfunc TestBasicStatsWithAllStats(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax := newBasicStats()\n\tminmax.Log = testutil.Logger{}\n\tminmax.Stats = []string{\"count\", \"min\", \"max\", \"mean\", \"stdev\", \"s2\", \"sum\", \"last\", \"first\"}\n\tminmax.initConfiguredStats()\n\n\tminmax.Add(m1)\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_count\": float64(2), // a\n\t\t\"a_max\":   float64(1),\n\t\t\"a_min\":   float64(1),\n\t\t\"a_mean\":  float64(1),\n\t\t\"a_stdev\": float64(0),\n\t\t\"a_s2\":    float64(0),\n\t\t\"a_sum\":   float64(2),\n\t\t\"a_last\":  float64(1),\n\t\t\"a_first\": float64(1),\n\t\t\"b_count\": float64(2), // b\n\t\t\"b_max\":   float64(3),\n\t\t\"b_min\":   float64(1),\n\t\t\"b_mean\":  float64(2),\n\t\t\"b_s2\":    float64(2),\n\t\t\"b_sum\":   float64(4),\n\t\t\"b_last\":  float64(3),\n\t\t\"b_stdev\": math.Sqrt(2),\n\t\t\"b_first\": float64(1),\n\t\t\"c_count\": float64(2), // c\n\t\t\"c_max\":   float64(4),\n\t\t\"c_min\":   float64(2),\n\t\t\"c_mean\":  float64(3),\n\t\t\"c_s2\":    float64(2),\n\t\t\"c_stdev\": math.Sqrt(2),\n\t\t\"c_sum\":   float64(6),\n\t\t\"c_last\":  float64(4),\n\t\t\"c_first\": float64(2),\n\t\t\"d_count\": float64(2), // d\n\t\t\"d_max\":   float64(6),\n\t\t\"d_min\":   float64(2),\n\t\t\"d_mean\":  float64(4),\n\t\t\"d_s2\":    float64(8),\n\t\t\"d_stdev\": math.Sqrt(8),\n\t\t\"d_sum\":   float64(8),\n\t\t\"d_last\":  float64(6),\n\t\t\"d_first\": float64(2),\n\t\t\"e_count\": float64(1), // e\n\t\t\"e_max\":   float64(200),\n\t\t\"e_min\":   float64(200),\n\t\t\"e_mean\":  float64(200),\n\t\t\"e_sum\":   float64(200),\n\t\t\"e_last\":  float64(200),\n\t\t\"e_first\": float64(200),\n\t\t\"f_count\": float64(1), // f\n\t\t\"f_max\":   float64(200),\n\t\t\"f_min\":   float64(200),\n\t\t\"f_mean\":  float64(200),\n\t\t\"f_sum\":   float64(200),\n\t\t\"f_last\":  float64(200),\n\t\t\"f_first\": float64(200),\n\t\t\"g_count\": float64(2), // g\n\t\t\"g_max\":   float64(3),\n\t\t\"g_min\":   float64(1),\n\t\t\"g_mean\":  float64(2),\n\t\t\"g_s2\":    float64(2),\n\t\t\"g_stdev\": math.Sqrt(2),\n\t\t\"g_sum\":   float64(4),\n\t\t\"g_last\":  float64(1),\n\t\t\"g_first\": float64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test that if an empty array is passed, no points are pushed\nfunc TestBasicStatsWithNoStats(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = make([]string, 0)\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"m1\")\n}\n\n// Test that if an unknown stat is configured, it doesn't explode\nfunc TestBasicStatsWithUnknownStat(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"crazy\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"m1\")\n}\n\n// Test that if Stats isn't supplied, then we only do count, min, max, mean,\n// stdev, and s2.  We purposely exclude sum for backwards compatibility,\n// otherwise user's working systems will suddenly (and surprisingly) start\n// capturing sum without their input.\nfunc TestBasicStatsWithDefaultStats(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\trequire.True(t, acc.HasField(\"m1\", \"a_count\"))\n\trequire.True(t, acc.HasField(\"m1\", \"a_min\"))\n\trequire.True(t, acc.HasField(\"m1\", \"a_max\"))\n\trequire.True(t, acc.HasField(\"m1\", \"a_mean\"))\n\trequire.True(t, acc.HasField(\"m1\", \"a_stdev\"))\n\trequire.True(t, acc.HasField(\"m1\", \"a_s2\"))\n\trequire.False(t, acc.HasField(\"m1\", \"a_sum\"))\n}\n\nfunc TestBasicStatsWithOnlyLast(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"last\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_last\": float64(1),\n\t\t\"b_last\": float64(3),\n\t\t\"c_last\": float64(4),\n\t\t\"d_last\": float64(6),\n\t\t\"e_last\": float64(200),\n\t\t\"f_last\": float64(200),\n\t\t\"g_last\": float64(1),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc TestBasicStatsWithOnlyFirst(t *testing.T) {\n\taggregator := newBasicStats()\n\taggregator.Stats = []string{\"first\"}\n\taggregator.Log = testutil.Logger{}\n\taggregator.initConfiguredStats()\n\n\taggregator.Add(m1)\n\taggregator.Add(m2)\n\n\tacc := testutil.Accumulator{}\n\taggregator.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_first\": float64(1),\n\t\t\"b_first\": float64(1),\n\t\t\"c_first\": float64(2),\n\t\t\"d_first\": float64(2),\n\t\t\"e_first\": float64(200),\n\t\t\"f_first\": float64(200),\n\t\t\"g_first\": float64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n"
  },
  {
    "path": "plugins/aggregators/basicstats/sample.conf",
    "content": "# Keep the aggregate basicstats of each metric passing through.\n[[aggregators.basicstats]]\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## Configures which basic stats to push as fields\n  # stats = [\"count\",\"min\",\"max\",\"mean\",\"variance\",\"stdev\"]\n"
  },
  {
    "path": "plugins/aggregators/deprecations.go",
    "content": "package aggregators\n\nimport \"github.com/influxdata/telegraf\"\n\n// Deprecations lists the deprecated plugins\nvar Deprecations = make(map[string]telegraf.DeprecationInfo)\n"
  },
  {
    "path": "plugins/aggregators/derivative/README.md",
    "content": "# Derivative Aggregator Plugin\n\nThis plugin computes the derivative for all fields of the aggregated metrics.\n\n⭐ Telegraf v1.18.0\n🏷️ math\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Calculates a derivative for every field.\n[[aggregators.derivative]]\n  ## The period in which to flush the aggregator.\n  # period = \"30s\"\n\n  ## Suffix to append for the resulting derivative field.\n  # suffix = \"_rate\"\n\n  ## Field to use for the quotient when computing the derivative.\n  ## When using a field as the derivation parameter the name of that field will\n  ## be used for the resulting derivative, e.g. *fieldname_by_parameter*.\n  ## By default the timestamps of the metrics are used and the suffix is omitted.\n  # variable = \"\"\n\n  ## Maximum number of roll-overs in case only one measurement is found during a period.\n  # max_roll_over = 10\n```\n\nThis aggregator will estimate a derivative for each field of a metric, which is\ncontained in both the first and last metric of the aggregation interval.\nWithout further configuration the derivative will be calculated with respect to\nthe time difference between these two measurements in seconds.\nThe following formula is applied is for every field\n\n```text\nderivative = (value_last - value_first) / (time_last - time_first)\n```\n\nThe resulting derivative will be named `<fieldname>_rate` if no `suffix` is\nconfigured.\n\nTo calculate a derivative for every field use\n\n```toml\n[[aggregators.derivative]]\n  ## Specific Derivative Aggregator Arguments:\n\n  ## Configure a custom derivation variable. Timestamp is used if none is given.\n  # variable = \"\"\n\n  ## Suffix to add to the field name for the derivative name.\n  # suffix = \"_rate\"\n\n  ## Roll-Over last measurement to first measurement of next period\n  # max_roll_over = 10\n\n  ## General Aggregator Arguments:\n\n  ## calculate derivative every 30 seconds\n  period = \"30s\"\n```\n\n## Time Derivatives\n\nIn its default configuration it determines the first and last measurement of\nthe period. From these measurements the time difference in seconds is\ncalculated. This time difference is than used to divide the difference of each\nfield using the following formula:\n\n```text\nderivative = (value_last - value_first) / (time_last - time_first)\n```\n\nFor each field the derivative is emitted with a naming pattern\n`<fieldname>_rate`.\n\n## Custom Derivation Variable\n\nThe plugin supports to use a field of the aggregated measurements as derivation\nvariable in the denominator. This variable is assumed to be a monotonically\nincreasing value. In this feature the following formula is used:\n\n```text\nderivative = (value_last - value_first) / (variable_last - variable_first)\n```\n\n**Make sure the specified variable is not filtered and exists in the metrics\npassed to this aggregator!**\n\nWhen using a custom derivation variable, you should change the `suffix` of the\nderivative name.  See the next section on [customizing the derivative\nname](#customize-the-derivative-name) for details.\n\n## Customize the Derivative Name\n\nThe derivatives generated by the aggregator are named `<fieldname>_rate`.\nThey are composed of the field name and a suffix `_rate`.\nYou can configure the suffix to be used by changing the `suffix` parameter.\n\n## Roll-Over to next Period\n\nCalculating the derivative for a period requires at least two distinct\nmeasurements during that period.  Whether those are available depends on the\nconfiguration of the aggregator `period` and the agent `interval`.  By default\nthe last measurement is used as first measurement in the next aggregation\nperiod. This enables a continuous calculation of the derivative. If within the\nnext period an earlier timestamp is encountered this measurement will replace\nthe roll-over metric. A main benefit of this roll-over is the ability to cope\nwith multiple \"quiet\" periods, where no new measurement is pushed to the\naggregator. The roll-over will take place at most `max_roll_over` times.\n\n### Example of Roll-Over\n\nLet us assume we have an input plugin, that generates a measurement with a\nsingle metric \"test\" every 2 seconds.  Let this metric increase the first 10\nseconds from 0.0 to 10.0 and then decrease the next 10 seconds form 10.0 to 0.0:\n\n| timestamp | value |\n|-----------|-------|\n|  0        |  0.0  |\n|  2        |  2.0  |\n|  4        |  4.0  |\n|  6        |  6.0  |\n|  8        |  8.0  |\n| 10        | 10.0  |\n| 12        |  8.0  |\n| 14        |  6.0  |\n| 16        |  4.0  |\n| 18        |  2.0  |\n| 20        |  0.0  |\n\nTo avoid thinking about border values, we consider periods to be inclusive at\nthe start but exclusive in the end.  Using `period = \"10s\"` and `max_roll_over =\n0` we would get the following aggregates:\n\n| timestamp | value | aggregate | explanation  |\n|-----------|-------|-----------|--------------|\n|  0        |  0.0  |           |              |\n|  2        |  2.0  |           |              |\n|  4        |  4.0  |           |              |\n|  6        |  6.0  |           |              |\n|  8        |  8.0  |           |              |\n|||  1.0      | (8.0 - 0.0) / (8 - 0) |\n| 10        | 10.0  |           |              |\n| 12        |  8.0  |           |              |\n| 14        |  6.0  |           |              |\n| 16        |  4.0  |           |              |\n| 18        |  2.0  |           |              |\n||| -1.0      | (2.0 - 10.0) / (18 - 10) |\n| 20        |  0.0  |           |              |\n\nIf we now decrease the period with `period = 2s`, no derivative could be\ncalculated since there would only one measurement for each period.  The\naggregator will emit the log messages `Same first and last event for \"test\",\nskipping.`.  This changes, if we use `max_roll_over = 1`, since now end\nmeasurements of a period are taking as start for the next period.\n\n| timestamp | value | aggregate | explanation |\n|-----------|-------|-----------|-------------|\n|  0        |  0.0  |           |             |\n|  2        |  2.0  |  1.0      | (2.0 - 0.0) / (2 - 0) |\n|  4        |  4.0  |  1.0      | (4.0 - 2.0) / (4 - 2) |\n|  6        |  6.0  |  1.0      | (6.0 - 4.0) / (6 - 4) |\n|  8        |  8.0  |  1.0      | (8.0 - 6.0) / (8 - 6) |\n| 10        | 10.0  |  1.0      | (10.0 - 8.0) / (10 - 8) |\n| 12        |  8.0  | -1.0      | (8.0 - 10.0) / (12 - 10) |\n| 14        |  6.0  | -1.0      | (6.0 - 8.0) / (14 - 12) |\n| 16        |  4.0  | -1.0      | (4.0 - 6.0) / (16 - 14) |\n| 18        |  2.0  | -1.0      | (2.0 - 4.0) / (18 - 16) |\n| 20        |  0.0  | -1.0      | (0.0 - 2.0) / (20 - 18) |\n\nThe default `max_roll_over = 10` allows for multiple periods without\nmeasurements either due to configuration or missing input.\n\nThere may be a slight difference in the calculation when using `max_roll_over`\ncompared to running without.  To illustrate this, let us compare the derivatives\nfor `period = \"7s\"`.\n\n| timestamp | value | `max_roll_over = 0` | explanation | `max_roll_over = 1` | explanation |\n|-----------|-------|---------------------|-------------|---------------------|-------------|\n|  0        |  0.0  |                     |             |                     |             |\n|  2        |  2.0  |                     |             |                     |             |\n|  4        |  4.0  |                     |             |                     |             |\n|  6        |  6.0  |                     |             |                     |             |\n|  7        |       | 0.8571... | (6-0) / (7-0) | 0.8571... | (6-0) / (7-0) |\n|  8        |  8.0  |                     |             |                     |             |\n| 10        | 10.0  |                     |             |                     |             |\n| 12        |  8.0  |                     |             |                     |             |\n| 14        |  8.0  | 0.0 | (8-8) / (14-7) | 0.2857... | (8-6) / (14-7) |\n| 16        |  4.0  |                     |             |                     |             |\n| 18        |  2.0  |                     |             |                     |             |\n| 20        |  0.0  |                     |             |                     |             |\n||| -1.0 | -1.0 | | |\n\nThe difference stems from the change of the value between periods, e.g. from 6.0\nto 8.0 between first and second period.  Those changes are omitted with\n`max_roll_over = 0` but are respected with `max_roll_over = 1`.  That there are\nno more differences in the calculated derivatives is due to the example data,\nwhich has constant derivatives in during the first and last period, even when\nincluding the gap between the periods.  Using `max_roll_over` with a value\ngreater 0 may be important, if you need to detect changes between periods,\ne.g. when you have very few measurements in a period or quasi-constant metrics\nwith only occasional changes.\n\n### Tags\n\nNo tags are applied by this aggregator.\nExisting tags are passed through the aggregator untouched.\n\n## Example Output\n\n```text\nnet bytes_recv=15409i,packets_recv=164i,bytes_sent=16649i,packets_sent=120i 1508843640000000000\nnet bytes_recv=73987i,packets_recv=364i,bytes_sent=87328i,packets_sent=452i 1508843660000000000\nnet bytes_recv_by_packets_recv=292.89 1508843660000000000\nnet packets_sent_rate=16.6,bytes_sent_rate=3533.95 1508843660000000000\nnet bytes_sent_by_packet=292.89 1508843660000000000\n```\n"
  },
  {
    "path": "plugins/aggregators/derivative/derivative.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage derivative\n\nimport (\n\t_ \"embed\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultSuffix = \"_rate\"\n\ntype Derivative struct {\n\tVariable    string          `toml:\"variable\"`\n\tSuffix      string          `toml:\"suffix\"`\n\tMaxRollOver uint            `toml:\"max_roll_over\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\tcache       map[uint64]*aggregate\n}\n\ntype aggregate struct {\n\tfirst    *event\n\tlast     *event\n\tname     string\n\ttags     map[string]string\n\trollOver uint\n}\n\ntype event struct {\n\tfields map[string]float64\n\ttime   time.Time\n}\n\nfunc (d *Derivative) Init() error {\n\td.Suffix = strings.TrimSpace(d.Suffix)\n\td.Variable = strings.TrimSpace(d.Variable)\n\treturn nil\n}\n\nfunc (*Derivative) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *Derivative) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\tcurrent, ok := d.cache[id]\n\tif !ok {\n\t\t// hit an uncached metric, create caches for first time:\n\t\td.cache[id] = newAggregate(in)\n\t\treturn\n\t}\n\tif current.first.time.After(in.Time()) {\n\t\tcurrent.first = newEvent(in)\n\t\tcurrent.rollOver = 0\n\t} else if current.first.time.Equal(in.Time()) {\n\t\tupsertConvertedFields(in.Fields(), current.first.fields)\n\t\tcurrent.rollOver = 0\n\t}\n\tif current.last.time.Before(in.Time()) {\n\t\tcurrent.last = newEvent(in)\n\t\tcurrent.rollOver = 0\n\t} else if current.last.time.Equal(in.Time()) {\n\t\tupsertConvertedFields(in.Fields(), current.last.fields)\n\t\tcurrent.rollOver = 0\n\t}\n}\n\nfunc (d *Derivative) Push(acc telegraf.Accumulator) {\n\tfor _, aggregate := range d.cache {\n\t\tif aggregate.first == aggregate.last {\n\t\t\td.Log.Debugf(\"Same first and last event for %q, skipping.\", aggregate.name)\n\t\t\tcontinue\n\t\t}\n\t\tvar denominator float64\n\t\tdenominator = aggregate.last.time.Sub(aggregate.first.time).Seconds()\n\t\tif len(d.Variable) > 0 {\n\t\t\tvar first float64\n\t\t\tvar last float64\n\t\t\tvar found bool\n\t\t\tif first, found = aggregate.first.fields[d.Variable]; !found {\n\t\t\t\td.Log.Debugf(\"Did not find %q in first event for %q.\", d.Variable, aggregate.name)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif last, found = aggregate.last.fields[d.Variable]; !found {\n\t\t\t\td.Log.Debugf(\"Did not find %q in last event for %q.\", d.Variable, aggregate.name)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdenominator = last - first\n\t\t}\n\t\tif denominator == 0 {\n\t\t\td.Log.Debugf(\"Got difference 0 in denominator for %q, skipping.\", aggregate.name)\n\t\t\tcontinue\n\t\t}\n\t\tderivatives := make(map[string]interface{})\n\t\tfor key, start := range aggregate.first.fields {\n\t\t\tif key == d.Variable {\n\t\t\t\t// Skip derivation variable\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif end, ok := aggregate.last.fields[key]; ok {\n\t\t\t\td.Log.Debugf(\"Adding derivative %q to %q.\", key+d.Suffix, aggregate.name)\n\t\t\t\tderivatives[key+d.Suffix] = (end - start) / denominator\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(aggregate.name, derivatives, aggregate.tags)\n\t}\n}\n\nfunc (d *Derivative) Reset() {\n\tfor id, aggregate := range d.cache {\n\t\tif aggregate.rollOver < d.MaxRollOver {\n\t\t\taggregate.first = aggregate.last\n\t\t\taggregate.rollOver = aggregate.rollOver + 1\n\t\t\td.cache[id] = aggregate\n\t\t\td.Log.Debugf(\"Roll-Over %q for the %d time.\", aggregate.name, aggregate.rollOver)\n\t\t} else {\n\t\t\tdelete(d.cache, id)\n\t\t\td.Log.Debugf(\"Removed %q from cache.\", aggregate.name)\n\t\t}\n\t}\n}\n\nfunc newAggregate(in telegraf.Metric) *aggregate {\n\tevent := newEvent(in)\n\treturn &aggregate{\n\t\tname:     in.Name(),\n\t\ttags:     in.Tags(),\n\t\tfirst:    event,\n\t\tlast:     event,\n\t\trollOver: 0,\n\t}\n}\n\nfunc newEvent(in telegraf.Metric) *event {\n\treturn &event{\n\t\tfields: extractConvertedFields(in),\n\t\ttime:   in.Time(),\n\t}\n}\n\nfunc extractConvertedFields(in telegraf.Metric) map[string]float64 {\n\tfields := make(map[string]float64, len(in.Fields()))\n\tupsertConvertedFields(in.Fields(), fields)\n\treturn fields\n}\n\nfunc upsertConvertedFields(source map[string]interface{}, target map[string]float64) {\n\tfor k, v := range source {\n\t\tif value, ok := convert(v); ok {\n\t\t\ttarget[k] = value\n\t\t}\n\t}\n}\n\nfunc convert(in interface{}) (float64, bool) {\n\tswitch v := in.(type) {\n\tcase float64:\n\t\treturn v, true\n\tcase int64:\n\t\treturn float64(v), true\n\tcase uint64:\n\t\treturn float64(v), true\n\t}\n\treturn 0, false\n}\n\nfunc newDerivative() *Derivative {\n\tderivative := &Derivative{Suffix: defaultSuffix, MaxRollOver: 10}\n\tderivative.cache = make(map[uint64]*aggregate)\n\tderivative.Reset()\n\treturn derivative\n}\n\nfunc init() {\n\taggregators.Add(\"derivative\", func() telegraf.Aggregator {\n\t\treturn newDerivative()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/derivative/derivative_test.go",
    "content": "package derivative\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar start = metric.New(\"TestMetric\",\n\tmap[string]string{\"state\": \"full\"},\n\tmap[string]interface{}{\n\t\t\"increasing\": int64(0),\n\t\t\"decreasing\": int64(100),\n\t\t\"unchanged\":  int64(42),\n\t\t\"ignored\":    \"strings are not supported\",\n\t\t\"parameter\":  float64(0.0),\n\t},\n\ttime.Now(),\n)\n\nvar finish = metric.New(\"TestMetric\",\n\tmap[string]string{\"state\": \"full\"},\n\tmap[string]interface{}{\n\t\t\"increasing\": int64(1000),\n\t\t\"decreasing\": int64(0),\n\t\t\"unchanged\":  int64(42),\n\t\t\"ignored\":    \"strings are not supported\",\n\t\t\"parameter\":  float64(10.0),\n\t},\n\ttime.Now().Add(time.Second),\n)\n\nfunc TestTwoFullEventsWithParameter(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable: \"parameter\",\n\t\tSuffix:   \"_by_parameter\",\n\t\tcache:    make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_by_parameter\": 100.0,\n\t\t\"decreasing_by_parameter\": -10.0,\n\t\t\"unchanged_by_parameter\":  0.0,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"state\": \"full\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"TestMetric\", expectedFields, expectedTags)\n}\n\nfunc TestTwoFullEventsWithParameterReverseSequence(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable: \"parameter\",\n\t\tSuffix:   \"_by_parameter\",\n\t\tcache:    make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(finish)\n\tderivative.Add(start)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_by_parameter\": 100.0,\n\t\t\"decreasing_by_parameter\": -10.0,\n\t\t\"unchanged_by_parameter\":  0.0,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"state\": \"full\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"TestMetric\", expectedFields, expectedTags)\n}\n\nfunc TestTwoFullEventsWithoutParameter(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := newDerivative()\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tstartTime := time.Now()\n\tduration, err := time.ParseDuration(\"2s\")\n\trequire.NoError(t, err)\n\tendTime := startTime.Add(duration)\n\n\tfirst := metric.New(\"One Field\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(10),\n\t\t},\n\t\tstartTime,\n\t)\n\tlast := metric.New(\"One Field\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(20),\n\t\t},\n\t\tendTime,\n\t)\n\n\tderivative.Add(first)\n\tderivative.Add(last)\n\tderivative.Push(&acc)\n\n\tacc.AssertContainsFields(t,\n\t\t\"One Field\",\n\t\tmap[string]interface{}{\n\t\t\t\"value_rate\": float64(5),\n\t\t},\n\t)\n}\n\nfunc TestTwoFullEventsInSeparatePushes(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable:    \" parameter\",\n\t\tSuffix:      \"_wrt_parameter\",\n\t\tMaxRollOver: 10,\n\t\tcache:       make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\tderivative.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n\n\tacc.ClearMetrics()\n\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_wrt_parameter\": 100.0,\n\t\t\"decreasing_wrt_parameter\": -10.0,\n\t\t\"unchanged_wrt_parameter\":  0.0,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"state\": \"full\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"TestMetric\", expectedFields, expectedTags)\n}\n\nfunc TestTwoFullEventsInSeparatePushesWithSeveralRollOvers(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable:    \"parameter\",\n\t\tSuffix:      \"_wrt_parameter\",\n\t\tMaxRollOver: 10,\n\t\tcache:       make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\tderivative.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n\n\tderivative.Push(&acc)\n\tderivative.Push(&acc)\n\tderivative.Push(&acc)\n\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_wrt_parameter\": 100.0,\n\t\t\"decreasing_wrt_parameter\": -10.0,\n\t\t\"unchanged_wrt_parameter\":  0.0,\n\t}\n\n\tacc.AssertContainsFields(t, \"TestMetric\", expectedFields)\n}\n\nfunc TestTwoFullEventsInSeparatePushesWithOutRollOver(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable:    \"parameter\",\n\t\tSuffix:      \"_by_parameter\",\n\t\tMaxRollOver: 0,\n\t\tcache:       make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\t// This test relies on RunningAggregator always callining Reset after Push\n\t// to remove the first metric after max-rollover of 0 has been reached.\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n\n\tacc.ClearMetrics()\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n}\n\nfunc TestIgnoresMissingVariable(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable: \"parameter\",\n\t\tSuffix:   \"_by_parameter\",\n\t\tcache:    make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tnoParameter := metric.New(\"TestMetric\",\n\t\tmap[string]string{\"state\": \"no_parameter\"},\n\t\tmap[string]interface{}{\n\t\t\t\"increasing\": int64(100),\n\t\t\t\"decreasing\": int64(0),\n\t\t\t\"unchanged\":  int64(42),\n\t\t},\n\t\ttime.Now(),\n\t)\n\n\tderivative.Add(noParameter)\n\tderivative.Push(&acc)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n\n\tacc.ClearMetrics()\n\tderivative.Add(noParameter)\n\tderivative.Add(start)\n\tderivative.Add(noParameter)\n\tderivative.Add(finish)\n\tderivative.Add(noParameter)\n\tderivative.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_by_parameter\": 100.0,\n\t\t\"decreasing_by_parameter\": -10.0,\n\t\t\"unchanged_by_parameter\":  0.0,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"state\": \"full\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"TestMetric\", expectedFields, expectedTags)\n}\n\nfunc TestMergesDifferentMetricsWithSameHash(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := newDerivative()\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tstartTime := time.Now()\n\tduration, err := time.ParseDuration(\"2s\")\n\trequire.NoError(t, err)\n\tendTime := startTime.Add(duration)\n\tpart1 := metric.New(\"TestMetric\",\n\t\tmap[string]string{\"state\": \"full\"},\n\t\tmap[string]interface{}{\"field1\": int64(10)},\n\t\tstartTime,\n\t)\n\tpart2 := metric.New(\"TestMetric\",\n\t\tmap[string]string{\"state\": \"full\"},\n\t\tmap[string]interface{}{\"field2\": int64(20)},\n\t\tstartTime,\n\t)\n\tfinal := metric.New(\"TestMetric\",\n\t\tmap[string]string{\"state\": \"full\"},\n\t\tmap[string]interface{}{\n\t\t\t\"field1\": int64(30),\n\t\t\t\"field2\": int64(30),\n\t\t},\n\t\tendTime,\n\t)\n\n\tderivative.Add(part1)\n\tderivative.Push(&acc)\n\tderivative.Add(part2)\n\tderivative.Push(&acc)\n\tderivative.Add(final)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"field1_rate\": 10.0,\n\t\t\"field2_rate\": 5.0,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"state\": \"full\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"TestMetric\", expectedFields, expectedTags)\n}\n\nfunc TestDropsAggregatesOnMaxRollOver(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tMaxRollOver: 1,\n\t\tcache:       make(map[uint64]*aggregate),\n\t}\n\tderivative.Log = testutil.Logger{}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\n\tacc.AssertDoesNotContainMeasurement(t, \"TestMetric\")\n}\n\nfunc TestAddMetricsResetsRollOver(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tderivative := &Derivative{\n\t\tVariable:    \"parameter\",\n\t\tSuffix:      \"_by_parameter\",\n\t\tMaxRollOver: 1,\n\t\tcache:       make(map[uint64]*aggregate),\n\t\tLog:         testutil.Logger{},\n\t}\n\terr := derivative.Init()\n\trequire.NoError(t, err)\n\n\tderivative.Add(start)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\tderivative.Add(start)\n\tderivative.Reset()\n\tderivative.Add(finish)\n\tderivative.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"increasing_by_parameter\": 100.0,\n\t\t\"decreasing_by_parameter\": -10.0,\n\t\t\"unchanged_by_parameter\":  0.0,\n\t}\n\n\tacc.AssertContainsFields(t, \"TestMetric\", expectedFields)\n}\n\nfunc TestCalculatesCorrectDerivativeOnTwoConsecutivePeriods(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tperiod, err := time.ParseDuration(\"10s\")\n\trequire.NoError(t, err)\n\tderivative := newDerivative()\n\tderivative.Log = testutil.Logger{}\n\trequire.NoError(t, derivative.Init())\n\n\tstartTime := time.Now()\n\tfirst := metric.New(\"One Field\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(10),\n\t\t},\n\t\tstartTime,\n\t)\n\tderivative.Add(first)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\n\tsecond := metric.New(\"One Field\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(20),\n\t\t},\n\t\tstartTime.Add(period),\n\t)\n\tderivative.Add(second)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\n\tacc.AssertContainsFields(t, \"One Field\", map[string]interface{}{\n\t\t\"value_rate\": 1.0,\n\t})\n\n\tacc.ClearMetrics()\n\tthird := metric.New(\"One Field\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"value\": int64(40),\n\t\t},\n\t\tstartTime.Add(period).Add(period),\n\t)\n\tderivative.Add(third)\n\tderivative.Push(&acc)\n\tderivative.Reset()\n\n\tacc.AssertContainsFields(t, \"One Field\", map[string]interface{}{\n\t\t\"value_rate\": 2.0,\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/derivative/sample.conf",
    "content": "# Calculates a derivative for every field.\n[[aggregators.derivative]]\n  ## The period in which to flush the aggregator.\n  # period = \"30s\"\n\n  ## Suffix to append for the resulting derivative field.\n  # suffix = \"_rate\"\n\n  ## Field to use for the quotient when computing the derivative.\n  ## When using a field as the derivation parameter the name of that field will\n  ## be used for the resulting derivative, e.g. *fieldname_by_parameter*.\n  ## By default the timestamps of the metrics are used and the suffix is omitted.\n  # variable = \"\"\n\n  ## Maximum number of roll-overs in case only one measurement is found during a period.\n  # max_roll_over = 10\n"
  },
  {
    "path": "plugins/aggregators/final/README.md",
    "content": "# Final Aggregator Plugin\n\nThis plugin emits the last metric of a contiguous series, defined as a\nseries which receives updates within the time period in `series_timeout`. The\ncontiguous series may be longer than the time interval defined by `period`.\nWhen a series has not been updated within the `series_timeout`, the last metric\nis emitted.\n\nAlternatively, the plugin emits the last metric in the `period` for the\n`periodic` output strategy.\n\nThis is useful for getting the final value for data sources that produce\ndiscrete time series such as procstat, cgroup, kubernetes etc. or to downsample\nmetrics collected at a higher frequency.\n\n> [!NOTE]\n> All emited metrics do have fields with `_final` appended to the field-name\n> by default.\n\n⭐ Telegraf v1.11.0\n🏷️ sampling\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Report the final metric of a series\n[[aggregators.final]]\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## If false, _final is added to every field name\n  # keep_original_field_names = false\n\n  ## The time that a series is not updated until considering it final. Ignored\n  ## when output_strategy is \"periodic\".\n  # series_timeout = \"5m\"\n\n  ## Output strategy, supported values:\n  ##   timeout  -- output a metric if no new input arrived for `series_timeout`\n  ##   periodic -- output the last received metric every `period`\n  # output_strategy = \"timeout\"\n```\n\n### Output strategy\n\nBy default (`output_strategy = \"timeout\"`) the plugin will only emit a metric\nfor the period if the last received one is older than the series_timeout. This\nwill not guarantee a regular output of a `final` metric e.g. if the\nseries-timeout is a multiple of the gathering interval for an input. In this\ncase metric sporadically arrive in the timeout phase of the period and emitting\nthe `final` metric is suppressed.\n\nContrary to this, `output_strategy = \"periodic\"` will always output a `final`\nmetric at the end of the period irrespectively of when the last metric arrived,\nthe `series_timeout` is ignored.\n\n## Metrics\n\nMeasurement and tags are unchanged, fields are emitted with the suffix\n`_final`.\n\n## Example Output\n\n```text\ncounter,host=bar i_final=3,j_final=6 1554281635115090133\ncounter,host=foo i_final=3,j_final=6 1554281635112992012\n```\n\nOriginal input:\n\n```text\ncounter,host=bar i=1,j=4 1554281633101153300\ncounter,host=foo i=1,j=4 1554281633099323601\ncounter,host=bar i=2,j=5 1554281634107980073\ncounter,host=foo i=2,j=5 1554281634105931116\ncounter,host=bar i=3,j=6 1554281635115090133\ncounter,host=foo i=3,j=6 1554281635112992012\n```\n"
  },
  {
    "path": "plugins/aggregators/final/final.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage final\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Final struct {\n\tOutputStrategy         string          `toml:\"output_strategy\"`\n\tSeriesTimeout          config.Duration `toml:\"series_timeout\"`\n\tKeepOriginalFieldNames bool            `toml:\"keep_original_field_names\"`\n\n\t// The last metric for all series which are active\n\tmetricCache map[uint64]telegraf.Metric\n}\n\nfunc (*Final) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Final) Init() error {\n\t// Check options and set defaults\n\tswitch m.OutputStrategy {\n\tcase \"\":\n\t\tm.OutputStrategy = \"timeout\"\n\tcase \"timeout\", \"periodic\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'output_strategy': %q\", m.OutputStrategy)\n\t}\n\n\t// Initialize the cache\n\tm.metricCache = make(map[uint64]telegraf.Metric)\n\n\treturn nil\n}\n\nfunc (m *Final) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\tm.metricCache[id] = in\n}\n\nfunc (m *Final) Push(acc telegraf.Accumulator) {\n\t// Preserve timestamp of original metric\n\tacc.SetPrecision(time.Nanosecond)\n\n\tfor id, metric := range m.metricCache {\n\t\tif m.OutputStrategy == \"timeout\" && time.Since(metric.Time()) <= time.Duration(m.SeriesTimeout) {\n\t\t\t// We output on timeout but the last metric of the series was\n\t\t\t// younger than that. So skip the output for this period.\n\t\t\tcontinue\n\t\t}\n\t\tvar fields map[string]any\n\t\tif m.KeepOriginalFieldNames {\n\t\t\tfields = metric.Fields()\n\t\t} else {\n\t\t\tfields = make(map[string]any, len(metric.FieldList()))\n\t\t\tfor _, field := range metric.FieldList() {\n\t\t\t\tfields[field.Key+\"_final\"] = field.Value\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(metric.Name(), fields, metric.Tags(), metric.Time())\n\t\tdelete(m.metricCache, id)\n\t}\n}\n\nfunc (*Final) Reset() {\n}\n\nfunc newFinal() *Final {\n\treturn &Final{\n\t\tSeriesTimeout: config.Duration(5 * time.Minute),\n\t}\n}\n\nfunc init() {\n\taggregators.Add(\"final\", func() telegraf.Aggregator {\n\t\treturn newFinal()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/final/final_test.go",
    "content": "package final\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSimple(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tfinal := newFinal()\n\trequire.NoError(t, final.Init())\n\n\ttags := map[string]string{\"foo\": \"bar\"}\n\tm1 := metric.New(\"m1\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(1)},\n\t\ttime.Unix(1530939936, 0))\n\tm2 := metric.New(\"m1\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(2)},\n\t\ttime.Unix(1530939937, 0))\n\tm3 := metric.New(\"m1\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(3)},\n\t\ttime.Unix(1530939938, 0))\n\tfinal.Add(m1)\n\tfinal.Add(m2)\n\tfinal.Add(m3)\n\tfinal.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m1\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 3,\n\t\t\t},\n\t\t\ttime.Unix(1530939938, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestTwoTags(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tfinal := newFinal()\n\trequire.NoError(t, final.Init())\n\n\ttags1 := map[string]string{\"foo\": \"bar\"}\n\ttags2 := map[string]string{\"foo\": \"baz\"}\n\n\tm1 := metric.New(\"m1\",\n\t\ttags1,\n\t\tmap[string]interface{}{\"a\": int64(1)},\n\t\ttime.Unix(1530939936, 0))\n\tm2 := metric.New(\"m1\",\n\t\ttags2,\n\t\tmap[string]interface{}{\"a\": int64(2)},\n\t\ttime.Unix(1530939937, 0))\n\tm3 := metric.New(\"m1\",\n\t\ttags1,\n\t\tmap[string]interface{}{\"a\": int64(3)},\n\t\ttime.Unix(1530939938, 0))\n\tfinal.Add(m1)\n\tfinal.Add(m2)\n\tfinal.Add(m3)\n\tfinal.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m1\",\n\t\t\ttags2,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 2,\n\t\t\t},\n\t\t\ttime.Unix(1530939937, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"m1\",\n\t\t\ttags1,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 3,\n\t\t\t},\n\t\t\ttime.Unix(1530939938, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.SortMetrics())\n}\n\nfunc TestLongDifference(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tfinal := newFinal()\n\tfinal.SeriesTimeout = config.Duration(30 * time.Second)\n\trequire.NoError(t, final.Init())\n\ttags := map[string]string{\"foo\": \"bar\"}\n\n\tnow := time.Now()\n\n\tm1 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(1)},\n\t\tnow.Add(time.Second*-290))\n\tm2 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(2)},\n\t\tnow.Add(time.Second*-275))\n\tm3 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(3)},\n\t\tnow.Add(time.Second*-100))\n\tm4 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(4)},\n\t\tnow.Add(time.Second*-20))\n\tfinal.Add(m1)\n\tfinal.Add(m2)\n\tfinal.Push(&acc)\n\tfinal.Add(m3)\n\tfinal.Push(&acc)\n\tfinal.Add(m4)\n\tfinal.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 2,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-275),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 3,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-100),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.SortMetrics())\n}\n\nfunc TestOutputStrategyInvalid(t *testing.T) {\n\tfinal := &Final{\n\t\tOutputStrategy: \"no way\",\n\t\tSeriesTimeout:  config.Duration(30 * time.Second),\n\t}\n\trequire.ErrorContains(t, final.Init(), `invalid 'output_strategy'`)\n}\n\nfunc TestOutputStrategyTimeout(t *testing.T) {\n\tfinal := &Final{\n\t\tOutputStrategy: \"timeout\",\n\t\tSeriesTimeout:  config.Duration(30 * time.Second),\n\t}\n\trequire.NoError(t, final.Init())\n\n\tnow := time.Now()\n\ttags := map[string]string{\"foo\": \"bar\"}\n\tm1 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(1)},\n\t\tnow.Add(time.Second*-290))\n\tm2 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(2)},\n\t\tnow.Add(time.Second*-275))\n\tm3 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(3)},\n\t\tnow.Add(time.Second*-100))\n\tm4 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(4)},\n\t\tnow.Add(time.Second*-20))\n\n\tvar acc testutil.Accumulator\n\tfinal.Add(m1)\n\tfinal.Add(m2)\n\tfinal.Push(&acc)\n\tfinal.Add(m3)\n\tfinal.Push(&acc)\n\tfinal.Add(m4)\n\tfinal.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 2,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-275),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 3,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-100),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.SortMetrics())\n}\n\nfunc TestOutputStrategyPeriodic(t *testing.T) {\n\tfinal := &Final{\n\t\tOutputStrategy: \"periodic\",\n\t\tSeriesTimeout:  config.Duration(30 * time.Second),\n\t}\n\trequire.NoError(t, final.Init())\n\n\tnow := time.Now()\n\ttags := map[string]string{\"foo\": \"bar\"}\n\tm1 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(1)},\n\t\tnow.Add(time.Second*-290))\n\tm2 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(2)},\n\t\tnow.Add(time.Second*-275))\n\tm3 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(3)},\n\t\tnow.Add(time.Second*-100))\n\tm4 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]interface{}{\"a\": int64(4)},\n\t\tnow.Add(time.Second*-20))\n\n\tvar acc testutil.Accumulator\n\tfinal.Add(m1)\n\tfinal.Add(m2)\n\tfinal.Push(&acc)\n\tfinal.Add(m3)\n\tfinal.Push(&acc)\n\tfinal.Add(m4)\n\tfinal.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 2,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-275),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 3,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-100),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_final\": 4,\n\t\t\t},\n\t\t\tnow.Add(time.Second*-20),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.SortMetrics())\n}\n\nfunc TestKeepOriginalFieldNames(t *testing.T) {\n\tfinal := &Final{\n\t\tOutputStrategy:         \"periodic\",\n\t\tSeriesTimeout:          config.Duration(30 * time.Second),\n\t\tKeepOriginalFieldNames: true,\n\t}\n\n\trequire.NoError(t, final.Init())\n\n\tnow := time.Now()\n\ttags := map[string]string{\"foo\": \"bar\"}\n\tm1 := metric.New(\"m\",\n\t\ttags,\n\t\tmap[string]any{\"a\": 3},\n\t\tnow.Add(time.Second*-90))\n\n\tvar acc testutil.Accumulator\n\tfinal.Add(m1)\n\tfinal.Push(&acc)\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"m\",\n\t\t\ttags,\n\t\t\tmap[string]any{\"a\": 3},\n\t\t\tnow.Add(time.Second*-90),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.SortMetrics())\n}\n"
  },
  {
    "path": "plugins/aggregators/final/sample.conf",
    "content": "# Report the final metric of a series\n[[aggregators.final]]\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## If false, _final is added to every field name\n  # keep_original_field_names = false\n\n  ## The time that a series is not updated until considering it final. Ignored\n  ## when output_strategy is \"periodic\".\n  # series_timeout = \"5m\"\n\n  ## Output strategy, supported values:\n  ##   timeout  -- output a metric if no new input arrived for `series_timeout`\n  ##   periodic -- output the last received metric every `period`\n  # output_strategy = \"timeout\"\n"
  },
  {
    "path": "plugins/aggregators/histogram/README.md",
    "content": "# Histogram Aggregator Plugin\n\nThis plugin creates histograms containing the counts of field values within the\nconfigured range. The histogram metric is emitted every `period`.\n\nIn `cumulative` mode, values added to a bucket are also added to the\nconsecutive buckets in the distribution creating a [cumulative histogram][1].\n\n> [!NOTE]\n> By default bucket counts are not reset between periods and will be\n> non-strictly increasing while Telegraf is running. This behavior can be\n> by setting the `reset` parameter.\n\n⭐ Telegraf v1.4.0\n🏷️ statistics\n💻 all\n\n[1]: https://en.wikipedia.org/wiki/Histogram#/media/File:Cumulative_vs_normal_histogram.svg\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Configuration for aggregate histogram metrics\n[[aggregators.histogram]]\n  ## The period in which to flush the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## If true, the histogram will be reset on flush instead\n  ## of accumulating the results.\n  reset = false\n\n  ## Whether bucket values should be accumulated. If set to false, \"gt\" tag will be added.\n  ## Defaults to true.\n  cumulative = true\n\n  ## Expiration interval for each histogram. The histogram will be expired if\n  ## there are no changes in any buckets for this time interval. 0 == no expiration.\n  # expiration_interval = \"0m\"\n\n  ## If true, aggregated histogram are pushed to output only if it was updated since\n  ## previous push. Defaults to false.\n  # push_only_on_update = false\n\n  ## Example config that aggregates all fields of the metric.\n  # [[aggregators.histogram.config]]\n  #   ## Right borders of buckets (with +Inf implicitly added).\n  #   buckets = [0.0, 15.6, 34.5, 49.1, 71.5, 80.5, 94.5, 100.0]\n  #   ## The name of metric.\n  #   measurement_name = \"cpu\"\n\n  ## Example config that aggregates only specific fields of the metric.\n  # [[aggregators.histogram.config]]\n  #   ## Right borders of buckets (with +Inf implicitly added).\n  #   buckets = [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]\n  #   ## The name of metric.\n  #   measurement_name = \"diskio\"\n  #   ## The concrete fields of metric\n  #   fields = [\"io_time\", \"read_time\", \"write_time\"]\n```\n\nThe user is responsible for defining the bounds of the histogram bucket as\nwell as the measurement name and fields to aggregate.\n\nEach histogram config section must contain a `buckets` and `measurement_name`\noption.  Optionally, if `fields` is set only the fields listed will be\naggregated.  If `fields` is not set all fields are aggregated.\n\nThe `buckets` option contains a list of floats which specify the bucket\nboundaries.  Each float value defines the inclusive upper (right) bound of the\nbucket.  The `+Inf` bucket is added automatically and does not need to be\ndefined.  (For left boundaries, these specified bucket borders and `-Inf` will\nbe used).\n\n## Measurements & Fields\n\nThe postfix `bucket` will be added to each field key.\n\n- measurement1\n  - field1_bucket\n  - field2_bucket\n\n### Tags\n\n- `cumulative = true` (default):\n  - `le`: Right bucket border. It means that the metric value is less than or\n    equal to the value of this tag. If a metric value is sorted into a bucket,\n    it is also sorted into all larger buckets. As a result, the value of\n    `<field>_bucket` is rising with rising `le` value. When `le` is `+Inf`,\n    the bucket value is the count of all metrics, because all metric values are\n    less than or equal to positive infinity.\n- `cumulative = false`:\n  - `gt`: Left bucket border. It means that the metric value is greater than\n    (and not equal to) the value of this tag.\n  - `le`: Right bucket border. It means that the metric value is less than or\n    equal to the value of this tag.\n  - As both `gt` and `le` are present, each metric is sorted in only exactly\n    one bucket.\n\n## Example Output\n\nLet assume we have the buckets [0, 10, 50, 100] and the following field values\nfor `usage_idle`: [50, 7, 99, 12]\n\nWith `cumulative = true`:\n\n```text\ncpu,cpu=cpu1,host=localhost,le=0.0 usage_idle_bucket=0i 1486998330000000000  # none\ncpu,cpu=cpu1,host=localhost,le=10.0 usage_idle_bucket=1i 1486998330000000000  # 7\ncpu,cpu=cpu1,host=localhost,le=50.0 usage_idle_bucket=2i 1486998330000000000  # 7, 12\ncpu,cpu=cpu1,host=localhost,le=100.0 usage_idle_bucket=4i 1486998330000000000  # 7, 12, 50, 99\ncpu,cpu=cpu1,host=localhost,le=+Inf usage_idle_bucket=4i 1486998330000000000  # 7, 12, 50, 99\n```\n\nWith `cumulative = false`:\n\n```text\ncpu,cpu=cpu1,host=localhost,gt=-Inf,le=0.0 usage_idle_bucket=0i 1486998330000000000  # none\ncpu,cpu=cpu1,host=localhost,gt=0.0,le=10.0 usage_idle_bucket=1i 1486998330000000000  # 7\ncpu,cpu=cpu1,host=localhost,gt=10.0,le=50.0 usage_idle_bucket=1i 1486998330000000000  # 12\ncpu,cpu=cpu1,host=localhost,gt=50.0,le=100.0 usage_idle_bucket=2i 1486998330000000000  # 50, 99\ncpu,cpu=cpu1,host=localhost,gt=100.0,le=+Inf usage_idle_bucket=0i 1486998330000000000  # none\n```\n"
  },
  {
    "path": "plugins/aggregators/histogram/histogram.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage histogram\n\nimport (\n\t_ \"embed\"\n\t\"sort\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar timeNow = time.Now\n\nconst (\n\t// bucketRightTag is the tag, which contains right bucket border\n\tbucketRightTag = \"le\"\n\t// bucketPosInf is the right bucket border for infinite values\n\tbucketPosInf = \"+Inf\"\n\t// bucketLeftTag is the tag, which contains left bucket border (exclusive)\n\tbucketLeftTag = \"gt\"\n\t// bucketNegInf is the left bucket border for infinite values\n\tbucketNegInf = \"-Inf\"\n)\n\ntype Histogram struct {\n\tConfigs            []bucketConfig  `toml:\"config\"`\n\tResetBuckets       bool            `toml:\"reset\"`\n\tCumulative         bool            `toml:\"cumulative\"`\n\tExpirationInterval config.Duration `toml:\"expiration_interval\"`\n\tPushOnlyOnUpdate   bool            `toml:\"push_only_on_update\"`\n\n\tbuckets bucketsByMetrics\n\tcache   map[uint64]metricHistogramCollection\n}\n\n// bucketConfig is the config, which contains name, field of metric and histogram buckets.\ntype bucketConfig struct {\n\tMetric  string   `toml:\"measurement_name\"`\n\tFields  []string `toml:\"fields\"`\n\tBuckets buckets  `toml:\"buckets\"`\n}\n\n// bucketsByMetrics contains the buckets grouped by metric and field name\ntype bucketsByMetrics map[string]bucketsByFields\n\n// bucketsByFields contains the buckets grouped by field name\ntype bucketsByFields map[string]buckets\n\n// buckets contains the right borders buckets\ntype buckets []float64\n\n// metricHistogramCollection aggregates the histogram data\ntype metricHistogramCollection struct {\n\thistogramCollection map[string]counts\n\tname                string\n\ttags                map[string]string\n\texpireTime          time.Time\n\tupdated             bool\n}\n\n// counts is the number of hits in the bucket\ntype counts []int64\n\n// groupedByCountFields contains grouped fields by their count and fields values\ntype groupedByCountFields struct {\n\tname            string\n\ttags            map[string]string\n\tfieldsWithCount map[string]int64\n}\n\nfunc (*Histogram) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *Histogram) Add(in telegraf.Metric) {\n\taddTime := timeNow()\n\n\tbucketsByField := make(map[string][]float64)\n\tfor field := range in.Fields() {\n\t\tbuckets := h.getBuckets(in.Name(), field)\n\t\tif buckets != nil {\n\t\t\tbucketsByField[field] = buckets\n\t\t}\n\t}\n\n\tif len(bucketsByField) == 0 {\n\t\treturn\n\t}\n\n\tid := in.HashID()\n\tagr, ok := h.cache[id]\n\tif !ok {\n\t\tagr = metricHistogramCollection{\n\t\t\tname:                in.Name(),\n\t\t\ttags:                in.Tags(),\n\t\t\thistogramCollection: make(map[string]counts),\n\t\t}\n\t}\n\n\tfor field, value := range in.Fields() {\n\t\tif buckets, ok := bucketsByField[field]; ok {\n\t\t\tif agr.histogramCollection[field] == nil {\n\t\t\t\tagr.histogramCollection[field] = make(counts, len(buckets)+1)\n\t\t\t}\n\n\t\t\tif value, ok := convert(value); ok {\n\t\t\t\tindex := sort.SearchFloat64s(buckets, value)\n\t\t\t\tagr.histogramCollection[field][index]++\n\t\t\t}\n\t\t\tif h.ExpirationInterval != 0 {\n\t\t\t\tagr.expireTime = addTime.Add(time.Duration(h.ExpirationInterval))\n\t\t\t}\n\t\t\tagr.updated = true\n\t\t}\n\t}\n\n\th.cache[id] = agr\n}\n\nfunc (h *Histogram) Push(acc telegraf.Accumulator) {\n\tnow := timeNow()\n\tmetricsWithGroupedFields := make([]groupedByCountFields, 0)\n\tfor id, aggregate := range h.cache {\n\t\tif h.ExpirationInterval != 0 && now.After(aggregate.expireTime) {\n\t\t\tdelete(h.cache, id)\n\t\t\tcontinue\n\t\t}\n\t\tif h.PushOnlyOnUpdate && !h.cache[id].updated {\n\t\t\tcontinue\n\t\t}\n\t\taggregate.updated = false\n\t\th.cache[id] = aggregate\n\t\tfor field, counts := range aggregate.histogramCollection {\n\t\t\th.groupFieldsByBuckets(&metricsWithGroupedFields, aggregate.name, field, copyTags(aggregate.tags), counts)\n\t\t}\n\t}\n\n\tfor _, metric := range metricsWithGroupedFields {\n\t\tacc.AddFields(metric.name, makeFieldsWithCount(metric.fieldsWithCount), metric.tags)\n\t}\n}\n\n// Reset does nothing by default, because we typically need to collect counts for a long time.\n// Otherwise, if config parameter 'reset' has 'true' value, we will get a histogram\n// with a small amount of the distribution. However, in some use cases, a reset is useful.\nfunc (h *Histogram) Reset() {\n\tif h.ResetBuckets {\n\t\th.resetCache()\n\t\th.buckets = make(bucketsByMetrics)\n\t}\n}\n\n// groupFieldsByBuckets groups fields by metric buckets which are represented as tags\nfunc (h *Histogram) groupFieldsByBuckets(\n\tmetricsWithGroupedFields *[]groupedByCountFields, name, field string, tags map[string]string, counts []int64,\n) {\n\tsum := int64(0)\n\tbuckets := h.getBuckets(name, field) // note that len(buckets) + 1 == len(counts)\n\n\tfor index, count := range counts {\n\t\tif !h.Cumulative {\n\t\t\tsum = 0 // reset sum -> don't store cumulative counts\n\n\t\t\ttags[bucketLeftTag] = bucketNegInf\n\t\t\tif index > 0 {\n\t\t\t\ttags[bucketLeftTag] = strconv.FormatFloat(buckets[index-1], 'f', -1, 64)\n\t\t\t}\n\t\t}\n\n\t\ttags[bucketRightTag] = bucketPosInf\n\t\tif index < len(buckets) {\n\t\t\ttags[bucketRightTag] = strconv.FormatFloat(buckets[index], 'f', -1, 64)\n\t\t}\n\n\t\tsum += count\n\t\tgroupField(metricsWithGroupedFields, name, field, sum, copyTags(tags))\n\t}\n}\n\n// groupField groups field by count value\nfunc groupField(metricsWithGroupedFields *[]groupedByCountFields, name, field string, count int64, tags map[string]string) {\n\tfor key, metric := range *metricsWithGroupedFields {\n\t\tif name == metric.name && isTagsIdentical(tags, metric.tags) {\n\t\t\t(*metricsWithGroupedFields)[key].fieldsWithCount[field] = count\n\t\t\treturn\n\t\t}\n\t}\n\n\tfieldsWithCount := map[string]int64{\n\t\tfield: count,\n\t}\n\n\t*metricsWithGroupedFields = append(\n\t\t*metricsWithGroupedFields,\n\t\tgroupedByCountFields{name: name, tags: tags, fieldsWithCount: fieldsWithCount},\n\t)\n}\n\n// resetCache resets cached counts(hits) in the buckets\nfunc (h *Histogram) resetCache() {\n\th.cache = make(map[uint64]metricHistogramCollection)\n}\n\n// getBuckets finds buckets and returns them\nfunc (h *Histogram) getBuckets(metric, field string) []float64 {\n\tif buckets, ok := h.buckets[metric][field]; ok {\n\t\treturn buckets\n\t}\n\n\tfor _, cfg := range h.Configs {\n\t\tif cfg.Metric == metric {\n\t\t\tif !isBucketExists(field, cfg) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := h.buckets[metric]; !ok {\n\t\t\t\th.buckets[metric] = make(bucketsByFields)\n\t\t\t}\n\n\t\t\th.buckets[metric][field] = sortBuckets(cfg.Buckets)\n\t\t}\n\t}\n\n\treturn h.buckets[metric][field]\n}\n\n// isBucketExists checks if buckets exists for the passed field\nfunc isBucketExists(field string, cfg bucketConfig) bool {\n\tif len(cfg.Fields) == 0 {\n\t\treturn true\n\t}\n\n\tfor _, fl := range cfg.Fields {\n\t\tif fl == field {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// sortBuckets sorts the buckets if it is needed\nfunc sortBuckets(buckets []float64) []float64 {\n\tfor i, bucket := range buckets {\n\t\tif i < len(buckets)-1 && bucket >= buckets[i+1] {\n\t\t\tsort.Float64s(buckets)\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn buckets\n}\n\n// convert converts interface to concrete type\nfunc convert(in interface{}) (float64, bool) {\n\tswitch v := in.(type) {\n\tcase float64:\n\t\treturn v, true\n\tcase int64:\n\t\treturn float64(v), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\n// copyTags copies tags\nfunc copyTags(tags map[string]string) map[string]string {\n\tcopiedTags := make(map[string]string, len(tags))\n\tfor key, val := range tags {\n\t\tcopiedTags[key] = val\n\t}\n\n\treturn copiedTags\n}\n\n// isTagsIdentical checks the identity of two list of tags\nfunc isTagsIdentical(originalTags, checkedTags map[string]string) bool {\n\tif len(originalTags) != len(checkedTags) {\n\t\treturn false\n\t}\n\n\tfor tagName, tagValue := range originalTags {\n\t\tif tagValue != checkedTags[tagName] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// makeFieldsWithCount assigns count value to all metric fields\nfunc makeFieldsWithCount(fieldsWithCountIn map[string]int64) map[string]interface{} {\n\tfieldsWithCountOut := make(map[string]interface{}, len(fieldsWithCountIn))\n\tfor field, count := range fieldsWithCountIn {\n\t\tfieldsWithCountOut[field+\"_bucket\"] = count\n\t}\n\n\treturn fieldsWithCountOut\n}\n\nfunc newHistogramAggregator() *Histogram {\n\th := &Histogram{\n\t\tCumulative: true,\n\t}\n\th.buckets = make(bucketsByMetrics)\n\th.resetCache()\n\n\treturn h\n}\n\nfunc init() {\n\taggregators.Add(\"histogram\", func() telegraf.Aggregator {\n\t\treturn newHistogramAggregator()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/histogram/histogram_test.go",
    "content": "package histogram\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype fields map[string]interface{}\ntype tags map[string]string\n\n// newTestHistogram creates new test histogram aggregation with specified config\nfunc newTestHistogram(cfg []bucketConfig, reset, cumulative, pushOnlyOnUpdate bool) telegraf.Aggregator {\n\treturn newTestHistogramWithExpirationInterval(cfg, reset, cumulative, pushOnlyOnUpdate, 0)\n}\n\nfunc newTestHistogramWithExpirationInterval(\n\tcfg []bucketConfig, reset, cumulative, pushOnlyOnUpdate bool, expirationInterval config.Duration,\n) telegraf.Aggregator {\n\thtm := newHistogramAggregator()\n\thtm.Configs = cfg\n\thtm.ResetBuckets = reset\n\thtm.Cumulative = cumulative\n\thtm.ExpirationInterval = expirationInterval\n\thtm.PushOnlyOnUpdate = pushOnlyOnUpdate\n\n\treturn htm\n}\n\n// firstMetric1 is the first test metric\nvar firstMetric1 = metric.New(\n\t\"first_metric_name\",\n\ttags{},\n\tfields{\n\t\t\"a\": float64(15.3),\n\t\t\"b\": float64(40),\n\t},\n\ttime.Now(),\n)\n\n// firstMetric1 is the first test metric with other value\nvar firstMetric2 = metric.New(\n\t\"first_metric_name\",\n\ttags{},\n\tfields{\n\t\t\"a\": float64(15.9),\n\t\t\"c\": float64(40),\n\t},\n\ttime.Now(),\n)\n\n// secondMetric is the second metric\nvar secondMetric = metric.New(\n\t\"second_metric_name\",\n\ttags{},\n\tfields{\n\t\t\"a\":        float64(105),\n\t\t\"ignoreme\": \"string\",\n\t\t\"andme\":    true,\n\t},\n\ttime.Now(),\n)\n\n// BenchmarkApply runs benchmarks\nfunc BenchmarkApply(b *testing.B) {\n\thistogram := newHistogramAggregator()\n\n\tfor n := 0; n < b.N; n++ {\n\t\thistogram.Add(firstMetric1)\n\t\thistogram.Add(firstMetric2)\n\t\thistogram.Add(secondMetric)\n\t}\n}\n\n// TestHistogram tests metrics for one period and for one field\nfunc TestHistogram(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tFields:  []string{\"a\"},\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, true, false)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Reset()\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: bucketPosInf})\n}\n\n// TestHistogram tests metrics for one period, for one field and push only on histogram update\nfunc TestHistogramPushOnUpdate(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tFields:  []string{\"a\"},\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, true, true)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Reset()\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketRightTag: bucketPosInf})\n\n\tacc.ClearMetrics()\n\thistogram.Push(acc)\n\trequire.Empty(t, acc.Metrics, \"Incorrect number of metrics\")\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(3)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(3)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(3)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(3)}, tags{bucketRightTag: bucketPosInf})\n}\n\n// TestHistogramNonCumulative tests metrics for one period and for one field\nfunc TestHistogramNonCumulative(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tFields:  []string{\"a\"},\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, false, false)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Reset()\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketLeftTag: bucketNegInf, bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketLeftTag: \"0\", bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2)}, tags{bucketLeftTag: \"10\", bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketLeftTag: \"20\", bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketLeftTag: \"30\", bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketLeftTag: \"40\", bucketRightTag: bucketPosInf})\n}\n\n// TestHistogramWithReset tests metrics for one period and for one field, with reset between metrics adding\nfunc TestHistogramWithReset(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tFields:  []string{\"a\"},\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, true, true, false)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Reset()\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1)}, tags{bucketRightTag: bucketPosInf})\n}\n\n// TestHistogramWithAllFields tests two metrics for one period and for all fields\nfunc TestHistogramWithAllFields(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tBuckets: []float64{0.0, 15.5, 20.0, 30.0, 40.0},\n\t\t},\n\t\t{\n\t\t\tMetric:  \"second_metric_name\",\n\t\t\tBuckets: []float64{0.0, 4.0, 10.0, 23.0, 30.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, true, false)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Add(firstMetric2)\n\thistogram.Add(secondMetric)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 12, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"15.5\"},\n\t)\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(1), \"c_bucket\": int64(1)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(2), \"b_bucket\": int64(1), \"c_bucket\": int64(1)},\n\t\ttags{bucketRightTag: bucketPosInf},\n\t)\n\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"0\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"4\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"10\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"23\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"30\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: bucketPosInf},\n\t)\n}\n\n// TestHistogramWithAllFieldsNonCumulative tests two metrics for one period and for all fields\nfunc TestHistogramWithAllFieldsNonCumulative(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tBuckets: []float64{0.0, 15.5, 20.0, 30.0, 40.0},\n\t\t},\n\t\t{\n\t\t\tMetric:  \"second_metric_name\",\n\t\t\tBuckets: []float64{0.0, 4.0, 10.0, 23.0, 30.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, false, false)\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\thistogram.Add(firstMetric2)\n\thistogram.Add(secondMetric)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 12, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: bucketNegInf, bucketRightTag: \"0\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"0\", bucketRightTag: \"15.5\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"15.5\", bucketRightTag: \"20\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"20\", bucketRightTag: \"30\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"b_bucket\": int64(1), \"c_bucket\": int64(1)},\n\t\ttags{bucketLeftTag: \"30\", bucketRightTag: \"40\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"40\", bucketRightTag: bucketPosInf},\n\t)\n\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: bucketNegInf, bucketRightTag: \"0\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"0\", bucketRightTag: \"4\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"4\", bucketRightTag: \"10\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"10\", bucketRightTag: \"23\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"23\", bucketRightTag: \"30\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketLeftTag: \"30\", bucketRightTag: bucketPosInf},\n\t)\n}\n\n// TestHistogramWithTwoPeriodsAndAllFields tests two metrics getting added with a push/reset in between (simulates\n// getting added in different periods) for all fields\nfunc TestHistogramWithTwoPeriodsAndAllFields(t *testing.T) {\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, true, false)\n\n\tacc := &testutil.Accumulator{}\n\thistogram.Add(firstMetric1)\n\thistogram.Push(acc)\n\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0), \"b_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0), \"b_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1), \"b_bucket\": int64(0)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1), \"b_bucket\": int64(0)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1), \"b_bucket\": int64(1)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(1), \"b_bucket\": int64(1)}, tags{bucketRightTag: bucketPosInf})\n\n\tacc.ClearMetrics()\n\thistogram.Add(firstMetric2)\n\thistogram.Push(acc)\n\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"0\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(0), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"10\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"20\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(0), \"c_bucket\": int64(0)}, tags{bucketRightTag: \"30\"})\n\tassertContainsTaggedField(t, acc, \"first_metric_name\", fields{\"a_bucket\": int64(2), \"b_bucket\": int64(1), \"c_bucket\": int64(1)}, tags{bucketRightTag: \"40\"})\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"first_metric_name\",\n\t\tfields{\"a_bucket\": int64(2), \"b_bucket\": int64(1), \"c_bucket\": int64(1)},\n\t\ttags{bucketRightTag: bucketPosInf},\n\t)\n}\n\n// TestWrongBucketsOrder tests the calling panic with incorrect order of buckets\nfunc TestWrongBucketsOrder(t *testing.T) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\trequire.Equal(\n\t\t\t\tt,\n\t\t\t\t\"histogram buckets must be in increasing order: 90.00 >= 20.00, metrics: first_metric_name, field: a\",\n\t\t\t\tfmt.Sprint(r),\n\t\t\t)\n\t\t}\n\t}()\n\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tBuckets: []float64{0.0, 90.0, 20.0, 30.0, 40.0},\n\t\t},\n\t}\n\thistogram := newTestHistogram(cfg, false, true, false)\n\thistogram.Add(firstMetric2)\n}\n\n// TestHistogram tests two metrics getting added and metric expiration\nfunc TestHistogramMetricExpiration(t *testing.T) {\n\tcurrentTime := time.Unix(10, 0)\n\ttimeNow = func() time.Time {\n\t\treturn currentTime\n\t}\n\tdefer func() {\n\t\ttimeNow = time.Now\n\t}()\n\n\tcfg := []bucketConfig{\n\t\t{\n\t\t\tMetric:  \"first_metric_name\",\n\t\t\tFields:  []string{\"a\"},\n\t\t\tBuckets: []float64{0.0, 10.0, 20.0, 30.0, 40.0},\n\t\t},\n\t\t{\n\t\t\tMetric:  \"second_metric_name\",\n\t\t\tBuckets: []float64{0.0, 4.0, 10.0, 23.0, 30.0},\n\t\t},\n\t}\n\thistogram := newTestHistogramWithExpirationInterval(cfg, false, true, false, config.Duration(30))\n\n\tacc := &testutil.Accumulator{}\n\n\thistogram.Add(firstMetric1)\n\tcurrentTime = time.Unix(41, 0)\n\thistogram.Add(secondMetric)\n\thistogram.Push(acc)\n\n\trequire.Len(t, acc.Metrics, 6, \"Incorrect number of metrics\")\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"0\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"4\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"10\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"23\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(0), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: \"30\"},\n\t)\n\tassertContainsTaggedField(\n\t\tt,\n\t\tacc,\n\t\t\"second_metric_name\",\n\t\tfields{\"a_bucket\": int64(1), \"ignoreme_bucket\": int64(0), \"andme_bucket\": int64(0)},\n\t\ttags{bucketRightTag: bucketPosInf},\n\t)\n}\n\n// assertContainsTaggedField is help functions to test histogram data\nfunc assertContainsTaggedField(t *testing.T, acc *testutil.Accumulator, metricName string, fields map[string]interface{}, tags map[string]string) {\n\tacc.Lock()\n\tdefer acc.Unlock()\n\n\tfor _, checkedMetric := range acc.Metrics {\n\t\t// filter by metric name\n\t\tif checkedMetric.Measurement != metricName {\n\t\t\tcontinue\n\t\t}\n\n\t\t// filter by tags\n\t\tisTagsIdentical := true\n\t\tfor tag := range tags {\n\t\t\tif val, ok := checkedMetric.Tags[tag]; !ok || val != tags[tag] {\n\t\t\t\tisTagsIdentical = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !isTagsIdentical {\n\t\t\tcontinue\n\t\t}\n\n\t\t// filter by field keys\n\t\tisFieldKeysIdentical := true\n\t\tfor field := range fields {\n\t\t\tif _, ok := checkedMetric.Fields[field]; !ok {\n\t\t\t\tisFieldKeysIdentical = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !isFieldKeysIdentical {\n\t\t\tcontinue\n\t\t}\n\n\t\t// check fields with their counts\n\t\trequire.Equal(t, fields, checkedMetric.Fields)\n\t\treturn\n\t}\n\n\trequire.Failf(t, \"Unknown measurement\", \"Unknown measurement %q with tags: %v, fields: %v\", metricName, tags, fields)\n}\n"
  },
  {
    "path": "plugins/aggregators/histogram/sample.conf",
    "content": "# Configuration for aggregate histogram metrics\n[[aggregators.histogram]]\n  ## The period in which to flush the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## If true, the histogram will be reset on flush instead\n  ## of accumulating the results.\n  reset = false\n\n  ## Whether bucket values should be accumulated. If set to false, \"gt\" tag will be added.\n  ## Defaults to true.\n  cumulative = true\n\n  ## Expiration interval for each histogram. The histogram will be expired if\n  ## there are no changes in any buckets for this time interval. 0 == no expiration.\n  # expiration_interval = \"0m\"\n\n  ## If true, aggregated histogram are pushed to output only if it was updated since\n  ## previous push. Defaults to false.\n  # push_only_on_update = false\n\n  ## Example config that aggregates all fields of the metric.\n  # [[aggregators.histogram.config]]\n  #   ## Right borders of buckets (with +Inf implicitly added).\n  #   buckets = [0.0, 15.6, 34.5, 49.1, 71.5, 80.5, 94.5, 100.0]\n  #   ## The name of metric.\n  #   measurement_name = \"cpu\"\n\n  ## Example config that aggregates only specific fields of the metric.\n  # [[aggregators.histogram.config]]\n  #   ## Right borders of buckets (with +Inf implicitly added).\n  #   buckets = [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]\n  #   ## The name of metric.\n  #   measurement_name = \"diskio\"\n  #   ## The concrete fields of metric\n  #   fields = [\"io_time\", \"read_time\", \"write_time\"]\n"
  },
  {
    "path": "plugins/aggregators/merge/README.md",
    "content": "# Merge Aggregator Plugin\n\nThis plugin merges metrics of the same series and timestamp into new metrics\nwith the super-set of fields. A series here is defined by the metric name and\nthe tag key-value set.\n\nUse this plugin when fields are split over multiple metrics, with the same\nmeasurement, tag set and timestamp.\n\n⭐ Telegraf v1.13.0\n🏷️ transformation\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Merge metrics into multifield metrics by series key\n[[aggregators.merge]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## Precision to round the metric timestamp to\n  ## This is useful for cases where metrics to merge arrive within a small\n  ## interval and thus vary in timestamp. The timestamp of the resulting metric\n  ## is also rounded.\n  # round_timestamp_to = \"1ns\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  drop_original = true\n```\n\n## Example\n\n```diff\n- cpu,host=localhost usage_time=42 1567562620000000000\n- cpu,host=localhost idle_time=42 1567562620000000000\n+ cpu,host=localhost idle_time=42,usage_time=42 1567562620000000000\n```\n"
  },
  {
    "path": "plugins/aggregators/merge/merge.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage merge\n\nimport (\n\t_ \"embed\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Merge struct {\n\tRoundTimestamp config.Duration `toml:\"round_timestamp_to\"`\n\tgrouper        *metric.SeriesGrouper\n}\n\nfunc (*Merge) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *Merge) Init() error {\n\ta.grouper = metric.NewSeriesGrouper()\n\treturn nil\n}\n\nfunc (a *Merge) Add(m telegraf.Metric) {\n\tgm := m\n\tif a.RoundTimestamp > 0 {\n\t\tif unwrapped, ok := m.(telegraf.UnwrappableMetric); ok {\n\t\t\tgm = unwrapped.Unwrap().Copy()\n\t\t} else {\n\t\t\tgm = m.Copy()\n\t\t}\n\t\tts := gm.Time()\n\t\tgm.SetTime(ts.Round(time.Duration(a.RoundTimestamp)))\n\t}\n\ta.grouper.AddMetric(gm)\n}\n\nfunc (a *Merge) Push(acc telegraf.Accumulator) {\n\t// Always use nanosecond precision to avoid rounding metrics that were\n\t// produced at a precision higher than the agent default.\n\tacc.SetPrecision(time.Nanosecond)\n\n\tfor _, m := range a.grouper.Metrics() {\n\t\tacc.AddMetric(m)\n\t}\n}\n\nfunc (a *Merge) Reset() {\n\ta.grouper = metric.NewSeriesGrouper()\n}\n\nfunc init() {\n\taggregators.Add(\"merge\", func() telegraf.Aggregator {\n\t\treturn &Merge{}\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/merge/merge_test.go",
    "content": "package merge\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSimple(t *testing.T) {\n\tplugin := &Merge{}\n\trequire.NoError(t, plugin.Init())\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\n\tvar acc testutil.Accumulator\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestNanosecondPrecision(t *testing.T) {\n\tplugin := &Merge{}\n\trequire.NoError(t, plugin.Init())\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\n\tvar acc testutil.Accumulator\n\tacc.SetPrecision(time.Second)\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestNoRounding(t *testing.T) {\n\tplugin := &Merge{}\n\trequire.NoError(t, plugin.Init())\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t)\n\n\tvar acc testutil.Accumulator\n\tacc.SetPrecision(time.Second)\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestWithRounding(t *testing.T) {\n\tplugin := &Merge{RoundTimestamp: config.Duration(10 * time.Nanosecond)}\n\trequire.NoError(t, plugin.Init())\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t)\n\n\tvar acc testutil.Accumulator\n\tacc.SetPrecision(time.Second)\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\":  23,\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestReset(t *testing.T) {\n\tplugin := &Merge{}\n\trequire.NoError(t, plugin.Init())\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\n\tvar acc testutil.Accumulator\n\tplugin.Push(&acc)\n\n\tplugin.Reset()\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc BenchmarkMergeOne(b *testing.B) {\n\tvar merger Merge\n\trequire.NoError(b, merger.Init())\n\n\tm := metric.New(\n\t\t\"mymetric\",\n\t\tmap[string]string{\n\t\t\t\"host\":        \"host.example.com\",\n\t\t\t\"mykey\":       \"myvalue\",\n\t\t\t\"another key\": \"another value\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"f1\": 1,\n\t\t\t\"f2\": 2,\n\t\t\t\"f3\": 3,\n\t\t\t\"f4\": 4,\n\t\t\t\"f5\": 5,\n\t\t\t\"f6\": 6,\n\t\t\t\"f7\": 7,\n\t\t\t\"f8\": 8,\n\t\t},\n\t\ttime.Now(),\n\t)\n\n\tvar acc testutil.NopAccumulator\n\tfor n := 0; n < b.N; n++ {\n\t\tmerger.Reset()\n\t\tmerger.Add(m)\n\t\tmerger.Push(&acc)\n\t}\n}\n\nfunc BenchmarkMergeTwo(b *testing.B) {\n\tvar merger Merge\n\trequire.NoError(b, merger.Init())\n\n\tnow := time.Now()\n\tm1 := metric.New(\n\t\t\"mymetric\",\n\t\tmap[string]string{\n\t\t\t\"host\":        \"host.example.com\",\n\t\t\t\"mykey\":       \"myvalue\",\n\t\t\t\"another key\": \"another value\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"f1\": 1,\n\t\t\t\"f2\": 2,\n\t\t\t\"f3\": 3,\n\t\t\t\"f4\": 4,\n\t\t\t\"f5\": 5,\n\t\t\t\"f6\": 6,\n\t\t\t\"f7\": 7,\n\t\t\t\"f8\": 8,\n\t\t},\n\t\tnow,\n\t)\n\n\tm2 := metric.New(\n\t\t\"mymetric\",\n\t\tmap[string]string{\n\t\t\t\"host\":        \"host.example.com\",\n\t\t\t\"mykey\":       \"myvalue\",\n\t\t\t\"another key\": \"another value\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"f8\":  8,\n\t\t\t\"f9\":  9,\n\t\t\t\"f10\": 10,\n\t\t\t\"f11\": 11,\n\t\t\t\"f12\": 12,\n\t\t\t\"f13\": 13,\n\t\t\t\"f14\": 14,\n\t\t\t\"f15\": 15,\n\t\t\t\"f16\": 16,\n\t\t},\n\t\tnow,\n\t)\n\n\tvar acc testutil.NopAccumulator\n\tfor n := 0; n < b.N; n++ {\n\t\tmerger.Reset()\n\t\tmerger.Add(m1)\n\t\tmerger.Add(m2)\n\t\tmerger.Push(&acc)\n\t}\n}\n"
  },
  {
    "path": "plugins/aggregators/merge/sample.conf",
    "content": "# Merge metrics into multifield metrics by series key\n[[aggregators.merge]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## Precision to round the metric timestamp to\n  ## This is useful for cases where metrics to merge arrive within a small\n  ## interval and thus vary in timestamp. The timestamp of the resulting metric\n  ## is also rounded.\n  # round_timestamp_to = \"1ns\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  drop_original = true\n"
  },
  {
    "path": "plugins/aggregators/minmax/README.md",
    "content": "# Minimum-Maximum Aggregator Plugin\n\nThis plugin aggregates the minimum and maximum values of each field it sees,\nemitting the aggrate every `period` seconds with field names suffixed by `_min`\nand `_max` respectively.\n\n⭐ Telegraf v1.1.0\n🏷️ statistics\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Keep the aggregate min/max of each metric passing through.\n[[aggregators.minmax]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n```\n\n## Measurements & Fields\n\n- measurement1\n  - field1_max\n  - field1_min\n\n## Tags\n\nNo tags are applied by this aggregator.\n\n## Example Output\n\n```text\nsystem,host=tars load1=1.72 1475583980000000000\nsystem,host=tars load1=1.6 1475583990000000000\nsystem,host=tars load1=1.66 1475584000000000000\nsystem,host=tars load1=1.63 1475584010000000000\nsystem,host=tars load1_max=1.72,load1_min=1.6 1475584010000000000\nsystem,host=tars load1=1.46 1475584020000000000\nsystem,host=tars load1=1.39 1475584030000000000\nsystem,host=tars load1=1.41 1475584040000000000\nsystem,host=tars load1_max=1.46,load1_min=1.39 1475584040000000000\n```\n"
  },
  {
    "path": "plugins/aggregators/minmax/minmax.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage minmax\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype MinMax struct {\n\tcache map[uint64]aggregate\n}\n\ntype aggregate struct {\n\tfields map[string]minmax\n\tname   string\n\ttags   map[string]string\n}\n\ntype minmax struct {\n\tmin float64\n\tmax float64\n}\n\nfunc (*MinMax) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *MinMax) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\tif _, ok := m.cache[id]; !ok {\n\t\t// hit an uncached metric, create caches for first time:\n\t\ta := aggregate{\n\t\t\tname:   in.Name(),\n\t\t\ttags:   in.Tags(),\n\t\t\tfields: make(map[string]minmax),\n\t\t}\n\t\tfor k, v := range in.Fields() {\n\t\t\tif fv, ok := convert(v); ok {\n\t\t\t\ta.fields[k] = minmax{\n\t\t\t\t\tmin: fv,\n\t\t\t\t\tmax: fv,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tm.cache[id] = a\n\t} else {\n\t\tfor k, v := range in.Fields() {\n\t\t\tif fv, ok := convert(v); ok {\n\t\t\t\tif _, ok := m.cache[id].fields[k]; !ok {\n\t\t\t\t\t// hit an uncached field of a cached metric\n\t\t\t\t\tm.cache[id].fields[k] = minmax{\n\t\t\t\t\t\tmin: fv,\n\t\t\t\t\t\tmax: fv,\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif fv < m.cache[id].fields[k].min {\n\t\t\t\t\ttmp := m.cache[id].fields[k]\n\t\t\t\t\ttmp.min = fv\n\t\t\t\t\tm.cache[id].fields[k] = tmp\n\t\t\t\t} else if fv > m.cache[id].fields[k].max {\n\t\t\t\t\ttmp := m.cache[id].fields[k]\n\t\t\t\t\ttmp.max = fv\n\t\t\t\t\tm.cache[id].fields[k] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (m *MinMax) Push(acc telegraf.Accumulator) {\n\tfor _, aggregate := range m.cache {\n\t\tfields := make(map[string]interface{}, len(aggregate.fields))\n\t\tfor k, v := range aggregate.fields {\n\t\t\tfields[k+\"_min\"] = v.min\n\t\t\tfields[k+\"_max\"] = v.max\n\t\t}\n\t\tacc.AddFields(aggregate.name, fields, aggregate.tags)\n\t}\n}\n\nfunc (m *MinMax) Reset() {\n\tm.cache = make(map[uint64]aggregate)\n}\n\nfunc convert(in interface{}) (float64, bool) {\n\tswitch v := in.(type) {\n\tcase float64:\n\t\treturn v, true\n\tcase int64:\n\t\treturn float64(v), true\n\tcase uint64:\n\t\treturn float64(v), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\nfunc newMinMax() telegraf.Aggregator {\n\tmm := &MinMax{}\n\tmm.Reset()\n\treturn mm\n}\n\nfunc init() {\n\taggregators.Add(\"minmax\", func() telegraf.Aggregator {\n\t\treturn newMinMax()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/minmax/minmax_test.go",
    "content": "package minmax\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar m1 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\": int64(1),\n\t\t\"b\": int64(1),\n\t\t\"c\": int64(1),\n\t\t\"d\": int64(1),\n\t\t\"e\": int64(1),\n\t\t\"f\": float64(2),\n\t\t\"g\": float64(2),\n\t\t\"h\": float64(2),\n\t\t\"i\": float64(2),\n\t\t\"j\": float64(3),\n\t},\n\ttime.Now(),\n)\nvar m2 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\":        int64(1),\n\t\t\"b\":        int64(3),\n\t\t\"c\":        int64(3),\n\t\t\"d\":        int64(3),\n\t\t\"e\":        int64(3),\n\t\t\"f\":        float64(1),\n\t\t\"g\":        float64(1),\n\t\t\"h\":        float64(1),\n\t\t\"i\":        float64(1),\n\t\t\"j\":        float64(1),\n\t\t\"k\":        float64(200),\n\t\t\"l\":        uint64(200),\n\t\t\"ignoreme\": \"string\",\n\t\t\"andme\":    true,\n\t},\n\ttime.Now(),\n)\n\nfunc BenchmarkApply(b *testing.B) {\n\tminmax := newMinMax()\n\n\tfor n := 0; n < b.N; n++ {\n\t\tminmax.Add(m1)\n\t\tminmax.Add(m2)\n\t}\n}\n\n// Test two metrics getting added.\nfunc TestMinMaxWithPeriod(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax := newMinMax()\n\n\tminmax.Add(m1)\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": float64(1),\n\t\t\"a_min\": float64(1),\n\t\t\"b_max\": float64(3),\n\t\t\"b_min\": float64(1),\n\t\t\"c_max\": float64(3),\n\t\t\"c_min\": float64(1),\n\t\t\"d_max\": float64(3),\n\t\t\"d_min\": float64(1),\n\t\t\"e_max\": float64(3),\n\t\t\"e_min\": float64(1),\n\t\t\"f_max\": float64(2),\n\t\t\"f_min\": float64(1),\n\t\t\"g_max\": float64(2),\n\t\t\"g_min\": float64(1),\n\t\t\"h_max\": float64(2),\n\t\t\"h_min\": float64(1),\n\t\t\"i_max\": float64(2),\n\t\t\"i_min\": float64(1),\n\t\t\"j_max\": float64(3),\n\t\t\"j_min\": float64(1),\n\t\t\"k_max\": float64(200),\n\t\t\"k_min\": float64(200),\n\t\t\"l_max\": float64(200),\n\t\t\"l_min\": float64(200),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test two metrics getting added with a push/reset in between (simulates\n// getting added in different periods.)\nfunc TestMinMaxDifferentPeriods(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax := newMinMax()\n\n\tminmax.Add(m1)\n\tminmax.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": float64(1),\n\t\t\"a_min\": float64(1),\n\t\t\"b_max\": float64(1),\n\t\t\"b_min\": float64(1),\n\t\t\"c_max\": float64(1),\n\t\t\"c_min\": float64(1),\n\t\t\"d_max\": float64(1),\n\t\t\"d_min\": float64(1),\n\t\t\"e_max\": float64(1),\n\t\t\"e_min\": float64(1),\n\t\t\"f_max\": float64(2),\n\t\t\"f_min\": float64(2),\n\t\t\"g_max\": float64(2),\n\t\t\"g_min\": float64(2),\n\t\t\"h_max\": float64(2),\n\t\t\"h_min\": float64(2),\n\t\t\"i_max\": float64(2),\n\t\t\"i_min\": float64(2),\n\t\t\"j_max\": float64(3),\n\t\t\"j_min\": float64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n\n\tacc.ClearMetrics()\n\tminmax.Reset()\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\texpectedFields = map[string]interface{}{\n\t\t\"a_max\": float64(1),\n\t\t\"a_min\": float64(1),\n\t\t\"b_max\": float64(3),\n\t\t\"b_min\": float64(3),\n\t\t\"c_max\": float64(3),\n\t\t\"c_min\": float64(3),\n\t\t\"d_max\": float64(3),\n\t\t\"d_min\": float64(3),\n\t\t\"e_max\": float64(3),\n\t\t\"e_min\": float64(3),\n\t\t\"f_max\": float64(1),\n\t\t\"f_min\": float64(1),\n\t\t\"g_max\": float64(1),\n\t\t\"g_min\": float64(1),\n\t\t\"h_max\": float64(1),\n\t\t\"h_min\": float64(1),\n\t\t\"i_max\": float64(1),\n\t\t\"i_min\": float64(1),\n\t\t\"j_max\": float64(1),\n\t\t\"j_min\": float64(1),\n\t\t\"k_max\": float64(200),\n\t\t\"k_min\": float64(200),\n\t\t\"l_max\": float64(200),\n\t\t\"l_min\": float64(200),\n\t}\n\texpectedTags = map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n"
  },
  {
    "path": "plugins/aggregators/minmax/sample.conf",
    "content": "# Keep the aggregate min/max of each metric passing through.\n[[aggregators.minmax]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n"
  },
  {
    "path": "plugins/aggregators/quantile/README.md",
    "content": "# Quantile Aggregator Plugin\n\nThis plugin aggregates each numeric field per metric into the specified\nquantiles and emits the quantiles every `period`. Different aggregation\nalgorithms are supported with varying accuracy and limitations.\n\n⭐ Telegraf v1.18.0\n🏷️ statistics\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Keep the aggregate quantiles of each metric passing through.\n[[aggregators.quantile]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## Quantiles to output in the range [0,1]\n  # quantiles = [0.25, 0.5, 0.75]\n\n  ## Type of aggregation algorithm\n  ## Supported are:\n  ##  \"t-digest\" -- approximation using centroids, can cope with large number of samples\n  ##  \"exact R7\" -- exact computation also used by Excel or NumPy (Hyndman & Fan 1996 R7)\n  ##  \"exact R8\" -- exact computation (Hyndman & Fan 1996 R8)\n  ## NOTE: Do not use \"exact\" algorithms with large number of samples\n  ##       to not impair performance or memory consumption!\n  # algorithm = \"t-digest\"\n\n  ## Compression for approximation (t-digest). The value needs to be\n  ## greater or equal to 1.0. Smaller values will result in more\n  ## performance but less accuracy.\n  # compression = 100.0\n```\n\n## Algorithm types\n\n### t-digest\n\nProposed by [Dunning & Ertl (2019)][tdigest_paper] this type uses a\nspecial data-structure to cluster data. These clusters are later used\nto approximate the requested quantiles. The bounds of the approximation\ncan be controlled by the `compression` setting where smaller values\nresult in higher performance but less accuracy.\n\nDue to its incremental nature, this algorithm can handle large\nnumbers of samples efficiently.  It is recommended for applications\nwhere exact quantile calculation isn't required.\n\nFor implementation details see the underlying [golang library][tdigest_lib].\n\n### exact R7 and R8\n\nThese algorithms compute quantiles as described in [Hyndman & Fan\n(1996)][hyndman_fan].  The R7 variant is used in Excel and NumPy.  The R8\nvariant is recommended by Hyndman & Fan due to its independence of the\nunderlying sample distribution.\n\nThese algorithms save all data for the aggregation `period`.  They require a lot\nof memory when used with a large number of series or a large number of\nsamples. They are slower than the `t-digest` algorithm and are recommended only\nto be used with a small number of samples and series.\n\n## Benchmark (linux/amd64)\n\nThe benchmark was performed by adding 100 metrics with six numeric\n(and two non-numeric) fields to the aggregator and the derive the aggregation\nresult.\n\n| algorithm  | # quantiles   | avg. runtime  |\n| :------------ | -------------:| -------------:|\n| t-digest      |            3  |  376372 ns/op |\n| exact R7      |            3  | 9782946 ns/op |\n| exact R8      |            3  | 9158205 ns/op |\n| t-digest      |          100  |  899204 ns/op |\n| exact R7      |          100  | 7868816 ns/op |\n| exact R8      |          100  | 8099612 ns/op |\n\n## Measurements\n\nMeasurement names are passed through this aggregator.\n\n### Fields\n\nFor all numeric fields (int32/64, uint32/64 and float32/64) new *quantile*\nfields are aggregated in the form `<fieldname>_<quantile*100>`. Other field\ntypes (e.g. boolean, string) are ignored and dropped from the output.\n\nFor example passing in the following metric as *input*:\n\n- somemetric\n  - average_response_ms (float64)\n  - minimum_response_ms (float64)\n  - maximum_response_ms (float64)\n  - status (string)\n  - ok (boolean)\n\nand the default setting for `quantiles` you get the following *output*\n\n- somemetric\n  - average_response_ms_025 (float64)\n  - average_response_ms_050 (float64)\n  - average_response_ms_075 (float64)\n  - minimum_response_ms_025 (float64)\n  - minimum_response_ms_050 (float64)\n  - minimum_response_ms_075 (float64)\n  - maximum_response_ms_025 (float64)\n  - maximum_response_ms_050 (float64)\n  - maximum_response_ms_075 (float64)\n\nThe `status` and `ok` fields are dropped because they are not numeric.  Note\nthat the number of resulting fields scales with the number of `quantiles`\nspecified.\n\n### Tags\n\nTags are passed through to the output by this aggregator.\n\n### Example Output\n\n```text\ncpu,cpu=cpu-total,host=Hugin usage_user=10.814851731872487,usage_system=2.1679541490155687,usage_irq=1.046598554697342,usage_steal=0,usage_guest_nice=0,usage_idle=85.79616247197244,usage_nice=0,usage_iowait=0,usage_softirq=0.1744330924495688,usage_guest=0 1608288360000000000\ncpu,cpu=cpu-total,host=Hugin usage_guest=0,usage_system=2.1601016518428664,usage_iowait=0.02541296060990694,usage_irq=1.0165184243964942,usage_softirq=0.1778907242693666,usage_steal=0,usage_guest_nice=0,usage_user=9.275730622616953,usage_idle=87.34434561626493,usage_nice=0 1608288370000000000\ncpu,cpu=cpu-total,host=Hugin usage_idle=85.78199052131747,usage_nice=0,usage_irq=1.0476428036915637,usage_guest=0,usage_guest_nice=0,usage_system=1.995510102269591,usage_iowait=0,usage_softirq=0.1995510102269662,usage_steal=0,usage_user=10.975305562484735 1608288380000000000\ncpu,cpu=cpu-total,host=Hugin usage_guest_nice_075=0,usage_user_050=10.814851731872487,usage_guest_075=0,usage_steal_025=0,usage_irq_025=1.031558489546918,usage_irq_075=1.0471206791944527,usage_iowait_025=0,usage_guest_050=0,usage_guest_nice_050=0,usage_nice_075=0,usage_iowait_050=0,usage_system_050=2.1601016518428664,usage_irq_050=1.046598554697342,usage_guest_nice_025=0,usage_idle_050=85.79616247197244,usage_softirq_075=0.1887208672481664,usage_steal_075=0,usage_system_025=2.0778058770562287,usage_system_075=2.1640279004292173,usage_softirq_050=0.1778907242693666,usage_nice_050=0,usage_iowait_075=0.01270648030495347,usage_user_075=10.895078647178611,usage_nice_025=0,usage_steal_050=0,usage_user_025=10.04529117724472,usage_idle_025=85.78907649664495,usage_idle_075=86.57025404411868,usage_softirq_025=0.1761619083594677,usage_guest_025=0 1608288390000000000\n```\n\n[tdigest_paper]: https://arxiv.org/abs/1902.04023\n[tdigest_lib]:   https://github.com/caio/go-tdigest\n[hyndman_fan]:   http://www.maths.usyd.edu.au/u/UG/SM/STAT3022/r/current/Misc/Sample%20Quantiles%20in%20Statistical%20Packages.pdf\n"
  },
  {
    "path": "plugins/aggregators/quantile/algorithms.go",
    "content": "package quantile\n\nimport (\n\t\"math\"\n\t\"sort\"\n\n\t\"github.com/caio/go-tdigest\"\n)\n\ntype algorithm interface {\n\tAdd(value float64) error\n\tQuantile(q float64) float64\n}\n\nfunc newTDigest(compression float64) (algorithm, error) {\n\treturn tdigest.New(tdigest.Compression(compression))\n}\n\ntype exactAlgorithmR7 struct {\n\txs     []float64\n\tsorted bool\n}\n\nfunc newExactR7(_ float64) (algorithm, error) {\n\treturn &exactAlgorithmR7{xs: make([]float64, 0, 100), sorted: false}, nil\n}\n\n// Add adds a value to the algorithm.\nfunc (e *exactAlgorithmR7) Add(value float64) error {\n\te.xs = append(e.xs, value)\n\te.sorted = false\n\n\treturn nil\n}\n\n// Quantile returns the quantile value for the given q.\nfunc (e *exactAlgorithmR7) Quantile(q float64) float64 {\n\tsize := len(e.xs)\n\n\t// No information\n\tif len(e.xs) == 0 {\n\t\treturn math.NaN()\n\t}\n\n\t// Sort the array if necessary\n\tif !e.sorted {\n\t\tsort.Float64s(e.xs)\n\t\te.sorted = true\n\t}\n\n\t// Get the quantile index and the fraction to the neighbor\n\t// Hyndman & Fan; Sample Quantiles in Statistical Packages; The American Statistician vol 50; pp 361-365; 1996 -- R7\n\t// Same as Excel and Numpy.\n\tn := q * (float64(size) - 1)\n\ti, gamma := math.Modf(n)\n\tj := int(i)\n\tif j < 0 {\n\t\treturn e.xs[0]\n\t}\n\tif j >= size {\n\t\treturn e.xs[size-1]\n\t}\n\t// Linear interpolation\n\treturn e.xs[j] + gamma*(e.xs[j+1]-e.xs[j])\n}\n\ntype exactAlgorithmR8 struct {\n\txs     []float64\n\tsorted bool\n}\n\nfunc newExactR8(_ float64) (algorithm, error) {\n\treturn &exactAlgorithmR8{xs: make([]float64, 0, 100), sorted: false}, nil\n}\n\n// Add adds a value to the algorithm.\nfunc (e *exactAlgorithmR8) Add(value float64) error {\n\te.xs = append(e.xs, value)\n\te.sorted = false\n\n\treturn nil\n}\n\n// Quantile returns the quantile value for the given q.\nfunc (e *exactAlgorithmR8) Quantile(q float64) float64 {\n\tsize := len(e.xs)\n\n\t// No information\n\tif size == 0 {\n\t\treturn math.NaN()\n\t}\n\n\t// Sort the array if necessary\n\tif !e.sorted {\n\t\tsort.Float64s(e.xs)\n\t\te.sorted = true\n\t}\n\n\t// Get the quantile index and the fraction to the neighbor\n\t// Hyndman & Fan; Sample Quantiles in Statistical Packages; The American Statistician vol 50; pp 361-365; 1996 -- R8\n\tn := q*(float64(size)+1.0/3.0) - (2.0 / 3.0) // Indices are zero-base here but one-based in the paper\n\ti, gamma := math.Modf(n)\n\tj := int(i)\n\tif j < 0 {\n\t\treturn e.xs[0]\n\t}\n\tif j >= size {\n\t\treturn e.xs[size-1]\n\t}\n\t// Linear interpolation\n\treturn e.xs[j] + gamma*(e.xs[j+1]-e.xs[j])\n}\n"
  },
  {
    "path": "plugins/aggregators/quantile/quantile.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage quantile\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Quantile struct {\n\tQuantiles     []float64       `toml:\"quantiles\"`\n\tCompression   float64         `toml:\"compression\"`\n\tAlgorithmType string          `toml:\"algorithm\"`\n\tLog           telegraf.Logger `toml:\"-\"`\n\n\tnewAlgorithm newAlgorithmFunc\n\tcache        map[uint64]aggregate\n\n\tsuffixes []string\n}\n\ntype aggregate struct {\n\tname   string\n\tfields map[string]algorithm\n\ttags   map[string]string\n}\n\ntype newAlgorithmFunc func(compression float64) (algorithm, error)\n\nfunc (*Quantile) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (q *Quantile) Init() error {\n\tswitch q.AlgorithmType {\n\tcase \"t-digest\", \"\":\n\t\tq.newAlgorithm = newTDigest\n\tcase \"exact R7\":\n\t\tq.newAlgorithm = newExactR7\n\tcase \"exact R8\":\n\t\tq.newAlgorithm = newExactR8\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown algorithm type %q\", q.AlgorithmType)\n\t}\n\tif _, err := q.newAlgorithm(q.Compression); err != nil {\n\t\treturn fmt.Errorf(\"cannot create %q algorithm: %w\", q.AlgorithmType, err)\n\t}\n\n\tif len(q.Quantiles) == 0 {\n\t\tq.Quantiles = []float64{0.25, 0.5, 0.75}\n\t}\n\n\tduplicates := make(map[float64]bool)\n\tq.suffixes = make([]string, 0, len(q.Quantiles))\n\tfor _, qtl := range q.Quantiles {\n\t\tif qtl < 0.0 || qtl > 1.0 {\n\t\t\treturn fmt.Errorf(\"quantile %v out of range\", qtl)\n\t\t}\n\t\tif _, found := duplicates[qtl]; found {\n\t\t\treturn fmt.Errorf(\"duplicate quantile %v\", qtl)\n\t\t}\n\t\tduplicates[qtl] = true\n\t\tq.suffixes = append(q.suffixes, fmt.Sprintf(\"_%03d\", int(qtl*100.0)))\n\t}\n\n\tq.Reset()\n\n\treturn nil\n}\n\nfunc (q *Quantile) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\tif cached, ok := q.cache[id]; ok {\n\t\tfields := in.Fields()\n\t\tfor k, algo := range cached.fields {\n\t\t\tif field, ok := fields[k]; ok {\n\t\t\t\tif v, isconvertible := convert(field); isconvertible {\n\t\t\t\t\terr := algo.Add(v)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tq.Log.Errorf(\"adding cached field %s: %v\", k, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\n\t// New metric, setup cache and init algorithm\n\ta := aggregate{\n\t\tname:   in.Name(),\n\t\ttags:   in.Tags(),\n\t\tfields: make(map[string]algorithm),\n\t}\n\tfor k, field := range in.Fields() {\n\t\tif v, isconvertible := convert(field); isconvertible {\n\t\t\talgo, err := q.newAlgorithm(q.Compression)\n\t\t\tif err != nil {\n\t\t\t\tq.Log.Errorf(\"generating algorithm %s: %v\", k, err)\n\t\t\t}\n\t\t\terr = algo.Add(v)\n\t\t\tif err != nil {\n\t\t\t\tq.Log.Errorf(\"adding field %s: %v\", k, err)\n\t\t\t}\n\t\t\ta.fields[k] = algo\n\t\t}\n\t}\n\tq.cache[id] = a\n}\n\nfunc (q *Quantile) Push(acc telegraf.Accumulator) {\n\tfor _, aggregate := range q.cache {\n\t\tfields := make(map[string]interface{}, len(aggregate.fields)*len(q.Quantiles))\n\t\tfor k, algo := range aggregate.fields {\n\t\t\tfor i, qtl := range q.Quantiles {\n\t\t\t\tfields[k+q.suffixes[i]] = algo.Quantile(qtl)\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(aggregate.name, fields, aggregate.tags)\n\t}\n}\n\nfunc (q *Quantile) Reset() {\n\tq.cache = make(map[uint64]aggregate)\n}\n\nfunc convert(in interface{}) (float64, bool) {\n\tswitch v := in.(type) {\n\tcase float64:\n\t\treturn v, true\n\tcase int64:\n\t\treturn float64(v), true\n\tcase uint64:\n\t\treturn float64(v), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\nfunc init() {\n\taggregators.Add(\"quantile\", func() telegraf.Aggregator {\n\t\treturn &Quantile{Compression: 100}\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/quantile/quantile_test.go",
    "content": "package quantile\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestConfigInvalidAlgorithm(t *testing.T) {\n\tq := Quantile{AlgorithmType: \"a strange one\"}\n\terr := q.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"unknown algorithm type\")\n}\n\nfunc TestConfigInvalidCompression(t *testing.T) {\n\tq := Quantile{Compression: 0, AlgorithmType: \"t-digest\"}\n\terr := q.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"cannot create \\\"t-digest\\\" algorithm\")\n}\n\nfunc TestConfigInvalidQuantiles(t *testing.T) {\n\tq := Quantile{Compression: 100, Quantiles: []float64{-0.5}}\n\terr := q.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"quantile -0.5 out of range\")\n\n\tq = Quantile{Compression: 100, Quantiles: []float64{1.5}}\n\terr = q.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"quantile 1.5 out of range\")\n\n\tq = Quantile{Compression: 100, Quantiles: []float64{0.1, 0.2, 0.3, 0.1}}\n\terr = q.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"duplicate quantile\")\n}\n\nfunc TestSingleMetricTDigest(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tCompression: 100,\n\t\tLog:         testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.75,\n\t\t\t\t\"a_050\": 49.50,\n\t\t\t\t\"a_075\": 74.25,\n\t\t\t\t\"b_025\": 24.75,\n\t\t\t\t\"b_050\": 49.50,\n\t\t\t\t\"b_075\": 74.25,\n\t\t\t\t\"c_025\": 24.75,\n\t\t\t\t\"c_050\": 49.50,\n\t\t\t\t\"c_075\": 74.25,\n\t\t\t\t\"d_025\": 24.75,\n\t\t\t\t\"d_050\": 49.50,\n\t\t\t\t\"d_075\": 74.25,\n\t\t\t\t\"e_025\": 24.75,\n\t\t\t\t\"e_050\": 49.50,\n\t\t\t\t\"e_075\": 74.25,\n\t\t\t\t\"f_025\": 24.75,\n\t\t\t\t\"f_050\": 49.50,\n\t\t\t\t\"f_075\": 74.25,\n\t\t\t\t\"g_025\": 0.2475,\n\t\t\t\t\"g_050\": 0.4950,\n\t\t\t\t\"g_075\": 0.7425,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  int32(i),\n\t\t\t\t\"b\":  int64(i),\n\t\t\t\t\"c\":  uint32(i),\n\t\t\t\t\"d\":  uint64(i),\n\t\t\t\t\"e\":  float32(i),\n\t\t\t\t\"f\":  float64(i),\n\t\t\t\t\"g\":  float64(i) / 100.0,\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metrics {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon)\n}\n\nfunc TestMultipleMetricsTDigest(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tCompression: 100,\n\t\tLog:         testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.75, \"a_050\": 49.50, \"a_075\": 74.25,\n\t\t\t\t\"b_025\": 24.75, \"b_050\": 49.50, \"b_075\": 74.25,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 49.50, \"a_050\": 99.00, \"a_075\": 148.50,\n\t\t\t\t\"b_025\": 49.50, \"b_050\": 99.00, \"b_075\": 148.50,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetricsA := make([]telegraf.Metric, 0, 100)\n\tmetricsB := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetricsA = append(metricsA, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\"a\": int64(i), \"b\": float64(i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\n\t\tmetricsB = append(metricsB, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\"a\": int64(2 * i), \"b\": float64(2 * i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metricsA {\n\t\tq.Add(m)\n\t}\n\tfor _, m := range metricsB {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\tsort := testutil.SortMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon, sort)\n}\n\nfunc TestSingleMetricExactR7(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R7\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.75,\n\t\t\t\t\"a_050\": 49.50,\n\t\t\t\t\"a_075\": 74.25,\n\t\t\t\t\"b_025\": 24.75,\n\t\t\t\t\"b_050\": 49.50,\n\t\t\t\t\"b_075\": 74.25,\n\t\t\t\t\"c_025\": 24.75,\n\t\t\t\t\"c_050\": 49.50,\n\t\t\t\t\"c_075\": 74.25,\n\t\t\t\t\"d_025\": 24.75,\n\t\t\t\t\"d_050\": 49.50,\n\t\t\t\t\"d_075\": 74.25,\n\t\t\t\t\"e_025\": 24.75,\n\t\t\t\t\"e_050\": 49.50,\n\t\t\t\t\"e_075\": 74.25,\n\t\t\t\t\"f_025\": 24.75,\n\t\t\t\t\"f_050\": 49.50,\n\t\t\t\t\"f_075\": 74.25,\n\t\t\t\t\"g_025\": 0.2475,\n\t\t\t\t\"g_050\": 0.4950,\n\t\t\t\t\"g_075\": 0.7425,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  int32(i),\n\t\t\t\t\"b\":  int64(i),\n\t\t\t\t\"c\":  uint32(i),\n\t\t\t\t\"d\":  uint64(i),\n\t\t\t\t\"e\":  float32(i),\n\t\t\t\t\"f\":  float64(i),\n\t\t\t\t\"g\":  float64(i) / 100.0,\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metrics {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon)\n}\n\nfunc TestMultipleMetricsExactR7(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R7\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.75, \"a_050\": 49.50, \"a_075\": 74.25,\n\t\t\t\t\"b_025\": 24.75, \"b_050\": 49.50, \"b_075\": 74.25,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 49.50, \"a_050\": 99.00, \"a_075\": 148.50,\n\t\t\t\t\"b_025\": 49.50, \"b_050\": 99.00, \"b_075\": 148.50,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetricsA := make([]telegraf.Metric, 0, 100)\n\tmetricsB := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetricsA = append(metricsA, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\"a\": int64(i), \"b\": float64(i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\n\t\tmetricsB = append(metricsB, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\"a\": int64(2 * i), \"b\": float64(2 * i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metricsA {\n\t\tq.Add(m)\n\t}\n\tfor _, m := range metricsB {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\tsort := testutil.SortMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon, sort)\n}\n\nfunc TestSingleMetricExactR8(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R8\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.417,\n\t\t\t\t\"a_050\": 49.500,\n\t\t\t\t\"a_075\": 74.583,\n\t\t\t\t\"b_025\": 24.417,\n\t\t\t\t\"b_050\": 49.500,\n\t\t\t\t\"b_075\": 74.583,\n\t\t\t\t\"c_025\": 24.417,\n\t\t\t\t\"c_050\": 49.500,\n\t\t\t\t\"c_075\": 74.583,\n\t\t\t\t\"d_025\": 24.417,\n\t\t\t\t\"d_050\": 49.500,\n\t\t\t\t\"d_075\": 74.583,\n\t\t\t\t\"e_025\": 24.417,\n\t\t\t\t\"e_050\": 49.500,\n\t\t\t\t\"e_075\": 74.583,\n\t\t\t\t\"f_025\": 24.417,\n\t\t\t\t\"f_050\": 49.500,\n\t\t\t\t\"f_075\": 74.583,\n\t\t\t\t\"g_025\": 0.24417,\n\t\t\t\t\"g_050\": 0.49500,\n\t\t\t\t\"g_075\": 0.74583,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  int32(i),\n\t\t\t\t\"b\":  int64(i),\n\t\t\t\t\"c\":  uint32(i),\n\t\t\t\t\"d\":  uint64(i),\n\t\t\t\t\"e\":  float32(i),\n\t\t\t\t\"f\":  float64(i),\n\t\t\t\t\"g\":  float64(i) / 100.0,\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metrics {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon)\n}\n\nfunc TestMultipleMetricsExactR8(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R8\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 24.417, \"a_050\": 49.500, \"a_075\": 74.583,\n\t\t\t\t\"b_025\": 24.417, \"b_050\": 49.500, \"b_075\": 74.583,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a_025\": 48.833, \"a_050\": 99.000, \"a_075\": 149.167,\n\t\t\t\t\"b_025\": 48.833, \"b_050\": 99.000, \"b_075\": 149.167,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\tmetricsA := make([]telegraf.Metric, 0, 100)\n\tmetricsB := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetricsA = append(metricsA, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"foo\"},\n\t\t\tmap[string]interface{}{\"a\": int64(i), \"b\": float64(i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\n\t\tmetricsB = append(metricsB, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"series\": \"bar\"},\n\t\t\tmap[string]interface{}{\"a\": int64(2 * i), \"b\": float64(2 * i), \"x1\": \"string\", \"x2\": true},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tfor _, m := range metricsA {\n\t\tq.Add(m)\n\t}\n\tfor _, m := range metricsB {\n\t\tq.Add(m)\n\t}\n\tq.Push(&acc)\n\n\tepsilon := cmpopts.EquateApprox(0, 1e-3)\n\tsort := testutil.SortMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), epsilon, sort)\n}\n\nfunc BenchmarkDefaultTDigest(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tq := Quantile{\n\t\tCompression: 100,\n\t\tLog:         testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n\nfunc BenchmarkDefaultTDigest100Q(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\tquantiles := make([]float64, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tquantiles = append(quantiles, 0.01*float64(i))\n\t}\n\n\tq := Quantile{\n\t\tCompression: 100,\n\t\tQuantiles:   quantiles,\n\t\tLog:         testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n\nfunc BenchmarkDefaultExactR7(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R7\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n\nfunc BenchmarkDefaultExactR7100Q(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\tquantiles := make([]float64, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tquantiles = append(quantiles, 0.01*float64(i))\n\t}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R7\",\n\t\tQuantiles:     quantiles,\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n\nfunc BenchmarkDefaultExactR8(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R8\",\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n\nfunc BenchmarkDefaultExactR8100Q(b *testing.B) {\n\tmetrics := make([]telegraf.Metric, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tmetrics = append(metrics, metric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\":  rand.Int31(),\n\t\t\t\t\"b\":  rand.Int63(),\n\t\t\t\t\"c\":  rand.Uint32(),\n\t\t\t\t\"d\":  rand.Uint64(),\n\t\t\t\t\"e\":  rand.Float32(),\n\t\t\t\t\"f\":  rand.Float64(),\n\t\t\t\t\"x1\": \"string\",\n\t\t\t\t\"x2\": true,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t))\n\t}\n\tquantiles := make([]float64, 0, 100)\n\tfor i := 0; i < 100; i++ {\n\t\tquantiles = append(quantiles, 0.01*float64(i))\n\t}\n\n\tq := Quantile{\n\t\tAlgorithmType: \"exact R8\",\n\t\tQuantiles:     quantiles,\n\t\tLog:           testutil.Logger{},\n\t}\n\terr := q.Init()\n\trequire.NoError(b, err)\n\n\tacc := testutil.Accumulator{}\n\tfor n := 0; n < b.N; n++ {\n\t\tfor _, m := range metrics {\n\t\t\tq.Add(m)\n\t\t}\n\t\tq.Push(&acc)\n\t}\n}\n"
  },
  {
    "path": "plugins/aggregators/quantile/sample.conf",
    "content": "# Keep the aggregate quantiles of each metric passing through.\n[[aggregators.quantile]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## Quantiles to output in the range [0,1]\n  # quantiles = [0.25, 0.5, 0.75]\n\n  ## Type of aggregation algorithm\n  ## Supported are:\n  ##  \"t-digest\" -- approximation using centroids, can cope with large number of samples\n  ##  \"exact R7\" -- exact computation also used by Excel or NumPy (Hyndman & Fan 1996 R7)\n  ##  \"exact R8\" -- exact computation (Hyndman & Fan 1996 R8)\n  ## NOTE: Do not use \"exact\" algorithms with large number of samples\n  ##       to not impair performance or memory consumption!\n  # algorithm = \"t-digest\"\n\n  ## Compression for approximation (t-digest). The value needs to be\n  ## greater or equal to 1.0. Smaller values will result in more\n  ## performance but less accuracy.\n  # compression = 100.0\n"
  },
  {
    "path": "plugins/aggregators/registry.go",
    "content": "package aggregators\n\nimport \"github.com/influxdata/telegraf\"\n\n// Creator is the function to create a new aggregator\ntype Creator func() telegraf.Aggregator\n\n// Aggregators contains the registry of all known aggregators\nvar Aggregators = make(map[string]Creator)\n\n// Add adds an aggregator to the registry. Usually this function is called in the plugin's init function\nfunc Add(name string, creator Creator) {\n\tAggregators[name] = creator\n}\n"
  },
  {
    "path": "plugins/aggregators/starlark/README.md",
    "content": "# Starlark Aggregator Plugin\n\nThis plugin allows to implement a custom aggregator plugin via a\n[Starlark][starlark] script.\n\nThe Starlark language is a dialect of Python and will be familiar to those who\nhave experience with the Python language. However, there are major\n[differences](#python-differences). Existing Python code is unlikely to work\nunmodified.\n\n> [!NOTE]\n> The execution environment is sandboxed, and it is not possible to access the\n> local filesystem or perfoming network operations. This is by design of the\n> Starlark language as a configuration language.\n\nThe Starlark script used by this plugin needs to be composed of the three\nmethods defining an aggreagtor named `add`, `push` and `reset`.\n\nThe `add` method is called as soon as a new metric is added to the plugin the\nmetrics to the aggregator. After `period`, the `push` method is called to\noutput the resulting metrics and finally the aggregation is reset by using the\n`reset` method of the Starlark script.\n\nThe Starlark functions might use the global function `state` to keep aggregation\ninformation such as added metrics etc.\n\nMore details on the syntax and available functions can be found in the\n[Starlark specification][spec].\n\n⭐ Telegraf v1.21.0\n🏷️ transformation\n💻 all\n\n[starlark]: https://github.com/google/starlark-go\n[spec]: https://github.com/google/starlark-go/blob/d1966c6b9fcd/doc/spec.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Aggregate metrics using a Starlark script\n[[aggregators.starlark]]\n  ## The Starlark source can be set as a string in this configuration file, or\n  ## by referencing a file containing the script.  Only one source or script\n  ## should be set at once.\n  ##\n  ## Source of the Starlark script.\n  source = '''\nstate = {}\n\ndef add(metric):\n  state[\"last\"] = metric\n\ndef push():\n  return state.get(\"last\")\n\ndef reset():\n  state.clear()\n'''\n\n  ## File containing a Starlark script.\n  # script = \"/usr/local/bin/myscript.star\"\n\n  ## The constants of the Starlark script.\n  # [aggregators.starlark.constants]\n  #   max_size = 10\n  #   threshold = 0.75\n  #   default_name = \"Julia\"\n  #   debug_mode = true\n```\n\n## Usage\n\nThe Starlark code should contain a function called `add` that takes a metric as\nargument.  The function will be called with each metric to add, and doesn't\nreturn anything.\n\n```python\ndef add(metric):\n  state[\"last\"] = metric\n```\n\nThe Starlark code should also contain a function called `push` that doesn't take\nany argument.  The function will be called to compute the aggregation, and\nreturns the metrics to push to the accumulator.\n\n```python\ndef push():\n  return state.get(\"last\")\n```\n\nThe Starlark code should also contain a function called `reset` that doesn't\ntake any argument.  The function will be called to reset the plugin, and doesn't\nreturn anything.\n\n```python\ndef reset():\n  state.clear()\n```\n\nFor a list of available types and functions that can be used in the code, see\nthe [Starlark specification][spec].\n\n## Python Differences\n\nRefer to the section [Python\nDifferences](../../processors/starlark/README.md#python-differences) of the\ndocumentation about the Starlark processor.\n\n## Libraries available\n\nRefer to the section [Libraries\navailable](../../processors/starlark/README.md#libraries-available) of the\ndocumentation about the Starlark processor.\n\n## Common Questions\n\nRefer to the section [Common\nQuestions](../../processors/starlark/README.md#common-questions) of the\ndocumentation about the Starlark processor.\n\n## Examples\n\n- [minmax](testdata/min_max.star)\n- [merge](testdata/merge.star)\n\n[All examples](testdata) are in the testdata folder.\n\nOpen a Pull Request to add any other useful Starlark examples.\n"
  },
  {
    "path": "plugins/aggregators/starlark/sample.conf",
    "content": "# Aggregate metrics using a Starlark script\n[[aggregators.starlark]]\n  ## The Starlark source can be set as a string in this configuration file, or\n  ## by referencing a file containing the script.  Only one source or script\n  ## should be set at once.\n  ##\n  ## Source of the Starlark script.\n  source = '''\nstate = {}\n\ndef add(metric):\n  state[\"last\"] = metric\n\ndef push():\n  return state.get(\"last\")\n\ndef reset():\n  state.clear()\n'''\n\n  ## File containing a Starlark script.\n  # script = \"/usr/local/bin/myscript.star\"\n\n  ## The constants of the Starlark script.\n  # [aggregators.starlark.constants]\n  #   max_size = 10\n  #   threshold = 0.75\n  #   default_name = \"Julia\"\n  #   debug_mode = true\n"
  },
  {
    "path": "plugins/aggregators/starlark/starlark.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage starlark\n\nimport (\n\t_ \"embed\"\n\n\t\"go.starlark.net/starlark\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/starlark\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Starlark struct {\n\tcommon.Common\n}\n\nfunc (*Starlark) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Starlark) Init() error {\n\t// Execute source\n\terr := s.Common.Init()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// The source should define an add function.\n\terr = s.AddFunction(\"add\", &common.Metric{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// The source should define a push function.\n\terr = s.AddFunction(\"push\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// The source should define a reset function.\n\terr = s.AddFunction(\"reset\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Starlark) Add(metric telegraf.Metric) {\n\tparameters, found := s.GetParameters(\"add\")\n\tif !found {\n\t\ts.Log.Errorf(\"The parameters of the add function could not be found\")\n\t\treturn\n\t}\n\tparameters[0].(*common.Metric).Wrap(metric)\n\n\t_, err := s.Call(\"add\")\n\tif err != nil {\n\t\ts.LogError(err)\n\t}\n}\n\nfunc (s *Starlark) Push(acc telegraf.Accumulator) {\n\trv, err := s.Call(\"push\")\n\tif err != nil {\n\t\ts.LogError(err)\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tswitch rv := rv.(type) {\n\tcase *starlark.List:\n\t\titer := rv.Iterate()\n\t\tdefer iter.Done()\n\t\tvar v starlark.Value\n\t\tfor iter.Next(&v) {\n\t\t\tswitch v := v.(type) {\n\t\t\tcase *common.Metric:\n\t\t\t\tm := v.Unwrap()\n\t\t\t\tacc.AddMetric(m)\n\t\t\tdefault:\n\t\t\t\ts.Log.Errorf(\"Invalid type returned in list: %s\", v.Type())\n\t\t\t}\n\t\t}\n\tcase *common.Metric:\n\t\tm := rv.Unwrap()\n\t\tacc.AddMetric(m)\n\tcase starlark.NoneType:\n\tdefault:\n\t\ts.Log.Errorf(\"Invalid type returned: %T\", rv)\n\t}\n}\n\nfunc (s *Starlark) Reset() {\n\t_, err := s.Call(\"reset\")\n\tif err != nil {\n\t\ts.LogError(err)\n\t}\n}\n\nfunc init() {\n\taggregators.Add(\"starlark\", func() telegraf.Aggregator {\n\t\treturn &Starlark{\n\t\t\tCommon: common.Common{\n\t\t\t\tStarlarkLoadFunc: common.LoadFunc,\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/starlark/starlark_test.go",
    "content": "package starlark\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/starlark\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar m1 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\": int64(1),\n\t\t\"b\": int64(1),\n\t\t\"c\": int64(1),\n\t\t\"d\": int64(1),\n\t\t\"e\": int64(1),\n\t\t\"f\": int64(2),\n\t\t\"g\": int64(2),\n\t\t\"h\": int64(2),\n\t\t\"i\": int64(2),\n\t\t\"j\": int64(3),\n\t},\n\ttime.Now(),\n)\nvar m2 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"a\":        int64(1),\n\t\t\"b\":        int64(3),\n\t\t\"c\":        int64(3),\n\t\t\"d\":        int64(3),\n\t\t\"e\":        int64(3),\n\t\t\"f\":        int64(1),\n\t\t\"g\":        int64(1),\n\t\t\"h\":        int64(1),\n\t\t\"i\":        int64(1),\n\t\t\"j\":        int64(1),\n\t\t\"k\":        int64(200),\n\t\t\"l\":        int64(200),\n\t\t\"ignoreme\": \"string\",\n\t\t\"andme\":    true,\n\t},\n\ttime.Now(),\n)\n\nfunc BenchmarkApply(b *testing.B) {\n\tminmax, err := newMinMax()\n\trequire.NoError(b, err)\n\n\tfor n := 0; n < b.N; n++ {\n\t\tminmax.Add(m1)\n\t\tminmax.Add(m2)\n\t}\n}\n\n// Test two metrics getting added.\nfunc TestMinMaxWithPeriod(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax, err := newMinMax()\n\trequire.NoError(t, err)\n\n\tminmax.Add(m1)\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": int64(1),\n\t\t\"a_min\": int64(1),\n\t\t\"b_max\": int64(3),\n\t\t\"b_min\": int64(1),\n\t\t\"c_max\": int64(3),\n\t\t\"c_min\": int64(1),\n\t\t\"d_max\": int64(3),\n\t\t\"d_min\": int64(1),\n\t\t\"e_max\": int64(3),\n\t\t\"e_min\": int64(1),\n\t\t\"f_max\": int64(2),\n\t\t\"f_min\": int64(1),\n\t\t\"g_max\": int64(2),\n\t\t\"g_min\": int64(1),\n\t\t\"h_max\": int64(2),\n\t\t\"h_min\": int64(1),\n\t\t\"i_max\": int64(2),\n\t\t\"i_min\": int64(1),\n\t\t\"j_max\": int64(3),\n\t\t\"j_min\": int64(1),\n\t\t\"k_max\": int64(200),\n\t\t\"k_min\": int64(200),\n\t\t\"l_max\": int64(200),\n\t\t\"l_min\": int64(200),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test two metrics getting added with a push/reset in between (simulates\n// getting added in different periods.)\nfunc TestMinMaxDifferentPeriods(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tminmax, err := newMinMax()\n\trequire.NoError(t, err)\n\tminmax.Add(m1)\n\tminmax.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"a_max\": int64(1),\n\t\t\"a_min\": int64(1),\n\t\t\"b_max\": int64(1),\n\t\t\"b_min\": int64(1),\n\t\t\"c_max\": int64(1),\n\t\t\"c_min\": int64(1),\n\t\t\"d_max\": int64(1),\n\t\t\"d_min\": int64(1),\n\t\t\"e_max\": int64(1),\n\t\t\"e_min\": int64(1),\n\t\t\"f_max\": int64(2),\n\t\t\"f_min\": int64(2),\n\t\t\"g_max\": int64(2),\n\t\t\"g_min\": int64(2),\n\t\t\"h_max\": int64(2),\n\t\t\"h_min\": int64(2),\n\t\t\"i_max\": int64(2),\n\t\t\"i_min\": int64(2),\n\t\t\"j_max\": int64(3),\n\t\t\"j_min\": int64(3),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n\n\tacc.ClearMetrics()\n\tminmax.Reset()\n\tminmax.Add(m2)\n\tminmax.Push(&acc)\n\texpectedFields = map[string]interface{}{\n\t\t\"a_max\": int64(1),\n\t\t\"a_min\": int64(1),\n\t\t\"b_max\": int64(3),\n\t\t\"b_min\": int64(3),\n\t\t\"c_max\": int64(3),\n\t\t\"c_min\": int64(3),\n\t\t\"d_max\": int64(3),\n\t\t\"d_min\": int64(3),\n\t\t\"e_max\": int64(3),\n\t\t\"e_min\": int64(3),\n\t\t\"f_max\": int64(1),\n\t\t\"f_min\": int64(1),\n\t\t\"g_max\": int64(1),\n\t\t\"g_min\": int64(1),\n\t\t\"h_max\": int64(1),\n\t\t\"h_min\": int64(1),\n\t\t\"i_max\": int64(1),\n\t\t\"i_min\": int64(1),\n\t\t\"j_max\": int64(1),\n\t\t\"j_min\": int64(1),\n\t\t\"k_max\": int64(200),\n\t\t\"k_min\": int64(200),\n\t\t\"l_max\": int64(200),\n\t\t\"l_min\": int64(200),\n\t}\n\texpectedTags = map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\nfunc newMinMax() (*Starlark, error) {\n\treturn newStarlarkFromScript(\"testdata/min_max.star\")\n}\n\nfunc TestSimple(t *testing.T) {\n\tplugin, err := newMerge()\n\trequire.NoError(t, err)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestNanosecondPrecision(t *testing.T) {\n\tplugin, err := newMerge()\n\n\trequire.NoError(t, err)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tacc.SetPrecision(time.Second)\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestReset(t *testing.T) {\n\tplugin, err := newMerge()\n\n\trequire.NoError(t, err)\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tplugin.Push(&acc)\n\n\tplugin.Reset()\n\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\n\tplugin.Push(&acc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_guest\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc newMerge() (*Starlark, error) {\n\treturn newStarlarkFromScript(\"testdata/merge.star\")\n}\n\nfunc TestLastFromSource(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\tplugin, err := newStarlarkFromSource(`\nstate = {}\ndef add(metric):\n  state[\"last\"] = metric\n\ndef push():\n  return state.get(\"last\")\n\ndef reset():\n  state.clear()\n`)\n\trequire.NoError(t, err)\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\tplugin.Add(\n\t\tmetric.New(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 31,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t)\n\trequire.NoError(t, err)\n\tplugin.Push(&acc)\n\texpectedFields := map[string]interface{}{\n\t\t\"time_idle\": int64(31),\n\t}\n\texpectedTags := map[string]string{\n\t\t\"cpu\": \"cpu2\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"cpu\", expectedFields, expectedTags)\n\tplugin.Reset()\n}\n\nfunc newStarlarkFromSource(source string) (*Starlark, error) {\n\tplugin := &Starlark{\n\t\tCommon: common.Common{\n\t\t\tStarlarkLoadFunc: common.LoadFunc,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tSource:           source,\n\t\t},\n\t}\n\terr := plugin.Init()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn plugin, nil\n}\n\nfunc newStarlarkFromScript(script string) (*Starlark, error) {\n\tplugin := &Starlark{\n\t\tCommon: common.Common{\n\t\t\tStarlarkLoadFunc: common.LoadFunc,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tScript:           script,\n\t\t},\n\t}\n\terr := plugin.Init()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn plugin, nil\n}\n"
  },
  {
    "path": "plugins/aggregators/starlark/testdata/merge.star",
    "content": "# Example of a merge aggregator implemented with a starlark script.\nload('time.star', 'time')\nstate = {}\ndef add(metric):\n    metrics = state.get(\"metrics\")\n    if metrics == None:\n        metrics = {}\n        state[\"metrics\"] = metrics\n        state[\"ordered\"] = []\n    gId = groupID(metric)\n    m = metrics.get(gId)\n    if m == None:\n        m = deepcopy(metric)\n        metrics[gId] = m \n        state[\"ordered\"].append(m)\n    else:\n        for k, v in metric.fields.items():\n            m.fields[k] = v\n\ndef push():\n    return state.get(\"ordered\")\n\ndef reset():\n    state.clear()\n\ndef groupID(metric):\n    key = metric.name + \"-\"\n    for k, v in metric.tags.items():\n        key = key + k + \"-\" + v + \"-\"\n    key = key + \"-\" + str(metric.time)\n    return hash(key)"
  },
  {
    "path": "plugins/aggregators/starlark/testdata/min_max.star",
    "content": "# Example of a min_max aggregator implemented with a starlark script.\n\nsupported_types = ([\"int\", \"float\"])\nstate = {}\ndef add(metric):\n    gId = groupID(metric)\n    aggregate = state.get(gId)\n    if aggregate == None:\n        aggregate = {\n            \"name\": metric.name, \n            \"tags\": metric.tags, \n            \"fields\": {}\n        }\n        for k, v in metric.fields.items():\n            if type(v) in supported_types:\n                aggregate[\"fields\"][k] = {\n\t\t\t\t    \"min\": v,\n\t\t\t\t    \"max\": v,\n\t\t\t    }\n        state[gId] = aggregate\n    else:\n        for k, v in metric.fields.items():\n            if type(v) in supported_types:\n                min_max = aggregate[\"fields\"].get(k)\n                if min_max == None:\n                    aggregate[\"fields\"][k] = {\n\t\t\t\t        \"min\": v,\n\t\t\t\t        \"max\": v,\n\t\t\t        }\n                elif v < min_max[\"min\"]:\n                    aggregate[\"fields\"][k][\"min\"] = v\n                elif v > min_max[\"max\"]:\n                    aggregate[\"fields\"][k][\"max\"] = v\n        \ndef push():\n    metrics = []\n    for a in state:\n        fields = {}\n        for k in state[a][\"fields\"]:\n            fields[k + \"_min\"] = state[a][\"fields\"][k][\"min\"]\n            fields[k + \"_max\"] = state[a][\"fields\"][k][\"max\"]\n        m = Metric(state[a][\"name\"], state[a][\"tags\"], fields)\n        metrics.append(m)\n    return metrics\n\ndef reset():\n    state.clear()\n\ndef groupID(metric):\n    key = metric.name + \"-\"\n    for k, v in metric.tags.items():\n        key = key + k + \"-\" + v\n    return hash(key)"
  },
  {
    "path": "plugins/aggregators/valuecounter/README.md",
    "content": "# Value Counter Aggregator Plugin\n\nThis plugin counts the occurrence of unique values in fields and emits the\ncounter once every `period` with the field-names being suffixed by the unique\nvalue converted to `string`.\n\n> [!NOTE]\n> The fields to be counted must be configured using the `fields` setting,\n> otherwise no field will be counted and no metric is emitted.\n\nThis plugin is useful to e.g. count the occurrances of HTTP status codes or\nother categorical values in the defined `period`.\n\n> [!IMPORTANT]\n> Counting fields with a high number of potential values may produce a\n> significant amounts of new fields and results in an increased memory usage.\n> Take care to only count fields with a limited set of values.\n\n⭐ Telegraf v1.8.0\n🏷️ statistics\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Count the occurrence of values in fields.\n[[aggregators.valuecounter]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## The fields for which the values will be counted\n  fields = [\"status\"]\n```\n\n### Measurements & Fields\n\n- measurement1\n  - field_value1\n  - field_value2\n\n### Tags\n\nNo tags are applied by this aggregator.\n\n## Example Output\n\nExample for parsing a HTTP access log.\n\ntelegraf.conf:\n\n```toml\n[[inputs.logparser]]\n  files = [\"/tmp/tst.log\"]\n  [inputs.logparser.grok]\n    patterns = ['%{DATA:url:tag} %{NUMBER:response:string}']\n    measurement = \"access\"\n\n[[aggregators.valuecounter]]\n  namepass = [\"access\"]\n  fields = [\"response\"]\n```\n\n/tmp/tst.log\n\n```text\n/some/path 200\n/some/path 401\n/some/path 200\n```\n\n```text\naccess,url=/some/path,path=/tmp/tst.log,host=localhost.localdomain response=\"200\" 1511948755991487011\naccess,url=/some/path,path=/tmp/tst.log,host=localhost.localdomain response=\"401\" 1511948755991522282\naccess,url=/some/path,path=/tmp/tst.log,host=localhost.localdomain response=\"200\" 1511948755991531697\naccess,path=/tmp/tst.log,host=localhost.localdomain,url=/some/path response_200=2i,response_401=1i 1511948761000000000\n```\n"
  },
  {
    "path": "plugins/aggregators/valuecounter/sample.conf",
    "content": "# Count the occurrence of values in fields.\n[[aggregators.valuecounter]]\n  ## General Aggregator Arguments:\n  ## The period on which to flush & clear the aggregator.\n  # period = \"30s\"\n\n  ## If true, the original metric will be dropped by the\n  ## aggregator and will not get sent to the output plugins.\n  # drop_original = false\n\n  ## The fields for which the values will be counted\n  fields = [\"status\"]\n"
  },
  {
    "path": "plugins/aggregators/valuecounter/valuecounter.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage valuecounter\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/aggregators\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype ValueCounter struct {\n\tFields []string `toml:\"fields\"`\n\n\tcache map[uint64]aggregate\n}\n\ntype aggregate struct {\n\tname       string\n\ttags       map[string]string\n\tfieldCount map[string]int\n}\n\nfunc (*ValueCounter) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (vc *ValueCounter) Add(in telegraf.Metric) {\n\tid := in.HashID()\n\n\t// Check if the cache already has an entry for this metric, if not create it\n\tif _, ok := vc.cache[id]; !ok {\n\t\ta := aggregate{\n\t\t\tname:       in.Name(),\n\t\t\ttags:       in.Tags(),\n\t\t\tfieldCount: make(map[string]int),\n\t\t}\n\t\tvc.cache[id] = a\n\t}\n\n\t// Check if this metric has fields which we need to count, if so increment\n\t// the count.\n\tfor fk, fv := range in.Fields() {\n\t\tfor _, cf := range vc.Fields {\n\t\t\tif fk == cf {\n\t\t\t\tfn := fmt.Sprintf(\"%v_%v\", fk, fv)\n\t\t\t\tvc.cache[id].fieldCount[fn]++\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (vc *ValueCounter) Push(acc telegraf.Accumulator) {\n\tfor _, agg := range vc.cache {\n\t\tfields := make(map[string]interface{}, len(agg.fieldCount))\n\t\tfor field, count := range agg.fieldCount {\n\t\t\tfields[field] = count\n\t\t}\n\n\t\tacc.AddFields(agg.name, fields, agg.tags)\n\t}\n}\n\nfunc (vc *ValueCounter) Reset() {\n\tvc.cache = make(map[uint64]aggregate)\n}\n\nfunc newValueCounter() telegraf.Aggregator {\n\tvc := &ValueCounter{}\n\tvc.Reset()\n\treturn vc\n}\n\nfunc init() {\n\taggregators.Add(\"valuecounter\", func() telegraf.Aggregator {\n\t\treturn newValueCounter()\n\t})\n}\n"
  },
  {
    "path": "plugins/aggregators/valuecounter/valuecounter_test.go",
    "content": "package valuecounter\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// Create a ValueCounter with config\nfunc newTestValueCounter(fields []string) telegraf.Aggregator {\n\tvc := &ValueCounter{\n\t\tFields: fields,\n\t}\n\tvc.Reset()\n\n\treturn vc\n}\n\nvar m1 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"status\": 200,\n\t\t\"foobar\": \"bar\",\n\t},\n\ttime.Now(),\n)\n\nvar m2 = metric.New(\"m1\",\n\tmap[string]string{\"foo\": \"bar\"},\n\tmap[string]interface{}{\n\t\t\"status\":    \"OK\",\n\t\t\"ignoreme\":  \"string\",\n\t\t\"andme\":     true,\n\t\t\"boolfield\": false,\n\t},\n\ttime.Now(),\n)\n\nfunc BenchmarkApply(b *testing.B) {\n\tvc := newTestValueCounter([]string{\"status\"})\n\n\tfor n := 0; n < b.N; n++ {\n\t\tvc.Add(m1)\n\t\tvc.Add(m2)\n\t}\n}\n\n// Test basic functionality\nfunc TestBasic(t *testing.T) {\n\tvc := newTestValueCounter([]string{\"status\"})\n\tacc := testutil.Accumulator{}\n\n\tvc.Add(m1)\n\tvc.Add(m2)\n\tvc.Add(m1)\n\tvc.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"status_200\": 2,\n\t\t\"status_OK\":  1,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test with multiple fields to count\nfunc TestMultipleFields(t *testing.T) {\n\tvc := newTestValueCounter([]string{\"status\", \"somefield\", \"boolfield\"})\n\tacc := testutil.Accumulator{}\n\n\tvc.Add(m1)\n\tvc.Add(m2)\n\tvc.Add(m2)\n\tvc.Add(m1)\n\tvc.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"status_200\":      2,\n\t\t\"status_OK\":       2,\n\t\t\"boolfield_false\": 2,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n\n// Test with a reset between two runs\nfunc TestWithReset(t *testing.T) {\n\tvc := newTestValueCounter([]string{\"status\"})\n\tacc := testutil.Accumulator{}\n\n\tvc.Add(m1)\n\tvc.Add(m1)\n\tvc.Add(m2)\n\tvc.Push(&acc)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"status_200\": 2,\n\t\t\"status_OK\":  1,\n\t}\n\texpectedTags := map[string]string{\n\t\t\"foo\": \"bar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n\n\tacc.ClearMetrics()\n\tvc.Reset()\n\n\tvc.Add(m2)\n\tvc.Add(m2)\n\tvc.Add(m1)\n\tvc.Push(&acc)\n\n\texpectedFields = map[string]interface{}{\n\t\t\"status_200\": 1,\n\t\t\"status_OK\":  2,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"m1\", expectedFields, expectedTags)\n}\n"
  },
  {
    "path": "plugins/all_test.go",
    "content": "package all\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\n// exceptionMap holds those plugins which differ in conventions when defining plugins.\n// Most plugins follow the convention of pkg-name to plugin-name.\n// For ex, Pivot processor pkg github.com/influxdata/telegraf/plugins/processors/pivot maps directly to\n// the last element of the pkg i.e \"pivot\"\n// But in case of \"aws_ec2\" processor, the pkg is defined as \"github.com/influxdata/telegraf/plugins/processors/aws/ec2\".\n// This ensures package names are not tied with plugin names.\n// it should be of the form <pkg-name>: <plugin-name>\nvar exceptionMap = map[string]string{\n\t\"github.com/influxdata/telegraf/plugins/processors/aws/ec2\": \"aws_ec2\",\n}\n\nfunc Test_AllPlugins(t *testing.T) {\n\tpluginDirs := []string{\"aggregators\", \"inputs\", \"outputs\", \"parsers\", \"processors\", \"secretstores\"}\n\tfor _, dir := range pluginDirs {\n\t\ttestPluginDirectory(t, dir)\n\t}\n}\n\nfunc testPluginDirectory(t *testing.T, directory string) {\n\tallDir := filepath.Join(directory, \"all\")\n\terr := filepath.WalkDir(allDir, func(goPluginFile string, d fs.DirEntry, walkErr error) error {\n\t\trequire.NoError(t, walkErr)\n\t\tif d.IsDir() || strings.HasSuffix(d.Name(), \"_test.go\") || strings.EqualFold(d.Name(), \"all.go\") {\n\t\t\treturn nil\n\t\t}\n\t\tt.Run(goPluginFile, func(t *testing.T) {\n\t\t\tparseSourceFile(t, goPluginFile, directory)\n\t\t})\n\t\treturn nil\n\t})\n\trequire.NoError(t, err)\n}\n\nfunc parseSourceFile(t *testing.T, goPluginFile, pluginCategory string) {\n\tfset := token.NewFileSet()\n\tnode, err := parser.ParseFile(fset, goPluginFile, nil, parser.ParseComments)\n\trequire.NoError(t, err)\n\n\tfoundGoBuild := false\n\tfor _, cg := range node.Comments {\n\t\tfor _, comm := range cg.List {\n\t\t\tif !strings.HasPrefix(comm.Text, \"//go:build\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfoundGoBuild = true\n\t\t\tplugin := resolvePluginFromImports(t, node.Imports)\n\t\t\ttestBuildTags(t, comm.Text, pluginCategory, plugin)\n\t\t}\n\t}\n\trequire.Truef(t, foundGoBuild, \"%s does not contain go:build tag\", goPluginFile)\n}\n\nfunc resolvePluginFromImports(t *testing.T, imports []*ast.ImportSpec) string {\n\t// should contain one or more import statements\n\trequire.NotEmpty(t, imports)\n\n\t// trim the path surrounded by quotes\n\timportPath := strings.Trim(imports[0].Path.Value, \"\\\"\")\n\n\t// check if present in exceptionMap\n\tplugin, ok := exceptionMap[importPath]\n\tif ok {\n\t\treturn plugin\n\t}\n\treturn filepath.Base(importPath)\n}\n\nfunc testBuildTags(t *testing.T, buildComment, pluginCategory, plugin string) {\n\ttags := strings.Split(buildComment, \"||\")\n\t// tags might contain spaces and hence trim\n\ttags = stringMap(tags, strings.TrimSpace)\n\n\trequire.Len(t, tags, 3)\n\trequire.Contains(t, tags, \"!custom\")\n\trequire.Contains(t, tags, pluginCategory)\n\n\tactual := getPluginBuildTag(tags, pluginCategory)\n\texpected := fmt.Sprintf(\"%s.%s\", pluginCategory, plugin)\n\trequire.Equal(t, expected, actual, \"invalid build tag\")\n}\n\n// getPluginBuildTag takes a slice of tags and returns the build tag corresponding to this plugin type.\n//\n// For ex [\"!custom\", \"inputs\", \"inputs.docker\"] returns \"inputs.docker\"\nfunc getPluginBuildTag(tags []string, pluginCategory string) string {\n\tfor _, tag := range tags {\n\t\tif strings.HasPrefix(tag, pluginCategory+\".\") {\n\t\t\treturn tag\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc stringMap(elems []string, transFormFunc func(string) string) []string {\n\tresult := make([]string, len(elems))\n\tfor i, elem := range elems {\n\t\tresult[i] = strings.TrimPrefix(transFormFunc(elem), \"//go:build \")\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "plugins/common/adx/adx.go",
    "content": "package adx\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/Azure/azure-kusto-go/kusto\"\n\tkustoerrors \"github.com/Azure/azure-kusto-go/kusto/data/errors\"\n\t\"github.com/Azure/azure-kusto-go/kusto/ingest\"\n\t\"github.com/Azure/azure-kusto-go/kusto/kql\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nconst (\n\tTablePerMetric = \"tablepermetric\"\n\tSingleTable    = \"singletable\"\n\t// These control the amount of memory we use when ingesting blobs\n\tbufferSize       = 1 << 20 // 1 MiB\n\tmaxBuffers       = 5\n\tManagedIngestion = \"managed\"\n\tQueuedIngestion  = \"queued\"\n)\n\ntype Config struct {\n\tEndpoint        string          `toml:\"endpoint_url\"`\n\tDatabase        string          `toml:\"database\"`\n\tTimeout         config.Duration `toml:\"timeout\"`\n\tMetricsGrouping string          `toml:\"metrics_grouping_type\"`\n\tTableName       string          `toml:\"table_name\"`\n\tCreateTables    bool            `toml:\"create_tables\"`\n\tIngestionType   string          `toml:\"ingestion_type\"`\n}\n\ntype Client struct {\n\tcfg       *Config\n\tclient    *kusto.Client\n\tingestors map[string]ingest.Ingestor\n\tlogger    telegraf.Logger\n}\n\nfunc (cfg *Config) NewClient(app string, log telegraf.Logger) (*Client, error) {\n\tif cfg.Endpoint == \"\" {\n\t\treturn nil, errors.New(\"endpoint configuration cannot be empty\")\n\t}\n\tif cfg.Database == \"\" {\n\t\treturn nil, errors.New(\"database configuration cannot be empty\")\n\t}\n\n\tcfg.MetricsGrouping = strings.ToLower(cfg.MetricsGrouping)\n\tif cfg.MetricsGrouping == SingleTable && cfg.TableName == \"\" {\n\t\treturn nil, errors.New(\"table name cannot be empty for SingleTable metrics grouping type\")\n\t}\n\n\tif cfg.MetricsGrouping == \"\" {\n\t\tcfg.MetricsGrouping = TablePerMetric\n\t}\n\n\tif cfg.MetricsGrouping != SingleTable && cfg.MetricsGrouping != TablePerMetric {\n\t\treturn nil, errors.New(\"metrics grouping type is not valid\")\n\t}\n\n\tif cfg.Timeout == 0 {\n\t\tcfg.Timeout = config.Duration(20 * time.Second)\n\t}\n\n\tswitch cfg.IngestionType {\n\tcase \"\":\n\t\tcfg.IngestionType = QueuedIngestion\n\tcase ManagedIngestion, QueuedIngestion:\n\t\t// Do nothing as those are valid\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown ingestion type %q\", cfg.IngestionType)\n\t}\n\n\tconn := kusto.NewConnectionStringBuilder(cfg.Endpoint).WithDefaultAzureCredential()\n\tconn.SetConnectorDetails(\"Telegraf\", internal.ProductToken(), app, \"\", false, \"\")\n\tclient, err := kusto.New(conn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Client{\n\t\tcfg:       cfg,\n\t\tingestors: make(map[string]ingest.Ingestor),\n\t\tlogger:    log,\n\t\tclient:    client,\n\t}, nil\n}\n\nfunc (adx *Client) Close() error {\n\tvar errs []error\n\tfor _, v := range adx.ingestors {\n\t\tif err := v.Close(); err != nil {\n\t\t\t// accumulate errors while closing ingestors\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\tif err := adx.client.Close(); err != nil {\n\t\terrs = append(errs, err)\n\t}\n\n\tadx.client = nil\n\tadx.ingestors = nil\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\t// Combine errors into a single object and return the combined error\n\treturn kustoerrors.GetCombinedError(errs...)\n}\n\nfunc (adx *Client) PushMetrics(format ingest.FileOption, tableName string, metrics []byte) error {\n\tctx := context.Background()\n\tctx, cancel := context.WithTimeout(ctx, time.Duration(adx.cfg.Timeout))\n\tdefer cancel()\n\tmetricIngestor, err := adx.getMetricIngestor(ctx, tableName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treader := bytes.NewReader(metrics)\n\tmapping := ingest.IngestionMappingRef(tableName+\"_mapping\", ingest.JSON)\n\tif metricIngestor != nil {\n\t\tif _, err := metricIngestor.FromReader(ctx, reader, format, mapping); err != nil {\n\t\t\treturn fmt.Errorf(\"sending ingestion request to Azure Data Explorer for table %q failed: %w\", tableName, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (adx *Client) getMetricIngestor(ctx context.Context, tableName string) (ingest.Ingestor, error) {\n\tif ingestor := adx.ingestors[tableName]; ingestor != nil {\n\t\treturn ingestor, nil\n\t}\n\n\tif adx.cfg.CreateTables {\n\t\tif _, err := adx.client.Mgmt(ctx, adx.cfg.Database, createTableCommand(tableName)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"creating table for %q failed: %w\", tableName, err)\n\t\t}\n\n\t\tif _, err := adx.client.Mgmt(ctx, adx.cfg.Database, createTableMappingCommand(tableName)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Create a new ingestor client for the table\n\tvar ingestor ingest.Ingestor\n\tvar err error\n\tswitch strings.ToLower(adx.cfg.IngestionType) {\n\tcase ManagedIngestion:\n\t\tingestor, err = ingest.NewManaged(adx.client, adx.cfg.Database, tableName)\n\tcase QueuedIngestion:\n\t\tingestor, err = ingest.New(adx.client, adx.cfg.Database, tableName, ingest.WithStaticBuffer(bufferSize, maxBuffers))\n\tdefault:\n\t\treturn nil, fmt.Errorf(`ingestion_type has to be one of %q or %q`, ManagedIngestion, QueuedIngestion)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating ingestor for %q failed: %w\", tableName, err)\n\t}\n\tadx.ingestors[tableName] = ingestor\n\n\treturn ingestor, nil\n}\n\nfunc createTableCommand(table string) kusto.Statement {\n\tbuilder := kql.New(`.create-merge table ['`).AddTable(table).AddLiteral(`'] `)\n\tbuilder.AddLiteral(`(['fields']:dynamic, ['name']:string, ['tags']:dynamic, ['timestamp']:datetime);`)\n\n\treturn builder\n}\n\nfunc createTableMappingCommand(table string) kusto.Statement {\n\tbuilder := kql.New(`.create-or-alter table ['`).AddTable(table).AddLiteral(`'] `)\n\tbuilder.AddLiteral(`ingestion json mapping '`).AddTable(table + \"_mapping\").AddLiteral(`' `)\n\tbuilder.AddLiteral(`'[{\"column\":\"fields\", `)\n\tbuilder.AddLiteral(`\"Properties\":{\"Path\":\"$[\\'fields\\']\"}},{\"column\":\"name\", `)\n\tbuilder.AddLiteral(`\"Properties\":{\"Path\":\"$[\\'name\\']\"}},{\"column\":\"tags\", `)\n\tbuilder.AddLiteral(`\"Properties\":{\"Path\":\"$[\\'tags\\']\"}},{\"column\":\"timestamp\", `)\n\tbuilder.AddLiteral(`\"Properties\":{\"Path\":\"$[\\'timestamp\\']\"}}]'`)\n\n\treturn builder\n}\n"
  },
  {
    "path": "plugins/common/adx/adx_test.go",
    "content": "package adx\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/Azure/azure-kusto-go/kusto\"\n\t\"github.com/Azure/azure-kusto-go/kusto/ingest\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tserializers_json \"github.com/influxdata/telegraf/plugins/serializers/json\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInitBlankEndpointData(t *testing.T) {\n\tplugin := Config{\n\t\tEndpoint: \"\",\n\t\tDatabase: \"mydb\",\n\t}\n\n\t_, err := plugin.NewClient(\"TestKusto.Telegraf\", nil)\n\trequire.Error(t, err)\n\trequire.Equal(t, \"endpoint configuration cannot be empty\", err.Error())\n}\n\nfunc TestQueryConstruction(t *testing.T) {\n\tconst tableName = \"mytable\"\n\tconst expectedCreate = `.create-merge table ['mytable'] (['fields']:dynamic, ['name']:string, ['tags']:dynamic, ['timestamp']:datetime);`\n\tconst expectedMapping = `` +\n\t\t`.create-or-alter table ['mytable'] ingestion json mapping 'mytable_mapping' '[{\"column\":\"fields\", ` +\n\t\t`\"Properties\":{\"Path\":\"$[\\'fields\\']\"}},{\"column\":\"name\", \"Properties\":{\"Path\":\"$[\\'name\\']\"}},{\"column\":\"tags\", ` +\n\t\t`\"Properties\":{\"Path\":\"$[\\'tags\\']\"}},{\"column\":\"timestamp\", \"Properties\":{\"Path\":\"$[\\'timestamp\\']\"}}]'`\n\trequire.Equal(t, expectedCreate, createTableCommand(tableName).String())\n\trequire.Equal(t, expectedMapping, createTableMappingCommand(tableName).String())\n}\n\nfunc TestGetMetricIngestor(t *testing.T) {\n\tplugin := Client{\n\t\tlogger: testutil.Logger{},\n\t\tclient: kusto.NewMockClient(),\n\t\tcfg: &Config{\n\t\t\tDatabase:      \"mydb\",\n\t\t\tIngestionType: QueuedIngestion,\n\t\t},\n\t\tingestors: map[string]ingest.Ingestor{\"test1\": &fakeIngestor{}},\n\t}\n\n\tingestor, err := plugin.getMetricIngestor(t.Context(), \"test1\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, ingestor)\n}\n\nfunc TestGetMetricIngestorNoIngester(t *testing.T) {\n\tplugin := Client{\n\t\tlogger: testutil.Logger{},\n\t\tclient: kusto.NewMockClient(),\n\t\tcfg: &Config{\n\t\t\tIngestionType: QueuedIngestion,\n\t\t},\n\t\tingestors: map[string]ingest.Ingestor{\"test1\": &fakeIngestor{}},\n\t}\n\n\tingestor, err := plugin.getMetricIngestor(t.Context(), \"test1\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, ingestor)\n}\n\nfunc TestPushMetrics(t *testing.T) {\n\tplugin := Client{\n\t\tlogger: testutil.Logger{},\n\t\tclient: kusto.NewMockClient(),\n\t\tcfg: &Config{\n\t\t\tDatabase:      \"mydb\",\n\t\t\tEndpoint:      \"https://ingest-test.westus.kusto.windows.net\",\n\t\t\tIngestionType: QueuedIngestion,\n\t\t},\n\t\tingestors: map[string]ingest.Ingestor{\"test1\": &fakeIngestor{}},\n\t}\n\n\tmetrics := []byte(`{\"fields\": {\"value\": 1}, \"name\": \"test1\", \"tags\": {\"tag1\": \"value1\"}, \"timestamp\": \"2021-01-01T00:00:00Z\"}`)\n\trequire.NoError(t, plugin.PushMetrics(ingest.FileFormat(ingest.JSON), \"test1\", metrics))\n}\n\nfunc TestPushMetricsOutputs(t *testing.T) {\n\ttestCases := []struct {\n\t\tname            string\n\t\tinputMetric     []telegraf.Metric\n\t\tmetricsGrouping string\n\t\tcreateTables    bool\n\t\tingestionType   string\n\t}{\n\t\t{\n\t\t\tname:            \"Valid metric\",\n\t\t\tinputMetric:     testutil.MockMetrics(),\n\t\t\tcreateTables:    true,\n\t\t\tmetricsGrouping: TablePerMetric,\n\t\t},\n\t\t{\n\t\t\tname:            \"Don't create tables'\",\n\t\t\tinputMetric:     testutil.MockMetrics(),\n\t\t\tcreateTables:    false,\n\t\t\tmetricsGrouping: TablePerMetric,\n\t\t},\n\t\t{\n\t\t\tname:            \"SingleTable metric grouping type\",\n\t\t\tinputMetric:     testutil.MockMetrics(),\n\t\t\tcreateTables:    true,\n\t\t\tmetricsGrouping: SingleTable,\n\t\t},\n\t\t{\n\t\t\tname:            \"Valid metric managed ingestion\",\n\t\t\tinputMetric:     testutil.MockMetrics(),\n\t\t\tcreateTables:    true,\n\t\t\tmetricsGrouping: TablePerMetric,\n\t\t\tingestionType:   ManagedIngestion,\n\t\t},\n\t}\n\tvar expectedMetric = map[string]interface{}{\n\t\t\"metricName\": \"test1\",\n\t\t\"fields\": map[string]interface{}{\n\t\t\t\"value\": 1.0,\n\t\t},\n\t\t\"tags\": map[string]interface{}{\n\t\t\t\"tag1\": \"value1\",\n\t\t},\n\t\t\"timestamp\": float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).UnixNano() / int64(time.Second)),\n\t}\n\tfor _, tC := range testCases {\n\t\tt.Run(tC.name, func(t *testing.T) {\n\t\t\tingestionType := \"queued\"\n\t\t\tif tC.ingestionType != \"\" {\n\t\t\t\tingestionType = tC.ingestionType\n\t\t\t}\n\n\t\t\tserializer := &serializers_json.Serializer{\n\t\t\t\tTimestampUnits:  config.Duration(time.Nanosecond),\n\t\t\t\tTimestampFormat: time.RFC3339Nano,\n\t\t\t}\n\n\t\t\tcfg := &Config{\n\t\t\t\tEndpoint:        \"https://someendpoint.kusto.net\",\n\t\t\t\tDatabase:        \"databasename\",\n\t\t\t\tMetricsGrouping: tC.metricsGrouping,\n\t\t\t\tTableName:       \"test1\",\n\t\t\t\tCreateTables:    tC.createTables,\n\t\t\t\tIngestionType:   ingestionType,\n\t\t\t\tTimeout:         config.Duration(20 * time.Second),\n\t\t\t}\n\t\t\tclient, err := cfg.NewClient(\"telegraf\", &testutil.Logger{})\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Inject the ingestor\n\t\t\tingestor := &fakeIngestor{}\n\t\t\tclient.ingestors[\"test1\"] = ingestor\n\n\t\t\ttableMetricGroups := make(map[string][]byte)\n\t\t\tmockmetrics := testutil.MockMetrics()\n\t\t\tfor _, m := range mockmetrics {\n\t\t\t\tmetricInBytes, err := serializer.Serialize(m)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttableMetricGroups[m.Name()] = append(tableMetricGroups[m.Name()], metricInBytes...)\n\t\t\t}\n\n\t\t\tformat := ingest.FileFormat(ingest.JSON)\n\t\t\tfor tableName, tableMetrics := range tableMetricGroups {\n\t\t\t\trequire.NoError(t, client.PushMetrics(format, tableName, tableMetrics))\n\t\t\t\tcreatedFakeIngestor := ingestor\n\t\t\t\trequire.EqualValues(t, expectedMetric[\"metricName\"], createdFakeIngestor.actualOutputMetric[\"name\"])\n\t\t\t\trequire.EqualValues(t, expectedMetric[\"fields\"], createdFakeIngestor.actualOutputMetric[\"fields\"])\n\t\t\t\trequire.EqualValues(t, expectedMetric[\"tags\"], createdFakeIngestor.actualOutputMetric[\"tags\"])\n\t\t\t\ttimestampStr := createdFakeIngestor.actualOutputMetric[\"timestamp\"].(string)\n\t\t\t\tparsedTime, err := time.Parse(time.RFC3339Nano, timestampStr)\n\t\t\t\tparsedTimeFloat := float64(parsedTime.UnixNano()) / 1e9\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.InDelta(t, expectedMetric[\"timestamp\"].(float64), parsedTimeFloat, testutil.DefaultDelta)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestAlreadyClosed(t *testing.T) {\n\tplugin := Client{\n\t\tlogger: testutil.Logger{},\n\t\tcfg: &Config{\n\t\t\tIngestionType: QueuedIngestion,\n\t\t},\n\t\tclient: kusto.NewMockClient(),\n\t}\n\trequire.NoError(t, plugin.Close())\n}\n\ntype fakeIngestor struct {\n\tactualOutputMetric map[string]interface{}\n}\n\nfunc (f *fakeIngestor) FromReader(_ context.Context, reader io.Reader, _ ...ingest.FileOption) (*ingest.Result, error) {\n\tscanner := bufio.NewScanner(reader)\n\tscanner.Scan()\n\tfirstLine := scanner.Text()\n\terr := json.Unmarshal([]byte(firstLine), &f.actualOutputMetric)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ingest.Result{}, nil\n}\n\nfunc (*fakeIngestor) FromFile(_ context.Context, _ string, _ ...ingest.FileOption) (*ingest.Result, error) {\n\treturn &ingest.Result{}, nil\n}\n\nfunc (*fakeIngestor) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/auth/basic_auth.go",
    "content": "package auth\n\nimport (\n\t\"crypto/subtle\"\n\t\"net/http\"\n)\n\ntype BasicAuth struct {\n\tUsername string `toml:\"username\"`\n\tPassword string `toml:\"password\"`\n}\n\nfunc (b *BasicAuth) Verify(r *http.Request) bool {\n\tif b.Username == \"\" && b.Password == \"\" {\n\t\treturn true\n\t}\n\n\tusername, password, ok := r.BasicAuth()\n\n\tusernameComparison := subtle.ConstantTimeCompare([]byte(username), []byte(b.Username)) == 1\n\tpasswordComparison := subtle.ConstantTimeCompare([]byte(password), []byte(b.Password)) == 1\n\treturn ok && usernameComparison && passwordComparison\n}\n"
  },
  {
    "path": "plugins/common/auth/basic_auth_test.go",
    "content": "package auth\n\nimport (\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBasicAuth_VerifyWithCredentials(t *testing.T) {\n\tauth := BasicAuth{\"username\", \"password\"}\n\n\tr := httptest.NewRequest(\"GET\", \"/github\", nil)\n\tr.SetBasicAuth(auth.Username, auth.Password)\n\n\trequire.True(t, auth.Verify(r))\n}\n\nfunc TestBasicAuth_VerifyWithoutCredentials(t *testing.T) {\n\tauth := BasicAuth{}\n\n\tr := httptest.NewRequest(\"GET\", \"/github\", nil)\n\n\trequire.True(t, auth.Verify(r))\n}\n\nfunc TestBasicAuth_VerifyWithInvalidCredentials(t *testing.T) {\n\tauth := BasicAuth{\"username\", \"password\"}\n\n\tr := httptest.NewRequest(\"GET\", \"/github\", nil)\n\tr.SetBasicAuth(\"wrong-username\", \"wrong-password\")\n\n\trequire.False(t, auth.Verify(r))\n}\n"
  },
  {
    "path": "plugins/common/aws/credentials.go",
    "content": "package aws\n\nimport (\n\t\"context\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/credentials\"\n\t\"github.com/aws/aws-sdk-go-v2/credentials/stscreds\"\n\t\"github.com/aws/aws-sdk-go-v2/service/sts\"\n)\n\ntype CredentialConfig struct {\n\tRegion               string `toml:\"region\"`\n\tAccessKey            string `toml:\"access_key\"`\n\tSecretKey            string `toml:\"secret_key\"`\n\tRoleARN              string `toml:\"role_arn\"`\n\tProfile              string `toml:\"profile\"`\n\tFilename             string `toml:\"shared_credential_file\"`\n\tToken                string `toml:\"token\"`\n\tEndpointURL          string `toml:\"endpoint_url\"`\n\tRoleSessionName      string `toml:\"role_session_name\"`\n\tWebIdentityTokenFile string `toml:\"web_identity_token_file\"`\n}\n\nfunc (c *CredentialConfig) Credentials() (aws.Config, error) {\n\tif c.RoleARN != \"\" {\n\t\treturn c.configWithAssumeCredentials()\n\t}\n\treturn c.configWithRootCredentials()\n}\n\nfunc (c *CredentialConfig) configWithRootCredentials() (aws.Config, error) {\n\toptions := []func(*config.LoadOptions) error{\n\t\tconfig.WithRegion(c.Region),\n\t}\n\n\tif c.Profile != \"\" {\n\t\toptions = append(options, config.WithSharedConfigProfile(c.Profile))\n\t}\n\tif c.Filename != \"\" {\n\t\toptions = append(options, config.WithSharedCredentialsFiles([]string{c.Filename}))\n\t}\n\n\tif c.AccessKey != \"\" || c.SecretKey != \"\" {\n\t\tprovider := credentials.NewStaticCredentialsProvider(c.AccessKey, c.SecretKey, c.Token)\n\t\toptions = append(options, config.WithCredentialsProvider(provider))\n\t}\n\n\treturn config.LoadDefaultConfig(context.Background(), options...)\n}\n\nfunc (c *CredentialConfig) configWithAssumeCredentials() (aws.Config, error) {\n\t// To generate credentials using assumeRole, we need to create AWS STS client with the default AWS endpoint,\n\tdefaultConfig, err := c.configWithRootCredentials()\n\tif err != nil {\n\t\treturn aws.Config{}, err\n\t}\n\n\tvar provider aws.CredentialsProvider\n\tstsService := sts.NewFromConfig(defaultConfig)\n\tif c.WebIdentityTokenFile != \"\" {\n\t\tprovider = stscreds.NewWebIdentityRoleProvider(\n\t\t\tstsService,\n\t\t\tc.RoleARN,\n\t\t\tstscreds.IdentityTokenFile(c.WebIdentityTokenFile),\n\t\t\tfunc(opts *stscreds.WebIdentityRoleOptions) {\n\t\t\t\tif c.RoleSessionName != \"\" {\n\t\t\t\t\topts.RoleSessionName = c.RoleSessionName\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t} else {\n\t\tprovider = stscreds.NewAssumeRoleProvider(stsService, c.RoleARN, func(opts *stscreds.AssumeRoleOptions) {\n\t\t\tif c.RoleSessionName != \"\" {\n\t\t\t\topts.RoleSessionName = c.RoleSessionName\n\t\t\t}\n\t\t})\n\t}\n\n\tdefaultConfig.Credentials = aws.NewCredentialsCache(provider)\n\treturn defaultConfig, nil\n}\n"
  },
  {
    "path": "plugins/common/cookie/cookie.go",
    "content": "package cookie\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tclockutil \"github.com/benbjohnson/clock\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype CookieAuthConfig struct {\n\tURL    string `toml:\"cookie_auth_url\"`\n\tMethod string `toml:\"cookie_auth_method\"`\n\n\tHeaders map[string]*config.Secret `toml:\"cookie_auth_headers\"`\n\n\t// HTTP Basic Auth Credentials\n\tUsername string `toml:\"cookie_auth_username\"`\n\tPassword string `toml:\"cookie_auth_password\"`\n\n\tBody    string          `toml:\"cookie_auth_body\"`\n\tRenewal config.Duration `toml:\"cookie_auth_renewal\"`\n\n\tclient *http.Client\n\twg     sync.WaitGroup\n}\n\nfunc (c *CookieAuthConfig) Start(client *http.Client, log telegraf.Logger, clock clockutil.Clock) (err error) {\n\tif err := c.initializeClient(client); err != nil {\n\t\treturn err\n\t}\n\n\t// continual auth renewal if set\n\tif c.Renewal > 0 {\n\t\tticker := clock.Ticker(time.Duration(c.Renewal))\n\t\t// this context is used in the tests only, it is to cancel the goroutine\n\t\tgo c.authRenewal(context.Background(), ticker, log)\n\t}\n\n\treturn nil\n}\n\nfunc (c *CookieAuthConfig) initializeClient(client *http.Client) (err error) {\n\tc.client = client\n\n\tif c.Method == \"\" {\n\t\tc.Method = http.MethodPost\n\t}\n\n\treturn c.auth()\n}\n\nfunc (c *CookieAuthConfig) authRenewal(ctx context.Context, ticker *clockutil.Ticker, log telegraf.Logger) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tc.wg.Done()\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t\tif err := c.auth(); err != nil && log != nil {\n\t\t\t\tlog.Errorf(\"renewal failed for %q: %v\", c.URL, err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *CookieAuthConfig) auth() error {\n\tvar err error\n\n\t// everytime we auth we clear out the cookie jar to ensure that the cookie\n\t// is not used as a part of re-authing. The only way to empty or reset is\n\t// to create a new cookie jar.\n\tc.client.Jar, err = cookiejar.New(nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar body io.Reader\n\tif c.Body != \"\" {\n\t\tbody = strings.NewReader(c.Body)\n\t}\n\n\treq, err := http.NewRequest(c.Method, c.URL, body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif c.Username != \"\" {\n\t\treq.SetBasicAuth(c.Username, c.Password)\n\t}\n\n\tfor k, v := range c.Headers {\n\t\tsecret, err := v.Get()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\theaderVal := secret.String()\n\t\tif strings.EqualFold(k, \"host\") {\n\t\t\treq.Host = headerVal\n\t\t} else {\n\t\t\treq.Header.Add(k, headerVal)\n\t\t}\n\n\t\tsecret.Destroy()\n\t}\n\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif resp.StatusCode < 200 || resp.StatusCode > 299 {\n\t\treturn fmt.Errorf(\"cookie auth renewal received status code: %v (%v) [%v]\",\n\t\t\tresp.StatusCode,\n\t\t\thttp.StatusText(resp.StatusCode),\n\t\t\tstring(respBody),\n\t\t)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/cookie/cookie_test.go",
    "content": "package cookie\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\tclockutil \"github.com/benbjohnson/clock\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\treqUser      = \"testUser\"\n\treqPasswd    = \"testPassword\"\n\treqBody      = \"a body\"\n\treqHeaderKey = \"hello\"\n\treqHeaderVal = \"world\"\n\n\tauthEndpointNoCreds                   = \"/auth\"\n\tauthEndpointWithBasicAuth             = \"/authWithCreds\"\n\tauthEndpointWithBasicAuthOnlyUsername = \"/authWithCredsUser\"\n\tauthEndpointWithBody                  = \"/authWithBody\"\n\tauthEndpointWithHeader                = \"/authWithHeader\"\n)\n\nvar fakeCookie = &http.Cookie{\n\tName:  \"test-cookie\",\n\tValue: \"this is an auth cookie\",\n}\n\nvar reqHeaderValSecret = config.NewSecret([]byte(reqHeaderVal))\n\ntype fakeServer struct {\n\t*httptest.Server\n\t*int32\n}\n\nfunc newFakeServer(t *testing.T) fakeServer {\n\tvar c int32\n\treturn fakeServer{\n\t\tServer: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tauthed := func() {\n\t\t\t\tatomic.AddInt32(&c, 1)        // increment auth counter\n\t\t\t\thttp.SetCookie(w, fakeCookie) // set fake cookie\n\t\t\t}\n\t\t\tswitch r.URL.Path {\n\t\t\tcase authEndpointNoCreds:\n\t\t\t\tauthed()\n\t\t\tcase authEndpointWithHeader:\n\t\t\t\tif !cmp.Equal(r.Header.Get(reqHeaderKey), reqHeaderVal) {\n\t\t\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tauthed()\n\t\t\tcase authEndpointWithBody:\n\t\t\t\tbody, err := io.ReadAll(r.Body)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif !cmp.Equal([]byte(reqBody), body) {\n\t\t\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tauthed()\n\t\t\tcase authEndpointWithBasicAuth:\n\t\t\t\tu, p, ok := r.BasicAuth()\n\t\t\t\tif !ok || u != reqUser || p != reqPasswd {\n\t\t\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tauthed()\n\t\t\tcase authEndpointWithBasicAuthOnlyUsername:\n\t\t\t\tu, p, ok := r.BasicAuth()\n\t\t\t\tif !ok || u != reqUser || p != \"\" {\n\t\t\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tauthed()\n\t\t\tdefault:\n\t\t\t\t// ensure cookie exists on request\n\t\t\t\tif _, err := r.Cookie(fakeCookie.Name); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif _, err := w.Write([]byte(\"good test response\")); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})),\n\t\tint32: &c,\n\t}\n}\n\nfunc (s fakeServer) checkResp(t *testing.T, expCode int) {\n\tt.Helper()\n\tresp, err := s.Client().Get(s.URL + \"/endpoint\")\n\trequire.NoError(t, err)\n\tdefer resp.Body.Close()\n\trequire.Equal(t, expCode, resp.StatusCode)\n\n\tif expCode == http.StatusOK {\n\t\trequire.Len(t, resp.Request.Cookies(), 1)\n\t\trequire.Equal(t, \"test-cookie\", resp.Request.Cookies()[0].Name)\n\t}\n}\n\nfunc (s fakeServer) checkAuthCount(t *testing.T, atLeast int32) {\n\tt.Helper()\n\trequire.GreaterOrEqual(t, atomic.LoadInt32(s.int32), atLeast)\n}\n\nfunc TestAuthConfig_Start(t *testing.T) {\n\tconst (\n\t\trenewal      = 50 * time.Millisecond\n\t\trenewalCheck = 5 * renewal\n\t)\n\ttype fields struct {\n\t\tMethod   string\n\t\tUsername string\n\t\tPassword string\n\t\tBody     string\n\t\tHeaders  map[string]*config.Secret\n\t}\n\ttype args struct {\n\t\trenewal  time.Duration\n\t\tendpoint string\n\t}\n\ttests := []struct {\n\t\tname              string\n\t\tfields            fields\n\t\targs              args\n\t\twantErr           error\n\t\tfirstAuthCount    int32\n\t\tlastAuthCount     int32\n\t\tfirstHTTPResponse int\n\t\tlastHTTPResponse  int\n\t}{\n\t\t{\n\t\t\tname: \"success no creds, no body, default method\",\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointNoCreds,\n\t\t\t},\n\t\t\tfirstAuthCount:    1,\n\t\t\tlastAuthCount:     3,\n\t\t\tfirstHTTPResponse: http.StatusOK,\n\t\t\tlastHTTPResponse:  http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname: \"success no creds, no body, default method, header set\",\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointWithHeader,\n\t\t\t},\n\t\t\tfields: fields{\n\t\t\t\tHeaders: map[string]*config.Secret{reqHeaderKey: &reqHeaderValSecret},\n\t\t\t},\n\t\t\tfirstAuthCount:    1,\n\t\t\tlastAuthCount:     3,\n\t\t\tfirstHTTPResponse: http.StatusOK,\n\t\t\tlastHTTPResponse:  http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname: \"success with creds, no body\",\n\t\t\tfields: fields{\n\t\t\t\tMethod:   http.MethodPost,\n\t\t\t\tUsername: reqUser,\n\t\t\t\tPassword: reqPasswd,\n\t\t\t},\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointWithBasicAuth,\n\t\t\t},\n\t\t\tfirstAuthCount:    1,\n\t\t\tlastAuthCount:     3,\n\t\t\tfirstHTTPResponse: http.StatusOK,\n\t\t\tlastHTTPResponse:  http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname: \"failure with bad creds\",\n\t\t\tfields: fields{\n\t\t\t\tMethod:   http.MethodPost,\n\t\t\t\tUsername: reqUser,\n\t\t\t\tPassword: \"a bad password\",\n\t\t\t},\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointWithBasicAuth,\n\t\t\t},\n\t\t\twantErr:           errors.New(\"cookie auth renewal received status code: 401 (Unauthorized) []\"),\n\t\t\tfirstAuthCount:    0,\n\t\t\tlastAuthCount:     0,\n\t\t\tfirstHTTPResponse: http.StatusForbidden,\n\t\t\tlastHTTPResponse:  http.StatusForbidden,\n\t\t},\n\t\t{\n\t\t\tname: \"success with no creds, with good body\",\n\t\t\tfields: fields{\n\t\t\t\tMethod: http.MethodPost,\n\t\t\t\tBody:   reqBody,\n\t\t\t},\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointWithBody,\n\t\t\t},\n\t\t\tfirstAuthCount:    1,\n\t\t\tlastAuthCount:     3,\n\t\t\tfirstHTTPResponse: http.StatusOK,\n\t\t\tlastHTTPResponse:  http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname: \"failure with bad body\",\n\t\t\tfields: fields{\n\t\t\t\tMethod: http.MethodPost,\n\t\t\t\tBody:   \"a bad body\",\n\t\t\t},\n\t\t\targs: args{\n\t\t\t\trenewal:  renewal,\n\t\t\t\tendpoint: authEndpointWithBody,\n\t\t\t},\n\t\t\twantErr:           errors.New(\"cookie auth renewal received status code: 401 (Unauthorized) []\"),\n\t\t\tfirstAuthCount:    0,\n\t\t\tlastAuthCount:     0,\n\t\t\tfirstHTTPResponse: http.StatusForbidden,\n\t\t\tlastHTTPResponse:  http.StatusForbidden,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tsrv := newFakeServer(t)\n\t\t\tc := &CookieAuthConfig{\n\t\t\t\tURL:      srv.URL + tt.args.endpoint,\n\t\t\t\tMethod:   tt.fields.Method,\n\t\t\t\tUsername: tt.fields.Username,\n\t\t\t\tPassword: tt.fields.Password,\n\t\t\t\tBody:     tt.fields.Body,\n\t\t\t\tHeaders:  tt.fields.Headers,\n\t\t\t\tRenewal:  config.Duration(tt.args.renewal),\n\t\t\t}\n\t\t\tif err := c.initializeClient(srv.Client()); tt.wantErr != nil {\n\t\t\t\trequire.EqualError(t, err, tt.wantErr.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\tmock := clockutil.NewMock()\n\t\t\tticker := mock.Ticker(time.Duration(c.Renewal))\n\t\t\tdefer ticker.Stop()\n\n\t\t\tc.wg.Add(1)\n\t\t\tctx, cancel := context.WithCancel(t.Context())\n\t\t\tgo c.authRenewal(ctx, ticker, testutil.Logger{Name: \"cookie_auth\"})\n\n\t\t\tsrv.checkAuthCount(t, tt.firstAuthCount)\n\t\t\tsrv.checkResp(t, tt.firstHTTPResponse)\n\t\t\tmock.Add(renewalCheck)\n\n\t\t\t// Ensure that the auth renewal goroutine has completed\n\t\t\trequire.Eventually(t, func() bool { return atomic.LoadInt32(srv.int32) >= tt.lastAuthCount }, time.Second, 10*time.Millisecond)\n\n\t\t\tcancel()\n\t\t\tc.wg.Wait()\n\t\t\tsrv.checkAuthCount(t, tt.lastAuthCount)\n\t\t\tsrv.checkResp(t, tt.lastHTTPResponse)\n\n\t\t\tsrv.Close()\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/docker/stats_helpers.go",
    "content": "// Package docker contains few helper functions copied from\n// https://github.com/docker/cli/blob/master/cli/command/container/stats_helpers.go\npackage docker\n\nimport (\n\t\"github.com/docker/docker/api/types/container\"\n)\n\n// CalculateCPUPercentUnix calculate CPU usage (for Unix, in percentages)\nfunc CalculateCPUPercentUnix(previousCPU, previousSystem uint64, v *container.StatsResponse) float64 {\n\tvar (\n\t\tcpuPercent = 0.0\n\t\t// calculate the change for the cpu usage of the container in between readings\n\t\tcpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)\n\t\t// calculate the change for the entire system between readings\n\t\tsystemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)\n\t\tonlineCPUs  = float64(v.CPUStats.OnlineCPUs)\n\t)\n\n\tif onlineCPUs == 0.0 {\n\t\tonlineCPUs = float64(len(v.CPUStats.CPUUsage.PercpuUsage))\n\t}\n\tif systemDelta > 0.0 && cpuDelta > 0.0 {\n\t\tcpuPercent = (cpuDelta / systemDelta) * onlineCPUs * 100.0\n\t}\n\treturn cpuPercent\n}\n\n// CalculateCPUPercentWindows calculate CPU usage (for Windows, in percentages)\nfunc CalculateCPUPercentWindows(v *container.StatsResponse) float64 {\n\t// Max number of 100ns intervals between the previous time read and now\n\tpossIntervals := uint64(v.Read.Sub(v.PreRead).Nanoseconds()) // Start with number of ns intervals\n\tpossIntervals /= 100                                         // Convert to number of 100ns intervals\n\tpossIntervals *= uint64(v.NumProcs)                          // Multiple by the number of processors\n\n\t// Intervals used\n\tintervalsUsed := v.CPUStats.CPUUsage.TotalUsage - v.PreCPUStats.CPUUsage.TotalUsage\n\n\t// Percentage avoiding divide-by-zero\n\tif possIntervals > 0 {\n\t\treturn float64(intervalsUsed) / float64(possIntervals) * 100.0\n\t}\n\treturn 0.00\n}\n\n// CalculateMemUsageUnixNoCache calculate memory usage of the container.\n// Cache is intentionally excluded to avoid misinterpretation of the output.\n//\n// On Docker 19.03 and older, the result is `mem.Usage - mem.Stats[\"cache\"]`.\n// On new docker with cgroup v1 host, the result is `mem.Usage - mem.Stats[\"total_inactive_file\"]`.\n// On new docker with cgroup v2 host, the result is `mem.Usage - mem.Stats[\"inactive_file\"]`.\n//\n// This definition is designed to be consistent with past values and the latest docker CLI\n// * https://github.com/docker/cli/blob/6e2838e18645e06f3e4b6c5143898ccc44063e3b/cli/command/container/stats_helpers.go#L239\nfunc CalculateMemUsageUnixNoCache(mem container.MemoryStats) float64 {\n\t// Docker 19.03 and older\n\tif v, isOldDocker := mem.Stats[\"cache\"]; isOldDocker && v < mem.Usage {\n\t\treturn float64(mem.Usage - v)\n\t}\n\t// cgroup v1\n\tif v, isCgroup1 := mem.Stats[\"total_inactive_file\"]; isCgroup1 && v < mem.Usage {\n\t\treturn float64(mem.Usage - v)\n\t}\n\t// cgroup v2\n\tif v := mem.Stats[\"inactive_file\"]; v < mem.Usage {\n\t\treturn float64(mem.Usage - v)\n\t}\n\treturn float64(mem.Usage)\n}\n\n// CalculateMemPercentUnixNoCache calculate memory usage of the container, in percentages.\nfunc CalculateMemPercentUnixNoCache(limit, usedNoCache float64) float64 {\n\t// MemoryStats.Limit will never be 0 unless the container is not running and we haven't\n\t// got any data from cgroup\n\tif limit != 0 {\n\t\treturn usedNoCache / limit * 100.0\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "plugins/common/encoding/decoder.go",
    "content": "package encoding\n\nimport (\n\t\"errors\"\n\n\t\"golang.org/x/text/encoding\"\n\t\"golang.org/x/text/encoding/unicode\"\n)\n\n// NewDecoder returns an x/text Decoder for the specified text encoding.  The\n// Decoder converts a character encoding into utf-8 bytes.  If a BOM is found\n// it will be converted into an utf-8 BOM, you can use\n// github.com/dimchansky/utfbom to strip the BOM.\n//\n// The \"none\" or \"\" encoding will pass through bytes unchecked.  Use the utf-8\n// encoding if you want invalid bytes replaced using the unicode\n// replacement character.\n//\n// Detection of utf-16 endianness using the BOM is not currently provided due\n// to the tail input plugins requirement to be able to start at the middle or\n// end of the file.\nfunc NewDecoder(enc string) (*Decoder, error) {\n\tswitch enc {\n\tcase \"utf-8\":\n\t\treturn createDecoder(unicode.UTF8.NewDecoder()), nil\n\tcase \"utf-16le\":\n\t\treturn createDecoder(unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder()), nil\n\tcase \"utf-16be\":\n\t\treturn createDecoder(unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM).NewDecoder()), nil\n\tcase \"none\", \"\":\n\t\treturn createDecoder(encoding.Nop.NewDecoder()), nil\n\t}\n\treturn nil, errors.New(\"unknown character encoding\")\n}\n"
  },
  {
    "path": "plugins/common/encoding/decoder_reader.go",
    "content": "package encoding\n\nimport (\n\t\"errors\"\n\t\"io\"\n\n\t\"golang.org/x/text/transform\"\n)\n\n// Other than resetting r.err and r.transformComplete in Read() this\n// was copied from x/text\n\nfunc createDecoder(t transform.Transformer) *Decoder {\n\treturn &Decoder{Transformer: t}\n}\n\n// A Decoder converts bytes to UTF-8. It implements transform.Transformer.\n//\n// Transforming source bytes that are not of that encoding will not result in an\n// error per se. Each byte that cannot be transcoded will be represented in the\n// output by the UTF-8 encoding of '\\uFFFD', the replacement rune.\ntype Decoder struct {\n\ttransform.Transformer\n\n\t// This forces external creators of Decoders to use names in struct\n\t// initializers, allowing for future extensibility without having to break\n\t// code.\n\t_ struct{}\n}\n\n// Bytes converts the given encoded bytes to UTF-8. It returns the converted\n// bytes or nil, err if any error occurred.\nfunc (d *Decoder) Bytes(b []byte) ([]byte, error) {\n\tb, _, err := transform.Bytes(d, b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b, nil\n}\n\n// String converts the given encoded string to UTF-8. It returns the converted\n// string or \"\", err if any error occurred.\nfunc (d *Decoder) String(s string) (string, error) {\n\ts, _, err := transform.String(d, s)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn s, nil\n}\n\n// Reader wraps another Reader to decode its bytes.\n//\n// The Decoder may not be used for any other operation as long as the returned\n// Reader is in use.\nfunc (d *Decoder) Reader(r io.Reader) io.Reader {\n\treturn NewReader(r, d)\n}\n\n// Reader wraps another io.Reader by transforming the bytes read.\ntype Reader struct {\n\tr   io.Reader\n\tt   transform.Transformer\n\terr error\n\n\t// dst[dst0:dst1] contains bytes that have been transformed by t but\n\t// not yet copied out via Read.\n\tdst        []byte\n\tdst0, dst1 int\n\n\t// src[src0:src1] contains bytes that have been read from r but not\n\t// yet transformed through t.\n\tsrc        []byte\n\tsrc0, src1 int\n\n\t// transformComplete is whether the transformation is complete,\n\t// regardless of whether it was successful.\n\ttransformComplete bool\n}\n\nvar (\n\t// errInconsistentByteCount means that Transform returned success (nil\n\t// error) but also returned nSrc inconsistent with the src argument.\n\terrInconsistentByteCount = errors.New(\"transform: inconsistent byte count returned\")\n)\n\nconst defaultBufSize = 4096\n\n// NewReader returns a new Reader that wraps r by transforming the bytes read\n// via t. It calls Reset on t.\nfunc NewReader(r io.Reader, t transform.Transformer) *Reader {\n\tt.Reset()\n\treturn &Reader{\n\t\tr:   r,\n\t\tt:   t,\n\t\tdst: make([]byte, defaultBufSize),\n\t\tsrc: make([]byte, defaultBufSize),\n\t}\n}\n\n// Read implements the io.Reader interface.\nfunc (r *Reader) Read(p []byte) (int, error) {\n\t// Clear previous errors so a Read can be performed even if the last call\n\t// returned EOF.\n\tr.err = nil\n\tr.transformComplete = false\n\n\tn := 0\n\tfor {\n\t\t// Copy out any transformed bytes and return the final error if we are done.\n\t\tif r.dst0 != r.dst1 {\n\t\t\tn = copy(p, r.dst[r.dst0:r.dst1])\n\t\t\tr.dst0 += n\n\t\t\tif r.dst0 == r.dst1 && r.transformComplete {\n\t\t\t\treturn n, r.err\n\t\t\t}\n\t\t\treturn n, nil\n\t\t} else if r.transformComplete {\n\t\t\treturn 0, r.err\n\t\t}\n\n\t\t// Try to transform some source bytes, or to flush the transformer if we\n\t\t// are out of source bytes. We do this even if r.r.Read returned an error.\n\t\t// As the io.Reader documentation says, \"process the n > 0 bytes returned\n\t\t// before considering the error\".\n\t\tif r.src0 != r.src1 || r.err != nil {\n\t\t\tvar err error\n\t\t\tr.dst0 = 0\n\t\t\tr.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], errors.Is(r.err, io.EOF))\n\t\t\tr.src0 += n\n\n\t\t\tswitch {\n\t\t\tcase err == nil:\n\t\t\t\tif r.src0 != r.src1 {\n\t\t\t\t\tr.err = errInconsistentByteCount\n\t\t\t\t}\n\t\t\t\t// The Transform call was successful; we are complete if we\n\t\t\t\t// cannot read more bytes into src.\n\t\t\t\tr.transformComplete = r.err != nil\n\t\t\t\tcontinue\n\t\t\tcase errors.Is(err, transform.ErrShortDst) && (r.dst1 != 0 || n != 0):\n\t\t\t\t// Make room in dst by copying out, and try again.\n\t\t\t\tcontinue\n\t\t\tcase errors.Is(err, transform.ErrShortSrc) && r.src1-r.src0 != len(r.src) && r.err == nil:\n\t\t\t\t// Read more bytes into src via the code below, and try again.\n\t\t\tdefault:\n\t\t\t\tr.transformComplete = true\n\t\t\t\t// The reader error (r.err) takes precedence over the\n\t\t\t\t// transformer error (err) unless r.err is nil or io.EOF.\n\t\t\t\tif r.err == nil || errors.Is(r.err, io.EOF) {\n\t\t\t\t\tr.err = err\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Move any untransformed source bytes to the start of the buffer\n\t\t// and read more bytes.\n\t\tif r.src0 != 0 {\n\t\t\tr.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])\n\t\t}\n\t\tn, r.err = r.r.Read(r.src[r.src1:])\n\t\tr.src1 += n\n\t}\n}\n"
  },
  {
    "path": "plugins/common/encoding/decoder_test.go",
    "content": "package encoding\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDecoder(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tencoding    string\n\t\tinput       []byte\n\t\texpected    []byte\n\t\texpectedErr bool\n\t}{\n\t\t{\n\t\t\tname:     \"no decoder utf-8\",\n\t\t\tencoding: \"\",\n\t\t\tinput:    []byte(\"howdy\"),\n\t\t\texpected: []byte(\"howdy\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-8 decoder\",\n\t\t\tencoding: \"utf-8\",\n\t\t\tinput:    []byte(\"howdy\"),\n\t\t\texpected: []byte(\"howdy\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-8 decoder invalid bytes replaced with replacement char\",\n\t\t\tencoding: \"utf-8\",\n\t\t\tinput:    []byte(\"\\xff\\xfe\"),\n\t\t\texpected: []byte(\"\\uFFFD\\uFFFD\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-16le decoder no BOM\",\n\t\t\tencoding: \"utf-16le\",\n\t\t\tinput:    []byte(\"h\\x00o\\x00w\\x00d\\x00y\\x00\"),\n\t\t\texpected: []byte(\"howdy\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-16le decoder with BOM\",\n\t\t\tencoding: \"utf-16le\",\n\t\t\tinput:    []byte(\"\\xff\\xfeh\\x00o\\x00w\\x00d\\x00y\\x00\"),\n\t\t\texpected: []byte(\"\\xef\\xbb\\xbfhowdy\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-16be decoder no BOM\",\n\t\t\tencoding: \"utf-16be\",\n\t\t\tinput:    []byte(\"\\x00h\\x00o\\x00w\\x00d\\x00y\"),\n\t\t\texpected: []byte(\"howdy\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"utf-16be decoder with BOM\",\n\t\t\tencoding: \"utf-16be\",\n\t\t\tinput:    []byte(\"\\xfe\\xff\\x00h\\x00o\\x00w\\x00d\\x00y\"),\n\t\t\texpected: []byte(\"\\xef\\xbb\\xbfhowdy\"),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdecoder, err := NewDecoder(tt.encoding)\n\t\t\trequire.NoError(t, err)\n\t\t\tbuf := bytes.NewBuffer(tt.input)\n\t\t\tr := decoder.Reader(buf)\n\t\t\tactual, err := io.ReadAll(r)\n\t\t\tif tt.expectedErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/gcp/auth.go",
    "content": "package gcp\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc ParseCredentialType(credentialsFile string) (string, error) {\n\tserviceAccount, err := os.ReadFile(credentialsFile)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"cannot load the credential file: %w\", err)\n\t}\n\n\ttype fileTypeChecker struct {\n\t\tType string `json:\"type\"`\n\t}\n\tvar f fileTypeChecker\n\tif err := json.Unmarshal(serviceAccount, &f); err != nil {\n\t\treturn \"\", fmt.Errorf(\"cannot parse the credential file: %w\", err)\n\t}\n\n\treturn f.Type, nil\n}\n"
  },
  {
    "path": "plugins/common/http/client.conf",
    "content": "  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # audience = \"\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"0s\""
  },
  {
    "path": "plugins/common/http/client.conf.in",
    "content": "  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n{{template \"transport.conf\"}}\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # audience = \"\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"0s\""
  },
  {
    "path": "plugins/common/http/config.go",
    "content": "//go:generate ../../../tools/config_includer/generator \"common.http\" \"transport.conf.in\"\n//go:generate ../../../tools/config_includer/generator \"common.http\" \"client.conf.in\"\npackage httpconfig\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/benbjohnson/clock\"\n\t\"github.com/peterbourgon/unixtransport\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/cookie\"\n\t\"github.com/influxdata/telegraf/plugins/common/oauth\"\n\t\"github.com/influxdata/telegraf/plugins/common/proxy\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\n// TransportConfig is configuration structure for HTTP transports\ntype TransportConfig struct {\n\tIdleConnTimeout       config.Duration `toml:\"idle_conn_timeout\"`\n\tMaxIdleConns          int             `toml:\"max_idle_conn\"`\n\tMaxIdleConnsPerHost   int             `toml:\"max_idle_conn_per_host\"`\n\tResponseHeaderTimeout config.Duration `toml:\"response_timeout\"`\n\tLocalAddress          string          `toml:\"local_address\"`\n\tproxy.HTTPProxy\n\ttls.ClientConfig\n}\n\nfunc (h *TransportConfig) CreateTransport() (*http.Transport, error) {\n\ttlsCfg, err := h.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating TLS configuration failed: %w\", err)\n\t}\n\n\tprox, err := h.HTTPProxy.Proxy()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"setting up proxy failed: %w\", err)\n\t}\n\n\ttransport := &http.Transport{\n\t\tTLSClientConfig:       tlsCfg,\n\t\tProxy:                 prox,\n\t\tIdleConnTimeout:       time.Duration(h.IdleConnTimeout),\n\t\tMaxIdleConns:          h.MaxIdleConns,\n\t\tMaxIdleConnsPerHost:   h.MaxIdleConnsPerHost,\n\t\tResponseHeaderTimeout: time.Duration(h.ResponseHeaderTimeout),\n\t}\n\n\tif h.LocalAddress != \"\" {\n\t\tlocalAddr, err := internal.ResolveLocalTCPAddress(h.LocalAddress)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdialer := &net.Dialer{LocalAddr: localAddr}\n\t\ttransport.DialContext = dialer.DialContext\n\t}\n\n\treturn transport, nil\n}\n\n// HTTPClientConfig is a common HTTP client struct.\ntype HTTPClientConfig struct {\n\tTimeout config.Duration `toml:\"timeout\"`\n\tTransportConfig\n\toauth.OAuth2Config\n\tcookie.CookieAuthConfig\n}\n\nfunc (h *HTTPClientConfig) CreateClient(ctx context.Context, log telegraf.Logger) (*http.Client, error) {\n\ttransport, err := h.TransportConfig.CreateTransport()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"setting up transport failed: %w\", err)\n\t}\n\n\t// Register \"http+unix\" and \"https+unix\" protocol handler.\n\tunixtransport.Register(transport)\n\n\tclient := &http.Client{\n\t\tTransport: transport,\n\t}\n\n\t// While CreateOauth2Client returns a http.Client keeping the Transport configuration,\n\t// it does not keep other http.Client parameters (e.g. Timeout).\n\tclient = h.OAuth2Config.CreateOauth2Client(ctx, client)\n\n\tif h.CookieAuthConfig.URL != \"\" {\n\t\tif err := h.CookieAuthConfig.Start(client, log, clock.New()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\ttimeout := h.Timeout\n\tif timeout == 0 {\n\t\ttimeout = config.Duration(time.Second * 5)\n\t}\n\tclient.Timeout = time.Duration(timeout)\n\n\treturn client, nil\n}\n"
  },
  {
    "path": "plugins/common/http/transport.conf",
    "content": "  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "plugins/common/http/transport.conf.in",
    "content": "  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n{{template \"/plugins/common/proxy/proxy.conf\"}}\n\n  ## Optional TLS settings\n{{template \"/plugins/common/tls/client.conf\"}}"
  },
  {
    "path": "plugins/common/jolokia2/client.go",
    "content": "package jolokia2\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\ntype Client struct {\n\tURL    string\n\tclient *http.Client\n\tconfig *ClientConfig\n}\n\ntype ClientConfig struct {\n\tResponseTimeout time.Duration\n\tUsername        string\n\tPassword        string\n\tOrigin          string\n\tProxyConfig     *ProxyConfig\n\ttls.ClientConfig\n}\n\ntype ProxyConfig struct {\n\tDefaultTargetUsername string\n\tDefaultTargetPassword string\n\tTargets               []ProxyTargetConfig\n}\n\ntype ProxyTargetConfig struct {\n\tUsername string\n\tPassword string\n\tURL      string\n}\n\ntype ReadRequest struct {\n\tMbean      string\n\tAttributes []string\n\tPath       string\n}\n\ntype ReadResponse struct {\n\tStatus            int\n\tValue             interface{}\n\tRequestMbean      string\n\tRequestAttributes []string\n\tRequestPath       string\n\tRequestTarget     string\n}\n\n//\tJolokia JSON request object. Example: {\n//\t  \"type\": \"read\",\n//\t  \"mbean: \"java.lang:type=\"Runtime\",\n//\t  \"attribute\": \"Uptime\",\n//\t  \"target\": {\n//\t    \"url: \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\"\n//\t  }\n//\t}\ntype jolokiaRequest struct {\n\tType      string         `json:\"type\"`\n\tMbean     string         `json:\"mbean\"`\n\tAttribute interface{}    `json:\"attribute,omitempty\"`\n\tPath      string         `json:\"path,omitempty\"`\n\tTarget    *jolokiaTarget `json:\"target,omitempty\"`\n}\n\ntype jolokiaTarget struct {\n\tURL      string `json:\"url\"`\n\tUser     string `json:\"user,omitempty\"`\n\tPassword string `json:\"password,omitempty\"`\n}\n\n// jolokiaOptions represents the options field in Jolokia 2.x responses.\n// In Jolokia 2.x, the target is returned under request.options.target\n// instead of request.target (Jolokia 1.x format).\ntype jolokiaOptions struct {\n\tTarget *jolokiaTarget `json:\"target,omitempty\"`\n}\n\n// Jolokia JSON response object. Example for Jolokia 1.x:\n//\n//\t{\n//\t  \"request\": {\n//\t    \"type\": \"read\"\n//\t    \"mbean\": \"java.lang:type=Runtime\",\n//\t    \"attribute\": \"Uptime\",\n//\t    \"target\": {\n//\t      \"url\": \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\"\n//\t    }\n//\t  },\n//\t  \"value\": 1214083,\n//\t  \"timestamp\": 1488059309,\n//\t  \"status\": 200\n//\t}\n//\n// Example for Jolokia 2.x:\n//\n//\t{\n//\t  \"request\": {\n//\t    \"type\": \"read\"\n//\t    \"mbean\": \"java.lang:type=Runtime\",\n//\t    \"attribute\": \"Uptime\",\n//\t    \"options\": {\n//\t      \"target\": {\n//\t        \"url\": \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\"\n//\t      }\n//\t    }\n//\t  },\n//\t  \"value\": 1214083,\n//\t  \"timestamp\": 1488059309,\n//\t  \"status\": 200\n//\t}\ntype jolokiaResponse struct {\n\tRequest jolokiaResponseRequest `json:\"request\"`\n\tValue   interface{}            `json:\"value\"`\n\tStatus  int                    `json:\"status\"`\n}\n\n// jolokiaResponseRequest is the request object echoed back in a Jolokia response.\n// It extends jolokiaRequest with the Options field for Jolokia 2.x compatibility.\ntype jolokiaResponseRequest struct {\n\tjolokiaRequest\n\tOptions *jolokiaOptions `json:\"options,omitempty\"`\n}\n\nfunc NewClient(address string, config *ClientConfig) (*Client, error) {\n\ttlsConfig, err := config.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttransport := &http.Transport{\n\t\tResponseHeaderTimeout: config.ResponseTimeout,\n\t\tTLSClientConfig:       tlsConfig,\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: transport,\n\t\tTimeout:   config.ResponseTimeout,\n\t}\n\n\treturn &Client{\n\t\tURL:    address,\n\t\tconfig: config,\n\t\tclient: client,\n\t}, nil\n}\n\nfunc (c *Client) read(requests []ReadRequest) ([]ReadResponse, error) {\n\tjRequests := makeJolokiaRequests(requests, c.config.ProxyConfig)\n\trequestBody, err := json.Marshal(jRequests)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trequestURL, err := formatReadURL(c.URL, c.config.Username, c.config.Password)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq, err := http.NewRequest(\"POST\", requestURL, bytes.NewBuffer(requestBody))\n\tif err != nil {\n\t\t// err is not contained in returned error - it may contain sensitive data (password) which should not be logged\n\t\treturn nil, fmt.Errorf(\"unable to create new request for: %q\", c.URL)\n\t}\n\n\treq.Header.Add(\"Content-type\", \"application/json\")\n\tif c.config.Origin != \"\" {\n\t\treq.Header.Add(\"Origin\", c.config.Origin)\n\t}\n\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"response from url %q has status code %d (%s), expected %d (%s)\",\n\t\t\tc.URL, resp.StatusCode, http.StatusText(resp.StatusCode), http.StatusOK, http.StatusText(http.StatusOK))\n\t}\n\n\tresponseBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar jResponses []jolokiaResponse\n\tif err = json.Unmarshal(responseBody, &jResponses); err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding JSON response: %w: %s\", err, responseBody)\n\t}\n\n\treturn makeReadResponses(jResponses), nil\n}\n\nfunc makeJolokiaRequests(rrequests []ReadRequest, proxyConfig *ProxyConfig) []jolokiaRequest {\n\tjrequests := make([]jolokiaRequest, 0)\n\tif proxyConfig == nil {\n\t\tfor _, rr := range rrequests {\n\t\t\tjrequests = append(jrequests, makeJolokiaRequest(rr, nil))\n\t\t}\n\t} else {\n\t\tfor _, t := range proxyConfig.Targets {\n\t\t\tif t.Username == \"\" {\n\t\t\t\tt.Username = proxyConfig.DefaultTargetUsername\n\t\t\t}\n\t\t\tif t.Password == \"\" {\n\t\t\t\tt.Password = proxyConfig.DefaultTargetPassword\n\t\t\t}\n\n\t\t\tfor _, rr := range rrequests {\n\t\t\t\tjtarget := &jolokiaTarget{\n\t\t\t\t\tURL:      t.URL,\n\t\t\t\t\tUser:     t.Username,\n\t\t\t\t\tPassword: t.Password,\n\t\t\t\t}\n\n\t\t\t\tjrequests = append(jrequests, makeJolokiaRequest(rr, jtarget))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn jrequests\n}\n\nfunc makeJolokiaRequest(rrequest ReadRequest, jtarget *jolokiaTarget) jolokiaRequest {\n\tjrequest := jolokiaRequest{\n\t\tType:   \"read\",\n\t\tMbean:  rrequest.Mbean,\n\t\tPath:   rrequest.Path,\n\t\tTarget: jtarget,\n\t}\n\n\tif len(rrequest.Attributes) == 1 {\n\t\tjrequest.Attribute = rrequest.Attributes[0]\n\t}\n\tif len(rrequest.Attributes) > 1 {\n\t\tjrequest.Attribute = rrequest.Attributes\n\t}\n\n\treturn jrequest\n}\n\nfunc makeReadResponses(jresponses []jolokiaResponse) []ReadResponse {\n\trresponses := make([]ReadResponse, 0, len(jresponses))\n\n\tfor _, jr := range jresponses {\n\t\trrequest := ReadRequest{\n\t\t\tMbean:      jr.Request.Mbean,\n\t\t\tPath:       jr.Request.Path,\n\t\t\tAttributes: make([]string, 0),\n\t\t}\n\n\t\tattrValue := jr.Request.Attribute\n\t\tif attrValue != nil {\n\t\t\tattribute, ok := attrValue.(string)\n\t\t\tif ok {\n\t\t\t\trrequest.Attributes = []string{attribute}\n\t\t\t} else {\n\t\t\t\tattributes, _ := attrValue.([]interface{})\n\t\t\t\trrequest.Attributes = make([]string, 0, len(attributes))\n\t\t\t\tfor _, attr := range attributes {\n\t\t\t\t\trrequest.Attributes = append(rrequest.Attributes, attr.(string))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trresponse := ReadResponse{\n\t\t\tValue:             jr.Value,\n\t\t\tStatus:            jr.Status,\n\t\t\tRequestMbean:      rrequest.Mbean,\n\t\t\tRequestAttributes: rrequest.Attributes,\n\t\t\tRequestPath:       rrequest.Path,\n\t\t}\n\t\t// Check for target in Jolokia 1.x location (request.target)\n\t\tif jtarget := jr.Request.Target; jtarget != nil {\n\t\t\trresponse.RequestTarget = jtarget.URL\n\t\t}\n\t\t// Check for target in Jolokia 2.x location (request.options.target)\n\t\tif rresponse.RequestTarget == \"\" && jr.Request.Options != nil && jr.Request.Options.Target != nil {\n\t\t\trresponse.RequestTarget = jr.Request.Options.Target.URL\n\t\t}\n\n\t\trresponses = append(rresponses, rresponse)\n\t}\n\n\treturn rresponses\n}\n\nfunc formatReadURL(configURL, username, password string) (string, error) {\n\tparsedURL, err := url.Parse(configURL)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treadURL := url.URL{\n\t\tHost:   parsedURL.Host,\n\t\tScheme: parsedURL.Scheme,\n\t}\n\n\tif username != \"\" || password != \"\" {\n\t\treadURL.User = url.UserPassword(username, password)\n\t}\n\n\treadURL.Path = path.Join(parsedURL.Path, \"read\")\n\treadURL.Query().Add(\"ignoreErrors\", \"true\")\n\treturn readURL.String(), nil\n}\n"
  },
  {
    "path": "plugins/common/jolokia2/client_test.go",
    "content": "package jolokia2\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMakeReadResponses_Jolokia1xTarget(t *testing.T) {\n\t// Jolokia 1.x returns target directly in request.target\n\tjresponses := []jolokiaResponse{\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  1214083,\n\t\t\tStatus: 200,\n\t\t},\n\t}\n\n\tresponses := makeReadResponses(jresponses)\n\n\trequire.Len(t, responses, 1)\n\trequire.Equal(t, \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\", responses[0].RequestTarget)\n\trequire.Equal(t, \"java.lang:type=Runtime\", responses[0].RequestMbean)\n\trequire.Equal(t, 200, responses[0].Status)\n}\n\nfunc TestMakeReadResponses_Jolokia2xTarget(t *testing.T) {\n\t// Jolokia 2.x returns target in request.options.target\n\tjresponses := []jolokiaResponse{\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t},\n\t\t\t\tOptions: &jolokiaOptions{\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  1214083,\n\t\t\tStatus: 200,\n\t\t},\n\t}\n\n\tresponses := makeReadResponses(jresponses)\n\n\trequire.Len(t, responses, 1)\n\trequire.Equal(t, \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\", responses[0].RequestTarget)\n\trequire.Equal(t, \"java.lang:type=Runtime\", responses[0].RequestMbean)\n\trequire.Equal(t, 200, responses[0].Status)\n}\n\nfunc TestMakeReadResponses_NoTarget(t *testing.T) {\n\t// No target (direct agent connection, not proxy)\n\tjresponses := []jolokiaResponse{\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  1214083,\n\t\t\tStatus: 200,\n\t\t},\n\t}\n\n\tresponses := makeReadResponses(jresponses)\n\n\trequire.Len(t, responses, 1)\n\trequire.Empty(t, responses[0].RequestTarget)\n\trequire.Equal(t, \"java.lang:type=Runtime\", responses[0].RequestMbean)\n}\n\nfunc TestMakeReadResponses_Jolokia1xTakesPrecedence(t *testing.T) {\n\t// If both locations have a target, Jolokia 1.x location takes precedence\n\tjresponses := []jolokiaResponse{\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tOptions: &jolokiaOptions{\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://target2:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  1214083,\n\t\t\tStatus: 200,\n\t\t},\n\t}\n\n\tresponses := makeReadResponses(jresponses)\n\n\trequire.Len(t, responses, 1)\n\t// Jolokia 1.x location (request.target) takes precedence\n\trequire.Equal(t, \"service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi\", responses[0].RequestTarget)\n}\n\nfunc TestMakeReadResponses_MultipleTargets(t *testing.T) {\n\t// Multiple responses with different targets (Jolokia 2.x format)\n\tjresponses := []jolokiaResponse{\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t},\n\t\t\t\tOptions: &jolokiaOptions{\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://host1:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  1000,\n\t\t\tStatus: 200,\n\t\t},\n\t\t{\n\t\t\tRequest: jolokiaResponseRequest{\n\t\t\t\tjolokiaRequest: jolokiaRequest{\n\t\t\t\t\tType:      \"read\",\n\t\t\t\t\tMbean:     \"java.lang:type=Runtime\",\n\t\t\t\t\tAttribute: \"Uptime\",\n\t\t\t\t},\n\t\t\t\tOptions: &jolokiaOptions{\n\t\t\t\t\tTarget: &jolokiaTarget{\n\t\t\t\t\t\tURL: \"service:jmx:rmi:///jndi/rmi://host2:9010/jmxrmi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tValue:  2000,\n\t\t\tStatus: 200,\n\t\t},\n\t}\n\n\tresponses := makeReadResponses(jresponses)\n\n\trequire.Len(t, responses, 2)\n\trequire.Equal(t, \"service:jmx:rmi:///jndi/rmi://host1:9010/jmxrmi\", responses[0].RequestTarget)\n\trequire.Equal(t, \"service:jmx:rmi:///jndi/rmi://host2:9010/jmxrmi\", responses[1].RequestTarget)\n}\n"
  },
  {
    "path": "plugins/common/jolokia2/gatherer.go",
    "content": "package jolokia2\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nconst defaultFieldName = \"value\"\n\ntype Gatherer struct {\n\tmetrics  []Metric\n\trequests []ReadRequest\n}\n\nfunc NewGatherer(metrics []Metric) *Gatherer {\n\treturn &Gatherer{\n\t\tmetrics:  metrics,\n\t\trequests: makeReadRequests(metrics),\n\t}\n}\n\n// Gather adds points to an accumulator from responses returned\n// by a Jolokia agent.\nfunc (g *Gatherer) Gather(client *Client, acc telegraf.Accumulator) error {\n\tvar tags map[string]string\n\n\tif client.config.ProxyConfig != nil {\n\t\ttags = map[string]string{\"jolokia_proxy_url\": client.URL}\n\t} else {\n\t\ttags = map[string]string{\"jolokia_agent_url\": client.URL}\n\t}\n\n\trequests := makeReadRequests(g.metrics)\n\tresponses, err := client.read(requests)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.gatherResponses(responses, tags, acc)\n\treturn nil\n}\n\n// gatherResponses adds points to an accumulator from the ReadResponse objects\n// returned by a Jolokia agent.\nfunc (g *Gatherer) gatherResponses(responses []ReadResponse, tags map[string]string, acc telegraf.Accumulator) {\n\tseries := make(map[string][]point)\n\n\tfor _, metric := range g.metrics {\n\t\tpoints, ok := series[metric.Name]\n\t\tif !ok {\n\t\t\tpoints = make([]point, 0)\n\t\t}\n\n\t\tresponsePoints, responseErrors := generatePoints(metric, responses)\n\t\tpoints = append(points, responsePoints...)\n\t\tfor _, err := range responseErrors {\n\t\t\tacc.AddError(err)\n\t\t}\n\n\t\tseries[metric.Name] = points\n\t}\n\n\tfor measurement, points := range series {\n\t\tfor _, point := range compactPoints(points) {\n\t\t\tacc.AddFields(measurement,\n\t\t\t\tpoint.Fields, mergeTags(point.Tags, tags))\n\t\t}\n\t}\n}\n\n// generatePoints creates points for the supplied metric from the ReadResponse objects returned by the Jolokia client.\nfunc generatePoints(metric Metric, responses []ReadResponse) ([]point, []error) {\n\tpoints := make([]point, 0)\n\terrors := make([]error, 0)\n\n\tfor _, response := range responses {\n\t\tswitch response.Status {\n\t\tcase 200:\n\t\t\t// Correct response status - do nothing.\n\t\tcase 404:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\terrors = append(errors, fmt.Errorf(\"unexpected status in response from target %s (%q): %d\",\n\t\t\t\tresponse.RequestTarget, response.RequestMbean, response.Status))\n\t\t\tcontinue\n\t\t}\n\n\t\tif !metricMatchesResponse(metric, response) {\n\t\t\tcontinue\n\t\t}\n\n\t\tpb := NewPointBuilder(metric, response.RequestAttributes, response.RequestPath)\n\t\tps, err := pb.Build(metric.Mbean, response.Value)\n\t\tif err != nil {\n\t\t\terrors = append(errors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, point := range ps {\n\t\t\tif response.RequestTarget != \"\" {\n\t\t\t\tpoint.Tags[\"jolokia_agent_url\"] = response.RequestTarget\n\t\t\t}\n\n\t\t\tpoints = append(points, point)\n\t\t}\n\t}\n\n\treturn points, errors\n}\n\n// mergeTags combines two tag sets into a single tag set.\nfunc mergeTags(metricTags, outerTags map[string]string) map[string]string {\n\ttags := make(map[string]string)\n\tfor k, v := range outerTags {\n\t\ttags[k] = strings.Trim(v, `'\"`)\n\t}\n\tfor k, v := range metricTags {\n\t\ttags[k] = strings.Trim(v, `'\"`)\n\t}\n\n\treturn tags\n}\n\n// metricMatchesResponse returns true when the name, attributes, and path\n// of a Metric match the corresponding elements in a ReadResponse object\n// returned by a Jolokia agent.\nfunc metricMatchesResponse(metric Metric, response ReadResponse) bool {\n\tif !metric.MatchObjectName(response.RequestMbean) {\n\t\treturn false\n\t}\n\n\tif len(metric.Paths) == 0 {\n\t\treturn len(response.RequestAttributes) == 0\n\t}\n\n\tfor _, attribute := range response.RequestAttributes {\n\t\tif metric.MatchAttributeAndPath(attribute, response.RequestPath) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// compactPoints attempts to remove points by compacting points\n// with matching tag sets. When a match is found, the fields from\n// one point are moved to another, and the empty point is removed.\nfunc compactPoints(points []point) []point {\n\tcompactedPoints := make([]point, 0)\n\n\tfor _, sourcePoint := range points {\n\t\tkeepPoint := true\n\n\t\tfor _, compactPoint := range compactedPoints {\n\t\t\tif !tagSetsMatch(sourcePoint.Tags, compactPoint.Tags) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tkeepPoint = false\n\t\t\tfor key, val := range sourcePoint.Fields {\n\t\t\t\tcompactPoint.Fields[key] = val\n\t\t\t}\n\t\t}\n\n\t\tif keepPoint {\n\t\t\tcompactedPoints = append(compactedPoints, sourcePoint)\n\t\t}\n\t}\n\n\treturn compactedPoints\n}\n\n// tagSetsMatch returns true if two maps are equivalent.\nfunc tagSetsMatch(a, b map[string]string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\tfor ak, av := range a {\n\t\tbv, ok := b[ak]\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tif av != bv {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// makeReadRequests creates ReadRequest objects from metrics definitions.\nfunc makeReadRequests(metrics []Metric) []ReadRequest {\n\tvar requests []ReadRequest\n\tfor _, metric := range metrics {\n\t\tif len(metric.Paths) == 0 {\n\t\t\trequests = append(requests, ReadRequest{\n\t\t\t\tMbean:      metric.Mbean,\n\t\t\t\tAttributes: make([]string, 0),\n\t\t\t})\n\t\t} else {\n\t\t\tattributes := make(map[string][]string)\n\n\t\t\tfor _, path := range metric.Paths {\n\t\t\t\tsegments := strings.Split(path, \"/\")\n\t\t\t\tattribute := segments[0]\n\n\t\t\t\tif _, ok := attributes[attribute]; !ok {\n\t\t\t\t\tattributes[attribute] = make([]string, 0)\n\t\t\t\t}\n\n\t\t\t\tif len(segments) > 1 {\n\t\t\t\t\tpaths := attributes[attribute]\n\t\t\t\t\tattributes[attribute] = append(paths, strings.Join(segments[1:], \"/\"))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trootAttributes := findRequestAttributesWithoutPaths(attributes)\n\t\t\tif len(rootAttributes) > 0 {\n\t\t\t\trequests = append(requests, ReadRequest{\n\t\t\t\t\tMbean:      metric.Mbean,\n\t\t\t\t\tAttributes: rootAttributes,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfor _, deepAttribute := range findRequestAttributesWithPaths(attributes) {\n\t\t\t\tfor _, path := range attributes[deepAttribute] {\n\t\t\t\t\trequests = append(requests, ReadRequest{\n\t\t\t\t\t\tMbean:      metric.Mbean,\n\t\t\t\t\t\tAttributes: []string{deepAttribute},\n\t\t\t\t\t\tPath:       path,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn requests\n}\n\nfunc findRequestAttributesWithoutPaths(attributes map[string][]string) []string {\n\tresults := make([]string, 0)\n\tfor attr, paths := range attributes {\n\t\tif len(paths) == 0 {\n\t\t\tresults = append(results, attr)\n\t\t}\n\t}\n\n\tsort.Strings(results)\n\treturn results\n}\n\nfunc findRequestAttributesWithPaths(attributes map[string][]string) []string {\n\tresults := make([]string, 0)\n\tfor attr, paths := range attributes {\n\t\tif len(paths) != 0 {\n\t\t\tresults = append(results, attr)\n\t\t}\n\t}\n\n\tsort.Strings(results)\n\treturn results\n}\n"
  },
  {
    "path": "plugins/common/jolokia2/gatherer_test.go",
    "content": "package jolokia2\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestJolokia2_makeReadRequests(t *testing.T) {\n\tcases := []struct {\n\t\tmetric   Metric\n\t\texpected []ReadRequest\n\t}{\n\t\t{\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: make([]string, 0),\n\t\t\t\t},\n\t\t\t},\n\t\t}, {\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object_with_an_attribute\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t\tPaths: []string{\"biz\"},\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"biz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}, {\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object_with_attributes\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t\tPaths: []string{\"baz\", \"biz\"},\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"baz\", \"biz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}, {\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object_with_an_attribute_and_path\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t\tPaths: []string{\"biz/baz\"},\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"biz\"},\n\t\t\t\t\tPath:       \"baz\",\n\t\t\t\t},\n\t\t\t},\n\t\t}, {\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object_with_an_attribute_and_a_deep_path\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t\tPaths: []string{\"biz/baz/fiz/faz\"},\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"biz\"},\n\t\t\t\t\tPath:       \"baz/fiz/faz\",\n\t\t\t\t},\n\t\t\t},\n\t\t}, {\n\t\t\tmetric: Metric{\n\t\t\t\tName:  \"object_with_attributes_and_paths\",\n\t\t\t\tMbean: \"test:foo=bar\",\n\t\t\t\tPaths: []string{\"baz/biz\", \"faz/fiz\"},\n\t\t\t},\n\t\t\texpected: []ReadRequest{\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"baz\"},\n\t\t\t\t\tPath:       \"biz\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMbean:      \"test:foo=bar\",\n\t\t\t\t\tAttributes: []string{\"faz\"},\n\t\t\t\t\tPath:       \"fiz\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tpayload := makeReadRequests([]Metric{c.metric})\n\n\t\trequire.Len(t, payload, len(c.expected), \"Failing case: \"+c.metric.Name)\n\t\tfor _, actual := range payload {\n\t\t\trequire.Contains(t, c.expected, actual, \"Failing case: \"+c.metric.Name)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/common/jolokia2/metric.go",
    "content": "package jolokia2\n\nimport \"strings\"\n\n// A MetricConfig represents a TOML form of\n// a Metric with some optional fields.\ntype MetricConfig struct {\n\tName           string\n\tMbean          string\n\tPaths          []string\n\tFieldName      *string\n\tFieldPrefix    *string\n\tFieldSeparator *string\n\tTagPrefix      *string\n\tTagKeys        []string\n}\n\n// A Metric represents a specification for a\n// Jolokia read request, and the transformations\n// to apply to points generated from the responses.\ntype Metric struct {\n\tName           string\n\tMbean          string\n\tPaths          []string\n\tFieldName      string\n\tFieldPrefix    string\n\tFieldSeparator string\n\tTagPrefix      string\n\tTagKeys        []string\n\n\tmbeanDomain     string\n\tmbeanProperties []string\n}\n\nfunc NewMetric(config MetricConfig, defaultFieldPrefix, defaultFieldSeparator, defaultTagPrefix string) Metric {\n\tmetric := Metric{\n\t\tName:    config.Name,\n\t\tMbean:   config.Mbean,\n\t\tPaths:   config.Paths,\n\t\tTagKeys: config.TagKeys,\n\t}\n\n\tif config.FieldName != nil {\n\t\tmetric.FieldName = *config.FieldName\n\t}\n\n\tif config.FieldPrefix == nil {\n\t\tmetric.FieldPrefix = defaultFieldPrefix\n\t} else {\n\t\tmetric.FieldPrefix = *config.FieldPrefix\n\t}\n\n\tif config.FieldSeparator == nil {\n\t\tmetric.FieldSeparator = defaultFieldSeparator\n\t} else {\n\t\tmetric.FieldSeparator = *config.FieldSeparator\n\t}\n\n\tif config.TagPrefix == nil {\n\t\tmetric.TagPrefix = defaultTagPrefix\n\t} else {\n\t\tmetric.TagPrefix = *config.TagPrefix\n\t}\n\n\tmbeanDomain, mbeanProperties := parseMbeanObjectName(config.Mbean)\n\tmetric.mbeanDomain = mbeanDomain\n\tmetric.mbeanProperties = mbeanProperties\n\n\treturn metric\n}\n\nfunc (m Metric) MatchObjectName(name string) bool {\n\tif name == m.Mbean {\n\t\treturn true\n\t}\n\n\tmbeanDomain, mbeanProperties := parseMbeanObjectName(name)\n\tif mbeanDomain != m.mbeanDomain {\n\t\treturn false\n\t}\n\n\tif len(mbeanProperties) != len(m.mbeanProperties) {\n\t\treturn false\n\t}\n\nNEXT_PROPERTY:\n\tfor _, mbeanProperty := range m.mbeanProperties {\n\t\tfor i := range mbeanProperties {\n\t\t\tif mbeanProperties[i] == mbeanProperty {\n\t\t\t\tcontinue NEXT_PROPERTY\n\t\t\t}\n\t\t}\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (m Metric) MatchAttributeAndPath(attribute, innerPath string) bool {\n\tpath := attribute\n\tif innerPath != \"\" {\n\t\tpath = path + \"/\" + innerPath\n\t}\n\n\tfor i := range m.Paths {\n\t\tif path == m.Paths[i] {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc parseMbeanObjectName(name string) (string, []string) {\n\tindex := strings.Index(name, \":\")\n\tif index == -1 {\n\t\treturn name, nil\n\t}\n\n\tdomain := name[:index]\n\n\tif index+1 > len(name) {\n\t\treturn domain, nil\n\t}\n\n\treturn domain, strings.Split(name[index+1:], \",\")\n}\n"
  },
  {
    "path": "plugins/common/jolokia2/point_builder.go",
    "content": "package jolokia2\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype point struct {\n\tTags   map[string]string\n\tFields map[string]interface{}\n}\n\ntype pointBuilder struct {\n\tmetric           Metric\n\tobjectAttributes []string\n\tobjectPath       string\n\tsubstitutions    []string\n}\n\nfunc NewPointBuilder(metric Metric, attributes []string, path string) *pointBuilder {\n\treturn &pointBuilder{\n\t\tmetric:           metric,\n\t\tobjectAttributes: attributes,\n\t\tobjectPath:       path,\n\t\tsubstitutions:    makeSubstitutionList(metric.Mbean),\n\t}\n}\n\n// Build generates a point for a given mbean name/pattern and value object.\nfunc (pb *pointBuilder) Build(mbean string, value interface{}) ([]point, error) {\n\thasPattern := strings.Contains(mbean, \"*\")\n\tif !hasPattern || value == nil {\n\t\tvalue = map[string]interface{}{mbean: value}\n\t}\n\n\tvalueMap, ok := value.(map[string]interface{})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"the response of %s's value should be a map\", mbean)\n\t}\n\n\tpoints := make([]point, 0, len(valueMap))\n\tfor mbean, value := range valueMap {\n\t\tpoints = append(points, point{\n\t\t\tTags:   pb.extractTags(mbean),\n\t\t\tFields: pb.extractFields(mbean, value),\n\t\t})\n\t}\n\n\treturn compactPoints(points), nil\n}\n\n// extractTags generates the map of tags for a given mbean name/pattern.\nfunc (pb *pointBuilder) extractTags(mbean string) map[string]string {\n\tpropertyMap := makePropertyMap(mbean)\n\ttagMap := make(map[string]string)\n\n\tfor key, value := range propertyMap {\n\t\tif pb.includeTag(key) {\n\t\t\ttagName := pb.formatTagName(key)\n\t\t\ttagMap[tagName] = value\n\t\t}\n\t}\n\n\treturn tagMap\n}\n\nfunc (pb *pointBuilder) includeTag(tagName string) bool {\n\tfor _, t := range pb.metric.TagKeys {\n\t\tif tagName == t {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (pb *pointBuilder) formatTagName(tagName string) string {\n\tif tagName == \"\" {\n\t\treturn \"\"\n\t}\n\n\tif tagPrefix := pb.metric.TagPrefix; tagPrefix != \"\" {\n\t\treturn tagPrefix + tagName\n\t}\n\n\treturn tagName\n}\n\n// extractFields generates the map of fields for a given mbean name\n// and value object.\nfunc (pb *pointBuilder) extractFields(mbean string, value interface{}) map[string]interface{} {\n\tfieldMap := make(map[string]interface{})\n\tvalueMap, ok := value.(map[string]interface{})\n\n\tif ok {\n\t\t// complex value\n\t\tif len(pb.objectAttributes) == 0 {\n\t\t\t// if there were no attributes requested,\n\t\t\t// then the keys are attributes\n\t\t\tpb.FillFields(\"\", valueMap, fieldMap)\n\t\t} else if len(pb.objectAttributes) == 1 {\n\t\t\t// if there was a single attribute requested,\n\t\t\t// then the keys are the attribute's properties\n\t\t\tfieldName := pb.formatFieldName(pb.objectAttributes[0], pb.objectPath)\n\t\t\tpb.FillFields(fieldName, valueMap, fieldMap)\n\t\t} else {\n\t\t\t// if there were multiple attributes requested,\n\t\t\t// then the keys are the attribute names\n\t\t\tfor _, attribute := range pb.objectAttributes {\n\t\t\t\tfieldName := pb.formatFieldName(attribute, pb.objectPath)\n\t\t\t\tpb.FillFields(fieldName, valueMap[attribute], fieldMap)\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// scalar value\n\t\tvar fieldName string\n\t\tif len(pb.objectAttributes) == 0 {\n\t\t\tfieldName = pb.formatFieldName(defaultFieldName, pb.objectPath)\n\t\t} else {\n\t\t\tfieldName = pb.formatFieldName(pb.objectAttributes[0], pb.objectPath)\n\t\t}\n\n\t\tpb.FillFields(fieldName, value, fieldMap)\n\t}\n\n\tif len(pb.substitutions) > 1 {\n\t\tpb.applySubstitutions(mbean, fieldMap)\n\t}\n\n\treturn fieldMap\n}\n\n// formatFieldName generates a field name from the supplied attribute and\n// path. The return value has the configured FieldPrefix and FieldSuffix\n// instructions applied.\nfunc (pb *pointBuilder) formatFieldName(attribute, path string) string {\n\tfieldName := attribute\n\tfieldPrefix := pb.metric.FieldPrefix\n\tfieldSeparator := pb.metric.FieldSeparator\n\n\tif fieldPrefix != \"\" {\n\t\tfieldName = fieldPrefix + fieldName\n\t}\n\n\tif path != \"\" {\n\t\tfieldName = fieldName + fieldSeparator + strings.ReplaceAll(path, \"/\", fieldSeparator)\n\t}\n\n\treturn fieldName\n}\n\n// FillFields recurses into the supplied value object, generating a named field\n// for every value it discovers.\nfunc (pb *pointBuilder) FillFields(name string, value interface{}, fieldMap map[string]interface{}) {\n\tif valueMap, ok := value.(map[string]interface{}); ok {\n\t\t// keep going until we get to something that is not a map\n\t\tfor key, innerValue := range valueMap {\n\t\t\tif _, ok := innerValue.([]interface{}); ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar innerName string\n\t\t\tif name == \"\" {\n\t\t\t\tinnerName = pb.metric.FieldPrefix + key\n\t\t\t} else {\n\t\t\t\tinnerName = name + pb.metric.FieldSeparator + key\n\t\t\t}\n\n\t\t\tpb.FillFields(innerName, innerValue, fieldMap)\n\t\t}\n\n\t\treturn\n\t}\n\n\tif _, ok := value.([]interface{}); ok {\n\t\treturn\n\t}\n\n\tif pb.metric.FieldName != \"\" {\n\t\tname = pb.metric.FieldName\n\t\tif prefix := pb.metric.FieldPrefix; prefix != \"\" {\n\t\t\tname = prefix + name\n\t\t}\n\t}\n\n\tif name == \"\" {\n\t\tname = defaultFieldName\n\t}\n\n\tfieldMap[name] = value\n}\n\n// applySubstitutions updates all the keys in the supplied map\n// of fields to account for $1-style substitution instructions.\nfunc (pb *pointBuilder) applySubstitutions(mbean string, fieldMap map[string]interface{}) {\n\tproperties := makePropertyMap(mbean)\n\n\tfor i, subKey := range pb.substitutions[1:] {\n\t\tsymbol := fmt.Sprintf(\"$%d\", i+1)\n\t\tsubstitution := properties[subKey]\n\n\t\tfor fieldName, fieldValue := range fieldMap {\n\t\t\tnewFieldName := strings.ReplaceAll(fieldName, symbol, substitution)\n\t\t\tif fieldName != newFieldName {\n\t\t\t\tfieldMap[newFieldName] = fieldValue\n\t\t\t\tdelete(fieldMap, fieldName)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// makePropertyMap returns a the mbean property-key list as\n// a dictionary. foo:x=y becomes map[string]string { \"x\": \"y\" }\nfunc makePropertyMap(mbean string) map[string]string {\n\tprops := make(map[string]string)\n\tobject := strings.SplitN(mbean, \":\", 2)\n\tdomain := object[0]\n\n\tif domain != \"\" && len(object) == 2 {\n\t\tlist := object[1]\n\n\t\tfor _, keyProperty := range strings.Split(list, \",\") {\n\t\t\tpair := strings.SplitN(keyProperty, \"=\", 2)\n\n\t\t\tif len(pair) != 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif key := pair[0]; key != \"\" {\n\t\t\t\tprops[key] = pair[1]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn props\n}\n\n// makeSubstitutionList returns an array of values to\n// use as substitutions when renaming fields\n// with the $1..$N syntax. The first item in the list\n// is always the mbean domain.\nfunc makeSubstitutionList(mbean string) []string {\n\tsubs := make([]string, 0)\n\n\tobject := strings.SplitN(mbean, \":\", 2)\n\tdomain := object[0]\n\n\tif domain != \"\" && len(object) == 2 {\n\t\tsubs = append(subs, domain)\n\t\tlist := object[1]\n\n\t\tfor _, keyProperty := range strings.Split(list, \",\") {\n\t\t\tpair := strings.SplitN(keyProperty, \"=\", 2)\n\n\t\t\tif len(pair) != 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tkey := pair[0]\n\t\t\tif key == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tproperty := pair[1]\n\t\t\tif !strings.Contains(property, \"*\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsubs = append(subs, key)\n\t\t}\n\t}\n\n\treturn subs\n}\n"
  },
  {
    "path": "plugins/common/kafka/config.go",
    "content": "package kafka\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBM/sarama\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\n// ReadConfig for kafka clients meaning to read from Kafka.\ntype ReadConfig struct {\n\tConfig\n}\n\n// SetConfig on the sarama.Config object from the ReadConfig struct.\nfunc (k *ReadConfig) SetConfig(cfg *sarama.Config, log telegraf.Logger) error {\n\tcfg.Consumer.Return.Errors = true\n\treturn k.Config.SetConfig(cfg, log)\n}\n\n// WriteConfig for kafka clients meaning to write to kafka\ntype WriteConfig struct {\n\tConfig\n\n\tRequiredAcks     int  `toml:\"required_acks\"`\n\tMaxRetry         int  `toml:\"max_retry\"`\n\tMaxMessageBytes  int  `toml:\"max_message_bytes\"`\n\tIdempotentWrites bool `toml:\"idempotent_writes\"`\n}\n\n// SetConfig on the sarama.Config object from the WriteConfig struct.\nfunc (k *WriteConfig) SetConfig(cfg *sarama.Config, log telegraf.Logger) error {\n\tcfg.Producer.Return.Successes = true\n\tcfg.Producer.Idempotent = k.IdempotentWrites\n\tcfg.Producer.Retry.Max = k.MaxRetry\n\tif k.MaxMessageBytes > 0 {\n\t\tcfg.Producer.MaxMessageBytes = k.MaxMessageBytes\n\t}\n\tcfg.Producer.RequiredAcks = sarama.RequiredAcks(k.RequiredAcks)\n\tif cfg.Producer.Idempotent {\n\t\tcfg.Net.MaxOpenRequests = 1\n\t}\n\treturn k.Config.SetConfig(cfg, log)\n}\n\n// Config common to all Kafka clients.\ntype Config struct {\n\tSASLAuth\n\ttls.ClientConfig\n\n\tVersion          string           `toml:\"version\"`\n\tClientID         string           `toml:\"client_id\"`\n\tCompressionCodec int              `toml:\"compression_codec\"`\n\tEnableTLS        *bool            `toml:\"enable_tls\"`\n\tKeepAlivePeriod  *config.Duration `toml:\"keep_alive_period\"`\n\n\tMetadataRetryMax         int             `toml:\"metadata_retry_max\"`\n\tMetadataRetryType        string          `toml:\"metadata_retry_type\"`\n\tMetadataRetryBackoff     config.Duration `toml:\"metadata_retry_backoff\"`\n\tMetadataRetryMaxDuration config.Duration `toml:\"metadata_retry_max_duration\"`\n\n\t// Disable full metadata fetching\n\tMetadataFull *bool `toml:\"metadata_full\"`\n}\n\ntype BackoffFunc func(retries, maxRetries int) time.Duration\n\nfunc makeBackoffFunc(backoff, maxDuration time.Duration) BackoffFunc {\n\treturn func(retries, _ int) time.Duration {\n\t\td := time.Duration(math.Pow(2, float64(retries))) * backoff\n\t\tif maxDuration != 0 && d > maxDuration {\n\t\t\treturn maxDuration\n\t\t}\n\t\treturn d\n\t}\n}\n\n// SetConfig on the sarama.Config object from the Config struct.\nfunc (k *Config) SetConfig(cfg *sarama.Config, log telegraf.Logger) error {\n\tif k.Version != \"\" {\n\t\tversion, err := sarama.ParseKafkaVersion(k.Version)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing kafka version failed: %w\", err)\n\t\t}\n\n\t\tcfg.Version = version\n\t}\n\n\tif k.ClientID != \"\" {\n\t\tcfg.ClientID = k.ClientID\n\t} else {\n\t\tcfg.ClientID = \"Telegraf\"\n\t}\n\n\tcfg.Producer.Compression = sarama.CompressionCodec(k.CompressionCodec)\n\n\tif k.EnableTLS != nil && *k.EnableTLS {\n\t\tcfg.Net.TLS.Enable = true\n\t}\n\n\ttlsConfig, err := k.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"configuring TLS failed: %w\", err)\n\t}\n\n\tif tlsConfig != nil {\n\t\tcfg.Net.TLS.Config = tlsConfig\n\n\t\t// To maintain backwards compatibility, if the enable_tls option is not\n\t\t// set TLS is enabled if a non-default TLS config is used.\n\t\tif k.EnableTLS == nil {\n\t\t\tcfg.Net.TLS.Enable = true\n\t\t}\n\t}\n\n\tif k.KeepAlivePeriod != nil {\n\t\t// Defaults to OS setting (15s currently)\n\t\tcfg.Net.KeepAlive = time.Duration(*k.KeepAlivePeriod)\n\t}\n\n\tif k.MetadataFull != nil {\n\t\t// Defaults to true in Sarama\n\t\tcfg.Metadata.Full = *k.MetadataFull\n\t}\n\n\tif k.MetadataRetryMax != 0 {\n\t\tcfg.Metadata.Retry.Max = k.MetadataRetryMax\n\t}\n\n\tif k.MetadataRetryBackoff != 0 {\n\t\t// If cfg.Metadata.Retry.BackoffFunc is set, sarama ignores\n\t\t// cfg.Metadata.Retry.Backoff\n\t\tcfg.Metadata.Retry.Backoff = time.Duration(k.MetadataRetryBackoff)\n\t}\n\n\tswitch strings.ToLower(k.MetadataRetryType) {\n\tdefault:\n\t\treturn errors.New(\"invalid metadata retry type\")\n\tcase \"exponential\":\n\t\tif k.MetadataRetryBackoff == 0 {\n\t\t\tk.MetadataRetryBackoff = config.Duration(250 * time.Millisecond)\n\t\t\tlog.Warnf(\"metadata_retry_backoff is 0, using %s\", time.Duration(k.MetadataRetryBackoff))\n\t\t}\n\t\tcfg.Metadata.Retry.BackoffFunc = makeBackoffFunc(\n\t\t\ttime.Duration(k.MetadataRetryBackoff),\n\t\t\ttime.Duration(k.MetadataRetryMaxDuration),\n\t\t)\n\tcase \"constant\", \"\":\n\t}\n\n\tif err := k.SetSASLConfig(cfg); err != nil {\n\t\treturn fmt.Errorf(\"configuring SASL failed: %w\", err)\n\t}\n\n\t// SASLv0 cannot be used with API requests so disable API requests in this case\n\tif cfg.Net.SASL.Version == sarama.SASLHandshakeV0 {\n\t\tcfg.ApiVersionsRequest = false\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/kafka/config_test.go",
    "content": "package kafka\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBackoffFunc(t *testing.T) {\n\tb := 250 * time.Millisecond\n\tlimit := 1100 * time.Millisecond\n\n\tf := makeBackoffFunc(b, limit)\n\trequire.Equal(t, b, f(0, 0))\n\trequire.Equal(t, b*2, f(1, 0))\n\trequire.Equal(t, b*4, f(2, 0))\n\trequire.Equal(t, limit, f(3, 0)) // would be 2000 but that's greater than max\n\n\tf = makeBackoffFunc(b, 0)      // max = 0 means no max\n\trequire.Equal(t, b*8, f(3, 0)) // with no max, it's 2000\n}\n"
  },
  {
    "path": "plugins/common/kafka/logger.go",
    "content": "package kafka\n\nimport (\n\t\"sync\"\n\n\t\"github.com/IBM/sarama\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/logger\"\n)\n\nvar (\n\tlog  = logger.New(\"sarama\", \"\", \"\")\n\tonce sync.Once\n)\n\ntype debugLogger struct{}\n\nfunc (*debugLogger) Print(v ...interface{}) {\n\tlog.Trace(v...)\n}\n\nfunc (*debugLogger) Printf(format string, v ...interface{}) {\n\tlog.Tracef(format, v...)\n}\n\nfunc (l *debugLogger) Println(v ...interface{}) {\n\tl.Print(v...)\n}\n\n// SetLogger configures a debug logger for kafka (sarama)\nfunc SetLogger(level telegraf.LogLevel) {\n\t// Set-up the sarama logger only once\n\tonce.Do(func() {\n\t\tsarama.Logger = &debugLogger{}\n\t})\n\t// Increase the log-level if needed.\n\tif !log.Level().Includes(level) {\n\t\tlog.SetLevel(level)\n\t}\n}\n"
  },
  {
    "path": "plugins/common/kafka/sasl.go",
    "content": "package kafka\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/IBM/sarama\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype SASLAuth struct {\n\tSASLUsername   config.Secret     `toml:\"sasl_username\"`\n\tSASLPassword   config.Secret     `toml:\"sasl_password\"`\n\tSASLExtensions map[string]string `toml:\"sasl_extensions\"`\n\tSASLMechanism  string            `toml:\"sasl_mechanism\"`\n\tSASLVersion    *int              `toml:\"sasl_version\"`\n\n\t// GSSAPI config\n\tSASLGSSAPIServiceName        string `toml:\"sasl_gssapi_service_name\"`\n\tSASLGSSAPIAuthType           string `toml:\"sasl_gssapi_auth_type\"`\n\tSASLGSSAPIDisablePAFXFAST    bool   `toml:\"sasl_gssapi_disable_pafxfast\"`\n\tSASLGSSAPIKerberosConfigPath string `toml:\"sasl_gssapi_kerberos_config_path\"`\n\tSASLGSSAPIKeyTabPath         string `toml:\"sasl_gssapi_key_tab_path\"`\n\tSASLGSSAPIRealm              string `toml:\"sasl_gssapi_realm\"`\n\n\t// OAUTHBEARER token based config\n\tSASLAccessToken config.Secret `toml:\"sasl_access_token\"`\n\n\t// OAUTHBEARER AWS MSK IAM based config\n\tSASLOAuthAWSMSKIAMConfig\n}\n\n// SetSASLConfig configures SASL for kafka (sarama)\nfunc (k *SASLAuth) SetSASLConfig(cfg *sarama.Config) error {\n\tusername, err := k.SASLUsername.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tcfg.Net.SASL.User = username.String()\n\tdefer username.Destroy()\n\tpassword, err := k.SASLPassword.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tcfg.Net.SASL.Password = password.String()\n\tdefer password.Destroy()\n\n\tmechanism := k.SASLMechanism\n\n\tswitch k.SASLMechanism {\n\tcase sarama.SASLTypeSCRAMSHA256:\n\t\tcfg.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient {\n\t\t\treturn &XDGSCRAMClient{HashGeneratorFcn: SHA256}\n\t\t}\n\tcase sarama.SASLTypeSCRAMSHA512:\n\t\tcfg.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient {\n\t\t\treturn &XDGSCRAMClient{HashGeneratorFcn: SHA512}\n\t\t}\n\tcase sarama.SASLTypeGSSAPI:\n\t\tcfg.Net.SASL.GSSAPI.ServiceName = k.SASLGSSAPIServiceName\n\t\tcfg.Net.SASL.GSSAPI.AuthType = gssapiAuthType(k.SASLGSSAPIAuthType)\n\t\tcfg.Net.SASL.GSSAPI.Username = username.String()\n\t\tcfg.Net.SASL.GSSAPI.Password = password.String()\n\t\tcfg.Net.SASL.GSSAPI.DisablePAFXFAST = k.SASLGSSAPIDisablePAFXFAST\n\t\tcfg.Net.SASL.GSSAPI.KerberosConfigPath = k.SASLGSSAPIKerberosConfigPath\n\t\tcfg.Net.SASL.GSSAPI.KeyTabPath = k.SASLGSSAPIKeyTabPath\n\t\tcfg.Net.SASL.GSSAPI.Realm = k.SASLGSSAPIRealm\n\tcase sarama.SASLTypeOAuth: // OAUTHBEARER secret based auth\n\t\tcfg.Net.SASL.TokenProvider = &oauthToken{\n\t\t\ttoken:      k.SASLAccessToken,\n\t\t\textensions: k.SASLExtensions,\n\t\t}\n\tcase saslTypeOAuthAWSMSKIAM: // AWS-MSK-IAM based auth\n\t\tp, err := k.SASLOAuthAWSMSKIAMConfig.tokenProvider(k.SASLExtensions)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating AWS MSK IAM token provider failed: %w\", err)\n\t\t}\n\t\tmechanism = sarama.SASLTypeOAuth\n\t\tcfg.Net.SASL.TokenProvider = p\n\tcase sarama.SASLTypePlaintext:\n\t\t// nothing.\n\tcase \"\":\n\t\t// no SASL\n\t}\n\tcfg.Net.SASL.Mechanism = sarama.SASLMechanism(mechanism)\n\n\tif !k.SASLUsername.Empty() || k.SASLMechanism != \"\" {\n\t\tcfg.Net.SASL.Enable = true\n\n\t\tversion, err := SASLVersion(cfg.Version, k.SASLVersion)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcfg.Net.SASL.Version = version\n\t}\n\treturn nil\n}\n\nfunc SASLVersion(kafkaVersion sarama.KafkaVersion, saslVersion *int) (int16, error) {\n\tif saslVersion == nil {\n\t\tif kafkaVersion.IsAtLeast(sarama.V1_0_0_0) {\n\t\t\treturn sarama.SASLHandshakeV1, nil\n\t\t}\n\t\treturn sarama.SASLHandshakeV0, nil\n\t}\n\n\tswitch *saslVersion {\n\tcase 0:\n\t\treturn sarama.SASLHandshakeV0, nil\n\tcase 1:\n\t\treturn sarama.SASLHandshakeV1, nil\n\tdefault:\n\t\treturn 0, errors.New(\"invalid SASL version\")\n\t}\n}\n\nfunc gssapiAuthType(authType string) int {\n\tswitch authType {\n\tcase \"KRB5_USER_AUTH\":\n\t\treturn sarama.KRB5_USER_AUTH\n\tcase \"KRB5_KEYTAB_AUTH\":\n\t\treturn sarama.KRB5_KEYTAB_AUTH\n\tdefault:\n\t\treturn 0\n\t}\n}\n"
  },
  {
    "path": "plugins/common/kafka/sasl_aws_iam_msk.go",
    "content": "package kafka\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/IBM/sarama\"\n\t\"github.com/aws/aws-msk-iam-sasl-signer-go/signer\"\n)\n\nconst saslTypeOAuthAWSMSKIAM = \"AWS-MSK-IAM\"\n\ntype SASLOAuthAWSMSKIAMConfig struct {\n\tSASLAWSRegion  string `toml:\"sasl_aws_msk_iam_region\"`\n\tSASLAWSProfile string `toml:\"sasl_aws_msk_iam_profile\"`\n\tSASLAWSRole    string `toml:\"sasl_aws_msk_iam_role\"`\n\tSASLAWSSession string `toml:\"sasl_aws_msk_iam_session\"`\n}\n\nfunc (c *SASLOAuthAWSMSKIAMConfig) tokenProvider(extensions map[string]string) (sarama.AccessTokenProvider, error) {\n\tif c.SASLAWSRegion == \"\" {\n\t\treturn nil, errors.New(\"region cannot be empty\")\n\t}\n\n\tif c.SASLAWSProfile != \"\" && (c.SASLAWSRole != \"\" || c.SASLAWSSession != \"\") {\n\t\treturn nil, errors.New(\"cannot mix profile based and role based authentication\")\n\t}\n\n\tif c.SASLAWSProfile == \"\" && (c.SASLAWSRole == \"\" || c.SASLAWSSession == \"\") {\n\t\treturn nil, errors.New(\"both role and session must be set for role based authentication\")\n\t}\n\n\tif c.SASLAWSProfile != \"\" {\n\t\treturn &oauthAWSMSKIAM{\n\t\t\tgenerator: func(ctx context.Context) (string, error) {\n\t\t\t\tt, _, err := signer.GenerateAuthTokenFromProfile(ctx, c.SASLAWSRegion, c.SASLAWSProfile)\n\t\t\t\treturn t, err\n\t\t\t},\n\t\t\textensions: extensions,\n\t\t}, nil\n\t}\n\n\t// Generate using role/session\n\tif c.SASLAWSRole != \"\" && c.SASLAWSSession != \"\" {\n\t\treturn &oauthAWSMSKIAM{\n\t\t\tgenerator: func(ctx context.Context) (string, error) {\n\t\t\t\tt, _, err := signer.GenerateAuthTokenFromRole(ctx, c.SASLAWSRegion, c.SASLAWSRole, c.SASLAWSSession)\n\t\t\t\treturn t, err\n\t\t\t},\n\t\t\textensions: extensions,\n\t\t}, nil\n\t}\n\n\treturn &oauthAWSMSKIAM{\n\t\tgenerator: func(ctx context.Context) (string, error) {\n\t\t\tt, _, err := signer.GenerateAuthToken(ctx, c.SASLAWSRegion)\n\t\t\treturn t, err\n\t\t},\n\t\textensions: extensions,\n\t}, nil\n}\n\ntype oauthAWSMSKIAM struct {\n\tgenerator  func(context.Context) (string, error)\n\textensions map[string]string\n}\n\n// Token generates a token using the provided AWS MSK IAM generator function.\nfunc (a *oauthAWSMSKIAM) Token() (*sarama.AccessToken, error) {\n\ttoken, err := a.generator(context.Background())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting AWS MSK IAM token failed: %w\", err)\n\t}\n\treturn &sarama.AccessToken{\n\t\tToken:      token,\n\t\tExtensions: a.extensions,\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/common/kafka/sasl_oauth_file.go",
    "content": "package kafka\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/IBM/sarama\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype oauthToken struct {\n\ttoken      config.Secret\n\textensions map[string]string\n}\n\n// Token does nothing smart, it just grabs a hard-coded token from config.\nfunc (a *oauthToken) Token() (*sarama.AccessToken, error) {\n\ttoken, err := a.token.Get()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting token failed: %w\", err)\n\t}\n\tdefer token.Destroy()\n\treturn &sarama.AccessToken{\n\t\tToken:      token.String(),\n\t\tExtensions: a.extensions,\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/common/kafka/scram_client.go",
    "content": "package kafka\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"hash\"\n\n\t\"github.com/xdg/scram\"\n)\n\nvar SHA256 scram.HashGeneratorFcn = func() hash.Hash { return sha256.New() }\nvar SHA512 scram.HashGeneratorFcn = func() hash.Hash { return sha512.New() }\n\ntype XDGSCRAMClient struct {\n\t*scram.Client\n\t*scram.ClientConversation\n\tscram.HashGeneratorFcn\n}\n\nfunc (x *XDGSCRAMClient) Begin(userName, password, authzID string) (err error) {\n\tx.Client, err = x.HashGeneratorFcn.NewClient(userName, password, authzID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tx.ClientConversation = x.Client.NewConversation()\n\treturn nil\n}\n\nfunc (x *XDGSCRAMClient) Step(challenge string) (response string, err error) {\n\treturn x.ClientConversation.Step(challenge)\n}\n\nfunc (x *XDGSCRAMClient) Done() bool {\n\treturn x.ClientConversation.Done()\n}\n"
  },
  {
    "path": "plugins/common/logrus/hook.go",
    "content": "package logrus\n\nimport (\n\t\"io\"\n\t\"log\" //nolint:depguard // Allow exceptional but valid use of log here.\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nvar once sync.Once\n\ntype LogHook struct {\n}\n\n// InstallHook installs a logging hook into the logrus standard logger, diverting all logs\n// through the Telegraf logger at debug level.  This is useful for libraries\n// that directly log to the logrus system without providing an override method.\nfunc InstallHook() {\n\tonce.Do(func() {\n\t\tlogrus.SetOutput(io.Discard)\n\t\tlogrus.AddHook(&LogHook{})\n\t})\n}\n\nfunc (*LogHook) Fire(entry *logrus.Entry) error {\n\tmsg := strings.ReplaceAll(entry.Message, \"\\n\", \" \")\n\tlog.Print(\"D! [logrus] \", msg)\n\treturn nil\n}\n\nfunc (*LogHook) Levels() []logrus.Level {\n\treturn logrus.AllLevels\n}\n"
  },
  {
    "path": "plugins/common/mqtt/mqtt.go",
    "content": "package mqtt\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\tpaho \"github.com/eclipse/paho.mqtt.golang\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\n// PublishProperties for mqtt v5-specific properties.\n// See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109\ntype PublishProperties struct {\n\tContentType    string            `toml:\"content_type\"`\n\tResponseTopic  string            `toml:\"response_topic\"`\n\tMessageExpiry  config.Duration   `toml:\"message_expiry\"`\n\tTopicAlias     *uint16           `toml:\"topic_alias\"`\n\tUserProperties map[string]string `toml:\"user_properties\"`\n}\n\ntype MqttConfig struct {\n\tServers             []string           `toml:\"servers\"`\n\tProtocol            string             `toml:\"protocol\"`\n\tUsername            config.Secret      `toml:\"username\"`\n\tPassword            config.Secret      `toml:\"password\"`\n\tTimeout             config.Duration    `toml:\"timeout\"`\n\tConnectionTimeout   config.Duration    `toml:\"connection_timeout\"`\n\tQoS                 int                `toml:\"qos\"`\n\tClientID            string             `toml:\"client_id\"`\n\tRetain              bool               `toml:\"retain\"`\n\tKeepAlive           int64              `toml:\"keep_alive\"`\n\tPersistentSession   bool               `toml:\"persistent_session\"`\n\tPublishPropertiesV5 *PublishProperties `toml:\"v5\"`\n\tClientTrace         bool               `toml:\"client_trace\" deprecated:\"1.37.0;1.45.0;use 'log_level' 'trace' instead\"`\n\n\ttls.ClientConfig\n\n\tAutoReconnect    bool        `toml:\"-\"`\n\tOnConnectionLost func(error) `toml:\"-\"`\n}\n\n// Client is a protocol neutral MQTT client for connecting,\n// disconnecting, and publishing data to a topic.\n// The protocol specific clients must implement this interface\ntype Client interface {\n\tConnect() (bool, error)\n\tPublish(topic string, data []byte) error\n\tSubscribeMultiple(filters map[string]byte, callback paho.MessageHandler) error\n\tAddRoute(topic string, callback paho.MessageHandler)\n\tClose() error\n}\n\nfunc NewClient(cfg *MqttConfig) (Client, error) {\n\tif len(cfg.Servers) == 0 {\n\t\treturn nil, errors.New(\"no servers specified\")\n\t}\n\n\tif cfg.PersistentSession && cfg.ClientID == \"\" {\n\t\treturn nil, errors.New(\"persistent_session requires client_id\")\n\t}\n\n\tif cfg.QoS > 2 || cfg.QoS < 0 {\n\t\treturn nil, fmt.Errorf(\"invalid QoS value %d; must be 0, 1 or 2\", cfg.QoS)\n\t}\n\n\tswitch cfg.Protocol {\n\tcase \"\", \"3.1.1\":\n\t\treturn NewMQTTv311Client(cfg)\n\tcase \"5\":\n\t\treturn NewMQTTv5Client(cfg)\n\t}\n\treturn nil, fmt.Errorf(\"unsupported protocol %q: must be \\\"3.1.1\\\" or \\\"5\\\"\", cfg.Protocol)\n}\n\nfunc parseServers(servers []string) ([]*url.URL, error) {\n\turls := make([]*url.URL, 0, len(servers))\n\tfor _, svr := range servers {\n\t\t// Preserve support for host:port style servers; deprecated in Telegraf 1.4.4\n\t\tif !strings.Contains(svr, \"://\") {\n\t\t\turls = append(urls, &url.URL{Scheme: \"tcp\", Host: svr})\n\t\t\tcontinue\n\t\t}\n\n\t\tu, err := url.Parse(svr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\turls = append(urls, u)\n\t}\n\treturn urls, nil\n}\n"
  },
  {
    "path": "plugins/common/mqtt/mqtt_logger.go",
    "content": "package mqtt\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype mqttLogger struct {\n\ttelegraf.Logger\n}\n\nfunc (l mqttLogger) Printf(fmt string, args ...interface{}) {\n\tl.Logger.Debugf(fmt, args...)\n}\n\nfunc (l mqttLogger) Println(args ...interface{}) {\n\tl.Logger.Debug(args...)\n}\n"
  },
  {
    "path": "plugins/common/mqtt/mqtt_test.go",
    "content": "package mqtt\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\n// Test that default client has random ID\nfunc TestRandomClientID(t *testing.T) {\n\tvar err error\n\n\tcfg := &MqttConfig{\n\t\tServers: []string{\"tcp://localhost:1883\"},\n\t}\n\n\tclient1, err := NewMQTTv311Client(cfg)\n\trequire.NoError(t, err)\n\n\tclient2, err := NewMQTTv311Client(cfg)\n\trequire.NoError(t, err)\n\n\toptions1 := client1.client.OptionsReader()\n\toptions2 := client2.client.OptionsReader()\n\trequire.NotEqual(t, options1.ClientID(), options2.ClientID())\n}\n"
  },
  {
    "path": "plugins/common/mqtt/mqtt_v3.go",
    "content": "package mqtt\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\tmqttv3 \"github.com/eclipse/paho.mqtt.golang\" // Library that supports v3.1.1\n\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/logger\"\n)\n\ntype mqttv311Client struct {\n\tclient  mqttv3.Client\n\ttimeout time.Duration\n\tqos     int\n\tretain  bool\n}\n\nfunc NewMQTTv311Client(cfg *MqttConfig) (*mqttv311Client, error) {\n\topts := mqttv3.NewClientOptions()\n\topts.KeepAlive = cfg.KeepAlive\n\topts.WriteTimeout = time.Duration(cfg.Timeout)\n\tif time.Duration(cfg.ConnectionTimeout) >= 1*time.Second {\n\t\topts.ConnectTimeout = time.Duration(cfg.ConnectionTimeout)\n\t}\n\topts.SetCleanSession(!cfg.PersistentSession)\n\tif cfg.OnConnectionLost != nil {\n\t\tonConnectionLost := func(_ mqttv3.Client, err error) {\n\t\t\tcfg.OnConnectionLost(err)\n\t\t}\n\t\topts.SetConnectionLostHandler(onConnectionLost)\n\t}\n\topts.SetAutoReconnect(cfg.AutoReconnect)\n\n\tif cfg.ClientID != \"\" {\n\t\topts.SetClientID(cfg.ClientID)\n\t} else {\n\t\tid, err := internal.RandomString(5)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"generating random client ID failed: %w\", err)\n\t\t}\n\t\topts.SetClientID(\"Telegraf-Output-\" + id)\n\t}\n\n\ttlsCfg, err := cfg.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\topts.SetTLSConfig(tlsCfg)\n\n\tif !cfg.Username.Empty() {\n\t\tuser, err := cfg.Username.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting username failed: %w\", err)\n\t\t}\n\t\topts.SetUsername(user.String())\n\t\tuser.Destroy()\n\t}\n\tif !cfg.Password.Empty() {\n\t\tpassword, err := cfg.Password.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting password failed: %w\", err)\n\t\t}\n\t\topts.SetPassword(password.String())\n\t\tpassword.Destroy()\n\t}\n\n\tservers, err := parseServers(cfg.Servers)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, server := range servers {\n\t\tif tlsCfg != nil {\n\t\t\tserver.Scheme = \"tls\"\n\t\t}\n\t\tbroker := server.String()\n\t\topts.AddBroker(broker)\n\t}\n\n\tif cfg.ClientTrace {\n\t\tlog := &mqttLogger{logger.New(\"paho\", \"\", \"\")}\n\t\tmqttv3.ERROR = log\n\t\tmqttv3.CRITICAL = log\n\t\tmqttv3.WARN = log\n\t\tmqttv3.DEBUG = log\n\t}\n\n\treturn &mqttv311Client{\n\t\tclient:  mqttv3.NewClient(opts),\n\t\ttimeout: time.Duration(cfg.Timeout),\n\t\tqos:     cfg.QoS,\n\t\tretain:  cfg.Retain,\n\t}, nil\n}\n\nfunc (m *mqttv311Client) Connect() (bool, error) {\n\ttoken := m.client.Connect()\n\n\tif token.Wait() && token.Error() != nil {\n\t\treturn false, token.Error()\n\t}\n\n\t// Persistent sessions should skip subscription if a session is present, as\n\t// the subscriptions are stored by the server.\n\ttype sessionPresent interface {\n\t\tSessionPresent() bool\n\t}\n\tif t, ok := token.(sessionPresent); ok {\n\t\treturn t.SessionPresent(), nil\n\t}\n\n\treturn false, nil\n}\n\nfunc (m *mqttv311Client) Publish(topic string, body []byte) error {\n\ttoken := m.client.Publish(topic, byte(m.qos), m.retain, body)\n\tif !token.WaitTimeout(m.timeout) {\n\t\treturn internal.ErrTimeout\n\t}\n\treturn token.Error()\n}\n\nfunc (m *mqttv311Client) SubscribeMultiple(filters map[string]byte, callback mqttv3.MessageHandler) error {\n\ttoken := m.client.SubscribeMultiple(filters, callback)\n\ttoken.Wait()\n\treturn token.Error()\n}\n\nfunc (m *mqttv311Client) AddRoute(topic string, callback mqttv3.MessageHandler) {\n\tm.client.AddRoute(topic, callback)\n}\n\nfunc (m *mqttv311Client) Close() error {\n\tif m.client.IsConnected() {\n\t\tm.client.Disconnect(100)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/mqtt/mqtt_v5.go",
    "content": "package mqtt\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\tmqttv5auto \"github.com/eclipse/paho.golang/autopaho\"\n\tmqttv5 \"github.com/eclipse/paho.golang/paho\"\n\tpaho \"github.com/eclipse/paho.mqtt.golang\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/logger\"\n)\n\ntype mqttv5Client struct {\n\tclient      *mqttv5auto.ConnectionManager\n\toptions     mqttv5auto.ClientConfig\n\tusername    config.Secret\n\tpassword    config.Secret\n\ttimeout     time.Duration\n\tqos         int\n\tretain      bool\n\tclientTrace bool\n\tproperties  *mqttv5.PublishProperties\n}\n\nfunc NewMQTTv5Client(cfg *MqttConfig) (*mqttv5Client, error) {\n\topts := mqttv5auto.ClientConfig{\n\t\tKeepAlive:      uint16(cfg.KeepAlive),\n\t\tOnConnectError: cfg.OnConnectionLost,\n\t}\n\topts.ConnectPacketBuilder = func(c *mqttv5.Connect, _ *url.URL) (*mqttv5.Connect, error) {\n\t\tc.CleanStart = cfg.PersistentSession\n\t\treturn c, nil\n\t}\n\n\tif time.Duration(cfg.ConnectionTimeout) >= 1*time.Second {\n\t\topts.ConnectTimeout = time.Duration(cfg.ConnectionTimeout)\n\t}\n\n\tif cfg.ClientID != \"\" {\n\t\topts.ClientID = cfg.ClientID\n\t} else {\n\t\tid, err := internal.RandomString(5)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"generating random client ID failed: %w\", err)\n\t\t}\n\t\topts.ClientID = \"Telegraf-Output-\" + id\n\t}\n\n\ttlsCfg, err := cfg.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif tlsCfg != nil {\n\t\topts.TlsCfg = tlsCfg\n\t}\n\n\tservers, err := parseServers(cfg.Servers)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbrokers := make([]*url.URL, 0, len(servers))\n\tfor _, server := range servers {\n\t\tif tlsCfg != nil {\n\t\t\tserver.Scheme = \"tls\"\n\t\t}\n\t\tbrokers = append(brokers, server)\n\t}\n\topts.BrokerUrls = brokers\n\n\t// Build the v5 specific publish properties if they are present in the config.\n\t// These should not change during the lifecycle of the client.\n\tvar properties *mqttv5.PublishProperties\n\tif cfg.PublishPropertiesV5 != nil {\n\t\tproperties = &mqttv5.PublishProperties{\n\t\t\tContentType:   cfg.PublishPropertiesV5.ContentType,\n\t\t\tResponseTopic: cfg.PublishPropertiesV5.ResponseTopic,\n\t\t\tTopicAlias:    cfg.PublishPropertiesV5.TopicAlias,\n\t\t}\n\n\t\tmessageExpiry := time.Duration(cfg.PublishPropertiesV5.MessageExpiry)\n\t\tif expirySeconds := uint32(messageExpiry.Seconds()); expirySeconds > 0 {\n\t\t\tproperties.MessageExpiry = &expirySeconds\n\t\t}\n\n\t\tproperties.User = make([]mqttv5.UserProperty, 0, len(cfg.PublishPropertiesV5.UserProperties))\n\t\tfor k, v := range cfg.PublishPropertiesV5.UserProperties {\n\t\t\tproperties.User.Add(k, v)\n\t\t}\n\t}\n\n\treturn &mqttv5Client{\n\t\toptions:     opts,\n\t\ttimeout:     time.Duration(cfg.Timeout),\n\t\tusername:    cfg.Username,\n\t\tpassword:    cfg.Password,\n\t\tqos:         cfg.QoS,\n\t\tretain:      cfg.Retain,\n\t\tproperties:  properties,\n\t\tclientTrace: cfg.ClientTrace,\n\t}, nil\n}\n\nfunc (m *mqttv5Client) Connect() (bool, error) {\n\tuser, err := m.username.Get()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tdefer user.Destroy()\n\tpass, err := m.password.Get()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer pass.Destroy()\n\tm.options.ConnectUsername = user.String()\n\tm.options.ConnectPassword = []byte(pass.String())\n\n\tif m.clientTrace {\n\t\tlog := mqttLogger{logger.New(\"paho\", \"\", \"\")}\n\t\tm.options.Debug = log\n\t\tm.options.Errors = log\n\t}\n\n\tclient, err := mqttv5auto.NewConnection(context.Background(), m.options)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tm.client = client\n\treturn false, client.AwaitConnection(context.Background())\n}\n\nfunc (m *mqttv5Client) Publish(topic string, body []byte) error {\n\tctx, cancel := context.WithTimeout(context.Background(), m.timeout)\n\tdefer cancel()\n\n\t_, err := m.client.Publish(ctx, &mqttv5.Publish{\n\t\tTopic:      topic,\n\t\tQoS:        byte(m.qos),\n\t\tRetain:     m.retain,\n\t\tPayload:    body,\n\t\tProperties: m.properties,\n\t})\n\n\treturn err\n}\n\nfunc (*mqttv5Client) SubscribeMultiple(filters map[string]byte, callback paho.MessageHandler) error {\n\t_, _ = filters, callback\n\tpanic(\"not implemented\")\n}\n\nfunc (*mqttv5Client) AddRoute(topic string, callback paho.MessageHandler) {\n\t_, _ = topic, callback\n\tpanic(\"not implemented\")\n}\n\nfunc (m *mqttv5Client) Close() error {\n\treturn m.client.Disconnect(context.Background())\n}\n"
  },
  {
    "path": "plugins/common/oauth/config.go",
    "content": "package oauth\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/oauth2\"\n\t\"golang.org/x/oauth2/clientcredentials\"\n)\n\ntype OAuth2Config struct {\n\t// OAuth2 Credentials\n\tClientID     string   `toml:\"client_id\"`\n\tClientSecret string   `toml:\"client_secret\"`\n\tTokenURL     string   `toml:\"token_url\"`\n\tAudience     string   `toml:\"audience\"`\n\tScopes       []string `toml:\"scopes\"`\n}\n\nfunc (o *OAuth2Config) CreateOauth2Client(ctx context.Context, client *http.Client) *http.Client {\n\tif o.ClientID == \"\" || o.ClientSecret == \"\" || o.TokenURL == \"\" {\n\t\treturn client\n\t}\n\n\toauthConfig := clientcredentials.Config{\n\t\tClientID:       o.ClientID,\n\t\tClientSecret:   o.ClientSecret,\n\t\tTokenURL:       o.TokenURL,\n\t\tScopes:         o.Scopes,\n\t\tEndpointParams: make(url.Values),\n\t}\n\n\tif o.Audience != \"\" {\n\t\toauthConfig.EndpointParams.Add(\"audience\", o.Audience)\n\t}\n\n\tctx = context.WithValue(ctx, oauth2.HTTPClient, client)\n\tclient = oauthConfig.Client(ctx)\n\n\treturn client\n}\n"
  },
  {
    "path": "plugins/common/opcua/client.go",
    "content": "package opcua\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\" //nolint:depguard // just for debug\n\t\"net/url\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua\"\n\t\"github.com/gopcua/opcua/debug\"\n\t\"github.com/gopcua/opcua/ua\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype OpcUAWorkarounds struct {\n\tAdditionalValidStatusCodes []string `toml:\"additional_valid_status_codes\"`\n}\n\ntype ConnectionState opcua.ConnState\n\nconst (\n\tClosed       ConnectionState = ConnectionState(opcua.Closed)\n\tConnected    ConnectionState = ConnectionState(opcua.Connected)\n\tConnecting   ConnectionState = ConnectionState(opcua.Connecting)\n\tDisconnected ConnectionState = ConnectionState(opcua.Disconnected)\n\tReconnecting ConnectionState = ConnectionState(opcua.Reconnecting)\n)\n\nfunc (c ConnectionState) String() string {\n\treturn opcua.ConnState(c).String()\n}\n\ntype OpcUAClientConfig struct {\n\tEndpoint          string          `toml:\"endpoint\"`\n\tSecurityPolicy    string          `toml:\"security_policy\"`\n\tSecurityMode      string          `toml:\"security_mode\"`\n\tCertificate       string          `toml:\"certificate\"`\n\tPrivateKey        string          `toml:\"private_key\"`\n\tRemoteCertificate string          `toml:\"remote_certificate\"`\n\tUsername          config.Secret   `toml:\"username\"`\n\tPassword          config.Secret   `toml:\"password\"`\n\tAuthMethod        string          `toml:\"auth_method\"`\n\tConnectTimeout    config.Duration `toml:\"connect_timeout\"`\n\tRequestTimeout    config.Duration `toml:\"request_timeout\"`\n\tClientTrace       bool            `toml:\"client_trace\"`\n\n\tOptionalFields []string         `toml:\"optional_fields\"`\n\tWorkarounds    OpcUAWorkarounds `toml:\"workarounds\"`\n\tSessionTimeout config.Duration  `toml:\"session_timeout\"`\n}\n\nfunc (o *OpcUAClientConfig) Validate() error {\n\t// Validate endpoint\n\tif o.Endpoint == \"\" {\n\t\treturn fmt.Errorf(\"%w: endpoint cannot be empty\", ErrInvalidEndpoint)\n\t}\n\tu, err := url.Parse(o.Endpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%w: invalid endpoint URL %q: %w\", ErrInvalidEndpoint, o.Endpoint, err)\n\t}\n\tif u.Scheme != \"opc.tcp\" {\n\t\treturn fmt.Errorf(\"%w: invalid endpoint scheme %q, expected 'opc.tcp'\", ErrInvalidEndpoint, u.Scheme)\n\t}\n\n\t// Validate security policy\n\tswitch o.SecurityPolicy {\n\tcase \"\", \"None\", \"Basic128Rsa15\", \"Basic256\", \"Basic256Sha256\", \"auto\":\n\t\t// valid\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %q, valid options: None, Basic128Rsa15, Basic256, Basic256Sha256, auto\", ErrInvalidSecurityPolicy, o.SecurityPolicy)\n\t}\n\n\t// Validate security mode\n\tswitch o.SecurityMode {\n\tcase \"\", \"None\", \"Sign\", \"SignAndEncrypt\", \"auto\":\n\t\t// valid\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %q, valid options: None, Sign, SignAndEncrypt, auto\", ErrInvalidSecurityMode, o.SecurityMode)\n\t}\n\n\t// Validate authentication method\n\tswitch o.AuthMethod {\n\tcase \"\", \"Anonymous\", \"UserName\", \"Certificate\", \"auto\":\n\t\t// valid\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %q, valid options: Anonymous, UserName, Certificate, auto\", ErrInvalidAuthMethod, o.AuthMethod)\n\t}\n\n\t// Validate certificate configuration\n\tif err := o.validateCertificateConfiguration(); err != nil {\n\t\treturn err\n\t}\n\n\t// Validate credentials based on auth method\n\tif o.AuthMethod == \"UserName\" {\n\t\tif o.Username.Empty() {\n\t\t\treturn fmt.Errorf(\"%w: username required for UserName authentication\", ErrInvalidConfiguration)\n\t\t}\n\t\tif o.Password.Empty() {\n\t\t\treturn fmt.Errorf(\"%w: password required for UserName authentication\", ErrInvalidConfiguration)\n\t\t}\n\t}\n\n\t// Validate optional fields\n\tfor i, field := range o.OptionalFields {\n\t\tif field != \"DataType\" {\n\t\t\treturn fmt.Errorf(\"%w: unknown optional_fields[%d] value %q, valid options: DataType\", ErrInvalidConfiguration, i, field)\n\t\t}\n\t}\n\n\t// Validate timeouts\n\tif o.ConnectTimeout < 0 {\n\t\treturn fmt.Errorf(\"%w: connect_timeout must be non-negative, got %v\", ErrInvalidConfiguration, o.ConnectTimeout)\n\t}\n\tif o.ConnectTimeout != 0 && time.Duration(o.ConnectTimeout) < 100*time.Millisecond {\n\t\treturn fmt.Errorf(\"%w: connect_timeout too short (%v), minimum recommended is 100ms\", ErrInvalidConfiguration, o.ConnectTimeout)\n\t}\n\n\tif o.RequestTimeout < 0 {\n\t\treturn fmt.Errorf(\"%w: request_timeout must be non-negative, got %v\", ErrInvalidConfiguration, o.RequestTimeout)\n\t}\n\tif o.RequestTimeout != 0 && time.Duration(o.RequestTimeout) < 100*time.Millisecond {\n\t\treturn fmt.Errorf(\"%w: request_timeout too short (%v), minimum recommended is 100ms\", ErrInvalidConfiguration, o.RequestTimeout)\n\t}\n\n\tif o.SessionTimeout < 0 {\n\t\treturn fmt.Errorf(\"%w: session_timeout must be non-negative, got %v\", ErrInvalidConfiguration, o.SessionTimeout)\n\t}\n\tif o.SessionTimeout != 0 && time.Duration(o.SessionTimeout) < 1*time.Second {\n\t\treturn fmt.Errorf(\"%w: session_timeout too short (%v), minimum recommended is 1s\", ErrInvalidConfiguration, o.SessionTimeout)\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAClientConfig) validateCertificateConfiguration() error {\n\t// If using None/None security, client certificates are optional\n\tif o.SecurityPolicy == \"None\" && o.SecurityMode == \"None\" {\n\t\treturn nil\n\t}\n\n\t// Both empty is valid (will generate self-signed)\n\tif o.Certificate == \"\" && o.PrivateKey == \"\" {\n\t\treturn nil\n\t}\n\n\t// Both must be provided if one is provided\n\tif o.Certificate == \"\" {\n\t\treturn fmt.Errorf(\"%w: private key provided without certificate\", ErrInvalidConfiguration)\n\t}\n\tif o.PrivateKey == \"\" {\n\t\treturn fmt.Errorf(\"%w: certificate provided without private key\", ErrInvalidConfiguration)\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAClientConfig) CreateClient(telegrafLogger telegraf.Logger) (*OpcUAClient, error) {\n\terr := o.Validate()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif o.ClientTrace {\n\t\tdebug.Enable = true\n\t\tdebug.Logger = log.New(&DebugLogger{Log: telegrafLogger}, \"\", 0)\n\t}\n\n\tc := &OpcUAClient{\n\t\tConfig: o,\n\t\tLog:    telegrafLogger,\n\t}\n\tc.Log.Debug(\"Initialising OpcUAClient\")\n\n\terr = c.setupWorkarounds()\n\treturn c, err\n}\n\ntype OpcUAClient struct {\n\tConfig *OpcUAClientConfig\n\tLog    telegraf.Logger\n\n\tClient         *opcua.Client\n\tnamespaceArray []string\n\n\topts  []opcua.Option\n\tcodes []ua.StatusCode\n}\n\n// determineOrCreateCertificates handles certificate determination and generation logic\nfunc (o *OpcUAClient) determineOrCreateCertificates() error {\n\tcertFile := o.Config.Certificate\n\tkeyFile := o.Config.PrivateKey\n\n\tif certFile == \"\" && keyFile != \"\" || certFile != \"\" && keyFile == \"\" {\n\t\treturn errors.New(\"specified only one of certificate or private key\")\n\t}\n\n\tvar generate, permanent bool\n\tif certFile == \"\" && keyFile == \"\" {\n\t\t// Case 1: Both empty, generate a non-permanent file\n\t\tgenerate = true\n\t} else {\n\t\t// Case 2 or 3: Both specified - check if files exist\n\t\tvar certExists, keyExists bool\n\t\tif _, err := os.Stat(certFile); err == nil {\n\t\t\tcertExists = true\n\t\t} else if !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"checking certificate %q failed: %w\", certFile, err)\n\t\t}\n\t\tif _, err := os.Stat(keyFile); err == nil {\n\t\t\tkeyExists = true\n\t\t} else if !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"checking private key %q failed: %w\", keyFile, err)\n\t\t}\n\n\t\t// Either both certificate and private key exists or they don't, we don't support mixed setups\n\t\tif certExists != keyExists {\n\t\t\treturn &CertificateError{\n\t\t\t\tOperation: \"validation\",\n\t\t\t\tPath:      keyFile,\n\t\t\t\tErr:       fmt.Errorf(\"only one of certificate %q and private key %q exists\", certFile, keyFile),\n\t\t\t}\n\t\t}\n\n\t\tgenerate = !certExists && !keyExists\n\t\tpermanent = true\n\t}\n\n\t// If both exist, we don't need to do anything, they will be loaded later\n\tif !generate {\n\t\to.Log.Debugf(\"Using existing certificates from %q and %q\", certFile, keyFile)\n\t\treturn nil\n\t}\n\n\tif permanent {\n\t\to.Log.Infof(\"Generating permanent self-signed certificate at %q and %q\", certFile, keyFile)\n\t} else {\n\t\to.Log.Debug(\"Generating temporary self-signed certificate\")\n\t}\n\n\t// Generate the certificates\n\tcert, privateKey, err := generateCert(\"urn:telegraf:gopcua:client\", 2048, certFile, keyFile, 365*24*time.Hour)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to.Config.Certificate = cert\n\to.Config.PrivateKey = privateKey\n\n\treturn nil\n}\n\n// SetupOptions reads the endpoints from the specified server and sets up all authentication\nfunc (o *OpcUAClient) SetupOptions() error {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Config.ConnectTimeout))\n\tdefer cancel()\n\t// Get a list of the endpoints for our target server\n\tendpoints, err := opcua.GetEndpoints(ctx, o.Config.Endpoint)\n\tif err != nil {\n\t\treturn &EndpointError{\n\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\tErr:      fmt.Errorf(\"failed to get endpoints: %w\", err),\n\t\t}\n\t}\n\n\tif o.Config.SecurityPolicy != \"None\" || o.Config.SecurityMode != \"None\" {\n\t\tif err := o.determineOrCreateCertificates(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\to.Log.Debug(\"Configuring OPC UA connection options\")\n\to.opts, err = o.generateClientOpts(endpoints)\n\n\treturn err\n}\n\nfunc (o *OpcUAClient) setupWorkarounds() error {\n\to.codes = []ua.StatusCode{ua.StatusOK}\n\tfor i, c := range o.Config.Workarounds.AdditionalValidStatusCodes {\n\t\tval, err := strconv.ParseUint(c, 0, 32) // setting 32 bits to allow for safe conversion\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w: invalid status code %q at index %d: %w\", ErrStatusCodeParsing, c, i, err)\n\t\t}\n\t\to.codes = append(o.codes, ua.StatusCode(val))\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAClient) StatusCodeOK(code ua.StatusCode) bool {\n\tfor _, val := range o.codes {\n\t\tif val == code {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Connect to an OPC UA device\nfunc (o *OpcUAClient) Connect(ctx context.Context) error {\n\to.Log.Debug(\"Connecting OPC UA Client to server\")\n\tu, err := url.Parse(o.Config.Endpoint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswitch u.Scheme {\n\tcase \"opc.tcp\":\n\t\tif err := o.SetupOptions(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif o.Client != nil {\n\t\t\to.Log.Warnf(\"Closing connection to %q as already connected\", u)\n\t\t\tif err := o.Client.Close(ctx); err != nil {\n\t\t\t\t// Only log the error but do not bail-out here as this prevents\n\t\t\t\t// reconnections for multiple parties (see e.g. #9523).\n\t\t\t\to.Log.Errorf(\"Closing connection to %s failed: %v\", o.Config.Endpoint, err)\n\t\t\t}\n\t\t}\n\n\t\to.Client, err = opcua.NewClient(o.Config.Endpoint, o.opts...)\n\t\tif err != nil {\n\t\t\treturn &EndpointError{\n\t\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\t\tErr:      fmt.Errorf(\"%w: failed to create client: %w\", ErrConnectionFailed, err),\n\t\t\t}\n\t\t}\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Config.ConnectTimeout))\n\t\tdefer cancel()\n\t\tif err := o.Client.Connect(ctx); err != nil {\n\t\t\treturn &EndpointError{\n\t\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\t\tErr:      fmt.Errorf(\"%w: %w\", ErrConnectionFailed, err),\n\t\t\t}\n\t\t}\n\t\to.Log.Debug(\"Connected to OPC UA Server\")\n\n\tdefault:\n\t\treturn &EndpointError{\n\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\tErr:      fmt.Errorf(\"%w: unsupported scheme %q, expected opc.tcp\", ErrInvalidEndpoint, u.Scheme),\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *OpcUAClient) Disconnect(ctx context.Context) error {\n\to.Log.Debug(\"Disconnecting from OPC UA Server\")\n\tu, err := url.Parse(o.Config.Endpoint)\n\tif err != nil {\n\t\treturn &EndpointError{\n\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\tErr:      fmt.Errorf(\"%w: %w\", ErrInvalidEndpoint, err),\n\t\t}\n\t}\n\n\tswitch u.Scheme {\n\tcase \"opc.tcp\":\n\t\t// We can't do anything about failing to close a connection\n\t\terr := o.Client.Close(ctx)\n\t\to.Client = nil\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to close connection to %s: %w\", o.Config.Endpoint, err)\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn &EndpointError{\n\t\t\tEndpoint: o.Config.Endpoint,\n\t\t\tErr:      fmt.Errorf(\"%w: unsupported scheme %q\", ErrInvalidEndpoint, u.Scheme),\n\t\t}\n\t}\n}\n\nfunc (o *OpcUAClient) State() ConnectionState {\n\tif o.Client == nil {\n\t\treturn Disconnected\n\t}\n\treturn ConnectionState(o.Client.State())\n}\n\n// UpdateNamespaceArray fetches the namespace array from the OPC UA server\n// The namespace array is stored at the well-known node ns=0;i=2255\nfunc (o *OpcUAClient) UpdateNamespaceArray(ctx context.Context) error {\n\tif o.Client == nil {\n\t\treturn errors.New(\"client not connected\")\n\t}\n\n\tnodeID := ua.NewNumericNodeID(0, 2255)\n\treq := &ua.ReadRequest{\n\t\tMaxAge: 2000,\n\t\tNodesToRead: []*ua.ReadValueID{\n\t\t\t{NodeID: nodeID},\n\t\t},\n\t\tTimestampsToReturn: ua.TimestampsToReturnBoth,\n\t}\n\n\tresp, err := o.Client.Read(ctx, req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read namespace array: %w\", err)\n\t}\n\n\tif len(resp.Results) == 0 {\n\t\treturn errors.New(\"no results returned when reading namespace array\")\n\t}\n\n\tresult := resp.Results[0]\n\tif result.Status != ua.StatusOK {\n\t\treturn fmt.Errorf(\"failed to read namespace array, status: %w\", result.Status)\n\t}\n\n\tif result.Value == nil {\n\t\treturn errors.New(\"namespace array value is nil\")\n\t}\n\n\t// The namespace array is an array of strings\n\tnamespaces, ok := result.Value.Value().([]string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"namespace array is not a string array, got type: %T\", result.Value.Value())\n\t}\n\n\to.namespaceArray = namespaces\n\to.Log.Debugf(\"Fetched namespace array with %d entries\", len(namespaces))\n\treturn nil\n}\n\n// NamespaceArray returns the cached namespace array\nfunc (o *OpcUAClient) NamespaceArray() []string {\n\treturn o.namespaceArray\n}\n"
  },
  {
    "path": "plugins/common/opcua/client_test.go",
    "content": "package opcua\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gopcua/opcua/ua\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSetupWorkarounds(t *testing.T) {\n\to := OpcUAClient{\n\t\tConfig: &OpcUAClientConfig{\n\t\t\tWorkarounds: OpcUAWorkarounds{\n\t\t\t\tAdditionalValidStatusCodes: []string{\"0xC0\", \"0x00AA0000\", \"0x80000000\"},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := o.setupWorkarounds()\n\trequire.NoError(t, err)\n\n\trequire.Len(t, o.codes, 4)\n\trequire.Equal(t, o.codes[0], ua.StatusCode(0))\n\trequire.Equal(t, o.codes[1], ua.StatusCode(192))\n\trequire.Equal(t, o.codes[2], ua.StatusCode(11141120))\n\trequire.Equal(t, o.codes[3], ua.StatusCode(2147483648))\n}\n\nfunc TestCheckStatusCode(t *testing.T) {\n\tvar o OpcUAClient\n\to.codes = []ua.StatusCode{ua.StatusCode(0), ua.StatusCode(192), ua.StatusCode(11141120)}\n\trequire.True(t, o.StatusCodeOK(ua.StatusCode(192)))\n}\n\nfunc TestOpcUAClientConfigValidateSuccess(t *testing.T) {\n\tconfig := OpcUAClientConfig{\n\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\tSecurityPolicy: \"None\",\n\t\tSecurityMode:   \"None\",\n\t}\n\n\terr := config.Validate()\n\trequire.NoError(t, err)\n}\n\nfunc TestOpcUAClientConfigValidateFail(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tconfig      OpcUAClientConfig\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname: \"empty endpoint\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint: \"\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidEndpoint,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid endpoint URL\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint: \"://invalid-url\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidEndpoint,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid security policy\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"InvalidPolicy\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidSecurityPolicy,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid security mode\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"InvalidMode\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidSecurityMode,\n\t\t},\n\t\t{\n\t\t\tname: \"certificate without private key\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"Basic256\",\n\t\t\t\tSecurityMode:   \"SignAndEncrypt\",\n\t\t\t\tCertificate:    \"cert.pem\",\n\t\t\t\tPrivateKey:     \"\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidConfiguration,\n\t\t},\n\t\t{\n\t\t\tname: \"private key without certificate\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"Basic256\",\n\t\t\t\tSecurityMode:   \"SignAndEncrypt\",\n\t\t\t\tCertificate:    \"\",\n\t\t\t\tPrivateKey:     \"key.pem\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidConfiguration,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid auth method\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:   \"opc.tcp://localhost:4840\",\n\t\t\t\tAuthMethod: \"InvalidAuth\",\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidAuthMethod,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid optional field\",\n\t\t\tconfig: OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tOptionalFields: []string{\"InvalidField\"},\n\t\t\t},\n\t\t\texpectedErr: ErrInvalidConfiguration,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.config.Validate()\n\t\t\trequire.Error(t, err)\n\t\t\t// Check that the error chain contains the expected error type\n\t\t\trequire.ErrorIs(t, err, tt.expectedErr)\n\t\t})\n\t}\n}\n\nfunc TestOpcUAClientSetupWorkarounds(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tstatusCodes []string\n\t\texpectErr   bool\n\t}{\n\t\t{\n\t\t\tname:        \"valid status codes\",\n\t\t\tstatusCodes: []string{\"0x80\", \"0x00AA0000\", \"123\"},\n\t\t\texpectErr:   false,\n\t\t},\n\t\t{\n\t\t\tname:        \"invalid status code\",\n\t\t\tstatusCodes: []string{\"invalid\"},\n\t\t\texpectErr:   true,\n\t\t},\n\t\t{\n\t\t\tname:        \"empty status codes\",\n\t\t\tstatusCodes: nil,\n\t\t\texpectErr:   false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tclient := &OpcUAClient{\n\t\t\t\tConfig: &OpcUAClientConfig{\n\t\t\t\t\tWorkarounds: OpcUAWorkarounds{\n\t\t\t\t\t\tAdditionalValidStatusCodes: tt.statusCodes,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := client.setupWorkarounds()\n\t\t\tif tt.expectErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.ErrorIs(t, err, ErrStatusCodeParsing)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\t// Should always have at least StatusOK\n\t\t\t\trequire.GreaterOrEqual(t, len(client.codes), 1)\n\t\t\t\trequire.Equal(t, ua.StatusOK, client.codes[0])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRemoteCertificateValidation(t *testing.T) {\n\ttests := []struct {\n\t\tname              string\n\t\tsecurityPolicy    string\n\t\tsecurityMode      string\n\t\tremoteCertificate string\n\t}{\n\t\t{\n\t\t\tname:              \"no remote certificate configured\",\n\t\t\tsecurityPolicy:    \"None\",\n\t\t\tsecurityMode:      \"None\",\n\t\t\tremoteCertificate: \"\",\n\t\t},\n\t\t{\n\t\t\tname:              \"remote certificate path provided with None security\",\n\t\t\tsecurityPolicy:    \"None\",\n\t\t\tsecurityMode:      \"None\",\n\t\t\tremoteCertificate: \"/etc/telegraf/server_cert.pem\",\n\t\t},\n\t\t{\n\t\t\tname:              \"remote certificate path provided with SignAndEncrypt\",\n\t\t\tsecurityPolicy:    \"Basic256Sha256\",\n\t\t\tsecurityMode:      \"SignAndEncrypt\",\n\t\t\tremoteCertificate: \"/etc/telegraf/server_cert.pem\",\n\t\t},\n\t\t{\n\t\t\tname:              \"remote certificate path provided with auto security\",\n\t\t\tsecurityPolicy:    \"auto\",\n\t\t\tsecurityMode:      \"auto\",\n\t\t\tremoteCertificate: \"/etc/telegraf/server_cert.pem\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconfig := OpcUAClientConfig{\n\t\t\t\tEndpoint:          \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy:    tt.securityPolicy,\n\t\t\t\tSecurityMode:      tt.securityMode,\n\t\t\t\tRemoteCertificate: tt.remoteCertificate,\n\t\t\t}\n\n\t\t\trequire.NoError(t, config.Validate())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/opcua/errors.go",
    "content": "package opcua\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Common OPC UA error types for better error handling and classification\nvar (\n\t// ErrInvalidEndpoint indicates an invalid or malformed endpoint URL\n\tErrInvalidEndpoint = errors.New(\"invalid endpoint\")\n\n\t// ErrInvalidSecurityPolicy indicates an unsupported security policy\n\tErrInvalidSecurityPolicy = errors.New(\"invalid security policy\")\n\n\t// ErrInvalidSecurityMode indicates an unsupported security mode\n\tErrInvalidSecurityMode = errors.New(\"invalid security mode\")\n\n\t// ErrInvalidAuthMethod indicates an unsupported authentication method\n\tErrInvalidAuthMethod = errors.New(\"invalid authentication method\")\n\n\t// ErrCertificateGeneration indicates a failure in certificate generation\n\tErrCertificateGeneration = errors.New(\"certificate generation failed\")\n\n\t// ErrConnectionFailed indicates a connection failure\n\tErrConnectionFailed = errors.New(\"connection failed\")\n\n\t// ErrEndpointNotFound indicates no suitable endpoint was found\n\tErrEndpointNotFound = errors.New(\"no suitable endpoint found\")\n\n\t// ErrInvalidConfiguration indicates invalid configuration parameters\n\tErrInvalidConfiguration = errors.New(\"invalid configuration\")\n\n\t// ErrStatusCodeParsing indicates failure to parse status codes\n\tErrStatusCodeParsing = errors.New(\"status code parsing failed\")\n)\n\n// EndpointError represents an error related to endpoint configuration\ntype EndpointError struct {\n\tEndpoint string\n\tErr      error\n}\n\nfunc (e *EndpointError) Error() string {\n\treturn fmt.Sprintf(\"endpoint %q: %v\", e.Endpoint, e.Err)\n}\n\nfunc (e *EndpointError) Unwrap() error {\n\treturn e.Err\n}\n\n// SecurityError represents an error related to security configuration\ntype SecurityError struct {\n\tPolicy string\n\tMode   string\n\tErr    error\n}\n\nfunc (e *SecurityError) Error() string {\n\tif e.Policy != \"\" && e.Mode != \"\" {\n\t\treturn fmt.Sprintf(\"security policy %q, mode %q: %v\", e.Policy, e.Mode, e.Err)\n\t} else if e.Policy != \"\" {\n\t\treturn fmt.Sprintf(\"security policy %q: %v\", e.Policy, e.Err)\n\t} else if e.Mode != \"\" {\n\t\treturn fmt.Sprintf(\"security mode %q: %v\", e.Mode, e.Err)\n\t}\n\treturn fmt.Sprintf(\"security configuration: %v\", e.Err)\n}\n\nfunc (e *SecurityError) Unwrap() error {\n\treturn e.Err\n}\n\n// AuthenticationError represents an error related to authentication\ntype AuthenticationError struct {\n\tMethod string\n\tErr    error\n}\n\nfunc (e *AuthenticationError) Error() string {\n\treturn fmt.Sprintf(\"authentication method %q: %v\", e.Method, e.Err)\n}\n\nfunc (e *AuthenticationError) Unwrap() error {\n\treturn e.Err\n}\n\n// CertificateError represents an error related to certificate operations\ntype CertificateError struct {\n\tOperation string\n\tPath      string\n\tErr       error\n}\n\nfunc (e *CertificateError) Error() string {\n\tif e.Path != \"\" {\n\t\treturn fmt.Sprintf(\"certificate %s at %q: %v\", e.Operation, e.Path, e.Err)\n\t}\n\treturn fmt.Sprintf(\"certificate %s: %v\", e.Operation, e.Err)\n}\n\nfunc (e *CertificateError) Unwrap() error {\n\treturn e.Err\n}\n"
  },
  {
    "path": "plugins/common/opcua/errors_test.go",
    "content": "package opcua\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEndpointError(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\terr      *EndpointError\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"endpoint error with wrapped error\",\n\t\t\terr: &EndpointError{\n\t\t\t\tEndpoint: \"opc.tcp://localhost:4840\",\n\t\t\t\tErr:      ErrInvalidEndpoint,\n\t\t\t},\n\t\t\texpected: `endpoint \"opc.tcp://localhost:4840\": invalid endpoint`,\n\t\t},\n\t\t{\n\t\t\tname: \"empty endpoint\",\n\t\t\terr: &EndpointError{\n\t\t\t\tEndpoint: \"\",\n\t\t\t\tErr:      ErrInvalidEndpoint,\n\t\t\t},\n\t\t\texpected: `endpoint \"\": invalid endpoint`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.err.Error())\n\t\t\trequire.ErrorIs(t, tt.err, ErrInvalidEndpoint)\n\t\t})\n\t}\n}\n\nfunc TestSecurityError(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\terr      *SecurityError\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"policy and mode error\",\n\t\t\terr: &SecurityError{\n\t\t\t\tPolicy: \"Basic256\",\n\t\t\t\tMode:   \"SignAndEncrypt\",\n\t\t\t\tErr:    ErrInvalidSecurityPolicy,\n\t\t\t},\n\t\t\texpected: `security policy \"Basic256\", mode \"SignAndEncrypt\": invalid security policy`,\n\t\t},\n\t\t{\n\t\t\tname: \"policy only error\",\n\t\t\terr: &SecurityError{\n\t\t\t\tPolicy: \"Invalid\",\n\t\t\t\tErr:    ErrInvalidSecurityPolicy,\n\t\t\t},\n\t\t\texpected: `security policy \"Invalid\": invalid security policy`,\n\t\t},\n\t\t{\n\t\t\tname: \"mode only error\",\n\t\t\terr: &SecurityError{\n\t\t\t\tMode: \"Invalid\",\n\t\t\t\tErr:  ErrInvalidSecurityMode,\n\t\t\t},\n\t\t\texpected: `security mode \"Invalid\": invalid security mode`,\n\t\t},\n\t\t{\n\t\t\tname: \"generic security error\",\n\t\t\terr: &SecurityError{\n\t\t\t\tErr: ErrInvalidConfiguration,\n\t\t\t},\n\t\t\texpected: `security configuration: invalid configuration`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.err.Error())\n\t\t\trequire.ErrorIs(t, tt.err, tt.err.Err)\n\t\t})\n\t}\n}\n\nfunc TestAuthenticationError(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\terr      *AuthenticationError\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"username authentication error\",\n\t\t\terr: &AuthenticationError{\n\t\t\t\tMethod: \"username\",\n\t\t\t\tErr:    errors.New(\"missing username\"),\n\t\t\t},\n\t\t\texpected: `authentication method \"username\": missing username`,\n\t\t},\n\t\t{\n\t\t\tname: \"certificate authentication error\",\n\t\t\terr: &AuthenticationError{\n\t\t\t\tMethod: \"certificate\",\n\t\t\t\tErr:    errors.New(\"invalid certificate\"),\n\t\t\t},\n\t\t\texpected: `authentication method \"certificate\": invalid certificate`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.err.Error())\n\t\t})\n\t}\n}\n\nfunc TestCertificateError(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\terr      *CertificateError\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"certificate generation with path\",\n\t\t\terr: &CertificateError{\n\t\t\t\tOperation: \"generation\",\n\t\t\t\tPath:      \"/tmp/cert.pem\",\n\t\t\t\tErr:       ErrCertificateGeneration,\n\t\t\t},\n\t\t\texpected: `certificate generation at \"/tmp/cert.pem\": certificate generation failed`,\n\t\t},\n\t\t{\n\t\t\tname: \"certificate operation without path\",\n\t\t\terr: &CertificateError{\n\t\t\t\tOperation: \"validation\",\n\t\t\t\tErr:       ErrCertificateGeneration,\n\t\t\t},\n\t\t\texpected: `certificate validation: certificate generation failed`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.err.Error())\n\t\t\trequire.ErrorIs(t, tt.err, ErrCertificateGeneration)\n\t\t})\n\t}\n}\n\nfunc TestErrorWrapping(t *testing.T) {\n\tbaseErr := errors.New(\"base error\")\n\n\ttests := []struct {\n\t\tname    string\n\t\terr     error\n\t\ttarget  error\n\t\twrapped error\n\t}{\n\t\t{\n\t\t\tname: \"endpoint error wraps correctly\",\n\t\t\terr: &EndpointError{\n\t\t\t\tEndpoint: \"test\",\n\t\t\t\tErr:      baseErr,\n\t\t\t},\n\t\t\ttarget:  baseErr,\n\t\t\twrapped: baseErr,\n\t\t},\n\t\t{\n\t\t\tname: \"security error wraps correctly\",\n\t\t\terr: &SecurityError{\n\t\t\t\tPolicy: \"test\",\n\t\t\t\tErr:    baseErr,\n\t\t\t},\n\t\t\ttarget:  baseErr,\n\t\t\twrapped: baseErr,\n\t\t},\n\t\t{\n\t\t\tname: \"authentication error wraps correctly\",\n\t\t\terr: &AuthenticationError{\n\t\t\t\tMethod: \"test\",\n\t\t\t\tErr:    baseErr,\n\t\t\t},\n\t\t\ttarget:  baseErr,\n\t\t\twrapped: baseErr,\n\t\t},\n\t\t{\n\t\t\tname: \"certificate error wraps correctly\",\n\t\t\terr: &CertificateError{\n\t\t\t\tOperation: \"test\",\n\t\t\t\tErr:       baseErr,\n\t\t\t},\n\t\t\ttarget:  baseErr,\n\t\t\twrapped: baseErr,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.ErrorIs(t, tt.err, tt.target)\n\t\t\trequire.Equal(t, tt.wrapped, errors.Unwrap(tt.err))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/opcua/input/input_client.go",
    "content": "package input\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua/id\"\n\t\"github.com/gopcua/opcua/ua\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n)\n\ntype Trigger string\n\nconst (\n\tStatus               Trigger = \"Status\"\n\tStatusValue          Trigger = \"StatusValue\"\n\tStatusValueTimestamp Trigger = \"StatusValueTimestamp\"\n)\n\ntype DeadbandType string\n\nconst (\n\tNone     DeadbandType = \"None\"\n\tAbsolute DeadbandType = \"Absolute\"\n\tPercent  DeadbandType = \"Percent\"\n)\n\ntype DataChangeFilter struct {\n\tTrigger       Trigger      `toml:\"trigger\"`\n\tDeadbandType  DeadbandType `toml:\"deadband_type\"`\n\tDeadbandValue *float64     `toml:\"deadband_value\"`\n}\n\ntype MonitoringParameters struct {\n\tSamplingInterval config.Duration   `toml:\"sampling_interval\"`\n\tQueueSize        *uint32           `toml:\"queue_size\"`\n\tDiscardOldest    *bool             `toml:\"discard_oldest\"`\n\tDataChangeFilter *DataChangeFilter `toml:\"data_change_filter\"`\n}\n\n// NodeSettings describes how to map from a OPC UA node to a Metric\ntype NodeSettings struct {\n\tFieldName        string               `toml:\"name\"`\n\tNodeIDStr        string               `toml:\"id\"`\n\tNamespace        string               `toml:\"namespace\"`\n\tNamespaceURI     string               `toml:\"namespace_uri\"`\n\tIdentifierType   string               `toml:\"identifier_type\"`\n\tIdentifier       string               `toml:\"identifier\"`\n\tDefaultTags      map[string]string    `toml:\"default_tags\"`\n\tMonitoringParams MonitoringParameters `toml:\"monitoring_params\"`\n}\n\n// NodeID returns the OPC UA node id\nfunc (tag *NodeSettings) NodeID() string {\n\tif tag.NodeIDStr != \"\" {\n\t\treturn tag.NodeIDStr\n\t}\n\tif tag.NamespaceURI != \"\" {\n\t\treturn \"nsu=\" + tag.NamespaceURI + \";\" + tag.IdentifierType + \"=\" + tag.Identifier\n\t}\n\treturn \"ns=\" + tag.Namespace + \";\" + tag.IdentifierType + \"=\" + tag.Identifier\n}\n\n// NodeGroupSettings describes a mapping of group of nodes to Metrics\ntype NodeGroupSettings struct {\n\tMetricName       string            `toml:\"name\"`            // Overrides plugin's setting\n\tNamespace        string            `toml:\"namespace\"`       // Can be overridden by node setting\n\tNamespaceURI     string            `toml:\"namespace_uri\"`   // Can be overridden by node setting\n\tIdentifierType   string            `toml:\"identifier_type\"` // Can be overridden by node setting\n\tNodes            []NodeSettings    `toml:\"nodes\"`\n\tDefaultTags      map[string]string `toml:\"default_tags\"`\n\tSamplingInterval config.Duration   `toml:\"sampling_interval\"` // Can be overridden by monitoring parameters\n}\n\ntype EventNodeSettings struct {\n\tNodeIDStr      string `toml:\"id\"`\n\tNamespace      string `toml:\"namespace\"`\n\tNamespaceURI   string `toml:\"namespace_uri\"`\n\tIdentifierType string `toml:\"identifier_type\"`\n\tIdentifier     string `toml:\"identifier\"`\n}\n\nfunc (e *EventNodeSettings) NodeID() string {\n\tif e.NodeIDStr != \"\" {\n\t\treturn e.NodeIDStr\n\t}\n\tif e.NamespaceURI != \"\" {\n\t\treturn \"nsu=\" + e.NamespaceURI + \";\" + e.IdentifierType + \"=\" + e.Identifier\n\t}\n\treturn \"ns=\" + e.Namespace + \";\" + e.IdentifierType + \"=\" + e.Identifier\n}\n\ntype EventGroupSettings struct {\n\tSamplingInterval config.Duration     `toml:\"sampling_interval\"`\n\tQueueSize        uint32              `toml:\"queue_size\"`\n\tEventTypeNode    EventNodeSettings   `toml:\"event_type_node\"`\n\tNamespace        string              `toml:\"namespace\"`\n\tNamespaceURI     string              `toml:\"namespace_uri\"`\n\tIdentifierType   string              `toml:\"identifier_type\"`\n\tNodeIDSettings   []EventNodeSettings `toml:\"node_ids\"`\n\tSourceNames      []string            `toml:\"source_names\"`\n\tFields           []string            `toml:\"fields\"`\n}\n\nfunc (e *EventGroupSettings) UpdateNodeIDSettings() {\n\tfor i := range e.NodeIDSettings {\n\t\tn := &e.NodeIDSettings[i]\n\n\t\t// Skip group defaults when node ID string is specified directly\n\t\tif n.NodeIDStr != \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Apply group defaults only if not already set\n\t\tif n.Namespace == \"\" {\n\t\t\tn.Namespace = e.Namespace\n\t\t}\n\t\tif n.NamespaceURI == \"\" {\n\t\t\tn.NamespaceURI = e.NamespaceURI\n\t\t}\n\t\tif n.IdentifierType == \"\" {\n\t\t\tn.IdentifierType = e.IdentifierType\n\t\t}\n\t}\n}\n\nfunc (e *EventGroupSettings) Validate() error {\n\tif err := e.EventTypeNode.validateEventNodeSettings(); err != nil {\n\t\treturn fmt.Errorf(\"invalid event_type_node_settings: %w\", err)\n\t}\n\n\tif len(e.NodeIDSettings) == 0 {\n\t\treturn errors.New(\"at least one node_id must be specified\")\n\t}\n\n\tfor _, node := range e.NodeIDSettings {\n\t\tif err := node.validateEventNodeSettings(); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid node_id_settings: %w\", err)\n\t\t}\n\t}\n\n\tif len(e.Fields) == 0 {\n\t\treturn errors.New(\"at least one Field must be specified\")\n\t}\n\tfor _, field := range e.Fields {\n\t\tif field == \"\" {\n\t\t\treturn errors.New(\"empty field name in fields stanza\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e EventNodeSettings) validateEventNodeSettings() error {\n\tvar defaultNodeSettings EventNodeSettings\n\tif e == defaultNodeSettings {\n\t\treturn errors.New(\"node settings can't be empty\")\n\t}\n\n\tif e.NodeIDStr != \"\" {\n\t\tif e.Namespace != \"\" || e.NamespaceURI != \"\" || e.IdentifierType != \"\" || e.Identifier != \"\" {\n\t\t\treturn errors.New(\"cannot specify both 'id' and individual fields (namespace/namespace_uri/identifier_type/identifier)\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tif e.Identifier == \"\" {\n\t\treturn errors.New(\"identifier must be set\")\n\t}\n\tif e.IdentifierType == \"\" {\n\t\treturn errors.New(\"identifier_type must be set\")\n\t}\n\n\t// Validate namespace configuration\n\thasNamespace := len(e.Namespace) > 0\n\thasNamespaceURI := len(e.NamespaceURI) > 0\n\n\tif hasNamespace && hasNamespaceURI {\n\t\treturn errors.New(\"cannot specify both 'namespace' and 'namespace_uri', use only one\")\n\t}\n\n\tif !hasNamespace && !hasNamespaceURI {\n\t\treturn errors.New(\"must specify either 'namespace' or 'namespace_uri'\")\n\t}\n\n\treturn nil\n}\n\ntype TimestampSource string\n\nconst (\n\tTimestampSourceServer   TimestampSource = \"server\"\n\tTimestampSourceSource   TimestampSource = \"source\"\n\tTimestampSourceTelegraf TimestampSource = \"gather\"\n)\n\n// InputClientConfig a configuration for the input client\ntype InputClientConfig struct {\n\topcua.OpcUAClientConfig\n\tMetricName      string               `toml:\"name\"`\n\tTimestamp       TimestampSource      `toml:\"timestamp\"`\n\tTimestampFormat string               `toml:\"timestamp_format\"`\n\tRootNodes       []NodeSettings       `toml:\"nodes\"`\n\tGroups          []NodeGroupSettings  `toml:\"group\"`\n\tEventGroups     []EventGroupSettings `toml:\"events\"`\n}\n\nfunc (o *InputClientConfig) Validate() error {\n\tif o.MetricName == \"\" {\n\t\treturn errors.New(\"metric name is empty\")\n\t}\n\n\tswitch string(o.Timestamp) {\n\tcase \"\", \"gather\", \"server\", \"source\":\n\t\t// Valid timestamp source\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown timestamp source %q, expected one of: [\\\"\\\", \\\"gather\\\", \\\"server\\\", \\\"source\\\"]\", o.Timestamp)\n\t}\n\n\tif o.TimestampFormat == \"\" {\n\t\to.TimestampFormat = time.RFC3339Nano\n\t}\n\n\tif len(o.Groups) == 0 && len(o.RootNodes) == 0 && o.EventGroups == nil {\n\t\treturn errors.New(\"no groups, root nodes or events provided to gather from\")\n\t}\n\tfor _, group := range o.Groups {\n\t\tif len(group.Nodes) == 0 {\n\t\t\treturn errors.New(\"group has no nodes to collect from\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *InputClientConfig) CreateInputClient(log telegraf.Logger) (*OpcUAInputClient, error) {\n\tif err := o.Validate(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif o.EventGroups != nil {\n\t\tfor i := range o.EventGroups {\n\t\t\to.EventGroups[i].UpdateNodeIDSettings()\n\t\t\tif err := o.EventGroups[i].Validate(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid event_settings: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tlog.Debug(\"Initialising OpcUAInputClient\")\n\topcClient, err := o.OpcUAClientConfig.CreateClient(log)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := &OpcUAInputClient{\n\t\tOpcUAClient: opcClient,\n\t\tLog:         log,\n\t\tConfig:      *o,\n\t\tEventGroups: o.EventGroups,\n\t}\n\n\tlog.Debug(\"Initialising node to metric mapping\")\n\tif err := c.InitNodeMetricMapping(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.initLastReceivedValues()\n\n\treturn c, nil\n}\n\n// NodeMetricMapping mapping from a single node to a metric\ntype NodeMetricMapping struct {\n\tTag        NodeSettings\n\tidStr      string\n\tmetricName string\n\tMetricTags map[string]string\n}\n\n// NewNodeMetricMapping builds a new NodeMetricMapping from the given argument\nfunc NewNodeMetricMapping(metricName string, node NodeSettings, groupTags map[string]string) (*NodeMetricMapping, error) {\n\tmergedTags := make(map[string]string)\n\tmaps.Copy(mergedTags, groupTags)\n\tmaps.Copy(mergedTags, node.DefaultTags)\n\n\treturn &NodeMetricMapping{\n\t\tTag:        node,\n\t\tidStr:      node.NodeID(),\n\t\tmetricName: metricName,\n\t\tMetricTags: mergedTags,\n\t}, nil\n}\n\ntype EventNodeMetricMapping struct {\n\tNodeID           *ua.NodeID\n\tSamplingInterval *config.Duration\n\tQueueSize        *uint32\n\tEventTypeNode    *ua.NodeID\n\tSourceNames      []string\n\tFields           []string\n}\n\n// NodeValue The received value for a node\ntype NodeValue struct {\n\tTagName    string\n\tValue      interface{}\n\tQuality    ua.StatusCode\n\tServerTime time.Time\n\tSourceTime time.Time\n\tDataType   ua.TypeID\n\tIsArray    bool\n}\n\n// OpcUAInputClient can receive data from an OPC UA server and map it to Metrics. This type does not contain\n// logic for actually retrieving data from the server, but is used by other types like ReadClient and\n// OpcUAInputSubscribeClient to store data needed to convert node ids to the corresponding metrics.\ntype OpcUAInputClient struct {\n\t*opcua.OpcUAClient\n\tConfig InputClientConfig\n\tLog    telegraf.Logger\n\n\tNodeMetricMapping      []NodeMetricMapping\n\tNodeIDs                []*ua.NodeID\n\tLastReceivedData       []NodeValue\n\tEventGroups            []EventGroupSettings\n\tEventNodeMetricMapping []EventNodeMetricMapping\n}\n\n// Stop the connection to the client\nfunc (o *OpcUAInputClient) Stop(ctx context.Context) <-chan struct{} {\n\tch := make(chan struct{})\n\tdefer close(ch)\n\terr := o.Disconnect(ctx)\n\tif err != nil {\n\t\to.Log.Warn(\"Disconnecting from server failed with error \", err)\n\t}\n\n\treturn ch\n}\n\n// metricParts is only used to ensure no duplicate metrics are created\ntype metricParts struct {\n\tmetricName string\n\tfieldName  string\n\ttags       string // sorted by tag name and in format tag1=value1, tag2=value2\n}\n\nfunc newMP(n *NodeMetricMapping) metricParts {\n\t// Include the node ID as the \"id\" tag since MetricForNode always adds it\n\ttags := map[string]string{\"id\": n.idStr}\n\tfor k, v := range n.MetricTags {\n\t\ttags[k] = v\n\t}\n\tkeys := make([]string, 0, len(tags))\n\tfor key := range tags {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\tvar sb strings.Builder\n\tfor i, key := range keys {\n\t\tif i != 0 {\n\t\t\tsb.WriteString(\", \")\n\t\t}\n\t\tsb.WriteString(key)\n\t\tsb.WriteString(\"=\")\n\t\tsb.WriteString(tags[key])\n\t}\n\treturn metricParts{\n\t\tmetricName: n.metricName,\n\t\tfieldName:  n.Tag.FieldName,\n\t\ttags:       sb.String(),\n\t}\n}\n\nfunc validateNodeToAdd(existing map[metricParts]struct{}, nmm *NodeMetricMapping) error {\n\tif nmm.Tag.FieldName == \"\" {\n\t\treturn fmt.Errorf(\"empty name in %q\", nmm.Tag.FieldName)\n\t}\n\n\tif nmm.Tag.NodeIDStr != \"\" {\n\t\tif nmm.Tag.Namespace != \"\" || nmm.Tag.NamespaceURI != \"\" || nmm.Tag.IdentifierType != \"\" || nmm.Tag.Identifier != \"\" {\n\t\t\treturn fmt.Errorf(\"node %q: cannot specify both 'id' and individual fields (namespace/namespace_uri/identifier_type/identifier)\", nmm.Tag.FieldName)\n\t\t}\n\t} else {\n\t\t// Validate namespace configuration\n\t\thasNamespace := len(nmm.Tag.Namespace) > 0\n\t\thasNamespaceURI := len(nmm.Tag.NamespaceURI) > 0\n\n\t\tif hasNamespace && hasNamespaceURI {\n\t\t\treturn fmt.Errorf(\"node %q: cannot specify both 'namespace' and 'namespace_uri', use only one\", nmm.Tag.FieldName)\n\t\t}\n\n\t\tif !hasNamespace && !hasNamespaceURI {\n\t\t\treturn fmt.Errorf(\"node %q: must specify either 'namespace' or 'namespace_uri'\", nmm.Tag.FieldName)\n\t\t}\n\n\t\tif len(nmm.Tag.Identifier) == 0 {\n\t\t\treturn errors.New(\"empty node identifier not allowed\")\n\t\t}\n\n\t\tswitch nmm.Tag.IdentifierType {\n\t\tcase \"i\":\n\t\t\tif _, err := strconv.Atoi(nmm.Tag.Identifier); err != nil {\n\t\t\t\treturn fmt.Errorf(\"identifier type %q does not match the type of identifier %q\", nmm.Tag.IdentifierType, nmm.Tag.Identifier)\n\t\t\t}\n\t\tcase \"s\", \"g\", \"b\":\n\t\t\t// Valid identifier type - do nothing.\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid identifier type %q in %q\", nmm.Tag.IdentifierType, nmm.Tag.FieldName)\n\t\t}\n\t}\n\n\tfor k, v := range nmm.MetricTags {\n\t\tif k == \"\" {\n\t\t\treturn fmt.Errorf(\"empty tag name in tags for %q\", nmm.Tag.FieldName)\n\t\t}\n\t\tif v == \"\" {\n\t\t\treturn fmt.Errorf(\"empty tag value for tag %q in %q\", k, nmm.Tag.FieldName)\n\t\t}\n\t}\n\n\tmp := newMP(nmm)\n\tif _, exists := existing[mp]; exists {\n\t\treturn fmt.Errorf(\"name %q is duplicated (metric name %q, tags %q)\",\n\t\t\tmp.fieldName, mp.metricName, mp.tags)\n\t}\n\n\texisting[mp] = struct{}{}\n\treturn nil\n}\n\n// InitNodeMetricMapping builds nodes from the configuration\nfunc (o *OpcUAInputClient) InitNodeMetricMapping() error {\n\texisting := make(map[metricParts]struct{}, len(o.Config.RootNodes))\n\tfor _, node := range o.Config.RootNodes {\n\t\tnmm, err := NewNodeMetricMapping(o.Config.MetricName, node, make(map[string]string))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := validateNodeToAdd(existing, nmm); err != nil {\n\t\t\treturn err\n\t\t}\n\t\to.NodeMetricMapping = append(o.NodeMetricMapping, *nmm)\n\t}\n\n\tfor gi := range o.Config.Groups {\n\t\tgroup := &o.Config.Groups[gi]\n\t\tif group.MetricName == \"\" {\n\t\t\tgroup.MetricName = o.Config.MetricName\n\t\t}\n\n\t\tfor _, node := range group.Nodes {\n\t\t\t// Skip group defaults when node ID string is specified directly\n\t\t\tif node.NodeIDStr == \"\" {\n\t\t\t\tif node.Namespace == \"\" {\n\t\t\t\t\tnode.Namespace = group.Namespace\n\t\t\t\t}\n\t\t\t\tif node.NamespaceURI == \"\" {\n\t\t\t\t\tnode.NamespaceURI = group.NamespaceURI\n\t\t\t\t}\n\t\t\t\tif node.IdentifierType == \"\" {\n\t\t\t\t\tnode.IdentifierType = group.IdentifierType\n\t\t\t\t}\n\t\t\t}\n\t\t\tif node.MonitoringParams.SamplingInterval == 0 {\n\t\t\t\tnode.MonitoringParams.SamplingInterval = group.SamplingInterval\n\t\t\t}\n\n\t\t\tnmm, err := NewNodeMetricMapping(group.MetricName, node, group.DefaultTags)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := validateNodeToAdd(existing, nmm); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\to.NodeMetricMapping = append(o.NodeMetricMapping, *nmm)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAInputClient) InitNodeIDs() error {\n\t// Get all namespace definitions of the remote device for handling\n\t// namespace URLs (the ones starting with \"nsu=\") gracefully\n\tnamespaces := o.NamespaceArray()\n\n\to.NodeIDs = make([]*ua.NodeID, 0, len(o.NodeMetricMapping))\n\tfor _, node := range o.NodeMetricMapping {\n\t\t// Determine the actual node-ID instance using the expanded form as\n\t\t// this handles namespace URLs (nsu=) gracefully\n\t\tnodeID := node.Tag.NodeID()\n\t\texpanded, err := ua.ParseExpandedNodeID(nodeID, namespaces)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse node ID %q: %w\", nodeID, err)\n\t\t}\n\t\to.NodeIDs = append(o.NodeIDs, ua.NewNodeIDFromExpandedNodeID(expanded))\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAInputClient) InitEventNodeIDs() error {\n\t// Get all namespace definitions of the remote device for handling\n\t// namespace URLs (the ones starting with \"nsu=\") gracefully\n\tnamespaces := o.NamespaceArray()\n\n\tfor _, eventSetting := range o.EventGroups {\n\t\t// Parse event type node ID\n\t\teventNodeID := eventSetting.EventTypeNode.NodeID()\n\t\texpanded, err := ua.ParseExpandedNodeID(eventNodeID, namespaces)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse event type node ID %q: %w\", eventNodeID, err)\n\t\t}\n\t\teid := ua.NewNodeIDFromExpandedNodeID(expanded)\n\n\t\tfor _, node := range eventSetting.NodeIDSettings {\n\t\t\tnodeID := node.NodeID()\n\t\t\texpanded, err := ua.ParseExpandedNodeID(nodeID, namespaces)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse node ID %q: %w\", nodeID, err)\n\t\t\t}\n\n\t\t\tnmm := EventNodeMetricMapping{\n\t\t\t\tNodeID:           ua.NewNodeIDFromExpandedNodeID(expanded),\n\t\t\t\tSamplingInterval: &eventSetting.SamplingInterval,\n\t\t\t\tQueueSize:        &eventSetting.QueueSize,\n\t\t\t\tEventTypeNode:    eid,\n\t\t\t\tSourceNames:      eventSetting.SourceNames,\n\t\t\t\tFields:           eventSetting.Fields,\n\t\t\t}\n\t\t\to.EventNodeMetricMapping = append(o.EventNodeMetricMapping, nmm)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpcUAInputClient) initLastReceivedValues() {\n\to.LastReceivedData = make([]NodeValue, len(o.NodeMetricMapping))\n\tfor nodeIdx, nmm := range o.NodeMetricMapping {\n\t\to.LastReceivedData[nodeIdx].TagName = nmm.Tag.FieldName\n\t}\n}\n\nfunc (o *OpcUAInputClient) UpdateNodeValue(nodeIdx int, d *ua.DataValue) {\n\to.LastReceivedData[nodeIdx].Quality = d.Status\n\tif !o.StatusCodeOK(d.Status) {\n\t\t// Verify NodeIDs array has been built before trying to get item; otherwise show '?' for node id\n\t\tif len(o.NodeIDs) > nodeIdx {\n\t\t\to.Log.Errorf(\"status not OK for node %v (%v): %v\", o.NodeMetricMapping[nodeIdx].Tag.FieldName, o.NodeIDs[nodeIdx].String(), d.Status)\n\t\t} else {\n\t\t\to.Log.Errorf(\"status not OK for node %v (%v): %v\", o.NodeMetricMapping[nodeIdx].Tag.FieldName, '?', d.Status)\n\t\t}\n\n\t\treturn\n\t}\n\n\tif d.Value != nil {\n\t\to.LastReceivedData[nodeIdx].DataType = d.Value.Type()\n\t\to.LastReceivedData[nodeIdx].IsArray = d.Value.Has(ua.VariantArrayValues)\n\n\t\to.LastReceivedData[nodeIdx].Value = d.Value.Value()\n\t\tif o.LastReceivedData[nodeIdx].DataType == ua.TypeIDDateTime {\n\t\t\tif t, ok := d.Value.Value().(time.Time); ok {\n\t\t\t\to.LastReceivedData[nodeIdx].Value = t.Format(o.Config.TimestampFormat)\n\t\t\t}\n\t\t}\n\t}\n\to.LastReceivedData[nodeIdx].ServerTime = d.ServerTimestamp\n\to.LastReceivedData[nodeIdx].SourceTime = d.SourceTimestamp\n}\n\nfunc (o *OpcUAInputClient) MetricForNode(nodeIdx int) telegraf.Metric {\n\tnmm := &o.NodeMetricMapping[nodeIdx]\n\ttags := map[string]string{\n\t\t\"id\": nmm.idStr,\n\t}\n\tfor k, v := range nmm.MetricTags {\n\t\ttags[k] = v\n\t}\n\n\tfields := make(map[string]interface{})\n\tif o.LastReceivedData[nodeIdx].Value != nil {\n\t\t// Simple scalar types can be stored directly under the field name while\n\t\t// arrays (see 5.2.5) and structures (see 5.2.6) must be unpacked.\n\t\t// Note: Structures and arrays of structures are currently not supported.\n\t\tif o.LastReceivedData[nodeIdx].IsArray {\n\t\t\tswitch typedValue := o.LastReceivedData[nodeIdx].Value.(type) {\n\t\t\tcase []uint8:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []uint16:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []uint32:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []uint64:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []int8:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []int16:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []int32:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []int64:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []float32:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []float64:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []string:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []bool:\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, typedValue)\n\t\t\tcase []time.Time:\n\t\t\t\tstrs := make([]string, len(typedValue))\n\t\t\t\tfor i, t := range typedValue {\n\t\t\t\t\tstrs[i] = t.Format(o.Config.TimestampFormat)\n\t\t\t\t}\n\t\t\t\tfields = unpack(nmm.Tag.FieldName, strs)\n\t\t\tdefault:\n\t\t\t\to.Log.Errorf(\"could not unpack variant array of type: %T\", typedValue)\n\t\t\t}\n\t\t} else {\n\t\t\tfields = map[string]interface{}{\n\t\t\t\tnmm.Tag.FieldName: o.LastReceivedData[nodeIdx].Value,\n\t\t\t}\n\t\t}\n\t}\n\n\tfields[\"Quality\"] = strings.TrimSpace(o.LastReceivedData[nodeIdx].Quality.Error())\n\tfor _, field := range o.Config.OptionalFields {\n\t\tif field == \"DataType\" {\n\t\t\tfields[\"DataType\"] = strings.Replace(o.LastReceivedData[nodeIdx].DataType.String(), \"TypeID\", \"\", 1)\n\t\t\tbreak\n\t\t}\n\t}\n\tif !o.StatusCodeOK(o.LastReceivedData[nodeIdx].Quality) {\n\t\tmp := newMP(nmm)\n\t\to.Log.Debugf(\"status not OK for node %q(metric name %q, tags %q)\",\n\t\t\tmp.fieldName, mp.metricName, mp.tags)\n\t}\n\n\tvar t time.Time\n\tswitch o.Config.Timestamp {\n\tcase TimestampSourceServer:\n\t\tt = o.LastReceivedData[nodeIdx].ServerTime\n\tcase TimestampSourceSource:\n\t\tt = o.LastReceivedData[nodeIdx].SourceTime\n\tdefault:\n\t\tt = time.Now()\n\t}\n\n\treturn metric.New(nmm.metricName, tags, fields, t)\n}\n\nfunc unpack[Slice ~[]E, E any](prefix string, value Slice) map[string]interface{} {\n\tfields := make(map[string]interface{}, len(value))\n\tfor i, v := range value {\n\t\tkey := fmt.Sprintf(\"%s[%d]\", prefix, i)\n\t\tfields[key] = v\n\t}\n\treturn fields\n}\n\nfunc (o *OpcUAInputClient) MetricForEvent(nodeIdx int, event *ua.EventFieldList) telegraf.Metric {\n\tnode := o.EventNodeMetricMapping[nodeIdx]\n\tfields := make(map[string]interface{}, len(event.EventFields))\n\tvar sourceTime, serverTime time.Time\n\tfor i, field := range event.EventFields {\n\t\tname := node.Fields[i]\n\t\tvalue := field.Value()\n\n\t\tif value == nil {\n\t\t\to.Log.Warnf(\"Field %s has no value\", name)\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch v := value.(type) {\n\t\tcase *ua.LocalizedText:\n\t\t\tfields[name] = v.Text\n\t\tcase time.Time:\n\t\t\tif name == \"Time\" {\n\t\t\t\tsourceTime = v\n\t\t\t} else if name == \"ReceiveTime\" {\n\t\t\t\tserverTime = v\n\t\t\t}\n\t\t\tfields[name] = v.Format(time.RFC3339)\n\t\tdefault:\n\t\t\tfields[name] = v\n\t\t}\n\t}\n\n\tif len(fields) == 0 {\n\t\to.Log.Warn(\"Event has no fields with values, skipping\")\n\t\treturn nil\n\t}\n\n\ttags := map[string]string{\n\t\t\"node_id\": node.NodeID.String(),\n\t\t\"source\":  o.Config.Endpoint,\n\t}\n\tvar t time.Time\n\tswitch o.Config.Timestamp {\n\tcase TimestampSourceServer:\n\t\tt = serverTime\n\tcase TimestampSourceSource:\n\t\tt = sourceTime\n\t}\n\tif t.IsZero() {\n\t\tt = time.Now()\n\t}\n\n\treturn metric.New(\"opcua_event\", tags, fields, t)\n}\n\n// CreateEventFilter creates a new event filter for event streaming\nfunc (node *EventNodeMetricMapping) CreateEventFilter() (*ua.ExtensionObject, error) {\n\tselects, err := node.createSelectClauses()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twheres, err := node.createWhereClauses()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ua.ExtensionObject{\n\t\tEncodingMask: ua.ExtensionObjectBinary,\n\t\tTypeID:       &ua.ExpandedNodeID{NodeID: ua.NewNumericNodeID(0, id.EventFilter_Encoding_DefaultBinary)},\n\t\tValue: ua.EventFilter{\n\t\t\tSelectClauses: selects,\n\t\t\tWhereClause:   wheres,\n\t\t},\n\t}, nil\n}\n\nfunc (node *EventNodeMetricMapping) createSelectClauses() ([]*ua.SimpleAttributeOperand, error) {\n\tselects := make([]*ua.SimpleAttributeOperand, len(node.Fields))\n\ttypeDefinition, err := node.determineNodeIDType()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor i, name := range node.Fields {\n\t\tselects[i] = &ua.SimpleAttributeOperand{\n\t\t\tTypeDefinitionID: typeDefinition,\n\t\t\tBrowsePath:       []*ua.QualifiedName{{NamespaceIndex: 0, Name: name}},\n\t\t\tAttributeID:      ua.AttributeIDValue,\n\t\t}\n\t}\n\treturn selects, nil\n}\n\nfunc (node *EventNodeMetricMapping) createWhereClauses() (*ua.ContentFilter, error) {\n\tif len(node.SourceNames) == 0 {\n\t\treturn &ua.ContentFilter{\n\t\t\tElements: make([]*ua.ContentFilterElement, 0),\n\t\t}, nil\n\t}\n\toperands := make([]*ua.ExtensionObject, 0, len(node.SourceNames))\n\tfor _, sourceName := range node.SourceNames {\n\t\tliteralOperand := &ua.ExtensionObject{\n\t\t\tEncodingMask: 1,\n\t\t\tTypeID: &ua.ExpandedNodeID{\n\t\t\t\tNodeID: ua.NewNumericNodeID(0, id.LiteralOperand_Encoding_DefaultBinary),\n\t\t\t},\n\t\t\tValue: ua.LiteralOperand{\n\t\t\t\tValue: ua.MustVariant(sourceName),\n\t\t\t},\n\t\t}\n\t\toperands = append(operands, literalOperand)\n\t}\n\n\ttypeDefinition, err := node.determineNodeIDType()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tattributeOperand := &ua.ExtensionObject{\n\t\tEncodingMask: ua.ExtensionObjectBinary,\n\t\tTypeID: &ua.ExpandedNodeID{\n\t\t\tNodeID: ua.NewNumericNodeID(0, id.SimpleAttributeOperand_Encoding_DefaultBinary),\n\t\t},\n\t\tValue: &ua.SimpleAttributeOperand{\n\t\t\tTypeDefinitionID: typeDefinition,\n\t\t\tBrowsePath: []*ua.QualifiedName{\n\t\t\t\t{NamespaceIndex: 0, Name: \"SourceName\"},\n\t\t\t},\n\t\t\tAttributeID: ua.AttributeIDValue,\n\t\t},\n\t}\n\n\tfilterElement := &ua.ContentFilterElement{\n\t\tFilterOperator: ua.FilterOperatorInList,\n\t\tFilterOperands: append([]*ua.ExtensionObject{attributeOperand}, operands...),\n\t}\n\n\twheres := &ua.ContentFilter{\n\t\tElements: []*ua.ContentFilterElement{filterElement},\n\t}\n\n\treturn wheres, nil\n}\n\nfunc (node *EventNodeMetricMapping) determineNodeIDType() (*ua.NodeID, error) {\n\tswitch node.EventTypeNode.Type() {\n\tcase ua.NodeIDTypeGUID:\n\t\treturn ua.NewGUIDNodeID(node.EventTypeNode.Namespace(), node.EventTypeNode.StringID()), nil\n\tcase ua.NodeIDTypeString:\n\t\treturn ua.NewStringNodeID(node.EventTypeNode.Namespace(), node.EventTypeNode.StringID()), nil\n\tcase ua.NodeIDTypeByteString:\n\t\treturn ua.NewByteStringNodeID(node.EventTypeNode.Namespace(), []byte(node.EventTypeNode.StringID())), nil\n\tcase ua.NodeIDTypeTwoByte:\n\t\tnodeID := node.EventTypeNode.IntID()\n\t\tif nodeID > 255 {\n\t\t\treturn nil, fmt.Errorf(\"twoByte EventType requires a value in the range 0-255, got %d\", nodeID)\n\t\t}\n\t\treturn ua.NewTwoByteNodeID(uint8(node.EventTypeNode.IntID())), nil\n\tcase ua.NodeIDTypeFourByte:\n\t\treturn ua.NewFourByteNodeID(uint8(node.EventTypeNode.Namespace()), uint16(node.EventTypeNode.IntID())), nil\n\tcase ua.NodeIDTypeNumeric:\n\t\treturn ua.NewNumericNodeID(node.EventTypeNode.Namespace(), node.EventTypeNode.IntID()), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported NodeID type: %v\", node.EventTypeNode.String())\n\t}\n}\n"
  },
  {
    "path": "plugins/common/opcua/input/input_client_test.go",
    "content": "package input\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua/ua\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestValidateOPCTags(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tconfig InputClientConfig\n\t\terr    error\n\t}{\n\t\t{\n\t\t\t\"duplicates\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tGroups: []NodeGroupSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDefaultTags: map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrors.New(`name \"fn\" is duplicated (metric name \"mn\", tags \"id=ns=2;s=i1, t1=v1, t2=v2\")`),\n\t\t},\n\t\t{\n\t\t\t\"empty tag value not allowed\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrors.New(`empty tag value for tag \"t1\" in \"fn\"`),\n\t\t},\n\t\t{\n\t\t\t\"empty tag name not allowed\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"\": \"1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrors.New(`empty tag name in tags for \"fn\"`),\n\t\t},\n\t\t{\n\t\t\t\"different metric tag names\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t3\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"different metric tag values\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"foo\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"bar\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"different metric names\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tGroups: []NodeGroupSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tMetricName: \"mn\",\n\t\t\t\t\t\tNamespace:  \"2\",\n\t\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tMetricName: \"mn2\",\n\t\t\t\t\t\tNamespace:  \"2\",\n\t\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"different field names\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"mn\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"fn2\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"i1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"same field name different node IDs\",\n\t\t\tInputClientConfig{\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"breaker_amps\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"AmpA/Value\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"breaker_amps\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"AmpB/Value\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"breaker_amps\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"AmpC/Value\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\to := OpcUAInputClient{\n\t\t\t\tConfig: tt.config,\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t}\n\t\t\trequire.Equal(t, tt.err, o.InitNodeMetricMapping())\n\t\t})\n\t}\n}\n\nfunc TestNewNodeMetricMappingTags(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tsettings     NodeSettings\n\t\tgroupTags    map[string]string\n\t\texpectedTags map[string]string\n\t\terr          error\n\t}{\n\t\t{\n\t\t\tname: \"empty tags\",\n\t\t\tsettings: NodeSettings{\n\t\t\t\tFieldName:      \"f\",\n\t\t\t\tNamespace:      \"2\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"h\",\n\t\t\t},\n\t\t\tgroupTags:    map[string]string{},\n\t\t\texpectedTags: map[string]string{},\n\t\t\terr:          nil,\n\t\t},\n\t\t{\n\t\t\tname: \"node tags only\",\n\t\t\tsettings: NodeSettings{\n\t\t\t\tFieldName:      \"f\",\n\t\t\t\tNamespace:      \"2\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"h\",\n\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\t},\n\t\t\tgroupTags:    map[string]string{},\n\t\t\texpectedTags: map[string]string{\"t1\": \"v1\"},\n\t\t\terr:          nil,\n\t\t},\n\t\t{\n\t\t\tname: \"group tags only\",\n\t\t\tsettings: NodeSettings{\n\t\t\t\tFieldName:      \"f\",\n\t\t\t\tNamespace:      \"2\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"h\",\n\t\t\t},\n\t\t\tgroupTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\texpectedTags: map[string]string{\"t1\": \"v1\"},\n\t\t\terr:          nil,\n\t\t},\n\t\t{\n\t\t\tname: \"node tag overrides group tags\",\n\t\t\tsettings: NodeSettings{\n\t\t\t\tFieldName:      \"f\",\n\t\t\t\tNamespace:      \"2\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"h\",\n\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v2\"},\n\t\t\t},\n\t\t\tgroupTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\texpectedTags: map[string]string{\"t1\": \"v2\"},\n\t\t\terr:          nil,\n\t\t},\n\t\t{\n\t\t\tname: \"node tag merged with group tags\",\n\t\t\tsettings: NodeSettings{\n\t\t\t\tFieldName:      \"f\",\n\t\t\t\tNamespace:      \"2\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"h\",\n\t\t\t\tDefaultTags:    map[string]string{\"t2\": \"v2\"},\n\t\t\t},\n\t\t\tgroupTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\texpectedTags: map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\terr:          nil,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", tt.settings, tt.groupTags)\n\t\t\trequire.Equal(t, tt.err, err)\n\t\t\trequire.Equal(t, tt.expectedTags, nmm.MetricTags)\n\t\t})\n\t}\n}\n\nfunc TestNewNodeMetricMappingIdStrInstantiated(t *testing.T) {\n\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\tFieldName:      \"f\",\n\t\tNamespace:      \"2\",\n\t\tIdentifierType: \"s\",\n\t\tIdentifier:     \"h\",\n\t}, map[string]string{})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"ns=2;s=h\", nmm.idStr)\n}\n\nfunc TestValidateNodeToAdd(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\texisting map[metricParts]struct{}\n\t\tnmm      *NodeMetricMapping\n\t\terr      error\n\t}{\n\t\t{\n\t\t\tname:     \"valid\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: nil,\n\t\t},\n\t\t{\n\t\t\tname:     \"empty field name not allowed\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(`empty name in \"\"`),\n\t\t},\n\t\t{\n\t\t\tname:     \"empty namespace not allowed\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"\",\n\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(\"node \\\"f\\\": must specify either 'namespace' or 'namespace_uri'\"),\n\t\t},\n\t\t{\n\t\t\tname:     \"empty identifier type not allowed\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(`invalid identifier type \"\" in \"f\"`),\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid identifier type not allowed\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"j\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(`invalid identifier type \"j\" in \"f\"`),\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate metric not allowed\",\n\t\t\texisting: map[metricParts]struct{}{\n\t\t\t\t{metricName: \"testmetric\", fieldName: \"f\", tags: \"id=ns=2;s=hf, t1=v1, t2=v2\"}: {},\n\t\t\t},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\", \"t2\": \"v2\"},\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(`name \"f\" is duplicated (metric name \"testmetric\", tags \"id=ns=2;s=hf, t1=v1, t2=v2\")`),\n\t\t},\n\t\t{\n\t\t\tname:     \"identifier type mismatch\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: \"i\",\n\t\t\t\t\tIdentifier:     \"hf\",\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: errors.New(`identifier type \"i\" does not match the type of identifier \"hf\"`),\n\t\t},\n\t}\n\n\tfor idT, idV := range map[string]string{\n\t\t\"s\": \"hf\",\n\t\t\"i\": \"1\",\n\t\t\"g\": \"849683f0-ce92-4fa2-836f-a02cde61d75d\",\n\t\t\"b\": \"aGVsbG8gSSBhbSBhIHRlc3QgaWRlbnRpZmllcg==\"} {\n\t\ttests = append(tests, struct {\n\t\t\tname     string\n\t\t\texisting map[metricParts]struct{}\n\t\t\tnmm      *NodeMetricMapping\n\t\t\terr      error\n\t\t}{\n\t\t\tname:     \"identifier type \" + idT + \" allowed\",\n\t\t\texisting: map[metricParts]struct{}{},\n\t\t\tnmm: func() *NodeMetricMapping {\n\t\t\t\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\tIdentifierType: idT,\n\t\t\t\t\tIdentifier:     idV,\n\t\t\t\t}, map[string]string{})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn nmm\n\t\t\t}(),\n\t\t\terr: nil,\n\t\t})\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := validateNodeToAdd(tt.existing, tt.nmm)\n\t\t\trequire.Equal(t, tt.err, err)\n\t\t})\n\t}\n}\n\nfunc TestInitNodeMetricMapping(t *testing.T) {\n\ttests := []struct {\n\t\ttestname string\n\t\tconfig   InputClientConfig\n\t\texpected []NodeMetricMapping\n\t\terr      error\n\t}{\n\t\t{\n\t\t\ttestname: \"only root node\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"testmetric\",\n\t\t\t\tTimestamp:  TimestampSourceTelegraf,\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=2;s=id1\",\n\t\t\t\t\tmetricName: \"testmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\terr: nil,\n\t\t},\n\t\t{\n\t\t\ttestname: \"root node and group node\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"testmetric\",\n\t\t\t\tTimestamp:  TimestampSourceTelegraf,\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tGroups: []NodeGroupSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tMetricName:     \"groupmetric\",\n\t\t\t\t\t\tNamespace:      \"3\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFieldName:   \"f\",\n\t\t\t\t\t\t\t\tIdentifier:  \"id2\",\n\t\t\t\t\t\t\t\tDefaultTags: map[string]string{\"t2\": \"v2\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"2\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id1\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t1\": \"v1\"},\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=2;s=id1\",\n\t\t\t\t\tmetricName: \"testmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"3\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id2\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=id2\",\n\t\t\t\t\tmetricName: \"groupmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t2\": \"v2\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\terr: nil,\n\t\t},\n\t\t{\n\t\t\ttestname: \"only group node\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"testmetric\",\n\t\t\t\tTimestamp:  TimestampSourceTelegraf,\n\t\t\t\tGroups: []NodeGroupSettings{\n\t\t\t\t\t{\n\t\t\t\t\t\tMetricName:     \"groupmetric\",\n\t\t\t\t\t\tNamespace:      \"3\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFieldName:   \"f\",\n\t\t\t\t\t\t\t\tIdentifier:  \"id2\",\n\t\t\t\t\t\t\t\tDefaultTags: map[string]string{\"t2\": \"v2\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName:      \"f\",\n\t\t\t\t\t\tNamespace:      \"3\",\n\t\t\t\t\t\tIdentifierType: \"s\",\n\t\t\t\t\t\tIdentifier:     \"id2\",\n\t\t\t\t\t\tDefaultTags:    map[string]string{\"t2\": \"v2\"},\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=id2\",\n\t\t\t\t\tmetricName: \"groupmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t2\": \"v2\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\terr: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.testname, func(t *testing.T) {\n\t\t\to := OpcUAInputClient{Config: tt.config}\n\t\t\terr := o.InitNodeMetricMapping()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, o.NodeMetricMapping)\n\t\t})\n\t}\n}\n\nfunc TestUpdateNodeValue(t *testing.T) {\n\ttype testStep struct {\n\t\tnodeIdx  int\n\t\tvalue    interface{}\n\t\tstatus   ua.StatusCode\n\t\texpected interface{}\n\t}\n\ttests := []struct {\n\t\ttestname string\n\t\tsteps    []testStep\n\t}{\n\t\t{\n\t\t\t\"value should update when code ok\",\n\t\t\t[]testStep{\n\t\t\t\t{\n\t\t\t\t\t0,\n\t\t\t\t\t\"Harmony\",\n\t\t\t\t\tua.StatusOK,\n\t\t\t\t\t\"Harmony\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"value should not update when code bad\",\n\t\t\t[]testStep{\n\t\t\t\t{\n\t\t\t\t\t0,\n\t\t\t\t\t\"Harmony\",\n\t\t\t\t\tua.StatusOK,\n\t\t\t\t\t\"Harmony\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t0,\n\t\t\t\t\t\"Odium\",\n\t\t\t\t\tua.StatusBad,\n\t\t\t\t\t\"Harmony\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t0,\n\t\t\t\t\t\"Ati\",\n\t\t\t\t\tua.StatusOK,\n\t\t\t\t\t\"Ati\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tconf := &opcua.OpcUAClientConfig{\n\t\tEndpoint:       \"opc.tcp://localhost:4930\",\n\t\tSecurityPolicy: \"None\",\n\t\tSecurityMode:   \"None\",\n\t\tAuthMethod:     \"\",\n\t\tConnectTimeout: config.Duration(2 * time.Second),\n\t\tRequestTimeout: config.Duration(2 * time.Second),\n\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t}\n\tc, err := conf.CreateClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\to := OpcUAInputClient{\n\t\tOpcUAClient: c,\n\t\tLog:         testutil.Logger{},\n\t\tNodeMetricMapping: []NodeMetricMapping{\n\t\t\t{\n\t\t\t\tTag: NodeSettings{\n\t\t\t\t\tFieldName: \"f\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tTag: NodeSettings{\n\t\t\t\t\tFieldName: \"f2\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLastReceivedData: make([]NodeValue, 2),\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.testname, func(t *testing.T) {\n\t\t\to.LastReceivedData = make([]NodeValue, 2)\n\t\t\tfor i, step := range tt.steps {\n\t\t\t\tv, err := ua.NewVariant(step.value)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\to.UpdateNodeValue(0, &ua.DataValue{\n\t\t\t\t\tValue:             v,\n\t\t\t\t\tStatus:            step.status,\n\t\t\t\t\tSourceTimestamp:   time.Date(2022, 03, 17, 8, 33, 00, 00, &time.Location{}).Add(time.Duration(i) * time.Second),\n\t\t\t\t\tSourcePicoseconds: 0,\n\t\t\t\t\tServerTimestamp:   time.Date(2022, 03, 17, 8, 33, 00, 500, &time.Location{}).Add(time.Duration(i) * time.Second),\n\t\t\t\t\tServerPicoseconds: 0,\n\t\t\t\t})\n\t\t\t\trequire.Equal(t, step.expected, o.LastReceivedData[0].Value)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMetricForNode(t *testing.T) {\n\tconf := &opcua.OpcUAClientConfig{\n\t\tEndpoint:       \"opc.tcp://localhost:4930\",\n\t\tSecurityPolicy: \"None\",\n\t\tSecurityMode:   \"None\",\n\t\tAuthMethod:     \"\",\n\t\tConnectTimeout: config.Duration(2 * time.Second),\n\t\tRequestTimeout: config.Duration(2 * time.Second),\n\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t}\n\tc, err := conf.CreateClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\to := OpcUAInputClient{\n\t\tConfig: InputClientConfig{\n\t\t\tTimestamp:       TimestampSourceSource,\n\t\t\tTimestampFormat: time.RFC3339Nano,\n\t\t},\n\t\tOpcUAClient:      c,\n\t\tLog:              testutil.Logger{},\n\t\tLastReceivedData: make([]NodeValue, 2),\n\t}\n\n\ttests := []struct {\n\t\ttestname string\n\t\tnmm      []NodeMetricMapping\n\t\tv        interface{}\n\t\tisArray  bool\n\t\tdataType ua.TypeID\n\t\ttime     time.Time\n\t\tstatus   ua.StatusCode\n\t\texpected telegraf.Metric\n\t}{\n\t\t{\n\t\t\ttestname: \"metric build correctly\",\n\t\t\tnmm: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName: \"fn\",\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=hi\",\n\t\t\t\t\tmetricName: \"testingmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tv:        16,\n\t\t\tisArray:  false,\n\t\t\tdataType: ua.TypeIDInt32,\n\t\t\ttime:     time.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{}),\n\t\t\tstatus:   ua.StatusOK,\n\t\t\texpected: metric.New(\"testingmetric\",\n\t\t\t\tmap[string]string{\"t1\": \"v1\", \"id\": \"ns=3;s=hi\"},\n\t\t\t\tmap[string]interface{}{\"Quality\": \"The operation succeeded. StatusGood (0x0)\", \"fn\": 16},\n\t\t\t\ttime.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{})),\n\t\t},\n\t\t{\n\t\t\ttestname: \"array-like metric build correctly\",\n\t\t\tnmm: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName: \"fn\",\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=hi\",\n\t\t\t\t\tmetricName: \"testingmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tv:        []int32{16, 17},\n\t\t\tisArray:  true,\n\t\t\tdataType: ua.TypeIDInt32,\n\t\t\ttime:     time.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{}),\n\t\t\tstatus:   ua.StatusOK,\n\t\t\texpected: metric.New(\"testingmetric\",\n\t\t\t\tmap[string]string{\"t1\": \"v1\", \"id\": \"ns=3;s=hi\"},\n\t\t\t\tmap[string]interface{}{\"Quality\": \"The operation succeeded. StatusGood (0x0)\", \"fn[0]\": 16, \"fn[1]\": 17},\n\t\t\t\ttime.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{})),\n\t\t},\n\t\t{\n\t\t\ttestname: \"datetime array metric build correctly\",\n\t\t\tnmm: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName: \"fn\",\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=hi\",\n\t\t\t\t\tmetricName: \"testingmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tv: []time.Time{\n\t\t\t\ttime.Date(2022, 3, 17, 8, 55, 0, 0, time.UTC),\n\t\t\t\ttime.Date(2022, 3, 17, 8, 56, 0, 0, time.UTC),\n\t\t\t},\n\t\t\tisArray:  true,\n\t\t\tdataType: ua.TypeIDDateTime,\n\t\t\ttime:     time.Date(2022, 3, 17, 8, 55, 0, 0, &time.Location{}),\n\t\t\tstatus:   ua.StatusOK,\n\t\t\texpected: metric.New(\"testingmetric\",\n\t\t\t\tmap[string]string{\"t1\": \"v1\", \"id\": \"ns=3;s=hi\"},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"Quality\": \"The operation succeeded. StatusGood (0x0)\",\n\t\t\t\t\t\"fn[0]\":   \"2022-03-17T08:55:00Z\",\n\t\t\t\t\t\"fn[1]\":   \"2022-03-17T08:56:00Z\",\n\t\t\t\t},\n\t\t\t\ttime.Date(2022, 3, 17, 8, 55, 0, 0, &time.Location{})),\n\t\t},\n\t\t{\n\t\t\ttestname: \"datetime array preserves timezone\",\n\t\t\tnmm: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName: \"fn\",\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=hi\",\n\t\t\t\t\tmetricName: \"testingmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tv: []time.Time{\n\t\t\t\ttime.Date(2022, 3, 17, 8, 55, 0, 0, time.FixedZone(\"EST\", -5*3600)),\n\t\t\t\ttime.Date(2022, 3, 17, 8, 56, 0, 0, time.FixedZone(\"EST\", -5*3600)),\n\t\t\t},\n\t\t\tisArray:  true,\n\t\t\tdataType: ua.TypeIDDateTime,\n\t\t\ttime:     time.Date(2022, 3, 17, 8, 55, 0, 0, &time.Location{}),\n\t\t\tstatus:   ua.StatusOK,\n\t\t\texpected: metric.New(\"testingmetric\",\n\t\t\t\tmap[string]string{\"t1\": \"v1\", \"id\": \"ns=3;s=hi\"},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"Quality\": \"The operation succeeded. StatusGood (0x0)\",\n\t\t\t\t\t\"fn[0]\":   \"2022-03-17T08:55:00-05:00\",\n\t\t\t\t\t\"fn[1]\":   \"2022-03-17T08:56:00-05:00\",\n\t\t\t\t},\n\t\t\t\ttime.Date(2022, 3, 17, 8, 55, 0, 0, &time.Location{})),\n\t\t},\n\t\t{\n\t\t\ttestname: \"nil does not panic\",\n\t\t\tnmm: []NodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tTag: NodeSettings{\n\t\t\t\t\t\tFieldName: \"fn\",\n\t\t\t\t\t},\n\t\t\t\t\tidStr:      \"ns=3;s=hi\",\n\t\t\t\t\tmetricName: \"testingmetric\",\n\t\t\t\t\tMetricTags: map[string]string{\"t1\": \"v1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tv:        nil,\n\t\t\tisArray:  false,\n\t\t\tdataType: ua.TypeIDNull,\n\t\t\ttime:     time.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{}),\n\t\t\tstatus:   ua.StatusOK,\n\t\t\texpected: metric.New(\"testingmetric\",\n\t\t\t\tmap[string]string{\"t1\": \"v1\", \"id\": \"ns=3;s=hi\"},\n\t\t\t\tmap[string]interface{}{\"Quality\": \"The operation succeeded. StatusGood (0x0)\"},\n\t\t\t\ttime.Date(2022, 03, 17, 8, 55, 00, 00, &time.Location{})),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.testname, func(t *testing.T) {\n\t\t\to.NodeMetricMapping = tt.nmm\n\t\t\to.LastReceivedData[0].SourceTime = tt.time\n\t\t\to.LastReceivedData[0].Quality = tt.status\n\t\t\to.LastReceivedData[0].Value = tt.v\n\t\t\to.LastReceivedData[0].DataType = tt.dataType\n\t\t\to.LastReceivedData[0].IsArray = tt.isArray\n\t\t\tactual := o.MetricForNode(0)\n\t\t\trequire.Equal(t, tt.expected.Tags(), actual.Tags())\n\t\t\trequire.Equal(t, tt.expected.Fields(), actual.Fields())\n\t\t\trequire.Equal(t, tt.expected.Time(), actual.Time())\n\t\t})\n\t}\n}\n\nfunc TestMetricForEvent(t *testing.T) {\n\tnow := time.Date(2026, 2, 23, 8, 44, 15, 0, time.UTC)\n\tconf := &opcua.OpcUAClientConfig{\n\t\tEndpoint:       \"opc.tcp://localhost:4862\",\n\t\tSecurityPolicy: \"None\",\n\t\tSecurityMode:   \"None\",\n\t\tConnectTimeout: config.Duration(2 * time.Second),\n\t\tRequestTimeout: config.Duration(2 * time.Second),\n\t}\n\tc, err := conf.CreateClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname     string\n\t\tconfig   InputClientConfig\n\t\tmapping  []EventNodeMetricMapping\n\t\tevent    *ua.EventFieldList\n\t\texpected telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"all fields nil returns nil\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceTelegraf,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(2, 1003),\n\t\t\t\t\tFields:        []string{\"EventId\", \"Message\", \"Severity\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields:  []*ua.Variant{ua.MustVariant(nil), ua.MustVariant(nil), ua.MustVariant(nil)},\n\t\t\t},\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"fields with values\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceTelegraf,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(0, 2041),\n\t\t\t\t\tFields:        []string{\"Severity\", \"SourceName\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields: []*ua.Variant{\n\t\t\t\t\tua.MustVariant(uint16(500)),\n\t\t\t\t\tua.MustVariant(\"TestSource\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: metric.New(\"opcua_event\",\n\t\t\t\tmap[string]string{\"node_id\": \"i=2253\", \"source\": \"opc.tcp://localhost:4862\"},\n\t\t\t\tmap[string]interface{}{\"Severity\": uint16(500), \"SourceName\": \"TestSource\"},\n\t\t\t\ttime.Time{},\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"source timestamp from event Time field\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceSource,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(0, 2041),\n\t\t\t\t\tFields:        []string{\"Time\", \"Severity\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields: []*ua.Variant{\n\t\t\t\t\tua.MustVariant(now),\n\t\t\t\t\tua.MustVariant(uint16(100)),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: metric.New(\"opcua_event\",\n\t\t\t\tmap[string]string{\"node_id\": \"i=2253\", \"source\": \"opc.tcp://localhost:4862\"},\n\t\t\t\tmap[string]interface{}{\"Time\": now.Format(time.RFC3339), \"Severity\": uint16(100)},\n\t\t\t\tnow,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"server timestamp from event ReceiveTime field\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceServer,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(0, 2041),\n\t\t\t\t\tFields:        []string{\"ReceiveTime\", \"Severity\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields: []*ua.Variant{\n\t\t\t\t\tua.MustVariant(now),\n\t\t\t\t\tua.MustVariant(uint16(200)),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: metric.New(\"opcua_event\",\n\t\t\t\tmap[string]string{\"node_id\": \"i=2253\", \"source\": \"opc.tcp://localhost:4862\"},\n\t\t\t\tmap[string]interface{}{\"ReceiveTime\": now.Format(time.RFC3339), \"Severity\": uint16(200)},\n\t\t\t\tnow,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"localized text field\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceTelegraf,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(0, 2041),\n\t\t\t\t\tFields:        []string{\"Message\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields: []*ua.Variant{\n\t\t\t\t\tua.MustVariant(&ua.LocalizedText{Text: \"Alarm triggered\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: metric.New(\"opcua_event\",\n\t\t\t\tmap[string]string{\"node_id\": \"i=2253\", \"source\": \"opc.tcp://localhost:4862\"},\n\t\t\t\tmap[string]interface{}{\"Message\": \"Alarm triggered\"},\n\t\t\t\ttime.Time{},\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"source timestamp falls back to now when Time field absent\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tOpcUAClientConfig: *conf,\n\t\t\t\tTimestamp:         TimestampSourceSource,\n\t\t\t},\n\t\t\tmapping: []EventNodeMetricMapping{\n\t\t\t\t{\n\t\t\t\t\tNodeID:        ua.NewNumericNodeID(0, 2253),\n\t\t\t\t\tEventTypeNode: ua.NewNumericNodeID(0, 2041),\n\t\t\t\t\tFields:        []string{\"Severity\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tevent: &ua.EventFieldList{\n\t\t\t\tClientHandle: 0,\n\t\t\t\tEventFields: []*ua.Variant{\n\t\t\t\t\tua.MustVariant(uint16(300)),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: metric.New(\"opcua_event\",\n\t\t\t\tmap[string]string{\"node_id\": \"i=2253\", \"source\": \"opc.tcp://localhost:4862\"},\n\t\t\t\tmap[string]interface{}{\"Severity\": uint16(300)},\n\t\t\t\ttime.Time{},\n\t\t\t),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\to := OpcUAInputClient{\n\t\t\t\tOpcUAClient:            c,\n\t\t\t\tConfig:                 tt.config,\n\t\t\t\tLog:                    testutil.Logger{},\n\t\t\t\tEventNodeMetricMapping: tt.mapping,\n\t\t\t}\n\t\t\tactual := o.MetricForEvent(0, tt.event)\n\t\t\tif tt.expected == nil {\n\t\t\t\trequire.Nil(t, actual)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NotNil(t, actual)\n\t\t\trequire.Equal(t, tt.expected.Tags(), actual.Tags())\n\t\t\trequire.Equal(t, tt.expected.Fields(), actual.Fields())\n\t\t\tif !tt.expected.Time().IsZero() {\n\t\t\t\trequire.Equal(t, tt.expected.Time(), actual.Time())\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestNodeIDGeneration tests that NodeID() generates correct node ID strings\nfunc TestNodeIDGeneration(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tnode     NodeSettings\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"namespace index format\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"Temperature\",\n\t\t\t},\n\t\t\texpected: \"ns=3;s=Temperature\",\n\t\t},\n\t\t{\n\t\t\tname: \"namespace URI format\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"2255\",\n\t\t\t},\n\t\t\texpected: \"nsu=http://opcfoundation.org/UA/;i=2255\",\n\t\t},\n\t\t{\n\t\t\tname: \"namespace index with numeric identifier\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNamespace:      \"0\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"2256\",\n\t\t\t},\n\t\t\texpected: \"ns=0;i=2256\",\n\t\t},\n\t\t{\n\t\t\tname: \"namespace URI with string identifier\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNamespaceURI:   \"http://example.com/MyNamespace\",\n\t\t\t\tIdentifierType: \"s\",\n\t\t\t\tIdentifier:     \"MyVariable\",\n\t\t\t},\n\t\t\texpected: \"nsu=http://example.com/MyNamespace;s=MyVariable\",\n\t\t},\n\t\t{\n\t\t\tname: \"namespace URI with GUID identifier\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNamespaceURI:   \"http://vendor.com/\",\n\t\t\t\tIdentifierType: \"g\",\n\t\t\t\tIdentifier:     \"12345678-1234-1234-1234-123456789012\",\n\t\t\t},\n\t\t\texpected: \"nsu=http://vendor.com/;g=12345678-1234-1234-1234-123456789012\",\n\t\t},\n\t\t{\n\t\t\tname: \"direct string takes precedence\",\n\t\t\tnode: NodeSettings{\n\t\t\t\tNodeIDStr: \"ns=5;s=MyNode\",\n\t\t\t},\n\t\t\texpected: \"ns=5;s=MyNode\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.node.NodeID())\n\t\t})\n\t}\n}\n\n// TestEventNodeIDGeneration tests that EventNodeSettings.NodeID() generates correct node ID strings\nfunc TestEventNodeIDGeneration(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tnode     EventNodeSettings\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"event node with namespace index\",\n\t\t\tnode: EventNodeSettings{\n\t\t\t\tNamespace:      \"1\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"2041\",\n\t\t\t},\n\t\t\texpected: \"ns=1;i=2041\",\n\t\t},\n\t\t{\n\t\t\tname: \"event node with namespace URI\",\n\t\t\tnode: EventNodeSettings{\n\t\t\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"2253\",\n\t\t\t},\n\t\t\texpected: \"nsu=http://opcfoundation.org/UA/;i=2253\",\n\t\t},\n\t\t{\n\t\t\tname: \"direct string takes precedence\",\n\t\t\tnode: EventNodeSettings{\n\t\t\t\tNodeIDStr: \"ns=2;s=EventSource\",\n\t\t\t},\n\t\t\texpected: \"ns=2;s=EventSource\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.node.NodeID())\n\t\t})\n\t}\n}\n\n// TestNodeValidationBothNamespaces tests that validation fails when both namespace and namespace_uri are set\nfunc TestNodeValidationBothNamespaces(t *testing.T) {\n\texisting := make(map[metricParts]struct{})\n\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\tFieldName:      \"test\",\n\t\tNamespace:      \"3\",\n\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\tIdentifierType: \"s\",\n\t\tIdentifier:     \"Temperature\",\n\t}, map[string]string{})\n\trequire.NoError(t, err)\n\n\terr = validateNodeToAdd(existing, nmm)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"cannot specify both 'namespace' and 'namespace_uri'\")\n}\n\n// TestNodeValidationNeitherNamespace tests that validation fails when neither namespace nor namespace_uri is set\nfunc TestNodeValidationNeitherNamespace(t *testing.T) {\n\texisting := make(map[metricParts]struct{})\n\tnmm, err := NewNodeMetricMapping(\"testmetric\", NodeSettings{\n\t\tFieldName:      \"test\",\n\t\tIdentifierType: \"s\",\n\t\tIdentifier:     \"Temperature\",\n\t}, map[string]string{})\n\trequire.NoError(t, err)\n\n\terr = validateNodeToAdd(existing, nmm)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"must specify either 'namespace' or 'namespace_uri'\")\n}\n\n// TestEventNodeValidationBothNamespaces tests event node validation with both namespace types\nfunc TestEventNodeValidationBothNamespaces(t *testing.T) {\n\tnode := EventNodeSettings{\n\t\tNamespace:      \"1\",\n\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\tIdentifierType: \"i\",\n\t\tIdentifier:     \"2041\",\n\t}\n\n\terr := node.validateEventNodeSettings()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"cannot specify both 'namespace' and 'namespace_uri'\")\n}\n\n// TestEventNodeValidationNeitherNamespace tests event node validation with neither namespace type\nfunc TestEventNodeValidationNeitherNamespace(t *testing.T) {\n\tnode := EventNodeSettings{\n\t\tIdentifierType: \"i\",\n\t\tIdentifier:     \"2041\",\n\t}\n\n\terr := node.validateEventNodeSettings()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"must specify either 'namespace' or 'namespace_uri'\")\n}\n\n// TestGroupNamespaceURIInheritance tests that nodes inherit namespace_uri from groups\nfunc TestGroupNamespaceURIInheritance(t *testing.T) {\n\tclient := &OpcUAInputClient{\n\t\tConfig: InputClientConfig{\n\t\t\tMetricName: \"opcua\",\n\t\t\tGroups: []NodeGroupSettings{\n\t\t\t\t{\n\t\t\t\t\tNamespace:      \"\",\n\t\t\t\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\t\t\t\tIdentifierType: \"i\",\n\t\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFieldName:  \"node1\",\n\t\t\t\t\t\t\tIdentifier: \"2255\",\n\t\t\t\t\t\t\t// Should inherit namespace_uri from group\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFieldName:    \"node2\",\n\t\t\t\t\t\t\tIdentifier:   \"2256\",\n\t\t\t\t\t\t\tNamespaceURI: \"http://custom.org/UA/\", // Override group default\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := client.InitNodeMetricMapping()\n\trequire.NoError(t, err)\n\trequire.Len(t, client.NodeMetricMapping, 2)\n\n\t// First node should inherit from group\n\trequire.Equal(t, \"http://opcfoundation.org/UA/\", client.NodeMetricMapping[0].Tag.NamespaceURI)\n\trequire.Equal(t, \"nsu=http://opcfoundation.org/UA/;i=2255\", client.NodeMetricMapping[0].Tag.NodeID())\n\n\t// Second node should use its own namespace_uri\n\trequire.Equal(t, \"http://custom.org/UA/\", client.NodeMetricMapping[1].Tag.NamespaceURI)\n\trequire.Equal(t, \"nsu=http://custom.org/UA/;i=2256\", client.NodeMetricMapping[1].Tag.NodeID())\n}\n\n// TestEventGroupNamespaceURIInheritance tests that event nodes inherit namespace_uri from event groups\nfunc TestEventGroupNamespaceURIInheritance(t *testing.T) {\n\teventGroup := EventGroupSettings{\n\t\tNamespaceURI:   \"http://opcfoundation.org/UA/\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []EventNodeSettings{\n\t\t\t{\n\t\t\t\tIdentifier: \"2253\",\n\t\t\t\t// Should inherit namespace_uri from group\n\t\t\t},\n\t\t\t{\n\t\t\t\tIdentifier:   \"2254\",\n\t\t\t\tNamespaceURI: \"http://custom.org/UA/\", // Override group default\n\t\t\t},\n\t\t},\n\t}\n\n\teventGroup.UpdateNodeIDSettings()\n\n\t// First node should inherit from group\n\trequire.Equal(t, \"http://opcfoundation.org/UA/\", eventGroup.NodeIDSettings[0].NamespaceURI)\n\trequire.Equal(t, \"nsu=http://opcfoundation.org/UA/;i=2253\", eventGroup.NodeIDSettings[0].NodeID())\n\n\t// Second node should use its own namespace_uri\n\trequire.Equal(t, \"http://custom.org/UA/\", eventGroup.NodeIDSettings[1].NamespaceURI)\n\trequire.Equal(t, \"nsu=http://custom.org/UA/;i=2254\", eventGroup.NodeIDSettings[1].NodeID())\n}\n\nfunc TestValidateOPCTagsWithNodeID(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tconfig InputClientConfig\n\t}{\n\t\t{\n\t\t\tname: \"valid config with node_id string\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{FieldName: \"ProductUri\", NodeIDStr: \"ns=0;i=2262\"},\n\t\t\t\t\t{FieldName: \"ServerState\", NodeIDStr: \"ns=0;i=2259\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed config with node_id and individual fields\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{FieldName: \"ProductUri\", NodeIDStr: \"ns=0;i=2262\"},\n\t\t\t\t\t{FieldName: \"Temperature\", Namespace: \"2\", IdentifierType: \"s\", Identifier: \"Temp\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"node_id with namespace URI\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{FieldName: \"ProductUri\", NodeIDStr: \"nsu=http://opcfoundation.org/UA/;i=2262\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\to := OpcUAInputClient{\n\t\t\t\tConfig: tt.config,\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, o.InitNodeMetricMapping())\n\t\t})\n\t}\n}\n\nfunc TestValidateOPCTagsWithNodeIDError(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tconfig      InputClientConfig\n\t\texpectedErr string\n\t}{\n\t\t{\n\t\t\tname: \"conflict between node_id and individual fields\",\n\t\t\tconfig: InputClientConfig{\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tRootNodes: []NodeSettings{\n\t\t\t\t\t{FieldName: \"Conflict\", NodeIDStr: \"ns=0;i=2262\", Namespace: \"1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"cannot specify both 'id' and individual fields\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\to := OpcUAInputClient{\n\t\t\t\tConfig: tt.config,\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t}\n\t\t\trequire.ErrorContains(t, o.InitNodeMetricMapping(), tt.expectedErr)\n\t\t})\n\t}\n}\n\nfunc TestNodeGroupWithNodeIDString(t *testing.T) {\n\tcfg := InputClientConfig{\n\t\tMetricName: \"opcua\",\n\t\tGroups: []NodeGroupSettings{\n\t\t\t{\n\t\t\t\tMetricName: \"group1\",\n\t\t\t\tNodes: []NodeSettings{\n\t\t\t\t\t{FieldName: \"Node1\", NodeIDStr: \"ns=2;s=Device.Temp\"},\n\t\t\t\t\t{FieldName: \"Node2\", NodeIDStr: \"nsu=http://example.org/;i=100\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\to := OpcUAInputClient{\n\t\tConfig: cfg,\n\t\tLog:    testutil.Logger{},\n\t}\n\trequire.NoError(t, o.InitNodeMetricMapping())\n\trequire.Len(t, o.NodeMetricMapping, 2)\n\n\t// Verify nodes use string directly (no decomposition into individual fields)\n\trequire.Equal(t, \"ns=2;s=Device.Temp\", o.NodeMetricMapping[0].Tag.NodeID())\n\trequire.Equal(t, \"nsu=http://example.org/;i=100\", o.NodeMetricMapping[1].Tag.NodeID())\n}\n\nfunc TestEventGroupWithNodeIDString(t *testing.T) {\n\teventGroup := EventGroupSettings{\n\t\tEventTypeNode: EventNodeSettings{\n\t\t\tNodeIDStr: \"ns=0;i=2041\",\n\t\t},\n\t\tNodeIDSettings: []EventNodeSettings{\n\t\t\t{NodeIDStr: \"ns=2;s=EventSource1\"},\n\t\t\t{NodeIDStr: \"nsu=http://example.org/;i=200\"},\n\t\t},\n\t\tFields: []string{\"Severity\", \"Message\"},\n\t}\n\n\teventGroup.UpdateNodeIDSettings()\n\n\t// Verify nodes use string directly (no decomposition into individual fields)\n\trequire.Equal(t, \"ns=0;i=2041\", eventGroup.EventTypeNode.NodeID())\n\trequire.Equal(t, \"ns=2;s=EventSource1\", eventGroup.NodeIDSettings[0].NodeID())\n\trequire.Equal(t, \"nsu=http://example.org/;i=200\", eventGroup.NodeIDSettings[1].NodeID())\n}\n"
  },
  {
    "path": "plugins/common/opcua/logger.go",
    "content": "package opcua\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\n// DebugLogger logs messages from opcua at the debug level.\ntype DebugLogger struct {\n\tLog telegraf.Logger\n}\n\nfunc (l *DebugLogger) Write(p []byte) (n int, err error) {\n\tl.Log.Debug(string(p))\n\treturn len(p), nil\n}\n"
  },
  {
    "path": "plugins/common/opcua/opcua_util.go",
    "content": "package opcua\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua\"\n\t\"github.com/gopcua/opcua/debug\"\n\t\"github.com/gopcua/opcua/ua\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\n// SELF SIGNED CERT FUNCTIONS\n\nfunc newTempDir() (string, error) {\n\tdir, err := os.MkdirTemp(\"\", \"ssc\")\n\treturn dir, err\n}\n\nfunc generateCert(host string, rsaBits int, certFile, keyFile string, dur time.Duration) (cert, key string, err error) {\n\tif len(host) == 0 {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"validation\",\n\t\t\tErr:       fmt.Errorf(\"%w: missing required host parameter\", ErrCertificateGeneration),\n\t\t}\n\t}\n\tif rsaBits == 0 {\n\t\trsaBits = 2048\n\t}\n\n\t// If both paths are empty, use temporary directory (backward compatible behavior)\n\tif certFile == \"\" && keyFile == \"\" {\n\t\tdir, err := newTempDir()\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", &CertificateError{\n\t\t\t\tOperation: \"directory creation\",\n\t\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t\t}\n\t\t}\n\t\tcertFile = dir + \"/cert.pem\"\n\t\tkeyFile = dir + \"/key.pem\"\n\t} else {\n\t\t// If paths are provided, create parent directories if they don't exist\n\t\tif err := os.MkdirAll(filepath.Dir(certFile), 0750); err != nil {\n\t\t\treturn \"\", \"\", &CertificateError{\n\t\t\t\tOperation: \"directory creation\",\n\t\t\t\tPath:      certFile,\n\t\t\t\tErr:       fmt.Errorf(\"%w: failed to create parent directory: %w\", ErrCertificateGeneration, err),\n\t\t\t}\n\t\t}\n\n\t\tif err := os.MkdirAll(filepath.Dir(keyFile), 0750); err != nil {\n\t\t\treturn \"\", \"\", &CertificateError{\n\t\t\t\tOperation: \"directory creation\",\n\t\t\t\tPath:      keyFile,\n\t\t\t\tErr:       fmt.Errorf(\"%w: failed to create parent directory: %w\", ErrCertificateGeneration, err),\n\t\t\t}\n\t\t}\n\t}\n\n\tpriv, err := rsa.GenerateKey(rand.Reader, rsaBits)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"private key generation\",\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\n\tnotBefore := time.Now()\n\tnotAfter := notBefore.Add(dur)\n\n\tserialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)\n\tserialNumber, err := rand.Int(rand.Reader, serialNumberLimit)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"serial number generation\",\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\n\ttemplate := x509.Certificate{\n\t\tSerialNumber: serialNumber,\n\t\tSubject: pkix.Name{\n\t\t\tOrganization: []string{\"Telegraf OPC UA Client\"},\n\t\t},\n\t\tNotBefore: notBefore,\n\t\tNotAfter:  notAfter,\n\n\t\tKeyUsage: x509.KeyUsageContentCommitment | x509.KeyUsageKeyEncipherment |\n\t\t\tx509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment | x509.KeyUsageCertSign,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},\n\t\tBasicConstraintsValid: true,\n\t}\n\n\thosts := strings.Split(host, \",\")\n\tfor _, h := range hosts {\n\t\tif ip := net.ParseIP(h); ip != nil {\n\t\t\ttemplate.IPAddresses = append(template.IPAddresses, ip)\n\t\t} else {\n\t\t\ttemplate.DNSNames = append(template.DNSNames, h)\n\t\t}\n\t\tif uri, err := url.Parse(h); err == nil {\n\t\t\ttemplate.URIs = append(template.URIs, uri)\n\t\t}\n\t}\n\n\tderBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"certificate creation\",\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\n\tcertOut, err := os.Create(certFile)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"file creation\",\n\t\t\tPath:      certFile,\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\tdefer func() {\n\t\tif closeErr := certOut.Close(); closeErr != nil {\n\t\t\t// Log the close error but don't override the main error\n\t\t\t_ = closeErr // Acknowledge that we're intentionally ignoring this error\n\t\t}\n\t}()\n\n\tif err := pem.Encode(certOut, &pem.Block{Type: \"CERTIFICATE\", Bytes: derBytes}); err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"encoding\",\n\t\t\tPath:      certFile,\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\n\tkeyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"file creation\",\n\t\t\tPath:      keyFile,\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\tdefer func() {\n\t\tif closeErr := keyOut.Close(); closeErr != nil {\n\t\t\t// Log the close error but don't override the main error\n\t\t\t_ = closeErr // Acknowledge that we're intentionally ignoring this error\n\t\t}\n\t}()\n\n\tkeyBlock, err := pemBlockForKey(priv)\n\tif err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"key block generation\",\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\tif err := pem.Encode(keyOut, keyBlock); err != nil {\n\t\treturn \"\", \"\", &CertificateError{\n\t\t\tOperation: \"encoding\",\n\t\t\tPath:      keyFile,\n\t\t\tErr:       fmt.Errorf(\"%w: %w\", ErrCertificateGeneration, err),\n\t\t}\n\t}\n\n\treturn certFile, keyFile, nil\n}\n\nfunc publicKey(priv interface{}) interface{} {\n\tswitch k := priv.(type) {\n\tcase *rsa.PrivateKey:\n\t\treturn &k.PublicKey\n\tcase *ecdsa.PrivateKey:\n\t\treturn &k.PublicKey\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc pemBlockForKey(priv interface{}) (*pem.Block, error) {\n\tswitch k := priv.(type) {\n\tcase *rsa.PrivateKey:\n\t\treturn &pem.Block{Type: \"RSA PRIVATE KEY\", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil\n\tcase *ecdsa.PrivateKey:\n\t\tb, err := x509.MarshalECPrivateKey(k)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to marshal ECDSA private key: %w\", err)\n\t\t}\n\t\treturn &pem.Block{Type: \"EC PRIVATE KEY\", Bytes: b}, nil\n\tdefault:\n\t\treturn nil, nil\n\t}\n}\n\nfunc (o *OpcUAClient) generateClientOpts(endpoints []*ua.EndpointDescription) ([]opcua.Option, error) {\n\tappuri := \"urn:telegraf:gopcua:client\"\n\tappname := \"Telegraf\"\n\n\t// ApplicationURI is automatically read from the cert so is not required if a cert if provided\n\topts := []opcua.Option{\n\t\topcua.ApplicationURI(appuri),\n\t\topcua.ApplicationName(appname),\n\t\topcua.RequestTimeout(time.Duration(o.Config.RequestTimeout)),\n\t}\n\n\tif o.Config.SessionTimeout != 0 {\n\t\topts = append(opts, opcua.SessionTimeout(time.Duration(o.Config.SessionTimeout)))\n\t}\n\n\tcertFile := o.Config.Certificate\n\tkeyFile := o.Config.PrivateKey\n\tpolicy := o.Config.SecurityPolicy\n\tmode := o.Config.SecurityMode\n\tvar err error\n\tif certFile == \"\" && keyFile == \"\" {\n\t\tif policy != \"None\" || mode != \"None\" {\n\t\t\tcertFile, keyFile, err = generateCert(appuri, 2048, certFile, keyFile, 365*24*time.Hour)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\tvar cert []byte\n\tvar pk *rsa.PrivateKey\n\tif certFile != \"\" && keyFile != \"\" {\n\t\tdebug.Printf(\"Loading cert/key from %s/%s\", certFile, keyFile)\n\t\tc, err := tls.LoadX509KeyPair(certFile, keyFile)\n\t\tif err != nil {\n\t\t\to.Log.Warnf(\"Failed to load certificate: %s\", err)\n\t\t} else {\n\t\t\tpkTemp, ok := c.PrivateKey.(*rsa.PrivateKey)\n\t\t\tif !ok {\n\t\t\t\treturn nil, errors.New(\"invalid private key\")\n\t\t\t}\n\t\t\tpk = pkTemp\n\t\t\tcert = c.Certificate[0]\n\t\t\topts = append(opts, opcua.PrivateKey(pk), opcua.Certificate(cert))\n\t\t}\n\t}\n\n\tvar secPolicy string\n\tswitch {\n\tcase policy == \"auto\":\n\t\t// set it later\n\tcase strings.HasPrefix(policy, ua.SecurityPolicyURIPrefix):\n\t\tsecPolicy = policy\n\t\tpolicy = \"\"\n\tcase policy == \"None\" || policy == \"Basic128Rsa15\" || policy == \"Basic256\" || policy == \"Basic256Sha256\" ||\n\t\tpolicy == \"Aes128_Sha256_RsaOaep\" || policy == \"Aes256_Sha256_RsaPss\":\n\t\tsecPolicy = ua.SecurityPolicyURIPrefix + policy\n\t\tpolicy = \"\"\n\tdefault:\n\t\treturn nil, &SecurityError{\n\t\t\tPolicy: policy,\n\t\t\tErr:    fmt.Errorf(\"%w: %s\", ErrInvalidSecurityPolicy, policy),\n\t\t}\n\t}\n\n\to.Log.Debugf(\"security policy from configuration %s\", secPolicy)\n\n\t// Select the most appropriate authentication mode from server capabilities and user input\n\tauthMode, authOptions, err := o.generateAuth(o.Config.AuthMethod, cert, pk, o.Config.Username, o.Config.Password)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\topts = append(opts, authOptions...)\n\n\tvar secMode ua.MessageSecurityMode\n\tswitch strings.ToLower(mode) {\n\tcase \"auto\":\n\tcase \"none\":\n\t\tsecMode = ua.MessageSecurityModeNone\n\t\tmode = \"\"\n\tcase \"sign\":\n\t\tsecMode = ua.MessageSecurityModeSign\n\t\tmode = \"\"\n\tcase \"signandencrypt\":\n\t\tsecMode = ua.MessageSecurityModeSignAndEncrypt\n\t\tmode = \"\"\n\tdefault:\n\t\treturn nil, &SecurityError{\n\t\t\tMode: mode,\n\t\t\tErr:  fmt.Errorf(\"%w: %s\", ErrInvalidSecurityMode, mode),\n\t\t}\n\t}\n\n\t// Allow input of only one of sec-mode,sec-policy when choosing 'None'\n\tif secMode == ua.MessageSecurityModeNone || secPolicy == ua.SecurityPolicyURINone {\n\t\tsecMode = ua.MessageSecurityModeNone\n\t\tsecPolicy = ua.SecurityPolicyURINone\n\t}\n\n\t// Find the best endpoint based on our input and server recommendation (highest SecurityMode+SecurityLevel)\n\tvar serverEndpoint *ua.EndpointDescription\n\tswitch {\n\tcase mode == \"auto\" && policy == \"auto\": // No user selection, choose best\n\t\tfor _, e := range endpoints {\n\t\t\tif serverEndpoint == nil || (e.SecurityMode >= serverEndpoint.SecurityMode && e.SecurityLevel >= serverEndpoint.SecurityLevel) {\n\t\t\t\tserverEndpoint = e\n\t\t\t}\n\t\t}\n\n\tcase mode != \"auto\" && policy == \"auto\": // User only cares about mode, select highest securitylevel with that mode\n\t\tfor _, e := range endpoints {\n\t\t\tif e.SecurityMode == secMode && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {\n\t\t\t\tserverEndpoint = e\n\t\t\t}\n\t\t}\n\n\tcase mode == \"auto\" && policy != \"auto\": // User only cares about policy, select highest securitylevel with that policy\n\t\tfor _, e := range endpoints {\n\t\t\tif e.SecurityPolicyURI == secPolicy && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {\n\t\t\t\tserverEndpoint = e\n\t\t\t}\n\t\t}\n\n\tdefault: // User cares about both\n\t\to.Log.Debugf(\"User cares about both the policy (%s) and security mode (%s)\", secPolicy, secMode)\n\t\to.Log.Debugf(\"Server has %d endpoints\", len(endpoints))\n\t\tfor _, e := range endpoints {\n\t\t\to.Log.Debugf(\"Evaluating endpoint %s, policy %s, mode %s, level %d\", e.EndpointURL, e.SecurityPolicyURI, e.SecurityMode, e.SecurityLevel)\n\t\t\tif e.SecurityPolicyURI == secPolicy && e.SecurityMode == secMode && (serverEndpoint == nil || e.SecurityLevel >= serverEndpoint.SecurityLevel) {\n\t\t\t\tserverEndpoint = e\n\t\t\t\to.Log.Debugf(\n\t\t\t\t\t\"Security policy and mode found. Using server endpoint %s for security. Policy %s\",\n\t\t\t\t\tserverEndpoint.EndpointURL,\n\t\t\t\t\tserverEndpoint.SecurityPolicyURI,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\tif serverEndpoint == nil { // Didn't find an endpoint with matching policy and mode.\n\t\treturn nil, &SecurityError{\n\t\t\tPolicy: secPolicy,\n\t\t\tMode:   mode,\n\t\t\tErr:    fmt.Errorf(\"%w: no suitable server endpoint found\", ErrEndpointNotFound),\n\t\t}\n\t}\n\n\tsecPolicy = serverEndpoint.SecurityPolicyURI\n\tsecMode = serverEndpoint.SecurityMode\n\n\t// Check that the selected endpoint is a valid combo\n\terr = validateEndpointConfig(endpoints, secPolicy, secMode, authMode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"endpoint validation failed: %w\", err)\n\t}\n\n\topts = append(opts, opcua.SecurityFromEndpoint(serverEndpoint, authMode))\n\n\t// If a remote certificate is explicitly configured, use it to override\n\t// the certificate from the endpoint. This allows trusting self-signed certificates.\n\tif o.Config.RemoteCertificate != \"\" {\n\t\to.Log.Debugf(\"Using explicitly configured remote certificate from %s\", o.Config.RemoteCertificate)\n\t\topts = append(opts, opcua.RemoteCertificateFile(o.Config.RemoteCertificate))\n\t}\n\n\treturn opts, nil\n}\n\nfunc (o *OpcUAClient) generateAuth(a string, cert []byte, pk *rsa.PrivateKey, user, passwd config.Secret) (ua.UserTokenType, []opcua.Option, error) {\n\tvar authMode ua.UserTokenType\n\tvar authOptions []opcua.Option\n\tswitch strings.ToLower(a) {\n\tcase \"anonymous\":\n\t\tauthMode = ua.UserTokenTypeAnonymous\n\t\tauthOptions = []opcua.Option{opcua.AuthAnonymous()}\n\tcase \"username\":\n\t\tauthMode = ua.UserTokenTypeUserName\n\n\t\tvar username, password []byte\n\t\tif !user.Empty() {\n\t\t\tusecret, err := user.Get()\n\t\t\tif err != nil {\n\t\t\t\treturn 0, nil, &AuthenticationError{\n\t\t\t\t\tMethod: a,\n\t\t\t\t\tErr:    fmt.Errorf(\"error reading username: %w\", err),\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefer usecret.Destroy()\n\t\t\tusername = usecret.Bytes()\n\t\t}\n\n\t\tif !passwd.Empty() {\n\t\t\tpsecret, err := passwd.Get()\n\t\t\tif err != nil {\n\t\t\t\treturn 0, nil, &AuthenticationError{\n\t\t\t\t\tMethod: a,\n\t\t\t\t\tErr:    fmt.Errorf(\"error reading password: %w\", err),\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefer psecret.Destroy()\n\t\t\tpassword = psecret.Bytes()\n\t\t}\n\t\tauthOptions = []opcua.Option{opcua.AuthUsername(string(username), string(password))}\n\tcase \"certificate\":\n\t\tauthMode = ua.UserTokenTypeCertificate\n\t\tauthOptions = []opcua.Option{opcua.AuthCertificate(cert)}\n\t\tif pk != nil {\n\t\t\to.Log.Debug(\"Setting private key for certificate-based user authentication\")\n\t\t\tauthOptions = append(authOptions, opcua.AuthPrivateKey(pk))\n\t\t}\n\tcase \"issuedtoken\":\n\t\t// TODO: this is unsupported, should we fail here or let the opcua package handle it?\n\t\tauthMode = ua.UserTokenTypeIssuedToken\n\t\tauthOptions = []opcua.Option{opcua.AuthIssuedToken([]byte(nil))}\n\tcase \"\":\n\t\t// Default to anonymous when auth method is not specified\n\t\tauthMode = ua.UserTokenTypeAnonymous\n\t\tauthOptions = []opcua.Option{opcua.AuthAnonymous()}\n\tdefault:\n\t\to.Log.Warnf(\"unknown auth method %q, defaulting to Anonymous\", a)\n\t\tauthMode = ua.UserTokenTypeAnonymous\n\t\tauthOptions = []opcua.Option{opcua.AuthAnonymous()}\n\t}\n\n\treturn authMode, authOptions, nil\n}\n\nfunc validateEndpointConfig(endpoints []*ua.EndpointDescription, secPolicy string, secMode ua.MessageSecurityMode, authMode ua.UserTokenType) error {\n\tfor _, e := range endpoints {\n\t\tif e.SecurityMode == secMode && e.SecurityPolicyURI == secPolicy {\n\t\t\tfor _, t := range e.UserIdentityTokens {\n\t\t\t\tif t.TokenType == authMode {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &SecurityError{\n\t\tPolicy: secPolicy,\n\t\tMode:   secMode.String(),\n\t\tErr:    fmt.Errorf(\"%w: server does not support the specified security configuration\", ErrEndpointNotFound),\n\t}\n}\n"
  },
  {
    "path": "plugins/common/opcua/opcua_util_test.go",
    "content": "package opcua\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGenerateCertEmptyPaths(t *testing.T) {\n\t// Case 1: Both paths empty - should generate in temp directory\n\tcertPath, keyPath, err := generateCert(\"urn:test:client\", 2048, \"\", \"\", 24*365*3600)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, certPath)\n\trequire.NotEmpty(t, keyPath)\n\n\t// Verify files were created\n\trequire.FileExists(t, certPath)\n\trequire.FileExists(t, keyPath)\n\n\t// Verify they're in a temp directory (check they start with /tmp or similar)\n\trequire.True(t, filepath.IsAbs(certPath))\n\trequire.True(t, filepath.IsAbs(keyPath))\n}\n\nfunc TestGenerateCertPersistentPaths(t *testing.T) {\n\t// Case 2: Both paths specified but files don't exist - should generate at specified paths\n\ttmpDir := t.TempDir()\n\tcertPath := filepath.Join(tmpDir, \"cert.pem\")\n\tkeyPath := filepath.Join(tmpDir, \"key.pem\")\n\n\t// Verify files don't exist yet\n\trequire.NoFileExists(t, certPath)\n\trequire.NoFileExists(t, keyPath)\n\n\t// Generate certificates\n\treturnedCertPath, returnedKeyPath, err := generateCert(\"urn:test:client\", 2048, certPath, keyPath, 24*365*3600)\n\trequire.NoError(t, err)\n\trequire.Equal(t, certPath, returnedCertPath)\n\trequire.Equal(t, keyPath, returnedKeyPath)\n\n\t// Verify files were created at specified paths\n\trequire.FileExists(t, certPath)\n\trequire.FileExists(t, keyPath)\n\n\t// Verify file permissions (key should be 0600)\n\t// Skip permission check on Windows as Unix-style permissions don't apply\n\tif runtime.GOOS != \"windows\" {\n\t\tinfo, err := os.Stat(keyPath)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, os.FileMode(0600), info.Mode().Perm())\n\t}\n}\n\nfunc TestGenerateCertCreatesParentDirectory(t *testing.T) {\n\t// Parent directory doesn't exist - should be created by os.MkdirAll\n\ttmpDir := t.TempDir()\n\tparentDir := filepath.Join(tmpDir, \"new\", \"nested\", \"dir\")\n\tcertPath := filepath.Join(parentDir, \"cert.pem\")\n\tkeyPath := filepath.Join(parentDir, \"key.pem\")\n\n\tcertPathResult, keyPathResult, err := generateCert(\"urn:test:client\", 2048, certPath, keyPath, 24*365*3600)\n\trequire.NoError(t, err)\n\trequire.Equal(t, certPath, certPathResult)\n\trequire.Equal(t, keyPath, keyPathResult)\n\n\t// Verify files were created\n\trequire.FileExists(t, certPath)\n\trequire.FileExists(t, keyPath)\n\n\t// Verify parent directory was created\n\tinfo, err := os.Stat(parentDir)\n\trequire.NoError(t, err)\n\trequire.True(t, info.IsDir())\n}\n\nfunc TestGenerateCertMissingHost(t *testing.T) {\n\ttmpDir := t.TempDir()\n\tcertPath := filepath.Join(tmpDir, \"cert.pem\")\n\tkeyPath := filepath.Join(tmpDir, \"key.pem\")\n\n\t_, _, err := generateCert(\"\", 2048, certPath, keyPath, 24*365*3600)\n\trequire.ErrorIs(t, err, ErrCertificateGeneration)\n}\n\nfunc TestGenerateCertDifferentKeySize(t *testing.T) {\n\t// Test with different RSA key size to validate rsaBits parameter\n\ttmpDir := t.TempDir()\n\tcertPath := filepath.Join(tmpDir, \"cert.pem\")\n\tkeyPath := filepath.Join(tmpDir, \"key.pem\")\n\n\t// Use 4096 bit RSA key instead of default 2048\n\treturnedCertPath, returnedKeyPath, err := generateCert(\"urn:test:client\", 4096, certPath, keyPath, 24*365*3600)\n\trequire.NoError(t, err)\n\trequire.Equal(t, certPath, returnedCertPath)\n\trequire.Equal(t, keyPath, returnedKeyPath)\n\n\t// Verify files were created\n\trequire.FileExists(t, certPath)\n\trequire.FileExists(t, keyPath)\n}\n"
  },
  {
    "path": "plugins/common/parallel/ordered.go",
    "content": "package parallel\n\nimport (\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Ordered struct {\n\twg sync.WaitGroup\n\tfn func(telegraf.Metric) []telegraf.Metric\n\n\t// queue of jobs coming in. Workers pick jobs off this queue for processing\n\tworkerQueue chan job\n\n\t// queue of ordered metrics going out\n\tqueue chan futureMetric\n}\n\nfunc NewOrdered(acc telegraf.Accumulator, fn func(telegraf.Metric) []telegraf.Metric, orderedQueueSize, workerCount int) *Ordered {\n\tp := &Ordered{\n\t\tfn:          fn,\n\t\tworkerQueue: make(chan job, workerCount),\n\t\tqueue:       make(chan futureMetric, orderedQueueSize),\n\t}\n\tp.startWorkers(workerCount)\n\tp.wg.Add(1)\n\tgo func() {\n\t\tp.readQueue(acc)\n\t\tp.wg.Done()\n\t}()\n\treturn p\n}\n\nfunc (p *Ordered) Enqueue(metric telegraf.Metric) {\n\tfuture := make(futureMetric)\n\tp.queue <- future\n\n\t// write the future to the worker pool. Order doesn't matter now because the\n\t// outgoing p.queue will enforce order regardless of the order the jobs are\n\t// completed in\n\tp.workerQueue <- job{\n\t\tfuture: future,\n\t\tmetric: metric,\n\t}\n}\n\nfunc (p *Ordered) readQueue(acc telegraf.Accumulator) {\n\t// wait for the response from each worker in order\n\tfor mCh := range p.queue {\n\t\t// allow each worker to write out multiple metrics\n\t\tfor metrics := range mCh {\n\t\t\tfor _, m := range metrics {\n\t\t\t\tacc.AddMetric(m)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *Ordered) startWorkers(count int) {\n\tp.wg.Add(count)\n\tfor i := 0; i < count; i++ {\n\t\tgo func() {\n\t\t\tfor job := range p.workerQueue {\n\t\t\t\tjob.future <- p.fn(job.metric)\n\t\t\t\tclose(job.future)\n\t\t\t}\n\t\t\tp.wg.Done()\n\t\t}()\n\t}\n}\n\nfunc (p *Ordered) Stop() {\n\tclose(p.queue)\n\tclose(p.workerQueue)\n\tp.wg.Wait()\n}\n\ntype futureMetric chan []telegraf.Metric\n\ntype job struct {\n\tfuture futureMetric\n\tmetric telegraf.Metric\n}\n"
  },
  {
    "path": "plugins/common/parallel/parallel.go",
    "content": "package parallel\n\nimport \"github.com/influxdata/telegraf\"\n\ntype Parallel interface {\n\tEnqueue(telegraf.Metric)\n\tStop()\n}\n"
  },
  {
    "path": "plugins/common/parallel/parallel_test.go",
    "content": "package parallel_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/parallel\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestOrderedJobsStayOrdered(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\n\tp := parallel.NewOrdered(acc, jobFunc, 10000, 10)\n\tnow := time.Now()\n\tfor i := 0; i < 20000; i++ {\n\t\tm := metric.New(\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"val\": i,\n\t\t\t},\n\t\t\tnow,\n\t\t)\n\t\tnow = now.Add(1)\n\t\tp.Enqueue(m)\n\t}\n\tp.Stop()\n\n\ti := 0\n\trequire.Len(t, acc.Metrics, 20000)\n\tfor _, m := range acc.GetTelegrafMetrics() {\n\t\tv, ok := m.GetField(\"val\")\n\t\trequire.True(t, ok)\n\t\trequire.EqualValues(t, i, v)\n\t\ti++\n\t}\n}\n\nfunc TestUnorderedJobsDontDropAnyJobs(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\n\tp := parallel.NewUnordered(acc, jobFunc, 10)\n\n\tnow := time.Now()\n\n\texpectedTotal := 0\n\tfor i := 0; i < 20000; i++ {\n\t\texpectedTotal += i\n\t\tm := metric.New(\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"val\": i,\n\t\t\t},\n\t\t\tnow,\n\t\t)\n\t\tnow = now.Add(1)\n\t\tp.Enqueue(m)\n\t}\n\tp.Stop()\n\n\tactualTotal := int64(0)\n\trequire.Len(t, acc.Metrics, 20000)\n\tfor _, m := range acc.GetTelegrafMetrics() {\n\t\tv, ok := m.GetField(\"val\")\n\t\trequire.True(t, ok)\n\t\tactualTotal += v.(int64)\n\t}\n\trequire.EqualValues(t, expectedTotal, actualTotal)\n}\n\nfunc BenchmarkOrdered(b *testing.B) {\n\tacc := &testutil.Accumulator{}\n\n\tp := parallel.NewOrdered(acc, jobFunc, 10000, 10)\n\n\tm := metric.New(\"test\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"val\": 1,\n\t\t},\n\t\ttime.Now(),\n\t)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tp.Enqueue(m)\n\t}\n\tp.Stop()\n}\n\nfunc BenchmarkUnordered(b *testing.B) {\n\tacc := &testutil.Accumulator{}\n\n\tp := parallel.NewUnordered(acc, jobFunc, 10)\n\n\tm := metric.New(\"test\",\n\t\tmap[string]string{},\n\t\tmap[string]interface{}{\n\t\t\t\"val\": 1,\n\t\t},\n\t\ttime.Now(),\n\t)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tp.Enqueue(m)\n\t}\n\tp.Stop()\n}\n\nfunc jobFunc(m telegraf.Metric) []telegraf.Metric {\n\treturn []telegraf.Metric{m}\n}\n"
  },
  {
    "path": "plugins/common/parallel/unordered.go",
    "content": "package parallel\n\nimport (\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Unordered struct {\n\twg      sync.WaitGroup\n\tacc     telegraf.Accumulator\n\tfn      func(telegraf.Metric) []telegraf.Metric\n\tinQueue chan telegraf.Metric\n}\n\nfunc NewUnordered(\n\tacc telegraf.Accumulator,\n\tfn func(telegraf.Metric) []telegraf.Metric,\n\tworkerCount int,\n) *Unordered {\n\tp := &Unordered{\n\t\tacc:     acc,\n\t\tinQueue: make(chan telegraf.Metric, workerCount),\n\t\tfn:      fn,\n\t}\n\n\t// start workers\n\tp.wg.Add(1)\n\tgo func() {\n\t\tp.startWorkers(workerCount)\n\t\tp.wg.Done()\n\t}()\n\n\treturn p\n}\n\nfunc (p *Unordered) startWorkers(count int) {\n\twg := sync.WaitGroup{}\n\twg.Add(count)\n\tfor i := 0; i < count; i++ {\n\t\tgo func() {\n\t\t\tfor metric := range p.inQueue {\n\t\t\t\tfor _, m := range p.fn(metric) {\n\t\t\t\t\tp.acc.AddMetric(m)\n\t\t\t\t}\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\twg.Wait()\n}\n\nfunc (p *Unordered) Stop() {\n\tclose(p.inQueue)\n\tp.wg.Wait()\n}\n\nfunc (p *Unordered) Enqueue(m telegraf.Metric) {\n\tp.inQueue <- m\n}\n"
  },
  {
    "path": "plugins/common/postgresql/config.go",
    "content": "package postgresql\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jackc/pgx/v4\"\n\t\"github.com/jackc/pgx/v4/stdlib\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\nvar socketRegexp = regexp.MustCompile(`/\\.s\\.PGSQL\\.\\d+$`)\nvar sanitizer = regexp.MustCompile(`(\\s|^)((?:password|sslcert|sslkey|sslmode|sslrootcert)\\s?=\\s?(?:(?:'(?:[^'\\\\]|\\\\.)*')|(?:\\S+)))`)\n\ntype Config struct {\n\tAddress       config.Secret   `toml:\"address\"`\n\tOutputAddress string          `toml:\"outputaddress\"`\n\tMaxIdle       int             `toml:\"max_idle\"`\n\tMaxOpen       int             `toml:\"max_open\"`\n\tMaxLifetime   config.Duration `toml:\"max_lifetime\"`\n\tIsPgBouncer   bool            `toml:\"-\"`\n}\n\nfunc (c *Config) CreateService() (*Service, error) {\n\taddrSecret, err := c.Address.Get()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting address failed: %w\", err)\n\t}\n\taddr := addrSecret.String()\n\tdefer addrSecret.Destroy()\n\n\tif c.Address.Empty() || addr == \"localhost\" {\n\t\taddr = \"host=localhost sslmode=disable\"\n\t\tif err := c.Address.Set([]byte(addr)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tconnConfig, err := pgx.ParseConfig(addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Remove the socket name from the path\n\tconnConfig.Host = socketRegexp.ReplaceAllLiteralString(connConfig.Host, \"\")\n\n\t// Specific support to make it work with PgBouncer too\n\t// See https://github.com/influxdata/telegraf/issues/3253#issuecomment-357505343\n\tif c.IsPgBouncer {\n\t\t// Remove DriveConfig and revert it by the ParseConfig method\n\t\t// See https://github.com/influxdata/telegraf/issues/9134\n\t\tconnConfig.PreferSimpleProtocol = true\n\t}\n\n\t// Provide the connection string without sensitive information for use as\n\t// tag or other output properties\n\tsanitizedAddr, err := c.sanitizedAddress()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Service{\n\t\tSanitizedAddress:   sanitizedAddr,\n\t\tConnectionDatabase: connectionDatabase(sanitizedAddr),\n\t\tmaxIdle:            c.MaxIdle,\n\t\tmaxOpen:            c.MaxOpen,\n\t\tmaxLifetime:        time.Duration(c.MaxLifetime),\n\t\tdsn:                stdlib.RegisterConnConfig(connConfig),\n\t}, nil\n}\n\n// connectionDatabase determines the database to which the connection was made\nfunc connectionDatabase(sanitizedAddr string) string {\n\tconnConfig, err := pgx.ParseConfig(sanitizedAddr)\n\tif err != nil || connConfig.Database == \"\" {\n\t\treturn \"postgres\"\n\t}\n\n\treturn connConfig.Database\n}\n\n// sanitizedAddress strips sensitive information from the connection string.\n// If the user set the output address use that before parsing anything else.\nfunc (c *Config) sanitizedAddress() (string, error) {\n\tif c.OutputAddress != \"\" {\n\t\treturn c.OutputAddress, nil\n\t}\n\n\t// Get the address\n\taddrSecret, err := c.Address.Get()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting address for sanitization failed: %w\", err)\n\t}\n\tdefer addrSecret.Destroy()\n\n\t// Make sure we convert URI-formatted strings into key-values\n\taddr := addrSecret.TemporaryString()\n\tif strings.HasPrefix(addr, \"postgres://\") || strings.HasPrefix(addr, \"postgresql://\") {\n\t\tif addr, err = toKeyValue(addr); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\t// Sanitize the string using a regular expression\n\tsanitized := sanitizer.ReplaceAllString(addr, \"\")\n\treturn strings.TrimSpace(sanitized), nil\n}\n\n// Based on parseURLSettings() at https://github.com/jackc/pgx/blob/master/pgconn/config.go\nfunc toKeyValue(uri string) (string, error) {\n\tu, err := url.Parse(uri)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"parsing URI failed: %w\", err)\n\t}\n\n\t// Check the protocol\n\tif u.Scheme != \"postgres\" && u.Scheme != \"postgresql\" {\n\t\treturn \"\", fmt.Errorf(\"invalid connection protocol: %s\", u.Scheme)\n\t}\n\n\tquoteIfNecessary := func(v string) string {\n\t\tif !strings.ContainsAny(v, ` ='\\`) {\n\t\t\treturn v\n\t\t}\n\t\tr := strings.ReplaceAll(v, `\\`, `\\\\`)\n\t\tr = strings.ReplaceAll(r, `'`, `\\'`)\n\t\treturn \"'\" + r + \"'\"\n\t}\n\n\t// Extract the parameters\n\tparts := make([]string, 0, len(u.Query())+5)\n\tif u.User != nil {\n\t\tparts = append(parts, \"user=\"+quoteIfNecessary(u.User.Username()))\n\t\tif password, found := u.User.Password(); found {\n\t\t\tparts = append(parts, \"password=\"+quoteIfNecessary(password))\n\t\t}\n\t}\n\n\t// Handle multiple host:port's in url.Host by splitting them into host,host,host and port,port,port.\n\thostParts := strings.Split(u.Host, \",\")\n\thosts := make([]string, 0, len(hostParts))\n\tports := make([]string, 0, len(hostParts))\n\tvar anyPortSet bool\n\tfor _, host := range hostParts {\n\t\tif host == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\th, p, err := net.SplitHostPort(host)\n\t\tif err != nil {\n\t\t\tif !strings.Contains(err.Error(), \"missing port\") {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to process host %q: %w\", host, err)\n\t\t\t}\n\t\t\th = host\n\t\t}\n\t\tanyPortSet = anyPortSet || err == nil\n\t\thosts = append(hosts, h)\n\t\tports = append(ports, p)\n\t}\n\tif len(hosts) > 0 {\n\t\tparts = append(parts, \"host=\"+strings.Join(hosts, \",\"))\n\t}\n\tif anyPortSet {\n\t\tparts = append(parts, \"port=\"+strings.Join(ports, \",\"))\n\t}\n\n\tdatabase := strings.TrimLeft(u.Path, \"/\")\n\tif database != \"\" {\n\t\tparts = append(parts, \"dbname=\"+quoteIfNecessary(database))\n\t}\n\n\tfor k, v := range u.Query() {\n\t\tparts = append(parts, k+\"=\"+quoteIfNecessary(strings.Join(v, \",\")))\n\t}\n\n\t// Required to produce a repeatable output e.g. for tags or testing\n\tsort.Strings(parts)\n\treturn strings.Join(parts, \" \"), nil\n}\n"
  },
  {
    "path": "plugins/common/postgresql/config_test.go",
    "content": "package postgresql\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\nfunc TestURIParsing(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\turi      string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"short\",\n\t\t\turi:      `postgres://localhost`,\n\t\t\texpected: \"host=localhost\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with port\",\n\t\t\turi:      `postgres://localhost:5432`,\n\t\t\texpected: \"host=localhost port=5432\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with database\",\n\t\t\turi:      `postgres://localhost/mydb`,\n\t\t\texpected: \"dbname=mydb host=localhost\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with additional parameters\",\n\t\t\turi:      `postgres://localhost/mydb?application_name=pgxtest&search_path=myschema&connect_timeout=5`,\n\t\t\texpected: \"application_name=pgxtest connect_timeout=5 dbname=mydb host=localhost search_path=myschema\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with database setting in params\",\n\t\t\turi:      `postgres://localhost:5432/?database=mydb`,\n\t\t\texpected: \"database=mydb host=localhost port=5432\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with authentication\",\n\t\t\turi:      `postgres://jack:secret@localhost:5432/mydb?sslmode=prefer`,\n\t\t\texpected: \"dbname=mydb host=localhost password=secret port=5432 sslmode=prefer user=jack\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with spaces\",\n\t\t\turi:      `postgres://jack%20hunter:secret@localhost/mydb?application_name=pgx%20test`,\n\t\t\texpected: \"application_name='pgx test' dbname=mydb host=localhost password=secret user='jack hunter'\",\n\t\t},\n\t\t{\n\t\t\tname:     \"with equal signs\",\n\t\t\turi:      `postgres://jack%20hunter:secret@localhost/mydb?application_name=pgx%3Dtest`,\n\t\t\texpected: \"application_name='pgx=test' dbname=mydb host=localhost password=secret user='jack hunter'\",\n\t\t},\n\t\t{\n\t\t\tname:     \"multiple hosts\",\n\t\t\turi:      `postgres://jack:secret@foo:1,bar:2,baz:3/mydb?sslmode=disable`,\n\t\t\texpected: \"dbname=mydb host=foo,bar,baz password=secret port=1,2,3 sslmode=disable user=jack\",\n\t\t},\n\t\t{\n\t\t\tname:     \"multiple hosts without ports\",\n\t\t\turi:      `postgres://jack:secret@foo,bar,baz/mydb?sslmode=disable`,\n\t\t\texpected: \"dbname=mydb host=foo,bar,baz password=secret sslmode=disable user=jack\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\t// Key value without spaces around equal sign\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := toKeyValue(tt.uri)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equalf(t, tt.expected, actual, \"initial: %s\", tt.uri)\n\t\t})\n\t}\n}\n\nfunc TestSanitizeAddressKeyValue(t *testing.T) {\n\tkeys := []string{\"password\", \"sslcert\", \"sslkey\", \"sslmode\", \"sslrootcert\"}\n\ttests := []struct {\n\t\tname  string\n\t\tvalue string\n\t}{\n\t\t{\n\t\t\tname:  \"simple text\",\n\t\t\tvalue: `foo`,\n\t\t},\n\t\t{\n\t\t\tname:  \"empty values\",\n\t\t\tvalue: `''`,\n\t\t},\n\t\t{\n\t\t\tname:  \"space in value\",\n\t\t\tvalue: `'foo bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"equal sign in value\",\n\t\t\tvalue: `'foo=bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"escaped quote\",\n\t\t\tvalue: `'foo\\'s bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"escaped quote no space\",\n\t\t\tvalue: `\\'foobar\\'s\\'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"escaped backslash\",\n\t\t\tvalue: `'foo bar\\\\'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"escaped quote and backslash\",\n\t\t\tvalue: `'foo\\\\\\'s bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"two escaped backslashes\",\n\t\t\tvalue: `'foo bar\\\\\\\\'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"multiple inline spaces\",\n\t\t\tvalue: \"'foo     \\t bar'\",\n\t\t},\n\t\t{\n\t\t\tname:  \"leading space\",\n\t\t\tvalue: `' foo bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"trailing space\",\n\t\t\tvalue: `'foo bar '`,\n\t\t},\n\t\t{\n\t\t\tname:  \"multiple equal signs\",\n\t\t\tvalue: `'foo===bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"leading equal sign\",\n\t\t\tvalue: `'=foo bar'`,\n\t\t},\n\t\t{\n\t\t\tname:  \"trailing equal sign\",\n\t\t\tvalue: `'foo bar='`,\n\t\t},\n\t\t{\n\t\t\tname:  \"mix of equal signs and spaces\",\n\t\t\tvalue: \"'foo = a\\t===\\tbar'\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\t// Key value without spaces around equal sign\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Generate the DSN from the given keys and value\n\t\t\tparts := make([]string, 0, len(keys))\n\t\t\tfor _, k := range keys {\n\t\t\t\tparts = append(parts, k+\"=\"+tt.value)\n\t\t\t}\n\t\t\tdsn := strings.Join(parts, \" canary=ok \")\n\n\t\t\tcfg := &Config{\n\t\t\t\tAddress: config.NewSecret([]byte(dsn)),\n\t\t\t}\n\n\t\t\texpected := strings.Join(make([]string, len(keys)), \"canary=ok \")\n\t\t\texpected = strings.TrimSpace(expected)\n\t\t\tactual, err := cfg.sanitizedAddress()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equalf(t, expected, actual, \"initial: %s\", dsn)\n\t\t})\n\n\t\t// Key value with spaces around equal sign\n\t\tt.Run(\"spaced \"+tt.name, func(t *testing.T) {\n\t\t\t// Generate the DSN from the given keys and value\n\t\t\tparts := make([]string, 0, len(keys))\n\t\t\tfor _, k := range keys {\n\t\t\t\tparts = append(parts, k+\" = \"+tt.value)\n\t\t\t}\n\t\t\tdsn := strings.Join(parts, \" canary=ok \")\n\n\t\t\tcfg := &Config{\n\t\t\t\tAddress: config.NewSecret([]byte(dsn)),\n\t\t\t}\n\n\t\t\texpected := strings.Join(make([]string, len(keys)), \"canary=ok \")\n\t\t\texpected = strings.TrimSpace(expected)\n\t\t\tactual, err := cfg.sanitizedAddress()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equalf(t, expected, actual, \"initial: %s\", dsn)\n\t\t})\n\t}\n}\n\nfunc TestSanitizeAddressURI(t *testing.T) {\n\tkeys := []string{\"password\", \"sslcert\", \"sslkey\", \"sslmode\", \"sslrootcert\"}\n\ttests := []struct {\n\t\tname  string\n\t\tvalue string\n\t}{\n\t\t{\n\t\t\tname:  \"simple text\",\n\t\t\tvalue: `foo`,\n\t\t},\n\t\t{\n\t\t\tname:  \"empty values\",\n\t\t\tvalue: ``,\n\t\t},\n\t\t{\n\t\t\tname:  \"space in value\",\n\t\t\tvalue: `foo bar`,\n\t\t},\n\t\t{\n\t\t\tname:  \"equal sign in value\",\n\t\t\tvalue: `foo=bar`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Generate the DSN from the given keys and value\n\t\t\tvalue := strings.ReplaceAll(tt.value, \"=\", \"%3D\")\n\t\t\tvalue = strings.ReplaceAll(value, \" \", \"%20\")\n\t\t\tparts := make([]string, 0, len(keys))\n\t\t\tfor _, k := range keys {\n\t\t\t\tparts = append(parts, k+\"=\"+value)\n\t\t\t}\n\t\t\tdsn := \"postgresql://user:passwd@localhost:5432/db?\" + strings.Join(parts, \"&\")\n\n\t\t\tcfg := &Config{\n\t\t\t\tAddress: config.NewSecret([]byte(dsn)),\n\t\t\t}\n\n\t\t\texpected := \"dbname=db host=localhost port=5432 user=user\"\n\t\t\tactual, err := cfg.sanitizedAddress()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equalf(t, expected, actual, \"initial: %s\", dsn)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/postgresql/service.go",
    "content": "package postgresql\n\nimport (\n\t\"database/sql\"\n\t\"time\"\n\n\t// Blank import required to register driver\n\t_ \"github.com/jackc/pgx/v4/stdlib\"\n)\n\n// Service common functionality shared between the postgresql and postgresql_extensible\n// packages.\ntype Service struct {\n\tDB                 *sql.DB\n\tSanitizedAddress   string\n\tConnectionDatabase string\n\n\tdsn         string\n\tmaxIdle     int\n\tmaxOpen     int\n\tmaxLifetime time.Duration\n}\n\nfunc (p *Service) Start() error {\n\tdb, err := sql.Open(\"pgx\", p.dsn)\n\tif err != nil {\n\t\treturn err\n\t}\n\tp.DB = db\n\n\tp.DB.SetMaxOpenConns(p.maxOpen)\n\tp.DB.SetMaxIdleConns(p.maxIdle)\n\tp.DB.SetConnMaxLifetime(p.maxLifetime)\n\n\treturn nil\n}\n\nfunc (p *Service) Stop() {\n\tif p.DB != nil {\n\t\tp.DB.Close()\n\t}\n}\n"
  },
  {
    "path": "plugins/common/proxy/connect.go",
    "content": "package proxy\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/proxy\"\n)\n\n// httpConnectProxy proxies (only?) TCP over a HTTP tunnel using the CONNECT method\ntype httpConnectProxy struct {\n\tforward proxy.Dialer\n\turl     *url.URL\n}\n\nfunc (c *httpConnectProxy) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {\n\t// Prevent using UDP\n\tif network == \"udp\" {\n\t\treturn nil, fmt.Errorf(\"cannot proxy %q traffic over HTTP CONNECT\", network)\n\t}\n\n\tvar proxyConn net.Conn\n\tvar err error\n\tif dialer, ok := c.forward.(proxy.ContextDialer); ok {\n\t\tproxyConn, err = dialer.DialContext(ctx, \"tcp\", c.url.Host)\n\t} else {\n\t\tshim := contextDialerShim{c.forward}\n\t\tproxyConn, err = shim.DialContext(ctx, \"tcp\", c.url.Host)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Add and strip http:// to extract authority portion of the URL\n\t// since CONNECT doesn't use a full URL. The request header would\n\t// look something like: \"CONNECT www.influxdata.com:443 HTTP/1.1\"\n\trequestURL, err := url.Parse(\"http://\" + addr)\n\tif err != nil {\n\t\tif err := proxyConn.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, err\n\t}\n\trequestURL.Scheme = \"\"\n\n\t// Build HTTP CONNECT request\n\treq, err := http.NewRequest(http.MethodConnect, requestURL.String(), nil)\n\tif err != nil {\n\t\tif err := proxyConn.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, err\n\t}\n\treq.Close = false\n\tif password, hasAuth := c.url.User.Password(); hasAuth {\n\t\treq.SetBasicAuth(c.url.User.Username(), password)\n\t}\n\n\terr = req.Write(proxyConn)\n\tif err != nil {\n\t\tif err := proxyConn.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tresp, err := http.ReadResponse(bufio.NewReader(proxyConn), req)\n\tif err != nil {\n\t\tif err := proxyConn.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, err\n\t}\n\tif err := resp.Body.Close(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != 200 {\n\t\tif err := proxyConn.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to connect to proxy: %q\", resp.Status)\n\t}\n\n\treturn proxyConn, nil\n}\n\nfunc (c *httpConnectProxy) Dial(network, addr string) (net.Conn, error) {\n\treturn c.DialContext(context.Background(), network, addr)\n}\n\nfunc newHTTPConnectProxy(proxyURL *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {\n\treturn &httpConnectProxy{forward, proxyURL}, nil\n}\n\nfunc init() {\n\t// Register new proxy types\n\tproxy.RegisterDialerType(\"http\", newHTTPConnectProxy)\n\tproxy.RegisterDialerType(\"https\", newHTTPConnectProxy)\n}\n\n// contextDialerShim allows cancellation of the dial from a context even if the underlying\n// dialer does not implement `proxy.ContextDialer`. Arguably, this shouldn't actually get run,\n// unless a new proxy type is added that doesn't implement `proxy.ContextDialer`, as all the\n// standard library dialers implement `proxy.ContextDialer`.\ntype contextDialerShim struct {\n\tdialer proxy.Dialer\n}\n\nfunc (cd *contextDialerShim) Dial(network, addr string) (net.Conn, error) {\n\treturn cd.dialer.Dial(network, addr)\n}\n\nfunc (cd *contextDialerShim) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {\n\tvar (\n\t\tconn net.Conn\n\t\tdone = make(chan struct{}, 1)\n\t\terr  error\n\t)\n\n\tgo func() {\n\t\tconn, err = cd.dialer.Dial(network, addr)\n\t\tclose(done)\n\t\tif conn != nil && ctx.Err() != nil {\n\t\t\t_ = conn.Close()\n\t\t}\n\t}()\n\n\tselect {\n\tcase <-ctx.Done():\n\t\terr = ctx.Err()\n\tcase <-done:\n\t}\n\n\treturn conn, err\n}\n"
  },
  {
    "path": "plugins/common/proxy/dialer.go",
    "content": "package proxy\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"time\"\n\n\t\"golang.org/x/net/proxy\"\n)\n\ntype ProxiedDialer struct {\n\tdialer proxy.Dialer\n}\n\nfunc (pd *ProxiedDialer) Dial(network, addr string) (net.Conn, error) {\n\treturn pd.dialer.Dial(network, addr)\n}\n\nfunc (pd *ProxiedDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {\n\tif contextDialer, ok := pd.dialer.(proxy.ContextDialer); ok {\n\t\treturn contextDialer.DialContext(ctx, network, addr)\n\t}\n\n\tcontextDialer := contextDialerShim{pd.dialer}\n\treturn contextDialer.DialContext(ctx, network, addr)\n}\n\nfunc (pd *ProxiedDialer) DialTimeout(network, addr string, timeout time.Duration) (net.Conn, error) {\n\tctx := context.Background()\n\tif timeout.Seconds() != 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, timeout)\n\t\tdefer cancel()\n\t}\n\n\treturn pd.DialContext(ctx, network, addr)\n}\n"
  },
  {
    "path": "plugins/common/proxy/proxy.conf",
    "content": "  # use_system_proxy = false\n  # http_proxy_url = \"\""
  },
  {
    "path": "plugins/common/proxy/proxy.go",
    "content": "package proxy\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/proxy\"\n)\n\ntype HTTPProxy struct {\n\tUseSystemProxy bool   `toml:\"use_system_proxy\"`\n\tHTTPProxyURL   string `toml:\"http_proxy_url\"`\n}\n\ntype proxyFunc func(req *http.Request) (*url.URL, error)\n\nfunc (p *HTTPProxy) Proxy() (proxyFunc, error) {\n\tif p.UseSystemProxy {\n\t\treturn http.ProxyFromEnvironment, nil\n\t} else if len(p.HTTPProxyURL) > 0 {\n\t\taddress, err := url.Parse(p.HTTPProxyURL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing proxy url %q: %w\", p.HTTPProxyURL, err)\n\t\t}\n\t\treturn http.ProxyURL(address), nil\n\t}\n\n\treturn nil, nil\n}\n\ntype TCPProxy struct {\n\tUseProxy bool   `toml:\"use_proxy\"`\n\tProxyURL string `toml:\"proxy_url\"`\n}\n\nfunc (p *TCPProxy) Proxy() (*ProxiedDialer, error) {\n\tvar dialer proxy.Dialer\n\tif p.UseProxy {\n\t\tif len(p.ProxyURL) > 0 {\n\t\t\tparsed, err := url.Parse(p.ProxyURL)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error parsing proxy url %q: %w\", p.ProxyURL, err)\n\t\t\t}\n\n\t\t\tif dialer, err = proxy.FromURL(parsed, proxy.Direct); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tdialer = proxy.FromEnvironment()\n\t\t}\n\t} else {\n\t\tdialer = proxy.Direct\n\t}\n\n\treturn &ProxiedDialer{dialer}, nil\n}\n"
  },
  {
    "path": "plugins/common/proxy/socks5.go",
    "content": "package proxy\n\nimport (\n\t\"golang.org/x/net/proxy\"\n)\n\ntype Socks5ProxyConfig struct {\n\tSocks5ProxyEnabled  bool   `toml:\"socks5_enabled\"`\n\tSocks5ProxyAddress  string `toml:\"socks5_address\"`\n\tSocks5ProxyUsername string `toml:\"socks5_username\"`\n\tSocks5ProxyPassword string `toml:\"socks5_password\"`\n}\n\nfunc (c *Socks5ProxyConfig) GetDialer() (proxy.Dialer, error) {\n\tvar auth *proxy.Auth\n\tif c.Socks5ProxyPassword != \"\" || c.Socks5ProxyUsername != \"\" {\n\t\tauth = new(proxy.Auth)\n\t\tauth.User = c.Socks5ProxyUsername\n\t\tauth.Password = c.Socks5ProxyPassword\n\t}\n\treturn proxy.SOCKS5(\"tcp\", c.Socks5ProxyAddress, auth, proxy.Direct)\n}\n"
  },
  {
    "path": "plugins/common/proxy/socks5_test.go",
    "content": "package proxy\n\nimport (\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/armon/go-socks5\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSocks5ProxyConfigIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tconst (\n\t\tproxyAddress  = \"127.0.0.1:12345\"\n\t\tproxyUsername = \"user\"\n\t\tproxyPassword = \"password\"\n\t)\n\n\tl, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tserver, err := socks5.New(&socks5.Config{\n\t\tAuthMethods: []socks5.Authenticator{socks5.UserPassAuthenticator{\n\t\t\tCredentials: socks5.StaticCredentials{\n\t\t\t\tproxyUsername: proxyPassword,\n\t\t\t},\n\t\t}},\n\t})\n\trequire.NoError(t, err)\n\n\tgo func() {\n\t\tif err := server.ListenAndServe(\"tcp\", proxyAddress); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\tconf := Socks5ProxyConfig{\n\t\tSocks5ProxyEnabled:  true,\n\t\tSocks5ProxyAddress:  proxyAddress,\n\t\tSocks5ProxyUsername: proxyUsername,\n\t\tSocks5ProxyPassword: proxyPassword,\n\t}\n\tdialer, err := conf.GetDialer()\n\trequire.NoError(t, err)\n\n\tvar proxyConn net.Conn\n\tfor i := 0; i < 10; i++ {\n\t\tproxyConn, err = dialer.Dial(\"tcp\", l.Addr().String())\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n\trequire.NotNil(t, proxyConn)\n\tdefer func() { require.NoError(t, proxyConn.Close()) }()\n\n\tserverConn, err := l.Accept()\n\trequire.NoError(t, err)\n\tdefer func() { require.NoError(t, serverConn.Close()) }()\n\n\twritePayload := []byte(\"test\")\n\t_, err = proxyConn.Write(writePayload)\n\trequire.NoError(t, err)\n\n\treceivePayload := make([]byte, 4)\n\t_, err = serverConn.Read(receivePayload)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, writePayload, receivePayload)\n}\n"
  },
  {
    "path": "plugins/common/psutil/mock_ps.go",
    "content": "package psutil\n\nimport (\n\t\"os\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\t\"github.com/shirou/gopsutil/v4/mem\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockPS is a mock implementation of the PS interface for testing purposes.\ntype MockPS struct {\n\tmock.Mock\n\tPSDiskDeps\n}\n\n// MockPSDisk is a mock implementation of the PSDiskDeps interface for testing purposes.\ntype MockPSDisk struct {\n\t*SystemPS\n\t*mock.Mock\n}\n\n// MockDiskUsage is a mock implementation for disk usage operations.\ntype MockDiskUsage struct {\n\t*mock.Mock\n}\n\n// CPUTimes returns the CPU times statistics.\nfunc (m *MockPS) CPUTimes(_, _ bool) ([]cpu.TimesStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).([]cpu.TimesStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// DiskUsage returns the disk usage statistics.\nfunc (m *MockPS) DiskUsage(mountPointFilter, mountOptsExclude, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error) {\n\tret := m.Called(mountPointFilter, mountOptsExclude, fstypeExclude)\n\n\tr0 := ret.Get(0).([]*disk.UsageStat)\n\tr1 := ret.Get(1).([]*disk.PartitionStat)\n\tr2 := ret.Error(2)\n\n\treturn r0, r1, r2\n}\n\n// NetIO returns network I/O statistics for every network interface installed on the system.\nfunc (m *MockPS) NetIO() ([]net.IOCountersStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).([]net.IOCountersStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// NetProto returns network statistics for the entire system.\nfunc (m *MockPS) NetProto() ([]net.ProtoCountersStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).([]net.ProtoCountersStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// DiskIO returns the disk I/O statistics.\nfunc (m *MockPS) DiskIO(_ []string) (map[string]disk.IOCountersStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).(map[string]disk.IOCountersStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// VMStat returns the virtual memory statistics.\nfunc (m *MockPS) VMStat() (*mem.VirtualMemoryStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).(*mem.VirtualMemoryStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// SwapStat returns the swap memory statistics.\nfunc (m *MockPS) SwapStat() (*mem.SwapMemoryStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).(*mem.SwapMemoryStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// NetConnections returns a list of network connections opened.\nfunc (m *MockPS) NetConnections() ([]net.ConnectionStat, error) {\n\tret := m.Called()\n\n\tr0 := ret.Get(0).([]net.ConnectionStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// NetConntrack returns more detailed info about the conntrack table.\nfunc (m *MockPS) NetConntrack(perCPU bool) ([]net.ConntrackStat, error) {\n\tret := m.Called(perCPU)\n\n\tr0 := ret.Get(0).([]net.ConntrackStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// Partitions returns the disk partition statistics.\nfunc (m *MockDiskUsage) Partitions(all bool) ([]disk.PartitionStat, error) {\n\tret := m.Called(all)\n\n\tr0 := ret.Get(0).([]disk.PartitionStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// OSGetenv returns the value of the environment variable named by the key.\nfunc (m *MockDiskUsage) OSGetenv(key string) string {\n\tret := m.Called(key)\n\treturn ret.Get(0).(string)\n}\n\n// OSStat returns the FileInfo structure describing the named file.\nfunc (m *MockDiskUsage) OSStat(name string) (os.FileInfo, error) {\n\tret := m.Called(name)\n\n\tr0 := ret.Get(0).(os.FileInfo)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n\n// PSDiskUsage returns a file system usage for the specified path.\nfunc (m *MockDiskUsage) PSDiskUsage(path string) (*disk.UsageStat, error) {\n\tret := m.Called(path)\n\n\tr0 := ret.Get(0).(*disk.UsageStat)\n\tr1 := ret.Error(1)\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "plugins/common/psutil/ps.go",
    "content": "package psutil\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\t\"github.com/shirou/gopsutil/v4/mem\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// PS is an interface that defines methods for gathering system statistics.\ntype PS interface {\n\t// CPUTimes returns the CPU times statistics.\n\tCPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error)\n\t// DiskUsage returns the disk usage statistics.\n\tDiskUsage(mountPointFilter []string, mountOptsExclude []string, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error)\n\t// NetIO returns network I/O statistics for every network interface installed on the system.\n\tNetIO() ([]net.IOCountersStat, error)\n\t// NetProto returns network statistics for the entire system.\n\tNetProto() ([]net.ProtoCountersStat, error)\n\t// DiskIO returns the disk I/O statistics.\n\tDiskIO(names []string) (map[string]disk.IOCountersStat, error)\n\t// VMStat returns the virtual memory statistics.\n\tVMStat() (*mem.VirtualMemoryStat, error)\n\t// SwapStat returns the swap memory statistics.\n\tSwapStat() (*mem.SwapMemoryStat, error)\n\t// NetConnections returns a list of network connections opened.\n\tNetConnections() ([]net.ConnectionStat, error)\n\t// NetConntrack returns more detailed info about the conntrack table.\n\tNetConntrack(perCPU bool) ([]net.ConntrackStat, error)\n}\n\n// PSDiskDeps is an interface that defines methods for gathering disk statistics.\ntype PSDiskDeps interface {\n\t// Partitions returns the disk partition statistics.\n\tPartitions(all bool) ([]disk.PartitionStat, error)\n\t// OSGetenv returns the value of the environment variable named by the key.\n\tOSGetenv(key string) string\n\t// OSStat returns the FileInfo structure describing the named file.\n\tOSStat(name string) (os.FileInfo, error)\n\t// PSDiskUsage returns a file system usage for the specified path.\n\tPSDiskUsage(path string) (*disk.UsageStat, error)\n}\n\n// SystemPS is a struct that implements the PS interface.\ntype SystemPS struct {\n\tPSDiskDeps\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\n// SystemPSDisk is a struct that implements the PSDiskDeps interface.\ntype SystemPSDisk struct{}\n\n// NewSystemPS creates a new instance of SystemPS.\nfunc NewSystemPS() *SystemPS {\n\treturn &SystemPS{PSDiskDeps: &SystemPSDisk{}}\n}\n\n// CPUTimes returns the CPU times statistics.\nfunc (*SystemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error) {\n\tvar cpuTimes []cpu.TimesStat\n\tif perCPU {\n\t\tperCPUTimes, err := cpu.Times(true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcpuTimes = append(cpuTimes, perCPUTimes...)\n\t}\n\tif totalCPU {\n\t\ttotalCPUTimes, err := cpu.Times(false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcpuTimes = append(cpuTimes, totalCPUTimes...)\n\t}\n\treturn cpuTimes, nil\n}\n\n// DiskUsage returns the disk usage statistics.\nfunc (s *SystemPS) DiskUsage(mountPointFilter, mountOptsExclude, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error) {\n\tparts, err := s.Partitions(true)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tmountPointFilterSet := newSet()\n\tfor _, filter := range mountPointFilter {\n\t\tmountPointFilterSet.add(filter)\n\t}\n\tmountOptFilterSet := newSet()\n\tfor _, filter := range mountOptsExclude {\n\t\tmountOptFilterSet.add(filter)\n\t}\n\tfstypeExcludeSet := newSet()\n\tfor _, filter := range fstypeExclude {\n\t\tfstypeExcludeSet.add(filter)\n\t}\n\tpaths := newSet()\n\tfor _, part := range parts {\n\t\tpaths.add(part.Mountpoint)\n\t}\n\n\t// Autofs mounts indicate a potential mount, the partition will also be\n\t// listed with the actual filesystem when mounted.  Ignore the autofs\n\t// partition to avoid triggering a mount.\n\tfstypeExcludeSet.add(\"autofs\")\n\n\tusage := make([]*disk.UsageStat, 0, len(parts))\n\tpartitions := make([]*disk.PartitionStat, 0, len(parts))\n\thostMountPrefix := s.OSGetenv(\"HOST_MOUNT_PREFIX\")\n\npartitionRange:\n\tfor i := range parts {\n\t\tp := parts[i]\n\n\t\tfor _, o := range p.Opts {\n\t\t\tif !mountOptFilterSet.empty() && mountOptFilterSet.has(o) {\n\t\t\t\tcontinue partitionRange\n\t\t\t}\n\t\t}\n\t\t// If there is a filter set and if the mount point is not a\n\t\t// member of the filter set, don't gather info on it.\n\t\tif !mountPointFilterSet.empty() && !mountPointFilterSet.has(p.Mountpoint) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the mount point is a member of the exclude set,\n\t\t// don't gather info on it.\n\t\tif fstypeExcludeSet.has(p.Fstype) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If there's a host mount prefix use it as newer gopsutil version check for\n\t\t// the init's mountpoints usually pointing to the host-mountpoint but in the\n\t\t// container. This won't work for checking the disk-usage as the disks are\n\t\t// mounted at HOST_MOUNT_PREFIX...\n\t\tmountpoint := p.Mountpoint\n\t\tif hostMountPrefix != \"\" && !strings.HasPrefix(p.Mountpoint, hostMountPrefix) {\n\t\t\tmountpoint = filepath.Join(hostMountPrefix, p.Mountpoint)\n\t\t\t// Exclude conflicting paths\n\t\t\tif paths.has(mountpoint) {\n\t\t\t\tif s.Log != nil {\n\t\t\t\t\ts.Log.Debugf(\"[SystemPS] => dropped by mount prefix (%q): %q\", mountpoint, hostMountPrefix)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tdu, err := s.PSDiskUsage(mountpoint)\n\t\tif err != nil {\n\t\t\tif s.Log != nil {\n\t\t\t\ts.Log.Debugf(\"[SystemPS] => unable to get disk usage (%q): %v\", mountpoint, err)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tdu.Path = filepath.Join(string(os.PathSeparator), strings.TrimPrefix(p.Mountpoint, hostMountPrefix))\n\t\tdu.Fstype = p.Fstype\n\t\tusage = append(usage, du)\n\t\tpartitions = append(partitions, &p)\n\t}\n\n\treturn usage, partitions, nil\n}\n\n// NetProto returns network statistics for the entire system.\nfunc (*SystemPS) NetProto() ([]net.ProtoCountersStat, error) {\n\treturn net.ProtoCounters(nil)\n}\n\n// NetIO returns network I/O statistics for every network interface installed on the system.\nfunc (*SystemPS) NetIO() ([]net.IOCountersStat, error) {\n\treturn net.IOCounters(true)\n}\n\n// NetConnections returns a list of network connections opened.\nfunc (*SystemPS) NetConnections() ([]net.ConnectionStat, error) {\n\treturn net.Connections(\"all\")\n}\n\n// NetConntrack returns more detailed info about the conntrack table.\nfunc (*SystemPS) NetConntrack(perCPU bool) ([]net.ConntrackStat, error) {\n\treturn net.ConntrackStats(perCPU)\n}\n\n// DiskIO returns the disk I/O statistics.\nfunc (*SystemPS) DiskIO(names []string) (map[string]disk.IOCountersStat, error) {\n\tm, err := disk.IOCounters(names...)\n\tif errors.Is(err, internal.ErrNotImplemented) {\n\t\treturn nil, nil\n\t}\n\n\treturn m, err\n}\n\n// VMStat returns the virtual memory statistics.\nfunc (*SystemPS) VMStat() (*mem.VirtualMemoryStat, error) {\n\treturn mem.VirtualMemory()\n}\n\n// SwapStat returns the swap memory statistics.\nfunc (*SystemPS) SwapStat() (*mem.SwapMemoryStat, error) {\n\treturn mem.SwapMemory()\n}\n\n// Partitions returns the disk partition statistics.\nfunc (*SystemPSDisk) Partitions(all bool) ([]disk.PartitionStat, error) {\n\treturn disk.Partitions(all)\n}\n\n// OSGetenv returns the value of the environment variable named by the key.\nfunc (*SystemPSDisk) OSGetenv(key string) string {\n\treturn os.Getenv(key)\n}\n\n// OSStat returns the FileInfo structure describing the named file.\nfunc (*SystemPSDisk) OSStat(name string) (os.FileInfo, error) {\n\treturn os.Stat(name)\n}\n\n// PSDiskUsage returns a file system usage for the specified path.\nfunc (*SystemPSDisk) PSDiskUsage(path string) (*disk.UsageStat, error) {\n\treturn disk.Usage(path)\n}\n\ntype set struct {\n\tm map[string]struct{}\n}\n\nfunc (s *set) empty() bool {\n\treturn len(s.m) == 0\n}\n\nfunc (s *set) add(key string) {\n\ts.m[key] = struct{}{}\n}\n\nfunc (s *set) has(key string) bool {\n\tvar ok bool\n\t_, ok = s.m[key]\n\treturn ok\n}\n\nfunc newSet() *set {\n\ts := &set{\n\t\tm: make(map[string]struct{}),\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "plugins/common/ratelimiter/config.go",
    "content": "package ratelimiter\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype RateLimitConfig struct {\n\tLimit  config.Size     `toml:\"rate_limit\"`\n\tPeriod config.Duration `toml:\"rate_limit_period\"`\n}\n\nfunc (cfg *RateLimitConfig) CreateRateLimiter() (*RateLimiter, error) {\n\tif cfg.Limit > 0 && cfg.Period <= 0 {\n\t\treturn nil, errors.New(\"invalid period for rate-limit\")\n\t}\n\treturn &RateLimiter{\n\t\tlimit:  int64(cfg.Limit),\n\t\tperiod: time.Duration(cfg.Period),\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/common/ratelimiter/limiters.go",
    "content": "package ratelimiter\n\nimport (\n\t\"errors\"\n\t\"math\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\tErrLimitExceeded = errors.New(\"not enough tokens\")\n)\n\ntype RateLimiter struct {\n\tlimit       int64\n\tperiod      time.Duration\n\tperiodStart time.Time\n\n\tremaining int64\n\treserved  int64\n\n\tsync.Mutex\n}\n\nfunc (r *RateLimiter) Remaining(t time.Time) int64 {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tif r.limit == 0 {\n\t\treturn math.MaxInt64\n\t}\n\n\t// Check for corner case\n\tif !r.periodStart.Before(t) {\n\t\treturn 0\n\t}\n\n\t// We are in a new period, so the complete size is available\n\tdeltat := t.Sub(r.periodStart)\n\tif deltat >= r.period {\n\t\treturn r.limit\n\t}\n\n\treturn r.remaining - r.reserved\n}\n\nfunc (r *RateLimiter) Reserve(used int64) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tr.reserved = max(r.reserved+used, used)\n}\n\nfunc (r *RateLimiter) Release() {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tr.reserved = 0\n}\n\nfunc (r *RateLimiter) Accept(t time.Time, used int64) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tif r.limit == 0 || r.periodStart.After(t) {\n\t\treturn\n\t}\n\n\t// Remember the first query and reset if we are in a new period\n\tif r.periodStart.IsZero() {\n\t\tr.periodStart = t\n\t\tr.remaining = r.limit\n\t} else if deltat := t.Sub(r.periodStart); deltat >= r.period {\n\t\tr.periodStart = r.periodStart.Add(deltat.Truncate(r.period))\n\t\tr.remaining = r.limit\n\t}\n\n\t// Update the state\n\tr.remaining = max(r.remaining-used, 0)\n\tr.reserved = max(r.reserved-used, 0)\n}\n\nfunc (r *RateLimiter) Undo(t time.Time, used int64) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\t// Do nothing if we are not in the current period or unlimited because we\n\t// already reset the limit on a new window.\n\tif r.limit == 0 || r.periodStart.IsZero() || r.periodStart.After(t) || t.Sub(r.periodStart) >= r.period {\n\t\treturn\n\t}\n\n\t// Undo the state update\n\tr.remaining = min(r.remaining+used, r.limit)\n}\n"
  },
  {
    "path": "plugins/common/ratelimiter/limiters_test.go",
    "content": "package ratelimiter\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\nfunc TestInvalidPeriod(t *testing.T) {\n\tcfg := &RateLimitConfig{Limit: config.Size(1024)}\n\t_, err := cfg.CreateRateLimiter()\n\trequire.ErrorContains(t, err, \"invalid period for rate-limit\")\n}\n\nfunc TestUnlimited(t *testing.T) {\n\tcfg := &RateLimitConfig{}\n\tlimiter, err := cfg.CreateRateLimiter()\n\trequire.NoError(t, err)\n\n\tstart := time.Now()\n\tend := start.Add(30 * time.Minute)\n\tfor ts := start; ts.Before(end); ts = ts.Add(1 * time.Minute) {\n\t\trequire.EqualValues(t, int64(math.MaxInt64), limiter.Remaining(ts))\n\t}\n}\n\nfunc TestUnlimitedWithPeriod(t *testing.T) {\n\tcfg := &RateLimitConfig{\n\t\tPeriod: config.Duration(5 * time.Minute),\n\t}\n\tlimiter, err := cfg.CreateRateLimiter()\n\trequire.NoError(t, err)\n\n\tstart := time.Now()\n\tend := start.Add(30 * time.Minute)\n\tfor ts := start; ts.Before(end); ts = ts.Add(1 * time.Minute) {\n\t\trequire.EqualValues(t, int64(math.MaxInt64), limiter.Remaining(ts))\n\t}\n}\n\nfunc TestLimited(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcfg      *RateLimitConfig\n\t\tstep     time.Duration\n\t\trequest  []int64\n\t\texpected []int64\n\t}{\n\t\t{\n\t\t\tname: \"constant usage\",\n\t\t\tcfg: &RateLimitConfig{\n\t\t\t\tLimit:  config.Size(1024),\n\t\t\t\tPeriod: config.Duration(5 * time.Minute),\n\t\t\t},\n\t\t\tstep:     time.Minute,\n\t\t\trequest:  []int64{300},\n\t\t\texpected: []int64{1024, 724, 424, 124, 0, 1024, 724, 424, 124, 0},\n\t\t},\n\t\t{\n\t\t\tname: \"variable usage\",\n\t\t\tcfg: &RateLimitConfig{\n\t\t\t\tLimit:  config.Size(1024),\n\t\t\t\tPeriod: config.Duration(5 * time.Minute),\n\t\t\t},\n\t\t\tstep:     time.Minute,\n\t\t\trequest:  []int64{256, 128, 512, 64, 64, 1024, 0, 0, 0, 0, 128, 4096, 4096, 4096, 4096, 4096},\n\t\t\texpected: []int64{1024, 768, 640, 128, 64, 1024, 0, 0, 0, 0, 1024, 896, 0, 0, 0, 1024},\n\t\t},\n\t}\n\n\t// Run the test with an offset of period multiples\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name+\" at period\", func(t *testing.T) {\n\t\t\t// Setup the limiter\n\t\t\tlimiter, err := tt.cfg.CreateRateLimiter()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Compute the actual values\n\t\t\tstart := time.Now().Truncate(tt.step)\n\t\t\tfor i, expected := range tt.expected {\n\t\t\t\tts := start.Add(time.Duration(i) * tt.step)\n\t\t\t\tremaining := limiter.Remaining(ts)\n\t\t\t\tuse := min(remaining, tt.request[i%len(tt.request)])\n\t\t\t\trequire.Equalf(t, expected, remaining, \"mismatch at index %d\", i)\n\t\t\t\tlimiter.Accept(ts, use)\n\t\t\t}\n\t\t})\n\t}\n\n\t// Run the test at a time of period multiples\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the limiter\n\t\t\tlimiter, err := tt.cfg.CreateRateLimiter()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Compute the actual values\n\t\t\tstart := time.Now().Truncate(tt.step).Add(1 * time.Second)\n\t\t\tfor i, expected := range tt.expected {\n\t\t\t\tts := start.Add(time.Duration(i) * tt.step)\n\t\t\t\tremaining := limiter.Remaining(ts)\n\t\t\t\tuse := min(remaining, tt.request[i%len(tt.request)])\n\t\t\t\trequire.Equalf(t, expected, remaining, \"mismatch at index %d\", i)\n\t\t\t\tlimiter.Accept(ts, use)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUndo(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcfg      *RateLimitConfig\n\t\tstep     time.Duration\n\t\trequest  []int64\n\t\texpected []int64\n\t}{\n\t\t{\n\t\t\tname: \"constant usage\",\n\t\t\tcfg: &RateLimitConfig{\n\t\t\t\tLimit:  config.Size(1024),\n\t\t\t\tPeriod: config.Duration(5 * time.Minute),\n\t\t\t},\n\t\t\tstep:     time.Minute,\n\t\t\trequest:  []int64{300},\n\t\t\texpected: []int64{1024, 724, 424, 124, 124, 1024, 724, 424, 124, 124},\n\t\t},\n\t\t{\n\t\t\tname: \"variable usage\",\n\t\t\tcfg: &RateLimitConfig{\n\t\t\t\tLimit:  config.Size(1024),\n\t\t\t\tPeriod: config.Duration(5 * time.Minute),\n\t\t\t},\n\t\t\tstep:     time.Minute,\n\t\t\trequest:  []int64{256, 128, 512, 64, 64, 1024, 0, 0, 0, 0, 128, 4096, 4096, 4096, 4096, 4096},\n\t\t\texpected: []int64{1024, 768, 640, 128, 64, 1024, 0, 0, 0, 0, 1024, 896, 896, 896, 896, 1024},\n\t\t},\n\t}\n\n\t// Run the test with an offset of period multiples\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name+\" at period\", func(t *testing.T) {\n\t\t\t// Setup the limiter\n\t\t\tlimiter, err := tt.cfg.CreateRateLimiter()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Compute the actual values\n\t\t\tstart := time.Now().Truncate(tt.step)\n\t\t\tfor i, expected := range tt.expected {\n\t\t\t\tts := start.Add(time.Duration(i) * tt.step)\n\t\t\t\tremaining := limiter.Remaining(ts)\n\t\t\t\tuse := min(remaining, tt.request[i%len(tt.request)])\n\t\t\t\trequire.Equalf(t, expected, remaining, \"mismatch at index %d\", i)\n\t\t\t\tlimiter.Accept(ts, use)\n\t\t\t\t// Undo too large operations\n\t\t\t\tif tt.request[i%len(tt.request)] > remaining {\n\t\t\t\t\tlimiter.Undo(ts, use)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t// Run the test at a time of period multiples\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the limiter\n\t\t\tlimiter, err := tt.cfg.CreateRateLimiter()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Compute the actual values\n\t\t\tstart := time.Now().Truncate(tt.step).Add(1 * time.Second)\n\t\t\tfor i, expected := range tt.expected {\n\t\t\t\tts := start.Add(time.Duration(i) * tt.step)\n\t\t\t\tremaining := limiter.Remaining(ts)\n\t\t\t\tuse := min(remaining, tt.request[i%len(tt.request)])\n\t\t\t\trequire.Equalf(t, expected, remaining, \"mismatch at index %d\", i)\n\t\t\t\tlimiter.Accept(ts, use)\n\t\t\t\t// Undo too large operations\n\t\t\t\tif tt.request[i%len(tt.request)] > remaining {\n\t\t\t\t\tlimiter.Undo(ts, use)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/ratelimiter/serializers.go",
    "content": "package ratelimiter\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// Serializer interface abstracting the different implementations of a\n// limited-size serializer\ntype Serializer interface {\n\tSerialize(metric telegraf.Metric, limit int64) ([]byte, error)\n\tSerializeBatch(metrics []telegraf.Metric, limit int64) ([]byte, error)\n}\n\n// IndividualSerializer instances serialize each metric individually using the\n// serializer's Serialize() function and add the resulting output to the buffer\n// until the limit is reached. This only works for serializers NOT requiring\n// the serialization of a batch as-a-whole.\ntype IndividualSerializer struct {\n\tserializer telegraf.Serializer\n\tbuffer     *bytes.Buffer\n}\n\nfunc NewIndividualSerializer(s telegraf.Serializer) *IndividualSerializer {\n\treturn &IndividualSerializer{\n\t\tserializer: s,\n\t\tbuffer:     &bytes.Buffer{},\n\t}\n}\n\nfunc (s *IndividualSerializer) Serialize(metric telegraf.Metric, limit int64) ([]byte, error) {\n\t// Do the serialization\n\tbuf, err := s.serializer.Serialize(metric)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// The serialized metric fits into the limit, so output it\n\tif buflen := int64(len(buf)); buflen <= limit {\n\t\treturn buf, nil\n\t}\n\n\t// The serialized metric exceeds the limit\n\treturn nil, internal.ErrSizeLimitReached\n}\n\nfunc (s *IndividualSerializer) SerializeBatch(metrics []telegraf.Metric, limit int64) ([]byte, error) {\n\t// Grow the buffer so it can hold at least the required size. This will\n\t// save us from reallocate often\n\ts.buffer.Reset()\n\tif limit > 0 && limit > int64(s.buffer.Cap()) && limit < int64(math.MaxInt) {\n\t\ts.buffer.Grow(int(limit))\n\t}\n\n\t// Prepare a potential write error and be optimistic\n\twerr := &internal.PartialWriteError{\n\t\tMetricsAccept: make([]int, 0, len(metrics)),\n\t}\n\n\t// Iterate through the metrics, serialize them and add them to the output\n\t// buffer if they are within the size limit.\n\tvar used int64\n\tfor i, m := range metrics {\n\t\tbuf, err := s.serializer.Serialize(m)\n\t\tif err != nil {\n\t\t\t// Failing serialization is a fatal error so mark the metric as such\n\t\t\twerr.Err = internal.ErrSerialization\n\t\t\twerr.MetricsReject = append(werr.MetricsReject, i)\n\t\t\twerr.MetricsRejectErrors = append(werr.MetricsRejectErrors, err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// The serialized metric fits into the limit, so add it to the output\n\t\tif usedAdded := used + int64(len(buf)); usedAdded <= limit {\n\t\t\tif _, err := s.buffer.Write(buf); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\twerr.MetricsAccept = append(werr.MetricsAccept, i)\n\t\t\tused = usedAdded\n\t\t\tcontinue\n\t\t}\n\n\t\t// Return only the size-limit-reached error if all metrics failed.\n\t\tif used == 0 {\n\t\t\treturn nil, internal.ErrSizeLimitReached\n\t\t}\n\n\t\t// Adding the serialized metric would exceed the limit so exit with an\n\t\t// WriteError and fill in the required information\n\t\twerr.Err = internal.ErrSizeLimitReached\n\t\tbreak\n\t}\n\tif werr.Err != nil {\n\t\treturn s.buffer.Bytes(), werr\n\t}\n\treturn s.buffer.Bytes(), nil\n}\n"
  },
  {
    "path": "plugins/common/ratelimiter/serializers_test.go",
    "content": "package ratelimiter\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/influx\"\n)\n\nfunc TestIndividualSerializer(t *testing.T) {\n\tinput := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"A\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 123,\n\t\t\t\t\"temperature\":     25.0,\n\t\t\t\t\"pressure\":        1023.4,\n\t\t\t},\n\t\t\ttime.Unix(1722443551, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"B\",\n\t\t\t\t\"status\":   \"failed\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 8430,\n\t\t\t\t\"temperature\":     65.2,\n\t\t\t\t\"pressure\":        985.9,\n\t\t\t},\n\t\t\ttime.Unix(1722443554, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"C\",\n\t\t\t\t\"status\":   \"warning\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 6765,\n\t\t\t\t\"temperature\":     42.5,\n\t\t\t\t\"pressure\":        986.1,\n\t\t\t},\n\t\t\ttime.Unix(1722443555, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\": \"ok\",\n\t\t\t},\n\t\t\ttime.Unix(1722443556, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"A\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 5544,\n\t\t\t\t\"temperature\":     18.6,\n\t\t\t\t\"pressure\":        1069.4,\n\t\t\t},\n\t\t\ttime.Unix(1722443552, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"B\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 65,\n\t\t\t\t\"temperature\":     29.7,\n\t\t\t\t\"pressure\":        1101.2,\n\t\t\t},\n\t\t\ttime.Unix(1722443553, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\": \"ok\",\n\t\t\t},\n\t\t\ttime.Unix(1722443559, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"C\",\n\t\t\t\t\"status\":   \"off\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 0,\n\t\t\t\t\"temperature\":     0.0,\n\t\t\t\t\"pressure\":        0.0,\n\t\t\t},\n\t\t\ttime.Unix(1722443562, 0),\n\t\t),\n\t}\n\t//nolint:lll // Resulting metrics should not be wrapped for readability\n\texpected := []string{\n\t\t\"serializer_test,location=factory_north,machine=A,source=localhost,status=ok operating_hours=123i,pressure=1023.4,temperature=25 1722443551000000000\\n\" +\n\t\t\t\"serializer_test,location=factory_north,machine=B,source=localhost,status=failed operating_hours=8430i,pressure=985.9,temperature=65.2 1722443554000000000\\n\",\n\t\t\"serializer_test,location=factory_north,machine=C,source=localhost,status=warning operating_hours=6765i,pressure=986.1,temperature=42.5 1722443555000000000\\n\" +\n\t\t\t\"device,location=factory_north,source=localhost status=\\\"ok\\\" 1722443556000000000\\n\" +\n\t\t\t\"serializer_test,location=factory_south,machine=A,source=gateway_af43e,status=ok operating_hours=5544i,pressure=1069.4,temperature=18.6 1722443552000000000\\n\",\n\t\t\"serializer_test,location=factory_south,machine=B,source=gateway_af43e,status=ok operating_hours=65i,pressure=1101.2,temperature=29.7 1722443553000000000\\n\" +\n\t\t\t\"device,location=factory_south,source=gateway_af43e status=\\\"ok\\\" 1722443559000000000\\n\" +\n\t\t\t\"serializer_test,location=factory_south,machine=C,source=gateway_af43e,status=off operating_hours=0i,pressure=0,temperature=0 1722443562000000000\\n\",\n\t}\n\n\t// Setup the limited serializer\n\ts := &influx.Serializer{SortFields: true}\n\trequire.NoError(t, s.Init())\n\tserializer := NewIndividualSerializer(s)\n\n\tvar werr *internal.PartialWriteError\n\n\t// Do the first serialization runs with all metrics\n\tbuf, err := serializer.SerializeBatch(input, 400)\n\trequire.ErrorAs(t, err, &werr)\n\trequire.ErrorIs(t, werr.Err, internal.ErrSizeLimitReached)\n\trequire.EqualValues(t, []int{0, 1}, werr.MetricsAccept)\n\trequire.Empty(t, werr.MetricsReject)\n\trequire.Equal(t, expected[0], string(buf))\n\n\t// Run again with the successful metrics removed\n\tbuf, err = serializer.SerializeBatch(input[2:], 400)\n\trequire.ErrorAs(t, err, &werr)\n\trequire.ErrorIs(t, werr.Err, internal.ErrSizeLimitReached)\n\trequire.EqualValues(t, []int{0, 1, 2}, werr.MetricsAccept)\n\trequire.Empty(t, werr.MetricsReject)\n\trequire.Equal(t, expected[1], string(buf))\n\n\t// Final run with the successful metrics removed\n\tbuf, err = serializer.SerializeBatch(input[5:], 400)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expected[2], string(buf))\n}\n\nfunc TestIndividualSerializerFirstTooBig(t *testing.T) {\n\tinput := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"A\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 123,\n\t\t\t\t\"temperature\":     25.0,\n\t\t\t\t\"pressure\":        1023.4,\n\t\t\t},\n\t\t\ttime.Unix(1722443551, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"B\",\n\t\t\t\t\"status\":   \"failed\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 8430,\n\t\t\t\t\"temperature\":     65.2,\n\t\t\t\t\"pressure\":        985.9,\n\t\t\t},\n\t\t\ttime.Unix(1722443554, 0),\n\t\t),\n\t}\n\n\t// Setup the limited serializer\n\ts := &influx.Serializer{SortFields: true}\n\trequire.NoError(t, s.Init())\n\tserializer := NewIndividualSerializer(s)\n\n\t// The first metric will already exceed the size so all metrics fail and\n\t// we expect a shortcut error.\n\tbuf, err := serializer.SerializeBatch(input, 100)\n\trequire.ErrorIs(t, err, internal.ErrSizeLimitReached)\n\trequire.Empty(t, buf)\n}\n\nfunc TestIndividualSerializerUnlimited(t *testing.T) {\n\tinput := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"A\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 123,\n\t\t\t\t\"temperature\":     25.0,\n\t\t\t\t\"pressure\":        1023.4,\n\t\t\t},\n\t\t\ttime.Unix(1722443551, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"B\",\n\t\t\t\t\"status\":   \"failed\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 8430,\n\t\t\t\t\"temperature\":     65.2,\n\t\t\t\t\"pressure\":        985.9,\n\t\t\t},\n\t\t\ttime.Unix(1722443554, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t\t\"machine\":  \"C\",\n\t\t\t\t\"status\":   \"warning\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 6765,\n\t\t\t\t\"temperature\":     42.5,\n\t\t\t\t\"pressure\":        986.1,\n\t\t\t},\n\t\t\ttime.Unix(1722443555, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"localhost\",\n\t\t\t\t\"location\": \"factory_north\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\": \"ok\",\n\t\t\t},\n\t\t\ttime.Unix(1722443556, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"A\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 5544,\n\t\t\t\t\"temperature\":     18.6,\n\t\t\t\t\"pressure\":        1069.4,\n\t\t\t},\n\t\t\ttime.Unix(1722443552, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"B\",\n\t\t\t\t\"status\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 65,\n\t\t\t\t\"temperature\":     29.7,\n\t\t\t\t\"pressure\":        1101.2,\n\t\t\t},\n\t\t\ttime.Unix(1722443553, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\": \"ok\",\n\t\t\t},\n\t\t\ttime.Unix(1722443559, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"serializer_test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":   \"gateway_af43e\",\n\t\t\t\t\"location\": \"factory_south\",\n\t\t\t\t\"machine\":  \"C\",\n\t\t\t\t\"status\":   \"off\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"operating_hours\": 0,\n\t\t\t\t\"temperature\":     0.0,\n\t\t\t\t\"pressure\":        0.0,\n\t\t\t},\n\t\t\ttime.Unix(1722443562, 0),\n\t\t),\n\t}\n\t//nolint:lll // Resulting metrics should not be wrapped for readability\n\texpected := \"serializer_test,location=factory_north,machine=A,source=localhost,status=ok operating_hours=123i,pressure=1023.4,temperature=25 1722443551000000000\\n\" +\n\t\t\"serializer_test,location=factory_north,machine=B,source=localhost,status=failed operating_hours=8430i,pressure=985.9,temperature=65.2 1722443554000000000\\n\" +\n\t\t\"serializer_test,location=factory_north,machine=C,source=localhost,status=warning operating_hours=6765i,pressure=986.1,temperature=42.5 1722443555000000000\\n\" +\n\t\t\"device,location=factory_north,source=localhost status=\\\"ok\\\" 1722443556000000000\\n\" +\n\t\t\"serializer_test,location=factory_south,machine=A,source=gateway_af43e,status=ok operating_hours=5544i,pressure=1069.4,temperature=18.6 1722443552000000000\\n\" +\n\t\t\"serializer_test,location=factory_south,machine=B,source=gateway_af43e,status=ok operating_hours=65i,pressure=1101.2,temperature=29.7 1722443553000000000\\n\" +\n\t\t\"device,location=factory_south,source=gateway_af43e status=\\\"ok\\\" 1722443559000000000\\n\" +\n\t\t\"serializer_test,location=factory_south,machine=C,source=gateway_af43e,status=off operating_hours=0i,pressure=0,temperature=0 1722443562000000000\\n\"\n\n\t// Setup the limited serializer\n\ts := &influx.Serializer{SortFields: true}\n\trequire.NoError(t, s.Init())\n\tserializer := NewIndividualSerializer(s)\n\n\t// Do the first serialization runs with all metrics\n\tbuf, err := serializer.SerializeBatch(input, math.MaxInt64)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expected, string(buf))\n}\n"
  },
  {
    "path": "plugins/common/shim/README.md",
    "content": "# Telegraf Execd Go Shim\n\nThe goal of this _shim_ is to make it trivial to extract an internal input,\nprocessor, or output plugin from the main Telegraf repo out to a stand-alone\nrepo. This allows anyone to build and run it as a separate app using one of the\nexecd plugins:\n\n- [inputs.execd](/plugins/inputs/execd)\n- [processors.execd](/plugins/processors/execd)\n- [outputs.execd](/plugins/outputs/execd)\n\n## Steps to externalize a plugin\n\n1. Move the project to an external repo, it's recommended to preserve the path\n   structure, (but not strictly necessary). eg if your plugin was at\n   `plugins/inputs/cpu`, it's recommended that it also be under `plugins/inputs/cpu`\n   in the new repo. For a further example of what this might look like, take a\n   look at [ssoroka/rand](https://github.com/ssoroka/rand) or\n   [danielnelson/telegraf-plugins](https://github.com/danielnelson/telegraf-plugins)\n1. Copy [main.go](/plugins/common/shim/example/cmd/main.go) into your project\n   under the `cmd` folder. This will be the entrypoint to the plugin when run as\n   a stand-alone program, and it will call the shim code for you to make that\n   happen. It's recommended to have only one plugin per repo, as the shim is not\n   designed to run multiple plugins at the same time (it would vastly complicate\n   things).\n1. Edit the main.go file to import your plugin. Within Telegraf this would have\n   been done in an all.go file, but here we don't split the two apart, and the\n   change  just goes in the top of main.go. If you skip this step, your plugin\n   will do nothing. eg: `_ \"github.com/me/my-plugin-telegraf/plugins/inputs/cpu\"`\n1. Optionally add a [plugin.conf](/plugins/common/shim/example/cmd/plugin.conf)\n   for configuration specific to your plugin. Note that this config file **must\n   be separate from the rest of the config for Telegraf, and must not be in a\n   shared directory where Telegraf is expecting to load all configs**.\n   If Telegraf reads this config file it will not know which plugin it relates\n   to. Telegraf instead uses an execd config block to look for this plugin.\n\n## Steps to build and run your plugin\n\n1. Build the cmd/main.go. For my rand project this looks like\n   `go build -o rand cmd/main.go`\n1. If you're building an input, you can test out the binary just by running it.\n   eg `./rand -config plugin.conf`Depending on your polling settings and whether\n   you implemented a service plugin or an input gathering plugin, you may see\n   data right away, or you may have to hit enter first, or wait for your poll\n   duration to elapse, but the metrics will be written to STDOUT. Ctrl-C to end\n   your test. If you're testing a processor or output manually, you can still do\n   this but you will need to feed valid metrics in on STDIN to verify that it is\n   doing what you want. This can be a very valuable debugging technique before\n   hooking it up to Telegraf.\n1. Configure Telegraf to call your new plugin binary. For an input, this would\n   look something like:\n\n```toml\n[[inputs.execd]]\n  command = [\"/path/to/rand\", \"-config\", \"/path/to/plugin.conf\"]\n  signal = \"none\"\n```\n\n  Refer to the execd plugin readmes for more information.\n\n## Congratulations\n\nYou've done it! Consider publishing your plugin to github and open a Pull\nRequest back to the Telegraf repo letting us know about the availability of your\n[external plugin](/EXTERNAL_PLUGINS.md).\n"
  },
  {
    "path": "plugins/common/shim/config.go",
    "content": "package shim\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\" //nolint:depguard // Allow exceptional but valid use of log here.\n\t\"os\"\n\n\t\"github.com/BurntSushi/toml\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n)\n\ntype config struct {\n\tInputs     map[string][]toml.Primitive\n\tProcessors map[string][]toml.Primitive\n\tOutputs    map[string][]toml.Primitive\n}\n\ntype loadedConfig struct {\n\tInput     telegraf.Input\n\tProcessor telegraf.StreamingProcessor\n\tOutput    telegraf.Output\n}\n\n// LoadConfig Adds plugins to the shim\nfunc (s *Shim) LoadConfig(filePath *string) error {\n\tconf, err := LoadConfig(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif conf.Input != nil {\n\t\tif err = s.AddInput(conf.Input); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to add Input: %w\", err)\n\t\t}\n\t} else if conf.Processor != nil {\n\t\tif err = s.AddStreamingProcessor(conf.Processor); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to add Processor: %w\", err)\n\t\t}\n\t} else if conf.Output != nil {\n\t\tif err = s.AddOutput(conf.Output); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to add Output: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// LoadConfig loads the config and returns inputs that later need to be loaded.\nfunc LoadConfig(filePath *string) (loaded loadedConfig, err error) {\n\tvar data string\n\tconf := config{}\n\tif filePath != nil && *filePath != \"\" {\n\t\tb, err := os.ReadFile(*filePath)\n\t\tif err != nil {\n\t\t\treturn loadedConfig{}, err\n\t\t}\n\n\t\tdata = expandEnvVars(b)\n\t} else {\n\t\tconf = DefaultImportedPlugins()\n\t}\n\n\tmd, err := toml.Decode(data, &conf)\n\tif err != nil {\n\t\treturn loadedConfig{}, err\n\t}\n\n\treturn createPluginsWithTomlConfig(md, conf)\n}\n\nfunc expandEnvVars(contents []byte) string {\n\treturn os.Expand(string(contents), getEnv)\n}\n\nfunc getEnv(key string) string {\n\tv := os.Getenv(key)\n\n\treturn envVarEscaper.Replace(v)\n}\n\nfunc createPluginsWithTomlConfig(md toml.MetaData, conf config) (loadedConfig, error) {\n\tloadedConf := loadedConfig{}\n\n\tfor name, primitives := range conf.Inputs {\n\t\tcreator, ok := inputs.Inputs[name]\n\t\tif !ok {\n\t\t\treturn loadedConf, errors.New(\"unknown input \" + name)\n\t\t}\n\n\t\tplugin := creator()\n\t\tif len(primitives) > 0 {\n\t\t\tprimitive := primitives[0]\n\t\t\tif err := md.PrimitiveDecode(primitive, plugin); err != nil {\n\t\t\t\treturn loadedConf, err\n\t\t\t}\n\t\t}\n\n\t\tloadedConf.Input = plugin\n\t\tbreak\n\t}\n\n\tfor name, primitives := range conf.Processors {\n\t\tcreator, ok := processors.Processors[name]\n\t\tif !ok {\n\t\t\treturn loadedConf, errors.New(\"unknown processor \" + name)\n\t\t}\n\n\t\tplugin := creator()\n\t\tif len(primitives) > 0 {\n\t\t\tprimitive := primitives[0]\n\t\t\tvar p telegraf.PluginDescriber = plugin\n\t\t\tif processor, ok := plugin.(processors.HasUnwrap); ok {\n\t\t\t\tp = processor.Unwrap()\n\t\t\t}\n\t\t\tif err := md.PrimitiveDecode(primitive, p); err != nil {\n\t\t\t\treturn loadedConf, err\n\t\t\t}\n\t\t}\n\t\tloadedConf.Processor = plugin\n\t\tbreak\n\t}\n\n\tfor name, primitives := range conf.Outputs {\n\t\tcreator, ok := outputs.Outputs[name]\n\t\tif !ok {\n\t\t\treturn loadedConf, errors.New(\"unknown output \" + name)\n\t\t}\n\n\t\tplugin := creator()\n\t\tif len(primitives) > 0 {\n\t\t\tprimitive := primitives[0]\n\t\t\tif err := md.PrimitiveDecode(primitive, plugin); err != nil {\n\t\t\t\treturn loadedConf, err\n\t\t\t}\n\t\t}\n\t\tloadedConf.Output = plugin\n\t\tbreak\n\t}\n\treturn loadedConf, nil\n}\n\n// DefaultImportedPlugins defaults to whatever plugins happen to be loaded and\n// have registered themselves with the registry. This makes loading plugins\n// without having to define a config dead easy.\nfunc DefaultImportedPlugins() config {\n\tconf := config{\n\t\tInputs:     make(map[string][]toml.Primitive, len(inputs.Inputs)),\n\t\tProcessors: make(map[string][]toml.Primitive, len(processors.Processors)),\n\t\tOutputs:    make(map[string][]toml.Primitive, len(outputs.Outputs)),\n\t}\n\tfor name := range inputs.Inputs {\n\t\tlog.Println(\"No config found. Loading default config for plugin\", name)\n\t\tconf.Inputs[name] = make([]toml.Primitive, 0)\n\t\treturn conf\n\t}\n\tfor name := range processors.Processors {\n\t\tlog.Println(\"No config found. Loading default config for plugin\", name)\n\t\tconf.Processors[name] = make([]toml.Primitive, 0)\n\t\treturn conf\n\t}\n\tfor name := range outputs.Outputs {\n\t\tlog.Println(\"No config found. Loading default config for plugin\", name)\n\t\tconf.Outputs[name] = make([]toml.Primitive, 0)\n\t\treturn conf\n\t}\n\treturn conf\n}\n"
  },
  {
    "path": "plugins/common/shim/config_test.go",
    "content": "package shim\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcfg \"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n)\n\nfunc TestLoadConfig(t *testing.T) {\n\tt.Setenv(\"SECRET_TOKEN\", \"xxxxxxxxxx\")\n\tt.Setenv(\"SECRET_VALUE\", `test\"\\test`)\n\n\tinputs.Add(\"test\", func() telegraf.Input {\n\t\treturn &serviceInput{}\n\t})\n\n\tc := \"./testdata/plugin.conf\"\n\tconf, err := LoadConfig(&c)\n\trequire.NoError(t, err)\n\n\tinp := conf.Input.(*serviceInput)\n\n\trequire.Equal(t, \"awesome name\", inp.ServiceName)\n\trequire.Equal(t, \"xxxxxxxxxx\", inp.SecretToken)\n\trequire.Equal(t, `test\"\\test`, inp.SecretValue)\n}\n\nfunc TestLoadingSpecialTypes(t *testing.T) {\n\tinputs.Add(\"test\", func() telegraf.Input {\n\t\treturn &testDurationInput{}\n\t})\n\n\tc := \"./testdata/special.conf\"\n\tconf, err := LoadConfig(&c)\n\trequire.NoError(t, err)\n\n\tinp := conf.Input.(*testDurationInput)\n\n\trequire.EqualValues(t, 3*time.Second, inp.Duration)\n\trequire.EqualValues(t, 3*1000*1000, inp.Size)\n\trequire.EqualValues(t, 52, inp.Hex)\n}\n\nfunc TestLoadingProcessorWithConfig(t *testing.T) {\n\tproc := &testConfigProcessor{}\n\tprocessors.Add(\"test_config_load\", func() telegraf.Processor {\n\t\treturn proc\n\t})\n\n\tc := \"./testdata/processor.conf\"\n\t_, err := LoadConfig(&c)\n\trequire.NoError(t, err)\n\n\trequire.EqualValues(t, \"yep\", proc.Loaded)\n}\n\ntype testDurationInput struct {\n\tDuration cfg.Duration `toml:\"duration\"`\n\tSize     cfg.Size     `toml:\"size\"`\n\tHex      int64        `toml:\"hex\"`\n}\n\nfunc (*testDurationInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (*testDurationInput) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\ntype testConfigProcessor struct {\n\tLoaded string `toml:\"loaded\"`\n}\n\nfunc (*testConfigProcessor) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (*testConfigProcessor) Apply(metrics ...telegraf.Metric) []telegraf.Metric {\n\treturn metrics\n}\n"
  },
  {
    "path": "plugins/common/shim/example/cmd/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t// TODO: import your plugins\n\t_ \"github.com/influxdata/tail\" // Example external package for showing where you can import your plugins\n\n\t\"github.com/influxdata/telegraf/plugins/common/shim\"\n)\n\nvar pollInterval = flag.Duration(\"poll_interval\", 1*time.Second, \"how often to send metrics\")\n\nvar pollIntervalDisabled = flag.Bool(\n\t\"poll_interval_disabled\",\n\tfalse,\n\t\"set to true to disable polling. You want to use this when you are sending metrics on your own schedule\",\n)\nvar configFile = flag.String(\"config\", \"\", \"path to the config file for this plugin\")\nvar err error\n\n// This is designed to be simple; Just change the import above, and you're good.\n//\n// However, if you want to do all your config in code, you can like so:\n//\n// // initialize your plugin with any settings you want\n//\n//\tmyInput := &mypluginname.MyPlugin{\n//\t\tDefaultSettingHere: 3,\n//\t}\n//\n// shim := shim.New()\n//\n// shim.AddInput(myInput)\n//\n// // now the shim.Run() call as below. Note the shim is only intended to run a single plugin.\nfunc main() {\n\t// parse command line options\n\tflag.Parse()\n\tif *pollIntervalDisabled {\n\t\t*pollInterval = shim.PollIntervalDisabled\n\t}\n\n\t// create the shim. This is what will run your plugins.\n\tshimLayer := shim.New()\n\n\t// If no config is specified, all imported plugins are loaded.\n\t// otherwise, follow what the config asks for.\n\t// Check for settings from a config toml file,\n\t// (or just use whatever plugins were imported above)\n\tif err = shimLayer.LoadConfig(configFile); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"Err loading input: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// run a single plugin until stdin closes, or we receive a termination signal\n\tif err = shimLayer.Run(*pollInterval); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"Err: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "plugins/common/shim/example/cmd/plugin.conf",
    "content": "[[inputs.my_plugin_name]]\n\tvalue_name = \"value\"\n"
  },
  {
    "path": "plugins/common/shim/goshim.go",
    "content": "package shim\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/influx\"\n)\n\ntype empty struct{}\n\nvar (\n\tforever       = 100 * 365 * 24 * time.Hour\n\tenvVarEscaper = strings.NewReplacer(\n\t\t`\"`, `\\\"`,\n\t\t`\\`, `\\\\`,\n\t)\n)\n\nconst (\n\t// PollIntervalDisabled is used to indicate that you want to disable polling,\n\t// as opposed to duration 0 meaning poll constantly.\n\tPollIntervalDisabled = time.Duration(0)\n)\n\n// Shim allows you to wrap your inputs and run them as if they were part of Telegraf,\n// except built externally.\ntype Shim struct {\n\tInput     telegraf.Input\n\tProcessor telegraf.StreamingProcessor\n\tOutput    telegraf.Output\n\n\tBatchSize    int\n\tBatchTimeout time.Duration\n\n\tlog telegraf.Logger\n\n\t// streams\n\tstdin  io.Reader\n\tstdout io.Writer\n\tstderr io.Writer\n\n\t// outgoing metric channel\n\tmetricCh chan telegraf.Metric\n\n\t// input only\n\tgatherPromptCh chan empty\n}\n\n// New creates a new shim interface\nfunc New() *Shim {\n\treturn &Shim{\n\t\tBatchSize:    1,\n\t\tBatchTimeout: 10 * time.Second,\n\t\tmetricCh:     make(chan telegraf.Metric, 1),\n\t\tstdin:        os.Stdin,\n\t\tstdout:       os.Stdout,\n\t\tstderr:       os.Stderr,\n\t\tlog:          logger.New(\"\", \"\", \"\"),\n\t}\n}\n\nfunc (*Shim) watchForShutdown(cancel context.CancelFunc) {\n\tquit := make(chan os.Signal, 1)\n\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\tgo func() {\n\t\t<-quit // user-triggered quit\n\t\t// cancel, but keep looping until the metric channel closes.\n\t\tcancel()\n\t}()\n}\n\n// Run the input plugins..\nfunc (s *Shim) Run(pollInterval time.Duration) error {\n\tif s.Input != nil {\n\t\terr := s.RunInput(pollInterval)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"running input failed: %w\", err)\n\t\t}\n\t} else if s.Processor != nil {\n\t\terr := s.RunProcessor()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"running processor failed: %w\", err)\n\t\t}\n\t} else if s.Output != nil {\n\t\terr := s.RunOutput()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"running output failed: %w\", err)\n\t\t}\n\t} else {\n\t\treturn errors.New(\"nothing to run\")\n\t}\n\n\treturn nil\n}\n\nfunc hasQuit(ctx context.Context) bool {\n\treturn ctx.Err() != nil\n}\n\nfunc (s *Shim) writeProcessedMetrics() error {\n\tserializer := &influx.Serializer{}\n\tif err := serializer.Init(); err != nil {\n\t\treturn fmt.Errorf(\"creating serializer failed: %w\", err)\n\t}\n\tfor { //nolint:staticcheck // for-select used on purpose\n\t\tselect {\n\t\tcase m, open := <-s.metricCh:\n\t\t\tif !open {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tb, err := serializer.Serialize(m)\n\t\t\tif err != nil {\n\t\t\t\tm.Reject()\n\t\t\t\treturn fmt.Errorf(\"failed to serialize metric: %w\", err)\n\t\t\t}\n\t\t\t// Write this to stdout\n\t\t\t_, err = fmt.Fprint(s.stdout, string(b))\n\t\t\tif err != nil {\n\t\t\t\tm.Drop()\n\t\t\t\treturn fmt.Errorf(\"failed to write metric: %w\", err)\n\t\t\t}\n\t\t\tm.Accept()\n\t\t}\n\t}\n}\n\n// LogName satisfies the MetricMaker interface\nfunc (*Shim) LogName() string {\n\treturn \"\"\n}\n\n// MakeMetric satisfies the MetricMaker interface\nfunc (*Shim) MakeMetric(m telegraf.Metric) telegraf.Metric {\n\treturn m // don't need to do anything to it.\n}\n\n// Log satisfies the MetricMaker interface\nfunc (s *Shim) Log() telegraf.Logger {\n\treturn s.log\n}\n"
  },
  {
    "path": "plugins/common/shim/goshim_test.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/logger\"\n)\n\nfunc TestShimSetsUpLogger(t *testing.T) {\n\tstderrReader, stderrWriter := io.Pipe()\n\tstdinReader, stdinWriter := io.Pipe()\n\n\trunErroringInputPlugin(t, 40*time.Second, stdinReader, nil, stderrWriter)\n\n\t_, err := stdinWriter.Write([]byte(\"\\n\"))\n\trequire.NoError(t, err)\n\n\tr := bufio.NewReader(stderrReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Contains(t, out, \"Error in plugin: intentional\")\n\n\terr = stdinWriter.Close()\n\trequire.NoError(t, err)\n}\n\nfunc runErroringInputPlugin(t *testing.T, interval time.Duration, stdin io.Reader, stdout, stderr io.Writer) (processed, exited chan bool) {\n\tprocessed = make(chan bool, 1)\n\texited = make(chan bool, 1)\n\tinp := &erroringInput{}\n\n\tshim := New()\n\tif stdin != nil {\n\t\tshim.stdin = stdin\n\t}\n\tif stdout != nil {\n\t\tshim.stdout = stdout\n\t}\n\tif stderr != nil {\n\t\tshim.stderr = stderr\n\t\tlogger.RedirectLogging(stderr)\n\t}\n\n\trequire.NoError(t, shim.AddInput(inp))\n\tgo func(e chan bool) {\n\t\tif err := shim.Run(interval); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\te <- true\n\t}(exited)\n\treturn processed, exited\n}\n\ntype erroringInput struct {\n}\n\nfunc (*erroringInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (*erroringInput) Gather(acc telegraf.Accumulator) error {\n\tacc.AddError(errors.New(\"intentional\"))\n\treturn nil\n}\n\nfunc (*erroringInput) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (*erroringInput) Stop() {\n}\n"
  },
  {
    "path": "plugins/common/shim/input.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/models\"\n)\n\n// AddInput adds the input to the shim. Later calls to Run() will run this input.\nfunc (s *Shim) AddInput(input telegraf.Input) error {\n\tmodels.SetLoggerOnPlugin(input, s.Log())\n\tif p, ok := input.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to init input: %w\", err)\n\t\t}\n\t}\n\n\ts.Input = input\n\treturn nil\n}\n\nfunc (s *Shim) RunInput(pollInterval time.Duration) error {\n\t// context is used only to close the stdin reader. everything else cascades\n\t// from that point and closes cleanly when it's done.\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\ts.watchForShutdown(cancel)\n\n\tacc := agent.NewAccumulator(s, s.metricCh)\n\tacc.SetPrecision(time.Nanosecond)\n\n\tif serviceInput, ok := s.Input.(telegraf.ServiceInput); ok {\n\t\tif err := serviceInput.Start(acc); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to start input: %w\", err)\n\t\t}\n\t}\n\ts.gatherPromptCh = make(chan empty, 1)\n\tgo func() {\n\t\ts.startGathering(ctx, s.Input, acc, pollInterval)\n\t\tif serviceInput, ok := s.Input.(telegraf.ServiceInput); ok {\n\t\t\tserviceInput.Stop()\n\t\t}\n\t\t// closing the metric channel gracefully stops writing to stdout\n\t\tclose(s.metricCh)\n\t}()\n\n\twg := sync.WaitGroup{}\n\twg.Add(1)\n\tgo func() {\n\t\terr := s.writeProcessedMetrics()\n\t\tif err != nil {\n\t\t\ts.log.Warn(err.Error())\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tgo func() {\n\t\tscanner := bufio.NewScanner(s.stdin)\n\t\tfor scanner.Scan() {\n\t\t\t// push a non-blocking message to trigger metric collection.\n\t\t\ts.pushCollectMetricsRequest()\n\t\t}\n\n\t\tcancel() // cancel gracefully stops gathering\n\t}()\n\n\twg.Wait() // wait for writing to stdout to finish\n\treturn nil\n}\n\nfunc (s *Shim) startGathering(ctx context.Context, input telegraf.Input, acc telegraf.Accumulator, pollInterval time.Duration) {\n\tif pollInterval == PollIntervalDisabled {\n\t\tpollInterval = forever\n\t}\n\tt := time.NewTicker(pollInterval)\n\tdefer t.Stop()\n\tfor {\n\t\t// give priority to stopping.\n\t\tif hasQuit(ctx) {\n\t\t\treturn\n\t\t}\n\t\t// see what's up\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-s.gatherPromptCh:\n\t\t\tif err := input.Gather(acc); err != nil {\n\t\t\t\tfmt.Fprintf(s.stderr, \"failed to gather metrics: %s\\n\", err)\n\t\t\t}\n\t\tcase <-t.C:\n\t\t\tif err := input.Gather(acc); err != nil {\n\t\t\t\tfmt.Fprintf(s.stderr, \"failed to gather metrics: %s\\n\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// pushCollectMetricsRequest pushes a non-blocking (nil) message to the\n// gatherPromptCh channel to trigger metric collection.\n// The channel is defined with a buffer of 1, so while it's full, subsequent\n// requests are discarded.\nfunc (s *Shim) pushCollectMetricsRequest() {\n\t// push a message out to each channel to collect metrics. don't block.\n\tselect {\n\tcase s.gatherPromptCh <- empty{}:\n\tdefault:\n\t}\n}\n"
  },
  {
    "path": "plugins/common/shim/input_test.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc TestInputShimTimer(t *testing.T) {\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\tstdin, _ := io.Pipe() // hold the stdin pipe open\n\n\tmetricProcessed, _ := runInputPlugin(t, 10*time.Millisecond, stdin, stdoutWriter, nil)\n\n\t<-metricProcessed\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Contains(t, out, \"\\n\")\n\tmetricLine := strings.Split(out, \"\\n\")[0]\n\trequire.Equal(t, \"measurement,tag=tag field=1i 1234000005678\", metricLine)\n}\n\nfunc TestInputShimStdinSignalingWorks(t *testing.T) {\n\tstdinReader, stdinWriter := io.Pipe()\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\tmetricProcessed, exited := runInputPlugin(t, 40*time.Second, stdinReader, stdoutWriter, nil)\n\n\t_, err := stdinWriter.Write([]byte(\"\\n\"))\n\trequire.NoError(t, err)\n\n\t<-metricProcessed\n\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"measurement,tag=tag field=1i 1234000005678\\n\", out)\n\n\terr = stdinWriter.Close()\n\trequire.NoError(t, err)\n\tgo func() {\n\t\tif _, err = io.ReadAll(r); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\t// check that it exits cleanly\n\t<-exited\n}\n\nfunc runInputPlugin(t *testing.T, interval time.Duration, stdin io.Reader, stdout, stderr io.Writer) (processed, exited chan bool) {\n\tprocessed = make(chan bool, 1)\n\texited = make(chan bool, 1)\n\tinp := &testInput{\n\t\tmetricProcessed: processed,\n\t}\n\n\tshim := New()\n\tif stdin != nil {\n\t\tshim.stdin = stdin\n\t}\n\tif stdout != nil {\n\t\tshim.stdout = stdout\n\t}\n\tif stderr != nil {\n\t\tshim.stderr = stderr\n\t}\n\terr := shim.AddInput(inp)\n\trequire.NoError(t, err)\n\tgo func(e chan bool) {\n\t\tif err := shim.Run(interval); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\te <- true\n\t}(exited)\n\treturn processed, exited\n}\n\ntype testInput struct {\n\tmetricProcessed chan bool\n}\n\nfunc (*testInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (i *testInput) Gather(acc telegraf.Accumulator) error {\n\tacc.AddFields(\"measurement\",\n\t\tmap[string]interface{}{\n\t\t\t\"field\": 1,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"tag\": \"tag\",\n\t\t}, time.Unix(1234, 5678))\n\ti.metricProcessed <- true\n\treturn nil\n}\n\nfunc (*testInput) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (*testInput) Stop() {\n}\n\ntype serviceInput struct {\n\tServiceName string `toml:\"service_name\"`\n\tSecretToken string `toml:\"secret_token\"`\n\tSecretValue string `toml:\"secret_value\"`\n}\n\nfunc (*serviceInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (*serviceInput) Gather(acc telegraf.Accumulator) error {\n\tacc.AddFields(\"measurement\",\n\t\tmap[string]interface{}{\n\t\t\t\"field\": 1,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"tag\": \"tag\",\n\t\t}, time.Unix(1234, 5678))\n\n\treturn nil\n}\n\nfunc (*serviceInput) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (*serviceInput) Stop() {\n}\n"
  },
  {
    "path": "plugins/common/shim/output.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n)\n\n// AddOutput adds the input to the shim. Later calls to Run() will run this.\nfunc (s *Shim) AddOutput(output telegraf.Output) error {\n\tmodels.SetLoggerOnPlugin(output, s.Log())\n\tif p, ok := output.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to init input: %w\", err)\n\t\t}\n\t}\n\n\ts.Output = output\n\treturn nil\n}\n\nfunc (s *Shim) RunOutput() error {\n\t// Create a parser for receiving the metrics in line-protocol format\n\tparser := influx.Parser{}\n\tif err := parser.Init(); err != nil {\n\t\treturn fmt.Errorf(\"failed to create new parser: %w\", err)\n\t}\n\n\t// Connect the output\n\tif err := s.Output.Connect(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start processor: %w\", err)\n\t}\n\tdefer s.Output.Close()\n\n\t// Collect the metrics from stdin. Note, we need to flush the metrics\n\t// when the batch is full or after the configured time, whatever comes\n\t// first. We need to lock the batch as we run into race conditions\n\t// otherwise.\n\tvar mu sync.Mutex\n\tmetrics := make([]telegraf.Metric, 0, s.BatchSize)\n\n\t// Prepare the flush timer...\n\tflush := func(whole bool) {\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\n\t\t// Exit early if there is nothing to do\n\t\tif len(metrics) == 0 {\n\t\t\treturn\n\t\t}\n\n\t\t// Determine the threshold on when to stop flushing depending on the\n\t\t// given flag.\n\t\tvar threshold int\n\t\tif whole {\n\t\t\tthreshold = s.BatchSize\n\t\t}\n\n\t\t// Flush out the metrics in batches of the configured size until we\n\t\t// got all of them out or if there is less than a whole batch left.\n\t\tfor len(metrics) > 0 && len(metrics) >= threshold {\n\t\t\t// Write the metrics and remove the batch\n\t\t\tbatch := metrics[:min(len(metrics), s.BatchSize)]\n\t\t\tif err := s.Output.Write(batch); err != nil {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"Failed to write metrics: %s\\n\", err)\n\t\t\t}\n\t\t\tmetrics = metrics[len(batch):]\n\t\t}\n\t}\n\n\t// Setup the time-based flush\n\tvar timer *time.Timer\n\tif s.BatchTimeout > 0 {\n\t\ttimer = time.AfterFunc(s.BatchTimeout, func() { flush(false) })\n\t\tdefer func() {\n\t\t\tif timer != nil {\n\t\t\t\ttimer.Stop()\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Start the processing loop\n\tscanner := bufio.NewScanner(s.stdin)\n\tfor scanner.Scan() {\n\t\t// Read metrics from stdin\n\t\tm, err := parser.ParseLine(scanner.Text())\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(s.stderr, \"Failed to parse metric: %s\\n\", err)\n\t\t\tcontinue\n\t\t}\n\t\tmu.Lock()\n\t\tmetrics = append(metrics, m)\n\t\tshouldFlush := len(metrics) >= s.BatchSize\n\t\tmu.Unlock()\n\n\t\t// If we got more enough metrics to fill the batch flush it out and\n\t\t// reset the time-based guard.\n\t\tif shouldFlush {\n\t\t\tif timer != nil {\n\t\t\t\ttimer.Stop()\n\t\t\t}\n\t\t\tflush(true)\n\t\t\tif s.BatchTimeout > 0 {\n\t\t\t\ttimer = time.AfterFunc(s.BatchTimeout, func() { flush(false) })\n\t\t\t}\n\t\t}\n\t}\n\n\t// Output all remaining metrics\n\tif timer != nil {\n\t\ttimer.Stop()\n\t}\n\tflush(false)\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/shim/output_test.go",
    "content": "package shim\n\nimport (\n\t\"io\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestOutputShim(t *testing.T) {\n\to := &testOutput{}\n\n\tstdinReader, stdinWriter := io.Pipe()\n\n\ts := New()\n\ts.stdin = stdinReader\n\trequire.NoError(t, s.AddOutput(o))\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tif err := s.RunOutput(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tserializer := &influx.Serializer{}\n\trequire.NoError(t, serializer.Init())\n\n\tm := metric.New(\"thing\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"b\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"v\": 1,\n\t\t},\n\t\ttime.Now(),\n\t)\n\tb, err := serializer.Serialize(m)\n\trequire.NoError(t, err)\n\t_, err = stdinWriter.Write(b)\n\trequire.NoError(t, err)\n\trequire.NoError(t, stdinWriter.Close())\n\n\twg.Wait()\n\n\trequire.Len(t, o.MetricsWritten, 1)\n\ttestutil.RequireMetricEqual(t, m, o.MetricsWritten[0])\n}\n\nfunc TestOutputShimWithBatchSize(t *testing.T) {\n\to := &testOutput{}\n\n\tstdinReader, stdinWriter := io.Pipe()\n\n\t// Setup a shim with a batch size but no timeout\n\ts := New()\n\ts.stdin = stdinReader\n\ts.BatchSize = 5\n\ts.BatchTimeout = 0\n\trequire.NoError(t, s.AddOutput(o))\n\n\t// Start the output processing\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tif err := s.RunOutput(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\t// Serialize the test metric\n\tserializer := &influx.Serializer{}\n\trequire.NoError(t, serializer.Init())\n\tm := metric.New(\"thing\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"b\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"v\": 1,\n\t\t},\n\t\ttime.Now(),\n\t)\n\tpayload, err := serializer.Serialize(m)\n\trequire.NoError(t, err)\n\n\t// Write a few more metrics than the batch-size and check that we only get\n\t// a full batch before closing the input stream.\n\texpected := make([]telegraf.Metric, 0, s.BatchSize+3)\n\tfor range cap(expected) {\n\t\t_, err := stdinWriter.Write(payload)\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, m)\n\t}\n\n\t// Wait for the metrics to arrive\n\trequire.Eventually(t, func() bool {\n\t\treturn o.Count.Load() >= uint32(s.BatchSize)\n\t}, 3*time.Second, 100*time.Millisecond)\n\ttestutil.RequireMetricsEqual(t, expected[:s.BatchSize], o.MetricsWritten)\n\n\t// Closing the input should force the remaining metrics to be written\n\trequire.NoError(t, stdinWriter.Close())\n\twg.Wait()\n\ttestutil.RequireMetricsEqual(t, expected, o.MetricsWritten)\n}\n\nfunc TestOutputShimWithFlushTimeout(t *testing.T) {\n\to := &testOutput{}\n\n\tstdinReader, stdinWriter := io.Pipe()\n\n\t// Setup a shim with a batch size and a short timeout\n\ts := New()\n\ts.stdin = stdinReader\n\ts.BatchSize = 5\n\ts.BatchTimeout = 500 * time.Millisecond\n\trequire.NoError(t, s.AddOutput(o))\n\n\t// Start the output processing\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tif err := s.RunOutput(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\t// Serialize the test metric\n\tserializer := &influx.Serializer{}\n\trequire.NoError(t, serializer.Init())\n\tm := metric.New(\"thing\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"b\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"v\": 1,\n\t\t},\n\t\ttime.Now(),\n\t)\n\tpayload, err := serializer.Serialize(m)\n\trequire.NoError(t, err)\n\n\t// Write less metrics than the batch-size and check if the flush timeout\n\t// triggers..\n\texpected := make([]telegraf.Metric, 0, s.BatchSize-1)\n\tfor range cap(expected) {\n\t\t_, err := stdinWriter.Write(payload)\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, m)\n\t}\n\t// Wait for the batch to be flushed\n\trequire.Eventually(t, func() bool {\n\t\treturn o.Count.Load() >= uint32(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\ttestutil.RequireMetricsEqual(t, expected, o.MetricsWritten)\n\n\t// Closing the input should not change anything\n\trequire.NoError(t, stdinWriter.Close())\n\twg.Wait()\n\ttestutil.RequireMetricsEqual(t, expected, o.MetricsWritten)\n}\n\ntype testOutput struct {\n\tMetricsWritten []telegraf.Metric\n\tCount          atomic.Uint32\n}\n\nfunc (*testOutput) Connect() error {\n\treturn nil\n}\nfunc (*testOutput) Close() error {\n\treturn nil\n}\nfunc (o *testOutput) Write(metrics []telegraf.Metric) error {\n\to.MetricsWritten = append(o.MetricsWritten, metrics...)\n\to.Count.Store(uint32(len(o.MetricsWritten)))\n\treturn nil\n}\n\nfunc (*testOutput) SampleConfig() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "plugins/common/shim/processor.go",
    "content": "package shim\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/processors\"\n)\n\n// AddProcessor adds the processor to the shim. Later calls to Run() will run this.\nfunc (s *Shim) AddProcessor(processor telegraf.Processor) error {\n\tmodels.SetLoggerOnPlugin(processor, s.Log())\n\tp := processors.NewStreamingProcessorFromProcessor(processor)\n\treturn s.AddStreamingProcessor(p)\n}\n\n// AddStreamingProcessor adds the processor to the shim. Later calls to Run() will run this.\nfunc (s *Shim) AddStreamingProcessor(processor telegraf.StreamingProcessor) error {\n\tmodels.SetLoggerOnPlugin(processor, s.Log())\n\tif p, ok := processor.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to init input: %w\", err)\n\t\t}\n\t}\n\n\ts.Processor = processor\n\treturn nil\n}\n\nfunc (s *Shim) RunProcessor() error {\n\tacc := agent.NewAccumulator(s, s.metricCh)\n\tacc.SetPrecision(time.Nanosecond)\n\n\terr := s.Processor.Start(acc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start processor: %w\", err)\n\t}\n\n\twg := sync.WaitGroup{}\n\twg.Add(1)\n\tgo func() {\n\t\terr := s.writeProcessedMetrics()\n\t\tif err != nil {\n\t\t\ts.log.Warn(err.Error())\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tparser := influx.NewStreamParser(s.stdin)\n\tfor {\n\t\tm, err := parser.Next()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, influx.EOF) {\n\t\t\t\tbreak // stream ended\n\t\t\t}\n\t\t\tvar parseErr *influx.ParseError\n\t\t\tif errors.As(err, &parseErr) {\n\t\t\t\tfmt.Fprintf(s.stderr, \"Failed to parse metric: %s\\b\", parseErr)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfmt.Fprintf(s.stderr, \"Failure during reading stdin: %s\\b\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = s.Processor.Add(m, acc); err != nil {\n\t\t\tfmt.Fprintf(s.stderr, \"Failure during processing metric by processor: %v\\b\", err)\n\t\t}\n\t}\n\n\tclose(s.metricCh)\n\ts.Processor.Stop()\n\twg.Wait()\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/shim/processor_test.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\tserializers_influx \"github.com/influxdata/telegraf/plugins/serializers/influx\"\n)\n\nfunc TestProcessorShim(t *testing.T) {\n\ttestSendAndReceive(t, \"f1\", \"fv1\")\n}\n\nfunc TestProcessorShimWithLargerThanDefaultScannerBufferSize(t *testing.T) {\n\tletters := []rune(\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\tb := make([]rune, 0, bufio.MaxScanTokenSize*2)\n\tfor i := 0; i < bufio.MaxScanTokenSize*2; i++ {\n\t\tb = append(b, letters[rand.Intn(len(letters))])\n\t}\n\n\ttestSendAndReceive(t, \"f1\", string(b))\n}\n\nfunc testSendAndReceive(t *testing.T, fieldKey, fieldValue string) {\n\tp := &testProcessor{\"hi\", \"mom\"}\n\n\tstdinReader, stdinWriter := io.Pipe()\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\ts := New()\n\t// inject test into shim\n\ts.stdin = stdinReader\n\ts.stdout = stdoutWriter\n\terr := s.AddProcessor(p)\n\trequire.NoError(t, err)\n\n\twg := sync.WaitGroup{}\n\n\twg.Add(1)\n\tgo func() {\n\t\tif err := s.RunProcessor(); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tserializer := &serializers_influx.Serializer{}\n\trequire.NoError(t, serializer.Init())\n\n\tparser := influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tm := metric.New(\"thing\",\n\t\tmap[string]string{\n\t\t\t\"a\": \"b\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"v\":      1,\n\t\t\tfieldKey: fieldValue,\n\t\t},\n\t\ttime.Now(),\n\t)\n\tb, err := serializer.Serialize(m)\n\trequire.NoError(t, err)\n\t_, err = stdinWriter.Write(b)\n\trequire.NoError(t, err)\n\terr = stdinWriter.Close()\n\trequire.NoError(t, err)\n\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\tmOut, err := parser.ParseLine(out)\n\trequire.NoError(t, err)\n\n\tval, ok := mOut.GetTag(p.tagName)\n\trequire.True(t, ok)\n\trequire.Equal(t, p.tagValue, val)\n\tval2, ok := mOut.Fields()[fieldKey]\n\trequire.True(t, ok)\n\trequire.Equal(t, fieldValue, val2)\n\tgo func() {\n\t\tif _, err = io.ReadAll(r); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\twg.Wait()\n}\n\ntype testProcessor struct {\n\ttagName  string\n\ttagValue string\n}\n\nfunc (p *testProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric {\n\tfor _, m := range in {\n\t\tm.AddTag(p.tagName, p.tagValue)\n\t}\n\treturn in\n}\n\nfunc (*testProcessor) SampleConfig() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "plugins/common/shim/testdata/plugin.conf",
    "content": "[[inputs.test]]\n\tservice_name = \"awesome name\"\n\tsecret_token = \"${SECRET_TOKEN}\"\n\tsecret_value = \"$SECRET_VALUE\"\n"
  },
  {
    "path": "plugins/common/shim/testdata/processor.conf",
    "content": "[[processors.test_config_load]]\n  loaded = \"yep\""
  },
  {
    "path": "plugins/common/shim/testdata/special.conf",
    "content": "# testing custom field types\n[[inputs.test]]\n\tduration = \"3s\"\n  size = \"3MB\"\n  hex = 0x34"
  },
  {
    "path": "plugins/common/slog/adapter.go",
    "content": "package slog\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"log/slog\" //nolint:depguard // Required for wrapping internal logging facility\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// NewLogger creates telegraf.Logger adapter for slog.Logger\nfunc NewLogger(l telegraf.Logger) *slog.Logger {\n\treturn slog.New(&tlgHandler{Log: l})\n}\n\n// tlgHandler translates slog.Record into telegraf.Logger call\n// inspired by https://github.com/golang/example/blob/master/slog-handler-guide/README.md\ntype tlgHandler struct {\n\tattrs  []slog.Attr\n\tgroups []string\n\n\tLog telegraf.Logger\n}\n\n// Enabled implements slog.Handler interface\n// It interprets errors as errors and everything else as debug.\nfunc (h *tlgHandler) Enabled(_ context.Context, level slog.Level) bool {\n\tif level == slog.LevelError {\n\t\treturn h.Log.Level() >= telegraf.Error\n\t}\n\treturn h.Log.Level() >= telegraf.Debug\n}\n\n// Handle implements slog.Handler interface\n// It interprets errors as errors and everything else as debug.\nfunc (h *tlgHandler) Handle(_ context.Context, r slog.Record) error {\n\tattrs := make([]slog.Attr, 0, 2+len(h.attrs)+r.NumAttrs())\n\tattrs = append(attrs,\n\t\tslog.String(\"logger\", strings.Join(h.groups, \",\")),\n\t\tslog.String(\"message\", r.Message),\n\t)\n\tattrs = append(attrs, h.attrs...)\n\n\tr.Attrs(func(attr slog.Attr) bool {\n\t\tif v, ok := attr.Value.Any().(json.RawMessage); ok {\n\t\t\tattrs = append(attrs, slog.String(attr.Key, string(v)))\n\t\t\treturn true\n\t\t}\n\t\tattrs = append(attrs, attr)\n\t\treturn true\n\t})\n\n\tif r.Level == slog.LevelError {\n\t\th.Log.Error(attrs)\n\t} else {\n\t\th.Log.Debug(attrs)\n\t}\n\n\treturn nil\n}\n\n// WithAttrs implements slog.Handler interface\nfunc (h *tlgHandler) WithAttrs(attrs []slog.Attr) slog.Handler {\n\tnested := &tlgHandler{Log: h.Log}\n\tnested.attrs = append(nested.attrs, h.attrs...)\n\tnested.groups = append(nested.groups, h.groups...)\n\n\tfor _, attr := range attrs {\n\t\tif v, ok := attr.Value.Any().(json.RawMessage); ok {\n\t\t\tnested.attrs = append(nested.attrs, slog.String(attr.Key, string(v)))\n\t\t\tcontinue\n\t\t}\n\t\tnested.attrs = append(nested.attrs, attr)\n\t}\n\n\treturn nested\n}\n\n// WithGroup implements slog.Handler interface\nfunc (h *tlgHandler) WithGroup(name string) slog.Handler {\n\tnested := &tlgHandler{Log: h.Log}\n\tnested.attrs = append(nested.attrs, h.attrs...)\n\tnested.groups = append(nested.groups, h.groups...)\n\tnested.groups = append(nested.groups, name)\n\treturn nested\n}\n"
  },
  {
    "path": "plugins/common/snmp/config.go",
    "content": "package snmp\n\nimport (\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype ClientConfig struct {\n\t// Timeout to wait for a response.\n\tTimeout              config.Duration `toml:\"timeout\"`\n\tRetries              int             `toml:\"retries\"`\n\tVersion              uint8           `toml:\"version\"`\n\tUnconnectedUDPSocket bool            `toml:\"unconnected_udp_socket\"`\n\tGosnmpDebugLogger    telegraf.Logger `toml:\"-\"`\n\n\t// Parameters for Version 1 & 2\n\tCommunity string `toml:\"community\"`\n\n\t// Parameters for Version 2 & 3\n\tMaxRepetitions uint32 `toml:\"max_repetitions\"`\n\n\t// Parameters for Version 3\n\tContextName  string        `toml:\"context_name\"`\n\tSecLevel     string        `toml:\"sec_level\"`\n\tSecName      string        `toml:\"sec_name\"`\n\tAuthProtocol string        `toml:\"auth_protocol\"`\n\tAuthPassword config.Secret `toml:\"auth_password\"`\n\tPrivProtocol string        `toml:\"priv_protocol\"`\n\tPrivPassword config.Secret `toml:\"priv_password\"`\n\tEngineID     string        `toml:\"-\"`\n\tEngineBoots  uint32        `toml:\"-\"`\n\tEngineTime   uint32        `toml:\"-\"`\n\n\t// Path to mib files\n\tPath       []string `toml:\"path\"`\n\tTranslator string   `toml:\"-\"`\n}\n\nfunc DefaultClientConfig() *ClientConfig {\n\treturn &ClientConfig{\n\t\tTimeout:        config.Duration(5 * time.Second),\n\t\tRetries:        3,\n\t\tVersion:        2,\n\t\tPath:           []string{\"/usr/share/snmp/mibs\"},\n\t\tTranslator:     \"gosmi\",\n\t\tCommunity:      \"public\",\n\t\tMaxRepetitions: 10,\n\t\tSecLevel:       \"authNoPriv\",\n\t\tSecName:        \"myuser\",\n\t\tAuthProtocol:   \"MD5\",\n\t\tAuthPassword:   config.NewSecret([]byte(\"pass\")),\n\t}\n}\n"
  },
  {
    "path": "plugins/common/snmp/field.go",
    "content": "package snmp\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\n// Field holds the configuration for a Field to look up.\ntype Field struct {\n\t// Name will be the name of the field.\n\tName string\n\t// OID is prefix for this field. The plugin will perform a walk through all\n\t// OIDs with this as their parent. For each value found, the plugin will strip\n\t// off the OID prefix, and use the remainder as the index. For multiple fields\n\t// to show up in the same row, they must share the same index.\n\tOid string\n\t// OidIndexSuffix is the trailing sub-identifier on a table record OID that will be stripped off to get the record's index.\n\tOidIndexSuffix string\n\t// 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.\n\tOidIndexLength int\n\t// IsTag controls whether this OID is output as a tag or a value.\n\tIsTag bool\n\t// Conversion controls any type conversion that is done on the value.\n\t//  \"float\"/\"float(0)\" will convert the value into a float.\n\t//  \"float(X)\" will convert the value into a float, and then move the decimal before Xth right-most digit.\n\t//  \"int\" will convert the value into an integer.\n\t//  \"hwaddr\" will convert a 6-byte string to a MAC address.\n\t//  \"ipaddr\" will convert the value to an IPv4 or IPv6 address.\n\t//  \"enum\"/\"enum(1)\" will convert the value according to its syntax. (Only supported with gosmi translator)\n\t//  \"displayhint\" will format the value according to the textual convention. (Only supported with gosmi translator)\n\tConversion string\n\t// Translate tells if the value of the field should be snmptranslated\n\tTranslate bool\n\t// Secondary index table allows to merge data from two tables with different index\n\t//  that this filed will be used to join them. There can be only one secondary index table.\n\tSecondaryIndexTable bool\n\t// This field is using secondary index, and will be later merged with primary index\n\t//  using SecondaryIndexTable. SecondaryIndexTable and SecondaryIndexUse are exclusive.\n\tSecondaryIndexUse bool\n\t// Controls if entries from secondary table should be added or not if joining\n\t//  index is present or not. I set to true, means that join is outer, and\n\t//  index is prepended with \"Secondary.\" for missing values to avoid overlapping\n\t//  indexes from both tables.\n\t// Can be set per field or globally with SecondaryIndexTable, global true overrides\n\t//  per field false.\n\tSecondaryOuterJoin bool\n\n\tinitialized bool\n\ttranslator  Translator\n}\n\n// Init converts OID names to numbers, and sets the .Name attribute if unset.\nfunc (f *Field) Init(tr Translator) error {\n\tif f.initialized {\n\t\treturn nil\n\t}\n\n\tf.translator = tr\n\n\t// check if oid needs translation or name is not set\n\tif strings.ContainsAny(f.Oid, \":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\") || f.Name == \"\" {\n\t\t_, oidNum, oidText, conversion, err := f.translator.SnmpTranslate(f.Oid)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"translating: %w\", err)\n\t\t}\n\t\tf.Oid = oidNum\n\t\tif f.Name == \"\" {\n\t\t\tf.Name = oidText\n\t\t}\n\t\tif f.Conversion == \"\" {\n\t\t\tf.Conversion = conversion\n\t\t}\n\t}\n\n\tif f.SecondaryIndexTable && f.SecondaryIndexUse {\n\t\treturn errors.New(\"fields SecondaryIndexTable and UseSecondaryIndex are exclusive\")\n\t}\n\n\tif !f.SecondaryIndexTable && !f.SecondaryIndexUse && f.SecondaryOuterJoin {\n\t\treturn errors.New(\"field SecondaryOuterJoin set to true, but field is not being used in join\")\n\t}\n\n\tswitch f.Conversion {\n\tcase \"hwaddr\", \"enum(1)\":\n\t\tconfig.PrintOptionValueDeprecationNotice(\"inputs.snmp\", \"field.conversion\", f.Conversion, telegraf.DeprecationInfo{\n\t\t\tSince:  \"1.33.0\",\n\t\t\tNotice: \"Use 'displayhint' instead\",\n\t\t})\n\t}\n\n\tf.initialized = true\n\treturn nil\n}\n\n// Convert converts from any type according to the conv specification\nfunc (f *Field) Convert(ent gosnmp.SnmpPDU) (interface{}, error) {\n\tv := ent.Value\n\n\t// snmptranslate table field value here\n\tif f.Translate {\n\t\tif entOid, ok := v.(string); ok {\n\t\t\t_, _, oidText, _, err := f.translator.SnmpTranslate(entOid)\n\t\t\tif err == nil {\n\t\t\t\t// If no error translating, the original value should be replaced\n\t\t\t\tv = oidText\n\t\t\t}\n\t\t}\n\t}\n\n\tif f.Conversion == \"\" {\n\t\t// OctetStrings may contain hex data that needs its own conversion\n\t\tif ent.Type == gosnmp.OctetString && !utf8.Valid(v.([]byte)[:]) {\n\t\t\treturn hex.EncodeToString(v.([]byte)), nil\n\t\t}\n\t\tif bs, ok := v.([]byte); ok {\n\t\t\treturn string(bs), nil\n\t\t}\n\t\treturn v, nil\n\t}\n\n\tvar d int\n\tif _, err := fmt.Sscanf(f.Conversion, \"float(%d)\", &d); err == nil || f.Conversion == \"float\" {\n\t\tswitch vt := v.(type) {\n\t\tcase float32:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase float64:\n\t\t\tv = vt / math.Pow10(d)\n\t\tcase int:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase int8:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase int16:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase int32:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase int64:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase uint:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase uint8:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase uint16:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase uint32:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase uint64:\n\t\t\tv = float64(vt) / math.Pow10(d)\n\t\tcase []byte:\n\t\t\tvf, err := strconv.ParseFloat(string(vt), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to convert field to float with value %s: %w\", vt, err)\n\t\t\t}\n\t\t\tv = vf / math.Pow10(d)\n\t\tcase string:\n\t\t\tvf, err := strconv.ParseFloat(vt, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to convert field to float with value %s: %w\", vt, err)\n\t\t\t}\n\t\t\tv = vf / math.Pow10(d)\n\t\t}\n\t\treturn v, nil\n\t}\n\n\tif f.Conversion == \"int\" {\n\t\tvar err error\n\t\tswitch vt := v.(type) {\n\t\tcase float32:\n\t\t\tv = int64(vt)\n\t\tcase float64:\n\t\t\tv = int64(vt)\n\t\tcase int:\n\t\t\tv = int64(vt)\n\t\tcase int8:\n\t\t\tv = int64(vt)\n\t\tcase int16:\n\t\t\tv = int64(vt)\n\t\tcase int32:\n\t\t\tv = int64(vt)\n\t\tcase int64:\n\t\t\tv = vt\n\t\tcase uint:\n\t\t\tv = int64(vt)\n\t\tcase uint8:\n\t\t\tv = int64(vt)\n\t\tcase uint16:\n\t\t\tv = int64(vt)\n\t\tcase uint32:\n\t\t\tv = int64(vt)\n\t\tcase uint64:\n\t\t\tv = int64(vt)\n\t\tcase []byte:\n\t\t\tv, err = strconv.ParseInt(string(vt), 10, 64)\n\t\tcase string:\n\t\t\tv, err = strconv.ParseInt(vt, 10, 64)\n\t\t}\n\t\treturn v, err\n\t}\n\n\t// Deprecated: Use displayhint instead\n\tif f.Conversion == \"hwaddr\" {\n\t\tswitch vt := v.(type) {\n\t\tcase string:\n\t\t\tv = net.HardwareAddr(vt).String()\n\t\tcase []byte:\n\t\t\tv = net.HardwareAddr(vt).String()\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid type (%T) for hwaddr conversion\", vt)\n\t\t}\n\t\treturn v, nil\n\t}\n\n\tif f.Conversion == \"hex\" {\n\t\tswitch vt := v.(type) {\n\t\tcase string:\n\t\t\tswitch ent.Type {\n\t\t\tcase gosnmp.IPAddress:\n\t\t\t\tip := net.ParseIP(vt)\n\t\t\t\tif ip4 := ip.To4(); ip4 != nil {\n\t\t\t\t\tv = hex.EncodeToString(ip4)\n\t\t\t\t} else {\n\t\t\t\t\tv = hex.EncodeToString(ip)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unsupported Asn1BER (%#v) for hex conversion\", ent.Type)\n\t\t\t}\n\t\tcase []byte:\n\t\t\tv = hex.EncodeToString(vt)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unsupported type (%T) for hex conversion\", vt)\n\t\t}\n\t\treturn v, nil\n\t}\n\n\tsplit := strings.Split(f.Conversion, \":\")\n\tif split[0] == \"hextoint\" && len(split) == 3 {\n\t\tendian := split[1]\n\t\tbit := split[2]\n\n\t\tbv, ok := v.([]byte)\n\t\tif !ok {\n\t\t\treturn v, nil\n\t\t}\n\n\t\tvar b []byte\n\t\tswitch bit {\n\t\tcase \"uint64\":\n\t\t\tb = make([]byte, 8)\n\t\tcase \"uint32\":\n\t\t\tb = make([]byte, 4)\n\t\tcase \"uint16\":\n\t\t\tb = make([]byte, 2)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid bit value (%s) for hex to int conversion\", bit)\n\t\t}\n\t\tcopy(b, bv)\n\n\t\tvar byteOrder binary.ByteOrder\n\t\tswitch endian {\n\t\tcase \"LittleEndian\":\n\t\t\tbyteOrder = binary.LittleEndian\n\t\tcase \"BigEndian\":\n\t\t\tbyteOrder = binary.BigEndian\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid Endian value (%s) for hex to int conversion\", endian)\n\t\t}\n\n\t\tswitch bit {\n\t\tcase \"uint64\":\n\t\t\tv = byteOrder.Uint64(b)\n\t\tcase \"uint32\":\n\t\t\tv = byteOrder.Uint32(b)\n\t\tcase \"uint16\":\n\t\t\tv = byteOrder.Uint16(b)\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tif f.Conversion == \"ipaddr\" {\n\t\tvar ipbs []byte\n\n\t\tswitch vt := v.(type) {\n\t\tcase string:\n\t\t\tipbs = []byte(vt)\n\t\tcase []byte:\n\t\t\tipbs = vt\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid type (%T) for ipaddr conversion\", vt)\n\t\t}\n\n\t\tswitch len(ipbs) {\n\t\tcase 4, 16:\n\t\t\tv = net.IP(ipbs).String()\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid length (%d) for ipaddr conversion\", len(ipbs))\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tif f.Conversion == \"enum\" {\n\t\treturn f.translator.SnmpFormatEnum(ent.Name, ent.Value, false)\n\t}\n\n\t// Deprecated: Use displayhint instead\n\tif f.Conversion == \"enum(1)\" {\n\t\treturn f.translator.SnmpFormatEnum(ent.Name, ent.Value, true)\n\t}\n\n\tif f.Conversion == \"displayhint\" {\n\t\treturn f.translator.SnmpFormatDisplayHint(ent.Name, ent.Value)\n\t}\n\n\treturn nil, fmt.Errorf(\"invalid conversion type %q\", f.Conversion)\n}\n"
  },
  {
    "path": "plugins/common/snmp/field_test.go",
    "content": "package snmp\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestConvertDefault(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tent      gosnmp.SnmpPDU\n\t\texpected interface{}\n\t\terrmsg   string\n\t}{\n\t\t{\n\t\t\tname: \"integer\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.Integer,\n\t\t\t\tValue: int(2),\n\t\t\t},\n\t\t\texpected: 2,\n\t\t},\n\t\t{\n\t\t\tname: \"octet string with valid bytes\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64},\n\t\t\t},\n\t\t\texpected: \"Hello world\",\n\t\t},\n\t\t{\n\t\t\tname: \"octet string with invalid bytes\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1},\n\t\t\t},\n\t\t\texpected: \"84c807fffd3854c1\",\n\t\t},\n\t}\n\n\tf := Field{}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := f.Convert(tt.ent)\n\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n\n\tt.Run(\"invalid\", func(t *testing.T) {\n\t\tf.Conversion = \"invalid\"\n\t\tactual, err := f.Convert(gosnmp.SnmpPDU{})\n\n\t\trequire.Nil(t, actual)\n\t\trequire.ErrorContains(t, err, \"invalid conversion type\")\n\t})\n}\n\nfunc TestConvertHex(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tent      gosnmp.SnmpPDU\n\t\texpected interface{}\n\t\terrmsg   string\n\t}{\n\t\t{\n\t\t\tname: \"octet string with valid bytes\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64},\n\t\t\t},\n\t\t\texpected: \"48656c6c6f20776f726c64\",\n\t\t},\n\t\t{\n\t\t\tname: \"octet string with invalid bytes\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1},\n\t\t\t},\n\t\t\texpected: \"84c807fffd3854c1\",\n\t\t},\n\t\t{\n\t\t\tname: \"IPv4\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.IPAddress,\n\t\t\t\tValue: \"192.0.2.1\",\n\t\t\t},\n\t\t\texpected: \"c0000201\",\n\t\t},\n\t\t{\n\t\t\tname: \"IPv6\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.IPAddress,\n\t\t\t\tValue: \"2001:db8::1\",\n\t\t\t},\n\t\t\texpected: \"20010db8000000000000000000000001\",\n\t\t},\n\t\t{\n\t\t\tname: \"oid\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\tValue: \".1.2.3\",\n\t\t\t},\n\t\t\terrmsg: \"unsupported Asn1BER (0x6) for hex conversion\",\n\t\t},\n\t\t{\n\t\t\tname: \"integer\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.Integer,\n\t\t\t\tValue: int(2),\n\t\t\t},\n\t\t\terrmsg: \"unsupported type (int) for hex conversion\",\n\t\t},\n\t}\n\n\tf := Field{Conversion: \"hex\"}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := f.Convert(tt.ent)\n\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestConvertHextoint(t *testing.T) {\n\ttests := []struct {\n\t\tname       string\n\t\tconversion string\n\t\tent        gosnmp.SnmpPDU\n\t\texpected   interface{}\n\t\terrmsg     string\n\t}{\n\t\t{\n\t\t\tname:       \"empty\",\n\t\t\tconversion: \"hextoint:BigEndian:uint64\",\n\t\t\tent:        gosnmp.SnmpPDU{},\n\t\t\texpected:   nil,\n\t\t},\n\t\t{\n\t\t\tname:       \"big endian uint64\",\n\t\t\tconversion: \"hextoint:BigEndian:uint64\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1},\n\t\t\t},\n\t\t\texpected: uint64(0x84c807fffd3854c1),\n\t\t},\n\t\t{\n\t\t\tname:       \"big endian uint32\",\n\t\t\tconversion: \"hextoint:BigEndian:uint32\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff},\n\t\t\t},\n\t\t\texpected: uint32(0x84c807ff),\n\t\t},\n\t\t{\n\t\t\tname:       \"big endian uint16\",\n\t\t\tconversion: \"hextoint:BigEndian:uint16\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8},\n\t\t\t},\n\t\t\texpected: uint16(0x84c8),\n\t\t},\n\t\t{\n\t\t\tname:       \"big endian invalid\",\n\t\t\tconversion: \"hextoint:BigEndian:invalid\",\n\t\t\tent:        gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]uint8, 0)},\n\t\t\terrmsg:     \"invalid bit value\",\n\t\t},\n\t\t{\n\t\t\tname:       \"little endian uint64\",\n\t\t\tconversion: \"hextoint:LittleEndian:uint64\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1},\n\t\t\t},\n\t\t\texpected: uint64(0xc15438fdff07c884),\n\t\t},\n\t\t{\n\t\t\tname:       \"little endian uint32\",\n\t\t\tconversion: \"hextoint:LittleEndian:uint32\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8, 0x7, 0xff},\n\t\t\t},\n\t\t\texpected: uint32(0xff07c884),\n\t\t},\n\t\t{\n\t\t\tname:       \"little endian uint16\",\n\t\t\tconversion: \"hextoint:LittleEndian:uint16\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84, 0xc8},\n\t\t\t},\n\t\t\texpected: uint16(0xc884),\n\t\t},\n\t\t{\n\t\t\tname:       \"little endian single byte\",\n\t\t\tconversion: \"hextoint:LittleEndian:uint16\",\n\t\t\tent: gosnmp.SnmpPDU{\n\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\tValue: []byte{0x84},\n\t\t\t},\n\t\t\texpected: uint16(0x84),\n\t\t},\n\t\t{\n\t\t\tname:       \"little endian invalid\",\n\t\t\tconversion: \"hextoint:LittleEndian:invalid\",\n\t\t\tent:        gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]byte, 0)},\n\t\t\terrmsg:     \"invalid bit value\",\n\t\t},\n\t\t{\n\t\t\tname:       \"invalid\",\n\t\t\tconversion: \"hextoint:invalid:uint64\",\n\t\t\tent:        gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]byte, 0)},\n\t\t\terrmsg:     \"invalid Endian value\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tf := Field{Conversion: tt.conversion}\n\n\t\t\tactual, err := f.Convert(tt.ent)\n\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/snmp/logger.go",
    "content": "package snmp\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Logger struct {\n\tgs Connection // Reference to the SNMP connection as the host is not available initially\n\ttelegraf.Logger\n}\n\nfunc (l *Logger) Print(args ...interface{}) {\n\tmessage := fmt.Sprint(args...)\n\tif l.gs != nil && l.gs.Host() != \"\" {\n\t\tmessage = fmt.Sprintf(\"agent %s: %s\", l.gs.Host(), message)\n\t}\n\tl.Trace(message)\n}\nfunc (l *Logger) Printf(format string, args ...interface{}) {\n\tif l.gs != nil && l.gs.Host() != \"\" {\n\t\tformat = fmt.Sprintf(\"agent %s: %s\", l.gs.Host(), format)\n\t}\n\tl.Tracef(format, args...)\n}\n"
  },
  {
    "path": "plugins/common/snmp/mib_loader.go",
    "content": "package snmp\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/sleepinggenius2/gosmi\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// must init, append path for each directory, load module for every file\n// or gosmi will fail without saying why\nvar m sync.Mutex\nvar once sync.Once\nvar cache = make(map[string]bool)\n\ntype MibLoader interface {\n\t// appendPath takes the path of a directory\n\tappendPath(path string)\n\n\t// loadModule takes the name of a file in one of the\n\t// directories. Basename only, no relative or absolute path\n\tloadModule(path string) error\n}\n\ntype GosmiMibLoader struct{}\n\nfunc (*GosmiMibLoader) appendPath(path string) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tgosmi.AppendPath(path)\n}\n\nfunc (*GosmiMibLoader) loadModule(path string) error {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t_, err := gosmi.LoadModule(path)\n\treturn err\n}\n\n// LoadMibsFromPath will give all found folders to gosmi and load in all modules found in the folders\nfunc LoadMibsFromPath(paths []string, log telegraf.Logger, loader MibLoader) error {\n\tfolders, err := walkPaths(paths, log)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, path := range folders {\n\t\tloader.appendPath(path)\n\t\tmodules, err := os.ReadDir(path)\n\t\tif err != nil {\n\t\t\tlog.Warnf(\"Can't read directory %v\", modules)\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, entry := range modules {\n\t\t\tinfo, err := entry.Info()\n\t\t\tif err != nil {\n\t\t\t\tlog.Warnf(\"Couldn't get info for %v: %v\", entry.Name(), err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif info.Mode()&os.ModeSymlink != 0 {\n\t\t\t\tsymlink := filepath.Join(path, info.Name())\n\t\t\t\ttarget, err := filepath.EvalSymlinks(symlink)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warnf(\"Couldn't evaluate symbolic links for %v: %v\", symlink, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// replace symlink's info with the target's info\n\t\t\t\tinfo, err = os.Lstat(target)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warnf(\"Couldn't stat target %v: %v\", target, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif info.Mode().IsRegular() {\n\t\t\t\terr := loader.loadModule(info.Name())\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warnf(\"Couldn't load module %v: %v\", info.Name(), err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// should walk the paths given and find all folders\nfunc walkPaths(paths []string, log telegraf.Logger) ([]string, error) {\n\tonce.Do(gosmi.Init)\n\n\tfolders := make([]string, 0)\n\tfor _, mibPath := range paths {\n\t\t// Check if we loaded that path already and skip it if so\n\t\tm.Lock()\n\t\tcached := cache[mibPath]\n\t\tcache[mibPath] = true\n\t\tm.Unlock()\n\t\tif cached {\n\t\t\tcontinue\n\t\t}\n\n\t\terr := filepath.Walk(mibPath, func(path string, info os.FileInfo, err error) error {\n\t\t\tif info == nil {\n\t\t\t\tlog.Warnf(\"No mibs found\")\n\t\t\t\tif os.IsNotExist(err) {\n\t\t\t\t\tlog.Warnf(\"MIB path doesn't exist: %q\", mibPath)\n\t\t\t\t} else if err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif info.Mode()&os.ModeSymlink != 0 {\n\t\t\t\ttarget, err := filepath.EvalSymlinks(path)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warnf(\"Couldn't evaluate symbolic links for %v: %v\", path, err)\n\t\t\t\t}\n\t\t\t\tinfo, err = os.Lstat(target)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warnf(\"Couldn't stat target %v: %v\", target, err)\n\t\t\t\t}\n\t\t\t\tpath = target\n\t\t\t}\n\t\t\tif info.IsDir() {\n\t\t\t\tfolders = append(folders, path)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn folders, fmt.Errorf(\"couldn't walk path %q: %w\", mibPath, err)\n\t\t}\n\t}\n\treturn folders, nil\n}\n"
  },
  {
    "path": "plugins/common/snmp/mib_loader_test.go",
    "content": "package snmp\n\nimport (\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype TestingMibLoader struct {\n\tfolders []string\n\tfiles   []string\n}\n\nfunc (t *TestingMibLoader) appendPath(path string) {\n\tt.folders = append(t.folders, path)\n}\n\nfunc (t *TestingMibLoader) loadModule(path string) error {\n\tt.files = append(t.files, path)\n\treturn nil\n}\nfunc TestFolderLookup(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping on windows\")\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\tmibPath [][]string\n\t\tpaths   [][]string\n\t\tfiles   []string\n\t}{\n\t\t{\n\t\t\tname:    \"loading folders\",\n\t\t\tmibPath: [][]string{{\"testdata\", \"loadMibsFromPath\", \"root\"}},\n\t\t\tpaths: [][]string{\n\t\t\t\t{\"testdata\", \"loadMibsFromPath\", \"root\"},\n\t\t\t\t{\"testdata\", \"loadMibsFromPath\", \"root\", \"dirOne\"},\n\t\t\t\t{\"testdata\", \"loadMibsFromPath\", \"root\", \"dirOne\", \"dirTwo\"},\n\t\t\t\t{\"testdata\", \"loadMibsFromPath\", \"linkTarget\"},\n\t\t\t},\n\t\t\tfiles: []string{\"empty\", \"emptyFile\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tloader := TestingMibLoader{}\n\n\t\t\tvar givenPath []string\n\t\t\tfor _, paths := range tt.mibPath {\n\t\t\t\trootPath := filepath.Join(paths...)\n\t\t\t\tgivenPath = append(givenPath, rootPath)\n\t\t\t}\n\n\t\t\terr := LoadMibsFromPath(givenPath, testutil.Logger{}, &loader)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar folders []string\n\t\t\tfor _, pathSlice := range tt.paths {\n\t\t\t\tpath := filepath.Join(pathSlice...)\n\t\t\t\tfolders = append(folders, path)\n\t\t\t}\n\t\t\trequire.Equal(t, folders, loader.folders)\n\n\t\t\trequire.Equal(t, tt.files, loader.files)\n\t\t})\n\t}\n}\n\nfunc TestMissingMibPath(t *testing.T) {\n\tlog := testutil.Logger{}\n\tpath := []string{\"non-existing-directory\"}\n\trequire.NoError(t, LoadMibsFromPath(path, log, &GosmiMibLoader{}))\n}\n\nfunc BenchmarkMibLoading(b *testing.B) {\n\tlog := testutil.Logger{}\n\tpath := []string{\"testdata/gosmi\"}\n\tfor i := 0; i < b.N; i++ {\n\t\trequire.NoError(b, LoadMibsFromPath(path, log, &GosmiMibLoader{}))\n\t}\n}\n"
  },
  {
    "path": "plugins/common/snmp/table.go",
    "content": "package snmp\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gosnmp/gosnmp\"\n)\n\n// Table holds the configuration for a SNMP table.\ntype Table struct {\n\t// Name will be the name of the measurement.\n\tName string\n\n\t// Which tags to inherit from the top-level config.\n\tInheritTags []string\n\n\t// Adds each row's table index as a tag.\n\tIndexAsTag bool\n\n\t// Fields is the tags and values to look up.\n\tFields []Field `toml:\"field\"`\n\n\t// OID for automatic field population.\n\t// If provided, init() will populate Fields with all the table columns of the\n\t// given OID.\n\tOid string\n\n\tinitialized bool\n\ttranslator  Translator\n}\n\n// RTable is the resulting table built from a Table.\ntype RTable struct {\n\t// Name is the name of the field, copied from Table.Name.\n\tName string\n\t// Time is the time the table was built.\n\tTime time.Time\n\t// Rows are the rows that were found, one row for each table OID index found.\n\tRows []RTableRow\n}\n\n// RTableRow is the resulting row containing all the OID values which shared\n// the same index.\ntype RTableRow struct {\n\t// Tags are all the Field values which had IsTag=true.\n\tTags map[string]string\n\t// Fields are all the Field values which had IsTag=false.\n\tFields map[string]interface{}\n}\n\n// Init builds & initializes the nested fields.\nfunc (t *Table) Init(tr Translator) error {\n\t// makes sure oid or name is set in config file\n\t// otherwise snmp will produce metrics with an empty name\n\tif t.Oid == \"\" && t.Name == \"\" {\n\t\treturn errors.New(\"unnamed SNMP table in config file: one or both of the oid and name settings must be set\")\n\t}\n\n\tif t.initialized {\n\t\treturn nil\n\t}\n\n\tt.translator = tr\n\tif err := t.initBuild(); err != nil {\n\t\treturn err\n\t}\n\n\tsecondaryIndexTablePresent := false\n\t// initialize all the nested fields\n\tfor i := range t.Fields {\n\t\tif err := t.Fields[i].Init(t.translator); err != nil {\n\t\t\treturn fmt.Errorf(\"initializing field %s: %w\", t.Fields[i].Name, err)\n\t\t}\n\t\tif t.Fields[i].SecondaryIndexTable {\n\t\t\tif secondaryIndexTablePresent {\n\t\t\t\treturn errors.New(\"only one field can be SecondaryIndexTable\")\n\t\t\t}\n\t\t\tsecondaryIndexTablePresent = true\n\t\t}\n\t}\n\n\tt.initialized = true\n\treturn nil\n}\n\n// initBuild initializes the table if it has an OID configured. If so, the\n// net-snmp tools will be used to look up the OID and auto-populate the table's\n// fields.\nfunc (t *Table) initBuild() error {\n\tif t.Oid == \"\" {\n\t\treturn nil\n\t}\n\n\t_, _, oidText, fields, err := t.translator.SnmpTable(t.Oid)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif t.Name == \"\" {\n\t\tt.Name = oidText\n\t}\n\n\tknownOIDs := make(map[string]bool, len(t.Fields))\n\tfor _, f := range t.Fields {\n\t\tknownOIDs[f.Oid] = true\n\t}\n\tfor _, f := range fields {\n\t\tif !knownOIDs[f.Oid] {\n\t\t\tt.Fields = append(t.Fields, f)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Build retrieves all the fields specified in the table and constructs the RTable.\nfunc (t Table) Build(gs Connection, walk bool) (*RTable, error) {\n\trows := make(map[string]RTableRow)\n\n\t// translation table for secondary index (when performing join on two tables)\n\tsecIdxTab := make(map[string]string)\n\tsecGlobalOuterJoin := false\n\tfor i, f := range t.Fields {\n\t\tif f.SecondaryIndexTable {\n\t\t\tsecGlobalOuterJoin = f.SecondaryOuterJoin\n\t\t\tif i != 0 {\n\t\t\t\tt.Fields[0], t.Fields[i] = t.Fields[i], t.Fields[0]\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\ttagCount := 0\n\tfor _, f := range t.Fields {\n\t\tif f.IsTag {\n\t\t\ttagCount++\n\t\t}\n\n\t\tif len(f.Oid) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"cannot have empty OID on field %s\", f.Name)\n\t\t}\n\t\tvar oid string\n\t\tif f.Oid[0] == '.' {\n\t\t\toid = f.Oid\n\t\t} else {\n\t\t\t// make sure OID has \".\" because the BulkWalkAll results do, and the prefix needs to match\n\t\t\toid = \".\" + f.Oid\n\t\t}\n\n\t\t// ifv contains a mapping of table OID index to field value\n\t\tifv := make(map[string]interface{})\n\n\t\tif !walk {\n\t\t\t// This is used when fetching non-table fields. Fields configured a the top\n\t\t\t// scope of the plugin.\n\t\t\t// We fetch the fields directly, and add them to ifv as if the index were an\n\t\t\t// empty string. This results in all the non-table fields sharing the same\n\t\t\t// index, and being added on the same row.\n\t\t\tif pkt, err := gs.Get([]string{oid}); err != nil {\n\t\t\t\tif errors.Is(err, gosnmp.ErrUnknownSecurityLevel) {\n\t\t\t\t\treturn nil, errors.New(\"unknown security level (sec_level)\")\n\t\t\t\t} else if errors.Is(err, gosnmp.ErrUnknownUsername) {\n\t\t\t\t\treturn nil, errors.New(\"unknown username (sec_name)\")\n\t\t\t\t} else if errors.Is(err, gosnmp.ErrWrongDigest) {\n\t\t\t\t\treturn nil, errors.New(\"wrong digest (auth_protocol, auth_password)\")\n\t\t\t\t} else if errors.Is(err, gosnmp.ErrDecryption) {\n\t\t\t\t\treturn nil, errors.New(\"decryption error (priv_protocol, priv_password)\")\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"performing get on field %s: %w\", f.Name, err)\n\t\t\t} else if pkt != nil && len(pkt.Variables) > 0 && pkt.Variables[0].Type != gosnmp.NoSuchObject && pkt.Variables[0].Type != gosnmp.NoSuchInstance {\n\t\t\t\tent := pkt.Variables[0]\n\t\t\t\tfv, err := f.Convert(ent)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"converting %q (OID %s) for field %s: %w\", ent.Value, ent.Name, f.Name, err)\n\t\t\t\t}\n\t\t\t\tifv[\"\"] = fv\n\t\t\t}\n\t\t} else {\n\t\t\terr := gs.Walk(oid, func(ent gosnmp.SnmpPDU) error {\n\t\t\t\tif len(ent.Name) <= len(oid) || ent.Name[:len(oid)+1] != oid+\".\" {\n\t\t\t\t\treturn &walkError{} // break the walk\n\t\t\t\t}\n\n\t\t\t\tidx := ent.Name[len(oid):]\n\t\t\t\tif f.OidIndexSuffix != \"\" {\n\t\t\t\t\tif !strings.HasSuffix(idx, f.OidIndexSuffix) {\n\t\t\t\t\t\t// this entry doesn't match our OidIndexSuffix. skip it\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t\tidx = idx[:len(idx)-len(f.OidIndexSuffix)]\n\t\t\t\t}\n\t\t\t\tif f.OidIndexLength != 0 {\n\t\t\t\t\ti := f.OidIndexLength + 1 // leading separator\n\t\t\t\t\tidx = strings.Map(func(r rune) rune {\n\t\t\t\t\t\tif r == '.' {\n\t\t\t\t\t\t\ti--\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif i < 1 {\n\t\t\t\t\t\t\treturn -1\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn r\n\t\t\t\t\t}, idx)\n\t\t\t\t}\n\n\t\t\t\tfv, err := f.Convert(ent)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn &walkError{\n\t\t\t\t\t\tmsg: fmt.Sprintf(\"converting %q (OID %s) for field %s\", ent.Value, ent.Name, f.Name),\n\t\t\t\t\t\terr: err,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tifv[idx] = fv\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\t// Our callback always wraps errors in a walkError.\n\t\t\t\t// If this error isn't a walkError, we know it's not\n\t\t\t\t// from the callback\n\t\t\t\tvar walkErr *walkError\n\t\t\t\tif !errors.As(err, &walkErr) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"performing bulk walk for field %s: %w\", f.Name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor idx, v := range ifv {\n\t\t\tif f.SecondaryIndexUse {\n\t\t\t\tif newidx, ok := secIdxTab[idx]; ok {\n\t\t\t\t\tidx = newidx\n\t\t\t\t} else {\n\t\t\t\t\tif !secGlobalOuterJoin && !f.SecondaryOuterJoin {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tidx = \".Secondary\" + idx\n\t\t\t\t}\n\t\t\t}\n\t\t\trtr, ok := rows[idx]\n\t\t\tif !ok {\n\t\t\t\trtr = RTableRow{}\n\t\t\t\trtr.Tags = make(map[string]string)\n\t\t\t\trtr.Fields = make(map[string]interface{})\n\t\t\t\trows[idx] = rtr\n\t\t\t}\n\t\t\tif t.IndexAsTag && idx != \"\" {\n\t\t\t\tif idx[0] == '.' {\n\t\t\t\t\tidx = idx[1:]\n\t\t\t\t}\n\t\t\t\trtr.Tags[\"index\"] = idx\n\t\t\t}\n\t\t\t// don't add an empty string\n\t\t\tif vs, ok := v.(string); !ok || vs != \"\" {\n\t\t\t\tif f.IsTag {\n\t\t\t\t\tif ok {\n\t\t\t\t\t\trtr.Tags[f.Name] = vs\n\t\t\t\t\t} else {\n\t\t\t\t\t\trtr.Tags[f.Name] = fmt.Sprintf(\"%v\", v)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\trtr.Fields[f.Name] = v\n\t\t\t\t}\n\t\t\t\tif f.SecondaryIndexTable {\n\t\t\t\t\t// indexes are stored here with prepending \".\" so we need to add them if needed\n\t\t\t\t\tvar vss string\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tvss = \".\" + vs\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvss = fmt.Sprintf(\".%v\", v)\n\t\t\t\t\t}\n\t\t\t\t\tif idx[0] == '.' {\n\t\t\t\t\t\tsecIdxTab[vss] = idx\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsecIdxTab[vss] = \".\" + idx\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\trt := RTable{\n\t\tName: t.Name,\n\t\tTime: time.Now(), // TODO record time at start\n\t\tRows: make([]RTableRow, 0, len(rows)),\n\t}\n\tfor _, r := range rows {\n\t\trt.Rows = append(rt.Rows, r)\n\t}\n\treturn &rt, nil\n}\n\ntype walkError struct {\n\tmsg string\n\terr error\n}\n\nfunc (e *walkError) Error() string {\n\treturn e.msg\n}\n\nfunc (e *walkError) Unwrap() error {\n\treturn e.err\n}\n"
  },
  {
    "path": "plugins/common/snmp/table_test.go",
    "content": "package snmp\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTableJoin_walk(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t\"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t\"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t\"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 3)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n}\n\nfunc TestTableOuterJoin_walk(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t\tSecondaryOuterJoin:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t\"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t\"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t\"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trtr4 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\":    \"Secondary.0\",\n\t\t\t\"myfield4\": \"foo\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield5\": 1,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 4)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n\trequire.Contains(t, tb.Rows, rtr4)\n}\n\nfunc TestTableJoinNoIndexAsTag_walk(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: false,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t// \"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t// \"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t// \"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 3)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n}\n\nfunc TestTableBuild_walk_duplicateIndex(t *testing.T) {\n\t// Two values that differ only after the first index component should result in\n\t// the same truncated index when OidIndexLength is used.\n\tconn := &testSNMPConnection{\n\t\thost: \"localhost\",\n\t\tvalues: map[string]interface{}{\n\t\t\t\".1.0.0.0.1.1.0.0\": 0,\n\t\t\t\".1.0.0.0.1.1.0.1\": 1,\n\t\t\t\".1.0.0.0.1.2.0\":   2,\n\t\t},\n\t}\n\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:           \"myfield1\",\n\t\t\t\tOid:            \".1.0.0.0.1.1\",\n\t\t\t\tOidIndexLength: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.0.1.2\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(conn, true)\n\trequire.NoError(t, err)\n\trequire.Len(t, tb.Rows, 1)\n\trequire.Equal(t, \"0\", tb.Rows[0].Tags[\"index\"])\n\trequire.Contains(t, tb.Rows[0].Fields, \"myfield1\")\n\trequire.Contains(t, tb.Rows[0].Fields, \"myfield2\")\n}\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/bridgeMib",
    "content": "BRIDGE-MIB DEFINITIONS ::= BEGIN\n\n-- ---------------------------------------------------------- --\n-- MIB for IEEE 802.1D devices\n-- ---------------------------------------------------------- --\nIMPORTS\n    MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,\n    Counter32, Integer32, TimeTicks, mib-2, TEXTUAL-CONVENTION, MacAddress,\n    MODULE-COMPLIANCE, NOTIFICATION-GROUP, OBJECT-GROUP, InterfaceIndex\n        FROM bridgeMibImports;\n\ndot1dBridge MODULE-IDENTITY\n    LAST-UPDATED \"200509190000Z\"\n    ORGANIZATION \"IETF Bridge MIB Working Group\"\n    CONTACT-INFO\n        \"Email: bridge-mib@ietf.org\n\n                 K.C. Norseth (Editor)\n                 L-3 Communications\n            Tel: +1 801-594-2809\n          Email: kenyon.c.norseth@L-3com.com\n         Postal: 640 N. 2200 West.\n                 Salt Lake City, Utah 84116-0850\n\n                 Les Bell (Editor)\n                 3Com Europe Limited\n          Phone: +44 1442 438025\n          Email: elbell@ntlworld.com\n         Postal: 3Com Centre, Boundary Way\n                 Hemel Hempstead\n                 Herts.  HP2 7YU\n                 UK\n\n         Send comments to <bridge-mib@ietf.org>\"\n    DESCRIPTION\n        \"The Bridge MIB module for managing devices that support\n        IEEE 802.1D.\n\n        Copyright (C) The Internet Society (2005).  This version of\n        this MIB module is part of RFC 4188; see the RFC itself for\n        full legal notices.\"\n    REVISION     \"200509190000Z\"\n    DESCRIPTION\n         \"Third revision, published as part of RFC 4188.\n\n         The MIB module has been converted to SMIv2 format.\n         Conformance statements have been added and some\n         description and reference clauses have been updated.\n\n         The object dot1dStpPortPathCost32 was added to\n         support IEEE 802.1t and the permissible values of\n         dot1dStpPriority and dot1dStpPortPriority have been\n         clarified for bridges supporting IEEE 802.1t or\n         IEEE 802.1w.\n\n         The interpretation of dot1dStpTimeSinceTopologyChange\n         has been clarified for bridges supporting the Rapid\n         Spanning Tree Protocol (RSTP).\"\n    REVISION     \"199307310000Z\"\n    DESCRIPTION\n         \"Second revision, published as part of RFC 1493.\"\n    REVISION     \"199112310000Z\"\n    DESCRIPTION\n         \"Initial revision, published as part of RFC 1286.\"\n    ::= { mib-2 17 }\n\n-- ---------------------------------------------------------- --\n-- Textual Conventions\n-- ---------------------------------------------------------- --\n\nBridgeId ::= TEXTUAL-CONVENTION\n    STATUS      current\n    DESCRIPTION\n        \"The Bridge-Identifier, as used in the Spanning Tree\n        Protocol, to uniquely identify a bridge.  Its first two\n        octets (in network byte order) contain a priority value,\n        and its last 6 octets contain the MAC address used to\n        refer to a bridge in a unique fashion (typically, the\n        numerically smallest MAC address of all ports on the\n        bridge).\"\n    SYNTAX      OCTET STRING (SIZE (8))\n\nTimeout ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"d\"\n    STATUS      current\n    DESCRIPTION\n        \"A Spanning Tree Protocol (STP) timer in units of 1/100\n        seconds.  Several objects in this MIB module represent\n        values of timers used by the Spanning Tree Protocol.\n        In this MIB, these timers have values in units of\n        hundredths of a second (i.e., 1/100 secs).\n\n        These timers, when stored in a Spanning Tree Protocol's\n        BPDU, are in units of 1/256 seconds.  Note, however, that\n        802.1D-1998 specifies a settable granularity of no more\n        than one second for these timers.  To avoid ambiguity,\n        a conversion algorithm is defined below for converting\n        between the different units, which ensures a timer's\n        value is not distorted by multiple conversions.\n\n        To convert a Timeout value into a value in units of\n        1/256 seconds, the following algorithm should be used:\n\n            b = floor( (n * 256) / 100)\n\n        where:\n            floor   =  quotient [ignore remainder]\n            n is the value in 1/100 second units\n            b is the value in 1/256 second units\n\n        To convert the value from 1/256 second units back to\n        1/100 seconds, the following algorithm should be used:\n\n            n = ceiling( (b * 100) / 256)\n\n        where:\n            ceiling = quotient [if remainder is 0], or\n                      quotient + 1 [if remainder is nonzero]\n            n is the value in 1/100 second units\n\n            b is the value in 1/256 second units\n\n        Note: it is important that the arithmetic operations are\n        done in the order specified (i.e., multiply first,\n        divide second).\"\n    SYNTAX      Integer32\n\n-- ---------------------------------------------------------- --\n-- subtrees in the Bridge MIB\n-- ---------------------------------------------------------- --\n\ndot1dNotifications  OBJECT IDENTIFIER ::= { dot1dBridge 0 }\n\ndot1dBase           OBJECT IDENTIFIER ::= { dot1dBridge 1 }\ndot1dStp            OBJECT IDENTIFIER ::= { dot1dBridge 2 }\n\ndot1dSr             OBJECT IDENTIFIER ::= { dot1dBridge 3 }\n-- documented in RFC 1525\n\ndot1dTp             OBJECT IDENTIFIER ::= { dot1dBridge 4 }\ndot1dStatic         OBJECT IDENTIFIER ::= { dot1dBridge 5 }\n\n-- Subtrees used by Bridge MIB Extensions:\n--      pBridgeMIB  MODULE-IDENTITY   ::= { dot1dBridge 6 }\n--      qBridgeMIB  MODULE-IDENTITY   ::= { dot1dBridge 7 }\n-- Note that the practice of registering related MIB modules\n-- below dot1dBridge has been discouraged since there is no\n-- robust mechanism to track such registrations.\n\ndot1dConformance    OBJECT IDENTIFIER ::= { dot1dBridge 8 }\n\n-- ---------------------------------------------------------- --\n-- the dot1dBase subtree\n-- ---------------------------------------------------------- --\n-- Implementation of the dot1dBase subtree is mandatory for all\n-- bridges.\n-- ---------------------------------------------------------- --\n\ndot1dBaseBridgeAddress OBJECT-TYPE\n    SYNTAX      MacAddress\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The MAC address used by this bridge when it must be\n        referred to in a unique fashion.  It is recommended\n        that this be the numerically smallest MAC address of\n        all ports that belong to this bridge.  However, it is only\n\n        required to be unique.  When concatenated with\n        dot1dStpPriority, a unique BridgeIdentifier is formed,\n        which is used in the Spanning Tree Protocol.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clauses 14.4.1.1.3 and 7.12.5\"\n    ::= { dot1dBase 1 }\n\ndot1dBaseNumPorts OBJECT-TYPE\n    SYNTAX      Integer32\n    UNITS       \"ports\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of ports controlled by this bridging\n        entity.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.4.1.1.3\"\n    ::= { dot1dBase 2 }\n\ndot1dBaseType OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    unknown(1),\n                    transparent-only(2),\n                    sourceroute-only(3),\n                    srt(4)\n                }\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"Indicates what type of bridging this bridge can\n        perform.  If a bridge is actually performing a\n        certain type of bridging, this will be indicated by\n        entries in the port table for the given type.\"\n    ::= { dot1dBase 3 }\n\n-- ---------------------------------------------------------- --\n-- The Generic Bridge Port Table\n-- ---------------------------------------------------------- --\ndot1dBasePortTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF Dot1dBasePortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A table that contains generic information about every\n        port that is associated with this bridge.  Transparent,\n        source-route, and srt ports are included.\"\n    ::= { dot1dBase 4 }\n\ndot1dBasePortEntry OBJECT-TYPE\n    SYNTAX      Dot1dBasePortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A list of information for each port of the bridge.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.4.2, 14.6.1\"\n    INDEX  { dot1dBasePort }\n    ::= { dot1dBasePortTable 1 }\n\nDot1dBasePortEntry ::=\n    SEQUENCE {\n        dot1dBasePort\n            Integer32,\n        dot1dBasePortIfIndex\n            InterfaceIndex,\n        dot1dBasePortCircuit\n            OBJECT IDENTIFIER,\n        dot1dBasePortDelayExceededDiscards\n            Counter32,\n        dot1dBasePortMtuExceededDiscards\n            Counter32\n    }\n\ndot1dBasePort OBJECT-TYPE\n    SYNTAX      Integer32 (1..65535)\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The port number of the port for which this entry\n        contains bridge management information.\"\n    ::= { dot1dBasePortEntry 1 }\n\ndot1dBasePortIfIndex OBJECT-TYPE\n    SYNTAX      InterfaceIndex\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The value of the instance of the ifIndex object,\n        defined in IF-MIB, for the interface corresponding\n        to this port.\"\n    ::= { dot1dBasePortEntry 2 }\n\ndot1dBasePortCircuit OBJECT-TYPE\n    SYNTAX      OBJECT IDENTIFIER\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"For a port that (potentially) has the same value of\n        dot1dBasePortIfIndex as another port on the same bridge.\n        This object contains the name of an object instance\n        unique to this port.  For example, in the case where\n        multiple ports correspond one-to-one with multiple X.25\n        virtual circuits, this value might identify an (e.g.,\n        the first) object instance associated with the X.25\n        virtual circuit corresponding to this port.\n\n        For a port which has a unique value of\n        dot1dBasePortIfIndex, this object can have the value\n        { 0 0 }.\"\n    ::= { dot1dBasePortEntry 3 }\n\ndot1dBasePortDelayExceededDiscards OBJECT-TYPE\n    SYNTAX      Counter32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of frames discarded by this port due\n        to excessive transit delay through the bridge.  It\n        is incremented by both transparent and source\n        route bridges.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.6.1.1.3\"\n    ::= { dot1dBasePortEntry 4 }\n\ndot1dBasePortMtuExceededDiscards OBJECT-TYPE\n    SYNTAX      Counter32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of frames discarded by this port due\n        to an excessive size.  It is incremented by both\n        transparent and source route bridges.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.6.1.1.3\"\n    ::= { dot1dBasePortEntry 5 }\n\n-- ---------------------------------------------------------- --\n-- the dot1dStp subtree\n-- ---------------------------------------------------------- --\n-- Implementation of the dot1dStp subtree is optional.  It is\n-- implemented by those bridges that support the Spanning Tree\n-- Protocol.\n-- ---------------------------------------------------------- --\n\ndot1dStpProtocolSpecification OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    unknown(1),\n                    decLb100(2),\n                    ieee8021d(3)\n                }\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"An indication of what version of the Spanning Tree\n        Protocol is being run.  The value 'decLb100(2)'\n        indicates the DEC LANbridge 100 Spanning Tree protocol.\n        IEEE 802.1D implementations will return 'ieee8021d(3)'.\n        If future versions of the IEEE Spanning Tree Protocol\n        that are incompatible with the current version\n        are released a new value will be defined.\"\n    ::= { dot1dStp 1 }\n\ndot1dStpPriority OBJECT-TYPE\n    SYNTAX      Integer32 (0..65535)\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The value of the write-able portion of the Bridge ID\n        (i.e., the first two octets of the (8 octet long) Bridge\n        ID).  The other (last) 6 octets of the Bridge ID are\n        given by the value of dot1dBaseBridgeAddress.\n        On bridges supporting IEEE 802.1t or IEEE 802.1w,\n        permissible values are 0-61440, in steps of 4096.\"\n    REFERENCE\n        \"IEEE 802.1D-1998 clause 8.10.2, Table 8-4,\n        IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3.\"\n    ::= { dot1dStp 2 }\n\ndot1dStpTimeSinceTopologyChange OBJECT-TYPE\n    SYNTAX      TimeTicks\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The time (in hundredths of a second) since the\n        last time a topology change was detected by the\n        bridge entity.\n        For RSTP, this reports the time since the tcWhile\n        timer for any port on this Bridge was nonzero.\"\n    REFERENCE\n        \"IEEE 802.1D-1998 clause 14.8.1.1.,\n        IEEE 802.1w clause 14.8.1.1.\"\n    ::= { dot1dStp 3 }\n\ndot1dStpTopChanges OBJECT-TYPE\n    SYNTAX      Counter32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The total number of topology changes detected by\n        this bridge since the management entity was last\n        reset or initialized.\"\n    REFERENCE\n        \"IEEE 802.1D-1998 clause 14.8.1.1.\"\n    ::= { dot1dStp 4 }\n\ndot1dStpDesignatedRoot OBJECT-TYPE\n    SYNTAX      BridgeId\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The bridge identifier of the root of the spanning\n        tree, as determined by the Spanning Tree Protocol,\n        as executed by this node.  This value is used as\n        the Root Identifier parameter in all Configuration\n        Bridge PDUs originated by this node.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.1\"\n    ::= { dot1dStp 5 }\n\ndot1dStpRootCost OBJECT-TYPE\n    SYNTAX      Integer32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The cost of the path to the root as seen from\n        this bridge.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.2\"\n    ::= { dot1dStp 6 }\n\ndot1dStpRootPort OBJECT-TYPE\n    SYNTAX      Integer32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The port number of the port that offers the lowest\n        cost path from this bridge to the root bridge.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.3\"\n    ::= { dot1dStp 7 }\n\ndot1dStpMaxAge OBJECT-TYPE\n    SYNTAX      Timeout\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The maximum age of Spanning Tree Protocol information\n        learned from the network on any port before it is\n        discarded, in units of hundredths of a second.  This is\n        the actual value that this bridge is currently using.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.4\"\n    ::= { dot1dStp 8 }\n\ndot1dStpHelloTime OBJECT-TYPE\n    SYNTAX      Timeout\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The amount of time between the transmission of\n        Configuration bridge PDUs by this node on any port when\n        it is the root of the spanning tree, or trying to become\n        so, in units of hundredths of a second.  This is the\n        actual value that this bridge is currently using.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.5\"\n    ::= { dot1dStp 9 }\n\ndot1dStpHoldTime OBJECT-TYPE\n    SYNTAX      Integer32\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"This time value determines the interval length\n        during which no more than two Configuration bridge\n        PDUs shall be transmitted by this node, in units\n        of hundredths of a second.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.14\"\n    ::= { dot1dStp 10 }\n\ndot1dStpForwardDelay OBJECT-TYPE\n    SYNTAX      Timeout\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"This time value, measured in units of hundredths of a\n        second, controls how fast a port changes its spanning\n        state when moving towards the Forwarding state.  The\n        value determines how long the port stays in each of the\n        Listening and Learning states, which precede the\n        Forwarding state.  This value is also used when a\n        topology change has been detected and is underway, to\n        age all dynamic entries in the Forwarding Database.\n        [Note that this value is the one that this bridge is\n        currently using, in contrast to\n        dot1dStpBridgeForwardDelay, which is the value that this\n        bridge and all others would start using if/when this\n        bridge were to become the root.]\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.6\"\n    ::= { dot1dStp 11 }\n\ndot1dStpBridgeMaxAge OBJECT-TYPE\n    SYNTAX      Timeout (600..4000)\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The value that all bridges use for MaxAge when this\n        bridge is acting as the root.  Note that 802.1D-1998\n        specifies that the range for this parameter is related\n        to the value of dot1dStpBridgeHelloTime.  The\n        granularity of this timer is specified by 802.1D-1998 to\n        be 1 second.  An agent may return a badValue error if a\n        set is attempted to a value that is not a whole number\n        of seconds.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.8\"\n    ::= { dot1dStp 12 }\n\ndot1dStpBridgeHelloTime OBJECT-TYPE\n    SYNTAX      Timeout (100..1000)\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The value that all bridges use for HelloTime when this\n        bridge is acting as the root.  The granularity of this\n        timer is specified by 802.1D-1998 to be 1 second.  An\n        agent may return a badValue error if a set is attempted\n\n        to a value that is not a whole number of seconds.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.9\"\n    ::= { dot1dStp 13 }\n\ndot1dStpBridgeForwardDelay OBJECT-TYPE\n    SYNTAX      Timeout (400..3000)\n    UNITS       \"centi-seconds\"\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The value that all bridges use for ForwardDelay when\n        this bridge is acting as the root.  Note that\n        802.1D-1998 specifies that the range for this parameter\n        is related to the value of dot1dStpBridgeMaxAge.  The\n        granularity of this timer is specified by 802.1D-1998 to\n        be 1 second.  An agent may return a badValue error if a\n        set is attempted to a value that is not a whole number\n        of seconds.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.3.10\"\n    ::= { dot1dStp 14 }\n\n-- ---------------------------------------------------------- --\n-- The Spanning Tree Port Table\n-- ---------------------------------------------------------- --\n\ndot1dStpPortTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF Dot1dStpPortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A table that contains port-specific information\n        for the Spanning Tree Protocol.\"\n    ::= { dot1dStp 15 }\n\ndot1dStpPortEntry OBJECT-TYPE\n    SYNTAX      Dot1dStpPortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A list of information maintained by every port about\n        the Spanning Tree Protocol state for that port.\"\n    INDEX   { dot1dStpPort }\n    ::= { dot1dStpPortTable 1 }\n\nDot1dStpPortEntry ::=\n    SEQUENCE {\n\n        dot1dStpPort\n            Integer32,\n        dot1dStpPortPriority\n            Integer32,\n        dot1dStpPortState\n            INTEGER,\n        dot1dStpPortEnable\n            INTEGER,\n        dot1dStpPortPathCost\n            Integer32,\n        dot1dStpPortDesignatedRoot\n            BridgeId,\n        dot1dStpPortDesignatedCost\n            Integer32,\n        dot1dStpPortDesignatedBridge\n            BridgeId,\n        dot1dStpPortDesignatedPort\n            OCTET STRING,\n        dot1dStpPortForwardTransitions\n            Counter32,\n        dot1dStpPortPathCost32\n            Integer32\n    }\n\ndot1dStpPort OBJECT-TYPE\n    SYNTAX      Integer32 (1..65535)\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The port number of the port for which this entry\n        contains Spanning Tree Protocol management information.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.8.2.1.2\"\n    ::= { dot1dStpPortEntry 1 }\n\ndot1dStpPortPriority OBJECT-TYPE\n    SYNTAX      Integer32 (0..255)\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The value of the priority field that is contained in\n        the first (in network byte order) octet of the (2 octet\n        long) Port ID.  The other octet of the Port ID is given\n        by the value of dot1dStpPort.\n        On bridges supporting IEEE 802.1t or IEEE 802.1w,\n        permissible values are 0-240, in steps of 16.\"\n    REFERENCE\n        \"IEEE 802.1D-1998 clause 8.10.2, Table 8-4,\n        IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3.\"\n    ::= { dot1dStpPortEntry 2 }\n\ndot1dStpPortState OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    disabled(1),\n                    blocking(2),\n                    listening(3),\n                    learning(4),\n                    forwarding(5),\n                    broken(6)\n                }\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The port's current state, as defined by application of\n        the Spanning Tree Protocol.  This state controls what\n        action a port takes on reception of a frame.  If the\n        bridge has detected a port that is malfunctioning, it\n        will place that port into the broken(6) state.  For\n        ports that are disabled (see dot1dStpPortEnable), this\n        object will have a value of disabled(1).\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.2\"\n    ::= { dot1dStpPortEntry 3 }\n\ndot1dStpPortEnable OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    enabled(1),\n                    disabled(2)\n                }\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The enabled/disabled status of the port.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.2\"\n    ::= { dot1dStpPortEntry 4 }\n\ndot1dStpPortPathCost OBJECT-TYPE\n    SYNTAX      Integer32 (1..65535)\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The contribution of this port to the path cost of\n        paths towards the spanning tree root which include\n        this port.  802.1D-1998 recommends that the default\n        value of this parameter be in inverse proportion to\n\n        the speed of the attached LAN.\n\n        New implementations should support dot1dStpPortPathCost32.\n        If the port path costs exceeds the maximum value of this\n        object then this object should report the maximum value,\n        namely 65535.  Applications should try to read the\n        dot1dStpPortPathCost32 object if this object reports\n        the maximum value.\"\n    REFERENCE \"IEEE 802.1D-1998: clause 8.5.5.3\"\n        ::= { dot1dStpPortEntry 5 }\n\ndot1dStpPortDesignatedRoot OBJECT-TYPE\n    SYNTAX      BridgeId\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The unique Bridge Identifier of the Bridge\n        recorded as the Root in the Configuration BPDUs\n        transmitted by the Designated Bridge for the\n        segment to which the port is attached.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.4\"\n    ::= { dot1dStpPortEntry 6 }\n\ndot1dStpPortDesignatedCost OBJECT-TYPE\n    SYNTAX      Integer32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The path cost of the Designated Port of the segment\n        connected to this port.  This value is compared to the\n        Root Path Cost field in received bridge PDUs.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.5\"\n    ::= { dot1dStpPortEntry 7 }\n\ndot1dStpPortDesignatedBridge OBJECT-TYPE\n    SYNTAX      BridgeId\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The Bridge Identifier of the bridge that this\n        port considers to be the Designated Bridge for\n        this port's segment.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.6\"\n    ::= { dot1dStpPortEntry 8 }\n\ndot1dStpPortDesignatedPort OBJECT-TYPE\n    SYNTAX      OCTET STRING (SIZE (2))\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The Port Identifier of the port on the Designated\n        Bridge for this port's segment.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 8.5.5.7\"\n    ::= { dot1dStpPortEntry 9 }\n\ndot1dStpPortForwardTransitions OBJECT-TYPE\n    SYNTAX      Counter32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of times this port has transitioned\n        from the Learning state to the Forwarding state.\"\n    ::= { dot1dStpPortEntry 10 }\n\ndot1dStpPortPathCost32 OBJECT-TYPE\n    SYNTAX      Integer32 (1..200000000)\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The contribution of this port to the path cost of\n        paths towards the spanning tree root which include\n        this port.  802.1D-1998 recommends that the default\n        value of this parameter be in inverse proportion to\n        the speed of the attached LAN.\n\n        This object replaces dot1dStpPortPathCost to support\n        IEEE 802.1t.\"\n    REFERENCE\n        \"IEEE 802.1t clause 8.10.2, Table 8-5.\"\n    ::= { dot1dStpPortEntry 11 }\n\n-- ---------------------------------------------------------- --\n-- the dot1dTp subtree\n-- ---------------------------------------------------------- --\n-- Implementation of the dot1dTp subtree is optional.  It is\n-- implemented by those bridges that support the transparent\n-- bridging mode.  A transparent or SRT bridge will implement\n-- this subtree.\n-- ---------------------------------------------------------- --\n\ndot1dTpLearnedEntryDiscards OBJECT-TYPE\n    SYNTAX      Counter32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The total number of Forwarding Database entries that\n        have been or would have been learned, but have been\n        discarded due to a lack of storage space in the\n        Forwarding Database.  If this counter is increasing, it\n        indicates that the Forwarding Database is regularly\n        becoming full (a condition that has unpleasant\n        performance effects on the subnetwork).  If this counter\n        has a significant value but is not presently increasing,\n        it indicates that the problem has been occurring but is\n        not persistent.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.7.1.1.3\"\n    ::= { dot1dTp 1 }\n\ndot1dTpAgingTime OBJECT-TYPE\n    SYNTAX      Integer32 (10..1000000)\n    UNITS       \"seconds\"\n    MAX-ACCESS  read-write\n    STATUS      current\n    DESCRIPTION\n        \"The timeout period in seconds for aging out\n        dynamically-learned forwarding information.\n        802.1D-1998 recommends a default of 300 seconds.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.7.1.1.3\"\n    ::= { dot1dTp 2 }\n\n-- ---------------------------------------------------------- --\n--  The Forwarding Database for Transparent Bridges\n-- ---------------------------------------------------------- --\n\ndot1dTpFdbTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF Dot1dTpFdbEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A table that contains information about unicast\n        entries for which the bridge has forwarding and/or\n        filtering information.  This information is used\n        by the transparent bridging function in\n        determining how to propagate a received frame.\"\n    ::= { dot1dTp 3 }\n\ndot1dTpFdbEntry OBJECT-TYPE\n    SYNTAX      Dot1dTpFdbEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"Information about a specific unicast MAC address\n        for which the bridge has some forwarding and/or\n        filtering information.\"\n    INDEX   { dot1dTpFdbAddress }\n    ::= { dot1dTpFdbTable 1 }\n\nDot1dTpFdbEntry ::=\n    SEQUENCE {\n        dot1dTpFdbAddress\n            MacAddress,\n        dot1dTpFdbPort\n            Integer32,\n        dot1dTpFdbStatus\n            INTEGER\n    }\n\ndot1dTpFdbAddress OBJECT-TYPE\n    SYNTAX      MacAddress\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"A unicast MAC address for which the bridge has\n        forwarding and/or filtering information.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 7.9.1, 7.9.2\"\n    ::= { dot1dTpFdbEntry 1 }\n\ndot1dTpFdbPort OBJECT-TYPE\n    SYNTAX      Integer32\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"Either the value '0', or the port number of the port on\n        which a frame having a source address equal to the value\n        of the corresponding instance of dot1dTpFdbAddress has\n        been seen.  A value of '0' indicates that the port\n        number has not been learned, but that the bridge does\n        have some forwarding/filtering information about this\n        address (e.g., in the dot1dStaticTable).  Implementors\n        are encouraged to assign the port value to this object\n        whenever it is learned, even for addresses for which the\n        corresponding value of dot1dTpFdbStatus is not\n        learned(3).\"\n    ::= { dot1dTpFdbEntry 2 }\n\ndot1dTpFdbStatus OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    other(1),\n                    invalid(2),\n                    learned(3),\n                    self(4),\n                    mgmt(5)\n                }\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The status of this entry.  The meanings of the\n        values are:\n            other(1) - none of the following.  This would\n                include the case where some other MIB object\n                (not the corresponding instance of\n                dot1dTpFdbPort, nor an entry in the\n                dot1dStaticTable) is being used to determine if\n                and how frames addressed to the value of the\n                corresponding instance of dot1dTpFdbAddress are\n                being forwarded.\n            invalid(2) - this entry is no longer valid (e.g.,\n                it was learned but has since aged out), but has\n                not yet been flushed from the table.\n            learned(3) - the value of the corresponding instance\n                of dot1dTpFdbPort was learned, and is being\n                used.\n            self(4) - the value of the corresponding instance of\n                dot1dTpFdbAddress represents one of the bridge's\n                addresses.  The corresponding instance of\n                dot1dTpFdbPort indicates which of the bridge's\n                ports has this address.\n            mgmt(5) - the value of the corresponding instance of\n                dot1dTpFdbAddress is also the value of an\n                existing instance of dot1dStaticAddress.\"\n    ::= { dot1dTpFdbEntry 3 }\n\n-- ---------------------------------------------------------- --\n--  Port Table for Transparent Bridges\n-- ---------------------------------------------------------- --\n\ndot1dTpPortTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF Dot1dTpPortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A table that contains information about every port that\n        is associated with this transparent bridge.\"\n    ::= { dot1dTp 4 }\n\ndot1dTpPortEntry OBJECT-TYPE\n    SYNTAX      Dot1dTpPortEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A list of information for each port of a transparent\n        bridge.\"\n    INDEX   { dot1dTpPort }\n    ::= { dot1dTpPortTable 1 }\n\nDot1dTpPortEntry ::=\n    SEQUENCE {\n        dot1dTpPort\n            Integer32,\n        dot1dTpPortMaxInfo\n            Integer32,\n        dot1dTpPortInFrames\n            Counter32,\n        dot1dTpPortOutFrames\n            Counter32,\n        dot1dTpPortInDiscards\n            Counter32\n    }\n\ndot1dTpPort OBJECT-TYPE\n    SYNTAX      Integer32 (1..65535)\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The port number of the port for which this entry\n        contains Transparent bridging management information.\"\n    ::= { dot1dTpPortEntry 1 }\n\n-- It would be nice if we could use ifMtu as the size of the\n-- largest INFO field, but we can't because ifMtu is defined\n-- to be the size that the (inter-)network layer can use, which\n-- can differ from the MAC layer (especially if several layers\n-- of encapsulation are used).\n\ndot1dTpPortMaxInfo OBJECT-TYPE\n    SYNTAX      Integer32\n    UNITS       \"bytes\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The maximum size of the INFO (non-MAC) field that\n\n        this port will receive or transmit.\"\n    ::= { dot1dTpPortEntry 2 }\n\ndot1dTpPortInFrames OBJECT-TYPE\n    SYNTAX      Counter32\n    UNITS       \"frames\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of frames that have been received by this\n        port from its segment.  Note that a frame received on the\n        interface corresponding to this port is only counted by\n        this object if and only if it is for a protocol being\n        processed by the local bridging function, including\n        bridge management frames.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.6.1.1.3\"\n    ::= { dot1dTpPortEntry 3 }\n\ndot1dTpPortOutFrames OBJECT-TYPE\n    SYNTAX      Counter32\n    UNITS       \"frames\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"The number of frames that have been transmitted by this\n        port to its segment.  Note that a frame transmitted on\n        the interface corresponding to this port is only counted\n        by this object if and only if it is for a protocol being\n        processed by the local bridging function, including\n        bridge management frames.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.6.1.1.3\"\n    ::= { dot1dTpPortEntry 4 }\n\ndot1dTpPortInDiscards OBJECT-TYPE\n    SYNTAX      Counter32\n    UNITS       \"frames\"\n    MAX-ACCESS  read-only\n    STATUS      current\n    DESCRIPTION\n        \"Count of received valid frames that were discarded\n        (i.e., filtered) by the Forwarding Process.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.6.1.1.3\"\n    ::= { dot1dTpPortEntry 5 }\n\n-- ---------------------------------------------------------- --\n\n-- The Static (Destination-Address Filtering) Database\n-- ---------------------------------------------------------- --\n-- Implementation of this subtree is optional.\n-- ---------------------------------------------------------- --\n\ndot1dStaticTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF Dot1dStaticEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"A table containing filtering information configured\n        into the bridge by (local or network) management\n        specifying the set of ports to which frames received\n        from specific ports and containing specific destination\n        addresses are allowed to be forwarded.  The value of\n        zero in this table, as the port number from which frames\n        with a specific destination address are received, is\n        used to specify all ports for which there is no specific\n        entry in this table for that particular destination\n        address.  Entries are valid for unicast and for\n        group/broadcast addresses.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.7.2\"\n    ::= { dot1dStatic 1 }\n\ndot1dStaticEntry OBJECT-TYPE\n    SYNTAX      Dot1dStaticEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n        \"Filtering information configured into the bridge by\n        (local or network) management specifying the set of\n        ports to which frames received from a specific port and\n        containing a specific destination address are allowed to\n        be forwarded.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 14.7.2\"\n    INDEX   { dot1dStaticAddress, dot1dStaticReceivePort }\n    ::= { dot1dStaticTable 1 }\n\nDot1dStaticEntry ::=\n    SEQUENCE {\n        dot1dStaticAddress       MacAddress,\n        dot1dStaticReceivePort   Integer32,\n        dot1dStaticAllowedToGoTo OCTET STRING,\n        dot1dStaticStatus        INTEGER\n    }\n\ndot1dStaticAddress OBJECT-TYPE\n    SYNTAX      MacAddress\n    MAX-ACCESS  read-create\n    STATUS      current\n    DESCRIPTION\n        \"The destination MAC address in a frame to which this\n        entry's filtering information applies.  This object can\n        take the value of a unicast address, a group address, or\n        the broadcast address.\"\n    REFERENCE\n        \"IEEE 802.1D-1998: clause 7.9.1, 7.9.2\"\n    ::= { dot1dStaticEntry 1 }\n\ndot1dStaticReceivePort OBJECT-TYPE\n    SYNTAX      Integer32 (0..65535)\n    MAX-ACCESS  read-create\n    STATUS      current\n    DESCRIPTION\n        \"Either the value '0', or the port number of the port\n        from which a frame must be received in order for this\n        entry's filtering information to apply.  A value of zero\n        indicates that this entry applies on all ports of the\n        bridge for which there is no other applicable entry.\"\n    ::= { dot1dStaticEntry 2 }\n\ndot1dStaticAllowedToGoTo OBJECT-TYPE\n    SYNTAX      OCTET STRING (SIZE (0..512))\n    MAX-ACCESS  read-create\n    STATUS      current\n    DESCRIPTION\n        \"The set of ports to which frames received from a\n        specific port and destined for a specific MAC address,\n        are allowed to be forwarded.  Each octet within the\n        value of this object specifies a set of eight ports,\n        with the first octet specifying ports 1 through 8, the\n        second octet specifying ports 9 through 16, etc.  Within\n        each octet, the most significant bit represents the\n        lowest numbered port, and the least significant bit\n        represents the highest numbered port.  Thus, each port\n        of the bridge is represented by a single bit within the\n        value of this object.  If that bit has a value of '1',\n        then that port is included in the set of ports; the port\n        is not included if its bit has a value of '0'.  (Note\n        that the setting of the bit corresponding to the port\n        from which a frame is received is irrelevant.)  The\n        default value of this object is a string of ones of\n        appropriate length.\n\n        The value of this object may exceed the required minimum\n        maximum message size of some SNMP transport (484 bytes,\n        in the case of SNMP over UDP, see RFC 3417, section 3.2).\n        SNMP engines on bridges supporting a large number of\n        ports must support appropriate maximum message sizes.\"\n    ::= { dot1dStaticEntry 3 }\n\ndot1dStaticStatus OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    other(1),\n                    invalid(2),\n                    permanent(3),\n                    deleteOnReset(4),\n                    deleteOnTimeout(5)\n                }\n    MAX-ACCESS  read-create\n    STATUS      current\n    DESCRIPTION\n        \"This object indicates the status of this entry.\n        The default value is permanent(3).\n            other(1) - this entry is currently in use but the\n                conditions under which it will remain so are\n                different from each of the following values.\n            invalid(2) - writing this value to the object\n                removes the corresponding entry.\n            permanent(3) - this entry is currently in use and\n                will remain so after the next reset of the\n                bridge.\n            deleteOnReset(4) - this entry is currently in use\n                and will remain so until the next reset of the\n                bridge.\n            deleteOnTimeout(5) - this entry is currently in use\n                and will remain so until it is aged out.\"\n    ::= { dot1dStaticEntry 4 }\n\n-- ---------------------------------------------------------- --\n-- Notifications for use by Bridges\n-- ---------------------------------------------------------- --\n-- Notifications for the Spanning Tree Protocol\n-- ---------------------------------------------------------- --\n\nnewRoot NOTIFICATION-TYPE\n    -- OBJECTS     { }\n    STATUS      current\n    DESCRIPTION\n        \"The newRoot trap indicates that the sending agent has\n        become the new root of the Spanning Tree; the trap is\n        sent by a bridge soon after its election as the new\n\n        root, e.g., upon expiration of the Topology Change Timer,\n        immediately subsequent to its election.  Implementation\n        of this trap is optional.\"\n    ::= { dot1dNotifications 1 }\n\ntopologyChange NOTIFICATION-TYPE\n    -- OBJECTS     { }\n    STATUS      current\n    DESCRIPTION\n        \"A topologyChange trap is sent by a bridge when any of\n        its configured ports transitions from the Learning state\n        to the Forwarding state, or from the Forwarding state to\n        the Blocking state.  The trap is not sent if a newRoot\n        trap is sent for the same transition.  Implementation of\n        this trap is optional.\"\n    ::= { dot1dNotifications 2 }\n\n-- ---------------------------------------------------------- --\n-- IEEE 802.1D MIB - Conformance Information\n-- ---------------------------------------------------------- --\n\ndot1dGroups         OBJECT IDENTIFIER ::= { dot1dConformance 1 }\ndot1dCompliances    OBJECT IDENTIFIER ::= { dot1dConformance 2 }\n\n-- ---------------------------------------------------------- --\n-- units of conformance\n-- ---------------------------------------------------------- --\n\n-- ---------------------------------------------------------- --\n-- the dot1dBase group\n-- ---------------------------------------------------------- --\n\ndot1dBaseBridgeGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dBaseBridgeAddress,\n        dot1dBaseNumPorts,\n        dot1dBaseType\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Bridge level information for this device.\"\n    ::= { dot1dGroups 1 }\n\ndot1dBasePortGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dBasePort,\n        dot1dBasePortIfIndex,\n        dot1dBasePortCircuit,\n        dot1dBasePortDelayExceededDiscards,\n        dot1dBasePortMtuExceededDiscards\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Information for each port on this device.\"\n    ::= { dot1dGroups 2 }\n\n-- ---------------------------------------------------------- --\n-- the dot1dStp group\n-- ---------------------------------------------------------- --\n\ndot1dStpBridgeGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dStpProtocolSpecification,\n        dot1dStpPriority,\n        dot1dStpTimeSinceTopologyChange,\n        dot1dStpTopChanges,\n        dot1dStpDesignatedRoot,\n        dot1dStpRootCost,\n        dot1dStpRootPort,\n        dot1dStpMaxAge,\n        dot1dStpHelloTime,\n        dot1dStpHoldTime,\n        dot1dStpForwardDelay,\n        dot1dStpBridgeMaxAge,\n        dot1dStpBridgeHelloTime,\n        dot1dStpBridgeForwardDelay\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Bridge level Spanning Tree data for this device.\"\n    ::= { dot1dGroups 3 }\n\ndot1dStpPortGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dStpPort,\n        dot1dStpPortPriority,\n        dot1dStpPortState,\n        dot1dStpPortEnable,\n        dot1dStpPortPathCost,\n        dot1dStpPortDesignatedRoot,\n        dot1dStpPortDesignatedCost,\n        dot1dStpPortDesignatedBridge,\n        dot1dStpPortDesignatedPort,\n        dot1dStpPortForwardTransitions\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Spanning Tree data for each port on this device.\"\n    ::= { dot1dGroups 4 }\n\ndot1dStpPortGroup2 OBJECT-GROUP\n    OBJECTS {\n        dot1dStpPort,\n        dot1dStpPortPriority,\n        dot1dStpPortState,\n        dot1dStpPortEnable,\n        dot1dStpPortDesignatedRoot,\n        dot1dStpPortDesignatedCost,\n        dot1dStpPortDesignatedBridge,\n        dot1dStpPortDesignatedPort,\n        dot1dStpPortForwardTransitions,\n        dot1dStpPortPathCost32\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Spanning Tree data for each port on this device.\"\n    ::= { dot1dGroups 5 }\n\ndot1dStpPortGroup3 OBJECT-GROUP\n    OBJECTS {\n        dot1dStpPortPathCost32\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Spanning Tree data for devices supporting 32-bit\n         path costs.\"\n    ::= { dot1dGroups 6 }\n\n-- ---------------------------------------------------------- --\n-- the dot1dTp group\n-- ---------------------------------------------------------- --\n\ndot1dTpBridgeGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dTpLearnedEntryDiscards,\n        dot1dTpAgingTime\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Bridge level Transparent Bridging data.\"\n    ::= { dot1dGroups 7 }\n\ndot1dTpFdbGroup OBJECT-GROUP\n    OBJECTS {\n\n        dot1dTpFdbAddress,\n        dot1dTpFdbPort,\n        dot1dTpFdbStatus\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Filtering Database information for the Bridge.\"\n    ::= { dot1dGroups 8 }\n\ndot1dTpGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dTpPort,\n        dot1dTpPortMaxInfo,\n        dot1dTpPortInFrames,\n        dot1dTpPortOutFrames,\n        dot1dTpPortInDiscards\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Dynamic Filtering Database information for each port of\n        the Bridge.\"\n    ::= { dot1dGroups 9 }\n\n-- ---------------------------------------------------------- --\n-- The Static (Destination-Address Filtering) Database\n-- ---------------------------------------------------------- --\n\ndot1dStaticGroup OBJECT-GROUP\n    OBJECTS {\n        dot1dStaticAddress,\n        dot1dStaticReceivePort,\n        dot1dStaticAllowedToGoTo,\n        dot1dStaticStatus\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Static Filtering Database information for each port of\n        the Bridge.\"\n    ::= { dot1dGroups 10 }\n\n-- ---------------------------------------------------------- --\n-- The Trap Notification Group\n-- ---------------------------------------------------------- --\n\ndot1dNotificationGroup NOTIFICATION-GROUP\n    NOTIFICATIONS {\n        newRoot,\n        topologyChange\n    }\n    STATUS      current\n    DESCRIPTION\n        \"Group of objects describing notifications (traps).\"\n    ::= { dot1dGroups 11 }\n\n-- ---------------------------------------------------------- --\n-- compliance statements\n-- ---------------------------------------------------------- --\n\nbridgeCompliance1493 MODULE-COMPLIANCE\n    STATUS      current\n    DESCRIPTION\n        \"The compliance statement for device support of bridging\n        services, as per RFC1493.\"\n\n    MODULE\n        MANDATORY-GROUPS {\n            dot1dBaseBridgeGroup,\n            dot1dBasePortGroup\n        }\n\n    GROUP   dot1dStpBridgeGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n        that support the Spanning Tree Protocol.\"\n\n    GROUP   dot1dStpPortGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n        that support the Spanning Tree Protocol.\"\n\n    GROUP   dot1dTpBridgeGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n        that support the transparent bridging mode.  A\n        transparent or SRT bridge will implement this group.\"\n\n    GROUP   dot1dTpFdbGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n        that support the transparent bridging mode.  A\n        transparent or SRT bridge will implement this group.\"\n\n    GROUP   dot1dTpGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n\n        that support the transparent bridging mode.  A\n        transparent or SRT bridge will implement this group.\"\n\n    GROUP   dot1dStaticGroup\n    DESCRIPTION\n        \"Implementation of this group is optional.\"\n\n    GROUP dot1dNotificationGroup\n    DESCRIPTION\n        \"Implementation of this group is optional.\"\n    ::= { dot1dCompliances 1 }\n\nbridgeCompliance4188 MODULE-COMPLIANCE\n    STATUS      current\n    DESCRIPTION\n        \"The compliance statement for device support of bridging\n        services.  This supports 32-bit Path Cost values and the\n        more restricted bridge and port priorities, as per IEEE\n        802.1t.\n\n        Full support for the 802.1D management objects requires that\n        the SNMPv2-MIB [RFC3418] objects sysDescr, and sysUpTime, as\n        well as the IF-MIB [RFC2863] objects ifIndex, ifType,\n        ifDescr, ifPhysAddress, and ifLastChange are implemented.\"\n\n    MODULE\n        MANDATORY-GROUPS {\n            dot1dBaseBridgeGroup,\n            dot1dBasePortGroup\n        }\n\n    GROUP   dot1dStpBridgeGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for\n        bridges that support the Spanning Tree Protocol.\"\n\n    OBJECT dot1dStpPriority\n    SYNTAX Integer32 (0|4096|8192|12288|16384|20480|24576\n                     |28672|32768|36864|40960|45056|49152\n                     |53248|57344|61440)\n    DESCRIPTION\n        \"The possible values defined by IEEE 802.1t.\"\n\n    GROUP   dot1dStpPortGroup2\n    DESCRIPTION\n        \"Implementation of this group is mandatory for\n        bridges that support the Spanning Tree Protocol.\"\n\n    GROUP   dot1dStpPortGroup3\n    DESCRIPTION\n        \"Implementation of this group is mandatory for bridges\n         that support the Spanning Tree Protocol and 32-bit path\n         costs.  In particular, this includes devices supporting\n         IEEE 802.1t and IEEE 802.1w.\"\n\n    OBJECT dot1dStpPortPriority\n    SYNTAX Integer32 (0|16|32|48|64|80|96|112|128\n                     |144|160|176|192|208|224|240)\n    DESCRIPTION\n        \"The possible values defined by IEEE 802.1t.\"\n\n    GROUP   dot1dTpBridgeGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for\n        bridges that support the transparent bridging\n        mode.  A transparent or SRT bridge will implement\n        this group.\"\n\n    GROUP   dot1dTpFdbGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for\n        bridges that support the transparent bridging\n        mode.  A transparent or SRT bridge will implement\n        this group.\"\n\n    GROUP   dot1dTpGroup\n    DESCRIPTION\n        \"Implementation of this group is mandatory for\n        bridges that support the transparent bridging\n        mode.  A transparent or SRT bridge will implement\n        this group.\"\n\n    GROUP   dot1dStaticGroup\n    DESCRIPTION\n        \"Implementation of this group is optional.\"\n\n    GROUP dot1dNotificationGroup\n    DESCRIPTION\n        \"Implementation of this group is optional.\"\n    ::= { dot1dCompliances 2 }\n\nEND\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/bridgeMibImports",
    "content": "SNMPv2-SMI DEFINITIONS ::= BEGIN\n\n-- the path to the root\n\norg            OBJECT IDENTIFIER ::= { iso 3 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 6 }\ninternet       OBJECT IDENTIFIER ::= { dod 1 }\n\ndirectory      OBJECT IDENTIFIER ::= { internet 1 }\n\nmgmt           OBJECT IDENTIFIER ::= { internet 2 }\nmib-2          OBJECT IDENTIFIER ::= { mgmt 1 }\ntransmission   OBJECT IDENTIFIER ::= { mib-2 10 }\n\nexperimental   OBJECT IDENTIFIER ::= { internet 3 }\n\nprivate        OBJECT IDENTIFIER ::= { internet 4 }\nenterprises    OBJECT IDENTIFIER ::= { private 1 }\n\nsecurity       OBJECT IDENTIFIER ::= { internet 5 }\n\nsnmpV2         OBJECT IDENTIFIER ::= { internet 6 }\n\n-- transport domains\nsnmpDomains    OBJECT IDENTIFIER ::= { snmpV2 1 }\n\n-- transport proxies\nsnmpProxys     OBJECT IDENTIFIER ::= { snmpV2 2 }\n\n-- module identities\nsnmpModules    OBJECT IDENTIFIER ::= { snmpV2 3 }\n\n-- Extended UTCTime, to allow dates with four-digit years\n-- (Note that this definition of ExtUTCTime is not to be IMPORTed\n--  by MIB modules.)\nExtUTCTime ::= OCTET STRING(SIZE(11 | 13))\n    -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ\n\n    --   where: YY   - last two digits of year (only years\n    --                 between 1900-1999)\n    --          YYYY - last four digits of the year (any year)\n    --          MM   - month (01 through 12)\n    --          DD   - day of month (01 through 31)\n    --          HH   - hours (00 through 23)\n    --          MM   - minutes (00 through 59)\n    --          Z    - denotes GMT (the ASCII character Z)\n    --\n    -- For example, \"9502192015Z\" and \"199502192015Z\" represent\n    -- 8:15pm GMT on 19 February 1995. Years after 1999 must use\n    -- the four digit year format. Years 1900-1999 may use the\n    -- two or four digit format.\n\n-- definitions for information modules\n\nMODULE-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"LAST-UPDATED\" value(Update ExtUTCTime)\n                  \"ORGANIZATION\" Text\n                  \"CONTACT-INFO\" Text\n                  \"DESCRIPTION\" Text\n                  RevisionPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    RevisionPart ::=\n                  Revisions\n                | empty\n    Revisions ::=\n                  Revision\n                | Revisions Revision\n    Revision ::=\n                  \"REVISION\" value(Update ExtUTCTime)\n                  \"DESCRIPTION\" Text\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nOBJECT-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- names of objects\n-- (Note that these definitions of ObjectName and NotificationName\n--  are not to be IMPORTed by MIB modules.)\n\nObjectName ::=\n    OBJECT IDENTIFIER\n\nNotificationName ::=\n    OBJECT IDENTIFIER\n\n-- syntax of objects\n\n-- the \"base types\" defined here are:\n--   3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER\n--   8 application-defined types: Integer32, IpAddress, Counter32,\n--              Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64\n\nObjectSyntax ::=\n    CHOICE {\n        simple\n            SimpleSyntax,\n          -- note that SEQUENCEs for conceptual tables and\n          -- rows are not mentioned here...\n\n        application-wide\n            ApplicationSyntax\n    }\n\n-- built-in ASN.1 types\n\nSimpleSyntax ::=\n    CHOICE {\n        -- INTEGERs with a more restrictive range\n        -- may also be used\n        integer-value               -- includes Integer32\n            INTEGER (-2147483648..2147483647),\n        -- OCTET STRINGs with a more restrictive size\n        -- may also be used\n        string-value\n            OCTET STRING (SIZE (0..65535)),\n        objectID-value\n            OBJECT IDENTIFIER\n    }\n\n-- indistinguishable from INTEGER, but never needs more than\n-- 32-bits for a two's complement representation\nInteger32 ::=\n        INTEGER (-2147483648..2147483647)\n\n-- application-wide types\n\nApplicationSyntax ::=\n    CHOICE {\n        ipAddress-value\n            IpAddress,\n        counter-value\n            Counter32,\n        timeticks-value\n            TimeTicks,\n        arbitrary-value\n            Opaque,\n        big-counter-value\n            Counter64,\n        unsigned-integer-value  -- includes Gauge32\n            Unsigned32\n    }\n\n-- in network-byte order\n\n-- (this is a tagged type for historical reasons)\nIpAddress ::=\n    [APPLICATION 0]\n        IMPLICIT OCTET STRING (SIZE (4))\n\n-- this wraps\nCounter32 ::=\n    [APPLICATION 1]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- this doesn't wrap\nGauge32 ::=\n    [APPLICATION 2]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- an unsigned 32-bit quantity\n-- indistinguishable from Gauge32\nUnsigned32 ::=\n    [APPLICATION 2]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- hundredths of seconds since an epoch\nTimeTicks ::=\n    [APPLICATION 3]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- for backward-compatibility only\nOpaque ::=\n    [APPLICATION 4]\n        IMPLICIT OCTET STRING\n\n-- for counters that wrap in less than one hour with only 32 bits\nCounter64 ::=\n    [APPLICATION 6]\n        IMPLICIT INTEGER (0..18446744073709551615)\n\n-- definition for objects\n\nOBJECT-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"SYNTAX\" Syntax\n                  UnitsPart\n                  \"MAX-ACCESS\" Access\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n                  IndexPart\n                  DefValPart\n\n    VALUE NOTATION ::=\n                  value(VALUE ObjectName)\n\n    Syntax ::=   -- Must be one of the following:\n                       -- a base type (or its refinement),\n                       -- a textual convention (or its refinement), or\n                       -- a BITS pseudo-type\n                   type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\n    UnitsPart ::=\n                  \"UNITS\" Text\n                | empty\n\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    IndexPart ::=\n                  \"INDEX\"    \"{\" IndexTypes \"}\"\n                | \"AUGMENTS\" \"{\" Entry      \"}\"\n                | empty\n    IndexTypes ::=\n                  IndexType\n                | IndexTypes \",\" IndexType\n    IndexType ::=\n                  \"IMPLIED\" Index\n                | Index\n\n    Index ::=\n                    -- use the SYNTAX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n    Entry ::=\n                    -- use the INDEX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n\n    DefValPart ::= \"DEFVAL\" \"{\" Defvalue \"}\"\n                | empty\n\n    Defvalue ::=  -- must be valid for the type specified in\n                  -- SYNTAX clause of same OBJECT-TYPE macro\n                  value(ObjectSyntax)\n                | \"{\" BitsValue \"}\"\n\n    BitsValue ::= BitNames\n                | empty\n\n    BitNames ::=  BitName\n                | BitNames \",\" BitName\n\n    BitName ::= identifier\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- definitions for notifications\n\nNOTIFICATION-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  ObjectsPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE NotificationName)\n\n    ObjectsPart ::=\n                  \"OBJECTS\" \"{\" Objects \"}\"\n                | empty\n    Objects ::=\n                  Object\n\n                | Objects \",\" Object\n    Object ::=\n                  value(ObjectName)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- definitions of administrative identifiers\n\nzeroDotZero    OBJECT-IDENTITY\n    STATUS     current\n    DESCRIPTION\n            \"A value used for null identifiers.\"\n    ::= { 0 0 }\n\n\n\nTEXTUAL-CONVENTION MACRO ::=\n\nBEGIN\n    TYPE NOTATION ::=\n                  DisplayPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n                  \"SYNTAX\" Syntax\n\n    VALUE NOTATION ::=\n                   value(VALUE Syntax)      -- adapted ASN.1\n\n    DisplayPart ::=\n                  \"DISPLAY-HINT\" Text\n                | empty\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\n\n    Syntax ::=   -- Must be one of the following:\n                       -- a base type (or its refinement), or\n                       -- a BITS pseudo-type\n                  type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\nEND\n\nMODULE-COMPLIANCE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n                  ModulePart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    ModulePart ::=\n                  Modules\n    Modules ::=\n                  Module\n                | Modules Module\n    Module ::=\n                  -- name of module --\n                  \"MODULE\" ModuleName\n                  MandatoryPart\n                  CompliancePart\n\n    ModuleName ::=\n                  -- identifier must start with uppercase letter\n                  identifier ModuleIdentifier\n                  -- must not be empty unless contained\n                  -- in MIB Module\n                | empty\n    ModuleIdentifier ::=\n                  value(OBJECT IDENTIFIER)\n                | empty\n\n    MandatoryPart ::=\n                  \"MANDATORY-GROUPS\" \"{\" Groups \"}\"\n                | empty\n\n    Groups ::=\n\n                  Group\n                | Groups \",\" Group\n    Group ::=\n                  value(OBJECT IDENTIFIER)\n\n    CompliancePart ::=\n                  Compliances\n                | empty\n\n    Compliances ::=\n                  Compliance\n                | Compliances Compliance\n    Compliance ::=\n                  ComplianceGroup\n                | Object\n\n    ComplianceGroup ::=\n                  \"GROUP\" value(OBJECT IDENTIFIER)\n                  \"DESCRIPTION\" Text\n\n    Object ::=\n                  \"OBJECT\" value(ObjectName)\n                  SyntaxPart\n                  WriteSyntaxPart\n                  AccessPart\n                  \"DESCRIPTION\" Text\n\n    -- must be a refinement for object's SYNTAX clause\n    SyntaxPart ::= \"SYNTAX\" Syntax\n                | empty\n\n    -- must be a refinement for object's SYNTAX clause\n    WriteSyntaxPart ::= \"WRITE-SYNTAX\" Syntax\n                | empty\n\n    Syntax ::=    -- Must be one of the following:\n                       -- a base type (or its refinement),\n                       -- a textual convention (or its refinement), or\n                       -- a BITS pseudo-type\n                  type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::= identifier \"(\" number \")\" -- number is nonnegative\n\n    AccessPart ::=\n                  \"MIN-ACCESS\" Access\n                | empty\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\nEND\n\nOBJECT-GROUP MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  ObjectsPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    ObjectsPart ::=\n                  \"OBJECTS\" \"{\" Objects \"}\"\n    Objects ::=\n                  Object\n                | Objects \",\" Object\n    Object ::=\n\n                  value(ObjectName)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\nEND\n\nInterfaceIndex ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"d\"\n    STATUS       current\n    DESCRIPTION\n            \"A unique value, greater than zero, for each interface or\n            interface sub-layer in the managed system.  It is\n            recommended that values are assigned contiguously starting\n            from 1.  The value for each interface sub-layer must remain\n            constant at least from one re-initialization of the entity's\n            network management system to the next re-initialization.\"\n    SYNTAX       Integer32 (1..2147483647)\n\n\n\nMacAddress ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"1x:\"\n    STATUS       current\n    DESCRIPTION\n            \"Represents an 802 MAC address represented in the\n            `canonical' order defined by IEEE 802.1a, i.e., as if it\n            were transmitted least significant bit first, even though\n            802.5 (in contrast to other 802.x protocols) requires MAC\n            addresses to be transmitted most significant bit first.\"\n    SYNTAX       OCTET STRING (SIZE (6))\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/foo",
    "content": "FOOTEST-MIB DEFINITIONS ::= BEGIN\n\nIMPORTS\n        MODULE-IDENTITY, OBJECT-TYPE, Integer32  FROM fooImports;\n\nfooTestMIB MODULE-IDENTITY\n    LAST-UPDATED \"2021090800Z\"\n    ORGANIZATION \"influx\"\n    CONTACT-INFO\n        \"EMail:  influx@email.com\"\n    DESCRIPTION\n        \"MIB module for testing snmp plugin\n        for telegraf\n        \"\n    ::= { iso 1 }\n\nfooMIBObjects OBJECT IDENTIFIER ::= { iso 2 }\nfooOne OBJECT IDENTIFIER ::= { iso 1 }\nsix OBJECT IDENTIFIER ::= { fooOne 1 }\nthree OBJECT IDENTIFIER ::= { six 3 }\n\nfoo OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"foo mib for testing\"\n            ::= { fooMIBObjects 3 }\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/fooImports",
    "content": "fooImports DEFINITIONS ::= BEGIN\n\n-- the path to the root \n\norg            OBJECT IDENTIFIER ::= { iso 1 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 2 }\ninternet       OBJECT IDENTIFIER ::= { dod 3 }\n\nExtUTCTime ::= OCTET STRING(SIZE(11 | 13))\n    -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ\n\n    --   where: YY   - last two digits of year (only years\n    --                 between 1900-1999)\n    --          YYYY - last four digits of the year (any year)\n    --          MM   - month (01 through 12)\n    --          DD   - day of month (01 through 31)\n    --          HH   - hours (00 through 23)\n    --          MM   - minutes (00 through 59)\n    --          Z    - denotes GMT (the ASCII character Z)\n    --\n    -- For example, \"9502192015Z\" and \"199502192015Z\" represent\n    -- 8:15pm GMT on 19 February 1995. Years after 1999 must use\n    -- the four digit year format. Years 1900-1999 may use the\n    -- two or four digit format.\n\n-- definitions for information modules\n\nMODULE-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"LAST-UPDATED\" value(Update ExtUTCTime)\n                  \"ORGANIZATION\" Text\n                  \"CONTACT-INFO\" Text\n                  \"DESCRIPTION\" Text\n                  RevisionPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    RevisionPart ::=\n                  Revisions\n                | empty\n    Revisions ::=\n                  Revision\n                | Revisions Revision\n    Revision ::=\n                  \"REVISION\" value(Update ExtUTCTime)\n                  \"DESCRIPTION\" Text\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nOBJECT-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- names of objects\n-- (Note that these definitions of ObjectName and NotificationName\n--  are not to be IMPORTed by MIB modules.)\n\nObjectName ::=\n    OBJECT IDENTIFIER\n\nNotificationName ::=\n    OBJECT IDENTIFIER\n\n\n-- indistinguishable from INTEGER, but never needs more than\n-- 32-bits for a two's complement representation\nInteger32 ::=\n        INTEGER (-2147483648..2147483647)\n\n\n\n-- definition for objects\n\nOBJECT-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  UnitsPart\n                  \"MAX-ACCESS\" Access\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n                  IndexPart\n                  DefValPart\n\n    VALUE NOTATION ::=\n                  value(VALUE ObjectName)\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\n    UnitsPart ::=\n                  \"UNITS\" Text\n                | empty\n\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    IndexPart ::=\n                  \"INDEX\"    \"{\" IndexTypes \"}\"\n                | \"AUGMENTS\" \"{\" Entry      \"}\"\n                | empty\n    IndexTypes ::=\n                  IndexType\n                | IndexTypes \",\" IndexType\n    IndexType ::=\n                  \"IMPLIED\" Index\n                | Index\n\n    Entry ::=\n                    -- use the INDEX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n\n    DefValPart ::= \"DEFVAL\" \"{\" Defvalue \"}\"\n                | empty\n\n    BitsValue ::= BitNames\n                | empty\n\n    BitNames ::=  BitName\n                | BitNames \",\" BitName\n\n    BitName ::= identifier\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/ifPhysAddress",
    "content": "IF-MIB DEFINITIONS ::= BEGIN\n\nIMPORTS\n        MODULE-IDENTITY, OBJECT-TYPE, Integer32, mib-2,\n        PhysAddress             FROM ifPhysAddressImports;\n\nifMIB MODULE-IDENTITY\n    LAST-UPDATED \"200006140000Z\"\n    ORGANIZATION \"IETF Interfaces MIB Working Group\"\n    CONTACT-INFO\n            \"   Keith McCloghrie\n                Cisco Systems, Inc.\n                170 West Tasman Drive\n                San Jose, CA  95134-1706\n                US\n\n                408-526-5260\n                kzm@cisco.com\"\n    DESCRIPTION\n            \"The MIB module to describe generic objects for network\n            interface sub-layers.  This MIB is an updated version of\n            MIB-II's ifTable, and incorporates the extensions defined in\n            RFC 1229.\"\n\n    REVISION      \"200006140000Z\"\n    DESCRIPTION\n            \"Clarifications agreed upon by the Interfaces MIB WG, and\n            published as RFC 2863.\"\n    REVISION      \"199602282155Z\"\n    DESCRIPTION\n            \"Revisions made by the Interfaces MIB WG, and published in\n            RFC 2233.\"\n    REVISION      \"199311082155Z\"\n    DESCRIPTION\n            \"Initial revision, published as part of RFC 1573.\"\n    ::= { mib-2 31 }\n\nifMIBObjects OBJECT IDENTIFIER ::= { ifMIB 1 }\n\ninterfaces   OBJECT IDENTIFIER ::= { mib-2 2 }\n\n\nifTable OBJECT-TYPE\n    SYNTAX      SEQUENCE OF IfEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n            \"A list of interface entries.  The number of entries is\n            given by the value of ifNumber.\"\n    ::= { interfaces 2 }\n\nifEntry OBJECT-TYPE\n    SYNTAX      IfEntry\n    MAX-ACCESS  not-accessible\n    STATUS      current\n    DESCRIPTION\n            \"An entry containing management information applicable to a\n            particular interface.\"\n    INDEX   { ifIndex }\n    ::= { ifTable 1 }\n\n\n\nifPhysAddress OBJECT-TYPE\n              SYNTAX  PhysAddress\n              ACCESS  read-only\n              STATUS  mandatory\n              DESCRIPTION\n                      \"The interface's address at the protocol layer\n                      immediately `below' the network layer in the\n                      protocol stack.  For interfaces which do not have\n                      such an address (e.g., a serial line), this object\n                      should contain an octet string of zero length.\"\n              ::= { ifEntry 6 }\n\nfoo OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"foo mib for testing\"\n            ::= { ifEntry 9 }\n    \nEND\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/ifPhysAddressImports",
    "content": "SNMPv2-SMI DEFINITIONS ::= BEGIN\n\n-- the path to the root\n\norg            OBJECT IDENTIFIER ::= { iso 3 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 6 }\ninternet       OBJECT IDENTIFIER ::= { dod 1 }\n\ndirectory      OBJECT IDENTIFIER ::= { internet 1 }\n\nmgmt           OBJECT IDENTIFIER ::= { internet 2 }\nmib-2          OBJECT IDENTIFIER ::= { mgmt 1 }\ntransmission   OBJECT IDENTIFIER ::= { mib-2 10 }\n\nexperimental   OBJECT IDENTIFIER ::= { internet 3 }\n\nprivate        OBJECT IDENTIFIER ::= { internet 4 }\nenterprises    OBJECT IDENTIFIER ::= { private 1 }\n\nsecurity       OBJECT IDENTIFIER ::= { internet 5 }\n\nsnmpV2         OBJECT IDENTIFIER ::= { internet 6 }\n\n-- transport domains\nsnmpDomains    OBJECT IDENTIFIER ::= { snmpV2 1 }\n\n-- transport proxies\nsnmpProxys     OBJECT IDENTIFIER ::= { snmpV2 2 }\n\n-- module identities\nsnmpModules    OBJECT IDENTIFIER ::= { snmpV2 3 }\n\n-- Extended UTCTime, to allow dates with four-digit years\n-- (Note that this definition of ExtUTCTime is not to be IMPORTed\n--  by MIB modules.)\nExtUTCTime ::= OCTET STRING(SIZE(11 | 13))\n    -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ\n\n    --   where: YY   - last two digits of year (only years\n    --                 between 1900-1999)\n    --          YYYY - last four digits of the year (any year)\n    --          MM   - month (01 through 12)\n    --          DD   - day of month (01 through 31)\n    --          HH   - hours (00 through 23)\n    --          MM   - minutes (00 through 59)\n    --          Z    - denotes GMT (the ASCII character Z)\n    --\n    -- For example, \"9502192015Z\" and \"199502192015Z\" represent\n    -- 8:15pm GMT on 19 February 1995. Years after 1999 must use\n    -- the four digit year format. Years 1900-1999 may use the\n    -- two or four digit format.\n\n-- definitions for information modules\n\nMODULE-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"LAST-UPDATED\" value(Update ExtUTCTime)\n                  \"ORGANIZATION\" Text\n                  \"CONTACT-INFO\" Text\n                  \"DESCRIPTION\" Text\n                  RevisionPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    RevisionPart ::=\n                  Revisions\n                | empty\n    Revisions ::=\n                  Revision\n                | Revisions Revision\n    Revision ::=\n                  \"REVISION\" value(Update ExtUTCTime)\n                  \"DESCRIPTION\" Text\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nOBJECT-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- names of objects\n-- (Note that these definitions of ObjectName and NotificationName\n--  are not to be IMPORTed by MIB modules.)\n\nObjectName ::=\n    OBJECT IDENTIFIER\n\nNotificationName ::=\n    OBJECT IDENTIFIER\n\n-- syntax of objects\n\n-- the \"base types\" defined here are:\n--   3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER\n--   8 application-defined types: Integer32, IpAddress, Counter32,\n--              Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64\n\nObjectSyntax ::=\n    CHOICE {\n        simple\n            SimpleSyntax,\n          -- note that SEQUENCEs for conceptual tables and\n          -- rows are not mentioned here...\n\n        application-wide\n            ApplicationSyntax\n    }\n\n-- built-in ASN.1 types\n\nSimpleSyntax ::=\n    CHOICE {\n        -- INTEGERs with a more restrictive range\n        -- may also be used\n        integer-value               -- includes Integer32\n            INTEGER (-2147483648..2147483647),\n        -- OCTET STRINGs with a more restrictive size\n        -- may also be used\n        string-value\n            OCTET STRING (SIZE (0..65535)),\n        objectID-value\n            OBJECT IDENTIFIER\n    }\n\n-- indistinguishable from INTEGER, but never needs more than\n-- 32-bits for a two's complement representation\nInteger32 ::=\n        INTEGER (-2147483648..2147483647)\n\n\n\n-- definition for objects\n\nOBJECT-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"SYNTAX\" Syntax\n                  UnitsPart\n                  \"MAX-ACCESS\" Access\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n                  IndexPart\n                  DefValPart\n\n    VALUE NOTATION ::=\n                  value(VALUE ObjectName)\n\n    Syntax ::=   -- Must be one of the following:\n                       -- a base type (or its refinement),\n                       -- a textual convention (or its refinement), or\n                       -- a BITS pseudo-type\n                   type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\n    UnitsPart ::=\n                  \"UNITS\" Text\n                | empty\n\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    IndexPart ::=\n                  \"INDEX\"    \"{\" IndexTypes \"}\"\n                | \"AUGMENTS\" \"{\" Entry      \"}\"\n                | empty\n    IndexTypes ::=\n                  IndexType\n                | IndexTypes \",\" IndexType\n    IndexType ::=\n                  \"IMPLIED\" Index\n                | Index\n\n    Index ::=\n                    -- use the SYNTAX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n    Entry ::=\n                    -- use the INDEX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n\n    DefValPart ::= \"DEFVAL\" \"{\" Defvalue \"}\"\n                | empty\n\n    Defvalue ::=  -- must be valid for the type specified in\n                  -- SYNTAX clause of same OBJECT-TYPE macro\n                  value(ObjectSyntax)\n                | \"{\" BitsValue \"}\"\n\n    BitsValue ::= BitNames\n                | empty\n\n    BitNames ::=  BitName\n                | BitNames \",\" BitName\n\n    BitName ::= identifier\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nPhysAddress ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"1x:\"\n    STATUS       current\n    DESCRIPTION\n            \"Represents media- or physical-level addresses.\"\n    SYNTAX       OCTET STRING\n\n\nEND\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/server",
    "content": "TEST DEFINITIONS ::= BEGIN\n\nIMPORTS\n        MODULE-IDENTITY, OBJECT-TYPE, Integer32  FROM fooImports;\n\nTestMIB MODULE-IDENTITY\n    LAST-UPDATED \"2021090800Z\"\n    ORGANIZATION \"influx\"\n    CONTACT-INFO\n        \"EMail:  influx@email.com\"\n    DESCRIPTION\n        \"MIB module for testing snmp plugin\n        for telegraf\n        \"\n    ::= { iso 1 }\n\nDateAndTime ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"2d-1d-1d,1d:1d:1d.1d,1a1d:1d\"\n    STATUS       current\n    DESCRIPTION\n            \"A date-time specification.\n\n            field  octets  contents                  range\n            -----  ------  --------                  -----\n              1      1-2   year*                     0..65536\n              2       3    month                     1..12\n              3       4    day                       1..31\n              4       5    hour                      0..23\n              5       6    minutes                   0..59\n              6       7    seconds                   0..60\n                           (use 60 for leap-second)\n              7       8    deci-seconds              0..9\n              8       9    direction from UTC        '+' / '-'\n              9      10    hours from UTC*           0..13\n             10      11    minutes from UTC          0..59\n\n            * Notes:\n            - the value of year is in network-byte order\n            - daylight saving time in New Zealand is +13\n\n            For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be\n            displayed as:\n\n                             1992-5-26,13:30:15.0,-4:0\n\n            Note that if only local time is known, then timezone\n            information (fields 8-10) is not present.\"\n    SYNTAX       OCTET STRING (SIZE (8 | 11))\n\ntestingObjects OBJECT IDENTIFIER ::= { iso 0 }\ntestObjects OBJECT IDENTIFIER ::= { testingObjects 0 }\nhostnameone OBJECT IDENTIFIER ::= {testObjects 1 }\nhostname OBJECT IDENTIFIER ::= { hostnameone 1 }\ntestTable OBJECT IDENTIFIER ::= { testObjects 0 }\ntestMIBObjects OBJECT IDENTIFIER ::= { testTable 1 }\n\n\nserver OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 1 }\n\nconnections OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 2 }\n\nlatency OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 3 }\n\ndescription OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 4 }   \n\ndateAndTime OBJECT-TYPE \n    SYNTAX DateAndTime\n    ACCESS read-only\n    STATUS current \n    DESCRIPTION\n        \"A date-time specification.\"\n    ::= { testMIBObjects 5 }   \n\nEND\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/serverImports",
    "content": "fooImports DEFINITIONS ::= BEGIN\n\n-- the path to the root \n\norg            OBJECT IDENTIFIER ::= { iso 1 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 1 }\ninternet       OBJECT IDENTIFIER ::= { dod 1 }\n\ndirectory      OBJECT IDENTIFIER ::= { internet 1 }\n\nmgmt           OBJECT IDENTIFIER ::= { internet 1 }\nmib-2          OBJECT IDENTIFIER ::= { mgmt 1 }\n\nExtUTCTime ::= OCTET STRING(SIZE(11 | 13))\n    -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ\n\n    --   where: YY   - last two digits of year (only years\n    --                 between 1900-1999)\n    --          YYYY - last four digits of the year (any year)\n    --          MM   - month (01 through 12)\n    --          DD   - day of month (01 through 31)\n    --          HH   - hours (00 through 23)\n    --          MM   - minutes (00 through 59)\n    --          Z    - denotes GMT (the ASCII character Z)\n    --\n    -- For example, \"9502192015Z\" and \"199502192015Z\" represent\n    -- 8:15pm GMT on 19 February 1995. Years after 1999 must use\n    -- the four digit year format. Years 1900-1999 may use the\n    -- two or four digit format.\n\n-- definitions for information modules\n\nMODULE-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"LAST-UPDATED\" value(Update ExtUTCTime)\n                  \"ORGANIZATION\" Text\n                  \"CONTACT-INFO\" Text\n                  \"DESCRIPTION\" Text\n                  RevisionPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    RevisionPart ::=\n                  Revisions\n                | empty\n    Revisions ::=\n                  Revision\n                | Revisions Revision\n    Revision ::=\n                  \"REVISION\" value(Update ExtUTCTime)\n                  \"DESCRIPTION\" Text\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nOBJECT-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- names of objects\n-- (Note that these definitions of ObjectName and NotificationName\n--  are not to be IMPORTed by MIB modules.)\n\nObjectName ::=\n    OBJECT IDENTIFIER\n\nNotificationName ::=\n    OBJECT IDENTIFIER\n\n\n-- indistinguishable from INTEGER, but never needs more than\n-- 32-bits for a two's complement representation\nInteger32 ::=\n        INTEGER (-2147483648..2147483647)\n\n\n\n-- definition for objects\n\nOBJECT-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  UnitsPart\n                  \"MAX-ACCESS\" Access\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n                  IndexPart\n                  DefValPart\n\n    VALUE NOTATION ::=\n                  value(VALUE ObjectName)\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\n    UnitsPart ::=\n                  \"UNITS\" Text\n                | empty\n\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    IndexPart ::=\n                  \"INDEX\"    \"{\" IndexTypes \"}\"\n                | \"AUGMENTS\" \"{\" Entry      \"}\"\n                | empty\n    IndexTypes ::=\n                  IndexType\n                | IndexTypes \",\" IndexType\n    IndexType ::=\n                  \"IMPLIED\" Index\n                | Index\n\n    Entry ::=\n                    -- use the INDEX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n\n    DefValPart ::= \"DEFVAL\" \"{\" Defvalue \"}\"\n                | empty\n\n    BitsValue ::= BitNames\n                | empty\n\n    BitNames ::=  BitName\n                | BitNames \",\" BitName\n\n    BitName ::= identifier\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/tableBuild",
    "content": "TEST DEFINITIONS ::= BEGIN\n\nIMPORTS\n        MODULE-IDENTITY, OBJECT-TYPE, Integer32  FROM fooImports;\n\nTestMIB MODULE-IDENTITY\n    LAST-UPDATED \"2021090800Z\"\n    ORGANIZATION \"influx\"\n    CONTACT-INFO\n        \"EMail:  influx@email.com\"\n    DESCRIPTION\n        \"MIB module for testing snmp plugin\n        for telegraf\n        \"\n    ::= { iso 1 }\n\ntestingObjects OBJECT IDENTIFIER ::= { iso 0 }\ntestObjects OBJECT IDENTIFIER ::= { testingObjects 0 }\nhostnameone OBJECT IDENTIFIER ::= {testObjects 1 }\nhostname OBJECT IDENTIFIER ::= { hostnameone 1 }\ntestTable OBJECT IDENTIFIER ::= { testObjects 0 }\ntestMIBObjects OBJECT IDENTIFIER ::= { testTable 1 }\n\n\nmyfield1 OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 1 }\n\nmyfield2 OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 2 }\n\nmyfield3 OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 3 }\n\nmyfield4 OBJECT-TYPE \n            SYNTAX Integer32\n            ACCESS read-only\n            STATUS current \n            DESCRIPTION\n                \"server mib for testing\"\n            ::= { testMIBObjects 4 }   \n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/tableMib",
    "content": "RFC1213-MIB DEFINITIONS ::= BEGIN\n\nIMPORTS\n        mgmt, NetworkAddress, IpAddress, Counter, Gauge,\n                TimeTicks\n            FROM RFC1155-SMI\n        OBJECT-TYPE\n                FROM fooImports;\n\n--  This MIB module uses the extended OBJECT-TYPE macro as\n--  defined in [14];\n\n--  MIB-II (same prefix as MIB-I)\n\nmib-2      OBJECT IDENTIFIER ::= { mgmt 1 }\n\n-- textual conventions\n\nDisplayString ::=\n    OCTET STRING\n-- This data type is used to model textual information taken\n-- from the NVT ASCII character set.  By convention, objects\n-- with this syntax are declared as having\n\n--\n--      SIZE (0..255)\n\nPhysAddress ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"1x:\"\n    STATUS       current\n    DESCRIPTION\n            \"Represents media- or physical-level addresses.\"\n    SYNTAX       OCTET STRING\n\n-- groups in MIB-II\n\nsystem       OBJECT IDENTIFIER ::= { mib-2 1 }\n\ninterfaces   OBJECT IDENTIFIER ::= { mib-2 2 }\n\nat           OBJECT IDENTIFIER ::= { mib-2 3 }\n\nip           OBJECT IDENTIFIER ::= { mib-2 4 }\n\nicmp         OBJECT IDENTIFIER ::= { mib-2 5 }\n\ntcp          OBJECT IDENTIFIER ::= { mib-2 6 }\n\nudp          OBJECT IDENTIFIER ::= { mib-2 7 }\n\negp          OBJECT IDENTIFIER ::= { mib-2 8 }\n\n-- historical (some say hysterical)\n-- cmot      OBJECT IDENTIFIER ::= { mib-2 9 }\n\ntransmission OBJECT IDENTIFIER ::= { mib-2 10 }\n\nsnmp         OBJECT IDENTIFIER ::= { mib-2 11 }\n\n-- the System group\n\n-- Implementation of the System group is mandatory for all\n-- systems.  If an agent is not configured to have a value\n-- for any of these variables, a string of length 0 is\n-- returned.\n\nsysDescr OBJECT-TYPE\n    SYNTAX  DisplayString (SIZE (0..255))\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A textual description of the entity.  This value\n            should include the full name and version\n            identification of the system's hardware type,\n            software operating-system, and networking\n            software.  It is mandatory that this only contain\n            printable ASCII characters.\"\n    ::= { system 1 }\n\nsysObjectID OBJECT-TYPE\n    SYNTAX  OBJECT IDENTIFIER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The vendor's authoritative identification of the\n            network management subsystem contained in the\n            entity.  This value is allocated within the SMI\n            enterprises subtree (1.3.6.1.4.1) and provides an\n            easy and unambiguous means for determining `what\n            kind of box' is being managed.  For example, if\n            vendor `Flintstones, Inc.' was assigned the\n            subtree 1.3.6.1.4.1.4242, it could assign the\n            identifier 1.3.6.1.4.1.4242.1.1 to its `Fred\n            Router'.\"\n    ::= { system 2 }\n\nsysUpTime OBJECT-TYPE\n    SYNTAX  TimeTicks\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The time (in hundredths of a second) since the\n            network management portion of the system was last\n            re-initialized.\"\n    ::= { system 3 }\n\nsysContact OBJECT-TYPE\n    SYNTAX  DisplayString (SIZE (0..255))\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The textual identification of the contact person\n            for this managed node, together with information\n            on how to contact this person.\"\n    ::= { system 4 }\n\nsysName OBJECT-TYPE\n    SYNTAX  DisplayString (SIZE (0..255))\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"An administratively-assigned name for this\n            managed node.  By convention, this is the node's\n            fully-qualified domain name.\"\n    ::= { system 5 }\n\nsysLocation OBJECT-TYPE\n    SYNTAX  DisplayString (SIZE (0..255))\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The physical location of this node (e.g.,\n            `telephone closet, 3rd floor').\"\n    ::= { system 6 }\n\nsysServices OBJECT-TYPE\n    SYNTAX  INTEGER (0..127)\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A value which indicates the set of services that\n            this entity primarily offers.\n\n            The value is a sum.  This sum initially takes the\n            value zero, Then, for each layer, L, in the range\n            1 through 7, that this node performs transactions\n            for, 2 raised to (L - 1) is added to the sum.  For\n            example, a node which performs primarily routing\n            functions would have a value of 4 (2^(3-1)).  In\n            contrast, a node which is a host offering\n            application services would have a value of 72\n            (2^(4-1) + 2^(7-1)).  Note that in the context of\n            the Internet suite of protocols, values should be\n            calculated accordingly:\n\n                 layer  functionality\n                     1  physical (e.g., repeaters)\n                     2  datalink/subnetwork (e.g., bridges)\n                     3  internet (e.g., IP gateways)\n                     4  end-to-end  (e.g., IP hosts)\n                     7  applications (e.g., mail relays)\n\n            For systems including OSI protocols, layers 5 and\n            6 may also be counted.\"\n    ::= { system 7 }\n\n-- the Interfaces group\n\n-- Implementation of the Interfaces group is mandatory for\n-- all systems.\n\nifNumber OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of network interfaces (regardless of\n            their current state) present on this system.\"\n    ::= { interfaces 1 }\n\n-- the Interfaces table\n\n-- The Interfaces table contains information on the entity's\n-- interfaces.  Each interface is thought of as being\n-- attached to a `subnetwork'.  Note that this term should\n-- not be confused with `subnet' which refers to an\n-- addressing partitioning scheme used in the Internet suite\n-- of protocols.\n\nifTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF IfEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"A list of interface entries.  The number of\n            entries is given by the value of ifNumber.\"\n    ::= { interfaces 2 }\n\nifEntry OBJECT-TYPE\n    SYNTAX  IfEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"An interface entry containing objects at the\n            subnetwork layer and below for a particular\n            interface.\"\n    INDEX   { ifIndex }\n    ::= { ifTable 1 }\n\nIfEntry ::=\n    SEQUENCE {\n        ifIndex\n            INTEGER,\n        ifDescr\n            DisplayString,\n        ifType\n            INTEGER,\n        ifMtu\n            INTEGER,\n        ifSpeed\n            Gauge,\n        ifPhysAddress\n            PhysAddress,\n        ifAdminStatus\n            INTEGER,\n        ifOperStatus\n            INTEGER,\n        ifLastChange\n            TimeTicks,\n        ifInOctets\n            Counter,\n        ifInUcastPkts\n            Counter,\n        ifInNUcastPkts\n            Counter,\n        ifInDiscards\n            Counter,\n        ifInErrors\n            Counter,\n        ifInUnknownProtos\n            Counter,\n        ifOutOctets\n            Counter,\n        ifOutUcastPkts\n            Counter,\n        ifOutNUcastPkts\n            Counter,\n        ifOutDiscards\n            Counter,\n        ifOutErrors\n            Counter,\n        ifOutQLen\n            Gauge,\n        ifSpecific\n            OBJECT IDENTIFIER\n    }\n\nifIndex OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A unique value for each interface.  Its value\n            ranges between 1 and the value of ifNumber.  The\n            value for each interface must remain constant at\n            least from one re-initialization of the entity's\n            network management system to the next re-\n            initialization.\"\n    ::= { ifEntry 1 }\n\nifDescr OBJECT-TYPE\n    SYNTAX  DisplayString (SIZE (0..255))\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A textual string containing information about the\n            interface.  This string should include the name of\n            the manufacturer, the product name and the version\n            of the hardware interface.\"\n    ::= { ifEntry 2 }\n\nifType OBJECT-TYPE\n    SYNTAX  INTEGER {\n                other(1),          -- none of the following\n                regular1822(2),\n                hdh1822(3),\n                ddn-x25(4),\n                rfc877-x25(5),\n                ethernet-csmacd(6),\n                iso88023-csmacd(7),\n                iso88024-tokenBus(8),\n                iso88025-tokenRing(9),\n                iso88026-man(10),\n                starLan(11),\n                proteon-10Mbit(12),\n                proteon-80Mbit(13),\n                hyperchannel(14),\n                fddi(15),\n                lapb(16),\n                sdlc(17),\n                ds1(18),           -- T-1\n                e1(19),            -- european equiv. of T-1\n                basicISDN(20),\n                primaryISDN(21),   -- proprietary serial\n                propPointToPointSerial(22),\n                ppp(23),\n                softwareLoopback(24),\n                eon(25),            -- CLNP over IP [11]\n                ethernet-3Mbit(26),\n                nsip(27),           -- XNS over IP\n                slip(28),           -- generic SLIP\n                ultra(29),          -- ULTRA technologies\n                ds3(30),            -- T-3\n                sip(31),            -- SMDS\n                frame-relay(32)\n            }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The type of interface, distinguished according to\n            the physical/link protocol(s) immediately `below'\n            the network layer in the protocol stack.\"\n    ::= { ifEntry 3 }\n\nifMtu OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The size of the largest datagram which can be\n            sent/received on the interface, specified in\n            octets.  For interfaces that are used for\n            transmitting network datagrams, this is the size\n            of the largest network datagram that can be sent\n            on the interface.\"\n    ::= { ifEntry 4 }\n\nifSpeed OBJECT-TYPE\n    SYNTAX  Gauge\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"An estimate of the interface's current bandwidth\n            in bits per second.  For interfaces which do not\n            vary in bandwidth or for those where no accurate\n            estimation can be made, this object should contain\n            the nominal bandwidth.\"\n    ::= { ifEntry 5 }\n\nifPhysAddress OBJECT-TYPE\n    SYNTAX  PhysAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The interface's address at the protocol layer\n            immediately `below' the network layer in the\n            protocol stack.  For interfaces which do not have\n\n            such an address (e.g., a serial line), this object\n            should contain an octet string of zero length.\"\n    ::= { ifEntry 6 }\n\nifAdminStatus OBJECT-TYPE\n    SYNTAX  INTEGER {\n                up(1),       -- ready to pass packets\n                down(2),\n                testing(3)   -- in some test mode\n            }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The desired state of the interface.  The\n            testing(3) state indicates that no operational\n            packets can be passed.\"\n    ::= { ifEntry 7 }\n\nifOperStatus OBJECT-TYPE\n    SYNTAX  INTEGER {\n                up(1),       -- ready to pass packets\n                down(2),\n                testing(3)   -- in some test mode\n            }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The current operational state of the interface.\n            The testing(3) state indicates that no operational\n            packets can be passed.\"\n    ::= { ifEntry 8 }\n\nifLastChange OBJECT-TYPE\n    SYNTAX  TimeTicks\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The value of sysUpTime at the time the interface\n            entered its current operational state.  If the\n            current state was entered prior to the last re-\n            initialization of the local network management\n            subsystem, then this object contains a zero\n            value.\"\n    ::= { ifEntry 9 }\n\nifInOctets OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of octets received on the\n            interface, including framing characters.\"\n    ::= { ifEntry 10 }\n\nifInUcastPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of subnetwork-unicast packets\n            delivered to a higher-layer protocol.\"\n    ::= { ifEntry 11 }\n\nifInNUcastPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of non-unicast (i.e., subnetwork-\n            broadcast or subnetwork-multicast) packets\n            delivered to a higher-layer protocol.\"\n    ::= { ifEntry 12 }\n\nifInDiscards OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of inbound packets which were chosen\n            to be discarded even though no errors had been\n            detected to prevent their being deliverable to a\n            higher-layer protocol.  One possible reason for\n            discarding such a packet could be to free up\n            buffer space.\"\n    ::= { ifEntry 13 }\n\nifInErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of inbound packets that contained\n            errors preventing them from being deliverable to a\n            higher-layer protocol.\"\n    ::= { ifEntry 14 }\n\nifInUnknownProtos OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of packets received via the interface\n            which were discarded because of an unknown or\n            unsupported protocol.\"\n    ::= { ifEntry 15 }\n\nifOutOctets OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of octets transmitted out of the\n            interface, including framing characters.\"\n    ::= { ifEntry 16 }\n\nifOutUcastPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of packets that higher-level\n            protocols requested be transmitted to a\n            subnetwork-unicast address, including those that\n            were discarded or not sent.\"\n    ::= { ifEntry 17 }\n\nifOutNUcastPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of packets that higher-level\n            protocols requested be transmitted to a non-\n            unicast (i.e., a subnetwork-broadcast or\n            subnetwork-multicast) address, including those\n            that were discarded or not sent.\"\n    ::= { ifEntry 18 }\n\nifOutDiscards OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of outbound packets which were chosen\n\n            to be discarded even though no errors had been\n            detected to prevent their being transmitted.  One\n            possible reason for discarding such a packet could\n            be to free up buffer space.\"\n    ::= { ifEntry 19 }\n\nifOutErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of outbound packets that could not be\n            transmitted because of errors.\"\n    ::= { ifEntry 20 }\n\nifOutQLen OBJECT-TYPE\n    SYNTAX  Gauge\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The length of the output packet queue (in\n            packets).\"\n    ::= { ifEntry 21 }\n\nifSpecific OBJECT-TYPE\n    SYNTAX  OBJECT IDENTIFIER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A reference to MIB definitions specific to the\n            particular media being used to realize the\n            interface.  For example, if the interface is\n            realized by an ethernet, then the value of this\n            object refers to a document defining objects\n            specific to ethernet.  If this information is not\n            present, its value should be set to the OBJECT\n            IDENTIFIER { 0 0 }, which is a syntactically valid\n            object identifier, and any conformant\n            implementation of ASN.1 and BER must be able to\n            generate and recognize this value.\"\n    ::= { ifEntry 22 }\n\n-- the Address Translation group\n\n-- Implementation of the Address Translation group is\n-- mandatory for all systems.  Note however that this group\n-- is deprecated by MIB-II. That is, it is being included\n\n-- solely for compatibility with MIB-I nodes, and will most\n-- likely be excluded from MIB-III nodes.  From MIB-II and\n-- onwards, each network protocol group contains its own\n-- address translation tables.\n\n-- The Address Translation group contains one table which is\n-- the union across all interfaces of the translation tables\n-- for converting a NetworkAddress (e.g., an IP address) into\n-- a subnetwork-specific address.  For lack of a better term,\n-- this document refers to such a subnetwork-specific address\n-- as a `physical' address.\n\n-- Examples of such translation tables are: for broadcast\n-- media where ARP is in use, the translation table is\n-- equivalent to the ARP cache; or, on an X.25 network where\n-- non-algorithmic translation to X.121 addresses is\n-- required, the translation table contains the\n-- NetworkAddress to X.121 address equivalences.\n\natTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF AtEntry\n    ACCESS  not-accessible\n    STATUS  deprecated\n    DESCRIPTION\n            \"The Address Translation tables contain the\n            NetworkAddress to `physical' address equivalences.\n            Some interfaces do not use translation tables for\n            determining address equivalences (e.g., DDN-X.25\n            has an algorithmic method); if all interfaces are\n            of this type, then the Address Translation table\n            is empty, i.e., has zero entries.\"\n    ::= { at 1 }\n\natEntry OBJECT-TYPE\n    SYNTAX  AtEntry\n    ACCESS  not-accessible\n    STATUS  deprecated\n    DESCRIPTION\n            \"Each entry contains one NetworkAddress to\n            `physical' address equivalence.\"\n    INDEX   { atIfIndex,\n              atNetAddress }\n    ::= { atTable 1 }\n\nAtEntry ::=\n    SEQUENCE {\n        atIfIndex\n            INTEGER,\n        atPhysAddress\n            PhysAddress,\n        atNetAddress\n            NetworkAddress\n    }\n\natIfIndex OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  deprecated\n    DESCRIPTION\n            \"The interface on which this entry's equivalence\n            is effective.  The interface identified by a\n            particular value of this index is the same\n            interface as identified by the same value of\n            ifIndex.\"\n    ::= { atEntry 1 }\n\natPhysAddress OBJECT-TYPE\n    SYNTAX  PhysAddress\n    ACCESS  read-write\n    STATUS  deprecated\n    DESCRIPTION\n            \"The media-dependent `physical' address.\n\n            Setting this object to a null string (one of zero\n            length) has the effect of invaliding the\n            corresponding entry in the atTable object.  That\n            is, it effectively disassociates the interface\n            identified with said entry from the mapping\n            identified with said entry.  It is an\n            implementation-specific matter as to whether the\n            agent removes an invalidated entry from the table.\n            Accordingly, management stations must be prepared\n            to receive tabular information from agents that\n            corresponds to entries not currently in use.\n            Proper interpretation of such entries requires\n            examination of the relevant atPhysAddress object.\"\n    ::= { atEntry 2 }\n\natNetAddress OBJECT-TYPE\n    SYNTAX  NetworkAddress\n    ACCESS  read-write\n    STATUS  deprecated\n    DESCRIPTION\n            \"The NetworkAddress (e.g., the IP address)\n            corresponding to the media-dependent `physical'\n            address.\"\n    ::= { atEntry 3 }\n\n-- the IP group\n\n-- Implementation of the IP group is mandatory for all\n-- systems.\n\nipForwarding OBJECT-TYPE\n    SYNTAX  INTEGER {\n                forwarding(1),    -- acting as a gateway\n                not-forwarding(2) -- NOT acting as a gateway\n            }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The indication of whether this entity is acting\n            as an IP gateway in respect to the forwarding of\n            datagrams received by, but not addressed to, this\n            entity.  IP gateways forward datagrams.  IP hosts\n            do not (except those source-routed via the host).\n\n            Note that for some managed nodes, this object may\n            take on only a subset of the values possible.\n            Accordingly, it is appropriate for an agent to\n            return a `badValue' response if a management\n            station attempts to change this object to an\n            inappropriate value.\"\n    ::= { ip 1 }\n\nipDefaultTTL OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The default value inserted into the Time-To-Live\n            field of the IP header of datagrams originated at\n            this entity, whenever a TTL value is not supplied\n            by the transport layer protocol.\"\n    ::= { ip 2 }\n\nipInReceives OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of input datagrams received from\n            interfaces, including those received in error.\"\n    ::= { ip 3 }\n\nipInHdrErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of input datagrams discarded due to\n            errors in their IP headers, including bad\n            checksums, version number mismatch, other format\n            errors, time-to-live exceeded, errors discovered\n            in processing their IP options, etc.\"\n    ::= { ip 4 }\n\nipInAddrErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of input datagrams discarded because\n            the IP address in their IP header's destination\n            field was not a valid address to be received at\n            this entity.  This count includes invalid\n            addresses (e.g., 0.0.0.0) and addresses of\n            unsupported Classes (e.g., Class E).  For entities\n            which are not IP Gateways and therefore do not\n            forward datagrams, this counter includes datagrams\n            discarded because the destination address was not\n            a local address.\"\n    ::= { ip 5 }\n\nipForwDatagrams OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of input datagrams for which this\n            entity was not their final IP destination, as a\n            result of which an attempt was made to find a\n            route to forward them to that final destination.\n            In entities which do not act as IP Gateways, this\n            counter will include only those packets which were\n            Source-Routed via this entity, and the Source-\n            Route option processing was successful.\"\n    ::= { ip 6 }\n\nipInUnknownProtos OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of locally-addressed datagrams\n            received successfully but discarded because of an\n            unknown or unsupported protocol.\"\n    ::= { ip 7 }\n\nipInDiscards OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of input IP datagrams for which no\n            problems were encountered to prevent their\n            continued processing, but which were discarded\n            (e.g., for lack of buffer space).  Note that this\n            counter does not include any datagrams discarded\n            while awaiting re-assembly.\"\n    ::= { ip 8 }\n\nipInDelivers OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of input datagrams successfully\n            delivered to IP user-protocols (including ICMP).\"\n    ::= { ip 9 }\n\nipOutRequests OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of IP datagrams which local IP\n            user-protocols (including ICMP) supplied to IP in\n            requests for transmission.  Note that this counter\n            does not include any datagrams counted in\n            ipForwDatagrams.\"\n    ::= { ip 10 }\n\nipOutDiscards OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of output IP datagrams for which no\n\n            problem was encountered to prevent their\n            transmission to their destination, but which were\n            discarded (e.g., for lack of buffer space).  Note\n            that this counter would include datagrams counted\n            in ipForwDatagrams if any such packets met this\n            (discretionary) discard criterion.\"\n    ::= { ip 11 }\n\nipOutNoRoutes OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP datagrams discarded because no\n            route could be found to transmit them to their\n            destination.  Note that this counter includes any\n            packets counted in ipForwDatagrams which meet this\n            `no-route' criterion.  Note that this includes any\n            datagarms which a host cannot route because all of\n            its default gateways are down.\"\n    ::= { ip 12 }\n\nipReasmTimeout OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The maximum number of seconds which received\n            fragments are held while they are awaiting\n            reassembly at this entity.\"\n    ::= { ip 13 }\n\nipReasmReqds OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP fragments received which needed\n            to be reassembled at this entity.\"\n    ::= { ip 14 }\n\nipReasmOKs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP datagrams successfully re-\n            assembled.\"\n    ::= { ip 15 }\n\nipReasmFails OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of failures detected by the IP re-\n            assembly algorithm (for whatever reason: timed\n            out, errors, etc).  Note that this is not\n            necessarily a count of discarded IP fragments\n            since some algorithms (notably the algorithm in\n            RFC 815) can lose track of the number of fragments\n            by combining them as they are received.\"\n    ::= { ip 16 }\n\nipFragOKs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP datagrams that have been\n            successfully fragmented at this entity.\"\n    ::= { ip 17 }\n\nipFragFails OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP datagrams that have been\n            discarded because they needed to be fragmented at\n            this entity but could not be, e.g., because their\n            Don't Fragment flag was set.\"\n    ::= { ip 18 }\n\nipFragCreates OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of IP datagram fragments that have\n            been generated as a result of fragmentation at\n            this entity.\"\n    ::= { ip 19 }\n\n-- the IP address table\n\n-- The IP address table contains this entity's IP addressing\n-- information.\n\nipAddrTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF IpAddrEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"The table of addressing information relevant to\n            this entity's IP addresses.\"\n    ::= { ip 20 }\n\nipAddrEntry OBJECT-TYPE\n    SYNTAX  IpAddrEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"The addressing information for one of this\n            entity's IP addresses.\"\n    INDEX   { ipAdEntAddr }\n    ::= { ipAddrTable 1 }\n\nIpAddrEntry ::=\n    SEQUENCE {\n        ipAdEntAddr\n            IpAddress,\n        ipAdEntIfIndex\n            INTEGER,\n        ipAdEntNetMask\n            IpAddress,\n        ipAdEntBcastAddr\n            INTEGER,\n        ipAdEntReasmMaxSize\n            INTEGER (0..65535)\n    }\n\nipAdEntAddr OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The IP address to which this entry's addressing\n            information pertains.\"\n    ::= { ipAddrEntry 1 }\n\nipAdEntIfIndex OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The index value which uniquely identifies the\n            interface to which this entry is applicable.  The\n            interface identified by a particular value of this\n            index is the same interface as identified by the\n            same value of ifIndex.\"\n    ::= { ipAddrEntry 2 }\n\nipAdEntNetMask OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The subnet mask associated with the IP address of\n            this entry.  The value of the mask is an IP\n            address with all the network bits set to 1 and all\n            the hosts bits set to 0.\"\n    ::= { ipAddrEntry 3 }\n\nipAdEntBcastAddr OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The value of the least-significant bit in the IP\n            broadcast address used for sending datagrams on\n            the (logical) interface associated with the IP\n            address of this entry.  For example, when the\n            Internet standard all-ones broadcast address is\n            used, the value will be 1.  This value applies to\n            both the subnet and network broadcasts addresses\n            used by the entity on this (logical) interface.\"\n    ::= { ipAddrEntry 4 }\n\nipAdEntReasmMaxSize OBJECT-TYPE\n    SYNTAX  INTEGER (0..65535)\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The size of the largest IP datagram which this\n            entity can re-assemble from incoming IP fragmented\n            datagrams received on this interface.\"\n    ::= { ipAddrEntry 5 }\n\n-- the IP routing table\n\n-- The IP routing table contains an entry for each route\n-- presently known to this entity.\n\nipRouteTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF IpRouteEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"This entity's IP Routing table.\"\n    ::= { ip 21 }\n\nipRouteEntry OBJECT-TYPE\n    SYNTAX  IpRouteEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"A route to a particular destination.\"\n    INDEX   { ipRouteDest }\n    ::= { ipRouteTable 1 }\n\nIpRouteEntry ::=\n    SEQUENCE {\n        ipRouteDest\n            IpAddress,\n        ipRouteIfIndex\n            INTEGER,\n        ipRouteMetric1\n            INTEGER,\n        ipRouteMetric2\n            INTEGER,\n        ipRouteMetric3\n            INTEGER,\n        ipRouteMetric4\n            INTEGER,\n        ipRouteNextHop\n            IpAddress,\n        ipRouteType\n            INTEGER,\n        ipRouteProto\n            INTEGER,\n        ipRouteAge\n            INTEGER,\n        ipRouteMask\n            IpAddress,\n        ipRouteMetric5\n            INTEGER,\n        ipRouteInfo\n            OBJECT IDENTIFIER\n    }\n\nipRouteDest OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The destination IP address of this route.  An\n            entry with a value of 0.0.0.0 is considered a\n            default route.  Multiple routes to a single\n            destination can appear in the table, but access to\n            such multiple entries is dependent on the table-\n            access mechanisms defined by the network\n            management protocol in use.\"\n    ::= { ipRouteEntry 1 }\n\nipRouteIfIndex OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The index value which uniquely identifies the\n            local interface through which the next hop of this\n            route should be reached.  The interface identified\n            by a particular value of this index is the same\n            interface as identified by the same value of\n            ifIndex.\"\n    ::= { ipRouteEntry 2 }\n\nipRouteMetric1 OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The primary routing metric for this route.  The\n            semantics of this metric are determined by the\n            routing-protocol specified in the route's\n            ipRouteProto value.  If this metric is not used,\n            its value should be set to -1.\"\n    ::= { ipRouteEntry 3 }\n\nipRouteMetric2 OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"An alternate routing metric for this route.  The\n            semantics of this metric are determined by the\n            routing-protocol specified in the route's\n            ipRouteProto value.  If this metric is not used,\n            its value should be set to -1.\"\n    ::= { ipRouteEntry 4 }\n\nipRouteMetric3 OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"An alternate routing metric for this route.  The\n            semantics of this metric are determined by the\n            routing-protocol specified in the route's\n            ipRouteProto value.  If this metric is not used,\n            its value should be set to -1.\"\n    ::= { ipRouteEntry 5 }\n\nipRouteMetric4 OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"An alternate routing metric for this route.  The\n            semantics of this metric are determined by the\n            routing-protocol specified in the route's\n            ipRouteProto value.  If this metric is not used,\n            its value should be set to -1.\"\n    ::= { ipRouteEntry 6 }\n\nipRouteNextHop OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The IP address of the next hop of this route.\n            (In the case of a route bound to an interface\n            which is realized via a broadcast media, the value\n            of this field is the agent's IP address on that\n            interface.)\"\n    ::= { ipRouteEntry 7 }\n\nipRouteType OBJECT-TYPE\n    SYNTAX  INTEGER {\n                other(1),        -- none of the following\n\n                invalid(2),      -- an invalidated route\n\n                                 -- route to directly\n                direct(3),       -- connected (sub-)network\n\n                                 -- route to a non-local\n                indirect(4)      -- host/network/sub-network\n            }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The type of route.  Note that the values\n            direct(3) and indirect(4) refer to the notion of\n            direct and indirect routing in the IP\n            architecture.\n\n            Setting this object to the value invalid(2) has\n            the effect of invalidating the corresponding entry\n            in the ipRouteTable object.  That is, it\n            effectively disassociates the destination\n            identified with said entry from the route\n            identified with said entry.  It is an\n            implementation-specific matter as to whether the\n            agent removes an invalidated entry from the table.\n            Accordingly, management stations must be prepared\n            to receive tabular information from agents that\n            corresponds to entries not currently in use.\n            Proper interpretation of such entries requires\n            examination of the relevant ipRouteType object.\"\n    ::= { ipRouteEntry 8 }\n\nipRouteProto OBJECT-TYPE\n    SYNTAX  INTEGER {\n                other(1),       -- none of the following\n\n                                -- non-protocol information,\n                                -- e.g., manually configured\n                local(2),       -- entries\n\n                                -- set via a network\n                netmgmt(3),     -- management protocol\n\n                                -- obtained via ICMP,\n                icmp(4),        -- e.g., Redirect\n\n                                -- the remaining values are\n                                -- all gateway routing\n                                -- protocols\n                egp(5),\n                ggp(6),\n                hello(7),\n                rip(8),\n                is-is(9),\n                es-is(10),\n                ciscoIgrp(11),\n                bbnSpfIgp(12),\n                ospf(13),\n                bgp(14)\n            }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The routing mechanism via which this route was\n            learned.  Inclusion of values for gateway routing\n            protocols is not intended to imply that hosts\n            should support those protocols.\"\n    ::= { ipRouteEntry 9 }\n\nipRouteAge OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of seconds since this route was last\n            updated or otherwise determined to be correct.\n            Note that no semantics of `too old' can be implied\n            except through knowledge of the routing protocol\n            by which the route was learned.\"\n    ::= { ipRouteEntry 10 }\n\nipRouteMask OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"Indicate the mask to be logical-ANDed with the\n            destination address before being compared to the\n            value in the ipRouteDest field.  For those systems\n            that do not support arbitrary subnet masks, an\n            agent constructs the value of the ipRouteMask by\n            determining whether the value of the correspondent\n            ipRouteDest field belong to a class-A, B, or C\n            network, and then using one of:\n\n                 mask           network\n                 255.0.0.0      class-A\n                 255.255.0.0    class-B\n                 255.255.255.0  class-C\n\n            If the value of the ipRouteDest is 0.0.0.0 (a\n            default route), then the mask value is also\n            0.0.0.0.  It should be noted that all IP routing\n            subsystems implicitly use this mechanism.\"\n    ::= { ipRouteEntry 11 }\n\nipRouteMetric5 OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"An alternate routing metric for this route.  The\n            semantics of this metric are determined by the\n            routing-protocol specified in the route's\n            ipRouteProto value.  If this metric is not used,\n            its value should be set to -1.\"\n    ::= { ipRouteEntry 12 }\n\nipRouteInfo OBJECT-TYPE\n    SYNTAX  OBJECT IDENTIFIER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"A reference to MIB definitions specific to the\n            particular routing protocol which is responsible\n            for this route, as determined by the value\n            specified in the route's ipRouteProto value.  If\n            this information is not present, its value should\n            be set to the OBJECT IDENTIFIER { 0 0 }, which is\n            a syntactically valid object identifier, and any\n            conformant implementation of ASN.1 and BER must be\n            able to generate and recognize this value.\"\n    ::= { ipRouteEntry 13 }\n\n-- the IP Address Translation table\n\n-- The IP address translation table contain the IpAddress to\n-- `physical' address equivalences.  Some interfaces do not\n-- use translation tables for determining address\n-- equivalences (e.g., DDN-X.25 has an algorithmic method);\n-- if all interfaces are of this type, then the Address\n-- Translation table is empty, i.e., has zero entries.\n\nipNetToMediaTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF IpNetToMediaEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"The IP Address Translation table used for mapping\n            from IP addresses to physical addresses.\"\n    ::= { ip 22 }\n\nipNetToMediaEntry OBJECT-TYPE\n    SYNTAX  IpNetToMediaEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"Each entry contains one IpAddress to `physical'\n            address equivalence.\"\n    INDEX   { ipNetToMediaIfIndex,\n              ipNetToMediaNetAddress }\n    ::= { ipNetToMediaTable 1 }\n\nIpNetToMediaEntry ::=\n    SEQUENCE {\n        ipNetToMediaIfIndex\n            INTEGER,\n        ipNetToMediaPhysAddress\n            PhysAddress,\n        ipNetToMediaNetAddress\n            IpAddress,\n        ipNetToMediaType\n            INTEGER\n    }\n\nipNetToMediaIfIndex OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The interface on which this entry's equivalence\n            is effective.  The interface identified by a\n            particular value of this index is the same\n            interface as identified by the same value of\n            ifIndex.\"\n    ::= { ipNetToMediaEntry 1 }\n\nipNetToMediaPhysAddress OBJECT-TYPE\n    SYNTAX  PhysAddress\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The media-dependent `physical' address.\"\n    ::= { ipNetToMediaEntry 2 }\n\nipNetToMediaNetAddress OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The IpAddress corresponding to the media-\n            dependent `physical' address.\"\n    ::= { ipNetToMediaEntry 3 }\n\nipNetToMediaType OBJECT-TYPE\n    SYNTAX  INTEGER {\n                other(1),        -- none of the following\n                invalid(2),      -- an invalidated mapping\n                dynamic(3),\n                static(4)\n            }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The type of mapping.\n\n            Setting this object to the value invalid(2) has\n            the effect of invalidating the corresponding entry\n            in the ipNetToMediaTable.  That is, it effectively\n            disassociates the interface identified with said\n            entry from the mapping identified with said entry.\n            It is an implementation-specific matter as to\n            whether the agent removes an invalidated entry\n            from the table.  Accordingly, management stations\n            must be prepared to receive tabular information\n            from agents that corresponds to entries not\n            currently in use.  Proper interpretation of such\n            entries requires examination of the relevant\n            ipNetToMediaType object.\"\n    ::= { ipNetToMediaEntry 4 }\n\n-- additional IP objects\n\nipRoutingDiscards OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of routing entries which were chosen\n            to be discarded even though they are valid.  One\n            possible reason for discarding such an entry could\n            be to free-up buffer space for other routing\n\n            entries.\"\n    ::= { ip 23 }\n\n-- the ICMP group\n\n-- Implementation of the ICMP group is mandatory for all\n-- systems.\n\nicmpInMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of ICMP messages which the\n            entity received.  Note that this counter includes\n            all those counted by icmpInErrors.\"\n    ::= { icmp 1 }\n\nicmpInErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP messages which the entity\n            received but determined as having ICMP-specific\n            errors (bad ICMP checksums, bad length, etc.).\"\n    ::= { icmp 2 }\n\nicmpInDestUnreachs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Destination Unreachable\n            messages received.\"\n    ::= { icmp 3 }\n\nicmpInTimeExcds OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Time Exceeded messages\n            received.\"\n    ::= { icmp 4 }\n\nicmpInParmProbs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Parameter Problem messages\n            received.\"\n    ::= { icmp 5 }\n\nicmpInSrcQuenchs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Source Quench messages\n            received.\"\n    ::= { icmp 6 }\n\nicmpInRedirects OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Redirect messages received.\"\n    ::= { icmp 7 }\n\nicmpInEchos OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Echo (request) messages\n            received.\"\n    ::= { icmp 8 }\n\nicmpInEchoReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Echo Reply messages received.\"\n    ::= { icmp 9 }\n\nicmpInTimestamps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Timestamp (request) messages\n            received.\"\n    ::= { icmp 10 }\n\nicmpInTimestampReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Timestamp Reply messages\n            received.\"\n    ::= { icmp 11 }\n\nicmpInAddrMasks OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Address Mask Request messages\n            received.\"\n    ::= { icmp 12 }\n\nicmpInAddrMaskReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Address Mask Reply messages\n            received.\"\n    ::= { icmp 13 }\n\nicmpOutMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of ICMP messages which this\n            entity attempted to send.  Note that this counter\n            includes all those counted by icmpOutErrors.\"\n    ::= { icmp 14 }\n\nicmpOutErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP messages which this entity did\n            not send due to problems discovered within ICMP\n\n            such as a lack of buffers.  This value should not\n            include errors discovered outside the ICMP layer\n            such as the inability of IP to route the resultant\n            datagram.  In some implementations there may be no\n            types of error which contribute to this counter's\n            value.\"\n    ::= { icmp 15 }\n\nicmpOutDestUnreachs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Destination Unreachable\n            messages sent.\"\n    ::= { icmp 16 }\n\nicmpOutTimeExcds OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Time Exceeded messages sent.\"\n    ::= { icmp 17 }\n\nicmpOutParmProbs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Parameter Problem messages\n            sent.\"\n    ::= { icmp 18 }\n\nicmpOutSrcQuenchs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Source Quench messages sent.\"\n    ::= { icmp 19 }\n\nicmpOutRedirects OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Redirect messages sent.  For a\n\n            host, this object will always be zero, since hosts\n            do not send redirects.\"\n    ::= { icmp 20 }\n\nicmpOutEchos OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Echo (request) messages sent.\"\n    ::= { icmp 21 }\n\nicmpOutEchoReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Echo Reply messages sent.\"\n    ::= { icmp 22 }\n\nicmpOutTimestamps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Timestamp (request) messages\n            sent.\"\n    ::= { icmp 23 }\n\nicmpOutTimestampReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Timestamp Reply messages\n            sent.\"\n    ::= { icmp 24 }\n\nicmpOutAddrMasks OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Address Mask Request messages\n            sent.\"\n    ::= { icmp 25 }\n\nicmpOutAddrMaskReps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of ICMP Address Mask Reply messages\n            sent.\"\n    ::= { icmp 26 }\n\n-- the TCP group\n\n-- Implementation of the TCP group is mandatory for all\n-- systems that implement the TCP.\n\n-- Note that instances of object types that represent\n-- information about a particular TCP connection are\n-- transient; they persist only as long as the connection\n-- in question.\n\ntcpRtoAlgorithm OBJECT-TYPE\n    SYNTAX  INTEGER {\n                other(1),    -- none of the following\n\n                constant(2), -- a constant rto\n                rsre(3),     -- MIL-STD-1778, Appendix B\n                vanj(4)      -- Van Jacobson's algorithm [10]\n            }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The algorithm used to determine the timeout value\n            used for retransmitting unacknowledged octets.\"\n    ::= { tcp 1 }\n\ntcpRtoMin OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The minimum value permitted by a TCP\n            implementation for the retransmission timeout,\n            measured in milliseconds.  More refined semantics\n            for objects of this type depend upon the algorithm\n            used to determine the retransmission timeout.  In\n            particular, when the timeout algorithm is rsre(3),\n            an object of this type has the semantics of the\n            LBOUND quantity described in RFC 793.\"\n    ::= { tcp 2 }\n\ntcpRtoMax OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The maximum value permitted by a TCP\n            implementation for the retransmission timeout,\n            measured in milliseconds.  More refined semantics\n            for objects of this type depend upon the algorithm\n            used to determine the retransmission timeout.  In\n            particular, when the timeout algorithm is rsre(3),\n            an object of this type has the semantics of the\n            UBOUND quantity described in RFC 793.\"\n    ::= { tcp 3 }\n\ntcpMaxConn OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The limit on the total number of TCP connections\n            the entity can support.  In entities where the\n            maximum number of connections is dynamic, this\n            object should contain the value -1.\"\n    ::= { tcp 4 }\n\ntcpActiveOpens OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of times TCP connections have made a\n            direct transition to the SYN-SENT state from the\n            CLOSED state.\"\n    ::= { tcp 5 }\n\ntcpPassiveOpens OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of times TCP connections have made a\n            direct transition to the SYN-RCVD state from the\n            LISTEN state.\"\n    ::= { tcp 6 }\n\ntcpAttemptFails OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of times TCP connections have made a\n            direct transition to the CLOSED state from either\n            the SYN-SENT state or the SYN-RCVD state, plus the\n            number of times TCP connections have made a direct\n            transition to the LISTEN state from the SYN-RCVD\n            state.\"\n    ::= { tcp 7 }\n\ntcpEstabResets OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of times TCP connections have made a\n            direct transition to the CLOSED state from either\n            the ESTABLISHED state or the CLOSE-WAIT state.\"\n    ::= { tcp 8 }\n\ntcpCurrEstab OBJECT-TYPE\n    SYNTAX  Gauge\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of TCP connections for which the\n            current state is either ESTABLISHED or CLOSE-\n            WAIT.\"\n    ::= { tcp 9 }\n\ntcpInSegs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of segments received, including\n            those received in error.  This count includes\n            segments received on currently established\n            connections.\"\n    ::= { tcp 10 }\n\ntcpOutSegs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of segments sent, including\n            those on current connections but excluding those\n            containing only retransmitted octets.\"\n    ::= { tcp 11 }\n\ntcpRetransSegs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of segments retransmitted - that\n            is, the number of TCP segments transmitted\n            containing one or more previously transmitted\n            octets.\"\n    ::= { tcp 12 }\n\n-- the TCP Connection table\n\n-- The TCP connection table contains information about this\n-- entity's existing TCP connections.\n\ntcpConnTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF TcpConnEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"A table containing TCP connection-specific\n            information.\"\n    ::= { tcp 13 }\n\ntcpConnEntry OBJECT-TYPE\n    SYNTAX  TcpConnEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"Information about a particular current TCP\n            connection.  An object of this type is transient,\n            in that it ceases to exist when (or soon after)\n            the connection makes the transition to the CLOSED\n            state.\"\n    INDEX   { tcpConnLocalAddress,\n              tcpConnLocalPort,\n              tcpConnRemAddress,\n              tcpConnRemPort }\n    ::= { tcpConnTable 1 }\n\nTcpConnEntry ::=\n    SEQUENCE {\n        tcpConnState\n            INTEGER,\n        tcpConnLocalAddress\n            IpAddress,\n        tcpConnLocalPort\n            INTEGER (0..65535),\n        tcpConnRemAddress\n            IpAddress,\n        tcpConnRemPort\n            INTEGER (0..65535)\n    }\n\ntcpConnState OBJECT-TYPE\n    SYNTAX  INTEGER {\n                closed(1),\n                listen(2),\n                synSent(3),\n                synReceived(4),\n                established(5),\n                finWait1(6),\n                finWait2(7),\n                closeWait(8),\n                lastAck(9),\n                closing(10),\n                timeWait(11),\n                deleteTCB(12)\n            }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"The state of this TCP connection.\n\n            The only value which may be set by a management\n            station is deleteTCB(12).  Accordingly, it is\n            appropriate for an agent to return a `badValue'\n            response if a management station attempts to set\n            this object to any other value.\n\n            If a management station sets this object to the\n            value deleteTCB(12), then this has the effect of\n            deleting the TCB (as defined in RFC 793) of the\n            corresponding connection on the managed node,\n            resulting in immediate termination of the\n            connection.\n\n            As an implementation-specific option, a RST\n\n            segment may be sent from the managed node to the\n            other TCP endpoint (note however that RST segments\n            are not sent reliably).\"\n    ::= { tcpConnEntry 1 }\n\ntcpConnLocalAddress OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The local IP address for this TCP connection.  In\n            the case of a connection in the listen state which\n            is willing to accept connections for any IP\n            interface associated with the node, the value\n            0.0.0.0 is used.\"\n    ::= { tcpConnEntry 2 }\n\ntcpConnLocalPort OBJECT-TYPE\n    SYNTAX  INTEGER (0..65535)\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The local port number for this TCP connection.\"\n    ::= { tcpConnEntry 3 }\n\ntcpConnRemAddress OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The remote IP address for this TCP connection.\"\n    ::= { tcpConnEntry 4 }\n\ntcpConnRemPort OBJECT-TYPE\n    SYNTAX  INTEGER (0..65535)\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The remote port number for this TCP connection.\"\n    ::= { tcpConnEntry 5 }\n\n-- additional TCP objects\n\ntcpInErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of segments received in error\n            (e.g., bad TCP checksums).\"\n    ::= { tcp 14 }\n\ntcpOutRsts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of TCP segments sent containing the\n            RST flag.\"\n    ::= { tcp 15 }\n\n-- the UDP group\n\n-- Implementation of the UDP group is mandatory for all\n-- systems which implement the UDP.\n\nudpInDatagrams OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of UDP datagrams delivered to\n            UDP users.\"\n    ::= { udp 1 }\n\nudpNoPorts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of received UDP datagrams for\n            which there was no application at the destination\n            port.\"\n    ::= { udp 2 }\n\nudpInErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of received UDP datagrams that could\n            not be delivered for reasons other than the lack\n            of an application at the destination port.\"\n    ::= { udp 3 }\n\nudpOutDatagrams OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of UDP datagrams sent from this\n            entity.\"\n    ::= { udp 4 }\n\n-- the UDP Listener table\n\n-- The UDP listener table contains information about this\n-- entity's UDP end-points on which a local application is\n-- currently accepting datagrams.\n\nudpTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF UdpEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"A table containing UDP listener information.\"\n    ::= { udp 5 }\n\nudpEntry OBJECT-TYPE\n    SYNTAX  UdpEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"Information about a particular current UDP\n            listener.\"\n    INDEX   { udpLocalAddress, udpLocalPort }\n    ::= { udpTable 1 }\n\nUdpEntry ::=\n    SEQUENCE {\n        udpLocalAddress\n            IpAddress,\n        udpLocalPort\n            INTEGER (0..65535)\n    }\n\nudpLocalAddress OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The local IP address for this UDP listener.  In\n\n            the case of a UDP listener which is willing to\n            accept datagrams for any IP interface associated\n            with the node, the value 0.0.0.0 is used.\"\n    ::= { udpEntry 1 }\n\nudpLocalPort OBJECT-TYPE\n    SYNTAX  INTEGER (0..65535)\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The local port number for this UDP listener.\"\n    ::= { udpEntry 2 }\n\n-- the EGP group\n\n-- Implementation of the EGP group is mandatory for all\n-- systems which implement the EGP.\n\negpInMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP messages received without\n            error.\"\n    ::= { egp 1 }\n\negpInErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP messages received that proved\n            to be in error.\"\n    ::= { egp 2 }\n\negpOutMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of locally generated EGP\n            messages.\"\n    ::= { egp 3 }\n\negpOutErrors OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of locally generated EGP messages not\n            sent due to resource limitations within an EGP\n            entity.\"\n    ::= { egp 4 }\n\n-- the EGP Neighbor table\n\n-- The EGP neighbor table contains information about this\n-- entity's EGP neighbors.\n\negpNeighTable OBJECT-TYPE\n    SYNTAX  SEQUENCE OF EgpNeighEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"The EGP neighbor table.\"\n    ::= { egp 5 }\n\negpNeighEntry OBJECT-TYPE\n    SYNTAX  EgpNeighEntry\n    ACCESS  not-accessible\n    STATUS  mandatory\n    DESCRIPTION\n            \"Information about this entity's relationship with\n            a particular EGP neighbor.\"\n    INDEX   { egpNeighAddr }\n    ::= { egpNeighTable 1 }\n\nEgpNeighEntry ::=\n    SEQUENCE {\n        egpNeighState\n            INTEGER,\n        egpNeighAddr\n            IpAddress,\n        egpNeighAs\n            INTEGER,\n        egpNeighInMsgs\n            Counter,\n        egpNeighInErrs\n            Counter,\n        egpNeighOutMsgs\n            Counter,\n        egpNeighOutErrs\n            Counter,\n        egpNeighInErrMsgs\n            Counter,\n        egpNeighOutErrMsgs\n            Counter,\n        egpNeighStateUps\n            Counter,\n        egpNeighStateDowns\n            Counter,\n        egpNeighIntervalHello\n            INTEGER,\n        egpNeighIntervalPoll\n            INTEGER,\n        egpNeighMode\n            INTEGER,\n        egpNeighEventTrigger\n            INTEGER\n    }\n\negpNeighState OBJECT-TYPE\n    SYNTAX  INTEGER {\n                idle(1),\n                acquisition(2),\n                down(3),\n                up(4),\n                cease(5)\n            }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The EGP state of the local system with respect to\n            this entry's EGP neighbor.  Each EGP state is\n            represented by a value that is one greater than\n            the numerical value associated with said state in\n            RFC 904.\"\n    ::= { egpNeighEntry 1 }\n\negpNeighAddr OBJECT-TYPE\n    SYNTAX  IpAddress\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The IP address of this entry's EGP neighbor.\"\n    ::= { egpNeighEntry 2 }\n\negpNeighAs OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The autonomous system of this EGP peer.  Zero\n            should be specified if the autonomous system\n            number of the neighbor is not yet known.\"\n    ::= { egpNeighEntry 3 }\n\negpNeighInMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP messages received without error\n            from this EGP peer.\"\n    ::= { egpNeighEntry 4 }\n\negpNeighInErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP messages received from this EGP\n            peer that proved to be in error (e.g., bad EGP\n            checksum).\"\n    ::= { egpNeighEntry 5 }\n\negpNeighOutMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of locally generated EGP messages to\n            this EGP peer.\"\n    ::= { egpNeighEntry 6 }\n\negpNeighOutErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of locally generated EGP messages not\n            sent to this EGP peer due to resource limitations\n            within an EGP entity.\"\n    ::= { egpNeighEntry 7 }\n\negpNeighInErrMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP-defined error messages received\n            from this EGP peer.\"\n    ::= { egpNeighEntry 8 }\n\negpNeighOutErrMsgs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP-defined error messages sent to\n            this EGP peer.\"\n    ::= { egpNeighEntry 9 }\n\negpNeighStateUps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP state transitions to the UP\n            state with this EGP peer.\"\n    ::= { egpNeighEntry 10 }\n\negpNeighStateDowns OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The number of EGP state transitions from the UP\n            state to any other state with this EGP peer.\"\n    ::= { egpNeighEntry 11 }\n\negpNeighIntervalHello OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The interval between EGP Hello command\n            retransmissions (in hundredths of a second).  This\n            represents the t1 timer as defined in RFC 904.\"\n    ::= { egpNeighEntry 12 }\n\negpNeighIntervalPoll OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The interval between EGP poll command\n\n            retransmissions (in hundredths of a second).  This\n            represents the t3 timer as defined in RFC 904.\"\n    ::= { egpNeighEntry 13 }\n\negpNeighMode OBJECT-TYPE\n    SYNTAX  INTEGER { active(1), passive(2) }\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The polling mode of this EGP entity, either\n            passive or active.\"\n    ::= { egpNeighEntry 14 }\n\negpNeighEventTrigger OBJECT-TYPE\n    SYNTAX  INTEGER { start(1), stop(2) }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"A control variable used to trigger operator-\n            initiated Start and Stop events.  When read, this\n            variable always returns the most recent value that\n            egpNeighEventTrigger was set to.  If it has not\n            been set since the last initialization of the\n            network management subsystem on the node, it\n            returns a value of `stop'.\n\n            When set, this variable causes a Start or Stop\n            event on the specified neighbor, as specified on\n            pages 8-10 of RFC 904.  Briefly, a Start event\n            causes an Idle peer to begin neighbor acquisition\n            and a non-Idle peer to reinitiate neighbor\n            acquisition.  A stop event causes a non-Idle peer\n            to return to the Idle state until a Start event\n            occurs, either via egpNeighEventTrigger or\n            otherwise.\"\n    ::= { egpNeighEntry 15 }\n\n-- additional EGP objects\n\negpAs OBJECT-TYPE\n    SYNTAX  INTEGER\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The autonomous system number of this EGP entity.\"\n    ::= { egp 6 }\n\n-- the Transmission group\n\n-- Based on the transmission media underlying each interface\n-- on a system, the corresponding portion of the Transmission\n-- group is mandatory for that system.\n\n-- When Internet-standard definitions for managing\n-- transmission media are defined, the transmission group is\n-- used to provide a prefix for the names of those objects.\n\n-- Typically, such definitions reside in the experimental\n-- portion of the MIB until they are \"proven\", then as a\n-- part of the Internet standardization process, the\n-- definitions are accordingly elevated and a new object\n-- identifier, under the transmission group is defined. By\n-- convention, the name assigned is:\n--\n--     type OBJECT IDENTIFIER    ::= { transmission number }\n--\n-- where \"type\" is the symbolic value used for the media in\n-- the ifType column of the ifTable object, and \"number\" is\n-- the actual integer value corresponding to the symbol.\n\n-- the SNMP group\n\n-- Implementation of the SNMP group is mandatory for all\n-- systems which support an SNMP protocol entity.  Some of\n-- the objects defined below will be zero-valued in those\n-- SNMP implementations that are optimized to support only\n-- those functions specific to either a management agent or\n-- a management station.  In particular, it should be\n-- observed that the objects below refer to an SNMP entity,\n-- and there may be several SNMP entities residing on a\n-- managed node (e.g., if the node is hosting acting as\n-- a management station).\n\nsnmpInPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of Messages delivered to the\n            SNMP entity from the transport service.\"\n    ::= { snmp 1 }\n\nsnmpOutPkts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Messages which were\n            passed from the SNMP protocol entity to the\n            transport service.\"\n    ::= { snmp 2 }\n\nsnmpInBadVersions OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Messages which were\n            delivered to the SNMP protocol entity and were for\n            an unsupported SNMP version.\"\n    ::= { snmp 3 }\n\nsnmpInBadCommunityNames OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Messages delivered to\n            the SNMP protocol entity which used a SNMP\n            community name not known to said entity.\"\n    ::= { snmp 4 }\n\nsnmpInBadCommunityUses OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Messages delivered to\n            the SNMP protocol entity which represented an SNMP\n            operation which was not allowed by the SNMP\n            community named in the Message.\"\n    ::= { snmp 5 }\n\nsnmpInASNParseErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of ASN.1 or BER errors\n            encountered by the SNMP protocol entity when\n            decoding received SNMP Messages.\"\n    ::= { snmp 6 }\n\n-- { snmp 7 } is not used\n\nsnmpInTooBigs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            delivered to the SNMP protocol entity and for\n            which the value of the error-status field is\n            `tooBig'.\"\n    ::= { snmp 8 }\n\nsnmpInNoSuchNames OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            delivered to the SNMP protocol entity and for\n            which the value of the error-status field is\n            `noSuchName'.\"\n    ::= { snmp 9 }\n\nsnmpInBadValues OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            delivered to the SNMP protocol entity and for\n            which the value of the error-status field is\n            `badValue'.\"\n    ::= { snmp 10 }\n\nsnmpInReadOnlys OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number valid SNMP PDUs which were\n            delivered to the SNMP protocol entity and for\n            which the value of the error-status field is\n            `readOnly'.  It should be noted that it is a\n            protocol error to generate an SNMP PDU which\n            contains the value `readOnly' in the error-status\n            field, as such this object is provided as a means\n            of detecting incorrect implementations of the\n\n            SNMP.\"\n    ::= { snmp 11 }\n\nsnmpInGenErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            delivered to the SNMP protocol entity and for\n            which the value of the error-status field is\n            `genErr'.\"\n    ::= { snmp 12 }\n\nsnmpInTotalReqVars OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of MIB objects which have been\n            retrieved successfully by the SNMP protocol entity\n            as the result of receiving valid SNMP Get-Request\n            and Get-Next PDUs.\"\n    ::= { snmp 13 }\n\nsnmpInTotalSetVars OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of MIB objects which have been\n            altered successfully by the SNMP protocol entity\n            as the result of receiving valid SNMP Set-Request\n            PDUs.\"\n    ::= { snmp 14 }\n\nsnmpInGetRequests OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Request PDUs which\n            have been accepted and processed by the SNMP\n            protocol entity.\"\n    ::= { snmp 15 }\n\nsnmpInGetNexts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Next PDUs which have\n            been accepted and processed by the SNMP protocol\n            entity.\"\n    ::= { snmp 16 }\n\nsnmpInSetRequests OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Set-Request PDUs which\n            have been accepted and processed by the SNMP\n            protocol entity.\"\n    ::= { snmp 17 }\n\nsnmpInGetResponses OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Response PDUs which\n            have been accepted and processed by the SNMP\n            protocol entity.\"\n    ::= { snmp 18 }\n\nsnmpInTraps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Trap PDUs which have\n            been accepted and processed by the SNMP protocol\n            entity.\"\n    ::= { snmp 19 }\n\nsnmpOutTooBigs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            generated by the SNMP protocol entity and for\n            which the value of the error-status field is\n            `tooBig.'\"\n    ::= { snmp 20 }\n\nsnmpOutNoSuchNames OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            generated by the SNMP protocol entity and for\n            which the value of the error-status is\n            `noSuchName'.\"\n    ::= { snmp 21 }\n\nsnmpOutBadValues OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            generated by the SNMP protocol entity and for\n            which the value of the error-status field is\n            `badValue'.\"\n    ::= { snmp 22 }\n\n-- { snmp 23 } is not used\n\nsnmpOutGenErrs OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP PDUs which were\n            generated by the SNMP protocol entity and for\n            which the value of the error-status field is\n            `genErr'.\"\n    ::= { snmp 24 }\n\nsnmpOutGetRequests OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Request PDUs which\n            have been generated by the SNMP protocol entity.\"\n    ::= { snmp 25 }\n\nsnmpOutGetNexts OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Next PDUs which have\n            been generated by the SNMP protocol entity.\"\n    ::= { snmp 26 }\n\nsnmpOutSetRequests OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Set-Request PDUs which\n            have been generated by the SNMP protocol entity.\"\n    ::= { snmp 27 }\n\nsnmpOutGetResponses OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Get-Response PDUs which\n            have been generated by the SNMP protocol entity.\"\n    ::= { snmp 28 }\n\nsnmpOutTraps OBJECT-TYPE\n    SYNTAX  Counter\n    ACCESS  read-only\n    STATUS  mandatory\n    DESCRIPTION\n            \"The total number of SNMP Trap PDUs which have\n            been generated by the SNMP protocol entity.\"\n    ::= { snmp 29 }\n\nsnmpEnableAuthenTraps OBJECT-TYPE\n    SYNTAX  INTEGER { enabled(1), disabled(2) }\n    ACCESS  read-write\n    STATUS  mandatory\n    DESCRIPTION\n            \"Indicates whether the SNMP agent process is\n            permitted to generate authentication-failure\n            traps.  The value of this object overrides any\n            configuration information; as such, it provides a\n            means whereby all authentication-failure traps may\n            be disabled.\n\n            Note that it is strongly recommended that this\n            object be stored in non-volatile memory so that it\n            remains constant between re-initializations of the\n            network management system.\"\n    ::= { snmp 30 }\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/tableMibImports",
    "content": "RFC1155-SMI DEFINITIONS ::= BEGIN\n\nEXPORTS -- EVERYTHING\n        internet, directory, mgmt,\n        experimental, private, enterprises,\n        OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax,\n        ApplicationSyntax, NetworkAddress, IpAddress,\n        Counter, Gauge, TimeTicks, Opaque;\n\n -- the path to the root\n\n internet      OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }\n\n directory     OBJECT IDENTIFIER ::= { internet 1 }\n\n mgmt          OBJECT IDENTIFIER ::= { internet 2 }\n\n experimental  OBJECT IDENTIFIER ::= { internet 3 }\n\n private       OBJECT IDENTIFIER ::= { internet 4 }\n enterprises   OBJECT IDENTIFIER ::= { private 1 }\n\n -- definition of object types\n\n OBJECT-TYPE MACRO ::=\n BEGIN\n     TYPE NOTATION ::= \"SYNTAX\" type (TYPE ObjectSyntax)\n                       \"ACCESS\" Access\n                       \"STATUS\" Status\n     VALUE NOTATION ::= value (VALUE ObjectName)\n\n     Access ::= \"read-only\"\n                     | \"read-write\"\n                     | \"write-only\"\n                     | \"not-accessible\"\n     Status ::= \"mandatory\"\n                     | \"optional\"\n                     | \"obsolete\"\n END\n\n    -- names of objects in the MIB\n\n    ObjectName ::=\n        OBJECT IDENTIFIER\n\n    -- syntax of objects in the MIB\n\n    ObjectSyntax ::=\n        CHOICE {\n            simple\n                SimpleSyntax,\n    -- note that simple SEQUENCEs are not directly\n    -- mentioned here to keep things simple (i.e.,\n    -- prevent mis-use).  However, application-wide\n    -- types which are IMPLICITly encoded simple\n    -- SEQUENCEs may appear in the following CHOICE\n\n            application-wide\n                ApplicationSyntax\n        }\n\n       SimpleSyntax ::=\n           CHOICE {\n               number\n                   INTEGER,\n               string\n                   OCTET STRING,\n               object\n                   OBJECT IDENTIFIER,\n               empty\n                   NULL\n           }\n\n       ApplicationSyntax ::=\n           CHOICE {\n               address\n                   NetworkAddress,\n               counter\n                   Counter,\n               gauge\n                   Gauge,\n               ticks\n                   TimeTicks,\n               arbitrary\n                   Opaque\n\n       -- other application-wide types, as they are\n       -- defined, will be added here\n           }\n\n       -- application-wide types\n\n       NetworkAddress ::=\n           CHOICE {\n               internet\n                   IpAddress\n           }\n\n       IpAddress ::=\n           [APPLICATION 0]          -- in network-byte order\n               IMPLICIT OCTET STRING (SIZE (4))\n\n       Counter ::=\n           [APPLICATION 1]\n               IMPLICIT INTEGER (0..4294967295)\n\n       Gauge ::=\n           [APPLICATION 2]\n               IMPLICIT INTEGER (0..4294967295)\n\n       TimeTicks ::=\n           [APPLICATION 3]\n               IMPLICIT INTEGER (0..4294967295)\n\n       Opaque ::=\n           [APPLICATION 4]          -- arbitrary ASN.1 value,\n               IMPLICIT OCTET STRING   --   \"double-wrapped\"\n\n       END"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/tcpMib",
    "content": "TCP-MIB DEFINITIONS ::= BEGIN\n\nIMPORTS\n    MODULE-IDENTITY, OBJECT-TYPE, Integer32, Unsigned32,\n    Gauge32, Counter32, Counter64, IpAddress, mib-2,\n    MODULE-COMPLIANCE, OBJECT-GROUP, InetAddress, \n    InetAddressType, InetPortNumber  \n    FROM tcpMibImports;\n\n\n\ntcpMIB MODULE-IDENTITY\n    LAST-UPDATED \"200502180000Z\"  -- 18 February 2005\n    ORGANIZATION\n           \"IETF IPv6 MIB Revision Team\n            http://www.ietf.org/html.charters/ipv6-charter.html\"\n    CONTACT-INFO\n           \"Rajiv Raghunarayan (editor)\n\n            Cisco Systems Inc.\n            170 West Tasman Drive\n            San Jose, CA 95134\n\n            Phone: +1 408 853 9612\n            Email: <raraghun@cisco.com>\n\n            Send comments to <ipv6@ietf.org>\"\n    DESCRIPTION\n           \"The MIB module for managing TCP implementations.\n\n            Copyright (C) The Internet Society (2005). This version\n            of this MIB module is a part of RFC 4022; see the RFC\n            itself for full legal notices.\"\n    REVISION      \"200502180000Z\"  -- 18 February 2005\n    DESCRIPTION\n           \"IP version neutral revision, published as RFC 4022.\"\n    REVISION      \"9411010000Z\"\n    DESCRIPTION\n           \"Initial SMIv2 version, published as RFC 2012.\"\n    REVISION      \"9103310000Z\"\n    DESCRIPTION\n           \"The initial revision of this MIB module was part of\n            MIB-II.\"\n    ::= { mib-2 49 }\n\n-- the TCP base variables group\n\ntcp      OBJECT IDENTIFIER ::= { mib-2 6 }\n\n-- Scalars\n\ntcpRtoAlgorithm OBJECT-TYPE\n    SYNTAX      INTEGER {\n                    other(1),    -- none of the following\n                    constant(2), -- a constant rto\n                    rsre(3),     -- MIL-STD-1778, Appendix B\n                    vanj(4),     -- Van Jacobson's algorithm\n                    rfc2988(5)   -- RFC 2988\n                }\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The algorithm used to determine the timeout value used for\n            retransmitting unacknowledged octets.\"\n    ::= { tcp 1 }\n\ntcpRtoMin OBJECT-TYPE\n    SYNTAX     Integer32 (0..2147483647)\n    UNITS      \"milliseconds\"\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The minimum value permitted by a TCP implementation for\n            the retransmission timeout, measured in milliseconds.\n            More refined semantics for objects of this type depend\n            on the algorithm used to determine the retransmission\n            timeout; in particular, the IETF standard algorithm\n            rfc2988(5) provides a minimum value.\"\n    ::= { tcp 2 }\n\ntcpRtoMax OBJECT-TYPE\n    SYNTAX     Integer32 (0..2147483647)\n    UNITS      \"milliseconds\"\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The maximum value permitted by a TCP implementation for\n            the retransmission timeout, measured in milliseconds.\n            More refined semantics for objects of this type depend\n            on the algorithm used to determine the retransmission\n            timeout; in particular, the IETF standard algorithm\n            rfc2988(5) provides an upper bound (as part of an\n            adaptive backoff algorithm).\"\n    ::= { tcp 3 }\n\ntcpMaxConn OBJECT-TYPE\n    SYNTAX     Integer32 (-1 | 0..2147483647)\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The limit on the total number of TCP connections the entity\n            can support.  In entities where the maximum number of\n            connections is dynamic, this object should contain the\n            value -1.\"\n    ::= { tcp 4 }\n\ntcpActiveOpens OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of times that TCP connections have made a direct\n            transition to the SYN-SENT state from the CLOSED state.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 5 }\n\ntcpPassiveOpens OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of times TCP connections have made a direct\n            transition to the SYN-RCVD state from the LISTEN state.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 6 }\n\ntcpAttemptFails OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of times that TCP connections have made a direct\n            transition to the CLOSED state from either the SYN-SENT\n            state or the SYN-RCVD state, plus the number of times that\n            TCP connections have made a direct transition to the\n            LISTEN state from the SYN-RCVD state.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 7 }\n\ntcpEstabResets OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of times that TCP connections have made a direct\n            transition to the CLOSED state from either the ESTABLISHED\n            state or the CLOSE-WAIT state.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 8 }\n\ntcpCurrEstab OBJECT-TYPE\n    SYNTAX     Gauge32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of TCP connections for which the current state\n            is either ESTABLISHED or CLOSE-WAIT.\"\n    ::= { tcp 9 }\n\ntcpInSegs OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments received, including those\n            received in error.  This count includes segments received\n            on currently established connections.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 10 }\n\ntcpOutSegs OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments sent, including those on\n            current connections but excluding those containing only\n            retransmitted octets.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 11 }\n\ntcpRetransSegs OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments retransmitted; that is, the\n            number of TCP segments transmitted containing one or more\n            previously transmitted octets.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 12 }\n\ntcpInErrs OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments received in error (e.g., bad\n            TCP checksums).\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 14 }\n\ntcpOutRsts OBJECT-TYPE\n    SYNTAX     Counter32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The number of TCP segments sent containing the RST flag.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 15 }\n\n-- { tcp 16 } was used to represent the ipv6TcpConnTable in RFC 2452,\n-- which has since been obsoleted.  It MUST not be used.\n\ntcpHCInSegs OBJECT-TYPE\n    SYNTAX     Counter64\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments received, including those\n            received in error.  This count includes segments received\n\n            on currently established connections.  This object is\n            the 64-bit equivalent of tcpInSegs.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 17 }\n\ntcpHCOutSegs OBJECT-TYPE\n    SYNTAX     Counter64\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The total number of segments sent, including those on\n            current connections but excluding those containing only\n            retransmitted octets.  This object is the 64-bit\n            equivalent of tcpOutSegs.\n\n            Discontinuities in the value of this counter are\n            indicated via discontinuities in the value of sysUpTime.\"\n    ::= { tcp 18 }\n\n-- The TCP Connection table\n\ntcpConnectionTable OBJECT-TYPE\n    SYNTAX     SEQUENCE OF TcpConnectionEntry\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"A table containing information about existing TCP\n            connections.  Note that unlike earlier TCP MIBs, there\n            is a separate table for connections in the LISTEN state.\"\n    ::= { tcp 19 }\n\ntcpConnectionEntry OBJECT-TYPE\n    SYNTAX     TcpConnectionEntry\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"A conceptual row of the tcpConnectionTable containing\n            information about a particular current TCP connection.\n            Each row of this table is transient in that it ceases to\n            exist when (or soon after) the connection makes the\n            transition to the CLOSED state.\"\n    INDEX   { tcpConnectionLocalAddressType,\n              tcpConnectionLocalAddress,\n              tcpConnectionLocalPort,\n              tcpConnectionRemAddressType,\n              tcpConnectionRemAddress,\n              tcpConnectionRemPort }\n    ::= { tcpConnectionTable 1 }\n\nTcpConnectionEntry ::= SEQUENCE {\n        tcpConnectionLocalAddressType   InetAddressType,\n        tcpConnectionLocalAddress       InetAddress,\n        tcpConnectionLocalPort          InetPortNumber,\n        tcpConnectionRemAddressType     InetAddressType,\n        tcpConnectionRemAddress         InetAddress,\n        tcpConnectionRemPort            InetPortNumber,\n        tcpConnectionState              INTEGER,\n        tcpConnectionProcess            Unsigned32\n    }\n\ntcpConnectionLocalAddressType OBJECT-TYPE\n    SYNTAX     InetAddressType\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The address type of tcpConnectionLocalAddress.\"\n    ::= { tcpConnectionEntry 1 }\n\ntcpConnectionLocalAddress OBJECT-TYPE\n    SYNTAX     InetAddress\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"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    ::= { tcpConnectionEntry 2 }\n\ntcpConnectionLocalPort OBJECT-TYPE\n    SYNTAX     InetPortNumber\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The local port number for this TCP connection.\"\n    ::= { tcpConnectionEntry 3 }\n\ntcpConnectionRemAddressType OBJECT-TYPE\n    SYNTAX     InetAddressType\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The address type of tcpConnectionRemAddress.\"\n    ::= { tcpConnectionEntry 4 }\n\ntcpConnectionRemAddress OBJECT-TYPE\n    SYNTAX     InetAddress\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The remote IP address for this TCP connection.  The type\n            of this address is determined by the value of\n            tcpConnectionRemAddressType.\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    ::= { tcpConnectionEntry 5 }\n\ntcpConnectionRemPort OBJECT-TYPE\n    SYNTAX     InetPortNumber\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The remote port number for this TCP connection.\"\n    ::= { tcpConnectionEntry 6 }\n\ntcpConnectionState OBJECT-TYPE\n    SYNTAX     INTEGER {\n                    closed(1),\n                    listen(2),\n                    synSent(3),\n                    synReceived(4),\n                    established(5),\n                    finWait1(6),\n                    finWait2(7),\n                    closeWait(8),\n                    lastAck(9),\n                    closing(10),\n                    timeWait(11),\n                    deleteTCB(12)\n                }\n    MAX-ACCESS read-write\n    STATUS     current\n    DESCRIPTION\n           \"The state of this TCP connection.\n\n            The value listen(2) is included only for parallelism to the\n            old tcpConnTable and should not be used.  A connection in\n            LISTEN state should be present in the tcpListenerTable.\n\n            The only value that may be set by a management station is\n            deleteTCB(12).  Accordingly, it is appropriate for an agent\n            to return a `badValue' response if a management station\n            attempts to set this object to any other value.\n\n            If a management station sets this object to the value\n            deleteTCB(12), then the TCB (as defined in [RFC793]) of\n            the corresponding connection on the managed node is\n            deleted, resulting in immediate termination of the\n            connection.\n\n            As an implementation-specific option, a RST segment may be\n            sent from the managed node to the other TCP endpoint (note,\n            however, that RST segments are not sent reliably).\"\n    ::= { tcpConnectionEntry 7 }\n\ntcpConnectionProcess OBJECT-TYPE\n    SYNTAX     Unsigned32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The system's process ID for the process associated with\n            this connection, or zero if there is no such process.  This\n            value is expected to be the same as HOST-RESOURCES-MIB::\n            hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some\n            row in the appropriate tables.\"\n    ::= { tcpConnectionEntry 8 }\n\n-- The TCP Listener table\n\ntcpListenerTable OBJECT-TYPE\n    SYNTAX     SEQUENCE OF TcpListenerEntry\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"A table containing information about TCP listeners.  A\n            listening application can be represented in three\n            possible ways:\n\n            1. An application that is willing to accept both IPv4 and\n               IPv6 datagrams is represented by\n\n               a tcpListenerLocalAddressType of unknown (0) and\n               a tcpListenerLocalAddress of ''h (a zero-length\n               octet-string).\n\n            2. An application that is willing to accept only IPv4 or\n               IPv6 datagrams is represented by a\n               tcpListenerLocalAddressType of the appropriate address\n               type and a tcpListenerLocalAddress of '0.0.0.0' or '::'\n               respectively.\n\n            3. An application that is listening for data destined\n               only to a specific IP address, but from any remote\n               system, is represented by a tcpListenerLocalAddressType\n               of an appropriate address type, with\n               tcpListenerLocalAddress as the specific local address.\n\n            NOTE: The address type in this table represents the\n            address type used for the communication, irrespective\n            of the higher-layer abstraction.  For example, an\n            application using IPv6 'sockets' to communicate via\n            IPv4 between ::ffff:10.0.0.1 and ::ffff:10.0.0.2 would\n            use InetAddressType ipv4(1)).\"\n    ::= { tcp 20 }\n\ntcpListenerEntry OBJECT-TYPE\n    SYNTAX     TcpListenerEntry\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"A conceptual row of the tcpListenerTable containing\n            information about a particular TCP listener.\"\n    INDEX   { tcpListenerLocalAddressType,\n              tcpListenerLocalAddress,\n              tcpListenerLocalPort }\n    ::= { tcpListenerTable 1 }\n\nTcpListenerEntry ::= SEQUENCE {\n        tcpListenerLocalAddressType       InetAddressType,\n        tcpListenerLocalAddress           InetAddress,\n        tcpListenerLocalPort              InetPortNumber,\n        tcpListenerProcess                Unsigned32\n    }\n\ntcpListenerLocalAddressType OBJECT-TYPE\n    SYNTAX     InetAddressType\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The address type of tcpListenerLocalAddress.  The value\n            should be unknown (0) if connection initiations to all\n            local IP addresses are accepted.\"\n    ::= { tcpListenerEntry 1 }\n\ntcpListenerLocalAddress OBJECT-TYPE\n    SYNTAX     InetAddress\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The local IP address for this TCP connection.\n\n            The value of this object can be represented in three\n            possible ways, depending on the characteristics of the\n            listening application:\n\n            1. For an application willing to accept both IPv4 and\n               IPv6 datagrams, the value of this object must be\n               ''h (a zero-length octet-string), with the value\n               of the corresponding tcpListenerLocalAddressType\n               object being unknown (0).\n\n            2. For an application willing to accept only IPv4 or\n               IPv6 datagrams, the value of this object must be\n               '0.0.0.0' or '::' respectively, with\n               tcpListenerLocalAddressType representing the\n               appropriate address type.\n\n            3. For an application which is listening for data\n               destined only to a specific IP address, the value\n               of this object is the specific local address, with\n               tcpListenerLocalAddressType representing the\n               appropriate address type.\n\n            As this object is used in the index for the\n            tcpListenerTable, 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, using SNMPv1, SNMPv2c, or SNMPv3.\"\n    ::= { tcpListenerEntry 2 }\n\ntcpListenerLocalPort OBJECT-TYPE\n    SYNTAX     InetPortNumber\n    MAX-ACCESS not-accessible\n    STATUS     current\n    DESCRIPTION\n           \"The local port number for this TCP connection.\"\n    ::= { tcpListenerEntry 3 }\n\ntcpListenerProcess OBJECT-TYPE\n    SYNTAX     Unsigned32\n    MAX-ACCESS read-only\n    STATUS     current\n    DESCRIPTION\n           \"The system's process ID for the process associated with\n            this listener, or zero if there is no such process.  This\n            value is expected to be the same as HOST-RESOURCES-MIB::\n            hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some\n            row in the appropriate tables.\"\n    ::= { tcpListenerEntry 4 }\n\n-- The deprecated TCP Connection table\n\ntcpConnTable OBJECT-TYPE\n    SYNTAX     SEQUENCE OF TcpConnEntry\n    MAX-ACCESS not-accessible\n    STATUS     deprecated\n    DESCRIPTION\n           \"A table containing information about existing IPv4-specific\n            TCP connections or listeners.  This table has been\n            deprecated in favor of the version neutral\n            tcpConnectionTable.\"\n    ::= { tcp 13 }\n\ntcpConnEntry OBJECT-TYPE\n    SYNTAX     TcpConnEntry\n    MAX-ACCESS not-accessible\n    STATUS     deprecated\n    DESCRIPTION\n           \"A conceptual row of the tcpConnTable containing information\n            about a particular current IPv4 TCP connection.  Each row\n            of this table is transient in that it ceases to exist when\n            (or soon after) the connection makes the transition to the\n            CLOSED state.\"\n    INDEX   { tcpConnLocalAddress,\n              tcpConnLocalPort,\n              tcpConnRemAddress,\n              tcpConnRemPort }\n    ::= { tcpConnTable 1 }\n\nTcpConnEntry ::= SEQUENCE {\n        tcpConnState         INTEGER,\n        tcpConnLocalAddress  IpAddress,\n        tcpConnLocalPort     Integer32,\n        tcpConnRemAddress    IpAddress,\n        tcpConnRemPort       Integer32\n\n    }\n\ntcpConnState OBJECT-TYPE\n    SYNTAX     INTEGER {\n                    closed(1),\n                    listen(2),\n                    synSent(3),\n                    synReceived(4),\n                    established(5),\n                    finWait1(6),\n                    finWait2(7),\n                    closeWait(8),\n                    lastAck(9),\n                    closing(10),\n                    timeWait(11),\n                    deleteTCB(12)\n                }\n    MAX-ACCESS read-write\n    STATUS     deprecated\n    DESCRIPTION\n           \"The state of this TCP connection.\n\n            The only value that may be set by a management station is\n            deleteTCB(12).  Accordingly, it is appropriate for an agent\n            to return a `badValue' response if a management station\n            attempts to set this object to any other value.\n\n            If a management station sets this object to the value\n            deleteTCB(12), then the TCB (as defined in [RFC793]) of\n            the corresponding connection on the managed node is\n            deleted, resulting in immediate termination of the\n            connection.\n\n            As an implementation-specific option, a RST segment may be\n            sent from the managed node to the other TCP endpoint (note,\n            however, that RST segments are not sent reliably).\"\n    ::= { tcpConnEntry 1 }\n\ntcpConnLocalAddress OBJECT-TYPE\n    SYNTAX     IpAddress\n    MAX-ACCESS read-only\n    STATUS     deprecated\n    DESCRIPTION\n           \"The local IP address for this TCP connection.  In the case\n            of a connection in the listen state willing to\n            accept connections for any IP interface associated with the\n            node, the value 0.0.0.0 is used.\"\n    ::= { tcpConnEntry 2 }\n\ntcpConnLocalPort OBJECT-TYPE\n    SYNTAX     Integer32 (0..65535)\n    MAX-ACCESS read-only\n    STATUS     deprecated\n    DESCRIPTION\n           \"The local port number for this TCP connection.\"\n    ::= { tcpConnEntry 3 }\n\ntcpConnRemAddress OBJECT-TYPE\n    SYNTAX     IpAddress\n    MAX-ACCESS read-only\n    STATUS     deprecated\n    DESCRIPTION\n           \"The remote IP address for this TCP connection.\"\n    ::= { tcpConnEntry 4 }\n\ntcpConnRemPort OBJECT-TYPE\n    SYNTAX     Integer32 (0..65535)\n    MAX-ACCESS read-only\n    STATUS     deprecated\n    DESCRIPTION\n           \"The remote port number for this TCP connection.\"\n    ::= { tcpConnEntry 5 }\n\n-- conformance information\n\ntcpMIBConformance OBJECT IDENTIFIER ::= { tcpMIB 2 }\n\ntcpMIBCompliances OBJECT IDENTIFIER ::= { tcpMIBConformance 1 }\ntcpMIBGroups      OBJECT IDENTIFIER ::= { tcpMIBConformance 2 }\n\n-- compliance statements\n\ntcpMIBCompliance2 MODULE-COMPLIANCE\n    STATUS     current\n    DESCRIPTION\n           \"The compliance statement for systems that implement TCP.\n\n            A number of INDEX objects cannot be\n            represented in the form of OBJECT clauses in SMIv2 but\n            have the following compliance requirements,\n            expressed in OBJECT clause form in this description\n            clause:\n\n            -- OBJECT      tcpConnectionLocalAddressType\n            -- SYNTAX      InetAddressType { ipv4(1), ipv6(2) }\n            -- DESCRIPTION\n            --     This MIB requires support for only global IPv4\n\n            --     and IPv6 address types.\n            --\n            -- OBJECT      tcpConnectionRemAddressType\n            -- SYNTAX      InetAddressType { ipv4(1), ipv6(2) }\n            -- DESCRIPTION\n            --     This MIB requires support for only global IPv4\n            --     and IPv6 address types.\n            --\n            -- OBJECT      tcpListenerLocalAddressType\n            -- SYNTAX      InetAddressType { unknown(0), ipv4(1),\n            --                               ipv6(2) }\n            -- DESCRIPTION\n            --     This MIB requires support for only global IPv4\n            --     and IPv6 address types.  The type unknown also\n            --     needs to be supported to identify a special\n            --     case in the listener table: a listen using\n            --     both IPv4 and IPv6 addresses on the device.\n            --\n           \"\n    MODULE  -- this module\n        MANDATORY-GROUPS { tcpBaseGroup, tcpConnectionGroup,\n                           tcpListenerGroup }\n        GROUP       tcpHCGroup\n        DESCRIPTION\n           \"This group is mandatory for systems that are capable\n            of receiving or transmitting more than 1 million TCP\n            segments per second.  1 million segments per second will\n            cause a Counter32 to wrap in just over an hour.\"\n        OBJECT      tcpConnectionState\n        SYNTAX      INTEGER { closed(1), listen(2), synSent(3),\n                              synReceived(4), established(5),\n                              finWait1(6), finWait2(7), closeWait(8),\n                              lastAck(9), closing(10), timeWait(11) }\n        MIN-ACCESS  read-only\n        DESCRIPTION\n           \"Write access is not required, nor is support for the value\n            deleteTCB (12).\"\n    ::= { tcpMIBCompliances 2 }\n\ntcpMIBCompliance MODULE-COMPLIANCE\n    STATUS     deprecated\n    DESCRIPTION\n           \"The compliance statement for IPv4-only systems that\n            implement TCP.  In order to be IP version independent, this\n            compliance statement is deprecated in favor of\n            tcpMIBCompliance2.  However, agents are still encouraged\n            to implement these objects in order to interoperate with\n            the deployed base of managers.\"\n\n    MODULE  -- this module\n        MANDATORY-GROUPS { tcpGroup }\n        OBJECT      tcpConnState\n        MIN-ACCESS  read-only\n        DESCRIPTION\n           \"Write access is not required.\"\n    ::= { tcpMIBCompliances 1 }\n\n-- units of conformance\n\ntcpGroup OBJECT-GROUP\n    OBJECTS   { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax,\n                tcpMaxConn, tcpActiveOpens,\n                tcpPassiveOpens, tcpAttemptFails,\n                tcpEstabResets, tcpCurrEstab, tcpInSegs,\n                tcpOutSegs, tcpRetransSegs, tcpConnState,\n                tcpConnLocalAddress, tcpConnLocalPort,\n                tcpConnRemAddress, tcpConnRemPort,\n                tcpInErrs, tcpOutRsts }\n    STATUS     deprecated\n    DESCRIPTION\n           \"The tcp group of objects providing for management of TCP\n            entities.\"\n    ::= { tcpMIBGroups 1 }\n\ntcpBaseGroup OBJECT-GROUP\n    OBJECTS   { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax,\n                tcpMaxConn, tcpActiveOpens,\n                tcpPassiveOpens, tcpAttemptFails,\n                tcpEstabResets, tcpCurrEstab, tcpInSegs,\n                tcpOutSegs, tcpRetransSegs,\n                tcpInErrs, tcpOutRsts }\n    STATUS     current\n    DESCRIPTION\n           \"The group of counters common to TCP entities.\"\n    ::= { tcpMIBGroups 2 }\n\ntcpConnectionGroup OBJECT-GROUP\n    OBJECTS    { tcpConnectionState, tcpConnectionProcess }\n    STATUS     current\n    DESCRIPTION\n           \"The group provides general information about TCP\n            connections.\"\n    ::= { tcpMIBGroups 3 }\n\ntcpListenerGroup OBJECT-GROUP\n    OBJECTS    { tcpListenerProcess }\n    STATUS     current\n    DESCRIPTION\n           \"This group has objects providing general information about\n            TCP listeners.\"\n    ::= { tcpMIBGroups 4 }\n\ntcpHCGroup OBJECT-GROUP\n    OBJECTS    { tcpHCInSegs, tcpHCOutSegs }\n    STATUS     current\n    DESCRIPTION\n           \"The group of objects providing for counters of high speed\n            TCP implementations.\"\n    ::= { tcpMIBGroups 5 }\n\nEND\n"
  },
  {
    "path": "plugins/common/snmp/testdata/gosmi/tcpMibImports",
    "content": "SNMPv2-SMI DEFINITIONS ::= BEGIN\n\n-- the path to the root\n\norg            OBJECT IDENTIFIER ::= { iso 3 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 6 }\ninternet       OBJECT IDENTIFIER ::= { dod 1 }\n\ndirectory      OBJECT IDENTIFIER ::= { internet 1 }\n\nmgmt           OBJECT IDENTIFIER ::= { internet 2 }\nmib-2          OBJECT IDENTIFIER ::= { mgmt 1 }\ntransmission   OBJECT IDENTIFIER ::= { mib-2 10 }\n\nexperimental   OBJECT IDENTIFIER ::= { internet 3 }\n\nprivate        OBJECT IDENTIFIER ::= { internet 4 }\nenterprises    OBJECT IDENTIFIER ::= { private 1 }\n\nsecurity       OBJECT IDENTIFIER ::= { internet 5 }\n\nsnmpV2         OBJECT IDENTIFIER ::= { internet 6 }\n\n-- transport domains\nsnmpDomains    OBJECT IDENTIFIER ::= { snmpV2 1 }\n\n-- transport proxies\nsnmpProxys     OBJECT IDENTIFIER ::= { snmpV2 2 }\n\n-- module identities\nsnmpModules    OBJECT IDENTIFIER ::= { snmpV2 3 }\n\n-- Extended UTCTime, to allow dates with four-digit years\n-- (Note that this definition of ExtUTCTime is not to be IMPORTed\n--  by MIB modules.)\nExtUTCTime ::= OCTET STRING(SIZE(11 | 13))\n    -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ\n\n    --   where: YY   - last two digits of year (only years\n    --                 between 1900-1999)\n    --          YYYY - last four digits of the year (any year)\n    --          MM   - month (01 through 12)\n    --          DD   - day of month (01 through 31)\n    --          HH   - hours (00 through 23)\n    --          MM   - minutes (00 through 59)\n    --          Z    - denotes GMT (the ASCII character Z)\n    --\n    -- For example, \"9502192015Z\" and \"199502192015Z\" represent\n    -- 8:15pm GMT on 19 February 1995. Years after 1999 must use\n    -- the four digit year format. Years 1900-1999 may use the\n    -- two or four digit format.\n\n-- definitions for information modules\n\nMODULE-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"LAST-UPDATED\" value(Update ExtUTCTime)\n                  \"ORGANIZATION\" Text\n                  \"CONTACT-INFO\" Text\n                  \"DESCRIPTION\" Text\n                  RevisionPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    RevisionPart ::=\n                  Revisions\n                | empty\n    Revisions ::=\n                  Revision\n                | Revisions Revision\n    Revision ::=\n                  \"REVISION\" value(Update ExtUTCTime)\n                  \"DESCRIPTION\" Text\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\nOBJECT-IDENTITY MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- names of objects\n-- (Note that these definitions of ObjectName and NotificationName\n--  are not to be IMPORTed by MIB modules.)\n\nObjectName ::=\n    OBJECT IDENTIFIER\n\nNotificationName ::=\n    OBJECT IDENTIFIER\n\n-- syntax of objects\n\n-- the \"base types\" defined here are:\n--   3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER\n--   8 application-defined types: Integer32, IpAddress, Counter32,\n--              Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64\n\nObjectSyntax ::=\n    CHOICE {\n        simple\n            SimpleSyntax,\n          -- note that SEQUENCEs for conceptual tables and\n          -- rows are not mentioned here...\n\n        application-wide\n            ApplicationSyntax\n    }\n\n-- built-in ASN.1 types\n\nSimpleSyntax ::=\n    CHOICE {\n        -- INTEGERs with a more restrictive range\n        -- may also be used\n        integer-value               -- includes Integer32\n            INTEGER (-2147483648..2147483647),\n        -- OCTET STRINGs with a more restrictive size\n        -- may also be used\n        string-value\n            OCTET STRING (SIZE (0..65535)),\n        objectID-value\n            OBJECT IDENTIFIER\n    }\n\n-- indistinguishable from INTEGER, but never needs more than\n-- 32-bits for a two's complement representation\nInteger32 ::=\n        INTEGER (-2147483648..2147483647)\n\n-- application-wide types\n\nApplicationSyntax ::=\n    CHOICE {\n        ipAddress-value\n            IpAddress,\n        counter-value\n            Counter32,\n        timeticks-value\n            TimeTicks,\n        arbitrary-value\n            Opaque,\n        big-counter-value\n            Counter64,\n        unsigned-integer-value  -- includes Gauge32\n            Unsigned32\n    }\n\n-- in network-byte order\n\n-- (this is a tagged type for historical reasons)\nIpAddress ::=\n    [APPLICATION 0]\n        IMPLICIT OCTET STRING (SIZE (4))\n\n-- this wraps\nCounter32 ::=\n    [APPLICATION 1]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- this doesn't wrap\nGauge32 ::=\n    [APPLICATION 2]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- an unsigned 32-bit quantity\n-- indistinguishable from Gauge32\nUnsigned32 ::=\n    [APPLICATION 2]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- hundredths of seconds since an epoch\nTimeTicks ::=\n    [APPLICATION 3]\n        IMPLICIT INTEGER (0..4294967295)\n\n-- for backward-compatibility only\nOpaque ::=\n    [APPLICATION 4]\n        IMPLICIT OCTET STRING\n\n-- for counters that wrap in less than one hour with only 32 bits\nCounter64 ::=\n    [APPLICATION 6]\n        IMPLICIT INTEGER (0..18446744073709551615)\n\n-- definition for objects\n\nOBJECT-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"SYNTAX\" Syntax\n                  UnitsPart\n                  \"MAX-ACCESS\" Access\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n                  IndexPart\n                  DefValPart\n\n    VALUE NOTATION ::=\n                  value(VALUE ObjectName)\n\n    Syntax ::=   -- Must be one of the following:\n                       -- a base type (or its refinement),\n                       -- a textual convention (or its refinement), or\n                       -- a BITS pseudo-type\n                   type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\n    UnitsPart ::=\n                  \"UNITS\" Text\n                | empty\n\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    IndexPart ::=\n                  \"INDEX\"    \"{\" IndexTypes \"}\"\n                | \"AUGMENTS\" \"{\" Entry      \"}\"\n                | empty\n    IndexTypes ::=\n                  IndexType\n                | IndexTypes \",\" IndexType\n    IndexType ::=\n                  \"IMPLIED\" Index\n                | Index\n\n    Index ::=\n                    -- use the SYNTAX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n    Entry ::=\n                    -- use the INDEX value of the\n                    -- correspondent OBJECT-TYPE invocation\n                  value(ObjectName)\n\n    DefValPart ::= \"DEFVAL\" \"{\" Defvalue \"}\"\n                | empty\n\n    Defvalue ::=  -- must be valid for the type specified in\n                  -- SYNTAX clause of same OBJECT-TYPE macro\n                  value(ObjectSyntax)\n                | \"{\" BitsValue \"}\"\n\n    BitsValue ::= BitNames\n                | empty\n\n    BitNames ::=  BitName\n                | BitNames \",\" BitName\n\n    BitName ::= identifier\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- definitions for notifications\n\nNOTIFICATION-TYPE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  ObjectsPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE NotificationName)\n\n    ObjectsPart ::=\n                  \"OBJECTS\" \"{\" Objects \"}\"\n                | empty\n    Objects ::=\n                  Object\n\n                | Objects \",\" Object\n    Object ::=\n                  value(ObjectName)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in section 3.1.1\n    Text ::= value(IA5String)\nEND\n\n-- definitions of administrative identifiers\n\nzeroDotZero    OBJECT-IDENTITY\n    STATUS     current\n    DESCRIPTION\n            \"A value used for null identifiers.\"\n    ::= { 0 0 }\n\n\n\nTEXTUAL-CONVENTION MACRO ::=\n\nBEGIN\n    TYPE NOTATION ::=\n                  DisplayPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n                  \"SYNTAX\" Syntax\n\n    VALUE NOTATION ::=\n                   value(VALUE Syntax)      -- adapted ASN.1\n\n    DisplayPart ::=\n                  \"DISPLAY-HINT\" Text\n                | empty\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\n\n    Syntax ::=   -- Must be one of the following:\n                       -- a base type (or its refinement), or\n                       -- a BITS pseudo-type\n                  type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::=  identifier \"(\" number \")\" -- number is nonnegative\n\nEND\n\nMODULE-COMPLIANCE MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n                  ModulePart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    ModulePart ::=\n                  Modules\n    Modules ::=\n                  Module\n                | Modules Module\n    Module ::=\n                  -- name of module --\n                  \"MODULE\" ModuleName\n                  MandatoryPart\n                  CompliancePart\n\n    ModuleName ::=\n                  -- identifier must start with uppercase letter\n                  identifier ModuleIdentifier\n                  -- must not be empty unless contained\n                  -- in MIB Module\n                | empty\n    ModuleIdentifier ::=\n                  value(OBJECT IDENTIFIER)\n                | empty\n\n    MandatoryPart ::=\n                  \"MANDATORY-GROUPS\" \"{\" Groups \"}\"\n                | empty\n\n    Groups ::=\n\n                  Group\n                | Groups \",\" Group\n    Group ::=\n                  value(OBJECT IDENTIFIER)\n\n    CompliancePart ::=\n                  Compliances\n                | empty\n\n    Compliances ::=\n                  Compliance\n                | Compliances Compliance\n    Compliance ::=\n                  ComplianceGroup\n                | Object\n\n    ComplianceGroup ::=\n                  \"GROUP\" value(OBJECT IDENTIFIER)\n                  \"DESCRIPTION\" Text\n\n    Object ::=\n                  \"OBJECT\" value(ObjectName)\n                  SyntaxPart\n                  WriteSyntaxPart\n                  AccessPart\n                  \"DESCRIPTION\" Text\n\n    -- must be a refinement for object's SYNTAX clause\n    SyntaxPart ::= \"SYNTAX\" Syntax\n                | empty\n\n    -- must be a refinement for object's SYNTAX clause\n    WriteSyntaxPart ::= \"WRITE-SYNTAX\" Syntax\n                | empty\n\n    Syntax ::=    -- Must be one of the following:\n                       -- a base type (or its refinement),\n                       -- a textual convention (or its refinement), or\n                       -- a BITS pseudo-type\n                  type\n                | \"BITS\" \"{\" NamedBits \"}\"\n\n    NamedBits ::= NamedBit\n                | NamedBits \",\" NamedBit\n\n    NamedBit ::= identifier \"(\" number \")\" -- number is nonnegative\n\n    AccessPart ::=\n                  \"MIN-ACCESS\" Access\n                | empty\n    Access ::=\n                  \"not-accessible\"\n                | \"accessible-for-notify\"\n                | \"read-only\"\n                | \"read-write\"\n                | \"read-create\"\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\nEND\n\nOBJECT-GROUP MACRO ::=\nBEGIN\n    TYPE NOTATION ::=\n                  ObjectsPart\n                  \"STATUS\" Status\n                  \"DESCRIPTION\" Text\n                  ReferPart\n\n    VALUE NOTATION ::=\n                  value(VALUE OBJECT IDENTIFIER)\n\n    ObjectsPart ::=\n                  \"OBJECTS\" \"{\" Objects \"}\"\n    Objects ::=\n                  Object\n                | Objects \",\" Object\n    Object ::=\n\n                  value(ObjectName)\n\n    Status ::=\n                  \"current\"\n                | \"deprecated\"\n                | \"obsolete\"\n\n    ReferPart ::=\n                  \"REFERENCE\" Text\n                | empty\n\n    -- a character string as defined in [2]\n    Text ::= value(IA5String)\nEND\n\nInetPortNumber ::= TEXTUAL-CONVENTION\n    DISPLAY-HINT \"d\"\n    STATUS       current\n    DESCRIPTION\n        \"Represents a 16 bit port number of an Internet transport\n\n         layer protocol.  Port numbers are assigned by IANA.  A\n         current list of all assignments is available from\n         <http://www.iana.org/>.\n\n         The value zero is object-specific and must be defined as\n         part of the description of any object that uses this\n         syntax.  Examples of the usage of zero might include\n         situations where a port number is unknown, or when the\n         value zero is used as a wildcard in a filter.\"\n    REFERENCE   \"STD 6 (RFC 768), STD 7 (RFC 793) and RFC 2960\"\n    SYNTAX       Unsigned32 (0..65535)\n\n\nInetAddress ::= TEXTUAL-CONVENTION\n    STATUS      current\n    DESCRIPTION\n        \"Denotes a generic Internet address.\n\n         An InetAddress value is always interpreted within the context\n         of an InetAddressType value.  Every usage of the InetAddress\n         textual convention is required to specify the InetAddressType\n         object that provides the context.  It is suggested that the\n         InetAddressType object be logically registered before the\n         object(s) that use the InetAddress textual convention, if\n         they appear in the same logical row.\n\n         The value of an InetAddress object must always be\n         consistent with the value of the associated InetAddressType\n         object.  Attempts to set an InetAddress object to a value\n         inconsistent with the associated InetAddressType\n         must fail with an inconsistentValue error.\n\n         When this textual convention is used as the syntax of an\n         index object, there may be issues with the limit of 128\n         sub-identifiers specified in SMIv2, STD 58.  In this case,\n         the object definition MUST include a 'SIZE' clause to\n         limit the number of potential instance sub-identifiers;\n         otherwise the applicable constraints MUST be stated in\n         the appropriate conceptual row DESCRIPTION clauses, or\n         in the surrounding documentation if there is no single\n         DESCRIPTION clause that is appropriate.\"\n    SYNTAX       OCTET STRING (SIZE (0..255))\n\nInetAddressType ::= TEXTUAL-CONVENTION\n    STATUS      current\n    DESCRIPTION\n        \"A value that represents a type of Internet address.\n\n         unknown(0)  An unknown address type.  This value MUST\n                     be used if the value of the corresponding\n                     InetAddress object is a zero-length string.\n                     It may also be used to indicate an IP address\n                     that is not in one of the formats defined\n                     below.\n\n         ipv4(1)     An IPv4 address as defined by the\n                     InetAddressIPv4 textual convention.\n\n         ipv6(2)     An IPv6 address as defined by the\n                     InetAddressIPv6 textual convention.\n\n         ipv4z(3)    A non-global IPv4 address including a zone\n                     index as defined by the InetAddressIPv4z\n                     textual convention.\n\n         ipv6z(4)    A non-global IPv6 address including a zone\n                     index as defined by the InetAddressIPv6z\n                     textual convention.\n\n         dns(16)     A DNS domain name as defined by the\n                     InetAddressDNS textual convention.\n\n         Each definition of a concrete InetAddressType value must be\n         accompanied by a definition of a textual convention for use\n         with that InetAddressType.\n\n         To support future extensions, the InetAddressType textual\n         convention SHOULD NOT be sub-typed in object type definitions.\n         It MAY be sub-typed in compliance statements in order to\n         require only a subset of these address types for a compliant\n         implementation.\n\n         Implementations must ensure that InetAddressType objects\n         and any dependent objects (e.g., InetAddress objects) are\n         consistent.  An inconsistentValue error must be generated\n         if an attempt to change an InetAddressType object would,\n         for example, lead to an undefined InetAddress value.  In\n\n         particular, InetAddressType/InetAddress pairs must be\n         changed together if the address type changes (e.g., from\n         ipv6(2) to ipv4(1)).\"\n    SYNTAX       INTEGER {\n                     unknown(0),\n                     ipv4(1),\n                     ipv6(2),\n                     ipv4z(3),\n                     ipv6z(4),\n                     dns(16)\n                 }\n\n\n\n\n\nEND"
  },
  {
    "path": "plugins/common/snmp/testdata/loadMibsFromPath/linkTarget/emptyFile",
    "content": ""
  },
  {
    "path": "plugins/common/snmp/testdata/loadMibsFromPath/root/dirOne/dirTwo/empty",
    "content": ""
  },
  {
    "path": "plugins/common/snmp/testdata/mibs/testmib",
    "content": "TGTEST-MIB DEFINITIONS ::= BEGIN\n\norg            OBJECT IDENTIFIER ::= { iso 3 }  --  \"iso\" = 1\ndod            OBJECT IDENTIFIER ::= { org 6 }\ninternet       OBJECT IDENTIFIER ::= { dod 1 }\nmgmt           OBJECT IDENTIFIER ::= { internet 2 }\nmibs           OBJECT IDENTIFIER ::= { mgmt 1 }\nsystem         OBJECT IDENTIFIER ::= { mibs 1 }\nsystemUpTime   OBJECT IDENTIFIER ::= { system 3 }\nsysUpTimeInstance OBJECT IDENTIFIER ::= { systemUpTime 0 }\n\nprivate        OBJECT IDENTIFIER ::= { internet 4 }\nenterprises    OBJECT IDENTIFIER ::= { private 1 }\n\nsnmpV2         OBJECT IDENTIFIER ::= { internet 6 }\nsnmpModules      OBJECT IDENTIFIER ::= { snmpV2 3 }\nsnmpMIB          OBJECT IDENTIFIER ::= { snmpModules 1 }\nsnmpMIBObjects   OBJECT IDENTIFIER ::= { snmpMIB 1 }\nsnmpTraps        OBJECT IDENTIFIER ::= { snmpMIBObjects 5 }\ncoldStart        OBJECT IDENTIFIER ::= { snmpTraps 1 }\n\nEND\n"
  },
  {
    "path": "plugins/common/snmp/translator.go",
    "content": "package snmp\n\ntype TranslatorPlugin interface {\n\tSetTranslator(name string) // Agent calls this on inputs before Init\n}\n\ntype Translator interface {\n\tSnmpTranslate(oid string) (\n\t\tmibName string, oidNum string, oidText string,\n\t\tconversion string,\n\t\terr error,\n\t)\n\n\tSnmpTable(oid string) (\n\t\tmibName string, oidNum string, oidText string,\n\t\tfields []Field,\n\t\terr error,\n\t)\n\n\tSnmpFormatEnum(oid string, value interface{}, full bool) (\n\t\tformatted string,\n\t\terr error,\n\t)\n\n\tSnmpFormatDisplayHint(oid string, value interface{}) (\n\t\tformatted string,\n\t\terr error,\n\t)\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_gosmi.go",
    "content": "package snmp\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/sleepinggenius2/gosmi\"\n\t\"github.com/sleepinggenius2/gosmi/models\"\n\t\"github.com/sleepinggenius2/gosmi/types\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nvar errCannotFormatUnkownType = errors.New(\"cannot format value, unknown type\")\n\ntype gosmiTranslator struct {\n}\n\nfunc NewGosmiTranslator(paths []string, log telegraf.Logger) (*gosmiTranslator, error) {\n\terr := LoadMibsFromPath(paths, log, &GosmiMibLoader{})\n\tif err == nil {\n\t\treturn &gosmiTranslator{}, nil\n\t}\n\treturn nil, err\n}\n\n//nolint:revive //function-result-limit conditionally 5 return results allowed\nfunc (g *gosmiTranslator) SnmpTranslate(oid string) (mibName string, oidNum string, oidText string, conversion string, err error) {\n\tmibName, oidNum, oidText, conversion, _, err = snmpTranslateCall(oid)\n\treturn mibName, oidNum, oidText, conversion, err\n}\n\n// snmpTable resolves the given OID as a table, providing information about the\n// table and fields within.\n//\n//nolint:revive //Too many return variable but necessary\nfunc (g *gosmiTranslator) SnmpTable(oid string) (\n\tmibName string, oidNum string, oidText string,\n\tfields []Field,\n\terr error) {\n\tmibName, oidNum, oidText, _, node, err := snmpTranslateCall(oid)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", nil, fmt.Errorf(\"translating: %w\", err)\n\t}\n\n\tmibPrefix := mibName + \"::\"\n\n\tcol, tagOids := getIndex(mibPrefix, node)\n\tfor _, c := range col {\n\t\t_, isTag := tagOids[mibPrefix+c]\n\t\tfields = append(fields, Field{Name: c, Oid: mibPrefix + c, IsTag: isTag})\n\t}\n\n\treturn mibName, oidNum, oidText, fields, nil\n}\n\nfunc (*gosmiTranslator) SnmpFormatEnum(oid string, value interface{}, full bool) (string, error) {\n\tif value == nil {\n\t\treturn \"\", nil\n\t}\n\n\t//nolint:dogsled // only need to get the node\n\t_, _, _, _, node, err := snmpTranslateCall(oid)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif node.Type == nil {\n\t\treturn \"\", errCannotFormatUnkownType\n\t}\n\n\tvar v models.Value\n\tif full {\n\t\tv = node.FormatValue(value, models.FormatEnumName, models.FormatEnumValue)\n\t} else {\n\t\tv = node.FormatValue(value, models.FormatEnumName)\n\t}\n\n\treturn v.String(), nil\n}\n\nfunc (*gosmiTranslator) SnmpFormatDisplayHint(oid string, value interface{}) (string, error) {\n\tif value == nil {\n\t\treturn \"\", nil\n\t}\n\n\t//nolint:dogsled // only need to get the node\n\t_, _, _, _, node, err := snmpTranslateCall(oid)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif node.Type == nil {\n\t\treturn \"\", errCannotFormatUnkownType\n\t}\n\n\treturn node.FormatValue(value).String(), nil\n}\n\nfunc getIndex(mibPrefix string, node gosmi.SmiNode) (col []string, tagOids map[string]struct{}) {\n\t// first attempt to get the table's tags\n\t// mimcks grabbing INDEX {} that is returned from snmptranslate -Td MibName\n\tindices := node.GetIndex()\n\ttagOids = make(map[string]struct{}, len(indices))\n\tfor _, index := range indices {\n\t\ttagOids[mibPrefix+index.Name] = struct{}{}\n\t}\n\n\t// grabs all columns from the table\n\t// mimmicks grabbing everything returned from snmptable -Ch -Cl -c public 127.0.0.1 oidFullName\n\t_, col = node.GetColumns()\n\n\treturn col, tagOids\n}\n\n//nolint:revive //Too many return variable but necessary\nfunc snmpTranslateCall(oid string) (mibName string, oidNum string, oidText string, conversion string, node gosmi.SmiNode, err error) {\n\tvar out gosmi.SmiNode\n\tvar end string\n\tif strings.ContainsAny(oid, \"::\") {\n\t\t// split given oid\n\t\t// for example RFC1213-MIB::sysUpTime.0\n\t\ts := strings.SplitN(oid, \"::\", 2)\n\t\t// moduleName becomes RFC1213\n\t\tmoduleName := s[0]\n\t\tmodule, err := gosmi.GetModule(moduleName)\n\t\tif err != nil {\n\t\t\treturn oid, oid, oid, \"\", gosmi.SmiNode{}, err\n\t\t}\n\t\tif s[1] == \"\" {\n\t\t\treturn \"\", oid, oid, \"\", gosmi.SmiNode{}, fmt.Errorf(\"cannot parse %v\", oid)\n\t\t}\n\t\t// node becomes sysUpTime.0\n\t\tnode := s[1]\n\t\tif strings.ContainsAny(node, \".\") {\n\t\t\ts = strings.SplitN(node, \".\", 2)\n\t\t\t// node becomes sysUpTime\n\t\t\tnode = s[0]\n\t\t\tend = \".\" + s[1]\n\t\t}\n\n\t\tout, err = module.GetNode(node)\n\t\tif err != nil {\n\t\t\treturn oid, oid, oid, \"\", out, err\n\t\t}\n\n\t\tif oidNum = out.RenderNumeric(); oidNum == \"\" {\n\t\t\treturn oid, oid, oid, \"\", out, fmt.Errorf(\"cannot translate %v into a numeric OID, please ensure all imported MIBs are in the path\", oid)\n\t\t}\n\n\t\toidNum = \".\" + oidNum + end\n\t} else if strings.ContainsAny(oid, \"abcdefghijklnmopqrstuvwxyz\") {\n\t\t//handle mixed oid ex. .iso.2.3\n\t\ts := strings.Split(oid, \".\")\n\t\tfor i := range s {\n\t\t\tif strings.ContainsAny(s[i], \"abcdefghijklmnopqrstuvwxyz\") {\n\t\t\t\tout, err = gosmi.GetNode(s[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn oid, oid, oid, \"\", out, err\n\t\t\t\t}\n\t\t\t\ts[i] = out.RenderNumeric()\n\t\t\t}\n\t\t}\n\t\toidNum = strings.Join(s, \".\")\n\t\tout, err = gosmi.GetNodeByOID(types.OidMustFromString(oidNum))\n\t\tif err != nil {\n\t\t\treturn oid, oid, oid, \"\", out, err\n\t\t}\n\t} else {\n\t\tout, err = gosmi.GetNodeByOID(types.OidMustFromString(oid))\n\t\toidNum = oid\n\t\t// ensure modules are loaded or node will be empty (might not error)\n\t\t//nolint:nilerr // do not return the err as the oid is numeric and telegraf can continue\n\t\tif err != nil || out.Name == \"iso\" {\n\t\t\treturn oid, oid, oid, \"\", out, nil\n\t\t}\n\t}\n\n\ttc := out.GetSubtree()\n\tfor i := range tc {\n\t\t// case where the mib doesn't have a conversion so Type struct will be nil\n\t\t// prevents seg fault\n\t\tif tc[i].Type == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif tc[i].Type.Format != \"\" {\n\t\t\tconversion = \"displayhint\"\n\t\t} else {\n\t\t\tswitch tc[i].Type.Name {\n\t\t\tcase \"InetAddress\", \"IPSIpAddress\":\n\t\t\t\tconversion = \"ipaddr\"\n\t\t\t}\n\t\t}\n\t}\n\n\toidText = out.RenderQualified()\n\ti := strings.Index(oidText, \"::\")\n\tif i == -1 {\n\t\treturn \"\", oid, oid, \"\", out, errors.New(\"not found\")\n\t}\n\tmibName = oidText[:i]\n\toidText = oidText[i+2:] + end\n\n\treturn mibName, oidNum, oidText, conversion, out, nil\n}\n\n// MibEntry is for snmp_trap\ntype MibEntry struct {\n\tMibName string\n\tOidText string\n}\n\nfunc TrapLookup(oid string) (e MibEntry, err error) {\n\tvar givenOid types.Oid\n\tif givenOid, err = types.OidFromString(oid); err != nil {\n\t\treturn e, fmt.Errorf(\"could not convert OID %s: %w\", oid, err)\n\t}\n\n\t// Get node name\n\tvar node gosmi.SmiNode\n\tif node, err = gosmi.GetNodeByOID(givenOid); err != nil {\n\t\treturn e, err\n\t}\n\te.OidText = node.Name\n\n\t// Add not found OID part\n\tif !givenOid.Equals(node.Oid) {\n\t\te.OidText += \".\" + givenOid[len(node.Oid):].String()\n\t}\n\n\t// Get module name\n\tmodule := node.GetModule()\n\tif module.Name != \"<well-known>\" {\n\t\te.MibName = module.Name\n\t}\n\n\treturn e, nil\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_gosmi_test.go",
    "content": "package snmp\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc getGosmiTr(t *testing.T) Translator {\n\ttestDataPath, err := filepath.Abs(\"./testdata/gosmi\")\n\trequire.NoError(t, err)\n\n\ttr, err := NewGosmiTranslator([]string{testDataPath}, testutil.Logger{})\n\trequire.NoError(t, err)\n\treturn tr\n}\n\nfunc TestGosmiTranslator(t *testing.T) {\n\tvar tr Translator\n\tvar err error\n\n\ttr, err = NewGosmiTranslator([]string{\"testdata\"}, testutil.Logger{})\n\trequire.NoError(t, err)\n\trequire.NotNil(t, tr)\n}\n\nfunc TestFieldInitGosmi(t *testing.T) {\n\ttr := getGosmiTr(t)\n\n\ttranslations := []struct {\n\t\tinputOid           string\n\t\tinputName          string\n\t\tinputConversion    string\n\t\texpectedOid        string\n\t\texpectedName       string\n\t\texpectedConversion string\n\t}{\n\t\t{\".1.2.3\", \"foo\", \"\", \".1.2.3\", \"foo\", \"\"},\n\t\t{\".iso.2.3\", \"foo\", \"\", \".1.2.3\", \"foo\", \"\"},\n\t\t{\".1.0.0.0.1.1\", \"\", \"\", \".1.0.0.0.1.1\", \"server\", \"\"},\n\t\t{\".1.0.0.0.1.5\", \"\", \"\", \".1.0.0.0.1.5\", \"dateAndTime\", \"displayhint\"},\n\t\t{\"IF-MIB::ifPhysAddress.1\", \"\", \"\", \".1.3.6.1.2.1.2.2.1.6.1\", \"ifPhysAddress.1\", \"displayhint\"},\n\t\t{\"IF-MIB::ifPhysAddress.1\", \"\", \"none\", \".1.3.6.1.2.1.2.2.1.6.1\", \"ifPhysAddress.1\", \"none\"},\n\t\t{\"BRIDGE-MIB::dot1dTpFdbAddress.1\", \"\", \"\", \".1.3.6.1.2.1.17.4.3.1.1.1\", \"dot1dTpFdbAddress.1\", \"displayhint\"},\n\t\t{\"TCP-MIB::tcpConnectionLocalAddress.1\", \"\", \"\", \".1.3.6.1.2.1.6.19.1.2.1\", \"tcpConnectionLocalAddress.1\", \"ipaddr\"},\n\t\t{\".999\", \"\", \"\", \".999\", \".999\", \"\"},\n\t}\n\n\tfor _, txl := range translations {\n\t\tf := Field{Oid: txl.inputOid, Name: txl.inputName, Conversion: txl.inputConversion}\n\t\trequire.NoError(t, f.Init(tr), \"inputOid=%q inputName=%q\", txl.inputOid, txl.inputName)\n\n\t\trequire.Equal(t, txl.expectedOid, f.Oid, \"inputOid=%q inputName=%q inputConversion=%q\", txl.inputOid, txl.inputName, txl.inputConversion)\n\t\trequire.Equal(t, txl.expectedName, f.Name, \"inputOid=%q inputName=%q inputConversion=%q\", txl.inputOid, txl.inputName, txl.inputConversion)\n\t\trequire.Equal(t, txl.expectedConversion, f.Conversion, \"inputOid=%q inputName=%q inputConversion=%q\", txl.inputOid, txl.inputName, txl.inputConversion)\n\t}\n}\n\nfunc TestTableInitGosmi(t *testing.T) {\n\ttbl := Table{\n\t\tOid: \".1.3.6.1.2.1.3.1\",\n\t\tFields: []Field{\n\t\t\t{Oid: \".999\", Name: \"foo\"},\n\t\t\t{Oid: \".1.3.6.1.2.1.3.1.1.1\", Name: \"atIfIndex\", IsTag: true},\n\t\t\t{Oid: \"RFC1213-MIB::atPhysAddress\", Name: \"atPhysAddress\"},\n\t\t},\n\t}\n\n\ttr := getGosmiTr(t)\n\trequire.NoError(t, tbl.Init(tr))\n\n\trequire.Equal(t, \"atTable\", tbl.Name)\n\n\trequire.Len(t, tbl.Fields, 5)\n\n\trequire.Equal(t, \".999\", tbl.Fields[0].Oid)\n\trequire.Equal(t, \"foo\", tbl.Fields[0].Name)\n\trequire.False(t, tbl.Fields[0].IsTag)\n\trequire.Empty(t, tbl.Fields[0].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.1\", tbl.Fields[1].Oid)\n\trequire.Equal(t, \"atIfIndex\", tbl.Fields[1].Name)\n\trequire.True(t, tbl.Fields[1].IsTag)\n\trequire.Empty(t, tbl.Fields[1].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.2\", tbl.Fields[2].Oid)\n\trequire.Equal(t, \"atPhysAddress\", tbl.Fields[2].Name)\n\trequire.False(t, tbl.Fields[2].IsTag)\n\trequire.Equal(t, \"displayhint\", tbl.Fields[2].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.3\", tbl.Fields[4].Oid)\n\trequire.Equal(t, \"atNetAddress\", tbl.Fields[4].Name)\n\trequire.True(t, tbl.Fields[4].IsTag)\n\trequire.Empty(t, tbl.Fields[4].Conversion)\n}\n\n// TestTableBuild_walk in snmp_test.go is split into two tests here,\n// noTranslate and Translate.\n//\n// This is only running with gosmi translator but should be valid with\n// netsnmp too.\nfunc TestTableBuild_walk_noTranslate(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:       \"myfield3\",\n\t\t\t\tOid:        \".1.0.0.0.1.3\",\n\t\t\t\tConversion: \"float\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:           \"myfield4\",\n\t\t\t\tOid:            \".1.0.0.2.1.5\",\n\t\t\t\tOidIndexSuffix: \".9.9\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:           \"myfield5\",\n\t\t\t\tOid:            \".1.0.0.2.1.5\",\n\t\t\t\tOidIndexLength: 1,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"foo\",\n\t\t\t\"index\":    \"0\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 1,\n\t\t\t\"myfield3\": float64(0.123),\n\t\t\t\"myfield4\": 11,\n\t\t\t\"myfield5\": 11,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"bar\",\n\t\t\t\"index\":    \"1\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 2,\n\t\t\t\"myfield3\": float64(0.456),\n\t\t\t\"myfield4\": 22,\n\t\t\t\"myfield5\": 22,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\": \"2\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 0,\n\t\t\t\"myfield3\": float64(0.0),\n\t\t},\n\t}\n\trtr4 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\": \"3\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield3\": float64(9.999),\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 4)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n\trequire.Contains(t, tb.Rows, rtr4)\n}\n\nfunc TestTableBuild_walk_Translate(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"atTable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"ifIndex\",\n\t\t\t\tOid:   \"1.3.6.1.2.1.3.1.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"atPhysAddress\",\n\t\t\t\tOid:       \"1.3.6.1.2.1.3.1.1.2\",\n\t\t\t\tTranslate: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"atNetAddress\",\n\t\t\t\tOid:       \"1.3.6.1.2.1.3.1.1.3\",\n\t\t\t\tTranslate: true,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, tbl.Init(getGosmiTr(t)))\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"atTable\", tb.Name)\n\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"ifIndex\": \"foo\",\n\t\t\t\"index\":   \"0\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"atPhysAddress\": 1,\n\t\t\t\"atNetAddress\":  \"atNetAddress\",\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"ifIndex\": \"bar\",\n\t\t\t\"index\":   \"1\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"atPhysAddress\": 2,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\": \"2\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"atPhysAddress\": 0,\n\t\t},\n\t}\n\n\trequire.Len(t, tb.Rows, 3)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n}\n\nfunc TestTableBuild_noWalkGosmi(t *testing.T) {\n\ttbl := Table{\n\t\tName: \"mytable\",\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"myfield3\",\n\t\t\t\tOid:   \".1.0.0.1.2\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"empty\",\n\t\t\t\tOid:  \".1.0.0.0.1.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"noexist\",\n\t\t\t\tOid:  \".1.2.3.4.5\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"myfield4\",\n\t\t\t\tOid:       \".1.3.6.1.2.1.3.1.1.3.0\",\n\t\t\t\tTranslate: true,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, tbl.Init(getGosmiTr(t)))\n\ttb, err := tbl.Build(tsc, false)\n\trequire.NoError(t, err)\n\n\trtr := RTableRow{\n\t\tTags:   map[string]string{\"myfield1\": \"baz\", \"myfield3\": \"234\"},\n\t\tFields: map[string]interface{}{\"myfield2\": 234, \"myfield4\": \"atNetAddress\"},\n\t}\n\trequire.Len(t, tb.Rows, 1)\n\trequire.Contains(t, tb.Rows, rtr)\n}\n\nfunc TestFieldConvertGosmi(t *testing.T) {\n\ttestTable := []struct {\n\t\tinput    interface{}\n\t\tconv     string\n\t\texpected interface{}\n\t}{\n\t\t{\"0.123\", \"float\", float64(0.123)},\n\t\t{[]byte(\"0.123\"), \"float\", float64(0.123)},\n\t\t{float32(0.123), \"float\", float64(float32(0.123))},\n\t\t{float64(0.123), \"float\", float64(0.123)},\n\t\t{float64(0.123123123123), \"float\", float64(0.123123123123)},\n\t\t{123, \"float\", float64(123)},\n\t\t{123, \"float(0)\", float64(123)},\n\t\t{123, \"float(4)\", float64(0.0123)},\n\t\t{int8(123), \"float(3)\", float64(0.123)},\n\t\t{int16(123), \"float(3)\", float64(0.123)},\n\t\t{int32(123), \"float(3)\", float64(0.123)},\n\t\t{int64(123), \"float(3)\", float64(0.123)},\n\t\t{uint(123), \"float(3)\", float64(0.123)},\n\t\t{uint8(123), \"float(3)\", float64(0.123)},\n\t\t{uint16(123), \"float(3)\", float64(0.123)},\n\t\t{uint32(123), \"float(3)\", float64(0.123)},\n\t\t{uint64(123), \"float(3)\", float64(0.123)},\n\t\t{\"123\", \"int\", int64(123)},\n\t\t{[]byte(\"123\"), \"int\", int64(123)},\n\t\t{\"123123123123\", \"int\", int64(123123123123)},\n\t\t{[]byte(\"123123123123\"), \"int\", int64(123123123123)},\n\t\t{float32(12.3), \"int\", int64(12)},\n\t\t{float64(12.3), \"int\", int64(12)},\n\t\t{123, \"int\", int64(123)},\n\t\t{int8(123), \"int\", int64(123)},\n\t\t{int16(123), \"int\", int64(123)},\n\t\t{int32(123), \"int\", int64(123)},\n\t\t{int64(123), \"int\", int64(123)},\n\t\t{uint(123), \"int\", int64(123)},\n\t\t{uint8(123), \"int\", int64(123)},\n\t\t{uint16(123), \"int\", int64(123)},\n\t\t{uint32(123), \"int\", int64(123)},\n\t\t{uint64(123), \"int\", int64(123)},\n\t\t{[]byte(\"abcdef\"), \"hwaddr\", \"61:62:63:64:65:66\"},\n\t\t{\"abcdef\", \"hwaddr\", \"61:62:63:64:65:66\"},\n\t\t{[]byte(\"abcd\"), \"ipaddr\", \"97.98.99.100\"},\n\t\t{\"abcd\", \"ipaddr\", \"97.98.99.100\"},\n\t\t{[]byte(\"abcdefghijklmnop\"), \"ipaddr\", \"6162:6364:6566:6768:696a:6b6c:6d6e:6f70\"},\n\t\t{3, \"enum\", \"testing\"},\n\t\t{3, \"enum(1)\", \"testing(3)\"},\n\t}\n\n\tfor _, tc := range testTable {\n\t\tf := Field{\n\t\t\tName:       \"test\",\n\t\t\tConversion: tc.conv,\n\t\t}\n\t\trequire.NoError(t, f.Init(getGosmiTr(t)))\n\n\t\tact, err := f.Convert(gosnmp.SnmpPDU{Name: \".1.3.6.1.2.1.2.2.1.8\", Value: tc.input})\n\t\trequire.NoError(t, err, \"input=%T(%v) conv=%s expected=%T(%v)\", tc.input, tc.input, tc.conv, tc.expected, tc.expected)\n\t\trequire.EqualValues(t, tc.expected, act, \"input=%T(%v) conv=%s expected=%T(%v)\", tc.input, tc.input, tc.conv, tc.expected, tc.expected)\n\t}\n}\n\nfunc TestSnmpFormatDisplayHint(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\toid      string\n\t\tinput    interface{}\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"ifOperStatus\",\n\t\t\toid:      \".1.3.6.1.2.1.2.2.1.8\",\n\t\t\tinput:    3,\n\t\t\texpected: \"testing(3)\",\n\t\t}, {\n\t\t\tname:     \"ifPhysAddress\",\n\t\t\toid:      \".1.3.6.1.2.1.2.2.1.6\",\n\t\t\tinput:    []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},\n\t\t\texpected: \"01:23:45:67:89:ab:cd:ef\",\n\t\t}, {\n\t\t\tname:     \"DateAndTime short\",\n\t\t\toid:      \".1.0.0.0.1.5\",\n\t\t\tinput:    []byte{0x07, 0xe8, 0x09, 0x18, 0x10, 0x24, 0x27, 0x05},\n\t\t\texpected: \"2024-9-24,16:36:39.5\",\n\t\t}, {\n\t\t\tname:     \"DateAndTime long\",\n\t\t\toid:      \".1.0.0.0.1.5\",\n\t\t\tinput:    []byte{0x07, 0xe8, 0x09, 0x18, 0x10, 0x24, 0x27, 0x05, 0x2b, 0x02, 0x00},\n\t\t\texpected: \"2024-9-24,16:36:39.5,+2:0\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttr := getGosmiTr(t)\n\n\t\t\tactual, err := tr.SnmpFormatDisplayHint(tt.oid, tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestTableJoin_walkGosmi(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, tbl.Init(getGosmiTr(t)))\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t\"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t\"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t\"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 3)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n}\n\nfunc TestTableOuterJoin_walkGosmi(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t\tSecondaryOuterJoin:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t\"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t\"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t\"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trtr4 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\":    \"Secondary.0\",\n\t\t\t\"myfield4\": \"foo\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield5\": 1,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 4)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n\trequire.Contains(t, tb.Rows, rtr4)\n}\n\nfunc TestTableJoinNoIndexAsTag_walkGosmi(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: false,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.3.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.3.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:                \"myfield3\",\n\t\t\t\tOid:                 \".1.0.0.3.1.3\",\n\t\t\t\tSecondaryIndexTable: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield4\",\n\t\t\t\tOid:               \".1.0.0.0.1.1\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t\tIsTag:             true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:              \"myfield5\",\n\t\t\t\tOid:               \".1.0.0.0.1.2\",\n\t\t\t\tSecondaryIndexUse: true,\n\t\t\t},\n\t\t},\n\t}\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance\",\n\t\t\t\"myfield4\": \"bar\",\n\t\t\t// \"index\":    \"10\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 10,\n\t\t\t\"myfield3\": 1,\n\t\t\t\"myfield5\": 2,\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance2\",\n\t\t\t// \"index\":    \"11\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 2,\n\t\t\t\"myfield5\": 0,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"instance3\",\n\t\t\t// \"index\":    \"12\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 20,\n\t\t\t\"myfield3\": 3,\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 3)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n}\n\nfunc TestCanNotParse(t *testing.T) {\n\ttr := getGosmiTr(t)\n\tf := Field{\n\t\tOid: \"RFC1213-MIB::\",\n\t}\n\n\trequire.Error(t, f.Init(tr))\n}\n\nfunc TestTrapLookup(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\toid      string\n\t\texpected MibEntry\n\t}{\n\t\t{\n\t\t\tname: \"Known trap OID\",\n\t\t\toid:  \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\texpected: MibEntry{\n\t\t\t\tMibName: \"TGTEST-MIB\",\n\t\t\t\tOidText: \"coldStart\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Known trap value OID\",\n\t\t\toid:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\texpected: MibEntry{\n\t\t\t\tMibName: \"TGTEST-MIB\",\n\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Unknown enterprise sub-OID\",\n\t\t\toid:  \".1.3.6.1.4.1.0.1.2.3\",\n\t\t\texpected: MibEntry{\n\t\t\t\tMibName: \"SNMPv2-SMI\",\n\t\t\t\tOidText: \"enterprises.0.1.2.3\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Unknown MIB\",\n\t\t\toid:      \".1.999\",\n\t\t\texpected: MibEntry{OidText: \"iso.999\"},\n\t\t},\n\t}\n\n\t// Load the MIBs\n\tgetGosmiTr(t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Run the actual test\n\t\t\tactual, err := TrapLookup(tt.oid)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestTrapLookupFail(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\toid      string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"New top level OID\",\n\t\t\toid:      \".3.6.1.3.0\",\n\t\t\texpected: \"Could not find node for OID 3.6.1.3.0\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Malformed OID\",\n\t\t\toid:      \".1.3.dod.1.3.0\",\n\t\t\texpected: \"could not convert OID .1.3.dod.1.3.0: strconv.ParseUint: parsing \\\"dod\\\": invalid syntax\",\n\t\t},\n\t}\n\n\t// Load the MIBs\n\tgetGosmiTr(t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Run the actual test\n\t\t\t_, err := TrapLookup(tt.oid)\n\t\t\trequire.EqualError(t, err, tt.expected)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_netsnmp.go",
    "content": "package snmp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// struct that implements the translator interface. This calls existing\n// code to exec netsnmp's snmptranslate program\ntype netsnmpTranslator struct {\n\tlog telegraf.Logger\n}\n\nfunc NewNetsnmpTranslator(log telegraf.Logger) *netsnmpTranslator {\n\treturn &netsnmpTranslator{log: log}\n}\n\ntype snmpTableCache struct {\n\tmibName string\n\toidNum  string\n\toidText string\n\tfields  []Field\n\terr     error\n}\n\n// execCommand is so tests can mock out exec.Command usage.\nvar execCommand = exec.Command\n\n// execCmd executes the specified command, returning the STDOUT content.\n// If command exits with error status, the output is captured into the returned error.\nfunc (n *netsnmpTranslator) execCmd(arg0 string, args ...string) ([]byte, error) {\n\tquoted := make([]string, 0, len(args))\n\tfor _, arg := range args {\n\t\tquoted = append(quoted, fmt.Sprintf(\"%q\", arg))\n\t}\n\tn.log.Debugf(\"executing %q %s\", arg0, strings.Join(quoted, \" \"))\n\n\tout, err := execCommand(arg0, args...).Output()\n\tif err != nil {\n\t\tvar exitErr *exec.ExitError\n\t\tif errors.As(err, &exitErr) {\n\t\t\treturn nil, fmt.Errorf(\"%s: %w\", bytes.TrimRight(exitErr.Stderr, \"\\r\\n\"), err)\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nvar snmpTableCaches map[string]snmpTableCache\nvar snmpTableCachesLock sync.Mutex\n\n// snmpTable resolves the given OID as a table, providing information about the\n// table and fields within.\n//\n//nolint:revive //function-result-limit conditionally 5 return results allowed\nfunc (n *netsnmpTranslator) SnmpTable(oid string) (\n\tmibName string, oidNum string, oidText string,\n\tfields []Field,\n\terr error) {\n\tsnmpTableCachesLock.Lock()\n\tif snmpTableCaches == nil {\n\t\tsnmpTableCaches = map[string]snmpTableCache{}\n\t}\n\n\tvar stc snmpTableCache\n\tvar ok bool\n\tif stc, ok = snmpTableCaches[oid]; !ok {\n\t\tstc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err = n.snmpTableCall(oid)\n\t\tsnmpTableCaches[oid] = stc\n\t}\n\n\tsnmpTableCachesLock.Unlock()\n\treturn stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err\n}\n\n//nolint:revive //function-result-limit conditionally 5 return results allowed\nfunc (n *netsnmpTranslator) snmpTableCall(oid string) (\n\tmibName string, oidNum string, oidText string,\n\tfields []Field,\n\terr error) {\n\tmibName, oidNum, oidText, _, err = n.SnmpTranslate(oid)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", nil, fmt.Errorf(\"translating: %w\", err)\n\t}\n\n\tmibPrefix := mibName + \"::\"\n\toidFullName := mibPrefix + oidText\n\n\t// first attempt to get the table's tags\n\ttagOids := map[string]struct{}{}\n\t// 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.\n\tif out, err := n.execCmd(\"snmptranslate\", \"-Td\", oidFullName+\".1\"); err == nil {\n\t\tscanner := bufio.NewScanner(bytes.NewBuffer(out))\n\t\tfor scanner.Scan() {\n\t\t\tline := scanner.Text()\n\n\t\t\tif !strings.HasPrefix(line, \"  INDEX\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ti := strings.Index(line, \"{ \")\n\t\t\tif i == -1 { // parse error\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tline = line[i+2:]\n\t\t\ti = strings.Index(line, \" }\")\n\t\t\tif i == -1 { // parse error\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tline = line[:i]\n\t\t\tfor _, col := range strings.Split(line, \", \") {\n\t\t\t\ttagOids[mibPrefix+col] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n\n\t// this won't actually try to run a query. The `-Ch` will just cause it to dump headers.\n\tout, err := n.execCmd(\"snmptable\", \"-Ch\", \"-Cl\", \"-c\", \"public\", \"127.0.0.1\", oidFullName)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", nil, fmt.Errorf(\"getting table columns: %w\", err)\n\t}\n\tscanner := bufio.NewScanner(bytes.NewBuffer(out))\n\tscanner.Scan()\n\tcols := scanner.Text()\n\tif len(cols) == 0 {\n\t\treturn \"\", \"\", \"\", nil, errors.New(\"could not find any columns in table\")\n\t}\n\tfor _, col := range strings.Split(cols, \" \") {\n\t\tif len(col) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\t_, isTag := tagOids[mibPrefix+col]\n\t\tfields = append(fields, Field{Name: col, Oid: mibPrefix + col, IsTag: isTag})\n\t}\n\n\treturn mibName, oidNum, oidText, fields, err\n}\n\ntype snmpTranslateCache struct {\n\tmibName    string\n\toidNum     string\n\toidText    string\n\tconversion string\n\terr        error\n}\n\nvar snmpTranslateCachesLock sync.Mutex\nvar snmpTranslateCaches map[string]snmpTranslateCache\n\n// snmpTranslate resolves the given OID.\n//\n//nolint:revive //function-result-limit conditionally 5 return results allowed\nfunc (n *netsnmpTranslator) SnmpTranslate(oid string) (\n\tmibName string, oidNum string, oidText string,\n\tconversion string,\n\terr error) {\n\tsnmpTranslateCachesLock.Lock()\n\tif snmpTranslateCaches == nil {\n\t\tsnmpTranslateCaches = map[string]snmpTranslateCache{}\n\t}\n\n\tvar stc snmpTranslateCache\n\tvar ok bool\n\tif stc, ok = snmpTranslateCaches[oid]; !ok {\n\t\t// This will result in only one call to snmptranslate running at a time.\n\t\t// We could speed it up by putting a lock in snmpTranslateCache and then\n\t\t// returning it immediately, and multiple callers would then release the\n\t\t// snmpTranslateCachesLock and instead wait on the individual\n\t\t// snmpTranslation.Lock to release. But I don't know that the extra complexity\n\t\t// is worth it. Especially when it would slam the system pretty hard if lots\n\t\t// of lookups are being performed.\n\n\t\tstc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.err = n.snmpTranslateCall(oid)\n\t\tsnmpTranslateCaches[oid] = stc\n\t}\n\n\tsnmpTranslateCachesLock.Unlock()\n\n\treturn stc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.err\n}\n\n//nolint:revive //function-result-limit conditionally 5 return results allowed\nfunc (n *netsnmpTranslator) snmpTranslateCall(oid string) (mibName string, oidNum string, oidText string, conversion string, err error) {\n\tvar out []byte\n\tif strings.ContainsAny(oid, \":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\") {\n\t\tout, err = n.execCmd(\"snmptranslate\", \"-Td\", \"-Ob\", oid)\n\t} else {\n\t\tout, err = n.execCmd(\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", oid)\n\t\tvar execErr *exec.Error\n\t\tif errors.As(err, &execErr) && errors.Is(execErr, exec.ErrNotFound) {\n\t\t\t// Silently discard error if snmptranslate not found and we have a numeric OID.\n\t\t\t// Meaning we can get by without the lookup.\n\t\t\treturn \"\", oid, oid, \"\", nil\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", \"\", err\n\t}\n\n\tscanner := bufio.NewScanner(bytes.NewBuffer(out))\n\tok := scanner.Scan()\n\tif !ok && scanner.Err() != nil {\n\t\treturn \"\", \"\", \"\", \"\", fmt.Errorf(\"getting OID text: %w\", scanner.Err())\n\t}\n\n\toidText = scanner.Text()\n\n\ti := strings.Index(oidText, \"::\")\n\tif i == -1 {\n\t\t// was not found in MIB.\n\t\tif bytes.Contains(out, []byte(\"[TRUNCATED]\")) {\n\t\t\treturn \"\", oid, oid, \"\", nil\n\t\t}\n\t\t// not truncated, but not fully found. We still need to parse out numeric OID, so keep going\n\t\toidText = oid\n\t} else {\n\t\tmibName = oidText[:i]\n\t\toidText = oidText[i+2:]\n\t}\n\n\tvar b strings.Builder\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif strings.HasPrefix(line, \"  -- TEXTUAL CONVENTION \") {\n\t\t\ttc := strings.TrimPrefix(line, \"  -- TEXTUAL CONVENTION \")\n\t\t\tswitch tc {\n\t\t\tcase \"MacAddress\", \"PhysAddress\":\n\t\t\t\tconversion = \"hwaddr\"\n\t\t\tcase \"InetAddressIPv4\", \"InetAddressIPv6\", \"InetAddress\", \"IPSIpAddress\":\n\t\t\t\tconversion = \"ipaddr\"\n\t\t\t}\n\t\t} else if strings.HasPrefix(line, \"::= { \") {\n\t\t\tobjs := strings.TrimPrefix(line, \"::= { \")\n\t\t\tobjs = strings.TrimSuffix(objs, \" }\")\n\n\t\t\tfor _, obj := range strings.Split(objs, \" \") {\n\t\t\t\tif len(obj) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif i := strings.Index(obj, \"(\"); i != -1 {\n\t\t\t\t\tobj = obj[i+1:]\n\t\t\t\t\tif j := strings.Index(obj, \")\"); j != -1 {\n\t\t\t\t\t\tb.WriteString(\".\")\n\t\t\t\t\t\tb.WriteString(obj[:j])\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn \"\", \"\", \"\", \"\", fmt.Errorf(\"getting OID number from: %s\", obj)\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tb.WriteString(\".\")\n\t\t\t\t\tb.WriteString(obj)\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\toidNum = b.String()\n\n\treturn mibName, oidNum, oidText, conversion, nil\n}\n\nfunc (*netsnmpTranslator) SnmpFormatEnum(string, interface{}, bool) (string, error) {\n\treturn \"\", errors.New(\"not implemented in netsnmp translator\")\n}\n\nfunc (*netsnmpTranslator) SnmpFormatDisplayHint(string, interface{}) (string, error) {\n\treturn \"\", errors.New(\"not implemented in netsnmp translator\")\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_netsnmp_mocks_generate.go",
    "content": "//go:build generate\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n)\n\n// This file is a generator used to generate the mocks for the commands used by the tests.\n\n// These are the commands to be mocked.\nvar mockedCommands = [][]string{\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.0\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.1.1\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.1.2\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \"1.0.0.1.1\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.0.1.1\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.0.1.1.0\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.0.1.5\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.2.3\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".1.0.0.0.1.7\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \".iso.2.3\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", \".999\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::server\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::server.0\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::testTable\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::connections\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::latency\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::description\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TEST::hostname\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"IF-MIB::ifPhysAddress.1\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"BRIDGE-MIB::dot1dTpFdbAddress.1\"},\n\t{\"snmptranslate\", \"-Td\", \"-Ob\", \"TCP-MIB::tcpConnectionLocalAddress.1\"},\n\t{\"snmptranslate\", \"-Td\", \"TEST::testTable.1\"},\n\t{\"snmptable\", \"-Ch\", \"-Cl\", \"-c\", \"public\", \"127.0.0.1\", \"TEST::testTable\"},\n}\n\ntype mockedCommandResult struct {\n\tstdout    string\n\tstderr    string\n\texitError bool\n}\n\nfunc main() {\n\tif err := generate(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"error: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc generate() error {\n\tf, err := os.OpenFile(\"snmp_mocks_test.go\", os.O_RDWR, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbr := bufio.NewReader(f)\n\tvar i int64\n\tfor l, err := br.ReadString('\\n'); err == nil; l, err = br.ReadString('\\n') {\n\t\ti += int64(len(l))\n\t\tif l == \"// BEGIN GO GENERATE CONTENT\\n\" {\n\t\t\tbreak\n\t\t}\n\t}\n\tf.Truncate(i)\n\tf.Seek(i, 0)\n\n\tfmt.Fprintf(f, \"var mockedCommandResults = map[string]mockedCommandResult{\\n\")\n\n\tfor _, cmd := range mockedCommands {\n\t\tec := exec.Command(cmd[0], cmd[1:]...)\n\t\tout := bytes.NewBuffer(nil)\n\t\terr := bytes.NewBuffer(nil)\n\t\tec.Stdout = out\n\t\tec.Stderr = err\n\t\tec.Env = []string{\n\t\t\t\"MIBDIRS=+./testdata\",\n\t\t}\n\n\t\tvar mcr mockedCommandResult\n\t\tif err := ec.Run(); err != nil {\n\t\t\tif err, ok := err.(*exec.ExitError); !ok {\n\t\t\t\tmcr.exitError = true\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"executing %v: %s\", cmd, err)\n\t\t\t}\n\t\t}\n\t\tmcr.stdout = string(out.Bytes())\n\t\tmcr.stderr = string(err.Bytes())\n\t\tcmd0 := strings.Join(cmd, \"\\000\")\n\t\tmcrv := fmt.Sprintf(\"%#v\", mcr)[5:] // trim `main.` prefix\n\t\tfmt.Fprintf(f, \"%#v: %s,\\n\", cmd0, mcrv)\n\t}\n\tf.Write([]byte(\"}\\n\"))\n\tf.Close()\n\n\treturn exec.Command(\"gofmt\", \"-w\", \"translator_netsnmp_mocks_test.go\").Run()\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_netsnmp_mocks_test.go",
    "content": "package snmp\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n)\n\ntype mockedCommandResult struct {\n\tstdout    string\n\tstderr    string\n\texitError bool\n}\n\nfunc mockExecCommand(arg0 string, args ...string) *exec.Cmd {\n\targs = append([]string{\"-test.run=TestMockExecCommand\", \"--\", arg0}, args...)\n\tcmd := exec.Command(os.Args[0], args...)\n\tcmd.Stderr = os.Stderr // so the test output shows errors\n\treturn cmd\n}\n\n// This is not a real test. This is just a way of mocking out commands.\n//\n// Idea based on https://github.com/golang/go/blob/7c31043/src/os/exec/exec_test.go#L568\nfunc TestMockExecCommand(_ *testing.T) {\n\tvar cmd []string //nolint:prealloc // Pre-allocated this slice would break the algorithm\n\tfor _, arg := range os.Args {\n\t\tif arg == \"--\" {\n\t\t\tcmd = make([]string, 0)\n\t\t\tcontinue\n\t\t}\n\t\tif cmd == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcmd = append(cmd, arg)\n\t}\n\tif cmd == nil {\n\t\treturn\n\t}\n\n\tcmd0 := strings.Join(cmd, \"\\000\")\n\tmcr, ok := mockedCommandResults[cmd0]\n\tif !ok {\n\t\tcv := fmt.Sprintf(\"%#v\", cmd)[8:] // trim `[]string` prefix\n\t\tfmt.Fprintf(\n\t\t\tos.Stderr,\n\t\t\t\"Unmocked command. Please add the following to `mockedCommands` in snmp_mocks_generate.go, and then run `go generate`:\\n\\t%s,\\n\",\n\t\t\tcv,\n\t\t)\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\tfmt.Printf(\"%s\", mcr.stdout)\n\tfmt.Fprintf(os.Stderr, \"%s\", mcr.stderr)\n\tif mcr.exitError {\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n\nfunc init() {\n\texecCommand = mockExecCommand\n}\n\n// BEGIN GO GENERATE CONTENT\nvar mockedCommandResults = map[string]mockedCommandResult{\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.0\": {\n\t\tstdout:    \"TEST::testTable\\ntestTable OBJECT-TYPE\\n  -- FROM\\tTEST\\n  MAX-ACCESS\\tnot-accessible\\n  STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) 0 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.1.1\": {\n\t\tstdout: \"TEST::hostname\\nhostname OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) 1 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.1.2\": {\n\t\tstdout:    \"TEST::1.2\\nanonymous#1 OBJECT-TYPE\\n  -- FROM\\tTEST\\n::= { iso(1) 0 testOID(0) 1 2 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x001.0.0.1.1\": {\n\t\tstdout: \"TEST::hostname\\nhostname OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) 1 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.0.1.1\": {\n\t\tstdout: \"TEST::server\\nserver OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.0.1.1.0\": {\n\t\tstdout: \"TEST::server.0\\nserver OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) server(1) 0 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.0.1.5\": {\n\t\tstdout: \"TEST::testTableEntry.5\\ntestTableEntry OBJECT-TYPE\\n  -- FROM\\tTEST\\n  MAX-ACCESS\\tnot-accessible\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n  INDEX\\t\\t{ server }\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 5 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.2.3\": {\n\t\tstdout:    \"iso.2.3\\niso OBJECT-TYPE\\n  -- FROM\\t#-1\\n::= { iso(1) 2 3 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.1.0.0.0.1.7\": {\n\t\tstdout: \"TEST::testTableEntry.7\\ntestTableEntry OBJECT-TYPE\\n  -- FROM\\tTEST\\n  MAX-ACCESS\\tnot-accessible\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n  INDEX\\t\\t{ server }\\n::= { iso(1) std(0) testOID(0) testTable(0) testTableEntry(1) 7 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00.iso.2.3\": {\n\t\tstdout:    \"iso.2.3\\niso OBJECT-TYPE\\n  -- FROM\\t#-1\\n::= { iso(1) 2 3 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00-m\\x00all\\x00.999\": {stdout: \".999\\n [TRUNCATED]\\n\", stderr: \"\", exitError: false},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::server\": {\n\t\tstdout: \"TEST::server\\nserver OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::server.0\": {\n\t\tstdout: \"TEST::server.0\\nserver OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) server(1) 0 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::testTable\": {\n\t\tstdout:    \"TEST::testTable\\ntestTable OBJECT-TYPE\\n  -- FROM\\tTEST\\n  MAX-ACCESS\\tnot-accessible\\n  STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) 0 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::connections\": {\n\t\tstdout: \"TEST::connections\\nconnections OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tINTEGER\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 2 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::latency\": {\n\t\tstdout: \"TEST::latency\\nlatency OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 3 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::description\": {\n\t\tstdout: \"TEST::description\\ndescription OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 4 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TEST::hostname\": {\n\t\tstdout: \"TEST::hostname\\nhostname OBJECT-TYPE\\n  -- FROM\\tTEST\\n  SYNTAX\\tOCTET STRING\\n  MAX-ACCESS\\tread-only\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n::= { iso(1) 0 testOID(0) 1 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00IF-MIB::ifPhysAddress.1\": {\n\t\tstdout: \"IF-MIB::ifPhysAddress.1\\nifPhysAddress OBJECT-TYPE\\n  -- FROM\\tIF-MIB\\n  -- TEXTUAL CONVENTION PhysAddress\\n  SYNTAX\\tOCTET STRING\\n  \" +\n\t\t\t\"DISPLAY-HINT\\t\\\"1x:\\\"\\n  MAX-ACCESS\\tread-only\\n  STATUS\\tcurrent\\n  DESCRIPTION\\t\\\"The interface's address at its protocol sub-layer.  \" +\n\t\t\t\"For\\n            example, for an 802.x interface, this object normally\\n            contains a MAC address.  \" +\n\t\t\t\"The interface's media-specific MIB\\n            must define the bit and byte ordering and the format of the\\n            \" +\n\t\t\t\"value of this object.  For interfaces which do not have such\\n            an address (e.g., a serial line), \" +\n\t\t\t\"this object should contain\\n            an octet string of zero length.\\\"\\n::= \" +\n\t\t\t\"{ iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) interfaces(2) ifTable(2) ifEntry(1) ifPhysAddress(6) 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00BRIDGE-MIB::dot1dTpFdbAddress.1\": {\n\t\tstdout: \"BRIDGE-MIB::dot1dTpFdbAddress.1\\ndot1dTpFdbAddress OBJECT-TYPE\\n  -- FROM\\tBRIDGE-MIB\\n  -- TEXTUAL CONVENTION MacAddress\\n  \" +\n\t\t\t\"SYNTAX\\tOCTET STRING (6) \\n  DISPLAY-HINT\\t\\\"1x:\\\"\\n  MAX-ACCESS\\tread-only\\n  STATUS\\tcurrent\\n  DESCRIPTION\\t\\\"\" +\n\t\t\t\"A unicast MAC address for which the bridge has\\n        forwarding and/or filtering information.\\\"\\n::= \" +\n\t\t\t\"{ 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\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00-Ob\\x00TCP-MIB::tcpConnectionLocalAddress.1\": {\n\t\tstdout: \"TCP-MIB::tcpConnectionLocalAddress.1\\ntcpConnectionLocalAddress OBJECT-TYPE\\n  -- FROM\\tTCP-MIB\\n  -- \" +\n\t\t\t\"TEXTUAL CONVENTION InetAddress\\n  SYNTAX\\tOCTET STRING (0..255) \\n  MAX-ACCESS\\tnot-accessible\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n  DESCRIPTION\\t\\\"The local IP address for this TCP connection.  \" +\n\t\t\t\"The type\\n            of this address is determined by the value of\\n            tcpConnectionLocalAddressType.\\n\\n            \" +\n\t\t\t\"As this object is used in the index for the\\n            tcpConnectionTable, implementors should be\\n            \" +\n\t\t\t\"careful not to create entries that would result in OIDs\\n            with more than 128 subidentifiers; \" +\n\t\t\t\"otherwise the information\\n            cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3.\\\"\\n\" +\n\t\t\t\"::= { iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) tcp(6) tcpConnectionTable(19) tcpConnectionEntry(1) tcpConnectionLocalAddress(2) 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptranslate\\x00-Td\\x00TEST::testTable.1\": {\n\t\tstdout: \"TEST::testTableEntry\\ntestTableEntry OBJECT-TYPE\\n  -- FROM\\tTEST\\n  MAX-ACCESS\\tnot-accessible\\n  \" +\n\t\t\t\"STATUS\\tcurrent\\n  INDEX\\t\\t{ server }\\n::= { iso(1) 0 testOID(0) testTable(0) 1 }\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n\t\"snmptable\\x00-Ch\\x00-Cl\\x00-c\\x00public\\x00127.0.0.1\\x00TEST::testTable\": {\n\t\tstdout:    \"server connections latency description \\nTEST::testTable: No entries\\n\",\n\t\tstderr:    \"\",\n\t\texitError: false,\n\t},\n}\n"
  },
  {
    "path": "plugins/common/snmp/translator_netsnmp_test.go",
    "content": "//go:generate go run -tags generate translator_netsnmp_mocks_generate.go\npackage snmp\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFieldInit(t *testing.T) {\n\ttranslations := []struct {\n\t\tinputOid           string\n\t\tinputName          string\n\t\tinputConversion    string\n\t\texpectedOid        string\n\t\texpectedName       string\n\t\texpectedConversion string\n\t}{\n\t\t{\".1.2.3\", \"foo\", \"\", \".1.2.3\", \"foo\", \"\"},\n\t\t{\".iso.2.3\", \"foo\", \"\", \".1.2.3\", \"foo\", \"\"},\n\t\t{\".1.0.0.0.1.1\", \"\", \"\", \".1.0.0.0.1.1\", \"server\", \"\"},\n\t\t{\".1.0.0.0.1.1.0\", \"\", \"\", \".1.0.0.0.1.1.0\", \"server.0\", \"\"},\n\t\t{\".999\", \"\", \"\", \".999\", \".999\", \"\"},\n\t\t{\"TEST::server\", \"\", \"\", \".1.0.0.0.1.1\", \"server\", \"\"},\n\t\t{\"TEST::server.0\", \"\", \"\", \".1.0.0.0.1.1.0\", \"server.0\", \"\"},\n\t\t{\"TEST::server\", \"foo\", \"\", \".1.0.0.0.1.1\", \"foo\", \"\"},\n\t\t{\"IF-MIB::ifPhysAddress.1\", \"\", \"\", \".1.3.6.1.2.1.2.2.1.6.1\", \"ifPhysAddress.1\", \"hwaddr\"},\n\t\t{\"IF-MIB::ifPhysAddress.1\", \"\", \"none\", \".1.3.6.1.2.1.2.2.1.6.1\", \"ifPhysAddress.1\", \"none\"},\n\t\t{\"BRIDGE-MIB::dot1dTpFdbAddress.1\", \"\", \"\", \".1.3.6.1.2.1.17.4.3.1.1.1\", \"dot1dTpFdbAddress.1\", \"hwaddr\"},\n\t\t{\"TCP-MIB::tcpConnectionLocalAddress.1\", \"\", \"\", \".1.3.6.1.2.1.6.19.1.2.1\", \"tcpConnectionLocalAddress.1\", \"ipaddr\"},\n\t}\n\n\ttr := NewNetsnmpTranslator(testutil.Logger{})\n\tfor _, txl := range translations {\n\t\tf := Field{Oid: txl.inputOid, Name: txl.inputName, Conversion: txl.inputConversion}\n\t\terr := f.Init(tr)\n\t\trequire.NoError(t, err, \"inputOid=%q inputName=%q\", txl.inputOid, txl.inputName)\n\t\trequire.Equal(t, txl.expectedOid, f.Oid, \"inputOid=%q inputName=%q inputConversion=%q\", txl.inputOid, txl.inputName, txl.inputConversion)\n\t\trequire.Equal(t, txl.expectedName, f.Name, \"inputOid=%q inputName=%q inputConversion=%q\", txl.inputOid, txl.inputName, txl.inputConversion)\n\t}\n}\n\nfunc TestTableInit(t *testing.T) {\n\ttbl := Table{\n\t\tOid: \".1.0.0.0\",\n\t\tFields: []Field{\n\t\t\t{Oid: \".999\", Name: \"foo\"},\n\t\t\t{Oid: \"TEST::description\", Name: \"description\", IsTag: true},\n\t\t},\n\t}\n\terr := tbl.Init(NewNetsnmpTranslator(testutil.Logger{}))\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"testTable\", tbl.Name)\n\n\trequire.Len(t, tbl.Fields, 5)\n\n\trequire.Equal(t, \".999\", tbl.Fields[0].Oid)\n\trequire.Equal(t, \"foo\", tbl.Fields[0].Name)\n\trequire.False(t, tbl.Fields[0].IsTag)\n\trequire.Empty(t, tbl.Fields[0].Conversion)\n\n\trequire.Equal(t, \".1.0.0.0.1.1\", tbl.Fields[2].Oid)\n\trequire.Equal(t, \"server\", tbl.Fields[2].Name)\n\trequire.True(t, tbl.Fields[1].IsTag)\n\trequire.Empty(t, tbl.Fields[1].Conversion)\n\n\trequire.Equal(t, \".1.0.0.0.1.2\", tbl.Fields[3].Oid)\n\trequire.Equal(t, \"connections\", tbl.Fields[3].Name)\n\trequire.False(t, tbl.Fields[3].IsTag)\n\trequire.Empty(t, tbl.Fields[3].Conversion)\n\n\trequire.Equal(t, \".1.0.0.0.1.3\", tbl.Fields[4].Oid)\n\trequire.Equal(t, \"latency\", tbl.Fields[4].Name)\n\trequire.False(t, tbl.Fields[4].IsTag)\n\trequire.Empty(t, tbl.Fields[4].Conversion)\n\n\trequire.Equal(t, \".1.0.0.0.1.4\", tbl.Fields[1].Oid)\n\trequire.Equal(t, \"description\", tbl.Fields[1].Name)\n\trequire.True(t, tbl.Fields[1].IsTag)\n\trequire.Empty(t, tbl.Fields[1].Conversion)\n}\n\nfunc TestTableBuild_walk(t *testing.T) {\n\ttbl := Table{\n\t\tName:       \"mytable\",\n\t\tIndexAsTag: true,\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:       \"myfield3\",\n\t\t\t\tOid:        \".1.0.0.0.1.3\",\n\t\t\t\tConversion: \"float\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:           \"myfield4\",\n\t\t\t\tOid:            \".1.0.0.2.1.5\",\n\t\t\t\tOidIndexSuffix: \".9.9\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:           \"myfield5\",\n\t\t\t\tOid:            \".1.0.0.2.1.5\",\n\t\t\t\tOidIndexLength: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"myfield6\",\n\t\t\t\tOid:       \".1.0.0.0.1.6\",\n\t\t\t\tTranslate: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"myfield7\",\n\t\t\t\tOid:       \".1.0.0.0.1.6\",\n\t\t\t\tTranslate: false,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, tbl.Init(NewNetsnmpTranslator(testutil.Logger{})))\n\n\ttb, err := tbl.Build(tsc, true)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"mytable\", tb.Name)\n\trtr1 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"foo\",\n\t\t\t\"index\":    \"0\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 1,\n\t\t\t\"myfield3\": float64(0.123),\n\t\t\t\"myfield4\": 11,\n\t\t\t\"myfield5\": 11,\n\t\t\t\"myfield6\": \"testTableEntry.7\",\n\t\t\t\"myfield7\": \".1.0.0.0.1.7\",\n\t\t},\n\t}\n\trtr2 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"myfield1\": \"bar\",\n\t\t\t\"index\":    \"1\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 2,\n\t\t\t\"myfield3\": float64(0.456),\n\t\t\t\"myfield4\": 22,\n\t\t\t\"myfield5\": 22,\n\t\t},\n\t}\n\trtr3 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\": \"2\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield2\": 0,\n\t\t\t\"myfield3\": float64(0.0),\n\t\t},\n\t}\n\trtr4 := RTableRow{\n\t\tTags: map[string]string{\n\t\t\t\"index\": \"3\",\n\t\t},\n\t\tFields: map[string]interface{}{\n\t\t\t\"myfield3\": float64(9.999),\n\t\t},\n\t}\n\trequire.Len(t, tb.Rows, 4)\n\trequire.Contains(t, tb.Rows, rtr1)\n\trequire.Contains(t, tb.Rows, rtr2)\n\trequire.Contains(t, tb.Rows, rtr3)\n\trequire.Contains(t, tb.Rows, rtr4)\n}\n\nfunc TestTableBuild_noWalk(t *testing.T) {\n\ttbl := Table{\n\t\tName: \"mytable\",\n\t\tFields: []Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"myfield3\",\n\t\t\t\tOid:   \".1.0.0.1.2\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"empty\",\n\t\t\t\tOid:  \".1.0.0.0.1.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"noexist\",\n\t\t\t\tOid:  \".1.2.3.4.5\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"myfield4\",\n\t\t\t\tOid:       \".1.0.0.0.1.6.0\",\n\t\t\t\tTranslate: true,\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, tbl.Init(NewNetsnmpTranslator(testutil.Logger{})))\n\ttb, err := tbl.Build(tsc, false)\n\trequire.NoError(t, err)\n\n\trtr := RTableRow{\n\t\tTags:   map[string]string{\"myfield1\": \"baz\", \"myfield3\": \"234\"},\n\t\tFields: map[string]interface{}{\"myfield2\": 234, \"myfield4\": \"testTableEntry.7\"},\n\t}\n\trequire.Len(t, tb.Rows, 1)\n\trequire.Contains(t, tb.Rows, rtr)\n}\n\nfunc TestSnmpTranslateCache_miss(t *testing.T) {\n\tsnmpTranslateCaches = nil\n\toid := \"IF-MIB::ifPhysAddress.1\"\n\tmibName, oidNum, oidText, conversion, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTranslate(oid)\n\trequire.Len(t, snmpTranslateCaches, 1)\n\tstc := snmpTranslateCaches[oid]\n\trequire.NotNil(t, stc)\n\trequire.Equal(t, mibName, stc.mibName)\n\trequire.Equal(t, oidNum, stc.oidNum)\n\trequire.Equal(t, oidText, stc.oidText)\n\trequire.Equal(t, conversion, stc.conversion)\n\trequire.Equal(t, err, stc.err)\n}\n\nfunc TestSnmpTranslateCache_hit(t *testing.T) {\n\tsnmpTranslateCaches = map[string]snmpTranslateCache{\n\t\t\"foo\": {\n\t\t\tmibName:    \"a\",\n\t\t\toidNum:     \"b\",\n\t\t\toidText:    \"c\",\n\t\t\tconversion: \"d\",\n\t\t},\n\t}\n\tmibName, oidNum, oidText, conversion, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTranslate(\"foo\")\n\trequire.Equal(t, \"a\", mibName)\n\trequire.Equal(t, \"b\", oidNum)\n\trequire.Equal(t, \"c\", oidText)\n\trequire.Equal(t, \"d\", conversion)\n\trequire.NoError(t, err)\n\tsnmpTranslateCaches = nil\n}\n\nfunc TestSnmpTableCache_miss(t *testing.T) {\n\tsnmpTableCaches = nil\n\toid := \".1.0.0.0\"\n\tmibName, oidNum, oidText, fields, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTable(oid)\n\trequire.Len(t, snmpTableCaches, 1)\n\tstc := snmpTableCaches[oid]\n\trequire.NotNil(t, stc)\n\trequire.Equal(t, mibName, stc.mibName)\n\trequire.Equal(t, oidNum, stc.oidNum)\n\trequire.Equal(t, oidText, stc.oidText)\n\trequire.Equal(t, fields, stc.fields)\n\trequire.Equal(t, err, stc.err)\n}\n\nfunc TestSnmpTableCache_hit(t *testing.T) {\n\tsnmpTableCaches = map[string]snmpTableCache{\n\t\t\"foo\": {\n\t\t\tmibName: \"a\",\n\t\t\toidNum:  \"b\",\n\t\t\toidText: \"c\",\n\t\t\tfields:  []Field{{Name: \"d\"}},\n\t\t},\n\t}\n\tmibName, oidNum, oidText, fields, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTable(\"foo\")\n\trequire.Equal(t, \"a\", mibName)\n\trequire.Equal(t, \"b\", oidNum)\n\trequire.Equal(t, \"c\", oidText)\n\trequire.Equal(t, []Field{{Name: \"d\"}}, fields)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "plugins/common/snmp/wrapper.go",
    "content": "package snmp\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gosnmp/gosnmp\"\n)\n\n// Connection is an interface which wraps a *gosnmp.GoSNMP object.\n// We interact through an interface so we can mock it out in tests.\ntype Connection interface {\n\tHost() string\n\t// BulkWalkAll(string) ([]gosnmp.SnmpPDU, error)\n\tWalk(string, gosnmp.WalkFunc) error\n\tGet(oids []string) (*gosnmp.SnmpPacket, error)\n\tReconnect() error\n}\n\n// GosnmpWrapper wraps a *gosnmp.GoSNMP object so we can use it as a snmpConnection.\ntype GosnmpWrapper struct {\n\t*gosnmp.GoSNMP\n}\n\n// Host returns the value of GoSNMP.Target.\nfunc (gs GosnmpWrapper) Host() string {\n\treturn gs.Target\n}\n\n// Walk wraps GoSNMP.Walk() or GoSNMP.BulkWalk(), depending on whether the\n// connection is using SNMPv1 or newer.\nfunc (gs GosnmpWrapper) Walk(oid string, fn gosnmp.WalkFunc) error {\n\tif gs.Version == gosnmp.Version1 {\n\t\treturn gs.GoSNMP.Walk(oid, fn)\n\t}\n\treturn gs.GoSNMP.BulkWalk(oid, fn)\n}\n\nfunc NewWrapper(s ClientConfig) (GosnmpWrapper, error) {\n\tgs := GosnmpWrapper{&gosnmp.GoSNMP{}}\n\n\tgs.Timeout = time.Duration(s.Timeout)\n\n\tgs.Retries = s.Retries\n\n\tgs.UseUnconnectedUDPSocket = s.UnconnectedUDPSocket\n\n\tif s.GosnmpDebugLogger != nil {\n\t\tgs.Logger = gosnmp.NewLogger(&Logger{gs: &gs, Logger: s.GosnmpDebugLogger})\n\t}\n\n\tswitch s.Version {\n\tcase 3:\n\t\tgs.Version = gosnmp.Version3\n\tcase 2, 0:\n\t\tgs.Version = gosnmp.Version2c\n\tcase 1:\n\t\tgs.Version = gosnmp.Version1\n\tdefault:\n\t\treturn GosnmpWrapper{}, errors.New(\"invalid version\")\n\t}\n\n\tif s.Version < 3 {\n\t\tif s.Community == \"\" {\n\t\t\tgs.Community = \"public\"\n\t\t} else {\n\t\t\tgs.Community = s.Community\n\t\t}\n\t}\n\n\tgs.MaxRepetitions = s.MaxRepetitions\n\n\tgs.AppOpts = map[string]any{\n\t\t\"c\": true, // disable OID increasing check (some devices don't strictly increase)\n\t}\n\n\tif s.Version == 3 {\n\t\tgs.ContextName = s.ContextName\n\n\t\tsp := &gosnmp.UsmSecurityParameters{}\n\t\tgs.SecurityParameters = sp\n\t\tgs.SecurityModel = gosnmp.UserSecurityModel\n\n\t\tswitch strings.ToLower(s.SecLevel) {\n\t\tcase \"noauthnopriv\", \"\":\n\t\t\tgs.MsgFlags = gosnmp.NoAuthNoPriv\n\t\tcase \"authnopriv\":\n\t\t\tgs.MsgFlags = gosnmp.AuthNoPriv\n\t\tcase \"authpriv\":\n\t\t\tgs.MsgFlags = gosnmp.AuthPriv\n\t\tdefault:\n\t\t\treturn GosnmpWrapper{}, errors.New(\"invalid secLevel\")\n\t\t}\n\n\t\tsp.UserName = s.SecName\n\n\t\tswitch strings.ToLower(s.AuthProtocol) {\n\t\tcase \"md5\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.MD5\n\t\tcase \"sha\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.SHA\n\t\tcase \"sha224\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.SHA224\n\t\tcase \"sha256\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.SHA256\n\t\tcase \"sha384\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.SHA384\n\t\tcase \"sha512\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.SHA512\n\t\tcase \"\":\n\t\t\tsp.AuthenticationProtocol = gosnmp.NoAuth\n\t\tdefault:\n\t\t\treturn GosnmpWrapper{}, errors.New(\"invalid authProtocol\")\n\t\t}\n\n\t\tif !s.AuthPassword.Empty() {\n\t\t\tp, err := s.AuthPassword.Get()\n\t\t\tif err != nil {\n\t\t\t\treturn GosnmpWrapper{}, fmt.Errorf(\"getting authentication password failed: %w\", err)\n\t\t\t}\n\t\t\tsp.AuthenticationPassphrase = p.String()\n\t\t\tp.Destroy()\n\t\t}\n\n\t\tswitch strings.ToLower(s.PrivProtocol) {\n\t\tcase \"des\":\n\t\t\tsp.PrivacyProtocol = gosnmp.DES\n\t\tcase \"aes\":\n\t\t\tsp.PrivacyProtocol = gosnmp.AES\n\t\tcase \"aes192\":\n\t\t\tsp.PrivacyProtocol = gosnmp.AES192\n\t\tcase \"aes192c\":\n\t\t\tsp.PrivacyProtocol = gosnmp.AES192C\n\t\tcase \"aes256\":\n\t\t\tsp.PrivacyProtocol = gosnmp.AES256\n\t\tcase \"aes256c\":\n\t\t\tsp.PrivacyProtocol = gosnmp.AES256C\n\t\tcase \"\":\n\t\t\tsp.PrivacyProtocol = gosnmp.NoPriv\n\t\tdefault:\n\t\t\treturn GosnmpWrapper{}, errors.New(\"invalid privProtocol\")\n\t\t}\n\n\t\tif !s.PrivPassword.Empty() {\n\t\t\tp, err := s.PrivPassword.Get()\n\t\t\tif err != nil {\n\t\t\t\treturn GosnmpWrapper{}, fmt.Errorf(\"getting private password failed: %w\", err)\n\t\t\t}\n\t\t\tsp.PrivacyPassphrase = p.String()\n\t\t\tp.Destroy()\n\t\t}\n\t\tsp.AuthoritativeEngineID = s.EngineID\n\t\tsp.AuthoritativeEngineBoots = s.EngineBoots\n\t\tsp.AuthoritativeEngineTime = s.EngineTime\n\t}\n\treturn gs, nil\n}\n\n// SetAgent takes a url (scheme://host:port) and sets the wrapped\n// GoSNMP struct's corresponding fields.  This shouldn't be called\n// after using the wrapped GoSNMP struct, for example after\n// connecting.\nfunc (gs *GosnmpWrapper) SetAgent(agent string) error {\n\tif !strings.Contains(agent, \"://\") {\n\t\tagent = \"udp://\" + agent\n\t}\n\n\tu, err := url.Parse(agent)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Only allow udp{4,6} and tcp{4,6}.\n\t// Allowing ip{4,6} does not make sense as specifying a port\n\t// requires the specification of a protocol.\n\t// gosnmp does not handle these errors well, which is why\n\t// they can result in cryptic errors by net.Dial.\n\tswitch u.Scheme {\n\tcase \"tcp\", \"tcp4\", \"tcp6\", \"udp\", \"udp4\", \"udp6\":\n\t\tgs.Transport = u.Scheme\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported scheme: %v\", u.Scheme)\n\t}\n\n\tgs.Target = u.Hostname()\n\n\tportStr := u.Port()\n\tif portStr == \"\" {\n\t\tportStr = \"161\"\n\t}\n\tport, err := strconv.ParseUint(portStr, 10, 16)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing port: %w\", err)\n\t}\n\tgs.Port = uint16(port)\n\treturn nil\n}\n\nfunc (gs GosnmpWrapper) Reconnect() error {\n\tif gs.Conn == nil {\n\t\treturn gs.Connect()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/snmp/wrapper_test.go",
    "content": "package snmp\n\nimport \"github.com/gosnmp/gosnmp\"\n\ntype testSNMPConnection struct {\n\thost   string\n\tvalues map[string]interface{}\n}\n\nfunc (tsc *testSNMPConnection) Host() string {\n\treturn tsc.host\n}\n\nfunc (tsc *testSNMPConnection) Get(oids []string) (*gosnmp.SnmpPacket, error) {\n\tsp := &gosnmp.SnmpPacket{}\n\tfor _, oid := range oids {\n\t\tv, ok := tsc.values[oid]\n\t\tif !ok {\n\t\t\tsp.Variables = append(sp.Variables, gosnmp.SnmpPDU{\n\t\t\t\tName: oid,\n\t\t\t\tType: gosnmp.NoSuchObject,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tsp.Variables = append(sp.Variables, gosnmp.SnmpPDU{\n\t\t\tName:  oid,\n\t\t\tValue: v,\n\t\t})\n\t}\n\treturn sp, nil\n}\nfunc (tsc *testSNMPConnection) Walk(oid string, wf gosnmp.WalkFunc) error {\n\tfor void, v := range tsc.values {\n\t\tif void == oid || (len(void) > len(oid) && void[:len(oid)+1] == oid+\".\") {\n\t\t\tif err := wf(gosnmp.SnmpPDU{\n\t\t\t\tName:  void,\n\t\t\t\tValue: v,\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\nfunc (*testSNMPConnection) Reconnect() error {\n\treturn nil\n}\n\nvar tsc = &testSNMPConnection{\n\thost: \"tsc\",\n\tvalues: map[string]interface{}{\n\t\t\".1.0.0.0.1.1.0\":         \"foo\",\n\t\t\".1.0.0.0.1.1.1\":         []byte(\"bar\"),\n\t\t\".1.0.0.0.1.1.2\":         []byte(\"\"),\n\t\t\".1.0.0.0.1.102\":         \"bad\",\n\t\t\".1.0.0.0.1.2.0\":         1,\n\t\t\".1.0.0.0.1.2.1\":         2,\n\t\t\".1.0.0.0.1.2.2\":         0,\n\t\t\".1.0.0.0.1.3.0\":         \"0.123\",\n\t\t\".1.0.0.0.1.3.1\":         \"0.456\",\n\t\t\".1.0.0.0.1.3.2\":         \"0.000\",\n\t\t\".1.0.0.0.1.3.3\":         \"9.999\",\n\t\t\".1.0.0.0.1.5.0\":         123456,\n\t\t\".1.0.0.0.1.6.0\":         \".1.0.0.0.1.7\",\n\t\t\".1.0.0.1.1\":             \"baz\",\n\t\t\".1.0.0.1.2\":             234,\n\t\t\".1.0.0.1.3\":             []byte(\"byte slice\"),\n\t\t\".1.0.0.2.1.5.0.9.9\":     11,\n\t\t\".1.0.0.2.1.5.1.9.9\":     22,\n\t\t\".1.0.0.3.1.1.10\":        \"instance\",\n\t\t\".1.0.0.3.1.1.11\":        \"instance2\",\n\t\t\".1.0.0.3.1.1.12\":        \"instance3\",\n\t\t\".1.0.0.3.1.2.10\":        10,\n\t\t\".1.0.0.3.1.2.11\":        20,\n\t\t\".1.0.0.3.1.2.12\":        20,\n\t\t\".1.0.0.3.1.3.10\":        1,\n\t\t\".1.0.0.3.1.3.11\":        2,\n\t\t\".1.0.0.3.1.3.12\":        3,\n\t\t\".1.3.6.1.2.1.3.1.1.1.0\": \"foo\",\n\t\t\".1.3.6.1.2.1.3.1.1.1.1\": []byte(\"bar\"),\n\t\t\".1.3.6.1.2.1.3.1.1.1.2\": []byte(\"\"),\n\t\t\".1.3.6.1.2.1.3.1.1.102\": \"bad\",\n\t\t\".1.3.6.1.2.1.3.1.1.2.0\": 1,\n\t\t\".1.3.6.1.2.1.3.1.1.2.1\": 2,\n\t\t\".1.3.6.1.2.1.3.1.1.2.2\": 0,\n\t\t\".1.3.6.1.2.1.3.1.1.3.0\": \"1.3.6.1.2.1.3.1.1.3\",\n\t\t\".1.3.6.1.2.1.3.1.1.5.0\": 123456,\n\t},\n}\n"
  },
  {
    "path": "plugins/common/socket/datagram.go",
    "content": "package socket\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/alitto/pond\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\ntype packetListener struct {\n\tAllowedSources       []net.IP\n\tEncoding             string\n\tMaxDecompressionSize int64\n\tSocketMode           string\n\tReadBufferSize       int\n\tLog                  telegraf.Logger\n\n\tconn      net.PacketConn\n\tdecoders  sync.Pool\n\tpath      string\n\twg        sync.WaitGroup\n\tparsePool *pond.WorkerPool\n}\n\nfunc newPacketListener(encoding string, maxDecompressionSize config.Size, maxWorkers int, allowedSources []net.IP, logger telegraf.Logger) *packetListener {\n\treturn &packetListener{\n\t\tAllowedSources:       allowedSources,\n\t\tEncoding:             encoding,\n\t\tLog:                  logger,\n\t\tMaxDecompressionSize: int64(maxDecompressionSize),\n\t\tparsePool:            pond.New(maxWorkers, 0, pond.MinWorkers(maxWorkers/2+1)),\n\t}\n}\n\nfunc (l *packetListener) listenData(onData CallbackData, onError CallbackError) {\n\tl.wg.Add(1)\n\n\tgo func() {\n\t\tdefer l.wg.Done()\n\n\t\tbuf := make([]byte, l.ReadBufferSize)\n\t\tfor {\n\t\t\tn, src, err := l.conn.ReadFrom(buf)\n\t\t\treceiveTime := time.Now()\n\t\t\tif err != nil {\n\t\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\t\tif onError != nil {\n\t\t\t\t\t\tonError(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif allowed, err := isSourceAllowed(l.AllowedSources, src); err != nil {\n\t\t\t\t// Drop message if the check failed as security-by-default\n\t\t\t\tif onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else if !allowed {\n\t\t\t\tl.Log.Debugf(\"Received message from blocked IP: %s\", src)\n\t\t\t\t// Drop message if it is not from an allowed IP source\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\td := make([]byte, n)\n\t\t\tcopy(d, buf[:n])\n\t\t\tl.parsePool.Submit(func() {\n\t\t\t\tdecoder := l.decoders.Get().(internal.ContentDecoder)\n\t\t\t\tdefer l.decoders.Put(decoder)\n\t\t\t\tbody, err := decoder.Decode(d)\n\t\t\t\tif err != nil && onError != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"unable to decode incoming packet: %w\", err))\n\t\t\t\t}\n\n\t\t\t\tif l.path != \"\" {\n\t\t\t\t\tsrc = &net.UnixAddr{Name: l.path, Net: \"unixgram\"}\n\t\t\t\t}\n\n\t\t\t\tonData(src, body, receiveTime)\n\t\t\t})\n\t\t}\n\t}()\n}\n\nfunc (l *packetListener) listenConnection(onConnection CallbackConnection, onError CallbackError) {\n\tl.wg.Add(1)\n\tgo func() {\n\t\tdefer l.wg.Done()\n\t\tdefer l.conn.Close()\n\n\t\tbuf := make([]byte, l.ReadBufferSize)\n\t\tfor {\n\t\t\t// Wait for packets and read them\n\t\t\tn, src, err := l.conn.ReadFrom(buf)\n\t\t\tif err != nil {\n\t\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\t\tif onError != nil {\n\t\t\t\t\t\tonError(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\td := make([]byte, n)\n\t\t\tcopy(d, buf[:n])\n\t\t\tl.parsePool.Submit(func() {\n\t\t\t\t// Decode the contents depending on the given encoding\n\t\t\t\tdecoder := l.decoders.Get().(internal.ContentDecoder)\n\t\t\t\t// Not possible to immediately return the decoder to the Pool after calling Decode, because some\n\t\t\t\t// decoders return a reference to their internal buffers. This would cause data races.\n\t\t\t\tdefer l.decoders.Put(decoder)\n\t\t\t\tbody, err := decoder.Decode(d[:n])\n\t\t\t\tif err != nil && onError != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"unable to decode incoming packet: %w\", err))\n\t\t\t\t}\n\n\t\t\t\t// Workaround to provide remote endpoints for Unix-type sockets\n\t\t\t\tif l.path != \"\" {\n\t\t\t\t\tsrc = &net.UnixAddr{Name: l.path, Net: \"unixgram\"}\n\t\t\t\t}\n\n\t\t\t\t// Create a pipe and notify the caller via Callback that new data is\n\t\t\t\t// available. Afterwards write the data. Please note: Write() will\n\t\t\t\t// block until all data is consumed!\n\t\t\t\treader, writer := io.Pipe()\n\t\t\t\tgo onConnection(src, reader)\n\t\t\t\tif _, err := writer.Write(body); err != nil && onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\twriter.Close()\n\t\t\t})\n\t\t}\n\t}()\n}\n\nfunc (l *packetListener) setupUnixgram(u *url.URL, socketMode string, bufferSize int) error {\n\tl.path = filepath.FromSlash(u.Path)\n\tif runtime.GOOS == \"windows\" && strings.Contains(l.path, \":\") {\n\t\tl.path = strings.TrimPrefix(l.path, `\\`)\n\t}\n\tif err := os.Remove(l.path); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\treturn fmt.Errorf(\"removing socket failed: %w\", err)\n\t}\n\n\tconn, err := net.ListenPacket(u.Scheme, l.path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"listening (unixgram) failed: %w\", err)\n\t}\n\tl.conn = conn\n\n\t// Set permissions on socket\n\tif socketMode != \"\" {\n\t\t// Convert from octal in string to int\n\t\ti, err := strconv.ParseUint(socketMode, 8, 32)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting socket mode failed: %w\", err)\n\t\t}\n\n\t\tperm := os.FileMode(uint32(i))\n\t\tif err := os.Chmod(u.Path, perm); err != nil {\n\t\t\treturn fmt.Errorf(\"changing socket permissions failed: %w\", err)\n\t\t}\n\t}\n\n\tif bufferSize > 0 {\n\t\tl.ReadBufferSize = bufferSize\n\t} else {\n\t\tl.ReadBufferSize = 64 * 1024 // 64kb - IP packet size\n\t}\n\n\treturn l.setupDecoder()\n}\n\nfunc (l *packetListener) setupUDP(u *url.URL, ifname string, bufferSize int) error {\n\tvar conn *net.UDPConn\n\n\taddr, err := net.ResolveUDPAddr(u.Scheme, u.Host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"resolving UDP address failed: %w\", err)\n\t}\n\tif addr.IP.IsMulticast() {\n\t\tvar iface *net.Interface\n\t\tif ifname != \"\" {\n\t\t\tvar err error\n\t\t\tiface, err = net.InterfaceByName(ifname)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"resolving address of %q failed: %w\", ifname, err)\n\t\t\t}\n\t\t}\n\t\tconn, err = net.ListenMulticastUDP(u.Scheme, iface, addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"listening (udp multicast) failed: %w\", err)\n\t\t}\n\t} else {\n\t\tconn, err = net.ListenUDP(u.Scheme, addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"listening (udp) failed: %w\", err)\n\t\t}\n\t}\n\n\tif bufferSize > 0 {\n\t\tif err := conn.SetReadBuffer(bufferSize); err != nil {\n\t\t\tl.Log.Warnf(\"Setting read buffer on %s socket failed: %v\", u.Scheme, err)\n\t\t}\n\t}\n\n\tl.ReadBufferSize = 64 * 1024 // 64kb - IP packet size\n\tl.conn = conn\n\treturn l.setupDecoder()\n}\n\nfunc (l *packetListener) setupIP(u *url.URL) error {\n\tconn, err := net.ListenPacket(u.Scheme, u.Host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"listening (ip) failed: %w\", err)\n\t}\n\n\tl.ReadBufferSize = 64 * 1024 // 64kb - IP packet size\n\tl.conn = conn\n\treturn l.setupDecoder()\n}\n\nfunc (l *packetListener) setupDecoder() error {\n\t// Create a decoder for the given encoding\n\tvar options []internal.DecodingOption\n\tif l.MaxDecompressionSize > 0 {\n\t\toptions = append(options, internal.WithMaxDecompressionSize(l.MaxDecompressionSize))\n\t}\n\n\tl.decoders = sync.Pool{New: func() any {\n\t\tdecoder, err := internal.NewContentDecoder(l.Encoding, options...)\n\t\tif err != nil {\n\t\t\tl.Log.Errorf(\"creating decoder failed: %v\", err)\n\t\t\treturn nil\n\t\t}\n\n\t\treturn decoder\n\t}}\n\n\treturn nil\n}\n\nfunc (l *packetListener) address() net.Addr {\n\treturn l.conn.LocalAddr()\n}\n\nfunc (l *packetListener) close() error {\n\tif err := l.conn.Close(); err != nil {\n\t\treturn err\n\t}\n\tl.wg.Wait()\n\n\tif l.path != \"\" {\n\t\tfn := filepath.FromSlash(l.path)\n\t\tif runtime.GOOS == \"windows\" && strings.Contains(fn, \":\") {\n\t\t\tfn = strings.TrimPrefix(fn, `\\`)\n\t\t}\n\t\tif err := os.Remove(fn); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t// Ignore file-not-exists errors when removing the socket\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.parsePool.StopAndWait()\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/common/socket/socket.conf",
    "content": "  ## Permission for unix sockets (only available on unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Maximum number of concurrent connections (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # max_connections = 0\n\n  ## Read timeout (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # read_timeout = \"0s\"\n\n  ## Optional TLS configuration (only available on stream sockets like TCP)\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key  = \"/etc/telegraf/key.pem\"\n  ## Enables client authentication if set.\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Maximum socket buffer size (in bytes when no unit specified)\n  ## For stream sockets, once the buffer fills up, the sender will start\n  ## backing up. For datagram sockets, once the buffer fills up, metrics will\n  ## start dropping. Defaults to the OS default.\n  # read_buffer_size = \"64KiB\"\n\n  ## Period between keep alive probes (only applies to TCP sockets)\n  ## Zero disables keep alive probes. Defaults to the OS configuration.\n  # keep_alive_period = \"5m\"\n\n  ## Content encoding for message payloads\n  ## Can be set to \"gzip\" for compressed payloads or \"identity\" for no encoding.\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded packet (in bytes when no unit specified)\n  # max_decompression_size = \"500MB\"\n\n  ## List of allowed source IP addresses for incoming packets/messages.\n  ## If not specified or empty, all sources are allowed.\n  # allowed_sources = []"
  },
  {
    "path": "plugins/common/socket/socket.go",
    "content": "package socket\n\nimport (\n\t\"bufio\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\ntype CallbackData func(net.Addr, []byte, time.Time)\ntype CallbackConnection func(net.Addr, io.ReadCloser)\ntype CallbackError func(error)\n\ntype listener interface {\n\taddress() net.Addr\n\tlistenData(CallbackData, CallbackError)\n\tlistenConnection(CallbackConnection, CallbackError)\n\tclose() error\n}\n\ntype Config struct {\n\tMaxConnections       uint64           `toml:\"max_connections\"`\n\tReadBufferSize       config.Size      `toml:\"read_buffer_size\"`\n\tReadTimeout          config.Duration  `toml:\"read_timeout\"`\n\tKeepAlivePeriod      *config.Duration `toml:\"keep_alive_period\"`\n\tSocketMode           string           `toml:\"socket_mode\"`\n\tContentEncoding      string           `toml:\"content_encoding\"`\n\tMaxDecompressionSize config.Size      `toml:\"max_decompression_size\"`\n\tMaxParallelParsers   int              `toml:\"max_parallel_parsers\"`\n\tAllowedSources       []net.IP         `toml:\"allowed_sources\"`\n\tcommon_tls.ServerConfig\n}\n\ntype Socket struct {\n\tConfig\n\n\turl           *url.URL\n\tinterfaceName string\n\ttlsCfg        *tls.Config\n\tlog           telegraf.Logger\n\n\tsplitter bufio.SplitFunc\n\tlistener listener\n}\n\nfunc (cfg *Config) NewSocket(address string, splitcfg *SplitConfig, logger telegraf.Logger) (*Socket, error) {\n\ts := &Socket{\n\t\tConfig: *cfg,\n\t\tlog:    logger,\n\t}\n\n\t// Setup the splitter if given\n\tif splitcfg != nil {\n\t\tsplitter, err := splitcfg.NewSplitter()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ts.splitter = splitter\n\t}\n\n\t// Resolve the interface to an address if any given\n\tifregex := regexp.MustCompile(`%([\\w\\.]+)`)\n\tif matches := ifregex.FindStringSubmatch(address); len(matches) == 2 {\n\t\ts.interfaceName = matches[1]\n\t\taddress = strings.Replace(address, \"%\"+s.interfaceName, \"\", 1)\n\t}\n\n\t// Preparing TLS configuration\n\ttlsCfg, err := s.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting TLS config failed: %w\", err)\n\t}\n\ts.tlsCfg = tlsCfg\n\n\t// Parse and check the address\n\tu, err := url.Parse(address)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing address failed: %w\", err)\n\t}\n\ts.url = u\n\n\tswitch s.url.Scheme {\n\tcase \"tcp\", \"tcp4\", \"tcp6\", \"unix\", \"unixpacket\",\n\t\t\"udp\", \"udp4\", \"udp6\", \"ip\", \"ip4\", \"ip6\", \"unixgram\", \"vsock\":\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown protocol %q in %q\", u.Scheme, address)\n\t}\n\n\treturn s, nil\n}\n\nfunc (s *Socket) Setup() error {\n\ts.MaxParallelParsers = max(s.MaxParallelParsers, 1)\n\tswitch s.url.Scheme {\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\tl := newStreamListener(\n\t\t\ts.Config,\n\t\t\ts.splitter,\n\t\t\ts.log,\n\t\t)\n\n\t\tif err := l.setupTCP(s.url, s.tlsCfg); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tcase \"unix\", \"unixpacket\":\n\t\tl := newStreamListener(\n\t\t\ts.Config,\n\t\t\ts.splitter,\n\t\t\ts.log,\n\t\t)\n\n\t\tif err := l.setupUnix(s.url, s.tlsCfg, s.SocketMode); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\tl := newPacketListener(s.ContentEncoding, s.MaxDecompressionSize, s.MaxParallelParsers, s.AllowedSources, s.log)\n\t\tif err := l.setupUDP(s.url, s.interfaceName, int(s.ReadBufferSize)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tcase \"ip\", \"ip4\", \"ip6\":\n\t\tl := newPacketListener(s.ContentEncoding, s.MaxDecompressionSize, s.MaxParallelParsers, s.AllowedSources, s.log)\n\t\tif err := l.setupIP(s.url); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tcase \"unixgram\":\n\t\tl := newPacketListener(s.ContentEncoding, s.MaxDecompressionSize, s.MaxParallelParsers, s.AllowedSources, s.log)\n\t\tif err := l.setupUnixgram(s.url, s.SocketMode, int(s.ReadBufferSize)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tcase \"vsock\":\n\t\tl := newStreamListener(\n\t\t\ts.Config,\n\t\t\ts.splitter,\n\t\t\ts.log,\n\t\t)\n\n\t\tif err := l.setupVsock(s.url); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.listener = l\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown protocol %q\", s.url.Scheme)\n\t}\n\n\treturn nil\n}\n\nfunc (s *Socket) Listen(onData CallbackData, onError CallbackError) {\n\ts.listener.listenData(onData, onError)\n}\n\nfunc (s *Socket) ListenConnection(onConnection CallbackConnection, onError CallbackError) {\n\ts.listener.listenConnection(onConnection, onError)\n}\n\nfunc (s *Socket) Close() {\n\tif s.listener != nil {\n\t\t// Ignore the returned error as we cannot do anything about it anyway\n\t\tif err := s.listener.close(); err != nil {\n\t\t\ts.log.Warnf(\"Closing socket failed: %v\", err)\n\t\t}\n\t\ts.listener = nil\n\t}\n}\n\nfunc (s *Socket) Address() net.Addr {\n\treturn s.listener.address()\n}\n\nfunc isSourceAllowed(allowed []net.IP, addr net.Addr) (bool, error) {\n\tif len(allowed) == 0 {\n\t\t// No filtering, allow all\n\t\treturn true, nil\n\t}\n\tvar src net.IP\n\tswitch a := addr.(type) {\n\tcase *net.UDPAddr:\n\t\tsrc = a.IP\n\tcase *net.TCPAddr:\n\t\tsrc = a.IP\n\tcase *net.IPAddr:\n\t\tsrc = a.IP\n\tdefault:\n\t\treturn false, fmt.Errorf(\"source address %q (%T) has no IP\", addr, addr)\n\t}\n\treturn slices.ContainsFunc(allowed, func(allowedIP net.IP) bool {\n\t\treturn src.Equal(allowedIP)\n\t}), nil\n}\n"
  },
  {
    "path": "plugins/common/socket/socket_test.go",
    "content": "package socket\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar pki = testutil.NewPKI(\"../../../testutil/pki\")\n\nfunc TestListenData(t *testing.T) {\n\tmessages := [][]byte{\n\t\t[]byte(\"test,foo=bar v=1i 123456789\\ntest,foo=baz v=2i 123456790\\n\"),\n\t\t[]byte(\"test,foo=zab v=3i 123456791\\n\"),\n\t}\n\texpectedTemplates := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\"v\": int64(1)},\n\t\t\ttime.Unix(0, 123456789),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"baz\"},\n\t\t\tmap[string]interface{}{\"v\": int64(2)},\n\t\t\ttime.Unix(0, 123456790),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"zab\"},\n\t\t\tmap[string]interface{}{\"v\": int64(3)},\n\t\t\ttime.Unix(0, 123456791),\n\t\t),\n\t}\n\n\ttests := []struct {\n\t\tname       string\n\t\tschema     string\n\t\tbuffersize config.Size\n\t\tencoding   string\n\t}{\n\t\t{\n\t\t\tname:       \"TCP\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"TCP with TLS\",\n\t\t\tschema: \"tcp+tls\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP with gzip encoding\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP with gzip encoding\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unix socket\",\n\t\t\tschema:     \"unix\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"unix socket with TLS\",\n\t\t\tschema: \"unix+tls\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unix socket with gzip encoding\",\n\t\t\tschema:   \"unix\",\n\t\t\tencoding: \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unixgram socket\",\n\t\t\tschema:     \"unixgram\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t}\n\n\tserverTLS := pki.TLSServerConfig()\n\tclientTLS := pki.TLSClientConfig()\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tproto := strings.TrimSuffix(tt.schema, \"+tls\")\n\n\t\t\t// Prepare the address and socket if needed\n\t\t\tvar sockPath string\n\t\t\tvar serviceAddress string\n\t\t\tvar tlsCfg *tls.Config\n\t\t\tswitch proto {\n\t\t\tcase \"tcp\", \"udp\":\n\t\t\t\tserviceAddress = proto + \"://\" + \"127.0.0.1:0\"\n\t\t\tcase \"unix\", \"unixgram\":\n\t\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\t\tt.Skip(\"Skipping on Windows, as unixgram sockets are not supported\")\n\t\t\t\t}\n\n\t\t\t\t// Create a socket\n\t\t\t\tsockPath = testutil.TempSocket(t)\n\t\t\t\tf, err := os.Create(sockPath)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tdefer f.Close()\n\t\t\t\tserviceAddress = proto + \"://\" + sockPath\n\t\t\t}\n\n\t\t\t// Setup the configuration according to test specification\n\t\t\tcfg := &Config{\n\t\t\t\tContentEncoding: tt.encoding,\n\t\t\t\tReadBufferSize:  tt.buffersize,\n\t\t\t}\n\t\t\tif strings.HasSuffix(tt.schema, \"tls\") {\n\t\t\t\tcfg.ServerConfig = *serverTLS\n\t\t\t\tvar err error\n\t\t\t\ttlsCfg, err = clientTLS.TLSConfig()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Create the socket\n\t\t\tsock, err := cfg.NewSocket(serviceAddress, &SplitConfig{}, &testutil.Logger{})\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Create callbacks\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tonData := func(remote net.Addr, data []byte, _ time.Time) {\n\t\t\t\tm, err := parser.Parse(data)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\taddr, _, err := net.SplitHostPort(remote.String())\n\t\t\t\tif err != nil {\n\t\t\t\t\taddr = remote.String()\n\t\t\t\t}\n\t\t\t\tfor i := range m {\n\t\t\t\t\tm[i].AddTag(\"source\", addr)\n\t\t\t\t}\n\t\t\t\tacc.AddMetrics(m)\n\t\t\t}\n\t\t\tonError := func(err error) {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\n\t\t\t// Start the listener\n\t\t\trequire.NoError(t, sock.Setup())\n\t\t\tsock.Listen(onData, onError)\n\t\t\tdefer sock.Close()\n\n\t\t\taddr := sock.Address()\n\n\t\t\t// Create a noop client\n\t\t\t// Server is async, so verify no errors at the end.\n\t\t\tclient, err := createClient(serviceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, client.Close())\n\n\t\t\t// Setup the client for submitting data\n\t\t\tclient, err = createClient(serviceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Conditionally add the source address to the expectation\n\t\t\texpected := make([]telegraf.Metric, 0, len(expectedTemplates))\n\t\t\tfor _, tmpl := range expectedTemplates {\n\t\t\t\tm := tmpl.Copy()\n\t\t\t\tswitch proto {\n\t\t\t\tcase \"tcp\", \"udp\":\n\t\t\t\t\tladdr := client.LocalAddr().String()\n\t\t\t\t\taddr, _, err := net.SplitHostPort(laddr)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\taddr = laddr\n\t\t\t\t\t}\n\t\t\t\t\tm.AddTag(\"source\", addr)\n\t\t\t\tcase \"unix\", \"unixgram\":\n\t\t\t\t\tm.AddTag(\"source\", sockPath)\n\t\t\t\t}\n\t\t\t\texpected = append(expected, m)\n\t\t\t}\n\n\t\t\t// Send the data with the correct encoding\n\t\t\tencoder, err := internal.NewContentEncoder(tt.encoding)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor i, msg := range messages {\n\t\t\t\tm, err := encoder.Encode(msg)\n\t\t\t\trequire.NoErrorf(t, err, \"encoding failed for msg %d\", i)\n\t\t\t\t_, err = client.Write(m)\n\t\t\t\trequire.NoErrorf(t, err, \"sending msg %d failed\", i)\n\t\t\t}\n\n\t\t\t// Test the resulting metrics and compare against expected results\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d)\", acc.NMetrics())\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc TestListenConnection(t *testing.T) {\n\tmessages := [][]byte{\n\t\t[]byte(\"test,foo=bar v=1i 123456789\\ntest,foo=baz v=2i 123456790\\n\"),\n\t\t[]byte(\"test,foo=zab v=3i 123456791\\n\"),\n\t}\n\texpectedTemplates := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\"v\": int64(1)},\n\t\t\ttime.Unix(0, 123456789),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"baz\"},\n\t\t\tmap[string]interface{}{\"v\": int64(2)},\n\t\t\ttime.Unix(0, 123456790),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"zab\"},\n\t\t\tmap[string]interface{}{\"v\": int64(3)},\n\t\t\ttime.Unix(0, 123456791),\n\t\t),\n\t}\n\n\ttests := []struct {\n\t\tname       string\n\t\tschema     string\n\t\tbuffersize config.Size\n\t\tencoding   string\n\t}{\n\t\t{\n\t\t\tname:       \"TCP\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"TCP with TLS\",\n\t\t\tschema: \"tcp+tls\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP with gzip encoding\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP with gzip encoding\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unix socket\",\n\t\t\tschema:     \"unix\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"unix socket with TLS\",\n\t\t\tschema: \"unix+tls\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unix socket with gzip encoding\",\n\t\t\tschema:   \"unix\",\n\t\t\tencoding: \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unixgram socket\",\n\t\t\tschema:     \"unixgram\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t}\n\n\tserverTLS := pki.TLSServerConfig()\n\tclientTLS := pki.TLSClientConfig()\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tproto := strings.TrimSuffix(tt.schema, \"+tls\")\n\n\t\t\t// Prepare the address and socket if needed\n\t\t\tvar sockPath string\n\t\t\tvar serviceAddress string\n\t\t\tvar tlsCfg *tls.Config\n\t\t\tswitch proto {\n\t\t\tcase \"tcp\", \"udp\":\n\t\t\t\tserviceAddress = proto + \"://\" + \"127.0.0.1:0\"\n\t\t\tcase \"unix\", \"unixgram\":\n\t\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\t\tt.Skip(\"Skipping on Windows, as unixgram sockets are not supported\")\n\t\t\t\t}\n\n\t\t\t\t// Create a socket\n\t\t\t\tsockPath = testutil.TempSocket(t)\n\t\t\t\tf, err := os.Create(sockPath)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tdefer f.Close()\n\t\t\t\tserviceAddress = proto + \"://\" + sockPath\n\t\t\t}\n\n\t\t\t// Setup the configuration according to test specification\n\t\t\tcfg := &Config{\n\t\t\t\tContentEncoding: tt.encoding,\n\t\t\t\tReadBufferSize:  tt.buffersize,\n\t\t\t}\n\t\t\tif strings.HasSuffix(tt.schema, \"tls\") {\n\t\t\t\tcfg.ServerConfig = *serverTLS\n\t\t\t\tvar err error\n\t\t\t\ttlsCfg, err = clientTLS.TLSConfig()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Create the socket\n\t\t\tsock, err := cfg.NewSocket(serviceAddress, &SplitConfig{}, &testutil.Logger{})\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Create callbacks\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tonConnection := func(remote net.Addr, reader io.ReadCloser) {\n\t\t\t\tdata, err := io.ReadAll(reader)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tm, err := parser.Parse(data)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\taddr, _, err := net.SplitHostPort(remote.String())\n\t\t\t\tif err != nil {\n\t\t\t\t\taddr = remote.String()\n\t\t\t\t}\n\t\t\t\tfor i := range m {\n\t\t\t\t\tm[i].AddTag(\"source\", addr)\n\t\t\t\t}\n\t\t\t\tacc.AddMetrics(m)\n\t\t\t}\n\t\t\tonError := func(err error) {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\n\t\t\t// Start the listener\n\t\t\trequire.NoError(t, sock.Setup())\n\t\t\tsock.ListenConnection(onConnection, onError)\n\t\t\tdefer sock.Close()\n\n\t\t\taddr := sock.Address()\n\n\t\t\t// Create a noop client\n\t\t\t// Server is async, so verify no errors at the end.\n\t\t\tclient, err := createClient(serviceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, client.Close())\n\n\t\t\t// Setup the client for submitting data\n\t\t\tclient, err = createClient(serviceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Conditionally add the source address to the expectation\n\t\t\texpected := make([]telegraf.Metric, 0, len(expectedTemplates))\n\t\t\tfor _, tmpl := range expectedTemplates {\n\t\t\t\tm := tmpl.Copy()\n\t\t\t\tswitch proto {\n\t\t\t\tcase \"tcp\", \"udp\":\n\t\t\t\t\tladdr := client.LocalAddr().String()\n\t\t\t\t\taddr, _, err := net.SplitHostPort(laddr)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\taddr = laddr\n\t\t\t\t\t}\n\t\t\t\t\tm.AddTag(\"source\", addr)\n\t\t\t\tcase \"unix\", \"unixgram\":\n\t\t\t\t\tm.AddTag(\"source\", sockPath)\n\t\t\t\t}\n\t\t\t\texpected = append(expected, m)\n\t\t\t}\n\n\t\t\t// Send the data with the correct encoding\n\t\t\tencoder, err := internal.NewContentEncoder(tt.encoding)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor i, msg := range messages {\n\t\t\t\tm, err := encoder.Encode(msg)\n\t\t\t\trequire.NoErrorf(t, err, \"encoding failed for msg %d\", i)\n\t\t\t\t_, err = client.Write(m)\n\t\t\t\trequire.NoErrorf(t, err, \"sending msg %d failed\", i)\n\t\t\t}\n\t\t\tclient.Close()\n\n\t\t\t// Test the resulting metrics and compare against expected results\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d)\", acc.NMetrics())\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc TestClosingConnections(t *testing.T) {\n\t// Setup the configuration\n\tcfg := &Config{\n\t\tReadBufferSize: 1024,\n\t}\n\n\t// Create the socket\n\tserviceAddress := \"tcp://127.0.0.1:0\"\n\tlogger := &testutil.CaptureLogger{}\n\tsock, err := cfg.NewSocket(serviceAddress, &SplitConfig{}, logger)\n\trequire.NoError(t, err)\n\n\t// Create callbacks\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tvar acc testutil.Accumulator\n\tonData := func(_ net.Addr, data []byte, _ time.Time) {\n\t\tm, err := parser.Parse(data)\n\t\trequire.NoError(t, err)\n\t\tacc.AddMetrics(m)\n\t}\n\tonError := func(err error) {\n\t\tacc.AddError(err)\n\t}\n\n\t// Start the listener\n\trequire.NoError(t, sock.Setup())\n\tsock.Listen(onData, onError)\n\tdefer sock.Close()\n\n\taddr := sock.Address()\n\n\t// Create a noop client\n\tclient, err := createClient(serviceAddress, addr, nil)\n\trequire.NoError(t, err)\n\n\t_, err = client.Write([]byte(\"test value=42i\\n\"))\n\trequire.NoError(t, err)\n\n\trequire.Eventually(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= 1\n\t}, time.Second, 100*time.Millisecond, \"did not receive metric\")\n\n\t// This has to be a stream-listener...\n\tlistener, ok := sock.listener.(*streamListener)\n\trequire.True(t, ok)\n\tlistener.Lock()\n\tconns := listener.connections\n\tlistener.Unlock()\n\trequire.NotZero(t, conns)\n\n\tsock.Close()\n\n\t// Verify that plugin.Stop() closed the client's connection\n\trequire.NoError(t, client.SetReadDeadline(time.Now().Add(time.Second)))\n\tbuf := []byte{1}\n\t_, err = client.Read(buf)\n\trequire.Equal(t, err, io.EOF)\n\n\trequire.Empty(t, logger.Errors())\n\trequire.Empty(t, logger.Warnings())\n}\nfunc TestMaxConnections(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" {\n\t\tt.Skip(\"Skipping on darwin due to missing socket options\")\n\t}\n\n\t// Setup the configuration\n\tperiod := config.Duration(10 * time.Millisecond)\n\tcfg := &Config{\n\t\tMaxConnections:  5,\n\t\tKeepAlivePeriod: &period,\n\t}\n\n\t// Create the socket\n\tserviceAddress := \"tcp://127.0.0.1:0\"\n\tsock, err := cfg.NewSocket(serviceAddress, nil, &testutil.Logger{})\n\trequire.NoError(t, err)\n\n\t// Create callback\n\tvar errs []error\n\tvar mu sync.Mutex\n\tonData := func(_ net.Addr, _ []byte, _ time.Time) {}\n\tonError := func(err error) {\n\t\tmu.Lock()\n\t\terrs = append(errs, err)\n\t\tmu.Unlock()\n\t}\n\n\t// Start the listener\n\trequire.NoError(t, sock.Setup())\n\tsock.Listen(onData, onError)\n\tdefer sock.Close()\n\n\taddr := sock.Address()\n\n\t// Create maximum number of connections and write some data. All of this\n\t// should succeed...\n\tclients := make([]*net.TCPConn, 0, cfg.MaxConnections)\n\tfor i := 0; i < int(cfg.MaxConnections); i++ {\n\t\tc, err := net.DialTCP(\"tcp\", nil, addr.(*net.TCPAddr))\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, c.SetWriteBuffer(0))\n\t\trequire.NoError(t, c.SetNoDelay(true))\n\t\tclients = append(clients, c)\n\n\t\t_, err = c.Write([]byte(\"test value=42i\\n\"))\n\t\trequire.NoError(t, err)\n\t}\n\n\tfunc() {\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\trequire.Empty(t, errs)\n\t}()\n\n\t// Create another client. This should fail because we already reached the\n\t// connection limit and the connection should be closed...\n\tclient, err := net.DialTCP(\"tcp\", nil, addr.(*net.TCPAddr))\n\trequire.NoError(t, err)\n\trequire.NoError(t, client.SetWriteBuffer(0))\n\trequire.NoError(t, client.SetNoDelay(true))\n\n\trequire.Eventually(t, func() bool {\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\treturn len(errs) > 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\tfunc() {\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\trequire.Len(t, errs, 1)\n\t\trequire.ErrorContains(t, errs[0], \"too many connections\")\n\t\terrs = make([]error, 0)\n\t}()\n\n\trequire.Eventually(t, func() bool {\n\t\t_, err := client.Write([]byte(\"fail\\n\"))\n\t\treturn err != nil\n\t}, 3*time.Second, 100*time.Millisecond)\n\t_, err = client.Write([]byte(\"test\\n\"))\n\trequire.Error(t, err)\n\n\t// Check other connections are still good\n\tfor _, c := range clients {\n\t\t_, err := c.Write([]byte(\"test\\n\"))\n\t\trequire.NoError(t, err)\n\t}\n\tfunc() {\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\trequire.Empty(t, errs)\n\t}()\n\n\t// Get the actual stream listener for introspection\n\tlistener, ok := sock.listener.(*streamListener)\n\trequire.True(t, ok)\n\n\t// Close the first client and wait for the plugin to realize the socket was\n\t// actually closed\n\trequire.NoError(t, clients[0].Close())\n\trequire.Eventually(t, func() bool {\n\t\tlistener.Lock()\n\t\tdefer listener.Unlock()\n\t\treturn listener.connections < listener.MaxConnections\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Attempt a new connection which should succeed now\n\tclient, err = net.DialTCP(\"tcp\", nil, addr.(*net.TCPAddr))\n\trequire.NoError(t, err)\n\trequire.NoError(t, client.SetWriteBuffer(0))\n\trequire.NoError(t, client.SetNoDelay(true))\n\t_, err = client.Write([]byte(\"success\\n\"))\n\trequire.NoError(t, err)\n\n\t// Close all connections\n\trequire.NoError(t, client.Close())\n\tfor _, c := range clients[1:] {\n\t\trequire.NoError(t, c.Close())\n\t}\n\n\t// Close the clients and check the connection counter\n\trequire.Eventually(t, func() bool {\n\t\tlistener.Lock()\n\t\tconns := listener.connections\n\t\tlistener.Unlock()\n\t\treturn conns == 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Close the socket and check again...\n\tsock.Close()\n\tlistener.Lock()\n\tconns := listener.connections\n\tlistener.Unlock()\n\trequire.Zero(t, conns)\n}\n\nfunc TestNoSplitter(t *testing.T) {\n\tmessages := [][]byte{\n\t\t[]byte(\"test,foo=bar v\"),\n\t\t[]byte(\"=1i 123456789\\ntest,foo=baz v=2i 123456790\\ntest,foo=zab v=3i 123456791\\n\"),\n\t}\n\texpectedTemplates := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\"v\": int64(1)},\n\t\t\ttime.Unix(0, 123456789),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"baz\"},\n\t\t\tmap[string]interface{}{\"v\": int64(2)},\n\t\t\ttime.Unix(0, 123456790),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"zab\"},\n\t\t\tmap[string]interface{}{\"v\": int64(3)},\n\t\t\ttime.Unix(0, 123456791),\n\t\t),\n\t}\n\n\t// Prepare the address and socket if needed\n\tserviceAddress := \"tcp://127.0.0.1:0\"\n\n\t// Setup the configuration according to test specification\n\tcfg := &Config{}\n\n\t// Create the socket\n\tsock, err := cfg.NewSocket(serviceAddress, nil, &testutil.Logger{})\n\trequire.NoError(t, err)\n\n\t// Create callbacks\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tvar acc testutil.Accumulator\n\tonConnection := func(remote net.Addr, reader io.ReadCloser) {\n\t\tdata, err := io.ReadAll(reader)\n\t\trequire.NoError(t, err)\n\t\tm, err := parser.Parse(data)\n\t\trequire.NoError(t, err)\n\t\taddr, _, err := net.SplitHostPort(remote.String())\n\t\tif err != nil {\n\t\t\taddr = remote.String()\n\t\t}\n\t\tfor i := range m {\n\t\t\tm[i].AddTag(\"source\", addr)\n\t\t}\n\t\tacc.AddMetrics(m)\n\t}\n\tonError := func(err error) {\n\t\tacc.AddError(err)\n\t}\n\n\t// Start the listener\n\trequire.NoError(t, sock.Setup())\n\tsock.ListenConnection(onConnection, onError)\n\tdefer sock.Close()\n\n\taddr := sock.Address()\n\n\t// Create a noop client\n\t// Server is async, so verify no errors at the end.\n\tclient, err := createClient(serviceAddress, addr, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, client.Close())\n\n\t// Setup the client for submitting data\n\tclient, err = createClient(serviceAddress, addr, nil)\n\trequire.NoError(t, err)\n\n\t// Conditionally add the source address to the expectation\n\texpected := make([]telegraf.Metric, 0, len(expectedTemplates))\n\tfor _, tmpl := range expectedTemplates {\n\t\tm := tmpl.Copy()\n\t\tladdr := client.LocalAddr().String()\n\t\taddr, _, err := net.SplitHostPort(laddr)\n\t\tif err != nil {\n\t\t\taddr = laddr\n\t\t}\n\t\tm.AddTag(\"source\", addr)\n\t\texpected = append(expected, m)\n\t}\n\n\t// Send the data\n\tfor i, msg := range messages {\n\t\t_, err = client.Write(msg)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\trequire.NoErrorf(t, err, \"sending msg %d failed\", i)\n\t}\n\tclient.Close()\n\n\t// Test the resulting metrics and compare against expected results\n\trequire.Eventuallyf(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d)\", acc.NMetrics())\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n}\n\nfunc TestTLSMemLeak(t *testing.T) {\n\t// For issue https://github.com/influxdata/telegraf/issues/15509\n\n\t// Prepare the address and socket if needed\n\tserviceAddress := \"tcp://127.0.0.1:0\"\n\n\t// Setup a TLS socket to trigger the issue\n\tcfg := &Config{\n\t\tServerConfig: *pki.TLSServerConfig(),\n\t}\n\n\t// Create the socket\n\tsock, err := cfg.NewSocket(serviceAddress, nil, &testutil.Logger{})\n\trequire.NoError(t, err)\n\n\t// Create callbacks\n\tonConnection := func(_ net.Addr, reader io.ReadCloser) {\n\t\t//nolint:errcheck // We are not interested in the data so ignore all errors\n\t\tio.Copy(io.Discard, reader)\n\t}\n\n\t// Start the listener\n\trequire.NoError(t, sock.Setup())\n\tsock.ListenConnection(onConnection, nil)\n\tdefer sock.Close()\n\n\taddr := sock.Address()\n\n\t// Setup the client side TLS\n\ttlsCfg, err := pki.TLSClientConfig().TLSConfig()\n\trequire.NoError(t, err)\n\n\t// Define a single client write sequence\n\tdata := []byte(\"test value=42i\")\n\twrite := func() error {\n\t\tconn, err := tls.Dial(\"tcp\", addr.String(), tlsCfg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer conn.Close()\n\n\t\t_, err = conn.Write(data)\n\t\treturn err\n\t}\n\n\t// Define a test with the given number of connections\n\tmaxConcurrency := runtime.GOMAXPROCS(0)\n\ttestCycle := func(connections int) (uint64, error) {\n\t\tvar mu sync.Mutex\n\t\tvar errs []error\n\t\tvar wg sync.WaitGroup\n\t\tfor count := 1; count < connections; count++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tif err := write(); err != nil {\n\t\t\t\t\tmu.Lock()\n\t\t\t\t\terrs = append(errs, err)\n\t\t\t\t\tmu.Unlock()\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif count%maxConcurrency == 0 {\n\t\t\t\twg.Wait()\n\t\t\t\tmu.Lock()\n\t\t\t\tif len(errs) > 0 {\n\t\t\t\t\tmu.Unlock()\n\t\t\t\t\treturn 0, errors.Join(errs...)\n\t\t\t\t}\n\t\t\t\tmu.Unlock()\n\t\t\t}\n\t\t}\n\t\t//nolint:revive // We need to actively run the garbage collector to get reliable measurements\n\t\truntime.GC()\n\n\t\tvar stats runtime.MemStats\n\t\truntime.ReadMemStats(&stats)\n\t\treturn stats.HeapObjects, nil\n\t}\n\n\t// Measure the memory usage after a short warmup and after some time.\n\t// The final number of heap objects should not exceed the number of\n\t// runs by a save margin\n\n\t// Warmup, do a low number of runs to initialize all data structures\n\t// taking them out of the equation.\n\tinitial, err := testCycle(100)\n\trequire.NoError(t, err)\n\n\t// Do some more runs and make sure the memory growth is bound\n\tfinal, err := testCycle(2000)\n\trequire.NoError(t, err)\n\n\trequire.Less(t, final, 3*initial)\n}\n\nfunc createClient(endpoint string, addr net.Addr, tlsCfg *tls.Config) (net.Conn, error) {\n\t// Determine the protocol in a crude fashion\n\tparts := strings.SplitN(endpoint, \"://\", 2)\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid endpoint %q\", endpoint)\n\t}\n\tprotocol := parts[0]\n\n\tif tlsCfg == nil {\n\t\treturn net.Dial(protocol, addr.String())\n\t}\n\n\tif protocol == \"unix\" {\n\t\ttlsCfg.InsecureSkipVerify = true\n\t}\n\treturn tls.Dial(protocol, addr.String(), tlsCfg)\n}\n"
  },
  {
    "path": "plugins/common/socket/splitter.conf",
    "content": "  ## Message splitting strategy and corresponding settings for stream sockets\n  ## (tcp, tcp4, tcp6, unix or unixpacket). The setting is ignored for packet\n  ## listeners such as udp.\n  ## Available strategies are:\n  ##   newline         -- split at newlines (default)\n  ##   null            -- split at null bytes\n  ##   delimiter       -- split at delimiter byte-sequence in hex-format\n  ##                      given in `splitting_delimiter`\n  ##   fixed length    -- split after number of bytes given in `splitting_length`\n  ##   variable length -- split depending on length information received in the\n  ##                      data. The length field information is specified in\n  ##                      `splitting_length_field`.\n  # splitting_strategy = \"newline\"\n\n  ## Delimiter used to split received data to messages consumed by the parser.\n  ## The delimiter is a hex byte-sequence marking the end of a message\n  ## e.g. \"0x0D0A\", \"x0d0a\" or \"0d0a\" marks a Windows line-break (CR LF).\n  ## The value is case-insensitive and can be specified with \"0x\" or \"x\" prefix\n  ## or without.\n  ## Note: This setting is only used for splitting_strategy = \"delimiter\".\n  # splitting_delimiter = \"\"\n\n  ## Fixed length of a message in bytes.\n  ## Note: This setting is only used for splitting_strategy = \"fixed length\".\n  # splitting_length = 0\n\n  ## Specification of the length field contained in the data to split messages\n  ## with variable length. The specification contains the following fields:\n  ##  offset        -- start of length field in bytes from begin of data\n  ##  bytes         -- length of length field in bytes\n  ##  endianness    -- endianness of the value, either \"be\" for big endian or\n  ##                   \"le\" for little endian\n  ##  header_length -- total length of header to be skipped when passing\n  ##                   data on to the parser. If zero (default), the header\n  ##                   is passed on to the parser together with the message.\n  ## Note: This setting is only used for splitting_strategy = \"variable length\".\n  # splitting_length_field = {offset = 0, bytes = 0, endianness = \"be\", header_length = 0}"
  },
  {
    "path": "plugins/common/socket/splitters.go",
    "content": "package socket\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n)\n\ntype lengthFieldSpec struct {\n\tOffset       int64  `toml:\"offset\"`\n\tBytes        int64  `toml:\"bytes\"`\n\tEndianness   string `toml:\"endianness\"`\n\tHeaderLength int64  `toml:\"header_length\"`\n\tconverter    func([]byte) int\n}\n\ntype SplitConfig struct {\n\tSplittingStrategy    string          `toml:\"splitting_strategy\"`\n\tSplittingDelimiter   string          `toml:\"splitting_delimiter\"`\n\tSplittingLength      int             `toml:\"splitting_length\"`\n\tSplittingLengthField lengthFieldSpec `toml:\"splitting_length_field\"`\n}\n\nfunc (cfg *SplitConfig) NewSplitter() (bufio.SplitFunc, error) {\n\tswitch cfg.SplittingStrategy {\n\tcase \"\", \"newline\":\n\t\treturn bufio.ScanLines, nil\n\tcase \"null\":\n\t\treturn scanNull, nil\n\tcase \"delimiter\":\n\t\tre := regexp.MustCompile(`(\\s*0?x)`)\n\t\td := re.ReplaceAllString(strings.ToLower(cfg.SplittingDelimiter), \"\")\n\t\tdelimiter, err := hex.DecodeString(d)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding delimiter failed: %w\", err)\n\t\t}\n\t\treturn createScanDelimiter(delimiter), nil\n\tcase \"fixed length\":\n\t\treturn createScanFixedLength(cfg.SplittingLength), nil\n\tcase \"variable length\":\n\t\t// Create the converter function\n\t\tvar order binary.ByteOrder\n\t\tswitch strings.ToLower(cfg.SplittingLengthField.Endianness) {\n\t\tcase \"\", \"be\":\n\t\t\torder = binary.BigEndian\n\t\tcase \"le\":\n\t\t\torder = binary.LittleEndian\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid 'endianness' %q\", cfg.SplittingLengthField.Endianness)\n\t\t}\n\n\t\tswitch cfg.SplittingLengthField.Bytes {\n\t\tcase 1:\n\t\t\tcfg.SplittingLengthField.converter = func(b []byte) int {\n\t\t\t\treturn int(b[0])\n\t\t\t}\n\t\tcase 2:\n\t\t\tcfg.SplittingLengthField.converter = func(b []byte) int {\n\t\t\t\treturn int(order.Uint16(b))\n\t\t\t}\n\t\tcase 4:\n\t\t\tcfg.SplittingLengthField.converter = func(b []byte) int {\n\t\t\t\treturn int(order.Uint32(b))\n\t\t\t}\n\t\tcase 8:\n\t\t\tcfg.SplittingLengthField.converter = func(b []byte) int {\n\t\t\t\treturn int(order.Uint64(b))\n\t\t\t}\n\t\tdefault:\n\t\t\tcfg.SplittingLengthField.converter = func(b []byte) int {\n\t\t\t\tbuf := make([]byte, 8)\n\t\t\t\tstart := 0\n\t\t\t\tif order == binary.BigEndian {\n\t\t\t\t\tstart = 8 - len(b)\n\t\t\t\t}\n\t\t\t\tfor i := 0; i < len(b); i++ {\n\t\t\t\t\tbuf[start+i] = b[i]\n\t\t\t\t}\n\t\t\t\treturn int(order.Uint64(buf))\n\t\t\t}\n\t\t}\n\n\t\t// Check if we have enough bytes in the header\n\t\treturn createScanVariableLength(cfg.SplittingLengthField), nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unknown 'splitting_strategy' %q\", cfg.SplittingStrategy)\n}\n\nfunc scanNull(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\tif atEOF && len(data) == 0 {\n\t\treturn 0, nil, nil\n\t}\n\tif i := bytes.IndexByte(data, 0); i >= 0 {\n\t\treturn i + 1, data[:i], nil\n\t}\n\tif atEOF {\n\t\treturn len(data), data, nil\n\t}\n\t// Request more data.\n\treturn 0, nil, nil\n}\n\nfunc createScanDelimiter(delimiter []byte) bufio.SplitFunc {\n\treturn func(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\t\tif atEOF && len(data) == 0 {\n\t\t\treturn 0, nil, nil\n\t\t}\n\t\tif i := bytes.Index(data, delimiter); i >= 0 {\n\t\t\treturn i + len(delimiter), data[:i], nil\n\t\t}\n\t\tif atEOF {\n\t\t\treturn len(data), data, nil\n\t\t}\n\t\t// Request more data.\n\t\treturn 0, nil, nil\n\t}\n}\n\nfunc createScanFixedLength(length int) bufio.SplitFunc {\n\treturn func(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\t\tif atEOF && len(data) == 0 {\n\t\t\treturn 0, nil, nil\n\t\t}\n\t\tif len(data) >= length {\n\t\t\treturn length, data[:length], nil\n\t\t}\n\t\tif atEOF {\n\t\t\treturn len(data), data, nil\n\t\t}\n\t\t// Request more data.\n\t\treturn 0, nil, nil\n\t}\n}\n\nfunc createScanVariableLength(spec lengthFieldSpec) bufio.SplitFunc {\n\tminlen := int(spec.Offset)\n\tminlen += int(spec.Bytes)\n\theaderLen := int(spec.HeaderLength)\n\n\treturn func(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\t\tif atEOF && len(data) == 0 {\n\t\t\treturn 0, nil, nil\n\t\t}\n\t\tdataLen := len(data)\n\t\tif dataLen >= minlen {\n\t\t\t// Extract the length field and convert it to a number\n\t\t\tlf := data[spec.Offset : spec.Offset+spec.Bytes]\n\t\t\tlength := spec.converter(lf)\n\t\t\tstart := headerLen\n\t\t\tend := length + headerLen\n\t\t\t// If we have enough data return it without the header\n\t\t\tif end <= dataLen {\n\t\t\t\treturn end, data[start:end], nil\n\t\t\t}\n\t\t}\n\t\tif atEOF {\n\t\t\treturn len(data), data, nil\n\t\t}\n\t\t// Request more data.\n\t\treturn 0, nil, nil\n\t}\n}\n"
  },
  {
    "path": "plugins/common/socket/stream.go",
    "content": "package socket\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/alitto/pond\"\n\t\"github.com/mdlayher/vsock\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\ntype hasSetReadBuffer interface {\n\tSetReadBuffer(bytes int) error\n}\n\ntype streamListener struct {\n\tAllowedSources  []net.IP\n\tEncoding        string\n\tReadBufferSize  int\n\tMaxConnections  uint64\n\tReadTimeout     config.Duration\n\tKeepAlivePeriod *config.Duration\n\tSplitter        bufio.SplitFunc\n\tLog             telegraf.Logger\n\n\tlistener    net.Listener\n\tconnections uint64\n\tpath        string\n\tcancel      context.CancelFunc\n\tparsePool   *pond.WorkerPool\n\n\twg sync.WaitGroup\n\tsync.Mutex\n}\n\nfunc newStreamListener(conf Config, splitter bufio.SplitFunc, log telegraf.Logger) *streamListener {\n\treturn &streamListener{\n\t\tAllowedSources:  conf.AllowedSources,\n\t\tReadBufferSize:  int(conf.ReadBufferSize),\n\t\tReadTimeout:     conf.ReadTimeout,\n\t\tKeepAlivePeriod: conf.KeepAlivePeriod,\n\t\tMaxConnections:  conf.MaxConnections,\n\t\tEncoding:        conf.ContentEncoding,\n\t\tSplitter:        splitter,\n\t\tLog:             log,\n\n\t\tparsePool: pond.New(\n\t\t\tconf.MaxParallelParsers,\n\t\t\t0,\n\t\t\tpond.MinWorkers(conf.MaxParallelParsers/2+1)),\n\t}\n}\n\nfunc (l *streamListener) setupTCP(u *url.URL, tlsCfg *tls.Config) error {\n\tvar err error\n\tif tlsCfg == nil {\n\t\tl.listener, err = net.Listen(u.Scheme, u.Host)\n\t} else {\n\t\tl.listener, err = tls.Listen(u.Scheme, u.Host, tlsCfg)\n\t}\n\treturn err\n}\n\nfunc (l *streamListener) setupUnix(u *url.URL, tlsCfg *tls.Config, socketMode string) error {\n\tl.path = filepath.FromSlash(u.Path)\n\tif runtime.GOOS == \"windows\" && strings.Contains(l.path, \":\") {\n\t\tl.path = strings.TrimPrefix(l.path, `\\`)\n\t}\n\tif err := os.Remove(l.path); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\treturn fmt.Errorf(\"removing socket failed: %w\", err)\n\t}\n\n\tvar err error\n\tif tlsCfg == nil {\n\t\tl.listener, err = net.Listen(u.Scheme, l.path)\n\t} else {\n\t\tl.listener, err = tls.Listen(u.Scheme, l.path, tlsCfg)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Set permissions on socket\n\tif socketMode != \"\" {\n\t\t// Convert from octal in string to int\n\t\ti, err := strconv.ParseUint(socketMode, 8, 32)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting socket mode failed: %w\", err)\n\t\t}\n\n\t\tperm := os.FileMode(uint32(i))\n\t\tif err := os.Chmod(u.Path, perm); err != nil {\n\t\t\treturn fmt.Errorf(\"changing socket permissions failed: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (l *streamListener) setupVsock(u *url.URL) error {\n\tvar err error\n\n\taddrTuple := strings.SplitN(u.String(), \":\", 2)\n\n\t// Check address string for containing two tokens\n\tif len(addrTuple) < 2 {\n\t\treturn errors.New(\"port and/or CID number missing\")\n\t}\n\t// Parse CID and port number from address string both being 32-bit\n\t// source: https://man7.org/linux/man-pages/man7/vsock.7.html\n\tcid, err := strconv.ParseUint(addrTuple[0], 10, 32)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CID %s: %w\", addrTuple[0], err)\n\t}\n\tif (cid >= uint64(math.Pow(2, 32))-1) && (cid <= 0) {\n\t\treturn fmt.Errorf(\"value of CID %d is out of range\", cid)\n\t}\n\tport, err := strconv.ParseUint(addrTuple[1], 10, 32)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse port number %s: %w\", addrTuple[1], err)\n\t}\n\tif (port >= uint64(math.Pow(2, 32))-1) && (port <= 0) {\n\t\treturn fmt.Errorf(\"port number %d is out of range\", port)\n\t}\n\n\tl.listener, err = vsock.Listen(uint32(port), nil)\n\treturn err\n}\n\nfunc (l *streamListener) setupConnection(conn net.Conn) error {\n\taddr := conn.RemoteAddr().String()\n\tl.Lock()\n\tif l.MaxConnections > 0 && l.connections >= l.MaxConnections {\n\t\tl.Unlock()\n\t\t// Ignore the returned error as we cannot do anything about it anyway\n\t\t_ = conn.Close()\n\t\treturn fmt.Errorf(\"unable to accept connection from %q: too many connections\", addr)\n\t}\n\tl.connections++\n\tl.Unlock()\n\n\tif l.ReadBufferSize > 0 {\n\t\tif rb, ok := conn.(hasSetReadBuffer); ok {\n\t\t\tif err := rb.SetReadBuffer(l.ReadBufferSize); err != nil {\n\t\t\t\tl.Log.Warnf(\"Setting read buffer on socket failed: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tl.Log.Warn(\"Cannot set read buffer on socket of this type\")\n\t\t}\n\t}\n\n\t// Set keep alive handlings\n\tif l.KeepAlivePeriod != nil {\n\t\tif c, ok := conn.(*tls.Conn); ok {\n\t\t\tconn = c.NetConn()\n\t\t}\n\t\ttcpConn, ok := conn.(*net.TCPConn)\n\t\tif !ok {\n\t\t\tl.Log.Warnf(\"connection not a TCP connection (%T)\", conn)\n\t\t}\n\t\tif *l.KeepAlivePeriod == 0 {\n\t\t\tif err := tcpConn.SetKeepAlive(false); err != nil {\n\t\t\t\tl.Log.Warnf(\"Cannot set keep-alive: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err := tcpConn.SetKeepAlive(true); err != nil {\n\t\t\t\tl.Log.Warnf(\"Cannot set keep-alive: %v\", err)\n\t\t\t}\n\t\t\terr := tcpConn.SetKeepAlivePeriod(time.Duration(*l.KeepAlivePeriod))\n\t\t\tif err != nil {\n\t\t\t\tl.Log.Warnf(\"Cannot set keep-alive period: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *streamListener) closeConnection(conn net.Conn) {\n\t// Fallback to enforce blocked reads on connections to end immediately\n\t//nolint:errcheck // Ignore errors as this is a fallback only\n\tconn.SetReadDeadline(time.Now())\n\n\taddr := conn.RemoteAddr().String()\n\tif err := conn.Close(); err != nil && !errors.Is(err, net.ErrClosed) && !errors.Is(err, syscall.EPIPE) {\n\t\tl.Log.Warnf(\"Cannot close connection to %q: %v\", addr, err)\n\t} else {\n\t\tl.Lock()\n\t\tl.connections--\n\t\tl.Unlock()\n\t}\n}\n\nfunc (l *streamListener) address() net.Addr {\n\treturn l.listener.Addr()\n}\n\nfunc (l *streamListener) close() error {\n\tif l.listener != nil {\n\t\t// Continue even if we cannot close the listener in order to at least\n\t\t// close all active connections\n\t\tif err := l.listener.Close(); err != nil {\n\t\t\tl.Log.Errorf(\"Cannot close listener: %v\", err)\n\t\t}\n\t}\n\n\tif l.cancel != nil {\n\t\tl.cancel()\n\t\tl.cancel = nil\n\t}\n\tl.wg.Wait()\n\n\tif l.path != \"\" {\n\t\tfn := filepath.FromSlash(l.path)\n\t\tif runtime.GOOS == \"windows\" && strings.Contains(fn, \":\") {\n\t\t\tfn = strings.TrimPrefix(fn, `\\`)\n\t\t}\n\t\t// Ignore file-not-exists errors when removing the socket\n\t\tif err := os.Remove(fn); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.parsePool.StopAndWait()\n\n\treturn nil\n}\n\nfunc (l *streamListener) listenData(onData CallbackData, onError CallbackError) {\n\tctx, cancel := context.WithCancel(context.Background())\n\tl.cancel = cancel\n\n\tl.wg.Add(1)\n\tgo func() {\n\t\tdefer l.wg.Done()\n\n\t\tfor {\n\t\t\tconn, err := l.listener.Accept()\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, net.ErrClosed) && onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif allowed, err := isSourceAllowed(l.AllowedSources, conn.RemoteAddr()); err != nil {\n\t\t\t\tif onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\tif err := conn.Close(); err != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"closing connection from %q failed: %w\", conn.RemoteAddr(), err))\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else if !allowed {\n\t\t\t\tif err = conn.Close(); err != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"closing connection from %q failed: %w\", conn.RemoteAddr(), err))\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := l.setupConnection(conn); err != nil && onError != nil {\n\t\t\t\tonError(err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tl.wg.Add(1)\n\t\t\tgo l.handleReaderConn(ctx, conn, onData, onError)\n\t\t}\n\t}()\n}\n\nfunc (l *streamListener) handleReaderConn(ctx context.Context, conn net.Conn, onData CallbackData, onError CallbackError) {\n\tdefer l.wg.Done()\n\n\tlocalCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\tdefer l.closeConnection(conn)\n\tstopFunc := context.AfterFunc(localCtx, func() { l.closeConnection(conn) })\n\tdefer stopFunc()\n\n\treader := l.read\n\tif l.Splitter == nil {\n\t\treader = l.readAll\n\t}\n\tif err := reader(conn, onData); err != nil {\n\t\tif !errors.Is(err, io.EOF) && !errors.Is(err, syscall.ECONNRESET) {\n\t\t\tif onError != nil {\n\t\t\t\tonError(err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (l *streamListener) listenConnection(onConnection CallbackConnection, onError CallbackError) {\n\tctx, cancel := context.WithCancel(context.Background())\n\tl.cancel = cancel\n\n\tl.wg.Add(1)\n\tgo func() {\n\t\tdefer l.wg.Done()\n\n\t\tfor {\n\t\t\tconn, err := l.listener.Accept()\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, net.ErrClosed) && onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif allowed, err := isSourceAllowed(l.AllowedSources, conn.RemoteAddr()); err != nil {\n\t\t\t\tif onError != nil {\n\t\t\t\t\tonError(err)\n\t\t\t\t}\n\t\t\t\tif err = conn.Close(); err != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"closing connection from %q failed: %w\", conn.RemoteAddr(), err))\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else if !allowed {\n\t\t\t\tif err = conn.Close(); err != nil {\n\t\t\t\t\tonError(fmt.Errorf(\"closing connection from %q failed: %w\", conn.RemoteAddr(), err))\n\t\t\t\t}\n\t\t\t\tl.Log.Debugf(\"Received message from blocked IP: %s\", conn.RemoteAddr())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := l.setupConnection(conn); err != nil && onError != nil {\n\t\t\t\tonError(err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tl.wg.Add(1)\n\t\t\tgo func(c net.Conn) {\n\t\t\t\tif err := l.handleConnection(ctx, c, onConnection); err != nil {\n\t\t\t\t\tif !errors.Is(err, io.EOF) && !errors.Is(err, syscall.ECONNRESET) {\n\t\t\t\t\t\tif onError != nil {\n\t\t\t\t\t\t\tonError(err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}(conn)\n\t\t}\n\t}()\n}\n\nfunc (l *streamListener) read(conn net.Conn, onData CallbackData) error {\n\tdecoder, err := internal.NewStreamContentDecoder(l.Encoding, conn)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating decoder failed: %w\", err)\n\t}\n\n\ttimeout := time.Duration(l.ReadTimeout)\n\n\tscanner := bufio.NewScanner(decoder)\n\tif l.ReadBufferSize > bufio.MaxScanTokenSize {\n\t\tscanner.Buffer(make([]byte, l.ReadBufferSize), l.ReadBufferSize)\n\t}\n\tscanner.Split(l.Splitter)\n\tfor {\n\t\t// Set the read deadline, if any, then start reading. The read\n\t\t// will accept the deadline and return if no or insufficient data\n\t\t// arrived in time. We need to set the deadline in every cycle as\n\t\t// it is an ABSOLUTE time and not a timeout.\n\t\tif timeout > 0 {\n\t\t\tdeadline := time.Now().Add(timeout)\n\t\t\tif err := conn.SetReadDeadline(deadline); err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting read deadline failed: %w\", err)\n\t\t\t}\n\t\t}\n\t\tif !scanner.Scan() {\n\t\t\t// Exit if no data arrived e.g. due to timeout or closed connection\n\t\t\tbreak\n\t\t}\n\n\t\treceiveTime := time.Now()\n\t\tsrc := conn.RemoteAddr()\n\t\tif l.path != \"\" {\n\t\t\tsrc = &net.UnixAddr{Name: l.path, Net: \"unix\"}\n\t\t}\n\n\t\tdata := scanner.Bytes()\n\t\td := make([]byte, len(data))\n\t\tcopy(d, data)\n\t\tl.parsePool.Submit(func() {\n\t\t\tonData(src, d, receiveTime)\n\t\t})\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\tif errors.Is(err, os.ErrDeadlineExceeded) {\n\t\t\t// Ignore the timeout and silently close the connection\n\t\t\tl.Log.Debug(err)\n\t\t\treturn nil\n\t\t}\n\t\tif errors.Is(err, net.ErrClosed) {\n\t\t\t// Ignore the connection closing of the remote side\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (l *streamListener) readAll(conn net.Conn, onData CallbackData) error {\n\tsrc := conn.RemoteAddr()\n\tif l.path != \"\" {\n\t\tsrc = &net.UnixAddr{Name: l.path, Net: \"unix\"}\n\t}\n\n\tdecoder, err := internal.NewStreamContentDecoder(l.Encoding, conn)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating decoder failed: %w\", err)\n\t}\n\n\ttimeout := time.Duration(l.ReadTimeout)\n\t// Set the read deadline, if any, then start reading. The read\n\t// will accept the deadline and return if no or insufficient data\n\t// arrived in time. We need to set the deadline in every cycle as\n\t// it is an ABSOLUTE time and not a timeout.\n\tif timeout > 0 {\n\t\tdeadline := time.Now().Add(timeout)\n\t\tif err := conn.SetReadDeadline(deadline); err != nil {\n\t\t\treturn fmt.Errorf(\"setting read deadline failed: %w\", err)\n\t\t}\n\t}\n\tbuf, err := io.ReadAll(decoder)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read on %s failed: %w\", src, err)\n\t}\n\n\treceiveTime := time.Now()\n\tl.parsePool.Submit(func() {\n\t\tonData(src, buf, receiveTime)\n\t})\n\n\treturn nil\n}\n\nfunc (l *streamListener) handleConnection(ctx context.Context, conn net.Conn, onConnection CallbackConnection) error {\n\tdefer l.wg.Done()\n\n\tlocalCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\tdefer l.closeConnection(conn)\n\tstopFunc := context.AfterFunc(localCtx, func() { l.closeConnection(conn) })\n\tdefer stopFunc()\n\n\t// Prepare the data decoder for the connection\n\tdecoder, err := internal.NewStreamContentDecoder(l.Encoding, conn)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating decoder failed: %w\", err)\n\t}\n\n\t// Get the remote address\n\tsrc := conn.RemoteAddr()\n\tif l.path != \"\" {\n\t\tsrc = &net.UnixAddr{Name: l.path, Net: \"unix\"}\n\t}\n\n\t// Create a pipe and feed it to the callback\n\treader, writer := io.Pipe()\n\tdefer writer.Close()\n\tgo onConnection(src, reader)\n\n\ttimeout := time.Duration(l.ReadTimeout)\n\tbuf := make([]byte, 4096) // 4kb\n\tfor {\n\t\t// Set the read deadline, if any, then start reading. The read\n\t\t// will accept the deadline and return if no or insufficient data\n\t\t// arrived in time. We need to set the deadline in every cycle as\n\t\t// it is an ABSOLUTE time and not a timeout.\n\t\tif timeout > 0 {\n\t\t\tdeadline := time.Now().Add(timeout)\n\t\t\tif err := conn.SetReadDeadline(deadline); err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting read deadline failed: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// Copy the data\n\t\tn, err := decoder.Read(buf)\n\t\tif err != nil {\n\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\tif !errors.Is(err, os.ErrDeadlineExceeded) && errors.Is(err, net.ErrClosed) {\n\t\t\t\t\twriter.CloseWithError(err)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tif _, err := writer.Write(buf[:n]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/common/starlark/builtins.go",
    "content": "package starlark\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"go.starlark.net/starlark\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nfunc newMetric(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar (\n\t\tname         starlark.String\n\t\ttags, fields starlark.Value\n\t)\n\tif err := starlark.UnpackArgs(\"Metric\", args, kwargs, \"name\", &name, \"tags?\", &tags, \"fields?\", &fields); err != nil {\n\t\treturn nil, err\n\t}\n\n\tallFields, err := toFields(fields)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tallTags, err := toTags(tags)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm := metric.New(string(name), allTags, allFields, time.Now())\n\n\treturn &Metric{metric: m}, nil\n}\n\nfunc toString(value starlark.Value, errorMsg string) (string, error) {\n\tif value, ok := value.(starlark.String); ok {\n\t\treturn string(value), nil\n\t}\n\treturn \"\", fmt.Errorf(errorMsg, value)\n}\n\nfunc items(value starlark.Value, errorMsg string) ([]starlark.Tuple, error) {\n\tif iter, ok := value.(starlark.IterableMapping); ok {\n\t\treturn iter.Items(), nil\n\t}\n\treturn nil, fmt.Errorf(errorMsg, value)\n}\n\nfunc deepcopy(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar sm *Metric\n\tvar track bool\n\tif err := starlark.UnpackArgs(\"deepcopy\", args, kwargs, \"source\", &sm, \"track?\", &track); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// In case we copy a tracking metric but do not want to track the result,\n\t// we have to strip the tracking information. This can be done by unwrapping\n\t// the metric.\n\tif tm, ok := sm.metric.(telegraf.TrackingMetric); ok && !track {\n\t\treturn &Metric{metric: tm.Unwrap().Copy()}, nil\n\t}\n\n\t// Copy the whole metric including potential tracking information\n\treturn &Metric{metric: sm.metric.Copy()}, nil\n}\n\n// catch(f) evaluates f() and returns its evaluation error message\n// if it failed or None if it succeeded.\nfunc catch(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar fn starlark.Callable\n\tif err := starlark.UnpackArgs(\"catch\", args, kwargs, \"fn\", &fn); err != nil {\n\t\treturn nil, err\n\t}\n\tif _, err := starlark.Call(thread, fn, nil, nil); err != nil {\n\t\t//nolint:nilerr // nil returned on purpose, error put inside starlark.Value\n\t\treturn starlark.String(err.Error()), nil\n\t}\n\treturn starlark.None, nil\n}\n\ntype builtinMethod func(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error)\n\nfunc builtinAttr(recv starlark.Value, name string, methods map[string]builtinMethod) (starlark.Value, error) {\n\tmethod := methods[name]\n\tif method == nil {\n\t\treturn starlark.None, fmt.Errorf(\"no such method %q\", name)\n\t}\n\n\t// Allocate a closure over 'method'.\n\timpl := func(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\t\treturn method(b, args, kwargs)\n\t}\n\treturn starlark.NewBuiltin(name, impl).BindReceiver(recv), nil\n}\n\nfunc builtinAttrNames(methods map[string]builtinMethod) []string {\n\tnames := make([]string, 0, len(methods))\n\tfor name := range methods {\n\t\tnames = append(names, name)\n\t}\n\tsort.Strings(names)\n\treturn names\n}\n\n// --- dictionary methods ---\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·clear\nfunc dictClear(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\n\ttype HasClear interface {\n\t\tClear() error\n\t}\n\treturn starlark.None, b.Receiver().(HasClear).Clear()\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·pop\nfunc dictPop(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar k, d starlark.Value\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k, &d); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\n\ttype HasDelete interface {\n\t\tDelete(k starlark.Value) (starlark.Value, bool, error)\n\t}\n\tif v, found, err := b.Receiver().(HasDelete).Delete(k); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err) // dict is frozen or key is unhashable\n\t} else if found {\n\t\treturn v, nil\n\t} else if d != nil {\n\t\treturn d, nil\n\t}\n\treturn starlark.None, fmt.Errorf(\"%s: missing key\", b.Name())\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·popitem\nfunc dictPopitem(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\n\ttype HasPopItem interface {\n\t\tPopItem() (starlark.Value, error)\n\t}\n\treturn b.Receiver().(HasPopItem).PopItem()\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·get\nfunc dictGet(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar key, dflt starlark.Value\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &key, &dflt); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\tif v, ok, err := b.Receiver().(starlark.Mapping).Get(key); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t} else if ok {\n\t\treturn v, nil\n\t} else if dflt != nil {\n\t\treturn dflt, nil\n\t}\n\treturn starlark.None, nil\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·setdefault\nfunc dictSetdefault(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tvar key, dflt starlark.Value = nil, starlark.None\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &key, &dflt); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\n\trecv := b.Receiver().(starlark.HasSetKey)\n\tv, found, err := recv.Get(key)\n\tif err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\tif !found {\n\t\tv = dflt\n\t\tif err := recv.SetKey(key, dflt); err != nil {\n\t\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t\t}\n\t}\n\treturn v, nil\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·update\nfunc dictUpdate(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\t// Unpack the arguments\n\tif len(args) > 1 {\n\t\treturn nil, fmt.Errorf(\"update: got %d arguments, want at most 1\", len(args))\n\t}\n\n\t// Get the target\n\tdict := b.Receiver().(starlark.HasSetKey)\n\n\tif len(args) == 1 {\n\t\tswitch updates := args[0].(type) {\n\t\tcase starlark.IterableMapping:\n\t\t\t// Iterate over dict's key/value pairs, not just keys.\n\t\t\tfor _, item := range updates.Items() {\n\t\t\t\tif err := dict.SetKey(item[0], item[1]); err != nil {\n\t\t\t\t\treturn nil, err // dict is frozen\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\t// all other sequences\n\t\t\titer := starlark.Iterate(updates)\n\t\t\tif iter == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"got %s, want iterable\", updates.Type())\n\t\t\t}\n\t\t\tdefer iter.Done()\n\t\t\tvar pair starlark.Value\n\t\t\tfor i := 0; iter.Next(&pair); i++ {\n\t\t\t\titerErr := func() error {\n\t\t\t\t\titer2 := starlark.Iterate(pair)\n\t\t\t\t\tif iter2 == nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"dictionary update sequence element #%d is not iterable (%s)\", i, pair.Type())\n\t\t\t\t\t}\n\t\t\t\t\tdefer iter2.Done()\n\t\t\t\t\tlength := starlark.Len(pair)\n\t\t\t\t\tif length < 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"dictionary update sequence element #%d has unknown length (%s)\", i, pair.Type())\n\t\t\t\t\t} else if length != 2 {\n\t\t\t\t\t\treturn fmt.Errorf(\"dictionary update sequence element #%d has length %d, want 2\", i, length)\n\t\t\t\t\t}\n\t\t\t\t\tvar k, v starlark.Value\n\t\t\t\t\titer2.Next(&k)\n\t\t\t\t\titer2.Next(&v)\n\n\t\t\t\t\treturn dict.SetKey(k, v)\n\t\t\t\t}()\n\n\t\t\t\tif iterErr != nil {\n\t\t\t\t\treturn nil, iterErr\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Then add the kwargs.\n\tbefore := starlark.Len(dict)\n\tfor _, pair := range kwargs {\n\t\tif err := dict.SetKey(pair[0], pair[1]); err != nil {\n\t\t\treturn nil, err // dict is frozen\n\t\t}\n\t}\n\t// In the common case, each kwarg will add another dict entry.\n\t// If that's not so, check whether it is because there was a duplicate kwarg.\n\tif starlark.Len(dict) < before+len(kwargs) {\n\t\tkeys := make(map[starlark.String]bool, len(kwargs))\n\t\tfor _, kv := range kwargs {\n\t\t\tk := kv[0].(starlark.String)\n\t\t\tif keys[k] {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate keyword arg: %v\", k)\n\t\t\t}\n\t\t\tkeys[k] = true\n\t\t}\n\t}\n\n\treturn starlark.None, nil\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·items\nfunc dictItems(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\titems := b.Receiver().(starlark.IterableMapping).Items()\n\tres := make([]starlark.Value, 0, len(items))\n\tfor _, item := range items {\n\t\tres = append(res, item) // convert [2]starlark.Value to starlark.Value\n\t}\n\treturn starlark.NewList(res), nil\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·keys\nfunc dictKeys(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\n\titems := b.Receiver().(starlark.IterableMapping).Items()\n\tres := make([]starlark.Value, 0, len(items))\n\tfor _, item := range items {\n\t\tres = append(res, item[0])\n\t}\n\treturn starlark.NewList(res), nil\n}\n\n// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·update\nfunc dictValues(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\titems := b.Receiver().(starlark.IterableMapping).Items()\n\tres := make([]starlark.Value, 0, len(items))\n\tfor _, item := range items {\n\t\tres = append(res, item[1])\n\t}\n\treturn starlark.NewList(res), nil\n}\n"
  },
  {
    "path": "plugins/common/starlark/field_dict.go",
    "content": "package starlark\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"go.starlark.net/starlark\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// FieldDict is a starlark.Value for the metric fields.  It is heavily based on the\n// starlark.Dict.\ntype FieldDict struct {\n\t*Metric\n}\n\nfunc (d FieldDict) String() string {\n\tbuf := new(strings.Builder)\n\tbuf.WriteString(\"{\")\n\tsep := \"\"\n\tfor _, item := range d.Items() {\n\t\tk, v := item[0], item[1]\n\t\tbuf.WriteString(sep)\n\t\tbuf.WriteString(k.String())\n\t\tbuf.WriteString(\": \")\n\t\tbuf.WriteString(v.String())\n\t\tsep = \", \"\n\t}\n\tbuf.WriteString(\"}\")\n\treturn buf.String()\n}\n\nfunc (FieldDict) Type() string {\n\treturn \"Fields\"\n}\n\nfunc (d FieldDict) Freeze() {\n\t// Disable linter check as the frozen variable is modified despite\n\t// passing a value instead of a pointer, because `FieldDict` holds\n\t// a pointer to the underlying metric containing the `frozen` field.\n\t//revive:disable:modifies-value-receiver\n\td.frozen = true\n}\n\nfunc (d FieldDict) Truth() starlark.Bool {\n\treturn len(d.metric.FieldList()) != 0\n}\n\nfunc (FieldDict) Hash() (uint32, error) {\n\treturn 0, errors.New(\"not hashable\")\n}\n\n// AttrNames implements the starlark.HasAttrs interface.\nfunc (FieldDict) AttrNames() []string {\n\treturn builtinAttrNames(FieldDictMethods)\n}\n\n// Attr implements the starlark.HasAttrs interface.\nfunc (d FieldDict) Attr(name string) (starlark.Value, error) {\n\treturn builtinAttr(d, name, FieldDictMethods)\n}\n\nvar FieldDictMethods = map[string]builtinMethod{\n\t\"clear\":      dictClear,\n\t\"get\":        dictGet,\n\t\"items\":      dictItems,\n\t\"keys\":       dictKeys,\n\t\"pop\":        dictPop,\n\t\"popitem\":    dictPopitem,\n\t\"setdefault\": dictSetdefault,\n\t\"update\":     dictUpdate,\n\t\"values\":     dictValues,\n}\n\n// Get implements the starlark.Mapping interface.\nfunc (d FieldDict) Get(key starlark.Value) (v starlark.Value, found bool, err error) {\n\tif k, ok := key.(starlark.String); ok {\n\t\tgv, found := d.metric.GetField(k.GoString())\n\t\tif !found {\n\t\t\treturn starlark.None, false, nil\n\t\t}\n\n\t\tv, err := asStarlarkValue(gv)\n\t\tif err != nil {\n\t\t\treturn starlark.None, false, err\n\t\t}\n\t\treturn v, true, nil\n\t}\n\n\treturn starlark.None, false, errors.New(\"key must be of type 'str'\")\n}\n\n// SetKey implements the starlark.HasSetKey interface to support map update\n// using x[k]=v syntax, like a dictionary.\nfunc (d FieldDict) SetKey(k, v starlark.Value) error {\n\tif d.fieldIterCount > 0 {\n\t\treturn errors.New(\"cannot insert during iteration\")\n\t}\n\n\tkey, ok := k.(starlark.String)\n\tif !ok {\n\t\treturn errors.New(\"field key must be of type 'str'\")\n\t}\n\n\tgv, err := asGoValue(v)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.metric.AddField(key.GoString(), gv)\n\treturn nil\n}\n\n// Items implements the starlark.IterableMapping interface.\nfunc (d FieldDict) Items() []starlark.Tuple {\n\titems := make([]starlark.Tuple, 0, len(d.metric.FieldList()))\n\tfor _, field := range d.metric.FieldList() {\n\t\tkey := starlark.String(field.Key)\n\t\tsv, err := asStarlarkValue(field.Value)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tpair := starlark.Tuple{key, sv}\n\t\titems = append(items, pair)\n\t}\n\treturn items\n}\n\nfunc (d FieldDict) Clear() error {\n\tif d.fieldIterCount > 0 {\n\t\treturn errors.New(\"cannot delete during iteration\")\n\t}\n\n\tkeys := make([]string, 0, len(d.metric.FieldList()))\n\tfor _, field := range d.metric.FieldList() {\n\t\tkeys = append(keys, field.Key)\n\t}\n\n\tfor _, key := range keys {\n\t\td.metric.RemoveField(key)\n\t}\n\treturn nil\n}\n\nfunc (d FieldDict) PopItem() (starlark.Value, error) {\n\tif d.fieldIterCount > 0 {\n\t\treturn nil, errors.New(\"cannot delete during iteration\")\n\t}\n\n\tif len(d.metric.FieldList()) == 0 {\n\t\treturn nil, errors.New(\"popitem(): field dictionary is empty\")\n\t}\n\n\tfield := d.metric.FieldList()[0]\n\tk := field.Key\n\tv := field.Value\n\n\td.metric.RemoveField(k)\n\n\tsk := starlark.String(k)\n\tsv, err := asStarlarkValue(v)\n\tif err != nil {\n\t\treturn nil, errors.New(\"could not convert to starlark value\")\n\t}\n\n\treturn starlark.Tuple{sk, sv}, nil\n}\n\nfunc (d FieldDict) Delete(k starlark.Value) (v starlark.Value, found bool, err error) {\n\tif d.fieldIterCount > 0 {\n\t\treturn nil, false, errors.New(\"cannot delete during iteration\")\n\t}\n\n\tif key, ok := k.(starlark.String); ok {\n\t\tvalue, ok := d.metric.GetField(key.GoString())\n\t\tif ok {\n\t\t\td.metric.RemoveField(key.GoString())\n\t\t\tsv, err := asStarlarkValue(value)\n\t\t\treturn sv, ok, err\n\t\t}\n\t\treturn starlark.None, false, nil\n\t}\n\n\treturn starlark.None, false, errors.New(\"key must be of type 'str'\")\n}\n\n// Iterate implements the starlark.Iterator interface.\nfunc (d FieldDict) Iterate() starlark.Iterator {\n\td.fieldIterCount++\n\treturn &FieldIterator{Metric: d.Metric, fields: d.metric.FieldList()}\n}\n\ntype FieldIterator struct {\n\t*Metric\n\tfields []*telegraf.Field\n}\n\n// Next implements the starlark.Iterator interface.\nfunc (i *FieldIterator) Next(p *starlark.Value) bool {\n\tif len(i.fields) == 0 {\n\t\treturn false\n\t}\n\n\tfield := i.fields[0]\n\ti.fields = i.fields[1:]\n\t*p = starlark.String(field.Key)\n\n\treturn true\n}\n\n// Done implements the starlark.Iterator interface.\nfunc (i *FieldIterator) Done() {\n\ti.fieldIterCount--\n}\n\n// AsStarlarkValue converts a field value to a starlark.Value.\nfunc asStarlarkValue(value interface{}) (starlark.Value, error) {\n\tv := reflect.ValueOf(value)\n\tswitch v.Kind() {\n\tcase reflect.Slice:\n\t\tlength := v.Len()\n\t\tarray := make([]starlark.Value, 0, length)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tsVal, err := asStarlarkValue(v.Index(i).Interface())\n\t\t\tif err != nil {\n\t\t\t\treturn starlark.None, err\n\t\t\t}\n\t\t\tarray = append(array, sVal)\n\t\t}\n\t\treturn starlark.NewList(array), nil\n\tcase reflect.Map:\n\t\tdict := starlark.NewDict(v.Len())\n\t\titer := v.MapRange()\n\t\tfor iter.Next() {\n\t\t\tsKey, err := asStarlarkValue(iter.Key().Interface())\n\t\t\tif err != nil {\n\t\t\t\treturn starlark.None, err\n\t\t\t}\n\t\t\tsValue, err := asStarlarkValue(iter.Value().Interface())\n\t\t\tif err != nil {\n\t\t\t\treturn starlark.None, err\n\t\t\t}\n\t\t\tif err := dict.SetKey(sKey, sValue); err != nil {\n\t\t\t\treturn starlark.None, err\n\t\t\t}\n\t\t}\n\t\treturn dict, nil\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn starlark.Float(v.Float()), nil\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn starlark.MakeInt64(v.Int()), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn starlark.MakeUint64(v.Uint()), nil\n\tcase reflect.String:\n\t\treturn starlark.String(v.String()), nil\n\tcase reflect.Bool:\n\t\treturn starlark.Bool(v.Bool()), nil\n\t}\n\n\treturn nil, fmt.Errorf(\"invalid type %T\", value)\n}\n\n// AsGoValue converts a starlark.Value to a field value.\nfunc asGoValue(value interface{}) (interface{}, error) {\n\tswitch v := value.(type) {\n\tcase starlark.Float:\n\t\treturn float64(v), nil\n\tcase starlark.Int:\n\t\tn, ok := v.Int64()\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"cannot represent integer %v as int64\", v)\n\t\t}\n\t\treturn n, nil\n\tcase starlark.String:\n\t\treturn string(v), nil\n\tcase starlark.Bool:\n\t\treturn bool(v), nil\n\t}\n\n\treturn nil, fmt.Errorf(\"invalid starlark type %T\", value)\n}\n\n// ToFields converts a starlark.Value to a map of values.\nfunc toFields(value starlark.Value) (map[string]interface{}, error) {\n\tif value == nil {\n\t\treturn nil, nil\n\t}\n\titems, err := items(value, \"The type %T is unsupported as type of collection of fields\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := make(map[string]interface{}, len(items))\n\tfor _, item := range items {\n\t\tkey, err := toString(item[0], \"The type %T is unsupported as type of key for fields\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvalue, err := asGoValue(item[1])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult[key] = value\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "plugins/common/starlark/logging.go",
    "content": "package starlark\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"go.starlark.net/starlark\"\n\t\"go.starlark.net/starlarkstruct\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// LogModule builds a module that defines all the supported logging functions which will log using the provided logger\nfunc LogModule(logger telegraf.Logger) *starlarkstruct.Module {\n\tvar logFunc = func(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {\n\t\treturn log(b, args, kwargs, logger)\n\t}\n\treturn &starlarkstruct.Module{\n\t\tName: \"log\",\n\t\tMembers: starlark.StringDict{\n\t\t\t\"debug\": starlark.NewBuiltin(\"log.debug\", logFunc),\n\t\t\t\"info\":  starlark.NewBuiltin(\"log.info\", logFunc),\n\t\t\t\"warn\":  starlark.NewBuiltin(\"log.warn\", logFunc),\n\t\t\t\"error\": starlark.NewBuiltin(\"log.error\", logFunc),\n\t\t},\n\t}\n}\n\n// Logs the provided message according to the level chosen\nfunc log(b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple, logger telegraf.Logger) (starlark.Value, error) {\n\tvar msg starlark.String\n\tif err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &msg); err != nil {\n\t\treturn starlark.None, fmt.Errorf(\"%s: %w\", b.Name(), err)\n\t}\n\tswitch b.Name() {\n\tcase \"log.debug\":\n\t\tlogger.Debug(string(msg))\n\tcase \"log.info\":\n\t\tlogger.Info(string(msg))\n\tcase \"log.warn\":\n\t\tlogger.Warn(string(msg))\n\tcase \"log.error\":\n\t\tlogger.Error(string(msg))\n\tdefault:\n\t\treturn nil, errors.New(\"method \" + b.Name() + \" is unknown\")\n\t}\n\treturn starlark.None, nil\n}\n"
  },
  {
    "path": "plugins/common/starlark/metric.go",
    "content": "package starlark\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.starlark.net/starlark\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Metric struct {\n\tID             telegraf.TrackingID\n\tmetric         telegraf.Metric\n\ttagIterCount   int\n\tfieldIterCount int\n\tfrozen         bool\n}\n\n// Wrap updates the starlark.Metric to wrap a new telegraf.Metric.\nfunc (m *Metric) Wrap(metric telegraf.Metric) {\n\tif tm, ok := metric.(telegraf.TrackingMetric); ok {\n\t\tm.ID = tm.TrackingID()\n\t}\n\tm.metric = metric\n\tm.tagIterCount = 0\n\tm.fieldIterCount = 0\n\tm.frozen = false\n}\n\n// Unwrap removes the telegraf.Metric from the startlark.Metric.\nfunc (m *Metric) Unwrap() telegraf.Metric {\n\treturn m.metric\n}\n\n// String returns the starlark representation of the Metric.\n//\n// The String function is called by both the repr() and str() functions, and so\n// it behaves more like the repr function would in Python.\nfunc (m *Metric) String() string {\n\tbuf := new(strings.Builder)\n\tbuf.WriteString(\"Metric(\")\n\tbuf.WriteString(m.Name().String())\n\tbuf.WriteString(\", tags=\")\n\tbuf.WriteString(m.Tags().String())\n\tbuf.WriteString(\", fields=\")\n\tbuf.WriteString(m.Fields().String())\n\tbuf.WriteString(\", time=\")\n\tbuf.WriteString(m.Time().String())\n\tbuf.WriteString(\")\")\n\tif m.ID != 0 {\n\t\tfmt.Fprintf(buf, \"[tracking ID=%v]\", m.ID)\n\t}\n\treturn buf.String()\n}\n\nfunc (*Metric) Type() string {\n\treturn \"Metric\"\n}\n\nfunc (m *Metric) Freeze() {\n\tm.frozen = true\n}\n\nfunc (*Metric) Truth() starlark.Bool {\n\treturn true\n}\n\nfunc (*Metric) Hash() (uint32, error) {\n\treturn 0, errors.New(\"not hashable\")\n}\n\n// AttrNames implements the starlark.HasAttrs interface.\nfunc (*Metric) AttrNames() []string {\n\treturn []string{\"name\", \"tags\", \"fields\", \"time\"}\n}\n\n// Attr implements the starlark.HasAttrs interface.\nfunc (m *Metric) Attr(name string) (starlark.Value, error) {\n\tswitch name {\n\tcase \"name\":\n\t\treturn m.Name(), nil\n\tcase \"tags\":\n\t\treturn m.Tags(), nil\n\tcase \"fields\":\n\t\treturn m.Fields(), nil\n\tcase \"time\":\n\t\treturn m.Time(), nil\n\tdefault:\n\t\t// Returning nil, nil indicates \"no such field or method\"\n\t\treturn nil, nil\n\t}\n}\n\n// SetField implements the starlark.HasSetField interface.\nfunc (m *Metric) SetField(name string, value starlark.Value) error {\n\tif m.frozen {\n\t\treturn errors.New(\"cannot modify frozen metric\")\n\t}\n\n\tswitch name {\n\tcase \"name\":\n\t\treturn m.SetName(value)\n\tcase \"time\":\n\t\treturn m.SetTime(value)\n\tcase \"tags\":\n\t\treturn errors.New(\"cannot set tags\")\n\tcase \"fields\":\n\t\treturn errors.New(\"cannot set fields\")\n\tdefault:\n\t\treturn starlark.NoSuchAttrError(\n\t\t\tfmt.Sprintf(\"cannot assign to field %q\", name))\n\t}\n}\n\nfunc (m *Metric) Name() starlark.String {\n\treturn starlark.String(m.metric.Name())\n}\n\nfunc (m *Metric) SetName(value starlark.Value) error {\n\tif str, ok := value.(starlark.String); ok {\n\t\tm.metric.SetName(str.GoString())\n\t\treturn nil\n\t}\n\n\treturn errors.New(\"type error\")\n}\n\nfunc (m *Metric) Tags() TagDict {\n\treturn TagDict{m}\n}\n\nfunc (m *Metric) Fields() FieldDict {\n\treturn FieldDict{m}\n}\n\nfunc (m *Metric) Time() starlark.Int {\n\treturn starlark.MakeInt64(m.metric.Time().UnixNano())\n}\n\nfunc (m *Metric) SetTime(value starlark.Value) error {\n\tswitch v := value.(type) {\n\tcase starlark.Int:\n\t\tns, ok := v.Int64()\n\t\tif !ok {\n\t\t\treturn errors.New(\"type error: unrepresentable time\")\n\t\t}\n\t\ttm := time.Unix(0, ns)\n\t\tm.metric.SetTime(tm)\n\t\treturn nil\n\tdefault:\n\t\treturn errors.New(\"type error\")\n\t}\n}\n"
  },
  {
    "path": "plugins/common/starlark/starlark.go",
    "content": "package starlark\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"go.starlark.net/lib/json\"\n\t\"go.starlark.net/lib/math\"\n\t\"go.starlark.net/lib/time\"\n\t\"go.starlark.net/starlark\"\n\t\"go.starlark.net/syntax\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype Common struct {\n\tSource    string                 `toml:\"source\"`\n\tScript    string                 `toml:\"script\"`\n\tConstants map[string]interface{} `toml:\"constants\"`\n\n\tLog              telegraf.Logger `toml:\"-\"`\n\tStarlarkLoadFunc func(module string, logger telegraf.Logger) (starlark.StringDict, error)\n\n\tthread     *starlark.Thread\n\tbuiltins   starlark.StringDict\n\tglobals    starlark.StringDict\n\tfunctions  map[string]*starlark.Function\n\tparameters map[string]starlark.Tuple\n\tstate      *starlark.Dict\n}\n\nfunc (s *Common) GetState() interface{} {\n\t// Return the actual byte-type instead of nil allowing the persister\n\t// to guess instantiate variable of the appropriate type\n\tif s.state == nil {\n\t\treturn make([]byte, 0)\n\t}\n\n\t// Convert the starlark dict into a golang dictionary for serialization\n\tstate := make(map[string]interface{}, s.state.Len())\n\titems := s.state.Items()\n\tfor _, item := range items {\n\t\tif len(item) != 2 {\n\t\t\t// We do expect key-value pairs in the state so there should be\n\t\t\t// two items.\n\t\t\ts.Log.Errorf(\"state item %+v does not contain a key-value pair\", item)\n\t\t\tcontinue\n\t\t}\n\t\tk, ok := item.Index(0).(starlark.String)\n\t\tif !ok {\n\t\t\ts.Log.Errorf(\"state item %+v has invalid key type %T\", item, item.Index(0))\n\t\t\tcontinue\n\t\t}\n\t\tv, err := asGoValue(item.Index(1))\n\t\tif err != nil {\n\t\t\ts.Log.Errorf(\"state item %+v value cannot be converted: %v\", item, err)\n\t\t\tcontinue\n\t\t}\n\t\tstate[k.GoString()] = v\n\t}\n\n\t// Do a binary GOB encoding to preserve types\n\tvar buf bytes.Buffer\n\tif err := gob.NewEncoder(&buf).Encode(state); err != nil {\n\t\ts.Log.Errorf(\"encoding state failed: %v\", err)\n\t\treturn make([]byte, 0)\n\t}\n\n\treturn buf.Bytes()\n}\n\nfunc (s *Common) SetState(state interface{}) error {\n\tdata, ok := state.([]byte)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T for state\", state)\n\t}\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\n\t// Decode the binary GOB encoding\n\tvar dict map[string]interface{}\n\tif err := gob.NewDecoder(bytes.NewBuffer(data)).Decode(&dict); err != nil {\n\t\treturn fmt.Errorf(\"decoding state failed: %w\", err)\n\t}\n\n\t// Convert the golang dict back to starlark types\n\ts.state = starlark.NewDict(len(dict))\n\tfor k, v := range dict {\n\t\tsv, err := asStarlarkValue(v)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"value %v of state item %q cannot be set: %w\", v, k, err)\n\t\t}\n\t\tif err := s.state.SetKey(starlark.String(k), sv); err != nil {\n\t\t\treturn fmt.Errorf(\"state item %q cannot be set: %w\", k, err)\n\t\t}\n\t}\n\ts.builtins[\"state\"] = s.state\n\n\treturn s.InitProgram()\n}\n\nfunc (s *Common) Init() error {\n\tif s.Source == \"\" && s.Script == \"\" {\n\t\treturn errors.New(\"one of source or script must be set\")\n\t}\n\tif s.Source != \"\" && s.Script != \"\" {\n\t\treturn errors.New(\"both source or script cannot be set\")\n\t}\n\n\ts.builtins = starlark.StringDict{}\n\ts.builtins[\"Metric\"] = starlark.NewBuiltin(\"Metric\", newMetric)\n\ts.builtins[\"deepcopy\"] = starlark.NewBuiltin(\"deepcopy\", deepcopy)\n\ts.builtins[\"catch\"] = starlark.NewBuiltin(\"catch\", catch)\n\n\tif err := s.addConstants(&s.builtins); err != nil {\n\t\treturn err\n\t}\n\n\t// Initialize the program\n\tif err := s.InitProgram(); err != nil {\n\t\t// Try again with a declared state. This might be necessary for\n\t\t// state persistence.\n\t\ts.state = starlark.NewDict(0)\n\t\ts.builtins[\"state\"] = s.state\n\t\tif serr := s.InitProgram(); serr != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\ts.functions = make(map[string]*starlark.Function)\n\ts.parameters = make(map[string]starlark.Tuple)\n\n\treturn nil\n}\n\nfunc (s *Common) InitProgram() error {\n\t// Load the program. In case of an error we can try to insert the state\n\t// which can be used implicitly e.g. when persisting states\n\tprogram, err := s.sourceProgram(s.builtins)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Execute source\n\ts.thread = &starlark.Thread{\n\t\tPrint: func(_ *starlark.Thread, msg string) { s.Log.Debug(msg) },\n\t\tLoad: func(_ *starlark.Thread, module string) (starlark.StringDict, error) {\n\t\t\treturn s.StarlarkLoadFunc(module, s.Log)\n\t\t},\n\t}\n\tglobals, err := program.Init(s.thread, s.builtins)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// In case the program declares a global \"state\" we should insert it to\n\t// avoid warnings about inserting into a frozen variable\n\tif _, found := globals[\"state\"]; found {\n\t\tglobals[\"state\"] = starlark.NewDict(0)\n\t}\n\n\t// Freeze the global state. This prevents modifications to the processor\n\t// state and prevents scripts from containing errors storing tracking\n\t// metrics. Tasks that require global state will not be possible due to\n\t// this, so maybe we should relax this in the future.\n\tglobals.Freeze()\n\ts.globals = globals\n\n\treturn nil\n}\n\nfunc (s *Common) GetParameters(name string) (starlark.Tuple, bool) {\n\tparameters, found := s.parameters[name]\n\treturn parameters, found\n}\n\nfunc (s *Common) AddFunction(name string, params ...starlark.Value) error {\n\tglobalFn, found := s.globals[name]\n\tif !found {\n\t\treturn fmt.Errorf(\"%s is not defined\", name)\n\t}\n\n\tfn, found := globalFn.(*starlark.Function)\n\tif !found {\n\t\treturn fmt.Errorf(\"%s is not a function\", name)\n\t}\n\n\tif fn.NumParams() != len(params) {\n\t\treturn fmt.Errorf(\"%s function must take %d parameter(s)\", name, len(params))\n\t}\n\tp := make(starlark.Tuple, len(params))\n\tcopy(p, params)\n\n\ts.functions[name] = fn\n\ts.parameters[name] = params\n\treturn nil\n}\n\n// Add all the constants defined in the plugin as constants of the script\nfunc (s *Common) addConstants(builtins *starlark.StringDict) error {\n\tfor key, val := range s.Constants {\n\t\tif key == \"state\" {\n\t\t\treturn errors.New(\"'state' constant uses reserved name\")\n\t\t}\n\t\tsVal, err := asStarlarkValue(val)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting type %T failed: %w\", val, err)\n\t\t}\n\t\t(*builtins)[key] = sVal\n\t}\n\treturn nil\n}\n\nfunc (s *Common) sourceProgram(builtins starlark.StringDict) (*starlark.Program, error) {\n\tvar src interface{}\n\tif s.Source != \"\" {\n\t\tsrc = s.Source\n\t}\n\n\t// AllowFloat - obsolete, no effect\n\t// AllowNestedDef - always on https://github.com/google/starlark-go/pull/328\n\t// AllowLambda - always on https://github.com/google/starlark-go/pull/328\n\toptions := syntax.FileOptions{\n\t\tRecursion:      true,\n\t\tGlobalReassign: true,\n\t\tSet:            true,\n\t}\n\n\t_, program, err := starlark.SourceProgramOptions(&options, s.Script, src, builtins.Has)\n\treturn program, err\n}\n\n// Call calls the function corresponding to the given name.\nfunc (s *Common) Call(name string) (starlark.Value, error) {\n\tfn, ok := s.functions[name]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"function %q does not exist\", name)\n\t}\n\targs, ok := s.parameters[name]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"params for function %q do not exist\", name)\n\t}\n\treturn starlark.Call(s.thread, fn, args, nil)\n}\n\nfunc (s *Common) LogError(err error) {\n\tvar evalErr *starlark.EvalError\n\tif errors.As(err, &evalErr) {\n\t\tfor _, line := range strings.Split(evalErr.Backtrace(), \"\\n\") {\n\t\t\ts.Log.Error(line)\n\t\t}\n\t} else {\n\t\ts.Log.Error(err)\n\t}\n}\n\nfunc LoadFunc(module string, logger telegraf.Logger) (starlark.StringDict, error) {\n\tswitch module {\n\tcase \"json.star\":\n\t\treturn starlark.StringDict{\n\t\t\t\"json\": json.Module,\n\t\t}, nil\n\tcase \"logging.star\":\n\t\treturn starlark.StringDict{\n\t\t\t\"log\": LogModule(logger),\n\t\t}, nil\n\tcase \"math.star\":\n\t\treturn starlark.StringDict{\n\t\t\t\"math\": math.Module,\n\t\t}, nil\n\tcase \"time.star\":\n\t\treturn starlark.StringDict{\n\t\t\t\"time\": time.Module,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, errors.New(\"module \" + module + \" is not available\")\n\t}\n}\n"
  },
  {
    "path": "plugins/common/starlark/tag_dict.go",
    "content": "package starlark\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"go.starlark.net/starlark\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// TagDict is a starlark.Value for the metric tags.  It is heavily based on the\n// starlark.Dict.\ntype TagDict struct {\n\t*Metric\n}\n\nfunc (d TagDict) String() string {\n\tbuf := new(strings.Builder)\n\tbuf.WriteString(\"{\")\n\tsep := \"\"\n\tfor _, item := range d.Items() {\n\t\tk, v := item[0], item[1]\n\t\tbuf.WriteString(sep)\n\t\tbuf.WriteString(k.String())\n\t\tbuf.WriteString(\": \")\n\t\tbuf.WriteString(v.String())\n\t\tsep = \", \"\n\t}\n\tbuf.WriteString(\"}\")\n\treturn buf.String()\n}\n\nfunc (TagDict) Type() string {\n\treturn \"Tags\"\n}\n\nfunc (d TagDict) Freeze() {\n\t// Disable linter check as the frozen variable is modified despite\n\t// passing a value instead of a pointer, because `TagDict` holds\n\t// a pointer to the underlying metric containing the `frozen` field.\n\t//revive:disable:modifies-value-receiver\n\td.frozen = true\n}\n\nfunc (d TagDict) Truth() starlark.Bool {\n\treturn len(d.metric.TagList()) != 0\n}\n\nfunc (TagDict) Hash() (uint32, error) {\n\treturn 0, errors.New(\"not hashable\")\n}\n\n// AttrNames implements the starlark.HasAttrs interface.\nfunc (TagDict) AttrNames() []string {\n\treturn builtinAttrNames(TagDictMethods)\n}\n\n// Attr implements the starlark.HasAttrs interface.\nfunc (d TagDict) Attr(name string) (starlark.Value, error) {\n\treturn builtinAttr(d, name, TagDictMethods)\n}\n\nvar TagDictMethods = map[string]builtinMethod{\n\t\"clear\":      dictClear,\n\t\"get\":        dictGet,\n\t\"items\":      dictItems,\n\t\"keys\":       dictKeys,\n\t\"pop\":        dictPop,\n\t\"popitem\":    dictPopitem,\n\t\"setdefault\": dictSetdefault,\n\t\"update\":     dictUpdate,\n\t\"values\":     dictValues,\n}\n\n// Get implements the starlark.Mapping interface.\nfunc (d TagDict) Get(key starlark.Value) (v starlark.Value, found bool, err error) {\n\tif k, ok := key.(starlark.String); ok {\n\t\tgv, found := d.metric.GetTag(k.GoString())\n\t\tif !found {\n\t\t\treturn starlark.None, false, nil\n\t\t}\n\t\treturn starlark.String(gv), true, err\n\t}\n\n\treturn starlark.None, false, errors.New(\"key must be of type 'str'\")\n}\n\n// SetKey implements the starlark.HasSetKey interface to support map update\n// using x[k]=v syntax, like a dictionary.\nfunc (d TagDict) SetKey(k, v starlark.Value) error {\n\tif d.tagIterCount > 0 {\n\t\treturn errors.New(\"cannot insert during iteration\")\n\t}\n\n\tkey, ok := k.(starlark.String)\n\tif !ok {\n\t\treturn errors.New(\"tag key must be of type 'str'\")\n\t}\n\n\tvalue, ok := v.(starlark.String)\n\tif !ok {\n\t\treturn errors.New(\"tag value must be of type 'str'\")\n\t}\n\n\td.metric.AddTag(key.GoString(), value.GoString())\n\treturn nil\n}\n\n// Items implements the starlark.IterableMapping interface.\nfunc (d TagDict) Items() []starlark.Tuple {\n\titems := make([]starlark.Tuple, 0, len(d.metric.TagList()))\n\tfor _, tag := range d.metric.TagList() {\n\t\tkey := starlark.String(tag.Key)\n\t\tvalue := starlark.String(tag.Value)\n\t\tpair := starlark.Tuple{key, value}\n\t\titems = append(items, pair)\n\t}\n\treturn items\n}\n\nfunc (d TagDict) Clear() error {\n\tif d.tagIterCount > 0 {\n\t\treturn errors.New(\"cannot delete during iteration\")\n\t}\n\n\tkeys := make([]string, 0, len(d.metric.TagList()))\n\tfor _, tag := range d.metric.TagList() {\n\t\tkeys = append(keys, tag.Key)\n\t}\n\n\tfor _, key := range keys {\n\t\td.metric.RemoveTag(key)\n\t}\n\treturn nil\n}\n\nfunc (d TagDict) PopItem() (v starlark.Value, err error) {\n\tif d.tagIterCount > 0 {\n\t\treturn nil, errors.New(\"cannot delete during iteration\")\n\t}\n\n\tfor _, tag := range d.metric.TagList() {\n\t\tk := tag.Key\n\t\tv := tag.Value\n\n\t\td.metric.RemoveTag(k)\n\n\t\tsk := starlark.String(k)\n\t\tsv := starlark.String(v)\n\t\treturn starlark.Tuple{sk, sv}, nil\n\t}\n\n\treturn nil, errors.New(\"popitem(): tag dictionary is empty\")\n}\n\nfunc (d TagDict) Delete(k starlark.Value) (v starlark.Value, found bool, err error) {\n\tif d.tagIterCount > 0 {\n\t\treturn nil, false, errors.New(\"cannot delete during iteration\")\n\t}\n\n\tif key, ok := k.(starlark.String); ok {\n\t\tvalue, ok := d.metric.GetTag(key.GoString())\n\t\tif ok {\n\t\t\td.metric.RemoveTag(key.GoString())\n\t\t\tv := starlark.String(value)\n\t\t\treturn v, ok, err\n\t\t}\n\t\treturn starlark.None, false, nil\n\t}\n\n\treturn starlark.None, false, errors.New(\"key must be of type 'str'\")\n}\n\n// Iterate implements the starlark.Iterator interface.\nfunc (d TagDict) Iterate() starlark.Iterator {\n\td.tagIterCount++\n\treturn &TagIterator{Metric: d.Metric, tags: d.metric.TagList()}\n}\n\ntype TagIterator struct {\n\t*Metric\n\ttags []*telegraf.Tag\n}\n\n// Next implements the starlark.Iterator interface.\nfunc (i *TagIterator) Next(p *starlark.Value) bool {\n\tif len(i.tags) == 0 {\n\t\treturn false\n\t}\n\n\ttag := i.tags[0]\n\ti.tags = i.tags[1:]\n\t*p = starlark.String(tag.Key)\n\n\treturn true\n}\n\n// Done implements the starlark.Iterator interface.\nfunc (i *TagIterator) Done() {\n\ti.tagIterCount--\n}\n\n// ToTags converts a starlark.Value to a map of string.\nfunc toTags(value starlark.Value) (map[string]string, error) {\n\tif value == nil {\n\t\treturn nil, nil\n\t}\n\titems, err := items(value, \"The type %T is unsupported as type of collection of tags\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := make(map[string]string, len(items))\n\tfor _, item := range items {\n\t\tkey, err := toString(item[0], \"The type %T is unsupported as type of key for tags\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvalue, err := toString(item[1], \"The type %T is unsupported as type of value for tags\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult[key] = value\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "plugins/common/tls/client.conf",
    "content": "  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "plugins/common/tls/common.go",
    "content": "package tls\n\nimport (\n\t\"crypto/tls\"\n\t\"sync\"\n)\n\nvar tlsVersionMap = map[string]uint16{\n\t\"TLS10\": tls.VersionTLS10,\n\t\"TLS11\": tls.VersionTLS11,\n\t\"TLS12\": tls.VersionTLS12,\n\t\"TLS13\": tls.VersionTLS13,\n}\n\nvar tlsCipherMapInit sync.Once\nvar tlsCipherMapSecure map[string]uint16\nvar tlsCipherMapInsecure map[string]uint16\n\nfunc init() {\n\ttlsCipherMapInit.Do(func() {\n\t\t// Initialize the secure suites\n\t\tsuites := tls.CipherSuites()\n\t\ttlsCipherMapSecure = make(map[string]uint16, len(suites))\n\t\tfor _, s := range suites {\n\t\t\ttlsCipherMapSecure[s.Name] = s.ID\n\t\t}\n\n\t\tsuites = tls.InsecureCipherSuites()\n\t\ttlsCipherMapInsecure = make(map[string]uint16, len(suites))\n\t\tfor _, s := range suites {\n\t\t\ttlsCipherMapInsecure[s.Name] = s.ID\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/common/tls/config.go",
    "content": "package tls\n\nimport (\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"go.step.sm/crypto/pemutil\"\n\n\t\"github.com/influxdata/telegraf/internal/choice\"\n)\n\nconst TLSMinVersionDefault = tls.VersionTLS12\n\n// ClientConfig represents the standard client TLS config.\ntype ClientConfig struct {\n\tTLSCA               string   `toml:\"tls_ca\"`\n\tTLSCert             string   `toml:\"tls_cert\"`\n\tTLSKey              string   `toml:\"tls_key\"`\n\tTLSKeyPwd           string   `toml:\"tls_key_pwd\"`\n\tTLSMinVersion       string   `toml:\"tls_min_version\"`\n\tTLSCipherSuites     []string `toml:\"tls_cipher_suites\"`\n\tInsecureSkipVerify  bool     `toml:\"insecure_skip_verify\"`\n\tServerName          string   `toml:\"tls_server_name\"`\n\tRenegotiationMethod string   `toml:\"tls_renegotiation_method\"`\n\tEnable              *bool    `toml:\"tls_enable\"`\n}\n\n// ServerConfig represents the standard server TLS config.\ntype ServerConfig struct {\n\tTLSCert            string   `toml:\"tls_cert\"`\n\tTLSKey             string   `toml:\"tls_key\"`\n\tTLSKeyPwd          string   `toml:\"tls_key_pwd\"`\n\tTLSAllowedCACerts  []string `toml:\"tls_allowed_cacerts\"`\n\tTLSCipherSuites    []string `toml:\"tls_cipher_suites\"`\n\tTLSMinVersion      string   `toml:\"tls_min_version\"`\n\tTLSMaxVersion      string   `toml:\"tls_max_version\"`\n\tTLSAllowedDNSNames []string `toml:\"tls_allowed_dns_names\"`\n}\n\n// TLSConfig returns a tls.Config, may be nil without error if TLS is not\n// configured.\nfunc (c *ClientConfig) TLSConfig() (*tls.Config, error) {\n\t// Check if TLS config is forcefully disabled\n\tif c.Enable != nil && !*c.Enable {\n\t\treturn nil, nil\n\t}\n\n\t// This check returns a nil (aka \"disabled\") or an empty config\n\t// (aka, \"use the default\") if no field is set that would have an effect on\n\t// a TLS connection. That is, any of:\n\t//     * client certificate settings,\n\t//     * peer certificate authorities,\n\t//     * disabled security,\n\t//     * an SNI server name, or\n\t//     * empty/never renegotiation method\n\tempty := c.TLSCA == \"\" && c.TLSKey == \"\" && c.TLSCert == \"\"\n\tempty = empty && !c.InsecureSkipVerify && c.ServerName == \"\"\n\tempty = empty && (c.RenegotiationMethod == \"\" || c.RenegotiationMethod == \"never\")\n\n\tif empty {\n\t\t// Check if TLS config is forcefully enabled and supposed to\n\t\t// use the system defaults.\n\t\tif c.Enable != nil && *c.Enable {\n\t\t\treturn &tls.Config{}, nil\n\t\t}\n\n\t\treturn nil, nil\n\t}\n\n\tvar renegotiationMethod tls.RenegotiationSupport\n\tswitch c.RenegotiationMethod {\n\tcase \"\", \"never\":\n\t\trenegotiationMethod = tls.RenegotiateNever\n\tcase \"once\":\n\t\trenegotiationMethod = tls.RenegotiateOnceAsClient\n\tcase \"freely\":\n\t\trenegotiationMethod = tls.RenegotiateFreelyAsClient\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unrecognized renegotiation method %q, choose from: 'never', 'once', 'freely'\", c.RenegotiationMethod)\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tInsecureSkipVerify: c.InsecureSkipVerify,\n\t\tRenegotiation:      renegotiationMethod,\n\t}\n\n\tif c.TLSCA != \"\" {\n\t\tpool, err := makeCertPool([]string{c.TLSCA})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttlsConfig.RootCAs = pool\n\t}\n\n\tif c.TLSCert != \"\" && c.TLSKey != \"\" {\n\t\terr := loadCertificate(tlsConfig, c.TLSCert, c.TLSKey, c.TLSKeyPwd)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Explicitly and consistently set the minimal accepted version using the\n\t// defined default. We use this setting for both clients and servers\n\t// instead of relying on Golang's default that is different for clients\n\t// and servers and might change over time.\n\ttlsConfig.MinVersion = TLSMinVersionDefault\n\tif c.TLSMinVersion != \"\" {\n\t\tversion, err := ParseTLSVersion(c.TLSMinVersion)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse tls min version %q: %w\", c.TLSMinVersion, err)\n\t\t}\n\t\ttlsConfig.MinVersion = version\n\t}\n\n\tif c.ServerName != \"\" {\n\t\ttlsConfig.ServerName = c.ServerName\n\t}\n\n\tif len(c.TLSCipherSuites) != 0 {\n\t\tcipherSuites, err := ParseCiphers(c.TLSCipherSuites)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse client cipher suites: %w\", err)\n\t\t}\n\t\ttlsConfig.CipherSuites = cipherSuites\n\t}\n\n\treturn tlsConfig, nil\n}\n\n// TLSConfig returns a tls.Config, may be nil without error if TLS is not\n// configured.\nfunc (c *ServerConfig) TLSConfig() (*tls.Config, error) {\n\tif c.TLSCert == \"\" && c.TLSKey == \"\" && len(c.TLSAllowedCACerts) == 0 {\n\t\treturn nil, nil\n\t}\n\n\ttlsConfig := &tls.Config{}\n\n\tif len(c.TLSAllowedCACerts) != 0 {\n\t\tpool, err := makeCertPool(c.TLSAllowedCACerts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttlsConfig.ClientCAs = pool\n\t\ttlsConfig.ClientAuth = tls.RequireAndVerifyClientCert\n\t}\n\n\tif c.TLSCert != \"\" && c.TLSKey != \"\" {\n\t\terr := loadCertificate(tlsConfig, c.TLSCert, c.TLSKey, c.TLSKeyPwd)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif len(c.TLSCipherSuites) != 0 {\n\t\tcipherSuites, err := ParseCiphers(c.TLSCipherSuites)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse server cipher suites: %w\", err)\n\t\t}\n\t\ttlsConfig.CipherSuites = cipherSuites\n\t}\n\n\tif c.TLSMaxVersion != \"\" {\n\t\tversion, err := ParseTLSVersion(c.TLSMaxVersion)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"could not parse tls max version %q: %w\", c.TLSMaxVersion, err)\n\t\t}\n\t\ttlsConfig.MaxVersion = version\n\t}\n\n\t// Explicitly and consistently set the minimal accepted version using the\n\t// defined default. We use this setting for both clients and servers\n\t// instead of relying on Golang's default that is different for clients\n\t// and servers and might change over time.\n\ttlsConfig.MinVersion = TLSMinVersionDefault\n\tif c.TLSMinVersion != \"\" {\n\t\tversion, err := ParseTLSVersion(c.TLSMinVersion)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse tls min version %q: %w\", c.TLSMinVersion, err)\n\t\t}\n\t\ttlsConfig.MinVersion = version\n\t}\n\n\tif tlsConfig.MinVersion != 0 && tlsConfig.MaxVersion != 0 && tlsConfig.MinVersion > tlsConfig.MaxVersion {\n\t\treturn nil, fmt.Errorf(\"tls min version %q can't be greater than tls max version %q\", tlsConfig.MinVersion, tlsConfig.MaxVersion)\n\t}\n\n\t// Since clientAuth is tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert\n\t// there must be certs to validate.\n\tif len(c.TLSAllowedCACerts) > 0 && len(c.TLSAllowedDNSNames) > 0 {\n\t\ttlsConfig.VerifyPeerCertificate = c.verifyPeerCertificate\n\t}\n\n\treturn tlsConfig, nil\n}\n\nfunc makeCertPool(certFiles []string) (*x509.CertPool, error) {\n\tpool := x509.NewCertPool()\n\tfor _, certFile := range certFiles {\n\t\tcert, err := os.ReadFile(certFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not read certificate %q: %w\", certFile, err)\n\t\t}\n\t\tif !pool.AppendCertsFromPEM(cert) {\n\t\t\treturn nil, fmt.Errorf(\"could not parse any PEM certificates %q: %w\", certFile, err)\n\t\t}\n\t}\n\treturn pool, nil\n}\n\nfunc loadCertificate(config *tls.Config, certFile, keyFile, privateKeyPassphrase string) error {\n\tcertBytes, err := os.ReadFile(certFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not load certificate %q: %w\", certFile, err)\n\t}\n\n\tkeyBytes, err := os.ReadFile(keyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not load private key %q: %w\", keyFile, err)\n\t}\n\n\tkeyPEMBlock, _ := pem.Decode(keyBytes)\n\tif keyPEMBlock == nil {\n\t\treturn errors.New(\"failed to decode private key: no PEM data found\")\n\t}\n\n\tvar cert tls.Certificate\n\tif keyPEMBlock.Type == \"ENCRYPTED PRIVATE KEY\" {\n\t\tif privateKeyPassphrase == \"\" {\n\t\t\treturn errors.New(\"missing password for PKCS#8 encrypted private key\")\n\t\t}\n\t\trawDecryptedKey, err := pemutil.DecryptPKCS8PrivateKey(keyPEMBlock.Bytes, []byte(privateKeyPassphrase))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decrypt PKCS#8 private key: %w\", err)\n\t\t}\n\t\tdecryptedKey, err := x509.ParsePKCS8PrivateKey(rawDecryptedKey)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse decrypted PKCS#8 private key: %w\", err)\n\t\t}\n\t\tprivateKey, ok := decryptedKey.(*rsa.PrivateKey)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"decrypted key is not a RSA private key: %T\", decryptedKey)\n\t\t}\n\t\tcert, err = tls.X509KeyPair(certBytes, pem.EncodeToMemory(&pem.Block{Type: keyPEMBlock.Type, Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load cert/key pair: %w\", err)\n\t\t}\n\t} else if keyPEMBlock.Headers[\"Proc-Type\"] == \"4,ENCRYPTED\" {\n\t\t// The key is an encrypted private key with the DEK-Info header.\n\t\t// This is currently unsupported because of the deprecation of x509.IsEncryptedPEMBlock and x509.DecryptPEMBlock.\n\t\treturn errors.New(\"password-protected keys in pkcs#1 format are not supported\")\n\t} else {\n\t\tcert, err = tls.X509KeyPair(certBytes, keyBytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load cert/key pair: %w\", err)\n\t\t}\n\t}\n\tconfig.Certificates = []tls.Certificate{cert}\n\treturn nil\n}\n\nfunc (c *ServerConfig) verifyPeerCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {\n\t// The certificate chain is client + intermediate + root.\n\t// Let's review the client certificate.\n\tcert, err := x509.ParseCertificate(rawCerts[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not validate peer certificate: %w\", err)\n\t}\n\n\tfor _, name := range cert.DNSNames {\n\t\tif choice.Contains(name, c.TLSAllowedDNSNames) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"peer certificate not in allowed DNS Name list: %v\", cert.DNSNames)\n}\n"
  },
  {
    "path": "plugins/common/tls/config_test.go",
    "content": "package tls_test\n\nimport (\n\tcryptotls \"crypto/tls\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar pki = testutil.NewPKI(\"../../../testutil/pki\")\n\nfunc TestClientConfig(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tclient tls.ClientConfig\n\t\texpNil bool\n\t\texpErr bool\n\t}{\n\t\t{\n\t\t\tname:   \"unset\",\n\t\t\tclient: tls.ClientConfig{},\n\t\t\texpNil: true,\n\t\t},\n\t\t{\n\t\t\tname: \"success\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientKeyPath(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"success with tls key password set\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:     pki.CACertPath(),\n\t\t\t\tTLSCert:   pki.ClientCertPath(),\n\t\t\t\tTLSKey:    pki.ClientKeyPath(),\n\t\t\t\tTLSKeyPwd: \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"success with unencrypted pkcs#8 key\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientPKCS8KeyPath(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"encrypted pkcs#8 key but missing password\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientEncPKCS8KeyPath(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"encrypted pkcs#8 key and incorrect password\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:     pki.CACertPath(),\n\t\t\t\tTLSCert:   pki.ClientCertPath(),\n\t\t\t\tTLSKey:    pki.ClientEncPKCS8KeyPath(),\n\t\t\t\tTLSKeyPwd: \"incorrect\",\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"success with encrypted pkcs#8 key and password set\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:     pki.CACertPath(),\n\t\t\t\tTLSCert:   pki.ClientCertPath(),\n\t\t\t\tTLSKey:    pki.ClientEncPKCS8KeyPath(),\n\t\t\t\tTLSKeyPwd: \"changeme\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"error with encrypted pkcs#1 key and password set\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:     pki.CACertPath(),\n\t\t\t\tTLSCert:   pki.ClientCertPath(),\n\t\t\t\tTLSKey:    pki.ClientEncKeyPath(),\n\t\t\t\tTLSKeyPwd: \"changeme\",\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\n\t\t{\n\t\t\tname: \"invalid ca\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.ClientKeyPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientKeyPath(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"missing ca is okay\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientKeyPath(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid cert\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientKeyPath(),\n\t\t\t\tTLSKey:  pki.ClientKeyPath(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"missing cert skips client keypair\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:  pki.CACertPath(),\n\t\t\t\tTLSKey: pki.ClientKeyPath(),\n\t\t\t},\n\t\t\texpNil: false,\n\t\t\texpErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"missing key skips client keypair\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t},\n\t\t\texpNil: false,\n\t\t\texpErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"set SNI server name\",\n\t\t\tclient: tls.ClientConfig{\n\t\t\t\tServerName: \"foo.example.com\",\n\t\t\t},\n\t\t\texpNil: false,\n\t\t\texpErr: false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttlsConfig, err := tt.client.TLSConfig()\n\t\t\tif !tt.expNil {\n\t\t\t\trequire.NotNil(t, tlsConfig)\n\t\t\t} else {\n\t\t\t\trequire.Nil(t, tlsConfig)\n\t\t\t}\n\n\t\t\tif !tt.expErr {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestServerConfig(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tserver tls.ServerConfig\n\t\texpNil bool\n\t\texpErr bool\n\t}{\n\t\t{\n\t\t\tname:   \"unset\",\n\t\t\tserver: tls.ServerConfig{},\n\t\t\texpNil: true,\n\t\t},\n\t\t{\n\t\t\tname: \"success\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:            pki.ServerCertPath(),\n\t\t\t\tTLSKey:             pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts:  []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:    []string{pki.CipherSuite()},\n\t\t\t\tTLSAllowedDNSNames: []string{\"localhost\", \"127.0.0.1\"},\n\t\t\t\tTLSMinVersion:      pki.TLSMinVersion(),\n\t\t\t\tTLSMaxVersion:      pki.TLSMaxVersion(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"success with tls key password set\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSKeyPwd:         \"\",\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t\tTLSMinVersion:     pki.TLSMinVersion(),\n\t\t\t\tTLSMaxVersion:     pki.TLSMaxVersion(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"missing tls cipher suites is okay\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"missing tls max version is okay\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t\tTLSMaxVersion:     pki.TLSMaxVersion(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"missing tls min version is okay\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t\tTLSMinVersion:     pki.TLSMinVersion(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"missing tls min/max versions is okay\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid ca\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.ServerKeyPath()},\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"missing allowed ca is okay\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert: pki.ServerCertPath(),\n\t\t\t\tTLSKey:  pki.ServerKeyPath(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid cert\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerKeyPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"missing cert\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"missing key\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid cipher suites\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CACertPath()},\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"TLS Max Version less than TLS Min version\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CACertPath()},\n\t\t\t\tTLSMinVersion:     pki.TLSMaxVersion(),\n\t\t\t\tTLSMaxVersion:     pki.TLSMinVersion(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid tls min version\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CipherSuite()},\n\t\t\t\tTLSMinVersion:     pki.ServerKeyPath(),\n\t\t\t\tTLSMaxVersion:     pki.TLSMaxVersion(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid tls max version\",\n\t\t\tserver: tls.ServerConfig{\n\t\t\t\tTLSCert:           pki.ServerCertPath(),\n\t\t\t\tTLSKey:            pki.ServerKeyPath(),\n\t\t\t\tTLSAllowedCACerts: []string{pki.CACertPath()},\n\t\t\t\tTLSCipherSuites:   []string{pki.CACertPath()},\n\t\t\t\tTLSMinVersion:     pki.TLSMinVersion(),\n\t\t\t\tTLSMaxVersion:     pki.ServerCertPath(),\n\t\t\t},\n\t\t\texpNil: true,\n\t\t\texpErr: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttlsConfig, err := tt.server.TLSConfig()\n\t\t\tif !tt.expNil {\n\t\t\t\trequire.NotNil(t, tlsConfig)\n\t\t\t}\n\t\t\tif !tt.expErr {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestConnect(t *testing.T) {\n\tclientConfig := tls.ClientConfig{\n\t\tTLSCA:   pki.CACertPath(),\n\t\tTLSCert: pki.ClientCertPath(),\n\t\tTLSKey:  pki.ClientKeyPath(),\n\t}\n\n\tserverConfig := tls.ServerConfig{\n\t\tTLSCert:            pki.ServerCertPath(),\n\t\tTLSKey:             pki.ServerKeyPath(),\n\t\tTLSAllowedCACerts:  []string{pki.CACertPath()},\n\t\tTLSAllowedDNSNames: []string{\"localhost\", \"127.0.0.1\"},\n\t}\n\n\tserverTLSConfig, err := serverConfig.TLSConfig()\n\trequire.NoError(t, err)\n\n\tts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tts.TLS = serverTLSConfig\n\n\tts.StartTLS()\n\tdefer ts.Close()\n\n\tclientTLSConfig, err := clientConfig.TLSConfig()\n\trequire.NoError(t, err)\n\n\tclient := http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: clientTLSConfig,\n\t\t},\n\t\tTimeout: 10 * time.Second,\n\t}\n\n\tresp, err := client.Get(ts.URL)\n\trequire.NoError(t, err)\n\n\tdefer resp.Body.Close()\n\trequire.Equal(t, 200, resp.StatusCode)\n}\n\nfunc TestConnectClientMinTLSVersion(t *testing.T) {\n\tserverConfig := tls.ServerConfig{\n\t\tTLSCert:            pki.ServerCertPath(),\n\t\tTLSKey:             pki.ServerKeyPath(),\n\t\tTLSAllowedCACerts:  []string{pki.CACertPath()},\n\t\tTLSAllowedDNSNames: []string{\"localhost\", \"127.0.0.1\"},\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\tcfg  tls.ClientConfig\n\t}{\n\t\t{\n\t\t\tname: \"TLS version default\",\n\t\t\tcfg: tls.ClientConfig{\n\t\t\t\tTLSCA:   pki.CACertPath(),\n\t\t\t\tTLSCert: pki.ClientCertPath(),\n\t\t\t\tTLSKey:  pki.ClientKeyPath(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TLS version 1.0\",\n\t\t\tcfg: tls.ClientConfig{\n\t\t\t\tTLSCA:         pki.CACertPath(),\n\t\t\t\tTLSCert:       pki.ClientCertPath(),\n\t\t\t\tTLSKey:        pki.ClientKeyPath(),\n\t\t\t\tTLSMinVersion: \"TLS10\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TLS version 1.1\",\n\t\t\tcfg: tls.ClientConfig{\n\t\t\t\tTLSCA:         pki.CACertPath(),\n\t\t\t\tTLSCert:       pki.ClientCertPath(),\n\t\t\t\tTLSKey:        pki.ClientKeyPath(),\n\t\t\t\tTLSMinVersion: \"TLS11\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TLS version 1.2\",\n\t\t\tcfg: tls.ClientConfig{\n\t\t\t\tTLSCA:         pki.CACertPath(),\n\t\t\t\tTLSCert:       pki.ClientCertPath(),\n\t\t\t\tTLSKey:        pki.ClientKeyPath(),\n\t\t\t\tTLSMinVersion: \"TLS12\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TLS version 1.3\",\n\t\t\tcfg: tls.ClientConfig{\n\t\t\t\tTLSCA:         pki.CACertPath(),\n\t\t\t\tTLSCert:       pki.ClientCertPath(),\n\t\t\t\tTLSKey:        pki.ClientKeyPath(),\n\t\t\t\tTLSMinVersion: \"TLS13\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttlsVersions := []uint16{\n\t\tcryptotls.VersionTLS10,\n\t\tcryptotls.VersionTLS11,\n\t\tcryptotls.VersionTLS12,\n\t\tcryptotls.VersionTLS13,\n\t}\n\n\ttlsVersionNames := []string{\n\t\t\"TLS 1.0\",\n\t\t\"TLS 1.1\",\n\t\t\"TLS 1.2\",\n\t\t\"TLS 1.3\",\n\t}\n\n\tfor _, tt := range tests {\n\t\tclientTLSConfig, err := tt.cfg.TLSConfig()\n\t\trequire.NoError(t, err)\n\n\t\tclient := http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tTLSClientConfig: clientTLSConfig,\n\t\t\t},\n\t\t\tTimeout: 1 * time.Second,\n\t\t}\n\n\t\tclientMinVersion := clientTLSConfig.MinVersion\n\t\tif tt.cfg.TLSMinVersion == \"\" {\n\t\t\tclientMinVersion = tls.TLSMinVersionDefault\n\t\t}\n\n\t\tfor i, serverTLSMaxVersion := range tlsVersions {\n\t\t\tserverVersionName := tlsVersionNames[i]\n\t\t\tt.Run(tt.name+\" vs \"+serverVersionName, func(t *testing.T) {\n\t\t\t\t// Constrain the server's maximum TLS version\n\t\t\t\tserverTLSConfig, err := serverConfig.TLSConfig()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tserverTLSConfig.MinVersion = cryptotls.VersionTLS10\n\t\t\t\tserverTLSConfig.MaxVersion = serverTLSMaxVersion\n\n\t\t\t\t// Start the server\n\t\t\t\tts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t}))\n\t\t\t\tts.TLS = serverTLSConfig\n\t\t\t\tts.StartTLS()\n\n\t\t\t\t// Do the connection and cleanup\n\t\t\t\tresp, err := client.Get(ts.URL)\n\t\t\t\tts.Close()\n\n\t\t\t\t// Things should fail if the currently tested \"serverTLSMaxVersion\"\n\t\t\t\t// is below the client minimum version.\n\t\t\t\tif serverTLSMaxVersion < clientMinVersion {\n\t\t\t\t\trequire.ErrorContains(t, err, \"tls: protocol version not supported\")\n\t\t\t\t} else {\n\t\t\t\t\trequire.NoErrorf(t, err, \"server=%v client=%v\", serverTLSMaxVersion, clientMinVersion)\n\t\t\t\t\trequire.Equal(t, 200, resp.StatusCode)\n\t\t\t\t\tresp.Body.Close()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestConnectClientInvalidMinTLSVersion(t *testing.T) {\n\tclientConfig := tls.ClientConfig{\n\t\tTLSCA:         pki.CACertPath(),\n\t\tTLSCert:       pki.ClientCertPath(),\n\t\tTLSKey:        pki.ClientKeyPath(),\n\t\tTLSMinVersion: \"garbage\",\n\t}\n\n\t_, err := clientConfig.TLSConfig()\n\texpected := `could not parse tls min version \"garbage\": unsupported version \"garbage\" (available: TLS10,TLS11,TLS12,TLS13)`\n\trequire.EqualError(t, err, expected)\n}\n\nfunc TestConnectWrongDNS(t *testing.T) {\n\tclientConfig := tls.ClientConfig{\n\t\tTLSCA:   pki.CACertPath(),\n\t\tTLSCert: pki.ClientCertPath(),\n\t\tTLSKey:  pki.ClientKeyPath(),\n\t}\n\n\tserverConfig := tls.ServerConfig{\n\t\tTLSCert:            pki.ServerCertPath(),\n\t\tTLSKey:             pki.ServerKeyPath(),\n\t\tTLSAllowedCACerts:  []string{pki.CACertPath()},\n\t\tTLSAllowedDNSNames: []string{\"localhos\", \"127.0.0.2\"},\n\t}\n\n\tserverTLSConfig, err := serverConfig.TLSConfig()\n\trequire.NoError(t, err)\n\n\tts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tts.TLS = serverTLSConfig\n\n\tts.StartTLS()\n\tdefer ts.Close()\n\n\tclientTLSConfig, err := clientConfig.TLSConfig()\n\trequire.NoError(t, err)\n\n\tclient := http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: clientTLSConfig,\n\t\t},\n\t\tTimeout: 10 * time.Second,\n\t}\n\n\tresp, err := client.Get(ts.URL)\n\trequire.Error(t, err)\n\tif resp != nil {\n\t\terr = resp.Body.Close()\n\t\trequire.NoError(t, err)\n\t}\n}\n\nfunc TestEnableFlagAuto(t *testing.T) {\n\tcfgEmpty := tls.ClientConfig{}\n\tcfg, err := cfgEmpty.TLSConfig()\n\trequire.NoError(t, err)\n\trequire.Nil(t, cfg)\n\n\tcfgSet := tls.ClientConfig{InsecureSkipVerify: true}\n\tcfg, err = cfgSet.TLSConfig()\n\trequire.NoError(t, err)\n\trequire.NotNil(t, cfg)\n}\n\nfunc TestEnableFlagDisabled(t *testing.T) {\n\tenabled := false\n\tcfgSet := tls.ClientConfig{\n\t\tInsecureSkipVerify: true,\n\t\tEnable:             &enabled,\n\t}\n\tcfg, err := cfgSet.TLSConfig()\n\trequire.NoError(t, err)\n\trequire.Nil(t, cfg)\n}\n\nfunc TestEnableFlagEnabled(t *testing.T) {\n\tenabled := true\n\tcfgSet := tls.ClientConfig{Enable: &enabled}\n\tcfg, err := cfgSet.TLSConfig()\n\trequire.NoError(t, err)\n\trequire.NotNil(t, cfg)\n\n\texpected := &cryptotls.Config{}\n\trequire.Equal(t, expected, cfg)\n}\n"
  },
  {
    "path": "plugins/common/tls/utils.go",
    "content": "package tls\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\nvar ErrCipherUnsupported = errors.New(\"unsupported cipher\")\n\n// InsecureCiphers returns the list of insecure ciphers among the list of given ciphers\nfunc InsecureCiphers(ciphers []string) []string {\n\tvar insecure []string\n\n\tfor _, c := range ciphers {\n\t\tcipher := strings.ToUpper(c)\n\t\tif _, ok := tlsCipherMapInsecure[cipher]; ok {\n\t\t\tinsecure = append(insecure, c)\n\t\t}\n\t}\n\n\treturn insecure\n}\n\n// Ciphers returns the list of supported ciphers\nfunc Ciphers() (secure, insecure []string) {\n\tfor c := range tlsCipherMapSecure {\n\t\tsecure = append(secure, c)\n\t}\n\n\tfor c := range tlsCipherMapInsecure {\n\t\tinsecure = append(insecure, c)\n\t}\n\n\treturn secure, insecure\n}\n\n// ParseCiphers returns a `[]uint16` by received `[]string` key that represents ciphers from crypto/tls.\n// If some of ciphers in received list doesn't exists  ParseCiphers returns nil with error\nfunc ParseCiphers(ciphers []string) ([]uint16, error) {\n\tsuites := make([]uint16, 0)\n\tadded := make(map[uint16]bool, len(ciphers))\n\tfor _, c := range ciphers {\n\t\t// Handle meta-keywords\n\t\tswitch c {\n\t\tcase \"all\":\n\t\t\tfor _, id := range tlsCipherMapInsecure {\n\t\t\t\tif added[id] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tsuites = append(suites, id)\n\t\t\t\tadded[id] = true\n\t\t\t}\n\t\t\tfor _, id := range tlsCipherMapSecure {\n\t\t\t\tif added[id] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tsuites = append(suites, id)\n\t\t\t\tadded[id] = true\n\t\t\t}\n\t\tcase \"insecure\":\n\t\t\tfor _, id := range tlsCipherMapInsecure {\n\t\t\t\tif added[id] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tsuites = append(suites, id)\n\t\t\t\tadded[id] = true\n\t\t\t}\n\t\tcase \"secure\":\n\t\t\tfor _, id := range tlsCipherMapSecure {\n\t\t\t\tif added[id] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tsuites = append(suites, id)\n\t\t\t\tadded[id] = true\n\t\t\t}\n\t\tdefault:\n\t\t\tcipher := strings.ToUpper(c)\n\t\t\tid, ok := tlsCipherMapSecure[cipher]\n\t\t\tif !ok {\n\t\t\t\tidInsecure, ok := tlsCipherMapInsecure[cipher]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%q %w\", cipher, ErrCipherUnsupported)\n\t\t\t\t}\n\t\t\t\tid = idInsecure\n\t\t\t}\n\t\t\tif added[id] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tsuites = append(suites, id)\n\t\t\tadded[id] = true\n\t\t}\n\t}\n\n\treturn suites, nil\n}\n\n// ParseTLSVersion returns a `uint16` by received version string key that represents tls version from crypto/tls.\n// If version isn't supported ParseTLSVersion returns 0 with error\nfunc ParseTLSVersion(version string) (uint16, error) {\n\tif v, ok := tlsVersionMap[version]; ok {\n\t\treturn v, nil\n\t}\n\n\tavailable := make([]string, 0, len(tlsVersionMap))\n\tfor n := range tlsVersionMap {\n\t\tavailable = append(available, n)\n\t}\n\tsort.Strings(available)\n\treturn 0, fmt.Errorf(\"unsupported version %q (available: %s)\", version, strings.Join(available, \",\"))\n}\n"
  },
  {
    "path": "plugins/common/yangmodel/decoder.go",
    "content": "package yangmodel\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/openconfig/goyang/pkg/yang\"\n)\n\nvar (\n\tErrInsufficientData = errors.New(\"insufficient data\")\n\tErrNotFound         = errors.New(\"no such node\")\n)\n\ntype Decoder struct {\n\tmodules   map[string]*yang.Module\n\trootNodes map[string][]yang.Node\n}\n\nfunc NewDecoder(paths ...string) (*Decoder, error) {\n\tmodules := yang.NewModules()\n\tmodules.ParseOptions.IgnoreSubmoduleCircularDependencies = true\n\n\tvar moduleFiles []string\n\tmodulePaths := paths\n\tunresolved := paths\n\tfor {\n\t\tvar newlyfound []string\n\t\tfor _, path := range unresolved {\n\t\t\tentries, err := os.ReadDir(path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"reading directory %q failed: %w\", path, err)\n\t\t\t}\n\t\t\tfor _, entry := range entries {\n\t\t\t\tinfo, err := entry.Info()\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"Couldn't get info for %q: %v\", entry.Name(), err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif info.Mode()&os.ModeSymlink != 0 {\n\t\t\t\t\ttarget, err := filepath.EvalSymlinks(entry.Name())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tfmt.Printf(\"Couldn't evaluate symbolic links for %q: %v\", entry.Name(), err)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tinfo, err = os.Lstat(target)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tfmt.Printf(\"Couldn't stat target %v: %v\", target, err)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewPath := filepath.Join(path, info.Name())\n\t\t\t\tif info.IsDir() {\n\t\t\t\t\tnewlyfound = append(newlyfound, newPath)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif info.Mode().IsRegular() && filepath.Ext(info.Name()) == \".yang\" {\n\t\t\t\t\tmoduleFiles = append(moduleFiles, info.Name())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(newlyfound) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tmodulePaths = append(modulePaths, newlyfound...)\n\t\tunresolved = newlyfound\n\t}\n\n\t// Add the module paths\n\tmodules.AddPath(modulePaths...)\n\tfor _, fn := range moduleFiles {\n\t\tif err := modules.Read(fn); err != nil {\n\t\t\tfmt.Printf(\"reading file %q failed: %v\\n\", fn, err)\n\t\t}\n\t}\n\tif errs := modules.Process(); len(errs) > 0 {\n\t\treturn nil, errors.Join(errs...)\n\t}\n\n\t// Get all root nodes defined in models with their origin. We require\n\t// those nodes to later resolve paths to YANG model leaf nodes...\n\tmoduleLUT := make(map[string]*yang.Module)\n\tmoduleRootNodes := make(map[string][]yang.Node)\n\tfor _, m := range modules.Modules {\n\t\t// Check if we processed the module already\n\t\tif _, found := moduleLUT[m.Name]; found {\n\t\t\tcontinue\n\t\t}\n\t\t// Create a module mapping for easily finding modules by name\n\t\tmoduleLUT[m.Name] = m\n\n\t\t// Determine the origin defined in the module\n\t\tvar prefix string\n\t\tfor _, imp := range m.Import {\n\t\t\tif imp.Name == \"openconfig-extensions\" {\n\t\t\t\tprefix = imp.Name\n\t\t\t\tif imp.Prefix != nil {\n\t\t\t\t\tprefix = imp.Prefix.Name\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tvar moduleOrigin string\n\t\tif prefix != \"\" {\n\t\t\tfor _, e := range m.Extensions {\n\t\t\t\tif e.Keyword == prefix+\":origin\" || e.Keyword == \"origin\" {\n\t\t\t\t\tmoduleOrigin = e.Argument\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor _, u := range m.Uses {\n\t\t\troot, err := yang.FindNode(m, u.Name)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmoduleRootNodes[moduleOrigin] = append(moduleRootNodes[moduleOrigin], root)\n\t\t}\n\t}\n\n\treturn &Decoder{modules: moduleLUT, rootNodes: moduleRootNodes}, nil\n}\n\nfunc (d *Decoder) FindLeaf(name, identifier string) (*yang.Leaf, error) {\n\t// Get module name from the element\n\tmodule, found := d.modules[name]\n\tif !found {\n\t\treturn nil, fmt.Errorf(\"cannot find module %q\", name)\n\t}\n\n\tfor _, grp := range module.Grouping {\n\t\tfor _, leaf := range grp.Leaf {\n\t\t\tif leaf.Name == identifier {\n\t\t\t\treturn leaf, nil\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, ErrNotFound\n}\n\nfunc DecodeLeafValue(leaf *yang.Leaf, value interface{}) (interface{}, error) {\n\tschema := leaf.Type.YangType\n\n\t// Ignore all non-string values as the types seem already converted...\n\ts, ok := value.(string)\n\tif !ok {\n\t\treturn value, nil\n\t}\n\n\tswitch schema.Kind {\n\tcase yang.Ybinary:\n\t\t// Binary values are encodes as base64 string, so decode the string\n\t\traw, err := base64.StdEncoding.DecodeString(s)\n\t\tif err != nil {\n\t\t\treturn value, err\n\t\t}\n\n\t\tswitch schema.Name {\n\t\tcase \"ieeefloat32\":\n\t\t\tif len(raw) != 4 {\n\t\t\t\treturn raw, fmt.Errorf(\"%w, expected 4 but got %d bytes\", ErrInsufficientData, len(raw))\n\t\t\t}\n\t\t\treturn math.Float32frombits(binary.BigEndian.Uint32(raw)), nil\n\t\tdefault:\n\t\t\treturn raw, nil\n\t\t}\n\tcase yang.Yint8:\n\t\tv, err := strconv.ParseInt(s, 10, 8)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn int8(v), nil\n\tcase yang.Yint16:\n\t\tv, err := strconv.ParseInt(s, 10, 16)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn int16(v), nil\n\tcase yang.Yint32:\n\t\tv, err := strconv.ParseInt(s, 10, 32)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn int32(v), nil\n\tcase yang.Yint64:\n\t\tv, err := strconv.ParseInt(s, 10, 64)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn v, nil\n\tcase yang.Yuint8:\n\t\tv, err := strconv.ParseUint(s, 10, 8)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn uint8(v), nil\n\tcase yang.Yuint16:\n\t\tv, err := strconv.ParseUint(s, 10, 16)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn uint16(v), nil\n\tcase yang.Yuint32:\n\t\tv, err := strconv.ParseUint(s, 10, 32)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn uint32(v), nil\n\tcase yang.Yuint64:\n\t\tv, err := strconv.ParseUint(s, 10, 64)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn v, nil\n\tcase yang.Ydecimal64:\n\t\tv, err := strconv.ParseFloat(s, 64)\n\t\tif err != nil {\n\t\t\treturn value, fmt.Errorf(\"parsing %s %q failed: %w\", yang.TypeKindToName[schema.Kind], s, err)\n\t\t}\n\t\treturn v, nil\n\t}\n\treturn value, nil\n}\n\nfunc (d *Decoder) DecodeLeafElement(namespace, identifier string, value interface{}) (interface{}, error) {\n\tleaf, err := d.FindLeaf(namespace, identifier)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"finding %s failed: %w\", identifier, err)\n\t}\n\n\treturn DecodeLeafValue(leaf, value)\n}\n\nfunc (d *Decoder) DecodePathElement(origin, path string, value interface{}) (interface{}, error) {\n\trootNodes, found := d.rootNodes[origin]\n\tif !found || len(rootNodes) == 0 {\n\t\treturn value, nil\n\t}\n\n\tfor _, root := range rootNodes {\n\t\tnode, err := yang.FindNode(root, path)\n\t\tif node == nil || err != nil {\n\t\t\t// The path does not exist in this root node\n\t\t\tcontinue\n\t\t}\n\t\t// We do expect a leaf node...\n\t\tif leaf, ok := node.(*yang.Leaf); ok {\n\t\t\treturn DecodeLeafValue(leaf, value)\n\t\t}\n\t}\n\n\treturn value, nil\n}\n"
  },
  {
    "path": "plugins/inputs/activemq/README.md",
    "content": "# ActiveMQ Input Plugin\n\nThis plugin gathers queue, topics and subscribers metrics using the Console API\n[ActiveMQ][activemq] message broker daemon.\n\n⭐ Telegraf v1.8.0\n🏷️ messaging\n💻 all\n\n[activemq]: https://activemq.apache.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather ActiveMQ metrics\n[[inputs.activemq]]\n  ## ActiveMQ WebConsole URL\n  url = \"http://127.0.0.1:8161\"\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Required ActiveMQ webadmin root path\n  # webadmin = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\nEvery effort was made to preserve the names based on the XML response from the\nActiveMQ Console API.\n\n- activemq_queues\n  - tags:\n    - name\n    - source\n    - port\n  - fields:\n    - size\n    - consumer_count\n    - enqueue_count\n    - dequeue_count\n- activemq_topics\n  - tags:\n    - name\n    - source\n    - port\n  - fields:\n    - size\n    - consumer_count\n    - enqueue_count\n    - dequeue_count\n- activemq_subscribers\n  - tags:\n    - client_id\n    - subscription_name\n    - connection_id\n    - destination_name\n    - selector\n    - active\n    - source\n    - port\n  - fields:\n    - pending_queue_size\n    - dispatched_queue_size\n    - dispatched_counter\n    - enqueue_counter\n    - dequeue_counter\n\n## Example Output\n\n```text\nactivemq_queues,name=sandra,host=88284b2fe51b,source=localhost,port=8161 consumer_count=0i,enqueue_count=0i,dequeue_count=0i,size=0i 1492610703000000000\nactivemq_queues,name=Test,host=88284b2fe51b,source=localhost,port=8161 dequeue_count=0i,size=0i,consumer_count=0i,enqueue_count=0i 1492610703000000000\nactivemq_topics,name=ActiveMQ.Advisory.MasterBroker\\ ,host=88284b2fe51b,source=localhost,port=8161 size=0i,consumer_count=0i,enqueue_count=1i,dequeue_count=0i 1492610703000000000\nactivemq_topics,host=88284b2fe51b,name=AAA\\,source=localhost,port=8161  size=0i,consumer_count=1i,enqueue_count=0i,dequeue_count=0i 1492610703000000000\nactivemq_topics,name=ActiveMQ.Advisory.Topic\\,source=localhost,port=8161 ,host=88284b2fe51b enqueue_count=1i,dequeue_count=0i,size=0i,consumer_count=0i 1492610703000000000\nactivemq_topics,name=ActiveMQ.Advisory.Queue\\,source=localhost,port=8161 ,host=88284b2fe51b size=0i,consumer_count=0i,enqueue_count=2i,dequeue_count=0i 1492610703000000000\nactivemq_topics,name=AAAA\\ ,host=88284b2fe51b,source=localhost,port=8161 consumer_count=0i,enqueue_count=0i,dequeue_count=0i,size=0i 1492610703000000000\nactivemq_subscribers,connection_id=NOTSET,destination_name=AAA,,source=localhost,port=8161,selector=AA,active=no,host=88284b2fe51b,client_id=AAA,subscription_name=AAA pending_queue_size=0i,dispatched_queue_size=0i,dispatched_counter=0i,enqueue_counter=0i,dequeue_counter=0i 1492610703000000000\n```\n"
  },
  {
    "path": "plugins/inputs/activemq/activemq.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage activemq\n\nimport (\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype ActiveMQ struct {\n\tServer          string          `toml:\"server\" deprecated:\"1.11.0;use 'url' instead\"`\n\tPort            int             `toml:\"port\" deprecated:\"1.11.0;use 'url' instead\"`\n\tURL             string          `toml:\"url\"`\n\tUsername        string          `toml:\"username\"`\n\tPassword        string          `toml:\"password\"`\n\tWebadmin        string          `toml:\"webadmin\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\ttls.ClientConfig\n\n\tclient  *http.Client\n\tbaseURL *url.URL\n}\n\ntype topics struct {\n\tXMLName    xml.Name `xml:\"topics\"`\n\tTopicItems []topic  `xml:\"topic\"`\n}\n\ntype topic struct {\n\tXMLName xml.Name `xml:\"topic\"`\n\tName    string   `xml:\"name,attr\"`\n\tStats   stats    `xml:\"stats\"`\n}\n\ntype subscribers struct {\n\tXMLName         xml.Name     `xml:\"subscribers\"`\n\tSubscriberItems []subscriber `xml:\"subscriber\"`\n}\n\ntype subscriber struct {\n\tXMLName          xml.Name `xml:\"subscriber\"`\n\tClientID         string   `xml:\"clientId,attr\"`\n\tSubscriptionName string   `xml:\"subscriptionName,attr\"`\n\tConnectionID     string   `xml:\"connectionId,attr\"`\n\tDestinationName  string   `xml:\"destinationName,attr\"`\n\tSelector         string   `xml:\"selector,attr\"`\n\tActive           string   `xml:\"active,attr\"`\n\tStats            stats    `xml:\"stats\"`\n}\n\ntype queues struct {\n\tXMLName    xml.Name `xml:\"queues\"`\n\tQueueItems []queue  `xml:\"queue\"`\n}\n\ntype queue struct {\n\tXMLName xml.Name `xml:\"queue\"`\n\tName    string   `xml:\"name,attr\"`\n\tStats   stats    `xml:\"stats\"`\n}\n\ntype stats struct {\n\tXMLName             xml.Name `xml:\"stats\"`\n\tSize                int      `xml:\"size,attr\"`\n\tConsumerCount       int      `xml:\"consumerCount,attr\"`\n\tEnqueueCount        int      `xml:\"enqueueCount,attr\"`\n\tDequeueCount        int      `xml:\"dequeueCount,attr\"`\n\tPendingQueueSize    int      `xml:\"pendingQueueSize,attr\"`\n\tDispatchedQueueSize int      `xml:\"dispatchedQueueSize,attr\"`\n\tDispatchedCounter   int      `xml:\"dispatchedCounter,attr\"`\n\tEnqueueCounter      int      `xml:\"enqueueCounter,attr\"`\n\tDequeueCounter      int      `xml:\"dequeueCounter,attr\"`\n}\n\nfunc (*ActiveMQ) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *ActiveMQ) Init() error {\n\tif a.ResponseTimeout < config.Duration(time.Second) {\n\t\ta.ResponseTimeout = config.Duration(time.Second * 5)\n\t}\n\n\tvar err error\n\tu := &url.URL{Scheme: \"http\", Host: a.Server + \":\" + strconv.Itoa(a.Port)}\n\tif a.URL != \"\" {\n\t\tu, err = url.Parse(a.URL)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !strings.HasPrefix(u.Scheme, \"http\") {\n\t\treturn fmt.Errorf(\"invalid scheme %q\", u.Scheme)\n\t}\n\n\tif u.Hostname() == \"\" {\n\t\treturn fmt.Errorf(\"invalid hostname %q\", u.Hostname())\n\t}\n\n\ta.baseURL = u\n\n\ta.client, err = a.createHTTPClient()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (a *ActiveMQ) Gather(acc telegraf.Accumulator) error {\n\tdataQueues, err := a.getMetrics(a.queuesURL())\n\tif err != nil {\n\t\treturn err\n\t}\n\tqueues := queues{}\n\terr = xml.Unmarshal(dataQueues, &queues)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"queues XML unmarshal error: %w\", err)\n\t}\n\n\tdataTopics, err := a.getMetrics(a.topicsURL())\n\tif err != nil {\n\t\treturn err\n\t}\n\ttopics := topics{}\n\terr = xml.Unmarshal(dataTopics, &topics)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"topics XML unmarshal error: %w\", err)\n\t}\n\n\tdataSubscribers, err := a.getMetrics(a.subscribersURL())\n\tif err != nil {\n\t\treturn err\n\t}\n\tsubscribers := subscribers{}\n\terr = xml.Unmarshal(dataSubscribers, &subscribers)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"subscribers XML unmarshal error: %w\", err)\n\t}\n\n\ta.gatherQueuesMetrics(acc, queues)\n\ta.gatherTopicsMetrics(acc, topics)\n\ta.gatherSubscribersMetrics(acc, subscribers)\n\n\treturn nil\n}\n\nfunc (a *ActiveMQ) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := a.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(a.ResponseTimeout),\n\t}\n\n\treturn client, nil\n}\n\nfunc (a *ActiveMQ) getMetrics(u string) ([]byte, error) {\n\treq, err := http.NewRequest(\"GET\", u, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif a.Username != \"\" || a.Password != \"\" {\n\t\treq.SetBasicAuth(a.Username, a.Password)\n\t}\n\n\tresp, err := a.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s\", u, resp.Status)\n\t}\n\n\treturn io.ReadAll(resp.Body)\n}\n\nfunc (a *ActiveMQ) gatherQueuesMetrics(acc telegraf.Accumulator, queues queues) {\n\tfor _, queue := range queues.QueueItems {\n\t\trecords := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\ttags[\"name\"] = strings.TrimSpace(queue.Name)\n\t\ttags[\"source\"] = a.baseURL.Hostname()\n\t\ttags[\"port\"] = a.baseURL.Port()\n\n\t\trecords[\"size\"] = queue.Stats.Size\n\t\trecords[\"consumer_count\"] = queue.Stats.ConsumerCount\n\t\trecords[\"enqueue_count\"] = queue.Stats.EnqueueCount\n\t\trecords[\"dequeue_count\"] = queue.Stats.DequeueCount\n\n\t\tacc.AddFields(\"activemq_queues\", records, tags)\n\t}\n}\n\nfunc (a *ActiveMQ) gatherTopicsMetrics(acc telegraf.Accumulator, topics topics) {\n\tfor _, topic := range topics.TopicItems {\n\t\trecords := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\ttags[\"name\"] = topic.Name\n\t\ttags[\"source\"] = a.baseURL.Hostname()\n\t\ttags[\"port\"] = a.baseURL.Port()\n\n\t\trecords[\"size\"] = topic.Stats.Size\n\t\trecords[\"consumer_count\"] = topic.Stats.ConsumerCount\n\t\trecords[\"enqueue_count\"] = topic.Stats.EnqueueCount\n\t\trecords[\"dequeue_count\"] = topic.Stats.DequeueCount\n\n\t\tacc.AddFields(\"activemq_topics\", records, tags)\n\t}\n}\n\nfunc (a *ActiveMQ) gatherSubscribersMetrics(acc telegraf.Accumulator, subscribers subscribers) {\n\tfor _, subscriber := range subscribers.SubscriberItems {\n\t\trecords := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\ttags[\"client_id\"] = subscriber.ClientID\n\t\ttags[\"subscription_name\"] = subscriber.SubscriptionName\n\t\ttags[\"connection_id\"] = subscriber.ConnectionID\n\t\ttags[\"destination_name\"] = subscriber.DestinationName\n\t\ttags[\"selector\"] = subscriber.Selector\n\t\ttags[\"active\"] = subscriber.Active\n\t\ttags[\"source\"] = a.baseURL.Hostname()\n\t\ttags[\"port\"] = a.baseURL.Port()\n\n\t\trecords[\"pending_queue_size\"] = subscriber.Stats.PendingQueueSize\n\t\trecords[\"dispatched_queue_size\"] = subscriber.Stats.DispatchedQueueSize\n\t\trecords[\"dispatched_counter\"] = subscriber.Stats.DispatchedCounter\n\t\trecords[\"enqueue_counter\"] = subscriber.Stats.EnqueueCounter\n\t\trecords[\"dequeue_counter\"] = subscriber.Stats.DequeueCounter\n\n\t\tacc.AddFields(\"activemq_subscribers\", records, tags)\n\t}\n}\n\nfunc (a *ActiveMQ) queuesURL() string {\n\tref := url.URL{Path: path.Join(\"/\", a.Webadmin, \"/xml/queues.jsp\")}\n\treturn a.baseURL.ResolveReference(&ref).String()\n}\n\nfunc (a *ActiveMQ) topicsURL() string {\n\tref := url.URL{Path: path.Join(\"/\", a.Webadmin, \"/xml/topics.jsp\")}\n\treturn a.baseURL.ResolveReference(&ref).String()\n}\n\nfunc (a *ActiveMQ) subscribersURL() string {\n\tref := url.URL{Path: path.Join(\"/\", a.Webadmin, \"/xml/subscribers.jsp\")}\n\treturn a.baseURL.ResolveReference(&ref).String()\n}\n\nfunc init() {\n\tinputs.Add(\"activemq\", func() telegraf.Input {\n\t\treturn &ActiveMQ{\n\t\t\tServer:   \"localhost\",\n\t\t\tPort:     8161,\n\t\t\tWebadmin: \"admin\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/activemq/activemq_test.go",
    "content": "package activemq\n\nimport (\n\t\"encoding/xml\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGatherQueuesMetrics(t *testing.T) {\n\ts := `<queues>\n<queue name=\"sandra\">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"0\" dequeueCount=\"0\"/>\n<feed>\n<atom>queueBrowse/sandra?view=rss&amp;feedType=atom_1.0</atom>\n<rss>queueBrowse/sandra?view=rss&amp;feedType=rss_2.0</rss>\n</feed>\n</queue>\n<queue name=\"Test\">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"0\" dequeueCount=\"0\"/>\n<feed>\n<atom>queueBrowse/Test?view=rss&amp;feedType=atom_1.0</atom>\n<rss>queueBrowse/Test?view=rss&amp;feedType=rss_2.0</rss>\n</feed>\n</queue>\n</queues>`\n\n\tqueues := queues{}\n\n\trequire.NoError(t, xml.Unmarshal([]byte(s), &queues))\n\n\trecords := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\ttags[\"name\"] = \"Test\"\n\ttags[\"source\"] = \"localhost\"\n\ttags[\"port\"] = \"8161\"\n\n\trecords[\"size\"] = 0\n\trecords[\"consumer_count\"] = 0\n\trecords[\"enqueue_count\"] = 0\n\trecords[\"dequeue_count\"] = 0\n\n\tplugin := &ActiveMQ{\n\t\tServer: \"localhost\",\n\t\tPort:   8161,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\tplugin.gatherQueuesMetrics(&acc, queues)\n\tacc.AssertContainsTaggedFields(t, \"activemq_queues\", records, tags)\n}\n\nfunc TestGatherTopicsMetrics(t *testing.T) {\n\ts := `<topics>\n<topic name=\"ActiveMQ.Advisory.MasterBroker \">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"1\" dequeueCount=\"0\"/>\n</topic>\n<topic name=\"AAA \">\n<stats size=\"0\" consumerCount=\"1\" enqueueCount=\"0\" dequeueCount=\"0\"/>\n</topic>\n<topic name=\"ActiveMQ.Advisory.Topic \">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"1\" dequeueCount=\"0\"/>\n</topic>\n<topic name=\"ActiveMQ.Advisory.Queue \">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"2\" dequeueCount=\"0\"/>\n</topic>\n<topic name=\"AAAA \">\n<stats size=\"0\" consumerCount=\"0\" enqueueCount=\"0\" dequeueCount=\"0\"/>\n</topic>\n</topics>`\n\n\ttopics := topics{}\n\n\trequire.NoError(t, xml.Unmarshal([]byte(s), &topics))\n\n\trecords := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\ttags[\"name\"] = \"ActiveMQ.Advisory.MasterBroker \"\n\ttags[\"source\"] = \"localhost\"\n\ttags[\"port\"] = \"8161\"\n\n\trecords[\"size\"] = 0\n\trecords[\"consumer_count\"] = 0\n\trecords[\"enqueue_count\"] = 1\n\trecords[\"dequeue_count\"] = 0\n\n\tplugin := &ActiveMQ{\n\t\tServer: \"localhost\",\n\t\tPort:   8161,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\tplugin.gatherTopicsMetrics(&acc, topics)\n\tacc.AssertContainsTaggedFields(t, \"activemq_topics\", records, tags)\n}\n\nfunc TestGatherSubscribersMetrics(t *testing.T) {\n\ts := `<subscribers>\n<subscriber clientId=\"AAA\" subscriptionName=\"AAA\" connectionId=\"NOTSET\" destinationName=\"AAA\" selector=\"AA\" active=\"no\">\n<stats pendingQueueSize=\"0\" dispatchedQueueSize=\"0\" dispatchedCounter=\"0\" enqueueCounter=\"0\" dequeueCounter=\"0\"/>\n</subscriber>\n</subscribers>`\n\n\tsubscribers := subscribers{}\n\trequire.NoError(t, xml.Unmarshal([]byte(s), &subscribers))\n\n\trecords := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\ttags[\"client_id\"] = \"AAA\"\n\ttags[\"subscription_name\"] = \"AAA\"\n\ttags[\"connection_id\"] = \"NOTSET\"\n\ttags[\"destination_name\"] = \"AAA\"\n\ttags[\"selector\"] = \"AA\"\n\ttags[\"active\"] = \"no\"\n\ttags[\"source\"] = \"localhost\"\n\ttags[\"port\"] = \"8161\"\n\n\trecords[\"pending_queue_size\"] = 0\n\trecords[\"dispatched_queue_size\"] = 0\n\trecords[\"dispatched_counter\"] = 0\n\trecords[\"enqueue_counter\"] = 0\n\trecords[\"dequeue_counter\"] = 0\n\n\tplugin := &ActiveMQ{\n\t\tServer: \"localhost\",\n\t\tPort:   8161,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\tplugin.gatherSubscribersMetrics(&acc, subscribers)\n\tacc.AssertContainsTaggedFields(t, \"activemq_subscribers\", records, tags)\n}\n\nfunc TestURLs(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/admin/xml/queues.jsp\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(\"<queues></queues>\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/admin/xml/topics.jsp\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(\"<topics></topics>\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/admin/xml/subscribers.jsp\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(\"<subscribers></subscribers>\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tt.Fatalf(\"unexpected path: %s\", r.URL.Path)\n\t\t}\n\t})\n\n\tplugin := ActiveMQ{\n\t\tURL:      \"http://\" + ts.Listener.Addr().String(),\n\t\tWebadmin: \"admin\",\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/activemq/sample.conf",
    "content": "# Gather ActiveMQ metrics\n[[inputs.activemq]]\n  ## ActiveMQ WebConsole URL\n  url = \"http://127.0.0.1:8161\"\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Required ActiveMQ webadmin root path\n  # webadmin = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/aerospike/README.md",
    "content": "# Aerospike Input Plugin\n\nThis plugin queries [Aerospike][aerospike] server(s) for node statistics and\nstatistics on all configured namespaces.\n\n> [!CAUTION]\n> As of version 1.30 the Aerospike plugin has been deprecated in favor of the\n> [prometheus plugin](/plugins/inputs/prometheus/README.md) and the officially\n> supported [Aerospike Prometheus Exporter][prometheus_exporter]\n\nFor details on the measurements mean, please consult the\n[Aerospike Metrics Reference Docs][ref_manual].\n\n> [!NOTE]\n> Metric names will have dashes (`-`) replaced as underscores (`_`) to make\n> querying more consistently and easy.\n\nAll metrics are attempted to be cast to integers, then booleans, then strings\nin order.\n\n⭐ Telegraf v0.2.0\n🚩 Telegraf v1.30.0\n🔥 Telegraf v1.40.0\n🏷️ server\n💻 all\n\n[aerospike]: https://www.aerospike.com\n[prometheus_exporter]: https://aerospike.com/docs/monitorstack/configure/configure-exporter\n[ref_manual]: https://www.aerospike.com/docs/reference/metrics\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read stats from aerospike server(s)\n[[inputs.aerospike]]\n  ## Aerospike servers to connect to (with port)\n  ## This plugin will query all namespaces the aerospike\n  ## server has configured and get stats for them.\n  servers = [\"localhost:3000\"]\n\n  # username = \"telegraf\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  # Feature Options\n  # Add namespace variable to limit the namespaces executed on\n  # Leave blank to do all\n  # disable_query_namespaces = true # default false\n  # namespaces = [\"namespace1\", \"namespace2\"]\n\n  # Enable set level telemetry\n  # query_sets = true # default: false\n  # Add namespace set combinations to limit sets executed on\n  # Leave blank to do all sets\n  # sets = [\"namespace1/set1\", \"namespace1/set2\", \"namespace3\"]\n\n  # Histograms\n  # enable_ttl_histogram = true # default: false\n  # enable_object_size_linear_histogram = true # default: false\n\n  # by default, aerospike produces a 100 bucket histogram\n  # this is not great for most graphing tools, this will allow\n  # the ability to squash this to a smaller number of buckets\n  # To have a balanced histogram, the number of buckets chosen\n  # should divide evenly into 100.\n  # num_histogram_buckets = 100 # default: 10\n```\n\n## Metrics\n\nThe aerospike metrics are under a few measurement names:\n\n***aerospike_node***: These are the aerospike **node** measurements, which are\navailable from the aerospike `statistics` command.\n\n```text\n  telnet localhost 3003\n  statistics\n  ...\n```\n\n***aerospike_namespace***: These are aerospike namespace measurements, which\nare available from the aerospike `namespace/<namespace_name>` command.\n\n```text\n  telnet localhost 3003\n  namespaces\n  <namespace_1>;<namespace_2>;etc.\n  namespace/<namespace_name>\n  ...\n```\n\n***aerospike_set***: These are aerospike set measurements, which\nare available from the aerospike `sets/<namespace_name>/<set_name>` command.\n\n```text\n  telnet localhost 3003\n  sets\n  sets/<namespace_name>\n  sets/<namespace_name>/<set_name>\n  ...\n```\n\n***aerospike_histogram_ttl***: These are aerospike ttl hisogram measurements,\nwhich is available from the aerospike\n`histogram:namespace=<namespace_name>;[set=<set_name>;]type=ttl` command.\n\n```text\n  telnet localhost 3003\n  histogram:namespace=<namespace_name>;type=ttl\n  histogram:namespace=<namespace_name>;[set=<set_name>;]type=ttl\n  ...\n```\n\n***aerospike_histogram_object_size_linear***: These are aerospike object size\nlinear histogram measurements, which is available from the aerospike\n`histogram:namespace=<namespace_name>;[set=<set_name>;]type=object_size_linear`\ncommand.\n\n```text\n  telnet localhost 3003\n  histogram:namespace=<namespace_name>;type=object_size_linear\n  histogram:namespace=<namespace_name>;[set=<set_name>;]type=object_size_linear\n  ...\n```\n\n### Tags\n\nAll measurements have tags:\n\n- aerospike_host\n- node_name\n\nNamespace metrics have tags:\n\n- namespace_name\n\nSet metrics have tags:\n\n- namespace_name\n- set_name\n\nHistogram metrics have tags:\n\n- namespace_name\n- set_name (optional)\n- type\n\n## Example Output\n\n```text\naerospike_node,aerospike_host=localhost:3000,node_name=\"BB9020011AC4202\" batch_error=0i,batch_index_complete=0i,batch_index_created_buffers=0i,batch_index_destroyed_buffers=0i,batch_index_error=0i,batch_index_huge_buffers=0i,batch_index_initiate=0i,batch_index_queue=\"0:0,0:0,0:0,0:0\",batch_index_timeout=0i,batch_index_unused_buffers=0i,batch_initiate=0i,batch_queue=0i,batch_timeout=0i,client_connections=6i,cluster_integrity=true,cluster_key=\"8AF422E05281249E\",cluster_size=1i,delete_queue=0i,demarshal_error=0i,early_tsvc_batch_sub_error=0i,early_tsvc_client_error=0i,early_tsvc_udf_sub_error=0i,fabric_connections=16i,fabric_msgs_rcvd=0i,fabric_msgs_sent=0i,heartbeat_connections=0i,heartbeat_received_foreign=0i,heartbeat_received_self=0i,info_complete=47i,info_queue=0i,migrate_allowed=true,migrate_partitions_remaining=0i,migrate_progress_recv=0i,migrate_progress_send=0i,objects=0i,paxos_principal=\"BB9020011AC4202\",proxy_in_progress=0i,proxy_retry=0i,query_long_running=0i,query_short_running=0i,reaped_fds=0i,record_refs=0i,rw_in_progress=0i,scans_active=0i,sindex_gc_activity_dur=0i,sindex_gc_garbage_cleaned=0i,sindex_gc_garbage_found=0i,sindex_gc_inactivity_dur=0i,sindex_gc_list_creation_time=0i,sindex_gc_list_deletion_time=0i,sindex_gc_locktimedout=0i,sindex_gc_objects_validated=0i,sindex_ucgarbage_found=0i,sub_objects=0i,system_free_mem_pct=92i,system_swapping=false,tsvc_queue=0i,uptime=1457i 1468923222000000000\naerospike_namespace,aerospike_host=localhost:3000,namespace=test,node_name=\"BB9020011AC4202\" allow_nonxdr_writes=true,allow_xdr_writes=true,available_bin_names=32768i,batch_sub_proxy_complete=0i,batch_sub_proxy_error=0i,batch_sub_proxy_timeout=0i,batch_sub_read_error=0i,batch_sub_read_not_found=0i,batch_sub_read_success=0i,batch_sub_read_timeout=0i,batch_sub_tsvc_error=0i,batch_sub_tsvc_timeout=0i,client_delete_error=0i,client_delete_not_found=0i,client_delete_success=0i,client_delete_timeout=0i,client_lang_delete_success=0i,client_lang_error=0i,client_lang_read_success=0i,client_lang_write_success=0i,client_proxy_complete=0i,client_proxy_error=0i,client_proxy_timeout=0i,client_read_error=0i,client_read_not_found=0i,client_read_success=0i,client_read_timeout=0i,client_tsvc_error=0i,client_tsvc_timeout=0i,client_udf_complete=0i,client_udf_error=0i,client_udf_timeout=0i,client_write_error=0i,client_write_success=0i,client_write_timeout=0i,cold_start_evict_ttl=4294967295i,conflict_resolution_policy=\"generation\",current_time=206619222i,data_in_index=false,default_ttl=432000i,device_available_pct=99i,device_free_pct=100i,device_total_bytes=4294967296i,device_used_bytes=0i,disallow_null_setname=false,enable_benchmarks_batch_sub=false,enable_benchmarks_read=false,enable_benchmarks_storage=false,enable_benchmarks_udf=false,enable_benchmarks_udf_sub=false,enable_benchmarks_write=false,enable_hist_proxy=false,enable_xdr=false,evict_hist_buckets=10000i,evict_tenths_pct=5i,evict_ttl=0i,evicted_objects=0i,expired_objects=0i,fail_generation=0i,fail_key_busy=0i,fail_record_too_big=0i,fail_xdr_forbidden=0i,geo2dsphere_within.earth_radius_meters=6371000i,geo2dsphere_within.level_mod=1i,geo2dsphere_within.max_cells=12i,geo2dsphere_within.max_level=30i,geo2dsphere_within.min_level=1i,geo2dsphere_within.strict=true,geo_region_query_cells=0i,geo_region_query_falsepos=0i,geo_region_query_points=0i,geo_region_query_reqs=0i,high_water_disk_pct=50i,high_water_memory_pct=60i,hwm_breached=false,ldt_enabled=false,ldt_gc_rate=0i,ldt_page_size=8192i,master_objects=0i,master_sub_objects=0i,max_ttl=315360000i,max_void_time=0i,memory_free_pct=100i,memory_size=1073741824i,memory_used_bytes=0i,memory_used_data_bytes=0i,memory_used_index_bytes=0i,memory_used_sindex_bytes=0i,migrate_order=5i,migrate_record_receives=0i,migrate_record_retransmits=0i,migrate_records_skipped=0i,migrate_records_transmitted=0i,migrate_rx_instances=0i,migrate_rx_partitions_active=0i,migrate_rx_partitions_initial=0i,migrate_rx_partitions_remaining=0i,migrate_sleep=1i,migrate_tx_instances=0i,migrate_tx_partitions_active=0i,migrate_tx_partitions_imbalance=0i,migrate_tx_partitions_initial=0i,migrate_tx_partitions_remaining=0i,non_expirable_objects=0i,ns_forward_xdr_writes=false,nsup_cycle_duration=0i,nsup_cycle_sleep_pct=0i,objects=0i,prole_objects=0i,prole_sub_objects=0i,query_agg=0i,query_agg_abort=0i,query_agg_avg_rec_count=0i,query_agg_error=0i,query_agg_success=0i,query_fail=0i,query_long_queue_full=0i,query_long_reqs=0i,query_lookup_abort=0i,query_lookup_avg_rec_count=0i,query_lookup_error=0i,query_lookup_success=0i,query_lookups=0i,query_reqs=0i,query_short_queue_full=0i,query_short_reqs=0i,query_udf_bg_failure=0i,query_udf_bg_success=0i,read_consistency_level_override=\"off\",repl_factor=1i,scan_aggr_abort=0i,scan_aggr_complete=0i,scan_aggr_error=0i,scan_basic_abort=0i,scan_basic_complete=0i,scan_basic_error=0i,scan_udf_bg_abort=0i,scan_udf_bg_complete=0i,scan_udf_bg_error=0i,set_deleted_objects=0i,sets_enable_xdr=true,sindex.data_max_memory=\"ULONG_MAX\",sindex.num_partitions=32i,single_bin=false,stop_writes=false,stop_writes_pct=90i,storage_engine=\"device\",storage_engine.cold_start_empty=false,storage_engine.data_in_memory=true,storage_engine.defrag_lwm_pct=50i,storage_engine.defrag_queue_min=0i,storage_engine.defrag_sleep=1000i,storage_engine.defrag_startup_minimum=10i,storage_engine.disable_odirect=false,storage_engine.enable_osync=false,storage_engine.file=\"/opt/aerospike/data/test.dat\",storage_engine.filesize=4294967296i,storage_engine.flush_max_ms=1000i,storage_engine.fsync_max_sec=0i,storage_engine.max_write_cache=67108864i,storage_engine.min_avail_pct=5i,storage_engine.post_write_queue=0i,storage_engine.scheduler_mode=\"null\",storage_engine.write_block_size=1048576i,storage_engine.write_threads=1i,sub_objects=0i,udf_sub_lang_delete_success=0i,udf_sub_lang_error=0i,udf_sub_lang_read_success=0i,udf_sub_lang_write_success=0i,udf_sub_tsvc_error=0i,udf_sub_tsvc_timeout=0i,udf_sub_udf_complete=0i,udf_sub_udf_error=0i,udf_sub_udf_timeout=0i,write_commit_level_override=\"off\",xdr_write_error=0i,xdr_write_success=0i,xdr_write_timeout=0i,{test}_query_hist_track_back=300i,{test}_query_hist_track_slice=10i,{test}_query_hist_track_thresholds=\"1,8,64\",{test}_read_hist_track_back=300i,{test}_read_hist_track_slice=10i,{test}_read_hist_track_thresholds=\"1,8,64\",{test}_udf_hist_track_back=300i,{test}_udf_hist_track_slice=10i,{test}_udf_hist_track_thresholds=\"1,8,64\",{test}_write_hist_track_back=300i,{test}_write_hist_track_slice=10i,{test}_write_hist_track_thresholds=\"1,8,64\" 1468923222000000000\naerospike_set,aerospike_host=localhost:3000,node_name=BB99458B42826B0,set=test/test disable_eviction=false,memory_data_bytes=0i,objects=0i,set_enable_xdr=\"use-default\",stop_writes_count=0i,tombstones=0i,truncate_lut=0i 1598033805000000000\naerospike_histogram_ttl,aerospike_host=localhost:3000,namespace=test,node_name=BB98EE5B42826B0,set=test 0=0i,1=0i,10=0i,11=0i,12=0i,13=0i,14=0i,15=0i,16=0i,17=0i,18=0i,19=0i,2=0i,20=0i,21=0i,22=0i,23=0i,24=0i,25=0i,26=0i,27=0i,28=0i,29=0i,3=0i,30=0i,31=0i,32=0i,33=0i,34=0i,35=0i,36=0i,37=0i,38=0i,39=0i,4=0i,40=0i,41=0i,42=0i,43=0i,44=0i,45=0i,46=0i,47=0i,48=0i,49=0i,5=0i,50=0i,51=0i,52=0i,53=0i,54=0i,55=0i,56=0i,57=0i,58=0i,59=0i,6=0i,60=0i,61=0i,62=0i,63=0i,64=0i,65=0i,66=0i,67=0i,68=0i,69=0i,7=0i,70=0i,71=0i,72=0i,73=0i,74=0i,75=0i,76=0i,77=0i,78=0i,79=0i,8=0i,80=0i,81=0i,82=0i,83=0i,84=0i,85=0i,86=0i,87=0i,88=0i,89=0i,9=0i,90=0i,91=0i,92=0i,93=0i,94=0i,95=0i,96=0i,97=0i,98=0i,99=0i 1598034191000000000\n```\n"
  },
  {
    "path": "plugins/inputs/aerospike/aerospike.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage aerospike\n\nimport (\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tas \"github.com/aerospike/aerospike-client-go/v5\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Aerospike struct {\n\tServers []string `toml:\"servers\"`\n\n\tUsername string `toml:\"username\"`\n\tPassword string `toml:\"password\"`\n\n\tEnableTLS bool   `toml:\"enable_tls\" deprecated:\"1.37.0;1.40.0;use 'tls_enable' instead\"`\n\tTLSName   string `toml:\"tls_name\" deprecated:\"1.37.0;1.40.0;use 'tls_server_name' instead\"`\n\tcommon_tls.ClientConfig\n\n\ttlsConfig *tls.Config\n\n\tDisableQueryNamespaces bool     `toml:\"disable_query_namespaces\"`\n\tNamespaces             []string `toml:\"namespaces\"`\n\n\tQuerySets bool     `toml:\"query_sets\"`\n\tSets      []string `toml:\"sets\"`\n\n\tEnableTTLHistogram              bool `toml:\"enable_ttl_histogram\"`\n\tEnableObjectSizeLinearHistogram bool `toml:\"enable_object_size_linear_histogram\"`\n\n\tNumberHistogramBuckets int `toml:\"num_histogram_buckets\"`\n}\n\n// On the random chance a hex value is all digits\n// these are fields that can contain hex and should always be strings\nvar protectedHexFields = map[string]bool{\n\t\"node_name\":       true,\n\t\"cluster_key\":     true,\n\t\"paxos_principal\": true,\n}\n\nfunc (*Aerospike) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *Aerospike) Init() error {\n\ta.ClientConfig.Enable = &a.EnableTLS\n\ta.ClientConfig.ServerName = a.TLSName\n\ttlsConfig, err := a.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\ta.tlsConfig = tlsConfig\n\n\tif a.NumberHistogramBuckets == 0 {\n\t\ta.NumberHistogramBuckets = 10\n\t} else if a.NumberHistogramBuckets > 100 {\n\t\ta.NumberHistogramBuckets = 100\n\t} else if a.NumberHistogramBuckets < 1 {\n\t\ta.NumberHistogramBuckets = 10\n\t}\n\n\treturn nil\n}\n\nfunc (a *Aerospike) Gather(acc telegraf.Accumulator) error {\n\tif len(a.Servers) == 0 {\n\t\treturn a.gatherServer(acc, \"127.0.0.1:3000\")\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(a.Servers))\n\tfor _, server := range a.Servers {\n\t\tgo func(serv string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(a.gatherServer(acc, serv))\n\t\t}(server)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (a *Aerospike) gatherServer(acc telegraf.Accumulator, hostPort string) error {\n\tpolicy := as.NewClientPolicy()\n\tpolicy.User = a.Username\n\tpolicy.Password = a.Password\n\tpolicy.TlsConfig = a.tlsConfig\n\tasHosts, err := as.NewHosts(hostPort)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif a.tlsConfig != nil {\n\t\tpolicy.ClusterName = a.tlsConfig.ServerName\n\t}\n\tc, err := as.NewClientWithPolicyAndHost(policy, asHosts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tasInfoPolicy := as.NewInfoPolicy()\n\tdefer c.Close()\n\n\tnodes := c.GetNodes()\n\tfor _, n := range nodes {\n\t\tnodeHost := n.GetHost().String()\n\t\tstats, err := getNodeInfo(n, asInfoPolicy)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tparseNodeInfo(acc, stats, nodeHost, n.GetName())\n\n\t\tnamespaces, err := a.getNamespaces(n, asInfoPolicy)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !a.DisableQueryNamespaces {\n\t\t\t// Query Namespaces\n\t\t\tfor _, namespace := range namespaces {\n\t\t\t\tstats, err = getNamespaceInfo(namespace, n, asInfoPolicy)\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tparseNamespaceInfo(acc, stats, nodeHost, namespace, n.GetName())\n\n\t\t\t\tif a.EnableTTLHistogram {\n\t\t\t\t\terr = a.getTTLHistogram(acc, nodeHost, namespace, \"\", n, asInfoPolicy)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif a.EnableObjectSizeLinearHistogram {\n\t\t\t\t\terr = a.getObjectSizeLinearHistogram(acc, nodeHost, namespace, \"\", n, asInfoPolicy)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif a.QuerySets {\n\t\t\tnamespaceSets, err := a.getSets(n, asInfoPolicy)\n\t\t\tif err == nil {\n\t\t\t\tfor _, namespaceSet := range namespaceSets {\n\t\t\t\t\tnamespace, set := splitNamespaceSet(namespaceSet)\n\t\t\t\t\tstats, err := getSetInfo(namespaceSet, n, asInfoPolicy)\n\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tparseSetInfo(acc, stats, nodeHost, namespaceSet, n.GetName())\n\n\t\t\t\t\tif a.EnableTTLHistogram {\n\t\t\t\t\t\terr = a.getTTLHistogram(acc, nodeHost, namespace, set, n, asInfoPolicy)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif a.EnableObjectSizeLinearHistogram {\n\t\t\t\t\t\terr = a.getObjectSizeLinearHistogram(acc, nodeHost, namespace, set, n, asInfoPolicy)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getNodeInfo(n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {\n\tstats, err := n.RequestInfo(infoPolicy, \"statistics\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn stats, nil\n}\n\nfunc parseNodeInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, nodeName string) {\n\tnTags := map[string]string{\n\t\t\"aerospike_host\": hostPort,\n\t\t\"node_name\":      nodeName,\n\t}\n\tnFields := make(map[string]interface{})\n\tstat := strings.Split(stats[\"statistics\"], \";\")\n\tfor _, pair := range stat {\n\t\tparts := strings.Split(pair, \"=\")\n\t\tif len(parts) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.ReplaceAll(parts[0], \"-\", \"_\")\n\t\tnFields[key] = parseAerospikeValue(key, parts[1])\n\t}\n\tacc.AddFields(\"aerospike_node\", nFields, nTags, time.Now())\n}\n\nfunc (a *Aerospike) getNamespaces(n *as.Node, infoPolicy *as.InfoPolicy) ([]string, error) {\n\tvar namespaces []string\n\tif len(a.Namespaces) == 0 {\n\t\tinfo, err := n.RequestInfo(infoPolicy, \"namespaces\")\n\t\tif err != nil {\n\t\t\treturn namespaces, err\n\t\t}\n\t\tnamespaces = strings.Split(info[\"namespaces\"], \";\")\n\t} else {\n\t\tnamespaces = a.Namespaces\n\t}\n\n\treturn namespaces, nil\n}\n\nfunc getNamespaceInfo(namespace string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {\n\tstats, err := n.RequestInfo(infoPolicy, \"namespace/\"+namespace)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn stats, err\n}\n\nfunc parseNamespaceInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, namespace, nodeName string) {\n\tnTags := map[string]string{\n\t\t\"aerospike_host\": hostPort,\n\t\t\"node_name\":      nodeName,\n\t}\n\tnTags[\"namespace\"] = namespace\n\tnFields := make(map[string]interface{})\n\n\tstat := strings.Split(stats[\"namespace/\"+namespace], \";\")\n\tfor _, pair := range stat {\n\t\tparts := strings.Split(pair, \"=\")\n\t\tif len(parts) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.ReplaceAll(parts[0], \"-\", \"_\")\n\t\tnFields[key] = parseAerospikeValue(key, parts[1])\n\t}\n\tacc.AddFields(\"aerospike_namespace\", nFields, nTags, time.Now())\n}\n\nfunc (a *Aerospike) getSets(n *as.Node, infoPolicy *as.InfoPolicy) ([]string, error) {\n\tvar namespaceSets []string\n\t// Gather all sets\n\tif len(a.Sets) == 0 {\n\t\tstats, err := n.RequestInfo(infoPolicy, \"sets\")\n\t\tif err != nil {\n\t\t\treturn namespaceSets, err\n\t\t}\n\t\tstat := strings.Split(stats[\"sets\"], \";\")\n\t\tfor _, setStats := range stat {\n\t\t\t// setInfo is \"ns=test:set=foo:objects=1:tombstones=0\"\n\t\t\tif len(setStats) > 0 {\n\t\t\t\tpairs := strings.Split(setStats, \":\")\n\t\t\t\tvar ns, set string\n\t\t\t\tfor _, pair := range pairs {\n\t\t\t\t\tparts := strings.Split(pair, \"=\")\n\t\t\t\t\tif len(parts) == 2 {\n\t\t\t\t\t\tif parts[0] == \"ns\" {\n\t\t\t\t\t\t\tns = parts[1]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif parts[0] == \"set\" {\n\t\t\t\t\t\t\tset = parts[1]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(ns) > 0 && len(set) > 0 {\n\t\t\t\t\tnamespaceSets = append(namespaceSets, fmt.Sprintf(\"%s/%s\", ns, set))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else { // User has passed in sets\n\t\tnamespaceSets = a.Sets\n\t}\n\n\treturn namespaceSets, nil\n}\n\nfunc getSetInfo(namespaceSet string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {\n\tstats, err := n.RequestInfo(infoPolicy, \"sets/\"+namespaceSet)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn stats, nil\n}\n\nfunc parseSetInfo(acc telegraf.Accumulator, stats map[string]string, hostPort, namespaceSet, nodeName string) {\n\tstat := strings.Split(\n\t\tstrings.TrimSuffix(\n\t\t\tstats[\"sets/\"+namespaceSet], \";\"), \":\")\n\tnTags := map[string]string{\n\t\t\"aerospike_host\": hostPort,\n\t\t\"node_name\":      nodeName,\n\t\t\"set\":            namespaceSet,\n\t}\n\tnFields := make(map[string]interface{})\n\tfor _, part := range stat {\n\t\tpieces := strings.Split(part, \"=\")\n\t\tif len(pieces) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey := strings.ReplaceAll(pieces[0], \"-\", \"_\")\n\t\tnFields[key] = parseAerospikeValue(key, pieces[1])\n\t}\n\tacc.AddFields(\"aerospike_set\", nFields, nTags, time.Now())\n}\n\nfunc (a *Aerospike) getTTLHistogram(acc telegraf.Accumulator, hostPort, namespace, set string, n *as.Node, infoPolicy *as.InfoPolicy) error {\n\tstats, err := getHistogram(namespace, set, \"ttl\", n, infoPolicy)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnTags := createTags(hostPort, n.GetName(), namespace, set)\n\ta.parseHistogram(acc, stats, nTags, \"ttl\")\n\n\treturn nil\n}\n\nfunc (a *Aerospike) getObjectSizeLinearHistogram(acc telegraf.Accumulator, hostPort, namespace, set string, n *as.Node, infoPolicy *as.InfoPolicy) error {\n\tstats, err := getHistogram(namespace, set, \"object-size-linear\", n, infoPolicy)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnTags := createTags(hostPort, n.GetName(), namespace, set)\n\ta.parseHistogram(acc, stats, nTags, \"object-size-linear\")\n\n\treturn nil\n}\n\nfunc getHistogram(namespace, set, histogramType string, n *as.Node, infoPolicy *as.InfoPolicy) (map[string]string, error) {\n\tvar queryArg string\n\tif len(set) > 0 {\n\t\tqueryArg = fmt.Sprintf(\"histogram:type=%s;namespace=%v;set=%v\", histogramType, namespace, set)\n\t} else {\n\t\tqueryArg = fmt.Sprintf(\"histogram:type=%s;namespace=%v\", histogramType, namespace)\n\t}\n\n\tstats, err := n.RequestInfo(infoPolicy, queryArg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn stats, nil\n}\n\nfunc (a *Aerospike) parseHistogram(acc telegraf.Accumulator, stats, nTags map[string]string, histogramType string) {\n\tnFields := make(map[string]interface{})\n\n\tfor _, stat := range stats {\n\t\tfor _, part := range strings.Split(stat, \":\") {\n\t\t\tpieces := strings.Split(part, \"=\")\n\t\t\tif len(pieces) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif pieces[0] == \"buckets\" {\n\t\t\t\tbuckets := strings.Split(pieces[1], \",\")\n\n\t\t\t\t// Normalize in case of less buckets than expected\n\t\t\t\tnumRecordsPerBucket := 1\n\t\t\t\tif len(buckets) > a.NumberHistogramBuckets {\n\t\t\t\t\tnumRecordsPerBucket = int(math.Ceil(float64(len(buckets)) / float64(a.NumberHistogramBuckets)))\n\t\t\t\t}\n\n\t\t\t\tbucketCount := 0\n\t\t\t\tbucketSum := int64(0) // cast to int64, as can have large object sums\n\t\t\t\tbucketName := 0\n\t\t\t\tfor i, bucket := range buckets {\n\t\t\t\t\t// Sum records and increment bucket collection counter\n\t\t\t\t\tif bucketCount < numRecordsPerBucket {\n\t\t\t\t\t\tbucketSum = bucketSum + parseAerospikeValue(\"\", bucket).(int64)\n\t\t\t\t\t\tbucketCount++\n\t\t\t\t\t}\n\n\t\t\t\t\t// Store records and reset counters\n\t\t\t\t\t// increment bucket name\n\t\t\t\t\tif bucketCount == numRecordsPerBucket {\n\t\t\t\t\t\tnFields[strconv.Itoa(bucketName)] = bucketSum\n\n\t\t\t\t\t\tbucketCount = 0\n\t\t\t\t\t\tbucketSum = 0\n\t\t\t\t\t\tbucketName++\n\t\t\t\t\t} else if i == (len(buckets) - 1) {\n\t\t\t\t\t\t// base/edge case where final bucket does not fully\n\t\t\t\t\t\t// fill number of records per bucket\n\t\t\t\t\t\tnFields[strconv.Itoa(bucketName)] = bucketSum\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tacc.AddFields(fmt.Sprintf(\"aerospike_histogram_%v\", strings.ReplaceAll(histogramType, \"-\", \"_\")), nFields, nTags, time.Now())\n}\n\nfunc splitNamespaceSet(namespaceSet string) (namespace, set string) {\n\tsplit := strings.Split(namespaceSet, \"/\")\n\treturn split[0], split[1]\n}\n\nfunc parseAerospikeValue(key, v string) interface{} {\n\tif protectedHexFields[key] {\n\t\treturn v\n\t} else if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {\n\t\treturn parsed\n\t} else if parsed, err := strconv.ParseUint(v, 10, 64); err == nil {\n\t\treturn parsed\n\t} else if parsed, err := strconv.ParseBool(v); err == nil {\n\t\treturn parsed\n\t} else if parsed, err := strconv.ParseFloat(v, 32); err == nil {\n\t\treturn parsed\n\t}\n\t// leave as string\n\treturn v\n}\n\nfunc createTags(hostPort, nodeName, namespace, set string) map[string]string {\n\tnTags := map[string]string{\n\t\t\"aerospike_host\": hostPort,\n\t\t\"node_name\":      nodeName,\n\t\t\"namespace\":      namespace,\n\t}\n\n\tif len(set) > 0 {\n\t\tnTags[\"set\"] = set\n\t}\n\treturn nTags\n}\n\nfunc init() {\n\tinputs.Add(\"aerospike\", func() telegraf.Input {\n\t\treturn &Aerospike{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/aerospike/aerospike_test.go",
    "content": "package aerospike\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\tas \"github.com/aerospike/aerospike-client-go/v5\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst servicePort = \"3000\"\n\nfunc launchTestServer(t *testing.T) *testutil.Container {\n\tcontainer := testutil.Container{\n\t\tImage:        \"aerospike:ce-8.1.0.1\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForLog(\"migrations: complete\"),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\n\treturn &container\n}\n\nfunc TestAerospikeStatisticsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\ta := &Aerospike{\n\t\tServers: []string{fmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort])},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_node\"))\n\trequire.True(t, acc.HasTag(\"aerospike_node\", \"node_name\"))\n\trequire.True(t, acc.HasMeasurement(\"aerospike_namespace\"))\n\trequire.True(t, acc.HasTag(\"aerospike_namespace\", \"node_name\"))\n\trequire.True(t, acc.HasInt64Field(\"aerospike_node\", \"batch_index_error\"))\n\n\tnamespaceName := acc.TagValue(\"aerospike_namespace\", \"namespace\")\n\trequire.Equal(t, \"test\", namespaceName)\n}\n\nfunc TestAerospikeStatisticsPartialErrIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\ttestutil.GetLocalHost() + \":9999\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\n\trequire.Error(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_node\"))\n\trequire.True(t, acc.HasMeasurement(\"aerospike_namespace\"))\n\trequire.True(t, acc.HasInt64Field(\"aerospike_node\", \"batch_index_error\"))\n\tnamespaceName := acc.TagSetValue(\"aerospike_namespace\", \"namespace\")\n\trequire.Equal(t, \"test\", namespaceName)\n}\n\nfunc TestSelectNamespacesIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\t// Select nonexistent namespace\n\ta := &Aerospike{\n\t\tServers:    []string{fmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort])},\n\t\tNamespaces: []string{\"notTest\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_node\"))\n\trequire.True(t, acc.HasTag(\"aerospike_node\", \"node_name\"))\n\trequire.True(t, acc.HasMeasurement(\"aerospike_namespace\"))\n\trequire.True(t, acc.HasTag(\"aerospike_namespace\", \"node_name\"))\n\n\t// Expect only 1 namespace\n\tcount := 0\n\tfor _, p := range acc.Metrics {\n\t\tif p.Measurement == \"aerospike_namespace\" {\n\t\t\tcount++\n\t\t}\n\t}\n\trequire.Equal(t, 1, count)\n\n\t// expect namespace to have no fields as nonexistent\n\trequire.False(t, acc.HasInt64Field(\"aerospike_namespace\", \"appeals_tx_remaining\"))\n}\n\nfunc TestDisableQueryNamespacesIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tDisableQueryNamespaces: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_node\"))\n\trequire.False(t, acc.HasMeasurement(\"aerospike_namespace\"))\n\n\ta.DisableQueryNamespaces = false\n\terr = acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_node\"))\n\trequire.True(t, acc.HasMeasurement(\"aerospike_namespace\"))\n}\n\nfunc TestQuerySetsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\tportInt, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\t// create a set\n\t// test is the default namespace from aerospike\n\tpolicy := as.NewClientPolicy()\n\tclient, errAs := as.NewClientWithPolicy(policy, container.Address, portInt)\n\trequire.NoError(t, errAs)\n\n\tkey, errAs := as.NewKey(\"test\", \"foo\", 123)\n\trequire.NoError(t, errAs)\n\tbins := as.BinMap{\n\t\t\"e\":  2,\n\t\t\"pi\": 3,\n\t}\n\terrAs = client.Add(nil, key, bins)\n\trequire.NoError(t, errAs)\n\n\tkey, errAs = as.NewKey(\"test\", \"bar\", 1234)\n\trequire.NoError(t, errAs)\n\tbins = as.BinMap{\n\t\t\"e\":  2,\n\t\t\"pi\": 3,\n\t}\n\terrAs = client.Add(nil, key, bins)\n\trequire.NoError(t, errAs)\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tQuerySets:              true,\n\t\tDisableQueryNamespaces: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, FindTagValue(&acc, \"aerospike_set\", \"set\", \"test/foo\"))\n\trequire.True(t, FindTagValue(&acc, \"aerospike_set\", \"set\", \"test/bar\"))\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_set\"))\n\trequire.True(t, acc.HasTag(\"aerospike_set\", \"set\"))\n\trequire.True(t, acc.HasInt64Field(\"aerospike_set\", \"data_used_bytes\"))\n}\n\nfunc TestSelectQuerySetsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\tportInt, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\t// create a set\n\t// test is the default namespace from aerospike\n\tpolicy := as.NewClientPolicy()\n\tclient, errAs := as.NewClientWithPolicy(policy, container.Address, portInt)\n\trequire.NoError(t, errAs)\n\n\tkey, errAs := as.NewKey(\"test\", \"foo\", 123)\n\trequire.NoError(t, errAs)\n\tbins := as.BinMap{\n\t\t\"e\":  2,\n\t\t\"pi\": 3,\n\t}\n\terrAs = client.Add(nil, key, bins)\n\trequire.NoError(t, errAs)\n\n\tkey, errAs = as.NewKey(\"test\", \"bar\", 1234)\n\trequire.NoError(t, errAs)\n\tbins = as.BinMap{\n\t\t\"e\":  2,\n\t\t\"pi\": 3,\n\t}\n\terrAs = client.Add(nil, key, bins)\n\trequire.NoError(t, errAs)\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tQuerySets:              true,\n\t\tSets:                   []string{\"test/foo\"},\n\t\tDisableQueryNamespaces: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, FindTagValue(&acc, \"aerospike_set\", \"set\", \"test/foo\"))\n\trequire.False(t, FindTagValue(&acc, \"aerospike_set\", \"set\", \"test/bar\"))\n\n\trequire.True(t, acc.HasMeasurement(\"aerospike_set\"))\n\trequire.True(t, acc.HasTag(\"aerospike_set\", \"set\"))\n\trequire.True(t, acc.HasInt64Field(\"aerospike_set\", \"data_used_bytes\"))\n}\n\nfunc TestDisableTTLHistogramIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tQuerySets:          true,\n\t\tEnableTTLHistogram: false,\n\t}\n\t/*\n\t\tNo measurement exists\n\t*/\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.False(t, acc.HasMeasurement(\"aerospike_histogram_ttl\"))\n}\n\nfunc TestDisableObjectSizeLinearHistogramIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping aerospike integration tests.\")\n\t}\n\n\tcontainer := launchTestServer(t)\n\tdefer container.Terminate()\n\n\ta := &Aerospike{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tQuerySets:                       true,\n\t\tEnableObjectSizeLinearHistogram: false,\n\t}\n\t/*\n\t\tNo Measurement\n\t*/\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\trequire.False(t, acc.HasMeasurement(\"aerospike_histogram_object_size_linear\"))\n}\n\nfunc TestInit(t *testing.T) {\n\ta := &Aerospike{}\n\n\trequire.NoError(t, a.Init())\n\n\trequire.Equal(t, 10, a.NumberHistogramBuckets)\n\trequire.Nil(t, a.tlsConfig)\n}\n\nfunc TestParseNodeInfo(t *testing.T) {\n\tstats := map[string]string{\n\t\t\"statistics\": \"early_tsvc_from_proxy_error=0;cluster_principal=BB9020012AC4202;cluster_is_member=true\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"early_tsvc_from_proxy_error\": int64(0),\n\t\t\"cluster_principal\":           \"BB9020012AC4202\",\n\t\t\"cluster_is_member\":           true,\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"aerospike_host\": \"127.0.0.1:3000\",\n\t\t\"node_name\":      \"TestNodeName\",\n\t}\n\n\tvar acc testutil.Accumulator\n\tparseNodeInfo(&acc, stats, \"127.0.0.1:3000\", \"TestNodeName\")\n\tacc.AssertContainsTaggedFields(t, \"aerospike_node\", expectedFields, expectedTags)\n}\n\nfunc TestParseNamespaceInfo(t *testing.T) {\n\tstats := map[string]string{\n\t\t\"namespace/test\": \"ns_cluster_size=1;effective_replication_factor=1;objects=2;tombstones=0;master_objects=2\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"ns_cluster_size\":              int64(1),\n\t\t\"effective_replication_factor\": int64(1),\n\t\t\"tombstones\":                   int64(0),\n\t\t\"objects\":                      int64(2),\n\t\t\"master_objects\":               int64(2),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"aerospike_host\": \"127.0.0.1:3000\",\n\t\t\"node_name\":      \"TestNodeName\",\n\t\t\"namespace\":      \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\tparseNamespaceInfo(&acc, stats, \"127.0.0.1:3000\", \"test\", \"TestNodeName\")\n\tacc.AssertContainsTaggedFields(t, \"aerospike_namespace\", expectedFields, expectedTags)\n}\n\nfunc TestParseSetInfo(t *testing.T) {\n\tstats := map[string]string{\n\t\t\"sets/test/foo\": \"objects=1:tombstones=0:memory_data_bytes=26;\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"objects\":           int64(1),\n\t\t\"tombstones\":        int64(0),\n\t\t\"memory_data_bytes\": int64(26),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"aerospike_host\": \"127.0.0.1:3000\",\n\t\t\"node_name\":      \"TestNodeName\",\n\t\t\"set\":            \"test/foo\",\n\t}\n\n\tvar acc testutil.Accumulator\n\tparseSetInfo(&acc, stats, \"127.0.0.1:3000\", \"test/foo\", \"TestNodeName\")\n\tacc.AssertContainsTaggedFields(t, \"aerospike_set\", expectedFields, expectedTags)\n}\n\nfunc TestParseHistogramSet(t *testing.T) {\n\ta := &Aerospike{\n\t\tNumberHistogramBuckets: 10,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tstats := map[string]string{\n\t\t\"histogram:type=object-size-linear;namespace=test;set=foo\": \"units=bytes:hist-width=1048576:bucket-width=1024:buckets=0,1,3,1,6,1,9,1,12,1,15,1,18\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"0\": int64(1),\n\t\t\"1\": int64(4),\n\t\t\"2\": int64(7),\n\t\t\"3\": int64(10),\n\t\t\"4\": int64(13),\n\t\t\"5\": int64(16),\n\t\t\"6\": int64(18),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"aerospike_host\": \"127.0.0.1:3000\",\n\t\t\"node_name\":      \"TestNodeName\",\n\t\t\"namespace\":      \"test\",\n\t\t\"set\":            \"foo\",\n\t}\n\n\tnTags := createTags(\"127.0.0.1:3000\", \"TestNodeName\", \"test\", \"foo\")\n\ta.parseHistogram(&acc, stats, nTags, \"object-size-linear\")\n\tacc.AssertContainsTaggedFields(t, \"aerospike_histogram_object_size_linear\", expectedFields, expectedTags)\n}\n\nfunc TestParseHistogramNamespace(t *testing.T) {\n\ta := &Aerospike{\n\t\tNumberHistogramBuckets: 10,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tstats := map[string]string{\n\t\t\"histogram:type=object-size-linear;namespace=test;set=foo\": \" units=bytes:hist-width=1048576:bucket-width=1024:buckets=0,1,3,1,6,1,9,1,12,1,15,1,18\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"0\": int64(1),\n\t\t\"1\": int64(4),\n\t\t\"2\": int64(7),\n\t\t\"3\": int64(10),\n\t\t\"4\": int64(13),\n\t\t\"5\": int64(16),\n\t\t\"6\": int64(18),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"aerospike_host\": \"127.0.0.1:3000\",\n\t\t\"node_name\":      \"TestNodeName\",\n\t\t\"namespace\":      \"test\",\n\t}\n\n\tnTags := createTags(\"127.0.0.1:3000\", \"TestNodeName\", \"test\", \"\")\n\ta.parseHistogram(&acc, stats, nTags, \"object-size-linear\")\n\tacc.AssertContainsTaggedFields(t, \"aerospike_histogram_object_size_linear\", expectedFields, expectedTags)\n}\n\nfunc TestAerospikeParseValue(t *testing.T) {\n\t// uint64 with value bigger than int64 max\n\tval := parseAerospikeValue(\"\", \"18446744041841121751\")\n\trequire.Equal(t, uint64(18446744041841121751), val)\n\n\tval = parseAerospikeValue(\"\", \"true\")\n\tv, ok := val.(bool)\n\trequire.Truef(t, ok, \"bool type expected, got '%T' with '%v' value instead\", val, val)\n\trequire.True(t, v)\n\n\t// int values\n\tval = parseAerospikeValue(\"\", \"42\")\n\trequire.Equal(t, int64(42), val, \"must be parsed as an int64\")\n\n\t// string values\n\tval = parseAerospikeValue(\"\", \"BB977942A2CA502\")\n\trequire.Equal(t, `BB977942A2CA502`, val, \"must be left as a string\")\n\n\t// all digit hex values, unprotected\n\tval = parseAerospikeValue(\"\", \"1992929191\")\n\trequire.Equal(t, int64(1992929191), val, \"must be parsed as an int64\")\n\n\t// all digit hex values, protected\n\tval = parseAerospikeValue(\"node_name\", \"1992929191\")\n\trequire.Equal(t, `1992929191`, val, \"must be left as a string\")\n}\n\nfunc FindTagValue(acc *testutil.Accumulator, measurement, key, value string) bool {\n\tfor _, p := range acc.Metrics {\n\t\tif p.Measurement == measurement {\n\t\t\tv, ok := p.Tags[key]\n\t\t\tif ok && v == value {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "plugins/inputs/aerospike/sample.conf",
    "content": "# Read stats from aerospike server(s)\n[[inputs.aerospike]]\n  ## Aerospike servers to connect to (with port)\n  ## This plugin will query all namespaces the aerospike\n  ## server has configured and get stats for them.\n  servers = [\"localhost:3000\"]\n\n  # username = \"telegraf\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  # Feature Options\n  # Add namespace variable to limit the namespaces executed on\n  # Leave blank to do all\n  # disable_query_namespaces = true # default false\n  # namespaces = [\"namespace1\", \"namespace2\"]\n\n  # Enable set level telemetry\n  # query_sets = true # default: false\n  # Add namespace set combinations to limit sets executed on\n  # Leave blank to do all sets\n  # sets = [\"namespace1/set1\", \"namespace1/set2\", \"namespace3\"]\n\n  # Histograms\n  # enable_ttl_histogram = true # default: false\n  # enable_object_size_linear_histogram = true # default: false\n\n  # by default, aerospike produces a 100 bucket histogram\n  # this is not great for most graphing tools, this will allow\n  # the ability to squash this to a smaller number of buckets\n  # To have a balanced histogram, the number of buckets chosen\n  # should divide evenly into 100.\n  # num_histogram_buckets = 100 # default: 10\n"
  },
  {
    "path": "plugins/inputs/aerospike/sample.conf.in",
    "content": "# Read stats from aerospike server(s)\n[[inputs.aerospike]]\n  ## Aerospike servers to connect to (with port)\n  ## This plugin will query all namespaces the aerospike\n  ## server has configured and get stats for them.\n  servers = [\"localhost:3000\"]\n\n  # username = \"telegraf\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n{{template \"/plugins/common/tls/client.conf\"}}\n\n  # Feature Options\n  # Add namespace variable to limit the namespaces executed on\n  # Leave blank to do all\n  # disable_query_namespaces = true # default false\n  # namespaces = [\"namespace1\", \"namespace2\"]\n\n  # Enable set level telemetry\n  # query_sets = true # default: false\n  # Add namespace set combinations to limit sets executed on\n  # Leave blank to do all sets\n  # sets = [\"namespace1/set1\", \"namespace1/set2\", \"namespace3\"]\n\n  # Histograms\n  # enable_ttl_histogram = true # default: false\n  # enable_object_size_linear_histogram = true # default: false\n\n  # by default, aerospike produces a 100 bucket histogram\n  # this is not great for most graphing tools, this will allow\n  # the ability to squash this to a smaller number of buckets\n  # To have a balanced histogram, the number of buckets chosen\n  # should divide evenly into 100.\n  # num_histogram_buckets = 100 # default: 10\n"
  },
  {
    "path": "plugins/inputs/aliyuncms/README.md",
    "content": "# Alibaba Cloud Monitor Service (Aliyun) Input Plugin\n\nThis plugin gathers statistics from the\n[Alibaba / Aliyun cloud monitoring service][alibaba]. In the following we will\nuse `Aliyun` instead of `Alibaba` as it's the default naming across the web\nconsole and docs.\n\n⭐ Telegraf v1.19.0\n🏷️ cloud\n💻 all\n\n[alibaba]: https://www.alibabacloud.com\n\n## Aliyun Authentication\n\nThis plugin uses an [AccessKey][1] credential for Authentication with the\nAliyun OpenAPI endpoint.  In the following order the plugin will attempt\nto authenticate.\n\n1. Ram RoleARN credential if `access_key_id`, `access_key_secret`, `role_arn`,\n   `role_session_name` is specified\n2. AccessKey STS token credential if `access_key_id`, `access_key_secret`,\n   `access_key_sts_token` is specified\n3. AccessKey credential if `access_key_id`, `access_key_secret` is specified\n4. Ecs Ram Role Credential if `role_name` is specified\n5. RSA keypair credential if `private_key`, `public_key_id` is specified\n6. Environment variables credential\n7. Instance metadata credential\n\n[1]: https://www.alibabacloud.com/help/doc-detail/53045.htm?spm=a2c63.p38356.b99.127.5cba21fdt5MJKr&parentId=28572\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Pull Metric Statistics from Aliyun CMS\n[[inputs.aliyuncms]]\n  ## Aliyun Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Ram RoleArn credential\n  ## 2) AccessKey STS token credential\n  ## 3) AccessKey credential\n  ## 4) Ecs Ram Role credential\n  ## 5) RSA keypair credential\n  ## 6) Environment variables credential\n  ## 7) Instance metadata credential\n\n  # access_key_id = \"\"\n  # access_key_secret = \"\"\n  # access_key_sts_token = \"\"\n  # role_arn = \"\"\n  # role_session_name = \"\"\n  # private_key = \"\"\n  # public_key_id = \"\"\n  # role_name = \"\"\n\n  ## Specify ali cloud regions to be queried for metric and object discovery\n  ## If not set, all supported regions (see below) would be covered, it can\n  ## provide a significant load on API, so the recommendation here is to\n  ## limit the list as much as possible.\n  ## Allowed values: https://www.alibabacloud.com/help/zh/doc-detail/40654.htm\n  ## Default supported regions are:\n  ##   cn-qingdao,cn-beijing,cn-zhangjiakou,cn-huhehaote,cn-hangzhou,\n  ##   cn-shanghai, cn-shenzhen, cn-heyuan,cn-chengdu,cn-hongkong,\n  ##   ap-southeast-1,ap-southeast-2,ap-southeast-3,ap-southeast-5,\n  ##   ap-south-1,ap-northeast-1, us-west-1,us-east-1,eu-central-1,\n  ##   eu-west-1,me-east-1\n  ##\n  ## From discovery perspective it set the scope for object discovery,\n  ## the discovered info can be used to enrich the metrics with objects\n  ##  attributes/tags. Discovery is not supported for all projects.\n  ## Currently, discovery supported for the following projects:\n  ## - acs_ecs_dashboard\n  ## - acs_rds_dashboard\n  ## - acs_slb_dashboard\n  ## - acs_vpc_eip\n  regions = [\"cn-hongkong\"]\n\n  ## Requested AliyunCMS aggregation Period (required)\n  ## The period must be multiples of 60s and the minimum for AliyunCMS metrics\n  ## is 1 minute (60s). However not all metrics are made available to the\n  ## one minute period. Some are collected at 3 minute, 5 minute, or larger\n  ## intervals.\n  ## See: https://help.aliyun.com/document_detail/51936.html?spm=a2c4g.11186623.2.18.2bc1750eeOw1Pv\n  ## Note that if a period is configured that is smaller than the minimum for\n  ## a particular metric, that metric will not be returned by Aliyun's\n  ## OpenAPI and will not be collected by Telegraf.\n  period = \"5m\"\n\n  ## Collection Delay (required)\n  ## The delay must account for metrics availability via AliyunCMS API.\n  delay = \"1m\"\n\n  ## Recommended: use metric 'interval' that is a multiple of 'period'\n  ## to avoid gaps or overlap in pulled data\n  interval = \"5m\"\n\n  ## Metric Statistic Project (required)\n  project = \"acs_slb_dashboard\"\n\n  ## Maximum requests per second, default value is 200\n  ratelimit = 200\n\n  ## How often the discovery API call executed (default 1m)\n  #discovery_interval = \"1m\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Metrics to Pull\n  ## At least one metrics definition required\n  [[inputs.aliyuncms.metrics]]\n    ## Metrics names to be requested,\n    ## Description can be found here (per project):\n    ## https://help.aliyun.com/document_detail/28619.html?spm=a2c4g.11186623.6.690.1938ad41wg8QSq\n    names = [\"InstanceActiveConnection\", \"InstanceNewConnection\"]\n\n    ## Dimension filters for Metric (optional)\n    ## This allows to get additional metric dimension. If dimension is not\n    ## specified it can be returned or the data can be aggregated - it depends\n    ## on particular metric, you can find details here:\n    ##   https://help.aliyun.com/document_detail/28619.html?spm=a2c4g.11186623.6.690.1938ad41wg8QSq\n    ##\n    ## Note, that by default dimension filter includes the list of discovered\n    ## objects in scope (if discovery is enabled). Values specified here would\n    ## be added into the list of discovered objects. You can specify either\n    ## single dimension:\n    # dimensions = '{\"instanceId\": \"p-example\"}'\n\n    ## Or you can specify several dimensions at once:\n    # dimensions = '[{\"instanceId\": \"p-example\"},{\"instanceId\": \"q-example\"}]'\n\n    ## Tag Query Path\n    ## The following tags added by default:\n    ##   * regionId (if discovery enabled)\n    ##   * userId\n    ##   * instanceId\n    ## Enrichment tags, can be added from discovery (if supported)\n    ## Notation is\n    ##   <measurement_tag_name>:<JMES query path (https://jmespath.org/tutorial.html)>\n    ## To figure out which fields are available, consult the\n    ## Describe<ObjectType> API per project. For example, for SLB see:\n    ##   https://api.aliyun.com/#/?product=Slb&version=2014-05-15&api=DescribeLoadBalancers&params={}&tab=MOCK&lang=GO\n    # tag_query_path = [\n    #    \"address:Address\",\n    #    \"name:LoadBalancerName\",\n    #    \"cluster_owner:Tags.Tag[?TagKey=='cs.cluster.name'].TagValue | [0]\"\n    #    ]\n\n    ## Allow metrics without discovery data, if discovery is enabled.\n    ## If set to true, then metric without discovery data would be emitted, otherwise dropped.\n    ## This cane be of help, in case debugging dimension filters, or partial coverage of\n    ## discovery scope vs monitoring scope\n    # allow_dps_without_discovery = false\n```\n\n### Requirements and Terminology\n\nPlugin Configuration utilizes [preset metric items references][2]\n\n- `discovery_region` must be a valid Aliyun\n  [Region](https://www.alibabacloud.com/help/doc-detail/40654.htm) value\n- `period` must be a valid duration value\n- `project` must be a preset project value\n- `names` must be preset metric names\n- `dimensions` must be preset dimension values\n\n[2]: https://www.alibabacloud.com/help/doc-detail/28619.htm?spm=a2c63.p38356.a3.2.389f233d0kPJn0\n\n## Metrics\n\nEach Aliyun CMS Project monitored records a measurement with fields for each\navailable Metric Statistic Project and Metrics are represented in [snake\ncase](https://en.wikipedia.org/wiki/Snake_case)\n\n- aliyuncms_{project}\n  - {metric}_average     (metric Average value)\n  - {metric}_minimum     (metric Minimum value)\n  - {metric}_maximum     (metric Maximum value)\n  - {metric}_value       (metric Value value)\n\n## Example Output\n\n```text\naliyuncms_acs_slb_dashboard,instanceId=p-example,regionId=cn-hangzhou,userId=1234567890 latency_average=0.004810798017284538,latency_maximum=0.1100282669067383,latency_minimum=0.0006084442138671875\n```\n"
  },
  {
    "path": "plugins/inputs/aliyuncms/aliyuncms.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage aliyuncms\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/providers\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/cms\"\n\t\"github.com/jmespath/go-jmespath\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/limiter\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype (\n\tAliyunCMS struct {\n\t\tAccessKeyID       string `toml:\"access_key_id\"`\n\t\tAccessKeySecret   string `toml:\"access_key_secret\"`\n\t\tAccessKeyStsToken string `toml:\"access_key_sts_token\"`\n\t\tRoleArn           string `toml:\"role_arn\"`\n\t\tRoleSessionName   string `toml:\"role_session_name\"`\n\t\tPrivateKey        string `toml:\"private_key\"`\n\t\tPublicKeyID       string `toml:\"public_key_id\"`\n\t\tRoleName          string `toml:\"role_name\"`\n\n\t\tRegions           []string        `toml:\"regions\"`\n\t\tDiscoveryInterval config.Duration `toml:\"discovery_interval\"`\n\t\tPeriod            config.Duration `toml:\"period\"`\n\t\tDelay             config.Duration `toml:\"delay\"`\n\t\tProject           string          `toml:\"project\"`\n\t\tMetrics           []*metric       `toml:\"metrics\"`\n\t\tRateLimit         int             `toml:\"ratelimit\"`\n\n\t\tLog telegraf.Logger `toml:\"-\"`\n\n\t\tclient        aliyuncmsClient\n\t\twindowStart   time.Time\n\t\twindowEnd     time.Time\n\t\tdt            *discoveryTool\n\t\tdimensionKey  string\n\t\tdiscoveryData map[string]interface{}\n\t\tmeasurement   string\n\t}\n\n\t// metric describes what metrics to get\n\tmetric struct {\n\t\tObjectsFilter                 string   `toml:\"objects_filter\"`\n\t\tMetricNames                   []string `toml:\"names\"`\n\t\tDimensions                    string   `toml:\"dimensions\"` // String representation of JSON dimensions\n\t\tTagsQueryPath                 []string `toml:\"tag_query_path\"`\n\t\tAllowDataPointWODiscoveryData bool     `toml:\"allow_dps_without_discovery\"` // Allow data points without discovery data (if no discovery data found)\n\n\t\tdtLock               sync.Mutex                   // Guard for discoveryTags & dimensions\n\t\tdiscoveryTags        map[string]map[string]string // Internal data structure that can enrich metrics with tags\n\t\tdimensionsUdObj      map[string]string\n\t\tdimensionsUdArr      []map[string]string // Parsed Dimesnsions JSON string (unmarshalled)\n\t\trequestDimensions    []map[string]string // this is the actual dimensions list that would be used in API request\n\t\trequestDimensionsStr string              // String representation of the above\n\n\t}\n\n\taliyuncmsClient interface {\n\t\tDescribeMetricList(request *cms.DescribeMetricListRequest) (response *cms.DescribeMetricListResponse, err error)\n\t}\n)\n\n// https://www.alibabacloud.com/help/doc-detail/40654.htm?gclid=Cj0KCQjw4dr0BRCxARIsAKUNjWTAMfyVUn_Y3OevFBV3CMaazrhq0URHsgE7c0m0SeMQRKlhlsJGgIEaAviyEALw_wcB\nvar aliyunRegionList = []string{\n\t\"cn-qingdao\",\n\t\"cn-beijing\",\n\t\"cn-zhangjiakou\",\n\t\"cn-huhehaote\",\n\t\"cn-hangzhou\",\n\t\"cn-shanghai\",\n\t\"cn-shenzhen\",\n\t\"cn-heyuan\",\n\t\"cn-chengdu\",\n\t\"cn-hongkong\",\n\t\"ap-southeast-1\",\n\t\"ap-southeast-2\",\n\t\"ap-southeast-3\",\n\t\"ap-southeast-5\",\n\t\"ap-south-1\",\n\t\"ap-northeast-1\",\n\t\"us-west-1\",\n\t\"us-east-1\",\n\t\"eu-central-1\",\n\t\"eu-west-1\",\n\t\"me-east-1\",\n}\n\nfunc (*AliyunCMS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *AliyunCMS) Init() error {\n\tif s.Project == \"\" {\n\t\treturn errors.New(\"project is not set\")\n\t}\n\n\tvar (\n\t\troleSessionExpiration = 600\n\t\tsessionExpiration     = 600\n\t)\n\tconfiguration := &providers.Configuration{\n\t\tAccessKeyID:           s.AccessKeyID,\n\t\tAccessKeySecret:       s.AccessKeySecret,\n\t\tAccessKeyStsToken:     s.AccessKeyStsToken,\n\t\tRoleArn:               s.RoleArn,\n\t\tRoleSessionName:       s.RoleSessionName,\n\t\tRoleSessionExpiration: &roleSessionExpiration,\n\t\tPrivateKey:            s.PrivateKey,\n\t\tPublicKeyID:           s.PublicKeyID,\n\t\tSessionExpiration:     &sessionExpiration,\n\t\tRoleName:              s.RoleName,\n\t}\n\tcredentialProviders := []providers.Provider{\n\t\tproviders.NewConfigurationCredentialProvider(configuration),\n\t\tproviders.NewEnvCredentialProvider(),\n\t\tproviders.NewInstanceMetadataProvider(),\n\t}\n\tcredential, err := providers.NewChainProvider(credentialProviders).Retrieve()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to retrieve credential: %w\", err)\n\t}\n\ts.client, err = cms.NewClientWithOptions(\"\", sdk.NewConfig(), credential)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cms client: %w\", err)\n\t}\n\n\t// check metrics dimensions consistency\n\tfor i := range s.Metrics {\n\t\tmetric := s.Metrics[i]\n\t\tif metric.Dimensions == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tmetric.dimensionsUdObj = make(map[string]string)\n\t\tmetric.dimensionsUdArr = make([]map[string]string, 0)\n\n\t\t// first try to unmarshal as an object\n\t\tif err := json.Unmarshal([]byte(metric.Dimensions), &metric.dimensionsUdObj); err == nil {\n\t\t\t// We were successful, so stop here\n\t\t\tcontinue\n\t\t}\n\n\t\t// then try to unmarshal as an array\n\t\tif err := json.Unmarshal([]byte(metric.Dimensions), &metric.dimensionsUdArr); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot parse dimensions (neither obj, nor array) %q: %w\", metric.Dimensions, err)\n\t\t}\n\t}\n\n\ts.measurement = formatMeasurement(s.Project)\n\n\t// Check regions\n\tif len(s.Regions) == 0 {\n\t\ts.Regions = aliyunRegionList\n\t\ts.Log.Infof(\"'regions' is not set. Metrics will be queried across %d regions:\\n%s\",\n\t\t\tlen(s.Regions), strings.Join(s.Regions, \",\"))\n\t}\n\n\t// Init discovery...\n\tif s.dt == nil { // Support for tests\n\t\ts.dt, err = newDiscoveryTool(s.Regions, s.Project, s.Log, credential, int(float32(s.RateLimit)*0.2), time.Duration(s.DiscoveryInterval))\n\t\tif err != nil {\n\t\t\ts.Log.Errorf(\"Discovery tool is not activated: %v\", err)\n\t\t\ts.dt = nil\n\t\t\treturn nil\n\t\t}\n\t}\n\n\ts.discoveryData, err = s.dt.getDiscoveryDataAcrossRegions(nil)\n\tif err != nil {\n\t\ts.Log.Errorf(\"Discovery tool is not activated: %v\", err)\n\t\ts.dt = nil\n\t\treturn nil\n\t}\n\n\ts.Log.Infof(\"%d object(s) discovered...\", len(s.discoveryData))\n\n\t//  Special setting for acs_oss project since the API differs\n\tif s.Project == \"acs_oss\" {\n\t\ts.dimensionKey = \"BucketName\"\n\t}\n\n\treturn nil\n}\n\n// Start plugin discovery loop, metrics are gathered through Gather\nfunc (s *AliyunCMS) Start(telegraf.Accumulator) error {\n\t// Start periodic discovery process\n\tif s.dt != nil {\n\t\ts.dt.start()\n\t}\n\n\treturn nil\n}\n\nfunc (s *AliyunCMS) Gather(acc telegraf.Accumulator) error {\n\ts.updateWindow(time.Now())\n\n\t// limit concurrency or we can easily exhaust user connection limit\n\tlmtr := limiter.NewRateLimiter(s.RateLimit, time.Second)\n\tdefer lmtr.Stop()\n\n\tvar wg sync.WaitGroup\n\tfor _, m := range s.Metrics {\n\t\t// Prepare internal structure with data from discovery\n\t\ts.prepareTagsAndDimensions(m)\n\t\twg.Add(len(m.MetricNames))\n\t\tfor _, metricName := range m.MetricNames {\n\t\t\t<-lmtr.C\n\t\t\tgo func(metricName string, m *metric) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tacc.AddError(s.gatherMetric(acc, metricName, m))\n\t\t\t}(metricName, m)\n\t\t}\n\t\twg.Wait()\n\t}\n\n\treturn nil\n}\n\n// Stop - stops the plugin discovery loop\nfunc (s *AliyunCMS) Stop() {\n\tif s.dt != nil {\n\t\ts.dt.stop()\n\t}\n}\n\nfunc (s *AliyunCMS) updateWindow(relativeTo time.Time) {\n\t// https://help.aliyun.com/document_detail/51936.html?spm=a2c4g.11186623.6.701.54025679zh6wiR\n\t// The start and end times are executed in the mode of\n\t// opening left and closing right, and startTime cannot be equal\n\t// to or greater than endTime.\n\n\twindowEnd := relativeTo.Add(-time.Duration(s.Delay))\n\n\tif s.windowEnd.IsZero() {\n\t\t// this is the first run, no window info, so just get a single period\n\t\ts.windowStart = windowEnd.Add(-time.Duration(s.Period))\n\t} else {\n\t\t// subsequent window, start where last window left off\n\t\ts.windowStart = s.windowEnd\n\t}\n\n\ts.windowEnd = windowEnd\n}\n\n// Gather given metric and emit error\nfunc (s *AliyunCMS) gatherMetric(acc telegraf.Accumulator, metricName string, metric *metric) error {\n\tfor _, region := range s.Regions {\n\t\treq := cms.CreateDescribeMetricListRequest()\n\t\treq.Period = strconv.FormatInt(int64(time.Duration(s.Period).Seconds()), 10)\n\t\treq.MetricName = metricName\n\t\treq.Length = \"10000\"\n\t\treq.Namespace = s.Project\n\t\treq.EndTime = strconv.FormatInt(s.windowEnd.Unix()*1000, 10)\n\t\treq.StartTime = strconv.FormatInt(s.windowStart.Unix()*1000, 10)\n\t\treq.Dimensions = metric.requestDimensionsStr\n\t\treq.RegionId = region\n\n\t\tfor more := true; more; {\n\t\t\tresp, err := s.client.DescribeMetricList(req)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to query metricName list: %w\", err)\n\t\t\t}\n\t\t\tif resp.Code != \"200\" {\n\t\t\t\ts.Log.Errorf(\"failed to query metricName list: %v\", resp.Message)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tvar datapoints []map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(resp.Datapoints), &datapoints); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to decode response datapoints: %w\", err)\n\t\t\t}\n\n\t\t\tif len(datapoints) == 0 {\n\t\t\t\ts.Log.Debugf(\"No metrics returned from CMS, response msg: %s\", resp.Message)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\tNextDataPoint:\n\t\t\tfor _, datapoint := range datapoints {\n\t\t\t\tfields := make(map[string]interface{}, len(datapoint))\n\t\t\t\ttags := make(map[string]string, len(datapoint))\n\t\t\t\tdatapointTime := int64(0)\n\t\t\t\tfor key, value := range datapoint {\n\t\t\t\t\tswitch key {\n\t\t\t\t\tcase \"instanceId\", \"BucketName\":\n\t\t\t\t\t\ttags[key] = value.(string)\n\t\t\t\t\t\tif metric.discoveryTags != nil { // discovery can be not activated\n\t\t\t\t\t\t\t// Skipping data point if discovery data not exist\n\t\t\t\t\t\t\t_, ok := metric.discoveryTags[value.(string)]\n\t\t\t\t\t\t\tif !ok &&\n\t\t\t\t\t\t\t\t!metric.AllowDataPointWODiscoveryData {\n\t\t\t\t\t\t\t\ts.Log.Warnf(\"Instance %q is not found in discovery, skipping monitoring datapoint...\", value.(string))\n\t\t\t\t\t\t\t\tcontinue NextDataPoint\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfor k, v := range metric.discoveryTags[value.(string)] {\n\t\t\t\t\t\t\t\ttags[k] = v\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\tcase \"userId\":\n\t\t\t\t\t\ttags[key] = value.(string)\n\t\t\t\t\tcase \"timestamp\":\n\t\t\t\t\t\tdatapointTime = int64(value.(float64)) / 1000\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tfields[formatField(metricName, key)] = value\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tacc.AddFields(s.measurement, fields, tags, time.Unix(datapointTime, 0))\n\t\t\t}\n\n\t\t\treq.NextToken = resp.NextToken\n\t\t\tmore = req.NextToken != \"\"\n\t\t}\n\t}\n\treturn nil\n}\n\n// tag helper\nfunc parseTag(tagSpec string, data interface{}) (tagKey, tagValue string, err error) {\n\tvar (\n\t\tok        bool\n\t\tqueryPath = tagSpec\n\t)\n\ttagKey = tagSpec\n\n\t// Split query path to tagKey and query path\n\tif splitted := strings.Split(tagSpec, \":\"); len(splitted) == 2 {\n\t\ttagKey = splitted[0]\n\t\tqueryPath = splitted[1]\n\t}\n\n\ttagRawValue, err := jmespath.Search(queryPath, data)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"can't query data from discovery data using query path %q: %w\", queryPath, err)\n\t}\n\n\tif tagRawValue == nil { // Nothing found\n\t\treturn \"\", \"\", nil\n\t}\n\n\ttagValue, ok = tagRawValue.(string)\n\tif !ok {\n\t\treturn \"\", \"\", fmt.Errorf(\"tag value %q parsed by query %q is not a string value\", tagRawValue, queryPath)\n\t}\n\n\treturn tagKey, tagValue, nil\n}\n\nfunc (s *AliyunCMS) prepareTagsAndDimensions(metric *metric) {\n\tvar (\n\t\tnewData     bool\n\t\tdefaultTags = []string{\"RegionId:RegionId\"}\n\t)\n\n\tif s.dt == nil { // Discovery is not activated\n\t\treturn\n\t}\n\n\t// Reading all data from buffered channel\nL:\n\tfor {\n\t\tselect {\n\t\tcase s.discoveryData = <-s.dt.dataChan:\n\t\t\tnewData = true\n\t\t\tcontinue\n\t\tdefault:\n\t\t\tbreak L\n\t\t}\n\t}\n\n\t// new data arrives (so process it) or this is the first call\n\tif newData || len(metric.discoveryTags) == 0 {\n\t\tmetric.dtLock.Lock()\n\t\tdefer metric.dtLock.Unlock()\n\n\t\tif metric.discoveryTags == nil {\n\t\t\tmetric.discoveryTags = make(map[string]map[string]string, len(s.discoveryData))\n\t\t}\n\n\t\tmetric.requestDimensions = nil // erasing\n\t\tmetric.requestDimensions = make([]map[string]string, 0, len(s.discoveryData))\n\n\t\t// Preparing tags & dims...\n\t\tfor instanceID, elem := range s.discoveryData {\n\t\t\t// Start filing tags\n\t\t\t// Remove old value if exist\n\t\t\tdelete(metric.discoveryTags, instanceID)\n\t\t\tmetric.discoveryTags[instanceID] = make(map[string]string, len(metric.TagsQueryPath)+len(defaultTags))\n\n\t\t\tfor _, tagQueryPath := range metric.TagsQueryPath {\n\t\t\t\ttagKey, tagValue, err := parseTag(tagQueryPath, elem)\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.Log.Errorf(\"%v\", err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err == nil && tagValue == \"\" { // Nothing found\n\t\t\t\t\ts.Log.Debugf(\"Data by query path %q: is not found, for instance %q\", tagQueryPath, instanceID)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tmetric.discoveryTags[instanceID][tagKey] = tagValue\n\t\t\t}\n\n\t\t\t// Adding default tags if not already there\n\t\t\tfor _, defaultTagQP := range defaultTags {\n\t\t\t\ttagKey, tagValue, err := parseTag(defaultTagQP, elem)\n\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.Log.Errorf(\"%v\", err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err == nil && tagValue == \"\" { // Nothing found\n\t\t\t\t\ts.Log.Debugf(\"Data by query path %q: is not found, for instance %q\",\n\t\t\t\t\t\tdefaultTagQP, instanceID)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tmetric.discoveryTags[instanceID][tagKey] = tagValue\n\t\t\t}\n\n\t\t\t// if no dimension configured in config file, use discovery data\n\t\t\tif len(metric.dimensionsUdArr) == 0 && len(metric.dimensionsUdObj) == 0 {\n\t\t\t\tmetric.requestDimensions = append(\n\t\t\t\t\tmetric.requestDimensions,\n\t\t\t\t\tmap[string]string{s.dimensionKey: instanceID})\n\t\t\t}\n\t\t}\n\n\t\t// add dimensions filter from config file\n\t\tif len(metric.dimensionsUdArr) != 0 {\n\t\t\tmetric.requestDimensions = append(metric.requestDimensions, metric.dimensionsUdArr...)\n\t\t}\n\t\tif len(metric.dimensionsUdObj) != 0 {\n\t\t\tmetric.requestDimensions = append(metric.requestDimensions, metric.dimensionsUdObj)\n\t\t}\n\n\t\t// Unmarshalling to string\n\t\treqDim, err := json.Marshal(metric.requestDimensions)\n\t\tif err != nil {\n\t\t\ts.Log.Errorf(\"Can't marshal metric request dimensions %v :%v\",\n\t\t\t\tmetric.requestDimensions, err)\n\t\t\tmetric.requestDimensionsStr = \"\"\n\t\t} else {\n\t\t\tmetric.requestDimensionsStr = string(reqDim)\n\t\t}\n\t}\n}\n\n// Formatting helpers\nfunc formatField(metricName, statistic string) string {\n\tif metricName == statistic {\n\t\tstatistic = \"value\"\n\t}\n\treturn fmt.Sprintf(\"%s_%s\", snakeCase(metricName), snakeCase(statistic))\n}\n\nfunc formatMeasurement(project string) string {\n\tproject = strings.ReplaceAll(project, \"/\", \"_\")\n\tproject = snakeCase(project)\n\treturn \"aliyuncms_\" + project\n}\n\nfunc snakeCase(s string) string {\n\ts = internal.SnakeCase(s)\n\ts = strings.ReplaceAll(s, \"__\", \"_\")\n\treturn s\n}\n\nfunc init() {\n\tinputs.Add(\"aliyuncms\", func() telegraf.Input {\n\t\treturn &AliyunCMS{\n\t\t\tRateLimit:         200,\n\t\t\tDiscoveryInterval: config.Duration(time.Minute),\n\t\t\tdimensionKey:      \"instanceId\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/aliyuncms/aliyuncms_test.go",
    "content": "package aliyuncms\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/providers\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/cms\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst inputTitle = \"inputs.aliyuncms\"\n\ntype mockGatherAliyunCMSClient struct{}\n\nfunc (*mockGatherAliyunCMSClient) DescribeMetricList(request *cms.DescribeMetricListRequest) (*cms.DescribeMetricListResponse, error) {\n\tresp := new(cms.DescribeMetricListResponse)\n\n\t// switch request.Metric {\n\tswitch request.MetricName {\n\tcase \"InstanceActiveConnection\":\n\t\tresp.Code = \"200\"\n\t\tresp.Period = \"60\"\n\t\tresp.Datapoints = `\n\t\t[{\n\t\t\t\"timestamp\": 1490152860000,\n\t\t\t\"Maximum\": 200,\n\t\t\t\"userId\": \"1234567898765432\",\n\t\t\t\"Minimum\": 100,\n\t\t\t\"instanceId\": \"i-abcdefgh123456\",\n\t\t\t\"Average\": 150,\n\t\t\t\"Value\": 300\n\t\t}]`\n\tcase \"ErrorCode\":\n\t\tresp.Code = \"404\"\n\t\tresp.Message = \"ErrorCode\"\n\tcase \"ErrorDatapoint\":\n\t\tresp.Code = \"200\"\n\t\tresp.Period = \"60\"\n\t\tresp.Datapoints = `\n\t\t[{\n\t\t\t\"timestamp\": 1490152860000,\n\t\t\t\"Maximum\": 200,\n\t\t\t\"userId\": \"1234567898765432\",\n\t\t\t\"Minimum\": 100,\n\t\t\t\"instanceId\": \"i-abcdefgh123456\",\n\t\t\t\"Average\": 150,\n\t\t}]`\n\tcase \"EmptyDatapoint\":\n\t\tresp.Code = \"200\"\n\t\tresp.Period = \"60\"\n\t\tresp.Datapoints = `[]`\n\tcase \"ErrorResp\":\n\t\treturn nil, errors.New(\"error response\")\n\t}\n\treturn resp, nil\n}\n\ntype mockAliyunSDKCli struct {\n\tresp *responses.CommonResponse\n}\n\nfunc (m *mockAliyunSDKCli) ProcessCommonRequest(_ *requests.CommonRequest) (response *responses.CommonResponse, err error) {\n\treturn m.resp, nil\n}\n\nfunc getDiscoveryTool(project string, discoverRegions []string) (*discoveryTool, error) {\n\tvar (\n\t\terr        error\n\t\tcredential auth.Credential\n\t)\n\n\tconfiguration := &providers.Configuration{\n\t\tAccessKeyID:     \"dummyKey\",\n\t\tAccessKeySecret: \"dummySecret\",\n\t}\n\tcredentialProviders := []providers.Provider{\n\t\tproviders.NewConfigurationCredentialProvider(configuration),\n\t\tproviders.NewEnvCredentialProvider(),\n\t\tproviders.NewInstanceMetadataProvider(),\n\t}\n\tcredential, err = providers.NewChainProvider(credentialProviders).Retrieve()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to retrieve credential: %w\", err)\n\t}\n\n\tdt, err := newDiscoveryTool(discoverRegions, project, testutil.Logger{Name: inputTitle}, credential, 1, time.Minute*2)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't create discovery tool object: %w\", err)\n\t}\n\treturn dt, nil\n}\n\nfunc getMockSdkCli(httpResp *http.Response) (mockAliyunSDKCli, error) {\n\tresp := responses.NewCommonResponse()\n\tif err := responses.Unmarshal(resp, httpResp, \"JSON\"); err != nil {\n\t\treturn mockAliyunSDKCli{}, fmt.Errorf(\"can't parse response: %w\", err)\n\t}\n\treturn mockAliyunSDKCli{resp: resp}, nil\n}\n\nfunc TestPluginDefaults(t *testing.T) {\n\trequire.Equal(t, &AliyunCMS{RateLimit: 200,\n\t\tDiscoveryInterval: config.Duration(time.Minute),\n\t\tdimensionKey:      \"instanceId\",\n\t}, inputs.Inputs[\"aliyuncms\"]())\n}\n\nfunc TestPluginInitialize(t *testing.T) {\n\tvar err error\n\n\tplugin := new(AliyunCMS)\n\tplugin.Log = testutil.Logger{Name: inputTitle}\n\tplugin.Regions = []string{\"cn-shanghai\"}\n\tplugin.dt, err = getDiscoveryTool(\"acs_slb_dashboard\", plugin.Regions)\n\tif err != nil {\n\t\tt.Fatalf(\"Can't create discovery tool object: %v\", err)\n\t}\n\n\thttpResp := &http.Response{\n\t\tStatusCode: 200,\n\t\tBody: io.NopCloser(bytes.NewBufferString(\n\t\t\t`{\n\t\t\t\t\t\t\"LoadBalancers\":\n\t\t\t\t\t\t {\n\t\t\t\t\t\t  \"LoadBalancer\": [\n \t\t\t\t\t\t\t {\"LoadBalancerId\":\"bla\"}\n                           ]\n                         },\n\t\t\t\t\t\t\"TotalCount\": 1,\n\t\t\t\t\t\t\"PageSize\": 1,\n\t\t\t\t\t\t\"PageNumber\": 1\n\t\t\t\t\t\t}`)),\n\t}\n\tmockCli, err := getMockSdkCli(httpResp)\n\tif err != nil {\n\t\tt.Fatalf(\"Can't create mock sdk cli: %v\", err)\n\t}\n\tplugin.dt.cli = map[string]aliyunSdkClient{plugin.Regions[0]: &mockCli}\n\n\ttests := []struct {\n\t\tname                string\n\t\tproject             string\n\t\taccessKeyID         string\n\t\taccessKeySecret     string\n\t\texpectedErrorString string\n\t\tregions             []string\n\t\tdiscoveryRegions    []string\n\t}{\n\t\t{\n\t\t\tname:                \"Empty project\",\n\t\t\texpectedErrorString: \"project is not set\",\n\t\t\tregions:             []string{\"cn-shanghai\"},\n\t\t},\n\t\t{\n\t\t\tname:            \"Valid project\",\n\t\t\tproject:         \"acs_slb_dashboard\",\n\t\t\tregions:         []string{\"cn-shanghai\"},\n\t\t\taccessKeyID:     \"dummy\",\n\t\t\taccessKeySecret: \"dummy\",\n\t\t},\n\t\t{\n\t\t\tname:            \"'regions' is not set\",\n\t\t\tproject:         \"acs_slb_dashboard\",\n\t\t\taccessKeyID:     \"dummy\",\n\t\t\taccessKeySecret: \"dummy\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin.Project = tt.project\n\t\t\tplugin.AccessKeyID = tt.accessKeyID\n\t\t\tplugin.AccessKeySecret = tt.accessKeySecret\n\t\t\tplugin.Regions = tt.regions\n\n\t\t\tif tt.expectedErrorString != \"\" {\n\t\t\t\trequire.EqualError(t, plugin.Init(), tt.expectedErrorString)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, plugin.Init())\n\t\t\t}\n\t\t\tif len(tt.regions) == 0 { // Check if set to default\n\t\t\t\trequire.Equal(t, plugin.Regions, aliyunRegionList)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPluginMetricsInitialize(t *testing.T) {\n\tvar err error\n\n\tplugin := new(AliyunCMS)\n\tplugin.Log = testutil.Logger{Name: inputTitle}\n\tplugin.Regions = []string{\"cn-shanghai\"}\n\tplugin.dt, err = getDiscoveryTool(\"acs_slb_dashboard\", plugin.Regions)\n\tif err != nil {\n\t\tt.Fatalf(\"Can't create discovery tool object: %v\", err)\n\t}\n\n\thttpResp := &http.Response{\n\t\tStatusCode: 200,\n\t\tBody: io.NopCloser(bytes.NewBufferString(\n\t\t\t`{\n\t\t\t\t\"LoadBalancers\":\n\t\t\t\t\t{\n\t\t\t\t\t\t\"LoadBalancer\": [\n \t\t\t\t\t\t\t{\"LoadBalancerId\":\"bla\"}\n                        ]\n                    },\n\t\t\t\t\"TotalCount\": 1,\n\t\t\t\t\"PageSize\": 1,\n\t\t\t\t\"PageNumber\": 1\n\t\t\t}`)),\n\t}\n\tmockCli, err := getMockSdkCli(httpResp)\n\tif err != nil {\n\t\tt.Fatalf(\"Can't create mock sdk cli: %v\", err)\n\t}\n\tplugin.dt.cli = map[string]aliyunSdkClient{plugin.Regions[0]: &mockCli}\n\n\ttests := []struct {\n\t\tname                string\n\t\tproject             string\n\t\taccessKeyID         string\n\t\taccessKeySecret     string\n\t\texpectedErrorString string\n\t\tregions             []string\n\t\tdiscoveryRegions    []string\n\t\tmetrics             []*metric\n\t}{\n\t\t{\n\t\t\tname:            \"Valid project\",\n\t\t\tproject:         \"acs_slb_dashboard\",\n\t\t\tregions:         []string{\"cn-shanghai\"},\n\t\t\taccessKeyID:     \"dummy\",\n\t\t\taccessKeySecret: \"dummy\",\n\t\t\tmetrics: []*metric{\n\t\t\t\t{\n\t\t\t\t\tDimensions: `{\"instanceId\": \"i-abcdefgh123456\"}`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"Valid project\",\n\t\t\tproject:         \"acs_slb_dashboard\",\n\t\t\tregions:         []string{\"cn-shanghai\"},\n\t\t\taccessKeyID:     \"dummy\",\n\t\t\taccessKeySecret: \"dummy\",\n\t\t\tmetrics: []*metric{\n\t\t\t\t{\n\t\t\t\t\tDimensions: `[{\"instanceId\": \"p-example\"},{\"instanceId\": \"q-example\"}]`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:                \"Valid project\",\n\t\t\tproject:             \"acs_slb_dashboard\",\n\t\t\tregions:             []string{\"cn-shanghai\"},\n\t\t\taccessKeyID:         \"dummy\",\n\t\t\taccessKeySecret:     \"dummy\",\n\t\t\texpectedErrorString: `cannot parse dimensions (neither obj, nor array) \"[\": unexpected end of JSON input`,\n\t\t\tmetrics: []*metric{\n\t\t\t\t{\n\t\t\t\t\tDimensions: `[`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin.Project = tt.project\n\t\t\tplugin.AccessKeyID = tt.accessKeyID\n\t\t\tplugin.AccessKeySecret = tt.accessKeySecret\n\t\t\tplugin.Regions = tt.regions\n\t\t\tplugin.Metrics = tt.metrics\n\n\t\t\tif tt.expectedErrorString != \"\" {\n\t\t\t\trequire.EqualError(t, plugin.Init(), tt.expectedErrorString)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, plugin.Init())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUpdateWindow(t *testing.T) {\n\tduration, err := time.ParseDuration(\"1m\")\n\trequire.NoError(t, err)\n\tinternalDuration := config.Duration(duration)\n\n\tplugin := &AliyunCMS{\n\t\tProject: \"acs_slb_dashboard\",\n\t\tPeriod:  internalDuration,\n\t\tDelay:   internalDuration,\n\t\tLog:     testutil.Logger{Name: inputTitle},\n\t}\n\n\tnow := time.Now()\n\n\trequire.True(t, plugin.windowEnd.IsZero())\n\trequire.True(t, plugin.windowStart.IsZero())\n\n\tplugin.updateWindow(now)\n\n\tnewStartTime := plugin.windowEnd\n\n\t// initial window just has a single period\n\trequire.EqualValues(t, plugin.windowEnd, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, plugin.windowStart, now.Add(-time.Duration(plugin.Delay)).Add(-time.Duration(plugin.Period)))\n\n\tnow = time.Now()\n\tplugin.updateWindow(now)\n\n\t// subsequent window uses previous end time as start time\n\trequire.EqualValues(t, plugin.windowEnd, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, plugin.windowStart, newStartTime)\n}\n\nfunc TestGatherMetric(t *testing.T) {\n\tplugin := &AliyunCMS{\n\t\tProject:     \"acs_slb_dashboard\",\n\t\tclient:      new(mockGatherAliyunCMSClient),\n\t\tmeasurement: formatMeasurement(\"acs_slb_dashboard\"),\n\t\tLog:         testutil.Logger{Name: inputTitle},\n\t\tRegions:     []string{\"cn-shanghai\"},\n\t}\n\n\tmetric := &metric{\n\t\tDimensions: `\"instanceId\": \"i-abcdefgh123456\"`,\n\t}\n\n\ttests := []struct {\n\t\tname                string\n\t\tmetricName          string\n\t\texpectedErrorString string\n\t}{\n\t\t{\n\t\t\tname:                \"Datapoint with corrupted JSON\",\n\t\t\tmetricName:          \"ErrorDatapoint\",\n\t\t\texpectedErrorString: `failed to decode response datapoints: invalid character '}' looking for beginning of object key string`,\n\t\t},\n\t\t{\n\t\t\tname:                \"General CMS response error\",\n\t\t\tmetricName:          \"ErrorResp\",\n\t\t\texpectedErrorString: \"failed to query metricName list: error response\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc telegraf.Accumulator\n\t\t\trequire.EqualError(t, plugin.gatherMetric(acc, tt.metricName, metric), tt.expectedErrorString)\n\t\t})\n\t}\n}\n\nfunc TestGather(t *testing.T) {\n\tm := &metric{\n\t\tDimensions: `{\"instanceId\": \"i-abcdefgh123456\"}`,\n\t}\n\tplugin := &AliyunCMS{\n\t\tAccessKeyID:     \"my_access_key_id\",\n\t\tAccessKeySecret: \"my_access_key_secret\",\n\t\tProject:         \"acs_slb_dashboard\",\n\t\tMetrics:         []*metric{m},\n\t\tRateLimit:       200,\n\t\tmeasurement:     formatMeasurement(\"acs_slb_dashboard\"),\n\t\tRegions:         []string{\"cn-shanghai\"},\n\t\tclient:          new(mockGatherAliyunCMSClient),\n\t\tLog:             testutil.Logger{Name: inputTitle},\n\t}\n\n\t// test table:\n\ttests := []struct {\n\t\tname           string\n\t\thasMeasurement bool\n\t\tmetricNames    []string\n\t\texpected       []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:        \"Empty data point\",\n\t\t\tmetricNames: []string{\"EmptyDatapoint\"},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"aliyuncms_acs_slb_dashboard\",\n\t\t\t\t\tnil,\n\t\t\t\t\tnil,\n\t\t\t\t\ttime.Time{}),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:           \"Data point with fields & tags\",\n\t\t\thasMeasurement: true,\n\t\t\tmetricNames:    []string{\"InstanceActiveConnection\"},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"aliyuncms_acs_slb_dashboard\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"instanceId\": \"i-abcdefgh123456\",\n\t\t\t\t\t\t\"userId\":     \"1234567898765432\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"instance_active_connection_minimum\": float64(100),\n\t\t\t\t\t\t\"instance_active_connection_maximum\": float64(200),\n\t\t\t\t\t\t\"instance_active_connection_average\": float64(150),\n\t\t\t\t\t\t\"instance_active_connection_value\":   float64(300),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1490152860000, 0)),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin.Metrics[0].MetricNames = tt.metricNames\n\t\t\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\t\t\trequire.Equal(t, acc.HasMeasurement(\"aliyuncms_acs_slb_dashboard\"), tt.hasMeasurement)\n\t\t\tif tt.hasMeasurement {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"aliyuncms_acs_slb_dashboard\", tt.expected[0].Fields(), tt.expected[0].Tags())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetDiscoveryDataAcrossRegions(t *testing.T) {\n\t// test table:\n\ttests := []struct {\n\t\tname                string\n\t\tproject             string\n\t\tregion              string\n\t\thttpResp            *http.Response\n\t\tdiscData            map[string]interface{}\n\t\ttotalCount          int\n\t\tpageSize            int\n\t\tpageNumber          int\n\t\texpectedErrorString string\n\t}{\n\t\t{\n\t\t\tname:    \"No root key in discovery response\",\n\t\t\tproject: \"acs_slb_dashboard\",\n\t\t\tregion:  \"cn-hongkong\",\n\t\t\thttpResp: &http.Response{\n\t\t\t\tStatusCode: 200,\n\t\t\t\tBody:       io.NopCloser(bytes.NewBufferString(`{}`)),\n\t\t\t},\n\t\t\ttotalCount:          0,\n\t\t\tpageSize:            0,\n\t\t\tpageNumber:          0,\n\t\t\texpectedErrorString: `didn't find root key \"LoadBalancers\" in discovery response`,\n\t\t},\n\t\t{\n\t\t\tname:    \"1 object discovered\",\n\t\t\tproject: \"acs_slb_dashboard\",\n\t\t\tregion:  \"cn-hongkong\",\n\t\t\thttpResp: &http.Response{\n\t\t\t\tStatusCode: 200,\n\t\t\t\tBody: io.NopCloser(bytes.NewBufferString(\n\t\t\t\t\t`{\n\t\t\t\t\t\t\"LoadBalancers\":\n\t\t\t\t\t\t {\n\t\t\t\t\t\t  \"LoadBalancer\": [\n \t\t\t\t\t\t\t {\"LoadBalancerId\":\"bla\"}\n                           ]\n                         },\n\t\t\t\t\t\t\"TotalCount\": 1,\n\t\t\t\t\t\t\"PageSize\": 1,\n\t\t\t\t\t\t\"PageNumber\": 1\n\t\t\t\t\t\t}`)),\n\t\t\t},\n\t\t\tdiscData:            map[string]interface{}{\"bla\": map[string]interface{}{\"LoadBalancerId\": \"bla\"}},\n\t\t\ttotalCount:          1,\n\t\t\tpageSize:            1,\n\t\t\tpageNumber:          1,\n\t\t\texpectedErrorString: \"\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdt, err := getDiscoveryTool(tt.project, []string{tt.region})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"Can't create discovery tool object: %v\", err)\n\t\t\t}\n\n\t\t\tmockCli, err := getMockSdkCli(tt.httpResp)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"Can't create mock sdk cli: %v\", err)\n\t\t\t}\n\t\t\tdt.cli = map[string]aliyunSdkClient{tt.region: &mockCli}\n\t\t\tdata, err := dt.getDiscoveryDataAcrossRegions(nil)\n\n\t\t\trequire.Equal(t, tt.discData, data)\n\t\t\tif err != nil {\n\t\t\t\trequire.EqualError(t, err, tt.expectedErrorString)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/aliyuncms/discovery.go",
    "content": "package aliyuncms\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/rds\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/slb\"\n\t\"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/limiter\"\n)\n\ntype discoveryRequest interface {\n}\n\ntype aliyunSdkClient interface {\n\tProcessCommonRequest(req *requests.CommonRequest) (response *responses.CommonResponse, err error)\n}\n\n// discoveryTool is an object that provides discovery feature\ntype discoveryTool struct {\n\treq                map[string]discoveryRequest // Discovery request (specific per object type)\n\trateLimit          int                         // Rate limit for API query, as it is limited by API backend\n\treqDefaultPageSize int                         // Default page size while querying data from API (how many objects per request)\n\tcli                map[string]aliyunSdkClient  // API client, which perform discovery request\n\n\trespRootKey     string // Root key in JSON response where to look for discovery data\n\trespObjectIDKey string // Key in element of array under root key, that stores object ID\n\t// for, the majority of cases it would be InstanceId, for OSS it is BucketName. This key is also used in dimension filtering\n\twg       sync.WaitGroup              // WG for primary discovery goroutine\n\tinterval time.Duration               // Discovery interval\n\tdone     chan bool                   // Done channel to stop primary discovery goroutine\n\tdataChan chan map[string]interface{} // Discovery data\n\tlg       telegraf.Logger             // Telegraf logger (should be provided)\n}\n\ntype parsedDResp struct {\n\tdata       []interface{}\n\ttotalCount int\n\tpageSize   int\n\tpageNumber int\n}\n\n// getRPCReqFromDiscoveryRequest - utility function to map between aliyun request primitives\n// discoveryRequest represents different type of discovery requests\nfunc getRPCReqFromDiscoveryRequest(req discoveryRequest) (*requests.RpcRequest, error) {\n\tif reflect.ValueOf(req).Type().Kind() != reflect.Ptr ||\n\t\treflect.ValueOf(req).IsNil() {\n\t\treturn nil, fmt.Errorf(\"unexpected type of the discovery request object: %q, %q\", reflect.ValueOf(req).Type(), reflect.ValueOf(req).Kind())\n\t}\n\n\tptrV := reflect.Indirect(reflect.ValueOf(req))\n\n\tfor i := 0; i < ptrV.NumField(); i++ {\n\t\tif ptrV.Field(i).Type().String() == \"*requests.RpcRequest\" {\n\t\t\tif !ptrV.Field(i).CanInterface() {\n\t\t\t\treturn nil, fmt.Errorf(\"can't get interface of %q\", ptrV.Field(i))\n\t\t\t}\n\n\t\t\trpcReq, ok := ptrV.Field(i).Interface().(*requests.RpcRequest)\n\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"can't convert interface of %q to '*requests.RpcRequest' type\", ptrV.Field(i).Interface())\n\t\t\t}\n\n\t\t\treturn rpcReq, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"didn't find *requests.RpcRequest embedded struct in %q\", ptrV.Type())\n}\n\n// newDiscoveryTool function returns discovery tool object.\n// The object is used to periodically get data about aliyun objects and send this\n// data into channel. The intention is to enrich reported metrics with discovery data.\n// Discovery is supported for a limited set of object types (defined by project) and can be extended in future.\n// Discovery can be limited by region if not set, then all regions is queried.\n// Request against API can inquire additional costs, consult with aliyun API documentation.\nfunc newDiscoveryTool(\n\tregions []string,\n\tproject string,\n\tlg telegraf.Logger,\n\tcredential auth.Credential,\n\trateLimit int,\n\tdiscoveryInterval time.Duration,\n) (*discoveryTool, error) {\n\tvar (\n\t\tresponseRootKey       string\n\t\tresponseObjectIDKey   string\n\t\terr                   error\n\t\tnoDiscoverySupportErr = fmt.Errorf(\"no discovery support for project %q\", project)\n\t)\n\n\tif len(regions) == 0 {\n\t\tregions = aliyunRegionList\n\t\tlg.Infof(\"'regions' is not provided! Discovery data will be queried across %d regions:\\n%s\",\n\t\t\tlen(aliyunRegionList), strings.Join(aliyunRegionList, \",\"))\n\t}\n\n\tif rateLimit == 0 { // Can be a rounding case\n\t\trateLimit = 1\n\t}\n\n\tdscReq := make(map[string]discoveryRequest, len(regions))\n\tcli := make(map[string]aliyunSdkClient, len(regions))\n\tfor _, region := range regions {\n\t\tswitch project {\n\t\tcase \"acs_ecs_dashboard\":\n\t\t\tdscReq[region] = ecs.CreateDescribeInstancesRequest()\n\t\t\tresponseRootKey = \"Instances\"\n\t\t\tresponseObjectIDKey = \"InstanceId\"\n\t\tcase \"acs_rds_dashboard\":\n\t\t\tdscReq[region] = rds.CreateDescribeDBInstancesRequest()\n\t\t\tresponseRootKey = \"Items\"\n\t\t\tresponseObjectIDKey = \"DBInstanceId\"\n\t\tcase \"acs_slb_dashboard\":\n\t\t\tdscReq[region] = slb.CreateDescribeLoadBalancersRequest()\n\t\t\tresponseRootKey = \"LoadBalancers\"\n\t\t\tresponseObjectIDKey = \"LoadBalancerId\"\n\t\tcase \"acs_memcache\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_ocs\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_oss\":\n\t\t\t// oss is really complicated and its' own format\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_vpc_eip\":\n\t\t\tdscReq[region] = vpc.CreateDescribeEipAddressesRequest()\n\t\t\tresponseRootKey = \"EipAddresses\"\n\t\t\tresponseObjectIDKey = \"AllocationId\"\n\t\tcase \"acs_kvstore\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_mns_new\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_cdn\":\n\t\t\t// API replies are in its own format.\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_polardb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_gdb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_ads\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_mongodb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_express_connect\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_fc\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_nat_gateway\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_sls_dashboard\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_containerservice_dashboard\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_vpn\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_bandwidth_package\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_cen\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_ens\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_opensearch\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_scdn\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_drds\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_iot\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_directmail\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_elasticsearch\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_ess_dashboard\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_streamcompute\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_global_acceleration\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_hitsdb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_kafka\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_openad\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_pcdn\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_dcdn\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_petadata\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_videolive\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_hybriddb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_adb\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_mps\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_maxcompute_prepay\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_hdfs\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_ddh\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_hbr\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_hdr\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tcase \"acs_cds\":\n\t\t\treturn nil, noDiscoverySupportErr\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"project %q is not recognized by discovery\", project)\n\t\t}\n\n\t\tcli[region], err = sdk.NewClientWithOptions(region, sdk.NewConfig(), credential)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif len(dscReq) == 0 || len(cli) == 0 {\n\t\treturn nil, fmt.Errorf(\"can't build discovery request for project: %q, regions: %v\", project, regions)\n\t}\n\n\treturn &discoveryTool{\n\t\treq:                dscReq,\n\t\tcli:                cli,\n\t\trespRootKey:        responseRootKey,\n\t\trespObjectIDKey:    responseObjectIDKey,\n\t\trateLimit:          rateLimit,\n\t\tinterval:           discoveryInterval,\n\t\treqDefaultPageSize: 20,\n\t\tdataChan:           make(chan map[string]interface{}, 1),\n\t\tlg:                 lg,\n\t}, nil\n}\n\nfunc (dt *discoveryTool) parseDiscoveryResponse(resp *responses.CommonResponse) (*parsedDResp, error) {\n\tvar (\n\t\tfullOutput    = make(map[string]interface{})\n\t\tdata          []byte\n\t\tfoundDataItem bool\n\t\tfoundRootKey  bool\n\t\tpdResp        = &parsedDResp{}\n\t)\n\n\tdata = resp.GetHttpContentBytes()\n\tif data == nil { // No data\n\t\treturn nil, errors.New(\"no data in response to be parsed\")\n\t}\n\n\tif err := json.Unmarshal(data, &fullOutput); err != nil {\n\t\treturn nil, fmt.Errorf(\"can't parse JSON from discovery response: %w\", err)\n\t}\n\n\tfor key, val := range fullOutput {\n\t\tswitch key {\n\t\tcase dt.respRootKey:\n\t\t\tfoundRootKey = true\n\t\t\trootKeyVal, ok := val.(map[string]interface{})\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"content of root key %q, is not an object: %q\", key, val)\n\t\t\t}\n\n\t\t\t// It should contain the array with discovered data\n\t\t\tfor _, item := range rootKeyVal {\n\t\t\t\tif pdResp.data, foundDataItem = item.([]interface{}); foundDataItem {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !foundDataItem {\n\t\t\t\treturn nil, fmt.Errorf(\"didn't find array item in root key %q\", key)\n\t\t\t}\n\t\tcase \"TotalCount\", \"TotalRecordCount\":\n\t\t\tpdResp.totalCount = int(val.(float64))\n\t\tcase \"PageSize\", \"PageRecordCount\":\n\t\t\tpdResp.pageSize = int(val.(float64))\n\t\tcase \"PageNumber\":\n\t\t\tpdResp.pageNumber = int(val.(float64))\n\t\t}\n\t}\n\tif !foundRootKey {\n\t\treturn nil, fmt.Errorf(\"didn't find root key %q in discovery response\", dt.respRootKey)\n\t}\n\n\treturn pdResp, nil\n}\n\nfunc (dt *discoveryTool) getDiscoveryData(cli aliyunSdkClient, req *requests.CommonRequest, lmtr chan bool) (map[string]interface{}, error) {\n\tvar (\n\t\terr           error\n\t\tresp          *responses.CommonResponse\n\t\tpDResp        *parsedDResp\n\t\tdiscoveryData []interface{}\n\t\ttotalCount    int\n\t\tpageNumber    int\n\t)\n\tdefer delete(req.QueryParams, \"PageNumber\")\n\n\tfor {\n\t\tif lmtr != nil {\n\t\t\t<-lmtr // Rate limiting\n\t\t}\n\n\t\tresp, err = cli.ProcessCommonRequest(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tpDResp, err = dt.parseDiscoveryResponse(resp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdiscoveryData = append(discoveryData, pDResp.data...)\n\t\tpageNumber = pDResp.pageNumber\n\t\ttotalCount = pDResp.totalCount\n\n\t\t// Pagination\n\t\tpageNumber++\n\t\treq.QueryParams[\"PageNumber\"] = strconv.Itoa(pageNumber)\n\n\t\tif len(discoveryData) == totalCount { // All data received\n\t\t\t// Map data to the appropriate shape before return\n\t\t\tpreparedData := make(map[string]interface{}, len(discoveryData))\n\n\t\t\tfor _, raw := range discoveryData {\n\t\t\t\telem, ok := raw.(map[string]interface{})\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, errors.New(\"can't parse input data element, not a map[string]interface{} type\")\n\t\t\t\t}\n\t\t\t\tif objectID, ok := elem[dt.respObjectIDKey].(string); ok {\n\t\t\t\t\tpreparedData[objectID] = elem\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn preparedData, nil\n\t\t}\n\t}\n}\n\nfunc (dt *discoveryTool) getDiscoveryDataAcrossRegions(lmtr chan bool) (map[string]interface{}, error) {\n\tresultData := make(map[string]interface{})\n\n\tfor region, cli := range dt.cli {\n\t\t// Building common request, as the code below is the same no matter\n\t\t// which aliyun object type (project) is used\n\t\tdscReq, ok := dt.req[region]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"error building common discovery request: not valid region %q\", region)\n\t\t}\n\n\t\trpcReq, err := getRPCReqFromDiscoveryRequest(dscReq)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcommonRequest := requests.NewCommonRequest()\n\t\tcommonRequest.Method = rpcReq.GetMethod()\n\t\tcommonRequest.Product = rpcReq.GetProduct()\n\t\tcommonRequest.Domain = rpcReq.GetDomain()\n\t\tcommonRequest.Version = rpcReq.GetVersion()\n\t\tcommonRequest.Scheme = rpcReq.GetScheme()\n\t\tcommonRequest.ApiName = rpcReq.GetActionName()\n\t\tcommonRequest.QueryParams = rpcReq.QueryParams\n\t\tcommonRequest.QueryParams[\"PageSize\"] = strconv.Itoa(dt.reqDefaultPageSize)\n\t\tcommonRequest.TransToAcsRequest()\n\n\t\t// Get discovery data using common request\n\t\tdata, err := dt.getDiscoveryData(cli, commonRequest, lmtr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor k, v := range data {\n\t\t\tresultData[k] = v\n\t\t}\n\t}\n\treturn resultData, nil\n}\n\n// start the discovery pooling; in case something new is found, it will be reported back through `dataChan`\nfunc (dt *discoveryTool) start() {\n\tvar (\n\t\terr      error\n\t\tdata     map[string]interface{}\n\t\tlastData map[string]interface{}\n\t)\n\n\t// Initializing channel\n\tdt.done = make(chan bool)\n\n\tdt.wg.Add(1)\n\tgo func() {\n\t\tdefer dt.wg.Done()\n\n\t\tticker := time.NewTicker(dt.interval)\n\t\tdefer ticker.Stop()\n\n\t\tlmtr := limiter.NewRateLimiter(dt.rateLimit, time.Second)\n\t\tdefer lmtr.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-dt.done:\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\tdata, err = dt.getDiscoveryDataAcrossRegions(lmtr.C)\n\t\t\t\tif err != nil {\n\t\t\t\t\tdt.lg.Errorf(\"Can't get discovery data: %v\", err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif !reflect.DeepEqual(data, lastData) {\n\t\t\t\t\tlastData = make(map[string]interface{}, len(data))\n\t\t\t\t\tfor k, v := range data {\n\t\t\t\t\t\tlastData[k] = v\n\t\t\t\t\t}\n\n\t\t\t\t\t// send discovery data in blocking mode\n\t\t\t\t\tdt.dataChan <- data\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// stop the discovery loop, making sure all data is read from 'dataChan'\nfunc (dt *discoveryTool) stop() {\n\tclose(dt.done)\n\n\t// Shutdown timer\n\ttimer := time.NewTimer(time.Second * 3)\n\tdefer timer.Stop()\nL:\n\tfor { // Unblock go routine by reading from dt.dataChan\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\tbreak L\n\t\tcase <-dt.dataChan:\n\t\t}\n\t}\n\n\tdt.wg.Wait()\n}\n"
  },
  {
    "path": "plugins/inputs/aliyuncms/sample.conf",
    "content": "# Pull Metric Statistics from Aliyun CMS\n[[inputs.aliyuncms]]\n  ## Aliyun Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Ram RoleArn credential\n  ## 2) AccessKey STS token credential\n  ## 3) AccessKey credential\n  ## 4) Ecs Ram Role credential\n  ## 5) RSA keypair credential\n  ## 6) Environment variables credential\n  ## 7) Instance metadata credential\n\n  # access_key_id = \"\"\n  # access_key_secret = \"\"\n  # access_key_sts_token = \"\"\n  # role_arn = \"\"\n  # role_session_name = \"\"\n  # private_key = \"\"\n  # public_key_id = \"\"\n  # role_name = \"\"\n\n  ## Specify ali cloud regions to be queried for metric and object discovery\n  ## If not set, all supported regions (see below) would be covered, it can\n  ## provide a significant load on API, so the recommendation here is to\n  ## limit the list as much as possible.\n  ## Allowed values: https://www.alibabacloud.com/help/zh/doc-detail/40654.htm\n  ## Default supported regions are:\n  ##   cn-qingdao,cn-beijing,cn-zhangjiakou,cn-huhehaote,cn-hangzhou,\n  ##   cn-shanghai, cn-shenzhen, cn-heyuan,cn-chengdu,cn-hongkong,\n  ##   ap-southeast-1,ap-southeast-2,ap-southeast-3,ap-southeast-5,\n  ##   ap-south-1,ap-northeast-1, us-west-1,us-east-1,eu-central-1,\n  ##   eu-west-1,me-east-1\n  ##\n  ## From discovery perspective it set the scope for object discovery,\n  ## the discovered info can be used to enrich the metrics with objects\n  ##  attributes/tags. Discovery is not supported for all projects.\n  ## Currently, discovery supported for the following projects:\n  ## - acs_ecs_dashboard\n  ## - acs_rds_dashboard\n  ## - acs_slb_dashboard\n  ## - acs_vpc_eip\n  regions = [\"cn-hongkong\"]\n\n  ## Requested AliyunCMS aggregation Period (required)\n  ## The period must be multiples of 60s and the minimum for AliyunCMS metrics\n  ## is 1 minute (60s). However not all metrics are made available to the\n  ## one minute period. Some are collected at 3 minute, 5 minute, or larger\n  ## intervals.\n  ## See: https://help.aliyun.com/document_detail/51936.html?spm=a2c4g.11186623.2.18.2bc1750eeOw1Pv\n  ## Note that if a period is configured that is smaller than the minimum for\n  ## a particular metric, that metric will not be returned by Aliyun's\n  ## OpenAPI and will not be collected by Telegraf.\n  period = \"5m\"\n\n  ## Collection Delay (required)\n  ## The delay must account for metrics availability via AliyunCMS API.\n  delay = \"1m\"\n\n  ## Recommended: use metric 'interval' that is a multiple of 'period'\n  ## to avoid gaps or overlap in pulled data\n  interval = \"5m\"\n\n  ## Metric Statistic Project (required)\n  project = \"acs_slb_dashboard\"\n\n  ## Maximum requests per second, default value is 200\n  ratelimit = 200\n\n  ## How often the discovery API call executed (default 1m)\n  #discovery_interval = \"1m\"\n\n  ## NOTE: Due to the way TOML is parsed, tables must be at the END of the\n  ## plugin definition, otherwise additional config options are read as part of\n  ## the table\n\n  ## Metrics to Pull\n  ## At least one metrics definition required\n  [[inputs.aliyuncms.metrics]]\n    ## Metrics names to be requested,\n    ## Description can be found here (per project):\n    ## https://help.aliyun.com/document_detail/28619.html?spm=a2c4g.11186623.6.690.1938ad41wg8QSq\n    names = [\"InstanceActiveConnection\", \"InstanceNewConnection\"]\n\n    ## Dimension filters for Metric (optional)\n    ## This allows to get additional metric dimension. If dimension is not\n    ## specified it can be returned or the data can be aggregated - it depends\n    ## on particular metric, you can find details here:\n    ##   https://help.aliyun.com/document_detail/28619.html?spm=a2c4g.11186623.6.690.1938ad41wg8QSq\n    ##\n    ## Note, that by default dimension filter includes the list of discovered\n    ## objects in scope (if discovery is enabled). Values specified here would\n    ## be added into the list of discovered objects. You can specify either\n    ## single dimension:\n    # dimensions = '{\"instanceId\": \"p-example\"}'\n\n    ## Or you can specify several dimensions at once:\n    # dimensions = '[{\"instanceId\": \"p-example\"},{\"instanceId\": \"q-example\"}]'\n\n    ## Tag Query Path\n    ## The following tags added by default:\n    ##   * regionId (if discovery enabled)\n    ##   * userId\n    ##   * instanceId\n    ## Enrichment tags, can be added from discovery (if supported)\n    ## Notation is\n    ##   <measurement_tag_name>:<JMES query path (https://jmespath.org/tutorial.html)>\n    ## To figure out which fields are available, consult the\n    ## Describe<ObjectType> API per project. For example, for SLB see:\n    ##   https://api.aliyun.com/#/?product=Slb&version=2014-05-15&api=DescribeLoadBalancers&params={}&tab=MOCK&lang=GO\n    # tag_query_path = [\n    #    \"address:Address\",\n    #    \"name:LoadBalancerName\",\n    #    \"cluster_owner:Tags.Tag[?TagKey=='cs.cluster.name'].TagValue | [0]\"\n    #    ]\n\n    ## Allow metrics without discovery data, if discovery is enabled.\n    ## If set to true, then metric without discovery data would be emitted, otherwise dropped.\n    ## This cane be of help, in case debugging dimension filters, or partial coverage of\n    ## discovery scope vs monitoring scope\n    # allow_dps_without_discovery = false\n"
  },
  {
    "path": "plugins/inputs/all/activemq.go",
    "content": "//go:build !custom || inputs || inputs.activemq\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/activemq\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/aerospike.go",
    "content": "//go:build !custom || inputs || inputs.aerospike\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/aerospike\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/aliyuncms.go",
    "content": "//go:build !custom || inputs || inputs.aliyuncms\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/aliyuncms\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/all.go",
    "content": "package all\n"
  },
  {
    "path": "plugins/inputs/all/amd_rocm_smi.go",
    "content": "//go:build !custom || inputs || inputs.amd_rocm_smi\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/amd_rocm_smi\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/amqp_consumer.go",
    "content": "//go:build !custom || inputs || inputs.amqp_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/amqp_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/apache.go",
    "content": "//go:build !custom || inputs || inputs.apache\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/apache\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/apcupsd.go",
    "content": "//go:build !custom || inputs || inputs.apcupsd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/apcupsd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/aurora.go",
    "content": "//go:build !custom || inputs || inputs.aurora\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/aurora\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/azure_monitor.go",
    "content": "//go:build !custom || inputs || inputs.azure_monitor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/azure_monitor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/azure_storage_queue.go",
    "content": "//go:build !custom || inputs || inputs.azure_storage_queue\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/azure_storage_queue\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/bcache.go",
    "content": "//go:build !custom || inputs || inputs.bcache\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/bcache\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/beanstalkd.go",
    "content": "//go:build !custom || inputs || inputs.beanstalkd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/beanstalkd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/beat.go",
    "content": "//go:build !custom || inputs || inputs.beat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/beat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/bind.go",
    "content": "//go:build !custom || inputs || inputs.bind\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/bind\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/bond.go",
    "content": "//go:build !custom || inputs || inputs.bond\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/bond\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/burrow.go",
    "content": "//go:build !custom || inputs || inputs.burrow\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/burrow\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ceph.go",
    "content": "//go:build !custom || inputs || inputs.ceph\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ceph\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cgroup.go",
    "content": "//go:build !custom || inputs || inputs.cgroup\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cgroup\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/chrony.go",
    "content": "//go:build !custom || inputs || inputs.chrony\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/chrony\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cisco_telemetry_mdt.go",
    "content": "//go:build !custom || inputs || inputs.cisco_telemetry_mdt\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cisco_telemetry_mdt\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/clickhouse.go",
    "content": "//go:build !custom || inputs || inputs.clickhouse\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/clickhouse\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cloud_pubsub.go",
    "content": "//go:build !custom || inputs || inputs.cloud_pubsub\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cloud_pubsub\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cloud_pubsub_push.go",
    "content": "//go:build !custom || inputs || inputs.cloud_pubsub_push\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cloud_pubsub_push\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cloudwatch.go",
    "content": "//go:build !custom || inputs || inputs.cloudwatch\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cloudwatch\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cloudwatch_metric_streams.go",
    "content": "//go:build !custom || inputs || inputs.cloudwatch_metric_streams\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cloudwatch_metric_streams\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/conntrack.go",
    "content": "//go:build !custom || inputs || inputs.conntrack\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/conntrack\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/consul.go",
    "content": "//go:build !custom || inputs || inputs.consul\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/consul\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/consul_agent.go",
    "content": "//go:build !custom || inputs || inputs.consul_agent\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/consul_agent\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/couchbase.go",
    "content": "//go:build !custom || inputs || inputs.couchbase\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/couchbase\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/couchdb.go",
    "content": "//go:build !custom || inputs || inputs.couchdb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/couchdb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/cpu.go",
    "content": "//go:build !custom || inputs || inputs.cpu\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/cpu\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/csgo.go",
    "content": "//go:build !custom || inputs || inputs.csgo\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/csgo\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ctrlx_datalayer.go",
    "content": "//go:build !custom || inputs || inputs.ctrlx_datalayer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ctrlx_datalayer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/dcos.go",
    "content": "//go:build !custom || inputs || inputs.dcos\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/dcos\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/directory_monitor.go",
    "content": "//go:build !custom || inputs || inputs.directory_monitor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/directory_monitor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/disk.go",
    "content": "//go:build !custom || inputs || inputs.disk\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/disk\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/diskio.go",
    "content": "//go:build !custom || inputs || inputs.diskio\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/diskio\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/disque.go",
    "content": "//go:build !custom || inputs || inputs.disque\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/disque\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/dmcache.go",
    "content": "//go:build !custom || inputs || inputs.dmcache\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/dmcache\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/dns_query.go",
    "content": "//go:build !custom || inputs || inputs.dns_query\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/dns_query\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/docker.go",
    "content": "//go:build !custom || inputs || inputs.docker\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/docker\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/docker_log.go",
    "content": "//go:build !custom || inputs || inputs.docker_log\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/docker_log\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/dovecot.go",
    "content": "//go:build !custom || inputs || inputs.dovecot\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/dovecot\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/dpdk.go",
    "content": "//go:build !custom || inputs || inputs.dpdk\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/dpdk\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ecs.go",
    "content": "//go:build !custom || inputs || inputs.ecs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ecs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/elasticsearch.go",
    "content": "//go:build !custom || inputs || inputs.elasticsearch\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/elasticsearch\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/elasticsearch_query.go",
    "content": "//go:build !custom || inputs || inputs.elasticsearch_query\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/elasticsearch_query\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ethtool.go",
    "content": "//go:build !custom || inputs || inputs.ethtool\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ethtool\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/eventhub_consumer.go",
    "content": "//go:build !custom || inputs || inputs.eventhub_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/eventhub_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/exec.go",
    "content": "//go:build !custom || inputs || inputs.exec\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/exec\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/execd.go",
    "content": "//go:build !custom || inputs || inputs.execd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/execd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/fail2ban.go",
    "content": "//go:build !custom || inputs || inputs.fail2ban\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/fail2ban\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/fibaro.go",
    "content": "//go:build !custom || inputs || inputs.fibaro\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/fibaro\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/file.go",
    "content": "//go:build !custom || inputs || inputs.file\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/file\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/filecount.go",
    "content": "//go:build !custom || inputs || inputs.filecount\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/filecount\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/filestat.go",
    "content": "//go:build !custom || inputs || inputs.filestat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/filestat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/fireboard.go",
    "content": "//go:build !custom || inputs || inputs.fireboard\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/fireboard\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/firehose.go",
    "content": "//go:build !custom || inputs || inputs.firehose\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/firehose\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/fluentd.go",
    "content": "//go:build !custom || inputs || inputs.fluentd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/fluentd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/fritzbox.go",
    "content": "//go:build !custom || inputs || inputs.fritzbox\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/fritzbox\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/github.go",
    "content": "//go:build !custom || inputs || inputs.github\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/github\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/gnmi.go",
    "content": "//go:build !custom || inputs || inputs.gnmi\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/gnmi\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/google_cloud_storage.go",
    "content": "//go:build !custom || inputs || inputs.google_cloud_storage\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/google_cloud_storage\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/graylog.go",
    "content": "//go:build !custom || inputs || inputs.graylog\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/graylog\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/haproxy.go",
    "content": "//go:build !custom || inputs || inputs.haproxy\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/haproxy\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/hddtemp.go",
    "content": "//go:build !custom || inputs || inputs.hddtemp\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/hddtemp\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/http.go",
    "content": "//go:build !custom || inputs || inputs.http\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/http\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/http_listener_v2.go",
    "content": "//go:build !custom || inputs || inputs.http_listener_v2\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/http_listener_v2\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/http_response.go",
    "content": "//go:build !custom || inputs || inputs.http_response\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/http_response\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/huebridge.go",
    "content": "//go:build !custom || inputs || inputs.huebridge\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/huebridge\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/hugepages.go",
    "content": "//go:build !custom || inputs || inputs.hugepages\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/hugepages\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/icinga2.go",
    "content": "//go:build !custom || inputs || inputs.icinga2\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/icinga2\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/infiniband.go",
    "content": "//go:build !custom || inputs || inputs.infiniband\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/infiniband\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/influxdb.go",
    "content": "//go:build !custom || inputs || inputs.influxdb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/influxdb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/influxdb_listener.go",
    "content": "//go:build !custom || inputs || inputs.influxdb_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/influxdb_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/influxdb_v2_listener.go",
    "content": "//go:build !custom || inputs || inputs.influxdb_v2_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/influxdb_v2_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_baseband.go",
    "content": "//go:build !custom || inputs || inputs.intel_baseband\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_baseband\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_dlb.go",
    "content": "//go:build !custom || inputs || inputs.intel_dlb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_dlb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_pmt.go",
    "content": "//go:build !custom || inputs || inputs.intel_pmt\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_pmt\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_pmu.go",
    "content": "//go:build !custom || inputs || inputs.intel_pmu\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_pmu\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_powerstat.go",
    "content": "//go:build !custom || inputs || inputs.intel_powerstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_powerstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/intel_rdt.go",
    "content": "//go:build !custom || inputs || inputs.intel_rdt\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/intel_rdt\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/internal.go",
    "content": "//go:build !custom || inputs || inputs.internal\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/internal\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/internet_speed.go",
    "content": "//go:build !custom || inputs || inputs.internet_speed\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/internet_speed\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/interrupts.go",
    "content": "//go:build !custom || inputs || inputs.interrupts\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/interrupts\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ipmi_sensor.go",
    "content": "//go:build !custom || inputs || inputs.ipmi_sensor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ipmi_sensor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ipset.go",
    "content": "//go:build !custom || inputs || inputs.ipset\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ipset\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/iptables.go",
    "content": "//go:build !custom || inputs || inputs.iptables\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/iptables\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ipvs.go",
    "content": "//go:build !custom || inputs || inputs.ipvs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ipvs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/jenkins.go",
    "content": "//go:build !custom || inputs || inputs.jenkins\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/jenkins\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/jolokia2_agent.go",
    "content": "//go:build !custom || inputs || inputs.jolokia2_agent\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/jolokia2_agent\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/jolokia2_proxy.go",
    "content": "//go:build !custom || inputs || inputs.jolokia2_proxy\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/jolokia2_proxy\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/jti_openconfig_telemetry.go",
    "content": "//go:build !custom || inputs || inputs.jti_openconfig_telemetry\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kafka_consumer.go",
    "content": "//go:build !custom || inputs || inputs.kafka_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kafka_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kapacitor.go",
    "content": "//go:build !custom || inputs || inputs.kapacitor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kapacitor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kernel.go",
    "content": "//go:build !custom || inputs || inputs.kernel\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kernel\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kernel_vmstat.go",
    "content": "//go:build !custom || inputs || inputs.kernel_vmstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kernel_vmstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kibana.go",
    "content": "//go:build !custom || inputs || inputs.kibana\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kibana\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kinesis_consumer.go",
    "content": "//go:build !custom || inputs || inputs.kinesis_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kinesis_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/knx_listener.go",
    "content": "//go:build !custom || inputs || inputs.knx_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/knx_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kube_inventory.go",
    "content": "//go:build !custom || inputs || inputs.kube_inventory\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kube_inventory\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/kubernetes.go",
    "content": "//go:build !custom || inputs || inputs.kubernetes\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/kubernetes\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/lanz.go",
    "content": "//go:build !custom || inputs || inputs.lanz\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/lanz\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ldap.go",
    "content": "//go:build !custom || inputs || inputs.ldap\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ldap\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/leofs.go",
    "content": "//go:build !custom || inputs || inputs.leofs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/leofs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/libvirt.go",
    "content": "//go:build !custom || inputs || inputs.libvirt\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/libvirt\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/linux_cpu.go",
    "content": "//go:build !custom || inputs || inputs.linux_cpu\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/linux_cpu\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/linux_sysctl_fs.go",
    "content": "//go:build !custom || inputs || inputs.linux_sysctl_fs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/linux_sysctl_fs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/logql.go",
    "content": "//go:build !custom || inputs || inputs.logql\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/logql\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/logstash.go",
    "content": "//go:build !custom || inputs || inputs.logstash\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/logstash\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/lustre2.go",
    "content": "//go:build !custom || inputs || inputs.lustre2\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/lustre2\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/lvm.go",
    "content": "//go:build !custom || inputs || inputs.lvm\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/lvm\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mailchimp.go",
    "content": "//go:build !custom || inputs || inputs.mailchimp\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mailchimp\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/marklogic.go",
    "content": "//go:build !custom || inputs || inputs.marklogic\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/marklogic\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mavlink.go",
    "content": "//go:build !custom || inputs || inputs.mavlink\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mavlink\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mcrouter.go",
    "content": "//go:build !custom || inputs || inputs.mcrouter\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mcrouter\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mdstat.go",
    "content": "//go:build !custom || inputs || inputs.mdstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mdstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mem.go",
    "content": "//go:build !custom || inputs || inputs.mem\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mem\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/memcached.go",
    "content": "//go:build !custom || inputs || inputs.memcached\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/memcached\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mesos.go",
    "content": "//go:build !custom || inputs || inputs.mesos\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mesos\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/minecraft.go",
    "content": "//go:build !custom || inputs || inputs.minecraft\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/minecraft\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mock.go",
    "content": "//go:build !custom || inputs || inputs.mock\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mock\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/modbus.go",
    "content": "//go:build !custom || inputs || inputs.modbus\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/modbus\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mongodb.go",
    "content": "//go:build !custom || inputs || inputs.mongodb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mongodb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/monit.go",
    "content": "//go:build !custom || inputs || inputs.monit\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/monit\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mqtt_consumer.go",
    "content": "//go:build !custom || inputs || inputs.mqtt_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mqtt_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/multifile.go",
    "content": "//go:build !custom || inputs || inputs.multifile\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/multifile\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/mysql.go",
    "content": "//go:build !custom || inputs || inputs.mysql\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/mysql\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nats.go",
    "content": "//go:build !custom || inputs || inputs.nats\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nats\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nats_consumer.go",
    "content": "//go:build !custom || inputs || inputs.nats_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nats_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/neoom_beaam.go",
    "content": "//go:build !custom || inputs || inputs.neoom_beaam\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/neoom_beaam\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/neptune_apex.go",
    "content": "//go:build !custom || inputs || inputs.neptune_apex\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/neptune_apex\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/net.go",
    "content": "//go:build !custom || inputs || inputs.net\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/net\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/net_response.go",
    "content": "//go:build !custom || inputs || inputs.net_response\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/net_response\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/netflow.go",
    "content": "//go:build !custom || inputs || inputs.netflow\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/netflow\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/netstat.go",
    "content": "//go:build !custom || inputs || inputs.netstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/netstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nfsclient.go",
    "content": "//go:build !custom || inputs || inputs.nfsclient\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nfsclient\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nftables.go",
    "content": "//go:build !custom || inputs || inputs.nftables\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nftables\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx.go",
    "content": "//go:build !custom || inputs || inputs.nginx\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx_plus.go",
    "content": "//go:build !custom || inputs || inputs.nginx_plus\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx_plus\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx_plus_api.go",
    "content": "//go:build !custom || inputs || inputs.nginx_plus_api\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx_plus_api\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx_sts.go",
    "content": "//go:build !custom || inputs || inputs.nginx_sts\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx_sts\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx_upstream_check.go",
    "content": "//go:build !custom || inputs || inputs.nginx_upstream_check\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx_upstream_check\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nginx_vts.go",
    "content": "//go:build !custom || inputs || inputs.nginx_vts\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nginx_vts\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nomad.go",
    "content": "//go:build !custom || inputs || inputs.nomad\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nomad\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nsd.go",
    "content": "//go:build !custom || inputs || inputs.nsd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nsd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nsdp.go",
    "content": "//go:build !custom || inputs || inputs.nsdp\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nsdp\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nsq.go",
    "content": "//go:build !custom || inputs || inputs.nsq\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nsq\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nsq_consumer.go",
    "content": "//go:build !custom || inputs || inputs.nsq_consumer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nsq_consumer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nstat.go",
    "content": "//go:build !custom || inputs || inputs.nstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ntpq.go",
    "content": "//go:build !custom || inputs || inputs.ntpq\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ntpq\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/nvidia_smi.go",
    "content": "//go:build !custom || inputs || inputs.nvidia_smi\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/nvidia_smi\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/opcua.go",
    "content": "//go:build !custom || inputs || inputs.opcua\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/opcua\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/opcua_listener.go",
    "content": "//go:build !custom || inputs || inputs.opcua_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/opcua_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/openldap.go",
    "content": "//go:build !custom || inputs || inputs.openldap\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/openldap\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/openntpd.go",
    "content": "//go:build !custom || inputs || inputs.openntpd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/openntpd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/opensearch_query.go",
    "content": "//go:build !custom || inputs || inputs.opensearch_query\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/opensearch_query\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/opensmtpd.go",
    "content": "//go:build !custom || inputs || inputs.opensmtpd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/opensmtpd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/openstack.go",
    "content": "//go:build !custom || inputs || inputs.openstack\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/openstack\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/opentelemetry.go",
    "content": "//go:build !custom || inputs || inputs.opentelemetry\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/opentelemetry\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/openweathermap.go",
    "content": "//go:build !custom || inputs || inputs.openweathermap\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/openweathermap\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/p4runtime.go",
    "content": "//go:build !custom || inputs || inputs.p4runtime\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/p4runtime\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/passenger.go",
    "content": "//go:build !custom || inputs || inputs.passenger\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/passenger\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/pf.go",
    "content": "//go:build !custom || inputs || inputs.pf\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/pf\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/pgbouncer.go",
    "content": "//go:build !custom || inputs || inputs.pgbouncer\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/pgbouncer\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/phpfpm.go",
    "content": "//go:build !custom || inputs || inputs.phpfpm\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/phpfpm\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ping.go",
    "content": "//go:build !custom || inputs || inputs.ping\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ping\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/postfix.go",
    "content": "//go:build !custom || inputs || inputs.postfix\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/postfix\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/postgresql.go",
    "content": "//go:build !custom || inputs || inputs.postgresql\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/postgresql\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/postgresql_extensible.go",
    "content": "//go:build !custom || inputs || inputs.postgresql_extensible\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/postgresql_extensible\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/powerdns.go",
    "content": "//go:build !custom || inputs || inputs.powerdns\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/powerdns\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/powerdns_recursor.go",
    "content": "//go:build !custom || inputs || inputs.powerdns_recursor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/powerdns_recursor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/processes.go",
    "content": "//go:build !custom || inputs || inputs.processes\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/processes\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/procstat.go",
    "content": "//go:build !custom || inputs || inputs.procstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/procstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/prometheus.go",
    "content": "//go:build !custom || inputs || inputs.prometheus\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/prometheus\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/promql.go",
    "content": "//go:build !custom || inputs || inputs.promql\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/promql\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/proxmox.go",
    "content": "//go:build !custom || inputs || inputs.proxmox\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/proxmox\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/puppetagent.go",
    "content": "//go:build !custom || inputs || inputs.puppetagent\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/puppetagent\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/rabbitmq.go",
    "content": "//go:build !custom || inputs || inputs.rabbitmq\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/rabbitmq\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/radius.go",
    "content": "//go:build !custom || inputs || inputs.radius\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/radius\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/raindrops.go",
    "content": "//go:build !custom || inputs || inputs.raindrops\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/raindrops\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ras.go",
    "content": "//go:build !custom || inputs || inputs.ras\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ras\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/ravendb.go",
    "content": "//go:build !custom || inputs || inputs.ravendb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/ravendb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/redfish.go",
    "content": "//go:build !custom || inputs || inputs.redfish\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/redfish\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/redis.go",
    "content": "//go:build !custom || inputs || inputs.redis\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/redis\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/redis_sentinel.go",
    "content": "//go:build !custom || inputs || inputs.redis_sentinel\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/redis_sentinel\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/rethinkdb.go",
    "content": "//go:build !custom || inputs || inputs.rethinkdb\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/rethinkdb\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/riak.go",
    "content": "//go:build !custom || inputs || inputs.riak\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/riak\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/riemann_listener.go",
    "content": "//go:build !custom || inputs || inputs.riemann_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/riemann_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/s7comm.go",
    "content": "//go:build !custom || inputs || inputs.s7comm\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/s7comm\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/salesforce.go",
    "content": "//go:build !custom || inputs || inputs.salesforce\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/salesforce\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sensors.go",
    "content": "//go:build !custom || inputs || inputs.sensors\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sensors\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sflow.go",
    "content": "//go:build !custom || inputs || inputs.sflow\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sflow\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sip.go",
    "content": "//go:build !custom || inputs || inputs.sip\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sip\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/slab.go",
    "content": "//go:build !custom || inputs || inputs.slab\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/slab\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/slurm.go",
    "content": "//go:build !custom || inputs || inputs.slurm\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/slurm\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/smart.go",
    "content": "//go:build !custom || inputs || inputs.smart\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/smart\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/smartctl.go",
    "content": "//go:build !custom || inputs || inputs.smartctl\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/smartctl\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/snmp.go",
    "content": "//go:build !custom || inputs || inputs.snmp\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/snmp\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/snmp_trap.go",
    "content": "//go:build !custom || inputs || inputs.snmp_trap\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/snmp_trap\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/socket_listener.go",
    "content": "//go:build !custom || inputs || inputs.socket_listener\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/socket_listener\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/socketstat.go",
    "content": "//go:build !custom || inputs || inputs.socketstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/socketstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/solr.go",
    "content": "//go:build !custom || inputs || inputs.solr\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/solr\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sql.go",
    "content": "//go:build !custom || inputs || inputs.sql\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sql\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sqlserver.go",
    "content": "//go:build !custom || inputs || inputs.sqlserver\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sqlserver\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/stackdriver.go",
    "content": "//go:build !custom || inputs || inputs.stackdriver\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/stackdriver\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/statsd.go",
    "content": "//go:build !custom || inputs || inputs.statsd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/statsd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/supervisor.go",
    "content": "//go:build !custom || inputs || inputs.supervisor\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/supervisor\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/suricata.go",
    "content": "//go:build !custom || inputs || inputs.suricata\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/suricata\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/swap.go",
    "content": "//go:build !custom || inputs || inputs.swap\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/swap\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/synproxy.go",
    "content": "//go:build !custom || inputs || inputs.synproxy\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/synproxy\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/syslog.go",
    "content": "//go:build !custom || inputs || inputs.syslog\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/syslog\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/sysstat.go",
    "content": "//go:build !custom || inputs || inputs.sysstat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/sysstat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/system.go",
    "content": "//go:build !custom || inputs || inputs.system\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/system\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/systemd_units.go",
    "content": "//go:build !custom || inputs || inputs.systemd_units\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/systemd_units\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/tacacs.go",
    "content": "//go:build !custom || inputs || inputs.tacacs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/tacacs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/tail.go",
    "content": "//go:build !custom || inputs || inputs.tail\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/tail\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/teamspeak.go",
    "content": "//go:build !custom || inputs || inputs.teamspeak\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/teamspeak\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/temp.go",
    "content": "//go:build !custom || inputs || inputs.temp\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/temp\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/tengine.go",
    "content": "//go:build !custom || inputs || inputs.tengine\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/tengine\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/timex.go",
    "content": "//go:build !custom || inputs || inputs.timex\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/timex\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/tomcat.go",
    "content": "//go:build !custom || inputs || inputs.tomcat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/tomcat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/trig.go",
    "content": "//go:build !custom || inputs || inputs.trig\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/trig\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/turbostat.go",
    "content": "//go:build !custom || inputs || inputs.turbostat\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/turbostat\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/twemproxy.go",
    "content": "//go:build !custom || inputs || inputs.twemproxy\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/twemproxy\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/unbound.go",
    "content": "//go:build !custom || inputs || inputs.unbound\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/unbound\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/upsd.go",
    "content": "//go:build !custom || inputs || inputs.upsd\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/upsd\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/uwsgi.go",
    "content": "//go:build !custom || inputs || inputs.uwsgi\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/uwsgi\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/varnish.go",
    "content": "//go:build !custom || inputs || inputs.varnish\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/varnish\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/vault.go",
    "content": "//go:build !custom || inputs || inputs.vault\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/vault\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/vsphere.go",
    "content": "//go:build !custom || inputs || inputs.vsphere\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/vsphere\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/webhooks.go",
    "content": "//go:build !custom || inputs || inputs.webhooks\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/webhooks\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/whois.go",
    "content": "//go:build !custom || inputs || inputs.whois\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/whois\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/win_eventlog.go",
    "content": "//go:build !custom || inputs || inputs.win_eventlog\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/win_eventlog\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/win_perf_counters.go",
    "content": "//go:build !custom || inputs || inputs.win_perf_counters\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/win_perf_counters\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/win_services.go",
    "content": "//go:build !custom || inputs || inputs.win_services\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/win_services\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/win_wmi.go",
    "content": "//go:build !custom || inputs || inputs.win_wmi\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/win_wmi\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/wireguard.go",
    "content": "//go:build !custom || inputs || inputs.wireguard\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/wireguard\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/wireless.go",
    "content": "//go:build !custom || inputs || inputs.wireless\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/wireless\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/x509_cert.go",
    "content": "//go:build !custom || inputs || inputs.x509_cert\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/x509_cert\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/xtremio.go",
    "content": "//go:build !custom || inputs || inputs.xtremio\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/xtremio\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/zfs.go",
    "content": "//go:build !custom || inputs || inputs.zfs\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/zfs\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/zipkin.go",
    "content": "//go:build !custom || inputs || inputs.zipkin\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/zipkin\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/all/zookeeper.go",
    "content": "//go:build !custom || inputs || inputs.zookeeper\n\npackage all\n\nimport _ \"github.com/influxdata/telegraf/plugins/inputs/zookeeper\" // register plugin\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/README.md",
    "content": "# AMD ROCm System Management Interface (SMI) Input Plugin\n\nThis plugin gathers statistics including memory and GPU usage, temperatures\netc from [AMD ROCm platform][amd_rocm] GPUs.\n\n> [!IMPORTANT]\n> The [`rocm-smi` binary][binary] is required and needs to be installed on the\n> system.\n\n⭐ Telegraf v1.20.0\n🏷️ hardware, system\n💻 all\n\n[amd_rocm]: https://rocm.docs.amd.com/\n[binary]: https://github.com/RadeonOpenCompute/rocm_smi_lib/tree/master/python_smi_tools\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  NOT AVAILABLE\n\n## Configuration\n\n```toml @sample.conf\n# Query statistics from AMD Graphics cards using rocm-smi binary\n[[inputs.amd_rocm_smi]]\n  ## Optional: path to rocm-smi binary, defaults to $PATH via exec.LookPath\n  # bin_path = \"/opt/rocm/bin/rocm-smi\"\n\n  ## Optional: timeout for GPU polling\n  # timeout = \"5s\"\n```\n\n## Metrics\n\n- measurement: `amd_rocm_smi`\n  - tags\n    - `name` (entry name assigned by rocm-smi executable)\n    - `gpu_id` (id of the GPU according to rocm-smi)\n    - `gpu_unique_id` (unique id of the GPU)\n\n  - fields\n    - `driver_version` (integer)\n    - `fan_speed` (integer)\n    - `memory_total` (integer, B)\n    - `memory_used` (integer, B)\n    - `memory_free` (integer, B)\n    - `temperature_sensor_edge` (float, Celsius)\n    - `temperature_sensor_junction` (float, Celsius)\n    - `temperature_sensor_memory` (float, Celsius)\n    - `utilization_gpu` (integer, percentage)\n    - `utilization_memory` (integer, percentage)\n    - `clocks_current_sm` (integer, Mhz)\n    - `clocks_current_memory` (integer, Mhz)\n    - `clocks_current_display` (integer, Mhz)\n    - `clocks_current_fabric` (integer, Mhz)\n    - `clocks_current_system` (integer, Mhz)\n    - `power_draw` (float, Watt)\n    - `card_series` (string)\n    - `card_model` (string)\n    - `card_vendor` (string)\n\n## Troubleshooting\n\nCheck the full output by running `rocm-smi` binary manually.\n\nLinux:\n\n```sh\nrocm-smi rocm-smi -o -l -m -M  -g -c -t -u -i -f -p -P -s -S -v --showreplaycount --showpids --showdriverversion --showmemvendor --showfwinfo --showproductname --showserial --showuniqueid --showbus --showpendingpages --showpagesinfo --showretiredpages --showunreservablepages --showmemuse --showvoltage --showtopo --showtopoweight --showtopohops --showtopotype --showtoponuma --showmeminfo all --json\n```\n\nPlease include the output of this command if opening a GitHub issue, together\nwith ROCm version.\n\n## Example Output\n\n```text\namd_rocm_smi,gpu_id=0x6861,gpu_unique_id=0x2150e7d042a1124,host=ali47xl,name=card0 clocks_current_memory=167i,clocks_current_sm=852i,driver_version=51114i,fan_speed=14i,memory_free=17145282560i,memory_total=17163091968i,memory_used=17809408i,power_draw=7,temperature_sensor_edge=28,temperature_sensor_junction=29,temperature_sensor_memory=92,utilization_gpu=0i 1630572551000000000\namd_rocm_smi,gpu_id=0x6861,gpu_unique_id=0x2150e7d042a1124,host=ali47xl,name=card0 clocks_current_memory=167i,clocks_current_sm=852i,driver_version=51114i,fan_speed=14i,memory_free=17145282560i,memory_total=17163091968i,memory_used=17809408i,power_draw=7,temperature_sensor_edge=29,temperature_sensor_junction=30,temperature_sensor_memory=91,utilization_gpu=0i 1630572701000000000\namd_rocm_smi,gpu_id=0x6861,gpu_unique_id=0x2150e7d042a1124,host=ali47xl,name=card0 clocks_current_memory=167i,clocks_current_sm=852i,driver_version=51114i,fan_speed=14i,memory_free=17145282560i,memory_total=17163091968i,memory_used=17809408i,power_draw=7,temperature_sensor_edge=29,temperature_sensor_junction=29,temperature_sensor_memory=92,utilization_gpu=0i 1630572749000000000\n```\n\n## Limitations and notices\n\nPlease notice that this plugin has been developed and tested on a limited number\nof versions and small set of GPUs. Currently the latest ROCm version tested is\n4.3.0.  Notice that depending on the device and driver versions the amount of\ninformation provided by `rocm-smi` can vary so that some fields would start/stop\nappearing in the metrics upon updates.  The `rocm-smi` JSON output is not\nperfectly homogeneous and is possibly changing in the future, hence parsing and\nunmarshalling can start failing upon updating ROCm.\n\nInspired by the current state of the art of the `nvidia-smi` plugin.\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/amd_rocm_smi.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage amd_rocm_smi\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst measurement = \"amd_rocm_smi\"\n\ntype ROCmSMI struct {\n\tBinPath string          `toml:\"bin_path\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tLog     telegraf.Logger `toml:\"-\"`\n}\n\ntype gpu struct {\n\tDeviceID                     string `json:\"Device ID\"`\n\tGpuID                        string `json:\"GPU ID\"`\n\tGpuUniqueID                  string `json:\"Unique ID\"`\n\tGpuVBIOSVersion              string `json:\"VBIOS version\"`\n\tGpuTemperatureSensorEdge     string `json:\"Temperature (Sensor edge) (C)\"`\n\tGpuTemperatureSensorJunction string `json:\"Temperature (Sensor junction) (C)\"`\n\tGpuTemperatureSensorMemory   string `json:\"Temperature (Sensor memory) (C)\"`\n\tGpuDcefClkClockSpeed         string `json:\"dcefclk clock speed:\"`\n\tGpuDcefClkClockLevel         string `json:\"dcefclk clock level:\"`\n\tGpuFclkClockSpeed            string `json:\"fclk clock speed:\"`\n\tGpuFclkClockLevel            string `json:\"fclk clock level:\"`\n\tGpuMclkClockSpeed            string `json:\"mclk clock speed:\"`\n\tGpuMclkClockLevel            string `json:\"mclk clock level:\"`\n\tGpuSclkClockSpeed            string `json:\"sclk clock speed:\"`\n\tGpuSclkClockLevel            string `json:\"sclk clock level:\"`\n\tGpuSocclkClockSpeed          string `json:\"socclk clock speed:\"`\n\tGpuSocclkClockLevel          string `json:\"socclk clock level:\"`\n\tGpuPcieClock                 string `json:\"pcie clock level\"`\n\tGpuFanSpeedLevel             string `json:\"Fan speed (level)\"`\n\tGpuFanSpeedPercentage        string `json:\"Fan speed (%)\"`\n\tGpuFanRPM                    string `json:\"Fan RPM\"`\n\tGpuPerformanceLevel          string `json:\"Performance Level\"`\n\tGpuOverdrive                 string `json:\"GPU OverDrive value (%)\"`\n\tGpuMaxPower                  string `json:\"Max Graphics Package Power (W)\"`\n\tGpuAveragePower              string `json:\"Average Graphics Package Power (W)\"`\n\tGpuUsePercentage             string `json:\"GPU use (%)\"`\n\tGpuMemoryAllocatedPercentage string `json:\"GPU Memory Allocated (VRAM%)\"`\n\tGpuMemoryUsePercentage       string `json:\"GPU memory use (%)\"`\n\tGpuMemoryVendor              string `json:\"GPU memory vendor\"`\n\tGpuPCIeReplay                string `json:\"PCIe Replay Count\"`\n\tGpuSerialNumber              string `json:\"Serial Number\"`\n\tGpuVoltagemV                 string `json:\"Voltage (mV)\"`\n\tGpuPCIBus                    string `json:\"PCI Bus\"`\n\tGpuASDDirmware               string `json:\"ASD firmware version\"`\n\tGpuCEFirmware                string `json:\"CE firmware version\"`\n\tGpuDMCUFirmware              string `json:\"DMCU firmware version\"`\n\tGpuMCFirmware                string `json:\"MC firmware version\"`\n\tGpuMEFirmware                string `json:\"ME firmware version\"`\n\tGpuMECFirmware               string `json:\"MEC firmware version\"`\n\tGpuMEC2Firmware              string `json:\"MEC2 firmware version\"`\n\tGpuPFPFirmware               string `json:\"PFP firmware version\"`\n\tGpuRLCFirmware               string `json:\"RLC firmware version\"`\n\tGpuRLCSRLC                   string `json:\"RLC SRLC firmware version\"`\n\tGpuRLCSRLG                   string `json:\"RLC SRLG firmware version\"`\n\tGpuRLCSRLS                   string `json:\"RLC SRLS firmware version\"`\n\tGpuSDMAFirmware              string `json:\"SDMA firmware version\"`\n\tGpuSDMA2Firmware             string `json:\"SDMA2 firmware version\"`\n\tGpuSMCFirmware               string `json:\"SMC firmware version\"`\n\tGpuSOSFirmware               string `json:\"SOS firmware version\"`\n\tGpuTARAS                     string `json:\"TA RAS firmware version\"`\n\tGpuTAXGMI                    string `json:\"TA XGMI firmware version\"`\n\tGpuUVDFirmware               string `json:\"UVD firmware version\"`\n\tGpuVCEFirmware               string `json:\"VCE firmware version\"`\n\tGpuVCNFirmware               string `json:\"VCN firmware version\"`\n\tGpuCardSeries                string `json:\"Card series\"`\n\tGpuCardModel                 string `json:\"Card model\"`\n\tGpuCardVendor                string `json:\"Card vendor\"`\n\tGpuCardSKU                   string `json:\"Card SKU\"`\n\tGpuNUMANode                  string `json:\"(Topology) Numa Node\"`\n\tGpuNUMAAffinity              string `json:\"(Topology) Numa Affinity\"`\n\tGpuVisVRAMTotalMemory        string `json:\"VIS_VRAM Total Memory (B)\"`\n\tGpuVisVRAMTotalUsedMemory    string `json:\"VIS_VRAM Total Used Memory (B)\"`\n\tGpuVRAMTotalMemory           string `json:\"VRAM Total Memory (B)\"`\n\tGpuVRAMTotalUsedMemory       string `json:\"VRAM Total Used Memory (B)\"`\n\tGpuGTTTotalMemory            string `json:\"GTT Total Memory (B)\"`\n\tGpuGTTTotalUsedMemory        string `json:\"GTT Total Used Memory (B)\"`\n}\n\ntype sysInfo struct {\n\tDriverVersion string `json:\"Driver version\"`\n}\n\ntype gpuMetric struct {\n\ttags   map[string]string\n\tfields map[string]interface{}\n}\n\nfunc (*ROCmSMI) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (rsmi *ROCmSMI) Start(telegraf.Accumulator) error {\n\tif _, err := os.Stat(rsmi.BinPath); os.IsNotExist(err) {\n\t\tbinPath, err := exec.LookPath(\"rocm-smi\")\n\t\tif err != nil {\n\t\t\treturn &internal.StartupError{Err: err}\n\t\t}\n\t\trsmi.BinPath = binPath\n\t}\n\n\treturn nil\n}\n\nfunc (rsmi *ROCmSMI) Gather(acc telegraf.Accumulator) error {\n\tdata, err := rsmi.pollROCmSMI()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to execute command in pollROCmSMI: %w\", err)\n\t}\n\n\treturn gatherROCmSMI(data, acc)\n}\n\nfunc (*ROCmSMI) Stop() {}\n\nfunc (rsmi *ROCmSMI) pollROCmSMI() ([]byte, error) {\n\t// Construct and execute metrics query, there currently exist (ROCm v4.3.x) a \"-a\" option\n\t// that does not provide all the information, so each needed parameter is set manually\n\tcmd := exec.Command(rsmi.BinPath,\n\t\t\"-o\",\n\t\t\"-l\",\n\t\t\"-m\",\n\t\t\"-M\",\n\t\t\"-g\",\n\t\t\"-c\",\n\t\t\"-t\",\n\t\t\"-u\",\n\t\t\"-i\",\n\t\t\"-f\",\n\t\t\"-p\",\n\t\t\"-P\",\n\t\t\"-s\",\n\t\t\"-S\",\n\t\t\"-v\",\n\t\t\"--showreplaycount\",\n\t\t\"--showpids\",\n\t\t\"--showdriverversion\",\n\t\t\"--showmemvendor\",\n\t\t\"--showfwinfo\",\n\t\t\"--showproductname\",\n\t\t\"--showserial\",\n\t\t\"--showuniqueid\",\n\t\t\"--showbus\",\n\t\t\"--showpendingpages\",\n\t\t\"--showpagesinfo\",\n\t\t\"--showmeminfo\",\n\t\t\"all\",\n\t\t\"--showretiredpages\",\n\t\t\"--showunreservablepages\",\n\t\t\"--showmemuse\",\n\t\t\"--showvoltage\",\n\t\t\"--showtopo\",\n\t\t\"--showtopoweight\",\n\t\t\"--showtopohops\",\n\t\t\"--showtopotype\",\n\t\t\"--showtoponuma\",\n\t\t\"--json\")\n\n\treturn internal.StdOutputTimeout(cmd, time.Duration(rsmi.Timeout))\n}\n\nfunc genTagsFields(gpus map[string]gpu, system map[string]sysInfo) []gpuMetric {\n\tmetrics := make([]gpuMetric, 0, len(gpus))\n\tfor cardID := range gpus {\n\t\tif strings.Contains(cardID, \"card\") {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"name\": cardID,\n\t\t\t}\n\n\t\t\tpayload := gpus[cardID]\n\t\t\t//nolint:errcheck // silently treat as zero if malformed\n\t\t\ttotVRAM, _ := strconv.ParseInt(payload.GpuVRAMTotalMemory, 10, 64)\n\t\t\t//nolint:errcheck // silently treat as zero if malformed\n\t\t\tusdVRAM, _ := strconv.ParseInt(payload.GpuVRAMTotalUsedMemory, 10, 64)\n\t\t\tstrFree := strconv.FormatInt(totVRAM-usdVRAM, 10)\n\n\t\t\t// Try using value found in Device ID first. If not found, try GPU\n\t\t\t// ID for backwards compatibility.\n\t\t\tsetTagIfUsed(tags, \"gpu_id\", payload.DeviceID)\n\t\t\tsetTagIfUsed(tags, \"gpu_id\", payload.GpuID)\n\n\t\t\tsetTagIfUsed(tags, \"gpu_unique_id\", payload.GpuUniqueID)\n\n\t\t\tfields := make(map[string]interface{}, 20)\n\t\t\tsetIfUsed(\"int\", fields, \"driver_version\", strings.ReplaceAll(system[\"system\"].DriverVersion, \".\", \"\"))\n\t\t\tsetIfUsed(\"int\", fields, \"fan_speed\", payload.GpuFanSpeedPercentage)\n\t\t\tsetIfUsed(\"int64\", fields, \"memory_total\", payload.GpuVRAMTotalMemory)\n\t\t\tsetIfUsed(\"int64\", fields, \"memory_used\", payload.GpuVRAMTotalUsedMemory)\n\t\t\tsetIfUsed(\"int64\", fields, \"memory_free\", strFree)\n\t\t\tsetIfUsed(\"float\", fields, \"temperature_sensor_edge\", payload.GpuTemperatureSensorEdge)\n\t\t\tsetIfUsed(\"float\", fields, \"temperature_sensor_junction\", payload.GpuTemperatureSensorJunction)\n\t\t\tsetIfUsed(\"float\", fields, \"temperature_sensor_memory\", payload.GpuTemperatureSensorMemory)\n\t\t\tsetIfUsed(\"int\", fields, \"utilization_gpu\", payload.GpuUsePercentage)\n\t\t\t// Try using allocated percentage first.\n\t\t\tsetIfUsed(\"int\", fields, \"utilization_memory\", payload.GpuMemoryAllocatedPercentage)\n\t\t\tsetIfUsed(\"int\", fields, \"utilization_memory\", payload.GpuMemoryUsePercentage)\n\t\t\tsetIfUsed(\"int\", fields, \"clocks_current_sm\", strings.Trim(payload.GpuSclkClockSpeed, \"(Mhz)\"))\n\t\t\tsetIfUsed(\"int\", fields, \"clocks_current_memory\", strings.Trim(payload.GpuMclkClockSpeed, \"(Mhz)\"))\n\t\t\tsetIfUsed(\"int\", fields, \"clocks_current_display\", strings.Trim(payload.GpuDcefClkClockSpeed, \"(Mhz)\"))\n\t\t\tsetIfUsed(\"int\", fields, \"clocks_current_fabric\", strings.Trim(payload.GpuFclkClockSpeed, \"(Mhz)\"))\n\t\t\tsetIfUsed(\"int\", fields, \"clocks_current_system\", strings.Trim(payload.GpuSocclkClockSpeed, \"(Mhz)\"))\n\t\t\tsetIfUsed(\"float\", fields, \"power_draw\", payload.GpuAveragePower)\n\t\t\tsetIfUsed(\"str\", fields, \"card_series\", payload.GpuCardSeries)\n\t\t\tsetIfUsed(\"str\", fields, \"card_model\", payload.GpuCardModel)\n\t\t\tsetIfUsed(\"str\", fields, \"card_vendor\", payload.GpuCardVendor)\n\n\t\t\tmetrics = append(metrics, gpuMetric{tags, fields})\n\t\t}\n\t}\n\treturn metrics\n}\n\nfunc gatherROCmSMI(ret []byte, acc telegraf.Accumulator) error {\n\tvar gpus map[string]gpu\n\tvar sys map[string]sysInfo\n\n\terr1 := json.Unmarshal(ret, &gpus)\n\tif err1 != nil {\n\t\treturn err1\n\t}\n\n\terr2 := json.Unmarshal(ret, &sys)\n\tif err2 != nil {\n\t\treturn err2\n\t}\n\n\tmetrics := genTagsFields(gpus, sys)\n\tfor _, metric := range metrics {\n\t\tacc.AddFields(measurement, metric.fields, metric.tags)\n\t}\n\n\treturn nil\n}\n\nfunc setTagIfUsed(m map[string]string, k, v string) {\n\tif v != \"\" {\n\t\tm[k] = v\n\t}\n}\n\nfunc setIfUsed(t string, m map[string]interface{}, k, v string) {\n\tvals := strings.Fields(v)\n\tif len(vals) < 1 {\n\t\treturn\n\t}\n\n\tval := vals[0]\n\n\tswitch t {\n\tcase \"float\":\n\t\tif val != \"\" {\n\t\t\tf, err := strconv.ParseFloat(val, 64)\n\t\t\tif err == nil {\n\t\t\t\tm[k] = f\n\t\t\t}\n\t\t}\n\tcase \"int\":\n\t\tif val != \"\" {\n\t\t\ti, err := strconv.Atoi(val)\n\t\t\tif err == nil {\n\t\t\t\tm[k] = i\n\t\t\t}\n\t\t}\n\tcase \"int64\":\n\t\tif val != \"\" {\n\t\t\ti, err := strconv.ParseInt(val, 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tm[k] = i\n\t\t\t}\n\t\t}\n\tcase \"str\":\n\t\tif val != \"\" {\n\t\t\tm[k] = val\n\t\t}\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"amd_rocm_smi\", func() telegraf.Input {\n\t\treturn &ROCmSMI{\n\t\t\tBinPath: \"/opt/rocm/bin/rocm-smi\",\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/amd_rocm_smi_test.go",
    "content": "package amd_rocm_smi\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestErrorBehaviorDefault(t *testing.T) {\n\t// make sure we can't find rocm-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &ROCmSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName: \"amd_rocm_smi\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorError(t *testing.T) {\n\t// make sure we can't find rocm-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &ROCmSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"amd_rocm_smi\",\n\t\tStartupErrorBehavior: \"error\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorRetry(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &ROCmSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"amd_rocm_smi\",\n\t\tStartupErrorBehavior: \"retry\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorIgnore(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &ROCmSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"amd_rocm_smi\",\n\t\tStartupErrorBehavior: \"ignore\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.ErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestGatherValidJSON(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:     \"Vega 10 XT\",\n\t\t\tfilename: \"vega-10-XT.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x6861\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0x2150e7d042a1124\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0xc1e\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              5925,\n\t\t\t\t\t\t\"fan_speed\":                   13,\n\t\t\t\t\t\t\"memory_total\":                int64(17163091968),\n\t\t\t\t\t\t\"memory_used\":                 int64(17776640),\n\t\t\t\t\t\t\"memory_free\":                 int64(17145315328),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     39.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 40.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   92.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"clocks_current_display\":      600,\n\t\t\t\t\t\t\"clocks_current_sm\":           1269,\n\t\t\t\t\t\t\"clocks_current_memory\":       167,\n\t\t\t\t\t\t\"clocks_current_system\":       960,\n\t\t\t\t\t\t\"power_draw\":                  15.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Vega 20 WKS GL-XE [Radeon Pro VII]\",\n\t\t\tfilename: \"vega-20-WKS-GL-XE.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x66a1\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0x2f048617326b1ea\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x834\",\n\t\t\t\t\t\t\"card_series\":                 \"Radeon\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              5917,\n\t\t\t\t\t\t\"fan_speed\":                   0,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(10850304),\n\t\t\t\t\t\t\"memory_free\":                 int64(34332110848),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     36.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 38.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   35.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_display\":      357,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1080,\n\t\t\t\t\t\t\"clocks_current_sm\":           1725,\n\t\t\t\t\t\t\"clocks_current_memory\":       1000,\n\t\t\t\t\t\t\"clocks_current_system\":       971,\n\t\t\t\t\t\t\"power_draw\":                  26.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"mi100 + ROCm 571\",\n\t\t\tfilename: \"mi100_rocm571.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     31.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 34.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   30.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  39.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     30.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 33.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   38.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  37.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     31.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 34.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   31.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  35.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card3\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     33.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 35.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   36.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  39.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card4\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     32.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 34.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   38.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  39.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card5\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              624,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6782976),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336178176),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     33.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 35.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   38.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  40.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"mi100 + ROCm 602\",\n\t\t\tfilename: \"mi100_rocm602.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0x79ccd55167a2124a\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6750208),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336210944),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     53.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 55.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   53.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  36.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0x4edfb117a17a07d\",\n\t\t\t\t\t\t\"name\":          \"card1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6750208),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336210944),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     55.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 58.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   54.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  44.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0xd4a9ec48d03d261d\",\n\t\t\t\t\t\t\"name\":          \"card2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6750208),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336210944),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     54.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 57.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   55.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  43.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x738c\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"0x1b9dd972253c3736\",\n\t\t\t\t\t\t\"name\":          \"card3\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x0c34\",\n\t\t\t\t\t\t\"card_series\":                 \"Arcturus\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(34342961152),\n\t\t\t\t\t\t\"memory_used\":                 int64(6750208),\n\t\t\t\t\t\t\"memory_free\":                 int64(34336210944),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     51.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 53.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   50.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1402,\n\t\t\t\t\t\t\"clocks_current_sm\":           300,\n\t\t\t\t\t\t\"clocks_current_memory\":       1200,\n\t\t\t\t\t\t\"clocks_current_system\":       1000,\n\t\t\t\t\t\t\"power_draw\":                  39.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"rx6700xt + ROCm 430\",\n\t\t\tfilename: \"rx6700xt_rocm430.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x73df\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x1002\",\n\t\t\t\t\t\t\"card_series\":                 \"0x1002\",\n\t\t\t\t\t\t\"card_vendor\":                 \"0x1002\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(12868124672),\n\t\t\t\t\t\t\"memory_used\":                 int64(1622728704),\n\t\t\t\t\t\t\"memory_free\":                 int64(11245395968),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     45.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 47.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   46.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_display\":      480,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1051,\n\t\t\t\t\t\t\"clocks_current_sm\":           500,\n\t\t\t\t\t\t\"clocks_current_memory\":       96,\n\t\t\t\t\t\t\"clocks_current_system\":       685,\n\t\t\t\t\t\t\"power_draw\":                  6.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"rx6700xt + ROCm 571\",\n\t\t\tfilename: \"rx6700xt_rocm571.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x73df\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x6601\",\n\t\t\t\t\t\t\"card_series\":                 \"Navi\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(12868124672),\n\t\t\t\t\t\t\"memory_used\":                 int64(1564491776),\n\t\t\t\t\t\t\"memory_free\":                 int64(11303632896),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     45.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 47.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   46.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_display\":      480,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1051,\n\t\t\t\t\t\t\"clocks_current_sm\":           500,\n\t\t\t\t\t\t\"clocks_current_memory\":       96,\n\t\t\t\t\t\t\"clocks_current_system\":       685,\n\t\t\t\t\t\t\"power_draw\":                  6.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"rx6700xt + ROCm 602\",\n\t\t\tfilename: \"rx6700xt_rocm602.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x73df\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x6601\",\n\t\t\t\t\t\t\"card_series\":                 \"Navi\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(12868124672),\n\t\t\t\t\t\t\"memory_used\":                 int64(1572757504),\n\t\t\t\t\t\t\"memory_free\":                 int64(11295367168),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     45.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 47.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   46.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          0,\n\t\t\t\t\t\t\"clocks_current_display\":      480,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1051,\n\t\t\t\t\t\t\"clocks_current_sm\":           500,\n\t\t\t\t\t\t\"clocks_current_memory\":       96,\n\t\t\t\t\t\t\"clocks_current_system\":       685,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"rx6700xt + ROCm 612\",\n\t\t\tfilename: \"rx6700xt_rocm612.json\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"amd_rocm_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"gpu_id\":        \"0x73df\",\n\t\t\t\t\t\t\"gpu_unique_id\": \"N/A\",\n\t\t\t\t\t\t\"name\":          \"card0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"card_model\":                  \"0x73df\",\n\t\t\t\t\t\t\"card_series\":                 \"Navi\",\n\t\t\t\t\t\t\"card_vendor\":                 \"Advanced\",\n\t\t\t\t\t\t\"driver_version\":              636,\n\t\t\t\t\t\t\"memory_total\":                int64(12868124672),\n\t\t\t\t\t\t\"memory_used\":                 int64(1572745216),\n\t\t\t\t\t\t\"memory_free\":                 int64(11295379456),\n\t\t\t\t\t\t\"temperature_sensor_edge\":     45.0,\n\t\t\t\t\t\t\"temperature_sensor_junction\": 47.0,\n\t\t\t\t\t\t\"temperature_sensor_memory\":   46.0,\n\t\t\t\t\t\t\"utilization_gpu\":             0,\n\t\t\t\t\t\t\"utilization_memory\":          12,\n\t\t\t\t\t\t\"clocks_current_display\":      480,\n\t\t\t\t\t\t\"clocks_current_fabric\":       1051,\n\t\t\t\t\t\t\"clocks_current_sm\":           0,\n\t\t\t\t\t\t\"clocks_current_memory\":       96,\n\t\t\t\t\t\t\"clocks_current_system\":       685,\n\t\t\t\t\t\t\"power_draw\":                  6.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\toctets, err := os.ReadFile(filepath.Join(\"testdata\", tt.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = gatherROCmSMI(octets, &acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/sample.conf",
    "content": "# Query statistics from AMD Graphics cards using rocm-smi binary\n[[inputs.amd_rocm_smi]]\n  ## Optional: path to rocm-smi binary, defaults to $PATH via exec.LookPath\n  # bin_path = \"/opt/rocm/bin/rocm-smi\"\n\n  ## Optional: timeout for GPU polling\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/mi100_rocm571.json",
    "content": "\n{\n    \"card0\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"31.0\",\n        \"Temperature (Sensor junction) (C)\": \"34.0\",\n        \"Temperature (Sensor memory) (C)\": \"30.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"39.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"662\",\n        \"PCI Bus\": \"0000:1E:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11399168\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"card1\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"30.0\",\n        \"Temperature (Sensor junction) (C)\": \"33.0\",\n        \"Temperature (Sensor memory) (C)\": \"38.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"37.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"hynix\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"662\",\n        \"PCI Bus\": \"0000:22:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11366400\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"card2\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"31.0\",\n        \"Temperature (Sensor junction) (C)\": \"34.0\",\n        \"Temperature (Sensor memory) (C)\": \"31.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"35.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"656\",\n        \"PCI Bus\": \"0000:3F:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11366400\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"card3\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"33.0\",\n        \"Temperature (Sensor junction) (C)\": \"35.0\",\n        \"Temperature (Sensor memory) (C)\": \"36.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"39.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"hynix\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"656\",\n        \"PCI Bus\": \"0000:43:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11366400\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"card4\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"32.0\",\n        \"Temperature (Sensor junction) (C)\": \"34.0\",\n        \"Temperature (Sensor memory) (C)\": \"38.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"39.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"hynix\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"656\",\n        \"PCI Bus\": \"0000:46:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11366400\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"card5\": {\n        \"GPU ID\": \"0x738c\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-D3430400-037\",\n        \"Temperature (Sensor edge) (C)\": \"33.0\",\n        \"Temperature (Sensor junction) (C)\": \"35.0\",\n        \"Temperature (Sensor memory) (C)\": \"38.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (8.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"40.0\",\n        \"0\": \"8.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"hynix\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"0\",\n        \"Voltage (mV)\": \"662\",\n        \"PCI Bus\": \"0000:49:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6782976\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6782976\",\n        \"GTT Total Memory (B)\": \"135048462336\",\n        \"GTT Total Used Memory (B)\": \"11366400\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"CE firmware version\": \"0\",\n        \"DMCU firmware version\": \"0\",\n        \"MC firmware version\": \"0\",\n        \"ME firmware version\": \"0\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"PFP firmware version\": \"0\",\n        \"RLC firmware version\": \"24\",\n        \"RLC SRLC firmware version\": \"0\",\n        \"RLC SRLG firmware version\": \"0\",\n        \"RLC SRLS firmware version\": \"0\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.15\",\n        \"UVD firmware version\": \"0x00000000\",\n        \"VCE firmware version\": \"0x00000000\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3430400\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"0\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.2.4\",\n        \"PID104225\": \"mlir-cpu-runner, 0, 0, 0, 0\",\n        \"(Topology) Weight between DRM devices 0 and 1\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 2\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 3\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 4\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 5\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 2\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 3\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 4\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 5\": \"40\",\n        \"(Topology) Weight between DRM devices 2 and 3\": \"40\",\n        \"(Topology) Weight between DRM devices 2 and 4\": \"40\",\n        \"(Topology) Weight between DRM devices 2 and 5\": \"40\",\n        \"(Topology) Weight between DRM devices 3 and 4\": \"40\",\n        \"(Topology) Weight between DRM devices 3 and 5\": \"40\",\n        \"(Topology) Weight between DRM devices 4 and 5\": \"40\",\n        \"(Topology) Hops between DRM devices 0 and 1\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 2\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 3\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 4\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 5\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 2\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 3\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 4\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 5\": \"2\",\n        \"(Topology) Hops between DRM devices 2 and 3\": \"2\",\n        \"(Topology) Hops between DRM devices 2 and 4\": \"2\",\n        \"(Topology) Hops between DRM devices 2 and 5\": \"2\",\n        \"(Topology) Hops between DRM devices 3 and 4\": \"2\",\n        \"(Topology) Hops between DRM devices 3 and 5\": \"2\",\n        \"(Topology) Hops between DRM devices 4 and 5\": \"2\",\n        \"(Topology) Link type between DRM devices 0 and 1\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 2\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 3\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 4\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 5\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 2\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 3\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 4\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 5\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 2 and 3\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 2 and 4\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 2 and 5\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 3 and 4\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 3 and 5\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 4 and 5\": \"PCIE\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/mi100_rocm602.json",
    "content": "{\n    \"card0\": {\n        \"Device ID\": \"0x738c\",\n        \"Device Rev\": \"0x1\",\n        \"Unique ID\": \"0x79ccd55167a2124a\",\n        \"VBIOS version\": \"113-D3431401-101\",\n        \"Temperature (Sensor edge) (C)\": \"53.0\",\n        \"Temperature (Sensor junction) (C)\": \"55.0\",\n        \"Temperature (Sensor memory) (C)\": \"53.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"36.0\",\n        \"0\": \"16.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"662\",\n        \"PCI Bus\": \"0000:83:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6750208\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6750208\",\n        \"GTT Total Memory (B)\": \"135138402304\",\n        \"GTT Total Used Memory (B)\": \"11354112\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"RLC firmware version\": \"24\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.17\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3431401\",\n        \"(Topology) Numa Node\": \"1\",\n        \"(Topology) Numa Affinity\": \"1\"\n    },\n    \"card1\": {\n        \"Device ID\": \"0x738c\",\n        \"Device Rev\": \"0x1\",\n        \"Unique ID\": \"0x4edfb117a17a07d\",\n        \"VBIOS version\": \"113-D3431401-101\",\n        \"Temperature (Sensor edge) (C)\": \"55.0\",\n        \"Temperature (Sensor junction) (C)\": \"58.0\",\n        \"Temperature (Sensor memory) (C)\": \"54.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"44.0\",\n        \"0\": \"16.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"668\",\n        \"PCI Bus\": \"0000:A3:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6750208\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6750208\",\n        \"GTT Total Memory (B)\": \"135138402304\",\n        \"GTT Total Used Memory (B)\": \"11354112\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"RLC firmware version\": \"24\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.17\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3431401\",\n        \"(Topology) Numa Node\": \"1\",\n        \"(Topology) Numa Affinity\": \"1\"\n    },\n    \"card2\": {\n        \"Device ID\": \"0x738c\",\n        \"Device Rev\": \"0x1\",\n        \"Unique ID\": \"0xd4a9ec48d03d261d\",\n        \"VBIOS version\": \"113-D3431401-101\",\n        \"Temperature (Sensor edge) (C)\": \"54.0\",\n        \"Temperature (Sensor junction) (C)\": \"57.0\",\n        \"Temperature (Sensor memory) (C)\": \"55.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"43.0\",\n        \"0\": \"16.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"668\",\n        \"PCI Bus\": \"0000:C3:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6750208\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6750208\",\n        \"GTT Total Memory (B)\": \"135138402304\",\n        \"GTT Total Used Memory (B)\": \"11354112\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"RLC firmware version\": \"24\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.17\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3431401\",\n        \"(Topology) Numa Node\": \"1\",\n        \"(Topology) Numa Affinity\": \"1\"\n    },\n    \"card3\": {\n        \"Device ID\": \"0x738c\",\n        \"Device Rev\": \"0x1\",\n        \"Unique ID\": \"0x1b9dd972253c3736\",\n        \"VBIOS version\": \"113-D3431401-101\",\n        \"Temperature (Sensor edge) (C)\": \"51.0\",\n        \"Temperature (Sensor junction) (C)\": \"53.0\",\n        \"Temperature (Sensor memory) (C)\": \"50.0\",\n        \"fclk clock speed:\": \"(1402Mhz)\",\n        \"fclk clock level:\": \"0\",\n        \"mclk clock speed:\": \"(1200Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(300Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(1000Mhz)\",\n        \"socclk clock level:\": \"0\",\n        \"pcie clock level\": \"0 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (300Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"290.0\",\n        \"Average Graphics Package Power (W)\": \"39.0\",\n        \"0\": \"16.0GT/s x16 *\",\n        \"1\": \"495Mhz\",\n        \"2\": \"731Mhz\",\n        \"3\": \"962Mhz\",\n        \"4\": \"1029Mhz\",\n        \"5\": \"1087Mhz\",\n        \"6\": \"1147Mhz\",\n        \"7\": \"1189Mhz\",\n        \"8\": \"1235Mhz\",\n        \"9\": \"1283Mhz\",\n        \"10\": \"1319Mhz\",\n        \"11\": \"1363Mhz\",\n        \"12\": \"1404Mhz\",\n        \"13\": \"1430Mhz\",\n        \"14\": \"1472Mhz\",\n        \"15\": \"1502Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"662\",\n        \"PCI Bus\": \"0000:E3:00.0\",\n        \"VRAM Total Memory (B)\": \"34342961152\",\n        \"VRAM Total Used Memory (B)\": \"6750208\",\n        \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n        \"VIS_VRAM Total Used Memory (B)\": \"6750208\",\n        \"GTT Total Memory (B)\": \"135138402304\",\n        \"GTT Total Used Memory (B)\": \"11354112\",\n        \"ASD firmware version\": \"0x21000059\",\n        \"MEC firmware version\": \"65\",\n        \"MEC2 firmware version\": \"65\",\n        \"RLC firmware version\": \"24\",\n        \"SDMA firmware version\": \"18\",\n        \"SDMA2 firmware version\": \"18\",\n        \"SMC firmware version\": \"00.54.29.00\",\n        \"SOS firmware version\": \"0x0017004f\",\n        \"TA RAS firmware version\": \"27.00.01.62\",\n        \"TA XGMI firmware version\": \"32.00.00.17\",\n        \"VCN firmware version\": \"0x01101015\",\n        \"Card series\": \"Arcturus GL-XL [Instinct MI100]\",\n        \"Card model\": \"0x0c34\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"D3431401\",\n        \"(Topology) Numa Node\": \"1\",\n        \"(Topology) Numa Affinity\": \"1\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.3.6\",\n        \"(Topology) Weight between DRM devices 0 and 1\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 2\": \"40\",\n        \"(Topology) Weight between DRM devices 0 and 3\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 2\": \"40\",\n        \"(Topology) Weight between DRM devices 1 and 3\": \"40\",\n        \"(Topology) Weight between DRM devices 2 and 3\": \"40\",\n        \"(Topology) Hops between DRM devices 0 and 1\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 2\": \"2\",\n        \"(Topology) Hops between DRM devices 0 and 3\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 2\": \"2\",\n        \"(Topology) Hops between DRM devices 1 and 3\": \"2\",\n        \"(Topology) Hops between DRM devices 2 and 3\": \"2\",\n        \"(Topology) Link type between DRM devices 0 and 1\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 2\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 0 and 3\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 2\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 1 and 3\": \"PCIE\",\n        \"(Topology) Link type between DRM devices 2 and 3\": \"PCIE\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm430.json",
    "content": "{\n    \"card0\": {\n        \"GPU ID\": \"0x73df\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-67XA6SSB1-D01\",\n        \"Temperature (Sensor edge) (C)\": \"45.0\",\n        \"Temperature (Sensor junction) (C)\": \"47.0\",\n        \"Temperature (Sensor memory) (C)\": \"46.0\",\n        \"Temperature (Sensor HBM 0) (C)\": \"N/A\",\n        \"Temperature (Sensor HBM 1) (C)\": \"N/A\",\n        \"Temperature (Sensor HBM 2) (C)\": \"N/A\",\n        \"Temperature (Sensor HBM 3) (C)\": \"N/A\",\n        \"dcefclk clock speed:\": \"(480Mhz)\",\n        \"dcefclk clock level:\": \"1\",\n        \"fclk clock speed:\": \"(1051Mhz)\",\n        \"fclk clock level:\": \"1\",\n        \"mclk clock speed:\": \"(96Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(500Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(685Mhz)\",\n        \"socclk clock level:\": \"1\",\n        \"pcie clock level\": \"1 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (500Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"211.0\",\n        \"Average Graphics Package Power (W)\": \"6.0\",\n        \"0\": \"2.5GT/s x1\",\n        \"1\": \"16.0GT/s x16 *\",\n        \"2\": \"1200Mhz\",\n        \"3\": \"1000Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"6\",\n        \"PCI Bus\": \"0000:07:00.0\",\n        \"VRAM Total Memory (B)\": \"12868124672\",\n        \"VRAM Total Used Memory (B)\": \"1622728704\",\n        \"VIS_VRAM Total Memory (B)\": \"268435456\",\n        \"VIS_VRAM Total Used Memory (B)\": \"70930432\",\n        \"GTT Total Memory (B)\": \"16792432640\",\n        \"GTT Total Used Memory (B)\": \"244150272\",\n        \"ASD firmware version\": \"553648315\",\n        \"CE firmware version\": \"37\",\n        \"ME firmware version\": \"64\",\n        \"MEC firmware version\": \"116\",\n        \"MEC2 firmware version\": \"116\",\n        \"PFP firmware version\": \"97\",\n        \"RLC firmware version\": \"74\",\n        \"SDMA firmware version\": \"80\",\n        \"SDMA2 firmware version\": \"80\",\n        \"SMC firmware version\": \"00.65.60.00\",\n        \"SOS firmware version\": \"0x00220b0c\",\n        \"VCN firmware version\": \"0x0211e006\",\n        \"Card series\": \"0x1002\",\n        \"Card model\": \"0x1002\",\n        \"Card vendor\": \"0x1002\",\n        \"Card SKU\": \"67XA6S\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"4294967295\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.3.6\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm571.json",
    "content": "{\n    \"card0\": {\n        \"GPU ID\": \"0x73df\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-67XA6SSB1-D01\",\n        \"Temperature (Sensor edge) (C)\": \"45.0\",\n        \"Temperature (Sensor junction) (C)\": \"47.0\",\n        \"Temperature (Sensor memory) (C)\": \"46.0\",\n        \"dcefclk clock speed:\": \"(480Mhz)\",\n        \"dcefclk clock level:\": \"1\",\n        \"fclk clock speed:\": \"(1051Mhz)\",\n        \"fclk clock level:\": \"1\",\n        \"mclk clock speed:\": \"(96Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(500Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(685Mhz)\",\n        \"socclk clock level:\": \"1\",\n        \"pcie clock level\": \"1 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (500Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"211.0\",\n        \"Average Graphics Package Power (W)\": \"6.0\",\n        \"0\": \"2.5GT/s x1\",\n        \"1\": \"16.0GT/s x16 *\",\n        \"2\": \"1200Mhz\",\n        \"3\": \"1000Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"862\",\n        \"PCI Bus\": \"0000:07:00.0\",\n        \"VRAM Total Memory (B)\": \"12868124672\",\n        \"VRAM Total Used Memory (B)\": \"1564491776\",\n        \"VIS_VRAM Total Memory (B)\": \"268435456\",\n        \"VIS_VRAM Total Used Memory (B)\": \"70930432\",\n        \"GTT Total Memory (B)\": \"16792432640\",\n        \"GTT Total Used Memory (B)\": \"248328192\",\n        \"ASD firmware version\": \"0x210000bb\",\n        \"CE firmware version\": \"37\",\n        \"ME firmware version\": \"64\",\n        \"MEC firmware version\": \"116\",\n        \"MEC2 firmware version\": \"116\",\n        \"PFP firmware version\": \"97\",\n        \"RLC firmware version\": \"74\",\n        \"SDMA firmware version\": \"80\",\n        \"SDMA2 firmware version\": \"80\",\n        \"SMC firmware version\": \"00.65.60.00\",\n        \"SOS firmware version\": \"0x00220b0c\",\n        \"VCN firmware version\": \"0x0211e006\",\n        \"Card series\": \"Navi 22 [Radeon RX 6700/6700 XT / 6800M]\",\n        \"Card model\": \"0x6601\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"67XA6SSB1\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"4294967295\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.3.6\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm602.json",
    "content": "{\n    \"card0\": {\n        \"Device ID\": \"0x73df\",\n        \"Device Rev\": \"0xc1\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-67XA6SSB1-D01\",\n        \"Temperature (Sensor edge) (C)\": \"45.0\",\n        \"Temperature (Sensor junction) (C)\": \"47.0\",\n        \"Temperature (Sensor memory) (C)\": \"46.0\",\n        \"dcefclk clock speed:\": \"(480Mhz)\",\n        \"dcefclk clock level:\": \"1\",\n        \"fclk clock speed:\": \"(1051Mhz)\",\n        \"fclk clock level:\": \"1\",\n        \"mclk clock speed:\": \"(96Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(500Mhz)\",\n        \"sclk clock level:\": \"1\",\n        \"socclk clock speed:\": \"(685Mhz)\",\n        \"socclk clock level:\": \"1\",\n        \"pcie clock level\": \"1 (16.0GT/s x16)\",\n        \"sclk clock level\": \"1 (500Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"211.0\",\n        \"Average Graphics Package Power (W)\": \"N/A (Secondary die)\",\n        \"0\": \"2.5GT/s x1\",\n        \"1\": \"16.0GT/s x16 *\",\n        \"2\": \"1200Mhz\",\n        \"3\": \"1000Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU memory use (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"6\",\n        \"PCI Bus\": \"0000:07:00.0\",\n        \"VRAM Total Memory (B)\": \"12868124672\",\n        \"VRAM Total Used Memory (B)\": \"1572757504\",\n        \"VIS_VRAM Total Memory (B)\": \"268435456\",\n        \"VIS_VRAM Total Used Memory (B)\": \"70930432\",\n        \"GTT Total Memory (B)\": \"16792432640\",\n        \"GTT Total Used Memory (B)\": \"242049024\",\n        \"ASD firmware version\": \"0x210000bb\",\n        \"CE firmware version\": \"37\",\n        \"ME firmware version\": \"64\",\n        \"MEC firmware version\": \"116\",\n        \"MEC2 firmware version\": \"116\",\n        \"PFP firmware version\": \"97\",\n        \"RLC firmware version\": \"74\",\n        \"SDMA firmware version\": \"80\",\n        \"SDMA2 firmware version\": \"80\",\n        \"SMC firmware version\": \"00.65.60.00\",\n        \"SOS firmware version\": \"0x00220b0c\",\n        \"VCN firmware version\": \"0x0211e006\",\n        \"Card series\": \"Navi 22 [Radeon RX 6700/6700 XT / 6800M]\",\n        \"Card model\": \"0x6601\",\n        \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"67XA6SSB1\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"-1\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.3.6\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm612.json",
    "content": "\n{\n    \"card0\": {\n        \"Device Name\": \"Navi 22 [Radeon RX 6700/6700 XT / 6800M]\",\n        \"Device ID\": \"0x73df\",\n        \"Device Rev\": \"0xc1\",\n        \"Subsystem ID\": \"0x6601\",\n        \"GUID\": \"55069\",\n        \"Unique ID\": \"N/A\",\n        \"VBIOS version\": \"113-67XA6SSB1-D01\",\n        \"Temperature (Sensor edge) (C)\": \"45.0\",\n        \"Temperature (Sensor junction) (C)\": \"47.0\",\n        \"Temperature (Sensor memory) (C)\": \"46.0\",\n        \"dcefclk clock speed:\": \"(480Mhz)\",\n        \"dcefclk clock level:\": \"1\",\n        \"fclk clock speed:\": \"(1051Mhz)\",\n        \"fclk clock level:\": \"1\",\n        \"mclk clock speed:\": \"(96Mhz)\",\n        \"mclk clock level:\": \"0\",\n        \"sclk clock speed:\": \"(0Mhz)\",\n        \"sclk clock level:\": \"0\",\n        \"socclk clock speed:\": \"(685Mhz)\",\n        \"socclk clock level:\": \"1\",\n        \"pcie clock level\": \"1 (16.0GT/s x16)\",\n        \"sclk clock level\": \"0 (0Mhz)\",\n        \"Performance Level\": \"auto\",\n        \"GPU OverDrive value (%)\": \"0\",\n        \"GPU Memory OverDrive value (%)\": \"0\",\n        \"Max Graphics Package Power (W)\": \"211.0\",\n        \"Average Graphics Package Power (W)\": \"6.0\",\n        \"0\": \"2.5GT/s x1\",\n        \"1\": \"16.0GT/s x16 *\",\n        \"2\": \"1200Mhz\",\n        \"3\": \"1000Mhz\",\n        \"GPU use (%)\": \"0\",\n        \"GPU Memory Allocated (VRAM%)\": \"12\",\n        \"GPU Memory Read/Write Activity (%)\": \"0\",\n        \"Memory Activity\": \"N/A\",\n        \"Avg. Memory Bandwidth\": \"0\",\n        \"GPU memory vendor\": \"samsung\",\n        \"PCIe Replay Count\": \"0\",\n        \"Serial Number\": \"N/A\",\n        \"Voltage (mV)\": \"6\",\n        \"PCI Bus\": \"0000:07:00.0\",\n        \"VRAM Total Memory (B)\": \"12868124672\",\n        \"VRAM Total Used Memory (B)\": \"1572745216\",\n        \"VIS_VRAM Total Memory (B)\": \"268435456\",\n        \"VIS_VRAM Total Used Memory (B)\": \"70930432\",\n        \"GTT Total Memory (B)\": \"16792432640\",\n        \"GTT Total Used Memory (B)\": \"242036736\",\n        \"ASD firmware version\": \"0x210000bb\",\n        \"CE firmware version\": \"37\",\n        \"ME firmware version\": \"64\",\n        \"MEC firmware version\": \"116\",\n        \"MEC2 firmware version\": \"116\",\n        \"PFP firmware version\": \"97\",\n        \"RLC firmware version\": \"74\",\n        \"SDMA firmware version\": \"80\",\n        \"SDMA2 firmware version\": \"80\",\n        \"SMC firmware version\": \"00.65.60.00\",\n        \"SOS firmware version\": \"0x00220b0c\",\n        \"VCN firmware version\": \"0x0211e006\",\n        \"Card Series\": \"Navi 22 [Radeon RX 6700/6700 XT / 6800M]\",\n        \"Card Model\": \"0x73df\",\n        \"Card Vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n        \"Card SKU\": \"67XA6SSB1\",\n        \"Node ID\": \"1\",\n        \"GFX Version\": \"gfx1031\",\n        \"(Topology) Numa Node\": \"0\",\n        \"(Topology) Numa Affinity\": \"-1\"\n    },\n    \"system\": {\n        \"Driver version\": \"6.3.6\"\n    }\n}\n"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/vega-10-XT.json",
    "content": "{\n  \"card0\": {\n    \"GPU ID\": \"0x6861\",\n    \"Unique ID\": \"0x2150e7d042a1124\",\n    \"VBIOS version\": \"113-D0510100-106\",\n    \"Temperature (Sensor edge) (C)\": \"39.0\",\n    \"Temperature (Sensor junction) (C)\": \"40.0\",\n    \"Temperature (Sensor memory) (C)\": \"92.0\",\n    \"dcefclk clock speed:\": \"(600Mhz)\",\n    \"dcefclk clock level:\": \"0\",\n    \"mclk clock speed:\": \"(167Mhz)\",\n    \"mclk clock level:\": \"0\",\n    \"sclk clock speed:\": \"(1269Mhz)\",\n    \"sclk clock level:\": \"3\",\n    \"socclk clock speed:\": \"(960Mhz)\",\n    \"socclk clock level:\": \"3\",\n    \"pcie clock level\": \"1 (8.0GT/s x16)\",\n    \"sclk clock level\": \"3 (1269Mhz)\",\n    \"Fan speed (level)\": \"33\",\n    \"Fan speed (%)\": \"13\",\n    \"Fan RPM\": \"682\",\n    \"Performance Level\": \"auto\",\n    \"GPU OverDrive value (%)\": \"0\",\n    \"GPU Memory OverDrive value (%)\": \"0\",\n    \"Max Graphics Package Power (W)\": \"170.0\",\n    \"Average Graphics Package Power (W)\": \"15.0\",\n    \"0\": \"8.0GT/s x16\",\n    \"1\": \"8.0GT/s x16 *\",\n    \"2\": \"847Mhz\",\n    \"3\": \"960Mhz *\",\n    \"4\": \"1028Mhz\",\n    \"5\": \"1107Mhz\",\n    \"6\": \"1440Mhz\",\n    \"7\": \"1500Mhz\",\n    \"GPU use (%)\": \"0\",\n    \"GPU memory vendor\": \"samsung\",\n    \"PCIe Replay Count\": \"0\",\n    \"Serial Number\": \"N/A\",\n    \"Voltage (mV)\": \"906\",\n    \"PCI Bus\": \"0000:04:00.0\",\n    \"VRAM Total Memory (B)\": \"17163091968\",\n    \"VRAM Total Used Memory (B)\": \"17776640\",\n    \"VIS_VRAM Total Memory (B)\": \"268435456\",\n    \"VIS_VRAM Total Used Memory (B)\": \"13557760\",\n    \"GTT Total Memory (B)\": \"17163091968\",\n    \"GTT Total Used Memory (B)\": \"25608192\",\n    \"ASD firmware version\": \"553648152\",\n    \"CE firmware version\": \"79\",\n    \"DMCU firmware version\": \"0\",\n    \"MC firmware version\": \"0\",\n    \"ME firmware version\": \"163\",\n    \"MEC firmware version\": \"432\",\n    \"MEC2 firmware version\": \"432\",\n    \"PFP firmware version\": \"186\",\n    \"RLC firmware version\": \"93\",\n    \"RLC SRLC firmware version\": \"0\",\n    \"RLC SRLG firmware version\": \"0\",\n    \"RLC SRLS firmware version\": \"0\",\n    \"SDMA firmware version\": \"430\",\n    \"SDMA2 firmware version\": \"430\",\n    \"SMC firmware version\": \"00.28.54.00\",\n    \"SOS firmware version\": \"0x0008015d\",\n    \"TA RAS firmware version\": \"00.00.00.00\",\n    \"TA XGMI firmware version\": \"00.00.00.00\",\n    \"UVD firmware version\": \"0x422b1100\",\n    \"VCE firmware version\": \"0x39060400\",\n    \"VCN firmware version\": \"0x00000000\",\n    \"Card model\": \"0xc1e\",\n    \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n    \"Card SKU\": \"D05101\",\n    \"(Topology) Numa Node\": \"0\",\n    \"(Topology) Numa Affinity\": \"0\"\n  },\n  \"system\": {\n    \"Driver version\": \"5.9.25\"\n  }\n}"
  },
  {
    "path": "plugins/inputs/amd_rocm_smi/testdata/vega-20-WKS-GL-XE.json",
    "content": "{\n  \"card0\": {\n    \"GPU ID\": \"0x66a1\",\n    \"Unique ID\": \"0x2f048617326b1ea\",\n    \"VBIOS version\": \"113-D1631700-111\",\n    \"Temperature (Sensor edge) (C)\": \"36.0\",\n    \"Temperature (Sensor junction) (C)\": \"38.0\",\n    \"Temperature (Sensor memory) (C)\": \"35.0\",\n    \"dcefclk clock speed:\": \"(357Mhz)\",\n    \"dcefclk clock level:\": \"0\",\n    \"fclk clock speed:\": \"(1080Mhz)\",\n    \"fclk clock level:\": \"6\",\n    \"mclk clock speed:\": \"(1000Mhz)\",\n    \"mclk clock level:\": \"2\",\n    \"sclk clock speed:\": \"(1725Mhz)\",\n    \"sclk clock level:\": \"8\",\n    \"socclk clock speed:\": \"(971Mhz)\",\n    \"socclk clock level:\": \"7\",\n    \"pcie clock level\": \"1 (16.0GT/s x16)\",\n    \"sclk clock level\": \"8 (1725Mhz)\",\n    \"Fan speed (level)\": \"0\",\n    \"Fan speed (%)\": \"0\",\n    \"Fan RPM\": \"0\",\n    \"Performance Level\": \"high\",\n    \"GPU OverDrive value (%)\": \"0\",\n    \"Max Graphics Package Power (W)\": \"225.0\",\n    \"Average Graphics Package Power (W)\": \"26.0\",\n    \"0\": \"2.5GT/s x16\",\n    \"1\": \"16.0GT/s x16 *\",\n    \"2\": \"566Mhz\",\n    \"3\": \"618Mhz\",\n    \"4\": \"680Mhz\",\n    \"5\": \"755Mhz\",\n    \"6\": \"850Mhz\",\n    \"7\": \"971Mhz *\",\n    \"8\": \"1725Mhz *\",\n    \"GPU use (%)\": \"0\",\n    \"GPU memory use (%)\": \"0\",\n    \"GPU memory vendor\": \"samsung\",\n    \"PCIe Replay Count\": \"0\",\n    \"Serial Number\": \"692024000810\",\n    \"Voltage (mV)\": \"1000\",\n    \"PCI Bus\": \"0000:63:00.0\",\n    \"VRAM Total Memory (B)\": \"34342961152\",\n    \"VRAM Total Used Memory (B)\": \"10850304\",\n    \"VIS_VRAM Total Memory (B)\": \"34342961152\",\n    \"VIS_VRAM Total Used Memory (B)\": \"10850304\",\n    \"GTT Total Memory (B)\": \"54974742528\",\n    \"GTT Total Used Memory (B)\": \"11591680\",\n    \"ASD firmware version\": \"553648199\",\n    \"CE firmware version\": \"79\",\n    \"DMCU firmware version\": \"0\",\n    \"MC firmware version\": \"0\",\n    \"ME firmware version\": \"164\",\n    \"MEC firmware version\": \"448\",\n    \"MEC2 firmware version\": \"448\",\n    \"PFP firmware version\": \"188\",\n    \"RLC firmware version\": \"50\",\n    \"RLC SRLC firmware version\": \"1\",\n    \"RLC SRLG firmware version\": \"1\",\n    \"RLC SRLS firmware version\": \"1\",\n    \"SDMA firmware version\": \"144\",\n    \"SDMA2 firmware version\": \"144\",\n    \"SMC firmware version\": \"00.40.59.00\",\n    \"SOS firmware version\": \"0x00080b67\",\n    \"TA RAS firmware version\": \"27.00.01.36\",\n    \"TA XGMI firmware version\": \"32.00.00.02\",\n    \"UVD firmware version\": \"0x42002b13\",\n    \"VCE firmware version\": \"0x39060400\",\n    \"VCN firmware version\": \"0x00000000\",\n    \"Card series\": \"Radeon Instinct MI50 32GB\",\n    \"Card model\": \"0x834\",\n    \"Card vendor\": \"Advanced Micro Devices, Inc. [AMD/ATI]\",\n    \"Card SKU\": \"D16317\",\n    \"(Topology) Numa Node\": \"0\",\n    \"(Topology) Numa Affinity\": \"0\"\n  },\n  \"system\": {\n    \"Driver version\": \"5.9.17\",\n    \"(Topology) Weight between DRM devices 0 and 1\": \"40\",\n    \"(Topology) Weight between DRM devices 0 and 2\": \"40\",\n    \"(Topology) Weight between DRM devices 0 and 3\": \"40\",\n    \"(Topology) Weight between DRM devices 0 and 4\": \"72\",\n    \"(Topology) Weight between DRM devices 0 and 5\": \"72\",\n    \"(Topology) Weight between DRM devices 0 and 6\": \"72\",\n    \"(Topology) Weight between DRM devices 0 and 7\": \"72\",\n    \"(Topology) Weight between DRM devices 1 and 2\": \"40\",\n    \"(Topology) Weight between DRM devices 1 and 3\": \"40\",\n    \"(Topology) Weight between DRM devices 1 and 4\": \"72\",\n    \"(Topology) Weight between DRM devices 1 and 5\": \"72\",\n    \"(Topology) Weight between DRM devices 1 and 6\": \"72\",\n    \"(Topology) Weight between DRM devices 1 and 7\": \"72\",\n    \"(Topology) Weight between DRM devices 2 and 3\": \"40\",\n    \"(Topology) Weight between DRM devices 2 and 4\": \"72\",\n    \"(Topology) Weight between DRM devices 2 and 5\": \"72\",\n    \"(Topology) Weight between DRM devices 2 and 6\": \"72\",\n    \"(Topology) Weight between DRM devices 2 and 7\": \"72\",\n    \"(Topology) Weight between DRM devices 3 and 4\": \"72\",\n    \"(Topology) Weight between DRM devices 3 and 5\": \"72\",\n    \"(Topology) Weight between DRM devices 3 and 6\": \"72\",\n    \"(Topology) Weight between DRM devices 3 and 7\": \"72\",\n    \"(Topology) Weight between DRM devices 4 and 5\": \"40\",\n    \"(Topology) Weight between DRM devices 4 and 6\": \"40\",\n    \"(Topology) Weight between DRM devices 4 and 7\": \"40\",\n    \"(Topology) Weight between DRM devices 5 and 6\": \"40\",\n    \"(Topology) Weight between DRM devices 5 and 7\": \"40\",\n    \"(Topology) Weight between DRM devices 6 and 7\": \"40\",\n    \"(Topology) Hops between DRM devices 0 and 1\": \"2\",\n    \"(Topology) Hops between DRM devices 0 and 2\": \"2\",\n    \"(Topology) Hops between DRM devices 0 and 3\": \"2\",\n    \"(Topology) Hops between DRM devices 0 and 4\": \"3\",\n    \"(Topology) Hops between DRM devices 0 and 5\": \"3\",\n    \"(Topology) Hops between DRM devices 0 and 6\": \"3\",\n    \"(Topology) Hops between DRM devices 0 and 7\": \"3\",\n    \"(Topology) Hops between DRM devices 1 and 2\": \"2\",\n    \"(Topology) Hops between DRM devices 1 and 3\": \"2\",\n    \"(Topology) Hops between DRM devices 1 and 4\": \"3\",\n    \"(Topology) Hops between DRM devices 1 and 5\": \"3\",\n    \"(Topology) Hops between DRM devices 1 and 6\": \"3\",\n    \"(Topology) Hops between DRM devices 1 and 7\": \"3\",\n    \"(Topology) Hops between DRM devices 2 and 3\": \"2\",\n    \"(Topology) Hops between DRM devices 2 and 4\": \"3\",\n    \"(Topology) Hops between DRM devices 2 and 5\": \"3\",\n    \"(Topology) Hops between DRM devices 2 and 6\": \"3\",\n    \"(Topology) Hops between DRM devices 2 and 7\": \"3\",\n    \"(Topology) Hops between DRM devices 3 and 4\": \"3\",\n    \"(Topology) Hops between DRM devices 3 and 5\": \"3\",\n    \"(Topology) Hops between DRM devices 3 and 6\": \"3\",\n    \"(Topology) Hops between DRM devices 3 and 7\": \"3\",\n    \"(Topology) Hops between DRM devices 4 and 5\": \"2\",\n    \"(Topology) Hops between DRM devices 4 and 6\": \"2\",\n    \"(Topology) Hops between DRM devices 4 and 7\": \"2\",\n    \"(Topology) Hops between DRM devices 5 and 6\": \"2\",\n    \"(Topology) Hops between DRM devices 5 and 7\": \"2\",\n    \"(Topology) Hops between DRM devices 6 and 7\": \"2\",\n    \"(Topology) Link type between DRM devices 0 and 1\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 2\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 3\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 4\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 5\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 0 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 2\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 3\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 4\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 5\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 1 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 2 and 3\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 2 and 4\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 2 and 5\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 2 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 2 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 3 and 4\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 3 and 5\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 3 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 3 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 4 and 5\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 4 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 4 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 5 and 6\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 5 and 7\": \"PCIE\",\n    \"(Topology) Link type between DRM devices 6 and 7\": \"PCIE\"\n  }\n}"
  },
  {
    "path": "plugins/inputs/amqp_consumer/README.md",
    "content": "# AMQP Consumer Input Plugin\n\nThis plugin consumes messages from an Advanced Message Queuing Protocol v0.9.1\nbroker. A prominent implementation of this protocol is [RabbitMQ][rabbitmq].\n\nMetrics are read from a topic exchange using the configured queue and binding\nkey. The message payloads must be formatted in one of the supported\n[data formats][data_formats].\n\nFor an introduction check the [AMQP concepts page][amqp_concepts] and the\n[RabbitMQ getting started guide][rabbitmq_getting_started].\n\n⭐ Telegraf v1.3.0\n🏷️ messaging\n💻 all\n\n[amqp_concepts]: https://www.rabbitmq.com/tutorials/amqp-concepts.html\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n[rabbitmq]: https://www.rabbitmq.com\n[rabbitmq_getting_started]: https://www.rabbitmq.com/getstarted.html\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options <!-- @/docs/includes/startup_error_behavior.md -->\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  Telegraf will try to startup the plugin in every gather or write\n            cycle in case of startup errors. The plugin is disabled until\n            the startup succeeds.\n- `probe`:  Telegraf will probe the plugin's function (if possible) and disables\n            the plugin in case probing fails. If the plugin does not support\n            probing, Telegraf will behave as if `ignore` was set instead.\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  ## Brokers to consume from.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\"]\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n## Message acknowledgement behavior\n\nThis plugin tracks metrics to report the delivery state to the broker.\n\nMessages are **acknowledged** (ACK) in the broker if they were successfully\nparsed and delivered to all corresponding output sinks.\n\nMessages are **not acknowledged** (NACK) if parsing of the messages fails and no\nmetrics were created. In this case requeueing is disabled so messages will not\nbe sent out to any other queue. The message will then be discarded or sent to a\ndead-letter exchange depending on the server configuration. See\n[RabitMQ documentation][rabbitmq_doc] for more details.\n\nMessages are **rejected** (REJECT) if the messages were parsed correctly but\ncould not be delivered e.g. due to output-service outages. Requeueing is\ndisabled in this case and messages will be discarded by the server. See\n[RabitMQ documentation][rabbitmq_doc] for more details.\n\n[rabbitmq_doc]: https://www.rabbitmq.com/docs/confirms\n\n## Metrics\n\nThe format of metrics produced by this plugin depends on the content and\ndata format of received messages.\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/amqp_consumer/amqp_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage amqp_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tamqp \"github.com/rabbitmq/amqp091-go\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype empty struct{}\ntype externalAuth struct{}\n\ntype semaphore chan empty\n\ntype AMQPConsumer struct {\n\tBrokers                []string               `toml:\"brokers\"`\n\tUsername               config.Secret          `toml:\"username\"`\n\tPassword               config.Secret          `toml:\"password\"`\n\tExchange               string                 `toml:\"exchange\"`\n\tExchangeType           string                 `toml:\"exchange_type\"`\n\tExchangeDurability     string                 `toml:\"exchange_durability\"`\n\tExchangePassive        bool                   `toml:\"exchange_passive\"`\n\tExchangeArguments      map[string]string      `toml:\"exchange_arguments\"`\n\tMaxUndeliveredMessages int                    `toml:\"max_undelivered_messages\"`\n\tQueue                  string                 `toml:\"queue\"`\n\tQueueDurability        string                 `toml:\"queue_durability\"`\n\tQueuePassive           bool                   `toml:\"queue_passive\"`\n\tQueueArguments         map[string]interface{} `toml:\"queue_arguments\"`\n\tQueueConsumeArguments  map[string]string      `toml:\"queue_consume_arguments\"`\n\tBindingKey             string                 `toml:\"binding_key\"`\n\tPrefetchCount          int                    `toml:\"prefetch_count\"`\n\tAuthMethod             string                 `toml:\"auth_method\"`\n\tContentEncoding        string                 `toml:\"content_encoding\"`\n\tMaxDecompressionSize   config.Size            `toml:\"max_decompression_size\"`\n\tTimeout                config.Duration        `toml:\"timeout\"`\n\tLog                    telegraf.Logger        `toml:\"-\"`\n\ttls.ClientConfig\n\n\tdeliveries map[telegraf.TrackingID]amqp.Delivery\n\n\tparser  telegraf.Parser\n\tconn    *amqp.Connection\n\twg      *sync.WaitGroup\n\tcancel  context.CancelFunc\n\tdecoder internal.ContentDecoder\n}\n\n// Mechanism represents the authentication mechanism used for AMQP connections.\nfunc (*externalAuth) Mechanism() string {\n\treturn \"EXTERNAL\"\n}\n\n// Response represents the response returned by the AMQP server.\nfunc (*externalAuth) Response() string {\n\treturn \"\\000\"\n}\n\nfunc (*AMQPConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *AMQPConsumer) Init() error {\n\t// Defaults\n\tif len(a.Brokers) == 0 {\n\t\ta.Brokers = []string{\"amqp://localhost:5672/influxdb\"}\n\t}\n\n\tif a.AuthMethod == \"\" {\n\t\ta.AuthMethod = \"PLAIN\"\n\t}\n\n\tif a.ExchangeType == \"\" {\n\t\ta.ExchangeType = \"topic\"\n\t}\n\n\tif a.ExchangeDurability == \"\" {\n\t\ta.ExchangeDurability = \"durable\"\n\t}\n\n\tif a.QueueDurability == \"\" {\n\t\ta.QueueDurability = \"durable\"\n\t}\n\n\tif a.PrefetchCount == 0 {\n\t\ta.PrefetchCount = 50\n\t}\n\n\tif a.MaxUndeliveredMessages == 0 {\n\t\ta.MaxUndeliveredMessages = 1000\n\t}\n\n\treturn nil\n}\n\nfunc (a *AMQPConsumer) SetParser(parser telegraf.Parser) {\n\ta.parser = parser\n}\n\nfunc (a *AMQPConsumer) Start(acc telegraf.Accumulator) error {\n\tamqpConf, err := a.createConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar options []internal.DecodingOption\n\tif a.MaxDecompressionSize > 0 {\n\t\toptions = append(options, internal.WithMaxDecompressionSize(int64(a.MaxDecompressionSize)))\n\t}\n\ta.decoder, err = internal.NewContentDecoder(a.ContentEncoding, options...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmsgs, err := a.connect(amqpConf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\ta.cancel = cancel\n\n\ta.wg = &sync.WaitGroup{}\n\ta.wg.Add(1)\n\tgo func() {\n\t\tdefer a.wg.Done()\n\t\ta.process(ctx, msgs, acc)\n\t}()\n\n\tgo func() {\n\t\tfor {\n\t\t\terr := <-a.conn.NotifyClose(make(chan *amqp.Error))\n\t\t\tif err == nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ta.Log.Infof(\"Connection closed: %s; trying to reconnect\", err)\n\t\t\tfor {\n\t\t\t\tmsgs, err := a.connect(amqpConf)\n\t\t\t\tif err != nil {\n\t\t\t\t\ta.Log.Errorf(\"AMQP connection failed: %s\", err)\n\t\t\t\t\ttime.Sleep(10 * time.Second)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ta.wg.Add(1)\n\t\t\t\tgo func() {\n\t\t\t\t\tdefer a.wg.Done()\n\t\t\t\t\ta.process(ctx, msgs, acc)\n\t\t\t\t}()\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (*AMQPConsumer) Gather(_ telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (a *AMQPConsumer) Stop() {\n\t// We did not connect successfully so there is nothing to do here.\n\tif a.conn == nil || a.conn.IsClosed() {\n\t\treturn\n\t}\n\ta.cancel()\n\ta.wg.Wait()\n\terr := a.conn.Close()\n\tif err != nil && !errors.Is(err, amqp.ErrClosed) {\n\t\ta.Log.Errorf(\"Error closing AMQP connection: %s\", err)\n\t\treturn\n\t}\n}\n\nfunc (a *AMQPConsumer) createConfig() (*amqp.Config, error) {\n\t// make new tls config\n\ttlsCfg, err := a.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar auth []amqp.Authentication\n\n\tif strings.EqualFold(a.AuthMethod, \"EXTERNAL\") {\n\t\tauth = []amqp.Authentication{&externalAuth{}}\n\t} else if !a.Username.Empty() || !a.Password.Empty() {\n\t\tusername, err := a.Username.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting username failed: %w\", err)\n\t\t}\n\t\tdefer username.Destroy()\n\n\t\tpassword, err := a.Password.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting password failed: %w\", err)\n\t\t}\n\t\tdefer password.Destroy()\n\n\t\tauth = []amqp.Authentication{\n\t\t\t&amqp.PlainAuth{\n\t\t\t\tUsername: username.String(),\n\t\t\t\tPassword: password.String(),\n\t\t\t},\n\t\t}\n\t}\n\tamqpConfig := amqp.Config{\n\t\tTLSClientConfig: tlsCfg,\n\t\tSASL:            auth, // if nil, it will be PLAIN\n\t\tDial:            amqp.DefaultDial(time.Duration(a.Timeout)),\n\t}\n\treturn &amqpConfig, nil\n}\n\nfunc (a *AMQPConsumer) connect(amqpConf *amqp.Config) (<-chan amqp.Delivery, error) {\n\tbrokers := a.Brokers\n\n\tp := rand.Perm(len(brokers))\n\tfor _, n := range p {\n\t\tbroker := brokers[n]\n\t\ta.Log.Debugf(\"Connecting to %q\", broker)\n\t\tconn, err := amqp.DialConfig(broker, *amqpConf)\n\t\tif err == nil {\n\t\t\ta.conn = conn\n\t\t\ta.Log.Debugf(\"Connected to %q\", broker)\n\t\t\tbreak\n\t\t}\n\t\ta.Log.Errorf(\"Error connecting to %q: %s\", broker, err)\n\t}\n\n\tif a.conn == nil {\n\t\treturn nil, &internal.StartupError{\n\t\t\tErr:   errors.New(\"could not connect to any broker\"),\n\t\t\tRetry: true,\n\t\t}\n\t}\n\n\tch, err := a.conn.Channel()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open a channel: %w\", err)\n\t}\n\n\tif a.Exchange != \"\" {\n\t\texchangeDurable := true\n\t\tif a.ExchangeDurability == \"transient\" {\n\t\t\texchangeDurable = false\n\t\t}\n\n\t\texchangeArgs := make(amqp.Table, len(a.ExchangeArguments))\n\t\tfor k, v := range a.ExchangeArguments {\n\t\t\texchangeArgs[k] = v\n\t\t}\n\n\t\terr = a.declareExchange(\n\t\t\tch,\n\t\t\texchangeDurable,\n\t\t\texchangeArgs)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tq, err := a.declareQueue(ch)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif a.BindingKey != \"\" {\n\t\terr = ch.QueueBind(\n\t\t\tq.Name,       // queue\n\t\t\ta.BindingKey, // binding-key\n\t\t\ta.Exchange,   // exchange\n\t\t\tfalse,\n\t\t\tnil,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to bind a queue: %w\", err)\n\t\t}\n\t}\n\n\terr = ch.Qos(\n\t\ta.PrefetchCount,\n\t\t0,     // prefetch-size\n\t\tfalse, // global\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to set QoS: %w\", err)\n\t}\n\n\tconsumeArgs := make(amqp.Table, len(a.QueueConsumeArguments))\n\tfor k, v := range a.QueueConsumeArguments {\n\t\tconsumeArgs[k] = v\n\t}\n\n\tmsgs, err := ch.Consume(\n\t\tq.Name,      // queue\n\t\t\"\",          // consumer\n\t\tfalse,       // auto-ack\n\t\tfalse,       // exclusive\n\t\tfalse,       // no-local\n\t\tfalse,       // no-wait\n\t\tconsumeArgs, // arguments\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed establishing connection to queue: %w\", err)\n\t}\n\n\treturn msgs, err\n}\n\nfunc (a *AMQPConsumer) declareExchange(\n\tchannel *amqp.Channel,\n\texchangeDurable bool,\n\texchangeArguments amqp.Table,\n) error {\n\tvar err error\n\tif a.ExchangePassive {\n\t\terr = channel.ExchangeDeclarePassive(\n\t\t\ta.Exchange,\n\t\t\ta.ExchangeType,\n\t\t\texchangeDurable,\n\t\t\tfalse, // delete when unused\n\t\t\tfalse, // internal\n\t\t\tfalse, // no-wait\n\t\t\texchangeArguments,\n\t\t)\n\t} else {\n\t\terr = channel.ExchangeDeclare(\n\t\t\ta.Exchange,\n\t\t\ta.ExchangeType,\n\t\t\texchangeDurable,\n\t\t\tfalse, // delete when unused\n\t\t\tfalse, // internal\n\t\t\tfalse, // no-wait\n\t\t\texchangeArguments,\n\t\t)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error declaring exchange: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (a *AMQPConsumer) declareQueue(channel *amqp.Channel) (*amqp.Queue, error) {\n\tvar queue amqp.Queue\n\tvar err error\n\n\tqueueDurable := true\n\tif a.QueueDurability == \"transient\" {\n\t\tqueueDurable = false\n\t}\n\n\tqueueArgs := make(amqp.Table, len(a.QueueArguments))\n\tfor k, v := range a.QueueArguments {\n\t\tqueueArgs[k] = v\n\t}\n\n\tif a.QueuePassive {\n\t\tqueue, err = channel.QueueDeclarePassive(\n\t\t\ta.Queue,      // queue\n\t\t\tqueueDurable, // durable\n\t\t\tfalse,        // delete when unused\n\t\t\tfalse,        // exclusive\n\t\t\tfalse,        // no-wait\n\t\t\tqueueArgs,    // arguments\n\t\t)\n\t} else {\n\t\tqueue, err = channel.QueueDeclare(\n\t\t\ta.Queue,      // queue\n\t\t\tqueueDurable, // durable\n\t\t\tfalse,        // delete when unused\n\t\t\tfalse,        // exclusive\n\t\t\tfalse,        // no-wait\n\t\t\tqueueArgs,    // arguments\n\t\t)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error declaring queue: %w\", err)\n\t}\n\treturn &queue, nil\n}\n\n// Read messages from queue and add them to the Accumulator\nfunc (a *AMQPConsumer) process(ctx context.Context, msgs <-chan amqp.Delivery, ac telegraf.Accumulator) {\n\ta.deliveries = make(map[telegraf.TrackingID]amqp.Delivery)\n\n\tacc := ac.WithTracking(a.MaxUndeliveredMessages)\n\tsem := make(semaphore, a.MaxUndeliveredMessages)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase track := <-acc.Delivered():\n\t\t\tif a.onDelivery(track) {\n\t\t\t\t<-sem\n\t\t\t}\n\t\tcase sem <- empty{}:\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase track := <-acc.Delivered():\n\t\t\t\tif a.onDelivery(track) {\n\t\t\t\t\t<-sem\n\t\t\t\t\t<-sem\n\t\t\t\t}\n\t\t\tcase d, ok := <-msgs:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\terr := a.onMessage(acc, d)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t<-sem\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (a *AMQPConsumer) onMessage(acc telegraf.TrackingAccumulator, d amqp.Delivery) error {\n\tonError := func() {\n\t\t// Discard the message from the queue; will never be able to process it\n\t\tif err := d.Nack(false, false); err != nil {\n\t\t\ta.Log.Errorf(\"Unable to NACK message: %d: %v\", d.DeliveryTag, err)\n\t\t\ta.conn.Close()\n\t\t}\n\t}\n\n\ta.decoder.SetEncoding(d.ContentEncoding)\n\tbody, err := a.decoder.Decode(d.Body)\n\tif err != nil {\n\t\tonError()\n\t\treturn err\n\t}\n\n\tmetrics, err := a.parser.Parse(body)\n\tif err != nil {\n\t\tonError()\n\t\treturn err\n\t}\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\ta.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tid := acc.AddTrackingMetricGroup(metrics)\n\ta.deliveries[id] = d\n\treturn nil\n}\n\nfunc (a *AMQPConsumer) onDelivery(track telegraf.DeliveryInfo) bool {\n\tdelivery, ok := a.deliveries[track.ID()]\n\tif !ok {\n\t\t// Added by a previous connection\n\t\treturn false\n\t}\n\n\tif track.Delivered() {\n\t\terr := delivery.Ack(false)\n\t\tif err != nil {\n\t\t\ta.Log.Errorf(\"Unable to ack written delivery: %d: %v\", delivery.DeliveryTag, err)\n\t\t\ta.conn.Close()\n\t\t}\n\t} else {\n\t\terr := delivery.Reject(false)\n\t\tif err != nil {\n\t\t\ta.Log.Errorf(\"Unable to reject failed delivery: %d: %v\", delivery.DeliveryTag, err)\n\t\t\ta.conn.Close()\n\t\t}\n\t}\n\n\tdelete(a.deliveries, track.ID())\n\treturn true\n}\n\nfunc init() {\n\tinputs.Add(\"amqp_consumer\", func() telegraf.Input {\n\t\treturn &AMQPConsumer{Timeout: config.Duration(30 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/amqp_consumer/amqp_consumer_test.go",
    "content": "package amqp_consumer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/rabbitmq/amqp091-go\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAutoEncoding(t *testing.T) {\n\t// Setup a gzipped payload\n\tenc, err := internal.NewGzipEncoder()\n\trequire.NoError(t, err)\n\tpayloadGZip, err := enc.Encode([]byte(`measurementName fieldKey=\"gzip\" 1556813561098000000`))\n\trequire.NoError(t, err)\n\n\t// Setup the plugin including the message parser\n\tdecoder, err := internal.NewContentDecoder(\"auto\")\n\trequire.NoError(t, err)\n\tplugin := &AMQPConsumer{\n\t\tdeliveries: make(map[telegraf.TrackingID]amqp091.Delivery),\n\t\tdecoder:    decoder,\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Setup the message creator\n\tmsg := amqp091.Delivery{\n\t\tContentEncoding: \"gzip\",\n\t\tBody:            payloadGZip,\n\t}\n\n\t// Simulate a message receive event\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.onMessage(&acc, msg))\n\tacc.AssertContainsFields(t, \"measurementName\", map[string]interface{}{\"fieldKey\": \"gzip\"})\n\n\t// Check the decoding\n\tencIdentity, err := internal.NewIdentityEncoder()\n\trequire.NoError(t, err)\n\tpayload, err := encIdentity.Encode([]byte(`measurementName2 fieldKey=\"identity\" 1556813561098000000`))\n\trequire.NoError(t, err)\n\n\t// Setup a non-encoded payload\n\tmsg = amqp091.Delivery{\n\t\tContentEncoding: \"not_gzip\",\n\t\tBody:            payload,\n\t}\n\n\t// Simulate a message receive event\n\trequire.NoError(t, plugin.onMessage(&acc, msg))\n\trequire.NoError(t, err)\n\tacc.AssertContainsFields(t, \"measurementName2\", map[string]interface{}{\"fieldKey\": \"identity\"})\n}\n\nfunc TestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Define common properties\n\tservicePort := \"5672\"\n\tvhost := \"/\"\n\texchange := \"telegraf\"\n\texchangeType := \"direct\"\n\tqueueName := \"test\"\n\tbindingKey := \"test\"\n\n\t// Setup the container\n\tcontainer := testutil.Container{\n\t\tImage:        \"rabbitmq\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"Server startup complete\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\turl := fmt.Sprintf(\"amqp://%s:%s%s\", container.Address, container.Ports[servicePort], vhost)\n\n\t// Setup a AMQP producer to send messages\n\tclient, err := newProducer(url, vhost, exchange, exchangeType, queueName, bindingKey)\n\trequire.NoError(t, err)\n\tdefer client.close()\n\n\t// Setup the plugin with an Influx line-protocol parser\n\tplugin := &AMQPConsumer{\n\t\tBrokers:      []string{url},\n\t\tUsername:     config.NewSecret([]byte(\"guest\")),\n\t\tPassword:     config.NewSecret([]byte(\"guest\")),\n\t\tTimeout:      config.Duration(3 * time.Second),\n\t\tExchange:     exchange,\n\t\tExchangeType: exchangeType,\n\t\tQueue:        queueName,\n\t\tBindingKey:   bindingKey,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the metrics\n\tmetrics := []string{\n\t\t\"test,source=A value=0i 1712780301000000000\",\n\t\t\"test,source=B value=1i 1712780301000000100\",\n\t\t\"test,source=C value=2i 1712780301000000200\",\n\t}\n\texpected := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, x := range metrics {\n\t\tm, err := parser.Parse([]byte(x))\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, m...)\n\t}\n\n\t// Start the plugin\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Write metrics\n\tfor _, x := range metrics {\n\t\trequire.NoError(t, client.write(t.Context(), exchange, queueName, []byte(x)))\n\t}\n\n\t// Verify that the metrics were actually written\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tclient.close()\n\tplugin.Stop()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestStartupErrorBehaviorError(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Define common properties\n\tservicePort := \"5672\"\n\tvhost := \"/\"\n\texchange := \"telegraf\"\n\texchangeType := \"direct\"\n\tqueueName := \"test\"\n\tbindingKey := \"test\"\n\n\t// Setup the container\n\tcontainer := testutil.Container{\n\t\tImage:        \"rabbitmq\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"Server startup complete\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\turl := fmt.Sprintf(\"amqp://%s:%s%s\", container.Address, container.Ports[servicePort], vhost)\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin with an Influx line-protocol parser\n\tplugin := &AMQPConsumer{\n\t\tBrokers:      []string{url},\n\t\tUsername:     config.NewSecret([]byte(\"guest\")),\n\t\tPassword:     config.NewSecret([]byte(\"guest\")),\n\t\tTimeout:      config.Duration(1 * time.Second),\n\t\tExchange:     exchange,\n\t\tExchangeType: exchangeType,\n\t\tQueue:        queueName,\n\t\tBindingKey:   bindingKey,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName: \"amqp\",\n\t\t},\n\t)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail with an error because the container\n\t// is paused.\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, model.Start(&acc), \"could not connect to any broker\")\n}\n\nfunc TestStartupErrorBehaviorIgnore(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Define common properties\n\tservicePort := \"5672\"\n\tvhost := \"/\"\n\texchange := \"telegraf\"\n\texchangeType := \"direct\"\n\tqueueName := \"test\"\n\tbindingKey := \"test\"\n\n\t// Setup the container\n\tcontainer := testutil.Container{\n\t\tImage:        \"rabbitmq\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"Server startup complete\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\turl := fmt.Sprintf(\"amqp://%s:%s%s\", container.Address, container.Ports[servicePort], vhost)\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin with an Influx line-protocol parser\n\tplugin := &AMQPConsumer{\n\t\tBrokers:      []string{url},\n\t\tUsername:     config.NewSecret([]byte(\"guest\")),\n\t\tPassword:     config.NewSecret([]byte(\"guest\")),\n\t\tTimeout:      config.Duration(1 * time.Second),\n\t\tExchange:     exchange,\n\t\tExchangeType: exchangeType,\n\t\tQueue:        queueName,\n\t\tBindingKey:   bindingKey,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"amqp\",\n\t\t\tStartupErrorBehavior: \"ignore\",\n\t\t},\n\t)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail because the container is paused.\n\t// The model code should convert it to a fatal error for the agent to remove\n\t// the plugin.\n\tvar acc testutil.Accumulator\n\terr := model.Start(&acc)\n\trequire.ErrorContains(t, err, \"could not connect to any broker\")\n\tvar fatalErr *internal.FatalError\n\trequire.ErrorAs(t, err, &fatalErr)\n}\n\nfunc TestStartupErrorBehaviorRetry(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Define common properties\n\tservicePort := \"5672\"\n\tvhost := \"/\"\n\texchange := \"telegraf\"\n\texchangeType := \"direct\"\n\tqueueName := \"test\"\n\tbindingKey := \"test\"\n\n\t// Setup the container\n\tcontainer := testutil.Container{\n\t\tImage:        \"rabbitmq\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"Server startup complete\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\turl := fmt.Sprintf(\"amqp://%s:%s%s\", container.Address, container.Ports[servicePort], vhost)\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin with an Influx line-protocol parser\n\tplugin := &AMQPConsumer{\n\t\tBrokers:      []string{url},\n\t\tUsername:     config.NewSecret([]byte(\"guest\")),\n\t\tPassword:     config.NewSecret([]byte(\"guest\")),\n\t\tTimeout:      config.Duration(1 * time.Second),\n\t\tExchange:     exchange,\n\t\tExchangeType: exchangeType,\n\t\tQueue:        queueName,\n\t\tBindingKey:   bindingKey,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"amqp\",\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t)\n\trequire.NoError(t, model.Init())\n\n\t// Setup the metrics\n\tmetrics := []string{\n\t\t\"test,source=A value=0i 1712780301000000000\",\n\t\t\"test,source=B value=1i 1712780301000000100\",\n\t\t\"test,source=C value=2i 1712780301000000200\",\n\t}\n\texpected := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, x := range metrics {\n\t\tm, err := parser.Parse([]byte(x))\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, m...)\n\t}\n\n\t// Starting the plugin should succeed as we will retry to startup later\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, model.Start(&acc))\n\n\t// There should be no metrics as the plugin is not fully started up yet\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n\trequire.Equal(t, int64(2), model.StartupErrors.Get())\n\n\t// Unpause the container, now writes should succeed\n\trequire.NoError(t, container.Resume())\n\trequire.NoError(t, model.Gather(&acc))\n\tdefer model.Stop()\n\n\t// Setup a AMQP producer and send messages\n\tclient, err := newProducer(url, vhost, exchange, exchangeType, queueName, bindingKey)\n\trequire.NoError(t, err)\n\tdefer client.close()\n\n\t// Write metrics\n\tfor _, x := range metrics {\n\t\trequire.NoError(t, client.write(t.Context(), exchange, queueName, []byte(x)))\n\t}\n\n\t// Verify that the metrics were actually collected\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tclient.close()\n\tplugin.Stop()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\ntype producer struct {\n\tconn    *amqp091.Connection\n\tchannel *amqp091.Channel\n\tqueue   amqp091.Queue\n}\n\nfunc newProducer(url, vhost, exchange, exchangeType, queueName, key string) (*producer, error) {\n\tcfg := amqp091.Config{\n\t\tVhost:      vhost,\n\t\tProperties: amqp091.NewConnectionProperties(),\n\t}\n\tcfg.Properties.SetClientConnectionName(\"test-producer\")\n\tconn, err := amqp091.DialConfig(url, cfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tchannel, err := conn.Channel()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := channel.ExchangeDeclare(exchange, exchangeType, true, false, false, false, nil); err != nil {\n\t\treturn nil, err\n\t}\n\n\tqueue, err := channel.QueueDeclare(queueName, true, false, false, false, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := channel.QueueBind(queue.Name, key, exchange, false, nil); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &producer{\n\t\tconn:    conn,\n\t\tchannel: channel,\n\t\tqueue:   queue,\n\t}, nil\n}\n\nfunc (p *producer) close() {\n\tp.channel.Close()\n\tp.conn.Close()\n}\n\nfunc (p *producer) write(testContext context.Context, exchange, key string, payload []byte) error {\n\tmsg := amqp091.Publishing{\n\t\tDeliveryMode: amqp091.Persistent,\n\t\tTimestamp:    time.Now(),\n\t\tContentType:  \"text/plain\",\n\t\tBody:         payload,\n\t}\n\n\tctx, cancel := context.WithTimeout(testContext, 3*time.Second)\n\tdefer cancel()\n\n\treturn p.channel.PublishWithContext(ctx, exchange, key, true, false, msg)\n}\n"
  },
  {
    "path": "plugins/inputs/amqp_consumer/sample.conf",
    "content": "# AMQP consumer plugin\n[[inputs.amqp_consumer]]\n  ## Brokers to consume from.  If multiple brokers are specified a random broker\n  ## will be selected anytime a connection is established.  This can be\n  ## helpful for load balancing when not using a dedicated load balancer.\n  brokers = [\"amqp://localhost:5672/influxdb\"]\n\n  ## Authentication credentials for the PLAIN auth_method.\n  # username = \"\"\n  # password = \"\"\n\n  ## Name of the exchange to declare.  If unset, no exchange will be declared.\n  exchange = \"telegraf\"\n\n  ## Exchange type; common types are \"direct\", \"fanout\", \"topic\", \"header\", \"x-consistent-hash\".\n  # exchange_type = \"topic\"\n\n  ## If true, exchange will be passively declared.\n  # exchange_passive = false\n\n  ## Exchange durability can be either \"transient\" or \"durable\".\n  # exchange_durability = \"durable\"\n\n  ## Additional exchange arguments.\n  # exchange_arguments = { }\n  # exchange_arguments = {\"hash_property\" = \"timestamp\"}\n\n  ## AMQP queue name.\n  queue = \"telegraf\"\n\n  ## AMQP queue durability can be \"transient\" or \"durable\".\n  queue_durability = \"durable\"\n\n  ## If true, queue will be passively declared.\n  # queue_passive = false\n\n  ## Additional arguments when consuming from Queue\n  # queue_consume_arguments = { }\n  # queue_consume_arguments = {\"x-stream-offset\" = \"first\"}\n\n  ## Additional queue arguments.\n  # queue_arguments = { }\n  # queue_arguments = {\"x-max-length\" = 100}\n\n  ## A binding between the exchange and queue using this binding key is\n  ## created.  If unset, no binding is created.\n  binding_key = \"#\"\n\n  ## Maximum number of messages server should give to the worker.\n  # prefetch_count = 50\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Timeout for establishing the connection to a broker\n  # timeout = \"30s\"\n\n  ## Auth method. PLAIN and EXTERNAL are supported\n  ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as\n  ## described here: https://www.rabbitmq.com/plugins.html\n  # auth_method = \"PLAIN\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Content encoding for message payloads, can be set to\n  ## \"gzip\", \"identity\" or \"auto\"\n  ## - Use \"gzip\" to decode gzip\n  ## - Use \"identity\" to apply no encoding\n  ## - Use \"auto\" determine the encoding using the ContentEncoding header\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded message.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  ## Without quotes and units, interpreted as size in bytes.\n  # max_decompression_size = \"500MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/apache/README.md",
    "content": "# Apache Input Plugin\n\nThis plugin collects performance information from [Apache HTTP Servers][apache]\nusing the [`mod_status` module][mod_status_module]. Typically, this module is\nconfigured to expose a page at the `/server-status?auto` endpoint the server.\n\nThe [ExtendedStatus option][extended_status] must be enabled in order to collect\nall available fields. For information about configuration of your server check\nthe [module documentation][mod_status_module].\n\n⭐ Telegraf v1.8.0\n🏷️ server, web\n💻 all\n\n[apache]: https://httpd.apache.org\n[extended_status]: https://httpd.apache.org/docs/current/mod/core.html#extendedstatus\n[mod_status_module]: https://httpd.apache.org/docs/current/mod/mod_status.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Apache status information (mod_status)\n[[inputs.apache]]\n  ## An array of URLs to gather from, must be directed at the machine\n  ## readable version of the mod_status page including the auto query string.\n  ## Default is \"http://localhost/server-status?auto\".\n  urls = [\"http://localhost/server-status?auto\"]\n\n  ## Credentials for basic HTTP authentication.\n  # username = \"myuser\"\n  # password = \"mypassword\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- apache\n  - BusyWorkers (float)\n  - BytesPerReq (float)\n  - BytesPerSec (float)\n  - ConnsAsyncClosing (float)\n  - ConnsAsyncKeepAlive (float)\n  - ConnsAsyncWriting (float)\n  - ConnsTotal (float)\n  - CPUChildrenSystem (float)\n  - CPUChildrenUser (float)\n  - CPULoad (float)\n  - CPUSystem (float)\n  - CPUUser (float)\n  - IdleWorkers (float)\n  - Load1 (float)\n  - Load5 (float)\n  - Load15 (float)\n  - ParentServerConfigGeneration (float)\n  - ParentServerMPMGeneration (float)\n  - ReqPerSec (float)\n  - ServerUptimeSeconds (float)\n  - TotalAccesses (float)\n  - TotalkBytes (float)\n  - Uptime (float)\n\nThe following fields are collected from the `Scoreboard`, and represent the\nnumber of requests in the given state:\n\n- apache\n  - scboard_closing (float)\n  - scboard_dnslookup (float)\n  - scboard_finishing (float)\n  - scboard_idle_cleanup (float)\n  - scboard_keepalive (float)\n  - scboard_logging (float)\n  - scboard_open (float)\n  - scboard_reading (float)\n  - scboard_sending (float)\n  - scboard_starting (float)\n  - scboard_waiting (float)\n\n## Tags\n\n- All measurements have the following tags:\n  - port\n  - server\n\n## Example Output\n\n```text\napache,port=80,server=debian-stretch-apache BusyWorkers=1,BytesPerReq=0,BytesPerSec=0,CPUChildrenSystem=0,CPUChildrenUser=0,CPULoad=0.00995025,CPUSystem=0.01,CPUUser=0.01,ConnsAsyncClosing=0,ConnsAsyncKeepAlive=0,ConnsAsyncWriting=0,ConnsTotal=0,IdleWorkers=49,Load1=0.01,Load15=0,Load5=0,ParentServerConfigGeneration=3,ParentServerMPMGeneration=2,ReqPerSec=0.00497512,ServerUptimeSeconds=201,TotalAccesses=1,TotalkBytes=0,Uptime=201,scboard_closing=0,scboard_dnslookup=0,scboard_finishing=0,scboard_idle_cleanup=0,scboard_keepalive=0,scboard_logging=0,scboard_open=100,scboard_reading=0,scboard_sending=1,scboard_starting=0,scboard_waiting=49 1502489900000000000\n```\n"
  },
  {
    "path": "plugins/inputs/apache/apache.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage apache\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Apache struct {\n\tUrls            []string\n\tUsername        string\n\tPassword        string\n\tResponseTimeout config.Duration\n\ttls.ClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*Apache) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Apache) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tif len(n.Urls) == 0 {\n\t\tn.Urls = []string{\"http://localhost/server-status?auto\"}\n\t}\n\tif n.ResponseTimeout < config.Duration(time.Second) {\n\t\tn.ResponseTimeout = config.Duration(time.Second * 5)\n\t}\n\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *Apache) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := n.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(n.ResponseTimeout),\n\t}\n\n\treturn client, nil\n}\n\nfunc (n *Apache) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\treq, err := http.NewRequest(\"GET\", addr.String(), nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error on new request to %q: %w\", addr.String(), err)\n\t}\n\n\tif len(n.Username) != 0 && len(n.Password) != 0 {\n\t\treq.SetBasicAuth(n.Username, n.Password)\n\t}\n\n\tresp, err := n.client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error on request to %q: %w\", addr.String(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\n\ttags := getTags(addr)\n\n\tsc := bufio.NewScanner(resp.Body)\n\tfields := make(map[string]interface{})\n\tfor sc.Scan() {\n\t\tline := sc.Text()\n\t\tif strings.Contains(line, \":\") {\n\t\t\tparts := strings.SplitN(line, \":\", 2)\n\t\t\tkey, part := strings.ReplaceAll(parts[0], \" \", \"\"), strings.TrimSpace(parts[1])\n\n\t\t\tswitch key {\n\t\t\tcase \"Scoreboard\":\n\t\t\t\tfor field, value := range gatherScores(part) {\n\t\t\t\t\tfields[field] = value\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tvalue, err := strconv.ParseFloat(part, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[key] = value\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"apache\", fields, tags)\n\n\treturn nil\n}\n\nfunc gatherScores(data string) map[string]interface{} {\n\tvar waiting, open = 0, 0\n\tvar s, r, w, k, d, c, l, g, i = 0, 0, 0, 0, 0, 0, 0, 0, 0\n\n\tfor _, str := range strings.Split(data, \"\") {\n\t\tswitch str {\n\t\tcase \"_\":\n\t\t\twaiting++\n\t\tcase \"S\":\n\t\t\ts++\n\t\tcase \"R\":\n\t\t\tr++\n\t\tcase \"W\":\n\t\t\tw++\n\t\tcase \"K\":\n\t\t\tk++\n\t\tcase \"D\":\n\t\t\td++\n\t\tcase \"C\":\n\t\t\tc++\n\t\tcase \"L\":\n\t\t\tl++\n\t\tcase \"G\":\n\t\t\tg++\n\t\tcase \"I\":\n\t\t\ti++\n\t\tcase \".\":\n\t\t\topen++\n\t\t}\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"scboard_waiting\":      float64(waiting),\n\t\t\"scboard_starting\":     float64(s),\n\t\t\"scboard_reading\":      float64(r),\n\t\t\"scboard_sending\":      float64(w),\n\t\t\"scboard_keepalive\":    float64(k),\n\t\t\"scboard_dnslookup\":    float64(d),\n\t\t\"scboard_closing\":      float64(c),\n\t\t\"scboard_logging\":      float64(l),\n\t\t\"scboard_finishing\":    float64(g),\n\t\t\"scboard_idle_cleanup\": float64(i),\n\t\t\"scboard_open\":         float64(open),\n\t}\n\treturn fields\n}\n\n// Get tag(s) for the apache plugin\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"server\": host, \"port\": port}\n}\n\nfunc init() {\n\tinputs.Add(\"apache\", func() telegraf.Input {\n\t\treturn &Apache{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/apache/apache_test.go",
    "content": "package apache\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n//nolint:lll // conditionally long lines allowed\nvar apacheStatus = `\nTotal Accesses: 129811861\nTotal kBytes: 5213701865\nCPULoad: 6.51929\nUptime: 941553\nReqPerSec: 137.87\nBytesPerSec: 5670240\nBytesPerReq: 41127.4\nBusyWorkers: 270\nIdleWorkers: 630\nConnsTotal: 1451\nConnsAsyncWriting: 32\nConnsAsyncKeepAlive: 945\nConnsAsyncClosing: 205\nScoreboard: WW_____W_RW_R_W__RRR____WR_W___WW________W_WW_W_____R__R_WR__WRWR_RRRW___R_RWW__WWWRW__R_RW___RR_RW_R__W__WR_WWW______WWR__R___R_WR_W___RW______RR________________W______R__RR______W________________R____R__________________________RW_W____R_____W_R_________________R____RR__W___R_R____RW______R____W______W_W_R_R______R__R_R__________R____W_______WW____W____RR__W_____W_R_______W__________W___W____________W_______WRR_R_W____W_____R____W_WW_R____RRW__W............................................................................................................................................................................................................................................................................................................WRRWR____WR__RR_R___RWR_________W_R____RWRRR____R_R__RW_R___WWW_RW__WR_RRR____W___R____WW_R__R___RR_W_W_RRRRWR__RRWR__RRW_W_RRRW_R_RR_W__RR_RWRR_R__R___RR_RR______R__RR____R_____W_R_R_R__R__R__________W____WW_R___R_R___R_________RR__RR____RWWWW___W_R________R_R____R_W___W___R___W_WRRWW_______R__W_RW_______R________RR__R________W_______________________W_W______________RW_________WR__R___R__R_______________WR_R_________W___RW_____R____________W____......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................\n`\n\nfunc TestHTTPApache(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := fmt.Fprintln(w, apacheStatus); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\ta := Apache{\n\t\t// Fetch it 2 times to catch possible data races.\n\t\tUrls: []string{ts.URL, ts.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"TotalAccesses\":        float64(1.29811861e+08),\n\t\t\"TotalkBytes\":          float64(5.213701865e+09),\n\t\t\"CPULoad\":              float64(6.51929),\n\t\t\"Uptime\":               float64(941553),\n\t\t\"ReqPerSec\":            float64(137.87),\n\t\t\"BytesPerSec\":          float64(5.67024e+06),\n\t\t\"BytesPerReq\":          float64(41127.4),\n\t\t\"BusyWorkers\":          float64(270),\n\t\t\"IdleWorkers\":          float64(630),\n\t\t\"ConnsTotal\":           float64(1451),\n\t\t\"ConnsAsyncWriting\":    float64(32),\n\t\t\"ConnsAsyncKeepAlive\":  float64(945),\n\t\t\"ConnsAsyncClosing\":    float64(205),\n\t\t\"scboard_waiting\":      float64(630),\n\t\t\"scboard_starting\":     float64(0),\n\t\t\"scboard_reading\":      float64(157),\n\t\t\"scboard_sending\":      float64(113),\n\t\t\"scboard_keepalive\":    float64(0),\n\t\t\"scboard_dnslookup\":    float64(0),\n\t\t\"scboard_closing\":      float64(0),\n\t\t\"scboard_logging\":      float64(0),\n\t\t\"scboard_finishing\":    float64(0),\n\t\t\"scboard_idle_cleanup\": float64(0),\n\t\t\"scboard_open\":         float64(2850),\n\t}\n\tacc.AssertContainsFields(t, \"apache\", fields)\n}\n"
  },
  {
    "path": "plugins/inputs/apache/sample.conf",
    "content": "# Read Apache status information (mod_status)\n[[inputs.apache]]\n  ## An array of URLs to gather from, must be directed at the machine\n  ## readable version of the mod_status page including the auto query string.\n  ## Default is \"http://localhost/server-status?auto\".\n  urls = [\"http://localhost/server-status?auto\"]\n\n  ## Credentials for basic HTTP authentication.\n  # username = \"myuser\"\n  # password = \"mypassword\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/apcupsd/README.md",
    "content": "# APC UPSD Input Plugin\n\nThis plugin gathers data from one or more [apcupsd daemon][apcupsd_daemon] over\nthe NIS network protocol. To query a server, the daemon must be running and be\naccessible.\n\n⭐ Telegraf v1.12.0\n🏷️ hardware, server\n💻 all\n\n[apcupsd_daemon]: https://sourceforge.net/projects/apcupsd/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Monitor APC UPSes connected to apcupsd\n[[inputs.apcupsd]]\n  # A list of running apcupsd server to connect to.\n  # If not provided will default to tcp://127.0.0.1:3551\n  servers = [\"tcp://127.0.0.1:3551\"]\n\n  ## Timeout for dialing server.\n  timeout = \"5s\"\n```\n\n## Metrics\n\n- apcupsd\n  - tags:\n    - serial\n    - ups_name\n    - status (string representing the set status_flags)\n    - model\n  - fields:\n    - status_flags ([status-bits][])\n    - input_voltage\n    - load_percent\n    - battery_charge_percent\n    - time_left_ns\n    - output_voltage\n    - internal_temp\n    - battery_voltage\n    - input_frequency\n    - time_on_battery_ns\n    - cumulative_time_on_battery_ns\n    - nominal_input_voltage\n    - nominal_battery_voltage\n    - nominal_power\n    - firmware\n    - battery_date\n    - last_transfer\n    - number_transfers\n\n## Example Output\n\n```text\napcupsd,serial=AS1231515,status=ONLINE,ups_name=name1 time_on_battery=0,load_percent=9.7,time_left_minutes=98,output_voltage=230.4,internal_temp=32.4,battery_voltage=27.4,input_frequency=50.2,input_voltage=230.4,battery_charge_percent=100,status_flags=8i 1490035922000000000\n```\n\n[status-bits]: http://www.apcupsd.org/manual/manual.html#status-bits\n"
  },
  {
    "path": "plugins/inputs/apcupsd/apcupsd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage apcupsd\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mdlayher/apcupsd\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultAddress = \"tcp://127.0.0.1:3551\"\n\nvar defaultTimeout = config.Duration(5 * time.Second)\n\ntype ApcUpsd struct {\n\tServers []string\n\tTimeout config.Duration\n}\n\nfunc (*ApcUpsd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *ApcUpsd) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\n\tfor _, server := range h.Servers {\n\t\terr := func(address string) error {\n\t\t\taddrBits, err := url.Parse(address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif addrBits.Scheme == \"\" {\n\t\t\t\taddrBits.Scheme = \"tcp\"\n\t\t\t}\n\n\t\t\tctx, cancel := context.WithTimeout(ctx, time.Duration(h.Timeout))\n\t\t\tdefer cancel()\n\n\t\t\tstatus, err := fetchStatus(ctx, addrBits)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttags := map[string]string{\n\t\t\t\t\"serial\":   status.SerialNumber,\n\t\t\t\t\"ups_name\": status.UPSName,\n\t\t\t\t\"status\":   status.Status,\n\t\t\t\t\"model\":    status.Model,\n\t\t\t}\n\n\t\t\tflags, err := strconv.ParseUint(strings.Fields(status.StatusFlags)[0], 0, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"status_flags\":                  flags,\n\t\t\t\t\"input_voltage\":                 status.LineVoltage,\n\t\t\t\t\"load_percent\":                  status.LoadPercent,\n\t\t\t\t\"battery_charge_percent\":        status.BatteryChargePercent,\n\t\t\t\t\"time_left_ns\":                  status.TimeLeft.Nanoseconds(),\n\t\t\t\t\"output_voltage\":                status.OutputVoltage,\n\t\t\t\t\"internal_temp\":                 status.InternalTemp,\n\t\t\t\t\"battery_voltage\":               status.BatteryVoltage,\n\t\t\t\t\"input_frequency\":               status.LineFrequency,\n\t\t\t\t\"time_on_battery_ns\":            status.TimeOnBattery.Nanoseconds(),\n\t\t\t\t\"cumulative_time_on_battery_ns\": status.CumulativeTimeOnBattery.Nanoseconds(),\n\t\t\t\t\"nominal_input_voltage\":         status.NominalInputVoltage,\n\t\t\t\t\"nominal_battery_voltage\":       status.NominalBatteryVoltage,\n\t\t\t\t\"nominal_power\":                 status.NominalPower,\n\t\t\t\t\"firmware\":                      status.Firmware,\n\t\t\t\t\"battery_date\":                  status.BatteryDate,\n\t\t\t\t\"last_transfer\":                 status.LastTransfer,\n\t\t\t\t\"number_transfers\":              status.NumberTransfers,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"apcupsd\", fields, tags)\n\t\t\treturn nil\n\t\t}(server)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fetchStatus(ctx context.Context, addr *url.URL) (*apcupsd.Status, error) {\n\tclient, err := apcupsd.DialContext(ctx, addr.Scheme, addr.Host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer client.Close()\n\n\treturn client.Status()\n}\n\nfunc init() {\n\tinputs.Add(\"apcupsd\", func() telegraf.Input {\n\t\treturn &ApcUpsd{\n\t\t\tServers: []string{defaultAddress},\n\t\t\tTimeout: defaultTimeout,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/apcupsd/apcupsd_test.go",
    "content": "package apcupsd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestApcupsdDocs(_ *testing.T) {\n\tapc := &ApcUpsd{}\n\tapc.SampleConfig()\n}\n\nfunc TestApcupsdInit(t *testing.T) {\n\tinput, ok := inputs.Inputs[\"apcupsd\"]\n\tif !ok {\n\t\tt.Fatal(\"Input not defined\")\n\t}\n\n\t_ = input().(*ApcUpsd)\n}\n\nfunc listen(ctx context.Context, t *testing.T, out [][]byte) (string, error) {\n\tlc := net.ListenConfig{}\n\tln, err := lc.Listen(ctx, \"tcp4\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tgo func() {\n\t\tdefer ln.Close()\n\n\t\tfor ctx.Err() == nil {\n\t\t\tfunc() {\n\t\t\t\tconn, err := ln.Accept()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdefer conn.Close()\n\n\t\t\t\tif err = conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tin := make([]byte, 128)\n\t\t\t\tn, err := conn.Read(in)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"Failed to read to connection: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tstatus := []byte{0, 6, 's', 't', 'a', 't', 'u', 's'}\n\t\t\t\twant, got := status, in[:n]\n\t\t\t\tif !bytes.Equal(want, got) {\n\t\t\t\t\tt.Errorf(\"expected %q, got %q\", want, got)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Run against test function and append EOF to end of output bytes\n\t\t\t\tout = append(out, []byte{0, 0})\n\n\t\t\t\tfor _, o := range out {\n\t\t\t\t\tif _, err := conn.Write(o); err != nil {\n\t\t\t\t\t\tt.Errorf(\"Failed to write to connection: %v\", err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}()\n\n\treturn ln.Addr().String(), nil\n}\n\nfunc TestConfig(t *testing.T) {\n\tapc := &ApcUpsd{Timeout: defaultTimeout}\n\n\tvar (\n\t\ttests = []struct {\n\t\t\tname    string\n\t\t\tservers []string\n\t\t\terr     bool\n\t\t}{\n\t\t\t{\n\t\t\t\tname:    \"test listen address no scheme\",\n\t\t\t\tservers: []string{\"127.0.0.1:1234\"},\n\t\t\t\terr:     true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:    \"test no port\",\n\t\t\t\tservers: []string{\"127.0.0.3\"},\n\t\t\t\terr:     true,\n\t\t\t},\n\t\t}\n\n\t\tacc testutil.Accumulator\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tapc.Servers = tt.servers\n\n\t\t\terr := apc.Gather(&acc)\n\t\t\tif tt.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestApcupsdGather(t *testing.T) {\n\tapc := &ApcUpsd{Timeout: defaultTimeout}\n\n\tvar (\n\t\ttests = []struct {\n\t\t\tname   string\n\t\t\terr    bool\n\t\t\ttags   map[string]string\n\t\t\tfields map[string]interface{}\n\t\t\tout    func() [][]byte\n\t\t}{\n\t\t\t{\n\t\t\t\tname: \"test listening server with output\",\n\t\t\t\terr:  false,\n\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\"serial\":   \"ABC123\",\n\t\t\t\t\t\"status\":   \"ONLINE\",\n\t\t\t\t\t\"ups_name\": \"BERTHA\",\n\t\t\t\t\t\"model\":    \"Model 12345\",\n\t\t\t\t},\n\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\"status_flags\":                  uint64(8),\n\t\t\t\t\t\"input_voltage\":                 float64(0),\n\t\t\t\t\t\"load_percent\":                  float64(13),\n\t\t\t\t\t\"battery_charge_percent\":        float64(0),\n\t\t\t\t\t\"time_left_ns\":                  int64(2790000000000),\n\t\t\t\t\t\"output_voltage\":                float64(0),\n\t\t\t\t\t\"internal_temp\":                 float64(0),\n\t\t\t\t\t\"battery_voltage\":               float64(0),\n\t\t\t\t\t\"input_frequency\":               float64(0),\n\t\t\t\t\t\"time_on_battery_ns\":            int64(0),\n\t\t\t\t\t\"cumulative_time_on_battery_ns\": int64(85000000000),\n\t\t\t\t\t\"nominal_input_voltage\":         float64(230),\n\t\t\t\t\t\"nominal_battery_voltage\":       float64(12),\n\t\t\t\t\t\"nominal_power\":                 865,\n\t\t\t\t\t\"firmware\":                      \"857.L3 .I USB FW:L3\",\n\t\t\t\t\t\"battery_date\":                  \"2016-09-06\",\n\t\t\t\t\t\"last_transfer\":                 \"Low line voltage\",\n\t\t\t\t\t\"number_transfers\":              1,\n\t\t\t\t},\n\t\t\t\tout: genOutput,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"test with bad output\",\n\t\t\t\terr:  true,\n\t\t\t\tout:  genBadOutput,\n\t\t\t},\n\t\t}\n\n\t\tacc testutil.Accumulator\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tctx, cancel := context.WithCancel(t.Context())\n\n\t\t\tlAddr, err := listen(ctx, t, tt.out())\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\tapc.Servers = []string{\"tcp://\" + lAddr}\n\n\t\t\terr = apc.Gather(&acc)\n\t\t\tif tt.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"apcupsd\", tt.fields, tt.tags)\n\t\t\t}\n\t\t\tcancel()\n\t\t})\n\t}\n}\n\n// The following functionality is straight from apcupsd tests.\n\n// kvBytes is a helper to generate length and key/value byte buffers.\nfunc kvBytes(kv string) (keyValLen, keyVal []byte) {\n\tlenb := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(lenb, uint16(len(kv)))\n\n\treturn lenb, []byte(kv)\n}\n\nfunc genOutput() [][]byte {\n\tkvs := []string{\n\t\t\"SERIALNO : ABC123\",\n\t\t\"STATUS   : ONLINE\",\n\t\t\"STATFLAG : 0x08 Status Flag\",\n\t\t\"UPSNAME  : BERTHA\",\n\t\t\"MODEL    : Model 12345\",\n\t\t\"DATE     : 2016-09-06 22:13:28 -0400\",\n\t\t\"HOSTNAME : example\",\n\t\t\"LOADPCT  : 13.0 Percent Load Capacity\",\n\t\t\"BATTDATE : 2016-09-06\",\n\t\t\"TIMELEFT : 46.5 Minutes\",\n\t\t\"TONBATT  : 0 seconds\",\n\t\t\"CUMONBATT: 85 seconds\",\n\t\t\"LASTXFER : Low line voltage\",\n\t\t\"NUMXFERS : 1\",\n\t\t\"SELFTEST : NO\",\n\t\t\"NOMINV   : 230 Volts\",\n\t\t\"NOMBATTV : 12.0 Volts\",\n\t\t\"NOMPOWER : 865 Watts\",\n\t\t\"FIRMWARE : 857.L3 .I USB FW:L3\",\n\t\t\"ALARMDEL : Low Battery\",\n\t}\n\n\tout := make([][]byte, 0, 2*len(kvs))\n\tfor _, kv := range kvs {\n\t\tlenb, kvb := kvBytes(kv)\n\t\tout = append(out, lenb, kvb)\n\t}\n\n\treturn out\n}\n\nfunc genBadOutput() [][]byte {\n\tkvs := []string{\n\t\t\"STATFLAG : 0x08Status Flag\",\n\t}\n\n\tout := make([][]byte, 0, 2*len(kvs))\n\tfor _, kv := range kvs {\n\t\tlenb, kvb := kvBytes(kv)\n\t\tout = append(out, lenb, kvb)\n\t}\n\n\treturn out\n}\n"
  },
  {
    "path": "plugins/inputs/apcupsd/sample.conf",
    "content": "# Monitor APC UPSes connected to apcupsd\n[[inputs.apcupsd]]\n  # A list of running apcupsd server to connect to.\n  # If not provided will default to tcp://127.0.0.1:3551\n  servers = [\"tcp://127.0.0.1:3551\"]\n\n  ## Timeout for dialing server.\n  timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/aurora/README.md",
    "content": "# Apache Aurora Input Plugin\n\nThis plugin gathers metrics from [Apache Aurora][aurora] schedulers. For\nmonitoring recommendations check the [Monitoring your Aurora cluster][monitoring]\narticle.\n\n⭐ Telegraf v1.7.0\n🏷️ applications, server\n💻 all\n\n[aurora]: https://aurora.apache.org\n[monitoring]: https://aurora.apache.org/documentation/latest/operations/monitoring\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather metrics from Apache Aurora schedulers\n[[inputs.aurora]]\n  ## Schedulers are the base addresses of your Aurora Schedulers\n  schedulers = [\"http://127.0.0.1:8081\"]\n\n  ## Set of role types to collect metrics from.\n  ##\n  ## The scheduler roles are checked each interval by contacting the\n  ## scheduler nodes; zookeeper is not contacted.\n  # roles = [\"leader\", \"follower\"]\n\n  ## Timeout is the max time for total network operations.\n  # timeout = \"5s\"\n\n  ## Username and password are sent using HTTP Basic Auth.\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- aurora\n  - tags:\n    - scheduler (URL of scheduler)\n    - role (leader or follower)\n  - fields:\n    - Numeric metrics are collected from the `/vars` endpoint; string fields\n      are not gathered.\n\n## Troubleshooting\n\nCheck the Scheduler role, the leader will return a 200 status:\n\n```shell\ncurl -v http://127.0.0.1:8081/leaderhealth\n```\n\nGet available metrics:\n\n```shell\ncurl http://127.0.0.1:8081/vars\n```\n\n## Example Output\n\nThe example output below has been trimmed.\n\n```text\naurora,role=leader,scheduler=http://debian-stretch-aurora-coordinator-3.virt:8081 CronBatchWorker_batch_locked_events=0i,CronBatchWorker_batch_locked_events_per_sec=0,CronBatchWorker_batch_locked_nanos_per_event=0,CronBatchWorker_batch_locked_nanos_total=0i,CronBatchWorker_batch_locked_nanos_total_per_sec=0,CronBatchWorker_batch_unlocked_events=0i,CronBatchWorker_batch_unlocked_events_per_sec=0,CronBatchWorker_batch_unlocked_nanos_per_event=0,CronBatchWorker_batch_unlocked_nanos_total=0i,CronBatchWorker_batch_unlocked_nanos_total_per_sec=0,CronBatchWorker_batches_processed=0i,CronBatchWorker_items_processed=0i,CronBatchWorker_last_processed_batch_size=0i,CronBatchWorker_queue_size=0i,TaskEventBatchWorker_batch_locked_events=0i,TaskEventBatchWorker_batch_locked_events_per_sec=0,TaskEventBatchWorker_batch_locked_nanos_per_event=0,TaskEventBatchWorker_batch_locked_nanos_total=0i,TaskEventBatchWorker_batch_locked_nanos_total_per_sec=0,TaskEventBatchWorker_batch_unlocked_events=0i,TaskEventBatchWorker_batch_unlocked_events_per_sec=0,TaskEventBatchWorker_batch_unlocked_nanos_per_event=0,TaskEventBatchWorker_batch_unlocked_nanos_total=0i,TaskEventBatchWorker_batch_unlocked_nanos_total_per_sec=0,TaskEventBatchWorker_batches_processed=0i,TaskEventBatchWorker_items_processed=0i,TaskEventBatchWorker_last_processed_batch_size=0i,TaskEventBatchWorker_queue_size=0i,TaskGroupBatchWorker_batch_locked_events=0i,TaskGroupBatchWorker_batch_locked_events_per_sec=0,TaskGroupBatchWorker_batch_locked_nanos_per_event=0,TaskGroupBatchWorker_batch_locked_nanos_total=0i,TaskGroupBatchWorker_batch_locked_nanos_total_per_sec=0,TaskGroupBatchWorker_batch_unlocked_events=0i,TaskGroupBatchWorker_batch_unlocked_events_per_sec=0,TaskGroupBatchWorker_batch_unlocked_nanos_per_event=0,TaskGroupBatchWorker_batch_unlocked_nanos_total=0i,TaskGroupBatchWorker_batch_unlocked_nanos_total_per_sec=0,TaskGroupBatchWorker_batches_processed=0i,TaskGroupBatchWorker_items_processed=0i,TaskGroupBatchWorker_last_processed_batch_size=0i,TaskGroupBatchWorker_queue_size=0i,assigner_launch_failures=0i,async_executor_uncaught_exceptions=0i,async_tasks_completed=1i,cron_job_collisions=0i,cron_job_concurrent_runs=0i,cron_job_launch_failures=0i,cron_job_misfires=0i,cron_job_parse_failures=0i,cron_job_triggers=0i,cron_jobs_loaded=1i,empty_slots_dedicated_large=0i,empty_slots_dedicated_medium=0i,empty_slots_dedicated_revocable_large=0i,empty_slots_dedicated_revocable_medium=0i,empty_slots_dedicated_revocable_small=0i,empty_slots_dedicated_revocable_xlarge=0i,empty_slots_dedicated_small=0i,empty_slots_dedicated_xlarge=0i,empty_slots_large=0i,empty_slots_medium=0i,empty_slots_revocable_large=0i,empty_slots_revocable_medium=0i,empty_slots_revocable_small=0i,empty_slots_revocable_xlarge=0i,empty_slots_small=0i,empty_slots_xlarge=0i,event_bus_dead_events=0i,event_bus_exceptions=1i,framework_registered=1i,globally_banned_offers_size=0i,http_200_responses_events=55i,http_200_responses_events_per_sec=0,http_200_responses_nanos_per_event=0,http_200_responses_nanos_total=310416694i,http_200_responses_nanos_total_per_sec=0,job_update_delete_errors=0i,job_update_recovery_errors=0i,job_update_state_change_errors=0i,job_update_store_delete_all_events=1i,job_update_store_delete_all_events_per_sec=0,job_update_store_delete_all_nanos_per_event=0,job_update_store_delete_all_nanos_total=1227254i,job_update_store_delete_all_nanos_total_per_sec=0,job_update_store_fetch_details_query_events=74i,job_update_store_fetch_details_query_events_per_sec=0,job_update_store_fetch_details_query_nanos_per_event=0,job_update_store_fetch_details_query_nanos_total=24643149i,job_update_store_fetch_details_query_nanos_total_per_sec=0,job_update_store_prune_history_events=59i,job_update_store_prune_history_events_per_sec=0,job_update_store_prune_history_nanos_per_event=0,job_update_store_prune_history_nanos_total=262868218i,job_update_store_prune_history_nanos_total_per_sec=0,job_updates_pruned=0i,jvm_available_processors=2i,jvm_class_loaded_count=6707i,jvm_class_total_loaded_count=6732i,jvm_class_unloaded_count=25i,jvm_gc_PS_MarkSweep_collection_count=2i,jvm_gc_PS_MarkSweep_collection_time_ms=223i,jvm_gc_PS_Scavenge_collection_count=27i,jvm_gc_PS_Scavenge_collection_time_ms=1691i,jvm_gc_collection_count=29i,jvm_gc_collection_time_ms=1914i,jvm_memory_free_mb=65i,jvm_memory_heap_mb_committed=157i,jvm_memory_heap_mb_max=446i,jvm_memory_heap_mb_used=91i,jvm_memory_max_mb=446i,jvm_memory_mb_total=157i,jvm_memory_non_heap_mb_committed=50i,jvm_memory_non_heap_mb_max=0i,jvm_memory_non_heap_mb_used=49i,jvm_threads_active=47i,jvm_threads_daemon=28i,jvm_threads_peak=48i,jvm_threads_started=62i,jvm_time_ms=1526530686927i,jvm_uptime_secs=79947i,log_entry_serialize_events=16i,log_entry_serialize_events_per_sec=0,log_entry_serialize_nanos_per_event=0,log_entry_serialize_nanos_total=4815321i,log_entry_serialize_nanos_total_per_sec=0,log_manager_append_events=16i,log_manager_append_events_per_sec=0,log_manager_append_nanos_per_event=0,log_manager_append_nanos_total=506453428i,log_manager_append_nanos_total_per_sec=0,log_manager_deflate_events=14i,log_manager_deflate_events_per_sec=0,log_manager_deflate_nanos_per_event=0,log_manager_deflate_nanos_total=21010565i,log_manager_deflate_nanos_total_per_sec=0 1526530687000000000\n```\n"
  },
  {
    "path": "plugins/inputs/aurora/aurora.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage aurora\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype roleType int\n\nconst (\n\tunknown roleType = iota\n\tleader\n\tfollower\n)\n\nfunc (r roleType) String() string {\n\tswitch r {\n\tcase leader:\n\t\treturn \"leader\"\n\tcase follower:\n\t\treturn \"follower\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\nvar (\n\tdefaultTimeout = 5 * time.Second\n\tdefaultRoles   = []string{\"leader\", \"follower\"}\n)\n\ntype vars map[string]interface{}\n\ntype Aurora struct {\n\tSchedulers []string        `toml:\"schedulers\"`\n\tRoles      []string        `toml:\"roles\"`\n\tTimeout    config.Duration `toml:\"timeout\"`\n\tUsername   string          `toml:\"username\"`\n\tPassword   string          `toml:\"password\"`\n\ttls.ClientConfig\n\n\tclient *http.Client\n\turls   []*url.URL\n}\n\nfunc (*Aurora) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *Aurora) Gather(acc telegraf.Accumulator) error {\n\tif a.client == nil {\n\t\terr := a.initialize()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(a.Timeout))\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\tfor _, u := range a.urls {\n\t\twg.Add(1)\n\t\tgo func(u *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\trole, err := a.gatherRole(ctx, u)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", u, err))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !a.roleEnabled(role) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terr = a.gatherScheduler(ctx, u, role, acc)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", u, err))\n\t\t\t}\n\t\t}(u)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (a *Aurora) initialize() error {\n\ttlsCfg, err := a.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tProxy:           http.ProxyFromEnvironment,\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t}\n\n\turls := make([]*url.URL, 0, len(a.Schedulers))\n\tfor _, s := range a.Schedulers {\n\t\tloc, err := url.Parse(s)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\turls = append(urls, loc)\n\t}\n\n\tif a.Timeout < config.Duration(time.Second) {\n\t\ta.Timeout = config.Duration(defaultTimeout)\n\t}\n\n\tif len(a.Roles) == 0 {\n\t\ta.Roles = defaultRoles\n\t}\n\n\ta.client = client\n\ta.urls = urls\n\treturn nil\n}\n\nfunc (a *Aurora) roleEnabled(role roleType) bool {\n\tif len(a.Roles) == 0 {\n\t\treturn true\n\t}\n\n\tfor _, v := range a.Roles {\n\t\tif role.String() == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Aurora) gatherRole(ctx context.Context, origin *url.URL) (roleType, error) {\n\tloc := *origin\n\tloc.Path = \"leaderhealth\"\n\treq, err := http.NewRequest(\"GET\", loc.String(), nil)\n\tif err != nil {\n\t\treturn unknown, err\n\t}\n\n\tif a.Username != \"\" || a.Password != \"\" {\n\t\treq.SetBasicAuth(a.Username, a.Password)\n\t}\n\treq.Header.Add(\"Accept\", \"text/plain\")\n\n\tresp, err := a.client.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\treturn unknown, err\n\t}\n\tif err := resp.Body.Close(); err != nil {\n\t\treturn unknown, fmt.Errorf(\"closing body failed: %w\", err)\n\t}\n\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\t\treturn leader, nil\n\tcase http.StatusBadGateway:\n\t\tfallthrough\n\tcase http.StatusServiceUnavailable:\n\t\treturn follower, nil\n\tdefault:\n\t\treturn unknown, fmt.Errorf(\"%v\", resp.Status)\n\t}\n}\n\nfunc (a *Aurora) gatherScheduler(\n\tctx context.Context, origin *url.URL, role roleType, acc telegraf.Accumulator,\n) error {\n\tloc := *origin\n\tloc.Path = \"vars.json\"\n\treq, err := http.NewRequest(\"GET\", loc.String(), nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif a.Username != \"\" || a.Password != \"\" {\n\t\treq.SetBasicAuth(a.Username, a.Password)\n\t}\n\treq.Header.Add(\"Accept\", \"application/json\")\n\n\tresp, err := a.client.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%v\", resp.Status)\n\t}\n\n\tvar metrics vars\n\tdecoder := json.NewDecoder(resp.Body)\n\tdecoder.UseNumber()\n\terr = decoder.Decode(&metrics)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"decoding response: %w\", err)\n\t}\n\n\tvar fields = make(map[string]interface{}, len(metrics))\n\tfor k, v := range metrics {\n\t\tswitch v := v.(type) {\n\t\tcase json.Number:\n\t\t\t// Aurora encodes numbers as you would specify them as a literal,\n\t\t\t// use this to determine if a value is a float or int.\n\t\t\tif strings.ContainsAny(v.String(), \".eE\") {\n\t\t\t\tfv, err := v.Float64()\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[k] = fv\n\t\t\t} else {\n\t\t\t\tfi, err := v.Int64()\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[k] = fi\n\t\t\t}\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n\n\tacc.AddFields(\"aurora\",\n\t\tfields,\n\t\tmap[string]string{\n\t\t\t\"scheduler\": origin.String(),\n\t\t\t\"role\":      role.String(),\n\t\t},\n\t)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"aurora\", func() telegraf.Input {\n\t\treturn &Aurora{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/aurora/aurora_test.go",
    "content": "package aurora\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype (\n\ttestHandlerFunc func(t *testing.T, w http.ResponseWriter, r *http.Request)\n\tcheckFunc       func(t *testing.T, err error, acc *testutil.Accumulator)\n)\n\nfunc TestAurora(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tu, err := url.Parse(\"http://\" + ts.Listener.Addr().String())\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname         string\n\t\tplugin       *Aurora\n\t\tschedulers   []string\n\t\troles        []string\n\t\tleaderhealth testHandlerFunc\n\t\tvarsjson     testHandlerFunc\n\t\tcheck        checkFunc\n\t}{\n\t\t{\n\t\t\tname: \"minimal\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tbody := `{\n\t\t\t\t\t\"variable_scrape_events\": 2958,\n\t\t\t\t\t\"variable_scrape_events_per_sec\": 1.0,\n\t\t\t\t\t\"variable_scrape_micros_per_event\": 1484.0,\n\t\t\t\t\t\"variable_scrape_micros_total\": 4401084,\n\t\t\t\t\t\"variable_scrape_micros_total_per_sec\": 1485.0\n\t\t\t\t}`\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, acc.Metrics, 1)\n\t\t\t\tacc.AssertContainsTaggedFields(t,\n\t\t\t\t\t\"aurora\",\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"variable_scrape_events\":               int64(2958),\n\t\t\t\t\t\t\"variable_scrape_events_per_sec\":       1.0,\n\t\t\t\t\t\t\"variable_scrape_micros_per_event\":     1484.0,\n\t\t\t\t\t\t\"variable_scrape_micros_total\":         int64(4401084),\n\t\t\t\t\t\t\"variable_scrape_micros_total_per_sec\": 1485.0,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"scheduler\": u.String(),\n\t\t\t\t\t\t\"role\":      \"leader\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"disabled role\",\n\t\t\troles: []string{\"leader\"},\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no metrics available\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(\"{}\"))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"string metrics skipped\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tbody := `{\n\t\t\t\t\t\"foo\": \"bar\"\n\t\t\t\t}`\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"float64 unparsable\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t// too large\n\t\t\t\tbody := `{\n\t\t\t\t\t\"foo\": 1e309\n\t\t\t\t}`\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Error(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"int64 unparsable\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t// too large\n\t\t\t\tbody := `{\n\t\t\t\t\t\"foo\": 9223372036854775808\n\t\t\t\t}`\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Error(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bad json\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tbody := `{]`\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Error(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"wrong status code\",\n\t\t\tleaderhealth: func(_ *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t\tvarsjson: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tbody := `{\n\t\t\t\t\t\"value\": 42\n\t\t\t\t}`\n\t\t\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t\t\t_, err := w.Write([]byte(body))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, err error, acc *testutil.Accumulator) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Error(t, acc.FirstError())\n\t\t\t\trequire.Empty(t, acc.Metrics)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/leaderhealth\":\n\t\t\t\t\ttt.leaderhealth(t, w, r)\n\t\t\t\tcase \"/vars.json\":\n\t\t\t\t\ttt.varsjson(t, w, r)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := &Aurora{}\n\t\t\tplugin.Schedulers = []string{u.String()}\n\t\t\tplugin.Roles = tt.roles\n\t\t\terr := plugin.Gather(&acc)\n\t\t\ttt.check(t, err, &acc)\n\t\t})\n\t}\n}\n\nfunc TestBasicAuth(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tu, err := url.Parse(\"http://\" + ts.Listener.Addr().String())\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname     string\n\t\tusername string\n\t\tpassword string\n\t}{\n\t\t{\n\t\t\tname: \"no auth\",\n\t\t},\n\t\t{\n\t\t\tname:     \"basic auth\",\n\t\t\tusername: \"username\",\n\t\t\tpassword: \"pa$$word\",\n\t\t},\n\t\t{\n\t\t\tname:     \"username only\",\n\t\t\tusername: \"username\",\n\t\t},\n\t\t{\n\t\t\tname:     \"password only\",\n\t\t\tpassword: \"pa$$word\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tusername, password, _ := r.BasicAuth()\n\t\t\t\tif username != tt.username {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", tt.username, username)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif password != tt.password {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", tt.password, password)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := w.Write([]byte(\"{}\")); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := &Aurora{}\n\t\t\tplugin.Schedulers = []string{u.String()}\n\t\t\tplugin.Username = tt.username\n\t\t\tplugin.Password = tt.password\n\t\t\terr := plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/aurora/sample.conf",
    "content": "# Gather metrics from Apache Aurora schedulers\n[[inputs.aurora]]\n  ## Schedulers are the base addresses of your Aurora Schedulers\n  schedulers = [\"http://127.0.0.1:8081\"]\n\n  ## Set of role types to collect metrics from.\n  ##\n  ## The scheduler roles are checked each interval by contacting the\n  ## scheduler nodes; zookeeper is not contacted.\n  # roles = [\"leader\", \"follower\"]\n\n  ## Timeout is the max time for total network operations.\n  # timeout = \"5s\"\n\n  ## Username and password are sent using HTTP Basic Auth.\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/README.md",
    "content": "# Azure Monitor Input Plugin\n\nThis plugin gathers metrics of Azure resources using the\n[Azure Monitor][azure_monitor] API. The plugin requires a `client_id`,\n`client_secret` and `tenant_id` for authentication via access token. The\n`subscription_id` is required for accessing Azure resources.\n\nCheck the [supported metrics page][supported_metrics] for available resource\ntypes and their metrics.\n\n> [!IMPORTANT]\n> The Azure API has a read limit of 12,000 requests per hour. Please make sure\n> you don't exceed this limit with the total number of metrics you are in the\n> configured interval.\n\n⭐ Telegraf v1.25.0\n🏷️ cloud\n💻 all\n\n[azure_monitor]: https://docs.microsoft.com/en-us/azure/azure-monitor\n[supported_metrics]: https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/metrics-supported\n\n## Property Locations\n\nThe `subscription_id` can be found under `Overview > Essentials` in the Azure\nportal for your application or service.\n\nThe `client_id` and `client_secret` can be obtained by registering an\napplication under Azure Active Directory.\n\nThe `tenant_id` can be found under `Azure Active Directory > Properties`.\n\nThe resource target `resource_id` can be found under\n`Overview > Essentials > JSON View` in the Azure portal for your\napplication or service.\n\nThe `cloud_option` defines the optional value for the API endpoints in case you\nare using the solution to get the metrics from the Azure Sovereign Cloud\nshipment e.g. AzureChina, AzureGovernment or AzurePublic.\nThe default value is AzurePublic\n\n## Usage\n\nUse `resource_targets` to collect metrics from specific resources using\nresource id.\n\nUse `resource_group_targets` to collect metrics from resources under the\nresource group with resource type.\n\nUse `subscription_targets` to collect metrics from resources under the\nsubscription with resource type.\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather Azure resources metrics from Azure Monitor API\n[[inputs.azure_monitor]]\n  # can be found under Overview->Essentials in the Azure portal for your application/service\n  subscription_id = \"<<SUBSCRIPTION_ID>>\"\n  # can be obtained by registering an application under Azure Active Directory\n  client_id = \"<<CLIENT_ID>>\"\n  # can be obtained by registering an application under Azure Active Directory.\n  # If not specified Default Azure Credentials chain will be attempted:\n  # - Environment credentials (AZURE_*)\n  # - Workload Identity in Kubernetes cluster\n  # - Managed Identity\n  # - Azure CLI auth\n  # - Developer Azure CLI auth\n  client_secret = \"<<CLIENT_SECRET>>\"\n  # can be found under Azure Active Directory->Properties\n  tenant_id = \"<<TENANT_ID>>\"\n  # Define the optional Azure cloud option e.g. AzureChina, AzureGovernment or AzurePublic. The default is AzurePublic.\n  # cloud_option = \"AzurePublic\"\n\n  # resource target #1 to collect metrics from\n  [[inputs.azure_monitor.resource_target]]\n    # can be found under Overview->Essentials->JSON View in the Azure portal for your application/service\n    # must start with 'resourceGroups/...' ('/subscriptions/xxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxxxx'\n    # must be removed from the beginning of Resource ID property value)\n    resource_id = \"<<RESOURCE_ID>>\"\n    # the metric names to collect\n    # leave the array empty to use all metrics available to this resource\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    # metrics aggregation type value to collect\n    # can be 'Total', 'Count', 'Average', 'Minimum', 'Maximum'\n    # leave the array empty to collect all aggregation types values for each metric\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource target #2 to collect metrics from\n  [[inputs.azure_monitor.resource_target]]\n    resource_id = \"<<RESOURCE_ID>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource group target #1 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.resource_group_target]]\n    # the resource group name\n    resource_group = \"<<RESOURCE_GROUP_NAME>>\"\n\n    # defines the resources to collect metrics from\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      # the resource type\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n    # defines the resources to collect metrics from\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource group target #2 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.resource_group_target]]\n    resource_group = \"<<RESOURCE_GROUP_NAME>>\"\n\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # subscription target #1 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.subscription_target]]\n    resource_type = \"<<RESOURCE_TYPE>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # subscription target #2 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.subscription_target]]\n    resource_type = \"<<RESOURCE_TYPE>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n```\n\n## Metrics\n\n* azure_monitor_<<RESOURCE_NAMESPACE>>_<<METRIC_NAME>>\n  * fields:\n    * total (float64)\n    * count (float64)\n    * average (float64)\n    * minimum (float64)\n    * maximum (float64)\n  * tags:\n    * namespace\n    * resource_group\n    * resource_name\n    * subscription_id\n    * resource_region\n    * unit\n\n## Example Output\n\n```text\nazure_monitor_microsoft_storage_storageaccounts_used_capacity,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=9065573,maximum=9065573,minimum=9065573,timeStamp=\"2021-11-08T09:52:00Z\",total=9065573 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_transactions,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Count average=1,count=6,maximum=1,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=6 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_ingress,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=5822.333333333333,count=6,maximum=5833,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=34934 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_egress,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=840.1666666666666,count=6,maximum=841,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=5041 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_success_server_latency,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=MilliSeconds average=12.833333333333334,count=6,maximum=30,minimum=8,timeStamp=\"2021-11-08T09:52:00Z\",total=77 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_success_e2e_latency,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=MilliSeconds average=12.833333333333334,count=6,maximum=30,minimum=8,timeStamp=\"2021-11-08T09:52:00Z\",total=77 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_availability,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Percent average=100,count=6,maximum=100,minimum=100,timeStamp=\"2021-11-08T09:52:00Z\",total=600 1636368744000000000\nazure_monitor_microsoft_storage_storageaccounts_used_capacity,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=9065573,maximum=9065573,minimum=9065573,timeStamp=\"2021-11-08T09:52:00Z\",total=9065573 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_transactions,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Count average=1,count=6,maximum=1,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=6 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_ingress,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=5822.333333333333,count=6,maximum=5833,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=34934 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_egress,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Bytes average=840.1666666666666,count=6,maximum=841,minimum=0,timeStamp=\"2021-11-08T09:52:00Z\",total=5041 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_success_server_latency,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=MilliSeconds average=12.833333333333334,count=6,maximum=30,minimum=8,timeStamp=\"2021-11-08T09:52:00Z\",total=77 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_success_e2e_latency,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=MilliSeconds average=12.833333333333334,count=6,maximum=30,minimum=8,timeStamp=\"2021-11-08T09:52:00Z\",total=77 1636368745000000000\nazure_monitor_microsoft_storage_storageaccounts_availability,host=Azure-MBP,namespace=Microsoft.Storage/storageAccounts,resource_group=azure-rg,resource_name=azuresa,resource_region=eastus,subscription_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,unit=Percent average=100,count=6,maximum=100,minimum=100,timeStamp=\"2021-11-08T09:52:00Z\",total=600 1636368745000000000\n```\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/azure_monitor.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage azure_monitor\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azidentity\"\n\treceiver \"github.com/logzio/azure-monitor-metrics-receiver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype AzureMonitor struct {\n\tSubscriptionID       string                 `toml:\"subscription_id\"`\n\tClientID             string                 `toml:\"client_id\"`\n\tClientSecret         string                 `toml:\"client_secret\"`\n\tTenantID             string                 `toml:\"tenant_id\"`\n\tCloudOption          string                 `toml:\"cloud_option,omitempty\"`\n\tResourceTargets      []*resourceTarget      `toml:\"resource_target\"`\n\tResourceGroupTargets []*resourceGroupTarget `toml:\"resource_group_target\"`\n\tSubscriptionTargets  []*resource            `toml:\"subscription_target\"`\n\tLog                  telegraf.Logger        `toml:\"-\"`\n\n\treceiver     *receiver.AzureMonitorMetricsReceiver\n\tazureManager azureClientsCreator\n\tazureClients *receiver.AzureClients\n}\n\ntype resourceTarget struct {\n\tResourceID   string   `toml:\"resource_id\"`\n\tMetrics      []string `toml:\"metrics\"`\n\tAggregations []string `toml:\"aggregations\"`\n}\n\ntype resourceGroupTarget struct {\n\tResourceGroup string      `toml:\"resource_group\"`\n\tResources     []*resource `toml:\"resource\"`\n}\n\ntype resource struct {\n\tResourceType string   `toml:\"resource_type\"`\n\tMetrics      []string `toml:\"metrics\"`\n\tAggregations []string `toml:\"aggregations\"`\n}\n\ntype azureClientsManager struct{}\n\ntype azureClientsCreator interface {\n\tcreateAzureClients(subscriptionID string, clientID string, clientSecret string, tenantID string,\n\t\tclientOptions azcore.ClientOptions) (*receiver.AzureClients, error)\n}\n\n//go:embed sample.conf\nvar sampleConfig string\n\nfunc (*AzureMonitor) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (am *AzureMonitor) Init() error {\n\tvar clientOptions azcore.ClientOptions\n\tswitch am.CloudOption {\n\tcase \"AzureChina\":\n\t\tclientOptions = azcore.ClientOptions{Cloud: cloud.AzureChina}\n\tcase \"AzureGovernment\":\n\t\tclientOptions = azcore.ClientOptions{Cloud: cloud.AzureGovernment}\n\tcase \"\", \"AzurePublic\":\n\t\tclientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown cloud option: %s\", am.CloudOption)\n\t}\n\n\tvar err error\n\tam.azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = am.setReceiver(); err != nil {\n\t\treturn fmt.Errorf(\"error setting Azure Monitor receiver: %w\", err)\n\t}\n\n\tif err = am.receiver.CreateResourceTargetsFromResourceGroupTargets(); err != nil {\n\t\treturn fmt.Errorf(\"error creating resource targets from resource group targets: %w\", err)\n\t}\n\n\tif err = am.receiver.CreateResourceTargetsFromSubscriptionTargets(); err != nil {\n\t\treturn fmt.Errorf(\"error creating resource targets from subscription targets: %w\", err)\n\t}\n\n\tif err = am.receiver.CheckResourceTargetsMetricsValidation(); err != nil {\n\t\treturn fmt.Errorf(\"error checking resource targets metrics validation: %w\", err)\n\t}\n\n\tif err = am.receiver.SetResourceTargetsMetrics(); err != nil {\n\t\treturn fmt.Errorf(\"error setting resource targets metrics: %w\", err)\n\t}\n\n\tif err = am.receiver.SplitResourceTargetsMetricsByMinTimeGrain(); err != nil {\n\t\treturn fmt.Errorf(\"error splitting resource targets metrics by min time grain: %w\", err)\n\t}\n\n\tam.receiver.SplitResourceTargetsWithMoreThanMaxMetrics()\n\tam.receiver.SetResourceTargetsAggregations()\n\n\tam.Log.Debug(\"Total resource targets: \", len(am.receiver.Targets.ResourceTargets))\n\n\treturn nil\n}\n\nfunc (am *AzureMonitor) Gather(acc telegraf.Accumulator) error {\n\tvar waitGroup sync.WaitGroup\n\n\tfor _, target := range am.receiver.Targets.ResourceTargets {\n\t\tam.Log.Debug(\"Collecting metrics for resource target \", target.ResourceID)\n\t\twaitGroup.Add(1)\n\n\t\tgo func(target *receiver.ResourceTarget) {\n\t\t\tdefer waitGroup.Done()\n\n\t\t\tcollectedMetrics, notCollectedMetrics, err := am.receiver.CollectResourceTargetMetrics(target)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\n\t\t\tfor _, collectedMetric := range collectedMetrics {\n\t\t\t\tacc.AddFields(collectedMetric.Name, collectedMetric.Fields, collectedMetric.Tags)\n\t\t\t}\n\n\t\t\tfor _, notCollectedMetric := range notCollectedMetrics {\n\t\t\t\tam.Log.Info(\"Did not get any metric value from Azure Monitor API for the metric ID \", notCollectedMetric)\n\t\t\t}\n\t\t}(target)\n\t}\n\n\twaitGroup.Wait()\n\treturn nil\n}\n\nfunc (am *AzureMonitor) setReceiver() error {\n\tresourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))\n\tresourceGroupTargets := make([]*receiver.ResourceGroupTarget, 0, len(am.ResourceGroupTargets))\n\tsubscriptionTargets := make([]*receiver.Resource, 0, len(am.SubscriptionTargets))\n\n\tfor _, target := range am.ResourceTargets {\n\t\tresourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))\n\t}\n\n\tfor _, target := range am.ResourceGroupTargets {\n\t\tresources := make([]*receiver.Resource, 0, len(target.Resources))\n\t\tfor _, resource := range target.Resources {\n\t\t\tresources = append(resources, receiver.NewResource(resource.ResourceType, resource.Metrics, resource.Aggregations))\n\t\t}\n\n\t\tresourceGroupTargets = append(resourceGroupTargets, receiver.NewResourceGroupTarget(target.ResourceGroup, resources))\n\t}\n\n\tfor _, target := range am.SubscriptionTargets {\n\t\tsubscriptionTargets = append(subscriptionTargets, receiver.NewResource(target.ResourceType, target.Metrics, target.Aggregations))\n\t}\n\n\ttargets := receiver.NewTargets(resourceTargets, resourceGroupTargets, subscriptionTargets)\n\tvar err error\n\tam.receiver, err = receiver.NewAzureMonitorMetricsReceiver(am.SubscriptionID, targets, am.azureClients)\n\treturn err\n}\n\nfunc (*azureClientsManager) createAzureClients(\n\tsubscriptionID, clientID, clientSecret, tenantID string,\n\tclientOptions azcore.ClientOptions,\n) (*receiver.AzureClients, error) {\n\tif clientSecret != \"\" {\n\t\treturn receiver.CreateAzureClients(subscriptionID, clientID, clientSecret, tenantID, receiver.WithAzureClientOptions(&clientOptions))\n\t}\n\n\ttoken, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{TenantID: tenantID,\n\t\tClientOptions: clientOptions})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating Azure token: %w\", err)\n\t}\n\treturn receiver.CreateAzureClientsWithCreds(subscriptionID, token, receiver.WithAzureClientOptions(&clientOptions))\n}\n\nfunc init() {\n\tinputs.Add(\"azure_monitor\", func() telegraf.Input {\n\t\treturn &AzureMonitor{\n\t\t\tazureManager: &azureClientsManager{},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/azure_monitor_test.go",
    "content": "package azure_monitor\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources\"\n\t\"github.com/influxdata/toml\"\n\treceiver \"github.com/logzio/azure-monitor-metrics-receiver\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockAzureClientsManager struct{}\n\ntype mockAzureResourcesClient struct{}\n\ntype mockAzureMetricDefinitionsClient struct{}\n\ntype mockAzureMetricsClient struct{}\n\nfunc (*mockAzureClientsManager) createAzureClients(_, _, _, _ string, _ azcore.ClientOptions) (*receiver.AzureClients, error) {\n\treturn &receiver.AzureClients{\n\t\tCtx:                     context.Background(),\n\t\tResourcesClient:         &mockAzureResourcesClient{},\n\t\tMetricDefinitionsClient: &mockAzureMetricDefinitionsClient{},\n\t\tMetricsClient:           &mockAzureMetricsClient{},\n\t}, nil\n}\n\nfunc (*mockAzureResourcesClient) List(_ context.Context, _ *armresources.ClientListOptions) ([]*armresources.ClientListResponse, error) {\n\tfile, err := os.ReadFile(\"testdata/json/azure_resources_response.json\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading file: %w\", err)\n\t}\n\n\tvar genericResourcesExpanded []*armresources.GenericResourceExpanded\n\tif err := json.Unmarshal(file, &genericResourcesExpanded); err != nil {\n\t\treturn nil, err\n\t}\n\n\tresponse := &armresources.ClientListResponse{\n\t\tResourceListResult: armresources.ResourceListResult{\n\t\t\tValue: genericResourcesExpanded,\n\t\t},\n\t}\n\n\treturn []*armresources.ClientListResponse{response}, nil\n}\n\nfunc (*mockAzureResourcesClient) ListByResourceGroup(\n\t_ context.Context,\n\tresourceGroup string,\n\t_ *armresources.ClientListByResourceGroupOptions) ([]*armresources.ClientListByResourceGroupResponse, error) {\n\tvar responses []*armresources.ClientListByResourceGroupResponse\n\n\tfile, err := os.ReadFile(\"testdata/json/azure_resources_response.json\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading file: %w\", err)\n\t}\n\n\tvar genericResourcesExpanded []*armresources.GenericResourceExpanded\n\tif err := json.Unmarshal(file, &genericResourcesExpanded); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resourceGroup == \"resourceGroup1\" {\n\t\tresponse := &armresources.ClientListByResourceGroupResponse{\n\t\t\tResourceListResult: armresources.ResourceListResult{\n\t\t\t\tValue: []*armresources.GenericResourceExpanded{\n\t\t\t\t\tgenericResourcesExpanded[0],\n\t\t\t\t\tgenericResourcesExpanded[1],\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tresponses = append(responses, response)\n\t\treturn responses, nil\n\t}\n\n\tif resourceGroup == \"resourceGroup2\" {\n\t\tresponse := &armresources.ClientListByResourceGroupResponse{\n\t\t\tResourceListResult: armresources.ResourceListResult{\n\t\t\t\tValue: []*armresources.GenericResourceExpanded{\n\t\t\t\t\tgenericResourcesExpanded[2],\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tresponses = append(responses, response)\n\t\treturn responses, nil\n\t}\n\n\treturn nil, errors.New(\"resource group was not found\")\n}\n\nfunc (*mockAzureMetricDefinitionsClient) List(\n\t_ context.Context,\n\tresourceID string,\n\t_ *armmonitor.MetricDefinitionsClientListOptions) (armmonitor.MetricDefinitionsClientListResponse, error) {\n\tfile, err := os.ReadFile(\"testdata/json/azure_metric_definitions_responses.json\")\n\tif err != nil {\n\t\treturn armmonitor.MetricDefinitionsClientListResponse{}, fmt.Errorf(\"error reading file: %w\", err)\n\t}\n\n\tvar metricDefinitions [][]*armmonitor.MetricDefinition\n\tif err := json.Unmarshal(file, &metricDefinitions); err != nil {\n\t\treturn armmonitor.MetricDefinitionsClientListResponse{}, err\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\" {\n\t\treturn armmonitor.MetricDefinitionsClientListResponse{\n\t\t\tMetricDefinitionCollection: armmonitor.MetricDefinitionCollection{\n\t\t\t\tValue: metricDefinitions[0],\n\t\t\t},\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\" {\n\t\treturn armmonitor.MetricDefinitionsClientListResponse{\n\t\t\tMetricDefinitionCollection: armmonitor.MetricDefinitionCollection{\n\t\t\t\tValue: metricDefinitions[1],\n\t\t\t},\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\" {\n\t\treturn armmonitor.MetricDefinitionsClientListResponse{\n\t\t\tMetricDefinitionCollection: armmonitor.MetricDefinitionCollection{\n\t\t\t\tValue: metricDefinitions[2],\n\t\t\t},\n\t\t}, nil\n\t}\n\n\treturn armmonitor.MetricDefinitionsClientListResponse{}, errors.New(\"resource ID was not found\")\n}\n\nfunc (*mockAzureMetricsClient) List(\n\t_ context.Context,\n\tresourceID string,\n\t_ *armmonitor.MetricsClientListOptions) (armmonitor.MetricsClientListResponse, error) {\n\tfile, err := os.ReadFile(\"testdata/json/azure_metrics_responses.json\")\n\tif err != nil {\n\t\treturn armmonitor.MetricsClientListResponse{}, fmt.Errorf(\"error reading file: %w\", err)\n\t}\n\n\tvar metricResponses []armmonitor.Response\n\tif err := json.Unmarshal(file, &metricResponses); err != nil {\n\t\treturn armmonitor.MetricsClientListResponse{}, err\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[0],\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[1],\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[2],\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource4\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[3],\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource5\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[4],\n\t\t}, nil\n\t}\n\n\tif resourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource6\" {\n\t\treturn armmonitor.MetricsClientListResponse{\n\t\t\tResponse: metricResponses[5],\n\t\t}, nil\n\t}\n\n\treturn armmonitor.MetricsClientListResponse{}, errors.New(\"resource ID was not found\")\n}\n\nfunc TestInit_ResourceTargetsOnly(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_targets_only.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tfor index := 1; index <= 27; index++ {\n\t\tif index <= 10 {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric1\")\n\t\t} else if index <= 23 {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric2\")\n\t\t} else {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric3\")\n\t\t}\n\t}\n\n\tvar expectedResourceMetrics []string\n\tfor index := 1; index <= receiver.MaxMetricsPerRequest; index++ {\n\t\tif index <= 10 {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric1\")\n\t\t} else {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric2\")\n\t\t}\n\t}\n\n\trequire.NoError(t, am.Init())\n\trequire.Len(t, am.receiver.Targets.ResourceTargets, 8)\n\n\tfor _, target := range am.receiver.Targets.ResourceTargets {\n\t\trequire.Contains(t, []string{\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"}, target.ResourceID)\n\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\" {\n\t\t\trequire.Contains(t, []int{1, 2, 3, 4, receiver.MaxMetricsPerRequest}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 1 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 2 {\n\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 3 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\", \"metric2\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 4 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\", \"metric3\", \"metric3\", \"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == receiver.MaxMetricsPerRequest {\n\t\t\t\trequire.Equal(t, expectedResourceMetrics, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\" {\n\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\trequire.Equal(t, []string{\n\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t}, target.Aggregations)\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\" {\n\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\", \"metric3\"}, target.Metrics)\n\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal)}, target.Aggregations)\n\t\t}\n\t}\n}\n\nfunc TestInit_ResourceGroupTargetsOnly(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_targets_only.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tfor index := 1; index <= 27; index++ {\n\t\tif index <= 10 {\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric1\")\n\t\t} else if index <= 23 {\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric2\")\n\t\t} else {\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric3\")\n\t\t}\n\t}\n\n\tvar expectedResourceMetrics []string\n\tfor index := 1; index <= receiver.MaxMetricsPerRequest; index++ {\n\t\tif index <= 10 {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric1\")\n\t\t} else {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric2\")\n\t\t}\n\t}\n\n\trequire.NoError(t, am.Init())\n\trequire.Len(t, am.receiver.Targets.ResourceTargets, 9)\n\n\tfor _, target := range am.receiver.Targets.ResourceTargets {\n\t\trequire.Contains(t, []string{\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"}, target.ResourceID)\n\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\" {\n\t\t\trequire.Contains(t, []int{1, 2, 3, 4, receiver.MaxMetricsPerRequest}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 1 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 2 {\n\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 3 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\", \"metric2\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 4 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\", \"metric3\", \"metric3\", \"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == receiver.MaxMetricsPerRequest {\n\t\t\t\trequire.Equal(t, expectedResourceMetrics, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\" {\n\t\t\trequire.Contains(t, []int{1, 2}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 1 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 2 {\n\t\t\t\trequire.Contains(t, []int{1, 5}, len(target.Aggregations))\n\n\t\t\t\tif len(target.Aggregations) == 1 {\n\t\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t\t}\n\t\t\t\tif len(target.Aggregations) == 5 {\n\t\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t\t}, target.Aggregations)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\" {\n\t\t\trequire.Equal(t, []string{\"metric3\"}, target.Metrics)\n\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t}\n\t}\n}\n\nfunc TestInit_SubscriptionTargetsOnly(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_targets_only.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tfor index := 1; index <= 27; index++ {\n\t\tif index <= 10 {\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric1\")\n\t\t} else if index <= 23 {\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric2\")\n\t\t} else {\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric3\")\n\t\t}\n\t}\n\n\tvar expectedResourceMetrics []string\n\tfor index := 1; index <= receiver.MaxMetricsPerRequest; index++ {\n\t\tif index <= 10 {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric1\")\n\t\t} else {\n\t\t\texpectedResourceMetrics = append(expectedResourceMetrics, \"metric2\")\n\t\t}\n\t}\n\n\trequire.NoError(t, am.Init())\n\trequire.Len(t, am.receiver.Targets.ResourceTargets, 11)\n\n\tfor _, target := range am.receiver.Targets.ResourceTargets {\n\t\trequire.Contains(t, []string{\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n\t\t\t\"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"}, target.ResourceID)\n\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\" {\n\t\t\trequire.Contains(t, []int{1, 2, 3, 4, receiver.MaxMetricsPerRequest}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 1 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 2 {\n\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 3 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\", \"metric2\", \"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 4 {\n\t\t\t\trequire.Equal(t, []string{\"metric3\", \"metric3\", \"metric3\", \"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == receiver.MaxMetricsPerRequest {\n\t\t\t\trequire.Equal(t, expectedResourceMetrics, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\" {\n\t\t\trequire.Contains(t, []int{1, 2}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 1 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 2 {\n\t\t\t\trequire.Contains(t, []int{1, 5}, len(target.Aggregations))\n\n\t\t\t\tif len(target.Aggregations) == 1 {\n\t\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t\t}\n\t\t\t\tif len(target.Aggregations) == 5 {\n\t\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\"}, target.Metrics)\n\t\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t\t}, target.Aggregations)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif target.ResourceID == \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\" {\n\t\t\trequire.Contains(t, []int{3, 7, receiver.MaxMetricsPerRequest}, len(target.Metrics))\n\n\t\t\tif len(target.Metrics) == 3 {\n\t\t\t\trequire.Equal(t, []string{\"metric1\", \"metric2\", \"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{string(armmonitor.AggregationTypeEnumTotal), string(armmonitor.AggregationTypeEnumAverage)}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == 7 {\n\t\t\t\trequire.Equal(t, []string{\"metric2\", \"metric2\", \"metric2\", \"metric3\", \"metric3\", \"metric3\", \"metric3\"}, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t\tif len(target.Metrics) == receiver.MaxMetricsPerRequest {\n\t\t\t\trequire.Equal(t, expectedResourceMetrics, target.Metrics)\n\t\t\t\trequire.Equal(t, []string{\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumAverage),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumCount),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMaximum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumMinimum),\n\t\t\t\t\tstring(armmonitor.AggregationTypeEnumTotal),\n\t\t\t\t}, target.Aggregations)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestInit_AllTargetTypes(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_all_target_types.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tfor index := 1; index <= 27; index++ {\n\t\tif index <= 10 {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric1\")\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric1\")\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric1\")\n\t\t} else if index <= 23 {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric2\")\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric2\")\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric2\")\n\t\t} else {\n\t\t\tam.ResourceTargets[4].Metrics = append(am.ResourceTargets[4].Metrics, \"metric3\")\n\t\t\tam.ResourceGroupTargets[0].Resources[1].Metrics = append(am.ResourceGroupTargets[0].Resources[1].Metrics, \"metric3\")\n\t\t\tam.SubscriptionTargets[4].Metrics = append(am.SubscriptionTargets[4].Metrics, \"metric3\")\n\t\t}\n\t}\n\n\trequire.NoError(t, am.Init())\n\trequire.Len(t, am.receiver.Targets.ResourceTargets, 28)\n}\n\nfunc TestInit_NoSubscriptionID(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_no_subscription_id.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_NoTargets(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_no_targets.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceTargetWithoutResourceID(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_target_without_resource_id.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceTargetWithInvalidResourceID(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_target_with_invalid_resource_id.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceTargetWithInvalidMetric(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_target_with_invalid_metric.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceTargetWithInvalidAggregation(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_target_with_invalid_aggregation.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithoutResourceGroup(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_without_resource_group.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithResourceWithoutResourceType(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_with_resource_without_resource_type.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithInvalidResourceGroup(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_with_invalid_resource_group.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithInvalidResourceType(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_with_invalid_resource_type.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithInvalidMetric(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_with_invalid_metric.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithInvalidAggregation(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_with_invalid_aggregation.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetWithoutResources(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_without_resources.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_ResourceGroupTargetNoResourceFound(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_resource_group_target_no_resource_found.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_SubscriptionTargetWithoutResourceType(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_target_without_resource_type.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_SubscriptionTargetWithInvalidResourceType(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_target_with_invalid_resource_type.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_SubscriptionTargetWithInvalidMetric(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_target_with_invalid_metric.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_SubscriptionTargetWithInvalidAggregation(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_target_with_invalid_aggregation.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_SubscriptionTargetNoResourceFound(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_subscription_target_no_resource_found.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\trequire.Error(t, am.Init())\n}\n\nfunc TestInit_BadCredentials(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/init_bad_credentials.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &azureClientsManager{}\n\trequire.Error(t, am.Init())\n}\n\nfunc TestGather_Success(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/gather_success.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\tresourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))\n\tfor _, target := range am.ResourceTargets {\n\t\tresourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))\n\t}\n\n\tvar clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}\n\n\tvar azureClients *receiver.AzureClients\n\tazureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, azureClients)\n\n\tam.receiver, err = receiver.NewAzureMonitorMetricsReceiver(\n\t\tam.SubscriptionID,\n\t\treceiver.NewTargets(resourceTargets, nil, nil),\n\t\tazureClients,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, am.receiver)\n\n\texpectedResource1Metric1Name := \"azure_monitor_microsoft_test_type1_metric1\"\n\texpectedResource1Metric1MetricFields := make(map[string]interface{})\n\texpectedResource1Metric1MetricFields[receiver.MetricFieldTimeStamp] = \"2022-02-22T22:59:00Z\"\n\texpectedResource1Metric1MetricFields[receiver.MetricFieldTotal] = 5.0\n\texpectedResource1Metric1MetricFields[receiver.MetricFieldMaximum] = 5.0\n\texpectedResource1Metric2Name := \"azure_monitor_microsoft_test_type1_metric2\"\n\texpectedResource1Metric2MetricFields := make(map[string]interface{})\n\texpectedResource1Metric2MetricFields[receiver.MetricFieldTimeStamp] = \"2022-02-22T22:59:00Z\"\n\texpectedResource1Metric2MetricFields[receiver.MetricFieldTotal] = 2.5\n\texpectedResource1Metric2MetricFields[receiver.MetricFieldMaximum] = 2.5\n\texpectedResource1MetricsTags := make(map[string]string)\n\texpectedResource1MetricsTags[receiver.MetricTagSubscriptionID] = \"subscriptionID\"\n\texpectedResource1MetricsTags[receiver.MetricTagResourceGroup] = \"resourceGroup1\"\n\texpectedResource1MetricsTags[receiver.MetricTagNamespace] = \"Microsoft.Test/type1\"\n\texpectedResource1MetricsTags[receiver.MetricTagResourceName] = \"resource1\"\n\texpectedResource1MetricsTags[receiver.MetricTagResourceRegion] = \"eastus\"\n\texpectedResource1MetricsTags[receiver.MetricTagUnit] = string(armmonitor.MetricUnitCount)\n\n\texpectedResource2Metric1Name := \"azure_monitor_microsoft_test_type2_metric1\"\n\texpectedResource2Metric1MetricFields := make(map[string]interface{})\n\texpectedResource2Metric1MetricFields[receiver.MetricFieldTimeStamp] = \"2022-02-22T22:59:00Z\"\n\texpectedResource2Metric1MetricFields[receiver.MetricFieldTotal] = 5.0\n\texpectedResource2Metric1MetricFields[receiver.MetricFieldMinimum] = 2.5\n\texpectedResource2MetricsTags := make(map[string]string)\n\texpectedResource2MetricsTags[receiver.MetricTagSubscriptionID] = \"subscriptionID\"\n\texpectedResource2MetricsTags[receiver.MetricTagResourceGroup] = \"resourceGroup1\"\n\texpectedResource2MetricsTags[receiver.MetricTagNamespace] = \"Microsoft.Test/type2\"\n\texpectedResource2MetricsTags[receiver.MetricTagResourceName] = \"resource2\"\n\texpectedResource2MetricsTags[receiver.MetricTagResourceRegion] = \"eastus\"\n\texpectedResource2MetricsTags[receiver.MetricTagUnit] = string(armmonitor.MetricUnitCount)\n\n\texpectedResource3Metric1Name := \"azure_monitor_microsoft_test_type1_metric1\"\n\texpectedResource3Metric1MetricFields := make(map[string]interface{})\n\texpectedResource3Metric1MetricFields[receiver.MetricFieldTimeStamp] = \"2022-02-22T22:58:00Z\"\n\texpectedResource3Metric1MetricFields[receiver.MetricFieldTotal] = 2.5\n\texpectedResource3Metric1MetricFields[receiver.MetricFieldMinimum] = 2.5\n\texpectedResource3MetricsTags := make(map[string]string)\n\texpectedResource3MetricsTags[receiver.MetricTagSubscriptionID] = \"subscriptionID\"\n\texpectedResource3MetricsTags[receiver.MetricTagResourceGroup] = \"resourceGroup2\"\n\texpectedResource3MetricsTags[receiver.MetricTagNamespace] = \"Microsoft.Test/type1\"\n\texpectedResource3MetricsTags[receiver.MetricTagResourceName] = \"resource3\"\n\texpectedResource3MetricsTags[receiver.MetricTagResourceRegion] = \"eastus\"\n\texpectedResource3MetricsTags[receiver.MetricTagUnit] = string(armmonitor.MetricUnitBytes)\n\n\tacc := testutil.Accumulator{}\n\n\trequire.NoError(t, acc.GatherError(am.Gather))\n\trequire.Len(t, acc.Metrics, 4)\n\n\tacc.AssertContainsTaggedFields(t, expectedResource1Metric1Name, expectedResource1Metric1MetricFields, expectedResource1MetricsTags)\n\tacc.AssertContainsTaggedFields(t, expectedResource1Metric2Name, expectedResource1Metric2MetricFields, expectedResource1MetricsTags)\n\tacc.AssertContainsTaggedFields(t, expectedResource2Metric1Name, expectedResource2Metric1MetricFields, expectedResource2MetricsTags)\n\tacc.AssertContainsTaggedFields(t, expectedResource3Metric1Name, expectedResource3Metric1MetricFields, expectedResource3MetricsTags)\n}\n\nfunc TestGather_China_Success(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/gather_success_cloud_option_china.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tresourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))\n\tfor _, target := range am.ResourceTargets {\n\t\tresourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))\n\t}\n\n\tvar clientOptions = azcore.ClientOptions{Cloud: cloud.AzureChina}\n\n\tvar azureClients *receiver.AzureClients\n\tazureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, azureClients)\n\n\tam.receiver, err = receiver.NewAzureMonitorMetricsReceiver(\n\t\tam.SubscriptionID,\n\t\treceiver.NewTargets(resourceTargets, nil, nil),\n\t\tazureClients,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, am.receiver)\n}\n\nfunc TestGather_Government_Success(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/gather_success_cloud_option_government.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tresourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))\n\tfor _, target := range am.ResourceTargets {\n\t\tresourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))\n\t}\n\n\tvar clientOptions = azcore.ClientOptions{Cloud: cloud.AzureGovernment}\n\n\tvar azureClients *receiver.AzureClients\n\tazureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, azureClients)\n\n\tam.receiver, err = receiver.NewAzureMonitorMetricsReceiver(\n\t\tam.SubscriptionID,\n\t\treceiver.NewTargets(resourceTargets, nil, nil),\n\t\tazureClients,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, am.receiver)\n}\n\nfunc TestGather_Public_Success(t *testing.T) {\n\tfile, err := os.ReadFile(\"testdata/toml/gather_success_cloud_option_public.toml\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, file)\n\trequire.NotEmpty(t, file)\n\n\tvar am *AzureMonitor\n\trequire.NoError(t, toml.Unmarshal(file, &am))\n\n\tam.Log = testutil.Logger{}\n\tam.azureManager = &mockAzureClientsManager{}\n\n\tresourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))\n\tfor _, target := range am.ResourceTargets {\n\t\tresourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))\n\t}\n\n\tvar clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}\n\n\tvar azureClients *receiver.AzureClients\n\tazureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, azureClients)\n\n\tam.receiver, err = receiver.NewAzureMonitorMetricsReceiver(\n\t\tam.SubscriptionID,\n\t\treceiver.NewTargets(resourceTargets, nil, nil),\n\t\tazureClients,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, am.receiver)\n}\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/sample.conf",
    "content": "# Gather Azure resources metrics from Azure Monitor API\n[[inputs.azure_monitor]]\n  # can be found under Overview->Essentials in the Azure portal for your application/service\n  subscription_id = \"<<SUBSCRIPTION_ID>>\"\n  # can be obtained by registering an application under Azure Active Directory\n  client_id = \"<<CLIENT_ID>>\"\n  # can be obtained by registering an application under Azure Active Directory.\n  # If not specified Default Azure Credentials chain will be attempted:\n  # - Environment credentials (AZURE_*)\n  # - Workload Identity in Kubernetes cluster\n  # - Managed Identity\n  # - Azure CLI auth\n  # - Developer Azure CLI auth\n  client_secret = \"<<CLIENT_SECRET>>\"\n  # can be found under Azure Active Directory->Properties\n  tenant_id = \"<<TENANT_ID>>\"\n  # Define the optional Azure cloud option e.g. AzureChina, AzureGovernment or AzurePublic. The default is AzurePublic.\n  # cloud_option = \"AzurePublic\"\n\n  # resource target #1 to collect metrics from\n  [[inputs.azure_monitor.resource_target]]\n    # can be found under Overview->Essentials->JSON View in the Azure portal for your application/service\n    # must start with 'resourceGroups/...' ('/subscriptions/xxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxxxx'\n    # must be removed from the beginning of Resource ID property value)\n    resource_id = \"<<RESOURCE_ID>>\"\n    # the metric names to collect\n    # leave the array empty to use all metrics available to this resource\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    # metrics aggregation type value to collect\n    # can be 'Total', 'Count', 'Average', 'Minimum', 'Maximum'\n    # leave the array empty to collect all aggregation types values for each metric\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource target #2 to collect metrics from\n  [[inputs.azure_monitor.resource_target]]\n    resource_id = \"<<RESOURCE_ID>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource group target #1 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.resource_group_target]]\n    # the resource group name\n    resource_group = \"<<RESOURCE_GROUP_NAME>>\"\n\n    # defines the resources to collect metrics from\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      # the resource type\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n    # defines the resources to collect metrics from\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # resource group target #2 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.resource_group_target]]\n    resource_group = \"<<RESOURCE_GROUP_NAME>>\"\n\n    [[inputs.azure_monitor.resource_group_target.resource]]\n      resource_type = \"<<RESOURCE_TYPE>>\"\n      metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n      aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # subscription target #1 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.subscription_target]]\n    resource_type = \"<<RESOURCE_TYPE>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n\n  # subscription target #2 to collect metrics from resources under it with resource type\n  [[inputs.azure_monitor.subscription_target]]\n    resource_type = \"<<RESOURCE_TYPE>>\"\n    metrics = [ \"<<METRIC>>\", \"<<METRIC>>\" ]\n    aggregations = [ \"<<AGGREGATION>>\", \"<<AGGREGATION>>\" ]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/json/azure_metric_definitions_responses.json",
    "content": "[\n  [\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n      \"name\": {\n        \"value\": \"metric1\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    },\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n      \"name\": {\n        \"value\": \"metric2\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    },\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n      \"name\": {\n        \"value\": \"metric3\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    }\n  ],\n  [\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n      \"name\": {\n        \"value\": \"metric1\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    },\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n      \"name\": {\n        \"value\": \"metric2\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        }\n      ]\n    }\n  ],\n  [\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\",\n      \"name\": {\n        \"value\": \"metric1\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    },\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\",\n      \"name\": {\n        \"value\": \"metric2\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    },\n    {\n      \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\",\n      \"name\": {\n        \"value\": \"metric3\"\n      },\n      \"metricAvailabilities\": [\n        {\n          \"timeGrain\": \"PT1M\"\n        },\n        {\n          \"timeGrain\": \"PT5M\"\n        }\n      ]\n    }\n  ]\n]"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/json/azure_metrics_responses.json",
    "content": "[\n  {\n    \"namespace\": \"Microsoft.Test/type1\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1/providers/Microsoft.Insights/metrics/metric1\",\n        \"name\": {\n          \"localizedValue\": \"metric1\"\n        },\n        \"unit\": \"Count\",\n        \"timeseries\": [\n          {\n            \"data\": [\n              {\n                \"timeStamp\": \"2022-02-22T22:00:00Z\",\n                \"total\": 1.0,\n                \"maximum\": 1.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:01:00Z\",\n                \"total\": 2.0,\n                \"maximum\": 2.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:02:00Z\",\n                \"total\": 2.5,\n                \"maximum\": 2.5\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:58:00Z\",\n                \"total\": 2.0,\n                \"maximum\": 2.5\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:59:00Z\",\n                \"total\": 5.0,\n                \"maximum\": 5.0\n              }\n            ]\n          }\n        ],\n        \"errorCode\": \"Success\"\n      },\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1/providers/Microsoft.Insights/metrics/metric2\",\n        \"name\": {\n          \"localizedValue\": \"metric2\"\n        },\n        \"unit\": \"Count\",\n        \"timeseries\": [\n          {\n            \"data\": [\n              {\n                \"timeStamp\": \"2022-02-22T22:00:00Z\",\n                \"total\": 2.0,\n                \"maximum\": 2.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:01:00Z\",\n                \"total\": 1.0,\n                \"maximum\": 2.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:02:00Z\",\n                \"total\": 1.0,\n                \"maximum\": 2.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:58:00Z\",\n                \"total\": 2.5,\n                \"maximum\": 2.5\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:59:00Z\",\n                \"total\": 2.5,\n                \"maximum\": 2.5\n              }\n            ]\n          }\n        ],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  },\n  {\n    \"namespace\": \"Microsoft.Test/type2\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2/providers/Microsoft.Insights/metrics/metric1\",\n        \"name\": {\n          \"localizedValue\": \"metric1\"\n        },\n        \"unit\": \"Count\",\n        \"timeseries\": [\n          {\n            \"data\": [\n              {\n                \"timeStamp\": \"2022-02-22T22:00:00Z\",\n                \"total\": 5.0,\n                \"minimum\": 5.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:01:00Z\",\n                \"total\": 3.0,\n                \"minimum\": 3.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:02:00Z\",\n                \"total\": 5.0,\n                \"minimum\": 3.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:58:00Z\",\n                \"total\": 2.5,\n                \"minimum\": 2.5\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:59:00Z\",\n                \"total\": 5.0,\n                \"minimum\": 2.5\n              }\n            ]\n          }\n        ],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  },\n  {\n    \"namespace\": \"Microsoft.Test/type1\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3/providers/Microsoft.Insights/metrics/metric1\",\n        \"name\": {\n          \"localizedValue\": \"metric1\"\n        },\n        \"unit\": \"Bytes\",\n        \"timeseries\": [\n          {\n            \"data\": [\n              {\n                \"timeStamp\": \"2022-02-22T22:00:00Z\",\n                \"total\": 5.0,\n                \"minimum\": 5.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:01:00Z\",\n                \"total\": 3.0,\n                \"minimum\": 3.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:02:00Z\",\n                \"total\": 5.0,\n                \"minimum\": 3.0\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:58:00Z\",\n                \"total\": 2.5,\n                \"minimum\": 2.5\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:59:00Z\"\n              }\n            ]\n          }\n        ],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  },\n  {\n    \"namespace\": \"Microsoft.Test/type2\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource4/providers/Microsoft.Insights/metrics/metric1\",\n        \"name\": {\n          \"localizedValue\": \"metric1\"\n        },\n        \"unit\": \"Bytes\",\n        \"timeseries\": [\n          {\n            \"data\": [\n              {\n                \"timeStamp\": \"2022-02-22T22:00:00Z\"\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:01:00Z\"\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:02:00Z\"\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:58:00Z\"\n              },\n              {\n                \"timeStamp\": \"2022-02-22T22:59:00Z\"\n              }\n            ]\n          }\n        ],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  },\n  {\n    \"namespace\": \"Microsoft.Test/type2\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource5/providers/Microsoft.Insights/metrics/metric2\",\n        \"name\": {\n          \"localizedValue\": \"metric2\"\n        },\n        \"unit\": \"Bytes\",\n        \"timeseries\": [\n          {\n            \"data\": []\n          }\n        ],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  },\n  {\n    \"namespace\": \"Microsoft.Test/type2\",\n    \"resourceregion\": \"eastus\",\n    \"value\": [\n      {\n        \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource6/providers/Microsoft.Insights/metrics/metric2\",\n        \"name\": {\n          \"localizedValue\": \"metric2\"\n        },\n        \"unit\": \"Bytes\",\n        \"timeseries\": [],\n        \"errorCode\": \"Success\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/json/azure_resources_response.json",
    "content": "[\n  {\n    \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\",\n    \"type\": \"Microsoft.Test/type1\"\n  },\n  {\n    \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\",\n    \"type\": \"Microsoft.Test/type2\"\n  },\n  {\n    \"id\": \"/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\",\n    \"type\": \"Microsoft.Test/type1\"\n  }\n]"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/gather_success.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = [\"Total\", \"Maximum\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\"\n    metrics = [\"metric1\"]\n    aggregations = [\"Total\", \"Minimum\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"\n    metrics = [\"metric1\"]\n    aggregations = [\"Total\", \"Minimum\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource4\"\n    metrics = [\"metric1\"]\n    aggregations = [\"Total\", \"Maximum\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource5\"\n    metrics = [\"metric2\"]\n    aggregations = [\"Total\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource6\"\n    metrics = [\"metric2\"]\n    aggregations = [\"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_china.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\ncloud_option = \"AzureChina\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = [\"Total\", \"Maximum\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_government.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\ncloud_option = \"AzureGovernment\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = [\"Total\", \"Maximum\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_public.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\ncloud_option = \"AzurePublic\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = [\"Total\", \"Maximum\"]"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_all_target_types.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = []\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"\n    metrics = []\n    aggregations = [\"Total\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\"\n    metrics = []\n    aggregations = []\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = [\"metric1\", \"metric2\", \"metric3\"]\n      aggregations = [\"Total\", \"Average\"]\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = []\n      aggregations = []\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = []\n      aggregations = [\"Average\"]\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = [\"metric2\"]\n      aggregations = []\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = [\"metric2\"]\n      aggregations = []\n\n  [[resource_group_target]]\n      resource_group = \"resourceGroup2\"\n\n      [[resource_group_target.resource]]\n        resource_type = \"Microsoft.Test/type1\"\n        metrics = [\"metric3\"]\n        aggregations = [\"Total\", \"Average\"]\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = []\n    aggregations = [\"Average\"]\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = [\"metric2\"]\n    aggregations = []\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = []\n    aggregations = []\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_bad_credentials.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_no_client_id.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_no_client_secret.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_no_subscription_id.toml",
    "content": "client_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_no_targets.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_no_tenant_id.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_no_resource_found.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup2\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = [\"metric1\", \"metric2\"]\n      aggregations = [\"Total\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_aggregation.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = []\n      aggregations = [\"Invalid\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_metric.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = [\"invalid\"]\n      aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_resource_group.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"invalid\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = [\"metric1\", \"metric2\", \"metric3\"]\n      aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_resource_type.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/invalid\"\n      metrics = [\"metric1\", \"metric2\", \"metric3\"]\n      aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_resource_without_resource_type.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      metrics = []\n      aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_without_resource_group.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = []\n      aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_without_resources.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_group_targets_only.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_group_target]]\n    resource_group = \"resourceGroup1\"\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = [\"metric1\", \"metric2\", \"metric3\"]\n      aggregations = [\"Total\", \"Average\"]\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type1\"\n      metrics = []\n      aggregations = []\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = []\n      aggregations = [\"Average\"]\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = [\"metric2\"]\n      aggregations = []\n\n    [[resource_group_target.resource]]\n      resource_type = \"Microsoft.Test/type2\"\n      metrics = [\"metric2\"]\n      aggregations = []\n\n  [[resource_group_target]]\n      resource_group = \"resourceGroup2\"\n\n      [[resource_group_target.resource]]\n        resource_type = \"Microsoft.Test/type1\"\n        metrics = [\"metric3\"]\n        aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_aggregation.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Invalid\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_metric.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"invalid\"]\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_resource_id.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"invalid\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_target_without_resource_id.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_resource_targets_only.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = []\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3\"\n    metrics = []\n    aggregations = [\"Total\"]\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2\"\n    metrics = []\n    aggregations = []\n\n  [[resource_target]]\n    resource_id = \"resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_no_resource_found.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type3\"\n    metrics = [\"metric1\", \"metric2\"]\n    aggregations = [\"Total\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_aggregation.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = []\n    aggregations = [\"Invalid\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_metric.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = [\"invalid\"]\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_resource_type.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/invalid\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_without_resource_type.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n"
  },
  {
    "path": "plugins/inputs/azure_monitor/testdata/toml/init_subscription_targets_only.toml",
    "content": "subscription_id = \"subscriptionID\"\nclient_id = \"clientID\"\nclient_secret = \"clientSecret\"\ntenant_id = \"tenantID\"\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = [\"metric1\", \"metric2\", \"metric3\"]\n    aggregations = [\"Total\", \"Average\"]\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = []\n    aggregations = [\"Average\"]\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = [\"metric2\"]\n    aggregations = []\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type2\"\n    metrics = []\n    aggregations = []\n\n  [[subscription_target]]\n    resource_type = \"Microsoft.Test/type1\"\n    metrics = []\n    aggregations = []\n"
  },
  {
    "path": "plugins/inputs/azure_storage_queue/README.md",
    "content": "# Azure Queue Storage Input Plugin\n\nThis plugin gathers queue sizes from the [Azure Queue Storage][azure_queues]\nservice, storing a large numbers of messages.\n\n⭐ Telegraf v1.13.0\n🏷️ cloud\n💻 all\n\n[azure_queues]: https://learn.microsoft.com/en-us/azure/storage/queues\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather Azure Storage Queue metrics\n[[inputs.azure_storage_queue]]\n  ## Azure Storage Account name and shared access key (required)\n  account_name = \"mystorageaccount\"\n  account_key = \"storageaccountaccesskey\"\n\n  ## Disable peeking age of oldest message (faster)\n  # peek_oldest_message_age = true\n```\n\n## Metrics\n\n- azure_storage_queues\n  - tags:\n    - queue\n    - account\n  - fields:\n    - size (integer, count)\n    - oldest_message_age_ns (integer, nanoseconds) Age of message at the head\n      of the queue. Requires `peek_oldest_message_age` to be configured\n      to `true`.\n\n## Example Output\n\n```text\nazure_storage_queues,queue=myqueue,account=mystorageaccount oldest_message_age=799714900i,size=7i 1565970503000000000\nazure_storage_queues,queue=myemptyqueue,account=mystorageaccount size=0i 1565970502000000000\n```\n"
  },
  {
    "path": "plugins/inputs/azure_storage_queue/azure_storage_queue.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage azure_storage_queue\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype AzureStorageQueue struct {\n\tEndpointURL          string `toml:\"endpoint\"`\n\tStorageAccountName   string `toml:\"account_name\"`\n\tStorageAccountKey    string `toml:\"account_key\"`\n\tPeekOldestMessageAge bool   `toml:\"peek_oldest_message_age\"`\n\tLog                  telegraf.Logger\n\n\tclient *azqueue.ServiceClient\n}\n\nfunc (*AzureStorageQueue) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (a *AzureStorageQueue) Init() error {\n\t// Check settings\n\tif a.StorageAccountName == \"\" {\n\t\treturn errors.New(\"account_name must be configured\")\n\t}\n\n\tif a.StorageAccountKey == \"\" {\n\t\treturn errors.New(\"account_key must be configured\")\n\t}\n\n\t// Prepare the client\n\tif a.EndpointURL == \"\" {\n\t\ta.EndpointURL = \"https://\" + a.StorageAccountName + \".queue.core.windows.net\"\n\t}\n\tcredentials, err := azqueue.NewSharedKeyCredential(a.StorageAccountName, a.StorageAccountKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating shared-key credentials failed: %w\", err)\n\t}\n\n\tclient, err := azqueue.NewServiceClientWithSharedKeyCredential(a.EndpointURL, credentials, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\ta.client = client\n\n\treturn nil\n}\n\nfunc (a *AzureStorageQueue) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\n\ta.Log.Debugf(\"Listing queues of storage account %q\", a.StorageAccountName)\n\n\t// Iterate through the queues and generate metrics\n\tpages := a.client.NewListQueuesPager(nil)\n\tfor pages.More() {\n\t\tresponse, err := pages.NextPage(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting next page failed: %w\", err)\n\t\t}\n\n\t\t// Get the properties and the message properties for each of the queues\n\t\tfor _, queue := range response.Queues {\n\t\t\tif queue.Name == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tname := strings.TrimSpace(*queue.Name)\n\n\t\t\t// Access the queue and get the properties\n\t\t\tc := a.client.NewQueueClient(*queue.Name)\n\t\t\tprops, err := c.GetProperties(ctx, nil)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"getting properties for queue %q failed: %w\", name, err))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif props.ApproximateMessagesCount == nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unset message count for queue %q\", name))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Setup the metric elements\n\t\t\ttags := map[string]string{\n\t\t\t\t\"account\": a.StorageAccountName,\n\t\t\t\t\"queue\":   strings.TrimSpace(name),\n\t\t\t}\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"size\": *props.ApproximateMessagesCount,\n\t\t\t}\n\t\t\tnow := time.Now()\n\t\t\tif a.PeekOldestMessageAge {\n\t\t\t\tif r, err := c.PeekMessage(ctx, nil); err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"peeking message for queue %q failed: %w\", name, err))\n\t\t\t\t} else if len(r.Messages) > 0 && r.Messages[0] != nil && r.Messages[0].InsertionTime != nil {\n\t\t\t\t\tmsg := r.Messages[0]\n\t\t\t\t\tfields[\"oldest_message_age_ns\"] = now.Sub(*msg.InsertionTime).Nanoseconds()\n\t\t\t\t}\n\t\t\t}\n\t\t\tacc.AddFields(\"azure_storage_queues\", fields, tags, now)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"azure_storage_queue\", func() telegraf.Input {\n\t\treturn &AzureStorageQueue{PeekOldestMessageAge: true}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/azure_storage_queue/azure_storage_queue_test.go",
    "content": "package azure_storage_queue\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go\"\n\t\"github.com/testcontainers/testcontainers-go/modules/azure/azurite\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestEmulatorIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Require the developers to explicitly accept the EULA of the emulator\n\tif os.Getenv(\"AZURE_EVENT_HUBS_EMULATOR_ACCEPT_EULA\") != \"yes\" {\n\t\tt.Skip(`\n\t\t\tSkipping due to unexcepted EULA. To run this test, please check the EULA of the emulator\n\t\t\tat https://github.com/Azure/azure-event-hubs-emulator-installer/blob/main/EMULATOR_EULA.md\n\t\t\tand accept it by setting the environment variable AZURE_EVENT_HUBS_EMULATOR_ACCEPT_EULA\n\t\t\tto 'yes'.\n\t\t`)\n\t}\n\n\t// Setup the Azure Event Hub emulator environment\n\t// See https://learn.microsoft.com/en-us/azure/event-hubs/test-locally-with-event-hub-emulator\n\temulator, err := azurite.Run(\n\t\tt.Context(),\n\t\t\"mcr.microsoft.com/azure-storage/azurite:3.28.0\",\n\t\tazurite.WithInMemoryPersistence(64.0),\n\t)\n\trequire.NoError(t, err, \"failed to start Azurite container\")\n\tdefer testcontainers.TerminateContainer(emulator) //nolint:errcheck // Ignore error as we can't do anything about it\n\n\tendpoint, err := emulator.QueueServiceURL(t.Context())\n\trequire.NoError(t, err, \"getting queue URL failed\")\n\tendpoint += \"/\" + azurite.AccountName\n\n\t// Create two queues and push some messages to get data\n\tcredentials, err := azqueue.NewSharedKeyCredential(azurite.AccountName, azurite.AccountKey)\n\trequire.NoError(t, err)\n\n\tclient, err := azqueue.NewServiceClientWithSharedKeyCredential(endpoint, credentials, nil)\n\trequire.NoError(t, err)\n\n\t// Remember the oldest messages\n\toldest := make(map[string]time.Time, 2)\n\n\t// Add five messages to test queue one\n\t_, err = client.CreateQueue(t.Context(), \"test-one\", nil)\n\trequire.NoError(t, err)\n\n\tqc := client.NewQueueClient(\"test-one\")\n\tfor i := range 5 {\n\t\tmsg := fmt.Sprintf(`{\"count\": %d, \"message\": \"foobar\"}`, i)\n\t\tresp, err := qc.EnqueueMessage(t.Context(), msg, nil)\n\t\trequire.NoError(t, err)\n\t\tif i == 0 {\n\t\t\toldest[\"test-one\"] = *resp.Date\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n\n\t// Add three messages to test queue two\n\t_, err = client.CreateQueue(t.Context(), \"test-two\", nil)\n\trequire.NoError(t, err)\n\n\tqc = client.NewQueueClient(\"test-two\")\n\tfor i := range 3 {\n\t\tmsg := fmt.Sprintf(`{\"count\": %d, \"message\": \"tiger\"}`, i)\n\t\tresp, err := qc.EnqueueMessage(t.Context(), msg, nil)\n\t\trequire.NoError(t, err)\n\t\tif i == 0 {\n\t\t\toldest[\"test-two\"] = *resp.Date\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n\n\t// Setup plugin\n\tplugin := &AzureStorageQueue{\n\t\tEndpointURL:          endpoint,\n\t\tStorageAccountName:   azurite.AccountName,\n\t\tStorageAccountKey:    azurite.AccountKey,\n\t\tPeekOldestMessageAge: true,\n\t\tLog:                  &testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\t// Make sure we are connected\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"azure_storage_queues\",\n\t\t\tmap[string]string{\n\t\t\t\t\"account\": azurite.AccountName,\n\t\t\t\t\"queue\":   \"test-one\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"oldest_message_age_ns\": int64(0),\n\t\t\t\t\"size\":                  int64(5),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"azure_storage_queues\",\n\t\t\tmap[string]string{\n\t\t\t\t\"account\": azurite.AccountName,\n\t\t\t\t\"queue\":   \"test-two\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"oldest_message_age_ns\": int64(0),\n\t\t\t\t\"size\":                  int64(3),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Test the metrics\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.IgnoreFields(\"oldest_message_age_ns\"),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\n\t// Test the oldest-message values\n\tfor _, m := range actual {\n\t\tq, found := m.GetTag(\"queue\")\n\t\trequire.True(t, found)\n\n\t\tactualAge, found := m.GetField(\"oldest_message_age_ns\")\n\t\trequire.True(t, found)\n\n\t\texpectedAge := m.Time().Sub(oldest[q])\n\t\trequire.Equal(t, expectedAge.Nanoseconds(), actualAge)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/azure_storage_queue/sample.conf",
    "content": "# Gather Azure Storage Queue metrics\n[[inputs.azure_storage_queue]]\n  ## Azure Storage Account name and shared access key (required)\n  account_name = \"mystorageaccount\"\n  account_key = \"storageaccountaccesskey\"\n\n  ## Disable peeking age of oldest message (faster)\n  # peek_oldest_message_age = true\n"
  },
  {
    "path": "plugins/inputs/bcache/README.md",
    "content": "# Bcache Input Plugin\n\nThis plugin gathers statistics for the [block layer cache][bcache]\nfrom the `stats_total` directory and `dirty_data` file.\n\n⭐ Telegraf v0.2.0\n🏷️ system\n💻 linux\n\n[bcache]: https://docs.kernel.org/admin-guide/bcache.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics of bcache from stats_total and dirty_data\n# This plugin ONLY supports Linux\n[[inputs.bcache]]\n  ## Bcache sets path\n  ## If not specified, then default is:\n  bcachePath = \"/sys/fs/bcache\"\n\n  ## By default, Telegraf gather stats for all bcache devices\n  ## Setting devices will restrict the stats to the specified\n  ## bcache devices.\n  bcacheDevs = [\"bcache0\"]\n```\n\n## Metrics\n\nTags:\n\n- `backing_dev` device backed by the cache\n- `bcache_dev` device used for caching\n\nFields:\n\n- `dirty_data`: Amount of dirty data for this backing device in the cache.\n  Continuously updated unlike the cache set's version, but may be slightly off\n- `bypassed`: Amount of IO (both reads and writes) that has bypassed the cache\n- `cache_bypass_hits`:  Hits for IO that is intended to skip the cache\n- `cache_bypass_misses`:  Misses for IO that is intended to skip the cache\n- `cache_hits`: Hits per individual IO as seen by bcache sees them; a\n  partial hit is counted as a miss.\n- `cache_misses`: Misses per individual IO as seen by bcache sees them; a\n  partial hit is counted as a miss.\n- `cache_hit_ratio`: Hit to miss ratio\n- `cache_miss_collisions`: Instances where data was going to be inserted into\n  cache from a miss, but raced with a write and data was already present\n  (usually zero since the synchronization for cache misses was rewritten)\n- `cache_readaheads`: Count of times readahead occurred.\n\n## Example Output\n\n```text\nbcache,backing_dev=\"md10\",bcache_dev=\"bcache0\" dirty_data=11639194i,bypassed=5167704440832i,cache_bypass_hits=146270986i,cache_bypass_misses=0i,cache_hit_ratio=90i,cache_hits=511941651i,cache_miss_collisions=157678i,cache_misses=50647396i,cache_readaheads=0i\n```\n"
  },
  {
    "path": "plugins/inputs/bcache/bcache.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage bcache\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Bcache struct {\n\tBcachePath string   `toml:\"bcachePath\"`\n\tBcacheDevs []string `toml:\"bcacheDevs\"`\n}\n\nfunc (*Bcache) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *Bcache) Gather(acc telegraf.Accumulator) error {\n\tbcacheDevsChecked := make(map[string]bool)\n\tvar restrictDevs bool\n\tif len(b.BcacheDevs) != 0 {\n\t\trestrictDevs = true\n\t\tfor _, bcacheDev := range b.BcacheDevs {\n\t\t\tbcacheDevsChecked[bcacheDev] = true\n\t\t}\n\t}\n\n\tbcachePath := b.BcachePath\n\tif len(bcachePath) == 0 {\n\t\tbcachePath = \"/sys/fs/bcache\"\n\t}\n\tbdevs, err := filepath.Glob(bcachePath + \"/*/bdev*\")\n\tif len(bdevs) < 1 || err != nil {\n\t\treturn errors.New(\"can't find any bcache device\")\n\t}\n\tfor _, bdev := range bdevs {\n\t\tif restrictDevs {\n\t\t\tbcacheDev := getTags(bdev)[\"bcache_dev\"]\n\t\t\tif !bcacheDevsChecked[bcacheDev] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif err := gatherBcache(bdev, acc); err != nil {\n\t\t\treturn fmt.Errorf(\"gathering bcache failed: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getTags(bdev string) map[string]string {\n\t//nolint:errcheck // unable to propagate\n\tbackingDevFile, _ := os.Readlink(bdev)\n\tbackingDevPath := strings.Split(backingDevFile, \"/\")\n\tbackingDev := backingDevPath[len(backingDevPath)-2]\n\n\t//nolint:errcheck // unable to propagate\n\tbcacheDevFile, _ := os.Readlink(bdev + \"/dev\")\n\tbcacheDevPath := strings.Split(bcacheDevFile, \"/\")\n\tbcacheDev := bcacheDevPath[len(bcacheDevPath)-1]\n\n\treturn map[string]string{\"backing_dev\": backingDev, \"bcache_dev\": bcacheDev}\n}\n\nfunc prettyToBytes(v string) uint64 {\n\tvar factors = map[string]uint64{\n\t\t\"k\": 1 << 10,\n\t\t\"M\": 1 << 20,\n\t\t\"G\": 1 << 30,\n\t\t\"T\": 1 << 40,\n\t\t\"P\": 1 << 50,\n\t\t\"E\": 1 << 60,\n\t}\n\tvar factor uint64\n\tfactor = 1\n\tprefix := v[len(v)-1:]\n\tif factors[prefix] != 0 {\n\t\tv = v[:len(v)-1]\n\t\tfactor = factors[prefix]\n\t}\n\t//nolint:errcheck // unable to propagate\n\tresult, _ := strconv.ParseFloat(v, 32)\n\tresult = result * float64(factor)\n\n\treturn uint64(result)\n}\n\nfunc gatherBcache(bdev string, acc telegraf.Accumulator) error {\n\ttags := getTags(bdev)\n\tmetrics, err := filepath.Glob(bdev + \"/stats_total/*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(metrics) == 0 {\n\t\treturn errors.New(\"can't read any stats file\")\n\t}\n\tfile, err := os.ReadFile(bdev + \"/dirty_data\")\n\tif err != nil {\n\t\treturn err\n\t}\n\trawValue := strings.TrimSpace(string(file))\n\tvalue := prettyToBytes(rawValue)\n\n\tfields := make(map[string]interface{})\n\tfields[\"dirty_data\"] = value\n\n\tfor _, path := range metrics {\n\t\tkey := filepath.Base(path)\n\t\tfile, err := os.ReadFile(path)\n\t\trawValue := strings.TrimSpace(string(file))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif key == \"bypassed\" {\n\t\t\tvalue := prettyToBytes(rawValue)\n\t\t\tfields[key] = value\n\t\t} else {\n\t\t\tvalue, err := strconv.ParseUint(rawValue, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\tacc.AddFields(\"bcache\", fields, tags)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"bcache\", func() telegraf.Input {\n\t\treturn &Bcache{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/bcache/bcache_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage bcache\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Bcache struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Bcache) SampleConfig() string { return sampleConfig }\n\nfunc (b *Bcache) Init() error {\n\tb.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Bcache) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"bcache\", func() telegraf.Input {\n\t\treturn &Bcache{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/bcache/bcache_test.go",
    "content": "//go:build linux\n\npackage bcache\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tdirtyData           = \"1.5G\"\n\tbypassed            = \"4.7T\"\n\tcacheBypassHits     = \"146155333\"\n\tcacheBypassMisses   = \"0\"\n\tcacheHitRatio       = \"90\"\n\tcacheHits           = \"511469583\"\n\tcacheMissCollisions = \"157567\"\n\tcacheMisses         = \"50616331\"\n\tcacheReadaheads     = \"2\"\n)\n\nfunc TestBcacheGeneratesMetrics(t *testing.T) {\n\ttmpDir := t.TempDir()\n\n\ttestBcachePath := tmpDir + \"/telegraf-bcache/sys/fs/bcache\"\n\ttestBcacheUUIDPath := testBcachePath + \"/663955a3-765a-4737-a9fd-8250a7a78411\"\n\ttestBcacheDevPath := tmpDir + \"/telegraf/sys/devices/virtual/block/bcache0\"\n\ttestBcacheBackingDevPath := tmpDir + \"/telegraf/sys/devices/virtual/block/md10\"\n\n\terr := os.MkdirAll(testBcacheUUIDPath, 0750)\n\trequire.NoError(t, err)\n\n\terr = os.MkdirAll(testBcacheDevPath, 0750)\n\trequire.NoError(t, err)\n\n\terr = os.MkdirAll(testBcacheBackingDevPath+\"/bcache\", 0750)\n\trequire.NoError(t, err)\n\n\terr = os.Symlink(testBcacheBackingDevPath+\"/bcache\", testBcacheUUIDPath+\"/bdev0\")\n\trequire.NoError(t, err)\n\n\terr = os.Symlink(testBcacheDevPath, testBcacheUUIDPath+\"/bdev0/dev\")\n\trequire.NoError(t, err)\n\n\terr = os.MkdirAll(testBcacheUUIDPath+\"/bdev0/stats_total\", 0750)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/dirty_data\", []byte(dirtyData), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/bypassed\", []byte(bypassed), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_bypass_hits\", []byte(cacheBypassHits), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_bypass_misses\", []byte(cacheBypassMisses), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_hit_ratio\", []byte(cacheHitRatio), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_hits\", []byte(cacheHits), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_miss_collisions\", []byte(cacheMissCollisions), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_misses\", []byte(cacheMisses), 0640)\n\trequire.NoError(t, err)\n\n\terr = os.WriteFile(testBcacheUUIDPath+\"/bdev0/stats_total/cache_readaheads\", []byte(cacheReadaheads), 0640)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"dirty_data\":            uint64(1610612736),\n\t\t\"bypassed\":              uint64(5167704440832),\n\t\t\"cache_bypass_hits\":     uint64(146155333),\n\t\t\"cache_bypass_misses\":   uint64(0),\n\t\t\"cache_hit_ratio\":       uint64(90),\n\t\t\"cache_hits\":            uint64(511469583),\n\t\t\"cache_miss_collisions\": uint64(157567),\n\t\t\"cache_misses\":          uint64(50616331),\n\t\t\"cache_readaheads\":      uint64(2),\n\t}\n\n\ttags := map[string]string{\n\t\t\"backing_dev\": \"md10\",\n\t\t\"bcache_dev\":  \"bcache0\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\t// all devs\n\tb := &Bcache{BcachePath: testBcachePath}\n\n\terr = b.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.AssertContainsTaggedFields(t, \"bcache\", fields, tags)\n\n\t// one exist dev\n\tb = &Bcache{BcachePath: testBcachePath, BcacheDevs: []string{\"bcache0\"}}\n\n\terr = b.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.AssertContainsTaggedFields(t, \"bcache\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/bcache/sample.conf",
    "content": "# Read metrics of bcache from stats_total and dirty_data\n# This plugin ONLY supports Linux\n[[inputs.bcache]]\n  ## Bcache sets path\n  ## If not specified, then default is:\n  bcachePath = \"/sys/fs/bcache\"\n\n  ## By default, Telegraf gather stats for all bcache devices\n  ## Setting devices will restrict the stats to the specified\n  ## bcache devices.\n  bcacheDevs = [\"bcache0\"]\n"
  },
  {
    "path": "plugins/inputs/beanstalkd/README.md",
    "content": "# Beanstalkd Input Plugin\n\nThis plugin collects server statistics as well as tube statistics from a\n[Beanstalkd work queue][beanstalkd] as reported by the `stats` and `stats-tube`\nserver commands.\n\n⭐ Telegraf v1.8.0\n🏷️ messaging\n💻 all\n\n[beanstalkd]: https://beanstalkd.github.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collects Beanstalkd server and tubes stats\n[[inputs.beanstalkd]]\n  ## Server to collect data from\n  server = \"localhost:11300\"\n\n  ## List of tubes to gather stats about.\n  ## If no tubes specified then data gathered for each tube on server reported by list-tubes command\n  tubes = [\"notifications\"]\n```\n\n## Metrics\n\nPlease see the [Beanstalk protocol doc][protocol] for a detailed explanation of\n`stats` and `stats-tube` server commands output.\n\n[protocol]: https://github.com/beanstalkd/beanstalkd/blob/master/doc/protocol.txt\n\n`beanstalkd_overview` – statistical information about the system as a whole\n\n- fields\n  - cmd_delete\n  - cmd_pause_tube\n  - current_jobs_buried\n  - current_jobs_delayed\n  - current_jobs_ready\n  - current_jobs_reserved\n  - current_jobs_urgent\n  - current_using\n  - current_waiting\n  - current_watching\n  - pause\n  - pause_time_left\n  - total_jobs\n- tags\n  - name\n  - server (address taken from config)\n\n`beanstalkd_tube` – statistical information about the specified tube\n\n- fields\n  - binlog_current_index\n  - binlog_max_size\n  - binlog_oldest_index\n  - binlog_records_migrated\n  - binlog_records_written\n  - cmd_bury\n  - cmd_delete\n  - cmd_ignore\n  - cmd_kick\n  - cmd_list_tube_used\n  - cmd_list_tubes\n  - cmd_list_tubes_watched\n  - cmd_pause_tube\n  - cmd_peek\n  - cmd_peek_buried\n  - cmd_peek_delayed\n  - cmd_peek_ready\n  - cmd_put\n  - cmd_release\n  - cmd_reserve\n  - cmd_reserve_with_timeout\n  - cmd_stats\n  - cmd_stats_job\n  - cmd_stats_tube\n  - cmd_touch\n  - cmd_use\n  - cmd_watch\n  - current_connections\n  - current_jobs_buried\n  - current_jobs_delayed\n  - current_jobs_ready\n  - current_jobs_reserved\n  - current_jobs_urgent\n  - current_producers\n  - current_tubes\n  - current_waiting\n  - current_workers\n  - job_timeouts\n  - max_job_size\n  - pid\n  - rusage_stime\n  - rusage_utime\n  - total_connections\n  - total_jobs\n  - uptime\n- tags\n  - hostname\n  - id\n  - server (address taken from config)\n  - version\n\n## Example Output\n\n```text\nbeanstalkd_overview,host=server.local,hostname=a2ab22ed12e0,id=232485800aa11b24,server=localhost:11300,version=1.10 cmd_stats_tube=29482i,current_jobs_delayed=0i,current_jobs_urgent=6i,cmd_kick=0i,cmd_stats=7378i,cmd_stats_job=0i,current_waiting=0i,max_job_size=65535i,pid=6i,cmd_bury=0i,cmd_reserve_with_timeout=0i,cmd_touch=0i,current_connections=1i,current_jobs_ready=6i,current_producers=0i,cmd_delete=0i,cmd_list_tubes=7369i,cmd_peek_ready=0i,cmd_put=6i,cmd_use=3i,cmd_watch=0i,current_jobs_reserved=0i,rusage_stime=6.07,cmd_list_tubes_watched=0i,cmd_pause_tube=0i,total_jobs=6i,binlog_records_migrated=0i,cmd_list_tube_used=0i,cmd_peek_delayed=0i,cmd_release=0i,current_jobs_buried=0i,job_timeouts=0i,binlog_current_index=0i,binlog_max_size=10485760i,total_connections=7378i,cmd_peek_buried=0i,cmd_reserve=0i,current_tubes=4i,binlog_records_written=0i,cmd_peek=0i,rusage_utime=1.13,uptime=7099i,binlog_oldest_index=0i,current_workers=0i,cmd_ignore=0i 1528801650000000000\nbeanstalkd_tube,host=server.local,name=notifications,server=localhost:11300 pause_time_left=0i,current_jobs_buried=0i,current_jobs_delayed=0i,current_jobs_reserved=0i,current_using=0i,current_waiting=0i,pause=0i,total_jobs=3i,cmd_delete=0i,cmd_pause_tube=0i,current_jobs_ready=3i,current_jobs_urgent=3i,current_watching=0i 1528801650000000000\n```\n"
  },
  {
    "path": "plugins/inputs/beanstalkd/beanstalkd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage beanstalkd\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/textproto\"\n\t\"sync\"\n\n\t\"go.yaml.in/yaml/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Beanstalkd struct {\n\tServer string   `toml:\"server\"`\n\tTubes  []string `toml:\"tubes\"`\n}\n\nfunc (*Beanstalkd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *Beanstalkd) Gather(acc telegraf.Accumulator) error {\n\tconnection, err := textproto.Dial(\"tcp\", b.Server)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer connection.Close()\n\n\ttubes := b.Tubes\n\tif len(tubes) == 0 {\n\t\terr = runQuery(connection, \"list-tubes\", &tubes)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\tgo func() {\n\t\terr := b.gatherServerStats(connection, acc)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t\twg.Done()\n\t}()\n\n\tfor _, tube := range tubes {\n\t\twg.Add(1)\n\t\tgo func(tube string) {\n\t\t\terr := b.gatherTubeStats(connection, tube, acc)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\twg.Done()\n\t\t}(tube)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (b *Beanstalkd) gatherServerStats(connection *textproto.Conn, acc telegraf.Accumulator) error {\n\tstats := new(statsResponse)\n\tif err := runQuery(connection, \"stats\", stats); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\"beanstalkd_overview\",\n\t\tmap[string]interface{}{\n\t\t\t\"binlog_current_index\":     stats.BinlogCurrentIndex,\n\t\t\t\"binlog_max_size\":          stats.BinlogMaxSize,\n\t\t\t\"binlog_oldest_index\":      stats.BinlogOldestIndex,\n\t\t\t\"binlog_records_migrated\":  stats.BinlogRecordsMigrated,\n\t\t\t\"binlog_records_written\":   stats.BinlogRecordsWritten,\n\t\t\t\"cmd_bury\":                 stats.CmdBury,\n\t\t\t\"cmd_delete\":               stats.CmdDelete,\n\t\t\t\"cmd_ignore\":               stats.CmdIgnore,\n\t\t\t\"cmd_kick\":                 stats.CmdKick,\n\t\t\t\"cmd_list_tube_used\":       stats.CmdListTubeUsed,\n\t\t\t\"cmd_list_tubes\":           stats.CmdListTubes,\n\t\t\t\"cmd_list_tubes_watched\":   stats.CmdListTubesWatched,\n\t\t\t\"cmd_pause_tube\":           stats.CmdPauseTube,\n\t\t\t\"cmd_peek\":                 stats.CmdPeek,\n\t\t\t\"cmd_peek_buried\":          stats.CmdPeekBuried,\n\t\t\t\"cmd_peek_delayed\":         stats.CmdPeekDelayed,\n\t\t\t\"cmd_peek_ready\":           stats.CmdPeekReady,\n\t\t\t\"cmd_put\":                  stats.CmdPut,\n\t\t\t\"cmd_release\":              stats.CmdRelease,\n\t\t\t\"cmd_reserve\":              stats.CmdReserve,\n\t\t\t\"cmd_reserve_with_timeout\": stats.CmdReserveWithTimeout,\n\t\t\t\"cmd_stats\":                stats.CmdStats,\n\t\t\t\"cmd_stats_job\":            stats.CmdStatsJob,\n\t\t\t\"cmd_stats_tube\":           stats.CmdStatsTube,\n\t\t\t\"cmd_touch\":                stats.CmdTouch,\n\t\t\t\"cmd_use\":                  stats.CmdUse,\n\t\t\t\"cmd_watch\":                stats.CmdWatch,\n\t\t\t\"current_connections\":      stats.CurrentConnections,\n\t\t\t\"current_jobs_buried\":      stats.CurrentJobsBuried,\n\t\t\t\"current_jobs_delayed\":     stats.CurrentJobsDelayed,\n\t\t\t\"current_jobs_ready\":       stats.CurrentJobsReady,\n\t\t\t\"current_jobs_reserved\":    stats.CurrentJobsReserved,\n\t\t\t\"current_jobs_urgent\":      stats.CurrentJobsUrgent,\n\t\t\t\"current_producers\":        stats.CurrentProducers,\n\t\t\t\"current_tubes\":            stats.CurrentTubes,\n\t\t\t\"current_waiting\":          stats.CurrentWaiting,\n\t\t\t\"current_workers\":          stats.CurrentWorkers,\n\t\t\t\"job_timeouts\":             stats.JobTimeouts,\n\t\t\t\"max_job_size\":             stats.MaxJobSize,\n\t\t\t\"pid\":                      stats.Pid,\n\t\t\t\"rusage_stime\":             stats.RusageStime,\n\t\t\t\"rusage_utime\":             stats.RusageUtime,\n\t\t\t\"total_connections\":        stats.TotalConnections,\n\t\t\t\"total_jobs\":               stats.TotalJobs,\n\t\t\t\"uptime\":                   stats.Uptime,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"hostname\": stats.Hostname,\n\t\t\t\"id\":       stats.ID,\n\t\t\t\"server\":   b.Server,\n\t\t\t\"version\":  stats.Version,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (b *Beanstalkd) gatherTubeStats(connection *textproto.Conn, tube string, acc telegraf.Accumulator) error {\n\tstats := new(statsTubeResponse)\n\tif err := runQuery(connection, \"stats-tube \"+tube, stats); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\"beanstalkd_tube\",\n\t\tmap[string]interface{}{\n\t\t\t\"cmd_delete\":            stats.CmdDelete,\n\t\t\t\"cmd_pause_tube\":        stats.CmdPauseTube,\n\t\t\t\"current_jobs_buried\":   stats.CurrentJobsBuried,\n\t\t\t\"current_jobs_delayed\":  stats.CurrentJobsDelayed,\n\t\t\t\"current_jobs_ready\":    stats.CurrentJobsReady,\n\t\t\t\"current_jobs_reserved\": stats.CurrentJobsReserved,\n\t\t\t\"current_jobs_urgent\":   stats.CurrentJobsUrgent,\n\t\t\t\"current_using\":         stats.CurrentUsing,\n\t\t\t\"current_waiting\":       stats.CurrentWaiting,\n\t\t\t\"current_watching\":      stats.CurrentWatching,\n\t\t\t\"pause\":                 stats.Pause,\n\t\t\t\"pause_time_left\":       stats.PauseTimeLeft,\n\t\t\t\"total_jobs\":            stats.TotalJobs,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"name\":   stats.Name,\n\t\t\t\"server\": b.Server,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc runQuery(connection *textproto.Conn, cmd string, result interface{}) error {\n\trequestID, err := connection.Cmd(\"%s\", cmd)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnection.StartResponse(requestID)\n\tdefer connection.EndResponse(requestID)\n\n\tstatus, err := connection.ReadLine()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsize := 0\n\tif _, err = fmt.Sscanf(status, \"OK %d\", &size); err != nil {\n\t\treturn err\n\t}\n\n\tbody := make([]byte, size+2)\n\tif _, err = io.ReadFull(connection.R, body); err != nil {\n\t\treturn err\n\t}\n\n\treturn yaml.Unmarshal(body, result)\n}\n\nfunc init() {\n\tinputs.Add(\"beanstalkd\", func() telegraf.Input {\n\t\treturn &Beanstalkd{}\n\t})\n}\n\ntype statsResponse struct {\n\tBinlogCurrentIndex    int     `yaml:\"binlog-current-index\"`\n\tBinlogMaxSize         int     `yaml:\"binlog-max-size\"`\n\tBinlogOldestIndex     int     `yaml:\"binlog-oldest-index\"`\n\tBinlogRecordsMigrated int     `yaml:\"binlog-records-migrated\"`\n\tBinlogRecordsWritten  int     `yaml:\"binlog-records-written\"`\n\tCmdBury               int     `yaml:\"cmd-bury\"`\n\tCmdDelete             int     `yaml:\"cmd-delete\"`\n\tCmdIgnore             int     `yaml:\"cmd-ignore\"`\n\tCmdKick               int     `yaml:\"cmd-kick\"`\n\tCmdListTubeUsed       int     `yaml:\"cmd-list-tube-used\"`\n\tCmdListTubes          int     `yaml:\"cmd-list-tubes\"`\n\tCmdListTubesWatched   int     `yaml:\"cmd-list-tubes-watched\"`\n\tCmdPauseTube          int     `yaml:\"cmd-pause-tube\"`\n\tCmdPeek               int     `yaml:\"cmd-peek\"`\n\tCmdPeekBuried         int     `yaml:\"cmd-peek-buried\"`\n\tCmdPeekDelayed        int     `yaml:\"cmd-peek-delayed\"`\n\tCmdPeekReady          int     `yaml:\"cmd-peek-ready\"`\n\tCmdPut                int     `yaml:\"cmd-put\"`\n\tCmdRelease            int     `yaml:\"cmd-release\"`\n\tCmdReserve            int     `yaml:\"cmd-reserve\"`\n\tCmdReserveWithTimeout int     `yaml:\"cmd-reserve-with-timeout\"`\n\tCmdStats              int     `yaml:\"cmd-stats\"`\n\tCmdStatsJob           int     `yaml:\"cmd-stats-job\"`\n\tCmdStatsTube          int     `yaml:\"cmd-stats-tube\"`\n\tCmdTouch              int     `yaml:\"cmd-touch\"`\n\tCmdUse                int     `yaml:\"cmd-use\"`\n\tCmdWatch              int     `yaml:\"cmd-watch\"`\n\tCurrentConnections    int     `yaml:\"current-connections\"`\n\tCurrentJobsBuried     int     `yaml:\"current-jobs-buried\"`\n\tCurrentJobsDelayed    int     `yaml:\"current-jobs-delayed\"`\n\tCurrentJobsReady      int     `yaml:\"current-jobs-ready\"`\n\tCurrentJobsReserved   int     `yaml:\"current-jobs-reserved\"`\n\tCurrentJobsUrgent     int     `yaml:\"current-jobs-urgent\"`\n\tCurrentProducers      int     `yaml:\"current-producers\"`\n\tCurrentTubes          int     `yaml:\"current-tubes\"`\n\tCurrentWaiting        int     `yaml:\"current-waiting\"`\n\tCurrentWorkers        int     `yaml:\"current-workers\"`\n\tHostname              string  `yaml:\"hostname\"`\n\tID                    string  `yaml:\"id\"`\n\tJobTimeouts           int     `yaml:\"job-timeouts\"`\n\tMaxJobSize            int     `yaml:\"max-job-size\"`\n\tPid                   int     `yaml:\"pid\"`\n\tRusageStime           float64 `yaml:\"rusage-stime\"`\n\tRusageUtime           float64 `yaml:\"rusage-utime\"`\n\tTotalConnections      int     `yaml:\"total-connections\"`\n\tTotalJobs             int     `yaml:\"total-jobs\"`\n\tUptime                int     `yaml:\"uptime\"`\n\tVersion               string  `yaml:\"version\"`\n}\n\ntype statsTubeResponse struct {\n\tCmdDelete           int    `yaml:\"cmd-delete\"`\n\tCmdPauseTube        int    `yaml:\"cmd-pause-tube\"`\n\tCurrentJobsBuried   int    `yaml:\"current-jobs-buried\"`\n\tCurrentJobsDelayed  int    `yaml:\"current-jobs-delayed\"`\n\tCurrentJobsReady    int    `yaml:\"current-jobs-ready\"`\n\tCurrentJobsReserved int    `yaml:\"current-jobs-reserved\"`\n\tCurrentJobsUrgent   int    `yaml:\"current-jobs-urgent\"`\n\tCurrentUsing        int    `yaml:\"current-using\"`\n\tCurrentWaiting      int    `yaml:\"current-waiting\"`\n\tCurrentWatching     int    `yaml:\"current-watching\"`\n\tName                string `yaml:\"name\"`\n\tPause               int    `yaml:\"pause\"`\n\tPauseTimeLeft       int    `yaml:\"pause-time-left\"`\n\tTotalJobs           int    `yaml:\"total-jobs\"`\n}\n"
  },
  {
    "path": "plugins/inputs/beanstalkd/beanstalkd_test.go",
    "content": "package beanstalkd_test\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"net/textproto\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/beanstalkd\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestBeanstalkd(t *testing.T) {\n\ttype tubeStats struct {\n\t\tname   string\n\t\tfields map[string]interface{}\n\t}\n\n\ttests := []struct {\n\t\tname             string\n\t\ttubesConfig      []string\n\t\texpectedTubes    []tubeStats\n\t\tnotExpectedTubes []tubeStats\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\tname: \"All tubes stats\",\n\t\t\texpectedTubes: []tubeStats{\n\t\t\t\t{name: \"default\", fields: defaultTubeFields},\n\t\t\t\t{name: \"test\", fields: testTubeFields},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Specified tubes stats\",\n\t\t\ttubesConfig: []string{\"test\"},\n\t\t\texpectedTubes: []tubeStats{\n\t\t\t\t{name: \"test\", fields: testTubeFields},\n\t\t\t},\n\t\t\tnotExpectedTubes: []tubeStats{\n\t\t\t\t{name: \"default\", fields: defaultTubeFields},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Unknown tube stats\",\n\t\t\ttubesConfig: []string{\"unknown\"},\n\t\t\tnotExpectedTubes: []tubeStats{\n\t\t\t\t{name: \"default\", fields: defaultTubeFields},\n\t\t\t\t{name: \"test\", fields: testTubeFields},\n\t\t\t},\n\t\t\texpectedError: \"input does not match format\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tserver, err := startTestServer(t)\n\t\t\trequire.NoError(t, err, \"Unable to create test server\")\n\t\t\tdefer server.Close()\n\n\t\t\tserverAddress := server.Addr().String()\n\t\t\tplugin := beanstalkd.Beanstalkd{\n\t\t\t\tServer: serverAddress,\n\t\t\t\tTubes:  test.tubesConfig,\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr = acc.GatherError(plugin.Gather)\n\t\t\tif test.expectedError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Equal(t, test.expectedError, err.Error())\n\t\t\t}\n\t\t\tacc.AssertContainsTaggedFields(t, \"beanstalkd_overview\",\n\t\t\t\toverviewFields,\n\t\t\t\tgetOverviewTags(serverAddress),\n\t\t\t)\n\n\t\t\tfor _, expectedTube := range test.expectedTubes {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"beanstalkd_tube\",\n\t\t\t\t\texpectedTube.fields,\n\t\t\t\t\tgetTubeTags(serverAddress, expectedTube.name),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tfor _, notExpectedTube := range test.notExpectedTubes {\n\t\t\t\tacc.AssertDoesNotContainsTaggedFields(t, \"beanstalkd_tube\",\n\t\t\t\t\tnotExpectedTube.fields,\n\t\t\t\t\tgetTubeTags(serverAddress, notExpectedTube.name),\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc startTestServer(t *testing.T) (net.Listener, error) {\n\tserver, err := net.Listen(\"tcp\", \"localhost:0\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgo func() {\n\t\tdefer server.Close()\n\n\t\tconnection, err := server.Accept()\n\t\tif err != nil {\n\t\t\tt.Log(\"Test server: failed to accept connection. Error: \", err)\n\t\t\treturn\n\t\t}\n\n\t\ttp := textproto.NewConn(connection)\n\t\tdefer tp.Close()\n\n\t\tsendSuccessResponse := func(body string) error {\n\t\t\treturn tp.PrintfLine(\"OK %d\\r\\n%s\", len(body), body)\n\t\t}\n\n\t\tfor {\n\t\t\tcmd, err := tp.ReadLine()\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\treturn\n\t\t\t} else if err != nil {\n\t\t\t\tt.Log(\"Test server: failed read command. Error: \", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch cmd {\n\t\t\tcase \"list-tubes\":\n\t\t\t\tif err := sendSuccessResponse(listTubesResponse); err != nil {\n\t\t\t\t\tt.Logf(\"sending response %q failed: %v\", listTubesResponse, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase \"stats\":\n\t\t\t\tif err := sendSuccessResponse(statsResponse); err != nil {\n\t\t\t\t\tt.Logf(\"sending response %q failed: %v\", statsResponse, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase \"stats-tube default\":\n\t\t\t\tif err := sendSuccessResponse(statsTubeDefaultResponse); err != nil {\n\t\t\t\t\tt.Logf(\"sending response %q failed: %v\", statsTubeDefaultResponse, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase \"stats-tube test\":\n\t\t\t\tif err := sendSuccessResponse(statsTubeTestResponse); err != nil {\n\t\t\t\t\tt.Logf(\"sending response %q failed: %v\", statsTubeTestResponse, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase \"stats-tube unknown\":\n\t\t\t\tif err := tp.PrintfLine(\"NOT_FOUND\"); err != nil {\n\t\t\t\t\tt.Logf(\"sending response %q failed: %v\", \"NOT_FOUND\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tt.Log(\"Test server: unknown command\")\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn server, nil\n}\n\nconst (\n\tlistTubesResponse = `---\n- default\n- test\n`\n\tstatsResponse = `---\ncurrent-jobs-urgent: 5\ncurrent-jobs-ready: 5\ncurrent-jobs-reserved: 0\ncurrent-jobs-delayed: 1\ncurrent-jobs-buried: 0\ncmd-put: 6\ncmd-peek: 0\ncmd-peek-ready: 1\ncmd-peek-delayed: 0\ncmd-peek-buried: 0\ncmd-reserve: 0\ncmd-reserve-with-timeout: 1\ncmd-delete: 1\ncmd-release: 0\ncmd-use: 2\ncmd-watch: 0\ncmd-ignore: 0\ncmd-bury: 1\ncmd-kick: 1\ncmd-touch: 0\ncmd-stats: 1\ncmd-stats-job: 0\ncmd-stats-tube: 2\ncmd-list-tubes: 1\ncmd-list-tube-used: 0\ncmd-list-tubes-watched: 0\ncmd-pause-tube: 0\njob-timeouts: 0\ntotal-jobs: 6\nmax-job-size: 65535\ncurrent-tubes: 2\ncurrent-connections: 2\ncurrent-producers: 1\ncurrent-workers: 1\ncurrent-waiting: 0\ntotal-connections: 2\npid: 6\nversion: 1.10\nrusage-utime: 0.000000\nrusage-stime: 0.000000\nuptime: 20\nbinlog-oldest-index: 0\nbinlog-current-index: 0\nbinlog-records-migrated: 0\nbinlog-records-written: 0\nbinlog-max-size: 10485760\nid: bba7546657efdd4c\nhostname: 2873efd3e88c\n`\n\tstatsTubeDefaultResponse = `---\nname: default\ncurrent-jobs-urgent: 0\ncurrent-jobs-ready: 0\ncurrent-jobs-reserved: 0\ncurrent-jobs-delayed: 0\ncurrent-jobs-buried: 0\ntotal-jobs: 0\ncurrent-using: 2\ncurrent-watching: 2\ncurrent-waiting: 0\ncmd-delete: 0\ncmd-pause-tube: 0\npause: 0\npause-time-left: 0\n`\n\tstatsTubeTestResponse = `---\nname: test\ncurrent-jobs-urgent: 5\ncurrent-jobs-ready: 5\ncurrent-jobs-reserved: 0\ncurrent-jobs-delayed: 1\ncurrent-jobs-buried: 0\ntotal-jobs: 6\ncurrent-using: 0\ncurrent-watching: 0\ncurrent-waiting: 0\ncmd-delete: 0\ncmd-pause-tube: 0\npause: 0\npause-time-left: 0\n`\n)\n\nvar (\n\t// Default tube without stats\n\tdefaultTubeFields = map[string]interface{}{\n\t\t\"cmd_delete\":            0,\n\t\t\"cmd_pause_tube\":        0,\n\t\t\"current_jobs_buried\":   0,\n\t\t\"current_jobs_delayed\":  0,\n\t\t\"current_jobs_ready\":    0,\n\t\t\"current_jobs_reserved\": 0,\n\t\t\"current_jobs_urgent\":   0,\n\t\t\"current_using\":         2,\n\t\t\"current_waiting\":       0,\n\t\t\"current_watching\":      2,\n\t\t\"pause\":                 0,\n\t\t\"pause_time_left\":       0,\n\t\t\"total_jobs\":            0,\n\t}\n\t// Test tube with stats\n\ttestTubeFields = map[string]interface{}{\n\t\t\"cmd_delete\":            0,\n\t\t\"cmd_pause_tube\":        0,\n\t\t\"current_jobs_buried\":   0,\n\t\t\"current_jobs_delayed\":  1,\n\t\t\"current_jobs_ready\":    5,\n\t\t\"current_jobs_reserved\": 0,\n\t\t\"current_jobs_urgent\":   5,\n\t\t\"current_using\":         0,\n\t\t\"current_waiting\":       0,\n\t\t\"current_watching\":      0,\n\t\t\"pause\":                 0,\n\t\t\"pause_time_left\":       0,\n\t\t\"total_jobs\":            6,\n\t}\n\t// Server stats\n\toverviewFields = map[string]interface{}{\n\t\t\"binlog_current_index\":     0,\n\t\t\"binlog_max_size\":          10485760,\n\t\t\"binlog_oldest_index\":      0,\n\t\t\"binlog_records_migrated\":  0,\n\t\t\"binlog_records_written\":   0,\n\t\t\"cmd_bury\":                 1,\n\t\t\"cmd_delete\":               1,\n\t\t\"cmd_ignore\":               0,\n\t\t\"cmd_kick\":                 1,\n\t\t\"cmd_list_tube_used\":       0,\n\t\t\"cmd_list_tubes\":           1,\n\t\t\"cmd_list_tubes_watched\":   0,\n\t\t\"cmd_pause_tube\":           0,\n\t\t\"cmd_peek\":                 0,\n\t\t\"cmd_peek_buried\":          0,\n\t\t\"cmd_peek_delayed\":         0,\n\t\t\"cmd_peek_ready\":           1,\n\t\t\"cmd_put\":                  6,\n\t\t\"cmd_release\":              0,\n\t\t\"cmd_reserve\":              0,\n\t\t\"cmd_reserve_with_timeout\": 1,\n\t\t\"cmd_stats\":                1,\n\t\t\"cmd_stats_job\":            0,\n\t\t\"cmd_stats_tube\":           2,\n\t\t\"cmd_touch\":                0,\n\t\t\"cmd_use\":                  2,\n\t\t\"cmd_watch\":                0,\n\t\t\"current_connections\":      2,\n\t\t\"current_jobs_buried\":      0,\n\t\t\"current_jobs_delayed\":     1,\n\t\t\"current_jobs_ready\":       5,\n\t\t\"current_jobs_reserved\":    0,\n\t\t\"current_jobs_urgent\":      5,\n\t\t\"current_producers\":        1,\n\t\t\"current_tubes\":            2,\n\t\t\"current_waiting\":          0,\n\t\t\"current_workers\":          1,\n\t\t\"job_timeouts\":             0,\n\t\t\"max_job_size\":             65535,\n\t\t\"pid\":                      6,\n\t\t\"rusage_stime\":             0.0,\n\t\t\"rusage_utime\":             0.0,\n\t\t\"total_connections\":        2,\n\t\t\"total_jobs\":               6,\n\t\t\"uptime\":                   20,\n\t}\n)\n\nfunc getOverviewTags(server string) map[string]string {\n\treturn map[string]string{\n\t\t\"hostname\": \"2873efd3e88c\",\n\t\t\"id\":       \"bba7546657efdd4c\",\n\t\t\"server\":   server,\n\t\t\"version\":  \"1.10\",\n\t}\n}\n\nfunc getTubeTags(server, tube string) map[string]string {\n\treturn map[string]string{\n\t\t\"name\":   tube,\n\t\t\"server\": server,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/beanstalkd/sample.conf",
    "content": "# Collects Beanstalkd server and tubes stats\n[[inputs.beanstalkd]]\n  ## Server to collect data from\n  server = \"localhost:11300\"\n\n  ## List of tubes to gather stats about.\n  ## If no tubes specified then data gathered for each tube on server reported by list-tubes command\n  tubes = [\"notifications\"]\n"
  },
  {
    "path": "plugins/inputs/beat/README.md",
    "content": "# Beat Input Plugin\n\nThis plugin will collect metrics from a [Beats][beats] instances. It is known\nto work with Filebeat and Kafkabeat.\n\n⭐ Telegraf v1.18.0\n🏷️ applications\n💻 all\n\n[beats]: https://www.elastic.co/beats\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics exposed by Beat\n[[inputs.beat]]\n  ## An URL from which to read Beat-formatted JSON\n  ## Default is \"http://127.0.0.1:5066\".\n  url = \"http://127.0.0.1:5066\"\n\n  ## Enable collection of the listed stats\n  ## An empty list means collect all. Available options are currently\n  ## \"beat\", \"libbeat\", \"system\" and \"filebeat\".\n  # include = [\"beat\", \"libbeat\", \"filebeat\"]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Override HTTP \"Host\" header\n  # host_header = \"logstash.example.com\"\n\n  ## Timeout for HTTP requests\n  # timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- **beat**\n  - Fields:\n    - cpu_system_ticks\n    - cpu_system_time_ms\n    - cpu_total_ticks\n    - cpu_total_time_ms\n    - cpu_total_value\n    - cpu_user_ticks\n    - cpu_user_time_ms\n    - info_uptime_ms\n    - memstats_gc_next\n    - memstats_memory_alloc\n    - memstats_memory_total\n    - memstats_rss\n  - Tags:\n    - beat_beat\n    - beat_host\n    - beat_id\n    - beat_name\n    - beat_version\n\n- **beat_filebeat**\n  - Fields:\n    - events_active\n    - events_added\n    - events_done\n    - harvester_closed\n    - harvester_open_files\n    - harvester_running\n    - harvester_skipped\n    - harvester_started\n    - input_log_files_renamed\n    - input_log_files_truncated\n  - Tags:\n    - beat_beat\n    - beat_host\n    - beat_id\n    - beat_name\n    - beat_version\n\n- **beat_libbeat**\n  - Fields:\n    - config_module_running\n    - config_module_starts\n    - config_module_stops\n    - config_reloads\n    - output_events_acked\n    - output_events_active\n    - output_events_batches\n    - output_events_dropped\n    - output_events_duplicates\n    - output_events_failed\n    - output_events_total\n    - output_type\n    - output_read_bytes\n    - output_read_errors\n    - output_write_bytes\n    - output_write_errors\n    - outputs_kafka_bytes_read\n    - outputs_kafka_bytes_write\n    - pipeline_clients\n    - pipeline_events_active\n    - pipeline_events_dropped\n    - pipeline_events_failed\n    - pipeline_events_filtered\n    - pipeline_events_published\n    - pipeline_events_retry\n    - pipeline_events_total\n    - pipeline_queue_acked\n  - Tags:\n    - beat_beat\n    - beat_host\n    - beat_id\n    - beat_name\n    - beat_version\n\n- **beat_system**\n  - Field:\n    - cpu_cores\n    - load_1\n    - load_15\n    - load_5\n    - load_norm_1\n    - load_norm_15\n    - load_norm_5\n  - Tags:\n    - beat_beat\n    - beat_host\n    - beat_id\n    - beat_name\n    - beat_version\n\n## Example Output\n\n```text\nbeat,beat_beat=filebeat,beat_host=node-6,beat_id=9c1c8697-acb4-4df0-987d-28197814f788,beat_name=node-6-test,beat_version=6.4.2,host=node-6 cpu_system_ticks=656750,cpu_system_time_ms=656750,cpu_total_ticks=5461190,cpu_total_time_ms=5461198,cpu_total_value=5461190,cpu_user_ticks=4804440,cpu_user_time_ms=4804448,info_uptime_ms=342634196,memstats_gc_next=20199584,memstats_memory_alloc=12547424,memstats_memory_total=486296424792,memstats_rss=72552448 1540316047000000000\nbeat_libbeat,beat_beat=filebeat,beat_host=node-6,beat_id=9c1c8697-acb4-4df0-987d-28197814f788,beat_name=node-6-test,beat_version=6.4.2,host=node-6 config_module_running=0,config_module_starts=0,config_module_stops=0,config_reloads=0,output_events_acked=192404,output_events_active=0,output_events_batches=1607,output_events_dropped=0,output_events_duplicates=0,output_events_failed=0,output_events_total=192404,output_read_bytes=0,output_read_errors=0,output_write_bytes=0,output_write_errors=0,outputs_kafka_bytes_read=1118528,outputs_kafka_bytes_write=48002014,pipeline_clients=1,pipeline_events_active=0,pipeline_events_dropped=0,pipeline_events_failed=0,pipeline_events_filtered=11496,pipeline_events_published=192404,pipeline_events_retry=14,pipeline_events_total=203900,pipeline_queue_acked=192404 1540316047000000000\nbeat_system,beat_beat=filebeat,beat_host=node-6,beat_id=9c1c8697-acb4-4df0-987d-28197814f788,beat_name=node-6-test,beat_version=6.4.2,host=node-6 cpu_cores=32,load_1=46.08,load_15=49.82,load_5=47.88,load_norm_1=1.44,load_norm_15=1.5569,load_norm_5=1.4963 1540316047000000000\nbeat_filebeat,beat_beat=filebeat,beat_host=node-6,beat_id=9c1c8697-acb4-4df0-987d-28197814f788,beat_name=node-6-test,beat_version=6.4.2,host=node-6 events_active=0,events_added=3223,events_done=3223,harvester_closed=0,harvester_open_files=0,harvester_running=0,harvester_skipped=0,harvester_started=0,input_log_files_renamed=0,input_log_files_truncated=0 1540320286000000000\n```\n"
  },
  {
    "path": "plugins/inputs/beat/beat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage beat\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tsuffixInfo  = \"/\"\n\tsuffixStats = \"/stats\"\n)\n\ntype Beat struct {\n\tURL string `toml:\"url\"`\n\n\tIncludes []string `toml:\"include\"`\n\n\tUsername   string            `toml:\"username\"`\n\tPassword   string            `toml:\"password\"`\n\tMethod     string            `toml:\"method\"`\n\tHeaders    map[string]string `toml:\"headers\"`\n\tHostHeader string            `toml:\"host_header\"`\n\tTimeout    config.Duration   `toml:\"timeout\"`\n\n\ttls.ClientConfig\n\tclient *http.Client\n}\n\ntype info struct {\n\tBeat     string `json:\"beat\"`\n\tHostname string `json:\"hostname\"`\n\tName     string `json:\"name\"`\n\tUUID     string `json:\"uuid\"`\n\tVersion  string `json:\"version\"`\n}\n\ntype stats struct {\n\tBeat     map[string]interface{} `json:\"beat\"`\n\tFileBeat interface{}            `json:\"filebeat\"`\n\tLibBeat  interface{}            `json:\"libbeat\"`\n\tSystem   interface{}            `json:\"system\"`\n}\n\nfunc (*Beat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (beat *Beat) Init() error {\n\tavailableStats := []string{\"beat\", \"libbeat\", \"system\", \"filebeat\"}\n\n\tvar err error\n\tbeat.client, err = beat.createHTTPClient()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = choice.CheckSlice(beat.Includes, availableStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (beat *Beat) Gather(accumulator telegraf.Accumulator) error {\n\tbeatStats := &stats{}\n\tbeatInfo := &info{}\n\n\tinfoURL, err := url.Parse(beat.URL + suffixInfo)\n\tif err != nil {\n\t\treturn err\n\t}\n\tstatsURL, err := url.Parse(beat.URL + suffixStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = beat.gatherJSONData(infoURL.String(), beatInfo)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttags := map[string]string{\n\t\t\"beat_beat\":    beatInfo.Beat,\n\t\t\"beat_id\":      beatInfo.UUID,\n\t\t\"beat_name\":    beatInfo.Name,\n\t\t\"beat_host\":    beatInfo.Hostname,\n\t\t\"beat_version\": beatInfo.Version,\n\t}\n\n\terr = beat.gatherJSONData(statsURL.String(), beatStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, name := range beat.Includes {\n\t\tvar stats interface{}\n\t\tvar metric string\n\n\t\tswitch name {\n\t\tcase \"beat\":\n\t\t\tstats = beatStats.Beat\n\t\t\tmetric = \"beat\"\n\t\tcase \"filebeat\":\n\t\t\tstats = beatStats.FileBeat\n\t\t\tmetric = \"beat_filebeat\"\n\t\tcase \"system\":\n\t\t\tstats = beatStats.System\n\t\t\tmetric = \"beat_system\"\n\t\tcase \"libbeat\":\n\t\t\tstats = beatStats.LibBeat\n\t\t\tmetric = \"beat_libbeat\"\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown stats-type %q\", name)\n\t\t}\n\t\tflattener := parsers_json.JSONFlattener{}\n\t\terr := flattener.FullFlattenJSON(\"\", stats, true, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\taccumulator.AddFields(metric, flattener.Fields, tags)\n\t}\n\n\treturn nil\n}\n\n// createHTTPClient create a clients to access API\nfunc (beat *Beat) createHTTPClient() (*http.Client, error) {\n\ttlsConfig, err := beat.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t\tTimeout: time.Duration(beat.Timeout),\n\t}\n\n\treturn client, nil\n}\n\n// gatherJSONData query the data source and parse the response JSON\nfunc (beat *Beat) gatherJSONData(address string, value interface{}) error {\n\trequest, err := http.NewRequest(beat.Method, address, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif beat.Username != \"\" {\n\t\trequest.SetBasicAuth(beat.Username, beat.Password)\n\t}\n\tfor k, v := range beat.Headers {\n\t\trequest.Header.Add(k, v)\n\t}\n\tif beat.HostHeader != \"\" {\n\t\trequest.Host = beat.HostHeader\n\t}\n\n\tresponse, err := beat.client.Do(request)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer response.Body.Close()\n\n\treturn json.NewDecoder(response.Body).Decode(value)\n}\n\nfunc newBeat() *Beat {\n\treturn &Beat{\n\t\tURL:      \"http://127.0.0.1:5066\",\n\t\tIncludes: []string{\"beat\", \"libbeat\", \"filebeat\"},\n\t\tMethod:   \"GET\",\n\t\tHeaders:  make(map[string]string),\n\t\tTimeout:  config.Duration(time.Second * 5),\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"beat\", func() telegraf.Input {\n\t\treturn newBeat()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/beat/beat6_info.json",
    "content": "{\n  \"beat\": \"filebeat\",\n  \"hostname\": \"node-6\",\n  \"name\": \"node-6-test\",\n  \"uuid\": \"9c1c8697-acb4-4df0-987d-28197814f785\",\n  \"version\": \"6.4.2\"\n}\n"
  },
  {
    "path": "plugins/inputs/beat/beat6_stats.json",
    "content": "{\n  \"beat\": {\n    \"cpu\": {\n      \"system\": {\n        \"ticks\": 626970,\n        \"time\": {\n          \"ms\": 626972\n        }\n      },\n      \"total\": {\n        \"ticks\": 5215010,\n        \"time\": {\n          \"ms\": 5215018\n        },\n        \"value\": 5215010\n      },\n      \"user\": {\n        \"ticks\": 4588040,\n        \"time\": {\n          \"ms\": 4588046\n        }\n      }\n    },\n    \"info\": {\n      \"ephemeral_id\": \"809e3b63-4fa0-4f74-822a-8e3c08298336\",\n      \"uptime\": {\n        \"ms\": 327248661\n      }\n    },\n    \"memstats\": {\n      \"gc_next\": 20611808,\n      \"memory_alloc\": 12692544,\n      \"memory_total\": 462910102088,\n      \"rss\": 80273408\n    }\n  },\n  \"filebeat\": {\n    \"events\": {\n      \"active\": 0,\n      \"added\": 182990,\n      \"done\": 182990\n    },\n    \"harvester\": {\n      \"closed\": 2222,\n      \"open_files\": 4,\n      \"running\": 4,\n      \"skipped\": 0,\n      \"started\": 2226\n    },\n    \"input\": {\n      \"log\": {\n        \"files\": {\n          \"renamed\": 0,\n          \"truncated\": 0\n        }\n      }\n    }\n  },\n  \"libbeat\": {\n    \"config\": {\n      \"module\": {\n        \"running\": 0,\n        \"starts\": 0,\n        \"stops\": 0\n      },\n      \"reloads\": 0\n    },\n    \"output\": {\n      \"events\": {\n        \"acked\": 172067,\n        \"active\": 0,\n        \"batches\": 1490,\n        \"dropped\": 0,\n        \"duplicates\": 0,\n        \"failed\": 0,\n        \"total\": 172067\n      },\n      \"read\": {\n        \"bytes\": 0,\n        \"errors\": 0\n      },\n      \"type\": \"kafka\",\n      \"write\": {\n        \"bytes\": 0,\n        \"errors\": 0\n      }\n    },\n    \"outputs\": {\n      \"kafka\": {\n        \"bytes_read\": 1048670,\n        \"bytes_write\": 43136887\n      }\n    },\n    \"pipeline\": {\n      \"clients\": 1,\n      \"events\": {\n        \"active\": 0,\n        \"dropped\": 0,\n        \"failed\": 0,\n        \"filtered\": 10923,\n        \"published\": 172067,\n        \"retry\": 14,\n        \"total\": 182990\n      },\n      \"queue\": {\n        \"acked\": 172067\n      }\n    }\n  },\n  \"registrar\": {\n    \"states\": {\n      \"cleanup\": 3446,\n      \"current\": 16409,\n      \"update\": 182990\n    },\n    \"writes\": {\n      \"fail\": 0,\n      \"success\": 11718,\n      \"total\": 11718\n    }\n  },\n  \"system\": {\n    \"cpu\": {\n      \"cores\": 32\n    },\n    \"load\": {\n      \"1\": 32.49,\n      \"15\": 41.9,\n      \"5\": 40.16,\n      \"norm\": {\n        \"1\": 1.0153,\n        \"15\": 1.3094,\n        \"5\": 1.255\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/beat/beat_test.go",
    "content": "package beat\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_BeatStats(t *testing.T) {\n\tvar beat6StatsAccumulator testutil.Accumulator\n\tvar beatTest = newBeat()\n\t// System stats are disabled by default\n\tbeatTest.Includes = []string{\"beat\", \"libbeat\", \"system\", \"filebeat\"}\n\trequire.NoError(t, beatTest.Init())\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch request.URL.Path {\n\t\tcase suffixInfo:\n\t\t\tjsonFilePath = \"beat6_info.json\"\n\t\tcase suffixStats:\n\t\t\tjsonFilePath = \"beat6_stats.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request\")\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(beatTest.URL)\n\trequire.NoErrorf(t, err, \"can't parse URL %s\", beatTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoErrorf(t, err, \"can't listen for %s: %v\", requestURL, err)\n\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\trequire.NoError(t, beatTest.Gather(&beat6StatsAccumulator))\n\n\tbeat6StatsAccumulator.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"beat\",\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_system_ticks\":      float64(626970),\n\t\t\t\"cpu_system_time_ms\":    float64(626972),\n\t\t\t\"cpu_total_ticks\":       float64(5215010),\n\t\t\t\"cpu_total_time_ms\":     float64(5215018),\n\t\t\t\"cpu_total_value\":       float64(5215010),\n\t\t\t\"cpu_user_ticks\":        float64(4588040),\n\t\t\t\"cpu_user_time_ms\":      float64(4588046),\n\t\t\t\"info_uptime_ms\":        float64(327248661),\n\t\t\t\"info_ephemeral_id\":     \"809e3b63-4fa0-4f74-822a-8e3c08298336\",\n\t\t\t\"memstats_gc_next\":      float64(20611808),\n\t\t\t\"memstats_memory_alloc\": float64(12692544),\n\t\t\t\"memstats_memory_total\": float64(462910102088),\n\t\t\t\"memstats_rss\":          float64(80273408),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"beat_beat\":    string(\"filebeat\"),\n\t\t\t\"beat_host\":    string(\"node-6\"),\n\t\t\t\"beat_id\":      string(\"9c1c8697-acb4-4df0-987d-28197814f785\"),\n\t\t\t\"beat_name\":    string(\"node-6-test\"),\n\t\t\t\"beat_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n\tbeat6StatsAccumulator.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"beat_filebeat\",\n\t\tmap[string]interface{}{\n\t\t\t\"events_active\":             float64(0),\n\t\t\t\"events_added\":              float64(182990),\n\t\t\t\"events_done\":               float64(182990),\n\t\t\t\"harvester_closed\":          float64(2222),\n\t\t\t\"harvester_open_files\":      float64(4),\n\t\t\t\"harvester_running\":         float64(4),\n\t\t\t\"harvester_skipped\":         float64(0),\n\t\t\t\"harvester_started\":         float64(2226),\n\t\t\t\"input_log_files_renamed\":   float64(0),\n\t\t\t\"input_log_files_truncated\": float64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"beat_beat\":    string(\"filebeat\"),\n\t\t\t\"beat_host\":    string(\"node-6\"),\n\t\t\t\"beat_id\":      string(\"9c1c8697-acb4-4df0-987d-28197814f785\"),\n\t\t\t\"beat_name\":    string(\"node-6-test\"),\n\t\t\t\"beat_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n\tbeat6StatsAccumulator.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"beat_libbeat\",\n\t\tmap[string]interface{}{\n\t\t\t\"config_module_running\":     float64(0),\n\t\t\t\"config_module_starts\":      float64(0),\n\t\t\t\"config_module_stops\":       float64(0),\n\t\t\t\"config_reloads\":            float64(0),\n\t\t\t\"output_type\":               \"kafka\",\n\t\t\t\"output_events_acked\":       float64(172067),\n\t\t\t\"output_events_active\":      float64(0),\n\t\t\t\"output_events_batches\":     float64(1490),\n\t\t\t\"output_events_dropped\":     float64(0),\n\t\t\t\"output_events_duplicates\":  float64(0),\n\t\t\t\"output_events_failed\":      float64(0),\n\t\t\t\"output_events_total\":       float64(172067),\n\t\t\t\"output_read_bytes\":         float64(0),\n\t\t\t\"output_read_errors\":        float64(0),\n\t\t\t\"output_write_bytes\":        float64(0),\n\t\t\t\"output_write_errors\":       float64(0),\n\t\t\t\"outputs_kafka_bytes_read\":  float64(1048670),\n\t\t\t\"outputs_kafka_bytes_write\": float64(43136887),\n\t\t\t\"pipeline_clients\":          float64(1),\n\t\t\t\"pipeline_events_active\":    float64(0),\n\t\t\t\"pipeline_events_dropped\":   float64(0),\n\t\t\t\"pipeline_events_failed\":    float64(0),\n\t\t\t\"pipeline_events_filtered\":  float64(10923),\n\t\t\t\"pipeline_events_published\": float64(172067),\n\t\t\t\"pipeline_events_retry\":     float64(14),\n\t\t\t\"pipeline_events_total\":     float64(182990),\n\t\t\t\"pipeline_queue_acked\":      float64(172067),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"beat_beat\":    string(\"filebeat\"),\n\t\t\t\"beat_host\":    string(\"node-6\"),\n\t\t\t\"beat_id\":      string(\"9c1c8697-acb4-4df0-987d-28197814f785\"),\n\t\t\t\"beat_name\":    string(\"node-6-test\"),\n\t\t\t\"beat_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n\tbeat6StatsAccumulator.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"beat_system\",\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_cores\":    float64(32),\n\t\t\t\"load_1\":       float64(32.49),\n\t\t\t\"load_15\":      float64(41.9),\n\t\t\t\"load_5\":       float64(40.16),\n\t\t\t\"load_norm_1\":  float64(1.0153),\n\t\t\t\"load_norm_15\": float64(1.3094),\n\t\t\t\"load_norm_5\":  float64(1.255),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"beat_beat\":    string(\"filebeat\"),\n\t\t\t\"beat_host\":    string(\"node-6\"),\n\t\t\t\"beat_id\":      string(\"9c1c8697-acb4-4df0-987d-28197814f785\"),\n\t\t\t\"beat_name\":    string(\"node-6-test\"),\n\t\t\t\"beat_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n}\n\nfunc Test_BeatRequest(t *testing.T) {\n\tvar beat6StatsAccumulator testutil.Accumulator\n\tbeatTest := newBeat()\n\t// System stats are disabled by default\n\tbeatTest.Includes = []string{\"beat\", \"libbeat\", \"system\", \"filebeat\"}\n\trequire.NoError(t, beatTest.Init())\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch request.URL.Path {\n\t\tcase suffixInfo:\n\t\t\tjsonFilePath = \"beat6_info.json\"\n\t\tcase suffixStats:\n\t\t\tjsonFilePath = \"beat6_stats.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request\")\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\t\tif request.Host != \"beat.test.local\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"beat.test.local\", request.Host)\n\t\t\treturn\n\t\t}\n\t\tif request.Method != \"POST\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"POST\", request.Method)\n\t\t\treturn\n\t\t}\n\t\tif request.Header.Get(\"Authorization\") != \"Basic YWRtaW46UFdE\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"Basic YWRtaW46UFdE\", request.Header.Get(\"Authorization\"))\n\t\t\treturn\n\t\t}\n\t\tif request.Header.Get(\"X-Test\") != \"test-value\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"test-value\", request.Header.Get(\"X-Test\"))\n\t\t\treturn\n\t\t}\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\n\trequestURL, err := url.Parse(beatTest.URL)\n\trequire.NoErrorf(t, err, \"can't parse URL %s\", beatTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoErrorf(t, err, \"can't listen for %s: %v\", requestURL, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tbeatTest.Headers[\"X-Test\"] = \"test-value\"\n\tbeatTest.HostHeader = \"beat.test.local\"\n\tbeatTest.Method = \"POST\"\n\tbeatTest.Username = \"admin\"\n\tbeatTest.Password = \"PWD\"\n\n\trequire.NoError(t, beatTest.Gather(&beat6StatsAccumulator))\n}\n"
  },
  {
    "path": "plugins/inputs/beat/sample.conf",
    "content": "# Read metrics exposed by Beat\n[[inputs.beat]]\n  ## An URL from which to read Beat-formatted JSON\n  ## Default is \"http://127.0.0.1:5066\".\n  url = \"http://127.0.0.1:5066\"\n\n  ## Enable collection of the listed stats\n  ## An empty list means collect all. Available options are currently\n  ## \"beat\", \"libbeat\", \"system\" and \"filebeat\".\n  # include = [\"beat\", \"libbeat\", \"filebeat\"]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Override HTTP \"Host\" header\n  # host_header = \"logstash.example.com\"\n\n  ## Timeout for HTTP requests\n  # timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/bind/README.md",
    "content": "# BIND 9 Nameserver Input Plugin\n\nThis plugin collects metrics from [BIND 9 nameservers][bind] using the XML or\nJSON endpoint.\n\nFor _XML_, version 2 statistics (BIND 9.6 to 9.9) and version 3 statistics\n(BIND 9.9+) are supported. Version 3 statistics are the default and only XML\nformat in BIND 9.10+.\n\n> [!NOTE]\n> For BIND 9.9 to support version 3 statistics, it must be built with the\n> `--enable-newstats` compile flag, and the statistics must be specifically\n> requested via the correct URL.\n\nFor _JSON_, version 1 statistics (BIND 9.10+) are supported. As of writing, some\ndistros still do not enable support for JSON statistics in their BIND packages.\n\n⭐ Telegraf v1.11.0\n🏷️ server\n💻 all\n\n[bind]: https://www.isc.org/bind\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read BIND nameserver XML statistics\n[[inputs.bind]]\n  ## An array of BIND XML statistics URI to gather stats.\n  ## Default is \"http://localhost:8053/xml/v3\".\n  # urls = [\"http://localhost:8053/xml/v3\"]\n  # gather_memory_contexts = false\n  # gather_views = false\n\n  ## Report xml v3 counters as integers instead of unsigned for backward\n  ## compatibility. Set this to false as soon as possible!\n  ## Values are clipped if exceeding the integer range.\n  # report_counters_as_int = true\n\n  ## Timeout for http requests made by bind nameserver\n  # timeout = \"4s\"\n```\n\n- **urls** []string: List of BIND statistics channel URLs to collect from.\n  Do not include a trailing slash in the URL.\n  Default is `http://localhost:8053/xml/v3`.\n- **gather_memory_contexts** bool: Report per-context memory statistics.\n- **gather_views** bool: Report per-view query statistics.\n- **timeout** Timeout for http requests made by bind (example: \"4s\").\n\nThe following table summarizes the URL formats which should be used,\ndepending on your BIND version and configured statistics channel.\n\n| BIND Version | Statistics Format | Example URL                   |\n| ------------ | ----------------- | ----------------------------- |\n| 9.6 - 9.8    | XML v2            | `http://localhost:8053`         |\n| 9.9          | XML v2            | `http://localhost:8053/xml/v2`  |\n| 9.9+         | XML v3            | `http://localhost:8053/xml/v3`  |\n| 9.10+        | JSON v1           | `http://localhost:8053/json/v1` |\n\n### Configuration of BIND Daemon\n\nAdd the following to your named.conf if running Telegraf on the same host\nas the BIND daemon:\n\n```json\nstatistics-channels {\n    inet 127.0.0.1 port 8053;\n};\n```\n\nAlternatively, specify a wildcard address (e.g., 0.0.0.0) or specific\nIP address of an interface to configure the BIND daemon to listen on that\naddress. Note that you should secure the statistics channel with an ACL if\nit is publicly reachable. Consult the BIND Administrator Reference Manual\nfor more information.\n\n## Metrics\n\n- bind_counter\n  - tags:\n    - url\n    - source\n    - port\n    - type\n    - view (optional)\n  - fields\n    - dynamic, record type name (multiple)\n- bind_memory\n  - tags:\n    - url\n    - source\n    - port\n  - fields\n    - total_use\n    - in_use\n    - block_size\n    - context_size\n    - lost\n- bind_memory_context\n  - tags:\n    - url\n    - source\n    - port\n    - id\n    - name\n  - fields\n    - total\n    - in_use\n\n## Example Output\n\nHere is example output of this plugin:\n\n```text\nbind_memory,host=LAP,port=8053,source=localhost,url=localhost:8053 block_size=12058624i,context_size=4575056i,in_use=4113717i,lost=0i,total_use=16663252i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=opcode,url=localhost:8053 IQUERY=0i,NOTIFY=0i,QUERY=9i,STATUS=0i,UPDATE=0i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=rcode,url=localhost:8053 17=0i,18=0i,19=0i,20=0i,21=0i,22=0i,BADCOOKIE=0i,BADVERS=0i,FORMERR=0i,NOERROR=7i,NOTAUTH=0i,NOTIMP=0i,NOTZONE=0i,NXDOMAIN=0i,NXRRSET=0i,REFUSED=0i,RESERVED11=0i,RESERVED12=0i,RESERVED13=0i,RESERVED14=0i,RESERVED15=0i,SERVFAIL=2i,YXDOMAIN=0i,YXRRSET=0i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=qtype,url=localhost:8053 A=1i,ANY=1i,NS=1i,PTR=5i,SOA=1i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=nsstat,url=localhost:8053 AuthQryRej=0i,CookieBadSize=0i,CookieBadTime=0i,CookieIn=9i,CookieMatch=0i,CookieNew=9i,CookieNoMatch=0i,DNS64=0i,ECSOpt=0i,ExpireOpt=0i,KeyTagOpt=0i,NSIDOpt=0i,OtherOpt=0i,QryAuthAns=7i,QryBADCOOKIE=0i,QryDropped=0i,QryDuplicate=0i,QryFORMERR=0i,QryFailure=0i,QryNXDOMAIN=0i,QryNXRedir=0i,QryNXRedirRLookup=0i,QryNoauthAns=0i,QryNxrrset=1i,QryRecursion=2i,QryReferral=0i,QrySERVFAIL=2i,QrySuccess=6i,QryTCP=1i,QryUDP=8i,RPZRewrites=0i,RateDropped=0i,RateSlipped=0i,RecQryRej=0i,RecursClients=0i,ReqBadEDNSVer=0i,ReqBadSIG=0i,ReqEdns0=9i,ReqSIG0=0i,ReqTCP=1i,ReqTSIG=0i,Requestv4=9i,Requestv6=0i,RespEDNS0=9i,RespSIG0=0i,RespTSIG=0i,Response=9i,TruncatedResp=0i,UpdateBadPrereq=0i,UpdateDone=0i,UpdateFail=0i,UpdateFwdFail=0i,UpdateRej=0i,UpdateReqFwd=0i,UpdateRespFwd=0i,XfrRej=0i,XfrReqDone=0i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=zonestat,url=localhost:8053 AXFRReqv4=0i,AXFRReqv6=0i,IXFRReqv4=0i,IXFRReqv6=0i,NotifyInv4=0i,NotifyInv6=0i,NotifyOutv4=0i,NotifyOutv6=0i,NotifyRej=0i,SOAOutv4=0i,SOAOutv6=0i,XfrFail=0i,XfrSuccess=0i 1554276619000000000\nbind_counter,host=LAP,port=8053,source=localhost,type=sockstat,url=localhost:8053 FDWatchClose=0i,FDwatchConn=0i,FDwatchConnFail=0i,FDwatchRecvErr=0i,FDwatchSendErr=0i,FdwatchBindFail=0i,RawActive=1i,RawClose=0i,RawOpen=1i,RawOpenFail=0i,RawRecvErr=0i,TCP4Accept=6i,TCP4AcceptFail=0i,TCP4Active=9i,TCP4BindFail=0i,TCP4Close=5i,TCP4Conn=0i,TCP4ConnFail=0i,TCP4Open=8i,TCP4OpenFail=0i,TCP4RecvErr=0i,TCP4SendErr=0i,TCP6Accept=0i,TCP6AcceptFail=0i,TCP6Active=2i,TCP6BindFail=0i,TCP6Close=0i,TCP6Conn=0i,TCP6ConnFail=0i,TCP6Open=2i,TCP6OpenFail=0i,TCP6RecvErr=0i,TCP6SendErr=0i,UDP4Active=18i,UDP4BindFail=14i,UDP4Close=14i,UDP4Conn=0i,UDP4ConnFail=0i,UDP4Open=32i,UDP4OpenFail=0i,UDP4RecvErr=0i,UDP4SendErr=0i,UDP6Active=3i,UDP6BindFail=0i,UDP6Close=6i,UDP6Conn=0i,UDP6ConnFail=6i,UDP6Open=9i,UDP6OpenFail=0i,UDP6RecvErr=0i,UDP6SendErr=0i,UnixAccept=0i,UnixAcceptFail=0i,UnixActive=0i,UnixBindFail=0i,UnixClose=0i,UnixConn=0i,UnixConnFail=0i,UnixOpen=0i,UnixOpenFail=0i,UnixRecvErr=0i,UnixSendErr=0i 1554276619000000000\n```\n"
  },
  {
    "path": "plugins/inputs/bind/bind.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage bind\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Bind struct {\n\tUrls                 []string        `toml:\"urls\"`\n\tGatherMemoryContexts bool            `toml:\"gather_memory_contexts\"`\n\tGatherViews          bool            `toml:\"gather_views\"`\n\tTimeout              config.Duration `toml:\"timeout\"`\n\tCountersAsInt        bool            `toml:\"report_counters_as_int\"`\n\n\tclient http.Client\n}\n\nfunc (*Bind) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *Bind) Init() error {\n\tb.client = http.Client{\n\t\tTimeout: time.Duration(b.Timeout),\n\t}\n\n\treturn nil\n}\n\nfunc (b *Bind) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tif len(b.Urls) == 0 {\n\t\tb.Urls = []string{\"http://localhost:8053/xml/v3\"}\n\t}\n\n\tfor _, u := range b.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(b.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (b *Bind) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tswitch addr.Path {\n\tcase \"\":\n\t\t// BIND 9.6 - 9.8\n\t\treturn b.readStatsXMLv2(addr, acc)\n\tcase \"/json/v1\":\n\t\t// BIND 9.10+\n\t\treturn b.readStatsJSON(addr, acc)\n\tcase \"/xml/v2\":\n\t\t// BIND 9.9\n\t\treturn b.readStatsXMLv2(addr, acc)\n\tcase \"/xml/v3\":\n\t\t// BIND 9.9+\n\t\treturn b.readStatsXMLv3(addr, acc)\n\tdefault:\n\t\treturn fmt.Errorf(\"provided URL %s is ambiguous, please check plugin documentation for supported URL formats\",\n\t\t\taddr)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"bind\", func() telegraf.Input { return &Bind{CountersAsInt: true} })\n}\n"
  },
  {
    "path": "plugins/inputs/bind/bind_test.go",
    "content": "package bind\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestBindJsonStats(t *testing.T) {\n\tts := httptest.NewServer(http.FileServer(http.Dir(\"testdata\")))\n\turl := ts.Listener.Addr().String()\n\thost, port, err := net.SplitHostPort(url)\n\trequire.NoError(t, err)\n\tdefer ts.Close()\n\n\tb := Bind{\n\t\tUrls:                 []string{ts.URL + \"/json/v1\"},\n\t\tGatherMemoryContexts: true,\n\t\tGatherViews:          true,\n\t\tCountersAsInt:        true,\n\t\tclient: http.Client{\n\t\t\tTimeout: 4 * time.Second,\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(b.Gather)\n\n\trequire.NoError(t, err)\n\n\t// Use subtests for counters, since they are similar structure\n\ttype fieldSet struct {\n\t\tfieldKey   string\n\t\tfieldValue int64\n\t}\n\n\ttestCases := []struct {\n\t\tcounterType string\n\t\tvalues      []fieldSet\n\t}{\n\t\t{\n\t\t\t\"opcode\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"NOTIFY\", 0},\n\t\t\t\t{\"UPDATE\", 0},\n\t\t\t\t{\"IQUERY\", 0},\n\t\t\t\t{\"QUERY\", 13},\n\t\t\t\t{\"STATUS\", 0},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"rcode\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"NOERROR\", 1732},\n\t\t\t\t{\"FORMERR\", 0},\n\t\t\t\t{\"SERVFAIL\", 6},\n\t\t\t\t{\"NXDOMAIN\", 200},\n\t\t\t\t{\"NOTIMP\", 0},\n\t\t\t\t{\"REFUSED\", 6},\n\t\t\t\t{\"REFUSED\", 0},\n\t\t\t\t{\"YXDOMAIN\", 0},\n\t\t\t\t{\"YXRRSET\", 0},\n\t\t\t\t{\"NXRRSET\", 0},\n\t\t\t\t{\"NOTAUTH\", 0},\n\t\t\t\t{\"NOTZONE\", 0},\n\t\t\t\t{\"RESERVED11\", 0},\n\t\t\t\t{\"RESERVED12\", 0},\n\t\t\t\t{\"RESERVED13\", 0},\n\t\t\t\t{\"RESERVED14\", 0},\n\t\t\t\t{\"RESERVED15\", 0},\n\t\t\t\t{\"BADVERS\", 0},\n\t\t\t\t{\"17\", 0},\n\t\t\t\t{\"18\", 0},\n\t\t\t\t{\"19\", 0},\n\t\t\t\t{\"20\", 0},\n\t\t\t\t{\"21\", 0},\n\t\t\t\t{\"22\", 0},\n\t\t\t\t{\"BADCOOKIE\", 0},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"qtype\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"A\", 2},\n\t\t\t\t{\"AAAA\", 2},\n\t\t\t\t{\"PTR\", 7},\n\t\t\t\t{\"SRV\", 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"QrySuccess\", 6},\n\t\t\t\t{\"QryRecursion\", 12},\n\t\t\t\t{\"Requestv4\", 13},\n\t\t\t\t{\"QryNXDOMAIN\", 4},\n\t\t\t\t{\"QryAuthAns\", 1},\n\t\t\t\t{\"QryNxrrset\", 1},\n\t\t\t\t{\"QryNoauthAns\", 10},\n\t\t\t\t{\"QryUDP\", 13},\n\t\t\t\t{\"QryDuplicate\", 1},\n\t\t\t\t{\"QrySERVFAIL\", 1},\n\t\t\t\t{\"Response\", 12},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"sockstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"TCP4Open\", 118},\n\t\t\t\t{\"UDP6Close\", 112},\n\t\t\t\t{\"UDP4Close\", 333},\n\t\t\t\t{\"TCP4Close\", 119},\n\t\t\t\t{\"TCP6Active\", 2},\n\t\t\t\t{\"UDP4Active\", 2},\n\t\t\t\t{\"UDP4RecvErr\", 1},\n\t\t\t\t{\"UDP4Open\", 335},\n\t\t\t\t{\"TCP4Active\", 10},\n\t\t\t\t{\"RawActive\", 1},\n\t\t\t\t{\"UDP6ConnFail\", 112},\n\t\t\t\t{\"TCP4Conn\", 114},\n\t\t\t\t{\"UDP6Active\", 1},\n\t\t\t\t{\"UDP6Open\", 113},\n\t\t\t\t{\"UDP4Conn\", 333},\n\t\t\t\t{\"UDP6SendErr\", 112},\n\t\t\t\t{\"RawOpen\", 1},\n\t\t\t\t{\"TCP4Accept\", 6},\n\t\t\t\t{\"TCP6Open\", 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"zonestat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"NotifyOutv4\", 8},\n\t\t\t\t{\"NotifyInv4\", 5},\n\t\t\t\t{\"SOAOutv4\", 5},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.counterType, func(t *testing.T) {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"type\":   tc.counterType,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{}\n\n\t\t\tfor _, val := range tc.values {\n\t\t\t\tfields[val.fieldKey] = val.fieldValue\n\t\t\t}\n\n\t\t\tacc.AssertContainsTaggedFields(t, \"bind_counter\", fields, tags)\n\t\t})\n\t}\n\n\t// Subtest for memory stats\n\tt.Run(\"memory\", func(t *testing.T) {\n\t\ttags := map[string]string{\n\t\t\t\"url\":    url,\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"block_size\":   int64(13893632),\n\t\t\t\"context_size\": int64(3685480),\n\t\t\t\"in_use\":       int64(3064368),\n\t\t\t\"lost\":         int64(0),\n\t\t\t\"total_use\":    int64(18206566),\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"bind_memory\", fields, tags)\n\t})\n\n\t// Subtest for per-context memory stats\n\tt.Run(\"memory_context\", func(t *testing.T) {\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"total\"))\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"in_use\"))\n\t})\n}\n\nfunc TestBindXmlStatsV2(t *testing.T) {\n\tts := httptest.NewServer(http.FileServer(http.Dir(\"testdata\")))\n\turl := ts.Listener.Addr().String()\n\thost, port, err := net.SplitHostPort(url)\n\trequire.NoError(t, err)\n\tdefer ts.Close()\n\n\tb := Bind{\n\t\tUrls:                 []string{ts.URL + \"/xml/v2\"},\n\t\tGatherMemoryContexts: true,\n\t\tGatherViews:          true,\n\t\tCountersAsInt:        true,\n\t\tclient: http.Client{\n\t\t\tTimeout: 4 * time.Second,\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(b.Gather)\n\n\trequire.NoError(t, err)\n\n\t// Use subtests for counters, since they are similar structure\n\ttype fieldSet struct {\n\t\tfieldKey   string\n\t\tfieldValue int64\n\t}\n\n\ttestCases := []struct {\n\t\tcounterType string\n\t\tvalues      []fieldSet\n\t}{\n\t\t{\n\t\t\t\"opcode\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"UPDATE\", 238},\n\t\t\t\t{\"QUERY\", 102312374},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"qtype\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"ANY\", 7},\n\t\t\t\t{\"DNSKEY\", 452},\n\t\t\t\t{\"SSHFP\", 2987},\n\t\t\t\t{\"SOA\", 100415},\n\t\t\t\t{\"AAAA\", 37786321},\n\t\t\t\t{\"MX\", 441155},\n\t\t\t\t{\"IXFR\", 157},\n\t\t\t\t{\"CNAME\", 531},\n\t\t\t\t{\"NS\", 1999},\n\t\t\t\t{\"TXT\", 34628},\n\t\t\t\t{\"A\", 58951432},\n\t\t\t\t{\"SRV\", 741082},\n\t\t\t\t{\"PTR\", 4211487},\n\t\t\t\t{\"NAPTR\", 39137},\n\t\t\t\t{\"DS\", 584},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"XfrReqDone\", 157},\n\t\t\t\t{\"ReqEdns0\", 441758},\n\t\t\t\t{\"ReqTSIG\", 0},\n\t\t\t\t{\"UpdateRespFwd\", 0},\n\t\t\t\t{\"RespEDNS0\", 441748},\n\t\t\t\t{\"QryDropped\", 16},\n\t\t\t\t{\"RPZRewrites\", 0},\n\t\t\t\t{\"XfrRej\", 0},\n\t\t\t\t{\"RecQryRej\", 0},\n\t\t\t\t{\"QryNxrrset\", 24423133},\n\t\t\t\t{\"QryFORMERR\", 0},\n\t\t\t\t{\"ReqTCP\", 1548156},\n\t\t\t\t{\"UpdateDone\", 0},\n\t\t\t\t{\"QrySERVFAIL\", 14422},\n\t\t\t\t{\"QryRecursion\", 2104239},\n\t\t\t\t{\"Requestv4\", 102312611},\n\t\t\t\t{\"UpdateFwdFail\", 0},\n\t\t\t\t{\"QryReferral\", 3},\n\t\t\t\t{\"Response\", 102301560},\n\t\t\t\t{\"RespTSIG\", 0},\n\t\t\t\t{\"QrySuccess\", 63811668},\n\t\t\t\t{\"QryFailure\", 0},\n\t\t\t\t{\"RespSIG0\", 0},\n\t\t\t\t{\"ReqSIG0\", 0},\n\t\t\t\t{\"UpdateRej\", 238},\n\t\t\t\t{\"QryAuthAns\", 72180718},\n\t\t\t\t{\"UpdateFail\", 0},\n\t\t\t\t{\"QryDuplicate\", 10879},\n\t\t\t\t{\"RateDropped\", 0},\n\t\t\t\t{\"QryNoauthAns\", 30106182},\n\t\t\t\t{\"QryNXDOMAIN\", 14052096},\n\t\t\t\t{\"ReqBadSIG\", 0},\n\t\t\t\t{\"UpdateReqFwd\", 0},\n\t\t\t\t{\"RateSlipped\", 0},\n\t\t\t\t{\"TruncatedResp\", 3787},\n\t\t\t\t{\"Requestv6\", 1},\n\t\t\t\t{\"UpdateBadPrereq\", 0},\n\t\t\t\t{\"AuthQryRej\", 0},\n\t\t\t\t{\"ReqBadEDNSVer\", 0},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"sockstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"FdwatchBindFail\", 0},\n\t\t\t\t{\"UDP6Open\", 238269},\n\t\t\t\t{\"UDP6SendErr\", 238250},\n\t\t\t\t{\"TCP4ConnFail\", 0},\n\t\t\t\t{\"TCP4Conn\", 590},\n\t\t\t\t{\"TCP6AcceptFail\", 0},\n\t\t\t\t{\"UDP4SendErr\", 0},\n\t\t\t\t{\"FDwatchConn\", 0},\n\t\t\t\t{\"TCP4RecvErr\", 1},\n\t\t\t\t{\"TCP4OpenFail\", 0},\n\t\t\t\t{\"UDP4OpenFail\", 0},\n\t\t\t\t{\"UDP6OpenFail\", 0},\n\t\t\t\t{\"TCP4Close\", 1548268},\n\t\t\t\t{\"TCP6BindFail\", 0},\n\t\t\t\t{\"TCP4AcceptFail\", 0},\n\t\t\t\t{\"UnixConn\", 0},\n\t\t\t\t{\"UDP4Open\", 3765532},\n\t\t\t\t{\"TCP6Close\", 0},\n\t\t\t\t{\"FDwatchRecvErr\", 0},\n\t\t\t\t{\"UDP4Conn\", 3764828},\n\t\t\t\t{\"UnixConnFail\", 0},\n\t\t\t\t{\"TCP6Conn\", 0},\n\t\t\t\t{\"TCP6OpenFail\", 0},\n\t\t\t\t{\"TCP6SendErr\", 0},\n\t\t\t\t{\"TCP6RecvErr\", 0},\n\t\t\t\t{\"FDwatchSendErr\", 0},\n\t\t\t\t{\"UDP4RecvErr\", 1650},\n\t\t\t\t{\"UDP4ConnFail\", 0},\n\t\t\t\t{\"UDP6Close\", 238267},\n\t\t\t\t{\"FDWatchClose\", 0},\n\t\t\t\t{\"TCP4Accept\", 1547672},\n\t\t\t\t{\"UnixAccept\", 0},\n\t\t\t\t{\"TCP4Open\", 602},\n\t\t\t\t{\"UDP4BindFail\", 219},\n\t\t\t\t{\"UDP6ConnFail\", 238250},\n\t\t\t\t{\"UnixClose\", 0},\n\t\t\t\t{\"TCP4BindFail\", 0},\n\t\t\t\t{\"UnixOpenFail\", 0},\n\t\t\t\t{\"UDP6BindFail\", 16},\n\t\t\t\t{\"UnixOpen\", 0},\n\t\t\t\t{\"UnixAcceptFail\", 0},\n\t\t\t\t{\"UnixRecvErr\", 0},\n\t\t\t\t{\"UDP6RecvErr\", 0},\n\t\t\t\t{\"TCP6ConnFail\", 0},\n\t\t\t\t{\"FDwatchConnFail\", 0},\n\t\t\t\t{\"TCP4SendErr\", 0},\n\t\t\t\t{\"UDP4Close\", 3765528},\n\t\t\t\t{\"UnixSendErr\", 0},\n\t\t\t\t{\"TCP6Open\", 2},\n\t\t\t\t{\"UDP6Conn\", 1},\n\t\t\t\t{\"TCP6Accept\", 0},\n\t\t\t\t{\"UnixBindFail\", 0},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.counterType, func(t *testing.T) {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"type\":   tc.counterType,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t}\n\n\t\t\tfields := make(map[string]interface{}, len(tc.values))\n\t\t\tfor _, val := range tc.values {\n\t\t\t\tfields[val.fieldKey] = val.fieldValue\n\t\t\t}\n\n\t\t\tacc.AssertContainsTaggedFields(t, \"bind_counter\", fields, tags)\n\t\t})\n\t}\n\n\t// Subtest for memory stats\n\tt.Run(\"memory\", func(t *testing.T) {\n\t\ttags := map[string]string{\n\t\t\t\"url\":    url,\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"block_size\":   int64(77070336),\n\t\t\t\"context_size\": int64(6663840),\n\t\t\t\"in_use\":       int64(20772579),\n\t\t\t\"lost\":         int64(0),\n\t\t\t\"total_use\":    int64(81804609),\n\t\t}\n\n\t\tacc.AssertContainsTaggedFields(t, \"bind_memory\", fields, tags)\n\t})\n\n\t// Subtest for per-context memory stats\n\tt.Run(\"memory_context\", func(t *testing.T) {\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"total\"))\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"in_use\"))\n\t})\n}\n\nfunc TestBindXmlStatsV3(t *testing.T) {\n\tts := httptest.NewServer(http.FileServer(http.Dir(\"testdata\")))\n\turl := ts.Listener.Addr().String()\n\thost, port, err := net.SplitHostPort(url)\n\trequire.NoError(t, err)\n\tdefer ts.Close()\n\n\tb := Bind{\n\t\tUrls:                 []string{ts.URL + \"/xml/v3\"},\n\t\tGatherMemoryContexts: true,\n\t\tGatherViews:          true,\n\t\tCountersAsInt:        true,\n\t\tclient: http.Client{\n\t\t\tTimeout: 4 * time.Second,\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(b.Gather)\n\trequire.NoError(t, err)\n\n\t// Use subtests for counters, since they are similar structure\n\ttype fieldSet struct {\n\t\tfieldKey   string\n\t\tfieldValue int64\n\t}\n\n\ttestCases := []struct {\n\t\tcounterType string\n\t\tvalues      []fieldSet\n\t}{\n\t\t{\n\t\t\t\"opcode\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"NOTIFY\", 0},\n\t\t\t\t{\"UPDATE\", 0},\n\t\t\t\t{\"IQUERY\", 0},\n\t\t\t\t{\"QUERY\", 74941},\n\t\t\t\t{\"STATUS\", 0},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"qtype\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"ANY\", 22},\n\t\t\t\t{\"SOA\", 18},\n\t\t\t\t{\"AAAA\", 5735},\n\t\t\t\t{\"MX\", 618},\n\t\t\t\t{\"NS\", 373},\n\t\t\t\t{\"TXT\", 970},\n\t\t\t\t{\"A\", 63672},\n\t\t\t\t{\"SRV\", 139},\n\t\t\t\t{\"PTR\", 3393},\n\t\t\t\t{\"RRSIG\", 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"DNS64\", 0},\n\t\t\t\t{\"ExpireOpt\", 0},\n\t\t\t\t{\"NSIDOpt\", 0},\n\t\t\t\t{\"OtherOpt\", 59},\n\t\t\t\t{\"XfrReqDone\", 0},\n\t\t\t\t{\"ReqEdns0\", 9250},\n\t\t\t\t{\"ReqTSIG\", 0},\n\t\t\t\t{\"UpdateRespFwd\", 0},\n\t\t\t\t{\"RespEDNS0\", 9250},\n\t\t\t\t{\"QryDropped\", 11},\n\t\t\t\t{\"RPZRewrites\", 0},\n\t\t\t\t{\"XfrRej\", 0},\n\t\t\t\t{\"RecQryRej\", 35},\n\t\t\t\t{\"QryNxrrset\", 2452},\n\t\t\t\t{\"QryFORMERR\", 0},\n\t\t\t\t{\"ReqTCP\", 260},\n\t\t\t\t{\"QryTCP\", 258},\n\t\t\t\t{\"QryUDP\", 74648},\n\t\t\t\t{\"UpdateDone\", 0},\n\t\t\t\t{\"QrySERVFAIL\", 122},\n\t\t\t\t{\"QryRecursion\", 53750},\n\t\t\t\t{\"RecursClients\", 0},\n\t\t\t\t{\"Requestv4\", 74942},\n\t\t\t\t{\"UpdateFwdFail\", 0},\n\t\t\t\t{\"QryReferral\", 0},\n\t\t\t\t{\"Response\", 63264},\n\t\t\t\t{\"RespTSIG\", 0},\n\t\t\t\t{\"QrySuccess\", 49044},\n\t\t\t\t{\"QryFailure\", 35},\n\t\t\t\t{\"RespSIG0\", 0},\n\t\t\t\t{\"ReqSIG0\", 0},\n\t\t\t\t{\"UpdateRej\", 0},\n\t\t\t\t{\"QryAuthAns\", 2752},\n\t\t\t\t{\"UpdateFail\", 0},\n\t\t\t\t{\"QryDuplicate\", 11667},\n\t\t\t\t{\"RateDropped\", 0},\n\t\t\t\t{\"QryNoauthAns\", 60354},\n\t\t\t\t{\"QryNXDOMAIN\", 11610},\n\t\t\t\t{\"ReqBadSIG\", 0},\n\t\t\t\t{\"UpdateReqFwd\", 0},\n\t\t\t\t{\"RateSlipped\", 0},\n\t\t\t\t{\"TruncatedResp\", 365},\n\t\t\t\t{\"Requestv6\", 0},\n\t\t\t\t{\"UpdateBadPrereq\", 0},\n\t\t\t\t{\"AuthQryRej\", 0},\n\t\t\t\t{\"ReqBadEDNSVer\", 0},\n\t\t\t\t{\"SitBadSize\", 0},\n\t\t\t\t{\"SitBadTime\", 0},\n\t\t\t\t{\"SitMatch\", 0},\n\t\t\t\t{\"SitNew\", 0},\n\t\t\t\t{\"SitNoMatch\", 0},\n\t\t\t\t{\"SitOpt\", 0},\n\t\t\t\t{\"TruncatedResp\", 365},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"sockstat\",\n\t\t\t[]fieldSet{\n\t\t\t\t{\"FDwatchConnFail\", 0},\n\t\t\t\t{\"UnixClose\", 0},\n\t\t\t\t{\"TCP6OpenFail\", 0},\n\t\t\t\t{\"TCP6Active\", 0},\n\t\t\t\t{\"UDP4RecvErr\", 14},\n\t\t\t\t{\"TCP6Conn\", 0},\n\t\t\t\t{\"FDWatchClose\", 0},\n\t\t\t\t{\"TCP4ConnFail\", 0},\n\t\t\t\t{\"UnixConn\", 0},\n\t\t\t\t{\"UnixSendErr\", 0},\n\t\t\t\t{\"UDP6Close\", 0},\n\t\t\t\t{\"UnixOpen\", 0},\n\t\t\t\t{\"UDP4Conn\", 92535},\n\t\t\t\t{\"TCP4Close\", 336},\n\t\t\t\t{\"UnixAcceptFail\", 0},\n\t\t\t\t{\"UnixAccept\", 0},\n\t\t\t\t{\"TCP6AcceptFail\", 0},\n\t\t\t\t{\"UDP6Open\", 0},\n\t\t\t\t{\"UDP6BindFail\", 0},\n\t\t\t\t{\"UDP6RecvErr\", 0},\n\t\t\t\t{\"RawOpenFail\", 0},\n\t\t\t\t{\"TCP4Accept\", 293},\n\t\t\t\t{\"UDP6SendErr\", 0},\n\t\t\t\t{\"UDP6Conn\", 0},\n\t\t\t\t{\"TCP4SendErr\", 0},\n\t\t\t\t{\"UDP4BindFail\", 1},\n\t\t\t\t{\"UDP4Active\", 4},\n\t\t\t\t{\"TCP4Active\", 297},\n\t\t\t\t{\"UnixConnFail\", 0},\n\t\t\t\t{\"UnixOpenFail\", 0},\n\t\t\t\t{\"UDP6ConnFail\", 0},\n\t\t\t\t{\"TCP6Accept\", 0},\n\t\t\t\t{\"UnixRecvErr\", 0},\n\t\t\t\t{\"RawActive\", 1},\n\t\t\t\t{\"UDP6OpenFail\", 0},\n\t\t\t\t{\"RawClose\", 0},\n\t\t\t\t{\"UnixBindFail\", 0},\n\t\t\t\t{\"UnixActive\", 0},\n\t\t\t\t{\"FdwatchBindFail\", 0},\n\t\t\t\t{\"UDP4SendErr\", 0},\n\t\t\t\t{\"RawRecvErr\", 0},\n\t\t\t\t{\"TCP6Close\", 0},\n\t\t\t\t{\"FDwatchRecvErr\", 0},\n\t\t\t\t{\"TCP4BindFail\", 0},\n\t\t\t\t{\"TCP4AcceptFail\", 0},\n\t\t\t\t{\"TCP4OpenFail\", 0},\n\t\t\t\t{\"UDP4Open\", 92542},\n\t\t\t\t{\"UDP4ConnFail\", 0},\n\t\t\t\t{\"TCP4Conn\", 44},\n\t\t\t\t{\"TCP6ConnFail\", 0},\n\t\t\t\t{\"FDwatchConn\", 0},\n\t\t\t\t{\"UDP6Active\", 0},\n\t\t\t\t{\"RawOpen\", 1},\n\t\t\t\t{\"TCP6BindFail\", 0},\n\t\t\t\t{\"UDP4Close\", 92538},\n\t\t\t\t{\"TCP6Open\", 0},\n\t\t\t\t{\"TCP6SendErr\", 0},\n\t\t\t\t{\"TCP4Open\", 48},\n\t\t\t\t{\"FDwatchSendErr\", 0},\n\t\t\t\t{\"TCP6RecvErr\", 0},\n\t\t\t\t{\"UDP4OpenFail\", 0},\n\t\t\t\t{\"TCP4RecvErr\", 0},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.counterType, func(t *testing.T) {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"type\":   tc.counterType,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t}\n\n\t\t\tfields := make(map[string]interface{}, len(tc.values))\n\t\t\tfor _, val := range tc.values {\n\t\t\t\tfields[val.fieldKey] = val.fieldValue\n\t\t\t}\n\t\t\tacc.AssertContainsTaggedFields(t, \"bind_counter\", fields, tags)\n\t\t})\n\t}\n\n\t// Subtest for memory stats\n\tt.Run(\"memory\", func(t *testing.T) {\n\t\ttags := map[string]string{\n\t\t\t\"url\":    url,\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"block_size\":   int64(45875200),\n\t\t\t\"context_size\": int64(10037400),\n\t\t\t\"in_use\":       int64(6000232),\n\t\t\t\"lost\":         int64(0),\n\t\t\t\"total_use\":    int64(777821909),\n\t\t}\n\n\t\tacc.AssertContainsTaggedFields(t, \"bind_memory\", fields, tags)\n\t})\n\n\t// Subtest for per-context memory stats\n\tt.Run(\"memory_context\", func(t *testing.T) {\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"total\"))\n\t\trequire.True(t, acc.HasInt64Field(\"bind_memory_context\", \"in_use\"))\n\t})\n}\n\nfunc TestBindXmlStatsV3Signed(t *testing.T) {\n\t// Setup a mock server to deliver the stats\n\tts := httptest.NewServer(http.FileServer(http.Dir(\"testdata\")))\n\turl := ts.Listener.Addr().String()\n\thost, port, err := net.SplitHostPort(url)\n\trequire.NoError(t, err)\n\tdefer ts.Close()\n\n\t// Setup the plugin\n\tplugin := &Bind{\n\t\tUrls:                 []string{ts.URL + \"/xml/v3\"},\n\t\tGatherMemoryContexts: true,\n\t\tGatherViews:          true,\n\t\tCountersAsInt:        true,\n\t\tTimeout:              config.Duration(4 * time.Second),\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Create the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"bind_memory\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"block_size\":   int64(45875200),\n\t\t\t\t\"context_size\": int64(10037400),\n\t\t\t\t\"in_use\":       int64(6000232),\n\t\t\t\t\"lost\":         int64(0),\n\t\t\t\t\"total_use\":    int64(777821909),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e042de0\",\n\t\t\t\t\"name\":   \"main\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(1454904),\n\t\t\t\t\"total\":  int64(2706043),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e0507e0\",\n\t\t\t\t\"name\":   \"dst\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(91776),\n\t\t\t\t\"total\":  int64(387478),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e0938e0\",\n\t\t\t\t\"name\":   \"zonemgr-pool\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(143776),\n\t\t\t\t\"total\":  int64(742986),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00017d0\",\n\t\t\t\t\"name\":   \"threadkey\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(0),\n\t\t\t\t\"total\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00475f0\",\n\t\t\t\t\"name\":   \"client\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(8760),\n\t\t\t\t\"total\":  int64(267800),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00dfca0\",\n\t\t\t\t\"name\":   \"cache\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(83650),\n\t\t\t\t\"total\":  int64(288938),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00eaa30\",\n\t\t\t\t\"name\":   \"cache_heap\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(132096),\n\t\t\t\t\"total\":  int64(393216),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d01094e0\",\n\t\t\t\t\"name\":   \"res0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(0),\n\t\t\t\t\"total\":  int64(262144),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d0114270\",\n\t\t\t\t\"name\":   \"res1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(0),\n\t\t\t\t\"total\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d011f000\",\n\t\t\t\t\"name\":   \"res2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": int64(0),\n\t\t\t\t\"total\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"opcode\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"IQUERY\": int64(0),\n\t\t\t\t\"NOTIFY\": int64(0),\n\t\t\t\t\"QUERY\":  int64(74941),\n\t\t\t\t\"STATUS\": int64(0),\n\t\t\t\t\"UPDATE\": int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"qtype\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"A\":     int64(63672),\n\t\t\t\t\"AAAA\":  int64(5735),\n\t\t\t\t\"ANY\":   int64(22),\n\t\t\t\t\"MX\":    int64(618),\n\t\t\t\t\"NS\":    int64(373),\n\t\t\t\t\"PTR\":   int64(3393),\n\t\t\t\t\"RRSIG\": int64(1),\n\t\t\t\t\"SOA\":   int64(18),\n\t\t\t\t\"SRV\":   int64(139),\n\t\t\t\t\"TXT\":   int64(970),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"nsstat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AuthQryRej\":      int64(0),\n\t\t\t\t\"DNS64\":           int64(0),\n\t\t\t\t\"ExpireOpt\":       int64(0),\n\t\t\t\t\"NSIDOpt\":         int64(0),\n\t\t\t\t\"OtherOpt\":        int64(59),\n\t\t\t\t\"QryAuthAns\":      int64(2752),\n\t\t\t\t\"QryDropped\":      int64(11),\n\t\t\t\t\"QryDuplicate\":    int64(11667),\n\t\t\t\t\"QryFORMERR\":      int64(0),\n\t\t\t\t\"QryFailure\":      int64(35),\n\t\t\t\t\"QryNXDOMAIN\":     int64(11610),\n\t\t\t\t\"QryNoauthAns\":    int64(60354),\n\t\t\t\t\"QryNxrrset\":      int64(2452),\n\t\t\t\t\"QryRecursion\":    int64(53750),\n\t\t\t\t\"QryReferral\":     int64(0),\n\t\t\t\t\"QrySERVFAIL\":     int64(122),\n\t\t\t\t\"QrySuccess\":      int64(49044),\n\t\t\t\t\"QryTCP\":          int64(258),\n\t\t\t\t\"QryUDP\":          int64(74648),\n\t\t\t\t\"RPZRewrites\":     int64(0),\n\t\t\t\t\"RateDropped\":     int64(0),\n\t\t\t\t\"RateSlipped\":     int64(0),\n\t\t\t\t\"RecQryRej\":       int64(35),\n\t\t\t\t\"RecursClients\":   int64(0),\n\t\t\t\t\"ReqBadEDNSVer\":   int64(0),\n\t\t\t\t\"ReqBadSIG\":       int64(0),\n\t\t\t\t\"ReqEdns0\":        int64(9250),\n\t\t\t\t\"ReqSIG0\":         int64(0),\n\t\t\t\t\"ReqTCP\":          int64(260),\n\t\t\t\t\"ReqTSIG\":         int64(0),\n\t\t\t\t\"Requestv4\":       int64(74942),\n\t\t\t\t\"Requestv6\":       int64(0),\n\t\t\t\t\"RespEDNS0\":       int64(9250),\n\t\t\t\t\"RespSIG0\":        int64(0),\n\t\t\t\t\"RespTSIG\":        int64(0),\n\t\t\t\t\"Response\":        int64(63264),\n\t\t\t\t\"SitBadSize\":      int64(0),\n\t\t\t\t\"SitBadTime\":      int64(0),\n\t\t\t\t\"SitMatch\":        int64(0),\n\t\t\t\t\"SitNew\":          int64(0),\n\t\t\t\t\"SitNoMatch\":      int64(0),\n\t\t\t\t\"SitOpt\":          int64(0),\n\t\t\t\t\"TruncatedResp\":   int64(365),\n\t\t\t\t\"UpdateBadPrereq\": int64(0),\n\t\t\t\t\"UpdateDone\":      int64(0),\n\t\t\t\t\"UpdateFail\":      int64(0),\n\t\t\t\t\"UpdateFwdFail\":   int64(0),\n\t\t\t\t\"UpdateRej\":       int64(0),\n\t\t\t\t\"UpdateReqFwd\":    int64(0),\n\t\t\t\t\"UpdateRespFwd\":   int64(0),\n\t\t\t\t\"XfrRej\":          int64(0),\n\t\t\t\t\"XfrReqDone\":      int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"zonestat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AXFRReqv4\":   int64(0),\n\t\t\t\t\"AXFRReqv6\":   int64(0),\n\t\t\t\t\"IXFRReqv4\":   int64(0),\n\t\t\t\t\"IXFRReqv6\":   int64(0),\n\t\t\t\t\"NotifyInv4\":  int64(0),\n\t\t\t\t\"NotifyInv6\":  int64(0),\n\t\t\t\t\"NotifyOutv4\": int64(2),\n\t\t\t\t\"NotifyOutv6\": int64(0),\n\t\t\t\t\"NotifyRej\":   int64(0),\n\t\t\t\t\"SOAOutv4\":    int64(0),\n\t\t\t\t\"SOAOutv6\":    int64(0),\n\t\t\t\t\"XfrFail\":     int64(0),\n\t\t\t\t\"XfrSuccess\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"sockstat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"FDWatchClose\":    int64(0),\n\t\t\t\t\"FDwatchConn\":     int64(0),\n\t\t\t\t\"FDwatchConnFail\": int64(0),\n\t\t\t\t\"FDwatchRecvErr\":  int64(0),\n\t\t\t\t\"FDwatchSendErr\":  int64(0),\n\t\t\t\t\"FdwatchBindFail\": int64(0),\n\t\t\t\t\"RawActive\":       int64(1),\n\t\t\t\t\"RawClose\":        int64(0),\n\t\t\t\t\"RawOpen\":         int64(1),\n\t\t\t\t\"RawOpenFail\":     int64(0),\n\t\t\t\t\"RawRecvErr\":      int64(0),\n\t\t\t\t\"TCP4Accept\":      int64(293),\n\t\t\t\t\"TCP4AcceptFail\":  int64(0),\n\t\t\t\t\"TCP4Active\":      int64(297),\n\t\t\t\t\"TCP4BindFail\":    int64(0),\n\t\t\t\t\"TCP4Close\":       int64(336),\n\t\t\t\t\"TCP4ConnFail\":    int64(0),\n\t\t\t\t\"TCP4Conn\":        int64(44),\n\t\t\t\t\"TCP4Open\":        int64(48),\n\t\t\t\t\"TCP4OpenFail\":    int64(0),\n\t\t\t\t\"TCP4RecvErr\":     int64(0),\n\t\t\t\t\"TCP4SendErr\":     int64(0),\n\t\t\t\t\"TCP6Accept\":      int64(0),\n\t\t\t\t\"TCP6AcceptFail\":  int64(0),\n\t\t\t\t\"TCP6Active\":      int64(0),\n\t\t\t\t\"TCP6BindFail\":    int64(0),\n\t\t\t\t\"TCP6Close\":       int64(0),\n\t\t\t\t\"TCP6Conn\":        int64(0),\n\t\t\t\t\"TCP6ConnFail\":    int64(0),\n\t\t\t\t\"TCP6Open\":        int64(0),\n\t\t\t\t\"TCP6OpenFail\":    int64(0),\n\t\t\t\t\"TCP6RecvErr\":     int64(0),\n\t\t\t\t\"TCP6SendErr\":     int64(0),\n\t\t\t\t\"UDP4Active\":      int64(4),\n\t\t\t\t\"UDP4BindFail\":    int64(1),\n\t\t\t\t\"UDP4Close\":       int64(92538),\n\t\t\t\t\"UDP4Conn\":        int64(92535),\n\t\t\t\t\"UDP4ConnFail\":    int64(0),\n\t\t\t\t\"UDP4Open\":        int64(92542),\n\t\t\t\t\"UDP4OpenFail\":    int64(0),\n\t\t\t\t\"UDP4RecvErr\":     int64(14),\n\t\t\t\t\"UDP4SendErr\":     int64(0),\n\t\t\t\t\"UDP6Active\":      int64(0),\n\t\t\t\t\"UDP6BindFail\":    int64(0),\n\t\t\t\t\"UDP6Close\":       int64(0),\n\t\t\t\t\"UDP6Conn\":        int64(0),\n\t\t\t\t\"UDP6ConnFail\":    int64(0),\n\t\t\t\t\"UDP6Open\":        int64(0),\n\t\t\t\t\"UDP6OpenFail\":    int64(0),\n\t\t\t\t\"UDP6RecvErr\":     int64(0),\n\t\t\t\t\"UDP6SendErr\":     int64(0),\n\t\t\t\t\"UnixAccept\":      int64(0),\n\t\t\t\t\"UnixAcceptFail\":  int64(0),\n\t\t\t\t\"UnixActive\":      int64(0),\n\t\t\t\t\"UnixBindFail\":    int64(0),\n\t\t\t\t\"UnixClose\":       int64(0),\n\t\t\t\t\"UnixConn\":        int64(0),\n\t\t\t\t\"UnixConnFail\":    int64(0),\n\t\t\t\t\"UnixOpen\":        int64(0),\n\t\t\t\t\"UnixOpenFail\":    int64(0),\n\t\t\t\t\"UnixRecvErr\":     int64(0),\n\t\t\t\t\"UnixSendErr\":     int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resqtype\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"A\":      int64(61568),\n\t\t\t\t\"AAAA\":   int64(3933),\n\t\t\t\t\"DNSKEY\": int64(1699),\n\t\t\t\t\"DS\":     int64(13749),\n\t\t\t\t\"MX\":     int64(286),\n\t\t\t\t\"NS\":     int64(9126),\n\t\t\t\t\"PTR\":    int64(1249),\n\t\t\t\t\"SRV\":    int64(21),\n\t\t\t\t\"TXT\":    int64(942),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resstats\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"BadEDNSVersion\":  int64(0),\n\t\t\t\t\"BucketSize\":      int64(31),\n\t\t\t\t\"EDNS0Fail\":       int64(0),\n\t\t\t\t\"FORMERR\":         int64(0),\n\t\t\t\t\"GlueFetchv4\":     int64(1398),\n\t\t\t\t\"GlueFetchv4Fail\": int64(3),\n\t\t\t\t\"GlueFetchv6\":     int64(0),\n\t\t\t\t\"GlueFetchv6Fail\": int64(0),\n\t\t\t\t\"Lame\":            int64(12),\n\t\t\t\t\"Mismatch\":        int64(0),\n\t\t\t\t\"NXDOMAIN\":        int64(8182),\n\t\t\t\t\"NumFetch\":        int64(0),\n\t\t\t\t\"OtherError\":      int64(0),\n\t\t\t\t\"QryRTT10\":        int64(0),\n\t\t\t\t\"QryRTT100\":       int64(45760),\n\t\t\t\t\"QryRTT1600\":      int64(75),\n\t\t\t\t\"QryRTT1600+\":     int64(0),\n\t\t\t\t\"QryRTT500\":       int64(45543),\n\t\t\t\t\"QryRTT800\":       int64(743),\n\t\t\t\t\"QueryAbort\":      int64(0),\n\t\t\t\t\"QueryCurTCP\":     int64(0),\n\t\t\t\t\"QueryCurUDP\":     int64(0),\n\t\t\t\t\"QuerySockFail\":   int64(0),\n\t\t\t\t\"QueryTimeout\":    int64(490),\n\t\t\t\t\"Queryv4\":         int64(92573),\n\t\t\t\t\"Queryv6\":         int64(0),\n\t\t\t\t\"REFUSED\":         int64(34),\n\t\t\t\t\"Responsev4\":      int64(92135),\n\t\t\t\t\"Responsev6\":      int64(0),\n\t\t\t\t\"Retry\":           int64(800),\n\t\t\t\t\"SERVFAIL\":        int64(318),\n\t\t\t\t\"ServerQuota\":     int64(0),\n\t\t\t\t\"SitClientOk\":     int64(0),\n\t\t\t\t\"SitClientOut\":    int64(0),\n\t\t\t\t\"SitIn\":           int64(0),\n\t\t\t\t\"SitOut\":          int64(0),\n\t\t\t\t\"Truncated\":       int64(42),\n\t\t\t\t\"ValAttempt\":      int64(90256),\n\t\t\t\t\"ValFail\":         int64(6),\n\t\t\t\t\"ValNegOk\":        int64(22850),\n\t\t\t\t\"ValOk\":           int64(67322),\n\t\t\t\t\"ZoneQuota\":       int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"adbstat\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entriescnt\": int64(314),\n\t\t\t\t\"namescnt\":   int64(316),\n\t\t\t\t\"nentries\":   int64(1021),\n\t\t\t\t\"nnames\":     int64(1021),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"cachestats\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"CacheBuckets\": int64(519),\n\t\t\t\t\"CacheHits\":    int64(1904593),\n\t\t\t\t\"CacheMisses\":  int64(96),\n\t\t\t\t\"CacheNodes\":   int64(769),\n\t\t\t\t\"DeleteLRU\":    int64(0),\n\t\t\t\t\"DeleteTTL\":    int64(47518),\n\t\t\t\t\"HeapMemInUse\": int64(132096),\n\t\t\t\t\"HeapMemMax\":   int64(132096),\n\t\t\t\t\"HeapMemTotal\": int64(393216),\n\t\t\t\t\"QueryHits\":    int64(336094),\n\t\t\t\t\"QueryMisses\":  int64(369336),\n\t\t\t\t\"TreeMemInUse\": int64(392128),\n\t\t\t\t\"TreeMemMax\":   int64(828966),\n\t\t\t\t\"TreeMemTotal\": int64(1464363),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resstats\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"BadEDNSVersion\":  int64(0),\n\t\t\t\t\"BucketSize\":      int64(31),\n\t\t\t\t\"EDNS0Fail\":       int64(0),\n\t\t\t\t\"FORMERR\":         int64(0),\n\t\t\t\t\"GlueFetchv4\":     int64(0),\n\t\t\t\t\"GlueFetchv4Fail\": int64(0),\n\t\t\t\t\"GlueFetchv6\":     int64(0),\n\t\t\t\t\"GlueFetchv6Fail\": int64(0),\n\t\t\t\t\"Lame\":            int64(0),\n\t\t\t\t\"Mismatch\":        int64(0),\n\t\t\t\t\"NXDOMAIN\":        int64(0),\n\t\t\t\t\"NumFetch\":        int64(0),\n\t\t\t\t\"OtherError\":      int64(0),\n\t\t\t\t\"QryRTT10\":        int64(0),\n\t\t\t\t\"QryRTT100\":       int64(0),\n\t\t\t\t\"QryRTT1600\":      int64(0),\n\t\t\t\t\"QryRTT1600+\":     int64(0),\n\t\t\t\t\"QryRTT500\":       int64(0),\n\t\t\t\t\"QryRTT800\":       int64(0),\n\t\t\t\t\"QueryAbort\":      int64(0),\n\t\t\t\t\"QueryCurTCP\":     int64(0),\n\t\t\t\t\"QueryCurUDP\":     int64(0),\n\t\t\t\t\"QuerySockFail\":   int64(0),\n\t\t\t\t\"QueryTimeout\":    int64(0),\n\t\t\t\t\"Queryv4\":         int64(0),\n\t\t\t\t\"Queryv6\":         int64(0),\n\t\t\t\t\"REFUSED\":         int64(0),\n\t\t\t\t\"Responsev4\":      int64(0),\n\t\t\t\t\"Responsev6\":      int64(0),\n\t\t\t\t\"Retry\":           int64(0),\n\t\t\t\t\"SERVFAIL\":        int64(0),\n\t\t\t\t\"ServerQuota\":     int64(0),\n\t\t\t\t\"SitClientOk\":     int64(0),\n\t\t\t\t\"SitClientOut\":    int64(0),\n\t\t\t\t\"SitIn\":           int64(0),\n\t\t\t\t\"SitOut\":          int64(0),\n\t\t\t\t\"Truncated\":       int64(0),\n\t\t\t\t\"ValAttempt\":      int64(0),\n\t\t\t\t\"ValFail\":         int64(0),\n\t\t\t\t\"ValNegOk\":        int64(0),\n\t\t\t\t\"ValOk\":           int64(0),\n\t\t\t\t\"ZoneQuota\":       int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"adbstat\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entriescnt\": int64(0),\n\t\t\t\t\"namescnt\":   int64(0),\n\t\t\t\t\"nentries\":   int64(1021),\n\t\t\t\t\"nnames\":     int64(1021),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"cachestats\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"CacheBuckets\": int64(64),\n\t\t\t\t\"CacheHits\":    int64(0),\n\t\t\t\t\"CacheMisses\":  int64(0),\n\t\t\t\t\"CacheNodes\":   int64(0),\n\t\t\t\t\"DeleteLRU\":    int64(0),\n\t\t\t\t\"DeleteTTL\":    int64(0),\n\t\t\t\t\"HeapMemInUse\": int64(1024),\n\t\t\t\t\"HeapMemMax\":   int64(1024),\n\t\t\t\t\"HeapMemTotal\": int64(262144),\n\t\t\t\t\"QueryHits\":    int64(0),\n\t\t\t\t\"QueryMisses\":  int64(0),\n\t\t\t\t\"TreeMemInUse\": int64(29608),\n\t\t\t\t\"TreeMemMax\":   int64(29608),\n\t\t\t\t\"TreeMemTotal\": int64(287392),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Gather and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\nfunc TestBindXmlStatsV3Unsigned(t *testing.T) {\n\t// Setup a mock server to deliver the stats\n\tts := httptest.NewServer(http.FileServer(http.Dir(\"testdata\")))\n\turl := ts.Listener.Addr().String()\n\thost, port, err := net.SplitHostPort(url)\n\trequire.NoError(t, err)\n\tdefer ts.Close()\n\n\t// Setup the plugin\n\tplugin := &Bind{\n\t\tUrls:                 []string{ts.URL + \"/xml/v3\"},\n\t\tGatherMemoryContexts: true,\n\t\tGatherViews:          true,\n\t\tTimeout:              config.Duration(4 * time.Second),\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Create the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"bind_memory\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"block_size\":   uint64(45875200),\n\t\t\t\t\"context_size\": uint64(10037400),\n\t\t\t\t\"in_use\":       uint64(6000232),\n\t\t\t\t\"lost\":         uint64(0),\n\t\t\t\t\"total_use\":    uint64(777821909),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e042de0\",\n\t\t\t\t\"name\":   \"main\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(1454904),\n\t\t\t\t\"total\":  uint64(2706043),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e0507e0\",\n\t\t\t\t\"name\":   \"dst\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(91776),\n\t\t\t\t\"total\":  uint64(387478),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x55fb2e0938e0\",\n\t\t\t\t\"name\":   \"zonemgr-pool\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(143776),\n\t\t\t\t\"total\":  uint64(742986),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00017d0\",\n\t\t\t\t\"name\":   \"threadkey\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(0),\n\t\t\t\t\"total\":  uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00475f0\",\n\t\t\t\t\"name\":   \"client\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(8760),\n\t\t\t\t\"total\":  uint64(267800),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00dfca0\",\n\t\t\t\t\"name\":   \"cache\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(83650),\n\t\t\t\t\"total\":  uint64(288938),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d00eaa30\",\n\t\t\t\t\"name\":   \"cache_heap\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(132096),\n\t\t\t\t\"total\":  uint64(393216),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d01094e0\",\n\t\t\t\t\"name\":   \"res0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(0),\n\t\t\t\t\"total\":  uint64(262144),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d0114270\",\n\t\t\t\t\"name\":   \"res1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(0),\n\t\t\t\t\"total\":  uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_memory_context\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"id\":     \"0x7f19d011f000\",\n\t\t\t\t\"name\":   \"res2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_use\": uint64(0),\n\t\t\t\t\"total\":  uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"opcode\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"IQUERY\": uint64(0),\n\t\t\t\t\"NOTIFY\": uint64(0),\n\t\t\t\t\"QUERY\":  uint64(74941),\n\t\t\t\t\"STATUS\": uint64(0),\n\t\t\t\t\"UPDATE\": uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"qtype\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"A\":     uint64(63672),\n\t\t\t\t\"AAAA\":  uint64(5735),\n\t\t\t\t\"ANY\":   uint64(22),\n\t\t\t\t\"MX\":    uint64(618),\n\t\t\t\t\"NS\":    uint64(373),\n\t\t\t\t\"PTR\":   uint64(3393),\n\t\t\t\t\"RRSIG\": uint64(1),\n\t\t\t\t\"SOA\":   uint64(18),\n\t\t\t\t\"SRV\":   uint64(139),\n\t\t\t\t\"TXT\":   uint64(970),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"nsstat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AuthQryRej\":      uint64(0),\n\t\t\t\t\"DNS64\":           uint64(0),\n\t\t\t\t\"ExpireOpt\":       uint64(0),\n\t\t\t\t\"NSIDOpt\":         uint64(0),\n\t\t\t\t\"OtherOpt\":        uint64(59),\n\t\t\t\t\"QryAuthAns\":      uint64(2752),\n\t\t\t\t\"QryDropped\":      uint64(11),\n\t\t\t\t\"QryDuplicate\":    uint64(11667),\n\t\t\t\t\"QryFORMERR\":      uint64(0),\n\t\t\t\t\"QryFailure\":      uint64(35),\n\t\t\t\t\"QryNXDOMAIN\":     uint64(11610),\n\t\t\t\t\"QryNoauthAns\":    uint64(60354),\n\t\t\t\t\"QryNxrrset\":      uint64(2452),\n\t\t\t\t\"QryRecursion\":    uint64(53750),\n\t\t\t\t\"QryReferral\":     uint64(0),\n\t\t\t\t\"QrySERVFAIL\":     uint64(122),\n\t\t\t\t\"QrySuccess\":      uint64(49044),\n\t\t\t\t\"QryTCP\":          uint64(258),\n\t\t\t\t\"QryUDP\":          uint64(74648),\n\t\t\t\t\"RPZRewrites\":     uint64(0),\n\t\t\t\t\"RateDropped\":     uint64(0),\n\t\t\t\t\"RateSlipped\":     uint64(0),\n\t\t\t\t\"RecQryRej\":       uint64(35),\n\t\t\t\t\"RecursClients\":   uint64(0),\n\t\t\t\t\"ReqBadEDNSVer\":   uint64(0),\n\t\t\t\t\"ReqBadSIG\":       uint64(0),\n\t\t\t\t\"ReqEdns0\":        uint64(9250),\n\t\t\t\t\"ReqSIG0\":         uint64(0),\n\t\t\t\t\"ReqTCP\":          uint64(260),\n\t\t\t\t\"ReqTSIG\":         uint64(0),\n\t\t\t\t\"Requestv4\":       uint64(74942),\n\t\t\t\t\"Requestv6\":       uint64(0),\n\t\t\t\t\"RespEDNS0\":       uint64(9250),\n\t\t\t\t\"RespSIG0\":        uint64(0),\n\t\t\t\t\"RespTSIG\":        uint64(0),\n\t\t\t\t\"Response\":        uint64(63264),\n\t\t\t\t\"SitBadSize\":      uint64(0),\n\t\t\t\t\"SitBadTime\":      uint64(0),\n\t\t\t\t\"SitMatch\":        uint64(0),\n\t\t\t\t\"SitNew\":          uint64(0),\n\t\t\t\t\"SitNoMatch\":      uint64(0),\n\t\t\t\t\"SitOpt\":          uint64(0),\n\t\t\t\t\"TruncatedResp\":   uint64(365),\n\t\t\t\t\"UpdateBadPrereq\": uint64(0),\n\t\t\t\t\"UpdateDone\":      uint64(0),\n\t\t\t\t\"UpdateFail\":      uint64(0),\n\t\t\t\t\"UpdateFwdFail\":   uint64(0),\n\t\t\t\t\"UpdateRej\":       uint64(0),\n\t\t\t\t\"UpdateReqFwd\":    uint64(0),\n\t\t\t\t\"UpdateRespFwd\":   uint64(0),\n\t\t\t\t\"XfrRej\":          uint64(0),\n\t\t\t\t\"XfrReqDone\":      uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"zonestat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AXFRReqv4\":   uint64(0),\n\t\t\t\t\"AXFRReqv6\":   uint64(0),\n\t\t\t\t\"IXFRReqv4\":   uint64(0),\n\t\t\t\t\"IXFRReqv6\":   uint64(0),\n\t\t\t\t\"NotifyInv4\":  uint64(0),\n\t\t\t\t\"NotifyInv6\":  uint64(0),\n\t\t\t\t\"NotifyOutv4\": uint64(2),\n\t\t\t\t\"NotifyOutv6\": uint64(0),\n\t\t\t\t\"NotifyRej\":   uint64(0),\n\t\t\t\t\"SOAOutv4\":    uint64(0),\n\t\t\t\t\"SOAOutv6\":    uint64(0),\n\t\t\t\t\"XfrFail\":     uint64(0),\n\t\t\t\t\"XfrSuccess\":  uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"sockstat\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"FDWatchClose\":    uint64(0),\n\t\t\t\t\"FDwatchConn\":     uint64(0),\n\t\t\t\t\"FDwatchConnFail\": uint64(0),\n\t\t\t\t\"FDwatchRecvErr\":  uint64(0),\n\t\t\t\t\"FDwatchSendErr\":  uint64(0),\n\t\t\t\t\"FdwatchBindFail\": uint64(0),\n\t\t\t\t\"RawActive\":       uint64(1),\n\t\t\t\t\"RawClose\":        uint64(0),\n\t\t\t\t\"RawOpen\":         uint64(1),\n\t\t\t\t\"RawOpenFail\":     uint64(0),\n\t\t\t\t\"RawRecvErr\":      uint64(0),\n\t\t\t\t\"TCP4Accept\":      uint64(293),\n\t\t\t\t\"TCP4AcceptFail\":  uint64(0),\n\t\t\t\t\"TCP4Active\":      uint64(297),\n\t\t\t\t\"TCP4BindFail\":    uint64(0),\n\t\t\t\t\"TCP4Close\":       uint64(336),\n\t\t\t\t\"TCP4ConnFail\":    uint64(0),\n\t\t\t\t\"TCP4Conn\":        uint64(44),\n\t\t\t\t\"TCP4Open\":        uint64(48),\n\t\t\t\t\"TCP4OpenFail\":    uint64(0),\n\t\t\t\t\"TCP4RecvErr\":     uint64(0),\n\t\t\t\t\"TCP4SendErr\":     uint64(0),\n\t\t\t\t\"TCP6Accept\":      uint64(0),\n\t\t\t\t\"TCP6AcceptFail\":  uint64(0),\n\t\t\t\t\"TCP6Active\":      uint64(0),\n\t\t\t\t\"TCP6BindFail\":    uint64(0),\n\t\t\t\t\"TCP6Close\":       uint64(0),\n\t\t\t\t\"TCP6Conn\":        uint64(0),\n\t\t\t\t\"TCP6ConnFail\":    uint64(0),\n\t\t\t\t\"TCP6Open\":        uint64(0),\n\t\t\t\t\"TCP6OpenFail\":    uint64(0),\n\t\t\t\t\"TCP6RecvErr\":     uint64(0),\n\t\t\t\t\"TCP6SendErr\":     uint64(0),\n\t\t\t\t\"UDP4Active\":      uint64(4),\n\t\t\t\t\"UDP4BindFail\":    uint64(1),\n\t\t\t\t\"UDP4Close\":       uint64(92538),\n\t\t\t\t\"UDP4Conn\":        uint64(92535),\n\t\t\t\t\"UDP4ConnFail\":    uint64(0),\n\t\t\t\t\"UDP4Open\":        uint64(92542),\n\t\t\t\t\"UDP4OpenFail\":    uint64(0),\n\t\t\t\t\"UDP4RecvErr\":     uint64(14),\n\t\t\t\t\"UDP4SendErr\":     uint64(0),\n\t\t\t\t\"UDP6Active\":      uint64(0),\n\t\t\t\t\"UDP6BindFail\":    uint64(0),\n\t\t\t\t\"UDP6Close\":       uint64(0),\n\t\t\t\t\"UDP6Conn\":        uint64(0),\n\t\t\t\t\"UDP6ConnFail\":    uint64(0),\n\t\t\t\t\"UDP6Open\":        uint64(0),\n\t\t\t\t\"UDP6OpenFail\":    uint64(0),\n\t\t\t\t\"UDP6RecvErr\":     uint64(0),\n\t\t\t\t\"UDP6SendErr\":     uint64(0),\n\t\t\t\t\"UnixAccept\":      uint64(0),\n\t\t\t\t\"UnixAcceptFail\":  uint64(0),\n\t\t\t\t\"UnixActive\":      uint64(0),\n\t\t\t\t\"UnixBindFail\":    uint64(0),\n\t\t\t\t\"UnixClose\":       uint64(0),\n\t\t\t\t\"UnixConn\":        uint64(0),\n\t\t\t\t\"UnixConnFail\":    uint64(0),\n\t\t\t\t\"UnixOpen\":        uint64(0),\n\t\t\t\t\"UnixOpenFail\":    uint64(0),\n\t\t\t\t\"UnixRecvErr\":     uint64(0),\n\t\t\t\t\"UnixSendErr\":     uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resqtype\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"A\":      uint64(61568),\n\t\t\t\t\"AAAA\":   uint64(3933),\n\t\t\t\t\"DNSKEY\": uint64(1699),\n\t\t\t\t\"DS\":     uint64(13749),\n\t\t\t\t\"MX\":     uint64(286),\n\t\t\t\t\"NS\":     uint64(9126),\n\t\t\t\t\"PTR\":    uint64(1249),\n\t\t\t\t\"SRV\":    uint64(21),\n\t\t\t\t\"TXT\":    uint64(942),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resstats\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"BadEDNSVersion\":  uint64(0),\n\t\t\t\t\"BucketSize\":      uint64(31),\n\t\t\t\t\"EDNS0Fail\":       uint64(0),\n\t\t\t\t\"FORMERR\":         uint64(0),\n\t\t\t\t\"GlueFetchv4\":     uint64(1398),\n\t\t\t\t\"GlueFetchv4Fail\": uint64(3),\n\t\t\t\t\"GlueFetchv6\":     uint64(0),\n\t\t\t\t\"GlueFetchv6Fail\": uint64(0),\n\t\t\t\t\"Lame\":            uint64(12),\n\t\t\t\t\"Mismatch\":        uint64(0),\n\t\t\t\t\"NXDOMAIN\":        uint64(8182),\n\t\t\t\t\"NumFetch\":        uint64(0),\n\t\t\t\t\"OtherError\":      uint64(0),\n\t\t\t\t\"QryRTT10\":        uint64(0),\n\t\t\t\t\"QryRTT100\":       uint64(45760),\n\t\t\t\t\"QryRTT1600\":      uint64(75),\n\t\t\t\t\"QryRTT1600+\":     uint64(0),\n\t\t\t\t\"QryRTT500\":       uint64(45543),\n\t\t\t\t\"QryRTT800\":       uint64(743),\n\t\t\t\t\"QueryAbort\":      uint64(0),\n\t\t\t\t\"QueryCurTCP\":     uint64(0),\n\t\t\t\t\"QueryCurUDP\":     uint64(0),\n\t\t\t\t\"QuerySockFail\":   uint64(0),\n\t\t\t\t\"QueryTimeout\":    uint64(490),\n\t\t\t\t\"Queryv4\":         uint64(92573),\n\t\t\t\t\"Queryv6\":         uint64(0),\n\t\t\t\t\"REFUSED\":         uint64(34),\n\t\t\t\t\"Responsev4\":      uint64(92135),\n\t\t\t\t\"Responsev6\":      uint64(0),\n\t\t\t\t\"Retry\":           uint64(800),\n\t\t\t\t\"SERVFAIL\":        uint64(318),\n\t\t\t\t\"ServerQuota\":     uint64(0),\n\t\t\t\t\"SitClientOk\":     uint64(0),\n\t\t\t\t\"SitClientOut\":    uint64(0),\n\t\t\t\t\"SitIn\":           uint64(0),\n\t\t\t\t\"SitOut\":          uint64(0),\n\t\t\t\t\"Truncated\":       uint64(42),\n\t\t\t\t\"ValAttempt\":      uint64(90256),\n\t\t\t\t\"ValFail\":         uint64(6),\n\t\t\t\t\"ValNegOk\":        uint64(22850),\n\t\t\t\t\"ValOk\":           uint64(67322),\n\t\t\t\t\"ZoneQuota\":       uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"adbstat\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entriescnt\": uint64(314),\n\t\t\t\t\"namescnt\":   uint64(316),\n\t\t\t\t\"nentries\":   uint64(1021),\n\t\t\t\t\"nnames\":     uint64(1021),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"cachestats\",\n\t\t\t\t\"view\":   \"_default\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"CacheBuckets\": uint64(519),\n\t\t\t\t\"CacheHits\":    uint64(1904593),\n\t\t\t\t\"CacheMisses\":  uint64(96),\n\t\t\t\t\"CacheNodes\":   uint64(769),\n\t\t\t\t\"DeleteLRU\":    uint64(0),\n\t\t\t\t\"DeleteTTL\":    uint64(47518),\n\t\t\t\t\"HeapMemInUse\": uint64(132096),\n\t\t\t\t\"HeapMemMax\":   uint64(132096),\n\t\t\t\t\"HeapMemTotal\": uint64(393216),\n\t\t\t\t\"QueryHits\":    uint64(336094),\n\t\t\t\t\"QueryMisses\":  uint64(369336),\n\t\t\t\t\"TreeMemInUse\": uint64(392128),\n\t\t\t\t\"TreeMemMax\":   uint64(828966),\n\t\t\t\t\"TreeMemTotal\": uint64(1464363),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"resstats\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"BadEDNSVersion\":  uint64(0),\n\t\t\t\t\"BucketSize\":      uint64(31),\n\t\t\t\t\"EDNS0Fail\":       uint64(0),\n\t\t\t\t\"FORMERR\":         uint64(0),\n\t\t\t\t\"GlueFetchv4\":     uint64(0),\n\t\t\t\t\"GlueFetchv4Fail\": uint64(0),\n\t\t\t\t\"GlueFetchv6\":     uint64(0),\n\t\t\t\t\"GlueFetchv6Fail\": uint64(0),\n\t\t\t\t\"Lame\":            uint64(0),\n\t\t\t\t\"Mismatch\":        uint64(0),\n\t\t\t\t\"NXDOMAIN\":        uint64(0),\n\t\t\t\t\"NumFetch\":        uint64(0),\n\t\t\t\t\"OtherError\":      uint64(0),\n\t\t\t\t\"QryRTT10\":        uint64(0),\n\t\t\t\t\"QryRTT100\":       uint64(0),\n\t\t\t\t\"QryRTT1600\":      uint64(0),\n\t\t\t\t\"QryRTT1600+\":     uint64(0),\n\t\t\t\t\"QryRTT500\":       uint64(0),\n\t\t\t\t\"QryRTT800\":       uint64(0),\n\t\t\t\t\"QueryAbort\":      uint64(0),\n\t\t\t\t\"QueryCurTCP\":     uint64(0),\n\t\t\t\t\"QueryCurUDP\":     uint64(0),\n\t\t\t\t\"QuerySockFail\":   uint64(0),\n\t\t\t\t\"QueryTimeout\":    uint64(0),\n\t\t\t\t\"Queryv4\":         uint64(0),\n\t\t\t\t\"Queryv6\":         uint64(0),\n\t\t\t\t\"REFUSED\":         uint64(0),\n\t\t\t\t\"Responsev4\":      uint64(0),\n\t\t\t\t\"Responsev6\":      uint64(0),\n\t\t\t\t\"Retry\":           uint64(0),\n\t\t\t\t\"SERVFAIL\":        uint64(0),\n\t\t\t\t\"ServerQuota\":     uint64(0),\n\t\t\t\t\"SitClientOk\":     uint64(0),\n\t\t\t\t\"SitClientOut\":    uint64(0),\n\t\t\t\t\"SitIn\":           uint64(0),\n\t\t\t\t\"SitOut\":          uint64(0),\n\t\t\t\t\"Truncated\":       uint64(0),\n\t\t\t\t\"ValAttempt\":      uint64(0),\n\t\t\t\t\"ValFail\":         uint64(0),\n\t\t\t\t\"ValNegOk\":        uint64(0),\n\t\t\t\t\"ValOk\":           uint64(0),\n\t\t\t\t\"ZoneQuota\":       uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"adbstat\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entriescnt\": uint64(0),\n\t\t\t\t\"namescnt\":   uint64(0),\n\t\t\t\t\"nentries\":   uint64(1021),\n\t\t\t\t\"nnames\":     uint64(1021),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bind_counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\":    url,\n\t\t\t\t\"source\": host,\n\t\t\t\t\"port\":   port,\n\t\t\t\t\"type\":   \"cachestats\",\n\t\t\t\t\"view\":   \"_bind\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"CacheBuckets\": uint64(64),\n\t\t\t\t\"CacheHits\":    uint64(0),\n\t\t\t\t\"CacheMisses\":  uint64(0),\n\t\t\t\t\"CacheNodes\":   uint64(0),\n\t\t\t\t\"DeleteLRU\":    uint64(0),\n\t\t\t\t\"DeleteTTL\":    uint64(0),\n\t\t\t\t\"HeapMemInUse\": uint64(1024),\n\t\t\t\t\"HeapMemMax\":   uint64(1024),\n\t\t\t\t\"HeapMemTotal\": uint64(262144),\n\t\t\t\t\"QueryHits\":    uint64(0),\n\t\t\t\t\"QueryMisses\":  uint64(0),\n\t\t\t\t\"TreeMemInUse\": uint64(29608),\n\t\t\t\t\"TreeMemMax\":   uint64(29608),\n\t\t\t\t\"TreeMemTotal\": uint64(287392),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Gather and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestBindUnparsableURL(t *testing.T) {\n\tb := Bind{\n\t\tUrls:          []string{\"://example.com\"},\n\t\tCountersAsInt: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(b.Gather)\n\trequire.Contains(t, err.Error(), \"unable to parse address\")\n}\n"
  },
  {
    "path": "plugins/inputs/bind/json_stats.go",
    "content": "package bind\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\ntype jsonStats struct {\n\tOpCodes   map[string]int\n\tQTypes    map[string]int\n\tRCodes    map[string]int\n\tZoneStats map[string]int\n\tNSStats   map[string]int\n\tSockStats map[string]int\n\tViews     map[string]jsonView\n\tMemory    jsonMemory\n}\n\ntype jsonMemory struct {\n\tTotalUse    int64\n\tInUse       int64\n\tBlockSize   int64\n\tContextSize int64\n\tLost        int64\n\tContexts    []struct {\n\t\tID    string\n\t\tName  string\n\t\tTotal int64\n\t\tInUse int64\n\t}\n}\n\ntype jsonView struct {\n\tResolver map[string]map[string]int\n}\n\n// addJSONCounter adds a counter array to a Telegraf Accumulator, with the specified tags.\nfunc addJSONCounter(acc telegraf.Accumulator, commonTags map[string]string, stats map[string]int) {\n\tgrouper := metric.NewSeriesGrouper()\n\tts := time.Now()\n\tfor name, value := range stats {\n\t\tif commonTags[\"type\"] == \"opcode\" && strings.HasPrefix(name, \"RESERVED\") {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := make(map[string]string)\n\n\t\t// Create local copy of tags since maps are reference types\n\t\tfor k, v := range commonTags {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\tgrouper.Add(\"bind_counter\", tags, ts, name, value)\n\t}\n\n\t// Add grouped metrics\n\tfor _, groupedMetric := range grouper.Metrics() {\n\t\tacc.AddMetric(groupedMetric)\n\t}\n}\n\n// addStatsJson walks a jsonStats struct and adds the values to the telegraf.Accumulator.\nfunc (b *Bind) addStatsJSON(stats jsonStats, acc telegraf.Accumulator, urlTag string) {\n\tgrouper := metric.NewSeriesGrouper()\n\tts := time.Now()\n\ttags := map[string]string{\"url\": urlTag}\n\thost, port, err := net.SplitHostPort(urlTag)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t}\n\ttags[\"source\"] = host\n\ttags[\"port\"] = port\n\n\t// Opcodes\n\ttags[\"type\"] = \"opcode\"\n\taddJSONCounter(acc, tags, stats.OpCodes)\n\n\t// RCodes stats\n\ttags[\"type\"] = \"rcode\"\n\taddJSONCounter(acc, tags, stats.RCodes)\n\n\t// Query RDATA types\n\ttags[\"type\"] = \"qtype\"\n\taddJSONCounter(acc, tags, stats.QTypes)\n\n\t// Nameserver stats\n\ttags[\"type\"] = \"nsstat\"\n\taddJSONCounter(acc, tags, stats.NSStats)\n\n\t// Socket statistics\n\ttags[\"type\"] = \"sockstat\"\n\taddJSONCounter(acc, tags, stats.SockStats)\n\n\t// Zonestats\n\ttags[\"type\"] = \"zonestat\"\n\taddJSONCounter(acc, tags, stats.ZoneStats)\n\n\t// Memory stats\n\tfields := map[string]interface{}{\n\t\t\"total_use\":    stats.Memory.TotalUse,\n\t\t\"in_use\":       stats.Memory.InUse,\n\t\t\"block_size\":   stats.Memory.BlockSize,\n\t\t\"context_size\": stats.Memory.ContextSize,\n\t\t\"lost\":         stats.Memory.Lost,\n\t}\n\tacc.AddGauge(\"bind_memory\", fields, map[string]string{\"url\": urlTag, \"source\": host, \"port\": port})\n\n\t// Detailed, per-context memory stats\n\tif b.GatherMemoryContexts {\n\t\tfor _, c := range stats.Memory.Contexts {\n\t\t\ttags := map[string]string{\"url\": urlTag, \"id\": c.ID, \"name\": c.Name, \"source\": host, \"port\": port}\n\t\t\tfields := map[string]interface{}{\"total\": c.Total, \"in_use\": c.InUse}\n\n\t\t\tacc.AddGauge(\"bind_memory_context\", fields, tags)\n\t\t}\n\t}\n\n\t// Detailed, per-view stats\n\tif b.GatherViews {\n\t\tfor vName, view := range stats.Views {\n\t\t\tfor cntrType, counters := range view.Resolver {\n\t\t\t\tfor cntrName, value := range counters {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"url\":    urlTag,\n\t\t\t\t\t\t\"source\": host,\n\t\t\t\t\t\t\"port\":   port,\n\t\t\t\t\t\t\"view\":   vName,\n\t\t\t\t\t\t\"type\":   cntrType,\n\t\t\t\t\t}\n\n\t\t\t\t\tgrouper.Add(\"bind_counter\", tags, ts, cntrName, value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add grouped metrics\n\tfor _, groupedMetric := range grouper.Metrics() {\n\t\tacc.AddMetric(groupedMetric)\n\t}\n}\n\n// readStatsJSON takes a base URL to probe, and requests the individual statistics blobs that we\n// are interested in. These individual blobs have a combined size which is significantly smaller\n// than if we requested everything at once (e.g. taskmgr and socketmgr can be omitted).\nfunc (b *Bind) readStatsJSON(addr *url.URL, acc telegraf.Accumulator) error {\n\tvar stats jsonStats\n\n\t// Progressively build up full jsonStats struct by parsing the individual HTTP responses\n\tfor _, suffix := range [...]string{\"/server\", \"/net\", \"/mem\"} {\n\t\terr := func() error {\n\t\t\tscrapeURL := addr.String() + suffix\n\n\t\t\tresp, err := b.client.Get(scrapeURL)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer resp.Body.Close()\n\n\t\t\tif resp.StatusCode != http.StatusOK {\n\t\t\t\treturn fmt.Errorf(\"%s returned HTTP status: %s\", scrapeURL, resp.Status)\n\t\t\t}\n\n\t\t\tif err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to decode JSON blob: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tb.addStatsJSON(stats, acc, addr.Host)\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/bind/sample.conf",
    "content": "# Read BIND nameserver XML statistics\n[[inputs.bind]]\n  ## An array of BIND XML statistics URI to gather stats.\n  ## Default is \"http://localhost:8053/xml/v3\".\n  # urls = [\"http://localhost:8053/xml/v3\"]\n  # gather_memory_contexts = false\n  # gather_views = false\n\n  ## Report xml v3 counters as integers instead of unsigned for backward\n  ## compatibility. Set this to false as soon as possible!\n  ## Values are clipped if exceeding the integer range.\n  # report_counters_as_int = true\n\n  ## Timeout for http requests made by bind nameserver\n  # timeout = \"4s\"\n"
  },
  {
    "path": "plugins/inputs/bind/testdata/json/v1/mem",
    "content": "{\n  \"json-stats-version\":\"1.2\",\n  \"boot-time\":\"2017-07-28T13:24:53Z\",\n  \"config-time\":\"2017-07-28T13:24:53Z\",\n  \"current-time\":\"2017-07-28T15:33:07Z\",\n  \"memory\":{\n    \"TotalUse\":18206566,\n    \"InUse\":3064368,\n    \"BlockSize\":13893632,\n    \"ContextSize\":3685480,\n    \"Lost\":0,\n    \"contexts\":[\n      {\n        \"id\":\"0x55fb2e042de0\",\n        \"name\":\"main\",\n        \"references\":202,\n        \"total\":2693003,\n        \"inuse\":1454904,\n        \"maxinuse\":1508072,\n        \"blocksize\":786432,\n        \"pools\":40,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x55fb2e0507e0\",\n        \"name\":\"dst\",\n        \"references\":1,\n        \"total\":387478,\n        \"inuse\":91776,\n        \"maxinuse\":97208,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x55fb2e0938e0\",\n        \"name\":\"zonemgr-pool\",\n        \"references\":113,\n        \"total\":742986,\n        \"inuse\":143776,\n        \"maxinuse\":313961,\n        \"blocksize\":262144,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d00017d0\",\n        \"name\":\"threadkey\",\n        \"references\":1,\n        \"total\":0,\n        \"inuse\":0,\n        \"maxinuse\":0,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d00475f0\",\n        \"name\":\"client\",\n        \"references\":3,\n        \"total\":267800,\n        \"inuse\":8760,\n        \"maxinuse\":8760,\n        \"blocksize\":262144,\n        \"pools\":2,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d00dfca0\",\n        \"name\":\"cache\",\n        \"references\":8,\n        \"total\":288938,\n        \"inuse\":83650,\n        \"maxinuse\":83842,\n        \"blocksize\":262144,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d00eaa30\",\n        \"name\":\"cache_heap\",\n        \"references\":18,\n        \"total\":393216,\n        \"inuse\":132096,\n        \"maxinuse\":132096,\n        \"blocksize\":262144,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d01094e0\",\n        \"name\":\"res0\",\n        \"references\":1,\n        \"total\":262144,\n        \"inuse\":0,\n        \"maxinuse\":22048,\n        \"blocksize\":262144,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d0114270\",\n        \"name\":\"res1\",\n        \"references\":1,\n        \"total\":0,\n        \"inuse\":0,\n        \"maxinuse\":0,\n        \"blocksize\":0,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      },\n      {\n        \"id\":\"0x7f19d011f000\",\n        \"name\":\"res2\",\n        \"references\":1,\n        \"total\":0,\n        \"inuse\":0,\n        \"maxinuse\":0,\n        \"blocksize\":0,\n        \"pools\":0,\n        \"hiwater\":0,\n        \"lowater\":0\n      }\n    ]\n  }\n}"
  },
  {
    "path": "plugins/inputs/bind/testdata/json/v1/net",
    "content": "{\n  \"json-stats-version\":\"1.2\",\n  \"boot-time\":\"2017-07-28T13:24:53Z\",\n  \"config-time\":\"2017-07-28T13:24:53Z\",\n  \"current-time\":\"2017-07-28T15:33:07Z\",\n  \"sockstats\":{\n    \"UDP4Open\":335,\n    \"UDP6Open\":113,\n    \"TCP4Open\":118,\n    \"TCP6Open\":2,\n    \"RawOpen\":1,\n    \"UDP4Close\":333,\n    \"UDP6Close\":112,\n    \"TCP4Close\":119,\n    \"UDP6ConnFail\":112,\n    \"UDP4Conn\":333,\n    \"TCP4Conn\":114,\n    \"TCP4Accept\":6,\n    \"UDP6SendErr\":112,\n    \"UDP4RecvErr\":1,\n    \"UDP4Active\":2,\n    \"UDP6Active\":1,\n    \"TCP4Active\":10,\n    \"TCP6Active\":2,\n    \"RawActive\":1\n  },\n  \"socketmgr\":{\n    \"sockets\":[\n      {\n        \"id\":\"0x7f19dd849010\",\n        \"references\":1,\n        \"type\":\"not-initialized\",\n        \"local-address\":\"<unknown address, family 16>\",\n        \"states\":[\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd849268\",\n        \"references\":1,\n        \"type\":\"tcp\",\n        \"local-address\":\"0.0.0.0#8053\",\n        \"states\":[\n          \"listener\",\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd849718\",\n        \"references\":2,\n        \"type\":\"udp\",\n        \"local-address\":\"::#53\",\n        \"states\":[\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd849970\",\n        \"references\":2,\n        \"type\":\"tcp\",\n        \"local-address\":\"::#53\",\n        \"states\":[\n          \"listener\",\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd849bc8\",\n        \"references\":2,\n        \"type\":\"udp\",\n        \"local-address\":\"127.0.0.1#53\",\n        \"states\":[\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd6f4010\",\n        \"references\":2,\n        \"type\":\"tcp\",\n        \"local-address\":\"127.0.0.1#53\",\n        \"states\":[\n          \"listener\",\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd6f4718\",\n        \"references\":1,\n        \"type\":\"tcp\",\n        \"local-address\":\"127.0.0.1#953\",\n        \"states\":[\n          \"listener\",\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19dd6f4bc8\",\n        \"references\":1,\n        \"type\":\"tcp\",\n        \"local-address\":\"::1#953\",\n        \"states\":[\n          \"listener\",\n          \"bound\"\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fb7970\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fb7bc8\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fc7010\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fc74c0\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fc7718\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fc7bc8\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd1010\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd1268\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd14c0\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd1718\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd1970\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd1bc8\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd9010\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fda4c0\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd9bc8\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fda268\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd9970\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fda010\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      },\n      {\n        \"id\":\"0x7f19d4fd9718\",\n        \"references\":1,\n        \"type\":\"udp\",\n        \"states\":[\n        ]\n      }\n    ]\n  }\n}"
  },
  {
    "path": "plugins/inputs/bind/testdata/json/v1/server",
    "content": "{\n  \"json-stats-version\":\"1.2\",\n  \"boot-time\":\"2017-07-28T13:24:53Z\",\n  \"config-time\":\"2017-07-28T13:24:53Z\",\n  \"current-time\":\"2017-07-28T15:33:07Z\",\n  \"opcodes\":{\n    \"QUERY\":13,\n    \"IQUERY\":0,\n    \"STATUS\":0,\n    \"RESERVED3\":0,\n    \"NOTIFY\":0,\n    \"UPDATE\":0,\n    \"RESERVED6\":0,\n    \"RESERVED7\":0,\n    \"RESERVED8\":0,\n    \"RESERVED9\":0,\n    \"RESERVED10\":0,\n    \"RESERVED11\":0,\n    \"RESERVED12\":0,\n    \"RESERVED13\":0,\n    \"RESERVED14\":0,\n    \"RESERVED15\":0\n  },\n  \"rcodes\":{\n\t\"NOERROR\":1732,\n\t\"FORMERR\":0,\n\t\"SERVFAIL\":6,\n\t\"NXDOMAIN\":200,\n\t\"NOTIMP\":0,\n\t\"REFUSED\":0,\n\t\"YXDOMAIN\":0,\n\t\"YXRRSET\":0,\n\t\"NXRRSET\":0,\n\t\"NOTAUTH\":0,\n\t\"NOTZONE\":0,\n\t\"RESERVED11\":0,\n\t\"RESERVED12\":0,\n\t\"RESERVED13\":0,\n\t\"RESERVED14\":0,\n\t\"RESERVED15\":0,\n\t\"BADVERS\":0,\n\t\"17\":0,\n\t\"18\":0,\n\t\"19\":0,\n\t\"20\":0,\n\t\"21\":0,\n\t\"22\":0,\n\t\"BADCOOKIE\":0\n  },\n  \"qtypes\":{\n    \"A\":2,\n    \"PTR\":7,\n    \"AAAA\":2,\n    \"SRV\":2\n  },\n  \"nsstats\":{\n    \"Requestv4\":13,\n    \"Response\":12,\n    \"QrySuccess\":6,\n    \"QryAuthAns\":1,\n    \"QryNoauthAns\":10,\n    \"QryNxrrset\":1,\n    \"QrySERVFAIL\":1,\n    \"QryNXDOMAIN\":4,\n    \"QryRecursion\":12,\n    \"QryDuplicate\":1,\n    \"QryUDP\":13\n  },\n  \"zonestats\":{\n\t\"NotifyOutv4\":8,\n\t\"NotifyInv4\":5,\n\t\"SOAOutv4\":5\n  },\n  \"views\":{\n    \"_default\":{\n      \"resolver\":{\n        \"stats\":{\n          \"Queryv4\":447,\n          \"Queryv6\":112,\n          \"Responsev4\":444,\n          \"NXDOMAIN\":3,\n          \"Truncated\":114,\n          \"Retry\":242,\n          \"QueryTimeout\":3,\n          \"GlueFetchv4\":61,\n          \"GlueFetchv6\":68,\n          \"GlueFetchv6Fail\":24,\n          \"ValAttempt\":36,\n          \"ValOk\":27,\n          \"ValNegOk\":9,\n          \"QryRTT100\":287,\n          \"QryRTT500\":152,\n          \"QryRTT800\":4,\n          \"BucketSize\":31\n        },\n        \"qtypes\":{\n          \"A\":220,\n          \"NS\":19,\n          \"PTR\":22,\n          \"AAAA\":233,\n          \"SRV\":14,\n          \"DS\":27,\n          \"DNSKEY\":24\n        },\n        \"cache\":{\n          \"A\":150,\n          \"NS\":44,\n          \"PTR\":3,\n          \"AAAA\":104,\n          \"DS\":23,\n          \"RRSIG\":94,\n          \"NSEC\":8,\n          \"DNSKEY\":7,\n          \"!AAAA\":23,\n          \"!DS\":5,\n          \"NXDOMAIN\":1\n        },\n        \"cachestats\":{\n          \"CacheHits\":1675,\n          \"CacheMisses\":44,\n          \"QueryHits\":17,\n          \"QueryMisses\":12,\n          \"DeleteLRU\":0,\n          \"DeleteTTL\":16,\n          \"CacheNodes\":219,\n          \"CacheBuckets\":129,\n          \"TreeMemTotal\":551082,\n          \"TreeMemInUse\":150704,\n          \"HeapMemMax\":132096,\n          \"HeapMemTotal\":393216,\n          \"HeapMemInUse\":132096\n        },\n        \"adb\":{\n          \"nentries\":1021,\n          \"entriescnt\":254,\n          \"nnames\":1021,\n          \"namescnt\":195\n        }\n      }\n    },\n    \"_bind\":{\n      \"resolver\":{\n        \"stats\":{\n          \"BucketSize\":31\n        },\n        \"qtypes\":{\n        },\n        \"cache\":{\n        },\n        \"cachestats\":{\n          \"CacheHits\":0,\n          \"CacheMisses\":0,\n          \"QueryHits\":0,\n          \"QueryMisses\":0,\n          \"DeleteLRU\":0,\n          \"DeleteTTL\":0,\n          \"CacheNodes\":0,\n          \"CacheBuckets\":64,\n          \"TreeMemTotal\":287392,\n          \"TreeMemInUse\":29608,\n          \"HeapMemMax\":1024,\n          \"HeapMemTotal\":262144,\n          \"HeapMemInUse\":1024\n        },\n        \"adb\":{\n          \"nentries\":1021,\n          \"nnames\":1021\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/bind/testdata/xml/v2",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"/bind9.xsl\"?>\n<isc version=\"1.0\">\n  <bind>\n    <statistics version=\"2.2\">\n      <views>\n        <view>\n          <name>_default</name>\n          <rdtype>\n            <name>A</name>\n            <counter>2936881</counter>\n          </rdtype>\n          <rdtype>\n            <name>NS</name>\n            <counter>28994</counter>\n          </rdtype>\n          <rdtype>\n            <name>CNAME</name>\n            <counter>26</counter>\n          </rdtype>\n          <rdtype>\n            <name>SOA</name>\n            <counter>15131</counter>\n          </rdtype>\n          <rdtype>\n            <name>PTR</name>\n            <counter>47924</counter>\n          </rdtype>\n          <rdtype>\n            <name>MX</name>\n            <counter>1884</counter>\n          </rdtype>\n          <rdtype>\n            <name>TXT</name>\n            <counter>6486</counter>\n          </rdtype>\n          <rdtype>\n            <name>AAAA</name>\n            <counter>949781</counter>\n          </rdtype>\n          <rdtype>\n            <name>SRV</name>\n            <counter>14740</counter>\n          </rdtype>\n          <rdtype>\n            <name>NAPTR</name>\n            <counter>1606</counter>\n          </rdtype>\n          <rdtype>\n            <name>DS</name>\n            <counter>25</counter>\n          </rdtype>\n          <rdtype>\n            <name>SSHFP</name>\n            <counter>185</counter>\n          </rdtype>\n          <rdtype>\n            <name>DNSKEY</name>\n            <counter>13</counter>\n          </rdtype>\n          <rdtype>\n            <name>ANY</name>\n            <counter>1</counter>\n          </rdtype>\n          <resstat>\n            <name>Queryv4</name>\n            <counter>3765426</counter>\n          </resstat>\n          <resstat>\n            <name>Queryv6</name>\n            <counter>238251</counter>\n          </resstat>\n          <resstat>\n            <name>Responsev4</name>\n            <counter>3716142</counter>\n          </resstat>\n          <resstat>\n            <name>Responsev6</name>\n            <counter>1</counter>\n          </resstat>\n          <resstat>\n            <name>NXDOMAIN</name>\n            <counter>100052</counter>\n          </resstat>\n          <resstat>\n            <name>SERVFAIL</name>\n            <counter>5894</counter>\n          </resstat>\n          <resstat>\n            <name>FORMERR</name>\n            <counter>2041</counter>\n          </resstat>\n          <resstat>\n            <name>OtherError</name>\n            <counter>14801</counter>\n          </resstat>\n          <resstat>\n            <name>EDNS0Fail</name>\n            <counter>2615</counter>\n          </resstat>\n          <resstat>\n            <name>Mismatch</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Truncated</name>\n            <counter>598</counter>\n          </resstat>\n          <resstat>\n            <name>Lame</name>\n            <counter>117</counter>\n          </resstat>\n          <resstat>\n            <name>Retry</name>\n            <counter>383343</counter>\n          </resstat>\n          <resstat>\n            <name>QueryAbort</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QuerySockFail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QueryTimeout</name>\n            <counter>50874</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv4</name>\n            <counter>260749</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv6</name>\n            <counter>225310</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv4Fail</name>\n            <counter>5756</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv6Fail</name>\n            <counter>141500</counter>\n          </resstat>\n          <resstat>\n            <name>ValAttempt</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValOk</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValNegOk</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValFail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT10</name>\n            <counter>458176</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT100</name>\n            <counter>3010133</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT500</name>\n            <counter>244312</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT800</name>\n            <counter>1275</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT1600</name>\n            <counter>361</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT1600+</name>\n            <counter>236</counter>\n          </resstat>\n          <cache name=\"_default\">\n            <rrset>\n              <name>A</name>\n              <counter>2700</counter>\n            </rrset>\n            <rrset>\n              <name>NS</name>\n              <counter>759</counter>\n            </rrset>\n            <rrset>\n              <name>CNAME</name>\n              <counter>486</counter>\n            </rrset>\n            <rrset>\n              <name>SOA</name>\n              <counter>2</counter>\n            </rrset>\n            <rrset>\n              <name>PTR</name>\n              <counter>6</counter>\n            </rrset>\n            <rrset>\n              <name>TXT</name>\n              <counter>2</counter>\n            </rrset>\n            <rrset>\n              <name>AAAA</name>\n              <counter>629</counter>\n            </rrset>\n            <rrset>\n              <name>SRV</name>\n              <counter>1</counter>\n            </rrset>\n            <rrset>\n              <name>DS</name>\n              <counter>48</counter>\n            </rrset>\n            <rrset>\n              <name>RRSIG</name>\n              <counter>203</counter>\n            </rrset>\n            <rrset>\n              <name>NSEC</name>\n              <counter>22</counter>\n            </rrset>\n            <rrset>\n              <name>DNSKEY</name>\n              <counter>1</counter>\n            </rrset>\n            <rrset>\n              <name>!A</name>\n              <counter>6</counter>\n            </rrset>\n            <rrset>\n              <name>!SOA</name>\n              <counter>26</counter>\n            </rrset>\n            <rrset>\n              <name>!AAAA</name>\n              <counter>84</counter>\n            </rrset>\n            <rrset>\n              <name>!NAPTR</name>\n              <counter>3</counter>\n            </rrset>\n            <rrset>\n              <name>NXDOMAIN</name>\n              <counter>143</counter>\n            </rrset>\n          </cache>\n        </view>\n        <view>\n          <name>_bind</name>\n          <resstat>\n            <name>Queryv4</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Queryv6</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Responsev4</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Responsev6</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>NXDOMAIN</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>SERVFAIL</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>FORMERR</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>OtherError</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>EDNS0Fail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Mismatch</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Truncated</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Lame</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>Retry</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QueryAbort</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QuerySockFail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QueryTimeout</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv4</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv6</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv4Fail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>GlueFetchv6Fail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValAttempt</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValOk</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValNegOk</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>ValFail</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT10</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT100</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT500</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT800</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT1600</name>\n            <counter>0</counter>\n          </resstat>\n          <resstat>\n            <name>QryRTT1600+</name>\n            <counter>0</counter>\n          </resstat>\n          <cache name=\"_bind\"/>\n        </view>\n      </views>\n      <server>\n        <boot-time>2016-10-02T18:45:00Z</boot-time>\n        <current-time>2016-10-23T19:27:48Z</current-time>\n        <requests>\n          <opcode>\n            <name>QUERY</name>\n            <counter>102312374</counter>\n          </opcode>\n          <opcode>\n            <name>UPDATE</name>\n            <counter>238</counter>\n          </opcode>\n        </requests>\n        <queries-in>\n          <rdtype>\n            <name>A</name>\n            <counter>58951432</counter>\n          </rdtype>\n          <rdtype>\n            <name>NS</name>\n            <counter>1999</counter>\n          </rdtype>\n          <rdtype>\n            <name>CNAME</name>\n            <counter>531</counter>\n          </rdtype>\n          <rdtype>\n            <name>SOA</name>\n            <counter>100415</counter>\n          </rdtype>\n          <rdtype>\n            <name>PTR</name>\n            <counter>4211487</counter>\n          </rdtype>\n          <rdtype>\n            <name>MX</name>\n            <counter>441155</counter>\n          </rdtype>\n          <rdtype>\n            <name>TXT</name>\n            <counter>34628</counter>\n          </rdtype>\n          <rdtype>\n            <name>AAAA</name>\n            <counter>37786321</counter>\n          </rdtype>\n          <rdtype>\n            <name>SRV</name>\n            <counter>741082</counter>\n          </rdtype>\n          <rdtype>\n            <name>NAPTR</name>\n            <counter>39137</counter>\n          </rdtype>\n          <rdtype>\n            <name>DS</name>\n            <counter>584</counter>\n          </rdtype>\n          <rdtype>\n            <name>SSHFP</name>\n            <counter>2987</counter>\n          </rdtype>\n          <rdtype>\n            <name>DNSKEY</name>\n            <counter>452</counter>\n          </rdtype>\n          <rdtype>\n            <name>IXFR</name>\n            <counter>157</counter>\n          </rdtype>\n          <rdtype>\n            <name>ANY</name>\n            <counter>7</counter>\n          </rdtype>\n        </queries-in>\n        <nsstat>\n          <name>Requestv4</name>\n          <counter>102312611</counter>\n        </nsstat>\n        <nsstat>\n          <name>Requestv6</name>\n          <counter>1</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqEdns0</name>\n          <counter>441758</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqBadEDNSVer</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqTSIG</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqSIG0</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqBadSIG</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>ReqTCP</name>\n          <counter>1548156</counter>\n        </nsstat>\n        <nsstat>\n          <name>AuthQryRej</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>RecQryRej</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>XfrRej</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateRej</name>\n          <counter>238</counter>\n        </nsstat>\n        <nsstat>\n          <name>Response</name>\n          <counter>102301560</counter>\n        </nsstat>\n        <nsstat>\n          <name>TruncatedResp</name>\n          <counter>3787</counter>\n        </nsstat>\n        <nsstat>\n          <name>RespEDNS0</name>\n          <counter>441748</counter>\n        </nsstat>\n        <nsstat>\n          <name>RespTSIG</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>RespSIG0</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>QrySuccess</name>\n          <counter>63811668</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryAuthAns</name>\n          <counter>72180718</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryNoauthAns</name>\n          <counter>30106182</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryReferral</name>\n          <counter>3</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryNxrrset</name>\n          <counter>24423133</counter>\n        </nsstat>\n        <nsstat>\n          <name>QrySERVFAIL</name>\n          <counter>14422</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryFORMERR</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryNXDOMAIN</name>\n          <counter>14052096</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryRecursion</name>\n          <counter>2104239</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryDuplicate</name>\n          <counter>10879</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryDropped</name>\n          <counter>16</counter>\n        </nsstat>\n        <nsstat>\n          <name>QryFailure</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>XfrReqDone</name>\n          <counter>157</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateReqFwd</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateRespFwd</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateFwdFail</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateDone</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateFail</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>UpdateBadPrereq</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>RPZRewrites</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>RateDropped</name>\n          <counter>0</counter>\n        </nsstat>\n        <nsstat>\n          <name>RateSlipped</name>\n          <counter>0</counter>\n        </nsstat>\n        <zonestat>\n          <name>NotifyOutv4</name>\n          <counter>663</counter>\n        </zonestat>\n        <zonestat>\n          <name>NotifyOutv6</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>NotifyInv4</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>NotifyInv6</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>NotifyRej</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>SOAOutv4</name>\n          <counter>386</counter>\n        </zonestat>\n        <zonestat>\n          <name>SOAOutv6</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>AXFRReqv4</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>AXFRReqv6</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>IXFRReqv4</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>IXFRReqv6</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>XfrSuccess</name>\n          <counter>0</counter>\n        </zonestat>\n        <zonestat>\n          <name>XfrFail</name>\n          <counter>0</counter>\n        </zonestat>\n        <resstat>\n          <name>Mismatch</name>\n          <counter>2</counter>\n        </resstat>\n        <sockstat>\n          <name>UDP4Open</name>\n          <counter>3765532</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6Open</name>\n          <counter>238269</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4Open</name>\n          <counter>602</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6Open</name>\n          <counter>2</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixOpen</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4OpenFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6OpenFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4OpenFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6OpenFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixOpenFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4Close</name>\n          <counter>3765528</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6Close</name>\n          <counter>238267</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4Close</name>\n          <counter>1548268</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6Close</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixClose</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FDWatchClose</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4BindFail</name>\n          <counter>219</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6BindFail</name>\n          <counter>16</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4BindFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6BindFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixBindFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FdwatchBindFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4ConnFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6ConnFail</name>\n          <counter>238250</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4ConnFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6ConnFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixConnFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FDwatchConnFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4Conn</name>\n          <counter>3764828</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6Conn</name>\n          <counter>1</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4Conn</name>\n          <counter>590</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6Conn</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixConn</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FDwatchConn</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4AcceptFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6AcceptFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixAcceptFail</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4Accept</name>\n          <counter>1547672</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6Accept</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixAccept</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4SendErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6SendErr</name>\n          <counter>238250</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4SendErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6SendErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixSendErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FDwatchSendErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP4RecvErr</name>\n          <counter>1650</counter>\n        </sockstat>\n        <sockstat>\n          <name>UDP6RecvErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP4RecvErr</name>\n          <counter>1</counter>\n        </sockstat>\n        <sockstat>\n          <name>TCP6RecvErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>UnixRecvErr</name>\n          <counter>0</counter>\n        </sockstat>\n        <sockstat>\n          <name>FDwatchRecvErr</name>\n          <counter>0</counter>\n        </sockstat>\n      </server>\n      <memory>\n        <contexts>\n          <context>\n            <id>0x7f8a94e061d0</id>\n            <name>main</name>\n            <references>229</references>\n            <total>5002528</total>\n            <inuse>3662792</inuse>\n            <maxinuse>4848264</maxinuse>\n            <blocksize>2359296</blocksize>\n            <pools>75</pools>\n            <hiwater>0</hiwater>\n            <lowater>0</lowater>\n          </context>\n          <context>\n            <id>0x7f8a94e13830</id>\n            <name>dst</name>\n            <references>1</references>\n            <total>133486</total>\n            <inuse>96456</inuse>\n            <maxinuse>102346</maxinuse>\n            <blocksize>-</blocksize>\n            <pools>0</pools>\n            <hiwater>0</hiwater>\n            <lowater>0</lowater>\n          </context>\n          <context>\n            <id>0x7f8a94e401c0</id>\n            <name>zonemgr-pool</name>\n            <references>501</references>\n            <total>6339848</total>\n            <inuse>4384240</inuse>\n            <maxinuse>5734049</maxinuse>\n            <blocksize>6029312</blocksize>\n            <pools>0</pools>\n            <hiwater>0</hiwater>\n            <lowater>0</lowater>\n          </context>\n        </contexts>\n        <summary>\n          <TotalUse>81804609</TotalUse>\n          <InUse>20772579</InUse>\n          <BlockSize>77070336</BlockSize>\n          <ContextSize>6663840</ContextSize>\n          <Lost>0</Lost>\n        </summary>\n      </memory>\n    </statistics>\n  </bind>\n</isc>\n"
  },
  {
    "path": "plugins/inputs/bind/testdata/xml/v3/mem",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"/bind9.xsl\"?>\n<statistics version=\"3.6\">\n  <server>\n    <boot-time>2017-07-21T11:53:28Z</boot-time>\n    <config-time>2017-07-21T11:53:28Z</config-time>\n    <current-time>2017-07-25T23:47:08Z</current-time>\n  </server>\n  <views>\n  </views>\n  <memory>\n    <contexts>\n      <context>\n        <id>0x55fb2e042de0</id>\n        <name>main</name>\n        <references>202</references>\n        <total>2706043</total>\n        <inuse>1454904</inuse>\n        <maxinuse>1508072</maxinuse>\n        <blocksize>786432</blocksize>\n        <pools>40</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x55fb2e0507e0</id>\n        <name>dst</name>\n        <references>1</references>\n        <total>387478</total>\n        <inuse>91776</inuse>\n        <maxinuse>97208</maxinuse>\n        <blocksize>-</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x55fb2e0938e0</id>\n        <name>zonemgr-pool</name>\n        <references>113</references>\n        <total>742986</total>\n        <inuse>143776</inuse>\n        <maxinuse>313961</maxinuse>\n        <blocksize>262144</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d00017d0</id>\n        <name>threadkey</name>\n        <references>1</references>\n        <total>0</total>\n        <inuse>0</inuse>\n        <maxinuse>0</maxinuse>\n        <blocksize>-</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d00475f0</id>\n        <name>client</name>\n        <references>3</references>\n        <total>267800</total>\n        <inuse>8760</inuse>\n        <maxinuse>8760</maxinuse>\n        <blocksize>262144</blocksize>\n        <pools>2</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d00dfca0</id>\n        <name>cache</name>\n        <references>8</references>\n        <total>288938</total>\n        <inuse>83650</inuse>\n        <maxinuse>83842</maxinuse>\n        <blocksize>262144</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d00eaa30</id>\n        <name>cache_heap</name>\n        <references>18</references>\n        <total>393216</total>\n        <inuse>132096</inuse>\n        <maxinuse>132096</maxinuse>\n        <blocksize>262144</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d01094e0</id>\n        <name>res0</name>\n        <references>1</references>\n        <total>262144</total>\n        <inuse>0</inuse>\n        <maxinuse>22048</maxinuse>\n        <blocksize>262144</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d0114270</id>\n        <name>res1</name>\n        <references>1</references>\n        <total>0</total>\n        <inuse>0</inuse>\n        <maxinuse>0</maxinuse>\n        <blocksize>0</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n      <context>\n        <id>0x7f19d011f000</id>\n        <name>res2</name>\n        <references>1</references>\n        <total>0</total>\n        <inuse>0</inuse>\n        <maxinuse>0</maxinuse>\n        <blocksize>0</blocksize>\n        <pools>0</pools>\n        <hiwater>0</hiwater>\n        <lowater>0</lowater>\n      </context>\n    </contexts>\n    <summary>\n      <TotalUse>777821909</TotalUse>\n      <InUse>6000232</InUse>\n      <BlockSize>45875200</BlockSize>\n      <ContextSize>10037400</ContextSize>\n      <Lost>0</Lost>\n    </summary>\n  </memory>\n</statistics>\n"
  },
  {
    "path": "plugins/inputs/bind/testdata/xml/v3/net",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"/bind9.xsl\"?>\n<statistics version=\"3.6\">\n  <server>\n    <boot-time>2017-07-21T11:53:28Z</boot-time>\n    <config-time>2017-07-21T11:53:28Z</config-time>\n    <current-time>2017-07-25T23:47:08Z</current-time>\n    <counters type=\"sockstat\">\n      <counter name=\"UDP4Open\">92542</counter>\n      <counter name=\"UDP6Open\">0</counter>\n      <counter name=\"TCP4Open\">48</counter>\n      <counter name=\"TCP6Open\">0</counter>\n      <counter name=\"UnixOpen\">0</counter>\n      <counter name=\"RawOpen\">1</counter>\n      <counter name=\"UDP4OpenFail\">0</counter>\n      <counter name=\"UDP6OpenFail\">0</counter>\n      <counter name=\"TCP4OpenFail\">0</counter>\n      <counter name=\"TCP6OpenFail\">0</counter>\n      <counter name=\"UnixOpenFail\">0</counter>\n      <counter name=\"RawOpenFail\">0</counter>\n      <counter name=\"UDP4Close\">92538</counter>\n      <counter name=\"UDP6Close\">0</counter>\n      <counter name=\"TCP4Close\">336</counter>\n      <counter name=\"TCP6Close\">0</counter>\n      <counter name=\"UnixClose\">0</counter>\n      <counter name=\"FDWatchClose\">0</counter>\n      <counter name=\"RawClose\">0</counter>\n      <counter name=\"UDP4BindFail\">1</counter>\n      <counter name=\"UDP6BindFail\">0</counter>\n      <counter name=\"TCP4BindFail\">0</counter>\n      <counter name=\"TCP6BindFail\">0</counter>\n      <counter name=\"UnixBindFail\">0</counter>\n      <counter name=\"FdwatchBindFail\">0</counter>\n      <counter name=\"UDP4ConnFail\">0</counter>\n      <counter name=\"UDP6ConnFail\">0</counter>\n      <counter name=\"TCP4ConnFail\">0</counter>\n      <counter name=\"TCP6ConnFail\">0</counter>\n      <counter name=\"UnixConnFail\">0</counter>\n      <counter name=\"FDwatchConnFail\">0</counter>\n      <counter name=\"UDP4Conn\">92535</counter>\n      <counter name=\"UDP6Conn\">0</counter>\n      <counter name=\"TCP4Conn\">44</counter>\n      <counter name=\"TCP6Conn\">0</counter>\n      <counter name=\"UnixConn\">0</counter>\n      <counter name=\"FDwatchConn\">0</counter>\n      <counter name=\"TCP4AcceptFail\">0</counter>\n      <counter name=\"TCP6AcceptFail\">0</counter>\n      <counter name=\"UnixAcceptFail\">0</counter>\n      <counter name=\"TCP4Accept\">293</counter>\n      <counter name=\"TCP6Accept\">0</counter>\n      <counter name=\"UnixAccept\">0</counter>\n      <counter name=\"UDP4SendErr\">0</counter>\n      <counter name=\"UDP6SendErr\">0</counter>\n      <counter name=\"TCP4SendErr\">0</counter>\n      <counter name=\"TCP6SendErr\">0</counter>\n      <counter name=\"UnixSendErr\">0</counter>\n      <counter name=\"FDwatchSendErr\">0</counter>\n      <counter name=\"UDP4RecvErr\">14</counter>\n      <counter name=\"UDP6RecvErr\">0</counter>\n      <counter name=\"TCP4RecvErr\">0</counter>\n      <counter name=\"TCP6RecvErr\">0</counter>\n      <counter name=\"UnixRecvErr\">0</counter>\n      <counter name=\"FDwatchRecvErr\">0</counter>\n      <counter name=\"RawRecvErr\">0</counter>\n      <counter name=\"UDP4Active\">4</counter>\n      <counter name=\"UDP6Active\">0</counter>\n      <counter name=\"TCP4Active\">297</counter>\n      <counter name=\"TCP6Active\">0</counter>\n      <counter name=\"UnixActive\">0</counter>\n      <counter name=\"RawActive\">1</counter>\n    </counters>\n  </server>\n  <views>\n  </views>\n  <socketmgr>\n    <sockets>\n      <socket>\n        <id>0x7f19dd849010</id>\n        <references>1</references>\n        <type>not-initialized</type>\n        <local-address>&lt;unknown address, family 16&gt;</local-address>\n        <states>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd849268</id>\n        <references>1</references>\n        <type>tcp</type>\n        <local-address>0.0.0.0#8053</local-address>\n        <states>\n          <state>listener</state>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd849718</id>\n        <references>2</references>\n        <type>udp</type>\n        <local-address>::#53</local-address>\n        <states>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd849970</id>\n        <references>2</references>\n        <type>tcp</type>\n        <local-address>::#53</local-address>\n        <states>\n          <state>listener</state>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd849bc8</id>\n        <references>2</references>\n        <type>udp</type>\n        <local-address>127.0.0.1#53</local-address>\n        <states>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd6f4010</id>\n        <references>2</references>\n        <type>tcp</type>\n        <local-address>127.0.0.1#53</local-address>\n        <states>\n          <state>listener</state>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd6f4718</id>\n        <references>1</references>\n        <type>tcp</type>\n        <local-address>127.0.0.1#953</local-address>\n        <states>\n          <state>listener</state>\n          <state>bound</state>\n        </states>\n      </socket>\n      <socket>\n        <id>0x7f19dd6f4bc8</id>\n        <references>1</references>\n        <type>tcp</type>\n        <local-address>::1#953</local-address>\n        <states>\n          <state>listener</state>\n          <state>bound</state>\n        </states>\n      </socket>\n    </sockets>\n  </socketmgr>\n</statistics>\n"
  },
  {
    "path": "plugins/inputs/bind/testdata/xml/v3/server",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"/bind9.xsl\"?>\n<statistics version=\"3.6\">\n  <server>\n    <boot-time>2017-07-21T11:53:28Z</boot-time>\n    <config-time>2017-07-21T11:53:28Z</config-time>\n    <current-time>2017-07-25T23:47:08Z</current-time>\n    <counters type=\"opcode\">\n      <counter name=\"QUERY\">74941</counter>\n      <counter name=\"IQUERY\">0</counter>\n      <counter name=\"STATUS\">0</counter>\n      <counter name=\"RESERVED3\">0</counter>\n      <counter name=\"NOTIFY\">0</counter>\n      <counter name=\"UPDATE\">0</counter>\n      <counter name=\"RESERVED6\">0</counter>\n      <counter name=\"RESERVED7\">0</counter>\n      <counter name=\"RESERVED8\">0</counter>\n      <counter name=\"RESERVED9\">0</counter>\n      <counter name=\"RESERVED10\">0</counter>\n      <counter name=\"RESERVED11\">0</counter>\n      <counter name=\"RESERVED12\">0</counter>\n      <counter name=\"RESERVED13\">0</counter>\n      <counter name=\"RESERVED14\">0</counter>\n      <counter name=\"RESERVED15\">0</counter>\n    </counters>\n    <counters type=\"qtype\">\n      <counter name=\"A\">63672</counter>\n      <counter name=\"NS\">373</counter>\n      <counter name=\"SOA\">18</counter>\n      <counter name=\"PTR\">3393</counter>\n      <counter name=\"MX\">618</counter>\n      <counter name=\"TXT\">970</counter>\n      <counter name=\"AAAA\">5735</counter>\n      <counter name=\"SRV\">139</counter>\n      <counter name=\"RRSIG\">1</counter>\n      <counter name=\"ANY\">22</counter>\n    </counters>\n    <counters type=\"nsstat\">\n      <counter name=\"Requestv4\">74942</counter>\n      <counter name=\"Requestv6\">0</counter>\n      <counter name=\"ReqEdns0\">9250</counter>\n      <counter name=\"ReqBadEDNSVer\">0</counter>\n      <counter name=\"ReqTSIG\">0</counter>\n      <counter name=\"ReqSIG0\">0</counter>\n      <counter name=\"ReqBadSIG\">0</counter>\n      <counter name=\"ReqTCP\">260</counter>\n      <counter name=\"AuthQryRej\">0</counter>\n      <counter name=\"RecQryRej\">35</counter>\n      <counter name=\"XfrRej\">0</counter>\n      <counter name=\"UpdateRej\">0</counter>\n      <counter name=\"Response\">63264</counter>\n      <counter name=\"TruncatedResp\">365</counter>\n      <counter name=\"RespEDNS0\">9250</counter>\n      <counter name=\"RespTSIG\">0</counter>\n      <counter name=\"RespSIG0\">0</counter>\n      <counter name=\"QrySuccess\">49044</counter>\n      <counter name=\"QryAuthAns\">2752</counter>\n      <counter name=\"QryNoauthAns\">60354</counter>\n      <counter name=\"QryReferral\">0</counter>\n      <counter name=\"QryNxrrset\">2452</counter>\n      <counter name=\"QrySERVFAIL\">122</counter>\n      <counter name=\"QryFORMERR\">0</counter>\n      <counter name=\"QryNXDOMAIN\">11610</counter>\n      <counter name=\"QryRecursion\">53750</counter>\n      <counter name=\"QryDuplicate\">11667</counter>\n      <counter name=\"QryDropped\">11</counter>\n      <counter name=\"QryFailure\">35</counter>\n      <counter name=\"XfrReqDone\">0</counter>\n      <counter name=\"UpdateReqFwd\">0</counter>\n      <counter name=\"UpdateRespFwd\">0</counter>\n      <counter name=\"UpdateFwdFail\">0</counter>\n      <counter name=\"UpdateDone\">0</counter>\n      <counter name=\"UpdateFail\">0</counter>\n      <counter name=\"UpdateBadPrereq\">0</counter>\n      <counter name=\"RecursClients\">0</counter>\n      <counter name=\"DNS64\">0</counter>\n      <counter name=\"RateDropped\">0</counter>\n      <counter name=\"RateSlipped\">0</counter>\n      <counter name=\"RPZRewrites\">0</counter>\n      <counter name=\"QryUDP\">74648</counter>\n      <counter name=\"QryTCP\">258</counter>\n      <counter name=\"NSIDOpt\">0</counter>\n      <counter name=\"ExpireOpt\">0</counter>\n      <counter name=\"OtherOpt\">59</counter>\n      <counter name=\"SitOpt\">0</counter>\n      <counter name=\"SitNew\">0</counter>\n      <counter name=\"SitBadSize\">0</counter>\n      <counter name=\"SitBadTime\">0</counter>\n      <counter name=\"SitNoMatch\">0</counter>\n      <counter name=\"SitMatch\">0</counter>\n    </counters>\n    <counters type=\"zonestat\">\n      <counter name=\"NotifyOutv4\">2</counter>\n      <counter name=\"NotifyOutv6\">0</counter>\n      <counter name=\"NotifyInv4\">0</counter>\n      <counter name=\"NotifyInv6\">0</counter>\n      <counter name=\"NotifyRej\">0</counter>\n      <counter name=\"SOAOutv4\">0</counter>\n      <counter name=\"SOAOutv6\">0</counter>\n      <counter name=\"AXFRReqv4\">0</counter>\n      <counter name=\"AXFRReqv6\">0</counter>\n      <counter name=\"IXFRReqv4\">0</counter>\n      <counter name=\"IXFRReqv6\">0</counter>\n      <counter name=\"XfrSuccess\">0</counter>\n      <counter name=\"XfrFail\">0</counter>\n    </counters>\n    <counters type=\"resstat\"/>\n  </server>\n  <views>\n    <view name=\"_default\">\n      <counters type=\"resqtype\">\n        <counter name=\"A\">61568</counter>\n        <counter name=\"NS\">9126</counter>\n        <counter name=\"PTR\">1249</counter>\n        <counter name=\"MX\">286</counter>\n        <counter name=\"TXT\">942</counter>\n        <counter name=\"AAAA\">3933</counter>\n        <counter name=\"SRV\">21</counter>\n        <counter name=\"DS\">13749</counter>\n        <counter name=\"DNSKEY\">1699</counter>\n      </counters>\n      <counters type=\"resstats\">\n        <counter name=\"Queryv4\">92573</counter>\n        <counter name=\"Queryv6\">0</counter>\n        <counter name=\"Responsev4\">92135</counter>\n        <counter name=\"Responsev6\">0</counter>\n        <counter name=\"NXDOMAIN\">8182</counter>\n        <counter name=\"SERVFAIL\">318</counter>\n        <counter name=\"FORMERR\">0</counter>\n        <counter name=\"OtherError\">0</counter>\n        <counter name=\"EDNS0Fail\">0</counter>\n        <counter name=\"Mismatch\">0</counter>\n        <counter name=\"Truncated\">42</counter>\n        <counter name=\"Lame\">12</counter>\n        <counter name=\"Retry\">800</counter>\n        <counter name=\"QueryAbort\">0</counter>\n        <counter name=\"QuerySockFail\">0</counter>\n        <counter name=\"QueryCurUDP\">0</counter>\n        <counter name=\"QueryCurTCP\">0</counter>\n        <counter name=\"QueryTimeout\">490</counter>\n        <counter name=\"GlueFetchv4\">1398</counter>\n        <counter name=\"GlueFetchv6\">0</counter>\n        <counter name=\"GlueFetchv4Fail\">3</counter>\n        <counter name=\"GlueFetchv6Fail\">0</counter>\n        <counter name=\"ValAttempt\">90256</counter>\n        <counter name=\"ValOk\">67322</counter>\n        <counter name=\"ValNegOk\">22850</counter>\n        <counter name=\"ValFail\">6</counter>\n        <counter name=\"QryRTT10\">0</counter>\n        <counter name=\"QryRTT100\">45760</counter>\n        <counter name=\"QryRTT500\">45543</counter>\n        <counter name=\"QryRTT800\">743</counter>\n        <counter name=\"QryRTT1600\">75</counter>\n        <counter name=\"QryRTT1600+\">0</counter>\n        <counter name=\"NumFetch\">0</counter>\n        <counter name=\"BucketSize\">31</counter>\n        <counter name=\"REFUSED\">34</counter>\n        <counter name=\"SitClientOut\">0</counter>\n        <counter name=\"SitOut\">0</counter>\n        <counter name=\"SitIn\">0</counter>\n        <counter name=\"SitClientOk\">0</counter>\n        <counter name=\"BadEDNSVersion\">0</counter>\n        <counter name=\"ZoneQuota\">0</counter>\n        <counter name=\"ServerQuota\">0</counter>\n      </counters>\n      <cache name=\"internal\">\n        <rrset>\n          <name>A</name>\n          <counter>195</counter>\n        </rrset>\n        <rrset>\n          <name>NS</name>\n          <counter>42</counter>\n        </rrset>\n        <rrset>\n          <name>CNAME</name>\n          <counter>7</counter>\n        </rrset>\n        <rrset>\n          <name>PTR</name>\n          <counter>48</counter>\n        </rrset>\n        <rrset>\n          <name>MX</name>\n          <counter>7</counter>\n        </rrset>\n        <rrset>\n          <name>TXT</name>\n          <counter>6</counter>\n        </rrset>\n        <rrset>\n          <name>AAAA</name>\n          <counter>4</counter>\n        </rrset>\n        <rrset>\n          <name>DS</name>\n          <counter>97</counter>\n        </rrset>\n        <rrset>\n          <name>RRSIG</name>\n          <counter>258</counter>\n        </rrset>\n        <rrset>\n          <name>NSEC</name>\n          <counter>89</counter>\n        </rrset>\n        <rrset>\n          <name>DNSKEY</name>\n          <counter>60</counter>\n        </rrset>\n        <rrset>\n          <name>!DS</name>\n          <counter>29</counter>\n        </rrset>\n        <rrset>\n          <name>NXDOMAIN</name>\n          <counter>25</counter>\n        </rrset>\n      </cache>\n      <counters type=\"adbstat\">\n        <counter name=\"nentries\">1021</counter>\n        <counter name=\"entriescnt\">314</counter>\n        <counter name=\"nnames\">1021</counter>\n        <counter name=\"namescnt\">316</counter>\n      </counters>\n      <counters type=\"cachestats\">\n        <counter name=\"CacheHits\">1904593</counter>\n        <counter name=\"CacheMisses\">96</counter>\n        <counter name=\"QueryHits\">336094</counter>\n        <counter name=\"QueryMisses\">369336</counter>\n        <counter name=\"DeleteLRU\">0</counter>\n        <counter name=\"DeleteTTL\">47518</counter>\n        <counter name=\"CacheNodes\">769</counter>\n        <counter name=\"CacheBuckets\">519</counter>\n        <counter name=\"TreeMemTotal\">1464363</counter>\n        <counter name=\"TreeMemInUse\">392128</counter>\n        <counter name=\"TreeMemMax\">828966</counter>\n        <counter name=\"HeapMemTotal\">393216</counter>\n        <counter name=\"HeapMemInUse\">132096</counter>\n        <counter name=\"HeapMemMax\">132096</counter>\n      </counters>\n    </view>\n    <view name=\"_bind\">\n      <zones>\n        <zone name=\"authors.bind\" rdataclass=\"CH\">\n          <serial>0</serial>\n        </zone>\n        <zone name=\"hostname.bind\" rdataclass=\"CH\">\n          <serial>0</serial>\n        </zone>\n        <zone name=\"version.bind\" rdataclass=\"CH\">\n          <serial>0</serial>\n        </zone>\n        <zone name=\"id.server\" rdataclass=\"CH\">\n          <serial>0</serial>\n        </zone>\n      </zones>\n      <counters type=\"resqtype\"/>\n      <counters type=\"resstats\">\n        <counter name=\"Queryv4\">0</counter>\n        <counter name=\"Queryv6\">0</counter>\n        <counter name=\"Responsev4\">0</counter>\n        <counter name=\"Responsev6\">0</counter>\n        <counter name=\"NXDOMAIN\">0</counter>\n        <counter name=\"SERVFAIL\">0</counter>\n        <counter name=\"FORMERR\">0</counter>\n        <counter name=\"OtherError\">0</counter>\n        <counter name=\"EDNS0Fail\">0</counter>\n        <counter name=\"Mismatch\">0</counter>\n        <counter name=\"Truncated\">0</counter>\n        <counter name=\"Lame\">0</counter>\n        <counter name=\"Retry\">0</counter>\n        <counter name=\"QueryAbort\">0</counter>\n        <counter name=\"QuerySockFail\">0</counter>\n        <counter name=\"QueryCurUDP\">0</counter>\n        <counter name=\"QueryCurTCP\">0</counter>\n        <counter name=\"QueryTimeout\">0</counter>\n        <counter name=\"GlueFetchv4\">0</counter>\n        <counter name=\"GlueFetchv6\">0</counter>\n        <counter name=\"GlueFetchv4Fail\">0</counter>\n        <counter name=\"GlueFetchv6Fail\">0</counter>\n        <counter name=\"ValAttempt\">0</counter>\n        <counter name=\"ValOk\">0</counter>\n        <counter name=\"ValNegOk\">0</counter>\n        <counter name=\"ValFail\">0</counter>\n        <counter name=\"QryRTT10\">0</counter>\n        <counter name=\"QryRTT100\">0</counter>\n        <counter name=\"QryRTT500\">0</counter>\n        <counter name=\"QryRTT800\">0</counter>\n        <counter name=\"QryRTT1600\">0</counter>\n        <counter name=\"QryRTT1600+\">0</counter>\n        <counter name=\"NumFetch\">0</counter>\n        <counter name=\"BucketSize\">31</counter>\n        <counter name=\"REFUSED\">0</counter>\n        <counter name=\"SitClientOut\">0</counter>\n        <counter name=\"SitOut\">0</counter>\n        <counter name=\"SitIn\">0</counter>\n        <counter name=\"SitClientOk\">0</counter>\n        <counter name=\"BadEDNSVersion\">0</counter>\n        <counter name=\"ZoneQuota\">0</counter>\n        <counter name=\"ServerQuota\">0</counter>\n      </counters>\n      <cache name=\"_bind\"/>\n      <counters type=\"adbstat\">\n        <counter name=\"nentries\">1021</counter>\n        <counter name=\"entriescnt\">0</counter>\n        <counter name=\"nnames\">1021</counter>\n        <counter name=\"namescnt\">0</counter>\n      </counters>\n      <counters type=\"cachestats\">\n        <counter name=\"CacheHits\">0</counter>\n        <counter name=\"CacheMisses\">0</counter>\n        <counter name=\"QueryHits\">0</counter>\n        <counter name=\"QueryMisses\">0</counter>\n        <counter name=\"DeleteLRU\">0</counter>\n        <counter name=\"DeleteTTL\">0</counter>\n        <counter name=\"CacheNodes\">0</counter>\n        <counter name=\"CacheBuckets\">64</counter>\n        <counter name=\"TreeMemTotal\">287392</counter>\n        <counter name=\"TreeMemInUse\">29608</counter>\n        <counter name=\"TreeMemMax\">29608</counter>\n        <counter name=\"HeapMemTotal\">262144</counter>\n        <counter name=\"HeapMemInUse\">1024</counter>\n        <counter name=\"HeapMemMax\">1024</counter>\n      </counters>\n    </view>\n  </views>\n</statistics>\n"
  },
  {
    "path": "plugins/inputs/bind/xml_stats_v2.go",
    "content": "package bind\n\nimport (\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\ntype v2Root struct {\n\tXMLName    xml.Name\n\tVersion    string       `xml:\"version,attr\"`\n\tStatistics v2Statistics `xml:\"bind>statistics\"`\n}\n\n// Omitted branches: socketmgr, taskmgr\ntype v2Statistics struct {\n\tVersion string `xml:\"version,attr\"`\n\tViews   []struct {\n\t\t// Omitted branches: zones\n\t\tName     string      `xml:\"name\"`\n\t\tRdTypes  []v2Counter `xml:\"rdtype\"`\n\t\tResStats []v2Counter `xml:\"resstat\"`\n\t\tCaches   []struct {\n\t\t\tName   string      `xml:\"name,attr\"`\n\t\t\tRRSets []v2Counter `xml:\"rrset\"`\n\t\t} `xml:\"cache\"`\n\t} `xml:\"views>view\"`\n\tServer struct {\n\t\tOpCodes   []v2Counter `xml:\"requests>opcode\"`\n\t\tRdTypes   []v2Counter `xml:\"queries-in>rdtype\"`\n\t\tNSStats   []v2Counter `xml:\"nsstat\"`\n\t\tZoneStats []v2Counter `xml:\"zonestat\"`\n\t\tResStats  []v2Counter `xml:\"resstat\"`\n\t\tSockStats []v2Counter `xml:\"sockstat\"`\n\t} `xml:\"server\"`\n\tMemory struct {\n\t\tContexts []struct {\n\t\t\t// Omitted nodes: references, maxinuse, blocksize, pools, hiwater, lowater\n\t\t\tID    string `xml:\"id\"`\n\t\t\tName  string `xml:\"name\"`\n\t\t\tTotal int64  `xml:\"total\"`\n\t\t\tInUse int64  `xml:\"inuse\"`\n\t\t} `xml:\"contexts>context\"`\n\t\tSummary struct {\n\t\t\tTotalUse    int64\n\t\t\tInUse       int64\n\t\t\tBlockSize   int64\n\t\t\tContextSize int64\n\t\t\tLost        int64\n\t\t} `xml:\"summary\"`\n\t} `xml:\"memory\"`\n}\n\n// BIND statistics v2 counter struct used throughout\ntype v2Counter struct {\n\tName  string `xml:\"name\"`\n\tValue int    `xml:\"counter\"`\n}\n\n// addXMLv2Counter adds a v2Counter array to a Telegraf Accumulator, with the specified tags\nfunc addXMLv2Counter(acc telegraf.Accumulator, commonTags map[string]string, stats []v2Counter) {\n\tgrouper := metric.NewSeriesGrouper()\n\tts := time.Now()\n\tfor _, c := range stats {\n\t\ttags := make(map[string]string)\n\n\t\t// Create local copy of tags since maps are reference types\n\t\tfor k, v := range commonTags {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\tgrouper.Add(\"bind_counter\", tags, ts, c.Name, c.Value)\n\t}\n\n\t// Add grouped metrics\n\tfor _, groupedMetric := range grouper.Metrics() {\n\t\tacc.AddMetric(groupedMetric)\n\t}\n}\n\n// readStatsXMLv2 decodes a BIND9 XML statistics version 2 document. Unlike the XML v3 statistics\n// format, the v2 format does not support broken-out subsets.\nfunc (b *Bind) readStatsXMLv2(addr *url.URL, acc telegraf.Accumulator) error {\n\tvar stats v2Root\n\n\tresp, err := b.client.Get(addr.String())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status: %s\", addr, resp.Status)\n\t}\n\n\tif err := xml.NewDecoder(resp.Body).Decode(&stats); err != nil {\n\t\treturn fmt.Errorf(\"unable to decode XML document: %w\", err)\n\t}\n\n\ttags := map[string]string{\"url\": addr.Host}\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to parse address host %q: %w\", addr.Host, err)\n\t}\n\ttags[\"source\"] = host\n\ttags[\"port\"] = port\n\n\t// Opcodes\n\ttags[\"type\"] = \"opcode\"\n\taddXMLv2Counter(acc, tags, stats.Statistics.Server.OpCodes)\n\n\t// Query RDATA types\n\ttags[\"type\"] = \"qtype\"\n\taddXMLv2Counter(acc, tags, stats.Statistics.Server.RdTypes)\n\n\t// Nameserver stats\n\ttags[\"type\"] = \"nsstat\"\n\taddXMLv2Counter(acc, tags, stats.Statistics.Server.NSStats)\n\n\t// Zone stats\n\ttags[\"type\"] = \"zonestat\"\n\taddXMLv2Counter(acc, tags, stats.Statistics.Server.ZoneStats)\n\n\t// Socket statistics\n\ttags[\"type\"] = \"sockstat\"\n\taddXMLv2Counter(acc, tags, stats.Statistics.Server.SockStats)\n\n\t// Memory stats\n\tfields := map[string]interface{}{\n\t\t\"total_use\":    stats.Statistics.Memory.Summary.TotalUse,\n\t\t\"in_use\":       stats.Statistics.Memory.Summary.InUse,\n\t\t\"block_size\":   stats.Statistics.Memory.Summary.BlockSize,\n\t\t\"context_size\": stats.Statistics.Memory.Summary.ContextSize,\n\t\t\"lost\":         stats.Statistics.Memory.Summary.Lost,\n\t}\n\tacc.AddGauge(\"bind_memory\", fields, map[string]string{\"url\": addr.Host, \"source\": host, \"port\": port})\n\n\t// Detailed, per-context memory stats\n\tif b.GatherMemoryContexts {\n\t\tfor _, c := range stats.Statistics.Memory.Contexts {\n\t\t\ttags := map[string]string{\"url\": addr.Host, \"id\": c.ID, \"name\": c.Name, \"source\": host, \"port\": port}\n\t\t\tfields := map[string]interface{}{\"total\": c.Total, \"in_use\": c.InUse}\n\n\t\t\tacc.AddGauge(\"bind_memory_context\", fields, tags)\n\t\t}\n\t}\n\n\t// Detailed, per-view stats\n\tif b.GatherViews {\n\t\tfor _, v := range stats.Statistics.Views {\n\t\t\ttags := map[string]string{\"url\": addr.Host, \"view\": v.Name}\n\n\t\t\t// Query RDATA types\n\t\t\ttags[\"type\"] = \"qtype\"\n\t\t\taddXMLv2Counter(acc, tags, v.RdTypes)\n\n\t\t\t// Resolver stats\n\t\t\ttags[\"type\"] = \"resstats\"\n\t\t\taddXMLv2Counter(acc, tags, v.ResStats)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/bind/xml_stats_v3.go",
    "content": "package bind\n\nimport (\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\n// XML path: //statistics\n// Omitted branches: socketmgr, taskmgr\ntype v3Stats struct {\n\tServer v3Server `xml:\"server\"`\n\tViews  []v3View `xml:\"views>view\"`\n\tMemory v3Memory `xml:\"memory\"`\n}\n\n// XML path: //statistics/memory\ntype v3Memory struct {\n\tContexts []struct {\n\t\t// Omitted nodes: references, maxinuse, blocksize, pools, hiwater, lowater\n\t\tID    string `xml:\"id\"`\n\t\tName  string `xml:\"name\"`\n\t\tTotal uint64 `xml:\"total\"`\n\t\tInUse uint64 `xml:\"inuse\"`\n\t} `xml:\"contexts>context\"`\n\tSummary struct {\n\t\tTotalUse    uint64\n\t\tInUse       uint64\n\t\tBlockSize   uint64\n\t\tContextSize uint64\n\t\tLost        uint64\n\t} `xml:\"summary\"`\n}\n\n// XML path: //statistics/server\ntype v3Server struct {\n\tCounterGroups []v3CounterGroup `xml:\"counters\"`\n}\n\n// XML path: //statistics/views/view\ntype v3View struct {\n\t// Omitted branches: zones\n\tName          string           `xml:\"name,attr\"`\n\tCounterGroups []v3CounterGroup `xml:\"counters\"`\n\tCaches        []struct {\n\t\tName   string `xml:\"name,attr\"`\n\t\tRRSets []struct {\n\t\t\tName  string `xml:\"name\"`\n\t\t\tValue uint64 `xml:\"counter\"`\n\t\t} `xml:\"rrset\"`\n\t} `xml:\"cache\"`\n}\n\n// Generic XML v3 doc fragment used in multiple places\ntype v3CounterGroup struct {\n\tType     string `xml:\"type,attr\"`\n\tCounters []struct {\n\t\tName  string `xml:\"name,attr\"`\n\t\tValue uint64 `xml:\",chardata\"`\n\t} `xml:\"counter\"`\n}\n\n// addStatsXMLv3 walks a v3Stats struct and adds the values to the telegraf.Accumulator.\nfunc (b *Bind) addStatsXMLv3(stats v3Stats, acc telegraf.Accumulator, hostPort string) {\n\tgrouper := metric.NewSeriesGrouper()\n\tts := time.Now()\n\thost, port, err := net.SplitHostPort(hostPort)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t}\n\t// Counter groups\n\tfor _, cg := range stats.Server.CounterGroups {\n\t\tfor _, c := range cg.Counters {\n\t\t\tif cg.Type == \"opcode\" && strings.HasPrefix(c.Name, \"RESERVED\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttags := map[string]string{\"url\": hostPort, \"source\": host, \"port\": port, \"type\": cg.Type}\n\t\t\tvar v interface{} = c.Value\n\t\t\tif b.CountersAsInt {\n\t\t\t\tif c.Value < math.MaxInt64 {\n\t\t\t\t\tv = int64(c.Value)\n\t\t\t\t} else {\n\t\t\t\t\tv = int64(math.MaxInt64)\n\t\t\t\t}\n\t\t\t}\n\t\t\tgrouper.Add(\"bind_counter\", tags, ts, c.Name, v)\n\t\t}\n\t}\n\n\t// Memory stats\n\tfields := map[string]interface{}{\n\t\t\"total_use\":    stats.Memory.Summary.TotalUse,\n\t\t\"in_use\":       stats.Memory.Summary.InUse,\n\t\t\"block_size\":   stats.Memory.Summary.BlockSize,\n\t\t\"context_size\": stats.Memory.Summary.ContextSize,\n\t\t\"lost\":         stats.Memory.Summary.Lost,\n\t}\n\tb.postProcessFields(fields)\n\tacc.AddGauge(\"bind_memory\", fields, map[string]string{\"url\": hostPort, \"source\": host, \"port\": port})\n\n\t// Detailed, per-context memory stats\n\tif b.GatherMemoryContexts {\n\t\tfor _, c := range stats.Memory.Contexts {\n\t\t\ttags := map[string]string{\"url\": hostPort, \"source\": host, \"port\": port, \"id\": c.ID, \"name\": c.Name}\n\t\t\tfields := map[string]interface{}{\"total\": c.Total, \"in_use\": c.InUse}\n\n\t\t\tb.postProcessFields(fields)\n\t\t\tacc.AddGauge(\"bind_memory_context\", fields, tags)\n\t\t}\n\t}\n\n\t// Detailed, per-view stats\n\tif b.GatherViews {\n\t\tfor _, v := range stats.Views {\n\t\t\tfor _, cg := range v.CounterGroups {\n\t\t\t\tfor _, c := range cg.Counters {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"url\":    hostPort,\n\t\t\t\t\t\t\"source\": host,\n\t\t\t\t\t\t\"port\":   port,\n\t\t\t\t\t\t\"view\":   v.Name,\n\t\t\t\t\t\t\"type\":   cg.Type,\n\t\t\t\t\t}\n\t\t\t\t\tvar v interface{} = c.Value\n\t\t\t\t\tif b.CountersAsInt {\n\t\t\t\t\t\tif c.Value < math.MaxInt64 {\n\t\t\t\t\t\t\tv = int64(c.Value)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tv = int64(math.MaxInt64)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tgrouper.Add(\"bind_counter\", tags, ts, c.Name, v)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add grouped metrics\n\tfor _, groupedMetric := range grouper.Metrics() {\n\t\tacc.AddMetric(groupedMetric)\n\t}\n}\n\n// readStatsXMLv3 takes a base URL to probe, and requests the individual statistics documents that\n// we are interested in. These individual documents have a combined size which is significantly\n// smaller than if we requested everything at once (e.g. taskmgr and socketmgr can be omitted).\nfunc (b *Bind) readStatsXMLv3(addr *url.URL, acc telegraf.Accumulator) error {\n\tvar stats v3Stats\n\n\t// Progressively build up full v3Stats struct by parsing the individual HTTP responses\n\tfor _, suffix := range [...]string{\"/server\", \"/net\", \"/mem\"} {\n\t\terr := func() error {\n\t\t\tscrapeURL := addr.String() + suffix\n\n\t\t\tresp, err := b.client.Get(scrapeURL)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer resp.Body.Close()\n\n\t\t\tif resp.StatusCode != http.StatusOK {\n\t\t\t\treturn fmt.Errorf(\"%s returned HTTP status: %s\", scrapeURL, resp.Status)\n\t\t\t}\n\n\t\t\tif err := xml.NewDecoder(resp.Body).Decode(&stats); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to decode XML document: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tb.addStatsXMLv3(stats, acc, addr.Host)\n\treturn nil\n}\n\nfunc (b *Bind) postProcessFields(fields map[string]interface{}) {\n\tif !b.CountersAsInt {\n\t\treturn\n\t}\n\tfor k, val := range fields {\n\t\tif v, ok := val.(uint64); ok {\n\t\t\tif v < math.MaxInt64 {\n\t\t\t\tfields[k] = int64(v)\n\t\t\t} else {\n\t\t\t\tfields[k] = int64(math.MaxInt64)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/bond/README.md",
    "content": "# Bond Input Plugin\n\nThis plugin collects metrics for both the network bond interface as well as its\nslave interfaces using `/proc/net/bonding/*` files.\n\n⭐ Telegraf v1.5.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect bond interface status, slaves statuses and failures count\n[[inputs.bond]]\n  ## Sets 'proc' directory path\n  ## If not specified, then default is /proc\n  # host_proc = \"/proc\"\n\n  ## Sets 'sys' directory path\n  ## If not specified, then default is /sys\n  # host_sys = \"/sys\"\n\n  ## By default, telegraf gather stats for all bond interfaces\n  ## Setting interfaces will restrict the stats to the specified\n  ## bond interfaces.\n  # bond_interfaces = [\"bond0\"]\n\n  ## Tries to collect additional bond details from /sys/class/net/{bond}\n  ## currently only useful for LACP (mode 4) bonds\n  # collect_sys_details = false\n```\n\n## Metrics\n\n- bond\n  - tags:\n    - `bond`: name of the bond\n  - fields:\n    - `active_slave`: currently active slave interface for active-backup mode\n    - `status`: status of the interface (0: down , 1: up)\n\n- bond_slave\n  - tags:\n    - `bond`: name of the bond\n    - `interface`: name of the network interface\n  - fields:\n    - `failures`: amount of failures for bond's slave interface\n    - `status`: status of the interface (0: down , 1: up)\n    - `count`: number of slaves attached to bond\n    - `actor_churned (for LACP bonds)`: count for local end of LACP bond flapped\n    - `partner_churned (for LACP bonds)`: count for remote end of LACP bond flapped\n    - `total_churned (for LACP bonds)`: full count of all churn events\n\n- bond_sys\n  - tags:\n    - `bond`: name of the bond\n    - `mode`: name of the bonding mode\n  - fields:\n    - `slave_count`: number of slaves\n    - `ad_port_count`: number of ports\n\n## Example Output\n\nConfiguration:\n\n```toml\n[[inputs.bond]]\n  ## Sets 'proc' directory path\n  ## If not specified, then default is /proc\n  host_proc = \"/proc\"\n\n  ## By default, telegraf gather stats for all bond interfaces\n  ## Setting interfaces will restrict the stats to the specified\n  ## bond interfaces.\n  bond_interfaces = [\"bond0\", \"bond1\"]\n```\n\nRun:\n\n```bash\ntelegraf --config telegraf.conf --input-filter bond --test\n```\n\nOutput:\n\n```text\nbond,bond=bond1,host=local active_slave=\"eth0\",status=1i 1509704525000000000\nbond_slave,bond=bond1,interface=eth0,host=local status=1i,failures=0i 1509704525000000000\nbond_slave,host=local,bond=bond1,interface=eth1 status=1i,failures=0i 1509704525000000000\nbond_slave,host=local,bond=bond1 count=2i 1509704525000000000\nbond,bond=bond0,host=isvetlov-mac.local status=1i 1509704525000000000\nbond_slave,bond=bond0,interface=eth1,host=local status=1i,failures=0i 1509704525000000000\nbond_slave,bond=bond0,interface=eth2,host=local status=1i,failures=0i 1509704525000000000\nbond_slave,bond=bond0,host=local count=2i 1509704525000000000\n```\n"
  },
  {
    "path": "plugins/inputs/bond/bond.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage bond\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Bond struct {\n\tHostProc       string   `toml:\"host_proc\"`\n\tHostSys        string   `toml:\"host_sys\"`\n\tSysDetails     bool     `toml:\"collect_sys_details\"`\n\tBondInterfaces []string `toml:\"bond_interfaces\"`\n\tBondType       string\n}\n\ntype sysFiles struct {\n\tModeFile    string\n\tSlaveFile   string\n\tADPortsFile string\n}\n\nfunc (*Bond) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (bond *Bond) Gather(acc telegraf.Accumulator) error {\n\t// load proc path, get default value if config value and env variable are empty\n\tbond.loadPaths()\n\t// list bond interfaces from bonding directory or gather all interfaces.\n\tbondNames, err := bond.listInterfaces()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, bondName := range bondNames {\n\t\tbondAbsPath := bond.HostProc + \"/net/bonding/\" + bondName\n\t\tfile, err := os.ReadFile(bondAbsPath)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error inspecting %q interface: %w\", bondAbsPath, err))\n\t\t\tcontinue\n\t\t}\n\t\trawProcFile := strings.TrimSpace(string(file))\n\t\terr = bond.gatherBondInterface(bondName, rawProcFile, acc)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error inspecting %q interface: %w\", bondName, err))\n\t\t}\n\n\t\t/*\n\t\t\tSome details about bonds only exist in /sys/class/net/\n\t\t\tIn particular, LACP bonds track upstream port state here\n\t\t*/\n\t\tif bond.SysDetails {\n\t\t\tfiles, err := bond.readSysFiles(bond.HostSys + \"/class/net/\" + bondName)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\tgatherSysDetails(bondName, files, acc)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (bond *Bond) gatherBondInterface(bondName, rawFile string, acc telegraf.Accumulator) error {\n\tsplitIndex := strings.Index(rawFile, \"Slave Interface:\")\n\tif splitIndex == -1 {\n\t\tsplitIndex = len(rawFile)\n\t}\n\tbondPart := rawFile[:splitIndex]\n\tslavePart := rawFile[splitIndex:]\n\n\terr := bond.gatherBondPart(bondName, bondPart, acc)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = bond.gatherSlavePart(bondName, slavePart, acc)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (bond *Bond) gatherBondPart(bondName, rawFile string, acc telegraf.Accumulator) error {\n\tfields := make(map[string]interface{})\n\ttags := map[string]string{\n\t\t\"bond\": bondName,\n\t}\n\tscanner := bufio.NewScanner(strings.NewReader(rawFile))\n\t/*\n\t\t/proc/bond/... files are formatted in a way that is difficult\n\t\tto use regexes to parse. Because of that, we scan through\n\t\tthe file one line at a time and rely on specific lines to\n\t\tmark \"ends\" of blocks. It's a hack that should be resolved,\n\t\tbut for now, it works.\n\t*/\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tstats := strings.Split(line, \":\")\n\t\tif len(stats) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tname := strings.TrimSpace(stats[0])\n\t\tvalue := strings.TrimSpace(stats[1])\n\t\tif name == \"Bonding Mode\" {\n\t\t\tbond.BondType = value\n\t\t}\n\t\tif strings.Contains(name, \"Currently Active Slave\") {\n\t\t\tfields[\"active_slave\"] = value\n\t\t}\n\t\tif strings.Contains(name, \"MII Status\") {\n\t\t\tfields[\"status\"] = 0\n\t\t\tif value == \"up\" {\n\t\t\t\tfields[\"status\"] = 1\n\t\t\t}\n\t\t\tacc.AddFields(\"bond\", fields, tags)\n\t\t\treturn nil\n\t\t}\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\treturn fmt.Errorf(\"couldn't find status info for %q\", bondName)\n}\n\nfunc (bond *Bond) readSysFiles(bondDir string) (sysFiles, error) {\n\t/*\n\t\tFiles we may need\n\t\tbonding/mode\n\t\tbonding/slaves\n\t\tbonding/ad_num_ports\n\n\t\tWe load files here first to allow for easier testing\n\t*/\n\tvar output sysFiles\n\n\tfile, err := os.ReadFile(bondDir + \"/bonding/mode\")\n\tif err != nil {\n\t\treturn sysFiles{}, fmt.Errorf(\"error inspecting %q interface: %w\", bondDir+\"/bonding/mode\", err)\n\t}\n\toutput.ModeFile = strings.TrimSpace(string(file))\n\tfile, err = os.ReadFile(bondDir + \"/bonding/slaves\")\n\tif err != nil {\n\t\treturn sysFiles{}, fmt.Errorf(\"error inspecting %q interface: %w\", bondDir+\"/bonding/slaves\", err)\n\t}\n\toutput.SlaveFile = strings.TrimSpace(string(file))\n\tif bond.BondType == \"IEEE 802.3ad Dynamic link aggregation\" {\n\t\tfile, err = os.ReadFile(bondDir + \"/bonding/ad_num_ports\")\n\t\tif err != nil {\n\t\t\treturn sysFiles{}, fmt.Errorf(\"error inspecting %q interface: %w\", bondDir+\"/bonding/ad_num_ports\", err)\n\t\t}\n\t\toutput.ADPortsFile = strings.TrimSpace(string(file))\n\t}\n\treturn output, nil\n}\n\nfunc gatherSysDetails(bondName string, files sysFiles, acc telegraf.Accumulator) {\n\tvar slaves []string\n\tvar adPortCount int\n\n\t// To start with, we get the bond operating mode\n\tmode := strings.TrimSpace(strings.Split(files.ModeFile, \" \")[0])\n\n\ttags := map[string]string{\n\t\t\"bond\": bondName,\n\t\t\"mode\": mode,\n\t}\n\n\t// Next we collect the number of bond slaves the system expects\n\tslavesTmp := strings.Split(files.SlaveFile, \" \")\n\tfor _, slave := range slavesTmp {\n\t\tif slave != \"\" {\n\t\t\tslaves = append(slaves, slave)\n\t\t}\n\t}\n\tif mode == \"802.3ad\" {\n\t\t/*\n\t\t\tIf we're in LACP mode, we should check on how the bond ports are\n\t\t\tinteracting with the upstream switch ports\n\t\t\ta failed conversion can be treated as 0 ports\n\t\t*/\n\t\tif pc, err := strconv.Atoi(strings.TrimSpace(files.ADPortsFile)); err == nil {\n\t\t\tadPortCount = pc\n\t\t}\n\t} else {\n\t\tadPortCount = len(slaves)\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"slave_count\":   len(slaves),\n\t\t\"ad_port_count\": adPortCount,\n\t}\n\tacc.AddFields(\"bond_sys\", fields, tags)\n}\n\nfunc (bond *Bond) gatherSlavePart(bondName, rawFile string, acc telegraf.Accumulator) error {\n\tvar slaveCount int\n\ttags := map[string]string{\n\t\t\"bond\": bondName,\n\t}\n\tfields := map[string]interface{}{\n\t\t\"status\": 0,\n\t}\n\tvar scanPast bool\n\tif bond.BondType == \"IEEE 802.3ad Dynamic link aggregation\" {\n\t\tscanPast = true\n\t}\n\n\tscanner := bufio.NewScanner(strings.NewReader(rawFile))\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tstats := strings.Split(line, \":\")\n\t\tif len(stats) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tname := strings.TrimSpace(stats[0])\n\t\tvalue := strings.TrimSpace(stats[1])\n\t\tif strings.Contains(name, \"Slave Interface\") {\n\t\t\ttags[\"interface\"] = value\n\t\t\tslaveCount++\n\t\t}\n\t\tif strings.Contains(name, \"MII Status\") && value == \"up\" {\n\t\t\tfields[\"status\"] = 1\n\t\t}\n\t\tif strings.Contains(name, \"Link Failure Count\") {\n\t\t\tcount, err := strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"failures\"] = count\n\t\t\tif !scanPast {\n\t\t\t\tacc.AddFields(\"bond_slave\", fields, tags)\n\t\t\t\tfields = map[string]interface{}{\n\t\t\t\t\t\"status\": 0,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif strings.Contains(name, \"Actor Churned Count\") {\n\t\t\tcount, err := strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"actor_churned\"] = count\n\t\t}\n\t\tif strings.Contains(name, \"Partner Churned Count\") {\n\t\t\tcount, err := strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"partner_churned\"] = count\n\t\t\tfields[\"total_churned\"] = fields[\"actor_churned\"].(int) + fields[\"partner_churned\"].(int)\n\t\t\tacc.AddFields(\"bond_slave\", fields, tags)\n\t\t\tfields = map[string]interface{}{\n\t\t\t\t\"status\": 0,\n\t\t\t}\n\t\t}\n\t}\n\ttags = map[string]string{\n\t\t\"bond\": bondName,\n\t}\n\tfields = map[string]interface{}{\n\t\t\"count\": slaveCount,\n\t}\n\tacc.AddFields(\"bond_slave\", fields, tags)\n\n\treturn scanner.Err()\n}\n\n// loadPaths can be used to read path firstly from config\n// if it is empty then try read from env variable\nfunc (bond *Bond) loadPaths() {\n\tif bond.HostProc == \"\" {\n\t\tbond.HostProc = internal.GetProcPath()\n\t}\n\tif bond.HostSys == \"\" {\n\t\tbond.HostSys = internal.GetSysPath()\n\t}\n}\n\nfunc (bond *Bond) listInterfaces() ([]string, error) {\n\tvar interfaces []string\n\tif len(bond.BondInterfaces) > 0 {\n\t\tinterfaces = bond.BondInterfaces\n\t} else {\n\t\tpaths, err := filepath.Glob(bond.HostProc + \"/net/bonding/*\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, p := range paths {\n\t\t\tinterfaces = append(interfaces, filepath.Base(p))\n\t\t}\n\t}\n\treturn interfaces, nil\n}\n\nfunc init() {\n\tinputs.Add(\"bond\", func() telegraf.Input {\n\t\treturn &Bond{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/bond/bond_test.go",
    "content": "package bond\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleTestAB = `\nEthernet Channel Bonding Driver: v3.6.0 (September 26, 2009)\n\nBonding Mode: fault-tolerance (active-backup)\nPrimary Slave: eth2 (primary_reselect always)\nCurrently Active Slave: eth2\nMII Status: up\nMII Polling Interval (ms): 100\nUp Delay (ms): 0\nDown Delay (ms): 0\n\nSlave Interface: eth3\nMII Status: down\nSpeed: 1000 Mbps\nDuplex: full\nLink Failure Count: 2\nPermanent HW addr:\nSlave queue ID: 0\n\nSlave Interface: eth2\nMII Status: up\nSpeed: 100 Mbps\nDuplex: full\nLink Failure Count: 0\nPermanent HW addr:\n`\n\nconst sampleTestLACP = `\nEthernet Channel Bonding Driver: v3.7.1 (April 27, 2011)\n\nBonding Mode: IEEE 802.3ad Dynamic link aggregation\nTransmit Hash Policy: layer2 (0)\nMII Status: up\nMII Polling Interval (ms): 100\nUp Delay (ms): 0\nDown Delay (ms): 0\n\n802.3ad info\nLACP rate: fast\nMin links: 0\nAggregator selection policy (ad_select): stable\n\nSlave Interface: eth0\nMII Status: up\nSpeed: 10000 Mbps\nDuplex: full\nLink Failure Count: 2\nPermanent HW addr: 3c:ec:ef:5e:71:58\nSlave queue ID: 0\nAggregator ID: 2\nActor Churn State: none\nPartner Churn State: none\nActor Churned Count: 2\nPartner Churned Count: 0\n\nSlave Interface: eth1\nMII Status: up\nSpeed: 10000 Mbps\nDuplex: full\nLink Failure Count: 1\nPermanent HW addr: 3c:ec:ef:5e:71:59\nSlave queue ID: 0\nAggregator ID: 2\nActor Churn State: none\nPartner Churn State: none\nActor Churned Count: 0\nPartner Churned Count: 0\n`\n\nconst sampleTestLACPFirstUpSecondDown = `\nEthernet Channel Bonding Driver: v3.7.1 (April 27, 2011)\n\nBonding Mode: IEEE 802.3ad Dynamic link aggregation\nTransmit Hash Policy: layer2 (0)\nMII Status: up\nMII Polling Interval (ms): 100\nUp Delay (ms): 0\nDown Delay (ms): 0\n\n802.3ad info\nLACP rate: fast\nMin links: 0\nAggregator selection policy (ad_select): stable\n\nSlave Interface: eth0\nMII Status: up\nSpeed: 10000 Mbps\nDuplex: full\nLink Failure Count: 2\nPermanent HW addr: 3c:ec:ef:5e:71:58\nSlave queue ID: 0\nAggregator ID: 2\nActor Churn State: none\nPartner Churn State: none\nActor Churned Count: 2\nPartner Churned Count: 0\n\nSlave Interface: eth1\nMII Status: down\nSpeed: Unknown\nDuplex: Unknown\nLink Failure Count: 1\nPermanent HW addr: 3c:ec:ef:5e:71:59\nSlave queue ID: 0\nAggregator ID: 2\nActor Churn State: none\nPartner Churn State: none\nActor Churned Count: 0\nPartner Churned Count: 0\n`\n\nconst sampleSysMode = \"802.3ad 5\"\nconst sampleSysSlaves = \"eth0 eth1 \"\nconst sampleSysAdPorts = \" 2 \"\n\nfunc TestGatherBondInterface(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tbond := &Bond{}\n\n\trequire.NoError(t, bond.gatherBondInterface(\"bondAB\", sampleTestAB, &acc))\n\tacc.AssertContainsTaggedFields(t, \"bond\", map[string]interface{}{\"active_slave\": \"eth2\", \"status\": 1}, map[string]string{\"bond\": \"bondAB\"})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 2, \"status\": 0},\n\t\tmap[string]string{\"bond\": \"bondAB\", \"interface\": \"eth3\"},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 0, \"status\": 1},\n\t\tmap[string]string{\"bond\": \"bondAB\", \"interface\": \"eth2\"},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"bond_slave\", map[string]interface{}{\"count\": 2}, map[string]string{\"bond\": \"bondAB\"})\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, bond.gatherBondInterface(\"bondLACP\", sampleTestLACP, &acc))\n\tgatherSysDetails(\"bondLACP\", sysFiles{ModeFile: sampleSysMode, SlaveFile: sampleSysSlaves, ADPortsFile: sampleSysAdPorts}, &acc)\n\tacc.AssertContainsTaggedFields(t, \"bond\", map[string]interface{}{\"status\": 1}, map[string]string{\"bond\": \"bondLACP\"})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 2, \"status\": 1, \"actor_churned\": 2, \"partner_churned\": 0, \"total_churned\": 2},\n\t\tmap[string]string{\"bond\": \"bondLACP\", \"interface\": \"eth0\"},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 1, \"status\": 1, \"actor_churned\": 0, \"partner_churned\": 0, \"total_churned\": 0},\n\t\tmap[string]string{\"bond\": \"bondLACP\", \"interface\": \"eth1\"},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"bond_slave\", map[string]interface{}{\"count\": 2}, map[string]string{\"bond\": \"bondLACP\"})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_sys\",\n\t\tmap[string]interface{}{\"slave_count\": 2, \"ad_port_count\": 2},\n\t\tmap[string]string{\"bond\": \"bondLACP\", \"mode\": \"802.3ad\"},\n\t)\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, bond.gatherBondInterface(\"bondLACPUpDown\", sampleTestLACPFirstUpSecondDown, &acc))\n\tgatherSysDetails(\"bondLACPUpDown\", sysFiles{ModeFile: sampleSysMode, SlaveFile: sampleSysSlaves, ADPortsFile: sampleSysAdPorts}, &acc)\n\tacc.AssertContainsTaggedFields(t, \"bond\", map[string]interface{}{\"status\": 1}, map[string]string{\"bond\": \"bondLACPUpDown\"})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 2, \"status\": 1, \"actor_churned\": 2, \"partner_churned\": 0, \"total_churned\": 2},\n\t\tmap[string]string{\"bond\": \"bondLACPUpDown\", \"interface\": \"eth0\"},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_slave\",\n\t\tmap[string]interface{}{\"failures\": 1, \"status\": 0, \"actor_churned\": 0, \"partner_churned\": 0, \"total_churned\": 0},\n\t\tmap[string]string{\"bond\": \"bondLACPUpDown\", \"interface\": \"eth1\"},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"bond_slave\", map[string]interface{}{\"count\": 2}, map[string]string{\"bond\": \"bondLACPUpDown\"})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"bond_sys\",\n\t\tmap[string]interface{}{\"slave_count\": 2, \"ad_port_count\": 2},\n\t\tmap[string]string{\"bond\": \"bondLACPUpDown\", \"mode\": \"802.3ad\"},\n\t)\n}\n"
  },
  {
    "path": "plugins/inputs/bond/sample.conf",
    "content": "# Collect bond interface status, slaves statuses and failures count\n[[inputs.bond]]\n  ## Sets 'proc' directory path\n  ## If not specified, then default is /proc\n  # host_proc = \"/proc\"\n\n  ## Sets 'sys' directory path\n  ## If not specified, then default is /sys\n  # host_sys = \"/sys\"\n\n  ## By default, telegraf gather stats for all bond interfaces\n  ## Setting interfaces will restrict the stats to the specified\n  ## bond interfaces.\n  # bond_interfaces = [\"bond0\"]\n\n  ## Tries to collect additional bond details from /sys/class/net/{bond}\n  ## currently only useful for LACP (mode 4) bonds\n  # collect_sys_details = false\n"
  },
  {
    "path": "plugins/inputs/burrow/README.md",
    "content": "# Burrow Input Plugin\n\nThis plugin collect Kafka topic, consumer and partition status from the\n[Burrow - Kafka Consumer Lag Checking][burrow] companion via [HTTP API][api].\nBurrow v1.x versions are supported.\n\n⭐ Telegraf v1.7.0\n🏷️ messaging\n💻 all\n\n[burrow]: https://github.com/linkedin/Burrow\n[api]: https://github.com/linkedin/Burrow/wiki/HTTP-Endpoint\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect Kafka topics and consumers status from Burrow HTTP API.\n[[inputs.burrow]]\n  ## Burrow API endpoints in format \"schema://host:port\".\n  ## Default is \"http://localhost:8000\".\n  servers = [\"http://localhost:8000\"]\n\n  ## Override Burrow API prefix.\n  ## Useful when Burrow is behind reverse-proxy.\n  # api_prefix = \"/v3/kafka\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Limit per-server concurrent connections.\n  ## Useful in case of large number of topics or consumer groups.\n  # concurrent_connections = 20\n\n  ## Filter clusters, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # clusters_include = []\n  # clusters_exclude = []\n\n  ## Filter consumer groups, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # groups_include = []\n  # groups_exclude = []\n\n  ## Filter topics, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # topics_include = []\n  # topics_exclude = []\n\n  ## Credentials for basic HTTP authentication.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional SSL config\n  # ssl_ca = \"/etc/telegraf/ca.pem\"\n  # ssl_cert = \"/etc/telegraf/cert.pem\"\n  # ssl_key = \"/etc/telegraf/key.pem\"\n  # insecure_skip_verify = false\n```\n\n## Group/Partition Status mappings\n\n* `OK` = 1\n* `NOT_FOUND` = 2\n* `WARN` = 3\n* `ERR` = 4\n* `STOP` = 5\n* `STALL` = 6\n\n> unknown value will be mapped to 0\n\n## Metrics\n\n### Fields\n\n* `burrow_group` (one event per each consumer group)\n  * status (string, see Partition Status mappings)\n  * status_code (int, `1..6`, see Partition status mappings)\n  * partition_count (int, `number of partitions`)\n  * offset (int64, `total offset of all partitions`)\n  * total_lag (int64, `totallag`)\n  * lag (int64, `maxlag.current_lag || 0`)\n  * timestamp (int64, `end.timestamp`)\n\n* `burrow_partition` (one event per each topic partition)\n  * status (string, see Partition Status mappings)\n  * status_code (int, `1..6`, see Partition status mappings)\n  * lag (int64, `current_lag || 0`)\n  * offset (int64, `end.timestamp`)\n  * timestamp (int64, `end.timestamp`)\n\n* `burrow_topic` (one event per topic offset)\n  * offset (int64)\n\n### Tags\n\n* `burrow_group`\n  * cluster (string)\n  * group (string)\n\n* `burrow_partition`\n  * cluster (string)\n  * group (string)\n  * topic (string)\n  * partition (int)\n  * owner (string)\n\n* `burrow_topic`\n  * cluster (string)\n  * topic (string)\n  * partition (int)\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/burrow/burrow.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage burrow\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultBurrowPrefix          = \"/v3/kafka\"\n\tdefaultConcurrentConnections = 20\n\tdefaultResponseTimeout       = time.Second * 5\n\tdefaultServer                = \"http://localhost:8000\"\n)\n\ntype (\n\tBurrow struct {\n\t\ttls.ClientConfig\n\n\t\tServers               []string\n\t\tUsername              string\n\t\tPassword              string\n\t\tResponseTimeout       config.Duration\n\t\tConcurrentConnections int\n\n\t\tAPIPrefix       string `toml:\"api_prefix\"`\n\t\tClustersExclude []string\n\t\tClustersInclude []string\n\t\tGroupsExclude   []string\n\t\tGroupsInclude   []string\n\t\tTopicsExclude   []string\n\t\tTopicsInclude   []string\n\n\t\tclient         *http.Client\n\t\tfilterClusters filter.Filter\n\t\tfilterGroups   filter.Filter\n\t\tfilterTopics   filter.Filter\n\t}\n\n\t// response\n\tapiResponse struct {\n\t\tClusters []string          `json:\"clusters\"`\n\t\tGroups   []string          `json:\"consumers\"`\n\t\tTopics   []string          `json:\"topics\"`\n\t\tOffsets  []int64           `json:\"offsets\"`\n\t\tStatus   apiStatusResponse `json:\"status\"`\n\t}\n\n\t// response: status field\n\tapiStatusResponse struct {\n\t\tPartitions     []apiStatusResponseLag `json:\"partitions\"`\n\t\tStatus         string                 `json:\"status\"`\n\t\tPartitionCount int                    `json:\"partition_count\"`\n\t\tMaxlag         *apiStatusResponseLag  `json:\"maxlag\"`\n\t\tTotalLag       int64                  `json:\"totallag\"`\n\t}\n\n\t// response: lag field\n\tapiStatusResponseLag struct {\n\t\tTopic      string                   `json:\"topic\"`\n\t\tPartition  int32                    `json:\"partition\"`\n\t\tStatus     string                   `json:\"status\"`\n\t\tStart      apiStatusResponseLagItem `json:\"start\"`\n\t\tEnd        apiStatusResponseLagItem `json:\"end\"`\n\t\tCurrentLag int64                    `json:\"current_lag\"`\n\t\tOwner      string                   `json:\"owner\"`\n\t}\n\n\t// response: lag field item\n\tapiStatusResponseLagItem struct {\n\t\tOffset    int64 `json:\"offset\"`\n\t\tTimestamp int64 `json:\"timestamp\"`\n\t\tLag       int64 `json:\"lag\"`\n\t}\n)\n\nfunc (*Burrow) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *Burrow) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tif len(b.Servers) == 0 {\n\t\tb.Servers = []string{defaultServer}\n\t}\n\n\tif b.client == nil {\n\t\tb.setDefaults()\n\t\tif err := b.compileGlobs(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc, err := b.createClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb.client = c\n\t}\n\n\tfor _, addr := range b.Servers {\n\t\tu, err := url.Parse(addr)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", addr, err))\n\t\t\tcontinue\n\t\t}\n\t\tif u.Path == \"\" {\n\t\t\tu.Path = b.APIPrefix\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(u *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(b.gatherServer(u, acc))\n\t\t}(u)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (b *Burrow) setDefaults() {\n\tif b.APIPrefix == \"\" {\n\t\tb.APIPrefix = defaultBurrowPrefix\n\t}\n\tif b.ConcurrentConnections < 1 {\n\t\tb.ConcurrentConnections = defaultConcurrentConnections\n\t}\n\tif time.Duration(b.ResponseTimeout) < time.Second {\n\t\tb.ResponseTimeout = config.Duration(defaultResponseTimeout)\n\t}\n}\n\nfunc (b *Burrow) compileGlobs() error {\n\tvar err error\n\n\t// compile glob patterns\n\tb.filterClusters, err = filter.NewIncludeExcludeFilter(b.ClustersInclude, b.ClustersExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.filterGroups, err = filter.NewIncludeExcludeFilter(b.GroupsInclude, b.GroupsExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.filterTopics, err = filter.NewIncludeExcludeFilter(b.TopicsInclude, b.TopicsExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (b *Burrow) createClient() (*http.Client, error) {\n\ttlsCfg, err := b.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttimeout := time.Duration(b.ResponseTimeout)\n\tdialContext := net.Dialer{Timeout: timeout, DualStack: true}\n\ttransport := http.Transport{\n\t\tDialContext:     dialContext.DialContext,\n\t\tTLSClientConfig: tlsCfg,\n\t\t// If b.ConcurrentConnections <= 1, then DefaultMaxIdleConnsPerHost is used (=2)\n\t\tMaxIdleConnsPerHost: b.ConcurrentConnections / 2,\n\t\t// If b.ConcurrentConnections == 0, then it is treated as \"no limits\"\n\t\tMaxConnsPerHost:       b.ConcurrentConnections,\n\t\tResponseHeaderTimeout: timeout,\n\t\tIdleConnTimeout:       90 * time.Second,\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &transport,\n\t\tTimeout:   timeout,\n\t}\n\n\treturn client, nil\n}\n\nfunc (b *Burrow) getResponse(u *url.URL) (*apiResponse, error) {\n\treq, err := http.NewRequest(http.MethodGet, u.String(), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif b.Username != \"\" {\n\t\treq.SetBasicAuth(b.Username, b.Password)\n\t}\n\n\tres, err := b.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer res.Body.Close()\n\tif res.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"wrong response: %d\", res.StatusCode)\n\t}\n\n\tares := &apiResponse{}\n\tdec := json.NewDecoder(res.Body)\n\n\treturn ares, dec.Decode(ares)\n}\n\nfunc (b *Burrow) gatherServer(src *url.URL, acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tr, err := b.getResponse(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tguard := make(chan struct{}, b.ConcurrentConnections)\n\tfor _, cluster := range r.Clusters {\n\t\tif !b.filterClusters.Match(cluster) {\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(cluster string) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// fetch topic list\n\t\t\t// endpoint: <api_prefix>/(cluster)/topic\n\t\t\tut := appendPathToURL(src, cluster, \"topic\")\n\t\t\tb.gatherTopics(guard, ut, cluster, acc)\n\t\t}(cluster)\n\n\t\twg.Add(1)\n\t\tgo func(cluster string) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// fetch consumer group list\n\t\t\t// endpoint: <api_prefix>/(cluster)/consumer\n\t\t\tuc := appendPathToURL(src, cluster, \"consumer\")\n\t\t\tb.gatherGroups(guard, uc, cluster, acc)\n\t\t}(cluster)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (b *Burrow) gatherTopics(guard chan struct{}, src *url.URL, cluster string, acc telegraf.Accumulator) {\n\tvar wg sync.WaitGroup\n\n\tr, err := b.getResponse(src)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, topic := range r.Topics {\n\t\tif !b.filterTopics.Match(topic) {\n\t\t\tcontinue\n\t\t}\n\n\t\tguard <- struct{}{}\n\t\twg.Add(1)\n\n\t\tgo func(topic string) {\n\t\t\tdefer func() {\n\t\t\t\t<-guard\n\t\t\t\twg.Done()\n\t\t\t}()\n\n\t\t\t// fetch topic offsets\n\t\t\t// endpoint: <api_prefix>/<cluster>/topic/<topic>\n\t\t\ttu := appendPathToURL(src, topic)\n\t\t\ttr, err := b.getResponse(tu)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tgenTopicMetrics(tr, cluster, topic, acc)\n\t\t}(topic)\n\t}\n\n\twg.Wait()\n}\n\nfunc genTopicMetrics(r *apiResponse, cluster, topic string, acc telegraf.Accumulator) {\n\tfor i, offset := range r.Offsets {\n\t\ttags := map[string]string{\n\t\t\t\"cluster\":   cluster,\n\t\t\t\"topic\":     topic,\n\t\t\t\"partition\": strconv.Itoa(i),\n\t\t}\n\n\t\tacc.AddFields(\n\t\t\t\"burrow_topic\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"offset\": offset,\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n}\n\nfunc (b *Burrow) gatherGroups(guard chan struct{}, src *url.URL, cluster string, acc telegraf.Accumulator) {\n\tvar wg sync.WaitGroup\n\n\tr, err := b.getResponse(src)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, group := range r.Groups {\n\t\tif !b.filterGroups.Match(group) {\n\t\t\tcontinue\n\t\t}\n\n\t\tguard <- struct{}{}\n\t\twg.Add(1)\n\n\t\tgo func(group string) {\n\t\t\tdefer func() {\n\t\t\t\t<-guard\n\t\t\t\twg.Done()\n\t\t\t}()\n\n\t\t\t// fetch consumer group status\n\t\t\t// endpoint: <api_prefix>/<cluster>/consumer/<group>/lag\n\t\t\tgl := appendPathToURL(src, group, \"lag\")\n\t\t\tgr, err := b.getResponse(gl)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tgenGroupStatusMetrics(gr, cluster, group, acc)\n\t\t\tb.genGroupLagMetrics(gr, cluster, group, acc)\n\t\t}(group)\n\t}\n\n\twg.Wait()\n}\n\nfunc genGroupStatusMetrics(r *apiResponse, cluster, group string, acc telegraf.Accumulator) {\n\tpartitionCount := r.Status.PartitionCount\n\tif partitionCount == 0 {\n\t\tpartitionCount = len(r.Status.Partitions)\n\t}\n\n\t// get max timestamp and total offset from partitions list\n\toffset := int64(0)\n\ttimestamp := int64(0)\n\tfor _, partition := range r.Status.Partitions {\n\t\toffset += partition.End.Offset\n\t\tif partition.End.Timestamp > timestamp {\n\t\t\ttimestamp = partition.End.Timestamp\n\t\t}\n\t}\n\n\tlag := int64(0)\n\tif r.Status.Maxlag != nil {\n\t\tlag = r.Status.Maxlag.CurrentLag\n\t}\n\n\tacc.AddFields(\n\t\t\"burrow_group\",\n\t\tmap[string]interface{}{\n\t\t\t\"status\":          r.Status.Status,\n\t\t\t\"status_code\":     mapStatusToCode(r.Status.Status),\n\t\t\t\"partition_count\": partitionCount,\n\t\t\t\"total_lag\":       r.Status.TotalLag,\n\t\t\t\"lag\":             lag,\n\t\t\t\"offset\":          offset,\n\t\t\t\"timestamp\":       timestamp,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"cluster\": cluster,\n\t\t\t\"group\":   group,\n\t\t},\n\t)\n}\n\nfunc (b *Burrow) genGroupLagMetrics(r *apiResponse, cluster, group string, acc telegraf.Accumulator) {\n\tfor _, partition := range r.Status.Partitions {\n\t\tif !b.filterTopics.Match(partition.Topic) {\n\t\t\tcontinue\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"burrow_partition\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\":      partition.Status,\n\t\t\t\t\"status_code\": mapStatusToCode(partition.Status),\n\t\t\t\t\"lag\":         partition.CurrentLag,\n\t\t\t\t\"offset\":      partition.End.Offset,\n\t\t\t\t\"timestamp\":   partition.End.Timestamp,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cluster\":   cluster,\n\t\t\t\t\"group\":     group,\n\t\t\t\t\"topic\":     partition.Topic,\n\t\t\t\t\"partition\": strconv.FormatInt(int64(partition.Partition), 10),\n\t\t\t\t\"owner\":     partition.Owner,\n\t\t\t},\n\t\t)\n\t}\n}\n\nfunc appendPathToURL(src *url.URL, parts ...string) *url.URL {\n\tdst := new(url.URL)\n\t*dst = *src\n\n\tfor i, part := range parts {\n\t\tparts[i] = url.PathEscape(part)\n\t}\n\n\text := strings.Join(parts, \"/\")\n\tdst.Path = fmt.Sprintf(\"%s/%s\", src.Path, ext)\n\treturn dst\n}\n\nfunc mapStatusToCode(src string) int {\n\tswitch src {\n\tcase \"OK\":\n\t\treturn 1\n\tcase \"NOT_FOUND\":\n\t\treturn 2\n\tcase \"WARN\":\n\t\treturn 3\n\tcase \"ERR\":\n\t\treturn 4\n\tcase \"STOP\":\n\t\treturn 5\n\tcase \"STALL\":\n\t\treturn 6\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"burrow\", func() telegraf.Input {\n\t\treturn &Burrow{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/burrow_test.go",
    "content": "package burrow\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// remap uri to json file, eg: /v3/kafka -> ./testdata/v3_kafka.json\nfunc getResponseJSON(requestURI string) ([]byte, int) {\n\turi := strings.TrimLeft(requestURI, \"/\")\n\tmappedFile := strings.ReplaceAll(uri, \"/\", \"_\")\n\tjsonFile := fmt.Sprintf(\"./testdata/%s.json\", mappedFile)\n\n\tcode := 200\n\t_, err := os.Stat(jsonFile)\n\tif err != nil {\n\t\tcode = 404\n\t\tjsonFile = \"./testdata/error.json\"\n\t}\n\n\t// respond with file\n\tb, err := os.ReadFile(jsonFile)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn b, code\n}\n\n// return mocked HTTP server\nfunc getHTTPServer() *httptest.Server {\n\treturn httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tbody, code := getResponseJSON(r.RequestURI)\n\t\tw.WriteHeader(code)\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tw.Write(body) //nolint:errcheck // ignore the returned error as the test will fail anyway\n\t}))\n}\n\n// return mocked HTTP server with basic auth\nfunc getHTTPServerBasicAuth() *httptest.Server {\n\treturn httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"WWW-Authenticate\", `Basic realm=\"Restricted\"`)\n\n\t\tusername, password, authOK := r.BasicAuth()\n\t\tif !authOK {\n\t\t\thttp.Error(w, \"Not authorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tif username != \"test\" && password != \"test\" {\n\t\t\thttp.Error(w, \"Not authorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\t// ok, continue\n\t\tbody, code := getResponseJSON(r.RequestURI)\n\t\tw.WriteHeader(code)\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tw.Write(body) //nolint:errcheck // ignore the returned error as the test will fail anyway\n\t}))\n}\n\n// test burrow_topic measurement\nfunc TestBurrowTopic(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{Servers: []string{s.URL}}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tfields := []map[string]interface{}{\n\t\t// topicA\n\t\t{\"offset\": int64(459178195)},\n\t\t{\"offset\": int64(459178022)},\n\t\t{\"offset\": int64(456491598)},\n\t}\n\ttags := []map[string]string{\n\t\t// topicA\n\t\t{\"cluster\": \"clustername1\", \"topic\": \"topicA\", \"partition\": \"0\"},\n\t\t{\"cluster\": \"clustername1\", \"topic\": \"topicA\", \"partition\": \"1\"},\n\t\t{\"cluster\": \"clustername1\", \"topic\": \"topicA\", \"partition\": \"2\"},\n\t}\n\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasMeasurement(\"burrow_topic\"))\n\tfor i := 0; i < len(fields); i++ {\n\t\tacc.AssertContainsTaggedFields(t, \"burrow_topic\", fields[i], tags[i])\n\t}\n}\n\n// test burrow_partition measurement\nfunc TestBurrowPartition(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers: []string{s.URL},\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tfields := []map[string]interface{}{\n\t\t{\n\t\t\t\"status\":      \"OK\",\n\t\t\t\"status_code\": 1,\n\t\t\t\"lag\":         int64(0),\n\t\t\t\"offset\":      int64(431323195),\n\t\t\t\"timestamp\":   int64(1515609490008),\n\t\t},\n\t\t{\n\t\t\t\"status\":      \"OK\",\n\t\t\t\"status_code\": 1,\n\t\t\t\"lag\":         int64(0),\n\t\t\t\"offset\":      int64(431322962),\n\t\t\t\"timestamp\":   int64(1515609490008),\n\t\t},\n\t\t{\n\t\t\t\"status\":      \"OK\",\n\t\t\t\"status_code\": 1,\n\t\t\t\"lag\":         int64(0),\n\t\t\t\"offset\":      int64(428636563),\n\t\t\t\"timestamp\":   int64(1515609490008),\n\t\t},\n\t}\n\ttags := []map[string]string{\n\t\t{\"cluster\": \"clustername1\", \"group\": \"group1\", \"topic\": \"topicA\", \"partition\": \"0\", \"owner\": \"kafka1\"},\n\t\t{\"cluster\": \"clustername1\", \"group\": \"group1\", \"topic\": \"topicA\", \"partition\": \"1\", \"owner\": \"kafka2\"},\n\t\t{\"cluster\": \"clustername1\", \"group\": \"group1\", \"topic\": \"topicA\", \"partition\": \"2\", \"owner\": \"kafka3\"},\n\t}\n\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasMeasurement(\"burrow_partition\"))\n\n\tfor i := 0; i < len(fields); i++ {\n\t\tacc.AssertContainsTaggedFields(t, \"burrow_partition\", fields[i], tags[i])\n\t}\n}\n\n// burrow_group\nfunc TestBurrowGroup(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers: []string{s.URL},\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tfields := []map[string]interface{}{\n\t\t{\n\t\t\t\"status\":          \"OK\",\n\t\t\t\"status_code\":     1,\n\t\t\t\"partition_count\": 3,\n\t\t\t\"total_lag\":       int64(0),\n\t\t\t\"lag\":             int64(0),\n\t\t\t\"offset\":          int64(431323195 + 431322962 + 428636563),\n\t\t\t\"timestamp\":       int64(1515609490008),\n\t\t},\n\t}\n\n\ttags := []map[string]string{\n\t\t{\"cluster\": \"clustername1\", \"group\": \"group1\"},\n\t}\n\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasMeasurement(\"burrow_group\"))\n\n\tfor i := 0; i < len(fields); i++ {\n\t\tacc.AssertContainsTaggedFields(t, \"burrow_group\", fields[i], tags[i])\n\t}\n}\n\n// collect from multiple servers\nfunc TestMultipleServers(t *testing.T) {\n\ts1 := getHTTPServer()\n\tdefer s1.Close()\n\n\ts2 := getHTTPServer()\n\tdefer s2.Close()\n\n\tplugin := &Burrow{\n\t\tServers: []string{s1.URL, s2.URL},\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 14)\n\trequire.Empty(t, acc.Errors)\n}\n\n// collect multiple times\nfunc TestMultipleRuns(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers: []string{s.URL},\n\t}\n\tfor i := 0; i < 4; i++ {\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, plugin.Gather(acc))\n\n\t\trequire.Len(t, acc.Metrics, 7)\n\t\trequire.Empty(t, acc.Errors)\n\t}\n}\n\n// collect from http basic auth server\nfunc TestBasicAuthConfig(t *testing.T) {\n\ts := getHTTPServerBasicAuth()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers:  []string{s.URL},\n\t\tUsername: \"test\",\n\t\tPassword: \"test\",\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 7)\n\trequire.Empty(t, acc.Errors)\n}\n\n// collect from whitelisted clusters\nfunc TestFilterClusters(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers:         []string{s.URL},\n\t\tClustersInclude: []string{\"wrongname*\"}, // clustername1 -> no match\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\t// no match by cluster\n\trequire.Empty(t, acc.Metrics)\n\trequire.Empty(t, acc.Errors)\n}\n\n// collect from whitelisted groups\nfunc TestFilterGroups(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers:       []string{s.URL},\n\t\tGroupsInclude: []string{\"group?\"}, // group1 -> match\n\t\tTopicsExclude: []string{\"*\"},      // exclude all\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Empty(t, acc.Errors)\n}\n\n// collect from whitelisted topics\nfunc TestFilterTopics(t *testing.T) {\n\ts := getHTTPServer()\n\tdefer s.Close()\n\n\tplugin := &Burrow{\n\t\tServers:       []string{s.URL},\n\t\tTopicsInclude: []string{\"topic?\"}, // topicA -> match\n\t\tGroupsExclude: []string{\"*\"},      // exclude all\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 3)\n\trequire.Empty(t, acc.Errors)\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/sample.conf",
    "content": "# Collect Kafka topics and consumers status from Burrow HTTP API.\n[[inputs.burrow]]\n  ## Burrow API endpoints in format \"schema://host:port\".\n  ## Default is \"http://localhost:8000\".\n  servers = [\"http://localhost:8000\"]\n\n  ## Override Burrow API prefix.\n  ## Useful when Burrow is behind reverse-proxy.\n  # api_prefix = \"/v3/kafka\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Limit per-server concurrent connections.\n  ## Useful in case of large number of topics or consumer groups.\n  # concurrent_connections = 20\n\n  ## Filter clusters, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # clusters_include = []\n  # clusters_exclude = []\n\n  ## Filter consumer groups, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # groups_include = []\n  # groups_exclude = []\n\n  ## Filter topics, default is no filtering.\n  ## Values can be specified as glob patterns.\n  # topics_include = []\n  # topics_exclude = []\n\n  ## Credentials for basic HTTP authentication.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional SSL config\n  # ssl_ca = \"/etc/telegraf/ca.pem\"\n  # ssl_cert = \"/etc/telegraf/cert.pem\"\n  # ssl_key = \"/etc/telegraf/key.pem\"\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/error.json",
    "content": "{\n  \"error\": true,\n  \"message\": \"Detailed error message\",\n  \"request\": {\n    \"uri\": \"/invalid/request\",\n    \"host\": \"responding.host.example.com\",\n    \"cluster\": \"\",\n    \"group\": \"\",\n    \"topic\": \"\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/v3_kafka.json",
    "content": "{\n  \"error\": false,\n  \"message\": \"cluster list returned\",\n  \"clusters\": [\n    \"clustername1\"\n  ],\n  \"request\": {\n    \"url\": \"/v3/kafka\",\n    \"host\": \"example.com\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/v3_kafka_clustername1_consumer.json",
    "content": "{\n  \"error\": false,\n  \"message\": \"consumer list returned\",\n  \"consumers\": [\n    \"group1\"\n  ],\n  \"request\": {\n    \"url\": \"/v3/kafka/clustername1/consumer\",\n    \"host\": \"example.com\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/v3_kafka_clustername1_consumer_group1_lag.json",
    "content": "{\n  \"error\": false,\n  \"message\": \"consumer status returned\",\n  \"status\": {\n    \"cluster\": \"clustername1\",\n    \"group\": \"group1\",\n    \"status\": \"OK\",\n    \"complete\": 1,\n    \"partitions\": [\n      {\n        \"topic\": \"topicA\",\n        \"partition\": 0,\n        \"owner\": \"kafka1\",\n        \"status\": \"OK\",\n        \"start\": {\n          \"offset\": 431323195,\n          \"timestamp\": 1515609445004,\n          \"lag\": 0\n        },\n        \"end\": {\n          \"offset\": 431323195,\n          \"timestamp\": 1515609490008,\n          \"lag\": 0\n        },\n        \"current_lag\": 0,\n        \"complete\": 1\n      },\n      {\n        \"topic\": \"topicA\",\n        \"partition\": 1,\n        \"owner\": \"kafka2\",\n        \"status\": \"OK\",\n        \"start\": {\n          \"offset\": 431322962,\n          \"timestamp\": 1515609445004,\n          \"lag\": 0\n        },\n        \"end\": {\n          \"offset\": 431322962,\n          \"timestamp\": 1515609490008,\n          \"lag\": 0\n        },\n        \"current_lag\": 0,\n        \"complete\": 1\n      },\n      {\n        \"topic\": \"topicA\",\n        \"partition\": 2,\n        \"owner\": \"kafka3\",\n        \"status\": \"OK\",\n        \"start\": {\n          \"offset\": 428636563,\n          \"timestamp\": 1515609445004,\n          \"lag\": 0\n        },\n        \"end\": {\n          \"offset\": 428636563,\n          \"timestamp\": 1515609490008,\n          \"lag\": 0\n        },\n        \"current_lag\": 0,\n        \"complete\": 1\n      }\n    ],\n    \"partition_count\": 3,\n    \"maxlag\": {\n      \"topic\": \"topicA\",\n      \"partition\": 0,\n      \"owner\": \"kafka\",\n      \"status\": \"OK\",\n      \"start\": {\n        \"offset\": 431323195,\n        \"timestamp\": 1515609445004,\n        \"lag\": 0\n      },\n      \"end\": {\n        \"offset\": 431323195,\n        \"timestamp\": 1515609490008,\n        \"lag\": 0\n      },\n      \"current_lag\": 0,\n      \"complete\": 1\n    },\n    \"totallag\": 0\n  },\n  \"request\": {\n    \"url\": \"/v3/kafka/clustername1/consumer/group1/lag\",\n    \"host\": \"example.com\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/v3_kafka_clustername1_topic.json",
    "content": "{\n  \"error\": false,\n  \"message\": \"topic list returned\",\n  \"topics\": [\n    \"topicA\"\n  ],\n  \"request\": {\n    \"url\": \"/v3/kafka/clustername1/topic\",\n    \"host\": \"example.com\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/burrow/testdata/v3_kafka_clustername1_topic_topicA.json",
    "content": "{\n  \"error\": false,\n  \"message\": \"topic offsets returned\",\n  \"offsets\": [\n    459178195,\n    459178022,\n    456491598\n  ],\n  \"request\": {\n    \"url\": \"/v3/kafka/clustername1/topic/topicA\",\n    \"host\": \"example.com\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/ceph/README.md",
    "content": "# Ceph Storage Input Plugin\n\nThis plugin collects performance metrics from MON and OSD nodes in a\n[Ceph storage cluster][ceph]. Support for Telegraf has been introduced in the\nv13.x Mimic release where data is sent to a socket (see\n[their documnetation][docs]).\n\n⭐ Telegraf v0.13.1\n🏷️ system\n💻 all\n\n[ceph]: https://ceph.com\n[docs]: https://docs.ceph.com/en/latest/mgr/telegraf\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collects performance metrics from the MON, OSD, MDS and RGW nodes\n# in a Ceph storage cluster.\n[[inputs.ceph]]\n  ## This is the recommended interval to poll. Too frequent and you\n  ## will lose data points due to timeouts during rebalancing and recovery\n  interval = '1m'\n\n  ## All configuration values are optional, defaults are shown below\n\n  ## location of ceph binary\n  ceph_binary = \"/usr/bin/ceph\"\n\n  ## directory in which to look for socket files\n  socket_dir = \"/var/run/ceph\"\n\n  ## prefix of MON and OSD socket files, used to determine socket type\n  mon_prefix = \"ceph-mon\"\n  osd_prefix = \"ceph-osd\"\n  mds_prefix = \"ceph-mds\"\n  rgw_prefix = \"ceph-client\"\n\n  ## suffix used to identify socket files\n  socket_suffix = \"asok\"\n\n  ## Ceph user to authenticate as, ceph will search for the corresponding\n  ## keyring e.g. client.admin.keyring in /etc/ceph, or the explicit path\n  ## defined in the client section of ceph.conf for example:\n  ##\n  ##     [client.telegraf]\n  ##         keyring = /etc/ceph/client.telegraf.keyring\n  ##\n  ## Consult the ceph documentation for more detail on keyring generation.\n  ceph_user = \"client.admin\"\n\n  ## Ceph configuration to use to locate the cluster\n  ceph_config = \"/etc/ceph/ceph.conf\"\n\n  ## Whether to gather statistics via the admin socket\n  gather_admin_socket_stats = true\n\n  ## Whether to gather statistics via ceph commands, requires ceph_user\n  ## and ceph_config to be specified\n  gather_cluster_stats = false\n```\n\n## Admin Socket Stats\n\nThis gatherer works by scanning the configured SocketDir for OSD, MON, MDS\nand RGW socket files.  When it finds a MON socket, it runs\n\n```shell\nceph --admin-daemon $file perfcounters_dump\n```\n\nFor OSDs it runs\n\n```shell\nceph --admin-daemon $file perf dump\n```\n\nThe resulting JSON is parsed and grouped into collections, based on\ntop-level key. Top-level keys are used as collection tags, and all\nsub-keys are flattened. For example:\n\n```json\n {\n   \"paxos\": {\n     \"refresh\": 9363435,\n     \"refresh_latency\": {\n       \"avgcount\": 9363435,\n       \"sum\": 5378.794002000\n     }\n   }\n }\n```\n\nWould be parsed into the following metrics, all of which would be tagged\nwith `collection=paxos`:\n\n- refresh = 9363435\n- refresh_latency.avgcount: 9363435\n- refresh_latency.sum: 5378.794002000\n\n## Cluster Stats\n\nThis gatherer works by invoking ceph commands against the cluster thus only\nrequires the ceph client, valid ceph configuration and an access key to\nfunction (the ceph_config and ceph_user configuration variables work in\nconjunction to specify these prerequisites). It may be run on any server you\nwish which has access to the cluster.  The currently supported commands are:\n\n- ceph status\n- ceph df\n- ceph osd pool stats\n\n## Metrics\n\n### Admin Socket\n\nAll fields are collected under the **ceph** measurement and stored as\nfloat64s. For a full list of fields, see the sample perf dumps in ceph_test.go.\n\nAll admin measurements will have the following tags:\n\n- type: either 'osd', 'mon', 'mds' or 'rgw' to indicate the queried node type\n- id: a unique string identifier, parsed from the socket file name for the node\n- collection: the top-level key under which these fields were reported.\n  Possible values are:\n  - for MON nodes:\n    - cluster\n    - leveldb\n    - mon\n    - paxos\n    - throttle-mon_client_bytes\n    - throttle-mon_daemon_bytes\n    - throttle-msgr_dispatch_throttler-mon\n  - for OSD nodes:\n    - WBThrottle\n    - filestore\n    - leveldb\n    - mutex-FileJournal::completions_lock\n    - mutex-FileJournal::finisher_lock\n    - mutex-FileJournal::write_lock\n    - mutex-FileJournal::writeq_lock\n    - mutex-JOS::ApplyManager::apply_lock\n    - mutex-JOS::ApplyManager::com_lock\n    - mutex-JOS::SubmitManager::lock\n    - mutex-WBThrottle::lock\n    - objecter\n    - osd\n    - recoverystate_perf\n    - throttle-filestore_bytes\n    - throttle-filestore_ops\n    - throttle-msgr_dispatch_throttler-client\n    - throttle-msgr_dispatch_throttler-cluster\n    - throttle-msgr_dispatch_throttler-hb_back_server\n    - throttle-msgr_dispatch_throttler-hb_front_serve\n    - throttle-msgr_dispatch_throttler-hbclient\n    - throttle-msgr_dispatch_throttler-ms_objecter\n    - throttle-objecter_bytes\n    - throttle-objecter_ops\n    - throttle-osd_client_bytes\n    - throttle-osd_client_messages\n  - for MDS nodes:\n    - AsyncMessenger::Worker-0\n    - AsyncMessenger::Worker-1\n    - AsyncMessenger::Worker-2\n    - finisher-PurgeQueue\n    - mds\n    - mds_cache\n    - mds_log\n    - mds_mem\n    - mds_server\n    - mds_sessions\n    - objecter\n    - purge_queue\n    - throttle-msgr_dispatch_throttler-mds\n    - throttle-objecter_bytes\n    - throttle-objecter_ops\n    - throttle-write_buf_throttle\n  - for RGW nodes:\n    - AsyncMessenger::Worker-0\n    - AsyncMessenger::Worker-1\n    - AsyncMessenger::Worker-2\n    - cct\n    - finisher-radosclient\n    - mempool\n    - objecter\n    - rgw\n    - simple-throttler\n    - throttle-msgr_dispatch_throttler-radosclient\n    - throttle-objecter_bytes\n    - throttle-objecter_ops\n    - throttle-rgw_async_rados_ops\n\n## Cluster\n\n- ceph_fsmap\n  - fields:\n    - up (float)\n    - in (float)\n    - max (float)\n    - up_standby (float)\n\n- ceph_health\n  - fields:\n    - status (string)\n    - status_code (int)\n    - overall_status (string, exists only in ceph <15)\n\n- ceph_monmap\n  - fields:\n    - num_mons (float)\n\n- ceph_osdmap\n  - fields:\n    - epoch (float)\n    - full (bool, exists only in ceph <15)\n    - nearfull (bool, exists only in ceph <15)\n    - num_in_osds (float)\n    - num_osds (float)\n    - num_remapped_pgs (float)\n    - num_up_osds (float)\n\n- ceph_pgmap\n  - fields:\n    - bytes_avail (float)\n    - bytes_total (float)\n    - bytes_used (float)\n    - data_bytes (float)\n    - degraded_objects (float)\n    - degraded_ratio (float)\n    - degraded_total (float)\n    - inactive_pgs_ratio (float)\n    - num_bytes_recovered (float)\n    - num_keys_recovered (float)\n    - num_objects (float)\n    - num_objects_recovered (float)\n    - num_pgs (float)\n    - num_pools (float)\n    - op_per_sec (float, exists only in ceph <10)\n    - read_bytes_sec (float)\n    - read_op_per_sec (float)\n    - recovering_bytes_per_sec (float)\n    - recovering_keys_per_sec (float)\n    - recovering_objects_per_sec (float)\n    - version (float)\n    - write_bytes_sec (float)\n    - write_op_per_sec (float)\n\n- ceph_pgmap_state\n  - tags:\n    - state\n  - fields:\n    - count (float)\n\n- ceph_usage\n  - fields:\n    - num_osd (float)\n    - num_per_pool_omap_osds (float)\n    - num_per_pool_osds (float)\n    - total_avail (float, exists only in ceph <0.84)\n    - total_avail_bytes (float)\n    - total_bytes (float)\n    - total_space (float, exists only in ceph <0.84)\n    - total_used (float, exists only in ceph <0.84)\n    - total_used_bytes (float)\n    - total_used_raw_bytes (float)\n    - total_used_raw_ratio (float)\n\n- ceph_deviceclass_usage\n  - tags:\n    - class\n  - fields:\n    - total_avail_bytes (float)\n    - total_bytes (float)\n    - total_used_bytes (float)\n    - total_used_raw_bytes (float)\n    - total_used_raw_ratio (float)\n\n- ceph_pool_usage\n  - tags:\n    - name\n  - fields:\n    - bytes_used (float)\n    - kb_used (float)\n    - max_avail (float)\n    - objects (float)\n    - percent_used (float)\n    - stored (float)\n\n- ceph_pool_stats\n  - tags:\n    - name\n  - fields:\n    - degraded_objects (float)\n    - degraded_ratio (float)\n    - degraded_total (float)\n    - num_bytes_recovered (float)\n    - num_keys_recovered (float)\n    - num_objects_recovered (float)\n    - op_per_sec (float, exists only in ceph <10)\n    - read_bytes_sec (float)\n    - read_op_per_sec (float)\n    - recovering_bytes_per_sec (float)\n    - recovering_keys_per_sec (float)\n    - recovering_objects_per_sec (float)\n    - write_bytes_sec (float)\n    - write_op_per_sec (float)\n\n## Example Output\n\nBelow is an example of a cluster stats:\n\n```text\nceph_fsmap,host=ceph in=1,max=1,up=1,up_standby=2 1646782035000000000\nceph_health,host=ceph status=\"HEALTH_OK\",status_code=2 1646782035000000000\nceph_monmap,host=ceph num_mons=3 1646782035000000000\nceph_osdmap,host=ceph epoch=10560,num_in_osds=6,num_osds=6,num_remapped_pgs=0,num_up_osds=6 1646782035000000000\nceph_pgmap,host=ceph bytes_avail=7863124942848,bytes_total=14882929901568,bytes_used=7019804958720,data_bytes=2411111520818,degraded_objects=0,degraded_ratio=0,degraded_total=0,inactive_pgs_ratio=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects=973030,num_objects_recovered=0,num_pgs=233,num_pools=6,read_bytes_sec=7334,read_op_per_sec=2,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,version=0,write_bytes_sec=13113085,write_op_per_sec=355 1646782035000000000\nceph_pgmap_state,host=ceph,state=active+clean count=233 1646782035000000000\nceph_usage,host=ceph num_osds=6,num_per_pool_omap_osds=6,num_per_pool_osds=6,total_avail_bytes=7863124942848,total_bytes=14882929901568,total_used_bytes=7019804958720,total_used_raw_bytes=7019804958720,total_used_raw_ratio=0.47166821360588074 1646782035000000000\nceph_deviceclass_usage,class=hdd,host=ceph total_avail_bytes=6078650843136,total_bytes=12002349023232,total_used_bytes=5923698180096,total_used_raw_bytes=5923698180096,total_used_raw_ratio=0.49354490637779236 1646782035000000000\nceph_deviceclass_usage,class=ssd,host=ceph total_avail_bytes=1784474099712,total_bytes=2880580878336,total_used_bytes=1096106778624,total_used_raw_bytes=1096106778624,total_used_raw_ratio=0.3805158734321594 1646782035000000000\nceph_pool_usage,host=ceph,name=Foo bytes_used=2019483848658,kb_used=1972152196,max_avail=1826022621184,objects=161029,percent_used=0.26935243606567383,stored=672915064134 1646782035000000000\nceph_pool_usage,host=ceph,name=Bar_metadata bytes_used=4370899787,kb_used=4268457,max_avail=546501918720,objects=89702,percent_used=0.002658897778019309,stored=1456936576 1646782035000000000\nceph_pool_usage,host=ceph,name=Bar_data bytes_used=3893328740352,kb_used=3802078848,max_avail=1826022621184,objects=518396,percent_used=0.41544806957244873,stored=1292214337536 1646782035000000000\nceph_pool_usage,host=ceph,name=device_health_metrics bytes_used=85289044,kb_used=83291,max_avail=3396406870016,objects=9,percent_used=0.000012555617104226258,stored=42644520 1646782035000000000\nceph_pool_usage,host=ceph,name=Foo_Fast bytes_used=597511814461,kb_used=583507632,max_avail=546501918720,objects=67014,percent_used=0.2671019732952118,stored=199093853972 1646782035000000000\nceph_pool_usage,host=ceph,name=Bar_data_fast bytes_used=490009280512,kb_used=478524688,max_avail=546501918720,objects=136880,percent_used=0.23010368645191193,stored=163047325696 1646782035000000000\nceph_pool_stats,host=ceph,name=Foo degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=0,read_op_per_sec=0,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=27720,write_op_per_sec=4 1646782036000000000\nceph_pool_stats,host=ceph,name=Bar_metadata degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=9638,read_op_per_sec=3,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=11802778,write_op_per_sec=60 1646782036000000000\nceph_pool_stats,host=ceph,name=Bar_data degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=0,read_op_per_sec=0,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=0,write_op_per_sec=104 1646782036000000000\nceph_pool_stats,host=ceph,name=device_health_metrics degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=0,read_op_per_sec=0,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=0,write_op_per_sec=0 1646782036000000000\nceph_pool_stats,host=ceph,name=Foo_Fast degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=0,read_op_per_sec=0,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=11173,write_op_per_sec=1 1646782036000000000\nceph_pool_stats,host=ceph,name=Bar_data_fast degraded_objects=0,degraded_ratio=0,degraded_total=0,num_bytes_recovered=0,num_keys_recovered=0,num_objects_recovered=0,read_bytes_sec=0,read_op_per_sec=0,recovering_bytes_per_sec=0,recovering_keys_per_sec=0,recovering_objects_per_sec=0,write_bytes_sec=2155404,write_op_per_sec=262 1646782036000000000\n```\n\nBelow is an example of admin socket stats:\n\n```text\nceph,collection=cct,host=stefanmon1,id=stefanmon1,type=monitor total_workers=0,unhealthy_workers=0 1587117563000000000\nceph,collection=mempool,host=stefanmon1,id=stefanmon1,type=monitor bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=0,bluefs_items=0,bluestore_alloc_bytes=0,bluestore_alloc_items=0,bluestore_cache_data_bytes=0,bluestore_cache_data_items=0,bluestore_cache_onode_bytes=0,bluestore_cache_onode_items=0,bluestore_cache_other_bytes=0,bluestore_cache_other_items=0,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=0,bluestore_txc_items=0,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=0,bluestore_writing_deferred_items=0,bluestore_writing_items=0,buffer_anon_bytes=719152,buffer_anon_items=192,buffer_meta_bytes=352,buffer_meta_items=4,mds_co_bytes=0,mds_co_items=0,osd_bytes=0,osd_items=0,osd_mapbl_bytes=0,osd_mapbl_items=0,osd_pglog_bytes=0,osd_pglog_items=0,osdmap_bytes=15872,osdmap_items=138,osdmap_mapping_bytes=63112,osdmap_mapping_items=7626,pgmap_bytes=38680,pgmap_items=477,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117563000000000\nceph,collection=throttle-mon_client_bytes,host=stefanmon1,id=stefanmon1,type=monitor get=1041157,get_or_fail_fail=0,get_or_fail_success=1041157,get_started=0,get_sum=64928901,max=104857600,put=1041157,put_sum=64928901,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117563000000000\nceph,collection=throttle-msgr_dispatch_throttler-mon,host=stefanmon1,id=stefanmon1,type=monitor get=12695426,get_or_fail_fail=0,get_or_fail_success=12695426,get_started=0,get_sum=42542216884,max=104857600,put=12695426,put_sum=42542216884,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117563000000000\nceph,collection=finisher-mon_finisher,host=stefanmon1,id=stefanmon1,type=monitor complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117563000000000\nceph,collection=finisher-monstore,host=stefanmon1,id=stefanmon1,type=monitor complete_latency.avgcount=1609831,complete_latency.avgtime=0.015857621,complete_latency.sum=25528.09131035,queue_len=0 1587117563000000000\nceph,collection=mon,host=stefanmon1,id=stefanmon1,type=monitor election_call=25,election_lose=0,election_win=22,num_elections=94,num_sessions=3,session_add=174679,session_rm=439316,session_trim=137 1587117563000000000\nceph,collection=throttle-mon_daemon_bytes,host=stefanmon1,id=stefanmon1,type=monitor get=72697,get_or_fail_fail=0,get_or_fail_success=72697,get_started=0,get_sum=32261199,max=419430400,put=72697,put_sum=32261199,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117563000000000\nceph,collection=rocksdb,host=stefanmon1,id=stefanmon1,type=monitor compact=1,compact_queue_len=0,compact_queue_merge=1,compact_range=19126,get=62449211,get_latency.avgcount=62449211,get_latency.avgtime=0.000022216,get_latency.sum=1387.371811726,rocksdb_write_delay_time.avgcount=0,rocksdb_write_delay_time.avgtime=0,rocksdb_write_delay_time.sum=0,rocksdb_write_memtable_time.avgcount=0,rocksdb_write_memtable_time.avgtime=0,rocksdb_write_memtable_time.sum=0,rocksdb_write_pre_and_post_time.avgcount=0,rocksdb_write_pre_and_post_time.avgtime=0,rocksdb_write_pre_and_post_time.sum=0,rocksdb_write_wal_time.avgcount=0,rocksdb_write_wal_time.avgtime=0,rocksdb_write_wal_time.sum=0,submit_latency.avgcount=0,submit_latency.avgtime=0,submit_latency.sum=0,submit_sync_latency.avgcount=3219961,submit_sync_latency.avgtime=0.007532173,submit_sync_latency.sum=24253.303584224,submit_transaction=0,submit_transaction_sync=3219961 1587117563000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanmon1,id=stefanmon1,type=monitor msgr_active_connections=148317,msgr_created_connections=162806,msgr_recv_bytes=11557888328,msgr_recv_messages=5113369,msgr_running_fast_dispatch_time=0,msgr_running_recv_time=868.377161686,msgr_running_send_time=1626.525392721,msgr_running_total_time=4222.235694322,msgr_send_bytes=91516226816,msgr_send_messages=6973706 1587117563000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanmon1,id=stefanmon1,type=monitor msgr_active_connections=146396,msgr_created_connections=159788,msgr_recv_bytes=2162802496,msgr_recv_messages=689168,msgr_running_fast_dispatch_time=0,msgr_running_recv_time=164.148550562,msgr_running_send_time=153.462890368,msgr_running_total_time=644.188791379,msgr_send_bytes=7422484152,msgr_send_messages=749381 1587117563000000000\nceph,collection=cluster,host=stefanmon1,id=stefanmon1,type=monitor num_bytes=5055,num_mon=3,num_mon_quorum=3,num_object=245,num_object_degraded=0,num_object_misplaced=0,num_object_unfound=0,num_osd=9,num_osd_in=8,num_osd_up=8,num_pg=504,num_pg_active=504,num_pg_active_clean=504,num_pg_peering=0,num_pool=17,osd_bytes=858959904768,osd_bytes_avail=849889787904,osd_bytes_used=9070116864,osd_epoch=203 1587117563000000000\nceph,collection=paxos,host=stefanmon1,id=stefanmon1,type=monitor accept_timeout=1,begin=1609847,begin_bytes.avgcount=1609847,begin_bytes.sum=41408662074,begin_keys.avgcount=1609847,begin_keys.sum=4829541,begin_latency.avgcount=1609847,begin_latency.avgtime=0.007213392,begin_latency.sum=11612.457661116,collect=0,collect_bytes.avgcount=0,collect_bytes.sum=0,collect_keys.avgcount=0,collect_keys.sum=0,collect_latency.avgcount=0,collect_latency.avgtime=0,collect_latency.sum=0,collect_timeout=1,collect_uncommitted=17,commit=1609831,commit_bytes.avgcount=1609831,commit_bytes.sum=41087428442,commit_keys.avgcount=1609831,commit_keys.sum=11637931,commit_latency.avgcount=1609831,commit_latency.avgtime=0.006236333,commit_latency.sum=10039.442388355,lease_ack_timeout=0,lease_timeout=0,new_pn=33,new_pn_latency.avgcount=33,new_pn_latency.avgtime=3.844272773,new_pn_latency.sum=126.86100151,refresh=1609856,refresh_latency.avgcount=1609856,refresh_latency.avgtime=0.005900486,refresh_latency.sum=9498.932866761,restart=109,share_state=2,share_state_bytes.avgcount=2,share_state_bytes.sum=39612,share_state_keys.avgcount=2,share_state_keys.sum=2,start_leader=22,start_peon=0,store_state=14,store_state_bytes.avgcount=14,store_state_bytes.sum=51908281,store_state_keys.avgcount=14,store_state_keys.sum=7016,store_state_latency.avgcount=14,store_state_latency.avgtime=11.668377665,store_state_latency.sum=163.357287311 1587117563000000000\nceph,collection=throttle-msgr_dispatch_throttler-mon-mgrc,host=stefanmon1,id=stefanmon1,type=monitor get=13225,get_or_fail_fail=0,get_or_fail_success=13225,get_started=0,get_sum=158700,max=104857600,put=13225,put_sum=158700,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117563000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanmon1,id=stefanmon1,type=monitor msgr_active_connections=147680,msgr_created_connections=162374,msgr_recv_bytes=29781706740,msgr_recv_messages=7170733,msgr_running_fast_dispatch_time=0,msgr_running_recv_time=1728.559151358,msgr_running_send_time=2086.681244508,msgr_running_total_time=6084.532916585,msgr_send_bytes=94062125718,msgr_send_messages=9161564 1587117563000000000\nceph,collection=throttle-msgr_dispatch_throttler-cluster,host=stefanosd1,id=0,type=osd get=281745,get_or_fail_fail=0,get_or_fail_success=281745,get_started=0,get_sum=446024457,max=104857600,put=281745,put_sum=446024457,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-bluestore_throttle_bytes,host=stefanosd1,id=0,type=osd get=275707,get_or_fail_fail=0,get_or_fail_success=0,get_started=275707,get_sum=185073179842,max=67108864,put=268870,put_sum=185073179842,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_server,host=stefanosd1,id=0,type=osd get=2606982,get_or_fail_fail=0,get_or_fail_success=2606982,get_started=0,get_sum=5224391928,max=104857600,put=2606982,put_sum=5224391928,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=rocksdb,host=stefanosd1,id=0,type=osd compact=0,compact_queue_len=0,compact_queue_merge=0,compact_range=0,get=1570,get_latency.avgcount=1570,get_latency.avgtime=0.000051233,get_latency.sum=0.080436788,rocksdb_write_delay_time.avgcount=0,rocksdb_write_delay_time.avgtime=0,rocksdb_write_delay_time.sum=0,rocksdb_write_memtable_time.avgcount=0,rocksdb_write_memtable_time.avgtime=0,rocksdb_write_memtable_time.sum=0,rocksdb_write_pre_and_post_time.avgcount=0,rocksdb_write_pre_and_post_time.avgtime=0,rocksdb_write_pre_and_post_time.sum=0,rocksdb_write_wal_time.avgcount=0,rocksdb_write_wal_time.avgtime=0,rocksdb_write_wal_time.sum=0,submit_latency.avgcount=275707,submit_latency.avgtime=0.000174936,submit_latency.sum=48.231345334,submit_sync_latency.avgcount=268870,submit_sync_latency.avgtime=0.006097313,submit_sync_latency.sum=1639.384555624,submit_transaction=275707,submit_transaction_sync=268870 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_server,host=stefanosd1,id=0,type=osd get=2606982,get_or_fail_fail=0,get_or_fail_success=2606982,get_started=0,get_sum=5224391928,max=104857600,put=2606982,put_sum=5224391928,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-objecter_bytes,host=stefanosd1,id=0,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_client,host=stefanosd1,id=0,type=osd get=2610285,get_or_fail_fail=0,get_or_fail_success=2610285,get_started=0,get_sum=5231011140,max=104857600,put=2610285,put_sum=5231011140,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanosd1,id=0,type=osd msgr_active_connections=2093,msgr_created_connections=29142,msgr_recv_bytes=7214238199,msgr_recv_messages=3928206,msgr_running_fast_dispatch_time=171.289615064,msgr_running_recv_time=278.531155966,msgr_running_send_time=489.482588813,msgr_running_total_time=1134.004853662,msgr_send_bytes=9814725232,msgr_send_messages=3814927 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-client,host=stefanosd1,id=0,type=osd get=488206,get_or_fail_fail=0,get_or_fail_success=488206,get_started=0,get_sum=104085134,max=104857600,put=488206,put_sum=104085134,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=finisher-defered_finisher,host=stefanosd1,id=0,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=recoverystate_perf,host=stefanosd1,id=0,type=osd activating_latency.avgcount=87,activating_latency.avgtime=0.114348341,activating_latency.sum=9.948305683,active_latency.avgcount=25,active_latency.avgtime=1790.961574431,active_latency.sum=44774.039360795,backfilling_latency.avgcount=0,backfilling_latency.avgtime=0,backfilling_latency.sum=0,clean_latency.avgcount=25,clean_latency.avgtime=1790.830827794,clean_latency.sum=44770.770694867,down_latency.avgcount=0,down_latency.avgtime=0,down_latency.sum=0,getinfo_latency.avgcount=141,getinfo_latency.avgtime=0.446233476,getinfo_latency.sum=62.918920183,getlog_latency.avgcount=87,getlog_latency.avgtime=0.007708069,getlog_latency.sum=0.670602073,getmissing_latency.avgcount=87,getmissing_latency.avgtime=0.000077594,getmissing_latency.sum=0.006750701,incomplete_latency.avgcount=0,incomplete_latency.avgtime=0,incomplete_latency.sum=0,initial_latency.avgcount=166,initial_latency.avgtime=0.001313715,initial_latency.sum=0.218076764,notbackfilling_latency.avgcount=0,notbackfilling_latency.avgtime=0,notbackfilling_latency.sum=0,notrecovering_latency.avgcount=0,notrecovering_latency.avgtime=0,notrecovering_latency.sum=0,peering_latency.avgcount=141,peering_latency.avgtime=0.948324273,peering_latency.sum=133.713722563,primary_latency.avgcount=79,primary_latency.avgtime=567.706192991,primary_latency.sum=44848.78924634,recovered_latency.avgcount=87,recovered_latency.avgtime=0.000378284,recovered_latency.sum=0.032910791,recovering_latency.avgcount=2,recovering_latency.avgtime=0.338242008,recovering_latency.sum=0.676484017,replicaactive_latency.avgcount=23,replicaactive_latency.avgtime=1790.893991295,replicaactive_latency.sum=41190.561799786,repnotrecovering_latency.avgcount=25,repnotrecovering_latency.avgtime=1647.627024984,repnotrecovering_latency.sum=41190.675624616,reprecovering_latency.avgcount=2,reprecovering_latency.avgtime=0.311884638,reprecovering_latency.sum=0.623769276,repwaitbackfillreserved_latency.avgcount=0,repwaitbackfillreserved_latency.avgtime=0,repwaitbackfillreserved_latency.sum=0,repwaitrecoveryreserved_latency.avgcount=2,repwaitrecoveryreserved_latency.avgtime=0.000462873,repwaitrecoveryreserved_latency.sum=0.000925746,reset_latency.avgcount=372,reset_latency.avgtime=0.125056393,reset_latency.sum=46.520978537,start_latency.avgcount=372,start_latency.avgtime=0.000109397,start_latency.sum=0.040695881,started_latency.avgcount=206,started_latency.avgtime=418.299777245,started_latency.sum=86169.754112641,stray_latency.avgcount=231,stray_latency.avgtime=0.98203205,stray_latency.sum=226.849403565,waitactingchange_latency.avgcount=0,waitactingchange_latency.avgtime=0,waitactingchange_latency.sum=0,waitlocalbackfillreserved_latency.avgcount=0,waitlocalbackfillreserved_latency.avgtime=0,waitlocalbackfillreserved_latency.sum=0,waitlocalrecoveryreserved_latency.avgcount=2,waitlocalrecoveryreserved_latency.avgtime=0.002802377,waitlocalrecoveryreserved_latency.sum=0.005604755,waitremotebackfillreserved_latency.avgcount=0,waitremotebackfillreserved_latency.avgtime=0,waitremotebackfillreserved_latency.sum=0,waitremoterecoveryreserved_latency.avgcount=2,waitremoterecoveryreserved_latency.avgtime=0.012855439,waitremoterecoveryreserved_latency.sum=0.025710878,waitupthru_latency.avgcount=87,waitupthru_latency.avgtime=0.805727895,waitupthru_latency.sum=70.09832695 1587117698000000000\nceph,collection=cct,host=stefanosd1,id=0,type=osd total_workers=6,unhealthy_workers=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_client,host=stefanosd1,id=0,type=osd get=2610285,get_or_fail_fail=0,get_or_fail_success=2610285,get_started=0,get_sum=5231011140,max=104857600,put=2610285,put_sum=5231011140,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=bluefs,host=stefanosd1,id=0,type=osd bytes_written_slow=0,bytes_written_sst=9018781,bytes_written_wal=831081573,db_total_bytes=4294967296,db_used_bytes=434110464,files_written_sst=3,files_written_wal=2,gift_bytes=0,log_bytes=134291456,log_compactions=1,logged_bytes=1101668352,max_bytes_db=1234173952,max_bytes_slow=0,max_bytes_wal=0,num_files=11,reclaim_bytes=0,slow_total_bytes=0,slow_used_bytes=0,wal_total_bytes=0,wal_used_bytes=0 1587117698000000000\nceph,collection=mempool,host=stefanosd1,id=0,type=osd bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=10600,bluefs_items=458,bluestore_alloc_bytes=230288,bluestore_alloc_items=28786,bluestore_cache_data_bytes=622592,bluestore_cache_data_items=43,bluestore_cache_onode_bytes=249280,bluestore_cache_onode_items=380,bluestore_cache_other_bytes=192678,bluestore_cache_other_items=20199,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=8272,bluestore_txc_items=11,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=670130,bluestore_writing_deferred_items=176,bluestore_writing_items=0,buffer_anon_bytes=2412465,buffer_anon_items=297,buffer_meta_bytes=5896,buffer_meta_items=67,mds_co_bytes=0,mds_co_items=0,osd_bytes=2124800,osd_items=166,osd_mapbl_bytes=155152,osd_mapbl_items=10,osd_pglog_bytes=3214704,osd_pglog_items=6288,osdmap_bytes=710892,osdmap_items=4426,osdmap_mapping_bytes=0,osdmap_mapping_items=0,pgmap_bytes=0,pgmap_items=0,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117698000000000\nceph,collection=osd,host=stefanosd1,id=0,type=osd agent_evict=0,agent_flush=0,agent_skip=0,agent_wake=0,cached_crc=0,cached_crc_adjusted=0,copyfrom=0,heartbeat_to_peers=7,loadavg=11,map_message_epoch_dups=21,map_message_epochs=40,map_messages=31,messages_delayed_for_map=0,missed_crc=0,numpg=166,numpg_primary=62,numpg_removing=0,numpg_replica=104,numpg_stray=0,object_ctx_cache_hit=476529,object_ctx_cache_total=476536,op=476525,op_before_dequeue_op_lat.avgcount=755708,op_before_dequeue_op_lat.avgtime=0.000205759,op_before_dequeue_op_lat.sum=155.493843473,op_before_queue_op_lat.avgcount=755702,op_before_queue_op_lat.avgtime=0.000047877,op_before_queue_op_lat.sum=36.181069552,op_cache_hit=0,op_in_bytes=0,op_latency.avgcount=476525,op_latency.avgtime=0.000365956,op_latency.sum=174.387387878,op_out_bytes=10882,op_prepare_latency.avgcount=476527,op_prepare_latency.avgtime=0.000205307,op_prepare_latency.sum=97.834380034,op_process_latency.avgcount=476525,op_process_latency.avgtime=0.000139616,op_process_latency.sum=66.530847665,op_r=476521,op_r_latency.avgcount=476521,op_r_latency.avgtime=0.00036559,op_r_latency.sum=174.21148267,op_r_out_bytes=10882,op_r_prepare_latency.avgcount=476523,op_r_prepare_latency.avgtime=0.000205302,op_r_prepare_latency.sum=97.831473175,op_r_process_latency.avgcount=476521,op_r_process_latency.avgtime=0.000139396,op_r_process_latency.sum=66.425498624,op_rw=2,op_rw_in_bytes=0,op_rw_latency.avgcount=2,op_rw_latency.avgtime=0.048818975,op_rw_latency.sum=0.097637951,op_rw_out_bytes=0,op_rw_prepare_latency.avgcount=2,op_rw_prepare_latency.avgtime=0.000467887,op_rw_prepare_latency.sum=0.000935775,op_rw_process_latency.avgcount=2,op_rw_process_latency.avgtime=0.013741256,op_rw_process_latency.sum=0.027482512,op_w=2,op_w_in_bytes=0,op_w_latency.avgcount=2,op_w_latency.avgtime=0.039133628,op_w_latency.sum=0.078267257,op_w_prepare_latency.avgcount=2,op_w_prepare_latency.avgtime=0.000985542,op_w_prepare_latency.sum=0.001971084,op_w_process_latency.avgcount=2,op_w_process_latency.avgtime=0.038933264,op_w_process_latency.sum=0.077866529,op_wip=0,osd_map_bl_cache_hit=22,osd_map_bl_cache_miss=40,osd_map_cache_hit=4570,osd_map_cache_miss=15,osd_map_cache_miss_low=0,osd_map_cache_miss_low_avg.avgcount=0,osd_map_cache_miss_low_avg.sum=0,osd_pg_biginfo=2050,osd_pg_fastinfo=265780,osd_pg_info=274542,osd_tier_flush_lat.avgcount=0,osd_tier_flush_lat.avgtime=0,osd_tier_flush_lat.sum=0,osd_tier_promote_lat.avgcount=0,osd_tier_promote_lat.avgtime=0,osd_tier_promote_lat.sum=0,osd_tier_r_lat.avgcount=0,osd_tier_r_lat.avgtime=0,osd_tier_r_lat.sum=0,pull=0,push=2,push_out_bytes=10,recovery_bytes=10,recovery_ops=2,stat_bytes=107369988096,stat_bytes_avail=106271539200,stat_bytes_used=1098448896,subop=253554,subop_in_bytes=168644225,subop_latency.avgcount=253554,subop_latency.avgtime=0.0073036,subop_latency.sum=1851.857230388,subop_pull=0,subop_pull_latency.avgcount=0,subop_pull_latency.avgtime=0,subop_pull_latency.sum=0,subop_push=0,subop_push_in_bytes=0,subop_push_latency.avgcount=0,subop_push_latency.avgtime=0,subop_push_latency.sum=0,subop_w=253554,subop_w_in_bytes=168644225,subop_w_latency.avgcount=253554,subop_w_latency.avgtime=0.0073036,subop_w_latency.sum=1851.857230388,tier_clean=0,tier_delay=0,tier_dirty=0,tier_evict=0,tier_flush=0,tier_flush_fail=0,tier_promote=0,tier_proxy_read=0,tier_proxy_write=0,tier_try_flush=0,tier_try_flush_fail=0,tier_whiteout=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-ms_objecter,host=stefanosd1,id=0,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanosd1,id=0,type=osd msgr_active_connections=2055,msgr_created_connections=27411,msgr_recv_bytes=6431950009,msgr_recv_messages=3552443,msgr_running_fast_dispatch_time=162.271664213,msgr_running_recv_time=254.307853033,msgr_running_send_time=503.037285799,msgr_running_total_time=1130.21070681,msgr_send_bytes=10865436237,msgr_send_messages=3523374 1587117698000000000\nceph,collection=bluestore,host=stefanosd1,id=0,type=osd bluestore_allocated=24641536,bluestore_blob_split=0,bluestore_blobs=88,bluestore_buffer_bytes=622592,bluestore_buffer_hit_bytes=160578,bluestore_buffer_miss_bytes=540236,bluestore_buffers=43,bluestore_compressed=0,bluestore_compressed_allocated=0,bluestore_compressed_original=0,bluestore_extent_compress=0,bluestore_extents=88,bluestore_fragmentation_micros=1,bluestore_gc_merged=0,bluestore_onode_hits=532102,bluestore_onode_misses=388,bluestore_onode_reshard=0,bluestore_onode_shard_hits=0,bluestore_onode_shard_misses=0,bluestore_onodes=380,bluestore_read_eio=0,bluestore_reads_with_retries=0,bluestore_stored=1987856,bluestore_txc=275707,bluestore_write_big=0,bluestore_write_big_blobs=0,bluestore_write_big_bytes=0,bluestore_write_small=60,bluestore_write_small_bytes=343843,bluestore_write_small_deferred=22,bluestore_write_small_new=38,bluestore_write_small_pre_read=22,bluestore_write_small_unused=0,commit_lat.avgcount=275707,commit_lat.avgtime=0.00699778,commit_lat.sum=1929.337103334,compress_lat.avgcount=0,compress_lat.avgtime=0,compress_lat.sum=0,compress_rejected_count=0,compress_success_count=0,csum_lat.avgcount=67,csum_lat.avgtime=0.000032601,csum_lat.sum=0.002184323,decompress_lat.avgcount=0,decompress_lat.avgtime=0,decompress_lat.sum=0,deferred_write_bytes=0,deferred_write_ops=0,kv_commit_lat.avgcount=268870,kv_commit_lat.avgtime=0.006365428,kv_commit_lat.sum=1711.472749866,kv_final_lat.avgcount=268867,kv_final_lat.avgtime=0.000043227,kv_final_lat.sum=11.622427109,kv_flush_lat.avgcount=268870,kv_flush_lat.avgtime=0.000000223,kv_flush_lat.sum=0.060141588,kv_sync_lat.avgcount=268870,kv_sync_lat.avgtime=0.006365652,kv_sync_lat.sum=1711.532891454,omap_lower_bound_lat.avgcount=2,omap_lower_bound_lat.avgtime=0.000006524,omap_lower_bound_lat.sum=0.000013048,omap_next_lat.avgcount=6704,omap_next_lat.avgtime=0.000004721,omap_next_lat.sum=0.031654097,omap_seek_to_first_lat.avgcount=323,omap_seek_to_first_lat.avgtime=0.00000522,omap_seek_to_first_lat.sum=0.00168614,omap_upper_bound_lat.avgcount=4,omap_upper_bound_lat.avgtime=0.000013086,omap_upper_bound_lat.sum=0.000052344,read_lat.avgcount=227,read_lat.avgtime=0.000699457,read_lat.sum=0.158776879,read_onode_meta_lat.avgcount=311,read_onode_meta_lat.avgtime=0.000072207,read_onode_meta_lat.sum=0.022456667,read_wait_aio_lat.avgcount=84,read_wait_aio_lat.avgtime=0.001556141,read_wait_aio_lat.sum=0.130715885,state_aio_wait_lat.avgcount=275707,state_aio_wait_lat.avgtime=0.000000345,state_aio_wait_lat.sum=0.095246457,state_deferred_aio_wait_lat.avgcount=0,state_deferred_aio_wait_lat.avgtime=0,state_deferred_aio_wait_lat.sum=0,state_deferred_cleanup_lat.avgcount=0,state_deferred_cleanup_lat.avgtime=0,state_deferred_cleanup_lat.sum=0,state_deferred_queued_lat.avgcount=0,state_deferred_queued_lat.avgtime=0,state_deferred_queued_lat.sum=0,state_done_lat.avgcount=275696,state_done_lat.avgtime=0.00000286,state_done_lat.sum=0.788700007,state_finishing_lat.avgcount=275696,state_finishing_lat.avgtime=0.000000302,state_finishing_lat.sum=0.083437168,state_io_done_lat.avgcount=275707,state_io_done_lat.avgtime=0.000001041,state_io_done_lat.sum=0.287025147,state_kv_commiting_lat.avgcount=275707,state_kv_commiting_lat.avgtime=0.006424459,state_kv_commiting_lat.sum=1771.268407864,state_kv_done_lat.avgcount=275707,state_kv_done_lat.avgtime=0.000001627,state_kv_done_lat.sum=0.448805853,state_kv_queued_lat.avgcount=275707,state_kv_queued_lat.avgtime=0.000488565,state_kv_queued_lat.sum=134.7009424,state_prepare_lat.avgcount=275707,state_prepare_lat.avgtime=0.000082464,state_prepare_lat.sum=22.736065534,submit_lat.avgcount=275707,submit_lat.avgtime=0.000120236,submit_lat.sum=33.149934412,throttle_lat.avgcount=275707,throttle_lat.avgtime=0.000001571,throttle_lat.sum=0.433185935,write_pad_bytes=151773,write_penalty_read_ops=0 1587117698000000000\nceph,collection=finisher-objecter-finisher-0,host=stefanosd1,id=0,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=objecter,host=stefanosd1,id=0,type=osd command_active=0,command_resend=0,command_send=0,linger_active=0,linger_ping=0,linger_resend=0,linger_send=0,map_epoch=203,map_full=0,map_inc=19,omap_del=0,omap_rd=0,omap_wr=0,op=0,op_active=0,op_laggy=0,op_pg=0,op_r=0,op_reply=0,op_resend=0,op_rmw=0,op_send=0,op_send_bytes=0,op_w=0,osd_laggy=0,osd_session_close=0,osd_session_open=0,osd_sessions=0,osdop_append=0,osdop_call=0,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=0,osdop_delete=0,osdop_getxattr=0,osdop_mapext=0,osdop_notify=0,osdop_other=0,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=0,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=0,osdop_truncate=0,osdop_watch=0,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=0,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117698000000000\nceph,collection=finisher-commit_finisher,host=stefanosd1,id=0,type=osd complete_latency.avgcount=11,complete_latency.avgtime=0.003447516,complete_latency.sum=0.037922681,queue_len=0 1587117698000000000\nceph,collection=throttle-objecter_ops,host=stefanosd1,id=0,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=1024,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanosd1,id=0,type=osd msgr_active_connections=2128,msgr_created_connections=33685,msgr_recv_bytes=8679123051,msgr_recv_messages=4200356,msgr_running_fast_dispatch_time=151.889337454,msgr_running_recv_time=297.632294886,msgr_running_send_time=599.20020523,msgr_running_total_time=1321.361931202,msgr_send_bytes=11716202897,msgr_send_messages=4347418 1587117698000000000\nceph,collection=throttle-osd_client_bytes,host=stefanosd1,id=0,type=osd get=476554,get_or_fail_fail=0,get_or_fail_success=476554,get_started=0,get_sum=103413728,max=524288000,put=476587,put_sum=103413728,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-bluestore_throttle_deferred_bytes,host=stefanosd1,id=0,type=osd get=11,get_or_fail_fail=0,get_or_fail_success=11,get_started=0,get_sum=7723117,max=201326592,put=0,put_sum=0,take=0,take_sum=0,val=7723117,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-cluster,host=stefanosd1,id=1,type=osd get=860895,get_or_fail_fail=0,get_or_fail_success=860895,get_started=0,get_sum=596482256,max=104857600,put=860895,put_sum=596482256,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-objecter_ops,host=stefanosd1,id=1,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=1024,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-objecter_bytes,host=stefanosd1,id=1,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=finisher-defered_finisher,host=stefanosd1,id=1,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=osd,host=stefanosd1,id=1,type=osd agent_evict=0,agent_flush=0,agent_skip=0,agent_wake=0,cached_crc=0,cached_crc_adjusted=0,copyfrom=0,heartbeat_to_peers=7,loadavg=11,map_message_epoch_dups=29,map_message_epochs=50,map_messages=39,messages_delayed_for_map=0,missed_crc=0,numpg=188,numpg_primary=71,numpg_removing=0,numpg_replica=117,numpg_stray=0,object_ctx_cache_hit=1349777,object_ctx_cache_total=2934118,op=1319230,op_before_dequeue_op_lat.avgcount=3792053,op_before_dequeue_op_lat.avgtime=0.000405802,op_before_dequeue_op_lat.sum=1538.826381623,op_before_queue_op_lat.avgcount=3778690,op_before_queue_op_lat.avgtime=0.000033273,op_before_queue_op_lat.sum=125.731131596,op_cache_hit=0,op_in_bytes=0,op_latency.avgcount=1319230,op_latency.avgtime=0.002858138,op_latency.sum=3770.541581676,op_out_bytes=1789210,op_prepare_latency.avgcount=1336472,op_prepare_latency.avgtime=0.000279458,op_prepare_latency.sum=373.488913339,op_process_latency.avgcount=1319230,op_process_latency.avgtime=0.002666408,op_process_latency.sum=3517.606407526,op_r=1075394,op_r_latency.avgcount=1075394,op_r_latency.avgtime=0.000303779,op_r_latency.sum=326.682443032,op_r_out_bytes=1789210,op_r_prepare_latency.avgcount=1075394,op_r_prepare_latency.avgtime=0.000171228,op_r_prepare_latency.sum=184.138580631,op_r_process_latency.avgcount=1075394,op_r_process_latency.avgtime=0.00011609,op_r_process_latency.sum=124.842894319,op_rw=243832,op_rw_in_bytes=0,op_rw_latency.avgcount=243832,op_rw_latency.avgtime=0.014123636,op_rw_latency.sum=3443.79445124,op_rw_out_bytes=0,op_rw_prepare_latency.avgcount=261072,op_rw_prepare_latency.avgtime=0.000725265,op_rw_prepare_latency.sum=189.346543463,op_rw_process_latency.avgcount=243832,op_rw_process_latency.avgtime=0.013914089,op_rw_process_latency.sum=3392.700241086,op_w=4,op_w_in_bytes=0,op_w_latency.avgcount=4,op_w_latency.avgtime=0.016171851,op_w_latency.sum=0.064687404,op_w_prepare_latency.avgcount=6,op_w_prepare_latency.avgtime=0.00063154,op_w_prepare_latency.sum=0.003789245,op_w_process_latency.avgcount=4,op_w_process_latency.avgtime=0.01581803,op_w_process_latency.sum=0.063272121,op_wip=0,osd_map_bl_cache_hit=36,osd_map_bl_cache_miss=40,osd_map_cache_hit=5404,osd_map_cache_miss=14,osd_map_cache_miss_low=0,osd_map_cache_miss_low_avg.avgcount=0,osd_map_cache_miss_low_avg.sum=0,osd_pg_biginfo=2333,osd_pg_fastinfo=576157,osd_pg_info=591751,osd_tier_flush_lat.avgcount=0,osd_tier_flush_lat.avgtime=0,osd_tier_flush_lat.sum=0,osd_tier_promote_lat.avgcount=0,osd_tier_promote_lat.avgtime=0,osd_tier_promote_lat.sum=0,osd_tier_r_lat.avgcount=0,osd_tier_r_lat.avgtime=0,osd_tier_r_lat.sum=0,pull=0,push=22,push_out_bytes=0,recovery_bytes=0,recovery_ops=21,stat_bytes=107369988096,stat_bytes_avail=106271997952,stat_bytes_used=1097990144,subop=306946,subop_in_bytes=204236742,subop_latency.avgcount=306946,subop_latency.avgtime=0.006744881,subop_latency.sum=2070.314452989,subop_pull=0,subop_pull_latency.avgcount=0,subop_pull_latency.avgtime=0,subop_pull_latency.sum=0,subop_push=0,subop_push_in_bytes=0,subop_push_latency.avgcount=0,subop_push_latency.avgtime=0,subop_push_latency.sum=0,subop_w=306946,subop_w_in_bytes=204236742,subop_w_latency.avgcount=306946,subop_w_latency.avgtime=0.006744881,subop_w_latency.sum=2070.314452989,tier_clean=0,tier_delay=0,tier_dirty=8,tier_evict=0,tier_flush=0,tier_flush_fail=0,tier_promote=0,tier_proxy_read=0,tier_proxy_write=0,tier_try_flush=0,tier_try_flush_fail=0,tier_whiteout=0 1587117698000000000\nceph,collection=objecter,host=stefanosd1,id=1,type=osd command_active=0,command_resend=0,command_send=0,linger_active=0,linger_ping=0,linger_resend=0,linger_send=0,map_epoch=203,map_full=0,map_inc=19,omap_del=0,omap_rd=0,omap_wr=0,op=0,op_active=0,op_laggy=0,op_pg=0,op_r=0,op_reply=0,op_resend=0,op_rmw=0,op_send=0,op_send_bytes=0,op_w=0,osd_laggy=0,osd_session_close=0,osd_session_open=0,osd_sessions=0,osdop_append=0,osdop_call=0,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=0,osdop_delete=0,osdop_getxattr=0,osdop_mapext=0,osdop_notify=0,osdop_other=0,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=0,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=0,osdop_truncate=0,osdop_watch=0,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=0,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanosd1,id=1,type=osd msgr_active_connections=1356,msgr_created_connections=12290,msgr_recv_bytes=8577187219,msgr_recv_messages=6387040,msgr_running_fast_dispatch_time=475.903632306,msgr_running_recv_time=425.937196699,msgr_running_send_time=783.676217521,msgr_running_total_time=1989.242459076,msgr_send_bytes=12583034449,msgr_send_messages=6074344 1587117698000000000\nceph,collection=bluestore,host=stefanosd1,id=1,type=osd bluestore_allocated=24182784,bluestore_blob_split=0,bluestore_blobs=88,bluestore_buffer_bytes=614400,bluestore_buffer_hit_bytes=142047,bluestore_buffer_miss_bytes=541480,bluestore_buffers=41,bluestore_compressed=0,bluestore_compressed_allocated=0,bluestore_compressed_original=0,bluestore_extent_compress=0,bluestore_extents=88,bluestore_fragmentation_micros=1,bluestore_gc_merged=0,bluestore_onode_hits=1403948,bluestore_onode_misses=1584732,bluestore_onode_reshard=0,bluestore_onode_shard_hits=0,bluestore_onode_shard_misses=0,bluestore_onodes=459,bluestore_read_eio=0,bluestore_reads_with_retries=0,bluestore_stored=1985647,bluestore_txc=593150,bluestore_write_big=0,bluestore_write_big_blobs=0,bluestore_write_big_bytes=0,bluestore_write_small=58,bluestore_write_small_bytes=343091,bluestore_write_small_deferred=20,bluestore_write_small_new=38,bluestore_write_small_pre_read=20,bluestore_write_small_unused=0,commit_lat.avgcount=593150,commit_lat.avgtime=0.006514834,commit_lat.sum=3864.274280733,compress_lat.avgcount=0,compress_lat.avgtime=0,compress_lat.sum=0,compress_rejected_count=0,compress_success_count=0,csum_lat.avgcount=60,csum_lat.avgtime=0.000028258,csum_lat.sum=0.001695512,decompress_lat.avgcount=0,decompress_lat.avgtime=0,decompress_lat.sum=0,deferred_write_bytes=0,deferred_write_ops=0,kv_commit_lat.avgcount=578129,kv_commit_lat.avgtime=0.00570707,kv_commit_lat.sum=3299.423186928,kv_final_lat.avgcount=578124,kv_final_lat.avgtime=0.000042752,kv_final_lat.sum=24.716171934,kv_flush_lat.avgcount=578129,kv_flush_lat.avgtime=0.000000209,kv_flush_lat.sum=0.121169044,kv_sync_lat.avgcount=578129,kv_sync_lat.avgtime=0.00570728,kv_sync_lat.sum=3299.544355972,omap_lower_bound_lat.avgcount=22,omap_lower_bound_lat.avgtime=0.000005979,omap_lower_bound_lat.sum=0.000131539,omap_next_lat.avgcount=13248,omap_next_lat.avgtime=0.000004836,omap_next_lat.sum=0.064077797,omap_seek_to_first_lat.avgcount=525,omap_seek_to_first_lat.avgtime=0.000004906,omap_seek_to_first_lat.sum=0.002575786,omap_upper_bound_lat.avgcount=0,omap_upper_bound_lat.avgtime=0,omap_upper_bound_lat.sum=0,read_lat.avgcount=406,read_lat.avgtime=0.000383254,read_lat.sum=0.155601529,read_onode_meta_lat.avgcount=483,read_onode_meta_lat.avgtime=0.000008805,read_onode_meta_lat.sum=0.004252832,read_wait_aio_lat.avgcount=77,read_wait_aio_lat.avgtime=0.001907361,read_wait_aio_lat.sum=0.146866799,state_aio_wait_lat.avgcount=593150,state_aio_wait_lat.avgtime=0.000000388,state_aio_wait_lat.sum=0.230498048,state_deferred_aio_wait_lat.avgcount=0,state_deferred_aio_wait_lat.avgtime=0,state_deferred_aio_wait_lat.sum=0,state_deferred_cleanup_lat.avgcount=0,state_deferred_cleanup_lat.avgtime=0,state_deferred_cleanup_lat.sum=0,state_deferred_queued_lat.avgcount=0,state_deferred_queued_lat.avgtime=0,state_deferred_queued_lat.sum=0,state_done_lat.avgcount=593140,state_done_lat.avgtime=0.000003048,state_done_lat.sum=1.80789161,state_finishing_lat.avgcount=593140,state_finishing_lat.avgtime=0.000000325,state_finishing_lat.sum=0.192952339,state_io_done_lat.avgcount=593150,state_io_done_lat.avgtime=0.000001202,state_io_done_lat.sum=0.713333116,state_kv_commiting_lat.avgcount=593150,state_kv_commiting_lat.avgtime=0.005788541,state_kv_commiting_lat.sum=3433.473378536,state_kv_done_lat.avgcount=593150,state_kv_done_lat.avgtime=0.000001472,state_kv_done_lat.sum=0.873559611,state_kv_queued_lat.avgcount=593150,state_kv_queued_lat.avgtime=0.000634215,state_kv_queued_lat.sum=376.18491577,state_prepare_lat.avgcount=593150,state_prepare_lat.avgtime=0.000089694,state_prepare_lat.sum=53.202464675,submit_lat.avgcount=593150,submit_lat.avgtime=0.000127856,submit_lat.sum=75.83816759,throttle_lat.avgcount=593150,throttle_lat.avgtime=0.000001726,throttle_lat.sum=1.023832181,write_pad_bytes=144333,write_penalty_read_ops=0 1587117698000000000\nceph,collection=throttle-osd_client_bytes,host=stefanosd1,id=1,type=osd get=2920772,get_or_fail_fail=0,get_or_fail_success=2920772,get_started=0,get_sum=739935873,max=524288000,put=4888498,put_sum=739935873,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_client,host=stefanosd1,id=1,type=osd get=2605442,get_or_fail_fail=0,get_or_fail_success=2605442,get_started=0,get_sum=5221305768,max=104857600,put=2605442,put_sum=5221305768,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanosd1,id=1,type=osd msgr_active_connections=1375,msgr_created_connections=12689,msgr_recv_bytes=6393440855,msgr_recv_messages=3260458,msgr_running_fast_dispatch_time=120.622437418,msgr_running_recv_time=225.24709441,msgr_running_send_time=499.150587343,msgr_running_total_time=1043.340296846,msgr_send_bytes=11134862571,msgr_send_messages=3450760 1587117698000000000\nceph,collection=bluefs,host=stefanosd1,id=1,type=osd bytes_written_slow=0,bytes_written_sst=19824993,bytes_written_wal=1788507023,db_total_bytes=4294967296,db_used_bytes=522190848,files_written_sst=4,files_written_wal=2,gift_bytes=0,log_bytes=1056768,log_compactions=2,logged_bytes=1933271040,max_bytes_db=1483735040,max_bytes_slow=0,max_bytes_wal=0,num_files=12,reclaim_bytes=0,slow_total_bytes=0,slow_used_bytes=0,wal_total_bytes=0,wal_used_bytes=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_client,host=stefanosd1,id=1,type=osd get=2605442,get_or_fail_fail=0,get_or_fail_success=2605442,get_started=0,get_sum=5221305768,max=104857600,put=2605442,put_sum=5221305768,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-bluestore_throttle_deferred_bytes,host=stefanosd1,id=1,type=osd get=10,get_or_fail_fail=0,get_or_fail_success=10,get_started=0,get_sum=7052009,max=201326592,put=0,put_sum=0,take=0,take_sum=0,val=7052009,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=rocksdb,host=stefanosd1,id=1,type=osd compact=0,compact_queue_len=0,compact_queue_merge=0,compact_range=0,get=1586061,get_latency.avgcount=1586061,get_latency.avgtime=0.000083009,get_latency.sum=131.658296684,rocksdb_write_delay_time.avgcount=0,rocksdb_write_delay_time.avgtime=0,rocksdb_write_delay_time.sum=0,rocksdb_write_memtable_time.avgcount=0,rocksdb_write_memtable_time.avgtime=0,rocksdb_write_memtable_time.sum=0,rocksdb_write_pre_and_post_time.avgcount=0,rocksdb_write_pre_and_post_time.avgtime=0,rocksdb_write_pre_and_post_time.sum=0,rocksdb_write_wal_time.avgcount=0,rocksdb_write_wal_time.avgtime=0,rocksdb_write_wal_time.sum=0,submit_latency.avgcount=593150,submit_latency.avgtime=0.000172072,submit_latency.sum=102.064900673,submit_sync_latency.avgcount=578129,submit_sync_latency.avgtime=0.005447017,submit_sync_latency.sum=3149.078822012,submit_transaction=593150,submit_transaction_sync=578129 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_server,host=stefanosd1,id=1,type=osd get=2607669,get_or_fail_fail=0,get_or_fail_success=2607669,get_started=0,get_sum=5225768676,max=104857600,put=2607669,put_sum=5225768676,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=recoverystate_perf,host=stefanosd1,id=1,type=osd activating_latency.avgcount=104,activating_latency.avgtime=0.071646485,activating_latency.sum=7.451234493,active_latency.avgcount=33,active_latency.avgtime=1734.369034268,active_latency.sum=57234.178130859,backfilling_latency.avgcount=1,backfilling_latency.avgtime=2.598401698,backfilling_latency.sum=2.598401698,clean_latency.avgcount=33,clean_latency.avgtime=1734.213467342,clean_latency.sum=57229.044422292,down_latency.avgcount=0,down_latency.avgtime=0,down_latency.sum=0,getinfo_latency.avgcount=167,getinfo_latency.avgtime=0.373444627,getinfo_latency.sum=62.365252849,getlog_latency.avgcount=105,getlog_latency.avgtime=0.003575062,getlog_latency.sum=0.375381569,getmissing_latency.avgcount=104,getmissing_latency.avgtime=0.000157091,getmissing_latency.sum=0.016337565,incomplete_latency.avgcount=0,incomplete_latency.avgtime=0,incomplete_latency.sum=0,initial_latency.avgcount=188,initial_latency.avgtime=0.001833512,initial_latency.sum=0.344700343,notbackfilling_latency.avgcount=0,notbackfilling_latency.avgtime=0,notbackfilling_latency.sum=0,notrecovering_latency.avgcount=0,notrecovering_latency.avgtime=0,notrecovering_latency.sum=0,peering_latency.avgcount=167,peering_latency.avgtime=1.501818082,peering_latency.sum=250.803619796,primary_latency.avgcount=97,primary_latency.avgtime=591.344286378,primary_latency.sum=57360.395778762,recovered_latency.avgcount=104,recovered_latency.avgtime=0.000291138,recovered_latency.sum=0.030278433,recovering_latency.avgcount=2,recovering_latency.avgtime=0.142378096,recovering_latency.sum=0.284756192,replicaactive_latency.avgcount=32,replicaactive_latency.avgtime=1788.474901442,replicaactive_latency.sum=57231.196846165,repnotrecovering_latency.avgcount=34,repnotrecovering_latency.avgtime=1683.273587087,repnotrecovering_latency.sum=57231.301960987,reprecovering_latency.avgcount=2,reprecovering_latency.avgtime=0.418094818,reprecovering_latency.sum=0.836189637,repwaitbackfillreserved_latency.avgcount=0,repwaitbackfillreserved_latency.avgtime=0,repwaitbackfillreserved_latency.sum=0,repwaitrecoveryreserved_latency.avgcount=2,repwaitrecoveryreserved_latency.avgtime=0.000588413,repwaitrecoveryreserved_latency.sum=0.001176827,reset_latency.avgcount=433,reset_latency.avgtime=0.15669689,reset_latency.sum=67.849753631,start_latency.avgcount=433,start_latency.avgtime=0.000412707,start_latency.sum=0.178702508,started_latency.avgcount=245,started_latency.avgtime=468.419544137,started_latency.sum=114762.788313581,stray_latency.avgcount=266,stray_latency.avgtime=1.489291271,stray_latency.sum=396.151478238,waitactingchange_latency.avgcount=1,waitactingchange_latency.avgtime=0.982689906,waitactingchange_latency.sum=0.982689906,waitlocalbackfillreserved_latency.avgcount=1,waitlocalbackfillreserved_latency.avgtime=0.000542092,waitlocalbackfillreserved_latency.sum=0.000542092,waitlocalrecoveryreserved_latency.avgcount=2,waitlocalrecoveryreserved_latency.avgtime=0.00391669,waitlocalrecoveryreserved_latency.sum=0.007833381,waitremotebackfillreserved_latency.avgcount=1,waitremotebackfillreserved_latency.avgtime=0.003110409,waitremotebackfillreserved_latency.sum=0.003110409,waitremoterecoveryreserved_latency.avgcount=2,waitremoterecoveryreserved_latency.avgtime=0.012229338,waitremoterecoveryreserved_latency.sum=0.024458677,waitupthru_latency.avgcount=104,waitupthru_latency.avgtime=1.807608905,waitupthru_latency.sum=187.991326197 1587117698000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanosd1,id=1,type=osd msgr_active_connections=1289,msgr_created_connections=9469,msgr_recv_bytes=8348149800,msgr_recv_messages=5048791,msgr_running_fast_dispatch_time=313.754567889,msgr_running_recv_time=372.054833029,msgr_running_send_time=694.900405016,msgr_running_total_time=1656.294769387,msgr_send_bytes=11550148208,msgr_send_messages=5175962 1587117698000000000\nceph,collection=throttle-bluestore_throttle_bytes,host=stefanosd1,id=1,type=osd get=593150,get_or_fail_fail=0,get_or_fail_success=0,get_started=593150,get_sum=398147414260,max=67108864,put=578129,put_sum=398147414260,take=0,take_sum=0,val=0,wait.avgcount=29,wait.avgtime=0.000972655,wait.sum=0.028207005 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-ms_objecter,host=stefanosd1,id=1,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=cct,host=stefanosd1,id=1,type=osd total_workers=6,unhealthy_workers=0 1587117698000000000\nceph,collection=mempool,host=stefanosd1,id=1,type=osd bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=13064,bluefs_items=593,bluestore_alloc_bytes=230288,bluestore_alloc_items=28786,bluestore_cache_data_bytes=614400,bluestore_cache_data_items=41,bluestore_cache_onode_bytes=301104,bluestore_cache_onode_items=459,bluestore_cache_other_bytes=230945,bluestore_cache_other_items=26119,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=7520,bluestore_txc_items=10,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=657768,bluestore_writing_deferred_items=172,bluestore_writing_items=0,buffer_anon_bytes=2328515,buffer_anon_items=271,buffer_meta_bytes=5808,buffer_meta_items=66,mds_co_bytes=0,mds_co_items=0,osd_bytes=2406400,osd_items=188,osd_mapbl_bytes=139623,osd_mapbl_items=9,osd_pglog_bytes=6768784,osd_pglog_items=18179,osdmap_bytes=710892,osdmap_items=4426,osdmap_mapping_bytes=0,osdmap_mapping_items=0,pgmap_bytes=0,pgmap_items=0,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-client,host=stefanosd1,id=1,type=osd get=2932513,get_or_fail_fail=0,get_or_fail_success=2932513,get_started=0,get_sum=740620215,max=104857600,put=2932513,put_sum=740620215,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_server,host=stefanosd1,id=1,type=osd get=2607669,get_or_fail_fail=0,get_or_fail_success=2607669,get_started=0,get_sum=5225768676,max=104857600,put=2607669,put_sum=5225768676,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=finisher-commit_finisher,host=stefanosd1,id=1,type=osd complete_latency.avgcount=10,complete_latency.avgtime=0.002884646,complete_latency.sum=0.028846469,queue_len=0 1587117698000000000\nceph,collection=finisher-objecter-finisher-0,host=stefanosd1,id=1,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=throttle-objecter_bytes,host=stefanosd1,id=2,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=finisher-commit_finisher,host=stefanosd1,id=2,type=osd complete_latency.avgcount=11,complete_latency.avgtime=0.002714416,complete_latency.sum=0.029858583,queue_len=0 1587117698000000000\nceph,collection=finisher-defered_finisher,host=stefanosd1,id=2,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=objecter,host=stefanosd1,id=2,type=osd command_active=0,command_resend=0,command_send=0,linger_active=0,linger_ping=0,linger_resend=0,linger_send=0,map_epoch=203,map_full=0,map_inc=19,omap_del=0,omap_rd=0,omap_wr=0,op=0,op_active=0,op_laggy=0,op_pg=0,op_r=0,op_reply=0,op_resend=0,op_rmw=0,op_send=0,op_send_bytes=0,op_w=0,osd_laggy=0,osd_session_close=0,osd_session_open=0,osd_sessions=0,osdop_append=0,osdop_call=0,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=0,osdop_delete=0,osdop_getxattr=0,osdop_mapext=0,osdop_notify=0,osdop_other=0,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=0,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=0,osdop_truncate=0,osdop_watch=0,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=0,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_client,host=stefanosd1,id=2,type=osd get=2607136,get_or_fail_fail=0,get_or_fail_success=2607136,get_started=0,get_sum=5224700544,max=104857600,put=2607136,put_sum=5224700544,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=mempool,host=stefanosd1,id=2,type=osd bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=11624,bluefs_items=522,bluestore_alloc_bytes=230288,bluestore_alloc_items=28786,bluestore_cache_data_bytes=614400,bluestore_cache_data_items=41,bluestore_cache_onode_bytes=228288,bluestore_cache_onode_items=348,bluestore_cache_other_bytes=174158,bluestore_cache_other_items=18527,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=8272,bluestore_txc_items=11,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=670130,bluestore_writing_deferred_items=176,bluestore_writing_items=0,buffer_anon_bytes=2311664,buffer_anon_items=244,buffer_meta_bytes=5456,buffer_meta_items=62,mds_co_bytes=0,mds_co_items=0,osd_bytes=1920000,osd_items=150,osd_mapbl_bytes=155152,osd_mapbl_items=10,osd_pglog_bytes=3393520,osd_pglog_items=9128,osdmap_bytes=710892,osdmap_items=4426,osdmap_mapping_bytes=0,osdmap_mapping_items=0,pgmap_bytes=0,pgmap_items=0,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117698000000000\nceph,collection=osd,host=stefanosd1,id=2,type=osd agent_evict=0,agent_flush=0,agent_skip=0,agent_wake=0,cached_crc=0,cached_crc_adjusted=0,copyfrom=0,heartbeat_to_peers=7,loadavg=11,map_message_epoch_dups=37,map_message_epochs=56,map_messages=37,messages_delayed_for_map=0,missed_crc=0,numpg=150,numpg_primary=59,numpg_removing=0,numpg_replica=91,numpg_stray=0,object_ctx_cache_hit=705923,object_ctx_cache_total=705951,op=690584,op_before_dequeue_op_lat.avgcount=1155697,op_before_dequeue_op_lat.avgtime=0.000217926,op_before_dequeue_op_lat.sum=251.856487141,op_before_queue_op_lat.avgcount=1148445,op_before_queue_op_lat.avgtime=0.000039696,op_before_queue_op_lat.sum=45.589516462,op_cache_hit=0,op_in_bytes=0,op_latency.avgcount=690584,op_latency.avgtime=0.002488685,op_latency.sum=1718.646504654,op_out_bytes=1026000,op_prepare_latency.avgcount=698700,op_prepare_latency.avgtime=0.000300375,op_prepare_latency.sum=209.872029659,op_process_latency.avgcount=690584,op_process_latency.avgtime=0.00230742,op_process_latency.sum=1593.46739165,op_r=548020,op_r_latency.avgcount=548020,op_r_latency.avgtime=0.000298287,op_r_latency.sum=163.467760649,op_r_out_bytes=1026000,op_r_prepare_latency.avgcount=548020,op_r_prepare_latency.avgtime=0.000186359,op_r_prepare_latency.sum=102.128629183,op_r_process_latency.avgcount=548020,op_r_process_latency.avgtime=0.00012716,op_r_process_latency.sum=69.686468884,op_rw=142562,op_rw_in_bytes=0,op_rw_latency.avgcount=142562,op_rw_latency.avgtime=0.010908597,op_rw_latency.sum=1555.151525732,op_rw_out_bytes=0,op_rw_prepare_latency.avgcount=150678,op_rw_prepare_latency.avgtime=0.000715043,op_rw_prepare_latency.sum=107.741399304,op_rw_process_latency.avgcount=142562,op_rw_process_latency.avgtime=0.01068836,op_rw_process_latency.sum=1523.754107887,op_w=2,op_w_in_bytes=0,op_w_latency.avgcount=2,op_w_latency.avgtime=0.013609136,op_w_latency.sum=0.027218273,op_w_prepare_latency.avgcount=2,op_w_prepare_latency.avgtime=0.001000586,op_w_prepare_latency.sum=0.002001172,op_w_process_latency.avgcount=2,op_w_process_latency.avgtime=0.013407439,op_w_process_latency.sum=0.026814879,op_wip=0,osd_map_bl_cache_hit=15,osd_map_bl_cache_miss=41,osd_map_cache_hit=4241,osd_map_cache_miss=14,osd_map_cache_miss_low=0,osd_map_cache_miss_low_avg.avgcount=0,osd_map_cache_miss_low_avg.sum=0,osd_pg_biginfo=1824,osd_pg_fastinfo=285998,osd_pg_info=294869,osd_tier_flush_lat.avgcount=0,osd_tier_flush_lat.avgtime=0,osd_tier_flush_lat.sum=0,osd_tier_promote_lat.avgcount=0,osd_tier_promote_lat.avgtime=0,osd_tier_promote_lat.sum=0,osd_tier_r_lat.avgcount=0,osd_tier_r_lat.avgtime=0,osd_tier_r_lat.sum=0,pull=0,push=1,push_out_bytes=0,recovery_bytes=0,recovery_ops=0,stat_bytes=107369988096,stat_bytes_avail=106271932416,stat_bytes_used=1098055680,subop=134165,subop_in_bytes=89501237,subop_latency.avgcount=134165,subop_latency.avgtime=0.007313523,subop_latency.sum=981.218888627,subop_pull=0,subop_pull_latency.avgcount=0,subop_pull_latency.avgtime=0,subop_pull_latency.sum=0,subop_push=0,subop_push_in_bytes=0,subop_push_latency.avgcount=0,subop_push_latency.avgtime=0,subop_push_latency.sum=0,subop_w=134165,subop_w_in_bytes=89501237,subop_w_latency.avgcount=134165,subop_w_latency.avgtime=0.007313523,subop_w_latency.sum=981.218888627,tier_clean=0,tier_delay=0,tier_dirty=4,tier_evict=0,tier_flush=0,tier_flush_fail=0,tier_promote=0,tier_proxy_read=0,tier_proxy_write=0,tier_try_flush=0,tier_try_flush_fail=0,tier_whiteout=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanosd1,id=2,type=osd msgr_active_connections=746,msgr_created_connections=15212,msgr_recv_bytes=8633229006,msgr_recv_messages=4284202,msgr_running_fast_dispatch_time=153.820479102,msgr_running_recv_time=282.031655658,msgr_running_send_time=585.444749736,msgr_running_total_time=1231.431789242,msgr_send_bytes=11962769351,msgr_send_messages=4440622 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-ms_objecter,host=stefanosd1,id=2,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_client,host=stefanosd1,id=2,type=osd get=2607136,get_or_fail_fail=0,get_or_fail_success=2607136,get_started=0,get_sum=5224700544,max=104857600,put=2607136,put_sum=5224700544,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=bluefs,host=stefanosd1,id=2,type=osd bytes_written_slow=0,bytes_written_sst=9065815,bytes_written_wal=901884611,db_total_bytes=4294967296,db_used_bytes=546308096,files_written_sst=3,files_written_wal=2,gift_bytes=0,log_bytes=225726464,log_compactions=1,logged_bytes=1195945984,max_bytes_db=1234173952,max_bytes_slow=0,max_bytes_wal=0,num_files=11,reclaim_bytes=0,slow_total_bytes=0,slow_used_bytes=0,wal_total_bytes=0,wal_used_bytes=0 1587117698000000000\nceph,collection=recoverystate_perf,host=stefanosd1,id=2,type=osd activating_latency.avgcount=88,activating_latency.avgtime=0.086149065,activating_latency.sum=7.581117751,active_latency.avgcount=29,active_latency.avgtime=1790.849396082,active_latency.sum=51934.632486379,backfilling_latency.avgcount=0,backfilling_latency.avgtime=0,backfilling_latency.sum=0,clean_latency.avgcount=29,clean_latency.avgtime=1790.754765195,clean_latency.sum=51931.888190683,down_latency.avgcount=0,down_latency.avgtime=0,down_latency.sum=0,getinfo_latency.avgcount=134,getinfo_latency.avgtime=0.427567953,getinfo_latency.sum=57.294105786,getlog_latency.avgcount=88,getlog_latency.avgtime=0.011810192,getlog_latency.sum=1.03929697,getmissing_latency.avgcount=88,getmissing_latency.avgtime=0.000104598,getmissing_latency.sum=0.009204673,incomplete_latency.avgcount=0,incomplete_latency.avgtime=0,incomplete_latency.sum=0,initial_latency.avgcount=150,initial_latency.avgtime=0.001251361,initial_latency.sum=0.187704197,notbackfilling_latency.avgcount=0,notbackfilling_latency.avgtime=0,notbackfilling_latency.sum=0,notrecovering_latency.avgcount=0,notrecovering_latency.avgtime=0,notrecovering_latency.sum=0,peering_latency.avgcount=134,peering_latency.avgtime=0.998405763,peering_latency.sum=133.786372331,primary_latency.avgcount=75,primary_latency.avgtime=693.473306562,primary_latency.sum=52010.497992212,recovered_latency.avgcount=88,recovered_latency.avgtime=0.000609715,recovered_latency.sum=0.053654964,recovering_latency.avgcount=1,recovering_latency.avgtime=0.100713031,recovering_latency.sum=0.100713031,replicaactive_latency.avgcount=21,replicaactive_latency.avgtime=1790.852354921,replicaactive_latency.sum=37607.89945336,repnotrecovering_latency.avgcount=21,repnotrecovering_latency.avgtime=1790.852315529,repnotrecovering_latency.sum=37607.898626121,reprecovering_latency.avgcount=0,reprecovering_latency.avgtime=0,reprecovering_latency.sum=0,repwaitbackfillreserved_latency.avgcount=0,repwaitbackfillreserved_latency.avgtime=0,repwaitbackfillreserved_latency.sum=0,repwaitrecoveryreserved_latency.avgcount=0,repwaitrecoveryreserved_latency.avgtime=0,repwaitrecoveryreserved_latency.sum=0,reset_latency.avgcount=346,reset_latency.avgtime=0.126826803,reset_latency.sum=43.882073917,start_latency.avgcount=346,start_latency.avgtime=0.000233277,start_latency.sum=0.080713962,started_latency.avgcount=196,started_latency.avgtime=457.885378797,started_latency.sum=89745.534244237,stray_latency.avgcount=212,stray_latency.avgtime=1.013774396,stray_latency.sum=214.920172121,waitactingchange_latency.avgcount=0,waitactingchange_latency.avgtime=0,waitactingchange_latency.sum=0,waitlocalbackfillreserved_latency.avgcount=0,waitlocalbackfillreserved_latency.avgtime=0,waitlocalbackfillreserved_latency.sum=0,waitlocalrecoveryreserved_latency.avgcount=1,waitlocalrecoveryreserved_latency.avgtime=0.001572379,waitlocalrecoveryreserved_latency.sum=0.001572379,waitremotebackfillreserved_latency.avgcount=0,waitremotebackfillreserved_latency.avgtime=0,waitremotebackfillreserved_latency.sum=0,waitremoterecoveryreserved_latency.avgcount=1,waitremoterecoveryreserved_latency.avgtime=0.012729633,waitremoterecoveryreserved_latency.sum=0.012729633,waitupthru_latency.avgcount=88,waitupthru_latency.avgtime=0.857137729,waitupthru_latency.sum=75.428120205 1587117698000000000\nceph,collection=throttle-objecter_ops,host=stefanosd1,id=2,type=osd get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=1024,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=bluestore,host=stefanosd1,id=2,type=osd bluestore_allocated=24248320,bluestore_blob_split=0,bluestore_blobs=83,bluestore_buffer_bytes=614400,bluestore_buffer_hit_bytes=161362,bluestore_buffer_miss_bytes=534799,bluestore_buffers=41,bluestore_compressed=0,bluestore_compressed_allocated=0,bluestore_compressed_original=0,bluestore_extent_compress=0,bluestore_extents=83,bluestore_fragmentation_micros=1,bluestore_gc_merged=0,bluestore_onode_hits=723852,bluestore_onode_misses=364,bluestore_onode_reshard=0,bluestore_onode_shard_hits=0,bluestore_onode_shard_misses=0,bluestore_onodes=348,bluestore_read_eio=0,bluestore_reads_with_retries=0,bluestore_stored=1984402,bluestore_txc=295997,bluestore_write_big=0,bluestore_write_big_blobs=0,bluestore_write_big_bytes=0,bluestore_write_small=60,bluestore_write_small_bytes=343843,bluestore_write_small_deferred=22,bluestore_write_small_new=38,bluestore_write_small_pre_read=22,bluestore_write_small_unused=0,commit_lat.avgcount=295997,commit_lat.avgtime=0.006994931,commit_lat.sum=2070.478673619,compress_lat.avgcount=0,compress_lat.avgtime=0,compress_lat.sum=0,compress_rejected_count=0,compress_success_count=0,csum_lat.avgcount=47,csum_lat.avgtime=0.000034434,csum_lat.sum=0.001618423,decompress_lat.avgcount=0,decompress_lat.avgtime=0,decompress_lat.sum=0,deferred_write_bytes=0,deferred_write_ops=0,kv_commit_lat.avgcount=291889,kv_commit_lat.avgtime=0.006347015,kv_commit_lat.sum=1852.624108527,kv_final_lat.avgcount=291885,kv_final_lat.avgtime=0.00004358,kv_final_lat.sum=12.720529751,kv_flush_lat.avgcount=291889,kv_flush_lat.avgtime=0.000000211,kv_flush_lat.sum=0.061636079,kv_sync_lat.avgcount=291889,kv_sync_lat.avgtime=0.006347227,kv_sync_lat.sum=1852.685744606,omap_lower_bound_lat.avgcount=1,omap_lower_bound_lat.avgtime=0.000004482,omap_lower_bound_lat.sum=0.000004482,omap_next_lat.avgcount=6933,omap_next_lat.avgtime=0.000003956,omap_next_lat.sum=0.027427456,omap_seek_to_first_lat.avgcount=309,omap_seek_to_first_lat.avgtime=0.000005879,omap_seek_to_first_lat.sum=0.001816658,omap_upper_bound_lat.avgcount=0,omap_upper_bound_lat.avgtime=0,omap_upper_bound_lat.sum=0,read_lat.avgcount=229,read_lat.avgtime=0.000394981,read_lat.sum=0.090450704,read_onode_meta_lat.avgcount=295,read_onode_meta_lat.avgtime=0.000016832,read_onode_meta_lat.sum=0.004965516,read_wait_aio_lat.avgcount=66,read_wait_aio_lat.avgtime=0.001237841,read_wait_aio_lat.sum=0.081697561,state_aio_wait_lat.avgcount=295997,state_aio_wait_lat.avgtime=0.000000357,state_aio_wait_lat.sum=0.105827433,state_deferred_aio_wait_lat.avgcount=0,state_deferred_aio_wait_lat.avgtime=0,state_deferred_aio_wait_lat.sum=0,state_deferred_cleanup_lat.avgcount=0,state_deferred_cleanup_lat.avgtime=0,state_deferred_cleanup_lat.sum=0,state_deferred_queued_lat.avgcount=0,state_deferred_queued_lat.avgtime=0,state_deferred_queued_lat.sum=0,state_done_lat.avgcount=295986,state_done_lat.avgtime=0.000003017,state_done_lat.sum=0.893199127,state_finishing_lat.avgcount=295986,state_finishing_lat.avgtime=0.000000306,state_finishing_lat.sum=0.090792683,state_io_done_lat.avgcount=295997,state_io_done_lat.avgtime=0.000001066,state_io_done_lat.sum=0.315577655,state_kv_commiting_lat.avgcount=295997,state_kv_commiting_lat.avgtime=0.006423586,state_kv_commiting_lat.sum=1901.362268572,state_kv_done_lat.avgcount=295997,state_kv_done_lat.avgtime=0.00000155,state_kv_done_lat.sum=0.458963064,state_kv_queued_lat.avgcount=295997,state_kv_queued_lat.avgtime=0.000477234,state_kv_queued_lat.sum=141.260101773,state_prepare_lat.avgcount=295997,state_prepare_lat.avgtime=0.000091806,state_prepare_lat.sum=27.174436583,submit_lat.avgcount=295997,submit_lat.avgtime=0.000135729,submit_lat.sum=40.17557682,throttle_lat.avgcount=295997,throttle_lat.avgtime=0.000002734,throttle_lat.sum=0.809479837,write_pad_bytes=151773,write_penalty_read_ops=0 1587117698000000000\nceph,collection=throttle-bluestore_throttle_bytes,host=stefanosd1,id=2,type=osd get=295997,get_or_fail_fail=0,get_or_fail_success=0,get_started=295997,get_sum=198686579299,max=67108864,put=291889,put_sum=198686579299,take=0,take_sum=0,val=0,wait.avgcount=83,wait.avgtime=0.003670612,wait.sum=0.304660858 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-cluster,host=stefanosd1,id=2,type=osd get=452060,get_or_fail_fail=0,get_or_fail_success=452060,get_started=0,get_sum=269934345,max=104857600,put=452060,put_sum=269934345,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-bluestore_throttle_deferred_bytes,host=stefanosd1,id=2,type=osd get=11,get_or_fail_fail=0,get_or_fail_success=11,get_started=0,get_sum=7723117,max=201326592,put=0,put_sum=0,take=0,take_sum=0,val=7723117,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_front_server,host=stefanosd1,id=2,type=osd get=2607433,get_or_fail_fail=0,get_or_fail_success=2607433,get_started=0,get_sum=5225295732,max=104857600,put=2607433,put_sum=5225295732,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=finisher-objecter-finisher-0,host=stefanosd1,id=2,type=osd complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117698000000000\nceph,collection=cct,host=stefanosd1,id=2,type=osd total_workers=6,unhealthy_workers=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanosd1,id=2,type=osd msgr_active_connections=670,msgr_created_connections=13455,msgr_recv_bytes=6334605563,msgr_recv_messages=3287843,msgr_running_fast_dispatch_time=137.016615819,msgr_running_recv_time=240.687997039,msgr_running_send_time=471.710658466,msgr_running_total_time=1034.029109337,msgr_send_bytes=9753423475,msgr_send_messages=3439611 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-client,host=stefanosd1,id=2,type=osd get=710355,get_or_fail_fail=0,get_or_fail_success=710355,get_started=0,get_sum=166306283,max=104857600,put=710355,put_sum=166306283,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=throttle-msgr_dispatch_throttler-hb_back_server,host=stefanosd1,id=2,type=osd get=2607433,get_or_fail_fail=0,get_or_fail_success=2607433,get_started=0,get_sum=5225295732,max=104857600,put=2607433,put_sum=5225295732,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanosd1,id=2,type=osd msgr_active_connections=705,msgr_created_connections=17953,msgr_recv_bytes=7261438733,msgr_recv_messages=4496034,msgr_running_fast_dispatch_time=254.716476808,msgr_running_recv_time=272.196741555,msgr_running_send_time=571.102924903,msgr_running_total_time=1338.461077493,msgr_send_bytes=10772250508,msgr_send_messages=4192781 1587117698000000000\nceph,collection=rocksdb,host=stefanosd1,id=2,type=osd compact=0,compact_queue_len=0,compact_queue_merge=0,compact_range=0,get=1424,get_latency.avgcount=1424,get_latency.avgtime=0.000030752,get_latency.sum=0.043792142,rocksdb_write_delay_time.avgcount=0,rocksdb_write_delay_time.avgtime=0,rocksdb_write_delay_time.sum=0,rocksdb_write_memtable_time.avgcount=0,rocksdb_write_memtable_time.avgtime=0,rocksdb_write_memtable_time.sum=0,rocksdb_write_pre_and_post_time.avgcount=0,rocksdb_write_pre_and_post_time.avgtime=0,rocksdb_write_pre_and_post_time.sum=0,rocksdb_write_wal_time.avgcount=0,rocksdb_write_wal_time.avgtime=0,rocksdb_write_wal_time.sum=0,submit_latency.avgcount=295997,submit_latency.avgtime=0.000173137,submit_latency.sum=51.248072285,submit_sync_latency.avgcount=291889,submit_sync_latency.avgtime=0.006094397,submit_sync_latency.sum=1778.887521449,submit_transaction=295997,submit_transaction_sync=291889 1587117698000000000\nceph,collection=throttle-osd_client_bytes,host=stefanosd1,id=2,type=osd get=698701,get_or_fail_fail=0,get_or_fail_success=698701,get_started=0,get_sum=165630172,max=524288000,put=920880,put_sum=165630172,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117698000000000\nceph,collection=mds_sessions,host=stefanmds1,id=stefanmds1,type=mds average_load=0,avg_session_uptime=0,session_add=0,session_count=0,session_remove=0,sessions_open=0,sessions_stale=0,total_load=0 1587117476000000000\nceph,collection=mempool,host=stefanmds1,id=stefanmds1,type=mds bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=0,bluefs_items=0,bluestore_alloc_bytes=0,bluestore_alloc_items=0,bluestore_cache_data_bytes=0,bluestore_cache_data_items=0,bluestore_cache_onode_bytes=0,bluestore_cache_onode_items=0,bluestore_cache_other_bytes=0,bluestore_cache_other_items=0,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=0,bluestore_txc_items=0,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=0,bluestore_writing_deferred_items=0,bluestore_writing_items=0,buffer_anon_bytes=132069,buffer_anon_items=82,buffer_meta_bytes=0,buffer_meta_items=0,mds_co_bytes=44208,mds_co_items=154,osd_bytes=0,osd_items=0,osd_mapbl_bytes=0,osd_mapbl_items=0,osd_pglog_bytes=0,osd_pglog_items=0,osdmap_bytes=16952,osdmap_items=139,osdmap_mapping_bytes=0,osdmap_mapping_items=0,pgmap_bytes=0,pgmap_items=0,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117476000000000\nceph,collection=objecter,host=stefanmds1,id=stefanmds1,type=mds command_active=0,command_resend=0,command_send=0,linger_active=0,linger_ping=0,linger_resend=0,linger_send=0,map_epoch=203,map_full=0,map_inc=1,omap_del=0,omap_rd=28,omap_wr=1,op=33,op_active=0,op_laggy=0,op_pg=0,op_r=26,op_reply=33,op_resend=2,op_rmw=0,op_send=35,op_send_bytes=364,op_w=7,osd_laggy=0,osd_session_close=91462,osd_session_open=91468,osd_sessions=6,osdop_append=0,osdop_call=0,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=0,osdop_delete=5,osdop_getxattr=14,osdop_mapext=0,osdop_notify=0,osdop_other=0,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=8,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=2,osdop_truncate=0,osdop_watch=0,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=1,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117476000000000\nceph,collection=cct,host=stefanmds1,id=stefanmds1,type=mds total_workers=1,unhealthy_workers=0 1587117476000000000\nceph,collection=mds_server,host=stefanmds1,id=stefanmds1,type=mds cap_revoke_eviction=0,dispatch_client_request=0,dispatch_server_request=0,handle_client_request=0,handle_client_session=0,handle_slave_request=0,req_create_latency.avgcount=0,req_create_latency.avgtime=0,req_create_latency.sum=0,req_getattr_latency.avgcount=0,req_getattr_latency.avgtime=0,req_getattr_latency.sum=0,req_getfilelock_latency.avgcount=0,req_getfilelock_latency.avgtime=0,req_getfilelock_latency.sum=0,req_link_latency.avgcount=0,req_link_latency.avgtime=0,req_link_latency.sum=0,req_lookup_latency.avgcount=0,req_lookup_latency.avgtime=0,req_lookup_latency.sum=0,req_lookuphash_latency.avgcount=0,req_lookuphash_latency.avgtime=0,req_lookuphash_latency.sum=0,req_lookupino_latency.avgcount=0,req_lookupino_latency.avgtime=0,req_lookupino_latency.sum=0,req_lookupname_latency.avgcount=0,req_lookupname_latency.avgtime=0,req_lookupname_latency.sum=0,req_lookupparent_latency.avgcount=0,req_lookupparent_latency.avgtime=0,req_lookupparent_latency.sum=0,req_lookupsnap_latency.avgcount=0,req_lookupsnap_latency.avgtime=0,req_lookupsnap_latency.sum=0,req_lssnap_latency.avgcount=0,req_lssnap_latency.avgtime=0,req_lssnap_latency.sum=0,req_mkdir_latency.avgcount=0,req_mkdir_latency.avgtime=0,req_mkdir_latency.sum=0,req_mknod_latency.avgcount=0,req_mknod_latency.avgtime=0,req_mknod_latency.sum=0,req_mksnap_latency.avgcount=0,req_mksnap_latency.avgtime=0,req_mksnap_latency.sum=0,req_open_latency.avgcount=0,req_open_latency.avgtime=0,req_open_latency.sum=0,req_readdir_latency.avgcount=0,req_readdir_latency.avgtime=0,req_readdir_latency.sum=0,req_rename_latency.avgcount=0,req_rename_latency.avgtime=0,req_rename_latency.sum=0,req_renamesnap_latency.avgcount=0,req_renamesnap_latency.avgtime=0,req_renamesnap_latency.sum=0,req_rmdir_latency.avgcount=0,req_rmdir_latency.avgtime=0,req_rmdir_latency.sum=0,req_rmsnap_latency.avgcount=0,req_rmsnap_latency.avgtime=0,req_rmsnap_latency.sum=0,req_rmxattr_latency.avgcount=0,req_rmxattr_latency.avgtime=0,req_rmxattr_latency.sum=0,req_setattr_latency.avgcount=0,req_setattr_latency.avgtime=0,req_setattr_latency.sum=0,req_setdirlayout_latency.avgcount=0,req_setdirlayout_latency.avgtime=0,req_setdirlayout_latency.sum=0,req_setfilelock_latency.avgcount=0,req_setfilelock_latency.avgtime=0,req_setfilelock_latency.sum=0,req_setlayout_latency.avgcount=0,req_setlayout_latency.avgtime=0,req_setlayout_latency.sum=0,req_setxattr_latency.avgcount=0,req_setxattr_latency.avgtime=0,req_setxattr_latency.sum=0,req_symlink_latency.avgcount=0,req_symlink_latency.avgtime=0,req_symlink_latency.sum=0,req_unlink_latency.avgcount=0,req_unlink_latency.avgtime=0,req_unlink_latency.sum=0 1587117476000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanmds1,id=stefanmds1,type=mds msgr_active_connections=84,msgr_created_connections=68511,msgr_recv_bytes=238078,msgr_recv_messages=2655,msgr_running_fast_dispatch_time=0.004247777,msgr_running_recv_time=25.369012545,msgr_running_send_time=3.743427461,msgr_running_total_time=130.277111559,msgr_send_bytes=172767043,msgr_send_messages=18172 1587117476000000000\nceph,collection=mds_log,host=stefanmds1,id=stefanmds1,type=mds ev=0,evadd=0,evex=0,evexd=0,evexg=0,evtrm=0,expos=4194304,jlat.avgcount=0,jlat.avgtime=0,jlat.sum=0,rdpos=4194304,replayed=1,seg=1,segadd=0,segex=0,segexd=0,segexg=0,segtrm=0,wrpos=0 1587117476000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanmds1,id=stefanmds1,type=mds msgr_active_connections=595,msgr_created_connections=943825,msgr_recv_bytes=78618003,msgr_recv_messages=914080,msgr_running_fast_dispatch_time=0.001544386,msgr_running_recv_time=459.627068807,msgr_running_send_time=469.337032316,msgr_running_total_time=2744.084305898,msgr_send_bytes=61684163658,msgr_send_messages=1858008 1587117476000000000\nceph,collection=throttle-msgr_dispatch_throttler-mds,host=stefanmds1,id=stefanmds1,type=mds get=1216458,get_or_fail_fail=0,get_or_fail_success=1216458,get_started=0,get_sum=51976882,max=104857600,put=1216458,put_sum=51976882,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117476000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanmds1,id=stefanmds1,type=mds msgr_active_connections=226,msgr_created_connections=42679,msgr_recv_bytes=63140151,msgr_recv_messages=299727,msgr_running_fast_dispatch_time=26.316138629,msgr_running_recv_time=36.969916165,msgr_running_send_time=70.457421128,msgr_running_total_time=226.230019936,msgr_send_bytes=193154464,msgr_send_messages=310481 1587117476000000000\nceph,collection=mds,host=stefanmds1,id=stefanmds1,type=mds caps=0,dir_commit=0,dir_fetch=12,dir_merge=0,dir_split=0,exported=0,exported_inodes=0,forward=0,imported=0,imported_inodes=0,inode_max=2147483647,inodes=10,inodes_bottom=3,inodes_expired=0,inodes_pin_tail=0,inodes_pinned=10,inodes_top=7,inodes_with_caps=0,load_cent=0,openino_backtrace_fetch=0,openino_dir_fetch=0,openino_peer_discover=0,q=0,reply=0,reply_latency.avgcount=0,reply_latency.avgtime=0,reply_latency.sum=0,request=0,subtrees=2,traverse=0,traverse_dir_fetch=0,traverse_discover=0,traverse_forward=0,traverse_hit=0,traverse_lock=0,traverse_remote_ino=0 1587117476000000000\nceph,collection=purge_queue,host=stefanmds1,id=stefanmds1,type=mds pq_executed=0,pq_executing=0,pq_executing_ops=0 1587117476000000000\nceph,collection=throttle-write_buf_throttle,host=stefanmds1,id=stefanmds1,type=mds get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=3758096384,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117476000000000\nceph,collection=throttle-write_buf_throttle-0x5624e9377f40,host=stefanmds1,id=stefanmds1,type=mds get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=3758096384,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117476000000000\nceph,collection=mds_cache,host=stefanmds1,id=stefanmds1,type=mds ireq_enqueue_scrub=0,ireq_exportdir=0,ireq_flush=0,ireq_fragmentdir=0,ireq_fragstats=0,ireq_inodestats=0,num_recovering_enqueued=0,num_recovering_prioritized=0,num_recovering_processing=0,num_strays=0,num_strays_delayed=0,num_strays_enqueuing=0,recovery_completed=0,recovery_started=0,strays_created=0,strays_enqueued=0,strays_migrated=0,strays_reintegrated=0 1587117476000000000\nceph,collection=throttle-objecter_bytes,host=stefanmds1,id=stefanmds1,type=mds get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=104857600,put=16,put_sum=1016,take=33,take_sum=1016,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117476000000000\nceph,collection=throttle-objecter_ops,host=stefanmds1,id=stefanmds1,type=mds get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=1024,put=33,put_sum=33,take=33,take_sum=33,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117476000000000\nceph,collection=mds_mem,host=stefanmds1,id=stefanmds1,type=mds cap=0,cap+=0,cap-=0,dir=12,dir+=12,dir-=0,dn=10,dn+=10,dn-=0,heap=322284,ino=13,ino+=13,ino-=0,rss=76032 1587117476000000000\nceph,collection=finisher-PurgeQueue,host=stefanmds1,id=stefanmds1,type=mds complete_latency.avgcount=4,complete_latency.avgtime=0.000176985,complete_latency.sum=0.000707941,queue_len=0 1587117476000000000\nceph,collection=cct,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw total_workers=0,unhealthy_workers=0 1587117156000000000\nceph,collection=throttle-objecter_bytes,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=791732,get_or_fail_fail=0,get_or_fail_success=791732,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=rgw,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw cache_hit=0,cache_miss=791706,failed_req=0,get=0,get_b=0,get_initial_lat.avgcount=0,get_initial_lat.avgtime=0,get_initial_lat.sum=0,keystone_token_cache_hit=0,keystone_token_cache_miss=0,pubsub_event_lost=0,pubsub_event_triggered=0,pubsub_events=0,pubsub_push_failed=0,pubsub_push_ok=0,pubsub_push_pending=0,pubsub_store_fail=0,pubsub_store_ok=0,put=0,put_b=0,put_initial_lat.avgcount=0,put_initial_lat.avgtime=0,put_initial_lat.sum=0,qactive=0,qlen=0,req=791705 1587117156000000000\nceph,collection=throttle-msgr_dispatch_throttler-radosclient,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=2697988,get_or_fail_fail=0,get_or_fail_success=2697988,get_started=0,get_sum=444563051,max=104857600,put=2697988,put_sum=444563051,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=finisher-radosclient,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw complete_latency.avgcount=2,complete_latency.avgtime=0.003530161,complete_latency.sum=0.007060323,queue_len=0 1587117156000000000\nceph,collection=throttle-rgw_async_rados_ops,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=0,get_or_fail_fail=0,get_or_fail_success=0,get_started=0,get_sum=0,max=64,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=throttle-objecter_ops,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=791732,get_or_fail_fail=0,get_or_fail_success=791732,get_started=0,get_sum=791732,max=24576,put=791732,put_sum=791732,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=throttle-objecter_bytes-0x5598969981c0,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=1637900,get_or_fail_fail=0,get_or_fail_success=1637900,get_started=0,get_sum=0,max=104857600,put=0,put_sum=0,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=objecter,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw command_active=0,command_resend=0,command_send=0,linger_active=8,linger_ping=1905736,linger_resend=4,linger_send=13,map_epoch=203,map_full=0,map_inc=17,omap_del=0,omap_rd=0,omap_wr=0,op=2697488,op_active=0,op_laggy=0,op_pg=0,op_r=791730,op_reply=2697476,op_resend=1,op_rmw=0,op_send=2697490,op_send_bytes=362,op_w=1905758,osd_laggy=5,osd_session_close=59558,osd_session_open=59566,osd_sessions=8,osdop_append=0,osdop_call=1,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=8,osdop_delete=0,osdop_getxattr=0,osdop_mapext=0,osdop_notify=0,osdop_other=791714,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=16,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=791706,osdop_truncate=0,osdop_watch=1905750,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=0,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117156000000000\nceph,collection=AsyncMessenger::Worker-2,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw msgr_active_connections=11,msgr_created_connections=59839,msgr_recv_bytes=342697143,msgr_recv_messages=1441603,msgr_running_fast_dispatch_time=161.807937536,msgr_running_recv_time=118.174064257,msgr_running_send_time=207.679154333,msgr_running_total_time=698.527662129,msgr_send_bytes=530785909,msgr_send_messages=1679950 1587117156000000000\nceph,collection=mempool,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw bloom_filter_bytes=0,bloom_filter_items=0,bluefs_bytes=0,bluefs_items=0,bluestore_alloc_bytes=0,bluestore_alloc_items=0,bluestore_cache_data_bytes=0,bluestore_cache_data_items=0,bluestore_cache_onode_bytes=0,bluestore_cache_onode_items=0,bluestore_cache_other_bytes=0,bluestore_cache_other_items=0,bluestore_fsck_bytes=0,bluestore_fsck_items=0,bluestore_txc_bytes=0,bluestore_txc_items=0,bluestore_writing_bytes=0,bluestore_writing_deferred_bytes=0,bluestore_writing_deferred_items=0,bluestore_writing_items=0,buffer_anon_bytes=225471,buffer_anon_items=163,buffer_meta_bytes=0,buffer_meta_items=0,mds_co_bytes=0,mds_co_items=0,osd_bytes=0,osd_items=0,osd_mapbl_bytes=0,osd_mapbl_items=0,osd_pglog_bytes=0,osd_pglog_items=0,osdmap_bytes=33904,osdmap_items=278,osdmap_mapping_bytes=0,osdmap_mapping_items=0,pgmap_bytes=0,pgmap_items=0,unittest_1_bytes=0,unittest_1_items=0,unittest_2_bytes=0,unittest_2_items=0 1587117156000000000\nceph,collection=throttle-msgr_dispatch_throttler-radosclient-0x559896998120,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=1652935,get_or_fail_fail=0,get_or_fail_success=1652935,get_started=0,get_sum=276333029,max=104857600,put=1652935,put_sum=276333029,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=AsyncMessenger::Worker-1,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw msgr_active_connections=17,msgr_created_connections=84859,msgr_recv_bytes=211170759,msgr_recv_messages=922646,msgr_running_fast_dispatch_time=31.487443762,msgr_running_recv_time=83.190789333,msgr_running_send_time=174.670510496,msgr_running_total_time=484.22086275,msgr_send_bytes=1322113179,msgr_send_messages=1636839 1587117156000000000\nceph,collection=finisher-radosclient-0x559896998080,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw complete_latency.avgcount=0,complete_latency.avgtime=0,complete_latency.sum=0,queue_len=0 1587117156000000000\nceph,collection=throttle-objecter_ops-0x559896997b80,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw get=1637900,get_or_fail_fail=0,get_or_fail_success=1637900,get_started=0,get_sum=1637900,max=24576,put=1637900,put_sum=1637900,take=0,take_sum=0,val=0,wait.avgcount=0,wait.avgtime=0,wait.sum=0 1587117156000000000\nceph,collection=AsyncMessenger::Worker-0,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw msgr_active_connections=18,msgr_created_connections=74757,msgr_recv_bytes=489001094,msgr_recv_messages=1986686,msgr_running_fast_dispatch_time=168.60950961,msgr_running_recv_time=142.903031533,msgr_running_send_time=267.911165712,msgr_running_total_time=824.885614951,msgr_send_bytes=707973504,msgr_send_messages=2463727 1587117156000000000\nceph,collection=objecter-0x559896997720,host=stefanrgw1,id=rgw.stefanrgw1.4219.94113851143184,type=rgw command_active=0,command_resend=0,command_send=0,linger_active=0,linger_ping=0,linger_resend=0,linger_send=0,map_epoch=203,map_full=0,map_inc=8,omap_del=0,omap_rd=0,omap_wr=0,op=1637998,op_active=0,op_laggy=0,op_pg=0,op_r=1062803,op_reply=1637998,op_resend=15,op_rmw=0,op_send=1638013,op_send_bytes=63321099,op_w=575195,osd_laggy=0,osd_session_close=125555,osd_session_open=125563,osd_sessions=8,osdop_append=0,osdop_call=1637886,osdop_clonerange=0,osdop_cmpxattr=0,osdop_create=0,osdop_delete=0,osdop_getxattr=0,osdop_mapext=0,osdop_notify=0,osdop_other=112,osdop_pgls=0,osdop_pgls_filter=0,osdop_read=0,osdop_resetxattrs=0,osdop_rmxattr=0,osdop_setxattr=0,osdop_sparse_read=0,osdop_src_cmpxattr=0,osdop_stat=0,osdop_truncate=0,osdop_watch=0,osdop_write=0,osdop_writefull=0,osdop_writesame=0,osdop_zero=0,poolop_active=0,poolop_resend=0,poolop_send=0,poolstat_active=0,poolstat_resend=0,poolstat_send=0,statfs_active=0,statfs_resend=0,statfs_send=0 1587117156000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ceph/ceph.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ceph\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmeasurement = \"ceph\"\n\ttypeMon     = \"monitor\"\n\ttypeOsd     = \"osd\"\n\ttypeMds     = \"mds\"\n\ttypeRgw     = \"rgw\"\n\tosdPrefix   = \"ceph-osd\"\n\tmonPrefix   = \"ceph-mon\"\n\tmdsPrefix   = \"ceph-mds\"\n\trgwPrefix   = \"ceph-client\"\n\tsockSuffix  = \"asok\"\n)\n\ntype Ceph struct {\n\tCephBinary             string `toml:\"ceph_binary\"`\n\tOsdPrefix              string `toml:\"osd_prefix\"`\n\tMonPrefix              string `toml:\"mon_prefix\"`\n\tMdsPrefix              string `toml:\"mds_prefix\"`\n\tRgwPrefix              string `toml:\"rgw_prefix\"`\n\tSocketDir              string `toml:\"socket_dir\"`\n\tSocketSuffix           string `toml:\"socket_suffix\"`\n\tCephUser               string `toml:\"ceph_user\"`\n\tCephConfig             string `toml:\"ceph_config\"`\n\tGatherAdminSocketStats bool   `toml:\"gather_admin_socket_stats\"`\n\tGatherClusterStats     bool   `toml:\"gather_cluster_stats\"`\n\n\tLog        telegraf.Logger `toml:\"-\"`\n\tschemaMaps map[socket]perfSchemaMap\n}\n\nfunc (*Ceph) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *Ceph) Gather(acc telegraf.Accumulator) error {\n\tif c.GatherAdminSocketStats {\n\t\tif err := c.gatherAdminSocketStats(acc); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif c.GatherClusterStats {\n\t\tif err := c.gatherClusterStats(acc); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Ceph) gatherAdminSocketStats(acc telegraf.Accumulator) error {\n\tsockets, err := findSockets(c)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find sockets at path %q: %w\", c.SocketDir, err)\n\t}\n\n\tif c.schemaMaps == nil {\n\t\tc.schemaMaps = make(map[socket]perfSchemaMap)\n\t}\n\n\tfor _, s := range sockets {\n\t\tif _, ok := c.schemaMaps[*s]; !ok {\n\t\t\trawSchema, err := perfSchema(c.CephBinary, s)\n\t\t\tif err != nil {\n\t\t\t\tc.Log.Warnf(\"failed to dump perf schema from socket %q: %v\", s.socket, err)\n\t\t\t} else if schema, err := parseSchema(rawSchema); err != nil {\n\t\t\t\tc.Log.Warnf(\"failed to parse perf schema from socket %q: %v\", s.socket, err)\n\t\t\t} else {\n\t\t\t\tc.schemaMaps[*s] = schema\n\t\t\t}\n\t\t}\n\t\tdump, err := perfDump(c.CephBinary, s)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error reading from socket %q: %w\", s.socket, err))\n\t\t\tcontinue\n\t\t}\n\t\tdata, err := c.parseDump(dump)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error parsing dump from socket %q: %w\", s.socket, err))\n\t\t\tcontinue\n\t\t}\n\t\tfor tag, metrics := range data {\n\t\t\tif schema, ok := c.schemaMaps[*s]; ok {\n\t\t\t\tfor name, metric := range metrics {\n\t\t\t\t\tvalueType := schema[tag][name]\n\t\t\t\t\tswitch valueType {\n\t\t\t\t\tcase telegraf.Counter:\n\t\t\t\t\t\tacc.AddCounter(measurement,\n\t\t\t\t\t\t\tmap[string]interface{}{name: metric},\n\t\t\t\t\t\t\tmap[string]string{\"type\": s.sockType, \"id\": s.sockID, \"collection\": tag})\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tacc.AddGauge(measurement,\n\t\t\t\t\t\t\tmap[string]interface{}{name: metric},\n\t\t\t\t\t\t\tmap[string]string{\"type\": s.sockType, \"id\": s.sockID, \"collection\": tag})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tacc.AddFields(measurement,\n\t\t\t\t\tmetrics,\n\t\t\t\t\tmap[string]string{\"type\": s.sockType, \"id\": s.sockID, \"collection\": tag})\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *Ceph) gatherClusterStats(acc telegraf.Accumulator) error {\n\tjobs := []struct {\n\t\tcommand string\n\t\tparser  func(telegraf.Accumulator, string) error\n\t}{\n\t\t{\"status\", decodeStatus},\n\t\t{\"df\", decodeDf},\n\t\t{\"osd pool stats\", decodeOsdPoolStats},\n\t}\n\n\t// For each job, execute against the cluster, parse and accumulate the data points\n\tfor _, job := range jobs {\n\t\toutput, err := c.execute(job.command)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error executing command: %w\", err)\n\t\t}\n\t\terr = job.parser(acc, output)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing output: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Run ceph perf schema on the passed socket.  The output is a JSON string\n// mapping collection names to a map of counter names to information.\n//\n// The counter information includes the type of the counter, which determines\n// the names of the final series produced.  For example, a real-integer pair\n// valued metric produces three series: sum, avgcount and avgtime; which hold\n// the sum of all values, the count of all values and the division of these\n// values.\nfunc perfSchema(binary string, socket *socket) (string, error) {\n\tcmdArgs := []string{\"--admin-daemon\", socket.socket}\n\n\tswitch socket.sockType {\n\tcase typeOsd, typeMds, typeRgw:\n\t\tcmdArgs = append(cmdArgs, \"perf\", \"schema\")\n\tcase typeMon:\n\t\tcmdArgs = append(cmdArgs, \"perfcounters_schema\")\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"ignoring unknown socket type: %s\", socket.sockType)\n\t}\n\n\tcmd := exec.Command(binary, cmdArgs...)\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error running ceph schema: %w\", err)\n\t}\n\n\treturn out.String(), nil\n}\n\nvar perfDump = func(binary string, socket *socket) (string, error) {\n\tcmdArgs := []string{\"--admin-daemon\", socket.socket}\n\n\tswitch socket.sockType {\n\tcase typeOsd:\n\t\tcmdArgs = append(cmdArgs, \"perf\", \"dump\")\n\tcase typeMon:\n\t\tcmdArgs = append(cmdArgs, \"perfcounters_dump\")\n\tcase typeMds:\n\t\tcmdArgs = append(cmdArgs, \"perf\", \"dump\")\n\tcase typeRgw:\n\t\tcmdArgs = append(cmdArgs, \"perf\", \"dump\")\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"ignoring unknown socket type: %s\", socket.sockType)\n\t}\n\n\tcmd := exec.Command(binary, cmdArgs...)\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error running ceph dump: %w\", err)\n\t}\n\n\treturn out.String(), nil\n}\n\nvar findSockets = func(c *Ceph) ([]*socket, error) {\n\tlisting, err := os.ReadDir(c.SocketDir)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read socket directory %q: %w\", c.SocketDir, err)\n\t}\n\tsockets := make([]*socket, 0, len(listing))\n\tfor _, info := range listing {\n\t\tf := info.Name()\n\t\tvar sockType string\n\t\tvar sockPrefix string\n\t\tif strings.HasPrefix(f, c.MonPrefix) {\n\t\t\tsockType = typeMon\n\t\t\tsockPrefix = monPrefix\n\t\t}\n\t\tif strings.HasPrefix(f, c.OsdPrefix) {\n\t\t\tsockType = typeOsd\n\t\t\tsockPrefix = osdPrefix\n\t\t}\n\t\tif strings.HasPrefix(f, c.MdsPrefix) {\n\t\t\tsockType = typeMds\n\t\t\tsockPrefix = mdsPrefix\n\t\t}\n\t\tif strings.HasPrefix(f, c.RgwPrefix) {\n\t\t\tsockType = typeRgw\n\t\t\tsockPrefix = rgwPrefix\n\t\t}\n\n\t\tif sockType == typeOsd || sockType == typeMon || sockType == typeMds || sockType == typeRgw {\n\t\t\tpath := filepath.Join(c.SocketDir, f)\n\t\t\tsockets = append(sockets, &socket{parseSockID(f, sockPrefix, c.SocketSuffix), sockType, path})\n\t\t}\n\t}\n\treturn sockets, nil\n}\n\nfunc parseSockID(fname, prefix, suffix string) string {\n\ts := fname\n\ts = strings.TrimPrefix(s, prefix)\n\ts = strings.TrimSuffix(s, suffix)\n\ts = strings.Trim(s, \".-_\")\n\treturn s\n}\n\ntype socket struct {\n\tsockID   string\n\tsockType string\n\tsocket   string\n}\n\ntype metric struct {\n\tpathStack []string // lifo stack of name components\n\tvalue     float64\n}\n\n// Pops names of pathStack to build the flattened name for a metric\nfunc (m *metric) name() string {\n\tbuf := bytes.Buffer{}\n\tfor i := len(m.pathStack) - 1; i >= 0; i-- {\n\t\tif buf.Len() > 0 {\n\t\t\tbuf.WriteString(\".\")\n\t\t}\n\t\tbuf.WriteString(m.pathStack[i])\n\t}\n\treturn buf.String()\n}\n\ntype metricMap map[string]interface{}\n\ntype taggedMetricMap map[string]metricMap\n\n// Mask bits for perf counters\nconst (\n\tperfCounterNone       = 0\n\tperfCounterTime       = 0x1\n\tperfCounterU64        = 0x2\n\tperfCounterLongRunAvg = 0x4\n\tperfCounterCounter    = 0x8\n\tperfCounterHistogram  = 0x10\n)\n\ntype rawPerfCounter struct {\n\tTypeMask    int    `json:\"type\"`\n\tMetricType  string `json:\"metric_type\"`\n\tValueType   string `json:\"value_type\"`\n\tDescription string `json:\"description\"`\n\tNick        string `json:\"nick\"`\n\tPriority    int    `json:\"priority\"`\n\tUnits       string `json:\"units\"`\n}\n\ntype rawCollection map[string]rawPerfCounter\n\ntype perfSchemaMap map[string]map[string]telegraf.ValueType\n\n// Parses the output of ceph perf schema into a useful format, mapping metrics\n// in collections to their Telegraf metric type.  This is made a little more\n// complicated by the need to expand averages into their component metrics.\nfunc parseSchema(rawSchema string) (perfSchemaMap, error) {\n\trawMap := make(map[string]rawCollection)\n\terr := json.Unmarshal([]byte(rawSchema), &rawMap)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse json: %q: %w\", rawSchema, err)\n\t}\n\n\tschemaMap := make(perfSchemaMap)\n\tfor collection, counters := range rawMap {\n\t\tschemaMap[collection] = make(map[string]telegraf.ValueType)\n\t\tfor counter, schema := range counters {\n\t\t\tif schema.TypeMask&perfCounterLongRunAvg != 0 {\n\t\t\t\tschemaMap[collection][counter+\".sum\"] = telegraf.Counter\n\t\t\t\tschemaMap[collection][counter+\".avgcount\"] = telegraf.Counter\n\t\t\t\tif schema.TypeMask&perfCounterTime != 0 {\n\t\t\t\t\tschemaMap[collection][counter+\".avgtime\"] = telegraf.Gauge\n\t\t\t\t}\n\t\t\t} else if schema.TypeMask&perfCounterCounter != 0 {\n\t\t\t\tschemaMap[collection][counter] = telegraf.Counter\n\t\t\t} else {\n\t\t\t\tschemaMap[collection][counter] = telegraf.Gauge\n\t\t\t}\n\t\t}\n\t}\n\treturn schemaMap, nil\n}\n\n// Parses a raw JSON string into a taggedMetricMap\n// Delegates the actual parsing to newTaggedMetricMap(..)\nfunc (c *Ceph) parseDump(dump string) (taggedMetricMap, error) {\n\tdata := make(map[string]interface{})\n\terr := json.Unmarshal([]byte(dump), &data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse json: %q: %w\", dump, err)\n\t}\n\n\treturn c.newTaggedMetricMap(data), nil\n}\n\n// Builds a TaggedMetricMap out of a generic string map.\n// The top-level key is used as a tag and all sub-keys are flattened into metrics\nfunc (c *Ceph) newTaggedMetricMap(data map[string]interface{}) taggedMetricMap {\n\ttmm := make(taggedMetricMap)\n\tfor tag, datapoints := range data {\n\t\tmm := make(metricMap)\n\t\tfor _, m := range c.flatten(datapoints) {\n\t\t\tmm[m.name()] = m.value\n\t\t}\n\t\ttmm[tag] = mm\n\t}\n\treturn tmm\n}\n\n// Recursively flattens any k-v hierarchy present in data.\n// Nested keys are flattened into ordered slices associated with a metric value.\n// The key slices are treated as stacks, and are expected to be reversed and concatenated\n// when passed as metrics to the accumulator. (see (*metric).name())\nfunc (c *Ceph) flatten(data interface{}) []*metric {\n\tvar metrics []*metric\n\n\tswitch val := data.(type) {\n\tcase float64:\n\t\tmetrics = []*metric{\n\t\t\t{\n\t\t\t\tmake([]string, 0, 1), val,\n\t\t\t},\n\t\t}\n\tcase map[string]interface{}:\n\t\tmetrics = make([]*metric, 0, len(val))\n\t\tfor k, v := range val {\n\t\t\tfor _, m := range c.flatten(v) {\n\t\t\t\tm.pathStack = append(m.pathStack, k)\n\t\t\t\tmetrics = append(metrics, m)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tc.Log.Infof(\"ignoring unexpected type '%T' for value %v\", val, val)\n\t}\n\n\treturn metrics\n}\n\n// execute executes the 'ceph' command with the supplied arguments, returning JSON formatted output\nfunc (c *Ceph) execute(command string) (string, error) {\n\tsplitCommand := strings.Split(command, \" \")\n\tcmdArgs := make([]string, 0, len(splitCommand)+6)\n\tcmdArgs = append(cmdArgs, \"--conf\", c.CephConfig, \"--name\", c.CephUser, \"--format\", \"json\")\n\tcmdArgs = append(cmdArgs, splitCommand...)\n\n\tcmd := exec.Command(c.CephBinary, cmdArgs...)\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error running ceph %q: %w\", command, err)\n\t}\n\n\toutput := out.String()\n\n\t// Ceph doesn't sanitize its output, and may return invalid JSON.  Patch this\n\t// up for them, as having some inaccurate data is better than none.\n\toutput = strings.ReplaceAll(output, \"-inf\", \"0\")\n\toutput = strings.ReplaceAll(output, \"inf\", \"0\")\n\n\treturn output, nil\n}\n\n// status is used to unmarshal \"ceph -s\" output\ntype status struct {\n\tFSMap struct {\n\t\tNumIn        float64 `json:\"in\"`\n\t\tNumMax       float64 `json:\"max\"`\n\t\tNumUp        float64 `json:\"up\"`\n\t\tNumUpStandby float64 `json:\"up:standby\"`\n\t} `json:\"fsmap\"`\n\tHealth struct {\n\t\tOverallStatus string `json:\"overall_status\"` // Only valid for ceph version <15\n\t\tStatus        string `json:\"status\"`\n\t} `json:\"health\"`\n\tMonMap struct {\n\t\tNumMons float64 `json:\"num_mons\"`\n\t} `json:\"monmap\"`\n\tOSDMap struct {\n\t\tEpoch          float64  `json:\"epoch\"`\n\t\tNumInOSDs      float64  `json:\"num_in_osds\"`\n\t\tNumOSDs        float64  `json:\"num_osds\"`\n\t\tNumRemappedPGs float64  `json:\"num_remapped_pgs\"`\n\t\tNumUpOSDs      float64  `json:\"num_up_osds\"`\n\t\tOSDMap         struct { // nested OSDmap used in ceph version <15\n\t\t\tEpoch          float64 `json:\"epoch\"`\n\t\t\tFull           bool    `json:\"full\"`\n\t\t\tNearFull       bool    `json:\"nearfull\"`\n\t\t\tNumInOSDs      float64 `json:\"num_in_osds\"`\n\t\t\tNumOSDs        float64 `json:\"num_osds\"`\n\t\t\tNumRemappedPGs float64 `json:\"num_remapped_pgs\"`\n\t\t\tNumUpOSDs      float64 `json:\"num_up_osds\"`\n\t\t} `json:\"osdmap\"`\n\t} `json:\"osdmap\"`\n\tPGMap struct {\n\t\tPGsByState []struct {\n\t\t\tCount     float64 `json:\"count\"`\n\t\t\tStateName string  `json:\"state_name\"`\n\t\t} `json:\"pgs_by_state\"`\n\t\tBytesAvail              float64 `json:\"bytes_avail\"`\n\t\tBytesTotal              float64 `json:\"bytes_total\"`\n\t\tBytesUsed               float64 `json:\"bytes_used\"`\n\t\tDataBytes               float64 `json:\"data_bytes\"`\n\t\tDegradedObjects         float64 `json:\"degraded_objects\"`\n\t\tDegradedRatio           float64 `json:\"degraded_ratio\"`\n\t\tDegradedTotal           float64 `json:\"degraded_total\"`\n\t\tInactivePGsRatio        float64 `json:\"inactive_pgs_ratio\"`\n\t\tNumBytesRecovered       float64 `json:\"num_bytes_recovered\"`\n\t\tNumKeysRecovered        float64 `json:\"num_keys_recovered\"`\n\t\tNumObjects              float64 `json:\"num_objects\"`\n\t\tNumObjectRecovered      float64 `json:\"num_objects_recovered\"`\n\t\tNumPGs                  float64 `json:\"num_pgs\"`\n\t\tNumPools                float64 `json:\"num_pools\"`\n\t\tOpPerSec                float64 `json:\"op_per_sec\"` // This field is no longer reported in ceph 10 and later\n\t\tReadBytesSec            float64 `json:\"read_bytes_sec\"`\n\t\tReadOpPerSec            float64 `json:\"read_op_per_sec\"`\n\t\tRecoveringBytesPerSec   float64 `json:\"recovering_bytes_per_sec\"`\n\t\tRecoveringKeysPerSec    float64 `json:\"recovering_keys_per_sec\"`\n\t\tRecoveringObjectsPerSec float64 `json:\"recovering_objects_per_sec\"`\n\t\tVersion                 float64 `json:\"version\"`\n\t\tWriteBytesSec           float64 `json:\"write_bytes_sec\"`\n\t\tWriteOpPerSec           float64 `json:\"write_op_per_sec\"`\n\t} `json:\"pgmap\"`\n}\n\n// decodeStatus decodes the output of 'ceph -s'\nfunc decodeStatus(acc telegraf.Accumulator, input string) error {\n\tdata := &status{}\n\tif err := json.Unmarshal([]byte(input), data); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse json: %q: %w\", input, err)\n\t}\n\n\tdecoders := []func(telegraf.Accumulator, *status) error{\n\t\tdecodeStatusFsmap,\n\t\tdecodeStatusHealth,\n\t\tdecodeStatusMonmap,\n\t\tdecodeStatusOsdmap,\n\t\tdecodeStatusPgmap,\n\t\tdecodeStatusPgmapState,\n\t}\n\n\tfor _, decoder := range decoders {\n\t\tif err := decoder(acc, data); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// decodeStatusFsmap decodes the FS map portion of the output of 'ceph -s'\nfunc decodeStatusFsmap(acc telegraf.Accumulator, data *status) error {\n\tfields := map[string]interface{}{\n\t\t\"in\":         data.FSMap.NumIn,\n\t\t\"max\":        data.FSMap.NumMax,\n\t\t\"up_standby\": data.FSMap.NumUpStandby,\n\t\t\"up\":         data.FSMap.NumUp,\n\t}\n\tacc.AddFields(\"ceph_fsmap\", fields, make(map[string]string))\n\treturn nil\n}\n\n// decodeStatusHealth decodes the health portion of the output of 'ceph status'\nfunc decodeStatusHealth(acc telegraf.Accumulator, data *status) error {\n\tstatusCodes := map[string]float64{\n\t\t\"HEALTH_ERR\":  0,\n\t\t\"HEALTH_WARN\": 1,\n\t\t\"HEALTH_OK\":   2,\n\t}\n\tfields := map[string]interface{}{\n\t\t\"overall_status\": data.Health.OverallStatus, // This field is no longer reported in ceph 10 and later\n\t\t\"status_code\":    statusCodes[data.Health.Status],\n\t\t\"status\":         data.Health.Status,\n\t}\n\tacc.AddFields(\"ceph_health\", fields, make(map[string]string))\n\treturn nil\n}\n\n// decodeStatusMonmap decodes the Mon map portion of the output of 'ceph -s'\nfunc decodeStatusMonmap(acc telegraf.Accumulator, data *status) error {\n\tfields := map[string]interface{}{\n\t\t\"num_mons\": data.MonMap.NumMons,\n\t}\n\tacc.AddFields(\"ceph_monmap\", fields, make(map[string]string))\n\treturn nil\n}\n\n// decodeStatusOsdmap decodes the OSD map portion of the output of 'ceph -s'\nfunc decodeStatusOsdmap(acc telegraf.Accumulator, data *status) error {\n\tfields := map[string]interface{}{\n\t\t\"epoch\":            data.OSDMap.Epoch,\n\t\t\"num_in_osds\":      data.OSDMap.NumInOSDs,\n\t\t\"num_osds\":         data.OSDMap.NumOSDs,\n\t\t\"num_remapped_pgs\": data.OSDMap.NumRemappedPGs,\n\t\t\"num_up_osds\":      data.OSDMap.NumUpOSDs,\n\t}\n\tif data.OSDMap.OSDMap.Epoch != 0 && data.OSDMap.OSDMap.NumOSDs != 0 {\n\t\tfields = map[string]interface{}{\n\t\t\t\"epoch\":            data.OSDMap.OSDMap.Epoch,\n\t\t\t\"full\":             data.OSDMap.OSDMap.Full,\n\t\t\t\"nearfull\":         data.OSDMap.OSDMap.NearFull,\n\t\t\t\"num_in_osds\":      data.OSDMap.OSDMap.NumInOSDs,\n\t\t\t\"num_osds\":         data.OSDMap.OSDMap.NumOSDs,\n\t\t\t\"num_remapped_pgs\": data.OSDMap.OSDMap.NumRemappedPGs,\n\t\t\t\"num_up_osds\":      data.OSDMap.OSDMap.NumUpOSDs,\n\t\t}\n\t}\n\n\tacc.AddFields(\"ceph_osdmap\", fields, make(map[string]string))\n\treturn nil\n}\n\n// decodeStatusPgmap decodes the PG map portion of the output of 'ceph -s'\nfunc decodeStatusPgmap(acc telegraf.Accumulator, data *status) error {\n\tfields := map[string]interface{}{\n\t\t\"bytes_avail\":                data.PGMap.BytesAvail,\n\t\t\"bytes_total\":                data.PGMap.BytesTotal,\n\t\t\"bytes_used\":                 data.PGMap.BytesUsed,\n\t\t\"data_bytes\":                 data.PGMap.DataBytes,\n\t\t\"degraded_objects\":           data.PGMap.DegradedObjects,\n\t\t\"degraded_ratio\":             data.PGMap.DegradedRatio,\n\t\t\"degraded_total\":             data.PGMap.DegradedTotal,\n\t\t\"inactive_pgs_ratio\":         data.PGMap.InactivePGsRatio,\n\t\t\"num_bytes_recovered\":        data.PGMap.NumBytesRecovered,\n\t\t\"num_keys_recovered\":         data.PGMap.NumKeysRecovered,\n\t\t\"num_objects_recovered\":      data.PGMap.NumObjectRecovered,\n\t\t\"num_objects\":                data.PGMap.NumObjects,\n\t\t\"num_pgs\":                    data.PGMap.NumPGs,\n\t\t\"num_pools\":                  data.PGMap.NumPools,\n\t\t\"op_per_sec\":                 data.PGMap.OpPerSec, // This field is no longer reported in ceph 10 and later\n\t\t\"read_bytes_sec\":             data.PGMap.ReadBytesSec,\n\t\t\"read_op_per_sec\":            data.PGMap.ReadOpPerSec,\n\t\t\"recovering_bytes_per_sec\":   data.PGMap.RecoveringBytesPerSec,\n\t\t\"recovering_keys_per_sec\":    data.PGMap.RecoveringKeysPerSec,\n\t\t\"recovering_objects_per_sec\": data.PGMap.RecoveringObjectsPerSec,\n\t\t\"version\":                    data.PGMap.Version,\n\t\t\"write_bytes_sec\":            data.PGMap.WriteBytesSec,\n\t\t\"write_op_per_sec\":           data.PGMap.WriteOpPerSec,\n\t}\n\tacc.AddFields(\"ceph_pgmap\", fields, make(map[string]string))\n\treturn nil\n}\n\n// decodeStatusPgmapState decodes the PG map state portion of the output of 'ceph -s'\nfunc decodeStatusPgmapState(acc telegraf.Accumulator, data *status) error {\n\tfor _, pgState := range data.PGMap.PGsByState {\n\t\ttags := map[string]string{\n\t\t\t\"state\": pgState.StateName,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"count\": pgState.Count,\n\t\t}\n\t\tacc.AddFields(\"ceph_pgmap_state\", fields, tags)\n\t}\n\treturn nil\n}\n\n// df is used to unmarshal 'ceph df' output\ntype df struct {\n\tStats struct {\n\t\tNumOSDs            float64 `json:\"num_osds\"`\n\t\tNumPerPoolOmapOSDs float64 `json:\"num_per_pool_omap_osds\"`\n\t\tNumPerPoolOSDs     float64 `json:\"num_per_pool_osds\"`\n\t\tTotalAvail         float64 `json:\"total_avail\"` // pre ceph 0.84\n\t\tTotalAvailBytes    float64 `json:\"total_avail_bytes\"`\n\t\tTotalBytes         float64 `json:\"total_bytes\"`\n\t\tTotalSpace         float64 `json:\"total_space\"` // pre ceph 0.84\n\t\tTotalUsed          float64 `json:\"total_used\"`  // pre ceph 0.84\n\t\tTotalUsedBytes     float64 `json:\"total_used_bytes\"`\n\t\tTotalUsedRawBytes  float64 `json:\"total_used_raw_bytes\"`\n\t\tTotalUsedRawRatio  float64 `json:\"total_used_raw_ratio\"`\n\t} `json:\"stats\"`\n\tStatsbyClass map[string]map[string]float64 `json:\"stats_by_class\"`\n\tPools        []struct {\n\t\tName  string `json:\"name\"`\n\t\tStats struct {\n\t\t\tBytesUsed   float64 `json:\"bytes_used\"`\n\t\t\tKBUsed      float64 `json:\"kb_used\"`\n\t\t\tMaxAvail    float64 `json:\"max_avail\"`\n\t\t\tObjects     float64 `json:\"objects\"`\n\t\t\tPercentUsed float64 `json:\"percent_used\"`\n\t\t\tStored      float64 `json:\"stored\"`\n\t\t} `json:\"stats\"`\n\t} `json:\"pools\"`\n}\n\n// decodeDf decodes the output of 'ceph df'\nfunc decodeDf(acc telegraf.Accumulator, input string) error {\n\tdata := &df{}\n\tif err := json.Unmarshal([]byte(input), data); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse json: %q: %w\", input, err)\n\t}\n\n\t// ceph.usage: records global utilization and number of objects\n\tfields := map[string]interface{}{\n\t\t\"num_osds\":               data.Stats.NumOSDs,\n\t\t\"num_per_pool_omap_osds\": data.Stats.NumPerPoolOmapOSDs,\n\t\t\"num_per_pool_osds\":      data.Stats.NumPerPoolOSDs,\n\t\t\"total_avail_bytes\":      data.Stats.TotalAvailBytes,\n\t\t\"total_avail\":            data.Stats.TotalAvail, // pre ceph 0.84\n\t\t\"total_bytes\":            data.Stats.TotalBytes,\n\t\t\"total_space\":            data.Stats.TotalSpace, // pre ceph 0.84\n\t\t\"total_used_bytes\":       data.Stats.TotalUsedBytes,\n\t\t\"total_used_raw_bytes\":   data.Stats.TotalUsedRawBytes,\n\t\t\"total_used_raw_ratio\":   data.Stats.TotalUsedRawRatio,\n\t\t\"total_used\":             data.Stats.TotalUsed, // pre ceph 0.84\n\t}\n\tacc.AddFields(\"ceph_usage\", fields, make(map[string]string))\n\n\t// ceph.stats_by_class: records per device-class usage\n\tfor class, stats := range data.StatsbyClass {\n\t\ttags := map[string]string{\n\t\t\t\"class\": class,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tfor key, value := range stats {\n\t\t\tfields[key] = value\n\t\t}\n\t\tacc.AddFields(\"ceph_deviceclass_usage\", fields, tags)\n\t}\n\n\t// ceph.pool.usage: records per pool utilization and number of objects\n\tfor _, pool := range data.Pools {\n\t\ttags := map[string]string{\n\t\t\t\"name\": pool.Name,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"bytes_used\":   pool.Stats.BytesUsed,\n\t\t\t\"kb_used\":      pool.Stats.KBUsed,\n\t\t\t\"max_avail\":    pool.Stats.MaxAvail,\n\t\t\t\"objects\":      pool.Stats.Objects,\n\t\t\t\"percent_used\": pool.Stats.PercentUsed,\n\t\t\t\"stored\":       pool.Stats.Stored,\n\t\t}\n\t\tacc.AddFields(\"ceph_pool_usage\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// osdPoolStats is used to unmarshal 'ceph osd pool stats' output\ntype osdPoolStats []struct {\n\tPoolName     string `json:\"pool_name\"`\n\tClientIORate struct {\n\t\tOpPerSec      float64 `json:\"op_per_sec\"` // This field is no longer reported in ceph 10 and later\n\t\tReadBytesSec  float64 `json:\"read_bytes_sec\"`\n\t\tReadOpPerSec  float64 `json:\"read_op_per_sec\"`\n\t\tWriteBytesSec float64 `json:\"write_bytes_sec\"`\n\t\tWriteOpPerSec float64 `json:\"write_op_per_sec\"`\n\t} `json:\"client_io_rate\"`\n\tRecoveryRate struct {\n\t\tNumBytesRecovered       float64 `json:\"num_bytes_recovered\"`\n\t\tNumKeysRecovered        float64 `json:\"num_keys_recovered\"`\n\t\tNumObjectRecovered      float64 `json:\"num_objects_recovered\"`\n\t\tRecoveringBytesPerSec   float64 `json:\"recovering_bytes_per_sec\"`\n\t\tRecoveringKeysPerSec    float64 `json:\"recovering_keys_per_sec\"`\n\t\tRecoveringObjectsPerSec float64 `json:\"recovering_objects_per_sec\"`\n\t} `json:\"recovery_rate\"`\n\tRecovery struct {\n\t\tDegradedObjects float64 `json:\"degraded_objects\"`\n\t\tDegradedRatio   float64 `json:\"degraded_ratio\"`\n\t\tDegradedTotal   float64 `json:\"degraded_total\"`\n\t} `json:\"recovery\"`\n}\n\n// decodeOsdPoolStats decodes the output of 'ceph osd pool stats'\nfunc decodeOsdPoolStats(acc telegraf.Accumulator, input string) error {\n\tdata := make(osdPoolStats, 0)\n\tif err := json.Unmarshal([]byte(input), &data); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse json: %q: %w\", input, err)\n\t}\n\n\t// ceph.pool.stats: records pre pool IO and recovery throughput\n\tfor _, pool := range data {\n\t\ttags := map[string]string{\n\t\t\t\"name\": pool.PoolName,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"degraded_objects\":           pool.Recovery.DegradedObjects,\n\t\t\t\"degraded_ratio\":             pool.Recovery.DegradedRatio,\n\t\t\t\"degraded_total\":             pool.Recovery.DegradedTotal,\n\t\t\t\"num_bytes_recovered\":        pool.RecoveryRate.NumBytesRecovered,\n\t\t\t\"num_keys_recovered\":         pool.RecoveryRate.NumKeysRecovered,\n\t\t\t\"num_objects_recovered\":      pool.RecoveryRate.NumObjectRecovered,\n\t\t\t\"op_per_sec\":                 pool.ClientIORate.OpPerSec, // This field is no longer reported in ceph 10 and later\n\t\t\t\"read_bytes_sec\":             pool.ClientIORate.ReadBytesSec,\n\t\t\t\"read_op_per_sec\":            pool.ClientIORate.ReadOpPerSec,\n\t\t\t\"recovering_bytes_per_sec\":   pool.RecoveryRate.RecoveringBytesPerSec,\n\t\t\t\"recovering_keys_per_sec\":    pool.RecoveryRate.RecoveringKeysPerSec,\n\t\t\t\"recovering_objects_per_sec\": pool.RecoveryRate.RecoveringObjectsPerSec,\n\t\t\t\"write_bytes_sec\":            pool.ClientIORate.WriteBytesSec,\n\t\t\t\"write_op_per_sec\":           pool.ClientIORate.WriteOpPerSec,\n\t\t}\n\t\tacc.AddFields(\"ceph_pool_stats\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(measurement, func() telegraf.Input {\n\t\treturn &Ceph{\n\t\t\tCephBinary:             \"/usr/bin/ceph\",\n\t\t\tOsdPrefix:              osdPrefix,\n\t\t\tMonPrefix:              monPrefix,\n\t\t\tMdsPrefix:              mdsPrefix,\n\t\t\tRgwPrefix:              rgwPrefix,\n\t\t\tSocketDir:              \"/var/run/ceph\",\n\t\t\tSocketSuffix:           sockSuffix,\n\t\t\tCephUser:               \"client.admin\",\n\t\t\tCephConfig:             \"/etc/ceph/ceph.conf\",\n\t\t\tGatherAdminSocketStats: true,\n\t\t\tGatherClusterStats:     false,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ceph/ceph_test.go",
    "content": "package ceph\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tepsilon = float64(0.00000001)\n)\n\ntype expectedResult struct {\n\tmetric string\n\tfields map[string]interface{}\n\ttags   map[string]string\n}\n\nfunc TestParseSockId(t *testing.T) {\n\ts := parseSockID(sockFile(osdPrefix, 1), osdPrefix, sockSuffix)\n\trequire.Equal(t, \"1\", s)\n}\n\nfunc TestParseMonDump(t *testing.T) {\n\tc := &Ceph{Log: testutil.Logger{}}\n\tdump, err := c.parseDump(monPerfDump)\n\trequire.NoError(t, err)\n\trequire.InEpsilon(t, int64(5678670180), dump[\"cluster\"][\"osd_kb_used\"], epsilon)\n\trequire.InEpsilon(t, 6866.540527000, dump[\"paxos\"][\"store_state_latency.sum\"], epsilon)\n}\n\nfunc TestParseOsdDump(t *testing.T) {\n\tc := &Ceph{Log: testutil.Logger{}}\n\tdump, err := c.parseDump(osdPerfDump)\n\trequire.NoError(t, err)\n\trequire.InEpsilon(t, 552132.109360000, dump[\"filestore\"][\"commitcycle_interval.sum\"], epsilon)\n\trequire.InDelta(t, float64(0), dump[\"mutex-FileJournal::finisher_lock\"][\"wait.avgcount\"], testutil.DefaultDelta)\n}\n\nfunc TestParseMdsDump(t *testing.T) {\n\tc := &Ceph{Log: testutil.Logger{}}\n\tdump, err := c.parseDump(mdsPerfDump)\n\trequire.NoError(t, err)\n\trequire.InEpsilon(t, 2408386.600934982, dump[\"mds\"][\"reply_latency.sum\"], epsilon)\n\trequire.InDelta(t, float64(0), dump[\"throttle-write_buf_throttle\"][\"wait.avgcount\"], testutil.DefaultDelta)\n}\n\nfunc TestParseRgwDump(t *testing.T) {\n\tc := &Ceph{Log: testutil.Logger{}}\n\tdump, err := c.parseDump(rgwPerfDump)\n\trequire.NoError(t, err)\n\trequire.InEpsilon(t, 0.002219876, dump[\"rgw\"][\"get_initial_lat.sum\"], epsilon)\n\trequire.InDelta(t, float64(0), dump[\"rgw\"][\"put_initial_lat.avgcount\"], testutil.DefaultDelta)\n}\n\nfunc TestDecodeStatus(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\terr := decodeStatus(acc, clusterStatusDump)\n\trequire.NoError(t, err)\n\n\tfor _, r := range cephStatusResults {\n\t\tacc.AssertContainsTaggedFields(t, r.metric, r.fields, r.tags)\n\t}\n}\nfunc TestDecodeStatusNestedOSD(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\terr := decodeStatus(acc, clusterStatusDumpNestedOSD)\n\trequire.NoError(t, err)\n\n\tfor _, r := range cephStatusResultsNestedOSD {\n\t\tacc.AssertContainsTaggedFields(t, r.metric, r.fields, r.tags)\n\t}\n}\n\nfunc TestDecodeDf(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\terr := decodeDf(acc, cephDFDump)\n\trequire.NoError(t, err)\n\n\tfor _, r := range cephDfResults {\n\t\tacc.AssertContainsTaggedFields(t, r.metric, r.fields, r.tags)\n\t}\n}\n\nfunc TestDecodeOSDPoolStats(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\terr := decodeOsdPoolStats(acc, cephODSPoolStatsDump)\n\trequire.NoError(t, err)\n\n\tfor _, r := range cephOSDPoolStatsResults {\n\t\tacc.AssertContainsTaggedFields(t, r.metric, r.fields, r.tags)\n\t}\n}\n\nfunc TestGather(t *testing.T) {\n\tsaveFind := findSockets\n\tsaveDump := perfDump\n\tdefer func() {\n\t\tfindSockets = saveFind\n\t\tperfDump = saveDump\n\t}()\n\n\tfindSockets = func(*Ceph) ([]*socket, error) {\n\t\treturn []*socket{{\"osd.1\", typeOsd, \"\"}}, nil\n\t}\n\n\tperfDump = func(string, *socket) (string, error) {\n\t\treturn osdPerfDump, nil\n\t}\n\n\tacc := &testutil.Accumulator{}\n\tc := &Ceph{}\n\trequire.NoError(t, c.Gather(acc))\n}\n\nfunc TestParseSchema(t *testing.T) {\n\tschemaMap, err := parseSchema(osdRawSchema)\n\n\trequire.NoError(t, err)\n\t// Test Gauge\n\trequire.Equal(t, telegraf.Counter, schemaMap[\"osd\"][\"op\"],\n\t\t\"op should be a Counter\")\n\t// Test Counter\n\trequire.Equal(t, telegraf.Gauge, schemaMap[\"osd\"][\"op_wip\"],\n\t\t\"op_wip should be a Gauge\")\n\t// Test LongRunAvg\n\trequire.Equal(t, telegraf.Counter, schemaMap[\"osd\"][\"op_latency.avgcount\"],\n\t\t\"op_latency.avgcount should be a Counter\")\n\trequire.Equal(t, telegraf.Counter, schemaMap[\"osd\"][\"op_latency.sum\"],\n\t\t\"op_latency.sum should be a Counter\")\n\trequire.Equal(t, telegraf.Gauge, schemaMap[\"osd\"][\"op_latency.avgtime\"],\n\t\t\"op_latency.avgtime should be a Gauge\")\n}\n\nfunc TestFindSockets(t *testing.T) {\n\ttmpdir := t.TempDir()\n\tc := &Ceph{\n\t\tCephBinary:             \"foo\",\n\t\tOsdPrefix:              \"ceph-osd\",\n\t\tMonPrefix:              \"ceph-mon\",\n\t\tMdsPrefix:              \"ceph-mds\",\n\t\tRgwPrefix:              \"ceph-client\",\n\t\tSocketDir:              tmpdir,\n\t\tSocketSuffix:           \"asok\",\n\t\tCephUser:               \"client.admin\",\n\t\tCephConfig:             \"/etc/ceph/ceph.conf\",\n\t\tGatherAdminSocketStats: true,\n\t\tGatherClusterStats:     false,\n\t}\n\n\tfor _, st := range sockTestParams {\n\t\trequire.NoError(t, createTestFiles(tmpdir, st))\n\n\t\tsockets, err := findSockets(c)\n\t\trequire.NoError(t, err)\n\n\t\tfor i := 1; i <= st.osds; i++ {\n\t\t\tassertFoundSocket(t, tmpdir, typeOsd, i, sockets)\n\t\t}\n\n\t\tfor i := 1; i <= st.mons; i++ {\n\t\t\tassertFoundSocket(t, tmpdir, typeMon, i, sockets)\n\t\t}\n\t\tfor i := 1; i <= st.mdss; i++ {\n\t\t\tassertFoundSocket(t, tmpdir, typeMds, i, sockets)\n\t\t}\n\t\tfor i := 1; i <= st.rgws; i++ {\n\t\t\tassertFoundSocket(t, tmpdir, typeRgw, i, sockets)\n\t\t}\n\t\trequire.NoError(t, cleanupTestFiles(tmpdir, st))\n\t}\n}\n\nfunc assertFoundSocket(t *testing.T, dir, sockType string, i int, sockets []*socket) {\n\tvar prefix string\n\tif sockType == typeOsd {\n\t\tprefix = osdPrefix\n\t} else if sockType == typeMds {\n\t\tprefix = mdsPrefix\n\t} else if sockType == typeRgw {\n\t\tprefix = rgwPrefix\n\t} else {\n\t\tprefix = monPrefix\n\t}\n\texpected := filepath.Join(dir, sockFile(prefix, i))\n\tfound := false\n\tfor _, s := range sockets {\n\t\tfmt.Printf(\"Checking %s\\n\", s.socket)\n\t\tif s.socket == expected {\n\t\t\tfound = true\n\t\t\trequire.Equal(t, s.sockType, sockType, \"Unexpected socket type for %q\", s)\n\t\t\trequire.Equal(t, s.sockID, strconv.Itoa(i))\n\t\t}\n\t}\n\trequire.True(t, found, \"Did not find socket: %s\", expected)\n}\n\nfunc sockFile(prefix string, i int) string {\n\treturn strings.Join([]string{prefix, strconv.Itoa(i), sockSuffix}, \".\")\n}\n\nfunc createTestFiles(dir string, st *SockTest) error {\n\twriteFile := func(prefix string, i int) error {\n\t\tf := sockFile(prefix, i)\n\t\tfpath := filepath.Join(dir, f)\n\t\treturn os.WriteFile(fpath, []byte(\"\"), 0640)\n\t}\n\treturn tstFileApply(st, writeFile)\n}\n\nfunc cleanupTestFiles(dir string, st *SockTest) error {\n\trmFile := func(prefix string, i int) error {\n\t\tf := sockFile(prefix, i)\n\t\tfpath := filepath.Join(dir, f)\n\t\treturn os.Remove(fpath)\n\t}\n\treturn tstFileApply(st, rmFile)\n}\n\nfunc tstFileApply(st *SockTest, fn func(string, int) error) error {\n\tfor i := 1; i <= st.osds; i++ {\n\t\tif err := fn(osdPrefix, i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := 1; i <= st.mons; i++ {\n\t\tif err := fn(monPrefix, i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := 1; i <= st.mdss; i++ {\n\t\tif err := fn(mdsPrefix, i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := 1; i <= st.rgws; i++ {\n\t\tif err := fn(rgwPrefix, i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\ntype SockTest struct {\n\tosds int\n\tmons int\n\tmdss int\n\trgws int\n}\n\nvar sockTestParams = []*SockTest{\n\t{\n\t\tosds: 2,\n\t\tmons: 2,\n\t\tmdss: 2,\n\t\trgws: 2,\n\t},\n\t{\n\t\tmons: 1,\n\t},\n\t{\n\t\tosds: 1,\n\t},\n\t{\n\t\tmdss: 1,\n\t},\n\t{\n\t\trgws: 1,\n\t},\n\t{},\n}\n\nvar monPerfDump = `\n{ \"cluster\": { \"num_mon\": 2,\n      \"num_mon_quorum\": 2,\n      \"num_osd\": 26,\n      \"num_osd_up\": 26,\n      \"num_osd_in\": 26,\n      \"osd_epoch\": 3306,\n      \"osd_kb\": 11487846448,\n      \"osd_kb_used\": 5678670180,\n      \"osd_kb_avail\": 5809176268,\n      \"num_pool\": 12,\n      \"num_pg\": 768,\n      \"num_pg_active_clean\": 768,\n      \"num_pg_active\": 768,\n      \"num_pg_peering\": 0,\n      \"num_object\": 397616,\n      \"num_object_degraded\": 0,\n      \"num_object_unfound\": 0,\n      \"num_bytes\": 2917848227467,\n      \"num_mds_up\": 0,\n      \"num_mds_in\": 0,\n      \"num_mds_failed\": 0,\n      \"mds_epoch\": 1},\n  \"leveldb\": { \"leveldb_get\": 321950312,\n      \"leveldb_transaction\": 18729922,\n      \"leveldb_compact\": 0,\n      \"leveldb_compact_range\": 74141,\n      \"leveldb_compact_queue_merge\": 0,\n      \"leveldb_compact_queue_len\": 0},\n  \"mon\": {},\n  \"paxos\": { \"start_leader\": 0,\n      \"start_peon\": 1,\n      \"restart\": 4,\n      \"refresh\": 9363435,\n      \"refresh_latency\": { \"avgcount\": 9363435,\n          \"sum\": 5378.794002000},\n      \"begin\": 9363435,\n      \"begin_keys\": { \"avgcount\": 0,\n          \"sum\": 0},\n      \"begin_bytes\": { \"avgcount\": 9363435,\n          \"sum\": 110468605489},\n      \"begin_latency\": { \"avgcount\": 9363435,\n          \"sum\": 5850.060682000},\n      \"commit\": 9363435,\n      \"commit_keys\": { \"avgcount\": 0,\n          \"sum\": 0},\n      \"commit_bytes\": { \"avgcount\": 0,\n          \"sum\": 0},\n      \"commit_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"collect\": 1,\n      \"collect_keys\": { \"avgcount\": 1,\n          \"sum\": 1},\n      \"collect_bytes\": { \"avgcount\": 1,\n          \"sum\": 24},\n      \"collect_latency\": { \"avgcount\": 1,\n          \"sum\": 0.000280000},\n      \"collect_uncommitted\": 0,\n      \"collect_timeout\": 0,\n      \"accept_timeout\": 0,\n      \"lease_ack_timeout\": 0,\n      \"lease_timeout\": 0,\n      \"store_state\": 9363435,\n      \"store_state_keys\": { \"avgcount\": 9363435,\n          \"sum\": 176572789},\n      \"store_state_bytes\": { \"avgcount\": 9363435,\n          \"sum\": 216355887217},\n      \"store_state_latency\": { \"avgcount\": 9363435,\n          \"sum\": 6866.540527000},\n      \"share_state\": 0,\n      \"share_state_keys\": { \"avgcount\": 0,\n          \"sum\": 0},\n      \"share_state_bytes\": { \"avgcount\": 0,\n          \"sum\": 0},\n      \"new_pn\": 0,\n      \"new_pn_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-mon_client_bytes\": { \"val\": 246,\n      \"max\": 104857600,\n      \"get\": 896030,\n      \"get_sum\": 45854374,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 896026,\n      \"put_sum\": 45854128,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-mon_daemon_bytes\": { \"val\": 0,\n      \"max\": 419430400,\n      \"get\": 2773768,\n      \"get_sum\": 3627676976,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 2773768,\n      \"put_sum\": 3627676976,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-mon\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 34504949,\n      \"get_sum\": 226860281124,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 34504949,\n      \"put_sum\": 226860281124,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}}}\n`\n\nvar osdPerfDump = `\n{ \"WBThrottle\": { \"bytes_dirtied\": 28405539,\n      \"bytes_wb\": 0,\n      \"ios_dirtied\": 93,\n      \"ios_wb\": 0,\n      \"inodes_dirtied\": 86,\n      \"inodes_wb\": 0},\n  \"filestore\": { \"journal_queue_max_ops\": 0,\n      \"journal_queue_ops\": 0,\n      \"journal_ops\": 1108008,\n      \"journal_queue_max_bytes\": 0,\n      \"journal_queue_bytes\": 0,\n      \"journal_bytes\": 73233416196,\n      \"journal_latency\": { \"avgcount\": 1108008,\n          \"sum\": 290.981036000},\n      \"journal_wr\": 1091866,\n      \"journal_wr_bytes\": { \"avgcount\": 1091866,\n          \"sum\": 74925682688},\n      \"journal_full\": 0,\n      \"committing\": 0,\n      \"commitcycle\": 110389,\n      \"commitcycle_interval\": { \"avgcount\": 110389,\n          \"sum\": 552132.109360000},\n      \"commitcycle_latency\": { \"avgcount\": 110389,\n          \"sum\": 178.657804000},\n      \"op_queue_max_ops\": 50,\n      \"op_queue_ops\": 0,\n      \"ops\": 1108008,\n      \"op_queue_max_bytes\": 104857600,\n      \"op_queue_bytes\": 0,\n      \"bytes\": 73226768148,\n      \"apply_latency\": { \"avgcount\": 1108008,\n          \"sum\": 947.742722000},\n      \"queue_transaction_latency_avg\": { \"avgcount\": 1108008,\n          \"sum\": 0.511327000}},\n  \"leveldb\": { \"leveldb_get\": 4361221,\n      \"leveldb_transaction\": 4351276,\n      \"leveldb_compact\": 0,\n      \"leveldb_compact_range\": 0,\n      \"leveldb_compact_queue_merge\": 0,\n      \"leveldb_compact_queue_len\": 0},\n  \"mutex-FileJournal::completions_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-FileJournal::finisher_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-FileJournal::write_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-FileJournal::writeq_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-JOS::ApplyManager::apply_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-JOS::ApplyManager::com_lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-JOS::SubmitManager::lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"mutex-WBThrottle::lock\": { \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"objecter\": { \"op_active\": 0,\n      \"op_laggy\": 0,\n      \"op_send\": 0,\n      \"op_send_bytes\": 0,\n      \"op_resend\": 0,\n      \"op_ack\": 0,\n      \"op_commit\": 0,\n      \"op\": 0,\n      \"op_r\": 0,\n      \"op_w\": 0,\n      \"op_rmw\": 0,\n      \"op_pg\": 0,\n      \"osdop_stat\": 0,\n      \"osdop_create\": 0,\n      \"osdop_read\": 0,\n      \"osdop_write\": 0,\n      \"osdop_writefull\": 0,\n      \"osdop_append\": 0,\n      \"osdop_zero\": 0,\n      \"osdop_truncate\": 0,\n      \"osdop_delete\": 0,\n      \"osdop_mapext\": 0,\n      \"osdop_sparse_read\": 0,\n      \"osdop_clonerange\": 0,\n      \"osdop_getxattr\": 0,\n      \"osdop_setxattr\": 0,\n      \"osdop_cmpxattr\": 0,\n      \"osdop_rmxattr\": 0,\n      \"osdop_resetxattrs\": 0,\n      \"osdop_tmap_up\": 0,\n      \"osdop_tmap_put\": 0,\n      \"osdop_tmap_get\": 0,\n      \"osdop_call\": 0,\n      \"osdop_watch\": 0,\n      \"osdop_notify\": 0,\n      \"osdop_src_cmpxattr\": 0,\n      \"osdop_pgls\": 0,\n      \"osdop_pgls_filter\": 0,\n      \"osdop_other\": 0,\n      \"linger_active\": 0,\n      \"linger_send\": 0,\n      \"linger_resend\": 0,\n      \"poolop_active\": 0,\n      \"poolop_send\": 0,\n      \"poolop_resend\": 0,\n      \"poolstat_active\": 0,\n      \"poolstat_send\": 0,\n      \"poolstat_resend\": 0,\n      \"statfs_active\": 0,\n      \"statfs_send\": 0,\n      \"statfs_resend\": 0,\n      \"command_active\": 0,\n      \"command_send\": 0,\n      \"command_resend\": 0,\n      \"map_epoch\": 3300,\n      \"map_full\": 0,\n      \"map_inc\": 3293,\n      \"osd_sessions\": 0,\n      \"osd_session_open\": 0,\n      \"osd_session_close\": 0,\n      \"osd_laggy\": 0},\n  \"osd\": { \"opq\": 0,\n      \"op_wip\": 0,\n      \"op\": 23939,\n      \"op_in_bytes\": 1245903961,\n      \"op_out_bytes\": 29103083856,\n      \"op_latency\": { \"avgcount\": 23939,\n          \"sum\": 440.192015000},\n      \"op_process_latency\": { \"avgcount\": 23939,\n          \"sum\": 30.170685000},\n      \"op_r\": 23112,\n      \"op_r_out_bytes\": 29103056146,\n      \"op_r_latency\": { \"avgcount\": 23112,\n          \"sum\": 19.373526000},\n      \"op_r_process_latency\": { \"avgcount\": 23112,\n          \"sum\": 14.625928000},\n      \"op_w\": 549,\n      \"op_w_in_bytes\": 1245804358,\n      \"op_w_rlat\": { \"avgcount\": 549,\n          \"sum\": 17.022299000},\n      \"op_w_latency\": { \"avgcount\": 549,\n          \"sum\": 418.494610000},\n      \"op_w_process_latency\": { \"avgcount\": 549,\n          \"sum\": 13.316555000},\n      \"op_rw\": 278,\n      \"op_rw_in_bytes\": 99603,\n      \"op_rw_out_bytes\": 27710,\n      \"op_rw_rlat\": { \"avgcount\": 278,\n          \"sum\": 2.213785000},\n      \"op_rw_latency\": { \"avgcount\": 278,\n          \"sum\": 2.323879000},\n      \"op_rw_process_latency\": { \"avgcount\": 278,\n          \"sum\": 2.228202000},\n      \"subop\": 1074774,\n      \"subop_in_bytes\": 26841811636,\n      \"subop_latency\": { \"avgcount\": 1074774,\n          \"sum\": 745.509160000},\n      \"subop_w\": 0,\n      \"subop_w_in_bytes\": 26841811636,\n      \"subop_w_latency\": { \"avgcount\": 1074774,\n          \"sum\": 745.509160000},\n      \"subop_pull\": 0,\n      \"subop_pull_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"subop_push\": 0,\n      \"subop_push_in_bytes\": 0,\n      \"subop_push_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"pull\": 0,\n      \"push\": 28,\n      \"push_out_bytes\": 103483392,\n      \"push_in\": 0,\n      \"push_in_bytes\": 0,\n      \"recovery_ops\": 15,\n      \"loadavg\": 202,\n      \"buffer_bytes\": 0,\n      \"numpg\": 18,\n      \"numpg_primary\": 8,\n      \"numpg_replica\": 10,\n      \"numpg_stray\": 0,\n      \"heartbeat_to_peers\": 10,\n      \"heartbeat_from_peers\": 0,\n      \"map_messages\": 7413,\n      \"map_message_epochs\": 9792,\n      \"map_message_epoch_dups\": 10105,\n      \"messages_delayed_for_map\": 83,\n      \"stat_bytes\": 102123175936,\n      \"stat_bytes_used\": 49961820160,\n      \"stat_bytes_avail\": 52161355776,\n      \"copyfrom\": 0,\n      \"tier_promote\": 0,\n      \"tier_flush\": 0,\n      \"tier_flush_fail\": 0,\n      \"tier_try_flush\": 0,\n      \"tier_try_flush_fail\": 0,\n      \"tier_evict\": 0,\n      \"tier_whiteout\": 0,\n      \"tier_dirty\": 230,\n      \"tier_clean\": 0,\n      \"tier_delay\": 0,\n      \"agent_wake\": 0,\n      \"agent_skip\": 0,\n      \"agent_flush\": 0,\n      \"agent_evict\": 0},\n  \"recoverystate_perf\": { \"initial_latency\": { \"avgcount\": 473,\n          \"sum\": 0.027207000},\n      \"started_latency\": { \"avgcount\": 1480,\n          \"sum\": 9854902.397648000},\n      \"reset_latency\": { \"avgcount\": 1953,\n          \"sum\": 0.096206000},\n      \"start_latency\": { \"avgcount\": 1953,\n          \"sum\": 0.059947000},\n      \"primary_latency\": { \"avgcount\": 765,\n          \"sum\": 4688922.186935000},\n      \"peering_latency\": { \"avgcount\": 704,\n          \"sum\": 1668.652135000},\n      \"backfilling_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"waitremotebackfillreserved_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"waitlocalbackfillreserved_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"notbackfilling_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"repnotrecovering_latency\": { \"avgcount\": 462,\n          \"sum\": 5158922.114600000},\n      \"repwaitrecoveryreserved_latency\": { \"avgcount\": 15,\n          \"sum\": 0.008275000},\n      \"repwaitbackfillreserved_latency\": { \"avgcount\": 1,\n          \"sum\": 0.000095000},\n      \"RepRecovering_latency\": { \"avgcount\": 16,\n          \"sum\": 2274.944727000},\n      \"activating_latency\": { \"avgcount\": 514,\n          \"sum\": 261.008520000},\n      \"waitlocalrecoveryreserved_latency\": { \"avgcount\": 20,\n          \"sum\": 0.175422000},\n      \"waitremoterecoveryreserved_latency\": { \"avgcount\": 20,\n          \"sum\": 0.682778000},\n      \"recovering_latency\": { \"avgcount\": 20,\n          \"sum\": 0.697551000},\n      \"recovered_latency\": { \"avgcount\": 511,\n          \"sum\": 0.011038000},\n      \"clean_latency\": { \"avgcount\": 503,\n          \"sum\": 4686961.154278000},\n      \"active_latency\": { \"avgcount\": 506,\n          \"sum\": 4687223.640464000},\n      \"replicaactive_latency\": { \"avgcount\": 446,\n          \"sum\": 5161197.078966000},\n      \"stray_latency\": { \"avgcount\": 794,\n          \"sum\": 4805.105128000},\n      \"getinfo_latency\": { \"avgcount\": 704,\n          \"sum\": 1138.477937000},\n      \"getlog_latency\": { \"avgcount\": 678,\n          \"sum\": 0.036393000},\n      \"waitactingchange_latency\": { \"avgcount\": 69,\n          \"sum\": 59.172893000},\n      \"incomplete_latency\": { \"avgcount\": 0,\n          \"sum\": 0.000000000},\n      \"getmissing_latency\": { \"avgcount\": 609,\n          \"sum\": 0.012288000},\n      \"waitupthru_latency\": { \"avgcount\": 576,\n          \"sum\": 530.106999000}},\n  \"throttle-filestore_bytes\": { \"val\": 0,\n      \"max\": 0,\n      \"get\": 0,\n      \"get_sum\": 0,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 0,\n      \"put_sum\": 0,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-filestore_ops\": { \"val\": 0,\n      \"max\": 0,\n      \"get\": 0,\n      \"get_sum\": 0,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 0,\n      \"put_sum\": 0,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-client\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 130730,\n      \"get_sum\": 1246039872,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 130730,\n      \"put_sum\": 1246039872,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-cluster\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 1108033,\n      \"get_sum\": 71277949992,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 1108033,\n      \"put_sum\": 71277949992,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-hb_back_server\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 18320575,\n      \"get_sum\": 861067025,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 18320575,\n      \"put_sum\": 861067025,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-hb_front_server\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 18320575,\n      \"get_sum\": 861067025,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 18320575,\n      \"put_sum\": 861067025,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-hbclient\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 40479394,\n      \"get_sum\": 1902531518,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 40479394,\n      \"put_sum\": 1902531518,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-msgr_dispatch_throttler-ms_objecter\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 0,\n      \"get_sum\": 0,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 0,\n      \"put_sum\": 0,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-objecter_bytes\": { \"val\": 0,\n      \"max\": 104857600,\n      \"get\": 0,\n      \"get_sum\": 0,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 0,\n      \"put_sum\": 0,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-objecter_ops\": { \"val\": 0,\n      \"max\": 1024,\n      \"get\": 0,\n      \"get_sum\": 0,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 0,\n      \"put_sum\": 0,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-osd_client_bytes\": { \"val\": 0,\n      \"max\": 524288000,\n      \"get\": 24241,\n      \"get_sum\": 1241992581,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 25958,\n      \"put_sum\": 1241992581,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}},\n  \"throttle-osd_client_messages\": { \"val\": 0,\n      \"max\": 100,\n      \"get\": 49214,\n      \"get_sum\": 49214,\n      \"get_or_fail_fail\": 0,\n      \"get_or_fail_success\": 0,\n      \"take\": 0,\n      \"take_sum\": 0,\n      \"put\": 49214,\n      \"put_sum\": 49214,\n      \"wait\": { \"avgcount\": 0,\n          \"sum\": 0.000000000}}}\n`\n\nvar mdsPerfDump = `\n{\n    \"AsyncMessenger::Worker-0\": {\n        \"msgr_recv_messages\": 2723536628,\n        \"msgr_send_messages\": 1160771414,\n        \"msgr_recv_bytes\": 1112936719134,\n        \"msgr_send_bytes\": 1368194904867,\n        \"msgr_created_connections\": 18281,\n        \"msgr_active_connections\": 83,\n        \"msgr_running_total_time\": 109001.938705141,\n        \"msgr_running_send_time\": 33686.215323581,\n        \"msgr_running_recv_time\": 8374950.111041426,\n        \"msgr_running_fast_dispatch_time\": 5828.083761243\n    },\n    \"AsyncMessenger::Worker-1\": {\n        \"msgr_recv_messages\": 1426105165,\n        \"msgr_send_messages\": 783174767,\n        \"msgr_recv_bytes\": 800620150187,\n        \"msgr_send_bytes\": 1394738277392,\n        \"msgr_created_connections\": 17677,\n        \"msgr_active_connections\": 100,\n        \"msgr_running_total_time\": 70660.929329800,\n        \"msgr_running_send_time\": 24190.940207198,\n        \"msgr_running_recv_time\": 3920894.209204916,\n        \"msgr_running_fast_dispatch_time\": 8206.816536602\n    },\n    \"AsyncMessenger::Worker-2\": {\n        \"msgr_recv_messages\": 3471200310,\n        \"msgr_send_messages\": 2757725529,\n        \"msgr_recv_bytes\": 1331676471794,\n        \"msgr_send_bytes\": 2593968875674,\n        \"msgr_created_connections\": 16714,\n        \"msgr_active_connections\": 73,\n        \"msgr_running_total_time\": 167020.893916556,\n        \"msgr_running_send_time\": 61197.682840176,\n        \"msgr_running_recv_time\": 5816036.495319415,\n        \"msgr_running_fast_dispatch_time\": 8581.768789481\n    },\n    \"finisher-PurgeQueue\": {\n        \"queue_len\": 0,\n        \"complete_latency\": {\n            \"avgcount\": 20170260,\n            \"sum\": 70213.859039869,\n            \"avgtime\": 0.003481058\n        }\n    },\n    \"mds\": {\n        \"request\": 2167457412,\n        \"reply\": 2167457403,\n        \"reply_latency\": {\n            \"avgcount\": 2167457403,\n            \"sum\": 2408386.600934982,\n            \"avgtime\": 0.001111157\n        },\n        \"forward\": 0,\n        \"dir_fetch\": 585012985,\n        \"dir_commit\": 58926158,\n        \"dir_split\": 8,\n        \"dir_merge\": 7,\n        \"inode_max\": 2147483647,\n        \"inodes\": 39604287,\n        \"inodes_top\": 9743493,\n        \"inodes_bottom\": 29063656,\n        \"inodes_pin_tail\": 797138,\n        \"inodes_pinned\": 25685011,\n        \"inodes_expired\": 1302542128,\n        \"inodes_with_caps\": 4517329,\n        \"caps\": 6370838,\n        \"subtrees\": 2,\n        \"traverse\": 2426357623,\n        \"traverse_hit\": 2202314009,\n        \"traverse_forward\": 0,\n        \"traverse_discover\": 0,\n        \"traverse_dir_fetch\": 35332112,\n        \"traverse_remote_ino\": 0,\n        \"traverse_lock\": 4371557,\n        \"load_cent\": 1966748,\n        \"q\": 976,\n        \"exported\": 0,\n        \"exported_inodes\": 0,\n        \"imported\": 0,\n        \"imported_inodes\": 0,\n        \"openino_dir_fetch\": 22725418,\n        \"openino_backtrace_fetch\": 6,\n        \"openino_peer_discover\": 0\n    },\n    \"mds_cache\": {\n        \"num_strays\": 384,\n        \"num_strays_delayed\": 0,\n        \"num_strays_enqueuing\": 0,\n        \"strays_created\": 29140050,\n        \"strays_enqueued\": 29134399,\n        \"strays_reintegrated\": 10171,\n        \"strays_migrated\": 0,\n        \"num_recovering_processing\": 0,\n        \"num_recovering_enqueued\": 0,\n        \"num_recovering_prioritized\": 0,\n        \"recovery_started\": 229,\n        \"recovery_completed\": 229,\n        \"ireq_enqueue_scrub\": 0,\n        \"ireq_exportdir\": 0,\n        \"ireq_flush\": 0,\n        \"ireq_fragmentdir\": 15,\n        \"ireq_fragstats\": 0,\n        \"ireq_inodestats\": 0\n    },\n    \"mds_log\": {\n        \"evadd\": 1920368707,\n        \"evex\": 1920372003,\n        \"evtrm\": 1920372003,\n        \"ev\": 106627,\n        \"evexg\": 0,\n        \"evexd\": 4369,\n        \"segadd\": 2247990,\n        \"segex\": 2247995,\n        \"segtrm\": 2247995,\n        \"seg\": 123,\n        \"segexg\": 0,\n        \"segexd\": 5,\n        \"expos\": 24852063335817,\n        \"wrpos\": 24852205446582,\n        \"rdpos\": 22044255640175,\n        \"jlat\": {\n            \"avgcount\": 182241259,\n            \"sum\": 1732094.198366820,\n            \"avgtime\": 0.009504402\n        },\n        \"replayed\": 109923\n    },\n    \"mds_mem\": {\n        \"ino\": 39604292,\n        \"ino+\": 1307214891,\n        \"ino-\": 1267610599,\n        \"dir\": 22827008,\n        \"dir+\": 591593031,\n        \"dir-\": 568766023,\n        \"dn\": 39604761,\n        \"dn+\": 1376976677,\n        \"dn-\": 1337371916,\n        \"cap\": 6370838,\n        \"cap+\": 1720930015,\n        \"cap-\": 1714559177,\n        \"rss\": 167723320,\n        \"heap\": 322260,\n        \"buf\": 0\n    },\n    \"mds_server\": {\n        \"dispatch_client_request\": 2932764331,\n        \"dispatch_server_request\": 0,\n        \"handle_client_request\": 2167457412,\n        \"handle_client_session\": 10929454,\n        \"handle_slave_request\": 0,\n        \"req_create_latency\": {\n            \"avgcount\": 30590326,\n            \"sum\": 23887.274170412,\n            \"avgtime\": 0.000780876\n        },\n        \"req_getattr_latency\": {\n            \"avgcount\": 124767480,\n            \"sum\": 718160.497644305,\n            \"avgtime\": 0.005755991\n        },\n        \"req_getfilelock_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_link_latency\": {\n            \"avgcount\": 5636,\n            \"sum\": 2.371499732,\n            \"avgtime\": 0.000420777\n        },\n        \"req_lookup_latency\": {\n            \"avgcount\": 474590034,\n            \"sum\": 452548.849373476,\n            \"avgtime\": 0.000953557\n        },\n        \"req_lookuphash_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_lookupino_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_lookupname_latency\": {\n            \"avgcount\": 9794,\n            \"sum\": 54.118496591,\n            \"avgtime\": 0.005525678\n        },\n        \"req_lookupparent_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_lookupsnap_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_lssnap_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_mkdir_latency\": {\n            \"avgcount\": 13394317,\n            \"sum\": 13025.982105531,\n            \"avgtime\": 0.000972500\n        },\n        \"req_mknod_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_mksnap_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_open_latency\": {\n            \"avgcount\": 32849768,\n            \"sum\": 12862.382994977,\n            \"avgtime\": 0.000391551\n        },\n        \"req_readdir_latency\": {\n            \"avgcount\": 654394394,\n            \"sum\": 715669.609601541,\n            \"avgtime\": 0.001093636\n        },\n        \"req_rename_latency\": {\n            \"avgcount\": 6058807,\n            \"sum\": 2126.232719555,\n            \"avgtime\": 0.000350932\n        },\n        \"req_renamesnap_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_rmdir_latency\": {\n            \"avgcount\": 1901530,\n            \"sum\": 4064.121157858,\n            \"avgtime\": 0.002137290\n        },\n        \"req_rmsnap_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_rmxattr_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_setattr_latency\": {\n            \"avgcount\": 37051209,\n            \"sum\": 171198.037329531,\n            \"avgtime\": 0.004620578\n        },\n        \"req_setdirlayout_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_setfilelock_latency\": {\n            \"avgcount\": 765439143,\n            \"sum\": 262660.582883819,\n            \"avgtime\": 0.000343150\n        },\n        \"req_setlayout_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"req_setxattr_latency\": {\n            \"avgcount\": 41572,\n            \"sum\": 7.273371375,\n            \"avgtime\": 0.000174958\n        },\n        \"req_symlink_latency\": {\n            \"avgcount\": 329,\n            \"sum\": 0.117859965,\n            \"avgtime\": 0.000358236\n        },\n        \"req_unlink_latency\": {\n            \"avgcount\": 26363064,\n            \"sum\": 32119.149726314,\n            \"avgtime\": 0.001218339\n        },\n        \"cap_revoke_eviction\": 0\n    },\n    \"mds_sessions\": {\n        \"session_count\": 80,\n        \"session_add\": 90,\n        \"session_remove\": 10,\n        \"sessions_open\": 80,\n        \"sessions_stale\": 0,\n        \"total_load\": 112490,\n        \"average_load\": 1406,\n        \"avg_session_uptime\": 2221807\n    },\n    \"objecter\": {\n        \"op_active\": 0,\n        \"op_laggy\": 0,\n        \"op_send\": 955060080,\n        \"op_send_bytes\": 3178832110019,\n        \"op_resend\": 67,\n        \"op_reply\": 955060013,\n        \"op\": 955060013,\n        \"op_r\": 585982837,\n        \"op_w\": 369077176,\n        \"op_rmw\": 0,\n        \"op_pg\": 0,\n        \"osdop_stat\": 45924375,\n        \"osdop_create\": 31162274,\n        \"osdop_read\": 969513,\n        \"osdop_write\": 183211164,\n        \"osdop_writefull\": 1063233,\n        \"osdop_writesame\": 0,\n        \"osdop_append\": 0,\n        \"osdop_zero\": 2,\n        \"osdop_truncate\": 8,\n        \"osdop_delete\": 60594735,\n        \"osdop_mapext\": 0,\n        \"osdop_sparse_read\": 0,\n        \"osdop_clonerange\": 0,\n        \"osdop_getxattr\": 584941886,\n        \"osdop_setxattr\": 62324548,\n        \"osdop_cmpxattr\": 0,\n        \"osdop_rmxattr\": 0,\n        \"osdop_resetxattrs\": 0,\n        \"osdop_tmap_up\": 0,\n        \"osdop_tmap_put\": 0,\n        \"osdop_tmap_get\": 0,\n        \"osdop_call\": 0,\n        \"osdop_watch\": 0,\n        \"osdop_notify\": 0,\n        \"osdop_src_cmpxattr\": 0,\n        \"osdop_pgls\": 0,\n        \"osdop_pgls_filter\": 0,\n        \"osdop_other\": 32053182,\n        \"linger_active\": 0,\n        \"linger_send\": 0,\n        \"linger_resend\": 0,\n        \"linger_ping\": 0,\n        \"poolop_active\": 0,\n        \"poolop_send\": 0,\n        \"poolop_resend\": 0,\n        \"poolstat_active\": 0,\n        \"poolstat_send\": 0,\n        \"poolstat_resend\": 0,\n        \"statfs_active\": 0,\n        \"statfs_send\": 0,\n        \"statfs_resend\": 0,\n        \"command_active\": 0,\n        \"command_send\": 0,\n        \"command_resend\": 0,\n        \"map_epoch\": 66793,\n        \"map_full\": 0,\n        \"map_inc\": 1762,\n        \"osd_sessions\": 120,\n        \"osd_session_open\": 52554,\n        \"osd_session_close\": 52434,\n        \"osd_laggy\": 0,\n        \"omap_wr\": 106692727,\n        \"omap_rd\": 1170026044,\n        \"omap_del\": 5674762\n    },\n    \"purge_queue\": {\n        \"pq_executing_ops\": 0,\n        \"pq_executing\": 0,\n        \"pq_executed\": 29134399\n    },\n    \"throttle-msgr_dispatch_throttler-mds\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 7620842095,\n        \"get_sum\": 2681291022887,\n        \"get_or_fail_fail\": 53,\n        \"get_or_fail_success\": 7620842095,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 7620842095,\n        \"put_sum\": 2681291022887,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_bytes\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 0,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 0,\n        \"take\": 955060013,\n        \"take_sum\": 3172776432475,\n        \"put\": 862340641,\n        \"put_sum\": 3172776432475,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_ops\": {\n        \"val\": 0,\n        \"max\": 1024,\n        \"get_started\": 0,\n        \"get\": 0,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 0,\n        \"take\": 955060013,\n        \"take_sum\": 955060013,\n        \"put\": 955060013,\n        \"put_sum\": 955060013,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-write_buf_throttle\": {\n        \"val\": 0,\n        \"max\": 3758096384,\n        \"get_started\": 0,\n        \"get\": 29134399,\n        \"get_sum\": 3160498139,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 29134399,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 969905,\n        \"put_sum\": 3160498139,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-write_buf_throttle-0x561894f0b8e0\": {\n        \"val\": 286270,\n        \"max\": 3758096384,\n        \"get_started\": 0,\n        \"get\": 1920368707,\n        \"get_sum\": 2807949805409,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 1920368707,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 182241259,\n        \"put_sum\": 2807949519139,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    }\n}\n`\n\nvar rgwPerfDump = `\n{\n    \"AsyncMessenger::Worker-0\": {\n        \"msgr_recv_messages\": 10684185,\n        \"msgr_send_messages\": 13448962,\n        \"msgr_recv_bytes\": 2622531258,\n        \"msgr_send_bytes\": 4195038384,\n        \"msgr_created_connections\": 8029,\n        \"msgr_active_connections\": 3,\n        \"msgr_running_total_time\": 3249.441108544,\n        \"msgr_running_send_time\": 739.821446096,\n        \"msgr_running_recv_time\": 310.354319110,\n        \"msgr_running_fast_dispatch_time\": 1915.410317430\n    },\n    \"AsyncMessenger::Worker-1\": {\n        \"msgr_recv_messages\": 2137773,\n        \"msgr_send_messages\": 3850070,\n        \"msgr_recv_bytes\": 503824366,\n        \"msgr_send_bytes\": 1130107261,\n        \"msgr_created_connections\": 11030,\n        \"msgr_active_connections\": 1,\n        \"msgr_running_total_time\": 445.055291782,\n        \"msgr_running_send_time\": 227.817750758,\n        \"msgr_running_recv_time\": 78.974093226,\n        \"msgr_running_fast_dispatch_time\": 47.587740615\n    },\n    \"AsyncMessenger::Worker-2\": {\n        \"msgr_recv_messages\": 2809014,\n        \"msgr_send_messages\": 4126613,\n        \"msgr_recv_bytes\": 653093470,\n        \"msgr_send_bytes\": 1022041970,\n        \"msgr_created_connections\": 14810,\n        \"msgr_active_connections\": 5,\n        \"msgr_running_total_time\": 453.384703728,\n        \"msgr_running_send_time\": 208.580910390,\n        \"msgr_running_recv_time\": 80.075306670,\n        \"msgr_running_fast_dispatch_time\": 46.854112208\n    },\n    \"cct\": {\n        \"total_workers\": 0,\n        \"unhealthy_workers\": 0\n    },\n    \"finisher-radosclient\": {\n        \"queue_len\": 0,\n        \"complete_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"finisher-radosclient-0x55994098e460\": {\n        \"queue_len\": 0,\n        \"complete_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"finisher-radosclient-0x5599409901c0\": {\n        \"queue_len\": 0,\n        \"complete_latency\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"mempool\": {\n        \"bloom_filter_bytes\": 0,\n        \"bloom_filter_items\": 0,\n        \"bluestore_alloc_bytes\": 0,\n        \"bluestore_alloc_items\": 0,\n        \"bluestore_cache_data_bytes\": 0,\n        \"bluestore_cache_data_items\": 0,\n        \"bluestore_cache_onode_bytes\": 0,\n        \"bluestore_cache_onode_items\": 0,\n        \"bluestore_cache_other_bytes\": 0,\n        \"bluestore_cache_other_items\": 0,\n        \"bluestore_fsck_bytes\": 0,\n        \"bluestore_fsck_items\": 0,\n        \"bluestore_txc_bytes\": 0,\n        \"bluestore_txc_items\": 0,\n        \"bluestore_writing_deferred_bytes\": 0,\n        \"bluestore_writing_deferred_items\": 0,\n        \"bluestore_writing_bytes\": 0,\n        \"bluestore_writing_items\": 0,\n        \"bluefs_bytes\": 0,\n        \"bluefs_items\": 0,\n        \"buffer_anon_bytes\": 258469,\n        \"buffer_anon_items\": 201,\n        \"buffer_meta_bytes\": 0,\n        \"buffer_meta_items\": 0,\n        \"osd_bytes\": 0,\n        \"osd_items\": 0,\n        \"osd_mapbl_bytes\": 0,\n        \"osd_mapbl_items\": 0,\n        \"osd_pglog_bytes\": 0,\n        \"osd_pglog_items\": 0,\n        \"osdmap_bytes\": 74448,\n        \"osdmap_items\": 732,\n        \"osdmap_mapping_bytes\": 0,\n        \"osdmap_mapping_items\": 0,\n        \"pgmap_bytes\": 0,\n        \"pgmap_items\": 0,\n        \"mds_co_bytes\": 0,\n        \"mds_co_items\": 0,\n        \"unittest_1_bytes\": 0,\n        \"unittest_1_items\": 0,\n        \"unittest_2_bytes\": 0,\n        \"unittest_2_items\": 0\n    },\n    \"objecter\": {\n        \"op_active\": 0,\n        \"op_laggy\": 0,\n        \"op_send\": 9377910,\n        \"op_send_bytes\": 312,\n        \"op_resend\": 0,\n        \"op_reply\": 9377904,\n        \"op\": 9377910,\n        \"op_r\": 2755291,\n        \"op_w\": 6622619,\n        \"op_rmw\": 0,\n        \"op_pg\": 0,\n        \"osdop_stat\": 2755258,\n        \"osdop_create\": 8,\n        \"osdop_read\": 25,\n        \"osdop_write\": 0,\n        \"osdop_writefull\": 0,\n        \"osdop_writesame\": 0,\n        \"osdop_append\": 0,\n        \"osdop_zero\": 0,\n        \"osdop_truncate\": 0,\n        \"osdop_delete\": 0,\n        \"osdop_mapext\": 0,\n        \"osdop_sparse_read\": 0,\n        \"osdop_clonerange\": 0,\n        \"osdop_getxattr\": 0,\n        \"osdop_setxattr\": 0,\n        \"osdop_cmpxattr\": 0,\n        \"osdop_rmxattr\": 0,\n        \"osdop_resetxattrs\": 0,\n        \"osdop_call\": 0,\n        \"osdop_watch\": 6622611,\n        \"osdop_notify\": 0,\n        \"osdop_src_cmpxattr\": 0,\n        \"osdop_pgls\": 0,\n        \"osdop_pgls_filter\": 0,\n        \"osdop_other\": 2755266,\n        \"linger_active\": 8,\n        \"linger_send\": 35,\n        \"linger_resend\": 27,\n        \"linger_ping\": 6622576,\n        \"poolop_active\": 0,\n        \"poolop_send\": 0,\n        \"poolop_resend\": 0,\n        \"poolstat_active\": 0,\n        \"poolstat_send\": 0,\n        \"poolstat_resend\": 0,\n        \"statfs_active\": 0,\n        \"statfs_send\": 0,\n        \"statfs_resend\": 0,\n        \"command_active\": 0,\n        \"command_send\": 0,\n        \"command_resend\": 0,\n        \"map_epoch\": 1064,\n        \"map_full\": 0,\n        \"map_inc\": 106,\n        \"osd_sessions\": 8,\n        \"osd_session_open\": 11928,\n        \"osd_session_close\": 11920,\n        \"osd_laggy\": 5,\n        \"omap_wr\": 0,\n        \"omap_rd\": 0,\n        \"omap_del\": 0\n    },\n    \"objecter-0x55994098e500\": {\n        \"op_active\": 0,\n        \"op_laggy\": 0,\n        \"op_send\": 827839,\n        \"op_send_bytes\": 0,\n        \"op_resend\": 0,\n        \"op_reply\": 827839,\n        \"op\": 827839,\n        \"op_r\": 0,\n        \"op_w\": 827839,\n        \"op_rmw\": 0,\n        \"op_pg\": 0,\n        \"osdop_stat\": 0,\n        \"osdop_create\": 0,\n        \"osdop_read\": 0,\n        \"osdop_write\": 0,\n        \"osdop_writefull\": 0,\n        \"osdop_writesame\": 0,\n        \"osdop_append\": 0,\n        \"osdop_zero\": 0,\n        \"osdop_truncate\": 0,\n        \"osdop_delete\": 0,\n        \"osdop_mapext\": 0,\n        \"osdop_sparse_read\": 0,\n        \"osdop_clonerange\": 0,\n        \"osdop_getxattr\": 0,\n        \"osdop_setxattr\": 0,\n        \"osdop_cmpxattr\": 0,\n        \"osdop_rmxattr\": 0,\n        \"osdop_resetxattrs\": 0,\n        \"osdop_call\": 0,\n        \"osdop_watch\": 827839,\n        \"osdop_notify\": 0,\n        \"osdop_src_cmpxattr\": 0,\n        \"osdop_pgls\": 0,\n        \"osdop_pgls_filter\": 0,\n        \"osdop_other\": 0,\n        \"linger_active\": 1,\n        \"linger_send\": 3,\n        \"linger_resend\": 2,\n        \"linger_ping\": 827836,\n        \"poolop_active\": 0,\n        \"poolop_send\": 0,\n        \"poolop_resend\": 0,\n        \"poolstat_active\": 0,\n        \"poolstat_send\": 0,\n        \"poolstat_resend\": 0,\n        \"statfs_active\": 0,\n        \"statfs_send\": 0,\n        \"statfs_resend\": 0,\n        \"command_active\": 0,\n        \"command_send\": 0,\n        \"command_resend\": 0,\n        \"map_epoch\": 1064,\n        \"map_full\": 0,\n        \"map_inc\": 106,\n        \"osd_sessions\": 1,\n        \"osd_session_open\": 1,\n        \"osd_session_close\": 0,\n        \"osd_laggy\": 1,\n        \"omap_wr\": 0,\n        \"omap_rd\": 0,\n        \"omap_del\": 0\n    },\n    \"objecter-0x55994098f720\": {\n        \"op_active\": 0,\n        \"op_laggy\": 0,\n        \"op_send\": 5415951,\n        \"op_send_bytes\": 205291238,\n        \"op_resend\": 8,\n        \"op_reply\": 5415943,\n        \"op\": 5415943,\n        \"op_r\": 3612105,\n        \"op_w\": 1803838,\n        \"op_rmw\": 0,\n        \"op_pg\": 0,\n        \"osdop_stat\": 0,\n        \"osdop_create\": 0,\n        \"osdop_read\": 0,\n        \"osdop_write\": 0,\n        \"osdop_writefull\": 0,\n        \"osdop_writesame\": 0,\n        \"osdop_append\": 0,\n        \"osdop_zero\": 0,\n        \"osdop_truncate\": 0,\n        \"osdop_delete\": 0,\n        \"osdop_mapext\": 0,\n        \"osdop_sparse_read\": 0,\n        \"osdop_clonerange\": 0,\n        \"osdop_getxattr\": 0,\n        \"osdop_setxattr\": 0,\n        \"osdop_cmpxattr\": 0,\n        \"osdop_rmxattr\": 0,\n        \"osdop_resetxattrs\": 0,\n        \"osdop_call\": 5415567,\n        \"osdop_watch\": 0,\n        \"osdop_notify\": 0,\n        \"osdop_src_cmpxattr\": 0,\n        \"osdop_pgls\": 0,\n        \"osdop_pgls_filter\": 0,\n        \"osdop_other\": 376,\n        \"linger_active\": 0,\n        \"linger_send\": 0,\n        \"linger_resend\": 0,\n        \"linger_ping\": 0,\n        \"poolop_active\": 0,\n        \"poolop_send\": 0,\n        \"poolop_resend\": 0,\n        \"poolstat_active\": 0,\n        \"poolstat_send\": 0,\n        \"poolstat_resend\": 0,\n        \"statfs_active\": 0,\n        \"statfs_send\": 0,\n        \"statfs_resend\": 0,\n        \"command_active\": 0,\n        \"command_send\": 0,\n        \"command_resend\": 0,\n        \"map_epoch\": 1064,\n        \"map_full\": 0,\n        \"map_inc\": 106,\n        \"osd_sessions\": 8,\n        \"osd_session_open\": 8834,\n        \"osd_session_close\": 8826,\n        \"osd_laggy\": 0,\n        \"omap_wr\": 0,\n        \"omap_rd\": 0,\n        \"omap_del\": 0\n    },\n    \"rgw\": {\n        \"req\": 2755258,\n        \"failed_req\": 0,\n        \"get\": 0,\n        \"get_b\": 0,\n        \"get_initial_lat\": {\n            \"avgcount\": 0,\n            \"sum\": 0.002219876,\n            \"avgtime\": 0.000000000\n        },\n        \"put\": 0,\n        \"put_b\": 0,\n        \"put_initial_lat\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        },\n        \"qlen\": 0,\n        \"qactive\": 0,\n        \"cache_hit\": 0,\n        \"cache_miss\": 2755261,\n        \"keystone_token_cache_hit\": 0,\n        \"keystone_token_cache_miss\": 0,\n        \"gc_retire_object\": 0,\n        \"pubsub_event_triggered\": 0,\n        \"pubsub_event_lost\": 0,\n        \"pubsub_store_ok\": 0,\n        \"pubsub_store_fail\": 0,\n        \"pubsub_events\": 0,\n        \"pubsub_push_ok\": 0,\n        \"pubsub_push_failed\": 0,\n        \"pubsub_push_pending\": 0\n    },\n    \"simple-throttler\": {\n        \"throttle\": 0\n    },\n    \"throttle-msgr_dispatch_throttler-radosclient\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 9379775,\n        \"get_sum\": 1545393284,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 9379775,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 9379775,\n        \"put_sum\": 1545393284,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-msgr_dispatch_throttler-radosclient-0x55994098e320\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 829631,\n        \"get_sum\": 162850310,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 829631,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 829631,\n        \"put_sum\": 162850310,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-msgr_dispatch_throttler-radosclient-0x55994098fa40\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 5421553,\n        \"get_sum\": 914508527,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 5421553,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 5421553,\n        \"put_sum\": 914508527,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_bytes\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 2755292,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 2755292,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 0,\n        \"put_sum\": 0,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_bytes-0x55994098e780\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 0,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 0,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 0,\n        \"put_sum\": 0,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_bytes-0x55994098f7c0\": {\n        \"val\": 0,\n        \"max\": 104857600,\n        \"get_started\": 0,\n        \"get\": 5415614,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 5415614,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 0,\n        \"put_sum\": 0,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_ops\": {\n        \"val\": 0,\n        \"max\": 24576,\n        \"get_started\": 0,\n        \"get\": 2755292,\n        \"get_sum\": 2755292,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 2755292,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 2755292,\n        \"put_sum\": 2755292,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_ops-0x55994098e640\": {\n        \"val\": 0,\n        \"max\": 24576,\n        \"get_started\": 0,\n        \"get\": 0,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 0,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 0,\n        \"put_sum\": 0,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-objecter_ops-0x55994098f0e0\": {\n        \"val\": 0,\n        \"max\": 24576,\n        \"get_started\": 0,\n        \"get\": 5415614,\n        \"get_sum\": 5415614,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 5415614,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 5415614,\n        \"put_sum\": 5415614,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    },\n    \"throttle-rgw_async_rados_ops\": {\n        \"val\": 0,\n        \"max\": 64,\n        \"get_started\": 0,\n        \"get\": 0,\n        \"get_sum\": 0,\n        \"get_or_fail_fail\": 0,\n        \"get_or_fail_success\": 0,\n        \"take\": 0,\n        \"take_sum\": 0,\n        \"put\": 0,\n        \"put_sum\": 0,\n        \"wait\": {\n            \"avgcount\": 0,\n            \"sum\": 0.000000000,\n            \"avgtime\": 0.000000000\n        }\n    }\n}\n`\nvar osdRawSchema = `\n{    \"osd\": {\n        \"op_wip\": {\n            \"type\": 2,\n            \"metric_type\": \"gauge\",\n            \"value_type\": \"integer\",\n            \"description\": \"Replication operations currently being processed (primary)\",\n            \"nick\": \"\",\n            \"priority\": 5,\n            \"units\": \"none\"\n        },\n        \"op\": {\n            \"type\": 10,\n            \"metric_type\": \"counter\",\n            \"value_type\": \"integer\",\n            \"description\": \"Client operations\",\n            \"nick\": \"ops\",\n            \"priority\": 10,\n            \"units\": \"none\"\n        },\n        \"op_in_bytes\": {\n            \"type\": 10,\n            \"metric_type\": \"counter\",\n            \"value_type\": \"integer\",\n            \"description\": \"Client operations total write size\",\n            \"nick\": \"wr\",\n            \"priority\": 8,\n            \"units\": \"bytes\"\n        },\n        \"op_out_bytes\": {\n            \"type\": 10,\n            \"metric_type\": \"counter\",\n            \"value_type\": \"integer\",\n            \"description\": \"Client operations total read size\",\n            \"nick\": \"rd\",\n            \"priority\": 8,\n            \"units\": \"bytes\"\n        },\n        \"op_latency\": {\n\t    \"type\": 5,\n            \"metric_type\": \"gauge\",\n            \"value_type\": \"real-integer-pair\",\n            \"description\": \"Latency of client operations (including queue time)\",\n            \"nick\": \"l\",\n            \"priority\": 9,\n            \"units\": \"none\"\n        },\n        \"op_process_latency\": {\n            \"type\": 5,\n            \"metric_type\": \"gauge\",\n            \"value_type\": \"real-integer-pair\",\n            \"description\": \"Latency of client operations (excluding queue time)\",\n            \"nick\": \"\",\n            \"priority\": 5,\n            \"units\": \"none\"\n        },\n        \"op_prepare_latency\": {\n            \"type\": 5,\n            \"metric_type\": \"gauge\",\n            \"value_type\": \"real-integer-pair\",\n            \"description\": \"Latency of client operations (excluding queue time and wait for finished)\",\n            \"nick\": \"\",\n            \"priority\": 5,\n            \"units\": \"none\"\n        }\n}\n}\n`\n\nvar clusterStatusDump = `\n{\n    \"health\": {\n        \"status\": \"HEALTH_OK\",\n        \"checks\": {},\n        \"mutes\": []\n    },\n    \"fsid\": \"01234567-abcd-9876-0123-ffeeddccbbaa\",\n    \"election_epoch\": 504,\n    \"quorum\": [\n        0,\n        1,\n        2\n    ],\n    \"quorum_names\": [\n        \"a\",\n        \"b\",\n        \"c\"\n    ],\n    \"monmap\": {\n        \"epoch\": 27,\n        \"min_mon_release_name\": \"pacific\",\n        \"num_mons\": 3\n    },\n    \"osdmap\": {\n        \"epoch\": 21734,\n        \"num_osds\": 24,\n        \"num_up_osds\": 24,\n        \"osd_up_since\": 1646008974,\n        \"num_in_osds\": 24,\n        \"osd_in_since\": 1637261831,\n        \"num_remapped_pgs\": 0\n    },\n    \"pgmap\": {\n        \"pgs_by_state\": [\n            {\n                \"state_name\": \"active+clean\",\n                \"count\": 2560\n            },\n            {\n                \"state_name\": \"active+scrubbing\",\n                \"count\": 10\n            },\n            {\n                \"state_name\": \"active+backfilling\",\n                \"count\": 5\n            }\n        ],\n        \"version\": 52314277,\n        \"num_pgs\": 2560,\n        \"num_pools\": 4,\n        \"num_objects\": 974827,\n        \"data_bytes\": 2700031960713,\n        \"bytes_used\": 7478347665408,\n        \"bytes_avail\": 9857462382592,\n        \"bytes_total\": 17335810048000,\n        \"inactive_pgs_ratio\": 0.19742488861083984,\n        \"degraded_objects\": 25919,\n        \"degraded_total\": 2920050,\n        \"degraded_ratio\": 0.008876217872981627,\n        \"recovering_objects_per_sec\": 6,\n        \"recovering_bytes_per_sec\": 223303,\n        \"recovering_keys_per_sec\": 10,\n        \"num_objects_recovered\": 40,\n        \"num_bytes_recovered\": 1335808,\n        \"num_keys_recovered\": 64,\n        \"read_bytes_sec\": 0,\n        \"write_bytes_sec\": 367217,\n        \"read_op_per_sec\": 322,\n        \"write_op_per_sec\": 1022\n    },\n    \"mdsmap\": {\n        \"epoch\": 1,\n        \"up\": 0,\n        \"in\": 0,\n        \"max\": 0,\n        \"by_rank\": []\n    },\n    \"fsmap\": {\n        \"epoch\": 24756,\n        \"id\": 4,\n        \"up\": 1,\n        \"in\": 1,\n        \"max\": 1,\n        \"by_rank\": [\n            {\n                \"filesystem_id\": 4,\n                \"rank\": 0,\n                \"name\": \"a\",\n                \"status\": \"up:active\",\n                \"gid\": 83585495\n            }\n        ],\n        \"up:standby\": 2\n    },\n    \"mgrmap\": {\n        \"available\": true,\n        \"num_standbys\": 2,\n        \"modules\": [\n            \"dashboard\",\n            \"iostat\",\n            \"restful\",\n            \"stats\"\n        ],\n        \"services\": {\n            \"dashboard\": \"https://192.168.0.1:8443/\"\n        }\n    },\n    \"servicemap\": {\n        \"epoch\": 219919,\n        \"modified\": \"2022-03-07T13:52:42.430153-0500\",\n        \"services\": {}\n    },\n    \"progress_events\": {}\n}\n`\n\nvar cephStatusResults = []expectedResult{\n\t{\n\t\tmetric: \"ceph_fsmap\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"in\":         float64(1),\n\t\t\t\"max\":        float64(1),\n\t\t\t\"up_standby\": float64(2),\n\t\t\t\"up\":         float64(1),\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_health\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"overall_status\": \"\",\n\t\t\t\"status_code\":    float64(2),\n\t\t\t\"status\":         \"HEALTH_OK\",\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_monmap\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"num_mons\": float64(3),\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_osdmap\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"epoch\":            float64(21734),\n\t\t\t\"num_in_osds\":      float64(24),\n\t\t\t\"num_osds\":         float64(24),\n\t\t\t\"num_remapped_pgs\": float64(0),\n\t\t\t\"num_up_osds\":      float64(24),\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_pgmap\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"bytes_avail\":                float64(9857462382592),\n\t\t\t\"bytes_total\":                float64(17335810048000),\n\t\t\t\"bytes_used\":                 float64(7478347665408),\n\t\t\t\"data_bytes\":                 float64(2700031960713),\n\t\t\t\"degraded_objects\":           float64(25919),\n\t\t\t\"degraded_ratio\":             float64(0.0088762178729816267),\n\t\t\t\"degraded_total\":             float64(2920050),\n\t\t\t\"inactive_pgs_ratio\":         float64(0.19742488861083984),\n\t\t\t\"num_bytes_recovered\":        float64(1335808),\n\t\t\t\"num_keys_recovered\":         float64(64),\n\t\t\t\"num_objects_recovered\":      float64(40),\n\t\t\t\"num_objects\":                float64(974827),\n\t\t\t\"num_pgs\":                    float64(2560),\n\t\t\t\"num_pools\":                  float64(4),\n\t\t\t\"op_per_sec\":                 float64(0), // exists only in ceph <10\n\t\t\t\"read_bytes_sec\":             float64(0),\n\t\t\t\"read_op_per_sec\":            float64(322),\n\t\t\t\"recovering_bytes_per_sec\":   float64(223303),\n\t\t\t\"recovering_keys_per_sec\":    float64(10),\n\t\t\t\"recovering_objects_per_sec\": float64(6),\n\t\t\t\"version\":                    float64(52314277),\n\t\t\t\"write_bytes_sec\":            float64(367217),\n\t\t\t\"write_op_per_sec\":           float64(1022),\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_pgmap_state\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"count\": float64(2560),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"state\": \"active+clean\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pgmap_state\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"count\": float64(10),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"state\": \"active+scrubbing\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pgmap_state\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"count\": float64(5),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"state\": \"active+backfilling\",\n\t\t},\n\t},\n}\n\nvar clusterStatusDumpNestedOSD = `\n{\n    \"health\": {\n        \"status\": \"HEALTH_OK\",\n        \"checks\": {},\n        \"mutes\": []\n    },\n    \"fsid\": \"01234567-abcd-9876-0123-ffeeddccbbaa\",\n    \"election_epoch\": 504,\n    \"quorum\": [\n        0,\n        1,\n        2\n    ],\n    \"quorum_names\": [\n        \"a\",\n        \"b\",\n        \"c\"\n    ],\n    \"monmap\": {\n        \"epoch\": 27,\n        \"min_mon_release_name\": \"pacific\",\n        \"num_mons\": 3\n    },\n    \"osdmap\": {\n        \"osdmap\": {\n            \"epoch\": 21734,\n            \"num_osds\": 24,\n            \"num_up_osds\": 24,\n            \"osd_up_since\": 1646008974,\n            \"num_in_osds\": 24,\n            \"osd_in_since\": 1637261831,\n            \"num_remapped_pgs\": 0\n        }\n    },\n    \"pgmap\": {\n        \"pgs_by_state\": [\n            {\n                \"state_name\": \"active+clean\",\n                \"count\": 2560\n            },\n            {\n                \"state_name\": \"active+scrubbing\",\n                \"count\": 10\n            },\n            {\n                \"state_name\": \"active+backfilling\",\n                \"count\": 5\n            }\n        ],\n        \"version\": 52314277,\n        \"num_pgs\": 2560,\n        \"num_pools\": 4,\n        \"num_objects\": 974827,\n        \"data_bytes\": 2700031960713,\n        \"bytes_used\": 7478347665408,\n        \"bytes_avail\": 9857462382592,\n        \"bytes_total\": 17335810048000,\n        \"inactive_pgs_ratio\": 0.19742488861083984,\n        \"degraded_objects\": 25919,\n        \"degraded_total\": 2920050,\n        \"degraded_ratio\": 0.008876217872981627,\n        \"recovering_objects_per_sec\": 6,\n        \"recovering_bytes_per_sec\": 223303,\n        \"recovering_keys_per_sec\": 10,\n        \"num_objects_recovered\": 40,\n        \"num_bytes_recovered\": 1335808,\n        \"num_keys_recovered\": 64,\n        \"read_bytes_sec\": 0,\n        \"write_bytes_sec\": 367217,\n        \"read_op_per_sec\": 322,\n        \"write_op_per_sec\": 1022\n    },\n    \"mdsmap\": {\n        \"epoch\": 1,\n        \"up\": 0,\n        \"in\": 0,\n        \"max\": 0,\n        \"by_rank\": []\n    },\n    \"fsmap\": {\n        \"epoch\": 24756,\n        \"id\": 4,\n        \"up\": 1,\n        \"in\": 1,\n        \"max\": 1,\n        \"by_rank\": [\n            {\n                \"filesystem_id\": 4,\n                \"rank\": 0,\n                \"name\": \"a\",\n                \"status\": \"up:active\",\n                \"gid\": 83585495\n            }\n        ],\n        \"up:standby\": 2\n    },\n    \"mgrmap\": {\n        \"available\": true,\n        \"num_standbys\": 2,\n        \"modules\": [\n            \"dashboard\",\n            \"iostat\",\n            \"restful\",\n            \"stats\"\n        ],\n        \"services\": {\n            \"dashboard\": \"https://192.168.0.1:8443/\"\n        }\n    },\n    \"servicemap\": {\n        \"epoch\": 219919,\n        \"modified\": \"2022-03-07T13:52:42.430153-0500\",\n        \"services\": {}\n    },\n    \"progress_events\": {}\n}\n`\n\nvar cephStatusResultsNestedOSD = []expectedResult{\n\t{\n\t\tmetric: \"ceph_osdmap\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"epoch\":            float64(21734),\n\t\t\t\"full\":             false,\n\t\t\t\"nearfull\":         false,\n\t\t\t\"num_in_osds\":      float64(24),\n\t\t\t\"num_osds\":         float64(24),\n\t\t\t\"num_remapped_pgs\": float64(0),\n\t\t\t\"num_up_osds\":      float64(24),\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n}\n\nvar cephDFDump = `\n{\n    \"stats\": {\n        \"total_bytes\": 14882929901568,\n        \"total_avail_bytes\": 7866135064576,\n        \"total_used_bytes\": 7016794836992,\n        \"total_used_raw_bytes\": 7016794836992,\n        \"total_used_raw_ratio\": 0.47146594524383545,\n        \"num_osds\": 6,\n        \"num_per_pool_osds\": 6,\n        \"num_per_pool_omap_osds\": 6\n    },\n    \"stats_by_class\": {\n        \"hdd\": {\n            \"total_bytes\": 12002349023232,\n            \"total_avail_bytes\": 6080040206336,\n            \"total_used_bytes\": 5922308816896,\n            \"total_used_raw_bytes\": 5922308816896,\n            \"total_used_raw_ratio\": 0.49342915415763855\n        },\n        \"ssd\": {\n            \"total_bytes\": 2880580878336,\n            \"total_avail_bytes\": 1786094858240,\n            \"total_used_bytes\": 1094486020096,\n            \"total_used_raw_bytes\": 1094486020096,\n            \"total_used_raw_ratio\": 0.3799532353878021\n        }\n    },\n    \"pools\": [\n        {\n            \"name\": \"foo\",\n            \"id\": 4,\n            \"stats\": {\n                \"stored\": 672914410122,\n                \"objects\": 161029,\n                \"kb_used\": 1972149256,\n                \"bytes_used\": 2019480838046,\n                \"percent_used\": 0.2692900002002716,\n                \"max_avail\": 1826599337984\n            }\n        },\n        {\n            \"name\": \"bar_metadata\",\n            \"id\": 12,\n            \"stats\": {\n                \"stored\": 1486436928,\n                \"objects\": 88452,\n                \"kb_used\": 4354883,\n                \"bytes_used\": 4459399953,\n                \"percent_used\": 0.0027088995557278395,\n                \"max_avail\": 547248046080\n            }\n        },\n        {\n            \"name\": \"bar_data\",\n            \"id\": 13,\n            \"stats\": {\n                \"stored\": 1291824398336,\n                \"objects\": 522694,\n                \"kb_used\": 3800912960,\n                \"bytes_used\": 3892134871040,\n                \"percent_used\": 0.41529691219329834,\n                \"max_avail\": 1826599337984\n            }\n        },\n        {\n            \"name\": \"device_health_metrics\",\n            \"id\": 17,\n            \"stats\": {\n                \"stored\": 42634584,\n                \"objects\": 9,\n                \"kb_used\": 83271,\n                \"bytes_used\": 85269164,\n                \"percent_used\": 0.000012548729500849731,\n                \"max_avail\": 3397479301120\n            }\n        }\n    ]\n}\n`\n\nvar cephDfResults = []expectedResult{\n\t{\n\t\tmetric: \"ceph_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"num_osds\":               float64(6),\n\t\t\t\"num_per_pool_omap_osds\": float64(6),\n\t\t\t\"num_per_pool_osds\":      float64(6),\n\t\t\t\"total_avail_bytes\":      float64(7866135064576),\n\t\t\t\"total_avail\":            float64(0), // pre ceph 0.84\n\t\t\t\"total_bytes\":            float64(14882929901568),\n\t\t\t\"total_space\":            float64(0), // pre ceph 0.84\n\t\t\t\"total_used_bytes\":       float64(7016794836992),\n\t\t\t\"total_used_raw_bytes\":   float64(7016794836992),\n\t\t\t\"total_used_raw_ratio\":   float64(0.47146594524383545),\n\t\t\t\"total_used\":             float64(0), // pre ceph 0.84\n\t\t},\n\t\ttags: map[string]string{},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"bytes_used\":   float64(2019480838046),\n\t\t\t\"kb_used\":      float64(1972149256),\n\t\t\t\"max_avail\":    float64(1826599337984),\n\t\t\t\"objects\":      float64(161029),\n\t\t\t\"percent_used\": float64(0.26929000020027161),\n\t\t\t\"stored\":       float64(672914410122),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"foo\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"bytes_used\":   float64(4459399953),\n\t\t\t\"kb_used\":      float64(4354883),\n\t\t\t\"max_avail\":    float64(547248046080),\n\t\t\t\"objects\":      float64(88452),\n\t\t\t\"percent_used\": float64(0.0027088995557278395),\n\t\t\t\"stored\":       float64(1486436928),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"bar_metadata\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"bytes_used\":   float64(3892134871040),\n\t\t\t\"kb_used\":      float64(3800912960),\n\t\t\t\"max_avail\":    float64(1826599337984),\n\t\t\t\"objects\":      float64(522694),\n\t\t\t\"percent_used\": float64(0.41529691219329834),\n\t\t\t\"stored\":       float64(1291824398336),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"bar_data\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"bytes_used\":   float64(85269164),\n\t\t\t\"kb_used\":      float64(83271),\n\t\t\t\"max_avail\":    float64(3397479301120),\n\t\t\t\"objects\":      float64(9),\n\t\t\t\"percent_used\": float64(0.000012548729500849731),\n\t\t\t\"stored\":       float64(42634584),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"device_health_metrics\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_deviceclass_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"total_avail_bytes\":    float64(6080040206336),\n\t\t\t\"total_bytes\":          float64(12002349023232),\n\t\t\t\"total_used_bytes\":     float64(5922308816896),\n\t\t\t\"total_used_raw_bytes\": float64(5922308816896),\n\t\t\t\"total_used_raw_ratio\": float64(0.49342915415763855),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"class\": \"hdd\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_deviceclass_usage\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"total_avail_bytes\":    float64(1786094858240),\n\t\t\t\"total_bytes\":          float64(2880580878336),\n\t\t\t\"total_used_bytes\":     float64(1094486020096),\n\t\t\t\"total_used_raw_bytes\": float64(1094486020096),\n\t\t\t\"total_used_raw_ratio\": float64(0.3799532353878021),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"class\": \"ssd\",\n\t\t},\n\t},\n}\n\nvar cephODSPoolStatsDump = `\n[\n    {\n        \"pool_name\": \"data\",\n        \"pool_id\": 0,\n        \"recovery\": {\n            \"degraded_objects\": 12,\n            \"degraded_total\": 483087,\n            \"degraded_ratio\": 0.000024840246166839513\n        },\n        \"recovery_rate\": {},\n        \"client_io_rate\": {}\n    },\n    {\n        \"pool_name\": \"metadata\",\n        \"pool_id\": 1,\n        \"recovery\": {},\n        \"recovery_rate\": {},\n        \"client_io_rate\": {}\n    },\n    {\n        \"pool_name\": \"rbd\",\n        \"pool_id\": 2,\n        \"recovery\": {},\n        \"recovery_rate\": {},\n        \"client_io_rate\": {}\n    },\n    {\n        \"pool_name\": \"pbench\",\n        \"pool_id\": 3,\n        \"recovery\": {},\n        \"recovery_rate\": {\n            \"recovering_objects_per_sec\": 16,\n            \"recovering_bytes_per_sec\": 0,\n            \"recovering_keys_per_sec\": 0,\n            \"num_objects_recovered\": 200,\n            \"num_bytes_recovered\": 0,\n            \"num_keys_recovered\": 0\n        },\n        \"client_io_rate\": {\n            \"read_bytes_sec\": 10566067,\n            \"write_bytes_sec\": 15165220376,\n            \"read_op_per_sec\": 182,\n            \"write_op_per_sec\": 473\n        }\n    }\n]\n`\n\nvar cephOSDPoolStatsResults = []expectedResult{\n\t{\n\t\tmetric: \"ceph_pool_stats\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"degraded_objects\":           float64(12),\n\t\t\t\"degraded_ratio\":             float64(0.000024840246166839513),\n\t\t\t\"degraded_total\":             float64(483087),\n\t\t\t\"num_bytes_recovered\":        float64(0),\n\t\t\t\"num_keys_recovered\":         float64(0),\n\t\t\t\"num_objects_recovered\":      float64(0),\n\t\t\t\"op_per_sec\":                 float64(0), // This field is no longer reported in ceph 10 and later\n\t\t\t\"read_bytes_sec\":             float64(0),\n\t\t\t\"read_op_per_sec\":            float64(0),\n\t\t\t\"recovering_bytes_per_sec\":   float64(0),\n\t\t\t\"recovering_keys_per_sec\":    float64(0),\n\t\t\t\"recovering_objects_per_sec\": float64(0),\n\t\t\t\"write_bytes_sec\":            float64(0),\n\t\t\t\"write_op_per_sec\":           float64(0),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"data\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_stats\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"degraded_objects\":           float64(0),\n\t\t\t\"degraded_ratio\":             float64(0),\n\t\t\t\"degraded_total\":             float64(0),\n\t\t\t\"num_bytes_recovered\":        float64(0),\n\t\t\t\"num_keys_recovered\":         float64(0),\n\t\t\t\"num_objects_recovered\":      float64(0),\n\t\t\t\"op_per_sec\":                 float64(0), // This field is no longer reported in ceph 10 and later\n\t\t\t\"read_bytes_sec\":             float64(0),\n\t\t\t\"read_op_per_sec\":            float64(0),\n\t\t\t\"recovering_bytes_per_sec\":   float64(0),\n\t\t\t\"recovering_keys_per_sec\":    float64(0),\n\t\t\t\"recovering_objects_per_sec\": float64(0),\n\t\t\t\"write_bytes_sec\":            float64(0),\n\t\t\t\"write_op_per_sec\":           float64(0),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"metadata\",\n\t\t},\n\t},\n\t{\n\t\tmetric: \"ceph_pool_stats\",\n\t\tfields: map[string]interface{}{\n\t\t\t\"degraded_objects\":           float64(0),\n\t\t\t\"degraded_ratio\":             float64(0),\n\t\t\t\"degraded_total\":             float64(0),\n\t\t\t\"num_bytes_recovered\":        float64(0),\n\t\t\t\"num_keys_recovered\":         float64(0),\n\t\t\t\"num_objects_recovered\":      float64(200),\n\t\t\t\"op_per_sec\":                 float64(0), // This field is no longer reported in ceph 10 and later\n\t\t\t\"read_bytes_sec\":             float64(10566067),\n\t\t\t\"read_op_per_sec\":            float64(182),\n\t\t\t\"recovering_bytes_per_sec\":   float64(0),\n\t\t\t\"recovering_keys_per_sec\":    float64(0),\n\t\t\t\"recovering_objects_per_sec\": float64(16),\n\t\t\t\"write_bytes_sec\":            float64(15165220376),\n\t\t\t\"write_op_per_sec\":           float64(473),\n\t\t},\n\t\ttags: map[string]string{\n\t\t\t\"name\": \"pbench\",\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "plugins/inputs/ceph/sample.conf",
    "content": "# Collects performance metrics from the MON, OSD, MDS and RGW nodes\n# in a Ceph storage cluster.\n[[inputs.ceph]]\n  ## This is the recommended interval to poll. Too frequent and you\n  ## will lose data points due to timeouts during rebalancing and recovery\n  interval = '1m'\n\n  ## All configuration values are optional, defaults are shown below\n\n  ## location of ceph binary\n  ceph_binary = \"/usr/bin/ceph\"\n\n  ## directory in which to look for socket files\n  socket_dir = \"/var/run/ceph\"\n\n  ## prefix of MON and OSD socket files, used to determine socket type\n  mon_prefix = \"ceph-mon\"\n  osd_prefix = \"ceph-osd\"\n  mds_prefix = \"ceph-mds\"\n  rgw_prefix = \"ceph-client\"\n\n  ## suffix used to identify socket files\n  socket_suffix = \"asok\"\n\n  ## Ceph user to authenticate as, ceph will search for the corresponding\n  ## keyring e.g. client.admin.keyring in /etc/ceph, or the explicit path\n  ## defined in the client section of ceph.conf for example:\n  ##\n  ##     [client.telegraf]\n  ##         keyring = /etc/ceph/client.telegraf.keyring\n  ##\n  ## Consult the ceph documentation for more detail on keyring generation.\n  ceph_user = \"client.admin\"\n\n  ## Ceph configuration to use to locate the cluster\n  ceph_config = \"/etc/ceph/ceph.conf\"\n\n  ## Whether to gather statistics via the admin socket\n  gather_admin_socket_stats = true\n\n  ## Whether to gather statistics via ceph commands, requires ceph_user\n  ## and ceph_config to be specified\n  gather_cluster_stats = false\n"
  },
  {
    "path": "plugins/inputs/cgroup/README.md",
    "content": "# Control Group Input Plugin\n\nThis plugin gathers statistics per [control group (cgroup)][cgroup].\n\n> [!NOTE]\n> Consider restricting paths to the set of cgroups you are interested in if you\n> have a large number of cgroups, to avoid cardinality issues.\n\nThe plugin supports the _single value format_ in the form\n\n```text\nVAL\\n\n```\n\nthe _new line separated values format_ in the form\n\n```text\nVAL0\\n\nVAL1\\n\n```\n\nthe _space separated values format_ in the form\n\n```text\nVAL0 VAL1 ...\\n\n```\n\nand the _space separated keys and value, separated by new line format_ in the\nform\n\n```text\nKEY0 ... VAL0\\n\nKEY1 ... VAL1\\n\n```\n\n⭐ Telegraf v1.0.0\n🏷️ system\n💻 linux\n\n[cgroup]: https://docs.kernel.org/admin-guide/cgroup-v2.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read specific statistics per cgroup\n# This plugin ONLY supports Linux\n[[inputs.cgroup]]\n  ## Directories in which to look for files, globs are supported.\n  ## Consider restricting paths to the set of cgroups you really\n  ## want to monitor if you have a large number of cgroups, to avoid\n  ## any cardinality issues.\n  # paths = [\n  #   \"/sys/fs/cgroup/memory\",\n  #   \"/sys/fs/cgroup/memory/child1\",\n  #   \"/sys/fs/cgroup/memory/child2/*\",\n  # ]\n  ## cgroup stat fields, as file names, globs are supported.\n  ## these file names are appended to each path from above.\n  # files = [\"memory.*usage*\", \"memory.limit_in_bytes\"]\n```\n\n## Metrics\n\nAll measurements have the `path` tag.\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/cgroup/cgroup.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cgroup\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CGroup struct {\n\tPaths []string `toml:\"paths\"`\n\tFiles []string `toml:\"files\"`\n\n\tlogged map[string]bool\n}\n\nfunc (*CGroup) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (cg *CGroup) Init() error {\n\tcg.logged = make(map[string]bool)\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"cgroup\", func() telegraf.Input { return &CGroup{} })\n}\n"
  },
  {
    "path": "plugins/inputs/cgroup/cgroup_linux.go",
    "content": "//go:build linux\n\npackage cgroup\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nconst metricName = \"cgroup\"\n\nfunc (cg *CGroup) Gather(acc telegraf.Accumulator) error {\n\tlist := make(chan pathInfo)\n\tgo cg.generateDirs(list)\n\n\tfor dir := range list {\n\t\tif dir.err != nil {\n\t\t\tacc.AddError(dir.err)\n\t\t\tcontinue\n\t\t}\n\t\tif err := cg.gatherDir(acc, dir.path); err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (cg *CGroup) gatherDir(acc telegraf.Accumulator, dir string) error {\n\tfields := make(map[string]interface{})\n\n\tlist := make(chan pathInfo)\n\tgo cg.generateFiles(dir, list)\n\n\tfor file := range list {\n\t\tif file.err != nil {\n\t\t\treturn file.err\n\t\t}\n\n\t\traw, err := os.ReadFile(file.path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(raw) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfd := fileData{data: raw, path: file.path}\n\t\tif err := fd.parse(fields); err != nil {\n\t\t\tif !cg.logged[file.path] {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\tcg.logged[file.path] = true\n\t\t\tcontinue\n\t\t}\n\t}\n\n\ttags := map[string]string{\"path\": dir}\n\n\tacc.AddFields(metricName, fields, tags)\n\n\treturn nil\n}\n\n// ======================================================================\n\ntype pathInfo struct {\n\tpath string\n\terr  error\n}\n\nfunc isDir(pathToCheck string) (bool, error) {\n\tresult, err := os.Stat(pathToCheck)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn result.IsDir(), nil\n}\n\nfunc (cg *CGroup) generateDirs(list chan<- pathInfo) {\n\tdefer close(list)\n\tfor _, dir := range cg.Paths {\n\t\t// getting all dirs that match the pattern 'dir'\n\t\titems, err := filepath.Glob(dir)\n\t\tif err != nil {\n\t\t\tlist <- pathInfo{err: err}\n\t\t\treturn\n\t\t}\n\n\t\tfor _, item := range items {\n\t\t\tok, err := isDir(item)\n\t\t\tif err != nil {\n\t\t\t\tlist <- pathInfo{err: err}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// supply only dirs\n\t\t\tif ok {\n\t\t\t\tlist <- pathInfo{path: item}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (cg *CGroup) generateFiles(dir string, list chan<- pathInfo) {\n\tdir = strings.Replace(dir, \"\\\\\", \"\\\\\\\\\", -1)\n\n\tdefer close(list)\n\tfor _, file := range cg.Files {\n\t\t// getting all file paths that match the pattern 'dir + file'\n\t\t// path.Base make sure that file variable does not contains part of path\n\t\titems, err := filepath.Glob(path.Join(dir, path.Base(file)))\n\t\tif err != nil {\n\t\t\tlist <- pathInfo{err: err}\n\t\t\treturn\n\t\t}\n\n\t\tfor _, item := range items {\n\t\t\tok, err := isDir(item)\n\t\t\tif err != nil {\n\t\t\t\tlist <- pathInfo{err: err}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// supply only files not dirs\n\t\t\tif !ok {\n\t\t\t\tlist <- pathInfo{path: item}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ======================================================================\n\ntype fileData struct {\n\tdata []byte\n\tpath string\n}\n\nfunc (fd *fileData) format() (*fileFormat, error) {\n\tfor _, ff := range fileFormats {\n\t\tok, err := ff.match(fd.data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif ok {\n\t\t\treturn &ff, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"%v: unknown file format\", fd.path)\n}\n\nfunc (fd *fileData) parse(fields map[string]interface{}) error {\n\tformat, err := fd.format()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tformat.parser(filepath.Base(fd.path), fields, fd.data)\n\treturn nil\n}\n\n// ======================================================================\n\ntype fileFormat struct {\n\tname    string\n\tpattern string\n\tparser  func(measurement string, fields map[string]interface{}, b []byte)\n}\n\nconst keyPattern = \"[[:alnum:]:_.]+\"\nconst valuePattern = \"(?:max|[\\\\d-\\\\.]+)\"\n\nvar fileFormats = [...]fileFormat{\n\t// \tVAL\\n\n\t{\n\t\tname:    \"Single value\",\n\t\tpattern: \"^\" + valuePattern + \"\\n$\",\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tre := regexp.MustCompile(\"^(\" + valuePattern + \")\\n$\")\n\t\t\tmatches := re.FindAllStringSubmatch(string(b), -1)\n\t\t\tfields[measurement] = numberOrString(matches[0][1])\n\t\t},\n\t},\n\t// \tVAL0\\n\n\t// \tVAL1\\n\n\t// \t...\n\t{\n\t\tname:    \"New line separated values\",\n\t\tpattern: \"^(\" + valuePattern + \"\\n){2,}$\",\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tre := regexp.MustCompile(\"(\" + valuePattern + \")\\n\")\n\t\t\tmatches := re.FindAllStringSubmatch(string(b), -1)\n\t\t\tfor i, v := range matches {\n\t\t\t\tfields[measurement+\".\"+strconv.Itoa(i)] = numberOrString(v[1])\n\t\t\t}\n\t\t},\n\t},\n\t// \tVAL0 VAL1 ...\\n\n\t{\n\t\tname:    \"Space separated values\",\n\t\tpattern: \"^(\" + valuePattern + \" ?)+\\n$\",\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tre := regexp.MustCompile(\"(\" + valuePattern + \")\")\n\t\t\tmatches := re.FindAllStringSubmatch(string(b), -1)\n\t\t\tfor i, v := range matches {\n\t\t\t\tfields[measurement+\".\"+strconv.Itoa(i)] = numberOrString(v[1])\n\t\t\t}\n\t\t},\n\t},\n\t// \tKEY0 ... VAL0\\n\n\t// \tKEY1 ... VAL1\\n\n\t// \t...\n\t{\n\t\tname:    \"Space separated keys and value, separated by new line\",\n\t\tpattern: \"^((\" + keyPattern + \" )+\" + valuePattern + \"\\n)+$\",\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tre := regexp.MustCompile(\"((?:\" + keyPattern + \" ?)+) (\" + valuePattern + \")\\n\")\n\t\t\tmatches := re.FindAllStringSubmatch(string(b), -1)\n\t\t\tfor _, v := range matches {\n\t\t\t\tk := strings.ReplaceAll(v[1], \" \", \".\")\n\t\t\t\tfields[measurement+\".\"+k] = numberOrString(v[2])\n\t\t\t}\n\t\t},\n\t},\n\t// \tNAME0 KEY0=VAL0 ...\\n\n\t// \tNAME1 KEY1=VAL1 ...\\n\n\t// \t...\n\t{\n\t\tname:    \"Equal sign separated key-value pairs,  multiple lines with name\",\n\t\tpattern: fmt.Sprintf(\"^(%s( %s=%s)+\\n)+$\", keyPattern, keyPattern, valuePattern),\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tlines := strings.Split(string(b), \"\\n\")\n\t\t\tfor _, line := range lines {\n\t\t\t\tf := strings.Fields(line)\n\t\t\t\tif len(f) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tname := f[0]\n\t\t\t\tfor _, field := range f[1:] {\n\t\t\t\t\tk, v, found := strings.Cut(field, \"=\")\n\t\t\t\t\tif found {\n\t\t\t\t\t\tfields[strings.Join([]string{measurement, name, k}, \".\")] = numberOrString(v)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n\t// \tKEY0=VAL0 KEY1=VAL1 ...\\n\n\t{\n\t\tname:    \"Equal sign separated key-value pairs on a single line\",\n\t\tpattern: fmt.Sprintf(\"^(%s=%s ?)+\\n$\", keyPattern, valuePattern),\n\t\tparser: func(measurement string, fields map[string]interface{}, b []byte) {\n\t\t\tf := strings.Fields(string(b))\n\t\t\tif len(f) == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfor _, field := range f {\n\t\t\t\tk, v, found := strings.Cut(field, \"=\")\n\t\t\t\tif found {\n\t\t\t\t\tfields[strings.Join([]string{measurement, k}, \".\")] = numberOrString(v)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n}\n\nfunc numberOrString(s string) interface{} {\n\ti, err := strconv.ParseInt(s, 10, 64)\n\tif err == nil {\n\t\treturn i\n\t}\n\tif s == \"max\" {\n\t\treturn int64(math.MaxInt64)\n\t}\n\n\t// Care should be taken to always interpret each field as the same type on every cycle.\n\t// *.pressure files follow the PSI format and contain numbers with fractional parts\n\t// that always have a decimal separator, even when the fractional part is 0 (e.g., \"0.00\"),\n\t// thus they will always be interpreted as floats.\n\t// https://www.kernel.org/doc/Documentation/accounting/psi.txt\n\tf, err := strconv.ParseFloat(s, 64)\n\tif err == nil {\n\t\treturn f\n\t}\n\n\treturn s\n}\n\nfunc (f fileFormat) match(b []byte) (bool, error) {\n\tok, err := regexp.Match(f.pattern, b)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif ok {\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n"
  },
  {
    "path": "plugins/inputs/cgroup/cgroup_notlinux.go",
    "content": "//go:build !linux\n\npackage cgroup\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc (*CGroup) Gather(_ telegraf.Accumulator) error {\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/cgroup/cgroup_test.go",
    "content": "//go:build linux\n\npackage cgroup\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCgroupStatistics_1(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/memory\"},\n\t\tFiles: []string{\n\t\t\t\"memory.empty\",\n\t\t\t\"memory.max_usage_in_bytes\",\n\t\t\t\"memory.limit_in_bytes\",\n\t\t\t\"memory.stat\",\n\t\t\t\"memory.use_hierarchy\",\n\t\t\t\"notify_on_release\",\n\t\t},\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.stat.cache\":           int64(1739362304123123123),\n\t\t\t\t\"memory.stat.rss\":             int64(1775325184),\n\t\t\t\t\"memory.stat.rss_huge\":        int64(778043392),\n\t\t\t\t\"memory.stat.mapped_file\":     int64(421036032),\n\t\t\t\t\"memory.stat.dirty\":           int64(-307200),\n\t\t\t\t\"memory.max_usage_in_bytes.0\": int64(0),\n\t\t\t\t\"memory.max_usage_in_bytes.1\": int64(-1),\n\t\t\t\t\"memory.max_usage_in_bytes.2\": int64(2),\n\t\t\t\t\"memory.limit_in_bytes\":       int64(223372036854771712),\n\t\t\t\t\"memory.use_hierarchy\":        \"12-781\",\n\t\t\t\t\"notify_on_release\":           int64(0),\n\t\t\t},\n\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_2(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/cpu\"},\n\t\tFiles: []string{\n\t\t\t\"cpuacct.usage_percpu\",\n\t\t\t\"cpu.stat\",\n\t\t},\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/cpu\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu.stat.core_sched.force_idle_usec\": int64(0),\n\t\t\t\t\"cpu.stat.system_usec\":                int64(103537582650),\n\t\t\t\t\"cpu.stat.usage_usec\":                 int64(614953149468),\n\t\t\t\t\"cpu.stat.user_usec\":                  int64(511415566817),\n\t\t\t\t\"cpuacct.usage_percpu.0\":              int64(-1452543795404),\n\t\t\t\t\"cpuacct.usage_percpu.1\":              int64(1376681271659),\n\t\t\t\t\"cpuacct.usage_percpu.2\":              int64(1450950799997),\n\t\t\t\t\"cpuacct.usage_percpu.3\":              int64(-1473113374257),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_3(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/memory/*\"},\n\t\tFiles: []string{\"memory.limit_in_bytes\"},\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"memory.limit_in_bytes\": int64(223372036854771712),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_1\",\n\t\t\t},\n\t\t\tfields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_2\",\n\t\t\t},\n\t\t\tfields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_4(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/memory/*/*\", \"testdata/memory/group_2\"},\n\t\tFiles: []string{\"memory.limit_in_bytes\"},\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"memory.limit_in_bytes\": int64(223372036854771712),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_1/group_1_1\",\n\t\t\t},\n\t\t\tfields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_1/group_1_2\",\n\t\t\t},\n\t\t\tfields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_2/group_1_1\",\n\t\t\t},\n\t\t\tfields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.limit_in_bytes\": int64(223372036854771712),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_5(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/memory/*/group_1_1\"},\n\t\tFiles: []string{\"memory.limit_in_bytes\"},\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_1/group_1_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.limit_in_bytes\": int64(223372036854771712),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory/group_2/group_1_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.limit_in_bytes\": int64(223372036854771712),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_6(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/memory\"},\n\t\tFiles: []string{\"memory.us*\", \"*/memory.kmem.*\"},\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/memory\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.usage_in_bytes\":      int64(3513667584),\n\t\t\t\t\"memory.use_hierarchy\":       \"12-781\",\n\t\t\t\t\"memory.kmem.limit_in_bytes\": int64(9223372036854771712),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_7(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths: []string{\"testdata/blkio\"},\n\t\tFiles: []string{\"blkio.throttle.io_serviced\"},\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"testdata/blkio\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"blkio.throttle.io_serviced.11:0.Read\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.11:0.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.11:0.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.11:0.Async\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.11:0.Total\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.8:0.Read\":   int64(49134),\n\t\t\t\t\"blkio.throttle.io_serviced.8:0.Write\":  int64(216703),\n\t\t\t\t\"blkio.throttle.io_serviced.8:0.Sync\":   int64(177906),\n\t\t\t\t\"blkio.throttle.io_serviced.8:0.Async\":  int64(87931),\n\t\t\t\t\"blkio.throttle.io_serviced.8:0.Total\":  int64(265837),\n\t\t\t\t\"blkio.throttle.io_serviced.7:7.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:7.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:7.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:7.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:7.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:6.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:6.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:6.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:6.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:6.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:5.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:5.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:5.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:5.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:5.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:4.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:4.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:4.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:4.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:4.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:3.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:3.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:3.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:3.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:3.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:2.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:2.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:2.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:2.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:2.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:1.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:1.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:1.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:1.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:1.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:0.Read\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:0.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:0.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:0.Async\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.7:0.Total\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:15.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:15.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:15.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:15.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:15.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:14.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:14.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:14.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:14.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:14.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:13.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:13.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:13.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:13.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:13.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:12.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:12.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:12.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:12.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:12.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:11.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:11.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:11.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:11.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:11.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:10.Read\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:10.Write\": int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:10.Sync\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:10.Async\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:10.Total\": int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:9.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:9.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:9.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:9.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:9.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:8.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:8.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:8.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:8.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:8.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:7.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:7.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:7.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:7.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:7.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:6.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:6.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:6.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:6.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:6.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:5.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:5.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:5.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:5.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:5.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:4.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:4.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:4.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:4.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:4.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:3.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:3.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:3.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:3.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:3.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:2.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:2.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:2.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:2.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:2.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:1.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:1.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:1.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:1.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:1.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:0.Read\":   int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:0.Write\":  int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:0.Sync\":   int64(0),\n\t\t\t\t\"blkio.throttle.io_serviced.1:0.Async\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.1:0.Total\":  int64(3),\n\t\t\t\t\"blkio.throttle.io_serviced.Total\":      int64(265885),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupStatistics_8(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/broken\"},\n\t\tFiles:  []string{\"malformed.file\", \"memory.limit_in_bytes\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\trequire.Error(t, acc.GatherError(cg.Gather))\n\trequire.Len(t, cg.logged, 1)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": \"testdata/broken\"},\n\t\t\tmap[string]interface{}{\"memory.limit_in_bytes\": int64(1)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t// clear errors so we can check for new errors in next round\n\tacc.Errors = nil\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\trequire.Len(t, cg.logged, 1)\n}\n\nfunc TestCgroupEscapeDir(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/backslash/machine-qemu\\x2d1\\x2d*\"},\n\t\tFiles:  []string{\"cpu.stat\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/backslash/machine-qemu-1-ubuntu`},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu.stat.core_sched.force_idle_usec\": int64(0),\n\t\t\t\t\"cpu.stat.system_usec\":                int64(103537582650),\n\t\t\t\t\"cpu.stat.usage_usec\":                 int64(614953149468),\n\t\t\t\t\"cpu.stat.user_usec\":                  int64(511415566817),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/cgroup/cgroupv2_test.go",
    "content": "//go:build linux\n\npackage cgroup\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCgroupV2Cpu(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/v2\"},\n\t\tFiles:  []string{\"cpu.*\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/v2`},\n\t\t\tmap[string]interface{}{\n\n\t\t\t\t\"cpu.idle\": int64(0),\n\n\t\t\t\t\"cpu.max.0\":     int64(4800000),\n\t\t\t\t\"cpu.max.1\":     int64(100000),\n\t\t\t\t\"cpu.max.burst\": int64(0),\n\n\t\t\t\t\"cpu.pressure.full.avg10\":  float64(0),\n\t\t\t\t\"cpu.pressure.full.avg300\": float64(0.05),\n\t\t\t\t\"cpu.pressure.full.avg60\":  float64(0.08),\n\t\t\t\t\"cpu.pressure.full.total\":  int64(277111656),\n\t\t\t\t\"cpu.pressure.some.avg10\":  float64(0),\n\t\t\t\t\"cpu.pressure.some.avg300\": float64(0.06),\n\t\t\t\t\"cpu.pressure.some.avg60\":  float64(0.08),\n\t\t\t\t\"cpu.pressure.some.total\":  int64(293391454),\n\n\t\t\t\t\"cpu.stat.burst_usec\":                 int64(0),\n\t\t\t\t\"cpu.stat.core_sched.force_idle_usec\": int64(0),\n\t\t\t\t\"cpu.stat.nr_bursts\":                  int64(0),\n\t\t\t\t\"cpu.stat.nr_periods\":                 int64(3936904),\n\t\t\t\t\"cpu.stat.nr_throttled\":               int64(6004),\n\t\t\t\t\"cpu.stat.system_usec\":                int64(37345608977),\n\t\t\t\t\"cpu.stat.throttled_usec\":             int64(19175137007),\n\t\t\t\t\"cpu.stat.usage_usec\":                 int64(98701325189),\n\t\t\t\t\"cpu.stat.user_usec\":                  int64(61355716211),\n\n\t\t\t\t\"cpu.weight\":      int64(79),\n\t\t\t\t\"cpu.weight.nice\": int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupV2Memory(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/v2\"},\n\t\tFiles:  []string{\"memory.*\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/v2`},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"memory.current\":                               int64(13071106048),\n\t\t\t\t\"memory.events.high\":                           int64(0),\n\t\t\t\t\"memory.events.local.high\":                     int64(0),\n\t\t\t\t\"memory.events.local.low\":                      int64(0),\n\t\t\t\t\"memory.events.local.max\":                      int64(0),\n\t\t\t\t\"memory.events.local.oom\":                      int64(0),\n\t\t\t\t\"memory.events.local.oom_group_kill\":           int64(0),\n\t\t\t\t\"memory.events.local.oom_kill\":                 int64(0),\n\t\t\t\t\"memory.events.low\":                            int64(0),\n\t\t\t\t\"memory.events.max\":                            int64(0),\n\t\t\t\t\"memory.events.oom\":                            int64(0),\n\t\t\t\t\"memory.events.oom_group_kill\":                 int64(0),\n\t\t\t\t\"memory.events.oom_kill\":                       int64(0),\n\t\t\t\t\"memory.high\":                                  int64(math.MaxInt64),\n\t\t\t\t\"memory.low\":                                   int64(0),\n\t\t\t\t\"memory.max\":                                   int64(103079215104),\n\t\t\t\t\"memory.min\":                                   int64(0),\n\t\t\t\t\"memory.numa_stat.active_anon.N0\":              int64(81920),\n\t\t\t\t\"memory.numa_stat.active_anon.N1\":              int64(98304),\n\t\t\t\t\"memory.numa_stat.active_file.N0\":              int64(2946760704),\n\t\t\t\t\"memory.numa_stat.active_file.N1\":              int64(2650640384),\n\t\t\t\t\"memory.numa_stat.anon.N0\":                     int64(1330585600),\n\t\t\t\t\"memory.numa_stat.anon.N1\":                     int64(1141161984),\n\t\t\t\t\"memory.numa_stat.anon_thp.N0\":                 int64(0),\n\t\t\t\t\"memory.numa_stat.anon_thp.N1\":                 int64(2097152),\n\t\t\t\t\"memory.numa_stat.file.N0\":                     int64(4531773440),\n\t\t\t\t\"memory.numa_stat.file.N1\":                     int64(4001075200),\n\t\t\t\t\"memory.numa_stat.file_dirty.N0\":               int64(258048),\n\t\t\t\t\"memory.numa_stat.file_dirty.N1\":               int64(45056),\n\t\t\t\t\"memory.numa_stat.file_mapped.N0\":              int64(10272768),\n\t\t\t\t\"memory.numa_stat.file_mapped.N1\":              int64(3940352),\n\t\t\t\t\"memory.numa_stat.file_thp.N0\":                 int64(0),\n\t\t\t\t\"memory.numa_stat.file_thp.N1\":                 int64(0),\n\t\t\t\t\"memory.numa_stat.file_writeback.N0\":           int64(0),\n\t\t\t\t\"memory.numa_stat.file_writeback.N1\":           int64(0),\n\t\t\t\t\"memory.numa_stat.inactive_anon.N0\":            int64(1330479104),\n\t\t\t\t\"memory.numa_stat.inactive_anon.N1\":            int64(1141067776),\n\t\t\t\t\"memory.numa_stat.inactive_file.N0\":            int64(1584979968),\n\t\t\t\t\"memory.numa_stat.inactive_file.N1\":            int64(1350430720),\n\t\t\t\t\"memory.numa_stat.kernel_stack.N0\":             int64(4161536),\n\t\t\t\t\"memory.numa_stat.kernel_stack.N1\":             int64(5537792),\n\t\t\t\t\"memory.numa_stat.pagetables.N0\":               int64(7839744),\n\t\t\t\t\"memory.numa_stat.pagetables.N1\":               int64(8462336),\n\t\t\t\t\"memory.numa_stat.sec_pagetables.N0\":           int64(0),\n\t\t\t\t\"memory.numa_stat.sec_pagetables.N1\":           int64(0),\n\t\t\t\t\"memory.numa_stat.shmem.N0\":                    int64(0),\n\t\t\t\t\"memory.numa_stat.shmem.N1\":                    int64(4096),\n\t\t\t\t\"memory.numa_stat.shmem_thp.N0\":                int64(0),\n\t\t\t\t\"memory.numa_stat.shmem_thp.N1\":                int64(0),\n\t\t\t\t\"memory.numa_stat.slab_reclaimable.N0\":         int64(950447920),\n\t\t\t\t\"memory.numa_stat.slab_reclaimable.N1\":         int64(1081869088),\n\t\t\t\t\"memory.numa_stat.slab_unreclaimable.N0\":       int64(2654816),\n\t\t\t\t\"memory.numa_stat.slab_unreclaimable.N1\":       int64(2661512),\n\t\t\t\t\"memory.numa_stat.swapcached.N0\":               int64(0),\n\t\t\t\t\"memory.numa_stat.swapcached.N1\":               int64(0),\n\t\t\t\t\"memory.numa_stat.unevictable.N0\":              int64(0),\n\t\t\t\t\"memory.numa_stat.unevictable.N1\":              int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_activate_anon.N0\": int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_activate_anon.N1\": int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_activate_file.N0\": int64(40145),\n\t\t\t\t\"memory.numa_stat.workingset_activate_file.N1\": int64(65541),\n\t\t\t\t\"memory.numa_stat.workingset_nodereclaim.N0\":   int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_nodereclaim.N1\":   int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_refault_anon.N0\":  int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_refault_anon.N1\":  int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_refault_file.N0\":  int64(346752),\n\t\t\t\t\"memory.numa_stat.workingset_refault_file.N1\":  int64(282604),\n\t\t\t\t\"memory.numa_stat.workingset_restore_anon.N0\":  int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_restore_anon.N1\":  int64(0),\n\t\t\t\t\"memory.numa_stat.workingset_restore_file.N0\":  int64(19386),\n\t\t\t\t\"memory.numa_stat.workingset_restore_file.N1\":  int64(10010),\n\t\t\t\t\"memory.oom.group\":                             int64(1),\n\t\t\t\t\"memory.peak\":                                  int64(87302021120),\n\t\t\t\t\"memory.pressure.full.avg10\":                   float64(0),\n\t\t\t\t\"memory.pressure.full.avg300\":                  float64(0),\n\t\t\t\t\"memory.pressure.full.avg60\":                   float64(0),\n\t\t\t\t\"memory.pressure.full.total\":                   int64(250662),\n\t\t\t\t\"memory.pressure.some.avg10\":                   float64(0),\n\t\t\t\t\"memory.pressure.some.avg300\":                  float64(0),\n\t\t\t\t\"memory.pressure.some.avg60\":                   float64(0),\n\t\t\t\t\"memory.pressure.some.total\":                   int64(250773),\n\t\t\t\t\"memory.stat.active_anon\":                      int64(180224),\n\t\t\t\t\"memory.stat.active_file\":                      int64(5597401088),\n\t\t\t\t\"memory.stat.anon\":                             int64(2471755776),\n\t\t\t\t\"memory.stat.anon_thp\":                         int64(2097152),\n\t\t\t\t\"memory.stat.file\":                             int64(8532865024),\n\t\t\t\t\"memory.stat.file_dirty\":                       int64(319488),\n\t\t\t\t\"memory.stat.file_mapped\":                      int64(14213120),\n\t\t\t\t\"memory.stat.file_thp\":                         int64(0),\n\t\t\t\t\"memory.stat.file_writeback\":                   int64(0),\n\t\t\t\t\"memory.stat.inactive_anon\":                    int64(2471559168),\n\t\t\t\t\"memory.stat.inactive_file\":                    int64(2935459840),\n\t\t\t\t\"memory.stat.kernel\":                           int64(2065149952),\n\t\t\t\t\"memory.stat.kernel_stack\":                     int64(9699328),\n\t\t\t\t\"memory.stat.pagetables\":                       int64(16302080),\n\t\t\t\t\"memory.stat.percpu\":                           int64(3528),\n\t\t\t\t\"memory.stat.pgactivate\":                       int64(13516655),\n\t\t\t\t\"memory.stat.pgdeactivate\":                     int64(9151751),\n\t\t\t\t\"memory.stat.pgfault\":                          int64(1973187551),\n\t\t\t\t\"memory.stat.pglazyfree\":                       int64(5549),\n\t\t\t\t\"memory.stat.pglazyfreed\":                      int64(1),\n\t\t\t\t\"memory.stat.pgmajfault\":                       int64(8497),\n\t\t\t\t\"memory.stat.pgrefill\":                         int64(9153617),\n\t\t\t\t\"memory.stat.pgscan\":                           int64(12149209),\n\t\t\t\t\"memory.stat.pgscan_direct\":                    int64(4436521),\n\t\t\t\t\"memory.stat.pgscan_kswapd\":                    int64(7712688),\n\t\t\t\t\"memory.stat.pgsteal\":                          int64(12139915),\n\t\t\t\t\"memory.stat.pgsteal_direct\":                   int64(4429690),\n\t\t\t\t\"memory.stat.pgsteal_kswapd\":                   int64(7710225),\n\t\t\t\t\"memory.stat.sec_pagetables\":                   int64(0),\n\t\t\t\t\"memory.stat.shmem\":                            int64(4096),\n\t\t\t\t\"memory.stat.shmem_thp\":                        int64(0),\n\t\t\t\t\"memory.stat.slab\":                             int64(2037641160),\n\t\t\t\t\"memory.stat.slab_reclaimable\":                 int64(2032322192),\n\t\t\t\t\"memory.stat.slab_unreclaimable\":               int64(5318968),\n\t\t\t\t\"memory.stat.sock\":                             int64(0),\n\t\t\t\t\"memory.stat.swapcached\":                       int64(0),\n\t\t\t\t\"memory.stat.thp_collapse_alloc\":               int64(3),\n\t\t\t\t\"memory.stat.thp_fault_alloc\":                  int64(13),\n\t\t\t\t\"memory.stat.unevictable\":                      int64(0),\n\t\t\t\t\"memory.stat.vmalloc\":                          int64(0),\n\t\t\t\t\"memory.stat.workingset_activate_anon\":         int64(0),\n\t\t\t\t\"memory.stat.workingset_activate_file\":         int64(105686),\n\t\t\t\t\"memory.stat.workingset_nodereclaim\":           int64(0),\n\t\t\t\t\"memory.stat.workingset_refault_anon\":          int64(0),\n\t\t\t\t\"memory.stat.workingset_refault_file\":          int64(629356),\n\t\t\t\t\"memory.stat.workingset_restore_anon\":          int64(0),\n\t\t\t\t\"memory.stat.workingset_restore_file\":          int64(29396),\n\t\t\t\t\"memory.swap.current\":                          int64(0),\n\t\t\t\t\"memory.swap.events.fail\":                      int64(0),\n\t\t\t\t\"memory.swap.events.high\":                      int64(0),\n\t\t\t\t\"memory.swap.events.max\":                       int64(0),\n\t\t\t\t\"memory.swap.high\":                             int64(math.MaxInt64),\n\t\t\t\t\"memory.swap.max\":                              int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\nfunc TestCgroupV2Io(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/v2\"},\n\t\tFiles:  []string{\"io.*\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/v2`},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"io.bfq.weight.default\":   int64(100),\n\t\t\t\t\"io.pressure.full.avg10\":  float64(0),\n\t\t\t\t\"io.pressure.full.avg300\": float64(0),\n\t\t\t\t\"io.pressure.full.avg60\":  float64(0),\n\t\t\t\t\"io.pressure.full.total\":  184607952,\n\t\t\t\t\"io.pressure.some.avg10\":  float64(0),\n\t\t\t\t\"io.pressure.some.avg300\": float64(0),\n\t\t\t\t\"io.pressure.some.avg60\":  float64(0),\n\t\t\t\t\"io.pressure.some.total\":  185162400,\n\t\t\t\t\"io.stat.259:8.dbytes\":    int64(0),\n\t\t\t\t\"io.stat.259:8.dios\":      int64(0),\n\t\t\t\t\"io.stat.259:8.rbytes\":    int64(74526720),\n\t\t\t\t\"io.stat.259:8.rios\":      int64(2936),\n\t\t\t\t\"io.stat.259:8.wbytes\":    int64(3789381632),\n\t\t\t\t\"io.stat.259:8.wios\":      int64(181928),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupV2Hugetlb(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/v2\"},\n\t\tFiles:  []string{\"hugetlb.*\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/v2`},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"hugetlb.1GB.current\":         int64(0),\n\t\t\t\t\"hugetlb.1GB.events.0\":        int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.1GB.events.1\":        int64(0),\n\t\t\t\t\"hugetlb.1GB.events.local.0\":  int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.1GB.events.local.1\":  int64(0),\n\t\t\t\t\"hugetlb.1GB.max\":             int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.1GB.numa_stat.N0\":    int64(0),\n\t\t\t\t\"hugetlb.1GB.numa_stat.N1\":    int64(0),\n\t\t\t\t\"hugetlb.1GB.numa_stat.total\": int64(0),\n\t\t\t\t\"hugetlb.1GB.rsvd.current\":    int64(0),\n\t\t\t\t\"hugetlb.1GB.rsvd.max\":        int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.2MB.current\":         int64(0),\n\t\t\t\t\"hugetlb.2MB.events.0\":        int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.2MB.events.1\":        int64(0),\n\t\t\t\t\"hugetlb.2MB.events.local.0\":  int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.2MB.events.local.1\":  int64(0),\n\t\t\t\t\"hugetlb.2MB.max\":             int64(math.MaxInt64),\n\t\t\t\t\"hugetlb.2MB.numa_stat.N0\":    int64(0),\n\t\t\t\t\"hugetlb.2MB.numa_stat.N1\":    int64(0),\n\t\t\t\t\"hugetlb.2MB.numa_stat.total\": int64(0),\n\t\t\t\t\"hugetlb.2MB.rsvd.current\":    int64(0),\n\t\t\t\t\"hugetlb.2MB.rsvd.max\":        int64(math.MaxInt64),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestCgroupV2Pids(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar cg = &CGroup{\n\t\tPaths:  []string{\"testdata/v2\"},\n\t\tFiles:  []string{\"pids.*\"},\n\t\tlogged: make(map[string]bool),\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cgroup\",\n\t\t\tmap[string]string{\"path\": `testdata/v2`},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"pids.current\":  int64(592),\n\t\t\t\t\"pids.events.0\": int64(math.MaxInt64),\n\t\t\t\t\"pids.events.1\": int64(0),\n\t\t\t\t\"pids.max\":      int64(629145),\n\t\t\t\t\"pids.peak\":     int64(2438),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\trequire.NoError(t, acc.GatherError(cg.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/cgroup/sample.conf",
    "content": "# Read specific statistics per cgroup\n# This plugin ONLY supports Linux\n[[inputs.cgroup]]\n  ## Directories in which to look for files, globs are supported.\n  ## Consider restricting paths to the set of cgroups you really\n  ## want to monitor if you have a large number of cgroups, to avoid\n  ## any cardinality issues.\n  # paths = [\n  #   \"/sys/fs/cgroup/memory\",\n  #   \"/sys/fs/cgroup/memory/child1\",\n  #   \"/sys/fs/cgroup/memory/child2/*\",\n  # ]\n  ## cgroup stat fields, as file names, globs are supported.\n  ## these file names are appended to each path from above.\n  # files = [\"memory.*usage*\", \"memory.limit_in_bytes\"]\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/backslash/machine-qemu-1-ubuntu/cpu.stat",
    "content": "usage_usec 614953149468\nuser_usec 511415566817\nsystem_usec 103537582650\ncore_sched.force_idle_usec 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/blkio/blkio.io_serviced",
    "content": "Total 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/blkio/blkio.throttle.io_serviced",
    "content": "11:0 Read 0\n11:0 Write 0\n11:0 Sync 0\n11:0 Async 0\n11:0 Total 0\n8:0 Read 49134\n8:0 Write 216703\n8:0 Sync 177906\n8:0 Async 87931\n8:0 Total 265837\n7:7 Read 0\n7:7 Write 0\n7:7 Sync 0\n7:7 Async 0\n7:7 Total 0\n7:6 Read 0\n7:6 Write 0\n7:6 Sync 0\n7:6 Async 0\n7:6 Total 0\n7:5 Read 0\n7:5 Write 0\n7:5 Sync 0\n7:5 Async 0\n7:5 Total 0\n7:4 Read 0\n7:4 Write 0\n7:4 Sync 0\n7:4 Async 0\n7:4 Total 0\n7:3 Read 0\n7:3 Write 0\n7:3 Sync 0\n7:3 Async 0\n7:3 Total 0\n7:2 Read 0\n7:2 Write 0\n7:2 Sync 0\n7:2 Async 0\n7:2 Total 0\n7:1 Read 0\n7:1 Write 0\n7:1 Sync 0\n7:1 Async 0\n7:1 Total 0\n7:0 Read 0\n7:0 Write 0\n7:0 Sync 0\n7:0 Async 0\n7:0 Total 0\n1:15 Read 3\n1:15 Write 0\n1:15 Sync 0\n1:15 Async 3\n1:15 Total 3\n1:14 Read 3\n1:14 Write 0\n1:14 Sync 0\n1:14 Async 3\n1:14 Total 3\n1:13 Read 3\n1:13 Write 0\n1:13 Sync 0\n1:13 Async 3\n1:13 Total 3\n1:12 Read 3\n1:12 Write 0\n1:12 Sync 0\n1:12 Async 3\n1:12 Total 3\n1:11 Read 3\n1:11 Write 0\n1:11 Sync 0\n1:11 Async 3\n1:11 Total 3\n1:10 Read 3\n1:10 Write 0\n1:10 Sync 0\n1:10 Async 3\n1:10 Total 3\n1:9 Read 3\n1:9 Write 0\n1:9 Sync 0\n1:9 Async 3\n1:9 Total 3\n1:8 Read 3\n1:8 Write 0\n1:8 Sync 0\n1:8 Async 3\n1:8 Total 3\n1:7 Read 3\n1:7 Write 0\n1:7 Sync 0\n1:7 Async 3\n1:7 Total 3\n1:6 Read 3\n1:6 Write 0\n1:6 Sync 0\n1:6 Async 3\n1:6 Total 3\n1:5 Read 3\n1:5 Write 0\n1:5 Sync 0\n1:5 Async 3\n1:5 Total 3\n1:4 Read 3\n1:4 Write 0\n1:4 Sync 0\n1:4 Async 3\n1:4 Total 3\n1:3 Read 3\n1:3 Write 0\n1:3 Sync 0\n1:3 Async 3\n1:3 Total 3\n1:2 Read 3\n1:2 Write 0\n1:2 Sync 0\n1:2 Async 3\n1:2 Total 3\n1:1 Read 3\n1:1 Write 0\n1:1 Sync 0\n1:1 Async 3\n1:1 Total 3\n1:0 Read 3\n1:0 Write 0\n1:0 Sync 0\n1:0 Async 3\n1:0 Total 3\nTotal 265885\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/broken/malformed.file",
    "content": "garbage\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/broken/memory.limit_in_bytes",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/cpu/cpu.cfs_quota_us",
    "content": "-1\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/cpu/cpu.stat",
    "content": "usage_usec 614953149468\nuser_usec 511415566817\nsystem_usec 103537582650\ncore_sched.force_idle_usec 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/cpu/cpuacct.usage_percpu",
    "content": "-1452543795404 1376681271659 1450950799997 -1473113374257 \n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/group_1_1/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/group_1_1/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/group_1_2/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/group_1_2/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/memory.kmem.limit_in_bytes",
    "content": "9223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/memory.kmem.max_usage_in_bytes",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_1/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_2/group_1_1/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_2/group_1_1/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_2/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/group_2/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.empty",
    "content": ""
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.kmem.limit_in_bytes",
    "content": "9223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.limit_in_bytes",
    "content": "223372036854771712\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.max_usage_in_bytes",
    "content": "0\n-1\n2\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.numa_stat",
    "content": "total=858067 N0=858067\nfile=406254 N0=406254\nanon=451792 N0=451792\nunevictable=21 N0=21\nhierarchical_total=858067 N0=858067\nhierarchical_file=406254 N0=406254\nhierarchical_anon=451792 N0=451792\nhierarchical_unevictable=21 N0=21\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.stat",
    "content": "cache 1739362304123123123\nrss 1775325184\nrss_huge 778043392\nmapped_file 421036032\ndirty -307200\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.usage_in_bytes",
    "content": "3513667584\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/memory.use_hierarchy",
    "content": "12-781\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/memory/notify_on_release",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.idle",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.max",
    "content": "4800000 100000\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.max.burst",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.pressure",
    "content": "some avg10=0.00 avg60=0.08 avg300=0.06 total=293391454\nfull avg10=0.00 avg60=0.08 avg300=0.05 total=277111656\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.stat",
    "content": "usage_usec 98701325189\nuser_usec 61355716211\nsystem_usec 37345608977\ncore_sched.force_idle_usec 0\nnr_periods 3936904\nnr_throttled 6004\nthrottled_usec 19175137007\nnr_bursts 0\nburst_usec 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.weight",
    "content": "79\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpu.weight.nice",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpuset.cpus",
    "content": "\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpuset.cpus.effective",
    "content": "0-95\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpuset.cpus.partition",
    "content": "member\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpuset.mems",
    "content": "\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/cpuset.mems.effective",
    "content": "0-1\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.current",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.events",
    "content": "max 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.events.local",
    "content": "max 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.max",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.numa_stat",
    "content": "total=0 N0=0 N1=0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.rsvd.current",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.rsvd.max",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.current",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.events",
    "content": "max 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.events.local",
    "content": "max 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.max",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.numa_stat",
    "content": "total=0 N0=0 N1=0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.rsvd.current",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.rsvd.max",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/io.bfq.weight",
    "content": "default 100\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/io.max",
    "content": ""
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/io.pressure",
    "content": "some avg10=0.00 avg60=0.00 avg300=0.00 total=185162400\nfull avg10=0.00 avg60=0.00 avg300=0.00 total=184607952\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/io.stat",
    "content": "259:8 rbytes=74526720 wbytes=3789381632 rios=2936 wios=181928 dbytes=0 dios=0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.current",
    "content": "13071106048\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.events",
    "content": "low 0\nhigh 0\nmax 0\noom 0\noom_kill 0\noom_group_kill 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.events.local",
    "content": "low 0\nhigh 0\nmax 0\noom 0\noom_kill 0\noom_group_kill 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.high",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.low",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.max",
    "content": "103079215104\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.min",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.numa_stat",
    "content": "anon N0=1330585600 N1=1141161984\nfile N0=4531773440 N1=4001075200\nkernel_stack N0=4161536 N1=5537792\npagetables N0=7839744 N1=8462336\nsec_pagetables N0=0 N1=0\nshmem N0=0 N1=4096\nfile_mapped N0=10272768 N1=3940352\nfile_dirty N0=258048 N1=45056\nfile_writeback N0=0 N1=0\nswapcached N0=0 N1=0\nanon_thp N0=0 N1=2097152\nfile_thp N0=0 N1=0\nshmem_thp N0=0 N1=0\ninactive_anon N0=1330479104 N1=1141067776\nactive_anon N0=81920 N1=98304\ninactive_file N0=1584979968 N1=1350430720\nactive_file N0=2946760704 N1=2650640384\nunevictable N0=0 N1=0\nslab_reclaimable N0=950447920 N1=1081869088\nslab_unreclaimable N0=2654816 N1=2661512\nworkingset_refault_anon N0=0 N1=0\nworkingset_refault_file N0=346752 N1=282604\nworkingset_activate_anon N0=0 N1=0\nworkingset_activate_file N0=40145 N1=65541\nworkingset_restore_anon N0=0 N1=0\nworkingset_restore_file N0=19386 N1=10010\nworkingset_nodereclaim N0=0 N1=0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.oom.group",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.peak",
    "content": "87302021120\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.pressure",
    "content": "some avg10=0.00 avg60=0.00 avg300=0.00 total=250773\nfull avg10=0.00 avg60=0.00 avg300=0.00 total=250662\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.reclaim",
    "content": ""
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.stat",
    "content": "anon 2471755776\nfile 8532865024\nkernel 2065149952\nkernel_stack 9699328\npagetables 16302080\nsec_pagetables 0\npercpu 3528\nsock 0\nvmalloc 0\nshmem 4096\nfile_mapped 14213120\nfile_dirty 319488\nfile_writeback 0\nswapcached 0\nanon_thp 2097152\nfile_thp 0\nshmem_thp 0\ninactive_anon 2471559168\nactive_anon 180224\ninactive_file 2935459840\nactive_file 5597401088\nunevictable 0\nslab_reclaimable 2032322192\nslab_unreclaimable 5318968\nslab 2037641160\nworkingset_refault_anon 0\nworkingset_refault_file 629356\nworkingset_activate_anon 0\nworkingset_activate_file 105686\nworkingset_restore_anon 0\nworkingset_restore_file 29396\nworkingset_nodereclaim 0\npgscan 12149209\npgsteal 12139915\npgscan_kswapd 7712688\npgscan_direct 4436521\npgsteal_kswapd 7710225\npgsteal_direct 4429690\npgfault 1973187551\npgmajfault 8497\npgrefill 9153617\npgactivate 13516655\npgdeactivate 9151751\npglazyfree 5549\npglazyfreed 1\nthp_fault_alloc 13\nthp_collapse_alloc 3\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.swap.current",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.swap.events",
    "content": "high 0\nmax 0\nfail 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.swap.high",
    "content": "max\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/memory.swap.max",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/pids.current",
    "content": "592\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/pids.events",
    "content": "max 0\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/pids.max",
    "content": "629145\n"
  },
  {
    "path": "plugins/inputs/cgroup/testdata/v2/pids.peak",
    "content": "2438\n"
  },
  {
    "path": "plugins/inputs/chrony/README.md",
    "content": "# chrony Input Plugin\n\nThis plugin queries metrics from a [chrony NTP server][chrony]. For details on\nthe meaning of the gathered fields please check the [chronyc manual][manual].\n\n⭐ Telegraf v0.13.1\n🏷️ system\n💻 all\n\n[chrony]: https://chrony-project.org\n[manual]: https://chrony-project.org/doc/4.4/chronyc.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get standard chrony metrics.\n[[inputs.chrony]]\n  ## Server address of chronyd with address scheme\n  ## If empty or not set, the plugin will mimic the behavior of chronyc and\n  ## check \"unixgram:///run/chrony/chronyd.sock\", \"udp://127.0.0.1:323\"\n  ## and \"udp://[::1]:323\".\n  # server = \"\"\n\n  ## Timeout for establishing the connection\n  # timeout = \"5s\"\n\n  ## Try to resolve received addresses to host-names via DNS lookups\n  ## Disabled by default to avoid DNS queries especially for slow DNS servers.\n  # dns_lookup = false\n\n  ## Metrics to query named according to chronyc commands\n  ## Available settings are:\n  ##   activity    -- number of peers online or offline\n  ##   tracking    -- information about system's clock performance\n  ##   serverstats -- chronyd server statistics\n  ##   sources     -- extended information about peers\n  ##   sourcestats -- statistics on peers\n  # metrics = [\"tracking\"]\n\n  ## Socket group & permissions\n  ## If the user requests collecting metrics via unix socket, then it is created\n  ## with the following group and permissions.\n  # socket_group = \"chrony\"\n  # socket_perms = \"0660\"\n```\n\n## Local socket permissions\n\nTo use the unix socket, telegraf must be able to talk to it. Please ensure that\nthe telegraf user is a member of the `chrony` group or telegraf won't be able to\nuse the socket!\n\nThe unix socket is needed in order to use the `serverstats` metrics. All other\nmetrics can be gathered using the udp connection.\n\n## Metrics\n\n- chrony\n  - system_time (float, seconds)\n  - last_offset (float, seconds)\n  - rms_offset (float, seconds)\n  - frequency (float, ppm)\n  - residual_freq (float, ppm)\n  - skew (float, ppm)\n  - root_delay (float, seconds)\n  - root_dispersion (float, seconds)\n  - update_interval (float, seconds)\n\n### Tags\n\n- All measurements have the following tags:\n  - reference_id\n  - stratum\n  - leap_status\n\n## Example Output\n\n```text\nchrony,leap_status=not\\ synchronized,reference_id=A29FC87B,stratum=3 frequency=-16.000999450683594,last_offset=0.000012651000361074694,residual_freq=0,rms_offset=0.000025576999178156257,root_delay=0.0016550000291317701,root_dispersion=0.00330700003542006,skew=0.006000000052154064,system_time=0.000020389999917824753,update_interval=507.1999816894531 1706271167571675297\n```\n"
  },
  {
    "path": "plugins/inputs/chrony/chrony.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage chrony\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/user\"\n\t\"path\"\n\t\"strconv\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\tfbchrony \"github.com/facebook/time/ntp/chrony\"\n\t\"github.com/google/uuid\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Chrony struct {\n\tServer      string          `toml:\"server\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\tDNSLookup   bool            `toml:\"dns_lookup\"`\n\tSocketGroup string          `toml:\"socket_group\"`\n\tSocketPerms string          `toml:\"socket_perms\"`\n\tMetrics     []string        `toml:\"metrics\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\n\tconn   net.Conn\n\tclient *fbchrony.Client\n\tsource string\n\tlocal  string\n\n\t// clientMu protects concurrent access to the chrony client.\n\t// This prevents race conditions when multiple Gather() calls\n\t// access the same client instance concurrently.\n\tsync.Mutex\n}\n\nfunc (*Chrony) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *Chrony) Init() error {\n\t// Use the configured server, if none set, we try to guess it in Start()\n\tif c.Server != \"\" {\n\t\t// Check the specified server address\n\t\tu, err := url.Parse(c.Server)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing server address failed: %w\", err)\n\t\t}\n\t\tswitch u.Scheme {\n\t\tcase \"unixgram\":\n\t\t\t// Keep the server unmodified\n\t\tcase \"udp\":\n\t\t\t// Check if we do have a port and add the default port if we don't\n\t\t\tif u.Port() == \"\" {\n\t\t\t\tu.Host += \":323\"\n\t\t\t}\n\t\t\t// We cannot have path elements in an UDP address\n\t\t\tif u.Path != \"\" {\n\t\t\t\treturn fmt.Errorf(\"path detected in UDP address %q\", c.Server)\n\t\t\t}\n\t\t\tu = &url.URL{Scheme: \"udp\", Host: u.Host}\n\t\tdefault:\n\t\t\treturn errors.New(\"unknown or missing address scheme\")\n\t\t}\n\t\tc.Server = u.String()\n\t}\n\n\t// Check the given metrics\n\tif len(c.Metrics) == 0 {\n\t\tc.Metrics = append(c.Metrics, \"tracking\")\n\t}\n\tfor _, m := range c.Metrics {\n\t\tswitch m {\n\t\tcase \"activity\", \"tracking\", \"serverstats\", \"sources\", \"sourcestats\":\n\t\t\t// Do nothing as those are valid\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid metric setting %q\", m)\n\t\t}\n\t}\n\n\tif c.SocketGroup == \"\" {\n\t\tc.SocketGroup = \"chrony\"\n\t}\n\n\tif c.SocketPerms == \"\" {\n\t\tc.SocketPerms = \"0660\"\n\t}\n\n\treturn nil\n}\n\nfunc (c *Chrony) Start(_ telegraf.Accumulator) error {\n\tif c.Server != \"\" {\n\t\t// Create a connection\n\t\tu, err := url.Parse(c.Server)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing server address failed: %w\", err)\n\t\t}\n\t\tswitch u.Scheme {\n\t\tcase \"unixgram\":\n\t\t\tconn, err := c.dialUnix(u.Path)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"dialing %q failed: %w\", c.Server, err)\n\t\t\t}\n\t\t\tc.conn = conn\n\t\t\tc.source = u.Path\n\t\tcase \"udp\":\n\t\t\tconn, err := net.DialTimeout(\"udp\", u.Host, time.Duration(c.Timeout))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"dialing %q failed: %w\", c.Server, err)\n\t\t\t}\n\t\t\tc.conn = conn\n\t\t\tc.source = u.Host\n\t\t}\n\t} else {\n\t\t// If no server is given, reproduce chronyc's behavior\n\t\tif conn, err := c.dialUnix(\"/run/chrony/chronyd.sock\"); err == nil {\n\t\t\tc.Server = \"unix:///run/chrony/chronyd.sock\"\n\t\t\tc.conn = conn\n\t\t} else if conn, err := net.DialTimeout(\"udp\", \"127.0.0.1:323\", time.Duration(c.Timeout)); err == nil {\n\t\t\tc.Server = \"udp://127.0.0.1:323\"\n\t\t\tc.conn = conn\n\t\t} else {\n\t\t\tconn, err := net.DialTimeout(\"udp\", \"[::1]:323\", time.Duration(c.Timeout))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"dialing server failed: %w\", err)\n\t\t\t}\n\t\t\tc.Server = \"udp://[::1]:323\"\n\t\t\tc.conn = conn\n\t\t}\n\t}\n\tc.Log.Debugf(\"Connected to %q...\", c.Server)\n\n\t// Initialize the client\n\tc.client = &fbchrony.Client{Connection: c.conn}\n\n\treturn nil\n}\n\nfunc (c *Chrony) Gather(acc telegraf.Accumulator) error {\n\t// Protect concurrent access to the chrony client to prevent race conditions\n\t// when multiple Gather() calls occur simultaneously (e.g., when a previous\n\t// gather hasn't completed before the next interval triggers).\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tfor _, m := range c.Metrics {\n\t\tswitch m {\n\t\tcase \"activity\":\n\t\t\tacc.AddError(c.gatherActivity(acc))\n\t\tcase \"tracking\":\n\t\t\tacc.AddError(c.gatherTracking(acc))\n\t\tcase \"serverstats\":\n\t\t\tacc.AddError(c.gatherServerStats(acc))\n\t\tcase \"sources\":\n\t\t\tacc.AddError(c.gatherSources(acc))\n\t\tcase \"sourcestats\":\n\t\t\tacc.AddError(c.gatherSourceStats(acc))\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid metric setting %q\", m)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Chrony) Stop() {\n\tif c.conn != nil {\n\t\tif err := c.conn.Close(); err != nil && !errors.Is(err, net.ErrClosed) && !errors.Is(err, syscall.EPIPE) {\n\t\t\tc.Log.Errorf(\"Closing connection to %q failed: %v\", c.Server, err)\n\t\t}\n\t}\n\tif c.local != \"\" {\n\t\tif err := os.Remove(c.local); err != nil {\n\t\t\tc.Log.Errorf(\"Removing temporary socket %q failed: %v\", c.local, err)\n\t\t}\n\t}\n}\n\n// dialUnix opens an unixgram connection with chrony\nfunc (c *Chrony) dialUnix(address string) (*net.UnixConn, error) {\n\tdir := path.Dir(address)\n\tc.local = path.Join(dir, fmt.Sprintf(\"chrony-telegraf-%s.sock\", uuid.New().String()))\n\tconn, err := net.DialUnix(\"unixgram\",\n\t\t&net.UnixAddr{Name: c.local, Net: \"unixgram\"},\n\t\t&net.UnixAddr{Name: address, Net: \"unixgram\"},\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfilemode, err := strconv.ParseUint(c.SocketPerms, 8, 32)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing file mode %q failed: %w\", c.SocketPerms, err)\n\t}\n\n\tif err := os.Chmod(c.local, os.FileMode(filemode)); err != nil {\n\t\treturn nil, fmt.Errorf(\"changing file mode of %q failed: %w\", c.local, err)\n\t}\n\n\tgroup, err := user.LookupGroup(c.SocketGroup)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"looking up group %q failed: %w\", c.SocketGroup, err)\n\t}\n\tgid, err := strconv.Atoi(group.Gid)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing group ID %q failed: %w\", group.Gid, err)\n\t}\n\tif err := os.Chown(c.local, os.Getuid(), gid); err != nil {\n\t\treturn nil, fmt.Errorf(\"changing group of %q failed: %w\", c.local, err)\n\t}\n\n\treturn conn, nil\n}\n\nfunc (c *Chrony) gatherActivity(acc telegraf.Accumulator) error {\n\treq := fbchrony.NewActivityPacket()\n\tr, err := c.client.Communicate(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying activity data failed: %w\", err)\n\t}\n\tresp, ok := r.(*fbchrony.ReplyActivity)\n\tif !ok {\n\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for activity data\", r)\n\t}\n\n\ttags := make(map[string]string, 1)\n\tif c.source != \"\" {\n\t\ttags[\"source\"] = c.source\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"online\":        resp.Online,\n\t\t\"offline\":       resp.Offline,\n\t\t\"burst_online\":  resp.BurstOnline,\n\t\t\"burst_offline\": resp.BurstOffline,\n\t\t\"unresolved\":    resp.Unresolved,\n\t}\n\tacc.AddFields(\"chrony_activity\", fields, tags)\n\n\treturn nil\n}\n\nfunc (c *Chrony) gatherTracking(acc telegraf.Accumulator) error {\n\treq := fbchrony.NewTrackingPacket()\n\tr, err := c.client.Communicate(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying tracking data failed: %w\", err)\n\t}\n\tresp, ok := r.(*fbchrony.ReplyTracking)\n\tif !ok {\n\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for tracking data\", r)\n\t}\n\n\t// according to https://github.com/mlichvar/chrony/blob/e11b518a1ffa704986fb1f1835c425844ba248ef/ntp.h#L70\n\tvar leapStatus string\n\tswitch resp.LeapStatus {\n\tcase 0:\n\t\tleapStatus = \"normal\"\n\tcase 1:\n\t\tleapStatus = \"insert second\"\n\tcase 2:\n\t\tleapStatus = \"delete second\"\n\tcase 3:\n\t\tleapStatus = \"not synchronized\"\n\t}\n\n\ttags := map[string]string{\n\t\t\"leap_status\":  leapStatus,\n\t\t\"reference_id\": fbchrony.RefidAsHEX(resp.RefID),\n\t\t\"stratum\":      strconv.FormatUint(uint64(resp.Stratum), 10),\n\t}\n\tif c.source != \"\" {\n\t\ttags[\"source\"] = c.source\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"frequency\":       resp.FreqPPM,\n\t\t\"system_time\":     resp.CurrentCorrection,\n\t\t\"last_offset\":     resp.LastOffset,\n\t\t\"residual_freq\":   resp.ResidFreqPPM,\n\t\t\"rms_offset\":      resp.RMSOffset,\n\t\t\"root_delay\":      resp.RootDelay,\n\t\t\"root_dispersion\": resp.RootDispersion,\n\t\t\"skew\":            resp.SkewPPM,\n\t\t\"update_interval\": resp.LastUpdateInterval,\n\t}\n\tacc.AddFields(\"chrony\", fields, tags)\n\n\treturn nil\n}\n\nfunc (c *Chrony) gatherServerStats(acc telegraf.Accumulator) error {\n\treq := fbchrony.NewServerStatsPacket()\n\tr, err := c.client.Communicate(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying server statistics failed: %w\", err)\n\t}\n\n\ttags := make(map[string]string, 1)\n\tif c.source != \"\" {\n\t\ttags[\"source\"] = c.source\n\t}\n\n\tvar fields map[string]interface{}\n\tswitch resp := r.(type) {\n\tcase *fbchrony.ReplyServerStats:\n\t\tfields = map[string]interface{}{\n\t\t\t\"ntp_hits\":  resp.NTPHits,\n\t\t\t\"ntp_drops\": resp.NTPDrops,\n\t\t\t\"cmd_hits\":  resp.CMDHits,\n\t\t\t\"cmd_drops\": resp.CMDDrops,\n\t\t\t\"log_drops\": resp.LogDrops,\n\t\t}\n\tcase *fbchrony.ReplyServerStats2:\n\t\tfields = map[string]interface{}{\n\t\t\t\"ntp_hits\":      resp.NTPHits,\n\t\t\t\"ntp_drops\":     resp.NTPDrops,\n\t\t\t\"ntp_auth_hits\": resp.NTPAuthHits,\n\t\t\t\"cmd_hits\":      resp.CMDHits,\n\t\t\t\"cmd_drops\":     resp.CMDDrops,\n\t\t\t\"log_drops\":     resp.LogDrops,\n\t\t\t\"nke_hits\":      resp.NKEHits,\n\t\t\t\"nke_drops\":     resp.NKEDrops,\n\t\t}\n\tcase *fbchrony.ReplyServerStats3:\n\t\tfields = map[string]interface{}{\n\t\t\t\"ntp_hits\":             resp.NTPHits,\n\t\t\t\"ntp_drops\":            resp.NTPDrops,\n\t\t\t\"ntp_auth_hits\":        resp.NTPAuthHits,\n\t\t\t\"ntp_interleaved_hits\": resp.NTPInterleavedHits,\n\t\t\t\"ntp_timestamps\":       resp.NTPTimestamps,\n\t\t\t\"ntp_span_seconds\":     resp.NTPSpanSeconds,\n\t\t\t\"cmd_hits\":             resp.CMDHits,\n\t\t\t\"cmd_drops\":            resp.CMDDrops,\n\t\t\t\"log_drops\":            resp.LogDrops,\n\t\t\t\"nke_hits\":             resp.NKEHits,\n\t\t\t\"nke_drops\":            resp.NKEDrops,\n\t\t}\n\tcase *fbchrony.ReplyServerStats4:\n\t\tfields = map[string]interface{}{\n\t\t\t\"ntp_hits\":                   resp.NTPHits,\n\t\t\t\"ntp_drops\":                  resp.NTPDrops,\n\t\t\t\"ntp_auth_hits\":              resp.NTPAuthHits,\n\t\t\t\"ntp_interleaved_hits\":       resp.NTPInterleavedHits,\n\t\t\t\"ntp_timestamps\":             resp.NTPTimestamps,\n\t\t\t\"ntp_span_seconds\":           resp.NTPSpanSeconds,\n\t\t\t\"cmd_hits\":                   resp.CMDHits,\n\t\t\t\"cmd_drops\":                  resp.CMDDrops,\n\t\t\t\"log_drops\":                  resp.LogDrops,\n\t\t\t\"nke_hits\":                   resp.NKEHits,\n\t\t\t\"nke_drops\":                  resp.NKEDrops,\n\t\t\t\"ntp_daemon_rx_timestamps\":   resp.NTPDaemonRxtimestamps,\n\t\t\t\"ntp_daemon_tx_timestamps\":   resp.NTPDaemonTxtimestamps,\n\t\t\t\"ntp_kernel_rx_timestamps\":   resp.NTPKernelRxtimestamps,\n\t\t\t\"ntp_kernel_tx_timestamps\":   resp.NTPKernelTxtimestamps,\n\t\t\t\"ntp_hardware_rx_timestamps\": resp.NTPHwRxTimestamps,\n\t\t\t\"ntp_hardware_tx_timestamps\": resp.NTPHwTxTimestamps,\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for server statistics\", r)\n\t}\n\n\tacc.AddFields(\"chrony_serverstats\", fields, tags)\n\n\treturn nil\n}\n\nfunc (c *Chrony) getSourceName(ip net.IP) (string, error) {\n\tsourceNameReq := fbchrony.NewNTPSourceNamePacket(ip)\n\tsourceNameRaw, err := c.client.Communicate(sourceNameReq)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"querying name of source %q failed: %w\", ip, err)\n\t}\n\tsourceName, ok := sourceNameRaw.(*fbchrony.ReplyNTPSourceName)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"got unexpected response type %T while waiting for source name\", sourceNameRaw)\n\t}\n\n\t// Cut the string at null termination\n\tif termidx := bytes.Index([]byte(sourceName.Name), []byte{0}); termidx >= 0 {\n\t\treturn sourceName.Name[:termidx], nil\n\t}\n\treturn sourceName.Name, nil\n}\n\nfunc (c *Chrony) gatherSources(acc telegraf.Accumulator) error {\n\tsourcesReq := fbchrony.NewSourcesPacket()\n\tsourcesRaw, err := c.client.Communicate(sourcesReq)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying sources failed: %w\", err)\n\t}\n\n\tsourcesResp, ok := sourcesRaw.(*fbchrony.ReplySources)\n\tif !ok {\n\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for sources\", sourcesRaw)\n\t}\n\n\tfor idx := int32(0); int(idx) < sourcesResp.NSources; idx++ {\n\t\t// Getting the source data\n\t\tsourceDataReq := fbchrony.NewSourceDataPacket(idx)\n\t\tsourceDataRaw, err := c.client.Communicate(sourceDataReq)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"querying data for source %d failed: %w\", idx, err)\n\t\t}\n\t\tsourceData, ok := sourceDataRaw.(*fbchrony.ReplySourceData)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for source data\", sourceDataRaw)\n\t\t}\n\n\t\t// Trying to resolve the source name\n\t\tvar peer string\n\n\t\tif sourceData.Mode == fbchrony.SourceModeRef && sourceData.IPAddr.To4() != nil {\n\t\t\t// References of local sources (PPS, etc..) are encoded in the bits of the IPv4 address,\n\t\t\t// instead of the RefId. Extract the correct name for those sources.\n\t\t\tipU32 := binary.BigEndian.Uint32(sourceData.IPAddr.To4())\n\n\t\t\tpeer = fbchrony.RefidToString(ipU32)\n\t\t} else {\n\t\t\tpeer, err = c.getSourceName(sourceData.IPAddr)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif peer == \"\" {\n\t\t\tpeer = sourceData.IPAddr.String()\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"peer\": peer,\n\t\t}\n\t\tif c.source != \"\" {\n\t\t\ttags[\"source\"] = c.source\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"index\":                    idx,\n\t\t\t\"ip\":                       sourceData.IPAddr.String(),\n\t\t\t\"poll\":                     sourceData.Poll,\n\t\t\t\"stratum\":                  sourceData.Stratum,\n\t\t\t\"state\":                    sourceData.State.String(),\n\t\t\t\"mode\":                     sourceData.Mode.String(),\n\t\t\t\"flags\":                    sourceData.Flags,\n\t\t\t\"reachability\":             sourceData.Reachability,\n\t\t\t\"sample\":                   sourceData.SinceSample,\n\t\t\t\"latest_measurement\":       sourceData.LatestMeas,\n\t\t\t\"latest_measurement_error\": sourceData.LatestMeasErr,\n\t\t}\n\t\tacc.AddFields(\"chrony_sources\", fields, tags)\n\t}\n\treturn nil\n}\n\nfunc (c *Chrony) gatherSourceStats(acc telegraf.Accumulator) error {\n\tsourcesReq := fbchrony.NewSourcesPacket()\n\tsourcesRaw, err := c.client.Communicate(sourcesReq)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying sources failed: %w\", err)\n\t}\n\n\tsourcesResp, ok := sourcesRaw.(*fbchrony.ReplySources)\n\tif !ok {\n\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for sources\", sourcesRaw)\n\t}\n\n\tfor idx := int32(0); int(idx) < sourcesResp.NSources; idx++ {\n\t\t// Getting the source data\n\t\tsourceStatsReq := fbchrony.NewSourceStatsPacket(idx)\n\t\tsourceStatsRaw, err := c.client.Communicate(sourceStatsReq)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"querying data for source %d failed: %w\", idx, err)\n\t\t}\n\t\tsourceStats, ok := sourceStatsRaw.(*fbchrony.ReplySourceStats)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"got unexpected response type %T while waiting for source data\", sourceStatsRaw)\n\t\t}\n\n\t\t// Trying to resolve the source name\n\t\tvar peer string\n\n\t\tif sourceStats.IPAddr.String() == \"::\" {\n\t\t\t// `::` IPs mean a local source directly connected to the server.\n\t\t\t// For example a PPS source or a local GPS receiver.\n\t\t\t// Then the name of the source is encoded in its RefID\n\t\t\tpeer = fbchrony.RefidToString(sourceStats.RefID)\n\t\t} else {\n\t\t\tpeer, err = c.getSourceName(sourceStats.IPAddr)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif peer == \"\" {\n\t\t\tpeer = sourceStats.IPAddr.String()\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"reference_id\": fbchrony.RefidAsHEX(sourceStats.RefID),\n\t\t\t\"peer\":         peer,\n\t\t}\n\t\tif c.source != \"\" {\n\t\t\ttags[\"source\"] = c.source\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"index\":              idx,\n\t\t\t\"ip\":                 sourceStats.IPAddr.String(),\n\t\t\t\"samples\":            sourceStats.NSamples,\n\t\t\t\"runs\":               sourceStats.NRuns,\n\t\t\t\"span_seconds\":       sourceStats.SpanSeconds,\n\t\t\t\"stddev\":             sourceStats.StandardDeviation,\n\t\t\t\"residual_frequency\": sourceStats.ResidFreqPPM,\n\t\t\t\"skew\":               sourceStats.SkewPPM,\n\t\t\t\"offset\":             sourceStats.EstimatedOffset,\n\t\t\t\"offset_error\":       sourceStats.EstimatedOffsetErr,\n\t\t}\n\t\tacc.AddFields(\"chrony_sourcestats\", fields, tags)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"chrony\", func() telegraf.Input {\n\t\treturn &Chrony{Timeout: config.Duration(3 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/chrony/chrony_test.go",
    "content": "package chrony\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\tfbchrony \"github.com/facebook/time/ntp/chrony\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGatherActivity(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tActivityInfo: &fbchrony.Activity{\n\t\t\tOnline:       34,\n\t\t\tOffline:      6,\n\t\t\tBurstOnline:  2,\n\t\t\tBurstOffline: 0,\n\t\t\tUnresolved:   5,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"activity\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_activity\",\n\t\t\tmap[string]string{\"source\": addr},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"online\":        34,\n\t\t\t\t\"offline\":       6,\n\t\t\t\t\"burst_online\":  2,\n\t\t\t\t\"burst_offline\": 0,\n\t\t\t\t\"unresolved\":    5,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherTracking(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tTrackingInfo: &fbchrony.Tracking{\n\t\t\tRefID:              0xA29FC87B,\n\t\t\tIPAddr:             net.ParseIP(\"192.168.1.22\"),\n\t\t\tStratum:            3,\n\t\t\tLeapStatus:         3,\n\t\t\tRefTime:            time.Now(),\n\t\t\tCurrentCorrection:  0.000020390,\n\t\t\tLastOffset:         0.000012651,\n\t\t\tRMSOffset:          0.000025577,\n\t\t\tFreqPPM:            -16.001,\n\t\t\tResidFreqPPM:       0.0,\n\t\t\tSkewPPM:            0.006,\n\t\t\tRootDelay:          0.001655,\n\t\t\tRootDispersion:     0.003307,\n\t\t\tLastUpdateInterval: 507.2,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"tracking\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":       addr,\n\t\t\t\t\"reference_id\": \"A29FC87B\",\n\t\t\t\t\"leap_status\":  \"not synchronized\",\n\t\t\t\t\"stratum\":      \"3\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"system_time\":     0.000020390,\n\t\t\t\t\"last_offset\":     0.000012651,\n\t\t\t\t\"rms_offset\":      0.000025577,\n\t\t\t\t\"frequency\":       -16.001,\n\t\t\t\t\"residual_freq\":   0.0,\n\t\t\t\t\"skew\":            0.006,\n\t\t\t\t\"root_delay\":      0.001655,\n\t\t\t\t\"root_dispersion\": 0.003307,\n\t\t\t\t\"update_interval\": 507.2,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherServerStats(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tServerStatInfo: &fbchrony.ServerStats{\n\t\t\tNTPHits:  2542,\n\t\t\tCMDHits:  112,\n\t\t\tNTPDrops: 42,\n\t\t\tCMDDrops: 8,\n\t\t\tLogDrops: 0,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"serverstats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_serverstats\",\n\t\t\tmap[string]string{\"source\": addr},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ntp_hits\":  uint64(2542),\n\t\t\t\t\"ntp_drops\": uint64(42),\n\t\t\t\t\"cmd_hits\":  uint64(112),\n\t\t\t\t\"cmd_drops\": uint64(8),\n\t\t\t\t\"log_drops\": uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherServerStats2(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tServerStatInfo: &fbchrony.ServerStats2{\n\t\t\tNTPHits:     2542,\n\t\t\tNKEHits:     5,\n\t\t\tCMDHits:     112,\n\t\t\tNTPDrops:    42,\n\t\t\tNKEDrops:    1,\n\t\t\tCMDDrops:    8,\n\t\t\tLogDrops:    0,\n\t\t\tNTPAuthHits: 9,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"serverstats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_serverstats\",\n\t\t\tmap[string]string{\"source\": addr},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ntp_hits\":      uint64(2542),\n\t\t\t\t\"ntp_drops\":     uint64(42),\n\t\t\t\t\"ntp_auth_hits\": uint64(9),\n\t\t\t\t\"cmd_hits\":      uint64(112),\n\t\t\t\t\"cmd_drops\":     uint64(8),\n\t\t\t\t\"log_drops\":     uint64(0),\n\t\t\t\t\"nke_hits\":      uint64(5),\n\t\t\t\t\"nke_drops\":     uint64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherServerStats3(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tServerStatInfo: &fbchrony.ServerStats3{\n\t\t\tNTPHits:            2542,\n\t\t\tNKEHits:            5,\n\t\t\tCMDHits:            112,\n\t\t\tNTPDrops:           42,\n\t\t\tNKEDrops:           1,\n\t\t\tCMDDrops:           8,\n\t\t\tLogDrops:           0,\n\t\t\tNTPAuthHits:        9,\n\t\t\tNTPInterleavedHits: 28,\n\t\t\tNTPTimestamps:      69527,\n\t\t\tNTPSpanSeconds:     33,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"serverstats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_serverstats\",\n\t\t\tmap[string]string{\"source\": addr},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ntp_hits\":             uint64(2542),\n\t\t\t\t\"ntp_drops\":            uint64(42),\n\t\t\t\t\"ntp_auth_hits\":        uint64(9),\n\t\t\t\t\"ntp_interleaved_hits\": uint64(28),\n\t\t\t\t\"ntp_timestamps\":       uint64(69527),\n\t\t\t\t\"ntp_span_seconds\":     uint64(33),\n\t\t\t\t\"cmd_hits\":             uint64(112),\n\t\t\t\t\"cmd_drops\":            uint64(8),\n\t\t\t\t\"log_drops\":            uint64(0),\n\t\t\t\t\"nke_hits\":             uint64(5),\n\t\t\t\t\"nke_drops\":            uint64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherSources(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tSourcesInfo: []source{\n\t\t\t{\n\t\t\t\tname: \"ntp1.my.org\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 0, 1),\n\t\t\t\t\tPoll:           64,\n\t\t\t\t\tStratum:        16,\n\t\t\t\t\tState:          fbchrony.SourceStateSync,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   0,\n\t\t\t\t\tSinceSample:    0,\n\t\t\t\t\tOrigLatestMeas: 1.22354,\n\t\t\t\t\tLatestMeas:     1.22354,\n\t\t\t\t\tLatestMeasErr:  0.00423,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp2.my.org\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 0, 2),\n\t\t\t\t\tPoll:           64,\n\t\t\t\t\tStratum:        16,\n\t\t\t\t\tState:          fbchrony.SourceStateSync,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   0,\n\t\t\t\t\tSinceSample:    0,\n\t\t\t\t\tOrigLatestMeas: 0.17791,\n\t\t\t\t\tLatestMeas:     0.35445,\n\t\t\t\t\tLatestMeasErr:  0.01196,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp3.my.org\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 0, 3),\n\t\t\t\t\tPoll:           512,\n\t\t\t\t\tStratum:        1,\n\t\t\t\t\tState:          fbchrony.SourceStateOutlier,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   512,\n\t\t\t\t\tSinceSample:    377,\n\t\t\t\t\tOrigLatestMeas: 7.21158,\n\t\t\t\t\tLatestMeas:     7.21158,\n\t\t\t\t\tLatestMeasErr:  2.15453,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"sources\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_sources\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": addr,\n\t\t\t\t\"peer\":   \"ntp1.my.org\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":                    0,\n\t\t\t\t\"ip\":                       \"192.168.0.1\",\n\t\t\t\t\"poll\":                     64,\n\t\t\t\t\"stratum\":                  uint64(16),\n\t\t\t\t\"state\":                    \"sync\",\n\t\t\t\t\"mode\":                     \"peer\",\n\t\t\t\t\"flags\":                    uint64(0),\n\t\t\t\t\"reachability\":             uint64(0),\n\t\t\t\t\"sample\":                   uint64(0),\n\t\t\t\t\"latest_measurement\":       1.22354,\n\t\t\t\t\"latest_measurement_error\": 0.00423,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"chrony_sources\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": addr,\n\t\t\t\t\"peer\":   \"ntp2.my.org\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":                    1,\n\t\t\t\t\"ip\":                       \"192.168.0.2\",\n\t\t\t\t\"poll\":                     64,\n\t\t\t\t\"stratum\":                  uint64(16),\n\t\t\t\t\"state\":                    \"sync\",\n\t\t\t\t\"mode\":                     \"peer\",\n\t\t\t\t\"flags\":                    uint64(0),\n\t\t\t\t\"reachability\":             uint64(0),\n\t\t\t\t\"sample\":                   uint64(0),\n\t\t\t\t\"latest_measurement\":       0.35445,\n\t\t\t\t\"latest_measurement_error\": 0.01196,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"chrony_sources\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": addr,\n\t\t\t\t\"peer\":   \"ntp3.my.org\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":                    2,\n\t\t\t\t\"ip\":                       \"192.168.0.3\",\n\t\t\t\t\"poll\":                     512,\n\t\t\t\t\"stratum\":                  uint64(1),\n\t\t\t\t\"state\":                    \"outlier\",\n\t\t\t\t\"mode\":                     \"peer\",\n\t\t\t\t\"flags\":                    uint64(0),\n\t\t\t\t\"reachability\":             uint64(512),\n\t\t\t\t\"sample\":                   uint64(377),\n\t\t\t\t\"latest_measurement\":       7.21158,\n\t\t\t\t\"latest_measurement_error\": 2.15453,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherSourceStats(t *testing.T) {\n\t// Setup a mock server\n\tserver := Server{\n\t\tSourcesInfo: []source{\n\t\t\t{\n\t\t\t\tname: \"ntp1.my.org\",\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              434354566,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 0, 1),\n\t\t\t\t\tNSamples:           1254,\n\t\t\t\t\tNRuns:              16,\n\t\t\t\t\tSpanSeconds:        32,\n\t\t\t\t\tStandardDeviation:  0.0244,\n\t\t\t\t\tResidFreqPPM:       0.0015,\n\t\t\t\t\tSkewPPM:            0.0001,\n\t\t\t\t\tEstimatedOffset:    0.0039,\n\t\t\t\t\tEstimatedOffsetErr: 0.0007,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp2.my.org\",\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              70349595,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 0, 2),\n\t\t\t\t\tNSamples:           23135,\n\t\t\t\t\tNRuns:              24,\n\t\t\t\t\tSpanSeconds:        3,\n\t\t\t\t\tStandardDeviation:  0.0099,\n\t\t\t\t\tResidFreqPPM:       0.0188,\n\t\t\t\t\tSkewPPM:            0.0002,\n\t\t\t\t\tEstimatedOffset:    0.0104,\n\t\t\t\t\tEstimatedOffsetErr: 0.0021,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp3.my.org\",\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              983490438,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 0, 3),\n\t\t\t\t\tNSamples:           23,\n\t\t\t\t\tNRuns:              4,\n\t\t\t\t\tSpanSeconds:        193,\n\t\t\t\t\tStandardDeviation:  7.0586,\n\t\t\t\t\tResidFreqPPM:       0.8320,\n\t\t\t\t\tSkewPPM:            0.0332,\n\t\t\t\t\tEstimatedOffset:    5.3345,\n\t\t\t\t\tEstimatedOffsetErr: 1.5437,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"sourcestats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin, do a gather and stop everything\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.Shutdown()\n\n\t// Do the comparison\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony_sourcestats\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":       addr,\n\t\t\t\t\"peer\":         \"ntp1.my.org\",\n\t\t\t\t\"reference_id\": \"19E3B986\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":              0,\n\t\t\t\t\"ip\":                 \"192.168.0.1\",\n\t\t\t\t\"samples\":            uint64(1254),\n\t\t\t\t\"runs\":               uint64(16),\n\t\t\t\t\"span_seconds\":       uint64(32),\n\t\t\t\t\"stddev\":             0.0244,\n\t\t\t\t\"residual_frequency\": 0.0015,\n\t\t\t\t\"skew\":               0.0001,\n\t\t\t\t\"offset\":             0.0039,\n\t\t\t\t\"offset_error\":       0.0007,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"chrony_sourcestats\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":       addr,\n\t\t\t\t\"peer\":         \"ntp2.my.org\",\n\t\t\t\t\"reference_id\": \"0431731B\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":              1,\n\t\t\t\t\"ip\":                 \"192.168.0.2\",\n\t\t\t\t\"samples\":            uint64(23135),\n\t\t\t\t\"runs\":               uint64(24),\n\t\t\t\t\"span_seconds\":       uint64(3),\n\t\t\t\t\"stddev\":             0.0099,\n\t\t\t\t\"residual_frequency\": 0.0188,\n\t\t\t\t\"skew\":               0.0002,\n\t\t\t\t\"offset\":             0.0104,\n\t\t\t\t\"offset_error\":       0.0021,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"chrony_sourcestats\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":       addr,\n\t\t\t\t\"peer\":         \"ntp3.my.org\",\n\t\t\t\t\"reference_id\": \"3A9EDF86\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"index\":              2,\n\t\t\t\t\"ip\":                 \"192.168.0.3\",\n\t\t\t\t\"samples\":            uint64(23),\n\t\t\t\t\"runs\":               uint64(4),\n\t\t\t\t\"span_seconds\":       uint64(193),\n\t\t\t\t\"stddev\":             7.0586,\n\t\t\t\t\"residual_frequency\": 0.8320,\n\t\t\t\t\"skew\":               0.0332,\n\t\t\t\t\"offset\":             5.3345,\n\t\t\t\t\"offset_error\":       1.5437,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\t// tests on linux with go1.20 will add a warning about code coverage, ignore that tag\n\t\ttestutil.IgnoreTags(\"warning\"),\n\t\ttestutil.IgnoreTime(),\n\t\tcmpopts.EquateApprox(0.001, 0),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"dockurr/chrony\",\n\t\tExposedPorts: []string{\"323/udp\"},\n\t\tFiles: map[string]string{\n\t\t\t\"/etc/telegraf-chrony.conf\": \"testdata/chrony.conf\",\n\t\t\t\"/start.sh\":                 \"testdata/start.sh\",\n\t\t},\n\t\tEntrypoint: []string{\"/start.sh\"},\n\t\tWaitingFor: wait.ForLog(\"Selected source\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\taddr := container.Address + \":\" + container.Ports[\"323\"]\n\n\t// Setup the plugin\n\tplugin := &Chrony{\n\t\tServer: \"udp://\" + addr,\n\t\tLog:    testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"chrony\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":       addr,\n\t\t\t\t\"leap_status\":  \"normal\",\n\t\t\t\t\"reference_id\": \"A29FC87B\",\n\t\t\t\t\"stratum\":      \"4\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"frequency\":       float64(0),\n\t\t\t\t\"last_offset\":     float64(0),\n\t\t\t\t\"residual_freq\":   float64(0),\n\t\t\t\t\"rms_offset\":      float64(0),\n\t\t\t\t\"root_delay\":      float64(0),\n\t\t\t\t\"root_dispersion\": float64(0),\n\t\t\t\t\"skew\":            float64(0),\n\t\t\t\t\"system_time\":     float64(0),\n\t\t\t\t\"update_interval\": float64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTags(\"leap_status\", \"reference_id\", \"stratum\"),\n\t\ttestutil.IgnoreTime(),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, options...)\n}\n\ntype source struct {\n\tname  string\n\tdata  *fbchrony.SourceData\n\tstats *fbchrony.SourceStats\n}\n\ntype Server struct {\n\tActivityInfo   *fbchrony.Activity\n\tTrackingInfo   *fbchrony.Tracking\n\tServerStatInfo interface{}\n\tSourcesInfo    []source\n\n\tconn net.PacketConn\n}\n\nfunc (s *Server) Shutdown() {\n\tif s.conn != nil {\n\t\ts.conn.Close()\n\t}\n}\n\nfunc (s *Server) Listen(t *testing.T) (string, error) {\n\tconn, err := net.ListenPacket(\"udp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ts.conn = conn\n\taddr := s.conn.LocalAddr().String()\n\n\tgo s.serve(t)\n\n\treturn addr, nil\n}\n\nfunc (s *Server) serve(t *testing.T) {\n\tdefer s.conn.Close()\n\n\tfor {\n\t\tbuf := make([]byte, 4096)\n\t\tn, addr, err := s.conn.ReadFrom(buf)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tt.Logf(\"mock server: received %d bytes from %q\\n\", n, addr.String())\n\n\t\tvar header fbchrony.RequestHead\n\t\tdata := bytes.NewBuffer(buf)\n\t\tif err := binary.Read(data, binary.BigEndian, &header); err != nil {\n\t\t\tt.Errorf(\"mock server: reading request header failed: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tseqno := header.Sequence + 1\n\n\t\tt.Logf(\"mock server: received request %d\", header.Command)\n\t\tswitch header.Command {\n\t\tcase 14: // sources\n\t\t\t_, err := s.conn.WriteTo(s.encodeSourcesReply(seqno), addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [sources]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [sources]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 15: // source data\n\t\t\tvar idx int32\n\t\t\tif err = binary.Read(data, binary.BigEndian, &idx); err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t_, err = s.conn.WriteTo(s.encodeSourceDataReply(seqno, idx), addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [source data]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [source data]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 33: // tracking\n\t\t\t_, err := s.conn.WriteTo(s.encodeTrackingReply(seqno), addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [tracking]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [tracking]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 34: // source stats\n\t\t\tvar idx int32\n\t\t\tif err = binary.Read(data, binary.BigEndian, &idx); err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t_, err = s.conn.WriteTo(s.encodeSourceStatsReply(seqno, idx), addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [source stats]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [source stats]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 44: // activity\n\t\t\tpayload, err := s.encodeActivityReply(seqno)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t_, err = s.conn.WriteTo(payload, addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [activity]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [activity]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 54: // server stats\n\t\t\tpayload, err := s.encodeServerStatsReply(seqno)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t_, err = s.conn.WriteTo(payload, addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [serverstats]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [serverstats]: successfully wrote reply\")\n\t\t\t}\n\t\tcase 65: // source name\n\t\t\tbuf := make([]byte, 20)\n\t\t\t_, err := data.Read(buf)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tip := decodeIP(buf)\n\t\t\tt.Logf(\"mock server [source name]: resolving %v\", ip)\n\t\t\t_, err = s.conn.WriteTo(s.encodeSourceNameReply(seqno, ip), addr)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"mock server [source name]: writing reply failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt.Log(\"mock server [source name]: successfully wrote reply\")\n\t\t\t}\n\t\tdefault:\n\t\t\tt.Logf(\"mock server: unhandled command %v\", header.Command)\n\t\t}\n\t}\n}\n\nfunc (s *Server) encodeActivityReply(sequence uint32) ([]byte, error) {\n\t// Encode the header\n\tbuf := encodeHeader(44, 12, 0, sequence) // activity request\n\n\t// Encode data\n\tb := bytes.NewBuffer(buf)\n\tif err := binary.Write(b, binary.BigEndian, s.ActivityInfo); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b.Bytes(), nil\n}\n\nfunc (s *Server) encodeTrackingReply(sequence uint32) []byte {\n\tt := s.TrackingInfo\n\n\t// Encode the header\n\tbuf := encodeHeader(33, 5, 0, sequence) // tracking request\n\n\t// Encode data\n\tbuf = binary.BigEndian.AppendUint32(buf, t.RefID)\n\tbuf = append(buf, encodeIP(t.IPAddr)...)\n\tbuf = binary.BigEndian.AppendUint16(buf, t.Stratum)\n\tbuf = binary.BigEndian.AppendUint16(buf, t.LeapStatus)\n\tsec := uint64(t.RefTime.Unix())\n\tnsec := uint32(t.RefTime.UnixNano() % t.RefTime.Unix() * int64(time.Second))\n\tbuf = binary.BigEndian.AppendUint32(buf, uint32(sec>>32))        // seconds high part\n\tbuf = binary.BigEndian.AppendUint32(buf, uint32(sec&0xffffffff)) // seconds low part\n\tbuf = binary.BigEndian.AppendUint32(buf, nsec)                   // nanoseconds\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.CurrentCorrection))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.LastOffset))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.RMSOffset))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.FreqPPM))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.ResidFreqPPM))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.SkewPPM))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.RootDelay))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.RootDispersion))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(t.LastUpdateInterval))\n\n\treturn buf\n}\n\nfunc (s *Server) encodeServerStatsReply(sequence uint32) ([]byte, error) {\n\tvar b *bytes.Buffer\n\tvar err error\n\n\tswitch info := s.ServerStatInfo.(type) {\n\tcase *fbchrony.ServerStats:\n\t\t// Encode the header\n\t\tbuf := encodeHeader(54, 14, 0, sequence) // activity request\n\n\t\t// Encode data\n\t\tb = bytes.NewBuffer(buf)\n\t\terr = binary.Write(b, binary.BigEndian, info)\n\tcase *fbchrony.ServerStats2:\n\t\t// Encode the header\n\t\tbuf := encodeHeader(54, 22, 0, sequence) // activity request\n\n\t\t// Encode data\n\t\tb = bytes.NewBuffer(buf)\n\t\terr = binary.Write(b, binary.BigEndian, info)\n\tcase *fbchrony.ServerStats3:\n\t\t// Encode the header\n\t\tbuf := encodeHeader(54, 24, 0, sequence) // activity request\n\n\t\t// Encode data\n\t\tb = bytes.NewBuffer(buf)\n\t\terr = binary.Write(b, binary.BigEndian, info)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b.Bytes(), nil\n}\n\nfunc (s *Server) encodeSourcesReply(sequence uint32) []byte {\n\t// Encode the header\n\tbuf := encodeHeader(14, 2, 0, sequence) // sources request\n\n\t// Encode data\n\tbuf = binary.BigEndian.AppendUint32(buf, uint32(len(s.SourcesInfo))) // NSources\n\n\treturn buf\n}\n\nfunc (s *Server) encodeSourceDataReply(sequence uint32, idx int32) []byte {\n\tif len(s.SourcesInfo) <= int(idx) {\n\t\treturn encodeHeader(15, 3, 3, sequence) // status invalid\n\t}\n\tsrc := s.SourcesInfo[idx].data\n\n\t// Encode the header\n\tbuf := encodeHeader(15, 3, 0, sequence) // source data request\n\n\t// Encode data\n\tbuf = append(buf, encodeIP(src.IPAddr)...)\n\tbuf = binary.BigEndian.AppendUint16(buf, uint16(src.Poll))\n\tbuf = binary.BigEndian.AppendUint16(buf, src.Stratum)\n\tbuf = binary.BigEndian.AppendUint16(buf, uint16(src.State))\n\tbuf = binary.BigEndian.AppendUint16(buf, uint16(src.Mode))\n\tbuf = binary.BigEndian.AppendUint16(buf, src.Flags)\n\tbuf = binary.BigEndian.AppendUint16(buf, src.Reachability)\n\tbuf = binary.BigEndian.AppendUint32(buf, src.SinceSample)\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.OrigLatestMeas))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.LatestMeas))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.LatestMeasErr))\n\n\treturn buf\n}\n\nfunc (s *Server) encodeSourceStatsReply(sequence uint32, idx int32) []byte {\n\tif len(s.SourcesInfo) <= int(idx) {\n\t\treturn encodeHeader(34, 6, 3, sequence) // status invalid\n\t}\n\tsrc := s.SourcesInfo[idx].stats\n\n\t// Encode the header\n\tbuf := encodeHeader(15, 6, 0, sequence) // source data request\n\n\t// Encode data\n\tbuf = binary.BigEndian.AppendUint32(buf, src.RefID)\n\tbuf = append(buf, encodeIP(src.IPAddr)...)\n\tbuf = binary.BigEndian.AppendUint32(buf, src.NSamples)\n\tbuf = binary.BigEndian.AppendUint32(buf, src.NRuns)\n\tbuf = binary.BigEndian.AppendUint32(buf, src.SpanSeconds)\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.StandardDeviation))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.ResidFreqPPM))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.SkewPPM))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.EstimatedOffset))\n\tbuf = binary.BigEndian.AppendUint32(buf, encodeFloat(src.EstimatedOffsetErr))\n\n\treturn buf\n}\n\nfunc (s *Server) encodeSourceNameReply(sequence uint32, ip net.IP) []byte {\n\t// Encode the header\n\tbuf := encodeHeader(65, 19, 0, sequence) // source name request\n\n\t// Find the correct source\n\tvar name []byte\n\tfor _, src := range s.SourcesInfo {\n\t\tif src.data != nil && src.data.IPAddr.Equal(ip) || src.stats != nil && src.stats.IPAddr.Equal(ip) {\n\t\t\tname = []byte(src.name)\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Encode data\n\tif len(name) > 256 {\n\t\tbuf = append(buf, name[:256]...)\n\t} else {\n\t\tbuf = append(buf, name...)\n\t\tbuf = append(buf, make([]byte, 256-len(name))...)\n\t}\n\n\treturn buf\n}\n\nfunc encodeHeader(command, replyType, status uint16, seqnr uint32) []byte {\n\tbuf := []byte{\n\t\t0x06, // version 6\n\t\t0x02, // packet type 2: reply\n\t\t0x00, // res1\n\t\t0x00, // res2\n\t}\n\tbuf = binary.BigEndian.AppendUint16(buf, command)   // command\n\tbuf = binary.BigEndian.AppendUint16(buf, replyType) // reply type\n\tbuf = binary.BigEndian.AppendUint16(buf, status)    // status 0: success\n\tbuf = append(buf, []byte{\n\t\t0x00, 0x00, // pad1\n\t\t0x00, 0x00, // pad2\n\t\t0x00, 0x00, // pad3\n\t}...)\n\tbuf = binary.BigEndian.AppendUint32(buf, seqnr)                   // sequence number\n\tbuf = append(buf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) // pad 4 & 5\n\n\treturn buf\n}\n\nfunc encodeIP(addr net.IP) []byte {\n\tvar buf []byte\n\n\tbuf = append(buf, addr.To16()...)\n\tif len(addr) == 4 {\n\t\tbuf = append(buf, 0x00, 0x01) // IPv4 address family\n\t} else {\n\t\tbuf = append(buf, 0x00, 0x02) // IPv6 address family\n\t}\n\tbuf = append(buf, 0x00, 0x00) // padding\n\n\treturn buf\n}\n\nfunc decodeIP(buf []byte) net.IP {\n\tif len(buf) != 20 {\n\t\tpanic(\"invalid length for IP\")\n\t}\n\n\taddr := net.IP(buf[0:16])\n\tfamily := binary.BigEndian.Uint16(buf[16:18])\n\tif family == 1 {\n\t\treturn addr.To4()\n\t}\n\n\treturn addr\n}\n\n// Modified based on https://github.com/mlichvar/chrony/blob/master/util.c\nconst (\n\tfloatExpBits   = int32(7)\n\tfloatCoeffBits = int32(25) // 32 - floatExpBits\n\tfloatExpMin    = int32(-(1 << (floatExpBits - 1)))\n\tfloatExpMax    = -floatExpMin - 1\n\tfloatCoefMin   = int32(-(1 << (floatCoeffBits - 1)))\n\tfloatCoefMax   = -floatCoefMin - 1\n)\n\nfunc encodeFloat(x float64) uint32 {\n\tvar neg int32\n\n\tif math.IsNaN(x) {\n\t\t/* Save NaN as zero */\n\t\tx = 0.0\n\t} else if x < 0.0 {\n\t\tx = -x\n\t\tneg = 1\n\t}\n\n\tvar exp, coef int32\n\tif x > 1.0e100 {\n\t\texp = floatExpMax\n\t\tcoef = floatCoefMax + neg\n\t} else if x > 1.0e-100 {\n\t\texp = int32(math.Log2(x)) + 1\n\t\tcoef = int32(x*math.Pow(2.0, float64(-exp+floatCoeffBits)) + 0.5)\n\n\t\tif coef <= 0 {\n\t\t\tpanic(fmt.Errorf(\"invalid coefficient %v for value %f\", coef, x))\n\t\t}\n\n\t\t/* we may need to shift up to two bits down */\n\t\tfor coef > floatCoefMax+neg {\n\t\t\tcoef >>= 1\n\t\t\texp++\n\t\t}\n\n\t\tif exp > floatExpMax {\n\t\t\t/* overflow */\n\t\t\texp = floatExpMax\n\t\t\tcoef = floatCoefMax + neg\n\t\t} else if exp < floatExpMin {\n\t\t\t/* underflow */\n\t\t\tif exp+floatCoeffBits >= floatExpMin {\n\t\t\t\tcoef >>= floatExpMin - exp\n\t\t\t\texp = floatExpMin\n\t\t\t} else {\n\t\t\t\texp = 0\n\t\t\t\tcoef = 0\n\t\t\t}\n\t\t}\n\t}\n\n\t/* negate back */\n\tif neg != 0 {\n\t\tcoef = int32(uint32(-coef) % (1 << floatCoeffBits))\n\t}\n\n\treturn uint32(exp<<floatCoeffBits) | uint32(coef)\n}\n\n// TestConcurrentGather verifies that concurrent Gather() calls don't cause\n// a race condition or panic when accessing the shared chrony client.\n// This test addresses the issue reported in GitHub issue #17757 where\n// concurrent access to the client caused \"index out of range [256] with length 256\" panics.\nfunc TestConcurrentGather(t *testing.T) {\n\t// Setup a mock server with multiple sources to ensure longer gather time\n\tserver := Server{\n\t\tActivityInfo: &fbchrony.Activity{\n\t\t\tOnline:       10,\n\t\t\tOffline:      2,\n\t\t\tBurstOnline:  1,\n\t\t\tBurstOffline: 0,\n\t\t\tUnresolved:   3,\n\t\t},\n\t\tTrackingInfo: &fbchrony.Tracking{\n\t\t\tRefID:              0xA29FC87B,\n\t\t\tIPAddr:             net.ParseIP(\"192.168.1.22\"),\n\t\t\tStratum:            3,\n\t\t\tLeapStatus:         0,\n\t\t\tRefTime:            time.Now(),\n\t\t\tCurrentCorrection:  0.000020390,\n\t\t\tLastOffset:         0.000012651,\n\t\t\tRMSOffset:          0.000025577,\n\t\t\tFreqPPM:            -16.001,\n\t\t\tResidFreqPPM:       0.0,\n\t\t\tSkewPPM:            0.006,\n\t\t\tRootDelay:          0.001655,\n\t\t\tRootDispersion:     0.003307,\n\t\t\tLastUpdateInterval: 507.2,\n\t\t},\n\t\tServerStatInfo: &fbchrony.ServerStats{\n\t\t\tNTPHits:  2542,\n\t\t\tCMDHits:  112,\n\t\t\tNTPDrops: 42,\n\t\t\tCMDDrops: 8,\n\t\t\tLogDrops: 0,\n\t\t},\n\t\tSourcesInfo: []source{\n\t\t\t{\n\t\t\t\tname: \"ntp1.example.com\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 1, 1),\n\t\t\t\t\tPoll:           64,\n\t\t\t\t\tStratum:        2,\n\t\t\t\t\tState:          fbchrony.SourceStateSync,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   255,\n\t\t\t\t\tSinceSample:    0,\n\t\t\t\t\tOrigLatestMeas: 0.001,\n\t\t\t\t\tLatestMeas:     0.001,\n\t\t\t\t\tLatestMeasErr:  0.0001,\n\t\t\t\t},\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              434354566,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 1, 1),\n\t\t\t\t\tNSamples:           100,\n\t\t\t\t\tNRuns:              10,\n\t\t\t\t\tSpanSeconds:        1000,\n\t\t\t\t\tStandardDeviation:  0.001,\n\t\t\t\t\tResidFreqPPM:       0.0001,\n\t\t\t\t\tSkewPPM:            0.0001,\n\t\t\t\t\tEstimatedOffset:    0.0001,\n\t\t\t\t\tEstimatedOffsetErr: 0.00001,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp2.example.com\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 1, 2),\n\t\t\t\t\tPoll:           64,\n\t\t\t\t\tStratum:        2,\n\t\t\t\t\tState:          fbchrony.SourceStateSync,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   255,\n\t\t\t\t\tSinceSample:    0,\n\t\t\t\t\tOrigLatestMeas: 0.002,\n\t\t\t\t\tLatestMeas:     0.002,\n\t\t\t\t\tLatestMeasErr:  0.0002,\n\t\t\t\t},\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              434354567,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 1, 2),\n\t\t\t\t\tNSamples:           100,\n\t\t\t\t\tNRuns:              10,\n\t\t\t\t\tSpanSeconds:        1000,\n\t\t\t\t\tStandardDeviation:  0.002,\n\t\t\t\t\tResidFreqPPM:       0.0002,\n\t\t\t\t\tSkewPPM:            0.0002,\n\t\t\t\t\tEstimatedOffset:    0.0002,\n\t\t\t\t\tEstimatedOffsetErr: 0.00002,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ntp3.example.com\",\n\t\t\t\tdata: &fbchrony.SourceData{\n\t\t\t\t\tIPAddr:         net.IPv4(192, 168, 1, 3),\n\t\t\t\t\tPoll:           64,\n\t\t\t\t\tStratum:        2,\n\t\t\t\t\tState:          fbchrony.SourceStateSync,\n\t\t\t\t\tMode:           fbchrony.SourceModePeer,\n\t\t\t\t\tFlags:          0,\n\t\t\t\t\tReachability:   255,\n\t\t\t\t\tSinceSample:    0,\n\t\t\t\t\tOrigLatestMeas: 0.003,\n\t\t\t\t\tLatestMeas:     0.003,\n\t\t\t\t\tLatestMeasErr:  0.0003,\n\t\t\t\t},\n\t\t\t\tstats: &fbchrony.SourceStats{\n\t\t\t\t\tRefID:              434354568,\n\t\t\t\t\tIPAddr:             net.IPv4(192, 168, 1, 3),\n\t\t\t\t\tNSamples:           100,\n\t\t\t\t\tNRuns:              10,\n\t\t\t\t\tSpanSeconds:        1000,\n\t\t\t\t\tStandardDeviation:  0.003,\n\t\t\t\t\tResidFreqPPM:       0.0003,\n\t\t\t\t\tSkewPPM:            0.0003,\n\t\t\t\t\tEstimatedOffset:    0.0003,\n\t\t\t\t\tEstimatedOffsetErr: 0.00003,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\t// Setup the plugin with all metrics enabled to maximize the gather time\n\t// and increase the likelihood of concurrent access\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"activity\", \"tracking\", \"serverstats\", \"sources\", \"sourcestats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(nil))\n\tdefer plugin.Stop()\n\n\t// Run multiple concurrent Gather() calls\n\t// This simulates what happens when a previous gather hasn't completed\n\t// before the next interval triggers\n\tconst numConcurrent = 10\n\tvar wg sync.WaitGroup\n\terrors := make(chan error, numConcurrent)\n\n\tfor i := 0; i < numConcurrent; i++ {\n\t\twg.Add(1)\n\t\tgo func(iteration int) {\n\t\t\tdefer wg.Done()\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tif err := plugin.Gather(&acc); err != nil {\n\t\t\t\terrors <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Verify we got metrics (no panic occurred)\n\t\t\tif len(acc.GetTelegrafMetrics()) == 0 {\n\t\t\t\tt.Logf(\"iteration %d: no metrics collected\", iteration)\n\t\t\t}\n\t\t}(i)\n\t}\n\n\t// Wait for all goroutines to complete\n\twg.Wait()\n\tclose(errors)\n\n\t// Check if any errors occurred\n\tfor err := range errors {\n\t\trequire.NoError(t, err, \"concurrent gather should not produce errors\")\n\t}\n}\n\n// TestRaceDetector runs the test with the Go race detector enabled.\nfunc TestRaceDetector(t *testing.T) {\n\t// Setup a minimal mock server\n\tserver := Server{\n\t\tServerStatInfo: &fbchrony.ServerStats{\n\t\t\tNTPHits:  100,\n\t\t\tCMDHits:  10,\n\t\t\tNTPDrops: 1,\n\t\t\tCMDDrops: 0,\n\t\t\tLogDrops: 0,\n\t\t},\n\t}\n\taddr, err := server.Listen(t)\n\trequire.NoError(t, err)\n\tdefer server.Shutdown()\n\n\tplugin := &Chrony{\n\t\tServer:  \"udp://\" + addr,\n\t\tMetrics: []string{\"serverstats\"},\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(nil))\n\tdefer plugin.Stop()\n\n\t// Run 100 concurrent gathers to give the race detector\n\t// a better chance of catching any race conditions\n\tconst iterations = 100\n\tvar wg sync.WaitGroup\n\terrors := make(chan error, iterations)\n\n\tfor i := 0; i < iterations; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tvar acc testutil.Accumulator\n\t\t\tif err := plugin.Gather(&acc); err != nil {\n\t\t\t\terrors <- err\n\t\t\t}\n\t\t}()\n\t}\n\n\twg.Wait()\n\tclose(errors)\n\n\t// Check if any errors occurred\n\tfor err := range errors {\n\t\trequire.NoError(t, err)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/chrony/sample.conf",
    "content": "# Get standard chrony metrics.\n[[inputs.chrony]]\n  ## Server address of chronyd with address scheme\n  ## If empty or not set, the plugin will mimic the behavior of chronyc and\n  ## check \"unixgram:///run/chrony/chronyd.sock\", \"udp://127.0.0.1:323\"\n  ## and \"udp://[::1]:323\".\n  # server = \"\"\n\n  ## Timeout for establishing the connection\n  # timeout = \"5s\"\n\n  ## Try to resolve received addresses to host-names via DNS lookups\n  ## Disabled by default to avoid DNS queries especially for slow DNS servers.\n  # dns_lookup = false\n\n  ## Metrics to query named according to chronyc commands\n  ## Available settings are:\n  ##   activity    -- number of peers online or offline\n  ##   tracking    -- information about system's clock performance\n  ##   serverstats -- chronyd server statistics\n  ##   sources     -- extended information about peers\n  ##   sourcestats -- statistics on peers\n  # metrics = [\"tracking\"]\n\n  ## Socket group & permissions\n  ## If the user requests collecting metrics via unix socket, then it is created\n  ## with the following group and permissions.\n  # socket_group = \"chrony\"\n  # socket_perms = \"0660\"\n"
  },
  {
    "path": "plugins/inputs/chrony/testdata/chrony.conf",
    "content": "server 0.pool.ntp.org iburst\nserver 1.pool.ntp.org iburst\nserver 2.pool.ntp.org iburst\nserver 3.pool.ntp.org iburst\n\ndriftfile /var/lib/chrony/chrony.drift\nmakestep 0.1 3\n\nbindcmdaddress 0.0.0.0\ncmdallow all\nallow all"
  },
  {
    "path": "plugins/inputs/chrony/testdata/start.sh",
    "content": "#!/bin/sh\n\n# confirm correct permissions on chrony run directory\nif [ -d /run/chrony ]; then\n  chown -R chrony:chrony /run/chrony\n  chmod o-rx /run/chrony\n  # remove previous pid file if it exist\n  rm -f /var/run/chrony/chronyd.pid\nfi\n\n# confirm correct permissions on chrony variable state directory\nif [ -d /var/lib/chrony ]; then\n  chown -R chrony:chrony /var/lib/chrony\nfi\n\n## startup chronyd in the foreground\nexec /usr/sbin/chronyd -u chrony -d -x -f /etc/telegraf-chrony.conf"
  },
  {
    "path": "plugins/inputs/cisco_telemetry_mdt/README.md",
    "content": "# Cisco Model-Driven Telemetry (MDT) Input Plugin\n\nThis plugin consumes [Cisco model-driven telemetry (MDT)][cisco_mdt] data from\nCisco IOS XR, IOS XE and NX-OS platforms via TCP or GRPC. GRPC-based transport\ncan utilize TLS for authentication and encryption. Telemetry data is expected to\nbe GPB-KV (self-describing-gpb) encoded.\n\nThe GRPC dialout transport is supported on various IOS XR (64-bit) 6.1.x and\nlater, IOS XE 16.10 and later, as well as NX-OS 7.x and later platforms. The\nTCP dialout transport is supported on IOS XR (32-bit and 64-bit) 6.1.x and\nlater.\n\n⭐ Telegraf v1.11.0\n🏷️ applications\n💻 all\n\n[cisco_mdt]: https://www.cisco.com/c/en/us/products/collateral/switches/catalyst-9300-series-switches/model-driven-telemetry-wp.html\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Cisco model-driven telemetry (MDT) input plugin for IOS XR, IOS XE and NX-OS platforms\n[[inputs.cisco_telemetry_mdt]]\n ## Telemetry transport can be \"tcp\" or \"grpc\".  TLS is only supported when\n ## using the grpc transport.\n transport = \"grpc\"\n\n ## Address and port to host telemetry listener\n service_address = \":57000\"\n\n ## Grpc Maximum Message Size, default is 4MB, increase the size. This is\n ## stored as a uint32, and limited to 4294967295.\n max_msg_size = 4000000\n\n ## Enable TLS; grpc transport only.\n # tls_cert = \"/etc/telegraf/cert.pem\"\n # tls_key = \"/etc/telegraf/key.pem\"\n\n ## Enable TLS client authentication and define allowed CA certificates; grpc\n ##  transport only.\n # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n ## Define (for certain nested telemetry measurements with embedded tags) which fields are tags\n # embedded_tags = [\"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics/class-stats/class-name\"]\n\n ## Include the delete field in every telemetry message.\n # include_delete_field = false\n\n ## Specify custom name for incoming MDT source field.\n # source_field_name = \"mdt_source\"\n\n ## Define aliases to map telemetry encoding paths to simple measurement names\n [inputs.cisco_telemetry_mdt.aliases]\n   ifstats = \"ietf-interfaces:interfaces-state/interface/statistics\"\n ## Define Property Xformation, please refer README and https://pubhub.devnetcloud.com/media/dme-docs-9-3-3/docs/appendix/ for Model details.\n [inputs.cisco_telemetry_mdt.dmes]\n#    Global Property Xformation.\n#    prop1 = \"uint64 to int\"\n#    prop2 = \"uint64 to string\"\n#    prop3 = \"string to uint64\"\n#    prop4 = \"string to int64\"\n#    prop5 = \"string to float64\"\n#    auto-prop-xfrom = \"auto-float-xfrom\" #Xform any property which is string, and has float number to type float64\n#    Per Path property xformation, Name is telemetry configuration under sensor-group, path configuration \"WORD         Distinguished Name\"\n#    Per Path configuration is better as it avoid property collision issue of types.\n#    dnpath = '{\"Name\": \"show ip route summary\",\"prop\": [{\"Key\": \"routes\",\"Value\": \"string\"}, {\"Key\": \"best-paths\",\"Value\": \"string\"}]}'\n#    dnpath2 = '{\"Name\": \"show processes cpu\",\"prop\": [{\"Key\": \"kernel_percent\",\"Value\": \"float\"}, {\"Key\": \"idle_percent\",\"Value\": \"float\"}, {\"Key\": \"process\",\"Value\": \"string\"}, {\"Key\": \"user_percent\",\"Value\": \"float\"}, {\"Key\": \"onesec\",\"Value\": \"float\"}]}'\n#    dnpath3 = '{\"Name\": \"show processes memory physical\",\"prop\": [{\"Key\": \"processname\",\"Value\": \"string\"}]}'\n\n ## Additional GRPC connection settings.\n [inputs.cisco_telemetry_mdt.grpc_enforcement_policy]\n  ## GRPC permit keepalives without calls, set to true if your clients are\n  ## sending pings without calls in-flight. This can sometimes happen on IOS-XE\n  ## devices where the GRPC connection is left open but subscriptions have been\n  ## removed, and adding subsequent subscriptions does not keep a stable session.\n  # permit_keepalive_without_calls = false\n\n  ## GRPC minimum timeout between successive pings, decreasing this value may\n  ## help if this plugin is closing connections with ENHANCE_YOUR_CALM (too_many_pings).\n  # keepalive_minimum_time = \"5m\"\n```\n\n## Metrics\n\nMetrics are named by the encoding path that generated the data, or by the alias\nif the `inputs.cisco_telemetry_mdt.aliases` config section is defined.\nMetric fields are dependent on the device type and path.\n\nTags included in all metrics:\n\n- source\n- path\n- subscription\n\nAdditional tags (such as interface_name) may be included depending on the path.\n\n## Example Output\n\n```text\nifstats,path=ietf-interfaces:interfaces-state/interface/statistics,host=linux,name=GigabitEthernet2,source=csr1kv,subscription=101 in-unicast-pkts=27i,in-multicast-pkts=0i,discontinuity-time=\"2019-05-23T07:40:23.000362+00:00\",in-octets=5233i,in-errors=0i,out-multicast-pkts=0i,out-discards=0i,in-broadcast-pkts=0i,in-discards=0i,in-unknown-protos=0i,out-unicast-pkts=0i,out-broadcast-pkts=0i,out-octets=0i,out-errors=0i 1559150462624000000\nifstats,path=ietf-interfaces:interfaces-state/interface/statistics,host=linux,name=GigabitEthernet1,source=csr1kv,subscription=101 in-octets=3394770806i,in-broadcast-pkts=0i,in-multicast-pkts=0i,out-broadcast-pkts=0i,in-unknown-protos=0i,out-octets=350212i,in-unicast-pkts=9477273i,in-discards=0i,out-unicast-pkts=2726i,out-discards=0i,discontinuity-time=\"2019-05-23T07:40:23.000363+00:00\",in-errors=30i,out-multicast-pkts=0i,out-errors=0i 1559150462624000000\n```\n\n### NX-OS Configuration Example\n\n```text\nRequirement      DATA-SOURCE   Configuration\n-----------------------------------------\nEnvironment      DME           path sys/ch query-condition query-target=subtree&target-subtree-class=eqptPsuSlot,eqptFtSlot,eqptSupCSlot,eqptPsu,eqptFt,eqptSensor,eqptLCSlot\n                 DME           path sys/ch depth 5  (Another configuration option)\nEnvironment      NXAPI         show environment power\n                 NXAPI         show environment fan\n                 NXAPI         show environment temperature\nInterface Stats  DME           path sys/intf query-condition query-target=subtree&target-subtree-class=rmonIfIn,rmonIfOut,rmonIfHCIn,rmonIfHCOut,rmonEtherStats\nInterface State  DME           path sys/intf depth unbounded query-condition query-target=subtree&target-subtree-class=l1PhysIf,pcAggrIf,l3EncRtdIf,l3LbRtdIf,ethpmPhysIf\nVPC              DME           path sys/vpc query-condition query-target=subtree&target-subtree-class=vpcDom,vpcIf\nResources cpu    DME           path sys/procsys query-condition query-target=subtree&target-subtree-class=procSystem,procSysCore,procSysCpuSummary,procSysCpu,procIdle,procIrq,procKernel,procNice,procSoftirq,procTotal,procUser,procWait,procSysCpuHistory,procSysLoad\nResources Mem    DME           path sys/procsys/sysmem/sysmemused\n                               path sys/procsys/sysmem/sysmemusage\n                               path sys/procsys/sysmem/sysmemfree\nPer Process cpu  DME           path sys/proc depth unbounded query-condition rsp-foreign-subtree=ephemeral\nvxlan(svi stats) DME           path sys/bd query-condition query-target=subtree&target-subtree-class=l2VlanStats\nBGP              DME           path sys/bgp query-condition query-target=subtree&target-subtree-class=bgpDom,bgpPeer,bgpPeerAf,bgpDomAf,bgpPeerAfEntry,bgpOperRtctrlL3,bgpOperRttP,bgpOperRttEntry,bgpOperAfCtrl\nmac dynamic      DME           path sys/mac query-condition query-target=subtree&target-subtree-class=l2MacAddressTable\nbfd              DME           path sys/bfd/inst depth unbounded\nlldp             DME           path sys/lldp depth unbounded\nurib             DME           path sys/urib depth unbounded query-condition rsp-foreign-subtree=ephemeral\nu6rib            DME           path sys/u6rib depth unbounded query-condition rsp-foreign-subtree=ephemeral\nmulticast flow   DME           path sys/mca/show/flows depth unbounded\nmulticast stats  DME           path sys/mca/show/stats depth unbounded\nmulticast igmp   NXAPI         show ip igmp groups vrf all\nmulticast igmp   NXAPI         show ip igmp interface vrf all\nmulticast igmp   NXAPI         show ip igmp snooping\nmulticast igmp   NXAPI         show ip igmp snooping groups\nmulticast igmp   NXAPI         show ip igmp snooping groups detail\nmulticast igmp   NXAPI         show ip igmp snooping groups summary\nmulticast igmp   NXAPI         show ip igmp snooping mrouter\nmulticast igmp   NXAPI         show ip igmp snooping statistics\nmulticast pim    NXAPI         show ip pim interface vrf all\nmulticast pim    NXAPI         show ip pim neighbor vrf all\nmulticast pim    NXAPI         show ip pim route vrf all\nmulticast pim    NXAPI         show ip pim rp vrf all\nmulticast pim    NXAPI         show ip pim statistics vrf all\nmulticast pim    NXAPI         show ip pim vrf all\nmicroburst       NATIVE        path microburst\n```\n"
  },
  {
    "path": "plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_mdt.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cisco_telemetry_mdt\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tmdtdialout \"github.com/cisco-ie/nx-telemetry-proto/mdt_dialout\"\n\ttelemetry \"github.com/cisco-ie/nx-telemetry-proto/telemetry_bis\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t_ \"google.golang.org/grpc/encoding/gzip\" // Required to allow gzip encoding\n\t\"google.golang.org/grpc/keepalive\"\n\t\"google.golang.org/grpc/peer\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// Maximum telemetry payload size (in bytes) to accept for GRPC dialout transport\n\ttcpMaxMsgLen uint32 = 1024 * 1024\n\n\t// default minimum time between successive pings\n\t// this value is specified in the GRPC docs via GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS\n\tdefaultKeepaliveMinTime = config.Duration(time.Second * 300)\n)\n\n// CiscoTelemetryMDT plugin for IOS XR, IOS XE and NXOS platforms\ntype CiscoTelemetryMDT struct {\n\t// Common configuration\n\tTransport          string                `toml:\"transport\"`\n\tServiceAddress     string                `toml:\"service_address\"`\n\tMaxMsgSize         int                   `toml:\"max_msg_size\"`\n\tAliases            map[string]string     `toml:\"aliases\"`\n\tDmes               map[string]string     `toml:\"dmes\"`\n\tEmbeddedTags       []string              `toml:\"embedded_tags\"`\n\tEnforcementPolicy  grpcEnforcementPolicy `toml:\"grpc_enforcement_policy\"`\n\tIncludeDeleteField bool                  `toml:\"include_delete_field\"`\n\tSourceFieldName    string                `toml:\"source_field_name\"`\n\n\tLog telegraf.Logger\n\n\t// GRPC TLS settings\n\tcommon_tls.ServerConfig\n\n\t// Internal listener / client handle\n\tgrpcServer *grpc.Server\n\tlistener   net.Listener\n\n\t// Internal state\n\tinternalAliases map[string]string\n\tdmesFuncs       map[string]string\n\twarned          map[string]struct{}\n\textraTags       map[string]map[string]struct{}\n\tnxpathMap       map[string]map[string]string // per path map\n\tpropMap         map[string]func(field *telemetry.TelemetryField, value interface{}) interface{}\n\tmutex           sync.Mutex\n\tacc             telegraf.Accumulator\n\twg              sync.WaitGroup\n\n\t// Though unused in the code, required by protoc-gen-go-grpc to maintain compatibility\n\tmdtdialout.UnimplementedGRPCMdtDialoutServer\n}\n\ntype grpcEnforcementPolicy struct {\n\tPermitKeepaliveWithoutCalls bool            `toml:\"permit_keepalive_without_calls\"`\n\tKeepaliveMinTime            config.Duration `toml:\"keepalive_minimum_time\"`\n}\n\ntype nxPayloadXfromStructure struct {\n\tName string `json:\"Name\"`\n\tProp []struct {\n\t\tKey   string `json:\"Key\"`\n\t\tValue string `json:\"Value\"`\n\t} `json:\"prop\"`\n}\n\nfunc (*CiscoTelemetryMDT) SampleConfig() string {\n\treturn sampleConfig\n}\n\n// Start the Cisco MDT service\nfunc (c *CiscoTelemetryMDT) Start(acc telegraf.Accumulator) error {\n\tvar err error\n\tc.acc = acc\n\tc.listener, err = net.Listen(\"tcp\", c.ServiceAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.propMap = make(map[string]func(field *telemetry.TelemetryField, value interface{}) interface{}, 100)\n\tc.propMap[\"test\"] = nxosValueXformUint64Toint64\n\tc.propMap[\"asn\"] = nxosValueXformUint64ToString            // uint64 to string.\n\tc.propMap[\"subscriptionId\"] = nxosValueXformUint64ToString // uint64 to string.\n\tc.propMap[\"operState\"] = nxosValueXformUint64ToString      // uint64 to string.\n\n\t// Invert aliases list\n\tc.warned = make(map[string]struct{})\n\tc.internalAliases = make(map[string]string, len(c.Aliases))\n\tfor alias, encodingPath := range c.Aliases {\n\t\tc.internalAliases[encodingPath] = alias\n\t}\n\tc.initDB()\n\n\tc.dmesFuncs = make(map[string]string, len(c.Dmes))\n\tfor dme, dmeKey := range c.Dmes {\n\t\tc.dmesFuncs[dmeKey] = dme\n\t\tswitch dmeKey {\n\t\tcase \"uint64 to int\":\n\t\t\tc.propMap[dme] = nxosValueXformUint64Toint64\n\t\tcase \"uint64 to string\":\n\t\t\tc.propMap[dme] = nxosValueXformUint64ToString\n\t\tcase \"string to float64\":\n\t\t\tc.propMap[dme] = nxosValueXformStringTofloat\n\t\tcase \"string to uint64\":\n\t\t\tc.propMap[dme] = nxosValueXformStringToUint64\n\t\tcase \"string to int64\":\n\t\t\tc.propMap[dme] = nxosValueXformStringToInt64\n\t\tcase \"auto-float-xfrom\":\n\t\t\tc.propMap[dme] = nxosValueAutoXformFloatProp\n\t\tdefault:\n\t\t\tif !strings.HasPrefix(dme, \"dnpath\") { // not path based property map\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar jsStruct nxPayloadXfromStructure\n\t\t\terr := json.Unmarshal([]byte(dmeKey), &jsStruct)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Build 2 level Hash nxpathMap Key = jsStruct.Name, Value = map of jsStruct.Prop\n\t\t\t// It will override the default of code if same path is provided in configuration.\n\t\t\tc.nxpathMap[jsStruct.Name] = make(map[string]string, len(jsStruct.Prop))\n\t\t\tfor _, prop := range jsStruct.Prop {\n\t\t\t\tc.nxpathMap[jsStruct.Name][prop.Key] = prop.Value\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fill extra tags\n\tc.extraTags = make(map[string]map[string]struct{})\n\tfor _, tag := range c.EmbeddedTags {\n\t\tdir := strings.ReplaceAll(path.Dir(tag), \"-\", \"_\")\n\t\tif _, hasKey := c.extraTags[dir]; !hasKey {\n\t\t\tc.extraTags[dir] = make(map[string]struct{})\n\t\t}\n\t\tc.extraTags[dir][path.Base(tag)] = struct{}{}\n\t}\n\n\tswitch c.Transport {\n\tcase \"tcp\":\n\t\t// TCP dialout server accept routine\n\t\tc.wg.Add(1)\n\t\tgo func() {\n\t\t\tc.acceptTCPClients()\n\t\t\tc.wg.Done()\n\t\t}()\n\n\tcase \"grpc\":\n\t\tvar opts []grpc.ServerOption\n\t\ttlsConfig, err := c.ServerConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\tc.listener.Close()\n\t\t\treturn err\n\t\t} else if tlsConfig != nil {\n\t\t\topts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig)))\n\t\t}\n\n\t\tif c.MaxMsgSize > 0 {\n\t\t\topts = append(opts, grpc.MaxRecvMsgSize(c.MaxMsgSize))\n\t\t}\n\n\t\tif c.EnforcementPolicy.PermitKeepaliveWithoutCalls ||\n\t\t\t(c.EnforcementPolicy.KeepaliveMinTime != 0 && c.EnforcementPolicy.KeepaliveMinTime != defaultKeepaliveMinTime) {\n\t\t\t// Only set if either parameter does not match defaults\n\t\t\topts = append(opts, grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{\n\t\t\t\tMinTime:             time.Duration(c.EnforcementPolicy.KeepaliveMinTime),\n\t\t\t\tPermitWithoutStream: c.EnforcementPolicy.PermitKeepaliveWithoutCalls,\n\t\t\t}))\n\t\t}\n\n\t\tc.grpcServer = grpc.NewServer(opts...)\n\t\tmdtdialout.RegisterGRPCMdtDialoutServer(c.grpcServer, c)\n\n\t\tc.wg.Add(1)\n\t\tgo func() {\n\t\t\tif err := c.grpcServer.Serve(c.listener); err != nil {\n\t\t\t\tc.Log.Errorf(\"serving GRPC server failed: %v\", err)\n\t\t\t}\n\t\t\tc.wg.Done()\n\t\t}()\n\n\tdefault:\n\t\tc.listener.Close()\n\t\treturn fmt.Errorf(\"invalid Cisco MDT transport: %s\", c.Transport)\n\t}\n\n\treturn nil\n}\n\nfunc (*CiscoTelemetryMDT) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\n// Stop listener and cleanup\nfunc (c *CiscoTelemetryMDT) Stop() {\n\tif c.grpcServer != nil {\n\t\t// Stop server and terminate all running dialout routines\n\t\tc.grpcServer.Stop()\n\t}\n\tif c.listener != nil {\n\t\tc.listener.Close()\n\t}\n\tc.wg.Wait()\n}\n\n// MdtDialout RPC server method for grpc-dialout transport\nfunc (c *CiscoTelemetryMDT) MdtDialout(stream mdtdialout.GRPCMdtDialout_MdtDialoutServer) error {\n\tpeerInCtx, peerOK := peer.FromContext(stream.Context())\n\tif peerOK {\n\t\tc.Log.Debugf(\"Accepted Cisco MDT GRPC dialout connection from %s\", peerInCtx.Addr)\n\t}\n\n\tvar chunkBuffer bytes.Buffer\n\n\tfor {\n\t\tpacket, err := stream.Recv()\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, io.EOF) {\n\t\t\t\tc.acc.AddError(fmt.Errorf(\"receive error during GRPC dialout: %w\", err))\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif len(packet.Data) == 0 && len(packet.Errors) != 0 {\n\t\t\tc.acc.AddError(fmt.Errorf(\"error during GRPC dialout: %s\", packet.Errors))\n\t\t\tbreak\n\t\t}\n\n\t\t// Reassemble chunked telemetry data received from NX-OS\n\t\tif packet.TotalSize == 0 {\n\t\t\tc.handleTelemetry(packet.Data)\n\t\t} else if int(packet.TotalSize) <= c.MaxMsgSize {\n\t\t\tchunkBuffer.Write(packet.Data)\n\t\t\tif chunkBuffer.Len() >= int(packet.TotalSize) {\n\t\t\t\tc.handleTelemetry(chunkBuffer.Bytes())\n\t\t\t\tchunkBuffer.Reset()\n\t\t\t}\n\t\t} else {\n\t\t\tc.acc.AddError(fmt.Errorf(\"dropped too large packet: %dB > %dB\", packet.TotalSize, c.MaxMsgSize))\n\t\t}\n\t}\n\n\tif peerOK {\n\t\tc.Log.Debugf(\"Closed Cisco MDT GRPC dialout connection from %s\", peerInCtx.Addr)\n\t}\n\n\treturn nil\n}\n\n// acceptTCPClients defines the TCP dialout server main routine\nfunc (c *CiscoTelemetryMDT) acceptTCPClients() {\n\t// Keep track of all active connections, so we can close them if necessary\n\tvar mutex sync.Mutex\n\tclients := make(map[net.Conn]struct{})\n\n\tfor {\n\t\tconn, err := c.listener.Accept()\n\t\tvar neterr *net.OpError\n\t\tif errors.As(err, &neterr) && (neterr.Timeout() || neterr.Temporary()) {\n\t\t\tcontinue\n\t\t} else if err != nil {\n\t\t\tbreak // Stop() will close the connection so Accept() will fail here\n\t\t}\n\n\t\tmutex.Lock()\n\t\tclients[conn] = struct{}{}\n\t\tmutex.Unlock()\n\n\t\t// Individual client connection routine\n\t\tc.wg.Add(1)\n\t\tgo func() {\n\t\t\tc.Log.Debugf(\"Accepted Cisco MDT TCP dialout connection from %s\", conn.RemoteAddr())\n\t\t\terr := c.handleTCPClient(conn)\n\t\t\tif err != nil {\n\t\t\t\tc.acc.AddError(err)\n\t\t\t}\n\t\t\tc.Log.Debugf(\"Closed Cisco MDT TCP dialout connection from %s\", conn.RemoteAddr())\n\n\t\t\tmutex.Lock()\n\t\t\tdelete(clients, conn)\n\t\t\tmutex.Unlock()\n\n\t\t\tif err := conn.Close(); err != nil {\n\t\t\t\tc.Log.Warnf(\"closing connection failed: %v\", err)\n\t\t\t}\n\t\t\tc.wg.Done()\n\t\t}()\n\t}\n\n\t// Close all remaining client connections\n\tmutex.Lock()\n\tfor client := range clients {\n\t\tif err := client.Close(); err != nil {\n\t\t\tc.Log.Errorf(\"Failed to close TCP dialout client: %v\", err)\n\t\t}\n\t}\n\tmutex.Unlock()\n}\n\n// Handle a TCP telemetry client\nfunc (c *CiscoTelemetryMDT) handleTCPClient(conn net.Conn) error {\n\t// TCP Dialout telemetry framing header\n\tvar hdr struct {\n\t\tMsgType       uint16\n\t\tMsgEncap      uint16\n\t\tMsgHdrVersion uint16\n\t\tMsgFlags      uint16\n\t\tMsgLen        uint32\n\t}\n\n\tvar payload bytes.Buffer\n\n\tfor {\n\t\t// Read and validate dialout telemetry header\n\t\tif err := binary.Read(conn, binary.BigEndian, &hdr); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tmaxMsgSize := tcpMaxMsgLen\n\t\tif c.MaxMsgSize > 0 {\n\t\t\tmaxMsgSize = uint32(c.MaxMsgSize)\n\t\t}\n\n\t\tif hdr.MsgLen > maxMsgSize {\n\t\t\treturn fmt.Errorf(\"dialout packet too long: %v\", hdr.MsgLen)\n\t\t} else if hdr.MsgFlags != 0 {\n\t\t\treturn fmt.Errorf(\"invalid dialout flags: %v\", hdr.MsgFlags)\n\t\t}\n\n\t\t// Read and handle telemetry packet\n\t\tpayload.Reset()\n\t\tif size, err := payload.ReadFrom(io.LimitReader(conn, int64(hdr.MsgLen))); size != int64(hdr.MsgLen) {\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn errors.New(\"premature EOF during TCP dialout\")\n\t\t}\n\n\t\tc.handleTelemetry(payload.Bytes())\n\t}\n}\n\n// Handle telemetry packet from any transport, decode and add as measurement\nfunc (c *CiscoTelemetryMDT) handleTelemetry(data []byte) {\n\tmsg := &telemetry.Telemetry{}\n\terr := proto.Unmarshal(data, msg)\n\tif err != nil {\n\t\tc.acc.AddError(fmt.Errorf(\"failed to decode: %w: %s\", err, msg.String()))\n\t\treturn\n\t}\n\n\tgrouper := metric.NewSeriesGrouper()\n\tfor _, gpbkv := range msg.DataGpbkv {\n\t\t// Produce metadata tags\n\t\tvar tags map[string]string\n\n\t\t// Top-level field may have measurement timestamp, if not use message timestamp\n\t\tmeasured := gpbkv.Timestamp\n\t\tif measured == 0 {\n\t\t\tmeasured = msg.MsgTimestamp\n\t\t}\n\n\t\ttimestamp := time.Unix(int64(measured/1000), int64(measured%1000)*1000000)\n\n\t\t// Find toplevel GPBKV fields \"keys\" and \"content\"\n\t\tvar keys, content *telemetry.TelemetryField = nil, nil\n\t\tfor _, field := range gpbkv.Fields {\n\t\t\tif field.Name == \"keys\" {\n\t\t\t\tkeys = field\n\t\t\t} else if field.Name == \"content\" {\n\t\t\t\tcontent = field\n\t\t\t}\n\t\t}\n\n\t\tif content == nil && !c.IncludeDeleteField {\n\t\t\tc.Log.Debug(\"Message skipped because no content found and include of delete field not enabled\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif keys != nil {\n\t\t\ttags = make(map[string]string, len(keys.Fields)+3)\n\t\t\tfor _, subfield := range keys.Fields {\n\t\t\t\tc.parseKeyField(tags, subfield, \"\")\n\t\t\t}\n\t\t\t// If incoming MDT contains source key, copy to mdt_src\n\t\t\tif _, ok := tags[\"source\"]; ok {\n\t\t\t\ttags[c.SourceFieldName] = tags[\"source\"]\n\t\t\t}\n\t\t} else {\n\t\t\ttags = make(map[string]string, 3)\n\t\t}\n\t\t// Parse keys\n\t\ttags[\"source\"] = msg.GetNodeIdStr()\n\t\tif msgID := msg.GetSubscriptionIdStr(); msgID != \"\" {\n\t\t\ttags[\"subscription\"] = msgID\n\t\t}\n\t\tencodingPath := msg.GetEncodingPath()\n\t\ttags[\"path\"] = encodingPath\n\n\t\tif content != nil {\n\t\t\t// Parse values\n\t\t\tfor _, subfield := range content.Fields {\n\t\t\t\tprefix := \"\"\n\t\t\t\tswitch subfield.Name {\n\t\t\t\tcase \"operation-metric\":\n\t\t\t\t\tif len(subfield.Fields[0].Fields) > 0 {\n\t\t\t\t\t\tprefix = subfield.Fields[0].Fields[0].GetStringValue()\n\t\t\t\t\t}\n\t\t\t\tcase \"class-stats\":\n\t\t\t\t\tif len(subfield.Fields[0].Fields) > 1 {\n\t\t\t\t\t\tprefix = subfield.Fields[0].Fields[1].GetStringValue()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tc.parseContentField(grouper, subfield, prefix, encodingPath, tags, timestamp)\n\t\t\t}\n\t\t}\n\t\tif c.IncludeDeleteField {\n\t\t\tgrouper.Add(c.getMeasurementName(encodingPath), tags, timestamp, \"delete\", gpbkv.GetDelete())\n\t\t}\n\n\t\tif content == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse values\n\t\tfor _, subfield := range content.Fields {\n\t\t\tc.parseContentField(grouper, subfield, \"\", encodingPath, tags, timestamp)\n\t\t}\n\t}\n\n\tfor _, groupedMetric := range grouper.Metrics() {\n\t\tc.acc.AddMetric(groupedMetric)\n\t}\n}\n\nfunc decodeValue(field *telemetry.TelemetryField) interface{} {\n\tswitch val := field.ValueByType.(type) {\n\tcase *telemetry.TelemetryField_BytesValue:\n\t\treturn val.BytesValue\n\tcase *telemetry.TelemetryField_StringValue:\n\t\tif len(val.StringValue) > 0 {\n\t\t\treturn val.StringValue\n\t\t}\n\tcase *telemetry.TelemetryField_BoolValue:\n\t\treturn val.BoolValue\n\tcase *telemetry.TelemetryField_Uint32Value:\n\t\treturn val.Uint32Value\n\tcase *telemetry.TelemetryField_Uint64Value:\n\t\treturn val.Uint64Value\n\tcase *telemetry.TelemetryField_Sint32Value:\n\t\treturn val.Sint32Value\n\tcase *telemetry.TelemetryField_Sint64Value:\n\t\treturn val.Sint64Value\n\tcase *telemetry.TelemetryField_DoubleValue:\n\t\treturn val.DoubleValue\n\tcase *telemetry.TelemetryField_FloatValue:\n\t\treturn val.FloatValue\n\t}\n\treturn nil\n}\n\nfunc decodeTag(field *telemetry.TelemetryField) string {\n\tswitch val := field.ValueByType.(type) {\n\tcase *telemetry.TelemetryField_BytesValue:\n\t\treturn string(val.BytesValue)\n\tcase *telemetry.TelemetryField_StringValue:\n\t\treturn val.StringValue\n\tcase *telemetry.TelemetryField_BoolValue:\n\t\tif val.BoolValue {\n\t\t\treturn \"true\"\n\t\t}\n\t\treturn \"false\"\n\tcase *telemetry.TelemetryField_Uint32Value:\n\t\treturn strconv.FormatUint(uint64(val.Uint32Value), 10)\n\tcase *telemetry.TelemetryField_Uint64Value:\n\t\treturn strconv.FormatUint(val.Uint64Value, 10)\n\tcase *telemetry.TelemetryField_Sint32Value:\n\t\treturn strconv.FormatInt(int64(val.Sint32Value), 10)\n\tcase *telemetry.TelemetryField_Sint64Value:\n\t\treturn strconv.FormatInt(val.Sint64Value, 10)\n\tcase *telemetry.TelemetryField_DoubleValue:\n\t\treturn strconv.FormatFloat(val.DoubleValue, 'f', -1, 64)\n\tcase *telemetry.TelemetryField_FloatValue:\n\t\treturn strconv.FormatFloat(float64(val.FloatValue), 'f', -1, 32)\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// Recursively parse tag fields\nfunc (c *CiscoTelemetryMDT) parseKeyField(tags map[string]string, field *telemetry.TelemetryField, prefix string) {\n\tlocalname := strings.ReplaceAll(field.Name, \"-\", \"_\")\n\tname := localname\n\tif len(localname) == 0 {\n\t\tname = prefix\n\t} else if len(prefix) > 0 {\n\t\tname = prefix + \"/\" + localname\n\t}\n\n\tif tag := decodeTag(field); len(name) > 0 && len(tag) > 0 {\n\t\tif _, exists := tags[localname]; !exists { // Use short keys whenever possible\n\t\t\ttags[localname] = tag\n\t\t} else {\n\t\t\ttags[name] = tag\n\t\t}\n\t}\n\n\tfor _, subfield := range field.Fields {\n\t\tc.parseKeyField(tags, subfield, name)\n\t}\n}\n\nfunc parseRib(grouper *metric.SeriesGrouper, field *telemetry.TelemetryField,\n\tencodingPath string, tags map[string]string, timestamp time.Time) {\n\t// RIB\n\tmeasurement := encodingPath\n\tfor _, subfield := range field.Fields {\n\t\t// For Every table fill the keys which are vrfName, address and masklen\n\t\tswitch subfield.Name {\n\t\tcase \"vrfName\", \"address\", \"maskLen\":\n\t\t\ttags[subfield.Name] = decodeTag(subfield)\n\t\t}\n\t\tif value := decodeValue(subfield); value != nil {\n\t\t\tgrouper.Add(measurement, tags, timestamp, subfield.Name, value)\n\t\t}\n\t\tif subfield.Name != \"nextHop\" {\n\t\t\tcontinue\n\t\t}\n\t\t// For next hop table fill the keys in the tag - which is address and vrfname\n\t\tfor _, subf := range subfield.Fields {\n\t\t\tfor _, ff := range subf.Fields {\n\t\t\t\tswitch ff.Name {\n\t\t\t\tcase \"address\", \"vrfName\":\n\t\t\t\t\tkey := \"nextHop/\" + ff.Name\n\t\t\t\t\ttags[key] = decodeTag(ff)\n\t\t\t\t}\n\t\t\t\tif value := decodeValue(ff); value != nil {\n\t\t\t\t\tname := \"nextHop/\" + ff.Name\n\t\t\t\t\tgrouper.Add(measurement, tags, timestamp, name, value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc parseMicroburst(grouper *metric.SeriesGrouper, field *telemetry.TelemetryField,\n\tencodingPath string, tags map[string]string, timestamp time.Time) {\n\tvar nxMicro *telemetry.TelemetryField\n\tvar nxMicro1 *telemetry.TelemetryField\n\t// Microburst\n\tmeasurement := encodingPath\n\tif len(field.Fields) > 3 {\n\t\tnxMicro = field.Fields[2]\n\t\tif len(nxMicro.Fields) > 0 {\n\t\t\tnxMicro1 = nxMicro.Fields[0]\n\t\t\tif len(nxMicro1.Fields) >= 3 {\n\t\t\t\tnxMicro = nxMicro1.Fields[3]\n\t\t\t}\n\t\t}\n\t}\n\tfor _, subfield := range nxMicro.Fields {\n\t\tif subfield.Name == \"interfaceName\" {\n\t\t\ttags[subfield.Name] = decodeTag(subfield)\n\t\t}\n\n\t\tfor _, subf := range subfield.Fields {\n\t\t\tswitch subf.Name {\n\t\t\tcase \"sourceName\":\n\t\t\t\tnewstr := strings.Split(decodeTag(subf), \"-[\")\n\t\t\t\tif len(newstr) <= 2 {\n\t\t\t\t\ttags[subf.Name] = decodeTag(subf)\n\t\t\t\t} else {\n\t\t\t\t\tintfName := strings.Split(newstr[1], \"]\")\n\t\t\t\t\tqueue := strings.Split(newstr[2], \"]\")\n\t\t\t\t\ttags[\"interface_name\"] = intfName[0]\n\t\t\t\t\ttags[\"queue_number\"] = queue[0]\n\t\t\t\t}\n\t\t\tcase \"startTs\":\n\t\t\t\ttags[subf.Name] = decodeTag(subf)\n\t\t\t}\n\t\t\tif value := decodeValue(subf); value != nil {\n\t\t\t\tgrouper.Add(measurement, tags, timestamp, subf.Name, value)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *CiscoTelemetryMDT) parseClassAttributeField(grouper *metric.SeriesGrouper, field *telemetry.TelemetryField,\n\tencodingPath string, tags map[string]string, timestamp time.Time) {\n\t// DME structure: https://developer.cisco.com/site/nxapi-dme-model-reference-api/\n\tvar nxAttributes *telemetry.TelemetryField\n\tisDme := strings.Contains(encodingPath, \"sys/\")\n\tif encodingPath == \"rib\" {\n\t\t// handle native data path rib\n\t\tparseRib(grouper, field, encodingPath, tags, timestamp)\n\t\treturn\n\t}\n\tif encodingPath == \"microburst\" {\n\t\t// dump microburst\n\t\tparseMicroburst(grouper, field, encodingPath, tags, timestamp)\n\t\treturn\n\t}\n\tif field == nil || !isDme || len(field.Fields) == 0 || len(field.Fields[0].Fields) == 0 || len(field.Fields[0].Fields[0].Fields) == 0 {\n\t\treturn\n\t}\n\n\tif field.Fields[0] != nil && field.Fields[0].Fields != nil && field.Fields[0].Fields[0] != nil && field.Fields[0].Fields[0].Fields[0].Name != \"attributes\" {\n\t\treturn\n\t}\n\tnxAttributes = field.Fields[0].Fields[0].Fields[0].Fields[0]\n\n\t// Find dn tag among list of attributes\n\tfor _, subfield := range nxAttributes.Fields {\n\t\tif subfield.Name == \"dn\" {\n\t\t\ttags[\"dn\"] = decodeTag(subfield)\n\t\t\tbreak\n\t\t}\n\t}\n\t// Add attributes to grouper with consistent dn tag\n\tfor _, subfield := range nxAttributes.Fields {\n\t\tc.parseContentField(grouper, subfield, \"\", encodingPath, tags, timestamp)\n\t}\n\t// Delete dn tag to prevent it from being added to the next node's attributes\n\tdelete(tags, \"dn\")\n}\n\nfunc (c *CiscoTelemetryMDT) getMeasurementName(encodingPath string) string {\n\t// Do alias lookup, to shorten measurement names\n\tmeasurement := encodingPath\n\tif alias, ok := c.internalAliases[encodingPath]; ok {\n\t\tmeasurement = alias\n\t} else {\n\t\tc.mutex.Lock()\n\t\tif _, haveWarned := c.warned[encodingPath]; !haveWarned {\n\t\t\tc.Log.Debugf(\"No measurement alias for encoding path: %s\", encodingPath)\n\t\t\tc.warned[encodingPath] = struct{}{}\n\t\t}\n\t\tc.mutex.Unlock()\n\t}\n\treturn measurement\n}\n\nfunc (c *CiscoTelemetryMDT) parseContentField(\n\tgrouper *metric.SeriesGrouper,\n\tfield *telemetry.TelemetryField,\n\tprefix, encodingPath string,\n\ttags map[string]string,\n\ttimestamp time.Time,\n) {\n\tname := strings.ReplaceAll(field.Name, \"-\", \"_\")\n\n\tif (name == \"modTs\" || name == \"createTs\") && decodeValue(field) == \"never\" {\n\t\treturn\n\t}\n\tif len(name) == 0 {\n\t\tname = prefix\n\t} else if len(prefix) > 0 {\n\t\tname = prefix + \"/\" + name\n\t}\n\n\textraTags := c.extraTags[strings.ReplaceAll(encodingPath, \"-\", \"_\")+\"/\"+name]\n\n\tif value := decodeValue(field); value != nil {\n\t\tmeasurement := c.getMeasurementName(encodingPath)\n\t\tif val := c.nxosValueXform(field, value, encodingPath); val != nil {\n\t\t\tgrouper.Add(measurement, tags, timestamp, name, val)\n\t\t} else {\n\t\t\tgrouper.Add(measurement, tags, timestamp, name, value)\n\t\t}\n\t\treturn\n\t}\n\n\tif len(extraTags) > 0 {\n\t\tfor _, subfield := range field.Fields {\n\t\t\tif _, isExtraTag := extraTags[subfield.Name]; isExtraTag {\n\t\t\t\ttags[name+\"/\"+strings.ReplaceAll(subfield.Name, \"-\", \"_\")] = decodeTag(subfield)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar nxAttributes, nxChildren, nxRows *telemetry.TelemetryField\n\tisNXOS := !strings.ContainsRune(encodingPath, ':') // IOS-XR and IOS-XE have a colon in their encoding path, NX-OS does not\n\tisEVENT := isNXOS && strings.Contains(encodingPath, \"EVENT-LIST\")\n\tnxChildren = nil\n\tnxAttributes = nil\n\tfor _, subfield := range field.Fields {\n\t\tif isNXOS && subfield.Name == \"attributes\" && len(subfield.Fields) > 0 {\n\t\t\tnxAttributes = subfield.Fields[0]\n\t\t} else if isNXOS && subfield.Name == \"children\" && len(subfield.Fields) > 0 {\n\t\t\tif !isEVENT {\n\t\t\t\tnxChildren = subfield\n\t\t\t} else {\n\t\t\t\tsub := subfield.Fields\n\t\t\t\tif len(sub) > 0 && sub[0] != nil && len(sub[0].Fields) >= 2 {\n\t\t\t\t\tif sub[0].Fields[0].Name == \"subscriptionId\" {\n\t\t\t\t\t\tnxAttributes = sub[0].Fields[1].Fields[0].Fields[0].Fields[0].Fields[0].Fields[0]\n\t\t\t\t\t} else if sub[0].Fields[1].Name == \"subscriptionId\" {\n\t\t\t\t\t\tnxAttributes = sub[0].Fields[0].Fields[0].Fields[0].Fields[0].Fields[0].Fields[0]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if nxAttributes == NULL then class based query.\n\t\t\tif nxAttributes == nil {\n\t\t\t\t// call function walking over walking list.\n\t\t\t\tfor _, sub := range subfield.Fields {\n\t\t\t\t\tc.parseClassAttributeField(grouper, sub, encodingPath, tags, timestamp)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if isNXOS && strings.HasPrefix(subfield.Name, \"ROW_\") {\n\t\t\tnxRows = subfield\n\t\t} else if _, isExtraTag := extraTags[subfield.Name]; !isExtraTag { // Regular telemetry decoding\n\t\t\tc.parseContentField(grouper, subfield, name, encodingPath, tags, timestamp)\n\t\t}\n\t}\n\n\tif nxAttributes == nil && nxRows == nil {\n\t\treturn\n\t} else if nxRows != nil {\n\t\t// NXAPI structure: https://developer.cisco.com/docs/cisco-nexus-9000-series-nx-api-cli-reference-release-9-2x/\n\t\tfor _, row := range nxRows.Fields {\n\t\t\tfor i, subfield := range row.Fields {\n\t\t\t\tif i == 0 { // First subfield contains the index, promote it from value to tag\n\t\t\t\t\ttags[prefix] = decodeTag(subfield)\n\t\t\t\t\t// We can have subfield so recursively handle it.\n\t\t\t\t\tif len(row.Fields) == 1 {\n\t\t\t\t\t\ttags[\"row_number\"] = strconv.FormatInt(int64(i), 10)\n\t\t\t\t\t\tc.parseContentField(grouper, subfield, \"\", encodingPath, tags, timestamp)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tc.parseContentField(grouper, subfield, \"\", encodingPath, tags, timestamp)\n\t\t\t\t}\n\t\t\t\t// Nxapi we can't identify keys always from prefix\n\t\t\t\ttags[\"row_number\"] = strconv.FormatInt(int64(i), 10)\n\t\t\t}\n\t\t\tdelete(tags, prefix)\n\t\t}\n\t\treturn\n\t}\n\n\t// DME structure: https://developer.cisco.com/site/nxapi-dme-model-reference-api/\n\trn := \"\"\n\tdn := false\n\n\tfor _, subfield := range nxAttributes.Fields {\n\t\tif subfield.Name == \"rn\" {\n\t\t\trn = decodeTag(subfield)\n\t\t} else if subfield.Name == \"dn\" {\n\t\t\tdn = true\n\t\t}\n\t}\n\n\tif len(rn) > 0 {\n\t\ttags[prefix] = rn\n\t} else if !dn { // Check for distinguished name being present\n\t\tc.acc.AddError(errors.New(\"failed while decoding NX-OS: missing 'dn' field\"))\n\t\treturn\n\t}\n\n\tfor _, subfield := range nxAttributes.Fields {\n\t\tif subfield.Name != \"rn\" {\n\t\t\tc.parseContentField(grouper, subfield, \"\", encodingPath, tags, timestamp)\n\t\t}\n\t}\n\n\tif nxChildren != nil {\n\t\t// This is a nested structure, children will inherit relative name keys of parent\n\t\tfor _, subfield := range nxChildren.Fields {\n\t\t\tc.parseContentField(grouper, subfield, prefix, encodingPath, tags, timestamp)\n\t\t}\n\t}\n\tdelete(tags, prefix)\n}\n\nfunc init() {\n\tinputs.Add(\"cisco_telemetry_mdt\", func() telegraf.Input {\n\t\treturn &CiscoTelemetryMDT{\n\t\t\tTransport:       \"grpc\",\n\t\t\tServiceAddress:  \"127.0.0.1:57000\",\n\t\t\tSourceFieldName: \"mdt_source\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_mdt_test.go",
    "content": "package cisco_telemetry_mdt\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\tmdtdialout \"github.com/cisco-ie/nx-telemetry-proto/mdt_dialout\"\n\ttelemetry \"github.com/cisco-ie/nx-telemetry-proto/telemetry_bis\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/connectivity\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestHandleTelemetryTwoSimple(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:       testutil.Logger{},\n\t\tTransport: \"dummy\",\n\t\tAliases: map[string]string{\n\t\t\t\"alias\": \"type:model/some/path\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"type:model/some/path\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"name\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"str\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"uint64\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint64Value{Uint64Value: 1234},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"bool\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_BoolValue{BoolValue: true},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"name\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"str2\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"bool\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_BoolValue{BoolValue: false},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags := map[string]string{\n\t\t\"path\":         \"type:model/some/path\",\n\t\t\"name\":         \"str\",\n\t\t\"uint64\":       \"1234\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields := map[string]interface{}{\"bool\": true}\n\tacc.AssertContainsTaggedFields(t, \"alias\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"path\":         \"type:model/some/path\",\n\t\t\"name\":         \"str2\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields = map[string]interface{}{\"bool\": false}\n\tacc.AssertContainsTaggedFields(t, \"alias\", fields, tags)\n}\n\nfunc TestIncludeDeleteField(t *testing.T) {\n\ttype TelemetryEntry struct {\n\t\tname        string\n\t\tfieldName   string\n\t\tuint32Value uint32\n\t\tuint64Value uint64\n\t\tstringValue string\n\t}\n\tencodingPath := TelemetryEntry{\n\t\tname:        \"path\",\n\t\tstringValue: \"openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address\",\n\t}\n\tname := TelemetryEntry{name: \"name\", stringValue: \"Loopback10\"}\n\tindex := TelemetryEntry{name: \"index\", stringValue: \"0\"}\n\tip := TelemetryEntry{name: \"ip\", fieldName: \"state/ip\", stringValue: \"10::10\"}\n\tprefixLength := TelemetryEntry{name: \"prefix-length\", fieldName: \"state/prefix_length\", uint32Value: uint32(128), uint64Value: 128}\n\torigin := TelemetryEntry{name: \"origin\", fieldName: \"state/origin\", stringValue: \"STATIC\"}\n\tstatus := TelemetryEntry{name: \"status\", fieldName: \"state/status\", stringValue: \"PREFERRED\"}\n\tsource := TelemetryEntry{name: \"source\", stringValue: \"hostname\"}\n\tsubscription := TelemetryEntry{name: \"subscription\", stringValue: \"subscription\"}\n\tdeleteKey := \"delete\"\n\tstateKey := \"state\"\n\n\ttestCases := []struct {\n\t\ttelemetry *telemetry.Telemetry\n\t\texpected  []telegraf.Metric\n\t}{{\n\t\ttelemetry: &telemetry.Telemetry{\n\t\t\tMsgTimestamp: 1543236572000,\n\t\t\tEncodingPath: encodingPath.stringValue,\n\t\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: source.stringValue},\n\t\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: subscription.stringValue},\n\t\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t\t{\n\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:        name.name,\n\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: name.stringValue},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:        index.name,\n\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint32Value{Uint32Value: index.uint32Value},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:        ip.name,\n\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: ip.stringValue},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: stateKey,\n\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:        ip.name,\n\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: ip.stringValue},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:        prefixLength.name,\n\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint32Value{Uint32Value: prefixLength.uint32Value},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:        origin.name,\n\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: origin.stringValue},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:        status.name,\n\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: status.stringValue},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\texpected: []telegraf.Metric{\n\t\t\tmetric.New(\n\t\t\t\t\"deleted\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\tencodingPath.name: encodingPath.stringValue,\n\t\t\t\t\tname.name:         name.stringValue,\n\t\t\t\t\tindex.name:        index.stringValue,\n\t\t\t\t\tip.name:           ip.stringValue,\n\t\t\t\t\tsource.name:       source.stringValue,\n\t\t\t\t\tsubscription.name: subscription.stringValue,\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\tdeleteKey:              false,\n\t\t\t\t\tip.fieldName:           ip.stringValue,\n\t\t\t\t\tprefixLength.fieldName: prefixLength.uint64Value,\n\t\t\t\t\torigin.fieldName:       origin.stringValue,\n\t\t\t\t\tstatus.fieldName:       status.stringValue,\n\t\t\t\t},\n\t\t\t\ttime.Now(),\n\t\t\t)},\n\t},\n\t\t{\n\t\t\ttelemetry: &telemetry.Telemetry{\n\t\t\t\tMsgTimestamp: 1543236572000,\n\t\t\t\tEncodingPath: encodingPath.stringValue,\n\t\t\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: source.stringValue},\n\t\t\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: subscription.stringValue},\n\t\t\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tDelete: true,\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        name.name,\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: name.stringValue},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        index.name,\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint32Value{Uint32Value: index.uint32Value},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        ip.name,\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: ip.stringValue},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"deleted\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\tencodingPath.name: encodingPath.stringValue,\n\t\t\t\t\t\tname.name:         name.stringValue,\n\t\t\t\t\t\tindex.name:        index.stringValue,\n\t\t\t\t\t\tip.name:           ip.stringValue,\n\t\t\t\t\t\tsource.name:       source.stringValue,\n\t\t\t\t\t\tsubscription.name: subscription.stringValue,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{deleteKey: true},\n\t\t\t\t\ttime.Now(),\n\t\t\t\t)},\n\t\t},\n\t}\n\tfor _, test := range testCases {\n\t\tc := &CiscoTelemetryMDT{\n\t\t\tLog:                testutil.Logger{},\n\t\t\tTransport:          \"dummy\",\n\t\t\tAliases:            map[string]string{\"deleted\": encodingPath.stringValue},\n\t\t\tIncludeDeleteField: true}\n\t\tacc := &testutil.Accumulator{}\n\t\t// error is expected since we are passing in dummy transport\n\t\trequire.ErrorContains(t, c.Start(acc), \"dummy\")\n\t\tdata, err := proto.Marshal(test.telemetry)\n\t\trequire.NoError(t, err)\n\n\t\tc.handleTelemetry(data)\n\t\tactual := acc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, test.expected, actual, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestHandleTelemetrySingleNested(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:       testutil.Logger{},\n\t\tTransport: \"dummy\",\n\t\tAliases: map[string]string{\n\t\t\t\"nested\": \"type:model/nested/path\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"type:model/nested/path\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"nested\",\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"key\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tName:        \"level\",\n\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_DoubleValue{DoubleValue: 3},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"nested\",\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"value\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags := map[string]string{\n\t\t\"path\":         \"type:model/nested/path\",\n\t\t\"level\":        \"3\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields := map[string]interface{}{\"nested/value/foo\": \"bar\"}\n\tacc.AssertContainsTaggedFields(t, \"nested\", fields, tags)\n}\n\nfunc TestHandleEmbeddedTags(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tTransport:    \"dummy\",\n\t\tAliases:      map[string]string{\"extra\": \"type:model/extra\"},\n\t\tEmbeddedTags: []string{\"type:model/extra/list/name\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"type:model/extra\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"list\",\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        \"name\",\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"entry1\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        \"test\",\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"foo\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"list\",\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        \"name\",\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"entry2\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:        \"test\",\n\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags1 := map[string]string{\n\t\t\"path\":         \"type:model/extra\",\n\t\t\"foo\":          \"bar\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t\t\"list/name\":    \"entry1\",\n\t}\n\tfields1 := map[string]interface{}{\"list/test\": \"foo\"}\n\ttags2 := map[string]string{\n\t\t\"path\":         \"type:model/extra\",\n\t\t\"foo\":          \"bar\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t\t\"list/name\":    \"entry2\",\n\t}\n\tfields2 := map[string]interface{}{\"list/test\": \"bar\"}\n\tacc.AssertContainsTaggedFields(t, \"extra\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"extra\", fields2, tags2)\n}\n\nfunc TestHandleNXAPI(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"nxapi\": \"show nxapi\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"show nxapi\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"TABLE_nxapi\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"ROW_nxapi\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"index\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"i1\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"value\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"foo\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"index\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"i2\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"value\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags1 := map[string]string{\n\t\t\"path\":         \"show nxapi\",\n\t\t\"foo\":          \"bar\",\n\t\t\"TABLE_nxapi\":  \"i1\",\n\t\t\"row_number\":   \"0\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields1 := map[string]interface{}{\"value\": \"foo\"}\n\ttags2 := map[string]string{\n\t\t\"path\":         \"show nxapi\",\n\t\t\"foo\":          \"bar\",\n\t\t\"TABLE_nxapi\":  \"i2\",\n\t\t\"row_number\":   \"0\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields2 := map[string]interface{}{\"value\": \"bar\"}\n\tacc.AssertContainsTaggedFields(t, \"nxapi\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"nxapi\", fields2, tags2)\n}\n\nfunc TestHandleNXAPIXformNXAPI(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:       testutil.Logger{},\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"nxapi\": \"show nxapi\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"show processes cpu\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"TABLE_process_cpu\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"ROW_process_cpu\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"index\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"i1\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"value\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"foo\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags1 := map[string]string{\n\t\t\"path\":              \"show processes cpu\",\n\t\t\"foo\":               \"bar\",\n\t\t\"TABLE_process_cpu\": \"i1\",\n\t\t\"row_number\":        \"0\",\n\t\t\"source\":            \"hostname\",\n\t\t\"subscription\":      \"subscription\",\n\t}\n\tfields1 := map[string]interface{}{\"value\": \"foo\"}\n\tacc.AssertContainsTaggedFields(t, \"show processes cpu\", fields1, tags1)\n}\n\nfunc TestHandleNXXformMulti(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"dme\": \"sys/lldp\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"sys/lldp\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"fooEntity\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"attributes\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"rn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"some-rn\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"portIdV\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint32Value{Uint32Value: 12},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"portDesc\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint64Value{Uint64Value: 100},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"test\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint64Value{Uint64Value: 281474976710655},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"subscriptionId\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint64Value{Uint64Value: 2814749767106551},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\t// validate various transformation scenaarios newly added in the code.\n\tfields := map[string]interface{}{\n\t\t\"portIdV\":        \"12\",\n\t\t\"portDesc\":       \"100\",\n\t\t\"test\":           int64(281474976710655),\n\t\t\"subscriptionId\": \"2814749767106551\",\n\t}\n\tacc.AssertContainsFields(t, \"dme\", fields)\n}\n\nfunc TestHandleNXDME(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"dme\": \"sys/dme\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"sys/dme\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"foo\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"bar\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"fooEntity\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"attributes\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"rn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"some-rn\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"value\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"foo\"},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags1 := map[string]string{\n\t\t\"path\":         \"sys/dme\",\n\t\t\"foo\":          \"bar\",\n\t\t\"fooEntity\":    \"some-rn\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields1 := map[string]interface{}{\"value\": \"foo\"}\n\tacc.AssertContainsTaggedFields(t, \"dme\", fields1, tags1)\n}\nfunc TestHandleNXDMESubtree(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"dme\": \"sys/dme\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"sys/dme\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"sys/dme\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"sys/dme\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"children\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"fooEntity\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"attributes\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"foo\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"bar1\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"dn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"eth1/1\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"fooEntity\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"attributes\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"foo\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"bar2\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"dn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"eth1/2\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\trequire.Len(t, acc.Metrics, 2)\n\n\ttags1 := map[string]string{\n\t\t\"dn\":           \"eth1/1\",\n\t\t\"path\":         \"sys/dme\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t\t\"sys/dme\":      \"sys/dme\",\n\t}\n\tfields1 := map[string]interface{}{\"foo\": \"bar1\", \"dn\": \"eth1/1\"}\n\tacc.AssertContainsTaggedFields(t, \"dme\", fields1, tags1)\n\n\ttags2 := map[string]string{\n\t\t\"dn\":           \"eth1/2\",\n\t\t\"path\":         \"sys/dme\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t\t\"sys/dme\":      \"sys/dme\",\n\t}\n\tfields2 := map[string]interface{}{\"foo\": \"bar2\", \"dn\": \"eth1/2\"}\n\tacc.AssertContainsTaggedFields(t, \"dme\", fields2, tags2)\n}\n\nfunc TestTCPDialoutOverflow(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"tcp\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\n\thdr := struct {\n\t\tMsgType       uint16\n\t\tMsgEncap      uint16\n\t\tMsgHdrVersion uint16\n\t\tMsgFlags      uint16\n\t\tMsgLen        uint32\n\t}{MsgLen: uint32(1000000000)}\n\n\taddr := c.listener.Addr()\n\tconn, err := net.Dial(addr.Network(), addr.String())\n\trequire.NoError(t, err)\n\trequire.NoError(t, binary.Write(conn, binary.BigEndian, hdr))\n\t_, err = conn.Read([]byte{0})\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\trequire.NoError(t, conn.Close())\n\n\tc.Stop()\n\n\trequire.Contains(t, acc.Errors, errors.New(\"dialout packet too long: 1000000000\"))\n}\n\nfunc mockTelemetryMicroburstMessage() *telemetry.Telemetry {\n\tdata, err := os.ReadFile(\"./testdata/microburst\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tnewMessage := &telemetry.Telemetry{}\n\terr = proto.Unmarshal(data, newMessage)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn newMessage\n}\n\nfunc mockTelemetryMessage() *telemetry.Telemetry {\n\treturn &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"type:model/some/path\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"name\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"str\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"value\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Sint64Value{Sint64Value: -1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc TestGRPCDialoutMicroburst(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"grpc\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t\tAliases: map[string]string{\n\t\t\t\"some\":     \"microburst\",\n\t\t\t\"parallel\": \"type:model/parallel/path\",\n\t\t\t\"other\":    \"type:model/other/path\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\n\ttel := mockTelemetryMicroburstMessage()\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\ttags := map[string]string{\n\t\t\"microburst\":   \"microburst\",\n\t\t\"path\":         \"microburst\",\n\t\t\"source\":       \"n9k-eor-tm4\",\n\t\t\"subscription\": \"1\",\n\t}\n\tfields := map[string]interface{}{\n\t\t\"duration\":      uint64(1200),\n\t\t\"endDepth\":      int64(0),\n\t\t\"interfaceName\": \"Eth0/0/0\",\n\t\t\"peak\":          int64(500),\n\t\t\"queue\":         \"queue-255\",\n\t\t\"queueType\":     \"unicast\",\n\t\t\"threshold\":     int64(0),\n\t\t\"ts\":            \"2023-08-03T20:12:59.655308Z\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"microburst\", fields, tags)\n}\n\nfunc TestTCPDialoutMultiple(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"tcp\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t\tAliases: map[string]string{\n\t\t\t\"some\":     \"type:model/some/path\",\n\t\t\t\"parallel\": \"type:model/parallel/path\",\n\t\t\t\"other\":    \"type:model/other/path\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\n\ttel := mockTelemetryMessage()\n\n\thdr := struct {\n\t\tMsgType       uint16\n\t\tMsgEncap      uint16\n\t\tMsgHdrVersion uint16\n\t\tMsgFlags      uint16\n\t\tMsgLen        uint32\n\t}{}\n\n\taddr := c.listener.Addr()\n\tconn, err := net.Dial(addr.Network(), addr.String())\n\trequire.NoError(t, err)\n\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\thdr.MsgLen = uint32(len(data))\n\trequire.NoError(t, binary.Write(conn, binary.BigEndian, hdr))\n\t_, err = conn.Write(data)\n\trequire.NoError(t, err)\n\n\tconn2, err := net.Dial(addr.Network(), addr.String())\n\trequire.NoError(t, err)\n\n\ttel.EncodingPath = \"type:model/parallel/path\"\n\tdata, err = proto.Marshal(tel)\n\trequire.NoError(t, err)\n\thdr.MsgLen = uint32(len(data))\n\trequire.NoError(t, binary.Write(conn2, binary.BigEndian, hdr))\n\t_, err = conn2.Write(data)\n\trequire.NoError(t, err)\n\t_, err = conn2.Write([]byte{0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0})\n\trequire.NoError(t, err)\n\t_, err = conn2.Read([]byte{0})\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\trequire.NoError(t, conn2.Close())\n\n\ttel.EncodingPath = \"type:model/other/path\"\n\tdata, err = proto.Marshal(tel)\n\trequire.NoError(t, err)\n\thdr.MsgLen = uint32(len(data))\n\trequire.NoError(t, binary.Write(conn, binary.BigEndian, hdr))\n\t_, err = conn.Write(data)\n\trequire.NoError(t, err)\n\t_, err = conn.Write([]byte{0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0})\n\trequire.NoError(t, err)\n\t_, err = conn.Read([]byte{0})\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\tc.Stop()\n\trequire.NoError(t, conn.Close())\n\n\t// We use the invalid dialout flags to let the server close the connection\n\trequire.Equal(t, []error{errors.New(\"invalid dialout flags: 257\"), errors.New(\"invalid dialout flags: 257\")}, acc.Errors)\n\n\ttags := map[string]string{\n\t\t\"path\":         \"type:model/some/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields := map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"some\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"path\":         \"type:model/parallel/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields = map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"parallel\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"path\":         \"type:model/other/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields = map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"other\", fields, tags)\n}\n\nfunc TestGRPCDialoutError(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"grpc\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\n\taddr := c.listener.Addr()\n\tconn, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))\n\trequire.NoError(t, err)\n\tclient := mdtdialout.NewGRPCMdtDialoutClient(conn)\n\tstream, err := client.MdtDialout(t.Context())\n\trequire.NoError(t, err)\n\n\targs := &mdtdialout.MdtDialoutArgs{Errors: \"foobar\"}\n\trequire.NoError(t, stream.Send(args))\n\n\t// Wait for the server to close\n\t_, err = stream.Recv()\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\tc.Stop()\n\n\trequire.Equal(t, []error{errors.New(\"error during GRPC dialout: foobar\")}, acc.Errors)\n}\n\nfunc TestGRPCDialoutMultiple(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"grpc\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t\tAliases: map[string]string{\n\t\t\t\"some\":     \"type:model/some/path\",\n\t\t\t\"parallel\": \"type:model/parallel/path\",\n\t\t\t\"other\":    \"type:model/other/path\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\ttel := mockTelemetryMessage()\n\n\taddr := c.listener.Addr()\n\tconn, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))\n\trequire.NoError(t, err)\n\trequire.True(t, conn.WaitForStateChange(t.Context(), connectivity.Connecting))\n\tclient := mdtdialout.NewGRPCMdtDialoutClient(conn)\n\tstream, err := client.MdtDialout(t.Context())\n\trequire.NoError(t, err)\n\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\targs := &mdtdialout.MdtDialoutArgs{Data: data, ReqId: 456}\n\trequire.NoError(t, stream.Send(args))\n\n\tconn2, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))\n\trequire.NoError(t, err)\n\trequire.True(t, conn.WaitForStateChange(t.Context(), connectivity.Connecting))\n\tclient2 := mdtdialout.NewGRPCMdtDialoutClient(conn2)\n\tstream2, err := client2.MdtDialout(t.Context())\n\trequire.NoError(t, err)\n\n\ttel.EncodingPath = \"type:model/parallel/path\"\n\tdata, err = proto.Marshal(tel)\n\trequire.NoError(t, err)\n\targs = &mdtdialout.MdtDialoutArgs{Data: data}\n\trequire.NoError(t, stream2.Send(args))\n\trequire.NoError(t, stream2.Send(&mdtdialout.MdtDialoutArgs{Errors: \"testclose\"}))\n\t_, err = stream2.Recv()\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\trequire.NoError(t, conn2.Close())\n\n\ttel.EncodingPath = \"type:model/other/path\"\n\tdata, err = proto.Marshal(tel)\n\trequire.NoError(t, err)\n\targs = &mdtdialout.MdtDialoutArgs{Data: data}\n\trequire.NoError(t, stream.Send(args))\n\trequire.NoError(t, stream.Send(&mdtdialout.MdtDialoutArgs{Errors: \"testclose\"}))\n\t_, err = stream.Recv()\n\trequire.True(t, err == nil || errors.Is(err, io.EOF))\n\n\tc.Stop()\n\trequire.NoError(t, conn.Close())\n\n\trequire.Equal(t, []error{errors.New(\"error during GRPC dialout: testclose\"), errors.New(\"error during GRPC dialout: testclose\")}, acc.Errors)\n\n\ttags := map[string]string{\n\t\t\"path\":         \"type:model/some/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields := map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"some\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"path\":         \"type:model/parallel/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields = map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"parallel\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"path\":         \"type:model/other/path\",\n\t\t\"name\":         \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields = map[string]interface{}{\"value\": int64(-1)}\n\tacc.AssertContainsTaggedFields(t, \"other\", fields, tags)\n}\n\nfunc TestGRPCDialoutKeepalive(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:            testutil.Logger{},\n\t\tTransport:      \"grpc\",\n\t\tServiceAddress: \"127.0.0.1:0\",\n\t\tEnforcementPolicy: grpcEnforcementPolicy{\n\t\t\tPermitKeepaliveWithoutCalls: true,\n\t\t\tKeepaliveMinTime:            0,\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\trequire.NoError(t, err)\n\n\taddr := c.listener.Addr()\n\tconn, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))\n\trequire.NoError(t, err)\n\tclient := mdtdialout.NewGRPCMdtDialoutClient(conn)\n\tstream, err := client.MdtDialout(t.Context())\n\trequire.NoError(t, err)\n\n\ttel := mockTelemetryMessage()\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\targs := &mdtdialout.MdtDialoutArgs{Data: data, ReqId: 456}\n\trequire.NoError(t, stream.Send(args))\n\n\tc.Stop()\n\trequire.NoError(t, conn.Close())\n}\n\nfunc TestSourceFieldRewrite(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:       testutil.Logger{},\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"alias\": \"type:model/some/path\"},\n\t}\n\tc.SourceFieldName = \"mdt_source\"\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1543236572000,\n\t\tEncodingPath: \"type:model/some/path\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"hostname\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"subscription\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"source\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"str\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"bool\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_BoolValue{BoolValue: false},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\ttags := map[string]string{\n\t\t\"path\":         \"type:model/some/path\",\n\t\t\"mdt_source\":   \"str\",\n\t\t\"source\":       \"hostname\",\n\t\t\"subscription\": \"subscription\",\n\t}\n\tfields := map[string]interface{}{\"bool\": false}\n\tacc.AssertContainsTaggedFields(t, \"alias\", fields, tags)\n}\n\nfunc TestHandleNXDMEEventListWithDn(t *testing.T) {\n\tc := &CiscoTelemetryMDT{\n\t\tLog:       testutil.Logger{},\n\t\tTransport: \"dummy\",\n\t\tAliases:   map[string]string{\"dme\": \"sys/intf/phys-[eth1/11]\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\terr := c.Start(acc)\n\t// error is expected since we are passing in dummy transport\n\trequire.Error(t, err)\n\n\ttel := &telemetry.Telemetry{\n\t\tMsgTimestamp: 1769120146205,\n\t\tEncodingPath: \"EVENT-LIST\",\n\t\tNodeId:       &telemetry.Telemetry_NodeIdStr{NodeIdStr: \"NX-PGBL-GX2\"},\n\t\tSubscription: &telemetry.Telemetry_SubscriptionIdStr{SubscriptionIdStr: \"1\"},\n\t\tDataGpbkv: []*telemetry.TelemetryField{\n\t\t\t{\n\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"keys\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:        \"EVENT-LIST\",\n\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{StringValue: \"EVENT-LIST\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"content\",\n\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName: \"children\",\n\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"imdata\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"ethpmPhysIf\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"attributes\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFields: []*telemetry.TelemetryField{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"childAction\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"dn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"sys/intf/phys-[eth1/11]/phys\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"lastLinkStChg\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"2026-01-22T14:15:46.199-08:00\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"operBitset\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"3-4\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"operSt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"up\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"operStQual\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"none\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"resetCtr\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Sint64Value{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSint64Value: 2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"rn\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"status\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_StringValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tStringValue: \"modified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tName:        \"subscriptionId\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tValueByType: &telemetry.TelemetryField_Uint64Value{Uint64Value: 18379759394883829764},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := proto.Marshal(tel)\n\trequire.NoError(t, err)\n\n\tc.handleTelemetry(data)\n\trequire.Empty(t, acc.Errors)\n\n\t// Verify that the metric was created with the correct measurement name and fields\n\trequire.Len(t, acc.Metrics, 1, \"Expected exactly 1 metric\")\n\n\ttags := map[string]string{\n\t\t\"path\":         \"EVENT-LIST\",\n\t\t\"EVENT_LIST\":   \"EVENT-LIST\",\n\t\t\"source\":       \"NX-PGBL-GX2\",\n\t\t\"subscription\": \"1\",\n\t}\n\tfields := map[string]interface{}{\n\t\t\"dn\":            \"sys/intf/phys-[eth1/11]/phys\",\n\t\t\"lastLinkStChg\": \"2026-01-22T14:15:46.199-08:00\",\n\t\t\"operBitset\":    \"3-4\",\n\t\t\"operSt\":        \"up\",\n\t\t\"operStQual\":    \"none\",\n\t\t\"resetCtr\":      int64(2),\n\t\t\"status\":        \"modified\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"EVENT-LIST\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_util.go",
    "content": "package cisco_telemetry_mdt\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\ttelemetry \"github.com/cisco-ie/nx-telemetry-proto/telemetry_bis\"\n)\n\n// xform Field to string\nfunc xformValueString(field *telemetry.TelemetryField) string {\n\tvar str string\n\tswitch val := field.ValueByType.(type) {\n\tcase *telemetry.TelemetryField_StringValue:\n\t\tif len(val.StringValue) > 0 {\n\t\t\treturn val.StringValue\n\t\t}\n\tcase *telemetry.TelemetryField_Uint32Value:\n\t\tstr = strconv.FormatUint(uint64(val.Uint32Value), 10)\n\t\treturn str\n\tcase *telemetry.TelemetryField_Uint64Value:\n\t\tstr = strconv.FormatUint(val.Uint64Value, 10)\n\t\treturn str\n\tcase *telemetry.TelemetryField_Sint32Value:\n\t\tstr = strconv.FormatInt(int64(val.Sint32Value), 10)\n\t\treturn str\n\tcase *telemetry.TelemetryField_Sint64Value:\n\t\tstr = strconv.FormatInt(val.Sint64Value, 10)\n\t\treturn str\n\t}\n\treturn \"\"\n}\n\n// xform Uint64 to int64\nfunc nxosValueXformUint64Toint64(field *telemetry.TelemetryField, value interface{}) interface{} {\n\tif field.GetUint64Value() != 0 {\n\t\treturn int64(value.(uint64))\n\t}\n\treturn nil\n}\n\n// xform string to float\nfunc nxosValueXformStringTofloat(field *telemetry.TelemetryField, _ interface{}) interface{} {\n\t// convert property to float from string.\n\tvals := field.GetStringValue()\n\tif vals != \"\" {\n\t\tif valf, err := strconv.ParseFloat(vals, 64); err == nil {\n\t\t\treturn valf\n\t\t}\n\t}\n\treturn nil\n}\n\n// xform string to uint64\nfunc nxosValueXformStringToUint64(field *telemetry.TelemetryField, _ interface{}) interface{} {\n\t// string to uint64\n\tvals := field.GetStringValue()\n\tif vals != \"\" {\n\t\tif val64, err := strconv.ParseUint(vals, 10, 64); err == nil {\n\t\t\treturn val64\n\t\t}\n\t}\n\treturn nil\n}\n\n// xform string to int64\nfunc nxosValueXformStringToInt64(field *telemetry.TelemetryField, _ interface{}) interface{} {\n\t// string to int64\n\tvals := field.GetStringValue()\n\tif vals != \"\" {\n\t\tif val64, err := strconv.ParseInt(vals, 10, 64); err == nil {\n\t\t\treturn val64\n\t\t}\n\t}\n\treturn nil\n}\n\n// auto-xform float properties\nfunc nxosValueAutoXformFloatProp(field *telemetry.TelemetryField, _ interface{}) interface{} {\n\t// check if we want auto xformation\n\tvals := field.GetStringValue()\n\tif vals != \"\" {\n\t\tif valf, err := strconv.ParseFloat(vals, 64); err == nil {\n\t\t\treturn valf\n\t\t}\n\t} // switch\n\treturn nil\n}\n\n// xform uint64 to string\nfunc nxosValueXformUint64ToString(field *telemetry.TelemetryField, _ interface{}) interface{} {\n\tswitch val := field.ValueByType.(type) {\n\tcase *telemetry.TelemetryField_StringValue:\n\t\tif len(val.StringValue) > 0 {\n\t\t\treturn val.StringValue\n\t\t}\n\tcase *telemetry.TelemetryField_Uint64Value:\n\t\treturn strconv.FormatUint(val.Uint64Value, 10)\n\t}\n\treturn nil\n}\n\n// Xform value field.\nfunc (c *CiscoTelemetryMDT) nxosValueXform(field *telemetry.TelemetryField, value interface{}, path string) interface{} {\n\tif strings.ContainsRune(path, ':') {\n\t\t// not NXOS\n\t\treturn nil\n\t}\n\tif _, ok := c.propMap[field.Name]; ok {\n\t\treturn c.propMap[field.Name](field, value)\n\t}\n\t// check if we want auto xformation\n\tif _, ok := c.propMap[\"auto-prop-xfromi\"]; ok {\n\t\treturn c.propMap[\"auto-prop-xfrom\"](field, value)\n\t}\n\t// Now check path based conversion.\n\t// If mapping is found then do the required transformation.\n\tif c.nxpathMap[path] == nil {\n\t\treturn nil\n\t}\n\tswitch c.nxpathMap[path][field.Name] {\n\t// Xformation supported is only from String, Uint32 and Uint64\n\tcase \"integer\":\n\t\tswitch val := field.ValueByType.(type) {\n\t\tcase *telemetry.TelemetryField_StringValue:\n\t\t\tif vali, err := strconv.ParseInt(val.StringValue, 10, 32); err == nil {\n\t\t\t\treturn vali\n\t\t\t}\n\t\tcase *telemetry.TelemetryField_Uint32Value:\n\t\t\tvali, ok := value.(uint32)\n\t\t\tif ok {\n\t\t\t\treturn vali\n\t\t\t}\n\t\tcase *telemetry.TelemetryField_Uint64Value:\n\t\t\tvali, ok := value.(uint64)\n\t\t\tif ok {\n\t\t\t\treturn vali\n\t\t\t}\n\t\t} // switch\n\t\treturn nil\n\t// Xformation supported is only from String\n\tcase \"float\":\n\t\t//nolint:revive // switch needed for `.(type)`\n\t\tswitch val := field.ValueByType.(type) {\n\t\tcase *telemetry.TelemetryField_StringValue:\n\t\t\tif valf, err := strconv.ParseFloat(val.StringValue, 64); err == nil {\n\t\t\t\treturn valf\n\t\t\t}\n\t\t} //switch\n\t\treturn nil\n\tcase \"string\":\n\t\treturn xformValueString(field)\n\tcase \"int64\":\n\t\tswitch val := field.ValueByType.(type) {\n\t\tcase *telemetry.TelemetryField_StringValue:\n\t\t\tif vali, err := strconv.ParseInt(val.StringValue, 10, 64); err == nil {\n\t\t\t\treturn vali\n\t\t\t}\n\t\tcase *telemetry.TelemetryField_Uint64Value:\n\t\t\treturn int64(value.(uint64))\n\t\t} // switch\n\t} // switch\n\treturn nil\n}\n\nfunc (c *CiscoTelemetryMDT) initMemPhys() {\n\tc.nxpathMap[\"show processes memory physical\"] = map[string]string{\"processname\": \"string\"}\n}\n\nfunc (c *CiscoTelemetryMDT) initBgpV4() {\n\tkey := \"show bgp ipv4 unicast\"\n\tc.nxpathMap[key] = make(map[string]string, 1)\n\tc.nxpathMap[key][\"aspath\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initCPU() {\n\tkey := \"show processes cpu\"\n\tc.nxpathMap[key] = make(map[string]string, 5)\n\tc.nxpathMap[key][\"kernel_percent\"] = \"float\"\n\tc.nxpathMap[key][\"idle_percent\"] = \"float\"\n\tc.nxpathMap[key][\"process\"] = \"string\"\n\tc.nxpathMap[key][\"user_percent\"] = \"float\"\n\tc.nxpathMap[key][\"onesec\"] = \"float\"\n}\n\nfunc (c *CiscoTelemetryMDT) initResources() {\n\tkey := \"show system resources\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"cpu_state_user\"] = \"float\"\n\tc.nxpathMap[key][\"kernel\"] = \"float\"\n\tc.nxpathMap[key][\"current_memory_status\"] = \"string\"\n\tc.nxpathMap[key][\"load_avg_15min\"] = \"float\"\n\tc.nxpathMap[key][\"idle\"] = \"float\"\n\tc.nxpathMap[key][\"load_avg_1min\"] = \"float\"\n\tc.nxpathMap[key][\"user\"] = \"float\"\n\tc.nxpathMap[key][\"cpu_state_idle\"] = \"float\"\n\tc.nxpathMap[key][\"load_avg_5min\"] = \"float\"\n\tc.nxpathMap[key][\"cpu_state_kernel\"] = \"float\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPower() {\n\tkey := \"show environment power\"\n\tc.nxpathMap[key] = make(map[string]string, 100)\n\tc.nxpathMap[key][\"reserve_sup\"] = \"string\"\n\tc.nxpathMap[key][\"det_volt\"] = \"string\"\n\tc.nxpathMap[key][\"heatsink_temp\"] = \"string\"\n\tc.nxpathMap[key][\"det_pintot\"] = \"string\"\n\tc.nxpathMap[key][\"det_iinb\"] = \"string\"\n\tc.nxpathMap[key][\"ps_input_current\"] = \"string\"\n\tc.nxpathMap[key][\"modnum\"] = \"string\"\n\tc.nxpathMap[key][\"trayfannum\"] = \"string\"\n\tc.nxpathMap[key][\"modstatus_3k\"] = \"string\"\n\tc.nxpathMap[key][\"fan2rpm\"] = \"string\"\n\tc.nxpathMap[key][\"amps_alloced\"] = \"string\"\n\tc.nxpathMap[key][\"all_inlets_connected\"] = \"string\"\n\tc.nxpathMap[key][\"tot_pow_out_actual_draw\"] = \"string\"\n\tc.nxpathMap[key][\"ps_redun_op_mode\"] = \"string\"\n\tc.nxpathMap[key][\"curtemp\"] = \"string\"\n\tc.nxpathMap[key][\"mod_model\"] = \"string\"\n\tc.nxpathMap[key][\"fanmodel\"] = \"string\"\n\tc.nxpathMap[key][\"ps_output_current\"] = \"string\"\n\tc.nxpathMap[key][\"majthres\"] = \"string\"\n\tc.nxpathMap[key][\"input_type\"] = \"string\"\n\tc.nxpathMap[key][\"allocated\"] = \"string\"\n\tc.nxpathMap[key][\"fanhwver\"] = \"string\"\n\tc.nxpathMap[key][\"clkhwver\"] = \"string\"\n\tc.nxpathMap[key][\"fannum\"] = \"string\"\n\tc.nxpathMap[key][\"watts_requested\"] = \"string\"\n\tc.nxpathMap[key][\"cumulative_power\"] = \"string\"\n\tc.nxpathMap[key][\"tot_gridB_capacity\"] = \"string\"\n\tc.nxpathMap[key][\"pow_used_by_mods\"] = \"string\"\n\tc.nxpathMap[key][\"tot_pow_alloc_budgeted\"] = \"string\"\n\tc.nxpathMap[key][\"psumod\"] = \"string\"\n\tc.nxpathMap[key][\"ps_status_3k\"] = \"string\"\n\tc.nxpathMap[key][\"temptype\"] = \"string\"\n\tc.nxpathMap[key][\"regval\"] = \"string\"\n\tc.nxpathMap[key][\"inlet_temp\"] = \"string\"\n\tc.nxpathMap[key][\"det_cord\"] = \"string\"\n\tc.nxpathMap[key][\"reserve_fan\"] = \"string\"\n\tc.nxpathMap[key][\"det_pina\"] = \"string\"\n\tc.nxpathMap[key][\"minthres\"] = \"string\"\n\tc.nxpathMap[key][\"actual_draw\"] = \"string\"\n\tc.nxpathMap[key][\"sensor\"] = \"string\"\n\tc.nxpathMap[key][\"zone\"] = \"string\"\n\tc.nxpathMap[key][\"det_iin\"] = \"string\"\n\tc.nxpathMap[key][\"det_iout\"] = \"string\"\n\tc.nxpathMap[key][\"det_vin\"] = \"string\"\n\tc.nxpathMap[key][\"fan1rpm\"] = \"string\"\n\tc.nxpathMap[key][\"tot_gridA_capacity\"] = \"string\"\n\tc.nxpathMap[key][\"fanperc\"] = \"string\"\n\tc.nxpathMap[key][\"det_pout\"] = \"string\"\n\tc.nxpathMap[key][\"alarm_str\"] = \"string\"\n\tc.nxpathMap[key][\"zonespeed\"] = \"string\"\n\tc.nxpathMap[key][\"det_total_cap\"] = \"string\"\n\tc.nxpathMap[key][\"reserve_xbar\"] = \"string\"\n\tc.nxpathMap[key][\"det_vout\"] = \"string\"\n\tc.nxpathMap[key][\"watts_alloced\"] = \"string\"\n\tc.nxpathMap[key][\"ps_in_power\"] = \"string\"\n\tc.nxpathMap[key][\"tot_pow_input_actual_draw\"] = \"string\"\n\tc.nxpathMap[key][\"ps_output_voltage\"] = \"string\"\n\tc.nxpathMap[key][\"det_name\"] = \"string\"\n\tc.nxpathMap[key][\"tempmod\"] = \"string\"\n\tc.nxpathMap[key][\"clockname\"] = \"string\"\n\tc.nxpathMap[key][\"fanname\"] = \"string\"\n\tc.nxpathMap[key][\"regnumstr\"] = \"string\"\n\tc.nxpathMap[key][\"bitnumstr\"] = \"string\"\n\tc.nxpathMap[key][\"ps_slot\"] = \"string\"\n\tc.nxpathMap[key][\"actual_out\"] = \"string\"\n\tc.nxpathMap[key][\"ps_input_voltage\"] = \"string\"\n\tc.nxpathMap[key][\"psmodel\"] = \"string\"\n\tc.nxpathMap[key][\"speed\"] = \"string\"\n\tc.nxpathMap[key][\"clkmodel\"] = \"string\"\n\tc.nxpathMap[key][\"ps_redun_mode_3k\"] = \"string\"\n\tc.nxpathMap[key][\"tot_pow_capacity\"] = \"string\"\n\tc.nxpathMap[key][\"amps\"] = \"string\"\n\tc.nxpathMap[key][\"available_pow\"] = \"string\"\n\tc.nxpathMap[key][\"reserve_supxbarfan\"] = \"string\"\n\tc.nxpathMap[key][\"watts\"] = \"string\"\n\tc.nxpathMap[key][\"det_pinb\"] = \"string\"\n\tc.nxpathMap[key][\"det_vinb\"] = \"string\"\n\tc.nxpathMap[key][\"ps_state\"] = \"string\"\n\tc.nxpathMap[key][\"det_sw_alarm\"] = \"string\"\n\tc.nxpathMap[key][\"regnum\"] = \"string\"\n\tc.nxpathMap[key][\"amps_requested\"] = \"string\"\n\tc.nxpathMap[key][\"fanrpm\"] = \"string\"\n\tc.nxpathMap[key][\"actual_input\"] = \"string\"\n\tc.nxpathMap[key][\"outlet_temp\"] = \"string\"\n\tc.nxpathMap[key][\"tot_capa\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPtpCorrection() {\n\tkey := \"show ptp corrections\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"sup-time\"] = \"string\"\n\tc.nxpathMap[key][\"correction-val\"] = \"int64\"\n\tc.nxpathMap[key][\"ptp-header\"] = \"string\"\n\tc.nxpathMap[key][\"intf-name\"] = \"string\"\n\tc.nxpathMap[key][\"ptp-end\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initTrans() {\n\tkey := \"show interface transceiver details\"\n\tc.nxpathMap[key] = make(map[string]string, 100)\n\tc.nxpathMap[key][\"uncorrect_ber_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_cur_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"current_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_max_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"serialnum\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_acc_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_max_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"laser_temp_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"type\"] = \"string\"\n\tc.nxpathMap[key][\"rx_pwr_0\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"qsfp_or_cfp\"] = \"string\"\n\tc.nxpathMap[key][\"protocol_type\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_cur_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"tec_current\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_max_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_min\"] = \"string\"\n\tc.nxpathMap[key][\"current_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_acc_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"snr_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"rev\"] = \"string\"\n\tc.nxpathMap[key][\"laser_temp_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"current\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr_1\"] = \"float\"\n\tc.nxpathMap[key][\"tec_current_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_cur_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"cisco_part_number\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_acc_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"temp_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"laser_freq_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_max_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"snr_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_cur_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"tx_pwr_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_min_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_min_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"rx_pwr_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"tec_current_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_acc_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"rx_pwr_4\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_cur\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"rx_pwr_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"bit_encoding\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_acc\"] = \"string\"\n\tc.nxpathMap[key][\"sfp\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_acc_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_min\"] = \"string\"\n\tc.nxpathMap[key][\"current_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_max_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_cur_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"current_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_acc_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"snr_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_acc\"] = \"string\"\n\tc.nxpathMap[key][\"tx_len\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"txcvr_type\"] = \"string\"\n\tc.nxpathMap[key][\"tec_current_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"volt_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"temp_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_min_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"laser_freq\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_min_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_cur_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_max_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"fiber_type_byte0\"] = \"string\"\n\tc.nxpathMap[key][\"laser_freq_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_cur_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"partnum\"] = \"string\"\n\tc.nxpathMap[key][\"snr\"] = \"float\"\n\tc.nxpathMap[key][\"volt_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"connector_type\"] = \"string\"\n\tc.nxpathMap[key][\"tx_medium\"] = \"string\"\n\tc.nxpathMap[key][\"tx_pwr_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"cisco_vendor_id\"] = \"string\"\n\tc.nxpathMap[key][\"cisco_ext_id\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_max_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_max\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_min_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"tx_pwr_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"10gbe_code\"] = \"string\"\n\tc.nxpathMap[key][\"cable_type\"] = \"string\"\n\tc.nxpathMap[key][\"laser_freq_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr_3\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr\"] = \"float\"\n\tc.nxpathMap[key][\"volt_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_cur_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"temperature\"] = \"float\"\n\tc.nxpathMap[key][\"voltage\"] = \"float\"\n\tc.nxpathMap[key][\"tx_pwr\"] = \"float\"\n\tc.nxpathMap[key][\"laser_temp_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"tx_speeds\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_min_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_min_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"ciscoid\"] = \"string\"\n\tc.nxpathMap[key][\"tx_pwr_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"cisco_product_id\"] = \"string\"\n\tc.nxpathMap[key][\"info_not_available\"] = \"string\"\n\tc.nxpathMap[key][\"laser_temp\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_cur\"] = \"string\"\n\tc.nxpathMap[key][\"fiber_type_byte1\"] = \"string\"\n\tc.nxpathMap[key][\"tx_type\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_min_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"pre_fec_ber_warn_lo\"] = \"string\"\n\tc.nxpathMap[key][\"temp_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"volt_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr_alrm_lo\"] = \"float\"\n\tc.nxpathMap[key][\"rx_pwr_2\"] = \"float\"\n\tc.nxpathMap[key][\"tec_current_alrm_hi\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_acc_alrm_lo\"] = \"string\"\n\tc.nxpathMap[key][\"uncorrect_ber_max_alrm_hi\"] = \"string\"\n\tc.nxpathMap[key][\"temp_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"snr_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"laser_temp_warn_lo\"] = \"float\"\n\tc.nxpathMap[key][\"pre_fec_ber_acc_warn_hi\"] = \"string\"\n\tc.nxpathMap[key][\"laser_freq_warn_hi\"] = \"float\"\n\tc.nxpathMap[key][\"uncorrect_ber_max\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIgmp() {\n\tkey := \"show ip igmp groups vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"group-type\"] = \"string\"\n\tc.nxpathMap[key][\"translate\"] = \"string\"\n\tc.nxpathMap[key][\"sourceaddress\"] = \"string\"\n\tc.nxpathMap[key][\"vrf-cntxt\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"group-addr\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initVrfAll() {\n\tkey := \"show ip igmp interface vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"if-name\"] = \"string\"\n\tc.nxpathMap[key][\"static-group-map\"] = \"string\"\n\tc.nxpathMap[key][\"rll\"] = \"string\"\n\tc.nxpathMap[key][\"host-proxy\"] = \"string\"\n\tc.nxpathMap[key][\"il\"] = \"string\"\n\tc.nxpathMap[key][\"join-group-map\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"host-proxy-group-map\"] = \"string\"\n\tc.nxpathMap[key][\"next-query\"] = \"string\"\n\tc.nxpathMap[key][\"q-ver\"] = \"string\"\n\tc.nxpathMap[key][\"if-status\"] = \"string\"\n\tc.nxpathMap[key][\"un-solicited\"] = \"string\"\n\tc.nxpathMap[key][\"ip-sum\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIgmpSnoop() {\n\tkey := \"show ip igmp snooping\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"repsup\"] = \"string\"\n\tc.nxpathMap[key][\"omf_enabled\"] = \"string\"\n\tc.nxpathMap[key][\"v3repsup\"] = \"string\"\n\tc.nxpathMap[key][\"grepsup\"] = \"string\"\n\tc.nxpathMap[key][\"lkupmode\"] = \"string\"\n\tc.nxpathMap[key][\"description\"] = \"string\"\n\tc.nxpathMap[key][\"vlinklocalgrpsup\"] = \"string\"\n\tc.nxpathMap[key][\"gv3repsup\"] = \"string\"\n\tc.nxpathMap[key][\"reportfloodall\"] = \"string\"\n\tc.nxpathMap[key][\"leavegroupaddress\"] = \"string\"\n\tc.nxpathMap[key][\"enabled\"] = \"string\"\n\tc.nxpathMap[key][\"omf\"] = \"string\"\n\tc.nxpathMap[key][\"sq\"] = \"string\"\n\tc.nxpathMap[key][\"sqr\"] = \"string\"\n\tc.nxpathMap[key][\"eht\"] = \"string\"\n\tc.nxpathMap[key][\"fl\"] = \"string\"\n\tc.nxpathMap[key][\"reportfloodenable\"] = \"string\"\n\tc.nxpathMap[key][\"snoop-on\"] = \"string\"\n\tc.nxpathMap[key][\"glinklocalgrpsup\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIgmpSnoopGroups() {\n\tkey := \"show ip igmp snooping groups\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"src-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"source\"] = \"string\"\n\tc.nxpathMap[key][\"dyn-if-name\"] = \"string\"\n\tc.nxpathMap[key][\"raddr\"] = \"string\"\n\tc.nxpathMap[key][\"old-host\"] = \"string\"\n\tc.nxpathMap[key][\"snoop-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"omf-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"src-expires\"] = \"string\"\n\tc.nxpathMap[key][\"addr\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIgmpSnoopGroupDetails() {\n\tkey := \"show ip igmp snooping groups detail\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"src-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"source\"] = \"string\"\n\tc.nxpathMap[key][\"dyn-if-name\"] = \"string\"\n\tc.nxpathMap[key][\"raddr\"] = \"string\"\n\tc.nxpathMap[key][\"old-host\"] = \"string\"\n\tc.nxpathMap[key][\"snoop-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"omf-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"src-expires\"] = \"string\"\n\tc.nxpathMap[key][\"addr\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIgmpSnoopGroupsSumm() {\n\tkey := \"show ip igmp snooping groups summary\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"src-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"source\"] = \"string\"\n\tc.nxpathMap[key][\"dyn-if-name\"] = \"string\"\n\tc.nxpathMap[key][\"raddr\"] = \"string\"\n\tc.nxpathMap[key][\"old-host\"] = \"string\"\n\tc.nxpathMap[key][\"snoop-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"omf-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"src-expires\"] = \"string\"\n\tc.nxpathMap[key][\"addr\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initMrouter() {\n\tkey := \"show ip igmp snooping mrouter\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initSnoopStats() {\n\tkey := \"show ip igmp snooping statistics\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"ut\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimInterface() {\n\tkey := \"show ip pim interface vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"if-is-border\"] = \"string\"\n\tc.nxpathMap[key][\"cached_if_status\"] = \"string\"\n\tc.nxpathMap[key][\"genid\"] = \"string\"\n\tc.nxpathMap[key][\"if-name\"] = \"string\"\n\tc.nxpathMap[key][\"last-cleared\"] = \"string\"\n\tc.nxpathMap[key][\"is-pim-vpc-svi\"] = \"string\"\n\tc.nxpathMap[key][\"if-addr\"] = \"string\"\n\tc.nxpathMap[key][\"is-pim-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"pim-dr-address\"] = \"string\"\n\tc.nxpathMap[key][\"hello-timer\"] = \"string\"\n\tc.nxpathMap[key][\"pim-bfd-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"vpc-peer-nbr\"] = \"string\"\n\tc.nxpathMap[key][\"nbr-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"is-auto-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"if-status\"] = \"string\"\n\tc.nxpathMap[key][\"jp-out-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"if-addr-summary\"] = \"string\"\n\tc.nxpathMap[key][\"if-dr\"] = \"string\"\n\tc.nxpathMap[key][\"jp-in-policy-name\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimNeigh() {\n\tkey := \"show ip pim neighbor vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"longest-hello-intvl\"] = \"string\"\n\tc.nxpathMap[key][\"if-name\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"expires\"] = \"string\"\n\tc.nxpathMap[key][\"bfd-state\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimRoute() {\n\tkey := \"show ip pim route vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"rpf-nbr-1\"] = \"string\"\n\tc.nxpathMap[key][\"rpf-nbr-addr\"] = \"string\"\n\tc.nxpathMap[key][\"register\"] = \"string\"\n\tc.nxpathMap[key][\"sgexpire\"] = \"string\"\n\tc.nxpathMap[key][\"oif-bf-str\"] = \"string\"\n\tc.nxpathMap[key][\"mcast-addrs\"] = \"string\"\n\tc.nxpathMap[key][\"rp-addr\"] = \"string\"\n\tc.nxpathMap[key][\"immediate-bf-str\"] = \"string\"\n\tc.nxpathMap[key][\"sgr-prune-list-bf-str\"] = \"string\"\n\tc.nxpathMap[key][\"context-name\"] = \"string\"\n\tc.nxpathMap[key][\"intf-name\"] = \"string\"\n\tc.nxpathMap[key][\"immediate-timeout-bf-str\"] = \"string\"\n\tc.nxpathMap[key][\"rp-local\"] = \"string\"\n\tc.nxpathMap[key][\"sgrexpire\"] = \"string\"\n\tc.nxpathMap[key][\"timeout-bf-str\"] = \"string\"\n\tc.nxpathMap[key][\"timeleft\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimRp() {\n\tkey := \"show ip pim rp vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 20)\n\tc.nxpathMap[key][\"is-bsr-forward-only\"] = \"string\"\n\tc.nxpathMap[key][\"is-rpaddr-local\"] = \"string\"\n\tc.nxpathMap[key][\"bsr-expires\"] = \"string\"\n\tc.nxpathMap[key][\"autorp-expire-time\"] = \"string\"\n\tc.nxpathMap[key][\"rp-announce-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"rp-cand-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"is-autorp-forward-only\"] = \"string\"\n\tc.nxpathMap[key][\"rp-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"rp-owner-flags\"] = \"string\"\n\tc.nxpathMap[key][\"df-bits-recovered\"] = \"string\"\n\tc.nxpathMap[key][\"bs-timer\"] = \"string\"\n\tc.nxpathMap[key][\"rp-discovery-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"arp-rp-addr\"] = \"string\"\n\tc.nxpathMap[key][\"auto-rp-addr\"] = \"string\"\n\tc.nxpathMap[key][\"autorp-expires\"] = \"string\"\n\tc.nxpathMap[key][\"is-autorp-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"is-bsr-local\"] = \"string\"\n\tc.nxpathMap[key][\"is-autorp-listen-only\"] = \"string\"\n\tc.nxpathMap[key][\"autorp-dis-timer\"] = \"string\"\n\tc.nxpathMap[key][\"bsr-rp-expires\"] = \"string\"\n\tc.nxpathMap[key][\"static-rp-group-map\"] = \"string\"\n\tc.nxpathMap[key][\"rp-source\"] = \"string\"\n\tc.nxpathMap[key][\"autorp-cand-address\"] = \"string\"\n\tc.nxpathMap[key][\"autorp-up-time\"] = \"string\"\n\tc.nxpathMap[key][\"is-bsr-enabled\"] = \"string\"\n\tc.nxpathMap[key][\"bsr-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"is-bsr-listen-only\"] = \"string\"\n\tc.nxpathMap[key][\"rpf-nbr-address\"] = \"string\"\n\tc.nxpathMap[key][\"is-rp-local\"] = \"string\"\n\tc.nxpathMap[key][\"is-autorp-local\"] = \"string\"\n\tc.nxpathMap[key][\"bsr-policy-name\"] = \"string\"\n\tc.nxpathMap[key][\"grange-grp\"] = \"string\"\n\tc.nxpathMap[key][\"rp-addr\"] = \"string\"\n\tc.nxpathMap[key][\"anycast-rp-addr\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimStats() {\n\tkey := \"show ip pim statistics vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 1)\n\tc.nxpathMap[key][\"vrf-name\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIntfBrief() {\n\tkey := \"show interface brief\"\n\tc.nxpathMap[key] = make(map[string]string, 2)\n\tc.nxpathMap[key][\"speed\"] = \"string\"\n\tc.nxpathMap[key][\"vlan\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initPimVrf() {\n\tkey := \"show ip pim vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 1)\n\tc.nxpathMap[key][\"table-id\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIPMroute() {\n\tkey := \"show ip mroute summary vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 40)\n\tc.nxpathMap[key][\"nat-mode\"] = \"string\"\n\tc.nxpathMap[key][\"oif-name\"] = \"string\"\n\tc.nxpathMap[key][\"nat-route-type\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"mofrr-nbr\"] = \"string\"\n\tc.nxpathMap[key][\"extranet_addr\"] = \"string\"\n\tc.nxpathMap[key][\"stale-route\"] = \"string\"\n\tc.nxpathMap[key][\"pending\"] = \"string\"\n\tc.nxpathMap[key][\"bidir\"] = \"string\"\n\tc.nxpathMap[key][\"expry_timer\"] = \"string\"\n\tc.nxpathMap[key][\"mofrr-iif\"] = \"string\"\n\tc.nxpathMap[key][\"group_addrs\"] = \"string\"\n\tc.nxpathMap[key][\"mpib-name\"] = \"string\"\n\tc.nxpathMap[key][\"rpf\"] = \"string\"\n\tc.nxpathMap[key][\"mcast-addrs\"] = \"string\"\n\tc.nxpathMap[key][\"route-mdt-iod\"] = \"string\"\n\tc.nxpathMap[key][\"sr-oif\"] = \"string\"\n\tc.nxpathMap[key][\"stats-rate-buf\"] = \"string\"\n\tc.nxpathMap[key][\"source_addr\"] = \"string\"\n\tc.nxpathMap[key][\"route-iif\"] = \"string\"\n\tc.nxpathMap[key][\"rpf-nbr\"] = \"string\"\n\tc.nxpathMap[key][\"translated-route-src\"] = \"string\"\n\tc.nxpathMap[key][\"group_addr\"] = \"string\"\n\tc.nxpathMap[key][\"lisp-src-rloc\"] = \"string\"\n\tc.nxpathMap[key][\"stats-pndg\"] = \"string\"\n\tc.nxpathMap[key][\"rate_buf\"] = \"string\"\n\tc.nxpathMap[key][\"extranet_vrf_name\"] = \"string\"\n\tc.nxpathMap[key][\"fabric-interest\"] = \"string\"\n\tc.nxpathMap[key][\"translated-route-grp\"] = \"string\"\n\tc.nxpathMap[key][\"internal\"] = \"string\"\n\tc.nxpathMap[key][\"oif-mpib-name\"] = \"string\"\n\tc.nxpathMap[key][\"oif-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"omd-vpc-svi\"] = \"string\"\n\tc.nxpathMap[key][\"source_addrs\"] = \"string\"\n\tc.nxpathMap[key][\"stale-oif\"] = \"string\"\n\tc.nxpathMap[key][\"core-interest\"] = \"string\"\n\tc.nxpathMap[key][\"oif-list-bitfield\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIpv6Mroute() {\n\tkey := \"show ipv6 mroute summary vrf all\"\n\tc.nxpathMap[key] = make(map[string]string, 40)\n\tc.nxpathMap[key][\"nat-mode\"] = \"string\"\n\tc.nxpathMap[key][\"oif-name\"] = \"string\"\n\tc.nxpathMap[key][\"nat-route-type\"] = \"string\"\n\tc.nxpathMap[key][\"uptime\"] = \"string\"\n\tc.nxpathMap[key][\"mofrr-nbr\"] = \"string\"\n\tc.nxpathMap[key][\"extranet_addr\"] = \"string\"\n\tc.nxpathMap[key][\"stale-route\"] = \"string\"\n\tc.nxpathMap[key][\"pending\"] = \"string\"\n\tc.nxpathMap[key][\"bidir\"] = \"string\"\n\tc.nxpathMap[key][\"expry_timer\"] = \"string\"\n\tc.nxpathMap[key][\"mofrr-iif\"] = \"string\"\n\tc.nxpathMap[key][\"group_addrs\"] = \"string\"\n\tc.nxpathMap[key][\"mpib-name\"] = \"string\"\n\tc.nxpathMap[key][\"rpf\"] = \"string\"\n\tc.nxpathMap[key][\"mcast-addrs\"] = \"string\"\n\tc.nxpathMap[key][\"route-mdt-iod\"] = \"string\"\n\tc.nxpathMap[key][\"sr-oif\"] = \"string\"\n\tc.nxpathMap[key][\"stats-rate-buf\"] = \"string\"\n\tc.nxpathMap[key][\"source_addr\"] = \"string\"\n\tc.nxpathMap[key][\"route-iif\"] = \"string\"\n\tc.nxpathMap[key][\"rpf-nbr\"] = \"string\"\n\tc.nxpathMap[key][\"translated-route-src\"] = \"string\"\n\tc.nxpathMap[key][\"group_addr\"] = \"string\"\n\tc.nxpathMap[key][\"lisp-src-rloc\"] = \"string\"\n\tc.nxpathMap[key][\"stats-pndg\"] = \"string\"\n\tc.nxpathMap[key][\"rate_buf\"] = \"string\"\n\tc.nxpathMap[key][\"extranet_vrf_name\"] = \"string\"\n\tc.nxpathMap[key][\"fabric-interest\"] = \"string\"\n\tc.nxpathMap[key][\"translated-route-grp\"] = \"string\"\n\tc.nxpathMap[key][\"internal\"] = \"string\"\n\tc.nxpathMap[key][\"oif-mpib-name\"] = \"string\"\n\tc.nxpathMap[key][\"oif-uptime\"] = \"string\"\n\tc.nxpathMap[key][\"omd-vpc-svi\"] = \"string\"\n\tc.nxpathMap[key][\"source_addrs\"] = \"string\"\n\tc.nxpathMap[key][\"stale-oif\"] = \"string\"\n\tc.nxpathMap[key][\"core-interest\"] = \"string\"\n\tc.nxpathMap[key][\"oif-list-bitfield\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initVpc() {\n\tkey := \"sys/vpc\"\n\tc.nxpathMap[key] = make(map[string]string, 5)\n\tc.nxpathMap[key][\"type2CompatQualStr\"] = \"string\"\n\tc.nxpathMap[key][\"compatQualStr\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"issuFromVer\"] = \"string\"\n\tc.nxpathMap[key][\"issuToVer\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initBgp() {\n\tkey := \"sys/bgp\"\n\tc.nxpathMap[key] = make(map[string]string, 18)\n\tc.nxpathMap[key][\"dynRtMap\"] = \"string\"\n\tc.nxpathMap[key][\"nhRtMap\"] = \"string\"\n\tc.nxpathMap[key][\"epePeerSet\"] = \"string\"\n\tc.nxpathMap[key][\"asn\"] = \"string\"\n\tc.nxpathMap[key][\"peerImp\"] = \"string\"\n\tc.nxpathMap[key][\"wght\"] = \"string\"\n\tc.nxpathMap[key][\"assocDom\"] = \"string\"\n\tc.nxpathMap[key][\"tblMap\"] = \"string\"\n\tc.nxpathMap[key][\"unSupprMap\"] = \"string\"\n\tc.nxpathMap[key][\"sessionContImp\"] = \"string\"\n\tc.nxpathMap[key][\"allocLblRtMap\"] = \"string\"\n\tc.nxpathMap[key][\"defMetric\"] = \"string\"\n\tc.nxpathMap[key][\"password\"] = \"string\"\n\tc.nxpathMap[key][\"retainRttRtMap\"] = \"string\"\n\tc.nxpathMap[key][\"clusterId\"] = \"string\"\n\tc.nxpathMap[key][\"localAsn\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"defOrgRtMap\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initCh() {\n\tkey := \"sys/ch\"\n\tc.nxpathMap[key] = make(map[string]string, 10)\n\tc.nxpathMap[key][\"fanName\"] = \"string\"\n\tc.nxpathMap[key][\"typeCordConnected\"] = \"string\"\n\tc.nxpathMap[key][\"vendor\"] = \"string\"\n\tc.nxpathMap[key][\"model\"] = \"string\"\n\tc.nxpathMap[key][\"rev\"] = \"string\"\n\tc.nxpathMap[key][\"vdrId\"] = \"string\"\n\tc.nxpathMap[key][\"hardwareAlarm\"] = \"string\"\n\tc.nxpathMap[key][\"unit\"] = \"string\"\n\tc.nxpathMap[key][\"hwVer\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initIntf() {\n\tkey := \"sys/intf\"\n\tc.nxpathMap[key] = make(map[string]string, 10)\n\tc.nxpathMap[key][\"descr\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"lastStCause\"] = \"string\"\n\tc.nxpathMap[key][\"description\"] = \"string\"\n\tc.nxpathMap[key][\"unit\"] = \"string\"\n\tc.nxpathMap[key][\"operFECMode\"] = \"string\"\n\tc.nxpathMap[key][\"operBitset\"] = \"string\"\n\tc.nxpathMap[key][\"mdix\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initProcsys() {\n\tkey := \"sys/procsys\"\n\tc.nxpathMap[key] = make(map[string]string, 10)\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"id\"] = \"string\"\n\tc.nxpathMap[key][\"upTs\"] = \"string\"\n\tc.nxpathMap[key][\"interval\"] = \"string\"\n\tc.nxpathMap[key][\"memstatus\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initProc() {\n\tkey := \"sys/proc\"\n\tc.nxpathMap[key] = make(map[string]string, 2)\n\tc.nxpathMap[key][\"processName\"] = \"string\"\n\tc.nxpathMap[key][\"procArg\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initBfd() {\n\tkey := \"sys/bfd/inst\"\n\tc.nxpathMap[key] = make(map[string]string, 4)\n\tc.nxpathMap[key][\"descr\"] = \"string\"\n\tc.nxpathMap[key][\"vrfName\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initLldp() {\n\tkey := \"sys/lldp\"\n\tc.nxpathMap[key] = make(map[string]string, 7)\n\tc.nxpathMap[key][\"sysDesc\"] = \"string\"\n\tc.nxpathMap[key][\"portDesc\"] = \"string\"\n\tc.nxpathMap[key][\"portIdV\"] = \"string\"\n\tc.nxpathMap[key][\"chassisIdV\"] = \"string\"\n\tc.nxpathMap[key][\"sysName\"] = \"string\"\n\tc.nxpathMap[key][\"name\"] = \"string\"\n\tc.nxpathMap[key][\"id\"] = \"string\"\n}\n\nfunc (c *CiscoTelemetryMDT) initDB() {\n\tc.nxpathMap = make(map[string]map[string]string, 200)\n\n\tc.initPower()\n\tc.initMemPhys()\n\tc.initBgpV4()\n\tc.initCPU()\n\tc.initResources()\n\tc.initPtpCorrection()\n\tc.initTrans()\n\tc.initIgmp()\n\tc.initVrfAll()\n\tc.initIgmpSnoop()\n\tc.initIgmpSnoopGroups()\n\tc.initIgmpSnoopGroupDetails()\n\tc.initIgmpSnoopGroupsSumm()\n\tc.initMrouter()\n\tc.initSnoopStats()\n\tc.initPimInterface()\n\tc.initPimNeigh()\n\tc.initPimRoute()\n\tc.initPimRp()\n\tc.initPimStats()\n\tc.initIntfBrief()\n\tc.initPimVrf()\n\tc.initIPMroute()\n\tc.initIpv6Mroute()\n\tc.initVpc()\n\tc.initBgp()\n\tc.initCh()\n\tc.initIntf()\n\tc.initProcsys()\n\tc.initProc()\n\tc.initBfd()\n\tc.initLldp()\n}\n"
  },
  {
    "path": "plugins/inputs/cisco_telemetry_mdt/sample.conf",
    "content": "# Cisco model-driven telemetry (MDT) input plugin for IOS XR, IOS XE and NX-OS platforms\n[[inputs.cisco_telemetry_mdt]]\n ## Telemetry transport can be \"tcp\" or \"grpc\".  TLS is only supported when\n ## using the grpc transport.\n transport = \"grpc\"\n\n ## Address and port to host telemetry listener\n service_address = \":57000\"\n\n ## Grpc Maximum Message Size, default is 4MB, increase the size. This is\n ## stored as a uint32, and limited to 4294967295.\n max_msg_size = 4000000\n\n ## Enable TLS; grpc transport only.\n # tls_cert = \"/etc/telegraf/cert.pem\"\n # tls_key = \"/etc/telegraf/key.pem\"\n\n ## Enable TLS client authentication and define allowed CA certificates; grpc\n ##  transport only.\n # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n ## Define (for certain nested telemetry measurements with embedded tags) which fields are tags\n # embedded_tags = [\"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics/class-stats/class-name\"]\n\n ## Include the delete field in every telemetry message.\n # include_delete_field = false\n\n ## Specify custom name for incoming MDT source field.\n # source_field_name = \"mdt_source\"\n\n ## Define aliases to map telemetry encoding paths to simple measurement names\n [inputs.cisco_telemetry_mdt.aliases]\n   ifstats = \"ietf-interfaces:interfaces-state/interface/statistics\"\n ## Define Property Xformation, please refer README and https://pubhub.devnetcloud.com/media/dme-docs-9-3-3/docs/appendix/ for Model details.\n [inputs.cisco_telemetry_mdt.dmes]\n#    Global Property Xformation.\n#    prop1 = \"uint64 to int\"\n#    prop2 = \"uint64 to string\"\n#    prop3 = \"string to uint64\"\n#    prop4 = \"string to int64\"\n#    prop5 = \"string to float64\"\n#    auto-prop-xfrom = \"auto-float-xfrom\" #Xform any property which is string, and has float number to type float64\n#    Per Path property xformation, Name is telemetry configuration under sensor-group, path configuration \"WORD         Distinguished Name\"\n#    Per Path configuration is better as it avoid property collision issue of types.\n#    dnpath = '{\"Name\": \"show ip route summary\",\"prop\": [{\"Key\": \"routes\",\"Value\": \"string\"}, {\"Key\": \"best-paths\",\"Value\": \"string\"}]}'\n#    dnpath2 = '{\"Name\": \"show processes cpu\",\"prop\": [{\"Key\": \"kernel_percent\",\"Value\": \"float\"}, {\"Key\": \"idle_percent\",\"Value\": \"float\"}, {\"Key\": \"process\",\"Value\": \"string\"}, {\"Key\": \"user_percent\",\"Value\": \"float\"}, {\"Key\": \"onesec\",\"Value\": \"float\"}]}'\n#    dnpath3 = '{\"Name\": \"show processes memory physical\",\"prop\": [{\"Key\": \"processname\",\"Value\": \"string\"}]}'\n\n ## Additional GRPC connection settings.\n [inputs.cisco_telemetry_mdt.grpc_enforcement_policy]\n  ## GRPC permit keepalives without calls, set to true if your clients are\n  ## sending pings without calls in-flight. This can sometimes happen on IOS-XE\n  ## devices where the GRPC connection is left open but subscriptions have been\n  ## removed, and adding subsequent subscriptions does not keep a stable session.\n  # permit_keepalive_without_calls = false\n\n  ## GRPC minimum timeout between successive pings, decreasing this value may\n  ## help if this plugin is closing connections with ENHANCE_YOUR_CALM (too_many_pings).\n  # keepalive_minimum_time = \"5m\"\n"
  },
  {
    "path": "plugins/inputs/clickhouse/README.md",
    "content": "# ClickHouse Input Plugin\n\nThis plugin gathers statistics data from a [ClickHouse server][clickhouse].\nUsers on Clickhouse Cloud will not see the Zookeeper metrics as they may not\nhave permissions to query those tables.\n\n⭐ Telegraf v1.14.0\n🏷️ server\n💻 all\n\n[clickhouse]: https://github.com/ClickHouse/ClickHouse\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many ClickHouse servers\n[[inputs.clickhouse]]\n  ## Username for authorization on ClickHouse server\n  username = \"default\"\n\n  ## Password for authorization on ClickHouse server\n  # password = \"\"\n\n  ## HTTP(s) timeout while getting metrics values\n  ## The timeout includes connection time, any redirects, and reading the\n  ## response body.\n  # timeout = 5s\n\n  ## List of servers for metrics scraping\n  ## metrics scrape via HTTP(s) clickhouse interface\n  ## https://clickhouse.tech/docs/en/interfaces/http/\n  servers = [\"http://127.0.0.1:8123\"]\n\n  ## Server Variant\n  ## When set to \"managed\", some queries are excluded from being run. This is\n  ## useful for instances hosted in ClickHouse Cloud where certain tables are\n  ## not available.\n  # variant = \"self-hosted\"\n\n  ## If \"auto_discovery\"\" is \"true\" plugin tries to connect to all servers\n  ## available in the cluster with using same \"user:password\" described in\n  ## \"user\" and \"password\" parameters and get this server hostname list from\n  ## \"system.clusters\" table. See\n  ## - https://clickhouse.tech/docs/en/operations/system_tables/#system-clusters\n  ## - https://clickhouse.tech/docs/en/operations/server_settings/settings/#server_settings_remote_servers\n  ## - https://clickhouse.tech/docs/en/operations/table_engines/distributed/\n  ## - https://clickhouse.tech/docs/en/operations/table_engines/replication/#creating-replicated-tables\n  # auto_discovery = true\n\n  ## Filter cluster names in \"system.clusters\" when \"auto_discovery\" is \"true\"\n  ## when this filter present then \"WHERE cluster IN (...)\" filter will apply\n  ## please use only full cluster names here, regexp and glob filters is not\n  ## allowed for \"/etc/clickhouse-server/config.d/remote.xml\"\n  ## <yandex>\n  ##  <remote_servers>\n  ##    <my-own-cluster>\n  ##        <shard>\n  ##          <replica><host>clickhouse-ru-1.local</host><port>9000</port></replica>\n  ##          <replica><host>clickhouse-ru-2.local</host><port>9000</port></replica>\n  ##        </shard>\n  ##        <shard>\n  ##          <replica><host>clickhouse-eu-1.local</host><port>9000</port></replica>\n  ##          <replica><host>clickhouse-eu-2.local</host><port>9000</port></replica>\n  ##        </shard>\n  ##    </my-own-cluster>\n  ##  </remote_servers>\n  ##\n  ## </yandex>\n  ##\n  ## example: cluster_include = [\"my-own-cluster\"]\n  # cluster_include = []\n\n  ## Filter cluster names in \"system.clusters\" when \"auto_discovery\" is\n  ## \"true\" when this filter present then \"WHERE cluster NOT IN (...)\"\n  ## filter will apply\n  ##    example: cluster_exclude = [\"my-internal-not-discovered-cluster\"]\n  # cluster_exclude = []\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- clickhouse_events (see [system.events][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - all rows from [system.events][]\n\n- clickhouse_metrics (see [system.metrics][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - all rows from [system.metrics][]\n\n- clickhouse_asynchronous_metrics (see [system.asynchronous_metrics][]\n  for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - all rows from [system.asynchronous_metrics][]\n\n- clickhouse_tables\n  - tags:\n    - source (ClickHouse server hostname)\n    - table\n    - database\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - bytes\n    - parts\n    - rows\n\n- clickhouse_zookeeper (see [system.zookeeper][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - root_nodes (count of node where path=/)\n\n- clickhouse_replication_queue (see [system.replication_queue][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - too_many_tries_replicas (count of replicas which have `num_tries > 1`)\n\n- clickhouse_detached_parts (see [system.detached_parts][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - detached_parts (total detached parts for all tables and databases\n      from [system.detached_parts][])\n\n- clickhouse_dictionaries (see [system.dictionaries][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n    - dict_origin (xml Filename when dictionary created from *_dictionary.xml,\n      database.table when dictionary created from DDL)\n  - fields:\n    - is_loaded (0 - when dictionary data not successful load, 1 - when\n      dictionary data loading fail\n    - bytes_allocated (bytes allocated in RAM after a dictionary loaded)\n\n- clickhouse_mutations (see [system.mutations][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - running - gauge which show how much mutation doesn't complete now\n    - failed - counter which show total failed mutations from first\n      clickhouse-server run\n    - completed - counter which show total successful finished mutations\n      from first clickhouse-server run\n\n- clickhouse_disks (see [system.disks][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n    - name (disk name in storage configuration)\n    - path (path to disk)\n  - fields:\n    - free_space_percent - 0-100, gauge which show current percent of\n      free disk space bytes relative to total disk space bytes\n    - keep_free_space_percent - 0-100, gauge which show current percent\n      of required keep free disk bytes relative to total disk space bytes\n\n- clickhouse_processes (see [system.processes][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n  - fields:\n    - percentile_50 - float gauge which show 50% percentile (quantile 0.5) for\n      `elapsed` field of running processes\n    - percentile_90 - float gauge which show 90% percentile (quantile 0.9) for\n      `elapsed` field of running processes\n    - longest_running - float gauge which show maximum value for `elapsed`\n      field of running processes\n\n- clickhouse_text_log (see [system.text_log][] for details)\n  - tags:\n    - source (ClickHouse server hostname)\n    - cluster (Name of the cluster [optional])\n    - shard_num (Shard number in the cluster [optional])\n    - level (message level, only messages with level less or equal Notice are\n      collected)\n  - fields:\n    - messages_last_10_min - gauge which show how many messages collected\n\n## Example Output\n\n```text\nclickhouse_events,cluster=test_cluster_two_shards_localhost,host=kshvakov,source=localhost,shard_num=1 read_compressed_bytes=212i,arena_alloc_chunks=35i,function_execute=85i,merge_tree_data_writer_rows=3i,rw_lock_acquired_read_locks=421i,file_open=46i,io_buffer_alloc_bytes=86451985i,inserted_bytes=196i,regexp_created=3i,real_time_microseconds=116832i,query=23i,network_receive_elapsed_microseconds=268i,merge_tree_data_writer_compressed_bytes=1080i,arena_alloc_bytes=212992i,disk_write_elapsed_microseconds=556i,inserted_rows=3i,compressed_read_buffer_bytes=81i,read_buffer_from_file_descriptor_read_bytes=148i,write_buffer_from_file_descriptor_write=47i,merge_tree_data_writer_blocks=3i,soft_page_faults=896i,hard_page_faults=7i,select_query=21i,merge_tree_data_writer_uncompressed_bytes=196i,merge_tree_data_writer_blocks_already_sorted=3i,user_time_microseconds=40196i,compressed_read_buffer_blocks=5i,write_buffer_from_file_descriptor_write_bytes=3246i,io_buffer_allocs=296i,created_write_buffer_ordinary=12i,disk_read_elapsed_microseconds=59347044i,network_send_elapsed_microseconds=1538i,context_lock=1040i,insert_query=1i,system_time_microseconds=14582i,read_buffer_from_file_descriptor_read=3i 1569421000000000000\nclickhouse_asynchronous_metrics,cluster=test_cluster_two_shards_localhost,host=kshvakov,source=localhost,shard_num=1 jemalloc.metadata_thp=0i,replicas_max_relative_delay=0i,jemalloc.mapped=1803177984i,jemalloc.allocated=1724839256i,jemalloc.background_thread.run_interval=0i,jemalloc.background_thread.num_threads=0i,uncompressed_cache_cells=0i,replicas_max_absolute_delay=0i,mark_cache_bytes=0i,compiled_expression_cache_count=0i,replicas_sum_queue_size=0i,number_of_tables=35i,replicas_max_merges_in_queue=0i,replicas_max_inserts_in_queue=0i,replicas_sum_merges_in_queue=0i,replicas_max_queue_size=0i,mark_cache_files=0i,jemalloc.background_thread.num_runs=0i,jemalloc.active=1726210048i,uptime=158i,jemalloc.retained=380481536i,replicas_sum_inserts_in_queue=0i,uncompressed_cache_bytes=0i,number_of_databases=2i,jemalloc.metadata=9207704i,max_part_count_for_partition=1i,jemalloc.resident=1742442496i 1569421000000000000\nclickhouse_metrics,cluster=test_cluster_two_shards_localhost,host=kshvakov,source=localhost,shard_num=1 replicated_send=0i,write=0i,ephemeral_node=0i,zoo_keeper_request=0i,distributed_files_to_insert=0i,replicated_fetch=0i,background_schedule_pool_task=0i,interserver_connection=0i,leader_replica=0i,delayed_inserts=0i,global_thread_active=41i,merge=0i,readonly_replica=0i,memory_tracking_in_background_schedule_pool=0i,memory_tracking_for_merges=0i,zoo_keeper_session=0i,context_lock_wait=0i,storage_buffer_bytes=0i,background_pool_task=0i,send_external_tables=0i,zoo_keeper_watch=0i,part_mutation=0i,disk_space_reserved_for_merge=0i,distributed_send=0i,version_integer=19014003i,local_thread=0i,replicated_checks=0i,memory_tracking=0i,memory_tracking_in_background_processing_pool=0i,leader_election=0i,revision=54425i,open_file_for_read=0i,open_file_for_write=0i,storage_buffer_rows=0i,rw_lock_waiting_readers=0i,rw_lock_waiting_writers=0i,rw_lock_active_writers=0i,local_thread_active=0i,query_preempted=0i,tcp_connection=1i,http_connection=1i,read=2i,query_thread=0i,dict_cache_requests=0i,rw_lock_active_readers=1i,global_thread=43i,query=1i 1569421000000000000\nclickhouse_tables,cluster=test_cluster_two_shards_localhost,database=system,host=kshvakov,source=localhost,shard_num=1,table=trace_log bytes=754i,parts=1i,rows=1i 1569421000000000000\nclickhouse_tables,cluster=test_cluster_two_shards_localhost,database=default,host=kshvakov,source=localhost,shard_num=1,table=example bytes=326i,parts=2i,rows=2i 1569421000000000000\n```\n\n[system.asynchronous_metrics]: https://clickhouse.tech/docs/en/operations/system-tables/asynchronous_metrics/\n[system.detached_parts]: https://clickhouse.tech/docs/en/operations/system-tables/detached_parts/\n[system.dictionaries]: https://clickhouse.tech/docs/en/operations/system-tables/dictionaries/\n[system.disks]: https://clickhouse.tech/docs/en/operations/system-tables/disks/\n[system.events]: https://clickhouse.tech/docs/en/operations/system-tables/events/\n[system.metrics]: https://clickhouse.tech/docs/en/operations/system-tables/metrics/\n[system.mutations]: https://clickhouse.tech/docs/en/operations/system-tables/mutations/\n[system.processes]: https://clickhouse.tech/docs/en/operations/system-tables/processes/\n[system.replication_queue]:https://clickhouse.com/docs/en/operations/system-tables/replication_queue/\n[system.text_log]: https://clickhouse.tech/docs/en/operations/system-tables/text_log/\n[system.zookeeper]: https://clickhouse.tech/docs/en/operations/system-tables/zookeeper/\n"
  },
  {
    "path": "plugins/inputs/clickhouse/clickhouse.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage clickhouse\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar defaultTimeout = 5 * time.Second\n\ntype ClickHouse struct {\n\tUsername       string          `toml:\"username\"`\n\tPassword       string          `toml:\"password\"`\n\tServers        []string        `toml:\"servers\"`\n\tAutoDiscovery  bool            `toml:\"auto_discovery\"`\n\tClusterInclude []string        `toml:\"cluster_include\"`\n\tClusterExclude []string        `toml:\"cluster_exclude\"`\n\tTimeout        config.Duration `toml:\"timeout\"`\n\tVariant        string          `toml:\"variant\"`\n\n\tHTTPClient http.Client\n\ttls.ClientConfig\n}\n\ntype connect struct {\n\tCluster  string `json:\"cluster\"`\n\tShardNum int    `json:\"shard_num\"`\n\tHostname string `json:\"host_name\"`\n\turl      *url.URL\n}\n\nfunc (*ClickHouse) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ch *ClickHouse) Init() error {\n\tswitch ch.Variant {\n\tcase \"\":\n\t\tch.Variant = \"self-hosted\"\n\tcase \"self-hosted\", \"managed\":\n\t\t// valid options\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown variant %q\", ch.Variant)\n\t}\n\n\treturn nil\n}\n\n// Start ClickHouse input service\nfunc (ch *ClickHouse) Start(telegraf.Accumulator) error {\n\ttimeout := defaultTimeout\n\tif time.Duration(ch.Timeout) != 0 {\n\t\ttimeout = time.Duration(ch.Timeout)\n\t}\n\ttlsCfg, err := ch.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tch.HTTPClient = http.Client{\n\t\tTimeout: timeout,\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig:     tlsCfg,\n\t\t\tProxy:               http.ProxyFromEnvironment,\n\t\t\tMaxIdleConnsPerHost: 1,\n\t\t},\n\t}\n\treturn nil\n}\n\n// Gather collect data from ClickHouse server\nfunc (ch *ClickHouse) Gather(acc telegraf.Accumulator) (err error) {\n\tvar (\n\t\tconnects []connect\n\t\texists   = func(host string) bool {\n\t\t\tfor _, c := range connects {\n\t\t\t\tif c.Hostname == host {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t)\n\n\tfor _, server := range ch.Servers {\n\t\tu, err := url.Parse(server)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch {\n\t\tcase ch.AutoDiscovery:\n\t\t\tvar conns []connect\n\t\t\tif err := ch.execQuery(u, \"SELECT cluster, shard_num, host_name FROM system.clusters \"+ch.clusterIncludeExcludeFilter(), &conns); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, c := range conns {\n\t\t\t\tif !exists(c.Hostname) {\n\t\t\t\t\tc.url = &url.URL{\n\t\t\t\t\t\tScheme: u.Scheme,\n\t\t\t\t\t\tHost:   net.JoinHostPort(c.Hostname, u.Port()),\n\t\t\t\t\t}\n\t\t\t\t\tconnects = append(connects, c)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tconnects = append(connects, connect{\n\t\t\t\tHostname: u.Hostname(),\n\t\t\t\turl:      u,\n\t\t\t})\n\t\t}\n\t}\n\n\tfor i := range connects {\n\t\tmetricsFuncs := []func(acc telegraf.Accumulator, conn *connect) error{\n\t\t\tch.tables,\n\t\t\tch.replicationQueue,\n\t\t\tch.detachedParts,\n\t\t\tch.dictionaries,\n\t\t\tch.mutations,\n\t\t\tch.disks,\n\t\t\tch.processes,\n\t\t\tch.textLog,\n\t\t}\n\n\t\t// Managed instances on Clickhouse Cloud does not give a user\n\t\t// permissions to the zookeeper table\n\t\tif ch.Variant != \"managed\" {\n\t\t\tmetricsFuncs = append(metricsFuncs, ch.zookeeper)\n\t\t}\n\n\t\tfor _, metricFunc := range metricsFuncs {\n\t\t\tif err := metricFunc(acc, &connects[i]); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}\n\n\t\tfor metric := range commonMetrics {\n\t\t\tif err := ch.commonMetrics(acc, &connects[i], metric); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ch *ClickHouse) Stop() {\n\tch.HTTPClient.CloseIdleConnections()\n}\n\nfunc (ch *ClickHouse) clusterIncludeExcludeFilter() string {\n\tif len(ch.ClusterInclude) == 0 && len(ch.ClusterExclude) == 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tescape = func(in string) string {\n\t\t\treturn \"'\" + strings.NewReplacer(`\\`, `\\\\`, `'`, `\\'`).Replace(in) + \"'\"\n\t\t}\n\t\tmakeFilter = func(expr string, args []string) string {\n\t\t\tin := make([]string, 0, len(args))\n\t\t\tfor _, v := range args {\n\t\t\t\tin = append(in, escape(v))\n\t\t\t}\n\t\t\treturn fmt.Sprintf(\"cluster %s (%s)\", expr, strings.Join(in, \", \"))\n\t\t}\n\t\tincludeFilter, excludeFilter string\n\t)\n\n\tif len(ch.ClusterInclude) != 0 {\n\t\tincludeFilter = makeFilter(\"IN\", ch.ClusterInclude)\n\t}\n\tif len(ch.ClusterExclude) != 0 {\n\t\texcludeFilter = makeFilter(\"NOT IN\", ch.ClusterExclude)\n\t}\n\tif includeFilter != \"\" && excludeFilter != \"\" {\n\t\treturn \"WHERE \" + includeFilter + \" OR \" + excludeFilter\n\t}\n\tif includeFilter == \"\" && excludeFilter != \"\" {\n\t\treturn \"WHERE \" + excludeFilter\n\t}\n\treturn \"WHERE \" + includeFilter\n}\n\nfunc (ch *ClickHouse) commonMetrics(acc telegraf.Accumulator, conn *connect, metric string) error {\n\tvar intResult []struct {\n\t\tMetric string   `json:\"metric\"`\n\t\tValue  chUInt64 `json:\"value\"`\n\t}\n\n\tvar floatResult []struct {\n\t\tMetric string  `json:\"metric\"`\n\t\tValue  float64 `json:\"value\"`\n\t}\n\n\ttags := makeDefaultTags(conn)\n\tfields := make(map[string]interface{})\n\n\tif commonMetricsIsFloat[metric] {\n\t\tif err := ch.execQuery(conn.url, commonMetrics[metric], &floatResult); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, r := range floatResult {\n\t\t\tfields[internal.SnakeCase(r.Metric)] = r.Value\n\t\t}\n\t} else {\n\t\tif err := ch.execQuery(conn.url, commonMetrics[metric], &intResult); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, r := range intResult {\n\t\t\tfields[internal.SnakeCase(r.Metric)] = uint64(r.Value)\n\t\t}\n\t}\n\tacc.AddFields(\"clickhouse_\"+metric, fields, tags)\n\n\treturn nil\n}\n\nfunc (ch *ClickHouse) zookeeper(acc telegraf.Accumulator, conn *connect) error {\n\tvar zkExists []struct {\n\t\tZkExists chUInt64 `json:\"zk_exists\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemZookeeperExistsSQL, &zkExists); err != nil {\n\t\treturn err\n\t}\n\ttags := makeDefaultTags(conn)\n\n\tif len(zkExists) > 0 && zkExists[0].ZkExists > 0 {\n\t\tvar zkRootNodes []struct {\n\t\t\tZkRootNodes chUInt64 `json:\"zk_root_nodes\"`\n\t\t}\n\t\tif err := ch.execQuery(conn.url, systemZookeeperRootNodesSQL, &zkRootNodes); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tacc.AddFields(\"clickhouse_zookeeper\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"root_nodes\": uint64(zkRootNodes[0].ZkRootNodes),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (ch *ClickHouse) replicationQueue(acc telegraf.Accumulator, conn *connect) error {\n\tvar replicationQueueExists []struct {\n\t\tReplicationQueueExists chUInt64 `json:\"replication_queue_exists\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemReplicationExistsSQL, &replicationQueueExists); err != nil {\n\t\treturn err\n\t}\n\n\ttags := makeDefaultTags(conn)\n\n\tif len(replicationQueueExists) > 0 && replicationQueueExists[0].ReplicationQueueExists > 0 {\n\t\tvar replicationTooManyTries []struct {\n\t\t\tNumTriesReplicas     chUInt64 `json:\"replication_num_tries_replicas\"`\n\t\t\tTooManyTriesReplicas chUInt64 `json:\"replication_too_many_tries_replicas\"`\n\t\t}\n\t\tif err := ch.execQuery(conn.url, systemReplicationNumTriesSQL, &replicationTooManyTries); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tacc.AddFields(\"clickhouse_replication_queue\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"too_many_tries_replicas\": uint64(replicationTooManyTries[0].TooManyTriesReplicas),\n\t\t\t\t\"num_tries_replicas\":      uint64(replicationTooManyTries[0].NumTriesReplicas),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (ch *ClickHouse) detachedParts(acc telegraf.Accumulator, conn *connect) error {\n\tvar detachedParts []struct {\n\t\tDetachedParts chUInt64 `json:\"detached_parts\"`\n\t}\n\tif err := ch.execQuery(conn.url, systemDetachedPartsSQL, &detachedParts); err != nil {\n\t\treturn err\n\t}\n\n\tif len(detachedParts) > 0 {\n\t\ttags := makeDefaultTags(conn)\n\t\tacc.AddFields(\"clickhouse_detached_parts\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"detached_parts\": uint64(detachedParts[0].DetachedParts),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (ch *ClickHouse) dictionaries(acc telegraf.Accumulator, conn *connect) error {\n\tvar brokenDictionaries []struct {\n\t\tOrigin         string   `json:\"origin\"`\n\t\tBytesAllocated chUInt64 `json:\"bytes_allocated\"`\n\t\tStatus         string   `json:\"status\"`\n\t}\n\tif err := ch.execQuery(conn.url, systemDictionariesSQL, &brokenDictionaries); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, dict := range brokenDictionaries {\n\t\ttags := makeDefaultTags(conn)\n\n\t\tisLoaded := uint64(1)\n\t\tif dict.Status != \"LOADED\" {\n\t\t\tisLoaded = 0\n\t\t}\n\n\t\tif dict.Origin != \"\" {\n\t\t\ttags[\"dict_origin\"] = dict.Origin\n\t\t\tacc.AddFields(\"clickhouse_dictionaries\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"is_loaded\":       isLoaded,\n\t\t\t\t\t\"bytes_allocated\": uint64(dict.BytesAllocated),\n\t\t\t\t},\n\t\t\t\ttags,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ch *ClickHouse) mutations(acc telegraf.Accumulator, conn *connect) error {\n\tvar mutationsStatus []struct {\n\t\tFailed    chUInt64 `json:\"failed\"`\n\t\tRunning   chUInt64 `json:\"running\"`\n\t\tCompleted chUInt64 `json:\"completed\"`\n\t}\n\tif err := ch.execQuery(conn.url, systemMutationSQL, &mutationsStatus); err != nil {\n\t\treturn err\n\t}\n\n\tif len(mutationsStatus) > 0 {\n\t\ttags := makeDefaultTags(conn)\n\n\t\tacc.AddFields(\"clickhouse_mutations\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"failed\":    uint64(mutationsStatus[0].Failed),\n\t\t\t\t\"running\":   uint64(mutationsStatus[0].Running),\n\t\t\t\t\"completed\": uint64(mutationsStatus[0].Completed),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (ch *ClickHouse) disks(acc telegraf.Accumulator, conn *connect) error {\n\tvar disksStatus []struct {\n\t\tName            string   `json:\"name\"`\n\t\tPath            string   `json:\"path\"`\n\t\tFreePercent     chUInt64 `json:\"free_space_percent\"`\n\t\tKeepFreePercent chUInt64 `json:\"keep_free_space_percent\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemDisksSQL, &disksStatus); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, disk := range disksStatus {\n\t\ttags := makeDefaultTags(conn)\n\t\ttags[\"name\"] = disk.Name\n\t\ttags[\"path\"] = disk.Path\n\n\t\tacc.AddFields(\"clickhouse_disks\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"free_space_percent\":      uint64(disk.FreePercent),\n\t\t\t\t\"keep_free_space_percent\": uint64(disk.KeepFreePercent),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (ch *ClickHouse) processes(acc telegraf.Accumulator, conn *connect) error {\n\tvar processesStats []struct {\n\t\tQueryType      string  `json:\"query_type\"`\n\t\tPercentile50   float64 `json:\"p50\"`\n\t\tPercentile90   float64 `json:\"p90\"`\n\t\tLongestRunning float64 `json:\"longest_running\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemProcessesSQL, &processesStats); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, process := range processesStats {\n\t\ttags := makeDefaultTags(conn)\n\t\ttags[\"query_type\"] = process.QueryType\n\n\t\tacc.AddFields(\"clickhouse_processes\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"percentile_50\":   process.Percentile50,\n\t\t\t\t\"percentile_90\":   process.Percentile90,\n\t\t\t\t\"longest_running\": process.LongestRunning,\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (ch *ClickHouse) textLog(acc telegraf.Accumulator, conn *connect) error {\n\tvar textLogExists []struct {\n\t\tTextLogExists chUInt64 `json:\"text_log_exists\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemTextLogExistsSQL, &textLogExists); err != nil {\n\t\treturn err\n\t}\n\n\tif len(textLogExists) > 0 && textLogExists[0].TextLogExists > 0 {\n\t\tvar textLogLast10MinMessages []struct {\n\t\t\tLevel             string   `json:\"level\"`\n\t\t\tMessagesLast10Min chUInt64 `json:\"messages_last_10_min\"`\n\t\t}\n\t\tif err := ch.execQuery(conn.url, systemTextLogSQL, &textLogLast10MinMessages); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, textLogItem := range textLogLast10MinMessages {\n\t\t\ttags := makeDefaultTags(conn)\n\t\t\ttags[\"level\"] = textLogItem.Level\n\t\t\tacc.AddFields(\"clickhouse_text_log\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"messages_last_10_min\": uint64(textLogItem.MessagesLast10Min),\n\t\t\t\t},\n\t\t\t\ttags,\n\t\t\t)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ch *ClickHouse) tables(acc telegraf.Accumulator, conn *connect) error {\n\tvar parts []struct {\n\t\tDatabase string   `json:\"database\"`\n\t\tTable    string   `json:\"table\"`\n\t\tBytes    chUInt64 `json:\"bytes\"`\n\t\tParts    chUInt64 `json:\"parts\"`\n\t\tRows     chUInt64 `json:\"rows\"`\n\t}\n\n\tif err := ch.execQuery(conn.url, systemPartsSQL, &parts); err != nil {\n\t\treturn err\n\t}\n\ttags := makeDefaultTags(conn)\n\n\tfor _, part := range parts {\n\t\ttags[\"table\"] = part.Table\n\t\ttags[\"database\"] = part.Database\n\t\tacc.AddFields(\"clickhouse_tables\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\": uint64(part.Bytes),\n\t\t\t\t\"parts\": uint64(part.Parts),\n\t\t\t\t\"rows\":  uint64(part.Rows),\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc makeDefaultTags(conn *connect) map[string]string {\n\ttags := map[string]string{\n\t\t\"source\": conn.Hostname,\n\t}\n\tif len(conn.Cluster) != 0 {\n\t\ttags[\"cluster\"] = conn.Cluster\n\t}\n\tif conn.ShardNum != 0 {\n\t\ttags[\"shard_num\"] = strconv.Itoa(conn.ShardNum)\n\t}\n\treturn tags\n}\n\ntype clickhouseError struct {\n\tStatusCode int\n\tbody       []byte\n}\n\nfunc (e *clickhouseError) Error() string {\n\treturn fmt.Sprintf(\"received error code %d: %s\", e.StatusCode, e.body)\n}\n\nfunc (ch *ClickHouse) execQuery(address *url.URL, query string, i interface{}) error {\n\tq := address.Query()\n\tq.Set(\"query\", query+\" FORMAT JSON\")\n\taddress.RawQuery = q.Encode()\n\treq, err := http.NewRequest(\"GET\", address.String(), nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ch.Username != \"\" {\n\t\treq.Header.Add(\"X-ClickHouse-User\", ch.Username)\n\t}\n\tif ch.Password != \"\" {\n\t\treq.Header.Add(\"X-ClickHouse-Key\", ch.Password)\n\t}\n\tresp, err := ch.HTTPClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\tif resp.StatusCode >= 300 {\n\t\t//nolint:errcheck // reading body for error reporting\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 200))\n\t\treturn &clickhouseError{\n\t\t\tStatusCode: resp.StatusCode,\n\t\t\tbody:       body,\n\t\t}\n\t}\n\tvar response struct {\n\t\tData json.RawMessage\n\t}\n\tif err := json.NewDecoder(resp.Body).Decode(&response); err != nil {\n\t\treturn err\n\t}\n\tif err := json.Unmarshal(response.Data, i); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := io.Copy(io.Discard, resp.Body); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// see https://clickhouse.yandex/docs/en/operations/settings/settings/#session_settings-output_format_json_quote_64bit_integers\ntype chUInt64 uint64\n\n// UnmarshalJSON is a custom unmarshaler for chUInt64 to handle ClickHouse's JSON format.\nfunc (i *chUInt64) UnmarshalJSON(b []byte) error {\n\tb = bytes.TrimPrefix(b, []byte(`\"`))\n\tb = bytes.TrimSuffix(b, []byte(`\"`))\n\tv, err := strconv.ParseUint(string(b), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*i = chUInt64(v)\n\treturn nil\n}\n\nconst (\n\tsystemEventsSQL       = \"SELECT event AS metric, toUInt64(value) AS value FROM system.events\"\n\tsystemMetricsSQL      = \"SELECT          metric, toUInt64(value) AS value FROM system.metrics\"\n\tsystemAsyncMetricsSQL = \"SELECT          metric, toFloat64(value) AS value FROM system.asynchronous_metrics\"\n\tsystemPartsSQL        = `\n\t\tSELECT\n\t\t\tdatabase,\n\t\t\ttable,\n\t\t\tSUM(bytes) AS bytes,\n\t\t\tCOUNT(*)   AS parts,\n\t\t\tSUM(rows)  AS rows\n\t\tFROM system.parts\n\t\tWHERE active = 1\n\t\tGROUP BY\n\t\t\tdatabase, table\n\t\tORDER BY\n\t\t\tdatabase, table\n\t`\n\tsystemZookeeperExistsSQL    = \"SELECT count() AS zk_exists FROM system.tables WHERE database='system' AND name='zookeeper'\"\n\tsystemZookeeperRootNodesSQL = \"SELECT count() AS zk_root_nodes FROM system.zookeeper WHERE path='/'\"\n\n\tsystemReplicationExistsSQL   = \"SELECT count() AS replication_queue_exists FROM system.tables WHERE database='system' AND name='replication_queue'\"\n\tsystemReplicationNumTriesSQL = \"SELECT countIf(num_tries>1) AS replication_num_tries_replicas, countIf(num_tries>100) \" +\n\t\t\"AS replication_too_many_tries_replicas FROM system.replication_queue SETTINGS empty_result_for_aggregation_by_empty_set=0\"\n\n\tsystemDetachedPartsSQL = \"SELECT count() AS detached_parts FROM system.detached_parts SETTINGS empty_result_for_aggregation_by_empty_set=0\"\n\n\tsystemDictionariesSQL = \"SELECT origin, status, bytes_allocated FROM system.dictionaries\"\n\n\tsystemMutationSQL = \"SELECT countIf(latest_fail_time>toDateTime('0000-00-00 00:00:00') AND is_done=0) \" +\n\t\t\"AS failed, countIf(latest_fail_time=toDateTime('0000-00-00 00:00:00') AND is_done=0) \" +\n\t\t\"AS running, countIf(is_done=1) AS completed FROM system.mutations SETTINGS empty_result_for_aggregation_by_empty_set=0\"\n\tsystemDisksSQL = \"SELECT name, path, toUInt64(100*free_space / total_space) \" +\n\t\t\"AS free_space_percent, toUInt64( 100 * keep_free_space / total_space) AS keep_free_space_percent FROM system.disks\"\n\tsystemProcessesSQL = \"SELECT multiIf(positionCaseInsensitive(query,'select')=1,'select',positionCaseInsensitive(query,'insert')=1,'insert','other') \" +\n\t\t\"AS query_type, quantile\\n(0.5)(elapsed) AS p50, quantile(0.9)(elapsed) AS p90, max(elapsed) AS longest_running \" +\n\t\t\"FROM system.processes GROUP BY query_type SETTINGS empty_result_for_aggregation_by_empty_set=0\"\n\n\tsystemTextLogExistsSQL = \"SELECT count() AS text_log_exists FROM system.tables WHERE database='system' AND name='text_log'\"\n\tsystemTextLogSQL       = \"SELECT count() AS messages_last_10_min, level FROM system.text_log \" +\n\t\t\"WHERE level <= 'Notice' AND event_time >= now() - INTERVAL 600 SECOND GROUP BY level SETTINGS empty_result_for_aggregation_by_empty_set=0\"\n)\n\nvar commonMetrics = map[string]string{\n\t\"events\":               systemEventsSQL,\n\t\"metrics\":              systemMetricsSQL,\n\t\"asynchronous_metrics\": systemAsyncMetricsSQL,\n}\n\nvar commonMetricsIsFloat = map[string]bool{\n\t\"events\":               false,\n\t\"metrics\":              false,\n\t\"asynchronous_metrics\": true,\n}\n\nvar _ telegraf.ServiceInput = &ClickHouse{}\n\nfunc init() {\n\tinputs.Add(\"clickhouse\", func() telegraf.Input {\n\t\treturn &ClickHouse{\n\t\t\tAutoDiscovery: true,\n\t\t\tClientConfig: tls.ClientConfig{\n\t\t\t\tInsecureSkipVerify: false,\n\t\t\t},\n\t\t\tTimeout: config.Duration(defaultTimeout),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/clickhouse/clickhouse_test.go",
    "content": "package clickhouse\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestClusterIncludeExcludeFilter(t *testing.T) {\n\tch := ClickHouse{}\n\trequire.Empty(t, ch.clusterIncludeExcludeFilter())\n\tch.ClusterExclude = []string{\"test_cluster\"}\n\trequire.Equal(t, \"WHERE cluster NOT IN ('test_cluster')\", ch.clusterIncludeExcludeFilter())\n\n\tch.ClusterExclude = []string{\"test_cluster\"}\n\tch.ClusterInclude = []string{\"cluster\"}\n\trequire.Equal(t, \"WHERE cluster IN ('cluster') OR cluster NOT IN ('test_cluster')\", ch.clusterIncludeExcludeFilter())\n\n\tch.ClusterExclude = make([]string, 0)\n\tch.ClusterInclude = []string{\"cluster1\", \"cluster2\"}\n\trequire.Equal(t, \"WHERE cluster IN ('cluster1', 'cluster2')\", ch.clusterIncludeExcludeFilter())\n\n\tch.ClusterExclude = []string{\"cluster1\", \"cluster2\"}\n\tch.ClusterInclude = make([]string, 0)\n\trequire.Equal(t, \"WHERE cluster NOT IN ('cluster1', 'cluster2')\", ch.clusterIncludeExcludeFilter())\n}\n\nfunc TestChInt64(t *testing.T) {\n\tassets := map[string]uint64{\n\t\t`\"1\"`:                  1,\n\t\t\"1\":                    1,\n\t\t\"42\":                   42,\n\t\t`\"42\"`:                 42,\n\t\t\"18446743937525109187\": 18446743937525109187,\n\t}\n\tfor src, expected := range assets {\n\t\tvar v chUInt64\n\t\terr := v.UnmarshalJSON([]byte(src))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, uint64(v))\n\t}\n}\n\nfunc TestGather(t *testing.T) {\n\tvar (\n\t\tts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\ttype result struct {\n\t\t\t\tData interface{} `json:\"data\"`\n\t\t\t}\n\t\t\tenc := json.NewEncoder(w)\n\t\t\tswitch query := r.URL.Query().Get(\"query\"); {\n\t\t\tcase strings.Contains(query, \"system.parts\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tDatabase string   `json:\"database\"`\n\t\t\t\t\t\tTable    string   `json:\"table\"`\n\t\t\t\t\t\tBytes    chUInt64 `json:\"bytes\"`\n\t\t\t\t\t\tParts    chUInt64 `json:\"parts\"`\n\t\t\t\t\t\tRows     chUInt64 `json:\"rows\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatabase: \"test_database\",\n\t\t\t\t\t\t\tTable:    \"test_table\",\n\t\t\t\t\t\t\tBytes:    1,\n\t\t\t\t\t\t\tParts:    10,\n\t\t\t\t\t\t\tRows:     100,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.events\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tMetric string   `json:\"metric\"`\n\t\t\t\t\t\tValue  chUInt64 `json:\"value\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemEvent\",\n\t\t\t\t\t\t\tValue:  1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemEvent2\",\n\t\t\t\t\t\t\tValue:  2000,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.metrics\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tMetric string   `json:\"metric\"`\n\t\t\t\t\t\tValue  chUInt64 `json:\"value\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemMetric\",\n\t\t\t\t\t\t\tValue:  1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemMetric2\",\n\t\t\t\t\t\t\tValue:  2000,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.asynchronous_metrics\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tMetric string   `json:\"metric\"`\n\t\t\t\t\t\tValue  chUInt64 `json:\"value\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemAsynchronousMetric\",\n\t\t\t\t\t\t\tValue:  1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMetric: \"TestSystemAsynchronousMetric2\",\n\t\t\t\t\t\t\tValue:  2000,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"zk_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tZkExists chUInt64 `json:\"zk_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tZkExists: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"zk_root_nodes\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tZkRootNodes chUInt64 `json:\"zk_root_nodes\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tZkRootNodes: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"replication_queue_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tReplicationQueueExists chUInt64 `json:\"replication_queue_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tReplicationQueueExists: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"replication_too_many_tries_replicas\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tTooManyTriesReplicas chUInt64 `json:\"replication_too_many_tries_replicas\"`\n\t\t\t\t\t\tNumTriesReplicas     chUInt64 `json:\"replication_num_tries_replicas\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTooManyTriesReplicas: 10,\n\t\t\t\t\t\t\tNumTriesReplicas:     100,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.detached_parts\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tDetachedParts chUInt64 `json:\"detached_parts\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDetachedParts: 10,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.dictionaries\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tOrigin         string   `json:\"origin\"`\n\t\t\t\t\t\tStatus         string   `json:\"status\"`\n\t\t\t\t\t\tBytesAllocated chUInt64 `json:\"bytes_allocated\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tOrigin:         \"default.test_dict\",\n\t\t\t\t\t\t\tStatus:         \"NOT_LOADED\",\n\t\t\t\t\t\t\tBytesAllocated: 100,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.mutations\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tFailed    chUInt64 `json:\"failed\"`\n\t\t\t\t\t\tCompleted chUInt64 `json:\"completed\"`\n\t\t\t\t\t\tRunning   chUInt64 `json:\"running\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFailed:    10,\n\t\t\t\t\t\t\tRunning:   1,\n\t\t\t\t\t\t\tCompleted: 100,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.disks\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tName            string   `json:\"name\"`\n\t\t\t\t\t\tPath            string   `json:\"path\"`\n\t\t\t\t\t\tFreePercent     chUInt64 `json:\"free_space_percent\"`\n\t\t\t\t\t\tKeepFreePercent chUInt64 `json:\"keep_free_space_percent\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:            \"default\",\n\t\t\t\t\t\t\tPath:            \"/var/lib/clickhouse\",\n\t\t\t\t\t\t\tFreePercent:     1,\n\t\t\t\t\t\t\tKeepFreePercent: 10,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.processes\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tQueryType      string  `json:\"query_type\"`\n\t\t\t\t\t\tPercentile50   float64 `json:\"p50\"`\n\t\t\t\t\t\tPercentile90   float64 `json:\"p90\"`\n\t\t\t\t\t\tLongestRunning float64 `json:\"longest_running\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tQueryType:      \"select\",\n\t\t\t\t\t\t\tPercentile50:   0.1,\n\t\t\t\t\t\t\tPercentile90:   0.5,\n\t\t\t\t\t\t\tLongestRunning: 10,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tQueryType:      \"insert\",\n\t\t\t\t\t\t\tPercentile50:   0.2,\n\t\t\t\t\t\t\tPercentile90:   1.5,\n\t\t\t\t\t\t\tLongestRunning: 100,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tQueryType:      \"other\",\n\t\t\t\t\t\t\tPercentile50:   0.4,\n\t\t\t\t\t\t\tPercentile90:   4.5,\n\t\t\t\t\t\t\tLongestRunning: 1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"text_log_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tTextLogExists chUInt64 `json:\"text_log_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTextLogExists: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"system.text_log\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tLevel                 string   `json:\"level\"`\n\t\t\t\t\t\tLastMessagesLast10Min chUInt64 `json:\"messages_last_10_min\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel:                 \"Fatal\",\n\t\t\t\t\t\t\tLastMessagesLast10Min: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel:                 \"Critical\",\n\t\t\t\t\t\t\tLastMessagesLast10Min: 10,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel:                 \"Error\",\n\t\t\t\t\t\t\tLastMessagesLast10Min: 20,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel:                 \"Warning\",\n\t\t\t\t\t\t\tLastMessagesLast10Min: 30,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLevel:                 \"Notice\",\n\t\t\t\t\t\t\tLastMessagesLast10Min: 40,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}))\n\t\tch = &ClickHouse{\n\t\t\tServers: []string{\n\t\t\t\tts.URL,\n\t\t\t},\n\t\t}\n\t\tacc = &testutil.Accumulator{}\n\t)\n\tdefer ts.Close()\n\trequire.NoError(t, ch.Gather(acc))\n\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_tables\",\n\t\tmap[string]interface{}{\n\t\t\t\"bytes\": uint64(1),\n\t\t\t\"parts\": uint64(10),\n\t\t\t\"rows\":  uint64(100),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":   \"127.0.0.1\",\n\t\t\t\"table\":    \"test_table\",\n\t\t\t\"database\": \"test_database\",\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_events\",\n\t\tmap[string]interface{}{\n\t\t\t\"test_system_event\":  uint64(1000),\n\t\t\t\"test_system_event2\": uint64(2000),\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_metrics\",\n\t\tmap[string]interface{}{\n\t\t\t\"test_system_metric\":  uint64(1000),\n\t\t\t\"test_system_metric2\": uint64(2000),\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_asynchronous_metrics\",\n\t\tmap[string]interface{}{\n\t\t\t\"test_system_asynchronous_metric\":  float64(1000),\n\t\t\t\"test_system_asynchronous_metric2\": float64(2000),\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_zookeeper\",\n\t\tmap[string]interface{}{\n\t\t\t\"root_nodes\": uint64(2),\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_replication_queue\",\n\t\tmap[string]interface{}{\n\t\t\t\"too_many_tries_replicas\": uint64(10),\n\t\t\t\"num_tries_replicas\":      uint64(100),\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_detached_parts\",\n\t\tmap[string]interface{}{\n\t\t\t\"detached_parts\": uint64(10),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_dictionaries\",\n\t\tmap[string]interface{}{\n\t\t\t\"is_loaded\":       uint64(0),\n\t\t\t\"bytes_allocated\": uint64(100),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":      \"127.0.0.1\",\n\t\t\t\"dict_origin\": \"default.test_dict\",\n\t\t},\n\t)\n\tacc.AssertContainsFields(t, \"clickhouse_mutations\",\n\t\tmap[string]interface{}{\n\t\t\t\"running\":   uint64(1),\n\t\t\t\"failed\":    uint64(10),\n\t\t\t\"completed\": uint64(100),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_disks\",\n\t\tmap[string]interface{}{\n\t\t\t\"free_space_percent\":      uint64(1),\n\t\t\t\"keep_free_space_percent\": uint64(10),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\"name\":   \"default\",\n\t\t\t\"path\":   \"/var/lib/clickhouse\",\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"percentile_50\":   0.1,\n\t\t\t\"percentile_90\":   0.5,\n\t\t\t\"longest_running\": float64(10),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":     \"127.0.0.1\",\n\t\t\t\"query_type\": \"select\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"percentile_50\":   0.2,\n\t\t\t\"percentile_90\":   1.5,\n\t\t\t\"longest_running\": float64(100),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":     \"127.0.0.1\",\n\t\t\t\"query_type\": \"insert\",\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(t, \"clickhouse_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"percentile_50\":   0.4,\n\t\t\t\"percentile_90\":   4.5,\n\t\t\t\"longest_running\": float64(1000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":     \"127.0.0.1\",\n\t\t\t\"query_type\": \"other\",\n\t\t},\n\t)\n\n\tfor i, level := range []string{\"Fatal\", \"Critical\", \"Error\", \"Warning\", \"Notice\"} {\n\t\tacc.AssertContainsTaggedFields(t, \"clickhouse_text_log\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_last_10_min\": uint64(i * 10),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\"level\":  level,\n\t\t\t},\n\t\t)\n\t}\n}\n\nfunc TestGatherWithSomeTablesNotExists(t *testing.T) {\n\tvar (\n\t\tts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\ttype result struct {\n\t\t\t\tData interface{} `json:\"data\"`\n\t\t\t}\n\t\t\tenc := json.NewEncoder(w)\n\t\t\tswitch query := r.URL.Query().Get(\"query\"); {\n\t\t\tcase strings.Contains(query, \"zk_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tZkExists chUInt64 `json:\"zk_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tZkExists: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"replication_queue_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tReplicationQueueExists chUInt64 `json:\"replication_queue_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tReplicationQueueExists: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase strings.Contains(query, \"text_log_exists\"):\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tTextLogExists chUInt64 `json:\"text_log_exists\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTextLogExists: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}))\n\t\tch = &ClickHouse{\n\t\t\tServers: []string{\n\t\t\t\tts.URL,\n\t\t\t},\n\t\t\tUsername: \"default\",\n\t\t}\n\t\tacc = &testutil.Accumulator{}\n\t)\n\tdefer ts.Close()\n\trequire.NoError(t, ch.Gather(acc))\n\n\tacc.AssertDoesNotContainMeasurement(t, \"clickhouse_zookeeper\")\n\tacc.AssertDoesNotContainMeasurement(t, \"clickhouse_replication_queue\")\n\tacc.AssertDoesNotContainMeasurement(t, \"clickhouse_text_log\")\n}\n\nfunc TestGatherClickhouseCloud(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\ttype result struct {\n\t\t\tData interface{} `json:\"data\"`\n\t\t}\n\t\tenc := json.NewEncoder(w)\n\t\tswitch query := r.URL.Query().Get(\"query\"); {\n\t\tcase strings.Contains(query, \"zk_exists\"):\n\t\t\terr := enc.Encode(result{\n\t\t\t\tData: []struct {\n\t\t\t\t\tZkExists chUInt64 `json:\"zk_exists\"`\n\t\t\t\t}{\n\t\t\t\t\t{\n\t\t\t\t\t\tZkExists: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase strings.Contains(query, \"zk_root_nodes\"):\n\t\t\terr := enc.Encode(result{\n\t\t\t\tData: []struct {\n\t\t\t\t\tZkRootNodes chUInt64 `json:\"zk_root_nodes\"`\n\t\t\t\t}{\n\t\t\t\t\t{\n\t\t\t\t\t\tZkRootNodes: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tch := &ClickHouse{\n\t\tServers: []string{ts.URL},\n\t\tVariant: \"managed\",\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, ch.Gather(acc))\n\tacc.AssertDoesNotContainMeasurement(t, \"clickhouse_zookeeper\")\n}\n\nfunc TestWrongJSONMarshalling(t *testing.T) {\n\tvar (\n\t\tts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\ttype result struct {\n\t\t\t\tData interface{} `json:\"data\"`\n\t\t\t}\n\t\t\tenc := json.NewEncoder(w)\n\t\t\t// wrong data section json\n\t\t\terr := enc.Encode(result{\n\t\t\t\tData: make([]struct{}, 0),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}))\n\t\tch = &ClickHouse{\n\t\t\tServers: []string{\n\t\t\t\tts.URL,\n\t\t\t},\n\t\t\tUsername: \"default\",\n\t\t}\n\t\tacc = &testutil.Accumulator{}\n\t)\n\tdefer ts.Close()\n\trequire.NoError(t, ch.Gather(acc))\n\n\trequire.Empty(t, acc.Metrics)\n\tallMeasurements := []string{\n\t\t\"clickhouse_events\",\n\t\t\"clickhouse_metrics\",\n\t\t\"clickhouse_asynchronous_metrics\",\n\t\t\"clickhouse_tables\",\n\t\t\"clickhouse_zookeeper\",\n\t\t\"clickhouse_replication_queue\",\n\t\t\"clickhouse_detached_parts\",\n\t\t\"clickhouse_dictionaries\",\n\t\t\"clickhouse_mutations\",\n\t\t\"clickhouse_disks\",\n\t\t\"clickhouse_processes\",\n\t\t\"clickhouse_text_log\",\n\t}\n\trequire.GreaterOrEqual(t, len(allMeasurements), len(acc.Errors))\n}\n\nfunc TestOfflineServer(t *testing.T) {\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\tch  = &ClickHouse{\n\t\t\tServers: []string{\n\t\t\t\t\"http://wrong-domain.local:8123\",\n\t\t\t},\n\t\t\tUsername: \"default\",\n\t\t\tHTTPClient: http.Client{\n\t\t\t\tTimeout: 1 * time.Millisecond,\n\t\t\t},\n\t\t}\n\t)\n\trequire.NoError(t, ch.Gather(acc))\n\n\trequire.Empty(t, acc.Metrics)\n\tallMeasurements := []string{\n\t\t\"clickhouse_events\",\n\t\t\"clickhouse_metrics\",\n\t\t\"clickhouse_asynchronous_metrics\",\n\t\t\"clickhouse_tables\",\n\t\t\"clickhouse_zookeeper\",\n\t\t\"clickhouse_replication_queue\",\n\t\t\"clickhouse_detached_parts\",\n\t\t\"clickhouse_dictionaries\",\n\t\t\"clickhouse_mutations\",\n\t\t\"clickhouse_disks\",\n\t\t\"clickhouse_processes\",\n\t\t\"clickhouse_text_log\",\n\t}\n\trequire.GreaterOrEqual(t, len(allMeasurements), len(acc.Errors))\n}\n\nfunc TestAutoDiscovery(t *testing.T) {\n\tvar (\n\t\tts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\ttype result struct {\n\t\t\t\tData interface{} `json:\"data\"`\n\t\t\t}\n\t\t\tenc := json.NewEncoder(w)\n\t\t\tquery := r.URL.Query().Get(\"query\")\n\t\t\tif strings.Contains(query, \"system.clusters\") {\n\t\t\t\terr := enc.Encode(result{\n\t\t\t\t\tData: []struct {\n\t\t\t\t\t\tCluster  string   `json:\"test\"`\n\t\t\t\t\t\tHostname string   `json:\"localhost\"`\n\t\t\t\t\t\tShardNum chUInt64 `json:\"shard_num\"`\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCluster:  \"test_database\",\n\t\t\t\t\t\t\tHostname: \"test_table\",\n\t\t\t\t\t\t\tShardNum: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}))\n\t\tch = &ClickHouse{\n\t\t\tServers: []string{\n\t\t\t\tts.URL,\n\t\t\t},\n\t\t\tUsername:      \"default\",\n\t\t\tAutoDiscovery: true,\n\t\t}\n\t\tacc = &testutil.Accumulator{}\n\t)\n\tdefer ts.Close()\n\trequire.NoError(t, ch.Gather(acc))\n}\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/dhparam.pem",
    "content": "-----BEGIN DH PARAMETERS-----\nMIICCAKCAgEAoo1x7wI5K57P1/AkHUmVWzKNfy46b/ni/QtClomTB78Ks1FP8dzs\nCQBW/pfL8yidxTialNhMRCZO1J+uPjTvd8dG8SFZzVylkF41LBNrUD+MLyh/b6Nr\n8uWf3tqYCtsiqsQsnq/oU7C29wn6UjhPPVbRRDPGyJUFOgp0ebPR0L2gOc5HhXSF\nTt0fuWnvgZJBKGvyodby3p2CSheu8K6ZteVc8ZgHuanhCQA30nVN+yNQzyozlB2H\nB9jxTDPJy8+/4Mui3iiNyXg6FaiI9lWdH7xgKoZlHi8BWlLz5Se9JVNYg0dPrMTz\nK0itQyyTKUlK73x+1uPm6q1AJwz08EZiCXNbk58/Sf+pdwDmAO2QSRrERC73vnvc\nB1+4+Kf7RS7oYpAHknKm/MFnkCJLVIq1b6kikYcIgVCYe+Z1UytSmG1QfwdgL8QQ\nTVYVHBg4w07+s3/IJ1ekvNhdxpkmmevYt7GjohWu8vKkip4se+reNdo+sqLsgFKf\n1IuDMD36zn9FVukvs7e3BwZCTkdosGHvHGjA7zm2DwPPO16hCvJ4mE6ULLpp2NEw\nEBYWm3Tv6M/xtrF5Afyh0gAh7eL767/qsarbx6jlqs+dnh3LptqsE3WerWK54+0B\n3Hr5CVfgYbeXuW2HeFb+fS6CNUWmiAsq1XRiz5p16hpeMGYN/qyF1IsCAQI=\n-----END DH PARAMETERS-----\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  clickhouse:\n# choose `:latest` after resolve https://github.com/ClickHouse/ClickHouse/issues/13057\n    image: docker.io/yandex/clickhouse-server:${CLICKHOUSE_VERSION:-latest}\n    volumes:\n      - ./init_schema.sql:/docker-entrypoint-initdb.d/init_schema.sql\n      - ./test_dictionary.xml:/etc/clickhouse-server/01-test_dictionary.xml\n      - ./zookeeper.xml:/etc/clickhouse-server/config.d/00-zookeeper.xml\n      - ./tls_settings.xml:/etc/clickhouse-server/config.d/01-tls_settings.xml\n      # please comment text_log.xml when CLICKHOUSE_VERSION = 19.16\n      - ./text_log.xml:/etc/clickhouse-server/config.d/02-text_log.xml\n      - ./part_log.xml:/etc/clickhouse-server/config.d/03-part_log.xml\n      - ./mysql_port.xml:/etc/clickhouse-server/config.d/04-mysql_port.xml\n      - ./dhparam.pem:/etc/clickhouse-server/dhparam.pem\n      - ../../../../testutil/pki/serverkey.pem:/etc/clickhouse-server/server.key\n      - ../../../../testutil/pki/servercert.pem:/etc/clickhouse-server/server.crt\n    ports:\n      - 3306:3306\n      - 8123:8123\n      - 8443:8443\n      - 9000:9000\n      - 9009:9009\n  zookeeper:\n    image: docker.io/zookeeper:3.5.6\n    volumes:\n    - /var/lib/zookeeper\n    ports:\n      - 2181:2181\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/init_schema.sql",
    "content": "﻿DROP TABLE IF EXISTS default.test;\nCREATE TABLE default.test(\n    Nom String,\n    Code Nullable(String) DEFAULT Null,\n    Cur Nullable(String) DEFAULT Null\n) ENGINE=MergeTree() ORDER BY tuple();\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/mysql_port.xml",
    "content": "<yandex>\n    <mysql_port>3306</mysql_port>\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/part_log.xml",
    "content": "<yandex>\n    <part_log>\n        <database>system</database>\n        <table>part_log</table>\n        <flush_interval_milliseconds>7500</flush_interval_milliseconds>\n        <!-- 19.16 -->\n        <partition_by>event_date</partition_by>\n        <!-- 20.5 -->\n        <!-- <engine>Engine = MergeTree PARTITION BY event_date ORDER BY event_time TTL event_date + INTERVAL 30 day</engine> -->\n    </part_log>\n\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/telegraf.conf",
    "content": "### ClickHouse input plugin\n\n[[inputs.clickhouse]]\n  timeout         = 2\n  username            = \"default\"\n  servers         = [\"http://127.0.0.1:8123\"]\n  auto_discovery  = true\n  cluster_include = []\n  cluster_exclude = [\"test_shard_localhost\"]\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/telegraf_ssl.conf",
    "content": "### ClickHouse input plugin\n\n[[inputs.clickhouse]]\n  timeout         = 2\n  username            = \"default\"\n  servers         = [\"https://127.0.0.1:8443\"]\n  auto_discovery  = true\n  cluster_include = []\n  cluster_exclude = [\"test_shard_localhost\"]\n  insecure_skip_verify = false\n  tls_cert = \"./testutil/pki/clientcert.pem\"\n  tls_key = \"./testutil/pki/clientkey.pem\"\n  tls_ca = \"./testutil/pki/cacert.pem\"\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/test_dictionary.xml",
    "content": "<!--\nCREATE DICTIONARY IF NOT EXISTS default.test_dict1(\n    Nom String,\n    Code Nullable(String) DEFAULT Null,\n    Cur Nullable(String) DEFAULT Null\n) PRIMARY KEY nom\nSOURCE(\n    MYSQL(port 3306 host '127.0.0.1' user 'default' password '' db 'default' table 'test')\n)\nLAYOUT(COMPLEX_KEY_HASHED())\nLIFETIME(MIN 300 MAX 600);\n-->\n<yandex>\n    <dictionary>\n        <name>default.test_dict</name>\n\n        <structure>\n            <!-- Complex key configuration -->\n            <key>\n                <attribute>\n                    <name>Nom</name>\n                    <type>String</type>\n                    <null_value></null_value>\n                </attribute>\n            </key>\n            <!-- Attribute parameters -->\n            <attribute>\n                <name>Code</name>\n                <type>String</type>\n                <null_value></null_value>\n            </attribute>\n            <attribute>\n                <name>Cur</name>\n                <type>String</type>\n                <null_value></null_value>\n            </attribute>\n        </structure>\n\n        <source>\n            <!-- Source configuration -->\n            <mysql>\n                <port>3306</port>\n                <user>default</user>\n                <password/>\n                <replica>\n                    <host>127.0.0.1</host>\n                    <priority>1</priority>\n                </replica>\n                <db>default</db>\n                <table>test</table>\n            </mysql>\n        </source>\n\n        <layout>\n            <!-- Memory layout configuration -->\n            <complex_key_hashed />\n        </layout>\n\n        <!-- Lifetime of dictionary in memory -->\n        <lifetime>300</lifetime>\n    </dictionary>\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/text_log.xml",
    "content": "<yandex>\n    <text_log>\n        <level>notice</level>\n        <database>system</database>\n        <table>text_log</table>\n        <flush_interval_milliseconds>7500</flush_interval_milliseconds>\n        <!-- 19.17 -->\n        <partition_by>event_date</partition_by>\n        <!-- 20.5 -->\n        <!-- <engine>Engine = MergeTree PARTITION BY event_date ORDER BY event_time TTL event_date + INTERVAL 30 day</engine> -->\n    </text_log>\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/tls_settings.xml",
    "content": "<yandex>\n  <https_port>8443</https_port>\n  <tcp_port_secure>9440</tcp_port_secure>\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/dev/zookeeper.xml",
    "content": "<yandex>\n    <zookeeper>\n        <node>\n            <host>zookeeper</host>\n            <port>2181</port>\n        </node>\n    </zookeeper>\n    <remote_servers replace=\"1\">\n        <test>\n            <shard>\n                <internal_replication>1</internal_replication>\n                <replica>\n                    <host>localhost</host>\n                    <port>9000</port>\n                </replica>\n            </shard>\n        </test>\n    </remote_servers>\n</yandex>\n"
  },
  {
    "path": "plugins/inputs/clickhouse/sample.conf",
    "content": "# Read metrics from one or many ClickHouse servers\n[[inputs.clickhouse]]\n  ## Username for authorization on ClickHouse server\n  username = \"default\"\n\n  ## Password for authorization on ClickHouse server\n  # password = \"\"\n\n  ## HTTP(s) timeout while getting metrics values\n  ## The timeout includes connection time, any redirects, and reading the\n  ## response body.\n  # timeout = 5s\n\n  ## List of servers for metrics scraping\n  ## metrics scrape via HTTP(s) clickhouse interface\n  ## https://clickhouse.tech/docs/en/interfaces/http/\n  servers = [\"http://127.0.0.1:8123\"]\n\n  ## Server Variant\n  ## When set to \"managed\", some queries are excluded from being run. This is\n  ## useful for instances hosted in ClickHouse Cloud where certain tables are\n  ## not available.\n  # variant = \"self-hosted\"\n\n  ## If \"auto_discovery\"\" is \"true\" plugin tries to connect to all servers\n  ## available in the cluster with using same \"user:password\" described in\n  ## \"user\" and \"password\" parameters and get this server hostname list from\n  ## \"system.clusters\" table. See\n  ## - https://clickhouse.tech/docs/en/operations/system_tables/#system-clusters\n  ## - https://clickhouse.tech/docs/en/operations/server_settings/settings/#server_settings_remote_servers\n  ## - https://clickhouse.tech/docs/en/operations/table_engines/distributed/\n  ## - https://clickhouse.tech/docs/en/operations/table_engines/replication/#creating-replicated-tables\n  # auto_discovery = true\n\n  ## Filter cluster names in \"system.clusters\" when \"auto_discovery\" is \"true\"\n  ## when this filter present then \"WHERE cluster IN (...)\" filter will apply\n  ## please use only full cluster names here, regexp and glob filters is not\n  ## allowed for \"/etc/clickhouse-server/config.d/remote.xml\"\n  ## <yandex>\n  ##  <remote_servers>\n  ##    <my-own-cluster>\n  ##        <shard>\n  ##          <replica><host>clickhouse-ru-1.local</host><port>9000</port></replica>\n  ##          <replica><host>clickhouse-ru-2.local</host><port>9000</port></replica>\n  ##        </shard>\n  ##        <shard>\n  ##          <replica><host>clickhouse-eu-1.local</host><port>9000</port></replica>\n  ##          <replica><host>clickhouse-eu-2.local</host><port>9000</port></replica>\n  ##        </shard>\n  ##    </my-own-cluster>\n  ##  </remote_servers>\n  ##\n  ## </yandex>\n  ##\n  ## example: cluster_include = [\"my-own-cluster\"]\n  # cluster_include = []\n\n  ## Filter cluster names in \"system.clusters\" when \"auto_discovery\" is\n  ## \"true\" when this filter present then \"WHERE cluster NOT IN (...)\"\n  ## filter will apply\n  ##    example: cluster_exclude = [\"my-internal-not-discovered-cluster\"]\n  # cluster_exclude = []\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/README.md",
    "content": "# Google Cloud PubSub Input Plugin\n\nThis plugin consumes messages from the [Google Cloud PubSub][pubsub] service\nand creates metrics using one of the supported [data formats][data_formats].\n\n⭐ Telegraf v1.10.0\n🏷️ cloud, messaging\n💻 all\n\n[pubsub]: https://cloud.google.com/pubsub\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from Google PubSub\n[[inputs.cloud_pubsub]]\n  ## Required. Name of Google Cloud Platform (GCP) Project that owns\n  ## the given PubSub subscription.\n  project = \"my-project\"\n\n  ## Required. Name of PubSub subscription to ingest metrics from.\n  subscription = \"my-subscription\"\n\n  ## Required. Data format to consume.\n  ## Each data format has its own unique set of configuration options.\n  ## Read more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Optional. Filepath for GCP credentials JSON file to authorize calls to\n  ## PubSub APIs. If not set explicitly, Telegraf will attempt to use\n  ## Application Default Credentials, which is preferred.\n  # credentials_file = \"path/to/my/creds.json\"\n\n  ## Optional. Number of seconds to wait before attempting to restart the\n  ## PubSub subscription receiver after an unexpected error.\n  ## If the streaming pull for a PubSub Subscription fails (receiver),\n  ## the agent attempts to restart receiving messages after this many seconds.\n  # retry_delay_seconds = 5\n\n  ## Optional. Maximum byte length of a message to consume.\n  ## Larger messages are dropped with an error. If less than 0 or unspecified,\n  ## treated as no limit.\n  # max_message_len = 1000000\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## The following are optional Subscription ReceiveSettings in PubSub.\n  ## Read more about these values:\n  ## https://godoc.org/cloud.google.com/go/pubsub/v2#ReceiveSettings\n\n  ## Optional. Maximum number of seconds for which a PubSub subscription\n  ## should auto-extend the PubSub ACK deadline for each message. If less than\n  ## 0, auto-extension is disabled.\n  # max_extension = 0\n\n  ## Optional. Maximum number of unprocessed messages in PubSub\n  ## (unacknowledged but not yet expired in PubSub).\n  ## A value of 0 is treated as the default PubSub value.\n  ## Negative values will be treated as unlimited.\n  # max_outstanding_messages = 0\n\n  ## Optional. Maximum size in bytes of unprocessed messages in PubSub\n  ## (unacknowledged but not yet expired in PubSub).\n  ## A value of 0 is treated as the default PubSub value.\n  ## Negative values will be treated as unlimited.\n  # max_outstanding_bytes = 0\n\n  ## Optional. Max number of goroutines a PubSub Subscription receiver can spawn\n  ## to pull messages from PubSub concurrently. This limit applies to each\n  ## subscription separately and is treated as the PubSub default if less than\n  ## 1. Note this setting does not limit the number of messages that can be\n  ## processed concurrently (use \"max_outstanding_messages\" instead).\n  # max_receiver_go_routines = 0\n\n  ## Optional. If true, Telegraf will attempt to base64 decode the\n  ## PubSub message data before parsing. Many GCP services that\n  ## output JSON to Google PubSub base64-encode the JSON payload.\n  # base64_data = false\n\n  ## Content encoding for message payloads, can be set to \"gzip\" or\n  ## \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## If content encoding is not \"identity\", sets the maximum allowed size, \n  ## in bytes, for a message payload when it's decompressed. Can be increased \n  ## for larger payloads or reduced to protect against decompression bombs.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  # max_decompression_size = \"500MB\"\n```\n\n### Multiple Subscriptions and Topics\n\nThis plugin assumes you have already created a PULL subscription for a given\nPubSub topic. To learn how to do so, see [how to create a subscription][pubsub\ncreate sub].\n\nEach plugin agent can listen to one subscription at a time, so you will\nneed to run multiple instances of the plugin to pull messages from multiple\nsubscriptions/topics.\n\n[pubsub create sub]: https://cloud.google.com/pubsub/docs/admin#create_a_pull_subscription\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/cloud_pubsub.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cloud_pubsub\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"cloud.google.com/go/pubsub/v2\"\n\t\"golang.org/x/oauth2/google\"\n\t\"google.golang.org/api/option\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_gcp \"github.com/influxdata/telegraf/plugins/common/gcp\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst (\n\tdefaultMaxUndeliveredMessages = 1000\n\tdefaultRetryDelaySeconds      = 5\n)\n\ntype PubSub struct {\n\tsync.Mutex\n\n\tCredentialsFile string `toml:\"credentials_file\"`\n\tProject         string `toml:\"project\"`\n\tSubscription    string `toml:\"subscription\"`\n\n\t// Subscription ReceiveSettings\n\tMaxExtension           config.Duration `toml:\"max_extension\"`\n\tMaxOutstandingMessages int             `toml:\"max_outstanding_messages\"`\n\tMaxOutstandingBytes    int             `toml:\"max_outstanding_bytes\"`\n\tMaxReceiverGoRoutines  int             `toml:\"max_receiver_go_routines\"`\n\n\t// Agent settings\n\tMaxMessageLen            int `toml:\"max_message_len\"`\n\tMaxUndeliveredMessages   int `toml:\"max_undelivered_messages\"`\n\tRetryReceiveDelaySeconds int `toml:\"retry_delay_seconds\"`\n\n\tBase64Data bool `toml:\"base64_data\"`\n\n\tContentEncoding      string          `toml:\"content_encoding\"`\n\tMaxDecompressionSize config.Size     `toml:\"max_decompression_size\"`\n\tLog                  telegraf.Logger `toml:\"-\"`\n\n\tsub     subscription\n\tstubSub func() subscription\n\n\tcancel context.CancelFunc\n\n\tparser telegraf.Parser\n\twg     *sync.WaitGroup\n\tacc    telegraf.TrackingAccumulator\n\n\tundelivered  map[telegraf.TrackingID]message\n\tsem          semaphore\n\tdecoder      internal.ContentDecoder\n\tdecoderMutex sync.Mutex\n}\n\ntype (\n\tempty     struct{}\n\tsemaphore chan empty\n)\n\nfunc (*PubSub) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ps *PubSub) Init() error {\n\tif ps.Subscription == \"\" {\n\t\treturn errors.New(`\"subscription\" is required`)\n\t}\n\n\tif ps.Project == \"\" {\n\t\treturn errors.New(`\"project\" is required`)\n\t}\n\n\tswitch ps.ContentEncoding {\n\tcase \"\", \"identity\":\n\t\tps.ContentEncoding = \"identity\"\n\tcase \"gzip\":\n\t\tvar err error\n\t\tvar options []internal.DecodingOption\n\t\tif ps.MaxDecompressionSize > 0 {\n\t\t\toptions = append(options, internal.WithMaxDecompressionSize(int64(ps.MaxDecompressionSize)))\n\t\t}\n\t\tps.decoder, err = internal.NewContentDecoder(ps.ContentEncoding, options...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid value %q for content_encoding\", ps.ContentEncoding)\n\t}\n\n\treturn nil\n}\n\nfunc (ps *PubSub) SetParser(parser telegraf.Parser) {\n\tps.parser = parser\n}\n\n// Start initializes the plugin and processing messages from Google PubSub.\n// Two goroutines are started - one pulling for the subscription, one\n// receiving delivery notifications from the accumulator.\nfunc (ps *PubSub) Start(ac telegraf.Accumulator) error {\n\tps.sem = make(semaphore, ps.MaxUndeliveredMessages)\n\tps.acc = ac.WithTracking(ps.MaxUndeliveredMessages)\n\n\t// Create top-level context with cancel that will be called on Stop().\n\tctx, cancel := context.WithCancel(context.Background())\n\tps.cancel = cancel\n\n\tif ps.stubSub != nil {\n\t\tps.sub = ps.stubSub()\n\t} else {\n\t\tsubRef, err := ps.getGCPSubscription(ps.Subscription)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to create subscription handle: %w\", err)\n\t\t}\n\t\tps.sub = subRef\n\t}\n\n\tps.wg = &sync.WaitGroup{}\n\t// Start goroutine to handle delivery notifications from accumulator.\n\tps.wg.Add(1)\n\tgo func() {\n\t\tdefer ps.wg.Done()\n\t\tps.waitForDelivery(ctx)\n\t}()\n\n\t// Start goroutine for subscription receiver.\n\tps.wg.Add(1)\n\tgo func() {\n\t\tdefer ps.wg.Done()\n\t\tps.receiveWithRetry(ctx)\n\t}()\n\n\treturn nil\n}\n\n// Gather does nothing for this service input.\nfunc (*PubSub) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\n// Stop ensures the PubSub subscriptions receivers are stopped by\n// canceling the context and waits for goroutines to finish.\nfunc (ps *PubSub) Stop() {\n\tps.cancel()\n\tps.wg.Wait()\n}\n\n// startReceiver is called within a goroutine and manages keeping a\n// subscription.Receive() up and running while the plugin has not been stopped.\nfunc (ps *PubSub) receiveWithRetry(parentCtx context.Context) {\n\terr := ps.startReceiver(parentCtx)\n\n\tfor err != nil && parentCtx.Err() == nil {\n\t\tps.Log.Errorf(\"Receiver for subscription %s exited with error: %v\", ps.sub.ID(), err)\n\n\t\tdelay := defaultRetryDelaySeconds\n\t\tif ps.RetryReceiveDelaySeconds > 0 {\n\t\t\tdelay = ps.RetryReceiveDelaySeconds\n\t\t}\n\n\t\tps.Log.Infof(\"Waiting %d seconds before attempting to restart receiver...\", delay)\n\t\ttime.Sleep(time.Duration(delay) * time.Second)\n\n\t\terr = ps.startReceiver(parentCtx)\n\t}\n}\n\nfunc (ps *PubSub) startReceiver(parentCtx context.Context) error {\n\tps.Log.Infof(\"Starting receiver for subscription %s...\", ps.sub.ID())\n\tcctx, ccancel := context.WithCancel(parentCtx)\n\terr := ps.sub.Receive(cctx, func(ctx context.Context, msg message) {\n\t\tif err := ps.onMessage(ctx, msg); err != nil {\n\t\t\tps.acc.AddError(fmt.Errorf(\"unable to add message from subscription %s: %w\", ps.sub.ID(), err))\n\t\t}\n\t})\n\tif err != nil {\n\t\tps.acc.AddError(fmt.Errorf(\"receiver for subscription %s exited: %w\", ps.sub.ID(), err))\n\t} else {\n\t\tps.Log.Info(\"Subscription pull ended (no error, most likely stopped)\")\n\t}\n\tccancel()\n\treturn err\n}\n\n// onMessage handles parsing and adding a received message to the accumulator.\nfunc (ps *PubSub) onMessage(ctx context.Context, msg message) error {\n\tif ps.MaxMessageLen > 0 && len(msg.Data()) > ps.MaxMessageLen {\n\t\tmsg.Ack()\n\t\treturn fmt.Errorf(\"message longer than max_message_len (%d > %d)\", len(msg.Data()), ps.MaxMessageLen)\n\t}\n\n\tdata, err := ps.decompressData(msg.Data())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to decompress %s message: %w\", ps.ContentEncoding, err)\n\t}\n\n\tdata, err = ps.decodeB64Data(data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to decode base64 message: %w\", err)\n\t}\n\n\tmetrics, err := ps.parser.Parse(data)\n\tif err != nil {\n\t\tmsg.Ack()\n\t\treturn fmt.Errorf(\"unable to parse message: %w\", err)\n\t}\n\n\tif len(metrics) == 0 {\n\t\tmsg.Ack()\n\n\t\tonce.Do(func() {\n\t\t\tps.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase ps.sem <- empty{}:\n\t\tbreak\n\t}\n\n\tps.Lock()\n\tdefer ps.Unlock()\n\n\tid := ps.acc.AddTrackingMetricGroup(metrics)\n\tif ps.undelivered == nil {\n\t\tps.undelivered = make(map[telegraf.TrackingID]message)\n\t}\n\tps.undelivered[id] = msg\n\n\treturn nil\n}\n\nfunc (ps *PubSub) decompressData(data []byte) ([]byte, error) {\n\tif ps.ContentEncoding == \"identity\" {\n\t\treturn data, nil\n\t}\n\n\tps.decoderMutex.Lock()\n\tdefer ps.decoderMutex.Unlock()\n\tdata, err := ps.decoder.Decode(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdecompressedData := make([]byte, len(data))\n\tcopy(decompressedData, data)\n\tdata = decompressedData\n\n\treturn data, nil\n}\n\nfunc (ps *PubSub) decodeB64Data(data []byte) ([]byte, error) {\n\tif ps.Base64Data {\n\t\treturn base64.StdEncoding.DecodeString(string(data))\n\t}\n\n\treturn data, nil\n}\n\nfunc (ps *PubSub) waitForDelivery(parentCtx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-parentCtx.Done():\n\t\t\treturn\n\t\tcase info := <-ps.acc.Delivered():\n\t\t\t<-ps.sem\n\t\t\tmsg := ps.removeDelivered(info.ID())\n\n\t\t\tif msg != nil {\n\t\t\t\tmsg.Ack()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ps *PubSub) removeDelivered(id telegraf.TrackingID) message {\n\tps.Lock()\n\tdefer ps.Unlock()\n\n\tmsg, ok := ps.undelivered[id]\n\tif !ok {\n\t\treturn nil\n\t}\n\tdelete(ps.undelivered, id)\n\treturn msg\n}\n\nfunc (ps *PubSub) getPubSubClient() (*pubsub.Client, error) {\n\tvar credsOpt option.ClientOption\n\tif ps.CredentialsFile != \"\" {\n\t\tcredType, err := common_gcp.ParseCredentialType(ps.CredentialsFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse credential file type: %w\", err)\n\t\t}\n\t\tcredsOpt = option.WithAuthCredentialsFile(option.CredentialsType(credType), ps.CredentialsFile)\n\t} else {\n\t\tcreds, err := google.FindDefaultCredentials(context.Background(), pubsub.ScopeCloudPlatform)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"unable to find GCP Application Default Credentials: %v.\"+\n\t\t\t\t\t\"Either set ADC or provide CredentialsFile config\", err)\n\t\t}\n\t\tcredsOpt = option.WithCredentials(creds)\n\t}\n\tclient, err := pubsub.NewClient(\n\t\tcontext.Background(),\n\t\tps.Project,\n\t\tcredsOpt,\n\t\toption.WithScopes(pubsub.ScopeCloudPlatform),\n\t\toption.WithUserAgent(internal.ProductToken()),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to generate PubSub client: %w\", err)\n\t}\n\treturn client, nil\n}\n\nfunc (ps *PubSub) getGCPSubscription(subID string) (subscription, error) {\n\tclient, err := ps.getPubSubClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts := client.Subscriber(subID)\n\ts.ReceiveSettings = pubsub.ReceiveSettings{\n\t\tNumGoroutines:          ps.MaxReceiverGoRoutines,\n\t\tMaxExtension:           time.Duration(ps.MaxExtension),\n\t\tMaxOutstandingMessages: ps.MaxOutstandingMessages,\n\t\tMaxOutstandingBytes:    ps.MaxOutstandingBytes,\n\t}\n\treturn &gcpSubscription{s}, nil\n}\n\nfunc init() {\n\tinputs.Add(\"cloud_pubsub\", func() telegraf.Input {\n\t\tps := &PubSub{\n\t\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\t}\n\t\treturn ps\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/cloud_pubsub_test.go",
    "content": "package cloud_pubsub\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tmsgInflux = \"cpu_load_short,host=server01 value=23422.0 1422568543702900257\\n\"\n)\n\n// Test ingesting InfluxDB-format PubSub message\nfunc TestRunParse(t *testing.T) {\n\tsubID := \"sub-run-parse\"\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tsub.receiver = testMessagesReceive(sub)\n\n\tdecoder, err := internal.NewContentDecoder(\"identity\")\n\trequire.NoError(t, err)\n\n\tps := &PubSub{\n\t\tLog:                    testutil.Logger{},\n\t\tparser:                 testParser,\n\t\tstubSub:                func() subscription { return sub },\n\t\tProject:                \"projectIDontMatterForTests\",\n\t\tSubscription:           subID,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tdecoder:                decoder,\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\ttestTracker := &testTracker{}\n\tmsg := &testMsg{\n\t\tvalue:   msgInflux,\n\t\ttracker: testTracker,\n\t}\n\tsub.messages <- msg\n\n\tacc.Wait(1)\n\trequire.Equal(t, 1, acc.NFields())\n\tmetric := acc.Metrics[0]\n\tvalidateTestInfluxMetric(t, metric)\n}\n\n// Test ingesting InfluxDB-format PubSub message\nfunc TestRunBase64(t *testing.T) {\n\tsubID := \"sub-run-base64\"\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tsub.receiver = testMessagesReceive(sub)\n\n\tdecoder, err := internal.NewContentDecoder(\"identity\")\n\trequire.NoError(t, err)\n\n\tps := &PubSub{\n\t\tLog:                    testutil.Logger{},\n\t\tparser:                 testParser,\n\t\tstubSub:                func() subscription { return sub },\n\t\tProject:                \"projectIDontMatterForTests\",\n\t\tSubscription:           subID,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tBase64Data:             true,\n\t\tdecoder:                decoder,\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\ttestTracker := &testTracker{}\n\tmsg := &testMsg{\n\t\tvalue:   base64.StdEncoding.EncodeToString([]byte(msgInflux)),\n\t\ttracker: testTracker,\n\t}\n\tsub.messages <- msg\n\n\tacc.Wait(1)\n\trequire.Equal(t, 1, acc.NFields())\n\tmetric := acc.Metrics[0]\n\tvalidateTestInfluxMetric(t, metric)\n}\n\nfunc TestRunGzipDecode(t *testing.T) {\n\tsubID := \"sub-run-gzip\"\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tsub.receiver = testMessagesReceive(sub)\n\n\tdecoder, err := internal.NewContentDecoder(\"gzip\")\n\trequire.NoError(t, err)\n\n\tps := &PubSub{\n\t\tLog:                    testutil.Logger{},\n\t\tparser:                 testParser,\n\t\tstubSub:                func() subscription { return sub },\n\t\tProject:                \"projectIDontMatterForTests\",\n\t\tSubscription:           subID,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tContentEncoding:        \"gzip\",\n\t\tdecoder:                decoder,\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\ttestTracker := &testTracker{}\n\tenc, err := internal.NewGzipEncoder()\n\trequire.NoError(t, err)\n\tgzippedMsg, err := enc.Encode([]byte(msgInflux))\n\trequire.NoError(t, err)\n\tmsg := &testMsg{\n\t\tvalue:   string(gzippedMsg),\n\t\ttracker: testTracker,\n\t}\n\tsub.messages <- msg\n\tacc.Wait(1)\n\trequire.Equal(t, 1, acc.NFields())\n\tmetric := acc.Metrics[0]\n\tvalidateTestInfluxMetric(t, metric)\n}\n\nfunc TestRunInvalidMessages(t *testing.T) {\n\tsubID := \"sub-invalid-messages\"\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tsub.receiver = testMessagesReceive(sub)\n\n\tdecoder, err := internal.NewContentDecoder(\"identity\")\n\trequire.NoError(t, err)\n\tps := &PubSub{\n\t\tLog:                    testutil.Logger{},\n\t\tparser:                 testParser,\n\t\tstubSub:                func() subscription { return sub },\n\t\tProject:                \"projectIDontMatterForTests\",\n\t\tSubscription:           subID,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tdecoder:                decoder,\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\ttestTracker := &testTracker{}\n\tmsg := &testMsg{\n\t\tvalue:   \"~invalidInfluxMsg~\",\n\t\ttracker: testTracker,\n\t}\n\tsub.messages <- msg\n\n\tacc.WaitError(1)\n\n\t// Make sure we acknowledged message so we don't receive it again.\n\ttestTracker.waitForAck(1)\n\n\trequire.Equal(t, 0, acc.NFields())\n}\n\nfunc TestRunOverlongMessages(t *testing.T) {\n\tsubID := \"sub-message-too-long\"\n\n\tacc := &testutil.Accumulator{}\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tsub.receiver = testMessagesReceive(sub)\n\n\tdecoder, err := internal.NewContentDecoder(\"identity\")\n\trequire.NoError(t, err)\n\tps := &PubSub{\n\t\tLog:                    testutil.Logger{},\n\t\tparser:                 testParser,\n\t\tstubSub:                func() subscription { return sub },\n\t\tProject:                \"projectIDontMatterForTests\",\n\t\tSubscription:           subID,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tdecoder:                decoder,\n\t\t// Add MaxMessageLen Param\n\t\tMaxMessageLen: 1,\n\t}\n\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\ttestTracker := &testTracker{}\n\tmsg := &testMsg{\n\t\tvalue:   msgInflux,\n\t\ttracker: testTracker,\n\t}\n\tsub.messages <- msg\n\n\tacc.WaitError(1)\n\n\t// Make sure we acknowledged message so we don't receive it again.\n\ttestTracker.waitForAck(1)\n\n\trequire.Equal(t, 0, acc.NFields())\n}\n\nfunc TestRunErrorInSubscriber(t *testing.T) {\n\tsubID := \"sub-unexpected-error\"\n\n\tacc := &testutil.Accumulator{}\n\n\ttestParser := &influx.Parser{}\n\trequire.NoError(t, testParser.Init())\n\n\tsub := &stubSub{\n\t\tid:       subID,\n\t\tmessages: make(chan *testMsg, 100),\n\t}\n\tfakeErrStr := \"a fake error\"\n\tsub.receiver = testMessagesError(errors.New(\"a fake error\"))\n\n\tdecoder, err := internal.NewContentDecoder(\"identity\")\n\trequire.NoError(t, err)\n\tps := &PubSub{\n\t\tLog:                      testutil.Logger{},\n\t\tparser:                   testParser,\n\t\tstubSub:                  func() subscription { return sub },\n\t\tProject:                  \"projectIDontMatterForTests\",\n\t\tSubscription:             subID,\n\t\tMaxUndeliveredMessages:   defaultMaxUndeliveredMessages,\n\t\tdecoder:                  decoder,\n\t\tRetryReceiveDelaySeconds: 1,\n\t}\n\n\trequire.NoError(t, ps.Init())\n\trequire.NoError(t, ps.Start(acc))\n\tdefer ps.Stop()\n\n\trequire.NotNil(t, ps.sub)\n\n\tacc.WaitError(1)\n\trequire.Regexp(t, fakeErrStr, acc.Errors[0])\n}\n\nfunc validateTestInfluxMetric(t *testing.T, m *testutil.Metric) {\n\trequire.Equal(t, \"cpu_load_short\", m.Measurement)\n\trequire.Equal(t, \"server01\", m.Tags[\"host\"])\n\trequire.InDelta(t, 23422.0, m.Fields[\"value\"], testutil.DefaultDelta)\n\trequire.Equal(t, int64(1422568543702900257), m.Time.UnixNano())\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/sample.conf",
    "content": "# Read metrics from Google PubSub\n[[inputs.cloud_pubsub]]\n  ## Required. Name of Google Cloud Platform (GCP) Project that owns\n  ## the given PubSub subscription.\n  project = \"my-project\"\n\n  ## Required. Name of PubSub subscription to ingest metrics from.\n  subscription = \"my-subscription\"\n\n  ## Required. Data format to consume.\n  ## Each data format has its own unique set of configuration options.\n  ## Read more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Optional. Filepath for GCP credentials JSON file to authorize calls to\n  ## PubSub APIs. If not set explicitly, Telegraf will attempt to use\n  ## Application Default Credentials, which is preferred.\n  # credentials_file = \"path/to/my/creds.json\"\n\n  ## Optional. Number of seconds to wait before attempting to restart the\n  ## PubSub subscription receiver after an unexpected error.\n  ## If the streaming pull for a PubSub Subscription fails (receiver),\n  ## the agent attempts to restart receiving messages after this many seconds.\n  # retry_delay_seconds = 5\n\n  ## Optional. Maximum byte length of a message to consume.\n  ## Larger messages are dropped with an error. If less than 0 or unspecified,\n  ## treated as no limit.\n  # max_message_len = 1000000\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## The following are optional Subscription ReceiveSettings in PubSub.\n  ## Read more about these values:\n  ## https://godoc.org/cloud.google.com/go/pubsub/v2#ReceiveSettings\n\n  ## Optional. Maximum number of seconds for which a PubSub subscription\n  ## should auto-extend the PubSub ACK deadline for each message. If less than\n  ## 0, auto-extension is disabled.\n  # max_extension = 0\n\n  ## Optional. Maximum number of unprocessed messages in PubSub\n  ## (unacknowledged but not yet expired in PubSub).\n  ## A value of 0 is treated as the default PubSub value.\n  ## Negative values will be treated as unlimited.\n  # max_outstanding_messages = 0\n\n  ## Optional. Maximum size in bytes of unprocessed messages in PubSub\n  ## (unacknowledged but not yet expired in PubSub).\n  ## A value of 0 is treated as the default PubSub value.\n  ## Negative values will be treated as unlimited.\n  # max_outstanding_bytes = 0\n\n  ## Optional. Max number of goroutines a PubSub Subscription receiver can spawn\n  ## to pull messages from PubSub concurrently. This limit applies to each\n  ## subscription separately and is treated as the PubSub default if less than\n  ## 1. Note this setting does not limit the number of messages that can be\n  ## processed concurrently (use \"max_outstanding_messages\" instead).\n  # max_receiver_go_routines = 0\n\n  ## Optional. If true, Telegraf will attempt to base64 decode the\n  ## PubSub message data before parsing. Many GCP services that\n  ## output JSON to Google PubSub base64-encode the JSON payload.\n  # base64_data = false\n\n  ## Content encoding for message payloads, can be set to \"gzip\" or\n  ## \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## If content encoding is not \"identity\", sets the maximum allowed size, \n  ## in bytes, for a message payload when it's decompressed. Can be increased \n  ## for larger payloads or reduced to protect against decompression bombs.\n  ## Acceptable units are B, KiB, KB, MiB, MB...\n  # max_decompression_size = \"500MB\"\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/subscription_gcp.go",
    "content": "package cloud_pubsub\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"cloud.google.com/go/pubsub/v2\"\n)\n\ntype (\n\tsubscription interface {\n\t\t// ID returns the unique identifier of the subscription.\n\t\tID() string\n\t\t// Receive starts receiving messages from the subscription and processes them using the provided function.\n\t\tReceive(ctx context.Context, f func(context.Context, message)) error\n\t}\n\n\tmessage interface {\n\t\t// Ack acknowledges the message, indicating successful processing.\n\t\tAck()\n\t\t// Nack negatively acknowledges the message, indicating it should be redelivered.\n\t\tNack()\n\t\t// ID returns the unique identifier of the message.\n\t\tID() string\n\t\t// Data returns the payload of the message.\n\t\tData() []byte\n\t\t// Attributes returns the attributes of the message as a key-value map.\n\t\tAttributes() map[string]string\n\t\t// PublishTime returns the time when the message was published.\n\t\tPublishTime() time.Time\n\t}\n\n\tgcpSubscription struct {\n\t\tsub *pubsub.Subscriber\n\t}\n\n\tgcpMessage struct {\n\t\tmsg *pubsub.Message\n\t}\n)\n\n// ID returns the unique identifier of the subscription.\nfunc (s *gcpSubscription) ID() string {\n\tif s.sub == nil {\n\t\treturn \"\"\n\t}\n\treturn s.sub.ID()\n}\n\n// Receive starts receiving messages from the subscription and processes them using the provided function.\nfunc (s *gcpSubscription) Receive(ctx context.Context, f func(context.Context, message)) error {\n\treturn s.sub.Receive(ctx, func(cctx context.Context, m *pubsub.Message) {\n\t\tf(cctx, &gcpMessage{m})\n\t})\n}\n\n// Ack acknowledges the message, indicating successful processing.\nfunc (env *gcpMessage) Ack() {\n\tenv.msg.Ack()\n}\n\n// Nack negatively acknowledges the message, indicating it should be redelivered.\nfunc (env *gcpMessage) Nack() {\n\tenv.msg.Nack()\n}\n\n// ID returns the unique identifier of the message.\nfunc (env *gcpMessage) ID() string {\n\treturn env.msg.ID\n}\n\n// Data returns the payload of the message.\nfunc (env *gcpMessage) Data() []byte {\n\treturn env.msg.Data\n}\n\n// Attributes returns the attributes of the message as a key-value map.\nfunc (env *gcpMessage) Attributes() map[string]string {\n\treturn env.msg.Attributes\n}\n\n// PublishTime returns the time when the message was published.\nfunc (env *gcpMessage) PublishTime() time.Time {\n\treturn env.msg.PublishTime\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub/subscription_stub_test.go",
    "content": "package cloud_pubsub\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype stubSub struct {\n\tid       string\n\tmessages chan *testMsg\n\treceiver receiveFunc\n}\n\nfunc (s *stubSub) ID() string {\n\treturn s.id\n}\n\nfunc (s *stubSub) Receive(ctx context.Context, f func(context.Context, message)) error {\n\treturn s.receiver(ctx, f)\n}\n\ntype receiveFunc func(ctx context.Context, f func(context.Context, message)) error\n\nfunc testMessagesError(expectedErr error) receiveFunc {\n\treturn func(context.Context, func(context.Context, message)) error {\n\t\treturn expectedErr\n\t}\n}\n\nfunc testMessagesReceive(s *stubSub) receiveFunc {\n\treturn func(ctx context.Context, f func(context.Context, message)) error {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase m := <-s.messages:\n\t\t\t\tf(ctx, m)\n\t\t\t}\n\t\t}\n\t}\n}\n\ntype testMsg struct {\n\tid          string\n\tvalue       string\n\tattributes  map[string]string\n\tpublishTime time.Time\n\n\ttracker *testTracker\n}\n\nfunc (tm *testMsg) Ack() {\n\ttm.tracker.ack()\n}\n\nfunc (tm *testMsg) Nack() {\n\ttm.tracker.nack()\n}\n\nfunc (tm *testMsg) ID() string {\n\treturn tm.id\n}\n\nfunc (tm *testMsg) Data() []byte {\n\treturn []byte(tm.value)\n}\n\nfunc (tm *testMsg) Attributes() map[string]string {\n\treturn tm.attributes\n}\n\nfunc (tm *testMsg) PublishTime() time.Time {\n\treturn tm.publishTime\n}\n\ntype testTracker struct {\n\tsync.Mutex\n\t*sync.Cond\n\n\tnumAcks  int\n\tnumNacks int\n}\n\nfunc (t *testTracker) waitForAck(num int) {\n\tt.Lock()\n\tif t.Cond == nil {\n\t\tt.Cond = sync.NewCond(&t.Mutex)\n\t}\n\tfor t.numAcks < num {\n\t\tt.Wait()\n\t}\n\tt.Unlock()\n}\n\nfunc (t *testTracker) ack() {\n\tt.Lock()\n\tdefer t.Unlock()\n\n\tt.numAcks++\n}\n\nfunc (t *testTracker) nack() {\n\tt.Lock()\n\tdefer t.Unlock()\n\n\tt.numNacks++\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub_push/README.md",
    "content": "# Google Cloud PubSub Push Input Plugin\n\nThis plugin listens for messages sent via an HTTP POST from\n[Google Cloud PubSub][pubsub] and expects messages in Google's Pub/Sub\n_JSON format_. The plugin allows Telegraf to serve as an endpoint of push\nservice.\n\nGoogle's PubSub service will __only__ send over HTTPS/TLS so this plugin must be\nbehind a valid proxy or must be configured to use TLS by setting the `tls_cert`\nand `tls_key` accordingly.\n\nEnable mutually authenticated TLS and authorize client connections by signing\ncertificate authority by including a list of allowed CA certificate file names\nin `tls_allowed_cacerts`.\n\n⭐ Telegraf v1.10.0\n🏷️ cloud, messaging\n💻 all\n\n[pubsub]: https://cloud.google.com/pubsub\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Google Cloud Pub/Sub Push HTTP listener\n[[inputs.cloud_pubsub_push]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8080\"\n\n  ## Application secret to verify messages originate from Cloud Pub/Sub\n  # token = \"\"\n\n  ## Path to listen to.\n  # path = \"/\"\n\n  ## Maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## Maximum duration before timing out write of the response. This should be\n  ## set to a value large enough that you can send at least 'metric_batch_size'\n  ## number of messages within the duration.\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,00 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Whether to add the pubsub metadata, such as message attributes and\n  ## subscription as a tag.\n  # add_meta = false\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\nThis plugin assumes you have already created a PUSH subscription for a given\nPubSub topic.\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub_push/cloud_pubsub_push.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cloud_pubsub_push\n\nimport (\n\t\"context\"\n\t\"crypto/subtle\"\n\t_ \"embed\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\n// defaultMaxBodySize is the default maximum request body size, in bytes.\n// if the request body is over this size, we will return an HTTP 413 error.\nconst (\n\t// 500 MB\n\tdefaultMaxBodySize            = 500 * 1024 * 1024\n\tdefaultMaxUndeliveredMessages = 1000\n)\n\ntype PubSubPush struct {\n\tServiceAddress string\n\tToken          string\n\tPath           string\n\tReadTimeout    config.Duration\n\tWriteTimeout   config.Duration\n\tMaxBodySize    config.Size\n\tAddMeta        bool\n\tLog            telegraf.Logger\n\n\tMaxUndeliveredMessages int `toml:\"max_undelivered_messages\"`\n\n\tcommon_tls.ServerConfig\n\ttelegraf.Parser\n\n\tserver *http.Server\n\tacc    telegraf.TrackingAccumulator\n\tctx    context.Context\n\tcancel context.CancelFunc\n\twg     *sync.WaitGroup\n\tmu     *sync.Mutex\n\n\tundelivered map[telegraf.TrackingID]chan bool\n\tsem         chan struct{}\n}\n\n// message defines the structure of a Google Pub/Sub message.\ntype message struct {\n\tAtts map[string]string `json:\"attributes\"`\n\tData string            `json:\"data\"` // Data is base64 encoded data\n}\n\n// payload is the received Google Pub/Sub data. (https://cloud.google.com/pubsub/docs/push)\ntype payload struct {\n\tMsg          message `json:\"message\"`\n\tSubscription string  `json:\"subscription\"`\n}\n\nfunc (*PubSubPush) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *PubSubPush) SetParser(parser telegraf.Parser) {\n\tp.Parser = parser\n}\n\n// Start starts the http listener service.\nfunc (p *PubSubPush) Start(acc telegraf.Accumulator) error {\n\tif p.MaxBodySize == 0 {\n\t\tp.MaxBodySize = config.Size(defaultMaxBodySize)\n\t}\n\n\tif p.ReadTimeout < config.Duration(time.Second) {\n\t\tp.ReadTimeout = config.Duration(time.Second * 10)\n\t}\n\tif p.WriteTimeout < config.Duration(time.Second) {\n\t\tp.WriteTimeout = config.Duration(time.Second * 10)\n\t}\n\n\ttlsConf, err := p.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.server = &http.Server{\n\t\tAddr:        p.ServiceAddress,\n\t\tHandler:     http.TimeoutHandler(p, time.Duration(p.WriteTimeout), \"timed out processing metric\"),\n\t\tReadTimeout: time.Duration(p.ReadTimeout),\n\t\tTLSConfig:   tlsConf,\n\t}\n\n\tp.ctx, p.cancel = context.WithCancel(context.Background())\n\tp.wg = &sync.WaitGroup{}\n\tp.acc = acc.WithTracking(p.MaxUndeliveredMessages)\n\tp.sem = make(chan struct{}, p.MaxUndeliveredMessages)\n\tp.undelivered = make(map[telegraf.TrackingID]chan bool)\n\tp.mu = &sync.Mutex{}\n\n\tp.wg.Add(1)\n\tgo func() {\n\t\tdefer p.wg.Done()\n\t\tp.receiveDelivered()\n\t}()\n\n\tp.wg.Add(1)\n\tgo func() {\n\t\tdefer p.wg.Done()\n\t\tif tlsConf != nil {\n\t\t\tif err := p.server.ListenAndServeTLS(\"\", \"\"); err != nil && err != http.ErrServerClosed {\n\t\t\t\tp.Log.Errorf(\"listening and serving TLS failed: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err := p.server.ListenAndServe(); err != nil {\n\t\t\t\tp.Log.Errorf(\"listening and serving TLS failed: %v\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (*PubSubPush) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\n// Stop cleans up all resources\nfunc (p *PubSubPush) Stop() {\n\tp.cancel()\n\tp.server.Shutdown(p.ctx) //nolint:errcheck // we cannot do anything if the shutdown fails\n\tp.wg.Wait()\n}\n\nfunc (p *PubSubPush) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tif req.URL.Path == p.Path {\n\t\tp.authenticateIfSet(p.serveWrite, res, req)\n\t} else {\n\t\tp.authenticateIfSet(http.NotFound, res, req)\n\t}\n}\n\nfunc (p *PubSubPush) serveWrite(res http.ResponseWriter, req *http.Request) {\n\tselect {\n\tcase <-req.Context().Done():\n\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\treturn\n\tcase <-p.ctx.Done():\n\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\treturn\n\tcase p.sem <- struct{}{}:\n\t\tbreak\n\t}\n\n\t// Check that the content length is not too large for us to handle.\n\tif req.ContentLength > int64(p.MaxBodySize) {\n\t\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t\treturn\n\t}\n\n\tif req.Method != http.MethodPost {\n\t\tres.WriteHeader(http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tbody := http.MaxBytesReader(res, req.Body, int64(p.MaxBodySize))\n\tbytes, err := io.ReadAll(body)\n\tif err != nil {\n\t\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t\treturn\n\t}\n\n\tvar payload payload\n\tif err = json.Unmarshal(bytes, &payload); err != nil {\n\t\tp.Log.Errorf(\"Error decoding payload %s\", err.Error())\n\t\tres.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tsDec, err := base64.StdEncoding.DecodeString(payload.Msg.Data)\n\tif err != nil {\n\t\tp.Log.Errorf(\"Base64-decode failed %s\", err.Error())\n\t\tres.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tmetrics, err := p.Parse(sDec)\n\tif err != nil {\n\t\tp.Log.Debug(err.Error())\n\t\tres.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\tp.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tif p.AddMeta {\n\t\tfor i := range metrics {\n\t\t\tfor k, v := range payload.Msg.Atts {\n\t\t\t\tmetrics[i].AddTag(k, v)\n\t\t\t}\n\t\t\tmetrics[i].AddTag(\"subscription\", payload.Subscription)\n\t\t}\n\t}\n\n\tch := make(chan bool, 1)\n\tp.mu.Lock()\n\tp.undelivered[p.acc.AddTrackingMetricGroup(metrics)] = ch\n\tp.mu.Unlock()\n\n\tselect {\n\tcase <-req.Context().Done():\n\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\treturn\n\tcase success := <-ch:\n\t\tif success {\n\t\t\tres.WriteHeader(http.StatusNoContent)\n\t\t} else {\n\t\t\tres.WriteHeader(http.StatusInternalServerError)\n\t\t}\n\t}\n}\n\nfunc (p *PubSubPush) receiveDelivered() {\n\tfor {\n\t\tselect {\n\t\tcase <-p.ctx.Done():\n\t\t\treturn\n\t\tcase info := <-p.acc.Delivered():\n\t\t\t<-p.sem\n\n\t\t\tp.mu.Lock()\n\t\t\tch, ok := p.undelivered[info.ID()]\n\t\t\tif !ok {\n\t\t\t\tp.mu.Unlock()\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdelete(p.undelivered, info.ID())\n\t\t\tp.mu.Unlock()\n\n\t\t\tif info.Delivered() {\n\t\t\t\tch <- true\n\t\t\t} else {\n\t\t\t\tch <- false\n\t\t\t\tp.Log.Debug(\"Metric group failed to process\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *PubSubPush) authenticateIfSet(handler http.HandlerFunc, res http.ResponseWriter, req *http.Request) {\n\tif p.Token != \"\" {\n\t\tif subtle.ConstantTimeCompare([]byte(req.FormValue(\"token\")), []byte(p.Token)) != 1 {\n\t\t\thttp.Error(res, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t}\n\n\thandler(res, req)\n}\n\nfunc init() {\n\tinputs.Add(\"cloud_pubsub_push\", func() telegraf.Input {\n\t\treturn &PubSubPush{\n\t\t\tServiceAddress:         \":8080\",\n\t\t\tPath:                   \"/\",\n\t\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go",
    "content": "//go:build !windows\n\npackage cloud_pubsub_push\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestServeHTTP(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tmethod   string\n\t\tpath     string\n\t\tbody     io.Reader\n\t\tstatus   int\n\t\tmaxsize  int64\n\t\texpected string\n\t\tfail     bool\n\t\tfull     bool\n\t}{\n\t\t{\n\t\t\tname:   \"bad method get\",\n\t\t\tmethod: \"GET\",\n\t\t\tpath:   \"/\",\n\t\t\tstatus: http.StatusMethodNotAllowed,\n\t\t},\n\t\t{\n\t\t\tname:   \"post not found\",\n\t\t\tmethod: \"POST\",\n\t\t\tpath:   \"/allthings\",\n\t\t\tstatus: http.StatusNotFound,\n\t\t},\n\t\t{\n\t\t\tname:   \"post large date\",\n\t\t\tmethod: \"POST\",\n\t\t\tpath:   \"/\",\n\t\t\tstatus: http.StatusRequestEntityTooLarge,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},` +\n\t\t\t\t\t`\"data\":\"dGVzdGluZ0dvb2dsZSxzZW5zb3I9Ym1lXzI4MCB0ZW1wX2M9MjMuOTUsaHVtaWRpdHk9NjIuODMgMTUzNjk1Mjk3NDU1MzUxMDIzMQ==\",` +\n\t\t\t\t\t`\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",\"publishTime\":\"2018-09-14T19:22:54.587Z\",` +\n\t\t\t\t\t`\"publish_time\":\"2018-09-14T19:22:54.587Z\"},\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname:    \"post valid data\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusNoContent,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},` +\n\t\t\t\t\t`\"data\":\"dGVzdGluZ0dvb2dsZSxzZW5zb3I9Ym1lXzI4MCB0ZW1wX2M9MjMuOTUsaHVtaWRpdHk9NjIuODMgMTUzNjk1Mjk3NDU1MzUxMDIzMQ==\",` +\n\t\t\t\t\t`\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",\"publishTime\":\"2018-09-14T19:22:54.587Z\",` +\n\t\t\t\t\t`\"publish_time\":\"2018-09-14T19:22:54.587Z\"},\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname:    \"fail write\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusServiceUnavailable,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},` +\n\t\t\t\t\t`\"data\":\"dGVzdGluZ0dvb2dsZSxzZW5zb3I9Ym1lXzI4MCB0ZW1wX2M9MjMuOTUsaHVtaWRpdHk9NjIuODMgMTUzNjk1Mjk3NDU1MzUxMDIzMQ==\",` +\n\t\t\t\t\t`\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",\"publishTime\":\"2018-09-14T19:22:54.587Z\",` +\n\t\t\t\t\t`\"publish_time\":\"2018-09-14T19:22:54.587Z\"},\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t\tfail: true,\n\t\t},\n\t\t{\n\t\t\tname:    \"full buffer\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusServiceUnavailable,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},` +\n\t\t\t\t\t`\"data\":\"dGVzdGluZ0dvb2dsZSxzZW5zb3I9Ym1lXzI4MCB0ZW1wX2M9MjMuOTUsaHVtaWRpdHk9NjIuODMgMTUzNjk1Mjk3NDU1MzUxMDIzMQ==\",` +\n\t\t\t\t\t`\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",\"publishTime\":\"2018-09-14T19:22:54.587Z\",` +\n\t\t\t\t\t`\"publish_time\":\"2018-09-14T19:22:54.587Z\"},\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t\tfull: true,\n\t\t},\n\t\t{\n\t\t\tname:    \"post invalid body\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusBadRequest,\n\t\t\tbody:    strings.NewReader(`invalid body`),\n\t\t},\n\t\t{\n\t\t\tname:    \"post invalid data\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusBadRequest,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},\"data\":\"not base 64 encoded data\",` +\n\t\t\t\t\t`\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",\"publishTime\":\"2018-09-14T19:22:54.587Z\",` +\n\t\t\t\t\t`\"publish_time\":\"2018-09-14T19:22:54.587Z\"},\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname:    \"post invalid data format\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusBadRequest,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"deviceId\":\"myPi\",\"deviceNumId\":\"2808946627307959\",\"deviceRegistryId\":\"my-registry\",` +\n\t\t\t\t\t`\"deviceRegistryLocation\":\"us-central1\",\"projectId\":\"conference-demos\",\"subFolder\":\"\"},` +\n\t\t\t\t\t`\"data\":\"bm90IHZhbGlkIGZvcm1hdHRlZCBkYXRh\",\"messageId\":\"204004313210337\",\"message_id\":\"204004313210337\",` +\n\t\t\t\t\t`\"publishTime\":\"2018-09-14T19:22:54.587Z\",\"publish_time\":\"2018-09-14T19:22:54.587Z\"},` +\n\t\t\t\t\t`\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname:    \"post invalid structured body\",\n\t\t\tmethod:  \"POST\",\n\t\t\tpath:    \"/\",\n\t\t\tmaxsize: 500 * 1024 * 1024,\n\t\t\tstatus:  http.StatusBadRequest,\n\t\t\tbody: strings.NewReader(\n\t\t\t\t`{\"message\":{\"attributes\":{\"thing\":1},\"data\":\"bm90IHZhbGlkIGZvcm1hdHRlZCBkYXRh\"},` +\n\t\t\t\t\t`\"subscription\":\"projects/conference-demos/subscriptions/my-subscription\"}`,\n\t\t\t),\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\twg := &sync.WaitGroup{}\n\t\treq, err := http.NewRequest(test.method, test.path, test.body)\n\t\trequire.NoError(t, err)\n\n\t\trr := httptest.NewRecorder()\n\t\tpubPush := &PubSubPush{\n\t\t\tLog:          testutil.Logger{},\n\t\t\tPath:         \"/\",\n\t\t\tMaxBodySize:  config.Size(test.maxsize),\n\t\t\tsem:          make(chan struct{}, 1),\n\t\t\tundelivered:  make(map[telegraf.TrackingID]chan bool),\n\t\t\tmu:           &sync.Mutex{},\n\t\t\tWriteTimeout: config.Duration(time.Millisecond * 10),\n\t\t}\n\n\t\tpubPush.ctx, pubPush.cancel = context.WithCancel(t.Context())\n\n\t\tif test.full {\n\t\t\t// fill buffer with fake message\n\t\t\tpubPush.sem <- struct{}{}\n\t\t}\n\n\t\tp := &influx.Parser{}\n\t\trequire.NoError(t, p.Init())\n\t\tpubPush.SetParser(p)\n\n\t\tdst := make(chan telegraf.Metric, 1)\n\t\tro := models.NewRunningOutput(&testOutput{failWrite: test.fail}, &models.OutputConfig{}, 1, 1)\n\t\tpubPush.acc = agent.NewAccumulator(&testMetricMaker{}, dst).WithTracking(1)\n\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tpubPush.receiveDelivered()\n\t\t}()\n\n\t\twg.Add(1)\n\t\tgo func(d chan telegraf.Metric) {\n\t\t\tdefer wg.Done()\n\t\t\tfor m := range d {\n\t\t\t\tro.AddMetric(m)\n\t\t\t\tro.Write() //nolint:errcheck // test will fail anyway if the write fails\n\t\t\t\tm.Accept()\n\t\t\t}\n\t\t}(dst)\n\n\t\tctx, cancel := context.WithTimeout(req.Context(), time.Duration(pubPush.WriteTimeout))\n\t\treq = req.WithContext(ctx)\n\n\t\tpubPush.ServeHTTP(rr, req)\n\t\trequire.Equal(t, test.status, rr.Code, test.name)\n\n\t\tif test.expected != \"\" {\n\t\t\trequire.Equal(t, test.expected, rr.Body.String(), test.name)\n\t\t}\n\n\t\tpubPush.cancel()\n\t\tcancel()\n\t\tclose(dst)\n\t\twg.Wait()\n\t}\n}\n\ntype testMetricMaker struct{}\n\nfunc (*testMetricMaker) Name() string {\n\treturn \"TestPlugin\"\n}\n\nfunc (tm *testMetricMaker) LogName() string {\n\treturn tm.Name()\n}\n\nfunc (*testMetricMaker) MakeMetric(metric telegraf.Metric) telegraf.Metric {\n\treturn metric\n}\n\nfunc (*testMetricMaker) Log() telegraf.Logger {\n\treturn logger.New(\"test\", \"test\", \"\")\n}\n\ntype testOutput struct {\n\t// if true, mock a write failure\n\tfailWrite bool\n}\n\nfunc (*testOutput) Connect() error {\n\treturn nil\n}\n\nfunc (*testOutput) Close() error {\n\treturn nil\n}\n\nfunc (*testOutput) Description() string {\n\treturn \"\"\n}\n\nfunc (*testOutput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (t *testOutput) Write(_ []telegraf.Metric) error {\n\tif t.failWrite {\n\t\treturn errors.New(\"failed write\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/cloud_pubsub_push/sample.conf",
    "content": "# Google Cloud Pub/Sub Push HTTP listener\n[[inputs.cloud_pubsub_push]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8080\"\n\n  ## Application secret to verify messages originate from Cloud Pub/Sub\n  # token = \"\"\n\n  ## Path to listen to.\n  # path = \"/\"\n\n  ## Maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## Maximum duration before timing out write of the response. This should be\n  ## set to a value large enough that you can send at least 'metric_batch_size'\n  ## number of messages within the duration.\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,00 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Whether to add the pubsub metadata, such as message attributes and\n  ## subscription as a tag.\n  # add_meta = false\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/cloudwatch/README.md",
    "content": "# Amazon CloudWatch Statistics Input Plugin\n\nThis plugin will gather metric statistics from [Amazon CloudWatch][cloudwatch].\n\n⭐ Telegraf v0.12.1\n🏷️ cloud\n💻 all\n\n[cloudwatch]: https://aws.amazon.com/cloudwatch\n\n## Amazon Authentication\n\nThis plugin uses a credential chain for Authentication with the CloudWatch\nAPI endpoint. In the following order the plugin will attempt to authenticate.\n\n1. Assumed credentials via STS if `role_arn` attribute is specified\n   (source credentials are evaluated from subsequent rules)\n2. Explicit credentials from `access_key`, `secret_key`, and `token` attributes\n3. Shared profile from `profile` attribute\n4. [Environment Variables][env]\n5. [Shared Credentials][credentials]\n6. [EC2 Instance Profile][iam-roles]\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Pull Metric Statistics from Amazon CloudWatch\n[[inputs.cloudwatch]]\n  ## Amazon Region\n  region = \"us-east-1\"\n\n  ## Amazon Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Web identity provider credentials via STS if role_arn and\n  ##    web_identity_token_file are specified\n  ## 2) Assumed credentials via STS if role_arn is specified\n  ## 3) explicit credentials from 'access_key' and 'secret_key'\n  ## 4) shared profile from 'profile'\n  ## 5) environment variables\n  ## 6) shared credentials file\n  ## 7) EC2 Instance Profile\n  # access_key = \"\"\n  # secret_key = \"\"\n  # token = \"\"\n  # role_arn = \"\"\n  # web_identity_token_file = \"\"\n  # role_session_name = \"\"\n  # profile = \"\"\n  # shared_credential_file = \"\"\n\n  ## If you are using CloudWatch cross-account observability, you can\n  ## set IncludeLinkedAccounts to true in a monitoring account\n  ## and collect metrics from the linked source accounts\n  # include_linked_accounts = false\n\n  ## Endpoint to make request against, the correct endpoint is automatically\n  ## determined and this option should only be set if you wish to override the\n  ## default.\n  ##   ex: endpoint_url = \"http://localhost:8000\"\n  # endpoint_url = \"\"\n\n  ## Set http_proxy\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## The minimum period for Cloudwatch metrics is 1 minute (60s). However not\n  ## all metrics are made available to the 1 minute period. Some are collected\n  ## at 3 minute, 5 minute, or larger intervals.\n  ## See https://aws.amazon.com/cloudwatch/faqs/#monitoring.\n  ## Note that if a period is configured that is smaller than the minimum for a\n  ## particular metric, that metric will not be returned by the Cloudwatch API\n  ## and will not be collected by Telegraf.\n  #\n  ## Requested CloudWatch aggregation Period (required)\n  ## Must be a multiple of 60s.\n  period = \"5m\"\n\n  ## Collection Delay (required)\n  ## Must account for metrics availability via CloudWatch API\n  delay = \"5m\"\n\n  ## Recommended: use metric 'interval' that is a multiple of 'period' to avoid\n  ## gaps or overlap in pulled data\n  interval = \"5m\"\n\n  ## Recommended if \"delay\" and \"period\" are both within 3 hours of request\n  ## time. Invalid values will be ignored. Recently Active feature will only\n  ## poll for CloudWatch ListMetrics values that occurred within the last 3h.\n  ## If enabled, it will reduce total API usage of the CloudWatch ListMetrics\n  ## API and require less memory to retain.\n  ## Do not enable if \"period\" or \"delay\" is longer than 3 hours, as it will\n  ## not return data more than 3 hours old.\n  ## See https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html\n  # recently_active = \"PT3H\"\n\n  ## Configure the TTL for the internal cache of metrics.\n  # cache_ttl = \"1h\"\n\n  ## Metric Statistic Namespaces, wildcards are allowed\n  # namespaces = [\"*\"]\n\n  ## Metric Format\n  ## This determines the format of the produces metrics. 'sparse', the default\n  ## will produce a unique field for each statistic. 'dense' will report all\n  ## statistics will be in a field called value and have a metric_name tag\n  ## defining the name of the statistic. See the plugin README for examples.\n  # metric_format = \"sparse\"\n\n  ## Maximum requests per second. Note that the global default AWS rate limit\n  ## is 50 reqs/sec, so if you define multiple namespaces, these should add up\n  ## to a maximum of 50.\n  ## See http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_limits.html\n  # ratelimit = 25\n\n  ## Timeout for http requests made by the cloudwatch client.\n  # timeout = \"5s\"\n\n  ## Batch Size\n  ## The size of each batch to send requests to Cloudwatch. 500 is the\n  ## suggested largest size. If a request gets to large (413 errors), consider\n  ## reducing this amount.\n  # batch_size = 500\n\n  ## Namespace-wide statistic filters. These allow fewer queries to be made to\n  ## cloudwatch.\n  # statistic_include = [\"average\", \"sum\", \"minimum\", \"maximum\", sample_count\"]\n  # statistic_exclude = []\n\n  ## Metrics to Pull\n  ## Defaults to all Metrics in Namespace if nothing is provided\n  ## Refreshes Namespace available metrics every 1h\n  #[[inputs.cloudwatch.metrics]]\n  #  names = [\"Latency\", \"RequestCount\"]\n  #\n  #  ## Statistic filters for Metric.  These allow for retrieving specific\n  #  ## statistics for an individual metric.\n  #  # statistic_include = [\"average\", \"sum\", \"minimum\", \"maximum\", sample_count\"]\n  #  # statistic_exclude = []\n  #\n  #  ## Dimension filters for Metric.\n  #  ## All dimensions defined for the metric names must be specified in order\n  #  ## to retrieve the metric statistics.\n  #  ## 'value' has wildcard / 'glob' matching support such as 'p-*'.\n  #  [[inputs.cloudwatch.metrics.dimensions]]\n  #    name = \"LoadBalancerName\"\n  #    value = \"p-example\"\n```\n\nPlease note, the `namespace` option is deprecated in favor of the `namespaces`\nlist option.\n\n## Requirements and Terminology\n\nPlugin Configuration utilizes [CloudWatch concepts][concept] and access\npattern to allow monitoring of any CloudWatch Metric.\n\n- `region` must be a valid AWS [region][] value\n- `period` must be a valid CloudWatch [period][] value\n- `namespaces` must be a list of valid CloudWatch [namespace][] value(s)\n- `names` must be valid CloudWatch [metric][] names\n- `dimensions` must be valid CloudWatch [dimension][] name/value pairs\n\nOmitting or specifying a value of `'*'` for a dimension value configures all\navailable metrics that contain a dimension with the specified name to be\nretrieved. If specifying >1 dimension, then the metric must contain *all* the\nconfigured dimensions where the value of the wildcard dimension is ignored.\n\nExample:\n\n```toml\n[[inputs.cloudwatch]]\n  period = \"1m\"\n  interval = \"5m\"\n\n  [[inputs.cloudwatch.metrics]]\n    names = [\"Latency\"]\n\n    ## Dimension filters for Metric (optional)\n    [[inputs.cloudwatch.metrics.dimensions]]\n      name = \"LoadBalancerName\"\n      value = \"p-example\"\n\n    [[inputs.cloudwatch.metrics.dimensions]]\n      name = \"AvailabilityZone\"\n      value = \"*\"\n```\n\nIf the following ELBs are available:\n\n- name: `p-example`, availabilityZone: `us-east-1a`\n- name: `p-example`, availabilityZone: `us-east-1b`\n- name: `q-example`, availabilityZone: `us-east-1a`\n- name: `q-example`, availabilityZone: `us-east-1b`\n\nThen 2 metrics will be output:\n\n- name: `p-example`, availabilityZone: `us-east-1a`\n- name: `p-example`, availabilityZone: `us-east-1b`\n\nIf the `AvailabilityZone` wildcard dimension was omitted, then a single metric\n(name: `p-example`) would be exported containing the aggregate values of the ELB\nacross availability zones.\n\nTo maximize efficiency and savings, consider making fewer requests by increasing\n`interval` but keeping `period` at the duration you would like metrics to be\nreported. The above example will request metrics from Cloudwatch every 5 minutes\nbut will output five metrics timestamped one minute apart.\n\n## Restrictions and Limitations\n\n- CloudWatch metrics are not available instantly via the CloudWatch API.\n  You should adjust your collection `delay` to account for this lag in metrics\n  availability based on your [monitoring subscription level][using]\n- CloudWatch API usage incurs cost - see [GetMetricData Pricing][pricing]\n\n## Metrics\n\nEach CloudWatch Namespace monitored records a measurement with fields for each\navailable Metric Statistic. Namespace and Metrics are represented in [snake\ncase](https://en.wikipedia.org/wiki/Snake_case)\n\n### Sparse Metrics\n\nBy default, metrics generated by this plugin are sparse. Use the `metric_format`\noption to override this setting.\n\nSparse metrics produce a set of fields for every AWS Metric.\n\n- cloudwatch_{namespace}\n  - Fields\n    - {metric}_sum         (metric Sum value)\n    - {metric}_average     (metric Average value)\n    - {metric}_minimum     (metric Minimum value)\n    - {metric}_maximum     (metric Maximum value)\n    - {metric}_sample_count (metric SampleCount value)\n\nFor example:\n\n```text\ncloudwatch_aws_usage,class=None,resource=GetSecretValue,service=Secrets\\ Manager,type=API call_count_maximum=1,call_count_minimum=1,call_count_sum=8,call_count_sample_count=8,call_count_average=1 1715097720000000000\n```\n\n### Dense Metrics\n\nDense metrics are generated when `metric_format` is set to `dense`.\n\nDense metrics use the same fields over and over for every AWS Metric and\ndifferentiate between AWS Metrics using a tag called `metric_name` with the AWS\nMetric name:\n\n- cloudwatch_{namespace}\n  - Tags\n    - metric_name (AWS Metric name)\n  - Fields\n    - sum         (metric Sum value)\n    - average     (metric Average value)\n    - minimum     (metric Minimum value)\n    - maximum     (metric Maximum value)\n    - sample_count (metric SampleCount value)\n\nFor example:\n\n```text\ncloudwatch_aws_usage,class=None,resource=GetSecretValue,service=Secrets\\ Manager,metric_name=call_count,type=API sum=6,sample_count=6,average=1,maximum=1,minimum=1 1715097840000000000\n```\n\n### Tags\n\nEach measurement is tagged with the following identifiers to uniquely identify\nthe associated metric Tag Dimension names are represented in [snake\ncase](https://en.wikipedia.org/wiki/Snake_case)\n\n- All measurements have the following tags:\n  - region           (CloudWatch Region)\n  - {dimension-name} (Cloudwatch Dimension value - one per metric dimension)\n- If `include_linked_accounts` is set to true then below tag is also provided:\n  - account           (The ID of the account where the metrics are located.)\n\n## Troubleshooting\n\nYou can use the aws cli to get a list of available metrics and dimensions:\n\n```shell\naws cloudwatch list-metrics --namespace AWS/EC2 --region us-east-1\naws cloudwatch list-metrics --namespace AWS/EC2 --region us-east-1 --metric-name CPUCreditBalance\n```\n\nIf the expected metrics are not returned, you can try getting them manually\nfor a short period of time:\n\n```shell\naws cloudwatch get-metric-data \\\n  --start-time 2018-07-01T00:00:00Z \\\n  --end-time 2018-07-01T00:15:00Z \\\n  --metric-data-queries '[\n  {\n    \"Id\": \"avgCPUCreditBalance\",\n    \"MetricStat\": {\n      \"Metric\": {\n        \"Namespace\": \"AWS/EC2\",\n        \"MetricName\": \"CPUCreditBalance\",\n        \"Dimensions\": [\n          {\n            \"Name\": \"InstanceId\",\n            \"Value\": \"i-deadbeef\"\n          }\n        ]\n      },\n      \"Period\": 300,\n      \"Stat\": \"Average\"\n    },\n    \"Label\": \"avgCPUCreditBalance\"\n  }\n]'\n```\n\n## Example Output\n\nSee the discussion above about sparse vs dense metrics for more details.\n\n```text\ncloudwatch_aws_elb,load_balancer_name=p-example,region=us-east-1 latency_average=0.004810798017284538,latency_maximum=0.1100282669067383,latency_minimum=0.0006084442138671875,latency_sample_count=4029,latency_sum=19.382705211639404 1459542420000000000\n```\n\n[concept]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html\n[credentials]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#shared-credentials-file\n[dimension]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#Dimension\n[env]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#environment-variables\n[iam-roles]: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html\n[metric]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#Metric\n[namespace]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#Namespace\n[period]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#CloudWatchPeriods\n[pricing]: https://aws.amazon.com/cloudwatch/pricing/\n[region]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#CloudWatchRegions\n[using]: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html\n"
  },
  {
    "path": "plugins/inputs/cloudwatch/cloudwatch.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cloudwatch\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/service/cloudwatch\"\n\t\"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/limiter\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_aws \"github.com/influxdata/telegraf/plugins/common/aws\"\n\t\"github.com/influxdata/telegraf/plugins/common/proxy\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CloudWatch struct {\n\tStatisticExclude []string        `toml:\"statistic_exclude\"`\n\tStatisticInclude []string        `toml:\"statistic_include\"`\n\tTimeout          config.Duration `toml:\"timeout\"`\n\n\tproxy.HTTPProxy\n\n\tPeriod                config.Duration     `toml:\"period\"`\n\tDelay                 config.Duration     `toml:\"delay\"`\n\tNamespaces            []string            `toml:\"namespaces\"`\n\tMetrics               []*cloudwatchMetric `toml:\"metrics\"`\n\tCacheTTL              config.Duration     `toml:\"cache_ttl\"`\n\tRateLimit             int                 `toml:\"ratelimit\"`\n\tRecentlyActive        string              `toml:\"recently_active\"`\n\tBatchSize             int                 `toml:\"batch_size\"`\n\tIncludeLinkedAccounts bool                `toml:\"include_linked_accounts\"`\n\tMetricFormat          string              `toml:\"metric_format\"`\n\tLog                   telegraf.Logger     `toml:\"-\"`\n\tcommon_aws.CredentialConfig\n\n\tclient          cloudwatchClient\n\tnsFilter        filter.Filter\n\tstatFilter      filter.Filter\n\tcache           *metricCache\n\tqueryDimensions map[string]*map[string]string\n\twindowStart     time.Time\n\twindowEnd       time.Time\n}\n\ntype cloudwatchMetric struct {\n\tMetricNames      []string     `toml:\"names\"`\n\tDimensions       []*dimension `toml:\"dimensions\"`\n\tStatisticExclude *[]string    `toml:\"statistic_exclude\"`\n\tStatisticInclude *[]string    `toml:\"statistic_include\"`\n}\n\ntype dimension struct {\n\tName         string `toml:\"name\"`\n\tValue        string `toml:\"value\"`\n\tvalueMatcher filter.Filter\n}\n\ntype metricCache struct {\n\tttl     time.Duration\n\tbuilt   time.Time\n\tmetrics []filteredMetric\n\tqueries map[string][]types.MetricDataQuery\n}\n\ntype filteredMetric struct {\n\tmetrics    []types.Metric\n\taccounts   []string\n\tstatFilter filter.Filter\n}\n\ntype cloudwatchClient interface {\n\tListMetrics(context.Context, *cloudwatch.ListMetricsInput, ...func(*cloudwatch.Options)) (*cloudwatch.ListMetricsOutput, error)\n\tGetMetricData(context.Context, *cloudwatch.GetMetricDataInput, ...func(*cloudwatch.Options)) (*cloudwatch.GetMetricDataOutput, error)\n}\n\nfunc (*CloudWatch) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *CloudWatch) Init() error {\n\t// Check user settings\n\tswitch c.MetricFormat {\n\tcase \"\":\n\t\tc.MetricFormat = \"sparse\"\n\tcase \"dense\", \"sparse\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid metric_format: %s\", c.MetricFormat)\n\t}\n\n\t// Setup the cloudwatch client\n\tproxyFunc, err := c.HTTPProxy.Proxy()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating proxy failed: %w\", err)\n\t}\n\n\tcreds, err := c.CredentialConfig.Credentials()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting credentials failed: %w\", err)\n\t}\n\n\tc.client = cloudwatch.NewFromConfig(creds, func(options *cloudwatch.Options) {\n\t\tif c.CredentialConfig.EndpointURL != \"\" && c.CredentialConfig.Region != \"\" {\n\t\t\toptions.BaseEndpoint = &c.CredentialConfig.EndpointURL\n\t\t}\n\n\t\toptions.ClientLogMode = 0\n\t\toptions.HTTPClient = &http.Client{\n\t\t\t// use values from DefaultTransport\n\t\t\tTransport: &http.Transport{\n\t\t\t\tProxy: proxyFunc,\n\t\t\t\tDialContext: (&net.Dialer{\n\t\t\t\t\tTimeout:   30 * time.Second,\n\t\t\t\t\tKeepAlive: 30 * time.Second,\n\t\t\t\t\tDualStack: true,\n\t\t\t\t}).DialContext,\n\t\t\t\tMaxIdleConns:          100,\n\t\t\t\tIdleConnTimeout:       90 * time.Second,\n\t\t\t\tTLSHandshakeTimeout:   10 * time.Second,\n\t\t\t\tExpectContinueTimeout: 1 * time.Second,\n\t\t\t},\n\t\t\tTimeout: time.Duration(c.Timeout),\n\t\t}\n\t})\n\n\tfor _, m := range c.Metrics {\n\t\t// Sort the metrics for efficient comparison later\n\t\tslices.SortStableFunc(m.Dimensions, func(a, b *dimension) int {\n\t\t\treturn strings.Compare(a.Name, b.Name)\n\t\t})\n\t\t// Initialize filter for metric dimensions to include\n\t\tfor _, dimension := range m.Dimensions {\n\t\t\tmatcher, err := filter.NewIncludeExcludeFilter([]string{dimension.Value}, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"creating dimension filter for dimension %q failed: %w\", dimension, err)\n\t\t\t}\n\t\t\tdimension.valueMatcher = matcher\n\t\t}\n\t}\n\n\t// Initialize statistics-type filter\n\tc.statFilter, err = filter.NewIncludeExcludeFilter(c.StatisticInclude, c.StatisticExclude)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating statistics filter failed: %w\", err)\n\t}\n\n\t// Initialize namespace filter\n\tc.nsFilter, err = filter.Compile(c.Namespaces)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating namespace filter failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *CloudWatch) Gather(acc telegraf.Accumulator) error {\n\tfilteredMetrics, err := c.getFilteredMetrics()\n\tif err != nil {\n\t\treturn err\n\t}\n\tc.updateWindow(time.Now())\n\n\t// Get all of the possible queries so we can send groups of 100.\n\tqueries := c.getDataQueries(filteredMetrics)\n\tif len(queries) == 0 {\n\t\treturn nil\n\t}\n\n\t// Limit concurrency or we can easily exhaust user connection limit.\n\t// See cloudwatch API request limits:\n\t// http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_limits.html\n\tlmtr := limiter.NewRateLimiter(c.RateLimit, time.Second)\n\tdefer lmtr.Stop()\n\twg := sync.WaitGroup{}\n\trLock := sync.Mutex{}\n\n\tresults := make(map[string][]types.MetricDataResult)\n\tfor namespace, namespacedQueries := range queries {\n\t\tvar batches [][]types.MetricDataQuery\n\n\t\tfor c.BatchSize < len(namespacedQueries) {\n\t\t\tnamespacedQueries, batches = namespacedQueries[c.BatchSize:], append(batches, namespacedQueries[0:c.BatchSize:c.BatchSize])\n\t\t}\n\t\tbatches = append(batches, namespacedQueries)\n\n\t\tfor i := range batches {\n\t\t\twg.Add(1)\n\t\t\t<-lmtr.C\n\t\t\tgo func(n string, inm []types.MetricDataQuery) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tresult, err := c.gatherMetrics(inm)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\trLock.Lock()\n\t\t\t\tresults[n] = append(results[n], result...)\n\t\t\t\trLock.Unlock()\n\t\t\t}(namespace, batches[i])\n\t\t}\n\t}\n\n\twg.Wait()\n\tc.aggregateMetrics(acc, results)\n\treturn nil\n}\n\nfunc (c *CloudWatch) getFilteredMetrics() ([]filteredMetric, error) {\n\tif c.cache != nil && c.cache.metrics != nil && time.Since(c.cache.built) < c.cache.ttl {\n\t\treturn c.cache.metrics, nil\n\t}\n\n\t// Get all metrics from cloudwatch for filtering\n\tparams := &cloudwatch.ListMetricsInput{\n\t\tIncludeLinkedAccounts: &c.IncludeLinkedAccounts,\n\t}\n\tif c.RecentlyActive == \"PT3H\" {\n\t\tparams.RecentlyActive = types.RecentlyActivePt3h\n\t}\n\n\t// Return the subset of metrics matching the namespace and at one of the\n\t// metric definitions if any\n\tvar metrics []types.Metric\n\tvar accounts []string\n\tfor {\n\t\tresp, err := c.client.ListMetrics(context.Background(), params)\n\t\tif err != nil {\n\t\t\tc.Log.Errorf(\"failed to list metrics: %v\", err)\n\t\t\tbreak\n\t\t}\n\t\tc.Log.Tracef(\"got %d metrics with %d accounts\", len(resp.Metrics), len(resp.OwningAccounts))\n\t\tfor i, m := range resp.Metrics {\n\t\t\tif c.Log.Level().Includes(telegraf.Trace) {\n\t\t\t\tdims := make([]string, 0, len(m.Dimensions))\n\t\t\t\tfor _, d := range m.Dimensions {\n\t\t\t\t\tdims = append(dims, *d.Name+\"=\"+*d.Value)\n\t\t\t\t}\n\t\t\t\ta := \"none\"\n\t\t\t\tif len(resp.OwningAccounts) > 0 {\n\t\t\t\t\ta = resp.OwningAccounts[i]\n\t\t\t\t}\n\t\t\t\tc.Log.Tracef(\"  metric %3d: %s (%s): %s [%s]\\n\", i, *m.MetricName, *m.Namespace, strings.Join(dims, \", \"), a)\n\t\t\t}\n\n\t\t\tif c.nsFilter != nil && !c.nsFilter.Match(*m.Namespace) {\n\t\t\t\tc.Log.Trace(\"  -> rejected by namespace\")\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif len(c.Metrics) > 0 && !slices.ContainsFunc(c.Metrics, func(cm *cloudwatchMetric) bool {\n\t\t\t\treturn metricMatch(cm, m)\n\t\t\t}) {\n\t\t\t\tc.Log.Trace(\"  -> rejected by metric mismatch\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.Log.Trace(\"  -> keeping metric\")\n\n\t\t\tmetrics = append(metrics, m)\n\t\t\tif len(resp.OwningAccounts) > 0 {\n\t\t\t\taccounts = append(accounts, resp.OwningAccounts[i])\n\t\t\t}\n\t\t}\n\n\t\tif resp.NextToken == nil {\n\t\t\tbreak\n\t\t}\n\t\tparams.NextToken = resp.NextToken\n\t}\n\n\tvar filtered []filteredMetric\n\tif len(c.Metrics) == 0 {\n\t\tfiltered = append(filtered, filteredMetric{\n\t\t\tmetrics:    metrics,\n\t\t\taccounts:   accounts,\n\t\t\tstatFilter: c.statFilter,\n\t\t})\n\t} else {\n\t\tfor idx, cm := range c.Metrics {\n\t\t\tvar entry filteredMetric\n\t\t\tif cm.StatisticInclude == nil && cm.StatisticExclude == nil {\n\t\t\t\tentry.statFilter = c.statFilter\n\t\t\t} else {\n\t\t\t\tvar includeStats, excludeStats []string\n\t\t\t\tif cm.StatisticInclude != nil {\n\t\t\t\t\tincludeStats = *cm.StatisticInclude\n\t\t\t\t}\n\t\t\t\tif cm.StatisticExclude != nil {\n\t\t\t\t\texcludeStats = *cm.StatisticExclude\n\t\t\t\t}\n\t\t\t\tf, err := filter.NewIncludeExcludeFilter(includeStats, excludeStats)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"creating statistics filter for metric %d failed: %w\", idx+1, err)\n\t\t\t\t}\n\t\t\t\tentry.statFilter = f\n\t\t\t}\n\n\t\t\tfor i, m := range metrics {\n\t\t\t\tif metricMatch(cm, m) {\n\t\t\t\t\tentry.metrics = append(entry.metrics, m)\n\t\t\t\t\tif len(accounts) > 0 {\n\t\t\t\t\t\tentry.accounts = append(entry.accounts, accounts[i])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiltered = append(filtered, entry)\n\t\t}\n\t}\n\n\tc.cache = &metricCache{\n\t\tmetrics: filtered,\n\t\tbuilt:   time.Now(),\n\t\tttl:     time.Duration(c.CacheTTL),\n\t}\n\n\treturn filtered, nil\n}\n\nfunc (c *CloudWatch) updateWindow(relativeTo time.Time) {\n\twindowEnd := relativeTo.Add(-time.Duration(c.Delay))\n\n\tif c.windowEnd.IsZero() {\n\t\t// this is the first run, no window info, so just get a single period\n\t\tc.windowStart = windowEnd.Add(-time.Duration(c.Period))\n\t} else {\n\t\t// subsequent window, start where last window left off\n\t\tc.windowStart = c.windowEnd\n\t}\n\n\tc.windowEnd = windowEnd\n}\n\n// getDataQueries gets all of the possible queries so we can maximize the request payload.\nfunc (c *CloudWatch) getDataQueries(filteredMetrics []filteredMetric) map[string][]types.MetricDataQuery {\n\tif c.cache != nil && c.cache.queries != nil && c.cache.metrics != nil && time.Since(c.cache.built) < c.cache.ttl {\n\t\treturn c.cache.queries\n\t}\n\n\tc.queryDimensions = make(map[string]*map[string]string)\n\tdataQueries := make(map[string][]types.MetricDataQuery)\n\tfor i, filtered := range filteredMetrics {\n\t\tfor j, singleMetric := range filtered.metrics {\n\t\t\tid := strconv.Itoa(j) + \"_\" + strconv.Itoa(i)\n\t\t\tdimension := ctod(singleMetric.Dimensions)\n\t\t\tvar accountID *string\n\t\t\tif c.IncludeLinkedAccounts && len(filtered.accounts) > j {\n\t\t\t\taccountID = aws.String(filtered.accounts[j])\n\t\t\t\t(*dimension)[\"account\"] = filtered.accounts[j]\n\t\t\t}\n\n\t\t\tstatisticTypes := map[string]string{\n\t\t\t\t\"average\":      \"Average\",\n\t\t\t\t\"maximum\":      \"Maximum\",\n\t\t\t\t\"minimum\":      \"Minimum\",\n\t\t\t\t\"sum\":          \"Sum\",\n\t\t\t\t\"sample_count\": \"SampleCount\",\n\t\t\t}\n\n\t\t\tfor statisticType, statistic := range statisticTypes {\n\t\t\t\tif !filtered.statFilter.Match(statisticType) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tqueryID := statisticType + \"_\" + id\n\t\t\t\tc.queryDimensions[queryID] = dimension\n\t\t\t\tdataQueries[*singleMetric.Namespace] = append(dataQueries[*singleMetric.Namespace], types.MetricDataQuery{\n\t\t\t\t\tId:        aws.String(queryID),\n\t\t\t\t\tAccountId: accountID,\n\t\t\t\t\tLabel:     aws.String(snakeCase(*singleMetric.MetricName + \"_\" + statisticType)),\n\t\t\t\t\tMetricStat: &types.MetricStat{\n\t\t\t\t\t\tMetric: &filtered.metrics[j],\n\t\t\t\t\t\tPeriod: aws.Int32(int32(time.Duration(c.Period).Seconds())),\n\t\t\t\t\t\tStat:   aws.String(statistic),\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(dataQueries) == 0 {\n\t\tc.Log.Debug(\"no metrics found to collect\")\n\t\treturn nil\n\t}\n\n\tif c.cache == nil {\n\t\tc.cache = &metricCache{\n\t\t\tqueries: dataQueries,\n\t\t\tbuilt:   time.Now(),\n\t\t\tttl:     time.Duration(c.CacheTTL),\n\t\t}\n\t} else {\n\t\tc.cache.queries = dataQueries\n\t}\n\n\treturn dataQueries\n}\n\nfunc (c *CloudWatch) gatherMetrics(queries []types.MetricDataQuery) ([]types.MetricDataResult, error) {\n\tparams := &cloudwatch.GetMetricDataInput{\n\t\tStartTime:         aws.Time(c.windowStart),\n\t\tEndTime:           aws.Time(c.windowEnd),\n\t\tMetricDataQueries: queries,\n\t}\n\n\tresults := make([]types.MetricDataResult, 0)\n\tfor {\n\t\tresp, err := c.client.GetMetricData(context.Background(), params)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get metric data: %w\", err)\n\t\t}\n\n\t\tresults = append(results, resp.MetricDataResults...)\n\t\tif resp.NextToken == nil {\n\t\t\tbreak\n\t\t}\n\t\tparams.NextToken = resp.NextToken\n\t}\n\n\treturn results, nil\n}\n\nfunc (c *CloudWatch) aggregateMetrics(acc telegraf.Accumulator, metricDataResults map[string][]types.MetricDataResult) {\n\tgrouper := metric.NewSeriesGrouper()\n\tfor namespace, results := range metricDataResults {\n\t\tnamespace = sanitizeMeasurement(namespace)\n\n\t\tfor _, result := range results {\n\t\t\ttags := make(map[string]string)\n\t\t\tif dimensions, ok := c.queryDimensions[*result.Id]; ok {\n\t\t\t\ttags = *dimensions\n\t\t\t}\n\t\t\ttags[\"region\"] = c.Region\n\n\t\t\tfor i := range result.Values {\n\t\t\t\tif c.MetricFormat == \"dense\" {\n\t\t\t\t\t// Remove the IDs from the result ID to get the statistic type\n\t\t\t\t\t// e.g. \"average\" from \"average_0_0\"\n\t\t\t\t\tre := regexp.MustCompile(`_\\d+_\\d+$`)\n\t\t\t\t\tstatisticType := re.ReplaceAllString(*result.Id, \"\")\n\n\t\t\t\t\t// Remove the statistic type from the label to get the AWS Metric name\n\t\t\t\t\t// e.g. \"CPUUtilization\" from \"CPUUtilization_average\"\n\t\t\t\t\tre = regexp.MustCompile(`_?` + regexp.QuoteMeta(statisticType) + `$`)\n\t\t\t\t\ttags[\"metric_name\"] = re.ReplaceAllString(*result.Label, \"\")\n\n\t\t\t\t\tgrouper.Add(namespace, tags, result.Timestamps[i], statisticType, result.Values[i])\n\t\t\t\t} else {\n\t\t\t\t\tgrouper.Add(namespace, tags, result.Timestamps[i], *result.Label, result.Values[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, singleMetric := range grouper.Metrics() {\n\t\tacc.AddMetric(singleMetric)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"cloudwatch\", func() telegraf.Input {\n\t\treturn &CloudWatch{\n\t\t\tCacheTTL:  config.Duration(time.Hour),\n\t\t\tRateLimit: 25,\n\t\t\tTimeout:   config.Duration(time.Second * 5),\n\t\t\tBatchSize: 500,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cloudwatch/cloudwatch_test.go",
    "content": "package cloudwatch\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/service/cloudwatch\"\n\t\"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_aws \"github.com/influxdata/telegraf/plugins/common/aws\"\n\t\"github.com/influxdata/telegraf/plugins/common/proxy\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSnakeCase(t *testing.T) {\n\trequire.Equal(t, \"cluster_name\", snakeCase(\"Cluster Name\"))\n\trequire.Equal(t, \"broker_id\", snakeCase(\"Broker ID\"))\n}\n\nfunc TestGather(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces: []string{\"AWS/ELB\"},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tRateLimit:  200,\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = defaultMockClient(\"AWS/ELB\")\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          123.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          124.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherDenseMetric(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces:   []string{\"AWS/ELB\"},\n\t\tDelay:        config.Duration(1 * time.Minute),\n\t\tPeriod:       config.Duration(1 * time.Minute),\n\t\tRateLimit:    200,\n\t\tBatchSize:    500,\n\t\tMetricFormat: \"dense\",\n\t\tLog:          testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = defaultMockClient(\"AWS/ELB\")\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example1\",\n\t\t\t\t\"metric_name\":        \"latency\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"minimum\":      0.1,\n\t\t\t\t\"maximum\":      0.3,\n\t\t\t\t\"average\":      0.2,\n\t\t\t\t\"sum\":          123.0,\n\t\t\t\t\"sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example2\",\n\t\t\t\t\"metric_name\":        \"latency\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"minimum\":      0.1,\n\t\t\t\t\"maximum\":      0.3,\n\t\t\t\t\"average\":      0.2,\n\t\t\t\t\"sum\":          124.0,\n\t\t\t\t\"sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestMultiAccountGather(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces:            []string{\"AWS/ELB\"},\n\t\tDelay:                 config.Duration(1 * time.Minute),\n\t\tPeriod:                config.Duration(1 * time.Minute),\n\t\tRateLimit:             200,\n\t\tBatchSize:             500,\n\t\tLog:                   testutil.Logger{},\n\t\tIncludeLinkedAccounts: true,\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = defaultMockClient(\"AWS/ELB\")\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example1\",\n\t\t\t\t\"account\":            \"123456789012\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          123.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example2\",\n\t\t\t\t\"account\":            \"923456789017\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          124.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherMultipleNamespaces(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces: []string{\"AWS/ELB\", \"AWS/EC2\"},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tRateLimit:  200,\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = defaultMockClient(\"AWS/ELB\", \"AWS/EC2\")\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          123.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_elb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          124.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_ec2\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          123.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"cloudwatch_aws_ec2\",\n\t\t\tmap[string]string{\n\t\t\t\t\"region\":             \"us-east-1\",\n\t\t\t\t\"load_balancer_name\": \"p-example2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"latency_minimum\":      0.1,\n\t\t\t\t\"latency_maximum\":      0.3,\n\t\t\t\t\"latency_average\":      0.2,\n\t\t\t\t\"latency_sum\":          124.0,\n\t\t\t\t\"latency_sample_count\": 100.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\toption := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.SortMetrics(),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), option...)\n}\n\nfunc TestSelectMetrics(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces: []string{\"AWS/ELB\"},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tRateLimit:  200,\n\t\tBatchSize:  500,\n\t\tMetrics: []*cloudwatchMetric{\n\t\t\t{\n\t\t\t\tMetricNames: []string{\"Latency\", \"RequestCount\"},\n\t\t\t\tDimensions: []*dimension{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"LoadBalancerName\",\n\t\t\t\t\t\tValue: \"lb*\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"AvailabilityZone\",\n\t\t\t\t\t\tValue: \"us-east*\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = selectedMockClient()\n\tfiltered, err := plugin.getFilteredMetrics()\n\trequire.NoError(t, err)\n\n\t// We've asked for 2 (out of 4) metrics, over all 3 load balancers in all 2\n\t// AZs. We should get 12 metrics.\n\trequire.Len(t, filtered[0].metrics, 12)\n}\n\nfunc TestSelectMetricsSummaryOnly(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tCredentialConfig: common_aws.CredentialConfig{\n\t\t\tRegion: \"us-east-1\",\n\t\t},\n\t\tNamespaces: []string{\"AWS/ELB\"},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tRateLimit:  200,\n\t\tBatchSize:  500,\n\t\tMetrics: []*cloudwatchMetric{\n\t\t\t{\n\t\t\t\tMetricNames: []string{\"Latency\", \"RequestCount\"},\n\t\t\t\tDimensions: []*dimension{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"LoadBalancerName\",\n\t\t\t\t\t\tValue: \"lb*\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.client = selectedMockClient()\n\tfiltered, err := plugin.getFilteredMetrics()\n\trequire.NoError(t, err)\n\n\t// We've asked for the non-AU specific metrics only so this should be\n\t// 2 (out of 4) metrics for all 3 load balancers but no AZ.\n\trequire.Len(t, filtered[0].metrics, 6)\n}\n\nfunc TestGenerateStatisticsInputParams(t *testing.T) {\n\td := types.Dimension{\n\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\tValue: aws.String(\"p-example\"),\n\t}\n\n\tnamespace := \"AWS/ELB\"\n\tm := types.Metric{\n\t\tMetricName: aws.String(\"Latency\"),\n\t\tDimensions: []types.Dimension{d},\n\t\tNamespace:  aws.String(namespace),\n\t}\n\n\tplugin := &CloudWatch{\n\t\tNamespaces: []string{namespace},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tnow := time.Now()\n\n\tplugin.updateWindow(now)\n\n\tstatFilter, err := filter.NewIncludeExcludeFilter(nil, nil)\n\trequire.NoError(t, err)\n\tqueries := plugin.getDataQueries([]filteredMetric{{metrics: []types.Metric{m}, statFilter: statFilter}})\n\tparams := &cloudwatch.GetMetricDataInput{\n\t\tStartTime:         aws.Time(plugin.windowStart),\n\t\tEndTime:           aws.Time(plugin.windowEnd),\n\t\tMetricDataQueries: queries[namespace],\n\t}\n\n\trequire.EqualValues(t, *params.EndTime, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, *params.StartTime, now.Add(-time.Duration(plugin.Period)).Add(-time.Duration(plugin.Delay)))\n\trequire.Len(t, params.MetricDataQueries, 5)\n\trequire.Len(t, params.MetricDataQueries[0].MetricStat.Metric.Dimensions, 1)\n\trequire.EqualValues(t, 60, *params.MetricDataQueries[0].MetricStat.Period)\n}\n\nfunc TestGenerateStatisticsInputParamsFiltered(t *testing.T) {\n\td := types.Dimension{\n\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\tValue: aws.String(\"p-example\"),\n\t}\n\n\tnamespace := \"AWS/ELB\"\n\tm := types.Metric{\n\t\tMetricName: aws.String(\"Latency\"),\n\t\tDimensions: []types.Dimension{d},\n\t\tNamespace:  aws.String(namespace),\n\t}\n\n\tplugin := &CloudWatch{\n\t\tNamespaces: []string{namespace},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tnow := time.Now()\n\n\tplugin.updateWindow(now)\n\n\tstatFilter, err := filter.NewIncludeExcludeFilter([]string{\"average\", \"sample_count\"}, nil)\n\trequire.NoError(t, err)\n\tqueries := plugin.getDataQueries([]filteredMetric{{metrics: []types.Metric{m}, statFilter: statFilter}})\n\tparams := &cloudwatch.GetMetricDataInput{\n\t\tStartTime:         aws.Time(plugin.windowStart),\n\t\tEndTime:           aws.Time(plugin.windowEnd),\n\t\tMetricDataQueries: queries[namespace],\n\t}\n\n\trequire.EqualValues(t, *params.EndTime, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, *params.StartTime, now.Add(-time.Duration(plugin.Period)).Add(-time.Duration(plugin.Delay)))\n\trequire.Len(t, params.MetricDataQueries, 2)\n\trequire.Len(t, params.MetricDataQueries[0].MetricStat.Metric.Dimensions, 1)\n\trequire.EqualValues(t, 60, *params.MetricDataQueries[0].MetricStat.Period)\n}\n\nfunc TestMetricsCacheTimeout(t *testing.T) {\n\tcache := &metricCache{\n\t\tmetrics: make([]filteredMetric, 0),\n\t\tbuilt:   time.Now(),\n\t\tttl:     time.Minute,\n\t}\n\n\trequire.True(t, cache.metrics != nil && time.Since(cache.built) < cache.ttl)\n\tcache.built = time.Now().Add(-time.Minute)\n\trequire.False(t, cache.metrics != nil && time.Since(cache.built) < cache.ttl)\n}\n\nfunc TestUpdateWindow(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tNamespaces: []string{\"AWS/ELB\"},\n\t\tDelay:      config.Duration(1 * time.Minute),\n\t\tPeriod:     config.Duration(1 * time.Minute),\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\n\tnow := time.Now()\n\n\trequire.True(t, plugin.windowEnd.IsZero())\n\trequire.True(t, plugin.windowStart.IsZero())\n\n\tplugin.updateWindow(now)\n\n\tnewStartTime := plugin.windowEnd\n\n\t// initial window just has a single period\n\trequire.EqualValues(t, plugin.windowEnd, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, plugin.windowStart, now.Add(-time.Duration(plugin.Delay)).Add(-time.Duration(plugin.Period)))\n\n\tnow = time.Now()\n\tplugin.updateWindow(now)\n\n\t// subsequent window uses previous end time as start time\n\trequire.EqualValues(t, plugin.windowEnd, now.Add(-time.Duration(plugin.Delay)))\n\trequire.EqualValues(t, plugin.windowStart, newStartTime)\n}\n\nfunc TestProxyFunction(t *testing.T) {\n\tproxyCfg := proxy.HTTPProxy{HTTPProxyURL: \"http://www.penguins.com\"}\n\n\tproxyFunction, err := proxyCfg.Proxy()\n\trequire.NoError(t, err)\n\n\tu, err := url.Parse(\"https://monitoring.us-west-1.amazonaws.com/\")\n\trequire.NoError(t, err)\n\n\tproxyResult, err := proxyFunction(&http.Request{URL: u})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"www.penguins.com\", proxyResult.Host)\n}\n\nfunc TestCombineNamespaces(t *testing.T) {\n\tplugin := &CloudWatch{\n\t\tNamespaces: []string{\"AWS/EC2\", \"AWS/Billing\"},\n\t\tBatchSize:  500,\n\t\tLog:        testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\trequire.Equal(t, []string{\"AWS/EC2\", \"AWS/Billing\"}, plugin.Namespaces)\n}\n\n// INTERNAL mock client implementation\ntype mockClient struct {\n\tmetrics []types.Metric\n}\n\nfunc defaultMockClient(namespaces ...string) *mockClient {\n\tc := &mockClient{\n\t\tmetrics: make([]types.Metric, 0, len(namespaces)),\n\t}\n\n\tfor _, namespace := range namespaces {\n\t\tc.metrics = append(c.metrics,\n\t\t\ttypes.Metric{\n\t\t\t\tNamespace:  aws.String(namespace),\n\t\t\t\tMetricName: aws.String(\"Latency\"),\n\t\t\t\tDimensions: []types.Dimension{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\t\t\t\t\tValue: aws.String(\"p-example1\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttypes.Metric{\n\t\t\t\tNamespace:  aws.String(namespace),\n\t\t\t\tMetricName: aws.String(\"Latency\"),\n\t\t\t\tDimensions: []types.Dimension{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\t\t\t\t\tValue: aws.String(\"p-example2\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t}\n\treturn c\n}\n\nfunc selectedMockClient() *mockClient {\n\tc := &mockClient{\n\t\tmetrics: make([]types.Metric, 0, 4*3*2),\n\t}\n\t// 4 metrics for 3 ELBs  in 2 AZs\n\tfor _, m := range []string{\"Latency\", \"RequestCount\", \"HealthyHostCount\", \"UnHealthyHostCount\"} {\n\t\tfor _, lb := range []string{\"lb-1\", \"lb-2\", \"lb-3\"} {\n\t\t\t// For each metric/ELB pair, we get an aggregate value across all AZs.\n\t\t\tc.metrics = append(c.metrics, types.Metric{\n\t\t\t\tNamespace:  aws.String(\"AWS/ELB\"),\n\t\t\t\tMetricName: aws.String(m),\n\t\t\t\tDimensions: []types.Dimension{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\t\t\t\t\tValue: aws.String(lb),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tfor _, az := range []string{\"us-east-1a\", \"us-east-1b\"} {\n\t\t\t\t// We get a metric for each metric/ELB/AZ triplet.\n\t\t\t\tc.metrics = append(c.metrics, types.Metric{\n\t\t\t\t\tNamespace:  aws.String(\"AWS/ELB\"),\n\t\t\t\t\tMetricName: aws.String(m),\n\t\t\t\t\tDimensions: []types.Dimension{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:  aws.String(\"LoadBalancerName\"),\n\t\t\t\t\t\t\tValue: aws.String(lb),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:  aws.String(\"AvailabilityZone\"),\n\t\t\t\t\t\t\tValue: aws.String(az),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn c\n}\n\nfunc (c *mockClient) ListMetrics(\n\t_ context.Context,\n\tparams *cloudwatch.ListMetricsInput,\n\t_ ...func(*cloudwatch.Options),\n) (*cloudwatch.ListMetricsOutput, error) {\n\tresponse := &cloudwatch.ListMetricsOutput{\n\t\tMetrics: c.metrics,\n\t}\n\n\tif params.IncludeLinkedAccounts != nil && *params.IncludeLinkedAccounts {\n\t\tresponse.OwningAccounts = []string{\"123456789012\", \"923456789017\"}\n\t}\n\treturn response, nil\n}\n\nfunc (*mockClient) GetMetricData(\n\t_ context.Context,\n\tparams *cloudwatch.GetMetricDataInput,\n\t_ ...func(*cloudwatch.Options),\n) (*cloudwatch.GetMetricDataOutput, error) {\n\treturn &cloudwatch.GetMetricDataOutput{\n\t\tMetricDataResults: []types.MetricDataResult{\n\t\t\t{\n\t\t\t\tId:         aws.String(\"minimum_0_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_minimum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.1},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"maximum_0_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_maximum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.3},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"average_0_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_average\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.2},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"sum_0_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_sum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{123},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"sample_count_0_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_sample_count\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{100},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"minimum_1_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_minimum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.1},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"maximum_1_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_maximum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.3},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"average_1_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_average\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{0.2},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"sum_1_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_sum\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{124},\n\t\t\t},\n\t\t\t{\n\t\t\t\tId:         aws.String(\"sample_count_1_0\"),\n\t\t\t\tLabel:      aws.String(\"latency_sample_count\"),\n\t\t\t\tStatusCode: types.StatusCodeComplete,\n\t\t\t\tTimestamps: []time.Time{\n\t\t\t\t\t*params.EndTime,\n\t\t\t\t},\n\t\t\t\tValues: []float64{100},\n\t\t\t},\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/cloudwatch/sample.conf",
    "content": "# Pull Metric Statistics from Amazon CloudWatch\n[[inputs.cloudwatch]]\n  ## Amazon Region\n  region = \"us-east-1\"\n\n  ## Amazon Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Web identity provider credentials via STS if role_arn and\n  ##    web_identity_token_file are specified\n  ## 2) Assumed credentials via STS if role_arn is specified\n  ## 3) explicit credentials from 'access_key' and 'secret_key'\n  ## 4) shared profile from 'profile'\n  ## 5) environment variables\n  ## 6) shared credentials file\n  ## 7) EC2 Instance Profile\n  # access_key = \"\"\n  # secret_key = \"\"\n  # token = \"\"\n  # role_arn = \"\"\n  # web_identity_token_file = \"\"\n  # role_session_name = \"\"\n  # profile = \"\"\n  # shared_credential_file = \"\"\n\n  ## If you are using CloudWatch cross-account observability, you can\n  ## set IncludeLinkedAccounts to true in a monitoring account\n  ## and collect metrics from the linked source accounts\n  # include_linked_accounts = false\n\n  ## Endpoint to make request against, the correct endpoint is automatically\n  ## determined and this option should only be set if you wish to override the\n  ## default.\n  ##   ex: endpoint_url = \"http://localhost:8000\"\n  # endpoint_url = \"\"\n\n  ## Set http_proxy\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## The minimum period for Cloudwatch metrics is 1 minute (60s). However not\n  ## all metrics are made available to the 1 minute period. Some are collected\n  ## at 3 minute, 5 minute, or larger intervals.\n  ## See https://aws.amazon.com/cloudwatch/faqs/#monitoring.\n  ## Note that if a period is configured that is smaller than the minimum for a\n  ## particular metric, that metric will not be returned by the Cloudwatch API\n  ## and will not be collected by Telegraf.\n  #\n  ## Requested CloudWatch aggregation Period (required)\n  ## Must be a multiple of 60s.\n  period = \"5m\"\n\n  ## Collection Delay (required)\n  ## Must account for metrics availability via CloudWatch API\n  delay = \"5m\"\n\n  ## Recommended: use metric 'interval' that is a multiple of 'period' to avoid\n  ## gaps or overlap in pulled data\n  interval = \"5m\"\n\n  ## Recommended if \"delay\" and \"period\" are both within 3 hours of request\n  ## time. Invalid values will be ignored. Recently Active feature will only\n  ## poll for CloudWatch ListMetrics values that occurred within the last 3h.\n  ## If enabled, it will reduce total API usage of the CloudWatch ListMetrics\n  ## API and require less memory to retain.\n  ## Do not enable if \"period\" or \"delay\" is longer than 3 hours, as it will\n  ## not return data more than 3 hours old.\n  ## See https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html\n  # recently_active = \"PT3H\"\n\n  ## Configure the TTL for the internal cache of metrics.\n  # cache_ttl = \"1h\"\n\n  ## Metric Statistic Namespaces, wildcards are allowed\n  # namespaces = [\"*\"]\n\n  ## Metric Format\n  ## This determines the format of the produces metrics. 'sparse', the default\n  ## will produce a unique field for each statistic. 'dense' will report all\n  ## statistics will be in a field called value and have a metric_name tag\n  ## defining the name of the statistic. See the plugin README for examples.\n  # metric_format = \"sparse\"\n\n  ## Maximum requests per second. Note that the global default AWS rate limit\n  ## is 50 reqs/sec, so if you define multiple namespaces, these should add up\n  ## to a maximum of 50.\n  ## See http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_limits.html\n  # ratelimit = 25\n\n  ## Timeout for http requests made by the cloudwatch client.\n  # timeout = \"5s\"\n\n  ## Batch Size\n  ## The size of each batch to send requests to Cloudwatch. 500 is the\n  ## suggested largest size. If a request gets to large (413 errors), consider\n  ## reducing this amount.\n  # batch_size = 500\n\n  ## Namespace-wide statistic filters. These allow fewer queries to be made to\n  ## cloudwatch.\n  # statistic_include = [\"average\", \"sum\", \"minimum\", \"maximum\", sample_count\"]\n  # statistic_exclude = []\n\n  ## Metrics to Pull\n  ## Defaults to all Metrics in Namespace if nothing is provided\n  ## Refreshes Namespace available metrics every 1h\n  #[[inputs.cloudwatch.metrics]]\n  #  names = [\"Latency\", \"RequestCount\"]\n  #\n  #  ## Statistic filters for Metric.  These allow for retrieving specific\n  #  ## statistics for an individual metric.\n  #  # statistic_include = [\"average\", \"sum\", \"minimum\", \"maximum\", sample_count\"]\n  #  # statistic_exclude = []\n  #\n  #  ## Dimension filters for Metric.\n  #  ## All dimensions defined for the metric names must be specified in order\n  #  ## to retrieve the metric statistics.\n  #  ## 'value' has wildcard / 'glob' matching support such as 'p-*'.\n  #  [[inputs.cloudwatch.metrics.dimensions]]\n  #    name = \"LoadBalancerName\"\n  #    value = \"p-example\"\n"
  },
  {
    "path": "plugins/inputs/cloudwatch/utils.go",
    "content": "package cloudwatch\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc metricMatch(cm *cloudwatchMetric, m types.Metric) bool {\n\tif !slices.Contains(cm.MetricNames, *m.MetricName) {\n\t\treturn false\n\t}\n\t// Dimensions need to match completely so exit early if the length mismatches\n\tif len(cm.Dimensions) != len(m.Dimensions) {\n\t\treturn false\n\t}\n\t// Sort the dimensions for efficient comparison\n\tslices.SortStableFunc(m.Dimensions, func(a, b types.Dimension) int {\n\t\treturn strings.Compare(*a.Name, *b.Name)\n\t})\n\treturn slices.EqualFunc(cm.Dimensions, m.Dimensions, func(rd *dimension, vd types.Dimension) bool {\n\t\treturn rd.Name == *vd.Name && (rd.valueMatcher == nil || rd.valueMatcher.Match(*vd.Value))\n\t})\n}\n\nfunc sanitizeMeasurement(namespace string) string {\n\tnamespace = strings.ReplaceAll(namespace, \"/\", \"_\")\n\tnamespace = snakeCase(namespace)\n\treturn \"cloudwatch_\" + namespace\n}\n\nfunc snakeCase(s string) string {\n\ts = internal.SnakeCase(s)\n\ts = strings.ReplaceAll(s, \" \", \"_\")\n\ts = strings.ReplaceAll(s, \"__\", \"_\")\n\treturn s\n}\n\nfunc ctod(cDimensions []types.Dimension) *map[string]string {\n\tdimensions := make(map[string]string, len(cDimensions))\n\tfor i := range cDimensions {\n\t\tdimensions[snakeCase(*cDimensions[i].Name)] = *cDimensions[i].Value\n\t}\n\treturn &dimensions\n}\n"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/README.md",
    "content": "# Amazon CloudWatch Metric Streams Input Plugin\n\nThis plugin listens for metrics sent via HTTP by\n[Cloudwatch metric streams][metric_streams] implementing the required\n[response specifications][response_specs].\n\n> [!IMPORTANT]\n> Using this plugin can incure costs, see the _Metric Streams example_ in\n> [CloudWatch pricing][pricing].\n\n⭐ Telegraf v1.24.0\n🏷️ cloud\n💻 all\n\n[pricing]: https://aws.amazon.com/cloudwatch/pricing\n[metric_streams]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Metric-Streams.html\n[response_specs]: https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# AWS Metric Streams listener\n[[inputs.cloudwatch_metric_streams]]\n  ## Address and port to host HTTP listener on\n  service_address = \":443\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Optional access key for Firehose security.\n  # access_key = \"test-key\"\n\n  ## An optional flag to keep Metric Streams metrics compatible with\n  ## CloudWatch's API naming\n  # api_compatability = false\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n```\n\n## Troubleshooting\n\nThe plugin has its own internal metrics for troubleshooting:\n\n* Requests Received\n  * The number of requests received by the listener.\n* Writes Served\n  * The number of writes served by the listener.\n* Bad Requests\n  * The number of bad requests, separated by the error code as a tag.\n* Request Time\n  * The duration of the request measured in ns.\n* Age Max\n  * The maximum age of a metric in this interval. This is useful for offsetting\n    any lag or latency measurements in a metrics pipeline that measures based\n    on the timestamp.\n* Age Min\n  * The minimum age of a metric in this interval.\n\nSpecific errors will be logged and an error will be returned to AWS.\n\nFor additional help check the [Firehose Troubleshooting][firehose_troubleshoot]\npage.\n\n[firehose_troubleshoot]: https://docs.aws.amazon.com/firehose/latest/dev/http_troubleshooting.html\n\n## Metrics\n\nMetrics sent by AWS are Base64 encoded blocks of JSON data.\nThe JSON block below is the Base64 decoded data in the `data`\nfield of a `record`.\nThere can be multiple blocks of JSON for each `data` field\nin each `record` and there can be multiple `record` fields in\na `record`.\n\nThe metric when decoded may look like this:\n\n```json\n{\n    \"metric_stream_name\": \"sandbox-dev-cloudwatch-metric-stream\",\n    \"account_id\": \"541737779709\",\n    \"region\": \"us-west-2\",\n    \"namespace\": \"AWS/EC2\",\n    \"metric_name\": \"CPUUtilization\",\n    \"dimensions\": {\n        \"InstanceId\": \"i-0efc7ghy09c123428\"\n    },\n    \"timestamp\": 1651679580000,\n    \"value\": {\n        \"max\": 10.011666666666667,\n        \"min\": 10.011666666666667,\n        \"sum\": 10.011666666666667,\n        \"count\": 1\n    },\n    \"unit\": \"Percent\"\n}\n```\n\n### Tags\n\nAll tags in the `dimensions` list are added as tags to the metric.\n\nThe `account_id` and `region` tag are added to each metric as well.\n\n### Measurements and Fields\n\nThe metric name is a combination of `namespace` and `metric_name`,\nseparated by `_` and lowercased.\n\nThe fields are each aggregate in the `value` list.\n\nThese fields are optionally renamed to match the CloudWatch API for\neasier transition from the API to Metric Streams. This relies on\nsetting the `api_compatability` flag in the configuration.\n\nThe timestamp applied is the timestamp from the metric,\ntypically 3-5 minutes older than the time processed due\nto CloudWatch delays.\n\n## Example Output\n\nExample output based on the above JSON & compatability flag is:\n\n**Standard Metric Streams format:**\n\n```text\naws_ec2_cpuutilization,accountId=541737779709,region=us-west-2,InstanceId=i-0efc7ghy09c123428 max=10.011666666666667,min=10.011666666666667,sum=10.011666666666667,count=1 1651679580000\n```\n\n**API Compatability format:**\n\n```text\naws_ec2_cpuutilization,accountId=541737779709,region=us-west-2,InstanceId=i-0efc7ghy09c123428 maximum=10.011666666666667,minimum=10.011666666666667,sum=10.011666666666667,samplecount=1 1651679580000\n```\n"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/cloudwatch_metric_streams.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cloudwatch_metric_streams\n\nimport (\n\t\"compress/gzip\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// defaultMaxBodySize is the default maximum request body size, in bytes.\n// if the request body is over this size, we will return an HTTP 413 error.\n// 500 MB\nconst defaultMaxBodySize = 500 * 1024 * 1024\n\ntype CloudWatchMetricStreams struct {\n\tServiceAddress   string          `toml:\"service_address\"`\n\tPaths            []string        `toml:\"paths\"`\n\tMaxBodySize      config.Size     `toml:\"max_body_size\"`\n\tReadTimeout      config.Duration `toml:\"read_timeout\"`\n\tWriteTimeout     config.Duration `toml:\"write_timeout\"`\n\tAccessKey        string          `toml:\"access_key\"`\n\tAPICompatability bool            `toml:\"api_compatability\"`\n\n\trequestsReceived selfstat.Stat\n\twritesServed     selfstat.Stat\n\trequestTime      selfstat.Stat\n\tageMax           selfstat.Stat\n\tageMin           selfstat.Stat\n\n\tLog telegraf.Logger\n\tcommon_tls.ServerConfig\n\twg       sync.WaitGroup\n\tclose    chan struct{}\n\tlistener net.Listener\n\tacc      telegraf.Accumulator\n}\n\ntype request struct {\n\tRequestID string `json:\"requestId\"`\n\tTimestamp int64  `json:\"timestamp\"`\n\tRecords   []struct {\n\t\tData string `json:\"data\"`\n\t} `json:\"records\"`\n}\n\ntype data struct {\n\tMetricStreamName string             `json:\"metric_stream_name\"`\n\tAccountID        string             `json:\"account_id\"`\n\tRegion           string             `json:\"region\"`\n\tNamespace        string             `json:\"namespace\"`\n\tMetricName       string             `json:\"metric_name\"`\n\tDimensions       map[string]string  `json:\"dimensions\"`\n\tTimestamp        int64              `json:\"timestamp\"`\n\tValue            map[string]float64 `json:\"value\"`\n\tUnit             string             `json:\"unit\"`\n}\n\ntype response struct {\n\tRequestID string `json:\"requestId\"`\n\tTimestamp int64  `json:\"timestamp\"`\n}\n\ntype age struct {\n\tmax time.Duration\n\tmin time.Duration\n}\n\nfunc (*CloudWatchMetricStreams) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (cms *CloudWatchMetricStreams) Init() error {\n\ttags := map[string]string{\n\t\t\"address\": cms.ServiceAddress,\n\t}\n\tcms.requestsReceived = selfstat.Register(\"cloudwatch_metric_streams\", \"requests_received\", tags)\n\tcms.writesServed = selfstat.Register(\"cloudwatch_metric_streams\", \"writes_served\", tags)\n\tcms.requestTime = selfstat.Register(\"cloudwatch_metric_streams\", \"request_time\", tags)\n\tcms.ageMax = selfstat.Register(\"cloudwatch_metric_streams\", \"age_max\", tags)\n\tcms.ageMin = selfstat.Register(\"cloudwatch_metric_streams\", \"age_min\", tags)\n\n\tif cms.MaxBodySize == 0 {\n\t\tcms.MaxBodySize = config.Size(defaultMaxBodySize)\n\t}\n\n\tif cms.ReadTimeout < config.Duration(time.Second) {\n\t\tcms.ReadTimeout = config.Duration(time.Second * 10)\n\t}\n\n\tif cms.WriteTimeout < config.Duration(time.Second) {\n\t\tcms.WriteTimeout = config.Duration(time.Second * 10)\n\t}\n\n\treturn nil\n}\n\n// Start starts the http listener service.\nfunc (cms *CloudWatchMetricStreams) Start(acc telegraf.Accumulator) error {\n\tcms.acc = acc\n\tserver := cms.createHTTPServer()\n\n\tvar err error\n\tserver.TLSConfig, err = cms.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif server.TLSConfig != nil {\n\t\tcms.listener, err = tls.Listen(\"tcp\", cms.ServiceAddress, server.TLSConfig)\n\t} else {\n\t\tcms.listener, err = net.Listen(\"tcp\", cms.ServiceAddress)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcms.wg.Add(1)\n\tgo func() {\n\t\tdefer cms.wg.Done()\n\t\tif err := server.Serve(cms.listener); err != nil {\n\t\t\tif !errors.Is(err, net.ErrClosed) {\n\t\t\t\tcms.Log.Errorf(\"Serve failed: %v\", err)\n\t\t\t}\n\t\t\tclose(cms.close)\n\t\t}\n\t}()\n\n\tcms.Log.Infof(\"Listening on %s\", cms.listener.Addr().String())\n\n\treturn nil\n}\n\nfunc (*CloudWatchMetricStreams) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (cms *CloudWatchMetricStreams) Stop() {\n\tif cms.listener != nil {\n\t\tcms.listener.Close()\n\t}\n\tcms.wg.Wait()\n}\n\nfunc (cms *CloudWatchMetricStreams) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tcms.requestsReceived.Incr(1)\n\tstart := time.Now()\n\tdefer cms.recordRequestTime(start)\n\n\thandler := cms.serveWrite\n\n\tif !choice.Contains(req.URL.Path, cms.Paths) {\n\t\thandler = http.NotFound\n\t}\n\n\tcms.authenticateIfSet(handler, res, req)\n}\n\nfunc (a *age) record(t time.Duration) {\n\tif t > a.max {\n\t\ta.max = t\n\t}\n\n\tif t < a.min {\n\t\ta.min = t\n\t}\n}\n\nfunc (a *age) submitMax(stat selfstat.Stat) {\n\tstat.Incr(a.max.Nanoseconds())\n}\n\nfunc (a *age) submitMin(stat selfstat.Stat) {\n\tstat.Incr(a.min.Nanoseconds())\n}\n\nfunc (cms *CloudWatchMetricStreams) createHTTPServer() *http.Server {\n\treturn &http.Server{\n\t\tAddr:         cms.ServiceAddress,\n\t\tHandler:      cms,\n\t\tReadTimeout:  time.Duration(cms.ReadTimeout),\n\t\tWriteTimeout: time.Duration(cms.WriteTimeout),\n\t}\n}\n\nfunc (cms *CloudWatchMetricStreams) recordRequestTime(start time.Time) {\n\telapsed := time.Since(start)\n\tcms.requestTime.Incr(elapsed.Nanoseconds())\n}\n\nfunc (cms *CloudWatchMetricStreams) serveWrite(res http.ResponseWriter, req *http.Request) {\n\tselect {\n\tcase <-cms.close:\n\t\tres.WriteHeader(http.StatusGone)\n\t\treturn\n\tdefault:\n\t}\n\n\tdefer cms.writesServed.Incr(1)\n\n\t// Check that the content length is not too large for us to handle.\n\tif req.ContentLength > int64(cms.MaxBodySize) {\n\t\tcms.Log.Errorf(\"content length exceeded maximum body size\")\n\t\tif err := tooLarge(res); err != nil {\n\t\t\tcms.Log.Debugf(\"error in too-large: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\t// Check that the method is a POST\n\tif req.Method != \"POST\" {\n\t\tcms.Log.Errorf(\"incompatible request method\")\n\t\tif err := methodNotAllowed(res); err != nil {\n\t\t\tcms.Log.Debugf(\"error in method-not-allowed: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\t// Decode GZIP\n\tvar body = req.Body\n\tencoding := req.Header.Get(\"Content-Encoding\")\n\n\tif encoding == \"gzip\" {\n\t\treader, err := gzip.NewReader(req.Body)\n\t\tif err != nil {\n\t\t\tcms.Log.Errorf(\"unable to uncompress metric-streams data: %v\", err)\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\tcms.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tbody = reader\n\t\tdefer reader.Close()\n\t}\n\n\t// Decode the request\n\tvar r request\n\terr := json.NewDecoder(body).Decode(&r)\n\tif err != nil {\n\t\tcms.Log.Errorf(\"unable to decode metric-streams request: %v\", err)\n\t\tif err := badRequest(res); err != nil {\n\t\t\tcms.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tagesInRequest := &age{max: 0, min: math.MaxInt32}\n\tdefer agesInRequest.submitMax(cms.ageMax)\n\tdefer agesInRequest.submitMin(cms.ageMin)\n\n\t// For each record, decode the base64 data and store it in a data struct\n\t// Metrics from Metric Streams are Base64 encoded JSON\n\t// https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html\n\tfor _, record := range r.Records {\n\t\tb, err := base64.StdEncoding.DecodeString(record.Data)\n\t\tif err != nil {\n\t\t\tcms.Log.Errorf(\"unable to base64 decode metric-streams data: %v\", err)\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\tcms.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tlist := strings.Split(string(b), \"\\n\")\n\n\t\t// If the last element is empty, remove it to avoid unexpected JSON\n\t\tif len(list) > 0 {\n\t\t\tif list[len(list)-1] == \"\" {\n\t\t\t\tlist = list[:len(list)-1]\n\t\t\t}\n\t\t}\n\n\t\tfor _, js := range list {\n\t\t\tvar d data\n\t\t\terr = json.Unmarshal([]byte(js), &d)\n\t\t\tif err != nil {\n\t\t\t\tcms.Log.Errorf(\"unable to unmarshal metric-streams data: %v\", err)\n\t\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\t\tcms.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcms.composeMetrics(d)\n\t\t\tagesInRequest.record(time.Since(time.Unix(d.Timestamp/1000, 0)))\n\t\t}\n\t}\n\n\t// Compose the response to AWS using the request's requestId\n\t// https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html#responseformat\n\tresponse := response{\n\t\tRequestID: r.RequestID,\n\t\tTimestamp: time.Now().UnixNano() / 1000000,\n\t}\n\n\tmarshalled, err := json.Marshal(response)\n\tif err != nil {\n\t\tcms.Log.Errorf(\"unable to compose response: %v\", err)\n\t\tif err := badRequest(res); err != nil {\n\t\t\tcms.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusOK)\n\t_, err = res.Write(marshalled)\n\tif err != nil {\n\t\tcms.Log.Debugf(\"Error writing response to AWS: %s\", err.Error())\n\t\treturn\n\t}\n}\n\nfunc (cms *CloudWatchMetricStreams) composeMetrics(data data) {\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\ttimestamp := time.Unix(data.Timestamp/1000, 0)\n\n\tnamespace := strings.Replace(data.Namespace, \"/\", \"_\", -1)\n\tmeasurement := strings.ToLower(namespace + \"_\" + data.MetricName)\n\n\tfor field, value := range data.Value {\n\t\tfields[field] = value\n\t}\n\n\t// Rename Statistics to match the CloudWatch API if in API Compatability mode\n\tif cms.APICompatability {\n\t\tif v, ok := fields[\"max\"]; ok {\n\t\t\tfields[\"maximum\"] = v\n\t\t\tdelete(fields, \"max\")\n\t\t}\n\n\t\tif v, ok := fields[\"min\"]; ok {\n\t\t\tfields[\"minimum\"] = v\n\t\t\tdelete(fields, \"min\")\n\t\t}\n\n\t\tif v, ok := fields[\"count\"]; ok {\n\t\t\tfields[\"samplecount\"] = v\n\t\t\tdelete(fields, \"count\")\n\t\t}\n\t}\n\n\ttags[\"accountId\"] = data.AccountID\n\ttags[\"region\"] = data.Region\n\n\tfor dimension, value := range data.Dimensions {\n\t\ttags[dimension] = value\n\t}\n\n\tcms.acc.AddFields(measurement, fields, tags, timestamp)\n}\n\nfunc tooLarge(res http.ResponseWriter) error {\n\ttags := map[string]string{\n\t\t\"status_code\": strconv.Itoa(http.StatusRequestEntityTooLarge),\n\t}\n\tselfstat.Register(\"cloudwatch_metric_streams\", \"bad_requests\", tags).Incr(1)\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t_, err := res.Write([]byte(`{\"error\":\"http: request body too large\"}`))\n\treturn err\n}\n\nfunc methodNotAllowed(res http.ResponseWriter) error {\n\ttags := map[string]string{\n\t\t\"status_code\": strconv.Itoa(http.StatusMethodNotAllowed),\n\t}\n\tselfstat.Register(\"cloudwatch_metric_streams\", \"bad_requests\", tags).Incr(1)\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusMethodNotAllowed)\n\t_, err := res.Write([]byte(`{\"error\":\"http: method not allowed\"}`))\n\treturn err\n}\n\nfunc badRequest(res http.ResponseWriter) error {\n\ttags := map[string]string{\n\t\t\"status_code\": strconv.Itoa(http.StatusBadRequest),\n\t}\n\tselfstat.Register(\"cloudwatch_metric_streams\", \"bad_requests\", tags).Incr(1)\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusBadRequest)\n\t_, err := res.Write([]byte(`{\"error\":\"http: bad request\"}`))\n\treturn err\n}\n\nfunc (cms *CloudWatchMetricStreams) authenticateIfSet(handler http.HandlerFunc, res http.ResponseWriter, req *http.Request) {\n\tif cms.AccessKey != \"\" {\n\t\tauth := req.Header.Get(\"X-Amz-Firehose-Access-Key\")\n\t\tif auth == \"\" || auth != cms.AccessKey {\n\t\t\thttp.Error(res, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t\thandler(res, req)\n\t} else {\n\t\thandler(res, req)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"cloudwatch_metric_streams\", func() telegraf.Input {\n\t\treturn &CloudWatchMetricStreams{\n\t\t\tServiceAddress: \":443\",\n\t\t\tPaths:          []string{\"/telegraf\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/cloudwatch_metric_streams_test.go",
    "content": "package cloudwatch_metric_streams\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tbadMsg       = \"blahblahblah: 42\\n\"\n\temptyMsg     = \"\"\n\taccessKey    = \"super-secure-password!\"\n\tbadAccessKey = \"super-insecure-password!\"\n\tmaxBodySize  = 524288000\n)\n\nvar (\n\tpki = testutil.NewPKI(\"../../../testutil/pki\")\n)\n\nfunc newTestCloudWatchMetricStreams() *CloudWatchMetricStreams {\n\tmetricStream := &CloudWatchMetricStreams{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:8080\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMaxBodySize:    config.Size(maxBodySize),\n\t\tclose:          make(chan struct{}),\n\t}\n\treturn metricStream\n}\n\nfunc newTestMetricStreamAuth() *CloudWatchMetricStreams {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\tmetricStream.AccessKey = accessKey\n\treturn metricStream\n}\n\nfunc newTestMetricStreamHTTPS() *CloudWatchMetricStreams {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\tmetricStream.ServerConfig = *pki.TLSServerConfig()\n\n\treturn metricStream\n}\n\nfunc newTestCompatibleCloudWatchMetricStreams() *CloudWatchMetricStreams {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\tmetricStream.APICompatability = true\n\treturn metricStream\n}\n\nfunc getHTTPSClient() *http.Client {\n\ttlsConfig, err := pki.TLSClientConfig().TLSConfig()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t}\n}\n\nfunc createURL(scheme, path string) string {\n\tu := url.URL{\n\t\tScheme:   scheme,\n\t\tHost:     \"localhost:8080\",\n\t\tPath:     path,\n\t\tRawQuery: \"\",\n\t}\n\treturn u.String()\n}\n\nfunc readJSON(t *testing.T, jsonFilePath string) []byte {\n\tdata, err := os.ReadFile(jsonFilePath)\n\trequire.NoErrorf(t, err, \"could not read from data file %s\", jsonFilePath)\n\n\treturn data\n}\n\nfunc TestInvalidListenerConfig(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\tmetricStream.ServiceAddress = \"address_without_port\"\n\n\tacc := &testutil.Accumulator{}\n\trequire.Error(t, metricStream.Start(acc))\n\n\t// Stop is called when any ServiceInput fails to start; it must succeed regardless of state\n\tmetricStream.Stop()\n}\n\nfunc TestWriteHTTPSNoClientAuth(t *testing.T) {\n\tmetricStream := newTestMetricStreamHTTPS()\n\tmetricStream.TLSAllowedCACerts = nil\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\tcas := x509.NewCertPool()\n\tcas.AppendCertsFromPEM([]byte(pki.ReadServerCert()))\n\tnoClientAuthClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tRootCAs: cas,\n\t\t\t},\n\t\t},\n\t}\n\n\t// post single message to the metric stream listener\n\trecord := readJSON(t, \"testdata/record.json\")\n\tresp, err := noClientAuthClient.Post(createURL(\"https\", \"/write\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\nfunc TestWriteHTTPSWithClientAuth(t *testing.T) {\n\tmetricStream := newTestMetricStreamHTTPS()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post single message to the metric stream listener\n\trecord := readJSON(t, \"testdata/record.json\")\n\tresp, err := getHTTPSClient().Post(createURL(\"https\", \"/write\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\nfunc TestWriteHTTPSuccessfulAuth(t *testing.T) {\n\tmetricStream := newTestMetricStreamAuth()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\tclient := &http.Client{}\n\n\trecord := readJSON(t, \"testdata/record.json\")\n\treq, err := http.NewRequest(\"POST\", createURL(\"http\", \"/write\"), bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"X-Amz-Firehose-Access-Key\", accessKey)\n\n\t// post single message to the metric stream listener\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc TestWriteHTTPFailedAuth(t *testing.T) {\n\tmetricStream := newTestMetricStreamAuth()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\tclient := &http.Client{}\n\n\trecord := readJSON(t, \"testdata/record.json\")\n\treq, err := http.NewRequest(\"POST\", createURL(\"http\", \"/write\"), bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"X-Amz-Firehose-Access-Key\", badAccessKey)\n\n\t// post single message to the metric stream listener\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusUnauthorized, resp.StatusCode)\n}\n\nfunc TestWriteHTTP(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post single message to the metric stream listener\n\trecord := readJSON(t, \"testdata/record.json\")\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\nfunc TestWriteHTTPMultipleRecords(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post multiple records to the metric stream listener\n\trecords := readJSON(t, \"testdata/records.json\")\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBuffer(records))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\nfunc TestWriteHTTPExactMaxBodySize(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\trecord := readJSON(t, \"testdata/record.json\")\n\tmetricStream.MaxBodySize = config.Size(len(record))\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post single message to the metric stream listener\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\nfunc TestWriteHTTPVerySmallMaxBody(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\tmetricStream.MaxBodySize = config.Size(512)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post single message to the metric stream listener\n\trecord := readJSON(t, \"testdata/record.json\")\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 413, resp.StatusCode)\n}\n\nfunc TestReceive404ForInvalidEndpoint(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post single message to the metric stream listener\n\trecord := readJSON(t, \"testdata/record.json\")\n\tresp, err := http.Post(createURL(\"http\", \"/foobar\"), \"\", bytes.NewBuffer(record))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 404, resp.StatusCode)\n}\n\nfunc TestWriteHTTPInvalid(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post a badly formatted message to the metric stream listener\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBufferString(badMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 400, resp.StatusCode)\n}\n\nfunc TestWriteHTTPEmpty(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// post empty message to the metric stream listener\n\tresp, err := http.Post(createURL(\"http\", \"/write\"), \"\", bytes.NewBufferString(emptyMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 400, resp.StatusCode)\n}\n\nfunc TestComposeMetrics(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// compose a data object for writing\n\tdata := data{\n\t\tMetricStreamName: \"cloudwatch-metric-stream\",\n\t\tAccountID:        \"546734499701\",\n\t\tRegion:           \"us-west-2\",\n\t\tNamespace:        \"AWS/EC2\",\n\t\tMetricName:       \"CPUUtilization\",\n\t\tDimensions:       map[string]string{\"AutoScalingGroupName\": \"test-autoscaling-group\"},\n\t\tTimestamp:        1651679400000,\n\t\tValue:            map[string]float64{\"max\": 0.4366666666666666, \"min\": 0.3683333333333333, \"sum\": 1.9399999999999997, \"count\": 5.0},\n\t\tUnit:             \"Percent\",\n\t}\n\n\t// Compose the metrics from data\n\tmetricStream.composeMetrics(data)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"aws_ec2_cpuutilization\",\n\t\tmap[string]interface{}{\"max\": 0.4366666666666666, \"min\": 0.3683333333333333, \"sum\": 1.9399999999999997, \"count\": 5.0},\n\t\tmap[string]string{\"AutoScalingGroupName\": \"test-autoscaling-group\", \"accountId\": \"546734499701\", \"region\": \"us-west-2\"},\n\t)\n}\n\nfunc TestComposeAPICompatibleMetrics(t *testing.T) {\n\tmetricStream := newTestCompatibleCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\t// compose a data object for writing\n\tdata := data{\n\t\tMetricStreamName: \"cloudwatch-metric-stream\",\n\t\tAccountID:        \"546734499701\",\n\t\tRegion:           \"us-west-2\",\n\t\tNamespace:        \"AWS/EC2\",\n\t\tMetricName:       \"CPUUtilization\",\n\t\tDimensions:       map[string]string{\"AutoScalingGroupName\": \"test-autoscaling-group\"},\n\t\tTimestamp:        1651679400000,\n\t\tValue:            map[string]float64{\"max\": 0.4366666666666666, \"min\": 0.3683333333333333, \"sum\": 1.9399999999999997, \"count\": 5.0},\n\t\tUnit:             \"Percent\",\n\t}\n\n\t// Compose the metrics from data\n\tmetricStream.composeMetrics(data)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"aws_ec2_cpuutilization\",\n\t\tmap[string]interface{}{\"maximum\": 0.4366666666666666, \"minimum\": 0.3683333333333333, \"sum\": 1.9399999999999997, \"samplecount\": 5.0},\n\t\tmap[string]string{\"AutoScalingGroupName\": \"test-autoscaling-group\", \"accountId\": \"546734499701\", \"region\": \"us-west-2\"},\n\t)\n}\n\n// post GZIP encoded data to the metric stream listener\nfunc TestWriteHTTPGzippedData(t *testing.T) {\n\tmetricStream := newTestCloudWatchMetricStreams()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, metricStream.Init())\n\trequire.NoError(t, metricStream.Start(acc))\n\tdefer metricStream.Stop()\n\n\tdata, err := os.ReadFile(\"./testdata/records.gz\")\n\trequire.NoError(t, err)\n\n\treq, err := http.NewRequest(\"POST\", createURL(\"http\", \"/write\"), bytes.NewBuffer(data))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Encoding\", \"gzip\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/sample.conf",
    "content": "# AWS Metric Streams listener\n[[inputs.cloudwatch_metric_streams]]\n  ## Address and port to host HTTP listener on\n  service_address = \":443\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Optional access key for Firehose security.\n  # access_key = \"test-key\"\n\n  ## An optional flag to keep Metric Streams metrics compatible with\n  ## CloudWatch's API naming\n  # api_compatability = false\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/testdata/record.json",
    "content": "{\n  \"requestId\": \"c8291d2e-8c46-4f2a-a8df-2562550287ad\",\n  \"timestamp\": 1651679861072,\n  \"records\": [\n    {\n      \"data\": \"eyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVmYzdmZGYwOWMxMjM0MjgifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwLjAxMTY2NjY2NjY2NjY2NywibWluIjoxMC4wMTE2NjY2NjY2NjY2NjcsInN1bSI6MTAuMDExNjY2NjY2NjY2NjY3LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQ==\"\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/cloudwatch_metric_streams/testdata/records.json",
    "content": "{\n  \"requestId\": \"c8291d2e-8c46-4f2a-a8df-2562550287ad\",\n  \"timestamp\": 1651679861072,\n  \"records\": [\n    {\n      \"data\": \"eyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNiYmM3ZTAyMWExOWJlMmUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjNkZjdhODI3Y2JjNzY1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2NzkzNDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6NDk5LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjQ5MDY5MjRlZjliNzhiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTQyMTcyNS4wLCJtaW4iOjk0MjE3MjUuMCwic3VtIjo5NDIxNzI1LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYuMCwibWluIjowLjAsInN1bSI6Ni4wLCJjb3VudCI6Mi4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2NzkzNDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDdkYmI0ZGZiNjhiMDU2YTYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTgzNTMyMjIwMDAwMDEwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC43NzEzMDE5N0U4LCJtaW4iOjMuNTk3NjY5RTcsInN1bSI6OS4xMzEwNjg4N0U4LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDI5ZThiOTE4OTM1MTA2NzIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMDA5NDExLjAsIm1pbiI6MTY4MjE4Ny4wLCJzdW0iOjkwNDI2MzIuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM1MzQ1ODQuMCwibWluIjoyNjY1MzM0LjAsInN1bSI6MS41ODk4MDE3RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGEyYTk3NTBmNDQyN2FiZTcifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1MjA1NzYuMCwibWluIjoxOTk4MzM2LjAsInN1bSI6MS4xMTc3OTg0RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTA1NTIwMy4wLCJtaW4iOjUwNTUyMDMuMCwic3VtIjo1MDU1MjAzLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA4OGJmNjU2ZTNlY2ZkMzBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxODM5NS4wLCJtaW4iOjE2MTEzLjAsInN1bSI6ODU5MDEuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjE5YzdiODYyNDg0NTBiMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc2Mi4wLCJtaW4iOjc2Mi4wLCJzdW0iOjM4MTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wODhiZjY1NmUzZWNmZDMwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyZWM2MmQzYzQwMmU5ZWVmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxLjkzMDg3RTcsIm1pbiI6MS45MzA4N0U3LCJzdW0iOjEuOTMwODdFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NDEuMCwibWluIjozMC4wLCJzdW0iOjE3NC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJlYzYyZDNjNDAyZTllZWYifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTIzLjAsIm1pbiI6MTE5LjAsInN1bSI6MjQyLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjgxMDk4MzUuMCwibWluIjo4MTA5ODM1LjAsInN1bSI6ODEwOTgzNS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjozLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ5MzAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjozNzEuMCwibWluIjoyNjcuMCwic3VtIjoxNDkxLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNS40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1LjUyNDk5OTk5OTk5OTk5OTUsIm1pbiI6NS41MjQ5OTk5OTk5OTk5OTk1LCJzdW0iOjUuNTI0OTk5OTk5OTk5OTk5NSwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDg4YmY2NTZlM2VjZmQzMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjM1Nzc2MC4wLCJtaW4iOjE4MDY4NDguMCwic3VtIjoxLjAwMDAzODRFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTM0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjg5OGM5YjFjNTExZWI0MSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAxMzYuMCwibWluIjo4NjI5LjAsInN1bSI6NDY3MjMuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVU3VycGx1c0NyZWRpdHNDaGFyZ2VkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjNkZjdhODI3Y2JjNzY1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmNDkwNjkyNGVmOWI3OGJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozOTM1MDkyLjAsIm1pbiI6MzkzNTA5Mi4wLCJzdW0iOjM5MzUwOTIuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY4OThjOWIxYzUxMWViNDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjguNzcxMzAxOTdFOCwibWluIjo4Ljc3MTMwMTk3RTgsInN1bSI6OC43NzEzMDE5N0U4LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA4OGJmNjU2ZTNlY2ZkMzBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MzA0NjQwMC4wLCJtaW4iOjE1NjYyMDguMCwic3VtIjoxLjA5MjcxMDRFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NDM3LjAsIm1pbiI6NDEwLjAsInN1bSI6MjEwNi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01bi44eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFlMjFhYjFkM2RjZDc0YjQifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM1MTM3LjAsIm1pbiI6MzQ2MDQuMCwic3VtIjoxNzQ3NTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE2MTY2MTczMDAwMDAwY2MifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ1ODc1Mi4wLCJtaW4iOjAuMCwic3VtIjo0NTg3NTIuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE2MTY2MTczMDAwMDAwY2MifSwidGltZXN0YW1wIjoxNjUxNjc5MzQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE0MzUzLjAsIm1pbiI6MTExNzMuMCwic3VtIjo2MjkxMS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZTI1ZGQ1MmJjZGU3NzI5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6InQyLm1pY3JvIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoyLjA2ODk2NTUxNzI0MjYzLCJtaW4iOjIuMDY4OTY1NTE3MjQyNjMsInN1bSI6Mi4wNjg5NjU1MTcyNDI2MywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1NzUzMjczLjAsIm1pbiI6NTc1MzI3My4wLCJzdW0iOjU3NTMyNzMuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTYuNTYzMzMzMzMzMzMzMzMzLCJtaW4iOjE2LjU2MzMzMzMzMzMzMzMzMywic3VtIjoxNi41NjMzMzMzMzMzMzMzMzMsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmODk4YzliMWM1MTFlYjQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNC43MjY0MjEyMjYzMTI4OTIsIm1pbiI6MTQuNzI2NDIxMjI2MzEyODkyLCJzdW0iOjE0LjcyNjQyMTIyNjMxMjg5MiwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI4Ni4wLCJtaW4iOjI4Ni4wLCJzdW0iOjI4Ni4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxOTNkZmJlMjczODZhYWExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzA2MTA2NzAwMDAwMGUzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxODM5NS4wLCJtaW4iOjE2MTEzLjAsInN1bSI6ODU5MDEuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTYxNjYxNzMwMDAwMDBjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjOTMxYTYzZjhiNWVhODk4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWEzNzMxZTk1ZTY0YmIzMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRVc2FnZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY3ODM1YTU0ZWEzODQ3M2EifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDA1NDk1LCJtaW4iOjAuMDA1NDk1LCJzdW0iOjAuMDA1NDk1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODMwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuNDg2NjY2NjY2NjY2NjY2NywibWluIjowLjQyNjY1OTU1NTY3NDA3MjEsInN1bSI6Mi4yNTMzMjYyMjIzNDA3Mzg2LCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3ZGJiNGRmYjY4YjA1NmE2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo4ODQyLjAsIm1pbiI6NzM3OS4wLCJzdW0iOjM5NDc4LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMGJjZTUyNjViYzU3MDVhMTkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUuMDk2NTAxRTcsIm1pbiI6MjgwOTI2NC4wLCJzdW0iOjIuMDQyMjQ4N0U4LCJjb3VudCI6MTYuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUuNTI0OTk5OTk5OTk5OTk5NSwibWluIjo1LjUyNDk5OTk5OTk5OTk5OTUsInN1bSI6NS41MjQ5OTk5OTk5OTk5OTk1LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuMDgxODc0OEU3LCJtaW4iOjEuMDgxODc0OEU3LCJzdW0iOjEuMDgxODc0OEU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo4MTA5ODM1LjAsIm1pbiI6NDQwOTA1OS4wLCJzdW0iOjEuMjUxODg5NEU3LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNC43MjY0MjEyMjYzMTI4OTIsIm1pbiI6NS4yODUsInN1bSI6MjAuMDExNDIxMjI2MzEyODksImNvdW50IjoyLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMDk0MGJhYmJiNTRkNjk4NzQifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmODk4YzliMWM1MTFlYjQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjkwMzg2Njg4RTgsIm1pbiI6My45MDM4NjY4OEU4LCJzdW0iOjMuOTAzODY2ODhFOCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVlMjVkZDUyYmNkZTc3MjkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjcuMCwibWluIjo3LjAsInN1bSI6Ny4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNS4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo0NDA5MDU5LjAsIm1pbiI6MjgwOTI2NC4wLCJzdW0iOjcyMTgzMjMuMCwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MzA3NzI4OC4wLCJtaW4iOjE5NDU2NTUuMCwic3VtIjoxLjE1NDA3MjhFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NjQ4MDU0LjAsIm1pbiI6Mjk3NTMxLjAsInN1bSI6MTg4OTgzMS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnt9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4wOTY1MDFFNywibWluIjoxNDc1MDYuMCwic3VtIjoyLjA0MzcyMzc2RTgsImNvdW50IjoxNy4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE2MTY2MTczMDAwMDAwY2MifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZmM3ZmRmMDljMTIzNDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjo5OS4wLCJzdW0iOjQ5Ni4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxODI5MTE3NTAwMDAwMTA5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMjAuMCwibWluIjozMjAuMCwic3VtIjozMjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ5MzAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyNTY3MzA5LjAsIm1pbiI6MTk4MDU5OS4wLCJzdW0iOjEuMDc0MjQ5RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJiNWQ0OTFmZGZjNmMxZDEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC40ODY2NjY2NjY2NjY2NjY3LCJtaW4iOjAuNDI2NjU5NTU1Njc0MDcyMSwic3VtIjoyLjI1MzMyNjIyMjM0MDczODYsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWJlNmFiM2UzNzlmNDhhZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NzYyLjAsIm1pbiI6NzYyLjAsInN1bSI6MzgxMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjozMDQ2NDAwLjAsIm1pbiI6MTU2NjIwOC4wLCJzdW0iOjEuMDkyNzEwNEU3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC40OTU3NjI3MTE4NTk0NywibWluIjo1LjA3MTY2NjY2NjY2NjY2Niwic3VtIjoxOS4xNzU3NjI3MTE4NTk0NywiY291bnQiOjMuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmVjNjJkM2M0MDJlOWVlZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MS40OTg3N0U3LCJtaW4iOjEuNDk4NzdFNywic3VtIjoxLjQ5ODc3RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjQ5MDY5MjRlZjliNzhiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6My4zNzMzMzMzMzMzMzMzMzMsIm1pbiI6My4zNzMzMzMzMzMzMzMzMzMsInN1bSI6My4zNzMzMzMzMzMzMzMzMzMsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMGJjZTUyNjViYzU3MDVhMTkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Ny4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuMTI4NzkzNkU3LCJtaW4iOjE2OTQyMDguMCwic3VtIjoyLjk5MTk3NDRFNywiY291bnQiOjMuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo0Mjk1OS4wLCJtaW4iOjI1NDE2LjAsInN1bSI6MTQ5MTMzLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxM2U5NWMyZGI1NTg5NTdiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo0MzgwNTQwLjAsIm1pbiI6MzE4Nzg5MC4wLCJzdW0iOjEuODQwOTM2MUU3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuNDU4MzMzMzMzMzMzMzMzMywibWluIjowLjQzMzMzMzMzMzMzMzMzMzMsInN1bSI6Mi4yNDE2NjY2NjY2NjY2NjYzLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM5NDAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3ZGJiNGRmYjY4YjA1NmE2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE4MjkxMTc1MDAwMDAxMDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImRzZS1vcHMtZGV2LWF1dG9zY2FsaW5nLWhvc3QifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTIyNTIuMCwibWluIjoxMDE4NS4wLCJzdW0iOjU2NjYxLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTA2MDIuMCwibWluIjo5MjUwLjAsInN1bSI6NDgyMTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjo5OS4wLCJzdW0iOjQ5Ny4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo4LjQyMjEzMTE0NzUzNjIxLCJtaW4iOjUuNzUwMDAwMDAwMDAwMDcsInN1bSI6MTQuMTcyMTMxMTQ3NTM2MjgsImNvdW50IjoyLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDczODhlZWFiYzhiNzYzMjMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWJlNmFiM2UzNzlmNDhhZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6ODY5NDQ5LjAsIm1pbiI6Njk5MDk0LjAsInN1bSI6MzY5MTIxNS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY4OThjOWIxYzUxMWViNDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUyNTQuMCwibWluIjo1MjU0LjAsInN1bSI6NTI1NC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjNTdiYzYwZDM1ZWYxODM2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2LjAsIm1pbiI6MC4wLCJzdW0iOjYuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDg0MDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYxMi4wLCJtaW4iOjI2NS4wLCJzdW0iOjE5ODguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC43NzEzMDE5N0U4LCJtaW4iOjEuMDY0MDE2NEU3LCJzdW0iOjguODc3NzAzNjFFOCwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYmIzYzcwODAwZjc4OWM2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1MDM2MS4wLCJtaW4iOjUwMzYxLjAsInN1bSI6NTAzNjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM1MTM3LjAsIm1pbiI6MzQ2MDQuMCwic3VtIjoxNzQ3NTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2E1ODAxZmMyMDAyYjA5OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTVjNzVmMDE1ZjM5MDU4MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6Mjk3MTIuMCwibWluIjoyNzI1MS4wLCJzdW0iOjE0MDQ3Mi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1MjU0LjAsIm1pbiI6MC4wLCJzdW0iOjUyNTQuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MTUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFlMjFhYjFkM2RjZDc0YjQifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU0NjE4LjAsIm1pbiI6NTM2MTguMCwic3VtIjoyNzAwNTIuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxLjEzNSwibWluIjoxLjA2MTY0ODk3MjUxNzEyNDgsInN1bSI6NS40NzUwMDA3MjI4MjQwNzQsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNW4uMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxM2U5NWMyZGI1NTg5NTdiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo4OTE1LjAsIm1pbiI6NzMzOC4wLCJzdW0iOjM4OTAzLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGJiM2M3MDgwMGY3ODljNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMWE3MzZhZjNiOGE1YmY0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjowLjAsInN1bSI6Mjk0LjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYmIzYzcwODAwZjc4OWM2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzkwNTAyNC4wLCJtaW4iOjAuMCwic3VtIjozOTA1MDI0LjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZmM3ZmRmMDljMTIzNDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5MTk4MDgwLjAsIm1pbiI6OTE5ODA4MC4wLCJzdW0iOjkxOTgwODAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDI5ZThiOTE4OTM1MTA2NzIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUuMDcxNjY2NjY2NjY2NjY2LCJtaW4iOjUuMDcxNjY2NjY2NjY2NjY2LCJzdW0iOjUuMDcxNjY2NjY2NjY2NjY2LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01LjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM4MjUxNTIuMCwibWluIjozODI1MTUyLjAsInN1bSI6MzgyNTE1Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxOTNkZmJlMjczODZhYWExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo2MjQ2MTMuMCwibWluIjozMTEyMTAuMCwic3VtIjoxOTA0ODg0LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMDk0MGJhYmJiNTRkNjk4NzQifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjUyMDU3Ni4wLCJtaW4iOjE5OTgzMzYuMCwic3VtIjoxLjExNzc5ODRFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY3ODM1YTU0ZWEzODQ3M2EifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3LjAsIm1pbiI6MC4wLCJzdW0iOjcuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZTc1ZjNjNDViZGMyOTg5MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjNTdiYzYwZDM1ZWYxODM2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo4NjU2NDAuMCwibWluIjo2OTE5MzIuMCwic3VtIjozNjgwMTcwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjE5YzdiODYyNDg0NTBiMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3ZGJiNGRmYjY4YjA1NmE2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMTUwOTEyLjAsIm1pbiI6MTc3NTEwNC4wLCJzdW0iOjkzNTU3NzYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyMTljN2I4NjI0ODQ1MGIyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1Ljc1MDAwMDAwMDAwMDA3LCJtaW4iOjUuNzUwMDAwMDAwMDAwMDcsInN1bSI6NS43NTAwMDAwMDAwMDAwNywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUuNjA4MzMzMzMzMzMzMzMzLCJtaW4iOjUuNjA4MzMzMzMzMzMzMzMzLCJzdW0iOjUuNjA4MzMzMzMzMzMzMzMzLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImRzZS1vcHMtZGV2LWF1dG9zY2FsaW5nLWhvc3QifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDczODhlZWFiYzhiNzYzMjMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29tcHV0ZS1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MTMyODMwMDAwMDAwZTYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6e30sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjguMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE4MjkxMTc1MDAwMDAxMDkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc4MTUuMCwibWluIjo2NjI5LjAsInN1bSI6MzU2MDcuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6NDk3LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc1NjU4MjQuMCwibWluIjo3NTY1ODI0LjAsInN1bSI6NzU2NTgyNC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTQ0LjAsIm1pbiI6MTQ0LjAsInN1bSI6MTQ0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU3NzUzNi4wLCJtaW4iOjAuMCwic3VtIjoxMzk4MjcyLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMTkuMCwibWluIjoxMTkuMCwic3VtIjoxMTkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNiYmM3ZTAyMWExOWJlMmUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3Mzg4ZWVhYmM4Yjc2MzIzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMDk0MGJhYmJiNTRkNjk4NzQifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MDYxMDY3MDAwMDAwZTMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjg0MzM2NjQuMCwibWluIjowLjAsInN1bSI6MS4xNzI4Mzg0RTcsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA4OGJmNjU2ZTNlY2ZkMzBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMTE5NC4wLCJtaW4iOjIwOTE0LjAsInN1bSI6MTA1NDQ5LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDEzZTk1YzJkYjU1ODk1N2IifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2NzkzNDAwMDAsInZhbHVlIjp7Im1heCI6MC4xNjk0OTE1MjU0MjM3MTksIm1pbiI6MC4wLCJzdW0iOjAuNTAyODI0ODU4NzU3MDMzLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01bi4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3NTY1ODI0LjAsIm1pbiI6NzA0OTcyOC4wLCJzdW0iOjEuNDYxNTU1MkU3LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjOTMxYTYzZjhiNWVhODk4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWUyMWFiMWQzZGNkNzRiNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mjg2LjAsIm1pbiI6Mjg2LjAsInN1bSI6Mjg2LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZTc1ZjNjNDViZGMyOTg5MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NzgxNS4wLCJtaW4iOjY2MjkuMCwic3VtIjozNTYwNy4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjQ5MDY5MjRlZjliNzhiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC45ODQxNjY0RTcsIm1pbiI6OC45ODQxNjY0RTcsInN1bSI6OC45ODQxNjY0RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5MDEuMCwibWluIjo2Ny4wLCJzdW0iOjE1MzguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxOTNkZmJlMjczODZhYWExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMjI1LjAsIm1pbiI6MTU0OC4wLCJzdW0iOjg0NzQuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wODhiZjY1NmUzZWNmZDMwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzUwMjgyOS4wLCJtaW4iOjM1MDI4MjkuMCwic3VtIjozNTAyODI5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWEzNzMxZTk1ZTY0YmIzMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM1N2JjNjBkMzVlZjE4MzYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2NzkzNDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMWE3MzZhZjNiOGE1YmY0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC40NDE2NjY2NjY2NjY2NjY3LCJtaW4iOjAuNDA4MzMzMzMzMzMzMzMzMjcsInN1bSI6Mi4xMTY2NjY2NjY2NjY2NjY3LCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGEyYTk3NTBmNDQyN2FiZTcifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTAxLjAsIm1pbiI6OTAxLjAsInN1bSI6OTAxLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1MzlmOGZmNzczNzZlNTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo0NzIwLjAsIm1pbiI6MjA1OC4wLCJzdW0iOjEzNjI5LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MzgzLjAsIm1pbiI6MjY1LjAsInN1bSI6MTU4NC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE3MjQ1ODA1MDAwMDAwZWIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVTdXJwbHVzQ3JlZGl0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTYxNjYxNzMwMDAwMDBjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjg4NDIuMCwibWluIjo3Mzc5LjAsInN1bSI6Mzk0NzguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTQwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NjI0NjEzLjAsIm1pbiI6MzExMjEwLjAsInN1bSI6MTkwNDg4NC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxM2U5NWMyZGI1NTg5NTdiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVQ3JlZGl0VXNhZ2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjYmJjN2UwMjFhMTliZTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjA1ODY3LCJtaW4iOjAuMDU4NjcsInN1bSI6MC4wNTg2NywiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE0OTYwNjQuMCwibWluIjoxNDk2MDY0LjAsInN1bSI6MTQ5NjA2NC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM0MDY2NzguMCwibWluIjozNDA2Njc4LjAsInN1bSI6MzQwNjY3OC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7fSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuOTAzODY2ODhFOCwibWluIjowLjAsInN1bSI6My45MDk3NjUxMkU4LCJjb3VudCI6MjAuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZTI1ZGQ1MmJjZGU3NzI5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTVjNzVmMDE1ZjM5MDU4MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbXB1dGUtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzEzMjgzMDAwMDAwMGU2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJlYzYyZDNjNDAyZTllZWYifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxNTUxNTU5OTAwMDAwMGMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxLjAsIm1pbiI6MS4wLCJzdW0iOjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wN2RiYjRkZmI2OGIwNTZhNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTVjNzVmMDE1ZjM5MDU4MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTYwLjAsIm1pbiI6MTYwLjAsInN1bSI6MTYwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTM5ZjhmZjc3Mzc2ZTUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE2MTY2MTczMDAwMDAwY2MifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuMTI4NzkzNkU3LCJtaW4iOjE0OTYwNjQuMCwic3VtIjo0LjU5Njk0MDhFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJiNWQ0OTFmZGZjNmMxZDEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMGJjZTUyNjViYzU3MDVhMTkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuOTAzODY2ODhFOCwibWluIjowLjAsInN1bSI6My45MDk3NjUxMkU4LCJjb3VudCI6MjAuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhMmE5NzUwZjQ0MjdhYmU3In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjOTMxYTYzZjhiNWVhODk4In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODMwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6ODkxNS4wLCJtaW4iOjczMzguMCwic3VtIjozODkwMy4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoidDIubWljcm8ifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjE0Nzg4ODVFNywibWluIjozLjE0Nzg4ODVFNywic3VtIjozLjE0Nzg4ODVFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM2NzUxMzYuMCwibWluIjozNjc1MTM2LjAsInN1bSI6MzY3NTEzNi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY3ODM1YTU0ZWEzODQ3M2EifSwidGltZXN0YW1wIjoxNjUxNjc5MzQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRVc2FnZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGEyYTk3NTBmNDQyN2FiZTcifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDU3NzQ5LCJtaW4iOjAuMDU3NzQ5LCJzdW0iOjAuMDU3NzQ5LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im00LjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE2MTY2MTczMDAwMDAwY2MifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6MjQ4MC4wLCJjb3VudCI6MjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTM5ZjhmZjc3Mzc2ZTUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6Ni4wLCJtaW4iOjYuMCwic3VtIjozMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNzI0NTgwNTAwMDAwMGViIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyNzcyNDgwLjAsIm1pbiI6MTY5NDIwOC4wLCJzdW0iOjQ0NjY2ODguMCwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIzZGY3YTgyN2NiYzc2NWMifSwidGltZXN0YW1wIjoxNjUxNjc5MzQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuMCwibWluIjoxLjAsInN1bSI6NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4NDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo3NDQxLjAsIm1pbiI6NjUyNy4wLCJzdW0iOjM1MjAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzkzMWE2M2Y4YjVlYTg5OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC40MzgzMzMzMzMzMzMzMzMzLCJtaW4iOjAuMzkzMzMzMzMzMzMzMzMzMywic3VtIjoyLjA4MzMzMzMzMzMzMzMzMzUsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDE5M2RmYmUyNzM4NmFhYTEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA2MzIwMDhmZDE4OTFmNmJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTI3OS4wLCJtaW4iOjc4NjEuMCwic3VtIjo0MzM5Ny4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE3MjQ1ODA1MDAwMDAwZWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjguMCwibWluIjo4LjAsInN1bSI6OC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM5NDAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo0OTUuMCwibWluIjo0MDEuMCwic3VtIjoyMTUzLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wODhiZjY1NmUzZWNmZDMwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDYwMi4wLCJtaW4iOjkyNTAuMCwic3VtIjo0ODIxMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxYTczNmFmM2I4YTViZjRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjE1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDdkYmI0ZGZiNjhiMDU2YTYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo0OTUuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YWQuNHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlYmU2YWIzZTM3OWY0OGFmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo2LjAsIm1pbiI6Ni4wLCJzdW0iOjMwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhZTIxYWIxZDNkY2Q3NGI0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3ODk5OTM1LjAsIm1pbiI6Nzg5OTkzNS4wLCJzdW0iOjc4OTk5MzUuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVU3VycGx1c0NyZWRpdHNDaGFyZ2VkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFlMjFhYjFkM2RjZDc0YjQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjk0NSwibWluIjowLjg3MTY2NjY2NjY2NjY2NjYsInN1bSI6NC40ODE2NjY2NjY2NjY2NjcsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoiYzVuLjl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM5MzUwOTIuMCwibWluIjozOTM1MDkyLjAsInN1bSI6MzkzNTA5Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZGUzYzM2ZGNiMTIxMGQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTVjNzVmMDE1ZjM5MDU4MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjkzNzYwMC4wLCJtaW4iOjY5Mzc2MDAuMCwic3VtIjo2OTM3NjAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MjMuODEzMzMzMzMzMzMzMzMzLCJtaW4iOjIzLjgxMzMzMzMzMzMzMzMzMywic3VtIjoyMy44MTMzMzMzMzMzMzMzMzMsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzg4MDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUxNi4wLCJtaW4iOjM5NS4wLCJzdW0iOjIxNzkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MTUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjh4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUwNTUyMDMuMCwibWluIjo1MDU1MjAzLjAsInN1bSI6NTA1NTIwMy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWJlNmFiM2UzNzlmNDhhZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMzU3NzYwLjAsIm1pbiI6MTgwNjg0OC4wLCJzdW0iOjEuMDAwMDM4NEU3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEzMTA3Mi4wLCJtaW4iOjEzMTA3Mi4wLCJzdW0iOjEzMTA3Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTU1MTU1OTkwMDAwMDBjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzgyNTE1Mi4wLCJtaW4iOjM4MjUxNTIuMCwic3VtIjozODI1MTUyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTM5ZjhmZjc3Mzc2ZTUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAxLjAsIm1pbiI6MC4wLCJzdW0iOjIxMi4wLCJjb3VudCI6MTUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wN2RiYjRkZmI2OGIwNTZhNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzkzMWE2M2Y4YjVlYTg5OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1bi45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNTE0LjAsIm1pbiI6MTUxNC4wLCJzdW0iOjE1MTQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW1hZ2VJZCI6ImFtaS0wOTQwYmFiYmI1NGQ2OTg3NCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6OTI1MDQuMCwibWluIjo5MjUwNC4wLCJzdW0iOjkyNTA0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhYTM3MzFlOTVlNjRiYjMzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjE0Nzg4ODVFNywibWluIjozLjE0Nzg4ODVFNywic3VtIjozLjE0Nzg4ODVFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5MzQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMzMzg5LjAsIm1pbiI6MjE3NDUuMCwic3VtIjoxMzE2MTkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImRzZS1vcHMtZGV2LWF1dG9zY2FsaW5nLWhvc3QifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxLjA5NzEzNjdFNywibWluIjoxLjA5NzEzNjdFNywic3VtIjoxLjA5NzEzNjdFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mi41NDk3NTE4MDhFOSwibWluIjo5MTk4MDgwLjAsInN1bSI6Mi41NTg5NDk4ODhFOSwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6e30sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo4Ljc3MTMwMTk3RTgsIm1pbiI6NTExNTkuMCwic3VtIjoxLjE0MTA3Mjc2MUU5LCJjb3VudCI6MTcuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MS40OTg3N0U3LCJtaW4iOjEuMDgxODc0OEU3LCJzdW0iOjIuNTgwNjQ0OEU3LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE4MjkxMTc1MDAwMDAxMDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo0MzgwNTQwLjAsIm1pbiI6MzE4Nzg5MC4wLCJzdW0iOjEuODQwOTM2MUU3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNW4uOXhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTNlOTVjMmRiNTU4OTU3YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6NDk2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NDU4NzUyLjAsIm1pbiI6NDU4NzUyLjAsInN1bSI6NDU4NzUyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjNkZjdhODI3Y2JjNzY1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2NzkzNDAwMDAsInZhbHVlIjp7Im1heCI6OS4xMzc5MzEwMzQ1MTI4NywibWluIjoxLjY5NDkxNTI1NDIzNzI5LCJzdW0iOjE2LjIxMzU5NzIxNDExOTQ5MiwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODMwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MzgzLjAsIm1pbiI6MjY1LjAsInN1bSI6MTU4NC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxODI5MTE3NTAwMDAwMTA5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozNjc1MTM2LjAsIm1pbiI6MzY3NTEzNi4wLCJzdW0iOjM2NzUxMzYuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhMmE5NzUwZjQ0MjdhYmU3In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTI1NC4wLCJtaW4iOjAuMCwic3VtIjo1MjU0LjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4wOTY1MDFFNywibWluIjo2MTA0MDM2LjAsInN1bSI6Ny4wNzE4MzYxRTcsImNvdW50IjozLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjh4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjg0MzM2NjQuMCwibWluIjowLjAsInN1bSI6MS4xNzI4Mzg0RTcsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIzZGY3YTgyN2NiYzc2NWMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNS4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNC43MjY0MjEyMjYzMTI4OTIsIm1pbiI6OC43NTQ5OTk5OTk5OTk5OTksInN1bSI6MjMuNDgxNDIxMjI2MzEyODksImNvdW50IjoyLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA4OGJmNjU2ZTNlY2ZkMzBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjUwNDk5OTk5OTk5OTk5OTQsIm1pbiI6My41MDQ5OTk5OTk5OTk5OTk0LCJzdW0iOjMuNTA0OTk5OTk5OTk5OTk5NCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDg4YmY2NTZlM2VjZmQzMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuMzU4MzMzMzMzMzMzMzMzLCJtaW4iOjMuMzU4MzMzMzMzMzMzMzMzLCJzdW0iOjMuMzU4MzMzMzMzMzMzMzMzLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMGJjZTUyNjViYzU3MDVhMTkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Ny4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuNzMzMzMzMzMzMzMzMzMzMywibWluIjowLjQxNjY2NjY2NjY2NjY2NjYsInN1bSI6Mi41NTgzNDI5MTY4MjYzOTEsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01bi44eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMTUuMCwibWluIjowLjAsInN1bSI6MzcxLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmVjNjJkM2M0MDJlOWVlZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mi42NjMzMzMzMzMzMzMzMzMsIm1pbiI6Mi42NjMzMzMzMzMzMzMzMzMsInN1bSI6Mi42NjMzMzMzMzMzMzMzMzMsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmNDkwNjkyNGVmOWI3OGJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyNTQ4NS4wLCJtaW4iOjkxNTUuMCwic3VtIjo3NDAxMS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlYmU2YWIzZTM3OWY0OGFmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTM0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxYTczNmFmM2I4YTViZjRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmVjNjJkM2M0MDJlOWVlZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWUyMWFiMWQzZGNkNzRiNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTMxMDcyLjAsIm1pbiI6MTMxMDcyLjAsInN1bSI6MTMxMDcyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNS45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMDguMCwibWluIjowLjAsInN1bSI6MzA4LjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNDk2MDY0LjAsIm1pbiI6MTQ5NjA2NC4wLCJzdW0iOjE0OTYwNjQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE4MzUzMjIyMDAwMDAxMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI3MjMzLjAsIm1pbiI6MTY5LjAsInN1bSI6Mjc0MDIuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo2LjAzNSwibWluIjo2LjAzNSwic3VtIjo2LjAzNSwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjYmJjN2UwMjFhMTliZTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1LjAsIm1pbiI6NS4wLCJzdW0iOjUuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzE1LjAsIm1pbiI6MC4wLCJzdW0iOjM3MS4wLCJjb3VudCI6NC4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlYmU2YWIzZTM3OWY0OGFmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5Mi4wLCJtaW4iOjAuMCwic3VtIjoyMDEuMCwiY291bnQiOjE1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuODA4Nzc0NUU3LCJtaW4iOjIuODA4Nzc0NUU3LCJzdW0iOjIuODA4Nzc0NUU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc3ODQ4MDUuMCwibWluIjo3Nzg0ODA1LjAsInN1bSI6Nzc4NDgwNS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZGUzYzM2ZGNiMTIxMGQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01LjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc4OTk5MzUuMCwibWluIjo3ODk5OTM1LjAsInN1bSI6Nzg5OTkzNS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhYTM3MzFlOTVlNjRiYjMzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDg4YmY2NTZlM2VjZmQzMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUwNTUyMDMuMCwibWluIjo1MDU1MjAzLjAsInN1bSI6NTA1NTIwMy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDI5ZThiOTE4OTM1MTA2NzIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEzMjg0LjAsIm1pbiI6MTI0NTcuMCwic3VtIjo2NDU1Ni4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbXB1dGUtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzEzMjgzMDAwMDAwMGU2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUuMDk2NTAxRTcsIm1pbiI6NS4wOTY1MDFFNywic3VtIjo1LjA5NjUwMUU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDg4YmY2NTZlM2VjZmQzMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo0OTUuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjg5OGM5YjFjNTExZWI0MSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mi41NDk3NTE4MDhFOSwibWluIjoyLjU0OTc1MTgwOEU5LCJzdW0iOjIuNTQ5NzUxODA4RTksImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM5MzFhNjNmOGI1ZWE4OTgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYzMTAyMi4wLCJtaW4iOjMyMDExOC4wLCJzdW0iOjE5NTY4MTQuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjgxMDk4MzUuMCwibWluIjo1MjM0MDczLjAsInN1bSI6MS4zMzQzOTA4RTcsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxODAwOC4wLCJtaW4iOjE1NjQyLjAsInN1bSI6ODM2ODguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc0NDEuMCwibWluIjo2NTI3LjAsInN1bSI6MzUyMDAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29tcHV0ZS1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MTMyODMwMDAwMDAwZTYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ2MzY2NDAuMCwibWluIjozOTM1MDkyLjAsInN1bSI6ODU3MTczMi4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1MzlmOGZmNzczNzZlNTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU0NzMyOC4wLCJtaW4iOjAuMCwic3VtIjoxMzQ2MDQ4LjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzA2MTA2NzAwMDAwMGUzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxNjg3NC4wLCJtaW4iOjEzODM1LjAsInN1bSI6NzY5NTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnt9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTI1NC4wLCJtaW4iOjAuMCwic3VtIjo1MjYyLjAsImNvdW50IjoyMC4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE2OS4wLCJtaW4iOjE2OS4wLCJzdW0iOjE2OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE2NTAuMCwibWluIjoxNjUwLjAsInN1bSI6ODI1MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWEuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mjc3MjQ4MC4wLCJtaW4iOjI3NzI0ODAuMCwic3VtIjoyNzcyNDgwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MTAuMDExNjY2NjY2NjY2NjY3LCJtaW4iOjEwLjAxMTY2NjY2NjY2NjY2Nywic3VtIjoxMC4wMTE2NjY2NjY2NjY2NjcsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9Cg==\"\n    },\n    {\n      \"data\": \"eyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkZTQ5NDFiNzdlODE3YTEzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhMmUxMmZhYWVlMjE2NTg3In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkYzJkODk1NzY5OTFiZGE4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWNiOGQxZTdmMzFlYjg0MyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNmQwZTdmZDYxZGZmMjM0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6NjAuMCwibWluIjo2MC4wLCJzdW0iOjYwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjJiMGQ1MWEzMTFkMzI1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTUsIm1pbiI6NTkuOTUsInN1bSI6NTkuOTUsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAyMjU2ODFkOTQwOWI2YTVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjI1MDc4OSwibWluIjowLjI1MDc4OSwic3VtIjowLjI1MDc4OSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRlNDk0MWI3N2U4MTdhMTMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMyMC4wLCJtaW4iOjMyMC4wLCJzdW0iOjMyMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGU2Y2IzYmIxZmE1ZDBhNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMzE0MDA3LCJtaW4iOjAuMzE0MDA3LCJzdW0iOjAuMzE0MDA3LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMjk1OTksIm1pbiI6MC4wMjk1OTksInN1bSI6MC4wMjk1OTksImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGYzOTM0M2IzNDI2MWZjZTQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDA3NjY3LCJtaW4iOjAuMDA3NjY3LCJzdW0iOjAuMDA3NjY3LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWNiOGQxZTdmMzFlYjg0MyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMDkyOTQ2LCJtaW4iOjYwLjA5Mjk0Niwic3VtIjo2MC4wOTI5NDYsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3ZTU1YjZlODE5MjkxMDlhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozNzEuMCwibWluIjozNzEuMCwic3VtIjozNzEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmYTRkNGVjNTc2MzgyNGEwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDMxZDJmYWU1ZDYxNzNjYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOWFhZGVjNzRjZDc3OWY0OSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS41NTMzNjQsIm1pbiI6NS41NTMzNjQsInN1bSI6NS41NTMzNjQsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBiMDU5OWRkNGQxNDEyN2ExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxLjY2NjY2NjY2NjY2NjY3RS00LCJtaW4iOjEuNjY2NjY2NjY2NjY2NjdFLTQsInN1bSI6MS42NjY2NjY2NjY2NjY2N0UtNCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDE0MTY5MTEzMTQ5M2I2Y2UifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDgxYTMyMjUzOGI3OTdlYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMTI2MTA2LCJtaW4iOjAuMTI2MTA2LCJzdW0iOjAuMTI2MTA2LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTU5Mzc3LCJtaW4iOjU5Ljk1OTM3Nywic3VtIjo1OS45NTkzNzcsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4N2I0YzBiODNmYmVmZDM1In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjI1MzQ1NiwibWluIjowLjI1MzQ1Niwic3VtIjowLjI1MzQ1NiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQ0YTYxZjVlNDQzYzc2ZGIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU5Ljk4MzE4MywibWluIjo1OS45ODMxODMsInN1bSI6NTkuOTgzMTgzLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5NDg3OGFjMzMzMTkyNGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGIwNTk5ZGQ0ZDE0MTI3YTEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wMSwiY291bnQiOjE1LjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjA5OTkyNCwibWluIjowLjA5OTkyNCwic3VtIjowLjA5OTkyNCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4MWEzMjI1MzhiNzk3ZWMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGJkMTYxMzc5NjE3YzE3YzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODFhMzIyNTM4Yjc5N2VjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDE5NTMxMjUsIm1pbiI6MC4wMDE5NTMxMjUsInN1bSI6MC4wMDE5NTMxMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGMyZDg5NTc2OTkxYmRhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMTMzNzAxLCJtaW4iOjYwLjEzMzcwMSwic3VtIjo2MC4xMzM3MDEsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDM1NjVmNWNmYjNhMDdiZmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQzNjIzNzgwNDhmNzEwNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDIyNTY4MWQ5NDA5YjZhNWMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAxMjE1LCJtaW4iOjAuMDAxMjE1LCJzdW0iOjAuMDAxMjE1LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzg3NjkxMWIxNDEwMTQ3ZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDhhNjQxY2RiZTc0NjRmZDgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRjODA3YzA5ZmFlYjMxZDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGU0OTQxYjc3ZTgxN2ExMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkZTQ5NDFiNzdlODE3YTEzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJCdXJzdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMTI3ZTdiMDUwMDMxMjY2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjoxMDAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJCdXJzdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAxMmJmNmY4ZGYxYTdkM2JkIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6OTkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZjM5MzQzYjM0MjYxZmNlNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Ny4wLCJtaW4iOjcuMCwic3VtIjo3LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4xNDEwMDMsIm1pbiI6MC4xNDEwMDMsInN1bSI6MC4xNDEwMDMsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMjMuMCwibWluIjoxMjMuMCwic3VtIjoxMjMuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGM4NzY5MTFiMTQxMDE0N2YifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkYzJkODk1NzY5OTFiZGE4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMzY0ZDFjZTcxYWE0MWQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4wMjE0NTYsIm1pbiI6NjAuMDIxNDU2LCJzdW0iOjYwLjAyMTQ1NiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDEyYmY2ZjhkZjFhN2QzYmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDA1ODU5Mzc1LCJtaW4iOjAuMDA1ODU5Mzc1LCJzdW0iOjAuMDA1ODU5Mzc1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZhN2IzODQ2ODBlYjQzNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBiZDE2MTM3OTYxN2MxN2MzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmYTRkNGVjNTc2MzgyNGEwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmODQwOTgyMzk2NTllMmQyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkMjg1MDFlMTUyN2E1YjQ2In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4xNzExMDksIm1pbiI6NjAuMTcxMTA5LCJzdW0iOjYwLjE3MTEwOSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2JiMWY2ZTk0NjVhYTI2ZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTQxNjkxMTMxNDkzYjZjZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2YTdiMzg0NjgwZWI0MzQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTY2ODc1LCJtaW4iOjU5Ljk2Njg3NSwic3VtIjo1OS45NjY4NzUsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMjgxY2ViODY4MmIzYjhlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45MSwibWluIjo1OS45MSwic3VtIjo1OS45MSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU5Ljg2LCJtaW4iOjU5Ljg2LCJzdW0iOjU5Ljg2LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzEyN2U3YjA1MDAzMTI2NiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDMsIm1pbiI6MC4wMDMsInN1bSI6MC4wMDMsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjJiMGQ1MWEzMTFkMzI1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMzFkMmZhZTVkNjE3M2NhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTJiZjZmOGRmMWE3ZDNiZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTQxNjkxMTMxNDkzYjZjZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6NTkuODcsIm1pbiI6NTkuODcsInN1bSI6NTkuODcsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2ZDBlN2ZkNjFkZmYyMzRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxLjY2NjY2NjY2NjY2NjY3RS00LCJtaW4iOjEuNjY2NjY2NjY2NjY2NjdFLTQsInN1bSI6MS42NjY2NjY2NjY2NjY2N0UtNCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDYwZDdlNWQwZTQ3NzFhNTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTZjYjNiYjFmYTVkMGE0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmODQwOTgyMzk2NTllMmQyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAzMWQyZmFlNWQ2MTczY2EifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGY4NDA5ODIzOTY1OWUyZDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAxNDE2OTExMzE0OTNiNmNlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjU5NzE0NTYuMCwiY291bnQiOjIwMy4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZmE0ZDRlYzU3NjM4MjRhMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MmIwZDUxYTMxMWQzMjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjE2NzQyNC4wLCJjb3VudCI6MzMuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg3YjRjMGI4M2ZiZWZkMzUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNmQwZTdmZDYxZGZmMjM0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAxLCJjb3VudCI6NjAuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDVhOTUyYmU0MGJlMjMyZmYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAyOTI5Njg3NSwibWluIjowLjAwMjkyOTY4NzUsInN1bSI6MC4wMDI5Mjk2ODc1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGM4MDdjMDlmYWViMzFkMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTZjYjNiYjFmYTVkMGE0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzA4LjAsIm1pbiI6MzA4LjAsInN1bSI6MzA4LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDRhNjFmNWU0NDNjNzZkYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OS43NjU2MjVFLTQsIm1pbiI6OS43NjU2MjVFLTQsInN1bSI6OS43NjU2MjVFLTQsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMjI1NjgxZDk0MDliNmE1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDM5MDYyNSwibWluIjowLjAwMzkwNjI1LCJzdW0iOjAuMDAzOTA2MjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDYwZDdlNWQwZTQ3NzFhNTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjODc2OTExYjE0MTAxNDdmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDkxYjAzNzUyYzM4ZWYzNTIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MTUyMDY0LjAsImNvdW50IjoyMS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBlOTA0MDE4YjI0MTZmOGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45OTEwODQsIm1pbiI6NTkuOTkxMDg0LCJzdW0iOjU5Ljk5MTA4NCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRjMmQ4OTU3Njk5MWJkYTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOGE2NDFjZGJlNzQ2NGZkOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAxMmJmNmY4ZGYxYTdkM2JkIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjM3NTgyMiwibWluIjowLjM3NTgyMiwic3VtIjowLjM3NTgyMiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3NDhjNWZiYjMxMTUwY2MzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkMzYyMzc4MDQ4ZjcxMDZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4xNjU0MjgsIm1pbiI6NjAuMTY1NDI4LCJzdW0iOjYwLjE2NTQyOCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWE5NTJiZTQwYmUyMzJmZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4NTJkZWFhOTU3ODk3NDllIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45NDUzMjMsIm1pbiI6NTkuOTQ1MzIzLCJzdW0iOjU5Ljk0NTMyMywiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZlNmMwZTI5M2ZlNzM4MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMzU2NWY1Y2ZiM2EwN2JmYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4xNDIxOTgsIm1pbiI6MC4xNDIxOTgsInN1bSI6MC4xNDIxOTgsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZhN2IzODQ2ODBlYjQzNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjODc2OTExYjE0MTAxNDdmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4xNzExMDgsIm1pbiI6NjAuMTcxMTA4LCJzdW0iOjYwLjE3MTEwOCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZhN2IzODQ2ODBlYjQzNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDkxYjAzNzUyYzM4ZWYzNTIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjJiMGQ1MWEzMTFkMzI1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAyMiwiY291bnQiOjMzLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDk5MDUzMmMyNTczZDBlMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBiMDU5OWRkNGQxNDEyN2ExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxNS4wLCJtaW4iOjE1LjAsInN1bSI6MTUuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhNmE3YjM4NDY4MGViNDM0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4wOTI5NDYsIm1pbiI6NjAuMDkyOTQ2LCJzdW0iOjYwLjA5Mjk0NiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDdiYjFmNmU5NDY1YWEyNmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE1MTQuMCwibWluIjoxNTE0LjAsInN1bSI6MTUxNC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDI4MWNlYjg2ODJiM2I4ZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjo1ODg4MDAuMCwiY291bnQiOjEwNy4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDI4MWNlYjg2ODJiM2I4ZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjo0NjIzMzYuMCwiY291bnQiOjc5LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDM1NjVmNWNmYjNhMDdiZmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGMzNjRkMWNlNzFhYTQxZDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEzNy4wLCJtaW4iOjEzNy4wLCJzdW0iOjEzNy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNzQ4YzVmYmIzMTE1MGNjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTQxNjkxMTMxNDkzYjZjZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MjAzLjAsIm1pbiI6MjAzLjAsInN1bSI6MjAzLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1Y2I4ZDFlN2YzMWViODQzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTJiZjZmOGRmMWE3ZDNiZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQzNjIzNzgwNDhmNzEwNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkNGE2MWY1ZTQ0M2M3NmRiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1YTk1MmJlNDBiZTIzMmZmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjIxOTg5NiwibWluIjowLjIxOTg5Niwic3VtIjowLjIxOTg5NiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRlNDk0MWI3N2U4MTdhMTMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAzOTA2MjUsIm1pbiI6MC4wMDM5MDYyNSwic3VtIjowLjAwMzkwNjI1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDVhOTUyYmU0MGJlMjMyZmYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU5LjkyNjE0MywibWluIjo1OS45MjYxNDMsInN1bSI6NTkuOTI2MTQzLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTJiZjZmOGRmMWE3ZDNiZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuODM0MDg3LCJtaW4iOjU5LjgzNDA4Nywic3VtIjo1OS44MzQwODcsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDE1MWYzOTc5YzBmZjEwOWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjg0MzM2NjQuMCwibWluIjo4NDMzNjY0LjAsInN1bSI6ODQzMzY2NC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NDAzOTY4LjAsIm1pbiI6NDAzOTY4LjAsInN1bSI6NDAzOTY4LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGM4NzY5MTFiMTQxMDE0N2YifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjBkN2U1ZDBlNDc3MWE1OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4xNjE2NTcsIm1pbiI6MC4xNjE2NTcsInN1bSI6MC4xNjE2NTcsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRjMmQ4OTU3Njk5MWJkYTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2YTdiMzg0NjgwZWI0MzQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2ZTZjMGUyOTNmZTczODAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE3LjAsIm1pbiI6MTcuMCwic3VtIjoxNy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTJiZjZmOGRmMWE3ZDNiZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5YWFkZWM3NGNkNzc5ZjQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMTIuODkyNDA5LCJtaW4iOjExMi44OTI0MDksInN1bSI6MTEyLjg5MjQwOSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmYTRkNGVjNTc2MzgyNGEwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMzFkMmZhZTVkNjE3M2NhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMTUuMCwibWluIjozMTUuMCwic3VtIjozMTUuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDk0ODc4YWMzMzMxOTI0ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGEyZTEyZmFhZWUyMTY1ODcifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMzU2NWY1Y2ZiM2EwN2JmYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZjg0MDk4MjM5NjU5ZTJkMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4N2I0YzBiODNmYmVmZDM1In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo0MDEuMCwibWluIjo0MDEuMCwic3VtIjo0MDEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDc0OGM1ZmJiMzExNTBjYzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTkwNDAxOGIyNDE2ZjhlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDI5Mjk2ODc1LCJtaW4iOjAuMDAyOTI5Njg3NSwic3VtIjowLjAwMjkyOTY4NzUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmODQwOTgyMzk2NTllMmQyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MGQ3ZTVkMGU0NzcxYTU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg3YjRjMGI4M2ZiZWZkMzUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAzOTA2MjUsIm1pbiI6MC4wMDM5MDYyNSwic3VtIjowLjAwMzkwNjI1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOTQ4NzhhYzMzMzE5MjRlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MjA1MzYzMi4wLCJtaW4iOjIwNTM2MzIuMCwic3VtIjoyMDUzNjMyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDk5MDUzMmMyNTczZDBlMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMzg5MzksIm1pbiI6MC4wMzg5MzksInN1bSI6MC4wMzg5MzksImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5MWIwMzc1MmMzOGVmMzUyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoyMS4wLCJtaW4iOjIxLjAsInN1bSI6MjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAzNTY1ZjVjZmIzYTA3YmZhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNjkuMCwibWluIjoxNjkuMCwic3VtIjoxNjkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhNmE3YjM4NDY4MGViNDM0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODdiNGMwYjgzZmJlZmQzNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMTI3ZTdiMDUwMDMxMjY2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBiZDE2MTM3OTYxN2MxN2MzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MGQ3ZTVkMGU0NzcxYTU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjlmMjlmNTEwYzY3ZjlhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODUyZGVhYTk1Nzg5NzQ5ZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MjczLjAsIm1pbiI6MjczLjAsInN1bSI6MjczLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4MWEzMjI1MzhiNzk3ZWMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAzMWQyZmFlNWQ2MTczY2EifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDA0ODgyODEyNSwibWluIjowLjAwNDg4MjgxMjUsInN1bSI6MC4wMDQ4ODI4MTI1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2ZTZjMGUyOTNmZTczODAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTJlMTJmYWFlZTIxNjU4NyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2OWYyOWY1MTBjNjdmOWE4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTJlMTJmYWFlZTIxNjU4NyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4MWEzMjI1MzhiNzk3ZWMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMTkuMCwibWluIjoxMTkuMCwic3VtIjoxMTkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDY5ZjI5ZjUxMGM2N2Y5YTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDM2MjM3ODA0OGY3MTA2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTcuMCwibWluIjoxNy4wLCJzdW0iOjE3LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBlNmNiM2JiMWZhNWQwYTRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGM4MDdjMDlmYWViMzFkMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MGQ3ZTVkMGU0NzcxYTU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4xMzM3MDEsIm1pbiI6NjAuMTMzNzAxLCJzdW0iOjYwLjEzMzcwMSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDhhNjQxY2RiZTc0NjRmZDgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTQxNjkxMTMxNDkzYjZjZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDU4MzMzMzMzMzMzMzMzMywibWluIjowLjAwNTgzMzMzMzMzMzMzMzMzLCJzdW0iOjAuMDA1ODMzMzMzMzMzMzMzMzMsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MGQ3ZTVkMGU0NzcxYTU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMzFkMmZhZTVkNjE3M2NhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjMzMzU3OCwibWluIjowLjMzMzU3OCwic3VtIjowLjMzMzU3OCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQ0YTYxZjVlNDQzYzc2ZGIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjY3LjAsIm1pbiI6NjcuMCwic3VtIjo2Ny4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGM4NzY5MTFiMTQxMDE0N2YifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGU0OTQxYjc3ZTgxN2ExMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4yODM0OTEsIm1pbiI6MC4yODM0OTEsInN1bSI6MC4yODM0OTEsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkMjg1MDFlMTUyN2E1YjQ2In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhNmU2YzBlMjkzZmU3MzgwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAxMTI3NywibWluIjowLjAxMTI3Nywic3VtIjowLjAxMTI3NywiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhMmUxMmZhYWVlMjE2NTg3In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3NDhjNWZiYjMxMTUwY2MzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmYTRkNGVjNTc2MzgyNGEwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMjI1NjgxZDk0MDliNmE1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzgyNTE1Mi4wLCJtaW4iOjM4MjUxNTIuMCwic3VtIjozODI1MTUyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDRhNjFmNWU0NDNjNzZkYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wODg5MzgsIm1pbiI6MC4wODg5MzgsInN1bSI6MC4wODg5MzgsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmMzkzNDNiMzQyNjFmY2U0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAxNDY0ODQzNzUsIm1pbiI6MC4wMTQ2NDg0Mzc1LCJzdW0iOjAuMDE0NjQ4NDM3NSwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGMyZDg5NTc2OTkxYmRhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5NDg3OGFjMzMzMTkyNGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAwNDg4MjgxMjUsIm1pbiI6MC4wMDQ4ODI4MTI1LCJzdW0iOjAuMDA0ODgyODEyNSwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDA5OTA1MzJjMjU3M2QwZTIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOTQ4NzhhYzMzMzE5MjRlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4zMzE1OTYsIm1pbiI6MC4zMzE1OTYsInN1bSI6MC4zMzE1OTYsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDZkMGU3ZmQ2MWRmZjIzNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDI4NTAxZTE1MjdhNWI0NiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZjg0MDk4MjM5NjU5ZTJkMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDYwZDdlNWQwZTQ3NzFhNTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQyODUwMWUxNTI3YTViNDYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGMyZDg5NTc2OTkxYmRhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGMxMjdlN2IwNTAwMzEyNjYifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MjczMDQ5Ni4wLCJjb3VudCI6MTE0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMTI0ODE4LCJtaW4iOjYwLjEyNDgxOCwic3VtIjo2MC4xMjQ4MTgsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQzNjIzNzgwNDhmNzEwNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGZhNGQ0ZWM1NzYzODI0YTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYwLjAwNDQxNSwibWluIjo2MC4wMDQ0MTUsInN1bSI6NjAuMDA0NDE1LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQo=\"\n    },\n    {\n      \"data\": \"eyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2U1NWI2ZTgxOTI5MTA5YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTZjYjNiYjFmYTVkMGE0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDQ4ODI4MTI1LCJtaW4iOjAuMDA0ODgyODEyNSwic3VtIjowLjAwNDg4MjgxMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOGE2NDFjZGJlNzQ2NGZkOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzM2NGQxY2U3MWFhNDFkOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDE5NTMxMjUsIm1pbiI6MC4wMDE5NTMxMjUsInN1bSI6MC4wMDE5NTMxMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzg3NjkxMWIxNDEwMTQ3ZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRjODA3YzA5ZmFlYjMxZDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYjA1OTlkZDRkMTQxMjdhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjoxMDM0MjQuMCwiY291bnQiOjE1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMzY0ZDFjZTcxYWE0MWQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDc0OGM1ZmJiMzExNTBjYzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYwLjAwNDQxNSwibWluIjo2MC4wMDQ0MTUsInN1bSI6NjAuMDA0NDE1LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2ZTZjMGUyOTNmZTczODAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo5OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg1MmRlYWE5NTc4OTc0OWUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWE5NTJiZTQwYmUyMzJmZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTgzODA4MC4wLCJtaW4iOjE4MzgwODAuMCwic3VtIjoxODM4MDgwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNjk0MjA4LjAsIm1pbiI6MTY5NDIwOC4wLCJzdW0iOjE2OTQyMDguMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOTQ4NzhhYzMzMzE5MjRlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDE5NTMxMjUsIm1pbiI6MC4wMDE5NTMxMjUsInN1bSI6MC4wMDE5NTMxMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTYuMCwibWluIjo1Ni4wLCJzdW0iOjU2LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBlOTA0MDE4YjI0MTZmOGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxODQzMjAwLjAsIm1pbiI6MTg0MzIwMC4wLCJzdW0iOjE4NDMyMDAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmMzkzNDNiMzQyNjFmY2U0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS44NzQ5MDgsIm1pbiI6NTkuODc0OTA4LCJzdW0iOjU5Ljg3NDkwOCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3ZTU1YjZlODE5MjkxMDlhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGIwNTk5ZGQ0ZDE0MTI3YTEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGMyZDg5NTc2OTkxYmRhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWNiOGQxZTdmMzFlYjg0MyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5MWIwMzc1MmMzOGVmMzUyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4YTY0MWNkYmU3NDY0ZmQ4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2MC4wMDMwNzIsIm1pbiI6NjAuMDAzMDcyLCJzdW0iOjYwLjAwMzA3MiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJCdXJzdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkMjg1MDFlMTUyN2E1YjQ2In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjoxMDAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg1MmRlYWE5NTc4OTc0OWUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMjY5MDc5LCJtaW4iOjAuMjY5MDc5LCJzdW0iOjAuMjY5MDc5LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDlhYWRlYzc0Y2Q3NzlmNDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuOTAzODY2ODhFOCwibWluIjozLjkwMzg2Njg4RTgsInN1bSI6My45MDM4NjY4OEU4LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZlNmMwZTI5M2ZlNzM4MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg3YjRjMGI4M2ZiZWZkMzUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODFhMzIyNTM4Yjc5N2VjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMjgxY2ViODY4MmIzYjhlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTZjYjNiYjFmYTVkMGE0YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzkwNTAyNC4wLCJtaW4iOjM5MDUwMjQuMCwic3VtIjozOTA1MDI0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTZlNmMwZTI5M2ZlNzM4MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMDg3MDk3LCJtaW4iOjYwLjA4NzA5Nywic3VtIjo2MC4wODcwOTcsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg1MmRlYWE5NTc4OTc0OWUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGM4MDdjMDlmYWViMzFkMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDMxZDJmYWU1ZDYxNzNjYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTIzMTYxLCJtaW4iOjU5LjkyMzE2MSwic3VtIjo1OS45MjMxNjEsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMTI3ZTdiMDUwMDMxMjY2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoxMTQuMCwibWluIjoxMTQuMCwic3VtIjoxMTQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5NDg3OGFjMzMzMTkyNGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS44MzAzMDQsIm1pbiI6NTkuODMwMzA0LCJzdW0iOjU5LjgzMDMwNCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAyMjU2ODFkOTQwOWI2YTVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMzEwNzIuMCwibWluIjoxMzEwNzIuMCwic3VtIjoxMzEwNzIuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDY5ZjI5ZjUxMGM2N2Y5YTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDdiYjFmNmU5NDY1YWEyNmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuNDM2ODYzLCJtaW4iOjMuNDM2ODYzLCJzdW0iOjMuNDM2ODYzLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4YTY0MWNkYmU3NDY0ZmQ4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1YTk1MmJlNDBiZTIzMmZmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyOTUuMCwibWluIjoyOTUuMCwic3VtIjoyOTUuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzM2NGQxY2U3MWFhNDFkOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDdiYjFmNmU5NDY1YWEyNmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZmE0ZDRlYzU3NjM4MjRhMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2JiMWY2ZTk0NjVhYTI2ZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wNTY2NDA2MjUsIm1pbiI6MC4wNTY2NDA2MjUsInN1bSI6MC4wNTY2NDA2MjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2U1NWI2ZTgxOTI5MTA5YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTQ0NzM1LCJtaW4iOjU5Ljk0NDczNSwic3VtIjo1OS45NDQ3MzUsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwOTkwNTMyYzI1NzNkMGUyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1Ni4wLCJtaW4iOjU2LjAsInN1bSI6NTYuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGY4NDA5ODIzOTY1OWUyZDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3NDhjNWZiYjMxMTUwY2MzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOGE2NDFjZGJlNzQ2NGZkOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDg3YjRjMGI4M2ZiZWZkMzUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo5OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3ZTU1YjZlODE5MjkxMDlhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDEyYmY2ZjhkZjFhN2QzYmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUxNi4wLCJtaW4iOjUxNi4wLCJzdW0iOjUxNi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDc0OGM1ZmJiMzExNTBjYzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZmE0ZDRlYzU3NjM4MjRhMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDlhYWRlYzc0Y2Q3NzlmNDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjUyNTQuMCwibWluIjo1MjU0LjAsInN1bSI6NTI1NC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDY5ZjI5ZjUxMGM2N2Y5YTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGEyZTEyZmFhZWUyMTY1ODcifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkNGE2MWY1ZTQ0M2M3NmRiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNDk2MDY0LjAsIm1pbiI6MTQ5NjA2NC4wLCJzdW0iOjE0OTYwNjQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkYzgwN2MwOWZhZWIzMWQzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzg3NjkxMWIxNDEwMTQ3ZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDdlNTViNmU4MTkyOTEwOWEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIxNTA5MTIuMCwibWluIjoyMTUwOTEyLjAsInN1bSI6MjE1MDkxMi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDVjYjhkMWU3ZjMxZWI4NDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGIwNTk5ZGQ0ZDE0MTI3YTEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU5Ljk5LCJtaW4iOjU5Ljk5LCJzdW0iOjU5Ljk5LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTYwLjAsIm1pbiI6MTYwLjAsInN1bSI6MTYwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjlmMjlmNTEwYzY3ZjlhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMDA0NDE1LCJtaW4iOjYwLjAwNDQxNSwic3VtIjo2MC4wMDQ0MTUsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDA5OTA1MzJjMjU3M2QwZTIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM1NTg0MC4wLCJtaW4iOjM1NTg0MC4wLCJzdW0iOjM1NTg0MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4xNjUsImNvdW50IjoxMDcuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4xMDUsImNvdW50Ijo3OS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDk0ODc4YWMzMzMxOTI0ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo5OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4NTJkZWFhOTU3ODk3NDllIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDRhNjFmNWU0NDNjNzZkYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDI4NTAxZTE1MjdhNWI0NiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzM2NGQxY2U3MWFhNDFkOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4xMjgxMywibWluIjowLjEyODEzLCJzdW0iOjAuMTI4MTMsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1Y2I4ZDFlN2YzMWViODQzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjkzNzYwMC4wLCJtaW4iOjY5Mzc2MDAuMCwic3VtIjo2OTM3NjAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGU2Y2IzYmIxZmE1ZDBhNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2JiMWY2ZTk0NjVhYTI2ZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC45ODQxNjY0RTcsIm1pbiI6OC45ODQxNjY0RTcsInN1bSI6OC45ODQxNjY0RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTkwNDAxOGIyNDE2ZjhlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTU5OTk5LCJtaW4iOjU5Ljk1OTk5OSwic3VtIjo1OS45NTk5OTksImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDVjYjhkMWU3ZjMxZWI4NDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjBkN2U1ZDBlNDc3MWE1OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDI4NTAxZTE1MjdhNWI0NiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2U1NWI2ZTgxOTI5MTA5YSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjk5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5MWIwMzc1MmMzOGVmMzUyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45OSwibWluIjo1OS45OSwic3VtIjo1OS45OSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWE5NTJiZTQwYmUyMzJmZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNzQ4YzVmYmIzMTE1MGNjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAxNDE2OTExMzE0OTNiNmNlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMzUsImNvdW50IjoyMDMuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzM2NGQxY2U3MWFhNDFkOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGYzOTM0M2IzNDI2MWZjZTQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ1ODc1Mi4wLCJtaW4iOjQ1ODc1Mi4wLCJzdW0iOjQ1ODc1Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhNmU2YzBlMjkzZmU3MzgwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDY5ZjI5ZjUxMGM2N2Y5YTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYTJlMTJmYWFlZTIxNjU4NyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMDk2NTAzLCJtaW4iOjYwLjA5NjUwMywic3VtIjo2MC4wOTY1MDMsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MmIwZDUxYTMxMWQzMjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjozMy4wLCJtaW4iOjMzLjAsInN1bSI6MzMuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2ZTZjMGUyOTNmZTczODAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE0Nzk2OC4wLCJtaW4iOjE0Nzk2OC4wLCJzdW0iOjE0Nzk2OC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDY5ZjI5ZjUxMGM2N2Y5YTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMDkyOGM3ZDQyYTM3ZjliIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5Ljc2NTYyNUUtNCwibWluIjo5Ljc2NTYyNUUtNCwic3VtIjo5Ljc2NTYyNUUtNCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYjA1OTlkZDRkMTQxMjdhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6MTAwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBjMTI3ZTdiMDUwMDMxMjY2In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMTgsImNvdW50IjoxMTQuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDA5OTA1MzJjMjU3M2QwZTIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMzU2NWY1Y2ZiM2EwN2JmYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NzU2NTgyNC4wLCJtaW4iOjc1NjU4MjQuMCwic3VtIjo3NTY1ODI0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNTQ2NTBjMDgzODdmYmFjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDE5NTMxMjUsIm1pbiI6MC4wMDE5NTMxMjUsInN1bSI6MC4wMDE5NTMxMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMzFkMmZhZTVkNjE3M2NhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMjk0NzIwLjAsIm1pbiI6MzI5NDcyMC4wLCJzdW0iOjMyOTQ3MjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMTUxZjM5NzljMGZmMTA5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTYuMCwibWluIjo1Ni4wLCJzdW0iOjU2LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGMyZDg5NTc2OTkxYmRhOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3ZTU1YjZlODE5MjkxMDlhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjI0NjI0NSwibWluIjowLjI0NjI0NSwic3VtIjowLjI0NjI0NSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzg3NjkxMWIxNDEwMTQ3ZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDgxYTMyMjUzOGI3OTdlYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI3NzI0ODAuMCwibWluIjoyNzcyNDgwLjAsInN1bSI6Mjc3MjQ4MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDdlNTViNmU4MTkyOTEwOWEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAzOTA2MjUsIm1pbiI6MC4wMDM5MDYyNSwic3VtIjowLjAwMzkwNjI1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNjJiMGQ1MWEzMTFkMzI1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVF1ZXVlTGVuZ3RoIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wOTFiMDM3NTJjMzhlZjM1MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MS42NjY2NjY2NjY2NjY2N0UtNCwibWluIjoxLjY2NjY2NjY2NjY2NjY3RS00LCJzdW0iOjEuNjY2NjY2NjY2NjY2NjdFLTQsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQzNjIzNzgwNDhmNzEwNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo5OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsUmVhZFRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5YWFkZWM3NGNkNzc5ZjQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo4NS4yOTkzMjYsIm1pbiI6ODUuMjk5MzI2LCJzdW0iOjg1LjI5OTMyNiwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGMxMjdlN2IwNTAwMzEyNjYifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU5Ljk1LCJtaW4iOjU5Ljk1LCJzdW0iOjU5Ljk1LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2YTdiMzg0NjgwZWI0MzQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwNy4wLCJtaW4iOjEwNy4wLCJzdW0iOjEwNy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAyODFjZWI4NjgyYjNiOGUifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjc5LjAsIm1pbiI6NzkuMCwic3VtIjo3OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDIyNTY4MWQ5NDA5YjZhNWMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI4Ni4wLCJtaW4iOjI4Ni4wLCJzdW0iOjI4Ni4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJCdXJzdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1YTk1MmJlNDBiZTIzMmZmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6OTkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGRjODA3YzA5ZmFlYjMxZDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYwLjAwMzA3MiwibWluIjo2MC4wMDMwNzIsInN1bSI6NjAuMDAzMDcyLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA1Y2I4ZDFlN2YzMWViODQzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMjgxY2ViODY4MmIzYjhlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAwMjgxY2ViODY4MmIzYjhlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA3YmIxZjZlOTQ2NWFhMjZkIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS4zOTE5MzksIm1pbiI6NTkuMzkxOTM5LCJzdW0iOjU5LjM5MTkzOSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGU5MDQwMThiMjQxNmY4ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMTk1ODY0LCJtaW4iOjAuMTk1ODY0LCJzdW0iOjAuMTk1ODY0LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmMzkzNDNiMzQyNjFmY2U0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyLjEyODc5MzZFNywibWluIjoyLjEyODc5MzZFNywic3VtIjoyLjEyODc5MzZFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDA5OTA1MzJjMjU3M2QwZTIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMjI1NjgxZDk0MDliNmE1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTQ1OTIxLCJtaW4iOjU5Ljk0NTkyMSwic3VtIjo1OS45NDU5MjEsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBlNmNiM2JiMWZhNWQwYTRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45MTg5MTgsIm1pbiI6NTkuOTE4OTE4LCJzdW0iOjU5LjkxODkxOCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGYzOTM0M2IzNDI2MWZjZTQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuOTI3ODk0LCJtaW4iOjAuOTI3ODk0LCJzdW0iOjAuOTI3ODk0LCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGU5MDQwMThiMjQxNmY4ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo5OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDk5MDUzMmMyNTczZDBlMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjAuMDgyNTAyLCJtaW4iOjYwLjA4MjUwMiwic3VtIjo2MC4wODI1MDIsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lSWRsZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkZTQ5NDFiNzdlODE3YTEzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1OS45Mzk5OTEsIm1pbiI6NTkuOTM5OTkxLCJzdW0iOjU5LjkzOTk5MSwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDk0ODc4YWMzMzMxOTI0ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQxMC4wLCJtaW4iOjQxMC4wLCJzdW0iOjQxMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGE2YTdiMzg0NjgwZWI0MzQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkMzYyMzc4MDQ4ZjcxMDZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMjMzOTIuMCwibWluIjoxMjMzOTIuMCwic3VtIjoxMjMzOTIuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQzNjIzNzgwNDhmNzEwNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMzU2NWY1Y2ZiM2EwN2JmYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTgyMjEyLCJtaW4iOjU5Ljk4MjIxMiwic3VtIjo1OS45ODIyMTIsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wNWE5NTJiZTQwYmUyMzJmZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4N2I0YzBiODNmYmVmZDM1In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxOTk4MzM2LjAsIm1pbiI6MTk5ODMzNi4wLCJzdW0iOjE5OTgzMzYuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5YWFkZWM3NGNkNzc5ZjQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjMwNDY4NzUsIm1pbiI6My4zMDQ2ODc1LCJzdW0iOjMuMzA0Njg3NSwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQyODUwMWUxNTI3YTViNDYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODUyZGVhYTk1Nzg5NzQ5ZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTE5ODA4MC4wLCJtaW4iOjkxOTgwODAuMCwic3VtIjo5MTk4MDgwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGY4NDA5ODIzOTY1OWUyZDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVRdWV1ZUxlbmd0aCIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDM1NjVmNWNmYjNhMDdiZmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMDAxOTUzMTI1LCJtaW4iOjAuMDAxOTUzMTI1LCJzdW0iOjAuMDAxOTUzMTI1LCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFJlYWRUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDI4NTAxZTE1MjdhNWI0NiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDlhYWRlYzc0Y2Q3NzlmNDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuNTQ5NzUxODA4RTksIm1pbiI6Mi41NDk3NTE4MDhFOSwic3VtIjoyLjU0OTc1MTgwOEU5LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVJZGxlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGY4NDA5ODIzOTY1OWUyZDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYwLjA5NjUwMywibWluIjo2MC4wOTY1MDMsInN1bSI6NjAuMDk2NTAzLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBlOTA0MDE4YjI0MTZmOGU4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDAwOTI4YzdkNDJhMzdmOWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVUb3RhbFdyaXRlVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDkxYjAzNzUyYzM4ZWYzNTIifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wMSwiY291bnQiOjIxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxXcml0ZVRpbWUiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBkYzgwN2MwOWZhZWIzMWQzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJTZWNvbmRzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJCdXJzdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA2MmIwZDUxYTMxMWQzMjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo5OS45OTk5NjI5NjI5NjMsIm1pbiI6OTkuOTk5OTYyOTYyOTYzLCJzdW0iOjk5Ljk5OTk2Mjk2Mjk2MywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wN2JiMWY2ZTk0NjVhYTI2ZCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODdiNGMwYjgzZmJlZmQzNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTAyNSwibWluIjo1OS45MDI1LCJzdW0iOjU5LjkwMjUsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiQnVyc3RCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYmQxNjEzNzk2MTdjMTdjMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjk5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lVG90YWxSZWFkVGltZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGU5MDQwMThiMjQxNmY4ZTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlNlY29uZHMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVRvdGFsV3JpdGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZDM2MjM3ODA0OGY3MTA2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wMDkzNDgsIm1pbiI6MC4wMDkzNDgsInN1bSI6MC4wMDkzNDgsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBmMzkzNDNiMzQyNjFmY2U0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo5MDEuMCwibWluIjo5MDEuMCwic3VtIjo5MDEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMGQ0YTYxZjVlNDQzYzc2ZGIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZGU0OTQxYjc3ZTgxN2ExMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzY3NTEzNi4wLCJtaW4iOjM2NzUxMzYuMCwic3VtIjozNjc1MTM2LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhMmUxMmZhYWVlMjE2NTg3In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDA5MjhjN2Q0MmEzN2Y5YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTBhMmUxMmZhYWVlMjE2NTg3In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA5YWFkZWM3NGNkNzc5ZjQ5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyNzIzMy4wLCJtaW4iOjI3MjMzLjAsInN1bSI6MjcyMzMuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUXVldWVMZW5ndGgiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTA4NTJkZWFhOTU3ODk3NDllIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAwMzkwNjI1LCJtaW4iOjAuMDAzOTA2MjUsInN1bSI6MC4wMDM5MDYyNSwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wMDk5MDUzMmMyNTczZDBlMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVJlYWRPcHMiLCJkaW1lbnNpb25zIjp7IlZvbHVtZUlkIjoidm9sLTAyMjU2ODFkOTQwOWI2YTVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxLjAsIm1pbiI6MS4wLCJzdW0iOjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDhhNjQxY2RiZTc0NjRmZDgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUJTIiwibWV0cmljX25hbWUiOiJWb2x1bWVXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wYzM2NGQxY2U3MWFhNDFkOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NzA0OTcyOC4wLCJtaW4iOjcwNDk3MjguMCwic3VtIjo3MDQ5NzI4LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZVdyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wZTkwNDAxOGIyNDE2ZjhlOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mjk0LjAsIm1pbiI6Mjk0LjAsInN1bSI6Mjk0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IkJ1cnN0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDVjYjhkMWU3ZjMxZWI4NDMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjEwMC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQlMiLCJtZXRyaWNfbmFtZSI6IlZvbHVtZUlkbGVUaW1lIiwiZGltZW5zaW9ucyI6eyJWb2x1bWVJZCI6InZvbC0wODFhMzIyNTM4Yjc5N2VjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NTkuOTk1OTkzLCJtaW4iOjU5Ljk5NTk5Mywic3VtIjo1OS45OTU5OTMsImNvdW50IjoxLjB9LCJ1bml0IjoiU2Vjb25kcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VCUyIsIm1ldHJpY19uYW1lIjoiVm9sdW1lV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiVm9sdW1lSWQiOiJ2b2wtMDEyYmY2ZjhkZjFhN2QzYmQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1NDY2ODguMCwibWluIjoyNTQ2Njg4LjAsInN1bSI6MjU0NjY4OC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0K\"\n    },\n    {\n      \"data\": \"eyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzkzMWE2M2Y4YjVlYTg5OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjIyNTY2NC4wLCJtaW4iOjIwNTM2MzIuMCwic3VtIjoxLjA2MjYwNDhFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjgxOTEuMCwibWluIjo2OTgwLjAsInN1bSI6MzcyNjEuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlYmU2YWIzZTM3OWY0OGFmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjQzMzMzMzMzMzMzMzMzMzMsIm1pbiI6MC4zOTE2NjY2NjY2NjY2NjY2LCJzdW0iOjIuMDgzMzMzMzMzMzMzMzMzLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlNzVmM2M0NWJkYzI5ODkwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjNTdiYzYwZDM1ZWYxODM2In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjU0MjcyMC4wLCJtaW4iOjAuMCwic3VtIjoxNzk1MDcyLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY4OThjOWIxYzUxMWViNDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI3MjMzLjAsIm1pbiI6MjcyMzMuMCwic3VtIjoyNzIzMy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhYTM3MzFlOTVlNjRiYjMzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxLjA5NzEzNjdFNywibWluIjoxLjA5NzEzNjdFNywic3VtIjoxLjA5NzEzNjdFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWJlNmFiM2UzNzlmNDhhZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzA2MTA2NzAwMDAwMGUzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMjAuMCwibWluIjozMjAuMCwic3VtIjozMjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY4OThjOWIxYzUxMWViNDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ0MDkwNTkuMCwibWluIjo0NDA5MDU5LjAsInN1bSI6NDQwOTA1OS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzUwMjgyOS4wLCJtaW4iOjM1MDI4MjkuMCwic3VtIjozNTAyODI5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVN1cnBsdXNDcmVkaXRCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYTJhOTc1MGY0NDI3YWJlNyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW1hZ2VJZCI6ImFtaS0wYmNlNTI2NWJjNTcwNWExOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Ni4wLCJtaW4iOjAuMCwic3VtIjo2LjAsImNvdW50IjoxNC4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxODI5MTE3NTAwMDAwMTA5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2Ljk2MzMzMzMzMzMzMzMzNCwibWluIjo2Ljk2MzMzMzMzMzMzMzMzNCwic3VtIjo2Ljk2MzMzMzMzMzMzMzMzNCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MjcyMzMuMCwibWluIjoyNzMuMCwic3VtIjoyNzUwNi4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxYTczNmFmM2I4YTViZjRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhZTIxYWIxZDNkY2Q3NGI0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1LjQyMTY2NjY2NjY2NjY2NywibWluIjo1LjQyMTY2NjY2NjY2NjY2Nywic3VtIjo1LjQyMTY2NjY2NjY2NjY2NywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjY3LjAsIm1pbiI6NjcuMCwic3VtIjo2Ny4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJ0Mi5taWNybyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6OTI1MDQuMCwibWluIjo5MjUwNC4wLCJzdW0iOjkyNTA0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZmM3ZmRmMDljMTIzNDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjo1MDAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVmYzdmZGYwOWMxMjM0MjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI3My4wLCJtaW4iOjI3My4wLCJzdW0iOjI3My4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlNzVmM2M0NWJkYzI5ODkwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhZTIxYWIxZDNkY2Q3NGI0In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM2NzUxMzYuMCwibWluIjozNjc1MTM2LjAsInN1bSI6MzY3NTEzNi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW1hZ2VJZCI6ImFtaS0wYmNlNTI2NWJjNTcwNWExOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MjcyMzMuMCwibWluIjowLjAsInN1bSI6MzE5ODEuMCwiY291bnQiOjIwLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjMmNmZWNiZjk4ZDMyNTc4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjo1MDAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM5MzFhNjNmOGI1ZWE4OTgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIyMjQuMCwibWluIjoxNTEzLjAsInN1bSI6ODM4OS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1MzlmOGZmNzczNzZlNTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjE1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVmYzdmZGYwOWMxMjM0MjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuMDY0MDE2NEU3LCJtaW4iOjEuMDY0MDE2NEU3LCJzdW0iOjEuMDY0MDE2NEU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFlMjFhYjFkM2RjZDc0YjQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb21wdXRlLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcxMzI4MzAwMDAwMDBlNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVUNyZWRpdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmNzgzNWE1NGVhMzg0NzNhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxNTEuNzI1NDgyLCJtaW4iOjE1MS43MjU0ODIsInN1bSI6MTUxLjcyNTQ4MiwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjgwLjAsIm1pbiI6MC4wLCJzdW0iOjI3MC4wLCJjb3VudCI6MTUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzODgwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6ODY1NjQwLjAsIm1pbiI6NjkxOTMyLjAsInN1bSI6MzY4MDE3MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MjgwOTI2NC4wLCJtaW4iOjI4MDkyNjQuMCwic3VtIjoyODA5MjY0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE4MzUzMjIyMDAwMDAxMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo2OTMuMCwiY291bnQiOjcuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3ZGJiNGRmYjY4YjA1NmE2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyNTY3MzA5LjAsIm1pbiI6MTk4MDU5OS4wLCJzdW0iOjEuMDc0MjQ5RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC40MzgzMzMzMzMzMzMzMzMzLCJtaW4iOjAuMzkzMzMzMzMzMzMzMzMzMywic3VtIjoyLjA4MzMzMzMzMzMzMzMzMzUsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNS45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo0NjA1MjIxLjAsIm1pbiI6NDYwNTIyMS4wLCJzdW0iOjQ2MDUyMjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNzI0NTgwNTAwMDAwMGViIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjo5OS4wLCJzdW0iOjk5MS4wLCJjb3VudCI6MTAuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDE5M2RmYmUyNzM4NmFhYTEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDg0MDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo0NjA1MjIxLjAsIm1pbiI6NDYwNTIyMS4wLCJzdW0iOjQ2MDUyMjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYxOTUyMC4wLCJtaW4iOjAuMCwic3VtIjoxOTUzNzkyLjAsImNvdW50IjoxNS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDE5M2RmYmUyNzM4NmFhYTEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo2NDgwNTQuMCwibWluIjoyOTc1MzEuMCwic3VtIjoxODg5ODMxLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wN2RiYjRkZmI2OGIwNTZhNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTA5OTMuMCwibWluIjo5MzkzLjAsInN1bSI6NTAwMjMuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNW4uOHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzUwMjgyOS4wLCJtaW4iOjM1MDI4MjkuMCwic3VtIjozNTAyODI5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxYTczNmFmM2I4YTViZjRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo2NDcxLjAsIm1pbiI6MzczNS4wLCJzdW0iOjI0MDYxLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoiYzVuLjl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk0MjE3MjUuMCwibWluIjo5NDIxNzI1LjAsInN1bSI6OTQyMTcyNS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGJiM2M3MDgwMGY3ODljNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE1ODMwLjAsIm1pbiI6MTMxMTYuMCwic3VtIjo3MTg5Ni4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDg4YmY2NTZlM2VjZmQzMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE2ODc0LjAsIm1pbiI6MTM4MzUuMCwic3VtIjo3Njk1MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2JiYzdlMDIxYTE5YmUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTQ0LjAsIm1pbiI6MTQ0LjAsInN1bSI6MTQ0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ5MzAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIwLjAsIm1pbiI6MTguMCwic3VtIjo5NC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmNDkwNjkyNGVmOWI3OGJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb21wdXRlLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcxMzI4MzAwMDAwMDBlNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NC42NzAwNzc4MzQ2MzA1NzcsIm1pbiI6My4zNzMzMzMzMzMzMzMzMzMsInN1bSI6OC4wNDM0MTExNjc5NjM5MSwiY291bnQiOjIuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA2MzIwMDhmZDE4OTFmNmJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo1MDM2MS4wLCJtaW4iOjUwMzYxLjAsInN1bSI6NTAzNjEuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTYxNjYxNzMwMDAwMDBjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4wOTY1MDFFNywibWluIjoyODA5MjY0LjAsInN1bSI6MS4wNTc3ODE4NEU4LCJjb3VudCI6Ni4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2Ljk2MzMzMzMzMzMzMzMzNCwibWluIjo2Ljk2MzMzMzMzMzMzMzMzNCwic3VtIjo2Ljk2MzMzMzMzMzMzMzMzNCwiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQyLjAsIm1pbiI6MzAuMCwic3VtIjoxNzcuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNzI0NTgwNTAwMDAwMGViIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxLjY0OTY5MDhFNywibWluIjo1NzUzMjczLjAsInN1bSI6Mi45ODQ4MzE5RTcsImNvdW50IjozLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjYTU4MDFmYzIwMDJiMDk5In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjE1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4NDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxLjEzNSwibWluIjoxLjA2MTY0ODk3MjUxNzEyNDgsInN1bSI6NS40NzUwMDA3MjI4MjQwNzQsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0OTMwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjE1MDkxMi4wLCJtaW4iOjE3NzUxMDQuMCwic3VtIjo5MzU1Nzc2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDEzZTk1YzJkYjU1ODk1N2IifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTM5ZjhmZjc3Mzc2ZTUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZTc1ZjNjNDViZGMyOTg5MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM5MzFhNjNmOGI1ZWE4OTgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWUyMWFiMWQzZGNkNzRiNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzgyNTE1Mi4wLCJtaW4iOjM4MjUxNTIuMCwic3VtIjozODI1MTUyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29tcHV0ZS1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MTMyODMwMDAwMDAwZTYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxYTczNmFmM2I4YTViZjRhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxODM0LjAsIm1pbiI6MTY1MC4wLCJzdW0iOjg2MTguMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1bi45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozLjM3MzMzMzMzMzMzMzMzMywibWluIjozLjM3MzMzMzMzMzMzMzMzMywic3VtIjozLjM3MzMzMzMzMzMzMzMzMywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxODI5MTE3NTAwMDAwMTA5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMjEwMjk5LjAsIm1pbiI6MzIxMDI5OS4wLCJzdW0iOjMyMTAyOTkuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI5ODA3LjAsIm1pbiI6Mjc0ODcuMCwic3VtIjoxNDE0NzcuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW1hZ2VJZCI6ImFtaS0wYmNlNTI2NWJjNTcwNWExOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mi41NDk3NTE4MDhFOSwibWluIjowLjAsInN1bSI6Mi43MjA3MjkwODhFOSwiY291bnQiOjIwLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTU1MTU1OTkwMDAwMDBjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzkzMWE2M2Y4YjVlYTg5OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZGUzYzM2ZGNiMTIxMGQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4yODUsIm1pbiI6NS4yODUsInN1bSI6NS4yODUsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVUNyZWRpdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxNDQuMCwibWluIjoxNDQuMCwic3VtIjoxNDQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6ODE5MS4wLCJtaW4iOjY5ODAuMCwic3VtIjozNzI2MS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0OTMwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MS4xNzY2NDcwNTU4ODI0MDIsIm1pbiI6MS4wNTE2NDkxMzkxODEwMTM3LCJzdW0iOjUuNTE4MzMyOTczNDU0MTY2LCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE4MzUzMjIyMDAwMDAxMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6Njk5LjAsImNvdW50Ijo3LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZTc1ZjNjNDViZGMyOTg5MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzEwOTY1Mi4wLCJtaW4iOjMxMDk2NTIuMCwic3VtIjozMTA5NjUyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuNHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NzcyODA3Mi4wLCJtaW4iOjc3MjgwNzIuMCwic3VtIjo3NzI4MDcyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNzI0NTgwNTAwMDAwMGViIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6OTkwLjAsImNvdW50IjoxMC4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuNTk3NjY5RTcsIm1pbiI6My4wNjM3MzE2RTcsInN1bSI6Ni42NjE0MDA2RTcsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNW4uMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTY5LjAsIm1pbiI6MTM3LjAsInN1bSI6MzA2LjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wODhiZjY1NmUzZWNmZDMwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6ODQzMzY2NC4wLCJtaW4iOjAuMCwic3VtIjoxLjE3MjgzODRFNywiY291bnQiOjQuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVU3VycGx1c0NyZWRpdHNDaGFyZ2VkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1bi45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo4Ljk4NDE2NjRFNywibWluIjo4Ljk4NDE2NjRFNywic3VtIjo4Ljk4NDE2NjRFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4MzAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYuOTYzMzMzMzMzMzMzMzM0LCJtaW4iOjYuOTYzMzMzMzMzMzMzMzM0LCJzdW0iOjYuOTYzMzMzMzMzMzMzMzM0LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTU1MTU1OTkwMDAwMDBjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NTQ2MTguMCwibWluIjo1MzYxOC4wLCJzdW0iOjI3MDA1Mi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE4MjkxMTc1MDAwMDAxMDkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMxMDk2NTIuMCwibWluIjozMTA5NjUyLjAsInN1bSI6MzEwOTY1Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmI1ZDQ5MWZkZmM2YzFkMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjE5YzdiODYyNDg0NTBiMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZTI1ZGQ1MmJjZGU3NzI5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyLjEyODc5MzZFNywibWluIjoyLjEyODc5MzZFNywic3VtIjoyLjEyODc5MzZFNywiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlNzVmM2M0NWJkYzI5ODkwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMjAuMCwibWluIjozMjAuMCwic3VtIjozMjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE4MzUzMjIyMDAwMDAxMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMwNzcyODguMCwibWluIjoxOTQ1NjU1LjAsInN1bSI6MS4xNTQwNzI4RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyMTljN2I4NjI0ODQ1MGIyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE4LjAsIm1pbiI6MTguMCwic3VtIjo5MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTQwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3Mzg4ZWVhYmM4Yjc2MzIzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNS40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxMzEwNzIuMCwibWluIjoxMzEwNzIuMCwic3VtIjoxMzEwNzIuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyNjU1Ni4wLCJtaW4iOjE0MDQwLjAsInN1bSI6ODUzMDIuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFlMjFhYjFkM2RjZDc0YjQifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuMCwibWluIjoxLjAsInN1bSI6MS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4NDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjozNTM0NTg0LjAsIm1pbiI6MjY2NTMzNC4wLCJzdW0iOjEuNTg5ODAxN0U3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjc4MzVhNTRlYTM4NDczYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNS45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA4OGJmNjU2ZTNlY2ZkMzBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjozMTUuMCwibWluIjowLjAsInN1bSI6MzcxLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIzZGY3YTgyN2NiYzc2NWMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2LjUzMzMzMzMzMzMzMzMzMiwibWluIjo1LjA3MTY2NjY2NjY2NjY2Niwic3VtIjoxNy42MTMzMzMzMzMzMzMzMzMsImNvdW50IjozLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM1N2JjNjBkMzVlZjE4MzYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1NDY2ODguMCwibWluIjoxOTYxNDcyLjAsInN1bSI6MS4wOTkyNjRFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNW4uOXhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIyMjQuMCwibWluIjoxNTEzLjAsInN1bSI6ODM4OS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3Mzg4ZWVhYmM4Yjc2MzIzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1MjM0MDczLjAsIm1pbiI6NTIzNDA3My4wLCJzdW0iOjUyMzQwNzMuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIyMjU2NjQuMCwibWluIjoyMDUzNjMyLjAsInN1bSI6MS4wNjI2MDQ4RTcsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE3MjQ1ODA1MDAwMDAwZWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhYTM3MzFlOTVlNjRiYjMzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVmYzdmZGYwOWMxMjM0MjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVTdXJwbHVzQ3JlZGl0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY3ODM1YTU0ZWEzODQ3M2EifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NjA1NC4wLCJtaW4iOjQ4NjIuMCwic3VtIjoyNzgyNi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZTc1ZjNjNDViZGMyOTg5MCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MzIxMDI5OS4wLCJtaW4iOjMyMTAyOTkuMCwic3VtIjozMjEwMjk5LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoidDIubWljcm8ifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjg1ODc1MS4wLCJtaW4iOjY5NTEwMy4wLCJzdW0iOjM2NzUxOTAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmNzgzNWE1NGVhMzg0NzNhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29tcHV0ZS1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MTMyODMwMDAwMDAwZTYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Mi4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZjQ5MDY5MjRlZjliNzhiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTUxNC4wLCJtaW4iOjE1MTQuMCwic3VtIjoxNTE0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNi41NjMzMzMzMzMzMzMzMzMsIm1pbiI6Mi42NjMzMzMzMzMzMzMzMzMsInN1bSI6NDQuODc3NDk5OTk5OTk5OTIsImNvdW50Ijo2LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6My41MDQ5OTk5OTk5OTk5OTk0LCJtaW4iOjMuNTA0OTk5OTk5OTk5OTk5NCwic3VtIjozLjUwNDk5OTk5OTk5OTk5OTQsImNvdW50IjoxLjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM1N2JjNjBkMzVlZjE4MzYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTQwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbWFnZUlkIjoiYW1pLTBiY2U1MjY1YmM1NzA1YTE5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1MjU0LjAsIm1pbiI6MC4wLCJzdW0iOjUyNjIuMCwiY291bnQiOjIwLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01LjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuMCwibWluIjoxLjAsInN1bSI6MS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzODgwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA2MzIwMDhmZDE4OTFmNmJhIn0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoyLjA2ODk2NTUxNzI0MjYzLCJtaW4iOjIuMDY4OTY1NTE3MjQyNjMsInN1bSI6Mi4wNjg5NjU1MTcyNDI2MywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNW4uOHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzODgwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTk5Ni4wLCJtaW4iOjEwODUuMCwic3VtIjo2NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDE5M2RmYmUyNzM4NmFhYTEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTYxNjYxNzMwMDAwMDBjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjoyNDg3LjAsImNvdW50IjoyNS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0J5dGVCYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo0OTUuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYxMi4wLCJtaW4iOjI2NS4wLCJzdW0iOjE5ODguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1LjYwODMzMzMzMzMzMzMzMywibWluIjo1LjYwODMzMzMzMzMzMzMzMywic3VtIjo1LjYwODMzMzMzMzMzMzMzMywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhYTM3MzFlOTVlNjRiYjMzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxM2U5NWMyZGI1NTg5NTdiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMDk0MGJhYmJiNTRkNjk4NzQifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0OTMwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTA5OTMuMCwibWluIjo5MzkzLjAsInN1bSI6NTAwMjMuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMxMDk2NTIuMCwibWluIjozMTA5NjUyLjAsInN1bSI6MzEwOTY1Mi4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6My45MDM4NjY4OEU4LCJtaW4iOjAuMCwic3VtIjozLjkwMzg2Njg4RTgsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzA2MTA2NzAwMDAwMGUzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb21wdXRlLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcxMzI4MzAwMDAwMDBlNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTUxNC4wLCJtaW4iOjAuMCwic3VtIjoxODIyLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxNTUxNTU5OTAwMDAwMGMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDFhNzM2YWYzYjhhNWJmNGEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjk5LjAsInN1bSI6NDk2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ5NjcuMCwibWluIjoyMDU4LjAsInN1bSI6MTU3NzkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuOTg2MTk2MkU3LCJtaW4iOjEuOTg2MTk2MkU3LCJzdW0iOjEuOTg2MTk2MkU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoyLjA2ODk2NTUxNzI0MjYzLCJtaW4iOjIuMDY4OTY1NTE3MjQyNjMsInN1bSI6Mi4wNjg5NjU1MTcyNDI2MywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyMTljN2I4NjI0ODQ1MGIyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDI5ZThiOTE4OTM1MTA2NzIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE2OTQyMDguMCwibWluIjoxNjk0MjA4LjAsInN1bSI6MTY5NDIwOC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YWQuNHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMTkzZGZiZTI3Mzg2YWFhMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NDk1LjAsIm1pbiI6NDAxLjAsInN1bSI6MjE1My4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3Mzg4ZWVhYmM4Yjc2MzIzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJ0Mi5taWNybyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWEzNzMxZTk1ZTY0YmIzMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmI1ZDQ5MWZkZmM2YzFkMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX0luc3RhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWUyMWFiMWQzZGNkNzRiNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4NDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5NDU2LjAsIm1pbiI6ODI5OC4wLCJzdW0iOjQ1MDY5LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDdkYmI0ZGZiNjhiMDU2YTYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM3MS4wLCJtaW4iOjI2Ny4wLCJzdW0iOjE0OTEuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1MjcwLjAsIm1pbiI6MTI2ODMuMCwic3VtIjo3NzIyMi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk0NTYuMCwibWluIjo4Mjk4LjAsInN1bSI6NDUwNjkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDdkYmI0ZGZiNjhiMDU2YTYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxM2U5NWMyZGI1NTg5NTdiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo0LjY3MDA3NzgzNDYzMDU3NywibWluIjo0LjY3MDA3NzgzNDYzMDU3Nywic3VtIjo0LjY3MDA3NzgzNDYzMDU3NywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC40eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVU3VycGx1c0NyZWRpdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJiNWQ0OTFmZGZjNmMxZDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI3NzI0ODAuMCwibWluIjoyNzcyNDgwLjAsInN1bSI6Mjc3MjQ4MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyOWU4YjkxODkzNTEwNjcyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTWV0YWRhdGFOb1Rva2VuIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWZjN2ZkZjA5YzEyMzQyOCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmEuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM5NDAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjo1MDAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTAwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTUuNHhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDE5M2RmYmUyNzM4NmFhYTEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE5MjIuMCwibWluIjoxMTIwLjAsInN1bSI6NjUxNC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmI1ZDQ5MWZkZmM2YzFkMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTUzMzUuMCwibWluIjoxNDUzNi4wLCJzdW0iOjc0ODQ2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVUNyZWRpdEJhbGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTQ0LjAsIm1pbiI6MTQ0LjAsInN1bSI6MTQ0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE3MjQ1ODA1MDAwMDAwZWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuNzY3OTM0NkU3LCJtaW4iOjEuMzY0OTMxNUU3LCJzdW0iOjYuMTE5MDYyM0U3LCJjb3VudCI6My4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnt9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Ni4wLCJtaW4iOjAuMCwic3VtIjo2LjAsImNvdW50IjoxNC4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1Ljl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjM5MDUwMjQuMCwibWluIjowLjAsInN1bSI6MzkwNTAyNC4wLCJjb3VudCI6NC4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wN2RiYjRkZmI2OGIwNTZhNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NDI3NTc0My4wLCJtaW4iOjMzMjc3NDguMCwic3VtIjoxLjg1NDA5MjdFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbWFnZUlkIjoiYW1pLTBiY2U1MjY1YmM1NzA1YTE5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjcuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDU1Yzc1ZjAxNWYzOTA1ODIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWEzNzMxZTk1ZTY0YmIzMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTA4NzQuMCwibWluIjo4MTQ1LjAsInN1bSI6NDYzODAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVU3VycGx1c0NyZWRpdHNDaGFyZ2VkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2JiYzdlMDIxYTE5YmUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6e30sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjguMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoiYzUuOXhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NDYzNjY0MC4wLCJtaW4iOjQ2MzY2NDAuMCwic3VtIjo0NjM2NjQwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDdkYmI0ZGZiNjhiMDU2YTYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkltYWdlSWQiOiJhbWktMGJjZTUyNjViYzU3MDVhMTkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjguNzcxMzAxOTdFOCwibWluIjozMTA5NjUyLjAsInN1bSI6MS4xNDEwMjE2MDJFOSwiY291bnQiOjE2LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNzI0NTgwNTAwMDAwMGViIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjMuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbWFnZUlkIjoiYW1pLTBiY2U1MjY1YmM1NzA1YTE5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjcuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyZWM2MmQzYzQwMmU5ZWVmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo4LjQ5NTc2MjcxMTg1OTQ3LCJtaW4iOjguNDk1NzYyNzExODU5NDcsInN1bSI6OC40OTU3NjI3MTE4NTk0NywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDkzMDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb21wdXRlLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcxMzI4MzAwMDAwMDBlNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTQyMTcyNS4wLCJtaW4iOjQ2MDUyMjEuMCwic3VtIjoxLjQwMjY5NDZFNywiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQ1ODc1Mi4wLCJtaW4iOjAuMCwic3VtIjo0NTg3NTIuMCwiY291bnQiOjMuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzODgwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVUNyZWRpdFVzYWdlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjNkZjdhODI3Y2JjNzY1YyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wODc2NzgsIm1pbiI6MC4wODc2NzgsInN1bSI6MC4wODc2NzgsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoidDIubWljcm8ifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM5MzFhNjNmOGI1ZWE4OTgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQzNy4wLCJtaW4iOjQxMC4wLCJzdW0iOjIxMDYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDg0MDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGJiM2M3MDgwMGY3ODljNmIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMwOC4wLCJtaW4iOjAuMCwic3VtIjozMDguMCwiY291bnQiOjQuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTgzNTMyMjIwMDAwMDEwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjUzOTA0LjAsIm1pbiI6MjU0MTYuMCwic3VtIjo0MDMwMzcuMCwiY291bnQiOjYuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNzM4OGVlYWJjOGI3NjMyMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6My4wNjM3MzE2RTcsIm1pbiI6My4wNjM3MzE2RTcsInN1bSI6My4wNjM3MzE2RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRVc2FnZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMTA3NTgzLCJtaW4iOjAuMTA3NTgzLCJzdW0iOjAuMTA3NTgzLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01bi44eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjNTdiYzYwZDM1ZWYxODM2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjQzNjY2NjY2NjY2NjY2NjYsIm1pbiI6MC4zNjgzMzMzMzMzMzMzMzMzLCJzdW0iOjEuOTM5OTk5OTk5OTk5OTk5NywiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDczODhlZWFiYzhiNzYzMjMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEzNy4wLCJtaW4iOjEzNy4wLCJzdW0iOjEzNy4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWEzNzMxZTk1ZTY0YmIzMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVN1cnBsdXNDcmVkaXRzQ2hhcmdlZCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJ0Mi5taWNybyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6NTAzNjEuMCwibWluIjo1MDM2MS4wLCJzdW0iOjUwMzYxLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxODI5MTE3NTAwMDAwMTA5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE3MjQ1ODA1MDAwMDAwZWIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb252ZXlvci1wbGF0Zm9ybS1zcG90MjAyMjAyMDkxMzE4MzUzMjIyMDAwMDAxMGMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuOTAzODY2ODhFOCwibWluIjowLjAsInN1bSI6My45MDM4NjY4OEU4LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGU3NWYzYzQ1YmRjMjk4OTAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVTdXJwbHVzQ3JlZGl0QmFsYW5jZSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfU3lzdGVtIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYmIzYzcwODAwZjc4OWM2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcwNjEwNjcwMDAwMDBlMyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDYzMjAwOGZkMTg5MWY2YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NTgwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im00LjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuNjcxNzIxN0U3LCJtaW4iOjEuNjQ5NjkwOEU3LCJzdW0iOjQuMzIxNDEyNUU3LCJjb3VudCI6Mi4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVDcmVkaXRCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYTJhOTc1MGY0NDI3YWJlNyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTQ0LjAsIm1pbiI6MTQ0LjAsInN1bSI6MTQ0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29tcHV0ZS1sYXJnZS1zcG90MjAyMjAyMDkxMzE3MTMyODMwMDAwMDAwZTYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1NDg1LjAsIm1pbiI6OTE1NS4wLCJzdW0iOjE0NTkwNy4wLCJjb3VudCI6MTAuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTU1MTU1OTkwMDAwMDBjMCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Nzg5OTkzNS4wLCJtaW4iOjc4OTk5MzUuMCwic3VtIjo3ODk5OTM1LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWJlNmFiM2UzNzlmNDhhZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTcuMCwibWluIjo2LjAsInN1bSI6NTMuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZEJ5dGVzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJjNS45eGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3ZGJiNGRmYjY4YjA1NmE2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxLjE3NjY0NzA1NTg4MjQwMiwibWluIjoxLjA1MTY0OTEzOTE4MTAxMzcsInN1bSI6NS41MTgzMzI5NzM0NTQxNjYsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1NWM3NWYwMTVmMzkwNTgyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ5MzAwMDAwMDA1In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY4OThjOWIxYzUxMWViNDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1MzkwNC4wLCJtaW4iOjI1MzkwNC4wLCJzdW0iOjI1MzkwNC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYmIzYzcwODAwZjc4OWM2YiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NDYzNjY0MC4wLCJtaW4iOjQ2MzY2NDAuMCwic3VtIjo0NjM2NjQwLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoiYzVuLjl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01bi4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjIuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo0OTUuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1nZW5lcmFsLW1lZGl1bS1zcG90MjAyMjAyMDkxMzE1NTE1NTk5MDAwMDAwYzAifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDUzOWY4ZmY3NzM3NmU1MmUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE2LjAsIm1pbiI6Ni4wLCJzdW0iOjQzLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7fSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuNTQ5NzUxODA4RTksIm1pbiI6MC4wLCJzdW0iOjIuNzIwNzI5MDg4RTksImNvdW50IjoyMC4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNCeXRlQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA1MzlmOGZmNzczNzZlNTJlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo5OS4wLCJtaW4iOjk5LjAsInN1bSI6NDk1LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4zMDAxNjE5RTcsIm1pbiI6NS4zMDAxNjE5RTcsInN1bSI6NS4zMDAxNjE5RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkRpc2tSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYWUyMWFiMWQzZGNkNzRiNCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NzcyODA3Mi4wLCJtaW4iOjc3MjgwNzIuMCwic3VtIjo3NzI4MDcyLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGMyY2ZlY2JmOThkMzI1NzgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wZWUyNWRkNTJiY2RlNzcyOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NjEwNDAzNi4wLCJtaW4iOjYxMDQwMzYuMCwic3VtIjo2MTA0MDM2LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlZmM3ZmRmMDljMTIzNDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNhNTgwMWZjMjAwMmIwOTkifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxODM1MzIyMjAwMDAwMTBjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo1ODQ1NC4wLCJtaW4iOjE0MDQwLjAsInN1bSI6MTQzNzU2LjAsImNvdW50Ijo2LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTA3Mzg4ZWVhYmM4Yjc2MzIzIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3MDQ5NzI4LjAsIm1pbiI6NzA0OTcyOC4wLCJzdW0iOjcwNDk3MjguMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJkc2Utb3BzLWRldi1hdXRvc2NhbGluZy1ob3N0In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4Ijo5MjUwNC4wLCJtaW4iOjkyNTA0LjAsInN1bSI6OTI1MDQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OTAxLjAsIm1pbiI6MTIzLjAsInN1bSI6MTE4NC4wLCJjb3VudCI6My4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVuLjh4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuNTA0OTk5OTk5OTk5OTk5NCwibWluIjozLjUwNDk5OTk5OTk5OTk5OTQsInN1bSI6My41MDQ5OTk5OTk5OTk5OTk0LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM5MDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1Ljl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlQnl0ZXMiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiY29udmV5b3ItcmFwaWQ2OS1jb21wdXRlLWxhcmdlLXNwb3QyMDIyMDIwOTEzMTcxMzI4MzAwMDAwMDBlNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6OC45ODQxNjY0RTcsIm1pbiI6MC4wLCJzdW0iOjkuMzc0NjY4OEU3LCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM1N2JjNjBkMzVlZjE4MzYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIyNzIuMCwibWluIjoxNTAyLjAsInN1bSI6ODQzMi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6NS4zMDAxNjE5RTcsIm1pbiI6NTc1MzI3My4wLCJzdW0iOjkuNjQ4NjEwNkU3LCJjb3VudCI6My4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTk5Ni4wLCJtaW4iOjEwODUuMCwic3VtIjo2NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzODgwMDAwMDAwMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6MTAwLjAsInN1bSI6NTAwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiUGVyY2VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktZ2VuZXJhbC1tZWRpdW0tc3BvdDIwMjIwMjA5MTMxNTUxNTU5OTAwMDAwMGMwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3NzI4MDcyLjAsIm1pbiI6NzcyODA3Mi4wLCJzdW0iOjc3MjgwNzIuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTQwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MjIyNS4wLCJtaW4iOjE1NDguMCwic3VtIjo4NDc0LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJlYzYyZDNjNDAyZTllZWYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjguMCwibWluIjo4LjAsInN1bSI6OC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrSW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3NTk4MTM4LjAsIm1pbiI6NzU5ODEzOC4wLCJzdW0iOjc1OTgxMzguMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJiNWQ0OTFmZGZjNmMxZDEifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEuOTg2MTk2MkU3LCJtaW4iOjEuOTg2MTk2MkU3LCJzdW0iOjEuOTg2MTk2MkU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9JbnN0YW5jZSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmIuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM4ODAwMDAwMDAxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3gucHVibGljLnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIzMzAxMDM5MDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxOTIxLjAsIm1pbiI6MTA5NS4wLCJzdW0iOjYzODYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTSU9CYWxhbmNlJSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGViZTZhYjNlMzc5ZjQ4YWYifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjk5LjAsIm1pbiI6OTkuMCwic3VtIjo0OTUuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDIxOWM3Yjg2MjQ4NDUwYjIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVTdXJwbHVzQ3JlZGl0c0NoYXJnZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBhMmE5NzUwZjQ0MjdhYmU3In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYy5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzkwMDAwMDAwMDIifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjYzMTAyMi4wLCJtaW4iOjMyMDExOC4wLCJzdW0iOjE5NTY4MTQuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya091dCIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJiLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0OTMwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NDI3NTc0My4wLCJtaW4iOjMzMjc3NDguMCwic3VtIjoxLjg1NDA5MjdFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImNvbnZleW9yLXJhcGlkNjktY29udmV5b3ItcGxhdGZvcm0tc3BvdDIwMjIwMjA5MTMxNjE2NjE3MzAwMDAwMGNjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo1LjMwMDE2MTlFNywibWluIjoxLjA2NDAxNjRFNywic3VtIjoxLjY5Njk4ODk3RTgsImNvdW50Ijo2LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGM5MzFhNjNmOGI1ZWE4OTgifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6NS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LnB1YmxpYy51cy13ZXN0LTJhLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMzMwMTAzOTQwMDAwMDAwNSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6ODY5NDQ5LjAsIm1pbiI6Njk5MDk0LjAsInN1bSI6MzY5MTIxNS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZU9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjExOS4wLCJtaW4iOjExOS4wLCJzdW0iOjExOS4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNXcml0ZUJ5dGVzIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzg4MDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI1NDY2ODguMCwibWluIjoxOTYxNDcyLjAsInN1bSI6MS4wOTkyNjRFNywiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmI1ZDQ5MWZkZmM2YzFkMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6OTkuMCwibWluIjo5OS4wLCJzdW0iOjQ5NS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjOTMxYTYzZjhiNWVhODk4In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo4NTg3NTEuMCwibWluIjo2OTUxMDMuMCwic3VtIjozNjc1MTkwLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjYTU4MDFmYzIwMDJiMDk5In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo2MTY2LjAsIm1pbiI6MzU5NC4wLCJzdW0iOjIzNjI2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTIzLjAsIm1pbiI6MTIzLjAsInN1bSI6MTIzLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtQYWNrZXRzT3V0IiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzg4MDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIyNzIuMCwibWluIjoxNTAyLjAsInN1bSI6ODQzMi4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNTVjNzVmMDE1ZjM5MDU4MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6My43NzMxMjE0RTcsIm1pbiI6My43NzMxMjE0RTcsInN1bSI6My43NzMxMjE0RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmVjNjJkM2M0MDJlOWVlZiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYi5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzg4MDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuNDM2NjY2NjY2NjY2NjY2NiwibWluIjowLjM2ODMzMzMzMzMzMzMzMzMsInN1bSI6MS45Mzk5OTk5OTk5OTk5OTk3LCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNW4uMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTYuNTYzMzMzMzMzMzMzMzMzLCJtaW4iOjUuMjg1LCJzdW0iOjIxLjg0ODMzMzMzMzMzMzMzMywiY291bnQiOjIuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDEzZTk1YzJkYjU1ODk1N2IifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuOTQ1LCJtaW4iOjAuODcxNjY2NjY2NjY2NjY2Niwic3VtIjo0LjQ4MTY2NjY2NjY2NjY2NywiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyZWM2MmQzYzQwMmU5ZWVmIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDI5ZThiOTE4OTM1MTA2NzIifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMjllOGI5MTg5MzUxMDY3MiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MS4zNjQ5MzE1RTcsIm1pbiI6MS4zNjQ5MzE1RTcsInN1bSI6MS4zNjQ5MzE1RTcsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDEzZTk1YzJkYjU1ODk1N2IifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGFhMzczMWU5NWU2NGJiMzMifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjIuNjYzMzMzMzMzMzMzMzMzLCJtaW4iOjIuNjYzMzMzMzMzMzMzMzMzLCJzdW0iOjIuNjYzMzMzMzMzMzMzMzMzLCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNJT0JhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wN2RiYjRkZmI2OGIwNTZhNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTkuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZF9TeXN0ZW0iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBlNzVmM2M0NWJkYzI5ODkwIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVVXRpbGl6YXRpb24iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6ImM1Ljl4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjQuNjcwMDc3ODM0NjMwNTc3LCJtaW4iOjQuNjcwMDc3ODM0NjMwNTc3LCJzdW0iOjQuNjcwMDc3ODM0NjMwNTc3LCJjb3VudCI6MS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wMmI1ZDQ5MWZkZmM2YzFkMSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAxOTNkZmJlMjczODZhYWExIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoxMDAuMCwibWluIjoxMDAuMCwic3VtIjo1MDAuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWFkLjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzkzMWE2M2Y4YjVlYTg5OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTkyMS4wLCJtaW4iOjEwOTUuMCwic3VtIjo2Mzg2LjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzU3YmM2MGQzNWVmMTgzNiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6NTE2LjAsIm1pbiI6Mzk1LjAsInN1bSI6MjE3OS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01YS4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTQnl0ZUJhbGFuY2UlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzJjZmVjYmY5OGQzMjU3OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MTAwLjAsIm1pbiI6OTkuMCwic3VtIjo0OTYuMCwiY291bnQiOjUuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVkLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTcyNDU4MDUwMDAwMDBlYiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoyLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbWFnZUlkIjoiYW1pLTA5NDBiYWJiYjU0ZDY5ODc0In0sInRpbWVzdGFtcCI6MTY1MTY3OTU4MDAwMCwidmFsdWUiOnsibWF4IjoyLjA2ODk2NTUxNzI0MjYzLCJtaW4iOjIuMDY4OTY1NTE3MjQyNjMsInN1bSI6Mi4wNjg5NjU1MTcyNDI2MywiY291bnQiOjEuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkQnl0ZXMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyYjVkNDkxZmRmYzZjMWQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01LjR4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjI4Ni4wLCJtaW4iOjI4Ni4wLCJzdW0iOjI4Ni4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrT3V0IiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wNjMyMDA4ZmQxODkxZjZiYSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6OTI1MDQuMCwibWluIjo5MjUwNC4wLCJzdW0iOjkyNTA0LjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU0lPQmFsYW5jZSUiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZWRnZS1wcm94eS5nZW5zYW5kYm94LmRlZmF1bHQudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjIwNTkxNDgzMDAwMDAwMDEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEwMC4wLCJtaW4iOjEwMC4wLCJzdW0iOjUwMC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVN1cnBsdXNDcmVkaXRCYWxhbmNlIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wY2JiYzdlMDIxYTE5YmUyZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6e30sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoyNzIzMy4wLCJtaW4iOjAuMCwic3VtIjozMTk4MS4wLCJjb3VudCI6MjAuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGY0OTA2OTI0ZWY5Yjc4YmEifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMyNDc3LjAsIm1pbiI6MTI5OTUuMCwic3VtIjoxMDY1NzguMCwiY291bnQiOjUuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRGlza1dyaXRlT3BzIiwiZGltZW5zaW9ucyI6e30sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjguMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbXB1dGUtbGFyZ2Utc3BvdDIwMjIwMjA5MTMxNzEzMjgzMDAwMDAwMGU2In0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjozMjQ3Ny4wLCJtaW4iOjEyOTk1LjAsInN1bSI6MTkwMjY2LjAsImNvdW50IjoxMC4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJDUFVVdGlsaXphdGlvbiIsImRpbWVuc2lvbnMiOnt9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MTYuNTYzMzMzMzMzMzMzMzMzLCJtaW4iOjIuMDk2Nzc0MTkzNTQ3MjEsInN1bSI6MTEwLjA5NDg2OTI5OTY4MzQsImNvdW50IjoxNy4wfSwidW5pdCI6IlBlcmNlbnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWdlbmVyYWwtbWVkaXVtLXNwb3QyMDIyMDIwOTEzMTgyOTExNzUwMDAwMDEwOSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTgzNTMyMjIwMDAwMDEwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6Mi41NDk3NTE4MDhFOSwibWluIjo3NTY1ODI0LjAsInN1bSI6Mi41NTczMTc2MzJFOSwiY291bnQiOjIuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTV3JpdGVPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlVHlwZSI6Im01ZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2Ny4wLCJtaW4iOjY3LjAsInN1bSI6NjcuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiRUJTUmVhZE9wcyIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhZC4yeGxhcmdlIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo3LjAsIm1pbiI6MC4wLCJzdW0iOjcuMCwiY291bnQiOjMuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDczODhlZWFiYzhiNzYzMjMifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjEyMzAzLjAsIm1pbiI6MTA1MjMuMCwic3VtIjo1NjMzMS4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJTdGF0dXNDaGVja0ZhaWxlZCIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGNiYmM3ZTAyMWExOWJlMmUifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJNZXRhZGF0YU5vVG9rZW4iLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBkZTNjMzZkY2IxMjEwZDI4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4Ijo2LjAsIm1pbiI6Ni4wLCJzdW0iOjYuMCwiY291bnQiOjEuMH0sInVuaXQiOiJOb25lIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnt9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo4LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGVlMjVkZDUyYmNkZTc3MjkifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTgzNTMyMjIwMDAwMDEwYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMGRlM2MzNmRjYjEyMTBkMjgifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjMuNTk3NjY5RTcsIm1pbiI6My41OTc2NjlFNywic3VtIjozLjU5NzY2OUU3LCJjb3VudCI6MS4wfSwidW5pdCI6IkJ5dGVzIn0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZVR5cGUiOiJtNWQuMnhsYXJnZSJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VUeXBlIjoibTVhLjJ4bGFyZ2UifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6Ik5vbmUifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik5ldHdvcmtJbiIsImRpbWVuc2lvbnMiOnsiSW1hZ2VJZCI6ImFtaS0wOTQwYmFiYmI1NGQ2OTg3NCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk1ODAwMDAsInZhbHVlIjp7Im1heCI6NTAzNjEuMCwibWluIjo1MDM2MS4wLCJzdW0iOjUwMzYxLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkVCU1JlYWRPcHMiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBiYjNjNzA4MDBmNzg5YzZiIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjQuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBjOTMxYTYzZjhiNWVhODk4In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiQ1BVQ3JlZGl0VXNhZ2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4xMDc1ODMsIm1pbiI6MC4xMDc1ODMsInN1bSI6MC4xMDc1ODMsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IlN0YXR1c0NoZWNrRmFpbGVkX1N5c3RlbSIsImRpbWVuc2lvbnMiOnsiSW5zdGFuY2VJZCI6ImktMDJlYzYyZDNjNDAyZTllZWYifSwidGltZXN0YW1wIjoxNjUxNjc5NjQwMDAwLCJ2YWx1ZSI6eyJtYXgiOjAuMCwibWluIjowLjAsInN1bSI6MC4wLCJjb3VudCI6MS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJFQlNSZWFkT3BzIiwiZGltZW5zaW9ucyI6eyJJbnN0YW5jZUlkIjoiaS0wYzJjZmVjYmY5OGQzMjU3OCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiQ291bnQifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6IkNQVVV0aWxpemF0aW9uIiwiZGltZW5zaW9ucyI6eyJJbWFnZUlkIjoiYW1pLTBiY2U1MjY1YmM1NzA1YTE5In0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjoxNi41NjMzMzMzMzMzMzMzMzMsIm1pbiI6Mi42NjMzMzMzMzMzMzMzMzMsInN1bSI6MTA3Ljk5ODA5NTEwNjEzNjE5LCJjb3VudCI6MTYuMH0sInVuaXQiOiJQZXJjZW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJOZXR3b3JrUGFja2V0c0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5wdWJsaWMudXMtd2VzdC0yYS5hbWktMGU3NGJjZTZjNzNiMDNiMmUuMjAyMjA1MDMyMjMzMDEwMzk0MDAwMDAwMDUifSwidGltZXN0YW1wIjoxNjUxNjc5NDAwMDAwLCJ2YWx1ZSI6eyJtYXgiOjE5MjIuMCwibWluIjoxMTIwLjAsInN1bSI6NjUxNC4wLCJjb3VudCI6NS4wfSwidW5pdCI6IkNvdW50In0KeyJtZXRyaWNfc3RyZWFtX25hbWUiOiJncnBuLXNhbmRib3gtZGV2LWNsb3Vkd2F0Y2gtbWV0cmljLXN0cmVhbSIsImFjY291bnRfaWQiOiI1NDk3MzQzOTk3MDkiLCJyZWdpb24iOiJ1cy13ZXN0LTIiLCJuYW1lc3BhY2UiOiJBV1MvRUMyIiwibWV0cmljX25hbWUiOiJEaXNrV3JpdGVCeXRlcyIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJjb252ZXlvci1yYXBpZDY5LWNvbnZleW9yLXBsYXRmb3JtLXNwb3QyMDIyMDIwOTEzMTYxNjYxNzMwMDAwMDBjYyJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo0LjB9LCJ1bml0IjoiQnl0ZXMifQp7Im1ldHJpY19zdHJlYW1fbmFtZSI6ImdycG4tc2FuZGJveC1kZXYtY2xvdWR3YXRjaC1tZXRyaWMtc3RyZWFtIiwiYWNjb3VudF9pZCI6IjU0OTczNDM5OTcwOSIsInJlZ2lvbiI6InVzLXdlc3QtMiIsIm5hbWVzcGFjZSI6IkFXUy9FQzIiLCJtZXRyaWNfbmFtZSI6Ik1ldGFkYXRhTm9Ub2tlbiIsImRpbWVuc2lvbnMiOnsiQXV0b1NjYWxpbmdHcm91cE5hbWUiOiJlZGdlLXByb3h5LmdlbnNhbmRib3guZGVmYXVsdC51cy13ZXN0LTJjLmFtaS0wZTc0YmNlNmM3M2IwM2IyZS4yMDIyMDUwMzIyMjA1OTE0ODQwMDAwMDAwMiJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk0MDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50Ijo1LjB9LCJ1bml0IjoiTm9uZSJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya1BhY2tldHNPdXQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTBmODk4YzliMWM1MTFlYjQxIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4Ijo1ODQ1NC4wLCJtaW4iOjU4NDU0LjAsInN1bSI6NTg0NTQuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiTmV0d29ya0luIiwiZGltZW5zaW9ucyI6eyJBdXRvU2NhbGluZ0dyb3VwTmFtZSI6ImVkZ2UtcHJveHkuZ2Vuc2FuZGJveC5kZWZhdWx0LnVzLXdlc3QtMmMuYW1pLTBlNzRiY2U2YzczYjAzYjJlLjIwMjIwNTAzMjIyMDU5MTQ4NDAwMDAwMDAyIn0sInRpbWVzdGFtcCI6MTY1MTY3OTQwMDAwMCwidmFsdWUiOnsibWF4IjoyMDA5NDExLjAsIm1pbiI6MTY4MjE4Ny4wLCJzdW0iOjkwNDI2MzIuMCwiY291bnQiOjUuMH0sInVuaXQiOiJCeXRlcyJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWQiLCJkaW1lbnNpb25zIjp7Ikluc3RhbmNlSWQiOiJpLTAyM2RmN2E4MjdjYmM3NjVjIn0sInRpbWVzdGFtcCI6MTY1MTY3OTY0MDAwMCwidmFsdWUiOnsibWF4IjowLjAsIm1pbiI6MC4wLCJzdW0iOjAuMCwiY291bnQiOjEuMH0sInVuaXQiOiJDb3VudCJ9CnsibWV0cmljX3N0cmVhbV9uYW1lIjoiZ3Jwbi1zYW5kYm94LWRldi1jbG91ZHdhdGNoLW1ldHJpYy1zdHJlYW0iLCJhY2NvdW50X2lkIjoiNTQ5NzM0Mzk5NzA5IiwicmVnaW9uIjoidXMtd2VzdC0yIiwibmFtZXNwYWNlIjoiQVdTL0VDMiIsIm1ldHJpY19uYW1lIjoiU3RhdHVzQ2hlY2tGYWlsZWRfSW5zdGFuY2UiLCJkaW1lbnNpb25zIjp7IkF1dG9TY2FsaW5nR3JvdXBOYW1lIjoiZHNlLW9wcy1kZXYtYXV0b3NjYWxpbmctaG9zdCJ9LCJ0aW1lc3RhbXAiOjE2NTE2Nzk2NDAwMDAsInZhbHVlIjp7Im1heCI6MC4wLCJtaW4iOjAuMCwic3VtIjowLjAsImNvdW50IjoxLjB9LCJ1bml0IjoiQ291bnQifQo=\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/conntrack/README.md",
    "content": "# Netfilter Conntrack Input Plugin\n\nThis plugin collects metrics from [Netfilter's conntrack tools][conntrack].\nThere are two collection mechanisms for this plugin:\n\n1. Extracting information from `/proc/net/stat/nf_conntrack` files if the\n   `collect` option is set accordingly for finding CPU specific values.\n2. Using specific files and directories by specifying the `dirs` option. At\n   runtime, conntrack exposes many of those connection statistics within\n   `/proc/sys/net`. Depending on your kernel version, these files can be found\n   in either `/proc/sys/net/ipv4/netfilter` or `/proc/sys/net/netfilter` and\n   will be prefixed with either `ip` or `nf`.\n\nIn order to simplify configuration in a heterogeneous environment, a superset\nof directory and filenames can be specified. Any locations that doesn't exist\nis ignored.\n\n⭐ Telegraf v1.0.0\n🏷️ system\n💻 linux\n\n[conntrack]: https://conntrack-tools.netfilter.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collects conntrack stats from the configured directories and files.\n# This plugin ONLY supports Linux\n[[inputs.conntrack]]\n  ## The following defaults would work with multiple versions of conntrack.\n  ## Note the nf_ and ip_ filename prefixes are mutually exclusive across\n  ## kernel versions, as are the directory locations.\n\n  ## Look through /proc/net/stat/nf_conntrack for these metrics\n  ## all - aggregated statistics\n  ## percpu - include detailed statistics with cpu tag\n  collect = [\"all\", \"percpu\"]\n\n  ## User-specified directories and files to look through\n  ## Directories to search within for the conntrack files above.\n  ## Missing directories will be ignored.\n  dirs = [\"/proc/sys/net/ipv4/netfilter\",\"/proc/sys/net/netfilter\"]\n\n  ## Superset of filenames to look for within the conntrack dirs.\n  ## Missing files will be ignored.\n  files = [\"ip_conntrack_count\",\"ip_conntrack_max\",\n          \"nf_conntrack_count\",\"nf_conntrack_max\"]\n```\n\n## Metrics\n\nA detailed explanation of each fields can be found in\n[kernel documentation][kerneldoc]\n\n[kerneldoc]: https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt\n\n- conntrack\n  - `ip_conntrack_count` `(int, count)`: The number of entries in the conntrack table\n  - `ip_conntrack_max` `(int, size)`: The max capacity of the conntrack table\n  - `ip_conntrack_buckets`  `(int, size)`: The size of hash table.\n\nWith `collect = [\"all\"]`:\n\n- `entries`: The number of entries in the conntrack table\n- `searched`: The number of conntrack table lookups performed\n- `found`: The number of searched entries which were successful\n- `new`: The number of entries added which were not expected before\n- `invalid`: The number of packets seen which can not be tracked\n- `ignore`: The number of packets seen which are already connected to an entry\n- `delete`: The number of entries which were removed\n- `delete_list`: The number of entries which were put to dying list\n- `insert`: The number of entries inserted into the list\n- `insert_failed`: The number of insertion attempted but failed (duplicate entry)\n- `drop`: The number of packets dropped due to conntrack failure\n- `early_drop`: The number of dropped entries to make room for new ones, if\n                `maxsize` is reached\n- `icmp_error`: Subset of invalid. Packets that can't be tracked due to error\n- `expect_new`: Entries added after an expectation was already present\n- `expect_create`: Expectations added\n- `expect_delete`: Expectations deleted\n- `search_restart`: Conntrack table lookups restarted due to hashtable resizes\n\n### Tags\n\nWith `collect = [\"percpu\"]` will include detailed statistics per CPU thread.\n\nWithout `\"percpu\"` the `cpu` tag will have `all` value.\n\n## Example Output\n\n```text\nconntrack,host=myhost ip_conntrack_count=2,ip_conntrack_max=262144 1461620427667995735\n```\n\nwith stats:\n\n```text\nconntrack,cpu=all,host=localhost delete=0i,delete_list=0i,drop=2i,early_drop=0i,entries=5568i,expect_create=0i,expect_delete=0i,expect_new=0i,found=7i,icmp_error=1962i,ignore=2586413402i,insert=0i,insert_failed=2i,invalid=46853i,new=0i,search_restart=453336i,searched=0i 1615233542000000000\nconntrack,host=localhost ip_conntrack_count=464,ip_conntrack_max=262144 1615233542000000000\n```\n"
  },
  {
    "path": "plugins/inputs/conntrack/conntrack.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage conntrack\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdfltDirs = []string{\n\t\t\"/proc/sys/net/ipv4/netfilter\",\n\t\t\"/proc/sys/net/netfilter\",\n\t}\n\n\tdfltFiles = []string{\n\t\t\"ip_conntrack_count\",\n\t\t\"ip_conntrack_max\",\n\t\t\"nf_conntrack_count\",\n\t\t\"nf_conntrack_max\",\n\t}\n)\n\nconst (\n\tinputName = \"conntrack\"\n)\n\ntype Conntrack struct {\n\tCollect []string `toml:\"collect\"`\n\tDirs    []string `toml:\"dirs\"`\n\tFiles   []string `toml:\"files\"`\n\tps      psutil.PS\n}\n\nfunc (*Conntrack) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *Conntrack) Init() error {\n\tc.setDefaults()\n\n\tif err := choice.CheckSlice(c.Collect, []string{\"all\", \"percpu\"}); err != nil {\n\t\treturn fmt.Errorf(\"config option 'collect': %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Conntrack) Gather(acc telegraf.Accumulator) error {\n\tvar metricKey string\n\tfields := make(map[string]interface{})\n\n\tfor _, dir := range c.Dirs {\n\t\tfor _, file := range c.Files {\n\t\t\t// NOTE: no system will have both nf_ and ip_ prefixes,\n\t\t\t// so we're safe to branch on suffix only.\n\t\t\tparts := strings.SplitN(file, \"_\", 2)\n\t\t\tif len(parts) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmetricKey = \"ip_\" + parts[1]\n\n\t\t\tfName := filepath.Join(dir, file)\n\t\t\tif _, err := os.Stat(fName); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcontents, err := os.ReadFile(fName)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"failed to read file %q: %w\", fName, err))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tv := strings.TrimSpace(string(contents))\n\t\t\tfields[metricKey], err = strconv.ParseFloat(v, 64)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"failed to parse metric, expected number but \"+\n\t\t\t\t\t\" found %q: %w\", v, err))\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, metric := range c.Collect {\n\t\tperCPU := metric == \"percpu\"\n\t\tstats, err := c.ps.NetConntrack(perCPU)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to retrieve conntrack statistics: %w\", err))\n\t\t}\n\n\t\tif len(stats) == 0 {\n\t\t\tacc.AddError(errors.New(\"conntrack input failed to collect stats\"))\n\t\t}\n\n\t\tcpuTag := \"all\"\n\t\tfor i, sts := range stats {\n\t\t\tif perCPU {\n\t\t\t\tcpuTag = fmt.Sprintf(\"cpu%d\", i)\n\t\t\t}\n\t\t\ttags := map[string]string{\n\t\t\t\t\"cpu\": cpuTag,\n\t\t\t}\n\n\t\t\tstatFields := map[string]interface{}{\n\t\t\t\t\"entries\":        sts.Entries,       // entries in the conntrack table\n\t\t\t\t\"searched\":       sts.Searched,      // conntrack table lookups performed\n\t\t\t\t\"found\":          sts.Found,         // searched entries which were successful\n\t\t\t\t\"new\":            sts.New,           // entries added which were not expected before\n\t\t\t\t\"invalid\":        sts.Invalid,       // packets seen which can not be tracked\n\t\t\t\t\"ignore\":         sts.Ignore,        // packets seen which are already connected to an entry\n\t\t\t\t\"delete\":         sts.Delete,        // entries which were removed\n\t\t\t\t\"delete_list\":    sts.DeleteList,    // entries which were put to dying list\n\t\t\t\t\"insert\":         sts.Insert,        // entries inserted into the list\n\t\t\t\t\"insert_failed\":  sts.InsertFailed,  // insertion attempted but failed (same entry exists)\n\t\t\t\t\"drop\":           sts.Drop,          // packets dropped due to conntrack failure\n\t\t\t\t\"early_drop\":     sts.EarlyDrop,     // dropped entries to make room for new ones, if maxsize reached\n\t\t\t\t\"icmp_error\":     sts.IcmpError,     // Subset of invalid. Packets that can't be tracked d/t error\n\t\t\t\t\"expect_new\":     sts.ExpectNew,     // Entries added after an expectation was already present\n\t\t\t\t\"expect_create\":  sts.ExpectCreate,  // Expectations added\n\t\t\t\t\"expect_delete\":  sts.ExpectDelete,  // Expectations deleted\n\t\t\t\t\"search_restart\": sts.SearchRestart, // onntrack table lookups restarted due to hashtable resizes\n\t\t\t}\n\t\t\tacc.AddCounter(inputName, statFields, tags)\n\t\t}\n\t}\n\n\tif len(fields) == 0 {\n\t\treturn errors.New(\"conntrack input failed to collect metrics, make sure that the kernel module is loaded\")\n\t}\n\n\tacc.AddFields(inputName, fields, nil)\n\treturn nil\n}\n\nfunc (c *Conntrack) setDefaults() {\n\tif len(c.Dirs) == 0 {\n\t\tc.Dirs = dfltDirs\n\t}\n\n\tif len(c.Files) == 0 {\n\t\tc.Files = dfltFiles\n\t}\n}\n\nfunc init() {\n\tinputs.Add(inputName, func() telegraf.Input {\n\t\treturn &Conntrack{\n\t\t\tps: psutil.NewSystemPS(),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/conntrack/conntrack_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage conntrack\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Conntrack struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Conntrack) SampleConfig() string { return sampleConfig }\n\nfunc (c *Conntrack) Init() error {\n\tc.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Conntrack) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"conntrack\", func() telegraf.Input {\n\t\treturn &Conntrack{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/conntrack/conntrack_test.go",
    "content": "//go:build linux\n\npackage conntrack\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/shirou/gopsutil/v4/net\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc restoreDflts(savedFiles, savedDirs []string) {\n\tdfltFiles = savedFiles\n\tdfltDirs = savedDirs\n}\n\nfunc TestNoFilesFound(t *testing.T) {\n\tdefer restoreDflts(dfltFiles, dfltDirs)\n\n\tdfltFiles = []string{\"baz.txt\"}\n\tdfltDirs = []string{\"./foo/bar\"}\n\tc := &Conntrack{}\n\trequire.NoError(t, c.Init())\n\tacc := &testutil.Accumulator{}\n\terr := c.Gather(acc)\n\n\trequire.EqualError(t, err, \"conntrack input failed to collect metrics, make sure that the kernel module is loaded\")\n}\n\nfunc TestDefaultsUsed(t *testing.T) {\n\tdefer restoreDflts(dfltFiles, dfltDirs)\n\ttmpdir := t.TempDir()\n\n\ttmpFile, err := os.CreateTemp(tmpdir, \"ip_conntrack_count\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(tmpFile.Name())\n\n\tdfltDirs = []string{tmpdir}\n\tfname := path.Base(tmpFile.Name())\n\tdfltFiles = []string{fname}\n\n\tcount := 1234321\n\trequire.NoError(t, os.WriteFile(tmpFile.Name(), []byte(strconv.Itoa(count)), 0640))\n\tc := &Conntrack{}\n\trequire.NoError(t, c.Init())\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, c.Gather(acc))\n\tacc.AssertContainsFields(t, inputName, map[string]interface{}{\n\t\tfname: float64(count)})\n}\n\nfunc TestConfigsUsed(t *testing.T) {\n\tdefer restoreDflts(dfltFiles, dfltDirs)\n\ttmpdir := t.TempDir()\n\n\tcntFile, err := os.CreateTemp(tmpdir, \"nf_conntrack_count\")\n\trequire.NoError(t, err)\n\tmaxFile, err := os.CreateTemp(tmpdir, \"nf_conntrack_max\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(cntFile.Name())\n\tdefer os.Remove(maxFile.Name())\n\n\tdfltDirs = []string{tmpdir}\n\tcntFname := path.Base(cntFile.Name())\n\tmaxFname := path.Base(maxFile.Name())\n\tdfltFiles = []string{cntFname, maxFname}\n\n\tcount := 1234321\n\tlimit := 9999999\n\trequire.NoError(t, os.WriteFile(cntFile.Name(), []byte(strconv.Itoa(count)), 0640))\n\trequire.NoError(t, os.WriteFile(maxFile.Name(), []byte(strconv.Itoa(limit)), 0640))\n\tc := &Conntrack{}\n\trequire.NoError(t, c.Init())\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, c.Gather(acc))\n\n\tfix := func(s string) string {\n\t\treturn strings.Replace(s, \"nf_\", \"ip_\", 1)\n\t}\n\n\tacc.AssertContainsFields(t, inputName,\n\t\tmap[string]interface{}{\n\t\t\tfix(cntFname): float64(count),\n\t\t\tfix(maxFname): float64(limit),\n\t\t})\n}\n\nfunc TestCollectStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\n\tsts := net.ConntrackStat{\n\t\tEntries:       1234,\n\t\tSearched:      10,\n\t\tFound:         1,\n\t\tNew:           5,\n\t\tInvalid:       43,\n\t\tIgnore:        13,\n\t\tDelete:        3,\n\t\tDeleteList:    5,\n\t\tInsert:        9,\n\t\tInsertFailed:  20,\n\t\tDrop:          49,\n\t\tEarlyDrop:     7,\n\t\tIcmpError:     21,\n\t\tExpectNew:     12,\n\t\tExpectCreate:  44,\n\t\tExpectDelete:  53,\n\t\tSearchRestart: 31,\n\t}\n\n\tmps.On(\"NetConntrack\", false).Return([]net.ConntrackStat{sts}, nil)\n\tcs := &Conntrack{\n\t\tps:      &mps,\n\t\tCollect: []string{\"all\"},\n\t}\n\trequire.NoError(t, cs.Init())\n\n\terr := cs.Gather(&acc)\n\tif err != nil && strings.Contains(err.Error(), \"Is the conntrack kernel module loaded?\") {\n\t\tt.Skip(\"Conntrack kernel module not loaded.\")\n\t}\n\trequire.NoError(t, err)\n\n\texpectedTags := map[string]string{\n\t\t\"cpu\": \"all\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"entries\":        uint32(1234),\n\t\t\"searched\":       uint32(10),\n\t\t\"found\":          uint32(1),\n\t\t\"new\":            uint32(5),\n\t\t\"invalid\":        uint32(43),\n\t\t\"ignore\":         uint32(13),\n\t\t\"delete\":         uint32(3),\n\t\t\"delete_list\":    uint32(5),\n\t\t\"insert\":         uint32(9),\n\t\t\"insert_failed\":  uint32(20),\n\t\t\"drop\":           uint32(49),\n\t\t\"early_drop\":     uint32(7),\n\t\t\"icmp_error\":     uint32(21),\n\t\t\"expect_new\":     uint32(12),\n\t\t\"expect_create\":  uint32(44),\n\t\t\"expect_delete\":  uint32(53),\n\t\t\"search_restart\": uint32(31),\n\t}\n\n\tacc.AssertContainsFields(t, inputName, expectedFields)\n\tacc.AssertContainsTaggedFields(t, inputName, expectedFields, expectedTags)\n\n\trequire.Equal(t, 19, acc.NFields())\n}\n\nfunc TestCollectStatsPerCpu(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\n\tsts := []net.ConntrackStat{\n\t\t{\n\t\t\tEntries:       59,\n\t\t\tSearched:      10,\n\t\t\tFound:         1,\n\t\t\tNew:           5,\n\t\t\tInvalid:       43,\n\t\t\tIgnore:        13,\n\t\t\tDelete:        3,\n\t\t\tDeleteList:    5,\n\t\t\tInsert:        9,\n\t\t\tInsertFailed:  20,\n\t\t\tDrop:          49,\n\t\t\tEarlyDrop:     7,\n\t\t\tIcmpError:     21,\n\t\t\tExpectNew:     12,\n\t\t\tExpectCreate:  44,\n\t\t\tExpectDelete:  53,\n\t\t\tSearchRestart: 31,\n\t\t},\n\t\t{\n\t\t\tEntries:       79,\n\t\t\tSearched:      10,\n\t\t\tFound:         1,\n\t\t\tNew:           5,\n\t\t\tInvalid:       43,\n\t\t\tIgnore:        13,\n\t\t\tDelete:        3,\n\t\t\tDeleteList:    5,\n\t\t\tInsert:        9,\n\t\t\tInsertFailed:  10,\n\t\t\tDrop:          49,\n\t\t\tEarlyDrop:     7,\n\t\t\tIcmpError:     21,\n\t\t\tExpectNew:     12,\n\t\t\tExpectCreate:  44,\n\t\t\tExpectDelete:  53,\n\t\t\tSearchRestart: 31,\n\t\t},\n\t}\n\n\tmps.On(\"NetConntrack\", true).Return(sts, nil)\n\n\tallSts := []net.ConntrackStat{\n\t\t{\n\t\t\tEntries:       129,\n\t\t\tSearched:      20,\n\t\t\tFound:         2,\n\t\t\tNew:           10,\n\t\t\tInvalid:       86,\n\t\t\tIgnore:        26,\n\t\t\tDelete:        6,\n\t\t\tDeleteList:    10,\n\t\t\tInsert:        18,\n\t\t\tInsertFailed:  40,\n\t\t\tDrop:          98,\n\t\t\tEarlyDrop:     17,\n\t\t\tIcmpError:     42,\n\t\t\tExpectNew:     24,\n\t\t\tExpectCreate:  88,\n\t\t\tExpectDelete:  106,\n\t\t\tSearchRestart: 62,\n\t\t},\n\t}\n\n\tmps.On(\"NetConntrack\", false).Return(allSts, nil)\n\n\tcs := &Conntrack{\n\t\tps:      &mps,\n\t\tCollect: []string{\"all\", \"percpu\"},\n\t}\n\trequire.NoError(t, cs.Init())\n\n\terr := cs.Gather(&acc)\n\tif err != nil && strings.Contains(err.Error(), \"Is the conntrack kernel module loaded?\") {\n\t\tt.Skip(\"Conntrack kernel module not loaded.\")\n\t}\n\trequire.NoError(t, err)\n\n\t// cpu0\n\texpectedFields := map[string]interface{}{\n\t\t\"entries\":        uint32(59),\n\t\t\"searched\":       uint32(10),\n\t\t\"found\":          uint32(1),\n\t\t\"new\":            uint32(5),\n\t\t\"invalid\":        uint32(43),\n\t\t\"ignore\":         uint32(13),\n\t\t\"delete\":         uint32(3),\n\t\t\"delete_list\":    uint32(5),\n\t\t\"insert\":         uint32(9),\n\t\t\"insert_failed\":  uint32(20),\n\t\t\"drop\":           uint32(49),\n\t\t\"early_drop\":     uint32(7),\n\t\t\"icmp_error\":     uint32(21),\n\t\t\"expect_new\":     uint32(12),\n\t\t\"expect_create\":  uint32(44),\n\t\t\"expect_delete\":  uint32(53),\n\t\t\"search_restart\": uint32(31),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, inputName, expectedFields,\n\t\tmap[string]string{\n\t\t\t\"cpu\": \"cpu0\",\n\t\t})\n\n\t// cpu1\n\texpectedFields1 := map[string]interface{}{\n\t\t\"entries\":        uint32(79),\n\t\t\"searched\":       uint32(10),\n\t\t\"found\":          uint32(1),\n\t\t\"new\":            uint32(5),\n\t\t\"invalid\":        uint32(43),\n\t\t\"ignore\":         uint32(13),\n\t\t\"delete\":         uint32(3),\n\t\t\"delete_list\":    uint32(5),\n\t\t\"insert\":         uint32(9),\n\t\t\"insert_failed\":  uint32(10),\n\t\t\"drop\":           uint32(49),\n\t\t\"early_drop\":     uint32(7),\n\t\t\"icmp_error\":     uint32(21),\n\t\t\"expect_new\":     uint32(12),\n\t\t\"expect_create\":  uint32(44),\n\t\t\"expect_delete\":  uint32(53),\n\t\t\"search_restart\": uint32(31),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, inputName, expectedFields1,\n\t\tmap[string]string{\n\t\t\t\"cpu\": \"cpu1\",\n\t\t})\n\n\tallFields := map[string]interface{}{\n\t\t\"entries\":        uint32(129),\n\t\t\"searched\":       uint32(20),\n\t\t\"found\":          uint32(2),\n\t\t\"new\":            uint32(10),\n\t\t\"invalid\":        uint32(86),\n\t\t\"ignore\":         uint32(26),\n\t\t\"delete\":         uint32(6),\n\t\t\"delete_list\":    uint32(10),\n\t\t\"insert\":         uint32(18),\n\t\t\"insert_failed\":  uint32(40),\n\t\t\"drop\":           uint32(98),\n\t\t\"early_drop\":     uint32(17),\n\t\t\"icmp_error\":     uint32(42),\n\t\t\"expect_new\":     uint32(24),\n\t\t\"expect_create\":  uint32(88),\n\t\t\"expect_delete\":  uint32(106),\n\t\t\"search_restart\": uint32(62),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, inputName, allFields,\n\t\tmap[string]string{\n\t\t\t\"cpu\": \"all\",\n\t\t})\n\n\trequire.Equal(t, 53, acc.NFields())\n}\n\nfunc TestCollectPsSystemInit(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tcs := &Conntrack{\n\t\tps:      psutil.NewSystemPS(),\n\t\tCollect: []string{\"all\"},\n\t}\n\trequire.NoError(t, cs.Init())\n\terr := cs.Gather(&acc)\n\tif err != nil && strings.Contains(err.Error(), \"Is the conntrack kernel module loaded?\") {\n\t\tt.Skip(\"Conntrack kernel module not loaded.\")\n\t}\n\t// make sure Conntrack.ps gets initialized without mocking\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/conntrack/sample.conf",
    "content": "# Collects conntrack stats from the configured directories and files.\n# This plugin ONLY supports Linux\n[[inputs.conntrack]]\n  ## The following defaults would work with multiple versions of conntrack.\n  ## Note the nf_ and ip_ filename prefixes are mutually exclusive across\n  ## kernel versions, as are the directory locations.\n\n  ## Look through /proc/net/stat/nf_conntrack for these metrics\n  ## all - aggregated statistics\n  ## percpu - include detailed statistics with cpu tag\n  collect = [\"all\", \"percpu\"]\n\n  ## User-specified directories and files to look through\n  ## Directories to search within for the conntrack files above.\n  ## Missing directories will be ignored.\n  dirs = [\"/proc/sys/net/ipv4/netfilter\",\"/proc/sys/net/netfilter\"]\n\n  ## Superset of filenames to look for within the conntrack dirs.\n  ## Missing files will be ignored.\n  files = [\"ip_conntrack_count\",\"ip_conntrack_max\",\n          \"nf_conntrack_count\",\"nf_conntrack_max\"]\n"
  },
  {
    "path": "plugins/inputs/consul/README.md",
    "content": "# Hashicorp Consul Input Plugin\n\nThis plugin will collect statistics about all health checks registered in\n[Consul][consul] using the [Consul API][api]. The plugin will not report any\n[telemetry metrics][telemetry] but Consul can report those statistics using\nthe StatsD protocol if needed.\n\n⭐ Telegraf v1.0.0\n🏷️ server\n💻 all\n\n[api]: https://www.consul.io/docs/agent/http/health.html#health_state\n[telemetry]: https://www.consul.io/docs/agent/telemetry.html\n[consul]: https://www.consul.io\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather health check statuses from services registered in Consul\n[[inputs.consul]]\n  ## Consul server address\n  # address = \"localhost:8500\"\n\n  ## URI scheme for the Consul server, one of \"http\", \"https\"\n  # scheme = \"http\"\n\n  ## Metric version controls the mapping from Consul metrics into\n  ## Telegraf metrics. Version 2 moved all fields with string values\n  ## to tags.\n  ##\n  ##   example: metric_version = 1; deprecated in 1.16\n  ##            metric_version = 2; recommended version\n  # metric_version = 1\n\n  ## ACL token used in every request\n  # token = \"\"\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Data center to query the health checks from\n  # datacenter = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Consul checks' tag splitting\n  # When tags are formatted like \"key:value\" with \":\" as a delimiter then\n  # they will be split and reported as proper key:value in Telegraf\n  # tag_delimiter = \":\"\n```\n\n## Metrics\n\n### metric_version = 1\n\n- consul_health_checks\n  - tags:\n    - node (node that check/service is registered on)\n    - service_name\n    - check_id\n  - fields:\n    - check_name\n    - service_id\n    - status\n    - passing (integer)\n    - critical (integer)\n    - warning (integer)\n\n### metric_version = 2\n\n- consul_health_checks\n  - tags:\n    - node (node that check/service is registered on)\n    - service_name\n    - check_id\n    - check_name\n    - service_id\n    - status\n  - fields:\n    - passing (integer)\n    - critical (integer)\n    - warning (integer)\n\n`passing`, `critical`, and `warning` are integer representations of the health\ncheck state. A value of `1` represents that the status was the state of the\nhealth check at this sample. `status` is string representation of the same\nstate.\n\n## Example Output\n\n```text\nconsul_health_checks,host=wolfpit,node=consul-server-node,check_id=\"serfHealth\" check_name=\"Serf Health Status\",service_id=\"\",status=\"passing\",passing=1i,critical=0i,warning=0i 1464698464486439902\nconsul_health_checks,host=wolfpit,node=consul-server-node,service_name=www.example.com,check_id=\"service:www-example-com.test01\" check_name=\"Service 'www.example.com' check\",service_id=\"www-example-com.test01\",status=\"critical\",passing=0i,critical=1i,warning=0i 1464698464486519036\n```\n"
  },
  {
    "path": "plugins/inputs/consul/consul.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage consul\n\nimport (\n\t_ \"embed\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/consul/api\"\n\n\t\"github.com/influxdata/telegraf\"\n\ttelegraf_config \"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Consul struct {\n\tAddress       string `toml:\"address\"`\n\tScheme        string `toml:\"scheme\"`\n\tToken         string `toml:\"token\"`\n\tUsername      string `toml:\"username\"`\n\tPassword      string `toml:\"password\"`\n\tDatacenter    string `toml:\"datacenter\"`\n\tTagDelimiter  string `toml:\"tag_delimiter\"`\n\tMetricVersion int    `toml:\"metric_version\"`\n\tLog           telegraf.Logger\n\ttls.ClientConfig\n\n\t// client used to connect to Consul agent\n\tclient *api.Client\n}\n\nfunc (*Consul) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *Consul) Init() error {\n\tif c.MetricVersion != 2 {\n\t\ttelegraf_config.PrintOptionValueDeprecationNotice(\"inputs.consul\", \"metric_version\", 1,\n\t\t\ttelegraf.DeprecationInfo{\n\t\t\t\tSince:     \"1.16.0\",\n\t\t\t\tRemovalIn: \"1.40.0\",\n\t\t\t\tNotice:    `please update to 'metric_version = 2'`,\n\t\t\t},\n\t\t)\n\t}\n\n\tconfig := api.DefaultConfig()\n\n\tif c.Address != \"\" {\n\t\tconfig.Address = c.Address\n\t}\n\n\tif c.Scheme != \"\" {\n\t\tconfig.Scheme = c.Scheme\n\t}\n\n\tif c.Datacenter != \"\" {\n\t\tconfig.Datacenter = c.Datacenter\n\t}\n\n\tif c.Token != \"\" {\n\t\tconfig.Token = c.Token\n\t}\n\n\tif c.Username != \"\" {\n\t\tconfig.HttpAuth = &api.HttpBasicAuth{\n\t\t\tUsername: c.Username,\n\t\t\tPassword: c.Password,\n\t\t}\n\t}\n\n\ttlsCfg, err := c.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconfig.Transport = &http.Transport{\n\t\tTLSClientConfig: tlsCfg,\n\t}\n\n\tc.client, err = api.NewClient(config)\n\treturn err\n}\n\nfunc (c *Consul) Gather(acc telegraf.Accumulator) error {\n\tchecks, _, err := c.client.Health().State(\"any\", nil)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.gatherHealthCheck(acc, checks)\n\n\treturn nil\n}\n\nfunc (c *Consul) gatherHealthCheck(acc telegraf.Accumulator, checks []*api.HealthCheck) {\n\tfor _, check := range checks {\n\t\trecord := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\trecord[\"passing\"] = 0\n\t\trecord[\"critical\"] = 0\n\t\trecord[\"warning\"] = 0\n\t\trecord[check.Status] = 1\n\n\t\tif c.MetricVersion == 2 {\n\t\t\ttags[\"check_name\"] = check.Name\n\t\t\ttags[\"service_id\"] = check.ServiceID\n\t\t\ttags[\"status\"] = check.Status\n\t\t} else {\n\t\t\trecord[\"check_name\"] = check.Name\n\t\t\trecord[\"service_id\"] = check.ServiceID\n\t\t\trecord[\"status\"] = check.Status\n\t\t}\n\n\t\ttags[\"node\"] = check.Node\n\t\ttags[\"service_name\"] = check.ServiceName\n\t\ttags[\"check_id\"] = check.CheckID\n\n\t\tfor _, checkTag := range check.ServiceTags {\n\t\t\tif c.TagDelimiter != \"\" {\n\t\t\t\tsplittedTag := strings.SplitN(checkTag, c.TagDelimiter, 2)\n\t\t\t\tif len(splittedTag) == 1 && checkTag != \"\" {\n\t\t\t\t\ttags[checkTag] = checkTag\n\t\t\t\t} else if len(splittedTag) == 2 && splittedTag[1] != \"\" {\n\t\t\t\t\ttags[splittedTag[0]] = splittedTag[1]\n\t\t\t\t}\n\t\t\t} else if checkTag != \"\" {\n\t\t\t\ttags[checkTag] = checkTag\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"consul_health_checks\", record, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"consul\", func() telegraf.Input {\n\t\treturn &Consul{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/consul/consul_test.go",
    "content": "package consul\n\nimport (\n\t\"testing\"\n\n\t\"github.com/hashicorp/consul/api\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar sampleChecks = []*api.HealthCheck{\n\t{\n\t\tNode:        \"localhost\",\n\t\tCheckID:     \"foo.health123\",\n\t\tName:        \"foo.health\",\n\t\tStatus:      \"passing\",\n\t\tNotes:       \"lorem ipsum\",\n\t\tOutput:      \"OK\",\n\t\tServiceID:   \"foo.123\",\n\t\tServiceName: \"foo\",\n\t\tServiceTags: []string{\"bar\", \"env:sandbox\", \"tagkey:value:stillvalue\"},\n\t},\n}\n\nfunc TestGatherHealthCheck(t *testing.T) {\n\texpectedFields := map[string]interface{}{\n\t\t\"check_name\": \"foo.health\",\n\t\t\"status\":     \"passing\",\n\t\t\"passing\":    1,\n\t\t\"critical\":   0,\n\t\t\"warning\":    0,\n\t\t\"service_id\": \"foo.123\",\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"node\":                    \"localhost\",\n\t\t\"service_name\":            \"foo\",\n\t\t\"check_id\":                \"foo.health123\",\n\t\t\"bar\":                     \"bar\",\n\t\t\"env:sandbox\":             \"env:sandbox\",\n\t\t\"tagkey:value:stillvalue\": \"tagkey:value:stillvalue\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tconsul := &Consul{}\n\tconsul.gatherHealthCheck(&acc, sampleChecks)\n\n\tacc.AssertContainsTaggedFields(t, \"consul_health_checks\", expectedFields, expectedTags)\n}\n\nfunc TestGatherHealthCheckWithDelimitedTags(t *testing.T) {\n\texpectedFields := map[string]interface{}{\n\t\t\"check_name\": \"foo.health\",\n\t\t\"status\":     \"passing\",\n\t\t\"passing\":    1,\n\t\t\"critical\":   0,\n\t\t\"warning\":    0,\n\t\t\"service_id\": \"foo.123\",\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"node\":         \"localhost\",\n\t\t\"service_name\": \"foo\",\n\t\t\"check_id\":     \"foo.health123\",\n\t\t\"bar\":          \"bar\",\n\t\t\"env\":          \"sandbox\",\n\t\t\"tagkey\":       \"value:stillvalue\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tconsul := &Consul{\n\t\tTagDelimiter: \":\",\n\t}\n\tconsul.gatherHealthCheck(&acc, sampleChecks)\n\n\tacc.AssertContainsTaggedFields(t, \"consul_health_checks\", expectedFields, expectedTags)\n}\n\nfunc TestGatherHealthCheckV2(t *testing.T) {\n\texpectedFields := map[string]interface{}{\n\t\t\"passing\":  1,\n\t\t\"critical\": 0,\n\t\t\"warning\":  0,\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"node\":                    \"localhost\",\n\t\t\"check_id\":                \"foo.health123\",\n\t\t\"check_name\":              \"foo.health\",\n\t\t\"status\":                  \"passing\",\n\t\t\"service_id\":              \"foo.123\",\n\t\t\"service_name\":            \"foo\",\n\t\t\"bar\":                     \"bar\",\n\t\t\"env:sandbox\":             \"env:sandbox\",\n\t\t\"tagkey:value:stillvalue\": \"tagkey:value:stillvalue\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tconsul := &Consul{\n\t\tMetricVersion: 2,\n\t}\n\tconsul.gatherHealthCheck(&acc, sampleChecks)\n\n\tacc.AssertContainsTaggedFields(t, \"consul_health_checks\", expectedFields, expectedTags)\n}\n\nfunc TestGatherHealthCheckWithDelimitedTagsV2(t *testing.T) {\n\texpectedFields := map[string]interface{}{\n\t\t\"passing\":  1,\n\t\t\"critical\": 0,\n\t\t\"warning\":  0,\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"node\":         \"localhost\",\n\t\t\"check_id\":     \"foo.health123\",\n\t\t\"check_name\":   \"foo.health\",\n\t\t\"status\":       \"passing\",\n\t\t\"service_id\":   \"foo.123\",\n\t\t\"service_name\": \"foo\",\n\t\t\"bar\":          \"bar\",\n\t\t\"env\":          \"sandbox\",\n\t\t\"tagkey\":       \"value:stillvalue\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tconsul := &Consul{\n\t\tMetricVersion: 2,\n\t\tTagDelimiter:  \":\",\n\t}\n\tconsul.gatherHealthCheck(&acc, sampleChecks)\n\n\tacc.AssertContainsTaggedFields(t, \"consul_health_checks\", expectedFields, expectedTags)\n}\n"
  },
  {
    "path": "plugins/inputs/consul/sample.conf",
    "content": "# Gather health check statuses from services registered in Consul\n[[inputs.consul]]\n  ## Consul server address\n  # address = \"localhost:8500\"\n\n  ## URI scheme for the Consul server, one of \"http\", \"https\"\n  # scheme = \"http\"\n\n  ## Metric version controls the mapping from Consul metrics into\n  ## Telegraf metrics. Version 2 moved all fields with string values\n  ## to tags.\n  ##\n  ##   example: metric_version = 1; deprecated in 1.16\n  ##            metric_version = 2; recommended version\n  # metric_version = 1\n\n  ## ACL token used in every request\n  # token = \"\"\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Data center to query the health checks from\n  # datacenter = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Consul checks' tag splitting\n  # When tags are formatted like \"key:value\" with \":\" as a delimiter then\n  # they will be split and reported as proper key:value in Telegraf\n  # tag_delimiter = \":\"\n"
  },
  {
    "path": "plugins/inputs/consul_agent/README.md",
    "content": "# Hashicorp Consul Agent Input Plugin\n\nThis plugin collects metrics from a [Consul agent][agent]. Telegraf may be\npresent in every node and connect to the agent locally. Tested on Consul v1.10.\n\n⭐ Telegraf v1.22.0\n🏷️ server\n💻 all\n\n[agent]: https://developer.hashicorp.com/consul/commands/agent\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from the Consul Agent API\n[[inputs.consul_agent]]\n  ## URL for the Consul agent\n  # url = \"http://127.0.0.1:8500\"\n\n  ## Use auth token for authorization.\n  ## If both are set, an error is thrown.\n  ## If both are empty, no token will be used.\n  # token_file = \"/path/to/auth/token\"\n  ## OR\n  # token = \"a1234567-40c7-9048-7bae-378687048181\"\n\n  ## Set timeout (default 5 seconds)\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n```\n\n## Metrics\n\nConsul collects various metrics. For every details, please have a look at\n[Consul's documentation](https://www.consul.io/api/agent#view-metrics).\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/consul_agent/consul_agent.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage consul_agent\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst timeLayout = \"2006-01-02 15:04:05 -0700 MST\"\n\ntype ConsulAgent struct {\n\tURL string `toml:\"url\"`\n\n\tTokenFile string `toml:\"token_file\"`\n\tToken     string `toml:\"token\"`\n\n\tResponseTimeout config.Duration `toml:\"timeout\"`\n\n\ttls.ClientConfig\n\n\troundTripper http.RoundTripper\n}\n\nfunc (*ConsulAgent) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *ConsulAgent) Init() error {\n\tif n.URL == \"\" {\n\t\tn.URL = \"http://127.0.0.1:8500\"\n\t}\n\n\tif n.TokenFile != \"\" && n.Token != \"\" {\n\t\treturn errors.New(\"config error: both token_file and token are set\")\n\t}\n\n\tif n.TokenFile != \"\" {\n\t\ttoken, err := os.ReadFile(n.TokenFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading file failed: %w\", err)\n\t\t}\n\t\tn.Token = strings.TrimSpace(string(token))\n\t}\n\n\ttlsCfg, err := n.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"setting up TLS configuration failed: %w\", err)\n\t}\n\n\tn.roundTripper = &http.Transport{\n\t\tTLSHandshakeTimeout:   time.Duration(n.ResponseTimeout),\n\t\tTLSClientConfig:       tlsCfg,\n\t\tResponseHeaderTimeout: time.Duration(n.ResponseTimeout),\n\t}\n\n\treturn nil\n}\n\nfunc (n *ConsulAgent) Gather(acc telegraf.Accumulator) error {\n\tsummaryMetrics, err := n.loadJSON(n.URL + \"/v1/agent/metrics\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn buildConsulAgent(acc, summaryMetrics)\n}\n\nfunc (n *ConsulAgent) loadJSON(url string) (*agentInfo, error) {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Header.Add(\"X-Consul-Token\", n.Token)\n\treq.Header.Add(\"Accept\", \"application/json\")\n\n\tresp, err := n.roundTripper.RoundTrip(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error making HTTP request to %q: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s\", url, resp.Status)\n\t}\n\n\tvar metrics agentInfo\n\terr = json.NewDecoder(resp.Body).Decode(&metrics)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing json response: %w\", err)\n\t}\n\n\treturn &metrics, nil\n}\n\n// buildConsulAgent, it builds all the metrics and adds them to the accumulator)\nfunc buildConsulAgent(acc telegraf.Accumulator, agentInfo *agentInfo) error {\n\tt, err := internal.ParseTimestamp(timeLayout, agentInfo.Timestamp, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing time: %w\", err)\n\t}\n\n\tfor _, counters := range agentInfo.Counters {\n\t\tfields := map[string]interface{}{\n\t\t\t\"count\":  counters.Count,\n\t\t\t\"sum\":    counters.Sum,\n\t\t\t\"max\":    counters.Max,\n\t\t\t\"mean\":   counters.Mean,\n\t\t\t\"min\":    counters.Min,\n\t\t\t\"rate\":   counters.Rate,\n\t\t\t\"stddev\": counters.Stddev,\n\t\t}\n\t\ttags := counters.Labels\n\n\t\tacc.AddCounter(counters.Name, fields, tags, t)\n\t}\n\n\tfor _, gauges := range agentInfo.Gauges {\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": gauges.Value,\n\t\t}\n\t\ttags := gauges.Labels\n\n\t\tacc.AddGauge(gauges.Name, fields, tags, t)\n\t}\n\n\tfor _, points := range agentInfo.Points {\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": points.Points,\n\t\t}\n\t\ttags := make(map[string]string)\n\n\t\tacc.AddFields(points.Name, fields, tags, t)\n\t}\n\n\tfor _, samples := range agentInfo.Samples {\n\t\tfields := map[string]interface{}{\n\t\t\t\"count\":  samples.Count,\n\t\t\t\"sum\":    samples.Sum,\n\t\t\t\"max\":    samples.Max,\n\t\t\t\"mean\":   samples.Mean,\n\t\t\t\"min\":    samples.Min,\n\t\t\t\"rate\":   samples.Rate,\n\t\t\t\"stddev\": samples.Stddev,\n\t\t}\n\t\ttags := samples.Labels\n\n\t\tacc.AddCounter(samples.Name, fields, tags, t)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"consul_agent\", func() telegraf.Input {\n\t\treturn &ConsulAgent{\n\t\t\tResponseTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/consul_agent/consul_agent_test.go",
    "content": "package consul_agent\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestConsulStats(t *testing.T) {\n\tvar applyTests = []struct {\n\t\tname     string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"Metrics\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"consul.rpc.request\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  int(5),\n\t\t\t\t\t\t\"max\":    float64(1),\n\t\t\t\t\t\t\"mean\":   float64(1),\n\t\t\t\t\t\t\"min\":    float64(1),\n\t\t\t\t\t\t\"rate\":   float64(0.5),\n\t\t\t\t\t\t\"stddev\": float64(0),\n\t\t\t\t\t\t\"sum\":    float64(5),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1639218930, 0),\n\t\t\t\t\t1,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"consul.consul.members.clients\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"datacenter\": \"dc1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1639218930, 0),\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"consul.api.http\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"path\":   \"v1_agent_self\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  int(1),\n\t\t\t\t\t\t\"max\":    float64(4.14815616607666),\n\t\t\t\t\t\t\"mean\":   float64(4.14815616607666),\n\t\t\t\t\t\t\"min\":    float64(4.14815616607666),\n\t\t\t\t\t\t\"rate\":   float64(0.414815616607666),\n\t\t\t\t\t\t\"stddev\": float64(0),\n\t\t\t\t\t\t\"sum\":    float64(4.14815616607666),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1639218930, 0),\n\t\t\t\t\t1,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range applyTests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif r.RequestURI == \"/v1/agent/metrics\" {\n\t\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t\tresponseKeyMetrics, err := os.ReadFile(\"testdata/response_key_metrics.json\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif _, err = fmt.Fprintln(w, string(responseKeyMetrics)); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &ConsulAgent{\n\t\t\t\tURL: ts.URL,\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc := testutil.Accumulator{}\n\t\t\terr = plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/consul_agent/consul_structs.go",
    "content": "package consul_agent\n\ntype agentInfo struct {\n\tTimestamp string\n\tGauges    []gaugeValue\n\tPoints    []pointValue\n\tCounters  []sampledValue\n\tSamples   []sampledValue\n}\n\ntype gaugeValue struct {\n\tName   string\n\tValue  float32\n\tLabels map[string]string\n}\n\ntype pointValue struct {\n\tName   string\n\tPoints []float32\n}\n\ntype sampledValue struct {\n\tName   string\n\tCount  int\n\tSum    float64\n\tMin    float64\n\tMax    float64\n\tMean   float64\n\tRate   float64\n\tStddev float64\n\tLabels map[string]string\n}\n"
  },
  {
    "path": "plugins/inputs/consul_agent/sample.conf",
    "content": "# Read metrics from the Consul Agent API\n[[inputs.consul_agent]]\n  ## URL for the Consul agent\n  # url = \"http://127.0.0.1:8500\"\n\n  ## Use auth token for authorization.\n  ## If both are set, an error is thrown.\n  ## If both are empty, no token will be used.\n  # token_file = \"/path/to/auth/token\"\n  ## OR\n  # token = \"a1234567-40c7-9048-7bae-378687048181\"\n\n  ## Set timeout (default 5 seconds)\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n"
  },
  {
    "path": "plugins/inputs/consul_agent/testdata/response_key_metrics.json",
    "content": "{\n\t\"Timestamp\": \"2021-12-11 10:35:30 +0000 UTC\",\n\t\"Gauges\": [\n\t  {\n\t\t\"Name\": \"consul.consul.members.clients\",\n\t\t\"Value\": 0,\n\t\t\"Labels\": {\n\t\t  \"datacenter\": \"dc1\"\n\t\t}\n\t  }\n\t],\n\t\"Points\": [],\n\t\"Counters\": [\n\t  {\n\t\t\"Name\": \"consul.rpc.request\",\n\t\t\"Count\": 5,\n\t\t\"Rate\": 0.5,\n\t\t\"Sum\": 5,\n\t\t\"Min\": 1,\n\t\t\"Max\": 1,\n\t\t\"Mean\": 1,\n\t\t\"Stddev\": 0,\n\t\t\"Labels\": {}\n\t  }\n\t],\n\t\"Samples\": [\n\t  {\n\t\t\"Name\": \"consul.api.http\",\n\t\t\"Count\": 1,\n\t\t\"Rate\": 0.414815616607666,\n\t\t\"Sum\": 4.14815616607666,\n\t\t\"Min\": 4.14815616607666,\n\t\t\"Max\": 4.14815616607666,\n\t\t\"Mean\": 4.14815616607666,\n\t\t\"Stddev\": 0,\n\t\t\"Labels\": {\n\t\t  \"method\": \"GET\",\n\t\t  \"path\": \"v1_agent_self\"\n\t\t}\n\t  }\n\t]\n  }\n"
  },
  {
    "path": "plugins/inputs/couchbase/README.md",
    "content": "# Couchbase Input Plugin\n\nThis plugin collects metrics from [Couchbase][couchbase], a distributed NoSQL\ndatabase. Metrics are collected for each node, as well as detailed metrics for\neach bucket, for a given couchbase server.\n\n⭐ Telegraf v0.12.0\n🏷️ server\n💻 all\n\n[couchbase]: https://www.couchbase.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read per-node and per-bucket metrics from Couchbase\n[[inputs.couchbase]]\n  ## specify servers via a url matching:\n  ##  [protocol://][:password]@address[:port]\n  ##  e.g.\n  ##    http://couchbase-0.example.com/\n  ##    http://admin:secret@couchbase-0.example.com:8091/\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no protocol is specified, HTTP is used.\n  ## If no port is specified, 8091 is used.\n  servers = [\"http://localhost:8091\"]\n\n  ## Filter bucket fields to include only here.\n  # bucket_stats_included = [\"quota_percent_used\", \"ops_per_sec\", \"disk_fetches\", \"item_count\", \"disk_used\", \"data_used\", \"mem_used\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification (defaults to false)\n  ## If set to false, tls_cert and tls_key are required\n  # insecure_skip_verify = false\n\n  ## Whether to collect cluster-wide bucket statistics\n  ## It is recommended to disable this in favor of node_stats\n  ## to get a better view of the cluster.\n  # cluster_bucket_stats = true\n\n  ## Whether to collect bucket stats for each individual node\n  # node_bucket_stats = false\n\n  ## List of additional stats to collect, choose from:\n  ##  * autofailover\n  # additional_stats = []\n```\n\n## Metrics\n\n### couchbase_node\n\nTags:\n\n- cluster: sanitized string from `servers` configuration field\n  e.g.: `http://user:password@couchbase-0.example.com:8091/endpoint` becomes\n  `http://couchbase-0.example.com:8091/endpoint`\n- hostname: Couchbase's name for the node and port, e.g., `172.16.10.187:8091`\n\nFields:\n\n- memory_free (unit: bytes, example: 23181365248.0)\n- memory_total (unit: bytes, example: 64424656896.0)\n\n### couchbase_autofailover\n\nTags:\n\n- cluster: sanitized string from `servers` configuration field\n  e.g.: `http://user:password@couchbase-0.example.com:8091/endpoint` becomes\n  `http://couchbase-0.example.com:8091/endpoint`\n\nFields:\n\n- count (unit: int, example: 1)\n- enabled (unit: bool, example: true)\n- max_count (unit: int, example: 2)\n- timeout (unit: int, example: 72)\n\n### couchbase_bucket and couchbase_node_bucket\n\nTags:\n\n- cluster: whatever you called it in `servers` in the configuration,\n  e.g. `http://couchbase-0.example.com/`\n- bucket: the name of the couchbase bucket, e.g., `blastro-df`\n- hostname: the hostname of the node the bucket metrics were collected\n  from, e.g. `172.16.10.187:8091` (only present in `couchbase_node_bucket`)\n\nDefault bucket fields:\n\n- quota_percent_used (unit: percent, example: 68.85424936294555)\n- ops_per_sec (unit: count, example: 5686.789686789687)\n- disk_fetches (unit: count, example: 0.0)\n- item_count (unit: count, example: 943239752.0)\n- disk_used (unit: bytes, example: 409178772321.0)\n- data_used (unit: bytes, example: 212179309111.0)\n- mem_used (unit: bytes, example: 202156957464.0)\n\nAdditional fields that can be configured with the `bucket_stats_included`\noption:\n\n- couch_total_disk_size\n- couch_docs_fragmentation\n- couch_views_fragmentation\n- hit_ratio\n- ep_cache_miss_rate\n- ep_resident_items_rate\n- vb_avg_active_queue_age\n- vb_avg_replica_queue_age\n- vb_avg_pending_queue_age\n- vb_avg_total_queue_age\n- vb_active_resident_items_ratio\n- vb_replica_resident_items_ratio\n- vb_pending_resident_items_ratio\n- avg_disk_update_time\n- avg_disk_commit_time\n- avg_bg_wait_time\n- avg_active_timestamp_drift\n- avg_replica_timestamp_drift\n- ep_dcp_views+indexes_count\n- ep_dcp_views+indexes_items_remaining\n- ep_dcp_views+indexes_producer_count\n- ep_dcp_views+indexes_total_backlog_size\n- ep_dcp_views+indexes_items_sent\n- ep_dcp_views+indexes_total_bytes\n- ep_dcp_views+indexes_backoff\n- bg_wait_count\n- bg_wait_total\n- bytes_read\n- bytes_written\n- cas_badval\n- cas_hits\n- cas_misses\n- cmd_get\n- cmd_lookup\n- cmd_set\n- couch_docs_actual_disk_size\n- couch_docs_data_size\n- couch_docs_disk_size\n- couch_spatial_data_size\n- couch_spatial_disk_size\n- couch_spatial_ops\n- couch_views_actual_disk_size\n- couch_views_data_size\n- couch_views_disk_size\n- couch_views_ops\n- curr_connections\n- curr_items\n- curr_items_tot\n- decr_hits\n- decr_misses\n- delete_hits\n- delete_misses\n- disk_commit_count\n- disk_commit_total\n- disk_update_count\n- disk_update_total\n- disk_write_queue\n- ep_active_ahead_exceptions\n- ep_active_hlc_drift\n- ep_active_hlc_drift_count\n- ep_bg_fetched\n- ep_clock_cas_drift_threshold_exceeded\n- ep_data_read_failed\n- ep_data_write_failed\n- ep_dcp_2i_backoff\n- ep_dcp_2i_count\n- ep_dcp_2i_items_remaining\n- ep_dcp_2i_items_sent\n- ep_dcp_2i_producer_count\n- ep_dcp_2i_total_backlog_size\n- ep_dcp_2i_total_bytes\n- ep_dcp_cbas_backoff\n- ep_dcp_cbas_count\n- ep_dcp_cbas_items_remaining\n- ep_dcp_cbas_items_sent\n- ep_dcp_cbas_producer_count\n- ep_dcp_cbas_total_backlog_size\n- ep_dcp_cbas_total_bytes\n- ep_dcp_eventing_backoff\n- ep_dcp_eventing_count\n- ep_dcp_eventing_items_remaining\n- ep_dcp_eventing_items_sent\n- ep_dcp_eventing_producer_count\n- ep_dcp_eventing_total_backlog_size\n- ep_dcp_eventing_total_bytes\n- ep_dcp_fts_backoff\n- ep_dcp_fts_count\n- ep_dcp_fts_items_remaining\n- ep_dcp_fts_items_sent\n- ep_dcp_fts_producer_count\n- ep_dcp_fts_total_backlog_size\n- ep_dcp_fts_total_bytes\n- ep_dcp_other_backoff\n- ep_dcp_other_count\n- ep_dcp_other_items_remaining\n- ep_dcp_other_items_sent\n- ep_dcp_other_producer_count\n- ep_dcp_other_total_backlog_size\n- ep_dcp_other_total_bytes\n- ep_dcp_replica_backoff\n- ep_dcp_replica_count\n- ep_dcp_replica_items_remaining\n- ep_dcp_replica_items_sent\n- ep_dcp_replica_producer_count\n- ep_dcp_replica_total_backlog_size\n- ep_dcp_replica_total_bytes\n- ep_dcp_views_backoff\n- ep_dcp_views_count\n- ep_dcp_views_items_remaining\n- ep_dcp_views_items_sent\n- ep_dcp_views_producer_count\n- ep_dcp_views_total_backlog_size\n- ep_dcp_views_total_bytes\n- ep_dcp_xdcr_backoff\n- ep_dcp_xdcr_count\n- ep_dcp_xdcr_items_remaining\n- ep_dcp_xdcr_items_sent\n- ep_dcp_xdcr_producer_count\n- ep_dcp_xdcr_total_backlog_size\n- ep_dcp_xdcr_total_bytes\n- ep_diskqueue_drain\n- ep_diskqueue_fill\n- ep_diskqueue_items\n- ep_flusher_todo\n- ep_item_commit_failed\n- ep_kv_size\n- ep_max_size\n- ep_mem_high_wat\n- ep_mem_low_wat\n- ep_meta_data_memory\n- ep_num_non_resident\n- ep_num_ops_del_meta\n- ep_num_ops_del_ret_meta\n- ep_num_ops_get_meta\n- ep_num_ops_set_meta\n- ep_num_ops_set_ret_meta\n- ep_num_value_ejects\n- ep_oom_errors\n- ep_ops_create\n- ep_ops_update\n- ep_overhead\n- ep_queue_size\n- ep_replica_ahead_exceptions\n- ep_replica_hlc_drift\n- ep_replica_hlc_drift_count\n- ep_tmp_oom_errors\n- ep_vb_total\n- evictions\n- get_hits\n- get_misses\n- incr_hits\n- incr_misses\n- mem_used\n- misses\n- ops\n- timestamp\n- vb_active_eject\n- vb_active_itm_memory\n- vb_active_meta_data_memory\n- vb_active_num\n- vb_active_num_non_resident\n- vb_active_ops_create\n- vb_active_ops_update\n- vb_active_queue_age\n- vb_active_queue_drain\n- vb_active_queue_fill\n- vb_active_queue_size\n- vb_active_sync_write_aborted_count\n- vb_active_sync_write_accepted_count\n- vb_active_sync_write_committed_count\n- vb_pending_curr_items\n- vb_pending_eject\n- vb_pending_itm_memory\n- vb_pending_meta_data_memory\n- vb_pending_num\n- vb_pending_num_non_resident\n- vb_pending_ops_create\n- vb_pending_ops_update\n- vb_pending_queue_age\n- vb_pending_queue_drain\n- vb_pending_queue_fill\n- vb_pending_queue_size\n- vb_replica_curr_items\n- vb_replica_eject\n- vb_replica_itm_memory\n- vb_replica_meta_data_memory\n- vb_replica_num\n- vb_replica_num_non_resident\n- vb_replica_ops_create\n- vb_replica_ops_update\n- vb_replica_queue_age\n- vb_replica_queue_drain\n- vb_replica_queue_fill\n- vb_replica_queue_size\n- vb_total_queue_age\n- xdc_ops\n- allocstall\n- cpu_cores_available\n- cpu_irq_rate\n- cpu_stolen_rate\n- cpu_sys_rate\n- cpu_user_rate\n- cpu_utilization_rate\n- hibernated_requests\n- hibernated_waked\n- mem_actual_free\n- mem_actual_used\n- mem_free\n- mem_limit\n- mem_total\n- mem_used_sys\n- odp_report_failed\n- rest_requests\n- swap_total\n- swap_used\n\n## Example Output\n\n```text\ncouchbase_node,cluster=http://localhost:8091/,hostname=172.17.0.2:8091 memory_free=7705575424,memory_total=16558182400 1547829754000000000\ncouchbase_bucket,bucket=beer-sample,cluster=http://localhost:8091/ quota_percent_used=27.09285736083984,ops_per_sec=0,disk_fetches=0,item_count=7303,disk_used=21662946,data_used=9325087,mem_used=28408920 1547829754000000000\n```\n"
  },
  {
    "path": "plugins/inputs/couchbase/couchbase.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage couchbase\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/couchbase/go-couchbase\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar regexpURI = regexp.MustCompile(`(\\S+://)?(\\S+\\:\\S+@)`)\n\ntype Couchbase struct {\n\tServers             []string `toml:\"servers\"`\n\tBucketStatsIncluded []string `toml:\"bucket_stats_included\"`\n\tClusterBucketStats  bool     `toml:\"cluster_bucket_stats\"`\n\tNodeBucketStats     bool     `toml:\"node_bucket_stats\"`\n\tAdditionalStats     []string `toml:\"additional_stats\"`\n\n\tbucketInclude filter.Filter\n\tclient        *http.Client\n\n\ttls.ClientConfig\n}\n\ntype autoFailover struct {\n\tCount    int  `json:\"count\"`\n\tEnabled  bool `json:\"enabled\"`\n\tMaxCount int  `json:\"maxCount\"`\n\tTimeout  int  `json:\"timeout\"`\n}\n\nfunc (*Couchbase) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (cb *Couchbase) Init() error {\n\tf, err := filter.NewIncludeExcludeFilter(cb.BucketStatsIncluded, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcb.bucketInclude = f\n\n\ttlsConfig, err := cb.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcb.client = &http.Client{\n\t\tTimeout: 10 * time.Second,\n\t\tTransport: &http.Transport{\n\t\t\tMaxIdleConnsPerHost: couchbase.MaxIdleConnsPerHost,\n\t\t\tTLSClientConfig:     tlsConfig,\n\t\t},\n\t}\n\n\tcouchbase.SetSkipVerify(cb.ClientConfig.InsecureSkipVerify)\n\tcouchbase.SetCertFile(cb.ClientConfig.TLSCert)\n\tcouchbase.SetKeyFile(cb.ClientConfig.TLSKey)\n\tcouchbase.SetRootFile(cb.ClientConfig.TLSCA)\n\n\treturn nil\n}\n\n// Gather reads stats from all configured clusters. Accumulates stats.\n// Returns one of the errors encountered while gathering stats (if any).\nfunc (cb *Couchbase) Gather(acc telegraf.Accumulator) error {\n\tif len(cb.Servers) == 0 {\n\t\treturn cb.gatherServer(acc, \"http://localhost:8091/\")\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, serv := range cb.Servers {\n\t\twg.Add(1)\n\t\tgo func(serv string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(cb.gatherServer(acc, serv))\n\t\t}(serv)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (cb *Couchbase) gatherServer(acc telegraf.Accumulator, addr string) error {\n\tescapedAddr := regexpURI.ReplaceAllString(addr, \"${1}\")\n\n\tclient, err := couchbase.Connect(addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// `default` is the only possible pool name. It's a\n\t// placeholder for a possible future Couchbase feature. See\n\t// http://stackoverflow.com/a/16990911/17498.\n\tpool, err := client.GetPool(\"default\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer pool.Close()\n\n\tfor i := 0; i < len(pool.Nodes); i++ {\n\t\tnode := pool.Nodes[i]\n\t\ttags := map[string]string{\"cluster\": escapedAddr, \"hostname\": node.Hostname}\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"memory_free\"] = node.MemoryFree\n\t\tfields[\"memory_total\"] = node.MemoryTotal\n\t\tacc.AddFields(\"couchbase_node\", fields, tags)\n\t}\n\n\tcluster := regexpURI.ReplaceAllString(addr, \"${1}\")\n\tfor name, bucket := range pool.BucketMap {\n\t\tif cb.ClusterBucketStats {\n\t\t\tfields := cb.basicBucketStats(bucket.BasicStats)\n\t\t\ttags := map[string]string{\"cluster\": cluster, \"bucket\": name}\n\n\t\t\terr := cb.gatherDetailedBucketStats(addr, name, \"\", fields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tacc.AddFields(\"couchbase_bucket\", fields, tags)\n\t\t}\n\n\t\tif cb.NodeBucketStats {\n\t\t\tfor _, node := range bucket.Nodes() {\n\t\t\t\tfields := cb.basicBucketStats(bucket.BasicStats)\n\t\t\t\ttags := map[string]string{\"cluster\": cluster, \"bucket\": name, \"hostname\": node.Hostname}\n\n\t\t\t\terr := cb.gatherDetailedBucketStats(addr, name, node.Hostname, fields)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tacc.AddFields(\"couchbase_node_bucket\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\n\tif choice.Contains(\"autofailover\", cb.AdditionalStats) {\n\t\ttags := map[string]string{\"cluster\": cluster}\n\t\tfields, err := cb.gatherAutoFailoverStats(addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to collect autofailover settings: %w\", err)\n\t\t}\n\n\t\tacc.AddFields(\"couchbase_autofailover\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (cb *Couchbase) gatherAutoFailoverStats(server string) (map[string]any, error) {\n\tvar fields map[string]any\n\n\turl := server + \"/settings/autoFailover\"\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn fields, err\n\t}\n\n\tr, err := cb.client.Do(req)\n\tif err != nil {\n\t\treturn fields, err\n\t}\n\tdefer r.Body.Close()\n\n\tvar stats autoFailover\n\tif err := json.NewDecoder(r.Body).Decode(&stats); err != nil {\n\t\treturn fields, err\n\t}\n\n\tfields = map[string]any{\n\t\t\"count\":     stats.Count,\n\t\t\"enabled\":   stats.Enabled,\n\t\t\"max_count\": stats.MaxCount,\n\t\t\"timeout\":   stats.Timeout,\n\t}\n\n\treturn fields, nil\n}\n\n// basicBucketStats gets the basic bucket statistics\nfunc (cb *Couchbase) basicBucketStats(basicStats map[string]interface{}) map[string]interface{} {\n\tfields := make(map[string]interface{})\n\tcb.addBucketField(fields, \"quota_percent_used\", basicStats[\"quotaPercentUsed\"])\n\tcb.addBucketField(fields, \"ops_per_sec\", basicStats[\"opsPerSec\"])\n\tcb.addBucketField(fields, \"disk_fetches\", basicStats[\"diskFetches\"])\n\tcb.addBucketField(fields, \"item_count\", basicStats[\"itemCount\"])\n\tcb.addBucketField(fields, \"disk_used\", basicStats[\"diskUsed\"])\n\tcb.addBucketField(fields, \"data_used\", basicStats[\"dataUsed\"])\n\tcb.addBucketField(fields, \"mem_used\", basicStats[\"memUsed\"])\n\treturn fields\n}\n\nfunc (cb *Couchbase) gatherDetailedBucketStats(server, bucket, nodeHostname string, fields map[string]interface{}) error {\n\textendedBucketStats := &bucketStats{}\n\terr := cb.queryDetailedBucketStats(server, bucket, nodeHostname, extendedBucketStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcb.addBucketFieldChecked(fields, \"couch_total_disk_size\", extendedBucketStats.Op.Samples.CouchTotalDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_docs_fragmentation\", extendedBucketStats.Op.Samples.CouchDocsFragmentation)\n\tcb.addBucketFieldChecked(fields, \"couch_views_fragmentation\", extendedBucketStats.Op.Samples.CouchViewsFragmentation)\n\tcb.addBucketFieldChecked(fields, \"hit_ratio\", extendedBucketStats.Op.Samples.HitRatio)\n\tcb.addBucketFieldChecked(fields, \"ep_cache_miss_rate\", extendedBucketStats.Op.Samples.EpCacheMissRate)\n\tcb.addBucketFieldChecked(fields, \"ep_resident_items_rate\", extendedBucketStats.Op.Samples.EpResidentItemsRate)\n\tcb.addBucketFieldChecked(fields, \"vb_avg_active_queue_age\", extendedBucketStats.Op.Samples.VbAvgActiveQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_avg_replica_queue_age\", extendedBucketStats.Op.Samples.VbAvgReplicaQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_avg_pending_queue_age\", extendedBucketStats.Op.Samples.VbAvgPendingQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_avg_total_queue_age\", extendedBucketStats.Op.Samples.VbAvgTotalQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_active_resident_items_ratio\", extendedBucketStats.Op.Samples.VbActiveResidentItemsRatio)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_resident_items_ratio\", extendedBucketStats.Op.Samples.VbReplicaResidentItemsRatio)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_resident_items_ratio\", extendedBucketStats.Op.Samples.VbPendingResidentItemsRatio)\n\tcb.addBucketFieldChecked(fields, \"avg_disk_update_time\", extendedBucketStats.Op.Samples.AvgDiskUpdateTime)\n\tcb.addBucketFieldChecked(fields, \"avg_disk_commit_time\", extendedBucketStats.Op.Samples.AvgDiskCommitTime)\n\tcb.addBucketFieldChecked(fields, \"avg_bg_wait_time\", extendedBucketStats.Op.Samples.AvgBgWaitTime)\n\tcb.addBucketFieldChecked(fields, \"avg_active_timestamp_drift\", extendedBucketStats.Op.Samples.AvgActiveTimestampDrift)\n\tcb.addBucketFieldChecked(fields, \"avg_replica_timestamp_drift\", extendedBucketStats.Op.Samples.AvgReplicaTimestampDrift)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_count\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_items_remaining\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_producer_count\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_items_sent\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_total_bytes\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views+indexes_backoff\", extendedBucketStats.Op.Samples.EpDcpViewsIndexesBackoff)\n\tcb.addBucketFieldChecked(fields, \"bg_wait_count\", extendedBucketStats.Op.Samples.BgWaitCount)\n\tcb.addBucketFieldChecked(fields, \"bg_wait_total\", extendedBucketStats.Op.Samples.BgWaitTotal)\n\tcb.addBucketFieldChecked(fields, \"bytes_read\", extendedBucketStats.Op.Samples.BytesRead)\n\tcb.addBucketFieldChecked(fields, \"bytes_written\", extendedBucketStats.Op.Samples.BytesWritten)\n\tcb.addBucketFieldChecked(fields, \"cas_badval\", extendedBucketStats.Op.Samples.CasBadval)\n\tcb.addBucketFieldChecked(fields, \"cas_hits\", extendedBucketStats.Op.Samples.CasHits)\n\tcb.addBucketFieldChecked(fields, \"cas_misses\", extendedBucketStats.Op.Samples.CasMisses)\n\tcb.addBucketFieldChecked(fields, \"cmd_get\", extendedBucketStats.Op.Samples.CmdGet)\n\tcb.addBucketFieldChecked(fields, \"cmd_lookup\", extendedBucketStats.Op.Samples.CmdLookup)\n\tcb.addBucketFieldChecked(fields, \"cmd_set\", extendedBucketStats.Op.Samples.CmdSet)\n\tcb.addBucketFieldChecked(fields, \"couch_docs_actual_disk_size\", extendedBucketStats.Op.Samples.CouchDocsActualDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_docs_data_size\", extendedBucketStats.Op.Samples.CouchDocsDataSize)\n\tcb.addBucketFieldChecked(fields, \"couch_docs_disk_size\", extendedBucketStats.Op.Samples.CouchDocsDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_spatial_data_size\", extendedBucketStats.Op.Samples.CouchSpatialDataSize)\n\tcb.addBucketFieldChecked(fields, \"couch_spatial_disk_size\", extendedBucketStats.Op.Samples.CouchSpatialDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_spatial_ops\", extendedBucketStats.Op.Samples.CouchSpatialOps)\n\tcb.addBucketFieldChecked(fields, \"couch_views_actual_disk_size\", extendedBucketStats.Op.Samples.CouchViewsActualDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_views_data_size\", extendedBucketStats.Op.Samples.CouchViewsDataSize)\n\tcb.addBucketFieldChecked(fields, \"couch_views_disk_size\", extendedBucketStats.Op.Samples.CouchViewsDiskSize)\n\tcb.addBucketFieldChecked(fields, \"couch_views_ops\", extendedBucketStats.Op.Samples.CouchViewsOps)\n\tcb.addBucketFieldChecked(fields, \"curr_connections\", extendedBucketStats.Op.Samples.CurrConnections)\n\tcb.addBucketFieldChecked(fields, \"curr_items\", extendedBucketStats.Op.Samples.CurrItems)\n\tcb.addBucketFieldChecked(fields, \"curr_items_tot\", extendedBucketStats.Op.Samples.CurrItemsTot)\n\tcb.addBucketFieldChecked(fields, \"decr_hits\", extendedBucketStats.Op.Samples.DecrHits)\n\tcb.addBucketFieldChecked(fields, \"decr_misses\", extendedBucketStats.Op.Samples.DecrMisses)\n\tcb.addBucketFieldChecked(fields, \"delete_hits\", extendedBucketStats.Op.Samples.DeleteHits)\n\tcb.addBucketFieldChecked(fields, \"delete_misses\", extendedBucketStats.Op.Samples.DeleteMisses)\n\tcb.addBucketFieldChecked(fields, \"disk_commit_count\", extendedBucketStats.Op.Samples.DiskCommitCount)\n\tcb.addBucketFieldChecked(fields, \"disk_commit_total\", extendedBucketStats.Op.Samples.DiskCommitTotal)\n\tcb.addBucketFieldChecked(fields, \"disk_update_count\", extendedBucketStats.Op.Samples.DiskUpdateCount)\n\tcb.addBucketFieldChecked(fields, \"disk_update_total\", extendedBucketStats.Op.Samples.DiskUpdateTotal)\n\tcb.addBucketFieldChecked(fields, \"disk_write_queue\", extendedBucketStats.Op.Samples.DiskWriteQueue)\n\tcb.addBucketFieldChecked(fields, \"ep_active_ahead_exceptions\", extendedBucketStats.Op.Samples.EpActiveAheadExceptions)\n\tcb.addBucketFieldChecked(fields, \"ep_active_hlc_drift\", extendedBucketStats.Op.Samples.EpActiveHlcDrift)\n\tcb.addBucketFieldChecked(fields, \"ep_active_hlc_drift_count\", extendedBucketStats.Op.Samples.EpActiveHlcDriftCount)\n\tcb.addBucketFieldChecked(fields, \"ep_bg_fetched\", extendedBucketStats.Op.Samples.EpBgFetched)\n\tcb.addBucketFieldChecked(fields, \"ep_clock_cas_drift_threshold_exceeded\", extendedBucketStats.Op.Samples.EpClockCasDriftThresholdExceeded)\n\tcb.addBucketFieldChecked(fields, \"ep_data_read_failed\", extendedBucketStats.Op.Samples.EpDataReadFailed)\n\tcb.addBucketFieldChecked(fields, \"ep_data_write_failed\", extendedBucketStats.Op.Samples.EpDataWriteFailed)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_backoff\", extendedBucketStats.Op.Samples.EpDcp2IBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_count\", extendedBucketStats.Op.Samples.EpDcp2ICount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_items_remaining\", extendedBucketStats.Op.Samples.EpDcp2IItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_items_sent\", extendedBucketStats.Op.Samples.EpDcp2IItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_producer_count\", extendedBucketStats.Op.Samples.EpDcp2IProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcp2ITotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_2i_total_bytes\", extendedBucketStats.Op.Samples.EpDcp2ITotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_backoff\", extendedBucketStats.Op.Samples.EpDcpCbasBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_count\", extendedBucketStats.Op.Samples.EpDcpCbasCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_items_remaining\", extendedBucketStats.Op.Samples.EpDcpCbasItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_items_sent\", extendedBucketStats.Op.Samples.EpDcpCbasItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_producer_count\", extendedBucketStats.Op.Samples.EpDcpCbasProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpCbasTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_cbas_total_bytes\", extendedBucketStats.Op.Samples.EpDcpCbasTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_backoff\", extendedBucketStats.Op.Samples.EpDcpEventingBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_count\", extendedBucketStats.Op.Samples.EpDcpEventingCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_items_remaining\", extendedBucketStats.Op.Samples.EpDcpEventingItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_items_sent\", extendedBucketStats.Op.Samples.EpDcpEventingItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_producer_count\", extendedBucketStats.Op.Samples.EpDcpEventingProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpEventingTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_eventing_total_bytes\", extendedBucketStats.Op.Samples.EpDcpEventingTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_backoff\", extendedBucketStats.Op.Samples.EpDcpFtsBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_count\", extendedBucketStats.Op.Samples.EpDcpFtsCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_items_remaining\", extendedBucketStats.Op.Samples.EpDcpFtsItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_items_sent\", extendedBucketStats.Op.Samples.EpDcpFtsItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_producer_count\", extendedBucketStats.Op.Samples.EpDcpFtsProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpFtsTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_fts_total_bytes\", extendedBucketStats.Op.Samples.EpDcpFtsTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_backoff\", extendedBucketStats.Op.Samples.EpDcpOtherBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_count\", extendedBucketStats.Op.Samples.EpDcpOtherCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_items_remaining\", extendedBucketStats.Op.Samples.EpDcpOtherItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_items_sent\", extendedBucketStats.Op.Samples.EpDcpOtherItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_producer_count\", extendedBucketStats.Op.Samples.EpDcpOtherProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpOtherTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_other_total_bytes\", extendedBucketStats.Op.Samples.EpDcpOtherTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_backoff\", extendedBucketStats.Op.Samples.EpDcpReplicaBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_count\", extendedBucketStats.Op.Samples.EpDcpReplicaCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_items_remaining\", extendedBucketStats.Op.Samples.EpDcpReplicaItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_items_sent\", extendedBucketStats.Op.Samples.EpDcpReplicaItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_producer_count\", extendedBucketStats.Op.Samples.EpDcpReplicaProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpReplicaTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_replica_total_bytes\", extendedBucketStats.Op.Samples.EpDcpReplicaTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_backoff\", extendedBucketStats.Op.Samples.EpDcpViewsBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_count\", extendedBucketStats.Op.Samples.EpDcpViewsCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_items_remaining\", extendedBucketStats.Op.Samples.EpDcpViewsItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_items_sent\", extendedBucketStats.Op.Samples.EpDcpViewsItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_producer_count\", extendedBucketStats.Op.Samples.EpDcpViewsProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpViewsTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_views_total_bytes\", extendedBucketStats.Op.Samples.EpDcpViewsTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_backoff\", extendedBucketStats.Op.Samples.EpDcpXdcrBackoff)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_count\", extendedBucketStats.Op.Samples.EpDcpXdcrCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_items_remaining\", extendedBucketStats.Op.Samples.EpDcpXdcrItemsRemaining)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_items_sent\", extendedBucketStats.Op.Samples.EpDcpXdcrItemsSent)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_producer_count\", extendedBucketStats.Op.Samples.EpDcpXdcrProducerCount)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_total_backlog_size\", extendedBucketStats.Op.Samples.EpDcpXdcrTotalBacklogSize)\n\tcb.addBucketFieldChecked(fields, \"ep_dcp_xdcr_total_bytes\", extendedBucketStats.Op.Samples.EpDcpXdcrTotalBytes)\n\tcb.addBucketFieldChecked(fields, \"ep_diskqueue_drain\", extendedBucketStats.Op.Samples.EpDiskqueueDrain)\n\tcb.addBucketFieldChecked(fields, \"ep_diskqueue_fill\", extendedBucketStats.Op.Samples.EpDiskqueueFill)\n\tcb.addBucketFieldChecked(fields, \"ep_diskqueue_items\", extendedBucketStats.Op.Samples.EpDiskqueueItems)\n\tcb.addBucketFieldChecked(fields, \"ep_flusher_todo\", extendedBucketStats.Op.Samples.EpFlusherTodo)\n\tcb.addBucketFieldChecked(fields, \"ep_item_commit_failed\", extendedBucketStats.Op.Samples.EpItemCommitFailed)\n\tcb.addBucketFieldChecked(fields, \"ep_kv_size\", extendedBucketStats.Op.Samples.EpKvSize)\n\tcb.addBucketFieldChecked(fields, \"ep_max_size\", extendedBucketStats.Op.Samples.EpMaxSize)\n\tcb.addBucketFieldChecked(fields, \"ep_mem_high_wat\", extendedBucketStats.Op.Samples.EpMemHighWat)\n\tcb.addBucketFieldChecked(fields, \"ep_mem_low_wat\", extendedBucketStats.Op.Samples.EpMemLowWat)\n\tcb.addBucketFieldChecked(fields, \"ep_meta_data_memory\", extendedBucketStats.Op.Samples.EpMetaDataMemory)\n\tcb.addBucketFieldChecked(fields, \"ep_num_non_resident\", extendedBucketStats.Op.Samples.EpNumNonResident)\n\tcb.addBucketFieldChecked(fields, \"ep_num_ops_del_meta\", extendedBucketStats.Op.Samples.EpNumOpsDelMeta)\n\tcb.addBucketFieldChecked(fields, \"ep_num_ops_del_ret_meta\", extendedBucketStats.Op.Samples.EpNumOpsDelRetMeta)\n\tcb.addBucketFieldChecked(fields, \"ep_num_ops_get_meta\", extendedBucketStats.Op.Samples.EpNumOpsGetMeta)\n\tcb.addBucketFieldChecked(fields, \"ep_num_ops_set_meta\", extendedBucketStats.Op.Samples.EpNumOpsSetMeta)\n\tcb.addBucketFieldChecked(fields, \"ep_num_ops_set_ret_meta\", extendedBucketStats.Op.Samples.EpNumOpsSetRetMeta)\n\tcb.addBucketFieldChecked(fields, \"ep_num_value_ejects\", extendedBucketStats.Op.Samples.EpNumValueEjects)\n\tcb.addBucketFieldChecked(fields, \"ep_oom_errors\", extendedBucketStats.Op.Samples.EpOomErrors)\n\tcb.addBucketFieldChecked(fields, \"ep_ops_create\", extendedBucketStats.Op.Samples.EpOpsCreate)\n\tcb.addBucketFieldChecked(fields, \"ep_ops_update\", extendedBucketStats.Op.Samples.EpOpsUpdate)\n\tcb.addBucketFieldChecked(fields, \"ep_overhead\", extendedBucketStats.Op.Samples.EpOverhead)\n\tcb.addBucketFieldChecked(fields, \"ep_queue_size\", extendedBucketStats.Op.Samples.EpQueueSize)\n\tcb.addBucketFieldChecked(fields, \"ep_replica_ahead_exceptions\", extendedBucketStats.Op.Samples.EpReplicaAheadExceptions)\n\tcb.addBucketFieldChecked(fields, \"ep_replica_hlc_drift\", extendedBucketStats.Op.Samples.EpReplicaHlcDrift)\n\tcb.addBucketFieldChecked(fields, \"ep_replica_hlc_drift_count\", extendedBucketStats.Op.Samples.EpReplicaHlcDriftCount)\n\tcb.addBucketFieldChecked(fields, \"ep_tmp_oom_errors\", extendedBucketStats.Op.Samples.EpTmpOomErrors)\n\tcb.addBucketFieldChecked(fields, \"ep_vb_total\", extendedBucketStats.Op.Samples.EpVbTotal)\n\tcb.addBucketFieldChecked(fields, \"evictions\", extendedBucketStats.Op.Samples.Evictions)\n\tcb.addBucketFieldChecked(fields, \"get_hits\", extendedBucketStats.Op.Samples.GetHits)\n\tcb.addBucketFieldChecked(fields, \"get_misses\", extendedBucketStats.Op.Samples.GetMisses)\n\tcb.addBucketFieldChecked(fields, \"incr_hits\", extendedBucketStats.Op.Samples.IncrHits)\n\tcb.addBucketFieldChecked(fields, \"incr_misses\", extendedBucketStats.Op.Samples.IncrMisses)\n\tcb.addBucketFieldChecked(fields, \"misses\", extendedBucketStats.Op.Samples.Misses)\n\tcb.addBucketFieldChecked(fields, \"ops\", extendedBucketStats.Op.Samples.Ops)\n\tcb.addBucketFieldChecked(fields, \"timestamp\", extendedBucketStats.Op.Samples.Timestamp)\n\tcb.addBucketFieldChecked(fields, \"vb_active_eject\", extendedBucketStats.Op.Samples.VbActiveEject)\n\tcb.addBucketFieldChecked(fields, \"vb_active_itm_memory\", extendedBucketStats.Op.Samples.VbActiveItmMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_active_meta_data_memory\", extendedBucketStats.Op.Samples.VbActiveMetaDataMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_active_num\", extendedBucketStats.Op.Samples.VbActiveNum)\n\tcb.addBucketFieldChecked(fields, \"vb_active_num_non_resident\", extendedBucketStats.Op.Samples.VbActiveNumNonResident)\n\tcb.addBucketFieldChecked(fields, \"vb_active_ops_create\", extendedBucketStats.Op.Samples.VbActiveOpsCreate)\n\tcb.addBucketFieldChecked(fields, \"vb_active_ops_update\", extendedBucketStats.Op.Samples.VbActiveOpsUpdate)\n\tcb.addBucketFieldChecked(fields, \"vb_active_queue_age\", extendedBucketStats.Op.Samples.VbActiveQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_active_queue_drain\", extendedBucketStats.Op.Samples.VbActiveQueueDrain)\n\tcb.addBucketFieldChecked(fields, \"vb_active_queue_fill\", extendedBucketStats.Op.Samples.VbActiveQueueFill)\n\tcb.addBucketFieldChecked(fields, \"vb_active_queue_size\", extendedBucketStats.Op.Samples.VbActiveQueueSize)\n\tcb.addBucketFieldChecked(fields, \"vb_active_sync_write_aborted_count\", extendedBucketStats.Op.Samples.VbActiveSyncWriteAbortedCount)\n\tcb.addBucketFieldChecked(fields, \"vb_active_sync_write_accepted_count\", extendedBucketStats.Op.Samples.VbActiveSyncWriteAcceptedCount)\n\tcb.addBucketFieldChecked(fields, \"vb_active_sync_write_committed_count\", extendedBucketStats.Op.Samples.VbActiveSyncWriteCommittedCount)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_curr_items\", extendedBucketStats.Op.Samples.VbPendingCurrItems)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_eject\", extendedBucketStats.Op.Samples.VbPendingEject)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_itm_memory\", extendedBucketStats.Op.Samples.VbPendingItmMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_meta_data_memory\", extendedBucketStats.Op.Samples.VbPendingMetaDataMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_num\", extendedBucketStats.Op.Samples.VbPendingNum)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_num_non_resident\", extendedBucketStats.Op.Samples.VbPendingNumNonResident)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_ops_create\", extendedBucketStats.Op.Samples.VbPendingOpsCreate)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_ops_update\", extendedBucketStats.Op.Samples.VbPendingOpsUpdate)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_queue_age\", extendedBucketStats.Op.Samples.VbPendingQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_queue_drain\", extendedBucketStats.Op.Samples.VbPendingQueueDrain)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_queue_fill\", extendedBucketStats.Op.Samples.VbPendingQueueFill)\n\tcb.addBucketFieldChecked(fields, \"vb_pending_queue_size\", extendedBucketStats.Op.Samples.VbPendingQueueSize)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_curr_items\", extendedBucketStats.Op.Samples.VbReplicaCurrItems)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_eject\", extendedBucketStats.Op.Samples.VbReplicaEject)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_itm_memory\", extendedBucketStats.Op.Samples.VbReplicaItmMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_meta_data_memory\", extendedBucketStats.Op.Samples.VbReplicaMetaDataMemory)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_num\", extendedBucketStats.Op.Samples.VbReplicaNum)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_num_non_resident\", extendedBucketStats.Op.Samples.VbReplicaNumNonResident)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_ops_create\", extendedBucketStats.Op.Samples.VbReplicaOpsCreate)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_ops_update\", extendedBucketStats.Op.Samples.VbReplicaOpsUpdate)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_queue_age\", extendedBucketStats.Op.Samples.VbReplicaQueueAge)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_queue_drain\", extendedBucketStats.Op.Samples.VbReplicaQueueDrain)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_queue_fill\", extendedBucketStats.Op.Samples.VbReplicaQueueFill)\n\tcb.addBucketFieldChecked(fields, \"vb_replica_queue_size\", extendedBucketStats.Op.Samples.VbReplicaQueueSize)\n\tcb.addBucketFieldChecked(fields, \"vb_total_queue_age\", extendedBucketStats.Op.Samples.VbTotalQueueAge)\n\tcb.addBucketFieldChecked(fields, \"xdc_ops\", extendedBucketStats.Op.Samples.XdcOps)\n\tcb.addBucketFieldChecked(fields, \"allocstall\", extendedBucketStats.Op.Samples.Allocstall)\n\tcb.addBucketFieldChecked(fields, \"cpu_cores_available\", extendedBucketStats.Op.Samples.CPUCoresAvailable)\n\tcb.addBucketFieldChecked(fields, \"cpu_irq_rate\", extendedBucketStats.Op.Samples.CPUIrqRate)\n\tcb.addBucketFieldChecked(fields, \"cpu_stolen_rate\", extendedBucketStats.Op.Samples.CPUStolenRate)\n\tcb.addBucketFieldChecked(fields, \"cpu_sys_rate\", extendedBucketStats.Op.Samples.CPUSysRate)\n\tcb.addBucketFieldChecked(fields, \"cpu_user_rate\", extendedBucketStats.Op.Samples.CPUUserRate)\n\tcb.addBucketFieldChecked(fields, \"cpu_utilization_rate\", extendedBucketStats.Op.Samples.CPUUtilizationRate)\n\tcb.addBucketFieldChecked(fields, \"hibernated_requests\", extendedBucketStats.Op.Samples.HibernatedRequests)\n\tcb.addBucketFieldChecked(fields, \"hibernated_waked\", extendedBucketStats.Op.Samples.HibernatedWaked)\n\tcb.addBucketFieldChecked(fields, \"mem_actual_free\", extendedBucketStats.Op.Samples.MemActualFree)\n\tcb.addBucketFieldChecked(fields, \"mem_actual_used\", extendedBucketStats.Op.Samples.MemActualUsed)\n\tcb.addBucketFieldChecked(fields, \"mem_free\", extendedBucketStats.Op.Samples.MemFree)\n\tcb.addBucketFieldChecked(fields, \"mem_limit\", extendedBucketStats.Op.Samples.MemLimit)\n\tcb.addBucketFieldChecked(fields, \"mem_total\", extendedBucketStats.Op.Samples.MemTotal)\n\tcb.addBucketFieldChecked(fields, \"mem_used_sys\", extendedBucketStats.Op.Samples.MemUsedSys)\n\tcb.addBucketFieldChecked(fields, \"odp_report_failed\", extendedBucketStats.Op.Samples.OdpReportFailed)\n\tcb.addBucketFieldChecked(fields, \"rest_requests\", extendedBucketStats.Op.Samples.RestRequests)\n\tcb.addBucketFieldChecked(fields, \"swap_total\", extendedBucketStats.Op.Samples.SwapTotal)\n\tcb.addBucketFieldChecked(fields, \"swap_used\", extendedBucketStats.Op.Samples.SwapUsed)\n\n\treturn nil\n}\n\nfunc (cb *Couchbase) addBucketField(fields map[string]interface{}, fieldKey string, value interface{}) {\n\tif !cb.bucketInclude.Match(fieldKey) {\n\t\treturn\n\t}\n\n\tfields[fieldKey] = value\n}\n\nfunc (cb *Couchbase) addBucketFieldChecked(fields map[string]interface{}, fieldKey string, values []float64) {\n\tif values == nil {\n\t\treturn\n\t}\n\n\tcb.addBucketField(fields, fieldKey, values[len(values)-1])\n}\n\nfunc (cb *Couchbase) queryDetailedBucketStats(server, bucket, nodeHostname string, bucketStats *bucketStats) error {\n\turl := server + \"/pools/default/buckets/\" + bucket\n\tif nodeHostname != \"\" {\n\t\turl += \"/nodes/\" + nodeHostname\n\t}\n\turl += \"/stats?\"\n\n\t// Set up an HTTP request to get the complete set of bucket stats.\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr, err := cb.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer r.Body.Close()\n\n\treturn json.NewDecoder(r.Body).Decode(bucketStats)\n}\n\nfunc init() {\n\tinputs.Add(\"couchbase\", func() telegraf.Input {\n\t\treturn &Couchbase{\n\t\t\tBucketStatsIncluded: []string{\"quota_percent_used\", \"ops_per_sec\", \"disk_fetches\", \"item_count\", \"disk_used\", \"data_used\", \"mem_used\"},\n\t\t\tClusterBucketStats:  true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/couchbase_data.go",
    "content": "package couchbase\n\ntype bucketStats struct {\n\tOp struct {\n\t\tSamples struct {\n\t\t\tCouchTotalDiskSize                []float64 `json:\"couch_total_disk_size\"`\n\t\t\tCouchDocsFragmentation            []float64 `json:\"couch_docs_fragmentation\"`\n\t\t\tCouchViewsFragmentation           []float64 `json:\"couch_views_fragmentation\"`\n\t\t\tHitRatio                          []float64 `json:\"hit_ratio\"`\n\t\t\tEpCacheMissRate                   []float64 `json:\"ep_cache_miss_rate\"`\n\t\t\tEpResidentItemsRate               []float64 `json:\"ep_resident_items_rate\"`\n\t\t\tVbAvgActiveQueueAge               []float64 `json:\"vb_avg_active_queue_age\"`\n\t\t\tVbAvgReplicaQueueAge              []float64 `json:\"vb_avg_replica_queue_age\"`\n\t\t\tVbAvgPendingQueueAge              []float64 `json:\"vb_avg_pending_queue_age\"`\n\t\t\tVbAvgTotalQueueAge                []float64 `json:\"vb_avg_total_queue_age\"`\n\t\t\tVbActiveResidentItemsRatio        []float64 `json:\"vb_active_resident_items_ratio\"`\n\t\t\tVbReplicaResidentItemsRatio       []float64 `json:\"vb_replica_resident_items_ratio\"`\n\t\t\tVbPendingResidentItemsRatio       []float64 `json:\"vb_pending_resident_items_ratio\"`\n\t\t\tAvgDiskUpdateTime                 []float64 `json:\"avg_disk_update_time\"`\n\t\t\tAvgDiskCommitTime                 []float64 `json:\"avg_disk_commit_time\"`\n\t\t\tAvgBgWaitTime                     []float64 `json:\"avg_bg_wait_time\"`\n\t\t\tAvgActiveTimestampDrift           []float64 `json:\"avg_active_timestamp_drift\"`\n\t\t\tAvgReplicaTimestampDrift          []float64 `json:\"avg_replica_timestamp_drift\"`\n\t\t\tEpDcpViewsIndexesCount            []float64 `json:\"ep_dcp_views+indexes_count\"`\n\t\t\tEpDcpViewsIndexesItemsRemaining   []float64 `json:\"ep_dcp_views+indexes_items_remaining\"`\n\t\t\tEpDcpViewsIndexesProducerCount    []float64 `json:\"ep_dcp_views+indexes_producer_count\"`\n\t\t\tEpDcpViewsIndexesTotalBacklogSize []float64 `json:\"ep_dcp_views+indexes_total_backlog_size\"`\n\t\t\tEpDcpViewsIndexesItemsSent        []float64 `json:\"ep_dcp_views+indexes_items_sent\"`\n\t\t\tEpDcpViewsIndexesTotalBytes       []float64 `json:\"ep_dcp_views+indexes_total_bytes\"`\n\t\t\tEpDcpViewsIndexesBackoff          []float64 `json:\"ep_dcp_views+indexes_backoff\"`\n\t\t\tBgWaitCount                       []float64 `json:\"bg_wait_count\"`\n\t\t\tBgWaitTotal                       []float64 `json:\"bg_wait_total\"`\n\t\t\tBytesRead                         []float64 `json:\"bytes_read\"`\n\t\t\tBytesWritten                      []float64 `json:\"bytes_written\"`\n\t\t\tCasBadval                         []float64 `json:\"cas_badval\"`\n\t\t\tCasHits                           []float64 `json:\"cas_hits\"`\n\t\t\tCasMisses                         []float64 `json:\"cas_misses\"`\n\t\t\tCmdGet                            []float64 `json:\"cmd_get\"`\n\t\t\tCmdLookup                         []float64 `json:\"cmd_lookup\"`\n\t\t\tCmdSet                            []float64 `json:\"cmd_set\"`\n\t\t\tCouchDocsActualDiskSize           []float64 `json:\"couch_docs_actual_disk_size\"`\n\t\t\tCouchDocsDataSize                 []float64 `json:\"couch_docs_data_size\"`\n\t\t\tCouchDocsDiskSize                 []float64 `json:\"couch_docs_disk_size\"`\n\t\t\tCouchSpatialDataSize              []float64 `json:\"couch_spatial_data_size\"`\n\t\t\tCouchSpatialDiskSize              []float64 `json:\"couch_spatial_disk_size\"`\n\t\t\tCouchSpatialOps                   []float64 `json:\"couch_spatial_ops\"`\n\t\t\tCouchViewsActualDiskSize          []float64 `json:\"couch_views_actual_disk_size\"`\n\t\t\tCouchViewsDataSize                []float64 `json:\"couch_views_data_size\"`\n\t\t\tCouchViewsDiskSize                []float64 `json:\"couch_views_disk_size\"`\n\t\t\tCouchViewsOps                     []float64 `json:\"couch_views_ops\"`\n\t\t\tCurrConnections                   []float64 `json:\"curr_connections\"`\n\t\t\tCurrItems                         []float64 `json:\"curr_items\"`\n\t\t\tCurrItemsTot                      []float64 `json:\"curr_items_tot\"`\n\t\t\tDecrHits                          []float64 `json:\"decr_hits\"`\n\t\t\tDecrMisses                        []float64 `json:\"decr_misses\"`\n\t\t\tDeleteHits                        []float64 `json:\"delete_hits\"`\n\t\t\tDeleteMisses                      []float64 `json:\"delete_misses\"`\n\t\t\tDiskCommitCount                   []float64 `json:\"disk_commit_count\"`\n\t\t\tDiskCommitTotal                   []float64 `json:\"disk_commit_total\"`\n\t\t\tDiskUpdateCount                   []float64 `json:\"disk_update_count\"`\n\t\t\tDiskUpdateTotal                   []float64 `json:\"disk_update_total\"`\n\t\t\tDiskWriteQueue                    []float64 `json:\"disk_write_queue\"`\n\t\t\tEpActiveAheadExceptions           []float64 `json:\"ep_active_ahead_exceptions\"`\n\t\t\tEpActiveHlcDrift                  []float64 `json:\"ep_active_hlc_drift\"`\n\t\t\tEpActiveHlcDriftCount             []float64 `json:\"ep_active_hlc_drift_count\"`\n\t\t\tEpBgFetched                       []float64 `json:\"ep_bg_fetched\"`\n\t\t\tEpClockCasDriftThresholdExceeded  []float64 `json:\"ep_clock_cas_drift_threshold_exceeded\"`\n\t\t\tEpDataReadFailed                  []float64 `json:\"ep_data_read_failed\"`\n\t\t\tEpDataWriteFailed                 []float64 `json:\"ep_data_write_failed\"`\n\t\t\tEpDcp2IBackoff                    []float64 `json:\"ep_dcp_2i_backoff\"`\n\t\t\tEpDcp2ICount                      []float64 `json:\"ep_dcp_2i_count\"`\n\t\t\tEpDcp2IItemsRemaining             []float64 `json:\"ep_dcp_2i_items_remaining\"`\n\t\t\tEpDcp2IItemsSent                  []float64 `json:\"ep_dcp_2i_items_sent\"`\n\t\t\tEpDcp2IProducerCount              []float64 `json:\"ep_dcp_2i_producer_count\"`\n\t\t\tEpDcp2ITotalBacklogSize           []float64 `json:\"ep_dcp_2i_total_backlog_size\"`\n\t\t\tEpDcp2ITotalBytes                 []float64 `json:\"ep_dcp_2i_total_bytes\"`\n\t\t\tEpDcpCbasBackoff                  []float64 `json:\"ep_dcp_cbas_backoff\"`\n\t\t\tEpDcpCbasCount                    []float64 `json:\"ep_dcp_cbas_count\"`\n\t\t\tEpDcpCbasItemsRemaining           []float64 `json:\"ep_dcp_cbas_items_remaining\"`\n\t\t\tEpDcpCbasItemsSent                []float64 `json:\"ep_dcp_cbas_items_sent\"`\n\t\t\tEpDcpCbasProducerCount            []float64 `json:\"ep_dcp_cbas_producer_count\"`\n\t\t\tEpDcpCbasTotalBacklogSize         []float64 `json:\"ep_dcp_cbas_total_backlog_size\"`\n\t\t\tEpDcpCbasTotalBytes               []float64 `json:\"ep_dcp_cbas_total_bytes\"`\n\t\t\tEpDcpEventingBackoff              []float64 `json:\"ep_dcp_eventing_backoff\"`\n\t\t\tEpDcpEventingCount                []float64 `json:\"ep_dcp_eventing_count\"`\n\t\t\tEpDcpEventingItemsRemaining       []float64 `json:\"ep_dcp_eventing_items_remaining\"`\n\t\t\tEpDcpEventingItemsSent            []float64 `json:\"ep_dcp_eventing_items_sent\"`\n\t\t\tEpDcpEventingProducerCount        []float64 `json:\"ep_dcp_eventing_producer_count\"`\n\t\t\tEpDcpEventingTotalBacklogSize     []float64 `json:\"ep_dcp_eventing_total_backlog_size\"`\n\t\t\tEpDcpEventingTotalBytes           []float64 `json:\"ep_dcp_eventing_total_bytes\"`\n\t\t\tEpDcpFtsBackoff                   []float64 `json:\"ep_dcp_fts_backoff\"`\n\t\t\tEpDcpFtsCount                     []float64 `json:\"ep_dcp_fts_count\"`\n\t\t\tEpDcpFtsItemsRemaining            []float64 `json:\"ep_dcp_fts_items_remaining\"`\n\t\t\tEpDcpFtsItemsSent                 []float64 `json:\"ep_dcp_fts_items_sent\"`\n\t\t\tEpDcpFtsProducerCount             []float64 `json:\"ep_dcp_fts_producer_count\"`\n\t\t\tEpDcpFtsTotalBacklogSize          []float64 `json:\"ep_dcp_fts_total_backlog_size\"`\n\t\t\tEpDcpFtsTotalBytes                []float64 `json:\"ep_dcp_fts_total_bytes\"`\n\t\t\tEpDcpOtherBackoff                 []float64 `json:\"ep_dcp_other_backoff\"`\n\t\t\tEpDcpOtherCount                   []float64 `json:\"ep_dcp_other_count\"`\n\t\t\tEpDcpOtherItemsRemaining          []float64 `json:\"ep_dcp_other_items_remaining\"`\n\t\t\tEpDcpOtherItemsSent               []float64 `json:\"ep_dcp_other_items_sent\"`\n\t\t\tEpDcpOtherProducerCount           []float64 `json:\"ep_dcp_other_producer_count\"`\n\t\t\tEpDcpOtherTotalBacklogSize        []float64 `json:\"ep_dcp_other_total_backlog_size\"`\n\t\t\tEpDcpOtherTotalBytes              []float64 `json:\"ep_dcp_other_total_bytes\"`\n\t\t\tEpDcpReplicaBackoff               []float64 `json:\"ep_dcp_replica_backoff\"`\n\t\t\tEpDcpReplicaCount                 []float64 `json:\"ep_dcp_replica_count\"`\n\t\t\tEpDcpReplicaItemsRemaining        []float64 `json:\"ep_dcp_replica_items_remaining\"`\n\t\t\tEpDcpReplicaItemsSent             []float64 `json:\"ep_dcp_replica_items_sent\"`\n\t\t\tEpDcpReplicaProducerCount         []float64 `json:\"ep_dcp_replica_producer_count\"`\n\t\t\tEpDcpReplicaTotalBacklogSize      []float64 `json:\"ep_dcp_replica_total_backlog_size\"`\n\t\t\tEpDcpReplicaTotalBytes            []float64 `json:\"ep_dcp_replica_total_bytes\"`\n\t\t\tEpDcpViewsBackoff                 []float64 `json:\"ep_dcp_views_backoff\"`\n\t\t\tEpDcpViewsCount                   []float64 `json:\"ep_dcp_views_count\"`\n\t\t\tEpDcpViewsItemsRemaining          []float64 `json:\"ep_dcp_views_items_remaining\"`\n\t\t\tEpDcpViewsItemsSent               []float64 `json:\"ep_dcp_views_items_sent\"`\n\t\t\tEpDcpViewsProducerCount           []float64 `json:\"ep_dcp_views_producer_count\"`\n\t\t\tEpDcpViewsTotalBacklogSize        []float64 `json:\"ep_dcp_views_total_backlog_size\"`\n\t\t\tEpDcpViewsTotalBytes              []float64 `json:\"ep_dcp_views_total_bytes\"`\n\t\t\tEpDcpXdcrBackoff                  []float64 `json:\"ep_dcp_xdcr_backoff\"`\n\t\t\tEpDcpXdcrCount                    []float64 `json:\"ep_dcp_xdcr_count\"`\n\t\t\tEpDcpXdcrItemsRemaining           []float64 `json:\"ep_dcp_xdcr_items_remaining\"`\n\t\t\tEpDcpXdcrItemsSent                []float64 `json:\"ep_dcp_xdcr_items_sent\"`\n\t\t\tEpDcpXdcrProducerCount            []float64 `json:\"ep_dcp_xdcr_producer_count\"`\n\t\t\tEpDcpXdcrTotalBacklogSize         []float64 `json:\"ep_dcp_xdcr_total_backlog_size\"`\n\t\t\tEpDcpXdcrTotalBytes               []float64 `json:\"ep_dcp_xdcr_total_bytes\"`\n\t\t\tEpDiskqueueDrain                  []float64 `json:\"ep_diskqueue_drain\"`\n\t\t\tEpDiskqueueFill                   []float64 `json:\"ep_diskqueue_fill\"`\n\t\t\tEpDiskqueueItems                  []float64 `json:\"ep_diskqueue_items\"`\n\t\t\tEpFlusherTodo                     []float64 `json:\"ep_flusher_todo\"`\n\t\t\tEpItemCommitFailed                []float64 `json:\"ep_item_commit_failed\"`\n\t\t\tEpKvSize                          []float64 `json:\"ep_kv_size\"`\n\t\t\tEpMaxSize                         []float64 `json:\"ep_max_size\"`\n\t\t\tEpMemHighWat                      []float64 `json:\"ep_mem_high_wat\"`\n\t\t\tEpMemLowWat                       []float64 `json:\"ep_mem_low_wat\"`\n\t\t\tEpMetaDataMemory                  []float64 `json:\"ep_meta_data_memory\"`\n\t\t\tEpNumNonResident                  []float64 `json:\"ep_num_non_resident\"`\n\t\t\tEpNumOpsDelMeta                   []float64 `json:\"ep_num_ops_del_meta\"`\n\t\t\tEpNumOpsDelRetMeta                []float64 `json:\"ep_num_ops_del_ret_meta\"`\n\t\t\tEpNumOpsGetMeta                   []float64 `json:\"ep_num_ops_get_meta\"`\n\t\t\tEpNumOpsSetMeta                   []float64 `json:\"ep_num_ops_set_meta\"`\n\t\t\tEpNumOpsSetRetMeta                []float64 `json:\"ep_num_ops_set_ret_meta\"`\n\t\t\tEpNumValueEjects                  []float64 `json:\"ep_num_value_ejects\"`\n\t\t\tEpOomErrors                       []float64 `json:\"ep_oom_errors\"`\n\t\t\tEpOpsCreate                       []float64 `json:\"ep_ops_create\"`\n\t\t\tEpOpsUpdate                       []float64 `json:\"ep_ops_update\"`\n\t\t\tEpOverhead                        []float64 `json:\"ep_overhead\"`\n\t\t\tEpQueueSize                       []float64 `json:\"ep_queue_size\"`\n\t\t\tEpReplicaAheadExceptions          []float64 `json:\"ep_replica_ahead_exceptions\"`\n\t\t\tEpReplicaHlcDrift                 []float64 `json:\"ep_replica_hlc_drift\"`\n\t\t\tEpReplicaHlcDriftCount            []float64 `json:\"ep_replica_hlc_drift_count\"`\n\t\t\tEpTmpOomErrors                    []float64 `json:\"ep_tmp_oom_errors\"`\n\t\t\tEpVbTotal                         []float64 `json:\"ep_vb_total\"`\n\t\t\tEvictions                         []float64 `json:\"evictions\"`\n\t\t\tGetHits                           []float64 `json:\"get_hits\"`\n\t\t\tGetMisses                         []float64 `json:\"get_misses\"`\n\t\t\tIncrHits                          []float64 `json:\"incr_hits\"`\n\t\t\tIncrMisses                        []float64 `json:\"incr_misses\"`\n\t\t\tMemUsed                           []float64 `json:\"mem_used\"`\n\t\t\tMisses                            []float64 `json:\"misses\"`\n\t\t\tOps                               []float64 `json:\"ops\"`\n\t\t\tTimestamp                         []float64 `json:\"timestamp\"`\n\t\t\tVbActiveEject                     []float64 `json:\"vb_active_eject\"`\n\t\t\tVbActiveItmMemory                 []float64 `json:\"vb_active_itm_memory\"`\n\t\t\tVbActiveMetaDataMemory            []float64 `json:\"vb_active_meta_data_memory\"`\n\t\t\tVbActiveNum                       []float64 `json:\"vb_active_num\"`\n\t\t\tVbActiveNumNonResident            []float64 `json:\"vb_active_num_non_resident\"`\n\t\t\tVbActiveOpsCreate                 []float64 `json:\"vb_active_ops_create\"`\n\t\t\tVbActiveOpsUpdate                 []float64 `json:\"vb_active_ops_update\"`\n\t\t\tVbActiveQueueAge                  []float64 `json:\"vb_active_queue_age\"`\n\t\t\tVbActiveQueueDrain                []float64 `json:\"vb_active_queue_drain\"`\n\t\t\tVbActiveQueueFill                 []float64 `json:\"vb_active_queue_fill\"`\n\t\t\tVbActiveQueueSize                 []float64 `json:\"vb_active_queue_size\"`\n\t\t\tVbActiveSyncWriteAbortedCount     []float64 `json:\"vb_active_sync_write_aborted_count\"`\n\t\t\tVbActiveSyncWriteAcceptedCount    []float64 `json:\"vb_active_sync_write_accepted_count\"`\n\t\t\tVbActiveSyncWriteCommittedCount   []float64 `json:\"vb_active_sync_write_committed_count\"`\n\t\t\tVbPendingCurrItems                []float64 `json:\"vb_pending_curr_items\"`\n\t\t\tVbPendingEject                    []float64 `json:\"vb_pending_eject\"`\n\t\t\tVbPendingItmMemory                []float64 `json:\"vb_pending_itm_memory\"`\n\t\t\tVbPendingMetaDataMemory           []float64 `json:\"vb_pending_meta_data_memory\"`\n\t\t\tVbPendingNum                      []float64 `json:\"vb_pending_num\"`\n\t\t\tVbPendingNumNonResident           []float64 `json:\"vb_pending_num_non_resident\"`\n\t\t\tVbPendingOpsCreate                []float64 `json:\"vb_pending_ops_create\"`\n\t\t\tVbPendingOpsUpdate                []float64 `json:\"vb_pending_ops_update\"`\n\t\t\tVbPendingQueueAge                 []float64 `json:\"vb_pending_queue_age\"`\n\t\t\tVbPendingQueueDrain               []float64 `json:\"vb_pending_queue_drain\"`\n\t\t\tVbPendingQueueFill                []float64 `json:\"vb_pending_queue_fill\"`\n\t\t\tVbPendingQueueSize                []float64 `json:\"vb_pending_queue_size\"`\n\t\t\tVbReplicaCurrItems                []float64 `json:\"vb_replica_curr_items\"`\n\t\t\tVbReplicaEject                    []float64 `json:\"vb_replica_eject\"`\n\t\t\tVbReplicaItmMemory                []float64 `json:\"vb_replica_itm_memory\"`\n\t\t\tVbReplicaMetaDataMemory           []float64 `json:\"vb_replica_meta_data_memory\"`\n\t\t\tVbReplicaNum                      []float64 `json:\"vb_replica_num\"`\n\t\t\tVbReplicaNumNonResident           []float64 `json:\"vb_replica_num_non_resident\"`\n\t\t\tVbReplicaOpsCreate                []float64 `json:\"vb_replica_ops_create\"`\n\t\t\tVbReplicaOpsUpdate                []float64 `json:\"vb_replica_ops_update\"`\n\t\t\tVbReplicaQueueAge                 []float64 `json:\"vb_replica_queue_age\"`\n\t\t\tVbReplicaQueueDrain               []float64 `json:\"vb_replica_queue_drain\"`\n\t\t\tVbReplicaQueueFill                []float64 `json:\"vb_replica_queue_fill\"`\n\t\t\tVbReplicaQueueSize                []float64 `json:\"vb_replica_queue_size\"`\n\t\t\tVbTotalQueueAge                   []float64 `json:\"vb_total_queue_age\"`\n\t\t\tXdcOps                            []float64 `json:\"xdc_ops\"`\n\t\t\tAllocstall                        []float64 `json:\"allocstall\"`\n\t\t\tCPUCoresAvailable                 []float64 `json:\"cpu_cores_available\"`\n\t\t\tCPUIrqRate                        []float64 `json:\"cpu_irq_rate\"`\n\t\t\tCPUStolenRate                     []float64 `json:\"cpu_stolen_rate\"`\n\t\t\tCPUSysRate                        []float64 `json:\"cpu_sys_rate\"`\n\t\t\tCPUUserRate                       []float64 `json:\"cpu_user_rate\"`\n\t\t\tCPUUtilizationRate                []float64 `json:\"cpu_utilization_rate\"`\n\t\t\tHibernatedRequests                []float64 `json:\"hibernated_requests\"`\n\t\t\tHibernatedWaked                   []float64 `json:\"hibernated_waked\"`\n\t\t\tMemActualFree                     []float64 `json:\"mem_actual_free\"`\n\t\t\tMemActualUsed                     []float64 `json:\"mem_actual_used\"`\n\t\t\tMemFree                           []float64 `json:\"mem_free\"`\n\t\t\tMemLimit                          []float64 `json:\"mem_limit\"`\n\t\t\tMemTotal                          []float64 `json:\"mem_total\"`\n\t\t\tMemUsedSys                        []float64 `json:\"mem_used_sys\"`\n\t\t\tOdpReportFailed                   []float64 `json:\"odp_report_failed\"`\n\t\t\tRestRequests                      []float64 `json:\"rest_requests\"`\n\t\t\tSwapTotal                         []float64 `json:\"swap_total\"`\n\t\t\tSwapUsed                          []float64 `json:\"swap_used\"`\n\t\t} `json:\"samples\"`\n\t\tSamplescount int   `json:\"samplesCount\"`\n\t\tIspersistent bool  `json:\"isPersistent\"`\n\t\tLasttstamp   int64 `json:\"lastTStamp\"`\n\t\tInterval     int   `json:\"interval\"`\n\t} `json:\"op\"`\n\tHotKeys []interface{} `json:\"hot_keys\"`\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/couchbase_test.go",
    "content": "package couchbase\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGatherServer(t *testing.T) {\n\tbucket := \"blastro-df\"\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/pools\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if r.URL.Path == \"/pools/default\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_default_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if r.URL.Path == \"/pools/default/buckets\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/bucket_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if r.URL.Path == \"/pools/default/buckets/\"+bucket+\"/stats\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/bucket_stats_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tcb := Couchbase{\n\t\tClusterBucketStats:  true,\n\t\tBucketStatsIncluded: []string{\"quota_percent_used\", \"ops_per_sec\", \"disk_fetches\", \"item_count\", \"disk_used\", \"data_used\", \"mem_used\"},\n\t}\n\trequire.NoError(t, cb.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, cb.gatherServer(&acc, fakeServer.URL))\n\n\tacc.AssertContainsTaggedFields(t, \"couchbase_node\",\n\t\tmap[string]interface{}{\"memory_free\": 23181365248.0, \"memory_total\": 64424656896.0},\n\t\tmap[string]string{\"cluster\": fakeServer.URL, \"hostname\": \"172.16.10.187:8091\"})\n\tacc.AssertContainsTaggedFields(t, \"couchbase_node\",\n\t\tmap[string]interface{}{\"memory_free\": 23665811456.0, \"memory_total\": 64424656896.0},\n\t\tmap[string]string{\"cluster\": fakeServer.URL, \"hostname\": \"172.16.10.65:8091\"})\n\tacc.AssertContainsTaggedFields(t, \"couchbase_bucket\",\n\t\tmap[string]interface{}{\n\t\t\t\"quota_percent_used\": 68.85424936294555,\n\t\t\t\"ops_per_sec\":        5686.789686789687,\n\t\t\t\"disk_fetches\":       0.0,\n\t\t\t\"item_count\":         943239752.0,\n\t\t\t\"disk_used\":          409178772321.0,\n\t\t\t\"data_used\":          212179309111.0,\n\t\t\t\"mem_used\":           202156957464.0,\n\t\t},\n\t\tmap[string]string{\"cluster\": fakeServer.URL, \"bucket\": \"blastro-df\"})\n}\n\nfunc TestSanitizeURI(t *testing.T) {\n\tvar sanitizeTest = []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\"http://user:password@localhost:121\", \"http://localhost:121\"},\n\t\t{\"user:password@localhost:12/endpoint\", \"localhost:12/endpoint\"},\n\t\t{\"https://mail@address.com:password@localhost\", \"https://localhost\"},\n\t\t{\"localhost\", \"localhost\"},\n\t\t{\"user:password@localhost:2321\", \"localhost:2321\"},\n\t\t{\"http://user:password@couchbase-0.example.com:8091/endpoint\", \"http://couchbase-0.example.com:8091/endpoint\"},\n\t\t{\" \", \" \"},\n\t}\n\n\tfor _, test := range sanitizeTest {\n\t\tresult := regexpURI.ReplaceAllString(test.input, \"${1}\")\n\n\t\tif result != test.expected {\n\t\t\tt.Errorf(\"TestSanitizeAddress: input %s, expected %s, actual %s\", test.input, test.expected, result)\n\t\t}\n\t}\n}\n\nfunc TestGatherDetailedBucketMetrics(t *testing.T) {\n\tbucket := \"Ducks\"\n\tnode := \"172.94.77.2:8091\"\n\n\tbucketStatsResponse := readJSON(t, \"testdata/bucket_stats_response.json\")\n\tbucketStatsResponseWithMissing := readJSON(t, \"testdata/bucket_stats_response_with_missing.json\")\n\tnodeBucketStatsResponse := readJSON(t, \"testdata/node_bucket_stats_response.json\")\n\n\ttests := []struct {\n\t\tname     string\n\t\tnode     string\n\t\tresponse []byte\n\t}{\n\t\t{\n\t\t\tname:     \"cluster-level with all fields\",\n\t\t\tresponse: bucketStatsResponse,\n\t\t},\n\t\t{\n\t\t\tname:     \"cluster-level with missing fields\",\n\t\t\tresponse: bucketStatsResponseWithMissing,\n\t\t},\n\t\t{\n\t\t\tname:     \"node-level with all fields\",\n\t\t\tresponse: nodeBucketStatsResponse,\n\t\t\tnode:     node,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif r.URL.Path == \"/pools/default/buckets/\"+bucket+\"/stats\" || r.URL.Path == \"/pools/default/buckets/\"+bucket+\"/nodes/\"+node+\"/stats\" {\n\t\t\t\t\tif _, err := w.Write(test.response); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\n\t\t\tvar err error\n\t\t\tvar cb Couchbase\n\t\t\tcb.BucketStatsIncluded = []string{\"couch_total_disk_size\"}\n\t\t\tcb.ClientConfig = tls.ClientConfig{\n\t\t\t\tInsecureSkipVerify: true,\n\t\t\t}\n\t\t\terr = cb.Init()\n\t\t\trequire.NoError(t, err)\n\t\t\tvar acc testutil.Accumulator\n\t\t\tbucketStats := &bucketStats{}\n\t\t\tif err := json.Unmarshal(test.response, bucketStats); err != nil {\n\t\t\t\tt.Fatal(\"parse bucketResponse\", err)\n\t\t\t}\n\n\t\t\tfields := make(map[string]interface{})\n\t\t\terr = cb.gatherDetailedBucketStats(fakeServer.URL, bucket, test.node, fields)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc.AddFields(\"couchbase_bucket\", fields, nil)\n\n\t\t\t// Ensure we gathered only one metric (the one that we configured).\n\t\t\trequire.Len(t, acc.Metrics, 1)\n\t\t\trequire.Len(t, acc.Metrics[0].Fields, 1)\n\t\t})\n\t}\n}\n\nfunc TestGatherNodeOnly(t *testing.T) {\n\tfaker := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/pools\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if r.URL.Path == \"/pools/default\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_default_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if r.URL.Path == \"/pools/default/buckets\" {\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/bucket_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tcb := Couchbase{\n\t\tServers: []string{faker.URL},\n\t}\n\trequire.NoError(t, cb.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, cb.gatherServer(&acc, faker.URL))\n\n\trequire.Empty(t, acc.Errors)\n\trequire.Len(t, acc.Metrics, 7)\n\tacc.AssertDoesNotContainMeasurement(t, \"couchbase_bucket\")\n}\n\nfunc TestGatherFailover(t *testing.T) {\n\tfaker := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/pools\":\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/pools/default\":\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/pools_default_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/pools/default/buckets\":\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/bucket_response.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/settings/autoFailover\":\n\t\t\tif _, err := w.Write(readJSON(t, \"testdata/settings_autofailover.json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tcb := Couchbase{\n\t\tServers:            []string{faker.URL},\n\t\tClusterBucketStats: false,\n\t\tNodeBucketStats:    false,\n\t\tAdditionalStats:    []string{\"autofailover\"},\n\t}\n\trequire.NoError(t, cb.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, cb.gatherServer(&acc, faker.URL))\n\trequire.Empty(t, acc.Errors)\n\trequire.Len(t, acc.Metrics, 8)\n\n\tvar metric *testutil.Metric\n\tfor _, m := range acc.Metrics {\n\t\tif m.Measurement == \"couchbase_autofailover\" {\n\t\t\tmetric = m\n\t\t\tbreak\n\t\t}\n\t}\n\n\trequire.NotNil(t, metric)\n\trequire.Equal(t, 1, metric.Fields[\"count\"])\n\tv, ok := metric.Fields[\"enabled\"].(bool)\n\trequire.Truef(t, ok, \"bool type expected, got '%T' with '%v' value instead\", metric.Fields[\"enabled\"], metric.Fields[\"enabled\"])\n\trequire.True(t, v)\n\n\trequire.Equal(t, 2, metric.Fields[\"max_count\"])\n\trequire.Equal(t, 72, metric.Fields[\"timeout\"])\n}\n\nfunc readJSON(t *testing.T, jsonFilePath string) []byte {\n\tdata, err := os.ReadFile(jsonFilePath)\n\trequire.NoErrorf(t, err, \"could not read from data file %s\", jsonFilePath)\n\n\treturn data\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/sample.conf",
    "content": "# Read per-node and per-bucket metrics from Couchbase\n[[inputs.couchbase]]\n  ## specify servers via a url matching:\n  ##  [protocol://][:password]@address[:port]\n  ##  e.g.\n  ##    http://couchbase-0.example.com/\n  ##    http://admin:secret@couchbase-0.example.com:8091/\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no protocol is specified, HTTP is used.\n  ## If no port is specified, 8091 is used.\n  servers = [\"http://localhost:8091\"]\n\n  ## Filter bucket fields to include only here.\n  # bucket_stats_included = [\"quota_percent_used\", \"ops_per_sec\", \"disk_fetches\", \"item_count\", \"disk_used\", \"data_used\", \"mem_used\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification (defaults to false)\n  ## If set to false, tls_cert and tls_key are required\n  # insecure_skip_verify = false\n\n  ## Whether to collect cluster-wide bucket statistics\n  ## It is recommended to disable this in favor of node_stats\n  ## to get a better view of the cluster.\n  # cluster_bucket_stats = true\n\n  ## Whether to collect bucket stats for each individual node\n  # node_bucket_stats = false\n\n  ## List of additional stats to collect, choose from:\n  ##  * autofailover\n  # additional_stats = []\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/bucket_response.json",
    "content": "[\n  {\n    \"name\": \"blastro-df\",\n    \"bucketType\": \"membase\",\n    \"authType\": \"sasl\",\n    \"saslPassword\": \"\",\n    \"proxyPort\": 0,\n    \"replicaIndex\": false,\n    \"uri\": \"/pools/default/buckets/blastro-df?bucket_uuid=2e6b9dc4c278300ce3a4f27ad540323f\",\n    \"streamingUri\": \"/pools/default/bucketsStreaming/blastro-df?bucket_uuid=2e6b9dc4c278300ce3a4f27ad540323f\",\n    \"localRandomKeyUri\": \"/pools/default/buckets/blastro-df/localRandomKey\",\n    \"controllers\": {\n      \"compactAll\": \"/pools/default/buckets/blastro-df/controller/compactBucket\",\n      \"compactDB\": \"/pools/default/buckets/default/controller/compactDatabases\",\n      \"purgeDeletes\": \"/pools/default/buckets/blastro-df/controller/unsafePurgeBucket\",\n      \"startRecovery\": \"/pools/default/buckets/blastro-df/controller/startRecovery\"\n    },\n    \"nodes\": [\n      {\n        \"couchApiBase\": \"http://172.16.8.148:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 18.39557399723375,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23791935488\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 10.98901098901099,\n          \"couch_docs_actual_disk_size\": 79525832077,\n          \"couch_docs_data_size\": 38633186946,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 139229304,\n          \"curr_items_tot\": 278470058,\n          \"ep_bg_fetched\": 0,\n          \"get_hits\": 5.994005994005994,\n          \"mem_used\": 36284362960,\n          \"ops\": 1275.724275724276,\n          \"vb_replica_curr_items\": 139240754\n        },\n        \"uptime\": \"343968\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23791935488,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.8.148\",\n        \"hostname\": \"172.16.8.148:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.8.127:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 21.97183098591549,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23533023232\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 39.96003996003996,\n          \"couch_docs_actual_disk_size\": 63322357663,\n          \"couch_docs_data_size\": 38603481061,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 139262616,\n          \"curr_items_tot\": 278508069,\n          \"ep_bg_fetched\": 0.999000999000999,\n          \"get_hits\": 30.96903096903097,\n          \"mem_used\": 36475078736,\n          \"ops\": 1370.629370629371,\n          \"vb_replica_curr_items\": 139245453\n        },\n        \"uptime\": \"339914\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23533023232,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.8.127\",\n        \"hostname\": \"172.16.8.127:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.15.120:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 23.38028169014084,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23672963072\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 88.08808808808809,\n          \"couch_docs_actual_disk_size\": 80260594761,\n          \"couch_docs_data_size\": 38632863189,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 139251563,\n          \"curr_items_tot\": 278498913,\n          \"ep_bg_fetched\": 0,\n          \"get_hits\": 74.07407407407408,\n          \"mem_used\": 36348663000,\n          \"ops\": 1707.707707707708,\n          \"vb_replica_curr_items\": 139247350\n        },\n        \"uptime\": \"343235\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23672963072,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.15.120\",\n        \"hostname\": \"172.16.15.120:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.13.173:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 22.15988779803646,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23818825728\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 103.1031031031031,\n          \"couch_docs_actual_disk_size\": 68247785524,\n          \"couch_docs_data_size\": 38747583467,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 139245453,\n          \"curr_items_tot\": 279451313,\n          \"ep_bg_fetched\": 1.001001001001001,\n          \"get_hits\": 86.08608608608608,\n          \"mem_used\": 36524715864,\n          \"ops\": 1749.74974974975,\n          \"vb_replica_curr_items\": 140205860\n        },\n        \"uptime\": \"343266\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23818825728,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.13.173\",\n        \"hostname\": \"172.16.13.173:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.13.105:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 21.94444444444444,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23721426944\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 113.1131131131131,\n          \"couch_docs_actual_disk_size\": 68102832275,\n          \"couch_docs_data_size\": 38747477407,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 139230887,\n          \"curr_items_tot\": 279420530,\n          \"ep_bg_fetched\": 0,\n          \"get_hits\": 106.1061061061061,\n          \"mem_used\": 36524887624,\n          \"ops\": 1799.7997997998,\n          \"vb_replica_curr_items\": 140189643\n        },\n        \"uptime\": \"343950\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23721426944,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.13.105\",\n        \"hostname\": \"172.16.13.105:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.10.65:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 60.62176165803109,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23618203648\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 30.96903096903097,\n          \"couch_docs_actual_disk_size\": 69052175561,\n          \"couch_docs_data_size\": 38755695030,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 140210194,\n          \"curr_items_tot\": 279454253,\n          \"ep_bg_fetched\": 0,\n          \"get_hits\": 26.97302697302698,\n          \"mem_used\": 36543072472,\n          \"ops\": 1337.662337662338,\n          \"vb_replica_curr_items\": 139244059\n        },\n        \"uptime\": \"343950\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23618203648,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.10.65\",\n        \"hostname\": \"172.16.10.65:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      },\n      {\n        \"couchApiBase\": \"http://172.16.10.187:8092/blastro-df%2B2e6b9dc4c278300ce3a4f27ad540323f\",\n        \"systemStats\": {\n          \"cpu_utilization_rate\": 21.83588317107093,\n          \"swap_total\": 0,\n          \"swap_used\": 0,\n          \"mem_total\": 64424656896,\n          \"mem_free\": 23062269952\n        },\n        \"interestingStats\": {\n          \"cmd_get\": 33.03303303303304,\n          \"couch_docs_actual_disk_size\": 74422029546,\n          \"couch_docs_data_size\": 38758172837,\n          \"couch_views_actual_disk_size\": 0,\n          \"couch_views_data_size\": 0,\n          \"curr_items\": 140194321,\n          \"curr_items_tot\": 279445526,\n          \"ep_bg_fetched\": 0,\n          \"get_hits\": 21.02102102102102,\n          \"mem_used\": 36527676832,\n          \"ops\": 1088.088088088088,\n          \"vb_replica_curr_items\": 139251205\n        },\n        \"uptime\": \"343971\",\n        \"memoryTotal\": 64424656896,\n        \"memoryFree\": 23062269952,\n        \"mcdMemoryReserved\": 49152,\n        \"mcdMemoryAllocated\": 49152,\n        \"replication\": 1,\n        \"clusterMembership\": \"active\",\n        \"recoveryType\": \"none\",\n        \"status\": \"healthy\",\n        \"otpNode\": \"ns_1@172.16.10.187\",\n        \"thisNode\": true,\n        \"hostname\": \"172.16.10.187:8091\",\n        \"clusterCompatibility\": 196608,\n        \"version\": \"3.0.1-1444-rel-community\",\n        \"os\": \"x86_64-unknown-linux-gnu\",\n        \"ports\": {\n          \"proxy\": 11211,\n          \"direct\": 11210\n        }\n      }\n    ],\n    \"stats\": {\n      \"uri\": \"/pools/default/buckets/blastro-df/stats\",\n      \"directoryURI\": \"/pools/default/buckets/blastro-df/statsDirectory\",\n      \"nodeStatsListURI\": \"/pools/default/buckets/blastro-df/nodes\"\n    },\n    \"ddocs\": {\n      \"uri\": \"/pools/default/buckets/blastro-df/ddocs\"\n    },\n    \"nodeLocator\": \"vbucket\",\n    \"fastWarmupSettings\": false,\n    \"autoCompactionSettings\": false,\n    \"uuid\": \"2e6b9dc4c278300ce3a4f27ad540323f\",\n    \"vBucketServerMap\": {\n      \"hashAlgorithm\": \"CRC\",\n      \"numReplicas\": 1,\n      \"serverList\": [\n        \"172.16.10.187:11210\",\n        \"172.16.10.65:11210\",\n        \"172.16.13.105:11210\",\n        \"172.16.13.173:11210\",\n        \"172.16.15.120:11210\",\n        \"172.16.8.127:11210\",\n        \"172.16.8.148:11210\"\n      ],\n      \"vBucketMap\": [\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          4\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          4\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          3,\n          5\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          2,\n          4\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          4,\n          5\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          2,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          3,\n          0\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          5\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          6\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          5\n        ],\n        [\n          1,\n          6\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          2,\n          5\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          2,\n          0\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          3,\n          4\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          0\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          5,\n          4\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          3,\n          6\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          5,\n          6\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          4,\n          0\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          1\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          5,\n          0\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          1\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          4,\n          3\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          5,\n          3\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          4,\n          6\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          6,\n          0\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          2,\n          1\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          2\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          6,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          3,\n          1\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          4,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          3,\n          2\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          1\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          5,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          6,\n          3\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          2\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          6,\n          2\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          0,\n          3\n        ],\n        [\n          1,\n          3\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          4\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          2,\n          3\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          5\n        ],\n        [\n          6,\n          2\n        ]\n      ]\n    },\n    \"replicaNumber\": 1,\n    \"threadsNumber\": 3,\n    \"quota\": {\n      \"ram\": 293601280000,\n      \"rawRAM\": 41943040000\n    },\n    \"basicStats\": {\n      \"quotaPercentUsed\": 68.85424936294555,\n      \"opsPerSec\": 5686.789686789687,\n      \"diskFetches\": 0,\n      \"itemCount\": 943239752,\n      \"diskUsed\": 409178772321,\n      \"dataUsed\": 212179309111,\n      \"memUsed\": 202156957464\n    },\n    \"evictionPolicy\": \"valueOnly\",\n    \"bucketCapabilitiesVer\": \"\",\n    \"bucketCapabilities\": [\n      \"cbhello\",\n      \"touch\",\n      \"couchapi\",\n      \"cccp\",\n      \"xdcrCheckpointing\",\n      \"nodesExt\"\n    ]\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/bucket_stats_response.json",
    "content": "{\n  \"op\": {\n    \"samples\": {\n      \"couch_total_disk_size\": [\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341\n      ],\n      \"couch_docs_fragmentation\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_fragmentation\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"hit_ratio\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_cache_miss_rate\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_resident_items_rate\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_avg_active_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_replica_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_pending_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_total_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_replica_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_pending_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"avg_disk_update_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_disk_commit_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_bg_wait_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_active_timestamp_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_replica_timestamp_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views+indexes_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bg_wait_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bg_wait_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bytes_read\": [\n        118.1818181818182,\n        142.2805247225025,\n        180.8080808080808,\n        197.7800201816347,\n        141.9939577039275,\n        118.5410334346505,\n        142.4242424242424,\n        148.4848484848485,\n        197.3816717019134,\n        202.4291497975709,\n        118.0625630676085,\n        142.4242424242424,\n        179.6165489404642,\n        197.979797979798,\n        142.4242424242424,\n        118.1818181818182,\n        142.2805247225025,\n        148.4848484848485,\n        197.979797979798,\n        201.816347124117,\n        118.1818181818182,\n        142.4242424242424,\n        148.4848484848485,\n        197.7800201816347,\n        142.4242424242424,\n        118.1818181818182,\n        142.2805247225025,\n        179.7979797979798,\n        197.1830985915493,\n        202.6342451874367,\n        118.1818181818182,\n        142.2805247225025,\n        180.4435483870968,\n        198.3805668016194,\n        142.2805247225025,\n        118.1818181818182,\n        142.2805247225025,\n        148.4848484848485,\n        197.979797979798,\n        202.020202020202,\n        118.0625630676085,\n        118.1818181818182,\n        204.040404040404,\n        197.7800201816347,\n        142.1370967741935,\n        118.4210526315789,\n        118.1818181818182,\n        172.5529767911201,\n        197.5806451612903,\n        202.4291497975709,\n        118.0625630676085,\n        118.1818181818182,\n        172.7272727272727,\n        197.7800201816347,\n        142.4242424242424,\n        118.0625630676085,\n        118.1818181818182,\n        204.040404040404,\n        197.979797979798,\n        201.816347124117\n      ],\n      \"bytes_written\": [\n        36420.20202020202,\n        37762.86579212916,\n        37225.25252525252,\n        50460.14127144299,\n        37686.80765357502,\n        36530.90172239109,\n        37801.0101010101,\n        37111.11111111111,\n        50358.50956696878,\n        60511.13360323886,\n        36383.45105953582,\n        37801.0101010101,\n        37393.54187689203,\n        50511.11111111111,\n        37801.0101010101,\n        36420.20202020202,\n        37762.86579212916,\n        37111.11111111111,\n        50511.11111111111,\n        60327.95156407669,\n        36420.20202020202,\n        37801.0101010101,\n        37111.11111111111,\n        50460.14127144299,\n        37801.0101010101,\n        36420.20202020202,\n        37762.86579212916,\n        37431.31313131313,\n        50307.84708249497,\n        60572.44174265451,\n        36420.20202020202,\n        37762.86579212916,\n        37150.20161290323,\n        50613.36032388664,\n        37762.86579212916,\n        36420.20202020202,\n        37762.86579212916,\n        37111.11111111111,\n        50511.11111111111,\n        60388.88888888889,\n        36383.45105953582,\n        36420.20202020202,\n        38812.12121212122,\n        50460.14127144299,\n        37724.79838709677,\n        36493.92712550607,\n        36420.20202020202,\n        38453.07769929364,\n        50409.27419354839,\n        60511.13360323886,\n        36383.45105953582,\n        36420.20202020202,\n        38491.91919191919,\n        50460.14127144299,\n        37801.0101010101,\n        36383.45105953582,\n        36420.20202020202,\n        38812.12121212122,\n        50511.11111111111,\n        60327.95156407669\n      ],\n      \"cas_badval\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cas_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cas_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_get\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_lookup\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_set\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_docs_actual_disk_size\": [\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341\n      ],\n      \"couch_docs_data_size\": [\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373\n      ],\n      \"couch_docs_disk_size\": [\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373,\n        531373\n      ],\n      \"couch_spatial_data_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_spatial_disk_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_spatial_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_actual_disk_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_data_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_disk_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"curr_connections\": [\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14,\n        14\n      ],\n      \"curr_items\": [\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1\n      ],\n      \"curr_items_tot\": [\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1\n      ],\n      \"decr_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"decr_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"delete_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"delete_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_commit_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_commit_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_update_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_update_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_write_queue\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_ahead_exceptions\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_hlc_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_hlc_drift_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_bg_fetched\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_clock_cas_drift_threshold_exceeded\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_data_read_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_data_write_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_cbas_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_eventing_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_fts_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_other_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_producer_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_total_backlog_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_xdcr_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_items\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_flusher_todo\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_item_commit_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_kv_size\": [\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340,\n        10340\n      ],\n      \"ep_max_size\": [\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032,\n        8264876032\n      ],\n      \"ep_mem_high_wat\": [\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627,\n        7025144627\n      ],\n      \"ep_mem_low_wat\": [\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024,\n        6198657024\n      ],\n      \"ep_meta_data_memory\": [\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68\n      ],\n      \"ep_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_del_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_del_ret_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_get_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_set_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_set_ret_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_value_ejects\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_oom_errors\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_overhead\": [\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824,\n        403824\n      ],\n      \"ep_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_ahead_exceptions\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_hlc_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_hlc_drift_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_tmp_oom_errors\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_vb_total\": [\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64\n      ],\n      \"evictions\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"get_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"get_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"incr_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"incr_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"mem_used\": [\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016,\n        4937016\n      ],\n      \"misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"timestamp\": [\n        1615918120012,\n        1615918121003,\n        1615918121993,\n        1615918122984,\n        1615918123977,\n        1615918124964,\n        1615918125954,\n        1615918126944,\n        1615918127937,\n        1615918128925,\n        1615918129916,\n        1615918130906,\n        1615918131897,\n        1615918132887,\n        1615918133877,\n        1615918134867,\n        1615918135858,\n        1615918136848,\n        1615918137838,\n        1615918138829,\n        1615918139819,\n        1615918140809,\n        1615918141799,\n        1615918142790,\n        1615918143780,\n        1615918144770,\n        1615918145761,\n        1615918146751,\n        1615918147745,\n        1615918148732,\n        1615918149722,\n        1615918150713,\n        1615918151705,\n        1615918152693,\n        1615918153684,\n        1615918154674,\n        1615918155665,\n        1615918156655,\n        1615918157645,\n        1615918158635,\n        1615918159626,\n        1615918160616,\n        1615918161606,\n        1615918162597,\n        1615918163589,\n        1615918164577,\n        1615918165567,\n        1615918166558,\n        1615918167550,\n        1615918168538,\n        1615918169529,\n        1615918170519,\n        1615918171509,\n        1615918172500,\n        1615918173490,\n        1615918174481,\n        1615918175471,\n        1615918176461,\n        1615918177451,\n        1615918178442\n      ],\n      \"vb_active_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_itm_memory\": [\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88,\n        88\n      ],\n      \"vb_active_meta_data_memory\": [\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68,\n        68\n      ],\n      \"vb_active_num\": [\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64,\n        64\n      ],\n      \"vb_active_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_aborted_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_accepted_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_committed_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_curr_items\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_itm_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_meta_data_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_num\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_curr_items\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_itm_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_meta_data_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_num\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_total_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"xdc_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"allocstall\": [\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615,\n        18446744073709551615\n      ],\n      \"cpu_cores_available\": [\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12,\n        12\n      ],\n      \"cpu_irq_rate\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cpu_stolen_rate\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cpu_sys_rate\": [\n        4.942965779467681,\n        5.243268776570619,\n        6.823027718550106,\n        4.815073272854153,\n        4.853128991060026,\n        5.068836045056321,\n        4.983108108108108,\n        4.110738255033557,\n        3.201347935973041,\n        3.959561920808762,\n        3.610411418975651,\n        3.459915611814346,\n        3.691275167785235,\n        4.553119730185498,\n        6.470588235294118,\n        4.545454545454546,\n        5.046257359125315,\n        5.976430976430977,\n        5.564924114671164,\n        3.703703703703704,\n        3.529411764705882,\n        3.544303797468354,\n        3.826787512588117,\n        5.118961788031723,\n        7.166947723440135,\n        5.87248322147651,\n        4.289318755256518,\n        5.485232067510548,\n        4.765886287625418,\n        4.672897196261682,\n        4.184100418410042,\n        4.560810810810811,\n        7.02928870292887,\n        6.081081081081081,\n        5.378151260504202,\n        6.239460370994941,\n        8.984047019311502,\n        6.896551724137931,\n        9.636517328825022,\n        9.335576114381833,\n        7.64063811922754,\n        8.684654300168635,\n        6.543624161073826,\n        6.465155331654072,\n        5.961376994122586,\n        3.807106598984772,\n        3.36417157275021,\n        3.700588730025231,\n        3.775167785234899,\n        9.45945945945946,\n        3.114478114478115,\n        3.451178451178451,\n        4.465037910699242,\n        3.852596314907873,\n        3.462837837837838,\n        5.205709487825357,\n        5.218855218855219,\n        6.532663316582915,\n        5.885057471264368,\n        4.030226700251889\n      ],\n      \"cpu_user_rate\": [\n        15.20912547528517,\n        9.58904109589041,\n        10.76759061833689,\n        8.443824145150035,\n        8.301404853128991,\n        10.95118898623279,\n        9.797297297297296,\n        6.879194630872483,\n        6.823925863521483,\n        6.908171861836562,\n        6.54911838790932,\n        6.835443037974684,\n        7.382550335570469,\n        10.28667790893761,\n        16.97478991596639,\n        11.53198653198653,\n        9.75609756097561,\n        11.11111111111111,\n        12.05733558178752,\n        7.154882154882155,\n        6.890756302521009,\n        6.666666666666667,\n        7.150050352467271,\n        10.23792357606345,\n        12.7318718381113,\n        9.479865771812081,\n        7.905803195962994,\n        8.016877637130802,\n        9.19732441471572,\n        9.600679694137638,\n        7.364016736401673,\n        8.108108108108109,\n        15.31380753138075,\n        13.85135135135135,\n        10.58823529411765,\n        12.64755480607083,\n        18.47187237615449,\n        13.28847771236333,\n        19.8647506339814,\n        21.86711522287637,\n        23.5936188077246,\n        22.17537942664418,\n        12.08053691275168,\n        16.96053736356003,\n        32.49370277078086,\n        8.20642978003384,\n        10.17661900756939,\n        7.653490328006728,\n        10.82214765100671,\n        14.27364864864865,\n        6.986531986531986,\n        7.407407407407407,\n        10.02527379949452,\n        11.55778894472362,\n        8.192567567567568,\n        12.34256926952141,\n        14.05723905723906,\n        28.64321608040201,\n        13.14942528735632,\n        7.388748950461797\n      ],\n      \"cpu_utilization_rate\": [\n        20.15209125475285,\n        14.83230987246103,\n        17.59061833688699,\n        13.25889741800419,\n        13.15453384418902,\n        16.02002503128911,\n        14.78040540540541,\n        10.98993288590604,\n        10.02527379949452,\n        10.86773378264532,\n        10.15952980688497,\n        10.29535864978903,\n        11.0738255033557,\n        14.8397976391231,\n        23.4453781512605,\n        16.07744107744108,\n        14.80235492010092,\n        17.08754208754209,\n        17.62225969645868,\n        10.85858585858586,\n        10.42016806722689,\n        10.21097046413502,\n        10.97683786505539,\n        15.35688536409517,\n        19.89881956155143,\n        15.35234899328859,\n        12.19512195121951,\n        13.50210970464135,\n        13.96321070234114,\n        14.27357689039932,\n        11.54811715481171,\n        12.66891891891892,\n        22.34309623430962,\n        19.93243243243243,\n        15.96638655462185,\n        18.88701517706577,\n        27.45591939546599,\n        20.18502943650126,\n        29.50126796280642,\n        31.2026913372582,\n        31.23425692695214,\n        30.86003372681282,\n        18.6241610738255,\n        23.42569269521411,\n        38.45507976490345,\n        12.01353637901861,\n        13.5407905803196,\n        11.35407905803196,\n        14.59731543624161,\n        23.73310810810811,\n        10.1010101010101,\n        10.85858585858586,\n        14.49031171019377,\n        15.41038525963149,\n        11.65540540540541,\n        17.54827875734677,\n        19.27609427609428,\n        35.17587939698493,\n        19.03448275862069,\n        11.41897565071369\n      ],\n      \"hibernated_requests\": [\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7,\n        7\n      ],\n      \"hibernated_waked\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"mem_actual_free\": [\n        7004864512,\n        6998364160,\n        7056683008,\n        7055605760,\n        7059243008,\n        7078457344,\n        7079067648,\n        7079514112,\n        7078977536,\n        7088099328,\n        7091081216,\n        7091773440,\n        7091589120,\n        7080108032,\n        7073554432,\n        7073914880,\n        7080144896,\n        7065124864,\n        7063183360,\n        7072677888,\n        7073767424,\n        7073542144,\n        7073542144,\n        7074902016,\n        7053836288,\n        7050895360,\n        7055720448,\n        7056822272,\n        7057281024,\n        7053025280,\n        7052763136,\n        7051984896,\n        7049113600,\n        7040618496,\n        7045636096,\n        7050907648,\n        7021027328,\n        7001329664,\n        6985895936,\n        6985895936,\n        6955642880,\n        7059750912,\n        7058616320,\n        7050067968,\n        7047163904,\n        7045873664,\n        7050272768,\n        7068528640,\n        7073677312,\n        7079116800,\n        7078252544,\n        7075880960,\n        7065079808,\n        7066251264,\n        7065726976,\n        7063486464,\n        7064797184,\n        7066206208,\n        7068819456,\n        7071809536\n      ],\n      \"mem_actual_used\": [\n        10175004672,\n        10181505024,\n        10123186176,\n        10124263424,\n        10120626176,\n        10101411840,\n        10100801536,\n        10100355072,\n        10100891648,\n        10091769856,\n        10088787968,\n        10088095744,\n        10088280064,\n        10099761152,\n        10106314752,\n        10105954304,\n        10099724288,\n        10114744320,\n        10116685824,\n        10107191296,\n        10106101760,\n        10106327040,\n        10106327040,\n        10104967168,\n        10126032896,\n        10128973824,\n        10124148736,\n        10123046912,\n        10122588160,\n        10126843904,\n        10127106048,\n        10127884288,\n        10130755584,\n        10139250688,\n        10134233088,\n        10128961536,\n        10158841856,\n        10178539520,\n        10193973248,\n        10193973248,\n        10224226304,\n        10120118272,\n        10121252864,\n        10129801216,\n        10132705280,\n        10133995520,\n        10129596416,\n        10111340544,\n        10106191872,\n        10100752384,\n        10101616640,\n        10103988224,\n        10114789376,\n        10113617920,\n        10114142208,\n        10116382720,\n        10115072000,\n        10113662976,\n        10111049728,\n        10108059648\n      ],\n      \"mem_free\": [\n        7004864512,\n        6998364160,\n        7056683008,\n        7055605760,\n        7059243008,\n        7078457344,\n        7079067648,\n        7079514112,\n        7078977536,\n        7088099328,\n        7091081216,\n        7091773440,\n        7091589120,\n        7080108032,\n        7073554432,\n        7073914880,\n        7080144896,\n        7065124864,\n        7063183360,\n        7072677888,\n        7073767424,\n        7073542144,\n        7073542144,\n        7074902016,\n        7053836288,\n        7050895360,\n        7055720448,\n        7056822272,\n        7057281024,\n        7053025280,\n        7052763136,\n        7051984896,\n        7049113600,\n        7040618496,\n        7045636096,\n        7050907648,\n        7021027328,\n        7001329664,\n        6985895936,\n        6985895936,\n        6955642880,\n        7059750912,\n        7058616320,\n        7050067968,\n        7047163904,\n        7045873664,\n        7050272768,\n        7068528640,\n        7073677312,\n        7079116800,\n        7078252544,\n        7075880960,\n        7065079808,\n        7066251264,\n        7065726976,\n        7063486464,\n        7064797184,\n        7066206208,\n        7068819456,\n        7071809536\n      ],\n      \"mem_limit\": [\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184\n      ],\n      \"mem_total\": [\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184,\n        17179869184\n      ],\n      \"mem_used_sys\": [\n        16694517760,\n        16707862528,\n        16608030720,\n        16610041856,\n        16604663808,\n        16553811968,\n        16553463808,\n        16553369600,\n        16553861120,\n        16539238400,\n        16536092672,\n        16535760896,\n        16535707648,\n        16553418752,\n        16559439872,\n        16558895104,\n        16554569728,\n        16580468736,\n        16582680576,\n        16565084160,\n        16564649984,\n        16565272576,\n        16565272576,\n        16562823168,\n        16599863296,\n        16602157056,\n        16597528576,\n        16596774912,\n        16595107840,\n        16593002496,\n        16593485824,\n        16596668416,\n        16598691840,\n        16607469568,\n        16599904256,\n        16590753792,\n        16644947968,\n        16684613632,\n        16714768384,\n        16714768384,\n        16781234176,\n        16573353984,\n        16575979520,\n        16593072128,\n        16603037696,\n        16605077504,\n        16599199744,\n        16581554176,\n        16570187776,\n        16560140288,\n        16561221632,\n        16565153792,\n        16577990656,\n        16577200128,\n        16578031616,\n        16582909952,\n        16569671680,\n        16565702656,\n        16560218112,\n        16554315776\n      ],\n      \"odp_report_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"rest_requests\": [\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        8,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        3,\n        2,\n        2,\n        1,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        3,\n        2,\n        2,\n        2,\n        2,\n        2\n      ],\n      \"swap_total\": [\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824,\n        1073741824\n      ],\n      \"swap_used\": [\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392,\n        122683392\n      ]\n    },\n    \"samplesCount\": 60,\n    \"isPersistent\": true,\n    \"lastTStamp\": 1615918178442,\n    \"interval\": 1000\n  },\n  \"hot_keys\": [\n    {\n      \"name\": \"first-duck\",\n      \"ops\": 6.003482019571351e-05\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/bucket_stats_response_with_missing.json",
    "content": "{\n  \"op\": {\n    \"samples\": {\n      \"couch_total_disk_size\": [\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341,\n        559341\n      ]\n    },\n    \"samplesCount\": 60,\n    \"isPersistent\": true,\n    \"lastTStamp\": 1615918178442,\n    \"interval\": 1000\n  },\n  \"hot_keys\": [\n    {\n      \"name\": \"first-duck\",\n      \"ops\": 6.003482019571351e-05\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/node_bucket_stats_response.json",
    "content": "{\n  \"hostname\": \"172.94.77.2:8091\",\n  \"hot_keys\": [\n    {\n      \"name\": \"anheuser_busch-michelob_ultra_amber\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"brouwerij_de_gouden_boom-blanche_de_bruges\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"cigar_city_brewing\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"eel_river_brewing-climax_california_classic\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"kaiserdom_privatbrauerei_bamberg\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"jack_s_brewing-grid_iron_amber_ale\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"niagara_falls_brewing-maple_wheat\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"rahr_sons_brewing_company-blind_salamander_pale_ale\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"middle_ages_brewing-tripel_crown\",\n      \"ops\": 0.0001942501942501943\n    },\n    {\n      \"name\": \"gordon_biersch_brewing-maibock\",\n      \"ops\": 0.0001942501942501943\n    }\n  ],\n  \"op\": {\n    \"samples\": {\n      \"couch_total_disk_size\": [\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202,\n        20822202\n      ],\n      \"couch_docs_fragmentation\": [\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83,\n        83\n      ],\n      \"couch_views_fragmentation\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"hit_ratio\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_cache_miss_rate\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_resident_items_rate\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_avg_active_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_replica_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_pending_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_avg_total_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_replica_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"vb_pending_resident_items_ratio\": [\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100,\n        100\n      ],\n      \"avg_disk_update_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_disk_commit_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_bg_wait_time\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_active_timestamp_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"avg_replica_timestamp_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bg_wait_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bg_wait_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"bytes_read\": [\n        151.3,\n        151.3,\n        151.3,\n        151.3,\n        151.3,\n        151.3,\n        151.3,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        147.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        151.6,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        138.9,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        154.8,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        139.2,\n        154.1,\n        154.1,\n        154.1\n      ],\n      \"bytes_written\": [\n        36915.2,\n        36915.2,\n        36915.2,\n        36915.2,\n        36915.2,\n        36915.2,\n        36915.2,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        38742.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        37827.3,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        36561.2,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        38749.5,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37473.3,\n        37259.6,\n        37259.6,\n        37259.6\n      ],\n      \"cas_badval\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cas_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cas_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_get\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_lookup\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cmd_set\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_docs_actual_disk_size\": [\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061,\n        20549061\n      ],\n      \"couch_docs_data_size\": [\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072,\n        2541072\n      ],\n      \"couch_docs_disk_size\": [\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780,\n        14747780\n      ],\n      \"couch_spatial_data_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_spatial_disk_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_spatial_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"couch_views_actual_disk_size\": [\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141\n      ],\n      \"couch_views_data_size\": [\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141\n      ],\n      \"couch_views_disk_size\": [\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141\n      ],\n      \"couch_views_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"curr_connections\": [\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67,\n        67\n      ],\n      \"curr_items\": [\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475,\n        2475\n      ],\n      \"curr_items_tot\": [\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897,\n        4897\n      ],\n      \"decr_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"decr_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"delete_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"delete_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_commit_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_commit_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_update_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_update_total\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"disk_write_queue\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_ahead_exceptions\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_hlc_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_active_hlc_drift_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_bg_fetched\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_clock_cas_drift_threshold_exceeded\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_data_read_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_data_write_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_count\": [\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5\n      ],\n      \"ep_dcp_2i_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_2i_producer_count\": [\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5,\n        5\n      ],\n      \"ep_dcp_2i_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_count\": [\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4,\n        4\n      ],\n      \"ep_dcp_replica_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_replica_producer_count\": [\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2,\n        2\n      ],\n      \"ep_dcp_replica_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_backoff\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_count\": [\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1\n      ],\n      \"ep_dcp_views_items_remaining\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_items_sent\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_dcp_views_producer_count\": [\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1,\n        1\n      ],\n      \"ep_dcp_views_total_bytes\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_diskqueue_items\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_flusher_todo\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_item_commit_failed\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_kv_size\": [\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370,\n        2665370\n      ],\n      \"ep_max_size\": [\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200,\n        209715200\n      ],\n      \"ep_mem_high_wat\": [\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920,\n        178257920\n      ],\n      \"ep_mem_low_wat\": [\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400,\n        157286400\n      ],\n      \"ep_meta_data_memory\": [\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082,\n        457082\n      ],\n      \"ep_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_del_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_del_ret_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_get_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_set_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_ops_set_ret_meta\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_num_value_ejects\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_oom_errors\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_overhead\": [\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424,\n        3650424\n      ],\n      \"ep_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_ahead_exceptions\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_hlc_drift\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_replica_hlc_drift_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_tmp_oom_errors\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ep_vb_total\": [\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684,\n        684\n      ],\n      \"get_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"get_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"incr_hits\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"incr_misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"mem_used\": [\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010296,\n        25010456,\n        25010456,\n        25010456\n      ],\n      \"misses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"timestamp\": [\n        1630694373240,\n        1630694374241,\n        1630694375242,\n        1630694376243,\n        1630694377244,\n        1630694378245,\n        1630694379246,\n        1630694380247,\n        1630694381248,\n        1630694382249,\n        1630694383250,\n        1630694384251,\n        1630694385252,\n        1630694386253,\n        1630694387254,\n        1630694388255,\n        1630694389256,\n        1630694390257,\n        1630694391258,\n        1630694392259,\n        1630694393260,\n        1630694394261,\n        1630694395262,\n        1630694396263,\n        1630694397264,\n        1630694398265,\n        1630694399266,\n        1630694400267,\n        1630694401268,\n        1630694402269,\n        1630694403270,\n        1630694404271,\n        1630694405272,\n        1630694406273,\n        1630694407274,\n        1630694408275,\n        1630694409276,\n        1630694410277,\n        1630694411278,\n        1630694412279,\n        1630694413280,\n        1630694414281,\n        1630694415282,\n        1630694416283,\n        1630694417284,\n        1630694418285,\n        1630694419286,\n        1630694420287,\n        1630694421288,\n        1630694422289,\n        1630694423290,\n        1630694424291,\n        1630694425292,\n        1630694426293,\n        1630694427294,\n        1630694428295,\n        1630694429296,\n        1630694430297,\n        1630694431298,\n        1630694432299\n      ],\n      \"vb_active_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_itm_memory\": [\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356,\n        1082356\n      ],\n      \"vb_active_meta_data_memory\": [\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761,\n        231761\n      ],\n      \"vb_active_num\": [\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342\n      ],\n      \"vb_active_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_aborted_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_accepted_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_active_sync_write_committed_count\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_curr_items\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_itm_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_meta_data_memory\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_num\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_pending_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_curr_items\": [\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422,\n        2422\n      ],\n      \"vb_replica_eject\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_itm_memory\": [\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366,\n        1067366\n      ],\n      \"vb_replica_meta_data_memory\": [\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321,\n        225321\n      ],\n      \"vb_replica_num\": [\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342,\n        342\n      ],\n      \"vb_replica_num_non_resident\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_ops_create\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_ops_update\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_drain\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_fill\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_replica_queue_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"vb_total_queue_age\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"xdc_ops\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"spatial/d41d8cd98f00b204e9800998ecf8427e/accesses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"spatial/d41d8cd98f00b204e9800998ecf8427e/data_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"spatial/d41d8cd98f00b204e9800998ecf8427e/disk_size\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"views/5a222b8c920aa5e3a28b51ee7eb609a0/accesses\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"views/5a222b8c920aa5e3a28b51ee7eb609a0/data_size\": [\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141\n      ],\n      \"views/5a222b8c920aa5e3a28b51ee7eb609a0/disk_size\": [\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141,\n        273141\n      ],\n      \"allocstall\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cpu_cores_available\": [\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8,\n        8\n      ],\n      \"cpu_irq_rate\": [\n        0.2062139125653011,\n        0.2062139125653011,\n        0.2062139125653011,\n        0.2062139125653011,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.2873150409423934,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1979078314956177,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1676445934618609,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1733853489380147,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1717721156598912,\n        0.1727115716753022,\n        0.1727115716753022,\n        0.1727115716753022,\n        0.1727115716753022,\n        0.1727115716753022,\n        0.1727115716753022\n      ],\n      \"cpu_stolen_rate\": [\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"cpu_sys_rate\": [\n        3.8355787737146,\n        3.8355787737146,\n        3.8355787737146,\n        3.8355787737146,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        5.15730498491596,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.368108566581849,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        4.121262922604079,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        3.395463083369455,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        5.969081019181219,\n        4.404145077720207,\n        4.404145077720207,\n        4.404145077720207,\n        4.404145077720207,\n        4.404145077720207,\n        4.404145077720207\n      ],\n      \"cpu_user_rate\": [\n        15.38355787737146,\n        15.38355787737146,\n        15.38355787737146,\n        15.38355787737146,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.48312024134463,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        17.14729997172745,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        20.82984073763621,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        11.40008669267447,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        20.82736902376181,\n        15.01151410477835,\n        15.01151410477835,\n        15.01151410477835,\n        15.01151410477835,\n        15.01151410477835,\n        15.01151410477835\n      ],\n      \"cpu_utilization_rate\": [\n        19.42535056365136,\n        19.42535056365136,\n        19.42535056365136,\n        19.42535056365136,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        22.92774026720299,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        21.71331636980492,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        25.11874825370215,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        14.96893512498194,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        26.96822215860292,\n        19.58837075417386,\n        19.58837075417386,\n        19.58837075417386,\n        19.58837075417386,\n        19.58837075417386,\n        19.58837075417386\n      ],\n      \"mem_actual_free\": [\n        4297187328,\n        4297187328,\n        4297187328,\n        4297187328,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408\n      ],\n      \"mem_actual_used\": [\n        12190720000,\n        12190720000,\n        12190720000,\n        12190720000,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12184035328,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12195545088,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12217913344,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12177022976,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12234674176,\n        12208209920,\n        12208209920,\n        12208209920,\n        12208209920,\n        12208209920,\n        12208209920\n      ],\n      \"mem_free\": [\n        4297187328,\n        4297187328,\n        4297187328,\n        4297187328,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4303872000,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4292362240,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4269993984,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4310884352,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4253233152,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408,\n        4279697408\n      ],\n      \"mem_limit\": [\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328\n      ],\n      \"mem_total\": [\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328,\n        16487907328\n      ],\n      \"mem_used_sys\": [\n        16111206400,\n        16111206400,\n        16111206400,\n        16111206400,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16107708416,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16139010048,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16140214272,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16101511168,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16175067136,\n        16130224128,\n        16130224128,\n        16130224128,\n        16130224128,\n        16130224128,\n        16130224128\n      ],\n      \"swap_total\": [\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552,\n        2147479552\n      ],\n      \"swap_used\": [\n        2146836480,\n        2146836480,\n        2146836480,\n        2146836480,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146832384,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146824192,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146799616,\n        2146791424,\n        2146791424,\n        2146791424,\n        2146791424,\n        2146791424,\n        2146791424\n      ]\n    },\n    \"samplesCount\": 60,\n    \"isPersistent\": true,\n    \"lastTStamp\": 1630694432299,\n    \"interval\": 1000\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/pools_default_response.json",
    "content": "{\n  \"storageTotals\": {\n    \"ram\": {\n      \"total\": 450972598272,\n      \"quotaTotal\": 360777252864,\n      \"quotaUsed\": 360777252864,\n      \"used\": 446826622976,\n      \"usedByData\": 255061495696,\n      \"quotaUsedPerNode\": 51539607552,\n      \"quotaTotalPerNode\": 51539607552\n    },\n    \"hdd\": {\n      \"total\": 1108766539776,\n      \"quotaTotal\": 1108766539776,\n      \"used\": 559135126484,\n      \"usedByData\": 515767865143,\n      \"free\": 498944942902\n    }\n  },\n  \"serverGroupsUri\": \"/pools/default/serverGroups\",\n  \"name\": \"default\",\n  \"alerts\": [\n    \"Metadata overhead warning. Over  63% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.8.148\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  65% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.10.65\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  64% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.13.173\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  65% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.15.75\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  65% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.13.105\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  64% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.8.127\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  63% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.15.120\\\" is taken up by keys and metadata.\",\n    \"Metadata overhead warning. Over  66% of RAM allocated to bucket  \\\"blastro-df\\\" on node \\\"172.16.10.187\\\" is taken up by keys and metadata.\"\n  ],\n  \"alertsSilenceURL\": \"/controller/resetAlerts\",\n  \"nodes\": [\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 35.43307086614173,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23181365248\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 17.98201798201798,\n        \"couch_docs_actual_disk_size\": 68506048063,\n        \"couch_docs_data_size\": 38718796110,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 140158886,\n        \"curr_items_tot\": 279374646,\n        \"ep_bg_fetched\": 0.999000999000999,\n        \"get_hits\": 10.98901098901099,\n        \"mem_used\": 36497390640,\n        \"ops\": 829.1708291708292,\n        \"vb_replica_curr_items\": 139215760\n      },\n      \"uptime\": \"341236\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23181365248,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.10.187:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.10.187\",\n      \"thisNode\": true,\n      \"hostname\": \"172.16.10.187:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 47.38255033557047,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23665811456\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 172.8271728271728,\n        \"couch_docs_actual_disk_size\": 79360565405,\n        \"couch_docs_data_size\": 38736382876,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 140174377,\n        \"curr_items_tot\": 279383025,\n        \"ep_bg_fetched\": 0.999000999000999,\n        \"get_hits\": 167.8321678321678,\n        \"mem_used\": 36650059656,\n        \"ops\": 1685.314685314685,\n        \"vb_replica_curr_items\": 139208648\n      },\n      \"uptime\": \"341210\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23665811456,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.10.65:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.10.65\",\n      \"hostname\": \"172.16.10.65:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 25.5586592178771,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23726600192\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 63.06306306306306,\n        \"couch_docs_actual_disk_size\": 79345105217,\n        \"couch_docs_data_size\": 38728086130,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 139195268,\n        \"curr_items_tot\": 279349113,\n        \"ep_bg_fetched\": 0,\n        \"get_hits\": 53.05305305305306,\n        \"mem_used\": 36476665576,\n        \"ops\": 1878.878878878879,\n        \"vb_replica_curr_items\": 140153845\n      },\n      \"uptime\": \"341210\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23726600192,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.13.105:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.13.105\",\n      \"hostname\": \"172.16.13.105:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 26.45803698435277,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23854841856\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 51.05105105105105,\n        \"couch_docs_actual_disk_size\": 74465931949,\n        \"couch_docs_data_size\": 38723830730,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 139209869,\n        \"curr_items_tot\": 279380019,\n        \"ep_bg_fetched\": 0,\n        \"get_hits\": 47.04704704704704,\n        \"mem_used\": 36471784896,\n        \"ops\": 1831.831831831832,\n        \"vb_replica_curr_items\": 140170150\n      },\n      \"uptime\": \"340526\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23854841856,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.13.173:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.13.173\",\n      \"hostname\": \"172.16.13.173:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 47.31034482758621,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23773573120\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 77.07707707707708,\n        \"couch_docs_actual_disk_size\": 74743093945,\n        \"couch_docs_data_size\": 38594660087,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 139215932,\n        \"curr_items_tot\": 278427644,\n        \"ep_bg_fetched\": 0,\n        \"get_hits\": 53.05305305305305,\n        \"mem_used\": 36306500344,\n        \"ops\": 1981.981981981982,\n        \"vb_replica_curr_items\": 139211712\n      },\n      \"uptime\": \"340495\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23773573120,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.15.120:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.15.120\",\n      \"hostname\": \"172.16.15.120:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 17.60660247592847,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 23662190592\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 146.8531468531468,\n        \"couch_docs_actual_disk_size\": 72932847344,\n        \"couch_docs_data_size\": 38581771457,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 139226879,\n        \"curr_items_tot\": 278436540,\n        \"ep_bg_fetched\": 0,\n        \"get_hits\": 144.8551448551448,\n        \"mem_used\": 36421860496,\n        \"ops\": 1495.504495504495,\n        \"vb_replica_curr_items\": 139209661\n      },\n      \"uptime\": \"337174\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 23662190592,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.8.127:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.8.127\",\n      \"hostname\": \"172.16.8.127:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    },\n    {\n      \"systemStats\": {\n        \"cpu_utilization_rate\": 21.68831168831169,\n        \"swap_total\": 0,\n        \"swap_used\": 0,\n        \"mem_total\": 64424656896,\n        \"mem_free\": 24049729536\n      },\n      \"interestingStats\": {\n        \"cmd_get\": 11.98801198801199,\n        \"couch_docs_actual_disk_size\": 66414273220,\n        \"couch_docs_data_size\": 38587642702,\n        \"couch_views_actual_disk_size\": 0,\n        \"couch_views_data_size\": 0,\n        \"curr_items\": 139193759,\n        \"curr_items_tot\": 278398926,\n        \"ep_bg_fetched\": 0,\n        \"get_hits\": 9.990009990009991,\n        \"mem_used\": 36237234088,\n        \"ops\": 883.1168831168832,\n        \"vb_replica_curr_items\": 139205167\n      },\n      \"uptime\": \"341228\",\n      \"memoryTotal\": 64424656896,\n      \"memoryFree\": 24049729536,\n      \"mcdMemoryReserved\": 49152,\n      \"mcdMemoryAllocated\": 49152,\n      \"couchApiBase\": \"http://172.16.8.148:8092/\",\n      \"clusterMembership\": \"active\",\n      \"recoveryType\": \"none\",\n      \"status\": \"healthy\",\n      \"otpNode\": \"ns_1@172.16.8.148\",\n      \"hostname\": \"172.16.8.148:8091\",\n      \"clusterCompatibility\": 196608,\n      \"version\": \"3.0.1-1444-rel-community\",\n      \"os\": \"x86_64-unknown-linux-gnu\",\n      \"ports\": {\n        \"proxy\": 11211,\n        \"direct\": 11210\n      }\n    }\n  ],\n  \"buckets\": {\n    \"uri\": \"/pools/default/buckets\",\n    \"terseBucketsBase\": \"/pools/default/b/\",\n    \"terseStreamingBucketsBase\": \"/pools/default/bs/\"\n  },\n  \"remoteClusters\": {\n    \"uri\": \"/pools/default/remoteClusters\",\n    \"validateURI\": \"/pools/default/remoteClusters?just_validate=1\"\n  },\n  \"controllers\": {\n    \"addNode\": {\n      \"uri\": \"/controller/addNode\"\n    },\n    \"rebalance\": {\n      \"uri\": \"/controller/rebalance\"\n    },\n    \"failOver\": {\n      \"uri\": \"/controller/failOver\"\n    },\n    \"startGracefulFailover\": {\n      \"uri\": \"/controller/startGracefulFailover\"\n    },\n    \"reAddNode\": {\n      \"uri\": \"/controller/reAddNode\"\n    },\n    \"reFailOver\": {\n      \"uri\": \"/controller/reFailOver\"\n    },\n    \"ejectNode\": {\n      \"uri\": \"/controller/ejectNode\"\n    },\n    \"setRecoveryType\": {\n      \"uri\": \"/controller/setRecoveryType\"\n    },\n    \"setAutoCompaction\": {\n      \"uri\": \"/controller/setAutoCompaction\",\n      \"validateURI\": \"/controller/setAutoCompaction?just_validate=1\"\n    },\n    \"clusterLogsCollection\": {\n      \"startURI\": \"/controller/startLogsCollection\",\n      \"cancelURI\": \"/controller/cancelLogsCollection\"\n    },\n    \"replication\": {\n      \"createURI\": \"/controller/createReplication\",\n      \"validateURI\": \"/controller/createReplication?just_validate=1\"\n    },\n    \"setFastWarmup\": {\n      \"uri\": \"/controller/setFastWarmup\",\n      \"validateURI\": \"/controller/setFastWarmup?just_validate=1\"\n    }\n  },\n  \"rebalanceStatus\": \"none\",\n  \"rebalanceProgressUri\": \"/pools/default/rebalanceProgress\",\n  \"stopRebalanceUri\": \"/controller/stopRebalance\",\n  \"nodeStatusesUri\": \"/nodeStatuses\",\n  \"maxBucketCount\": 10,\n  \"autoCompactionSettings\": {\n    \"parallelDBAndViewCompaction\": false,\n    \"databaseFragmentationThreshold\": {\n      \"percentage\": 50,\n      \"size\": \"undefined\"\n    },\n    \"viewFragmentationThreshold\": {\n      \"percentage\": 50,\n      \"size\": \"undefined\"\n    }\n  },\n  \"fastWarmupSettings\": {\n    \"fastWarmupEnabled\": true,\n    \"minMemoryThreshold\": 10,\n    \"minItemsThreshold\": 10\n  },\n  \"tasks\": {\n    \"uri\": \"/pools/default/tasks\"\n  },\n  \"visualSettingsUri\": \"/internalSettings/visual\",\n  \"counters\": {\n    \"rebalance_success\": 4,\n    \"rebalance_start\": 6,\n    \"rebalance_stop\": 2\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/pools_response.json",
    "content": "{\n  \"pools\": [\n    {\n      \"name\": \"default\",\n      \"uri\": \"/pools/default\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/couchbase/testdata/settings_autofailover.json",
    "content": "{\n    \"enabled\": true,\n    \"timeout\": 72,\n    \"count\": 1,\n    \"failoverOnDataDiskIssues\": {\n      \"enabled\": true,\n      \"timePeriod\": 89\n    },\n    \"maxCount\": 2,\n    \"canAbortRebalance\": true\n}\n"
  },
  {
    "path": "plugins/inputs/couchdb/README.md",
    "content": "# Apache CouchDB Input Plugin\n\nThis plugin gathers metrics from [Apache CouchDB][couchdb] instances using the\n[stats][stats] endpoint.\n\n⭐ Telegraf v0.10.3\n🏷️ server\n💻 all\n\n[couchdb]: https://couchdb.apache.org/\n[stats]: http://docs.couchdb.org/en/1.6.1/api/server/common.html?highlight=stats#get--_stats\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read CouchDB Stats from one or more servers\n[[inputs.couchdb]]\n  ## Works with CouchDB stats endpoints out of the box\n  ## Multiple Hosts from which to read CouchDB stats:\n  hosts = [\"http://localhost:8086/_stats\"]\n\n  ## Use HTTP Basic Authentication.\n  # basic_username = \"telegraf\"\n  # basic_password = \"p@ssw0rd\"\n```\n\n## Metrics\n\nStatistics specific to the internals of CouchDB:\n\n- couchdb_auth_cache_misses\n- couchdb_database_writes\n- couchdb_open_databases\n- couchdb_auth_cache_hits\n- couchdb_request_time\n- couchdb_database_reads\n- couchdb_open_os_files\n\nStatistics of HTTP requests by method:\n\n- httpd_request_methods_put\n- httpd_request_methods_get\n- httpd_request_methods_copy\n- httpd_request_methods_delete\n- httpd_request_methods_post\n- httpd_request_methods_head\n\nStatistics of HTTP requests by response code:\n\n- httpd_status_codes_200\n- httpd_status_codes_201\n- httpd_status_codes_202\n- httpd_status_codes_301\n- httpd_status_codes_304\n- httpd_status_codes_400\n- httpd_status_codes_401\n- httpd_status_codes_403\n- httpd_status_codes_404\n- httpd_status_codes_405\n- httpd_status_codes_409\n- httpd_status_codes_412\n- httpd_status_codes_500\n\nhttpd statistics:\n\n- httpd_clients_requesting_changes\n- httpd_temporary_view_reads\n- httpd_requests\n- httpd_bulk_requests\n- httpd_view_reads\n\n## Tags\n\n- server (url of the couchdb _stats endpoint)\n\n## Example Output\n\n### Post Couchdb 2.0\n\n```text\ncouchdb,server=http://couchdb22:5984/_node/_local/_stats couchdb_auth_cache_hits_value=0,httpd_request_methods_delete_value=0,couchdb_auth_cache_misses_value=0,httpd_request_methods_get_value=42,httpd_status_codes_304_value=0,httpd_status_codes_400_value=0,httpd_request_methods_head_value=0,httpd_status_codes_201_value=0,couchdb_database_reads_value=0,httpd_request_methods_copy_value=0,couchdb_request_time_max=0,httpd_status_codes_200_value=42,httpd_status_codes_301_value=0,couchdb_open_os_files_value=2,httpd_request_methods_put_value=0,httpd_request_methods_post_value=0,httpd_status_codes_202_value=0,httpd_status_codes_403_value=0,httpd_status_codes_409_value=0,couchdb_database_writes_value=0,couchdb_request_time_min=0,httpd_status_codes_412_value=0,httpd_status_codes_500_value=0,httpd_status_codes_401_value=0,httpd_status_codes_404_value=0,httpd_status_codes_405_value=0,couchdb_open_databases_value=0 1536707179000000000\n```\n\n### Pre Couchdb 2.0\n\n```text\ncouchdb,server=http://couchdb16:5984/_stats couchdb_request_time_sum=96,httpd_status_codes_200_sum=37,httpd_status_codes_200_min=0,httpd_requests_mean=0.005,httpd_requests_min=0,couchdb_request_time_stddev=3.833,couchdb_request_time_min=1,httpd_request_methods_get_stddev=0.073,httpd_request_methods_get_min=0,httpd_status_codes_200_mean=0.005,httpd_status_codes_200_max=1,httpd_requests_sum=37,couchdb_request_time_current=96,httpd_request_methods_get_sum=37,httpd_request_methods_get_mean=0.005,httpd_request_methods_get_max=1,httpd_status_codes_200_stddev=0.073,couchdb_request_time_mean=2.595,couchdb_request_time_max=25,httpd_request_methods_get_current=37,httpd_status_codes_200_current=37,httpd_requests_current=37,httpd_requests_stddev=0.073,httpd_requests_max=1 1536707179000000000\n```\n"
  },
  {
    "path": "plugins/inputs/couchdb/couchdb.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage couchdb\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CouchDB struct {\n\tHosts         []string `toml:\"hosts\"`\n\tBasicUsername string   `toml:\"basic_username\"`\n\tBasicPassword string   `toml:\"basic_password\"`\n\n\tclient *http.Client\n}\n\ntype (\n\tmetaData struct {\n\t\tCurrent *float64 `json:\"current\"`\n\t\tSum     *float64 `json:\"sum\"`\n\t\tMean    *float64 `json:\"mean\"`\n\t\tStddev  *float64 `json:\"stddev\"`\n\t\tMin     *float64 `json:\"min\"`\n\t\tMax     *float64 `json:\"max\"`\n\t\tValue   *float64 `json:\"value\"`\n\t}\n\n\toldValue struct {\n\t\tValue metaData `json:\"value\"`\n\t\tmetaData\n\t}\n\n\tcouchdb struct {\n\t\tAuthCacheHits       metaData            `json:\"auth_cache_hits\"`\n\t\tAuthCacheMisses     metaData            `json:\"auth_cache_misses\"`\n\t\tDatabaseWrites      metaData            `json:\"database_writes\"`\n\t\tDatabaseReads       metaData            `json:\"database_reads\"`\n\t\tOpenDatabases       metaData            `json:\"open_databases\"`\n\t\tOpenOsFiles         metaData            `json:\"open_os_files\"`\n\t\tRequestTime         oldValue            `json:\"request_time\"`\n\t\tHttpdRequestMethods httpdRequestMethods `json:\"httpd_request_methods\"`\n\t\tHttpdStatusCodes    httpdStatusCodes    `json:\"httpd_status_codes\"`\n\t}\n\n\thttpdRequestMethods struct {\n\t\tPut    metaData `json:\"PUT\"`\n\t\tGet    metaData `json:\"GET\"`\n\t\tCopy   metaData `json:\"COPY\"`\n\t\tDelete metaData `json:\"DELETE\"`\n\t\tPost   metaData `json:\"POST\"`\n\t\tHead   metaData `json:\"HEAD\"`\n\t}\n\n\thttpdStatusCodes struct {\n\t\tStatus200 metaData `json:\"200\"`\n\t\tStatus201 metaData `json:\"201\"`\n\t\tStatus202 metaData `json:\"202\"`\n\t\tStatus301 metaData `json:\"301\"`\n\t\tStatus304 metaData `json:\"304\"`\n\t\tStatus400 metaData `json:\"400\"`\n\t\tStatus401 metaData `json:\"401\"`\n\t\tStatus403 metaData `json:\"403\"`\n\t\tStatus404 metaData `json:\"404\"`\n\t\tStatus405 metaData `json:\"405\"`\n\t\tStatus409 metaData `json:\"409\"`\n\t\tStatus412 metaData `json:\"412\"`\n\t\tStatus500 metaData `json:\"500\"`\n\t}\n\n\thttpd struct {\n\t\tBulkRequests             metaData `json:\"bulk_requests\"`\n\t\tRequests                 metaData `json:\"requests\"`\n\t\tTemporaryViewReads       metaData `json:\"temporary_view_reads\"`\n\t\tViewReads                metaData `json:\"view_reads\"`\n\t\tClientsRequestingChanges metaData `json:\"clients_requesting_changes\"`\n\t}\n\n\tstats struct {\n\t\tCouchdb             couchdb             `json:\"couchdb\"`\n\t\tHttpdRequestMethods httpdRequestMethods `json:\"httpd_request_methods\"`\n\t\tHttpdStatusCodes    httpdStatusCodes    `json:\"httpd_status_codes\"`\n\t\tHttpd               httpd               `json:\"httpd\"`\n\t}\n)\n\nfunc (*CouchDB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *CouchDB) Gather(accumulator telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, u := range c.Hosts {\n\t\twg.Add(1)\n\t\tgo func(host string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := c.fetchAndInsertData(accumulator, host); err != nil {\n\t\t\t\taccumulator.AddError(fmt.Errorf(\"[host=%s]: %w\", host, err))\n\t\t\t}\n\t\t}(u)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (c *CouchDB) fetchAndInsertData(accumulator telegraf.Accumulator, host string) error {\n\tif c.client == nil {\n\t\tc.client = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t\t},\n\t\t\tTimeout: 4 * time.Second,\n\t\t}\n\t}\n\n\treq, err := http.NewRequest(\"GET\", host, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif c.BasicUsername != \"\" || c.BasicPassword != \"\" {\n\t\treq.SetBasicAuth(c.BasicUsername, c.BasicPassword)\n\t}\n\n\tresponse, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\n\tif response.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"failed to get stats from couchdb: HTTP responded %d\", response.StatusCode)\n\t}\n\n\tstats := stats{}\n\tdecoder := json.NewDecoder(response.Body)\n\tif err := decoder.Decode(&stats); err != nil {\n\t\treturn fmt.Errorf(\"failed to decode stats from couchdb: HTTP body %q\", response.Body)\n\t}\n\n\t// for couchdb 2.0 API changes\n\trequestTime := metaData{\n\t\tCurrent: stats.Couchdb.RequestTime.Current,\n\t\tSum:     stats.Couchdb.RequestTime.Sum,\n\t\tMean:    stats.Couchdb.RequestTime.Mean,\n\t\tStddev:  stats.Couchdb.RequestTime.Stddev,\n\t\tMin:     stats.Couchdb.RequestTime.Min,\n\t\tMax:     stats.Couchdb.RequestTime.Max,\n\t}\n\n\thttpdRequestMethodsPut := stats.HttpdRequestMethods.Put\n\thttpdRequestMethodsGet := stats.HttpdRequestMethods.Get\n\thttpdRequestMethodsCopy := stats.HttpdRequestMethods.Copy\n\thttpdRequestMethodsDelete := stats.HttpdRequestMethods.Delete\n\thttpdRequestMethodsPost := stats.HttpdRequestMethods.Post\n\thttpdRequestMethodsHead := stats.HttpdRequestMethods.Head\n\n\thttpdStatusCodesStatus200 := stats.HttpdStatusCodes.Status200\n\thttpdStatusCodesStatus201 := stats.HttpdStatusCodes.Status201\n\thttpdStatusCodesStatus202 := stats.HttpdStatusCodes.Status202\n\thttpdStatusCodesStatus301 := stats.HttpdStatusCodes.Status301\n\thttpdStatusCodesStatus304 := stats.HttpdStatusCodes.Status304\n\thttpdStatusCodesStatus400 := stats.HttpdStatusCodes.Status400\n\thttpdStatusCodesStatus401 := stats.HttpdStatusCodes.Status401\n\thttpdStatusCodesStatus403 := stats.HttpdStatusCodes.Status403\n\thttpdStatusCodesStatus404 := stats.HttpdStatusCodes.Status404\n\thttpdStatusCodesStatus405 := stats.HttpdStatusCodes.Status405\n\thttpdStatusCodesStatus409 := stats.HttpdStatusCodes.Status409\n\thttpdStatusCodesStatus412 := stats.HttpdStatusCodes.Status412\n\thttpdStatusCodesStatus500 := stats.HttpdStatusCodes.Status500\n\t// check if couchdb2.0 is used\n\tif stats.Couchdb.HttpdRequestMethods.Get.Value != nil {\n\t\trequestTime = stats.Couchdb.RequestTime.Value\n\n\t\thttpdRequestMethodsPut = stats.Couchdb.HttpdRequestMethods.Put\n\t\thttpdRequestMethodsGet = stats.Couchdb.HttpdRequestMethods.Get\n\t\thttpdRequestMethodsCopy = stats.Couchdb.HttpdRequestMethods.Copy\n\t\thttpdRequestMethodsDelete = stats.Couchdb.HttpdRequestMethods.Delete\n\t\thttpdRequestMethodsPost = stats.Couchdb.HttpdRequestMethods.Post\n\t\thttpdRequestMethodsHead = stats.Couchdb.HttpdRequestMethods.Head\n\n\t\thttpdStatusCodesStatus200 = stats.Couchdb.HttpdStatusCodes.Status200\n\t\thttpdStatusCodesStatus201 = stats.Couchdb.HttpdStatusCodes.Status201\n\t\thttpdStatusCodesStatus202 = stats.Couchdb.HttpdStatusCodes.Status202\n\t\thttpdStatusCodesStatus301 = stats.Couchdb.HttpdStatusCodes.Status301\n\t\thttpdStatusCodesStatus304 = stats.Couchdb.HttpdStatusCodes.Status304\n\t\thttpdStatusCodesStatus400 = stats.Couchdb.HttpdStatusCodes.Status400\n\t\thttpdStatusCodesStatus401 = stats.Couchdb.HttpdStatusCodes.Status401\n\t\thttpdStatusCodesStatus403 = stats.Couchdb.HttpdStatusCodes.Status403\n\t\thttpdStatusCodesStatus404 = stats.Couchdb.HttpdStatusCodes.Status404\n\t\thttpdStatusCodesStatus405 = stats.Couchdb.HttpdStatusCodes.Status405\n\t\thttpdStatusCodesStatus409 = stats.Couchdb.HttpdStatusCodes.Status409\n\t\thttpdStatusCodesStatus412 = stats.Couchdb.HttpdStatusCodes.Status412\n\t\thttpdStatusCodesStatus500 = stats.Couchdb.HttpdStatusCodes.Status500\n\t}\n\n\tfields := make(map[string]interface{}, 31)\n\t// CouchDB meta stats:\n\tgenerateFields(fields, \"couchdb_auth_cache_misses\", stats.Couchdb.AuthCacheMisses)\n\tgenerateFields(fields, \"couchdb_database_writes\", stats.Couchdb.DatabaseWrites)\n\tgenerateFields(fields, \"couchdb_open_databases\", stats.Couchdb.OpenDatabases)\n\tgenerateFields(fields, \"couchdb_auth_cache_hits\", stats.Couchdb.AuthCacheHits)\n\tgenerateFields(fields, \"couchdb_request_time\", requestTime)\n\tgenerateFields(fields, \"couchdb_database_reads\", stats.Couchdb.DatabaseReads)\n\tgenerateFields(fields, \"couchdb_open_os_files\", stats.Couchdb.OpenOsFiles)\n\n\t// http request methods stats:\n\tgenerateFields(fields, \"httpd_request_methods_put\", httpdRequestMethodsPut)\n\tgenerateFields(fields, \"httpd_request_methods_get\", httpdRequestMethodsGet)\n\tgenerateFields(fields, \"httpd_request_methods_copy\", httpdRequestMethodsCopy)\n\tgenerateFields(fields, \"httpd_request_methods_delete\", httpdRequestMethodsDelete)\n\tgenerateFields(fields, \"httpd_request_methods_post\", httpdRequestMethodsPost)\n\tgenerateFields(fields, \"httpd_request_methods_head\", httpdRequestMethodsHead)\n\n\t// status code stats:\n\tgenerateFields(fields, \"httpd_status_codes_200\", httpdStatusCodesStatus200)\n\tgenerateFields(fields, \"httpd_status_codes_201\", httpdStatusCodesStatus201)\n\tgenerateFields(fields, \"httpd_status_codes_202\", httpdStatusCodesStatus202)\n\tgenerateFields(fields, \"httpd_status_codes_301\", httpdStatusCodesStatus301)\n\tgenerateFields(fields, \"httpd_status_codes_304\", httpdStatusCodesStatus304)\n\tgenerateFields(fields, \"httpd_status_codes_400\", httpdStatusCodesStatus400)\n\tgenerateFields(fields, \"httpd_status_codes_401\", httpdStatusCodesStatus401)\n\tgenerateFields(fields, \"httpd_status_codes_403\", httpdStatusCodesStatus403)\n\tgenerateFields(fields, \"httpd_status_codes_404\", httpdStatusCodesStatus404)\n\tgenerateFields(fields, \"httpd_status_codes_405\", httpdStatusCodesStatus405)\n\tgenerateFields(fields, \"httpd_status_codes_409\", httpdStatusCodesStatus409)\n\tgenerateFields(fields, \"httpd_status_codes_412\", httpdStatusCodesStatus412)\n\tgenerateFields(fields, \"httpd_status_codes_500\", httpdStatusCodesStatus500)\n\n\t// httpd stats:\n\tgenerateFields(fields, \"httpd_clients_requesting_changes\", stats.Httpd.ClientsRequestingChanges)\n\tgenerateFields(fields, \"httpd_temporary_view_reads\", stats.Httpd.TemporaryViewReads)\n\tgenerateFields(fields, \"httpd_requests\", stats.Httpd.Requests)\n\tgenerateFields(fields, \"httpd_bulk_requests\", stats.Httpd.BulkRequests)\n\tgenerateFields(fields, \"httpd_view_reads\", stats.Httpd.ViewReads)\n\n\ttags := map[string]string{\n\t\t\"server\": host,\n\t}\n\taccumulator.AddFields(\"couchdb\", fields, tags)\n\treturn nil\n}\n\nfunc generateFields(fields map[string]interface{}, prefix string, obj metaData) {\n\tif obj.Value != nil {\n\t\tfields[prefix+\"_value\"] = *obj.Value\n\t}\n\tif obj.Current != nil {\n\t\tfields[prefix+\"_current\"] = *obj.Current\n\t}\n\tif obj.Sum != nil {\n\t\tfields[prefix+\"_sum\"] = *obj.Sum\n\t}\n\tif obj.Mean != nil {\n\t\tfields[prefix+\"_mean\"] = *obj.Mean\n\t}\n\tif obj.Stddev != nil {\n\t\tfields[prefix+\"_stddev\"] = *obj.Stddev\n\t}\n\tif obj.Min != nil {\n\t\tfields[prefix+\"_min\"] = *obj.Min\n\t}\n\tif obj.Max != nil {\n\t\tfields[prefix+\"_max\"] = *obj.Max\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"couchdb\", func() telegraf.Input {\n\t\treturn &CouchDB{\n\t\t\tclient: &http.Client{\n\t\t\t\tTransport: &http.Transport{\n\t\t\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t\t\t},\n\t\t\t\tTimeout: 4 * time.Second,\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/couchdb/couchdb_test.go",
    "content": "package couchdb_test\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/couchdb\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestBasic(t *testing.T) {\n\tjs := `\n{\n    \"couchdb\": {\n        \"auth_cache_misses\": {\n            \"description\": \"number of authentication cache misses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"database_writes\": {\n            \"description\": \"number of times a database was changed\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"open_databases\": {\n            \"description\": \"number of open databases\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"auth_cache_hits\": {\n            \"description\": \"number of authentication cache hits\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"request_time\": {\n            \"description\": \"length of a request inside CouchDB without MochiWeb\",\n            \"current\": 18.0,\n            \"sum\": 18.0,\n            \"mean\": 18.0,\n            \"stddev\": null,\n            \"min\": 18.0,\n            \"max\": 18.0\n        },\n        \"database_reads\": {\n            \"description\": \"number of times a document was read from a database\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"open_os_files\": {\n            \"description\": \"number of file descriptors CouchDB has open\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        }\n    },\n    \"httpd_request_methods\": {\n        \"PUT\": {\n            \"description\": \"number of HTTP PUT requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"GET\": {\n            \"description\": \"number of HTTP GET requests\",\n            \"current\": 2.0,\n            \"sum\": 2.0,\n            \"mean\": 0.25,\n            \"stddev\": 0.70699999999999996181,\n            \"min\": 0,\n            \"max\": 2\n        },\n        \"COPY\": {\n            \"description\": \"number of HTTP COPY requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"DELETE\": {\n            \"description\": \"number of HTTP DELETE requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"POST\": {\n            \"description\": \"number of HTTP POST requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"HEAD\": {\n            \"description\": \"number of HTTP HEAD requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        }\n    },\n    \"httpd_status_codes\": {\n        \"403\": {\n            \"description\": \"number of HTTP 403 Forbidden responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"202\": {\n            \"description\": \"number of HTTP 202 Accepted responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"401\": {\n            \"description\": \"number of HTTP 401 Unauthorized responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"409\": {\n            \"description\": \"number of HTTP 409 Conflict responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"200\": {\n            \"description\": \"number of HTTP 200 OK responses\",\n            \"current\": 1.0,\n            \"sum\": 1.0,\n            \"mean\": 0.125,\n            \"stddev\": 0.35399999999999998135,\n            \"min\": 0,\n            \"max\": 1\n        },\n        \"405\": {\n            \"description\": \"number of HTTP 405 Method Not Allowed responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"400\": {\n            \"description\": \"number of HTTP 400 Bad Request responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"201\": {\n            \"description\": \"number of HTTP 201 Created responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"404\": {\n            \"description\": \"number of HTTP 404 Not Found responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"500\": {\n            \"description\": \"number of HTTP 500 Internal Server Error responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"412\": {\n            \"description\": \"number of HTTP 412 Precondition Failed responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"301\": {\n            \"description\": \"number of HTTP 301 Moved Permanently responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"304\": {\n            \"description\": \"number of HTTP 304 Not Modified responses\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        }\n    },\n    \"httpd\": {\n        \"clients_requesting_changes\": {\n            \"description\": \"number of clients for continuous _changes\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"temporary_view_reads\": {\n            \"description\": \"number of temporary view reads\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"requests\": {\n            \"description\": \"number of HTTP requests\",\n            \"current\": 2.0,\n            \"sum\": 2.0,\n            \"mean\": 0.25,\n            \"stddev\": 0.70699999999999996181,\n            \"min\": 0,\n            \"max\": 2\n        },\n        \"bulk_requests\": {\n            \"description\": \"number of bulk requests\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        },\n        \"view_reads\": {\n            \"description\": \"number of view reads\",\n            \"current\": null,\n            \"sum\": null,\n            \"mean\": null,\n            \"stddev\": null,\n            \"min\": null,\n            \"max\": null\n        }\n    }\n}\n\n`\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/_stats\" {\n\t\t\tif _, err := w.Write([]byte(js)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\tplugin := &couchdb.CouchDB{\n\t\tHosts: []string{fakeServer.URL + \"/_stats\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n}\n"
  },
  {
    "path": "plugins/inputs/couchdb/dev/telegraf.conf",
    "content": "[agent]\n  interval=\"1s\"\n  flush_interval=\"1s\"\n\n[[inputs.couchdb]]\n  hosts = [\"http://couchdb16:5984/_stats\", \"http://couchdb22:5984/_node/_local/_stats\"]\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/couchdb/sample.conf",
    "content": "# Read CouchDB Stats from one or more servers\n[[inputs.couchdb]]\n  ## Works with CouchDB stats endpoints out of the box\n  ## Multiple Hosts from which to read CouchDB stats:\n  hosts = [\"http://localhost:8086/_stats\"]\n\n  ## Use HTTP Basic Authentication.\n  # basic_username = \"telegraf\"\n  # basic_password = \"p@ssw0rd\"\n"
  },
  {
    "path": "plugins/inputs/cpu/README.md",
    "content": "# CPU Input Plugin\n\nThis plugin gathers metrics about the system's CPUs.\n\n⭐ Telegraf v0.1.5\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about cpu usage\n[[inputs.cpu]]\n  ## Whether to report per-cpu stats or not\n  percpu = true\n  ## Whether to report total system cpu stats or not\n  totalcpu = true\n  ## If true, collect raw CPU time metrics\n  collect_cpu_time = false\n  ## If true, compute and report the sum of all non-idle CPU states\n  ## NOTE: The resulting 'time_active' field INCLUDES 'iowait'!\n  report_active = false\n  ## If true and the info is available then add core_id and physical_id tags\n  core_tags = false\n```\n\n## Metrics\n\nOn Linux, consult `man proc` for details on the meanings of these values.\n\n- cpu\n  - tags:\n    - cpu (CPU ID or `cpu-total`)\n  - fields:\n    - time_user (float)\n    - time_system (float)\n    - time_idle (float)\n    - time_active (float)\n    - time_nice (float)\n    - time_iowait (float)\n    - time_irq (float)\n    - time_softirq (float)\n    - time_steal (float)\n    - time_guest (float)\n    - time_guest_nice (float)\n    - usage_user (float, percent)\n    - usage_system (float, percent)\n    - usage_idle (float, percent)\n    - usage_active (float)\n    - usage_nice (float, percent)\n    - usage_iowait (float, percent)\n    - usage_irq (float, percent)\n    - usage_softirq (float, percent)\n    - usage_steal (float, percent)\n    - usage_guest (float, percent)\n    - usage_guest_nice (float, percent)\n\n## Troubleshooting\n\nOn Linux systems the `/proc/stat` file is used to gather CPU times.\nPercentages are based on the last 2 samples.\nTags core_id and physical_id are read from `/proc/cpuinfo` on Linux systems\n\n## Example Output\n\n```text\ncpu,cpu=cpu0,host=loaner time_active=202224.15999999992,time_guest=30250.35,time_guest_nice=0,time_idle=1527035.04,time_iowait=1352,time_irq=0,time_nice=169.28,time_softirq=6281.4,time_steal=0,time_system=40097.14,time_user=154324.34 1568760922000000000\ncpu,cpu=cpu0,host=loaner usage_active=31.249999981810106,usage_guest=2.083333333080696,usage_guest_nice=0,usage_idle=68.7500000181899,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=0,usage_steal=0,usage_system=4.166666666161392,usage_user=25.000000002273737 1568760922000000000\ncpu,cpu=cpu1,host=loaner time_active=201890.02000000002,time_guest=30508.41,time_guest_nice=0,time_idle=264641.18,time_iowait=210.44,time_irq=0,time_nice=181.75,time_softirq=4537.88,time_steal=0,time_system=39480.7,time_user=157479.25 1568760922000000000\ncpu,cpu=cpu1,host=loaner usage_active=12.500000010610771,usage_guest=2.0833333328280585,usage_guest_nice=0,usage_idle=87.49999998938922,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=2.0833333332070145,usage_steal=0,usage_system=4.166666665656117,usage_user=4.166666666414029 1568760922000000000\ncpu,cpu=cpu2,host=loaner time_active=201382.78999999998,time_guest=30325.8,time_guest_nice=0,time_idle=264686.63,time_iowait=202.77,time_irq=0,time_nice=162.81,time_softirq=3378.34,time_steal=0,time_system=39270.59,time_user=158368.28 1568760922000000000\ncpu,cpu=cpu2,host=loaner usage_active=15.999999993480742,usage_guest=1.9999999999126885,usage_guest_nice=0,usage_idle=84.00000000651926,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=2.0000000002764864,usage_steal=0,usage_system=3.999999999825377,usage_user=7.999999998923158 1568760922000000000\ncpu,cpu=cpu3,host=loaner time_active=198953.51000000007,time_guest=30344.43,time_guest_nice=0,time_idle=265504.09,time_iowait=187.64,time_irq=0,time_nice=197.47,time_softirq=2301.47,time_steal=0,time_system=39313.73,time_user=156953.2 1568760922000000000\ncpu,cpu=cpu3,host=loaner usage_active=10.41666667424579,usage_guest=0,usage_guest_nice=0,usage_idle=89.58333332575421,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=0,usage_steal=0,usage_system=4.166666666666667,usage_user=6.249999998484175 1568760922000000000\ncpu,cpu=cpu-total,host=loaner time_active=804450.5299999998,time_guest=121429,time_guest_nice=0,time_idle=2321866.96,time_iowait=1952.86,time_irq=0,time_nice=711.32,time_softirq=16499.1,time_steal=0,time_system=158162.17,time_user=627125.08 1568760922000000000\ncpu,cpu=cpu-total,host=loaner usage_active=17.616580305880305,usage_guest=1.036269430422946,usage_guest_nice=0,usage_idle=82.3834196941197,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=1.0362694300459534,usage_steal=0,usage_system=4.145077721691784,usage_user=11.398963731636465 1568760922000000000\n```\n"
  },
  {
    "path": "plugins/inputs/cpu/cpu.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage cpu\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CPU struct {\n\tps         psutil.PS\n\tlastStats  map[string]cpu.TimesStat\n\tcpuInfo    map[string]cpu.InfoStat\n\tcoreID     bool\n\tphysicalID bool\n\n\tPerCPU         bool `toml:\"percpu\"`\n\tTotalCPU       bool `toml:\"totalcpu\"`\n\tCollectCPUTime bool `toml:\"collect_cpu_time\"`\n\tReportActive   bool `toml:\"report_active\"`\n\tCoreTags       bool `toml:\"core_tags\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*CPU) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *CPU) Init() error {\n\tif c.CoreTags {\n\t\tcpuInfo, err := cpu.Info()\n\t\tif err == nil {\n\t\t\tc.coreID = cpuInfo[0].CoreID != \"\"\n\t\t\tc.physicalID = cpuInfo[0].PhysicalID != \"\"\n\n\t\t\tc.cpuInfo = make(map[string]cpu.InfoStat)\n\t\t\tfor _, ci := range cpuInfo {\n\t\t\t\tc.cpuInfo[fmt.Sprintf(\"cpu%d\", ci.CPU)] = ci\n\t\t\t}\n\t\t} else {\n\t\t\tc.Log.Warnf(\"Failed to gather info about CPUs: %s\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *CPU) Gather(acc telegraf.Accumulator) error {\n\ttimes, err := c.ps.CPUTimes(c.PerCPU, c.TotalCPU)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting CPU info: %w\", err)\n\t}\n\tnow := time.Now()\n\n\tfor _, cts := range times {\n\t\ttags := map[string]string{\n\t\t\t\"cpu\": cts.CPU,\n\t\t}\n\t\tif c.coreID {\n\t\t\ttags[\"core_id\"] = c.cpuInfo[cts.CPU].CoreID\n\t\t}\n\t\tif c.physicalID {\n\t\t\ttags[\"physical_id\"] = c.cpuInfo[cts.CPU].PhysicalID\n\t\t}\n\n\t\ttotal := totalCPUTime(cts)\n\t\tactive := activeCPUTime(cts)\n\n\t\tif c.CollectCPUTime {\n\t\t\t// Add cpu time metrics\n\t\t\tfieldsC := map[string]interface{}{\n\t\t\t\t\"time_user\":       cts.User,\n\t\t\t\t\"time_system\":     cts.System,\n\t\t\t\t\"time_idle\":       cts.Idle,\n\t\t\t\t\"time_nice\":       cts.Nice,\n\t\t\t\t\"time_iowait\":     cts.Iowait,\n\t\t\t\t\"time_irq\":        cts.Irq,\n\t\t\t\t\"time_softirq\":    cts.Softirq,\n\t\t\t\t\"time_steal\":      cts.Steal,\n\t\t\t\t\"time_guest\":      cts.Guest,\n\t\t\t\t\"time_guest_nice\": cts.GuestNice,\n\t\t\t}\n\t\t\tif c.ReportActive {\n\t\t\t\tfieldsC[\"time_active\"] = activeCPUTime(cts)\n\t\t\t}\n\t\t\tacc.AddCounter(\"cpu\", fieldsC, tags, now)\n\t\t}\n\n\t\t// Add in percentage\n\t\tif len(c.lastStats) == 0 {\n\t\t\t// If it's the 1st gather, can't get CPU Usage stats yet\n\t\t\tcontinue\n\t\t}\n\n\t\tlastCts, ok := c.lastStats[cts.CPU]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tlastTotal := totalCPUTime(lastCts)\n\t\tlastActive := activeCPUTime(lastCts)\n\t\ttotalDelta := total - lastTotal\n\n\t\tif totalDelta < 0 {\n\t\t\terr = errors.New(\"current total CPU time is less than previous total CPU time\")\n\t\t\tbreak\n\t\t}\n\n\t\tif totalDelta == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfieldsG := map[string]interface{}{\n\t\t\t\"usage_user\":       100 * (cts.User - lastCts.User - (cts.Guest - lastCts.Guest)) / totalDelta,\n\t\t\t\"usage_system\":     100 * (cts.System - lastCts.System) / totalDelta,\n\t\t\t\"usage_idle\":       100 * (cts.Idle - lastCts.Idle) / totalDelta,\n\t\t\t\"usage_nice\":       100 * (cts.Nice - lastCts.Nice - (cts.GuestNice - lastCts.GuestNice)) / totalDelta,\n\t\t\t\"usage_iowait\":     100 * (cts.Iowait - lastCts.Iowait) / totalDelta,\n\t\t\t\"usage_irq\":        100 * (cts.Irq - lastCts.Irq) / totalDelta,\n\t\t\t\"usage_softirq\":    100 * (cts.Softirq - lastCts.Softirq) / totalDelta,\n\t\t\t\"usage_steal\":      100 * (cts.Steal - lastCts.Steal) / totalDelta,\n\t\t\t\"usage_guest\":      100 * (cts.Guest - lastCts.Guest) / totalDelta,\n\t\t\t\"usage_guest_nice\": 100 * (cts.GuestNice - lastCts.GuestNice) / totalDelta,\n\t\t}\n\t\tif c.ReportActive {\n\t\t\tfieldsG[\"usage_active\"] = 100 * (active - lastActive) / totalDelta\n\t\t}\n\t\tacc.AddGauge(\"cpu\", fieldsG, tags, now)\n\t}\n\n\tc.lastStats = make(map[string]cpu.TimesStat)\n\tfor _, cts := range times {\n\t\tc.lastStats[cts.CPU] = cts\n\t}\n\n\treturn err\n}\n\nfunc totalCPUTime(t cpu.TimesStat) float64 {\n\ttotal := t.User + t.System + t.Nice + t.Iowait + t.Irq + t.Softirq + t.Steal + t.Idle\n\treturn total\n}\n\nfunc activeCPUTime(t cpu.TimesStat) float64 {\n\tactive := totalCPUTime(t) - t.Idle\n\treturn active\n}\n\nfunc init() {\n\tinputs.Add(\"cpu\", func() telegraf.Input {\n\t\treturn &CPU{\n\t\t\tPerCPU:   true,\n\t\t\tTotalCPU: true,\n\t\t\tps:       psutil.NewSystemPS(),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/cpu/cpu_test.go",
    "content": "package cpu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc newCPUStats(ps psutil.PS) *CPU {\n\treturn &CPU{\n\t\tps:             ps,\n\t\tCollectCPUTime: true,\n\t\tReportActive:   true,\n\t}\n}\n\nfunc TestCPUStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\n\tcts := cpu.TimesStat{\n\t\tCPU:       \"cpu0\",\n\t\tUser:      8.8,\n\t\tSystem:    8.2,\n\t\tIdle:      80.1,\n\t\tNice:      1.3,\n\t\tIowait:    0.8389,\n\t\tIrq:       0.6,\n\t\tSoftirq:   0.11,\n\t\tSteal:     0.0511,\n\t\tGuest:     3.1,\n\t\tGuestNice: 0.324,\n\t}\n\n\tcts2 := cpu.TimesStat{\n\t\tCPU:       \"cpu0\",\n\t\tUser:      24.9,     // increased by 16.1\n\t\tSystem:    10.9,     // increased by 2.7\n\t\tIdle:      157.9798, // increased by 77.8798 (for total increase of 100)\n\t\tNice:      3.5,      // increased by 2.2\n\t\tIowait:    0.929,    // increased by 0.0901\n\t\tIrq:       1.2,      // increased by 0.6\n\t\tSoftirq:   0.31,     // increased by 0.2\n\t\tSteal:     0.2812,   // increased by 0.2301\n\t\tGuest:     11.4,     // increased by 8.3\n\t\tGuestNice: 2.524,    // increased by 2.2\n\t}\n\n\tmps.On(\"CPUTimes\").Return([]cpu.TimesStat{cts}, nil)\n\n\tcs := newCPUStats(&mps)\n\n\terr := cs.Gather(&acc)\n\trequire.NoError(t, err)\n\n\t// Computed values are checked with delta > 0 because of floating point arithmetic\n\t// imprecision\n\tassertContainsTaggedFloat(t, &acc, \"time_user\", 8.8, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_system\", 8.2, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_idle\", 80.1, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_active\", 19.9, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"time_nice\", 1.3, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_iowait\", 0.8389, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_irq\", 0.6, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_softirq\", 0.11, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_steal\", 0.0511, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_guest\", 3.1, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_guest_nice\", 0.324, 0)\n\n\tmps2 := psutil.MockPS{}\n\tmps2.On(\"CPUTimes\").Return([]cpu.TimesStat{cts2}, nil)\n\tcs.ps = &mps2\n\n\t// Should have added cpu percentages too\n\terr = cs.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tassertContainsTaggedFloat(t, &acc, \"time_user\", 24.9, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_system\", 10.9, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_idle\", 157.9798, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_active\", 42.0202, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"time_nice\", 3.5, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_iowait\", 0.929, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_irq\", 1.2, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_softirq\", 0.31, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_steal\", 0.2812, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_guest\", 11.4, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_guest_nice\", 2.524, 0)\n\n\tassertContainsTaggedFloat(t, &acc, \"usage_user\", 7.8, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_system\", 2.7, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_idle\", 77.8798, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_active\", 22.1202, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_nice\", 0, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_iowait\", 0.0901, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_irq\", 0.6, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_softirq\", 0.2, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_steal\", 0.2301, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_guest\", 8.3, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_guest_nice\", 2.2, 0.0005)\n}\n\n// Asserts that a given accumulator contains a measurement of type float64 with\n// specific tags within a certain distance of a given expected value. Asserts a failure\n// if the measurement is of the wrong type, or if no matching measurements are found\n//\n// Parameters:\n//\n//\tt *testing.T            : Testing object to use\n//\tacc testutil.Accumulator: Accumulator to examine\n//\tfield string            : Name of field to examine\n//\texpectedValue float64   : Value to search for within the measurement\n//\tdelta float64           : Maximum acceptable distance of an accumulated value\n//\t                          from the expectedValue parameter. Useful when\n//\t                          floating-point arithmetic imprecision makes looking\n//\t                          for an exact match impractical\nfunc assertContainsTaggedFloat(\n\tt *testing.T,\n\tacc *testutil.Accumulator,\n\tfield string,\n\texpectedValue, delta float64,\n) {\n\tvar actualValue float64\n\tmeasurement := \"cpu\" // always cpu\n\tfor _, pt := range acc.Metrics {\n\t\tif pt.Measurement == measurement {\n\t\t\tfor fieldname, value := range pt.Fields {\n\t\t\t\tif fieldname == field {\n\t\t\t\t\tif value, ok := value.(float64); ok {\n\t\t\t\t\t\tactualValue = value\n\t\t\t\t\t\tif (value >= expectedValue-delta) && (value <= expectedValue+delta) {\n\t\t\t\t\t\t\t// Found the point, return without failing\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequire.Failf(t, \"Wrong type\", \"Measurement %q does not have type float64\", measurement)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\trequire.Failf(t, \"Measurement not found\",\n\t\t\"Could not find measurement %q with requested tags within %f of %f, Actual: %f\", measurement, delta, expectedValue, actualValue)\n}\n\n// TestCPUCountChange tests that no errors are encountered if the number of\n// CPUs increases as reported with LXC.\nfunc TestCPUCountIncrease(t *testing.T) {\n\tvar mps psutil.MockPS\n\tvar mps2 psutil.MockPS\n\tvar acc testutil.Accumulator\n\tvar err error\n\n\tcs := newCPUStats(&mps)\n\n\tmps.On(\"CPUTimes\").Return(\n\t\t[]cpu.TimesStat{\n\t\t\t{\n\t\t\t\tCPU: \"cpu0\",\n\t\t\t},\n\t\t}, nil)\n\n\terr = cs.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tmps2.On(\"CPUTimes\").Return(\n\t\t[]cpu.TimesStat{\n\t\t\t{\n\t\t\t\tCPU: \"cpu0\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tCPU: \"cpu1\",\n\t\t\t},\n\t\t}, nil)\n\tcs.ps = &mps2\n\n\terr = cs.Gather(&acc)\n\trequire.NoError(t, err)\n}\n\n// TestCPUTimesDecrease tests that telegraf continue to works after\n// CPU times decrease, which seems to occur when Linux system is suspended.\nfunc TestCPUTimesDecrease(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\n\tcts := cpu.TimesStat{\n\t\tCPU:    \"cpu0\",\n\t\tUser:   18,\n\t\tIdle:   80,\n\t\tIowait: 2,\n\t}\n\n\tcts2 := cpu.TimesStat{\n\t\tCPU:    \"cpu0\",\n\t\tUser:   38, // increased by 20\n\t\tIdle:   40, // decreased by 40\n\t\tIowait: 1,  // decreased by 1\n\t}\n\n\tcts3 := cpu.TimesStat{\n\t\tCPU:    \"cpu0\",\n\t\tUser:   56,  // increased by 18\n\t\tIdle:   120, // increased by 80\n\t\tIowait: 3,   // increased by 2\n\t}\n\n\tmps.On(\"CPUTimes\").Return([]cpu.TimesStat{cts}, nil)\n\n\tcs := newCPUStats(&mps)\n\n\terr := cs.Gather(&acc)\n\trequire.NoError(t, err)\n\n\t// Computed values are checked with delta > 0 because of floating point arithmetic\n\t// imprecision\n\tassertContainsTaggedFloat(t, &acc, \"time_user\", 18, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_idle\", 80, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_iowait\", 2, 0)\n\n\tmps2 := psutil.MockPS{}\n\tmps2.On(\"CPUTimes\").Return([]cpu.TimesStat{cts2}, nil)\n\tcs.ps = &mps2\n\n\t// CPU times decreased. An error should be raised\n\terr = cs.Gather(&acc)\n\trequire.Error(t, err)\n\n\tmps3 := psutil.MockPS{}\n\tmps3.On(\"CPUTimes\").Return([]cpu.TimesStat{cts3}, nil)\n\tcs.ps = &mps3\n\n\terr = cs.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tassertContainsTaggedFloat(t, &acc, \"time_user\", 56, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_idle\", 120, 0)\n\tassertContainsTaggedFloat(t, &acc, \"time_iowait\", 3, 0)\n\n\tassertContainsTaggedFloat(t, &acc, \"usage_user\", 18, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_idle\", 80, 0.0005)\n\tassertContainsTaggedFloat(t, &acc, \"usage_iowait\", 2, 0.0005)\n}\n"
  },
  {
    "path": "plugins/inputs/cpu/sample.conf",
    "content": "# Read metrics about cpu usage\n[[inputs.cpu]]\n  ## Whether to report per-cpu stats or not\n  percpu = true\n  ## Whether to report total system cpu stats or not\n  totalcpu = true\n  ## If true, collect raw CPU time metrics\n  collect_cpu_time = false\n  ## If true, compute and report the sum of all non-idle CPU states\n  ## NOTE: The resulting 'time_active' field INCLUDES 'iowait'!\n  report_active = false\n  ## If true and the info is available then add core_id and physical_id tags\n  core_tags = false\n"
  },
  {
    "path": "plugins/inputs/csgo/README.md",
    "content": "# Counter-Strike: Global Offensive (CSGO) Input Plugin\n\nThis plugin gather metrics from [Counter-Strike: Global Offensive][csgo]\nservers.\n\n⭐ Telegraf v1.18.0\n🏷️ server\n💻 all\n\n[csgo]: https://www.counter-strike.net/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Fetch metrics from a CSGO SRCDS\n[[inputs.csgo]]\n  ## Specify servers using the following format:\n  ##    servers = [\n  ##      [\"ip1:port1\", \"rcon_password1\"],\n  ##      [\"ip2:port2\", \"rcon_password2\"],\n  ##    ]\n  #\n  ## If no servers are specified, no data will be collected\n  servers = []\n```\n\n## Metrics\n\nThe plugin retrieves the output of the `stats` command that is executed via\nrcon.\n\nIf no servers are specified, no data will be collected\n\n- csgo\n  - tags:\n    - host\n  - fields:\n    - cpu (float)\n    - net_in (float)\n    - net_out (float)\n    - uptime_minutes (float)\n    - maps (float)\n    - fps (float)\n    - players (float)\n    - sv_ms (float)\n    - variance_ms (float)\n    - tick_ms (float)\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/csgo/csgo.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage csgo\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorcon/rcon\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CSGO struct {\n\tServers [][]string `toml:\"servers\"`\n}\n\nfunc (*CSGO) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *CSGO) Init() error {\n\tfor _, server := range s.Servers {\n\t\tif len(server) != 2 {\n\t\t\treturn errors.New(\"incorrect server config\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *CSGO) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Loop through each server and collect metrics\n\tfor _, server := range s.Servers {\n\t\twg.Add(1)\n\t\tgo func(addr, passwd string) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// Connect and send the request\n\t\t\tclient, err := rcon.Dial(addr, passwd)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer client.Close()\n\n\t\t\tt := time.Now()\n\t\t\tresponse, err := client.Execute(\"stats\")\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Generate the metric and add it to the accumulator\n\t\t\tm, err := parseResponse(addr, response, t)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tacc.AddMetric(m)\n\t\t}(server[0], server[1])\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc parseResponse(addr, response string, t time.Time) (telegraf.Metric, error) {\n\trows := strings.Split(response, \"\\n\")\n\tif len(rows) < 2 {\n\t\treturn nil, errors.New(\"bad response\")\n\t}\n\n\t// Parse the columns\n\tcolumns := strings.Fields(rows[1])\n\tif len(columns) != 10 {\n\t\treturn nil, errors.New(\"not enough columns\")\n\t}\n\n\tcpu, err := strconv.ParseFloat(columns[0], 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnetIn, err := strconv.ParseFloat(columns[1], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnetOut, err := strconv.ParseFloat(columns[2], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tuptimeMinutes, err := strconv.ParseFloat(columns[3], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmaps, err := strconv.ParseFloat(columns[4], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfps, err := strconv.ParseFloat(columns[5], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tplayers, err := strconv.ParseFloat(columns[6], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsvms, err := strconv.ParseFloat(columns[7], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmsVar, err := strconv.ParseFloat(columns[8], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttick, err := strconv.ParseFloat(columns[9], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Construct the metric\n\ttags := map[string]string{\"host\": addr}\n\tfields := map[string]interface{}{\n\t\t\"cpu\":            cpu,\n\t\t\"net_in\":         netIn,\n\t\t\"net_out\":        netOut,\n\t\t\"uptime_minutes\": uptimeMinutes,\n\t\t\"maps\":           maps,\n\t\t\"fps\":            fps,\n\t\t\"players\":        players,\n\t\t\"sv_ms\":          svms,\n\t\t\"variance_ms\":    msVar,\n\t\t\"tick_ms\":        tick,\n\t}\n\treturn metric.New(\"csgo\", tags, fields, t, telegraf.Gauge), nil\n}\n\nfunc init() {\n\tinputs.Add(\"csgo\", func() telegraf.Input {\n\t\treturn &CSGO{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/csgo/csgo_test.go",
    "content": "package csgo\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorcon/rcon\"\n\t\"github.com/gorcon/rcon/rcontest\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCPUStats(t *testing.T) {\n\t// Define the input\n\tconst input = `CPU   NetIn   NetOut    Uptime  Maps   FPS   Players  Svms    +-ms   ~tick\n10.0      1.2      3.4   100     1   120.20       15    5.23    0.01    0.02`\n\n\t// Start the mockup server\n\tserver := rcontest.NewUnstartedServer()\n\tserver.Settings.Password = \"password\"\n\tserver.SetAuthHandler(func(c *rcontest.Context) {\n\t\tif c.Request().Body() == c.Server().Settings.Password {\n\t\t\tpkg := rcon.NewPacket(rcon.SERVERDATA_AUTH_RESPONSE, c.Request().ID, \"\")\n\t\t\t_, err := pkg.WriteTo(c.Conn())\n\t\t\trequire.NoError(t, err)\n\t\t} else {\n\t\t\tpkg := rcon.NewPacket(rcon.SERVERDATA_AUTH_RESPONSE, -1, string([]byte{0x00}))\n\t\t\t_, err := pkg.WriteTo(c.Conn())\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n\tserver.SetCommandHandler(func(c *rcontest.Context) {\n\t\tpkg := rcon.NewPacket(rcon.SERVERDATA_RESPONSE_VALUE, c.Request().ID, input)\n\t\t_, err := pkg.WriteTo(c.Conn())\n\t\trequire.NoError(t, err)\n\t})\n\tserver.Start()\n\tdefer server.Close()\n\n\t// Setup the plugin\n\tplugin := &CSGO{\n\t\tServers: [][]string{\n\t\t\t{server.Addr(), \"password\"},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Define expected result\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"csgo\",\n\t\t\tmap[string]string{\n\t\t\t\t\"host\": server.Addr(),\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu\":            10.0,\n\t\t\t\t\"fps\":            120.2,\n\t\t\t\t\"maps\":           1.0,\n\t\t\t\t\"net_in\":         1.2,\n\t\t\t\t\"net_out\":        3.4,\n\t\t\t\t\"players\":        15.0,\n\t\t\t\t\"sv_ms\":          5.23,\n\t\t\t\t\"tick_ms\":        0.02,\n\t\t\t\t\"uptime_minutes\": 100.0,\n\t\t\t\t\"variance_ms\":    0.01,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\t// Gather data\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t// Test the result\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/csgo/sample.conf",
    "content": "# Fetch metrics from a CSGO SRCDS\n[[inputs.csgo]]\n  ## Specify servers using the following format:\n  ##    servers = [\n  ##      [\"ip1:port1\", \"rcon_password1\"],\n  ##      [\"ip2:port2\", \"rcon_password2\"],\n  ##    ]\n  #\n  ## If no servers are specified, no data will be collected\n  servers = []\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/README.md",
    "content": "# Bosch Rexroth ctrlX Data Layer Input Plugin\n\nThis plugin gathers data from the [ctrlX Data Layer][ctrlx] a communication\nmiddleware running on Bosch Rexroth's [ctrlX CORE devices][core_devs]. The\nplatform is used for professional automation applications like industrial\nautomation, building automation, robotics, IoT Gateways or as classical PLC.\n\n⭐ Telegraf v1.27.0\n🏷️ iot, messaging\n💻 all\n\n[ctrlx]: https://ctrlx-automation.com\n[core_devs]: https://ctrlx-core.com\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# A ctrlX Data Layer server sent event input plugin\n[[inputs.ctrlx_datalayer]]\n   ## Hostname or IP address of the ctrlX CORE Data Layer server\n   ##  example: server = \"localhost\"        # Telegraf is running directly on the device\n   ##           server = \"192.168.1.1\"      # Connect to ctrlX CORE remote via IP\n   ##           server = \"host.example.com\" # Connect to ctrlX CORE remote via hostname\n   ##           server = \"10.0.2.2:8443\"    # Connect to ctrlX CORE Virtual from development environment\n   server = \"localhost\"\n\n   ## Authentication credentials\n   username = \"boschrexroth\"\n   password = \"boschrexroth\"\n\n   ## Use TLS but skip chain & host verification\n   # insecure_skip_verify = false\n\n   ## Timeout for HTTP requests. (default: \"10s\")\n   # timeout = \"10s\"\n\n\n   ## Create a ctrlX Data Layer subscription.\n   ## It is possible to define multiple subscriptions per host. Each subscription can have its own\n   ## sampling properties and a list of nodes to subscribe to.\n   ## All subscriptions share the same credentials.\n   [[inputs.ctrlx_datalayer.subscription]]\n      ## The name of the measurement. (default: \"ctrlx\")\n      measurement = \"memory\"\n\n      ## Configure the ctrlX Data Layer nodes which should be subscribed.\n      ## address - node address in ctrlX Data Layer (mandatory)\n      ## name    - field name to use in the output (optional, default: base name of address)\n      ## tags    - extra node tags to be added to the output metric (optional)\n      ## Note: \n      ## Use either the inline notation or the bracketed notation, not both.\n      ## The tags property is only supported in bracketed notation due to toml parser restrictions\n      ## Examples:\n      ## Inline notation \n      nodes=[\n         {name=\"available\", address=\"framework/metrics/system/memavailable-mb\"},\n         {name=\"used\", address=\"framework/metrics/system/memused-mb\"},\n      ]\n      ## Bracketed notation\n      # [[inputs.ctrlx_datalayer.subscription.nodes]]\n      #    name   =\"available\"\n      #    address=\"framework/metrics/system/memavailable-mb\"\n      #    ## Define extra tags related to node to be added to the output metric (optional)\n      #    [inputs.ctrlx_datalayer.subscription.nodes.tags]\n      #       node_tag1=\"node_tag1\"\n      #       node_tag2=\"node_tag2\"\n      # [[inputs.ctrlx_datalayer.subscription.nodes]]\n      #    name   =\"used\"\n      #    address=\"framework/metrics/system/memused-mb\"\n\n      ## The switch \"output_json_string\" enables output of the measurement as json. \n      ## That way it can be used in in a subsequent processor plugin, e.g. \"Starlark Processor Plugin\".\n      # output_json_string = false\n\n      ## Define extra tags related to subscription to be added to the output metric (optional)\n      # [inputs.ctrlx_datalayer.subscription.tags]\n      #    subscription_tag1 = \"subscription_tag1\"\n      #    subscription_tag2 = \"subscription_tag2\"\n\n      ## The interval in which messages shall be sent by the ctrlX Data Layer to this plugin. (default: 1s)\n      ## Higher values reduce load on network by queuing samples on server side and sending as a single TCP packet.\n      # publish_interval = \"1s\"\n\n      ## The interval a \"keepalive\" message is sent if no change of data occurs. (default: 60s)\n      ## Only used internally to detect broken network connections.\n      # keep_alive_interval = \"60s\"\n\n      ## The interval an \"error\" message is sent if an error was received from a node. (default: 10s)\n      ## Higher values reduce load on output target and network in case of errors by limiting frequency of error messages.\n      # error_interval = \"10s\"\n\n      ## The interval that defines the fastest rate at which the node values should be sampled and values captured. (default: 1s)\n      ## The sampling frequency should be adjusted to the dynamics of the signal to be sampled.\n      ## Higher sampling frequencies increases load on ctrlX Data Layer.\n      ## The sampling frequency can be higher, than the publish interval. Captured samples are put in a queue and sent in publish interval.\n      ## Note: The minimum sampling interval can be overruled by a global setting in the ctrlX Data Layer configuration ('datalayer/subscriptions/settings').\n      # sampling_interval = \"1s\"\n\n      ## The requested size of the node value queue. (default: 10)\n      ## Relevant if more values are captured than can be sent.\n      # queue_size = 10\n\n      ## The behaviour of the queue if it is full. (default: \"DiscardOldest\")\n      ## Possible values: \n      ## - \"DiscardOldest\"\n      ##   The oldest value gets deleted from the queue when it is full.\n      ## - \"DiscardNewest\"\n      ##   The newest value gets deleted from the queue when it is full.\n      # queue_behaviour = \"DiscardOldest\"\n\n      ## The filter when a new value will be sampled. (default: 0.0)\n      ## Calculation rule: If (abs(lastCapturedValue - newValue) > dead_band_value) capture(newValue).\n      # dead_band_value = 0.0\n\n      ## The conditions on which a sample should be captured and thus will be sent as a message. (default: \"StatusValue\")\n      ## Possible values:\n      ## - \"Status\"\n      ##   Capture the value only, when the state of the node changes from or to error state. Value changes are ignored.\n      ## - \"StatusValue\" \n      ##   Capture when the value changes or the node changes from or to error state.\n      ##   See also 'dead_band_value' for what is considered as a value change.\n      ## - \"StatusValueTimestamp\": \n      ##   Capture even if the value is the same, but the timestamp of the value is newer.\n      ##   Note: This might lead to high load on the network because every sample will be sent as a message\n      ##   even if the value of the node did not change.\n      # value_change = \"StatusValue\"\n      \n```\n\n## Metrics\n\nAll measurements are tagged with the server address of the device and the\ncorresponding node address as defined in the ctrlX Data Layer.\n\n- measurement name\n  - tags:\n    - `source` (ctrlX Data Layer server where the metrics are gathered from)\n    - `node` (Address of the ctrlX Data Layer node)\n  - fields:\n    - `{name}` (for nodes with simple data types)\n    - `{name}_{index}`(for nodes with array data types)\n    - `{name}_{jsonflat.key}` (for nodes with object data types)\n\n### Output Format\n\nThe switch \"output_json_string\" determines the format of the output metric.\n\n#### Output default format\n\nWith the output default format\n\n```toml\noutput_json_string=false\n```\n\nthe output is formatted automatically as follows depending on the data type:\n\n##### Simple data type\n\nThe value is passed 'as it is' to a metric with pattern:\n\n```text\n{name}={value}\n```\n\nSimple data types of ctrlX Data Layer:\n\n```text\nbool8,int8,uint8,int16,uint16,int32,uint32,int64,uint64,float,double,string,timestamp\n```\n\n##### Array data type\n\nEvery value in the array is passed to a metric with pattern:\n\n```text\n{name}_{index}={value[index]}\n```\n\nexample:\n\n```text\nmyarray=[1,2,3] -> myarray_1=1, myarray_2=2, myarray_3=3\n```\n\nArray data types of ctrlX Data Layer:\n\n```text\narbool8,arint8,aruint8,arint16,aruint16,arint32,aruint32,arint64,aruint64,arfloat,ardouble,arstring,artimestamp\n```\n\n##### Object data type (JSON)\n\nEvery value of the flattened json is passed to a metric with pattern:\n\n```text\n{name}_{jsonflat.key}={jsonflat.value}\n```\n\nexample:\n\n```text\nmyobj={\"a\":1,\"b\":2,\"c\":{\"d\": 3}} -> myobj_a=1, myobj_b=2, myobj_c_d=3\n```\n\n#### Output JSON format\n\nWith the output JSON format\n\n```toml\noutput_json_string=true\n```\n\nthe output is formatted as JSON string:\n\n```text\n{name}=\"{value}\"\n```\n\nexamples:\n\n```text\ninput=true -> output=\"true\"\n```\n\n```text\ninput=[1,2,3] -> output=\"[1,2,3]\"\n```\n\n```text\ninput={\"x\":4720,\"y\":9440,\"z\":{\"d\": 14160}} -> output=\"{\\\"x\\\":4720,\\\"y\\\":9440,\\\"z\\\":14160}\"\n```\n\nThe JSON output string can be passed to a processor plugin for transformation\ne.g. [Parser Processor Plugin][PARSER.md]\nor [Starlark Processor Plugin][STARLARK.md]\n\n[PARSER.md]: ../../processors/parser/README.md\n[STARLARK.md]: ../../processors/starlark/README.md\n\nexample:\n\n```toml\n[[inputs.ctrlx_datalayer.subscription]]\n   measurement = \"osci\"\n   nodes = [\n     {address=\"oscilloscope/instances/Osci_PLC/rec-values/allsignals\"},\n   ]\n   output_json_string = true\n\n[[processors.starlark]]\n   namepass = [\n      'osci',\n   ]\n   script = \"oscilloscope.star\"\n```\n\n## Troubleshooting\n\nThis plugin was contributed by\n[Bosch Rexroth](https://www.boschrexroth.com).\nFor questions regarding ctrlX AUTOMATION and this plugin feel\nfree to check out and be part of the\n[ctrlX AUTOMATION Community](https://ctrlx-automation.com/community)\nto get additional support or leave some ideas and feedback.\n\nAlso, join\n[InfluxData Community Slack](https://influxdata.com/slack) or\n[InfluxData Community Page](https://community.influxdata.com/)\nif you have questions or comments for the telegraf engineering teams.\n\n## Example Output\n\nThe plugin handles simple, array and object (JSON) data types.\n\n### Example with simple data type\n\nConfiguration:\n\n```toml\n[[inputs.ctrlx_datalayer.subscription]]\n   measurement=\"memory\"\n   [inputs.ctrlx_datalayer.subscription.tags]\n      sub_tag1=\"memory_tag1\"\n      sub_tag2=\"memory_tag2\"\n\n   [[inputs.ctrlx_datalayer.subscription.nodes]]\n      name   =\"available\"\n      address=\"framework/metrics/system/memavailable-mb\"\n      [inputs.ctrlx_datalayer.subscription.nodes.tags]\n         node_tag1=\"memory_available_tag1\"\n         node_tag2=\"memory_available_tag2\"\n\n   [[inputs.ctrlx_datalayer.subscription.nodes]]\n      name   =\"used\"\n      address=\"framework/metrics/system/memused-mb\"\n      [inputs.ctrlx_datalayer.subscription.nodes.tags]\n         node_tag1=\"memory_used_node_tag1\"\n         node_tag2=\"memory_used_node_tag2\"\n```\n\nSource:\n\n```json\n\"framework/metrics/system/memavailable-mb\" : 365.93359375\n\"framework/metrics/system/memused-mb\" : 567.67578125\n```\n\nMetrics:\n\n```text\nmemory,source=192.168.1.1,host=host.example.com,node=framework/metrics/system/memavailable-mb,node_tag1=memory_available_tag1,node_tag2=memory_available_tag2,sub_tag1=memory2_tag1,sub_tag2=memory_tag2 available=365.93359375 1680093310249627400\nmemory,source=192.168.1.1,host=host.example.com,node=framework/metrics/system/memused-mb,node_tag1=memory_used_node_tag1,node_tag2=memory_used_node_tag2,sub_tag1=memory2_tag1,sub_tag2=memory_tag2 used=567.67578125 1680093310249667600\n```\n\n### Example with array data type\n\nConfiguration:\n\n```toml\n[[inputs.ctrlx_datalayer.subscription]]\n   measurement=\"array\"\n   nodes=[\n      { name=\"ar_uint8\", address=\"alldata/dynamic/array-of-uint8\"},\n      { name=\"ar_bool8\", address=\"alldata/dynamic/array-of-bool8\"},\n   ]\n```\n\nSource:\n\n```json\n\"alldata/dynamic/array-of-bool8\" : [true, false, true]\n\"alldata/dynamic/array-of-uint8\" : [0, 255]\n```\n\nMetrics:\n\n```text\narray,source=192.168.1.1,host=host.example.com,node=alldata/dynamic/array-of-bool8 ar_bool8_0=true,ar_bool8_1=false,ar_bool8_2=true 1680095727347018800\narray,source=192.168.1.1,host=host.example.com,node=alldata/dynamic/array-of-uint8 ar_uint8_0=0,ar_uint8_1=255 1680095727347223300\n```\n\n### Example with object data type (JSON)\n\nConfiguration:\n\n```toml\n[[inputs.ctrlx_datalayer.subscription]]\n   measurement=\"motion\"\n   nodes=[\n      {name=\"linear\", address=\"motion/axs/Axis_1/state/values/actual\"},\n      {name=\"rotational\", address=\"motion/axs/Axis_2/state/values/actual\"},\n   ]\n```\n\nSource:\n\n```json\n\"motion/axs/Axis_1/state/values/actual\" : {\"actualPos\":65.249329860957,\"actualVel\":5,\"actualAcc\":0,\"actualTorque\":0,\"distLeft\":0,\"actualPosUnit\":\"mm\",\"actualVelUnit\":\"mm/min\",\"actualAccUnit\":\"m/s^2\",\"actualTorqueUnit\":\"Nm\",\"distLeftUnit\":\"mm\"}\n\"motion/axs/Axis_2/state/values/actual\" : {\"actualPos\":120,\"actualVel\":0,\"actualAcc\":0,\"actualTorque\":0,\"distLeft\":0,\"actualPosUnit\":\"deg\",\"actualVelUnit\":\"rpm\",\"actualAccUnit\":\"rad/s^2\",\"actualTorqueUnit\":\"Nm\",\"distLeftUnit\":\"deg\"}\n```\n\nMetrics:\n\n```text\nmotion,source=192.168.1.1,host=host.example.com,node=motion/axs/Axis_1/state/values/actual linear_actualVel=5,linear_distLeftUnit=\"mm\",linear_actualAcc=0,linear_distLeft=0,linear_actualPosUnit=\"mm\",linear_actualAccUnit=\"m/s^2\",linear_actualTorqueUnit=\"Nm\",linear_actualPos=65.249329860957,linear_actualVelUnit=\"mm/min\",linear_actualTorque=0 1680258290342523500\nmotion,source=192.168.1.1,host=host.example.com,node=motion/axs/Axis_2/state/values/actual rotational_distLeft=0,rotational_actualVelUnit=\"rpm\",rotational_actualAccUnit=\"rad/s^2\",rotational_distLeftUnit=\"deg\",rotational_actualPos=120,rotational_actualVel=0,rotational_actualAcc=0,rotational_actualPosUnit=\"deg\",rotational_actualTorqueUnit=\"Nm\",rotational_actualTorque=0 1680258290342538100\n```\n\nIf `output_json_string` is set in the configuration:\n\n```toml\n  output_json_string = true\n```\n\nthen the metrics will be generated like this:\n\n```text\nmotion,source=192.168.1.1,host=host.example.com,node=motion/axs/Axis_1/state/values/actual linear=\"{\\\"actualAcc\\\":0,\\\"actualAccUnit\\\":\\\"m/s^2\\\",\\\"actualPos\\\":65.249329860957,\\\"actualPosUnit\\\":\\\"mm\\\",\\\"actualTorque\\\":0,\\\"actualTorqueUnit\\\":\\\"Nm\\\",\\\"actualVel\\\":5,\\\"actualVelUnit\\\":\\\"mm/min\\\",\\\"distLeft\\\":0,\\\"distLeftUnit\\\":\\\"mm\\\"}\" 1680258290342523500\nmotion,source=192.168.1.1,host=host.example.com,node=motion/axs/Axis_2/state/values/actual rotational=\"{\\\"actualAcc\\\":0,\\\"actualAccUnit\\\":\\\"rad/s^2\\\",\\\"actualPos\\\":120,\\\"actualPosUnit\\\":\\\"deg\\\",\\\"actualTorque\\\":0,\\\"actualTorqueUnit\\\":\\\"Nm\\\",\\\"actualVel\\\":0,\\\"actualVelUnit\\\":\\\"rpm\\\",\\\"distLeft\\\":0,\\\"distLeftUnit\\\":\\\"deg\\\"}\" 1680258290342538100\n```\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/ctrlx_datalayer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ctrlx_datalayer\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/boschrexroth/ctrlx-datalayer-golang/pkg/sseclient\"\n\t\"github.com/boschrexroth/ctrlx-datalayer-golang/pkg/token\"\n\t\"github.com/google/uuid\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\n// This plugin is based on the official ctrlX CORE API. Documentation can be found in OpenAPI format at:\n// https://boschrexroth.github.io/rest-api-description/ctrlx-automation/ctrlx-core/\n// Used APIs are:\n// * ctrlX CORE - Authorization and Authentication API\n// * ctrlX CORE - Data Layer API\n//\n// All communication between the device and this input plugin is based\n// on https REST and HTML5 Server Sent Events (sse).\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype CtrlXDataLayer struct {\n\tServer   string        `toml:\"server\"`\n\tUsername config.Secret `toml:\"username\"`\n\tPassword config.Secret `toml:\"password\"`\n\n\tLog          telegraf.Logger `toml:\"-\"`\n\tSubscription []subscription\n\n\turl    string\n\twg     sync.WaitGroup\n\tcancel context.CancelFunc\n\n\tacc          telegraf.Accumulator\n\tconnection   *http.Client\n\ttokenManager token.TokenManager\n\tcommon_http.HTTPClientConfig\n}\n\nfunc (*CtrlXDataLayer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *CtrlXDataLayer) Init() error {\n\t// Check all configured subscriptions for valid settings\n\tfor i := range c.Subscription {\n\t\tsub := &c.Subscription[i]\n\t\tsub.applyDefaultSettings()\n\t\tif !choice.Contains(sub.QueueBehaviour, queueBehaviours) {\n\t\t\tc.Log.Infof(\"The right queue behaviour values are %v\", queueBehaviours)\n\t\t\treturn fmt.Errorf(\"subscription %d: setting 'queue_behaviour' %q is invalid\", i, sub.QueueBehaviour)\n\t\t}\n\t\tif !choice.Contains(sub.ValueChange, valueChanges) {\n\t\t\tc.Log.Infof(\"The right value change values are %v\", valueChanges)\n\t\t\treturn fmt.Errorf(\"subscription %d: setting 'value_change' %q is invalid\", i, sub.ValueChange)\n\t\t}\n\t\tif len(sub.Nodes) == 0 {\n\t\t\tc.Log.Warn(\"A configured subscription has no nodes configured\")\n\t\t}\n\t\tsub.index = i\n\t}\n\n\t// Generate valid communication url based on configured server address\n\tu := url.URL{\n\t\tScheme: \"https\",\n\t\tHost:   c.Server,\n\t}\n\tc.url = u.String()\n\tif _, err := url.Parse(c.url); err != nil {\n\t\treturn errors.New(\"invalid server address\")\n\t}\n\n\treturn nil\n}\n\nfunc (c *CtrlXDataLayer) Start(acc telegraf.Accumulator) error {\n\tvar ctx context.Context\n\tctx, c.cancel = context.WithCancel(context.Background())\n\n\tvar err error\n\tc.connection, err = c.HTTPClientConfig.CreateClient(ctx, c.Log)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create http client: %w\", err)\n\t}\n\n\tusername, err := c.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\n\tpassword, err := c.Password.Get()\n\tif err != nil {\n\t\tusername.Destroy()\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\n\tc.tokenManager = token.TokenManager{\n\t\tUrl:        c.url,\n\t\tUsername:   username.String(),\n\t\tPassword:   password.String(),\n\t\tConnection: c.connection,\n\t}\n\tusername.Destroy()\n\tpassword.Destroy()\n\n\tc.acc = acc\n\n\tc.gatherLoop(ctx)\n\n\treturn nil\n}\n\nfunc (*CtrlXDataLayer) Gather(telegraf.Accumulator) error {\n\t// Metrics are sent to the accumulator asynchronously in worker thread. So nothing to do here.\n\treturn nil\n}\n\nfunc (c *CtrlXDataLayer) Stop() {\n\tc.cancel()\n\tc.wg.Wait()\n\tif c.connection != nil {\n\t\tc.connection.CloseIdleConnections()\n\t}\n}\n\n// convertTimestamp2UnixTime converts the given Data Layer timestamp of the payload to UnixTime.\nfunc convertTimestamp2UnixTime(t int64) time.Time {\n\t// 1 sec=1000 millisec=1000000 microsec=1000000000 nanosec.\n\t// Convert from FILETIME (100-nanosecond intervals since January 1, 1601 UTC) to\n\t// seconds and nanoseconds since January 1, 1970 UTC.\n\t// Between Jan 1, 1601 and Jan 1, 1970 there are 11644473600 seconds.\n\treturn time.Unix(0, (t-116444736000000000)*100)\n}\n\n// createSubscription uses the official 'ctrlX Data Layer API' to create the sse subscription.\nfunc (c *CtrlXDataLayer) createSubscription(sub *subscription) (string, error) {\n\tsseURL := c.url + subscriptionPath\n\n\tid := \"telegraf_\" + uuid.New().String()\n\trequest := sub.createRequest(id)\n\tpayload, err := json.Marshal(request)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create subscription %d payload: %w\", sub.index, err)\n\t}\n\n\trequestBody := bytes.NewBuffer(payload)\n\treq, err := http.NewRequest(\"POST\", sseURL, requestBody)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create subscription %d request: %w\", sub.index, err)\n\t}\n\n\treq.Header.Add(\"Authorization\", c.tokenManager.Token.String())\n\n\tresp, err := c.connection.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to do request to create sse subscription %d: %w\", sub.index, err)\n\t}\n\tresp.Body.Close()\n\n\tif resp.StatusCode != 200 && resp.StatusCode != 201 {\n\t\treturn \"\", fmt.Errorf(\"failed to create sse subscription %d, status: %s\", sub.index, resp.Status)\n\t}\n\n\treturn sseURL + \"/\" + id, nil\n}\n\n// createSubscriptionAndSseClient creates a sse subscription on the server and\n// initializes a sse client to receive sse events from the server.\nfunc (c *CtrlXDataLayer) createSubscriptionAndSseClient(sub *subscription) (*sseclient.SseClient, error) {\n\tt, err := c.tokenManager.RequestAuthToken()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsubURL, err := c.createSubscription(sub)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := sseclient.NewSseClient(subURL, t.String(), c.InsecureSkipVerify)\n\n\treturn client, nil\n}\n\n// addMetric writes sse metric into accumulator.\nfunc (c *CtrlXDataLayer) addMetric(se *sseclient.SseEvent, sub *subscription) {\n\tswitch se.Event {\n\tcase \"update\":\n\t\t// Received an updated value, that we translate into a metric\n\t\tvar d sseEventData\n\n\t\tif err := json.Unmarshal([]byte(se.Data), &d); err != nil {\n\t\t\tc.acc.AddError(fmt.Errorf(\"received malformed data from 'update' event: %w\", err))\n\t\t\treturn\n\t\t}\n\t\tm, err := c.createMetric(&d, sub)\n\t\tif err != nil {\n\t\t\tc.acc.AddError(fmt.Errorf(\"failed to create metrics: %w\", err))\n\t\t\treturn\n\t\t}\n\t\tc.acc.AddMetric(m)\n\tcase \"error\":\n\t\t// Received an error event, that we report to the accumulator\n\t\tvar e sseEventError\n\t\tif err := json.Unmarshal([]byte(se.Data), &e); err != nil {\n\t\t\tc.acc.AddError(fmt.Errorf(\"received malformed data from 'error' event: %w\", err))\n\t\t\treturn\n\t\t}\n\t\tc.acc.AddError(fmt.Errorf(\"received 'error' event for node: %q\", e.Instance))\n\tcase \"keepalive\":\n\t\t// Keepalive events are ignored for the moment\n\t\tc.Log.Debug(\"Received keepalive event\")\n\tdefault:\n\t\t// Received a yet unsupported event type\n\t\tc.Log.Debugf(\"Received unsupported event: %q\", se.Event)\n\t}\n}\n\n// createMetric - create metric depending on flag 'output_json' and data type\nfunc (c *CtrlXDataLayer) createMetric(em *sseEventData, sub *subscription) (telegraf.Metric, error) {\n\tt := convertTimestamp2UnixTime(em.Timestamp)\n\tnode := sub.node(em.Node)\n\tif node == nil {\n\t\treturn nil, errors.New(\"node not found\")\n\t}\n\n\t// default tags\n\ttags := map[string]string{\n\t\t\"node\":   em.Node,\n\t\t\"source\": c.Server,\n\t}\n\n\t// add tags of subscription if user has defined\n\tfor key, value := range sub.Tags {\n\t\ttags[key] = value\n\t}\n\n\t// add tags of node if user has defined\n\tfor key, value := range node.Tags {\n\t\ttags[key] = value\n\t}\n\n\t// set measurement of subscription\n\tmeasurement := sub.Measurement\n\n\t// get field key from node properties\n\tfieldKey := node.fieldKey()\n\n\tif fieldKey == \"\" {\n\t\treturn nil, errors.New(\"field key not valid\")\n\t}\n\n\tif sub.OutputJSONString {\n\t\tb, err := json.Marshal(em.Value)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfields := map[string]interface{}{fieldKey: string(b)}\n\t\tm := metric.New(measurement, tags, fields, t)\n\t\treturn m, nil\n\t}\n\n\tswitch em.Type {\n\tcase \"object\":\n\t\tflattener := parsers_json.JSONFlattener{}\n\t\terr := flattener.FullFlattenJSON(fieldKey, em.Value, true, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tm := metric.New(measurement, tags, flattener.Fields, t)\n\t\treturn m, nil\n\tcase \"arbool8\",\n\t\t\"arint8\", \"aruint8\",\n\t\t\"arint16\", \"aruint16\",\n\t\t\"arint32\", \"aruint32\",\n\t\t\"arint64\", \"aruint64\",\n\t\t\"arfloat\", \"ardouble\",\n\t\t\"arstring\",\n\t\t\"artimestamp\":\n\t\tfields := make(map[string]interface{})\n\t\tvalues := em.Value.([]interface{})\n\t\tfor i := 0; i < len(values); i++ {\n\t\t\tindex := strconv.Itoa(i)\n\t\t\tkey := fieldKey + \"_\" + index\n\t\t\tfields[key] = values[i]\n\t\t}\n\t\tm := metric.New(measurement, tags, fields, t)\n\t\treturn m, nil\n\tcase \"bool8\",\n\t\t\"int8\", \"uint8\",\n\t\t\"int16\", \"uint16\",\n\t\t\"int32\", \"uint32\",\n\t\t\"int64\", \"uint64\",\n\t\t\"float\", \"double\",\n\t\t\"string\",\n\t\t\"timestamp\":\n\t\tfields := map[string]interface{}{fieldKey: em.Value}\n\t\tm := metric.New(measurement, tags, fields, t)\n\t\treturn m, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unsupported value type: %s\", em.Type)\n}\n\n// gatherLoop creates sse subscriptions on the Data Layer and requests the sse data\n// the connection will be restablished if the sse subscription is broken.\nfunc (c *CtrlXDataLayer) gatherLoop(ctx context.Context) {\n\tfor _, sub := range c.Subscription {\n\t\tc.wg.Add(1)\n\t\tgo func(sub subscription) {\n\t\t\tdefer c.wg.Done()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\tc.Log.Debugf(\"Gather loop for subscription %d stopped\", sub.index)\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t\tclient, err := c.createSubscriptionAndSseClient(&sub)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tc.Log.Errorf(\"Creating sse client to subscription %d: %v\", sub.index, err)\n\t\t\t\t\t\ttime.Sleep(time.Duration(defaultReconnectInterval))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tc.Log.Debugf(\"Created sse client to subscription %d\", sub.index)\n\n\t\t\t\t\t// Establish connection and handle events in a callback function.\n\t\t\t\t\terr = client.Subscribe(ctx, func(event string, data string) {\n\t\t\t\t\t\tc.addMetric(&sseclient.SseEvent{\n\t\t\t\t\t\t\tEvent: event,\n\t\t\t\t\t\t\tData:  data,\n\t\t\t\t\t\t}, &sub)\n\t\t\t\t\t})\n\t\t\t\t\tif errors.Is(err, context.Canceled) {\n\t\t\t\t\t\t// Subscription cancelled\n\t\t\t\t\t\tc.Log.Debugf(\"Requesting data of subscription %d cancelled\", sub.index)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tc.Log.Errorf(\"Requesting data of subscription %d failed: %v\", sub.index, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}(sub)\n\t}\n}\n\n// init registers the plugin in telegraf.\nfunc init() {\n\tinputs.Add(\"ctrlx_datalayer\", func() telegraf.Input {\n\t\treturn &CtrlXDataLayer{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_payload_types.go",
    "content": "package ctrlx_datalayer\n\n// Once a subscription is created, the server will send event notifications to this plugin.\n// This file contains the different event types and the included event payload.\n\n// sseEventData represents the json structure send by the ctrlX CORE\n// server on an \"update\" event.\ntype sseEventData struct {\n\tNode      string      `json:\"node\"`\n\tTimestamp int64       `json:\"timestamp\"`\n\tType      string      `json:\"type\"`\n\tValue     interface{} `json:\"value\"`\n}\n\n// sseEventError represents the json structure send by the ctrlX CORE\n// server on an \"error\" event.\ntype sseEventError struct {\n\tInstance string `json:\"instance\"`\n}\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_subscription.go",
    "content": "package ctrlx_datalayer\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\n// A subscription can be used to watch multiple ctrlX Data Layer nodes for changes.\n// Additional configuration settings can be given to tune the sampling and monitoring behaviour of the nodes.\n// All nodes in a subscription share the same configuration.\n// The plugin is able to create and manage multiple subscriptions.\n\n// The allowed values of the subscription property 'QueueBehaviour'\nvar queueBehaviours = []string{\"DiscardOldest\", \"DiscardNewest\"}\n\n// The allowed values of the subscription property 'ValueChange'\nvar valueChanges = []string{\"Status\", \"StatusValue\", \"StatusValueTimestamp\"}\n\n// The default subscription settings\nconst (\n\tdefaultKeepaliveInterval = config.Duration(60 * time.Second)\n\tdefaultErrorInterval     = config.Duration(10 * time.Second)\n\tdefaultReconnectInterval = config.Duration(10 * time.Second)\n\tdefaultPublishInterval   = config.Duration(1 * time.Second)\n\tdefaultSamplingInterval  = config.Duration(1 * time.Second)\n\tdefaultQueueSize         = 10\n\tdefaultQueueBehaviour    = \"DiscardOldest\"\n\tdefaultValueChange       = \"StatusValue\"\n\tdefaultMeasurementName   = \"ctrlx\"\n\tsubscriptionPath         = \"/automation/api/v2/events\"\n)\n\n// node contains all properties of a node configuration\ntype node struct {\n\tName    string            `toml:\"name\"`\n\tAddress string            `toml:\"address\"`\n\tTags    map[string]string `toml:\"tags\"`\n}\n\n// subscription contains all properties of a subscription configuration\ntype subscription struct {\n\tindex             int\n\tNodes             []node            `toml:\"nodes\"`\n\tTags              map[string]string `toml:\"tags\"`\n\tMeasurement       string            `toml:\"measurement\"`\n\tPublishInterval   config.Duration   `toml:\"publish_interval\"`\n\tKeepaliveInterval config.Duration   `toml:\"keep_alive_interval\"`\n\tErrorInterval     config.Duration   `toml:\"error_interval\"`\n\tSamplingInterval  config.Duration   `toml:\"sampling_interval\"`\n\tQueueSize         uint              `toml:\"queue_size\"`\n\tQueueBehaviour    string            `toml:\"queue_behaviour\"`\n\tDeadBandValue     float64           `toml:\"dead_band_value\"`\n\tValueChange       string            `toml:\"value_change\"`\n\tOutputJSONString  bool              `toml:\"output_json_string\"`\n}\n\n// rule can be used to override default rule settings.\ntype rule struct {\n\tRuleType string      `json:\"rule_type\"`\n\tRule     interface{} `json:\"rule\"`\n}\n\n// sampling can be used to override default sampling settings.\ntype sampling struct {\n\tSamplingInterval uint64 `json:\"samplingInterval\"`\n}\n\n// queueing can be used to override default queuing settings.\ntype queueing struct {\n\tQueueSize uint   `json:\"queueSize\"`\n\tBehaviour string `json:\"behaviour\"`\n}\n\n// dataChangeFilter can be used to override default data change filter settings.\ntype dataChangeFilter struct {\n\tDeadBandValue float64 `json:\"deadBandValue\"`\n}\n\n// changeEvents can be used to override default change events settings.\ntype changeEvents struct {\n\tValueChange      string `json:\"valueChange\"`\n\tBrowselistChange bool   `json:\"browselistChange\"`\n\tMetadataChange   bool   `json:\"metadataChange\"`\n}\n\n// subscriptionProperties can be used to override default subscription settings.\ntype subscriptionProperties struct {\n\tKeepaliveInterval int64  `json:\"keepaliveInterval\"`\n\tRules             []rule `json:\"rules\"`\n\tID                string `json:\"id\"`\n\tPublishInterval   int64  `json:\"publishInterval\"`\n\tErrorInterval     int64  `json:\"errorInterval\"`\n}\n\n// subscriptionRequest can be used to create a sse subscription at the ctrlX Data Layer.\ntype subscriptionRequest struct {\n\tProperties subscriptionProperties `json:\"properties\"`\n\tNodes      []string               `json:\"nodes\"`\n}\n\n// applyDefaultSettings applies the default settings if they are not configured in the config file.\nfunc (s *subscription) applyDefaultSettings() {\n\tif s.Measurement == \"\" {\n\t\ts.Measurement = defaultMeasurementName\n\t}\n\tif s.PublishInterval == 0 {\n\t\ts.PublishInterval = defaultPublishInterval\n\t}\n\tif s.KeepaliveInterval == 0 {\n\t\ts.KeepaliveInterval = defaultKeepaliveInterval\n\t}\n\tif s.ErrorInterval == 0 {\n\t\ts.ErrorInterval = defaultErrorInterval\n\t}\n\tif s.SamplingInterval == 0 {\n\t\ts.SamplingInterval = defaultSamplingInterval\n\t}\n\tif s.QueueSize == 0 {\n\t\ts.QueueSize = defaultQueueSize\n\t}\n\tif s.QueueBehaviour == \"\" {\n\t\ts.QueueBehaviour = defaultQueueBehaviour\n\t}\n\tif s.ValueChange == \"\" {\n\t\ts.ValueChange = defaultValueChange\n\t}\n}\n\n// createRequestBody builds the request body for the sse subscription, based on the subscription configuration.\n// The request body can be send to the server to create a new subscription.\nfunc (s *subscription) createRequest(id string) subscriptionRequest {\n\tpl := subscriptionRequest{\n\t\tProperties: subscriptionProperties{\n\t\t\tRules: []rule{\n\t\t\t\t{\"Sampling\", sampling{uint64(time.Duration(s.SamplingInterval).Microseconds())}},\n\t\t\t\t{\"Queueing\", queueing{s.QueueSize, s.QueueBehaviour}},\n\t\t\t\t{\"DataChangeFilter\", dataChangeFilter{s.DeadBandValue}},\n\t\t\t\t{\"ChangeEvents\", changeEvents{s.ValueChange, false, false}},\n\t\t\t},\n\t\t\tID:                id,\n\t\t\tKeepaliveInterval: time.Duration(s.KeepaliveInterval).Milliseconds(),\n\t\t\tPublishInterval:   time.Duration(s.PublishInterval).Milliseconds(),\n\t\t\tErrorInterval:     time.Duration(s.ErrorInterval).Milliseconds(),\n\t\t},\n\t\tNodes: s.addressList(),\n\t}\n\n\treturn pl\n}\n\n// addressList lists all configured node addresses\nfunc (s *subscription) addressList() []string {\n\taddressList := make([]string, 0, len(s.Nodes))\n\tfor _, node := range s.Nodes {\n\t\taddressList = append(addressList, node.Address)\n\t}\n\treturn addressList\n}\n\n// node finds the node according the node address\nfunc (s *subscription) node(address string) *node {\n\tfor _, node := range s.Nodes {\n\t\tif address == node.Address {\n\t\t\treturn &node\n\t\t}\n\t}\n\treturn nil\n}\n\n// fieldKey determines the field key out of node name or address\nfunc (n *node) fieldKey() string {\n\tif n.Name != \"\" {\n\t\t// return user defined node name as field key\n\t\treturn n.Name\n\t}\n\n\t// fallback: field key is extracted from mandatory node address\n\ti := strings.LastIndex(n.Address, \"/\")\n\tif i > 0 {\n\t\t// return last part of node address as field key\n\t\treturn n.Address[i+1:]\n\t}\n\n\t// return full node address as field key\n\treturn n.Address\n}\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_subscription_test.go",
    "content": "package ctrlx_datalayer\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\nfunc TestSubscription_createRequest(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tsubscription subscription\n\t\tid           string\n\t\twantBody     subscriptionRequest\n\t\twantErr      bool\n\t}{\n\t\t{\n\t\t\tname: \"Should_Return_Expected_Request\",\n\t\t\tsubscription: subscription{\n\t\t\t\tNodes: []node{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"node1\",\n\t\t\t\t\t\tAddress: \"path/to/node1\",\n\t\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"node2\",\n\t\t\t\t\t\tAddress: \"path/to/node2\",\n\t\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTags:              map[string]string{},\n\t\t\t\tMeasurement:       \"\",\n\t\t\t\tPublishInterval:   config.Duration(2 * time.Second),\n\t\t\t\tKeepaliveInterval: config.Duration(10 * time.Second),\n\t\t\t\tErrorInterval:     config.Duration(20 * time.Second),\n\t\t\t\tSamplingInterval:  config.Duration(100 * time.Millisecond),\n\t\t\t\tQueueSize:         100,\n\t\t\t\tQueueBehaviour:    \"DiscardNewest\",\n\t\t\t\tDeadBandValue:     1.12345,\n\t\t\t\tValueChange:       \"StatusValueTimestamp\",\n\t\t\t\tOutputJSONString:  true,\n\t\t\t},\n\t\t\tid: \"sub_id\",\n\t\t\twantBody: subscriptionRequest{\n\t\t\t\tProperties: subscriptionProperties{\n\t\t\t\t\tKeepaliveInterval: 10000,\n\t\t\t\t\tRules: []rule{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"Sampling\",\n\t\t\t\t\t\t\tsampling{\n\t\t\t\t\t\t\t\tSamplingInterval: 100000,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"Queueing\",\n\t\t\t\t\t\t\tqueueing{\n\t\t\t\t\t\t\t\tQueueSize: 100,\n\t\t\t\t\t\t\t\tBehaviour: \"DiscardNewest\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"DataChangeFilter\",\n\t\t\t\t\t\t\tdataChangeFilter{\n\t\t\t\t\t\t\t\tDeadBandValue: 1.12345,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"ChangeEvents\",\n\t\t\t\t\t\t\tchangeEvents{\n\t\t\t\t\t\t\t\tValueChange: \"StatusValueTimestamp\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tID:              \"sub_id\",\n\t\t\t\t\tPublishInterval: 2000,\n\t\t\t\t\tErrorInterval:   20000,\n\t\t\t\t},\n\t\t\t\tNodes: []string{\n\t\t\t\t\t\"path/to/node1\",\n\t\t\t\t\t\"path/to/node2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot := tt.subscription.createRequest(tt.id)\n\t\t\trequire.Equal(t, tt.wantBody, got)\n\t\t})\n\t}\n}\n\nfunc TestSubscription_node(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tnodes   []node\n\t\taddress string\n\t\twant    *node\n\t}{\n\t\t{\n\t\t\tname: \"Should_Return_Node_Of_Given_Address\",\n\t\t\tnodes: []node{\n\t\t\t\t{\n\t\t\t\t\tName:    \"node1\",\n\t\t\t\t\tAddress: \"path/to/node1\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"node2\",\n\t\t\t\t\tAddress: \"path/to/node2\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"\",\n\t\t\t\t\tAddress: \"path/to/node3\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t},\n\t\t\taddress: \"path/to/node3\",\n\t\t\twant: &node{\n\t\t\t\tName:    \"\",\n\t\t\t\tAddress: \"path/to/node3\",\n\t\t\t\tTags:    map[string]string{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Should_Return_Nil_If_Node_With_Given_Address_Not_Found\",\n\t\t\tnodes: []node{\n\t\t\t\t{\n\t\t\t\t\tName:    \"Node1\",\n\t\t\t\t\tAddress: \"path/to/node1\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"Node2\",\n\t\t\t\t\tAddress: \"path/to/node2\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"\",\n\t\t\t\t\tAddress: \"path/to/node3\",\n\t\t\t\t\tTags:    map[string]string{},\n\t\t\t\t},\n\t\t\t},\n\t\t\taddress: \"path/to/node4\",\n\t\t\twant:    nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ts := &subscription{\n\t\t\t\tNodes: tt.nodes,\n\t\t\t}\n\t\t\trequire.Equal(t, tt.want, s.node(tt.address))\n\t\t})\n\t}\n}\n\nfunc TestSubscription_addressList(t *testing.T) {\n\ttests := []struct {\n\t\tname  string\n\t\tnodes []node\n\t\twant  []string\n\t}{\n\t\t{\n\t\t\tname: \"Should_Return_AddressArray_Of_All_Nodes\",\n\t\t\tnodes: []node{\n\t\t\t\t{\n\t\t\t\t\tAddress: \"framework/metrics/system/memused-mb\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddress: \"framework/metrics/system/memavailable-mb\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddress: \"root\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddress: \"\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twant: []string{\n\t\t\t\t\"framework/metrics/system/memused-mb\",\n\t\t\t\t\"framework/metrics/system/memavailable-mb\",\n\t\t\t\t\"root\",\n\t\t\t\t\"\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ts := &subscription{\n\t\t\t\tNodes: tt.nodes,\n\t\t\t}\n\t\t\trequire.Equal(t, tt.want, s.addressList())\n\t\t})\n\t}\n}\n\nfunc TestNode_fieldKey(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tnode node\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"Should_Return_Name_When_Name_Is_Not_Empty\",\n\t\t\tnode: node{\n\t\t\t\tName:    \"used\",\n\t\t\t\tAddress: \"framework/metrics/system/memused-mb\",\n\t\t\t},\n\t\t\twant: \"used\",\n\t\t},\n\t\t{\n\t\t\tname: \"Should_Return_Address_Base_When_Name_Is_Empty_And_Address_Contains_Full_Path\",\n\t\t\tnode: node{\n\t\t\t\tName:    \"\",\n\t\t\t\tAddress: \"framework/metrics/system/memused-mb\",\n\t\t\t},\n\t\t\twant: \"memused-mb\",\n\t\t},\n\t\t{\n\t\t\tname: \"Should_Return_Address_Base_Root_When_Name_Is_Empty_And_Address_Contains_Root_Path\",\n\t\t\tnode: node{\n\t\t\t\tName:    \"\",\n\t\t\t\tAddress: \"root\",\n\t\t\t},\n\t\t\twant: \"root\",\n\t\t},\n\t\t{\n\t\t\tname: \"Should_Return_Empty_When_Name_and_Address_Are_Empty\",\n\t\t\tnode: node{\n\t\t\t\tName:    \"\",\n\t\t\t\tAddress: \"\",\n\t\t\t},\n\t\t\twant: \"\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.want, tt.node.fieldKey())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_test.go",
    "content": "package ctrlx_datalayer\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/boschrexroth/ctrlx-datalayer-golang/pkg/token\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst path = \"/automation/api/v2/events\"\n\nvar multiEntries = false\nvar mux sync.Mutex\n\nfunc setMultiEntries(m bool) {\n\tmux.Lock()\n\tdefer mux.Unlock()\n\tmultiEntries = m\n}\n\nfunc getMultiEntries() bool {\n\tmux.Lock()\n\tdefer mux.Unlock()\n\treturn multiEntries\n}\n\nfunc TestCtrlXCreateSubscriptionBasic(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusCreated)\n\t\tif _, err := w.Write([]byte(\"201 created\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\tsubs := []subscription{\n\t\t{\n\t\t\tindex: 0,\n\t\t\tNodes: []node{\n\t\t\t\t{Name: \"counter\", Address: \"plc/app/Application/sym/PLC_PRG/counter\"},\n\t\t\t\t{Name: \"counterReverse\", Address: \"plc/app/Application/sym/PLC_PRG/counterReverse\"},\n\t\t\t},\n\t\t},\n\t}\n\ts := &CtrlXDataLayer{\n\t\tconnection:   &http.Client{},\n\t\turl:          server.URL,\n\t\tUsername:     config.NewSecret([]byte(\"user\")),\n\t\tPassword:     config.NewSecret([]byte(\"password\")),\n\t\ttokenManager: token.TokenManager{Url: server.URL, Username: \"user\", Password: \"password\", Connection: &http.Client{}},\n\t\tSubscription: subs,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tsubID, err := s.createSubscription(&subs[0])\n\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, subID)\n}\n\nfunc TestCtrlXCreateSubscriptionDriven(t *testing.T) {\n\tvar tests = []struct {\n\t\tres       string\n\t\tstatus    int\n\t\twantError bool\n\t}{\n\t\t{res: \"{\\\"status\\\":200}\", status: 200, wantError: false},\n\t\t{res: \"{\\\"status\\\":401}\", status: 401, wantError: true},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.res, func(t *testing.T) {\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(test.status)\n\t\t\t\tif _, err := w.Write([]byte(test.res)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\tsubs := []subscription{\n\t\t\t\t{\n\t\t\t\t\tNodes: []node{\n\t\t\t\t\t\t{Name: \"counter\", Address: \"plc/app/Application/sym/PLC_PRG/counter\"},\n\t\t\t\t\t\t{Name: \"counterReverse\", Address: \"plc/app/Application/sym/PLC_PRG/counterReverse\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\ts := &CtrlXDataLayer{\n\t\t\t\tconnection:   &http.Client{},\n\t\t\t\turl:          server.URL,\n\t\t\t\tUsername:     config.NewSecret([]byte(\"user\")),\n\t\t\t\tPassword:     config.NewSecret([]byte(\"password\")),\n\t\t\t\tSubscription: subs,\n\t\t\t\ttokenManager: token.TokenManager{Url: server.URL, Username: \"user\", Password: \"password\", Connection: &http.Client{}},\n\t\t\t\tLog:          testutil.Logger{},\n\t\t\t}\n\t\t\tsubID, err := s.createSubscription(&subs[0])\n\n\t\t\tif test.wantError {\n\t\t\t\trequire.EqualError(t, err, \"failed to create sse subscription 0, status: 401 Unauthorized\")\n\t\t\t\trequire.Empty(t, subID)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, subID)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc newServer(t *testing.T) *httptest.Server {\n\tmux := http.NewServeMux()\n\t// Handle request to fetch token\n\tmux.HandleFunc(\"/identity-manager/api/v2/auth/token\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := w.Write([]byte(\"{\\\"access_token\\\": \\\"eyJhbGciOiJIU.xxx.xxx\\\", \\\"token_type\\\":\\\"Bearer\\\"}\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t})\n\t// Handle request to validate token\n\tmux.HandleFunc(\"/identity-manager/api/v2/auth/token/validity\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := w.Write([]byte(\"{\\\"valid\\\": \\\"true\\\"}\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t})\n\t// Handle request to create subscription\n\tmux.HandleFunc(path, func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusCreated)\n\t\tif _, err := w.Write([]byte(\"201 created\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t})\n\t// Handle request to fetch sse data\n\tmux.HandleFunc(path+\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method == http.MethodGet {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(\"event: update\\n\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif _, err := w.Write([]byte(\"id: 12345\\n\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif getMultiEntries() {\n\t\t\t\tdata := \"data: {\\n\"\n\t\t\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdata = \"data: \\\"node\\\":\\\"plc/app/Application/sym/PLC_PRG/counter\\\", \\\"timestamp\\\":132669450604571037,\\\"type\\\":\\\"double\\\",\\\"value\\\":44.0\\n\"\n\t\t\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdata = \"data: }\\n\"\n\t\t\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdata := \"data: {\\\"node\\\":\\\"plc/app/Application/sym/PLC_PRG/counter\\\", \\\"timestamp\\\":132669450604571037,\\\"type\\\":\\\"double\\\",\\\"value\\\":43.0}\\n\"\n\t\t\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif _, err := w.Write([]byte(\"\\n\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\treturn httptest.NewServer(mux)\n}\n\nfunc cleanup(server *httptest.Server) {\n\tserver.CloseClientConnections()\n\tserver.Close()\n}\n\nfunc initRunner(t *testing.T) (*CtrlXDataLayer, *httptest.Server) {\n\tserver := newServer(t)\n\tsubs := []subscription{\n\t\t{\n\t\t\tMeasurement: \"ctrlx\",\n\t\t\tNodes: []node{\n\t\t\t\t{Name: \"counter\", Address: \"plc/app/Application/sym/PLC_PRG/counter\"},\n\t\t\t},\n\t\t},\n\t}\n\n\ts := &CtrlXDataLayer{\n\t\tconnection: &http.Client{},\n\t\turl:        server.URL,\n\t\tUsername:   config.NewSecret([]byte(\"user\")),\n\t\tPassword:   config.NewSecret([]byte(\"password\")),\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\tClientConfig: tls.ClientConfig{\n\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tSubscription: subs,\n\t\ttokenManager: token.TokenManager{Url: server.URL, Username: \"user\", Password: \"password\", Connection: &http.Client{}},\n\t\tLog:          testutil.Logger{},\n\t}\n\treturn s, server\n}\n\nfunc TestCtrlXMetricsField(t *testing.T) {\n\tconst measurement = \"ctrlx\"\n\tconst fieldName = \"counter\"\n\n\ts, server := initRunner(t)\n\tdefer cleanup(server)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(s.Start))\n\trequire.Eventually(t, func() bool {\n\t\tif v, found := acc.FloatField(measurement, fieldName); found {\n\t\t\trequire.InDelta(t, 43.0, v, testutil.DefaultDelta)\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}, time.Second*10, time.Second)\n}\n\nfunc TestCtrlXMetricsMulti(t *testing.T) {\n\tconst measurement = \"ctrlx\"\n\tconst fieldName = \"counter\"\n\n\tsetMultiEntries(true)\n\ts, server := initRunner(t)\n\tdefer cleanup(server)\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, acc.GatherError(s.Start))\n\trequire.Eventually(t, func() bool {\n\t\tif v, found := acc.FloatField(measurement, fieldName); found {\n\t\t\trequire.InDelta(t, 44.0, v, testutil.DefaultDelta)\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}, time.Second*10, time.Second)\n\n\tsetMultiEntries(false)\n}\n\nfunc TestCtrlXCreateSseClient(t *testing.T) {\n\tsub := subscription{\n\t\tMeasurement: \"ctrlx\",\n\t\tNodes: []node{\n\t\t\t{Name: \"counter\", Address: \"plc/app/Application/sym/PLC_PRG/counter\"},\n\t\t\t{Name: \"counterReverse\", Address: \"plc/app/Application/sym/PLC_PRG/counterReverse\"},\n\t\t},\n\t}\n\ts, server := initRunner(t)\n\tdefer cleanup(server)\n\tclient, err := s.createSubscriptionAndSseClient(&sub)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, client)\n}\n\nfunc TestConvertTimestamp2UnixTime(t *testing.T) {\n\texpected := time.Date(2022, 02, 14, 14, 22, 38, 333552400, time.UTC)\n\tactual := convertTimestamp2UnixTime(132893221583335524)\n\trequire.EqualValues(t, expected.UnixNano(), actual.UnixNano())\n}\n"
  },
  {
    "path": "plugins/inputs/ctrlx_datalayer/sample.conf",
    "content": "# A ctrlX Data Layer server sent event input plugin\n[[inputs.ctrlx_datalayer]]\n   ## Hostname or IP address of the ctrlX CORE Data Layer server\n   ##  example: server = \"localhost\"        # Telegraf is running directly on the device\n   ##           server = \"192.168.1.1\"      # Connect to ctrlX CORE remote via IP\n   ##           server = \"host.example.com\" # Connect to ctrlX CORE remote via hostname\n   ##           server = \"10.0.2.2:8443\"    # Connect to ctrlX CORE Virtual from development environment\n   server = \"localhost\"\n\n   ## Authentication credentials\n   username = \"boschrexroth\"\n   password = \"boschrexroth\"\n\n   ## Use TLS but skip chain & host verification\n   # insecure_skip_verify = false\n\n   ## Timeout for HTTP requests. (default: \"10s\")\n   # timeout = \"10s\"\n\n\n   ## Create a ctrlX Data Layer subscription.\n   ## It is possible to define multiple subscriptions per host. Each subscription can have its own\n   ## sampling properties and a list of nodes to subscribe to.\n   ## All subscriptions share the same credentials.\n   [[inputs.ctrlx_datalayer.subscription]]\n      ## The name of the measurement. (default: \"ctrlx\")\n      measurement = \"memory\"\n\n      ## Configure the ctrlX Data Layer nodes which should be subscribed.\n      ## address - node address in ctrlX Data Layer (mandatory)\n      ## name    - field name to use in the output (optional, default: base name of address)\n      ## tags    - extra node tags to be added to the output metric (optional)\n      ## Note: \n      ## Use either the inline notation or the bracketed notation, not both.\n      ## The tags property is only supported in bracketed notation due to toml parser restrictions\n      ## Examples:\n      ## Inline notation \n      nodes=[\n         {name=\"available\", address=\"framework/metrics/system/memavailable-mb\"},\n         {name=\"used\", address=\"framework/metrics/system/memused-mb\"},\n      ]\n      ## Bracketed notation\n      # [[inputs.ctrlx_datalayer.subscription.nodes]]\n      #    name   =\"available\"\n      #    address=\"framework/metrics/system/memavailable-mb\"\n      #    ## Define extra tags related to node to be added to the output metric (optional)\n      #    [inputs.ctrlx_datalayer.subscription.nodes.tags]\n      #       node_tag1=\"node_tag1\"\n      #       node_tag2=\"node_tag2\"\n      # [[inputs.ctrlx_datalayer.subscription.nodes]]\n      #    name   =\"used\"\n      #    address=\"framework/metrics/system/memused-mb\"\n\n      ## The switch \"output_json_string\" enables output of the measurement as json. \n      ## That way it can be used in in a subsequent processor plugin, e.g. \"Starlark Processor Plugin\".\n      # output_json_string = false\n\n      ## Define extra tags related to subscription to be added to the output metric (optional)\n      # [inputs.ctrlx_datalayer.subscription.tags]\n      #    subscription_tag1 = \"subscription_tag1\"\n      #    subscription_tag2 = \"subscription_tag2\"\n\n      ## The interval in which messages shall be sent by the ctrlX Data Layer to this plugin. (default: 1s)\n      ## Higher values reduce load on network by queuing samples on server side and sending as a single TCP packet.\n      # publish_interval = \"1s\"\n\n      ## The interval a \"keepalive\" message is sent if no change of data occurs. (default: 60s)\n      ## Only used internally to detect broken network connections.\n      # keep_alive_interval = \"60s\"\n\n      ## The interval an \"error\" message is sent if an error was received from a node. (default: 10s)\n      ## Higher values reduce load on output target and network in case of errors by limiting frequency of error messages.\n      # error_interval = \"10s\"\n\n      ## The interval that defines the fastest rate at which the node values should be sampled and values captured. (default: 1s)\n      ## The sampling frequency should be adjusted to the dynamics of the signal to be sampled.\n      ## Higher sampling frequencies increases load on ctrlX Data Layer.\n      ## The sampling frequency can be higher, than the publish interval. Captured samples are put in a queue and sent in publish interval.\n      ## Note: The minimum sampling interval can be overruled by a global setting in the ctrlX Data Layer configuration ('datalayer/subscriptions/settings').\n      # sampling_interval = \"1s\"\n\n      ## The requested size of the node value queue. (default: 10)\n      ## Relevant if more values are captured than can be sent.\n      # queue_size = 10\n\n      ## The behaviour of the queue if it is full. (default: \"DiscardOldest\")\n      ## Possible values: \n      ## - \"DiscardOldest\"\n      ##   The oldest value gets deleted from the queue when it is full.\n      ## - \"DiscardNewest\"\n      ##   The newest value gets deleted from the queue when it is full.\n      # queue_behaviour = \"DiscardOldest\"\n\n      ## The filter when a new value will be sampled. (default: 0.0)\n      ## Calculation rule: If (abs(lastCapturedValue - newValue) > dead_band_value) capture(newValue).\n      # dead_band_value = 0.0\n\n      ## The conditions on which a sample should be captured and thus will be sent as a message. (default: \"StatusValue\")\n      ## Possible values:\n      ## - \"Status\"\n      ##   Capture the value only, when the state of the node changes from or to error state. Value changes are ignored.\n      ## - \"StatusValue\" \n      ##   Capture when the value changes or the node changes from or to error state.\n      ##   See also 'dead_band_value' for what is considered as a value change.\n      ## - \"StatusValueTimestamp\": \n      ##   Capture even if the value is the same, but the timestamp of the value is newer.\n      ##   Note: This might lead to high load on the network because every sample will be sent as a message\n      ##   even if the value of the node did not change.\n      # value_change = \"StatusValue\"\n      \n"
  },
  {
    "path": "plugins/inputs/dcos/README.md",
    "content": "# Mesosphere Distributed Cloud OS Input Plugin\n\nThis input plugin gathers metrics from a [Distributed Cloud OS][dcos] cluster's\n[metrics component][metrics].\n\n> [!WARNING]\n> Depending on the workload of your DC/OS cluster, this plugin can quickly\n> create a high number of series which, when unchecked, can cause high load on\n> your database!\n\n⭐ Telegraf v1.5.0\n🏷️ containers\n💻 all\n\n[dcos]: https://dcos.io/\n[metrics]: https://docs.mesosphere.com/1.10/metrics/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Input plugin for DC/OS metrics\n[[inputs.dcos]]\n  ## The DC/OS cluster URL.\n  cluster_url = \"https://dcos-master-1\"\n\n  ## The ID of the service account.\n  service_account_id = \"telegraf\"\n  ## The private key file for the service account.\n  service_account_private_key = \"/etc/telegraf/telegraf-sa-key.pem\"\n\n  ## Path containing login token.  If set, will read on every gather.\n  # token_file = \"/home/dcos/.dcos/token\"\n\n  ## In all filter options if both include and exclude are empty all items\n  ## will be collected.  Arrays may contain glob patterns.\n  ##\n  ## Node IDs to collect metrics from.  If a node is excluded, no metrics will\n  ## be collected for its containers or apps.\n  # node_include = []\n  # node_exclude = []\n  ## Container IDs to collect container metrics from.\n  # container_include = []\n  # container_exclude = []\n  ## Container IDs to collect app metrics from.\n  # app_include = []\n  # app_exclude = []\n\n  ## Maximum concurrent connections to the cluster.\n  # max_connections = 10\n  ## Maximum time to receive a response from cluster.\n  # response_timeout = \"20s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## If false, skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Recommended filtering to reduce series cardinality.\n  # [inputs.dcos.tagdrop]\n  #   path = [\"/var/lib/mesos/slave/slaves/*\"]\n```\n\n### Enterprise Authentication\n\nWhen using Enterprise DC/OS, it is recommended to use a service account to\nauthenticate with the cluster.\n\nThe plugin requires the following permissions:\n\n```text\ndcos:adminrouter:ops:system-metrics full\ndcos:adminrouter:ops:mesos full\n```\n\nFollow the directions to [create a service account and assign permissions][1].\n\nQuick configuration using the Enterprise CLI:\n\n```text\ndcos security org service-accounts keypair telegraf-sa-key.pem telegraf-sa-cert.pem\ndcos security org service-accounts create -p telegraf-sa-cert.pem -d \"Telegraf DC/OS input plugin\" telegraf\ndcos security org users grant telegraf dcos:adminrouter:ops:system-metrics full\ndcos security org users grant telegraf dcos:adminrouter:ops:mesos full\n```\n\n[1]: https://docs.mesosphere.com/1.10/security/service-auth/custom-service-auth/\n\n### Open Source Authentication\n\nThe Open Source DC/OS does not provide service accounts.  Instead you can use\nof the following options:\n\n1. [Disable authentication](https://dcos.io/docs/1.10/security/managing-authentication/#authentication-opt-out)\n2. Use the `token_file` parameter to read a authentication token from a file.\n\nThen `token_file` can be set by using the [dcos cli] to login periodically.\nThe cli can login for at most XXX days, you will need to ensure the cli\nperforms a new login before this time expires.\n\n```shell\ndcos auth login --username foo --password bar\ndcos config show core.dcos_acs_token > ~/.dcos/token\n```\n\nAnother option to create a `token_file` is to generate a token using the\ncluster secret.  This will allow you to set the expiration date manually or\neven create a never expiring token.  However, if the cluster secret or the\ntoken is compromised it cannot be revoked and may require a full reinstall of\nthe cluster.  For more information on this technique reference\n[this blog post][2].\n\n[2]: https://medium.com/@richardgirges/authenticating-open-source-dc-os-with-third-party-services-125fa33a5add\n\n### Series Cardinality Mitigation\n\n- Use [measurement filtering](/docs/CONFIGURATION.md#metric-filtering)to exclude\nunnecessary tags.\n- Write to a database with an appropriate\n  [retention policy](https://docs.influxdata.com/influxdb/latest/guides/downsampling_and_retention/).\n- Consider using the\n  [Time Series Index](https://docs.influxdata.com/influxdb/latest/concepts/time-series-index/).\n- Monitor your databases'\n  [series cardinality](https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality).\n\n## Metrics\n\nPlease consult the [Metrics Reference][3] for details about field\ninterpretation.\n\n- dcos_node\n  - tags:\n    - cluster\n    - hostname\n    - path (filesystem fields only)\n    - interface (network fields only)\n  - fields:\n    - system_uptime (float)\n    - cpu_cores (float)\n    - cpu_total (float)\n    - cpu_user (float)\n    - cpu_system (float)\n    - cpu_idle (float)\n    - cpu_wait (float)\n    - load_1min (float)\n    - load_5min (float)\n    - load_15min (float)\n    - filesystem_capacity_total_bytes (int)\n    - filesystem_capacity_used_bytes (int)\n    - filesystem_capacity_free_bytes (int)\n    - filesystem_inode_total (float)\n    - filesystem_inode_used (float)\n    - filesystem_inode_free (float)\n    - memory_total_bytes (int)\n    - memory_free_bytes (int)\n    - memory_buffers_bytes (int)\n    - memory_cached_bytes (int)\n    - swap_total_bytes (int)\n    - swap_free_bytes (int)\n    - swap_used_bytes (int)\n    - network_in_bytes (int)\n    - network_out_bytes (int)\n    - network_in_packets (float)\n    - network_out_packets (float)\n    - network_in_dropped (float)\n    - network_out_dropped (float)\n    - network_in_errors (float)\n    - network_out_errors (float)\n    - process_count (float)\n\n- dcos_container\n  - tags:\n    - cluster\n    - hostname\n    - container_id\n    - task_name\n  - fields:\n    - cpus_limit (float)\n    - cpus_system_time (float)\n    - cpus_throttled_time (float)\n    - cpus_user_time (float)\n    - disk_limit_bytes (int)\n    - disk_used_bytes (int)\n    - mem_limit_bytes (int)\n    - mem_total_bytes (int)\n    - net_rx_bytes (int)\n    - net_rx_dropped (float)\n    - net_rx_errors (float)\n    - net_rx_packets (float)\n    - net_tx_bytes (int)\n    - net_tx_dropped (float)\n    - net_tx_errors (float)\n    - net_tx_packets (float)\n\n- dcos_app\n  - tags:\n    - cluster\n    - hostname\n    - container_id\n    - task_name\n  - fields:\n    - fields are application specific\n\n[3]: https://docs.mesosphere.com/1.10/metrics/reference/\n\n## Example Output\n\n```text\ndcos_node,cluster=enterprise,hostname=192.168.122.18,path=/boot filesystem_capacity_free_bytes=918188032i,filesystem_capacity_total_bytes=1063256064i,filesystem_capacity_used_bytes=145068032i,filesystem_inode_free=523958,filesystem_inode_total=524288,filesystem_inode_used=330 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=dummy0 network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=0i,network_out_dropped=0,network_out_errors=0,network_out_packets=0 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=docker0 network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=0i,network_out_dropped=0,network_out_errors=0,network_out_packets=0 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18 cpu_cores=2,cpu_idle=81.62,cpu_system=4.19,cpu_total=13.670000000000002,cpu_user=9.48,cpu_wait=0,load_15min=0.7,load_1min=0.22,load_5min=0.6,memory_buffers_bytes=970752i,memory_cached_bytes=1830473728i,memory_free_bytes=1178636288i,memory_total_bytes=3975073792i,process_count=198,swap_free_bytes=859828224i,swap_total_bytes=859828224i,swap_used_bytes=0i,system_uptime=18874 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=lo network_in_bytes=1090992450i,network_in_dropped=0,network_in_errors=0,network_in_packets=1546938,network_out_bytes=1090992450i,network_out_dropped=0,network_out_errors=0,network_out_packets=1546938 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,path=/ filesystem_capacity_free_bytes=1668378624i,filesystem_capacity_total_bytes=6641680384i,filesystem_capacity_used_bytes=4973301760i,filesystem_inode_free=3107856,filesystem_inode_total=3248128,filesystem_inode_used=140272 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=minuteman network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=210i,network_out_dropped=0,network_out_errors=0,network_out_packets=3 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=eth0 network_in_bytes=539886216i,network_in_dropped=1,network_in_errors=0,network_in_packets=979808,network_out_bytes=112395836i,network_out_dropped=0,network_out_errors=0,network_out_packets=891239 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=spartan network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=210i,network_out_dropped=0,network_out_errors=0,network_out_packets=3 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,path=/var/lib/docker/overlay filesystem_capacity_free_bytes=1668378624i,filesystem_capacity_total_bytes=6641680384i,filesystem_capacity_used_bytes=4973301760i,filesystem_inode_free=3107856,filesystem_inode_total=3248128,filesystem_inode_used=140272 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=vtep1024 network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=0i,network_out_dropped=0,network_out_errors=0,network_out_packets=0 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,path=/var/lib/docker/plugins filesystem_capacity_free_bytes=1668378624i,filesystem_capacity_total_bytes=6641680384i,filesystem_capacity_used_bytes=4973301760i,filesystem_inode_free=3107856,filesystem_inode_total=3248128,filesystem_inode_used=140272 1511859222000000000\ndcos_node,cluster=enterprise,hostname=192.168.122.18,interface=d-dcos network_in_bytes=0i,network_in_dropped=0,network_in_errors=0,network_in_packets=0,network_out_bytes=0i,network_out_dropped=0,network_out_errors=0,network_out_packets=0 1511859222000000000\ndcos_app,cluster=enterprise,container_id=9a78d34a-3bbf-467e-81cf-a57737f154ee,hostname=192.168.122.18 container_received_bytes_per_sec=0,container_throttled_bytes_per_sec=0 1511859222000000000\ndcos_container,cluster=enterprise,container_id=cbf19b77-3b8d-4bcf-b81f-824b67279629,hostname=192.168.122.18 cpus_limit=0.3,cpus_system_time=307.31,cpus_throttled_time=102.029930607,cpus_user_time=268.57,disk_limit_bytes=268435456i,disk_used_bytes=30953472i,mem_limit_bytes=570425344i,mem_total_bytes=13316096i,net_rx_bytes=0i,net_rx_dropped=0,net_rx_errors=0,net_rx_packets=0,net_tx_bytes=0i,net_tx_dropped=0,net_tx_errors=0,net_tx_packets=0 1511859222000000000\ndcos_app,cluster=enterprise,container_id=cbf19b77-3b8d-4bcf-b81f-824b67279629,hostname=192.168.122.18 container_received_bytes_per_sec=0,container_throttled_bytes_per_sec=0 1511859222000000000\ndcos_container,cluster=enterprise,container_id=5725e219-f66e-40a8-b3ab-519d85f4c4dc,hostname=192.168.122.18,task_name=hello-world cpus_limit=0.6,cpus_system_time=25.6,cpus_throttled_time=327.977109217,cpus_user_time=566.54,disk_limit_bytes=0i,disk_used_bytes=0i,mem_limit_bytes=1107296256i,mem_total_bytes=335941632i,net_rx_bytes=0i,net_rx_dropped=0,net_rx_errors=0,net_rx_packets=0,net_tx_bytes=0i,net_tx_dropped=0,net_tx_errors=0,net_tx_packets=0 1511859222000000000\ndcos_app,cluster=enterprise,container_id=5725e219-f66e-40a8-b3ab-519d85f4c4dc,hostname=192.168.122.18 container_received_bytes_per_sec=0,container_throttled_bytes_per_sec=0 1511859222000000000\ndcos_app,cluster=enterprise,container_id=c76e1488-4fb7-4010-a4cf-25725f8173f9,hostname=192.168.122.18 container_received_bytes_per_sec=0,container_throttled_bytes_per_sec=0 1511859222000000000\ndcos_container,cluster=enterprise,container_id=cbe0b2f9-061f-44ac-8f15-4844229e8231,hostname=192.168.122.18,task_name=telegraf cpus_limit=0.2,cpus_system_time=8.109999999,cpus_throttled_time=93.183916045,cpus_user_time=17.97,disk_limit_bytes=0i,disk_used_bytes=0i,mem_limit_bytes=167772160i,mem_total_bytes=0i,net_rx_bytes=0i,net_rx_dropped=0,net_rx_errors=0,net_rx_packets=0,net_tx_bytes=0i,net_tx_dropped=0,net_tx_errors=0,net_tx_packets=0 1511859222000000000\ndcos_container,cluster=enterprise,container_id=b64115de-3d2a-431d-a805-76e7c46453f1,hostname=192.168.122.18 cpus_limit=0.2,cpus_system_time=2.69,cpus_throttled_time=20.064861214,cpus_user_time=6.56,disk_limit_bytes=268435456i,disk_used_bytes=29360128i,mem_limit_bytes=297795584i,mem_total_bytes=13733888i,net_rx_bytes=0i,net_rx_dropped=0,net_rx_errors=0,net_rx_packets=0,net_tx_bytes=0i,net_tx_dropped=0,net_tx_errors=0,net_tx_packets=0 1511859222000000000\ndcos_app,cluster=enterprise,container_id=b64115de-3d2a-431d-a805-76e7c46453f1,hostname=192.168.122.18 container_received_bytes_per_sec=0,container_throttled_bytes_per_sec=0 1511859222000000000\n```\n"
  },
  {
    "path": "plugins/inputs/dcos/client.go",
    "content": "package dcos\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nconst (\n\t// How long to stayed logged in for\n\tloginDuration = 65 * time.Minute\n)\n\n// client is an interface for communicating with the DC/OS API.\ntype client interface {\n\tsetToken(token string)\n\n\tlogin(ctx context.Context, sa *serviceAccount) (*authToken, error)\n\tgetSummary(ctx context.Context) (*summary, error)\n\tgetContainers(ctx context.Context, node string) ([]container, error)\n\tgetNodeMetrics(ctx context.Context, node string) (*metrics, error)\n\tgetContainerMetrics(ctx context.Context, node, container string) (*metrics, error)\n\tgetAppMetrics(ctx context.Context, node, container string) (*metrics, error)\n}\n\ntype apiError struct {\n\turl         string\n\tstatusCode  int\n\ttitle       string\n\tdescription string\n}\n\n// login is request data for logging in.\ntype login struct {\n\tUID   string `json:\"uid\"`\n\tExp   int64  `json:\"exp\"`\n\tToken string `json:\"token\"`\n}\n\n// loginError is the response when login fails.\ntype loginError struct {\n\tTitle       string `json:\"title\"`\n\tDescription string `json:\"description\"`\n}\n\n// loginAuth is the response to a successful login.\ntype loginAuth struct {\n\tToken string `json:\"token\"`\n}\n\n// slave is a node in the cluster.\ntype slave struct {\n\tID string `json:\"id\"`\n}\n\n// summary provides high level cluster wide information.\ntype summary struct {\n\tCluster string\n\tSlaves  []slave\n}\n\n// container is a container on a node.\ntype container struct {\n\tID string\n}\n\ntype dataPoint struct {\n\tName  string            `json:\"name\"`\n\tTags  map[string]string `json:\"tags\"`\n\tUnit  string            `json:\"unit\"`\n\tValue float64           `json:\"value\"`\n}\n\n// metrics are the DCOS metrics\ntype metrics struct {\n\tDatapoints []dataPoint            `json:\"datapoints\"`\n\tDimensions map[string]interface{} `json:\"dimensions\"`\n}\n\n// authToken is the authentication token.\ntype authToken struct {\n\tText   string\n\tExpire time.Time\n}\n\n// clusterClient is a client that uses the cluster URL.\ntype clusterClient struct {\n\tclusterURL *url.URL\n\thttpClient *http.Client\n\ttoken      string\n\tsemaphore  chan struct{}\n}\n\ntype claims struct {\n\tUID string `json:\"uid\"`\n\tjwt.RegisteredClaims\n}\n\nfunc (e apiError) Error() string {\n\tif e.description != \"\" {\n\t\treturn fmt.Sprintf(\"[%s] %s: %s\", e.url, e.title, e.description)\n\t}\n\treturn fmt.Sprintf(\"[%s] %s\", e.url, e.title)\n}\n\nfunc newClusterClient(clusterURL *url.URL, timeout time.Duration, maxConns int, tlsConfig *tls.Config) *clusterClient {\n\thttpClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tMaxIdleConns:    maxConns,\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t\tTimeout: timeout,\n\t}\n\tsemaphore := make(chan struct{}, maxConns)\n\n\tc := &clusterClient{\n\t\tclusterURL: clusterURL,\n\t\thttpClient: httpClient,\n\t\tsemaphore:  semaphore,\n\t}\n\treturn c\n}\n\nfunc (c *clusterClient) setToken(token string) {\n\tc.token = token\n}\n\nfunc (c *clusterClient) login(ctx context.Context, sa *serviceAccount) (*authToken, error) {\n\ttoken, err := createLoginToken(sa)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\texp := time.Now().Add(loginDuration)\n\n\tbody := &login{\n\t\tUID:   sa.accountID,\n\t\tExp:   exp.Unix(),\n\t\tToken: token,\n\t}\n\n\toctets, err := json.Marshal(body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tloc := c.toURL(\"/acs/api/v1/auth/login\")\n\treq, err := http.NewRequest(\"POST\", loc, bytes.NewBuffer(octets))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\treq = req.WithContext(ctx)\n\tresp, err := c.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusOK {\n\t\tauth := &loginAuth{}\n\t\tdec := json.NewDecoder(resp.Body)\n\t\terr = dec.Decode(auth)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\ttoken := &authToken{\n\t\t\tText:   auth.Token,\n\t\t\tExpire: exp,\n\t\t}\n\t\treturn token, nil\n\t}\n\n\tloginError := &loginError{}\n\tdec := json.NewDecoder(resp.Body)\n\terr = dec.Decode(loginError)\n\tif err != nil {\n\t\terr := &apiError{\n\t\t\turl:        loc,\n\t\t\tstatusCode: resp.StatusCode,\n\t\t\ttitle:      resp.Status,\n\t\t}\n\t\treturn nil, err\n\t}\n\n\terr = &apiError{\n\t\turl:         loc,\n\t\tstatusCode:  resp.StatusCode,\n\t\ttitle:       loginError.Title,\n\t\tdescription: loginError.Description,\n\t}\n\treturn nil, err\n}\n\nfunc (c *clusterClient) getSummary(ctx context.Context) (*summary, error) {\n\tsummary := &summary{}\n\terr := c.doGet(ctx, c.toURL(\"/mesos/master/state-summary\"), summary)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn summary, nil\n}\n\nfunc (c *clusterClient) getContainers(ctx context.Context, node string) ([]container, error) {\n\tlist := make([]string, 0)\n\terr := c.doGet(ctx, c.toURL(fmt.Sprintf(\"/system/v1/agent/%s/metrics/v0/containers\", node)), &list)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcontainers := make([]container, 0, len(list))\n\tfor _, c := range list {\n\t\tcontainers = append(containers, container{ID: c})\n\t}\n\n\treturn containers, nil\n}\n\nfunc (c *clusterClient) getMetrics(ctx context.Context, address string) (*metrics, error) {\n\tmetrics := &metrics{}\n\n\terr := c.doGet(ctx, address, metrics)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn metrics, nil\n}\n\nfunc (c *clusterClient) getNodeMetrics(ctx context.Context, node string) (*metrics, error) {\n\tpath := fmt.Sprintf(\"/system/v1/agent/%s/metrics/v0/node\", node)\n\treturn c.getMetrics(ctx, c.toURL(path))\n}\n\nfunc (c *clusterClient) getContainerMetrics(ctx context.Context, node, container string) (*metrics, error) {\n\tpath := fmt.Sprintf(\"/system/v1/agent/%s/metrics/v0/containers/%s\", node, container)\n\treturn c.getMetrics(ctx, c.toURL(path))\n}\n\nfunc (c *clusterClient) getAppMetrics(ctx context.Context, node, container string) (*metrics, error) {\n\tpath := fmt.Sprintf(\"/system/v1/agent/%s/metrics/v0/containers/%s/app\", node, container)\n\treturn c.getMetrics(ctx, c.toURL(path))\n}\n\nfunc createGetRequest(address, token string) (*http.Request, error) {\n\treq, err := http.NewRequest(\"GET\", address, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif token != \"\" {\n\t\treq.Header.Add(\"Authorization\", \"token=\"+token)\n\t}\n\treq.Header.Add(\"Accept\", \"application/json\")\n\n\treturn req, nil\n}\n\nfunc (c *clusterClient) doGet(ctx context.Context, address string, v interface{}) error {\n\treq, err := createGetRequest(address, c.token)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase c.semaphore <- struct{}{}:\n\t\tbreak\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\tresp, err := c.httpClient.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\t<-c.semaphore\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tresp.Body.Close()\n\t\t<-c.semaphore\n\t}()\n\n\t// Clear invalid token if unauthorized\n\tif resp.StatusCode == http.StatusUnauthorized {\n\t\tc.token = \"\"\n\t}\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn &apiError{\n\t\t\turl:        address,\n\t\t\tstatusCode: resp.StatusCode,\n\t\t\ttitle:      resp.Status,\n\t\t}\n\t}\n\n\tif resp.StatusCode == http.StatusNoContent {\n\t\treturn nil\n\t}\n\n\terr = json.NewDecoder(resp.Body).Decode(v)\n\treturn err\n}\n\nfunc (c *clusterClient) toURL(path string) string {\n\tclusterURL := *c.clusterURL\n\tclusterURL.Path = path\n\treturn clusterURL.String()\n}\n\nfunc createLoginToken(sa *serviceAccount) (string, error) {\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims{\n\t\tUID: sa.accountID,\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\t// How long we have to login with this token\n\t\t\tExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 5)),\n\t\t},\n\t})\n\treturn token.SignedString(sa.privateKey)\n}\n"
  },
  {
    "path": "plugins/inputs/dcos/client_test.go",
    "content": "package dcos\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar privateKey = testutil.NewPKI(\"../../../testutil/pki\").ReadServerKey()\n\nfunc TestLogin(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tvar tests = []struct {\n\t\tname          string\n\t\tresponseCode  int\n\t\tresponseBody  string\n\t\texpectedError error\n\t\texpectedToken string\n\t}{\n\t\t{\n\t\t\tname:          \"Login successful\",\n\t\t\tresponseCode:  http.StatusOK,\n\t\t\tresponseBody:  `{\"token\": \"XXX.YYY.ZZZ\"}`,\n\t\t\texpectedError: nil,\n\t\t\texpectedToken: \"XXX.YYY.ZZZ\",\n\t\t},\n\t\t{\n\t\t\tname:         \"Unauthorized Error\",\n\t\t\tresponseCode: http.StatusUnauthorized,\n\t\t\tresponseBody: `{\"title\": \"x\", \"description\": \"y\"}`,\n\t\t\texpectedError: &apiError{\n\t\t\t\turl:         ts.URL + \"/acs/api/v1/auth/login\",\n\t\t\t\tstatusCode:  http.StatusUnauthorized,\n\t\t\t\ttitle:       \"x\",\n\t\t\t\tdescription: \"y\",\n\t\t\t},\n\t\t\texpectedToken: \"\",\n\t\t},\n\t}\n\n\tkey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(tt.responseCode)\n\t\t\t\tfmt.Fprintln(w, tt.responseBody)\n\t\t\t})\n\n\t\t\tu, err := url.Parse(ts.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tsa := &serviceAccount{\n\t\t\t\taccountID:  \"telegraf\",\n\t\t\t\tprivateKey: key,\n\t\t\t}\n\t\t\tclient := newClusterClient(u, defaultResponseTimeout, 1, nil)\n\t\t\tauth, err := client.login(t.Context(), sa)\n\n\t\t\trequire.Equal(t, tt.expectedError, err)\n\n\t\t\tif tt.expectedToken != \"\" {\n\t\t\t\trequire.Equal(t, tt.expectedToken, auth.Text)\n\t\t\t} else {\n\t\t\t\trequire.Nil(t, auth)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetSummary(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tvar tests = []struct {\n\t\tname          string\n\t\tresponseCode  int\n\t\tresponseBody  string\n\t\texpectedValue *summary\n\t\texpectedError error\n\t}{\n\t\t{\n\t\t\tname:          \"No nodes\",\n\t\t\tresponseCode:  http.StatusOK,\n\t\t\tresponseBody:  `{\"cluster\": \"a\", \"slaves\": []}`,\n\t\t\texpectedValue: &summary{Cluster: \"a\", Slaves: make([]slave, 0)},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:          \"Unauthorized Error\",\n\t\t\tresponseCode:  http.StatusUnauthorized,\n\t\t\tresponseBody:  `<html></html>`,\n\t\t\texpectedValue: nil,\n\t\t\texpectedError: &apiError{\n\t\t\t\turl:        ts.URL + \"/mesos/master/state-summary\",\n\t\t\t\tstatusCode: http.StatusUnauthorized,\n\t\t\t\ttitle:      \"401 Unauthorized\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"Has nodes\",\n\t\t\tresponseCode: http.StatusOK,\n\t\t\tresponseBody: `{\"cluster\": \"a\", \"slaves\": [{\"id\": \"a\"}, {\"id\": \"b\"}]}`,\n\t\t\texpectedValue: &summary{\n\t\t\t\tCluster: \"a\",\n\t\t\t\tSlaves: []slave{\n\t\t\t\t\t{ID: \"a\"},\n\t\t\t\t\t{ID: \"b\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t// check the path\n\t\t\t\tw.WriteHeader(tt.responseCode)\n\t\t\t\tfmt.Fprintln(w, tt.responseBody)\n\t\t\t})\n\n\t\t\tu, err := url.Parse(ts.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tclient := newClusterClient(u, defaultResponseTimeout, 1, nil)\n\t\t\tsummary, err := client.getSummary(t.Context())\n\n\t\t\trequire.Equal(t, tt.expectedError, err)\n\t\t\trequire.Equal(t, tt.expectedValue, summary)\n\t\t})\n\t}\n}\n\nfunc TestGetNodeMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tvar tests = []struct {\n\t\tname          string\n\t\tresponseCode  int\n\t\tresponseBody  string\n\t\texpectedValue *metrics\n\t\texpectedError error\n\t}{\n\t\t{\n\t\t\tname:          \"Empty Body\",\n\t\t\tresponseCode:  http.StatusOK,\n\t\t\tresponseBody:  `{}`,\n\t\t\texpectedValue: &metrics{},\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t// check the path\n\t\t\t\tw.WriteHeader(tt.responseCode)\n\t\t\t\tfmt.Fprintln(w, tt.responseBody)\n\t\t\t})\n\n\t\t\tu, err := url.Parse(ts.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tclient := newClusterClient(u, defaultResponseTimeout, 1, nil)\n\t\t\tm, err := client.getNodeMetrics(t.Context(), \"foo\")\n\n\t\t\trequire.Equal(t, tt.expectedError, err)\n\t\t\trequire.Equal(t, tt.expectedValue, m)\n\t\t})\n\t}\n}\n\nfunc TestGetContainerMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tvar tests = []struct {\n\t\tname          string\n\t\tresponseCode  int\n\t\tresponseBody  string\n\t\texpectedValue *metrics\n\t\texpectedError error\n\t}{\n\t\t{\n\t\t\tname:          \"204 No Content\",\n\t\t\tresponseCode:  http.StatusNoContent,\n\t\t\tresponseBody:  ``,\n\t\t\texpectedValue: &metrics{},\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t// check the path\n\t\t\t\tw.WriteHeader(tt.responseCode)\n\t\t\t\tfmt.Fprintln(w, tt.responseBody)\n\t\t\t})\n\n\t\t\tu, err := url.Parse(ts.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tclient := newClusterClient(u, defaultResponseTimeout, 1, nil)\n\t\t\tm, err := client.getContainerMetrics(t.Context(), \"foo\", \"bar\")\n\n\t\t\trequire.Equal(t, tt.expectedError, err)\n\t\t\trequire.Equal(t, tt.expectedValue, m)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/dcos/creds.go",
    "content": "package dcos\n\nimport (\n\t\"context\"\n\t\"crypto/rsa\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n)\n\nconst (\n\t// How long before expiration to renew token\n\trelogDuration = 5 * time.Minute\n)\n\ntype credentials interface {\n\ttoken(ctx context.Context, client client) (string, error)\n\tisExpired() bool\n}\n\ntype serviceAccount struct {\n\taccountID  string\n\tprivateKey *rsa.PrivateKey\n\n\tauth *authToken\n}\n\ntype tokenCreds struct {\n\tPath string\n}\n\ntype nullCreds struct {\n}\n\nfunc (c *serviceAccount) token(ctx context.Context, client client) (string, error) {\n\tauth, err := client.login(ctx, c)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tc.auth = auth\n\treturn auth.Text, nil\n}\n\nfunc (c *serviceAccount) isExpired() bool {\n\treturn c.auth.Text != \"\" || c.auth.Expire.Add(relogDuration).After(time.Now())\n}\n\nfunc (c *tokenCreds) token(_ context.Context, _ client) (string, error) {\n\toctets, err := os.ReadFile(c.Path)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error reading token file %q: %w\", c.Path, err)\n\t}\n\tif !utf8.Valid(octets) {\n\t\treturn \"\", fmt.Errorf(\"token file does not contain utf-8 encoded text: %s\", c.Path)\n\t}\n\ttoken := strings.TrimSpace(string(octets))\n\treturn token, nil\n}\n\nfunc (*tokenCreds) isExpired() bool {\n\treturn true\n}\n\nfunc (*nullCreds) token(context.Context, client) (string, error) {\n\treturn \"\", nil\n}\n\nfunc (*nullCreds) isExpired() bool {\n\treturn true\n}\n"
  },
  {
    "path": "plugins/inputs/dcos/dcos.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage dcos\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"net/url\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tnodeDimensions = []string{\n\t\t\"hostname\",\n\t\t\"path\",\n\t\t\"interface\",\n\t}\n\tcontainerDimensions = []string{\n\t\t\"hostname\",\n\t\t\"container_id\",\n\t\t\"task_name\",\n\t}\n\tappDimensions = []string{\n\t\t\"hostname\",\n\t\t\"container_id\",\n\t\t\"task_name\",\n\t}\n)\n\nconst (\n\tdefaultMaxConnections  = 10\n\tdefaultResponseTimeout = 20 * time.Second\n)\n\ntype DCOS struct {\n\tClusterURL string `toml:\"cluster_url\"`\n\n\tServiceAccountID         string `toml:\"service_account_id\"`\n\tServiceAccountPrivateKey string `toml:\"service_account_private_key\"`\n\n\tTokenFile string `toml:\"token_file\"`\n\n\tNodeInclude      []string `toml:\"node_include\"`\n\tNodeExclude      []string `toml:\"node_exclude\"`\n\tContainerInclude []string `toml:\"container_include\"`\n\tContainerExclude []string `toml:\"container_exclude\"`\n\tAppInclude       []string `toml:\"app_include\"`\n\tAppExclude       []string `toml:\"app_exclude\"`\n\n\tMaxConnections  int             `toml:\"max_connections\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\ttls.ClientConfig\n\n\tclient client\n\tcreds  credentials\n\n\tinitialized     bool\n\tnodeFilter      filter.Filter\n\tcontainerFilter filter.Filter\n\tappFilter       filter.Filter\n}\n\ntype point struct {\n\ttags   map[string]string\n\tlabels map[string]string\n\tfields map[string]interface{}\n}\n\nfunc (*DCOS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *DCOS) Gather(acc telegraf.Accumulator) error {\n\terr := d.initialize()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tctx := context.Background()\n\n\ttoken, err := d.creds.token(ctx, d.client)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.client.setToken(token)\n\n\tsummary, err := d.client.getSummary(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, node := range summary.Slaves {\n\t\twg.Add(1)\n\t\tgo func(node string) {\n\t\t\tdefer wg.Done()\n\t\t\td.gatherNode(ctx, acc, summary.Cluster, node)\n\t\t}(node.ID)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (d *DCOS) gatherNode(ctx context.Context, acc telegraf.Accumulator, cluster, node string) {\n\tif !d.nodeFilter.Match(node) {\n\t\treturn\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tm, err := d.client.getNodeMetrics(ctx, node)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\treturn\n\t\t}\n\t\taddNodeMetrics(acc, cluster, m)\n\t}()\n\n\td.gatherContainers(ctx, acc, cluster, node)\n\twg.Wait()\n}\n\nfunc (d *DCOS) gatherContainers(ctx context.Context, acc telegraf.Accumulator, cluster, node string) {\n\tcontainers, err := d.client.getContainers(ctx, node)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, container := range containers {\n\t\tif d.containerFilter.Match(container.ID) {\n\t\t\twg.Add(1)\n\t\t\tgo func(container string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tm, err := d.client.getContainerMetrics(ctx, node, container)\n\t\t\t\tif err != nil {\n\t\t\t\t\tvar apiErr apiError\n\t\t\t\t\tif errors.As(err, &apiErr) && apiErr.statusCode == 404 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\taddContainerMetrics(acc, cluster, m)\n\t\t\t}(container.ID)\n\t\t}\n\n\t\tif d.appFilter.Match(container.ID) {\n\t\t\twg.Add(1)\n\t\t\tgo func(container string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tm, err := d.client.getAppMetrics(ctx, node, container)\n\t\t\t\tif err != nil {\n\t\t\t\t\tvar apiErr apiError\n\t\t\t\t\tif errors.As(err, &apiErr) && apiErr.statusCode == 404 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\taddAppMetrics(acc, cluster, m)\n\t\t\t}(container.ID)\n\t\t}\n\t}\n\twg.Wait()\n}\n\nfunc createPoints(m *metrics) []*point {\n\tpoints := make(map[string]*point)\n\tfor _, dp := range m.Datapoints {\n\t\tfieldKey := strings.ReplaceAll(dp.Name, \".\", \"_\")\n\n\t\ttags := dp.Tags\n\t\tif tags == nil {\n\t\t\ttags = make(map[string]string)\n\t\t}\n\n\t\tif dp.Unit == \"bytes\" && !strings.HasSuffix(fieldKey, \"_bytes\") {\n\t\t\tfieldKey = fieldKey + \"_bytes\"\n\t\t}\n\n\t\tfieldKey = strings.TrimPrefix(fieldKey, \"dcos_metrics_module_\")\n\n\t\ttagset := make([]string, 0, len(tags))\n\t\tfor k, v := range tags {\n\t\t\ttagset = append(tagset, k+\"=\"+v)\n\t\t}\n\t\tsort.Strings(tagset)\n\t\tseriesParts := make([]string, 0, len(tagset))\n\t\tseriesParts = append(seriesParts, tagset...)\n\t\tseriesKey := strings.Join(seriesParts, \",\")\n\n\t\tp, ok := points[seriesKey]\n\t\tif !ok {\n\t\t\tp = &point{}\n\t\t\tp.tags = tags\n\t\t\tp.labels = make(map[string]string)\n\t\t\tp.fields = make(map[string]interface{})\n\t\t\tpoints[seriesKey] = p\n\t\t}\n\n\t\tif dp.Unit == \"bytes\" {\n\t\t\tp.fields[fieldKey] = int64(dp.Value)\n\t\t} else {\n\t\t\tp.fields[fieldKey] = dp.Value\n\t\t}\n\t}\n\n\tresults := make([]*point, 0, len(points))\n\tfor _, p := range points {\n\t\tfor k, v := range m.Dimensions {\n\t\t\tswitch v := v.(type) {\n\t\t\tcase string:\n\t\t\t\tp.tags[k] = v\n\t\t\tcase map[string]string:\n\t\t\t\tif k == \"labels\" {\n\t\t\t\t\tfor k, v := range v {\n\t\t\t\t\t\tp.labels[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tresults = append(results, p)\n\t}\n\treturn results\n}\n\nfunc addMetrics(acc telegraf.Accumulator, cluster, mname string, m *metrics, tagDimensions []string) {\n\ttm := time.Now()\n\n\tpoints := createPoints(m)\n\n\tfor _, p := range points {\n\t\ttags := make(map[string]string)\n\t\ttags[\"cluster\"] = cluster\n\t\tfor _, tagkey := range tagDimensions {\n\t\t\tv, ok := p.tags[tagkey]\n\t\t\tif ok {\n\t\t\t\ttags[tagkey] = v\n\t\t\t}\n\t\t}\n\t\tfor k, v := range p.labels {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\tacc.AddFields(mname, p.fields, tags, tm)\n\t}\n}\n\nfunc addNodeMetrics(acc telegraf.Accumulator, cluster string, m *metrics) {\n\taddMetrics(acc, cluster, \"dcos_node\", m, nodeDimensions)\n}\n\nfunc addContainerMetrics(acc telegraf.Accumulator, cluster string, m *metrics) {\n\taddMetrics(acc, cluster, \"dcos_container\", m, containerDimensions)\n}\n\nfunc addAppMetrics(acc telegraf.Accumulator, cluster string, m *metrics) {\n\taddMetrics(acc, cluster, \"dcos_app\", m, appDimensions)\n}\n\nfunc (d *DCOS) initialize() error {\n\tif !d.initialized {\n\t\terr := d.createFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif d.client == nil {\n\t\t\tclient, err := d.createClient()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\td.client = client\n\t\t}\n\n\t\tif d.creds == nil {\n\t\t\tcreds, err := d.createCredentials()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\td.creds = creds\n\t\t}\n\n\t\td.initialized = true\n\t}\n\treturn nil\n}\n\nfunc (d *DCOS) createClient() (client, error) {\n\ttlsCfg, err := d.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taddress, err := url.Parse(d.ClusterURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := newClusterClient(\n\t\taddress,\n\t\ttime.Duration(d.ResponseTimeout),\n\t\td.MaxConnections,\n\t\ttlsCfg,\n\t)\n\n\treturn client, nil\n}\n\nfunc (d *DCOS) createCredentials() (credentials, error) {\n\tif d.ServiceAccountID != \"\" && d.ServiceAccountPrivateKey != \"\" {\n\t\tbs, err := os.ReadFile(d.ServiceAccountPrivateKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tprivateKey, err := jwt.ParseRSAPrivateKeyFromPEM(bs)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcreds := &serviceAccount{\n\t\t\taccountID:  d.ServiceAccountID,\n\t\t\tprivateKey: privateKey,\n\t\t}\n\t\treturn creds, nil\n\t} else if d.TokenFile != \"\" {\n\t\tcreds := &tokenCreds{\n\t\t\tPath: d.TokenFile,\n\t\t}\n\t\treturn creds, nil\n\t}\n\n\treturn &nullCreds{}, nil\n}\n\nfunc (d *DCOS) createFilters() error {\n\tvar err error\n\td.nodeFilter, err = filter.NewIncludeExcludeFilter(\n\t\td.NodeInclude, d.NodeExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.containerFilter, err = filter.NewIncludeExcludeFilter(\n\t\td.ContainerInclude, d.ContainerExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.appFilter, err = filter.NewIncludeExcludeFilter(\n\t\td.AppInclude, d.AppExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"dcos\", func() telegraf.Input {\n\t\treturn &DCOS{\n\t\t\tMaxConnections:  defaultMaxConnections,\n\t\t\tResponseTimeout: config.Duration(defaultResponseTimeout),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dcos/dcos_test.go",
    "content": "package dcos\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockClient struct {\n\tSetTokenF            func()\n\tLoginF               func(ctx context.Context, sa *serviceAccount) (*authToken, error)\n\tGetSummaryF          func() (*summary, error)\n\tGetContainersF       func() ([]container, error)\n\tGetNodeMetricsF      func() (*metrics, error)\n\tGetContainerMetricsF func(ctx context.Context, node, container string) (*metrics, error)\n\tGetAppMetricsF       func(ctx context.Context, node, container string) (*metrics, error)\n}\n\nfunc (c *mockClient) setToken(string) {\n\tc.SetTokenF()\n}\n\nfunc (c *mockClient) login(ctx context.Context, sa *serviceAccount) (*authToken, error) {\n\treturn c.LoginF(ctx, sa)\n}\n\nfunc (c *mockClient) getSummary(context.Context) (*summary, error) {\n\treturn c.GetSummaryF()\n}\n\nfunc (c *mockClient) getContainers(context.Context, string) ([]container, error) {\n\treturn c.GetContainersF()\n}\n\nfunc (c *mockClient) getNodeMetrics(context.Context, string) (*metrics, error) {\n\treturn c.GetNodeMetricsF()\n}\n\nfunc (c *mockClient) getContainerMetrics(ctx context.Context, node, container string) (*metrics, error) {\n\treturn c.GetContainerMetricsF(ctx, node, container)\n}\n\nfunc (c *mockClient) getAppMetrics(ctx context.Context, node, container string) (*metrics, error) {\n\treturn c.GetAppMetricsF(ctx, node, container)\n}\n\nfunc TestAddNodeMetrics(t *testing.T) {\n\tvar tests = []struct {\n\t\tname    string\n\t\tmetrics *metrics\n\t\tcheck   func(*testutil.Accumulator) []bool\n\t}{\n\t\t{\n\t\t\tname: \"basic datapoint conversion\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"process.count\",\n\t\t\t\t\t\tUnit:  \"count\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{acc.HasPoint(\n\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"cluster\": \"a\",\n\t\t\t\t\t},\n\t\t\t\t\t\"process_count\", 42.0,\n\t\t\t\t)}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"path added as tag\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"filesystem.inode.free\",\n\t\t\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\t\t\"path\": \"/var/lib\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tUnit:  \"count\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{acc.HasPoint(\n\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"cluster\": \"a\",\n\t\t\t\t\t\t\"path\":    \"/var/lib\",\n\t\t\t\t\t},\n\t\t\t\t\t\"filesystem_inode_free\", 42.0,\n\t\t\t\t)}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"interface added as tag\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"network.out.dropped\",\n\t\t\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\t\t\"interface\": \"eth0\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tUnit:  \"count\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{acc.HasPoint(\n\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"cluster\":   \"a\",\n\t\t\t\t\t\t\"interface\": \"eth0\",\n\t\t\t\t\t},\n\t\t\t\t\t\"network_out_dropped\", 42.0,\n\t\t\t\t)}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bytes unit appended to fieldkey\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"network.in\",\n\t\t\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\t\t\"interface\": \"eth0\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tUnit:  \"bytes\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{acc.HasPoint(\n\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"cluster\":   \"a\",\n\t\t\t\t\t\t\"interface\": \"eth0\",\n\t\t\t\t\t},\n\t\t\t\t\t\"network_in_bytes\", int64(42),\n\t\t\t\t)}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"dimensions added as tags\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"process.count\",\n\t\t\t\t\t\tTags:  map[string]string{},\n\t\t\t\t\t\tUnit:  \"count\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"memory.total\",\n\t\t\t\t\t\tTags:  map[string]string{},\n\t\t\t\t\t\tUnit:  \"bytes\",\n\t\t\t\t\t\tValue: 42,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tDimensions: map[string]interface{}{\n\t\t\t\t\t\"cluster_id\": \"c0760bbd-9e9d-434b-bd4a-39c7cdef8a63\",\n\t\t\t\t\t\"hostname\":   \"192.168.122.18\",\n\t\t\t\t\t\"mesos_id\":   \"2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\":  \"a\",\n\t\t\t\t\t\t\t\"hostname\": \"192.168.122.18\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"process_count\", 42.0),\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\":  \"a\",\n\t\t\t\t\t\t\t\"hostname\": \"192.168.122.18\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"memory_total_bytes\", int64(42)),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\taddNodeMetrics(&acc, \"a\", tt.metrics)\n\t\t\tfor i, ok := range tt.check(&acc) {\n\t\t\t\trequire.Truef(t, ok, \"Index was not true: %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestAddContainerMetrics(t *testing.T) {\n\tvar tests = []struct {\n\t\tname    string\n\t\tmetrics *metrics\n\t\tcheck   func(*testutil.Accumulator) []bool\n\t}{\n\t\t{\n\t\t\tname: \"container\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"net.rx.errors\",\n\t\t\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\t\t\"container_id\":  \"f25c457b-fceb-44f0-8f5b-38be34cbb6fb\",\n\t\t\t\t\t\t\t\"executor_id\":   \"telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a\",\n\t\t\t\t\t\t\t\"executor_name\": \"Command Executor (Task: telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a) (Command: NO EXECUTABLE)\",\n\t\t\t\t\t\t\t\"framework_id\":  \"ab2f3a8b-06db-4e8c-95b6-fb1940874a30-0001\",\n\t\t\t\t\t\t\t\"source\":        \"telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tUnit:  \"count\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tDimensions: map[string]interface{}{\n\t\t\t\t\t\"cluster_id\":          \"c0760bbd-9e9d-434b-bd4a-39c7cdef8a63\",\n\t\t\t\t\t\"container_id\":        \"f25c457b-fceb-44f0-8f5b-38be34cbb6fb\",\n\t\t\t\t\t\"executor_id\":         \"telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a\",\n\t\t\t\t\t\"framework_id\":        \"ab2f3a8b-06db-4e8c-95b6-fb1940874a30-0001\",\n\t\t\t\t\t\"framework_name\":      \"marathon\",\n\t\t\t\t\t\"framework_principal\": \"dcos_marathon\",\n\t\t\t\t\t\"framework_role\":      \"slave_public\",\n\t\t\t\t\t\"hostname\":            \"192.168.122.18\",\n\t\t\t\t\t\"labels\": map[string]string{\n\t\t\t\t\t\t\"DCOS_SPACE\": \"/telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\t\"mesos_id\":  \"2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1\",\n\t\t\t\t\t\"task_id\":   \"telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a\",\n\t\t\t\t\t\"task_name\": \"telegraf\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_container\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\":      \"a\",\n\t\t\t\t\t\t\t\"container_id\": \"f25c457b-fceb-44f0-8f5b-38be34cbb6fb\",\n\t\t\t\t\t\t\t\"hostname\":     \"192.168.122.18\",\n\t\t\t\t\t\t\t\"task_name\":    \"telegraf\",\n\t\t\t\t\t\t\t\"DCOS_SPACE\":   \"/telegraf\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"net_rx_errors\",\n\t\t\t\t\t\t42.0,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\taddContainerMetrics(&acc, \"a\", tt.metrics)\n\t\t\tfor i, ok := range tt.check(&acc) {\n\t\t\t\trequire.Truef(t, ok, \"Index was not true: %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestAddAppMetrics(t *testing.T) {\n\tvar tests = []struct {\n\t\tname    string\n\t\tmetrics *metrics\n\t\tcheck   func(*testutil.Accumulator) []bool\n\t}{\n\t\t{\n\t\t\tname: \"tags are optional\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"dcos.metrics.module.container_throttled_bytes_per_sec\",\n\t\t\t\t\t\tUnit:  \"\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_app\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\": \"a\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"container_throttled_bytes_per_sec\", 42.0,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"dimensions are tagged\",\n\t\t\tmetrics: &metrics{\n\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"dcos.metrics.module.container_throttled_bytes_per_sec\",\n\t\t\t\t\t\tUnit:  \"\",\n\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tDimensions: map[string]interface{}{\n\t\t\t\t\t\"cluster_id\":   \"c0760bbd-9e9d-434b-bd4a-39c7cdef8a63\",\n\t\t\t\t\t\"container_id\": \"02d31175-1c01-4459-8520-ef8b1339bc52\",\n\t\t\t\t\t\"hostname\":     \"192.168.122.18\",\n\t\t\t\t\t\"mesos_id\":     \"2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_app\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\":      \"a\",\n\t\t\t\t\t\t\t\"container_id\": \"02d31175-1c01-4459-8520-ef8b1339bc52\",\n\t\t\t\t\t\t\t\"hostname\":     \"192.168.122.18\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"container_throttled_bytes_per_sec\", 42.0,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\taddAppMetrics(&acc, \"a\", tt.metrics)\n\t\t\tfor i, ok := range tt.check(&acc) {\n\t\t\t\trequire.Truef(t, ok, \"Index was not true: %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGatherFilterNode(t *testing.T) {\n\tvar tests = []struct {\n\t\tname        string\n\t\tnodeInclude []string\n\t\tnodeExclude []string\n\t\tclient      client\n\t\tcheck       func(*testutil.Accumulator) []bool\n\t}{\n\t\t{\n\t\t\tname: \"cluster without nodes has no metrics\",\n\t\t\tclient: &mockClient{\n\t\t\t\tSetTokenF: func() {},\n\t\t\t\tGetSummaryF: func() (*summary, error) {\n\t\t\t\t\treturn &summary{\n\t\t\t\t\t\tCluster: \"a\",\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.NMetrics() == 0,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"node include\",\n\t\t\tnodeInclude: []string{\"x\"},\n\t\t\tclient: &mockClient{\n\t\t\t\tSetTokenF: func() {},\n\t\t\t\tGetSummaryF: func() (*summary, error) {\n\t\t\t\t\treturn &summary{\n\t\t\t\t\t\tCluster: \"a\",\n\t\t\t\t\t\tSlaves: []slave{\n\t\t\t\t\t\t\t{ID: \"x\"},\n\t\t\t\t\t\t\t{ID: \"y\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tGetContainersF: func() ([]container, error) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t},\n\t\t\t\tGetNodeMetricsF: func() (*metrics, error) {\n\t\t\t\t\treturn &metrics{\n\t\t\t\t\t\tDatapoints: []dataPoint{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:  \"value\",\n\t\t\t\t\t\t\t\tValue: 42.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDimensions: map[string]interface{}{\n\t\t\t\t\t\t\t\"hostname\": \"x\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(acc *testutil.Accumulator) []bool {\n\t\t\t\treturn []bool{\n\t\t\t\t\tacc.HasPoint(\n\t\t\t\t\t\t\"dcos_node\",\n\t\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\t\"cluster\":  \"a\",\n\t\t\t\t\t\t\t\"hostname\": \"x\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"value\", 42.0,\n\t\t\t\t\t),\n\t\t\t\t\tacc.NMetrics() == 1,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tdcos := &DCOS{\n\t\t\t\tNodeInclude: tt.nodeInclude,\n\t\t\t\tNodeExclude: tt.nodeExclude,\n\t\t\t\tclient:      tt.client,\n\t\t\t}\n\t\t\terr := dcos.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\t\t\tfor i, ok := range tt.check(&acc) {\n\t\t\t\trequire.Truef(t, ok, \"Index was not true: %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/dcos/sample.conf",
    "content": "# Input plugin for DC/OS metrics\n[[inputs.dcos]]\n  ## The DC/OS cluster URL.\n  cluster_url = \"https://dcos-master-1\"\n\n  ## The ID of the service account.\n  service_account_id = \"telegraf\"\n  ## The private key file for the service account.\n  service_account_private_key = \"/etc/telegraf/telegraf-sa-key.pem\"\n\n  ## Path containing login token.  If set, will read on every gather.\n  # token_file = \"/home/dcos/.dcos/token\"\n\n  ## In all filter options if both include and exclude are empty all items\n  ## will be collected.  Arrays may contain glob patterns.\n  ##\n  ## Node IDs to collect metrics from.  If a node is excluded, no metrics will\n  ## be collected for its containers or apps.\n  # node_include = []\n  # node_exclude = []\n  ## Container IDs to collect container metrics from.\n  # container_include = []\n  # container_exclude = []\n  ## Container IDs to collect app metrics from.\n  # app_include = []\n  # app_exclude = []\n\n  ## Maximum concurrent connections to the cluster.\n  # max_connections = 10\n  ## Maximum time to receive a response from cluster.\n  # response_timeout = \"20s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## If false, skip chain & host verification\n  # insecure_skip_verify = true\n\n  ## Recommended filtering to reduce series cardinality.\n  # [inputs.dcos.tagdrop]\n  #   path = [\"/var/lib/mesos/slave/slaves/*\"]\n"
  },
  {
    "path": "plugins/inputs/deprecations.go",
    "content": "package inputs\n\nimport \"github.com/influxdata/telegraf\"\n\n// Deprecations lists the deprecated plugins\nvar Deprecations = map[string]telegraf.DeprecationInfo{\n\t\"aerospike\": {\n\t\tSince:     \"1.30.0\",\n\t\tRemovalIn: \"1.40.0\",\n\t\tNotice:    \"use 'inputs.prometheus' with the Aerospike Prometheus Exporter instead\",\n\t},\n\t\"cassandra\": {\n\t\tSince:     \"1.7.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.jolokia2' with the 'cassandra.conf' example configuration instead\",\n\t},\n\t\"cisco_telemetry_gnmi\": {\n\t\tSince:     \"1.15.0\",\n\t\tRemovalIn: \"1.35.0\",\n\t\tNotice:    \"has been renamed to 'gnmi'\",\n\t},\n\t\"http_listener\": {\n\t\tSince:     \"1.9.0\",\n\t\tRemovalIn: \"1.35.0\",\n\t\tNotice:    \"has been renamed to 'influxdb_listener', use 'inputs.influxdb_listener' or 'inputs.http_listener_v2' instead\",\n\t},\n\t\"httpjson\": {\n\t\tSince:     \"1.6.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.http' instead\",\n\t},\n\t\"io\": {\n\t\tSince:     \"0.10.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.diskio' instead\",\n\t},\n\t\"jolokia\": {\n\t\tSince:     \"1.5.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.jolokia2' instead\",\n\t},\n\t\"kafka_consumer_legacy\": {\n\t\tSince:     \"1.4.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.kafka_consumer' instead, NOTE: 'kafka_consumer' only supports Kafka v0.8+\",\n\t},\n\t\"KNXListener\": {\n\t\tSince:     \"1.20.1\",\n\t\tRemovalIn: \"1.35.0\",\n\t\tNotice:    \"has been renamed to 'knx_listener'\",\n\t},\n\t\"logparser\": {\n\t\tSince:     \"1.15.0\",\n\t\tRemovalIn: \"1.35.0\",\n\t\tNotice:    \"use 'inputs.tail' with 'grok' data format instead\",\n\t},\n\t\"sflow\": {\n\t\tSince:     \"1.31.0\",\n\t\tRemovalIn: \"1.40.0\",\n\t\tNotice:    \"use 'inputs.netflow' instead\",\n\t},\n\t\"snmp_legacy\": {\n\t\tSince:     \"1.0.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.snmp' instead\",\n\t},\n\t\"tcp_listener\": {\n\t\tSince:     \"1.3.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.socket_listener' instead\",\n\t},\n\t\"udp_listener\": {\n\t\tSince:     \"1.3.0\",\n\t\tRemovalIn: \"1.30.0\",\n\t\tNotice:    \"use 'inputs.socket_listener' instead\",\n\t},\n}\n"
  },
  {
    "path": "plugins/inputs/directory_monitor/README.md",
    "content": "# Directory Monitor Input Plugin\n\nThis plugin monitors a single directory (traversing sub-directories), and\nprocesses each file placed in the directory. The plugin will gather all files in\nthe directory at the configured interval, and parse the ones that haven't been\npicked up yet.\n\n> [!NOTE]\n> Files should not be used by another process or the plugin may fail.\n> Furthermore, files should not be written _live_ to the monitored directory.\n> If you absolutely must write files directly, they must be guaranteed to finish\n> writing before `directory_duration_threshold`.\n\n⭐ Telegraf v1.18.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Ingests files in a directory and then moves them to a target directory.\n[[inputs.directory_monitor]]\n  ## The directory to monitor and read files from (including sub-directories if \"recursive\" is true).\n  directory = \"\"\n  #\n  ## The directory to move finished files to (maintaining directory hierarchy from source).\n  finished_directory = \"\"\n  #\n  ## Setting recursive to true will make the plugin recursively walk the directory and process all sub-directories.\n  # recursive = false\n  #\n  ## The directory to move files to upon file error.\n  ## If not provided, erroring files will stay in the monitored directory.\n  # error_directory = \"\"\n  #\n  ## The amount of time a file is allowed to sit in the directory before it is picked up.\n  ## This time can generally be low but if you choose to have a very large file written to the directory and it's potentially slow,\n  ## set this higher so that the plugin will wait until the file is fully copied to the directory.\n  # directory_duration_threshold = \"50ms\"\n  #\n  ## A list of the only file names to monitor, if necessary. Supports regex. If left blank, all files are ingested.\n  # files_to_monitor = [\"^.*\\\\.csv\"]\n  #\n  ## A list of files to ignore, if necessary. Supports regex.\n  # files_to_ignore = [\".DS_Store\"]\n  #\n  ## Maximum lines of the file to process that have not yet be written by the\n  ## output. For best throughput set to the size of the output's metric_buffer_limit.\n  ## Warning: setting this number higher than the output's metric_buffer_limit can cause dropped metrics.\n  # max_buffered_metrics = 10000\n  #\n  ## The maximum amount of file paths to queue up for processing at once, before waiting until files are processed to find more files.\n  ## Lowering this value will result in *slightly* less memory use, with a potential sacrifice in speed efficiency, if absolutely necessary.\n  # file_queue_size = 100000\n  #\n  ## Name a tag containing the name of the file the data was parsed from.  Leave empty\n  ## to disable. Cautious when file name variation is high, this can increase the cardinality\n  ## significantly. Read more about cardinality here:\n  ## https://docs.influxdata.com/influxdb/cloud/reference/glossary/#series-cardinality\n  # file_tag = \"\"\n  #\n  ## Specify if the file can be read completely at once or if it needs to be read line by line (default).\n  ## Possible values: \"line-by-line\", \"at-once\"\n  # parse_method = \"line-by-line\"\n  #\n  ## The dataformat to be read from the files.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n## Metrics\n\nThe format of metrics produced by this plugin depends on the content and data\nformat of the file.\n\nWhen the [internal][] input is enabled:\n\n- internal_directory_monitor\n  - fields:\n    - files_processed - How many files have been processed (counter)\n    - files_dropped - How many files have been dropped (counter)\n- internal_directory_monitor\n  - tags:\n    - directory - The monitored directory\n  - fields:\n    - files_processed_per_dir - How many files have been processed (counter)\n    - files_dropped_per_dir - How many files have been dropped (counter)\n    - files_queue_per_dir - How many files to be processed (gauge)\n\n## Example Output\n\nThe metrics produced by this plugin depends on the content and data\nformat of the file.\n\n[internal]: /plugins/inputs/internal\n"
  },
  {
    "path": "plugins/inputs/directory_monitor/directory_monitor.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage directory_monitor\n\nimport (\n\t\"bufio\"\n\t\"compress/gzip\"\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/djherbis/times\"\n\t\"golang.org/x/sync/semaphore\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst (\n\tdefaultMaxBufferedMetrics         = 10000\n\tdefaultDirectoryDurationThreshold = config.Duration(0 * time.Millisecond)\n\tdefaultFileQueueSize              = 100000\n\tdefaultParseMethod                = \"line-by-line\"\n)\n\ntype DirectoryMonitor struct {\n\tDirectory         string `toml:\"directory\"`\n\tFinishedDirectory string `toml:\"finished_directory\"`\n\tRecursive         bool   `toml:\"recursive\"`\n\tErrorDirectory    string `toml:\"error_directory\"`\n\tFileTag           string `toml:\"file_tag\"`\n\n\tFilesToMonitor             []string        `toml:\"files_to_monitor\"`\n\tFilesToIgnore              []string        `toml:\"files_to_ignore\"`\n\tMaxBufferedMetrics         int             `toml:\"max_buffered_metrics\"`\n\tDirectoryDurationThreshold config.Duration `toml:\"directory_duration_threshold\"`\n\tLog                        telegraf.Logger `toml:\"-\"`\n\tFileQueueSize              int             `toml:\"file_queue_size\"`\n\tParseMethod                string          `toml:\"parse_method\"`\n\n\tfilesInUse          sync.Map\n\tcancel              context.CancelFunc\n\tcontext             context.Context\n\tparserFunc          telegraf.ParserFunc\n\tfilesProcessed      selfstat.Stat\n\tfilesProcessedDir   selfstat.Stat\n\tfilesDropped        selfstat.Stat\n\tfilesDroppedDir     selfstat.Stat\n\tfilesQueuedDir      selfstat.Stat\n\twaitGroup           *sync.WaitGroup\n\tacc                 telegraf.TrackingAccumulator\n\tsem                 *semaphore.Weighted\n\tfileRegexesToMatch  []*regexp.Regexp\n\tfileRegexesToIgnore []*regexp.Regexp\n\tfilesToProcess      chan string\n}\n\nfunc (*DirectoryMonitor) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (monitor *DirectoryMonitor) SetParserFunc(fn telegraf.ParserFunc) {\n\tmonitor.parserFunc = fn\n}\n\nfunc (monitor *DirectoryMonitor) Init() error {\n\tif monitor.Directory == \"\" || monitor.FinishedDirectory == \"\" {\n\t\treturn errors.New(\"missing one of the following required config options: directory, finished_directory\")\n\t}\n\n\tif monitor.FileQueueSize <= 0 {\n\t\treturn errors.New(\"file queue size needs to be more than 0\")\n\t}\n\n\t// Finished directory can be created if not exists for convenience.\n\tif _, err := os.Stat(monitor.FinishedDirectory); os.IsNotExist(err) {\n\t\terr = os.Mkdir(monitor.FinishedDirectory, 0750)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\ttags := map[string]string{\n\t\t\"directory\": monitor.Directory,\n\t}\n\tmonitor.filesDropped = selfstat.Register(\"directory_monitor\", \"files_dropped\", make(map[string]string))\n\tmonitor.filesDroppedDir = selfstat.Register(\"directory_monitor\", \"files_dropped_per_dir\", tags)\n\tmonitor.filesProcessed = selfstat.Register(\"directory_monitor\", \"files_processed\", make(map[string]string))\n\tmonitor.filesProcessedDir = selfstat.Register(\"directory_monitor\", \"files_processed_per_dir\", tags)\n\tmonitor.filesQueuedDir = selfstat.Register(\"directory_monitor\", \"files_queue_per_dir\", tags)\n\n\t// If an error directory should be used but has not been configured yet, create one ourselves.\n\tif monitor.ErrorDirectory != \"\" {\n\t\tif _, err := os.Stat(monitor.ErrorDirectory); os.IsNotExist(err) {\n\t\t\terr := os.Mkdir(monitor.ErrorDirectory, 0750)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tmonitor.waitGroup = &sync.WaitGroup{}\n\tmonitor.sem = semaphore.NewWeighted(int64(monitor.MaxBufferedMetrics))\n\tmonitor.context, monitor.cancel = context.WithCancel(context.Background())\n\tmonitor.filesToProcess = make(chan string, monitor.FileQueueSize)\n\n\t// Establish file matching / exclusion regexes.\n\tfor _, matcher := range monitor.FilesToMonitor {\n\t\tregex, err := regexp.Compile(matcher)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmonitor.fileRegexesToMatch = append(monitor.fileRegexesToMatch, regex)\n\t}\n\n\tfor _, matcher := range monitor.FilesToIgnore {\n\t\tregex, err := regexp.Compile(matcher)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmonitor.fileRegexesToIgnore = append(monitor.fileRegexesToIgnore, regex)\n\t}\n\n\tif err := choice.Check(monitor.ParseMethod, []string{\"line-by-line\", \"at-once\"}); err != nil {\n\t\treturn fmt.Errorf(\"config option parse_method: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (monitor *DirectoryMonitor) Start(acc telegraf.Accumulator) error {\n\t// Use tracking to determine when more metrics can be added without overflowing the outputs.\n\tmonitor.acc = acc.WithTracking(monitor.MaxBufferedMetrics)\n\tgo func() {\n\t\tfor range monitor.acc.Delivered() {\n\t\t\tmonitor.sem.Release(1)\n\t\t}\n\t}()\n\n\t// Monitor the files channel and read what they receive.\n\tmonitor.waitGroup.Add(1)\n\tgo func() {\n\t\tmonitor.monitor()\n\t\tmonitor.waitGroup.Done()\n\t}()\n\n\treturn nil\n}\n\nfunc (monitor *DirectoryMonitor) Gather(_ telegraf.Accumulator) error {\n\tprocessFile := func(path string) error {\n\t\t// We've been cancelled via Stop().\n\t\tif monitor.context.Err() != nil {\n\t\t\treturn io.EOF\n\t\t}\n\n\t\tstat, err := times.Stat(path)\n\t\tif err != nil {\n\t\t\treturn nil //nolint:nilerr // don't stop traversing if there is an error\n\t\t}\n\n\t\ttimeThresholdExceeded := time.Since(stat.AccessTime()) >= time.Duration(monitor.DirectoryDurationThreshold)\n\n\t\t// If file is decaying, process it.\n\t\tif timeThresholdExceeded {\n\t\t\tmonitor.processFile(path)\n\t\t}\n\t\treturn nil\n\t}\n\n\tif monitor.Recursive {\n\t\terr := filepath.Walk(monitor.Directory,\n\t\t\tfunc(path string, _ os.FileInfo, err error) error {\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn processFile(path)\n\t\t\t})\n\t\t// We've been cancelled via Stop().\n\t\tif errors.Is(err, io.EOF) {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// Get all files sitting in the directory.\n\t\tfiles, err := os.ReadDir(monitor.Directory)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to monitor the targeted directory: %w\", err)\n\t\t}\n\n\t\tfor _, file := range files {\n\t\t\tif file.IsDir() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpath := monitor.Directory + \"/\" + file.Name()\n\t\t\terr := processFile(path)\n\t\t\t// We've been cancelled via Stop().\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (monitor *DirectoryMonitor) Stop() {\n\t// Before stopping, wrap up all file-reading routines.\n\tmonitor.cancel()\n\tclose(monitor.filesToProcess)\n\tmonitor.Log.Warnf(\"Exiting the Directory Monitor plugin. Waiting to quit until all current files are finished.\")\n\tmonitor.waitGroup.Wait()\n}\n\nfunc (monitor *DirectoryMonitor) monitor() {\n\tfor filePath := range monitor.filesToProcess {\n\t\tif monitor.context.Err() != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// Prevent goroutines from taking the same file as another.\n\t\tif _, exists := monitor.filesInUse.LoadOrStore(filePath, true); exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tmonitor.read(filePath)\n\n\t\t// We've finished reading the file and moved it away, delete it from files in use.\n\t\tmonitor.filesInUse.Delete(filePath)\n\n\t\t// Keep track of how many files still to process\n\t\tmonitor.filesQueuedDir.Set(int64(len(monitor.filesToProcess)))\n\t}\n}\n\nfunc (monitor *DirectoryMonitor) processFile(path string) {\n\tbasePath := strings.Replace(path, monitor.Directory, \"\", 1)\n\n\t// File must be configured to be monitored, if any configuration...\n\tif !monitor.isMonitoredFile(basePath) {\n\t\treturn\n\t}\n\n\t// ...and should not be configured to be ignored.\n\tif monitor.isIgnoredFile(basePath) {\n\t\treturn\n\t}\n\n\tselect {\n\tcase monitor.filesToProcess <- path:\n\tdefault:\n\t}\n}\n\nfunc (monitor *DirectoryMonitor) read(filePath string) {\n\t// Open, read, and parse the contents of the file.\n\terr := monitor.ingestFile(filePath)\n\tvar pathErr *os.PathError\n\tif errors.As(err, &pathErr) {\n\t\treturn\n\t}\n\n\t// Handle a file read error. We don't halt execution but do document, log, and move the problematic file.\n\tif err != nil {\n\t\tmonitor.Log.Errorf(\"Error while reading file: %q: %v\", filePath, err)\n\t\tmonitor.filesDropped.Incr(1)\n\t\tmonitor.filesDroppedDir.Incr(1)\n\t\tif monitor.ErrorDirectory != \"\" {\n\t\t\tmonitor.moveFile(filePath, monitor.ErrorDirectory)\n\t\t}\n\t\treturn\n\t}\n\n\t// File is finished, move it to the 'finished' directory.\n\tmonitor.moveFile(filePath, monitor.FinishedDirectory)\n\tmonitor.filesProcessed.Incr(1)\n\tmonitor.filesProcessedDir.Incr(1)\n}\n\nfunc (monitor *DirectoryMonitor) ingestFile(filePath string) error {\n\tfile, err := os.Open(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\n\tparser, err := monitor.parserFunc()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating parser: %w\", err)\n\t}\n\n\t// Handle gzipped files.\n\tvar reader io.Reader\n\tif filepath.Ext(filePath) == \".gz\" {\n\t\treader, err = gzip.NewReader(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\treader = file\n\t}\n\n\treturn monitor.parseFile(parser, reader, file.Name())\n}\n\nfunc (monitor *DirectoryMonitor) parseFile(parser telegraf.Parser, reader io.Reader, fileName string) error {\n\tvar splitter bufio.SplitFunc\n\n\t// Decide on how to split the file\n\tswitch monitor.ParseMethod {\n\tcase \"at-once\":\n\t\treturn monitor.parseAtOnce(parser, reader, fileName)\n\tcase \"line-by-line\":\n\t\tsplitter = bufio.ScanLines\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown parse method %q\", monitor.ParseMethod)\n\t}\n\n\tscanner := bufio.NewScanner(reader)\n\tscanner.Split(splitter)\n\n\tfor scanner.Scan() {\n\t\tmetrics, err := monitor.parseMetrics(parser, scanner.Bytes(), fileName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := monitor.sendMetrics(metrics); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (monitor *DirectoryMonitor) parseAtOnce(parser telegraf.Parser, reader io.Reader, fileName string) error {\n\tbytes, err := io.ReadAll(reader)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmetrics, err := monitor.parseMetrics(parser, bytes, fileName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn monitor.sendMetrics(metrics)\n}\n\nfunc (monitor *DirectoryMonitor) parseMetrics(parser telegraf.Parser, line []byte, fileName string) (metrics []telegraf.Metric, err error) {\n\tmetrics, err = parser.Parse(line)\n\tif err != nil {\n\t\tif errors.Is(err, parsers.ErrEOF) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\tmonitor.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tif monitor.FileTag != \"\" {\n\t\tfor _, m := range metrics {\n\t\t\tm.AddTag(monitor.FileTag, filepath.Base(fileName))\n\t\t}\n\t}\n\n\treturn metrics, err\n}\n\nfunc (monitor *DirectoryMonitor) sendMetrics(metrics []telegraf.Metric) error {\n\t// Report the metrics for the file.\n\tfor _, m := range metrics {\n\t\t// Block until metric can be written.\n\t\tif err := monitor.sem.Acquire(monitor.context, 1); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmonitor.acc.AddTrackingMetricGroup([]telegraf.Metric{m})\n\t}\n\treturn nil\n}\n\nfunc (monitor *DirectoryMonitor) moveFile(srcPath, dstBaseDir string) {\n\t// Appends any subdirectories in the srcPath to the dstBaseDir and\n\t// creates those subdirectories.\n\tbasePath := strings.Replace(srcPath, monitor.Directory, \"\", 1)\n\tdstPath := filepath.Join(dstBaseDir, basePath)\n\terr := os.MkdirAll(filepath.Dir(dstPath), 0750)\n\tif err != nil {\n\t\tmonitor.Log.Errorf(\"Error creating directory hierarchy for %q: %v\", srcPath, err)\n\t}\n\n\tinputFile, err := os.Open(srcPath)\n\tif err != nil {\n\t\tmonitor.Log.Errorf(\"Could not open input file: %s\", err)\n\t}\n\n\toutputFile, err := os.Create(dstPath)\n\tif err != nil {\n\t\tmonitor.Log.Errorf(\"Could not open output file: %s\", err)\n\t}\n\tdefer outputFile.Close()\n\n\t_, err = io.Copy(outputFile, inputFile)\n\tif err != nil {\n\t\tmonitor.Log.Errorf(\"Writing to output file failed: %s\", err)\n\t}\n\n\t// We need to close the file for remove on Windows as we otherwise\n\t// will run into a \"being used by another process\" error\n\t// (see https://github.com/influxdata/telegraf/issues/12287)\n\tif err := inputFile.Close(); err != nil {\n\t\tmonitor.Log.Errorf(\"Could not close input file: %s\", err)\n\t}\n\n\tif err := os.Remove(srcPath); err != nil {\n\t\tmonitor.Log.Errorf(\"Failed removing original file: %s\", err)\n\t}\n}\n\nfunc (monitor *DirectoryMonitor) isMonitoredFile(fileName string) bool {\n\tif len(monitor.fileRegexesToMatch) == 0 {\n\t\treturn true\n\t}\n\n\t// Only monitor matching files.\n\tfor _, regex := range monitor.fileRegexesToMatch {\n\t\tif regex.MatchString(fileName) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (monitor *DirectoryMonitor) isIgnoredFile(fileName string) bool {\n\t// Skip files that are set to be ignored.\n\tfor _, regex := range monitor.fileRegexesToIgnore {\n\t\tif regex.MatchString(fileName) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc init() {\n\tinputs.Add(\"directory_monitor\", func() telegraf.Input {\n\t\treturn &DirectoryMonitor{\n\t\t\tMaxBufferedMetrics:         defaultMaxBufferedMetrics,\n\t\t\tDirectoryDurationThreshold: defaultDirectoryDurationThreshold,\n\t\t\tFileQueueSize:              defaultFileQueueSize,\n\t\t\tParseMethod:                defaultParseMethod,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/directory_monitor/directory_monitor_test.go",
    "content": "package directory_monitor\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/csv\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCreator(t *testing.T) {\n\tcreator, found := inputs.Inputs[\"directory_monitor\"]\n\trequire.True(t, found)\n\n\texpected := &DirectoryMonitor{\n\t\tMaxBufferedMetrics:         defaultMaxBufferedMetrics,\n\t\tDirectoryDurationThreshold: defaultDirectoryDurationThreshold,\n\t\tFileQueueSize:              defaultFileQueueSize,\n\t\tParseMethod:                defaultParseMethod,\n\t}\n\n\trequire.Equal(t, expected, creator())\n}\n\nfunc TestCSVGZImport(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestCsvFile := \"test.csv\"\n\ttestCsvGzFile := \"test.csv.gz\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := csv.Parser{\n\t\t\tHeaderRowCount: 1,\n\t\t}\n\t\terr := parser.Init()\n\t\treturn &parser, err\n\t})\n\tr.Log = testutil.Logger{}\n\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"thing,color\\nsky,blue\\ngrass,green\\nclifford,red\\n\")\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Write csv.gz file to process into the 'process' directory.\n\tvar b bytes.Buffer\n\tw := gzip.NewWriter(&b)\n\t_, err = w.Write([]byte(\"thing,color\\nsky,blue\\ngrass,green\\nclifford,red\\n\"))\n\trequire.NoError(t, err)\n\terr = w.Close()\n\trequire.NoError(t, err)\n\terr = os.WriteFile(filepath.Join(processDirectory, testCsvGzFile), b.Bytes(), 0640)\n\trequire.NoError(t, err)\n\n\t// Start plugin before adding file.\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(6)\n\tr.Stop()\n\n\t// Verify that we read both files once.\n\trequire.Len(t, acc.Metrics, 6)\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvGzFile))\n\trequire.NoError(t, err)\n}\n\nfunc TestCSVGZImportWithHeader(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestCsvFile := \"test.csv\"\n\ttestCsvGzFile := \"test.csv.gz\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := csv.Parser{\n\t\t\tHeaderRowCount: 1,\n\t\t\tSkipRows:       1,\n\t\t}\n\t\terr := parser.Init()\n\t\treturn &parser, err\n\t})\n\tr.Log = testutil.Logger{}\n\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"This is some garbage to be skipped\\n\")\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"thing,color\\nsky,blue\\ngrass,green\\nclifford,red\\n\")\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Write csv.gz file to process into the 'process' directory.\n\tvar b bytes.Buffer\n\tw := gzip.NewWriter(&b)\n\t_, err = w.Write([]byte(\"This is some garbage to be skipped\\n\"))\n\trequire.NoError(t, err)\n\t_, err = w.Write([]byte(\"thing,color\\nsky,blue\\ngrass,green\\nclifford,red\\n\"))\n\trequire.NoError(t, err)\n\terr = w.Close()\n\trequire.NoError(t, err)\n\terr = os.WriteFile(filepath.Join(processDirectory, testCsvGzFile), b.Bytes(), 0640)\n\trequire.NoError(t, err)\n\n\t// Start plugin before adding file.\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(6)\n\tr.Stop()\n\n\t// Verify that we read both files once.\n\trequire.Len(t, acc.Metrics, 6)\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvGzFile))\n\trequire.NoError(t, err)\n}\n\nfunc TestMultipleJSONFileImports(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestJSONFile := \"test.json\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{NameKey: \"Name\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\t// Let's drop a 5-line LINE-DELIMITED json.\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\n\t\t\"{\\\"Name\\\": \\\"event1\\\",\\\"Speed\\\": 100.1,\\\"Length\\\": 20.1}\\n{\\\"Name\\\": \\\"event2\\\",\\\"Speed\\\": 500,\\\"Length\\\": 1.4}\\n\" +\n\t\t\t\"{\\\"Name\\\": \" + \"\\\"event3\\\",\\\"Speed\\\": 200,\\\"Length\\\": 10.23}\\n{\\\"Name\\\": \\\"event4\\\",\\\"Speed\\\": 80,\\\"Length\\\": 250}\\n\" +\n\t\t\t\"{\\\"Name\\\": \\\"event5\\\",\\\"Speed\\\": 120.77,\\\"Length\\\": 25.97}\",\n\t)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\terr = r.Start(&acc)\n\tr.Log = testutil.Logger{}\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(5)\n\tr.Stop()\n\n\t// Verify that we read each JSON line once to a single metric.\n\trequire.Len(t, acc.Metrics, 5)\n}\n\nfunc TestFileTag(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestJSONFile := \"test.json\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tFileTag:            \"filename\",\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{NameKey: \"Name\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\t// Let's drop a 1-line LINE-DELIMITED json.\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"{\\\"Name\\\": \\\"event1\\\",\\\"Speed\\\": 100.1,\\\"Length\\\": 20.1}\")\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\terr = r.Start(&acc)\n\tr.Log = testutil.Logger{}\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\t// Verify that we read each JSON line once to a single metric.\n\trequire.Len(t, acc.Metrics, 1)\n\tfor _, m := range acc.Metrics {\n\t\tfor key, value := range m.Tags {\n\t\t\trequire.Equal(t, r.FileTag, key)\n\t\t\trequire.Equal(t, filepath.Base(testJSONFile), value)\n\t\t}\n\t}\n}\n\nfunc TestCSVNoSkipRows(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestCsvFile := \"test.csv\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := csv.Parser{\n\t\t\tHeaderRowCount: 1,\n\t\t\tSkipRows:       0,\n\t\t\tTagColumns:     []string{\"line1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn &parser, err\n\t})\n\tr.Log = testutil.Logger{}\n\n\ttestCSV := `line1,line2,line3\nhello,80,test_name2`\n\n\texpectedFields := map[string]interface{}{\n\t\t\"line2\": int64(80),\n\t\t\"line3\": \"test_name2\",\n\t}\n\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testCSV)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Start plugin before adding file.\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\t// Verify that we read both files once.\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\tfor _, m := range acc.Metrics {\n\t\tfor key, value := range m.Tags {\n\t\t\trequire.Equal(t, \"line1\", key)\n\t\t\trequire.Equal(t, \"hello\", value)\n\t\t}\n\t\trequire.Equal(t, expectedFields, m.Fields)\n\t}\n}\n\nfunc TestCSVSkipRows(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestCsvFile := \"test.csv\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := csv.Parser{\n\t\t\tHeaderRowCount: 1,\n\t\t\tSkipRows:       2,\n\t\t\tTagColumns:     []string{\"line1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn &parser, err\n\t})\n\tr.Log = testutil.Logger{}\n\n\ttestCSV := `garbage nonsense 1\ngarbage,nonsense,2\nline1,line2,line3\nhello,80,test_name2`\n\n\texpectedFields := map[string]interface{}{\n\t\t\"line2\": int64(80),\n\t\t\"line3\": \"test_name2\",\n\t}\n\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testCSV)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Start plugin before adding file.\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\t// Verify that we read both files once.\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\tfor _, m := range acc.Metrics {\n\t\tfor key, value := range m.Tags {\n\t\t\trequire.Equal(t, \"line1\", key)\n\t\t\trequire.Equal(t, \"hello\", value)\n\t\t}\n\t\trequire.Equal(t, expectedFields, m.Fields)\n\t}\n}\n\nfunc TestCSVMultiHeader(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\ttestCsvFile := \"test.csv\"\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        defaultParseMethod,\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := csv.Parser{\n\t\t\tHeaderRowCount: 2,\n\t\t\tTagColumns:     []string{\"line1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn &parser, err\n\t})\n\tr.Log = testutil.Logger{}\n\n\ttestCSV := `line,line,line\n1,2,3\nhello,80,test_name2`\n\n\texpectedFields := map[string]interface{}{\n\t\t\"line2\": int64(80),\n\t\t\"line3\": \"test_name2\",\n\t}\n\n\t// Write csv file to process into the 'process' directory.\n\tf, err := os.Create(filepath.Join(processDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testCSV)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Start plugin before adding file.\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\t// Verify that we read both files once.\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testCsvFile))\n\trequire.NoError(t, err)\n\tfor _, m := range acc.Metrics {\n\t\tfor key, value := range m.Tags {\n\t\t\trequire.Equal(t, \"line1\", key)\n\t\t\trequire.Equal(t, \"hello\", value)\n\t\t}\n\t\trequire.Equal(t, expectedFields, m.Fields)\n\t}\n}\n\nfunc TestParseCompleteFile(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        \"at-once\",\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\tr.Log = testutil.Logger{}\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &json.Parser{\n\t\t\tNameKey: \"name\",\n\t\t\tTagKeys: []string{\"tag1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t})\n\n\ttestJSON := `{\n\t\t\"name\": \"test1\",\n\t\t\"value\": 100.1,\n\t\t\"tag1\": \"value1\"\n\t}`\n\n\t// Write json file to process into the 'process' directory.\n\tf, err := os.CreateTemp(processDirectory, \"test.json\")\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testJSON)\n\trequire.NoError(t, err)\n\tf.Close()\n\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\trequire.NoError(t, acc.FirstError())\n\trequire.Len(t, acc.Metrics, 1)\n\ttestutil.RequireMetricEqual(t, testutil.TestMetric(100.1), acc.GetTelegrafMetrics()[0], testutil.IgnoreTime())\n}\n\nfunc TestParseSubdirectories(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tRecursive:          true,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        \"at-once\",\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\tr.Log = testutil.Logger{}\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &json.Parser{\n\t\t\tNameKey: \"name\",\n\t\t\tTagKeys: []string{\"tag1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t})\n\n\ttestJSON := `{\n\t\t\"name\": \"test1\",\n\t\t\"value\": 100.1,\n\t\t\"tag1\": \"value1\"\n\t}`\n\n\t// Write json file to process into the 'process' directory.\n\ttestJSONFile := \"test.json\"\n\tf, err := os.Create(filepath.Join(processDirectory, testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testJSON)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Write json file to process into a subdirectory in the 'process' directory.\n\terr = os.Mkdir(filepath.Join(processDirectory, \"sub\"), 0750)\n\trequire.NoError(t, err)\n\tf, err = os.Create(filepath.Join(processDirectory, \"sub\", testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testJSON)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(2)\n\tr.Stop()\n\n\trequire.NoError(t, acc.FirstError())\n\trequire.Len(t, acc.Metrics, 2)\n\ttestutil.RequireMetricEqual(t, testutil.TestMetric(100.1), acc.GetTelegrafMetrics()[0], testutil.IgnoreTime())\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = os.Stat(filepath.Join(finishedDirectory, \"sub\", testJSONFile))\n\trequire.NoError(t, err)\n}\n\nfunc TestParseSubdirectoriesFilesIgnore(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\n\t// Establish process directory and finished directory.\n\tfinishedDirectory := t.TempDir()\n\tprocessDirectory := t.TempDir()\n\n\tfilesToIgnore := `sub/test.json`\n\tif runtime.GOOS == \"windows\" {\n\t\tfilesToIgnore = `\\\\sub\\\\test.json`\n\t}\n\n\t// Init plugin.\n\tr := DirectoryMonitor{\n\t\tDirectory:          processDirectory,\n\t\tFinishedDirectory:  finishedDirectory,\n\t\tRecursive:          true,\n\t\tMaxBufferedMetrics: defaultMaxBufferedMetrics,\n\t\tFileQueueSize:      defaultFileQueueSize,\n\t\tParseMethod:        \"at-once\",\n\t\tFilesToIgnore:      []string{filesToIgnore},\n\t}\n\terr := r.Init()\n\trequire.NoError(t, err)\n\tr.Log = testutil.Logger{}\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &json.Parser{\n\t\t\tNameKey: \"name\",\n\t\t\tTagKeys: []string{\"tag1\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t})\n\n\ttestJSON := `{\n\t\t\"name\": \"test1\",\n\t\t\"value\": 100.1,\n\t\t\"tag1\": \"value1\"\n\t}`\n\n\t// Write json file to process into the 'process' directory.\n\ttestJSONFile := \"test.json\"\n\tf, err := os.Create(filepath.Join(processDirectory, testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testJSON)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\t// Write json file to process into a subdirectory in the 'process' directory.\n\terr = os.Mkdir(filepath.Join(processDirectory, \"sub\"), 0750)\n\trequire.NoError(t, err)\n\tf, err = os.Create(filepath.Join(processDirectory, \"sub\", testJSONFile))\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(testJSON)\n\trequire.NoError(t, err)\n\terr = f.Close()\n\trequire.NoError(t, err)\n\n\terr = r.Start(&acc)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\tacc.Wait(1)\n\tr.Stop()\n\n\trequire.NoError(t, acc.FirstError())\n\trequire.Len(t, acc.Metrics, 1)\n\ttestutil.RequireMetricEqual(t, testutil.TestMetric(100.1), acc.GetTelegrafMetrics()[0], testutil.IgnoreTime())\n\n\t// File should have gone back to the test directory, as we configured.\n\t_, err = os.Stat(filepath.Join(finishedDirectory, testJSONFile))\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/directory_monitor/sample.conf",
    "content": "# Ingests files in a directory and then moves them to a target directory.\n[[inputs.directory_monitor]]\n  ## The directory to monitor and read files from (including sub-directories if \"recursive\" is true).\n  directory = \"\"\n  #\n  ## The directory to move finished files to (maintaining directory hierarchy from source).\n  finished_directory = \"\"\n  #\n  ## Setting recursive to true will make the plugin recursively walk the directory and process all sub-directories.\n  # recursive = false\n  #\n  ## The directory to move files to upon file error.\n  ## If not provided, erroring files will stay in the monitored directory.\n  # error_directory = \"\"\n  #\n  ## The amount of time a file is allowed to sit in the directory before it is picked up.\n  ## This time can generally be low but if you choose to have a very large file written to the directory and it's potentially slow,\n  ## set this higher so that the plugin will wait until the file is fully copied to the directory.\n  # directory_duration_threshold = \"50ms\"\n  #\n  ## A list of the only file names to monitor, if necessary. Supports regex. If left blank, all files are ingested.\n  # files_to_monitor = [\"^.*\\\\.csv\"]\n  #\n  ## A list of files to ignore, if necessary. Supports regex.\n  # files_to_ignore = [\".DS_Store\"]\n  #\n  ## Maximum lines of the file to process that have not yet be written by the\n  ## output. For best throughput set to the size of the output's metric_buffer_limit.\n  ## Warning: setting this number higher than the output's metric_buffer_limit can cause dropped metrics.\n  # max_buffered_metrics = 10000\n  #\n  ## The maximum amount of file paths to queue up for processing at once, before waiting until files are processed to find more files.\n  ## Lowering this value will result in *slightly* less memory use, with a potential sacrifice in speed efficiency, if absolutely necessary.\n  # file_queue_size = 100000\n  #\n  ## Name a tag containing the name of the file the data was parsed from.  Leave empty\n  ## to disable. Cautious when file name variation is high, this can increase the cardinality\n  ## significantly. Read more about cardinality here:\n  ## https://docs.influxdata.com/influxdb/cloud/reference/glossary/#series-cardinality\n  # file_tag = \"\"\n  #\n  ## Specify if the file can be read completely at once or if it needs to be read line by line (default).\n  ## Possible values: \"line-by-line\", \"at-once\"\n  # parse_method = \"line-by-line\"\n  #\n  ## The dataformat to be read from the files.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/disk/README.md",
    "content": "# Disk Input Plugin\n\nThis plugin gathers metrics about disk usage.\n\n> [!NOTE]\n> The `used_percent` field is calculated by `used / (used + free)` and _not_\n> `used / total` as the unix `df` command does it. See [wikipedia - df][wiki_df]\n> for more details.\n\n⭐ Telegraf v0.1.1\n🏷️ system\n💻 all\n\n[wiki_df]: https://en.wikipedia.org/wiki/Df_(Unix)\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about disk usage by mount point\n[[inputs.disk]]\n  ## By default stats will be gathered for all mount points.\n  ## Set mount_points will restrict the stats to only the specified mount points.\n  # mount_points = [\"/\"]\n\n  ## Ignore mount points by filesystem type.\n  ignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n\n  ## Ignore mount points by mount options.\n  ## The 'mount' command reports options of all mounts in parathesis.\n  ## Bind mounts can be ignored with the special 'bind' option.\n  # ignore_mount_opts = []\n```\n\n### Docker container\n\nTo monitor the Docker engine host from within a container you will need to mount\nthe host's filesystem into the container and set the `HOST_PROC` environment\nvariable to the location of the `/proc` filesystem.  If desired, you can also\nset the `HOST_MOUNT_PREFIX` environment variable to the prefix containing the\n`/proc` directory, when present this variable is stripped from the reported\n`path` tag.\n\n```shell\ndocker run -v /:/hostfs:ro -e HOST_MOUNT_PREFIX=/hostfs -e HOST_PROC=/hostfs/proc telegraf\n```\n\n## Metrics\n\n- disk\n  - tags:\n    - fstype (filesystem type)\n    - device (device file)\n    - path (mount point path)\n    - mode (whether the mount is rw or ro)\n    - label (devicemapper labels, only if present)\n  - fields:\n    - free (integer, bytes)\n    - total (integer, bytes)\n    - used (integer, bytes)\n    - used_percent (float, percent)\n    - inodes_free (integer, files)\n    - inodes_total (integer, files)\n    - inodes_used (integer, files)\n    - inodes_used_percent (float, percent)\n\n## Troubleshooting\n\nOn Linux, the list of disks is taken from the `/proc/self/mounts` file and a\n[statfs] call is made on the second column.  If any expected filesystems are\nmissing ensure that the `telegraf` user can read these files:\n\n```shell\n$ sudo -u telegraf cat /proc/self/mounts | grep sda2\n/dev/sda2 /home ext4 rw,relatime,data=ordered 0 0\n$ sudo -u telegraf stat /home\n```\n\nIt may be desired to use POSIX ACLs to provide additional access:\n\n```shell\nsudo setfacl -R -m u:telegraf:X /var/lib/docker/volumes/\n```\n\n## Example Output\n\n```text\ndisk,fstype=hfs,mode=ro,path=/ free=398407520256i,inodes_free=97267461i,inodes_total=121847806i,inodes_used=24580345i,total=499088621568i,used=100418957312i,used_percent=20.131039916242397,inodes_used_percent=20.1729894 1453832006274071563\ndisk,fstype=devfs,mode=rw,path=/dev free=0i,inodes_free=0i,inodes_total=628i,inodes_used=628i,total=185856i,used=185856i,used_percent=100,inodes_used_percent=100 1453832006274137913\ndisk,fstype=autofs,mode=rw,path=/net free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0,inodes_used_percent=0 1453832006274157077\ndisk,fstype=autofs,mode=rw,path=/home free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0,inodes_used_percent=0 1453832006274169688\ndisk,device=dm-1,fstype=xfs,label=lvg-lv,mode=rw,path=/mnt inodes_free=8388605i,inodes_used=3i,total=17112760320i,free=16959598592i,used=153161728i,used_percent=0.8950147441789215,inodes_total=8388608i,inodes_used_percent=0.0017530778 1677001387000000000\n```\n\n[statfs]: http://man7.org/linux/man-pages/man2/statfs.2.html\n"
  },
  {
    "path": "plugins/inputs/disk/disk.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage disk\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Disk struct {\n\tMountPoints     []string        `toml:\"mount_points\"`\n\tIgnoreFS        []string        `toml:\"ignore_fs\"`\n\tIgnoreMountOpts []string        `toml:\"ignore_mount_opts\"`\n\tLog             telegraf.Logger `toml:\"-\"`\n\n\tps psutil.PS\n}\n\nfunc (*Disk) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ds *Disk) Init() error {\n\tps := psutil.NewSystemPS()\n\tps.Log = ds.Log\n\tds.ps = ps\n\n\treturn nil\n}\n\nfunc (ds *Disk) Gather(acc telegraf.Accumulator) error {\n\tdisks, partitions, err := ds.ps.DiskUsage(ds.MountPoints, ds.IgnoreMountOpts, ds.IgnoreFS)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting disk usage info: %w\", err)\n\t}\n\tfor i, du := range disks {\n\t\tif du.Total == 0 {\n\t\t\t// Skip dummy filesystem (procfs, cgroupfs, ...)\n\t\t\tcontinue\n\t\t}\n\n\t\tdevice := partitions[i].Device\n\t\tif device == \"none\" || device == \"\" {\n\t\t\tdevice = partitions[i].Fstype\n\t\t}\n\t\tmountOpts := mountOptions(partitions[i].Opts)\n\t\ttags := map[string]string{\n\t\t\t\"path\":   du.Path,\n\t\t\t\"device\": strings.ReplaceAll(device, \"/dev/\", \"\"),\n\t\t\t\"fstype\": du.Fstype,\n\t\t\t\"mode\":   mountOpts.mode(),\n\t\t}\n\n\t\tlabel, err := disk.Label(strings.TrimPrefix(device, \"/dev/\"))\n\t\tif err == nil && label != \"\" {\n\t\t\ttags[\"label\"] = label\n\t\t}\n\n\t\tvar usedPercent float64\n\t\tif du.Used+du.Free > 0 {\n\t\t\tusedPercent = float64(du.Used) /\n\t\t\t\t(float64(du.Used) + float64(du.Free)) * 100\n\t\t}\n\n\t\tvar inodesUsedPercent float64\n\t\tif du.InodesUsed+du.InodesFree > 0 {\n\t\t\tinodesUsedPercent = float64(du.InodesUsed) /\n\t\t\t\t(float64(du.InodesUsed) + float64(du.InodesFree)) * 100\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"total\":               du.Total,\n\t\t\t\"free\":                du.Free,\n\t\t\t\"used\":                du.Used,\n\t\t\t\"used_percent\":        usedPercent,\n\t\t\t\"inodes_total\":        du.InodesTotal,\n\t\t\t\"inodes_free\":         du.InodesFree,\n\t\t\t\"inodes_used\":         du.InodesUsed,\n\t\t\t\"inodes_used_percent\": inodesUsedPercent,\n\t\t}\n\t\tacc.AddGauge(\"disk\", fields, tags)\n\t}\n\n\treturn nil\n}\n\ntype mountOptions []string\n\nfunc (opts mountOptions) mode() string {\n\tif opts.exists(\"rw\") {\n\t\treturn \"rw\"\n\t} else if opts.exists(\"ro\") {\n\t\treturn \"ro\"\n\t}\n\treturn \"unknown\"\n}\n\nfunc (opts mountOptions) exists(opt string) bool {\n\tfor _, o := range opts {\n\t\tif o == opt {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc init() {\n\tinputs.Add(\"disk\", func() telegraf.Input {\n\t\treturn &Disk{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/disk/disk_test.go",
    "content": "package disk\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDiskUsage(t *testing.T) {\n\tmck := &mock.Mock{}\n\tmps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}\n\tdefer mps.AssertExpectations(t)\n\n\tvar acc testutil.Accumulator\n\tvar err error\n\n\tpsAll := []disk.PartitionStat{\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\"},\n\t\t},\n\t\t{\n\t\t\tDevice:     \"/dev/sdb\",\n\t\t\tMountpoint: \"/home\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"rw\", \"noatime\", \"nodiratime\", \"errors=remount-ro\"},\n\t\t},\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/var/rootbind\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\", \"bind\"},\n\t\t},\n\t}\n\tduAll := []disk.UsageStat{\n\t\t{\n\t\t\tPath:        \"/\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t\t{\n\t\t\tPath:        \"/home\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       256,\n\t\t\tFree:        46,\n\t\t\tUsed:        200,\n\t\t\tInodesTotal: 2468,\n\t\t\tInodesFree:  468,\n\t\t\tInodesUsed:  2000,\n\t\t},\n\t\t{\n\t\t\tPath:        \"/var/rootbind\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t}\n\n\tmps.On(\"Partitions\", true).Return(psAll, nil)\n\tmps.On(\"OSGetenv\", \"HOST_MOUNT_PREFIX\").Return(\"\")\n\tmps.On(\"PSDiskUsage\", \"/\").Return(&duAll[0], nil)\n\tmps.On(\"PSDiskUsage\", \"/home\").Return(&duAll[1], nil)\n\tmps.On(\"PSDiskUsage\", \"/var/rootbind\").Return(&duAll[2], nil)\n\n\terr = (&Disk{ps: mps}).Gather(&acc)\n\trequire.NoError(t, err)\n\n\tnumDiskMetrics := acc.NFields()\n\texpectedAllDiskMetrics := 24\n\trequire.Equal(t, expectedAllDiskMetrics, numDiskMetrics)\n\n\ttags1 := map[string]string{\n\t\t\"path\":   string(os.PathSeparator),\n\t\t\"fstype\": \"ext4\",\n\t\t\"device\": \"sda\",\n\t\t\"mode\":   \"ro\",\n\t}\n\ttags2 := map[string]string{\n\t\t\"path\":   fmt.Sprintf(\"%chome\", os.PathSeparator),\n\t\t\"fstype\": \"ext4\",\n\t\t\"device\": \"sdb\",\n\t\t\"mode\":   \"rw\",\n\t}\n\ttags3 := map[string]string{\n\t\t\"path\":   fmt.Sprintf(\"%cvar%crootbind\", os.PathSeparator, os.PathSeparator),\n\t\t\"fstype\": \"ext4\",\n\t\t\"device\": \"sda\",\n\t\t\"mode\":   \"ro\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"total\":               uint64(128),\n\t\t\"used\":                uint64(100),\n\t\t\"free\":                uint64(23),\n\t\t\"inodes_total\":        uint64(1234),\n\t\t\"inodes_free\":         uint64(234),\n\t\t\"inodes_used\":         uint64(1000),\n\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t}\n\tfields2 := map[string]interface{}{\n\t\t\"total\":               uint64(256),\n\t\t\"used\":                uint64(200),\n\t\t\"free\":                uint64(46),\n\t\t\"inodes_total\":        uint64(2468),\n\t\t\"inodes_free\":         uint64(468),\n\t\t\"inodes_used\":         uint64(2000),\n\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t}\n\tfields3 := map[string]interface{}{\n\t\t\"total\":               uint64(128),\n\t\t\"used\":                uint64(100),\n\t\t\"free\":                uint64(23),\n\t\t\"inodes_total\":        uint64(1234),\n\t\t\"inodes_free\":         uint64(234),\n\t\t\"inodes_used\":         uint64(1000),\n\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"disk\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"disk\", fields2, tags2)\n\tacc.AssertContainsTaggedFields(t, \"disk\", fields3, tags3)\n\n\t// We expect 7 more DiskMetrics to show up with an explicit match on \"/\"\n\t// and /home not matching the /dev in MountPoints\n\terr = (&Disk{ps: &mps, MountPoints: []string{\"/\", \"/dev\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8, acc.NFields())\n\n\t// We should see all the diskpoints as MountPoints includes both\n\t// /, /home, and /var/rootbind\n\terr = (&Disk{ps: &mps, MountPoints: []string{\"/\", \"/home\", \"/var/rootbind\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8*4, acc.NFields())\n\n\t// We should see all the mounts as MountPoints except the bind mound\n\terr = (&Disk{ps: &mps, IgnoreMountOpts: []string{\"bind\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8*6, acc.NFields())\n}\n\nfunc TestDiskUsageHostMountPrefix(t *testing.T) {\n\ttests := []struct {\n\t\tname            string\n\t\tpartitionStats  []disk.PartitionStat\n\t\tusageStats      []*disk.UsageStat\n\t\thostMountPrefix string\n\t\texpectedTags    map[string]string\n\t\texpectedFields  map[string]interface{}\n\t}{\n\t\t{\n\t\t\tname: \"no host mount prefix\",\n\t\t\tpartitionStats: []disk.PartitionStat{\n\t\t\t\t{\n\t\t\t\t\tDevice:     \"/dev/sda\",\n\t\t\t\t\tMountpoint: \"/\",\n\t\t\t\t\tFstype:     \"ext4\",\n\t\t\t\t\tOpts:       []string{\"ro\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tusageStats: []*disk.UsageStat{\n\t\t\t\t{\n\t\t\t\t\tPath:  \"/\",\n\t\t\t\t\tTotal: 42,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedTags: map[string]string{\n\t\t\t\t\"path\":   string(os.PathSeparator),\n\t\t\t\t\"device\": \"sda\",\n\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\"mode\":   \"ro\",\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"total\":               uint64(42),\n\t\t\t\t\"used\":                uint64(0),\n\t\t\t\t\"free\":                uint64(0),\n\t\t\t\t\"inodes_total\":        uint64(0),\n\t\t\t\t\"inodes_free\":         uint64(0),\n\t\t\t\t\"inodes_used\":         uint64(0),\n\t\t\t\t\"used_percent\":        float64(0),\n\t\t\t\t\"inodes_used_percent\": float64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"host mount prefix\",\n\t\t\tpartitionStats: []disk.PartitionStat{\n\t\t\t\t{\n\t\t\t\t\tDevice:     \"/dev/sda\",\n\t\t\t\t\tMountpoint: \"/hostfs/var\",\n\t\t\t\t\tFstype:     \"ext4\",\n\t\t\t\t\tOpts:       []string{\"ro\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tusageStats: []*disk.UsageStat{\n\t\t\t\t{\n\t\t\t\t\tPath:  \"/hostfs/var\",\n\t\t\t\t\tTotal: 42,\n\t\t\t\t},\n\t\t\t},\n\t\t\thostMountPrefix: \"/hostfs\",\n\t\t\texpectedTags: map[string]string{\n\t\t\t\t\"path\":   fmt.Sprintf(\"%cvar\", os.PathSeparator),\n\t\t\t\t\"device\": \"sda\",\n\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\"mode\":   \"ro\",\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"total\":               uint64(42),\n\t\t\t\t\"used\":                uint64(0),\n\t\t\t\t\"free\":                uint64(0),\n\t\t\t\t\"inodes_total\":        uint64(0),\n\t\t\t\t\"inodes_free\":         uint64(0),\n\t\t\t\t\"inodes_used\":         uint64(0),\n\t\t\t\t\"used_percent\":        float64(0),\n\t\t\t\t\"inodes_used_percent\": float64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"host mount prefix exact match\",\n\t\t\tpartitionStats: []disk.PartitionStat{\n\t\t\t\t{\n\t\t\t\t\tDevice:     \"/dev/sda\",\n\t\t\t\t\tMountpoint: \"/hostfs\",\n\t\t\t\t\tFstype:     \"ext4\",\n\t\t\t\t\tOpts:       []string{\"ro\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tusageStats: []*disk.UsageStat{\n\t\t\t\t{\n\t\t\t\t\tPath:  \"/hostfs\",\n\t\t\t\t\tTotal: 42,\n\t\t\t\t},\n\t\t\t},\n\t\t\thostMountPrefix: \"/hostfs\",\n\t\t\texpectedTags: map[string]string{\n\t\t\t\t\"path\":   string(os.PathSeparator),\n\t\t\t\t\"device\": \"sda\",\n\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\"mode\":   \"ro\",\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"total\":               uint64(42),\n\t\t\t\t\"used\":                uint64(0),\n\t\t\t\t\"free\":                uint64(0),\n\t\t\t\t\"inodes_total\":        uint64(0),\n\t\t\t\t\"inodes_free\":         uint64(0),\n\t\t\t\t\"inodes_used\":         uint64(0),\n\t\t\t\t\"used_percent\":        float64(0),\n\t\t\t\t\"inodes_used_percent\": float64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"virtual filesystem with none device\",\n\t\t\tpartitionStats: []disk.PartitionStat{\n\t\t\t\t{\n\t\t\t\t\tDevice:     \"none\",\n\t\t\t\t\tMountpoint: \"/tmp\",\n\t\t\t\t\tFstype:     \"tmpfs\",\n\t\t\t\t\tOpts:       []string{\"rw\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tusageStats: []*disk.UsageStat{\n\t\t\t\t{\n\t\t\t\t\tPath:  \"/tmp\",\n\t\t\t\t\tTotal: 42,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedTags: map[string]string{\n\t\t\t\t\"path\":   fmt.Sprintf(\"%ctmp\", os.PathSeparator),\n\t\t\t\t\"device\": \"tmpfs\",\n\t\t\t\t\"fstype\": \"tmpfs\",\n\t\t\t\t\"mode\":   \"rw\",\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"total\":               uint64(42),\n\t\t\t\t\"used\":                uint64(0),\n\t\t\t\t\"free\":                uint64(0),\n\t\t\t\t\"inodes_total\":        uint64(0),\n\t\t\t\t\"inodes_free\":         uint64(0),\n\t\t\t\t\"inodes_used\":         uint64(0),\n\t\t\t\t\"used_percent\":        float64(0),\n\t\t\t\t\"inodes_used_percent\": float64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"virtual filesystem with empty device\",\n\t\t\tpartitionStats: []disk.PartitionStat{\n\t\t\t\t{\n\t\t\t\t\tDevice:     \"\",\n\t\t\t\t\tMountpoint: \"/sys\",\n\t\t\t\t\tFstype:     \"sysfs\",\n\t\t\t\t\tOpts:       []string{\"ro\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tusageStats: []*disk.UsageStat{\n\t\t\t\t{\n\t\t\t\t\tPath:  \"/sys\",\n\t\t\t\t\tTotal: 42,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedTags: map[string]string{\n\t\t\t\t\"path\":   fmt.Sprintf(\"%csys\", os.PathSeparator),\n\t\t\t\t\"device\": \"sysfs\",\n\t\t\t\t\"fstype\": \"sysfs\",\n\t\t\t\t\"mode\":   \"ro\",\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"total\":               uint64(42),\n\t\t\t\t\"used\":                uint64(0),\n\t\t\t\t\"free\":                uint64(0),\n\t\t\t\t\"inodes_total\":        uint64(0),\n\t\t\t\t\"inodes_free\":         uint64(0),\n\t\t\t\t\"inodes_used\":         uint64(0),\n\t\t\t\t\"used_percent\":        float64(0),\n\t\t\t\t\"inodes_used_percent\": float64(0),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tmck := &mock.Mock{}\n\t\t\tmps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}\n\t\t\tdefer mps.AssertExpectations(t)\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tvar err error\n\n\t\t\tmps.On(\"Partitions\", true).Return(tt.partitionStats, nil)\n\n\t\t\tfor _, v := range tt.usageStats {\n\t\t\t\tmps.On(\"PSDiskUsage\", v.Path).Return(v, nil)\n\t\t\t}\n\n\t\t\tmps.On(\"OSGetenv\", \"HOST_MOUNT_PREFIX\").Return(tt.hostMountPrefix)\n\n\t\t\terr = (&Disk{ps: mps}).Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc.AssertContainsTaggedFields(t, \"disk\", tt.expectedFields, tt.expectedTags)\n\t\t})\n\t}\n}\n\nfunc TestDiskStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\tvar err error\n\n\tduAll := []*disk.UsageStat{\n\t\t{\n\t\t\tPath:        \"/\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t\t{\n\t\t\tPath:        \"/home\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       256,\n\t\t\tFree:        46,\n\t\t\tUsed:        200,\n\t\t\tInodesTotal: 2468,\n\t\t\tInodesFree:  468,\n\t\t\tInodesUsed:  2000,\n\t\t},\n\t\t{\n\t\t\tPath:        \"/var/rootbind\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t}\n\tduMountFiltered := []*disk.UsageStat{\n\t\t{\n\t\t\tPath:        \"/\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t}\n\tduOptFiltered := []*disk.UsageStat{\n\t\t{\n\t\t\tPath:        \"/\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       128,\n\t\t\tFree:        23,\n\t\t\tUsed:        100,\n\t\t\tInodesTotal: 1234,\n\t\t\tInodesFree:  234,\n\t\t\tInodesUsed:  1000,\n\t\t},\n\t\t{\n\t\t\tPath:        \"/home\",\n\t\t\tFstype:      \"ext4\",\n\t\t\tTotal:       256,\n\t\t\tFree:        46,\n\t\t\tUsed:        200,\n\t\t\tInodesTotal: 2468,\n\t\t\tInodesFree:  468,\n\t\t\tInodesUsed:  2000,\n\t\t},\n\t}\n\n\tpsAll := []*disk.PartitionStat{\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\"},\n\t\t},\n\t\t{\n\t\t\tDevice:     \"/dev/sdb\",\n\t\t\tMountpoint: \"/home\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"rw\", \"noatime\", \"nodiratime\", \"errors=remount-ro\"},\n\t\t},\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/var/rootbind\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\", \"bind\"},\n\t\t},\n\t}\n\n\tpsMountFiltered := []*disk.PartitionStat{\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\"},\n\t\t},\n\t}\n\tpsOptFiltered := []*disk.PartitionStat{\n\t\t{\n\t\t\tDevice:     \"/dev/sda\",\n\t\t\tMountpoint: \"/\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"ro\", \"noatime\", \"nodiratime\"},\n\t\t},\n\t\t{\n\t\t\tDevice:     \"/dev/sdb\",\n\t\t\tMountpoint: \"/home\",\n\t\t\tFstype:     \"ext4\",\n\t\t\tOpts:       []string{\"rw\", \"noatime\", \"nodiratime\", \"errors=remount-ro\"},\n\t\t},\n\t}\n\n\tmps.On(\"DiskUsage\", []string(nil), []string(nil), []string(nil)).Return(duAll, psAll, nil)\n\tmps.On(\"DiskUsage\", []string{\"/\", \"/dev\"}, []string(nil), []string(nil)).Return(duMountFiltered, psMountFiltered, nil)\n\tmps.On(\"DiskUsage\", []string{\"/\", \"/home\", \"/var/rootbind\"}, []string(nil), []string(nil)).Return(duAll, psAll, nil)\n\tmps.On(\"DiskUsage\", []string(nil), []string{\"bind\"}, []string(nil)).Return(duOptFiltered, psOptFiltered, nil)\n\n\terr = (&Disk{ps: &mps}).Gather(&acc)\n\trequire.NoError(t, err)\n\n\tnumDiskMetrics := acc.NFields()\n\texpectedAllDiskMetrics := 24\n\trequire.Equal(t, expectedAllDiskMetrics, numDiskMetrics)\n\n\ttags1 := map[string]string{\n\t\t\"path\":   \"/\",\n\t\t\"fstype\": \"ext4\",\n\t\t\"device\": \"sda\",\n\t\t\"mode\":   \"ro\",\n\t}\n\ttags2 := map[string]string{\n\t\t\"path\":   \"/home\",\n\t\t\"fstype\": \"ext4\",\n\t\t\"device\": \"sdb\",\n\t\t\"mode\":   \"rw\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"total\":               uint64(128),\n\t\t\"used\":                uint64(100),\n\t\t\"free\":                uint64(23),\n\t\t\"inodes_total\":        uint64(1234),\n\t\t\"inodes_free\":         uint64(234),\n\t\t\"inodes_used\":         uint64(1000),\n\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t}\n\tfields2 := map[string]interface{}{\n\t\t\"total\":               uint64(256),\n\t\t\"used\":                uint64(200),\n\t\t\"free\":                uint64(46),\n\t\t\"inodes_total\":        uint64(2468),\n\t\t\"inodes_free\":         uint64(468),\n\t\t\"inodes_used\":         uint64(2000),\n\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"disk\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"disk\", fields2, tags2)\n\n\t// We expect 7 more DiskMetrics to show up with an explicit match on \"/\"\n\t// and /home and /var/rootbind not matching the /dev in MountPoints\n\terr = (&Disk{ps: &mps, MountPoints: []string{\"/\", \"/dev\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8, acc.NFields())\n\n\t// We should see all the diskpoints as MountPoints includes both\n\t// /, /home, and /var/rootbind\n\terr = (&Disk{ps: &mps, MountPoints: []string{\"/\", \"/home\", \"/var/rootbind\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8*4, acc.NFields())\n\n\t// We should see all the mounts as MountPoints except the bind mound\n\terr = (&Disk{ps: &mps, IgnoreMountOpts: []string{\"bind\"}}).Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedAllDiskMetrics+8*6, acc.NFields())\n}\n\nfunc TestDiskUsageIssues(t *testing.T) {\n\tif runtime.GOOS != \"linux\" {\n\t\tt.Skip(\"Skipping due to Linux-only test-cases...\")\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\tprefix   string\n\t\tdu       disk.UsageStat\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:   \"success\",\n\t\t\tprefix: \"\",\n\t\t\tdu: disk.UsageStat{\n\t\t\t\tTotal:       256,\n\t\t\t\tFree:        46,\n\t\t\t\tUsed:        200,\n\t\t\t\tInodesTotal: 2468,\n\t\t\t\tInodesFree:  468,\n\t\t\t\tInodesUsed:  2000,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"disk\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"tmpfs\",\n\t\t\t\t\t\t\"fstype\": \"tmpfs\",\n\t\t\t\t\t\t\"mode\":   \"rw\",\n\t\t\t\t\t\t\"path\":   \"/tmp\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"total\":               uint64(256),\n\t\t\t\t\t\t\"used\":                uint64(200),\n\t\t\t\t\t\t\"free\":                uint64(46),\n\t\t\t\t\t\t\"inodes_total\":        uint64(2468),\n\t\t\t\t\t\t\"inodes_free\":         uint64(468),\n\t\t\t\t\t\t\"inodes_used\":         uint64(2000),\n\t\t\t\t\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\t\t\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"disk\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"nvme0n1p4\",\n\t\t\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\t\t\"mode\":   \"rw\",\n\t\t\t\t\t\t\"path\":   \"/\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"total\":               uint64(256),\n\t\t\t\t\t\t\"used\":                uint64(200),\n\t\t\t\t\t\t\"free\":                uint64(46),\n\t\t\t\t\t\t\"inodes_total\":        uint64(2468),\n\t\t\t\t\t\t\"inodes_free\":         uint64(468),\n\t\t\t\t\t\t\"inodes_used\":         uint64(2000),\n\t\t\t\t\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\t\t\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"issue 10297\",\n\t\t\tprefix: \"/host\",\n\t\t\tdu: disk.UsageStat{\n\t\t\t\tTotal:       256,\n\t\t\t\tFree:        46,\n\t\t\t\tUsed:        200,\n\t\t\t\tInodesTotal: 2468,\n\t\t\t\tInodesFree:  468,\n\t\t\t\tInodesUsed:  2000,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"disk\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"sda1\",\n\t\t\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\t\t\"label\":  \"root\",\n\t\t\t\t\t\t\"mode\":   \"rw\",\n\t\t\t\t\t\t\"path\":   \"/\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"total\":               uint64(256),\n\t\t\t\t\t\t\"used\":                uint64(200),\n\t\t\t\t\t\t\"free\":                uint64(46),\n\t\t\t\t\t\t\"inodes_total\":        uint64(2468),\n\t\t\t\t\t\t\"inodes_free\":         uint64(468),\n\t\t\t\t\t\t\"inodes_used\":         uint64(2000),\n\t\t\t\t\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\t\t\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"disk\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"sdb\",\n\t\t\t\t\t\t\"fstype\": \"ext4\",\n\t\t\t\t\t\t\"label\":  \"storage\",\n\t\t\t\t\t\t\"mode\":   \"rw\",\n\t\t\t\t\t\t\"path\":   \"/mnt/storage\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"total\":               uint64(256),\n\t\t\t\t\t\t\"used\":                uint64(200),\n\t\t\t\t\t\t\"free\":                uint64(46),\n\t\t\t\t\t\t\"inodes_total\":        uint64(2468),\n\t\t\t\t\t\t\"inodes_free\":         uint64(468),\n\t\t\t\t\t\t\"inodes_used\":         uint64(2000),\n\t\t\t\t\t\t\"used_percent\":        float64(81.30081300813008),\n\t\t\t\t\t\t\"inodes_used_percent\": float64(81.03727714748784),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the environment\n\t\t\thostMountPrefix := tt.prefix\n\n\t\t\thostProcPrefix, err := filepath.Abs(filepath.Join(\"testdata\", strings.ReplaceAll(tt.name, \" \", \"_\"), \"proc\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\thostSysPrefix, err := filepath.Abs(filepath.Join(\"testdata\", strings.ReplaceAll(tt.name, \" \", \"_\"), \"sys\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Get the partitions in the test-case\n\t\t\tos.Clearenv()\n\t\t\tt.Setenv(\"HOST_PROC\", hostProcPrefix)\n\t\t\tt.Setenv(\"HOST_SYS\", hostSysPrefix)\n\n\t\t\tpartitions, err := disk.Partitions(true)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Mock the disk usage\n\t\t\tmck := &mock.Mock{}\n\t\t\tmps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}\n\t\t\tdefer mps.AssertExpectations(t)\n\n\t\t\tmps.On(\"Partitions\", true).Return(partitions, nil)\n\n\t\t\tfor _, partition := range partitions {\n\t\t\t\tmountpoint := partition.Mountpoint\n\t\t\t\tif hostMountPrefix != \"\" {\n\t\t\t\t\tmountpoint = filepath.Join(hostMountPrefix, partition.Mountpoint)\n\t\t\t\t}\n\t\t\t\tdiskUsage := tt.du\n\t\t\t\tdiskUsage.Path = mountpoint\n\t\t\t\tdiskUsage.Fstype = partition.Fstype\n\t\t\t\tmps.On(\"PSDiskUsage\", mountpoint).Return(&diskUsage, nil)\n\t\t\t}\n\t\t\tmps.On(\"OSGetenv\", \"HOST_MOUNT_PREFIX\").Return(hostMountPrefix)\n\n\t\t\t// Setup the plugin and run the test\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := &Disk{ps: &mps}\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n\t\t})\n\t}\n\tos.Clearenv()\n}\n"
  },
  {
    "path": "plugins/inputs/disk/sample.conf",
    "content": "# Read metrics about disk usage by mount point\n[[inputs.disk]]\n  ## By default stats will be gathered for all mount points.\n  ## Set mount_points will restrict the stats to only the specified mount points.\n  # mount_points = [\"/\"]\n\n  ## Ignore mount points by filesystem type.\n  ignore_fs = [\"tmpfs\", \"devtmpfs\", \"devfs\", \"iso9660\", \"overlay\", \"aufs\", \"squashfs\"]\n\n  ## Ignore mount points by mount options.\n  ## The 'mount' command reports options of all mounts in parathesis.\n  ## Bind mounts can be ignored with the special 'bind' option.\n  # ignore_mount_opts = []\n"
  },
  {
    "path": "plugins/inputs/disk/testdata/issue_10297/proc/1/mountinfo",
    "content": "31 1 8:1 / / rw,relatime shared:1 - ext4 /dev/sda1 rw,discard,errors=remount-ro\n126 31 8:16 / /mnt/storage rw,relatime shared:67 - ext4 /dev/sdb rw,discard\n"
  },
  {
    "path": "plugins/inputs/disk/testdata/issue_10297/sys/block/sda1/dm/name",
    "content": "root\n"
  },
  {
    "path": "plugins/inputs/disk/testdata/issue_10297/sys/block/sdb/dm/name",
    "content": "storage\n"
  },
  {
    "path": "plugins/inputs/disk/testdata/success/proc/1/mountinfo",
    "content": "26 1 259:4 / / rw,relatime shared:1 - ext4 /dev/nvme0n1p4 rw\n39 26 0:32 / /tmp rw,nosuid,nodev shared:17 - tmpfs tmpfs rw,size=16427752k,nr_inodes=409600,inode64\n"
  },
  {
    "path": "plugins/inputs/diskio/README.md",
    "content": "# DiskIO Input Plugin\n\nThis plugin gathers metrics about disk traffic and timing.\n\n⭐ Telegraf v0.10.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about disk IO by device\n[[inputs.diskio]]\n  ## Devices to collect stats for\n  ## Wildcards are supported except for disk synonyms like '/dev/disk/by-id'.\n  ## ex. devices = [\"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  # devices = [\"*\"]\n\n  ## Skip gathering of the disk's serial numbers.\n  # skip_serial_number = true\n\n  ## Device metadata tags to add on systems supporting it (Linux only)\n  ## Use 'udevadm info -q property -n <device>' to get a list of properties.\n  ## Note: Most, but not all, udev properties can be accessed this way. Properties\n  ## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.\n  # device_tags = [\"ID_FS_TYPE\", \"ID_FS_USAGE\"]\n\n  ## Using the same metadata source as device_tags, you can also customize the\n  ## name of the device via templates.\n  ## The 'name_templates' parameter is a list of templates to try and apply to\n  ## the device. The template may contain variables in the form of '$PROPERTY' or\n  ## '${PROPERTY}'. The first template which does not contain any variables not\n  ## present for the device is used as the device name tag.\n  ## The typical use case is for LVM volumes, to get the VG/LV name instead of\n  ## the near-meaningless DM-0 name.\n  # name_templates = [\"$ID_FS_LABEL\",\"$DM_VG_NAME/$DM_LV_NAME\"]\n```\n\n### Docker container\n\nTo monitor the Docker engine host from within a container you will need to\nmount the host's filesystem into the container and set the `HOST_PROC`\nenvironment variable to the location of the `/proc` filesystem.  Additionally,\nit is required to use privileged mode to provide access to `/dev`.\n\nIf you are using the `device_tags` or `name_templates` options, you will need\nto bind mount `/run/udev` into the container.\n\n```shell\ndocker run --privileged -v /:/hostfs:ro -v /run/udev:/run/udev:ro -e HOST_PROC=/hostfs/proc telegraf\n```\n\n## Metrics\n\n- diskio\n  - tags:\n    - name (device name)\n    - serial (device serial number)\n  - fields:\n    - reads (integer, counter)\n    - writes (integer, counter)\n    - read_bytes (integer, counter, bytes)\n    - write_bytes (integer, counter, bytes)\n    - read_time (integer, counter, milliseconds)\n    - write_time (integer, counter, milliseconds)\n    - io_time (integer, counter, milliseconds)\n    - weighted_io_time (integer, counter, milliseconds)\n    - iops_in_progress (integer, gauge)\n    - merged_reads (integer, counter)\n    - merged_writes (integer, counter)\n    - io_util (float64, gauge, percent)\n    - io_await (float64, gauge, milliseconds)\n    - io_svctm (float64, gauge, milliseconds)\n\nOn linux these values correspond to the values in [`/proc/diskstats`][1] and\n[`/sys/block/<dev>/stat`][2].\n\n[1]: https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats\n\n[2]: https://www.kernel.org/doc/Documentation/block/stat.txt\n\n### `reads` & `writes`\n\nThese values increment when an I/O request completes.\n\n### `read_bytes` & `write_bytes`\n\nThese values count the number of bytes read from or written to this\nblock device.\n\n### `read_time` & `write_time`\n\nThese values count the number of milliseconds that I/O requests have\nwaited on this block device.  If there are multiple I/O requests waiting,\nthese values will increase at a rate greater than 1000/second; for\nexample, if 60 read requests wait for an average of 30 ms, the read_time\nfield will increase by 60*30 = 1800.\n\n### `io_time`\n\nThis value counts the number of milliseconds during which the device has\nhad I/O requests queued.\n\n### `weighted_io_time`\n\nThis value counts the number of milliseconds that I/O requests have waited\non this block device.  If there are multiple I/O requests waiting, this\nvalue will increase as the product of the number of milliseconds times the\nnumber of requests waiting (see `read_time` above for an example).\n\n### `iops_in_progress`\n\nThis value counts the number of I/O requests that have been issued to\nthe device driver but have not yet completed.  It does not include I/O\nrequests that are in the queue but not yet issued to the device driver.\n\n### `merged_reads` & `merged_writes`\n\nReads and writes which are adjacent to each other may be merged for\nefficiency.  Thus two 4K reads may become one 8K read before it is\nultimately handed to the disk, and so it will be counted (and queued)\nas only one I/O. These fields lets you know how often this was done.\n\n### `io_await`\n\nThe average time per I/O operation (ms)\n\n### `io_svctm`\n\nThe service time per I/O operation, excluding wait time (ms)\n\n### `io_util`\n\nThe percentage of time the disk was active (%)\n\n## Sample Queries\n\n### Calculate percent IO utilization per disk and host\n\n```sql\nSELECT non_negative_derivative(last(\"io_time\"),1ms) FROM \"diskio\" WHERE time > now() - 30m GROUP BY \"host\",\"name\",time(60s)\n```\n\n### Calculate average queue depth\n\n`iops_in_progress` will give you an instantaneous value. This will give you the\naverage between polling intervals.\n\n```sql\nSELECT non_negative_derivative(last(\"weighted_io_time\"),1ms) from \"diskio\" WHERE time > now() - 30m GROUP BY \"host\",\"name\",time(60s)\n```\n\n## Example Output\n\n```text\ndiskio,name=sda1 merged_reads=0i,reads=2353i,writes=10i,write_bytes=2117632i,write_time=49i,io_time=1271i,weighted_io_time=1350i,read_bytes=31350272i,read_time=1303i,iops_in_progress=0i,merged_writes=0i 1578326400000000000\ndiskio,name=centos/var_log reads=1063077i,writes=591025i,read_bytes=139325491712i,write_bytes=144233131520i,read_time=650221i,write_time=24368817i,io_time=852490i,weighted_io_time=25037394i,iops_in_progress=1i,merged_reads=0i,merged_writes=0i 1578326400000000000\ndiskio,name=sda write_time=49i,io_time=1317i,weighted_io_time=1404i,reads=2495i,read_time=1357i,write_bytes=2117632i,iops_in_progress=0i,merged_reads=0i,merged_writes=0i,writes=10i,read_bytes=38956544i 1578326400000000000\n```\n\n```text\ndiskio,name=sda io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000\ndiskio,name=sda1 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000\ndiskio,name=sda2 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000\n```\n"
  },
  {
    "path": "plugins/inputs/diskio/diskio.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage diskio\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tvarRegex           = regexp.MustCompile(`\\$(?:\\w+|\\{\\w+\\})`)\n\tserialTagSanitizer = strings.NewReplacer(\"\\n\", \"\", \"\\r\", \"\")\n)\n\ntype DiskIO struct {\n\tDevices          []string        `toml:\"devices\"`\n\tDeviceTags       []string        `toml:\"device_tags\"`\n\tNameTemplates    []string        `toml:\"name_templates\"`\n\tSkipSerialNumber bool            `toml:\"skip_serial_number\"`\n\tLog              telegraf.Logger `toml:\"-\"`\n\n\tps                psutil.PS\n\tinfoCache         map[string]diskInfoCache\n\tdeviceFilter      filter.Filter\n\twarnDiskName      map[string]bool\n\twarnDiskTags      map[string]bool\n\tlastIOCounterStat map[string]disk.IOCountersStat\n\tlastCollectTime   time.Time\n}\n\nfunc (*DiskIO) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *DiskIO) Init() error {\n\tfor _, device := range d.Devices {\n\t\tif hasMeta(device) {\n\t\t\tdeviceFilter, err := filter.Compile(d.Devices)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error compiling device pattern: %w\", err)\n\t\t\t}\n\t\t\td.deviceFilter = deviceFilter\n\t\t}\n\t}\n\n\td.infoCache = make(map[string]diskInfoCache)\n\td.warnDiskName = make(map[string]bool)\n\td.warnDiskTags = make(map[string]bool)\n\td.lastIOCounterStat = make(map[string]disk.IOCountersStat)\n\n\treturn nil\n}\n\nfunc (d *DiskIO) Gather(acc telegraf.Accumulator) error {\n\tvar devices []string\n\tif d.deviceFilter == nil {\n\t\tfor _, dev := range d.Devices {\n\t\t\tdevices = append(devices, resolveName(dev))\n\t\t}\n\t}\n\n\tdiskio, err := d.ps.DiskIO(devices)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting disk io info: %w\", err)\n\t}\n\tcollectTime := time.Now()\n\tfor k, io := range diskio {\n\t\tmatch := false\n\t\tif d.deviceFilter != nil && d.deviceFilter.Match(io.Name) {\n\t\t\tmatch = true\n\t\t}\n\n\t\ttags := make(map[string]string)\n\t\tvar devLinks []string\n\t\ttags[\"name\"], devLinks = d.diskName(io.Name)\n\n\t\tif wwid := getDeviceWWID(io.Name); wwid != \"\" {\n\t\t\ttags[\"wwid\"] = wwid\n\t\t}\n\n\t\tif d.deviceFilter != nil && !match {\n\t\t\tfor _, devLink := range devLinks {\n\t\t\t\tif d.deviceFilter.Match(devLink) {\n\t\t\t\t\tmatch = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !match {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tfor t, v := range d.diskTags(io.Name) {\n\t\t\ttags[t] = v\n\t\t}\n\n\t\tif !d.SkipSerialNumber {\n\t\t\tserial := sanitizeSerialNumber(io.SerialNumber)\n\t\t\tif len(serial) != 0 {\n\t\t\t\ttags[\"serial\"] = serial\n\t\t\t} else {\n\t\t\t\ttags[\"serial\"] = \"unknown\"\n\t\t\t}\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"reads\":            io.ReadCount,\n\t\t\t\"writes\":           io.WriteCount,\n\t\t\t\"read_bytes\":       io.ReadBytes,\n\t\t\t\"write_bytes\":      io.WriteBytes,\n\t\t\t\"read_time\":        io.ReadTime,\n\t\t\t\"write_time\":       io.WriteTime,\n\t\t\t\"io_time\":          io.IoTime,\n\t\t\t\"weighted_io_time\": io.WeightedIO,\n\t\t\t\"iops_in_progress\": io.IopsInProgress,\n\t\t\t\"merged_reads\":     io.MergedReadCount,\n\t\t\t\"merged_writes\":    io.MergedWriteCount,\n\t\t}\n\t\tif lastValue, exists := d.lastIOCounterStat[k]; exists {\n\t\t\t// Check for wrap around\n\t\t\twrap := io.ReadCount < lastValue.ReadCount || io.WriteCount < lastValue.WriteCount\n\t\t\twrap = wrap || io.ReadTime < lastValue.ReadTime || io.WriteTime < lastValue.WriteTime\n\t\t\twrap = wrap || io.IoTime < lastValue.IoTime\n\n\t\t\tif !wrap {\n\t\t\t\tdeltaRWCount := float64(io.ReadCount-lastValue.ReadCount) + float64(io.WriteCount-lastValue.WriteCount)\n\t\t\t\tdeltaRWTime := float64(io.ReadTime-lastValue.ReadTime) + float64(io.WriteTime-lastValue.WriteTime)\n\t\t\t\tdeltaIOTime := float64(io.IoTime - lastValue.IoTime)\n\n\t\t\t\tif deltaRWCount > 0 {\n\t\t\t\t\tfields[\"io_await\"] = deltaRWTime / deltaRWCount\n\t\t\t\t\tfields[\"io_svctm\"] = deltaIOTime / deltaRWCount\n\t\t\t\t}\n\n\t\t\t\titv := float64(collectTime.Sub(d.lastCollectTime).Milliseconds())\n\t\t\t\tif itv > 0 {\n\t\t\t\t\tfields[\"io_util\"] = 100 * deltaIOTime / itv\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tacc.AddCounter(\"diskio\", fields, tags)\n\t}\n\td.lastCollectTime = collectTime\n\td.lastIOCounterStat = diskio\n\treturn nil\n}\n\n// hasMeta reports whether s contains any special glob characters.\nfunc hasMeta(s string) bool {\n\treturn strings.ContainsAny(s, \"*?[\")\n}\n\nfunc sanitizeSerialNumber(serial string) string {\n\treturn strings.TrimSpace(serialTagSanitizer.Replace(serial))\n}\n\nfunc (d *DiskIO) diskName(devName string) (string, []string) {\n\tdi, err := d.diskInfo(devName)\n\tdevLinks := strings.Split(di[\"DEVLINKS\"], \" \")\n\tfor i, devLink := range devLinks {\n\t\tdevLinks[i] = strings.TrimPrefix(devLink, \"/dev/\")\n\t}\n\t// Return error after attempting to process some of the devlinks.\n\t// These could exist if we got further along the diskInfo call.\n\tif err != nil {\n\t\tif ok := d.warnDiskName[devName]; !ok {\n\t\t\td.warnDiskName[devName] = true\n\t\t\td.Log.Warnf(\"Unable to gather disk name for %q: %s\", devName, err)\n\t\t}\n\t\treturn devName, devLinks\n\t}\n\n\tif len(d.NameTemplates) == 0 {\n\t\treturn devName, devLinks\n\t}\n\n\tfor _, nt := range d.NameTemplates {\n\t\tmiss := false\n\t\tname := varRegex.ReplaceAllStringFunc(nt, func(sub string) string {\n\t\t\tsub = sub[1:] // strip leading '$'\n\t\t\tif sub[0] == '{' {\n\t\t\t\tsub = sub[1 : len(sub)-1] // strip leading & trailing '{' '}'\n\t\t\t}\n\t\t\tif v, ok := di[sub]; ok {\n\t\t\t\treturn v\n\t\t\t}\n\t\t\tmiss = true\n\t\t\treturn \"\"\n\t\t})\n\n\t\tif !miss {\n\t\t\treturn name, devLinks\n\t\t}\n\t}\n\n\treturn devName, devLinks\n}\n\nfunc (d *DiskIO) diskTags(devName string) map[string]string {\n\tif len(d.DeviceTags) == 0 {\n\t\treturn nil\n\t}\n\n\tdi, err := d.diskInfo(devName)\n\tif err != nil {\n\t\tif ok := d.warnDiskTags[devName]; !ok {\n\t\t\td.warnDiskTags[devName] = true\n\t\t\td.Log.Warnf(\"Unable to gather disk tags for %q: %s\", devName, err)\n\t\t}\n\t\treturn nil\n\t}\n\n\ttags := make(map[string]string, len(d.DeviceTags))\n\tfor _, dt := range d.DeviceTags {\n\t\tif v, ok := di[dt]; ok {\n\t\t\ttags[dt] = v\n\t\t}\n\t}\n\n\treturn tags\n}\n\nfunc init() {\n\tps := psutil.NewSystemPS()\n\tinputs.Add(\"diskio\", func() telegraf.Input {\n\t\treturn &DiskIO{ps: ps, SkipSerialNumber: true}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/diskio/diskio_linux.go",
    "content": "package diskio\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\ntype diskInfoCache struct {\n\tmodifiedAt   int64 // Unix Nano timestamp of the last modification of the device. This value is used to invalidate the cache\n\tudevDataPath string\n\tsysBlockPath string\n\tvalues       map[string]string\n}\n\nfunc (d *DiskIO) diskInfo(devName string) (map[string]string, error) {\n\t// Check if the device exists\n\tpath := \"/dev/\" + devName\n\tvar stat unix.Stat_t\n\tif err := unix.Stat(path, &stat); err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading %s: %w\", path, err)\n\t}\n\n\t// Check if we already got a cached and valid entry\n\tic, ok := d.infoCache[devName]\n\tif ok && stat.Mtim.Nano() == ic.modifiedAt {\n\t\treturn ic.values, nil\n\t}\n\n\t// Determine udev properties\n\tvar udevDataPath string\n\tif ok && len(ic.udevDataPath) > 0 {\n\t\t// We can reuse the udev data path from a \"previous\" entry.\n\t\t// This allows us to also \"poison\" it during test scenarios\n\t\tudevDataPath = ic.udevDataPath\n\t} else {\n\t\tmajor := unix.Major(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures\n\t\tminor := unix.Minor(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures\n\t\tudevDataPath = fmt.Sprintf(\"/run/udev/data/b%d:%d\", major, minor)\n\t\tif _, err := os.Stat(udevDataPath); err != nil {\n\t\t\t// This path failed, try the fallback .udev style (non-systemd)\n\t\t\tudevDataPath = \"/dev/.udev/db/block:\" + devName\n\t\t\tif _, err := os.Stat(udevDataPath); err != nil {\n\t\t\t\t// Giving up, cannot retrieve disk info\n\t\t\t\treturn nil, fmt.Errorf(\"error reading %s: %w\", udevDataPath, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tinfo, err := readUdevData(udevDataPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Read additional (optional) device properties\n\tvar sysBlockPath string\n\tif ok && len(ic.sysBlockPath) > 0 {\n\t\t// We can reuse the /sys block path from a \"previous\" entry.\n\t\t// This allows us to also \"poison\" it during test scenarios\n\t\tsysBlockPath = ic.sysBlockPath\n\t} else {\n\t\tsysBlockPath = \"/sys/class/block/\" + devName\n\t}\n\n\tdevInfo, err := readDevData(sysBlockPath)\n\tif err == nil {\n\t\tfor k, v := range devInfo {\n\t\t\tinfo[k] = v\n\t\t}\n\t} else if !errors.Is(err, os.ErrNotExist) {\n\t\treturn nil, err\n\t}\n\n\td.infoCache[devName] = diskInfoCache{\n\t\tmodifiedAt:   stat.Mtim.Nano(),\n\t\tudevDataPath: udevDataPath,\n\t\tvalues:       info,\n\t}\n\n\treturn info, nil\n}\n\nfunc readUdevData(path string) (map[string]string, error) {\n\t// Final open of the confirmed (or the previously detected/used) udev file\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\n\tinfo := make(map[string]string)\n\tscnr := bufio.NewScanner(f)\n\tvar devlinks bytes.Buffer\n\tfor scnr.Scan() {\n\t\tl := scnr.Text()\n\t\tif len(l) < 4 {\n\t\t\tcontinue\n\t\t}\n\t\tif l[:2] == \"S:\" {\n\t\t\tif devlinks.Len() > 0 {\n\t\t\t\tdevlinks.WriteString(\" \")\n\t\t\t}\n\t\t\tdevlinks.WriteString(\"/dev/\")\n\t\t\tdevlinks.WriteString(l[2:])\n\t\t\tcontinue\n\t\t}\n\t\tif l[:2] != \"E:\" {\n\t\t\tcontinue\n\t\t}\n\t\tkv := strings.SplitN(l[2:], \"=\", 2)\n\t\tif len(kv) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tinfo[kv[0]] = kv[1]\n\t}\n\n\tif devlinks.Len() > 0 {\n\t\tinfo[\"DEVLINKS\"] = devlinks.String()\n\t}\n\n\treturn info, nil\n}\n\nfunc readDevData(path string) (map[string]string, error) {\n\t// Open the file and read line-wise\n\tf, err := os.Open(filepath.Join(path, \"uevent\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\n\t// Read DEVNAME and DEVTYPE\n\tinfo := make(map[string]string)\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif !strings.HasPrefix(line, \"DEV\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tk, v, found := strings.Cut(line, \"=\")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\tinfo[strings.TrimSpace(k)] = strings.TrimSpace(v)\n\t}\n\tif d, found := info[\"DEVNAME\"]; found && !strings.HasPrefix(d, \"/dev\") {\n\t\tinfo[\"DEVNAME\"] = \"/dev/\" + d\n\t}\n\n\t// Find the DEVPATH property\n\tif devlnk, err := filepath.EvalSymlinks(filepath.Join(path, \"device\")); err == nil {\n\t\tdevlnk = filepath.Join(devlnk, filepath.Base(path))\n\t\tdevlnk = strings.TrimPrefix(devlnk, \"/sys\")\n\t\tinfo[\"DEVPATH\"] = devlnk\n\t}\n\n\treturn info, nil\n}\n\nfunc resolveName(name string) string {\n\tresolved, err := filepath.EvalSymlinks(name)\n\tif err == nil {\n\t\treturn resolved\n\t}\n\tif !errors.Is(err, fs.ErrNotExist) {\n\t\treturn name\n\t}\n\t// Try to prepend \"/dev\"\n\tresolved, err = filepath.EvalSymlinks(\"/dev/\" + name)\n\tif err != nil {\n\t\treturn name\n\t}\n\n\treturn resolved\n}\n\nfunc getDeviceWWID(name string) string {\n\tpath := fmt.Sprintf(\"/sys/block/%s/wwid\", filepath.Base(name))\n\tbuf, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSuffix(string(buf), \"\\n\")\n}\n"
  },
  {
    "path": "plugins/inputs/diskio/diskio_linux_test.go",
    "content": "//go:build linux\n\npackage diskio\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDiskInfo(t *testing.T) {\n\tplugin := &DiskIO{\n\t\tinfoCache: map[string]diskInfoCache{\n\t\t\t\"null\": {\n\t\t\t\tmodifiedAt:   0,\n\t\t\t\tudevDataPath: \"testdata/udev.txt\",\n\t\t\t\tsysBlockPath: \"testdata\",\n\t\t\t\tvalues:       map[string]string{},\n\t\t\t},\n\t\t},\n\t}\n\n\tdi, err := plugin.diskInfo(\"null\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"myval1\", di[\"MY_PARAM_1\"])\n\trequire.Equal(t, \"myval2\", di[\"MY_PARAM_2\"])\n\trequire.Equal(t, \"/dev/foo/bar/devlink /dev/foo/bar/devlink1\", di[\"DEVLINKS\"])\n}\n\n// DiskIOStats.diskName isn't a linux specific function, but dependent\n// functions are a no-op on non-Linux.\nfunc TestDiskIOStats_diskName(t *testing.T) {\n\ttests := []struct {\n\t\ttemplates []string\n\t\texpected  string\n\t}{\n\t\t{[]string{\"$MY_PARAM_1\"}, \"myval1\"},\n\t\t{[]string{\"${MY_PARAM_1}\"}, \"myval1\"},\n\t\t{[]string{\"x$MY_PARAM_1\"}, \"xmyval1\"},\n\t\t{[]string{\"x${MY_PARAM_1}x\"}, \"xmyval1x\"},\n\t\t{[]string{\"$MISSING\", \"$MY_PARAM_1\"}, \"myval1\"},\n\t\t{[]string{\"$MY_PARAM_1\", \"$MY_PARAM_2\"}, \"myval1\"},\n\t\t{[]string{\"$MISSING\"}, \"null\"},\n\t\t{[]string{\"$MY_PARAM_1/$MY_PARAM_2\"}, \"myval1/myval2\"},\n\t\t{[]string{\"$MY_PARAM_2/$MISSING\"}, \"null\"},\n\t}\n\n\tfor i, tc := range tests {\n\t\tt.Run(fmt.Sprintf(\"template %d\", i), func(t *testing.T) {\n\t\t\tplugin := DiskIO{\n\t\t\t\tNameTemplates: tc.templates,\n\t\t\t\tinfoCache: map[string]diskInfoCache{\n\t\t\t\t\t\"null\": {\n\t\t\t\t\t\tmodifiedAt:   0,\n\t\t\t\t\t\tudevDataPath: \"testdata/udev.txt\",\n\t\t\t\t\t\tsysBlockPath: \"testdata\",\n\t\t\t\t\t\tvalues:       map[string]string{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tname, _ := plugin.diskName(\"null\")\n\t\t\trequire.Equal(t, tc.expected, name, \"Templates: %#v\", tc.templates)\n\t\t})\n\t}\n}\n\n// DiskIOStats.diskTags isn't a linux specific function, but dependent\n// functions are a no-op on non-Linux.\nfunc TestDiskIOStats_diskTags(t *testing.T) {\n\tplugin := &DiskIO{\n\t\tDeviceTags: []string{\"MY_PARAM_2\"},\n\t\tinfoCache: map[string]diskInfoCache{\n\t\t\t\"null\": {\n\t\t\t\tmodifiedAt:   0,\n\t\t\t\tudevDataPath: \"testdata/udev.txt\",\n\t\t\t\tsysBlockPath: \"testdata\",\n\t\t\t\tvalues:       map[string]string{},\n\t\t\t},\n\t\t},\n\t}\n\tdt := plugin.diskTags(\"null\")\n\trequire.Equal(t, map[string]string{\"MY_PARAM_2\": \"myval2\"}, dt)\n}\n"
  },
  {
    "path": "plugins/inputs/diskio/diskio_other.go",
    "content": "//go:build !linux\n\npackage diskio\n\ntype diskInfoCache struct{}\n\nfunc (*DiskIO) diskInfo(_ string) (map[string]string, error) {\n\treturn nil, nil\n}\n\nfunc resolveName(name string) string {\n\treturn name\n}\n\nfunc getDeviceWWID(_ string) string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "plugins/inputs/diskio/diskio_test.go",
    "content": "package diskio\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/disk\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDiskIO(t *testing.T) {\n\ttype Result struct {\n\t\tstats map[string]disk.IOCountersStat\n\t\terr   error\n\t}\n\ttype Metric struct {\n\t\ttags   map[string]string\n\t\tfields map[string]interface{}\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\tdevices []string\n\t\tresult  Result\n\t\terr     error\n\t\tmetrics []Metric\n\t}{\n\t\t{\n\t\t\tname: \"minimal\",\n\t\t\tresult: Result{\n\t\t\t\tstats: map[string]disk.IOCountersStat{\n\t\t\t\t\t\"sda\": {\n\t\t\t\t\t\tReadCount:        888,\n\t\t\t\t\t\tWriteCount:       5341,\n\t\t\t\t\t\tReadBytes:        100000,\n\t\t\t\t\t\tWriteBytes:       200000,\n\t\t\t\t\t\tReadTime:         7123,\n\t\t\t\t\t\tWriteTime:        9087,\n\t\t\t\t\t\tMergedReadCount:  11,\n\t\t\t\t\t\tMergedWriteCount: 12,\n\t\t\t\t\t\tName:             \"sda\",\n\t\t\t\t\t\tIoTime:           123552,\n\t\t\t\t\t\tSerialNumber:     \"ab-123-ad\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terr: nil,\n\t\t\t},\n\t\t\terr: nil,\n\t\t\tmetrics: []Metric{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"name\":   \"sda\",\n\t\t\t\t\t\t\"serial\": \"ab-123-ad\",\n\t\t\t\t\t},\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"reads\":            uint64(888),\n\t\t\t\t\t\t\"writes\":           uint64(5341),\n\t\t\t\t\t\t\"read_bytes\":       uint64(100000),\n\t\t\t\t\t\t\"write_bytes\":      uint64(200000),\n\t\t\t\t\t\t\"read_time\":        uint64(7123),\n\t\t\t\t\t\t\"write_time\":       uint64(9087),\n\t\t\t\t\t\t\"io_time\":          uint64(123552),\n\t\t\t\t\t\t\"weighted_io_time\": uint64(0),\n\t\t\t\t\t\t\"iops_in_progress\": uint64(0),\n\t\t\t\t\t\t\"merged_reads\":     uint64(11),\n\t\t\t\t\t\t\"merged_writes\":    uint64(12),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"sanitize serial newlines\",\n\t\t\tresult: Result{\n\t\t\t\tstats: map[string]disk.IOCountersStat{\n\t\t\t\t\t\"sdb\": {\n\t\t\t\t\t\tReadCount:    1,\n\t\t\t\t\t\tWriteCount:   2,\n\t\t\t\t\t\tName:         \"sdb\",\n\t\t\t\t\t\tSerialNumber: \"INTEL SSDPE21K100GA \\n_PHKE831600AC100EGN \\n\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terr: nil,\n\t\t\t},\n\t\t\terr: nil,\n\t\t\tmetrics: []Metric{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"name\":   \"sdb\",\n\t\t\t\t\t\t\"serial\": \"INTEL SSDPE21K100GA _PHKE831600AC100EGN\",\n\t\t\t\t\t},\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"reads\": uint64(1),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"glob device\",\n\t\t\tdevices: []string{\"sd*\"},\n\t\t\tresult: Result{\n\t\t\t\tstats: map[string]disk.IOCountersStat{\n\t\t\t\t\t\"sda\": {\n\t\t\t\t\t\tName:      \"sda\",\n\t\t\t\t\t\tReadCount: 42,\n\t\t\t\t\t},\n\t\t\t\t\t\"vda\": {\n\t\t\t\t\t\tName:      \"vda\",\n\t\t\t\t\t\tReadCount: 42,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\terr: nil,\n\t\t\t},\n\t\t\terr: nil,\n\t\t\tmetrics: []Metric{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"name\":   \"sda\",\n\t\t\t\t\t\t\"serial\": \"unknown\",\n\t\t\t\t\t},\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"reads\": uint64(42),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar mps psutil.MockPS\n\t\t\tmps.On(\"DiskIO\").Return(tt.result.stats, tt.result.err)\n\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\tdiskio := &DiskIO{\n\t\t\t\tLog:     testutil.Logger{},\n\t\t\t\tps:      &mps,\n\t\t\t\tDevices: tt.devices,\n\t\t\t}\n\t\t\trequire.NoError(t, diskio.Init())\n\t\t\terr := diskio.Gather(&acc)\n\t\t\trequire.Equal(t, tt.err, err)\n\n\t\t\tfor _, metric := range tt.metrics {\n\t\t\t\tfor k, v := range metric.fields {\n\t\t\t\t\trequire.True(t, acc.HasPoint(\"diskio\", metric.tags, k, v),\n\t\t\t\t\t\t\"missing point: diskio %v %q: %v\", metric.tags, k, v)\n\t\t\t\t}\n\t\t\t}\n\t\t\trequire.Len(t, tt.metrics, int(acc.NMetrics()), \"unexpected number of metrics\")\n\t\t\trequire.True(t, mps.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc TestDiskIOUtil(t *testing.T) {\n\tcts := map[string]disk.IOCountersStat{\n\t\t\"sda\": {\n\t\t\tReadCount:        888,\n\t\t\tWriteCount:       5341,\n\t\t\tReadBytes:        100000,\n\t\t\tWriteBytes:       200000,\n\t\t\tReadTime:         7123,\n\t\t\tWriteTime:        9087,\n\t\t\tMergedReadCount:  11,\n\t\t\tMergedWriteCount: 12,\n\t\t\tName:             \"sda\",\n\t\t\tIoTime:           123552,\n\t\t\tSerialNumber:     \"ab-123-ad\",\n\t\t},\n\t}\n\n\tcts2 := map[string]disk.IOCountersStat{\n\t\t\"sda\": {\n\t\t\tReadCount:        1000,\n\t\t\tWriteCount:       6000,\n\t\t\tReadBytes:        200000,\n\t\t\tWriteBytes:       300000,\n\t\t\tReadTime:         8123,\n\t\t\tWriteTime:        9187,\n\t\t\tMergedReadCount:  16,\n\t\t\tMergedWriteCount: 30,\n\t\t\tName:             \"sda\",\n\t\t\tIoTime:           163552,\n\t\t\tSerialNumber:     \"ab-123-ad\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\tvar mps psutil.MockPS\n\tmps.On(\"DiskIO\").Return(cts, nil)\n\tdiskio := &DiskIO{\n\t\tLog:     testutil.Logger{},\n\t\tDevices: []string{\"sd*\"},\n\t\tps:      &mps,\n\t}\n\trequire.NoError(t, diskio.Init())\n\t// gather\n\trequire.NoError(t, diskio.Gather(&acc))\n\t// sleep\n\ttime.Sleep(1 * time.Second)\n\t// gather twice\n\tmps2 := psutil.MockPS{}\n\tmps2.On(\"DiskIO\").Return(cts2, nil)\n\tdiskio.ps = &mps2\n\n\terr := diskio.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasField(\"diskio\", \"io_util\"), \"miss io util\")\n\trequire.True(t, acc.HasField(\"diskio\", \"io_svctm\"), \"miss io_svctm\")\n\trequire.True(t, acc.HasField(\"diskio\", \"io_await\"), \"miss io_await\")\n\n\trequire.True(t, acc.HasFloatField(\"diskio\", \"io_util\"), \"io_util not have value\")\n\trequire.True(t, acc.HasFloatField(\"diskio\", \"io_svctm\"), \"io_svctm not have value\")\n\trequire.True(t, acc.HasFloatField(\"diskio\", \"io_await\"), \"io_await not have value\")\n}\n\nfunc TestCounterWraparound(t *testing.T) {\n\tcts := map[string]disk.IOCountersStat{\n\t\t\"sda\": {\n\t\t\tReadCount:  1000,\n\t\t\tWriteCount: 2000,\n\t\t\tReadTime:   8000,\n\t\t\tWriteTime:  9000,\n\t\t\tIoTime:     30000,\n\t\t\tName:       \"sda\",\n\t\t},\n\t}\n\n\t// Simulate wraparound - counters decrease significantly\n\tcts2 := map[string]disk.IOCountersStat{\n\t\t\"sda\": {\n\t\t\tReadCount:  100,  // wrapped around\n\t\t\tWriteCount: 200,  // wrapped around\n\t\t\tReadTime:   1000, // wrapped around\n\t\t\tWriteTime:  1500, // wrapped around\n\t\t\tIoTime:     3000, // wrapped around\n\t\t\tName:       \"sda\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\tvar mps psutil.MockPS\n\tmps.On(\"DiskIO\").Return(cts, nil)\n\tdiskio := &DiskIO{\n\t\tLog:     testutil.Logger{},\n\t\tDevices: []string{\"sda\"},\n\t\tps:      &mps,\n\t}\n\trequire.NoError(t, diskio.Init())\n\n\t// First gather to establish baseline\n\trequire.NoError(t, diskio.Gather(&acc))\n\n\t// Second gather with wrapped counters\n\tmps2 := psutil.MockPS{}\n\tmps2.On(\"DiskIO\").Return(cts2, nil)\n\tdiskio.ps = &mps2\n\n\trequire.NoError(t, diskio.Gather(&acc))\n\n\t// Should NOT have calculated fields due to wraparound detection\n\trequire.False(t, acc.HasFloatField(\"diskio\", \"io_util\"), \"io_util should not be present on wraparound\")\n\trequire.False(t, acc.HasFloatField(\"diskio\", \"io_svctm\"), \"io_svctm should not be present on wraparound\")\n\trequire.False(t, acc.HasFloatField(\"diskio\", \"io_await\"), \"io_await should not be present on wraparound\")\n\n\t// But basic counter fields should still be present\n\trequire.True(t, acc.HasField(\"diskio\", \"reads\"), \"reads should be present\")\n\trequire.True(t, acc.HasField(\"diskio\", \"writes\"), \"writes should be present\")\n}\n"
  },
  {
    "path": "plugins/inputs/diskio/sample.conf",
    "content": "# Read metrics about disk IO by device\n[[inputs.diskio]]\n  ## Devices to collect stats for\n  ## Wildcards are supported except for disk synonyms like '/dev/disk/by-id'.\n  ## ex. devices = [\"sda\", \"sdb\", \"vd*\", \"/dev/disk/by-id/nvme-eui.00123deadc0de123\"]\n  # devices = [\"*\"]\n\n  ## Skip gathering of the disk's serial numbers.\n  # skip_serial_number = true\n\n  ## Device metadata tags to add on systems supporting it (Linux only)\n  ## Use 'udevadm info -q property -n <device>' to get a list of properties.\n  ## Note: Most, but not all, udev properties can be accessed this way. Properties\n  ## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.\n  # device_tags = [\"ID_FS_TYPE\", \"ID_FS_USAGE\"]\n\n  ## Using the same metadata source as device_tags, you can also customize the\n  ## name of the device via templates.\n  ## The 'name_templates' parameter is a list of templates to try and apply to\n  ## the device. The template may contain variables in the form of '$PROPERTY' or\n  ## '${PROPERTY}'. The first template which does not contain any variables not\n  ## present for the device is used as the device name tag.\n  ## The typical use case is for LVM volumes, to get the VG/LV name instead of\n  ## the near-meaningless DM-0 name.\n  # name_templates = [\"$ID_FS_LABEL\",\"$DM_VG_NAME/$DM_LV_NAME\"]\n"
  },
  {
    "path": "plugins/inputs/diskio/testdata/udev.txt",
    "content": "E:MY_PARAM_1=myval1\nE:MY_PARAM_2=myval2\nS:foo/bar/devlink\nS:foo/bar/devlink1"
  },
  {
    "path": "plugins/inputs/diskio/testdata/uevent",
    "content": "MAJOR=259\nMINOR=1\nDEVNAME=null\nDEVTYPE=disk\nDISKSEQ=2\n"
  },
  {
    "path": "plugins/inputs/disque/README.md",
    "content": "# Disque Input Plugin\n\nThis plugin gathers data from a [Disque][disque] instance, an experimental\ndistributed, in-memory, message broker.\n\n⭐ Telegraf v0.10.0\n🏷️ messaging\n💻 all\n\n[disque]: https://github.com/antirez/disque\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many disque servers\n[[inputs.disque]]\n  ## An array of URI to gather stats about. Specify an ip or hostname\n  ## with optional port and password.\n  ## ie disque://localhost, disque://10.10.3.33:18832, 10.0.0.1:10000, etc.\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n```\n\n## Metrics\n\n- disque\n  - disque_host\n    - uptime_in_seconds\n    - connected_clients\n    - blocked_clients\n    - used_memory\n    - used_memory_rss\n    - used_memory_peak\n    - total_connections_received\n    - total_commands_processed\n    - instantaneous_ops_per_sec\n    - latest_fork_usec\n    - mem_fragmentation_ratio\n    - used_cpu_sys\n    - used_cpu_user\n    - used_cpu_sys_children\n    - used_cpu_user_children\n    - registered_jobs\n    - registered_queues\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/disque/disque.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage disque\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultTimeout = 5 * time.Second\n\ttracking       = map[string]string{\n\t\t\"uptime_in_seconds\":          \"uptime\",\n\t\t\"connected_clients\":          \"clients\",\n\t\t\"blocked_clients\":            \"blocked_clients\",\n\t\t\"used_memory\":                \"used_memory\",\n\t\t\"used_memory_rss\":            \"used_memory_rss\",\n\t\t\"used_memory_peak\":           \"used_memory_peak\",\n\t\t\"total_connections_received\": \"total_connections_received\",\n\t\t\"total_commands_processed\":   \"total_commands_processed\",\n\t\t\"instantaneous_ops_per_sec\":  \"instantaneous_ops_per_sec\",\n\t\t\"latest_fork_usec\":           \"latest_fork_usec\",\n\t\t\"mem_fragmentation_ratio\":    \"mem_fragmentation_ratio\",\n\t\t\"used_cpu_sys\":               \"used_cpu_sys\",\n\t\t\"used_cpu_user\":              \"used_cpu_user\",\n\t\t\"used_cpu_sys_children\":      \"used_cpu_sys_children\",\n\t\t\"used_cpu_user_children\":     \"used_cpu_user_children\",\n\t\t\"registered_jobs\":            \"registered_jobs\",\n\t\t\"registered_queues\":          \"registered_queues\",\n\t}\n\terrProtocol = errors.New(\"disque protocol error\")\n)\n\nconst (\n\tdefaultPort = \"7711\"\n)\n\ntype Disque struct {\n\tServers []string `toml:\"servers\"`\n\n\tc net.Conn\n}\n\nfunc (*Disque) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *Disque) Gather(acc telegraf.Accumulator) error {\n\tif len(d.Servers) == 0 {\n\t\taddress := &url.URL{\n\t\t\tHost: \":\" + defaultPort,\n\t\t}\n\t\treturn d.gatherServer(address, acc)\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, serv := range d.Servers {\n\t\tu, err := url.Parse(serv)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse to address %q: %w\", serv, err))\n\t\t\tcontinue\n\t\t} else if u.Scheme == \"\" {\n\t\t\t// fallback to simple string based address (i.e. \"10.0.0.1:10000\")\n\t\t\tu.Scheme = \"tcp\"\n\t\t\tu.Host = serv\n\t\t\tu.Path = \"\"\n\t\t}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(d.gatherServer(u, acc))\n\t\t}()\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (d *Disque) gatherServer(addr *url.URL, acc telegraf.Accumulator) error {\n\tif d.c == nil {\n\t\t_, _, err := net.SplitHostPort(addr.Host)\n\t\tif err != nil {\n\t\t\taddr.Host = addr.Host + \":\" + defaultPort\n\t\t}\n\n\t\tc, err := net.DialTimeout(\"tcp\", addr.Host, defaultTimeout)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to connect to disque server %q: %w\", addr.Host, err)\n\t\t}\n\n\t\tif addr.User != nil {\n\t\t\tpwd, set := addr.User.Password()\n\t\t\tif set && pwd != \"\" {\n\t\t\t\tif _, err := fmt.Fprintf(c, \"AUTH %s\\r\\n\", pwd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tr := bufio.NewReader(c)\n\n\t\t\t\tline, err := r.ReadString('\\n')\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif line[0] != '+' {\n\t\t\t\t\treturn errors.New(strings.TrimSpace(line)[1:])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\td.c = c\n\t}\n\n\t// Extend connection\n\tif err := d.c.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := d.c.Write([]byte(\"info\\r\\n\")); err != nil {\n\t\treturn err\n\t}\n\n\tr := bufio.NewReader(d.c)\n\n\tline, err := r.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif line[0] != '$' {\n\t\treturn fmt.Errorf(\"bad line start: %w\", errProtocol)\n\t}\n\n\tline = strings.TrimSpace(line)\n\n\tszStr := line[1:]\n\n\tsz, err := strconv.Atoi(szStr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bad size string <<%s>>: %w\", szStr, errProtocol)\n\t}\n\n\tvar read int\n\n\tfields := make(map[string]interface{})\n\ttags := map[string]string{\"disque_host\": addr.String()}\n\tfor read < sz {\n\t\tline, err := r.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tread += len(line)\n\n\t\tif len(line) == 1 || line[0] == '#' {\n\t\t\tcontinue\n\t\t}\n\n\t\tparts := strings.SplitN(line, \":\", 2)\n\n\t\tname := parts[0]\n\n\t\tmetric, ok := tracking[name]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tval := strings.TrimSpace(parts[1])\n\n\t\tival, err := strconv.ParseUint(val, 10, 64)\n\t\tif err == nil {\n\t\t\tfields[metric] = ival\n\t\t\tcontinue\n\t\t}\n\n\t\tfval, err := strconv.ParseFloat(val, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfields[metric] = fval\n\t}\n\tacc.AddFields(\"disque\", fields, tags)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"disque\", func() telegraf.Input {\n\t\treturn &Disque{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/disque/disque_test.go",
    "content": "package disque\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDisqueGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tl, err := net.Listen(\"tcp\", \"localhost:0\")\n\trequire.NoError(t, err)\n\n\tdefer l.Close()\n\n\tgo func() {\n\t\tc, err := l.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tbuf := bufio.NewReader(c)\n\n\t\tfor {\n\t\t\tline, err := buf.ReadString('\\n')\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif line != \"info\\r\\n\" {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif _, err := fmt.Fprintf(c, \"$%d\\n\", len(testOutput)); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif _, err := c.Write([]byte(testOutput)); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\taddr := \"disque://\" + l.Addr().String()\n\n\tr := &Disque{\n\t\tServers: []string{addr},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(r.Gather)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"uptime\":                     uint64(1452705),\n\t\t\"clients\":                    uint64(31),\n\t\t\"blocked_clients\":            uint64(13),\n\t\t\"used_memory\":                uint64(1840104),\n\t\t\"used_memory_rss\":            uint64(3227648),\n\t\t\"used_memory_peak\":           uint64(89603656),\n\t\t\"total_connections_received\": uint64(5062777),\n\t\t\"total_commands_processed\":   uint64(12308396),\n\t\t\"instantaneous_ops_per_sec\":  uint64(18),\n\t\t\"latest_fork_usec\":           uint64(1644),\n\t\t\"registered_jobs\":            uint64(360),\n\t\t\"registered_queues\":          uint64(12),\n\t\t\"mem_fragmentation_ratio\":    float64(1.75),\n\t\t\"used_cpu_sys\":               float64(19585.73),\n\t\t\"used_cpu_user\":              float64(11255.96),\n\t\t\"used_cpu_sys_children\":      float64(1.75),\n\t\t\"used_cpu_user_children\":     float64(1.91),\n\t}\n\tacc.AssertContainsFields(t, \"disque\", fields)\n}\n\nfunc TestDisqueCanPullStatsFromMultipleServersIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tl, err := net.Listen(\"tcp\", \"localhost:0\")\n\trequire.NoError(t, err)\n\n\tdefer l.Close()\n\n\tgo func() {\n\t\tc, err := l.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tbuf := bufio.NewReader(c)\n\n\t\tfor {\n\t\t\tline, err := buf.ReadString('\\n')\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif line != \"info\\r\\n\" {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif _, err := fmt.Fprintf(c, \"$%d\\n\", len(testOutput)); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif _, err := c.Write([]byte(testOutput)); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\taddr := \"disque://\" + l.Addr().String()\n\n\tr := &Disque{\n\t\tServers: []string{addr},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(r.Gather)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"uptime\":                     uint64(1452705),\n\t\t\"clients\":                    uint64(31),\n\t\t\"blocked_clients\":            uint64(13),\n\t\t\"used_memory\":                uint64(1840104),\n\t\t\"used_memory_rss\":            uint64(3227648),\n\t\t\"used_memory_peak\":           uint64(89603656),\n\t\t\"total_connections_received\": uint64(5062777),\n\t\t\"total_commands_processed\":   uint64(12308396),\n\t\t\"instantaneous_ops_per_sec\":  uint64(18),\n\t\t\"latest_fork_usec\":           uint64(1644),\n\t\t\"registered_jobs\":            uint64(360),\n\t\t\"registered_queues\":          uint64(12),\n\t\t\"mem_fragmentation_ratio\":    float64(1.75),\n\t\t\"used_cpu_sys\":               float64(19585.73),\n\t\t\"used_cpu_user\":              float64(11255.96),\n\t\t\"used_cpu_sys_children\":      float64(1.75),\n\t\t\"used_cpu_user_children\":     float64(1.91),\n\t}\n\tacc.AssertContainsFields(t, \"disque\", fields)\n}\n\nconst testOutput = `# Server\ndisque_version:0.0.1\ndisque_git_sha1:b5247598\ndisque_git_dirty:0\ndisque_build_id:379fda78983a60c6\nos:Linux 3.13.0-44-generic x86_64\narch_bits:64\nmultiplexing_api:epoll\ngcc_version:4.8.2\nprocess_id:32420\nrun_id:1cfdfa4c6bc3f285182db5427522a8a4c16e42e4\ntcp_port:7711\nuptime_in_seconds:1452705\nuptime_in_days:16\nhz:10\nconfig_file:/usr/local/etc/disque/disque.conf\n\n# Clients\nconnected_clients:31\nclient_longest_output_list:0\nclient_biggest_input_buf:0\nblocked_clients:13\n\n# Memory\nused_memory:1840104\nused_memory_human:1.75M\nused_memory_rss:3227648\nused_memory_peak:89603656\nused_memory_peak_human:85.45M\nmem_fragmentation_ratio:1.75\nmem_allocator:jemalloc-3.6.0\n\n# Jobs\nregistered_jobs:360\n\n# Queues\nregistered_queues:12\n\n# Persistence\nloading:0\naof_enabled:1\naof_state:on\naof_rewrite_in_progress:0\naof_rewrite_scheduled:0\naof_last_rewrite_time_sec:0\naof_current_rewrite_time_sec:-1\naof_last_bgrewrite_status:ok\naof_last_write_status:ok\naof_current_size:41952430\naof_base_size:9808\naof_pending_rewrite:0\naof_buffer_length:0\naof_rewrite_buffer_length:0\naof_pending_bio_fsync:0\naof_delayed_fsync:1\n\n# Stats\ntotal_connections_received:5062777\ntotal_commands_processed:12308396\ninstantaneous_ops_per_sec:18\ntotal_net_input_bytes:1346996528\ntotal_net_output_bytes:1967551763\ninstantaneous_input_kbps:1.38\ninstantaneous_output_kbps:1.78\nrejected_connections:0\nlatest_fork_usec:1644\n\n# CPU\nused_cpu_sys:19585.73\nused_cpu_user:11255.96\nused_cpu_sys_children:1.75\nused_cpu_user_children:1.91\n`\n"
  },
  {
    "path": "plugins/inputs/disque/sample.conf",
    "content": "# Read metrics from one or many disque servers\n[[inputs.disque]]\n  ## An array of URI to gather stats about. Specify an ip or hostname\n  ## with optional port and password.\n  ## ie disque://localhost, disque://10.10.3.33:18832, 10.0.0.1:10000, etc.\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost\"]\n"
  },
  {
    "path": "plugins/inputs/dmcache/README.md",
    "content": "# Device Mapper Cache Input Plugin\n\nThis plugin provide a native collection for dmsetup based statistics for\n[dm-cache][dmcache].\n\n> [!NOTE]\n> This plugin requires super-user permissions! Please make sure, Telegraf is\n> able to run `sudo /sbin/dmsetup status --target cache` without requiring a\n> password.\n\n⭐ Telegraf v1.3.0\n🏷️ system\n💻 linux\n\n[dmcache]: https://docs.kernel.org/admin-guide/device-mapper/cache.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Provide a native collection for dmsetup based statistics for dm-cache\n# This plugin ONLY supports Linux\n[[inputs.dmcache]]\n  ## Whether to report per-device stats or not\n  per_device = true\n```\n\n## Metrics\n\n- dmcache\n  - length\n  - target\n  - metadata_blocksize\n  - metadata_used\n  - metadata_total\n  - cache_blocksize\n  - cache_used\n  - cache_total\n  - read_hits\n  - read_misses\n  - write_hits\n  - write_misses\n  - demotions\n  - promotions\n  - dirty\n\n## Tags\n\n- All measurements have the following tags:\n  - device\n\n## Example Output\n\n```text\ndmcache,device=example cache_blocksize=0i,read_hits=995134034411520i,read_misses=916807089127424i,write_hits=195107267543040i,metadata_used=12861440i,write_misses=563725346013184i,promotions=3265223720960i,dirty=0i,metadata_blocksize=0i,cache_used=1099511627776ii,cache_total=0i,length=0i,metadata_total=1073741824i,demotions=3265223720960i 1491482035000000000\n```\n"
  },
  {
    "path": "plugins/inputs/dmcache/dmcache.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage dmcache\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype DMCache struct {\n\tPerDevice bool `toml:\"per_device\"`\n\n\tgetCurrentStatus func() ([]string, error)\n}\n\nfunc (*DMCache) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc init() {\n\tinputs.Add(\"dmcache\", func() telegraf.Input {\n\t\treturn &DMCache{\n\t\t\tPerDevice:        true,\n\t\t\tgetCurrentStatus: dmSetupStatus,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dmcache/dmcache_linux.go",
    "content": "//go:build linux\n\npackage dmcache\n\nimport (\n\t\"errors\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nconst metricName = \"dmcache\"\n\ntype cacheStatus struct {\n\tdevice            string\n\tlength            int64\n\ttarget            string\n\tmetadataBlocksize int64\n\tmetadataUsed      int64\n\tmetadataTotal     int64\n\tcacheBlocksize    int64\n\tcacheUsed         int64\n\tcacheTotal        int64\n\treadHits          int64\n\treadMisses        int64\n\twriteHits         int64\n\twriteMisses       int64\n\tdemotions         int64\n\tpromotions        int64\n\tdirty             int64\n}\n\nfunc (c *DMCache) Gather(acc telegraf.Accumulator) error {\n\toutputLines, err := c.getCurrentStatus()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttotalStatus := cacheStatus{}\n\n\tfor _, s := range outputLines {\n\t\tstatus, err := parseDMSetupStatus(s)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif c.PerDevice {\n\t\t\ttags := map[string]string{\"device\": status.device}\n\t\t\tacc.AddFields(metricName, toFields(status), tags)\n\t\t}\n\t\taggregateStats(&totalStatus, status)\n\t}\n\n\tacc.AddFields(metricName, toFields(totalStatus), map[string]string{\"device\": \"all\"})\n\n\treturn nil\n}\n\nfunc parseDMSetupStatus(line string) (cacheStatus, error) {\n\tvar err error\n\tparseError := errors.New(\"output from dmsetup could not be parsed\")\n\tstatus := cacheStatus{}\n\tvalues := strings.Fields(line)\n\tif len(values) < 15 {\n\t\treturn cacheStatus{}, parseError\n\t}\n\n\tstatus.device = strings.TrimRight(values[0], \":\")\n\tstatus.length, err = strconv.ParseInt(values[2], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.target = values[3]\n\tstatus.metadataBlocksize, err = strconv.ParseInt(values[4], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tmetadata := strings.Split(values[5], \"/\")\n\tif len(metadata) != 2 {\n\t\treturn cacheStatus{}, parseError\n\t}\n\tstatus.metadataUsed, err = strconv.ParseInt(metadata[0], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.metadataTotal, err = strconv.ParseInt(metadata[1], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.cacheBlocksize, err = strconv.ParseInt(values[6], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tcache := strings.Split(values[7], \"/\")\n\tif len(cache) != 2 {\n\t\treturn cacheStatus{}, parseError\n\t}\n\tstatus.cacheUsed, err = strconv.ParseInt(cache[0], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.cacheTotal, err = strconv.ParseInt(cache[1], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.readHits, err = strconv.ParseInt(values[8], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.readMisses, err = strconv.ParseInt(values[9], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.writeHits, err = strconv.ParseInt(values[10], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.writeMisses, err = strconv.ParseInt(values[11], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.demotions, err = strconv.ParseInt(values[12], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.promotions, err = strconv.ParseInt(values[13], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\tstatus.dirty, err = strconv.ParseInt(values[14], 10, 64)\n\tif err != nil {\n\t\treturn cacheStatus{}, err\n\t}\n\n\treturn status, nil\n}\n\nfunc aggregateStats(totalStatus *cacheStatus, status cacheStatus) {\n\ttotalStatus.length += status.length\n\ttotalStatus.metadataBlocksize += status.metadataBlocksize\n\ttotalStatus.metadataUsed += status.metadataUsed\n\ttotalStatus.metadataTotal += status.metadataTotal\n\ttotalStatus.cacheBlocksize += status.cacheBlocksize\n\ttotalStatus.cacheUsed += status.cacheUsed\n\ttotalStatus.cacheTotal += status.cacheTotal\n\ttotalStatus.readHits += status.readHits\n\ttotalStatus.readMisses += status.readMisses\n\ttotalStatus.writeHits += status.writeHits\n\ttotalStatus.writeMisses += status.writeMisses\n\ttotalStatus.demotions += status.demotions\n\ttotalStatus.promotions += status.promotions\n\ttotalStatus.dirty += status.dirty\n}\n\nfunc toFields(status cacheStatus) map[string]interface{} {\n\tfields := make(map[string]interface{})\n\tfields[\"length\"] = status.length\n\tfields[\"metadata_blocksize\"] = status.metadataBlocksize\n\tfields[\"metadata_used\"] = status.metadataUsed\n\tfields[\"metadata_total\"] = status.metadataTotal\n\tfields[\"cache_blocksize\"] = status.cacheBlocksize\n\tfields[\"cache_used\"] = status.cacheUsed\n\tfields[\"cache_total\"] = status.cacheTotal\n\tfields[\"read_hits\"] = status.readHits\n\tfields[\"read_misses\"] = status.readMisses\n\tfields[\"write_hits\"] = status.writeHits\n\tfields[\"write_misses\"] = status.writeMisses\n\tfields[\"demotions\"] = status.demotions\n\tfields[\"promotions\"] = status.promotions\n\tfields[\"dirty\"] = status.dirty\n\treturn fields\n}\n\nfunc dmSetupStatus() ([]string, error) {\n\tout, err := exec.Command(\"/bin/sh\", \"-c\", \"sudo /sbin/dmsetup status --target cache\").Output()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif string(out) == \"No devices found\\n\" {\n\t\treturn nil, nil\n\t}\n\n\toutString := strings.TrimRight(string(out), \"\\n\")\n\tstatus := strings.Split(outString, \"\\n\")\n\n\treturn status, nil\n}\n"
  },
  {
    "path": "plugins/inputs/dmcache/dmcache_linux_test.go",
    "content": "//go:build linux\n\npackage dmcache\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar (\n\tmeasurement              = \"dmcache\"\n\tbadFormatOutput          = []string{\"cs-1: 0 4883791872 cache 8 1018/1501122 512 7/464962 139 352643 \"}\n\tgood2DevicesFormatOutput = []string{\n\t\t\"cs-1: 0 4883791872 cache 8 1018/1501122 512 7/464962 139 352643 15 46 0 7 0 1 writeback 2 migration_threshold 2048 mq 10 random_threshold 4 \" +\n\t\t\t\"sequential_threshold 512 discard_promote_adjustment 1 read_promote_adjustment 4 write_promote_adjustment 8\",\n\t\t\"cs-2: 0 4294967296 cache 8 72352/1310720 128 26/24327168 2409 286 265 524682 0 0 0 1 writethrough 2 migration_threshold 2048 mq 10 \" +\n\t\t\t\"random_threshold 4 sequential_threshold 512 discard_promote_adjustment 1 read_promote_adjustment 4 write_promote_adjustment 8\",\n\t}\n)\n\nfunc TestPerDeviceGoodOutput(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar plugin = &DMCache{\n\t\tPerDevice: true,\n\t\tgetCurrentStatus: func() ([]string, error) {\n\t\t\treturn good2DevicesFormatOutput, nil\n\t\t},\n\t}\n\n\terr := plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags1 := map[string]string{\n\t\t\"device\": \"cs-1\",\n\t}\n\tfields1 := map[string]interface{}{\n\t\t\"length\":             int64(4883791872),\n\t\t\"metadata_blocksize\": int64(8),\n\t\t\"metadata_used\":      int64(1018),\n\t\t\"metadata_total\":     int64(1501122),\n\t\t\"cache_blocksize\":    int64(512),\n\t\t\"cache_used\":         int64(7),\n\t\t\"cache_total\":        int64(464962),\n\t\t\"read_hits\":          int64(139),\n\t\t\"read_misses\":        int64(352643),\n\t\t\"write_hits\":         int64(15),\n\t\t\"write_misses\":       int64(46),\n\t\t\"demotions\":          int64(0),\n\t\t\"promotions\":         int64(7),\n\t\t\"dirty\":              int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, measurement, fields1, tags1)\n\n\ttags2 := map[string]string{\n\t\t\"device\": \"cs-2\",\n\t}\n\tfields2 := map[string]interface{}{\n\t\t\"length\":             int64(4294967296),\n\t\t\"metadata_blocksize\": int64(8),\n\t\t\"metadata_used\":      int64(72352),\n\t\t\"metadata_total\":     int64(1310720),\n\t\t\"cache_blocksize\":    int64(128),\n\t\t\"cache_used\":         int64(26),\n\t\t\"cache_total\":        int64(24327168),\n\t\t\"read_hits\":          int64(2409),\n\t\t\"read_misses\":        int64(286),\n\t\t\"write_hits\":         int64(265),\n\t\t\"write_misses\":       int64(524682),\n\t\t\"demotions\":          int64(0),\n\t\t\"promotions\":         int64(0),\n\t\t\"dirty\":              int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, measurement, fields2, tags2)\n\n\ttags3 := map[string]string{\n\t\t\"device\": \"all\",\n\t}\n\n\tfields3 := map[string]interface{}{\n\t\t\"length\":             int64(9178759168),\n\t\t\"metadata_blocksize\": int64(16),\n\t\t\"metadata_used\":      int64(73370),\n\t\t\"metadata_total\":     int64(2811842),\n\t\t\"cache_blocksize\":    int64(640),\n\t\t\"cache_used\":         int64(33),\n\t\t\"cache_total\":        int64(24792130),\n\t\t\"read_hits\":          int64(2548),\n\t\t\"read_misses\":        int64(352929),\n\t\t\"write_hits\":         int64(280),\n\t\t\"write_misses\":       int64(524728),\n\t\t\"demotions\":          int64(0),\n\t\t\"promotions\":         int64(7),\n\t\t\"dirty\":              int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, measurement, fields3, tags3)\n}\n\nfunc TestNotPerDeviceGoodOutput(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar plugin = &DMCache{\n\t\tPerDevice: false,\n\t\tgetCurrentStatus: func() ([]string, error) {\n\t\t\treturn good2DevicesFormatOutput, nil\n\t\t},\n\t}\n\n\terr := plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"device\": \"all\",\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"length\":             int64(9178759168),\n\t\t\"metadata_blocksize\": int64(16),\n\t\t\"metadata_used\":      int64(73370),\n\t\t\"metadata_total\":     int64(2811842),\n\t\t\"cache_blocksize\":    int64(640),\n\t\t\"cache_used\":         int64(33),\n\t\t\"cache_total\":        int64(24792130),\n\t\t\"read_hits\":          int64(2548),\n\t\t\"read_misses\":        int64(352929),\n\t\t\"write_hits\":         int64(280),\n\t\t\"write_misses\":       int64(524728),\n\t\t\"demotions\":          int64(0),\n\t\t\"promotions\":         int64(7),\n\t\t\"dirty\":              int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, measurement, fields, tags)\n}\n\nfunc TestNoDevicesOutput(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar plugin = &DMCache{\n\t\tPerDevice: true,\n\t\tgetCurrentStatus: func() ([]string, error) {\n\t\t\treturn nil, nil\n\t\t},\n\t}\n\n\terr := plugin.Gather(&acc)\n\trequire.NoError(t, err)\n}\n\nfunc TestErrorDuringGettingStatus(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar plugin = &DMCache{\n\t\tPerDevice: true,\n\t\tgetCurrentStatus: func() ([]string, error) {\n\t\t\treturn nil, errors.New(\"dmsetup doesn't exist\")\n\t\t},\n\t}\n\n\terr := plugin.Gather(&acc)\n\trequire.Error(t, err)\n}\n\nfunc TestBadFormatOfStatus(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tvar plugin = &DMCache{\n\t\tPerDevice: true,\n\t\tgetCurrentStatus: func() ([]string, error) {\n\t\t\treturn badFormatOutput, nil\n\t\t},\n\t}\n\n\terr := plugin.Gather(&acc)\n\trequire.Error(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/dmcache/dmcache_notlinux.go",
    "content": "//go:build !linux\n\npackage dmcache\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc (*DMCache) Gather(_ telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc dmSetupStatus() ([]string, error) {\n\treturn make([]string, 0), nil\n}\n"
  },
  {
    "path": "plugins/inputs/dmcache/sample.conf",
    "content": "# Provide a native collection for dmsetup based statistics for dm-cache\n# This plugin ONLY supports Linux\n[[inputs.dmcache]]\n  ## Whether to report per-device stats or not\n  per_device = true\n"
  },
  {
    "path": "plugins/inputs/dns_query/README.md",
    "content": "# DNS Query Input Plugin\n\nThis plugin gathers information about DNS queries such as response time and\nresult codes.\n\n⭐ Telegraf v1.4.0\n🏷️ system, network\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Query given DNS server and gives statistics\n[[inputs.dns_query]]\n  ## servers to query\n  servers = [\"8.8.8.8\"]\n\n  ## Network is the network protocol name.\n  # network = \"udp\"\n\n  ## Domains or subdomains to query.\n  # domains = [\".\"]\n\n  ## Query record type.\n  ## Possible values: A, AAAA, CNAME, MX, NS, PTR, TXT, SOA, SPF, SRV.\n  # record_type = \"A\"\n\n  ## Dns server port.\n  # port = 53\n\n  ## Query timeout\n  # timeout = \"2s\"\n\n  ## Include the specified additional properties in the resulting metric.\n  ## The following values are supported:\n  ##    \"first_ip\" -- return IP of the first A and AAAA answer\n  ##    \"all_ips\"  -- return IPs of all A and AAAA answers\n  # include_fields = []\n```\n\n## Metrics\n\n- dns_query\n  - tags:\n    - server\n    - domain\n    - record_type\n    - result\n    - rcode\n  - fields:\n    - query_time_ms (float)\n    - result_code (int, success = 0, timeout = 1, error = 2)\n    - rcode_value (int)\n\n## Rcode Descriptions\n\n|rcode_value|rcode|Description|\n|---|-----------|-----------------------------------|\n|0  | NoError   | No Error                          |\n|1  | FormErr   | Format Error                      |\n|2  | ServFail  | Server Failure                    |\n|3  | NXDomain  | Non-Existent Domain               |\n|4  | NotImp    | Not Implemented                   |\n|5  | Refused   | Query Refused                     |\n|6  | YXDomain  | Name Exists when it should not    |\n|7  | YXRRSet   | RR Set Exists when it should not  |\n|8  | NXRRSet   | RR Set that should exist does not |\n|9  | NotAuth   | Server Not Authoritative for zone |\n|10 | NotZone   | Name not contained in zone        |\n|16 | BADSIG    | TSIG Signature Failure            |\n|16 | BADVERS   | Bad OPT Version                   |\n|17 | BADKEY    | Key not recognized                |\n|18 | BADTIME   | Signature out of time window      |\n|19 | BADMODE   | Bad TKEY Mode                     |\n|20 | BADNAME   | Duplicate key name                |\n|21 | BADALG    | Algorithm not supported           |\n|22 | BADTRUNC  | Bad Truncation                    |\n|23 | BADCOOKIE | Bad/missing Server Cookie         |\n\n## Example Output\n\n```text\ndns_query,domain=google.com,rcode=NOERROR,record_type=A,result=success,server=127.0.0.1 rcode_value=0i,result_code=0i,query_time_ms=0.13746 1550020750001000000\n```\n"
  },
  {
    "path": "plugins/inputs/dns_query/dns_query.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage dns_query\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"slices\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar ignoredErrors = []string{\n\t\"NXDOMAIN\",\n}\n\ntype resultType uint64\n\nconst (\n\tsuccessResult resultType = iota\n\ttimeoutResult\n\terrorResult\n)\n\ntype DNSQuery struct {\n\tDomains       []string        `toml:\"domains\"`\n\tNetwork       string          `toml:\"network\"`\n\tServers       []string        `toml:\"servers\"`\n\tRecordType    string          `toml:\"record_type\"`\n\tPort          int             `toml:\"port\"`\n\tTimeout       config.Duration `toml:\"timeout\"`\n\tIncludeFields []string        `toml:\"include_fields\"`\n\n\tfieldEnabled map[string]bool\n}\n\nfunc (*DNSQuery) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *DNSQuery) Init() error {\n\t// Convert the included fields into a lookup-table\n\td.fieldEnabled = make(map[string]bool, len(d.IncludeFields))\n\tfor _, f := range d.IncludeFields {\n\t\tswitch f {\n\t\tcase \"first_ip\", \"all_ips\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid field %q included\", f)\n\t\t}\n\t\td.fieldEnabled[f] = true\n\t}\n\n\t// Set defaults\n\tif d.Network == \"\" {\n\t\td.Network = \"udp\"\n\t}\n\n\tif d.RecordType == \"\" {\n\t\td.RecordType = \"NS\"\n\t}\n\n\tif len(d.Domains) == 0 {\n\t\td.Domains = []string{\".\"}\n\t\td.RecordType = \"NS\"\n\t}\n\n\tif d.Port < 1 {\n\t\td.Port = 53\n\t}\n\n\treturn nil\n}\n\nfunc (d *DNSQuery) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, domain := range d.Domains {\n\t\tfor _, server := range d.Servers {\n\t\t\twg.Add(1)\n\t\t\tgo func(domain, server string) {\n\t\t\t\tdefer wg.Done()\n\n\t\t\t\tfields, tags, err := d.query(domain, server)\n\t\t\t\tif err != nil && !slices.Contains(ignoredErrors, tags[\"rcode\"]) {\n\t\t\t\t\tvar opErr *net.OpError\n\t\t\t\t\tif !errors.As(err, &opErr) || !opErr.Timeout() {\n\t\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"dns_query\", fields, tags)\n\t\t\t}(domain, server)\n\t\t}\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (d *DNSQuery) query(domain, server string) (map[string]interface{}, map[string]string, error) {\n\ttags := map[string]string{\n\t\t\"server\":      server,\n\t\t\"domain\":      domain,\n\t\t\"record_type\": d.RecordType,\n\t\t\"result\":      \"error\",\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"query_time_ms\": float64(0),\n\t\t\"result_code\":   uint64(errorResult),\n\t}\n\n\tc := dns.Client{\n\t\tReadTimeout: time.Duration(d.Timeout),\n\t\tNet:         d.Network,\n\t}\n\n\trecordType, err := d.parseRecordType()\n\tif err != nil {\n\t\treturn fields, tags, err\n\t}\n\n\tvar msg dns.Msg\n\tmsg.SetQuestion(dns.Fqdn(domain), recordType)\n\tmsg.RecursionDesired = true\n\n\taddr := net.JoinHostPort(server, strconv.Itoa(d.Port))\n\tr, rtt, err := c.Exchange(&msg, addr)\n\tif err != nil {\n\t\tvar opErr *net.OpError\n\t\tif errors.As(err, &opErr) && opErr.Timeout() {\n\t\t\ttags[\"result\"] = \"timeout\"\n\t\t\tfields[\"result_code\"] = uint64(timeoutResult)\n\t\t\treturn fields, tags, err\n\t\t}\n\t\treturn fields, tags, err\n\t}\n\n\t// Fill valid fields\n\ttags[\"rcode\"] = dns.RcodeToString[r.Rcode]\n\tfields[\"rcode_value\"] = r.Rcode\n\tfields[\"query_time_ms\"] = float64(rtt.Nanoseconds()) / 1e6\n\n\t// Handle the failure case\n\tif r.Rcode != dns.RcodeSuccess {\n\t\treturn fields, tags, fmt.Errorf(\"invalid answer (%s) from %s after %s query for %s\", dns.RcodeToString[r.Rcode], server, d.RecordType, domain)\n\t}\n\n\t// Success\n\ttags[\"result\"] = \"success\"\n\tfields[\"result_code\"] = uint64(successResult)\n\n\t// Fill out custom fields for specific record types\n\tfor _, record := range r.Answer {\n\t\tswitch x := record.(type) {\n\t\tcase *dns.A:\n\t\t\tfields[\"name\"] = x.Hdr.Name\n\t\tcase *dns.AAAA:\n\t\t\tfields[\"name\"] = x.Hdr.Name\n\t\tcase *dns.CNAME:\n\t\t\tfields[\"name\"] = x.Hdr.Name\n\t\tcase *dns.MX:\n\t\t\tfields[\"name\"] = x.Hdr.Name\n\t\t\tfields[\"preference\"] = x.Preference\n\t\tcase *dns.SOA:\n\t\t\tfields[\"expire\"] = x.Expire\n\t\t\tfields[\"minttl\"] = x.Minttl\n\t\t\tfields[\"name\"] = x.Hdr.Name\n\t\t\tfields[\"refresh\"] = x.Refresh\n\t\t\tfields[\"retry\"] = x.Retry\n\t\t\tfields[\"serial\"] = x.Serial\n\t\t}\n\t}\n\n\tif d.fieldEnabled[\"first_ip\"] {\n\t\tfor _, record := range r.Answer {\n\t\t\tif ip, found := extractIP(record); found {\n\t\t\t\tfields[\"ip\"] = ip\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif d.fieldEnabled[\"all_ips\"] {\n\t\tfor i, record := range r.Answer {\n\t\t\tif ip, found := extractIP(record); found {\n\t\t\t\tfields[\"ip_\"+strconv.Itoa(i)] = ip\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fields, tags, nil\n}\n\nfunc (d *DNSQuery) parseRecordType() (uint16, error) {\n\tvar recordType uint16\n\tvar err error\n\n\tswitch d.RecordType {\n\tcase \"A\":\n\t\trecordType = dns.TypeA\n\tcase \"AAAA\":\n\t\trecordType = dns.TypeAAAA\n\tcase \"ANY\":\n\t\trecordType = dns.TypeANY\n\tcase \"CNAME\":\n\t\trecordType = dns.TypeCNAME\n\tcase \"MX\":\n\t\trecordType = dns.TypeMX\n\tcase \"NS\":\n\t\trecordType = dns.TypeNS\n\tcase \"PTR\":\n\t\trecordType = dns.TypePTR\n\tcase \"SOA\":\n\t\trecordType = dns.TypeSOA\n\tcase \"SPF\":\n\t\trecordType = dns.TypeSPF\n\tcase \"SRV\":\n\t\trecordType = dns.TypeSRV\n\tcase \"TXT\":\n\t\trecordType = dns.TypeTXT\n\tdefault:\n\t\terr = fmt.Errorf(\"record type %s not recognized\", d.RecordType)\n\t}\n\n\treturn recordType, err\n}\n\nfunc extractIP(record dns.RR) (string, bool) {\n\tif r, ok := record.(*dns.A); ok {\n\t\treturn r.A.String(), true\n\t}\n\tif r, ok := record.(*dns.AAAA); ok {\n\t\treturn r.AAAA.String(), true\n\t}\n\treturn \"\", false\n}\n\nfunc init() {\n\tinputs.Add(\"dns_query\", func() telegraf.Input {\n\t\treturn &DNSQuery{\n\t\t\tTimeout: config.Duration(2 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dns_query/dns_query_test.go",
    "content": "package dns_query\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar (\n\tservers = []string{\"8.8.8.8\"}\n\tdomains = []string{\"google.com\"}\n)\n\nfunc TestGathering(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers: servers,\n\t\tDomains: domains,\n\t\tTimeout: config.Duration(2 * time.Second),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, dnsConfig.Init())\n\trequire.NoError(t, acc.GatherError(dnsConfig.Gather))\n\tm, ok := acc.Get(\"dns_query\")\n\trequire.True(t, ok)\n\tqueryTime, ok := m.Fields[\"query_time_ms\"].(float64)\n\trequire.True(t, ok)\n\trequire.NotEqual(t, float64(0), queryTime)\n}\n\nfunc TestGatherInvalid(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers: servers,\n\t\tDomains: []string{\"qwerty123.example.com\"},\n\t\tTimeout: config.Duration(1 * time.Second),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, dnsConfig.Init())\n\trequire.NoError(t, dnsConfig.Gather(&acc))\n\trequire.Empty(t, acc.Errors)\n}\n\nfunc TestGatheringMxRecord(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers:    servers,\n\t\tDomains:    domains,\n\t\tRecordType: \"MX\",\n\t\tTimeout:    config.Duration(2 * time.Second),\n\t}\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, dnsConfig.Init())\n\trequire.NoError(t, acc.GatherError(dnsConfig.Gather))\n\tm, ok := acc.Get(\"dns_query\")\n\trequire.True(t, ok)\n\tqueryTime, ok := m.Fields[\"query_time_ms\"].(float64)\n\trequire.True(t, ok)\n\trequire.NotEqual(t, float64(0), queryTime)\n\tpreference, ok := m.Fields[\"preference\"].(uint16)\n\trequire.True(t, ok)\n\trequire.NotEqual(t, 0, preference)\n}\n\nfunc TestGatheringRootDomain(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers:    servers,\n\t\tDomains:    []string{\".\"},\n\t\tRecordType: \"MX\",\n\t\tTimeout:    config.Duration(2 * time.Second),\n\t}\n\trequire.NoError(t, dnsConfig.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(dnsConfig.Gather))\n\n\tm, ok := acc.Get(\"dns_query\")\n\trequire.True(t, ok)\n\tqueryTime, ok := m.Fields[\"query_time_ms\"].(float64)\n\trequire.True(t, ok)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"dns_query\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\":      \"8.8.8.8\",\n\t\t\t\t\"domain\":      \".\",\n\t\t\t\t\"record_type\": \"MX\",\n\t\t\t\t\"rcode\":       \"NOERROR\",\n\t\t\t\t\"result\":      \"success\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"rcode_value\":   0,\n\t\t\t\t\"result_code\":   uint64(0),\n\t\t\t\t\"query_time_ms\": queryTime,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestMetricContainsServerAndDomainAndRecordTypeTags(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers: servers,\n\t\tDomains: domains,\n\t\tTimeout: config.Duration(2 * time.Second),\n\t}\n\trequire.NoError(t, dnsConfig.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(dnsConfig.Gather))\n\n\tm, ok := acc.Get(\"dns_query\")\n\trequire.True(t, ok)\n\tqueryTime, ok := m.Fields[\"query_time_ms\"].(float64)\n\trequire.True(t, ok)\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"dns_query\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\":      \"8.8.8.8\",\n\t\t\t\t\"domain\":      \"google.com\",\n\t\t\t\t\"record_type\": \"NS\",\n\t\t\t\t\"rcode\":       \"NOERROR\",\n\t\t\t\t\"result\":      \"success\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"rcode_value\":   0,\n\t\t\t\t\"result_code\":   uint64(0),\n\t\t\t\t\"query_time_ms\": queryTime,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatheringTimeout(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\n\tdnsConfig := DNSQuery{\n\t\tServers: servers,\n\t\tDomains: domains,\n\t\tTimeout: config.Duration(1 * time.Second),\n\t\tPort:    60054,\n\t}\n\trequire.NoError(t, dnsConfig.Init())\n\n\tvar acc testutil.Accumulator\n\tchannel := make(chan error, 1)\n\tgo func() {\n\t\tchannel <- acc.GatherError(dnsConfig.Gather)\n\t}()\n\tselect {\n\tcase err := <-channel:\n\t\trequire.NoError(t, err)\n\tcase <-time.After(time.Second * 2):\n\t\trequire.Fail(t, \"DNS query did not timeout\")\n\t}\n}\n\nfunc TestSettingDefaultValues(t *testing.T) {\n\tdnsConfig := DNSQuery{\n\t\tTimeout: config.Duration(2 * time.Second),\n\t}\n\trequire.NoError(t, dnsConfig.Init())\n\trequire.Equal(t, []string{\".\"}, dnsConfig.Domains, \"Default domain not equal \\\".\\\"\")\n\trequire.Equal(t, \"NS\", dnsConfig.RecordType, \"Default record type not equal 'NS'\")\n\trequire.Equal(t, 53, dnsConfig.Port, \"Default port number not equal 53\")\n\trequire.Equal(t, config.Duration(2*time.Second), dnsConfig.Timeout, \"Default timeout not equal 2s\")\n\n\tdnsConfig = DNSQuery{\n\t\tDomains: []string{\".\"},\n\t\tTimeout: config.Duration(2 * time.Second),\n\t}\n\trequire.NoError(t, dnsConfig.Init())\n\trequire.Equal(t, \"NS\", dnsConfig.RecordType, \"Default record type not equal 'NS'\")\n}\n\nfunc TestRecordTypeParser(t *testing.T) {\n\ttests := []struct {\n\t\trecord   string\n\t\texpected uint16\n\t}{\n\t\t{\n\t\t\trecord:   \"A\",\n\t\t\texpected: dns.TypeA,\n\t\t},\n\t\t{\n\t\t\trecord:   \"AAAA\",\n\t\t\texpected: dns.TypeAAAA,\n\t\t},\n\t\t{\n\t\t\trecord:   \"ANY\",\n\t\t\texpected: dns.TypeANY,\n\t\t},\n\t\t{\n\t\t\trecord:   \"CNAME\",\n\t\t\texpected: dns.TypeCNAME,\n\t\t},\n\t\t{\n\t\t\trecord:   \"MX\",\n\t\t\texpected: dns.TypeMX,\n\t\t},\n\t\t{\n\t\t\trecord:   \"NS\",\n\t\t\texpected: dns.TypeNS,\n\t\t},\n\t\t{\n\t\t\trecord:   \"PTR\",\n\t\t\texpected: dns.TypePTR,\n\t\t},\n\t\t{\n\t\t\trecord:   \"SOA\",\n\t\t\texpected: dns.TypeSOA,\n\t\t},\n\t\t{\n\t\t\trecord:   \"SPF\",\n\t\t\texpected: dns.TypeSPF,\n\t\t},\n\t\t{\n\t\t\trecord:   \"SRV\",\n\t\t\texpected: dns.TypeSRV,\n\t\t},\n\t\t{\n\t\t\trecord:   \"TXT\",\n\t\t\texpected: dns.TypeTXT,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.record, func(t *testing.T) {\n\t\t\tplugin := DNSQuery{\n\t\t\t\tTimeout:    config.Duration(2 * time.Second),\n\t\t\t\tDomains:    []string{\"example.com\"},\n\t\t\t\tRecordType: tt.record,\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trecordType, err := plugin.parseRecordType()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, recordType)\n\t\t})\n\t}\n}\n\nfunc TestRecordTypeParserError(t *testing.T) {\n\tplugin := DNSQuery{\n\t\tTimeout:    config.Duration(2 * time.Second),\n\t\tRecordType: \"nil\",\n\t}\n\n\t_, err := plugin.parseRecordType()\n\trequire.Error(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/dns_query/sample.conf",
    "content": "# Query given DNS server and gives statistics\n[[inputs.dns_query]]\n  ## servers to query\n  servers = [\"8.8.8.8\"]\n\n  ## Network is the network protocol name.\n  # network = \"udp\"\n\n  ## Domains or subdomains to query.\n  # domains = [\".\"]\n\n  ## Query record type.\n  ## Possible values: A, AAAA, CNAME, MX, NS, PTR, TXT, SOA, SPF, SRV.\n  # record_type = \"A\"\n\n  ## Dns server port.\n  # port = 53\n\n  ## Query timeout\n  # timeout = \"2s\"\n\n  ## Include the specified additional properties in the resulting metric.\n  ## The following values are supported:\n  ##    \"first_ip\" -- return IP of the first A and AAAA answer\n  ##    \"all_ips\"  -- return IPs of all A and AAAA answers\n  # include_fields = []\n"
  },
  {
    "path": "plugins/inputs/docker/README.md",
    "content": "# Docker Input Plugin\n\nThis plugin uses the [Docker Engine API][api] to gather metrics on running\nDocker containers.\n\n> [!NOTE]\n> Make sure Telegraf has sufficient permissions to access the configured\n> endpoint.\n\n⭐ Telegraf v0.1.9\n🏷️ containers\n💻 all\n\n[api]: https://docs.docker.com/engine/api\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about docker containers\n[[inputs.docker]]\n  ## Docker Endpoint\n  ##   To use TCP, set endpoint = \"tcp://[ip]:[port]\"\n  ##   To use environment variables (ie, docker-machine), set endpoint = \"ENV\"\n  endpoint = \"unix:///var/run/docker.sock\"\n\n  ## Set to true to collect Swarm metrics(desired_replicas, running_replicas)\n  ## Note: configure this in one of the manager nodes in a Swarm cluster.\n  ## configuring in multiple Swarm managers results in duplication of metrics.\n  gather_services = false\n\n  ## Set the source tag for the metrics to the container ID hostname, eg first 12 chars\n  source_tag = false\n\n  ## Containers to include and exclude. Collect all if empty. Globs accepted.\n  container_name_include = []\n  container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"running\" state will be captured.\n  ## example: container_state_include = [\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"]\n  ## example: container_state_exclude = [\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"]\n  # container_state_include = []\n  # container_state_exclude = []\n\n  ## Objects to include for disk usage query\n  ## Allowed values are \"container\", \"image\", \"volume\"\n  ## When empty disk usage is excluded\n  storage_objects = []\n\n  ## Timeout for docker list, info, and stats commands\n  timeout = \"5s\"\n\n  ## Podman compatibility settings (auto-enabled when Podman detected)\n  ## Cache TTL for accurate CPU percentage calculation (default: 60s)\n  ## Set higher than your collection interval for accurate measurements\n  ## Set to 0 to keep cache entries forever (not recommended for dynamic environments)\n  # podman_cache_ttl = \"60s\"\n\n  ## Specifies for which classes a per-device metric should be issued\n  ## Possible values are 'cpu' (cpu0, cpu1, ...), 'blkio' (8:0, 8:1, ...) and 'network' (eth0, eth1, ...)\n  # perdevice_include = [\"cpu\"]\n\n  ## Specifies for which classes a total metric should be issued. Total is an aggregated of the 'perdevice_include' values.\n  ## Possible values are 'cpu', 'blkio' and 'network'\n  ## Total 'cpu' is reported directly by Docker daemon, and 'network' and 'blkio' totals are aggregated by this plugin.\n  # total_include = [\"cpu\", \"blkio\", \"network\"]\n\n  ## docker labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  docker_label_include = []\n  docker_label_exclude = []\n\n  ## Which environment variables should we use as a tag\n  tag_env = [\"JAVA_HOME\", \"HEAP_SIZE\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### Environment Configuration\n\nWhen using the `\"ENV\"` endpoint, the connection is configured using the [cli\nDocker environment variables][3].\n\n[3]: https://godoc.org/github.com/moby/moby/client#NewEnvClient\n\n### Security\n\nGiving telegraf access to the Docker daemon expands the [attack surface][4] that\ncould result in an attacker gaining root access to a machine. This is especially\nrelevant if the telegraf configuration can be changed by untrusted users.\n\n[4]: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface\n\n### Podman Compatibility\n\nThis plugin is compatible with Podman through its Docker-compatible API.\nWhen connected to Podman:\n\n- The plugin automatically detects Podman by examining the server version and\n  endpoint\n- Uses an intelligent caching mechanism to calculate accurate CPU percentages\n- Configure Podman socket endpoint, for example:\n  `endpoint = \"unix:///run/podman/podman.sock\"`\n\n### Docker Daemon Permissions\n\nTypically, telegraf must be given permission to access the docker daemon unix\nsocket when using the default endpoint. This can be done by adding the\n`telegraf` unix user (created when installing a Telegraf package) to the\n`docker` unix group with the following command:\n\n```shell\nsudo usermod -aG docker telegraf\n```\n\nIf telegraf is run within a container, the unix socket will need to be exposed\nwithin the telegraf container. This can be done in the docker CLI by add the\noption `-v /var/run/docker.sock:/var/run/docker.sock` or adding the following\nlines to the telegraf container definition in a docker compose file.\nAdditionally docker `telegraf` user must be assigned to `docker` group id\nfrom host:\n\n```yaml\nuser: telegraf:<host_docker_gid>\nvolumes:\n  - /var/run/docker.sock:/var/run/docker.sock\n```\n\n### source tag\n\nSelecting the containers measurements can be tricky if you have many containers\nwith the same name.  To alleviate this issue you can set the below value to\n`true`\n\n```toml\nsource_tag = true\n```\n\nThis will cause all measurements to have the `source` tag be set to the first 12\ncharacters of the container id. The first 12 characters is the common hostname\nfor containers that have no explicit hostname set, as defined by docker.\n\n### Kubernetes Labels\n\nKubernetes may add many labels to your containers, if they are not needed you\nmay prefer to exclude them:\n\n```json\n  docker_label_exclude = [\"annotation.kubernetes*\"]\n```\n\n### Docker-compose Labels\n\nDocker-compose will add labels to your containers. You can limit restrict labels\nto selected ones, e.g.\n\n```json\n  docker_label_include = [\n    \"com.docker.compose.config-hash\",\n    \"com.docker.compose.container-number\",\n    \"com.docker.compose.oneoff\",\n    \"com.docker.compose.project\",\n    \"com.docker.compose.service\",\n  ]\n```\n\n## Metrics\n\n- docker\n  - tags:\n    - unit\n    - engine_host\n    - server_version\n  - fields:\n    - n_used_file_descriptors\n    - n_cpus\n    - n_containers\n    - n_containers_running\n    - n_containers_stopped\n    - n_containers_paused\n    - n_images\n    - n_goroutines\n    - n_listener_events\n    - memory_total\n    - pool_blocksize (requires devicemapper storage driver) (deprecated see: `docker_devicemapper`)\n\nThe `docker_data` and `docker_metadata` measurements are available only for\nsome storage drivers such as devicemapper.\n\n- docker_data (deprecated see: `docker_devicemapper`)\n  - tags:\n    - unit\n    - engine_host\n    - server_version\n  - fields:\n    - available\n    - total\n    - used\n\n- docker_metadata (deprecated see: `docker_devicemapper`)\n  - tags:\n    - unit\n    - engine_host\n    - server_version\n  - fields:\n    - available\n    - total\n    - used\n\nThe above measurements for the devicemapper storage driver can now be found in\nthe new `docker_devicemapper` measurement\n\n- docker_devicemapper\n  - tags:\n    - engine_host\n    - server_version\n    - pool_name\n  - fields:\n    - pool_blocksize_bytes\n    - data_space_used_bytes\n    - data_space_total_bytes\n    - data_space_available_bytes\n    - metadata_space_used_bytes\n    - metadata_space_total_bytes\n    - metadata_space_available_bytes\n    - thin_pool_minimum_free_space_bytes\n\n- docker_container_mem\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n  - fields:\n    - total_pgmajfault\n    - cache\n    - mapped_file\n    - total_inactive_file\n    - pgpgout\n    - rss\n    - total_mapped_file\n    - writeback\n    - unevictable\n    - pgpgin\n    - total_unevictable\n    - pgmajfault\n    - total_rss\n    - total_rss_huge\n    - total_writeback\n    - total_inactive_anon\n    - rss_huge\n    - hierarchical_memory_limit\n    - total_pgfault\n    - total_active_file\n    - active_anon\n    - total_active_anon\n    - total_pgpgout\n    - total_cache\n    - inactive_anon\n    - active_file\n    - pgfault\n    - inactive_file\n    - total_pgpgin\n    - max_usage\n    - usage\n    - failcnt\n    - limit\n    - container_id\n\n- docker_container_cpu\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n    - cpu\n  - fields:\n    - throttling_periods\n    - throttling_throttled_periods\n    - throttling_throttled_time\n    - usage_in_kernelmode\n    - usage_in_usermode\n    - usage_system\n    - usage_total\n    - usage_percent\n    - container_id\n\n- docker_container_net\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n    - network\n  - fields:\n    - rx_dropped\n    - rx_bytes\n    - rx_errors\n    - tx_packets\n    - tx_dropped\n    - rx_packets\n    - tx_errors\n    - tx_bytes\n    - container_id\n\n- docker_container_blkio\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n    - device\n  - fields:\n    - io_service_bytes_recursive_async\n    - io_service_bytes_recursive_read\n    - io_service_bytes_recursive_sync\n    - io_service_bytes_recursive_total\n    - io_service_bytes_recursive_write\n    - io_serviced_recursive_async\n    - io_serviced_recursive_read\n    - io_serviced_recursive_sync\n    - io_serviced_recursive_total\n    - io_serviced_recursive_write\n    - container_id\n\nThe `docker_container_health` measurements report on a containers\n[HEALTHCHECK](https://docs.docker.com/engine/reference/builder/#healthcheck)\nstatus if configured.\n\n- docker_container_health (container must use the HEALTHCHECK)\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n  - fields:\n    - health_status (string)\n    - failing_streak (integer)\n\n- docker_container_status\n  - tags:\n    - engine_host\n    - server_version\n    - container_image\n    - container_name\n    - container_status\n    - container_version\n  - fields:\n    - container_id\n    - oomkilled (boolean)\n    - pid (integer)\n    - exitcode (integer)\n    - started_at (integer)\n    - finished_at (integer)\n    - uptime_ns (integer)\n\n- docker_swarm\n  - tags:\n    - service_id\n    - service_name\n    - service_mode\n  - fields:\n    - tasks_desired\n    - tasks_running\n\n- docker_disk_usage\n  - tags:\n    - engine_host\n    - server_version\n    - container_name\n    - container_image\n    - container_version\n    - image_id\n    - image_name\n    - image_version\n    - volume_name\n  - fields:\n    - size_rw\n    - size_root_fs\n    - size\n    - shared_size\n\n## Example Output\n\n```text\ndocker,engine_host=debian-stretch-docker,server_version=17.09.0-ce n_containers=6i,n_containers_paused=0i,n_containers_running=1i,n_containers_stopped=5i,n_cpus=2i,n_goroutines=41i,n_images=2i,n_listener_events=0i,n_used_file_descriptors=27i 1524002041000000000\ndocker,engine_host=debian-stretch-docker,server_version=17.09.0-ce,unit=bytes memory_total=2101661696i 1524002041000000000\ndocker_container_mem,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,engine_host=debian-stretch-docker,server_version=17.09.0-ce active_anon=8327168i,active_file=2314240i,cache=27402240i,container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",hierarchical_memory_limit=9223372036854771712i,inactive_anon=0i,inactive_file=25088000i,limit=2101661696i,mapped_file=20582400i,max_usage=36646912i,pgfault=4193i,pgmajfault=214i,pgpgin=9243i,pgpgout=520i,rss=8327168i,rss_huge=0i,total_active_anon=8327168i,total_active_file=2314240i,total_cache=27402240i,total_inactive_anon=0i,total_inactive_file=25088000i,total_mapped_file=20582400i,total_pgfault=4193i,total_pgmajfault=214i,total_pgpgin=9243i,total_pgpgout=520i,total_rss=8327168i,total_rss_huge=0i,total_unevictable=0i,total_writeback=0i,unevictable=0i,usage=36528128i,usage_percent=0.4342225020025297,writeback=0i 1524002042000000000\ndocker_container_cpu,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,cpu=cpu-total,engine_host=debian-stretch-docker,server_version=17.09.0-ce container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",throttling_periods=0i,throttling_throttled_periods=0i,throttling_throttled_time=0i,usage_in_kernelmode=40000000i,usage_in_usermode=100000000i,usage_percent=0,usage_system=6394210000000i,usage_total=117319068i 1524002042000000000\ndocker_container_cpu,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,cpu=cpu0,engine_host=debian-stretch-docker,server_version=17.09.0-ce container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",usage_total=20825265i 1524002042000000000\ndocker_container_cpu,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,cpu=cpu1,engine_host=debian-stretch-docker,server_version=17.09.0-ce container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",usage_total=96493803i 1524002042000000000\ndocker_container_net,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,engine_host=debian-stretch-docker,network=eth0,server_version=17.09.0-ce container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",rx_bytes=1576i,rx_dropped=0i,rx_errors=0i,rx_packets=20i,tx_bytes=0i,tx_dropped=0i,tx_errors=0i,tx_packets=0i 1524002042000000000\ndocker_container_blkio,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,device=254:0,engine_host=debian-stretch-docker,server_version=17.09.0-ce container_id=\"adc4ba9593871bf2ab95f3ffde70d1b638b897bb225d21c2c9c84226a10a8cf4\",io_service_bytes_recursive_async=27398144i,io_service_bytes_recursive_read=27398144i,io_service_bytes_recursive_sync=0i,io_service_bytes_recursive_total=27398144i,io_service_bytes_recursive_write=0i,io_serviced_recursive_async=529i,io_serviced_recursive_read=529i,io_serviced_recursive_sync=0i,io_serviced_recursive_total=529i,io_serviced_recursive_write=0i 1524002042000000000\ndocker_container_health,container_image=telegraf,container_name=zen_ritchie,container_status=running,container_version=unknown,engine_host=debian-stretch-docker,server_version=17.09.0-ce failing_streak=0i,health_status=\"healthy\" 1524007529000000000\ndocker_swarm,service_id=xaup2o9krw36j2dy1mjx1arjw,service_mode=replicated,service_name=test tasks_desired=3,tasks_running=3 1508968160000000000\ndocker_disk_usage,engine_host=docker-desktop,server_version=24.0.5 layers_size=17654519107i 1695742041000000000\ndocker_disk_usage,container_image=influxdb,container_name=frosty_wright,container_version=1.8,engine_host=docker-desktop,server_version=24.0.5 size_root_fs=286593526i,size_rw=538i 1695742041000000000\ndocker_disk_usage,engine_host=docker-desktop,image_id=7f4a1cc74046,image_name=telegraf,image_version=latest,server_version=24.0.5 shared_size=0i,size=425484494i 1695742041000000000\ndocker_disk_usage,engine_host=docker-desktop,server_version=24.0.5,volume_name=docker_influxdb-data size=91989940i 1695742041000000000\n```\n"
  },
  {
    "path": "plugins/inputs/docker/client.go",
    "content": "package docker\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net/http\"\n\n\t\"github.com/docker/docker/api/types\"\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/api/types/swarm\"\n\t\"github.com/docker/docker/api/types/system\"\n\t\"github.com/docker/docker/client\"\n)\n\nvar (\n\tdefaultHeaders = map[string]string{\"User-Agent\": \"engine-api-cli-1.0\"}\n)\n\n//nolint:interfacebloat // wrapping upstream docker client which has many methods\ntype dockerClient interface {\n\t// Info retrieves system-wide information about the Docker server.\n\tInfo(ctx context.Context) (system.Info, error)\n\t// ContainerList retrieves a list of containers based on the specified options.\n\tContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error)\n\t// ContainerStats retrieves real-time statistics for a specific container.\n\tContainerStats(ctx context.Context, containerID string, stream bool) (container.StatsResponseReader, error)\n\t// ContainerInspect retrieves detailed information about a specific container.\n\tContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error)\n\t// ServiceList retrieves a list of services based on the specified options.\n\tServiceList(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error)\n\t// TaskList retrieves a list of tasks based on the specified options.\n\tTaskList(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error)\n\t// NodeList retrieves a list of nodes based on the specified options.\n\tNodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error)\n\t// DiskUsage retrieves disk usage information.\n\tDiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error)\n\t// ClientVersion retrieves the version of the Docker client.\n\tClientVersion() string\n\t// Ping pings the server and returns information about the server.\n\tPing(ctx context.Context) (types.Ping, error)\n\t// Close releases any resources held by the client.\n\tClose() error\n}\n\nfunc newEnvClient() (dockerClient, error) {\n\tdockerClient, err := client.NewClientWithOpts(client.FromEnv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &socketClient{dockerClient}, nil\n}\n\nfunc newClient(host string, tlsConfig *tls.Config) (dockerClient, error) {\n\ttransport := &http.Transport{\n\t\tTLSClientConfig: tlsConfig,\n\t}\n\thttpClient := &http.Client{Transport: transport}\n\n\tdockerClient, err := client.NewClientWithOpts(\n\t\tclient.WithHTTPHeaders(defaultHeaders),\n\t\tclient.WithHTTPClient(httpClient),\n\t\tclient.WithAPIVersionNegotiation(),\n\t\tclient.WithHost(host))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &socketClient{dockerClient}, nil\n}\n\ntype socketClient struct {\n\tclient *client.Client\n}\n\n// Info retrieves system-wide information about the Docker server.\nfunc (c *socketClient) Info(ctx context.Context) (system.Info, error) {\n\treturn c.client.Info(ctx)\n}\n\n// ContainerList retrieves a list of containers based on the specified options.\nfunc (c *socketClient) ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error) {\n\treturn c.client.ContainerList(ctx, options)\n}\n\n// ContainerStats retrieves real-time statistics for a specific container.\nfunc (c *socketClient) ContainerStats(ctx context.Context, containerID string, stream bool) (container.StatsResponseReader, error) {\n\treturn c.client.ContainerStats(ctx, containerID, stream)\n}\n\n// ContainerInspect retrieves detailed information about a specific container.\nfunc (c *socketClient) ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error) {\n\treturn c.client.ContainerInspect(ctx, containerID)\n}\n\n// ServiceList retrieves a list of services based on the specified options.\nfunc (c *socketClient) ServiceList(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error) {\n\treturn c.client.ServiceList(ctx, options)\n}\n\n// TaskList retrieves a list of tasks based on the specified options.\nfunc (c *socketClient) TaskList(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error) {\n\treturn c.client.TaskList(ctx, options)\n}\n\n// NodeList retrieves a list of nodes based on the specified options.\nfunc (c *socketClient) NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {\n\treturn c.client.NodeList(ctx, options)\n}\n\n// DiskUsage retrieves disk usage information.\nfunc (c *socketClient) DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error) {\n\treturn c.client.DiskUsage(ctx, options)\n}\n\n// ClientVersion retrieves the version of the Docker client.\nfunc (c *socketClient) ClientVersion() string {\n\treturn c.client.ClientVersion()\n}\n\n// Ping pings the server and returns information about the server.\nfunc (c *socketClient) Ping(ctx context.Context) (types.Ping, error) {\n\treturn c.client.Ping(ctx)\n}\n\n// Close releases any resources held by the client.\nfunc (c *socketClient) Close() error {\n\treturn c.client.Close()\n}\n"
  },
  {
    "path": "plugins/inputs/docker/docker.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage docker\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/Masterminds/semver/v3\"\n\t\"github.com/docker/docker/api/types\"\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/api/types/swarm\"\n\t\"github.com/docker/docker/api/types/system\"\n\t\"github.com/docker/docker/client\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/internal/docker\"\n\tdocker_stats \"github.com/influxdata/telegraf/plugins/common/docker\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tsizeRegex              = regexp.MustCompile(`^(\\d+(\\.\\d+)*) ?([kKmMgGtTpP])?[bB]?$`)\n\tcontainerMetricClasses = []string{\"cpu\", \"network\", \"blkio\"}\n\tnow                    = time.Now\n\n\tminVersion          = semver.MustParse(\"1.23\")\n\tminDiskUsageVersion = semver.MustParse(\"1.42\")\n)\n\n// KB, MB, GB, TB, PB...human friendly\nconst (\n\tKB = 1000\n\tMB = 1000 * KB\n\tGB = 1000 * MB\n\tTB = 1000 * GB\n\tPB = 1000 * TB\n\n\tdefaultEndpoint = \"unix:///var/run/docker.sock\"\n)\n\ntype Docker struct {\n\tEndpoint string `toml:\"endpoint\"`\n\n\tGatherServices bool `toml:\"gather_services\"`\n\n\tTimeout          config.Duration `toml:\"timeout\"`\n\tPerDeviceInclude []string        `toml:\"perdevice_include\"`\n\tTotalInclude     []string        `toml:\"total_include\"`\n\tTagEnvironment   []string        `toml:\"tag_env\"`\n\tLabelInclude     []string        `toml:\"docker_label_include\"`\n\tLabelExclude     []string        `toml:\"docker_label_exclude\"`\n\n\tContainerInclude []string `toml:\"container_name_include\"`\n\tContainerExclude []string `toml:\"container_name_exclude\"`\n\n\tContainerStateInclude []string `toml:\"container_state_include\"`\n\tContainerStateExclude []string `toml:\"container_state_exclude\"`\n\n\tStorageObjects []string `toml:\"storage_objects\"`\n\n\tIncludeSourceTag bool `toml:\"source_tag\"`\n\n\t// Podman-specific configuration\n\tPodmanCacheTTL config.Duration `toml:\"podman_cache_ttl\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tcommon_tls.ClientConfig\n\n\tnewEnvClient func() (dockerClient, error)\n\tnewClient    func(string, *tls.Config) (dockerClient, error)\n\n\tclient          dockerClient\n\tengineHost      string\n\tserverVersion   string\n\tisPodman        bool\n\tfiltersCreated  bool\n\tlabelFilter     filter.Filter\n\tcontainerFilter filter.Filter\n\tstateFilter     filter.Filter\n\tobjectTypes     []types.DiskUsageObject\n\n\t// Stats cache for Podman CPU calculation\n\tstatsCache      map[string]*cachedContainerStats\n\tstatsCacheMutex sync.Mutex\n}\n\n// cachedContainerStats holds cached stats and metadata for a container\ntype cachedContainerStats struct {\n\tstats     *container.StatsResponse\n\ttimestamp time.Time\n}\n\nfunc (*Docker) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *Docker) Init() error {\n\terr := choice.CheckSlice(d.PerDeviceInclude, containerMetricClasses)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error validating 'perdevice_include' setting: %w\", err)\n\t}\n\n\terr = choice.CheckSlice(d.TotalInclude, containerMetricClasses)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error validating 'total_include' setting: %w\", err)\n\t}\n\n\td.objectTypes = make([]types.DiskUsageObject, 0, len(d.StorageObjects))\n\n\tfor _, object := range d.StorageObjects {\n\t\tswitch object {\n\t\tcase \"container\":\n\t\t\td.objectTypes = append(d.objectTypes, types.ContainerObject)\n\t\tcase \"image\":\n\t\t\td.objectTypes = append(d.objectTypes, types.ImageObject)\n\t\tcase \"volume\":\n\t\t\td.objectTypes = append(d.objectTypes, types.VolumeObject)\n\t\tdefault:\n\t\t\td.Log.Warnf(\"Unrecognized storage object type: %s\", object)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (d *Docker) Start(telegraf.Accumulator) error {\n\t// Get client - this only creates the client object, doesn't connect\n\tc, err := d.getNewClient()\n\tif err != nil {\n\t\treturn err\n\t}\n\td.client = c\n\n\t// Use Ping to check connectivity - this is a lightweight check\n\tctxPing, cancelPing := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancelPing()\n\tif _, err := d.client.Ping(ctxPing); err != nil {\n\t\td.Stop()\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"failed to ping Docker daemon: %w\", err),\n\t\t\tRetry: client.IsErrConnectionFailed(err),\n\t\t}\n\t}\n\n\t// Check API version compatibility\n\tversion, err := semver.NewVersion(d.client.ClientVersion())\n\tif err != nil {\n\t\td.Stop()\n\t\treturn fmt.Errorf(\"failed to parse client version: %w\", err)\n\t}\n\n\tif version.LessThan(minVersion) {\n\t\td.Log.Warnf(\"Unsupported api version (%v.%v), upgrade to docker engine 1.12 or later (api version 1.24)\",\n\t\t\tversion.Major(), version.Minor())\n\t} else if version.LessThan(minDiskUsageVersion) && len(d.objectTypes) > 0 {\n\t\td.Log.Warnf(\"Unsupported api version for disk usage (%v.%v), upgrade to docker engine 23.0 or later (api version 1.42)\",\n\t\t\tversion.Major(), version.Minor())\n\t}\n\n\t// Get info from docker daemon for Podman detection\n\tctxInfo, cancelInfo := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancelInfo()\n\n\tinfo, err := d.client.Info(ctxInfo)\n\tif err != nil {\n\t\td.Stop()\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"failed to get Docker info: %w\", err),\n\t\t\tRetry: client.IsErrConnectionFailed(err),\n\t\t}\n\t}\n\n\td.engineHost = info.Name\n\td.serverVersion = info.ServerVersion\n\n\t// Detect if we're connected to Podman\n\td.isPodman = d.detectPodman(&info)\n\n\tif d.isPodman {\n\t\t// Initialize stats cache only for Podman to save memory for Docker users\n\t\td.statsCache = make(map[string]*cachedContainerStats)\n\t\td.Log.Debugf(\"Detected Podman engine (version: %s, name: %s), using stats caching for accurate CPU measurements\", info.ServerVersion, info.Name)\n\t}\n\n\treturn nil\n}\n\nfunc (d *Docker) Stop() {\n\t// Close client connection if exists\n\tif d.client != nil {\n\t\td.client.Close()\n\t\td.client = nil\n\t}\n}\n\nfunc (d *Docker) Gather(acc telegraf.Accumulator) error {\n\t// Create label filters if not already created\n\tif !d.filtersCreated {\n\t\terr := d.createLabelFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = d.createContainerFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = d.createContainerStateFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\td.filtersCreated = true\n\t}\n\n\t// Get daemon info\n\terr := d.gatherInfo(acc)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t}\n\n\tif d.GatherServices {\n\t\terr := d.gatherSwarmInfo(acc)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}\n\n\t// List containers\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\tcontainers, err := d.client.ContainerList(ctx, container.ListOptions{})\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn errListTimeout\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Get container data\n\tvar wg sync.WaitGroup\n\twg.Add(len(containers))\n\tfor _, cntnr := range containers {\n\t\tgo func(c container.Summary) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := d.gatherContainer(c, acc); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(cntnr)\n\t}\n\twg.Wait()\n\n\t// Get disk usage data\n\tif len(d.objectTypes) > 0 {\n\t\td.gatherDiskUsage(acc, types.DiskUsageOptions{Types: d.objectTypes})\n\t}\n\n\t// Clean up stale cache entries for Podman\n\tif d.isPodman {\n\t\td.cleanupStaleCache()\n\t}\n\n\treturn nil\n}\n\nfunc (d *Docker) gatherSwarmInfo(acc telegraf.Accumulator) error {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\tservices, err := d.client.ServiceList(ctx, swarm.ServiceListOptions{})\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn errServiceTimeout\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(services) > 0 {\n\t\ttasks, err := d.client.TaskList(ctx, swarm.TaskListOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnodes, err := d.client.NodeList(ctx, swarm.NodeListOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tactiveNodes := make(map[string]struct{})\n\t\tfor _, n := range nodes {\n\t\t\tif n.Status.State != swarm.NodeStateDown {\n\t\t\t\tactiveNodes[n.ID] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\ttasksNoShutdown := make(map[string]uint64, len(tasks))\n\t\trunning := make(map[string]int, len(tasks))\n\t\tfor _, task := range tasks {\n\t\t\tif task.DesiredState != swarm.TaskStateShutdown {\n\t\t\t\ttasksNoShutdown[task.ServiceID]++\n\t\t\t}\n\n\t\t\tif task.Status.State == swarm.TaskStateRunning {\n\t\t\t\trunning[task.ServiceID]++\n\t\t\t}\n\t\t}\n\n\t\tfor _, service := range services {\n\t\t\ttags := make(map[string]string, 3)\n\t\t\tfields := make(map[string]interface{}, 2)\n\t\t\tnow := time.Now()\n\t\t\ttags[\"service_id\"] = service.ID\n\t\t\ttags[\"service_name\"] = service.Spec.Name\n\t\t\tif service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {\n\t\t\t\ttags[\"service_mode\"] = \"replicated\"\n\t\t\t\tfields[\"tasks_running\"] = running[service.ID]\n\t\t\t\tfields[\"tasks_desired\"] = *service.Spec.Mode.Replicated.Replicas\n\t\t\t} else if service.Spec.Mode.Global != nil {\n\t\t\t\ttags[\"service_mode\"] = \"global\"\n\t\t\t\tfields[\"tasks_running\"] = running[service.ID]\n\t\t\t\tfields[\"tasks_desired\"] = tasksNoShutdown[service.ID]\n\t\t\t} else if service.Spec.Mode.ReplicatedJob != nil {\n\t\t\t\ttags[\"service_mode\"] = \"replicated_job\"\n\t\t\t\tfields[\"tasks_running\"] = running[service.ID]\n\t\t\t\tif service.Spec.Mode.ReplicatedJob.MaxConcurrent != nil {\n\t\t\t\t\tfields[\"max_concurrent\"] = *service.Spec.Mode.ReplicatedJob.MaxConcurrent\n\t\t\t\t}\n\t\t\t\tif service.Spec.Mode.ReplicatedJob.TotalCompletions != nil {\n\t\t\t\t\tfields[\"total_completions\"] = *service.Spec.Mode.ReplicatedJob.TotalCompletions\n\t\t\t\t}\n\t\t\t} else if service.Spec.Mode.GlobalJob != nil {\n\t\t\t\ttags[\"service_mode\"] = \"global_job\"\n\t\t\t\tfields[\"tasks_running\"] = running[service.ID]\n\t\t\t} else {\n\t\t\t\td.Log.Error(\"Unknown replica mode\")\n\t\t\t}\n\t\t\t// Add metrics\n\t\t\tacc.AddFields(\"docker_swarm\",\n\t\t\t\tfields,\n\t\t\t\ttags,\n\t\t\t\tnow)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (d *Docker) gatherInfo(acc telegraf.Accumulator) error {\n\t// Init vars\n\tdataFields := make(map[string]interface{})\n\tmetadataFields := make(map[string]interface{})\n\tnow := time.Now()\n\n\t// Get info from docker daemon\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\tinfo, err := d.client.Info(ctx)\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn errInfoTimeout\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.engineHost = info.Name\n\td.serverVersion = info.ServerVersion\n\n\ttags := map[string]string{\n\t\t\"engine_host\":    d.engineHost,\n\t\t\"server_version\": d.serverVersion,\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"n_cpus\":                  info.NCPU,\n\t\t\"n_used_file_descriptors\": info.NFd,\n\t\t\"n_containers\":            info.Containers,\n\t\t\"n_containers_running\":    info.ContainersRunning,\n\t\t\"n_containers_stopped\":    info.ContainersStopped,\n\t\t\"n_containers_paused\":     info.ContainersPaused,\n\t\t\"n_images\":                info.Images,\n\t\t\"n_goroutines\":            info.NGoroutines,\n\t\t\"n_listener_events\":       info.NEventsListener,\n\t}\n\n\t// Add metrics\n\tacc.AddFields(\"docker\", fields, tags, now)\n\tacc.AddFields(\"docker\",\n\t\tmap[string]interface{}{\"memory_total\": info.MemTotal},\n\t\ttags,\n\t\tnow)\n\n\t// Get storage metrics\n\ttags[\"unit\"] = \"bytes\"\n\n\tvar (\n\t\t// \"docker_devicemapper\" measurement fields\n\t\tpoolName           string\n\t\tdeviceMapperFields = make(map[string]interface{}, len(info.DriverStatus))\n\t)\n\n\tfor _, rawData := range info.DriverStatus {\n\t\tname := strings.ToLower(strings.ReplaceAll(rawData[0], \" \", \"_\"))\n\t\tif name == \"pool_name\" {\n\t\t\tpoolName = rawData[1]\n\t\t\tcontinue\n\t\t}\n\n\t\t// Try to convert string to int (bytes)\n\t\tvalue, err := parseSize(rawData[1])\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch name {\n\t\tcase \"pool_blocksize\",\n\t\t\t\"base_device_size\",\n\t\t\t\"data_space_used\",\n\t\t\t\"data_space_total\",\n\t\t\t\"data_space_available\",\n\t\t\t\"metadata_space_used\",\n\t\t\t\"metadata_space_total\",\n\t\t\t\"metadata_space_available\",\n\t\t\t\"thin_pool_minimum_free_space\":\n\t\t\tdeviceMapperFields[name+\"_bytes\"] = value\n\t\t}\n\n\t\t// Legacy devicemapper measurements\n\t\tif name == \"pool_blocksize\" {\n\t\t\t// pool blocksize\n\t\t\tacc.AddFields(\"docker\",\n\t\t\t\tmap[string]interface{}{\"pool_blocksize\": value},\n\t\t\t\ttags,\n\t\t\t\tnow)\n\t\t} else if strings.HasPrefix(name, \"data_space_\") {\n\t\t\t// data space\n\t\t\tfieldName := strings.TrimPrefix(name, \"data_space_\")\n\t\t\tdataFields[fieldName] = value\n\t\t} else if strings.HasPrefix(name, \"metadata_space_\") {\n\t\t\t// metadata space\n\t\t\tfieldName := strings.TrimPrefix(name, \"metadata_space_\")\n\t\t\tmetadataFields[fieldName] = value\n\t\t}\n\t}\n\n\tif len(dataFields) > 0 {\n\t\tacc.AddFields(\"docker_data\", dataFields, tags, now)\n\t}\n\n\tif len(metadataFields) > 0 {\n\t\tacc.AddFields(\"docker_metadata\", metadataFields, tags, now)\n\t}\n\n\tif len(deviceMapperFields) > 0 {\n\t\ttags := map[string]string{\n\t\t\t\"engine_host\":    d.engineHost,\n\t\t\t\"server_version\": d.serverVersion,\n\t\t}\n\n\t\tif poolName != \"\" {\n\t\t\ttags[\"pool_name\"] = poolName\n\t\t}\n\n\t\tacc.AddFields(\"docker_devicemapper\", deviceMapperFields, tags, now)\n\t}\n\n\treturn nil\n}\n\nfunc hostnameFromID(id string) string {\n\tif len(id) > 12 {\n\t\treturn id[0:12]\n\t}\n\treturn id\n}\n\n// Parse container name\nfunc parseContainerName(containerNames []string) string {\n\tfor _, name := range containerNames {\n\t\ttrimmedName := strings.TrimPrefix(name, \"/\")\n\t\tif !strings.Contains(trimmedName, \"/\") {\n\t\t\treturn trimmedName\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc (d *Docker) gatherContainer(\n\tcntnr container.Summary,\n\tacc telegraf.Accumulator,\n) error {\n\tvar v *container.StatsResponse\n\n\tcontainerName := parseContainerName(cntnr.Names)\n\n\tif containerName == \"\" {\n\t\treturn nil\n\t}\n\n\tif !d.containerFilter.Match(containerName) {\n\t\treturn nil\n\t}\n\n\tif !d.stateFilter.Match(cntnr.State) {\n\t\treturn nil\n\t}\n\n\timageName, imageVersion := docker.ParseImage(cntnr.Image)\n\n\ttags := map[string]string{\n\t\t\"engine_host\":       d.engineHost,\n\t\t\"server_version\":    d.serverVersion,\n\t\t\"container_name\":    containerName,\n\t\t\"container_image\":   imageName,\n\t\t\"container_version\": imageVersion,\n\t}\n\n\tif d.IncludeSourceTag {\n\t\ttags[\"source\"] = hostnameFromID(cntnr.ID)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\t// Get container stats\n\tr, err := d.client.ContainerStats(ctx, cntnr.ID, false)\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn errStatsTimeout\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting docker stats: %w\", err)\n\t}\n\tdefer r.Body.Close()\n\n\tdaemonOSType := r.OSType\n\tdec := json.NewDecoder(r.Body)\n\tif err = dec.Decode(&v); err != nil {\n\t\tif !errors.Is(err, io.EOF) {\n\t\t\treturn fmt.Errorf(\"error decoding: %w\", err)\n\t\t}\n\t\t// EOF is expected for non-running containers (e.g. exited, created);\n\t\t// continue with nil stats so inspect metrics are still collected.\n\t}\n\n\t// For Podman, fix the CPU stats using cache if available\n\tif d.isPodman && v != nil {\n\t\td.fixPodmanCPUStats(cntnr.ID, v)\n\t}\n\n\t// Add labels to tags\n\tfor k, label := range cntnr.Labels {\n\t\tif d.labelFilter.Match(k) {\n\t\t\ttags[k] = label\n\t\t}\n\t}\n\n\treturn d.gatherContainerInspect(cntnr, acc, tags, daemonOSType, v)\n}\n\nfunc (d *Docker) gatherContainerInspect(\n\tcntnr container.Summary,\n\tacc telegraf.Accumulator,\n\ttags map[string]string,\n\tdaemonOSType string,\n\tv *container.StatsResponse,\n) error {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\tinfo, err := d.client.ContainerInspect(ctx, cntnr.ID)\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\treturn errInspectTimeout\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error inspecting docker container: %w\", err)\n\t}\n\n\t// Add whitelisted environment variables to tags\n\tif len(d.TagEnvironment) > 0 {\n\t\tfor _, envvar := range info.Config.Env {\n\t\t\tfor _, configvar := range d.TagEnvironment {\n\t\t\t\tdockEnv := strings.SplitN(envvar, \"=\", 2)\n\t\t\t\t// check for presence of tag in whitelist\n\t\t\t\tif len(dockEnv) == 2 && len(strings.TrimSpace(dockEnv[1])) != 0 && configvar == dockEnv[0] {\n\t\t\t\t\ttags[dockEnv[0]] = dockEnv[1]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif info.State != nil {\n\t\ttags[\"container_status\"] = info.State.Status\n\t\tstatefields := map[string]interface{}{\n\t\t\t\"oomkilled\":     info.State.OOMKilled,\n\t\t\t\"pid\":           info.State.Pid,\n\t\t\t\"exitcode\":      info.State.ExitCode,\n\t\t\t\"restart_count\": info.RestartCount,\n\t\t\t\"container_id\":  cntnr.ID,\n\t\t}\n\n\t\tfinished, err := time.Parse(time.RFC3339, info.State.FinishedAt)\n\t\tif err == nil && !finished.IsZero() {\n\t\t\tstatefields[\"finished_at\"] = finished.UnixNano()\n\t\t} else {\n\t\t\t// set finished to now for use in uptime\n\t\t\tfinished = now()\n\t\t}\n\n\t\tstarted, err := time.Parse(time.RFC3339, info.State.StartedAt)\n\t\tif err == nil && !started.IsZero() {\n\t\t\tstatefields[\"started_at\"] = started.UnixNano()\n\n\t\t\tuptime := finished.Sub(started)\n\t\t\tif finished.Before(started) {\n\t\t\t\tuptime = now().Sub(started)\n\t\t\t}\n\t\t\tstatefields[\"uptime_ns\"] = uptime.Nanoseconds()\n\t\t}\n\n\t\tacc.AddFields(\"docker_container_status\", statefields, tags, now())\n\n\t\tif info.State.Health != nil {\n\t\t\thealthfields := map[string]interface{}{\n\t\t\t\t\"health_status\":  info.State.Health.Status,\n\t\t\t\t\"failing_streak\": info.ContainerJSONBase.State.Health.FailingStreak,\n\t\t\t}\n\t\t\tacc.AddFields(\"docker_container_health\", healthfields, tags, now())\n\t\t}\n\t}\n\n\td.parseContainerStats(v, acc, tags, cntnr.ID, daemonOSType)\n\n\treturn nil\n}\n\nfunc (d *Docker) parseContainerStats(\n\tstat *container.StatsResponse,\n\tacc telegraf.Accumulator,\n\ttags map[string]string,\n\tid, daemonOSType string,\n) {\n\tif stat == nil {\n\t\treturn\n\t}\n\n\ttm := stat.Read\n\n\tif tm.Before(time.Unix(0, 0)) {\n\t\ttm = time.Now()\n\t}\n\n\tmemfields := map[string]interface{}{\n\t\t\"container_id\": id,\n\t}\n\n\tmemstats := []string{\n\t\t\"active_anon\",\n\t\t\"active_file\",\n\t\t\"cache\",\n\t\t\"hierarchical_memory_limit\",\n\t\t\"inactive_anon\",\n\t\t\"inactive_file\",\n\t\t\"mapped_file\",\n\t\t\"pgfault\",\n\t\t\"pgmajfault\",\n\t\t\"pgpgin\",\n\t\t\"pgpgout\",\n\t\t\"rss\",\n\t\t\"rss_huge\",\n\t\t\"total_active_anon\",\n\t\t\"total_active_file\",\n\t\t\"total_cache\",\n\t\t\"total_inactive_anon\",\n\t\t\"total_inactive_file\",\n\t\t\"total_mapped_file\",\n\t\t\"total_pgfault\",\n\t\t\"total_pgmajfault\",\n\t\t\"total_pgpgin\",\n\t\t\"total_pgpgout\",\n\t\t\"total_rss\",\n\t\t\"total_rss_huge\",\n\t\t\"total_unevictable\",\n\t\t\"total_writeback\",\n\t\t\"unevictable\",\n\t\t\"writeback\",\n\t}\n\tfor _, field := range memstats {\n\t\tif value, ok := stat.MemoryStats.Stats[field]; ok {\n\t\t\tmemfields[field] = value\n\t\t}\n\t}\n\tif stat.MemoryStats.Failcnt != 0 {\n\t\tmemfields[\"fail_count\"] = stat.MemoryStats.Failcnt\n\t}\n\n\tif daemonOSType != \"windows\" {\n\t\tmemfields[\"limit\"] = stat.MemoryStats.Limit\n\t\tmemfields[\"max_usage\"] = stat.MemoryStats.MaxUsage\n\n\t\tmem := docker_stats.CalculateMemUsageUnixNoCache(stat.MemoryStats)\n\t\tmemLimit := float64(stat.MemoryStats.Limit)\n\t\tmemfields[\"usage\"] = uint64(mem)\n\t\tmemfields[\"usage_percent\"] = docker_stats.CalculateMemPercentUnixNoCache(memLimit, mem)\n\t} else {\n\t\tmemfields[\"commit_bytes\"] = stat.MemoryStats.Commit\n\t\tmemfields[\"commit_peak_bytes\"] = stat.MemoryStats.CommitPeak\n\t\tmemfields[\"private_working_set\"] = stat.MemoryStats.PrivateWorkingSet\n\t}\n\n\tacc.AddFields(\"docker_container_mem\", memfields, tags, tm)\n\n\tif choice.Contains(\"cpu\", d.TotalInclude) {\n\t\tcpufields := map[string]interface{}{\n\t\t\t\"usage_total\":                  stat.CPUStats.CPUUsage.TotalUsage,\n\t\t\t\"usage_in_usermode\":            stat.CPUStats.CPUUsage.UsageInUsermode,\n\t\t\t\"usage_in_kernelmode\":          stat.CPUStats.CPUUsage.UsageInKernelmode,\n\t\t\t\"usage_system\":                 stat.CPUStats.SystemUsage,\n\t\t\t\"throttling_periods\":           stat.CPUStats.ThrottlingData.Periods,\n\t\t\t\"throttling_throttled_periods\": stat.CPUStats.ThrottlingData.ThrottledPeriods,\n\t\t\t\"throttling_throttled_time\":    stat.CPUStats.ThrottlingData.ThrottledTime,\n\t\t\t\"container_id\":                 id,\n\t\t}\n\n\t\tif daemonOSType != \"windows\" {\n\t\t\tpreviousCPU := stat.PreCPUStats.CPUUsage.TotalUsage\n\t\t\tpreviousSystem := stat.PreCPUStats.SystemUsage\n\t\t\tcpuPercent := docker_stats.CalculateCPUPercentUnix(previousCPU, previousSystem, stat)\n\t\t\tcpufields[\"usage_percent\"] = cpuPercent\n\t\t} else {\n\t\t\tcpuPercent := docker_stats.CalculateCPUPercentWindows(stat)\n\t\t\tcpufields[\"usage_percent\"] = cpuPercent\n\t\t}\n\n\t\tcputags := copyTags(tags)\n\t\tcputags[\"cpu\"] = \"cpu-total\"\n\t\tacc.AddFields(\"docker_container_cpu\", cpufields, cputags, tm)\n\t}\n\n\tif choice.Contains(\"cpu\", d.PerDeviceInclude) && len(stat.CPUStats.CPUUsage.PercpuUsage) > 0 {\n\t\t// If we have OnlineCPUs field, then use it to restrict stats gathering to only Online CPUs\n\t\t// (https://github.com/moby/moby/commit/115f91d7575d6de6c7781a96a082f144fd17e400)\n\t\tvar percpuusage []uint64\n\t\tif stat.CPUStats.OnlineCPUs > 0 {\n\t\t\tpercpuusage = stat.CPUStats.CPUUsage.PercpuUsage[:stat.CPUStats.OnlineCPUs]\n\t\t} else {\n\t\t\tpercpuusage = stat.CPUStats.CPUUsage.PercpuUsage\n\t\t}\n\n\t\tfor i, percpu := range percpuusage {\n\t\t\tpercputags := copyTags(tags)\n\t\t\tpercputags[\"cpu\"] = fmt.Sprintf(\"cpu%d\", i)\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"usage_total\":  percpu,\n\t\t\t\t\"container_id\": id,\n\t\t\t}\n\t\t\tacc.AddFields(\"docker_container_cpu\", fields, percputags, tm)\n\t\t}\n\t}\n\n\ttotalNetworkStatMap := make(map[string]interface{})\n\tfor network, netstats := range stat.Networks {\n\t\tnetfields := map[string]interface{}{\n\t\t\t\"rx_dropped\":   netstats.RxDropped,\n\t\t\t\"rx_bytes\":     netstats.RxBytes,\n\t\t\t\"rx_errors\":    netstats.RxErrors,\n\t\t\t\"tx_packets\":   netstats.TxPackets,\n\t\t\t\"tx_dropped\":   netstats.TxDropped,\n\t\t\t\"rx_packets\":   netstats.RxPackets,\n\t\t\t\"tx_errors\":    netstats.TxErrors,\n\t\t\t\"tx_bytes\":     netstats.TxBytes,\n\t\t\t\"container_id\": id,\n\t\t}\n\t\t// Create a new network tag dictionary for the \"network\" tag\n\t\tif choice.Contains(\"network\", d.PerDeviceInclude) {\n\t\t\tnettags := copyTags(tags)\n\t\t\tnettags[\"network\"] = network\n\t\t\tacc.AddFields(\"docker_container_net\", netfields, nettags, tm)\n\t\t}\n\t\tif choice.Contains(\"network\", d.TotalInclude) {\n\t\t\tfor field, value := range netfields {\n\t\t\t\tif field == \"container_id\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar uintV uint64\n\t\t\t\tswitch v := value.(type) {\n\t\t\t\tcase uint64:\n\t\t\t\t\tuintV = v\n\t\t\t\tcase int64:\n\t\t\t\t\tuintV = uint64(v)\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t_, ok := totalNetworkStatMap[field]\n\t\t\t\tif ok {\n\t\t\t\t\ttotalNetworkStatMap[field] = totalNetworkStatMap[field].(uint64) + uintV\n\t\t\t\t} else {\n\t\t\t\t\ttotalNetworkStatMap[field] = uintV\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// totalNetworkStatMap could be empty if container is running with --net=host.\n\tif choice.Contains(\"network\", d.TotalInclude) && len(totalNetworkStatMap) != 0 {\n\t\tnettags := copyTags(tags)\n\t\tnettags[\"network\"] = \"total\"\n\t\ttotalNetworkStatMap[\"container_id\"] = id\n\t\tacc.AddFields(\"docker_container_net\", totalNetworkStatMap, nettags, tm)\n\t}\n\n\td.gatherBlockIOMetrics(acc, stat, tags, tm, id)\n}\n\n// Make a map of devices to their block io stats\nfunc getDeviceStatMap(blkioStats container.BlkioStats) map[string]map[string]interface{} {\n\tdeviceStatMap := make(map[string]map[string]interface{})\n\n\tfor _, metric := range blkioStats.IoServiceBytesRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\t_, ok := deviceStatMap[device]\n\t\tif !ok {\n\t\t\tdeviceStatMap[device] = make(map[string]interface{})\n\t\t}\n\n\t\tfield := \"io_service_bytes_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoServicedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\t_, ok := deviceStatMap[device]\n\t\tif !ok {\n\t\t\tdeviceStatMap[device] = make(map[string]interface{})\n\t\t}\n\n\t\tfield := \"io_serviced_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoQueuedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_queue_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoServiceTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_service_time_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoWaitTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_wait_time_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoMergedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_merged_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tdeviceStatMap[device][\"io_time_recursive\"] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.SectorsRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tdeviceStatMap[device][\"sectors_recursive\"] = metric.Value\n\t}\n\treturn deviceStatMap\n}\n\nfunc (d *Docker) gatherBlockIOMetrics(\n\tacc telegraf.Accumulator,\n\tstat *container.StatsResponse,\n\ttags map[string]string,\n\ttm time.Time,\n\tid string,\n) {\n\tperDeviceBlkio := choice.Contains(\"blkio\", d.PerDeviceInclude)\n\ttotalBlkio := choice.Contains(\"blkio\", d.TotalInclude)\n\tblkioStats := stat.BlkioStats\n\tdeviceStatMap := getDeviceStatMap(blkioStats)\n\n\ttotalStatMap := make(map[string]interface{})\n\tfor device, fields := range deviceStatMap {\n\t\tfields[\"container_id\"] = id\n\t\tif perDeviceBlkio {\n\t\t\tiotags := copyTags(tags)\n\t\t\tiotags[\"device\"] = device\n\t\t\tacc.AddFields(\"docker_container_blkio\", fields, iotags, tm)\n\t\t}\n\t\tif totalBlkio {\n\t\t\tfor field, value := range fields {\n\t\t\t\tif field == \"container_id\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar uintV uint64\n\t\t\t\tswitch v := value.(type) {\n\t\t\t\tcase uint64:\n\t\t\t\t\tuintV = v\n\t\t\t\tcase int64:\n\t\t\t\t\tuintV = uint64(v)\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t_, ok := totalStatMap[field]\n\t\t\t\tif ok {\n\t\t\t\t\ttotalStatMap[field] = totalStatMap[field].(uint64) + uintV\n\t\t\t\t} else {\n\t\t\t\t\ttotalStatMap[field] = uintV\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif totalBlkio {\n\t\ttotalStatMap[\"container_id\"] = id\n\t\tiotags := copyTags(tags)\n\t\tiotags[\"device\"] = \"total\"\n\t\tacc.AddFields(\"docker_container_blkio\", totalStatMap, iotags, tm)\n\t}\n}\n\nfunc (d *Docker) gatherDiskUsage(acc telegraf.Accumulator, opts types.DiskUsageOptions) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(d.Timeout))\n\tdefer cancel()\n\n\tdu, err := d.client.DiskUsage(ctx, opts)\n\n\tif err != nil {\n\t\tacc.AddError(err)\n\t}\n\n\tnow := time.Now()\n\tduName := \"docker_disk_usage\"\n\n\t// Layers size\n\tfields := map[string]interface{}{\n\t\t\"layers_size\": du.LayersSize,\n\t}\n\n\ttags := map[string]string{\n\t\t\"engine_host\":    d.engineHost,\n\t\t\"server_version\": d.serverVersion,\n\t}\n\n\tacc.AddFields(duName, fields, tags, now)\n\n\t// Containers\n\tfor _, cntnr := range du.Containers {\n\t\tfields := map[string]interface{}{\n\t\t\t\"size_rw\":      cntnr.SizeRw,\n\t\t\t\"size_root_fs\": cntnr.SizeRootFs,\n\t\t}\n\n\t\timageName, imageVersion := docker.ParseImage(cntnr.Image)\n\n\t\ttags := map[string]string{\n\t\t\t\"engine_host\":       d.engineHost,\n\t\t\t\"server_version\":    d.serverVersion,\n\t\t\t\"container_name\":    parseContainerName(cntnr.Names),\n\t\t\t\"container_image\":   imageName,\n\t\t\t\"container_version\": imageVersion,\n\t\t}\n\n\t\tif d.IncludeSourceTag {\n\t\t\ttags[\"source\"] = hostnameFromID(cntnr.ID)\n\t\t}\n\n\t\tacc.AddFields(duName, fields, tags, now)\n\t}\n\n\t// Images\n\tfor _, image := range du.Images {\n\t\tfields := map[string]interface{}{\n\t\t\t\"size\":        image.Size,\n\t\t\t\"shared_size\": image.SharedSize,\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"engine_host\":    d.engineHost,\n\t\t\t\"server_version\": d.serverVersion,\n\t\t\t\"image_id\":       image.ID[7:19], // remove \"sha256:\" and keep the first 12 characters\n\t\t}\n\n\t\tif len(image.RepoTags) > 0 {\n\t\t\timageName, imageVersion := docker.ParseImage(image.RepoTags[0])\n\t\t\ttags[\"image_name\"] = imageName\n\t\t\ttags[\"image_version\"] = imageVersion\n\t\t}\n\n\t\tacc.AddFields(duName, fields, tags, now)\n\t}\n\n\t// Volumes\n\tfor _, volume := range du.Volumes {\n\t\tfields := map[string]interface{}{\n\t\t\t\"size\": volume.UsageData.Size,\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"engine_host\":    d.engineHost,\n\t\t\t\"server_version\": d.serverVersion,\n\t\t\t\"volume_name\":    volume.Name,\n\t\t}\n\n\t\tacc.AddFields(duName, fields, tags, now)\n\t}\n}\n\nfunc copyTags(in map[string]string) map[string]string {\n\tout := make(map[string]string)\n\tfor k, v := range in {\n\t\tout[k] = v\n\t}\n\treturn out\n}\n\n// Parses the human-readable size string into the amount it represents.\nfunc parseSize(sizeStr string) (int64, error) {\n\tmatches := sizeRegex.FindStringSubmatch(sizeStr)\n\tif len(matches) != 4 {\n\t\treturn -1, fmt.Errorf(\"invalid size: %s\", sizeStr)\n\t}\n\n\tsize, err := strconv.ParseFloat(matches[1], 64)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\n\tuMap := map[string]int64{\"k\": KB, \"m\": MB, \"g\": GB, \"t\": TB, \"p\": PB}\n\tunitPrefix := strings.ToLower(matches[3])\n\tif mul, ok := uMap[unitPrefix]; ok {\n\t\tsize *= float64(mul)\n\t}\n\n\treturn int64(size), nil\n}\n\nfunc (d *Docker) createContainerFilters() error {\n\tcontainerFilter, err := filter.NewIncludeExcludeFilter(d.ContainerInclude, d.ContainerExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.containerFilter = containerFilter\n\treturn nil\n}\n\nfunc (d *Docker) createLabelFilters() error {\n\tlabelFilter, err := filter.NewIncludeExcludeFilter(d.LabelInclude, d.LabelExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.labelFilter = labelFilter\n\treturn nil\n}\n\nfunc (d *Docker) createContainerStateFilters() error {\n\tif len(d.ContainerStateInclude) == 0 && len(d.ContainerStateExclude) == 0 {\n\t\td.ContainerStateInclude = []string{\"running\"}\n\t}\n\tstateFilter, err := filter.NewIncludeExcludeFilter(d.ContainerStateInclude, d.ContainerStateExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.stateFilter = stateFilter\n\treturn nil\n}\n\nfunc (d *Docker) getNewClient() (dockerClient, error) {\n\tif d.Endpoint == \"ENV\" {\n\t\treturn d.newEnvClient()\n\t}\n\n\ttlsConfig, err := d.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn d.newClient(d.Endpoint, tlsConfig)\n}\n\n// detectPodman detects if we're connected to Podman by checking Docker info response.\n// Uses a conservative approach prioritizing explicit indicators over heuristics.\nfunc (d *Docker) detectPodman(info *system.Info) bool {\n\tsv := strings.ToLower(info.ServerVersion)\n\tname := strings.ToLower(info.Name)\n\tendpoint := strings.ToLower(d.Endpoint)\n\n\t// 1. Explicit Docker indicators (highest confidence)\n\tif strings.Contains(sv, \"docker\") || strings.Contains(name, \"docker\") ||\n\t\tstrings.Contains(info.InitBinary, \"docker\") {\n\t\treturn false\n\t}\n\n\t// 2. Explicit Podman indicators (highest confidence)\n\tif strings.Contains(sv, \"podman\") || strings.Contains(name, \"podman\") ||\n\t\tstrings.Contains(endpoint, \"podman\") {\n\t\treturn true\n\t}\n\n\t// 3. Exclude other known container runtimes\n\tif strings.Contains(name, \"kubernetes\") || strings.Contains(name, \"containerd\") ||\n\t\tstrings.Contains(endpoint, \"containerd\") {\n\t\treturn false\n\t}\n\n\t// 4. Podman heuristics - conservative approach\n\t// Common Podman patterns: crun runtime, localhost domains, short names, container sockets\n\tif info.InitBinary == \"crun\" ||\n\t\tstrings.Contains(name, \"localhost\") ||\n\t\tstrings.Contains(endpoint, \"container.sock\") ||\n\t\t(len(name) <= 4 && name != \"\") {\n\t\treturn true\n\t}\n\n\t// 5. Default to Docker for safety\n\treturn false\n}\n\n// fixPodmanCPUStats fixes Podman's CPU stats using cached previous stats\nfunc (d *Docker) fixPodmanCPUStats(containerID string, current *container.StatsResponse) {\n\tnow := time.Now()\n\tttl := time.Duration(d.PodmanCacheTTL)\n\n\t// Single lock for read-check-update operation\n\td.statsCacheMutex.Lock()\n\tdefer d.statsCacheMutex.Unlock()\n\n\tif cached, exists := d.statsCache[containerID]; exists && cached != nil && cached.stats != nil {\n\t\t// Check if cached stats are recent enough\n\t\tage := now.Sub(cached.timestamp)\n\t\tif age <= ttl {\n\t\t\t// Use cached stats as PreCPUStats for accurate CPU calculation\n\t\t\tcurrent.PreCPUStats = cached.stats.CPUStats\n\t\t\td.Log.Tracef(\"Podman stats cache hit for container %s (age: %v)\", hostnameFromID(containerID), age)\n\t\t} else {\n\t\t\td.Log.Tracef(\"Podman stats cache expired for container %s (age: %v)\", hostnameFromID(containerID), age)\n\t\t}\n\t} else {\n\t\td.Log.Tracef(\"Podman stats cache miss for container %s (first collection)\", hostnameFromID(containerID))\n\t}\n\n\t// Update cache with current stats (reuse timestamp)\n\td.statsCache[containerID] = &cachedContainerStats{\n\t\tstats:     current,\n\t\ttimestamp: now,\n\t}\n}\n\n// cleanupStaleCache removes expired entries from the stats cache\nfunc (d *Docker) cleanupStaleCache() {\n\tif len(d.statsCache) == 0 {\n\t\treturn // Early exit if cache is empty\n\t}\n\n\td.statsCacheMutex.Lock()\n\tdefer d.statsCacheMutex.Unlock()\n\n\tcutoff := time.Now().Add(-time.Duration(d.PodmanCacheTTL))\n\texpiredCount := 0\n\n\tfor id, cached := range d.statsCache {\n\t\tif cached.timestamp.Before(cutoff) {\n\t\t\tdelete(d.statsCache, id)\n\t\t\texpiredCount++\n\t\t}\n\t}\n\n\td.Log.Tracef(\"Cleaned up %d expired entries from Podman stats cache\", expiredCount)\n}\n\nfunc init() {\n\tinputs.Add(\"docker\", func() telegraf.Input {\n\t\treturn &Docker{\n\t\t\tPerDeviceInclude: []string{\"cpu\"},\n\t\t\tTotalInclude:     []string{\"cpu\", \"blkio\", \"network\"},\n\t\t\tTimeout:          config.Duration(time.Second * 5),\n\t\t\tEndpoint:         defaultEndpoint,\n\t\t\tPodmanCacheTTL:   config.Duration(60 * time.Second),\n\t\t\tnewEnvClient:     newEnvClient,\n\t\t\tnewClient:        newClient,\n\t\t\tfiltersCreated:   false,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/docker/docker_test.go",
    "content": "package docker\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types\"\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/api/types/swarm\"\n\t\"github.com/docker/docker/api/types/system\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockClient struct {\n\tInfoF             func() (system.Info, error)\n\tContainerListF    func(options container.ListOptions) ([]container.Summary, error)\n\tContainerStatsF   func(containerID string) (container.StatsResponseReader, error)\n\tContainerInspectF func() (container.InspectResponse, error)\n\tServiceListF      func() ([]swarm.Service, error)\n\tTaskListF         func() ([]swarm.Task, error)\n\tNodeListF         func() ([]swarm.Node, error)\n\tDiskUsageF        func() (types.DiskUsage, error)\n\tClientVersionF    func() string\n\tPingF             func() (types.Ping, error)\n\tCloseF            func() error\n}\n\nfunc (c *mockClient) Info(context.Context) (system.Info, error) {\n\treturn c.InfoF()\n}\n\nfunc (c *mockClient) ContainerList(_ context.Context, options container.ListOptions) ([]container.Summary, error) {\n\treturn c.ContainerListF(options)\n}\n\nfunc (c *mockClient) ContainerStats(_ context.Context, containerID string, _ bool) (container.StatsResponseReader, error) {\n\treturn c.ContainerStatsF(containerID)\n}\n\nfunc (c *mockClient) ContainerInspect(context.Context, string) (container.InspectResponse, error) {\n\treturn c.ContainerInspectF()\n}\n\nfunc (c *mockClient) ServiceList(context.Context, swarm.ServiceListOptions) ([]swarm.Service, error) {\n\treturn c.ServiceListF()\n}\n\nfunc (c *mockClient) TaskList(context.Context, swarm.TaskListOptions) ([]swarm.Task, error) {\n\treturn c.TaskListF()\n}\n\nfunc (c *mockClient) NodeList(context.Context, swarm.NodeListOptions) ([]swarm.Node, error) {\n\treturn c.NodeListF()\n}\n\nfunc (c *mockClient) DiskUsage(context.Context, types.DiskUsageOptions) (types.DiskUsage, error) {\n\treturn c.DiskUsageF()\n}\n\nfunc (c *mockClient) ClientVersion() string {\n\treturn c.ClientVersionF()\n}\n\nfunc (c *mockClient) Ping(context.Context) (types.Ping, error) {\n\treturn c.PingF()\n}\n\nfunc (c *mockClient) Close() error {\n\treturn c.CloseF()\n}\n\nvar baseClient = mockClient{\n\tInfoF: func() (system.Info, error) {\n\t\treturn info, nil\n\t},\n\tContainerListF: func(container.ListOptions) ([]container.Summary, error) {\n\t\treturn containerList, nil\n\t},\n\tContainerStatsF: func(s string) (container.StatsResponseReader, error) {\n\t\treturn containerStats(s), nil\n\t},\n\tContainerInspectF: func() (container.InspectResponse, error) {\n\t\treturn containerInspect(), nil\n\t},\n\tServiceListF: func() ([]swarm.Service, error) {\n\t\treturn serviceList, nil\n\t},\n\tTaskListF: func() ([]swarm.Task, error) {\n\t\treturn taskList, nil\n\t},\n\tNodeListF: func() ([]swarm.Node, error) {\n\t\treturn nodeList, nil\n\t},\n\tDiskUsageF: func() (types.DiskUsage, error) {\n\t\treturn diskUsage, nil\n\t},\n\tClientVersionF: func() string {\n\t\treturn version\n\t},\n\tPingF: func() (types.Ping, error) {\n\t\treturn types.Ping{}, nil\n\t},\n\tCloseF: func() error {\n\t\treturn nil\n\t},\n}\n\nfunc TestDockerGatherContainerStats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tstats := testStats()\n\n\ttags := map[string]string{\n\t\t\"container_name\":  \"redis\",\n\t\t\"container_image\": \"redis/image\",\n\t}\n\n\td := &Docker{\n\t\tLog:              testutil.Logger{},\n\t\tPerDeviceInclude: containerMetricClasses,\n\t\tTotalInclude:     containerMetricClasses,\n\t}\n\td.parseContainerStats(stats, &acc, tags, \"123456789\", \"linux\")\n\n\t// test docker_container_net measurement\n\tnetfields := map[string]interface{}{\n\t\t\"rx_dropped\":   uint64(1),\n\t\t\"rx_bytes\":     uint64(2),\n\t\t\"rx_errors\":    uint64(3),\n\t\t\"tx_packets\":   uint64(4),\n\t\t\"tx_dropped\":   uint64(1),\n\t\t\"rx_packets\":   uint64(2),\n\t\t\"tx_errors\":    uint64(3),\n\t\t\"tx_bytes\":     uint64(4),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tnettags := copyTags(tags)\n\tnettags[\"network\"] = \"eth0\"\n\tacc.AssertContainsTaggedFields(t, \"docker_container_net\", netfields, nettags)\n\n\tnetfields = map[string]interface{}{\n\t\t\"rx_dropped\":   uint64(6),\n\t\t\"rx_bytes\":     uint64(8),\n\t\t\"rx_errors\":    uint64(10),\n\t\t\"tx_packets\":   uint64(12),\n\t\t\"tx_dropped\":   uint64(6),\n\t\t\"rx_packets\":   uint64(8),\n\t\t\"tx_errors\":    uint64(10),\n\t\t\"tx_bytes\":     uint64(12),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tnettags = copyTags(tags)\n\tnettags[\"network\"] = \"total\"\n\tacc.AssertContainsTaggedFields(t, \"docker_container_net\", netfields, nettags)\n\n\t// test docker_blkio measurement\n\tblkiotags := copyTags(tags)\n\tblkiotags[\"device\"] = \"6:0\"\n\tblkiofields := map[string]interface{}{\n\t\t\"io_service_bytes_recursive_read\": uint64(100),\n\t\t\"io_serviced_recursive_write\":     uint64(101),\n\t\t\"container_id\":                    \"123456789\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"docker_container_blkio\", blkiofields, blkiotags)\n\n\tblkiotags = copyTags(tags)\n\tblkiotags[\"device\"] = \"total\"\n\tblkiofields = map[string]interface{}{\n\t\t\"io_service_bytes_recursive_read\": uint64(100),\n\t\t\"io_serviced_recursive_write\":     uint64(302),\n\t\t\"container_id\":                    \"123456789\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"docker_container_blkio\", blkiofields, blkiotags)\n\n\t// test docker_container_mem measurement\n\tmemfields := map[string]interface{}{\n\t\t\"active_anon\":               uint64(0),\n\t\t\"active_file\":               uint64(1),\n\t\t\"cache\":                     uint64(0),\n\t\t\"container_id\":              \"123456789\",\n\t\t\"fail_count\":                uint64(1),\n\t\t\"hierarchical_memory_limit\": uint64(0),\n\t\t\"inactive_anon\":             uint64(0),\n\t\t\"inactive_file\":             uint64(3),\n\t\t\"limit\":                     uint64(2000),\n\t\t\"mapped_file\":               uint64(0),\n\t\t\"max_usage\":                 uint64(1001),\n\t\t\"pgfault\":                   uint64(2),\n\t\t\"pgmajfault\":                uint64(0),\n\t\t\"pgpgin\":                    uint64(0),\n\t\t\"pgpgout\":                   uint64(0),\n\t\t\"rss_huge\":                  uint64(0),\n\t\t\"rss\":                       uint64(0),\n\t\t\"total_active_anon\":         uint64(0),\n\t\t\"total_active_file\":         uint64(0),\n\t\t\"total_cache\":               uint64(0),\n\t\t\"total_inactive_anon\":       uint64(0),\n\t\t\"total_inactive_file\":       uint64(0),\n\t\t\"total_mapped_file\":         uint64(0),\n\t\t\"total_pgfault\":             uint64(0),\n\t\t\"total_pgmajfault\":          uint64(0),\n\t\t\"total_pgpgin\":              uint64(4),\n\t\t\"total_pgpgout\":             uint64(0),\n\t\t\"total_rss_huge\":            uint64(444),\n\t\t\"total_rss\":                 uint64(44),\n\t\t\"total_unevictable\":         uint64(0),\n\t\t\"total_writeback\":           uint64(55),\n\t\t\"unevictable\":               uint64(0),\n\t\t\"usage_percent\":             float64(55.55),\n\t\t\"usage\":                     uint64(1111),\n\t\t\"writeback\":                 uint64(0),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"docker_container_mem\", memfields, tags)\n\n\t// test docker_container_cpu measurement\n\tcputags := copyTags(tags)\n\tcputags[\"cpu\"] = \"cpu-total\"\n\tcpufields := map[string]interface{}{\n\t\t\"usage_total\":                  uint64(500),\n\t\t\"usage_in_usermode\":            uint64(100),\n\t\t\"usage_in_kernelmode\":          uint64(200),\n\t\t\"usage_system\":                 uint64(100),\n\t\t\"throttling_periods\":           uint64(1),\n\t\t\"throttling_throttled_periods\": uint64(0),\n\t\t\"throttling_throttled_time\":    uint64(0),\n\t\t\"usage_percent\":                float64(400.0),\n\t\t\"container_id\":                 \"123456789\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"docker_container_cpu\", cpufields, cputags)\n\n\tcputags[\"cpu\"] = \"cpu0\"\n\tcpu0fields := map[string]interface{}{\n\t\t\"usage_total\":  uint64(1),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"docker_container_cpu\", cpu0fields, cputags)\n\n\tcputags[\"cpu\"] = \"cpu1\"\n\tcpu1fields := map[string]interface{}{\n\t\t\"usage_total\":  uint64(1002),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"docker_container_cpu\", cpu1fields, cputags)\n\n\t// Those tagged filed should not be present because of offline CPUs\n\tcputags[\"cpu\"] = \"cpu2\"\n\tcpu2fields := map[string]interface{}{\n\t\t\"usage_total\":  uint64(0),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, \"docker_container_cpu\", cpu2fields, cputags)\n\n\tcputags[\"cpu\"] = \"cpu3\"\n\tcpu3fields := map[string]interface{}{\n\t\t\"usage_total\":  uint64(0),\n\t\t\"container_id\": \"123456789\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, \"docker_container_cpu\", cpu3fields, cputags)\n}\n\nfunc TestDockerMemoryExcludesCache(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tstats := testStats()\n\n\ttags := map[string]string{\n\t\t\"container_name\":  \"redis\",\n\t\t\"container_image\": \"redis/image\",\n\t}\n\n\td := &Docker{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tdelete(stats.MemoryStats.Stats, \"cache\")\n\tdelete(stats.MemoryStats.Stats, \"inactive_file\")\n\tdelete(stats.MemoryStats.Stats, \"total_inactive_file\")\n\n\t// set cgroup v2 cache value\n\tstats.MemoryStats.Stats[\"inactive_file\"] = 9\n\n\td.parseContainerStats(stats, &acc, tags, \"123456789\", \"linux\")\n\n\t// test docker_container_mem measurement\n\tmemfields := map[string]interface{}{\n\t\t\"active_anon\":               uint64(0),\n\t\t\"active_file\":               uint64(1),\n\t\t\"container_id\":              \"123456789\",\n\t\t\"fail_count\":                uint64(1),\n\t\t\"hierarchical_memory_limit\": uint64(0),\n\t\t\"inactive_anon\":             uint64(0),\n\t\t\"inactive_file\":             uint64(9),\n\t\t\"limit\":                     uint64(2000),\n\t\t\"mapped_file\":               uint64(0),\n\t\t\"max_usage\":                 uint64(1001),\n\t\t\"pgfault\":                   uint64(2),\n\t\t\"pgmajfault\":                uint64(0),\n\t\t\"pgpgin\":                    uint64(0),\n\t\t\"pgpgout\":                   uint64(0),\n\t\t\"rss_huge\":                  uint64(0),\n\t\t\"rss\":                       uint64(0),\n\t\t\"total_active_anon\":         uint64(0),\n\t\t\"total_active_file\":         uint64(0),\n\t\t\"total_cache\":               uint64(0),\n\t\t\"total_inactive_anon\":       uint64(0),\n\t\t\"total_mapped_file\":         uint64(0),\n\t\t\"total_pgfault\":             uint64(0),\n\t\t\"total_pgmajfault\":          uint64(0),\n\t\t\"total_pgpgin\":              uint64(4),\n\t\t\"total_pgpgout\":             uint64(0),\n\t\t\"total_rss_huge\":            uint64(444),\n\t\t\"total_rss\":                 uint64(44),\n\t\t\"total_unevictable\":         uint64(0),\n\t\t\"total_writeback\":           uint64(55),\n\t\t\"unevictable\":               uint64(0),\n\t\t\"usage_percent\":             float64(55.1), // 1102 / 2000\n\t\t\"usage\":                     uint64(1102),\n\t\t\"writeback\":                 uint64(0),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"docker_container_mem\", memfields, tags)\n\tacc.ClearMetrics()\n\n\t// set cgroup v1 cache value (has priority over cgroups v2)\n\tstats.MemoryStats.Stats[\"total_inactive_file\"] = 7\n\n\td.parseContainerStats(stats, &acc, tags, \"123456789\", \"linux\")\n\n\t// test docker_container_mem measurement\n\tmemfields = map[string]interface{}{\n\t\t\"active_anon\": uint64(0),\n\t\t\"active_file\": uint64(1),\n\t\t// \"cache\":                     uint64(0),\n\t\t\"container_id\":              \"123456789\",\n\t\t\"fail_count\":                uint64(1),\n\t\t\"hierarchical_memory_limit\": uint64(0),\n\t\t\"inactive_anon\":             uint64(0),\n\t\t\"inactive_file\":             uint64(9),\n\t\t\"limit\":                     uint64(2000),\n\t\t\"mapped_file\":               uint64(0),\n\t\t\"max_usage\":                 uint64(1001),\n\t\t\"pgfault\":                   uint64(2),\n\t\t\"pgmajfault\":                uint64(0),\n\t\t\"pgpgin\":                    uint64(0),\n\t\t\"pgpgout\":                   uint64(0),\n\t\t\"rss_huge\":                  uint64(0),\n\t\t\"rss\":                       uint64(0),\n\t\t\"total_active_anon\":         uint64(0),\n\t\t\"total_active_file\":         uint64(0),\n\t\t\"total_cache\":               uint64(0),\n\t\t\"total_inactive_anon\":       uint64(0),\n\t\t\"total_inactive_file\":       uint64(7),\n\t\t\"total_mapped_file\":         uint64(0),\n\t\t\"total_pgfault\":             uint64(0),\n\t\t\"total_pgmajfault\":          uint64(0),\n\t\t\"total_pgpgin\":              uint64(4),\n\t\t\"total_pgpgout\":             uint64(0),\n\t\t\"total_rss_huge\":            uint64(444),\n\t\t\"total_rss\":                 uint64(44),\n\t\t\"total_unevictable\":         uint64(0),\n\t\t\"total_writeback\":           uint64(55),\n\t\t\"unevictable\":               uint64(0),\n\t\t\"usage_percent\":             float64(55.2), // 1104 / 2000\n\t\t\"usage\":                     uint64(1104),\n\t\t\"writeback\":                 uint64(0),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"docker_container_mem\", memfields, tags)\n\tacc.ClearMetrics()\n\n\t// set Docker 19.03 and older cache value (has priority over cgroups v1 and v2)\n\tstats.MemoryStats.Stats[\"cache\"] = 16\n\n\td.parseContainerStats(stats, &acc, tags, \"123456789\", \"linux\")\n\n\t// test docker_container_mem measurement\n\tmemfields = map[string]interface{}{\n\t\t\"active_anon\":               uint64(0),\n\t\t\"active_file\":               uint64(1),\n\t\t\"cache\":                     uint64(16),\n\t\t\"container_id\":              \"123456789\",\n\t\t\"fail_count\":                uint64(1),\n\t\t\"hierarchical_memory_limit\": uint64(0),\n\t\t\"inactive_anon\":             uint64(0),\n\t\t\"inactive_file\":             uint64(9),\n\t\t\"limit\":                     uint64(2000),\n\t\t\"mapped_file\":               uint64(0),\n\t\t\"max_usage\":                 uint64(1001),\n\t\t\"pgfault\":                   uint64(2),\n\t\t\"pgmajfault\":                uint64(0),\n\t\t\"pgpgin\":                    uint64(0),\n\t\t\"pgpgout\":                   uint64(0),\n\t\t\"rss_huge\":                  uint64(0),\n\t\t\"rss\":                       uint64(0),\n\t\t\"total_active_anon\":         uint64(0),\n\t\t\"total_active_file\":         uint64(0),\n\t\t\"total_cache\":               uint64(0),\n\t\t\"total_inactive_anon\":       uint64(0),\n\t\t\"total_inactive_file\":       uint64(7),\n\t\t\"total_mapped_file\":         uint64(0),\n\t\t\"total_pgfault\":             uint64(0),\n\t\t\"total_pgmajfault\":          uint64(0),\n\t\t\"total_pgpgin\":              uint64(4),\n\t\t\"total_pgpgout\":             uint64(0),\n\t\t\"total_rss_huge\":            uint64(444),\n\t\t\"total_rss\":                 uint64(44),\n\t\t\"total_unevictable\":         uint64(0),\n\t\t\"total_writeback\":           uint64(55),\n\t\t\"unevictable\":               uint64(0),\n\t\t\"usage_percent\":             float64(54.75), // 1095 / 2000\n\t\t\"usage\":                     uint64(1095),\n\t\t\"writeback\":                 uint64(0),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"docker_container_mem\", memfields, tags)\n}\n\nfunc TestDocker_WindowsMemoryContainerStats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\td := Docker{\n\t\tLog:     testutil.Logger{},\n\t\tTimeout: config.Duration(5 * time.Second),\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) {\n\t\t\treturn &mockClient{\n\t\t\t\tInfoF: func() (system.Info, error) {\n\t\t\t\t\treturn info, nil\n\t\t\t\t},\n\t\t\t\tContainerListF: func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\treturn containerList, nil\n\t\t\t\t},\n\t\t\t\tContainerStatsF: func(string) (container.StatsResponseReader, error) {\n\t\t\t\t\treturn containerStatsWindows(), nil\n\t\t\t\t},\n\t\t\t\tContainerInspectF: func() (container.InspectResponse, error) {\n\t\t\t\t\treturn containerInspect(), nil\n\t\t\t\t},\n\t\t\t\tServiceListF: func() ([]swarm.Service, error) {\n\t\t\t\t\treturn serviceList, nil\n\t\t\t\t},\n\t\t\t\tTaskListF: func() ([]swarm.Task, error) {\n\t\t\t\t\treturn taskList, nil\n\t\t\t\t},\n\t\t\t\tNodeListF: func() ([]swarm.Node, error) {\n\t\t\t\t\treturn nodeList, nil\n\t\t\t\t},\n\t\t\t\tDiskUsageF: func() (types.DiskUsage, error) {\n\t\t\t\t\treturn diskUsage, nil\n\t\t\t\t},\n\t\t\t\tClientVersionF: func() string {\n\t\t\t\t\treturn version\n\t\t\t\t},\n\t\t\t\tPingF: func() (types.Ping, error) {\n\t\t\t\t\treturn types.Ping{}, nil\n\t\t\t\t},\n\t\t\t\tCloseF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t}\n\trequire.NoError(t, d.Init())\n\trequire.NoError(t, d.Start(&acc))\n\terr := d.Gather(&acc)\n\trequire.NoError(t, err)\n}\n\nfunc TestContainerLabels(t *testing.T) {\n\tvar tests = []struct {\n\t\tname      string\n\t\tcontainer container.Summary\n\t\tinclude   []string\n\t\texclude   []string\n\t\texpected  map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"Nil filters matches all\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t}),\n\t\t\tinclude: nil,\n\t\t\texclude: nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Empty filters matches all\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t}),\n\t\t\texpected: map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Must match include\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t\t\"b\": \"y\",\n\t\t\t}),\n\t\t\tinclude: []string{\"a\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Must not match exclude\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t\t\"b\": \"y\",\n\t\t\t}),\n\t\t\texclude: []string{\"b\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"a\": \"x\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Include Glob\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"aa\": \"x\",\n\t\t\t\t\"ab\": \"y\",\n\t\t\t\t\"bb\": \"z\",\n\t\t\t}),\n\t\t\tinclude: []string{\"a*\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"aa\": \"x\",\n\t\t\t\t\"ab\": \"y\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Exclude Glob\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"aa\": \"x\",\n\t\t\t\t\"ab\": \"y\",\n\t\t\t\t\"bb\": \"z\",\n\t\t\t}),\n\t\t\texclude: []string{\"a*\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"bb\": \"z\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Excluded Includes\",\n\t\t\tcontainer: genContainerLabeled(map[string]string{\n\t\t\t\t\"aa\": \"x\",\n\t\t\t\t\"ab\": \"y\",\n\t\t\t\t\"bb\": \"z\",\n\t\t\t}),\n\t\t\tinclude: []string{\"a*\"},\n\t\t\texclude: []string{\"*b\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"aa\": \"x\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\tnewClientFunc := func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\tclient := baseClient\n\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\treturn []container.Summary{tt.container}, nil\n\t\t\t\t}\n\t\t\t\treturn &client, nil\n\t\t\t}\n\n\t\t\td := Docker{\n\t\t\t\tLog:          testutil.Logger{},\n\t\t\t\tnewClient:    newClientFunc,\n\t\t\t\tLabelInclude: tt.include,\n\t\t\t\tLabelExclude: tt.exclude,\n\t\t\t\tTotalInclude: []string{\"cpu\"},\n\t\t\t}\n\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\terr := d.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Grab tags from a container metric\n\t\t\tvar actual map[string]string\n\t\t\tfor _, mt := range acc.Metrics {\n\t\t\t\tif mt.Measurement == \"docker_container_cpu\" {\n\t\t\t\t\tactual = mt.Tags\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor k, v := range tt.expected {\n\t\t\t\trequire.Equal(t, v, actual[k])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc genContainerLabeled(labels map[string]string) container.Summary {\n\tc := containerList[0]\n\tc.Labels = labels\n\tc.State = \"running\"\n\treturn c\n}\n\nfunc TestContainerNames(t *testing.T) {\n\tvar tests = []struct {\n\t\tname       string\n\t\tcontainers [][]string\n\t\tinclude    []string\n\t\texclude    []string\n\t\texpected   []string\n\t}{\n\t\t{\n\t\t\tname:     \"Nil filters matches all\",\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: []string{\"etcd\", \"etcd2\", \"acme\", \"acme-test\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Empty filters matches all\",\n\t\t\texpected: []string{\"etcd\", \"etcd2\", \"acme\", \"acme-test\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Match all containers\",\n\t\t\tinclude:  []string{\"*\"},\n\t\t\texpected: []string{\"etcd\", \"etcd2\", \"acme\", \"acme-test\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Include prefix match\",\n\t\t\tinclude:  []string{\"etc*\"},\n\t\t\texpected: []string{\"etcd\", \"etcd2\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Exact match\",\n\t\t\tinclude:  []string{\"etcd\"},\n\t\t\texpected: []string{\"etcd\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Star matches zero length\",\n\t\t\tinclude:  []string{\"etcd2*\"},\n\t\t\texpected: []string{\"etcd2\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Exclude matches all\",\n\t\t\texclude:  []string{\"etc*\"},\n\t\t\texpected: []string{\"acme\", \"acme-test\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Exclude single\",\n\t\t\texclude:  []string{\"etcd\"},\n\t\t\texpected: []string{\"etcd2\", \"acme\", \"acme-test\", \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"Exclude all\",\n\t\t\tinclude: []string{\"*\"},\n\t\t\texclude: []string{\"*\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Exclude item matching include\",\n\t\t\tinclude:  []string{\"acme*\"},\n\t\t\texclude:  []string{\"*test*\"},\n\t\t\texpected: []string{\"acme\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Exclude item no wildcards\",\n\t\t\tinclude:  []string{\"acme*\"},\n\t\t\texclude:  []string{\"test\"},\n\t\t\texpected: []string{\"acme\", \"acme-test\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\tnewClientFunc := func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\tclient := baseClient\n\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\treturn containerList, nil\n\t\t\t\t}\n\t\t\t\tclient.ContainerStatsF = func(s string) (container.StatsResponseReader, error) {\n\t\t\t\t\treturn containerStats(s), nil\n\t\t\t\t}\n\n\t\t\t\treturn &client, nil\n\t\t\t}\n\n\t\t\td := Docker{\n\t\t\t\tLog:              testutil.Logger{},\n\t\t\t\tnewClient:        newClientFunc,\n\t\t\t\tContainerInclude: tt.include,\n\t\t\t\tContainerExclude: tt.exclude,\n\t\t\t}\n\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\terr := d.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Set of expected names\n\t\t\texpected := make(map[string]bool)\n\t\t\tfor _, v := range tt.expected {\n\t\t\t\texpected[v] = true\n\t\t\t}\n\n\t\t\t// Set of actual names\n\t\t\tactual := make(map[string]bool)\n\t\t\tfor _, mt := range acc.Metrics {\n\t\t\t\tif name, ok := mt.Tags[\"container_name\"]; ok {\n\t\t\t\t\tactual[name] = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.Equal(t, expected, actual)\n\t\t})\n\t}\n}\n\nfunc filterMetrics(metrics []telegraf.Metric, f func(telegraf.Metric) bool) []telegraf.Metric {\n\tresults := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, m := range metrics {\n\t\tif f(m) {\n\t\t\tresults = append(results, m)\n\t\t}\n\t}\n\treturn results\n}\n\nfunc TestContainerStatus(t *testing.T) {\n\tvar tests = []struct {\n\t\tname     string\n\t\tnow      func() time.Time\n\t\tinspect  container.InspectResponse\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"finished_at is zero value\",\n\t\t\tnow: func() time.Time {\n\t\t\t\treturn time.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC)\n\t\t\t},\n\t\t\tinspect: containerInspect(),\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_container_status\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"etcd\",\n\t\t\t\t\t\t\"container_image\":   \"quay.io/coreos/etcd\",\n\t\t\t\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\t\t\t\"container_status\":  \"running\",\n\t\t\t\t\t\t\"source\":            \"e2173b9478a6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"oomkilled\":     false,\n\t\t\t\t\t\t\"pid\":           1234,\n\t\t\t\t\t\t\"restart_count\": 0,\n\t\t\t\t\t\t\"exitcode\":      0,\n\t\t\t\t\t\t\"container_id\":  \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\",\n\t\t\t\t\t\t\"started_at\":    time.Date(2018, 6, 14, 5, 48, 53, 266176036, time.UTC).UnixNano(),\n\t\t\t\t\t\t\"uptime_ns\":     int64(3 * time.Minute),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"finished_at is non-zero value\",\n\t\t\tnow: func() time.Time {\n\t\t\t\treturn time.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC)\n\t\t\t},\n\t\t\tinspect: func() container.InspectResponse {\n\t\t\t\ti := containerInspect()\n\t\t\t\ti.ContainerJSONBase.State.FinishedAt = \"2018-06-14T05:53:53.266176036Z\"\n\t\t\t\treturn i\n\t\t\t}(),\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_container_status\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"etcd\",\n\t\t\t\t\t\t\"container_image\":   \"quay.io/coreos/etcd\",\n\t\t\t\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\t\t\t\"container_status\":  \"running\",\n\t\t\t\t\t\t\"source\":            \"e2173b9478a6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"oomkilled\":     false,\n\t\t\t\t\t\t\"pid\":           1234,\n\t\t\t\t\t\t\"exitcode\":      0,\n\t\t\t\t\t\t\"restart_count\": 0,\n\t\t\t\t\t\t\"container_id\":  \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\",\n\t\t\t\t\t\t\"started_at\":    time.Date(2018, 6, 14, 5, 48, 53, 266176036, time.UTC).UnixNano(),\n\t\t\t\t\t\t\"finished_at\":   time.Date(2018, 6, 14, 5, 53, 53, 266176036, time.UTC).UnixNano(),\n\t\t\t\t\t\t\"uptime_ns\":     int64(5 * time.Minute),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"started_at is zero value\",\n\t\t\tnow: func() time.Time {\n\t\t\t\treturn time.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC)\n\t\t\t},\n\t\t\tinspect: func() container.InspectResponse {\n\t\t\t\ti := containerInspect()\n\t\t\t\ti.ContainerJSONBase.State.StartedAt = \"\"\n\t\t\t\ti.ContainerJSONBase.State.FinishedAt = \"2018-06-14T05:53:53.266176036Z\"\n\t\t\t\treturn i\n\t\t\t}(),\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_container_status\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"etcd\",\n\t\t\t\t\t\t\"container_image\":   \"quay.io/coreos/etcd\",\n\t\t\t\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\t\t\t\"container_status\":  \"running\",\n\t\t\t\t\t\t\"source\":            \"e2173b9478a6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"oomkilled\":     false,\n\t\t\t\t\t\t\"pid\":           1234,\n\t\t\t\t\t\t\"exitcode\":      0,\n\t\t\t\t\t\t\"restart_count\": 0,\n\t\t\t\t\t\t\"container_id\":  \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\",\n\t\t\t\t\t\t\"finished_at\":   time.Date(2018, 6, 14, 5, 53, 53, 266176036, time.UTC).UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"container has been restarted\",\n\t\t\tnow: func() time.Time {\n\t\t\t\treturn time.Date(2019, 1, 1, 0, 0, 3, 0, time.UTC)\n\t\t\t},\n\t\t\tinspect: func() container.InspectResponse {\n\t\t\t\ti := containerInspect()\n\t\t\t\ti.ContainerJSONBase.State.StartedAt = \"2019-01-01T00:00:02Z\"\n\t\t\t\ti.ContainerJSONBase.State.FinishedAt = \"2019-01-01T00:00:01Z\"\n\t\t\t\treturn i\n\t\t\t}(),\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_container_status\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"etcd\",\n\t\t\t\t\t\t\"container_image\":   \"quay.io/coreos/etcd\",\n\t\t\t\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\t\t\t\"container_status\":  \"running\",\n\t\t\t\t\t\t\"source\":            \"e2173b9478a6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"oomkilled\":     false,\n\t\t\t\t\t\t\"pid\":           1234,\n\t\t\t\t\t\t\"exitcode\":      0,\n\t\t\t\t\t\t\"restart_count\": 0,\n\t\t\t\t\t\t\"container_id\":  \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\",\n\t\t\t\t\t\t\"started_at\":    time.Date(2019, 1, 1, 0, 0, 2, 0, time.UTC).UnixNano(),\n\t\t\t\t\t\t\"finished_at\":   time.Date(2019, 1, 1, 0, 0, 1, 0, time.UTC).UnixNano(),\n\t\t\t\t\t\t\"uptime_ns\":     int64(1 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2019, 1, 1, 0, 0, 3, 0, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar (\n\t\t\t\tacc           testutil.Accumulator\n\t\t\t\tnewClientFunc = func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\t\tclient := baseClient\n\t\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\t\treturn containerList[:1], nil\n\t\t\t\t\t}\n\t\t\t\t\tclient.ContainerInspectF = func() (container.InspectResponse, error) {\n\t\t\t\t\t\treturn tt.inspect, nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn &client, nil\n\t\t\t\t}\n\t\t\t\td = Docker{\n\t\t\t\t\tLog:              testutil.Logger{},\n\t\t\t\t\tnewClient:        newClientFunc,\n\t\t\t\t\tIncludeSourceTag: true,\n\t\t\t\t}\n\t\t\t)\n\n\t\t\t// mock time\n\t\t\tif tt.now != nil {\n\t\t\t\tnow = tt.now\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\tnow = time.Now\n\t\t\t}()\n\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\terr := d.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tactual := filterMetrics(acc.GetTelegrafMetrics(), func(m telegraf.Metric) bool {\n\t\t\t\treturn m.Name() == \"docker_container_status\"\n\t\t\t})\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestDockerGatherInfo(t *testing.T) {\n\tvar acc testutil.Accumulator\n\td := Docker{\n\t\tLog:       testutil.Logger{},\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) { return &baseClient, nil },\n\t\tTagEnvironment: []string{\"ENVVAR1\", \"ENVVAR2\", \"ENVVAR3\", \"ENVVAR5\",\n\t\t\t\"ENVVAR6\", \"ENVVAR7\", \"ENVVAR8\", \"ENVVAR9\"},\n\t\tPerDeviceInclude: []string{\"cpu\", \"network\", \"blkio\"},\n\t\tTotalInclude:     []string{\"cpu\", \"blkio\", \"network\"},\n\t}\n\n\trequire.NoError(t, d.Init())\n\trequire.NoError(t, d.Start(&acc))\n\terr := acc.GatherError(d.Gather)\n\trequire.NoError(t, err)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker\",\n\t\tmap[string]interface{}{\n\t\t\t\"n_listener_events\":       int(0),\n\t\t\t\"n_cpus\":                  int(4),\n\t\t\t\"n_used_file_descriptors\": int(19),\n\t\t\t\"n_containers\":            int(108),\n\t\t\t\"n_containers_running\":    int(98),\n\t\t\t\"n_containers_stopped\":    int(6),\n\t\t\t\"n_containers_paused\":     int(3),\n\t\t\t\"n_images\":                int(199),\n\t\t\t\"n_goroutines\":            int(39),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker\",\n\t\tmap[string]interface{}{\n\t\t\t\"memory_total\": int64(3840757760),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker\",\n\t\tmap[string]interface{}{\n\t\t\t\"pool_blocksize\": int64(65540),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t\t\"unit\":           \"bytes\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_data\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\":      int64(17300000000),\n\t\t\t\"total\":     int64(107400000000),\n\t\t\t\"available\": int64(36530000000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t\t\"unit\":           \"bytes\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_metadata\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\":      int64(20970000),\n\t\t\t\"total\":     int64(2146999999),\n\t\t\t\"available\": int64(2126999999),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t\t\"unit\":           \"bytes\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_devicemapper\",\n\t\tmap[string]interface{}{\n\t\t\t\"base_device_size_bytes\":             int64(10740000000),\n\t\t\t\"pool_blocksize_bytes\":               int64(65540),\n\t\t\t\"data_space_used_bytes\":              int64(17300000000),\n\t\t\t\"data_space_total_bytes\":             int64(107400000000),\n\t\t\t\"data_space_available_bytes\":         int64(36530000000),\n\t\t\t\"metadata_space_used_bytes\":          int64(20970000),\n\t\t\t\"metadata_space_total_bytes\":         int64(2146999999),\n\t\t\t\"metadata_space_available_bytes\":     int64(2126999999),\n\t\t\t\"thin_pool_minimum_free_space_bytes\": int64(10740000000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t\t\"pool_name\":      \"docker-8:1-1182287-pool\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_container_cpu\",\n\t\tmap[string]interface{}{\n\t\t\t\"usage_total\":  uint64(1231652),\n\t\t\t\"container_id\": \"b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173\",\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"container_name\":    \"etcd2\",\n\t\t\t\"container_image\":   \"quay.io:4443/coreos/etcd\",\n\t\t\t\"cpu\":               \"cpu3\",\n\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\"ENVVAR1\":           \"loremipsum\",\n\t\t\t\"ENVVAR2\":           \"dolorsitamet\",\n\t\t\t\"ENVVAR3\":           \"=ubuntu:10.04\",\n\t\t\t\"ENVVAR7\":           \"ENVVAR8=ENVVAR9\",\n\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\"container_status\":  \"running\",\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_container_mem\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\":  \"b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173\",\n\t\t\t\"limit\":         uint64(18935443456),\n\t\t\t\"max_usage\":     uint64(0),\n\t\t\t\"usage\":         uint64(0),\n\t\t\t\"usage_percent\": float64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\"container_name\":    \"etcd2\",\n\t\t\t\"container_image\":   \"quay.io:4443/coreos/etcd\",\n\t\t\t\"container_version\": \"v3.3.25\",\n\t\t\t\"ENVVAR1\":           \"loremipsum\",\n\t\t\t\"ENVVAR2\":           \"dolorsitamet\",\n\t\t\t\"ENVVAR3\":           \"=ubuntu:10.04\",\n\t\t\t\"ENVVAR7\":           \"ENVVAR8=ENVVAR9\",\n\t\t\t\"label1\":            \"test_value_1\",\n\t\t\t\"label2\":            \"test_value_2\",\n\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\"container_status\":  \"running\",\n\t\t},\n\t)\n}\n\nfunc TestDockerGatherSwarmInfo(t *testing.T) {\n\tvar acc testutil.Accumulator\n\td := Docker{\n\t\tLog:       testutil.Logger{},\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) { return &baseClient, nil },\n\t}\n\n\trequire.NoError(t, d.Init())\n\trequire.NoError(t, d.Start(&acc))\n\terr := acc.GatherError(d.Gather)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, d.gatherSwarmInfo(&acc))\n\n\t// test docker_container_net measurement\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_swarm\",\n\t\tmap[string]interface{}{\n\t\t\t\"tasks_running\": int(2),\n\t\t\t\"tasks_desired\": uint64(2),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"service_id\":   \"qolkls9g5iasdiuihcyz9rnx2\",\n\t\t\t\"service_name\": \"test1\",\n\t\t\t\"service_mode\": \"replicated\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_swarm\",\n\t\tmap[string]interface{}{\n\t\t\t\"tasks_running\": int(1),\n\t\t\t\"tasks_desired\": uint64(1),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"service_id\":   \"qolkls9g5iasdiuihcyz9rn3\",\n\t\t\t\"service_name\": \"test2\",\n\t\t\t\"service_mode\": \"global\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_swarm\",\n\t\tmap[string]interface{}{\n\t\t\t\"tasks_running\":     int(0),\n\t\t\t\"max_concurrent\":    uint64(2),\n\t\t\t\"total_completions\": uint64(2),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"service_id\":   \"rfmqydhe8cluzl9hayyrhw5ga\",\n\t\t\t\"service_name\": \"test3\",\n\t\t\t\"service_mode\": \"replicated_job\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_swarm\",\n\t\tmap[string]interface{}{\n\t\t\t\"tasks_running\": int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"service_id\":   \"mp50lo68vqgkory4e26ts8f9d\",\n\t\t\t\"service_name\": \"test4\",\n\t\t\t\"service_mode\": \"global_job\",\n\t\t},\n\t)\n}\n\nfunc TestContainerStateFilter(t *testing.T) {\n\tvar tests = []struct {\n\t\tname     string\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname:     \"default\",\n\t\t\texpected: []string{\"running\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"include running\",\n\t\t\tinclude:  []string{\"running\"},\n\t\t\texpected: []string{\"running\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"include glob\",\n\t\t\tinclude:  []string{\"r*\"},\n\t\t\texpected: []string{\"restarting\", \"running\", \"removing\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"include all\",\n\t\t\tinclude:  []string{\"*\"},\n\t\t\texpected: []string{\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"exclude all\",\n\t\t\texclude: []string{\"*\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"exclude exited\",\n\t\t\tinclude:  []string{\"*\"},\n\t\t\texclude:  []string{\"exited\"},\n\t\t\texpected: []string{\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"dead\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\tcontainerStates := []string{\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"}\n\n\t\t\tnewClientFunc := func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\tclient := baseClient\n\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\tcontainers := make([]container.Summary, 0, len(containerStates))\n\t\t\t\t\tfor _, v := range containerStates {\n\t\t\t\t\t\tcontainers = append(containers, container.Summary{\n\t\t\t\t\t\t\tNames: []string{v},\n\t\t\t\t\t\t\tState: v,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\treturn containers, nil\n\t\t\t\t}\n\t\t\t\treturn &client, nil\n\t\t\t}\n\n\t\t\td := Docker{\n\t\t\t\tLog:                   testutil.Logger{},\n\t\t\t\tnewClient:             newClientFunc,\n\t\t\t\tContainerStateInclude: tt.include,\n\t\t\t\tContainerStateExclude: tt.exclude,\n\t\t\t}\n\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\terr := d.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Set of expected names\n\t\t\texpected := make(map[string]bool)\n\t\t\tfor _, v := range tt.expected {\n\t\t\t\texpected[v] = true\n\t\t\t}\n\n\t\t\t// Set of actual names\n\t\t\tactual := make(map[string]bool)\n\t\t\tfor _, mt := range acc.Metrics {\n\t\t\t\tif name, ok := mt.Tags[\"container_name\"]; ok {\n\t\t\t\t\tactual[name] = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.Equal(t, expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestNonRunningContainerEmitsStatusMetrics(t *testing.T) {\n\tnewClientFunc := func(string, *tls.Config) (dockerClient, error) {\n\t\tclient := baseClient\n\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\treturn []container.Summary{\n\t\t\t\t{\n\t\t\t\t\tID:    \"abc123\",\n\t\t\t\t\tNames: []string{\"/stopped-container\"},\n\t\t\t\t\tState: \"exited\",\n\t\t\t\t},\n\t\t\t}, nil\n\t\t}\n\t\tclient.ContainerStatsF = func(string) (container.StatsResponseReader, error) {\n\t\t\treturn container.StatsResponseReader{\n\t\t\t\tBody: io.NopCloser(strings.NewReader(\"\")),\n\t\t\t}, nil\n\t\t}\n\t\tclient.ContainerInspectF = func() (container.InspectResponse, error) {\n\t\t\treturn container.InspectResponse{\n\t\t\t\tConfig: &container.Config{},\n\t\t\t\tContainerJSONBase: &container.ContainerJSONBase{\n\t\t\t\t\tState: &container.State{\n\t\t\t\t\t\tStatus:     \"exited\",\n\t\t\t\t\t\tExitCode:   137,\n\t\t\t\t\t\tStartedAt:  \"2024-01-01T00:00:00Z\",\n\t\t\t\t\t\tFinishedAt: \"2024-01-01T01:00:00Z\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}, nil\n\t\t}\n\t\treturn &client, nil\n\t}\n\n\td := Docker{\n\t\tLog:                   testutil.Logger{},\n\t\tnewClient:             newClientFunc,\n\t\tContainerStateInclude: []string{\"exited\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, d.Init())\n\trequire.NoError(t, d.Start(&acc))\n\trequire.NoError(t, d.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"docker_container_status\",\n\t\t\tmap[string]string{\n\t\t\t\t\"container_name\":    \"stopped-container\",\n\t\t\t\t\"container_image\":   \"\",\n\t\t\t\t\"container_version\": \"unknown\",\n\t\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\t\"container_status\":  \"exited\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"oomkilled\":     false,\n\t\t\t\t\"pid\":           0,\n\t\t\t\t\"exitcode\":      137,\n\t\t\t\t\"restart_count\": 0,\n\t\t\t\t\"container_id\":  \"abc123\",\n\t\t\t\t\"started_at\":    time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC).UnixNano(),\n\t\t\t\t\"finished_at\":   time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC).UnixNano(),\n\t\t\t\t\"uptime_ns\":     int64(time.Hour),\n\t\t\t},\n\t\t\ttime.Time{},\n\t\t),\n\t}\n\n\tactual := filterMetrics(acc.GetTelegrafMetrics(), func(m telegraf.Metric) bool {\n\t\treturn strings.HasPrefix(m.Name(), \"docker_container_\")\n\t})\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestContainerName(t *testing.T) {\n\ttests := []struct {\n\t\tname       string\n\t\tclientFunc func(host string, tlsConfig *tls.Config) (dockerClient, error)\n\t\texpected   string\n\t}{\n\t\t{\n\t\t\tname: \"container stats name is preferred\",\n\t\t\tclientFunc: func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\tclient := baseClient\n\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\tcontainers := []container.Summary{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNames: []string{\"/logspout/foo\"},\n\t\t\t\t\t\t\tState: \"running\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn containers, nil\n\t\t\t\t}\n\t\t\t\tclient.ContainerStatsF = func(string) (container.StatsResponseReader, error) {\n\t\t\t\t\treturn container.StatsResponseReader{\n\t\t\t\t\t\tBody: io.NopCloser(strings.NewReader(`{\"name\": \"logspout\"}`)),\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t\treturn &client, nil\n\t\t\t},\n\t\t\texpected: \"logspout\",\n\t\t},\n\t\t{\n\t\t\tname: \"container stats without name uses container list name\",\n\t\t\tclientFunc: func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\tclient := baseClient\n\t\t\t\tclient.ContainerListF = func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\tcontainers := []container.Summary{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNames: []string{\"/logspout\"},\n\t\t\t\t\t\t\tState: \"running\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn containers, nil\n\t\t\t\t}\n\t\t\t\tclient.ContainerStatsF = func(string) (container.StatsResponseReader, error) {\n\t\t\t\t\treturn container.StatsResponseReader{\n\t\t\t\t\t\tBody: io.NopCloser(strings.NewReader(`{}`)),\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t\treturn &client, nil\n\t\t\t},\n\t\t\texpected: \"logspout\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\td := Docker{\n\t\t\t\tLog:       testutil.Logger{},\n\t\t\t\tnewClient: tt.clientFunc,\n\t\t\t}\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\terr := d.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, mt := range acc.Metrics {\n\t\t\t\t// This tag is set on all container measurements\n\t\t\t\tif mt.Measurement == \"docker_container_mem\" {\n\t\t\t\t\trequire.Equal(t, tt.expected, mt.Tags[\"container_name\"])\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHostnameFromID(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tid     string\n\t\texpect string\n\t}{\n\t\t{\n\t\t\tname:   \"Real ID\",\n\t\t\tid:     \"565e3a55f5843cfdd4aa5659a1a75e4e78d47f73c3c483f782fe4a26fc8caa07\",\n\t\t\texpect: \"565e3a55f584\",\n\t\t},\n\t\t{\n\t\t\tname:   \"Short ID\",\n\t\t\tid:     \"shortid123\",\n\t\t\texpect: \"shortid123\",\n\t\t},\n\t\t{\n\t\t\tname:   \"No ID\",\n\t\t\tid:     \"\",\n\t\t\texpect: \"shortid123\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\toutput := hostnameFromID(test.id)\n\t\t\tif test.expect != output {\n\t\t\t\tt.Logf(\"Container ID for hostname is wrong. Want: %s, Got: %s\", output, test.expect)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_parseContainerStatsPerDeviceAndTotal(t *testing.T) {\n\ttype args struct {\n\t\tstat             *container.StatsResponse\n\t\ttags             map[string]string\n\t\tid               string\n\t\tperDeviceInclude []string\n\t\ttotalInclude     []string\n\t\tdaemonOSType     string\n\t}\n\n\tvar (\n\t\ttestDate       = time.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC)\n\t\tmetricCPUTotal = testutil.MustMetric(\n\t\t\t\"docker_container_cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu-total\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\n\t\tmetricCPU0 = testutil.MustMetric(\n\t\t\t\"docker_container_cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\t\tmetricCPU1 = testutil.MustMetric(\n\t\t\t\"docker_container_cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu\": \"cpu1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\n\t\tmetricNetworkTotal = testutil.MustMetric(\n\t\t\t\"docker_container_net\",\n\t\t\tmap[string]string{\n\t\t\t\t\"network\": \"total\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\n\t\tmetricNetworkEth0 = testutil.MustMetric(\n\t\t\t\"docker_container_net\",\n\t\t\tmap[string]string{\n\t\t\t\t\"network\": \"eth0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\n\t\tmetricNetworkEth1 = testutil.MustMetric(\n\t\t\t\"docker_container_net\",\n\t\t\tmap[string]string{\n\t\t\t\t\"network\": \"eth0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\t\tmetricBlkioTotal = testutil.MustMetric(\n\t\t\t\"docker_container_blkio\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"total\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\t\tmetricBlkio6_0 = testutil.MustMetric(\n\t\t\t\"docker_container_blkio\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"6:0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\t\tmetricBlkio6_1 = testutil.MustMetric(\n\t\t\t\"docker_container_blkio\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"6:1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{},\n\t\t\ttestDate)\n\t)\n\tstats := testStats()\n\ttests := []struct {\n\t\tname     string\n\t\targs     args\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"Per device and total metrics enabled\",\n\t\t\targs: args{\n\t\t\t\tstat:             stats,\n\t\t\t\tperDeviceInclude: containerMetricClasses,\n\t\t\t\ttotalInclude:     containerMetricClasses,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetricCPUTotal, metricCPU0, metricCPU1,\n\t\t\t\tmetricNetworkTotal, metricNetworkEth0, metricNetworkEth1,\n\t\t\t\tmetricBlkioTotal, metricBlkio6_0, metricBlkio6_1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Per device metrics enabled\",\n\t\t\targs: args{\n\t\t\t\tstat:             stats,\n\t\t\t\tperDeviceInclude: containerMetricClasses,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetricCPU0, metricCPU1,\n\t\t\t\tmetricNetworkEth0, metricNetworkEth1,\n\t\t\t\tmetricBlkio6_0, metricBlkio6_1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Total metrics enabled\",\n\t\t\targs: args{\n\t\t\t\tstat:         stats,\n\t\t\t\ttotalInclude: containerMetricClasses,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{metricCPUTotal, metricNetworkTotal, metricBlkioTotal},\n\t\t},\n\t\t{\n\t\t\tname: \"Per device and total metrics disabled\",\n\t\t\targs: args{\n\t\t\t\tstat: stats,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\td := &Docker{\n\t\t\t\tLog:              testutil.Logger{},\n\t\t\t\tPerDeviceInclude: tt.args.perDeviceInclude,\n\t\t\t\tTotalInclude:     tt.args.totalInclude,\n\t\t\t}\n\t\t\td.parseContainerStats(tt.args.stat, &acc, tt.args.tags, tt.args.id, tt.args.daemonOSType)\n\n\t\t\tactual := filterMetrics(acc.GetTelegrafMetrics(), func(m telegraf.Metric) bool {\n\t\t\t\treturn choice.Contains(m.Name(),\n\t\t\t\t\t[]string{\"docker_container_cpu\", \"docker_container_net\", \"docker_container_blkio\"})\n\t\t\t})\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, testutil.OnlyTags(), testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc TestDocker_Init(t *testing.T) {\n\ttype fields struct {\n\t\tPerDeviceInclude []string\n\t\tTotalInclude     []string\n\t}\n\ttests := []struct {\n\t\tname                 string\n\t\tfields               fields\n\t\twantErr              bool\n\t\twantPerDeviceInclude []string\n\t\twantTotalInclude     []string\n\t}{\n\t\t{\n\t\t\tname: \"Unsupported perdevice_include setting\",\n\t\t\tfields: fields{\n\t\t\t\tPerDeviceInclude: []string{\"nonExistentClass\"},\n\t\t\t\tTotalInclude:     []string{\"cpu\"},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Unsupported total_include setting\",\n\t\t\tfields: fields{\n\t\t\t\tPerDeviceInclude: []string{\"cpu\"},\n\t\t\t\tTotalInclude:     []string{\"nonExistentClass\"},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Valid perdevice_include and total_include\",\n\t\t\tfields: fields{\n\t\t\t\tPerDeviceInclude: []string{\"cpu\", \"network\"},\n\t\t\t\tTotalInclude:     []string{\"cpu\", \"blkio\"},\n\t\t\t},\n\t\t\twantPerDeviceInclude: []string{\"cpu\", \"network\"},\n\t\t\twantTotalInclude:     []string{\"cpu\", \"blkio\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\td := &Docker{\n\t\t\t\tLog:              testutil.Logger{},\n\t\t\t\tPerDeviceInclude: tt.fields.PerDeviceInclude,\n\t\t\t\tTotalInclude:     tt.fields.TotalInclude,\n\t\t\t}\n\t\t\terr := d.Init()\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"Init() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t}\n\n\t\t\tif err == nil {\n\t\t\t\tif !reflect.DeepEqual(d.PerDeviceInclude, tt.wantPerDeviceInclude) {\n\t\t\t\t\tt.Errorf(\"Perdevice include: got  '%v', want '%v'\", d.PerDeviceInclude, tt.wantPerDeviceInclude)\n\t\t\t\t}\n\n\t\t\t\tif !reflect.DeepEqual(d.TotalInclude, tt.wantTotalInclude) {\n\t\t\t\t\tt.Errorf(\"Total include: got  '%v', want '%v'\", d.TotalInclude, tt.wantTotalInclude)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDockerGatherDiskUsage(t *testing.T) {\n\tvar acc testutil.Accumulator\n\td := Docker{\n\t\tLog:       testutil.Logger{},\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) { return &baseClient, nil },\n\t}\n\n\trequire.NoError(t, d.Init())\n\trequire.NoError(t, d.Start(&acc))\n\n\trequire.NoError(t, acc.GatherError(d.Gather))\n\n\td.gatherDiskUsage(&acc, types.DiskUsageOptions{})\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_disk_usage\",\n\t\tmap[string]interface{}{\n\t\t\t\"layers_size\": int64(1e10),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_disk_usage\",\n\t\tmap[string]interface{}{\n\t\t\t\"size_root_fs\": int64(123456789),\n\t\t\t\"size_rw\":      int64(0)},\n\t\tmap[string]string{\n\t\t\t\"container_image\":   \"some_image\",\n\t\t\t\"container_version\": \"1.0.0-alpine\",\n\t\t\t\"engine_host\":       \"absol\",\n\t\t\t\"server_version\":    \"17.09.0-ce\",\n\t\t\t\"container_name\":    \"some_container\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_disk_usage\",\n\t\tmap[string]interface{}{\n\t\t\t\"size\":        int64(123456789),\n\t\t\t\"shared_size\": int64(0)},\n\t\tmap[string]string{\n\t\t\t\"image_id\":       \"some_imageid\",\n\t\t\t\"image_name\":     \"some_image_tag\",\n\t\t\t\"image_version\":  \"1.0.0-alpine\",\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_disk_usage\",\n\t\tmap[string]interface{}{\n\t\t\t\"size\":        int64(425484494),\n\t\t\t\"shared_size\": int64(0)},\n\t\tmap[string]string{\n\t\t\t\"image_id\":       \"7f4a1cc74046\",\n\t\t\t\"image_name\":     \"telegraf\",\n\t\t\t\"image_version\":  \"latest\",\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"docker_disk_usage\",\n\t\tmap[string]interface{}{\n\t\t\t\"size\": int64(123456789),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"volume_name\":    \"some_volume\",\n\t\t\t\"engine_host\":    \"absol\",\n\t\t\t\"server_version\": \"17.09.0-ce\",\n\t\t},\n\t)\n}\n\nfunc TestPodmanDetection(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tserverVersion string\n\t\tengineName    string\n\t\tendpoint      string\n\t\tinitBinary    string\n\t\texpectPodman  bool\n\t}{\n\t\t{\n\t\t\tname:          \"Docker engine\",\n\t\t\tserverVersion: \"28.3.2\",\n\t\t\tengineName:    \"docker-desktop\",\n\t\t\tendpoint:      \"unix:///var/run/docker.sock\",\n\t\t\tinitBinary:    \"docker-init\",\n\t\t\texpectPodman:  false,\n\t\t},\n\t\t{\n\t\t\tname:          \"Real Podman with version number\",\n\t\t\tserverVersion: \"5.6.1\",\n\t\t\tengineName:    \"localhost.localdomain\",\n\t\t\tendpoint:      \"unix:///run/podman/podman.sock\",\n\t\t\tinitBinary:    \"crun\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t\t{\n\t\t\tname:          \"Podman with version string containing podman\",\n\t\t\tserverVersion: \"4.9.4-podman\",\n\t\t\tengineName:    \"localhost\",\n\t\t\tendpoint:      \"unix:///run/podman/podman.sock\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t\t{\n\t\t\tname:          \"Podman with podman in name\",\n\t\t\tserverVersion: \"4.9.4\",\n\t\t\tengineName:    \"podman-machine\",\n\t\t\tendpoint:      \"unix:///var/run/docker.sock\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t\t{\n\t\t\tname:          \"Podman detected by endpoint\",\n\t\t\tserverVersion: \"5.2.0\",\n\t\t\tengineName:    \"localhost\",\n\t\t\tendpoint:      \"unix:///run/podman/podman.sock\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t\t{\n\t\t\tname:          \"Podman with crun runtime\",\n\t\t\tserverVersion: \"5.0.1\",\n\t\t\tengineName:    \"myhost.local\",\n\t\t\tendpoint:      \"unix:///var/run/container.sock\",\n\t\t\tinitBinary:    \"crun\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t\t{\n\t\t\tname:          \"Docker with crun (should not detect as Podman)\",\n\t\t\tserverVersion: \"20.10.7\",\n\t\t\tengineName:    \"docker-host\",\n\t\t\tendpoint:      \"unix:///var/run/docker.sock\",\n\t\t\tinitBinary:    \"crun\",\n\t\t\texpectPodman:  false,\n\t\t},\n\t\t{\n\t\t\tname:          \"Edge case - simple version with generic name\",\n\t\t\tserverVersion: \"4.8.2\",\n\t\t\tengineName:    \"host\",\n\t\t\tendpoint:      \"unix:///var/run/container.sock\",\n\t\t\texpectPodman:  true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\td := Docker{\n\t\t\t\tEndpoint: tt.endpoint,\n\t\t\t\tTimeout:  config.Duration(5 * time.Second),\n\t\t\t\tnewClient: func(string, *tls.Config) (dockerClient, error) {\n\t\t\t\t\treturn &mockClient{\n\t\t\t\t\t\tInfoF: func() (system.Info, error) {\n\t\t\t\t\t\t\treturn system.Info{\n\t\t\t\t\t\t\t\tName:          tt.engineName,\n\t\t\t\t\t\t\t\tServerVersion: tt.serverVersion,\n\t\t\t\t\t\t\t\tInitBinary:    tt.initBinary,\n\t\t\t\t\t\t\t}, nil\n\t\t\t\t\t\t},\n\t\t\t\t\t\tContainerListF: func(container.ListOptions) ([]container.Summary, error) {\n\t\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t\t},\n\t\t\t\t\t\tServiceListF: func() ([]swarm.Service, error) {\n\t\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t\t},\n\t\t\t\t\t\tClientVersionF: func() string {\n\t\t\t\t\t\t\treturn \"1.24.0\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPingF: func() (types.Ping, error) {\n\t\t\t\t\t\t\treturn types.Ping{}, nil\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCloseF: func() error {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t}\n\n\t\t\trequire.NoError(t, d.Init())\n\t\t\trequire.NoError(t, d.Start(&acc))\n\t\t\trequire.Equal(t, tt.expectPodman, d.isPodman, \"Podman detection mismatch\")\n\t\t})\n\t}\n}\n\nfunc TestPodmanStatsCache(t *testing.T) {\n\t// Create a mock Docker plugin configured as Podman\n\td := &Docker{\n\t\tisPodman:       true,\n\t\tPodmanCacheTTL: config.Duration(60 * time.Second),\n\t\tLog:            testutil.Logger{},\n\t\tstatsCache:     make(map[string]*cachedContainerStats),\n\t}\n\n\t// Create test stats\n\ttestID := \"test-container-123\"\n\tstats1 := &container.StatsResponse{\n\t\tCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tTotalUsage: 1000,\n\t\t\t},\n\t\t\tSystemUsage: 2000,\n\t\t},\n\t}\n\n\tstats2 := &container.StatsResponse{\n\t\tCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tTotalUsage: 2000,\n\t\t\t},\n\t\t\tSystemUsage: 4000,\n\t\t},\n\t\tPreCPUStats: container.CPUStats{}, // Will be filled by fixPodmanCPUStats\n\t}\n\n\t// First call should cache the stats\n\td.fixPodmanCPUStats(testID, stats1)\n\trequire.Contains(t, d.statsCache, testID)\n\trequire.Equal(t, stats1, d.statsCache[testID].stats)\n\n\t// Second call should use cached stats as PreCPUStats\n\td.fixPodmanCPUStats(testID, stats2)\n\trequire.Equal(t, stats1.CPUStats, stats2.PreCPUStats)\n\n\t// Test cache cleanup\n\td.statsCache[\"old-container\"] = &cachedContainerStats{\n\t\tstats:     stats1,\n\t\ttimestamp: time.Now().Add(-3 * time.Hour),\n\t}\n\td.cleanupStaleCache()\n\trequire.NotContains(t, d.statsCache, \"old-container\")\n\trequire.Contains(t, d.statsCache, testID)\n}\n\nfunc TestStartupErrorBehaviorError(t *testing.T) {\n\t// Test that model.Start returns error when Ping fails with default \"error\" behavior\n\t// Uses the startup-error-behavior framework (TSD-006)\n\tplugin := &Docker{\n\t\tTimeout: config.Duration(100 * time.Millisecond),\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) {\n\t\t\treturn &mockClient{\n\t\t\t\tPingF: func() (types.Ping, error) {\n\t\t\t\t\treturn types.Ping{}, errors.New(\"connection refused\")\n\t\t\t\t},\n\t\t\t\tCloseF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t\tnewEnvClient: func() (dockerClient, error) {\n\t\t\treturn nil, errors.New(\"not using env client\")\n\t\t},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:  \"docker\",\n\t\tAlias: \"error-test\",\n\t})\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail with an error because Ping fails\n\tvar acc testutil.Accumulator\n\terr := model.Start(&acc)\n\tmodel.Stop()\n\trequire.ErrorContains(t, err, \"failed to ping Docker daemon\")\n}\n\nfunc TestStartupErrorBehaviorIgnore(t *testing.T) {\n\t// Test that model.Start returns fatal error with \"ignore\" behavior when Ping fails\n\tplugin := &Docker{\n\t\tTimeout: config.Duration(100 * time.Millisecond),\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) {\n\t\t\treturn &mockClient{\n\t\t\t\tPingF: func() (types.Ping, error) {\n\t\t\t\t\treturn types.Ping{}, errors.New(\"connection refused\")\n\t\t\t\t},\n\t\t\t\tCloseF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t\tnewEnvClient: func() (dockerClient, error) {\n\t\t\treturn nil, errors.New(\"not using env client\")\n\t\t},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"docker\",\n\t\tAlias:                \"ignore-test\",\n\t\tStartupErrorBehavior: \"ignore\",\n\t})\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail and model should convert to fatal error\n\tvar acc testutil.Accumulator\n\terr := model.Start(&acc)\n\tmodel.Stop()\n\trequire.ErrorContains(t, err, \"failed to ping Docker daemon\")\n}\n\nfunc TestStartSuccess(t *testing.T) {\n\t// Test that Start succeeds when Docker is available\n\tplugin := &Docker{\n\t\tTimeout: config.Duration(5 * time.Second),\n\t\tnewClient: func(string, *tls.Config) (dockerClient, error) {\n\t\t\treturn &mockClient{\n\t\t\t\tPingF: func() (types.Ping, error) {\n\t\t\t\t\treturn types.Ping{}, nil\n\t\t\t\t},\n\t\t\t\tInfoF: func() (system.Info, error) {\n\t\t\t\t\treturn system.Info{\n\t\t\t\t\t\tName:          \"docker-desktop\",\n\t\t\t\t\t\tServerVersion: \"20.10.0\",\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tClientVersionF: func() string {\n\t\t\t\t\treturn \"1.24.0\"\n\t\t\t\t},\n\t\t\t\tCloseF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t\tnewEnvClient: func() (dockerClient, error) {\n\t\t\treturn nil, errors.New(\"not using env client\")\n\t\t},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:  \"docker\",\n\t\tAlias: \"success-test\",\n\t})\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, model.Start(&acc))\n\tmodel.Stop()\n}\n"
  },
  {
    "path": "plugins/inputs/docker/docker_testdata.go",
    "content": "package docker\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types\"\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/api/types/image\"\n\t\"github.com/docker/docker/api/types/registry\"\n\t\"github.com/docker/docker/api/types/swarm\"\n\t\"github.com/docker/docker/api/types/system\"\n\t\"github.com/docker/docker/api/types/volume\"\n)\n\nvar info = system.Info{\n\tContainers:         108,\n\tContainersRunning:  98,\n\tContainersStopped:  6,\n\tContainersPaused:   3,\n\tOomKillDisable:     false,\n\tSystemTime:         \"2016-02-24T00:55:09.15073105-05:00\",\n\tNEventsListener:    0,\n\tID:                 \"5WQQ:TFWR:FDNG:OKQ3:37Y4:FJWG:QIKK:623T:R3ME:QTKB:A7F7:OLHD\",\n\tDebug:              false,\n\tLoggingDriver:      \"json-file\",\n\tKernelVersion:      \"4.3.0-1-amd64\",\n\tIndexServerAddress: \"https://index.docker.io/v1/\",\n\tMemTotal:           3840757760,\n\tImages:             199,\n\tCPUCfsQuota:        true,\n\tName:               \"absol\",\n\tSwapLimit:          false,\n\tIPv4Forwarding:     true,\n\tExperimentalBuild:  false,\n\tCPUCfsPeriod:       true,\n\tRegistryConfig: &registry.ServiceConfig{\n\t\tIndexConfigs: map[string]*registry.IndexInfo{\n\t\t\t\"docker.io\": {\n\t\t\t\tName:     \"docker.io\",\n\t\t\t\tMirrors:  make([]string, 0),\n\t\t\t\tOfficial: true,\n\t\t\t\tSecure:   true,\n\t\t\t},\n\t\t}, InsecureRegistryCIDRs: []*registry.NetIPNet{{IP: []byte{127, 0, 0, 0}, Mask: []byte{255, 0, 0, 0}}}, Mirrors: make([]string, 0)},\n\tOperatingSystem: \"Linux Mint LMDE (containerized)\",\n\tHTTPSProxy:      \"\",\n\tLabels:          make([]string, 0),\n\tMemoryLimit:     false,\n\tDriverStatus: [][2]string{\n\t\t{\"Pool Name\", \"docker-8:1-1182287-pool\"},\n\t\t{\"Base Device Size\", \"10.74 GB\"},\n\t\t{\"Pool Blocksize\", \"65.54 kB\"},\n\t\t{\"Backing Filesystem\", \"extfs\"},\n\t\t{\"Data file\", \"/dev/loop0\"},\n\t\t{\"Metadata file\", \"/dev/loop1\"},\n\t\t{\"Data Space Used\", \"17.3 GB\"},\n\t\t{\"Data Space Total\", \"107.4 GB\"},\n\t\t{\"Data Space Available\", \"36.53 GB\"},\n\t\t{\"Metadata Space Used\", \"20.97 MB\"},\n\t\t{\"Metadata Space Total\", \"2.147 GB\"},\n\t\t{\"Metadata Space Available\", \"2.127 GB\"},\n\t\t{\"Udev Sync Supported\", \"true\"},\n\t\t{\"Deferred Removal Enabled\", \"false\"},\n\t\t{\"Data loop file\", \"/var/lib/docker/devicemapper/devicemapper/data\"},\n\t\t{\"Metadata loop file\", \"/var/lib/docker/devicemapper/devicemapper/metadata\"},\n\t\t{\"Library Version\", \"1.02.115 (2016-01-25)\"},\n\t\t{\"Thin Pool Minimum Free Space\", \"10.74GB\"},\n\t},\n\tNFd:           19,\n\tHTTPProxy:     \"\",\n\tDriver:        \"devicemapper\",\n\tNGoroutines:   39,\n\tNCPU:          4,\n\tDockerRootDir: \"/var/lib/docker\",\n\tNoProxy:       \"\",\n\tServerVersion: \"17.09.0-ce\",\n}\n\nvar containerList = []container.Summary{\n\t{\n\t\tID:      \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\",\n\t\tNames:   []string{\"/etcd\"},\n\t\tImage:   \"quay.io/coreos/etcd:v3.3.25\",\n\t\tCommand: \"/etcd -name etcd0 -advertise-client-urls http://localhost:2379 -listen-client-urls http://0.0.0.0:2379\",\n\t\tCreated: 1455941930,\n\t\tState:   \"running\",\n\t\tStatus:  \"Up 4 hours\",\n\t\tPorts: []container.Port{\n\t\t\t{\n\t\t\t\tPrivatePort: 7001,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 4001,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 2380,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 2379,\n\t\t\t\tPublicPort:  2379,\n\t\t\t\tType:        \"tcp\",\n\t\t\t\tIP:          \"0.0.0.0\",\n\t\t\t},\n\t\t},\n\t\tLabels: map[string]string{\n\t\t\t\"label1\": \"test_value_1\",\n\t\t\t\"label2\": \"test_value_2\",\n\t\t},\n\t\tSizeRw:     0,\n\t\tSizeRootFs: 0,\n\t},\n\t{\n\t\tID:      \"b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173\",\n\t\tNames:   []string{\"/etcd2\"},\n\t\tImage:   \"quay.io:4443/coreos/etcd:v3.3.25\",\n\t\tCommand: \"/etcd -name etcd2 -advertise-client-urls http://localhost:2379 -listen-client-urls http://0.0.0.0:2379\",\n\t\tCreated: 1455941933,\n\t\tState:   \"running\",\n\t\tStatus:  \"Up 4 hours\",\n\t\tPorts: []container.Port{\n\t\t\t{\n\t\t\t\tPrivatePort: 7002,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 4002,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 2381,\n\t\t\t\tPublicPort:  0,\n\t\t\t\tType:        \"tcp\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPrivatePort: 2382,\n\t\t\t\tPublicPort:  2382,\n\t\t\t\tType:        \"tcp\",\n\t\t\t\tIP:          \"0.0.0.0\",\n\t\t\t},\n\t\t},\n\t\tLabels: map[string]string{\n\t\t\t\"label1\": \"test_value_1\",\n\t\t\t\"label2\": \"test_value_2\",\n\t\t},\n\t\tSizeRw:     0,\n\t\tSizeRootFs: 0,\n\t},\n\t{\n\t\tID:    \"e8a713dd90604f5a257b97c15945e047ab60ed5b2c4397c5a6b5bf40e1bd2791\",\n\t\tNames: []string{\"/acme\"},\n\t\tState: \"running\",\n\t},\n\t{\n\t\tID:    \"9bc6faf9ba8106fae32e8faafd38a1dd6f6d262bec172398cc10bc03c0d6841a\",\n\t\tNames: []string{\"/acme-test\"},\n\t\tState: \"running\",\n\t},\n\t{\n\t\tID:    \"d4ccced494a1d5fe8ebdb0a86335a0dab069319912221e5838a132ab18a8bc84\",\n\t\tNames: []string{\"/foo\"},\n\t\tState: \"running\",\n\t},\n}\n\nvar two = uint64(2)\nvar serviceList = []swarm.Service{\n\t{\n\t\tID: \"qolkls9g5iasdiuihcyz9rnx2\",\n\t\tSpec: swarm.ServiceSpec{\n\t\t\tAnnotations: swarm.Annotations{\n\t\t\t\tName: \"test1\",\n\t\t\t},\n\t\t\tMode: swarm.ServiceMode{\n\t\t\t\tReplicated: &swarm.ReplicatedService{\n\t\t\t\t\tReplicas: &two,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tID: \"qolkls9g5iasdiuihcyz9rn3\",\n\t\tSpec: swarm.ServiceSpec{\n\t\t\tAnnotations: swarm.Annotations{\n\t\t\t\tName: \"test2\",\n\t\t\t},\n\t\t\tMode: swarm.ServiceMode{\n\t\t\t\tGlobal: &swarm.GlobalService{},\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tID: \"rfmqydhe8cluzl9hayyrhw5ga\",\n\t\tSpec: swarm.ServiceSpec{\n\t\t\tAnnotations: swarm.Annotations{\n\t\t\t\tName: \"test3\",\n\t\t\t},\n\t\t\tMode: swarm.ServiceMode{\n\t\t\t\tReplicatedJob: &swarm.ReplicatedJob{\n\t\t\t\t\tMaxConcurrent:    &two,\n\t\t\t\t\tTotalCompletions: &two,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tID: \"mp50lo68vqgkory4e26ts8f9d\",\n\t\tSpec: swarm.ServiceSpec{\n\t\t\tAnnotations: swarm.Annotations{\n\t\t\t\tName: \"test4\",\n\t\t\t},\n\t\t\tMode: swarm.ServiceMode{\n\t\t\t\tGlobalJob: &swarm.GlobalJob{},\n\t\t\t},\n\t\t},\n\t},\n}\n\nvar taskList = []swarm.Task{\n\t{\n\t\tID:        \"kwh0lv7hwwbh\",\n\t\tServiceID: \"qolkls9g5iasdiuihcyz9rnx2\",\n\t\tNodeID:    \"0cl4jturcyd1ks3fwpd010kor\",\n\t\tStatus: swarm.TaskStatus{\n\t\t\tState: \"running\",\n\t\t},\n\t\tDesiredState: \"running\",\n\t},\n\t{\n\t\tID:        \"u78m5ojbivc3\",\n\t\tServiceID: \"qolkls9g5iasdiuihcyz9rnx2\",\n\t\tNodeID:    \"0cl4jturcyd1ks3fwpd010kor\",\n\t\tStatus: swarm.TaskStatus{\n\t\t\tState: \"running\",\n\t\t},\n\t\tDesiredState: \"running\",\n\t},\n\t{\n\t\tID:        \"1n1uilkhr98l\",\n\t\tServiceID: \"qolkls9g5iasdiuihcyz9rn3\",\n\t\tNodeID:    \"0cl4jturcyd1ks3fwpd010kor\",\n\t\tStatus: swarm.TaskStatus{\n\t\t\tState: \"running\",\n\t\t},\n\t\tDesiredState: \"running\",\n\t},\n}\n\nvar nodeList = []swarm.Node{\n\t{\n\t\tID: \"0cl4jturcyd1ks3fwpd010kor\",\n\t\tStatus: swarm.NodeStatus{\n\t\t\tState: \"ready\",\n\t\t},\n\t},\n\t{\n\t\tID: \"0cl4jturcyd1ks3fwpd010kor\",\n\t\tStatus: swarm.NodeStatus{\n\t\t\tState: \"ready\",\n\t\t},\n\t},\n}\n\nfunc containerStats(s string) container.StatsResponseReader {\n\tvar stat container.StatsResponseReader\n\tvar name string\n\tswitch s {\n\tcase \"e2173b9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296b7dfb\":\n\t\tname = \"etcd\"\n\tcase \"b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173\":\n\t\tname = \"etcd2\"\n\tcase \"e8a713dd90604f5a257b97c15945e047ab60ed5b2c4397c5a6b5bf40e1bd2791\":\n\t\tname = \"/acme\"\n\tcase \"9bc6faf9ba8106fae32e8faafd38a1dd6f6d262bec172398cc10bc03c0d6841a\":\n\t\tname = \"/acme-test\"\n\tcase \"d4ccced494a1d5fe8ebdb0a86335a0dab069319912221e5838a132ab18a8bc84\":\n\t\tname = \"/foo\"\n\t}\n\n\tjsonStat := fmt.Sprintf(`\n{\n    \"name\": \"%s\",\n    \"blkio_stats\": {\n        \"io_service_bytes_recursive\": [\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Read\",\n                \"value\": 753664\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Write\"\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Sync\"\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Async\",\n                \"value\": 753664\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Total\",\n                \"value\": 753664\n            }\n        ],\n        \"io_serviced_recursive\": [\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Read\",\n                \"value\": 26\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Write\"\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Sync\"\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Async\",\n                \"value\": 26\n            },\n            {\n                \"major\": 252,\n                \"minor\": 1,\n                \"op\": \"Total\",\n                \"value\": 26\n            }\n        ]\n    },\n    \"cpu_stats\": {\n        \"cpu_usage\": {\n            \"percpu_usage\": [\n                17871,\n                4959158,\n                1646137,\n                1231652,\n                11829401,\n                244656,\n                369972,\n                0\n            ],\n            \"total_usage\": 20298847,\n            \"usage_in_usermode\": 10000000\n        },\n        \"system_cpu_usage\": 24052607520000000,\n        \"throttling_data\": {}\n    },\n    \"memory_stats\": {\n        \"limit\": 18935443456,\n        \"stats\": {}\n    },\n    \"precpu_stats\": {\n        \"cpu_usage\": {\n            \"percpu_usage\": [\n                17871,\n                4959158,\n                1646137,\n                1231652,\n                11829401,\n                244656,\n                369972,\n                0\n            ],\n            \"total_usage\": 20298847,\n            \"usage_in_usermode\": 10000000\n        },\n        \"system_cpu_usage\": 24052599550000000,\n        \"throttling_data\": {}\n    },\n    \"read\": \"2016-02-24T11:42:27.472459608-05:00\"\n}`, name)\n\tstat.Body = io.NopCloser(strings.NewReader(jsonStat))\n\treturn stat\n}\n\nfunc testStats() *container.StatsResponse {\n\tstats := &container.StatsResponse{}\n\tstats.Read = time.Now()\n\tstats.Networks = make(map[string]container.NetworkStats)\n\tstats.CPUStats.OnlineCPUs = 2\n\tstats.CPUStats.CPUUsage.PercpuUsage = []uint64{1, 1002, 0, 0}\n\tstats.CPUStats.CPUUsage.UsageInUsermode = 100\n\tstats.CPUStats.CPUUsage.TotalUsage = 500\n\tstats.CPUStats.CPUUsage.UsageInKernelmode = 200\n\tstats.CPUStats.SystemUsage = 100\n\tstats.CPUStats.ThrottlingData.Periods = 1\n\n\tstats.PreCPUStats.CPUUsage.TotalUsage = 400\n\tstats.PreCPUStats.SystemUsage = 50\n\n\tstats.MemoryStats.Stats = make(map[string]uint64)\n\tstats.MemoryStats.Stats[\"active_anon\"] = 0\n\tstats.MemoryStats.Stats[\"active_file\"] = 1\n\tstats.MemoryStats.Stats[\"cache\"] = 0\n\tstats.MemoryStats.Stats[\"hierarchical_memory_limit\"] = 0\n\tstats.MemoryStats.Stats[\"inactive_anon\"] = 0\n\tstats.MemoryStats.Stats[\"inactive_file\"] = 3\n\tstats.MemoryStats.Stats[\"mapped_file\"] = 0\n\tstats.MemoryStats.Stats[\"pgfault\"] = 2\n\tstats.MemoryStats.Stats[\"pgmajfault\"] = 0\n\tstats.MemoryStats.Stats[\"pgpgin\"] = 0\n\tstats.MemoryStats.Stats[\"pgpgout\"] = 0\n\tstats.MemoryStats.Stats[\"rss\"] = 0\n\tstats.MemoryStats.Stats[\"rss_huge\"] = 0\n\tstats.MemoryStats.Stats[\"total_active_anon\"] = 0\n\tstats.MemoryStats.Stats[\"total_active_file\"] = 0\n\tstats.MemoryStats.Stats[\"total_cache\"] = 0\n\tstats.MemoryStats.Stats[\"total_inactive_anon\"] = 0\n\tstats.MemoryStats.Stats[\"total_inactive_file\"] = 0\n\tstats.MemoryStats.Stats[\"total_mapped_file\"] = 0\n\tstats.MemoryStats.Stats[\"total_pgfault\"] = 0\n\tstats.MemoryStats.Stats[\"total_pgmajfault\"] = 0\n\tstats.MemoryStats.Stats[\"total_pgpgin\"] = 4\n\tstats.MemoryStats.Stats[\"total_pgpgout\"] = 0\n\tstats.MemoryStats.Stats[\"total_rss\"] = 44\n\tstats.MemoryStats.Stats[\"total_rss_huge\"] = 444\n\tstats.MemoryStats.Stats[\"total_unevictable\"] = 0\n\tstats.MemoryStats.Stats[\"total_writeback\"] = 55\n\tstats.MemoryStats.Stats[\"unevictable\"] = 0\n\tstats.MemoryStats.Stats[\"writeback\"] = 0\n\n\tstats.MemoryStats.MaxUsage = 1001\n\tstats.MemoryStats.Usage = 1111\n\tstats.MemoryStats.Failcnt = 1\n\tstats.MemoryStats.Limit = 2000\n\n\tstats.Networks[\"eth0\"] = container.NetworkStats{\n\t\tRxDropped: 1,\n\t\tRxBytes:   2,\n\t\tRxErrors:  3,\n\t\tTxPackets: 4,\n\t\tTxDropped: 1,\n\t\tRxPackets: 2,\n\t\tTxErrors:  3,\n\t\tTxBytes:   4,\n\t}\n\n\tstats.Networks[\"eth1\"] = container.NetworkStats{\n\t\tRxDropped: 5,\n\t\tRxBytes:   6,\n\t\tRxErrors:  7,\n\t\tTxPackets: 8,\n\t\tTxDropped: 5,\n\t\tRxPackets: 6,\n\t\tTxErrors:  7,\n\t\tTxBytes:   8,\n\t}\n\n\tsbr := container.BlkioStatEntry{\n\t\tMajor: 6,\n\t\tMinor: 0,\n\t\tOp:    \"read\",\n\t\tValue: 100,\n\t}\n\tsr := container.BlkioStatEntry{\n\t\tMajor: 6,\n\t\tMinor: 0,\n\t\tOp:    \"write\",\n\t\tValue: 101,\n\t}\n\tsr2 := container.BlkioStatEntry{\n\t\tMajor: 6,\n\t\tMinor: 1,\n\t\tOp:    \"write\",\n\t\tValue: 201,\n\t}\n\n\tstats.BlkioStats.IoServiceBytesRecursive = append(\n\t\tstats.BlkioStats.IoServiceBytesRecursive, sbr)\n\tstats.BlkioStats.IoServicedRecursive = append(\n\t\tstats.BlkioStats.IoServicedRecursive, sr)\n\tstats.BlkioStats.IoServicedRecursive = append(\n\t\tstats.BlkioStats.IoServicedRecursive, sr2)\n\n\treturn stats\n}\n\nfunc containerStatsWindows() container.StatsResponseReader {\n\tvar stat container.StatsResponseReader\n\tjsonStat := `\n{\n\t\"read\":\"2017-01-11T08:32:46.2413794Z\",\n\t\"preread\":\"0001-01-01T00:00:00Z\",\n\t\"num_procs\":64,\n\t\"cpu_stats\":{\n\t\t\"cpu_usage\":{\n\t\t\t\"total_usage\":536718750,\n\t\t\t\"usage_in_kernelmode\":390468750,\n\t\t\t\"usage_in_usermode\":390468750\n\t\t},\n\t\t\"throttling_data\":{\n\t\t\t\"periods\":0,\n\t\t\t\"throttled_periods\":0,\n\t\t\t\"throttled_time\":0\n\t\t}\n\t},\n\t\"precpu_stats\":{\n\t\t\"cpu_usage\":{\n\t\t\t\"total_usage\":0,\n\t\t\t\"usage_in_kernelmode\":0,\n\t\t\t\"usage_in_usermode\":0\n\t\t},\n\t\t\"throttling_data\":{\n\t\t\t\"periods\":0,\n\t\t\t\"throttled_periods\":0,\n\t\t\t\"throttled_time\":0\n\t\t}\n\t},\n\t\"memory_stats\":{\n\t\t\"commitbytes\":77160448,\n\t\t\"commitpeakbytes\":105000960,\n\t\t\"privateworkingset\":59961344\n\t},\n\t\"name\":\"/gt_test_iis\",\n}`\n\tstat.Body = io.NopCloser(strings.NewReader(jsonStat))\n\treturn stat\n}\n\nfunc containerInspect() container.InspectResponse {\n\treturn container.InspectResponse{\n\t\tConfig: &container.Config{\n\t\t\tEnv: []string{\n\t\t\t\t\"ENVVAR1=loremipsum\",\n\t\t\t\t\"ENVVAR1FOO=loremipsum\",\n\t\t\t\t\"ENVVAR2=dolorsitamet\",\n\t\t\t\t\"ENVVAR3==ubuntu:10.04\",\n\t\t\t\t\"ENVVAR4\",\n\t\t\t\t\"ENVVAR5=\",\n\t\t\t\t\"ENVVAR6= \",\n\t\t\t\t\"ENVVAR7=ENVVAR8=ENVVAR9\",\n\t\t\t\t\"PATH=/bin:/sbin\",\n\t\t\t},\n\t\t},\n\t\tContainerJSONBase: &container.ContainerJSONBase{\n\t\t\tState: &container.State{\n\t\t\t\tHealth: &container.Health{\n\t\t\t\t\tFailingStreak: 1,\n\t\t\t\t\tStatus:        \"Unhealthy\",\n\t\t\t\t},\n\t\t\t\tStatus:     \"running\",\n\t\t\t\tOOMKilled:  false,\n\t\t\t\tPid:        1234,\n\t\t\t\tExitCode:   0,\n\t\t\t\tStartedAt:  \"2018-06-14T05:48:53.266176036Z\",\n\t\t\t\tFinishedAt: \"0001-01-01T00:00:00Z\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nvar diskUsage = types.DiskUsage{\n\tLayersSize: 1e10,\n\tContainers: []*container.Summary{\n\t\t{Names: []string{\"/some_container\"}, Image: \"some_image:1.0.0-alpine\", SizeRw: 0, SizeRootFs: 123456789},\n\t},\n\tImages: []*image.Summary{\n\t\t{ID: \"sha256:some_imageid\", RepoTags: []string{\"some_image_tag:1.0.0-alpine\"}, Size: 123456789, SharedSize: 0},\n\t\t{ID: \"sha256:7f4a1cc74046ce48cd918693cd6bf4b2683f4ce0d7be3f7148a21df9f06f5b5f\", RepoTags: []string{\"telegraf:latest\"}, Size: 425484494, SharedSize: 0},\n\t},\n\tVolumes: []*volume.Volume{{Name: \"some_volume\", UsageData: &volume.UsageData{Size: 123456789}}},\n}\n\nvar version = \"1.43\"\n"
  },
  {
    "path": "plugins/inputs/docker/errors.go",
    "content": "package docker\n\nimport \"errors\"\n\nvar (\n\terrInfoTimeout    = errors.New(\"timeout retrieving docker engine info\")\n\terrStatsTimeout   = errors.New(\"timeout retrieving container stats\")\n\terrInspectTimeout = errors.New(\"timeout retrieving container environment\")\n\terrListTimeout    = errors.New(\"timeout retrieving container list\")\n\terrServiceTimeout = errors.New(\"timeout retrieving swarm service list\")\n)\n"
  },
  {
    "path": "plugins/inputs/docker/sample.conf",
    "content": "# Read metrics about docker containers\n[[inputs.docker]]\n  ## Docker Endpoint\n  ##   To use TCP, set endpoint = \"tcp://[ip]:[port]\"\n  ##   To use environment variables (ie, docker-machine), set endpoint = \"ENV\"\n  endpoint = \"unix:///var/run/docker.sock\"\n\n  ## Set to true to collect Swarm metrics(desired_replicas, running_replicas)\n  ## Note: configure this in one of the manager nodes in a Swarm cluster.\n  ## configuring in multiple Swarm managers results in duplication of metrics.\n  gather_services = false\n\n  ## Set the source tag for the metrics to the container ID hostname, eg first 12 chars\n  source_tag = false\n\n  ## Containers to include and exclude. Collect all if empty. Globs accepted.\n  container_name_include = []\n  container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"running\" state will be captured.\n  ## example: container_state_include = [\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"]\n  ## example: container_state_exclude = [\"created\", \"restarting\", \"running\", \"removing\", \"paused\", \"exited\", \"dead\"]\n  # container_state_include = []\n  # container_state_exclude = []\n\n  ## Objects to include for disk usage query\n  ## Allowed values are \"container\", \"image\", \"volume\"\n  ## When empty disk usage is excluded\n  storage_objects = []\n\n  ## Timeout for docker list, info, and stats commands\n  timeout = \"5s\"\n\n  ## Podman compatibility settings (auto-enabled when Podman detected)\n  ## Cache TTL for accurate CPU percentage calculation (default: 60s)\n  ## Set higher than your collection interval for accurate measurements\n  ## Set to 0 to keep cache entries forever (not recommended for dynamic environments)\n  # podman_cache_ttl = \"60s\"\n\n  ## Specifies for which classes a per-device metric should be issued\n  ## Possible values are 'cpu' (cpu0, cpu1, ...), 'blkio' (8:0, 8:1, ...) and 'network' (eth0, eth1, ...)\n  # perdevice_include = [\"cpu\"]\n\n  ## Specifies for which classes a total metric should be issued. Total is an aggregated of the 'perdevice_include' values.\n  ## Possible values are 'cpu', 'blkio' and 'network'\n  ## Total 'cpu' is reported directly by Docker daemon, and 'network' and 'blkio' totals are aggregated by this plugin.\n  # total_include = [\"cpu\", \"blkio\", \"network\"]\n\n  ## docker labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  docker_label_include = []\n  docker_label_exclude = []\n\n  ## Which environment variables should we use as a tag\n  tag_env = [\"JAVA_HOME\", \"HEAP_SIZE\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/docker_log/README.md",
    "content": "# Docker Log Input Plugin\n\nThis plugin uses the [Docker Engine API][api] to gather logs from running\nDocker containers.\n\n> [!NOTE]\n> This plugin works only for containers with the `local` or `json-file` or\n> `journald` logging driver. Make sure Telegraf has sufficient permissions to\n> access the configured endpoint.\n\n⭐ Telegraf v1.12.0\n🏷️ containers, logging\n💻 all\n\n[api]: https://docs.docker.com/engine/api\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read logging output from the Docker engine\n[[inputs.docker_log]]\n  ## Docker Endpoint\n  ##   To use TCP, set endpoint = \"tcp://[ip]:[port]\"\n  ##   To use environment variables (ie, docker-machine), set endpoint = \"ENV\"\n  # endpoint = \"unix:///var/run/docker.sock\"\n\n  ## When true, container logs are read from the beginning; otherwise reading\n  ## begins at the end of the log. If state-persistence is enabled for Telegraf,\n  ## the reading continues at the last previously processed timestamp.\n  # from_beginning = false\n\n  ## Timeout for Docker API calls.\n  # timeout = \"5s\"\n\n  ## Containers to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all containers\n  # container_name_include = []\n  # container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"running\" state will be captured.\n  # container_state_include = []\n  # container_state_exclude = []\n\n  ## docker labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  # docker_label_include = []\n  # docker_label_exclude = []\n\n  ## Set the source tag for the metrics to the container ID hostname, eg first 12 chars\n  source_tag = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### Environment Configuration\n\nWhen using the `\"ENV\"` endpoint, the connection is configured using the\n[CLI Docker environment variables][env]\n\n[env]: https://godoc.org/github.com/moby/moby/client#NewEnvClient\n\n## source tag\n\nSelecting the containers can be tricky if you have many containers with the same\nname.  To alleviate this issue you can set the below value to `true`\n\n```toml\nsource_tag = true\n```\n\nThis will cause all data points to have the `source` tag be set to the first 12\ncharacters of the container id. The first 12 characters is the common hostname\nfor containers that have no explicit hostname set, as defined by docker.\n\n## Metrics\n\n- docker_log\n  - tags:\n    - container_image\n    - container_version\n    - container_name\n    - stream (stdout, stderr, or tty)\n    - source\n  - fields:\n    - container_id\n    - message\n\n## Example Output\n\n```text\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:\\\"371ee5d3e587\\\", Flush Interval:10s\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Tags enabled: host=371ee5d3e587\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Loaded outputs: file\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Loaded processors:\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Loaded aggregators:\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Loaded inputs: net\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Using config file: /etc/telegraf/telegraf.conf\" 1560913872000000000\ndocker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id=\"371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023\",message=\"2019-06-19T03:11:11Z I! Starting Telegraf 1.10.4\" 1560913872000000000\n```\n"
  },
  {
    "path": "plugins/inputs/docker_log/client.go",
    "content": "package docker_log\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\tdocker \"github.com/docker/docker/client\"\n)\n\ntype dockerClient interface {\n\t// ContainerList lists the containers in the Docker environment.\n\tContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error)\n\t// ContainerLogs retrieves the logs of a specific container.\n\tContainerLogs(ctx context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error)\n\t// ContainerInspect inspects a specific container and retrieves its details.\n\tContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error)\n}\n\nfunc newEnvClient() (dockerClient, error) {\n\tclient, err := docker.NewClientWithOpts(docker.FromEnv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &socketClient{client}, nil\n}\n\nfunc newClient(host string, tlsConfig *tls.Config) (dockerClient, error) {\n\ttransport := &http.Transport{\n\t\tTLSClientConfig: tlsConfig,\n\t}\n\thttpClient := &http.Client{Transport: transport}\n\tclient, err := docker.NewClientWithOpts(\n\t\tdocker.WithHTTPHeaders(map[string]string{\"User-Agent\": \"engine-api-cli-1.0\"}),\n\t\tdocker.WithHTTPClient(httpClient),\n\t\tdocker.WithAPIVersionNegotiation(),\n\t\tdocker.WithHost(host))\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &socketClient{client}, nil\n}\n\ntype socketClient struct {\n\tclient *docker.Client\n}\n\n// ContainerList lists the containers in the Docker environment.\nfunc (c *socketClient) ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error) {\n\treturn c.client.ContainerList(ctx, options)\n}\n\n// ContainerLogs retrieves the logs of a specific container.\nfunc (c *socketClient) ContainerLogs(ctx context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error) {\n\treturn c.client.ContainerLogs(ctx, containerID, options)\n}\n\n// ContainerInspect inspects a specific container and retrieves its details.\nfunc (c *socketClient) ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error) {\n\treturn c.client.ContainerInspect(ctx, containerID)\n}\n"
  },
  {
    "path": "plugins/inputs/docker_log/docker_log.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage docker_log\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/pkg/stdcopy\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/docker\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\t// ensure *DockerLogs implements telegraf.ServiceInput\n\t_ telegraf.ServiceInput = (*DockerLogs)(nil)\n)\n\nconst (\n\tdefaultEndpoint = \"unix:///var/run/docker.sock\"\n)\n\ntype DockerLogs struct {\n\tEndpoint              string          `toml:\"endpoint\"`\n\tFromBeginning         bool            `toml:\"from_beginning\"`\n\tTimeout               config.Duration `toml:\"timeout\"`\n\tLabelInclude          []string        `toml:\"docker_label_include\"`\n\tLabelExclude          []string        `toml:\"docker_label_exclude\"`\n\tContainerInclude      []string        `toml:\"container_name_include\"`\n\tContainerExclude      []string        `toml:\"container_name_exclude\"`\n\tContainerStateInclude []string        `toml:\"container_state_include\"`\n\tContainerStateExclude []string        `toml:\"container_state_exclude\"`\n\tIncludeSourceTag      bool            `toml:\"source_tag\"`\n\n\tcommon_tls.ClientConfig\n\n\tnewEnvClient func() (dockerClient, error)\n\tnewClient    func(string, *tls.Config) (dockerClient, error)\n\n\tclient          dockerClient\n\tlabelFilter     filter.Filter\n\tcontainerFilter filter.Filter\n\tstateFilter     filter.Filter\n\twg              sync.WaitGroup\n\tmu              sync.Mutex\n\tcontainerList   map[string]context.CancelFunc\n\n\t// State of the plugin mapping container-ID to the timestamp of the\n\t// last record processed\n\tlastRecord    map[string]time.Time\n\tlastRecordMtx sync.Mutex\n}\n\nfunc (*DockerLogs) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *DockerLogs) Init() error {\n\tvar err error\n\tif d.Endpoint == \"ENV\" {\n\t\td.client, err = d.newEnvClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\ttlsConfig, err := d.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\td.client, err = d.newClient(d.Endpoint, tlsConfig)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Create filters\n\terr = d.createLabelFilters()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = d.createContainerFilters()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = d.createContainerStateFilters()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.lastRecord = make(map[string]time.Time)\n\n\treturn nil\n}\n\n// Start is a noop which is required for a *DockerLogs to implement the telegraf.ServiceInput interface\nfunc (*DockerLogs) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (d *DockerLogs) GetState() interface{} {\n\td.lastRecordMtx.Lock()\n\trecordOffsets := make(map[string]time.Time, len(d.lastRecord))\n\tfor k, v := range d.lastRecord {\n\t\trecordOffsets[k] = v\n\t}\n\td.lastRecordMtx.Unlock()\n\n\treturn recordOffsets\n}\n\nfunc (d *DockerLogs) SetState(state interface{}) error {\n\trecordOffsets, ok := state.(map[string]time.Time)\n\tif !ok {\n\t\treturn fmt.Errorf(\"state has wrong type %T\", state)\n\t}\n\td.lastRecordMtx.Lock()\n\tfor k, v := range recordOffsets {\n\t\td.lastRecord[k] = v\n\t}\n\td.lastRecordMtx.Unlock()\n\n\treturn nil\n}\n\nfunc (d *DockerLogs) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\tacc.SetPrecision(time.Nanosecond)\n\n\tctx, cancel := context.WithTimeout(ctx, time.Duration(d.Timeout))\n\tdefer cancel()\n\tcontainers, err := d.client.ContainerList(ctx, container.ListOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, cntnr := range containers {\n\t\tif d.containerInContainerList(cntnr.ID) {\n\t\t\tcontinue\n\t\t}\n\n\t\tcontainerName := parseContainerName(cntnr.Names)\n\n\t\tif containerName == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !d.containerFilter.Match(containerName) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !d.stateFilter.Match(cntnr.State) {\n\t\t\tcontinue\n\t\t}\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\td.addToContainerList(cntnr.ID, cancel)\n\n\t\t// Start a new goroutine for every new container that has logs to collect\n\t\td.wg.Add(1)\n\t\tgo func(container container.Summary) {\n\t\t\tdefer d.wg.Done()\n\t\t\tdefer d.removeFromContainerList(container.ID)\n\n\t\t\terr = d.tailContainerLogs(ctx, acc, container, containerName)\n\t\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(cntnr)\n\t}\n\treturn nil\n}\n\nfunc (d *DockerLogs) Stop() {\n\td.cancelTails()\n\td.wg.Wait()\n}\n\nfunc (d *DockerLogs) addToContainerList(containerID string, cancel context.CancelFunc) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\td.containerList[containerID] = cancel\n}\n\nfunc (d *DockerLogs) removeFromContainerList(containerID string) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tdelete(d.containerList, containerID)\n}\n\nfunc (d *DockerLogs) containerInContainerList(containerID string) bool {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\t_, ok := d.containerList[containerID]\n\treturn ok\n}\n\nfunc (d *DockerLogs) cancelTails() {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tfor _, cancel := range d.containerList {\n\t\tcancel()\n\t}\n}\n\nfunc (d *DockerLogs) hasTTY(ctx context.Context, cntnr container.Summary) (bool, error) {\n\tctx, cancel := context.WithTimeout(ctx, time.Duration(d.Timeout))\n\tdefer cancel()\n\tc, err := d.client.ContainerInspect(ctx, cntnr.ID)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn c.Config.Tty, nil\n}\n\nfunc (d *DockerLogs) tailContainerLogs(\n\tctx context.Context,\n\tacc telegraf.Accumulator,\n\tcntnr container.Summary,\n\tcontainerName string,\n) error {\n\timageName, imageVersion := docker.ParseImage(cntnr.Image)\n\ttags := map[string]string{\n\t\t\"container_name\":    containerName,\n\t\t\"container_image\":   imageName,\n\t\t\"container_version\": imageVersion,\n\t}\n\n\tif d.IncludeSourceTag {\n\t\ttags[\"source\"] = hostnameFromID(cntnr.ID)\n\t}\n\n\t// Add matching container labels as tags\n\tfor k, label := range cntnr.Labels {\n\t\tif d.labelFilter.Match(k) {\n\t\t\ttags[k] = label\n\t\t}\n\t}\n\n\thasTTY, err := d.hasTTY(ctx, cntnr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsince := time.Time{}.Format(time.RFC3339Nano)\n\tif !d.FromBeginning {\n\t\td.lastRecordMtx.Lock()\n\t\tif ts, ok := d.lastRecord[cntnr.ID]; ok {\n\t\t\tsince = ts.Format(time.RFC3339Nano)\n\t\t}\n\t\td.lastRecordMtx.Unlock()\n\t}\n\n\tlogOptions := container.LogsOptions{\n\t\tShowStdout: true,\n\t\tShowStderr: true,\n\t\tTimestamps: true,\n\t\tDetails:    false,\n\t\tFollow:     true,\n\t\tSince:      since,\n\t}\n\n\tlogReader, err := d.client.ContainerLogs(ctx, cntnr.ID, logOptions)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// If the container is using a TTY, there is only a single stream\n\t// (stdout), and data is copied directly from the container output stream,\n\t// no extra multiplexing or headers.\n\t//\n\t// If the container is *not* using a TTY, streams for stdout and stderr are\n\t// multiplexed.\n\tvar last time.Time\n\tif hasTTY {\n\t\tlast, err = tailStream(acc, tags, cntnr.ID, logReader, \"tty\")\n\t} else {\n\t\tlast, err = tailMultiplexed(acc, tags, cntnr.ID, logReader)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif ts, ok := d.lastRecord[cntnr.ID]; !ok || ts.Before(last) {\n\t\td.lastRecordMtx.Lock()\n\t\td.lastRecord[cntnr.ID] = last\n\t\td.lastRecordMtx.Unlock()\n\t}\n\n\treturn nil\n}\n\n// Parse container name\nfunc parseContainerName(containerNames []string) string {\n\tfor _, name := range containerNames {\n\t\ttrimmedName := strings.TrimPrefix(name, \"/\")\n\t\tif !strings.Contains(trimmedName, \"/\") {\n\t\t\treturn trimmedName\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc parseLine(line []byte) (time.Time, string, error) {\n\tparts := bytes.SplitN(line, []byte(\" \"), 2)\n\n\tif len(parts) == 1 {\n\t\tparts = append(parts, []byte(\"\"))\n\t}\n\n\ttsString := string(parts[0])\n\n\t// Keep any leading space, but remove whitespace from end of line.\n\t// This preserves space in, for example, stacktraces, while removing\n\t// annoying end of line characters and is similar to how other logging\n\t// plugins such as syslog behave.\n\tmessage := bytes.TrimRightFunc(parts[1], unicode.IsSpace)\n\n\tts, err := time.Parse(time.RFC3339Nano, tsString)\n\tif err != nil {\n\t\treturn time.Time{}, \"\", fmt.Errorf(\"error parsing timestamp %q: %w\", tsString, err)\n\t}\n\n\treturn ts, string(message), nil\n}\n\nfunc tailStream(\n\tacc telegraf.Accumulator,\n\tbaseTags map[string]string,\n\tcontainerID string,\n\treader io.ReadCloser,\n\tstream string,\n) (time.Time, error) {\n\tdefer reader.Close()\n\n\ttags := make(map[string]string, len(baseTags)+1)\n\tfor k, v := range baseTags {\n\t\ttags[k] = v\n\t}\n\ttags[\"stream\"] = stream\n\n\tr := bufio.NewReaderSize(reader, 64*1024)\n\n\tvar lastTS time.Time\n\tfor {\n\t\tline, err := r.ReadBytes('\\n')\n\n\t\tif len(line) != 0 {\n\t\t\tts, message, err := parseLine(line)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t} else {\n\t\t\t\tacc.AddFields(\"docker_log\", map[string]interface{}{\n\t\t\t\t\t\"container_id\": containerID,\n\t\t\t\t\t\"message\":      message,\n\t\t\t\t}, tags, ts)\n\t\t\t}\n\n\t\t\t// Store the last processed timestamp\n\t\t\tif ts.After(lastTS) {\n\t\t\t\tlastTS = ts\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn lastTS, nil\n\t\t\t}\n\t\t\treturn time.Time{}, err\n\t\t}\n\t}\n}\n\nfunc tailMultiplexed(\n\tacc telegraf.Accumulator,\n\ttags map[string]string,\n\tcontainerID string,\n\tsrc io.ReadCloser,\n) (time.Time, error) {\n\toutReader, outWriter := io.Pipe()\n\terrReader, errWriter := io.Pipe()\n\n\tvar tsStdout, tsStderr time.Time\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tvar err error\n\t\ttsStdout, err = tailStream(acc, tags, containerID, outReader, \"stdout\")\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}()\n\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tvar err error\n\t\ttsStderr, err = tailStream(acc, tags, containerID, errReader, \"stderr\")\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}()\n\n\t_, err := stdcopy.StdCopy(outWriter, errWriter, src)\n\n\t// Ignore the returned errors as we cannot do anything if the closing fails\n\t_ = outWriter.Close()\n\t_ = errWriter.Close()\n\t_ = src.Close()\n\twg.Wait()\n\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\tif tsStdout.After(tsStderr) {\n\t\treturn tsStdout, nil\n\t}\n\treturn tsStderr, nil\n}\n\n// Following few functions have been inherited from telegraf docker input plugin\nfunc (d *DockerLogs) createContainerFilters() error {\n\tcontainerFilter, err := filter.NewIncludeExcludeFilter(d.ContainerInclude, d.ContainerExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.containerFilter = containerFilter\n\treturn nil\n}\n\nfunc (d *DockerLogs) createLabelFilters() error {\n\tlabelFilter, err := filter.NewIncludeExcludeFilter(d.LabelInclude, d.LabelExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.labelFilter = labelFilter\n\treturn nil\n}\n\nfunc (d *DockerLogs) createContainerStateFilters() error {\n\tif len(d.ContainerStateInclude) == 0 && len(d.ContainerStateExclude) == 0 {\n\t\td.ContainerStateInclude = []string{\"running\"}\n\t}\n\tstateFilter, err := filter.NewIncludeExcludeFilter(d.ContainerStateInclude, d.ContainerStateExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.stateFilter = stateFilter\n\treturn nil\n}\n\nfunc hostnameFromID(id string) string {\n\tif len(id) > 12 {\n\t\treturn id[0:12]\n\t}\n\treturn id\n}\n\nfunc init() {\n\tinputs.Add(\"docker_log\", func() telegraf.Input {\n\t\treturn &DockerLogs{\n\t\t\tTimeout:       config.Duration(time.Second * 5),\n\t\t\tEndpoint:      defaultEndpoint,\n\t\t\tnewEnvClient:  newEnvClient,\n\t\t\tnewClient:     newClient,\n\t\t\tcontainerList: make(map[string]context.CancelFunc),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/docker_log/docker_log_test.go",
    "content": "package docker_log\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/docker/docker/pkg/stdcopy\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockClient struct {\n\tContainerListF    func() ([]container.Summary, error)\n\tContainerInspectF func() (container.InspectResponse, error)\n\tContainerLogsF    func() (io.ReadCloser, error)\n}\n\nfunc (c *mockClient) ContainerList(context.Context, container.ListOptions) ([]container.Summary, error) {\n\treturn c.ContainerListF()\n}\n\nfunc (c *mockClient) ContainerInspect(context.Context, string) (container.InspectResponse, error) {\n\treturn c.ContainerInspectF()\n}\n\nfunc (c *mockClient) ContainerLogs(context.Context, string, container.LogsOptions) (io.ReadCloser, error) {\n\treturn c.ContainerLogsF()\n}\n\ntype response struct {\n\tio.Reader\n}\n\nfunc (*response) Close() error {\n\treturn nil\n}\n\nfunc mustParse(layout, value string) time.Time {\n\ttm, err := time.Parse(layout, value)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn tm\n}\n\nfunc Test(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tclient   *mockClient\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"no containers\",\n\t\t\tclient: &mockClient{\n\t\t\t\tContainerListF: func() ([]container.Summary, error) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"one container tty\",\n\t\t\tclient: &mockClient{\n\t\t\t\tContainerListF: func() ([]container.Summary, error) {\n\t\t\t\t\treturn []container.Summary{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tID:    \"deadbeef\",\n\t\t\t\t\t\t\tNames: []string{\"/telegraf\"},\n\t\t\t\t\t\t\tImage: \"influxdata/telegraf:1.11.0\",\n\t\t\t\t\t\t\tState: \"running\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tContainerInspectF: func() (container.InspectResponse, error) {\n\t\t\t\t\treturn container.InspectResponse{\n\t\t\t\t\t\tConfig: &container.Config{\n\t\t\t\t\t\t\tTty: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tContainerLogsF: func() (io.ReadCloser, error) {\n\t\t\t\t\treturn &response{Reader: bytes.NewBufferString(\"2020-04-28T18:43:16.432691200Z hello\\n\")}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_log\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"telegraf\",\n\t\t\t\t\t\t\"container_image\":   \"influxdata/telegraf\",\n\t\t\t\t\t\t\"container_version\": \"1.11.0\",\n\t\t\t\t\t\t\"stream\":            \"tty\",\n\t\t\t\t\t\t\"source\":            \"deadbeef\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"container_id\": \"deadbeef\",\n\t\t\t\t\t\t\"message\":      \"hello\",\n\t\t\t\t\t},\n\t\t\t\t\tmustParse(time.RFC3339Nano, \"2020-04-28T18:43:16.432691200Z\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"one container multiplex\",\n\t\t\tclient: &mockClient{\n\t\t\t\tContainerListF: func() ([]container.Summary, error) {\n\t\t\t\t\treturn []container.Summary{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tID:    \"deadbeef\",\n\t\t\t\t\t\t\tNames: []string{\"/telegraf\"},\n\t\t\t\t\t\t\tImage: \"influxdata/telegraf:1.11.0\",\n\t\t\t\t\t\t\tState: \"running\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tContainerInspectF: func() (container.InspectResponse, error) {\n\t\t\t\t\treturn container.InspectResponse{\n\t\t\t\t\t\tConfig: &container.Config{\n\t\t\t\t\t\t\tTty: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t\tContainerLogsF: func() (io.ReadCloser, error) {\n\t\t\t\t\tvar buf bytes.Buffer\n\t\t\t\t\tw := stdcopy.NewStdWriter(&buf, stdcopy.Stdout)\n\t\t\t\t\t_, err := w.Write([]byte(\"2020-04-28T18:42:16.432691200Z hello from stdout\"))\n\t\t\t\t\treturn &response{Reader: &buf}, err\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"docker_log\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"container_name\":    \"telegraf\",\n\t\t\t\t\t\t\"container_image\":   \"influxdata/telegraf\",\n\t\t\t\t\t\t\"container_version\": \"1.11.0\",\n\t\t\t\t\t\t\"stream\":            \"stdout\",\n\t\t\t\t\t\t\"source\":            \"deadbeef\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"container_id\": \"deadbeef\",\n\t\t\t\t\t\t\"message\":      \"hello from stdout\",\n\t\t\t\t\t},\n\t\t\t\t\tmustParse(time.RFC3339Nano, \"2020-04-28T18:42:16.432691200Z\"),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := &DockerLogs{\n\t\t\t\tTimeout:          config.Duration(time.Second * 5),\n\t\t\t\tnewClient:        func(string, *tls.Config) (dockerClient, error) { return tt.client, nil },\n\t\t\t\tcontainerList:    make(map[string]context.CancelFunc),\n\t\t\t\tIncludeSourceTag: true,\n\t\t\t}\n\n\t\t\terr := plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc.Wait(len(tt.expected))\n\t\t\tplugin.Stop()\n\n\t\t\trequire.Nil(t, acc.Errors) // no errors during gathering\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/docker_log/sample.conf",
    "content": "# Read logging output from the Docker engine\n[[inputs.docker_log]]\n  ## Docker Endpoint\n  ##   To use TCP, set endpoint = \"tcp://[ip]:[port]\"\n  ##   To use environment variables (ie, docker-machine), set endpoint = \"ENV\"\n  # endpoint = \"unix:///var/run/docker.sock\"\n\n  ## When true, container logs are read from the beginning; otherwise reading\n  ## begins at the end of the log. If state-persistence is enabled for Telegraf,\n  ## the reading continues at the last previously processed timestamp.\n  # from_beginning = false\n\n  ## Timeout for Docker API calls.\n  # timeout = \"5s\"\n\n  ## Containers to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all containers\n  # container_name_include = []\n  # container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"running\" state will be captured.\n  # container_state_include = []\n  # container_state_exclude = []\n\n  ## docker labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  # docker_label_include = []\n  # docker_label_exclude = []\n\n  ## Set the source tag for the metrics to the container ID hostname, eg first 12 chars\n  source_tag = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/dovecot/README.md",
    "content": "# Dovecot Input Plugin\n\nThis plugin uses the Dovecot [v2.1 stats protocol][stats] to gather\nmetrics about configured domains of [Dovecot][dovecot] servers. You can use this\nplugin on Dovecot up to and including version v2.3.x.\n\n> [!IMPORTANT]\n> Dovecot v2.4+ has the old protocol removed and this plugin will not work.\n> Please use Dovecot's [Openmetrics exporter][openmetrics] in combination with\n> the [http input plugin][http_plugin] and `openmetrics` data format for newer\n> versions of Dovecot.\n\n⭐ Telegraf v0.10.3\n🏷️ server\n💻 all\n\n[dovecot]: https://www.dovecot.org/\n[stats]: https://doc.dovecot.org/configuration_manual/stats/old_statistics/#old-statistics\n[http_plugin]: /plugins/inputs/http/README.md\n[openmetrics]: https://doc.dovecot.org/latest/core/config/statistics.html#openmetrics\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about dovecot servers\n[[inputs.dovecot]]\n  ## specify dovecot servers via an address:port list\n  ##  e.g.\n  ##    localhost:24242\n  ## or as an UDS socket\n  ##  e.g.\n  ##    /var/run/dovecot/old-stats\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost:24242\"]\n\n  ## Type is one of \"user\", \"domain\", \"ip\", or \"global\"\n  type = \"global\"\n\n  ## Wildcard matches like \"*.com\". An empty string \"\" is same as \"*\"\n  ## If type = \"ip\" filters should be <IP/network>\n  filters = [\"\"]\n```\n\n## Metrics\n\n- dovecot\n  - tags:\n    - server (hostname)\n    - type (query type)\n    - ip (ip addr)\n    - user (username)\n    - domain (domain name)\n  - fields:\n    - reset_timestamp (string)\n    - last_update (string)\n    - num_logins (integer)\n    - num_cmds (integer)\n    - num_connected_sessions (integer)\n    - user_cpu (float)\n    - sys_cpu (float)\n    - clock_time (float)\n    - min_faults (integer)\n    - maj_faults (integer)\n    - vol_cs (integer)\n    - invol_cs (integer)\n    - disk_input (integer)\n    - disk_output (integer)\n    - read_count (integer)\n    - read_bytes (integer)\n    - write_count (integer)\n    - write_bytes (integer)\n    - mail_lookup_path (integer)\n    - mail_lookup_attr (integer)\n    - mail_read_count (integer)\n    - mail_read_bytes (integer)\n    - mail_cache_hits (integer)\n\n## Example Output\n\n```text\ndovecot,server=dovecot-1.domain.test,type=global clock_time=101196971074203.94,disk_input=6493168218112i,disk_output=17978638815232i,invol_cs=1198855447i,last_update=\"2016-04-08 11:04:13.000379245 +0200 CEST\",mail_cache_hits=68192209i,mail_lookup_attr=0i,mail_lookup_path=653861i,mail_read_bytes=86705151847i,mail_read_count=566125i,maj_faults=17208i,min_faults=1286179702i,num_cmds=917469i,num_connected_sessions=8896i,num_logins=174827i,read_bytes=30327690466186i,read_count=1772396430i,reset_timestamp=\"2016-04-08 10:28:45 +0200 CEST\",sys_cpu=157965.692,user_cpu=219337.48,vol_cs=2827615787i,write_bytes=17150837661940i,write_count=992653220i 1460106266642153907\n```\n"
  },
  {
    "path": "plugins/inputs/dovecot/dovecot.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage dovecot\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultTimeout = time.Second * time.Duration(5)\n\tvalidQuery     = map[string]bool{\n\t\t\"user\": true, \"domain\": true, \"global\": true, \"ip\": true,\n\t}\n)\n\ntype Dovecot struct {\n\tType    string   `toml:\"type\"`\n\tFilters []string `toml:\"filters\"`\n\tServers []string `toml:\"servers\"`\n}\n\nfunc (*Dovecot) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *Dovecot) Gather(acc telegraf.Accumulator) error {\n\tif !validQuery[d.Type] {\n\t\treturn fmt.Errorf(\"error: %s is not a valid query type\", d.Type)\n\t}\n\n\tif len(d.Servers) == 0 {\n\t\td.Servers = append(d.Servers, \"127.0.0.1:24242\")\n\t}\n\n\tif len(d.Filters) == 0 {\n\t\td.Filters = append(d.Filters, \"\")\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, server := range d.Servers {\n\t\tfor _, filter := range d.Filters {\n\t\t\twg.Add(1)\n\t\t\tgo func(s string, f string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tacc.AddError(gatherServer(s, acc, d.Type, f))\n\t\t\t}(server, filter)\n\t\t}\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc gatherServer(addr string, acc telegraf.Accumulator, qtype, filter string) error {\n\tvar proto string\n\n\tif strings.HasPrefix(addr, \"/\") {\n\t\tproto = \"unix\"\n\t} else {\n\t\tproto = \"tcp\"\n\n\t\t_, _, err := net.SplitHostPort(addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w on url %q\", err, addr)\n\t\t}\n\t}\n\n\tc, err := net.DialTimeout(proto, addr, defaultTimeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to dovecot server %q: %w\", addr, err)\n\t}\n\tdefer c.Close()\n\n\t// Extend connection\n\tif err := c.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn fmt.Errorf(\"setting deadline failed for dovecot server %q: %w\", addr, err)\n\t}\n\n\tmsg := \"EXPORT\\t\" + qtype\n\tif len(filter) > 0 {\n\t\tmsg += fmt.Sprintf(\"\\t%s=%s\", qtype, filter)\n\t}\n\tmsg += \"\\n\"\n\n\tif _, err := c.Write([]byte(msg)); err != nil {\n\t\treturn fmt.Errorf(\"writing message %q failed for dovecot server %q: %w\", msg, addr, err)\n\t}\n\tvar buf bytes.Buffer\n\tif _, err := io.Copy(&buf, c); err != nil {\n\t\t// We need to accept the timeout here as reading from the connection will only terminate on EOF\n\t\t// or on a timeout to happen. As EOF for TCP connections will only be sent on connection closing,\n\t\t// the only way to get the whole message is to wait for the timeout to happen.\n\t\tvar nerr net.Error\n\t\tif !errors.As(err, &nerr) || !nerr.Timeout() {\n\t\t\treturn fmt.Errorf(\"copying message failed for dovecot server %q: %w\", addr, err)\n\t\t}\n\t}\n\n\tvar host string\n\tif strings.HasPrefix(addr, \"/\") {\n\t\thost = addr\n\t} else {\n\t\thost, _, err = net.SplitHostPort(addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading address failed for dovecot server %q: %w\", addr, err)\n\t\t}\n\t}\n\n\tgatherStats(&buf, acc, host, qtype)\n\treturn nil\n}\n\nfunc gatherStats(buf *bytes.Buffer, acc telegraf.Accumulator, host, qtype string) {\n\tlines := strings.Split(buf.String(), \"\\n\")\n\thead := strings.Split(lines[0], \"\\t\")\n\tvals := lines[1:]\n\n\tfor i := range vals {\n\t\tif vals[i] == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tval := strings.Split(vals[i], \"\\t\")\n\n\t\tfields := make(map[string]interface{})\n\t\ttags := map[string]string{\"server\": host, \"type\": qtype}\n\n\t\tif qtype != \"global\" {\n\t\t\ttags[qtype] = val[0]\n\t\t}\n\n\t\tfor n := range val {\n\t\t\tswitch head[n] {\n\t\t\tcase qtype:\n\t\t\t\tcontinue\n\t\t\tcase \"user_cpu\", \"sys_cpu\", \"clock_time\":\n\t\t\t\tfields[head[n]] = secParser(val[n])\n\t\t\tcase \"reset_timestamp\", \"last_update\":\n\t\t\t\tfields[head[n]] = timeParser(val[n])\n\t\t\tdefault:\n\t\t\t\tival, _ := splitSec(val[n])\n\t\t\t\tfields[head[n]] = ival\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"dovecot\", fields, tags)\n\t}\n}\n\nfunc splitSec(tm string) (sec, msec int64) {\n\tvar err error\n\tss := strings.Split(tm, \".\")\n\n\tsec, err = strconv.ParseInt(ss[0], 10, 64)\n\tif err != nil {\n\t\tsec = 0\n\t}\n\tif len(ss) > 1 {\n\t\tmsec, err = strconv.ParseInt(ss[1], 10, 64)\n\t\tif err != nil {\n\t\t\tmsec = 0\n\t\t}\n\t} else {\n\t\tmsec = 0\n\t}\n\n\treturn sec, msec\n}\n\nfunc timeParser(tm string) time.Time {\n\tsec, msec := splitSec(tm)\n\treturn time.Unix(sec, msec)\n}\n\nfunc secParser(tm string) float64 {\n\tsec, msec := splitSec(tm)\n\treturn float64(sec) + (float64(msec) / 1000000.0)\n}\n\nfunc init() {\n\tinputs.Add(\"dovecot\", func() telegraf.Input {\n\t\treturn &Dovecot{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dovecot/dovecot_test.go",
    "content": "package dovecot\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"net/textproto\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDovecotIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"reset_timestamp\":        time.Unix(1453969886, 0),\n\t\t\"last_update\":            time.Unix(1454603963, 39864),\n\t\t\"num_logins\":             int64(7503897),\n\t\t\"num_cmds\":               int64(52595715),\n\t\t\"num_connected_sessions\": int64(1204),\n\t\t\"user_cpu\":               1.00831175372e+08,\n\t\t\"sys_cpu\":                8.3849071112e+07,\n\t\t\"clock_time\":             4.3260019315281835e+15,\n\t\t\"min_faults\":             int64(763950011),\n\t\t\"maj_faults\":             int64(1112443),\n\t\t\"vol_cs\":                 int64(4120386897),\n\t\t\"invol_cs\":               int64(3685239306),\n\t\t\"disk_input\":             int64(41679480946688),\n\t\t\"disk_output\":            int64(1819070669176832),\n\t\t\"read_count\":             int64(2368906465),\n\t\t\"read_bytes\":             int64(2957928122981169),\n\t\t\"write_count\":            int64(3545389615),\n\t\t\"write_bytes\":            int64(1666822498251286),\n\t\t\"mail_lookup_path\":       int64(24396105),\n\t\t\"mail_lookup_attr\":       int64(302845),\n\t\t\"mail_read_count\":        int64(20155768),\n\t\t\"mail_read_bytes\":        int64(669946617705),\n\t\t\"mail_cache_hits\":        int64(1557255080),\n\t}\n\n\tvar acc testutil.Accumulator\n\n\t// Test type=global server=unix\n\taddr := \"/tmp/socket\"\n\twaitCh := make(chan int)\n\tgo func() {\n\t\tdefer close(waitCh)\n\n\t\tla, err := net.ResolveUnixAddr(\"unix\", addr)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tl, err := net.ListenUnix(\"unix\", la)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tdefer l.Close()\n\t\tdefer os.Remove(addr)\n\n\t\twaitCh <- 0\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tdefer conn.Close()\n\n\t\treadertp := textproto.NewReader(bufio.NewReader(conn))\n\t\tif _, err = readertp.ReadLine(); err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tbuf := bytes.NewBufferString(sampleGlobal)\n\t\tif _, err = io.Copy(conn, buf); err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}()\n\n\t// Wait for server to start\n\t<-waitCh\n\n\td := &Dovecot{Servers: []string{addr}, Type: \"global\"}\n\terr := d.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\"server\": addr, \"type\": \"global\"}\n\tacc.AssertContainsTaggedFields(t, \"dovecot\", fields, tags)\n\n\t// Test type=global\n\ttags = map[string]string{\"server\": \"dovecot.test\", \"type\": \"global\"}\n\tbuf := bytes.NewBufferString(sampleGlobal)\n\n\tgatherStats(buf, &acc, \"dovecot.test\", \"global\")\n\tacc.AssertContainsTaggedFields(t, \"dovecot\", fields, tags)\n\n\t// Test type=domain\n\ttags = map[string]string{\"server\": \"dovecot.test\", \"type\": \"domain\", \"domain\": \"domain.test\"}\n\tbuf = bytes.NewBufferString(sampleDomain)\n\n\tgatherStats(buf, &acc, \"dovecot.test\", \"domain\")\n\tacc.AssertContainsTaggedFields(t, \"dovecot\", fields, tags)\n\n\t// Test type=ip\n\ttags = map[string]string{\"server\": \"dovecot.test\", \"type\": \"ip\", \"ip\": \"192.168.0.100\"}\n\tbuf = bytes.NewBufferString(sampleIP)\n\n\tgatherStats(buf, &acc, \"dovecot.test\", \"ip\")\n\tacc.AssertContainsTaggedFields(t, \"dovecot\", fields, tags)\n\n\t// Test type=user\n\tfields = map[string]interface{}{\n\t\t\"reset_timestamp\":  time.Unix(1453969886, 0),\n\t\t\"last_update\":      time.Unix(1454603963, 39864),\n\t\t\"num_logins\":       int64(7503897),\n\t\t\"num_cmds\":         int64(52595715),\n\t\t\"user_cpu\":         1.00831175372e+08,\n\t\t\"sys_cpu\":          8.3849071112e+07,\n\t\t\"clock_time\":       4.3260019315281835e+15,\n\t\t\"min_faults\":       int64(763950011),\n\t\t\"maj_faults\":       int64(1112443),\n\t\t\"vol_cs\":           int64(4120386897),\n\t\t\"invol_cs\":         int64(3685239306),\n\t\t\"disk_input\":       int64(41679480946688),\n\t\t\"disk_output\":      int64(1819070669176832),\n\t\t\"read_count\":       int64(2368906465),\n\t\t\"read_bytes\":       int64(2957928122981169),\n\t\t\"write_count\":      int64(3545389615),\n\t\t\"write_bytes\":      int64(1666822498251286),\n\t\t\"mail_lookup_path\": int64(24396105),\n\t\t\"mail_lookup_attr\": int64(302845),\n\t\t\"mail_read_count\":  int64(20155768),\n\t\t\"mail_read_bytes\":  int64(669946617705),\n\t\t\"mail_cache_hits\":  int64(1557255080),\n\t}\n\n\ttags = map[string]string{\"server\": \"dovecot.test\", \"type\": \"user\", \"user\": \"user.1@domain.test\"}\n\tbuf = bytes.NewBufferString(sampleUser)\n\n\tgatherStats(buf, &acc, \"dovecot.test\", \"user\")\n\tacc.AssertContainsTaggedFields(t, \"dovecot\", fields, tags)\n}\n\nconst sampleGlobal = `reset_timestamp\tlast_update\tnum_logins\tnum_cmds\tnum_connected_sessions\tuser_cpu\tsys_cpu\tclock_time\t` +\n\t`min_faults\tmaj_faults\tvol_cs\tinvol_cs\tdisk_input\tdisk_output\tread_count\tread_bytes\twrite_count\twrite_bytes\t` +\n\t`mail_lookup_path\tmail_lookup_attr\tmail_read_count\tmail_read_bytes\tmail_cache_hits\n1453969886\t1454603963.039864\t7503897\t52595715\t1204\t100831175.372000\t83849071.112000\t4326001931528183.495762\t` +\n\t`763950011\t1112443\t4120386897\t3685239306\t41679480946688\t1819070669176832\t2368906465\t2957928122981169\t` +\n\t`3545389615\t1666822498251286\t24396105\t302845\t20155768\t669946617705\t1557255080`\n\nconst sampleDomain = `domain\treset_timestamp\tlast_update\tnum_logins\tnum_cmds\tnum_connected_sessions\tuser_cpu\t` +\n\t`sys_cpu\tclock_time\tmin_faults\tmaj_faults\tvol_cs\tinvol_cs\tdisk_input\tdisk_output\tread_count\tread_bytes\t` +\n\t`write_count\twrite_bytes\tmail_lookup_path\tmail_lookup_attr\tmail_read_count\tmail_read_bytes\tmail_cache_hits\ndomain.test\t1453969886\t1454603963.039864\t7503897\t52595715\t1204\t100831175.372000\t83849071.112000\t` +\n\t`4326001931528183.495762\t763950011\t1112443\t4120386897\t3685239306\t41679480946688\t1819070669176832\t` +\n\t`2368906465\t2957928122981169\t3545389615\t1666822498251286\t24396105\t302845\t20155768\t669946617705\t1557255080`\n\nconst sampleIP = `ip\treset_timestamp\tlast_update\tnum_logins\tnum_cmds\tnum_connected_sessions\tuser_cpu\t` +\n\t`sys_cpu\tclock_time\tmin_faults\tmaj_faults\tvol_cs\tinvol_cs\tdisk_input\tdisk_output\tread_count\t` +\n\t`read_bytes\twrite_count\twrite_bytes\tmail_lookup_path\tmail_lookup_attr\tmail_read_count\tmail_read_bytes\tmail_cache_hits\n192.168.0.100\t1453969886\t1454603963.039864\t7503897\t52595715\t1204\t100831175.372000\t83849071.112000\t` +\n\t`4326001931528183.495762\t763950011\t1112443\t4120386897\t3685239306\t41679480946688\t1819070669176832\t` +\n\t`2368906465\t2957928122981169\t3545389615\t1666822498251286\t24396105\t302845\t20155768\t669946617705\t1557255080`\n\nconst sampleUser = `user\treset_timestamp\tlast_update\tnum_logins\tnum_cmds\tuser_cpu\tsys_cpu\tclock_time\t` +\n\t`min_faults\tmaj_faults\tvol_cs\tinvol_cs\tdisk_input\tdisk_output\tread_count\tread_bytes\twrite_count\t` +\n\t`write_bytes\tmail_lookup_path\tmail_lookup_attr\tmail_read_count\tmail_read_bytes\tmail_cache_hits\nuser.1@domain.test\t1453969886\t1454603963.039864\t7503897\t52595715\t100831175.372000\t83849071.112000\t` +\n\t`4326001931528183.495762\t763950011\t1112443\t4120386897\t3685239306\t41679480946688\t1819070669176832\t` +\n\t`2368906465\t2957928122981169\t3545389615\t1666822498251286\t24396105\t302845\t20155768\t669946617705\t1557255080`\n\nfunc TestDovecotContainerIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping dovecot integration tests.\")\n\t}\n\n\ttestdata, err := filepath.Abs(\"testdata/dovecot.conf\")\n\trequire.NoError(t, err, \"determining absolute path of test-data failed\")\n\n\tservicePort := \"24242\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"dovecot/dovecot:2.3-latest\",\n\t\tExposedPorts: []string{servicePort},\n\t\tFiles: map[string]string{\n\t\t\t\"/etc/dovecot/dovecot.conf\": testdata,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"starting up for imap\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\td := &Dovecot{\n\t\tServers: []string{container.Address + \":\" + container.Ports[servicePort]},\n\t\tType:    \"global\",\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, d.Gather(&acc))\n\trequire.Eventually(t,\n\t\tfunc() bool { return acc.HasMeasurement(\"dovecot\") },\n\t\t5*time.Second,\n\t\t10*time.Millisecond,\n\t)\n\n\trequire.True(t, acc.HasTag(\"dovecot\", \"type\"))\n\trequire.True(t, acc.HasField(\"dovecot\", \"sys_cpu\"))\n\trequire.True(t, acc.HasField(\"dovecot\", \"write_count\"))\n\trequire.True(t, acc.HasField(\"dovecot\", \"mail_read_count\"))\n\trequire.True(t, acc.HasField(\"dovecot\", \"auth_failures\"))\n}\n"
  },
  {
    "path": "plugins/inputs/dovecot/sample.conf",
    "content": "# Read metrics about dovecot servers\n[[inputs.dovecot]]\n  ## specify dovecot servers via an address:port list\n  ##  e.g.\n  ##    localhost:24242\n  ## or as an UDS socket\n  ##  e.g.\n  ##    /var/run/dovecot/old-stats\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"localhost:24242\"]\n\n  ## Type is one of \"user\", \"domain\", \"ip\", or \"global\"\n  type = \"global\"\n\n  ## Wildcard matches like \"*.com\". An empty string \"\" is same as \"*\"\n  ## If type = \"ip\" filters should be <IP/network>\n  filters = [\"\"]\n"
  },
  {
    "path": "plugins/inputs/dovecot/testdata/dovecot.conf",
    "content": "## This is a default dovecot.conf file with the\n## addition of the service stats section\n\nmail_home=/srv/mail/%Lu\nmail_location=sdbox:~/Mail\nmail_uid=1000\nmail_gid=1000\n\nprotocols = imap pop3 submission sieve lmtp\n\nfirst_valid_uid = 1000\nlast_valid_uid = 1000\n\npassdb {\n  driver = static\n  args = password=pass\n}\n\nssl=yes\nssl_cert=<cert.pem\nssl_key=<key.pem\n\nnamespace {\n  inbox = yes\n  separator = /\n}\n\nservice lmtp {\n  inet_listener {\n    port = 24\n  }\n}\n\nplugin {\n  old_stats_refresh = 30 secs\n}\n\nservice old-stats {\n  inet_listener {\n    address = *\n    port = 24242\n  }\n}\n\nlisten = *\n\nlog_path=/dev/stdout\ninfo_log_path=/dev/stdout\ndebug_log_path=/dev/stdout\n"
  },
  {
    "path": "plugins/inputs/dpdk/README.md",
    "content": "# Data Plane Development Kit (DPDK) Input Plugin\n\nThis plugin collects metrics exposed by applications built with the\n[Data Plane Development Kit][dpdk] which is an extensive set of open\nsource libraries designed for accelerating packet processing workloads.\n\n> [!NOTE]\n> Since DPDK will most likely run with root privileges, the telemetry socket\n> exposed by DPDK will also require root access. Please adjust permissions\n> accordingly!\n\nRefer to the [Telemetry User Guide][user_guide] for details and examples on how\nto use DPDK in your application.\n\n> [!IMPORTANT]\n> This plugin uses the `v2` interface to read telemetry > data from applications\n> and required DPDK version `v20.05` or higher. Some metrics might require later\n> versions.\n> The recommended version, especially in conjunction with the `in_memory`\n> option is `DPDK 21.11.2` or higher.\n\n⭐ Telegraf v1.19.0\n🏷️ applications, network\n💻 linux\n\n[dpdk]: https://www.dpdk.org\n[user_guide]: https://doc.dpdk.org/guides/howto/telemetry.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Reads metrics from DPDK applications using v2 telemetry interface.\n# This plugin ONLY supports Linux\n[[inputs.dpdk]]\n  ## Path to DPDK telemetry socket. This shall point to v2 version of DPDK\n  ## telemetry interface.\n  # socket_path = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\n  ## Duration that defines how long the connected socket client will wait for\n  ## a response before terminating connection.\n  ## This includes both writing to and reading from socket. Since it's local\n  ## socket access to a fast packet processing application, the timeout should\n  ## be sufficient for most users.\n  ## Setting the value to 0 disables the timeout (not recommended)\n  # socket_access_timeout = \"200ms\"\n\n  ## Enables telemetry data collection for selected device types.\n  ## Adding \"ethdev\" enables collection of telemetry from DPDK NICs (stats, xstats, link_status, info).\n  ## Adding \"rawdev\" enables collection of telemetry from DPDK Raw Devices (xstats).\n  # device_types = [\"ethdev\"]\n\n  ## List of custom, application-specific telemetry commands to query\n  ## The list of available commands depend on the application deployed.\n  ## Applications can register their own commands via telemetry library API\n  ## https://doc.dpdk.org/guides/prog_guide/telemetry_lib.html#registering-commands\n  ## For L3 Forwarding with Power Management Sample Application this could be:\n  ##   additional_commands = [\"/l3fwd-power/stats\"]\n  # additional_commands = []\n\n  ## List of plugin options.\n  ## Supported options:\n  ##  - \"in_memory\" option enables reading for multiple sockets when a dpdk application is running with --in-memory option.\n  ##    When option is enabled plugin will try to find additional socket paths related to provided socket_path.\n  ##    Details: https://doc.dpdk.org/guides/howto/telemetry.html#connecting-to-different-dpdk-processes\n  # plugin_options = [\"in_memory\"]\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error during the startup and gather phases if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n\n  ## List of metadata fields which will be added to every metric produced by the plugin.\n  ## Supported options:\n  ##  - \"pid\" - exposes PID of DPDK process. Example: pid=2179660i\n  ##  - \"version\" - exposes version of DPDK. Example: version=\"DPDK 21.11.2\"\n  # metadata_fields = [\"pid\", \"version\"]\n\n  ## Allows turning off collecting data for individual \"ethdev\" commands.\n  ## Remove \"/ethdev/link_status\" from list to gather link status metrics.\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/link_status\"]\n\n  ## When running multiple instances of the plugin it's recommended to add a\n  ## unique tag to each instance to identify metrics exposed by an instance\n  ## of DPDK application. This is useful when multiple DPDK apps run on a\n  ## single host.\n  ##  [inputs.dpdk.tags]\n  ##    dpdk_instance = \"my-fwd-app\"\n```\n\nThis plugin offers multiple configuration options, please review examples below\nfor additional usage information.\n\n### Example: Minimal Configuration for NIC metrics\n\nThis configuration allows getting metrics for all devices reported via\n`/ethdev/list` command:\n\n* `/ethdev/info` - device information: name, MAC address, buffers size, etc\n                   (since `DPDK 21.11`)\n* `/ethdev/stats` - basic device statistics (since `DPDK 20.11`)\n* `/ethdev/xstats` - extended device statistics\n* `/ethdev/link_status` - up/down link status\n\n```toml\n[[inputs.dpdk]]\n  device_types = [\"ethdev\"]\n```\n\nSince this configuration will query `/ethdev/link_status` it's recommended to\nincrease timeout to `socket_access_timeout = \"10s\"`.\n\nThe [plugin collecting interval](../../../docs/CONFIGURATION.md#input-plugins)\nshould be adjusted accordingly (e.g. `interval = \"30s\"`).\n\n### Example: Excluding NIC link status from being collected\n\nChecking link status depending on underlying implementation may take more time\nto complete. This configuration can be used to exclude this telemetry command\nto allow faster response for metrics.\n\n```toml\n[[inputs.dpdk]]\n  device_types = [\"ethdev\"]\n\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/link_status\"]\n```\n\nA separate plugin instance with higher timeout settings can be used to get\n`/ethdev/link_status` independently.  Consult [Independent NIC link status\nconfiguration](#example-independent-nic-link-status-configuration) and [Getting\nmetrics from multiple DPDK instances running on same\nhost](#example-getting-metrics-from-multiple-dpdk-instances-on-same-host)\nexamples for further details.\n\n### Example: Independent NIC link status configuration\n\nThis configuration allows getting `/ethdev/link_status` using separate\nconfiguration, with higher timeout.\n\n```toml\n[[inputs.dpdk]]\n  interval = \"30s\"\n  socket_access_timeout = \"10s\"\n  device_types = [\"ethdev\"]\n\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/info\", \"/ethdev/stats\", \"/ethdev/xstats\"]\n```\n\n### Example: Getting application-specific metrics\n\nThis configuration allows reading custom metrics exposed by\napplications. Example telemetry command obtained from\n[L3 Forwarding with Power Management Sample Application][sample].\n\n```toml\n[[inputs.dpdk]]\n  device_types = [\"ethdev\"]\n  additional_commands = [\"/l3fwd-power/stats\"]\n\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/link_status\"]\n```\n\nCommand entries specified in `additional_commands` should match DPDK command\nformat:\n\n* Command entry format: either `command` or `command,params` for commands that\n  expect parameters, where comma (`,`) separates command from params.\n* Command entry length (command with params) should be `< 1024` characters.\n* Command length (without params) should be `< 56` characters.\n* Commands have to start with `/`.\n\nProviding invalid commands will prevent the plugin from starting. Additional\ncommands allow duplicates, but they will be removed during execution, so each\ncommand will be executed only once during each metric gathering interval.\n\n[sample]: https://doc.dpdk.org/guides/sample_app_ug/l3_forward_power_man.html\n\n### Example: Getting metrics from multiple DPDK instances on same host\n\nThis configuration allows getting metrics from two separate applications\nexposing their telemetry interfaces via separate sockets. For each plugin\ninstance a unique tag `[inputs.dpdk.tags]` allows distinguishing between them.\n\n```toml\n# Instance #1 - L3 Forwarding with Power Management Application\n[[inputs.dpdk]]\n  socket_path = \"/var/run/dpdk/rte/l3fwd-power_telemetry.v2\"\n  device_types = [\"ethdev\"]\n  additional_commands = [\"/l3fwd-power/stats\"]\n\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/link_status\"]\n\n  [inputs.dpdk.tags]\n    dpdk_instance = \"l3fwd-power\"\n\n# Instance #2 - L2 Forwarding with Intel Cache Allocation Technology (CAT)\n# Application\n[[inputs.dpdk]]\n  socket_path = \"/var/run/dpdk/rte/l2fwd-cat_telemetry.v2\"\n  device_types = [\"ethdev\"]\n\n[inputs.dpdk.ethdev]\n  exclude_commands = [\"/ethdev/link_status\"]\n\n  [inputs.dpdk.tags]\n    dpdk_instance = \"l2fwd-cat\"\n```\n\nThis utilizes Telegraf's standard capability of [adding custom\ntags](../../../docs/CONFIGURATION.md#input-plugins) to input plugin's\nmeasurements.\n\n## Metrics\n\nThe DPDK socket accepts `command,params` requests and returns metric data in\nJSON format. All metrics from DPDK socket become flattened using [Telegraf's\nJSON Flattener](../../parsers/json/README.md) and exposed as fields.  If DPDK\nresponse contains no information (is empty or is null) then such response will\nbe discarded.\n\n> **NOTE:** Since DPDK allows registering custom metrics in its telemetry\n> framework the JSON response from DPDK may contain various sets of metrics.\n> While metrics from `/ethdev/stats` should be most stable, the `/ethdev/xstats`\n> may contain driver-specific metrics (depending on DPDK application\n> configuration). The application-specific commands like `/l3fwd-power/stats`\n> can return their own specific set of metrics.\n\n## Example Output\n\nThe output consists of plugin name (`dpdk`), and a set of tags that identify\nquerying hierarchy:\n\n```text\ndpdk,host=dpdk-host,dpdk_instance=l3fwd-power,command=/ethdev/stats,params=0 [fields] [timestamp]\n```\n\n| Tag | Description |\n|-----|-------------|\n| `host` | hostname of the machine (consult [Telegraf Agent configuration](https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md#agent) for additional details) |\n| `dpdk_instance` | custom tag from `[inputs.dpdk.tags]` (optional) |\n| `command` | executed command (without params) |\n| `params` | command parameter, e.g. for `/ethdev/stats` it is the ID of NIC as exposed by `/ethdev/list`. For DPDK app that uses 2 NICs the metrics will output e.g. `params=0`, `params=1`. |\n\nWhen running plugin configuration below...\n\n```toml\n[[inputs.dpdk]]\n  device_types = [\"ethdev\"]\n  additional_commands = [\"/l3fwd-power/stats\"]\n  metadata_fields = []\n  [inputs.dpdk.tags]\n    dpdk_instance = \"l3fwd-power\"\n```\n\n...expected output for `dpdk` plugin instance running on host named\n`host=dpdk-host`:\n\n```text\ndpdk,command=/ethdev/info,dpdk_instance=l3fwd-power,host=dpdk-host,params=0 all_multicast=0,dev_configured=1,dev_flags=74,dev_started=1,ethdev_rss_hf=0,lro=0,mac_addr=\"E4:3D:1A:DD:13:31\",mtu=1500,name=\"0000:ca:00.1\",nb_rx_queues=1,nb_tx_queues=1,numa_node=1,port_id=0,promiscuous=1,rx_mbuf_alloc_fail=0,rx_mbuf_size_min=2176,rx_offloads=0,rxq_state_0=1,scattered_rx=0,state=1,tx_offloads=65536,txq_state_0=1 1659017414000000000\ndpdk,command=/ethdev/stats,dpdk_instance=l3fwd-power,host=dpdk-host,params=0 q_opackets_0=0,q_ipackets_5=0,q_errors_11=0,ierrors=0,q_obytes_5=0,q_obytes_10=0,q_opackets_10=0,q_ipackets_4=0,q_ipackets_7=0,q_ipackets_15=0,q_ibytes_5=0,q_ibytes_6=0,q_ibytes_9=0,obytes=0,q_opackets_1=0,q_opackets_11=0,q_obytes_7=0,q_errors_5=0,q_errors_10=0,q_ibytes_4=0,q_obytes_6=0,q_errors_1=0,q_opackets_5=0,q_errors_3=0,q_errors_12=0,q_ipackets_11=0,q_ipackets_12=0,q_obytes_14=0,q_opackets_15=0,q_obytes_2=0,q_errors_8=0,q_opackets_12=0,q_errors_0=0,q_errors_9=0,q_opackets_14=0,q_ibytes_3=0,q_ibytes_15=0,q_ipackets_13=0,q_ipackets_14=0,q_obytes_3=0,q_errors_13=0,q_opackets_3=0,q_ibytes_0=7092,q_ibytes_2=0,q_ibytes_8=0,q_ipackets_8=0,q_ipackets_10=0,q_obytes_4=0,q_ibytes_10=0,q_ibytes_13=0,q_ibytes_1=0,q_ibytes_12=0,opackets=0,q_obytes_1=0,q_errors_15=0,q_opackets_2=0,oerrors=0,rx_nombuf=0,q_opackets_8=0,q_ibytes_11=0,q_ipackets_3=0,q_obytes_0=0,q_obytes_12=0,q_obytes_11=0,q_obytes_13=0,q_errors_6=0,q_ipackets_1=0,q_ipackets_6=0,q_ipackets_9=0,q_obytes_15=0,q_opackets_7=0,q_ibytes_14=0,ipackets=98,q_ipackets_2=0,q_opackets_6=0,q_ibytes_7=0,imissed=0,q_opackets_4=0,q_opackets_9=0,q_obytes_8=0,q_obytes_9=0,q_errors_4=0,q_errors_14=0,q_opackets_13=0,ibytes=7092,q_ipackets_0=98,q_errors_2=0,q_errors_7=0 1606310780000000000\ndpdk,command=/ethdev/stats,dpdk_instance=l3fwd-power,host=dpdk-host,params=1 q_opackets_0=0,q_ipackets_5=0,q_errors_11=0,ierrors=0,q_obytes_5=0,q_obytes_10=0,q_opackets_10=0,q_ipackets_4=0,q_ipackets_7=0,q_ipackets_15=0,q_ibytes_5=0,q_ibytes_6=0,q_ibytes_9=0,obytes=0,q_opackets_1=0,q_opackets_11=0,q_obytes_7=0,q_errors_5=0,q_errors_10=0,q_ibytes_4=0,q_obytes_6=0,q_errors_1=0,q_opackets_5=0,q_errors_3=0,q_errors_12=0,q_ipackets_11=0,q_ipackets_12=0,q_obytes_14=0,q_opackets_15=0,q_obytes_2=0,q_errors_8=0,q_opackets_12=0,q_errors_0=0,q_errors_9=0,q_opackets_14=0,q_ibytes_3=0,q_ibytes_15=0,q_ipackets_13=0,q_ipackets_14=0,q_obytes_3=0,q_errors_13=0,q_opackets_3=0,q_ibytes_0=7092,q_ibytes_2=0,q_ibytes_8=0,q_ipackets_8=0,q_ipackets_10=0,q_obytes_4=0,q_ibytes_10=0,q_ibytes_13=0,q_ibytes_1=0,q_ibytes_12=0,opackets=0,q_obytes_1=0,q_errors_15=0,q_opackets_2=0,oerrors=0,rx_nombuf=0,q_opackets_8=0,q_ibytes_11=0,q_ipackets_3=0,q_obytes_0=0,q_obytes_12=0,q_obytes_11=0,q_obytes_13=0,q_errors_6=0,q_ipackets_1=0,q_ipackets_6=0,q_ipackets_9=0,q_obytes_15=0,q_opackets_7=0,q_ibytes_14=0,ipackets=98,q_ipackets_2=0,q_opackets_6=0,q_ibytes_7=0,imissed=0,q_opackets_4=0,q_opackets_9=0,q_obytes_8=0,q_obytes_9=0,q_errors_4=0,q_errors_14=0,q_opackets_13=0,ibytes=7092,q_ipackets_0=98,q_errors_2=0,q_errors_7=0 1606310780000000000\ndpdk,command=/ethdev/xstats,dpdk_instance=l3fwd-power,host=dpdk-host,params=0 out_octets_encrypted=0,rx_fcoe_mbuf_allocation_errors=0,tx_q1packets=0,rx_priority0_xoff_packets=0,rx_priority7_xoff_packets=0,rx_errors=0,mac_remote_errors=0,in_pkts_invalid=0,tx_priority3_xoff_packets=0,tx_errors=0,rx_fcoe_bytes=0,rx_flow_control_xon_packets=0,rx_priority4_xoff_packets=0,tx_priority2_xoff_packets=0,rx_illegal_byte_errors=0,rx_xoff_packets=0,rx_management_packets=0,rx_priority7_dropped=0,rx_priority4_dropped=0,in_pkts_unchecked=0,rx_error_bytes=0,rx_size_256_to_511_packets=0,tx_priority4_xoff_packets=0,rx_priority6_xon_packets=0,tx_priority4_xon_to_xoff_packets=0,in_pkts_delayed=0,rx_priority0_mbuf_allocation_errors=0,out_octets_protected=0,tx_priority7_xon_to_xoff_packets=0,tx_priority1_xon_to_xoff_packets=0,rx_fcoe_no_direct_data_placement_ext_buff=0,tx_priority6_xon_to_xoff_packets=0,flow_director_filter_add_errors=0,rx_total_packets=99,rx_crc_errors=0,flow_director_filter_remove_errors=0,rx_missed_errors=0,tx_size_64_packets=0,rx_priority3_dropped=0,flow_director_matched_filters=0,tx_priority2_xon_to_xoff_packets=0,rx_priority1_xon_packets=0,rx_size_65_to_127_packets=99,rx_fragment_errors=0,in_pkts_notusingsa=0,rx_q0bytes=7162,rx_fcoe_dropped=0,rx_priority1_dropped=0,rx_fcoe_packets=0,rx_priority5_xoff_packets=0,out_pkts_protected=0,tx_total_packets=0,rx_priority2_dropped=0,in_pkts_late=0,tx_q1bytes=0,in_pkts_badtag=0,rx_multicast_packets=99,rx_priority6_xoff_packets=0,tx_flow_control_xoff_packets=0,rx_flow_control_xoff_packets=0,rx_priority0_xon_packets=0,in_pkts_untagged=0,tx_fcoe_packets=0,rx_priority7_mbuf_allocation_errors=0,tx_priority0_xon_to_xoff_packets=0,tx_priority5_xon_to_xoff_packets=0,tx_flow_control_xon_packets=0,tx_q0packets=0,tx_xoff_packets=0,rx_size_512_to_1023_packets=0,rx_priority3_xon_packets=0,rx_q0errors=0,rx_oversize_errors=0,tx_priority4_xon_packets=0,tx_priority5_xoff_packets=0,rx_priority5_xon_packets=0,rx_total_missed_packets=0,rx_priority4_mbuf_allocation_errors=0,tx_priority1_xon_packets=0,tx_management_packets=0,rx_priority5_mbuf_allocation_errors=0,rx_fcoe_no_direct_data_placement=0,rx_undersize_errors=0,tx_priority1_xoff_packets=0,rx_q0packets=99,tx_q2packets=0,tx_priority6_xon_packets=0,rx_good_packets=99,tx_priority5_xon_packets=0,tx_size_256_to_511_packets=0,rx_priority6_dropped=0,rx_broadcast_packets=0,tx_size_512_to_1023_packets=0,tx_priority3_xon_to_xoff_packets=0,in_pkts_unknownsci=0,in_octets_validated=0,tx_priority6_xoff_packets=0,tx_priority7_xoff_packets=0,rx_jabber_errors=0,tx_priority7_xon_packets=0,tx_priority0_xon_packets=0,in_pkts_unusedsa=0,tx_priority0_xoff_packets=0,mac_local_errors=33,rx_total_bytes=7162,in_pkts_notvalid=0,rx_length_errors=0,in_octets_decrypted=0,rx_size_128_to_255_packets=0,rx_good_bytes=7162,tx_size_65_to_127_packets=0,rx_mac_short_packet_dropped=0,tx_size_1024_to_max_packets=0,rx_priority2_mbuf_allocation_errors=0,flow_director_added_filters=0,tx_multicast_packets=0,rx_fcoe_crc_errors=0,rx_priority1_xoff_packets=0,flow_director_missed_filters=0,rx_xon_packets=0,tx_size_128_to_255_packets=0,out_pkts_encrypted=0,rx_priority4_xon_packets=0,rx_priority0_dropped=0,rx_size_1024_to_max_packets=0,tx_good_bytes=0,rx_management_dropped=0,rx_mbuf_allocation_errors=0,tx_xon_packets=0,rx_priority3_xoff_packets=0,tx_good_packets=0,tx_fcoe_bytes=0,rx_priority6_mbuf_allocation_errors=0,rx_priority2_xon_packets=0,tx_broadcast_packets=0,tx_q2bytes=0,rx_priority7_xon_packets=0,out_pkts_untagged=0,rx_priority2_xoff_packets=0,rx_priority1_mbuf_allocation_errors=0,tx_q0bytes=0,rx_size_64_packets=0,rx_priority5_dropped=0,tx_priority2_xon_packets=0,in_pkts_nosci=0,flow_director_removed_filters=0,in_pkts_ok=0,rx_l3_l4_xsum_error=0,rx_priority3_mbuf_allocation_errors=0,tx_priority3_xon_packets=0 1606310780000000000\ndpdk,command=/ethdev/xstats,dpdk_instance=l3fwd-power,host=dpdk-host,params=1 tx_priority5_xoff_packets=0,in_pkts_unknownsci=0,tx_q0packets=0,tx_total_packets=0,rx_crc_errors=0,rx_priority4_xoff_packets=0,rx_priority5_dropped=0,tx_size_65_to_127_packets=0,rx_good_packets=98,tx_priority6_xoff_packets=0,tx_fcoe_bytes=0,out_octets_protected=0,out_pkts_encrypted=0,rx_priority1_xon_packets=0,tx_size_128_to_255_packets=0,rx_flow_control_xoff_packets=0,rx_priority7_xoff_packets=0,tx_priority0_xon_to_xoff_packets=0,rx_broadcast_packets=0,tx_priority1_xon_packets=0,rx_xon_packets=0,rx_fragment_errors=0,tx_flow_control_xoff_packets=0,tx_q0bytes=0,out_pkts_untagged=0,rx_priority4_xon_packets=0,tx_priority5_xon_packets=0,rx_priority1_xoff_packets=0,rx_good_bytes=7092,rx_priority4_mbuf_allocation_errors=0,in_octets_decrypted=0,tx_priority2_xon_to_xoff_packets=0,rx_priority3_dropped=0,tx_multicast_packets=0,mac_local_errors=33,in_pkts_ok=0,rx_illegal_byte_errors=0,rx_xoff_packets=0,rx_q0errors=0,flow_director_added_filters=0,rx_size_256_to_511_packets=0,rx_priority3_xon_packets=0,rx_l3_l4_xsum_error=0,rx_priority6_dropped=0,in_pkts_notvalid=0,rx_size_64_packets=0,tx_management_packets=0,rx_length_errors=0,tx_priority7_xon_to_xoff_packets=0,rx_mbuf_allocation_errors=0,rx_missed_errors=0,rx_priority1_mbuf_allocation_errors=0,rx_fcoe_no_direct_data_placement=0,tx_priority3_xoff_packets=0,in_pkts_delayed=0,tx_errors=0,rx_size_512_to_1023_packets=0,tx_priority4_xon_packets=0,rx_q0bytes=7092,in_pkts_unchecked=0,tx_size_512_to_1023_packets=0,rx_fcoe_packets=0,in_pkts_nosci=0,rx_priority6_mbuf_allocation_errors=0,rx_priority1_dropped=0,tx_q2packets=0,rx_priority7_dropped=0,tx_size_1024_to_max_packets=0,rx_management_packets=0,rx_multicast_packets=98,rx_total_bytes=7092,mac_remote_errors=0,tx_priority3_xon_packets=0,rx_priority2_mbuf_allocation_errors=0,rx_priority5_mbuf_allocation_errors=0,tx_q2bytes=0,rx_size_128_to_255_packets=0,in_pkts_badtag=0,out_pkts_protected=0,rx_management_dropped=0,rx_fcoe_bytes=0,flow_director_removed_filters=0,tx_priority2_xoff_packets=0,rx_fcoe_crc_errors=0,rx_priority0_mbuf_allocation_errors=0,rx_priority0_xon_packets=0,rx_fcoe_dropped=0,tx_priority1_xon_to_xoff_packets=0,rx_size_65_to_127_packets=98,rx_q0packets=98,tx_priority0_xoff_packets=0,rx_priority6_xon_packets=0,rx_total_packets=98,rx_undersize_errors=0,flow_director_missed_filters=0,rx_jabber_errors=0,in_pkts_invalid=0,in_pkts_late=0,rx_priority5_xon_packets=0,tx_priority4_xoff_packets=0,out_octets_encrypted=0,tx_q1packets=0,rx_priority5_xoff_packets=0,rx_priority6_xoff_packets=0,rx_errors=0,in_octets_validated=0,rx_priority3_xoff_packets=0,tx_priority4_xon_to_xoff_packets=0,tx_priority5_xon_to_xoff_packets=0,tx_flow_control_xon_packets=0,rx_priority0_dropped=0,flow_director_filter_add_errors=0,tx_q1bytes=0,tx_priority6_xon_to_xoff_packets=0,flow_director_matched_filters=0,tx_priority2_xon_packets=0,rx_fcoe_mbuf_allocation_errors=0,rx_priority2_xoff_packets=0,tx_priority7_xoff_packets=0,rx_priority0_xoff_packets=0,rx_oversize_errors=0,in_pkts_notusingsa=0,tx_size_64_packets=0,rx_size_1024_to_max_packets=0,tx_priority6_xon_packets=0,rx_priority2_dropped=0,rx_priority4_dropped=0,rx_priority7_mbuf_allocation_errors=0,rx_flow_control_xon_packets=0,tx_good_bytes=0,tx_priority3_xon_to_xoff_packets=0,rx_total_missed_packets=0,rx_error_bytes=0,tx_priority7_xon_packets=0,rx_mac_short_packet_dropped=0,tx_priority1_xoff_packets=0,tx_good_packets=0,tx_broadcast_packets=0,tx_xon_packets=0,in_pkts_unusedsa=0,rx_priority2_xon_packets=0,in_pkts_untagged=0,tx_fcoe_packets=0,flow_director_filter_remove_errors=0,rx_priority3_mbuf_allocation_errors=0,tx_priority0_xon_packets=0,rx_priority7_xon_packets=0,rx_fcoe_no_direct_data_placement_ext_buff=0,tx_xoff_packets=0,tx_size_256_to_511_packets=0 1606310780000000000\ndpdk,command=/ethdev/link_status,dpdk_instance=l3fwd-power,host=dpdk-host,params=0 status=\"UP\",link_status=1,speed=10000,duplex=\"full-duplex\" 1606310780000000000\ndpdk,command=/ethdev/link_status,dpdk_instance=l3fwd-power,host=dpdk-host,params=1 status=\"UP\",link_status=1,speed=10000,duplex=\"full-duplex\" 1606310780000000000\ndpdk,command=/l3fwd-power/stats,dpdk_instance=l3fwd-power,host=dpdk-host empty_poll=49506395979901,full_poll=0,busy_percent=0 1606310780000000000\n```\n\nWhen running plugin configuration below...\n\n```toml\n[[inputs.dpdk]]\n  interval = \"30s\"\n  socket_access_timeout = \"10s\"\n  device_types = [\"ethdev\"]\n  metadata_fields = [\"version\", \"pid\"]\n  plugin_options = [\"in_memory\"]\n\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/info\", \"/ethdev/stats\", \"/ethdev/xstats\"]\n```\n\nExpected output for `dpdk` plugin instance running with `link_status` command\nand all metadata fields enabled, additionally `link_status` field will be\nexposed to represent string value of `status` field (`DOWN`=0,`UP`=1):\n\n```text\ndpdk,command=/ethdev/link_status,host=dpdk-host,params=0 pid=100988i,version=\"DPDK 21.11.2\",status=\"DOWN\",link_status=0i 1660295749000000000\ndpdk,command=/ethdev/link_status,host=dpdk-host,params=0 pid=2401624i,version=\"DPDK 21.11.2\",status=\"UP\",link_status=1i 1660295749000000000\n```\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage dpdk\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultPathToSocket        = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\tdefaultAccessTimeout       = config.Duration(200 * time.Millisecond)\n\tmaxCommandLength           = 56\n\tmaxCommandLengthWithParams = 1024\n\tpluginName                 = \"dpdk\"\n\tethdevListCommand          = \"/ethdev/list\"\n\trawdevListCommand          = \"/rawdev/list\"\n\n\tdpdkMetadataFieldPidName     = \"pid\"\n\tdpdkMetadataFieldVersionName = \"version\"\n\n\tdpdkPluginOptionInMemory = \"in_memory\"\n\n\tunreachableSocketBehaviorIgnore = \"ignore\"\n\tunreachableSocketBehaviorError  = \"error\"\n)\n\ntype Dpdk struct {\n\tSocketPath                string          `toml:\"socket_path\"`\n\tAccessTimeout             config.Duration `toml:\"socket_access_timeout\"`\n\tDeviceTypes               []string        `toml:\"device_types\"`\n\tEthdevConfig              ethdevConfig    `toml:\"ethdev\"`\n\tAdditionalCommands        []string        `toml:\"additional_commands\"`\n\tMetadataFields            []string        `toml:\"metadata_fields\"`\n\tPluginOptions             []string        `toml:\"plugin_options\"`\n\tUnreachableSocketBehavior string          `toml:\"unreachable_socket_behavior\"`\n\tLog                       telegraf.Logger `toml:\"-\"`\n\n\tconnectors                   []*dpdkConnector\n\trawdevCommands               []string\n\tethdevCommands               []string\n\tethdevExcludedCommandsFilter filter.Filter\n\tsocketGlobPath               *globpath.GlobPath\n}\n\ntype ethdevConfig struct {\n\tEthdevExcludeCommands []string `toml:\"exclude_commands\"`\n}\n\nfunc (*Dpdk) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (dpdk *Dpdk) Init() error {\n\tdpdk.setupDefaultValues()\n\n\terr := dpdk.validateAdditionalCommands()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif dpdk.AccessTimeout < 0 {\n\t\treturn errors.New(\"socket_access_timeout should be positive number or equal to 0 (to disable timeouts)\")\n\t}\n\n\tif len(dpdk.AdditionalCommands) == 0 && len(dpdk.DeviceTypes) == 0 {\n\t\treturn errors.New(\"plugin was configured with nothing to read\")\n\t}\n\n\tdpdk.ethdevExcludedCommandsFilter, err = filter.Compile(dpdk.EthdevConfig.EthdevExcludeCommands)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error occurred during filter preparation for ethdev excluded commands: %w\", err)\n\t}\n\n\tif err = choice.Check(dpdk.UnreachableSocketBehavior, []string{unreachableSocketBehaviorError, unreachableSocketBehaviorIgnore}); err != nil {\n\t\treturn fmt.Errorf(\"unreachable_socket_behavior: %w\", err)\n\t}\n\n\tglob, err := globpath.Compile(dpdk.SocketPath + \"*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdpdk.socketGlobPath = glob\n\treturn nil\n}\n\nfunc (dpdk *Dpdk) Start(telegraf.Accumulator) error {\n\treturn dpdk.maintainConnections()\n}\n\n// Gather function gathers all unique commands and processes each command sequentially\n// Parallel processing could be achieved by running several instances of this plugin with different settings\nfunc (dpdk *Dpdk) Gather(acc telegraf.Accumulator) error {\n\tif err := dpdk.Start(acc); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, dpdkConn := range dpdk.connectors {\n\t\tcommands := dpdk.gatherCommands(acc, dpdkConn)\n\t\tfor _, command := range commands {\n\t\t\tdpdkConn.processCommand(acc, dpdk.Log, command, dpdk.MetadataFields)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (dpdk *Dpdk) Stop() {\n\tfor _, connector := range dpdk.connectors {\n\t\tif err := connector.tryClose(); err != nil {\n\t\t\tdpdk.Log.Warnf(\"Couldn't close connection for %q: %v\", connector.pathToSocket, err)\n\t\t}\n\t}\n\tdpdk.connectors = nil\n}\n\n// Setup default values for dpdk\nfunc (dpdk *Dpdk) setupDefaultValues() {\n\tif dpdk.SocketPath == \"\" {\n\t\tdpdk.SocketPath = defaultPathToSocket\n\t}\n\n\tif dpdk.DeviceTypes == nil {\n\t\tdpdk.DeviceTypes = []string{\"ethdev\"}\n\t}\n\n\tif dpdk.MetadataFields == nil {\n\t\tdpdk.MetadataFields = []string{dpdkMetadataFieldPidName, dpdkMetadataFieldVersionName}\n\t}\n\n\tif dpdk.PluginOptions == nil {\n\t\tdpdk.PluginOptions = []string{dpdkPluginOptionInMemory}\n\t}\n\n\tif len(dpdk.UnreachableSocketBehavior) == 0 {\n\t\tdpdk.UnreachableSocketBehavior = unreachableSocketBehaviorError\n\t}\n\n\tdpdk.rawdevCommands = []string{\"/rawdev/xstats\"}\n\tdpdk.ethdevCommands = []string{\"/ethdev/stats\", \"/ethdev/xstats\", \"/ethdev/info\", ethdevLinkStatusCommand}\n}\n\nfunc (dpdk *Dpdk) getDpdkInMemorySocketPaths() []string {\n\tfilePaths := dpdk.socketGlobPath.Match()\n\n\tvar results []string\n\tfor _, filePath := range filePaths {\n\t\tfileInfo, err := os.Stat(filePath)\n\t\tif err != nil || fileInfo.IsDir() || !strings.Contains(filePath, dpdkSocketTemplateName) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif isInMemorySocketPath(filePath, dpdk.SocketPath) {\n\t\t\tresults = append(results, filePath)\n\t\t}\n\t}\n\n\treturn results\n}\n\n// Checks that user-supplied commands are unique and match DPDK commands format\nfunc (dpdk *Dpdk) validateAdditionalCommands() error {\n\tdpdk.AdditionalCommands = uniqueValues(dpdk.AdditionalCommands)\n\n\tfor _, cmd := range dpdk.AdditionalCommands {\n\t\tif len(cmd) == 0 {\n\t\t\treturn errors.New(\"got empty command\")\n\t\t}\n\n\t\tif cmd[0] != '/' {\n\t\t\treturn fmt.Errorf(\"%q command should start with slash\", cmd)\n\t\t}\n\n\t\tif commandWithoutParams := stripParams(cmd); len(commandWithoutParams) >= maxCommandLength {\n\t\t\treturn fmt.Errorf(\"%q command is too long. It shall be less than %v characters\", commandWithoutParams, maxCommandLength)\n\t\t}\n\n\t\tif len(cmd) >= maxCommandLengthWithParams {\n\t\t\treturn fmt.Errorf(\"command with parameters %q shall be less than %v characters\", cmd, maxCommandLengthWithParams)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Establishes connections do DPDK telemetry sockets\nfunc (dpdk *Dpdk) maintainConnections() error {\n\tcandidates := []string{dpdk.SocketPath}\n\tif choice.Contains(dpdkPluginOptionInMemory, dpdk.PluginOptions) {\n\t\tcandidates = dpdk.getDpdkInMemorySocketPaths()\n\t}\n\n\t// Find sockets in the connected-sockets list that are not among\n\t// the candidates anymore and thus need to be removed.\n\tfor i := 0; i < len(dpdk.connectors); i++ {\n\t\tconnector := dpdk.connectors[i]\n\t\tif !choice.Contains(connector.pathToSocket, candidates) {\n\t\t\tdpdk.Log.Debugf(\"Close unused connection: %s\", connector.pathToSocket)\n\t\t\tif closeErr := connector.tryClose(); closeErr != nil {\n\t\t\t\tdpdk.Log.Warnf(\"Failed to close unused connection: %v\", closeErr)\n\t\t\t}\n\t\t\tdpdk.connectors = append(dpdk.connectors[:i], dpdk.connectors[i+1:]...)\n\t\t\ti--\n\t\t}\n\t}\n\n\t// Find candidates that are not yet in the connected-sockets list as we\n\t// need to connect to those.\n\tfor _, candidate := range candidates {\n\t\tvar found bool\n\t\tfor _, connector := range dpdk.connectors {\n\t\t\tif candidate == connector.pathToSocket {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tconnector := newDpdkConnector(candidate, dpdk.AccessTimeout)\n\t\t\tconnectionInitMessage, err := connector.connect()\n\t\t\tif err != nil {\n\t\t\t\tif dpdk.UnreachableSocketBehavior == unreachableSocketBehaviorError {\n\t\t\t\t\treturn fmt.Errorf(\"couldn't connect to socket %s: %w\", candidate, err)\n\t\t\t\t}\n\t\t\t\tdpdk.Log.Warnf(\"Couldn't connect to socket %s: %v\", candidate, err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdpdk.Log.Debugf(\"Successfully connected to the socket: %s. Version: %v running as process with PID %v with len %v\",\n\t\t\t\tcandidate, connectionInitMessage.Version, connectionInitMessage.Pid, connectionInitMessage.MaxOutputLen)\n\t\t\tdpdk.connectors = append(dpdk.connectors, connector)\n\t\t}\n\t}\n\n\tif len(dpdk.connectors) == 0 {\n\t\terrMsg := \"no active sockets connections present\"\n\t\tif dpdk.UnreachableSocketBehavior == unreachableSocketBehaviorError {\n\t\t\treturn errors.New(errMsg)\n\t\t}\n\t\tdpdk.Log.Warnf(\"Unreachable socket issue occurred: %v\", errMsg)\n\t}\n\n\treturn nil\n}\n\n// Gathers all unique commands\nfunc (dpdk *Dpdk) gatherCommands(acc telegraf.Accumulator, dpdkConnector *dpdkConnector) []string {\n\tvar commands []string\n\tif choice.Contains(\"ethdev\", dpdk.DeviceTypes) {\n\t\tethdevCommands := removeSubset(dpdk.ethdevCommands, dpdk.ethdevExcludedCommandsFilter)\n\t\tethdevCommands, err := dpdkConnector.appendCommandsWithParamsFromList(ethdevListCommand, ethdevCommands)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error occurred during fetching of %q params: %w\", ethdevListCommand, err))\n\t\t}\n\t\tcommands = append(commands, ethdevCommands...)\n\t}\n\n\tif choice.Contains(\"rawdev\", dpdk.DeviceTypes) {\n\t\trawdevCommands, err := dpdkConnector.appendCommandsWithParamsFromList(rawdevListCommand, dpdk.rawdevCommands)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error occurred during fetching of %q params: %w\", rawdevListCommand, err))\n\t\t}\n\t\tcommands = append(commands, rawdevCommands...)\n\t}\n\n\tcommands = append(commands, dpdk.AdditionalCommands...)\n\treturn uniqueValues(commands)\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\tdpdk := &Dpdk{\n\t\t\t// Setting it here (rather than in `Init()`) to distinguish between \"zero\" value,\n\t\t\t// default value and don't having value in config at all.\n\t\t\tAccessTimeout: defaultAccessTimeout,\n\t\t}\n\t\treturn dpdk\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_cmds.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype linkStatus int64\n\nconst (\n\tdown linkStatus = iota\n\tup\n)\n\nconst (\n\tethdevLinkStatusCommand    = \"/ethdev/link_status\"\n\tlinkStatusStringFieldName  = \"status\"\n\tlinkStatusIntegerFieldName = \"link_status\"\n)\n\nvar (\n\tlinkStatusMap = map[string]linkStatus{\n\t\t\"down\": down,\n\t\t\"up\":   up,\n\t}\n)\n\nfunc processCommandResponse(command string, data map[string]interface{}) error {\n\tif command == ethdevLinkStatusCommand {\n\t\treturn processLinkStatusCmd(data)\n\t}\n\treturn nil\n}\n\nfunc processLinkStatusCmd(data map[string]interface{}) error {\n\tstatus, ok := data[linkStatusStringFieldName].(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"can't find or parse %q field\", linkStatusStringFieldName)\n\t}\n\n\tparsedLinkStatus, ok := parseLinkStatus(status)\n\tif !ok {\n\t\treturn fmt.Errorf(\"can't parse linkStatus: unknown value: %q\", status)\n\t}\n\n\tdata[linkStatusIntegerFieldName] = int64(parsedLinkStatus)\n\treturn nil\n}\n\nfunc parseLinkStatus(s string) (linkStatus, bool) {\n\tvalue, ok := linkStatusMap[strings.ToLower(s)]\n\treturn value, ok\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_cmds_test.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_LinkStatusCommand(t *testing.T) {\n\tt.Run(\"when 'status' field is DOWN then return 'link_status'=0\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q:{%q: \"DOWN\"}}`, ethdevLinkStatusCommand, linkStatusStringFieldName)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tdpdkConn := dpdk.connectors[0]\n\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, ethdevLinkStatusCommand+\",1\", nil)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": ethdevLinkStatusCommand,\n\t\t\t\t\t\"params\":  \"1\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\tlinkStatusStringFieldName:  \"DOWN\",\n\t\t\t\t\tlinkStatusIntegerFieldName: int64(0),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"when 'status' field is UP then return 'link_status'=1\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q:{%q: \"UP\"}}`, ethdevLinkStatusCommand, linkStatusStringFieldName)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tdpdkConn := dpdk.connectors[0]\n\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, ethdevLinkStatusCommand+\",1\", nil)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": ethdevLinkStatusCommand,\n\t\t\t\t\t\"params\":  \"1\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\tlinkStatusStringFieldName:  \"UP\",\n\t\t\t\t\tlinkStatusIntegerFieldName: int64(1),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"when link status output doesn't have any fields then don't return 'link_status' field\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q:{}}`, ethdevLinkStatusCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tdpdkConn := dpdk.connectors[0]\n\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, ethdevLinkStatusCommand+\",1\", nil)\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, nil, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"when link status output doesn't have status field then don't return 'link_status' field\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q:{\"tag1\": 1}}`, ethdevLinkStatusCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tdpdkConn := dpdk.connectors[0]\n\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, ethdevLinkStatusCommand+\",1\", nil)\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": ethdevLinkStatusCommand,\n\t\t\t\t\t\"params\":  \"1\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"tag1\": float64(1),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"when link status output is invalid then don't return 'link_status' field\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q:{%q: \"BOB\"}}`, ethdevLinkStatusCommand, linkStatusStringFieldName)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tdpdkConn := dpdk.connectors[0]\n\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, ethdevLinkStatusCommand+\",1\", nil)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": ethdevLinkStatusCommand,\n\t\t\t\t\t\"params\":  \"1\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\tlinkStatusStringFieldName: \"BOB\",\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_connector.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\nconst (\n\tmaxInitMessageLength   = 1024 // based on https://github.com/DPDK/dpdk/blob/v22.07/lib/telemetry/telemetry.c#L352\n\tdpdkSocketTemplateName = \"dpdk_telemetry\"\n)\n\ntype initMessage struct {\n\tVersion      string `json:\"version\"`\n\tPid          int    `json:\"pid\"`\n\tMaxOutputLen uint32 `json:\"max_output_len\"`\n}\n\ntype dpdkConnector struct {\n\tpathToSocket  string\n\taccessTimeout time.Duration\n\tconnection    net.Conn\n\tinitMessage   *initMessage\n}\n\nfunc newDpdkConnector(pathToSocket string, accessTimeout config.Duration) *dpdkConnector {\n\treturn &dpdkConnector{\n\t\tpathToSocket:  pathToSocket,\n\t\taccessTimeout: time.Duration(accessTimeout),\n\t}\n}\n\n// Connects to the socket\n// Since DPDK is a local unix socket, it is instantly returns error or connection, so there's no need to set timeout for it\nfunc (conn *dpdkConnector) connect() (*initMessage, error) {\n\tif err := isSocket(conn.pathToSocket); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconnection, err := net.Dial(\"unixpacket\", conn.pathToSocket)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect to the socket: %w\", err)\n\t}\n\tconn.connection = connection\n\n\tconn.initMessage, err = conn.readInitMessage()\n\tif err != nil {\n\t\tif closeErr := conn.tryClose(); closeErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w and failed to close connection: %w\", err, closeErr)\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn conn.initMessage, nil\n}\n\n// Add metadata fields to data\nfunc (conn *dpdkConnector) addMetadataFields(metadataFields []string, data map[string]interface{}) {\n\tif conn.initMessage == nil {\n\t\treturn\n\t}\n\n\tfor _, field := range metadataFields {\n\t\tswitch field {\n\t\tcase dpdkMetadataFieldPidName:\n\t\t\tdata[dpdkMetadataFieldPidName] = conn.initMessage.Pid\n\t\tcase dpdkMetadataFieldVersionName:\n\t\t\tdata[dpdkMetadataFieldVersionName] = conn.initMessage.Version\n\t\t}\n\t}\n}\n\n// Fetches all identifiers of devices and then creates all possible combinations of commands for each device\nfunc (conn *dpdkConnector) appendCommandsWithParamsFromList(listCommand string, commands []string) ([]string, error) {\n\tresponse, err := conn.getCommandResponse(listCommand)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparams, err := jsonToArray(response, listCommand)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]string, 0, len(commands)*len(params))\n\tfor _, command := range commands {\n\t\tfor _, param := range params {\n\t\t\tresult = append(result, commandWithParams(command, param))\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\n// Executes command using provided connection and returns response\n// If error (such as timeout) occurred, then connection is discarded and recreated\n// because otherwise behavior of connection is undefined (e.g. it could return result of timed out command instead of latest)\nfunc (conn *dpdkConnector) getCommandResponse(fullCommand string) ([]byte, error) {\n\tconnection, err := conn.getConnection()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get connection to execute %q command: %w\", fullCommand, err)\n\t}\n\n\terr = conn.setTimeout()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to set timeout for %q command: %w\", fullCommand, err)\n\t}\n\n\t_, err = connection.Write([]byte(fullCommand))\n\tif err != nil {\n\t\tif closeErr := conn.tryClose(); closeErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to send %q command: %w and failed to close connection: %w\", fullCommand, err, closeErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to send %q command: %w\", fullCommand, err)\n\t}\n\n\tbuf := make([]byte, conn.initMessage.MaxOutputLen)\n\tmessageLength, err := connection.Read(buf)\n\tif err != nil {\n\t\tif closeErr := conn.tryClose(); closeErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed read response of %q command: %w and failed to close connection: %w\", fullCommand, err, closeErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to read response of %q command: %w\", fullCommand, err)\n\t}\n\n\tif messageLength == 0 {\n\t\treturn nil, fmt.Errorf(\"got empty response during execution of %q command\", fullCommand)\n\t}\n\treturn buf[:messageLength], nil\n}\n\n// Executes command, parses response and creates/writes metrics from response to accumulator\nfunc (conn *dpdkConnector) processCommand(acc telegraf.Accumulator, log telegraf.Logger, commandWithParams string, metadataFields []string) {\n\tbuf, err := conn.getCommandResponse(commandWithParams)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tvar parsedResponse map[string]interface{}\n\terr = json.Unmarshal(buf, &parsedResponse)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"failed to unmarshal json response from %q command: %w\", commandWithParams, err))\n\t\treturn\n\t}\n\n\tcommand := stripParams(commandWithParams)\n\tvalue := parsedResponse[command]\n\tif isEmpty(value) {\n\t\tlog.Warnf(\"got empty json on %q command\", commandWithParams)\n\t\treturn\n\t}\n\n\tjf := parsers_json.JSONFlattener{}\n\terr = jf.FullFlattenJSON(\"\", value, true, true)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"failed to flatten response: %w\", err))\n\t\treturn\n\t}\n\n\terr = processCommandResponse(command, jf.Fields)\n\tif err != nil {\n\t\tlog.Warnf(\"Failed to process a response of the command: %s. Error: %v. Continue to handle data\", command, err)\n\t}\n\n\t// Add metadata fields if required\n\tconn.addMetadataFields(metadataFields, jf.Fields)\n\n\t// Add common fields\n\tacc.AddFields(pluginName, jf.Fields, map[string]string{\n\t\t\"command\": command,\n\t\t\"params\":  getParams(commandWithParams),\n\t})\n}\n\nfunc (conn *dpdkConnector) tryClose() error {\n\tif conn.connection == nil {\n\t\treturn nil\n\t}\n\n\terr := conn.connection.Close()\n\tconn.connection = nil\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (conn *dpdkConnector) setTimeout() error {\n\tif conn.connection == nil {\n\t\treturn errors.New(\"connection had not been established before\")\n\t}\n\n\tif conn.accessTimeout == 0 {\n\t\treturn conn.connection.SetDeadline(time.Time{})\n\t}\n\treturn conn.connection.SetDeadline(time.Now().Add(conn.accessTimeout))\n}\n\n// Returns connections, if connection is not created then function tries to recreate it\nfunc (conn *dpdkConnector) getConnection() (net.Conn, error) {\n\tif conn.connection == nil {\n\t\t_, err := conn.connect()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn conn.connection, nil\n}\n\n// Reads InitMessage for connection. Should be read for each connection, otherwise InitMessage is returned as response for first command.\nfunc (conn *dpdkConnector) readInitMessage() (*initMessage, error) {\n\tbuf := make([]byte, maxInitMessageLength)\n\terr := conn.setTimeout()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to set timeout: %w\", err)\n\t}\n\n\tmessageLength, err := conn.connection.Read(buf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read InitMessage: %w\", err)\n\t}\n\n\tvar connectionInitMessage initMessage\n\terr = json.Unmarshal(buf[:messageLength], &connectionInitMessage)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n\t}\n\n\tif connectionInitMessage.MaxOutputLen == 0 {\n\t\treturn nil, errors.New(\"failed to read maxOutputLen information\")\n\t}\n\n\treturn &connectionInitMessage, nil\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_connector_test.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/dpdk/mocks\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_readMaxOutputLen(t *testing.T) {\n\tt.Run(\"should return error if timeout occurred\", func(t *testing.T) {\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Read\", mock.Anything).Return(0, errors.New(\"timeout\"))\n\t\tconn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tconnector := dpdkConnector{connection: conn}\n\n\t\tinitMessage, err := connector.readInitMessage()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"timeout\")\n\t\trequire.Empty(t, initMessage)\n\t})\n\n\tt.Run(\"should pass and set maxOutputLen if provided with valid InitMessage\", func(t *testing.T) {\n\t\tmaxOutputLen := uint32(4567)\n\t\tinitMessage := initMessage{\n\t\t\tVersion:      \"DPDK test version\",\n\t\t\tPid:          1234,\n\t\t\tMaxOutputLen: maxOutputLen,\n\t\t}\n\t\tmessage, err := json.Marshal(initMessage)\n\t\trequire.NoError(t, err)\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, message)\n\t\t}).Return(len(message), nil)\n\t\tconn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tconnector := dpdkConnector{connection: conn}\n\n\t\tinitMsg, err := connector.readInitMessage()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, maxOutputLen, initMsg.MaxOutputLen)\n\t})\n\n\tt.Run(\"should fail if received invalid json\", func(t *testing.T) {\n\t\tmessage := `{notAJson}`\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, message)\n\t\t}).Return(len(message), nil)\n\t\tconn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tconnector := dpdkConnector{connection: conn}\n\n\t\t_, err := connector.readInitMessage()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"looking for beginning of object key string\")\n\t})\n\n\tt.Run(\"should fail if received maxOutputLen equals to 0\", func(t *testing.T) {\n\t\tmessage, err := json.Marshal(initMessage{\n\t\t\tVersion:      \"test\",\n\t\t\tPid:          1,\n\t\t\tMaxOutputLen: 0,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, message)\n\t\t}).Return(len(message), nil)\n\t\tconn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tconnector := dpdkConnector{connection: conn}\n\n\t\t_, err = connector.readInitMessage()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to read maxOutputLen information\")\n\t})\n}\n\nfunc Test_connect(t *testing.T) {\n\tt.Run(\"should pass if PathToSocket points to socket\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath: pathToSocket,\n\t\t\tconnectors: []*dpdkConnector{newDpdkConnector(pathToSocket, 0)},\n\t\t}\n\t\tgo simulateSocketResponse(socket, t)\n\n\t\t_, err := dpdk.connectors[0].connect()\n\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc Test_getCommandResponse(t *testing.T) {\n\tcommand := \"/\"\n\tresponse := \"myResponseString\"\n\n\tt.Run(\"should return proper buffer size and value if no error occurred\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\tfor _, connector := range dpdk.connectors {\n\t\t\tbuf, err := connector.getCommandResponse(command)\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, buf, len(response))\n\t\t\trequire.Equal(t, response, string(buf))\n\t\t}\n\t})\n\n\tt.Run(\"should return error if failed to get connection handler\", func(t *testing.T) {\n\t\t_, dpdk, _ := prepareEnvironment()\n\t\tdpdk.connectors[0].connection = nil\n\n\t\tbuf, err := dpdk.connectors[0].getCommandResponse(command)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to get connection to execute \\\"/\\\" command\")\n\t\trequire.Empty(t, buf)\n\t})\n\n\tt.Run(\"should return error if failed to set timeout duration\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tmockConn.On(\"SetDeadline\", mock.Anything).Return(errors.New(\"deadline error\"))\n\n\t\tbuf, err := dpdk.connectors[0].getCommandResponse(command)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"deadline error\")\n\t\trequire.Empty(t, buf)\n\t})\n\n\tt.Run(\"should return error if timeout occurred during Write operation\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, errors.New(\"write timeout\"))\n\t\tmockConn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tmockConn.On(\"Close\").Return(nil)\n\n\t\tbuf, err := dpdk.connectors[0].getCommandResponse(command)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"write timeout\")\n\t\trequire.Empty(t, buf)\n\t})\n\n\tt.Run(\"should return error if timeout occurred during Read operation\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tsimulateResponse(mockConn, \"\", errors.New(\"read timeout\"))\n\n\t\tbuf, err := dpdk.connectors[0].getCommandResponse(command)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"read timeout\")\n\t\trequire.Empty(t, buf)\n\t})\n\n\tt.Run(\"should return error if got empty response\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tsimulateResponse(mockConn, \"\", nil)\n\n\t\tbuf, err := dpdk.connectors[0].getCommandResponse(command)\n\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, buf)\n\t\trequire.Contains(t, err.Error(), \"got empty response during execution of\")\n\t})\n}\n\nfunc Test_processCommand(t *testing.T) {\n\tt.Run(\"should pass if received valid response\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := `{\"/\": [\"/\", \"/eal/app_params\", \"/eal/params\", \"/ethdev/link_status, /ethdev/info\"]}`\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\tfor _, dpdkConn := range dpdk.connectors {\n\t\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, \"/\", nil)\n\t\t}\n\n\t\trequire.Empty(t, mockAcc.Errors)\n\t})\n\n\tt.Run(\"if received a non-JSON object then should return error\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := `notAJson`\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\tfor _, dpdkConn := range dpdk.connectors {\n\t\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, \"/\", nil)\n\t\t}\n\n\t\trequire.Len(t, mockAcc.Errors, 1)\n\t\trequire.Contains(t, mockAcc.Errors[0].Error(), \"invalid character\")\n\t})\n\n\tt.Run(\"if failed to get command response then accumulator should contain error\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, errors.New(\"deadline exceeded\"))\n\t\tmockConn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\t\tmockConn.On(\"Close\").Return(nil)\n\t\tfor _, dpdkConn := range dpdk.connectors {\n\t\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, \"/\", nil)\n\t\t}\n\n\t\trequire.Len(t, mockAcc.Errors, 1)\n\t\trequire.Contains(t, mockAcc.Errors[0].Error(), \"deadline exceeded\")\n\t})\n\n\tt.Run(\"if response contains nil or empty value then error shouldn't be returned in accumulator\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := `{\"/test\": null}`\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tfor _, dpdkConn := range dpdk.connectors {\n\t\t\tdpdkConn.processCommand(mockAcc, testutil.Logger{}, \"/test,param\", nil)\n\t\t}\n\n\t\trequire.Empty(t, mockAcc.Errors)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage dpdk\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Dpdk struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Dpdk) SampleConfig() string { return sampleConfig }\n\nfunc (d *Dpdk) Init() error {\n\td.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Dpdk) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"dpdk\", func() telegraf.Input {\n\t\treturn &Dpdk{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_test.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/dpdk/mocks\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_Init(t *testing.T) {\n\tt.Run(\"when SocketPath field isn't set then it should be set to default value\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tLog:        testutil.Logger{},\n\t\t\tSocketPath: \"\",\n\t\t}\n\n\t\trequire.Empty(t, dpdk.SocketPath)\n\n\t\trequire.NoError(t, dpdk.Init())\n\n\t\trequire.Equal(t, defaultPathToSocket, dpdk.SocketPath)\n\t})\n\n\tt.Run(\"when Metadata Fields isn't set then it should be set to default value (dpdk_pid)\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tLog: testutil.Logger{},\n\t\t}\n\t\trequire.Nil(t, dpdk.MetadataFields)\n\n\t\trequire.NoError(t, dpdk.Init())\n\t\trequire.Equal(t, []string{dpdkMetadataFieldPidName, dpdkMetadataFieldVersionName}, dpdk.MetadataFields)\n\t})\n\n\tt.Run(\"when PluginOptions field isn't set then it should be set to default value (in_memory)\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tLog: testutil.Logger{},\n\t\t}\n\t\trequire.Nil(t, dpdk.PluginOptions)\n\n\t\trequire.NoError(t, dpdk.Init())\n\t\trequire.Equal(t, []string{dpdkPluginOptionInMemory}, dpdk.PluginOptions)\n\t})\n\n\tt.Run(\"when commands are in invalid format (doesn't start with '/') then error should be returned\", func(t *testing.T) {\n\t\tpathToSocket, _ := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tLog:                testutil.Logger{},\n\t\t\tSocketPath:         pathToSocket,\n\t\t\tAdditionalCommands: []string{\"invalid\"},\n\t\t}\n\n\t\terr := dpdk.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"command should start with slash\")\n\t})\n\n\tt.Run(\"when AccessTime is < 0 then error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tLog:           testutil.Logger{},\n\t\t\tAccessTimeout: -1,\n\t\t}\n\t\terr := dpdk.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"socket_access_timeout should be positive number\")\n\t})\n\n\tt.Run(\"when device_types and additional_commands are empty, then error should be returned\", func(t *testing.T) {\n\t\tpathToSocket, _ := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:  pathToSocket,\n\t\t\tDeviceTypes: make([]string, 0),\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\n\t\terr := dpdk.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"plugin was configured with nothing to read\")\n\t})\n\n\tt.Run(\"when UnreachableSocketBehavior specified with unknown value - err should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tDeviceTypes:               []string{\"ethdev\"},\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: \"whatisthat\",\n\t\t}\n\t\terr := dpdk.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"unreachable_socket_behavior\")\n\t})\n}\n\nfunc Test_Start(t *testing.T) {\n\tt.Run(\"when socket doesn't exist err should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tDeviceTypes: []string{\"ethdev\"},\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\t\terr := dpdk.Init()\n\t\trequire.NoError(t, err)\n\n\t\terr = dpdk.Start(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"no active sockets connections present\")\n\t})\n\n\tt.Run(\"when socket doesn't exist, but UnreachableSocketBehavior is Ignore err shouldn't be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tDeviceTypes:               []string{\"ethdev\"},\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: unreachableSocketBehaviorIgnore,\n\t\t}\n\t\terr := dpdk.Init()\n\t\trequire.NoError(t, err)\n\n\t\terr = dpdk.Start(nil)\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"when all values are valid, then no error should be returned\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:  pathToSocket,\n\t\t\tDeviceTypes: []string{\"ethdev\"},\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\t\terr := dpdk.Init()\n\t\trequire.NoError(t, err)\n\n\t\tgo simulateSocketResponse(socket, t)\n\n\t\terr = dpdk.Start(nil)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestMaintainConnections(t *testing.T) {\n\tt.Run(\"maintainConnections should return the error if socket doesn't exist\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:                \"/tmp/justrandompath\",\n\t\t\tDeviceTypes:               []string{\"ethdev\"},\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: unreachableSocketBehaviorError,\n\t\t}\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr := dpdk.maintainConnections()\n\t\tdefer dpdk.Stop()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"couldn't connect to socket\")\n\t})\n\n\tt.Run(\"maintainConnections should return the error if socket not found with dpdkPluginOptionInMemory\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:                defaultPathToSocket,\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tPluginOptions:             []string{dpdkPluginOptionInMemory},\n\t\t\tUnreachableSocketBehavior: unreachableSocketBehaviorError,\n\t\t}\n\t\tvar err error\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr = dpdk.maintainConnections()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"no active sockets connections present\")\n\t})\n\n\tt.Run(\"maintainConnections shouldn't return error with 1 socket\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:  pathToSocket,\n\t\t\tDeviceTypes: []string{\"ethdev\"},\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\n\t\tgo simulateSocketResponse(socket, t)\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr := dpdk.maintainConnections()\n\t\tdefer dpdk.Stop()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 1)\n\t})\n\n\tt.Run(\"maintainConnections shouldn't return error with multiple sockets\", func(t *testing.T) {\n\t\tnumSockets := rand.Intn(5) + 1\n\n\t\tpathToSockets, sockets := createMultipleSocketsForTest(t, numSockets, \"\")\n\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:    pathToSockets[0],\n\t\t\tDeviceTypes:   []string{\"ethdev\"},\n\t\t\tLog:           testutil.Logger{},\n\t\t\tPluginOptions: []string{dpdkPluginOptionInMemory},\n\t\t}\n\t\tvar err error\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\tfor _, socket := range sockets {\n\t\t\tgo simulateSocketResponse(socket, t)\n\t\t}\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr = dpdk.maintainConnections()\n\t\tdefer dpdk.Stop()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, numSockets)\n\t})\n\n\tt.Run(\"Test maintainConnections without dpdkPluginOptionInMemory option\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:  pathToSocket,\n\t\t\tDeviceTypes: []string{\"ethdev\"},\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\n\t\tgo simulateSocketResponse(socket, t)\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr := dpdk.maintainConnections()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 1)\n\n\t\tdpdk.Stop()\n\t\trequire.Empty(t, dpdk.connectors)\n\t})\n\n\tt.Run(\"Test maintainConnections with dpdkPluginOptionInMemory option\", func(t *testing.T) {\n\t\tpathToSocket1, socket1 := createSocketForTest(t, \"\")\n\t\tgo simulateSocketResponse(socket1, t)\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:    pathToSocket1,\n\t\t\tDeviceTypes:   []string{\"ethdev\"},\n\t\t\tLog:           testutil.Logger{},\n\t\t\tPluginOptions: []string{dpdkPluginOptionInMemory},\n\t\t}\n\t\tvar err error\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr = dpdk.maintainConnections()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 1)\n\n\t\t// Adding 2 sockets more\n\t\tpathToSocket2, socket2 := createSocketForTest(t, filepath.Dir(pathToSocket1))\n\t\tpathToSocket3, socket3 := createSocketForTest(t, filepath.Dir(pathToSocket1))\n\t\trequire.NotEqual(t, pathToSocket2, pathToSocket3)\n\t\tgo simulateSocketResponse(socket2, t)\n\t\tgo simulateSocketResponse(socket3, t)\n\t\terr = dpdk.maintainConnections()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 3)\n\n\t\t// Close 2 new sockets\n\t\tsocket2.Close()\n\t\tsocket3.Close()\n\t\terr = dpdk.maintainConnections()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 1)\n\t\trequire.Equal(t, pathToSocket1, dpdk.connectors[0].pathToSocket)\n\n\t\tdpdk.Stop()\n\t\trequire.Empty(t, dpdk.connectors)\n\t})\n}\n\nfunc TestClose(t *testing.T) {\n\tt.Run(\"Num of connections should be 0 after Stop func\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath:  pathToSocket,\n\t\t\tDeviceTypes: []string{\"ethdev\"},\n\t\t\tLog:         testutil.Logger{},\n\t\t}\n\n\t\tgo simulateSocketResponse(socket, t)\n\n\t\trequire.Empty(t, dpdk.connectors)\n\t\terr := dpdk.maintainConnections()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, dpdk.connectors, 1)\n\n\t\tdpdk.Stop()\n\t\trequire.Empty(t, dpdk.connectors)\n\t})\n}\n\nfunc Test_validateAdditionalCommands(t *testing.T) {\n\tt.Run(\"when validating commands in correct format then no error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\"/test\", \"/help\"},\n\t\t}\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"when validating command that doesn't begin with slash then error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\n\t\t\t\t\"/test\", \"commandWithoutSlash\",\n\t\t\t},\n\t\t}\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"command should start with slash\")\n\t})\n\n\tt.Run(\"when validating long command (without parameters) then error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\n\t\t\t\t\"/test\", \"/\" + strings.Repeat(\"a\", maxCommandLength),\n\t\t\t},\n\t\t}\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"command is too long\")\n\t})\n\n\tt.Run(\"when validating long command (with params) then error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\n\t\t\t\t\"/test\", \"/,\" + strings.Repeat(\"a\", maxCommandLengthWithParams),\n\t\t\t},\n\t\t}\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"shall be less than 1024 characters\")\n\t})\n\n\tt.Run(\"when validating empty command then error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\n\t\t\t\t\"/test\", \"\",\n\t\t\t},\n\t\t}\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"got empty command\")\n\t})\n\n\tt.Run(\"when validating commands with duplicates then duplicates should be removed and no error should be returned\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tAdditionalCommands: []string{\n\t\t\t\t\"/test\", \"/test\",\n\t\t\t},\n\t\t}\n\t\trequire.Len(t, dpdk.AdditionalCommands, 2)\n\n\t\terr := dpdk.validateAdditionalCommands()\n\n\t\trequire.Len(t, dpdk.AdditionalCommands, 1)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc prepareEnvironment() (*mocks.Conn, Dpdk, *testutil.Accumulator) {\n\tmockConnection := &mocks.Conn{}\n\tdpdk := Dpdk{\n\t\tconnectors: []*dpdkConnector{{\n\t\t\tconnection: mockConnection,\n\t\t\tinitMessage: &initMessage{\n\t\t\t\tVersion:      \"mockedDPDK\",\n\t\t\t\tPid:          1,\n\t\t\t\tMaxOutputLen: 1024,\n\t\t\t},\n\t\t\taccessTimeout: 2 * time.Second,\n\t\t}},\n\t\tLog: testutil.Logger{},\n\t}\n\tmockAcc := &testutil.Accumulator{}\n\treturn mockConnection, dpdk, mockAcc\n}\n\nfunc prepareEnvironmentWithMultiSockets() ([]*mocks.Conn, Dpdk, *testutil.Accumulator) {\n\tmockConnections := []*mocks.Conn{{}, {}}\n\tdpdk := Dpdk{\n\t\tconnectors: []*dpdkConnector{\n\t\t\t{\n\t\t\t\tconnection: mockConnections[0],\n\t\t\t\tinitMessage: &initMessage{\n\t\t\t\t\tVersion:      \"mockedDPDK\",\n\t\t\t\t\tPid:          1,\n\t\t\t\t\tMaxOutputLen: 1024,\n\t\t\t\t},\n\t\t\t\taccessTimeout: 2 * time.Second,\n\t\t\t},\n\t\t\t{\n\t\t\t\tconnection: mockConnections[1],\n\t\t\t\tinitMessage: &initMessage{\n\t\t\t\t\tVersion:      \"mockedDPDK\",\n\t\t\t\t\tPid:          2,\n\t\t\t\t\tMaxOutputLen: 1024,\n\t\t\t\t},\n\t\t\t\taccessTimeout: 2 * time.Second,\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\tmockAcc := &testutil.Accumulator{}\n\treturn mockConnections, dpdk, mockAcc\n}\n\nfunc prepareEnvironmentWithInitializedMessage(initMsg *initMessage) (*mocks.Conn, Dpdk, *testutil.Accumulator) {\n\tmockConnection := &mocks.Conn{}\n\tdpdk := Dpdk{\n\t\tconnectors: []*dpdkConnector{{\n\t\t\tconnection:    mockConnection,\n\t\t\taccessTimeout: 2 * time.Second,\n\t\t\tinitMessage:   initMsg,\n\t\t}},\n\t\tLog: testutil.Logger{},\n\t}\n\tmockAcc := &testutil.Accumulator{}\n\treturn mockConnection, dpdk, mockAcc\n}\n\nfunc Test_appendCommandsWithParams(t *testing.T) {\n\tt.Run(\"when got valid data, then valid commands with params should be created\", func(t *testing.T) {\n\t\tmockConn, dpdk, _ := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := `{\"/testendpoint\": [1,123]}`\n\t\tsimulateResponse(mockConn, response, nil)\n\t\texpectedCommands := []string{\"/action1,1\", \"/action1,123\", \"/action2,1\", \"/action2,123\"}\n\n\t\tfor _, dpdkConn := range dpdk.connectors {\n\t\t\tresult, err := dpdkConn.appendCommandsWithParamsFromList(\"/testendpoint\", []string{\"/action1\", \"/action2\"})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, result, 4)\n\t\t\trequire.ElementsMatch(t, result, expectedCommands)\n\t\t}\n\t})\n}\n\nfunc Test_getCommandsAndParamsCombinations(t *testing.T) {\n\tt.Run(\"when 2 ethdev commands are enabled, then 2*numberOfIds new commands should be appended\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q: [1, 123]}`, ethdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\texpectedCommands := []string{\"/ethdev/stats,1\", \"/ethdev/stats,123\", \"/ethdev/xstats,1\", \"/ethdev/xstats,123\"}\n\n\t\tdpdk.DeviceTypes = []string{\"ethdev\"}\n\t\tdpdk.ethdevCommands = []string{\"/ethdev/stats\", \"/ethdev/xstats\"}\n\t\tcommands := dpdk.gatherCommands(mockAcc, dpdk.connectors[0])\n\n\t\trequire.ElementsMatch(t, commands, expectedCommands)\n\t\trequire.Empty(t, mockAcc.Errors)\n\t})\n\n\tt.Run(\"when 1 rawdev command is enabled, then 2*numberOfIds new commands should be appended\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q: [1, 123]}`, rawdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\texpectedCommands := []string{\"/rawdev/xstats,1\", \"/rawdev/xstats,123\"}\n\n\t\tdpdk.DeviceTypes = []string{\"rawdev\"}\n\t\tdpdk.rawdevCommands = []string{\"/rawdev/xstats\"}\n\t\tcommands := dpdk.gatherCommands(mockAcc, dpdk.connectors[0])\n\n\t\trequire.ElementsMatch(t, commands, expectedCommands)\n\t\trequire.Empty(t, mockAcc.Errors)\n\t})\n\n\tt.Run(\"when 2 ethdev commands are enabled but one command is disabled, then numberOfIds new commands should be appended\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tresponse := fmt.Sprintf(`{%q: [1, 123]}`, ethdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\t\texpectedCommands := []string{\"/ethdev/stats,1\", \"/ethdev/stats,123\"}\n\n\t\tdpdk.DeviceTypes = []string{\"ethdev\"}\n\t\tdpdk.ethdevCommands = []string{\"/ethdev/stats\", \"/ethdev/xstats\"}\n\t\tvar err error\n\t\tdpdk.ethdevExcludedCommandsFilter, err = filter.Compile([]string{\"/ethdev/xstats\"})\n\t\trequire.NoError(t, err)\n\t\tcommands := dpdk.gatherCommands(mockAcc, dpdk.connectors[0])\n\n\t\trequire.ElementsMatch(t, commands, expectedCommands)\n\t\trequire.Empty(t, mockAcc.Errors)\n\t})\n\n\tt.Run(\"when ethdev commands are enabled but params fetching command returns error then error should be logged in accumulator\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tsimulateResponse(mockConn, `{notAJson}`, errors.New(\"some error\"))\n\n\t\tdpdk.DeviceTypes = []string{\"ethdev\"}\n\t\tdpdk.ethdevCommands = []string{\"/ethdev/stats\", \"/ethdev/xstats\"}\n\t\tcommands := dpdk.gatherCommands(mockAcc, dpdk.connectors[0])\n\n\t\trequire.Empty(t, commands)\n\t\trequire.Len(t, mockAcc.Errors, 1)\n\t})\n}\n\nfunc Test_getDpdkInMemorySocketPaths(t *testing.T) {\n\tvar err error\n\n\tt.Run(\"Should return nil if path doesn't exist\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath: \"/tmp/nothing-should-exist-here/test.socket\",\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\tsocketsPaths := dpdk.getDpdkInMemorySocketPaths()\n\t\trequire.Nil(t, socketsPaths)\n\t})\n\n\tt.Run(\"Should return nil if can't read the dir\", func(t *testing.T) {\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath: \"/root/no_access\",\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\tsocketsPaths := dpdk.getDpdkInMemorySocketPaths()\n\t\trequire.Nil(t, socketsPaths)\n\t})\n\n\tt.Run(\"Should return one socket from socket path\", func(t *testing.T) {\n\t\tsocketPath, _ := createSocketForTest(t, \"\")\n\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath: socketPath,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\tsocketsPaths := dpdk.getDpdkInMemorySocketPaths()\n\t\trequire.Len(t, socketsPaths, 1)\n\t\trequire.Equal(t, socketPath, socketsPaths[0])\n\t})\n\n\tt.Run(\"Should return 2 sockets from socket path\", func(t *testing.T) {\n\t\tsocketPaths, _ := createMultipleSocketsForTest(t, 2, \"\")\n\n\t\tdpdk := Dpdk{\n\t\t\tSocketPath: socketPaths[0],\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tdpdk.socketGlobPath, err = prepareGlob(dpdk.SocketPath)\n\t\trequire.NoError(t, err)\n\n\t\tsocketsPathsFromFunc := dpdk.getDpdkInMemorySocketPaths()\n\t\trequire.Len(t, socketsPathsFromFunc, 2)\n\t\trequire.Equal(t, socketPaths, socketsPathsFromFunc)\n\t})\n}\n\nfunc Test_Gather(t *testing.T) {\n\tt.Run(\"Gather should return error, because socket weren't created\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tdpdk := Dpdk{\n\t\t\tLog:           testutil.Logger{},\n\t\t\tPluginOptions: make([]string, 0),\n\t\t}\n\n\t\trequire.NoError(t, dpdk.Init())\n\n\t\terr := dpdk.Gather(mockAcc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"couldn't connect to socket\")\n\t})\n\n\tt.Run(\"Gather shouldn't return error with UnreachableSocketBehavior: Ignore option, because socket weren't created\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tdpdk := Dpdk{\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: unreachableSocketBehaviorIgnore,\n\t\t}\n\t\trequire.NoError(t, dpdk.Init())\n\n\t\terr := dpdk.Gather(mockAcc)\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"When parsing a plain json without nested object, then its key should be equal to \\\"\\\"\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\t\tsimulateResponse(mockConn, `{\"/endpoint1\":\"myvalue\"}`, nil)\n\n\t\terr := dpdk.Gather(mockAcc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\": \"myvalue\",\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"When parsing a list of value in nested object then list should be flattened\", func(t *testing.T) {\n\t\tmockConn, dpdk, mockAcc := prepareEnvironment()\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\t\tsimulateResponse(mockConn, `{\"/endpoint1\":{\"myvalue\":[0,1,123]}}`, nil)\n\n\t\terr := dpdk.Gather(mockAcc)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"myvalue_0\": float64(0),\n\t\t\t\t\t\"myvalue_1\": float64(1),\n\t\t\t\t\t\"myvalue_2\": float64(123),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"Test Gather with Metadata Fields dpdk pid and version\", func(t *testing.T) {\n\t\ttestInitMessage := &initMessage{\n\t\t\tPid:          100,\n\t\t\tVersion:      \"DPDK 21.11.11\",\n\t\t\tMaxOutputLen: 1024,\n\t\t}\n\t\tmockConn, dpdk, mockAcc := prepareEnvironmentWithInitializedMessage(testInitMessage)\n\t\tdpdk.MetadataFields = []string{dpdkMetadataFieldPidName, dpdkMetadataFieldVersionName}\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\t\tsimulateResponse(mockConn, `{\"/endpoint1\":\"myvalue\"}`, nil)\n\n\t\terr := dpdk.Gather(mockAcc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\":                           \"myvalue\",\n\t\t\t\t\tdpdkMetadataFieldPidName:     testInitMessage.Pid,\n\t\t\t\t\tdpdkMetadataFieldVersionName: testInitMessage.Version,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"Test Gather with Metadata Fields dpdk_pid\", func(t *testing.T) {\n\t\ttestInitMessage := &initMessage{\n\t\t\tPid:          100,\n\t\t\tVersion:      \"DPDK 21.11.11\",\n\t\t\tMaxOutputLen: 1024,\n\t\t}\n\t\tmockConn, dpdk, mockAcc := prepareEnvironmentWithInitializedMessage(testInitMessage)\n\t\tdpdk.MetadataFields = []string{dpdkMetadataFieldPidName}\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\t\tsimulateResponse(mockConn, `{\"/endpoint1\":\"myvalue\"}`, nil)\n\n\t\terr := dpdk.Gather(mockAcc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\":                       \"myvalue\",\n\t\t\t\t\tdpdkMetadataFieldPidName: testInitMessage.Pid,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"Test Gather without Metadata Fields\", func(t *testing.T) {\n\t\ttestInitMessage := &initMessage{\n\t\t\tPid:          100,\n\t\t\tVersion:      \"DPDK 21.11.11\",\n\t\t\tMaxOutputLen: 1024,\n\t\t}\n\t\tmockConn, dpdk, mockAcc := prepareEnvironmentWithInitializedMessage(testInitMessage)\n\t\tdefer mockConn.AssertExpectations(t)\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\t\tsimulateResponse(mockConn, `{\"/endpoint1\":\"myvalue\"}`, nil)\n\n\t\terr := dpdk.Gather(mockAcc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\": \"myvalue\",\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n}\n\nfunc Test_Gather_MultiSocket(t *testing.T) {\n\tt.Run(\"Test Gather without Metadata Fields\", func(t *testing.T) {\n\t\tmockConns, dpdk, mockAcc := prepareEnvironmentWithMultiSockets()\n\t\tdefer func() {\n\t\t\tfor _, mockConn := range mockConns {\n\t\t\t\tmockConn.AssertExpectations(t)\n\t\t\t}\n\t\t}()\n\t\tdpdk.AdditionalCommands = []string{\"/endpoint1\"}\n\n\t\tfor _, mockConn := range mockConns {\n\t\t\tsimulateResponse(mockConn, `{\"/endpoint1\":\"myvalue\"}`, nil)\n\t\t}\n\n\t\terr := dpdk.Gather(mockAcc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, mockAcc.Errors)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\": \"myvalue\",\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"dpdk\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/endpoint1\",\n\t\t\t\t\t\"params\":  \"\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"\": \"myvalue\",\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t})\n}\n\nfunc simulateResponse(mockConn *mocks.Conn, response string, readErr error) {\n\tmockConn.On(\"Write\", mock.Anything).Return(0, nil)\n\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\telem := arg.Get(0).([]byte)\n\t\tcopy(elem, response)\n\t}).Return(len(response), readErr)\n\tmockConn.On(\"SetDeadline\", mock.Anything).Return(nil)\n\n\tif readErr != nil {\n\t\tmockConn.On(\"Close\").Return(nil)\n\t}\n}\n\nfunc createSocketForTest(t *testing.T, dirPath string) (string, net.Listener) {\n\tvar err error\n\tvar pathToSocket string\n\n\tif len(dirPath) == 0 {\n\t\t// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases\n\t\t// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.\n\t\t//nolint:usetesting // Ignore \"os.MkdirTemp() could be replaced by t.TempDir() in createSocketForTest\" finding.\n\t\tdirPath, err = os.MkdirTemp(\"\", \"dpdk-test-socket\")\n\t\trequire.NoError(t, err)\n\t\tpathToSocket = filepath.Join(dirPath, dpdkSocketTemplateName)\n\t} else {\n\t\t// Create a socket in provided dirPath without duplication (similar to os.CreateTemp without creating a file)\n\t\ttry := 1\n\t\tfor {\n\t\t\tpathToSocket = fmt.Sprintf(\"%s:%d\", filepath.Join(dirPath, dpdkSocketTemplateName), try)\n\t\t\tif _, err = os.Stat(pathToSocket); err == nil {\n\t\t\t\tif try++; try < 1000 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tt.Fatalf(\"Can't create a temporary file for socket\")\n\t\t\t}\n\t\t\trequire.ErrorIs(t, err, os.ErrNotExist)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsocket, err := net.Listen(\"unixpacket\", pathToSocket)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\tsocket.Close()\n\t\tos.RemoveAll(dirPath)\n\t})\n\n\treturn pathToSocket, socket\n}\n\nfunc createMultipleSocketsForTest(t *testing.T, numSockets int, dirPath string) (socketsPaths []string, sockets []net.Listener) {\n\tfor i := 0; i < numSockets; i++ {\n\t\tpathToSocket, socket := createSocketForTest(t, dirPath)\n\t\tdirPath = filepath.Dir(pathToSocket)\n\t\tsocketsPaths = append(socketsPaths, pathToSocket)\n\t\tsockets = append(sockets, socket)\n\t}\n\treturn socketsPaths, sockets\n}\n\nfunc simulateSocketResponse(socket net.Listener, t *testing.T) {\n\tconn, err := socket.Accept()\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tinitMessage, err := json.Marshal(initMessage{MaxOutputLen: 1})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif _, err = conn.Write(initMessage); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc prepareGlob(path string) (*globpath.GlobPath, error) {\n\treturn globpath.Compile(path + \"*\")\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_utils.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf/filter\"\n)\n\nfunc commandWithParams(command, params string) string {\n\tif params != \"\" {\n\t\treturn command + \",\" + params\n\t}\n\treturn command\n}\n\nfunc stripParams(command string) string {\n\tindex := strings.IndexRune(command, ',')\n\tif index == -1 {\n\t\treturn command\n\t}\n\treturn command[:index]\n}\n\n// Since DPDK is an open-source project, developers can use their own format of params\n// so it could \"/command,1,3,5,123\" or \"/command,userId=1, count=1234\".\n// To avoid issues with different formats of params, all params are returned as single string\nfunc getParams(command string) string {\n\tindex := strings.IndexRune(command, ',')\n\tif index == -1 {\n\t\treturn \"\"\n\t}\n\treturn command[index+1:]\n}\n\n// Checks if the provided filePath contains in-memory socket\nfunc isInMemorySocketPath(filePath, socketPath string) bool {\n\tif filePath == socketPath {\n\t\treturn true\n\t}\n\n\tsocketPathPrefix := socketPath + \":\"\n\tif strings.HasPrefix(filePath, socketPathPrefix) {\n\t\tsuffix := filePath[len(socketPathPrefix):]\n\t\tif number, err := strconv.Atoi(suffix); err == nil {\n\t\t\tif number > 0 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Checks if provided path points to socket\nfunc isSocket(path string) error {\n\tpathInfo, err := os.Lstat(path)\n\tif os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"provided path does not exist: %q\", path)\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get system information of %q file: %w\", path, err)\n\t}\n\n\tif pathInfo.Mode()&os.ModeSocket != os.ModeSocket {\n\t\treturn fmt.Errorf(\"provided path does not point to a socket file: %q\", path)\n\t}\n\n\treturn nil\n}\n\n// Converts JSON array containing devices identifiers from DPDK response to string slice\nfunc jsonToArray(input []byte, command string) ([]string, error) {\n\tif len(input) == 0 {\n\t\treturn nil, errors.New(\"got empty object instead of json\")\n\t}\n\n\tvar rawMessage map[string]json.RawMessage\n\terr := json.Unmarshal(input, &rawMessage)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar intArray []int64\n\terr = json.Unmarshal(rawMessage[command], &intArray)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal json response: %w\", err)\n\t}\n\n\tstringArray := make([]string, 0, len(intArray))\n\tfor _, value := range intArray {\n\t\tstringArray = append(stringArray, strconv.FormatInt(value, 10))\n\t}\n\n\treturn stringArray, nil\n}\n\nfunc removeSubset(elements []string, excludedFilter filter.Filter) []string {\n\tif excludedFilter == nil {\n\t\treturn elements\n\t}\n\n\tvar result []string\n\tfor _, element := range elements {\n\t\tif !excludedFilter.Match(element) {\n\t\t\tresult = append(result, element)\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc uniqueValues(values []string) []string {\n\tin := make(map[string]bool)\n\tresult := make([]string, 0, len(values))\n\n\tfor _, value := range values {\n\t\tif !in[value] {\n\t\t\tin[value] = true\n\t\t\tresult = append(result, value)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc isEmpty(value interface{}) bool {\n\treturn value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil())\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/dpdk_utils_test.go",
    "content": "//go:build linux\n\npackage dpdk\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_isSocket(t *testing.T) {\n\tt.Run(\"when path points to non-existing file then error should be returned\", func(t *testing.T) {\n\t\terr := isSocket(\"/tmp/file-that-doesnt-exists\")\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided path does not exist\")\n\t})\n\n\tt.Run(\"Should pass if path points to socket\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t, \"\")\n\t\tdefer socket.Close()\n\n\t\terr := isSocket(pathToSocket)\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"if path points to regular file instead of socket then error should be returned\", func(t *testing.T) {\n\t\tpathToFile := \"/tmp/dpdk-text-file.txt\"\n\t\t_, err := os.Create(pathToFile)\n\t\trequire.NoError(t, err)\n\t\tdefer os.Remove(pathToFile)\n\n\t\terr = isSocket(pathToFile)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided path does not point to a socket file\")\n\t})\n}\n\nfunc Test_stripParams(t *testing.T) {\n\tcommand := \"/mycommand\"\n\tparams := \"myParams\"\n\tt.Run(\"when passed string without params then passed string should be returned\", func(t *testing.T) {\n\t\tstrippedCommand := stripParams(command)\n\n\t\trequire.Equal(t, command, strippedCommand)\n\t})\n\n\tt.Run(\"when passed string with params then string without params should be returned\", func(t *testing.T) {\n\t\tstrippedCommand := stripParams(commandWithParams(command, params))\n\n\t\trequire.Equal(t, command, strippedCommand)\n\t})\n}\n\nfunc Test_commandWithParams(t *testing.T) {\n\tcommand := \"/mycommand\"\n\tparams := \"myParams\"\n\tt.Run(\"when passed string with params then command with comma should be returned\", func(t *testing.T) {\n\t\tcommandWithParams := commandWithParams(command, params)\n\n\t\trequire.Equal(t, command+\",\"+params, commandWithParams)\n\t})\n\n\tt.Run(\"when passed command with no params then command should be returned\", func(t *testing.T) {\n\t\tcommandWithParams := commandWithParams(command, \"\")\n\n\t\trequire.Equal(t, command, commandWithParams)\n\t})\n}\n\nfunc Test_getParams(t *testing.T) {\n\tcommand := \"/mycommand\"\n\tparams := \"myParams\"\n\tt.Run(\"when passed string with params then command with comma should be returned\", func(t *testing.T) {\n\t\tcommandParams := getParams(commandWithParams(command, params))\n\n\t\trequire.Equal(t, params, commandParams)\n\t})\n\n\tt.Run(\"when passed command with no params then empty string (representing empty params) should be returned\", func(t *testing.T) {\n\t\tcommandParams := getParams(commandWithParams(command, \"\"))\n\n\t\trequire.Empty(t, commandParams)\n\t})\n}\n\nfunc Test_jsonToArray(t *testing.T) {\n\tkey := \"/ethdev/list\"\n\tt.Run(\"when got numeric array then string array should be returned\", func(t *testing.T) {\n\t\tfirstValue := int64(0)\n\t\tsecondValue := int64(1)\n\t\tjsonString := fmt.Sprintf(`{%q: [%d, %d]}`, key, firstValue, secondValue)\n\n\t\tarr, err := jsonToArray([]byte(jsonString), key)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, strconv.FormatInt(firstValue, 10), arr[0])\n\t\trequire.Equal(t, strconv.FormatInt(secondValue, 10), arr[1])\n\t})\n\n\tt.Run(\"if non-json string is supplied as input then error should be returned\", func(t *testing.T) {\n\t\t_, err := jsonToArray([]byte(\"{notAJson}\"), key)\n\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"when empty string is supplied as input then error should be returned\", func(t *testing.T) {\n\t\tjsonString := \"\"\n\n\t\t_, err := jsonToArray([]byte(jsonString), key)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"got empty object instead of json\")\n\t})\n\n\tt.Run(\"when valid json with json-object is supplied as input then error should be returned\", func(t *testing.T) {\n\t\tjsonString := fmt.Sprintf(`{%q: {\"testKey\": \"testValue\"}}`, key)\n\n\t\t_, err := jsonToArray([]byte(jsonString), key)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to unmarshal json response\")\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/mocks/conn.go",
    "content": "// Code generated by mockery v2.46.3. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tnet \"net\"\n\ttime \"time\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// Conn is an autogenerated mock type for the Conn type\ntype Conn struct {\n\tmock.Mock\n}\n\n// Close provides a mock function with given fields:\nfunc (_m *Conn) Close() error {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Close\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// LocalAddr provides a mock function with given fields:\nfunc (_m *Conn) LocalAddr() net.Addr {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for LocalAddr\")\n\t}\n\n\tvar r0 net.Addr\n\tif rf, ok := ret.Get(0).(func() net.Addr); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(net.Addr)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// Read provides a mock function with given fields: b\nfunc (_m *Conn) Read(b []byte) (int, error) {\n\tret := _m.Called(b)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Read\")\n\t}\n\n\tvar r0 int\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {\n\t\treturn rf(b)\n\t}\n\tif rf, ok := ret.Get(0).(func([]byte) int); ok {\n\t\tr0 = rf(b)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(b)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// RemoteAddr provides a mock function with given fields:\nfunc (_m *Conn) RemoteAddr() net.Addr {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for RemoteAddr\")\n\t}\n\n\tvar r0 net.Addr\n\tif rf, ok := ret.Get(0).(func() net.Addr); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(net.Addr)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// SetDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SetReadDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetReadDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetReadDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SetWriteDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetWriteDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetWriteDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Write provides a mock function with given fields: b\nfunc (_m *Conn) Write(b []byte) (int, error) {\n\tret := _m.Called(b)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Write\")\n\t}\n\n\tvar r0 int\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {\n\t\treturn rf(b)\n\t}\n\tif rf, ok := ret.Get(0).(func([]byte) int); ok {\n\t\tr0 = rf(b)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(b)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// NewConn creates a new instance of Conn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.\n// The first argument is typically a *testing.T value.\nfunc NewConn(t interface {\n\tmock.TestingT\n\tCleanup(func())\n}) *Conn {\n\tmock := &Conn{}\n\tmock.Mock.Test(t)\n\n\tt.Cleanup(func() { mock.AssertExpectations(t) })\n\n\treturn mock\n}\n"
  },
  {
    "path": "plugins/inputs/dpdk/sample.conf",
    "content": "# Reads metrics from DPDK applications using v2 telemetry interface.\n# This plugin ONLY supports Linux\n[[inputs.dpdk]]\n  ## Path to DPDK telemetry socket. This shall point to v2 version of DPDK\n  ## telemetry interface.\n  # socket_path = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\n  ## Duration that defines how long the connected socket client will wait for\n  ## a response before terminating connection.\n  ## This includes both writing to and reading from socket. Since it's local\n  ## socket access to a fast packet processing application, the timeout should\n  ## be sufficient for most users.\n  ## Setting the value to 0 disables the timeout (not recommended)\n  # socket_access_timeout = \"200ms\"\n\n  ## Enables telemetry data collection for selected device types.\n  ## Adding \"ethdev\" enables collection of telemetry from DPDK NICs (stats, xstats, link_status, info).\n  ## Adding \"rawdev\" enables collection of telemetry from DPDK Raw Devices (xstats).\n  # device_types = [\"ethdev\"]\n\n  ## List of custom, application-specific telemetry commands to query\n  ## The list of available commands depend on the application deployed.\n  ## Applications can register their own commands via telemetry library API\n  ## https://doc.dpdk.org/guides/prog_guide/telemetry_lib.html#registering-commands\n  ## For L3 Forwarding with Power Management Sample Application this could be:\n  ##   additional_commands = [\"/l3fwd-power/stats\"]\n  # additional_commands = []\n\n  ## List of plugin options.\n  ## Supported options:\n  ##  - \"in_memory\" option enables reading for multiple sockets when a dpdk application is running with --in-memory option.\n  ##    When option is enabled plugin will try to find additional socket paths related to provided socket_path.\n  ##    Details: https://doc.dpdk.org/guides/howto/telemetry.html#connecting-to-different-dpdk-processes\n  # plugin_options = [\"in_memory\"]\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error during the startup and gather phases if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n\n  ## List of metadata fields which will be added to every metric produced by the plugin.\n  ## Supported options:\n  ##  - \"pid\" - exposes PID of DPDK process. Example: pid=2179660i\n  ##  - \"version\" - exposes version of DPDK. Example: version=\"DPDK 21.11.2\"\n  # metadata_fields = [\"pid\", \"version\"]\n\n  ## Allows turning off collecting data for individual \"ethdev\" commands.\n  ## Remove \"/ethdev/link_status\" from list to gather link status metrics.\n  [inputs.dpdk.ethdev]\n    exclude_commands = [\"/ethdev/link_status\"]\n\n  ## When running multiple instances of the plugin it's recommended to add a\n  ## unique tag to each instance to identify metrics exposed by an instance\n  ## of DPDK application. This is useful when multiple DPDK apps run on a\n  ## single host.\n  ##  [inputs.dpdk.tags]\n  ##    dpdk_instance = \"my-fwd-app\"\n"
  },
  {
    "path": "plugins/inputs/ecs/README.md",
    "content": "# Amazon Elastic Container Service Input Plugin\n\nThis plugin gathers statistics on running containers in a Task from the\n[Amazon Elastic Container Service][ecs] using the [Amazon ECS metadata][metadata]\nand the [v2][v2_endpoint] or [v3][v3_endpoint] statistics API endpoints.\n\n> [!IMPORTANT]\n> The telegraf container must be run in the same Task as the workload it is\n> inspecting.\n\nThe amazon-ecs-agent (though it _is_ a container running on the host) is not\npresent in the metadata/stats endpoints.\n\n⭐ Telegraf v1.11.0\n🏷️ cloud\n💻 all\n\n[ecs]: https://aws.amazon.com/ecs/\n[metadata]: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint.html\n[v2_endpoint]: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v2.html\n[v3_endpoint]: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about ECS containers\n[[inputs.ecs]]\n  ## ECS metadata url.\n  ## Metadata v2 API is used if set explicitly. Otherwise,\n  ## v3 metadata endpoint API is used if available.\n  # endpoint_url = \"\"\n\n  ## Containers to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all containers\n  # container_name_include = []\n  # container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"RUNNING\" state will be captured.\n  ## Possible values are \"NONE\", \"PULLED\", \"CREATED\", \"RUNNING\",\n  ## \"RESOURCES_PROVISIONED\", \"STOPPED\".\n  # container_status_include = []\n  # container_status_exclude = []\n\n  ## ecs labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  ecs_label_include = [ \"com.amazonaws.ecs.*\" ]\n  ecs_label_exclude = []\n\n  ## Timeout for queries.\n  # timeout = \"5s\"\n```\n\n## Configuration (enforce v2 metadata)\n\n```toml\n# Read metrics about ECS containers\n[[inputs.ecs]]\n  ## ECS metadata url.\n  ## Metadata v2 API is used if set explicitly. Otherwise,\n  ## v3 metadata endpoint API is used if available.\n  endpoint_url = \"http://169.254.170.2\"\n\n  ## Containers to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all containers\n  # container_name_include = []\n  # container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"RUNNING\" state will be captured.\n  ## Possible values are \"NONE\", \"PULLED\", \"CREATED\", \"RUNNING\",\n  ## \"RESOURCES_PROVISIONED\", \"STOPPED\".\n  # container_status_include = []\n  # container_status_exclude = []\n\n  ## ecs labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  ecs_label_include = [ \"com.amazonaws.ecs.*\" ]\n  ecs_label_exclude = []\n\n  ## Timeout for queries.\n  # timeout = \"5s\"\n```\n\n## Metrics\n\n- ecs_task\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n  - fields:\n    - desired_status (string)\n    - known_status (string)\n    - limit_cpu (float)\n    - limit_mem (float)\n\n- ecs_container_mem\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n  - fields:\n    - container_id\n    - active_anon\n    - active_file\n    - cache\n    - hierarchical_memory_limit\n    - inactive_anon\n    - inactive_file\n    - mapped_file\n    - pgfault\n    - pgmajfault\n    - pgpgin\n    - pgpgout\n    - rss\n    - rss_huge\n    - total_active_anon\n    - total_active_file\n    - total_cache\n    - total_inactive_anon\n    - total_inactive_file\n    - total_mapped_file\n    - total_pgfault\n    - total_pgmajfault\n    - total_pgpgin\n    - total_pgpgout\n    - total_rss\n    - total_rss_huge\n    - total_unevictable\n    - total_writeback\n    - unevictable\n    - writeback\n    - fail_count\n    - limit\n    - max_usage\n    - usage\n    - usage_percent\n\n- ecs_container_cpu\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n    - cpu\n  - fields:\n    - container_id\n    - usage_total\n    - usage_in_usermode\n    - usage_in_kernelmode\n    - usage_system\n    - throttling_periods\n    - throttling_throttled_periods\n    - throttling_throttled_time\n    - usage_percent\n    - usage_total\n\n- ecs_container_net\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n    - network\n  - fields:\n    - container_id\n    - rx_packets\n    - rx_dropped\n    - rx_bytes\n    - rx_errors\n    - tx_packets\n    - tx_dropped\n    - tx_bytes\n    - tx_errors\n\n- ecs_container_blkio\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n    - device\n  - fields:\n    - container_id\n    - io_service_bytes_recursive_async\n    - io_service_bytes_recursive_read\n    - io_service_bytes_recursive_sync\n    - io_service_bytes_recursive_total\n    - io_service_bytes_recursive_write\n    - io_serviced_recursive_async\n    - io_serviced_recursive_read\n    - io_serviced_recursive_sync\n    - io_serviced_recursive_total\n    - io_serviced_recursive_write\n\n- ecs_container_meta\n  - tags:\n    - cluster\n    - task_arn\n    - family\n    - revision\n    - id\n    - name\n  - fields:\n    - container_id\n    - docker_name\n    - image\n    - image_id\n    - desired_status\n    - known_status\n    - limit_cpu\n    - limit_mem\n    - created_at\n    - started_at\n    - type\n\n## Example Output\n\n```text\necs_task,cluster=test,family=nginx,host=c4b301d4a123,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a desired_status=\"RUNNING\",known_status=\"RUNNING\",limit_cpu=0.5,limit_mem=512 1542641488000000000\necs_container_mem,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a active_anon=40960i,active_file=8192i,cache=790528i,pgpgin=1243i,total_pgfault=1298i,total_rss=40960i,limit=1033658368i,max_usage=4825088i,hierarchical_memory_limit=536870912i,rss=40960i,total_active_file=8192i,total_mapped_file=618496i,usage_percent=0.05349543109392212,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",pgfault=1298i,pgmajfault=6i,pgpgout=1040i,total_active_anon=40960i,total_inactive_file=782336i,total_pgpgin=1243i,usage=552960i,inactive_file=782336i,mapped_file=618496i,total_cache=790528i,total_pgpgout=1040i 1542642001000000000\necs_container_cpu,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,cpu=cpu-total,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a usage_in_kernelmode=0i,throttling_throttled_periods=0i,throttling_periods=0i,throttling_throttled_time=0i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",usage_percent=0,usage_total=26426156i,usage_in_usermode=20000000i,usage_system=2336100000000i 1542642001000000000\necs_container_cpu,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,cpu=cpu0,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",usage_total=26426156i 1542642001000000000\necs_container_net,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,network=eth0,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a rx_errors=0i,rx_packets=36i,tx_errors=0i,tx_bytes=648i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",rx_dropped=0i,rx_bytes=5338i,tx_packets=8i,tx_dropped=0i 1542642001000000000\necs_container_net,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,network=eth5,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a rx_errors=0i,tx_packets=9i,rx_packets=26i,tx_errors=0i,rx_bytes=4641i,tx_dropped=0i,tx_bytes=690i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",rx_dropped=0i 1542642001000000000\necs_container_net,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,network=total,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a rx_dropped=0i,rx_bytes=9979i,rx_errors=0i,rx_packets=62i,tx_bytes=1338i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",tx_packets=17i,tx_dropped=0i,tx_errors=0i 1542642001000000000\necs_container_blkio,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,device=253:1,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a io_service_bytes_recursive_sync=790528i,io_service_bytes_recursive_total=790528i,io_serviced_recursive_sync=10i,io_serviced_recursive_write=0i,io_serviced_recursive_async=0i,io_serviced_recursive_total=10i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",io_service_bytes_recursive_read=790528i,io_service_bytes_recursive_write=0i,io_service_bytes_recursive_async=0i,io_serviced_recursive_read=10i 1542642001000000000\necs_container_blkio,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,device=253:2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a io_service_bytes_recursive_sync=790528i,io_service_bytes_recursive_total=790528i,io_serviced_recursive_async=0i,io_serviced_recursive_total=10i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",io_service_bytes_recursive_read=790528i,io_service_bytes_recursive_write=0i,io_service_bytes_recursive_async=0i,io_serviced_recursive_read=10i,io_serviced_recursive_write=0i,io_serviced_recursive_sync=10i 1542642001000000000\necs_container_blkio,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,device=253:4,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a io_service_bytes_recursive_write=0i,io_service_bytes_recursive_sync=790528i,io_service_bytes_recursive_async=0i,io_service_bytes_recursive_total=790528i,io_serviced_recursive_async=0i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",io_service_bytes_recursive_read=790528i,io_serviced_recursive_read=10i,io_serviced_recursive_write=0i,io_serviced_recursive_sync=10i,io_serviced_recursive_total=10i 1542642001000000000\necs_container_blkio,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,device=202:26368,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a io_serviced_recursive_read=10i,io_serviced_recursive_write=0i,io_serviced_recursive_sync=10i,io_serviced_recursive_async=0i,io_serviced_recursive_total=10i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",io_service_bytes_recursive_sync=790528i,io_service_bytes_recursive_total=790528i,io_service_bytes_recursive_async=0i,io_service_bytes_recursive_read=790528i,io_service_bytes_recursive_write=0i 1542642001000000000\necs_container_blkio,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,device=total,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a io_serviced_recursive_async=0i,io_serviced_recursive_read=40i,io_serviced_recursive_sync=40i,io_serviced_recursive_write=0i,io_serviced_recursive_total=40i,io_service_bytes_recursive_read=3162112i,io_service_bytes_recursive_write=0i,io_service_bytes_recursive_async=0i,container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",io_service_bytes_recursive_sync=3162112i,io_service_bytes_recursive_total=3162112i 1542642001000000000\necs_container_meta,cluster=test,com.amazonaws.ecs.cluster=test,com.amazonaws.ecs.container-name=~internal~ecs~pause,com.amazonaws.ecs.task-arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a,com.amazonaws.ecs.task-definition-family=nginx,com.amazonaws.ecs.task-definition-version=2,family=nginx,host=c4b301d4a123,id=e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba,name=~internal~ecs~pause,revision=2,task_arn=arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a limit_mem=0,type=\"CNI_PAUSE\",container_id=\"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",docker_name=\"ecs-nginx-2-internalecspause\",limit_cpu=0,known_status=\"RESOURCES_PROVISIONED\",image=\"amazon/amazon-ecs-pause:0.1.0\",image_id=\"\",desired_status=\"RESOURCES_PROVISIONED\" 1542642001000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ecs/cgroupv2_test.go",
    "content": "package ecs\n\nimport (\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst cgroupID = \"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\"\n\nfunc TestParseCgroupV2Stats(t *testing.T) {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\texpected, err := testutil.ParseMetricsFromFile(\"testdata/cgroupv2/stats.out\", parser)\n\trequire.NoError(t, err)\n\n\tstats, err := os.Open(\"testdata/cgroupv2/stats.json\")\n\trequire.NoError(t, err)\n\tparsedStats, err := unmarshalStats(stats)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\tmemstats(cgroupID, parsedStats[cgroupID], &acc, tags, time.Now())\n\tcpustats(cgroupID, parsedStats[cgroupID], &acc, tags, time.Now())\n\tnetstats(cgroupID, parsedStats[cgroupID], &acc, tags, time.Now())\n\tblkstats(cgroupID, parsedStats[cgroupID], &acc, tags, time.Now())\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestParseCgroupV2Meta(t *testing.T) {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\texpected, err := testutil.ParseMetricsFromFile(\"testdata/cgroupv2/meta.out\", parser)\n\trequire.NoError(t, err)\n\n\tmeta, err := os.Open(\"testdata/cgroupv2/meta.json\")\n\trequire.NoError(t, err)\n\tvalidMeta, err := unmarshalTask(meta)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\tmetastats(cgroupID, &validMeta.Containers[0], &acc, tags, time.Now())\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/client.go",
    "content": "package ecs\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types/container\"\n)\n\nvar (\n\t// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v2.html\n\tecsMetadataPathV2  = \"/v2/metadata\"\n\tecsMetaStatsPathV2 = \"/v2/stats\"\n\n\t// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html\n\t// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html\n\tecsMetadataPath  = \"/task\"\n\tecsMetaStatsPath = \"/task/stats\"\n)\n\n// client is the ECS client contract\ntype client interface {\n\ttask() (*ecsTask, error)\n\tcontainerStats() (map[string]*container.StatsResponse, error)\n}\n\ntype httpClient interface {\n\tDo(req *http.Request) (*http.Response, error)\n}\n\n// newClient constructs an ECS client with the passed configuration params\nfunc newClient(timeout time.Duration, endpoint string, version int) (*ecsClient, error) {\n\tif version < 2 || version > 4 {\n\t\tconst msg = \"expected metadata version 2, 3 or 4, got %d\"\n\t\treturn nil, fmt.Errorf(msg, version)\n\t}\n\n\tbaseURL, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := &http.Client{\n\t\tTimeout: timeout,\n\t}\n\n\treturn &ecsClient{\n\t\tclient:   c,\n\t\tbaseURL:  baseURL,\n\t\ttaskURL:  resolveTaskURL(baseURL, version),\n\t\tstatsURL: resolveStatsURL(baseURL, version),\n\t\tversion:  version,\n\t}, nil\n}\n\nfunc resolveTaskURL(base *url.URL, version int) string {\n\tvar path string\n\tswitch version {\n\tcase 2:\n\t\tpath = ecsMetadataPathV2\n\tcase 3:\n\t\tpath = ecsMetadataPath\n\tcase 4:\n\t\tpath = ecsMetadataPath\n\tdefault:\n\t\tconst msg = \"resolveTaskURL: unexpected version %d\"\n\t\tpanic(fmt.Errorf(msg, version))\n\t}\n\treturn resolveURL(base, path)\n}\n\nfunc resolveStatsURL(base *url.URL, version int) string {\n\tvar path string\n\tswitch version {\n\tcase 2:\n\t\tpath = ecsMetaStatsPathV2\n\tcase 3:\n\t\tpath = ecsMetaStatsPath\n\tcase 4:\n\t\tpath = ecsMetaStatsPath\n\tdefault:\n\t\t// Should never happen.\n\t\tconst msg = \"resolveStatsURL: unexpected version %d\"\n\t\tpanic(fmt.Errorf(msg, version))\n\t}\n\treturn resolveURL(base, path)\n}\n\n// resolveURL returns a URL string by concatenating the string representation of base\n// and path. This is consistent with AWS metadata documentation:\n// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html#task-metadata-endpoint-v3-paths\nfunc resolveURL(base *url.URL, path string) string {\n\treturn base.String() + path\n}\n\n// ecsClient contains ECS connection config\ntype ecsClient struct {\n\tclient   httpClient\n\tversion  int\n\tbaseURL  *url.URL\n\ttaskURL  string\n\tstatsURL string\n}\n\n// task calls the ECS metadata endpoint and returns a populated task\nfunc (c *ecsClient) task() (*ecsTask, error) {\n\treq, err := http.NewRequest(\"GET\", c.taskURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 200))\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s: %q\", c.taskURL, resp.Status, body)\n\t}\n\n\ttask, err := unmarshalTask(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn task, nil\n}\n\n// containerStats calls the ECS stats endpoint and returns a populated container stats map\nfunc (c *ecsClient) containerStats() (map[string]*container.StatsResponse, error) {\n\treq, err := http.NewRequest(\"GET\", c.statsURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 200))\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s: %q\", c.statsURL, resp.Status, body)\n\t}\n\n\treturn unmarshalStats(resp.Body)\n}\n\n// pollSync executes task and containerStats in parallel.\n// If both succeed, both structs are returned.\n// If either errors, a single error is returned.\nfunc pollSync(c client) (*ecsTask, map[string]*container.StatsResponse, error) {\n\tvar task *ecsTask\n\tvar stats map[string]*container.StatsResponse\n\tvar err error\n\n\tif stats, err = c.containerStats(); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif task, err = c.task(); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn task, stats, nil\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/client_test.go",
    "content": "package ecs\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype pollMock struct {\n\tgetTask  func() (*ecsTask, error)\n\tgetStats func() (map[string]*container.StatsResponse, error)\n}\n\nfunc (p *pollMock) task() (*ecsTask, error) {\n\treturn p.getTask()\n}\n\nfunc (p *pollMock) containerStats() (map[string]*container.StatsResponse, error) {\n\treturn p.getStats()\n}\n\nfunc TestEcsClient_PollSync(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tmock    *pollMock\n\t\twant    *ecsTask\n\t\twant1   map[string]*container.StatsResponse\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"success\",\n\t\t\tmock: &pollMock{\n\t\t\t\tgetTask: func() (*ecsTask, error) {\n\t\t\t\t\treturn &validMeta, nil\n\t\t\t\t},\n\t\t\t\tgetStats: func() (map[string]*container.StatsResponse, error) {\n\t\t\t\t\treturn validStats, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:  &validMeta,\n\t\t\twant1: validStats,\n\t\t},\n\t\t{\n\t\t\tname: \"task err\",\n\t\t\tmock: &pollMock{\n\t\t\t\tgetTask: func() (*ecsTask, error) {\n\t\t\t\t\treturn nil, errors.New(\"err\")\n\t\t\t\t},\n\t\t\t\tgetStats: func() (map[string]*container.StatsResponse, error) {\n\t\t\t\t\treturn validStats, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"stats err\",\n\t\t\tmock: &pollMock{\n\t\t\t\tgetTask: func() (*ecsTask, error) {\n\t\t\t\t\treturn &validMeta, nil\n\t\t\t\t},\n\t\t\t\tgetStats: func() (map[string]*container.StatsResponse, error) {\n\t\t\t\t\treturn nil, errors.New(\"err\")\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, got1, err := pollSync(tt.mock)\n\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ecsClient.pollSync() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, tt.want, got, \"ecsClient.pollSync() got = %v, want %v\", got, tt.want)\n\t\t\trequire.Equal(t, tt.want1, got1, \"ecsClient.pollSync() got1 = %v, want %v\", got1, tt.want1)\n\t\t})\n\t}\n}\n\ntype mockDo struct {\n\tdo func() (*http.Response, error)\n}\n\nfunc (m mockDo) Do(*http.Request) (*http.Response, error) {\n\treturn m.do()\n}\n\nfunc TestEcsClient_Task(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tclient  httpClient\n\t\twant    *ecsTask\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"happy\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\trc, err := os.Open(\"testdata/metadata.golden\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\t\tBody:       io.NopCloser(rc),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twant: &validMeta,\n\t\t},\n\t\t{\n\t\t\tname: \"do err\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn nil, errors.New(\"err\")\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"malformed 500 resp\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusInternalServerError,\n\t\t\t\t\t\tBody:       io.NopCloser(bytes.NewReader([]byte(\"foo\"))),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"malformed 200 resp\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\t\tBody:       io.NopCloser(bytes.NewReader([]byte(\"foo\"))),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := &ecsClient{\n\t\t\t\tclient:  tt.client,\n\t\t\t\ttaskURL: \"abc\",\n\t\t\t}\n\t\t\tgot, err := c.task()\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ecsClient.task() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, tt.want, got, \"ecsClient.task() = %v, want %v\", got, tt.want)\n\t\t})\n\t}\n}\n\nfunc TestEcsClient_ContainerStats(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tclient  httpClient\n\t\twant    map[string]*container.StatsResponse\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"happy\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\trc, err := os.Open(\"testdata/stats.golden\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\t\tBody:       io.NopCloser(rc),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twant: validStats,\n\t\t},\n\t\t{\n\t\t\tname: \"do err\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn nil, errors.New(\"err\")\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    nil,\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"malformed 200 resp\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\t\tBody:       io.NopCloser(bytes.NewReader([]byte(\"foo\"))),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    nil,\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"malformed 500 resp\",\n\t\t\tclient: mockDo{\n\t\t\t\tdo: func() (*http.Response, error) {\n\t\t\t\t\treturn &http.Response{\n\t\t\t\t\t\tStatusCode: http.StatusInternalServerError,\n\t\t\t\t\t\tBody:       io.NopCloser(bytes.NewReader([]byte(\"foo\"))),\n\t\t\t\t\t}, nil\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    nil,\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := &ecsClient{\n\t\t\t\tclient:   tt.client,\n\t\t\t\tstatsURL: \"abc\",\n\t\t\t}\n\t\t\tgot, err := c.containerStats()\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ecsClient.containerStats() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, tt.want, got, \"ecsClient.containerStats() = %v, want %v\", got, tt.want)\n\t\t})\n\t}\n}\n\nfunc TestResolveTaskURL(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tbase string\n\t\tver  int\n\t\texp  string\n\t}{\n\t\t{\n\t\t\tname: \"default v2 endpoint\",\n\t\t\tbase: v2Endpoint,\n\t\t\tver:  2,\n\t\t\texp:  \"http://169.254.170.2/v2/metadata\",\n\t\t},\n\t\t{\n\t\t\tname: \"custom v2 endpoint\",\n\t\t\tbase: \"http://192.168.0.1\",\n\t\t\tver:  2,\n\t\t\texp:  \"http://192.168.0.1/v2/metadata\",\n\t\t},\n\t\t{\n\t\t\tname: \"theoretical v3 endpoint\",\n\t\t\tbase: \"http://169.254.170.2/v3/metadata\",\n\t\t\tver:  3,\n\t\t\texp:  \"http://169.254.170.2/v3/metadata/task\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbaseURL, err := url.Parse(tt.base)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tact := resolveTaskURL(baseURL, tt.ver)\n\t\t\trequire.Equal(t, tt.exp, act)\n\t\t})\n\t}\n}\n\nfunc TestResolveStatsURL(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tbase string\n\t\tver  int\n\t\texp  string\n\t}{\n\t\t{\n\t\t\tname: \"default v2 endpoint\",\n\t\t\tbase: v2Endpoint,\n\t\t\tver:  2,\n\t\t\texp:  \"http://169.254.170.2/v2/stats\",\n\t\t},\n\t\t{\n\t\t\tname: \"custom v2 endpoint\",\n\t\t\tbase: \"http://192.168.0.1\",\n\t\t\tver:  2,\n\t\t\texp:  \"http://192.168.0.1/v2/stats\",\n\t\t},\n\t\t{\n\t\t\tname: \"theoretical v3 endpoint\",\n\t\t\tbase: \"http://169.254.170.2/v3/metadata\",\n\t\t\tver:  3,\n\t\t\texp:  \"http://169.254.170.2/v3/metadata/task/stats\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbaseURL, err := url.Parse(tt.base)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tact := resolveStatsURL(baseURL, tt.ver)\n\t\t\trequire.Equal(t, tt.exp, act)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/ecs.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ecs\n\nimport (\n\t_ \"embed\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tv2Endpoint = \"http://169.254.170.2\"\n)\n\ntype Ecs struct {\n\tEndpointURL string          `toml:\"endpoint_url\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\n\tContainerNameInclude []string `toml:\"container_name_include\"`\n\tContainerNameExclude []string `toml:\"container_name_exclude\"`\n\n\tContainerStatusInclude []string `toml:\"container_status_include\"`\n\tContainerStatusExclude []string `toml:\"container_status_exclude\"`\n\n\tLabelInclude []string `toml:\"ecs_label_include\"`\n\tLabelExclude []string `toml:\"ecs_label_exclude\"`\n\n\tnewClient func(timeout time.Duration, endpoint string, version int) (*ecsClient, error)\n\n\tclient              client\n\tfiltersCreated      bool\n\tlabelFilter         filter.Filter\n\tcontainerNameFilter filter.Filter\n\tstatusFilter        filter.Filter\n\tmetadataVersion     int\n}\n\nfunc (*Ecs) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ecs *Ecs) Gather(acc telegraf.Accumulator) error {\n\terr := initSetup(ecs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttask, stats, err := pollSync(ecs.client)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmergeTaskStats(task, stats)\n\n\ttaskTags := map[string]string{\n\t\t\"cluster\":  task.Cluster,\n\t\t\"task_arn\": task.TaskARN,\n\t\t\"family\":   task.Family,\n\t\t\"revision\": task.Revision,\n\t}\n\n\t// accumulate metrics\n\taccTask(task, taskTags, acc)\n\tecs.accContainers(task, taskTags, acc)\n\n\treturn nil\n}\n\nfunc initSetup(ecs *Ecs) error {\n\tif ecs.client == nil {\n\t\tresolveEndpoint(ecs)\n\n\t\tc, err := ecs.newClient(time.Duration(ecs.Timeout), ecs.EndpointURL, ecs.metadataVersion)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tecs.client = c\n\t}\n\n\t// Create filters\n\tif !ecs.filtersCreated {\n\t\terr := ecs.createContainerNameFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = ecs.createContainerStatusFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = ecs.createLabelFilters()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tecs.filtersCreated = true\n\t}\n\n\treturn nil\n}\n\nfunc resolveEndpoint(ecs *Ecs) {\n\tif ecs.EndpointURL != \"\" {\n\t\t// Use metadata v2 API since endpoint is set explicitly.\n\t\tecs.metadataVersion = 2\n\t\treturn\n\t}\n\n\t// Auto-detect metadata endpoint version.\n\n\t// Use metadata v4 if available.\n\t// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html\n\tv4Endpoint := os.Getenv(\"ECS_CONTAINER_METADATA_URI_V4\")\n\tif v4Endpoint != \"\" {\n\t\tecs.EndpointURL = v4Endpoint\n\t\tecs.metadataVersion = 4\n\t\treturn\n\t}\n\n\t// Use metadata v3 if available.\n\t// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html\n\tv3Endpoint := os.Getenv(\"ECS_CONTAINER_METADATA_URI\")\n\tif v3Endpoint != \"\" {\n\t\tecs.EndpointURL = v3Endpoint\n\t\tecs.metadataVersion = 3\n\t\treturn\n\t}\n\n\t// Use v2 endpoint if nothing else is available.\n\tecs.EndpointURL = v2Endpoint\n\tecs.metadataVersion = 2\n}\n\nfunc accTask(task *ecsTask, tags map[string]string, acc telegraf.Accumulator) {\n\ttaskFields := map[string]interface{}{\n\t\t\"desired_status\": task.DesiredStatus,\n\t\t\"known_status\":   task.KnownStatus,\n\t\t\"limit_cpu\":      task.Limits[\"CPU\"],\n\t\t\"limit_mem\":      task.Limits[\"Memory\"],\n\t}\n\n\tacc.AddFields(\"ecs_task\", taskFields, tags)\n}\n\nfunc (ecs *Ecs) accContainers(task *ecsTask, taskTags map[string]string, acc telegraf.Accumulator) {\n\tfor i := range task.Containers {\n\t\tc := &task.Containers[i]\n\t\tif !ecs.containerNameFilter.Match(c.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !ecs.statusFilter.Match(strings.ToUpper(c.KnownStatus)) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// add matching ECS container Labels\n\t\tcontainerTags := map[string]string{\n\t\t\t\"id\":   c.ID,\n\t\t\t\"name\": c.Name,\n\t\t}\n\t\tfor k, v := range c.Labels {\n\t\t\tif ecs.labelFilter.Match(k) {\n\t\t\t\tcontainerTags[k] = v\n\t\t\t}\n\t\t}\n\t\ttags := mergeTags(taskTags, containerTags)\n\n\t\tparseContainerStats(c, acc, tags)\n\t}\n}\n\n// returns a new map with the same content values as the input map\nfunc copyTags(in map[string]string) map[string]string {\n\tout := make(map[string]string)\n\tfor k, v := range in {\n\t\tout[k] = v\n\t}\n\treturn out\n}\n\n// returns a new map with the merged content values of the two input maps\nfunc mergeTags(a, b map[string]string) map[string]string {\n\tc := copyTags(a)\n\tfor k, v := range b {\n\t\tc[k] = v\n\t}\n\treturn c\n}\n\nfunc (ecs *Ecs) createContainerNameFilters() error {\n\tcontainerNameFilter, err := filter.NewIncludeExcludeFilter(ecs.ContainerNameInclude, ecs.ContainerNameExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tecs.containerNameFilter = containerNameFilter\n\treturn nil\n}\n\nfunc (ecs *Ecs) createLabelFilters() error {\n\tlabelFilter, err := filter.NewIncludeExcludeFilter(ecs.LabelInclude, ecs.LabelExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tecs.labelFilter = labelFilter\n\treturn nil\n}\n\nfunc (ecs *Ecs) createContainerStatusFilters() error {\n\tif len(ecs.ContainerStatusInclude) == 0 && len(ecs.ContainerStatusExclude) == 0 {\n\t\tecs.ContainerStatusInclude = []string{\"RUNNING\"}\n\t}\n\n\t// ECS uses uppercase status names, normalizing for comparison.\n\tfor i, include := range ecs.ContainerStatusInclude {\n\t\tecs.ContainerStatusInclude[i] = strings.ToUpper(include)\n\t}\n\tfor i, exclude := range ecs.ContainerStatusExclude {\n\t\tecs.ContainerStatusExclude[i] = strings.ToUpper(exclude)\n\t}\n\n\tstatusFilter, err := filter.NewIncludeExcludeFilter(ecs.ContainerStatusInclude, ecs.ContainerStatusExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tecs.statusFilter = statusFilter\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"ecs\", func() telegraf.Input {\n\t\treturn &Ecs{\n\t\t\tEndpointURL:    \"\",\n\t\t\tTimeout:        config.Duration(5 * time.Second),\n\t\t\tnewClient:      newClient,\n\t\t\tfiltersCreated: false,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/ecs_test.go",
    "content": "package ecs\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// codified golden objects for tests\n\n// stats\nconst pauseStatsKey = \"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\"\nconst nginxStatsKey = \"fffe894e232d46c76475cfeabf4907f712e8b92618a37fca3ef0805bbbfb0299\"\n\nvar pauseStatsRead = mustParseNano(\"2018-11-19T15:40:00.936081344Z\")\nvar pauseStatsPreRead = mustParseNano(\"2018-11-19T15:39:59.933000984Z\")\n\nvar nginxStatsRead = mustParseNano(\"2018-11-19T15:40:00.93733207Z\")\nvar nginxStatsPreRead = mustParseNano(\"2018-11-19T15:39:59.934291009Z\")\n\nfunc mustParseNano(value string) time.Time {\n\tt, err := time.Parse(time.RFC3339Nano, value)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn t\n}\n\nvar validStats = map[string]*container.StatsResponse{\n\tpauseStatsKey: {\n\t\tRead:    pauseStatsRead,\n\t\tPreRead: pauseStatsPreRead,\n\t\tBlkioStats: container.BlkioStats{\n\t\t\tIoServiceBytesRecursive: []container.BlkioStatEntry{\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 790528,\n\t\t\t\t},\n\t\t\t},\n\t\t\tIoServicedRecursive: []container.BlkioStatEntry{\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 4,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 10,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tPercpuUsage: []uint64{\n\t\t\t\t\t26426156,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t},\n\t\t\t\tUsageInUsermode: 20000000,\n\t\t\t\tTotalUsage:      26426156,\n\t\t\t},\n\t\t\tSystemUsage:    2336100000000,\n\t\t\tOnlineCPUs:     1,\n\t\t\tThrottlingData: container.ThrottlingData{},\n\t\t},\n\t\tPreCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tPercpuUsage: []uint64{\n\t\t\t\t\t26426156,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t},\n\t\t\t\tUsageInUsermode: 20000000,\n\t\t\t\tTotalUsage:      26426156,\n\t\t\t},\n\t\t\tSystemUsage:    2335090000000,\n\t\t\tOnlineCPUs:     1,\n\t\t\tThrottlingData: container.ThrottlingData{},\n\t\t},\n\t\tMemoryStats: container.MemoryStats{\n\t\t\tStats: map[string]uint64{\n\t\t\t\t\"cache\":                     790528,\n\t\t\t\t\"mapped_file\":               618496,\n\t\t\t\t\"total_inactive_file\":       782336,\n\t\t\t\t\"pgpgout\":                   1040,\n\t\t\t\t\"rss\":                       40960,\n\t\t\t\t\"total_mapped_file\":         618496,\n\t\t\t\t\"pgpgin\":                    1243,\n\t\t\t\t\"pgmajfault\":                6,\n\t\t\t\t\"total_rss\":                 40960,\n\t\t\t\t\"hierarchical_memory_limit\": 536870912,\n\t\t\t\t\"total_pgfault\":             1298,\n\t\t\t\t\"total_active_file\":         8192,\n\t\t\t\t\"active_anon\":               40960,\n\t\t\t\t\"total_active_anon\":         40960,\n\t\t\t\t\"total_pgpgout\":             1040,\n\t\t\t\t\"total_cache\":               790528,\n\t\t\t\t\"active_file\":               8192,\n\t\t\t\t\"pgfault\":                   1298,\n\t\t\t\t\"inactive_file\":             782336,\n\t\t\t\t\"total_pgpgin\":              1243,\n\t\t\t\t\"hierarchical_memsw_limit\":  9223372036854772000,\n\t\t\t},\n\t\t\tMaxUsage: 4825088,\n\t\t\tUsage:    1343488,\n\t\t\tLimit:    1033658368,\n\t\t},\n\t\tNetworks: map[string]container.NetworkStats{\n\t\t\t\"eth0\": {\n\t\t\t\tRxBytes:   uint64(5338),\n\t\t\t\tRxDropped: uint64(0),\n\t\t\t\tRxErrors:  uint64(0),\n\t\t\t\tRxPackets: uint64(36),\n\t\t\t\tTxBytes:   uint64(648),\n\t\t\t\tTxDropped: uint64(0),\n\t\t\t\tTxErrors:  uint64(0),\n\t\t\t\tTxPackets: uint64(8),\n\t\t\t},\n\t\t\t\"eth5\": {\n\t\t\t\tRxBytes:   uint64(4641),\n\t\t\t\tRxDropped: uint64(0),\n\t\t\t\tRxErrors:  uint64(0),\n\t\t\t\tRxPackets: uint64(26),\n\t\t\t\tTxBytes:   uint64(690),\n\t\t\t\tTxDropped: uint64(0),\n\t\t\t\tTxErrors:  uint64(0),\n\t\t\t\tTxPackets: uint64(9),\n\t\t\t},\n\t\t},\n\t},\n\tnginxStatsKey: {\n\t\tRead:    nginxStatsRead,\n\t\tPreRead: nginxStatsPreRead,\n\t\tBlkioStats: container.BlkioStats{\n\t\t\tIoServiceBytesRecursive: []container.BlkioStatEntry{\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 5730304,\n\t\t\t\t},\n\t\t\t},\n\t\t\tIoServicedRecursive: []container.BlkioStatEntry{\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 202,\n\t\t\t\t\tMinor: 26368,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 1,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 2,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 156,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Read\",\n\t\t\t\t\tValue: 147,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Write\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Sync\",\n\t\t\t\t\tValue: 147,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Async\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMajor: 253,\n\t\t\t\t\tMinor: 5,\n\t\t\t\t\tOp:    \"Total\",\n\t\t\t\t\tValue: 147,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tPercpuUsage: []uint64{\n\t\t\t\t\t65599511,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t},\n\t\t\t\tUsageInUsermode:   40000000,\n\t\t\t\tTotalUsage:        65599511,\n\t\t\t\tUsageInKernelmode: 10000000,\n\t\t\t},\n\t\t\tSystemUsage:    2336100000000,\n\t\t\tOnlineCPUs:     1,\n\t\t\tThrottlingData: container.ThrottlingData{},\n\t\t},\n\t\tPreCPUStats: container.CPUStats{\n\t\t\tCPUUsage: container.CPUUsage{\n\t\t\t\tPercpuUsage: []uint64{\n\t\t\t\t\t65599511,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t},\n\t\t\t\tUsageInUsermode:   40000000,\n\t\t\t\tTotalUsage:        65599511,\n\t\t\t\tUsageInKernelmode: 10000000,\n\t\t\t},\n\t\t\tSystemUsage:    2335090000000,\n\t\t\tOnlineCPUs:     1,\n\t\t\tThrottlingData: container.ThrottlingData{},\n\t\t},\n\t\tMemoryStats: container.MemoryStats{\n\t\t\tStats: map[string]uint64{\n\t\t\t\t\"cache\":                     5787648,\n\t\t\t\t\"mapped_file\":               3616768,\n\t\t\t\t\"total_inactive_file\":       4321280,\n\t\t\t\t\"pgpgout\":                   1674,\n\t\t\t\t\"rss\":                       1597440,\n\t\t\t\t\"total_mapped_file\":         3616768,\n\t\t\t\t\"pgpgin\":                    3477,\n\t\t\t\t\"pgmajfault\":                40,\n\t\t\t\t\"total_rss\":                 1597440,\n\t\t\t\t\"total_inactive_anon\":       4096,\n\t\t\t\t\"hierarchical_memory_limit\": 536870912,\n\t\t\t\t\"total_pgfault\":             2924,\n\t\t\t\t\"total_active_file\":         1462272,\n\t\t\t\t\"active_anon\":               1597440,\n\t\t\t\t\"total_active_anon\":         1597440,\n\t\t\t\t\"total_pgpgout\":             1674,\n\t\t\t\t\"total_cache\":               5787648,\n\t\t\t\t\"inactive_anon\":             4096,\n\t\t\t\t\"active_file\":               1462272,\n\t\t\t\t\"pgfault\":                   2924,\n\t\t\t\t\"inactive_file\":             4321280,\n\t\t\t\t\"total_pgpgin\":              3477,\n\t\t\t\t\"hierarchical_memsw_limit\":  9223372036854772000,\n\t\t\t},\n\t\t\tMaxUsage: 8667136,\n\t\t\tUsage:    8179712,\n\t\t\tLimit:    1033658368,\n\t\t},\n\t},\n}\n\n// meta\nvar metaPauseCreated = mustParseNano(\"2018-11-19T15:31:26.641964373Z\")\nvar metaPauseStarted = mustParseNano(\"2018-11-19T15:31:27.035698679Z\")\nvar metaCreated = mustParseNano(\"2018-11-19T15:31:27.614884084Z\")\nvar metaStarted = mustParseNano(\"2018-11-19T15:31:27.975996351Z\")\nvar metaPullStart = mustParseNano(\"2018-11-19T15:31:27.197327103Z\")\nvar metaPullStop = mustParseNano(\"2018-11-19T15:31:27.609089471Z\")\n\nvar validMeta = ecsTask{\n\tCluster:       \"test\",\n\tTaskARN:       \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n\tFamily:        \"nginx\",\n\tRevision:      \"2\",\n\tDesiredStatus: \"RUNNING\",\n\tKnownStatus:   \"RUNNING\",\n\tContainers: []ecsContainer{\n\t\t{\n\t\t\tID:         pauseStatsKey,\n\t\t\tName:       \"~internal~ecs~pause\",\n\t\t\tDockerName: \"ecs-nginx-2-internalecspause\",\n\t\t\tImage:      \"amazon/amazon-ecs-pause:0.1.0\",\n\t\t\tImageID:    \"\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"com.amazonaws.ecs.cluster\":                 \"test\",\n\t\t\t\t\"com.amazonaws.ecs.container-name\":          \"~internal~ecs~pause\",\n\t\t\t\t\"com.amazonaws.ecs.task-arn\":                \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n\t\t\t\t\"com.amazonaws.ecs.task-definition-family\":  \"nginx\",\n\t\t\t\t\"com.amazonaws.ecs.task-definition-version\": \"2\",\n\t\t\t},\n\t\t\tDesiredStatus: \"RESOURCES_PROVISIONED\",\n\t\t\tKnownStatus:   \"RESOURCES_PROVISIONED\",\n\t\t\tLimits: map[string]float64{\n\t\t\t\t\"CPU\":    0,\n\t\t\t\t\"Memory\": 0,\n\t\t\t},\n\t\t\tCreatedAt: metaPauseCreated,\n\t\t\tStartedAt: metaPauseStarted,\n\t\t\tType:      \"CNI_PAUSE\",\n\t\t\tNetworks: []network{\n\t\t\t\t{\n\t\t\t\t\tNetworkMode: \"awsvpc\",\n\t\t\t\t\tIPv4Addresses: []string{\n\t\t\t\t\t\t\"172.31.25.181\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tID:         nginxStatsKey,\n\t\t\tName:       \"nginx\",\n\t\t\tDockerName: \"ecs-nginx-2-nginx\",\n\t\t\tImage:      \"nginx:alpine\",\n\t\t\tImageID:    \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"com.amazonaws.ecs.cluster\":                 \"test\",\n\t\t\t\t\"com.amazonaws.ecs.container-name\":          \"nginx\",\n\t\t\t\t\"com.amazonaws.ecs.task-arn\":                \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n\t\t\t\t\"com.amazonaws.ecs.task-definition-family\":  \"nginx\",\n\t\t\t\t\"com.amazonaws.ecs.task-definition-version\": \"2\",\n\t\t\t},\n\t\t\tDesiredStatus: \"RUNNING\",\n\t\t\tKnownStatus:   \"RUNNING\",\n\t\t\tLimits: map[string]float64{\n\t\t\t\t\"CPU\":    0,\n\t\t\t\t\"Memory\": 0,\n\t\t\t},\n\t\t\tCreatedAt: metaCreated,\n\t\t\tStartedAt: metaStarted,\n\t\t\tType:      \"NORMAL\",\n\t\t\tNetworks: []network{\n\t\t\t\t{\n\t\t\t\t\tNetworkMode: \"awsvpc\",\n\t\t\t\t\tIPv4Addresses: []string{\n\t\t\t\t\t\t\"172.31.25.181\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tLimits: map[string]float64{\n\t\t\"CPU\":    0.5,\n\t\t\"Memory\": 512,\n\t},\n\tPullStartedAt: metaPullStart,\n\tPullStoppedAt: metaPullStop,\n}\n\nfunc TestResolveEndpoint(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tgiven  Ecs\n\t\texp    Ecs\n\t\tsetEnv func(*testing.T)\n\t}{\n\t\t{\n\t\t\tname: \"Endpoint is explicitly set => use v2 metadata\",\n\t\t\tgiven: Ecs{\n\t\t\t\tEndpointURL: \"192.162.0.1/custom_endpoint\",\n\t\t\t},\n\t\t\texp: Ecs{\n\t\t\t\tEndpointURL:     \"192.162.0.1/custom_endpoint\",\n\t\t\t\tmetadataVersion: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Endpoint is not set, ECS_CONTAINER_METADATA_URI is not set => use v2 metadata\",\n\t\t\tgiven: Ecs{\n\t\t\t\tEndpointURL: \"\",\n\t\t\t},\n\t\t\texp: Ecs{\n\t\t\t\tEndpointURL:     v2Endpoint,\n\t\t\t\tmetadataVersion: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Endpoint is not set, ECS_CONTAINER_METADATA_URI is set => use v3 metadata\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"ECS_CONTAINER_METADATA_URI\", \"v3-endpoint.local\")\n\t\t\t},\n\t\t\tgiven: Ecs{\n\t\t\t\tEndpointURL: \"\",\n\t\t\t},\n\t\t\texp: Ecs{\n\t\t\t\tEndpointURL:     \"v3-endpoint.local\",\n\t\t\t\tmetadataVersion: 3,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Endpoint is not set, ECS_CONTAINER_METADATA_URI_V4 is set => use v4 metadata\",\n\t\t\tsetEnv: func(t *testing.T) {\n\t\t\t\tt.Setenv(\"ECS_CONTAINER_METADATA_URI_V4\", \"v4-endpoint.local\")\n\t\t\t},\n\t\t\tgiven: Ecs{\n\t\t\t\tEndpointURL: \"\",\n\t\t\t},\n\t\t\texp: Ecs{\n\t\t\t\tEndpointURL:     \"v4-endpoint.local\",\n\t\t\t\tmetadataVersion: 4,\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.setEnv != nil {\n\t\t\t\ttt.setEnv(t)\n\t\t\t}\n\n\t\t\tact := tt.given\n\t\t\tresolveEndpoint(&act)\n\t\t\trequire.Equal(t, tt.exp, act)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/sample.conf",
    "content": "# Read metrics about ECS containers\n[[inputs.ecs]]\n  ## ECS metadata url.\n  ## Metadata v2 API is used if set explicitly. Otherwise,\n  ## v3 metadata endpoint API is used if available.\n  # endpoint_url = \"\"\n\n  ## Containers to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all containers\n  # container_name_include = []\n  # container_name_exclude = []\n\n  ## Container states to include and exclude. Globs accepted.\n  ## When empty only containers in the \"RUNNING\" state will be captured.\n  ## Possible values are \"NONE\", \"PULLED\", \"CREATED\", \"RUNNING\",\n  ## \"RESOURCES_PROVISIONED\", \"STOPPED\".\n  # container_status_include = []\n  # container_status_exclude = []\n\n  ## ecs labels to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all labels as tags\n  ecs_label_include = [ \"com.amazonaws.ecs.*\" ]\n  ecs_label_exclude = []\n\n  ## Timeout for queries.\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/ecs/stats.go",
    "content": "package ecs\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types/container\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/docker\"\n)\n\nfunc parseContainerStats(c *ecsContainer, acc telegraf.Accumulator, tags map[string]string) {\n\tid := c.ID\n\tstats := &c.Stats\n\ttm := stats.Read\n\n\tif tm.Before(time.Unix(0, 0)) {\n\t\ttm = time.Now()\n\t}\n\n\tmetastats(id, c, acc, tags, tm)\n\tmemstats(id, stats, acc, tags, tm)\n\tcpustats(id, stats, acc, tags, tm)\n\tnetstats(id, stats, acc, tags, tm)\n\tblkstats(id, stats, acc, tags, tm)\n}\n\nfunc metastats(id string, c *ecsContainer, acc telegraf.Accumulator, tags map[string]string, tm time.Time) {\n\tmetafields := map[string]interface{}{\n\t\t\"container_id\":   id,\n\t\t\"docker_name\":    c.DockerName,\n\t\t\"image\":          c.Image,\n\t\t\"image_id\":       c.ImageID,\n\t\t\"desired_status\": c.DesiredStatus,\n\t\t\"known_status\":   c.KnownStatus,\n\t\t\"limit_cpu\":      c.Limits[\"CPU\"],\n\t\t\"limit_mem\":      c.Limits[\"Memory\"],\n\t\t\"created_at\":     c.CreatedAt,\n\t\t\"started_at\":     c.StartedAt,\n\t\t\"type\":           c.Type,\n\t}\n\n\tacc.AddFields(\"ecs_container_meta\", metafields, tags, tm)\n}\n\nfunc memstats(id string, stats *container.StatsResponse, acc telegraf.Accumulator, tags map[string]string, tm time.Time) {\n\tmemfields := map[string]interface{}{\n\t\t\"container_id\": id,\n\t}\n\n\tmemstats := []string{\n\t\t\"active_anon\",\n\t\t\"active_file\",\n\t\t\"cache\",\n\t\t\"hierarchical_memory_limit\",\n\t\t\"inactive_anon\",\n\t\t\"inactive_file\",\n\t\t\"mapped_file\",\n\t\t\"pgfault\",\n\t\t\"pgmajfault\",\n\t\t\"pgpgin\",\n\t\t\"pgpgout\",\n\t\t\"rss\",\n\t\t\"rss_huge\",\n\t\t\"total_active_anon\",\n\t\t\"total_active_file\",\n\t\t\"total_cache\",\n\t\t\"total_inactive_anon\",\n\t\t\"total_inactive_file\",\n\t\t\"total_mapped_file\",\n\t\t\"total_pgfault\",\n\t\t\"total_pgmajfault\",\n\t\t\"total_pgpgin\",\n\t\t\"total_pgpgout\",\n\t\t\"total_rss\",\n\t\t\"total_rss_huge\",\n\t\t\"total_unevictable\",\n\t\t\"total_writeback\",\n\t\t\"unevictable\",\n\t\t\"writeback\",\n\t}\n\n\tfor _, field := range memstats {\n\t\tif value, ok := stats.MemoryStats.Stats[field]; ok {\n\t\t\tmemfields[field] = value\n\t\t}\n\t}\n\tif stats.MemoryStats.Failcnt != 0 {\n\t\tmemfields[\"fail_count\"] = stats.MemoryStats.Failcnt\n\t}\n\n\tmemfields[\"limit\"] = stats.MemoryStats.Limit\n\tmemfields[\"max_usage\"] = stats.MemoryStats.MaxUsage\n\n\tmem := docker.CalculateMemUsageUnixNoCache(stats.MemoryStats)\n\tmemLimit := float64(stats.MemoryStats.Limit)\n\tmemfields[\"usage\"] = uint64(mem)\n\tmemfields[\"usage_percent\"] = docker.CalculateMemPercentUnixNoCache(memLimit, mem)\n\n\tacc.AddFields(\"ecs_container_mem\", memfields, tags, tm)\n}\n\nfunc cpustats(id string, stats *container.StatsResponse, acc telegraf.Accumulator, tags map[string]string, tm time.Time) {\n\tcpufields := map[string]interface{}{\n\t\t\"usage_total\":                  stats.CPUStats.CPUUsage.TotalUsage,\n\t\t\"usage_in_usermode\":            stats.CPUStats.CPUUsage.UsageInUsermode,\n\t\t\"usage_in_kernelmode\":          stats.CPUStats.CPUUsage.UsageInKernelmode,\n\t\t\"usage_system\":                 stats.CPUStats.SystemUsage,\n\t\t\"throttling_periods\":           stats.CPUStats.ThrottlingData.Periods,\n\t\t\"throttling_throttled_periods\": stats.CPUStats.ThrottlingData.ThrottledPeriods,\n\t\t\"throttling_throttled_time\":    stats.CPUStats.ThrottlingData.ThrottledTime,\n\t\t\"container_id\":                 id,\n\t}\n\n\tpreviousCPU := stats.PreCPUStats.CPUUsage.TotalUsage\n\tpreviousSystem := stats.PreCPUStats.SystemUsage\n\tcpuPercent := docker.CalculateCPUPercentUnix(previousCPU, previousSystem, stats)\n\tcpufields[\"usage_percent\"] = cpuPercent\n\n\tcputags := copyTags(tags)\n\tcputags[\"cpu\"] = \"cpu-total\"\n\tacc.AddFields(\"ecs_container_cpu\", cpufields, cputags, tm)\n\n\t// If we have OnlineCPUs field, then use it to restrict stats gathering to only Online CPUs\n\t// (https://github.com/moby/moby/commit/115f91d7575d6de6c7781a96a082f144fd17e400)\n\tvar percpuusage []uint64\n\tif stats.CPUStats.OnlineCPUs > 0 && len(stats.CPUStats.CPUUsage.PercpuUsage) > 0 {\n\t\tpercpuusage = stats.CPUStats.CPUUsage.PercpuUsage[:stats.CPUStats.OnlineCPUs]\n\t} else {\n\t\tpercpuusage = stats.CPUStats.CPUUsage.PercpuUsage\n\t}\n\n\tfor i, percpu := range percpuusage {\n\t\tpercputags := copyTags(tags)\n\t\tpercputags[\"cpu\"] = fmt.Sprintf(\"cpu%d\", i)\n\t\tfields := map[string]interface{}{\n\t\t\t\"usage_total\":  percpu,\n\t\t\t\"container_id\": id,\n\t\t}\n\t\tacc.AddFields(\"ecs_container_cpu\", fields, percputags, tm)\n\t}\n}\n\nfunc netstats(id string, stats *container.StatsResponse, acc telegraf.Accumulator, tags map[string]string, tm time.Time) {\n\ttotalNetworkStatMap := make(map[string]interface{})\n\tfor network, netstats := range stats.Networks {\n\t\tnetfields := map[string]interface{}{\n\t\t\t\"rx_dropped\":   netstats.RxDropped,\n\t\t\t\"rx_bytes\":     netstats.RxBytes,\n\t\t\t\"rx_errors\":    netstats.RxErrors,\n\t\t\t\"tx_packets\":   netstats.TxPackets,\n\t\t\t\"tx_dropped\":   netstats.TxDropped,\n\t\t\t\"rx_packets\":   netstats.RxPackets,\n\t\t\t\"tx_errors\":    netstats.TxErrors,\n\t\t\t\"tx_bytes\":     netstats.TxBytes,\n\t\t\t\"container_id\": id,\n\t\t}\n\n\t\tnettags := copyTags(tags)\n\t\tnettags[\"network\"] = network\n\t\tacc.AddFields(\"ecs_container_net\", netfields, nettags, tm)\n\n\t\tfor field, value := range netfields {\n\t\t\tif field == \"container_id\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar uintV uint64\n\t\t\tswitch v := value.(type) {\n\t\t\tcase uint64:\n\t\t\t\tuintV = v\n\t\t\tcase int64:\n\t\t\t\tuintV = uint64(v)\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t_, ok := totalNetworkStatMap[field]\n\t\t\tif ok {\n\t\t\t\ttotalNetworkStatMap[field] = totalNetworkStatMap[field].(uint64) + uintV\n\t\t\t} else {\n\t\t\t\ttotalNetworkStatMap[field] = uintV\n\t\t\t}\n\t\t}\n\t}\n\n\t// totalNetworkStatMap could be empty if container is running with --net=host.\n\tif len(totalNetworkStatMap) != 0 {\n\t\tnettags := copyTags(tags)\n\t\tnettags[\"network\"] = \"total\"\n\t\ttotalNetworkStatMap[\"container_id\"] = id\n\t\tacc.AddFields(\"ecs_container_net\", totalNetworkStatMap, nettags, tm)\n\t}\n}\n\nfunc blkstats(id string, stats *container.StatsResponse, acc telegraf.Accumulator, tags map[string]string, tm time.Time) {\n\tblkioStats := stats.BlkioStats\n\t// Make a map of devices to their block io stats\n\tdeviceStatMap := make(map[string]map[string]interface{})\n\n\tfor _, metric := range blkioStats.IoServiceBytesRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\t_, ok := deviceStatMap[device]\n\t\tif !ok {\n\t\t\tdeviceStatMap[device] = make(map[string]interface{})\n\t\t}\n\n\t\tfield := \"io_service_bytes_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoServicedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\t_, ok := deviceStatMap[device]\n\t\tif !ok {\n\t\t\tdeviceStatMap[device] = make(map[string]interface{})\n\t\t}\n\n\t\tfield := \"io_serviced_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoQueuedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_queue_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoServiceTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_service_time_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoWaitTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_wait_time_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoMergedRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tfield := \"io_merged_recursive_\" + strings.ToLower(metric.Op)\n\t\tdeviceStatMap[device][field] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.IoTimeRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tdeviceStatMap[device][\"io_time_recursive\"] = metric.Value\n\t}\n\n\tfor _, metric := range blkioStats.SectorsRecursive {\n\t\tdevice := fmt.Sprintf(\"%d:%d\", metric.Major, metric.Minor)\n\t\tdeviceStatMap[device][\"sectors_recursive\"] = metric.Value\n\t}\n\n\ttotalStatMap := make(map[string]interface{})\n\tfor device, fields := range deviceStatMap {\n\t\tfields[\"container_id\"] = id\n\n\t\tiotags := copyTags(tags)\n\t\tiotags[\"device\"] = device\n\t\tacc.AddFields(\"ecs_container_blkio\", fields, iotags, tm)\n\n\t\tfor field, value := range fields {\n\t\t\tif field == \"container_id\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar uintV uint64\n\t\t\tswitch v := value.(type) {\n\t\t\tcase uint64:\n\t\t\t\tuintV = v\n\t\t\tcase int64:\n\t\t\t\tuintV = uint64(v)\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t_, ok := totalStatMap[field]\n\t\t\tif ok {\n\t\t\t\ttotalStatMap[field] = totalStatMap[field].(uint64) + uintV\n\t\t\t} else {\n\t\t\t\ttotalStatMap[field] = uintV\n\t\t\t}\n\t\t}\n\t}\n\n\ttotalStatMap[\"container_id\"] = id\n\tiotags := copyTags(tags)\n\tiotags[\"device\"] = \"total\"\n\tacc.AddFields(\"ecs_container_blkio\", totalStatMap, iotags, tm)\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/stats_test.go",
    "content": "package ecs\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_metastats(t *testing.T) {\n\tvar mockAcc testutil.Accumulator\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\ttm := time.Now()\n\n\tmetastats(nginxStatsKey, &validMeta.Containers[1], &mockAcc, tags, tm)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_meta\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\":   nginxStatsKey,\n\t\t\t\"docker_name\":    \"ecs-nginx-2-nginx\",\n\t\t\t\"image\":          \"nginx:alpine\",\n\t\t\t\"image_id\":       \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\t\"desired_status\": \"RUNNING\",\n\t\t\t\"known_status\":   \"RUNNING\",\n\t\t\t\"limit_cpu\":      float64(0),\n\t\t\t\"limit_mem\":      float64(0),\n\t\t\t\"created_at\":     metaCreated,\n\t\t\t\"started_at\":     metaStarted,\n\t\t\t\"type\":           \"NORMAL\",\n\t\t},\n\t\ttags,\n\t)\n}\n\nfunc Test_memstats(t *testing.T) {\n\tvar mockAcc testutil.Accumulator\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\ttm := time.Now()\n\n\tmemstats(nginxStatsKey, validStats[nginxStatsKey], &mockAcc, tags, tm)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_mem\",\n\t\tmap[string]interface{}{\n\t\t\t\"active_anon\":               uint64(1597440),\n\t\t\t\"active_file\":               uint64(1462272),\n\t\t\t\"cache\":                     uint64(5787648),\n\t\t\t\"container_id\":              nginxStatsKey,\n\t\t\t\"hierarchical_memory_limit\": uint64(536870912),\n\t\t\t\"inactive_anon\":             uint64(4096),\n\t\t\t\"inactive_file\":             uint64(4321280),\n\t\t\t\"limit\":                     uint64(1033658368),\n\t\t\t\"mapped_file\":               uint64(3616768),\n\t\t\t\"max_usage\":                 uint64(8667136),\n\t\t\t\"pgmajfault\":                uint64(40),\n\t\t\t\"pgpgin\":                    uint64(3477),\n\t\t\t\"pgpgout\":                   uint64(1674),\n\t\t\t\"pgfault\":                   uint64(2924),\n\t\t\t\"rss\":                       uint64(1597440),\n\t\t\t\"total_active_anon\":         uint64(1597440),\n\t\t\t\"total_active_file\":         uint64(1462272),\n\t\t\t\"total_cache\":               uint64(5787648),\n\t\t\t\"total_inactive_anon\":       uint64(4096),\n\t\t\t\"total_inactive_file\":       uint64(4321280),\n\t\t\t\"total_mapped_file\":         uint64(3616768),\n\t\t\t\"total_pgfault\":             uint64(2924),\n\t\t\t\"total_pgpgout\":             uint64(1674),\n\t\t\t\"total_pgpgin\":              uint64(3477),\n\t\t\t\"total_rss\":                 uint64(1597440),\n\t\t\t\"usage\":                     uint64(2392064),\n\t\t\t\"usage_percent\":             float64(0.23141727228778164),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t},\n\t)\n}\n\nfunc Test_cpustats(t *testing.T) {\n\tvar mockAcc testutil.Accumulator\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\ttm := time.Now()\n\n\tcpustats(nginxStatsKey, validStats[nginxStatsKey], &mockAcc, tags, tm)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_cpu\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\":                 nginxStatsKey,\n\t\t\t\"throttling_periods\":           uint64(0),\n\t\t\t\"throttling_throttled_periods\": uint64(0),\n\t\t\t\"throttling_throttled_time\":    uint64(0),\n\t\t\t\"usage_in_usermode\":            uint64(40000000),\n\t\t\t\"usage_in_kernelmode\":          uint64(10000000),\n\t\t\t\"usage_percent\":                float64(0),\n\t\t\t\"usage_system\":                 uint64(2336100000000),\n\t\t\t\"usage_total\":                  uint64(65599511),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"cpu\":      \"cpu-total\",\n\t\t},\n\t)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_cpu\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\": nginxStatsKey,\n\t\t\t\"usage_total\":  uint64(65599511),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"cpu\":      \"cpu0\",\n\t\t},\n\t)\n}\n\nfunc Test_netstats(t *testing.T) {\n\tvar mockAcc testutil.Accumulator\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\ttm := time.Now()\n\n\tnetstats(pauseStatsKey, validStats[pauseStatsKey], &mockAcc, tags, tm)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_net\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\": pauseStatsKey,\n\t\t\t\"rx_bytes\":     uint64(5338),\n\t\t\t\"rx_dropped\":   uint64(0),\n\t\t\t\"rx_errors\":    uint64(0),\n\t\t\t\"rx_packets\":   uint64(36),\n\t\t\t\"tx_bytes\":     uint64(648),\n\t\t\t\"tx_dropped\":   uint64(0),\n\t\t\t\"tx_errors\":    uint64(0),\n\t\t\t\"tx_packets\":   uint64(8),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"network\":  \"eth0\",\n\t\t},\n\t)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_net\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\": pauseStatsKey,\n\t\t\t\"rx_bytes\":     uint64(4641),\n\t\t\t\"rx_dropped\":   uint64(0),\n\t\t\t\"rx_errors\":    uint64(0),\n\t\t\t\"rx_packets\":   uint64(26),\n\t\t\t\"tx_bytes\":     uint64(690),\n\t\t\t\"tx_dropped\":   uint64(0),\n\t\t\t\"tx_errors\":    uint64(0),\n\t\t\t\"tx_packets\":   uint64(9),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"network\":  \"eth5\",\n\t\t},\n\t)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_net\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\": pauseStatsKey,\n\t\t\t\"rx_bytes\":     uint64(9979),\n\t\t\t\"rx_dropped\":   uint64(0),\n\t\t\t\"rx_errors\":    uint64(0),\n\t\t\t\"rx_packets\":   uint64(62),\n\t\t\t\"tx_bytes\":     uint64(1338),\n\t\t\t\"tx_dropped\":   uint64(0),\n\t\t\t\"tx_errors\":    uint64(0),\n\t\t\t\"tx_packets\":   uint64(17),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"network\":  \"total\",\n\t\t},\n\t)\n}\n\nfunc Test_blkstats(t *testing.T) {\n\tvar mockAcc testutil.Accumulator\n\n\ttags := map[string]string{\n\t\t\"test_tag\": \"test\",\n\t}\n\ttm := time.Now()\n\n\tblkstats(nginxStatsKey, validStats[nginxStatsKey], &mockAcc, tags, tm)\n\tmockAcc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"ecs_container_blkio\",\n\t\tmap[string]interface{}{\n\t\t\t\"container_id\":                     nginxStatsKey,\n\t\t\t\"io_service_bytes_recursive_read\":  uint64(5730304),\n\t\t\t\"io_service_bytes_recursive_write\": uint64(0),\n\t\t\t\"io_service_bytes_recursive_sync\":  uint64(5730304),\n\t\t\t\"io_service_bytes_recursive_async\": uint64(0),\n\t\t\t\"io_service_bytes_recursive_total\": uint64(5730304),\n\t\t\t\"io_serviced_recursive_read\":       uint64(156),\n\t\t\t\"io_serviced_recursive_write\":      uint64(0),\n\t\t\t\"io_serviced_recursive_sync\":       uint64(156),\n\t\t\t\"io_serviced_recursive_async\":      uint64(0),\n\t\t\t\"io_serviced_recursive_total\":      uint64(156),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test_tag\": \"test\",\n\t\t\t\"device\":   \"202:26368\",\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/testdata/cgroupv2/meta.json",
    "content": "{\n    \"Cluster\": \"ecs-cluster-prod\",\n    \"TaskARN\": \"arn:aws:ecs:eu-west-2:<account_id>:task/ecs-cluster-prod/a22cfc58cdb04b27ada2caa3fd526463\",\n    \"Family\": \"nginx-telegraf\",\n    \"Revision\": \"3\",\n    \"DesiredStatus\": \"RUNNING\",\n    \"KnownStatus\": \"RUNNING\",\n    \"Containers\": [\n      {\n        \"DockerId\": \"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",\n        \"Name\": \"~internal~ecs~pause\",\n        \"DockerName\": \"ecs-nginx-telegraf-3-internalecspause-f0cc8fe3bfc9a8efd601\",\n        \"Image\": \"amazon/amazon-ecs-pause:0.1.0\",\n        \"ImageID\": \"\",\n        \"Labels\": {\n          \"com.amazonaws.ecs.cluster\": \"ecs-cluster-prod\",\n          \"com.amazonaws.ecs.container-name\": \"~internal~ecs~pause\",\n          \"com.amazonaws.ecs.task-arn\": \"arn:aws:ecs:eu-west-2:<account_id>:task/ecs-cluster-prod/a22cfc58cdb04b27ada2caa3fd526463\",\n          \"com.amazonaws.ecs.task-definition-family\": \"nginx-telegraf\",\n          \"com.amazonaws.ecs.task-definition-version\": \"3\"\n        },\n        \"DesiredStatus\": \"RESOURCES_PROVISIONED\",\n        \"KnownStatus\": \"RESOURCES_PROVISIONED\",\n        \"Limits\": {\n          \"CPU\": 2,\n          \"Memory\": 0\n        },\n        \"CreatedAt\": \"2023-10-26T15:57:02.520698803Z\",\n        \"StartedAt\": \"2023-10-26T15:57:02.806357646Z\",\n        \"Type\": \"CNI_PAUSE\",\n        \"Networks\": [\n          {\n            \"NetworkMode\": \"awsvpc\",\n            \"IPv4Addresses\": [\n              \"10.1.4.120\"\n            ]\n          }\n        ]\n      }\n    ],\n    \"Limits\": {\n      \"CPU\": 0.5,\n      \"Memory\": 1024\n    },\n    \"PullStartedAt\": \"2023-10-26T15:57:03.528549391Z\",\n    \"PullStoppedAt\": \"2023-10-26T15:57:18.310985676Z\",\n    \"AvailabilityZone\": \"eu-west-2b\"\n  }\n"
  },
  {
    "path": "plugins/inputs/ecs/testdata/cgroupv2/meta.out",
    "content": "ecs_container_meta,test_tag=test container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",desired_status=\"RESOURCES_PROVISIONED\",docker_name=\"ecs-nginx-telegraf-3-internalecspause-f0cc8fe3bfc9a8efd601\",image=\"amazon/amazon-ecs-pause:0.1.0\",image_id=\"\",known_status=\"RESOURCES_PROVISIONED\",limit_cpu=2,limit_mem=0,type=\"CNI_PAUSE\" 1698343335413572143\n"
  },
  {
    "path": "plugins/inputs/ecs/testdata/cgroupv2/stats.json",
    "content": "{\n    \"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\": {\n      \"read\": \"2023-10-26T15:58:32.690109934Z\",\n      \"preread\": \"2023-10-26T15:58:31.642796089Z\",\n      \"pids_stats\": {\n        \"current\": 1,\n        \"limit\": 4618\n      },\n      \"blkio_stats\": {\n        \"io_service_bytes_recursive\": null,\n        \"io_serviced_recursive\": null,\n        \"io_queue_recursive\": null,\n        \"io_service_time_recursive\": null,\n        \"io_wait_time_recursive\": null,\n        \"io_merged_recursive\": null,\n        \"io_time_recursive\": null,\n        \"sectors_recursive\": null\n      },\n      \"num_procs\": 0,\n      \"storage_stats\": {},\n      \"cpu_stats\": {\n        \"cpu_usage\": {\n          \"total_usage\": 34818000,\n          \"usage_in_kernelmode\": 5397000,\n          \"usage_in_usermode\": 29420000\n        },\n        \"system_cpu_usage\": 16970500000000,\n        \"online_cpus\": 2,\n        \"throttling_data\": {\n          \"periods\": 0,\n          \"throttled_periods\": 0,\n          \"throttled_time\": 0\n        }\n      },\n      \"precpu_stats\": {\n        \"cpu_usage\": {\n          \"total_usage\": 34818000,\n          \"usage_in_kernelmode\": 5397000,\n          \"usage_in_usermode\": 29420000\n        },\n        \"system_cpu_usage\": 16968420000000,\n        \"online_cpus\": 2,\n        \"throttling_data\": {\n          \"periods\": 0,\n          \"throttled_periods\": 0,\n          \"throttled_time\": 0\n        }\n      },\n      \"memory_stats\": {\n        \"usage\": 303104,\n        \"stats\": {\n          \"active_anon\": 4096,\n          \"active_file\": 0,\n          \"anon\": 45056,\n          \"anon_thp\": 0,\n          \"file\": 0,\n          \"file_dirty\": 0,\n          \"file_mapped\": 0,\n          \"file_writeback\": 0,\n          \"inactive_anon\": 40960,\n          \"inactive_file\": 0,\n          \"kernel_stack\": 16384,\n          \"pgactivate\": 1,\n          \"pgdeactivate\": 0,\n          \"pgfault\": 1113,\n          \"pglazyfree\": 0,\n          \"pglazyfreed\": 0,\n          \"pgmajfault\": 0,\n          \"pgrefill\": 0,\n          \"pgscan\": 0,\n          \"pgsteal\": 0,\n          \"shmem\": 0,\n          \"slab\": 190768,\n          \"slab_reclaimable\": 66320,\n          \"slab_unreclaimable\": 124448,\n          \"sock\": 0,\n          \"thp_collapse_alloc\": 0,\n          \"thp_fault_alloc\": 0,\n          \"unevictable\": 0,\n          \"workingset_activate\": 0,\n          \"workingset_nodereclaim\": 0,\n          \"workingset_refault\": 0\n        },\n        \"limit\": 4051226624\n      },\n      \"name\": \"/ecs-nginx-telegraf-3-internalecspause-f0cc8fe3bfc9a8efd601\",\n      \"id\": \"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",\n      \"networks\": {\n        \"eth0\": {\n          \"rx_bytes\": 14,\n          \"rx_packets\": 0,\n          \"rx_errors\": 0,\n          \"rx_dropped\": 0,\n          \"tx_bytes\": 21,\n          \"tx_packets\": 0,\n          \"tx_errors\": 0,\n          \"tx_dropped\": 0\n        }\n      }\n    }\n  }\n"
  },
  {
    "path": "plugins/inputs/ecs/testdata/cgroupv2/stats.out",
    "content": "ecs_container_mem,test_tag=test active_anon=4096u,active_file=0u,container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",inactive_anon=40960u,inactive_file=0u,limit=4051226624u,max_usage=0u,pgfault=1113u,pgmajfault=0u,unevictable=0u,usage=303104u,usage_percent=0.00748178337406187 1698343335413563073\necs_container_cpu,cpu=cpu-total,test_tag=test container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",throttling_periods=0u,throttling_throttled_periods=0u,throttling_throttled_time=0u,usage_in_kernelmode=5397000u,usage_in_usermode=29420000u,usage_percent=0,usage_system=16970500000000u,usage_total=34818000u 1698343335413566953\necs_container_net,network=eth0,test_tag=test container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",rx_bytes=14u,rx_dropped=0u,rx_errors=0u,rx_packets=0u,tx_bytes=21u,tx_dropped=0u,tx_errors=0u,tx_packets=0u 1698343335413572143\necs_container_net,network=total,test_tag=test container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\",rx_bytes=14u,rx_dropped=0u,rx_errors=0u,rx_packets=0u,tx_bytes=21u,tx_dropped=0u,tx_errors=0u,tx_packets=0u 1698343335413572143\necs_container_blkio,device=total,test_tag=test container_id=\"c69461b2c836cc3f0e3e5deb07b1f16e25f6009da2a48bb0adc7dd580befaf55\" 1698343335413575563\n"
  },
  {
    "path": "plugins/inputs/ecs/testdata/metadata.golden",
    "content": "{\n  \"Cluster\": \"test\",\n  \"TaskARN\": \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n  \"Family\": \"nginx\",\n  \"Revision\": \"2\",\n  \"DesiredStatus\": \"RUNNING\",\n  \"KnownStatus\": \"RUNNING\",\n  \"Containers\": [\n    {\n      \"DockerId\": \"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\",\n      \"Name\": \"~internal~ecs~pause\",\n      \"DockerName\": \"ecs-nginx-2-internalecspause\",\n      \"Image\": \"amazon/amazon-ecs-pause:0.1.0\",\n      \"ImageID\": \"\",\n      \"Labels\": {\n        \"com.amazonaws.ecs.cluster\": \"test\",\n        \"com.amazonaws.ecs.container-name\": \"~internal~ecs~pause\",\n        \"com.amazonaws.ecs.task-arn\": \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n        \"com.amazonaws.ecs.task-definition-family\": \"nginx\",\n        \"com.amazonaws.ecs.task-definition-version\": \"2\"\n      },\n      \"DesiredStatus\": \"RESOURCES_PROVISIONED\",\n      \"KnownStatus\": \"RESOURCES_PROVISIONED\",\n      \"Limits\": {\n        \"CPU\": 0,\n        \"Memory\": 0\n      },\n      \"CreatedAt\": \"2018-11-19T15:31:26.641964373Z\",\n      \"StartedAt\": \"2018-11-19T15:31:27.035698679Z\",\n      \"Type\": \"CNI_PAUSE\",\n      \"Networks\": [\n        {\n          \"NetworkMode\": \"awsvpc\",\n          \"IPv4Addresses\": [\n            \"172.31.25.181\"\n          ]\n        }\n      ]\n    },\n    {\n      \"DockerId\": \"fffe894e232d46c76475cfeabf4907f712e8b92618a37fca3ef0805bbbfb0299\",\n      \"Name\": \"nginx\",\n      \"DockerName\": \"ecs-nginx-2-nginx\",\n      \"Image\": \"nginx:alpine\",\n      \"ImageID\": \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n      \"Labels\": {\n        \"com.amazonaws.ecs.cluster\": \"test\",\n        \"com.amazonaws.ecs.container-name\": \"nginx\",\n        \"com.amazonaws.ecs.task-arn\": \"arn:aws:ecs:aws-region-1:012345678901:task/a1234abc-a0a0-0a01-ab01-0abc012a0a0a\",\n        \"com.amazonaws.ecs.task-definition-family\": \"nginx\",\n        \"com.amazonaws.ecs.task-definition-version\": \"2\"\n      },\n      \"DesiredStatus\": \"RUNNING\",\n      \"KnownStatus\": \"RUNNING\",\n      \"Limits\": {\n        \"CPU\": 0,\n        \"Memory\": 0\n      },\n      \"CreatedAt\": \"2018-11-19T15:31:27.614884084Z\",\n      \"StartedAt\": \"2018-11-19T15:31:27.975996351Z\",\n      \"Type\": \"NORMAL\",\n      \"Networks\": [\n        {\n          \"NetworkMode\": \"awsvpc\",\n          \"IPv4Addresses\": [\n            \"172.31.25.181\"\n          ]\n        }\n      ]\n    }\n  ],\n  \"Limits\": {\n    \"CPU\": 0.5,\n    \"Memory\": 512\n  },\n  \"PullStartedAt\": \"2018-11-19T15:31:27.197327103Z\",\n  \"PullStoppedAt\": \"2018-11-19T15:31:27.609089471Z\"\n}"
  },
  {
    "path": "plugins/inputs/ecs/testdata/stats.golden",
    "content": "{\n  \"e6af031b91deb3136a2b7c42f262ed2ab554e2fe2736998c7d8edf4afe708dba\": {\n    \"read\": \"2018-11-19T15:40:00.936081344Z\",\n    \"preread\": \"2018-11-19T15:39:59.933000984Z\",\n    \"num_procs\": 0,\n    \"pids_stats\": {},\n    \"networks\": {\n      \"eth0\": {\n        \"rx_bytes\": 5338,\n        \"rx_dropped\": 0,\n        \"rx_errors\": 0,\n        \"rx_packets\": 36,\n        \"tx_bytes\": 648,\n        \"tx_dropped\": 0,\n        \"tx_errors\": 0,\n        \"tx_packets\": 8\n      },\n      \"eth5\": {\n        \"rx_bytes\": 4641,\n        \"rx_dropped\": 0,\n        \"rx_errors\": 0,\n        \"rx_packets\": 26,\n        \"tx_bytes\": 690,\n        \"tx_dropped\": 0,\n        \"tx_errors\": 0,\n        \"tx_packets\": 9\n      }\n    },\n    \"memory_stats\": {\n      \"stats\": {\n        \"cache\": 790528,\n        \"mapped_file\": 618496,\n        \"total_inactive_file\": 782336,\n        \"pgpgout\": 1040,\n        \"rss\": 40960,\n        \"total_mapped_file\": 618496,\n        \"pgpgin\": 1243,\n        \"pgmajfault\": 6,\n        \"total_rss\": 40960,\n        \"hierarchical_memory_limit\": 536870912,\n        \"total_pgfault\": 1298,\n        \"total_active_file\": 8192,\n        \"active_anon\": 40960,\n        \"total_active_anon\": 40960,\n        \"total_pgpgout\": 1040,\n        \"total_cache\": 790528,\n        \"active_file\": 8192,\n        \"pgfault\": 1298,\n        \"inactive_file\": 782336,\n        \"total_pgpgin\": 1243,\n        \"hierarchical_memsw_limit\": 9223372036854772000\n      },\n      \"max_usage\": 4825088,\n      \"usage\": 1343488,\n      \"limit\": 1033658368\n    },\n    \"blkio_stats\": {\n      \"io_service_bytes_recursive\": [\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Read\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Sync\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Total\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Read\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Sync\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Total\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Read\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Sync\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Total\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Read\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Sync\",\n          \"value\": 790528\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Total\",\n          \"value\": 790528\n        }\n      ],\n      \"io_serviced_recursive\": [\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Read\",\n          \"value\": 10\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Sync\",\n          \"value\": 10\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Total\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Read\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Sync\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Total\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Read\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Sync\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Total\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Read\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Sync\",\n          \"value\": 10\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 4,\n          \"op\": \"Total\",\n          \"value\": 10\n        }\n      ]\n    },\n    \"cpu_stats\": {\n      \"cpu_usage\": {\n        \"percpu_usage\": [\n          26426156,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0\n        ],\n        \"usage_in_usermode\": 20000000,\n        \"total_usage\": 26426156\n      },\n      \"system_cpu_usage\": 2336100000000,\n      \"online_cpus\": 1,\n      \"throttling_data\": {}\n    },\n    \"precpu_stats\": {\n      \"cpu_usage\": {\n        \"percpu_usage\": [\n          26426156,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0\n        ],\n        \"usage_in_usermode\": 20000000,\n        \"total_usage\": 26426156\n      },\n      \"system_cpu_usage\": 2335090000000,\n      \"online_cpus\": 1,\n      \"throttling_data\": {}\n    },\n    \"storage_stats\": {}\n  },\n  \"fffe894e232d46c76475cfeabf4907f712e8b92618a37fca3ef0805bbbfb0299\": {\n    \"read\": \"2018-11-19T15:40:00.93733207Z\",\n    \"preread\": \"2018-11-19T15:39:59.934291009Z\",\n    \"num_procs\": 0,\n    \"pids_stats\": {},\n    \"network\": {},\n    \"memory_stats\": {\n      \"stats\": {\n        \"cache\": 5787648,\n        \"mapped_file\": 3616768,\n        \"total_inactive_file\": 4321280,\n        \"pgpgout\": 1674,\n        \"rss\": 1597440,\n        \"total_mapped_file\": 3616768,\n        \"pgpgin\": 3477,\n        \"pgmajfault\": 40,\n        \"total_rss\": 1597440,\n        \"total_inactive_anon\": 4096,\n        \"hierarchical_memory_limit\": 536870912,\n        \"total_pgfault\": 2924,\n        \"total_active_file\": 1462272,\n        \"active_anon\": 1597440,\n        \"total_active_anon\": 1597440,\n        \"total_pgpgout\": 1674,\n        \"total_cache\": 5787648,\n        \"inactive_anon\": 4096,\n        \"active_file\": 1462272,\n        \"pgfault\": 2924,\n        \"inactive_file\": 4321280,\n        \"total_pgpgin\": 3477,\n        \"hierarchical_memsw_limit\": 9223372036854772000\n      },\n      \"max_usage\": 8667136,\n      \"usage\": 8179712,\n      \"limit\": 1033658368\n    },\n    \"blkio_stats\": {\n      \"io_service_bytes_recursive\": [\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Read\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Sync\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Total\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Read\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Sync\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Total\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Read\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Sync\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Total\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Read\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Sync\",\n          \"value\": 5730304\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Total\",\n          \"value\": 5730304\n        }\n      ],\n      \"io_serviced_recursive\": [\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Read\",\n          \"value\": 156\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Sync\",\n          \"value\": 156\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 202,\n          \"minor\": 26368,\n          \"op\": \"Total\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Read\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Sync\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 1,\n          \"op\": \"Total\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Read\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Sync\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 2,\n          \"op\": \"Total\",\n          \"value\": 156\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Read\",\n          \"value\": 147\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Write\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Sync\",\n          \"value\": 147\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Async\"\n        },\n        {\n          \"major\": 253,\n          \"minor\": 5,\n          \"op\": \"Total\",\n          \"value\": 147\n        }\n      ]\n    },\n    \"cpu_stats\": {\n      \"cpu_usage\": {\n        \"percpu_usage\": [\n          65599511,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0\n        ],\n        \"usage_in_usermode\": 40000000,\n        \"total_usage\": 65599511,\n        \"usage_in_kernelmode\": 10000000\n      },\n      \"system_cpu_usage\": 2336100000000,\n      \"online_cpus\": 1,\n      \"throttling_data\": {}\n    },\n    \"precpu_stats\": {\n      \"cpu_usage\": {\n        \"percpu_usage\": [\n          65599511,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0\n        ],\n        \"usage_in_usermode\": 40000000,\n        \"total_usage\": 65599511,\n        \"usage_in_kernelmode\": 10000000\n      },\n      \"system_cpu_usage\": 2335090000000,\n      \"online_cpus\": 1,\n      \"throttling_data\": {}\n    },\n    \"storage_stats\": {}\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/types.go",
    "content": "package ecs\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types/container\"\n)\n\n// ecsTask is the ECS task representation\ntype ecsTask struct {\n\tCluster       string\n\tTaskARN       string\n\tFamily        string\n\tRevision      string\n\tDesiredStatus string\n\tKnownStatus   string\n\tContainers    []ecsContainer\n\tLimits        map[string]float64\n\tPullStartedAt time.Time\n\tPullStoppedAt time.Time\n}\n\n// ecsContainer is the ECS metadata container representation\ntype ecsContainer struct {\n\tID            string `json:\"DockerId\"`\n\tName          string\n\tDockerName    string\n\tImage         string\n\tImageID       string\n\tLabels        map[string]string\n\tDesiredStatus string\n\tKnownStatus   string\n\tLimits        map[string]float64\n\tCreatedAt     time.Time\n\tStartedAt     time.Time\n\tStats         container.StatsResponse\n\tType          string\n\tNetworks      []network\n}\n\n// network is a docker network configuration\ntype network struct {\n\tNetworkMode   string\n\tIPv4Addresses []string\n}\n\nfunc unmarshalTask(r io.Reader) (*ecsTask, error) {\n\ttask := &ecsTask{}\n\terr := json.NewDecoder(r).Decode(task)\n\treturn task, err\n}\n\n// docker parsers\nfunc unmarshalStats(r io.Reader) (map[string]*container.StatsResponse, error) {\n\tvar statsMap map[string]*container.StatsResponse\n\tif err := json.NewDecoder(r).Decode(&statsMap); err != nil {\n\t\treturn nil, err\n\t}\n\treturn statsMap, nil\n}\n\n// interleaves Stats in to the Container objects in the ecsTask\nfunc mergeTaskStats(task *ecsTask, stats map[string]*container.StatsResponse) {\n\tfor i := range task.Containers {\n\t\tc := &task.Containers[i]\n\t\tif strings.Trim(c.ID, \" \") == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tstat, ok := stats[c.ID]\n\t\tif !ok || stat == nil {\n\t\t\tcontinue\n\t\t}\n\t\tc.Stats = *stat\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ecs/types_test.go",
    "content": "package ecs\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_parseTask(t *testing.T) {\n\tr, err := os.Open(\"testdata/metadata.golden\")\n\trequire.NoError(t, err)\n\n\tparsed, err := unmarshalTask(r)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, validMeta, *parsed)\n}\n\nfunc Test_parseStats(t *testing.T) {\n\tr, err := os.Open(\"testdata/stats.golden\")\n\trequire.NoError(t, err)\n\n\tparsed, err := unmarshalStats(r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, validStats, parsed)\n}\n\nfunc Test_mergeTaskStats(t *testing.T) {\n\tmetadata, err := os.Open(\"testdata/metadata.golden\")\n\trequire.NoError(t, err)\n\n\tparsedMetadata, err := unmarshalTask(metadata)\n\trequire.NoError(t, err)\n\n\tstats, err := os.Open(\"testdata/stats.golden\")\n\trequire.NoError(t, err)\n\n\tparsedStats, err := unmarshalStats(stats)\n\trequire.NoError(t, err)\n\n\tmergeTaskStats(parsedMetadata, parsedStats)\n\n\tfor i := range parsedMetadata.Containers {\n\t\trequire.Equal(t, validStats[parsedMetadata.Containers[i].ID], &parsedMetadata.Containers[i].Stats)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch/README.md",
    "content": "# Elasticsearch Input Plugin\n\nThis plugin queries endpoints of a [Elasticsearch][elastic] instance to obtain\n[node statistics][node_stats] and optionally [cluster-health][cluster_health]\nmetrics.\nAdditionally, the plugin is able to query [cluster][cluster_stats],\n[indices and shard][indices_stats] statistics for the master node.\n\n> [!NOTE]\n> Specific statistics information can change between Elasticsearch versions. In\n> general, this plugin attempts to stay as version-generic as possible by\n> tagging high-level categories only and creating unique field names of\n> whatever statistics names are provided at the mid-low level.\n\n⭐ Telegraf v0.1.5\n🏷️ server\n💻 all\n\n[elastic]: https://www.elastic.co/\n[node_stats]: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-stats.html\n[cluster_health]: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html\n[cluster_stats]: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-stats.html\n[indices_stats]: https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-stats.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read stats from one or more Elasticsearch servers or clusters\n[[inputs.elasticsearch]]\n  ## specify a list of one or more Elasticsearch servers\n  ## you can add username and password to your url to use basic authentication:\n  ## servers = [\"http://user:pass@localhost:9200\"]\n  servers = [\"http://localhost:9200\"]\n\n  ## HTTP headers to send with each request\n  # headers = { \"X-Custom-Header\" = \"Custom\" }\n\n  ## When local is true (the default), the node will read only its own stats.\n  ## Set local to false when you want to read the node stats from all nodes\n  ## of the cluster.\n  local = true\n\n  ## Set cluster_health to true when you want to obtain cluster health stats\n  cluster_health = false\n\n  ## Adjust cluster_health_level when you want to obtain detailed health stats\n  ## The options are\n  ##  - indices (default)\n  ##  - cluster\n  # cluster_health_level = \"indices\"\n\n  ## Set cluster_stats to true when you want to obtain cluster stats.\n  cluster_stats = false\n\n  ## Only gather cluster_stats from the master node.\n  ## To work this require local = true\n  cluster_stats_only_from_master = true\n\n  ## Gather stats from the enrich API\n  # enrich_stats = false\n\n  ## Indices to collect; can be one or more indices names or _all\n  ## Use of wildcards is allowed. Use a wildcard at the end to retrieve index\n  ## names that end with a changing value, like a date.\n  indices_include = [\"_all\"]\n\n  ## One of \"shards\", \"cluster\", \"indices\"\n  ## Currently only \"shards\" is implemented\n  indices_level = \"shards\"\n\n  ## node_stats is a list of sub-stats that you want to have gathered.\n  ## Valid options are \"indices\", \"os\", \"process\", \"jvm\", \"thread_pool\",\n  ## \"fs\", \"transport\", \"http\", \"breaker\". Per default, all stats are gathered.\n  # node_stats = [\"jvm\", \"http\"]\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## Sets the number of most recent indices to return for indices that are\n  ## configured with a date-stamped suffix. Each 'indices_include' entry\n  ## ending with a wildcard (*) or glob matching pattern will group together\n  ## all indices that match it, and  sort them by the date or number after\n  ## the wildcard. Metrics then are gathered for only the\n  ## 'num_most_recent_indices' amount of most  recent indices.\n  # num_most_recent_indices = 0\n```\n\n## Metrics\n\nEmitted when `cluster_health = true`:\n\n- elasticsearch_cluster_health\n  - tags:\n    - name\n  - fields:\n    - active_primary_shards (integer)\n    - active_shards (integer)\n    - active_shards_percent_as_number (float)\n    - delayed_unassigned_shards (integer)\n    - initializing_shards (integer)\n    - number_of_data_nodes (integer)\n    - number_of_in_flight_fetch (integer)\n    - number_of_nodes (integer)\n    - number_of_pending_tasks (integer)\n    - relocating_shards (integer)\n    - status (string, one of green, yellow or red)\n    - status_code (integer, green = 1, yellow = 2, red = 3),\n    - task_max_waiting_in_queue_millis (integer)\n    - timed_out (boolean)\n    - unassigned_shards (integer)\n\nEmitted when `cluster_health = true` and `cluster_health_level = \"indices\"`:\n\n- elasticsearch_cluster_health_indices\n  - tags:\n    - index\n    - name\n  - fields:\n    - active_primary_shards (integer)\n    - active_shards (integer)\n    - initializing_shards (integer)\n    - number_of_replicas (integer)\n    - number_of_shards (integer)\n    - relocating_shards (integer)\n    - status (string, one of green, yellow or red)\n    - status_code (integer, green = 1, yellow = 2, red = 3),\n    - unassigned_shards (integer)\n\nEmitted when `cluster_stats = true`:\n\n- elasticsearch_clusterstats_indices\n  - tags:\n    - cluster_name\n    - node_name\n    - status\n  - fields:\n    - completion_size_in_bytes (float)\n    - count (float)\n    - docs_count (float)\n    - docs_deleted (float)\n    - fielddata_evictions (float)\n    - fielddata_memory_size_in_bytes (float)\n    - query_cache_cache_count (float)\n    - query_cache_cache_size (float)\n    - query_cache_evictions (float)\n    - query_cache_hit_count (float)\n    - query_cache_memory_size_in_bytes (float)\n    - query_cache_miss_count (float)\n    - query_cache_total_count (float)\n    - segments_count (float)\n    - segments_doc_values_memory_in_bytes (float)\n    - segments_fixed_bit_set_memory_in_bytes (float)\n    - segments_index_writer_memory_in_bytes (float)\n    - segments_max_unsafe_auto_id_timestamp (float)\n    - segments_memory_in_bytes (float)\n    - segments_norms_memory_in_bytes (float)\n    - segments_points_memory_in_bytes (float)\n    - segments_stored_fields_memory_in_bytes (float)\n    - segments_term_vectors_memory_in_bytes (float)\n    - segments_terms_memory_in_bytes (float)\n    - segments_version_map_memory_in_bytes (float)\n    - shards_index_primaries_avg (float)\n    - shards_index_primaries_max (float)\n    - shards_index_primaries_min (float)\n    - shards_index_replication_avg (float)\n    - shards_index_replication_max (float)\n    - shards_index_replication_min (float)\n    - shards_index_shards_avg (float)\n    - shards_index_shards_max (float)\n    - shards_index_shards_min (float)\n    - shards_primaries (float)\n    - shards_replication (float)\n    - shards_total (float)\n    - store_size_in_bytes (float)\n\n- elasticsearch_clusterstats_nodes\n  - tags:\n    - cluster_name\n    - node_name\n    - status\n  - fields:\n    - count_coordinating_only (float)\n    - count_data (float)\n    - count_ingest (float)\n    - count_master (float)\n    - count_total (float)\n    - fs_available_in_bytes (float)\n    - fs_free_in_bytes (float)\n    - fs_total_in_bytes (float)\n    - jvm_max_uptime_in_millis (float)\n    - jvm_mem_heap_max_in_bytes (float)\n    - jvm_mem_heap_used_in_bytes (float)\n    - jvm_threads (float)\n    - jvm_versions_0_count (float)\n    - jvm_versions_0_version (string)\n    - jvm_versions_0_vm_name (string)\n    - jvm_versions_0_vm_vendor (string)\n    - jvm_versions_0_vm_version (string)\n    - network_types_http_types_security4 (float)\n    - network_types_transport_types_security4 (float)\n    - os_allocated_processors (float)\n    - os_available_processors (float)\n    - os_mem_free_in_bytes (float)\n    - os_mem_free_percent (float)\n    - os_mem_total_in_bytes (float)\n    - os_mem_used_in_bytes (float)\n    - os_mem_used_percent (float)\n    - os_names_0_count (float)\n    - os_names_0_name (string)\n    - os_pretty_names_0_count (float)\n    - os_pretty_names_0_pretty_name (string)\n    - process_cpu_percent (float)\n    - process_open_file_descriptors_avg (float)\n    - process_open_file_descriptors_max (float)\n    - process_open_file_descriptors_min (float)\n    - versions_0 (string)\n\nEmitted when the appropriate `node_stats` options are set.\n\n- elasticsearch_transport\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - rx_count (float)\n    - rx_size_in_bytes (float)\n    - server_open (float)\n    - tx_count (float)\n    - tx_size_in_bytes (float)\n\n- elasticsearch_breakers\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - accounting_estimated_size_in_bytes (float)\n    - accounting_limit_size_in_bytes (float)\n    - accounting_overhead (float)\n    - accounting_tripped (float)\n    - fielddata_estimated_size_in_bytes (float)\n    - fielddata_limit_size_in_bytes (float)\n    - fielddata_overhead (float)\n    - fielddata_tripped (float)\n    - in_flight_requests_estimated_size_in_bytes (float)\n    - in_flight_requests_limit_size_in_bytes (float)\n    - in_flight_requests_overhead (float)\n    - in_flight_requests_tripped (float)\n    - parent_estimated_size_in_bytes (float)\n    - parent_limit_size_in_bytes (float)\n    - parent_overhead (float)\n    - parent_tripped (float)\n    - request_estimated_size_in_bytes (float)\n    - request_limit_size_in_bytes (float)\n    - request_overhead (float)\n    - request_tripped (float)\n\n- elasticsearch_fs\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - data_0_available_in_bytes (float)\n    - data_0_free_in_bytes (float)\n    - data_0_total_in_bytes (float)\n    - io_stats_devices_0_operations (float)\n    - io_stats_devices_0_read_kilobytes (float)\n    - io_stats_devices_0_read_operations (float)\n    - io_stats_devices_0_write_kilobytes (float)\n    - io_stats_devices_0_write_operations (float)\n    - io_stats_total_operations (float)\n    - io_stats_total_read_kilobytes (float)\n    - io_stats_total_read_operations (float)\n    - io_stats_total_write_kilobytes (float)\n    - io_stats_total_write_operations (float)\n    - timestamp (float)\n    - total_available_in_bytes (float)\n    - total_free_in_bytes (float)\n    - total_total_in_bytes (float)\n\n- elasticsearch_http\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - current_open (float)\n    - total_opened (float)\n\n- elasticsearch_indices\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - completion_size_in_bytes (float)\n    - docs_count (float)\n    - docs_deleted (float)\n    - fielddata_evictions (float)\n    - fielddata_memory_size_in_bytes (float)\n    - flush_periodic (float)\n    - flush_total (float)\n    - flush_total_time_in_millis (float)\n    - get_current (float)\n    - get_exists_time_in_millis (float)\n    - get_exists_total (float)\n    - get_missing_time_in_millis (float)\n    - get_missing_total (float)\n    - get_time_in_millis (float)\n    - get_total (float)\n    - indexing_delete_current (float)\n    - indexing_delete_time_in_millis (float)\n    - indexing_delete_total (float)\n    - indexing_index_current (float)\n    - indexing_index_failed (float)\n    - indexing_index_time_in_millis (float)\n    - indexing_index_total (float)\n    - indexing_noop_update_total (float)\n    - indexing_throttle_time_in_millis (float)\n    - merges_current (float)\n    - merges_current_docs (float)\n    - merges_current_size_in_bytes (float)\n    - merges_total (float)\n    - merges_total_auto_throttle_in_bytes (float)\n    - merges_total_docs (float)\n    - merges_total_size_in_bytes (float)\n    - merges_total_stopped_time_in_millis (float)\n    - merges_total_throttled_time_in_millis (float)\n    - merges_total_time_in_millis (float)\n    - query_cache_cache_count (float)\n    - query_cache_cache_size (float)\n    - query_cache_evictions (float)\n    - query_cache_hit_count (float)\n    - query_cache_memory_size_in_bytes (float)\n    - query_cache_miss_count (float)\n    - query_cache_total_count (float)\n    - recovery_current_as_source (float)\n    - recovery_current_as_target (float)\n    - recovery_throttle_time_in_millis (float)\n    - refresh_listeners (float)\n    - refresh_total (float)\n    - refresh_total_time_in_millis (float)\n    - request_cache_evictions (float)\n    - request_cache_hit_count (float)\n    - request_cache_memory_size_in_bytes (float)\n    - request_cache_miss_count (float)\n    - search_fetch_current (float)\n    - search_fetch_time_in_millis (float)\n    - search_fetch_total (float)\n    - search_open_contexts (float)\n    - search_query_current (float)\n    - search_query_time_in_millis (float)\n    - search_query_total (float)\n    - search_scroll_current (float)\n    - search_scroll_time_in_millis (float)\n    - search_scroll_total (float)\n    - search_suggest_current (float)\n    - search_suggest_time_in_millis (float)\n    - search_suggest_total (float)\n    - segments_count (float)\n    - segments_doc_values_memory_in_bytes (float)\n    - segments_fixed_bit_set_memory_in_bytes (float)\n    - segments_index_writer_memory_in_bytes (float)\n    - segments_max_unsafe_auto_id_timestamp (float)\n    - segments_memory_in_bytes (float)\n    - segments_norms_memory_in_bytes (float)\n    - segments_points_memory_in_bytes (float)\n    - segments_stored_fields_memory_in_bytes (float)\n    - segments_term_vectors_memory_in_bytes (float)\n    - segments_terms_memory_in_bytes (float)\n    - segments_version_map_memory_in_bytes (float)\n    - store_size_in_bytes (float)\n    - translog_earliest_last_modified_age (float)\n    - translog_operations (float)\n    - translog_size_in_bytes (float)\n    - translog_uncommitted_operations (float)\n    - translog_uncommitted_size_in_bytes (float)\n    - warmer_current (float)\n    - warmer_total (float)\n    - warmer_total_time_in_millis (float)\n\n- elasticsearch_jvm\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - buffer_pools_direct_count (float)\n    - buffer_pools_direct_total_capacity_in_bytes (float)\n    - buffer_pools_direct_used_in_bytes (float)\n    - buffer_pools_mapped_count (float)\n    - buffer_pools_mapped_total_capacity_in_bytes (float)\n    - buffer_pools_mapped_used_in_bytes (float)\n    - classes_current_loaded_count (float)\n    - classes_total_loaded_count (float)\n    - classes_total_unloaded_count (float)\n    - gc_collectors_old_collection_count (float)\n    - gc_collectors_old_collection_time_in_millis (float)\n    - gc_collectors_young_collection_count (float)\n    - gc_collectors_young_collection_time_in_millis (float)\n    - mem_heap_committed_in_bytes (float)\n    - mem_heap_max_in_bytes (float)\n    - mem_heap_used_in_bytes (float)\n    - mem_heap_used_percent (float)\n    - mem_non_heap_committed_in_bytes (float)\n    - mem_non_heap_used_in_bytes (float)\n    - mem_pools_old_max_in_bytes (float)\n    - mem_pools_old_peak_max_in_bytes (float)\n    - mem_pools_old_peak_used_in_bytes (float)\n    - mem_pools_old_used_in_bytes (float)\n    - mem_pools_survivor_max_in_bytes (float)\n    - mem_pools_survivor_peak_max_in_bytes (float)\n    - mem_pools_survivor_peak_used_in_bytes (float)\n    - mem_pools_survivor_used_in_bytes (float)\n    - mem_pools_young_max_in_bytes (float)\n    - mem_pools_young_peak_max_in_bytes (float)\n    - mem_pools_young_peak_used_in_bytes (float)\n    - mem_pools_young_used_in_bytes (float)\n    - threads_count (float)\n    - threads_peak_count (float)\n    - timestamp (float)\n    - uptime_in_millis (float)\n\n- elasticsearch_os\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - cgroup_cpu_cfs_period_micros (float)\n    - cgroup_cpu_cfs_quota_micros (float)\n    - cgroup_cpu_stat_number_of_elapsed_periods (float)\n    - cgroup_cpu_stat_number_of_times_throttled (float)\n    - cgroup_cpu_stat_time_throttled_nanos (float)\n    - cgroup_cpuacct_usage_nanos (float)\n    - cpu_load_average_15m (float)\n    - cpu_load_average_1m (float)\n    - cpu_load_average_5m (float)\n    - cpu_percent (float)\n    - mem_free_in_bytes (float)\n    - mem_free_percent (float)\n    - mem_total_in_bytes (float)\n    - mem_used_in_bytes (float)\n    - mem_used_percent (float)\n    - swap_free_in_bytes (float)\n    - swap_total_in_bytes (float)\n    - swap_used_in_bytes (float)\n    - timestamp (float)\n\n- elasticsearch_process\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - cpu_percent (float)\n    - cpu_total_in_millis (float)\n    - max_file_descriptors (float)\n    - mem_total_virtual_in_bytes (float)\n    - open_file_descriptors (float)\n    - timestamp (float)\n\n- elasticsearch_thread_pool\n  - tags:\n    - cluster_name\n    - node_attribute_ml.enabled\n    - node_attribute_ml.machine_memory\n    - node_attribute_ml.max_open_jobs\n    - node_attribute_xpack.installed\n    - node_host\n    - node_id\n    - node_name\n  - fields:\n    - analyze_active (float)\n    - analyze_completed (float)\n    - analyze_largest (float)\n    - analyze_queue (float)\n    - analyze_rejected (float)\n    - analyze_threads (float)\n    - ccr_active (float)\n    - ccr_completed (float)\n    - ccr_largest (float)\n    - ccr_queue (float)\n    - ccr_rejected (float)\n    - ccr_threads (float)\n    - fetch_shard_started_active (float)\n    - fetch_shard_started_completed (float)\n    - fetch_shard_started_largest (float)\n    - fetch_shard_started_queue (float)\n    - fetch_shard_started_rejected (float)\n    - fetch_shard_started_threads (float)\n    - fetch_shard_store_active (float)\n    - fetch_shard_store_completed (float)\n    - fetch_shard_store_largest (float)\n    - fetch_shard_store_queue (float)\n    - fetch_shard_store_rejected (float)\n    - fetch_shard_store_threads (float)\n    - flush_active (float)\n    - flush_completed (float)\n    - flush_largest (float)\n    - flush_queue (float)\n    - flush_rejected (float)\n    - flush_threads (float)\n    - force_merge_active (float)\n    - force_merge_completed (float)\n    - force_merge_largest (float)\n    - force_merge_queue (float)\n    - force_merge_rejected (float)\n    - force_merge_threads (float)\n    - generic_active (float)\n    - generic_completed (float)\n    - generic_largest (float)\n    - generic_queue (float)\n    - generic_rejected (float)\n    - generic_threads (float)\n    - get_active (float)\n    - get_completed (float)\n    - get_largest (float)\n    - get_queue (float)\n    - get_rejected (float)\n    - get_threads (float)\n    - index_active (float)\n    - index_completed (float)\n    - index_largest (float)\n    - index_queue (float)\n    - index_rejected (float)\n    - index_threads (float)\n    - listener_active (float)\n    - listener_completed (float)\n    - listener_largest (float)\n    - listener_queue (float)\n    - listener_rejected (float)\n    - listener_threads (float)\n    - management_active (float)\n    - management_completed (float)\n    - management_largest (float)\n    - management_queue (float)\n    - management_rejected (float)\n    - management_threads (float)\n    - ml_autodetect_active (float)\n    - ml_autodetect_completed (float)\n    - ml_autodetect_largest (float)\n    - ml_autodetect_queue (float)\n    - ml_autodetect_rejected (float)\n    - ml_autodetect_threads (float)\n    - ml_datafeed_active (float)\n    - ml_datafeed_completed (float)\n    - ml_datafeed_largest (float)\n    - ml_datafeed_queue (float)\n    - ml_datafeed_rejected (float)\n    - ml_datafeed_threads (float)\n    - ml_utility_active (float)\n    - ml_utility_completed (float)\n    - ml_utility_largest (float)\n    - ml_utility_queue (float)\n    - ml_utility_rejected (float)\n    - ml_utility_threads (float)\n    - refresh_active (float)\n    - refresh_completed (float)\n    - refresh_largest (float)\n    - refresh_queue (float)\n    - refresh_rejected (float)\n    - refresh_threads (float)\n    - rollup_indexing_active (float)\n    - rollup_indexing_completed (float)\n    - rollup_indexing_largest (float)\n    - rollup_indexing_queue (float)\n    - rollup_indexing_rejected (float)\n    - rollup_indexing_threads (float)\n    - search_active (float)\n    - search_completed (float)\n    - search_largest (float)\n    - search_queue (float)\n    - search_rejected (float)\n    - search_threads (float)\n    - search_throttled_active (float)\n    - search_throttled_completed (float)\n    - search_throttled_largest (float)\n    - search_throttled_queue (float)\n    - search_throttled_rejected (float)\n    - search_throttled_threads (float)\n    - security-token-key_active (float)\n    - security-token-key_completed (float)\n    - security-token-key_largest (float)\n    - security-token-key_queue (float)\n    - security-token-key_rejected (float)\n    - security-token-key_threads (float)\n    - snapshot_active (float)\n    - snapshot_completed (float)\n    - snapshot_largest (float)\n    - snapshot_queue (float)\n    - snapshot_rejected (float)\n    - snapshot_threads (float)\n    - warmer_active (float)\n    - warmer_completed (float)\n    - warmer_largest (float)\n    - warmer_queue (float)\n    - warmer_rejected (float)\n    - warmer_threads (float)\n    - watcher_active (float)\n    - watcher_completed (float)\n    - watcher_largest (float)\n    - watcher_queue (float)\n    - watcher_rejected (float)\n    - watcher_threads (float)\n    - write_active (float)\n    - write_completed (float)\n    - write_largest (float)\n    - write_queue (float)\n    - write_rejected (float)\n    - write_threads (float)\n\nEmitted when the appropriate `indices_stats` options are set.\n\n- elasticsearch_indices_stats_(primaries|total)\n  - tags:\n    - index_name\n  - fields:\n    - completion_size_in_bytes (float)\n    - docs_count (float)\n    - docs_deleted (float)\n    - fielddata_evictions (float)\n    - fielddata_memory_size_in_bytes (float)\n    - flush_periodic (float)\n    - flush_total (float)\n    - flush_total_time_in_millis (float)\n    - get_current (float)\n    - get_exists_time_in_millis (float)\n    - get_exists_total (float)\n    - get_missing_time_in_millis (float)\n    - get_missing_total (float)\n    - get_time_in_millis (float)\n    - get_total (float)\n    - indexing_delete_current (float)\n    - indexing_delete_time_in_millis (float)\n    - indexing_delete_total (float)\n    - indexing_index_current (float)\n    - indexing_index_failed (float)\n    - indexing_index_time_in_millis (float)\n    - indexing_index_total (float)\n    - indexing_is_throttled (float)\n    - indexing_noop_update_total (float)\n    - indexing_throttle_time_in_millis (float)\n    - merges_current (float)\n    - merges_current_docs (float)\n    - merges_current_size_in_bytes (float)\n    - merges_total (float)\n    - merges_total_auto_throttle_in_bytes (float)\n    - merges_total_docs (float)\n    - merges_total_size_in_bytes (float)\n    - merges_total_stopped_time_in_millis (float)\n    - merges_total_throttled_time_in_millis (float)\n    - merges_total_time_in_millis (float)\n    - query_cache_cache_count (float)\n    - query_cache_cache_size (float)\n    - query_cache_evictions (float)\n    - query_cache_hit_count (float)\n    - query_cache_memory_size_in_bytes (float)\n    - query_cache_miss_count (float)\n    - query_cache_total_count (float)\n    - recovery_current_as_source (float)\n    - recovery_current_as_target (float)\n    - recovery_throttle_time_in_millis (float)\n    - refresh_external_total (float)\n    - refresh_external_total_time_in_millis (float)\n    - refresh_listeners (float)\n    - refresh_total (float)\n    - refresh_total_time_in_millis (float)\n    - request_cache_evictions (float)\n    - request_cache_hit_count (float)\n    - request_cache_memory_size_in_bytes (float)\n    - request_cache_miss_count (float)\n    - search_fetch_current (float)\n    - search_fetch_time_in_millis (float)\n    - search_fetch_total (float)\n    - search_open_contexts (float)\n    - search_query_current (float)\n    - search_query_time_in_millis (float)\n    - search_query_total (float)\n    - search_scroll_current (float)\n    - search_scroll_time_in_millis (float)\n    - search_scroll_total (float)\n    - search_suggest_current (float)\n    - search_suggest_time_in_millis (float)\n    - search_suggest_total (float)\n    - segments_count (float)\n    - segments_doc_values_memory_in_bytes (float)\n    - segments_fixed_bit_set_memory_in_bytes (float)\n    - segments_index_writer_memory_in_bytes (float)\n    - segments_max_unsafe_auto_id_timestamp (float)\n    - segments_memory_in_bytes (float)\n    - segments_norms_memory_in_bytes (float)\n    - segments_points_memory_in_bytes (float)\n    - segments_stored_fields_memory_in_bytes (float)\n    - segments_term_vectors_memory_in_bytes (float)\n    - segments_terms_memory_in_bytes (float)\n    - segments_version_map_memory_in_bytes (float)\n    - store_size_in_bytes (float)\n    - translog_earliest_last_modified_age (float)\n    - translog_operations (float)\n    - translog_size_in_bytes (float)\n    - translog_uncommitted_operations (float)\n    - translog_uncommitted_size_in_bytes (float)\n    - warmer_current (float)\n    - warmer_total (float)\n    - warmer_total_time_in_millis (float)\n\nEmitted when the appropriate `shards_stats` options are set.\n\n- elasticsearch_indices_stats_shards_total\n  - fields:\n    - failed (float)\n    - successful (float)\n    - total (float)\n\n- elasticsearch_indices_stats_shards\n  - tags:\n    - index_name\n    - node_name\n    - shard_name\n    - type\n  - fields:\n    - commit_generation (float)\n    - commit_num_docs (float)\n    - completion_size_in_bytes (float)\n    - docs_count (float)\n    - docs_deleted (float)\n    - fielddata_evictions (float)\n    - fielddata_memory_size_in_bytes (float)\n    - flush_periodic (float)\n    - flush_total (float)\n    - flush_total_time_in_millis (float)\n    - get_current (float)\n    - get_exists_time_in_millis (float)\n    - get_exists_total (float)\n    - get_missing_time_in_millis (float)\n    - get_missing_total (float)\n    - get_time_in_millis (float)\n    - get_total (float)\n    - indexing_delete_current (float)\n    - indexing_delete_time_in_millis (float)\n    - indexing_delete_total (float)\n    - indexing_index_current (float)\n    - indexing_index_failed (float)\n    - indexing_index_time_in_millis (float)\n    - indexing_index_total (float)\n    - indexing_is_throttled (bool)\n    - indexing_noop_update_total (float)\n    - indexing_throttle_time_in_millis (float)\n    - merges_current (float)\n    - merges_current_docs (float)\n    - merges_current_size_in_bytes (float)\n    - merges_total (float)\n    - merges_total_auto_throttle_in_bytes (float)\n    - merges_total_docs (float)\n    - merges_total_size_in_bytes (float)\n    - merges_total_stopped_time_in_millis (float)\n    - merges_total_throttled_time_in_millis (float)\n    - merges_total_time_in_millis (float)\n    - query_cache_cache_count (float)\n    - query_cache_cache_size (float)\n    - query_cache_evictions (float)\n    - query_cache_hit_count (float)\n    - query_cache_memory_size_in_bytes (float)\n    - query_cache_miss_count (float)\n    - query_cache_total_count (float)\n    - recovery_current_as_source (float)\n    - recovery_current_as_target (float)\n    - recovery_throttle_time_in_millis (float)\n    - refresh_external_total (float)\n    - refresh_external_total_time_in_millis (float)\n    - refresh_listeners (float)\n    - refresh_total (float)\n    - refresh_total_time_in_millis (float)\n    - request_cache_evictions (float)\n    - request_cache_hit_count (float)\n    - request_cache_memory_size_in_bytes (float)\n    - request_cache_miss_count (float)\n    - retention_leases_primary_term (float)\n    - retention_leases_version (float)\n    - routing_state (int)\n      (UNASSIGNED = 1, INITIALIZING = 2, STARTED = 3, RELOCATING = 4, other = 0)\n    - search_fetch_current (float)\n    - search_fetch_time_in_millis (float)\n    - search_fetch_total (float)\n    - search_open_contexts (float)\n    - search_query_current (float)\n    - search_query_time_in_millis (float)\n    - search_query_total (float)\n    - search_scroll_current (float)\n    - search_scroll_time_in_millis (float)\n    - search_scroll_total (float)\n    - search_suggest_current (float)\n    - search_suggest_time_in_millis (float)\n    - search_suggest_total (float)\n    - segments_count (float)\n    - segments_doc_values_memory_in_bytes (float)\n    - segments_fixed_bit_set_memory_in_bytes (float)\n    - segments_index_writer_memory_in_bytes (float)\n    - segments_max_unsafe_auto_id_timestamp (float)\n    - segments_memory_in_bytes (float)\n    - segments_norms_memory_in_bytes (float)\n    - segments_points_memory_in_bytes (float)\n    - segments_stored_fields_memory_in_bytes (float)\n    - segments_term_vectors_memory_in_bytes (float)\n    - segments_terms_memory_in_bytes (float)\n    - segments_version_map_memory_in_bytes (float)\n    - seq_no_global_checkpoint (float)\n    - seq_no_local_checkpoint (float)\n    - seq_no_max_seq_no (float)\n    - shard_path_is_custom_data_path (bool)\n    - store_size_in_bytes (float)\n    - translog_earliest_last_modified_age (float)\n    - translog_operations (float)\n    - translog_size_in_bytes (float)\n    - translog_uncommitted_operations (float)\n    - translog_uncommitted_size_in_bytes (float)\n    - warmer_current (float)\n    - warmer_total (float)\n    - warmer_total_time_in_millis (float)\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/elasticsearch/elasticsearch.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage elasticsearch\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// mask for masking username/password from error messages\nvar mask = regexp.MustCompile(`https?:\\/\\/\\S+:\\S+@`)\n\nconst (\n\t// Node stats are always generated, so simply define a constant for these endpoints\n\tstatsPath      = \"/_nodes/stats\"\n\tstatsPathLocal = \"/_nodes/_local/stats\"\n)\n\ntype Elasticsearch struct {\n\tLocal                      bool              `toml:\"local\"`\n\tServers                    []string          `toml:\"servers\"`\n\tHTTPHeaders                map[string]string `toml:\"headers\"`\n\tClusterHealth              bool              `toml:\"cluster_health\"`\n\tClusterHealthLevel         string            `toml:\"cluster_health_level\"`\n\tClusterStats               bool              `toml:\"cluster_stats\"`\n\tClusterStatsOnlyFromMaster bool              `toml:\"cluster_stats_only_from_master\"`\n\tEnrichStats                bool              `toml:\"enrich_stats\"`\n\tIndicesInclude             []string          `toml:\"indices_include\"`\n\tIndicesLevel               string            `toml:\"indices_level\"`\n\tNodeStats                  []string          `toml:\"node_stats\"`\n\tUsername                   string            `toml:\"username\"`\n\tPassword                   string            `toml:\"password\"`\n\tNumMostRecentIndices       int               `toml:\"num_most_recent_indices\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient *http.Client\n\tcommon_http.HTTPClientConfig\n\n\tserverInfo      map[string]serverInfo\n\tserverInfoMutex sync.Mutex\n\tindexMatchers   map[string]filter.Filter\n}\n\ntype nodeStat struct {\n\tHost       string            `json:\"host\"`\n\tName       string            `json:\"name\"`\n\tRoles      []string          `json:\"roles\"`\n\tAttributes map[string]string `json:\"attributes\"`\n\tIndices    interface{}       `json:\"indices\"`\n\tOS         interface{}       `json:\"os\"`\n\tProcess    interface{}       `json:\"process\"`\n\tJVM        interface{}       `json:\"jvm\"`\n\tThreadPool interface{}       `json:\"thread_pool\"`\n\tFS         interface{}       `json:\"fs\"`\n\tTransport  interface{}       `json:\"transport\"`\n\tHTTP       interface{}       `json:\"http\"`\n\tBreakers   interface{}       `json:\"breakers\"`\n}\n\ntype clusterHealth struct {\n\tActivePrimaryShards         int                    `json:\"active_primary_shards\"`\n\tActiveShards                int                    `json:\"active_shards\"`\n\tActiveShardsPercentAsNumber float64                `json:\"active_shards_percent_as_number\"`\n\tClusterName                 string                 `json:\"cluster_name\"`\n\tDelayedUnassignedShards     int                    `json:\"delayed_unassigned_shards\"`\n\tInitializingShards          int                    `json:\"initializing_shards\"`\n\tNumberOfDataNodes           int                    `json:\"number_of_data_nodes\"`\n\tNumberOfInFlightFetch       int                    `json:\"number_of_in_flight_fetch\"`\n\tNumberOfNodes               int                    `json:\"number_of_nodes\"`\n\tNumberOfPendingTasks        int                    `json:\"number_of_pending_tasks\"`\n\tRelocatingShards            int                    `json:\"relocating_shards\"`\n\tStatus                      string                 `json:\"status\"`\n\tTaskMaxWaitingInQueueMillis int                    `json:\"task_max_waiting_in_queue_millis\"`\n\tTimedOut                    bool                   `json:\"timed_out\"`\n\tUnassignedShards            int                    `json:\"unassigned_shards\"`\n\tIndices                     map[string]indexHealth `json:\"indices\"`\n}\n\ntype enrichStats struct {\n\tCoordinatorStats []struct {\n\t\tNodeID                string `json:\"node_id\"`\n\t\tQueueSize             int    `json:\"queue_size\"`\n\t\tRemoteRequestsCurrent int    `json:\"remote_requests_current\"`\n\t\tRemoteRequestsTotal   int    `json:\"remote_requests_total\"`\n\t\tExecutedSearchesTotal int    `json:\"executed_searches_total\"`\n\t} `json:\"coordinator_stats\"`\n\tCacheStats []struct {\n\t\tNodeID    string `json:\"node_id\"`\n\t\tCount     int    `json:\"count\"`\n\t\tHits      int64  `json:\"hits\"`\n\t\tMisses    int    `json:\"misses\"`\n\t\tEvictions int    `json:\"evictions\"`\n\t} `json:\"cache_stats\"`\n}\n\ntype indexHealth struct {\n\tActivePrimaryShards int    `json:\"active_primary_shards\"`\n\tActiveShards        int    `json:\"active_shards\"`\n\tInitializingShards  int    `json:\"initializing_shards\"`\n\tNumberOfReplicas    int    `json:\"number_of_replicas\"`\n\tNumberOfShards      int    `json:\"number_of_shards\"`\n\tRelocatingShards    int    `json:\"relocating_shards\"`\n\tStatus              string `json:\"status\"`\n\tUnassignedShards    int    `json:\"unassigned_shards\"`\n}\n\ntype clusterStats struct {\n\tNodeName    string      `json:\"node_name\"`\n\tClusterName string      `json:\"cluster_name\"`\n\tStatus      string      `json:\"status\"`\n\tIndices     interface{} `json:\"indices\"`\n\tNodes       interface{} `json:\"nodes\"`\n}\n\ntype indexStat struct {\n\tPrimaries interface{}              `json:\"primaries\"`\n\tTotal     interface{}              `json:\"total\"`\n\tShards    map[string][]interface{} `json:\"shards\"`\n}\ntype serverInfo struct {\n\tnodeID   string\n\tmasterID string\n}\n\nfunc (*Elasticsearch) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (e *Elasticsearch) Init() error {\n\t// Compile the configured indexes to match for sorting.\n\tindexMatchers, err := e.compileIndexMatchers()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\te.indexMatchers = indexMatchers\n\n\treturn nil\n}\n\nfunc (*Elasticsearch) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (e *Elasticsearch) Gather(acc telegraf.Accumulator) error {\n\tif e.client == nil {\n\t\tclient, err := e.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\te.client = client\n\t}\n\n\tif e.ClusterStats || len(e.IndicesInclude) > 0 || len(e.IndicesLevel) > 0 {\n\t\tvar wgC sync.WaitGroup\n\t\twgC.Add(len(e.Servers))\n\n\t\te.serverInfo = make(map[string]serverInfo)\n\t\tfor _, serv := range e.Servers {\n\t\t\tgo func(s string, acc telegraf.Accumulator) {\n\t\t\t\tdefer wgC.Done()\n\t\t\t\tinfo := serverInfo{}\n\n\t\t\t\tvar err error\n\n\t\t\t\t// Gather node ID\n\t\t\t\tif info.nodeID, err = e.gatherNodeID(s + \"/_nodes/_local/name\"); err != nil {\n\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// get cat/master information here so NodeStats can determine\n\t\t\t\t// whether this node is the Master\n\t\t\t\tif info.masterID, err = e.getCatMaster(s + \"/_cat/master\"); err != nil {\n\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\te.serverInfoMutex.Lock()\n\t\t\t\te.serverInfo[s] = info\n\t\t\t\te.serverInfoMutex.Unlock()\n\t\t\t}(serv, acc)\n\t\t}\n\t\twgC.Wait()\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(e.Servers))\n\n\tfor _, serv := range e.Servers {\n\t\tgo func(s string, acc telegraf.Accumulator) {\n\t\t\tdefer wg.Done()\n\t\t\turl := e.nodeStatsURL(s)\n\n\t\t\t// Always gather node stats\n\t\t\tif err := e.gatherNodeStats(url, acc); err != nil {\n\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif e.ClusterHealth {\n\t\t\t\turl = s + \"/_cluster/health\"\n\t\t\t\tif e.ClusterHealthLevel != \"\" {\n\t\t\t\t\turl = url + \"?level=\" + e.ClusterHealthLevel\n\t\t\t\t}\n\t\t\t\tif err := e.gatherClusterHealth(url, acc); err != nil {\n\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif e.ClusterStats && (e.serverInfo[s].isMaster() || !e.ClusterStatsOnlyFromMaster || !e.Local) {\n\t\t\t\tif err := e.gatherClusterStats(s+\"/_cluster/stats\", acc); err != nil {\n\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(e.IndicesInclude) > 0 && (e.serverInfo[s].isMaster() || !e.ClusterStatsOnlyFromMaster || !e.Local) {\n\t\t\t\tif e.IndicesLevel != \"shards\" {\n\t\t\t\t\tif err := e.gatherIndicesStats(s+\"/\"+strings.Join(e.IndicesInclude, \",\")+\"/_stats\", acc); err != nil {\n\t\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err := e.gatherIndicesStats(s+\"/\"+strings.Join(e.IndicesInclude, \",\")+\"/_stats?level=shards\", acc); err != nil {\n\t\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif e.EnrichStats {\n\t\t\t\tif err := e.gatherEnrichStats(s+\"/_enrich/_stats\", acc); err != nil {\n\t\t\t\t\tacc.AddError(errors.New(mask.ReplaceAllString(err.Error(), \"http(s)://XXX:XXX@\")))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(serv, acc)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (e *Elasticsearch) Stop() {\n\tif e.client != nil {\n\t\te.client.CloseIdleConnections()\n\t}\n}\n\nfunc (e *Elasticsearch) createHTTPClient() (*http.Client, error) {\n\tctx := context.Background()\n\treturn e.HTTPClientConfig.CreateClient(ctx, e.Log)\n}\n\nfunc (e *Elasticsearch) nodeStatsURL(baseURL string) string {\n\tvar url string\n\n\tif e.Local {\n\t\turl = baseURL + statsPathLocal\n\t} else {\n\t\turl = baseURL + statsPath\n\t}\n\n\tif len(e.NodeStats) == 0 {\n\t\treturn url\n\t}\n\n\treturn fmt.Sprintf(\"%s/%s\", url, strings.Join(e.NodeStats, \",\"))\n}\n\nfunc (e *Elasticsearch) gatherNodeID(url string) (string, error) {\n\tnodeStats := &struct {\n\t\tClusterName string               `json:\"cluster_name\"`\n\t\tNodes       map[string]*nodeStat `json:\"nodes\"`\n\t}{}\n\tif err := e.gatherJSONData(url, nodeStats); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Only 1 should be returned\n\tfor id := range nodeStats.Nodes {\n\t\treturn id, nil\n\t}\n\treturn \"\", nil\n}\n\nfunc (e *Elasticsearch) gatherNodeStats(url string, acc telegraf.Accumulator) error {\n\tnodeStats := &struct {\n\t\tClusterName string               `json:\"cluster_name\"`\n\t\tNodes       map[string]*nodeStat `json:\"nodes\"`\n\t}{}\n\tif err := e.gatherJSONData(url, nodeStats); err != nil {\n\t\treturn err\n\t}\n\n\tfor id, n := range nodeStats.Nodes {\n\t\tsort.Strings(n.Roles)\n\t\ttags := map[string]string{\n\t\t\t\"node_id\":      id,\n\t\t\t\"node_host\":    n.Host,\n\t\t\t\"node_name\":    n.Name,\n\t\t\t\"cluster_name\": nodeStats.ClusterName,\n\t\t\t\"node_roles\":   strings.Join(n.Roles, \",\"),\n\t\t}\n\n\t\tfor k, v := range n.Attributes {\n\t\t\ttags[\"node_attribute_\"+k] = v\n\t\t}\n\n\t\tstats := map[string]interface{}{\n\t\t\t\"indices\":     n.Indices,\n\t\t\t\"os\":          n.OS,\n\t\t\t\"process\":     n.Process,\n\t\t\t\"jvm\":         n.JVM,\n\t\t\t\"thread_pool\": n.ThreadPool,\n\t\t\t\"fs\":          n.FS,\n\t\t\t\"transport\":   n.Transport,\n\t\t\t\"http\":        n.HTTP,\n\t\t\t\"breakers\":    n.Breakers,\n\t\t}\n\n\t\tnow := time.Now()\n\t\tfor p, s := range stats {\n\t\t\t// if one of the individual node stats is not even in the\n\t\t\t// original result\n\t\t\tif s == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tf := parsers_json.JSONFlattener{}\n\t\t\t// parse Json, ignoring strings and bools\n\t\t\terr := f.FlattenJSON(\"\", s)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tacc.AddFields(\"elasticsearch_\"+p, f.Fields, tags, now)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e *Elasticsearch) gatherClusterHealth(url string, acc telegraf.Accumulator) error {\n\thealthStats := &clusterHealth{}\n\tif err := e.gatherJSONData(url, healthStats); err != nil {\n\t\treturn err\n\t}\n\tmeasurementTime := time.Now()\n\tclusterFields := map[string]interface{}{\n\t\t\"active_primary_shards\":            healthStats.ActivePrimaryShards,\n\t\t\"active_shards\":                    healthStats.ActiveShards,\n\t\t\"active_shards_percent_as_number\":  healthStats.ActiveShardsPercentAsNumber,\n\t\t\"delayed_unassigned_shards\":        healthStats.DelayedUnassignedShards,\n\t\t\"initializing_shards\":              healthStats.InitializingShards,\n\t\t\"number_of_data_nodes\":             healthStats.NumberOfDataNodes,\n\t\t\"number_of_in_flight_fetch\":        healthStats.NumberOfInFlightFetch,\n\t\t\"number_of_nodes\":                  healthStats.NumberOfNodes,\n\t\t\"number_of_pending_tasks\":          healthStats.NumberOfPendingTasks,\n\t\t\"relocating_shards\":                healthStats.RelocatingShards,\n\t\t\"status\":                           healthStats.Status,\n\t\t\"status_code\":                      mapHealthStatusToCode(healthStats.Status),\n\t\t\"task_max_waiting_in_queue_millis\": healthStats.TaskMaxWaitingInQueueMillis,\n\t\t\"timed_out\":                        healthStats.TimedOut,\n\t\t\"unassigned_shards\":                healthStats.UnassignedShards,\n\t}\n\tacc.AddFields(\n\t\t\"elasticsearch_cluster_health\",\n\t\tclusterFields,\n\t\tmap[string]string{\"name\": healthStats.ClusterName},\n\t\tmeasurementTime,\n\t)\n\n\tfor name, health := range healthStats.Indices {\n\t\tindexFields := map[string]interface{}{\n\t\t\t\"active_primary_shards\": health.ActivePrimaryShards,\n\t\t\t\"active_shards\":         health.ActiveShards,\n\t\t\t\"initializing_shards\":   health.InitializingShards,\n\t\t\t\"number_of_replicas\":    health.NumberOfReplicas,\n\t\t\t\"number_of_shards\":      health.NumberOfShards,\n\t\t\t\"relocating_shards\":     health.RelocatingShards,\n\t\t\t\"status\":                health.Status,\n\t\t\t\"status_code\":           mapHealthStatusToCode(health.Status),\n\t\t\t\"unassigned_shards\":     health.UnassignedShards,\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"elasticsearch_cluster_health_indices\",\n\t\t\tindexFields,\n\t\t\tmap[string]string{\"index\": name, \"name\": healthStats.ClusterName},\n\t\t\tmeasurementTime,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (e *Elasticsearch) gatherEnrichStats(url string, acc telegraf.Accumulator) error {\n\tenrichStats := &enrichStats{}\n\tif err := e.gatherJSONData(url, enrichStats); err != nil {\n\t\treturn err\n\t}\n\tmeasurementTime := time.Now()\n\n\tfor _, coordinator := range enrichStats.CoordinatorStats {\n\t\tcoordinatorFields := map[string]interface{}{\n\t\t\t\"queue_size\":              coordinator.QueueSize,\n\t\t\t\"remote_requests_current\": coordinator.RemoteRequestsCurrent,\n\t\t\t\"remote_requests_total\":   coordinator.RemoteRequestsTotal,\n\t\t\t\"executed_searches_total\": coordinator.ExecutedSearchesTotal,\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"elasticsearch_enrich_stats_coordinator\",\n\t\t\tcoordinatorFields,\n\t\t\tmap[string]string{\"node_id\": coordinator.NodeID},\n\t\t\tmeasurementTime,\n\t\t)\n\t}\n\n\tfor _, cache := range enrichStats.CacheStats {\n\t\tcacheFields := map[string]interface{}{\n\t\t\t\"count\":     cache.Count,\n\t\t\t\"hits\":      cache.Hits,\n\t\t\t\"misses\":    cache.Misses,\n\t\t\t\"evictions\": cache.Evictions,\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"elasticsearch_enrich_stats_cache\",\n\t\t\tcacheFields,\n\t\t\tmap[string]string{\"node_id\": cache.NodeID},\n\t\t\tmeasurementTime,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (e *Elasticsearch) gatherClusterStats(url string, acc telegraf.Accumulator) error {\n\tclusterStats := &clusterStats{}\n\tif err := e.gatherJSONData(url, clusterStats); err != nil {\n\t\treturn err\n\t}\n\tnow := time.Now()\n\ttags := map[string]string{\n\t\t\"node_name\":    clusterStats.NodeName,\n\t\t\"cluster_name\": clusterStats.ClusterName,\n\t\t\"status\":       clusterStats.Status,\n\t}\n\n\tstats := map[string]interface{}{\n\t\t\"nodes\":   clusterStats.Nodes,\n\t\t\"indices\": clusterStats.Indices,\n\t}\n\n\tfor p, s := range stats {\n\t\tf := parsers_json.JSONFlattener{}\n\t\t// parse json, including bools and strings\n\t\terr := f.FullFlattenJSON(\"\", s, true, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tacc.AddFields(\"elasticsearch_clusterstats_\"+p, f.Fields, tags, now)\n\t}\n\n\treturn nil\n}\n\nfunc (e *Elasticsearch) gatherIndicesStats(url string, acc telegraf.Accumulator) error {\n\tindicesStats := &struct {\n\t\tShards  map[string]interface{} `json:\"_shards\"`\n\t\tAll     map[string]interface{} `json:\"_all\"`\n\t\tIndices map[string]indexStat   `json:\"indices\"`\n\t}{}\n\n\tif err := e.gatherJSONData(url, indicesStats); err != nil {\n\t\treturn err\n\t}\n\tnow := time.Now()\n\n\t// Total Shards Stats\n\tshardsStats := make(map[string]interface{}, len(indicesStats.Shards))\n\tfor k, v := range indicesStats.Shards {\n\t\tshardsStats[k] = v\n\t}\n\tacc.AddFields(\"elasticsearch_indices_stats_shards_total\", shardsStats, make(map[string]string), now)\n\n\t// All Stats\n\tfor m, s := range indicesStats.All {\n\t\t// parse Json, ignoring strings and bools\n\t\tjsonParser := parsers_json.JSONFlattener{}\n\t\terr := jsonParser.FullFlattenJSON(\"_\", s, true, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tacc.AddFields(\"elasticsearch_indices_stats_\"+m, jsonParser.Fields, map[string]string{\"index_name\": \"_all\"}, now)\n\t}\n\n\t// Gather stats for each index.\n\terr := e.gatherIndividualIndicesStats(indicesStats.Indices, now, acc)\n\n\treturn err\n}\n\n// gatherSortedIndicesStats gathers stats for all indices in no particular order.\nfunc (e *Elasticsearch) gatherIndividualIndicesStats(indices map[string]indexStat, now time.Time, acc telegraf.Accumulator) error {\n\t// Sort indices into buckets based on their configured prefix, if any matches.\n\tcategorizedIndexNames := e.categorizeIndices(indices)\n\tfor _, matchingIndices := range categorizedIndexNames {\n\t\t// Establish the number of each category of indices to use. User can configure to use only the latest 'X' amount.\n\t\tindicesCount := len(matchingIndices)\n\t\tindicesToTrackCount := indicesCount\n\n\t\t// Sort the indices if configured to do so.\n\t\tif e.NumMostRecentIndices > 0 {\n\t\t\tif e.NumMostRecentIndices < indicesToTrackCount {\n\t\t\t\tindicesToTrackCount = e.NumMostRecentIndices\n\t\t\t}\n\t\t\tsort.Strings(matchingIndices)\n\t\t}\n\n\t\t// Gather only the number of indexes that have been configured, in descending order (most recent, if date-stamped).\n\t\tfor i := indicesCount - 1; i >= indicesCount-indicesToTrackCount; i-- {\n\t\t\tindexName := matchingIndices[i]\n\n\t\t\terr := e.gatherSingleIndexStats(indexName, indices[indexName], now, acc)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (e *Elasticsearch) categorizeIndices(indices map[string]indexStat) map[string][]string {\n\tcategorizedIndexNames := make(map[string][]string, len(indices))\n\n\t// If all indices are configured to be gathered, bucket them all together.\n\tif len(e.IndicesInclude) == 0 || e.IndicesInclude[0] == \"_all\" {\n\t\tfor indexName := range indices {\n\t\t\tcategorizedIndexNames[\"_all\"] = append(categorizedIndexNames[\"_all\"], indexName)\n\t\t}\n\n\t\treturn categorizedIndexNames\n\t}\n\n\t// Bucket each returned index with its associated configured index (if any match).\n\tfor indexName := range indices {\n\t\tmatch := indexName\n\t\tfor name, matcher := range e.indexMatchers {\n\t\t\t// If a configured index matches one of the returned indexes, mark it as a match.\n\t\t\tif matcher.Match(match) {\n\t\t\t\tmatch = name\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Bucket all matching indices together for sorting.\n\t\tcategorizedIndexNames[match] = append(categorizedIndexNames[match], indexName)\n\t}\n\n\treturn categorizedIndexNames\n}\n\nfunc (e *Elasticsearch) gatherSingleIndexStats(name string, index indexStat, now time.Time, acc telegraf.Accumulator) error {\n\tindexTag := map[string]string{\"index_name\": name}\n\tstats := map[string]interface{}{\n\t\t\"primaries\": index.Primaries,\n\t\t\"total\":     index.Total,\n\t}\n\tfor m, s := range stats {\n\t\tf := parsers_json.JSONFlattener{}\n\t\t// parse Json, getting strings and bools\n\t\terr := f.FullFlattenJSON(\"\", s, true, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tacc.AddFields(\"elasticsearch_indices_stats_\"+m, f.Fields, indexTag, now)\n\t}\n\n\tif e.IndicesLevel == \"shards\" {\n\t\tfor shardNumber, shards := range index.Shards {\n\t\t\tfor _, shard := range shards {\n\t\t\t\t// Get Shard Stats\n\t\t\t\tflattened := parsers_json.JSONFlattener{}\n\t\t\t\terr := flattened.FullFlattenJSON(\"\", shard, true, true)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\t// determine shard tag and primary/replica designation\n\t\t\t\tshardType := \"replica\"\n\t\t\t\troutingPrimary, _ := flattened.Fields[\"routing_primary\"].(bool)\n\t\t\t\tif routingPrimary {\n\t\t\t\t\tshardType = \"primary\"\n\t\t\t\t}\n\t\t\t\tdelete(flattened.Fields, \"routing_primary\")\n\n\t\t\t\troutingState, ok := flattened.Fields[\"routing_state\"].(string)\n\t\t\t\tif ok {\n\t\t\t\t\tflattened.Fields[\"routing_state\"] = mapShardStatusToCode(routingState)\n\t\t\t\t}\n\n\t\t\t\troutingNode, _ := flattened.Fields[\"routing_node\"].(string)\n\t\t\t\tshardTags := map[string]string{\n\t\t\t\t\t\"index_name\": name,\n\t\t\t\t\t\"node_id\":    routingNode,\n\t\t\t\t\t\"shard_name\": shardNumber,\n\t\t\t\t\t\"type\":       shardType,\n\t\t\t\t}\n\n\t\t\t\tfor key, field := range flattened.Fields {\n\t\t\t\t\tswitch field.(type) {\n\t\t\t\t\tcase string, bool:\n\t\t\t\t\t\tdelete(flattened.Fields, key)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tacc.AddFields(\"elasticsearch_indices_stats_shards\",\n\t\t\t\t\tflattened.Fields,\n\t\t\t\t\tshardTags,\n\t\t\t\t\tnow)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (e *Elasticsearch) getCatMaster(url string) (string, error) {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif e.Username != \"\" || e.Password != \"\" {\n\t\treq.SetBasicAuth(e.Username, e.Password)\n\t}\n\n\tfor key, value := range e.HTTPHeaders {\n\t\treq.Header.Add(key, value)\n\t}\n\n\tr, err := e.client.Do(req)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer r.Body.Close()\n\tif r.StatusCode != http.StatusOK {\n\t\t// NOTE: we are not going to read/discard r.Body under the assumption we'd prefer\n\t\t// to let the underlying transport close the connection and re-establish a new one for\n\t\t// future calls.\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"elasticsearch: Unable to retrieve master node information. API responded with status-code %d, expected %d\",\n\t\t\tr.StatusCode,\n\t\t\thttp.StatusOK,\n\t\t)\n\t}\n\tresponse, err := io.ReadAll(r.Body)\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmasterID := strings.Split(string(response), \" \")[0]\n\n\treturn masterID, nil\n}\n\nfunc (e *Elasticsearch) gatherJSONData(url string, v interface{}) error {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif e.Username != \"\" || e.Password != \"\" {\n\t\treq.SetBasicAuth(e.Username, e.Password)\n\t}\n\n\tfor key, value := range e.HTTPHeaders {\n\t\treq.Header.Add(key, value)\n\t}\n\n\tr, err := e.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Body.Close()\n\tif r.StatusCode != http.StatusOK {\n\t\t// NOTE: we are not going to read/discard r.Body under the assumption we'd prefer\n\t\t// to let the underlying transport close the connection and re-establish a new one for\n\t\t// future calls.\n\t\treturn fmt.Errorf(\"elasticsearch: API responded with status-code %d, expected %d\",\n\t\t\tr.StatusCode, http.StatusOK)\n\t}\n\n\treturn json.NewDecoder(r.Body).Decode(v)\n}\n\nfunc (e *Elasticsearch) compileIndexMatchers() (map[string]filter.Filter, error) {\n\tvar err error\n\tindexMatchers := make(map[string]filter.Filter, len(e.IndicesInclude))\n\n\t// Compile each configured index into a glob matcher.\n\tfor _, configuredIndex := range e.IndicesInclude {\n\t\tif _, exists := indexMatchers[configuredIndex]; !exists {\n\t\t\tindexMatchers[configuredIndex], err = filter.Compile([]string{configuredIndex})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn indexMatchers, nil\n}\n\nfunc (i serverInfo) isMaster() bool {\n\treturn i.nodeID == i.masterID\n}\n\n// perform status mapping\nfunc mapHealthStatusToCode(s string) int {\n\tswitch strings.ToLower(s) {\n\tcase \"green\":\n\t\treturn 1\n\tcase \"yellow\":\n\t\treturn 2\n\tcase \"red\":\n\t\treturn 3\n\t}\n\treturn 0\n}\n\n// perform shard status mapping\nfunc mapShardStatusToCode(s string) int {\n\tswitch strings.ToUpper(s) {\n\tcase \"UNASSIGNED\":\n\t\treturn 1\n\tcase \"INITIALIZING\":\n\t\treturn 2\n\tcase \"STARTED\":\n\t\treturn 3\n\tcase \"RELOCATING\":\n\t\treturn 4\n\t}\n\treturn 0\n}\n\nfunc newElasticsearch() *Elasticsearch {\n\treturn &Elasticsearch{\n\t\tClusterStatsOnlyFromMaster: true,\n\t\tClusterHealthLevel:         \"indices\",\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\tResponseHeaderTimeout: config.Duration(5 * time.Second),\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"elasticsearch\", func() telegraf.Input {\n\t\treturn newElasticsearch()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch/elasticsearch_test.go",
    "content": "package elasticsearch\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc defaultTags() map[string]string {\n\treturn map[string]string{\n\t\t\"cluster_name\":          \"es-testcluster\",\n\t\t\"node_attribute_master\": \"true\",\n\t\t\"node_id\":               \"SDFsfSDFsdfFSDSDfSFDSDF\",\n\t\t\"node_name\":             \"test.host.com\",\n\t\t\"node_host\":             \"test\",\n\t\t\"node_roles\":            \"data,ingest,master\",\n\t}\n}\nfunc defaultServerInfo() serverInfo {\n\treturn serverInfo{nodeID: \"\", masterID: \"SDFsfSDFsdfFSDSDfSFDSDF\"}\n}\n\ntype transportMock struct {\n\tstatusCode int\n\tbody       string\n}\n\nfunc newTransportMock(body string) http.RoundTripper {\n\treturn &transportMock{\n\t\tstatusCode: http.StatusOK,\n\t\tbody:       body,\n\t}\n}\n\nfunc (t *transportMock) RoundTrip(r *http.Request) (*http.Response, error) {\n\tres := &http.Response{\n\t\tHeader:     make(http.Header),\n\t\tRequest:    r,\n\t\tStatusCode: t.statusCode,\n\t}\n\tres.Header.Set(\"Content-Type\", \"application/json\")\n\tres.Body = io.NopCloser(strings.NewReader(t.body))\n\treturn res, nil\n}\n\nfunc checkNodeStatsResult(t *testing.T, acc *testutil.Accumulator) {\n\ttags := defaultTags()\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices\", nodestatsIndicesExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_os\", nodestatsOsExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_process\", nodestatsProcessExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_jvm\", nodestatsJvmExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_thread_pool\", nodestatsThreadPoolExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_fs\", nodestatsFsExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_transport\", nodestatsTransportExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_http\", nodestatsHTTPExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_breakers\", nodestatsBreakersExpected, tags)\n}\n\nfunc TestGather(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.client.Transport = newTransportMock(nodeStatsResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(es.Gather))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\tcheckNodeStatsResult(t, &acc)\n}\n\nfunc TestGatherIndividualStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.NodeStats = []string{\"jvm\", \"process\"}\n\tes.client.Transport = newTransportMock(nodeStatsResponseJVMProcess)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(es.Gather))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\n\ttags := defaultTags()\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_indices\", nodestatsIndicesExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_os\", nodestatsOsExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_process\", nodestatsProcessExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_jvm\", nodestatsJvmExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_thread_pool\", nodestatsThreadPoolExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_fs\", nodestatsFsExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_transport\", nodestatsTransportExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_http\", nodestatsHTTPExpected, tags)\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_breakers\", nodestatsBreakersExpected, tags)\n}\n\nfunc TestGatherEnrichStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.EnrichStats = true\n\tes.client.Transport = newTransportMock(enrichStatsResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(es.Gather))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\n\tmetrics := acc.GetTelegrafMetrics()\n\trequire.Len(t, metrics, 8)\n}\n\nfunc TestGatherNodeStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.client.Transport = newTransportMock(nodeStatsResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherNodeStats(\"junk\", &acc))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\tcheckNodeStatsResult(t, &acc)\n}\n\nfunc TestGatherClusterHealthEmptyClusterHealth(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.ClusterHealth = true\n\tes.ClusterHealthLevel = \"\"\n\tes.client.Transport = newTransportMock(clusterHealthResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherClusterHealth(\"junk\", &acc))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_cluster_health\",\n\t\tclusterHealthExpected,\n\t\tmap[string]string{\"name\": \"elasticsearch_telegraf\"})\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv1IndexExpected,\n\t\tmap[string]string{\"index\": \"v1\"})\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv2IndexExpected,\n\t\tmap[string]string{\"index\": \"v2\"})\n}\n\nfunc TestGatherClusterHealthSpecificClusterHealth(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.ClusterHealth = true\n\tes.ClusterHealthLevel = \"cluster\"\n\tes.client.Transport = newTransportMock(clusterHealthResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherClusterHealth(\"junk\", &acc))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_cluster_health\",\n\t\tclusterHealthExpected,\n\t\tmap[string]string{\"name\": \"elasticsearch_telegraf\"})\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv1IndexExpected,\n\t\tmap[string]string{\"index\": \"v1\"})\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv2IndexExpected,\n\t\tmap[string]string{\"index\": \"v2\"})\n}\n\nfunc TestGatherClusterHealthAlsoIndicesHealth(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.ClusterHealth = true\n\tes.ClusterHealthLevel = \"indices\"\n\tes.client.Transport = newTransportMock(clusterHealthResponseWithIndices)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherClusterHealth(\"junk\", &acc))\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_cluster_health\",\n\t\tclusterHealthExpected,\n\t\tmap[string]string{\"name\": \"elasticsearch_telegraf\"})\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv1IndexExpected,\n\t\tmap[string]string{\"index\": \"v1\", \"name\": \"elasticsearch_telegraf\"})\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_cluster_health_indices\",\n\t\tv2IndexExpected,\n\t\tmap[string]string{\"index\": \"v2\", \"name\": \"elasticsearch_telegraf\"})\n}\n\nfunc TestGatherClusterStatsMaster(t *testing.T) {\n\t// This needs multiple steps to replicate the multiple calls internally.\n\tes := newElasticsearchWithClient()\n\tes.ClusterStats = true\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.serverInfo = make(map[string]serverInfo)\n\tinfo := serverInfo{nodeID: \"SDFsfSDFsdfFSDSDfSFDSDF\", masterID: \"\"}\n\n\t// first get catMaster\n\tes.client.Transport = newTransportMock(IsMasterResult)\n\tmasterID, err := es.getCatMaster(\"junk\")\n\trequire.NoError(t, err)\n\tinfo.masterID = masterID\n\tes.serverInfo[\"http://example.com:9200\"] = info\n\n\tisMasterResultTokens := strings.Split(IsMasterResult, \" \")\n\trequire.Equal(t, masterID, isMasterResultTokens[0], \"catmaster is incorrect\")\n\n\t// now get node status, which determines whether we're master\n\tvar acc testutil.Accumulator\n\tes.Local = true\n\tes.client.Transport = newTransportMock(nodeStatsResponse)\n\trequire.NoError(t, es.gatherNodeStats(\"junk\", &acc))\n\trequire.True(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\tcheckNodeStatsResult(t, &acc)\n\n\t// now test the clusterstats method\n\tes.client.Transport = newTransportMock(clusterStatsResponse)\n\trequire.NoError(t, es.gatherClusterStats(\"junk\", &acc))\n\n\ttags := map[string]string{\n\t\t\"cluster_name\": \"es-testcluster\",\n\t\t\"node_name\":    \"test.host.com\",\n\t\t\"status\":       \"red\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_clusterstats_nodes\", clusterstatsNodesExpected, tags)\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_clusterstats_indices\", clusterstatsIndicesExpected, tags)\n}\n\nfunc TestGatherClusterStatsNonMaster(t *testing.T) {\n\t// This needs multiple steps to replicate the multiple calls internally.\n\tes := newElasticsearchWithClient()\n\tes.ClusterStats = true\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = serverInfo{nodeID: \"SDFsfSDFsdfFSDSDfSFDSDF\", masterID: \"\"}\n\n\t// first get catMaster\n\tes.client.Transport = newTransportMock(IsNotMasterResult)\n\tmasterID, err := es.getCatMaster(\"junk\")\n\trequire.NoError(t, err)\n\n\tisNotMasterResultTokens := strings.Split(IsNotMasterResult, \" \")\n\trequire.Equal(t, masterID, isNotMasterResultTokens[0], \"catmaster is incorrect\")\n\n\t// now get node status, which determines whether we're master\n\tvar acc testutil.Accumulator\n\tes.Local = true\n\tes.client.Transport = newTransportMock(nodeStatsResponse)\n\trequire.NoError(t, es.gatherNodeStats(\"junk\", &acc))\n\n\t// ensure flag is clear so Cluster Stats would not be done\n\trequire.False(t, es.serverInfo[es.Servers[0]].isMaster(), \"IsMaster set incorrectly\")\n\tcheckNodeStatsResult(t, &acc)\n}\n\nfunc TestGatherClusterIndicesStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.IndicesInclude = []string{\"_all\"}\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.client.Transport = newTransportMock(clusterIndicesResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherIndicesStats(\"junk\", &acc))\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"twitter\"})\n}\n\nfunc TestGatherDateStampedIndicesStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.IndicesInclude = []string{\"twitter*\", \"influx*\", \"penguins\"}\n\tes.NumMostRecentIndices = 2\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.client.Transport = newTransportMock(dateStampedIndicesResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\trequire.NoError(t, es.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherIndicesStats(es.Servers[0]+\"/\"+strings.Join(es.IndicesInclude, \",\")+\"/_stats\", &acc))\n\n\t// includes 2 most recent indices for \"twitter\", only expect the most recent two.\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"twitter_2020_08_02\"})\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"twitter_2020_08_01\"})\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"twitter_2020_07_31\"})\n\n\t// includes 2 most recent indices for \"influx\", only expect the most recent two.\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"influx2021.01.02\"})\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"influx2021.01.01\"})\n\tacc.AssertDoesNotContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"influx2020.12.31\"})\n\n\t// not configured to sort the 'penguins' index, but ensure it is also included.\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"penguins\"})\n}\n\nfunc TestGatherClusterIndiceShardsStats(t *testing.T) {\n\tes := newElasticsearchWithClient()\n\tes.IndicesLevel = \"shards\"\n\tes.Servers = []string{\"http://example.com:9200\"}\n\tes.client.Transport = newTransportMock(clusterIndicesShardsResponse)\n\tes.serverInfo = make(map[string]serverInfo)\n\tes.serverInfo[\"http://example.com:9200\"] = defaultServerInfo()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, es.gatherIndicesStats(\"junk\", &acc))\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_primaries\",\n\t\tclusterIndicesExpected,\n\t\tmap[string]string{\"index_name\": \"twitter\"})\n\n\tprimaryTags := map[string]string{\n\t\t\"index_name\": \"twitter\",\n\t\t\"node_id\":    \"oqvR8I1dTpONvwRM30etww\",\n\t\t\"shard_name\": \"0\",\n\t\t\"type\":       \"primary\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_shards\",\n\t\tclusterIndicesPrimaryShardsExpected,\n\t\tprimaryTags)\n\n\treplicaTags := map[string]string{\n\t\t\"index_name\": \"twitter\",\n\t\t\"node_id\":    \"oqvR8I1dTpONvwRM30etww\",\n\t\t\"shard_name\": \"1\",\n\t\t\"type\":       \"replica\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"elasticsearch_indices_stats_shards\",\n\t\tclusterIndicesReplicaShardsExpected,\n\t\treplicaTags)\n}\n\nfunc newElasticsearchWithClient() *Elasticsearch {\n\tes := newElasticsearch()\n\tes.client = &http.Client{}\n\treturn es\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch/sample.conf",
    "content": "# Read stats from one or more Elasticsearch servers or clusters\n[[inputs.elasticsearch]]\n  ## specify a list of one or more Elasticsearch servers\n  ## you can add username and password to your url to use basic authentication:\n  ## servers = [\"http://user:pass@localhost:9200\"]\n  servers = [\"http://localhost:9200\"]\n\n  ## HTTP headers to send with each request\n  # headers = { \"X-Custom-Header\" = \"Custom\" }\n\n  ## When local is true (the default), the node will read only its own stats.\n  ## Set local to false when you want to read the node stats from all nodes\n  ## of the cluster.\n  local = true\n\n  ## Set cluster_health to true when you want to obtain cluster health stats\n  cluster_health = false\n\n  ## Adjust cluster_health_level when you want to obtain detailed health stats\n  ## The options are\n  ##  - indices (default)\n  ##  - cluster\n  # cluster_health_level = \"indices\"\n\n  ## Set cluster_stats to true when you want to obtain cluster stats.\n  cluster_stats = false\n\n  ## Only gather cluster_stats from the master node.\n  ## To work this require local = true\n  cluster_stats_only_from_master = true\n\n  ## Gather stats from the enrich API\n  # enrich_stats = false\n\n  ## Indices to collect; can be one or more indices names or _all\n  ## Use of wildcards is allowed. Use a wildcard at the end to retrieve index\n  ## names that end with a changing value, like a date.\n  indices_include = [\"_all\"]\n\n  ## One of \"shards\", \"cluster\", \"indices\"\n  ## Currently only \"shards\" is implemented\n  indices_level = \"shards\"\n\n  ## node_stats is a list of sub-stats that you want to have gathered.\n  ## Valid options are \"indices\", \"os\", \"process\", \"jvm\", \"thread_pool\",\n  ## \"fs\", \"transport\", \"http\", \"breaker\". Per default, all stats are gathered.\n  # node_stats = [\"jvm\", \"http\"]\n\n  ## HTTP Basic Authentication username and password.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## Sets the number of most recent indices to return for indices that are\n  ## configured with a date-stamped suffix. Each 'indices_include' entry\n  ## ending with a wildcard (*) or glob matching pattern will group together\n  ## all indices that match it, and  sort them by the date or number after\n  ## the wildcard. Metrics then are gathered for only the\n  ## 'num_most_recent_indices' amount of most  recent indices.\n  # num_most_recent_indices = 0\n"
  },
  {
    "path": "plugins/inputs/elasticsearch/testdata_test.go",
    "content": "package elasticsearch\n\nconst clusterHealthResponse = `\n{\n   \"cluster_name\": \"elasticsearch_telegraf\",\n   \"status\": \"green\",\n   \"timed_out\": false,\n   \"number_of_nodes\": 3,\n   \"number_of_data_nodes\": 3,\n   \"number_of_in_flight_fetch\": 0,\n   \"active_primary_shards\": 5,\n   \"active_shards\": 15,\n   \"relocating_shards\": 0,\n   \"initializing_shards\": 0,\n   \"unassigned_shards\": 0,\n   \"delayed_unassigned_shards\": 0,\n   \"number_of_pending_tasks\": 0,\n   \"task_max_waiting_in_queue_millis\": 0,\n   \"active_shards_percent_as_number\": 100.0\n}\n`\n\nconst clusterHealthResponseWithIndices = `\n{\n   \"cluster_name\": \"elasticsearch_telegraf\",\n   \"status\": \"green\",\n   \"timed_out\": false,\n   \"number_of_nodes\": 3,\n   \"number_of_data_nodes\": 3,\n   \"number_of_in_flight_fetch\": 0,\n   \"active_primary_shards\": 5,\n   \"active_shards\": 15,\n   \"relocating_shards\": 0,\n   \"initializing_shards\": 0,\n   \"unassigned_shards\": 0,\n   \"delayed_unassigned_shards\": 0,\n   \"number_of_pending_tasks\": 0,\n   \"task_max_waiting_in_queue_millis\": 0,\n   \"active_shards_percent_as_number\": 100.0,\n   \"indices\": {\n      \"v1\": {\n         \"status\": \"green\",\n         \"number_of_shards\": 10,\n         \"number_of_replicas\": 1,\n         \"active_primary_shards\": 10,\n         \"active_shards\": 20,\n         \"relocating_shards\": 0,\n         \"initializing_shards\": 0,\n         \"unassigned_shards\": 0\n      },\n      \"v2\": {\n         \"status\": \"red\",\n         \"number_of_shards\": 10,\n         \"number_of_replicas\": 1,\n         \"active_primary_shards\": 0,\n         \"active_shards\": 0,\n         \"relocating_shards\": 0,\n         \"initializing_shards\": 0,\n         \"unassigned_shards\": 20\n      }\n   }\n}\n`\n\nconst enrichStatsResponse = `\n{\n  \"executing_policies\": [],\n  \"coordinator_stats\": [\n    {\n      \"node_id\": \"RWkDKDRu_aV1fISRA7PIkg\",\n      \"queue_size\": 0,\n      \"remote_requests_current\": 0,\n      \"remote_requests_total\": 101636700,\n      \"executed_searches_total\": 102230925\n    },\n    {\n      \"node_id\": \"2BOvel8nrXRjmSMAMBSUp3\",\n      \"queue_size\": 0,\n      \"remote_requests_current\": 0,\n      \"remote_requests_total\": 242051423,\n      \"executed_searches_total\": 242752071\n    },\n    {\n      \"node_id\": \"smkOUPQOK1pymt8MCoglZJ\",\n      \"queue_size\": 0,\n      \"remote_requests_current\": 0,\n      \"remote_requests_total\": 248009084,\n      \"executed_searches_total\": 248735550\n    },\n    {\n      \"node_id\": \"g5EUAaS-6-z5w27OtGQeTI\",\n      \"queue_size\": 0,\n      \"remote_requests_current\": 0,\n      \"remote_requests_total\": 233693129,\n      \"executed_searches_total\": 234476004\n    }\n  ],\n  \"cache_stats\": [\n    {\n      \"node_id\": \"RWkDKDRu_aV1fISRA7PIkg\",\n      \"count\": 2500,\n      \"hits\": 6044497858,\n      \"misses\": 102230925,\n      \"evictions\": 92663663\n    },\n    {\n      \"node_id\": \"2BOvel8nrXRjmSMAMBSUp3\",\n      \"count\": 2500,\n      \"hits\": 14640821136,\n      \"misses\": 242752071,\n      \"evictions\": 226826313\n    },\n    {\n      \"node_id\": \"smkOUPQOK1pymt8MCoglZJ\",\n      \"count\": 2500,\n      \"hits\": 14145580115,\n      \"misses\": 248735550,\n      \"evictions\": 233860968\n    },\n    {\n      \"node_id\": \"g5EUAaS-6-z5w27OtGQeTI\",\n      \"count\": 2500,\n      \"hits\": 11016000946,\n      \"misses\": 234476004,\n      \"evictions\": 217698127\n    }\n  ]\n}\n`\n\nvar clusterHealthExpected = map[string]interface{}{\n\t\"status\":                           \"green\",\n\t\"status_code\":                      1,\n\t\"timed_out\":                        false,\n\t\"number_of_nodes\":                  3,\n\t\"number_of_data_nodes\":             3,\n\t\"number_of_in_flight_fetch\":        0,\n\t\"active_primary_shards\":            5,\n\t\"active_shards\":                    15,\n\t\"relocating_shards\":                0,\n\t\"initializing_shards\":              0,\n\t\"unassigned_shards\":                0,\n\t\"delayed_unassigned_shards\":        0,\n\t\"number_of_pending_tasks\":          0,\n\t\"task_max_waiting_in_queue_millis\": 0,\n\t\"active_shards_percent_as_number\":  100.0,\n}\n\nvar v1IndexExpected = map[string]interface{}{\n\t\"status\":                \"green\",\n\t\"status_code\":           1,\n\t\"number_of_shards\":      10,\n\t\"number_of_replicas\":    1,\n\t\"active_primary_shards\": 10,\n\t\"active_shards\":         20,\n\t\"relocating_shards\":     0,\n\t\"initializing_shards\":   0,\n\t\"unassigned_shards\":     0,\n}\n\nvar v2IndexExpected = map[string]interface{}{\n\t\"status\":                \"red\",\n\t\"status_code\":           3,\n\t\"number_of_shards\":      10,\n\t\"number_of_replicas\":    1,\n\t\"active_primary_shards\": 0,\n\t\"active_shards\":         0,\n\t\"relocating_shards\":     0,\n\t\"initializing_shards\":   0,\n\t\"unassigned_shards\":     20,\n}\n\nconst nodeStatsResponse = `\n{\n  \"cluster_name\": \"es-testcluster\",\n  \"nodes\": {\n    \"SDFsfSDFsdfFSDSDfSFDSDF\": {\n      \"timestamp\": 1436365550135,\n      \"name\": \"test.host.com\",\n      \"transport_address\": \"inet[/127.0.0.1:9300]\",\n      \"host\": \"test\",\n      \"ip\": [\n        \"inet[/127.0.0.1:9300]\",\n        \"NONE\"\n      ],\n      \"roles\": [\n        \"master\",\n        \"data\",\n        \"ingest\"\n      ],\n      \"attributes\": {\n        \"master\": \"true\"\n      },\n      \"indices\": {\n        \"docs\": {\n          \"count\": 29652,\n          \"deleted\": 5229\n        },\n        \"store\": {\n          \"size_in_bytes\": 37715234,\n          \"throttle_time_in_millis\": 215\n        },\n        \"indexing\": {\n          \"index_total\": 84790,\n          \"index_time_in_millis\": 29680,\n          \"index_current\": 0,\n          \"delete_total\": 13879,\n          \"delete_time_in_millis\": 1139,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 1,\n          \"time_in_millis\": 2,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 1,\n          \"missing_time_in_millis\": 2,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 1452,\n          \"query_time_in_millis\": 5695,\n          \"query_current\": 0,\n          \"fetch_total\": 414,\n          \"fetch_time_in_millis\": 146,\n          \"fetch_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 133,\n          \"total_time_in_millis\": 21060,\n          \"total_docs\": 203672,\n          \"total_size_in_bytes\": 142900226\n        },\n        \"refresh\": {\n          \"total\": 1076,\n          \"total_time_in_millis\": 20078\n        },\n        \"flush\": {\n          \"total\": 115,\n          \"total_time_in_millis\": 2401\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 2319,\n          \"total_time_in_millis\": 448\n        },\n        \"filter_cache\": {\n          \"memory_size_in_bytes\": 7384,\n          \"evictions\": 0\n        },\n        \"id_cache\": {\n          \"memory_size_in_bytes\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 12996,\n          \"evictions\": 0\n        },\n        \"percolate\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"current\": 0,\n          \"memory_size_in_bytes\": -1,\n          \"memory_size\": \"-1b\",\n          \"queries\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 134,\n          \"memory_in_bytes\": 1285212,\n          \"index_writer_memory_in_bytes\": 0,\n          \"index_writer_max_memory_in_bytes\": 172368955,\n          \"version_map_memory_in_bytes\": 611844,\n          \"fixed_bit_set_memory_in_bytes\": 0\n        },\n        \"translog\": {\n          \"operations\": 17702,\n          \"size_in_bytes\": 17\n        },\n        \"suggest\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"os\": {\n        \"timestamp\": 1436460392944,\n        \"load_average\": [\n          0.01,\n          0.04,\n          0.05\n        ],\n        \"mem\": {\n          \"free_in_bytes\": 477761536,\n          \"used_in_bytes\": 1621868544,\n          \"free_percent\": 74,\n          \"used_percent\": 25,\n          \"actual_free_in_bytes\": 1565470720,\n          \"actual_used_in_bytes\": 534159360\n        },\n        \"swap\": {\n          \"used_in_bytes\": 0,\n          \"free_in_bytes\": 487997440\n        }\n      },\n      \"process\": {\n        \"timestamp\": 1436460392945,\n        \"open_file_descriptors\": 160,\n        \"cpu\": {\n          \"percent\": 2,\n          \"sys_in_millis\": 1870,\n          \"user_in_millis\": 13610,\n          \"total_in_millis\": 15480\n        },\n        \"mem\": {\n          \"total_virtual_in_bytes\": 4747890688\n        }\n      },\n      \"jvm\": {\n        \"timestamp\": 1436460392945,\n        \"uptime_in_millis\": 202245,\n        \"mem\": {\n          \"heap_used_in_bytes\": 52709568,\n          \"heap_used_percent\": 5,\n          \"heap_committed_in_bytes\": 259522560,\n          \"heap_max_in_bytes\": 1038876672,\n          \"non_heap_used_in_bytes\": 39634576,\n          \"non_heap_committed_in_bytes\": 40841216,\n          \"pools\": {\n            \"young\": {\n              \"used_in_bytes\": 32685760,\n              \"max_in_bytes\": 279183360,\n              \"peak_used_in_bytes\": 71630848,\n              \"peak_max_in_bytes\": 279183360\n            },\n            \"survivor\": {\n              \"used_in_bytes\": 8912880,\n              \"max_in_bytes\": 34865152,\n              \"peak_used_in_bytes\": 8912888,\n              \"peak_max_in_bytes\": 34865152\n            },\n            \"old\": {\n              \"used_in_bytes\": 11110928,\n              \"max_in_bytes\": 724828160,\n              \"peak_used_in_bytes\": 14354608,\n              \"peak_max_in_bytes\": 724828160\n            }\n          }\n        },\n        \"threads\": {\n          \"count\": 44,\n          \"peak_count\": 45\n        },\n        \"gc\": {\n          \"collectors\": {\n            \"young\": {\n              \"collection_count\": 2,\n              \"collection_time_in_millis\": 98\n            },\n            \"old\": {\n              \"collection_count\": 1,\n              \"collection_time_in_millis\": 24\n            }\n          }\n        },\n        \"buffer_pools\": {\n          \"direct\": {\n            \"count\": 40,\n            \"used_in_bytes\": 6304239,\n            \"total_capacity_in_bytes\": 6304239\n          },\n          \"mapped\": {\n            \"count\": 0,\n            \"used_in_bytes\": 0,\n            \"total_capacity_in_bytes\": 0\n          }\n        }\n      },\n      \"thread_pool\": {\n        \"percolate\": {\n          \"threads\": 123,\n          \"queue\": 23,\n          \"active\": 13,\n          \"rejected\": 235,\n          \"largest\": 23,\n          \"completed\": 33\n        },\n        \"fetch_shard_started\": {\n          \"threads\": 3,\n          \"queue\": 1,\n          \"active\": 5,\n          \"rejected\": 6,\n          \"largest\": 4,\n          \"completed\": 54\n        },\n        \"listener\": {\n          \"threads\": 1,\n          \"queue\": 2,\n          \"active\": 4,\n          \"rejected\": 8,\n          \"largest\": 1,\n          \"completed\": 1\n        },\n        \"index\": {\n          \"threads\": 6,\n          \"queue\": 8,\n          \"active\": 4,\n          \"rejected\": 2,\n          \"largest\": 3,\n          \"completed\": 6\n        },\n        \"refresh\": {\n          \"threads\": 23,\n          \"queue\": 7,\n          \"active\": 3,\n          \"rejected\": 4,\n          \"largest\": 8,\n          \"completed\": 3\n        },\n        \"suggest\": {\n          \"threads\": 2,\n          \"queue\": 7,\n          \"active\": 2,\n          \"rejected\": 1,\n          \"largest\": 8,\n          \"completed\": 3\n        },\n        \"generic\": {\n          \"threads\": 1,\n          \"queue\": 4,\n          \"active\": 6,\n          \"rejected\": 3,\n          \"largest\": 2,\n          \"completed\": 27\n        },\n        \"warmer\": {\n          \"threads\": 2,\n          \"queue\": 7,\n          \"active\": 3,\n          \"rejected\": 2,\n          \"largest\": 3,\n          \"completed\": 1\n        },\n        \"search\": {\n          \"threads\": 5,\n          \"queue\": 7,\n          \"active\": 2,\n          \"rejected\": 7,\n          \"largest\": 2,\n          \"completed\": 4\n        },\n        \"flush\": {\n          \"threads\": 3,\n          \"queue\": 8,\n          \"active\": 0,\n          \"rejected\": 1,\n          \"largest\": 5,\n          \"completed\": 3\n        },\n        \"optimize\": {\n          \"threads\": 3,\n          \"queue\": 4,\n          \"active\": 1,\n          \"rejected\": 2,\n          \"largest\": 7,\n          \"completed\": 3\n        },\n        \"fetch_shard_store\": {\n          \"threads\": 1,\n          \"queue\": 7,\n          \"active\": 4,\n          \"rejected\": 2,\n          \"largest\": 4,\n          \"completed\": 1\n        },\n        \"management\": {\n          \"threads\": 2,\n          \"queue\": 3,\n          \"active\": 1,\n          \"rejected\": 6,\n          \"largest\": 2,\n          \"completed\": 22\n        },\n        \"get\": {\n          \"threads\": 1,\n          \"queue\": 8,\n          \"active\": 4,\n          \"rejected\": 3,\n          \"largest\": 2,\n          \"completed\": 1\n        },\n        \"merge\": {\n          \"threads\": 6,\n          \"queue\": 4,\n          \"active\": 5,\n          \"rejected\": 2,\n          \"largest\": 5,\n          \"completed\": 1\n        },\n        \"bulk\": {\n          \"threads\": 4,\n          \"queue\": 5,\n          \"active\": 7,\n          \"rejected\": 3,\n          \"largest\": 1,\n          \"completed\": 4\n        },\n        \"snapshot\": {\n          \"threads\": 8,\n          \"queue\": 5,\n          \"active\": 6,\n          \"rejected\": 2,\n          \"largest\": 1,\n          \"completed\": 0\n        }\n      },\n      \"fs\": {\n        \"timestamp\": 1436460392946,\n        \"total\": {\n          \"total_in_bytes\": 19507089408,\n          \"free_in_bytes\": 16909316096,\n          \"available_in_bytes\": 15894814720\n        },\n        \"data\": [\n          {\n            \"path\": \"/usr/share/elasticsearch/data/elasticsearch/nodes/0\",\n            \"mount\": \"/usr/share/elasticsearch/data\",\n            \"type\": \"ext4\",\n            \"total_in_bytes\": 19507089408,\n            \"free_in_bytes\": 16909316096,\n            \"available_in_bytes\": 15894814720\n          }\n        ]\n      },\n      \"transport\": {\n        \"server_open\": 13,\n        \"rx_count\": 6,\n        \"rx_size_in_bytes\": 1380,\n        \"tx_count\": 6,\n        \"tx_size_in_bytes\": 1380\n      },\n      \"http\": {\n        \"current_open\": 3,\n        \"total_opened\": 3\n      },\n      \"breakers\": {\n        \"fielddata\": {\n          \"limit_size_in_bytes\": 623326003,\n          \"limit_size\": \"594.4mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.03,\n          \"tripped\": 0\n        },\n        \"request\": {\n          \"limit_size_in_bytes\": 415550668,\n          \"limit_size\": \"396.2mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.0,\n          \"tripped\": 0\n        },\n        \"parent\": {\n          \"limit_size_in_bytes\": 727213670,\n          \"limit_size\": \"693.5mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.0,\n          \"tripped\": 0\n        }\n      }\n    },\n    \"SDFsfSDFsdfFSDSDfSPOJUY\": {\n      \"timestamp\": 1436365550135,\n      \"name\": \"test.host.com\",\n      \"transport_address\": \"inet[/127.0.0.1:9300]\",\n      \"host\": \"test\",\n      \"ip\": [\n        \"inet[/127.0.0.1:9300]\",\n        \"NONE\"\n      ],\n      \"attributes\": {\n        \"master\": \"true\"\n      },\n      \"indices\": {\n        \"docs\": {\n          \"count\": 29652,\n          \"deleted\": 5229\n        },\n        \"store\": {\n          \"size_in_bytes\": 37715234,\n          \"throttle_time_in_millis\": 215\n        },\n        \"indexing\": {\n          \"index_total\": 84790,\n          \"index_time_in_millis\": 29680,\n          \"index_current\": 0,\n          \"delete_total\": 13879,\n          \"delete_time_in_millis\": 1139,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 1,\n          \"time_in_millis\": 2,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 1,\n          \"missing_time_in_millis\": 2,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 1452,\n          \"query_time_in_millis\": 5695,\n          \"query_current\": 0,\n          \"fetch_total\": 414,\n          \"fetch_time_in_millis\": 146,\n          \"fetch_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 133,\n          \"total_time_in_millis\": 21060,\n          \"total_docs\": 203672,\n          \"total_size_in_bytes\": 142900226\n        },\n        \"refresh\": {\n          \"total\": 1076,\n          \"total_time_in_millis\": 20078\n        },\n        \"flush\": {\n          \"total\": 115,\n          \"total_time_in_millis\": 2401\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 2319,\n          \"total_time_in_millis\": 448\n        },\n        \"filter_cache\": {\n          \"memory_size_in_bytes\": 7384,\n          \"evictions\": 0\n        },\n        \"id_cache\": {\n          \"memory_size_in_bytes\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 12996,\n          \"evictions\": 0\n        },\n        \"percolate\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"current\": 0,\n          \"memory_size_in_bytes\": -1,\n          \"memory_size\": \"-1b\",\n          \"queries\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 134,\n          \"memory_in_bytes\": 1285212,\n          \"index_writer_memory_in_bytes\": 0,\n          \"index_writer_max_memory_in_bytes\": 172368955,\n          \"version_map_memory_in_bytes\": 611844,\n          \"fixed_bit_set_memory_in_bytes\": 0\n        },\n        \"translog\": {\n          \"operations\": 17702,\n          \"size_in_bytes\": 17\n        },\n        \"suggest\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"os\": {\n        \"timestamp\": 1436460392944,\n        \"load_average\": [\n          0.01,\n          0.04,\n          0.05\n        ],\n        \"mem\": {\n          \"free_in_bytes\": 477761536,\n          \"used_in_bytes\": 1621868544,\n          \"free_percent\": 74,\n          \"used_percent\": 25,\n          \"actual_free_in_bytes\": 1565470720,\n          \"actual_used_in_bytes\": 534159360\n        },\n        \"swap\": {\n          \"used_in_bytes\": 0,\n          \"free_in_bytes\": 487997440\n        }\n      },\n      \"process\": {\n        \"timestamp\": 1436460392945,\n        \"open_file_descriptors\": 160,\n        \"cpu\": {\n          \"percent\": 2,\n          \"sys_in_millis\": 1870,\n          \"user_in_millis\": 13610,\n          \"total_in_millis\": 15480\n        },\n        \"mem\": {\n          \"total_virtual_in_bytes\": 4747890688\n        }\n      },\n      \"jvm\": {\n        \"timestamp\": 1436460392945,\n        \"uptime_in_millis\": 202245,\n        \"mem\": {\n          \"heap_used_in_bytes\": 52709568,\n          \"heap_used_percent\": 5,\n          \"heap_committed_in_bytes\": 259522560,\n          \"heap_max_in_bytes\": 1038876672,\n          \"non_heap_used_in_bytes\": 39634576,\n          \"non_heap_committed_in_bytes\": 40841216,\n          \"pools\": {\n            \"young\": {\n              \"used_in_bytes\": 32685760,\n              \"max_in_bytes\": 279183360,\n              \"peak_used_in_bytes\": 71630848,\n              \"peak_max_in_bytes\": 279183360\n            },\n            \"survivor\": {\n              \"used_in_bytes\": 8912880,\n              \"max_in_bytes\": 34865152,\n              \"peak_used_in_bytes\": 8912888,\n              \"peak_max_in_bytes\": 34865152\n            },\n            \"old\": {\n              \"used_in_bytes\": 11110928,\n              \"max_in_bytes\": 724828160,\n              \"peak_used_in_bytes\": 14354608,\n              \"peak_max_in_bytes\": 724828160\n            }\n          }\n        },\n        \"threads\": {\n          \"count\": 44,\n          \"peak_count\": 45\n        },\n        \"gc\": {\n          \"collectors\": {\n            \"young\": {\n              \"collection_count\": 2,\n              \"collection_time_in_millis\": 98\n            },\n            \"old\": {\n              \"collection_count\": 1,\n              \"collection_time_in_millis\": 24\n            }\n          }\n        },\n        \"buffer_pools\": {\n          \"direct\": {\n            \"count\": 40,\n            \"used_in_bytes\": 6304239,\n            \"total_capacity_in_bytes\": 6304239\n          },\n          \"mapped\": {\n            \"count\": 0,\n            \"used_in_bytes\": 0,\n            \"total_capacity_in_bytes\": 0\n          }\n        }\n      },\n      \"thread_pool\": {\n        \"percolate\": {\n          \"threads\": 123,\n          \"queue\": 23,\n          \"active\": 13,\n          \"rejected\": 235,\n          \"largest\": 23,\n          \"completed\": 33\n        },\n        \"fetch_shard_started\": {\n          \"threads\": 3,\n          \"queue\": 1,\n          \"active\": 5,\n          \"rejected\": 6,\n          \"largest\": 4,\n          \"completed\": 54\n        },\n        \"listener\": {\n          \"threads\": 1,\n          \"queue\": 2,\n          \"active\": 4,\n          \"rejected\": 8,\n          \"largest\": 1,\n          \"completed\": 1\n        },\n        \"index\": {\n          \"threads\": 6,\n          \"queue\": 8,\n          \"active\": 4,\n          \"rejected\": 2,\n          \"largest\": 3,\n          \"completed\": 6\n        },\n        \"refresh\": {\n          \"threads\": 23,\n          \"queue\": 7,\n          \"active\": 3,\n          \"rejected\": 4,\n          \"largest\": 8,\n          \"completed\": 3\n        },\n        \"suggest\": {\n          \"threads\": 2,\n          \"queue\": 7,\n          \"active\": 2,\n          \"rejected\": 1,\n          \"largest\": 8,\n          \"completed\": 3\n        },\n        \"generic\": {\n          \"threads\": 1,\n          \"queue\": 4,\n          \"active\": 6,\n          \"rejected\": 3,\n          \"largest\": 2,\n          \"completed\": 27\n        },\n        \"warmer\": {\n          \"threads\": 2,\n          \"queue\": 7,\n          \"active\": 3,\n          \"rejected\": 2,\n          \"largest\": 3,\n          \"completed\": 1\n        },\n        \"search\": {\n          \"threads\": 5,\n          \"queue\": 7,\n          \"active\": 2,\n          \"rejected\": 7,\n          \"largest\": 2,\n          \"completed\": 4\n        },\n        \"flush\": {\n          \"threads\": 3,\n          \"queue\": 8,\n          \"active\": 0,\n          \"rejected\": 1,\n          \"largest\": 5,\n          \"completed\": 3\n        },\n        \"optimize\": {\n          \"threads\": 3,\n          \"queue\": 4,\n          \"active\": 1,\n          \"rejected\": 2,\n          \"largest\": 7,\n          \"completed\": 3\n        },\n        \"fetch_shard_store\": {\n          \"threads\": 1,\n          \"queue\": 7,\n          \"active\": 4,\n          \"rejected\": 2,\n          \"largest\": 4,\n          \"completed\": 1\n        },\n        \"management\": {\n          \"threads\": 2,\n          \"queue\": 3,\n          \"active\": 1,\n          \"rejected\": 6,\n          \"largest\": 2,\n          \"completed\": 22\n        },\n        \"get\": {\n          \"threads\": 1,\n          \"queue\": 8,\n          \"active\": 4,\n          \"rejected\": 3,\n          \"largest\": 2,\n          \"completed\": 1\n        },\n        \"merge\": {\n          \"threads\": 6,\n          \"queue\": 4,\n          \"active\": 5,\n          \"rejected\": 2,\n          \"largest\": 5,\n          \"completed\": 1\n        },\n        \"bulk\": {\n          \"threads\": 4,\n          \"queue\": 5,\n          \"active\": 7,\n          \"rejected\": 3,\n          \"largest\": 1,\n          \"completed\": 4\n        },\n        \"snapshot\": {\n          \"threads\": 8,\n          \"queue\": 5,\n          \"active\": 6,\n          \"rejected\": 2,\n          \"largest\": 1,\n          \"completed\": 0\n        }\n      },\n      \"fs\": {\n        \"timestamp\": 1436460392946,\n        \"total\": {\n          \"total_in_bytes\": 19507089408,\n          \"free_in_bytes\": 16909316096,\n          \"available_in_bytes\": 15894814720\n        },\n        \"data\": [\n          {\n            \"path\": \"/usr/share/elasticsearch/data/elasticsearch/nodes/0\",\n            \"mount\": \"/usr/share/elasticsearch/data\",\n            \"type\": \"ext4\",\n            \"total_in_bytes\": 19507089408,\n            \"free_in_bytes\": 16909316096,\n            \"available_in_bytes\": 15894814720\n          }\n        ]\n      },\n      \"transport\": {\n        \"server_open\": 13,\n        \"rx_count\": 6,\n        \"rx_size_in_bytes\": 1380,\n        \"tx_count\": 6,\n        \"tx_size_in_bytes\": 1380\n      },\n      \"http\": {\n        \"current_open\": 3,\n        \"total_opened\": 3\n      },\n      \"breakers\": {\n        \"fielddata\": {\n          \"limit_size_in_bytes\": 623326003,\n          \"limit_size\": \"594.4mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.03,\n          \"tripped\": 0\n        },\n        \"request\": {\n          \"limit_size_in_bytes\": 415550668,\n          \"limit_size\": \"396.2mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.0,\n          \"tripped\": 0\n        },\n        \"parent\": {\n          \"limit_size_in_bytes\": 727213670,\n          \"limit_size\": \"693.5mb\",\n          \"estimated_size_in_bytes\": 0,\n          \"estimated_size\": \"0b\",\n          \"overhead\": 1.0,\n          \"tripped\": 0\n        }\n      }\n    }\n  }\n}\n`\n\nconst nodeStatsResponseJVMProcess = `\n{\n  \"cluster_name\": \"es-testcluster\",\n  \"nodes\": {\n    \"SDFsfSDFsdfFSDSDfSFDSDF\": {\n      \"timestamp\": 1436365550135,\n      \"name\": \"test.host.com\",\n      \"transport_address\": \"inet[/127.0.0.1:9300]\",\n      \"host\": \"test\",\n      \"ip\": [\n        \"inet[/127.0.0.1:9300]\",\n        \"NONE\"\n      ],\n      \"roles\": [\n        \"master\",\n        \"data\",\n        \"ingest\"\n      ],\n      \"attributes\": {\n        \"master\": \"true\"\n      },\n      \"process\": {\n        \"timestamp\": 1436460392945,\n        \"open_file_descriptors\": 160,\n        \"cpu\": {\n          \"percent\": 2,\n          \"sys_in_millis\": 1870,\n          \"user_in_millis\": 13610,\n          \"total_in_millis\": 15480\n        },\n        \"mem\": {\n          \"total_virtual_in_bytes\": 4747890688\n        }\n      },\n      \"jvm\": {\n        \"timestamp\": 1436460392945,\n        \"uptime_in_millis\": 202245,\n        \"mem\": {\n          \"heap_used_in_bytes\": 52709568,\n          \"heap_used_percent\": 5,\n          \"heap_committed_in_bytes\": 259522560,\n          \"heap_max_in_bytes\": 1038876672,\n          \"non_heap_used_in_bytes\": 39634576,\n          \"non_heap_committed_in_bytes\": 40841216,\n          \"pools\": {\n            \"young\": {\n              \"used_in_bytes\": 32685760,\n              \"max_in_bytes\": 279183360,\n              \"peak_used_in_bytes\": 71630848,\n              \"peak_max_in_bytes\": 279183360\n            },\n            \"survivor\": {\n              \"used_in_bytes\": 8912880,\n              \"max_in_bytes\": 34865152,\n              \"peak_used_in_bytes\": 8912888,\n              \"peak_max_in_bytes\": 34865152\n            },\n            \"old\": {\n              \"used_in_bytes\": 11110928,\n              \"max_in_bytes\": 724828160,\n              \"peak_used_in_bytes\": 14354608,\n              \"peak_max_in_bytes\": 724828160\n            }\n          }\n        },\n        \"threads\": {\n          \"count\": 44,\n          \"peak_count\": 45\n        },\n        \"gc\": {\n          \"collectors\": {\n            \"young\": {\n              \"collection_count\": 2,\n              \"collection_time_in_millis\": 98\n            },\n            \"old\": {\n              \"collection_count\": 1,\n              \"collection_time_in_millis\": 24\n            }\n          }\n        },\n        \"buffer_pools\": {\n          \"direct\": {\n            \"count\": 40,\n            \"used_in_bytes\": 6304239,\n            \"total_capacity_in_bytes\": 6304239\n          },\n          \"mapped\": {\n            \"count\": 0,\n            \"used_in_bytes\": 0,\n            \"total_capacity_in_bytes\": 0\n          }\n        }\n      }\n    }\n  }\n}\n`\n\nvar nodestatsIndicesExpected = map[string]interface{}{\n\t\"id_cache_memory_size_in_bytes\":             float64(0),\n\t\"completion_size_in_bytes\":                  float64(0),\n\t\"suggest_total\":                             float64(0),\n\t\"suggest_time_in_millis\":                    float64(0),\n\t\"suggest_current\":                           float64(0),\n\t\"query_cache_memory_size_in_bytes\":          float64(0),\n\t\"query_cache_evictions\":                     float64(0),\n\t\"query_cache_hit_count\":                     float64(0),\n\t\"query_cache_miss_count\":                    float64(0),\n\t\"store_size_in_bytes\":                       float64(37715234),\n\t\"store_throttle_time_in_millis\":             float64(215),\n\t\"merges_current_docs\":                       float64(0),\n\t\"merges_current_size_in_bytes\":              float64(0),\n\t\"merges_total\":                              float64(133),\n\t\"merges_total_time_in_millis\":               float64(21060),\n\t\"merges_total_docs\":                         float64(203672),\n\t\"merges_total_size_in_bytes\":                float64(142900226),\n\t\"merges_current\":                            float64(0),\n\t\"filter_cache_memory_size_in_bytes\":         float64(7384),\n\t\"filter_cache_evictions\":                    float64(0),\n\t\"indexing_index_total\":                      float64(84790),\n\t\"indexing_index_time_in_millis\":             float64(29680),\n\t\"indexing_index_current\":                    float64(0),\n\t\"indexing_noop_update_total\":                float64(0),\n\t\"indexing_throttle_time_in_millis\":          float64(0),\n\t\"indexing_delete_total\":                     float64(13879),\n\t\"indexing_delete_time_in_millis\":            float64(1139),\n\t\"indexing_delete_current\":                   float64(0),\n\t\"get_exists_time_in_millis\":                 float64(0),\n\t\"get_missing_total\":                         float64(1),\n\t\"get_missing_time_in_millis\":                float64(2),\n\t\"get_current\":                               float64(0),\n\t\"get_total\":                                 float64(1),\n\t\"get_time_in_millis\":                        float64(2),\n\t\"get_exists_total\":                          float64(0),\n\t\"refresh_total\":                             float64(1076),\n\t\"refresh_total_time_in_millis\":              float64(20078),\n\t\"percolate_current\":                         float64(0),\n\t\"percolate_memory_size_in_bytes\":            float64(-1),\n\t\"percolate_queries\":                         float64(0),\n\t\"percolate_total\":                           float64(0),\n\t\"percolate_time_in_millis\":                  float64(0),\n\t\"translog_operations\":                       float64(17702),\n\t\"translog_size_in_bytes\":                    float64(17),\n\t\"recovery_current_as_source\":                float64(0),\n\t\"recovery_current_as_target\":                float64(0),\n\t\"recovery_throttle_time_in_millis\":          float64(0),\n\t\"docs_count\":                                float64(29652),\n\t\"docs_deleted\":                              float64(5229),\n\t\"flush_total_time_in_millis\":                float64(2401),\n\t\"flush_total\":                               float64(115),\n\t\"fielddata_memory_size_in_bytes\":            float64(12996),\n\t\"fielddata_evictions\":                       float64(0),\n\t\"search_fetch_current\":                      float64(0),\n\t\"search_open_contexts\":                      float64(0),\n\t\"search_query_total\":                        float64(1452),\n\t\"search_query_time_in_millis\":               float64(5695),\n\t\"search_query_current\":                      float64(0),\n\t\"search_fetch_total\":                        float64(414),\n\t\"search_fetch_time_in_millis\":               float64(146),\n\t\"warmer_current\":                            float64(0),\n\t\"warmer_total\":                              float64(2319),\n\t\"warmer_total_time_in_millis\":               float64(448),\n\t\"segments_count\":                            float64(134),\n\t\"segments_memory_in_bytes\":                  float64(1285212),\n\t\"segments_index_writer_memory_in_bytes\":     float64(0),\n\t\"segments_index_writer_max_memory_in_bytes\": float64(172368955),\n\t\"segments_version_map_memory_in_bytes\":      float64(611844),\n\t\"segments_fixed_bit_set_memory_in_bytes\":    float64(0),\n}\n\nvar nodestatsOsExpected = map[string]interface{}{\n\t\"load_average_0\":           float64(0.01),\n\t\"load_average_1\":           float64(0.04),\n\t\"load_average_2\":           float64(0.05),\n\t\"swap_used_in_bytes\":       float64(0),\n\t\"swap_free_in_bytes\":       float64(487997440),\n\t\"timestamp\":                float64(1436460392944),\n\t\"mem_free_percent\":         float64(74),\n\t\"mem_used_percent\":         float64(25),\n\t\"mem_actual_free_in_bytes\": float64(1565470720),\n\t\"mem_actual_used_in_bytes\": float64(534159360),\n\t\"mem_free_in_bytes\":        float64(477761536),\n\t\"mem_used_in_bytes\":        float64(1621868544),\n}\n\nvar nodestatsProcessExpected = map[string]interface{}{\n\t\"mem_total_virtual_in_bytes\": float64(4747890688),\n\t\"timestamp\":                  float64(1436460392945),\n\t\"open_file_descriptors\":      float64(160),\n\t\"cpu_total_in_millis\":        float64(15480),\n\t\"cpu_percent\":                float64(2),\n\t\"cpu_sys_in_millis\":          float64(1870),\n\t\"cpu_user_in_millis\":         float64(13610),\n}\n\nvar nodestatsJvmExpected = map[string]interface{}{\n\t\"timestamp\":                                     float64(1436460392945),\n\t\"uptime_in_millis\":                              float64(202245),\n\t\"mem_non_heap_used_in_bytes\":                    float64(39634576),\n\t\"mem_non_heap_committed_in_bytes\":               float64(40841216),\n\t\"mem_pools_young_max_in_bytes\":                  float64(279183360),\n\t\"mem_pools_young_peak_used_in_bytes\":            float64(71630848),\n\t\"mem_pools_young_peak_max_in_bytes\":             float64(279183360),\n\t\"mem_pools_young_used_in_bytes\":                 float64(32685760),\n\t\"mem_pools_survivor_peak_used_in_bytes\":         float64(8912888),\n\t\"mem_pools_survivor_peak_max_in_bytes\":          float64(34865152),\n\t\"mem_pools_survivor_used_in_bytes\":              float64(8912880),\n\t\"mem_pools_survivor_max_in_bytes\":               float64(34865152),\n\t\"mem_pools_old_peak_max_in_bytes\":               float64(724828160),\n\t\"mem_pools_old_used_in_bytes\":                   float64(11110928),\n\t\"mem_pools_old_max_in_bytes\":                    float64(724828160),\n\t\"mem_pools_old_peak_used_in_bytes\":              float64(14354608),\n\t\"mem_heap_used_in_bytes\":                        float64(52709568),\n\t\"mem_heap_used_percent\":                         float64(5),\n\t\"mem_heap_committed_in_bytes\":                   float64(259522560),\n\t\"mem_heap_max_in_bytes\":                         float64(1038876672),\n\t\"threads_peak_count\":                            float64(45),\n\t\"threads_count\":                                 float64(44),\n\t\"gc_collectors_young_collection_count\":          float64(2),\n\t\"gc_collectors_young_collection_time_in_millis\": float64(98),\n\t\"gc_collectors_old_collection_count\":            float64(1),\n\t\"gc_collectors_old_collection_time_in_millis\":   float64(24),\n\t\"buffer_pools_direct_count\":                     float64(40),\n\t\"buffer_pools_direct_used_in_bytes\":             float64(6304239),\n\t\"buffer_pools_direct_total_capacity_in_bytes\":   float64(6304239),\n\t\"buffer_pools_mapped_count\":                     float64(0),\n\t\"buffer_pools_mapped_used_in_bytes\":             float64(0),\n\t\"buffer_pools_mapped_total_capacity_in_bytes\":   float64(0),\n}\n\nvar nodestatsThreadPoolExpected = map[string]interface{}{\n\t\"merge_threads\":                 float64(6),\n\t\"merge_queue\":                   float64(4),\n\t\"merge_active\":                  float64(5),\n\t\"merge_rejected\":                float64(2),\n\t\"merge_largest\":                 float64(5),\n\t\"merge_completed\":               float64(1),\n\t\"bulk_threads\":                  float64(4),\n\t\"bulk_queue\":                    float64(5),\n\t\"bulk_active\":                   float64(7),\n\t\"bulk_rejected\":                 float64(3),\n\t\"bulk_largest\":                  float64(1),\n\t\"bulk_completed\":                float64(4),\n\t\"warmer_threads\":                float64(2),\n\t\"warmer_queue\":                  float64(7),\n\t\"warmer_active\":                 float64(3),\n\t\"warmer_rejected\":               float64(2),\n\t\"warmer_largest\":                float64(3),\n\t\"warmer_completed\":              float64(1),\n\t\"get_largest\":                   float64(2),\n\t\"get_completed\":                 float64(1),\n\t\"get_threads\":                   float64(1),\n\t\"get_queue\":                     float64(8),\n\t\"get_active\":                    float64(4),\n\t\"get_rejected\":                  float64(3),\n\t\"index_threads\":                 float64(6),\n\t\"index_queue\":                   float64(8),\n\t\"index_active\":                  float64(4),\n\t\"index_rejected\":                float64(2),\n\t\"index_largest\":                 float64(3),\n\t\"index_completed\":               float64(6),\n\t\"suggest_threads\":               float64(2),\n\t\"suggest_queue\":                 float64(7),\n\t\"suggest_active\":                float64(2),\n\t\"suggest_rejected\":              float64(1),\n\t\"suggest_largest\":               float64(8),\n\t\"suggest_completed\":             float64(3),\n\t\"fetch_shard_store_queue\":       float64(7),\n\t\"fetch_shard_store_active\":      float64(4),\n\t\"fetch_shard_store_rejected\":    float64(2),\n\t\"fetch_shard_store_largest\":     float64(4),\n\t\"fetch_shard_store_completed\":   float64(1),\n\t\"fetch_shard_store_threads\":     float64(1),\n\t\"management_threads\":            float64(2),\n\t\"management_queue\":              float64(3),\n\t\"management_active\":             float64(1),\n\t\"management_rejected\":           float64(6),\n\t\"management_largest\":            float64(2),\n\t\"management_completed\":          float64(22),\n\t\"percolate_queue\":               float64(23),\n\t\"percolate_active\":              float64(13),\n\t\"percolate_rejected\":            float64(235),\n\t\"percolate_largest\":             float64(23),\n\t\"percolate_completed\":           float64(33),\n\t\"percolate_threads\":             float64(123),\n\t\"listener_active\":               float64(4),\n\t\"listener_rejected\":             float64(8),\n\t\"listener_largest\":              float64(1),\n\t\"listener_completed\":            float64(1),\n\t\"listener_threads\":              float64(1),\n\t\"listener_queue\":                float64(2),\n\t\"search_rejected\":               float64(7),\n\t\"search_largest\":                float64(2),\n\t\"search_completed\":              float64(4),\n\t\"search_threads\":                float64(5),\n\t\"search_queue\":                  float64(7),\n\t\"search_active\":                 float64(2),\n\t\"fetch_shard_started_threads\":   float64(3),\n\t\"fetch_shard_started_queue\":     float64(1),\n\t\"fetch_shard_started_active\":    float64(5),\n\t\"fetch_shard_started_rejected\":  float64(6),\n\t\"fetch_shard_started_largest\":   float64(4),\n\t\"fetch_shard_started_completed\": float64(54),\n\t\"refresh_rejected\":              float64(4),\n\t\"refresh_largest\":               float64(8),\n\t\"refresh_completed\":             float64(3),\n\t\"refresh_threads\":               float64(23),\n\t\"refresh_queue\":                 float64(7),\n\t\"refresh_active\":                float64(3),\n\t\"optimize_threads\":              float64(3),\n\t\"optimize_queue\":                float64(4),\n\t\"optimize_active\":               float64(1),\n\t\"optimize_rejected\":             float64(2),\n\t\"optimize_largest\":              float64(7),\n\t\"optimize_completed\":            float64(3),\n\t\"snapshot_largest\":              float64(1),\n\t\"snapshot_completed\":            float64(0),\n\t\"snapshot_threads\":              float64(8),\n\t\"snapshot_queue\":                float64(5),\n\t\"snapshot_active\":               float64(6),\n\t\"snapshot_rejected\":             float64(2),\n\t\"generic_threads\":               float64(1),\n\t\"generic_queue\":                 float64(4),\n\t\"generic_active\":                float64(6),\n\t\"generic_rejected\":              float64(3),\n\t\"generic_largest\":               float64(2),\n\t\"generic_completed\":             float64(27),\n\t\"flush_threads\":                 float64(3),\n\t\"flush_queue\":                   float64(8),\n\t\"flush_active\":                  float64(0),\n\t\"flush_rejected\":                float64(1),\n\t\"flush_largest\":                 float64(5),\n\t\"flush_completed\":               float64(3),\n}\n\nvar nodestatsFsExpected = map[string]interface{}{\n\t\"data_0_total_in_bytes\":     float64(19507089408),\n\t\"data_0_free_in_bytes\":      float64(16909316096),\n\t\"data_0_available_in_bytes\": float64(15894814720),\n\t\"timestamp\":                 float64(1436460392946),\n\t\"total_free_in_bytes\":       float64(16909316096),\n\t\"total_available_in_bytes\":  float64(15894814720),\n\t\"total_total_in_bytes\":      float64(19507089408),\n}\n\nvar nodestatsTransportExpected = map[string]interface{}{\n\t\"server_open\":      float64(13),\n\t\"rx_count\":         float64(6),\n\t\"rx_size_in_bytes\": float64(1380),\n\t\"tx_count\":         float64(6),\n\t\"tx_size_in_bytes\": float64(1380),\n}\n\nvar nodestatsHTTPExpected = map[string]interface{}{\n\t\"current_open\": float64(3),\n\t\"total_opened\": float64(3),\n}\n\nvar nodestatsBreakersExpected = map[string]interface{}{\n\t\"fielddata_estimated_size_in_bytes\": float64(0),\n\t\"fielddata_overhead\":                float64(1.03),\n\t\"fielddata_tripped\":                 float64(0),\n\t\"fielddata_limit_size_in_bytes\":     float64(623326003),\n\t\"request_estimated_size_in_bytes\":   float64(0),\n\t\"request_overhead\":                  float64(1.0),\n\t\"request_tripped\":                   float64(0),\n\t\"request_limit_size_in_bytes\":       float64(415550668),\n\t\"parent_overhead\":                   float64(1.0),\n\t\"parent_tripped\":                    float64(0),\n\t\"parent_limit_size_in_bytes\":        float64(727213670),\n\t\"parent_estimated_size_in_bytes\":    float64(0),\n}\n\nconst clusterStatsResponse = `\n{\n   \"host\":\"ip-10-0-1-214\",\n   \"log_type\":\"metrics\",\n   \"timestamp\":1475767451229,\n   \"log_level\":\"INFO\",\n   \"node_name\":\"test.host.com\",\n   \"cluster_name\":\"es-testcluster\",\n   \"status\":\"red\",\n   \"indices\":{\n      \"count\":1,\n      \"shards\":{\n         \"total\":4,\n         \"primaries\":4,\n         \"replication\":0.0,\n         \"index\":{\n            \"shards\":{\n               \"min\":4,\n               \"max\":4,\n               \"avg\":4.0\n            },\n            \"primaries\":{\n               \"min\":4,\n               \"max\":4,\n               \"avg\":4.0\n            },\n            \"replication\":{\n               \"min\":0.0,\n               \"max\":0.0,\n               \"avg\":0.0\n            }\n         }\n      },\n      \"docs\":{\n         \"count\":4,\n         \"deleted\":0\n      },\n      \"store\":{\n         \"size_in_bytes\":17084,\n         \"throttle_time_in_millis\":0\n      },\n      \"fielddata\":{\n         \"memory_size_in_bytes\":0,\n         \"evictions\":0\n      },\n      \"query_cache\":{\n         \"memory_size_in_bytes\":0,\n         \"total_count\":0,\n         \"hit_count\":0,\n         \"miss_count\":0,\n         \"cache_size\":0,\n         \"cache_count\":0,\n         \"evictions\":0\n      },\n      \"completion\":{\n         \"size_in_bytes\":0\n      },\n      \"segments\":{\n         \"count\":4,\n         \"memory_in_bytes\":11828,\n         \"terms_memory_in_bytes\":8932,\n         \"stored_fields_memory_in_bytes\":1248,\n         \"term_vectors_memory_in_bytes\":0,\n         \"norms_memory_in_bytes\":1280,\n         \"doc_values_memory_in_bytes\":368,\n         \"index_writer_memory_in_bytes\":0,\n         \"index_writer_max_memory_in_bytes\":2048000,\n         \"version_map_memory_in_bytes\":0,\n         \"fixed_bit_set_memory_in_bytes\":0\n      },\n      \"percolate\":{\n         \"total\":0,\n         \"time_in_millis\":0,\n         \"current\":0,\n         \"memory_size_in_bytes\":-1,\n         \"memory_size\":\"-1b\",\n         \"queries\":0\n      }\n   },\n   \"nodes\":{\n      \"count\":{\n         \"total\":1,\n         \"master_only\":0,\n         \"data_only\":0,\n         \"master_data\":1,\n         \"client\":0\n      },\n      \"versions\":[\n         {\n         \"version\": \"2.3.3\"\n         }\n      ],\n      \"os\":{\n         \"available_processors\":1,\n         \"allocated_processors\":1,\n         \"mem\":{\n            \"total_in_bytes\":593301504\n         },\n         \"names\":[\n            {\n               \"name\":\"Linux\",\n               \"count\":1\n            }\n         ]\n      },\n      \"process\":{\n         \"cpu\":{\n            \"percent\":0\n         },\n         \"open_file_descriptors\":{\n            \"min\":145,\n            \"max\":145,\n            \"avg\":145\n         }\n      },\n      \"jvm\":{\n         \"max_uptime_in_millis\":11580527,\n         \"versions\":[\n            {\n               \"version\":\"1.8.0_101\",\n               \"vm_name\":\"OpenJDK 64-Bit Server VM\",\n               \"vm_version\":\"25.101-b13\",\n               \"vm_vendor\":\"Oracle Corporation\",\n               \"count\":1\n            }\n         ],\n         \"mem\":{\n            \"heap_used_in_bytes\":70550288,\n            \"heap_max_in_bytes\":1065025536\n         },\n         \"threads\":30\n      },\n      \"fs\":{\n         \"total_in_bytes\":8318783488,\n         \"free_in_bytes\":6447439872,\n         \"available_in_bytes\":6344785920\n      },\n      \"plugins\":[\n         {\n            \"name\":\"cloud-aws\",\n            \"version\":\"2.3.3\",\n            \"description\":\"The Amazon Web Service (AWS) Cloud plugin allows to use AWS API for the unicast discovery mechanism and add S3 repositories.\",\n            \"jvm\":true,\n            \"classname\":\"org.elasticsearch.plugin.cloud.aws.CloudAwsPlugin\",\n            \"isolated\":true,\n            \"site\":false\n         },\n         {\n            \"name\":\"kopf\",\n            \"version\":\"2.0.1\",\n            \"description\":\"kopf - simple web administration tool for Elasticsearch\",\n            \"url\":\"/_plugin/kopf/\",\n            \"jvm\":false,\n            \"site\":true\n         },\n         {\n            \"name\":\"tr-metrics\",\n            \"version\":\"7bd5b4b\",\n            \"description\":\"Logs cluster and node stats for performance monitoring.\",\n            \"jvm\":true,\n            \"classname\":\"com.trgr.elasticsearch.plugin.metrics.MetricsPlugin\",\n            \"isolated\":true,\n            \"site\":false\n         }\n      ]\n   }\n}\n`\n\nvar clusterstatsIndicesExpected = map[string]interface{}{\n\t\"completion_size_in_bytes\":                  float64(0),\n\t\"count\":                                     float64(1),\n\t\"docs_count\":                                float64(4),\n\t\"docs_deleted\":                              float64(0),\n\t\"fielddata_evictions\":                       float64(0),\n\t\"fielddata_memory_size_in_bytes\":            float64(0),\n\t\"percolate_current\":                         float64(0),\n\t\"percolate_memory_size_in_bytes\":            float64(-1),\n\t\"percolate_queries\":                         float64(0),\n\t\"percolate_time_in_millis\":                  float64(0),\n\t\"percolate_total\":                           float64(0),\n\t\"percolate_memory_size\":                     \"-1b\",\n\t\"query_cache_cache_count\":                   float64(0),\n\t\"query_cache_cache_size\":                    float64(0),\n\t\"query_cache_evictions\":                     float64(0),\n\t\"query_cache_hit_count\":                     float64(0),\n\t\"query_cache_memory_size_in_bytes\":          float64(0),\n\t\"query_cache_miss_count\":                    float64(0),\n\t\"query_cache_total_count\":                   float64(0),\n\t\"segments_count\":                            float64(4),\n\t\"segments_doc_values_memory_in_bytes\":       float64(368),\n\t\"segments_fixed_bit_set_memory_in_bytes\":    float64(0),\n\t\"segments_index_writer_max_memory_in_bytes\": float64(2.048e+06),\n\t\"segments_index_writer_memory_in_bytes\":     float64(0),\n\t\"segments_memory_in_bytes\":                  float64(11828),\n\t\"segments_norms_memory_in_bytes\":            float64(1280),\n\t\"segments_stored_fields_memory_in_bytes\":    float64(1248),\n\t\"segments_term_vectors_memory_in_bytes\":     float64(0),\n\t\"segments_terms_memory_in_bytes\":            float64(8932),\n\t\"segments_version_map_memory_in_bytes\":      float64(0),\n\t\"shards_index_primaries_avg\":                float64(4),\n\t\"shards_index_primaries_max\":                float64(4),\n\t\"shards_index_primaries_min\":                float64(4),\n\t\"shards_index_replication_avg\":              float64(0),\n\t\"shards_index_replication_max\":              float64(0),\n\t\"shards_index_replication_min\":              float64(0),\n\t\"shards_index_shards_avg\":                   float64(4),\n\t\"shards_index_shards_max\":                   float64(4),\n\t\"shards_index_shards_min\":                   float64(4),\n\t\"shards_primaries\":                          float64(4),\n\t\"shards_replication\":                        float64(0),\n\t\"shards_total\":                              float64(4),\n\t\"store_size_in_bytes\":                       float64(17084),\n\t\"store_throttle_time_in_millis\":             float64(0),\n}\n\nvar clusterstatsNodesExpected = map[string]interface{}{\n\t\"count_client\":                      float64(0),\n\t\"count_data_only\":                   float64(0),\n\t\"count_master_data\":                 float64(1),\n\t\"count_master_only\":                 float64(0),\n\t\"count_total\":                       float64(1),\n\t\"fs_available_in_bytes\":             float64(6.34478592e+09),\n\t\"fs_free_in_bytes\":                  float64(6.447439872e+09),\n\t\"fs_total_in_bytes\":                 float64(8.318783488e+09),\n\t\"jvm_max_uptime_in_millis\":          float64(1.1580527e+07),\n\t\"jvm_mem_heap_max_in_bytes\":         float64(1.065025536e+09),\n\t\"jvm_mem_heap_used_in_bytes\":        float64(7.0550288e+07),\n\t\"jvm_threads\":                       float64(30),\n\t\"jvm_versions_0_count\":              float64(1),\n\t\"jvm_versions_0_version\":            \"1.8.0_101\",\n\t\"jvm_versions_0_vm_name\":            \"OpenJDK 64-Bit Server VM\",\n\t\"jvm_versions_0_vm_vendor\":          \"Oracle Corporation\",\n\t\"jvm_versions_0_vm_version\":         \"25.101-b13\",\n\t\"os_allocated_processors\":           float64(1),\n\t\"os_available_processors\":           float64(1),\n\t\"os_mem_total_in_bytes\":             float64(5.93301504e+08),\n\t\"os_names_0_count\":                  float64(1),\n\t\"os_names_0_name\":                   \"Linux\",\n\t\"process_cpu_percent\":               float64(0),\n\t\"process_open_file_descriptors_avg\": float64(145),\n\t\"process_open_file_descriptors_max\": float64(145),\n\t\"process_open_file_descriptors_min\": float64(145),\n\t\"versions_0_version\":                \"2.3.3\",\n\t\"plugins_0_classname\":               \"org.elasticsearch.plugin.cloud.aws.CloudAwsPlugin\",\n\t\"plugins_0_description\": \"The Amazon Web Service (AWS) Cloud plugin allows to use AWS API \" +\n\t\t\"for the unicast discovery mechanism and add S3 repositories.\",\n\t\"plugins_0_isolated\":    true,\n\t\"plugins_0_jvm\":         true,\n\t\"plugins_0_name\":        \"cloud-aws\",\n\t\"plugins_0_site\":        false,\n\t\"plugins_0_version\":     \"2.3.3\",\n\t\"plugins_1_description\": \"kopf - simple web administration tool for Elasticsearch\",\n\t\"plugins_1_jvm\":         false,\n\t\"plugins_1_name\":        \"kopf\",\n\t\"plugins_1_site\":        true,\n\t\"plugins_1_url\":         \"/_plugin/kopf/\",\n\t\"plugins_1_version\":     \"2.0.1\",\n\t\"plugins_2_classname\":   \"com.trgr.elasticsearch.plugin.metrics.MetricsPlugin\",\n\t\"plugins_2_description\": \"Logs cluster and node stats for performance monitoring.\",\n\t\"plugins_2_isolated\":    true,\n\t\"plugins_2_jvm\":         true,\n\t\"plugins_2_name\":        \"tr-metrics\",\n\t\"plugins_2_site\":        false,\n\t\"plugins_2_version\":     \"7bd5b4b\",\n}\n\nconst IsMasterResult = \"SDFsfSDFsdfFSDSDfSFDSDF 10.206.124.66 10.206.124.66 test.host.com \"\n\nconst IsNotMasterResult = \"junk 10.206.124.66 10.206.124.66 test.junk.com \"\n\nconst clusterIndicesResponse = `\n{\n  \"_shards\": {\n    \"total\": 9,\n    \"successful\": 6,\n    \"failed\": 0\n  },\n  \"_all\": {\n    \"primaries\": {\n      \"docs\": {\n        \"count\": 999,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 267500\n      },\n      \"indexing\": {\n        \"index_total\": 999,\n        \"index_time_in_millis\": 548,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 62914560\n      },\n      \"refresh\": {\n        \"total\": 9,\n        \"total_time_in_millis\": 256,\n        \"external_total\": 9,\n        \"external_total_time_in_millis\": 258,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 6,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 3,\n        \"memory_in_bytes\": 12849,\n        \"terms_memory_in_bytes\": 10580,\n        \"stored_fields_memory_in_bytes\": 904,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 1152,\n        \"points_memory_in_bytes\": 9,\n        \"doc_values_memory_in_bytes\": 204,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 999,\n        \"size_in_bytes\": 226444,\n        \"uncommitted_operations\": 999,\n        \"uncommitted_size_in_bytes\": 226444,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    },\n    \"total\": {\n      \"docs\": {\n        \"count\": 1998,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 535000\n      },\n      \"indexing\": {\n        \"index_total\": 1998,\n        \"index_time_in_millis\": 793,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 125829120\n      },\n      \"refresh\": {\n        \"total\": 18,\n        \"total_time_in_millis\": 518,\n        \"external_total\": 18,\n        \"external_total_time_in_millis\": 522,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 12,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 6,\n        \"memory_in_bytes\": 25698,\n        \"terms_memory_in_bytes\": 21160,\n        \"stored_fields_memory_in_bytes\": 1808,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 2304,\n        \"points_memory_in_bytes\": 18,\n        \"doc_values_memory_in_bytes\": 408,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 1998,\n        \"size_in_bytes\": 452888,\n        \"uncommitted_operations\": 1998,\n        \"uncommitted_size_in_bytes\": 452888,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    }\n  },\n  \"indices\": {\n    \"twitter\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    }\n  }\n}`\n\nconst dateStampedIndicesResponse = `\n{\n  \"_shards\": {\n    \"total\": 9,\n    \"successful\": 6,\n    \"failed\": 0\n  },\n  \"_all\": {\n    \"primaries\": {\n      \"docs\": {\n        \"count\": 999,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 267500\n      },\n      \"indexing\": {\n        \"index_total\": 999,\n        \"index_time_in_millis\": 548,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 62914560\n      },\n      \"refresh\": {\n        \"total\": 9,\n        \"total_time_in_millis\": 256,\n        \"external_total\": 9,\n        \"external_total_time_in_millis\": 258,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 6,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 3,\n        \"memory_in_bytes\": 12849,\n        \"terms_memory_in_bytes\": 10580,\n        \"stored_fields_memory_in_bytes\": 904,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 1152,\n        \"points_memory_in_bytes\": 9,\n        \"doc_values_memory_in_bytes\": 204,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 999,\n        \"size_in_bytes\": 226444,\n        \"uncommitted_operations\": 999,\n        \"uncommitted_size_in_bytes\": 226444,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    },\n    \"total\": {\n      \"docs\": {\n        \"count\": 1998,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 535000\n      },\n      \"indexing\": {\n        \"index_total\": 1998,\n        \"index_time_in_millis\": 793,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 125829120\n      },\n      \"refresh\": {\n        \"total\": 18,\n        \"total_time_in_millis\": 518,\n        \"external_total\": 18,\n        \"external_total_time_in_millis\": 522,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 12,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 6,\n        \"memory_in_bytes\": 25698,\n        \"terms_memory_in_bytes\": 21160,\n        \"stored_fields_memory_in_bytes\": 1808,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 2304,\n        \"points_memory_in_bytes\": 18,\n        \"doc_values_memory_in_bytes\": 408,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 1998,\n        \"size_in_bytes\": 452888,\n        \"uncommitted_operations\": 1998,\n        \"uncommitted_size_in_bytes\": 452888,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    }\n  },\n  \"indices\": {\n    \"twitter_2020_08_02\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"twitter_2020_08_01\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"twitter_2020_07_31\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"influx2021.01.02\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"influx2020.12.31\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"influx2021.01.01\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    },\n    \"penguins\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      }\n    }\n  }\n}`\n\nvar clusterIndicesExpected = map[string]interface{}{\n\t\"completion_size_in_bytes\":               float64(0),\n\t\"docs_count\":                             float64(999),\n\t\"docs_deleted\":                           float64(0),\n\t\"fielddata_evictions\":                    float64(0),\n\t\"fielddata_memory_size_in_bytes\":         float64(0),\n\t\"flush_periodic\":                         float64(0),\n\t\"flush_total\":                            float64(0),\n\t\"flush_total_time_in_millis\":             float64(0),\n\t\"get_current\":                            float64(0),\n\t\"get_exists_time_in_millis\":              float64(0),\n\t\"get_exists_total\":                       float64(0),\n\t\"get_missing_time_in_millis\":             float64(0),\n\t\"get_missing_total\":                      float64(0),\n\t\"get_time_in_millis\":                     float64(0),\n\t\"get_total\":                              float64(0),\n\t\"indexing_delete_current\":                float64(0),\n\t\"indexing_delete_time_in_millis\":         float64(0),\n\t\"indexing_delete_total\":                  float64(0),\n\t\"indexing_index_current\":                 float64(0),\n\t\"indexing_index_failed\":                  float64(0),\n\t\"indexing_index_time_in_millis\":          float64(548),\n\t\"indexing_index_total\":                   float64(999),\n\t\"indexing_is_throttled\":                  false,\n\t\"indexing_noop_update_total\":             float64(0),\n\t\"indexing_throttle_time_in_millis\":       float64(0),\n\t\"merges_current\":                         float64(0),\n\t\"merges_current_docs\":                    float64(0),\n\t\"merges_current_size_in_bytes\":           float64(0),\n\t\"merges_total\":                           float64(0),\n\t\"merges_total_auto_throttle_in_bytes\":    float64(62914560),\n\t\"merges_total_docs\":                      float64(0),\n\t\"merges_total_size_in_bytes\":             float64(0),\n\t\"merges_total_stopped_time_in_millis\":    float64(0),\n\t\"merges_total_throttled_time_in_millis\":  float64(0),\n\t\"merges_total_time_in_millis\":            float64(0),\n\t\"query_cache_cache_count\":                float64(0),\n\t\"query_cache_cache_size\":                 float64(0),\n\t\"query_cache_evictions\":                  float64(0),\n\t\"query_cache_hit_count\":                  float64(0),\n\t\"query_cache_memory_size_in_bytes\":       float64(0),\n\t\"query_cache_miss_count\":                 float64(0),\n\t\"query_cache_total_count\":                float64(0),\n\t\"recovery_current_as_source\":             float64(0),\n\t\"recovery_current_as_target\":             float64(0),\n\t\"recovery_throttle_time_in_millis\":       float64(0),\n\t\"refresh_external_total\":                 float64(9),\n\t\"refresh_external_total_time_in_millis\":  float64(258),\n\t\"refresh_listeners\":                      float64(0),\n\t\"refresh_total\":                          float64(9),\n\t\"refresh_total_time_in_millis\":           float64(256),\n\t\"request_cache_evictions\":                float64(0),\n\t\"request_cache_hit_count\":                float64(0),\n\t\"request_cache_memory_size_in_bytes\":     float64(0),\n\t\"request_cache_miss_count\":               float64(0),\n\t\"search_fetch_current\":                   float64(0),\n\t\"search_fetch_time_in_millis\":            float64(0),\n\t\"search_fetch_total\":                     float64(0),\n\t\"search_open_contexts\":                   float64(0),\n\t\"search_query_current\":                   float64(0),\n\t\"search_query_time_in_millis\":            float64(0),\n\t\"search_query_total\":                     float64(0),\n\t\"search_scroll_current\":                  float64(0),\n\t\"search_scroll_time_in_millis\":           float64(0),\n\t\"search_scroll_total\":                    float64(0),\n\t\"search_suggest_current\":                 float64(0),\n\t\"search_suggest_time_in_millis\":          float64(0),\n\t\"search_suggest_total\":                   float64(0),\n\t\"segments_count\":                         float64(3),\n\t\"segments_doc_values_memory_in_bytes\":    float64(204),\n\t\"segments_fixed_bit_set_memory_in_bytes\": float64(0),\n\t\"segments_index_writer_memory_in_bytes\":  float64(0),\n\t\"segments_max_unsafe_auto_id_timestamp\":  float64(-1),\n\t\"segments_memory_in_bytes\":               float64(12849),\n\t\"segments_norms_memory_in_bytes\":         float64(1152),\n\t\"segments_points_memory_in_bytes\":        float64(9),\n\t\"segments_stored_fields_memory_in_bytes\": float64(904),\n\t\"segments_term_vectors_memory_in_bytes\":  float64(0),\n\t\"segments_terms_memory_in_bytes\":         float64(10580),\n\t\"segments_version_map_memory_in_bytes\":   float64(0),\n\t\"store_size_in_bytes\":                    float64(267500),\n\t\"translog_earliest_last_modified_age\":    float64(0),\n\t\"translog_operations\":                    float64(999),\n\t\"translog_size_in_bytes\":                 float64(226444),\n\t\"translog_uncommitted_operations\":        float64(999),\n\t\"translog_uncommitted_size_in_bytes\":     float64(226444),\n\t\"warmer_current\":                         float64(0),\n\t\"warmer_total\":                           float64(6),\n\t\"warmer_total_time_in_millis\":            float64(0),\n}\n\nconst clusterIndicesShardsResponse = `\n{\n  \"_shards\": {\n    \"total\": 9,\n    \"successful\": 6,\n    \"failed\": 0\n  },\n  \"_all\": {\n    \"primaries\": {\n      \"docs\": {\n        \"count\": 999,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 267500\n      },\n      \"indexing\": {\n        \"index_total\": 999,\n        \"index_time_in_millis\": 548,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 62914560\n      },\n      \"refresh\": {\n        \"total\": 9,\n        \"total_time_in_millis\": 256,\n        \"external_total\": 9,\n        \"external_total_time_in_millis\": 258,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 6,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 3,\n        \"memory_in_bytes\": 12849,\n        \"terms_memory_in_bytes\": 10580,\n        \"stored_fields_memory_in_bytes\": 904,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 1152,\n        \"points_memory_in_bytes\": 9,\n        \"doc_values_memory_in_bytes\": 204,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 999,\n        \"size_in_bytes\": 226444,\n        \"uncommitted_operations\": 999,\n        \"uncommitted_size_in_bytes\": 226444,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    },\n    \"total\": {\n      \"docs\": {\n        \"count\": 1998,\n        \"deleted\": 0\n      },\n      \"store\": {\n        \"size_in_bytes\": 535000\n      },\n      \"indexing\": {\n        \"index_total\": 1998,\n        \"index_time_in_millis\": 793,\n        \"index_current\": 0,\n        \"index_failed\": 0,\n        \"delete_total\": 0,\n        \"delete_time_in_millis\": 0,\n        \"delete_current\": 0,\n        \"noop_update_total\": 0,\n        \"is_throttled\": false,\n        \"throttle_time_in_millis\": 0\n      },\n      \"get\": {\n        \"total\": 0,\n        \"time_in_millis\": 0,\n        \"exists_total\": 0,\n        \"exists_time_in_millis\": 0,\n        \"missing_total\": 0,\n        \"missing_time_in_millis\": 0,\n        \"current\": 0\n      },\n      \"search\": {\n        \"open_contexts\": 0,\n        \"query_total\": 0,\n        \"query_time_in_millis\": 0,\n        \"query_current\": 0,\n        \"fetch_total\": 0,\n        \"fetch_time_in_millis\": 0,\n        \"fetch_current\": 0,\n        \"scroll_total\": 0,\n        \"scroll_time_in_millis\": 0,\n        \"scroll_current\": 0,\n        \"suggest_total\": 0,\n        \"suggest_time_in_millis\": 0,\n        \"suggest_current\": 0\n      },\n      \"merges\": {\n        \"current\": 0,\n        \"current_docs\": 0,\n        \"current_size_in_bytes\": 0,\n        \"total\": 0,\n        \"total_time_in_millis\": 0,\n        \"total_docs\": 0,\n        \"total_size_in_bytes\": 0,\n        \"total_stopped_time_in_millis\": 0,\n        \"total_throttled_time_in_millis\": 0,\n        \"total_auto_throttle_in_bytes\": 125829120\n      },\n      \"refresh\": {\n        \"total\": 18,\n        \"total_time_in_millis\": 518,\n        \"external_total\": 18,\n        \"external_total_time_in_millis\": 522,\n        \"listeners\": 0\n      },\n      \"flush\": {\n        \"total\": 0,\n        \"periodic\": 0,\n        \"total_time_in_millis\": 0\n      },\n      \"warmer\": {\n        \"current\": 0,\n        \"total\": 12,\n        \"total_time_in_millis\": 0\n      },\n      \"query_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"total_count\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0,\n        \"cache_size\": 0,\n        \"cache_count\": 0,\n        \"evictions\": 0\n      },\n      \"fielddata\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0\n      },\n      \"completion\": {\n        \"size_in_bytes\": 0\n      },\n      \"segments\": {\n        \"count\": 6,\n        \"memory_in_bytes\": 25698,\n        \"terms_memory_in_bytes\": 21160,\n        \"stored_fields_memory_in_bytes\": 1808,\n        \"term_vectors_memory_in_bytes\": 0,\n        \"norms_memory_in_bytes\": 2304,\n        \"points_memory_in_bytes\": 18,\n        \"doc_values_memory_in_bytes\": 408,\n        \"index_writer_memory_in_bytes\": 0,\n        \"version_map_memory_in_bytes\": 0,\n        \"fixed_bit_set_memory_in_bytes\": 0,\n        \"max_unsafe_auto_id_timestamp\": -1,\n        \"file_sizes\": {}\n      },\n      \"translog\": {\n        \"operations\": 1998,\n        \"size_in_bytes\": 452888,\n        \"uncommitted_operations\": 1998,\n        \"uncommitted_size_in_bytes\": 452888,\n        \"earliest_last_modified_age\": 0\n      },\n      \"request_cache\": {\n        \"memory_size_in_bytes\": 0,\n        \"evictions\": 0,\n        \"hit_count\": 0,\n        \"miss_count\": 0\n      },\n      \"recovery\": {\n        \"current_as_source\": 0,\n        \"current_as_target\": 0,\n        \"throttle_time_in_millis\": 0\n      }\n    }\n  },\n  \"indices\": {\n    \"twitter\": {\n      \"uuid\": \"AtNrbbl_QhirW0p7Fnq26A\",\n      \"primaries\": {\n        \"docs\": {\n          \"count\": 999,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 267500\n        },\n        \"indexing\": {\n          \"index_total\": 999,\n          \"index_time_in_millis\": 548,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 62914560\n        },\n        \"refresh\": {\n          \"total\": 9,\n          \"total_time_in_millis\": 256,\n          \"external_total\": 9,\n          \"external_total_time_in_millis\": 258,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 6,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 3,\n          \"memory_in_bytes\": 12849,\n          \"terms_memory_in_bytes\": 10580,\n          \"stored_fields_memory_in_bytes\": 904,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 1152,\n          \"points_memory_in_bytes\": 9,\n          \"doc_values_memory_in_bytes\": 204,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 999,\n          \"size_in_bytes\": 226444,\n          \"uncommitted_operations\": 999,\n          \"uncommitted_size_in_bytes\": 226444,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"total\": {\n        \"docs\": {\n          \"count\": 1998,\n          \"deleted\": 0\n        },\n        \"store\": {\n          \"size_in_bytes\": 535000\n        },\n        \"indexing\": {\n          \"index_total\": 1998,\n          \"index_time_in_millis\": 793,\n          \"index_current\": 0,\n          \"index_failed\": 0,\n          \"delete_total\": 0,\n          \"delete_time_in_millis\": 0,\n          \"delete_current\": 0,\n          \"noop_update_total\": 0,\n          \"is_throttled\": false,\n          \"throttle_time_in_millis\": 0\n        },\n        \"get\": {\n          \"total\": 0,\n          \"time_in_millis\": 0,\n          \"exists_total\": 0,\n          \"exists_time_in_millis\": 0,\n          \"missing_total\": 0,\n          \"missing_time_in_millis\": 0,\n          \"current\": 0\n        },\n        \"search\": {\n          \"open_contexts\": 0,\n          \"query_total\": 0,\n          \"query_time_in_millis\": 0,\n          \"query_current\": 0,\n          \"fetch_total\": 0,\n          \"fetch_time_in_millis\": 0,\n          \"fetch_current\": 0,\n          \"scroll_total\": 0,\n          \"scroll_time_in_millis\": 0,\n          \"scroll_current\": 0,\n          \"suggest_total\": 0,\n          \"suggest_time_in_millis\": 0,\n          \"suggest_current\": 0\n        },\n        \"merges\": {\n          \"current\": 0,\n          \"current_docs\": 0,\n          \"current_size_in_bytes\": 0,\n          \"total\": 0,\n          \"total_time_in_millis\": 0,\n          \"total_docs\": 0,\n          \"total_size_in_bytes\": 0,\n          \"total_stopped_time_in_millis\": 0,\n          \"total_throttled_time_in_millis\": 0,\n          \"total_auto_throttle_in_bytes\": 125829120\n        },\n        \"refresh\": {\n          \"total\": 18,\n          \"total_time_in_millis\": 518,\n          \"external_total\": 18,\n          \"external_total_time_in_millis\": 522,\n          \"listeners\": 0\n        },\n        \"flush\": {\n          \"total\": 0,\n          \"periodic\": 0,\n          \"total_time_in_millis\": 0\n        },\n        \"warmer\": {\n          \"current\": 0,\n          \"total\": 12,\n          \"total_time_in_millis\": 0\n        },\n        \"query_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"total_count\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0,\n          \"cache_size\": 0,\n          \"cache_count\": 0,\n          \"evictions\": 0\n        },\n        \"fielddata\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0\n        },\n        \"completion\": {\n          \"size_in_bytes\": 0\n        },\n        \"segments\": {\n          \"count\": 6,\n          \"memory_in_bytes\": 25698,\n          \"terms_memory_in_bytes\": 21160,\n          \"stored_fields_memory_in_bytes\": 1808,\n          \"term_vectors_memory_in_bytes\": 0,\n          \"norms_memory_in_bytes\": 2304,\n          \"points_memory_in_bytes\": 18,\n          \"doc_values_memory_in_bytes\": 408,\n          \"index_writer_memory_in_bytes\": 0,\n          \"version_map_memory_in_bytes\": 0,\n          \"fixed_bit_set_memory_in_bytes\": 0,\n          \"max_unsafe_auto_id_timestamp\": -1,\n          \"file_sizes\": {}\n        },\n        \"translog\": {\n          \"operations\": 1998,\n          \"size_in_bytes\": 452888,\n          \"uncommitted_operations\": 1998,\n          \"uncommitted_size_in_bytes\": 452888,\n          \"earliest_last_modified_age\": 0\n        },\n        \"request_cache\": {\n          \"memory_size_in_bytes\": 0,\n          \"evictions\": 0,\n          \"hit_count\": 0,\n          \"miss_count\": 0\n        },\n        \"recovery\": {\n          \"current_as_source\": 0,\n          \"current_as_target\": 0,\n          \"throttle_time_in_millis\": 0\n        }\n      },\n      \"shards\": {\n        \"0\": [\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": true,\n              \"node\": \"oqvR8I1dTpONvwRM30etww\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 340,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 90564\n            },\n            \"indexing\": {\n              \"index_total\": 340,\n              \"index_time_in_millis\": 176,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 103,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 105,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 32\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4301,\n              \"terms_memory_in_bytes\": 3534,\n              \"stored_fields_memory_in_bytes\": 312,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 340,\n              \"size_in_bytes\": 77158,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936870\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"13gxQDHZ96BnNkzSgEdElQ==\",\n              \"generation\": 4,\n              \"user_data\": {\n                \"local_checkpoint\": \"339\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"340\",\n                \"translog_uuid\": \"4rp02VCQRTSJXgochWk3Hg\",\n                \"history_uuid\": \"-od5QvNmQlero8jatbG-5w\",\n                \"sync_id\": \"KKglZYafSaWN_MFUbpNviA\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"339\"\n              },\n              \"num_docs\": 340\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 339,\n              \"local_checkpoint\": 339,\n              \"global_checkpoint\": 339\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          },\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": false,\n              \"node\": \"0jfDeZxuTsGblcDGa39DzQ\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 340,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 90564\n            },\n            \"indexing\": {\n              \"index_total\": 340,\n              \"index_time_in_millis\": 99,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 139,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 140,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 34\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4301,\n              \"terms_memory_in_bytes\": 3534,\n              \"stored_fields_memory_in_bytes\": 312,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 340,\n              \"size_in_bytes\": 77158,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936653\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"A8QO9SiMWYX000riUOApBg==\",\n              \"generation\": 5,\n              \"user_data\": {\n                \"local_checkpoint\": \"339\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"340\",\n                \"translog_uuid\": \"9kWpEKQyQ3yIUwwEp4fP8A\",\n                \"history_uuid\": \"-od5QvNmQlero8jatbG-5w\",\n                \"sync_id\": \"KKglZYafSaWN_MFUbpNviA\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"339\"\n              },\n              \"num_docs\": 340\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 339,\n              \"local_checkpoint\": 339,\n              \"global_checkpoint\": 339\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          }\n        ],\n        \"1\": [\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": false,\n              \"node\": \"oqvR8I1dTpONvwRM30etww\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 352,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 94584\n            },\n            \"indexing\": {\n              \"index_total\": 352,\n              \"index_time_in_millis\": 66,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 104,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 106,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 26\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4280,\n              \"terms_memory_in_bytes\": 3529,\n              \"stored_fields_memory_in_bytes\": 296,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 352,\n              \"size_in_bytes\": 79980,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936144\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"13gxQDHZ96BnNkzSgEdEkg==\",\n              \"generation\": 5,\n              \"user_data\": {\n                \"local_checkpoint\": \"351\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"352\",\n                \"translog_uuid\": \"SjKxb5TIRqCinxWbqVBo-g\",\n                \"history_uuid\": \"3SAavs9KTPm-jhaioYg4UA\",\n                \"sync_id\": \"swZVzk6tShS0tcbBQt9AjA\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"351\"\n              },\n              \"num_docs\": 352\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 351,\n              \"local_checkpoint\": 351,\n              \"global_checkpoint\": 351\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          },\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": true,\n              \"node\": \"0jfDeZxuTsGblcDGa39DzQ\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 352,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 94584\n            },\n            \"indexing\": {\n              \"index_total\": 352,\n              \"index_time_in_millis\": 154,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 74,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 74,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 29\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4280,\n              \"terms_memory_in_bytes\": 3529,\n              \"stored_fields_memory_in_bytes\": 296,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 352,\n              \"size_in_bytes\": 79980,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936839\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"A8QO9SiMWYX000riUOApAw==\",\n              \"generation\": 4,\n              \"user_data\": {\n                \"local_checkpoint\": \"351\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"352\",\n                \"translog_uuid\": \"GpauXMbxQpWKUYGYqQUIdQ\",\n                \"history_uuid\": \"3SAavs9KTPm-jhaioYg4UA\",\n                \"sync_id\": \"swZVzk6tShS0tcbBQt9AjA\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"351\"\n              },\n              \"num_docs\": 352\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 351,\n              \"local_checkpoint\": 351,\n              \"global_checkpoint\": 351\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          }\n        ],\n        \"2\": [\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": true,\n              \"node\": \"oqvR8I1dTpONvwRM30etww\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 307,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 82727\n            },\n            \"indexing\": {\n              \"index_total\": 307,\n              \"index_time_in_millis\": 218,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 86,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 87,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 33\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4268,\n              \"terms_memory_in_bytes\": 3517,\n              \"stored_fields_memory_in_bytes\": 296,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 307,\n              \"size_in_bytes\": 69471,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936881\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"13gxQDHZ96BnNkzSgEdElg==\",\n              \"generation\": 4,\n              \"user_data\": {\n                \"local_checkpoint\": \"306\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"307\",\n                \"translog_uuid\": \"Y0a3bdIQTD2Ir6Ex9J3gSQ\",\n                \"history_uuid\": \"WmsCMyRyRaGz9mnR50wYFA\",\n                \"sync_id\": \"nvNppgfgTp63llS8r-Pwiw\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"306\"\n              },\n              \"num_docs\": 307\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 306,\n              \"local_checkpoint\": 306,\n              \"global_checkpoint\": 306\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          },\n          {\n            \"routing\": {\n              \"state\": \"STARTED\",\n              \"primary\": false,\n              \"node\": \"0jfDeZxuTsGblcDGa39DzQ\",\n              \"relocating_node\": null\n            },\n            \"docs\": {\n              \"count\": 307,\n              \"deleted\": 0\n            },\n            \"store\": {\n              \"size_in_bytes\": 82727\n            },\n            \"indexing\": {\n              \"index_total\": 307,\n              \"index_time_in_millis\": 80,\n              \"index_current\": 0,\n              \"index_failed\": 0,\n              \"delete_total\": 0,\n              \"delete_time_in_millis\": 0,\n              \"delete_current\": 0,\n              \"noop_update_total\": 0,\n              \"is_throttled\": false,\n              \"throttle_time_in_millis\": 0\n            },\n            \"get\": {\n              \"total\": 0,\n              \"time_in_millis\": 0,\n              \"exists_total\": 0,\n              \"exists_time_in_millis\": 0,\n              \"missing_total\": 0,\n              \"missing_time_in_millis\": 0,\n              \"current\": 0\n            },\n            \"search\": {\n              \"open_contexts\": 0,\n              \"query_total\": 0,\n              \"query_time_in_millis\": 0,\n              \"query_current\": 0,\n              \"fetch_total\": 0,\n              \"fetch_time_in_millis\": 0,\n              \"fetch_current\": 0,\n              \"scroll_total\": 0,\n              \"scroll_time_in_millis\": 0,\n              \"scroll_current\": 0,\n              \"suggest_total\": 0,\n              \"suggest_time_in_millis\": 0,\n              \"suggest_current\": 0\n            },\n            \"merges\": {\n              \"current\": 0,\n              \"current_docs\": 0,\n              \"current_size_in_bytes\": 0,\n              \"total\": 0,\n              \"total_time_in_millis\": 0,\n              \"total_docs\": 0,\n              \"total_size_in_bytes\": 0,\n              \"total_stopped_time_in_millis\": 0,\n              \"total_throttled_time_in_millis\": 0,\n              \"total_auto_throttle_in_bytes\": 20971520\n            },\n            \"refresh\": {\n              \"total\": 6,\n              \"total_time_in_millis\": 33,\n              \"external_total\": 4,\n              \"external_total_time_in_millis\": 30,\n              \"listeners\": 0\n            },\n            \"flush\": {\n              \"total\": 1,\n              \"periodic\": 0,\n              \"total_time_in_millis\": 37\n            },\n            \"warmer\": {\n              \"current\": 0,\n              \"total\": 3,\n              \"total_time_in_millis\": 0\n            },\n            \"query_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"total_count\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0,\n              \"cache_size\": 0,\n              \"cache_count\": 0,\n              \"evictions\": 0\n            },\n            \"fielddata\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0\n            },\n            \"completion\": {\n              \"size_in_bytes\": 0\n            },\n            \"segments\": {\n              \"count\": 1,\n              \"memory_in_bytes\": 4268,\n              \"terms_memory_in_bytes\": 3517,\n              \"stored_fields_memory_in_bytes\": 296,\n              \"term_vectors_memory_in_bytes\": 0,\n              \"norms_memory_in_bytes\": 384,\n              \"points_memory_in_bytes\": 3,\n              \"doc_values_memory_in_bytes\": 68,\n              \"index_writer_memory_in_bytes\": 0,\n              \"version_map_memory_in_bytes\": 0,\n              \"fixed_bit_set_memory_in_bytes\": 0,\n              \"max_unsafe_auto_id_timestamp\": -1,\n              \"file_sizes\": {}\n            },\n            \"translog\": {\n              \"operations\": 307,\n              \"size_in_bytes\": 69471,\n              \"uncommitted_operations\": 0,\n              \"uncommitted_size_in_bytes\": 55,\n              \"earliest_last_modified_age\": 936696\n            },\n            \"request_cache\": {\n              \"memory_size_in_bytes\": 0,\n              \"evictions\": 0,\n              \"hit_count\": 0,\n              \"miss_count\": 0\n            },\n            \"recovery\": {\n              \"current_as_source\": 0,\n              \"current_as_target\": 0,\n              \"throttle_time_in_millis\": 0\n            },\n            \"commit\": {\n              \"id\": \"A8QO9SiMWYX000riUOApBw==\",\n              \"generation\": 5,\n              \"user_data\": {\n                \"local_checkpoint\": \"306\",\n                \"max_unsafe_auto_id_timestamp\": \"-1\",\n                \"min_retained_seq_no\": \"307\",\n                \"translog_uuid\": \"s62inR7FRA2p86axtAIvgA\",\n                \"history_uuid\": \"WmsCMyRyRaGz9mnR50wYFA\",\n                \"sync_id\": \"nvNppgfgTp63llS8r-Pwiw\",\n                \"translog_generation\": \"3\",\n                \"max_seq_no\": \"306\"\n              },\n              \"num_docs\": 307\n            },\n            \"seq_no\": {\n              \"max_seq_no\": 306,\n              \"local_checkpoint\": 306,\n              \"global_checkpoint\": 306\n            },\n            \"retention_leases\": {\n              \"primary_term\": 1,\n              \"version\": 0,\n              \"leases\": []\n            },\n            \"shard_path\": {\n              \"state_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"data_path\": \"/usr/share/elasticsearch/data/nodes/0\",\n              \"is_custom_data_path\": false\n            }\n          }\n        ]\n      }\n    }\n  }\n}`\n\nvar clusterIndicesPrimaryShardsExpected = map[string]interface{}{\n\t\"commit_generation\":                      float64(4),\n\t\"commit_num_docs\":                        float64(340),\n\t\"completion_size_in_bytes\":               float64(0),\n\t\"docs_count\":                             float64(340),\n\t\"docs_deleted\":                           float64(0),\n\t\"fielddata_evictions\":                    float64(0),\n\t\"fielddata_memory_size_in_bytes\":         float64(0),\n\t\"flush_periodic\":                         float64(0),\n\t\"flush_total\":                            float64(1),\n\t\"flush_total_time_in_millis\":             float64(32),\n\t\"get_current\":                            float64(0),\n\t\"get_exists_time_in_millis\":              float64(0),\n\t\"get_exists_total\":                       float64(0),\n\t\"get_missing_time_in_millis\":             float64(0),\n\t\"get_missing_total\":                      float64(0),\n\t\"get_time_in_millis\":                     float64(0),\n\t\"get_total\":                              float64(0),\n\t\"indexing_delete_current\":                float64(0),\n\t\"indexing_delete_time_in_millis\":         float64(0),\n\t\"indexing_delete_total\":                  float64(0),\n\t\"indexing_index_current\":                 float64(0),\n\t\"indexing_index_failed\":                  float64(0),\n\t\"indexing_index_time_in_millis\":          float64(176),\n\t\"indexing_index_total\":                   float64(340),\n\t\"indexing_noop_update_total\":             float64(0),\n\t\"indexing_throttle_time_in_millis\":       float64(0),\n\t\"merges_current\":                         float64(0),\n\t\"merges_current_docs\":                    float64(0),\n\t\"merges_current_size_in_bytes\":           float64(0),\n\t\"merges_total\":                           float64(0),\n\t\"merges_total_auto_throttle_in_bytes\":    float64(2.097152e+07),\n\t\"merges_total_docs\":                      float64(0),\n\t\"merges_total_size_in_bytes\":             float64(0),\n\t\"merges_total_stopped_time_in_millis\":    float64(0),\n\t\"merges_total_throttled_time_in_millis\":  float64(0),\n\t\"merges_total_time_in_millis\":            float64(0),\n\t\"query_cache_cache_count\":                float64(0),\n\t\"query_cache_cache_size\":                 float64(0),\n\t\"query_cache_evictions\":                  float64(0),\n\t\"query_cache_hit_count\":                  float64(0),\n\t\"query_cache_memory_size_in_bytes\":       float64(0),\n\t\"query_cache_miss_count\":                 float64(0),\n\t\"query_cache_total_count\":                float64(0),\n\t\"recovery_current_as_source\":             float64(0),\n\t\"recovery_current_as_target\":             float64(0),\n\t\"recovery_throttle_time_in_millis\":       float64(0),\n\t\"refresh_external_total\":                 float64(4),\n\t\"refresh_external_total_time_in_millis\":  float64(105),\n\t\"refresh_listeners\":                      float64(0),\n\t\"refresh_total\":                          float64(6),\n\t\"refresh_total_time_in_millis\":           float64(103),\n\t\"request_cache_evictions\":                float64(0),\n\t\"request_cache_hit_count\":                float64(0),\n\t\"request_cache_memory_size_in_bytes\":     float64(0),\n\t\"request_cache_miss_count\":               float64(0),\n\t\"retention_leases_primary_term\":          float64(1),\n\t\"retention_leases_version\":               float64(0),\n\t\"routing_state\":                          int(3),\n\t\"search_fetch_current\":                   float64(0),\n\t\"search_fetch_time_in_millis\":            float64(0),\n\t\"search_fetch_total\":                     float64(0),\n\t\"search_open_contexts\":                   float64(0),\n\t\"search_query_current\":                   float64(0),\n\t\"search_query_time_in_millis\":            float64(0),\n\t\"search_query_total\":                     float64(0),\n\t\"search_scroll_current\":                  float64(0),\n\t\"search_scroll_time_in_millis\":           float64(0),\n\t\"search_scroll_total\":                    float64(0),\n\t\"search_suggest_current\":                 float64(0),\n\t\"search_suggest_time_in_millis\":          float64(0),\n\t\"search_suggest_total\":                   float64(0),\n\t\"segments_count\":                         float64(1),\n\t\"segments_doc_values_memory_in_bytes\":    float64(68),\n\t\"segments_fixed_bit_set_memory_in_bytes\": float64(0),\n\t\"segments_index_writer_memory_in_bytes\":  float64(0),\n\t\"segments_max_unsafe_auto_id_timestamp\":  float64(-1),\n\t\"segments_memory_in_bytes\":               float64(4301),\n\t\"segments_norms_memory_in_bytes\":         float64(384),\n\t\"segments_points_memory_in_bytes\":        float64(3),\n\t\"segments_stored_fields_memory_in_bytes\": float64(312),\n\t\"segments_term_vectors_memory_in_bytes\":  float64(0),\n\t\"segments_terms_memory_in_bytes\":         float64(3534),\n\t\"segments_version_map_memory_in_bytes\":   float64(0),\n\t\"seq_no_global_checkpoint\":               float64(339),\n\t\"seq_no_local_checkpoint\":                float64(339),\n\t\"seq_no_max_seq_no\":                      float64(339),\n\t\"store_size_in_bytes\":                    float64(90564),\n\t\"translog_earliest_last_modified_age\":    float64(936870),\n\t\"translog_operations\":                    float64(340),\n\t\"translog_size_in_bytes\":                 float64(77158),\n\t\"translog_uncommitted_operations\":        float64(0),\n\t\"translog_uncommitted_size_in_bytes\":     float64(55),\n\t\"warmer_current\":                         float64(0),\n\t\"warmer_total\":                           float64(3),\n\t\"warmer_total_time_in_millis\":            float64(0),\n}\n\nvar clusterIndicesReplicaShardsExpected = map[string]interface{}{\n\t\"commit_generation\":                      float64(5),\n\t\"commit_num_docs\":                        float64(352),\n\t\"completion_size_in_bytes\":               float64(0),\n\t\"docs_count\":                             float64(352),\n\t\"docs_deleted\":                           float64(0),\n\t\"fielddata_evictions\":                    float64(0),\n\t\"fielddata_memory_size_in_bytes\":         float64(0),\n\t\"flush_periodic\":                         float64(0),\n\t\"flush_total\":                            float64(1),\n\t\"flush_total_time_in_millis\":             float64(26),\n\t\"get_current\":                            float64(0),\n\t\"get_exists_time_in_millis\":              float64(0),\n\t\"get_exists_total\":                       float64(0),\n\t\"get_missing_time_in_millis\":             float64(0),\n\t\"get_missing_total\":                      float64(0),\n\t\"get_time_in_millis\":                     float64(0),\n\t\"get_total\":                              float64(0),\n\t\"indexing_delete_current\":                float64(0),\n\t\"indexing_delete_time_in_millis\":         float64(0),\n\t\"indexing_delete_total\":                  float64(0),\n\t\"indexing_index_current\":                 float64(0),\n\t\"indexing_index_failed\":                  float64(0),\n\t\"indexing_index_time_in_millis\":          float64(66),\n\t\"indexing_index_total\":                   float64(352),\n\t\"indexing_noop_update_total\":             float64(0),\n\t\"indexing_throttle_time_in_millis\":       float64(0),\n\t\"merges_current\":                         float64(0),\n\t\"merges_current_docs\":                    float64(0),\n\t\"merges_current_size_in_bytes\":           float64(0),\n\t\"merges_total\":                           float64(0),\n\t\"merges_total_auto_throttle_in_bytes\":    float64(20971520),\n\t\"merges_total_docs\":                      float64(0),\n\t\"merges_total_size_in_bytes\":             float64(0),\n\t\"merges_total_stopped_time_in_millis\":    float64(0),\n\t\"merges_total_throttled_time_in_millis\":  float64(0),\n\t\"merges_total_time_in_millis\":            float64(0),\n\t\"query_cache_cache_count\":                float64(0),\n\t\"query_cache_cache_size\":                 float64(0),\n\t\"query_cache_evictions\":                  float64(0),\n\t\"query_cache_hit_count\":                  float64(0),\n\t\"query_cache_memory_size_in_bytes\":       float64(0),\n\t\"query_cache_miss_count\":                 float64(0),\n\t\"query_cache_total_count\":                float64(0),\n\t\"recovery_current_as_source\":             float64(0),\n\t\"recovery_current_as_target\":             float64(0),\n\t\"recovery_throttle_time_in_millis\":       float64(0),\n\t\"refresh_external_total\":                 float64(4),\n\t\"refresh_external_total_time_in_millis\":  float64(106),\n\t\"refresh_listeners\":                      float64(0),\n\t\"refresh_total\":                          float64(6),\n\t\"refresh_total_time_in_millis\":           float64(104),\n\t\"request_cache_evictions\":                float64(0),\n\t\"request_cache_hit_count\":                float64(0),\n\t\"request_cache_memory_size_in_bytes\":     float64(0),\n\t\"request_cache_miss_count\":               float64(0),\n\t\"retention_leases_primary_term\":          float64(1),\n\t\"retention_leases_version\":               float64(0),\n\t\"routing_state\":                          int(3),\n\t\"search_fetch_current\":                   float64(0),\n\t\"search_fetch_time_in_millis\":            float64(0),\n\t\"search_fetch_total\":                     float64(0),\n\t\"search_open_contexts\":                   float64(0),\n\t\"search_query_current\":                   float64(0),\n\t\"search_query_time_in_millis\":            float64(0),\n\t\"search_query_total\":                     float64(0),\n\t\"search_scroll_current\":                  float64(0),\n\t\"search_scroll_time_in_millis\":           float64(0),\n\t\"search_scroll_total\":                    float64(0),\n\t\"search_suggest_current\":                 float64(0),\n\t\"search_suggest_time_in_millis\":          float64(0),\n\t\"search_suggest_total\":                   float64(0),\n\t\"segments_count\":                         float64(1),\n\t\"segments_doc_values_memory_in_bytes\":    float64(68),\n\t\"segments_fixed_bit_set_memory_in_bytes\": float64(0),\n\t\"segments_index_writer_memory_in_bytes\":  float64(0),\n\t\"segments_max_unsafe_auto_id_timestamp\":  float64(-1),\n\t\"segments_memory_in_bytes\":               float64(4280),\n\t\"segments_norms_memory_in_bytes\":         float64(384),\n\t\"segments_points_memory_in_bytes\":        float64(3),\n\t\"segments_stored_fields_memory_in_bytes\": float64(296),\n\t\"segments_term_vectors_memory_in_bytes\":  float64(0),\n\t\"segments_terms_memory_in_bytes\":         float64(3529),\n\t\"segments_version_map_memory_in_bytes\":   float64(0),\n\t\"seq_no_global_checkpoint\":               float64(351),\n\t\"seq_no_local_checkpoint\":                float64(351),\n\t\"seq_no_max_seq_no\":                      float64(351),\n\t\"store_size_in_bytes\":                    float64(94584),\n\t\"translog_earliest_last_modified_age\":    float64(936144),\n\t\"translog_operations\":                    float64(352),\n\t\"translog_size_in_bytes\":                 float64(79980),\n\t\"translog_uncommitted_operations\":        float64(0),\n\t\"translog_uncommitted_size_in_bytes\":     float64(55),\n\t\"warmer_current\":                         float64(0),\n\t\"warmer_total\":                           float64(3),\n\t\"warmer_total_time_in_millis\":            float64(0),\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/README.md",
    "content": "# Elasticsearch Query Input Plugin\n\nThis plugin allows to query an [Elasticsearch][elastic] instance to obtain\nmetrics from data stored in the cluster. The plugins supports counting the\nnumber of hits for a search query, calculating statistics for numeric fields,\nfiltered by a query, aggregated per tag and to count the number of terms for a\nparticular field.\n\n> [!IMPORTANT]\n> This plugins supports Elasticsearch 5.x and 6.x but is known to break on 7.x\n> or higher.\n\n⭐ Telegraf v1.20.0\n🏷️ datastore\n💻 all\n\n[elastic]: https://www.elastic.co/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Derive metrics from aggregating Elasticsearch query results\n[[inputs.elasticsearch_query]]\n  ## The full HTTP endpoint URL for your Elasticsearch instance\n  ## Multiple urls can be specified as part of the same cluster,\n  ## this means that only ONE of the urls will be written to each interval.\n  urls = [ \"http://node1.es.example.com:9200\" ] # required.\n\n  ## Elasticsearch client timeout, defaults to \"5s\".\n  # timeout = \"5s\"\n\n  ## Set to true to ask Elasticsearch a list of all cluster nodes,\n  ## thus it is not necessary to list all nodes in the urls config option\n  # enable_sniffer = false\n\n  ## Set the interval to check if the Elasticsearch nodes are available\n  ## This option is only used if enable_sniffer is also set (0s to disable it)\n  # health_check_interval = \"10s\"\n\n  ## HTTP basic authentication details (eg. when using x-pack)\n  # username = \"telegraf\"\n  # password = \"mypassword\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n \n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  [[inputs.elasticsearch_query.aggregation]]\n    ## measurement name for the results of the aggregation query\n    measurement_name = \"measurement\"\n\n    ## Elasticsearch indexes to query (accept wildcards).\n    index = \"index-*\"\n\n    ## The date/time field in the Elasticsearch index (mandatory).\n    date_field = \"@timestamp\"\n\n    ## If the field used for the date/time field in Elasticsearch is also using\n    ## a custom date/time format it may be required to provide the format to\n    ## correctly parse the field.\n    ##\n    ## If using one of the built in elasticsearch formats this is not required.\n    # date_field_custom_format = \"\"\n\n    ## Time window to query (eg. \"1m\" to query documents from last minute).\n    ## Normally should be set to same as collection interval\n    query_period = \"1m\"\n\n    ## Lucene query to filter results\n    # filter_query = \"*\"\n\n    ## Fields to aggregate values (must be numeric fields)\n    # metric_fields = [\"metric\"]\n\n    ## Aggregation function to use on the metric fields\n    ## Must be set if 'metric_fields' is set\n    ## Valid values are: avg, sum, min, max, sum\n    # metric_function = \"avg\"\n\n    ## Fields to be used as tags\n    ## Must be text, non-analyzed fields. Metric aggregations are performed\n    ## per tag\n    # tags = [\"field.keyword\", \"field2.keyword\"]\n\n    ## Set to true to not ignore documents when the tag(s) above are missing\n    # include_missing_tag = false\n\n    ## String value of the tag when the tag does not exist\n    ## Used when include_missing_tag is true\n    # missing_tag_value = \"null\"\n```\n\n## Examples\n\nPlease note that the `[[inputs.elasticsearch_query]]` is still required for all\nof the examples below.\n\n### Search the average response time, per URI and per response status code\n\n```toml\n[[inputs.elasticsearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"my-index-*\"\n  filter_query = \"*\"\n  metric_fields = [\"response_time\"]\n  metric_function = \"avg\"\n  tags = [\"URI.keyword\", \"response.keyword\"]\n  include_missing_tag = true\n  missing_tag_value = \"null\"\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n### Search the maximum response time per method and per URI\n\n```toml\n[[inputs.elasticsearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"my-index-*\"\n  filter_query = \"*\"\n  metric_fields = [\"response_time\"]\n  metric_function = \"max\"\n  tags = [\"method.keyword\",\"URI.keyword\"]\n  include_missing_tag = false\n  missing_tag_value = \"null\"\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n### Search number of documents matching a filter query in all indices\n\n```toml\n[[inputs.elasticsearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"*\"\n  filter_query = \"product_1 AND HEAD\"\n  query_period = \"1m\"\n  date_field = \"@timestamp\"\n```\n\n### Search number of documents matching a filter query, returning per response status code\n\n```toml\n[[inputs.elasticsearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"*\"\n  filter_query = \"downloads\"\n  tags = [\"response.keyword\"]\n  include_missing_tag = false\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n### Required parameters\n\n- `measurement_name`: The target measurement to be stored the results of the\n  aggregation query.\n- `index`: The index name to query on Elasticsearch\n- `query_period`: The time window to query (eg. \"1m\" to query documents from\n  last minute). Normally should be set to same as collection\n- `date_field`: The date/time field in the Elasticsearch index\n\n### Optional parameters\n\n- `date_field_custom_format`: Not needed if using one of the built in date/time\n  formats of Elasticsearch, but may be required if using a custom date/time\n  format. The format syntax uses the [Joda date format][joda].\n- `filter_query`: Lucene query to filter the results (default: \"\\*\")\n- `metric_fields`: The list of fields to perform metric aggregation (these must\n  be indexed as numeric fields)\n- `metric_function`: The single-value metric aggregation function to be performed\n  on the `metric_fields` defined. Currently supported aggregations are \"avg\",\n  \"min\", \"max\", \"sum\". (see the [aggregation docs][agg]\n- `tags`: The list of fields to be used as tags (these must be indexed as\n  non-analyzed fields). A \"terms aggregation\" will be done per tag defined\n- `include_missing_tag`: Set to true to not ignore documents where the tag(s)\n  specified above does not exist. (If false, documents without the specified tag\n  field will be ignored in `doc_count` and in the metric aggregation)\n- `missing_tag_value`: The value of the tag that will be set for documents in\n  which the tag field does not exist. Only used when `include_missing_tag` is\n  set to `true`.\n\n[joda]: https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-aggregations-bucket-daterange-aggregation.html#date-format-pattern\n[agg]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics.html\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/aggregation_parser.go",
    "content": "package elasticsearch_query\n\nimport (\n\t\"fmt\"\n\n\telastic5 \"gopkg.in/olivere/elastic.v5\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype resultMetric struct {\n\tname   string\n\tfields map[string]interface{}\n\ttags   map[string]string\n}\n\nfunc parseSimpleResult(acc telegraf.Accumulator, measurement string, searchResult *elastic5.SearchResult) {\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\tfields[\"doc_count\"] = searchResult.Hits.TotalHits\n\n\tacc.AddFields(measurement, fields, tags)\n}\n\nfunc parseAggregationResult(acc telegraf.Accumulator, aggregationQueryList []aggregationQueryData, searchResult *elastic5.SearchResult) error {\n\tmeasurements := make(map[string]map[string]string, len(aggregationQueryList))\n\n\t// organize the aggregation query data by measurement\n\tfor _, aggregationQuery := range aggregationQueryList {\n\t\tif measurements[aggregationQuery.measurement] == nil {\n\t\t\tmeasurements[aggregationQuery.measurement] = map[string]string{\n\t\t\t\taggregationQuery.name: aggregationQuery.function,\n\t\t\t}\n\t\t} else {\n\t\t\tt := measurements[aggregationQuery.measurement]\n\t\t\tt[aggregationQuery.name] = aggregationQuery.function\n\t\t\tmeasurements[aggregationQuery.measurement] = t\n\t\t}\n\t}\n\n\t// recurse over query aggregation results per measurement\n\tfor measurement, aggNameFunction := range measurements {\n\t\tvar m resultMetric\n\n\t\tm.fields = make(map[string]interface{})\n\t\tm.tags = make(map[string]string)\n\t\tm.name = measurement\n\n\t\t_, err := recurseResponse(acc, aggNameFunction, searchResult.Aggregations, m)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc recurseResponse(acc telegraf.Accumulator, aggNameFunction map[string]string, bucketResponse elastic5.Aggregations, m resultMetric) (resultMetric, error) {\n\tvar err error\n\n\taggNames := getAggNames(bucketResponse)\n\tif len(aggNames) == 0 {\n\t\t// we've reached a single bucket or response without aggregation, nothing here\n\t\treturn m, nil\n\t}\n\n\t// metrics aggregations response can contain multiple field values, so we iterate over them\n\tfor _, aggName := range aggNames {\n\t\taggFunction, found := aggNameFunction[aggName]\n\t\tif !found {\n\t\t\treturn m, fmt.Errorf(\"child aggregation function %q not found %v\", aggName, aggNameFunction)\n\t\t}\n\n\t\tresp := getResponseAggregation(aggFunction, aggName, bucketResponse)\n\t\tif resp == nil {\n\t\t\treturn m, fmt.Errorf(\"child aggregation %q not found\", aggName)\n\t\t}\n\n\t\tswitch resp := resp.(type) {\n\t\tcase *elastic5.AggregationBucketKeyItems:\n\t\t\t// we've found a terms aggregation, iterate over the buckets and try to retrieve the inner aggregation values\n\t\t\tfor _, bucket := range resp.Buckets {\n\t\t\t\tvar s string\n\t\t\t\tvar ok bool\n\t\t\t\tm.fields[\"doc_count\"] = bucket.DocCount\n\t\t\t\tif s, ok = bucket.Key.(string); !ok {\n\t\t\t\t\treturn m, fmt.Errorf(\"bucket key is not a string (%s, %s)\", aggName, aggFunction)\n\t\t\t\t}\n\t\t\t\tm.tags[aggName] = s\n\n\t\t\t\t// we need to recurse down through the buckets, as it may contain another terms aggregation\n\t\t\t\tm, err = recurseResponse(acc, aggNameFunction, bucket.Aggregations, m)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn m, err\n\t\t\t\t}\n\n\t\t\t\t// if there are fields present after finishing the bucket, it is a complete metric\n\t\t\t\t// store it and clean the fields to start a new metric\n\t\t\t\tif len(m.fields) > 0 {\n\t\t\t\t\tacc.AddFields(m.name, m.fields, m.tags)\n\t\t\t\t\tm.fields = make(map[string]interface{})\n\t\t\t\t}\n\n\t\t\t\t// after finishing the bucket, remove its tag from the tags map\n\t\t\t\tdelete(m.tags, aggName)\n\t\t\t}\n\n\t\tcase *elastic5.AggregationValueMetric:\n\t\t\tif resp.Value != nil {\n\t\t\t\tm.fields[aggName] = *resp.Value\n\t\t\t} else {\n\t\t\t\tm.fields[aggName] = float64(0)\n\t\t\t}\n\n\t\tdefault:\n\t\t\treturn m, fmt.Errorf(\"aggregation type %T not supported\", resp)\n\t\t}\n\t}\n\n\t// if there are fields here it comes from a metrics aggregation without a parent terms aggregation\n\tif len(m.fields) > 0 {\n\t\tacc.AddFields(m.name, m.fields, m.tags)\n\t\tm.fields = make(map[string]interface{})\n\t}\n\treturn m, nil\n}\n\nfunc getResponseAggregation(function, aggName string, aggs elastic5.Aggregations) (agg interface{}) {\n\tswitch function {\n\tcase \"avg\":\n\t\tagg, _ = aggs.Avg(aggName)\n\tcase \"sum\":\n\t\tagg, _ = aggs.Sum(aggName)\n\tcase \"min\":\n\t\tagg, _ = aggs.Min(aggName)\n\tcase \"max\":\n\t\tagg, _ = aggs.Max(aggName)\n\tcase \"terms\":\n\t\tagg, _ = aggs.Terms(aggName)\n\t}\n\n\treturn agg\n}\n\n// getAggNames returns the aggregation names from a response aggregation\nfunc getAggNames(agg elastic5.Aggregations) (aggs []string) {\n\tfor k := range agg {\n\t\tif (k != \"key\") && (k != \"doc_count\") {\n\t\t\taggs = append(aggs, k)\n\t\t}\n\t}\n\n\treturn aggs\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/aggregation_query.go",
    "content": "package elasticsearch_query\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\telastic5 \"gopkg.in/olivere/elastic.v5\"\n)\n\ntype aggKey struct {\n\tmeasurement string\n\tname        string\n\tfunction    string\n\tfield       string\n}\n\ntype aggregationQueryData struct {\n\taggKey\n\tisParent    bool\n\taggregation elastic5.Aggregation\n}\n\nfunc (e *ElasticsearchQuery) runAggregationQuery(ctx context.Context, aggregation esAggregation) (*elastic5.SearchResult, error) {\n\tnow := time.Now().UTC()\n\tfrom := now.Add(time.Duration(-aggregation.QueryPeriod))\n\tfilterQuery := aggregation.FilterQuery\n\tif filterQuery == \"\" {\n\t\tfilterQuery = \"*\"\n\t}\n\n\tquery := elastic5.NewBoolQuery()\n\tquery = query.Filter(elastic5.NewQueryStringQuery(filterQuery))\n\tquery = query.Filter(elastic5.NewRangeQuery(aggregation.DateField).From(from).To(now).Format(aggregation.DateFieldFormat))\n\n\tsrc, err := query.Source()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get query source: %w\", err)\n\t}\n\tdata, err := json.Marshal(src)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n\t}\n\te.Log.Debugf(\"{\\\"query\\\": %s}\", string(data))\n\n\tsearch := e.esClient.Search().Index(aggregation.Index).Query(query).Size(0)\n\n\t// add only parent elastic.Aggregations to the search request, all the rest are subaggregations of these\n\tfor _, v := range aggregation.aggregationQueryList {\n\t\tif v.isParent && v.aggregation != nil {\n\t\t\tsearch.Aggregation(v.aggKey.name, v.aggregation)\n\t\t}\n\t}\n\n\tsearchResult, err := search.Do(ctx)\n\tif err != nil && searchResult != nil {\n\t\treturn searchResult, fmt.Errorf(\"%s - %s\", searchResult.Error.Type, searchResult.Error.Reason)\n\t}\n\n\treturn searchResult, err\n}\n\n// getMetricFields function returns a map of fields and field types on Elasticsearch that matches field.MetricFields\nfunc (e *ElasticsearchQuery) getMetricFields(ctx context.Context, aggregation esAggregation) (map[string]string, error) {\n\tmapMetricFields := make(map[string]string)\n\n\tfor _, metricField := range aggregation.MetricFields {\n\t\tresp, err := e.esClient.GetFieldMapping().Index(aggregation.Index).Field(metricField).Do(ctx)\n\t\tif err != nil {\n\t\t\treturn mapMetricFields, fmt.Errorf(\"error retrieving field mappings for %s: %w\", aggregation.Index, err)\n\t\t}\n\n\t\tfor _, index := range resp {\n\t\t\tvar ok bool\n\t\t\tvar mappings interface{}\n\t\t\tif mappings, ok = index.(map[string]interface{})[\"mappings\"]; !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", index)\n\t\t\t}\n\n\t\t\tvar types map[string]interface{}\n\t\t\tif types, ok = mappings.(map[string]interface{}); !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", mappings)\n\t\t\t}\n\n\t\t\tvar fields map[string]interface{}\n\t\t\tfor _, _type := range types {\n\t\t\t\tif fields, ok = _type.(map[string]interface{}); !ok {\n\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", _type)\n\t\t\t\t}\n\n\t\t\t\tvar field map[string]interface{}\n\t\t\t\tfor _, _field := range fields {\n\t\t\t\t\tif field, ok = _field.(map[string]interface{}); !ok {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", _field)\n\t\t\t\t\t}\n\n\t\t\t\t\tfullname := field[\"full_name\"]\n\t\t\t\t\tmapping := field[\"mapping\"]\n\n\t\t\t\t\tvar fname string\n\t\t\t\t\tif fname, ok = fullname.(string); !ok {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected string, got %T)\", fullname)\n\t\t\t\t\t}\n\n\t\t\t\t\tvar fieldTypes map[string]interface{}\n\t\t\t\t\tif fieldTypes, ok = mapping.(map[string]interface{}); !ok {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", mapping)\n\t\t\t\t\t}\n\n\t\t\t\t\tvar fieldType interface{}\n\t\t\t\t\tfor _, _fieldType := range fieldTypes {\n\t\t\t\t\t\tif fieldType, ok = _fieldType.(map[string]interface{})[\"type\"]; !ok {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected map[string]interface{}, got %T)\", _fieldType)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar ftype string\n\t\t\t\t\t\tif ftype, ok = fieldType.(string); !ok {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"assertion error, wrong type (expected string, got %T)\", fieldType)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmapMetricFields[fname] = ftype\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn mapMetricFields, nil\n}\n\nfunc (aggregation *esAggregation) buildAggregationQuery() error {\n\t// create one aggregation per metric field found & function defined for numeric fields\n\tfor k, v := range aggregation.mapMetricFields {\n\t\tswitch v {\n\t\tcase \"long\":\n\t\tcase \"float\":\n\t\tcase \"integer\":\n\t\tcase \"short\":\n\t\tcase \"double\":\n\t\tcase \"scaled_float\":\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tagg, err := getFunctionAggregation(aggregation.MetricFunction, k)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\taggregationQuery := aggregationQueryData{\n\t\t\taggKey: aggKey{\n\t\t\t\tmeasurement: aggregation.MeasurementName,\n\t\t\t\tfunction:    aggregation.MetricFunction,\n\t\t\t\tfield:       k,\n\t\t\t\tname:        strings.ReplaceAll(k, \".\", \"_\") + \"_\" + aggregation.MetricFunction,\n\t\t\t},\n\t\t\tisParent:    true,\n\t\t\taggregation: agg,\n\t\t}\n\n\t\taggregation.aggregationQueryList = append(aggregation.aggregationQueryList, aggregationQuery)\n\t}\n\n\t// create a terms aggregation per tag\n\tfor _, term := range aggregation.Tags {\n\t\tagg := elastic5.NewTermsAggregation()\n\t\tif aggregation.IncludeMissingTag && aggregation.MissingTagValue != \"\" {\n\t\t\tagg.Missing(aggregation.MissingTagValue)\n\t\t}\n\n\t\tagg.Field(term).Size(1000)\n\n\t\t// add each previous parent aggregations as subaggregations of this terms aggregation\n\t\tfor key, aggMap := range aggregation.aggregationQueryList {\n\t\t\tif aggMap.isParent {\n\t\t\t\tagg.Field(term).SubAggregation(aggMap.name, aggMap.aggregation).Size(1000)\n\t\t\t\t// update subaggregation map with parent information\n\t\t\t\taggregation.aggregationQueryList[key].isParent = false\n\t\t\t}\n\t\t}\n\n\t\taggregationQuery := aggregationQueryData{\n\t\t\taggKey: aggKey{\n\t\t\t\tmeasurement: aggregation.MeasurementName,\n\t\t\t\tfunction:    \"terms\",\n\t\t\t\tfield:       term,\n\t\t\t\tname:        strings.ReplaceAll(term, \".\", \"_\"),\n\t\t\t},\n\t\t\tisParent:    true,\n\t\t\taggregation: agg,\n\t\t}\n\n\t\taggregation.aggregationQueryList = append(aggregation.aggregationQueryList, aggregationQuery)\n\t}\n\n\treturn nil\n}\n\nfunc getFunctionAggregation(function, aggfield string) (elastic5.Aggregation, error) {\n\tvar agg elastic5.Aggregation\n\n\tswitch function {\n\tcase \"avg\":\n\t\tagg = elastic5.NewAvgAggregation().Field(aggfield)\n\tcase \"sum\":\n\t\tagg = elastic5.NewSumAggregation().Field(aggfield)\n\tcase \"min\":\n\t\tagg = elastic5.NewMinAggregation().Field(aggfield)\n\tcase \"max\":\n\t\tagg = elastic5.NewMaxAggregation().Field(aggfield)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"aggregation function %q not supported\", function)\n\t}\n\n\treturn agg, nil\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/elasticsearch_query.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage elasticsearch_query\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\telastic5 \"gopkg.in/olivere/elastic.v5\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype ElasticsearchQuery struct {\n\tURLs                []string        `toml:\"urls\"`\n\tUsername            string          `toml:\"username\"`\n\tPassword            string          `toml:\"password\"`\n\tEnableSniffer       bool            `toml:\"enable_sniffer\"`\n\tHealthCheckInterval config.Duration `toml:\"health_check_interval\"`\n\tAggregations        []esAggregation `toml:\"aggregation\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\thttpclient *http.Client\n\tcommon_http.HTTPClientConfig\n\n\tesClient *elastic5.Client\n}\n\ntype esAggregation struct {\n\tIndex                string          `toml:\"index\"`\n\tMeasurementName      string          `toml:\"measurement_name\"`\n\tDateField            string          `toml:\"date_field\"`\n\tDateFieldFormat      string          `toml:\"date_field_custom_format\"`\n\tQueryPeriod          config.Duration `toml:\"query_period\"`\n\tFilterQuery          string          `toml:\"filter_query\"`\n\tMetricFields         []string        `toml:\"metric_fields\"`\n\tMetricFunction       string          `toml:\"metric_function\"`\n\tTags                 []string        `toml:\"tags\"`\n\tIncludeMissingTag    bool            `toml:\"include_missing_tag\"`\n\tMissingTagValue      string          `toml:\"missing_tag_value\"`\n\tmapMetricFields      map[string]string\n\taggregationQueryList []aggregationQueryData\n}\n\nfunc (*ElasticsearchQuery) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (e *ElasticsearchQuery) Init() error {\n\tif e.URLs == nil {\n\t\treturn errors.New(\"elasticsearch urls is not defined\")\n\t}\n\n\terr := e.connectToES()\n\tif err != nil {\n\t\te.Log.Errorf(\"error connecting to elasticsearch: %s\", err)\n\t\treturn nil\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(e.Timeout))\n\tdefer cancel()\n\n\tfor i, agg := range e.Aggregations {\n\t\tif agg.MeasurementName == \"\" {\n\t\t\treturn errors.New(\"field 'measurement_name' is not set\")\n\t\t}\n\t\tif agg.DateField == \"\" {\n\t\t\treturn errors.New(\"field 'date_field' is not set\")\n\t\t}\n\t\terr = e.initAggregation(ctx, agg, i)\n\t\tif err != nil {\n\t\t\te.Log.Error(err.Error())\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (*ElasticsearchQuery) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\n// Gather writes the results of the queries from Elasticsearch to the Accumulator.\nfunc (e *ElasticsearchQuery) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\terr := e.connectToES()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i, agg := range e.Aggregations {\n\t\twg.Add(1)\n\t\tgo func(agg esAggregation, i int) {\n\t\t\tdefer wg.Done()\n\t\t\terr := e.esAggregationQuery(acc, agg, i)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"elasticsearch query aggregation %s: %w\", agg.MeasurementName, err))\n\t\t\t}\n\t\t}(agg, i)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (e *ElasticsearchQuery) Stop() {\n\tif e.httpclient != nil {\n\t\te.httpclient.CloseIdleConnections()\n\t}\n}\n\nfunc (e *ElasticsearchQuery) initAggregation(ctx context.Context, agg esAggregation, i int) (err error) {\n\t// retrieve field mapping and build queries only once\n\tagg.mapMetricFields, err = e.getMetricFields(ctx, agg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"not possible to retrieve fields: %w\", err)\n\t}\n\n\tfor _, metricField := range agg.MetricFields {\n\t\tif _, ok := agg.mapMetricFields[metricField]; !ok {\n\t\t\treturn fmt.Errorf(\"metric field %q not found on index %q\", metricField, agg.Index)\n\t\t}\n\t}\n\n\terr = agg.buildAggregationQuery()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\te.Aggregations[i] = agg\n\treturn nil\n}\n\nfunc (e *ElasticsearchQuery) connectToES() error {\n\tvar clientOptions []elastic5.ClientOptionFunc\n\n\tif e.esClient != nil {\n\t\tif e.esClient.IsRunning() {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif e.httpclient == nil {\n\t\thttpclient, err := e.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\te.httpclient = httpclient\n\t}\n\n\tclientOptions = append(clientOptions,\n\t\telastic5.SetHttpClient(e.httpclient),\n\t\telastic5.SetSniff(e.EnableSniffer),\n\t\telastic5.SetURL(e.URLs...),\n\t\telastic5.SetHealthcheckInterval(time.Duration(e.HealthCheckInterval)),\n\t)\n\n\tif e.Username != \"\" {\n\t\tclientOptions = append(clientOptions, elastic5.SetBasicAuth(e.Username, e.Password))\n\t}\n\n\tif time.Duration(e.HealthCheckInterval) == 0 {\n\t\tclientOptions = append(clientOptions, elastic5.SetHealthcheck(false))\n\t}\n\n\tclient, err := elastic5.NewClient(clientOptions...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// check for ES version on first node\n\tesVersion, err := client.ElasticsearchVersion(e.URLs[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"elasticsearch version check failed: %w\", err)\n\t}\n\n\tesVersionSplit := strings.Split(esVersion, \".\")\n\n\t// quit if ES version is not supported\n\tif len(esVersionSplit) == 0 {\n\t\treturn errors.New(\"elasticsearch version check failed\")\n\t}\n\n\ti, err := strconv.Atoi(esVersionSplit[0])\n\tif err != nil || i < 5 || i > 6 {\n\t\treturn fmt.Errorf(\"elasticsearch version %s not supported (currently supported versions are 5.x and 6.x)\", esVersion)\n\t}\n\n\te.esClient = client\n\treturn nil\n}\n\nfunc (e *ElasticsearchQuery) createHTTPClient() (*http.Client, error) {\n\tctx := context.Background()\n\treturn e.HTTPClientConfig.CreateClient(ctx, e.Log)\n}\n\nfunc (e *ElasticsearchQuery) esAggregationQuery(acc telegraf.Accumulator, aggregation esAggregation, i int) error {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(e.Timeout))\n\tdefer cancel()\n\n\t// try to init the aggregation query if it is not done already\n\tif aggregation.aggregationQueryList == nil {\n\t\terr := e.initAggregation(ctx, aggregation, i)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\taggregation = e.Aggregations[i]\n\t}\n\n\tsearchResult, err := e.runAggregationQuery(ctx, aggregation)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif searchResult.Aggregations == nil {\n\t\tparseSimpleResult(acc, aggregation.MeasurementName, searchResult)\n\t\treturn nil\n\t}\n\n\treturn parseAggregationResult(acc, aggregation.aggregationQueryList, searchResult)\n}\n\nfunc init() {\n\tinputs.Add(\"elasticsearch_query\", func() telegraf.Input {\n\t\treturn &ElasticsearchQuery{\n\t\t\tHealthCheckInterval: config.Duration(time.Second * 10),\n\t\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\t\tResponseHeaderTimeout: config.Duration(5 * time.Second),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/elasticsearch_query_test.go",
    "content": "package elasticsearch_query\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\telastic5 \"gopkg.in/olivere/elastic.v5\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tservicePort = \"9200\"\n\ttestindex   = \"test-elasticsearch\"\n)\n\ntype esAggregationQueryTest struct {\n\tqueryName                 string\n\ttestAggregationQueryInput esAggregation\n\ttestAggregationQueryData  []aggregationQueryData\n\texpectedMetrics           []telegraf.Metric\n\twantBuildQueryErr         bool\n\twantGetMetricFieldsErr    bool\n\twantQueryResErr           bool\n}\n\nvar queryPeriod = config.Duration(time.Second * 600)\n\nvar testEsAggregationData = []esAggregationQueryTest{\n\t{\n\t\t\"query 1\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement1\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tFilterQuery:     \"product_1\",\n\t\t\tMetricFunction:  \"avg\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement1\", name: \"size_avg\", function: \"avg\", field: \"size\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement1\", name: \"URI_keyword\", function: \"terms\", field: \"URI.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement1\",\n\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\tmap[string]interface{}{\"size_avg\": float64(202.30038022813687), \"doc_count\": int64(263)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 2\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement2\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tFilterQuery:     \"downloads\",\n\t\t\tMetricFunction:  \"max\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement2\", name: \"size_max\", function: \"max\", field: \"size\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement2\", name: \"URI_keyword\", function: \"terms\", field: \"URI.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement2\",\n\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\tmap[string]interface{}{\"size_max\": float64(3301), \"doc_count\": int64(263)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement2\",\n\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\tmap[string]interface{}{\"size_max\": float64(3318), \"doc_count\": int64(237)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 3\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement3\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tFilterQuery:     \"downloads\",\n\t\t\tMetricFunction:  \"sum\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tTags:            []string{\"response.keyword\"},\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement3\", name: \"size_sum\", function: \"sum\", field: \"size\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement3\", name: \"response_keyword\", function: \"terms\", field: \"response.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement3\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\"},\n\t\t\t\tmap[string]interface{}{\"size_sum\": float64(22790), \"doc_count\": int64(22)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement3\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"304\"},\n\t\t\t\tmap[string]interface{}{\"size_sum\": float64(0), \"doc_count\": int64(219)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement3\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"404\"},\n\t\t\t\tmap[string]interface{}{\"size_sum\": float64(86932), \"doc_count\": int64(259)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 4\",\n\t\tesAggregation{\n\t\t\tIndex:             testindex,\n\t\t\tMeasurementName:   \"measurement4\",\n\t\t\tMetricFields:      []string{\"size\", \"response_time\"},\n\t\t\tFilterQuery:       \"downloads\",\n\t\t\tMetricFunction:    \"min\",\n\t\t\tDateField:         \"@timestamp\",\n\t\t\tQueryPeriod:       queryPeriod,\n\t\t\tIncludeMissingTag: true,\n\t\t\tMissingTagValue:   \"missing\",\n\t\t\tTags:              []string{\"response.keyword\", \"URI.keyword\", \"method.keyword\"},\n\t\t\tmapMetricFields:   map[string]string{\"size\": \"long\", \"response_time\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement4\", name: \"size_min\", function: \"min\", field: \"size\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement4\", name: \"response_time_min\", function: \"min\", field: \"response_time\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement4\", name: \"response_keyword\", function: \"terms\", field: \"response.keyword\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement4\", name: \"URI_keyword\", function: \"terms\", field: \"URI.keyword\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement4\", name: \"method_keyword\", function: \"terms\", field: \"method.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"404\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(318), \"response_time_min\": float64(126), \"doc_count\": int64(146)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"304\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(0), \"response_time_min\": float64(71), \"doc_count\": int64(113)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(490), \"response_time_min\": float64(1514), \"doc_count\": int64(3)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"404\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(318), \"response_time_min\": float64(237), \"doc_count\": int64(113)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"304\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(0), \"response_time_min\": float64(134), \"doc_count\": int64(106)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(490), \"response_time_min\": float64(2), \"doc_count\": int64(13)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"HEAD\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(0), \"response_time_min\": float64(8479), \"doc_count\": int64(1)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement4\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"HEAD\"},\n\t\t\t\tmap[string]interface{}{\"size_min\": float64(0), \"response_time_min\": float64(1059), \"doc_count\": int64(5)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 5\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement5\",\n\t\t\tFilterQuery:     \"product_2\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement5\", name: \"URI_keyword\", function: \"terms\", field: \"URI.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement5\",\n\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\tmap[string]interface{}{\"doc_count\": int64(237)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 6\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement6\",\n\t\t\tFilterQuery:     \"response: 200\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tTags:            []string{\"URI.keyword\", \"response.keyword\"},\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement6\", name: \"URI_keyword\", function: \"terms\", field: \"URI.keyword\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement6\", name: \"response_keyword\", function: \"terms\", field: \"response.keyword\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement6\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\tmap[string]interface{}{\"doc_count\": int64(4)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement6\",\n\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\tmap[string]interface{}{\"doc_count\": int64(18)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 7 - simple query\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement7\",\n\t\t\tFilterQuery:     \"response: 200\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\tnil,\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement7\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\"doc_count\": int64(22)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 8\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement8\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tFilterQuery:     \"downloads\",\n\t\t\tMetricFunction:  \"max\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement8\", name: \"size_max\", function: \"max\", field: \"size\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement8\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\"size_max\": float64(3318)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 9 - invalid function\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement9\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tFilterQuery:     \"downloads\",\n\t\t\tMetricFunction:  \"average\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\ttrue,\n\t\tfalse,\n\t\ttrue,\n\t},\n\t{\n\t\t\"query 10 - non-existing metric field\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement10\",\n\t\t\tMetricFields:    []string{\"none\"},\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\tfalse,\n\t\tfalse,\n\t\ttrue,\n\t},\n\t{\n\t\t\"query 11 - non-existing index field\",\n\t\tesAggregation{\n\t\t\tIndex:           \"notanindex\",\n\t\t\tMeasurementName: \"measurement11\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\tfalse,\n\t\tfalse,\n\t\ttrue,\n\t},\n\t{\n\t\t\"query 12 - non-existing timestamp field\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement12\",\n\t\t\tMetricFields:    []string{\"size\"},\n\t\t\tMetricFunction:  \"avg\",\n\t\t\tDateField:       \"@notatimestamp\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement12\", name: \"size_avg\", function: \"avg\", field: \"size\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\t[]telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"measurement12\",\n\t\t\t\tmap[string]string{},\n\t\t\t\tmap[string]interface{}{\"size_avg\": float64(0)},\n\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t),\n\t\t},\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 13 - non-existing tag field\",\n\t\tesAggregation{\n\t\t\tIndex:             testindex,\n\t\t\tMeasurementName:   \"measurement13\",\n\t\t\tMetricFields:      []string{\"size\"},\n\t\t\tMetricFunction:    \"avg\",\n\t\t\tDateField:         \"@timestamp\",\n\t\t\tQueryPeriod:       queryPeriod,\n\t\t\tIncludeMissingTag: false,\n\t\t\tTags:              []string{\"nothere\"},\n\t\t\tmapMetricFields:   map[string]string{\"size\": \"long\"},\n\t\t},\n\t\t[]aggregationQueryData{\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement13\", name: \"size_avg\", function: \"avg\", field: \"size\"},\n\t\t\t\tisParent: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\taggKey:   aggKey{measurement: \"measurement13\", name: \"nothere\", function: \"terms\", field: \"nothere\"},\n\t\t\t\tisParent: true,\n\t\t\t},\n\t\t},\n\t\tnil,\n\t\tfalse,\n\t\tfalse,\n\t\tfalse,\n\t},\n\t{\n\t\t\"query 14 - non-existing custom date/time format\",\n\t\tesAggregation{\n\t\t\tIndex:           testindex,\n\t\t\tMeasurementName: \"measurement14\",\n\t\t\tDateField:       \"@timestamp\",\n\t\t\tDateFieldFormat: \"yyyy\",\n\t\t\tQueryPeriod:     queryPeriod,\n\t\t\tmapMetricFields: map[string]string{},\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\tfalse,\n\t\tfalse,\n\t\ttrue,\n\t},\n}\n\nfunc setupIntegrationTest(t *testing.T) (*testutil.Container, error) {\n\ttype nginxlog struct {\n\t\tIPaddress    string    `json:\"IP\"`\n\t\tTimestamp    time.Time `json:\"@timestamp\"`\n\t\tMethod       string    `json:\"method\"`\n\t\tURI          string    `json:\"URI\"`\n\t\tHttpversion  string    `json:\"http_version\"`\n\t\tResponse     string    `json:\"response\"`\n\t\tSize         float64   `json:\"size\"`\n\t\tResponseTime float64   `json:\"response_time\"`\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"elasticsearch:6.8.23\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"discovery.type\": \"single-node\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"] mode [basic] - valid\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\n\turl := fmt.Sprintf(\n\t\t\"http://%s:%s\", container.Address, container.Ports[servicePort],\n\t)\n\te := &ElasticsearchQuery{\n\t\tURLs: []string{url},\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(30 * time.Second),\n\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\tResponseHeaderTimeout: config.Duration(30 * time.Second),\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\terr = e.connectToES()\n\tif err != nil {\n\t\treturn &container, err\n\t}\n\n\tbulkRequest := e.esClient.Bulk()\n\n\t// populate elasticsearch with nginx_logs test data file\n\tfile, err := os.Open(\"testdata/nginx_logs\")\n\tif err != nil {\n\t\treturn &container, err\n\t}\n\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\n\tfor scanner.Scan() {\n\t\tparts := strings.Split(scanner.Text(), \" \")\n\t\tsize, err := strconv.Atoi(parts[9])\n\t\trequire.NoError(t, err)\n\t\tresponseTime, err := strconv.Atoi(parts[len(parts)-1])\n\t\trequire.NoError(t, err)\n\n\t\tlogline := nginxlog{\n\t\t\tIPaddress:    parts[0],\n\t\t\tTimestamp:    time.Now().UTC(),\n\t\t\tMethod:       strings.ReplaceAll(parts[5], `\"`, \"\"),\n\t\t\tURI:          parts[6],\n\t\t\tHttpversion:  strings.ReplaceAll(parts[7], `\"`, \"\"),\n\t\t\tResponse:     parts[8],\n\t\t\tSize:         float64(size),\n\t\t\tResponseTime: float64(responseTime),\n\t\t}\n\n\t\tbulkRequest.Add(elastic5.NewBulkIndexRequest().\n\t\t\tIndex(testindex).\n\t\t\tType(\"testquery_data\").\n\t\t\tDoc(logline))\n\t}\n\tif scanner.Err() != nil {\n\t\treturn &container, err\n\t}\n\n\t_, err = bulkRequest.Do(t.Context())\n\tif err != nil {\n\t\treturn &container, err\n\t}\n\n\t// force elastic to refresh indexes to get new batch data\n\t_, err = e.esClient.Refresh().Do(t.Context())\n\tif err != nil {\n\t\treturn &container, err\n\t}\n\n\treturn &container, nil\n}\n\nfunc TestElasticsearchQueryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer, err := setupIntegrationTest(t)\n\trequire.NoError(t, err)\n\tdefer container.Terminate()\n\n\tvar acc testutil.Accumulator\n\te := &ElasticsearchQuery{\n\t\tURLs: []string{\n\t\t\tfmt.Sprintf(\"http://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(30 * time.Second),\n\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\tResponseHeaderTimeout: config.Duration(30 * time.Second),\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\terr = e.connectToES()\n\trequire.NoError(t, err)\n\n\tvar aggs []esAggregation\n\tvar aggsErr []esAggregation\n\n\tfor _, agg := range testEsAggregationData {\n\t\tif !agg.wantQueryResErr {\n\t\t\taggs = append(aggs, agg.testAggregationQueryInput)\n\t\t}\n\t}\n\te.Aggregations = aggs\n\n\trequire.NoError(t, e.Init())\n\trequire.NoError(t, e.Gather(&acc))\n\n\tif len(acc.Errors) > 0 {\n\t\tt.Errorf(\"%s\", acc.Errors)\n\t}\n\n\tvar expectedMetrics []telegraf.Metric\n\tfor _, result := range testEsAggregationData {\n\t\texpectedMetrics = append(expectedMetrics, result.expectedMetrics...)\n\t}\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, acc.GetTelegrafMetrics(), testutil.SortMetrics(), testutil.IgnoreTime())\n\n\t// aggregations that should return an error\n\tfor _, agg := range testEsAggregationData {\n\t\tif agg.wantQueryResErr {\n\t\t\taggsErr = append(aggsErr, agg.testAggregationQueryInput)\n\t\t}\n\t}\n\te.Aggregations = aggsErr\n\trequire.NoError(t, e.Init())\n\trequire.NoError(t, e.Gather(&acc))\n\n\tif len(acc.Errors) != len(aggsErr) {\n\t\tt.Errorf(\"expecting %v query result errors, got %v: %s\", len(aggsErr), len(acc.Errors), acc.Errors)\n\t}\n}\n\nfunc TestElasticsearchQueryIntegration_getMetricFields(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer, err := setupIntegrationTest(t)\n\trequire.NoError(t, err)\n\tdefer container.Terminate()\n\n\ttype args struct {\n\t\tctx         context.Context\n\t\taggregation esAggregation\n\t}\n\n\te := &ElasticsearchQuery{\n\t\tURLs: []string{\n\t\t\tfmt.Sprintf(\"http://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(30 * time.Second),\n\t\t\tTransportConfig: common_http.TransportConfig{\n\t\t\t\tResponseHeaderTimeout: config.Duration(30 * time.Second),\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\terr = e.connectToES()\n\trequire.NoError(t, err)\n\n\ttype test struct {\n\t\tname    string\n\t\te       *ElasticsearchQuery\n\t\targs    args\n\t\twant    map[string]string\n\t\twantErr bool\n\t}\n\n\ttests := make([]test, 0, len(testEsAggregationData))\n\tfor _, d := range testEsAggregationData {\n\t\ttests = append(tests, test{\n\t\t\t\"getMetricFields \" + d.queryName,\n\t\t\te,\n\t\t\targs{t.Context(), d.testAggregationQueryInput},\n\t\t\td.testAggregationQueryInput.mapMetricFields,\n\t\t\td.wantGetMetricFieldsErr,\n\t\t})\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := tt.e.getMetricFields(tt.args.ctx, tt.args.aggregation)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ElasticsearchQuery.buildAggregationQuery() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !cmp.Equal(got, tt.want) {\n\t\t\t\tt.Errorf(\"ElasticsearchQuery.getMetricFields() = error = %s\", cmp.Diff(got, tt.want))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestElasticsearchQuery_buildAggregationQuery(t *testing.T) {\n\ttype test struct {\n\t\tname        string\n\t\taggregation esAggregation\n\t\twant        []aggregationQueryData\n\t\twantErr     bool\n\t}\n\n\ttests := make([]test, 0, len(testEsAggregationData))\n\tfor _, d := range testEsAggregationData {\n\t\ttests = append(tests, test{\n\t\t\t\"build \" + d.queryName,\n\t\t\td.testAggregationQueryInput,\n\t\t\td.testAggregationQueryData,\n\t\t\td.wantBuildQueryErr,\n\t\t})\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.aggregation.buildAggregationQuery()\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ElasticsearchQuery.buildAggregationQuery() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\topts := []cmp.Option{\n\t\t\t\tcmp.AllowUnexported(aggKey{}, aggregationQueryData{}),\n\t\t\t\tcmpopts.IgnoreFields(aggregationQueryData{}, \"aggregation\"),\n\t\t\t\tcmpopts.SortSlices(func(x, y aggregationQueryData) bool { return x.aggKey.name > y.aggKey.name }),\n\t\t\t}\n\n\t\t\tif !cmp.Equal(tt.aggregation.aggregationQueryList, tt.want, opts...) {\n\t\t\t\tt.Errorf(\"ElasticsearchQuery.buildAggregationQuery(): %s error = %s \", tt.name, cmp.Diff(tt.aggregation.aggregationQueryList, tt.want, opts...))\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/sample.conf",
    "content": "# Derive metrics from aggregating Elasticsearch query results\n[[inputs.elasticsearch_query]]\n  ## The full HTTP endpoint URL for your Elasticsearch instance\n  ## Multiple urls can be specified as part of the same cluster,\n  ## this means that only ONE of the urls will be written to each interval.\n  urls = [ \"http://node1.es.example.com:9200\" ] # required.\n\n  ## Elasticsearch client timeout, defaults to \"5s\".\n  # timeout = \"5s\"\n\n  ## Set to true to ask Elasticsearch a list of all cluster nodes,\n  ## thus it is not necessary to list all nodes in the urls config option\n  # enable_sniffer = false\n\n  ## Set the interval to check if the Elasticsearch nodes are available\n  ## This option is only used if enable_sniffer is also set (0s to disable it)\n  # health_check_interval = \"10s\"\n\n  ## HTTP basic authentication details (eg. when using x-pack)\n  # username = \"telegraf\"\n  # password = \"mypassword\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n \n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  [[inputs.elasticsearch_query.aggregation]]\n    ## measurement name for the results of the aggregation query\n    measurement_name = \"measurement\"\n\n    ## Elasticsearch indexes to query (accept wildcards).\n    index = \"index-*\"\n\n    ## The date/time field in the Elasticsearch index (mandatory).\n    date_field = \"@timestamp\"\n\n    ## If the field used for the date/time field in Elasticsearch is also using\n    ## a custom date/time format it may be required to provide the format to\n    ## correctly parse the field.\n    ##\n    ## If using one of the built in elasticsearch formats this is not required.\n    # date_field_custom_format = \"\"\n\n    ## Time window to query (eg. \"1m\" to query documents from last minute).\n    ## Normally should be set to same as collection interval\n    query_period = \"1m\"\n\n    ## Lucene query to filter results\n    # filter_query = \"*\"\n\n    ## Fields to aggregate values (must be numeric fields)\n    # metric_fields = [\"metric\"]\n\n    ## Aggregation function to use on the metric fields\n    ## Must be set if 'metric_fields' is set\n    ## Valid values are: avg, sum, min, max, sum\n    # metric_function = \"avg\"\n\n    ## Fields to be used as tags\n    ## Must be text, non-analyzed fields. Metric aggregations are performed\n    ## per tag\n    # tags = [\"field.keyword\", \"field2.keyword\"]\n\n    ## Set to true to not ignore documents when the tag(s) above are missing\n    # include_missing_tag = false\n\n    ## String value of the tag when the tag does not exist\n    ## Used when include_missing_tag is true\n    # missing_tag_value = \"null\"\n"
  },
  {
    "path": "plugins/inputs/elasticsearch_query/testdata/nginx_logs",
    "content": "93.180.71.3 - - [17/May/2015:08:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 12060\n93.180.71.3 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 12355\n80.91.33.133 - - [17/May/2015:08:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26272\n217.168.17.5 - - [17/May/2015:08:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 1514\n217.168.17.5 - - [17/May/2015:08:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 2204\n93.180.71.3 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 6012\n217.168.17.5 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 11220\n217.168.17.5 - - [17/May/2015:08:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 17843\n80.91.33.133 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 22599\n93.180.71.3 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 24828\n217.168.17.5 - - [17/May/2015:08:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 3316 \"-\" \"-\" 6947\n188.138.60.101 - - [17/May/2015:08:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28288\n80.91.33.133 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23182\n46.4.66.76 - - [17/May/2015:08:05:45 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16302\n93.180.71.3 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16102\n91.234.194.89 - - [17/May/2015:08:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20268\n80.91.33.133 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 2794\n37.26.93.214 - - [17/May/2015:08:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 319 \"-\" \"Go 1.1 package http\" 22809\n188.138.60.101 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8807\n93.180.71.3 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30172\n46.4.66.76 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 1973\n62.75.198.179 - - [17/May/2015:08:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10182\n80.91.33.133 - - [17/May/2015:08:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14307\n173.203.139.108 - - [17/May/2015:08:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10828\n210.245.80.75 - - [17/May/2015:08:05:32 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 21956\n46.4.83.163 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5726\n91.234.194.89 - - [17/May/2015:08:05:18 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10841\n31.22.86.126 - - [17/May/2015:08:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18132\n217.168.17.5 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 3301 \"-\" \"-\" 10094\n80.91.33.133 - - [17/May/2015:08:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12355\n173.203.139.108 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27325\n80.91.33.133 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14101\n5.83.131.103 - - [17/May/2015:08:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20175\n80.91.33.133 - - [17/May/2015:08:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21384\n200.6.73.40 - - [17/May/2015:08:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6570\n80.91.33.133 - - [17/May/2015:08:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26145\n93.180.71.3 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 32705\n62.75.198.179 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18865\n50.57.209.92 - - [17/May/2015:08:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21639\n188.138.60.101 - - [17/May/2015:08:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31242\n46.4.66.76 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 5910\n50.57.209.92 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22900\n91.239.186.133 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23919\n173.203.139.108 - - [17/May/2015:08:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25169\n80.91.33.133 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24395\n93.190.71.150 - - [17/May/2015:08:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25750\n91.234.194.89 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26673\n46.4.83.163 - - [17/May/2015:08:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32509\n173.203.139.108 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32714\n54.187.216.43 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 5016\n50.57.209.92 - - [17/May/2015:08:05:59 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14449\n80.91.33.133 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13183\n173.203.139.108 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 7791\n5.83.131.103 - - [17/May/2015:08:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 586\n173.203.139.108 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5036\n80.91.33.133 - - [17/May/2015:08:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20358\n50.57.209.92 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2106\n80.91.33.133 - - [17/May/2015:08:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9757\n37.26.93.214 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 3318 \"-\" \"Go 1.1 package http\" 6222\n23.23.226.37 - - [17/May/2015:08:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 2578 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 9523\n93.180.71.3 - - [17/May/2015:08:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 7228\n173.203.139.108 - - [17/May/2015:08:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31464\n62.75.198.179 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22462\n31.22.86.126 - - [17/May/2015:08:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29906\n50.57.209.92 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16217\n91.239.186.133 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18335\n46.4.66.76 - - [17/May/2015:08:05:00 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 27375\n200.6.73.40 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32073\n173.203.139.108 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31071\n93.190.71.150 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1200\n91.234.194.89 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13143\n173.203.139.108 - - [17/May/2015:08:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16138\n80.91.33.133 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21432\n217.168.17.5 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 1419\n46.4.83.163 - - [17/May/2015:08:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28449\n80.91.33.133 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25906\n50.57.209.92 - - [17/May/2015:08:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27099\n173.203.139.108 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32238\n188.138.60.101 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 237\n80.91.33.133 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7103\n134.119.20.172 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5423\n173.203.139.108 - - [17/May/2015:08:05:29 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6373\n80.91.33.133 - - [17/May/2015:08:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22230\n91.121.161.213 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14196\n80.91.33.133 - - [17/May/2015:08:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17820\n80.91.33.133 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9097\n37.26.93.214 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Go 1.1 package http\" 27632\n5.83.131.103 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14609\n50.57.209.92 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21926\n173.203.139.108 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4915\n54.64.16.235 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 12816\n93.180.71.3 - - [17/May/2015:08:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30742\n202.143.95.26 - - [17/May/2015:08:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24544\n202.143.95.26 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25819\n202.143.95.26 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26831\n80.91.33.133 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 1344\n91.239.186.133 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4987\n173.203.139.108 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 328 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13419\n80.91.33.133 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12879\n87.233.156.242 - - [17/May/2015:08:05:37 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20611\n62.75.198.179 - - [17/May/2015:08:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1387\n50.57.209.92 - - [17/May/2015:08:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31286\n80.91.33.133 - - [17/May/2015:08:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15247\n93.190.71.150 - - [17/May/2015:08:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 134\n46.4.66.76 - - [17/May/2015:08:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 23909\n80.91.33.133 - - [17/May/2015:08:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15771\n91.234.194.89 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4641\n217.168.17.5 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 6382\n46.4.83.163 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14599\n50.57.209.92 - - [17/May/2015:08:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8263\n200.6.73.40 - - [17/May/2015:08:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23514\n91.121.161.213 - - [17/May/2015:08:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29473\n80.91.33.133 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26659\n188.138.60.101 - - [17/May/2015:08:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5147\n144.76.151.58 - - [17/May/2015:08:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21698\n134.119.20.172 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21077\n80.91.33.133 - - [17/May/2015:09:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 7173\n80.91.33.133 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1878\n5.83.131.103 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24451\n93.180.71.3 - - [17/May/2015:09:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30170\n80.91.33.133 - - [17/May/2015:09:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13156\n50.57.209.92 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 306\n5.83.131.103 - - [17/May/2015:09:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 345 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24862\n62.75.167.106 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10227\n37.26.93.214 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Go 1.1 package http\" 28504\n93.64.134.186 - - [17/May/2015:09:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27681\n87.233.156.242 - - [17/May/2015:09:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 1502\n80.91.33.133 - - [17/May/2015:09:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18177\n80.91.33.133 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7934\n54.193.30.212 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 2\n62.75.198.179 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23920\n91.239.186.133 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9333\n83.161.14.106 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19640\n80.91.33.133 - - [17/May/2015:09:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11061\n80.91.33.133 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 24501\n93.190.71.150 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15895\n50.57.209.92 - - [17/May/2015:09:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20558\n80.91.33.133 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 2338\n80.91.33.133 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12192\n217.168.17.5 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 9824\n80.91.33.133 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2246\n54.191.136.177 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 7239\n80.91.33.133 - - [17/May/2015:09:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 21154\n91.234.194.89 - - [17/May/2015:09:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2966\n80.91.33.133 - - [17/May/2015:09:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 10715\n80.91.33.133 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14856\n46.4.83.163 - - [17/May/2015:09:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17717\n91.121.161.213 - - [17/May/2015:09:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9951\n188.138.60.101 - - [17/May/2015:09:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25787\n144.76.151.58 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4930\n195.154.77.170 - - [17/May/2015:09:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21921\n50.57.209.92 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29773\n31.22.86.126 - - [17/May/2015:09:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7593\n54.64.16.235 - - [17/May/2015:09:05:51 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 26867\n202.143.95.26 - - [17/May/2015:09:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31361\n202.143.95.26 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13167\n87.233.156.242 - - [17/May/2015:09:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22554\n62.75.167.106 - - [17/May/2015:09:05:37 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29795\n152.90.220.17 - - [17/May/2015:09:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18753\n80.91.33.133 - - [17/May/2015:09:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 27083\n93.180.71.3 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 28187\n80.91.33.133 - - [17/May/2015:09:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25595\n5.83.131.103 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 26070\n5.83.131.103 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27724\n200.6.73.40 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8086\n46.4.88.134 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 4853\n50.57.209.92 - - [17/May/2015:09:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9464\n93.64.134.186 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 12194\n80.91.33.133 - - [17/May/2015:09:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26621\n62.75.198.180 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29857\n80.91.33.133 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 20514\n80.91.33.133 - - [17/May/2015:09:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 5526\n62.75.198.179 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14143\n80.91.33.133 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 20873\n91.239.186.133 - - [17/May/2015:09:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23230\n80.91.33.133 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25246\n83.161.14.106 - - [17/May/2015:09:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19052\n80.91.33.133 - - [17/May/2015:09:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12362\n195.154.77.170 - - [17/May/2015:09:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10153\n93.190.71.150 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22418\n80.91.33.133 - - [17/May/2015:09:05:43 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 6565\n80.91.33.133 - - [17/May/2015:09:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9883\n144.76.160.62 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 2564\n91.121.161.213 - - [17/May/2015:09:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17140\n46.4.83.163 - - [17/May/2015:09:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22794\n91.234.194.89 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17718\n50.57.209.92 - - [17/May/2015:09:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5434\n188.138.60.101 - - [17/May/2015:09:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 573\n210.245.80.75 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 28482\n144.76.151.58 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31161\n80.91.33.133 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24151\n144.76.117.56 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 6185\n80.91.33.133 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 6276\n31.22.86.126 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 27127\n80.91.33.133 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 9549\n62.75.167.106 - - [17/May/2015:09:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21397\n87.233.156.242 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 10781\n152.90.220.18 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19773\n93.180.71.3 - - [17/May/2015:09:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 11889\n80.91.33.133 - - [17/May/2015:09:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14111\n31.22.86.126 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 319 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17787\n50.57.209.92 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18330\n5.83.131.103 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8993\n46.4.88.134 - - [17/May/2015:09:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17460\n80.91.33.133 - - [17/May/2015:09:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 32412\n80.91.33.133 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12639\n62.75.198.180 - - [17/May/2015:09:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32511\n80.91.33.133 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29012\n80.91.33.133 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9767\n5.83.131.103 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12212\n5.83.131.103 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2440\n5.83.131.103 - - [17/May/2015:09:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8157\n195.154.77.170 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16242\n202.143.95.26 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22261\n93.64.134.186 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15048\n85.214.47.178 - - [17/May/2015:09:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27105\n83.161.14.106 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 32234\n80.70.214.71 - - [17/May/2015:09:05:20 +0000] \"HEAD /downloads/product_1 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 8479\n87.233.156.242 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20831\n54.64.16.235 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 18289\n50.57.209.92 - - [17/May/2015:09:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9858\n91.239.186.133 - - [17/May/2015:09:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20442\n91.121.161.213 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9004\n200.6.73.40 - - [17/May/2015:09:05:30 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13221\n62.75.198.179 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 954\n93.190.71.150 - - [17/May/2015:09:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26398\n80.91.33.133 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22775\n80.91.33.133 - - [17/May/2015:09:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13886\n80.91.33.133 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19340\n144.76.160.62 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17157\n80.91.33.133 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9971\n217.168.17.5 - - [17/May/2015:09:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 26268\n80.91.33.133 - - [17/May/2015:09:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 5983\n80.91.33.133 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15296\n144.76.117.56 - - [17/May/2015:09:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 13922\n144.76.151.58 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10692\n80.91.33.133 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 22550\n62.75.167.106 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20757\n80.91.33.133 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25956\n37.187.238.39 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16674\n80.70.214.71 - - [17/May/2015:10:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 327 \"-\" \"Wget/1.13.4 (linux-gnu)\" 15327\n91.234.194.89 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21807\n80.91.33.133 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 20469\n188.138.60.101 - - [17/May/2015:10:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10122\n80.91.33.133 - - [17/May/2015:10:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1971\n80.91.33.133 - - [17/May/2015:10:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7263\n93.180.71.3 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 953\n46.4.88.134 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 23703\n80.91.33.133 - - [17/May/2015:10:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 126\n62.210.138.59 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 19171\n31.22.86.126 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31107\n80.91.33.133 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 8252\n54.86.157.236 - - [17/May/2015:10:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 25651\n195.154.233.202 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 3446\n54.86.157.236 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 20770\n80.91.33.133 - - [17/May/2015:10:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27979\n94.23.21.169 - - [17/May/2015:10:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28723\n54.86.157.236 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 13439\n195.154.77.170 - - [17/May/2015:10:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22432\n54.86.157.236 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 1572\n85.214.47.178 - - [17/May/2015:10:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27196\n5.83.131.103 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9637\n5.83.131.103 - - [17/May/2015:10:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 18830\n5.83.131.103 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 844\n5.83.131.103 - - [17/May/2015:10:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20882\n80.91.33.133 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1325\n80.91.33.133 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11125\n84.53.65.28 - - [17/May/2015:10:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10771\n80.91.33.133 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24891\n54.86.157.236 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23541\n217.168.17.5 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 22323\n91.121.161.213 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29114\n80.70.214.71 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 329 \"-\" \"Wget/1.13.4 (linux-gnu)\" 13629\n144.76.160.62 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32440\n54.86.157.236 - - [17/May/2015:10:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 20402\n93.64.134.186 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5113\n93.190.71.150 - - [17/May/2015:10:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31729\n87.233.156.242 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 28958\n80.91.33.133 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15630\n91.239.186.133 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 7488\n62.75.198.179 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9316\n144.76.117.56 - - [17/May/2015:10:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9965\n178.32.54.253 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2881\n37.187.238.39 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17544\n83.161.14.106 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11419\n54.86.157.236 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 16406\n91.194.188.90 - - [17/May/2015:10:05:51 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 28324\n83.161.14.106 - - [17/May/2015:10:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 1893\n80.91.33.133 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14697\n93.180.71.3 - - [17/May/2015:10:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16168\n62.210.138.59 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 663\n46.4.88.134 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 27962\n202.143.95.26 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18539\n202.143.95.26 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13495\n202.143.95.26 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3192\n62.75.198.180 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4349\n144.76.137.134 - - [17/May/2015:10:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1395\n80.91.33.133 - - [17/May/2015:10:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12898\n54.86.157.236 - - [17/May/2015:10:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 26930\n80.70.214.71 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 326 \"-\" \"Wget/1.13.4 (linux-gnu)\" 16662\n91.234.194.89 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9445\n188.138.60.101 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18804\n80.91.33.133 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22429\n195.154.233.202 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 8456\n94.23.21.169 - - [17/May/2015:10:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32187\n144.76.151.58 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29276\n80.91.33.133 - - [17/May/2015:10:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9700\n62.75.167.106 - - [17/May/2015:10:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10078\n80.91.33.133 - - [17/May/2015:10:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7600\n50.57.209.92 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8540\n202.143.95.26 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24400\n200.6.73.40 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29363\n195.154.77.170 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17025\n54.187.216.43 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 27997\n80.91.33.133 - - [17/May/2015:10:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1806\n80.91.33.133 - - [17/May/2015:10:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 28234\n54.86.157.236 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 19286\n202.143.95.26 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 325 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19522\n202.143.95.26 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23841\n54.86.157.236 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 31135\n80.91.33.133 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21510\n80.91.33.133 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26977\n80.91.33.133 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 1078\n80.91.33.133 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7473\n84.53.65.28 - - [17/May/2015:10:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28347\n92.50.100.22 - - [17/May/2015:10:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8699\n85.214.47.178 - - [17/May/2015:10:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2078\n80.91.33.133 - - [17/May/2015:10:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7013\n54.86.157.236 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 29440\n5.83.131.103 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24206\n37.187.238.39 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 5674\n80.91.33.133 - - [17/May/2015:10:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15781\n195.210.47.239 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 1462\n80.91.33.133 - - [17/May/2015:10:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9446\n54.64.16.235 - - [17/May/2015:10:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23687\n178.32.54.253 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17314\n144.92.16.161 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 4021\n54.86.157.236 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 13168\n87.233.156.242 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 8142\n31.22.86.126 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 28923\n80.91.33.133 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17021\n91.121.161.213 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 711\n80.91.33.133 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15815\n50.57.209.92 - - [17/May/2015:10:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 12290\n91.239.186.133 - - [17/May/2015:10:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9172\n144.76.117.56 - - [17/May/2015:10:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27106\n144.76.160.62 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 2607\n62.210.138.59 - - [17/May/2015:10:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26922\n54.86.157.236 - - [17/May/2015:10:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 2045\n62.75.198.179 - - [17/May/2015:10:05:14 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14090\n93.190.71.150 - - [17/May/2015:10:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2233\n144.76.117.56 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14988\n94.23.21.169 - - [17/May/2015:10:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11645\n91.194.188.90 - - [17/May/2015:10:05:05 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 28064\n93.64.134.186 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16583\n54.86.157.236 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23208\n80.70.214.71 - - [17/May/2015:10:05:23 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 1059\n93.180.71.3 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16367\n195.154.233.202 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26788\n193.192.58.163 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6753\n144.76.137.134 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18307\n54.86.157.236 - - [17/May/2015:11:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 10520\n83.161.14.106 - - [17/May/2015:11:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 5640\n144.76.151.58 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9992\n144.92.16.161 - - [17/May/2015:11:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 3262\n195.154.77.170 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17687\n62.75.198.180 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18911\n91.234.194.89 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22038\n80.91.33.133 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 2238\n188.138.60.101 - - [17/May/2015:11:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10581\n62.75.167.106 - - [17/May/2015:11:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14869\n46.4.88.134 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 6669\n80.91.33.133 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12780\n80.91.33.133 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24133\n84.53.65.28 - - [17/May/2015:11:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14350\n152.90.220.17 - - [17/May/2015:11:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23513\n80.91.33.133 - - [17/May/2015:11:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31695\n80.91.33.133 - - [17/May/2015:11:05:21 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12243\n178.32.54.253 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2641\n54.72.39.202 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 27639\n91.120.61.154 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21180\n37.187.238.39 - - [17/May/2015:11:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 30661\n85.214.47.178 - - [17/May/2015:11:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20380\n80.91.33.133 - - [17/May/2015:11:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11957\n5.83.131.103 - - [17/May/2015:11:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19230\n200.6.73.40 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4087\n5.83.131.103 - - [17/May/2015:11:05:45 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 16383\n91.121.161.213 - - [17/May/2015:11:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11487\n91.239.186.133 - - [17/May/2015:11:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11774\n50.57.209.92 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28472\n80.91.33.133 - - [17/May/2015:11:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24011\n144.92.16.161 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 26633\n87.233.156.242 - - [17/May/2015:11:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16170\n94.23.21.169 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15992\n5.83.131.103 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20999\n80.91.33.133 - - [17/May/2015:11:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23097\n202.143.95.26 - - [17/May/2015:11:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3282\n202.143.95.26 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 4869\n80.91.33.133 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 9310\n80.91.33.133 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 23547\n80.91.33.133 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 5516\n80.91.33.133 - - [17/May/2015:11:05:13 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26601\n62.210.138.59 - - [17/May/2015:11:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26830\n144.76.160.62 - - [17/May/2015:11:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 15405\n93.190.71.150 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16982\n80.91.33.133 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 6019\n202.143.95.26 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3822\n193.192.58.163 - - [17/May/2015:11:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13461\n195.154.233.202 - - [17/May/2015:11:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32439\n80.70.214.71 - - [17/May/2015:11:05:59 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 31402\n62.75.198.179 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 452\n80.91.33.133 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25508\n144.92.16.161 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 29252\n195.154.77.170 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19649\n50.57.209.92 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 24457\n144.76.117.56 - - [17/May/2015:11:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 10519\n80.91.33.133 - - [17/May/2015:11:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 6815\n144.76.137.134 - - [17/May/2015:11:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 798\n188.138.60.101 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19441\n54.172.198.124 - - [17/May/2015:11:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 2582 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 17903\n37.187.238.39 - - [17/May/2015:11:05:27 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 3443\n178.32.54.253 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9634\n62.75.198.180 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5417\n62.75.167.106 - - [17/May/2015:11:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1055\n195.210.47.239 - - [17/May/2015:11:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 4218\n91.234.194.89 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23355\n31.22.86.126 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29547\n91.194.188.90 - - [17/May/2015:11:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Wget/1.13.4 (linux-gnu)\" 26988\n92.50.100.22 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13600\n144.76.151.58 - - [17/May/2015:11:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18988\n93.64.134.186 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2281\n85.214.47.178 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16054\n94.23.21.169 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21647\n80.91.33.133 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31277\n80.91.33.133 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19500\n91.121.161.213 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29579\n83.161.14.106 - - [17/May/2015:11:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 1080\n54.64.16.235 - - [17/May/2015:11:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 15057\n84.53.65.28 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5805\n80.91.33.133 - - [17/May/2015:11:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 32764\n50.57.209.92 - - [17/May/2015:11:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28248\n91.239.186.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32046\n144.92.16.161 - - [17/May/2015:11:05:30 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 31342\n62.210.138.59 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22861\n210.245.80.75 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32649\n80.91.33.133 - - [17/May/2015:11:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11268\n83.161.14.106 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8233\n87.233.156.242 - - [17/May/2015:11:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 10052\n5.83.131.103 - - [17/May/2015:11:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20084\n80.91.33.133 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9007\n91.120.61.154 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8410\n195.154.233.202 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20582\n80.91.33.133 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8327\n193.192.58.163 - - [17/May/2015:11:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4041\n93.190.71.150 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26973\n144.76.160.62 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 24342\n50.57.209.92 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27744\n62.75.198.179 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2455\n193.192.59.41 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19596\n195.154.77.170 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23424\n80.91.33.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 4171\n200.6.73.40 - - [17/May/2015:11:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8274\n188.138.60.101 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2949\n80.91.33.133 - - [17/May/2015:11:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 5641\n80.91.33.133 - - [17/May/2015:11:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 28746\n80.91.33.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18396\n80.91.33.133 - - [17/May/2015:11:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 17638\n80.91.33.133 - - [17/May/2015:11:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 7865\n144.76.137.134 - - [17/May/2015:11:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4280\n80.70.214.71 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Wget/1.13.4 (linux-gnu)\" 32436\n144.76.117.56 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 30048\n94.23.21.169 - - [17/May/2015:11:05:21 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6186\n198.61.216.151 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 21567\n80.91.33.133 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 674\n91.194.188.90 - - [17/May/2015:11:05:32 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 5354\n62.75.198.180 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5345\n80.91.33.133 - - [17/May/2015:11:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2326\n31.22.86.126 - - [17/May/2015:12:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3114\n84.53.65.28 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9036\n144.92.16.161 - - [17/May/2015:12:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 9410\n50.57.209.92 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2039\n5.83.131.103 - - [17/May/2015:12:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14852\n5.83.131.103 - - [17/May/2015:12:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 71\n62.75.167.106 - - [17/May/2015:12:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6439\n178.32.54.253 - - [17/May/2015:12:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8721\n91.121.161.213 - - [17/May/2015:12:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1795\n91.234.194.89 - - [17/May/2015:12:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8556\n37.187.238.39 - - [17/May/2015:12:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17627\n91.239.186.133 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10970\n87.233.156.242 - - [17/May/2015:12:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 409\n202.143.95.26 - - [17/May/2015:12:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 10283\n144.76.151.58 - - [17/May/2015:12:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22461\n62.210.138.59 - - [17/May/2015:12:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22736\n80.91.33.133 - - [17/May/2015:12:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 21014\n83.161.14.106 - - [17/May/2015:12:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 18047\n80.91.33.133 - - [17/May/2015:12:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25206\n5.83.131.103 - - [17/May/2015:12:05:21 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15330\n80.91.33.133 - - [17/May/2015:12:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 8763\n198.61.216.151 - - [17/May/2015:12:05:59 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11132\n195.154.77.170 - - [17/May/2015:12:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23768\n"
  },
  {
    "path": "plugins/inputs/ethtool/README.md",
    "content": "# Ethtool Input Plugin\n\nThis plugin collects ethernet device statistics. The available information\nstrongly depends on the network device and driver.\n\n⭐ Telegraf v1.13.0\n🏷️ system, network\n💻 linux\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Returns ethtool statistics for given interfaces\n# This plugin ONLY supports Linux\n[[inputs.ethtool]]\n  ## List of interfaces to pull metrics for\n  # interface_include = [\"eth0\"]\n\n  ## List of interfaces to ignore when pulling metrics.\n  # interface_exclude = [\"eth1\"]\n\n  ## Plugin behavior for downed interfaces\n  ## Available choices:\n  ##   - expose: collect & report metrics for down interfaces\n  ##   - skip: ignore interfaces that are marked down\n  # down_interfaces = \"expose\"\n\n  ## Reading statistics from interfaces in additional namespaces is also\n  ## supported, so long as the namespaces are named (have a symlink in\n  ## /var/run/netns). The telegraf process will also need the CAP_SYS_ADMIN\n  ## permission.\n  ## By default, only the current namespace will be used. For additional\n  ## namespace support, at least one of `namespace_include` and\n  ## `namespace_exclude` must be provided.\n  ## To include all namespaces, set `namespace_include` to `[\"*\"]`.\n  ## The initial namespace (if anonymous) can be specified with the empty\n  ## string (\"\").\n\n  ## List of namespaces to pull metrics for\n  # namespace_include = []\n\n  ## List of namespace to ignore when pulling metrics.\n  # namespace_exclude = []\n\n  ## Some drivers declare statistics with extra whitespace, different spacing,\n  ## and mix cases. This list, when enabled, can be used to clean the keys.\n  ## Here are the current possible normalizations:\n  ##  * snakecase: converts fooBarBaz to foo_bar_baz\n  ##  * trim: removes leading and trailing whitespace\n  ##  * lower: changes all capitalized letters to lowercase\n  ##  * underscore: replaces spaces with underscores\n  # normalize_keys = [\"snakecase\", \"trim\", \"lower\", \"underscore\"]\n```\n\nInterfaces can be included or ignored using:\n\n- `interface_include`\n- `interface_exclude`\n\nNote that loopback interfaces will be automatically ignored.\n\n## Namespaces\n\nMetrics from interfaces in additional namespaces will be retrieved if either\n`namespace_include` or `namespace_exclude` is configured (to a non-empty list).\nThis requires `CAP_SYS_ADMIN` permissions to switch namespaces, which can be\ngranted to telegraf in several ways. The two recommended ways are listed below:\n\n### Using systemd capabilities\n\nIf you are using systemd to run Telegraf, you may run\n`systemctl edit telegraf.service` and add the following:\n\n```text\n[Service]\nAmbientCapabilities=CAP_SYS_ADMIN\n```\n\n### Configuring executable capabilities\n\nIf you are not using systemd to run Telegraf, you can configure the Telegraf\nexecutable to have `CAP_SYS_ADMIN` when run.\n\n```sh\nsudo setcap CAP_SYS_ADMIN+epi $(which telegraf)\n```\n\nN.B.: This capability is a filesystem attribute on the binary itself. The\nattribute needs to be re-applied if the Telegraf binary is rotated (e.g. on\ninstallation of new a Telegraf version from the system package manager).\n\n## Metrics\n\nMetrics are dependent on the network device and driver.\n\n## Example Output\n\n```text\nethtool,driver=igb,host=test01,interface=mgmt0 tx_queue_1_packets=280782i,rx_queue_5_csum_err=0i,tx_queue_4_restart=0i,tx_multicast=7i,tx_queue_1_bytes=39674885i,rx_queue_2_alloc_failed=0i,tx_queue_5_packets=173970i,tx_single_coll_ok=0i,rx_queue_1_drops=0i,tx_queue_2_restart=0i,tx_aborted_errors=0i,rx_queue_6_csum_err=0i,tx_queue_5_restart=0i,tx_queue_4_bytes=64810835i,tx_abort_late_coll=0i,tx_queue_4_packets=109102i,os2bmc_tx_by_bmc=0i,tx_bytes=427527435i,tx_queue_7_packets=66665i,dropped_smbus=0i,rx_queue_0_csum_err=0i,tx_flow_control_xoff=0i,rx_packets=25926536i,rx_queue_7_csum_err=0i,rx_queue_3_bytes=84326060i,rx_multicast=83771i,rx_queue_4_alloc_failed=0i,rx_queue_3_drops=0i,rx_queue_3_csum_err=0i,rx_errors=0i,tx_errors=0i,tx_queue_6_packets=183236i,rx_broadcast=24378893i,rx_queue_7_packets=88680i,tx_dropped=0i,rx_frame_errors=0i,tx_queue_3_packets=161045i,tx_packets=1257017i,rx_queue_1_csum_err=0i,tx_window_errors=0i,tx_dma_out_of_sync=0i,rx_length_errors=0i,rx_queue_5_drops=0i,tx_timeout_count=0i,rx_queue_4_csum_err=0i,rx_flow_control_xon=0i,tx_heartbeat_errors=0i,tx_flow_control_xon=0i,collisions=0i,tx_queue_0_bytes=29465801i,rx_queue_6_drops=0i,rx_queue_0_alloc_failed=0i,tx_queue_1_restart=0i,rx_queue_0_drops=0i,tx_broadcast=9i,tx_carrier_errors=0i,tx_queue_7_bytes=13777515i,tx_queue_7_restart=0i,rx_queue_5_bytes=50732006i,rx_queue_7_bytes=35744457i,tx_deferred_ok=0i,tx_multi_coll_ok=0i,rx_crc_errors=0i,rx_fifo_errors=0i,rx_queue_6_alloc_failed=0i,tx_queue_2_packets=175206i,tx_queue_0_packets=107011i,rx_queue_4_bytes=201364548i,rx_queue_6_packets=372573i,os2bmc_rx_by_host=0i,multicast=83771i,rx_queue_4_drops=0i,rx_queue_5_packets=130535i,rx_queue_6_bytes=139488035i,tx_fifo_errors=0i,tx_queue_5_bytes=84899130i,rx_queue_0_packets=24529563i,rx_queue_3_alloc_failed=0i,rx_queue_7_drops=0i,tx_queue_6_bytes=96288614i,tx_queue_2_bytes=22132949i,tx_tcp_seg_failed=0i,rx_queue_1_bytes=246703840i,rx_queue_0_bytes=1506870738i,tx_queue_0_restart=0i,rx_queue_2_bytes=111344804i,tx_tcp_seg_good=0i,tx_queue_3_restart=0i,rx_no_buffer_count=0i,rx_smbus=0i,rx_queue_1_packets=273865i,rx_over_errors=0i,os2bmc_tx_by_host=0i,rx_queue_1_alloc_failed=0i,rx_queue_7_alloc_failed=0i,rx_short_length_errors=0i,tx_hwtstamp_timeouts=0i,tx_queue_6_restart=0i,rx_queue_2_packets=207136i,tx_queue_3_bytes=70391970i,rx_queue_3_packets=112007i,rx_queue_4_packets=212177i,tx_smbus=0i,rx_long_byte_count=2480280632i,rx_queue_2_csum_err=0i,rx_missed_errors=0i,rx_bytes=2480280632i,rx_queue_5_alloc_failed=0i,rx_queue_2_drops=0i,os2bmc_rx_by_bmc=0i,rx_align_errors=0i,rx_long_length_errors=0i,interface_up=1i,rx_hwtstamp_cleared=0i,rx_flow_control_xoff=0i,speed=1000i,link=1i,duplex=1i,autoneg=1i 1564658080000000000\nethtool,driver=igb,host=test02,interface=mgmt0 rx_queue_2_bytes=111344804i,tx_queue_3_bytes=70439858i,multicast=83771i,rx_broadcast=24378975i,tx_queue_0_packets=107011i,rx_queue_6_alloc_failed=0i,rx_queue_6_drops=0i,rx_hwtstamp_cleared=0i,tx_window_errors=0i,tx_tcp_seg_good=0i,rx_queue_1_drops=0i,tx_queue_1_restart=0i,rx_queue_7_csum_err=0i,rx_no_buffer_count=0i,tx_queue_1_bytes=39675245i,tx_queue_5_bytes=84899130i,tx_broadcast=9i,rx_queue_1_csum_err=0i,tx_flow_control_xoff=0i,rx_queue_6_csum_err=0i,tx_timeout_count=0i,os2bmc_tx_by_bmc=0i,rx_queue_6_packets=372577i,rx_queue_0_alloc_failed=0i,tx_flow_control_xon=0i,rx_queue_2_drops=0i,tx_queue_2_packets=175206i,rx_queue_3_csum_err=0i,tx_abort_late_coll=0i,tx_queue_5_restart=0i,tx_dropped=0i,rx_queue_2_alloc_failed=0i,tx_multi_coll_ok=0i,rx_queue_1_packets=273865i,rx_flow_control_xon=0i,tx_single_coll_ok=0i,rx_length_errors=0i,rx_queue_7_bytes=35744457i,rx_queue_4_alloc_failed=0i,rx_queue_6_bytes=139488395i,rx_queue_2_csum_err=0i,rx_long_byte_count=2480288216i,rx_queue_1_alloc_failed=0i,tx_queue_0_restart=0i,rx_queue_0_csum_err=0i,tx_queue_2_bytes=22132949i,rx_queue_5_drops=0i,tx_dma_out_of_sync=0i,rx_queue_3_drops=0i,rx_queue_4_packets=212177i,tx_queue_6_restart=0i,rx_packets=25926650i,rx_queue_7_packets=88680i,rx_frame_errors=0i,rx_queue_3_bytes=84326060i,rx_short_length_errors=0i,tx_queue_7_bytes=13777515i,rx_queue_3_alloc_failed=0i,tx_queue_6_packets=183236i,rx_queue_0_drops=0i,rx_multicast=83771i,rx_queue_2_packets=207136i,rx_queue_5_csum_err=0i,rx_queue_5_packets=130535i,rx_queue_7_alloc_failed=0i,tx_smbus=0i,tx_queue_3_packets=161081i,rx_queue_7_drops=0i,tx_queue_2_restart=0i,tx_multicast=7i,tx_fifo_errors=0i,tx_queue_3_restart=0i,rx_long_length_errors=0i,tx_queue_6_bytes=96288614i,tx_queue_1_packets=280786i,tx_tcp_seg_failed=0i,rx_align_errors=0i,tx_errors=0i,rx_crc_errors=0i,rx_queue_0_packets=24529673i,rx_flow_control_xoff=0i,tx_queue_0_bytes=29465801i,rx_over_errors=0i,rx_queue_4_drops=0i,os2bmc_rx_by_bmc=0i,rx_smbus=0i,dropped_smbus=0i,tx_hwtstamp_timeouts=0i,rx_errors=0i,tx_queue_4_packets=109102i,tx_carrier_errors=0i,tx_queue_4_bytes=64810835i,tx_queue_4_restart=0i,rx_queue_4_csum_err=0i,tx_queue_7_packets=66665i,tx_aborted_errors=0i,rx_missed_errors=0i,tx_bytes=427575843i,collisions=0i,rx_queue_1_bytes=246703840i,rx_queue_5_bytes=50732006i,rx_bytes=2480288216i,os2bmc_rx_by_host=0i,rx_queue_5_alloc_failed=0i,rx_queue_3_packets=112007i,tx_deferred_ok=0i,os2bmc_tx_by_host=0i,tx_heartbeat_errors=0i,rx_queue_0_bytes=1506877506i,tx_queue_7_restart=0i,tx_packets=1257057i,rx_queue_4_bytes=201364548i,interface_up=0i,rx_fifo_errors=0i,tx_queue_5_packets=173970i,speed=1000i,link=1i,duplex=1i,autoneg=1i 1564658090000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ethtool/ethtool.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ethtool\n\nimport (\n\t_ \"embed\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst pluginName = \"ethtool\"\n\nfunc (*Ethtool) SampleConfig() string {\n\treturn sampleConfig\n}\n"
  },
  {
    "path": "plugins/inputs/ethtool/ethtool_linux.go",
    "content": "//go:build linux\n\npackage ethtool\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vishvananda/netns\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nvar downInterfacesBehaviors = []string{\"expose\", \"skip\"}\n\nconst (\n\ttagInterface     = \"interface\"\n\ttagNamespace     = \"namespace\"\n\ttagDriverName    = \"driver\"\n\tfieldInterfaceUp = \"interface_up\"\n)\n\ntype Ethtool struct {\n\t// This is the list of interface names to include\n\tInterfaceInclude []string `toml:\"interface_include\"`\n\n\t// This is the list of interface names to ignore\n\tInterfaceExclude []string `toml:\"interface_exclude\"`\n\n\t// Behavior regarding metrics for downed interfaces\n\tDownInterfaces string `toml:\" down_interfaces\"`\n\n\t// This is the list of namespace names to include\n\tNamespaceInclude []string `toml:\"namespace_include\"`\n\n\t// This is the list of namespace names to ignore\n\tNamespaceExclude []string `toml:\"namespace_exclude\"`\n\n\t// Normalization on the key names\n\tNormalizeKeys []string `toml:\"normalize_keys\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tinterfaceFilter   filter.Filter\n\tnamespaceFilter   filter.Filter\n\tincludeNamespaces bool\n\n\t// the ethtool command\n\tcommand command\n}\n\ntype command interface {\n\tinit() error\n\tdriverName(intf namespacedInterface) (string, error)\n\tinterfaces(includeNamespaces bool) ([]namespacedInterface, error)\n\tstats(intf namespacedInterface) (map[string]uint64, error)\n\tget(intf namespacedInterface) (map[string]uint64, error)\n}\n\ntype commandEthtool struct {\n\tlog                 telegraf.Logger\n\tnamespaceGoroutines map[string]*namespaceGoroutine\n}\n\nfunc (e *Ethtool) Init() error {\n\tvar err error\n\te.interfaceFilter, err = filter.NewIncludeExcludeFilter(e.InterfaceInclude, e.InterfaceExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif e.DownInterfaces == \"\" {\n\t\te.DownInterfaces = \"expose\"\n\t}\n\n\tif err = choice.Check(e.DownInterfaces, downInterfacesBehaviors); err != nil {\n\t\treturn fmt.Errorf(\"down_interfaces: %w\", err)\n\t}\n\n\t// If no namespace include or exclude filters were provided, then default\n\t// to just the initial namespace.\n\te.includeNamespaces = len(e.NamespaceInclude) > 0 || len(e.NamespaceExclude) > 0\n\tif len(e.NamespaceInclude) == 0 && len(e.NamespaceExclude) == 0 {\n\t\te.NamespaceInclude = []string{\"\"}\n\t} else if len(e.NamespaceInclude) == 0 {\n\t\te.NamespaceInclude = []string{\"*\"}\n\t}\n\te.namespaceFilter, err = filter.NewIncludeExcludeFilter(e.NamespaceInclude, e.NamespaceExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif command, ok := e.command.(*commandEthtool); ok {\n\t\tcommand.log = e.Log\n\t}\n\n\treturn e.command.init()\n}\n\nfunc (e *Ethtool) Gather(acc telegraf.Accumulator) error {\n\t// Get the list of interfaces\n\tinterfaces, err := e.command.interfaces(e.includeNamespaces)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn nil\n\t}\n\n\t// parallelize the ethtool call in event of many interfaces\n\tvar wg sync.WaitGroup\n\n\tfor _, iface := range interfaces {\n\t\t// Check this isn't a loop back and that its matched by the filter(s)\n\t\tif e.interfaceEligibleForGather(iface) {\n\t\t\twg.Add(1)\n\n\t\t\tgo func(i namespacedInterface) {\n\t\t\t\te.gatherEthtoolStats(i, acc)\n\t\t\t\twg.Done()\n\t\t\t}(iface)\n\t\t}\n\t}\n\n\t// Waiting for all the interfaces\n\twg.Wait()\n\treturn nil\n}\n\nfunc (e *Ethtool) interfaceEligibleForGather(iface namespacedInterface) bool {\n\t// Don't gather if it is a loop back, or it isn't matched by the filter\n\tif isLoopback(iface) || !e.interfaceFilter.Match(iface.Name) {\n\t\treturn false\n\t}\n\n\t// Don't gather if it's not in a namespace matched by the filter\n\tif !e.namespaceFilter.Match(iface.namespace.name()) {\n\t\treturn false\n\t}\n\n\t// For downed interfaces, gather only for \"expose\"\n\tif !interfaceUp(iface) {\n\t\treturn e.DownInterfaces == \"expose\"\n\t}\n\n\treturn true\n}\n\n// Gather the stats for the interface.\nfunc (e *Ethtool) gatherEthtoolStats(iface namespacedInterface, acc telegraf.Accumulator) {\n\ttags := make(map[string]string)\n\ttags[tagInterface] = iface.Name\n\ttags[tagNamespace] = iface.namespace.name()\n\n\tdriverName, err := e.command.driverName(iface)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"%q driver: %w\", iface.Name, err))\n\t\treturn\n\t}\n\n\ttags[tagDriverName] = driverName\n\n\tfields := make(map[string]interface{})\n\tstats, err := e.command.stats(iface)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"%q stats: %w\", iface.Name, err))\n\t\treturn\n\t}\n\n\tfields[fieldInterfaceUp] = interfaceUp(iface)\n\tfor k, v := range stats {\n\t\tfields[e.normalizeKey(k)] = v\n\t}\n\n\tcmdget, err := e.command.get(iface)\n\t// error text is directly from running ethtool and syscalls\n\tif err != nil && err.Error() != \"operation not supported\" {\n\t\tacc.AddError(fmt.Errorf(\"%q get: %w\", iface.Name, err))\n\t\treturn\n\t}\n\tfor k, v := range cmdget {\n\t\tfields[e.normalizeKey(k)] = v\n\t}\n\n\tacc.AddFields(pluginName, fields, tags)\n}\n\n// normalize key string; order matters to avoid replacing whitespace with\n// underscores, then trying to trim those same underscores. Likewise with\n// camelcase before trying to lower case things.\nfunc (e *Ethtool) normalizeKey(key string) string {\n\t// must trim whitespace or this will have a leading _\n\tif inStringSlice(e.NormalizeKeys, \"snakecase\") {\n\t\tkey = camelCase2SnakeCase(strings.TrimSpace(key))\n\t}\n\t// must occur before underscore, otherwise nothing to trim\n\tif inStringSlice(e.NormalizeKeys, \"trim\") {\n\t\tkey = strings.TrimSpace(key)\n\t}\n\tif inStringSlice(e.NormalizeKeys, \"lower\") {\n\t\tkey = strings.ToLower(key)\n\t}\n\tif inStringSlice(e.NormalizeKeys, \"underscore\") {\n\t\tkey = strings.ReplaceAll(key, \" \", \"_\")\n\t}\n\t// aws has a conflicting name that needs to be renamed\n\tif key == \"interface_up\" {\n\t\tkey = \"interface_up_counter\"\n\t}\n\n\treturn key\n}\n\nfunc camelCase2SnakeCase(value string) string {\n\tmatchFirstCap := regexp.MustCompile(\"(.)([A-Z][a-z]+)\")\n\tmatchAllCap := regexp.MustCompile(\"([a-z0-9])([A-Z])\")\n\n\tsnake := matchFirstCap.ReplaceAllString(value, \"${1}_${2}\")\n\tsnake = matchAllCap.ReplaceAllString(snake, \"${1}_${2}\")\n\treturn strings.ToLower(snake)\n}\n\nfunc inStringSlice(slice []string, value string) bool {\n\tfor _, item := range slice {\n\t\tif item == value {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc isLoopback(iface namespacedInterface) bool {\n\treturn (iface.Flags & net.FlagLoopback) != 0\n}\n\nfunc interfaceUp(iface namespacedInterface) bool {\n\treturn (iface.Flags & net.FlagUp) != 0\n}\n\nfunc newCommandEthtool() *commandEthtool {\n\treturn &commandEthtool{}\n}\n\nfunc (c *commandEthtool) init() error {\n\t// Create the goroutine for the initial namespace\n\tinitialNamespace, err := netns.Get()\n\tif err != nil {\n\t\treturn err\n\t}\n\tnspaceGoroutine := &namespaceGoroutine{\n\t\tnamespaceName: \"\",\n\t\thandle:        initialNamespace,\n\t\tlog:           c.log,\n\t}\n\tif err := nspaceGoroutine.start(); err != nil {\n\t\tc.log.Errorf(`Failed to start goroutine for the initial namespace: %s`, err)\n\t\treturn err\n\t}\n\tc.namespaceGoroutines = map[string]*namespaceGoroutine{\n\t\t\"\": nspaceGoroutine,\n\t}\n\treturn nil\n}\n\nfunc (*commandEthtool) driverName(intf namespacedInterface) (driver string, err error) {\n\treturn intf.namespace.driverName(intf)\n}\n\nfunc (*commandEthtool) stats(intf namespacedInterface) (stats map[string]uint64, err error) {\n\treturn intf.namespace.stats(intf)\n}\n\nfunc (*commandEthtool) get(intf namespacedInterface) (stats map[string]uint64, err error) {\n\treturn intf.namespace.get(intf)\n}\n\nfunc (c *commandEthtool) interfaces(includeNamespaces bool) ([]namespacedInterface, error) {\n\tconst namespaceDirectory = \"/var/run/netns\"\n\n\tinitialNamespace, err := netns.Get()\n\tif err != nil {\n\t\tc.log.Errorf(\"Could not get initial namespace: %s\", err)\n\t\treturn nil, err\n\t}\n\tdefer initialNamespace.Close()\n\n\t// Gather the list of namespace names to from which to retrieve interfaces.\n\tinitialNamespaceIsNamed := false\n\tvar namespaceNames []string\n\t// Handles are only used to create namespaced goroutines. We don't prefill\n\t// with the handle for the initial namespace because we've already created\n\t// its goroutine in Init().\n\thandles := make(map[string]netns.NsHandle)\n\n\tif includeNamespaces {\n\t\tnamespaces, err := os.ReadDir(namespaceDirectory)\n\t\tif err != nil {\n\t\t\tc.log.Warnf(\"Could not find namespace directory: %s\", err)\n\t\t}\n\n\t\t// We'll always have at least the initial namespace, so add one to ensure\n\t\t// we have capacity for it.\n\t\tnamespaceNames = make([]string, 0, len(namespaces)+1)\n\t\tfor _, namespace := range namespaces {\n\t\t\tname := namespace.Name()\n\t\t\tnamespaceNames = append(namespaceNames, name)\n\n\t\t\thandle, err := netns.GetFromPath(filepath.Join(namespaceDirectory, name))\n\t\t\tif err != nil {\n\t\t\t\tc.log.Warnf(\"Could not get handle for namespace %q: %s\", name, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\thandles[name] = handle\n\t\t\tif handle.Equal(initialNamespace) {\n\t\t\t\tinitialNamespaceIsNamed = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// We don't want to gather interfaces from the same namespace twice, and\n\t// it's possible, though unlikely, that the initial namespace is also a\n\t// named interface.\n\tif !initialNamespaceIsNamed {\n\t\tnamespaceNames = append(namespaceNames, \"\")\n\t}\n\n\tallInterfaces := make([]namespacedInterface, 0)\n\tfor _, namespace := range namespaceNames {\n\t\tif _, ok := c.namespaceGoroutines[namespace]; !ok {\n\t\t\tc.namespaceGoroutines[namespace] = &namespaceGoroutine{\n\t\t\t\tnamespaceName: namespace,\n\t\t\t\thandle:        handles[namespace],\n\t\t\t\tlog:           c.log,\n\t\t\t}\n\t\t\tif err := c.namespaceGoroutines[namespace].start(); err != nil {\n\t\t\t\tc.log.Errorf(\"Failed to start goroutine for namespace %q: %s\", namespace, err.Error())\n\t\t\t\tdelete(c.namespaceGoroutines, namespace)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tinterfaces, err := c.namespaceGoroutines[namespace].interfaces()\n\t\tif err != nil {\n\t\t\tc.log.Warnf(\"Could not get interfaces from namespace %q: %s\", namespace, err.Error())\n\t\t\tcontinue\n\t\t}\n\t\tallInterfaces = append(allInterfaces, interfaces...)\n\t}\n\n\treturn allInterfaces, nil\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\treturn &Ethtool{\n\t\t\tcommand: newCommandEthtool(),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ethtool/ethtool_notlinux.go",
    "content": "//go:build !linux\n\npackage ethtool\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype Ethtool struct {\n\t// This is the list of interface names to include\n\tInterfaceInclude []string `toml:\"interface_include\"`\n\n\t// This is the list of interface names to ignore\n\tInterfaceExclude []string `toml:\"interface_exclude\"`\n\n\t// Behavior regarding metrics for downed interfaces\n\tDownInterfaces string `toml:\" down_interfaces\"`\n\n\t// This is the list of namespace names to include\n\tNamespaceInclude []string `toml:\"namespace_include\"`\n\n\t// This is the list of namespace names to ignore\n\tNamespaceExclude []string `toml:\"namespace_exclude\"`\n\n\t// Normalization on the key names\n\tNormalizeKeys []string `toml:\"normalize_keys\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (e *Ethtool) Init() error {\n\te.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Ethtool) Gather(_ telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\treturn &Ethtool{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ethtool/ethtool_test.go",
    "content": "//go:build linux\n\npackage ethtool\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar (\n\teth          *Ethtool\n\tinterfaceMap map[string]*interfaceMock\n)\n\ntype interfaceMock struct {\n\tname          string\n\tdriverName    string\n\tnamespaceName string\n\tstat          map[string]uint64\n\tloopBack      bool\n\tinterfaceUp   bool\n\tcmdGet        map[string]uint64\n}\n\ntype namespaceMock struct {\n\tnamespaceName string\n}\n\nfunc (n *namespaceMock) name() string {\n\treturn n.namespaceName\n}\n\nfunc (*namespaceMock) interfaces() ([]namespacedInterface, error) {\n\treturn nil, errors.New(\"it is a test bug to invoke this function\")\n}\n\nfunc (*namespaceMock) driverName(_ namespacedInterface) (string, error) {\n\treturn \"\", errors.New(\"it is a test bug to invoke this function\")\n}\n\nfunc (*namespaceMock) stats(_ namespacedInterface) (map[string]uint64, error) {\n\treturn nil, errors.New(\"it is a test bug to invoke this function\")\n}\n\nfunc (*namespaceMock) get(_ namespacedInterface) (map[string]uint64, error) {\n\treturn nil, errors.New(\"it is a test bug to invoke this function\")\n}\n\ntype commandEthtoolMock struct {\n\tinterfaceMap map[string]*interfaceMock\n}\n\nfunc (*commandEthtoolMock) init() error {\n\t// Not required for test mock\n\treturn nil\n}\n\nfunc (c *commandEthtoolMock) driverName(intf namespacedInterface) (string, error) {\n\ti := c.interfaceMap[intf.Name]\n\tif i != nil {\n\t\treturn i.driverName, nil\n\t}\n\treturn \"\", errors.New(\"interface not found\")\n}\n\nfunc (c *commandEthtoolMock) interfaces(includeNamespaces bool) ([]namespacedInterface, error) {\n\tnamespaces := map[string]*namespaceMock{\"\": {namespaceName: \"\"}}\n\n\tinterfaces := make([]namespacedInterface, 0)\n\tfor k, v := range c.interfaceMap {\n\t\tif v.namespaceName != \"\" && !includeNamespaces {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar flag net.Flags\n\t\t// When interface is up\n\t\tif v.interfaceUp {\n\t\t\tflag |= net.FlagUp\n\t\t}\n\t\t// For loopback interface\n\t\tif v.loopBack {\n\t\t\tflag |= net.FlagLoopback\n\t\t}\n\n\t\t// Create a dummy interface\n\t\tiface := net.Interface{\n\t\t\tIndex:        0,\n\t\t\tMTU:          1500,\n\t\t\tName:         k,\n\t\t\tHardwareAddr: nil,\n\t\t\tFlags:        flag,\n\t\t}\n\n\t\t// Ensure there is a namespace if necessary\n\t\tif _, ok := namespaces[v.namespaceName]; !ok {\n\t\t\tnamespaces[v.namespaceName] = &namespaceMock{\n\t\t\t\tnamespaceName: v.namespaceName,\n\t\t\t}\n\t\t}\n\n\t\tinterfaces = append(\n\t\t\tinterfaces,\n\t\t\tnamespacedInterface{\n\t\t\t\tInterface: iface,\n\t\t\t\tnamespace: namespaces[v.namespaceName],\n\t\t\t},\n\t\t)\n\t}\n\treturn interfaces, nil\n}\n\nfunc (c *commandEthtoolMock) stats(intf namespacedInterface) (map[string]uint64, error) {\n\ti := c.interfaceMap[intf.Name]\n\tif i != nil {\n\t\treturn i.stat, nil\n\t}\n\treturn nil, errors.New(\"interface not found\")\n}\n\nfunc (c *commandEthtoolMock) get(intf namespacedInterface) (map[string]uint64, error) {\n\ti := c.interfaceMap[intf.Name]\n\tif i != nil {\n\t\treturn i.cmdGet, nil\n\t}\n\treturn nil, errors.New(\"interface not found\")\n}\n\nfunc setup() {\n\tinterfaceMap = make(map[string]*interfaceMock)\n\n\teth1Stat := map[string]uint64{\n\t\t\"interface_up\":                   1,\n\t\t\"port_rx_1024_to_15xx\":           25167245,\n\t\t\"port_rx_128_to_255\":             1573526387,\n\t\t\"port_rx_15xx_to_jumbo\":          137819058,\n\t\t\"port_rx_256_to_511\":             772038107,\n\t\t\"port_rx_512_to_1023\":            78294457,\n\t\t\"port_rx_64\":                     8798065,\n\t\t\"port_rx_65_to_127\":              450348015,\n\t\t\"port_rx_bad\":                    0,\n\t\t\"port_rx_bad_bytes\":              0,\n\t\t\"port_rx_bad_gtjumbo\":            0,\n\t\t\"port_rx_broadcast\":              6428250,\n\t\t\"port_rx_bytes\":                  893460472634,\n\t\t\"port_rx_control\":                0,\n\t\t\"port_rx_dp_di_dropped_packets\":  2772680304,\n\t\t\"port_rx_dp_hlb_fetch\":           0,\n\t\t\"port_rx_dp_hlb_wait\":            0,\n\t\t\"port_rx_dp_q_disabled_packets\":  0,\n\t\t\"port_rx_dp_streaming_packets\":   0,\n\t\t\"port_rx_good\":                   3045991334,\n\t\t\"port_rx_good_bytes\":             893460472927,\n\t\t\"port_rx_gtjumbo\":                0,\n\t\t\"port_rx_lt64\":                   0,\n\t\t\"port_rx_multicast\":              1639566045,\n\t\t\"port_rx_nodesc_drops\":           0,\n\t\t\"port_rx_overflow\":               0,\n\t\t\"port_rx_packets\":                3045991334,\n\t\t\"port_rx_pause\":                  0,\n\t\t\"port_rx_pm_discard_bb_overflow\": 0,\n\t\t\"port_rx_pm_discard_mapping\":     0,\n\t\t\"port_rx_pm_discard_qbb\":         0,\n\t\t\"port_rx_pm_discard_vfifo_full\":  0,\n\t\t\"port_rx_pm_trunc_bb_overflow\":   0,\n\t\t\"port_rx_pm_trunc_qbb\":           0,\n\t\t\"port_rx_pm_trunc_vfifo_full\":    0,\n\t\t\"port_rx_unicast\":                1399997040,\n\t\t\"port_tx_1024_to_15xx\":           236,\n\t\t\"port_tx_128_to_255\":             275090219,\n\t\t\"port_tx_15xx_to_jumbo\":          926,\n\t\t\"port_tx_256_to_511\":             48567221,\n\t\t\"port_tx_512_to_1023\":            5142016,\n\t\t\"port_tx_64\":                     113903973,\n\t\t\"port_tx_65_to_127\":              161935699,\n\t\t\"port_tx_broadcast\":              8,\n\t\t\"port_tx_bytes\":                  94357131016,\n\t\t\"port_tx_control\":                0,\n\t\t\"port_tx_lt64\":                   0,\n\t\t\"port_tx_multicast\":              325891647,\n\t\t\"port_tx_packets\":                604640290,\n\t\t\"port_tx_pause\":                  0,\n\t\t\"port_tx_unicast\":                278748635,\n\t\t\"ptp_bad_syncs\":                  1,\n\t\t\"ptp_fast_syncs\":                 1,\n\t\t\"ptp_filter_matches\":             0,\n\t\t\"ptp_good_syncs\":                 136151,\n\t\t\"ptp_invalid_sync_windows\":       0,\n\t\t\"ptp_no_time_syncs\":              1,\n\t\t\"ptp_non_filter_matches\":         0,\n\t\t\"ptp_oversize_sync_windows\":      53,\n\t\t\"ptp_rx_no_timestamp\":            0,\n\t\t\"ptp_rx_timestamp_packets\":       0,\n\t\t\"ptp_sync_timeouts\":              1,\n\t\t\"ptp_timestamp_packets\":          0,\n\t\t\"ptp_tx_timestamp_packets\":       0,\n\t\t\"ptp_undersize_sync_windows\":     3,\n\t\t\"rx-0.rx_packets\":                55659234,\n\t\t\"rx-1.rx_packets\":                87880538,\n\t\t\"rx-2.rx_packets\":                26746234,\n\t\t\"rx-3.rx_packets\":                103026471,\n\t\t\"rx-4.rx_packets\":                0,\n\t\t\"rx_eth_crc_err\":                 0,\n\t\t\"rx_frm_trunc\":                   0,\n\t\t\"rx_inner_ip_hdr_chksum_err\":     0,\n\t\t\"rx_inner_tcp_udp_chksum_err\":    0,\n\t\t\"rx_ip_hdr_chksum_err\":           0,\n\t\t\"rx_mcast_mismatch\":              0,\n\t\t\"rx_merge_events\":                0,\n\t\t\"rx_merge_packets\":               0,\n\t\t\"rx_nodesc_trunc\":                0,\n\t\t\"rx_noskb_drops\":                 0,\n\t\t\"rx_outer_ip_hdr_chksum_err\":     0,\n\t\t\"rx_outer_tcp_udp_chksum_err\":    0,\n\t\t\"rx_reset\":                       0,\n\t\t\"rx_tcp_udp_chksum_err\":          0,\n\t\t\"rx_tobe_disc\":                   0,\n\t\t\"tx-0.tx_packets\":                85843565,\n\t\t\"tx-1.tx_packets\":                108642725,\n\t\t\"tx-2.tx_packets\":                202596078,\n\t\t\"tx-3.tx_packets\":                207561010,\n\t\t\"tx-4.tx_packets\":                0,\n\t\t\"tx_cb_packets\":                  4,\n\t\t\"tx_merge_events\":                11025,\n\t\t\"tx_pio_packets\":                 531928114,\n\t\t\"tx_pushes\":                      604643378,\n\t\t\"tx_tso_bursts\":                  0,\n\t\t\"tx_tso_fallbacks\":               0,\n\t\t\"tx_tso_long_headers\":            0,\n\t}\n\teth1Get := map[string]uint64{\n\t\t\"autoneg\": 1,\n\t\t\"duplex\":  1,\n\t\t\"link\":    1,\n\t\t\"speed\":   1000,\n\t}\n\teth1 := &interfaceMock{\"eth1\", \"driver1\", \"\", eth1Stat, false, true, eth1Get}\n\tinterfaceMap[eth1.name] = eth1\n\n\teth2Stat := map[string]uint64{\n\t\t\"interface_up\":                   0,\n\t\t\"port_rx_1024_to_15xx\":           11529312,\n\t\t\"port_rx_128_to_255\":             1868952037,\n\t\t\"port_rx_15xx_to_jumbo\":          130339387,\n\t\t\"port_rx_256_to_511\":             843846270,\n\t\t\"port_rx_512_to_1023\":            173194372,\n\t\t\"port_rx_64\":                     9190374,\n\t\t\"port_rx_65_to_127\":              507806115,\n\t\t\"port_rx_bad\":                    0,\n\t\t\"port_rx_bad_bytes\":              0,\n\t\t\"port_rx_bad_gtjumbo\":            0,\n\t\t\"port_rx_broadcast\":              6648019,\n\t\t\"port_rx_bytes\":                  1007358162202,\n\t\t\"port_rx_control\":                0,\n\t\t\"port_rx_dp_di_dropped_packets\":  3164124639,\n\t\t\"port_rx_dp_hlb_fetch\":           0,\n\t\t\"port_rx_dp_hlb_wait\":            0,\n\t\t\"port_rx_dp_q_disabled_packets\":  0,\n\t\t\"port_rx_dp_streaming_packets\":   0,\n\t\t\"port_rx_good\":                   3544857867,\n\t\t\"port_rx_good_bytes\":             1007358162202,\n\t\t\"port_rx_gtjumbo\":                0,\n\t\t\"port_rx_lt64\":                   0,\n\t\t\"port_rx_multicast\":              2231999743,\n\t\t\"port_rx_nodesc_drops\":           0,\n\t\t\"port_rx_overflow\":               0,\n\t\t\"port_rx_packets\":                3544857867,\n\t\t\"port_rx_pause\":                  0,\n\t\t\"port_rx_pm_discard_bb_overflow\": 0,\n\t\t\"port_rx_pm_discard_mapping\":     0,\n\t\t\"port_rx_pm_discard_qbb\":         0,\n\t\t\"port_rx_pm_discard_vfifo_full\":  0,\n\t\t\"port_rx_pm_trunc_bb_overflow\":   0,\n\t\t\"port_rx_pm_trunc_qbb\":           0,\n\t\t\"port_rx_pm_trunc_vfifo_full\":    0,\n\t\t\"port_rx_unicast\":                1306210105,\n\t\t\"port_tx_1024_to_15xx\":           379,\n\t\t\"port_tx_128_to_255\":             202767251,\n\t\t\"port_tx_15xx_to_jumbo\":          558,\n\t\t\"port_tx_256_to_511\":             31454719,\n\t\t\"port_tx_512_to_1023\":            6865731,\n\t\t\"port_tx_64\":                     17268276,\n\t\t\"port_tx_65_to_127\":              272816313,\n\t\t\"port_tx_broadcast\":              6,\n\t\t\"port_tx_bytes\":                  78071946593,\n\t\t\"port_tx_control\":                0,\n\t\t\"port_tx_lt64\":                   0,\n\t\t\"port_tx_multicast\":              239510586,\n\t\t\"port_tx_packets\":                531173227,\n\t\t\"port_tx_pause\":                  0,\n\t\t\"port_tx_unicast\":                291662635,\n\t\t\"ptp_bad_syncs\":                  0,\n\t\t\"ptp_fast_syncs\":                 0,\n\t\t\"ptp_filter_matches\":             0,\n\t\t\"ptp_good_syncs\":                 0,\n\t\t\"ptp_invalid_sync_windows\":       0,\n\t\t\"ptp_no_time_syncs\":              0,\n\t\t\"ptp_non_filter_matches\":         0,\n\t\t\"ptp_oversize_sync_windows\":      0,\n\t\t\"ptp_rx_no_timestamp\":            0,\n\t\t\"ptp_rx_timestamp_packets\":       0,\n\t\t\"ptp_sync_timeouts\":              0,\n\t\t\"ptp_timestamp_packets\":          0,\n\t\t\"ptp_tx_timestamp_packets\":       0,\n\t\t\"ptp_undersize_sync_windows\":     0,\n\t\t\"rx-0.rx_packets\":                84587075,\n\t\t\"rx-1.rx_packets\":                74029305,\n\t\t\"rx-2.rx_packets\":                134586471,\n\t\t\"rx-3.rx_packets\":                87531322,\n\t\t\"rx-4.rx_packets\":                0,\n\t\t\"rx_eth_crc_err\":                 0,\n\t\t\"rx_frm_trunc\":                   0,\n\t\t\"rx_inner_ip_hdr_chksum_err\":     0,\n\t\t\"rx_inner_tcp_udp_chksum_err\":    0,\n\t\t\"rx_ip_hdr_chksum_err\":           0,\n\t\t\"rx_mcast_mismatch\":              0,\n\t\t\"rx_merge_events\":                0,\n\t\t\"rx_merge_packets\":               0,\n\t\t\"rx_nodesc_trunc\":                0,\n\t\t\"rx_noskb_drops\":                 0,\n\t\t\"rx_outer_ip_hdr_chksum_err\":     0,\n\t\t\"rx_outer_tcp_udp_chksum_err\":    0,\n\t\t\"rx_reset\":                       0,\n\t\t\"rx_tcp_udp_chksum_err\":          0,\n\t\t\"rx_tobe_disc\":                   0,\n\t\t\"tx-0.tx_packets\":                232521451,\n\t\t\"tx-1.tx_packets\":                97876137,\n\t\t\"tx-2.tx_packets\":                106822111,\n\t\t\"tx-3.tx_packets\":                93955050,\n\t\t\"tx-4.tx_packets\":                0,\n\t\t\"tx_cb_packets\":                  1,\n\t\t\"tx_merge_events\":                8402,\n\t\t\"tx_pio_packets\":                 481040054,\n\t\t\"tx_pushes\":                      531174491,\n\t\t\"tx_tso_bursts\":                  128,\n\t\t\"tx_tso_fallbacks\":               0,\n\t\t\"tx_tso_long_headers\":            0,\n\t}\n\teth2Get := map[string]uint64{\n\t\t\"autoneg\": 0,\n\t\t\"duplex\":  255,\n\t\t\"link\":    0,\n\t\t\"speed\":   9223372036854775807,\n\t}\n\teth2 := &interfaceMock{\"eth2\", \"driver1\", \"\", eth2Stat, false, false, eth2Get}\n\tinterfaceMap[eth2.name] = eth2\n\n\teth3Stat := map[string]uint64{\n\t\t\"interface_up\":                   1,\n\t\t\"port_rx_1024_to_15xx\":           25167245,\n\t\t\"port_rx_128_to_255\":             1573526387,\n\t\t\"port_rx_15xx_to_jumbo\":          137819058,\n\t\t\"port_rx_256_to_511\":             772038107,\n\t\t\"port_rx_512_to_1023\":            78294457,\n\t\t\"port_rx_64\":                     8798065,\n\t\t\"port_rx_65_to_127\":              450348015,\n\t\t\"port_rx_bad\":                    0,\n\t\t\"port_rx_bad_bytes\":              0,\n\t\t\"port_rx_bad_gtjumbo\":            0,\n\t\t\"port_rx_broadcast\":              6428250,\n\t\t\"port_rx_bytes\":                  893460472634,\n\t\t\"port_rx_control\":                0,\n\t\t\"port_rx_dp_di_dropped_packets\":  2772680304,\n\t\t\"port_rx_dp_hlb_fetch\":           0,\n\t\t\"port_rx_dp_hlb_wait\":            0,\n\t\t\"port_rx_dp_q_disabled_packets\":  0,\n\t\t\"port_rx_dp_streaming_packets\":   0,\n\t\t\"port_rx_good\":                   3045991334,\n\t\t\"port_rx_good_bytes\":             893460472927,\n\t\t\"port_rx_gtjumbo\":                0,\n\t\t\"port_rx_lt64\":                   0,\n\t\t\"port_rx_multicast\":              1639566045,\n\t\t\"port_rx_nodesc_drops\":           0,\n\t\t\"port_rx_overflow\":               0,\n\t\t\"port_rx_packets\":                3045991334,\n\t\t\"port_rx_pause\":                  0,\n\t\t\"port_rx_pm_discard_bb_overflow\": 0,\n\t\t\"port_rx_pm_discard_mapping\":     0,\n\t\t\"port_rx_pm_discard_qbb\":         0,\n\t\t\"port_rx_pm_discard_vfifo_full\":  0,\n\t\t\"port_rx_pm_trunc_bb_overflow\":   0,\n\t\t\"port_rx_pm_trunc_qbb\":           0,\n\t\t\"port_rx_pm_trunc_vfifo_full\":    0,\n\t\t\"port_rx_unicast\":                1399997040,\n\t\t\"port_tx_1024_to_15xx\":           236,\n\t\t\"port_tx_128_to_255\":             275090219,\n\t\t\"port_tx_15xx_to_jumbo\":          926,\n\t\t\"port_tx_256_to_511\":             48567221,\n\t\t\"port_tx_512_to_1023\":            5142016,\n\t\t\"port_tx_64\":                     113903973,\n\t\t\"port_tx_65_to_127\":              161935699,\n\t\t\"port_tx_broadcast\":              8,\n\t\t\"port_tx_bytes\":                  94357131016,\n\t\t\"port_tx_control\":                0,\n\t\t\"port_tx_lt64\":                   0,\n\t\t\"port_tx_multicast\":              325891647,\n\t\t\"port_tx_packets\":                604640290,\n\t\t\"port_tx_pause\":                  0,\n\t\t\"port_tx_unicast\":                278748635,\n\t\t\"ptp_bad_syncs\":                  1,\n\t\t\"ptp_fast_syncs\":                 1,\n\t\t\"ptp_filter_matches\":             0,\n\t\t\"ptp_good_syncs\":                 136151,\n\t\t\"ptp_invalid_sync_windows\":       0,\n\t\t\"ptp_no_time_syncs\":              1,\n\t\t\"ptp_non_filter_matches\":         0,\n\t\t\"ptp_oversize_sync_windows\":      53,\n\t\t\"ptp_rx_no_timestamp\":            0,\n\t\t\"ptp_rx_timestamp_packets\":       0,\n\t\t\"ptp_sync_timeouts\":              1,\n\t\t\"ptp_timestamp_packets\":          0,\n\t\t\"ptp_tx_timestamp_packets\":       0,\n\t\t\"ptp_undersize_sync_windows\":     3,\n\t\t\"rx-0.rx_packets\":                55659234,\n\t\t\"rx-1.rx_packets\":                87880538,\n\t\t\"rx-2.rx_packets\":                26746234,\n\t\t\"rx-3.rx_packets\":                103026471,\n\t\t\"rx-4.rx_packets\":                0,\n\t\t\"rx_eth_crc_err\":                 0,\n\t\t\"rx_frm_trunc\":                   0,\n\t\t\"rx_inner_ip_hdr_chksum_err\":     0,\n\t\t\"rx_inner_tcp_udp_chksum_err\":    0,\n\t\t\"rx_ip_hdr_chksum_err\":           0,\n\t\t\"rx_mcast_mismatch\":              0,\n\t\t\"rx_merge_events\":                0,\n\t\t\"rx_merge_packets\":               0,\n\t\t\"rx_nodesc_trunc\":                0,\n\t\t\"rx_noskb_drops\":                 0,\n\t\t\"rx_outer_ip_hdr_chksum_err\":     0,\n\t\t\"rx_outer_tcp_udp_chksum_err\":    0,\n\t\t\"rx_reset\":                       0,\n\t\t\"rx_tcp_udp_chksum_err\":          0,\n\t\t\"rx_tobe_disc\":                   0,\n\t\t\"tx-0.tx_packets\":                85843565,\n\t\t\"tx-1.tx_packets\":                108642725,\n\t\t\"tx-2.tx_packets\":                202596078,\n\t\t\"tx-3.tx_packets\":                207561010,\n\t\t\"tx-4.tx_packets\":                0,\n\t\t\"tx_cb_packets\":                  4,\n\t\t\"tx_merge_events\":                11025,\n\t\t\"tx_pio_packets\":                 531928114,\n\t\t\"tx_pushes\":                      604643378,\n\t\t\"tx_tso_bursts\":                  0,\n\t\t\"tx_tso_fallbacks\":               0,\n\t\t\"tx_tso_long_headers\":            0,\n\t}\n\teth3Get := map[string]uint64{\n\t\t\"autoneg\": 1,\n\t\t\"duplex\":  1,\n\t\t\"link\":    1,\n\t\t\"speed\":   1000,\n\t}\n\teth3 := &interfaceMock{\"eth3\", \"driver1\", \"namespace1\", eth3Stat, false, true, eth3Get}\n\tinterfaceMap[eth3.name] = eth3\n\n\teth4Stat := map[string]uint64{\n\t\t\"interface_up\":                   1,\n\t\t\"port_rx_1024_to_15xx\":           25167245,\n\t\t\"port_rx_128_to_255\":             1573526387,\n\t\t\"port_rx_15xx_to_jumbo\":          137819058,\n\t\t\"port_rx_256_to_511\":             772038107,\n\t\t\"port_rx_512_to_1023\":            78294457,\n\t\t\"port_rx_64\":                     8798065,\n\t\t\"port_rx_65_to_127\":              450348015,\n\t\t\"port_rx_bad\":                    0,\n\t\t\"port_rx_bad_bytes\":              0,\n\t\t\"port_rx_bad_gtjumbo\":            0,\n\t\t\"port_rx_broadcast\":              6428250,\n\t\t\"port_rx_bytes\":                  893460472634,\n\t\t\"port_rx_control\":                0,\n\t\t\"port_rx_dp_di_dropped_packets\":  2772680304,\n\t\t\"port_rx_dp_hlb_fetch\":           0,\n\t\t\"port_rx_dp_hlb_wait\":            0,\n\t\t\"port_rx_dp_q_disabled_packets\":  0,\n\t\t\"port_rx_dp_streaming_packets\":   0,\n\t\t\"port_rx_good\":                   3045991334,\n\t\t\"port_rx_good_bytes\":             893460472927,\n\t\t\"port_rx_gtjumbo\":                0,\n\t\t\"port_rx_lt64\":                   0,\n\t\t\"port_rx_multicast\":              1639566045,\n\t\t\"port_rx_nodesc_drops\":           0,\n\t\t\"port_rx_overflow\":               0,\n\t\t\"port_rx_packets\":                3045991334,\n\t\t\"port_rx_pause\":                  0,\n\t\t\"port_rx_pm_discard_bb_overflow\": 0,\n\t\t\"port_rx_pm_discard_mapping\":     0,\n\t\t\"port_rx_pm_discard_qbb\":         0,\n\t\t\"port_rx_pm_discard_vfifo_full\":  0,\n\t\t\"port_rx_pm_trunc_bb_overflow\":   0,\n\t\t\"port_rx_pm_trunc_qbb\":           0,\n\t\t\"port_rx_pm_trunc_vfifo_full\":    0,\n\t\t\"port_rx_unicast\":                1399997040,\n\t\t\"port_tx_1024_to_15xx\":           236,\n\t\t\"port_tx_128_to_255\":             275090219,\n\t\t\"port_tx_15xx_to_jumbo\":          926,\n\t\t\"port_tx_256_to_511\":             48567221,\n\t\t\"port_tx_512_to_1023\":            5142016,\n\t\t\"port_tx_64\":                     113903973,\n\t\t\"port_tx_65_to_127\":              161935699,\n\t\t\"port_tx_broadcast\":              8,\n\t\t\"port_tx_bytes\":                  94357131016,\n\t\t\"port_tx_control\":                0,\n\t\t\"port_tx_lt64\":                   0,\n\t\t\"port_tx_multicast\":              325891647,\n\t\t\"port_tx_packets\":                604640290,\n\t\t\"port_tx_pause\":                  0,\n\t\t\"port_tx_unicast\":                278748635,\n\t\t\"ptp_bad_syncs\":                  1,\n\t\t\"ptp_fast_syncs\":                 1,\n\t\t\"ptp_filter_matches\":             0,\n\t\t\"ptp_good_syncs\":                 136151,\n\t\t\"ptp_invalid_sync_windows\":       0,\n\t\t\"ptp_no_time_syncs\":              1,\n\t\t\"ptp_non_filter_matches\":         0,\n\t\t\"ptp_oversize_sync_windows\":      53,\n\t\t\"ptp_rx_no_timestamp\":            0,\n\t\t\"ptp_rx_timestamp_packets\":       0,\n\t\t\"ptp_sync_timeouts\":              1,\n\t\t\"ptp_timestamp_packets\":          0,\n\t\t\"ptp_tx_timestamp_packets\":       0,\n\t\t\"ptp_undersize_sync_windows\":     3,\n\t\t\"rx-0.rx_packets\":                55659234,\n\t\t\"rx-1.rx_packets\":                87880538,\n\t\t\"rx-2.rx_packets\":                26746234,\n\t\t\"rx-3.rx_packets\":                103026471,\n\t\t\"rx-4.rx_packets\":                0,\n\t\t\"rx_eth_crc_err\":                 0,\n\t\t\"rx_frm_trunc\":                   0,\n\t\t\"rx_inner_ip_hdr_chksum_err\":     0,\n\t\t\"rx_inner_tcp_udp_chksum_err\":    0,\n\t\t\"rx_ip_hdr_chksum_err\":           0,\n\t\t\"rx_mcast_mismatch\":              0,\n\t\t\"rx_merge_events\":                0,\n\t\t\"rx_merge_packets\":               0,\n\t\t\"rx_nodesc_trunc\":                0,\n\t\t\"rx_noskb_drops\":                 0,\n\t\t\"rx_outer_ip_hdr_chksum_err\":     0,\n\t\t\"rx_outer_tcp_udp_chksum_err\":    0,\n\t\t\"rx_reset\":                       0,\n\t\t\"rx_tcp_udp_chksum_err\":          0,\n\t\t\"rx_tobe_disc\":                   0,\n\t\t\"tx-0.tx_packets\":                85843565,\n\t\t\"tx-1.tx_packets\":                108642725,\n\t\t\"tx-2.tx_packets\":                202596078,\n\t\t\"tx-3.tx_packets\":                207561010,\n\t\t\"tx-4.tx_packets\":                0,\n\t\t\"tx_cb_packets\":                  4,\n\t\t\"tx_merge_events\":                11025,\n\t\t\"tx_pio_packets\":                 531928114,\n\t\t\"tx_pushes\":                      604643378,\n\t\t\"tx_tso_bursts\":                  0,\n\t\t\"tx_tso_fallbacks\":               0,\n\t\t\"tx_tso_long_headers\":            0,\n\t}\n\teth4Get := map[string]uint64{\n\t\t\"autoneg\": 1,\n\t\t\"duplex\":  1,\n\t\t\"link\":    1,\n\t\t\"speed\":   100,\n\t}\n\teth4 := &interfaceMock{\"eth4\", \"driver1\", \"namespace2\", eth4Stat, false, true, eth4Get}\n\tinterfaceMap[eth4.name] = eth4\n\n\t// dummy loopback including dummy stat to ensure that the ignore feature is working\n\tlo0Stat := map[string]uint64{\n\t\t\"dummy\": 0,\n\t}\n\tlo0Get := map[string]uint64{\n\t\t\"autoneg\": 1,\n\t\t\"duplex\":  1,\n\t\t\"link\":    1,\n\t\t\"speed\":   1000,\n\t}\n\tlo0 := &interfaceMock{\"lo0\", \"\", \"\", lo0Stat, true, true, lo0Get}\n\tinterfaceMap[lo0.name] = lo0\n\n\tc := &commandEthtoolMock{interfaceMap}\n\teth = &Ethtool{\n\t\tDownInterfaces: \"expose\",\n\t\tcommand:        c,\n\t}\n}\n\nfunc toStringMapInterface(in map[string]uint64) map[string]interface{} {\n\tm := map[string]interface{}{}\n\tfor k, v := range in {\n\t\tm[k] = v\n\t}\n\treturn m\n}\n\nfunc toStringMapUint(in map[string]interface{}) map[string]uint64 {\n\tm := map[string]uint64{}\n\tfor k, v := range in {\n\t\tt := v.(uint64)\n\t\tm[k] = t\n\t}\n\treturn m\n}\n\nfunc TestGather(t *testing.T) {\n\tsetup()\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 2)\n\n\texpectedFieldsEth1 := toStringMapInterface(interfaceMap[\"eth1\"].stat)\n\tfor k, v := range interfaceMap[\"eth1\"].cmdGet {\n\t\texpectedFieldsEth1[k] = v\n\t}\n\texpectedFieldsEth1[\"interface_up_counter\"] = expectedFieldsEth1[\"interface_up\"]\n\texpectedFieldsEth1[\"interface_up\"] = true\n\n\texpectedTagsEth1 := map[string]string{\n\t\t\"interface\": \"eth1\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)\n\n\texpectedFieldsEth2 := toStringMapInterface(interfaceMap[\"eth2\"].stat)\n\tfor k, v := range interfaceMap[\"eth2\"].cmdGet {\n\t\texpectedFieldsEth2[k] = v\n\t}\n\texpectedFieldsEth2[\"interface_up_counter\"] = expectedFieldsEth2[\"interface_up\"]\n\texpectedFieldsEth2[\"interface_up\"] = false\n\texpectedTagsEth2 := map[string]string{\n\t\t\"driver\":    \"driver1\",\n\t\t\"interface\": \"eth2\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)\n}\n\nfunc TestGatherIncludeInterfaces(t *testing.T) {\n\tsetup()\n\n\teth.InterfaceInclude = append(eth.InterfaceInclude, \"eth1\")\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// Should contain eth1\n\texpectedFieldsEth1 := toStringMapInterface(interfaceMap[\"eth1\"].stat)\n\tfor k, v := range interfaceMap[\"eth1\"].cmdGet {\n\t\texpectedFieldsEth1[k] = v\n\t}\n\texpectedFieldsEth1[\"interface_up_counter\"] = expectedFieldsEth1[\"interface_up\"]\n\texpectedFieldsEth1[\"interface_up\"] = true\n\texpectedTagsEth1 := map[string]string{\n\t\t\"interface\": \"eth1\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)\n\n\t// Should not contain eth2\n\texpectedFieldsEth2 := toStringMapInterface(interfaceMap[\"eth2\"].stat)\n\tfor k, v := range interfaceMap[\"eth2\"].cmdGet {\n\t\texpectedFieldsEth2[k] = v\n\t}\n\texpectedFieldsEth2[\"interface_up_counter\"] = expectedFieldsEth2[\"interface_up\"]\n\texpectedFieldsEth2[\"interface_up\"] = false\n\texpectedTagsEth2 := map[string]string{\n\t\t\"interface\": \"eth2\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)\n}\n\nfunc TestGatherIgnoreInterfaces(t *testing.T) {\n\tsetup()\n\n\teth.InterfaceExclude = append(eth.InterfaceExclude, \"eth1\")\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// Should not contain eth1\n\texpectedFieldsEth1 := toStringMapInterface(interfaceMap[\"eth1\"].stat)\n\tfor k, v := range interfaceMap[\"eth1\"].cmdGet {\n\t\texpectedFieldsEth1[k] = v\n\t}\n\texpectedFieldsEth1[\"interface_up_counter\"] = expectedFieldsEth1[\"interface_up\"]\n\texpectedFieldsEth1[\"interface_up\"] = true\n\texpectedTagsEth1 := map[string]string{\n\t\t\"interface\": \"eth1\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)\n\n\t// Should contain eth2\n\texpectedFieldsEth2 := toStringMapInterface(interfaceMap[\"eth2\"].stat)\n\tfor k, v := range interfaceMap[\"eth2\"].cmdGet {\n\t\texpectedFieldsEth2[k] = v\n\t}\n\texpectedFieldsEth2[\"interface_up_counter\"] = expectedFieldsEth2[\"interface_up\"]\n\texpectedFieldsEth2[\"interface_up\"] = false\n\texpectedTagsEth2 := map[string]string{\n\t\t\"interface\": \"eth2\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)\n}\n\nfunc TestSkipMetricsForInterfaceDown(t *testing.T) {\n\tsetup()\n\n\teth.DownInterfaces = \"skip\"\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 1)\n\n\texpectedFieldsEth1 := toStringMapInterface(interfaceMap[\"eth1\"].stat)\n\tfor k, v := range interfaceMap[\"eth1\"].cmdGet {\n\t\texpectedFieldsEth1[k] = v\n\t}\n\texpectedFieldsEth1[\"interface_up_counter\"] = expectedFieldsEth1[\"interface_up\"]\n\texpectedFieldsEth1[\"interface_up\"] = true\n\n\texpectedTagsEth1 := map[string]string{\n\t\t\"interface\": \"eth1\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)\n}\n\nfunc TestGatherIncludeNamespaces(t *testing.T) {\n\tsetup()\n\tvar acc testutil.Accumulator\n\n\teth.NamespaceInclude = append(eth.NamespaceInclude, \"namespace1\")\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// Should contain eth3\n\texpectedFieldsEth3 := toStringMapInterface(interfaceMap[\"eth3\"].stat)\n\tfor k, v := range interfaceMap[\"eth3\"].cmdGet {\n\t\texpectedFieldsEth3[k] = v\n\t}\n\texpectedFieldsEth3[\"interface_up_counter\"] = expectedFieldsEth3[\"interface_up\"]\n\texpectedFieldsEth3[\"interface_up\"] = true\n\texpectedTagsEth3 := map[string]string{\n\t\t\"interface\": \"eth3\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"namespace1\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth3, expectedTagsEth3)\n\n\t// Should not contain eth2\n\texpectedFieldsEth2 := toStringMapInterface(interfaceMap[\"eth2\"].stat)\n\tfor k, v := range interfaceMap[\"eth2\"].cmdGet {\n\t\texpectedFieldsEth2[k] = v\n\t}\n\texpectedFieldsEth2[\"interface_up_counter\"] = expectedFieldsEth2[\"interface_up\"]\n\texpectedFieldsEth2[\"interface_up\"] = false\n\texpectedTagsEth2 := map[string]string{\n\t\t\"interface\": \"eth2\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)\n}\n\nfunc TestGatherIgnoreNamespaces(t *testing.T) {\n\tsetup()\n\tvar acc testutil.Accumulator\n\n\teth.NamespaceExclude = append(eth.NamespaceExclude, \"namespace2\")\n\n\terr := eth.Init()\n\trequire.NoError(t, err)\n\n\terr = eth.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 3)\n\n\t// Should not contain eth4\n\texpectedFieldsEth4 := toStringMapInterface(interfaceMap[\"eth4\"].stat)\n\tfor k, v := range interfaceMap[\"eth4\"].cmdGet {\n\t\texpectedFieldsEth4[k] = v\n\t}\n\texpectedFieldsEth4[\"interface_up_counter\"] = expectedFieldsEth4[\"interface_up\"]\n\texpectedFieldsEth4[\"interface_up\"] = true\n\texpectedTagsEth4 := map[string]string{\n\t\t\"interface\": \"eth4\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"namespace2\",\n\t}\n\tacc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth4, expectedTagsEth4)\n\n\t// Should contain eth2\n\texpectedFieldsEth2 := toStringMapInterface(interfaceMap[\"eth2\"].stat)\n\tfor k, v := range interfaceMap[\"eth2\"].cmdGet {\n\t\texpectedFieldsEth2[k] = v\n\t}\n\texpectedFieldsEth2[\"interface_up_counter\"] = expectedFieldsEth2[\"interface_up\"]\n\texpectedFieldsEth2[\"interface_up\"] = false\n\texpectedTagsEth2 := map[string]string{\n\t\t\"interface\": \"eth2\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)\n\n\t// Should contain eth3\n\texpectedFieldsEth3 := toStringMapInterface(interfaceMap[\"eth3\"].stat)\n\tfor k, v := range interfaceMap[\"eth3\"].cmdGet {\n\t\texpectedFieldsEth3[k] = v\n\t}\n\texpectedFieldsEth3[\"interface_up_counter\"] = expectedFieldsEth3[\"interface_up\"]\n\texpectedFieldsEth3[\"interface_up\"] = true\n\texpectedTagsEth3 := map[string]string{\n\t\t\"interface\": \"eth3\",\n\t\t\"driver\":    \"driver1\",\n\t\t\"namespace\": \"namespace1\",\n\t}\n\tacc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth3, expectedTagsEth3)\n}\n\ntype testCase struct {\n\tnormalization  []string\n\tstats          map[string]interface{}\n\texpectedFields map[string]interface{}\n}\n\nfunc TestNormalizedKeys(t *testing.T) {\n\tcases := []testCase{\n\t\t{\n\t\t\tnormalization: []string{\"underscore\"},\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"port rx\":      uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"port_rx\":              uint64(1),\n\t\t\t\t\"_Port_tx\":             uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tnormalization: []string{\"underscore\", \"lower\"},\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"Port rx\":      uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"port_rx\":              uint64(1),\n\t\t\t\t\"_port_tx\":             uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tnormalization: []string{\"underscore\", \"lower\", \"trim\"},\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"  Port RX \":   uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"port_rx\":              uint64(1),\n\t\t\t\t\"port_tx\":              uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tnormalization: []string{\"underscore\", \"lower\", \"snakecase\", \"trim\"},\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"  Port RX \":   uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"port_rx\":              uint64(1),\n\t\t\t\t\"port_tx\":              uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tnormalization: []string{\"snakecase\"},\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"  PortRX \":    uint64(1),\n\t\t\t\t\" PortTX\":      uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"port_rx\":              uint64(1),\n\t\t\t\t\"port_tx\":              uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"  Port RX \":   uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"  Port RX \":           uint64(1),\n\t\t\t\t\" Port_tx\":             uint64(0),\n\t\t\t\t\"interface_up\":         true,\n\t\t\t\t\"interface_up_counter\": uint64(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tstats: map[string]interface{}{\n\t\t\t\t\"  Port RX \": uint64(1),\n\t\t\t\t\" Port_tx\":   uint64(0),\n\t\t\t},\n\t\t\texpectedFields: map[string]interface{}{\n\t\t\t\t\"  Port RX \":   uint64(1),\n\t\t\t\t\" Port_tx\":     uint64(0),\n\t\t\t\t\"interface_up\": true,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\teth0 := &interfaceMock{\"eth0\", \"e1000e\", \"\", toStringMapUint(c.stats), false, true, map[string]uint64{}}\n\t\texpectedTags := map[string]string{\n\t\t\t\"interface\": eth0.name,\n\t\t\t\"driver\":    eth0.driverName,\n\t\t\t\"namespace\": \"\",\n\t\t}\n\n\t\tinterfaceMap = make(map[string]*interfaceMock)\n\t\tinterfaceMap[eth0.name] = eth0\n\n\t\tcmd := &commandEthtoolMock{interfaceMap}\n\t\teth = &Ethtool{\n\t\t\tNormalizeKeys: c.normalization,\n\t\t\tcommand:       cmd,\n\t\t}\n\n\t\terr := eth.Init()\n\t\trequire.NoError(t, err)\n\n\t\tvar acc testutil.Accumulator\n\t\terr = eth.Gather(&acc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, acc.Metrics, 1)\n\n\t\tacc.AssertContainsFields(t, pluginName, c.expectedFields)\n\t\tacc.AssertContainsTaggedFields(t, pluginName, c.expectedFields, expectedTags)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ethtool/namespace_linux.go",
    "content": "//go:build linux\n\npackage ethtool\n\nimport (\n\t\"math\"\n\t\"net\"\n\t\"runtime\"\n\n\t\"github.com/safchain/ethtool\"\n\t\"github.com/vishvananda/netns\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype namespace interface {\n\tname() string\n\tinterfaces() ([]namespacedInterface, error)\n\tdriverName(intf namespacedInterface) (string, error)\n\tstats(intf namespacedInterface) (map[string]uint64, error)\n\tget(intf namespacedInterface) (map[string]uint64, error)\n}\n\ntype namespacedInterface struct {\n\tnet.Interface\n\tnamespace namespace\n}\n\ntype namespacedAction struct {\n\tresult chan<- namespacedResult\n\tf      func(*namespaceGoroutine) (interface{}, error)\n}\n\ntype namespacedResult struct {\n\tresult interface{}\n\terr    error\n}\n\ntype namespaceGoroutine struct {\n\tnamespaceName string\n\thandle        netns.NsHandle\n\tethtoolClient *ethtool.Ethtool\n\tc             chan namespacedAction\n\tlog           telegraf.Logger\n}\n\nfunc (n *namespaceGoroutine) name() string {\n\treturn n.namespaceName\n}\n\nfunc (n *namespaceGoroutine) interfaces() ([]namespacedInterface, error) {\n\tinterfaces, err := n.do(func(n *namespaceGoroutine) (interface{}, error) {\n\t\tinterfaces, err := net.Interfaces()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnamespacedInterfaces := make([]namespacedInterface, 0, len(interfaces))\n\t\tfor _, iface := range interfaces {\n\t\t\tnamespacedInterfaces = append(\n\t\t\t\tnamespacedInterfaces,\n\t\t\t\tnamespacedInterface{\n\t\t\t\t\tInterface: iface,\n\t\t\t\t\tnamespace: n,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\treturn namespacedInterfaces, nil\n\t})\n\n\treturn interfaces.([]namespacedInterface), err\n}\n\nfunc (n *namespaceGoroutine) driverName(intf namespacedInterface) (string, error) {\n\tdriver, err := n.do(func(n *namespaceGoroutine) (interface{}, error) {\n\t\treturn n.ethtoolClient.DriverName(intf.Name)\n\t})\n\treturn driver.(string), err\n}\n\nfunc (n *namespaceGoroutine) stats(intf namespacedInterface) (map[string]uint64, error) {\n\tdriver, err := n.do(func(n *namespaceGoroutine) (interface{}, error) {\n\t\treturn n.ethtoolClient.Stats(intf.Name)\n\t})\n\treturn driver.(map[string]uint64), err\n}\n\nfunc (n *namespaceGoroutine) get(intf namespacedInterface) (map[string]uint64, error) {\n\tresult, err := n.do(func(n *namespaceGoroutine) (interface{}, error) {\n\t\tecmd := ethtool.EthtoolCmd{}\n\t\tspeed32, err := n.ethtoolClient.CmdGet(&ecmd, intf.Name)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar speed = uint64(speed32)\n\t\tif speed == math.MaxUint32 {\n\t\t\tspeed = math.MaxUint64\n\t\t}\n\n\t\tvar link32 uint32\n\t\tlink32, err = n.ethtoolClient.LinkState(intf.Name)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn map[string]uint64{\n\t\t\t\"speed\":   speed,\n\t\t\t\"duplex\":  uint64(ecmd.Duplex),\n\t\t\t\"autoneg\": uint64(ecmd.Autoneg),\n\t\t\t\"link\":    uint64(link32),\n\t\t}, nil\n\t})\n\n\tif result != nil {\n\t\treturn result.(map[string]uint64), err\n\t}\n\treturn nil, err\n}\n\n// start locks a goroutine to an OS thread and ties it to the namespace, then\n// loops for actions to run in the namespace.\nfunc (n *namespaceGoroutine) start() error {\n\tn.c = make(chan namespacedAction)\n\tstarted := make(chan error)\n\tgo func() {\n\t\t// We're going to hold this thread locked permanently. We're going to\n\t\t// do this for every namespace. This makes it very likely that the Go\n\t\t// runtime will spin up new threads to replace it. To avoid thread\n\t\t// leaks, we don't unlock when we're done and instead let this thread\n\t\t// die.\n\t\truntime.LockOSThread()\n\n\t\t// If this goroutine is for the initial namespace, we are already in\n\t\t// the correct namespace. Switching would require CAP_SYS_ADMIN, which\n\t\t// we may not have. Don't switch if the desired namespace matches the\n\t\t// current one.\n\t\tinitialNamespace, err := netns.Get()\n\t\tif err != nil {\n\t\t\tn.log.Errorf(\"Could not get initial namespace: %s\", err)\n\t\t\tstarted <- err\n\t\t\treturn\n\t\t}\n\t\tif !initialNamespace.Equal(n.handle) {\n\t\t\tif err := netns.Set(n.handle); err != nil {\n\t\t\t\tn.log.Errorf(\"Could not switch to namespace %q: %s\", n.namespaceName, err.Error())\n\t\t\t\tstarted <- err\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// Every namespace needs its own connection to ethtool\n\t\te, err := ethtool.NewEthtool()\n\t\tif err != nil {\n\t\t\tn.log.Errorf(\"Could not create ethtool client for namespace %q: %s\", n.namespaceName, err.Error())\n\t\t\tstarted <- err\n\t\t\treturn\n\t\t}\n\t\tn.ethtoolClient = e\n\t\tstarted <- nil\n\t\tfor command := range n.c {\n\t\t\tresult, err := command.f(n)\n\t\t\tcommand.result <- namespacedResult{\n\t\t\t\tresult: result,\n\t\t\t\terr:    err,\n\t\t\t}\n\t\t\tclose(command.result)\n\t\t}\n\t}()\n\treturn <-started\n}\n\n// do runs a function inside the OS thread tied to the namespace.\nfunc (n *namespaceGoroutine) do(f func(*namespaceGoroutine) (interface{}, error)) (interface{}, error) {\n\tresult := make(chan namespacedResult)\n\tn.c <- namespacedAction{\n\t\tresult: result,\n\t\tf:      f,\n\t}\n\tr := <-result\n\treturn r.result, r.err\n}\n"
  },
  {
    "path": "plugins/inputs/ethtool/sample.conf",
    "content": "# Returns ethtool statistics for given interfaces\n# This plugin ONLY supports Linux\n[[inputs.ethtool]]\n  ## List of interfaces to pull metrics for\n  # interface_include = [\"eth0\"]\n\n  ## List of interfaces to ignore when pulling metrics.\n  # interface_exclude = [\"eth1\"]\n\n  ## Plugin behavior for downed interfaces\n  ## Available choices:\n  ##   - expose: collect & report metrics for down interfaces\n  ##   - skip: ignore interfaces that are marked down\n  # down_interfaces = \"expose\"\n\n  ## Reading statistics from interfaces in additional namespaces is also\n  ## supported, so long as the namespaces are named (have a symlink in\n  ## /var/run/netns). The telegraf process will also need the CAP_SYS_ADMIN\n  ## permission.\n  ## By default, only the current namespace will be used. For additional\n  ## namespace support, at least one of `namespace_include` and\n  ## `namespace_exclude` must be provided.\n  ## To include all namespaces, set `namespace_include` to `[\"*\"]`.\n  ## The initial namespace (if anonymous) can be specified with the empty\n  ## string (\"\").\n\n  ## List of namespaces to pull metrics for\n  # namespace_include = []\n\n  ## List of namespace to ignore when pulling metrics.\n  # namespace_exclude = []\n\n  ## Some drivers declare statistics with extra whitespace, different spacing,\n  ## and mix cases. This list, when enabled, can be used to clean the keys.\n  ## Here are the current possible normalizations:\n  ##  * snakecase: converts fooBarBaz to foo_bar_baz\n  ##  * trim: removes leading and trailing whitespace\n  ##  * lower: changes all capitalized letters to lowercase\n  ##  * underscore: replaces spaces with underscores\n  # normalize_keys = [\"snakecase\", \"trim\", \"lower\", \"underscore\"]\n"
  },
  {
    "path": "plugins/inputs/eventhub_consumer/README.md",
    "content": "# Azure Event Hub Consumer Input Plugin\n\nThis plugin allows consuming messages from [Azure Event Hubs][eventhub] and\n[Azure IoT Hub][iothub] instances.\n\n⭐ Telegraf v1.14.0\n🏷️ iot, messaging\n💻 all\n\n[eventhub]: https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-about\n[iothub]: https://azure.microsoft.com/en-us/products/iot-hub\n\n## IoT Hub Setup\n\nThe main focus for development of this plugin is Azure IoT hub:\n\n1. Create an Azure IoT Hub by following any of the guides provided here: [Azure\n   IoT Hub](https://docs.microsoft.com/en-us/azure/iot-hub/)\n2. Create a device, for example a [simulated Raspberry\n   Pi](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-raspberry-pi-web-simulator-get-started)\n3. The connection string needed for the plugin is located under *Shared access\n   policies*, both the *iothubowner* and *service* policies should work\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Azure Event Hubs service input plugin\n[[inputs.eventhub_consumer]]\n  ## The default behavior is to create a new Event Hub client from environment variables.\n  ## This requires one of the following sets of environment variables to be set:\n  ##\n  ## 1) Expected Environment Variables:\n  ##    - \"EVENTHUB_CONNECTION_STRING\"\n  ##\n  ## 2) Expected Environment Variables:\n  ##    - \"EVENTHUB_NAMESPACE\"\n  ##    - \"EVENTHUB_NAME\"\n  ##    - \"EVENTHUB_KEY_NAME\"\n  ##    - \"EVENTHUB_KEY_VALUE\"\n\n  ## 3) Expected Environment Variables:\n  ##    - \"EVENTHUB_NAMESPACE\"\n  ##    - \"EVENTHUB_NAME\"\n  ##    - \"AZURE_TENANT_ID\"\n  ##    - \"AZURE_CLIENT_ID\"\n  ##    - \"AZURE_CLIENT_SECRET\"\n\n  ## Uncommenting the option below will create an Event Hub client based solely on the connection string.\n  ## This can either be the associated environment variable or hard coded directly.\n  ## If this option is uncommented, environment variables will be ignored.\n  ## Connection string should contain EventHubName (EntityPath)\n  # connection_string = \"\"\n\n  ## Set persistence directory to a valid folder to use a file persister instead of an in-memory persister\n  # persistence_dir = \"\"\n\n  ## Change the default consumer group\n  # consumer_group = \"\"\n\n  ## By default the event hub receives all messages present on the broker, alternative modes can be set below.\n  ## The timestamp should be in https://github.com/toml-lang/toml#offset-date-time format (RFC 3339).\n  ## The 3 options below only apply if no valid persister is read from memory or file (e.g. first run).\n  # from_timestamp =\n  # latest = true\n\n  ## Set a custom prefetch count for the receiver(s)\n  # prefetch_count = 1000\n\n  ## Add an epoch to the receiver(s)\n  # epoch = 0\n\n  ## Change to set a custom user agent, \"telegraf\" is used by default\n  # user_agent = \"telegraf\"\n\n  ## To consume from a specific partition, set the partition_ids option.\n  ## An empty array will result in receiving from all partitions.\n  # partition_ids = [\"0\",\"1\"]\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Set either option below to true to use a system property as timestamp.\n  ## You have the choice between EnqueuedTime and IoTHubEnqueuedTime.\n  ## It is recommended to use this setting when the data itself has no timestamp.\n  # enqueued_time_as_ts = true\n  # iot_hub_enqueued_time_as_ts = true\n\n  ## Tags or fields to create from keys present in the application property bag.\n  ## These could for example be set by message enrichments in Azure IoT Hub.\n  # application_property_tags = []\n  # application_property_fields = []\n\n  ## Tag or field name to use for metadata\n  ## By default all metadata is disabled\n  # sequence_number_field = \"SequenceNumber\"\n  # enqueued_time_field = \"EnqueuedTime\"\n  # offset_field = \"Offset\"\n  # partition_id_tag = \"PartitionID\"\n  # partition_key_tag = \"PartitionKey\"\n  # iot_hub_device_connection_id_tag = \"IoTHubDeviceConnectionID\"\n  # iot_hub_auth_generation_id_tag = \"IoTHubAuthGenerationID\"\n  # iot_hub_connection_auth_method_tag = \"IoTHubConnectionAuthMethod\"\n  # iot_hub_connection_module_id_tag = \"IoTHubConnectionModuleID\"\n  # iot_hub_enqueued_time_field = \"IoTHubEnqueuedTime\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n### Environment Variables\n\n[Full documentation of the available environment variables][envvar].\n\n[envvar]: https://github.com/Azure/azure-event-hubs-go#environment-variables\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/eventhub_consumer/eventhub_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage eventhub_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\teventhub \"github.com/Azure/azure-event-hubs-go/v3\"\n\t\"github.com/Azure/azure-event-hubs-go/v3/persist\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst (\n\tdefaultMaxUndeliveredMessages = 1000\n)\n\ntype EventHub struct {\n\t// Configuration\n\tConnectionString       string    `toml:\"connection_string\"`\n\tPersistenceDir         string    `toml:\"persistence_dir\"`\n\tConsumerGroup          string    `toml:\"consumer_group\"`\n\tFromTimestamp          time.Time `toml:\"from_timestamp\"`\n\tLatest                 bool      `toml:\"latest\"`\n\tPrefetchCount          uint32    `toml:\"prefetch_count\"`\n\tEpoch                  int64     `toml:\"epoch\"`\n\tUserAgent              string    `toml:\"user_agent\"`\n\tPartitionIDs           []string  `toml:\"partition_ids\"`\n\tMaxUndeliveredMessages int       `toml:\"max_undelivered_messages\"`\n\tEnqueuedTimeAsTS       bool      `toml:\"enqueued_time_as_ts\"`\n\tIotHubEnqueuedTimeAsTS bool      `toml:\"iot_hub_enqueued_time_as_ts\"`\n\n\t// Metadata\n\tApplicationPropertyFields     []string `toml:\"application_property_fields\"`\n\tApplicationPropertyTags       []string `toml:\"application_property_tags\"`\n\tSequenceNumberField           string   `toml:\"sequence_number_field\"`\n\tEnqueuedTimeField             string   `toml:\"enqueued_time_field\"`\n\tOffsetField                   string   `toml:\"offset_field\"`\n\tPartitionIDTag                string   `toml:\"partition_id_tag\"`\n\tPartitionKeyTag               string   `toml:\"partition_key_tag\"`\n\tIoTHubDeviceConnectionIDTag   string   `toml:\"iot_hub_device_connection_id_tag\"`\n\tIoTHubAuthGenerationIDTag     string   `toml:\"iot_hub_auth_generation_id_tag\"`\n\tIoTHubConnectionAuthMethodTag string   `toml:\"iot_hub_connection_auth_method_tag\"`\n\tIoTHubConnectionModuleIDTag   string   `toml:\"iot_hub_connection_module_id_tag\"`\n\tIoTHubEnqueuedTimeField       string   `toml:\"iot_hub_enqueued_time_field\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\t// Azure\n\thub    *eventhub.Hub\n\tcancel context.CancelFunc\n\twg     sync.WaitGroup\n\n\tparser telegraf.Parser\n\tin     chan []telegraf.Metric\n}\n\ntype (\n\tempty     struct{}\n\tsemaphore chan empty\n)\n\nfunc (*EventHub) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (e *EventHub) Init() (err error) {\n\tif e.MaxUndeliveredMessages == 0 {\n\t\te.MaxUndeliveredMessages = defaultMaxUndeliveredMessages\n\t}\n\n\t// Set hub options\n\thubOpts := make([]eventhub.HubOption, 0, 2)\n\n\tif e.PersistenceDir != \"\" {\n\t\tpersister, err := persist.NewFilePersister(e.PersistenceDir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\thubOpts = append(hubOpts, eventhub.HubWithOffsetPersistence(persister))\n\t}\n\n\tif e.UserAgent != \"\" {\n\t\thubOpts = append(hubOpts, eventhub.HubWithUserAgent(e.UserAgent))\n\t} else {\n\t\thubOpts = append(hubOpts, eventhub.HubWithUserAgent(internal.ProductToken()))\n\t}\n\n\t// Create event hub connection\n\tif e.ConnectionString != \"\" {\n\t\te.hub, err = eventhub.NewHubFromConnectionString(e.ConnectionString, hubOpts...)\n\t} else {\n\t\te.hub, err = eventhub.NewHubFromEnvironment(hubOpts...)\n\t}\n\n\treturn err\n}\n\nfunc (e *EventHub) SetParser(parser telegraf.Parser) {\n\te.parser = parser\n}\n\nfunc (e *EventHub) Start(acc telegraf.Accumulator) error {\n\te.in = make(chan []telegraf.Metric)\n\n\tvar ctx context.Context\n\tctx, e.cancel = context.WithCancel(context.Background())\n\n\t// Start tracking\n\te.wg.Add(1)\n\tgo func() {\n\t\tdefer e.wg.Done()\n\t\te.startTracking(ctx, acc)\n\t}()\n\n\t// Configure receiver options\n\treceiveOpts := e.configureReceiver()\n\tpartitions := e.PartitionIDs\n\n\tif len(e.PartitionIDs) == 0 {\n\t\truntimeinfo, err := e.hub.GetRuntimeInformation(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpartitions = runtimeinfo.PartitionIDs\n\t}\n\n\tfor _, partitionID := range partitions {\n\t\t_, err := e.hub.Receive(ctx, partitionID, e.onMessage, receiveOpts...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating receiver for partition %q: %w\", partitionID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (*EventHub) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (e *EventHub) Stop() {\n\terr := e.hub.Close(context.Background())\n\tif err != nil {\n\t\te.Log.Errorf(\"Error closing Event Hub connection: %v\", err)\n\t}\n\te.cancel()\n\te.wg.Wait()\n}\n\nfunc (e *EventHub) configureReceiver() []eventhub.ReceiveOption {\n\treceiveOpts := make([]eventhub.ReceiveOption, 0, 4)\n\n\tif e.ConsumerGroup != \"\" {\n\t\treceiveOpts = append(receiveOpts, eventhub.ReceiveWithConsumerGroup(e.ConsumerGroup))\n\t}\n\n\tif !e.FromTimestamp.IsZero() {\n\t\treceiveOpts = append(receiveOpts, eventhub.ReceiveFromTimestamp(e.FromTimestamp))\n\t} else if e.Latest {\n\t\treceiveOpts = append(receiveOpts, eventhub.ReceiveWithLatestOffset())\n\t}\n\n\tif e.PrefetchCount != 0 {\n\t\treceiveOpts = append(receiveOpts, eventhub.ReceiveWithPrefetchCount(e.PrefetchCount))\n\t}\n\n\tif e.Epoch != 0 {\n\t\treceiveOpts = append(receiveOpts, eventhub.ReceiveWithEpoch(e.Epoch))\n\t}\n\n\treturn receiveOpts\n}\n\n// OnMessage handles an Event.  When this function returns without error the\n// Event is immediately accepted and the offset is updated.  If an error is\n// returned the Event is marked for redelivery.\nfunc (e *EventHub) onMessage(ctx context.Context, event *eventhub.Event) error {\n\tmetrics, err := e.createMetrics(event)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase e.in <- metrics:\n\t\treturn nil\n\t}\n}\n\n// OnDelivery returns true if a new slot has opened up in the TrackingAccumulator.\nfunc (e *EventHub) onDelivery(\n\tacc telegraf.TrackingAccumulator,\n\tgroups map[telegraf.TrackingID][]telegraf.Metric,\n\ttrack telegraf.DeliveryInfo,\n) bool {\n\tif track.Delivered() {\n\t\tdelete(groups, track.ID())\n\t\treturn true\n\t}\n\n\t// The metric was already accepted when onMessage completed, so we can't\n\t// fallback on redelivery from Event Hub.  Add a new copy of the metric for\n\t// reprocessing.\n\tmetrics, ok := groups[track.ID()]\n\tdelete(groups, track.ID())\n\tif !ok {\n\t\t// The metrics should always be found, this message indicates a programming error.\n\t\te.Log.Errorf(\"Could not find delivery: %d\", track.ID())\n\t\treturn true\n\t}\n\n\tbackup := deepCopyMetrics(metrics)\n\tid := acc.AddTrackingMetricGroup(metrics)\n\tgroups[id] = backup\n\treturn false\n}\n\nfunc (e *EventHub) startTracking(ctx context.Context, ac telegraf.Accumulator) {\n\tacc := ac.WithTracking(e.MaxUndeliveredMessages)\n\tsem := make(semaphore, e.MaxUndeliveredMessages)\n\tgroups := make(map[telegraf.TrackingID][]telegraf.Metric, e.MaxUndeliveredMessages)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase track := <-acc.Delivered():\n\t\t\tif e.onDelivery(acc, groups, track) {\n\t\t\t\t<-sem\n\t\t\t}\n\t\tcase sem <- empty{}:\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase track := <-acc.Delivered():\n\t\t\t\tif e.onDelivery(acc, groups, track) {\n\t\t\t\t\t<-sem\n\t\t\t\t\t<-sem\n\t\t\t\t}\n\t\t\tcase metrics := <-e.in:\n\t\t\t\tbackup := deepCopyMetrics(metrics)\n\t\t\t\tid := acc.AddTrackingMetricGroup(metrics)\n\t\t\t\tgroups[id] = backup\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc deepCopyMetrics(in []telegraf.Metric) []telegraf.Metric {\n\tmetrics := make([]telegraf.Metric, 0, len(in))\n\tfor _, m := range in {\n\t\tmetrics = append(metrics, m.Copy())\n\t}\n\treturn metrics\n}\n\n// CreateMetrics returns the Metrics from the Event.\nfunc (e *EventHub) createMetrics(event *eventhub.Event) ([]telegraf.Metric, error) {\n\tmetrics, err := e.parser.Parse(event.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\te.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tfor i := range metrics {\n\t\tfor _, field := range e.ApplicationPropertyFields {\n\t\t\tif val, ok := event.Get(field); ok {\n\t\t\t\tmetrics[i].AddField(field, val)\n\t\t\t}\n\t\t}\n\n\t\tfor _, tag := range e.ApplicationPropertyTags {\n\t\t\tif val, ok := event.Get(tag); ok {\n\t\t\t\tmetrics[i].AddTag(tag, fmt.Sprintf(\"%v\", val))\n\t\t\t}\n\t\t}\n\n\t\tif e.SequenceNumberField != \"\" {\n\t\t\tmetrics[i].AddField(e.SequenceNumberField, *event.SystemProperties.SequenceNumber)\n\t\t}\n\n\t\tif e.EnqueuedTimeAsTS {\n\t\t\tmetrics[i].SetTime(*event.SystemProperties.EnqueuedTime)\n\t\t} else if e.EnqueuedTimeField != \"\" {\n\t\t\tmetrics[i].AddField(e.EnqueuedTimeField, (*event.SystemProperties.EnqueuedTime).UnixNano()/int64(time.Millisecond))\n\t\t}\n\n\t\tif e.OffsetField != \"\" {\n\t\t\tmetrics[i].AddField(e.OffsetField, *event.SystemProperties.Offset)\n\t\t}\n\n\t\tif event.SystemProperties.PartitionID != nil && e.PartitionIDTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.PartitionIDTag, strconv.Itoa(int(*event.SystemProperties.PartitionID)))\n\t\t}\n\t\tif event.SystemProperties.PartitionKey != nil && e.PartitionKeyTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.PartitionKeyTag, *event.SystemProperties.PartitionKey)\n\t\t}\n\t\tif event.SystemProperties.IoTHubDeviceConnectionID != nil && e.IoTHubDeviceConnectionIDTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.IoTHubDeviceConnectionIDTag, *event.SystemProperties.IoTHubDeviceConnectionID)\n\t\t}\n\t\tif event.SystemProperties.IoTHubAuthGenerationID != nil && e.IoTHubAuthGenerationIDTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.IoTHubAuthGenerationIDTag, *event.SystemProperties.IoTHubAuthGenerationID)\n\t\t}\n\t\tif event.SystemProperties.IoTHubConnectionAuthMethod != nil && e.IoTHubConnectionAuthMethodTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.IoTHubConnectionAuthMethodTag, *event.SystemProperties.IoTHubConnectionAuthMethod)\n\t\t}\n\t\tif event.SystemProperties.IoTHubConnectionModuleID != nil && e.IoTHubConnectionModuleIDTag != \"\" {\n\t\t\tmetrics[i].AddTag(e.IoTHubConnectionModuleIDTag, *event.SystemProperties.IoTHubConnectionModuleID)\n\t\t}\n\t\tif event.SystemProperties.IoTHubEnqueuedTime != nil {\n\t\t\tif e.IotHubEnqueuedTimeAsTS {\n\t\t\t\tmetrics[i].SetTime(*event.SystemProperties.IoTHubEnqueuedTime)\n\t\t\t} else if e.IoTHubEnqueuedTimeField != \"\" {\n\t\t\t\tmetrics[i].AddField(e.IoTHubEnqueuedTimeField, (*event.SystemProperties.IoTHubEnqueuedTime).UnixNano()/int64(time.Millisecond))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn metrics, nil\n}\n\nfunc init() {\n\tinputs.Add(\"eventhub_consumer\", func() telegraf.Input {\n\t\treturn &EventHub{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/eventhub_consumer/sample.conf",
    "content": "# Azure Event Hubs service input plugin\n[[inputs.eventhub_consumer]]\n  ## The default behavior is to create a new Event Hub client from environment variables.\n  ## This requires one of the following sets of environment variables to be set:\n  ##\n  ## 1) Expected Environment Variables:\n  ##    - \"EVENTHUB_CONNECTION_STRING\"\n  ##\n  ## 2) Expected Environment Variables:\n  ##    - \"EVENTHUB_NAMESPACE\"\n  ##    - \"EVENTHUB_NAME\"\n  ##    - \"EVENTHUB_KEY_NAME\"\n  ##    - \"EVENTHUB_KEY_VALUE\"\n\n  ## 3) Expected Environment Variables:\n  ##    - \"EVENTHUB_NAMESPACE\"\n  ##    - \"EVENTHUB_NAME\"\n  ##    - \"AZURE_TENANT_ID\"\n  ##    - \"AZURE_CLIENT_ID\"\n  ##    - \"AZURE_CLIENT_SECRET\"\n\n  ## Uncommenting the option below will create an Event Hub client based solely on the connection string.\n  ## This can either be the associated environment variable or hard coded directly.\n  ## If this option is uncommented, environment variables will be ignored.\n  ## Connection string should contain EventHubName (EntityPath)\n  # connection_string = \"\"\n\n  ## Set persistence directory to a valid folder to use a file persister instead of an in-memory persister\n  # persistence_dir = \"\"\n\n  ## Change the default consumer group\n  # consumer_group = \"\"\n\n  ## By default the event hub receives all messages present on the broker, alternative modes can be set below.\n  ## The timestamp should be in https://github.com/toml-lang/toml#offset-date-time format (RFC 3339).\n  ## The 3 options below only apply if no valid persister is read from memory or file (e.g. first run).\n  # from_timestamp =\n  # latest = true\n\n  ## Set a custom prefetch count for the receiver(s)\n  # prefetch_count = 1000\n\n  ## Add an epoch to the receiver(s)\n  # epoch = 0\n\n  ## Change to set a custom user agent, \"telegraf\" is used by default\n  # user_agent = \"telegraf\"\n\n  ## To consume from a specific partition, set the partition_ids option.\n  ## An empty array will result in receiving from all partitions.\n  # partition_ids = [\"0\",\"1\"]\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Set either option below to true to use a system property as timestamp.\n  ## You have the choice between EnqueuedTime and IoTHubEnqueuedTime.\n  ## It is recommended to use this setting when the data itself has no timestamp.\n  # enqueued_time_as_ts = true\n  # iot_hub_enqueued_time_as_ts = true\n\n  ## Tags or fields to create from keys present in the application property bag.\n  ## These could for example be set by message enrichments in Azure IoT Hub.\n  # application_property_tags = []\n  # application_property_fields = []\n\n  ## Tag or field name to use for metadata\n  ## By default all metadata is disabled\n  # sequence_number_field = \"SequenceNumber\"\n  # enqueued_time_field = \"EnqueuedTime\"\n  # offset_field = \"Offset\"\n  # partition_id_tag = \"PartitionID\"\n  # partition_key_tag = \"PartitionKey\"\n  # iot_hub_device_connection_id_tag = \"IoTHubDeviceConnectionID\"\n  # iot_hub_auth_generation_id_tag = \"IoTHubAuthGenerationID\"\n  # iot_hub_connection_auth_method_tag = \"IoTHubConnectionAuthMethod\"\n  # iot_hub_connection_module_id_tag = \"IoTHubConnectionModuleID\"\n  # iot_hub_enqueued_time_field = \"IoTHubEnqueuedTime\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/example/README.md",
    "content": "# Example Input Plugin\n\nThe `example` plugin gathers metrics about example things.  This description\nexplains at a high level what the plugin does and provides links to where\nadditional information can be found.\n\nTelegraf minimum version: Telegraf x.x Plugin minimum tested version: x.x\n\n⭐ Telegraf v1.0.0  <!-- introduction version -->\n🚩 Telegraf v1.10.0 <!-- deprecation version if any -->\n🔥 Telegraf v1.20.0 <!-- removal version  if any -->\n🏷️ system           <!-- plugin tags -->\n💻 all              <!-- OS support -->\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# This is an example plugin\n[[inputs.example]]\n  example_option = \"example_value\"\n```\n\nRunning `telegraf --usage <plugin-name>` also gives the sample TOML\nconfiguration.\n\n### example_option\n\nA more in depth description of an option can be provided here, but only do so if\nthe option cannot be fully described in the sample config.\n\n## Metrics\n\nHere you should add an optional description and links to where the user can get\nmore information about the measurements.\n\nIf the output is determined dynamically based on the input source, or there are\nmore metrics than can reasonably be listed, describe how the input is mapped to\nthe output.\n\n- measurement1\n  - tags:\n    - tag1 (optional description)\n    - tag2\n  - fields:\n    - field1 (type, unit)\n    - field2 (float, percent)\n\n- measurement2\n  - tags:\n    - tag3\n  - fields:\n    - field3 (integer, bytes)\n    - field4 (integer, green=1 yellow=2 red=3)\n    - field5 (string)\n    - field6 (float)\n    - field7 (boolean)\n\n## Sample Queries\n\nThis section can contain some useful InfluxDB queries that can be used to get\nstarted with the plugin or to generate dashboards.  For each query listed,\ndescribe at a high level what data is returned.\n\nGet the max, mean, and min for the measurement in the last hour:\n\n```sql\nSELECT max(field1), mean(field1), min(field1) FROM measurement1 WHERE tag1=bar AND time > now() - 1h GROUP BY tag\n```\n\n## Troubleshooting\n\nThis optional section can provide basic troubleshooting steps that a user can\nperform.\n\n## Example Output\n\nThis section shows example output in Line Protocol format.  You can often use\n`telegraf --input-filter <plugin-name> --test` or use the `file` output to get\nthis information.\n\n```text\nmeasurement1,tag1=foo,tag2=bar field1=1i,field2=2.1 1453831884664956455\nmeasurement2,tag1=foo,tag2=bar,tag3=baz field3=1i 1453831884664956455\n```\n"
  },
  {
    "path": "plugins/inputs/example/example.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage example\n\nimport (\n\t\"crypto/rand\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Example struct should be named the same as the Plugin\ntype Example struct {\n\t// Example for a mandatory option to set a tag\n\tDeviceName string `toml:\"device_name\"`\n\n\t// Config options are converted to the correct type automatically\n\tNumberFields int64 `toml:\"number_fields\"`\n\n\t// We can also use booleans and have diverging names between user-configuration options and struct members\n\tEnableRandomVariable bool `toml:\"enable_random\"`\n\n\t// Example of passing a duration option allowing the format of e.g. \"100ms\", \"5m\" or \"1h\"\n\tTimeout config.Duration `toml:\"timeout\"`\n\n\t// Example of passing a password/token/username or other sensitive data with the secret-store\n\tUserName config.Secret `toml:\"username\"`\n\tPassword config.Secret `toml:\"password\"`\n\n\t// Telegraf logging facility\n\t// The exact name is important to allow automatic initialization by telegraf.\n\tLog telegraf.Logger `toml:\"-\"`\n\n\t// This is a non-exported internal state.\n\tcount int64\n}\n\nfunc (*Example) SampleConfig() string {\n\treturn sampleConfig\n}\n\n// Init can be implemented to do one-time processing stuff like initializing variables\nfunc (m *Example) Init() error {\n\t// Check your options according to your requirements\n\tif m.DeviceName == \"\" {\n\t\treturn errors.New(\"device name cannot be empty\")\n\t}\n\n\t// Set your defaults.\n\t// Please note: In golang all fields are initialized to their nil value, so you should not\n\t// set these fields if the nil value is what you want (e.g. for booleans).\n\tif m.NumberFields < 1 {\n\t\tm.Log.Debugf(\"Setting number of fields to default from invalid value %d\", m.NumberFields)\n\t\tm.NumberFields = 2\n\t}\n\n\t// Check using the secret-store\n\tif m.UserName.Empty() {\n\t\t// For example, use a default value\n\t\tm.Log.Debug(\"using default username\")\n\t}\n\n\t// Retrieve credentials using the secret-store\n\tpassword, err := m.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer password.Destroy()\n\n\t// Initialize your internal states\n\tm.count = 1\n\n\treturn nil\n}\n\n// Gather defines what data the plugin will gather.\nfunc (m *Example) Gather(acc telegraf.Accumulator) error {\n\t// Imagine some completely arbitrary error occurring here\n\tif m.NumberFields > 10 {\n\t\treturn errors.New(\"too many fields\")\n\t}\n\n\t// For illustration, we gather three metrics in one go\n\tfor run := 0; run < 3; run++ {\n\t\t// Imagine an error occurs here, but you want to keep the other\n\t\t// metrics, then you cannot simply return, as this would drop\n\t\t// all later metrics. Simply accumulate errors in this case\n\t\t// and ignore the metric.\n\t\tif m.EnableRandomVariable && m.DeviceName == \"flappy\" && run > 1 {\n\t\t\tacc.AddError(errors.New(\"too many runs for random values\"))\n\t\t\tcontinue\n\t\t}\n\n\t\t// Construct the fields\n\t\tfields := map[string]interface{}{\"count\": m.count}\n\t\tfor i := int64(1); i < m.NumberFields; i++ {\n\t\t\tname := fmt.Sprintf(\"field%d\", i)\n\t\t\tvar err error\n\t\t\tvalue := big.NewInt(0)\n\t\t\tif m.EnableRandomVariable {\n\t\t\t\tvalue, err = rand.Int(rand.Reader, big.NewInt(math.MaxUint32))\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tfields[name] = float64(value.Int64())\n\t\t}\n\n\t\t// Construct the tags\n\t\ttags := map[string]string{\"device\": m.DeviceName}\n\n\t\t// Add the metric with the current timestamp\n\t\tacc.AddFields(\"example\", fields, tags)\n\n\t\tm.count++\n\t}\n\n\treturn nil\n}\n\n// Register the plugin\nfunc init() {\n\tinputs.Add(\"example\", func() telegraf.Input {\n\t\treturn &Example{\n\t\t\t// Set the default timeout here to distinguish it from the user setting it to zero\n\t\t\tTimeout: config.Duration(100 * time.Millisecond),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/example/example_test.go",
    "content": "package example\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// This file should contain a set of unit-tests to cover your plugin. This will ease\n// spotting bugs and mistakes when later modifying or extending the functionality.\n// To do so, please write one 'TestXYZ' function per 'case' e.g. default init,\n// things that should fail or expected values from a mockup.\n\nfunc TestInitDefault(t *testing.T) {\n\t// This test should succeed with the default initialization.\n\n\t// Use whatever you use in the init() function plus the mandatory options.\n\t// ATTENTION: Always initialize the \"Log\" as you will get SIGSEGV otherwise.\n\tplugin := &Example{\n\t\tDeviceName: \"test\",\n\t\tTimeout:    config.Duration(100 * time.Millisecond),\n\t\tLog:        testutil.Logger{},\n\t}\n\n\t// Test the initialization succeeds\n\trequire.NoError(t, plugin.Init())\n\n\t// Also test that default values are set correctly\n\trequire.Equal(t, config.Duration(100*time.Millisecond), plugin.Timeout)\n\trequire.Equal(t, \"test\", plugin.DeviceName)\n\trequire.Equal(t, int64(2), plugin.NumberFields)\n}\n\nfunc TestInitFail(t *testing.T) {\n\t// You should also test for your safety nets to work i.e. you get errors for\n\t// invalid configuration-option values. So check your error paths in Init()\n\t// and check if you reach them\n\n\t// We setup a table-test here to specify \"setting\" - \"expected error\" values.\n\t// Even though it seems overkill here for the example plugin, we reuse this structure\n\t// later for checking the metrics\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *Example\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"all empty\",\n\t\t\tplugin:   &Example{},\n\t\t\texpected: \"device name cannot be empty\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Always initialize the logger to avoid SIGSEGV. This is done automatically by\n\t\t\t// telegraf during normal operation.\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\terr := tt.plugin.Init()\n\t\t\trequire.Error(t, err)\n\t\t\trequire.EqualError(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestFixedValue(t *testing.T) {\n\t// You can organize the test e.g. by operation mode (like we do here random vs. fixed), by features or\n\t// by different metrics gathered. Please choose the partitioning most suited for your plugin\n\n\t// We again setup a table-test here to specify \"setting\" - \"expected output metric\" pairs.\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *Example\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"count only\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:   \"test\",\n\t\t\t\tNumberFields: 1,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": 2,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": 3,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"default settings\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName: \"test\",\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  1,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  2,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  3,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"more fields\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:   \"test\",\n\t\t\t\tNumberFields: 4,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  1,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t\t\"field2\": float64(0),\n\t\t\t\t\t\t\"field3\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  2,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t\t\"field2\": float64(0),\n\t\t\t\t\t\t\"field3\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  3,\n\t\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t\t\"field2\": float64(0),\n\t\t\t\t\t\t\"field3\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\n\t\t\t// Call gather and check no error occurs. In case you use acc.AddError() somewhere\n\t\t\t// in your code, it is not sufficient to only check the return value of Gather().\n\t\t\trequire.NoError(t, tt.plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors, \"found errors accumulated by acc.AddError()\")\n\n\t\t\t// Wait for the expected number of metrics to avoid flaky tests due to\n\t\t\t// race conditions.\n\t\t\tacc.Wait(len(tt.expected))\n\n\t\t\t// Compare the metrics in a convenient way. Here we ignore\n\t\t\t// the metric time during comparison as we cannot inject the time\n\t\t\t// during test. For more comparison options check testutil package.\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRandomValue(t *testing.T) {\n\t// Sometimes, you cannot know the exact outcome of the gather cycle e.g. if the gathering involves random data.\n\t// However, you should check the result nevertheless, applying as many conditions as you can.\n\n\t// We again setup a table-test here to specify \"setting\" - \"expected output metric\" pairs.\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *Example\n\t\ttemplate telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"count only\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:           \"test\",\n\t\t\t\tNumberFields:         1,\n\t\t\t\tEnableRandomVariable: true,\n\t\t\t},\n\t\t\ttemplate: testutil.MustMetric(\n\t\t\t\t\"example\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"count\": 1,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"default settings\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:           \"test\",\n\t\t\t\tEnableRandomVariable: true,\n\t\t\t},\n\t\t\ttemplate: testutil.MustMetric(\n\t\t\t\t\"example\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"count\":  1,\n\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tname: \"more fields\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:           \"test\",\n\t\t\t\tNumberFields:         4,\n\t\t\t\tEnableRandomVariable: true,\n\t\t\t},\n\t\t\ttemplate: testutil.MustMetric(\n\t\t\t\t\"example\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"device\": \"test\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"count\":  1,\n\t\t\t\t\t\"field1\": float64(0),\n\t\t\t\t\t\"field2\": float64(0),\n\t\t\t\t\t\"field3\": float64(0),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\n\t\t\t// Call gather and check no error occurs. In case you use acc.AddError() somewhere\n\t\t\t// in your code, it is not sufficient to only check the return value of Gather().\n\t\t\trequire.NoError(t, tt.plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors, \"found errors accumulated by acc.AddError()\")\n\n\t\t\t// Wait for the expected number of metrics to avoid flaky tests due to\n\t\t\t// race conditions.\n\t\t\tacc.Wait(3)\n\n\t\t\t// Compare all aspects of the metric that are known to you\n\t\t\tfor i, m := range acc.GetTelegrafMetrics() {\n\t\t\t\trequire.Equal(t, m.Name(), tt.template.Name())\n\t\t\t\trequire.Equal(t, m.Tags(), tt.template.Tags())\n\n\t\t\t\t// Check if all expected fields are there\n\t\t\t\tfields := m.Fields()\n\t\t\t\tfor k := range tt.template.Fields() {\n\t\t\t\t\tif k == \"count\" {\n\t\t\t\t\t\trequire.Equal(t, fields[\"count\"], int64(i+1))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t_, found := fields[k]\n\t\t\t\t\trequire.Truef(t, found, \"field %q not found\", k)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGatherFail(t *testing.T) {\n\t// You should also test for error conditions in your Gather() method. Try to cover all error paths.\n\n\t// We again setup a table-test here to specify \"setting\" - \"expected error\" pair.\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *Example\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"too many fields\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:   \"test\",\n\t\t\t\tNumberFields: 11,\n\t\t\t},\n\t\t\texpected: \"too many fields\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\n\t\t\terr := tt.plugin.Gather(&acc)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.EqualError(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestRandomValueFailPartial(t *testing.T) {\n\t// You should also test for error conditions in your Gather() with partial output. This is required when\n\t// using acc.AddError() as Gather() might succeed (return nil) but there are some metrics missing.\n\n\t// We again setup a table-test here to specify \"setting\" - \"expected output metric\" and \"errors\".\n\ttests := []struct {\n\t\tname        string\n\t\tplugin      *Example\n\t\texpected    []telegraf.Metric\n\t\texpectedErr string\n\t}{\n\t\t{\n\t\t\tname: \"flappy gather\",\n\t\t\tplugin: &Example{\n\t\t\t\tDeviceName:           \"flappy\",\n\t\t\t\tNumberFields:         1,\n\t\t\t\tEnableRandomVariable: true,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"flappy\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"example\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"device\": \"flappy\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": 2,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\texpectedErr: \"too many runs for random values\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\n\t\t\t// Call gather and check no error occurs. However, we expect an error accumulated by acc.AddError()\n\t\t\trequire.NoError(t, tt.plugin.Gather(&acc))\n\n\t\t\t// Wait for the expected number of metrics to avoid flaky tests due to\n\t\t\t// race conditions.\n\t\t\tacc.Wait(len(tt.expected))\n\n\t\t\t// Check the accumulated errors\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.EqualError(t, acc.Errors[0], tt.expectedErr)\n\n\t\t\t// Compare the expected partial metrics.\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/example/sample.conf",
    "content": "# This is an example plugin\n[[inputs.example]]\n  example_option = \"example_value\"\n"
  },
  {
    "path": "plugins/inputs/exec/README.md",
    "content": "# Exec Input Plugin\n\nThis plugin executes the given `commands` on every interval and parses metrics\nfrom their output in any one of the supported [data formats][data_formats].\nThis plugin can be used to poll for custom metrics from any source.\n\n⭐ Telegraf v0.1.5\n🏷️ system\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or more commands that can output to stdout\n[[inputs.exec]]\n  ## Commands array\n  commands = []\n\n  ## Environment variables\n  ## Array of \"key=value\" pairs to pass as environment variables\n  ## e.g. \"KEY=value\", \"USERNAME=John Doe\",\n  ## \"LD_LIBRARY_PATH=/opt/custom/lib64:/usr/local/libs\"\n  # environment = []\n\n  ## Timeout for each command to complete.\n  # timeout = \"5s\"\n\n  ## Measurement name suffix\n  ## Used for separating different commands\n  # name_suffix = \"\"\n\n  ## Ignore Error Code\n  ## If set to true, a non-zero error code in not considered an error and the\n  ## plugin will continue to parse the output.\n  # ignore_error = false\n\n  ## Log all messages sent to stderr\n  # log_stderr = false\n\n  ## Data format\n  ## By default, exec expects JSON. This was done for historical reasons and is\n  ## different than other inputs that use the influx line protocol. Each data\n  ## format has its own unique set of configuration options, read more about\n  ## them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"json\"\n```\n\nGlob patterns in the `command` option are matched on every run, so adding new\nscripts that match the pattern will cause them to be picked up immediately.\n\n### Logging\n\nWhen setting `log_stderr` to `true`, the called command may write log messages\nto `stderr`, which Telegraf will log line-wise using the configured logging\nfacility. By default, the _error_ level will be used. Use the known prefixes\n`E!`, `W!`, `I!`, `D!` or `T!` to log with the _error_, _warning_, _info_,\n_debug_ or _trace_ log-level, respectively.\n\n### Example\n\nThis script produces static values, since no timestamp is specified the values\nare at the current time. Ensure that int values are followed with `i` for proper\nparsing.\n\n```sh\n#!/bin/sh\necho 'example,tag1=a,tag2=b i=42i,j=43i,k=44i'\n```\n\nIt can be paired with the following configuration and will be run at the\n`interval` of the agent.\n\n```toml\n[[inputs.exec]]\n  commands = [\"sh /tmp/test.sh\"]\n  timeout = \"5s\"\n  data_format = \"influx\"\n```\n\n## Troubleshooting\n\n### My script works when I run it by hand, but not when Telegraf is running as a service\n\nThis may be related to the Telegraf service running as a different user. The\nofficial packages run Telegraf as the `telegraf` user and group on Linux\nsystems.\n\n### With a PowerShell on Windows, the output of the script appears to be truncated\n\nYou may need to set a variable in your script to increase the number of columns\navailable for output:\n\n```shell\n$host.UI.RawUI.BufferSize = new-object System.Management.Automation.Host.Size(1024,50)\n```\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/exec/dev/telegraf.conf",
    "content": "[agent]\n  interval=\"1s\"\n  flush_interval=\"1s\"\n\n[[inputs.exec]]\n  timeout = \"1s\"\n  data_format = \"influx\"\n  commands = [\n    \"echo 'deal,computer_name=hosta message=\\\"stuff\\\" 1530654676316265790'\",\n    \"echo 'deal,computer_name=hostb message=\\\"stuff\\\" 1530654676316265790'\",\n  ]\n\n[[processors.regex]]\n  [[processors.regex.tags]]\n    key = \"computer_name\"\n    pattern = \"^(.*?)a$\"\n    replacement = \"${1}\"\n    result_key = \"server_name\"\n  [[processors.regex.tags]]\n    key = \"computer_name\"\n    pattern = \"^(.*?)b$\"\n    replacement = \"${1}\"\n    result_key = \"server_name\"\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/exec/exec.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage exec\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/nagios\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst maxStderrBytes int = 512\n\ntype Exec struct {\n\tCommands    []string        `toml:\"commands\"`\n\tCommand     string          `toml:\"command\"`\n\tEnvironment []string        `toml:\"environment\"`\n\tIgnoreError bool            `toml:\"ignore_error\"`\n\tLogStdErr   bool            `toml:\"log_stderr\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\n\tparser telegraf.Parser\n\n\trunner runner\n\n\t// Allow post-processing of command exit codes\n\texitCodeHandler   exitCodeHandlerFunc\n\tparseDespiteError bool\n}\n\ntype exitCodeHandlerFunc func([]telegraf.Metric, error, []byte) []telegraf.Metric\n\ntype runner interface {\n\trun(string) ([]byte, []byte, error)\n}\n\ntype commandRunner struct {\n\tenvironment []string\n\ttimeout     time.Duration\n\tdebug       bool\n}\n\nfunc (*Exec) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (e *Exec) Init() error {\n\t// Legacy single command support\n\tif e.Command != \"\" {\n\t\te.Commands = append(e.Commands, e.Command)\n\t}\n\n\te.runner = &commandRunner{\n\t\tenvironment: e.Environment,\n\t\ttimeout:     time.Duration(e.Timeout),\n\t\tdebug:       e.Log.Level().Includes(telegraf.Debug),\n\t}\n\n\treturn nil\n}\n\nfunc (e *Exec) SetParser(parser telegraf.Parser) {\n\te.parser = parser\n\tunwrapped, ok := parser.(*models.RunningParser)\n\tif ok {\n\t\tif _, ok := unwrapped.Parser.(*nagios.Parser); ok {\n\t\t\te.exitCodeHandler = func(metrics []telegraf.Metric, err error, msg []byte) []telegraf.Metric {\n\t\t\t\treturn nagios.AddState(err, msg, metrics)\n\t\t\t}\n\t\t\te.parseDespiteError = true\n\t\t}\n\t}\n}\n\nfunc (e *Exec) Gather(acc telegraf.Accumulator) error {\n\tcommands := e.updateRunners()\n\n\tvar wg sync.WaitGroup\n\tfor _, cmd := range commands {\n\t\twg.Add(1)\n\n\t\tgo func(c string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(e.processCommand(acc, c))\n\t\t}(cmd)\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc (e *Exec) updateRunners() []string {\n\tcommands := make([]string, 0, len(e.Commands))\n\tfor _, pattern := range e.Commands {\n\t\tif pattern == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Try to expand globbing expressions\n\t\tcmd, args, found := strings.Cut(pattern, \" \")\n\t\tmatches, err := filepath.Glob(cmd)\n\t\tif err != nil {\n\t\t\te.Log.Errorf(\"Matching command %q failed: %v\", cmd, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(matches) == 0 {\n\t\t\t// There were no matches with the glob pattern, so let's assume\n\t\t\t// the command is in PATH and just run it as it is\n\t\t\tcommands = append(commands, pattern)\n\t\t} else {\n\t\t\t// There were matches, so we'll append each match together with\n\t\t\t// the arguments to the commands slice\n\t\t\tfor _, match := range matches {\n\t\t\t\tif found {\n\t\t\t\t\tmatch += \" \" + args\n\t\t\t\t}\n\t\t\t\tcommands = append(commands, match)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn commands\n}\n\nfunc (e *Exec) processCommand(acc telegraf.Accumulator, cmd string) error {\n\tout, errBuf, runErr := e.runner.run(cmd)\n\tif !e.IgnoreError && !e.parseDespiteError && runErr != nil {\n\t\treturn fmt.Errorf(\"exec: %w for command %q: %s\", runErr, cmd, string(errBuf))\n\t}\n\n\t// Log output in stderr\n\tif e.LogStdErr && len(errBuf) > 0 {\n\t\tscanner := bufio.NewScanner(bytes.NewBuffer(errBuf))\n\n\t\tfor scanner.Scan() {\n\t\t\tmsg := scanner.Text()\n\t\t\tswitch {\n\t\t\tcase strings.TrimSpace(msg) == \"\":\n\t\t\t\tcontinue\n\t\t\tcase strings.HasPrefix(msg, \"E! \"):\n\t\t\t\te.Log.Error(msg[3:])\n\t\t\tcase strings.HasPrefix(msg, \"W! \"):\n\t\t\t\te.Log.Warn(msg[3:])\n\t\t\tcase strings.HasPrefix(msg, \"I! \"):\n\t\t\t\te.Log.Info(msg[3:])\n\t\t\tcase strings.HasPrefix(msg, \"D! \"):\n\t\t\t\te.Log.Debug(msg[3:])\n\t\t\tcase strings.HasPrefix(msg, \"T! \"):\n\t\t\t\te.Log.Trace(msg[3:])\n\t\t\tdefault:\n\t\t\t\te.Log.Error(msg)\n\t\t\t}\n\t\t}\n\n\t\tif err := scanner.Err(); err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error reading stderr: %w\", err))\n\t\t}\n\t}\n\n\tmetrics, err := e.parser.Parse(out)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\te.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tif e.exitCodeHandler != nil {\n\t\tmetrics = e.exitCodeHandler(metrics, runErr, errBuf)\n\t}\n\n\tfor _, m := range metrics {\n\t\tacc.AddMetric(m)\n\t}\n\n\treturn nil\n}\n\nfunc truncate(buf *bytes.Buffer) {\n\t// Limit the number of bytes.\n\tdidTruncate := false\n\tif buf.Len() > maxStderrBytes {\n\t\tbuf.Truncate(maxStderrBytes)\n\t\tdidTruncate = true\n\t}\n\tif i := bytes.IndexByte(buf.Bytes(), '\\n'); i > 0 {\n\t\t// Only show truncation if the newline wasn't the last character.\n\t\tif i < buf.Len()-1 {\n\t\t\tdidTruncate = true\n\t\t}\n\t\tbuf.Truncate(i)\n\t}\n\tif didTruncate {\n\t\tbuf.WriteString(\"...\")\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"exec\", func() telegraf.Input {\n\t\treturn &Exec{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/exec/exec_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage exec\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/csv\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/value\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst validJSON = `\n{\n    \"status\": \"green\",\n    \"num_processes\": 82,\n    \"cpu\": {\n        \"status\": \"red\",\n        \"nil_status\": null,\n        \"used\": 8234,\n        \"free\": 32\n    },\n    \"percent\": 0.81,\n    \"users\": [0, 1, 2, 3]\n}`\n\nconst malformedJSON = `\n{\n    \"status\": \"green\",\n`\n\ntype runnerMock struct {\n\tout    []byte\n\terrout []byte\n\terr    error\n}\n\nfunc (r runnerMock) run(string) (out, errout []byte, err error) {\n\treturn r.out, r.errout, r.err\n}\n\nfunc TestExec(t *testing.T) {\n\t// Setup parser\n\tparser := &json.Parser{MetricName: \"exec\"}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"testcommand arg1\"},\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\tplugin.runner = &runnerMock{out: []byte(validJSON)}\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"num_processes\": float64(82),\n\t\t\t\t\"cpu_used\":      float64(8234),\n\t\t\t\t\"cpu_free\":      float64(32),\n\t\t\t\t\"percent\":       float64(0.81),\n\t\t\t\t\"users_0\":       float64(0),\n\t\t\t\t\"users_1\":       float64(1),\n\t\t\t\t\"users_2\":       float64(2),\n\t\t\t\t\"users_3\":       float64(3),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestExecMalformed(t *testing.T) {\n\t// Setup parser\n\tparser := &json.Parser{MetricName: \"exec\"}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"badcommand arg1\"},\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\tplugin.runner = &runnerMock{out: []byte(malformedJSON)}\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, acc.GatherError(plugin.Gather), \"unexpected end of JSON input\")\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n}\n\nfunc TestCommandError(t *testing.T) {\n\t// Setup parser\n\tparser := &json.Parser{MetricName: \"exec\"}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"badcommand\"},\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\tplugin.runner = &runnerMock{err: errors.New(\"exit status code 1\")}\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, acc.GatherError(plugin.Gather), \"exit status code 1 for command\")\n\trequire.Equal(t, 0, acc.NFields(), \"No new points should have been added\")\n}\n\nfunc TestCommandIgnoreError(t *testing.T) {\n\t// Setup parser\n\tparser := &json.Parser{MetricName: \"exec\"}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands:    []string{\"badcommand\"},\n\t\tIgnoreError: true,\n\t\tLog:         testutil.Logger{},\n\t}\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\tplugin.runner = &runnerMock{\n\t\tout:    []byte(validJSON),\n\t\terrout: []byte(\"error\"),\n\t\terr:    errors.New(\"exit status code 1\"),\n\t}\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"num_processes\": float64(82),\n\t\t\t\t\"cpu_used\":      float64(8234),\n\t\t\t\t\"cpu_free\":      float64(32),\n\t\t\t\t\"percent\":       float64(0.81),\n\t\t\t\t\"users_0\":       float64(0),\n\t\t\t\t\"users_1\":       float64(1),\n\t\t\t\t\"users_2\":       float64(2),\n\t\t\t\t\"users_3\":       float64(3),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestExecCommandWithGlob(t *testing.T) {\n\t// Setup parser\n\tparser := value.Parser{\n\t\tMetricName: \"metric\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"/bin/ech* metric_value\"},\n\t\tTimeout:  config.Duration(5 * time.Second),\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(&parser)\n\trequire.NoError(t, plugin.Init())\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"metric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": \"metric_value\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestExecCommandWithoutGlob(t *testing.T) {\n\t// Setup parser\n\tparser := value.Parser{\n\t\tMetricName: \"metric\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"/bin/echo metric_value\"},\n\t\tTimeout:  config.Duration(5 * time.Second),\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(&parser)\n\trequire.NoError(t, plugin.Init())\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"metric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": \"metric_value\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestExecCommandWithoutGlobAndPath(t *testing.T) {\n\t// Setup parser\n\tparser := value.Parser{\n\t\tMetricName: \"metric\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"echo metric_value\"},\n\t\tTimeout:  config.Duration(5 * time.Second),\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(&parser)\n\trequire.NoError(t, plugin.Init())\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"metric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": \"metric_value\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestExecCommandWithEnv(t *testing.T) {\n\t// Setup parser\n\tparser := value.Parser{\n\t\tMetricName: \"metric\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup plugin\n\tplugin := &Exec{\n\t\tCommands:    []string{\"/bin/sh -c 'echo ${METRIC_NAME}'\"},\n\t\tEnvironment: []string{\"METRIC_NAME=metric_value\"},\n\t\tTimeout:     config.Duration(5 * time.Second),\n\t\tLog:         testutil.Logger{},\n\t}\n\tplugin.SetParser(&parser)\n\trequire.NoError(t, plugin.Init())\n\n\t// Gather the metrics and check the result\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"metric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": \"metric_value\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestStderrLogging(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\toutput   string\n\t\texpected []testutil.Entry\n\t}{\n\t\t{\n\t\t\tname:   \"no level\",\n\t\t\toutput: `an error message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelError,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `an error message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"error\",\n\t\t\toutput: `E! an error message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelError,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `an error message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"warning\",\n\t\t\toutput: `W! a warning message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelWarn,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `a warning message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"info\",\n\t\t\toutput: `I! an info message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelInfo,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `an info message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"debug\",\n\t\t\toutput: `D! a debug message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelDebug,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `a debug message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"trace\",\n\t\t\toutput: `T! a trace message`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelTrace,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `a trace message`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tname: \"multiline output\",\n\t\t\toutput: `\nE! an error message\nD! some details\nD! some more details\nT! very detailed details\n`,\n\t\t\texpected: []testutil.Entry{\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelError,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `an error message`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelDebug,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `some details`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelDebug,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `some more details`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tLevel: testutil.LevelTrace,\n\t\t\t\t\tName:  \"inputs.exec\",\n\t\t\t\t\tText:  `very detailed details`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup parser\n\t\t\tparser := &value.Parser{\n\t\t\t\tMetricName: \"exec\",\n\t\t\t\tDataType:   \"integer\",\n\t\t\t}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Setup logger\n\t\t\tlogger := &testutil.CaptureLogger{Name: \"inputs.exec\"}\n\n\t\t\t// Setup plugin\n\t\t\tplugin := &Exec{\n\t\t\t\tCommands:  []string{\"echo 42\"},\n\t\t\t\tLogStdErr: true,\n\t\t\t\tLog:       logger,\n\t\t\t}\n\t\t\tplugin.SetParser(parser)\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Mock the runner\n\t\t\tplugin.runner = &runnerMock{\n\t\t\t\tout:    []byte(\"42\"),\n\t\t\t\terrout: []byte(tt.output),\n\t\t\t}\n\n\t\t\t// Gather the metrics and check the result\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"exec\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"value\": int64(42)},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t\t\t// Check the received log-messages\n\t\t\trequire.ElementsMatch(t, tt.expected, logger.Messages())\n\t\t})\n\t}\n}\n\nfunc TestTruncate(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tbufF     func() *bytes.Buffer\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"should not truncate\",\n\t\t\tbufF: func() *bytes.Buffer {\n\t\t\t\treturn bytes.NewBufferString(\"hello world\")\n\t\t\t},\n\t\t\texpected: \"hello world\",\n\t\t},\n\t\t{\n\t\t\tname: \"should truncate up to the new line\",\n\t\t\tbufF: func() *bytes.Buffer {\n\t\t\t\treturn bytes.NewBufferString(\"hello world\\nand all the people\")\n\t\t\t},\n\t\t\texpected: \"hello world...\",\n\t\t},\n\t\t{\n\t\t\tname: \"should truncate to the maxStderrBytes\",\n\t\t\tbufF: func() *bytes.Buffer {\n\t\t\t\tvar b bytes.Buffer\n\t\t\t\tfor i := 0; i < 2*maxStderrBytes; i++ {\n\t\t\t\t\tb.WriteByte('b')\n\t\t\t\t}\n\t\t\t\treturn &b\n\t\t\t},\n\t\t\texpected: strings.Repeat(\"b\", maxStderrBytes) + \"...\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbuf := tt.bufF()\n\t\t\ttruncate(buf)\n\t\t\trequire.Equal(t, tt.expected, buf.String())\n\t\t})\n\t}\n}\n\nfunc TestCSVBehavior(t *testing.T) {\n\t// Setup the CSV parser\n\tparser := &csv.Parser{\n\t\tMetricName:     \"exec\",\n\t\tHeaderRowCount: 1,\n\t\tResetMode:      \"always\",\n\t}\n\trequire.NoError(t, parser.Init())\n\n\t// Setup the plugin\n\tplugin := &Exec{\n\t\tCommands: []string{\"echo \\\"a,b\\n1,2\\n3,4\\\"\"},\n\t\tTimeout:  config.Duration(5 * time.Second),\n\t\tLog:      testutil.Logger{},\n\t}\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 3),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 4),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\t// Run gather once\n\trequire.NoError(t, plugin.Gather(&acc))\n\t// Run gather a second time\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Eventuallyf(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"Expected %d metrics found %d\", len(expected), acc.NMetrics())\n\n\t// Check the result\n\toptions := []cmp.Option{\n\t\ttestutil.SortMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Register the plugin\n\tinputs.Add(\"exec\", func() telegraf.Input {\n\t\treturn &Exec{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\tLog:     testutil.Logger{},\n\t\t}\n\t})\n\n\t// Setup the plugin\n\tcfg := config.NewConfig()\n\trequire.NoError(t, cfg.LoadConfigData([]byte(`\n\t[[inputs.exec]]\n\tcommands = [ \"echo \\\"a,b\\n1,2\\n3,4\\\"\" ]\n\tdata_format = \"csv\"\n\tcsv_header_row_count = 1\n`), config.EmptySourcePath))\n\trequire.Len(t, cfg.Inputs, 1)\n\tplugin := cfg.Inputs[0]\n\trequire.NoError(t, plugin.Init())\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 3),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"exec\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 4),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\t// Run gather once\n\trequire.NoError(t, plugin.Gather(&acc))\n\t// Run gather a second time\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Eventuallyf(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"Expected %d metrics found %d\", len(expected), acc.NMetrics())\n\n\t// Check the result\n\toptions := []cmp.Option{\n\t\ttestutil.SortMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n"
  },
  {
    "path": "plugins/inputs/exec/run_notwindows.go",
    "content": "//go:build !windows\n\npackage exec\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"syscall\"\n\n\t\"github.com/kballard/go-shellquote\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc (c *commandRunner) run(command string) (out, errout []byte, err error) {\n\tsplitCmd, err := shellquote.Split(command)\n\tif err != nil || len(splitCmd) == 0 {\n\t\treturn nil, nil, fmt.Errorf(\"exec: unable to parse command %q: %w\", command, err)\n\t}\n\n\tcmd := exec.Command(splitCmd[0], splitCmd[1:]...)\n\tcmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}\n\n\tif len(c.environment) > 0 {\n\t\tcmd.Env = append(os.Environ(), c.environment...)\n\t}\n\n\tvar outbuf, stderr bytes.Buffer\n\tcmd.Stdout = &outbuf\n\tcmd.Stderr = &stderr\n\n\trunErr := internal.RunTimeout(cmd, c.timeout)\n\n\tif stderr.Len() > 0 && !c.debug {\n\t\ttruncate(&stderr)\n\t}\n\n\treturn outbuf.Bytes(), stderr.Bytes(), runErr\n}\n"
  },
  {
    "path": "plugins/inputs/exec/run_windows.go",
    "content": "//go:build windows\n\npackage exec\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"syscall\"\n\n\t\"github.com/kballard/go-shellquote\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc (c *commandRunner) run(command string) (out, errout []byte, err error) {\n\tsplitCmd, err := shellquote.Split(command)\n\tif err != nil || len(splitCmd) == 0 {\n\t\treturn nil, nil, fmt.Errorf(\"exec: unable to parse command: %w\", err)\n\t}\n\n\tcmd := exec.Command(splitCmd[0], splitCmd[1:]...)\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tCreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,\n\t}\n\n\tif len(c.environment) > 0 {\n\t\tcmd.Env = append(os.Environ(), c.environment...)\n\t}\n\n\tvar outbuf, stderr bytes.Buffer\n\tcmd.Stdout = &outbuf\n\tcmd.Stderr = &stderr\n\n\trunErr := internal.RunTimeout(cmd, c.timeout)\n\n\toutbuf = removeWindowsCarriageReturns(outbuf)\n\tstderr = removeWindowsCarriageReturns(stderr)\n\tif stderr.Len() > 0 && !c.debug {\n\t\ttruncate(&stderr)\n\t}\n\n\treturn outbuf.Bytes(), stderr.Bytes(), runErr\n}\n\nfunc removeWindowsCarriageReturns(b bytes.Buffer) bytes.Buffer {\n\tvar buf bytes.Buffer\n\tfor {\n\t\tbyt, err := b.ReadBytes(0x0D)\n\t\tbyt = bytes.TrimRight(byt, \"\\x0d\")\n\t\tif len(byt) > 0 {\n\t\t\tbuf.Write(byt)\n\t\t}\n\t\tif errors.Is(err, io.EOF) {\n\t\t\treturn buf\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/exec/sample.conf",
    "content": "# Read metrics from one or more commands that can output to stdout\n[[inputs.exec]]\n  ## Commands array\n  commands = []\n\n  ## Environment variables\n  ## Array of \"key=value\" pairs to pass as environment variables\n  ## e.g. \"KEY=value\", \"USERNAME=John Doe\",\n  ## \"LD_LIBRARY_PATH=/opt/custom/lib64:/usr/local/libs\"\n  # environment = []\n\n  ## Timeout for each command to complete.\n  # timeout = \"5s\"\n\n  ## Measurement name suffix\n  ## Used for separating different commands\n  # name_suffix = \"\"\n\n  ## Ignore Error Code\n  ## If set to true, a non-zero error code in not considered an error and the\n  ## plugin will continue to parse the output.\n  # ignore_error = false\n\n  ## Log all messages sent to stderr\n  # log_stderr = false\n\n  ## Data format\n  ## By default, exec expects JSON. This was done for historical reasons and is\n  ## different than other inputs that use the influx line protocol. Each data\n  ## format has its own unique set of configuration options, read more about\n  ## them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"json\"\n"
  },
  {
    "path": "plugins/inputs/execd/README.md",
    "content": "# Execd Input Plugin\n\nThis plugin runs the given external program as a long-running daemon and collects\nthe metrics in one of the supported [data formats][data_formats] on the\nprocess's `stdout`. The program is expected to stay running and output data\nwhen receiving the configured `signal`.\n\nThe `stderr` output of the process will be relayed to Telegraf's logging\nfacilities and will be logged as _error_ by default. However, you can log to\nother levels by prefixing your message with `E!` for error, `W!` for warning,\n`I!` for info, `D!` for debugging and `T!` for trace levels followed by a space\nand the actual message. For example outputting `I! A log message` will create a\n`info` log line in your Telegraf logging output.\n\n⭐ Telegraf v1.14.0\n🏷️ system\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Run executable as long-running input plugin\n[[inputs.execd]]\n  ## One program to run as daemon.\n  ## NOTE: process and each argument should each be their own string\n  command = [\"telegraf-smartctl\", \"-d\", \"/dev/sda\"]\n\n  ## Environment variables\n  ## Array of \"key=value\" pairs to pass as environment variables\n  ## e.g. \"KEY=value\", \"USERNAME=John Doe\",\n  ## \"LD_LIBRARY_PATH=/opt/custom/lib64:/usr/local/libs\"\n  # environment = []\n\n  ## Define how the process is signaled on each collection interval.\n  ## Valid values are:\n  ##   \"none\"    : Do not signal anything. (Recommended for service inputs)\n  ##               The process must output metrics by itself.\n  ##   \"STDIN\"   : Send a newline on STDIN. (Recommended for gather inputs)\n  ##   \"SIGHUP\"  : Send a HUP signal. Not available on Windows. (not recommended)\n  ##   \"SIGUSR1\" : Send a USR1 signal. Not available on Windows.\n  ##   \"SIGUSR2\" : Send a USR2 signal. Not available on Windows.\n  # signal = \"none\"\n\n  ## Delay before the process is restarted after an unexpected termination\n  # restart_delay = \"10s\"\n\n  ## Buffer size used to read from the command output stream\n  ## Optional parameter. Default is 64 Kib, minimum is 16 bytes\n  # buffer_size = \"64Kib\"\n\n  ## Disable automatic restart of the program and stop if the program exits\n  ## with an error (non-zero error code)\n  # stop_on_error = false\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n```\n\n## Example\n\nSee the examples directory for basic examples in different languages expecting\nvarious signals from Telegraf:\n\n- [Go](./examples/count.go): Example expects `signal = \"SIGHUP\"`\n- [Python](./examples/count.py): Example expects `signal = \"none\"`\n- [Ruby](./examples/count.rb): Example expects `signal = \"none\"`\n- [shell](./examples/count.sh): Example expects `signal = \"STDIN\"`\n\n## Metrics\n\nVaries depending on the users data.\n\n## Example Output\n\nVaries depending on the users data.\n"
  },
  {
    "path": "plugins/inputs/execd/examples/count.go",
    "content": "package main\n\n// Example using HUP signaling\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nfunc main() {\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, syscall.SIGHUP)\n\n\tcounter := 0\n\n\tfor {\n\t\t<-c\n\n\t\tfmt.Printf(\"counter_go count=%d\\n\", counter)\n\t\tcounter++\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/execd/examples/count.py",
    "content": "#!/usr/bin/env python3\nimport sys\nimport time\n\nCOUNTER = 0\n\nwhile True:\n    print(\"counter_python count=\" + str(COUNTER))\n    sys.stdout.flush()\n    COUNTER += 1\n\n    time.sleep(1)\n"
  },
  {
    "path": "plugins/inputs/execd/examples/count.rb",
    "content": "#!/usr/bin/env ruby\n\n## Example in Ruby not using any signaling\n\ncounter = 0\n\ndef time_ns_str(t)\n  ns = t.nsec.to_s\n  (9 - ns.size).times do \n    ns = \"0\" + ns # left pad\n  end\n  t.to_i.to_s + ns\nend\n\nloop do\n  puts \"counter_ruby count=#{counter} #{time_ns_str(Time.now)}\"\n  STDOUT.flush\n  counter += 1\n\n  sleep 1\nend\n"
  },
  {
    "path": "plugins/inputs/execd/examples/count.sh",
    "content": "#!/bin/sh\n\n## Example in bash using STDIN signaling\n\ncounter=0\n\nwhile read -r _; do\n    echo \"counter_bash count=${counter}\"\n    counter=$((counter+1))\ndone\n\ntrap \"echo terminate 1>&2\" EXIT\n"
  },
  {
    "path": "plugins/inputs/execd/execd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage execd\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/process\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype Execd struct {\n\tCommand      []string        `toml:\"command\"`\n\tEnvironment  []string        `toml:\"environment\"`\n\tBufferSize   config.Size     `toml:\"buffer_size\"`\n\tSignal       string          `toml:\"signal\"`\n\tRestartDelay config.Duration `toml:\"restart_delay\"`\n\tStopOnError  bool            `toml:\"stop_on_error\"`\n\tLog          telegraf.Logger `toml:\"-\"`\n\n\tprocess      *process.Process\n\tacc          telegraf.Accumulator\n\tparser       telegraf.Parser\n\toutputReader func(io.Reader)\n}\n\nfunc (*Execd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (e *Execd) Init() error {\n\tif len(e.Command) == 0 {\n\t\treturn errors.New(\"no command specified\")\n\t}\n\treturn nil\n}\n\nfunc (e *Execd) SetParser(parser telegraf.Parser) {\n\te.parser = parser\n\te.outputReader = e.cmdReadOut\n\n\tunwrapped, ok := parser.(*models.RunningParser)\n\tif ok {\n\t\tif _, ok := unwrapped.Parser.(*influx.Parser); ok {\n\t\t\te.outputReader = e.cmdReadOutStream\n\t\t}\n\t}\n}\n\nfunc (e *Execd) Start(acc telegraf.Accumulator) error {\n\te.acc = acc\n\tvar err error\n\te.process, err = process.New(e.Command, e.Environment)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating new process: %w\", err)\n\t}\n\te.process.ReadStdoutFn = e.outputReader\n\te.process.ReadStderrFn = e.cmdReadErr\n\te.process.RestartDelay = time.Duration(e.RestartDelay)\n\te.process.StopOnError = e.StopOnError\n\te.process.Log = e.Log\n\n\tif err = e.process.Start(); err != nil {\n\t\t// if there was only one argument, and it contained spaces, warn the user\n\t\t// that they may have configured it wrong.\n\t\tif len(e.Command) == 1 && strings.Contains(e.Command[0], \" \") {\n\t\t\te.Log.Warn(\"The inputs.execd Command contained spaces but no arguments. \" +\n\t\t\t\t\"This setting expects the program and arguments as an array of strings, \" +\n\t\t\t\t\"not as a space-delimited string. See the plugin readme for an example.\")\n\t\t}\n\t\treturn fmt.Errorf(\"failed to start process %s: %w\", e.Command, err)\n\t}\n\n\treturn nil\n}\n\nfunc (e *Execd) Stop() {\n\te.process.Stop()\n}\n\nfunc (e *Execd) cmdReadOut(out io.Reader) {\n\trdr := bufio.NewReaderSize(out, int(e.BufferSize))\n\n\tfor {\n\t\tdata, err := rdr.ReadBytes('\\n')\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) || errors.Is(err, os.ErrClosed) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\te.acc.AddError(fmt.Errorf(\"error reading stdout: %w\", err))\n\t\t\tcontinue\n\t\t}\n\n\t\tmetrics, err := e.parser.Parse(data)\n\t\tif err != nil {\n\t\t\te.acc.AddError(fmt.Errorf(\"parse error: %w\", err))\n\t\t}\n\n\t\tif len(metrics) == 0 {\n\t\t\tonce.Do(func() {\n\t\t\t\te.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t\t})\n\t\t}\n\n\t\tfor _, metric := range metrics {\n\t\t\te.acc.AddMetric(metric)\n\t\t}\n\t}\n}\n\nfunc (e *Execd) cmdReadOutStream(out io.Reader) {\n\tparser := influx.NewStreamParser(out)\n\n\tfor {\n\t\tmetric, err := parser.Next()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, influx.EOF) {\n\t\t\t\tbreak // stream ended\n\t\t\t}\n\t\t\tvar parseErr *influx.ParseError\n\t\t\tif errors.As(err, &parseErr) {\n\t\t\t\t// parse error.\n\t\t\t\te.acc.AddError(parseErr)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// some non-recoverable error?\n\t\t\te.acc.AddError(err)\n\t\t\treturn\n\t\t}\n\n\t\te.acc.AddMetric(metric)\n\t}\n}\n\nfunc (e *Execd) cmdReadErr(out io.Reader) {\n\tscanner := bufio.NewScanner(out)\n\n\tfor scanner.Scan() {\n\t\tmsg := scanner.Text()\n\t\tswitch {\n\t\tcase strings.HasPrefix(msg, \"E! \"):\n\t\t\te.Log.Error(msg[3:])\n\t\tcase strings.HasPrefix(msg, \"W! \"):\n\t\t\te.Log.Warn(msg[3:])\n\t\tcase strings.HasPrefix(msg, \"I! \"):\n\t\t\te.Log.Info(msg[3:])\n\t\tcase strings.HasPrefix(msg, \"D! \"):\n\t\t\te.Log.Debug(msg[3:])\n\t\tcase strings.HasPrefix(msg, \"T! \"):\n\t\t\te.Log.Trace(msg[3:])\n\t\tdefault:\n\t\t\te.Log.Errorf(\"stderr: %q\", msg)\n\t\t}\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\te.acc.AddError(fmt.Errorf(\"error reading stderr: %w\", err))\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"execd\", func() telegraf.Input {\n\t\treturn &Execd{\n\t\t\tSignal:       \"none\",\n\t\t\tRestartDelay: config.Duration(10 * time.Second),\n\t\t\tBufferSize:   config.Size(64 * 1024),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/execd/execd_posix.go",
    "content": "//go:build !windows\n\npackage execd\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc (e *Execd) Gather(_ telegraf.Accumulator) error {\n\tif e.process == nil || e.process.Cmd == nil {\n\t\treturn nil\n\t}\n\n\tosProcess := e.process.Cmd.Process\n\tif osProcess == nil {\n\t\treturn nil\n\t}\n\tswitch e.Signal {\n\tcase \"SIGHUP\":\n\t\treturn osProcess.Signal(syscall.SIGHUP)\n\tcase \"SIGUSR1\":\n\t\treturn osProcess.Signal(syscall.SIGUSR1)\n\tcase \"SIGUSR2\":\n\t\treturn osProcess.Signal(syscall.SIGUSR2)\n\tcase \"STDIN\":\n\t\tif osStdin, ok := e.process.Stdin.(*os.File); ok {\n\t\t\tif err := osStdin.SetWriteDeadline(time.Now().Add(1 * time.Second)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting write deadline failed: %w\", err)\n\t\t\t}\n\t\t}\n\t\tif _, err := io.WriteString(e.process.Stdin, \"\\n\"); err != nil {\n\t\t\treturn fmt.Errorf(\"writing to stdin failed: %w\", err)\n\t\t}\n\tcase \"none\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid signal: %s\", e.Signal)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/execd/execd_test.go",
    "content": "package execd\n\nimport (\n\t\"bufio\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/logger\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/prometheus\"\n\tserializers_influx \"github.com/influxdata/telegraf/plugins/serializers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSettingConfigWorks(t *testing.T) {\n\tcfg := `\n\t[[inputs.execd]]\n\t\tcommand = [\"a\", \"b\", \"c\"]\n\t\tenvironment = [\"d=e\", \"f=1\"]\n\t\trestart_delay = \"1m\"\n\t\tsignal = \"SIGHUP\"\n\t`\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfigData([]byte(cfg), config.EmptySourcePath))\n\n\trequire.Len(t, conf.Inputs, 1)\n\tinp, ok := conf.Inputs[0].Input.(*Execd)\n\trequire.True(t, ok)\n\trequire.EqualValues(t, []string{\"a\", \"b\", \"c\"}, inp.Command)\n\trequire.EqualValues(t, []string{\"d=e\", \"f=1\"}, inp.Environment)\n\trequire.EqualValues(t, 1*time.Minute, inp.RestartDelay)\n\trequire.EqualValues(t, \"SIGHUP\", inp.Signal)\n}\n\nfunc TestExternalInputWorks(t *testing.T) {\n\tinfluxParser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, influxParser.Init())\n\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\te := &Execd{\n\t\tCommand:      []string{exe, \"-mode\", \"counter\"},\n\t\tEnvironment:  []string{\"PLUGINS_INPUTS_EXECD_MODE=application\", \"METRIC_NAME=counter\"},\n\t\tRestartDelay: config.Duration(5 * time.Second),\n\t\tSignal:       \"STDIN\",\n\t\tLog:          testutil.Logger{},\n\t}\n\te.SetParser(influxParser)\n\n\tmetrics := make(chan telegraf.Metric, 10)\n\tdefer close(metrics)\n\tacc := agent.NewAccumulator(&TestMetricMaker{}, metrics)\n\n\trequire.NoError(t, e.Start(acc))\n\trequire.NoError(t, e.Gather(acc))\n\n\t// grab a metric and make sure it's a thing\n\tm := readChanWithTimeout(t, metrics, 10*time.Second)\n\n\te.Stop()\n\n\trequire.Equal(t, \"counter\", m.Name())\n\tval, ok := m.GetField(\"count\")\n\trequire.True(t, ok)\n\trequire.EqualValues(t, 0, val)\n}\n\nfunc TestParsesLinesContainingNewline(t *testing.T) {\n\tparser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, parser.Init())\n\n\tmetrics := make(chan telegraf.Metric, 10)\n\tdefer close(metrics)\n\tacc := agent.NewAccumulator(&TestMetricMaker{}, metrics)\n\n\te := &Execd{\n\t\tRestartDelay: config.Duration(5 * time.Second),\n\t\tSignal:       \"STDIN\",\n\t\tacc:          acc,\n\t\tLog:          testutil.Logger{},\n\t}\n\te.SetParser(parser)\n\n\tcases := []struct {\n\t\tName  string\n\t\tValue string\n\t}{\n\t\t{\n\t\t\tName:  \"no-newline\",\n\t\t\tValue: \"my message\",\n\t\t}, {\n\t\t\tName:  \"newline\",\n\t\t\tValue: \"my\\nmessage\",\n\t\t},\n\t}\n\n\tfor _, test := range cases {\n\t\tt.Run(test.Name, func(t *testing.T) {\n\t\t\tline := fmt.Sprintf(\"event message=\\\"%v\\\" 1587128639239000000\", test.Value)\n\n\t\t\te.outputReader(strings.NewReader(line))\n\n\t\t\tm := readChanWithTimeout(t, metrics, 1*time.Second)\n\n\t\t\trequire.Equal(t, \"event\", m.Name())\n\t\t\tval, ok := m.GetField(\"message\")\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, test.Value, val)\n\t\t})\n\t}\n}\n\nfunc TestParsesPrometheus(t *testing.T) {\n\tparser := models.NewRunningParser(&prometheus.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, parser.Init())\n\n\tmetrics := make(chan telegraf.Metric, 10)\n\tdefer close(metrics)\n\n\tvar acc testutil.Accumulator\n\n\te := &Execd{\n\t\tRestartDelay: config.Duration(5 * time.Second),\n\t\tSignal:       \"STDIN\",\n\t\tacc:          &acc,\n\t\tLog:          testutil.Logger{},\n\t}\n\te.SetParser(parser)\n\n\tlines := `# HELP This is just a test metric.\n# TYPE test summary\ntest{handler=\"execd\",quantile=\"0.5\"} 42.0\n`\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"prometheus\",\n\t\t\tmap[string]string{\"handler\": \"execd\", \"quantile\": \"0.5\"},\n\t\t\tmap[string]interface{}{\"test\": float64(42.0)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\te.outputReader(strings.NewReader(lines))\n\tcheck := func() bool { return acc.NMetrics() == uint64(len(expected)) }\n\trequire.Eventually(t, check, 1*time.Second, 100*time.Millisecond)\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestStopOnError(t *testing.T) {\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\tplugin := &Execd{\n\t\tCommand:      []string{exe, \"-mode\", \"fail\"},\n\t\tEnvironment:  []string{\"PLUGINS_INPUTS_EXECD_MODE=application\"},\n\t\tStopOnError:  true,\n\t\tRestartDelay: config.Duration(5 * time.Second),\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.Eventually(t, func() bool {\n\t\t_, running := plugin.process.State()\n\t\treturn !running\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tstate, running := plugin.process.State()\n\trequire.False(t, running)\n\trequire.Equal(t, 42, state.ExitCode())\n}\n\nfunc TestStopOnErrorSuccess(t *testing.T) {\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\tplugin := &Execd{\n\t\tCommand:      []string{exe, \"-mode\", \"success\"},\n\t\tEnvironment:  []string{\"PLUGINS_INPUTS_EXECD_MODE=application\"},\n\t\tStopOnError:  true,\n\t\tRestartDelay: config.Duration(100 * time.Millisecond),\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tparser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Wait for at least two metric as this indicates the process was restarted\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() > 1\n\t}, 3*time.Second, 100*time.Millisecond)\n}\n\nfunc TestLoggingNoPrefix(t *testing.T) {\n\t// Use own test as mocking executable\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\t// Setup the plugin with a capturing logger\n\tvar l testutil.CaptureLogger\n\tplugin := &Execd{\n\t\tCommand: []string{exe, \"-mode\", \"logging\"},\n\t\tEnvironment: []string{\n\t\t\t\"PLUGINS_INPUTS_EXECD_MODE=application\",\n\t\t\t\"MESSAGE=this is an error\",\n\t\t},\n\t\tSignal:       \"STDIN\",\n\t\tStopOnError:  true,\n\t\tRestartDelay: config.Duration(100 * time.Millisecond),\n\t\tLog:          &l,\n\t}\n\n\tparser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Run the plugin and trigger a report\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\n\t// Wait for at least two metric as this indicates the process was restarted\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() > 0 && l.NMessages() > 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Check the metric\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": int64(0)}, time.Unix(0, 0)),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t// Check the error message type\n\texpectedLevel := byte(testutil.LevelError)\n\tlevels := make(map[byte]int, 0)\n\tfor _, m := range l.Messages() {\n\t\tif strings.HasPrefix(m.Text, \"Starting process\") || strings.HasSuffix(m.Text, \"shut down\") {\n\t\t\tcontinue\n\t\t}\n\t\tif m.Level != expectedLevel {\n\t\t\tt.Logf(\"received msg %q (%s)\", m.Text, string(m.Level))\n\t\t} else {\n\t\t\trequire.Equal(t, \"stderr: \\\"this is an error\\\"\", m.Text)\n\t\t}\n\t\tlevels[m.Level]++\n\t}\n\trequire.Equal(t, 1, levels[testutil.LevelError])\n\trequire.Len(t, levels, 1)\n}\n\nfunc TestLoggingWithPrefix(t *testing.T) {\n\t// Use own test as mocking executable\n\texe, err := os.Executable()\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname  string\n\t\tlevel byte\n\t}{\n\t\t{\"error\", testutil.LevelError},\n\t\t{\"warn\", testutil.LevelWarn},\n\t\t{\"info\", testutil.LevelInfo},\n\t\t{\"debug\", testutil.LevelDebug},\n\t\t{\"trace\", testutil.LevelTrace},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin with a capturing logger\n\t\t\tvar l testutil.CaptureLogger\n\t\t\tplugin := &Execd{\n\t\t\t\tCommand: []string{exe, \"-mode\", \"logging\"},\n\t\t\t\tEnvironment: []string{\n\t\t\t\t\t\"PLUGINS_INPUTS_EXECD_MODE=application\",\n\t\t\t\t\tfmt.Sprintf(\"MESSAGE=%s! a log message\", string(tt.level)),\n\t\t\t\t},\n\t\t\t\tSignal:       \"STDIN\",\n\t\t\t\tStopOnError:  true,\n\t\t\t\tRestartDelay: config.Duration(100 * time.Millisecond),\n\t\t\t\tLog:          &l,\n\t\t\t}\n\n\t\t\tparser := models.NewRunningParser(&influx.Parser{}, &models.ParserConfig{})\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tplugin.SetParser(parser)\n\n\t\t\t// Run the plugin and trigger a report\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tplugin.Stop()\n\n\t\t\t// Wait for at least two metric as this indicates the process was restarted\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() > 0 && l.NMessages() > 0\n\t\t\t}, 3*time.Second, 100*time.Millisecond)\n\n\t\t\t// Check the metric\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\tmetric.New(\"test\", map[string]string{}, map[string]interface{}{\"value\": int64(0)}, time.Unix(0, 0)),\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t\t\t// Check the error message type\n\t\t\texpectedLevel := tt.level\n\t\t\tlevels := make(map[byte]int, 0)\n\t\t\tfor _, m := range l.Messages() {\n\t\t\t\tif strings.HasPrefix(m.Text, \"Starting process\") || strings.HasSuffix(m.Text, \"shut down\") {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif m.Level != expectedLevel {\n\t\t\t\t\tt.Logf(\"received msg %q (%s)\", m.Text, string(m.Level))\n\t\t\t\t} else {\n\t\t\t\t\trequire.Equal(t, \"a log message\", m.Text)\n\t\t\t\t}\n\t\t\t\tlevels[m.Level]++\n\t\t\t}\n\t\t\trequire.Equal(t, 1, levels[tt.level])\n\t\t\trequire.Len(t, levels, 1)\n\t\t})\n\t}\n}\n\nfunc readChanWithTimeout(t *testing.T, metrics chan telegraf.Metric, timeout time.Duration) telegraf.Metric {\n\tto := time.NewTimer(timeout)\n\tdefer to.Stop()\n\tselect {\n\tcase m := <-metrics:\n\t\treturn m\n\tcase <-to.C:\n\t\trequire.Fail(t, \"Timeout waiting for metric\")\n\t}\n\treturn nil\n}\n\ntype TestMetricMaker struct{}\n\nfunc (*TestMetricMaker) Name() string {\n\treturn \"TestPlugin\"\n}\n\nfunc (tm *TestMetricMaker) LogName() string {\n\treturn tm.Name()\n}\n\nfunc (*TestMetricMaker) MakeMetric(aMetric telegraf.Metric) telegraf.Metric {\n\treturn aMetric\n}\n\nfunc (*TestMetricMaker) Log() telegraf.Logger {\n\treturn logger.New(\"TestPlugin\", \"test\", \"\")\n}\n\nfunc TestMain(m *testing.M) {\n\tvar mode string\n\n\tflag.StringVar(&mode, \"mode\", \"counter\", \"determines the output when run as mockup program\")\n\tflag.Parse()\n\n\toperationMode := os.Getenv(\"PLUGINS_INPUTS_EXECD_MODE\")\n\tif operationMode != \"application\" {\n\t\t// Run the normal test mode\n\t\tos.Exit(m.Run())\n\t}\n\n\t// Run as a mock program\n\tswitch mode {\n\tcase \"counter\":\n\t\tif err := runCounterProgram(); err != nil {\n\t\t\tos.Exit(1)\n\t\t}\n\t\tos.Exit(0)\n\tcase \"fail\":\n\t\tos.Exit(42)\n\tcase \"success\":\n\t\tfmt.Println(\"test value=42i\")\n\t\tos.Exit(0)\n\tcase \"logging\":\n\t\tif err := runLoggingProgram(); err != nil {\n\t\t\tos.Exit(1)\n\t\t}\n\t\tos.Exit(0)\n\t}\n\tos.Exit(23)\n}\n\nfunc runCounterProgram() error {\n\tenvMetricName := os.Getenv(\"METRIC_NAME\")\n\tserializer := &serializers_influx.Serializer{}\n\tif err := serializer.Init(); err != nil {\n\t\treturn err\n\t}\n\n\ti := 0\n\tscanner := bufio.NewScanner(os.Stdin)\n\tfor scanner.Scan() {\n\t\tm := metric.New(envMetricName,\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"count\": i},\n\t\t\ttime.Now(),\n\t\t)\n\t\ti++\n\n\t\tb, err := serializer.Serialize(m)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"ERR %v\\n\", err)\n\t\t\treturn err\n\t\t}\n\t\tif _, err := fmt.Fprint(os.Stdout, string(b)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc runLoggingProgram() error {\n\tmsg := os.Getenv(\"MESSAGE\")\n\n\ti := 0\n\tscanner := bufio.NewScanner(os.Stdin)\n\tfor scanner.Scan() {\n\t\tif _, err := fmt.Fprintf(os.Stdout, \"test value=%di\\n\", i); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif msg != \"\" {\n\t\t\tif _, err := fmt.Fprintln(os.Stderr, msg); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/execd/execd_windows.go",
    "content": "//go:build windows\n\npackage execd\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc (e *Execd) Gather(_ telegraf.Accumulator) error {\n\tif e.process == nil {\n\t\treturn nil\n\t}\n\n\tswitch e.Signal {\n\tcase \"STDIN\":\n\t\tif osStdin, ok := e.process.Stdin.(*os.File); ok {\n\t\t\tif err := osStdin.SetWriteDeadline(time.Now().Add(1 * time.Second)); err != nil {\n\t\t\t\tif !errors.Is(err, os.ErrNoDeadline) {\n\t\t\t\t\treturn fmt.Errorf(\"setting write deadline failed: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif _, err := io.WriteString(e.process.Stdin, \"\\n\"); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing to stdin: %w\", err)\n\t\t}\n\tcase \"none\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid signal: %s\", e.Signal)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/execd/sample.conf",
    "content": "# Run executable as long-running input plugin\n[[inputs.execd]]\n  ## One program to run as daemon.\n  ## NOTE: process and each argument should each be their own string\n  command = [\"telegraf-smartctl\", \"-d\", \"/dev/sda\"]\n\n  ## Environment variables\n  ## Array of \"key=value\" pairs to pass as environment variables\n  ## e.g. \"KEY=value\", \"USERNAME=John Doe\",\n  ## \"LD_LIBRARY_PATH=/opt/custom/lib64:/usr/local/libs\"\n  # environment = []\n\n  ## Define how the process is signaled on each collection interval.\n  ## Valid values are:\n  ##   \"none\"    : Do not signal anything. (Recommended for service inputs)\n  ##               The process must output metrics by itself.\n  ##   \"STDIN\"   : Send a newline on STDIN. (Recommended for gather inputs)\n  ##   \"SIGHUP\"  : Send a HUP signal. Not available on Windows. (not recommended)\n  ##   \"SIGUSR1\" : Send a USR1 signal. Not available on Windows.\n  ##   \"SIGUSR2\" : Send a USR2 signal. Not available on Windows.\n  # signal = \"none\"\n\n  ## Delay before the process is restarted after an unexpected termination\n  # restart_delay = \"10s\"\n\n  ## Buffer size used to read from the command output stream\n  ## Optional parameter. Default is 64 Kib, minimum is 16 bytes\n  # buffer_size = \"64Kib\"\n\n  ## Disable automatic restart of the program and stop if the program exits\n  ## with an error (non-zero error code)\n  # stop_on_error = false\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/execd/shim/README.md",
    "content": "# Telegraf Execd Go Shim\n\nThis is deprecated. Please see [/plugins/common/shim/README.md](https://github.com/influxdata/telegraf/tree/master/plugins/common/shim/README.md)\n"
  },
  {
    "path": "plugins/inputs/execd/shim/example/cmd/main.go",
    "content": "package main\n\n// see /plugins/common/shim/example/cmd/main.go instead.\n"
  },
  {
    "path": "plugins/inputs/execd/shim/example/cmd/plugin.conf",
    "content": "[[inputs.my_plugin_name]]\n\tvalue_name = \"value\"\n"
  },
  {
    "path": "plugins/inputs/execd/shim/goshim.go",
    "content": "package shim\n\n// this package is deprecated. use plugins/common/shim instead\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/BurntSushi/toml\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/agent\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/influx\"\n)\n\nvar (\n\tenvVarEscaper = strings.NewReplacer(\n\t\t`\"`, `\\\"`,\n\t\t`\\`, `\\\\`,\n\t)\n\toldpkg = \"github.com/influxdata/telegraf/plugins/inputs/execd/shim\"\n\tnewpkg = \"github.com/influxdata/telegraf/plugins/common/shim\"\n)\n\nconst (\n\t// PollIntervalDisabled is used to indicate that you want to disable polling,\n\t// as opposed to duration 0 meaning poll constantly.\n\tPollIntervalDisabled = time.Duration(0)\n)\n\n// Shim allows you to wrap your inputs and run them as if they were part of Telegraf,\n// except built externally.\ntype Shim struct {\n\tInputs            []telegraf.Input\n\tgatherPromptChans []chan empty\n\tmetricCh          chan telegraf.Metric\n\n\tstdin  io.Reader\n\tstdout io.Writer\n\tstderr io.Writer\n}\n\ntype empty struct{}\n\n// New creates a new shim interface\nfunc New() *Shim {\n\tfmt.Fprintf(os.Stderr, \"%s is deprecated; please change your import to %s\\n\", oldpkg, newpkg)\n\treturn &Shim{\n\t\tstdin:  os.Stdin,\n\t\tstdout: os.Stdout,\n\t\tstderr: os.Stderr,\n\t}\n}\n\n// AddInput adds the input to the shim. Later calls to Run() will run this input.\nfunc (s *Shim) AddInput(input telegraf.Input) error {\n\tif p, ok := input.(telegraf.Initializer); ok {\n\t\terr := p.Init()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to init input: %w\", err)\n\t\t}\n\t}\n\n\ts.Inputs = append(s.Inputs, input)\n\treturn nil\n}\n\n// AddInputs adds multiple inputs to the shim. Later calls to Run() will run these.\nfunc (s *Shim) AddInputs(newInputs []telegraf.Input) error {\n\tfor _, inp := range newInputs {\n\t\tif err := s.AddInput(inp); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Run the input plugins..\nfunc (s *Shim) Run(pollInterval time.Duration) error {\n\t// context is used only to close the stdin reader. everything else cascades\n\t// from that point and closes cleanly when it's done.\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\ts.metricCh = make(chan telegraf.Metric, 1)\n\n\twg := sync.WaitGroup{}\n\tquit := make(chan os.Signal, 1)\n\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n\tcollectMetricsPrompt := make(chan os.Signal, 1)\n\tlistenForCollectMetricsSignals(ctx, collectMetricsPrompt)\n\n\tserializer := &influx.Serializer{}\n\tif err := serializer.Init(); err != nil {\n\t\treturn fmt.Errorf(\"creating serializer failed: %w\", err)\n\t}\n\n\tfor _, input := range s.Inputs {\n\t\twrappedInput := inputShim{Input: input}\n\n\t\tacc := agent.NewAccumulator(wrappedInput, s.metricCh)\n\t\tacc.SetPrecision(time.Nanosecond)\n\n\t\tif serviceInput, ok := input.(telegraf.ServiceInput); ok {\n\t\t\tif err := serviceInput.Start(acc); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to start input: %w\", err)\n\t\t\t}\n\t\t}\n\t\tgatherPromptCh := make(chan empty, 1)\n\t\ts.gatherPromptChans = append(s.gatherPromptChans, gatherPromptCh)\n\t\twg.Add(1) // one per input\n\t\tgo func(input telegraf.Input) {\n\t\t\ts.startGathering(ctx, input, acc, gatherPromptCh, pollInterval)\n\t\t\tif serviceInput, ok := input.(telegraf.ServiceInput); ok {\n\t\t\t\tserviceInput.Stop()\n\t\t\t}\n\t\t\tclose(gatherPromptCh)\n\t\t\twg.Done()\n\t\t}(input)\n\t}\n\n\tgo s.stdinCollectMetricsPrompt(ctx, cancel, collectMetricsPrompt)\n\tgo s.closeMetricChannelWhenInputsFinish(&wg)\n\nloop:\n\tfor {\n\t\tselect {\n\t\tcase <-quit: // user-triggered quit\n\t\t\t// cancel, but keep looping until the metric channel closes.\n\t\t\tcancel()\n\t\tcase _, open := <-collectMetricsPrompt:\n\t\t\tif !open { // stdin-close-triggered quit\n\t\t\t\tcancel()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ts.collectMetrics(ctx)\n\t\tcase m, open := <-s.metricCh:\n\t\t\tif !open {\n\t\t\t\tbreak loop\n\t\t\t}\n\t\t\tb, err := serializer.Serialize(m)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to serialize metric: %w\", err)\n\t\t\t}\n\t\t\t// Write this to stdout\n\t\t\tif _, err := fmt.Fprint(s.stdout, string(b)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write %q to stdout: %w\", string(b), err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// LoadConfig loads and adds the inputs to the shim\nfunc (s *Shim) LoadConfig(filePath *string) error {\n\tloadedInputs, err := LoadConfig(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn s.AddInputs(loadedInputs)\n}\n\n// DefaultImportedPlugins defaults to whatever plugins happen to be loaded and\n// have registered themselves with the registry. This makes loading plugins\n// without having to define a config dead easy.\nfunc DefaultImportedPlugins() (i []telegraf.Input, e error) {\n\tfor _, inputCreatorFunc := range inputs.Inputs {\n\t\ti = append(i, inputCreatorFunc())\n\t}\n\treturn i, nil\n}\n\n// LoadConfig loads the config and returns inputs that later need to be loaded.\nfunc LoadConfig(filePath *string) ([]telegraf.Input, error) {\n\tif filePath == nil || *filePath == \"\" {\n\t\treturn DefaultImportedPlugins()\n\t}\n\n\tb, err := os.ReadFile(*filePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ts := expandEnvVars(b)\n\n\tconf := struct {\n\t\tInputs map[string][]toml.Primitive\n\t}{}\n\n\tmd, err := toml.Decode(s, &conf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn loadConfigIntoInputs(md, conf.Inputs)\n}\n\nfunc hasQuit(ctx context.Context) bool {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (s *Shim) stdinCollectMetricsPrompt(ctx context.Context, cancel context.CancelFunc, collectMetricsPrompt chan<- os.Signal) {\n\tdefer func() {\n\t\tcancel()\n\t\tclose(collectMetricsPrompt)\n\t}()\n\n\tscanner := bufio.NewScanner(s.stdin)\n\t// for every line read from stdin, make sure we're not supposed to quit,\n\t// then push a message on to the collectMetricsPrompt\n\tfor scanner.Scan() {\n\t\t// first check if we should quit\n\t\tif hasQuit(ctx) {\n\t\t\treturn\n\t\t}\n\n\t\t// now push a non-blocking message to trigger metric collection.\n\t\tpushCollectMetricsRequest(collectMetricsPrompt)\n\t}\n}\n\n// pushCollectMetricsRequest pushes a non-blocking (nil) message to the\n// collectMetricsPrompt channel to trigger metric collection.\n// The channel is defined with a buffer of 1, so while it's full, subsequent\n// requests are discarded.\nfunc pushCollectMetricsRequest(collectMetricsPrompt chan<- os.Signal) {\n\tselect {\n\tcase collectMetricsPrompt <- nil:\n\tdefault:\n\t}\n}\n\nfunc (s *Shim) collectMetrics(ctx context.Context) {\n\tif hasQuit(ctx) {\n\t\treturn\n\t}\n\tfor i := 0; i < len(s.gatherPromptChans); i++ {\n\t\t// push a message out to each channel to collect metrics. don't block.\n\t\tselect {\n\t\tcase s.gatherPromptChans[i] <- empty{}:\n\t\tdefault:\n\t\t}\n\t}\n}\n\nfunc (s *Shim) startGathering(ctx context.Context, input telegraf.Input, acc telegraf.Accumulator, gatherPromptCh <-chan empty, pollInterval time.Duration) {\n\tif pollInterval == PollIntervalDisabled {\n\t\treturn // don't poll\n\t}\n\tt := time.NewTicker(pollInterval)\n\tdefer t.Stop()\n\tfor {\n\t\t// give priority to stopping.\n\t\tif hasQuit(ctx) {\n\t\t\treturn\n\t\t}\n\t\t// see what's up\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-gatherPromptCh:\n\t\t\tif err := input.Gather(acc); err != nil {\n\t\t\t\tif _, perr := fmt.Fprintf(s.stderr, \"failed to gather metrics: %s\", err); perr != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tacc.AddError(perr)\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-t.C:\n\t\t\tif err := input.Gather(acc); err != nil {\n\t\t\t\tif _, perr := fmt.Fprintf(s.stderr, \"failed to gather metrics: %s\", err); perr != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\tacc.AddError(perr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc expandEnvVars(contents []byte) string {\n\treturn os.Expand(string(contents), getEnv)\n}\n\nfunc getEnv(key string) string {\n\tv := os.Getenv(key)\n\n\treturn envVarEscaper.Replace(v)\n}\n\nfunc loadConfigIntoInputs(md toml.MetaData, inputConfigs map[string][]toml.Primitive) ([]telegraf.Input, error) {\n\trenderedInputs := make([]telegraf.Input, 0, len(inputConfigs))\n\tfor name, primitives := range inputConfigs {\n\t\tinputCreator, ok := inputs.Inputs[name]\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"unknown input \" + name)\n\t\t}\n\n\t\tfor _, primitive := range primitives {\n\t\t\tinp := inputCreator()\n\t\t\t// Parse specific configuration\n\t\t\tif err := md.PrimitiveDecode(primitive, inp); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\trenderedInputs = append(renderedInputs, inp)\n\t\t}\n\t}\n\treturn renderedInputs, nil\n}\n\nfunc (s *Shim) closeMetricChannelWhenInputsFinish(wg *sync.WaitGroup) {\n\twg.Wait()\n\tclose(s.metricCh)\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/goshim_posix.go",
    "content": "//go:build !windows\n\npackage shim\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nfunc listenForCollectMetricsSignals(ctx context.Context, collectMetricsPrompt chan os.Signal) {\n\t// just listen to all the signals.\n\tsignal.Notify(collectMetricsPrompt, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGUSR2)\n\n\tgo func() {\n\t\t<-ctx.Done()\n\t\tsignal.Stop(collectMetricsPrompt)\n\t}()\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/goshim_windows.go",
    "content": "//go:build windows\n\npackage shim\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nfunc listenForCollectMetricsSignals(ctx context.Context, collectMetricsPrompt chan os.Signal) {\n\tsignal.Notify(collectMetricsPrompt, syscall.SIGHUP)\n\n\tgo func() {\n\t\t<-ctx.Done()\n\t\t// context done. stop to signals to avoid pushing messages to a closed channel\n\t\tsignal.Stop(collectMetricsPrompt)\n\t}()\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/input.go",
    "content": "package shim\n\nimport \"github.com/influxdata/telegraf\"\n\n// inputShim implements the MetricMaker interface.\ntype inputShim struct {\n\tInput telegraf.Input\n}\n\n// LogName satisfies the MetricMaker interface\nfunc (inputShim) LogName() string {\n\treturn \"\"\n}\n\n// MakeMetric satisfies the MetricMaker interface\nfunc (inputShim) MakeMetric(m telegraf.Metric) telegraf.Metric {\n\treturn m // don't need to do anything to it.\n}\n\n// Log satisfies the MetricMaker interface\nfunc (inputShim) Log() telegraf.Logger {\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/shim_posix_test.go",
    "content": "//go:build !windows\n\npackage shim\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestShimUSR1SignalingWorks(t *testing.T) {\n\tstdinReader, stdinWriter := io.Pipe()\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\tmetricProcessed, exited := runInputPlugin(t, 20*time.Minute, stdinReader, stdoutWriter, nil)\n\n\t// signal USR1 to yourself.\n\tpid := os.Getpid()\n\tprocess, err := os.FindProcess(pid)\n\trequire.NoError(t, err)\n\n\tgo func() {\n\t\t// On slow machines this signal can fire before the service comes up.\n\t\t// rather than depend on accurate sleep times, we'll just retry sending\n\t\t// the signal every so often until it goes through.\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn // test is done\n\t\t\tdefault:\n\t\t\t\t// test isn't done, keep going.\n\t\t\t\tif err := process.Signal(syscall.SIGUSR1); err != nil {\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\tmetricProcessed <- false\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t}\n\t\t}\n\t}()\n\n\t<-metricProcessed\n\tcancel()\n\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"measurement,tag=tag field=1i 1234000005678\\n\", out)\n\n\trequire.NoError(t, stdinWriter.Close())\n\treadUntilEmpty(r)\n\n\t<-exited\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/shim_test.go",
    "content": "package shim\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nfunc TestShimWorks(t *testing.T) {\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\tstdin, _ := io.Pipe() // hold the stdin pipe open\n\n\tmetricProcessed, _ := runInputPlugin(t, 10*time.Millisecond, stdin, stdoutWriter, nil)\n\n\t<-metricProcessed\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Contains(t, out, \"\\n\")\n\tmetricLine := strings.Split(out, \"\\n\")[0]\n\trequire.Equal(t, \"measurement,tag=tag field=1i 1234000005678\", metricLine)\n}\n\nfunc TestShimStdinSignalingWorks(t *testing.T) {\n\tstdinReader, stdinWriter := io.Pipe()\n\tstdoutReader, stdoutWriter := io.Pipe()\n\n\tmetricProcessed, exited := runInputPlugin(t, 40*time.Second, stdinReader, stdoutWriter, nil)\n\n\t_, err := stdinWriter.Write([]byte(\"\\n\"))\n\trequire.NoError(t, err)\n\n\t<-metricProcessed\n\n\tr := bufio.NewReader(stdoutReader)\n\tout, err := r.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"measurement,tag=tag field=1i 1234000005678\\n\", out)\n\n\trequire.NoError(t, stdinWriter.Close())\n\n\treadUntilEmpty(r)\n\n\t// check that it exits cleanly\n\t<-exited\n}\n\nfunc runInputPlugin(t *testing.T, interval time.Duration, stdin io.Reader, stdout, stderr io.Writer) (processed, exited chan bool) {\n\tprocessed = make(chan bool)\n\texited = make(chan bool)\n\tinp := &testInput{\n\t\tmetricProcessed: processed,\n\t}\n\n\tshim := New()\n\tif stdin != nil {\n\t\tshim.stdin = stdin\n\t}\n\tif stdout != nil {\n\t\tshim.stdout = stdout\n\t}\n\tif stderr != nil {\n\t\tshim.stderr = stderr\n\t}\n\n\trequire.NoError(t, shim.AddInput(inp))\n\tgo func(e chan bool) {\n\t\tif err := shim.Run(interval); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t\te <- true\n\t}(exited)\n\treturn processed, exited\n}\n\ntype testInput struct {\n\tmetricProcessed chan bool\n}\n\nfunc (*testInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (i *testInput) Gather(acc telegraf.Accumulator) error {\n\tacc.AddFields(\"measurement\",\n\t\tmap[string]interface{}{\n\t\t\t\"field\": 1,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"tag\": \"tag\",\n\t\t}, time.Unix(1234, 5678))\n\ti.metricProcessed <- true\n\treturn nil\n}\n\nfunc (*testInput) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (*testInput) Stop() {\n}\n\nfunc TestLoadConfig(t *testing.T) {\n\tt.Setenv(\"SECRET_TOKEN\", \"xxxxxxxxxx\")\n\tt.Setenv(\"SECRET_VALUE\", `test\"\\test`)\n\n\tinputs.Add(\"test\", func() telegraf.Input {\n\t\treturn &serviceInput{}\n\t})\n\n\tc := \"./testdata/plugin.conf\"\n\tloadedInputs, err := LoadConfig(&c)\n\trequire.NoError(t, err)\n\n\tinp := loadedInputs[0].(*serviceInput)\n\n\trequire.Equal(t, \"awesome name\", inp.ServiceName)\n\trequire.Equal(t, \"xxxxxxxxxx\", inp.SecretToken)\n\trequire.Equal(t, `test\"\\test`, inp.SecretValue)\n}\n\ntype serviceInput struct {\n\tServiceName string `toml:\"service_name\"`\n\tSecretToken string `toml:\"secret_token\"`\n\tSecretValue string `toml:\"secret_value\"`\n}\n\nfunc (*serviceInput) SampleConfig() string {\n\treturn \"\"\n}\n\nfunc (*serviceInput) Gather(acc telegraf.Accumulator) error {\n\tacc.AddFields(\"measurement\",\n\t\tmap[string]interface{}{\n\t\t\t\"field\": 1,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"tag\": \"tag\",\n\t\t}, time.Unix(1234, 5678))\n\n\treturn nil\n}\n\nfunc (*serviceInput) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (*serviceInput) Stop() {\n}\n\n// we can get stuck if stdout gets clogged up and nobody's reading from it.\n// make sure we keep it going\nfunc readUntilEmpty(r *bufio.Reader) {\n\tgo func() {\n\t\tvar err error\n\t\tfor err != io.EOF {\n\t\t\t_, err = r.ReadString('\\n')\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "plugins/inputs/execd/shim/testdata/plugin.conf",
    "content": "[[inputs.test]]\n\tservice_name = \"awesome name\"\n\tsecret_token = \"${SECRET_TOKEN}\"\n\tsecret_value = \"$SECRET_VALUE\"\n"
  },
  {
    "path": "plugins/inputs/fail2ban/README.md",
    "content": "# Fail2ban Input Plugin\n\nThis plugin gathers the count of failed and banned IP addresses using\n[fail2ban][fail2ban] by running the `fail2ban-client` command.\n\n> [!NOTE]\n> The `fail2ban-client` requires root access, so please make sure to either\n> allow Telegraf to run that command using `sudo` without a password or by\n> running telegraf as root (not recommended).\n\n⭐ Telegraf v1.4.0\n🏷️ network, system\n💻 all\n\n[fail2ban]: https://www.fail2ban.org\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from fail2ban.\n[[inputs.fail2ban]]\n  ## Use sudo to run fail2ban-client\n  # use_sudo = false\n\n  ## Use the given socket instead of the default one\n  # socket = \"/var/run/fail2ban/fail2ban.sock\"\n```\n\n## Using sudo\n\nMake sure to set `use_sudo = true` in your configuration file.\n\nYou will also need to update your sudoers file.  It is recommended to modify a\nfile in the `/etc/sudoers.d` directory using `visudo`:\n\n```bash\nsudo visudo -f /etc/sudoers.d/telegraf\n```\n\nAdd the following lines to the file, these commands allow the `telegraf` user\nto call `fail2ban-client` without needing to provide a password and disables\nlogging of the call in the auth.log.  Consult `man 8 visudo` and `man 5\nsudoers` for details.\n\n```text\nCmnd_Alias FAIL2BAN = /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *\ntelegraf  ALL=(root) NOEXEC: NOPASSWD: FAIL2BAN\nDefaults!FAIL2BAN !logfile, !syslog, !pam_session\n```\n\n## Metrics\n\n- fail2ban\n  - tags:\n    - jail\n  - fields:\n    - failed (integer, count)\n    - banned (integer, count)\n\n## Example Output\n\n```text\nfail2ban,jail=sshd failed=5i,banned=2i 1495868667000000000\n```\n\n### Execute the binary directly\n\n```shell\n# fail2ban-client status sshd\nStatus for the jail: sshd\n|- Filter\n|  |- Currently failed: 5\n|  |- Total failed:     20\n|  `- File list:        /var/log/secure\n`- Actions\n   |- Currently banned: 2\n   |- Total banned:     10\n   `- Banned IP list:   192.168.0.1 192.168.0.2\n```\n"
  },
  {
    "path": "plugins/inputs/fail2ban/fail2ban.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage fail2ban\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\texecCommand    = exec.Command // execCommand is used to mock commands in tests.\n\tmetricsTargets = []struct {\n\t\ttarget string\n\t\tfield  string\n\t}{\n\t\t{\n\t\t\ttarget: \"Currently failed:\",\n\t\t\tfield:  \"failed\",\n\t\t},\n\t\t{\n\t\t\ttarget: \"Currently banned:\",\n\t\t\tfield:  \"banned\",\n\t\t},\n\t}\n)\n\nconst cmd = \"fail2ban-client\"\n\ntype Fail2ban struct {\n\tUseSudo bool   `toml:\"use_sudo\"`\n\tSocket  string `toml:\"socket\"`\n\tpath    string\n}\n\nfunc (*Fail2ban) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *Fail2ban) Init() error {\n\t// Set defaults\n\tif f.path == \"\" {\n\t\tpath, err := exec.LookPath(cmd)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"looking up %q failed: %w\", cmd, err)\n\t\t}\n\t\tf.path = path\n\t}\n\n\t// Check parameters\n\tif f.path == \"\" {\n\t\treturn fmt.Errorf(\"%q not found\", cmd)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Fail2ban) Gather(acc telegraf.Accumulator) error {\n\tif len(f.path) == 0 {\n\t\treturn errors.New(\"fail2ban-client not found: verify that fail2ban is installed and that fail2ban-client is in your PATH\")\n\t}\n\n\tname := f.path\n\tvar args []string\n\n\tif f.UseSudo {\n\t\tname = \"sudo\"\n\t\targs = append(args, f.path)\n\t}\n\n\tif f.Socket != \"\" {\n\t\targs = append(args, \"--socket\", f.Socket)\n\t}\n\targs = append(args, \"status\")\n\n\tcmd := execCommand(name, args...)\n\tout, err := cmd.Output()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to run command %q: %w - %s\", strings.Join(cmd.Args, \" \"), err, string(out))\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\tconst targetString = \"Jail list:\"\n\tvar jails []string\n\tfor _, line := range lines {\n\t\tidx := strings.LastIndex(line, targetString)\n\t\tif idx < 0 {\n\t\t\t// not target line, skip.\n\t\t\tcontinue\n\t\t}\n\t\tjails = strings.Split(strings.TrimSpace(line[idx+len(targetString):]), \", \")\n\t\tbreak\n\t}\n\n\tfor _, jail := range jails {\n\t\t// Skip over empty jails\n\t\tif jail == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tcmd := execCommand(name, append(args, jail)...)\n\t\tout, err := cmd.Output()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to run command %q: %w - %s\", strings.Join(cmd.Args, \" \"), err, string(out))\n\t\t}\n\n\t\tlines := strings.Split(string(out), \"\\n\")\n\t\tfor _, line := range lines {\n\t\t\tkey, value := extractCount(line)\n\t\t\tif key != \"\" {\n\t\t\t\tfields[key] = value\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"fail2ban\", fields, map[string]string{\"jail\": jail})\n\t}\n\treturn nil\n}\n\nfunc extractCount(line string) (string, int) {\n\tfor _, metricsTarget := range metricsTargets {\n\t\tidx := strings.LastIndex(line, metricsTarget.target)\n\t\tif idx < 0 {\n\t\t\tcontinue\n\t\t}\n\t\tban := strings.TrimSpace(line[idx+len(metricsTarget.target):])\n\t\tbanCount, err := strconv.Atoi(ban)\n\t\tif err != nil {\n\t\t\treturn \"\", -1\n\t\t}\n\t\treturn metricsTarget.field, banCount\n\t}\n\treturn \"\", -1\n}\n\nfunc init() {\n\tinputs.Add(\"fail2ban\", func() telegraf.Input {\n\t\treturn &Fail2ban{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/fail2ban/fail2ban_test.go",
    "content": "package fail2ban\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// By all rights, we should use `string literal`, but the string contains \"`\".\nvar execStatusOutput = \"Status\\n\" +\n\t\"|- Number of jail:\\t3\\n\" +\n\t\"`- Jail list:\\tdovecot, postfix, sshd\"\nvar execStatusDovecotOutput = \"Status for the jail: dovecot\\n\" +\n\t\"|- Filter\\n\" +\n\t\"|  |- Currently failed:\\t11\\n\" +\n\t\"|  |- Total failed:\\t22\\n\" +\n\t\"|  `- File list:\\t/var/log/maillog\\n\" +\n\t\"`- Actions\\n\" +\n\t\"   |- Currently banned:\\t0\\n\" +\n\t\"   |- Total banned:\\t100\\n\" +\n\t\"   `- Banned IP list:\"\nvar execStatusPostfixOutput = \"Status for the jail: postfix\\n\" +\n\t\"|- Filter\\n\" +\n\t\"|  |- Currently failed:\\t4\\n\" +\n\t\"|  |- Total failed:\\t10\\n\" +\n\t\"|  `- File list:\\t/var/log/maillog\\n\" +\n\t\"`- Actions\\n\" +\n\t\"   |- Currently banned:\\t3\\n\" +\n\t\"   |- Total banned:\\t60\\n\" +\n\t\"   `- Banned IP list:\\t192.168.10.1 192.168.10.3\"\nvar execStatusSshdOutput = \"Status for the jail: sshd\\n\" +\n\t\"|- Filter\\n\" +\n\t\"|  |- Currently failed:\\t0\\n\" +\n\t\"|  |- Total failed:\\t5\\n\" +\n\t\"|  `- File list:\\t/var/log/secure\\n\" +\n\t\"`- Actions\\n\" +\n\t\"   |- Currently banned:\\t2\\n\" +\n\t\"   |- Total banned:\\t50\\n\" +\n\t\"   `- Banned IP list:\\t192.168.0.1 192.168.1.1\"\n\nfunc TestGather(t *testing.T) {\n\tf := Fail2ban{\n\t\tpath: \"/usr/bin/fail2ban-client\",\n\t}\n\n\texecCommand = fakeExecCommand\n\tdefer func() { execCommand = exec.Command }()\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, f.Init())\n\trequire.NoError(t, f.Gather(&acc))\n\n\tfields1 := map[string]interface{}{\n\t\t\"banned\": 2,\n\t\t\"failed\": 0,\n\t}\n\ttags1 := map[string]string{\n\t\t\"jail\": \"sshd\",\n\t}\n\n\tfields2 := map[string]interface{}{\n\t\t\"banned\": 3,\n\t\t\"failed\": 4,\n\t}\n\ttags2 := map[string]string{\n\t\t\"jail\": \"postfix\",\n\t}\n\n\tfields3 := map[string]interface{}{\n\t\t\"banned\": 0,\n\t\t\"failed\": 11,\n\t}\n\ttags3 := map[string]string{\n\t\t\"jail\": \"dovecot\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"fail2ban\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"fail2ban\", fields2, tags2)\n\tacc.AssertContainsTaggedFields(t, \"fail2ban\", fields3, tags3)\n}\n\nfunc fakeExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestHelperProcess\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\nfunc TestHelperProcess(_ *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\targs := os.Args\n\tcmd, args := args[3], args[4:]\n\n\tif !strings.HasSuffix(cmd, \"fail2ban-client\") {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // os.Exit called intentionally\n\t\tos.Exit(1)\n\t}\n\n\tif len(args) == 1 && args[0] == \"status\" {\n\t\tfmt.Fprint(os.Stdout, execStatusOutput)\n\t\t//nolint:revive // os.Exit called intentionally\n\t\tos.Exit(0)\n\t} else if len(args) == 2 && args[0] == \"status\" {\n\t\tif args[1] == \"sshd\" {\n\t\t\tfmt.Fprint(os.Stdout, execStatusSshdOutput)\n\t\t\t//nolint:revive // os.Exit called intentionally\n\t\t\tos.Exit(0)\n\t\t} else if args[1] == \"postfix\" {\n\t\t\tfmt.Fprint(os.Stdout, execStatusPostfixOutput)\n\t\t\t//nolint:revive // os.Exit called intentionally\n\t\t\tos.Exit(0)\n\t\t} else if args[1] == \"dovecot\" {\n\t\t\tfmt.Fprint(os.Stdout, execStatusDovecotOutput)\n\t\t\t//nolint:revive // os.Exit called intentionally\n\t\t\tos.Exit(0)\n\t\t}\n\t}\n\n\tfmt.Fprint(os.Stdout, \"invalid argument\")\n\t//nolint:revive // os.Exit called intentionally\n\tos.Exit(1)\n}\n"
  },
  {
    "path": "plugins/inputs/fail2ban/sample.conf",
    "content": "# Read metrics from fail2ban.\n[[inputs.fail2ban]]\n  ## Use sudo to run fail2ban-client\n  # use_sudo = false\n\n  ## Use the given socket instead of the default one\n  # socket = \"/var/run/fail2ban/fail2ban.sock\"\n"
  },
  {
    "path": "plugins/inputs/fibaro/README.md",
    "content": "# Fibaro Input Plugin\n\nThis plugin gathers data from devices connected to a [Fibaro][fibaro]\ncontroller. Those values could be true (1) or false (0) for switches, percentage\nfor dimmers, temperature, etc. Both _Home Center 2_ and _Home Center 3_ devices\nare supported.\n\n⭐ Telegraf v1.7.0\n🏷️ iot\n💻 all\n\n[fibaro]: https://www.fibaro.com\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read devices value(s) from a Fibaro controller\n[[inputs.fibaro]]\n  ## Required Fibaro controller address/hostname.\n  ## Note: at the time of writing this plugin, Fibaro only implemented http - no https available\n  url = \"http://<controller>:80\"\n\n  ## Required credentials to access the API (http://<controller/api/<component>)\n  username = \"<username>\"\n  password = \"<password>\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Fibaro Device Type\n  ## By default, this plugin will attempt to read using the HC2 API. For HC3\n  ## devices, set this to \"HC3\"\n  # device_type = \"HC2\"\n```\n\n## Metrics\n\n- fibaro\n  - tags:\n    - deviceId (device id)\n    - section (section name)\n    - room (room name)\n    - name (device name)\n    - type (device type)\n  - fields:\n    - batteryLevel (float, when available from device)\n    - energy (float, when available from device)\n    - power (float, when available from device)\n    - value (float)\n    - value2 (float, when available from device)\n\n## Example Output\n\n```text\nfibaro,deviceId=9,host=vm1,name=Fenêtre\\ haute,room=Cuisine,section=Cuisine,type=com.fibaro.FGRM222 energy=2.04,power=0.7,value=99,value2=99 1529996807000000000\nfibaro,deviceId=10,host=vm1,name=Escaliers,room=Dégagement,section=Pièces\\ communes,type=com.fibaro.binarySwitch value=0 1529996807000000000\nfibaro,deviceId=13,host=vm1,name=Porte\\ fenêtre,room=Salon,section=Pièces\\ communes,type=com.fibaro.FGRM222 energy=4.33,power=0.7,value=99,value2=99 1529996807000000000\nfibaro,deviceId=21,host=vm1,name=LED\\ îlot\\ central,room=Cuisine,section=Cuisine,type=com.fibaro.binarySwitch value=0 1529996807000000000\nfibaro,deviceId=90,host=vm1,name=Détérioration,room=Entrée,section=Pièces\\ communes,type=com.fibaro.heatDetector value=0 1529996807000000000\nfibaro,deviceId=163,host=vm1,name=Température,room=Cave,section=Cave,type=com.fibaro.temperatureSensor value=21.62 1529996807000000000\nfibaro,deviceId=191,host=vm1,name=Présence,room=Garde-manger,section=Cuisine,type=com.fibaro.FGMS001 value=1 1529996807000000000\nfibaro,deviceId=193,host=vm1,name=Luminosité,room=Garde-manger,section=Cuisine,type=com.fibaro.lightSensor value=195 1529996807000000000\nfibaro,deviceId=200,host=vm1,name=Etat,room=Garage,section=Extérieur,type=com.fibaro.doorSensor value=0 1529996807000000000\nfibaro,deviceId=220,host=vm1,name=CO2\\ (ppm),room=Salon,section=Pièces\\ communes,type=com.fibaro.multilevelSensor value=536 1529996807000000000\nfibaro,deviceId=221,host=vm1,name=Humidité\\ (%),room=Salon,section=Pièces\\ communes,type=com.fibaro.humiditySensor value=61 1529996807000000000\nfibaro,deviceId=222,host=vm1,name=Pression\\ (mb),room=Salon,section=Pièces\\ communes,type=com.fibaro.multilevelSensor value=1013.7 1529996807000000000\nfibaro,deviceId=223,host=vm1,name=Bruit\\ (db),room=Salon,section=Pièces\\ communes,type=com.fibaro.multilevelSensor value=44 1529996807000000000\nfibaro,deviceId=248,host=vm1,name=Température,room=Garage,section=Extérieur,type=com.fibaro.temperatureSensor batteryLevel=85,value=10.8 1529996807000000000\n```\n"
  },
  {
    "path": "plugins/inputs/fibaro/fibaro.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage fibaro\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/fibaro/hc2\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/fibaro/hc3\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultTimeout = 5 * time.Second\n\ntype Fibaro struct {\n\tURL        string          `toml:\"url\"`\n\tUsername   string          `toml:\"username\"`\n\tPassword   string          `toml:\"password\"`\n\tTimeout    config.Duration `toml:\"timeout\"`\n\tDeviceType string          `toml:\"device_type\"`\n\n\tclient *http.Client\n}\n\nfunc (*Fibaro) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *Fibaro) Init() error {\n\tswitch f.DeviceType {\n\tcase \"\":\n\t\tf.DeviceType = \"HC2\"\n\tcase \"HC2\", \"HC3\":\n\tdefault:\n\t\treturn errors.New(\"invalid option for device type\")\n\t}\n\n\treturn nil\n}\n\nfunc (f *Fibaro) Gather(acc telegraf.Accumulator) error {\n\tif f.client == nil {\n\t\tf.client = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tProxy: http.ProxyFromEnvironment,\n\t\t\t},\n\t\t\tTimeout: time.Duration(f.Timeout),\n\t\t}\n\t}\n\n\tsections, err := f.getJSON(\"/api/sections\")\n\tif err != nil {\n\t\treturn err\n\t}\n\trooms, err := f.getJSON(\"/api/rooms\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdevices, err := f.getJSON(\"/api/devices\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswitch f.DeviceType {\n\tcase \"HC2\":\n\t\treturn hc2.Parse(acc, sections, rooms, devices)\n\tcase \"HC3\":\n\t\treturn hc3.Parse(acc, sections, rooms, devices)\n\t}\n\n\treturn nil\n}\n\n// getJSON connects, authenticates and reads JSON payload returned by Fibaro box\nfunc (f *Fibaro) getJSON(path string) ([]byte, error) {\n\tvar requestURL = f.URL + path\n\n\treq, err := http.NewRequest(\"GET\", requestURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.SetBasicAuth(f.Username, f.Password)\n\tresp, err := f.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"response from url %q has status code %d (%s), expected %d (%s)\",\n\t\t\trequestURL,\n\t\t\tresp.StatusCode,\n\t\t\thttp.StatusText(resp.StatusCode),\n\t\t\thttp.StatusOK,\n\t\t\thttp.StatusText(http.StatusOK))\n\t\treturn nil, err\n\t}\n\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to read response body: %w\", err)\n\t}\n\n\treturn bodyBytes, nil\n}\n\nfunc init() {\n\tinputs.Add(\"fibaro\", func() telegraf.Input {\n\t\treturn &Fibaro{\n\t\t\tTimeout: config.Duration(defaultTimeout),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/fibaro_test.go",
    "content": "package fibaro\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// TestUnauthorized validates that 401 (wrong credentials) is managed properly\nfunc TestUnauthorized(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusUnauthorized)\n\t}))\n\tdefer ts.Close()\n\n\ta := Fibaro{\n\t\tURL:      ts.URL,\n\t\tUsername: \"user\",\n\t\tPassword: \"pass\",\n\t\tclient:   &http.Client{},\n\t}\n\trequire.NoError(t, a.Init())\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.Error(t, err)\n}\n\n// TestJSONSuccess validates that module works OK with valid JSON payloads\nfunc TestJSONSuccess(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tpayload := \"\"\n\t\tswitch r.URL.Path {\n\t\tcase \"/api/sections\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"sections.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\tcase \"/api/rooms\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"rooms.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\tcase \"/api/devices\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"device_hc2.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := fmt.Fprintln(w, payload); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\ta := Fibaro{\n\t\tURL:      ts.URL,\n\t\tUsername: \"user\",\n\t\tPassword: \"pass\",\n\t\tclient:   &http.Client{},\n\t}\n\trequire.NoError(t, a.Init())\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\trequire.Equal(t, uint64(5), acc.NMetrics())\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"1\",\n\t\t\t\t\"section\":  \"Section 1\",\n\t\t\t\t\"room\":     \"Room 1\",\n\t\t\t\t\"name\":     \"Device 1\",\n\t\t\t\t\"type\":     \"com.fibaro.binarySwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"2\",\n\t\t\t\t\"section\":  \"Section 2\",\n\t\t\t\t\"room\":     \"Room 2\",\n\t\t\t\t\"name\":     \"Device 2\",\n\t\t\t\t\"type\":     \"com.fibaro.binarySwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"3\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 3\",\n\t\t\t\t\"name\":     \"Device 3\",\n\t\t\t\t\"type\":     \"com.fibaro.multilevelSwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(67),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"4\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 4\",\n\t\t\t\t\"name\":     \"Device 4\",\n\t\t\t\t\"type\":     \"com.fibaro.temperatureSensor\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"batteryLevel\": float64(100),\n\t\t\t\t\"value\":        float64(22.8),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"5\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 4\",\n\t\t\t\t\"name\":     \"Device 5\",\n\t\t\t\t\"type\":     \"com.fibaro.FGRM222\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"energy\": float64(4.33),\n\t\t\t\t\"power\":  float64(0.7),\n\t\t\t\t\"value\":  float64(50),\n\t\t\t\t\"value2\": float64(75),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestHC3JSON(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tpayload := \"\"\n\t\tswitch r.URL.Path {\n\t\tcase \"/api/sections\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"sections.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\tcase \"/api/rooms\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"rooms.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\tcase \"/api/devices\":\n\t\t\tcontent, err := os.ReadFile(path.Join(\"testdata\", \"device_hc3.json\"))\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpayload = string(content)\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := fmt.Fprintln(w, payload); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\ta := Fibaro{\n\t\tURL:        ts.URL,\n\t\tUsername:   \"user\",\n\t\tPassword:   \"pass\",\n\t\tDeviceType: \"HC3\",\n\t\tclient:     &http.Client{},\n\t}\n\trequire.NoError(t, a.Init())\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(a.Gather)\n\trequire.NoError(t, err)\n\trequire.Equal(t, uint64(5), acc.NMetrics())\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"1\",\n\t\t\t\t\"section\":  \"Section 1\",\n\t\t\t\t\"room\":     \"Room 1\",\n\t\t\t\t\"name\":     \"Device 1\",\n\t\t\t\t\"type\":     \"com.fibaro.binarySwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"2\",\n\t\t\t\t\"section\":  \"Section 2\",\n\t\t\t\t\"room\":     \"Room 2\",\n\t\t\t\t\"name\":     \"Device 2\",\n\t\t\t\t\"type\":     \"com.fibaro.binarySwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"3\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 3\",\n\t\t\t\t\"name\":     \"Device 3\",\n\t\t\t\t\"type\":     \"com.fibaro.multilevelSwitch\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(67),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"4\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 4\",\n\t\t\t\t\"name\":     \"Device 4\",\n\t\t\t\t\"type\":     \"com.fibaro.temperatureSensor\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"batteryLevel\": float64(100),\n\t\t\t\t\"value\":        float64(22.8),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"fibaro\",\n\t\t\tmap[string]string{\n\t\t\t\t\"deviceId\": \"5\",\n\t\t\t\t\"section\":  \"Section 3\",\n\t\t\t\t\"room\":     \"Room 4\",\n\t\t\t\t\"name\":     \"Device 5\",\n\t\t\t\t\"type\":     \"com.fibaro.FGRM222\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"energy\": float64(4.33),\n\t\t\t\t\"power\":  float64(0.7),\n\t\t\t\t\"value\":  float64(34),\n\t\t\t\t\"value2\": float64(75),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestInvalidDeviceType(t *testing.T) {\n\ta := Fibaro{\n\t\tDeviceType: \"foobar\",\n\t}\n\trequire.Error(t, a.Init())\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/hc2/parser.go",
    "content": "package hc2\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Parse parses data from sections, rooms and devices, and adds measurements containing parsed data.\nfunc Parse(acc telegraf.Accumulator, sectionBytes, roomBytes, devicesBytes []byte) error {\n\tvar tmpSections []Sections\n\tif err := json.Unmarshal(sectionBytes, &tmpSections); err != nil {\n\t\treturn err\n\t}\n\n\tsections := make(map[uint16]string, len(tmpSections))\n\tfor _, v := range tmpSections {\n\t\tsections[v.ID] = v.Name\n\t}\n\n\tvar tmpRooms []Rooms\n\tif err := json.Unmarshal(roomBytes, &tmpRooms); err != nil {\n\t\treturn err\n\t}\n\trooms := make(map[uint16]LinkRoomsSections, len(tmpRooms))\n\tfor _, v := range tmpRooms {\n\t\trooms[v.ID] = LinkRoomsSections{Name: v.Name, SectionID: v.SectionID}\n\t}\n\n\tvar devices []Devices\n\tif err := json.Unmarshal(devicesBytes, &devices); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, device := range devices {\n\t\t// skip device in some cases\n\t\tif device.RoomID == 0 ||\n\t\t\t!device.Enabled ||\n\t\t\tdevice.Properties.Dead == \"true\" ||\n\t\t\tdevice.Type == \"com.fibaro.zwaveDevice\" {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"deviceId\": strconv.FormatUint(uint64(device.ID), 10),\n\t\t\t\"section\":  sections[rooms[device.RoomID].SectionID],\n\t\t\t\"room\":     rooms[device.RoomID].Name,\n\t\t\t\"name\":     device.Name,\n\t\t\t\"type\":     device.Type,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\n\t\tif device.Properties.BatteryLevel != nil {\n\t\t\tif fValue, err := strconv.ParseFloat(*device.Properties.BatteryLevel, 64); err == nil {\n\t\t\t\tfields[\"batteryLevel\"] = fValue\n\t\t\t}\n\t\t}\n\n\t\tif device.Properties.Energy != nil {\n\t\t\tif fValue, err := strconv.ParseFloat(*device.Properties.Energy, 64); err == nil {\n\t\t\t\tfields[\"energy\"] = fValue\n\t\t\t}\n\t\t}\n\n\t\tif device.Properties.Power != nil {\n\t\t\tif fValue, err := strconv.ParseFloat(*device.Properties.Power, 64); err == nil {\n\t\t\t\tfields[\"power\"] = fValue\n\t\t\t}\n\t\t}\n\n\t\tif device.Properties.Value != nil {\n\t\t\tvalue := device.Properties.Value\n\t\t\tswitch value {\n\t\t\tcase \"true\":\n\t\t\t\tvalue = \"1\"\n\t\t\tcase \"false\":\n\t\t\t\tvalue = \"0\"\n\t\t\t}\n\n\t\t\tif fValue, err := strconv.ParseFloat(value.(string), 64); err == nil {\n\t\t\t\tfields[\"value\"] = fValue\n\t\t\t}\n\t\t}\n\n\t\tif device.Properties.Value2 != nil {\n\t\t\tif fValue, err := strconv.ParseFloat(*device.Properties.Value2, 64); err == nil {\n\t\t\t\tfields[\"value2\"] = fValue\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"fibaro\", fields, tags)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/hc2/types.go",
    "content": "package hc2\n\n// LinkRoomsSections links rooms to sections\ntype LinkRoomsSections struct {\n\tName      string\n\tSectionID uint16\n}\n\n// Sections contains sections information\ntype Sections struct {\n\tID   uint16 `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\n// Rooms contains rooms information\ntype Rooms struct {\n\tID        uint16 `json:\"id\"`\n\tName      string `json:\"name\"`\n\tSectionID uint16 `json:\"sectionID\"`\n}\n\n// Devices contains devices information\ntype Devices struct {\n\tID         uint16 `json:\"id\"`\n\tName       string `json:\"name\"`\n\tRoomID     uint16 `json:\"roomID\"`\n\tType       string `json:\"type\"`\n\tEnabled    bool   `json:\"enabled\"`\n\tProperties struct {\n\t\tBatteryLevel *string     `json:\"batteryLevel\"`\n\t\tDead         string      `json:\"dead\"`\n\t\tEnergy       *string     `json:\"energy\"`\n\t\tPower        *string     `json:\"power\"`\n\t\tValue        interface{} `json:\"value\"`\n\t\tValue2       *string     `json:\"value2\"`\n\t} `json:\"properties\"`\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/hc3/parser.go",
    "content": "package hc3\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// Parse parses data from sections, rooms and devices, and adds measurements containing parsed data.\nfunc Parse(acc telegraf.Accumulator, sectionBytes, roomBytes, devicesBytes []byte) error {\n\tvar tmpSections []Sections\n\tif err := json.Unmarshal(sectionBytes, &tmpSections); err != nil {\n\t\treturn err\n\t}\n\tsections := make(map[uint16]string, len(tmpSections))\n\tfor _, v := range tmpSections {\n\t\tsections[v.ID] = v.Name\n\t}\n\n\tvar tmpRooms []Rooms\n\tif err := json.Unmarshal(roomBytes, &tmpRooms); err != nil {\n\t\treturn err\n\t}\n\trooms := make(map[uint16]linkRoomsSections, len(tmpRooms))\n\tfor _, v := range tmpRooms {\n\t\trooms[v.ID] = linkRoomsSections{Name: v.Name, SectionID: v.SectionID}\n\t}\n\n\tvar devices []Devices\n\tif err := json.Unmarshal(devicesBytes, &devices); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, device := range devices {\n\t\t// skip device in some cases\n\t\tif device.RoomID == 0 ||\n\t\t\t!device.Enabled ||\n\t\t\tdevice.Properties.Dead ||\n\t\t\tdevice.Type == \"com.fibaro.zwaveDevice\" {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"deviceId\": strconv.FormatUint(uint64(device.ID), 10),\n\t\t\t\"section\":  sections[rooms[device.RoomID].SectionID],\n\t\t\t\"room\":     rooms[device.RoomID].Name,\n\t\t\t\"name\":     device.Name,\n\t\t\t\"type\":     device.Type,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\n\t\tif device.Properties.BatteryLevel != nil {\n\t\t\tfields[\"batteryLevel\"] = *device.Properties.BatteryLevel\n\t\t}\n\n\t\tif device.Properties.Energy != nil {\n\t\t\tfields[\"energy\"] = *device.Properties.Energy\n\t\t}\n\n\t\tif device.Properties.Power != nil {\n\t\t\tfields[\"power\"] = *device.Properties.Power\n\t\t}\n\n\t\t// Value can be a JSON bool, string, or numeric value\n\t\tif device.Properties.Value != nil {\n\t\t\tv, err := internal.ToFloat64(device.Properties.Value)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to convert value: %w\", err))\n\t\t\t} else {\n\t\t\t\tfields[\"value\"] = v\n\t\t\t}\n\t\t}\n\n\t\tif device.Properties.Value2 != nil {\n\t\t\tv, err := internal.ToFloat64(device.Properties.Value2)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to convert value2: %w\", err))\n\t\t\t} else {\n\t\t\t\tfields[\"value2\"] = v\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"fibaro\", fields, tags)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/hc3/types.go",
    "content": "package hc3\n\n// LinkRoomsSections links rooms to sections\ntype linkRoomsSections struct {\n\tName      string\n\tSectionID uint16\n}\n\n// Sections contains sections information\ntype Sections struct {\n\tID   uint16 `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\n// Rooms contains rooms information\ntype Rooms struct {\n\tID        uint16 `json:\"id\"`\n\tName      string `json:\"name\"`\n\tSectionID uint16 `json:\"sectionID\"`\n}\n\n// Devices contains devices information\ntype Devices struct {\n\tID         uint16 `json:\"id\"`\n\tName       string `json:\"name\"`\n\tRoomID     uint16 `json:\"roomID\"`\n\tType       string `json:\"type\"`\n\tEnabled    bool   `json:\"enabled\"`\n\tProperties struct {\n\t\tBatteryLevel *float64    `json:\"batteryLevel\"`\n\t\tDead         bool        `json:\"dead\"`\n\t\tEnergy       *float64    `json:\"energy\"`\n\t\tPower        *float64    `json:\"power\"`\n\t\tValue        interface{} `json:\"value\"`\n\t\tValue2       interface{} `json:\"value2\"`\n\t} `json:\"properties\"`\n}\n"
  },
  {
    "path": "plugins/inputs/fibaro/sample.conf",
    "content": "# Read devices value(s) from a Fibaro controller\n[[inputs.fibaro]]\n  ## Required Fibaro controller address/hostname.\n  ## Note: at the time of writing this plugin, Fibaro only implemented http - no https available\n  url = \"http://<controller>:80\"\n\n  ## Required credentials to access the API (http://<controller/api/<component>)\n  username = \"<username>\"\n  password = \"<password>\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Fibaro Device Type\n  ## By default, this plugin will attempt to read using the HC2 API. For HC3\n  ## devices, set this to \"HC3\"\n  # device_type = \"HC2\"\n"
  },
  {
    "path": "plugins/inputs/fibaro/testdata/device_hc2.json",
    "content": "[\n    {\n        \"id\": 1,\n        \"name\": \"Device 1\",\n        \"roomID\": 1,\n        \"type\": \"com.fibaro.binarySwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": \"false\",\n            \"value\": \"false\"\n        },\n        \"sortOrder\": 1\n    },\n    {\n        \"id\": 2,\n        \"name\": \"Device 2\",\n        \"roomID\": 2,\n        \"type\": \"com.fibaro.binarySwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": \"false\",\n            \"value\": \"true\"\n        },\n        \"sortOrder\": 2\n    },\n    {\n        \"id\": 3,\n        \"name\": \"Device 3\",\n        \"roomID\": 3,\n        \"type\": \"com.fibaro.multilevelSwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": \"false\",\n            \"value\": \"67\"\n        },\n        \"sortOrder\": 3\n    },\n    {\n        \"id\": 4,\n        \"name\": \"Device 4\",\n        \"roomID\": 4,\n        \"type\": \"com.fibaro.temperatureSensor\",\n        \"enabled\": true,\n        \"properties\": {\n            \"batteryLevel\": \"100\",\n            \"dead\": \"false\",\n            \"value\": \"22.80\"\n        },\n        \"sortOrder\": 4\n    },\n    {\n        \"id\": 5,\n        \"name\": \"Device 5\",\n        \"roomID\": 4,\n        \"type\": \"com.fibaro.FGRM222\",\n        \"enabled\": true,\n        \"properties\": {\n            \"energy\": \"4.33\",\n            \"power\": \"0.7\",\n            \"dead\": \"false\",\n            \"value\": \"50\",\n            \"value2\": \"75\"\n        },\n        \"sortOrder\": 5\n    }\n]\n"
  },
  {
    "path": "plugins/inputs/fibaro/testdata/device_hc3.json",
    "content": "[\n    {\n        \"id\": 1,\n        \"name\": \"Device 1\",\n        \"roomID\": 1,\n        \"type\": \"com.fibaro.binarySwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": false,\n            \"value\": false\n        },\n        \"sortOrder\": 1\n    },\n    {\n        \"id\": 2,\n        \"name\": \"Device 2\",\n        \"roomID\": 2,\n        \"type\": \"com.fibaro.binarySwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": false,\n            \"value\": true\n        },\n        \"sortOrder\": 2\n    },\n    {\n        \"id\": 3,\n        \"name\": \"Device 3\",\n        \"roomID\": 3,\n        \"type\": \"com.fibaro.multilevelSwitch\",\n        \"enabled\": true,\n        \"properties\": {\n            \"dead\": false,\n            \"value\": \"67\"\n        },\n        \"sortOrder\": 3\n    },\n    {\n        \"id\": 4,\n        \"name\": \"Device 4\",\n        \"roomID\": 4,\n        \"type\": \"com.fibaro.temperatureSensor\",\n        \"enabled\": true,\n        \"properties\": {\n            \"batteryLevel\": 100,\n            \"dead\": false,\n            \"value\": 22.80\n        },\n        \"sortOrder\": 4\n    },\n    {\n        \"id\": 5,\n        \"name\": \"Device 5\",\n        \"roomID\": 4,\n        \"type\": \"com.fibaro.FGRM222\",\n        \"enabled\": true,\n        \"properties\": {\n            \"energy\": 4.33,\n            \"power\": 0.7,\n            \"dead\": false,\n            \"value\": 34,\n            \"value2\": 75\n        },\n        \"sortOrder\": 5\n    }\n]\n"
  },
  {
    "path": "plugins/inputs/fibaro/testdata/rooms.json",
    "content": "[\n    {\n        \"id\": 1,\n        \"name\": \"Room 1\",\n        \"sectionID\": 1,\n        \"icon\": \"room_1\",\n        \"sortOrder\": 1\n    },\n    {\n        \"id\": 2,\n        \"name\": \"Room 2\",\n        \"sectionID\": 2,\n        \"icon\": \"room_2\",\n        \"sortOrder\": 2\n    },\n    {\n        \"id\": 3,\n        \"name\": \"Room 3\",\n        \"sectionID\": 3,\n        \"icon\": \"room_3\",\n        \"sortOrder\": 3\n    },\n    {\n        \"id\": 4,\n        \"name\": \"Room 4\",\n        \"sectionID\": 3,\n        \"icon\": \"room_4\",\n        \"sortOrder\": 4\n    }\n]\n"
  },
  {
    "path": "plugins/inputs/fibaro/testdata/sections.json",
    "content": "[\n    {\n        \"id\": 1,\n        \"name\": \"Section 1\",\n        \"sortOrder\": 1\n    },\n    {\n        \"id\": 2,\n        \"name\": \"Section 2\",\n        \"sortOrder\": 2\n    },\n    {\n        \"id\": 3,\n        \"name\": \"Section 3\",\n        \"sortOrder\": 3\n    }\n]\n"
  },
  {
    "path": "plugins/inputs/file/README.md",
    "content": "# File Input Plugin\n\nThis plugin reads the __complete__ contents of the configured files in\n__every__ interval. The file content is split line-wise and parsed according to\none of the supported [data formats][data_formats].\n\n> [!TIP]\n> If you wish to only process newly appended lines use the [tail][tail] input\n> plugin instead.\n\n⭐ Telegraf v1.8.0\n🏷️ system\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n[tail]: /plugins/inputs/tail\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Parse a complete file each interval\n[[inputs.file]]\n  ## Files to parse each interval.  Accept standard unix glob matching rules,\n  ## as well as ** to match recursive files and directories.\n  files = [\"/tmp/metrics.out\"]\n\n  ## Character encoding to use when interpreting the file contents.  Invalid\n  ## characters are replaced using the unicode replacement character.  When set\n  ## to the empty string the data is not decoded to text.\n  ##   ex: character_encoding = \"utf-8\"\n  ##       character_encoding = \"utf-16le\"\n  ##       character_encoding = \"utf-16be\"\n  ##       character_encoding = \"\"\n  # character_encoding = \"\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Please use caution when using the following options: when file name\n  ## variation is high, this can increase the cardinality significantly. Read\n  ## more about cardinality here:\n  ## https://docs.influxdata.com/influxdb/cloud/reference/glossary/#series-cardinality\n\n  ## Name of tag to store the name of the file. Disabled if not set.\n  # file_tag = \"\"\n\n  ## Name of tag to store the absolute path and name of the file. Disabled if\n  ## not set.\n  # file_path_tag = \"\"\n```\n\n## Metrics\n\nThe format of metrics produced by this plugin depends on the content and data\nformat of the file.\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/file/dev/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  telegraf:\n      image: glinton/scratch\n      volumes:\n        - ./telegraf.conf:/telegraf.conf\n        - ../../../../telegraf:/telegraf\n        - ./dev/json_a.log:/var/log/test.log\n      entrypoint:\n        - /telegraf\n        - --config\n        - /telegraf.conf\n"
  },
  {
    "path": "plugins/inputs/file/dev/telegraf.conf",
    "content": "[[inputs.file]]\n  files = [\"/var/log/test.log\"]\n  data_format = \"json\"\n  name_override = \"json_file\"\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/file/dev/testfiles/grok_a.log",
    "content": "127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326\n128.0.0.1 user-identifier tony [10/Oct/2000:13:55:36 -0800] \"GET /apache_pb.gif HTTP/1.0\" 300 45"
  },
  {
    "path": "plugins/inputs/file/dev/testfiles/json_a.log",
    "content": "{\n\t\"parent\": {\n\t\t\"child\": 3.0,\n\t\t\"ignored_child\": \"hi\"\n\t},\n\t\"ignored_null\": null,\n\t\"integer\": 4,\n\t\"list\": [3, 4],\n\t\"ignored_parent\": {\n\t\t\"another_ignored_null\": null,\n\t\t\"ignored_string\": \"hello, world!\"\n\t},\n\t\"another_list\": [4]\n}\n"
  },
  {
    "path": "plugins/inputs/file/file.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage file\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/dimchansky/utfbom\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/common/encoding\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype File struct {\n\tFiles             []string        `toml:\"files\"`\n\tFileTag           string          `toml:\"file_tag\"`\n\tFilePathTag       string          `toml:\"file_path_tag\"`\n\tCharacterEncoding string          `toml:\"character_encoding\"`\n\tLog               telegraf.Logger `toml:\"-\"`\n\n\tparserFunc telegraf.ParserFunc\n\tfilenames  []string\n\tdecoder    *encoding.Decoder\n}\n\nfunc (*File) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *File) Init() error {\n\tvar err error\n\tf.decoder, err = encoding.NewDecoder(f.CharacterEncoding)\n\treturn err\n}\n\nfunc (f *File) SetParserFunc(fn telegraf.ParserFunc) {\n\tf.parserFunc = fn\n}\n\nfunc (f *File) Gather(acc telegraf.Accumulator) error {\n\terr := f.refreshFilePaths()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, k := range f.filenames {\n\t\tmetrics, err := f.readMetric(k)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, m := range metrics {\n\t\t\tif f.FileTag != \"\" {\n\t\t\t\tm.AddTag(f.FileTag, filepath.Base(k))\n\t\t\t}\n\t\t\tif f.FilePathTag != \"\" {\n\t\t\t\tif absPath, err := filepath.Abs(k); err == nil {\n\t\t\t\t\tm.AddTag(f.FilePathTag, absPath)\n\t\t\t\t}\n\t\t\t}\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *File) refreshFilePaths() error {\n\tvar allFiles []string\n\tfor _, file := range f.Files {\n\t\tg, err := globpath.Compile(file)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not compile glob %q: %w\", file, err)\n\t\t}\n\t\tfiles := g.Match()\n\t\tif len(files) == 0 {\n\t\t\treturn fmt.Errorf(\"could not find file(s): %v\", file)\n\t\t}\n\t\tallFiles = append(allFiles, files...)\n\t}\n\n\tf.filenames = allFiles\n\treturn nil\n}\n\nfunc (f *File) readMetric(filename string) ([]telegraf.Metric, error) {\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\n\tr, _ := utfbom.Skip(f.decoder.Reader(file))\n\tfileContents, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not read %q: %w\", filename, err)\n\t}\n\tparser, err := f.parserFunc()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not instantiate parser: %w\", err)\n\t}\n\tmetrics, err := parser.Parse(fileContents)\n\tif err != nil {\n\t\treturn metrics, fmt.Errorf(\"could not parse %q: %w\", filename, err)\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\tf.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\treturn metrics, err\n}\n\nfunc init() {\n\tinputs.Add(\"file\", func() telegraf.Input {\n\t\treturn &File{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/file/file_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage file\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/csv\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/grok\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRefreshFilePaths(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\n\tr := File{\n\t\tFiles: []string{filepath.Join(wd, \"dev\", \"testfiles\", \"**.log\")},\n\t\tLog:   testutil.Logger{},\n\t}\n\terr = r.Init()\n\trequire.NoError(t, err)\n\n\terr = r.refreshFilePaths()\n\trequire.NoError(t, err)\n\trequire.Len(t, r.filenames, 2)\n}\n\nfunc TestFileTag(t *testing.T) {\n\tacc := testutil.Accumulator{}\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tr := File{\n\t\tFiles:       []string{filepath.Join(wd, \"dev\", \"testfiles\", \"json_a.log\")},\n\t\tFileTag:     \"filename\",\n\t\tFilePathTag: \"filepath\",\n\t\tLog:         testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\trequire.NoError(t, r.Gather(&acc))\n\n\tfor _, m := range acc.Metrics {\n\t\trequire.Contains(t, m.Tags, \"filename\")\n\t\trequire.Equal(t, filepath.Base(r.Files[0]), m.Tags[\"filename\"])\n\n\t\trequire.Contains(t, m.Tags, \"filepath\")\n\t\trequire.True(t, filepath.IsAbs(m.Tags[\"filepath\"]))\n\t}\n}\n\nfunc TestJSONParserCompile(t *testing.T) {\n\tvar acc testutil.Accumulator\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tr := File{\n\t\tFiles: []string{filepath.Join(wd, \"dev\", \"testfiles\", \"json_a.log\")},\n\t\tLog:   testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{TagKeys: []string{\"parent_ignored_child\"}}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\trequire.NoError(t, r.Gather(&acc))\n\trequire.Equal(t, map[string]string{\"parent_ignored_child\": \"hi\"}, acc.Metrics[0].Tags)\n\trequire.Len(t, acc.Metrics[0].Fields, 5)\n}\n\nfunc TestGrokParser(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tvar acc testutil.Accumulator\n\tr := File{\n\t\tFiles: []string{filepath.Join(wd, \"dev\", \"testfiles\", \"grok_a.log\")},\n\t\tLog:   testutil.Logger{},\n\t}\n\terr = r.Init()\n\trequire.NoError(t, err)\n\n\tr.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &grok.Parser{\n\t\t\tPatterns: []string{\"%{COMMON_LOG_FORMAT}\"},\n\t\t\tLog:      testutil.Logger{},\n\t\t}\n\t\terr := parser.Init()\n\n\t\treturn parser, err\n\t})\n\n\terr = r.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.Len(t, acc.Metrics, 2)\n}\n\nfunc TestCharacterEncoding(t *testing.T) {\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"1\",\n\t\t\t\t\"ip\":   \"12.122.114.5\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    21.55,\n\t\t\t\t\"best\":   19.34,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  2.05,\n\t\t\t\t\"worst\":  26.83,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"2\",\n\t\t\t\t\"ip\":   \"192.205.32.238\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    25.11,\n\t\t\t\t\"best\":   20.8,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  6.03,\n\t\t\t\t\"worst\":  38.85,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"3\",\n\t\t\t\t\"ip\":   \"152.195.85.133\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    20.18,\n\t\t\t\t\"best\":   19.75,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  0.0,\n\t\t\t\t\"worst\":  20.78,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"4\",\n\t\t\t\t\"ip\":   \"93.184.216.34\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    24.02,\n\t\t\t\t\"best\":   19.75,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  4.67,\n\t\t\t\t\"worst\":  32.41,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttests := []struct {\n\t\tname   string\n\t\tplugin *File\n\t\tcsv    *csv.Parser\n\t\tfile   string\n\t}{\n\t\t{\n\t\t\tname: \"empty character_encoding with utf-8\",\n\t\t\tplugin: &File{\n\t\t\t\tFiles:             []string{\"testdata/mtr-utf-8.csv\"},\n\t\t\t\tCharacterEncoding: \"\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcsv: &csv.Parser{\n\t\t\t\tMetricName:  \"file\",\n\t\t\t\tSkipRows:    1,\n\t\t\t\tColumnNames: []string{\"\", \"\", \"status\", \"dest\", \"hop\", \"ip\", \"loss\", \"snt\", \"\", \"\", \"avg\", \"best\", \"worst\", \"stdev\"},\n\t\t\t\tTagColumns:  []string{\"dest\", \"hop\", \"ip\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"utf-8 character_encoding with utf-8\",\n\t\t\tplugin: &File{\n\t\t\t\tFiles:             []string{\"testdata/mtr-utf-8.csv\"},\n\t\t\t\tCharacterEncoding: \"utf-8\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcsv: &csv.Parser{\n\t\t\t\tMetricName:  \"file\",\n\t\t\t\tSkipRows:    1,\n\t\t\t\tColumnNames: []string{\"\", \"\", \"status\", \"dest\", \"hop\", \"ip\", \"loss\", \"snt\", \"\", \"\", \"avg\", \"best\", \"worst\", \"stdev\"},\n\t\t\t\tTagColumns:  []string{\"dest\", \"hop\", \"ip\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"utf-16le character_encoding with utf-16le\",\n\t\t\tplugin: &File{\n\t\t\t\tFiles:             []string{\"testdata/mtr-utf-16le.csv\"},\n\t\t\t\tCharacterEncoding: \"utf-16le\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcsv: &csv.Parser{\n\t\t\t\tMetricName:  \"file\",\n\t\t\t\tSkipRows:    1,\n\t\t\t\tColumnNames: []string{\"\", \"\", \"status\", \"dest\", \"hop\", \"ip\", \"loss\", \"snt\", \"\", \"\", \"avg\", \"best\", \"worst\", \"stdev\"},\n\t\t\t\tTagColumns:  []string{\"dest\", \"hop\", \"ip\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"utf-16be character_encoding with utf-16be\",\n\t\t\tplugin: &File{\n\t\t\t\tFiles:             []string{\"testdata/mtr-utf-16be.csv\"},\n\t\t\t\tCharacterEncoding: \"utf-16be\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcsv: &csv.Parser{\n\t\t\t\tMetricName:  \"file\",\n\t\t\t\tSkipRows:    1,\n\t\t\t\tColumnNames: []string{\"\", \"\", \"status\", \"dest\", \"hop\", \"ip\", \"loss\", \"snt\", \"\", \"\", \"avg\", \"best\", \"worst\", \"stdev\"},\n\t\t\t\tTagColumns:  []string{\"dest\", \"hop\", \"ip\"},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttt.plugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\t\tparser := &csv.Parser{\n\t\t\t\t\tMetricName:  tt.csv.MetricName,\n\t\t\t\t\tSkipRows:    tt.csv.SkipRows,\n\t\t\t\t\tColumnNames: tt.csv.ColumnNames,\n\t\t\t\t\tTagColumns:  tt.csv.TagColumns,\n\t\t\t\t}\n\t\t\t\terr := parser.Init()\n\t\t\t\treturn parser, err\n\t\t\t})\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr = tt.plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestStatefulParsers(t *testing.T) {\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"1\",\n\t\t\t\t\"ip\":   \"12.122.114.5\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    21.55,\n\t\t\t\t\"best\":   19.34,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  2.05,\n\t\t\t\t\"worst\":  26.83,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"2\",\n\t\t\t\t\"ip\":   \"192.205.32.238\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    25.11,\n\t\t\t\t\"best\":   20.8,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  6.03,\n\t\t\t\t\"worst\":  38.85,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"3\",\n\t\t\t\t\"ip\":   \"152.195.85.133\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    20.18,\n\t\t\t\t\"best\":   19.75,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  0.0,\n\t\t\t\t\"worst\":  20.78,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"file\",\n\t\t\tmap[string]string{\n\t\t\t\t\"dest\": \"example.org\",\n\t\t\t\t\"hop\":  \"4\",\n\t\t\t\t\"ip\":   \"93.184.216.34\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg\":    24.02,\n\t\t\t\t\"best\":   19.75,\n\t\t\t\t\"loss\":   0.0,\n\t\t\t\t\"snt\":    10,\n\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\"stdev\":  4.67,\n\t\t\t\t\"worst\":  32.41,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttests := []struct {\n\t\tname   string\n\t\tplugin *File\n\t\tcsv    *csv.Parser\n\t\tfile   string\n\t\tcount  int\n\t}{\n\t\t{\n\t\t\tname: \"read file twice\",\n\t\t\tplugin: &File{\n\t\t\t\tFiles:             []string{\"testdata/mtr-utf-8.csv\"},\n\t\t\t\tCharacterEncoding: \"\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcsv: &csv.Parser{\n\t\t\t\tMetricName:  \"file\",\n\t\t\t\tSkipRows:    1,\n\t\t\t\tColumnNames: []string{\"\", \"\", \"status\", \"dest\", \"hop\", \"ip\", \"loss\", \"snt\", \"\", \"\", \"avg\", \"best\", \"worst\", \"stdev\"},\n\t\t\t\tTagColumns:  []string{\"dest\", \"hop\", \"ip\"},\n\t\t\t},\n\t\t\tcount: 2,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttt.plugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\t\tparser := &csv.Parser{\n\t\t\t\t\tMetricName:  tt.csv.MetricName,\n\t\t\t\t\tSkipRows:    tt.csv.SkipRows,\n\t\t\t\t\tColumnNames: tt.csv.ColumnNames,\n\t\t\t\t\tTagColumns:  tt.csv.TagColumns,\n\t\t\t\t}\n\t\t\t\terr := parser.Init()\n\t\t\t\treturn parser, err\n\t\t\t})\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tfor i := 0; i < tt.count; i++ {\n\t\t\t\trequire.NoError(t, tt.plugin.Gather(&acc))\n\n\t\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t\t\tacc.ClearMetrics()\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCSVBehavior(t *testing.T) {\n\t// Setup the CSV parser creator function\n\tparserFunc := func() (telegraf.Parser, error) {\n\t\tparser := &csv.Parser{\n\t\t\tMetricName:     \"file\",\n\t\t\tHeaderRowCount: 1,\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t}\n\n\t// Setup the plugin\n\tplugin := &File{\n\t\tFiles: []string{filepath.Join(\"testdata\", \"csv_behavior_input.csv\")},\n\t\tLog:   testutil.Logger{},\n\t}\n\tplugin.SetParserFunc(parserFunc)\n\trequire.NoError(t, plugin.Init())\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"file\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 1),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"file\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 2),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"file\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(1),\n\t\t\t\t\"b\": int64(2),\n\t\t\t},\n\t\t\ttime.Unix(0, 3),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"file\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": int64(3),\n\t\t\t\t\"b\": int64(4),\n\t\t\t},\n\t\t\ttime.Unix(0, 4),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\t// Run gather once\n\trequire.NoError(t, plugin.Gather(&acc))\n\t// Run gather a second time\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Eventuallyf(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"Expected %d metrics found %d\", len(expected), acc.NMetrics())\n\n\t// Check the result\n\toptions := []cmp.Option{\n\t\ttestutil.SortMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n"
  },
  {
    "path": "plugins/inputs/file/sample.conf",
    "content": "# Parse a complete file each interval\n[[inputs.file]]\n  ## Files to parse each interval.  Accept standard unix glob matching rules,\n  ## as well as ** to match recursive files and directories.\n  files = [\"/tmp/metrics.out\"]\n\n  ## Character encoding to use when interpreting the file contents.  Invalid\n  ## characters are replaced using the unicode replacement character.  When set\n  ## to the empty string the data is not decoded to text.\n  ##   ex: character_encoding = \"utf-8\"\n  ##       character_encoding = \"utf-16le\"\n  ##       character_encoding = \"utf-16be\"\n  ##       character_encoding = \"\"\n  # character_encoding = \"\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Please use caution when using the following options: when file name\n  ## variation is high, this can increase the cardinality significantly. Read\n  ## more about cardinality here:\n  ## https://docs.influxdata.com/influxdb/cloud/reference/glossary/#series-cardinality\n\n  ## Name of tag to store the name of the file. Disabled if not set.\n  # file_tag = \"\"\n\n  ## Name of tag to store the absolute path and name of the file. Disabled if\n  ## not set.\n  # file_path_tag = \"\"\n"
  },
  {
    "path": "plugins/inputs/file/testdata/csv_behavior_input.csv",
    "content": "a,b\n1,2\n3,4\n"
  },
  {
    "path": "plugins/inputs/file/testdata/mtr-utf-8.csv",
    "content": "Mtr_Version,Start_Time,Status,Host,Hop,Ip,Loss%,Snt, ,Last,Avg,Best,Wrst,StDev,\nMTR.0.87,1593667013,OK,example.org,1,12.122.114.5,0.00,10,0,21.86,21.55,19.34,26.83,2.05\nMTR.0.87,1593667013,OK,example.org,2,192.205.32.238,0.00,10,0,32.83,25.11,20.80,38.85,6.03\nMTR.0.87,1593667013,OK,example.org,3,152.195.85.133,0.00,10,0,19.75,20.18,19.75,20.78,0.00\nMTR.0.87,1593667013,OK,example.org,4,93.184.216.34,0.00,10,0,19.75,24.02,19.75,32.41,4.67\n"
  },
  {
    "path": "plugins/inputs/filecount/README.md",
    "content": "# Filecount Input Plugin\n\nThis plugin reports the number and total size of files in specified directories.\n\n⭐ Telegraf v1.8.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Count files in a directory\n[[inputs.filecount]]\n  ## Directories to gather stats about.\n  ## This accept standard unit glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". ie:\n  ##   /var/log/**    -> recursively find all directories in /var/log and count files in each directories\n  ##   /var/log/*/*   -> find all directories with a parent dir in /var/log and count files in each directories\n  ##   /var/log       -> count all files in /var/log and all of its subdirectories\n  directories = [\"/var/cache/apt\", \"/tmp\"]\n\n  ## Only count files that match the name pattern. Defaults to \"*\".\n  name = \"*\"\n\n  ## Count files in subdirectories. Defaults to true.\n  recursive = true\n\n  ## Only count regular files. Defaults to true.\n  regular_only = true\n\n  ## Follow all symlinks while walking the directory tree. Defaults to false.\n  follow_symlinks = false\n\n  ## Only count files that are at least this size. If size is\n  ## a negative number, only count files that are smaller than the\n  ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...\n  ## Without quotes and units, interpreted as size in bytes.\n  size = \"0B\"\n\n  ## Only count files that have not been touched for at least this\n  ## duration. If mtime is negative, only count files that have been\n  ## touched in this duration. Defaults to \"0s\".\n  mtime = \"0s\"\n```\n\n## Metrics\n\n- filecount\n  - tags:\n    - directory (the directory path)\n  - fields:\n    - count (integer)\n    - size_bytes (integer)\n    - oldest_file_timestamp (int, unix time nanoseconds)\n    - newest_file_timestamp (int, unix time nanoseconds)\n\n## Example Output\n\n```text\nfilecount,directory=/var/cache/apt count=7i,size_bytes=7438336i,oldest_file_timestamp=1507152973123456789i,newest_file_timestamp=1507152973123456789i 1530034445000000000\nfilecount,directory=/tmp count=17i,size_bytes=28934786i,oldest_file_timestamp=1507152973123456789i,newest_file_timestamp=1507152973123456789i 1530034445000000000\n```\n"
  },
  {
    "path": "plugins/inputs/filecount/filecount.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage filecount\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/karrick/godirwalk\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype FileCount struct {\n\tDirectories    []string        `toml:\"directories\"`\n\tName           string          `toml:\"name\"`\n\tRecursive      bool            `toml:\"recursive\"`\n\tRegularOnly    bool            `toml:\"regular_only\"`\n\tFollowSymlinks bool            `toml:\"follow_symlinks\"`\n\tSize           config.Size     `toml:\"size\"`\n\tMTime          config.Duration `toml:\"mtime\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tfs          fileSystem\n\tfileFilters []fileFilterFunc\n\tglobPaths   []globpath.GlobPath\n}\n\ntype fileFilterFunc func(os.FileInfo) (bool, error)\n\nfunc (*FileCount) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (fc *FileCount) Gather(acc telegraf.Accumulator) error {\n\tif fc.globPaths == nil {\n\t\tfc.initGlobPaths(acc)\n\t}\n\n\tfor _, glob := range fc.globPaths {\n\t\tfor _, dir := range fc.onlyDirectories(glob.GetRoots()) {\n\t\t\tfc.count(acc, dir, glob)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc rejectNilFilters(filters []fileFilterFunc) []fileFilterFunc {\n\tfiltered := make([]fileFilterFunc, 0, len(filters))\n\tfor _, f := range filters {\n\t\tif f != nil {\n\t\t\tfiltered = append(filtered, f)\n\t\t}\n\t}\n\treturn filtered\n}\n\nfunc (fc *FileCount) nameFilter() fileFilterFunc {\n\tif fc.Name == \"*\" {\n\t\treturn nil\n\t}\n\n\treturn func(f os.FileInfo) (bool, error) {\n\t\tmatch, err := filepath.Match(fc.Name, f.Name())\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn match, nil\n\t}\n}\n\nfunc (fc *FileCount) regularOnlyFilter() fileFilterFunc {\n\tif !fc.RegularOnly {\n\t\treturn nil\n\t}\n\n\treturn func(f os.FileInfo) (bool, error) {\n\t\treturn f.Mode().IsRegular(), nil\n\t}\n}\n\nfunc (fc *FileCount) sizeFilter() fileFilterFunc {\n\tif fc.Size == 0 {\n\t\treturn nil\n\t}\n\n\treturn func(f os.FileInfo) (bool, error) {\n\t\tif !f.Mode().IsRegular() {\n\t\t\treturn false, nil\n\t\t}\n\t\tif fc.Size < 0 {\n\t\t\treturn f.Size() < -int64(fc.Size), nil\n\t\t}\n\t\treturn f.Size() >= int64(fc.Size), nil\n\t}\n}\n\nfunc (fc *FileCount) mtimeFilter() fileFilterFunc {\n\tif time.Duration(fc.MTime) == 0 {\n\t\treturn nil\n\t}\n\n\treturn func(f os.FileInfo) (bool, error) {\n\t\tage := absDuration(time.Duration(fc.MTime))\n\t\tmtime := time.Now().Add(-age)\n\t\tif time.Duration(fc.MTime) < 0 {\n\t\t\treturn f.ModTime().After(mtime), nil\n\t\t}\n\t\treturn f.ModTime().Before(mtime), nil\n\t}\n}\n\nfunc absDuration(x time.Duration) time.Duration {\n\tif x < 0 {\n\t\treturn -x\n\t}\n\treturn x\n}\n\nfunc (fc *FileCount) initFileFilters() {\n\tfilters := []fileFilterFunc{\n\t\tfc.nameFilter(),\n\t\tfc.regularOnlyFilter(),\n\t\tfc.sizeFilter(),\n\t\tfc.mtimeFilter(),\n\t}\n\tfc.fileFilters = rejectNilFilters(filters)\n}\n\nfunc (fc *FileCount) count(acc telegraf.Accumulator, basedir string, glob globpath.GlobPath) {\n\tchildCount := make(map[string]int64)\n\tchildSize := make(map[string]int64)\n\toldestFileTimestamp := make(map[string]int64)\n\tnewestFileTimestamp := make(map[string]int64)\n\n\twalkFn := func(path string, _ *godirwalk.Dirent) error {\n\t\trel, err := filepath.Rel(basedir, path)\n\t\tif err == nil && rel == \".\" {\n\t\t\treturn nil\n\t\t}\n\t\tfile, err := fc.resolveLink(path)\n\t\tif err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\tmatch, err := fc.filter(file)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\treturn nil\n\t\t}\n\t\tif match {\n\t\t\tparent := filepath.Dir(path)\n\t\t\tchildCount[parent]++\n\t\t\tchildSize[parent] += file.Size()\n\t\t\tif oldestFileTimestamp[parent] == 0 || oldestFileTimestamp[parent] > file.ModTime().UnixNano() {\n\t\t\t\toldestFileTimestamp[parent] = file.ModTime().UnixNano()\n\t\t\t}\n\t\t\tif newestFileTimestamp[parent] == 0 || newestFileTimestamp[parent] < file.ModTime().UnixNano() {\n\t\t\t\tnewestFileTimestamp[parent] = file.ModTime().UnixNano()\n\t\t\t}\n\t\t}\n\t\tif file.IsDir() && !fc.Recursive && !glob.HasSuperMeta {\n\t\t\treturn filepath.SkipDir\n\t\t}\n\t\treturn nil\n\t}\n\n\tpostChildrenFn := func(path string, _ *godirwalk.Dirent) error {\n\t\tif glob.MatchString(path) {\n\t\t\tgauge := map[string]interface{}{\n\t\t\t\t\"count\":      childCount[path],\n\t\t\t\t\"size_bytes\": childSize[path],\n\t\t\t}\n\t\t\tgauge[\"oldest_file_timestamp\"] = oldestFileTimestamp[path]\n\t\t\tgauge[\"newest_file_timestamp\"] = newestFileTimestamp[path]\n\t\t\tacc.AddGauge(\"filecount\", gauge,\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"directory\": path,\n\t\t\t\t})\n\t\t}\n\t\tparent := filepath.Dir(path)\n\t\tif fc.Recursive {\n\t\t\tchildCount[parent] += childCount[path]\n\t\t\tchildSize[parent] += childSize[path]\n\t\t\tif oldestFileTimestamp[parent] == 0 || oldestFileTimestamp[parent] > oldestFileTimestamp[path] {\n\t\t\t\toldestFileTimestamp[parent] = oldestFileTimestamp[path]\n\t\t\t}\n\t\t\tif newestFileTimestamp[parent] == 0 || newestFileTimestamp[parent] < newestFileTimestamp[path] {\n\t\t\t\tnewestFileTimestamp[parent] = newestFileTimestamp[path]\n\t\t\t}\n\t\t}\n\t\tdelete(childCount, path)\n\t\tdelete(childSize, path)\n\t\tdelete(oldestFileTimestamp, path)\n\t\tdelete(newestFileTimestamp, path)\n\t\treturn nil\n\t}\n\n\terr := godirwalk.Walk(basedir, &godirwalk.Options{\n\t\tCallback:             walkFn,\n\t\tPostChildrenCallback: postChildrenFn,\n\t\tUnsorted:             true,\n\t\tFollowSymbolicLinks:  fc.FollowSymlinks,\n\t\tErrorCallback: func(_ string, err error) godirwalk.ErrorAction {\n\t\t\tif errors.Is(err, fs.ErrPermission) {\n\t\t\t\tfc.Log.Debug(err)\n\t\t\t\treturn godirwalk.SkipNode\n\t\t\t}\n\t\t\treturn godirwalk.Halt\n\t\t},\n\t})\n\tif err != nil {\n\t\tacc.AddError(err)\n\t}\n}\n\nfunc (fc *FileCount) filter(file os.FileInfo) (bool, error) {\n\tif fc.fileFilters == nil {\n\t\tfc.initFileFilters()\n\t}\n\n\tfor _, fileFilter := range fc.fileFilters {\n\t\tmatch, err := fileFilter(file)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif !match {\n\t\t\treturn false, nil\n\t\t}\n\t}\n\n\treturn true, nil\n}\n\nfunc (fc *FileCount) resolveLink(path string) (os.FileInfo, error) {\n\tif fc.FollowSymlinks {\n\t\treturn fc.fs.stat(path)\n\t}\n\tfi, err := fc.fs.lstat(path)\n\tif err != nil {\n\t\treturn fi, err\n\t}\n\tif fi.Mode()&os.ModeSymlink != 0 {\n\t\t// if this file is a symlink, skip it\n\t\treturn nil, godirwalk.SkipThis\n\t}\n\treturn fi, nil\n}\n\nfunc (fc *FileCount) onlyDirectories(directories []string) []string {\n\tout := make([]string, 0)\n\tfor _, path := range directories {\n\t\tinfo, err := fc.fs.stat(path)\n\t\tif err == nil && info.IsDir() {\n\t\t\tout = append(out, path)\n\t\t}\n\t}\n\treturn out\n}\n\nfunc (fc *FileCount) getDirs() []string {\n\tdirs := make([]string, 0, len(fc.Directories)+1)\n\tfor _, dir := range fc.Directories {\n\t\tdirs = append(dirs, filepath.Clean(dir))\n\t}\n\n\treturn dirs\n}\n\nfunc (fc *FileCount) initGlobPaths(acc telegraf.Accumulator) {\n\tdirs := fc.getDirs()\n\tfc.globPaths = make([]globpath.GlobPath, 0, len(dirs))\n\tfor _, directory := range dirs {\n\t\tglob, err := globpath.Compile(directory)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t} else {\n\t\t\tfc.globPaths = append(fc.globPaths, *glob)\n\t\t}\n\t}\n}\n\nfunc newFileCount() *FileCount {\n\treturn &FileCount{\n\t\tName:           \"*\",\n\t\tRecursive:      true,\n\t\tRegularOnly:    true,\n\t\tFollowSymlinks: false,\n\t\tSize:           config.Size(0),\n\t\tMTime:          config.Duration(0),\n\t\tfileFilters:    nil,\n\t\tfs:             osFS{},\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"filecount\", func() telegraf.Input {\n\t\treturn newFileCount()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/filecount/filecount_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage filecount\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNoFilters(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tmatches := []string{\"foo\", \"bar\", \"baz\", \"qux\",\n\t\t\"subdir/\", \"subdir/quux\", \"subdir/quuz\",\n\t\t\"subdir/nested2\", \"subdir/nested2/qux\"}\n\tfileCountEquals(t, fc, len(matches), 5096)\n}\n\nfunc TestNoFiltersOnChildDir(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Directories = []string{getTestdataDir() + \"/*\"}\n\tmatches := []string{\"subdir/quux\", \"subdir/quuz\",\n\t\t\"subdir/nested2/qux\", \"subdir/nested2\"}\n\n\ttags := map[string]string{\"directory\": getTestdataDir() + \"/subdir\"}\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fc.Gather))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"count\", int64(len(matches))))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"size_bytes\", int64(600)))\n\trequire.True(t, acc.HasInt64Field(\"filecount\", \"oldest_file_timestamp\"))\n\trequire.True(t, acc.HasInt64Field(\"filecount\", \"newest_file_timestamp\"))\n}\n\nfunc TestNoRecursiveButSuperMeta(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Recursive = false\n\tfc.Directories = []string{getTestdataDir() + \"/**\"}\n\tmatches := []string{\"subdir/quux\", \"subdir/quuz\", \"subdir/nested2\"}\n\n\ttags := map[string]string{\"directory\": getTestdataDir() + \"/subdir\"}\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fc.Gather))\n\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"count\", int64(len(matches))))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"size_bytes\", int64(200)))\n\trequire.True(t, acc.HasInt64Field(\"filecount\", \"oldest_file_timestamp\"))\n\trequire.True(t, acc.HasInt64Field(\"filecount\", \"newest_file_timestamp\"))\n}\n\nfunc TestNameFilter(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Name = \"ba*\"\n\tmatches := []string{\"bar\", \"baz\"}\n\tfileCountEquals(t, fc, len(matches), 0)\n}\n\nfunc TestNonRecursive(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Recursive = false\n\tmatches := []string{\"foo\", \"bar\", \"baz\", \"qux\", \"subdir\"}\n\n\tfileCountEquals(t, fc, len(matches), 4496)\n}\n\nfunc TestDoubleAndSimpleStar(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Directories = []string{getTestdataDir() + \"/**/*\"}\n\tmatches := []string{\"qux\"}\n\n\ttags := map[string]string{\"directory\": getTestdataDir() + \"/subdir/nested2\"}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fc.Gather))\n\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"count\", int64(len(matches))))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"size_bytes\", int64(400)))\n}\n\nfunc TestRegularOnlyFilter(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.RegularOnly = true\n\tmatches := []string{\n\t\t\"foo\", \"bar\", \"baz\", \"qux\", \"subdir/quux\", \"subdir/quuz\",\n\t\t\"subdir/nested2/qux\"}\n\n\tfileCountEquals(t, fc, len(matches), 800)\n}\n\nfunc TestSizeFilter(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.Size = config.Size(-100)\n\tmatches := []string{\"foo\", \"bar\", \"baz\",\n\t\t\"subdir/quux\", \"subdir/quuz\"}\n\tfileCountEquals(t, fc, len(matches), 0)\n\n\tfc.Size = config.Size(100)\n\tmatches = []string{\"qux\", \"subdir/nested2//qux\"}\n\n\tfileCountEquals(t, fc, len(matches), 800)\n}\n\nfunc TestMTimeFilter(t *testing.T) {\n\tmtime := time.Date(2011, time.December, 14, 18, 25, 5, 0, time.UTC)\n\tfileAge := time.Since(mtime) - (60 * time.Second)\n\n\tfc := getNoFilterFileCount()\n\tfc.MTime = config.Duration(-fileAge)\n\tmatches := []string{\"foo\", \"bar\", \"qux\",\n\t\t\"subdir/\", \"subdir/quux\", \"subdir/quuz\",\n\t\t\"subdir/nested2\", \"subdir/nested2/qux\"}\n\n\tfileCountEquals(t, fc, len(matches), 5096)\n\n\tfc.MTime = config.Duration(fileAge)\n\tmatches = []string{\"baz\"}\n\tfileCountEquals(t, fc, len(matches), 0)\n}\n\n// The library dependency karrick/godirwalk completely abstracts out the\n// behavior of the FollowSymlinks plugin input option. However, it should at\n// least behave identically when enabled on a filesystem with no symlinks.\nfunc TestFollowSymlinks(t *testing.T) {\n\tfc := getNoFilterFileCount()\n\tfc.FollowSymlinks = true\n\tmatches := []string{\"foo\", \"bar\", \"baz\", \"qux\",\n\t\t\"subdir/\", \"subdir/quux\", \"subdir/quuz\",\n\t\t\"subdir/nested2\", \"subdir/nested2/qux\"}\n\n\tfileCountEquals(t, fc, len(matches), 5096)\n}\n\n// Paths with a trailing slash will not exactly match paths produced during the\n// walk as these paths are cleaned before being returned from godirwalk. #6329\nfunc TestDirectoryWithTrailingSlash(t *testing.T) {\n\tplugin := &FileCount{\n\t\tDirectories: []string{getTestdataDir() + string(filepath.Separator)},\n\t\tName:        \"*\",\n\t\tRecursive:   true,\n\t\tfs:          getFakeFileSystem(getTestdataDir()),\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"filecount\",\n\t\t\tmap[string]string{\n\t\t\t\t\"directory\": getTestdataDir(),\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\":                 9,\n\t\t\t\t\"size_bytes\":            5096,\n\t\t\t\t\"newest_file_timestamp\": time.Unix(1450117505, 0).UnixNano(),\n\t\t\t\t\"oldest_file_timestamp\": time.Unix(1292351105, 0).UnixNano(),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc getNoFilterFileCount() FileCount {\n\treturn FileCount{\n\t\tLog:         testutil.Logger{},\n\t\tDirectories: []string{getTestdataDir()},\n\t\tName:        \"*\",\n\t\tRecursive:   true,\n\t\tRegularOnly: false,\n\t\tSize:        config.Size(0),\n\t\tMTime:       config.Duration(0),\n\t\tfileFilters: nil,\n\t\tfs:          getFakeFileSystem(getTestdataDir()),\n\t}\n}\n\nfunc getTestdataDir() string {\n\tdir, err := os.Getwd()\n\tif err != nil {\n\t\t// if we cannot even establish the test directory, further progress is meaningless\n\t\tpanic(err)\n\t}\n\n\tvar chunks []string\n\tvar testDirectory string\n\n\t//nolint:staticcheck // Silence linter for now as we plan to reenable tests for Windows later\n\tif runtime.GOOS == \"windows\" {\n\t\tchunks = strings.Split(dir, \"\\\\\")\n\t\ttestDirectory = strings.Join(chunks[:], \"\\\\\") + \"\\\\testdata\"\n\t} else {\n\t\tchunks = strings.Split(dir, \"/\")\n\t\ttestDirectory = strings.Join(chunks[:], \"/\") + \"/testdata\"\n\t}\n\treturn testDirectory\n}\n\nfunc getFakeFileSystem(basePath string) fakeFileSystem {\n\t// create our desired \"filesystem\" object, complete with an internal map allowing our funcs to return meta data as requested\n\n\tmtime := time.Date(2015, time.December, 14, 18, 25, 5, 0, time.UTC)\n\tolderMtime := time.Date(2010, time.December, 14, 18, 25, 5, 0, time.UTC)\n\n\t// set file permissions\n\tvar fmask uint32 = 0666\n\tvar dmask uint32 = 0666\n\n\t// set directory bit\n\tdmask |= 1 << uint(32-1)\n\n\t// create a lookup map for getting \"files\" from the \"filesystem\"\n\tfileList := map[string]fakeFileInfo{\n\t\tbasePath:                         {name: \"testdata\", size: int64(4096), filemode: dmask, modtime: mtime, isdir: true},\n\t\tbasePath + \"/foo\":                {name: \"foo\", filemode: fmask, modtime: mtime},\n\t\tbasePath + \"/bar\":                {name: \"bar\", filemode: fmask, modtime: mtime},\n\t\tbasePath + \"/baz\":                {name: \"baz\", filemode: fmask, modtime: olderMtime},\n\t\tbasePath + \"/qux\":                {name: \"qux\", size: int64(400), filemode: fmask, modtime: mtime},\n\t\tbasePath + \"/subdir\":             {name: \"subdir\", size: int64(4096), filemode: dmask, modtime: mtime, isdir: true},\n\t\tbasePath + \"/subdir/quux\":        {name: \"quux\", filemode: fmask, modtime: mtime},\n\t\tbasePath + \"/subdir/quuz\":        {name: \"quuz\", filemode: fmask, modtime: mtime},\n\t\tbasePath + \"/subdir/nested2\":     {name: \"nested2\", size: int64(200), filemode: dmask, modtime: mtime, isdir: true},\n\t\tbasePath + \"/subdir/nested2/qux\": {name: \"qux\", filemode: fmask, modtime: mtime, size: int64(400)},\n\t}\n\n\treturn fakeFileSystem{files: fileList}\n}\n\nfunc fileCountEquals(t *testing.T, fc FileCount, expectedCount, expectedSize int) {\n\ttags := map[string]string{\"directory\": getTestdataDir()}\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fc.Gather))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"count\", int64(expectedCount)))\n\trequire.True(t, acc.HasPoint(\"filecount\", tags, \"size_bytes\", int64(expectedSize)))\n}\n"
  },
  {
    "path": "plugins/inputs/filecount/filesystem_helpers.go",
    "content": "package filecount\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\n/*\n\tThe code below is lifted from numerous articles and originates from Andrew Gerrand's 10 things you (probably) don't know about Go.\n\tIt allows for mocking a filesystem; this allows for consistent testing of this code across platforms (directory sizes reported\n\tdifferently by different platforms, for example), while preserving the rest of the functionality as-is, without modification.\n*/\n\ntype fileSystem interface {\n\topen(name string) (file, error)\n\tstat(name string) (os.FileInfo, error)\n\tlstat(name string) (os.FileInfo, error)\n}\n\ntype file interface {\n\tio.Closer\n\tio.Reader\n\tio.ReaderAt\n\tio.Seeker\n\tStat() (os.FileInfo, error)\n}\n\n// osFS implements fileSystem using the local disk\ntype osFS struct{}\n\nfunc (osFS) open(name string) (file, error)         { return os.Open(name) }\nfunc (osFS) stat(name string) (os.FileInfo, error)  { return os.Stat(name) }\nfunc (osFS) lstat(name string) (os.FileInfo, error) { return os.Lstat(name) }\n"
  },
  {
    "path": "plugins/inputs/filecount/filesystem_helpers_notwindows_test.go",
    "content": "//go:build !windows\n\n// TODO: These types are not used in Windows tests because they are disabled for Windows.\n// They can be moved to filesystem_helpers.go when following bug is fixed:\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage filecount\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"time\"\n)\n\n/*\n\tThe following are for mocking the filesystem - this allows us to mock Stat() files. This means that we can set file attributes, and know that they\n\twill be the same regardless of the platform sitting underneath our tests (directory sizes vary see https://github.com/influxdata/telegraf/issues/6011)\n\n\tNOTE: still need the on-disk file structure to mirror this because the 3rd party library (\"github.com/karrick/godirwalk\") uses its own\n\twalk functions, that we cannot mock from here.\n*/\n\ntype fakeFileSystem struct {\n\tfiles map[string]fakeFileInfo\n}\n\ntype fakeFileInfo struct {\n\tname     string\n\tsize     int64\n\tfilemode uint32\n\tmodtime  time.Time\n\tisdir    bool\n\tsys      interface{}\n}\n\nfunc (f fakeFileInfo) Name() string       { return f.name }\nfunc (f fakeFileInfo) Size() int64        { return f.size }\nfunc (f fakeFileInfo) Mode() os.FileMode  { return os.FileMode(f.filemode) }\nfunc (f fakeFileInfo) ModTime() time.Time { return f.modtime }\nfunc (f fakeFileInfo) IsDir() bool        { return f.isdir }\nfunc (f fakeFileInfo) Sys() interface{}   { return f.sys }\n\nfunc (fakeFileSystem) open(name string) (file, error) {\n\treturn nil, &os.PathError{Op: \"Open\", Path: name, Err: errors.New(\"not implemented by fake filesystem\")}\n}\n\nfunc (f fakeFileSystem) stat(name string) (os.FileInfo, error) {\n\tif fakeInfo, found := f.files[name]; found {\n\t\treturn fakeInfo, nil\n\t}\n\treturn nil, &os.PathError{Op: \"Stat\", Path: name, Err: errors.New(\"no such file or directory\")}\n}\n\nfunc (f fakeFileSystem) lstat(name string) (os.FileInfo, error) {\n\t// not able to test with symlinks currently\n\treturn f.stat(name)\n}\n"
  },
  {
    "path": "plugins/inputs/filecount/filesystem_helpers_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage filecount\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMTime(t *testing.T) {\n\t// this is the time our foo file should have\n\tmtime := time.Date(2015, time.December, 14, 18, 25, 5, 0, time.UTC)\n\n\tfs := getTestFileSystem()\n\tfileInfo, err := fs.stat(\"/testdata/foo\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, mtime, fileInfo.ModTime())\n}\n\nfunc TestSize(t *testing.T) {\n\t// this is the time our foo file should have\n\tsize := int64(4096)\n\tfs := getTestFileSystem()\n\tfileInfo, err := fs.stat(\"/testdata\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, size, fileInfo.Size())\n}\n\nfunc TestIsDir(t *testing.T) {\n\t// this is the time our foo file should have\n\tfs := getTestFileSystem()\n\tfileInfo, err := fs.stat(\"/testdata\")\n\trequire.NoError(t, err)\n\trequire.True(t, fileInfo.IsDir())\n}\n\nfunc TestRealFS(t *testing.T) {\n\t// test that the default (non-test) empty FS causes expected behaviour\n\tvar fs fileSystem = osFS{}\n\t// the following file exists on disk - and not in our fake fs\n\tfileInfo, err := fs.stat(getTestdataDir() + \"/qux\")\n\trequire.NoError(t, err)\n\trequire.False(t, fileInfo.IsDir())\n\trequire.Equal(t, int64(446), fileInfo.Size())\n\n\t// now swap out real, for fake filesystem\n\tfs = getTestFileSystem()\n\t// now, the same test as above will return an error as the file doesn't exist in our fake fs\n\texpectedError := \"Stat \" + getTestdataDir() + \"/qux: No such file or directory\"\n\t_, err = fs.stat(getTestdataDir() + \"/qux\")\n\trequire.Error(t, err, expectedError)\n\t// and verify that what we DO expect to find, we do\n\tfileInfo, err = fs.stat(\"/testdata/foo\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, fileInfo)\n}\n\nfunc getTestFileSystem() fakeFileSystem {\n\t/*\n\t\tcreate our desired \"filesystem\" object, complete with an internal map allowing our funcs to return meta data as requested\n\n\t\ttype FileInfo interface {\n\t\t\tName() string       // base name of the file\n\t\t\tSize() int64        // length in bytes of file\n\t\t\tMode() FileMode     // file mode bits\n\t\t\tModTime() time.Time // modification time\n\t\t\tIsDir() bool        // returns bool indicating if a Dir or not\n\t\t\tSys() interface{}   // underlying data source. always nil (in this case)\n\t\t}\n\n\t*/\n\n\tmtime := time.Date(2015, time.December, 14, 18, 25, 5, 0, time.UTC)\n\n\t// set file permissions\n\tvar fmask uint32 = 0666\n\tvar dmask uint32 = 0666\n\n\t// set directory bit\n\tdmask |= 1 << uint(32-1)\n\n\tfileList := map[string]fakeFileInfo{\n\t\t\"/testdata\":     {name: \"testdata\", size: int64(4096), filemode: dmask, modtime: mtime, isdir: true},\n\t\t\"/testdata/foo\": {name: \"foo\", filemode: fmask, modtime: mtime},\n\t}\n\n\treturn fakeFileSystem{files: fileList}\n}\n"
  },
  {
    "path": "plugins/inputs/filecount/sample.conf",
    "content": "# Count files in a directory\n[[inputs.filecount]]\n  ## Directories to gather stats about.\n  ## This accept standard unit glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". ie:\n  ##   /var/log/**    -> recursively find all directories in /var/log and count files in each directories\n  ##   /var/log/*/*   -> find all directories with a parent dir in /var/log and count files in each directories\n  ##   /var/log       -> count all files in /var/log and all of its subdirectories\n  directories = [\"/var/cache/apt\", \"/tmp\"]\n\n  ## Only count files that match the name pattern. Defaults to \"*\".\n  name = \"*\"\n\n  ## Count files in subdirectories. Defaults to true.\n  recursive = true\n\n  ## Only count regular files. Defaults to true.\n  regular_only = true\n\n  ## Follow all symlinks while walking the directory tree. Defaults to false.\n  follow_symlinks = false\n\n  ## Only count files that are at least this size. If size is\n  ## a negative number, only count files that are smaller than the\n  ## absolute value of size. Acceptable units are B, KiB, MiB, KB, ...\n  ## Without quotes and units, interpreted as size in bytes.\n  size = \"0B\"\n\n  ## Only count files that have not been touched for at least this\n  ## duration. If mtime is negative, only count files that have been\n  ## touched in this duration. Defaults to \"0s\".\n  mtime = \"0s\"\n"
  },
  {
    "path": "plugins/inputs/filecount/testdata/bar",
    "content": ""
  },
  {
    "path": "plugins/inputs/filecount/testdata/baz",
    "content": ""
  },
  {
    "path": "plugins/inputs/filecount/testdata/foo",
    "content": ""
  },
  {
    "path": "plugins/inputs/filecount/testdata/qux",
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad\nminim veniam, quis nostrud exercitation ullamco laboris nisi ut\naliquip ex ea commodo consequat. Duis aute irure dolor in\nreprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\npariatur. Excepteur sint occaecat cupidatat non proident, sunt in\nculpa qui officia deserunt mollit anim id est laborum.\n"
  },
  {
    "path": "plugins/inputs/filecount/testdata/subdir/nested2/qux",
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad\nminim veniam, quis nostrud exercitation ullamco laboris nisi ut\naliquip ex ea commodo consequat. Duis aute irure dolor in\nreprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\npariatur. Excepteur sint occaecat cupidatat non proident, sunt in\nculpa qui officia deserunt mollit anim id est laborum.\n"
  },
  {
    "path": "plugins/inputs/filecount/testdata/subdir/quux",
    "content": ""
  },
  {
    "path": "plugins/inputs/filecount/testdata/subdir/quuz",
    "content": ""
  },
  {
    "path": "plugins/inputs/filestat/README.md",
    "content": "# File statistics Input Plugin\n\nThis plugin gathers metrics about file existence, size, and other file\nstatistics.\n\n⭐ Telegraf v0.13.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read stats about given file(s)\n[[inputs.filestat]]\n  ## Files to gather stats about.\n  ## These accept standard unix glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". See https://github.com/gobwas/glob.\n  files = [\"/etc/telegraf/telegraf.conf\", \"/var/log/**.log\"]\n\n  ## If true, read the entire file and calculate an md5 checksum.\n  md5 = false\n```\n\n## Metrics\n\n### Measurements & Fields\n\n- filestat\n  - exists (int, 0 | 1)\n  - size_bytes (int, bytes)\n  - modification_time (int, unix time nanoseconds)\n  - md5 (optional, string)\n\n### Tags\n\n- All measurements have the following tags:\n  - file (the path the to file, as specified in the config)\n\n## Example Output\n\n```text\nfilestat,file=/tmp/foo/bar,host=tyrion exists=0i 1507218518192154351\nfilestat,file=/Users/sparrc/ws/telegraf.conf,host=tyrion exists=1i,size=47894i,modification_time=1507152973123456789i  1507218518192154351\n```\n"
  },
  {
    "path": "plugins/inputs/filestat/filestat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage filestat\n\nimport (\n\t\"crypto/md5\" //nolint:gosec // G501: Blocklisted import crypto/md5: weak cryptographic primitive - md5 hash is what is desired in this case\n\t_ \"embed\"\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype FileStat struct {\n\tMd5   bool     `toml:\"md5\"`\n\tFiles []string `toml:\"files\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\t// maps full file paths to globmatch obj\n\tglobs map[string]*globpath.GlobPath\n\n\t// files that were missing - we only log the first time it's not found.\n\tmissingFiles map[string]bool\n\t// files that had an error in Stat - we only log the first error.\n\tfilesWithErrors map[string]bool\n}\n\nfunc (*FileStat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *FileStat) Gather(acc telegraf.Accumulator) error {\n\tvar err error\n\n\tfor _, filepath := range f.Files {\n\t\t// Get the compiled glob object for this filepath\n\t\tg, ok := f.globs[filepath]\n\t\tif !ok {\n\t\t\tif g, err = globpath.Compile(filepath); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tf.globs[filepath] = g\n\t\t}\n\n\t\tfiles := g.Match()\n\t\tif len(files) == 0 {\n\t\t\tacc.AddFields(\"filestat\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"exists\": int64(0),\n\t\t\t\t},\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"file\": filepath,\n\t\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, fileName := range files {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"file\": fileName,\n\t\t\t}\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"exists\": int64(1),\n\t\t\t}\n\t\t\tfileInfo, err := os.Stat(fileName)\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\tfields[\"exists\"] = int64(0)\n\t\t\t\tacc.AddFields(\"filestat\", fields, tags)\n\t\t\t\tif !f.missingFiles[fileName] {\n\t\t\t\t\tf.Log.Warnf(\"File %q not found\", fileName)\n\t\t\t\t\tf.missingFiles[fileName] = true\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tf.missingFiles[fileName] = false\n\n\t\t\tif fileInfo == nil {\n\t\t\t\tif !f.filesWithErrors[fileName] {\n\t\t\t\t\tf.filesWithErrors[fileName] = true\n\t\t\t\t\tf.Log.Errorf(\"Unable to get info for file %q: %v\",\n\t\t\t\t\t\tfileName, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tf.filesWithErrors[fileName] = false\n\t\t\t\tfields[\"size_bytes\"] = fileInfo.Size()\n\t\t\t\tfields[\"modification_time\"] = fileInfo.ModTime().UnixNano()\n\t\t\t}\n\n\t\t\tif f.Md5 {\n\t\t\t\tmd5Hash, err := getMd5(fileName)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"md5_sum\"] = md5Hash\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tacc.AddFields(\"filestat\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Read given file and calculate a md5 hash.\nfunc getMd5(file string) (string, error) {\n\tof, err := os.Open(file)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer of.Close()\n\n\t//nolint:gosec // G401: Use of weak cryptographic primitive - md5 hash is what is desired in this case\n\thash := md5.New()\n\t_, err = io.Copy(hash, of)\n\tif err != nil {\n\t\t// fatal error\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(hash.Sum(nil)), nil\n}\n\nfunc newFileStat() *FileStat {\n\treturn &FileStat{\n\t\tglobs:           make(map[string]*globpath.GlobPath),\n\t\tmissingFiles:    make(map[string]bool),\n\t\tfilesWithErrors: make(map[string]bool),\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"filestat\", func() telegraf.Input {\n\t\treturn newFileStat()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/filestat/filestat_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage filestat\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar testdataDir = getTestdataDir()\n\nfunc TestGatherNoMd5(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"log1.log\"),\n\t\tfilepath.Join(testdataDir, \"log2.log\"),\n\t\tfilepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log1.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(1)))\n\n\ttags2 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log2.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"exists\", int64(1)))\n\n\ttags3 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags3, \"exists\", int64(0)))\n}\n\nfunc TestGatherExplicitFiles(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Md5 = true\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"log1.log\"),\n\t\tfilepath.Join(testdataDir, \"log2.log\"),\n\t\tfilepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log1.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n\n\ttags2 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log2.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n\n\ttags3 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags3, \"exists\", int64(0)))\n}\n\nfunc TestNonExistentFile(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Md5 = true\n\tfs.Files = []string{\n\t\t\"/non/existant/file\",\n\t}\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\tacc.AssertContainsFields(t, \"filestat\", map[string]interface{}{\"exists\": int64(0)})\n\trequire.False(t, acc.HasField(\"filestat\", \"error\"))\n\trequire.False(t, acc.HasField(\"filestat\", \"md5_sum\"))\n\trequire.False(t, acc.HasField(\"filestat\", \"size_bytes\"))\n\trequire.False(t, acc.HasField(\"filestat\", \"modification_time\"))\n}\n\nfunc TestGatherGlob(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Md5 = true\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"*.log\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log1.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n\n\ttags2 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log2.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n}\n\nfunc TestGatherSuperAsterisk(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Md5 = true\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"**\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log1.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n\n\ttags2 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log2.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags2, \"md5_sum\", \"d41d8cd98f00b204e9800998ecf8427e\"))\n\n\ttags3 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"test.conf\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags3, \"size_bytes\", int64(104)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags3, \"exists\", int64(1)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags3, \"md5_sum\", \"5a7e9b77fa25e7bb411dbd17cf403c1f\"))\n}\n\nfunc TestModificationTime(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"log1.log\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"log1.log\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"size_bytes\", int64(0)))\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(1)))\n\trequire.True(t, acc.HasInt64Field(\"filestat\", \"modification_time\"))\n}\n\nfunc TestNoModificationTime(t *testing.T) {\n\tfs := newFileStat()\n\tfs.Log = testutil.Logger{}\n\tfs.Files = []string{\n\t\tfilepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, acc.GatherError(fs.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"file\": filepath.Join(testdataDir, \"non_existent_file\"),\n\t}\n\trequire.True(t, acc.HasPoint(\"filestat\", tags1, \"exists\", int64(0)))\n\trequire.False(t, acc.HasInt64Field(\"filestat\", \"modification_time\"))\n}\n\nfunc TestGetMd5(t *testing.T) {\n\tmd5, err := getMd5(filepath.Join(testdataDir, \"test.conf\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"5a7e9b77fa25e7bb411dbd17cf403c1f\", md5)\n\n\t_, err = getMd5(\"/tmp/foo/bar/fooooo\")\n\trequire.Error(t, err)\n}\n\nfunc getTestdataDir() string {\n\tdir, err := os.Getwd()\n\tif err != nil {\n\t\t// if we cannot even establish the test directory, further progress is meaningless\n\t\tpanic(err)\n\t}\n\n\treturn filepath.Join(dir, \"testdata\")\n}\n"
  },
  {
    "path": "plugins/inputs/filestat/sample.conf",
    "content": "# Read stats about given file(s)\n[[inputs.filestat]]\n  ## Files to gather stats about.\n  ## These accept standard unix glob matching rules, but with the addition of\n  ## ** as a \"super asterisk\". See https://github.com/gobwas/glob.\n  files = [\"/etc/telegraf/telegraf.conf\", \"/var/log/**.log\"]\n\n  ## If true, read the entire file and calculate an md5 checksum.\n  md5 = false\n"
  },
  {
    "path": "plugins/inputs/filestat/testdata/log1.log",
    "content": ""
  },
  {
    "path": "plugins/inputs/filestat/testdata/log2.log",
    "content": ""
  },
  {
    "path": "plugins/inputs/filestat/testdata/test.conf",
    "content": "# this is a fake testing config file\n# for testing the filestat plugin\n\noption1 = \"foo\"\noption2 = \"bar\"\n"
  },
  {
    "path": "plugins/inputs/fireboard/README.md",
    "content": "# Fireboard Input Plugin\n\nThis plugin gathers real-time temperature data from [fireboard][fireboard]\nthermometers.\n\n> [!NOTE]\n> You will need to sign up to for the [Fireboard REST API][api] in order to use\n> this plugin.\n\n⭐ Telegraf v1.12.0\n🏷️ iot\n💻 all\n\n[fireboard]: https://www.fireboard.com\n[api]: https://docs.fireboard.io/reference/restapi.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read real time temps from fireboard.io servers\n[[inputs.fireboard]]\n  ## Specify auth token for your account\n  auth_token = \"invalidAuthToken\"\n  ## You can override the fireboard server URL if necessary\n  # url = https://fireboard.io/api/v1/devices.json\n  ## You can set a different http_timeout if you need to\n  ## You should set a string using an number and time indicator\n  ## for example \"12s\" for 12 seconds.\n  # http_timeout = \"4s\"\n```\n\n### auth_token\n\nIn lieu of requiring a username and password, this plugin requires an\nauthentication token that you can generate using the [Fireboard REST\nAPI](https://docs.fireboard.io/reference/restapi.html#Authentication).\n\n### url\n\nWhile there should be no reason to override the URL, the option is available\nin case Fireboard changes their site, etc.\n\n### http_timeout\n\nIf you need to increase the HTTP timeout, you can do so here. You can set this\nvalue in seconds. The default value is four (4) seconds.\n\n## Metrics\n\nThe Fireboard REST API docs have good examples of the data that is available,\ncurrently this input only returns the real time temperatures. Temperature\nvalues are included if they are less than a minute old.\n\n- fireboard\n  - tags:\n    - channel\n    - scale (Celcius; Fahrenheit)\n    - title (name of the Fireboard)\n    - uuid (UUID of the Fireboard)\n  - fields:\n    - temperature (float, unit)\n\n## Example Output\n\nThis section shows example output in Line Protocol format.  You can often use\n`telegraf --input-filter <plugin-name> --test` or use the `file` output to get\nthis information.\n\n```text\nfireboard,channel=2,host=patas-mbp,scale=Fahrenheit,title=telegraf-FireBoard,uuid=b55e766c-b308-49b5-93a4-df89fe31efd0 temperature=78.2 1561690040000000000\n```\n"
  },
  {
    "path": "plugins/inputs/fireboard/fireboard.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage fireboard\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Fireboard struct {\n\tAuthToken   string          `toml:\"auth_token\"`\n\tURL         string          `toml:\"url\"`\n\tHTTPTimeout config.Duration `toml:\"http_timeout\"`\n\n\tclient *http.Client\n}\n\ntype rtt struct {\n\tTemp       float64 `json:\"temp\"`\n\tChannel    int64   `json:\"channel\"`\n\tDegreeType int     `json:\"degreetype\"`\n\tCreated    string  `json:\"created\"`\n}\n\ntype fireboardStats struct {\n\tTitle       string `json:\"title\"`\n\tUUID        string `json:\"uuid\"`\n\tLatestTemps []rtt  `json:\"latest_temps\"`\n}\n\nfunc (*Fireboard) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Fireboard) Init() error {\n\tif len(r.AuthToken) == 0 {\n\t\treturn errors.New(\"you must specify an authToken\")\n\t}\n\tif len(r.URL) == 0 {\n\t\tr.URL = \"https://fireboard.io/api/v1/devices.json\"\n\t}\n\t// Have a default timeout of 4s\n\tif r.HTTPTimeout == 0 {\n\t\tr.HTTPTimeout = config.Duration(time.Second * 4)\n\t}\n\n\tr.client.Timeout = time.Duration(r.HTTPTimeout)\n\n\treturn nil\n}\n\nfunc (r *Fireboard) Gather(acc telegraf.Accumulator) error {\n\t// Perform the GET request to the fireboard servers\n\treq, err := http.NewRequest(\"GET\", r.URL, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Set(\"Authorization\", \"Token \"+r.AuthToken)\n\tresp, err := r.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\t// Successful responses will always return status code 200\n\tif resp.StatusCode != http.StatusOK {\n\t\tif resp.StatusCode == http.StatusForbidden {\n\t\t\treturn fmt.Errorf(\"fireboard server responded with %d [Forbidden], verify your authToken\", resp.StatusCode)\n\t\t}\n\t\treturn fmt.Errorf(\"fireboard responded with unexpected status code %d\", resp.StatusCode)\n\t}\n\t// Decode the response JSON into a new stats struct\n\tvar stats []fireboardStats\n\tif err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {\n\t\treturn fmt.Errorf(\"unable to decode fireboard response: %w\", err)\n\t}\n\t// Range over all devices, gathering stats. Returns early in case of any error.\n\tfor _, s := range stats {\n\t\tgatherTemps(s, acc)\n\t}\n\treturn nil\n}\n\n// Return text description of degree type (scale)\nfunc scale(n int) string {\n\tswitch n {\n\tcase 1:\n\t\treturn \"Celcius\"\n\tcase 2:\n\t\treturn \"Fahrenheit\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// Gathers stats from a single device, adding them to the accumulator\nfunc gatherTemps(s fireboardStats, acc telegraf.Accumulator) {\n\t// Construct lookup for scale values\n\n\tfor _, t := range s.LatestTemps {\n\t\ttags := map[string]string{\n\t\t\t\"title\":   s.Title,\n\t\t\t\"uuid\":    s.UUID,\n\t\t\t\"channel\": strconv.FormatInt(t.Channel, 10),\n\t\t\t\"scale\":   scale(t.DegreeType),\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"temperature\": t.Temp,\n\t\t}\n\t\tacc.AddFields(\"fireboard\", fields, tags)\n\t}\n}\n\nfunc newFireboard() *Fireboard {\n\ttr := &http.Transport{ResponseHeaderTimeout: 3 * time.Second}\n\tclient := &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   4 * time.Second,\n\t}\n\treturn &Fireboard{client: client}\n}\n\nfunc init() {\n\tinputs.Add(\"fireboard\", func() telegraf.Input {\n\t\treturn newFireboard()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/fireboard/fireboard_test.go",
    "content": "package fireboard\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFireboard(t *testing.T) {\n\t// Create a test server with the const response JSON\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := fmt.Fprintln(w, response); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Parse the URL of the test server, used to verify the expected host\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\t// Create a new fb instance with our given test server\n\tfireboard := newFireboard()\n\tfireboard.AuthToken = \"b4bb6e6a7b6231acb9f71b304edb2274693d8849\"\n\tfireboard.URL = u.String()\n\n\t// Create a test accumulator\n\tacc := &testutil.Accumulator{}\n\n\t// Gather data from the test server\n\terr = fireboard.Gather(acc)\n\trequire.NoError(t, err)\n\n\t// Expect the correct values for all known keys\n\texpectFields := map[string]interface{}{\n\t\t\"temperature\": float64(79.9),\n\t}\n\t// Expect the correct values for all tags\n\texpectTags := map[string]string{\n\t\t\"title\":   \"telegraf-FireBoard\",\n\t\t\"uuid\":    \"b55e766c-b308-49b5-93a4-df89fe31efd0\",\n\t\t\"channel\": strconv.FormatInt(1, 10),\n\t\t\"scale\":   \"Fahrenheit\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"fireboard\", expectFields, expectTags)\n}\n\nvar response = `\n[{\n\t\"id\": 99999,\n\t\"title\": \"telegraf-FireBoard\",\n\t\"created\": \"2019-03-23T16:48:32.152010Z\",\n\t\"uuid\": \"b55e766c-b308-49b5-93a4-df89fe31efd0\",\n\t\"hardware_id\": \"XXXXXXXXX\",\n\t\"latest_temps\": [\n\t  {\n\t\t\"temp\": 79.9,\n\t\t\"channel\": 1,\n\t\t\"degreetype\": 2,\n\t\t\"created\": \"2019-06-25T06:07:10Z\"\n\t  }\n\t],\n\t\"last_templog\": \"2019-06-25T06:06:40Z\",\n\t\"model\": \"FBX11E\",\n\t\"channel_count\": 6,\n\t\"degreetype\": 2\n  }]\n`\n"
  },
  {
    "path": "plugins/inputs/fireboard/sample.conf",
    "content": "# Read real time temps from fireboard.io servers\n[[inputs.fireboard]]\n  ## Specify auth token for your account\n  auth_token = \"invalidAuthToken\"\n  ## You can override the fireboard server URL if necessary\n  # url = https://fireboard.io/api/v1/devices.json\n  ## You can set a different http_timeout if you need to\n  ## You should set a string using an number and time indicator\n  ## for example \"12s\" for 12 seconds.\n  # http_timeout = \"4s\"\n"
  },
  {
    "path": "plugins/inputs/firehose/README.md",
    "content": "# AWS Data Firehose Input Plugin\n\nThis plugin listens for metrics sent via HTTP from [AWS Data Firehose][firehose]\nin one of the supported [data formats][data_formats].\nThe plugin strictly follows the request-response schema as describe in the\nofficial [documentation][response_spec].\n\n⭐ Telegraf v1.34.0\n🏷️ cloud, messaging\n💻 all\n\n[firehose]: https://aws.amazon.com/de/firehose/\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n[response_spec]: https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# AWS Data Firehose listener\n[[inputs.firehose]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8080\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"5s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"5s\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional access key to accept for authentication.\n  ## AWS Data Firehose uses \"x-amz-firehose-access-key\" header to set the access key.\n  ## If no access_key is provided (default), authentication is completely disabled and\n  ## this plugin will accept all request ignoring the provided access-key in the request!\n  # access_key = \"foobar\"\n\n  ## Optional setting to add parameters as tags\n  ## If the http header \"x-amz-firehose-common-attributes\" is not present on the\n  ## request, no corresponding tag will be added. The header value should be a\n  ## json and should follow the schema as describe in the official documentation:\n  ## https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html#requestformat\n  # parameter_tags = [\"env\"]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n```\n\n## Metrics\n\nMetrics are collected from the `records.[*].data` field in the request body.\nThe data must be base64 encoded and may be sent in any supported\n[data format][data_formats].\n\n## Example Output\n\nWhen run with this configuration:\n\n```toml\n[[inputs.firehose]]\n  service_address = \":8080\"\n  paths = [\"/telegraf\"]\n  data_format = \"value\"\n  data_type = \"string\"\n```\n\nthe following curl command:\n\n```sh\ncurl -i -XPOST 'localhost:8080/telegraf' \\\n--header 'x-amz-firehose-request-id: ed4acda5-034f-9f42-bba1-f29aea6d7d8f' \\\n--header 'Content-Type: application/json' \\\n--data '{\n    \"requestId\": \"ed4acda5-034f-9f42-bba1-f29aea6d7d8f\",\n    \"timestamp\": 1578090901599,\n    \"records\": [\n        {\n          \"data\": \"aGVsbG8gd29ybGQK\" // \"hello world\"\n        }\n    ]\n}'\n```\n\nproduces:\n\n```text\nfirehose,firehose_http_path=/telegraf value=\"hello world\" 1725001851000000000\n```\n"
  },
  {
    "path": "plugins/inputs/firehose/firehose.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage firehose\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Firehose struct {\n\tServiceAddress string          `toml:\"service_address\"`\n\tPaths          []string        `toml:\"paths\"`\n\tReadTimeout    config.Duration `toml:\"read_timeout\"`\n\tWriteTimeout   config.Duration `toml:\"write_timeout\"`\n\tAccessKey      config.Secret   `toml:\"access_key\"`\n\tParameterTags  []string        `toml:\"parameter_tags\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tcommon_tls.ServerConfig\n\ttlsConf *tls.Config\n\n\tonce sync.Once\n\n\tlistener net.Listener\n\tserver   http.Server\n\n\tparser telegraf.Parser\n\tacc    telegraf.Accumulator\n}\n\nfunc (*Firehose) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *Firehose) SetParser(parser telegraf.Parser) {\n\tf.parser = parser\n}\n\nfunc (f *Firehose) Init() error {\n\tif f.ServiceAddress == \"\" {\n\t\tf.ServiceAddress = \":8080\"\n\t}\n\tif len(f.Paths) == 0 {\n\t\tf.Paths = []string{\"/telegraf\"}\n\t}\n\n\tvar err error\n\tf.tlsConf, err = f.ServerConfig.TLSConfig()\n\treturn err\n}\n\n// Start starts the http listener service.\nfunc (f *Firehose) Start(acc telegraf.Accumulator) error {\n\tf.acc = acc\n\n\tvar err error\n\tif f.tlsConf != nil {\n\t\tf.listener, err = tls.Listen(\"tcp\", f.ServiceAddress, f.tlsConf)\n\t} else {\n\t\tf.listener, err = net.Listen(\"tcp\", f.ServiceAddress)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating listener failed: %w\", err)\n\t}\n\n\tf.server = http.Server{\n\t\tAddr:         f.ServiceAddress,\n\t\tHandler:      f,\n\t\tReadTimeout:  time.Duration(f.ReadTimeout),\n\t\tWriteTimeout: time.Duration(f.WriteTimeout),\n\t\tTLSConfig:    f.tlsConf,\n\t}\n\n\tgo func() {\n\t\tif err := f.server.Serve(f.listener); err != nil {\n\t\t\tif !errors.Is(err, net.ErrClosed) {\n\t\t\t\tf.Log.Errorf(\"Server failed: %v\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tf.Log.Infof(\"Listening on %s\", f.listener.Addr().String())\n\n\treturn nil\n}\n\n// Stop cleans up all resources\nfunc (f *Firehose) Stop() {\n\tif err := f.server.Shutdown(context.Background()); err != nil {\n\t\tf.Log.Errorf(\"Shutting down server failed: %v\", err)\n\t}\n}\n\nfunc (*Firehose) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (f *Firehose) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\tif !slices.Contains(f.Paths, req.URL.Path) {\n\t\tres.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\tmsg, err := f.handleRequest(req)\n\tif err != nil {\n\t\tf.acc.AddError(err)\n\t}\n\tif err := msg.sendResponse(res); err != nil {\n\t\tf.acc.AddError(fmt.Errorf(\"sending response failed: %w\", err))\n\t}\n}\n\nfunc (f *Firehose) handleRequest(req *http.Request) (*message, error) {\n\t// Create a request with a default response status code\n\tmsg := &message{\n\t\tresponseCode: http.StatusInternalServerError,\n\t}\n\n\t// Extract the request ID used to reference the request\n\tmsg.id = req.Header.Get(\"x-amz-firehose-request-id\")\n\tif msg.id == \"\" {\n\t\tmsg.responseCode = http.StatusBadRequest\n\t\treturn msg, errors.New(\"x-amz-firehose-request-id header is not set\")\n\t}\n\n\t// Check the maximum body size which can be up to 64 MiB according to\n\t// https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html\n\tif req.ContentLength > int64(64*1024*1024) {\n\t\tmsg.responseCode = http.StatusRequestEntityTooLarge\n\t\treturn msg, errors.New(\"content length is too large\")\n\t}\n\n\t// Check the HTTP method used\n\tswitch req.Method {\n\tcase http.MethodPost, http.MethodPut:\n\t\t// Do nothing, those methods are allowed\n\tdefault:\n\t\tmsg.responseCode = http.StatusMethodNotAllowed\n\t\treturn msg, fmt.Errorf(\"method %q is not allowed\", req.Method)\n\t}\n\n\tif req.Header.Get(\"content-type\") != \"application/json\" {\n\t\tmsg.responseCode = http.StatusUnsupportedMediaType\n\t\treturn msg, fmt.Errorf(\"content type %q is not allowed\", req.Header.Get(\"content-type\"))\n\t}\n\n\t// Decode the content if necessary and parse the JSON message\n\tencoding := req.Header.Get(\"content-encoding\")\n\tbody, err := internal.NewStreamContentDecoder(encoding, req.Body)\n\tif err != nil {\n\t\tmsg.responseCode = http.StatusUnsupportedMediaType\n\t\treturn msg, fmt.Errorf(\"creating %q decoder for request %q failed: %w\", encoding, msg.id, err)\n\t}\n\tdefer req.Body.Close()\n\n\tvar reqbody requestBody\n\tif err := json.NewDecoder(body).Decode(&reqbody); err != nil {\n\t\tmsg.responseCode = http.StatusBadRequest\n\t\treturn msg, fmt.Errorf(\"decode body for request %q failed: %w\", msg.id, err)\n\t}\n\n\t// Validate the body content\n\tif msg.id != reqbody.RequestID {\n\t\tmsg.responseCode = http.StatusBadRequest\n\t\treturn msg, fmt.Errorf(\"mismatch between request ID in header (%q) and body (%q)\", msg.id, reqbody.RequestID)\n\t}\n\n\t// Authenticate the request\n\tif err := msg.authenticate(req, f.AccessKey); err != nil {\n\t\treturn msg, fmt.Errorf(\"authentication for request %q failed: %w\", msg.id, err)\n\t}\n\n\t// Extract the records and parameters for tagging\n\trecords, err := msg.decodeData(&reqbody)\n\tif err != nil {\n\t\treturn msg, fmt.Errorf(\"decode base64 data from request %q failed: %w\", msg.id, err)\n\t}\n\n\ttags, err := msg.extractTagsFromCommonAttributes(req, f.ParameterTags)\n\tif err != nil {\n\t\treturn msg, fmt.Errorf(\"extracting parameter tags for request %q failed: %w\", msg.id, err)\n\t}\n\n\t// Parse the metrics\n\tvar metrics []telegraf.Metric\n\tfor _, record := range records {\n\t\tm, err := f.parser.Parse(record)\n\t\tif err != nil {\n\t\t\t// respond with bad request status code to inform firehose about the failure\n\t\t\tmsg.responseCode = http.StatusBadRequest\n\t\t\treturn msg, fmt.Errorf(\"parsing data of request %q failed: %w\", msg.id, err)\n\t\t}\n\t\tmetrics = append(metrics, m...)\n\t}\n\n\tif len(metrics) == 0 {\n\t\tf.once.Do(func() {\n\t\t\tf.Log.Info(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\t// Add the extracted tags and the path\n\tfor _, m := range metrics {\n\t\tfor k, v := range tags {\n\t\t\tm.AddTag(k, v)\n\t\t}\n\t\tm.AddTag(\"path\", req.URL.Path)\n\t\tf.acc.AddMetric(m)\n\t}\n\n\tmsg.responseCode = http.StatusOK\n\treturn msg, nil\n}\n\nfunc init() {\n\tinputs.Add(\"firehose\", func() telegraf.Input {\n\t\treturn &Firehose{\n\t\t\tReadTimeout:  config.Duration(time.Second * 5),\n\t\t\tWriteTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/firehose/firehose_request_test.go",
    "content": "package firehose\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInvalidRequests(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\theaders      map[string]string\n\t\tbody         string\n\t\tmethod       string\n\t\texpectedMsg  string\n\t\texpectedCode int\n\t}{\n\t\t{\n\t\t\tname:         \"missing request id\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"\"},\n\t\t\tbody:         `{\"requestId\":\"test-id\",\"timestamp\":1578090901599,\"records\":[{\"data\":\"dGVzdA==\"}]}`,\n\t\t\texpectedMsg:  \"x-amz-firehose-request-id header is not set\",\n\t\t\texpectedCode: 400,\n\t\t},\n\t\t{\n\t\t\tname:         \"request id mismatch\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"test-id\"},\n\t\t\tbody:         `{\"requestId\":\"some-other-id\",\"timestamp\":1578090901599,\"records\":[{\"data\":\"dGVzdA==\"}]}`,\n\t\t\texpectedMsg:  \"mismatch between request ID\",\n\t\t\texpectedCode: 400,\n\t\t},\n\t\t{\n\t\t\tname:         \"invalid body\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"test-id\"},\n\t\t\tbody:         \"not a json\",\n\t\t\texpectedMsg:  `decode body for request \"test-id\" failed`,\n\t\t\texpectedCode: 400,\n\t\t},\n\t\t{\n\t\t\tname:         \"invalid data encoding\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"test-id\"},\n\t\t\tbody:         `{\"requestId\":\"test-id\",\"timestamp\":1578090901599,\"records\":[{\"data\":\"not a base64 encoded text\"}]}`,\n\t\t\texpectedMsg:  `ecode base64 data from request \"test-id\" failed: illegal base64 data`,\n\t\t\texpectedCode: 400,\n\t\t},\n\t\t{\n\t\t\tname:         \"content too large\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"test-id\"},\n\t\t\tbody:         strings.Repeat(\"x\", 65*1024*1024),\n\t\t\texpectedMsg:  `content length is too large`,\n\t\t\texpectedCode: 413,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid content type\",\n\t\t\theaders: map[string]string{\n\t\t\t\t\"x-amz-firehose-request-id\": \"test-id\",\n\t\t\t\t\"content-type\":              \"application/text\",\n\t\t\t},\n\t\t\tbody:         `{\"requestId\":\"test-id\",\"timestamp\":1578090901599,\"records\":[{\"data\":\"dGVzdA==\"}]}`,\n\t\t\texpectedMsg:  `content type \"application/text\" is not allowed`,\n\t\t\texpectedCode: 415,\n\t\t},\n\t\t{\n\t\t\tname:         \"invalid method\",\n\t\t\theaders:      map[string]string{\"x-amz-firehose-request-id\": \"test-id\"},\n\t\t\tbody:         `{\"requestId\":\"test-id\",\"timestamp\":1578090901599,\"records\":[{\"data\":\"dGVzdA==\"}]}`,\n\t\t\tmethod:       \"GET\",\n\t\t\texpectedMsg:  `method \"GET\" is not allowed`,\n\t\t\texpectedCode: 405,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup plugin and start it\n\t\t\tplugin := &Firehose{\n\t\t\t\tServiceAddress: \"127.0.0.1:0\",\n\t\t\t\tLog:            &testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Get the listening address\n\t\t\taddr := plugin.listener.Addr().String()\n\n\t\t\t// Create a request with the data defined in the test case\n\t\t\tmethod := \"POST\"\n\t\t\tif tt.method != \"\" {\n\t\t\t\tmethod = tt.method\n\t\t\t}\n\t\t\treq, err := http.NewRequest(method, \"http://\"+addr+\"/telegraf\", bytes.NewBufferString(tt.body))\n\t\t\trequire.NoError(t, err)\n\t\t\treq.Header.Set(\"content-type\", \"application/json\")\n\t\t\tfor k, v := range tt.headers {\n\t\t\t\treq.Header.Set(k, v)\n\t\t\t}\n\n\t\t\t// Execute the request\n\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer resp.Body.Close()\n\n\t\t\t// Check the result\n\t\t\trequire.ErrorContains(t, acc.FirstError(), tt.expectedMsg)\n\t\t\trequire.Equal(t, tt.expectedCode, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestAuthentication(t *testing.T) {\n\ttests := []struct {\n\t\tname         string\n\t\tbody         string\n\t\theaders      map[string]string\n\t\tkey          string\n\t\texpectedMsg  string\n\t\texpectedCode int\n\t}{\n\t\t{\n\t\t\tname: \"no auth required\",\n\t\t\theaders: map[string]string{\n\t\t\t\t\"x-amz-firehose-request-id\": \"test-id\",\n\t\t\t},\n\t\t\tbody: `\n\t\t\t{\n\t\t\t  \"requestId\": \"test-id\",\n\t\t\t  \"timestamp\":1734625715000000000,\n\t\t\t  \"records\":[{\"data\":\"dGVzdCB2YWx1ZT00MmkgMTczNDYyNTcxNTAwMDAwMDAwMAo=\"}]\n\t\t\t}`,\n\t\t\texpectedCode: 200,\n\t\t},\n\t\t{\n\t\t\tname: \"no auth required but key sent\",\n\t\t\theaders: map[string]string{\n\t\t\t\t\"x-amz-firehose-request-id\": \"test-id\",\n\t\t\t\t\"x-amz-firehose-access-key\": \"test-key\",\n\t\t\t},\n\t\t\tbody: `\n\t\t\t{\n\t\t\t  \"requestId\": \"test-id\",\n\t\t\t  \"timestamp\":1734625715000000000,\n\t\t\t  \"records\":[{\"data\":\"dGVzdCB2YWx1ZT00MmkgMTczNDYyNTcxNTAwMDAwMDAwMAo=\"}]\n\t\t\t}`,\n\t\t\texpectedCode: 200,\n\t\t},\n\t\t{\n\t\t\tname: \"auth required success\",\n\t\t\theaders: map[string]string{\n\t\t\t\t\"x-amz-firehose-request-id\": \"test-id\",\n\t\t\t\t\"x-amz-firehose-access-key\": \"test-key\",\n\t\t\t},\n\t\t\tbody: `\n\t\t\t{\n\t\t\t  \"requestId\": \"test-id\",\n\t\t\t  \"timestamp\":1734625715000000000,\n\t\t\t  \"records\":[{\"data\":\"dGVzdCB2YWx1ZT00MmkgMTczNDYyNTcxNTAwMDAwMDAwMAo=\"}]\n\t\t\t}`,\n\t\t\tkey:          \"test-key\",\n\t\t\texpectedCode: 200,\n\t\t},\n\t\t{\n\t\t\tname: \"auth required wrong key\",\n\t\t\theaders: map[string]string{\n\t\t\t\t\"x-amz-firehose-request-id\": \"test-id\",\n\t\t\t\t\"x-amz-firehose-access-key\": \"foo bar\",\n\t\t\t},\n\t\t\tbody: `\n\t\t\t{\n\t\t\t  \"requestId\": \"test-id\",\n\t\t\t  \"timestamp\":1734625715000000000,\n\t\t\t  \"records\":[{\"data\":\"dGVzdCB2YWx1ZT00MmkgMTczNDYyNTcxNTAwMDAwMDAwMAo=\"}]\n\t\t\t}`,\n\t\t\tkey:          \"test-key\",\n\t\t\texpectedMsg:  \"unauthorized request\",\n\t\t\texpectedCode: 401,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup plugin\n\t\t\tplugin := &Firehose{\n\t\t\t\tServiceAddress: \"127.0.0.1:0\",\n\t\t\t\tAccessKey:      config.NewSecret([]byte(tt.key)),\n\t\t\t\tLog:            &testutil.Logger{},\n\t\t\t}\n\n\t\t\t// Setup a parser\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tplugin.SetParser(parser)\n\n\t\t\t// Start the plugin\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Get the listening address\n\t\t\taddr := plugin.listener.Addr().String()\n\n\t\t\t// Create a request with the data defined in the test case\n\t\t\treq, err := http.NewRequest(\"POST\", \"http://\"+addr+\"/telegraf\", bytes.NewBufferString(tt.body))\n\t\t\trequire.NoError(t, err)\n\t\t\treq.Header.Set(\"content-type\", \"application/json\")\n\t\t\tfor k, v := range tt.headers {\n\t\t\t\treq.Header.Set(k, v)\n\t\t\t}\n\n\t\t\t// Execute the request\n\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer resp.Body.Close()\n\n\t\t\t// Check the result\n\t\t\tif tt.expectedMsg == \"\" {\n\t\t\t\trequire.NoError(t, acc.FirstError())\n\t\t\t} else {\n\t\t\t\trequire.ErrorContains(t, acc.FirstError(), tt.expectedMsg)\n\t\t\t}\n\t\t\trequire.Equal(t, tt.expectedCode, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"firehose\", func() telegraf.Input {\n\t\treturn &Firehose{\n\t\t\tReadTimeout:  config.Duration(time.Second * 5),\n\t\t\tWriteTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\theaders, bodies, err := readInputData(testcasePath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure and initialize the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\tplugin := cfg.Inputs[0].Input.(*Firehose)\n\t\t\tplugin.ServiceAddress = \"127.0.0.1:0\"\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Start the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Get the listening address\n\t\t\taddr := plugin.listener.Addr().String()\n\n\t\t\t// Set all message bodies\n\t\t\tendpoint := \"http://\" + addr + plugin.Paths[0]\n\t\t\tfor i, body := range bodies {\n\t\t\t\treq, err := http.NewRequest(\"POST\", endpoint, bytes.NewBuffer(body))\n\t\t\t\trequire.NoErrorf(t, err, \"creating request for body %d\", i)\n\t\t\t\treq.Header.Set(\"content-type\", \"application/json\")\n\t\t\t\tfor k, v := range headers {\n\t\t\t\t\treq.Header.Set(k, v)\n\t\t\t\t}\n\n\t\t\t\t// Execute the request\n\t\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\t\trequire.NoErrorf(t, err, \"executing request for body %d\", i)\n\t\t\t\tresp.Body.Close()\n\n\t\t\t\tif len(expectedErrors) == 0 {\n\t\t\t\t\trequire.Equalf(t, 200, resp.StatusCode, \"result for body %d: %v\", i, acc.Errors)\n\t\t\t\t} else {\n\t\t\t\t\trequire.NotEqualf(t, 200, resp.StatusCode, \"result for body %d: %v\", i, acc.Errors)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check the result\n\t\t\tvar actualErrorMsgs []string\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc readInputData(path string) (map[string]string, [][]byte, error) {\n\t// Reading the headers file\n\tvar headers map[string]string\n\theadersBuf, err := os.ReadFile(filepath.Join(path, \"headers.json\"))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif err := json.Unmarshal(headersBuf, &headers); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Read all bodies\n\tbodyFiles, err := filepath.Glob(filepath.Join(path, \"body*.json\"))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tsort.Strings(bodyFiles)\n\tbodies := make([][]byte, 0, len(bodyFiles))\n\tfor _, fn := range bodyFiles {\n\t\tbuf, err := os.ReadFile(fn)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tbodies = append(bodies, buf)\n\t}\n\n\treturn headers, bodies, nil\n}\n"
  },
  {
    "path": "plugins/inputs/firehose/firehose_test.go",
    "content": "package firehose\n"
  },
  {
    "path": "plugins/inputs/firehose/message.go",
    "content": "package firehose\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\n// Firehose request data-structures according to\n// https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html#requestformat\ntype record struct {\n\tEncodedData string `json:\"data\"`\n}\n\ntype requestBody struct {\n\tRequestID string   `json:\"requestId\"`\n\tTimestamp int64    `json:\"timestamp\"`\n\tRecords   []record `json:\"records\"`\n}\n\n// Required response data structure according to\n// https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html#responseformat\ntype responseBody struct {\n\tRequestID    string `json:\"requestId\"`\n\tTimestamp    int64  `json:\"timestamp\"`\n\tErrorMessage string `json:\"errorMessage,omitempty\"`\n}\n\ntype message struct {\n\tid           string\n\tresponseCode int\n}\n\nfunc (m *message) authenticate(req *http.Request, expected config.Secret) error {\n\t// We completely switch off authentication if no 'access_key' was provided in the config, it's intended!\n\tif expected.Empty() {\n\t\treturn nil\n\t}\n\tkey := req.Header.Get(\"x-amz-firehose-access-key\")\n\tmatch, err := expected.EqualTo([]byte(key))\n\tif err != nil {\n\t\tm.responseCode = http.StatusInternalServerError\n\t\treturn fmt.Errorf(\"comparing keys failed: %w\", err)\n\t}\n\tif !match {\n\t\tm.responseCode = http.StatusUnauthorized\n\t\treturn fmt.Errorf(\"unauthorized request from %v\", req.RemoteAddr)\n\t}\n\n\treturn nil\n}\n\nfunc (m *message) decodeData(r *requestBody) ([][]byte, error) {\n\t// Decode base64-encoded data and return them as a slice of byte slices\n\tdecodedData := make([][]byte, 0, len(r.Records))\n\tfor _, record := range r.Records {\n\t\tdata, err := base64.StdEncoding.DecodeString(record.EncodedData)\n\t\tif err != nil {\n\t\t\tm.responseCode = http.StatusBadRequest\n\t\t\treturn nil, err\n\t\t}\n\t\tdecodedData = append(decodedData, data)\n\t}\n\treturn decodedData, nil\n}\n\nfunc (m *message) extractTagsFromCommonAttributes(req *http.Request, tagkeys []string) (map[string]string, error) {\n\ttags := make(map[string]string, len(tagkeys))\n\n\th := req.Header.Get(\"x-amz-firehose-common-attributes\")\n\tif len(tagkeys) == 0 || h == \"\" {\n\t\treturn tags, nil\n\t}\n\n\tvar params map[string]interface{}\n\tif err := json.Unmarshal([]byte(h), &params); err != nil {\n\t\tm.responseCode = http.StatusBadRequest\n\t\treturn nil, fmt.Errorf(\"decoding x-amz-firehose-common-attributes header failed: %w\", err)\n\t}\n\n\traw, ok := params[\"commonAttributes\"]\n\tif !ok {\n\t\tm.responseCode = http.StatusBadRequest\n\t\treturn nil, errors.New(\"commonAttributes not found in x-amz-firehose-common-attributes header\")\n\t}\n\n\tattributes, ok := raw.(map[string]interface{})\n\tif !ok {\n\t\tm.responseCode = http.StatusBadRequest\n\t\treturn nil, errors.New(\"parse parameters data failed\")\n\t}\n\tfor _, k := range tagkeys {\n\t\tif v, found := attributes[k]; found {\n\t\t\ttags[k] = v.(string)\n\t\t}\n\t}\n\treturn tags, nil\n}\n\nfunc (m *message) sendResponse(w http.ResponseWriter) error {\n\tvar errorMessage string\n\tif m.responseCode != http.StatusOK {\n\t\terrorMessage = http.StatusText(m.responseCode)\n\t}\n\n\tresponse, err := json.Marshal(responseBody{\n\t\tRequestID:    m.id,\n\t\tTimestamp:    time.Now().Unix(),\n\t\tErrorMessage: errorMessage,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tw.Header().Set(\"content-type\", \"application/json\")\n\tw.WriteHeader(m.responseCode)\n\tif _, err := w.Write(response); err != nil {\n\t\treturn fmt.Errorf(\"writing response to request %s failed: %w\", m.id, err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/firehose/sample.conf",
    "content": "# AWS Data Firehose listener\n[[inputs.firehose]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8080\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"5s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"5s\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional access key to accept for authentication.\n  ## AWS Data Firehose uses \"x-amz-firehose-access-key\" header to set the access key.\n  ## If no access_key is provided (default), authentication is completely disabled and\n  ## this plugin will accept all request ignoring the provided access-key in the request!\n  # access_key = \"foobar\"\n\n  ## Optional setting to add parameters as tags\n  ## If the http header \"x-amz-firehose-common-attributes\" is not present on the\n  ## request, no corresponding tag will be added. The header value should be a\n  ## json and should follow the schema as describe in the official documentation:\n  ## https://docs.aws.amazon.com/firehose/latest/dev/httpdeliveryrequestresponse.html#requestformat\n  # parameter_tags = [\"env\"]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/firehose/testcases/common-attributes/body.json",
    "content": "{\n    \"requestId\": \"telegraf-test-id\",\n    \"timestamp\":1734625715000000000,\n    \"records\":[{\"data\":\"dGVzdCB2YWx1ZT00MmkgMTczNDYyNTcxNTAwMDAwMDAwMAo=\"}]\n}"
  },
  {
    "path": "plugins/inputs/firehose/testcases/common-attributes/expected.out",
    "content": "test,device=pc,deployment=prod,path=/telegraf value=42i 1734625715000000000\n"
  },
  {
    "path": "plugins/inputs/firehose/testcases/common-attributes/headers.json",
    "content": "{\n    \"x-amz-firehose-request-id\": \"telegraf-test-id\",\n    \"x-amz-firehose-access-key\": \"secret\",\n    \"x-amz-firehose-common-attributes\": \"{\\\"commonAttributes\\\": {\\\"deployment\\\": \\\"prod\\\", \\\"device\\\": \\\"pc\\\"}}\"\n}"
  },
  {
    "path": "plugins/inputs/firehose/testcases/common-attributes/telegraf.conf",
    "content": "[[inputs.firehose]]\n  service_address = \"dummy\"\n  access_key = \"secret\"\n  parameter_tags = [\"deployment\", \"device\"]\n"
  },
  {
    "path": "plugins/inputs/fluentd/README.md",
    "content": "# Fluentd Input Plugin\n\nThis plugin gathers internal metrics of a [fluentd][fluentd] instance provided\nby fluentd's [monitor agent plugin][monitor_agent]. Data provided\nby the `/api/plugin.json` resource, `/api/config.json` is not covered.\n\n> [!IMPORTANT]\n> This plugin might produce high-cardinality series as the `plugin_id` value is\n> random after each restart of fluentd.  You might need to adjust your fluentd\n> configuration, in order to reduce series cardinality in case your fluentd\n> restarts frequently by adding the `@id` parameter to each plugin.\n> See [fluentd's documentation][docs] for details.\n\n⭐ Telegraf v1.4.0\n🏷️ server\n💻 all\n\n[fluentd]: https://www.fluentd.org/\n[monitor_agent]: https://docs.fluentd.org/input/monitor_agent\n[docs]: https://docs.fluentd.org/configuration/config-file#common-plugin-parameter\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics exposed by fluentd in_monitor plugin\n[[inputs.fluentd]]\n  ## This plugin reads information exposed by fluentd (using /api/plugins.json endpoint).\n  ##\n  ## Endpoint:\n  ## - only one URI is allowed\n  ## - https is not supported\n  endpoint = \"http://localhost:24220/api/plugins.json\"\n\n  ## Define which plugins have to be excluded (based on \"type\" field - e.g. monitor_agent)\n  exclude = [\n    \"monitor_agent\",\n    \"dummy\",\n  ]\n```\n\n## Metrics\n\n### Measurements & Fields\n\nFields may vary depending on the plugin type\n\n- fluentd\n  - retry_count              (float, unit)\n  - buffer_queue_length      (float, unit)\n  - buffer_total_queued_size (float, unit)\n  - rollback_count           (float, unit)\n  - flush_time_count         (float, unit)\n  - slow_flush_count         (float, unit)\n  - emit_count               (float, unit)\n  - emit_records             (float, unit)\n  - emit_size                (float, unit)\n  - write_count              (float, unit)\n  - buffer_stage_length      (float, unit)\n  - buffer_queue_byte_size   (float, unit)\n  - buffer_stage_byte_size   (float, unit)\n  - buffer_available_buffer_space_ratios (float, unit)\n\n### Tags\n\n- All measurements have the following tags:\n  - plugin_id        (unique plugin id)\n  - plugin_type      (type of the plugin e.g. s3)\n    - plugin_category  (plugin category e.g. output)\n\n## Example Output\n\n```text\nfluentd,host=T440s,plugin_id=object:9f748c,plugin_category=input,plugin_type=dummy buffer_total_queued_size=0,buffer_queue_length=0,retry_count=0 1492006105000000000\nfluentd,plugin_category=input,plugin_type=dummy,host=T440s,plugin_id=object:8da98c buffer_queue_length=0,retry_count=0,buffer_total_queued_size=0 1492006105000000000\nfluentd,plugin_id=object:820190,plugin_category=input,plugin_type=monitor_agent,host=T440s retry_count=0,buffer_total_queued_size=0,buffer_queue_length=0 1492006105000000000\nfluentd,plugin_id=object:c5e054,plugin_category=output,plugin_type=stdout,host=T440s buffer_queue_length=0,retry_count=0,buffer_total_queued_size=0 1492006105000000000\nfluentd,plugin_type=s3,host=T440s,plugin_id=object:bd7a90,plugin_category=output buffer_queue_length=0,retry_count=0,buffer_total_queued_size=0 1492006105000000000\nfluentd,plugin_id=output_td, plugin_category=output,plugin_type=tdlog, host=T440s buffer_available_buffer_space_ratios=100,buffer_queue_byte_size=0,buffer_queue_length=0,buffer_stage_byte_size=0,buffer_stage_length=0,buffer_total_queued_size=0,emit_count=0,emit_records=0,flush_time_count=0,retry_count=0,rollback_count=0,slow_flush_count=0,write_count=0 1651474085000000000\n```\n"
  },
  {
    "path": "plugins/inputs/fluentd/fluentd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage fluentd\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst measurement = \"fluentd\"\n\ntype Fluentd struct {\n\tEndpoint string   `toml:\"endpoint\"`\n\tExclude  []string `toml:\"exclude\"`\n\n\tclient *http.Client\n}\n\ntype endpointInfo struct {\n\tPayload []pluginData `json:\"plugins\"`\n}\n\ntype pluginData struct {\n\tPluginID               string   `json:\"plugin_id\"`\n\tPluginType             string   `json:\"type\"`\n\tPluginCategory         string   `json:\"plugin_category\"`\n\tRetryCount             *float64 `json:\"retry_count\"`\n\tBufferQueueLength      *float64 `json:\"buffer_queue_length\"`\n\tBufferTotalQueuedSize  *float64 `json:\"buffer_total_queued_size\"`\n\tRollbackCount          *float64 `json:\"rollback_count\"`\n\tEmitRecords            *float64 `json:\"emit_records\"`\n\tEmitSize               *float64 `json:\"emit_size\"`\n\tEmitCount              *float64 `json:\"emit_count\"`\n\tWriteCount             *float64 `json:\"write_count\"`\n\tSlowFlushCount         *float64 `json:\"slow_flush_count\"`\n\tFlushTimeCount         *float64 `json:\"flush_time_count\"`\n\tBufferStageLength      *float64 `json:\"buffer_stage_length\"`\n\tBufferStageByteSize    *float64 `json:\"buffer_stage_byte_size\"`\n\tBufferQueueByteSize    *float64 `json:\"buffer_queue_byte_size\"`\n\tAvailBufferSpaceRatios *float64 `json:\"buffer_available_buffer_space_ratios\"`\n}\n\nfunc (*Fluentd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *Fluentd) Gather(acc telegraf.Accumulator) error {\n\t_, err := url.Parse(h.Endpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid URL %q\", h.Endpoint)\n\t}\n\n\tif h.client == nil {\n\t\ttr := &http.Transport{\n\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t}\n\n\t\tclient := &http.Client{\n\t\t\tTransport: tr,\n\t\t\tTimeout:   4 * time.Second,\n\t\t}\n\n\t\th.client = client\n\t}\n\n\tresp, err := h.client.Get(h.Endpoint)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to perform HTTP client GET on %q: %w\", h.Endpoint, err)\n\t}\n\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to read the HTTP body %q: %w\", string(body), err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn errors.New(\"http status ok not met\")\n\t}\n\n\tdataPoints, err := parse(body)\n\n\tif err != nil {\n\t\treturn errors.New(\"problem with parsing\")\n\t}\n\n\t// Go through all plugins one by one\n\tfor _, p := range dataPoints {\n\t\tskip := false\n\n\t\t// Check if this specific type was excluded in configuration\n\t\tfor _, exclude := range h.Exclude {\n\t\t\tif exclude == p.PluginType {\n\t\t\t\tskip = true\n\t\t\t}\n\t\t}\n\n\t\t// If not, create new metric and add it to Accumulator\n\t\tif !skip {\n\t\t\ttmpFields := make(map[string]interface{})\n\n\t\t\ttmpTags := map[string]string{\n\t\t\t\t\"plugin_id\":       p.PluginID,\n\t\t\t\t\"plugin_category\": p.PluginCategory,\n\t\t\t\t\"plugin_type\":     p.PluginType,\n\t\t\t}\n\n\t\t\tif p.BufferQueueLength != nil {\n\t\t\t\ttmpFields[\"buffer_queue_length\"] = *p.BufferQueueLength\n\t\t\t}\n\n\t\t\tif p.RetryCount != nil {\n\t\t\t\ttmpFields[\"retry_count\"] = *p.RetryCount\n\t\t\t}\n\n\t\t\tif p.BufferTotalQueuedSize != nil {\n\t\t\t\ttmpFields[\"buffer_total_queued_size\"] = *p.BufferTotalQueuedSize\n\t\t\t}\n\n\t\t\tif p.RollbackCount != nil {\n\t\t\t\ttmpFields[\"rollback_count\"] = *p.RollbackCount\n\t\t\t}\n\n\t\t\tif p.EmitRecords != nil {\n\t\t\t\ttmpFields[\"emit_records\"] = *p.EmitRecords\n\t\t\t}\n\n\t\t\tif p.EmitCount != nil {\n\t\t\t\ttmpFields[\"emit_count\"] = *p.EmitCount\n\t\t\t}\n\n\t\t\tif p.EmitSize != nil {\n\t\t\t\ttmpFields[\"emit_size\"] = *p.EmitSize\n\t\t\t}\n\n\t\t\tif p.WriteCount != nil {\n\t\t\t\ttmpFields[\"write_count\"] = *p.WriteCount\n\t\t\t}\n\n\t\t\tif p.SlowFlushCount != nil {\n\t\t\t\ttmpFields[\"slow_flush_count\"] = *p.SlowFlushCount\n\t\t\t}\n\n\t\t\tif p.FlushTimeCount != nil {\n\t\t\t\ttmpFields[\"flush_time_count\"] = *p.FlushTimeCount\n\t\t\t}\n\n\t\t\tif p.BufferStageLength != nil {\n\t\t\t\ttmpFields[\"buffer_stage_length\"] = *p.BufferStageLength\n\t\t\t}\n\n\t\t\tif p.BufferStageByteSize != nil {\n\t\t\t\ttmpFields[\"buffer_stage_byte_size\"] = *p.BufferStageByteSize\n\t\t\t}\n\n\t\t\tif p.BufferQueueByteSize != nil {\n\t\t\t\ttmpFields[\"buffer_queue_byte_size\"] = *p.BufferQueueByteSize\n\t\t\t}\n\n\t\t\tif p.AvailBufferSpaceRatios != nil {\n\t\t\t\ttmpFields[\"buffer_available_buffer_space_ratios\"] = *p.AvailBufferSpaceRatios\n\t\t\t}\n\n\t\t\tif p.BufferQueueLength != nil ||\n\t\t\t\tp.RetryCount != nil ||\n\t\t\t\tp.BufferTotalQueuedSize != nil ||\n\t\t\t\tp.EmitCount != nil ||\n\t\t\t\tp.EmitRecords != nil ||\n\t\t\t\tp.EmitSize != nil ||\n\t\t\t\tp.WriteCount != nil ||\n\t\t\t\tp.FlushTimeCount != nil ||\n\t\t\t\tp.SlowFlushCount != nil ||\n\t\t\t\tp.RollbackCount != nil ||\n\t\t\t\tp.BufferStageLength != nil ||\n\t\t\t\tp.BufferStageByteSize != nil ||\n\t\t\t\tp.BufferQueueByteSize != nil ||\n\t\t\t\tp.AvailBufferSpaceRatios != nil {\n\t\t\t\tacc.AddFields(measurement, tmpFields, tmpTags)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// parse JSON from fluentd Endpoint\n// Parameters:\n//\n//\tdata: unprocessed json received from endpoint\n//\n// Returns:\n//\n//\tpluginData:\t\tslice that contains parsed plugins\n//\terror:\t\t\terror that may have occurred\nfunc parse(data []byte) (datapointArray []pluginData, err error) {\n\tvar endpointData endpointInfo\n\n\tif err = json.Unmarshal(data, &endpointData); err != nil {\n\t\terr = errors.New(\"processing JSON structure\")\n\t\treturn nil, err\n\t}\n\n\tdatapointArray = append(datapointArray, endpointData.Payload...)\n\treturn datapointArray, err\n}\n\nfunc init() {\n\tinputs.Add(\"fluentd\", func() telegraf.Input { return &Fluentd{} })\n}\n"
  },
  {
    "path": "plugins/inputs/fluentd/fluentd_test.go",
    "content": "package fluentd\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// sampleJSON from fluentd version '0.14.9'\nconst sampleJSON = `\n{\n  \"plugins\": [\n    {\n      \"plugin_id\": \"object:f48698\",\n      \"plugin_category\": \"input\",\n      \"type\": \"dummy\",\n      \"config\": {\n        \"@type\": \"dummy\",\n        \"@log_level\": \"info\",\n        \"tag\": \"stdout.page.node\",\n        \"rate\": \"\",\n        \"dummy\": \"{\\\"hello\\\":\\\"world_from_first_dummy\\\"}\",\n        \"auto_increment_key\": \"id1\"\n      },\n      \"output_plugin\": false,\n      \"retry_count\": null\n    },\n    {\n      \"plugin_id\": \"object:e27138\",\n      \"plugin_category\": \"input\",\n      \"type\": \"dummy\",\n      \"config\": {\n        \"@type\": \"dummy\",\n        \"@log_level\": \"info\",\n        \"tag\": \"stdout.superproject.supercontainer\",\n        \"rate\": \"\",\n        \"dummy\": \"{\\\"hello\\\":\\\"world_from_second_dummy\\\"}\",\n        \"auto_increment_key\": \"id1\"\n      },\n      \"output_plugin\": false,\n      \"retry_count\": null\n    },\n    {\n      \"plugin_id\": \"object:d74060\",\n      \"plugin_category\": \"input\",\n      \"type\": \"monitor_agent\",\n      \"config\": {\n        \"@type\": \"monitor_agent\",\n        \"@log_level\": \"error\",\n        \"bind\": \"0.0.0.0\",\n        \"port\": \"24220\"\n      },\n      \"output_plugin\": false,\n      \"retry_count\": null\n    },\n    {\n      \"plugin_id\": \"object:11a5e2c\",\n      \"plugin_category\": \"output\",\n      \"type\": \"stdout\",\n      \"config\": {\n        \"@type\": \"stdout\"\n      },\n      \"output_plugin\": true,\n      \"retry_count\": 0\n    },\n    {\n      \"plugin_id\": \"object:11237ec\",\n      \"plugin_category\": \"output\",\n      \"type\": \"s3\",\n      \"config\": {\n        \"@type\": \"s3\",\n        \"@log_level\": \"info\",\n        \"aws_key_id\": \"xxxxxx\",\n        \"aws_sec_key\": \"xxxxxx\",\n        \"s3_bucket\": \"bucket\",\n        \"s3_endpoint\": \"http://mock:4567\",\n        \"path\": \"logs/%Y%m%d_%H/${tag[1]}/\",\n        \"time_slice_format\": \"%M\",\n        \"s3_object_key_format\": \"%{path}%{time_slice}_%{hostname}_%{index}_%{hex_random}.%{file_extension}\",\n        \"store_as\": \"gzip\"\n      },\n      \"output_plugin\": true,\n      \"buffer_queue_length\": 0,\n      \"retry_count\": 0,\n      \"buffer_total_queued_size\": 0\n    },\n    {\n      \"plugin_id\": \"object:output_td_1\",\n      \"plugin_category\": \"output\",\n      \"type\": \"tdlog\",\n      \"config\": {\n        \"@type\": \"tdlog\",\n        \"@id\": \"output_td\",\n        \"apikey\": \"xxxxxx\",\n        \"auto_create_table\": \"\"\n      },\n      \"output_plugin\": true,\n      \"buffer_queue_length\": 0,\n      \"buffer_total_queued_size\": 0,\n      \"retry_count\": 0,\n      \"emit_records\": 0,\n      \"emit_size\": 0,\n      \"emit_count\": 0,\n      \"write_count\": 0,\n      \"rollback_count\": 0,\n      \"slow_flush_count\": 0,\n      \"flush_time_count\": 0,\n      \"buffer_stage_length\": 0,\n      \"buffer_stage_byte_size\": 0,\n      \"buffer_queue_byte_size\": 0,\n      \"buffer_available_buffer_space_ratios\": 0\n    },\n    {\n      \"plugin_id\": \"object:output_td_2\",\n      \"plugin_category\": \"output\",\n      \"type\": \"tdlog\",\n      \"config\": {\n        \"@type\": \"tdlog\",\n        \"@id\": \"output_td\",\n        \"apikey\": \"xxxxxx\",\n        \"auto_create_table\": \"\"\n      },\n      \"output_plugin\": true,\n      \"buffer_queue_length\": 0,\n      \"buffer_total_queued_size\": 0,\n      \"retry_count\": 0,\n      \"rollback_count\": 0,\n      \"emit_records\": 0,\n      \"slow_flush_count\": 0,\n      \"buffer_available_buffer_space_ratios\": 0\n    }\n  ]\n}\n`\n\nvar (\n\tzero           float64\n\texpectedOutput = []pluginData{\n\t\t// \t\t{\"object:f48698\", \"dummy\", \"input\", nil, nil, nil},\n\t\t// \t\t{\"object:e27138\", \"dummy\", \"input\", nil, nil, nil},\n\t\t// \t\t{\"object:d74060\", \"monitor_agent\", \"input\", nil, nil, nil},\n\t\t{\"object:11a5e2c\", \"stdout\", \"output\", &zero, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},\n\t\t{\"object:11237ec\", \"s3\", \"output\", &zero, &zero, &zero, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},\n\t\t{\"object:output_td_1\", \"tdlog\", \"output\", &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero},\n\t\t{\"object:output_td_2\", \"tdlog\", \"output\", &zero, &zero, &zero, &zero, &zero, nil, nil, nil, &zero, nil, nil, nil, nil, &zero},\n\t}\n\tfluentdTest = &Fluentd{\n\t\tEndpoint: \"http://localhost:8081\",\n\t}\n)\n\nfunc Test_parse(t *testing.T) {\n\tt.Log(\"Testing parser function\")\n\tt.Logf(\"JSON (%s) \", sampleJSON)\n\t_, err := parse([]byte(sampleJSON))\n\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Gather(t *testing.T) {\n\tt.Logf(\"Start HTTP mock (%s) with sampleJSON\", fluentdTest.Endpoint)\n\n\tts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(w, \"%s\", sampleJSON); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\n\trequestURL, err := url.Parse(fluentdTest.Endpoint)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, requestURL)\n\n\tts.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(t, err)\n\n\tts.Start()\n\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\terr = fluentdTest.Gather(&acc)\n\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\n\tif !acc.HasMeasurement(\"fluentd\") {\n\t\tt.Errorf(\"acc.HasMeasurement: expected fluentd\")\n\t}\n\n\trequire.Equal(t, expectedOutput[0].PluginID, acc.Metrics[0].Tags[\"plugin_id\"])\n\trequire.Equal(t, expectedOutput[0].PluginType, acc.Metrics[0].Tags[\"plugin_type\"])\n\trequire.Equal(t, expectedOutput[0].PluginCategory, acc.Metrics[0].Tags[\"plugin_category\"])\n\trequire.InDelta(t, *expectedOutput[0].RetryCount, acc.Metrics[0].Fields[\"retry_count\"], testutil.DefaultDelta)\n\n\trequire.Equal(t, expectedOutput[1].PluginID, acc.Metrics[1].Tags[\"plugin_id\"])\n\trequire.Equal(t, expectedOutput[1].PluginType, acc.Metrics[1].Tags[\"plugin_type\"])\n\trequire.Equal(t, expectedOutput[1].PluginCategory, acc.Metrics[1].Tags[\"plugin_category\"])\n\trequire.InDelta(t, *expectedOutput[1].RetryCount, acc.Metrics[1].Fields[\"retry_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[1].BufferQueueLength, acc.Metrics[1].Fields[\"buffer_queue_length\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[1].BufferTotalQueuedSize, acc.Metrics[1].Fields[\"buffer_total_queued_size\"], testutil.DefaultDelta)\n\n\trequire.Equal(t, expectedOutput[2].PluginID, acc.Metrics[2].Tags[\"plugin_id\"])\n\trequire.Equal(t, expectedOutput[2].PluginType, acc.Metrics[2].Tags[\"plugin_type\"])\n\trequire.Equal(t, expectedOutput[2].PluginCategory, acc.Metrics[2].Tags[\"plugin_category\"])\n\trequire.InDelta(t, *expectedOutput[2].RetryCount, acc.Metrics[2].Fields[\"retry_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].BufferQueueLength, acc.Metrics[2].Fields[\"buffer_queue_length\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].BufferTotalQueuedSize, acc.Metrics[2].Fields[\"buffer_total_queued_size\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].EmitRecords, acc.Metrics[2].Fields[\"emit_records\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].EmitSize, acc.Metrics[2].Fields[\"emit_size\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].EmitCount, acc.Metrics[2].Fields[\"emit_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].RollbackCount, acc.Metrics[2].Fields[\"rollback_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].SlowFlushCount, acc.Metrics[2].Fields[\"slow_flush_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].WriteCount, acc.Metrics[2].Fields[\"write_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].FlushTimeCount, acc.Metrics[2].Fields[\"flush_time_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].BufferStageLength, acc.Metrics[2].Fields[\"buffer_stage_length\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].BufferStageByteSize, acc.Metrics[2].Fields[\"buffer_stage_byte_size\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].BufferQueueByteSize, acc.Metrics[2].Fields[\"buffer_queue_byte_size\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[2].AvailBufferSpaceRatios, acc.Metrics[2].Fields[\"buffer_available_buffer_space_ratios\"], testutil.DefaultDelta)\n\n\trequire.Equal(t, expectedOutput[3].PluginID, acc.Metrics[3].Tags[\"plugin_id\"])\n\trequire.Equal(t, expectedOutput[3].PluginType, acc.Metrics[3].Tags[\"plugin_type\"])\n\trequire.Equal(t, expectedOutput[3].PluginCategory, acc.Metrics[3].Tags[\"plugin_category\"])\n\trequire.InDelta(t, *expectedOutput[3].RetryCount, acc.Metrics[3].Fields[\"retry_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].BufferQueueLength, acc.Metrics[3].Fields[\"buffer_queue_length\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].BufferTotalQueuedSize, acc.Metrics[3].Fields[\"buffer_total_queued_size\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].EmitRecords, acc.Metrics[3].Fields[\"emit_records\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].RollbackCount, acc.Metrics[3].Fields[\"rollback_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].SlowFlushCount, acc.Metrics[3].Fields[\"slow_flush_count\"], testutil.DefaultDelta)\n\trequire.InDelta(t, *expectedOutput[3].AvailBufferSpaceRatios, acc.Metrics[3].Fields[\"buffer_available_buffer_space_ratios\"], testutil.DefaultDelta)\n}\n"
  },
  {
    "path": "plugins/inputs/fluentd/sample.conf",
    "content": "# Read metrics exposed by fluentd in_monitor plugin\n[[inputs.fluentd]]\n  ## This plugin reads information exposed by fluentd (using /api/plugins.json endpoint).\n  ##\n  ## Endpoint:\n  ## - only one URI is allowed\n  ## - https is not supported\n  endpoint = \"http://localhost:24220/api/plugins.json\"\n\n  ## Define which plugins have to be excluded (based on \"type\" field - e.g. monitor_agent)\n  exclude = [\n    \"monitor_agent\",\n    \"dummy\",\n  ]\n"
  },
  {
    "path": "plugins/inputs/fritzbox/README.md",
    "content": "# Fritzbox Input Plugin\n\nThis plugin gathers status information from [AVM][avm] devices (routers,\nrepeaters, etc) using the device's [TR-064][tr064] interface.\n\n⭐ Telegraf v1.35.0\n🏷️ network, iot\n💻 all\n\n[avm]: https://en.avm.de/\n[tr064]: https://avm.de/service/schnittstellen/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather fritzbox status\n[[inputs.fritzbox]]\n  ## URLs of the devices to query including login credentials\n  urls = [ \"http://user:password@fritz.box:49000/\" ]\n\n  ## The information to collect (see README for further details).\n  # collect = [\n  #   \"device\",\n  #   \"wan\",\n  #   \"ppp\",\n  #   \"dsl\",\n  #   \"wlan\",\n  # ]\n\n  ## The http timeout to use.\n  # timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### Collect options\n\nThe following collect options are available:\n\n`device` : Collect device information like model name, SW version, uptime etc\nfor the configured devices. Will create `fritzbox_device` metrics.\n\n`wan` : Collect generic WAN connection status like bit rates, transferred\nbytes for the configured devices. Will create `fritzbox_wan`metrics.\n\n`ppp` : Collect PPP connection parameters like bit rates, uptime for the\nconfigured devices. Will create `fritzbox_ppp` metrics.\n\n`dsl` : Collect DSL line status and statistics for the configured devices.\nWill create `fritzbox_dsl` metrics.\n\n`wlan` : Collect status and number of associated devices for all WLANs.\nWill create `fritzbox_wlan` metrics.\n\n`hosts` : Collect detailed information of the mesh network including\nconnected nodes, there role in the network as well as their connection\nbandwidth. Will create `fritzbox_hosts` metrics.\n\n> [!NOTE] Collecting `hosts` metrics is time consuming and generates\n> very detailed data. If you activate this option, consider increasing\n> the plugin's query interval to avoid interval overruns and to minimize\n> the amount of collected data.\n\n## Metrics\n\nBy default field names are directly derived from the corresponding [interface\nspecification][tr064].\n\n- `fritzbox_device`\n  - tags\n    - `source` - The name of the device (this metric has been queried from)\n    - `service` - The service id used to query this metric\n  - fields\n    - `uptime` (uint) - Device's uptime in seconds.\n    - `model_name` (string) - Device's model name.\n    - `serial_number` (string) - Device's serial number.\n    - `hardware_version` (string) - Device's hardware version.\n    - `software_version` (string) - Device's software version.\n- `fritzbox_wan`\n  - tags\n    - `source` - The name of the device (this metric has been queried from)\n    - `service` - The service id used to query this metric\n  - fields\n    - `layer1_upstream_max_bit_rate`   (uint) - WAN interface's maximum upstream\n                                                bit rate (bits/sec)\n    - `layer1_downstream_max_bit_rate` (uint) - WAN interface's maximum\n                                                downstream bit rate (bits/sec)\n    - `upstream_current_max_speed`     (uint) - WAN interface's current maximum\n                                                upstream transfer rate (bytes/sec)\n    - `downstream_current_max_speed`   (uint) - WAN interface's current maximum\n                                                downstream data rate (bytes/sec)\n    - `total_bytes_sent`               (uint) - Total number of bytes sent via\n                                                the WAN interface (bytes)\n    - `total_bytes_received`           (uint) - Total number of bytes received\n                                                via the WAN interface (bytes)\n- `fritzbox_ppp`\n  - tags\n    - `source`  - The name of the device (this metric has been queried from)\n    - `service` - The service id used to query this metric\n  - fields\n    - `uptime`                  (uint) - Uptime of the PPP connection in seconds\n    - `upstream_max_bit_rate`   (uint) - Maximum upstream bit rate negotiated\n                                         for the PPP connection (bits/sec)\n    - `downstream_max_bit_rate` (uint) - Maximum downstream bit rate negotiated\n                                         for the PPP connection (bits/sec)\n- `fritzbox_dsl`\n  - tags\n    - `source`  - The name of the device (this metric has been queried from)\n    - `service` - The service id used to query this metric\n    - `status`  - The status of the DLS line (Up or Down)\n  - fields\n    - `upstream_curr_rate`      (uint) - Current DSL upstream rate (kbits/sec)\n    - `downstream_curr_rate`    (uint) - Current DSL downstream rate (kbits/sec)\n    - `upstream_max_rate`       (uint) - Maximum DSL upstream rate (kbits/sec)\n    - `downstream_max_rate`     (uint) - Maximum DSL downstream rate (kbits/sec)\n    - `upstream_noise_margin`   (uint) - Upstream noise margin (db)\n    - `downstream_noise_margin` (uint) - Downstream noise margin (db)\n    - `upstream_attenuation`    (uint) - Upstream attenuation (db)\n    - `downstream_attenuation`  (uint) - Downstream attenuation (db)\n    - `upstream_power`          (uint) - Upstream power\n    - `downstream_power`        (uint) - Downstream power\n    - `receive_blocks`          (uint) - Received blocks\n    - `transmit_blocks`         (uint) - Transmitted blocks\n    - `cell_delin`              (uint) - Cell delineation count\n    - `link_retrain`            (uint) - Link retrains\n    - `init_errors`             (uint) - Initialization errors\n    - `init_timeouts`           (uint) - Initialization timeouts\n    - `loss_of_framing`         (uint) - Loss of frame errors\n    - `errored_secs`            (uint) - Continuous seconds with errors\n    - `severly_errored_secs`    (uint) - Continuous seconds with severe errors\n    - `fec_errors`              (uint) - Local Modem Forward Error Correction errors\n    - `atuc_fec_errors`         (uint) - Remote DSLAM Forward Error Correction errors\n    - `hec_errors`              (uint) - Local Modem Header Error Control errors\n    - `atuc_hec_errors`         (uint) - Remote DSLAM Header Error Control errors\n    - `crc_errors`              (uint) - Local Modem Cyclic Redundancy Check error\n    - `atuc_crc_errors`         (uint) - Remote DSLAM Cyclic Redundancy Check errors\n- `fritzbox_wlan`\n  - tags\n    - `source`  - The name of the device (this metric has been queried from)\n    - `service` - The service id used to query this metric\n    - `wlan`    - The WLAN SSID (name)\n    - `channel` - The channel used by this WLAN\n    - `band`    - The band (in MHz) used by this WLAN\n    - `status`  - The status of the WLAN line (Up or Down)\n  - fields\n    - `total_associations` (uint) - The number of devices connected to this WLAN.\n- `fritzbox_hosts`\n  - tags\n    - `source`       - Device name this metric has been queried from\n    - `service`      - Service ID used to query this metric\n    - `node`         - Node name connected to the mesh network\n    - `node_role`    - Node role in the network\n                       (\"master\" = mesh master, \"slave\" = mesh slave, \"client\")\n    - `node_ap`      - Name of the access point this node is connected to\n    - `node_ap_role` - Access point's role  in the network\n                       (\"master\" = mesh master, \"slave\" = mesh slave)\n    - `link_type`    - Link type (\"WLAN\" or \"LAN\") of the peer connection\n    - `link_name`    - Link name of the connection\n  - fields\n    - `max_data_rate_tx` (uint) - The connection's maximum transmit rate (kbits/sec)\n    - `max_data_rate_rx` (uint) - The connection's maximum receive rate (kbits/sec)\n    - `cur_data_rate_tx` (uint) - The connection's maximum transmit rate (kbits/sec)\n    - `cur_data_rate_rx` (uint) - The connection's current receive rate (kbits/sec)\n\n## Example Output\n\n```text\nfritzbox_device,service=DeviceInfo1,source=fritz.box uptime=2058438i,model_name=\"Mock 1234\",serial_number=\"123456789\",hardware_version=\"Mock 1234\",software_version=\"1.02.03\" 1737003520174438000\n\nfritzbox_wan,service=WANCommonInterfaceConfig1,source=fritz.box layer1_upstream_max_bit_rate=48816000i,layer1_downstream_max_bit_rate=253247000i,upstream_current_max_speed=511831i,downstream_current_max_speed=1304268i,total_bytes_sent=129497283207i,total_bytes_received=554484531337i 1737003587690504000\n\nfritzbox_ppp,service=WANPPPConnection1,source=fritz.box uptime=369434i,upstream_max_bit_rate=44213433i,downstream_max_bit_rate=68038668i 1737003622308149000\n\nfritzbox_dsl,service=WANDSLInterfaceConfig1,source=fritz.box,status=Up downstream_curr_rate=249065i,downstream_max_rate=249065i,downstream_power=513i,init_timeouts=0i,atuc_crc_errors=13i,errored_secs=25i,atuc_hec_errors=0i,upstream_noise_margin=80i,downstream_noise_margin=60i,downstream_attenuation=140i,receive_blocks=490282831i,transmit_blocks=254577751i,init_errors=0i,crc_errors=53i,fec_errors=0i,hec_errors=0i,upstream_max_rate=48873i,upstream_attenuation=80i,upstream_power=498i,cell_delin=0i,link_retrain=2i,loss_of_framing=0i,upstream_curr_rate=46719i,severly_errored_secs=0i,atuc_fec_errors=0i 1737003645769642000\n\nfritzbox_wlan,band=2400,channel=13,service=WLANConfiguration1,source=fritz.box,ssid=MOCK1234,status=Up total_associations=11i 1737003673561198000\n\nfritzbox_hosts,node=device#17,node_ap=device#1,node_ap_role=master,node_role=slave,link_name=AP:2G:0,link_type=WLAN,service=Hosts1,source=fritz.box cur_data_rate_tx=216000i,cur_data_rate_rx=216000i,max_data_rate_tx=216000i,max_data_rate_rx=216000i 1737003707257394000\nfritzbox_hosts,node=device#24,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=LAN:1,link_type=LAN,service=Hosts1,source=fritz.box max_data_rate_tx=1000000i,max_data_rate_rx=1000000i,cur_data_rate_tx=0i,cur_data_rate_rx=0i 1737003707257248000\n```\n"
  },
  {
    "path": "plugins/inputs/fritzbox/fritzbox.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage fritzbox\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/tdrn-org/go-tr064\"\n\t\"github.com/tdrn-org/go-tr064/mesh\"\n\t\"github.com/tdrn-org/go-tr064/services/igddesc/igdicfg\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/deviceinfo\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/hosts\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/wancommonifconfig\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/wandslifconfig\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/wanpppconn\"\n\t\"github.com/tdrn-org/go-tr064/services/tr64desc/wlanconfig\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype serviceHandlerFunc func(telegraf.Accumulator, *tr064.Client, tr064.ServiceDescriptor) error\n\ntype Fritzbox struct {\n\tURLs    []string        `toml:\"urls\"`\n\tCollect []string        `toml:\"collect\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tLog     telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\tdeviceClients   []*tr064.Client\n\tserviceHandlers map[string]serviceHandlerFunc\n}\n\nfunc (*Fritzbox) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (f *Fritzbox) Init() error {\n\t// No need to run without any devices configured\n\tif len(f.URLs) == 0 {\n\t\treturn errors.New(\"no device URLs configured\")\n\t}\n\n\t// Use default collect options if nothing is configured\n\tif len(f.Collect) == 0 {\n\t\tf.Collect = []string{\"device\", \"wan\", \"ppp\", \"dsl\", \"wlan\"}\n\t}\n\n\t// Setup TLS\n\ttlsConfig, err := f.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"initializing TLS configuration failed: %w\", err)\n\t}\n\n\t// Initialize the device clients\n\tdebug := f.Log.Level().Includes(telegraf.Trace)\n\tf.deviceClients = make([]*tr064.Client, 0, len(f.URLs))\n\tfor _, rawURL := range f.URLs {\n\t\tparsedURL, err := url.Parse(rawURL)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing device URL %q failed: %w\", rawURL, err)\n\t\t}\n\t\tclient := tr064.NewClient(parsedURL)\n\t\tclient.Debug = debug\n\t\tclient.Timeout = time.Duration(f.Timeout)\n\t\tclient.TlsConfig = tlsConfig\n\t\tf.deviceClients = append(f.deviceClients, client)\n\t}\n\n\t// Initialize the service handlers\n\tf.serviceHandlers = make(map[string]serviceHandlerFunc, len(f.Collect))\n\tfor _, c := range f.Collect {\n\t\tswitch c {\n\t\tcase \"device\":\n\t\t\tf.serviceHandlers[deviceinfo.ServiceShortType] = gatherDeviceInfo\n\t\tcase \"wan\":\n\t\t\tf.serviceHandlers[wancommonifconfig.ServiceShortType] = gatherWanInfo\n\t\tcase \"ppp\":\n\t\t\tf.serviceHandlers[wanpppconn.ServiceShortType] = gatherPppInfo\n\t\tcase \"dsl\":\n\t\t\tf.serviceHandlers[wandslifconfig.ServiceShortType] = gatherDslInfo\n\t\tcase \"wlan\":\n\t\t\tf.serviceHandlers[wlanconfig.ServiceShortType] = gatherWlanInfo\n\t\tcase \"hosts\":\n\t\t\tf.serviceHandlers[hosts.ServiceShortType] = gatherHostsInfo\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid service %q in collect parameter\", c)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (f *Fritzbox) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, deviceClient := range f.deviceClients {\n\t\twg.Add(1)\n\t\t// Pass deviceClient as parameter to avoid any race conditions\n\t\tgo func(client *tr064.Client) {\n\t\t\tdefer wg.Done()\n\t\t\tf.gatherDevice(acc, client)\n\t\t}(deviceClient)\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc (f *Fritzbox) gatherDevice(acc telegraf.Accumulator, deviceClient *tr064.Client) {\n\tservices, err := deviceClient.Services(tr064.DefaultServiceSpec)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, service := range services {\n\t\tserviceHandler, exists := f.serviceHandlers[service.ShortType()]\n\t\t// If no serviceHandler has been setup during Init(), we ignore this service.\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\t\tacc.AddError(serviceHandler(acc, deviceClient, service))\n\t}\n}\n\nfunc gatherDeviceInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := deviceinfo.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tinfo := &deviceinfo.GetInfoResponse{}\n\tif err := serviceClient.GetInfo(info); err != nil {\n\t\treturn fmt.Errorf(\"failed to query device info: %w\", err)\n\t}\n\ttags := map[string]string{\n\t\t\"source\":  serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\"service\": serviceClient.Service.ShortId(),\n\t}\n\tfields := map[string]interface{}{\n\t\t\"uptime\":           info.NewUpTime,\n\t\t\"model_name\":       info.NewModelName,\n\t\t\"serial_number\":    info.NewSerialNumber,\n\t\t\"hardware_version\": info.NewHardwareVersion,\n\t\t\"software_version\": info.NewSoftwareVersion,\n\t}\n\tacc.AddFields(\"fritzbox_device\", fields, tags)\n\treturn nil\n}\n\nfunc gatherWanInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := wancommonifconfig.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tcommonLinkProperties := &wancommonifconfig.GetCommonLinkPropertiesResponse{}\n\tif err := serviceClient.GetCommonLinkProperties(commonLinkProperties); err != nil {\n\t\treturn fmt.Errorf(\"failed to query link properties: %w\", err)\n\t}\n\t// Prefer igdicfg service over wancommonifconfig service for total bytes stats, because igdicfg supports uint64 counters\n\tigdServices, err := deviceClient.ServicesByType(tr064.IgdServiceSpec, igdicfg.ServiceShortType)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to lookup IGD service: %w\", err)\n\t}\n\tvar totalBytesSent uint64\n\tvar totalBytesReceived uint64\n\tif len(igdServices) > 0 {\n\t\tigdServiceClient := &igdicfg.ServiceClient{\n\t\t\tTR064Client: deviceClient,\n\t\t\tService:     igdServices[0],\n\t\t}\n\t\taddonInfos := &igdicfg.GetAddonInfosResponse{}\n\t\tif err = igdServiceClient.GetAddonInfos(addonInfos); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to query addon info: %w\", err)\n\t\t}\n\t\ttotalBytesSent, err = strconv.ParseUint(addonInfos.NewX_AVM_DE_TotalBytesSent64, 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse total bytes sent: %w\", err)\n\t\t}\n\t\ttotalBytesReceived, err = strconv.ParseUint(addonInfos.NewX_AVM_DE_TotalBytesReceived64, 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse total bytes received: %w\", err)\n\t\t}\n\t} else {\n\t\t// Fall back to wancommonifconfig service in case igdicfg is not available (only uint32 based)\n\t\ttotalBytesSentResponse := &wancommonifconfig.GetTotalBytesSentResponse{}\n\t\tif err = serviceClient.GetTotalBytesSent(totalBytesSentResponse); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to query bytes sent: %w\", err)\n\t\t}\n\t\ttotalBytesSent = uint64(totalBytesSentResponse.NewTotalBytesSent)\n\t\ttotalBytesReceivedResponse := &wancommonifconfig.GetTotalBytesReceivedResponse{}\n\t\tif err = serviceClient.GetTotalBytesReceived(totalBytesReceivedResponse); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to query bytes received: %w\", err)\n\t\t}\n\t\ttotalBytesReceived = uint64(totalBytesReceivedResponse.NewTotalBytesReceived)\n\t}\n\ttags := map[string]string{\n\t\t\"source\":  serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\"service\": serviceClient.Service.ShortId(),\n\t}\n\tfields := map[string]interface{}{\n\t\t\"layer1_upstream_max_bit_rate\":   commonLinkProperties.NewLayer1UpstreamMaxBitRate,\n\t\t\"layer1_downstream_max_bit_rate\": commonLinkProperties.NewLayer1DownstreamMaxBitRate,\n\t\t\"upstream_current_max_speed\":     commonLinkProperties.NewX_AVM_DE_UpstreamCurrentMaxSpeed,\n\t\t\"downstream_current_max_speed\":   commonLinkProperties.NewX_AVM_DE_DownstreamCurrentMaxSpeed,\n\t\t\"total_bytes_sent\":               totalBytesSent,\n\t\t\"total_bytes_received\":           totalBytesReceived,\n\t}\n\tacc.AddFields(\"fritzbox_wan\", fields, tags)\n\treturn nil\n}\n\nfunc gatherPppInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := wanpppconn.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tinfo := &wanpppconn.GetInfoResponse{}\n\tif err := serviceClient.GetInfo(info); err != nil {\n\t\treturn fmt.Errorf(\"failed to query PPP info: %w\", err)\n\t}\n\ttags := map[string]string{\n\t\t\"source\":  serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\"service\": serviceClient.Service.ShortId(),\n\t}\n\tfields := map[string]interface{}{\n\t\t\"uptime\":                  info.NewUptime,\n\t\t\"upstream_max_bit_rate\":   info.NewUpstreamMaxBitRate,\n\t\t\"downstream_max_bit_rate\": info.NewDownstreamMaxBitRate,\n\t}\n\tacc.AddFields(\"fritzbox_ppp\", fields, tags)\n\treturn nil\n}\n\nfunc gatherDslInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := wandslifconfig.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tinfo := &wandslifconfig.GetInfoResponse{}\n\tif err := serviceClient.GetInfo(info); err != nil {\n\t\treturn fmt.Errorf(\"failed to query DSL info: %w\", err)\n\t}\n\tstatisticsTotal := &wandslifconfig.GetStatisticsTotalResponse{}\n\tif info.NewStatus == \"Up\" {\n\t\tif err := serviceClient.GetStatisticsTotal(statisticsTotal); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to query DSL statistics: %w\", err)\n\t\t}\n\t}\n\ttags := map[string]string{\n\t\t\"source\":  serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\"service\": serviceClient.Service.ShortId(),\n\t\t\"status\":  info.NewStatus,\n\t}\n\tfields := map[string]interface{}{\n\t\t\"upstream_curr_rate\":      info.NewUpstreamCurrRate,\n\t\t\"downstream_curr_rate\":    info.NewDownstreamCurrRate,\n\t\t\"upstream_max_rate\":       info.NewUpstreamMaxRate,\n\t\t\"downstream_max_rate\":     info.NewDownstreamMaxRate,\n\t\t\"upstream_noise_margin\":   info.NewUpstreamNoiseMargin,\n\t\t\"downstream_noise_margin\": info.NewDownstreamNoiseMargin,\n\t\t\"upstream_attenuation\":    info.NewUpstreamAttenuation,\n\t\t\"downstream_attenuation\":  info.NewDownstreamAttenuation,\n\t\t\"upstream_power\":          info.NewUpstreamPower,\n\t\t\"downstream_power\":        info.NewDownstreamPower,\n\t\t\"receive_blocks\":          statisticsTotal.NewReceiveBlocks,\n\t\t\"transmit_blocks\":         statisticsTotal.NewTransmitBlocks,\n\t\t\"cell_delin\":              statisticsTotal.NewCellDelin,\n\t\t\"link_retrain\":            statisticsTotal.NewLinkRetrain,\n\t\t\"init_errors\":             statisticsTotal.NewInitErrors,\n\t\t\"init_timeouts\":           statisticsTotal.NewInitTimeouts,\n\t\t\"loss_of_framing\":         statisticsTotal.NewLossOfFraming,\n\t\t\"errored_secs\":            statisticsTotal.NewErroredSecs,\n\t\t\"severly_errored_secs\":    statisticsTotal.NewSeverelyErroredSecs,\n\t\t\"fec_errors\":              statisticsTotal.NewFECErrors,\n\t\t\"atuc_fec_errors\":         statisticsTotal.NewATUCFECErrors,\n\t\t\"hec_errors\":              statisticsTotal.NewHECErrors,\n\t\t\"atuc_hec_errors\":         statisticsTotal.NewATUCHECErrors,\n\t\t\"crc_errors\":              statisticsTotal.NewCRCErrors,\n\t\t\"atuc_crc_errors\":         statisticsTotal.NewATUCCRCErrors,\n\t}\n\tacc.AddFields(\"fritzbox_dsl\", fields, tags)\n\treturn nil\n}\n\nfunc gatherWlanInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := wlanconfig.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tinfo := &wlanconfig.GetInfoResponse{}\n\tif err := serviceClient.GetInfo(info); err != nil {\n\t\treturn fmt.Errorf(\"failed to query WLAN info: %w\", err)\n\t}\n\ttotalAssociations := &wlanconfig.GetTotalAssociationsResponse{}\n\tif info.NewStatus == \"Up\" {\n\t\tif err := serviceClient.GetTotalAssociations(totalAssociations); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to query WLAN associations: %w\", err)\n\t\t}\n\t}\n\ttags := map[string]string{\n\t\t\"source\":  serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\"service\": serviceClient.Service.ShortId(),\n\t\t\"status\":  info.NewStatus,\n\t\t\"ssid\":    info.NewSSID,\n\t\t\"channel\": strconv.Itoa(int(info.NewChannel)),\n\t\t\"band\":    wlanBandFromInfo(info),\n\t}\n\tfields := map[string]interface{}{\n\t\t\"total_associations\": totalAssociations.NewTotalAssociations,\n\t}\n\tacc.AddGauge(\"fritzbox_wlan\", fields, tags)\n\treturn nil\n}\n\nfunc wlanBandFromInfo(info *wlanconfig.GetInfoResponse) string {\n\tband := info.NewX_AVM_DE_FrequencyBand\n\tif band != \"\" {\n\t\treturn band\n\t}\n\tif 1 <= info.NewChannel && info.NewChannel <= 14 {\n\t\treturn \"2400\"\n\t}\n\treturn \"5000\"\n}\n\nfunc gatherHostsInfo(acc telegraf.Accumulator, deviceClient *tr064.Client, service tr064.ServiceDescriptor) error {\n\tserviceClient := hosts.ServiceClient{\n\t\tTR064Client: deviceClient,\n\t\tService:     service,\n\t}\n\tconnections, err := fetchHostsConnections(&serviceClient)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch hosts connections: %w\", err)\n\t}\n\tfor _, connection := range connections {\n\t\t// Ignore ephemeral UUID style device names\n\t\t_, err = uuid.Parse(connection.RightDeviceName)\n\t\tif err == nil {\n\t\t\tcontinue\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"source\":       serviceClient.TR064Client.DeviceUrl.Hostname(),\n\t\t\t\"service\":      serviceClient.Service.ShortId(),\n\t\t\t\"node\":         connection.RightDeviceName,\n\t\t\t\"node_role\":    hostRole(connection.RightMeshRole),\n\t\t\t\"node_ap\":      connection.LeftDeviceName,\n\t\t\t\"node_ap_role\": hostRole(connection.LeftMeshRole),\n\t\t\t\"link_type\":    connection.InterfaceType,\n\t\t\t\"link_name\":    connection.InterfaceName,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"max_data_rate_tx\": connection.MaxDataRateTx,\n\t\t\t\"max_data_rate_rx\": connection.MaxDataRateRx,\n\t\t\t\"cur_data_rate_tx\": connection.CurDataRateTx,\n\t\t\t\"cur_data_rate_rx\": connection.CurDataRateRx,\n\t\t}\n\t\tacc.AddGauge(\"fritzbox_hosts\", fields, tags)\n\t}\n\treturn nil\n}\n\nfunc hostRole(role string) string {\n\tif role == \"unknown\" {\n\t\treturn \"client\"\n\t}\n\treturn role\n}\n\nfunc fetchHostsConnections(serviceClient *hosts.ServiceClient) ([]*mesh.Connection, error) {\n\tmeshListPath := &hosts.X_AVM_DE_GetMeshListPathResponse{}\n\tif err := serviceClient.X_AVM_DE_GetMeshListPath(meshListPath); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query mesh list path: %w\", err)\n\t}\n\tmeshListResponse, err := serviceClient.TR064Client.Get(meshListPath.NewX_AVM_DE_MeshListPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to access mesh list %q: %w\", meshListPath.NewX_AVM_DE_MeshListPath, err)\n\t}\n\tif meshListResponse.StatusCode == http.StatusNotFound {\n\t\treturn make([]*mesh.Connection, 0), nil\n\t}\n\tif meshListResponse.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to fetch mesh list %q: %s\", meshListPath.NewX_AVM_DE_MeshListPath, meshListResponse.Status)\n\t}\n\tdefer meshListResponse.Body.Close()\n\tmeshListBytes, err := io.ReadAll(meshListResponse.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read mesh list: %w\", err)\n\t}\n\tmeshList := &mesh.List{}\n\tif err := json.Unmarshal(meshListBytes, meshList); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse mesh list: %w\", err)\n\t}\n\treturn meshList.Connections(), nil\n}\n\nfunc init() {\n\tinputs.Add(\"fritzbox\", func() telegraf.Input {\n\t\treturn &Fritzbox{Timeout: config.Duration(10 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/fritzbox/fritzbox_test.go",
    "content": "package fritzbox\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tdrn-org/go-tr064/mock\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestValidDefaultConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"sample.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\tf, ok := conf.Inputs[0].Input.(*Fritzbox)\n\trequire.True(t, ok)\n\n\t// Verify successful Init\n\trequire.NoError(t, f.Init())\n\n\t// Verify everything is setup according to plugin defaults\n\trequire.ElementsMatch(t, []string{\"http://user:password@fritz.box:49000/\"}, f.URLs)\n\trequire.Equal(t, []string{\"device\", \"wan\", \"ppp\", \"dsl\", \"wlan\"}, f.Collect)\n\trequire.Equal(t, config.Duration(10*time.Second), f.Timeout)\n\trequire.Empty(t, f.TLSKeyPwd)\n\trequire.False(t, f.InsecureSkipVerify)\n}\n\nfunc TestValidCustomConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"testdata/conf/valid.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\tf, ok := conf.Inputs[0].Input.(*Fritzbox)\n\trequire.True(t, ok)\n\n\t// Verify successful Init\n\trequire.NoError(t, f.Init())\n\n\t// Verify everything is setup according to the config file\n\trequire.ElementsMatch(t, []string{\"http://boxuser:boxpassword@fritz.box:49000/\", \"http://:repeaterpassword@fritz.repeater:49000/\"}, f.URLs)\n\trequire.Equal(t, []string{\"device\", \"wan\", \"ppp\", \"dsl\", \"wlan\", \"hosts\"}, f.Collect)\n\trequire.Equal(t, config.Duration(60*time.Second), f.Timeout)\n\trequire.Equal(t, \"secret\", f.TLSKeyPwd)\n\trequire.True(t, f.InsecureSkipVerify)\n}\n\nfunc TestInvalidURLsConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"testdata/conf/invalid_urls.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\tf, ok := conf.Inputs[0].Input.(*Fritzbox)\n\trequire.True(t, ok)\n\n\t// Verify Init failure\n\trequire.EqualError(t, f.Init(), `parsing device URL \"::\" failed: parse \"::\": missing protocol scheme`)\n}\n\nfunc TestInvalidCollectConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"testdata/conf/invalid_collect.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\tf, ok := conf.Inputs[0].Input.(*Fritzbox)\n\trequire.True(t, ok)\n\n\t// Verify Init failure\n\trequire.EqualError(t, f.Init(), `invalid service \"undefined\" in collect parameter`)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all testcase directories\n\ttestcases, err := os.ReadDir(\"testdata/testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"fritzbox\", func() telegraf.Input {\n\t\treturn &Fritzbox{Timeout: config.Duration(10 * time.Second)}\n\t})\n\n\tfor _, testcase := range testcases {\n\t\t// Only handle folders\n\t\tif !testcase.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(testcase.Name(), func(t *testing.T) {\n\t\t\ttestcaseDir := filepath.Join(\"testdata\", \"testcases\", testcase.Name())\n\t\t\tconfigFile := filepath.Join(testcaseDir, \"telegraf.conf\")\n\t\t\tmockDir := filepath.Join(testcaseDir, \"mock\")\n\t\t\texpectedMetricsFile := filepath.Join(testcaseDir, \"expected.out\")\n\n\t\t\t// Setup the services to mock (one per sub-folder of mockDir)\n\t\t\tservices, err := os.ReadDir(mockDir)\n\t\t\trequire.NoError(t, err)\n\t\t\tserviceMocks := make([]*mock.ServiceMock, 0, len(services))\n\t\t\tfor _, service := range services {\n\t\t\t\t// Ignore the mock files\n\t\t\t\tif !testcase.IsDir() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tserviceMock := mock.ServiceMockFromFile(\"/\"+service.Name(), filepath.Join(mockDir, service.Name(), \"response.xml\"))\n\t\t\t\tserviceMocks = append(serviceMocks, serviceMock)\n\t\t\t}\n\n\t\t\t// Start testcase mock server\n\t\t\ttr064Server := mock.Start(mockDir, serviceMocks...)\n\t\t\tdefer tr064Server.Stop(t.Context())\n\n\t\t\t// Load plugin from config\n\t\t\tconf := config.NewConfig()\n\t\t\trequire.NoError(t, conf.LoadConfig(configFile))\n\t\t\trequire.Len(t, conf.Inputs, 1)\n\t\t\tf, ok := conf.Inputs[0].Input.(*Fritzbox)\n\t\t\trequire.True(t, ok)\n\n\t\t\t// Target plugin at mock server\n\t\t\tf.URLs = []string{tr064Server.Server().String()}\n\t\t\tf.Log = &testutil.Logger{Name: \"fritzbox\"}\n\n\t\t\t// Verify successful Init\n\t\t\trequire.NoError(t, f.Init())\n\n\t\t\t// Verify successfull Gather\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, acc.GatherError(f.Gather))\n\n\t\t\t// Load expexected metrics\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\texpectedMetrics, err := testutil.ParseMetricsFromFile(expectedMetricsFile, parser)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Verify metrics are as expected\n\t\t\ttestutil.RequireMetricsEqual(t, expectedMetrics, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.IgnoreType(), testutil.SortMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/fritzbox/sample.conf",
    "content": "# Gather fritzbox status\n[[inputs.fritzbox]]\n  ## URLs of the devices to query including login credentials\n  urls = [ \"http://user:password@fritz.box:49000/\" ]\n\n  ## The information to collect (see README for further details).\n  # collect = [\n  #   \"device\",\n  #   \"wan\",\n  #   \"ppp\",\n  #   \"dsl\",\n  #   \"wlan\",\n  # ]\n\n  ## The http timeout to use.\n  # timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/conf/invalid_collect.conf",
    "content": "# Gather fritzbox status\n[[inputs.fritzbox]]\n  ## URLs of the devices to query including login credentials  \n  urls = [ \"http://user:password@fritz.box:49000/\" ]\n\n  ## The information to collect (see README for further details).\n  collect = [ \"undefined\" ]\n  \n  ## The http timeout to use.\n  # timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/conf/invalid_urls.conf",
    "content": "# Gather fritzbox status\n[[inputs.fritzbox]]\n  ## URLs of the devices to query including login credentials  \n  urls = [ \"http://user:password@fritz.box:49000/\", \"::\" ]\n\n  ## The information to collect (see README for further details).\n  # collect = [\n  #   \"device\",\n  #   \"wan\",\n  #   \"ppp\",\n  #   \"dsl\",\n  #   \"wlan\",\n  # ]\n\n  ## The http timeout to use.\n  # timeout = \"10s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/conf/valid.conf",
    "content": "# Gather fritzbox status\n[[inputs.fritzbox]]\n  ## URLs of the devices to query including login credentials  \n  urls = [\n    \"http://boxuser:boxpassword@fritz.box:49000/\",\n    \"http://:repeaterpassword@fritz.repeater:49000/\",\n  ]\n\n  ## The information to collect (see README for further details).\n  collect = [\n    \"device\",\n    \"wan\",\n    \"ppp\",\n    \"dsl\",\n    \"wlan\",\n    \"hosts\",\n  ]\n\n  ## The http timeout to use.\n  timeout = \"1m\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  insecure_skip_verify = true\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/device/expected.out",
    "content": "fritzbox_device,service=DeviceInfo1,source=127.0.0.1 hardware_version=\"Mock 1234\",model_name=\"Mock 1234\",serial_number=\"123456789\",software_version=\"1.02.03\",uptime=2058438u 1737088489284767000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/device/mock/deviceinfo/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetInfoResponse xmlns:u=\"urn:dslforum-org:service:DeviceInfo:1\">\n<NewManufacturerName>AVM</NewManufacturerName>\n<NewManufacturerOUI>00000E</NewManufacturerOUI>\n<NewModelName>Mock 1234</NewModelName>\n<NewDescription>Mock 1234 Release 1.02.03</NewDescription>\n<NewProductClass>MOCK1234</NewProductClass>\n<NewSerialNumber>123456789</NewSerialNumber>\n<NewSoftwareVersion>1.02.03</NewSoftwareVersion>\n<NewHardwareVersion>Mock 1234</NewHardwareVersion>\n<NewSpecVersion>1.0</NewSpecVersion>\n<NewProvisioningCode>000.000.000.000</NewProvisioningCode>\n<NewUpTime>2058438</NewUpTime>\n<NewDeviceLog/>\n</u:GetInfoResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/device/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/device/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:DeviceInfo:1</serviceType>\n                <serviceId>urn:DeviceInfo-com:serviceId:DeviceInfo1</serviceId>\n                <controlURL>/deviceinfo</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/device/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"device\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/dsl/expected.out",
    "content": "fritzbox_dsl,service=WANDSLInterfaceConfig1,source=127.0.0.1,status=Up atuc_crc_errors=13u,atuc_fec_errors=0u,atuc_hec_errors=0u,cell_delin=0u,crc_errors=53u,downstream_attenuation=140u,downstream_curr_rate=249065u,downstream_max_rate=249065u,downstream_noise_margin=60u,downstream_power=513u,errored_secs=25u,fec_errors=0u,hec_errors=0u,init_errors=0u,init_timeouts=0u,link_retrain=2u,loss_of_framing=0u,receive_blocks=490282831u,severly_errored_secs=0u,transmit_blocks=254577751u,upstream_attenuation=80u,upstream_curr_rate=46719i,upstream_max_rate=48873u,upstream_noise_margin=80u,upstream_power=498u 1737088741855188000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/dsl/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/dsl/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:WANDSLInterfaceConfig:1</serviceType>\n                <serviceId>urn:WANDSLIfConfig-com:serviceId:WANDSLInterfaceConfig1</serviceId>\n                <controlURL>/wandslifconfig</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/dsl/mock/wandslifconfig/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetInfoResponse xmlns:u=\"urn:dslforum-org:service:WANDSLInterfaceConfig:1\">\n<NewEnable>1</NewEnable>\n<NewStatus>Up</NewStatus>\n<NewDataPath>Fast</NewDataPath>\n<NewUpstreamCurrRate>46719</NewUpstreamCurrRate>\n<NewDownstreamCurrRate>249065</NewDownstreamCurrRate>\n<NewUpstreamMaxRate>48873</NewUpstreamMaxRate>\n<NewDownstreamMaxRate>249065</NewDownstreamMaxRate>\n<NewUpstreamNoiseMargin>80</NewUpstreamNoiseMargin>\n<NewDownstreamNoiseMargin>60</NewDownstreamNoiseMargin>\n<NewUpstreamAttenuation>80</NewUpstreamAttenuation>\n<NewDownstreamAttenuation>140</NewDownstreamAttenuation>\n<NewATURVendor>41564d00</NewATURVendor>\n<NewATURCountry>0400</NewATURCountry>\n<NewUpstreamPower>498</NewUpstreamPower>\n<NewDownstreamPower>513</NewDownstreamPower>\n</u:GetInfoResponse>\n<u:GetStatisticsTotalResponse xmlns:u=\"urn:dslforum-org:service:WANDSLInterfaceConfig:1\">\n<NewReceiveBlocks>490282831</NewReceiveBlocks>\n<NewTransmitBlocks>254577751</NewTransmitBlocks>\n<NewCellDelin>0</NewCellDelin>\n<NewLinkRetrain>2</NewLinkRetrain>\n<NewInitErrors>0</NewInitErrors>\n<NewInitTimeouts>0</NewInitTimeouts>\n<NewLossOfFraming>0</NewLossOfFraming>\n<NewErroredSecs>25</NewErroredSecs>\n<NewSeverelyErroredSecs>0</NewSeverelyErroredSecs>\n<NewFECErrors>0</NewFECErrors>\n<NewATUCFECErrors>0</NewATUCFECErrors>\n<NewHECErrors>0</NewHECErrors>\n<NewATUCHECErrors>0</NewATUCHECErrors>\n<NewCRCErrors>53</NewCRCErrors>\n<NewATUCCRCErrors>13</NewATUCCRCErrors>\n</u:GetStatisticsTotalResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/dsl/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"dsl\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/expected.out",
    "content": "fritzbox_hosts,node=device#17,node_ap=device#1,node_ap_role=master,node_role=slave,link_name=AP:2G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=216000i,cur_data_rate_tx=216000i,max_data_rate_rx=216000i,max_data_rate_tx=216000i 1737063884317915000\nfritzbox_hosts,node=device#17,node_ap=device#1,node_ap_role=master,node_role=slave,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=1300000i,cur_data_rate_tx=975000i,max_data_rate_rx=1300000i,max_data_rate_tx=1300000i 1737063884317962000\nfritzbox_hosts,node=device#4,node_ap=device#1,node_ap_role=master,node_role=client,link_name=LAN:1,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=1000000i,cur_data_rate_tx=1000000i,max_data_rate_rx=1000000i,max_data_rate_tx=1000000i 1737063884317976000\nfritzbox_hosts,node=device#26,node_ap=device#1,node_ap_role=master,node_role=client,link_name=LAN:2,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=1000000i,cur_data_rate_tx=1000000i,max_data_rate_rx=1000000i,max_data_rate_tx=1000000i 1737063884317992000\nfritzbox_hosts,node=device#2,node_ap=device#1,node_ap_role=master,node_role=client,link_name=LAN:3,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=100000i,cur_data_rate_tx=100000i,max_data_rate_rx=100000i,max_data_rate_tx=100000i 1737063884318005000\nfritzbox_hosts,node=device#3,node_ap=device#1,node_ap_role=master,node_role=client,link_name=LAN:4,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=100000i,cur_data_rate_tx=100000i,max_data_rate_rx=100000i,max_data_rate_tx=100000i 1737063884318018000\nfritzbox_hosts,node=device#14,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:2G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=65000i,cur_data_rate_tx=72000i,max_data_rate_rx=72200i,max_data_rate_tx=72200i 1737063884318031000\nfritzbox_hosts,node=device#5,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:2G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=72000i,cur_data_rate_tx=72000i,max_data_rate_rx=72200i,max_data_rate_tx=72200i 1737063884318043000\nfritzbox_hosts,node=device#11,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=390000i,cur_data_rate_tx=433000i,max_data_rate_rx=433300i,max_data_rate_tx=433300i 1737063884318065000\nfritzbox_hosts,node=device#11,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=585000i,cur_data_rate_tx=866000i,max_data_rate_rx=866700i,max_data_rate_tx=866700i 1737063884318082000\nfritzbox_hosts,node=device#16,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=866000i,cur_data_rate_tx=866000i,max_data_rate_rx=866700i,max_data_rate_tx=866700i 1737063884318118000\nfritzbox_hosts,node=device#18,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=526000i,cur_data_rate_tx=780000i,max_data_rate_rx=866700i,max_data_rate_tx=866700i 1737063884318140000\nfritzbox_hosts,node=device#19,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=650000i,cur_data_rate_tx=1170000i,max_data_rate_rx=1733300i,max_data_rate_tx=1733300i 1737063884318153000\nfritzbox_hosts,node=device#7,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=780000i,cur_data_rate_tx=866000i,max_data_rate_rx=866700i,max_data_rate_tx=866700i 1737063884318166000\nfritzbox_hosts,node=device#8,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=390000i,cur_data_rate_tx=433000i,max_data_rate_rx=433300i,max_data_rate_tx=433300i 1737063884318179000\nfritzbox_hosts,node=device#9,node_ap=device#1,node_ap_role=master,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=390000i,cur_data_rate_tx=433000i,max_data_rate_rx=433300i,max_data_rate_tx=433300i 1737063884318192000\nfritzbox_hosts,node=device#13,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=LAN:1,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=0i,cur_data_rate_tx=0i,max_data_rate_rx=1000000i,max_data_rate_tx=1000000i 1737063884318215000\nfritzbox_hosts,node=device#24,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=LAN:1,link_type=LAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=0i,cur_data_rate_tx=0i,max_data_rate_rx=1000000i,max_data_rate_tx=1000000i 1737063884318233000\nfritzbox_hosts,node=device#6,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=AP:2G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=72200i,cur_data_rate_tx=72000i,max_data_rate_rx=72000i,max_data_rate_tx=72000i 1737063884318251000\nfritzbox_hosts,node=device#10,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=866700i,cur_data_rate_tx=866000i,max_data_rate_rx=866000i,max_data_rate_tx=866000i 1737063884318263000\nfritzbox_hosts,node=device#22,node_ap=device#17,node_ap_role=slave,node_role=client,link_name=AP:5G:0,link_type=WLAN,service=Hosts1,source=127.0.0.1 cur_data_rate_rx=866700i,cur_data_rate_tx=866000i,max_data_rate_rx=866000i,max_data_rate_tx=866000i 1737063884318275000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/mock/hosts/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:X_AVM-DE_GetMeshListPathResponse xmlns:u=\"urn:dslforum-org:service:Hosts:1\">\n<NewX_AVM-DE_MeshListPath>/meshlist.json?sid=123456789abcdef</NewX_AVM-DE_MeshListPath>\n</u:X_AVM-DE_GetMeshListPathResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/mock/meshlist.json",
    "content": "{\n\t\"schema_version\": \"7.8\",\n\t\"nodes\": [\n\t\t{\n\t\t\t\"uid\": \"n-1\",\n\t\t\t\"device_name\": \"device#1\",\n\t\t\t\"is_meshed\": true,\n\t\t\t\"mesh_role\": \"master\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-6\",\n\t\t\t\t\t\"name\": \"LANBridge\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-17\",\n\t\t\t\t\t\"name\": \"LAN:2\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-286\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-17\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-287\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1000000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-43\",\n\t\t\t\t\t\"name\": \"LAN:1\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-54\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-43\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-55\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1000000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-47\",\n\t\t\t\t\t\"name\": \"LAN:3\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-50\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-47\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-51\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 100000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-48\",\n\t\t\t\t\t\"name\": \"LAN:4\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-52\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-48\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-53\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 100000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-49\",\n\t\t\t\t\t\"name\": \"WAN:1\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-59\",\n\t\t\t\t\t\"name\": \"AP:2G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-81\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-82\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 72000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-252\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 216000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 216000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 216000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 216000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-205\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-206\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 65000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-60\",\n\t\t\t\t\t\"name\": \"AP:5G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-217\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-218\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1733300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1733300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 650000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1170000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-106\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-107\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 780000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-251\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1300000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1300000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1300000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 975000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-199\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-200\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 526000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 780000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-100\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-101\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 585000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-210\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-211\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-148\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-149\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-50\",\n\t\t\t\"device_name\": \"device#2\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-51\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-50\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-47\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-51\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 100000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-52\",\n\t\t\t\"device_name\": \"device#3\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-53\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-52\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-48\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-53\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 100000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 100000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-54\",\n\t\t\t\"device_name\": \"device#4\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-55\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-54\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-43\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-55\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1000000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-81\",\n\t\t\t\"device_name\": \"device#5\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-82\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-81\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-82\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 72000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-92\",\n\t\t\t\"device_name\": \"device#6\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-93\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-92\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-93\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-106\",\n\t\t\t\"device_name\": \"device#7\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-107\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-106\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-107\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 780000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-148\",\n\t\t\t\"device_name\": \"device#8\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-149\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-148\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-149\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-210\",\n\t\t\t\"device_name\": \"device#9\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-211\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-210\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-211\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-44\",\n\t\t\t\"device_name\": \"device#10\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-45\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-44\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-45\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-100\",\n\t\t\t\"device_name\": \"device#11\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-101\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-100\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-101\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 433300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 433300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 390000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 433000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-122\",\n\t\t\t\"device_name\": \"device#12\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-123\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-203\",\n\t\t\t\"device_name\": \"device#13\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-204\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-203\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-89\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-204\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-205\",\n\t\t\t\"device_name\": \"device#14\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-206\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-205\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-206\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 65000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-62\",\n\t\t\t\"device_name\": \"device#15\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-67\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-178\",\n\t\t\t\"device_name\": \"device#11\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-179\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 585000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-102\",\n\t\t\t\"device_name\": \"device#16\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-103\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-110\",\n\t\t\t\"device_name\": \"device#17\",\n\t\t\t\"is_meshed\": true,\n\t\t\t\"mesh_role\": \"slave\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-89\",\n\t\t\t\t\t\"name\": \"LAN:1\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-121\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-89\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-138\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-203\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-89\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-204\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-250\",\n\t\t\t\t\t\"name\": \"LANBridge\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-251\",\n\t\t\t\t\t\"name\": \"UPLINK:5G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-251\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1300000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1300000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1300000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 975000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-252\",\n\t\t\t\t\t\"name\": \"UPLINK:2G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-252\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 216000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 216000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 216000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 216000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-253\",\n\t\t\t\t\t\"name\": \"AP:5G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-196\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-207\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-44\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-45\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-254\",\n\t\t\t\t\t\"name\": \"AP:2G:0\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-92\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-93\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 72000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 72000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 72200,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 72000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-178\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-179\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-199\",\n\t\t\t\"device_name\": \"device#18\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-200\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-199\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-200\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 526000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 780000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-217\",\n\t\t\t\"device_name\": \"device#19\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-218\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-217\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-218\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1733300,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1733300,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 650000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1170000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-197\",\n\t\t\t\"device_name\": \"device#20\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-202\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-180\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-182\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-196\",\n\t\t\t\"device_name\": \"device#22\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-207\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-196\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-207\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-284\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-285\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-166\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-186\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-225\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-227\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-244\",\n\t\t\t\"device_name\": \"device#19\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-245\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-238\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-239\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-233\",\n\t\t\t\"device_name\": \"device#23\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-234\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-121\",\n\t\t\t\"device_name\": \"device#24\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-138\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-121\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-89\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-138\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-247\",\n\t\t\t\"device_name\": \"device#16\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-248\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-60\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 866700,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 866700,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 866000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 866000\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-253\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-110\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-254\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"DISCONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-247\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-59\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-248\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 0,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 0\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-191\",\n\t\t\t\"device_name\": \"device#25\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-193\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-209\",\n\t\t\t\"device_name\": \"device#21\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-212\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"WLAN\",\n\t\t\t\t\t\"node_links\": []\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"uid\": \"n-286\",\n\t\t\t\"device_name\": \"device#26\",\n\t\t\t\"is_meshed\": false,\n\t\t\t\"mesh_role\": \"unknown\",\n\t\t\t\"node_interfaces\": [\n\t\t\t\t{\n\t\t\t\t\t\"uid\": \"ni-287\",\n\t\t\t\t\t\"name\": \"\",\n\t\t\t\t\t\"type\": \"LAN\",\n\t\t\t\t\t\"node_links\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"state\": \"CONNECTED\",\n\t\t\t\t\t\t\t\"node_1_uid\": \"n-1\",\n\t\t\t\t\t\t\t\"node_2_uid\": \"n-286\",\n\t\t\t\t\t\t\t\"node_interface_1_uid\": \"ni-17\",\n\t\t\t\t\t\t\t\"node_interface_2_uid\": \"ni-287\",\n\t\t\t\t\t\t\t\"max_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"max_data_rate_tx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_rx\": 1000000,\n\t\t\t\t\t\t\t\"cur_data_rate_tx\": 1000000\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:Hosts:1</serviceType>\n                <serviceId>urn:LanDeviceHosts-com:serviceId:Hosts1</serviceId>\n                <controlURL>/hosts</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/hosts/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"hosts\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/ppp/expected.out",
    "content": "fritzbox_ppp,service=WANPPPConnection1,source=127.0.0.1 downstream_max_bit_rate=68038668u,upstream_max_bit_rate=44213433u,uptime=369434u 1737088658570388000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/ppp/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/ppp/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:WANPPPConnection:1</serviceType>\n                <serviceId>urn:WANPPPConnection-com:serviceId:WANPPPConnection1</serviceId>\n                <controlURL>/wanpppconn</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/ppp/mock/wanpppconn/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetInfoResponse xmlns:u=\"urn:dslforum-org:service:WANPPPConnection:1\">\n<NewEnable>1</NewEnable>\n<NewConnectionStatus>Connected</NewConnectionStatus>\n<NewPossibleConnectionTypes>IP_Routed, IP_Bridged</NewPossibleConnectionTypes>\n<NewConnectionType>IP_Routed</NewConnectionType>\n<NewName>internet</NewName>\n<NewUptime>369434</NewUptime>\n<NewUpstreamMaxBitRate>44213433</NewUpstreamMaxBitRate>\n<NewDownstreamMaxBitRate>68038668</NewDownstreamMaxBitRate>\n<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>\n<NewIdleDisconnectTime>0</NewIdleDisconnectTime>\n<NewRSIPAvailable>0</NewRSIPAvailable>\n<NewUserName>5511248654630001@setup.t-online.de</NewUserName>\n<NewNATEnabled>1</NewNATEnabled>\n<NewExternalIPAddress>217.238.141.33</NewExternalIPAddress>\n<NewDNSServers>2003:180:2:7000::53, 2003:180:2:9000::53,217.237.151.115,217.237.148.102</NewDNSServers>\n<NewMACAddress>dc:39:6f:3a:bc:40</NewMACAddress>\n<NewConnectionTrigger>AlwaysOn</NewConnectionTrigger>\n<NewLastAuthErrorInfo></NewLastAuthErrorInfo>\n<NewMaxCharsUsername>128</NewMaxCharsUsername>\n<NewMinCharsUsername>3</NewMinCharsUsername>\n<NewAllowedCharsUsername>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._@()#/%[]{}*+§$&amp;=?!:;,</NewAllowedCharsUsername>\n<NewMaxCharsPassword>64</NewMaxCharsPassword>\n<NewMinCharsPassword>3</NewMinCharsPassword>\n<NewAllowedCharsPassword>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._@()#/%[]{}*+§$&amp;=?!:;,</NewAllowedCharsPassword>\n<NewTransportType>PPPoE</NewTransportType>\n<NewRouteProtocolRx>Off</NewRouteProtocolRx>\n<NewPPPoEServiceName></NewPPPoEServiceName>\n<NewRemoteIPAddress></NewRemoteIPAddress>\n<NewPPPoEACName>MUNJ20</NewPPPoEACName>\n<NewDNSEnabled>1</NewDNSEnabled>\n<NewDNSOverrideAllowed>1</NewDNSOverrideAllowed>\n</u:GetInfoResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/ppp/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"ppp\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/expected.out",
    "content": "fritzbox_wan,service=WANCommonInterfaceConfig1,source=127.0.0.1 downstream_current_max_speed=1304268u,layer1_downstream_max_bit_rate=253247000u,layer1_upstream_max_bit_rate=48816000u,total_bytes_received=554484531337u,total_bytes_sent=129497283207u,upstream_current_max_speed=511831u 1737088572669757000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/mock/WANCommonIFC1/response.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetAddonInfosResponse xmlns:u=\"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\">\n<NewByteSendRate>178</NewByteSendRate>\n<NewByteReceiveRate>10893</NewByteReceiveRate>\n<NewPacketSendRate>0</NewPacketSendRate>\n<NewPacketReceiveRate>0</NewPacketReceiveRate>\n<NewTotalBytesSent>648264327</NewTotalBytesSent>\n<NewTotalBytesReceived>433750153</NewTotalBytesReceived>\n<NewAutoDisconnectTime>0</NewAutoDisconnectTime>\n<NewIdleDisconnectTime>1</NewIdleDisconnectTime>\n<NewDNSServer1>0.0.0.0</NewDNSServer1>\n<NewDNSServer2>0.0.0.0</NewDNSServer2>\n<NewVoipDNSServer1>0.0.0.0</NewVoipDNSServer1>\n<NewVoipDNSServer2>0.0.0.0</NewVoipDNSServer2>\n<NewUpnpControlEnabled>0</NewUpnpControlEnabled>\n<NewRoutedBridgedModeBoth>1</NewRoutedBridgedModeBoth>\n<NewX_AVM_DE_TotalBytesSent64>129497283207</NewX_AVM_DE_TotalBytesSent64>\n<NewX_AVM_DE_TotalBytesReceived64>554484531337</NewX_AVM_DE_TotalBytesReceived64>\n<NewX_AVM_DE_WANAccessType>DSL</NewX_AVM_DE_WANAccessType>\n</u:GetAddonInfosResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/mock/igddesc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>\n                <serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>\n                <controlURL>/WANCommonIFC1</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:WANCommonInterfaceConfig:1</serviceType>\n                <serviceId>urn:WANCIfConfig-com:serviceId:WANCommonInterfaceConfig1</serviceId>\n                <controlURL>/wancommonifconfig</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/mock/wancommonifconfig/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetCommonLinkPropertiesResponse xmlns:u=\"urn:dslforum-org:service:WANCommonInterfaceConfig:1\">\n<NewWANAccessType>DSL</NewWANAccessType>\n<NewLayer1UpstreamMaxBitRate>48816000</NewLayer1UpstreamMaxBitRate>\n<NewLayer1DownstreamMaxBitRate>253247000</NewLayer1DownstreamMaxBitRate>\n<NewPhysicalLinkStatus>Up</NewPhysicalLinkStatus>\n<NewX_AVM-DE_DownstreamCurrentUtilization>281672,1069998,122887,154143,335464,376641,201036,1046752,1304268,117397,42277,54058,41911,193162,372545,232857,661911,884903,35486,43050</NewX_AVM-DE_DownstreamCurrentUtilization>\n<NewX_AVM-DE_UpstreamCurrentUtilization>100417,76139,389328,217575,68110,49200,248209,122899,83175,466221,511831,491191,372128,192963,269890,222214,41261,56576,328630,388027</NewX_AVM-DE_UpstreamCurrentUtilization>\n<NewX_AVM-DE_DownstreamCurrentMaxSpeed>1304268</NewX_AVM-DE_DownstreamCurrentMaxSpeed>\n<NewX_AVM-DE_UpstreamCurrentMaxSpeed>511831</NewX_AVM-DE_UpstreamCurrentMaxSpeed>\n</u:GetCommonLinkPropertiesResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wan/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"wan\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wlan/expected.out",
    "content": "fritzbox_wlan,band=2400,channel=13,service=WLANConfiguration1,source=127.0.0.1,ssid=MOCK1234,status=Up total_associations=11u 1737063660847310000\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wlan/mock/dummySCPD.xml",
    "content": "<scpd xmlns=\"urn:dslforum-org:service-1-0\">\n    <actionList/>\n    <serviceStateTable/>\n</scpd>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wlan/mock/tr64desc.xml",
    "content": "<root xmlns=\"urn:dslforum-org:device-1-0\">\n    <device>\n        <serviceList>\n            <service>\n                <serviceType>urn:dslforum-org:service:WLANConfiguration:1</serviceType>\n                <serviceId>urn:WLANConfiguration-com:serviceId:WLANConfiguration1</serviceId>\n                <controlURL>/wlanconfig</controlURL>\n                <SCPDURL>/dummySCPD.xml</SCPDURL>\n            </service>\n        </serviceList>\n        <deviceList/>\n    </device>\n</root>"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wlan/mock/wlanconfig/response.xml",
    "content": "<?xml version=\"1.0\"?>\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<s:Body>\n<u:GetInfoResponse xmlns:u=\"urn:dslforum-org:service:WLANConfiguration:1\">\n<NewEnable>1</NewEnable>\n<NewStatus>Up</NewStatus>\n<NewMaxBitRate>Auto</NewMaxBitRate>\n<NewChannel>13</NewChannel>\n<NewSSID>MOCK1234</NewSSID>\n<NewBeaconType>11i</NewBeaconType>\n<NewX_AVM-DE_PossibleBeaconTypes>None,11i,WPAand11i,11iandWPA3</NewX_AVM-DE_PossibleBeaconTypes>\n<NewMACAddressControlEnabled>0</NewMACAddressControlEnabled>\n<NewStandard>n</NewStandard>\n<NewBSSID>00:00:00:00:00:00</NewBSSID>\n<NewBasicEncryptionModes>None</NewBasicEncryptionModes>\n<NewBasicAuthenticationMode>None</NewBasicAuthenticationMode>\n<NewMaxCharsSSID>32</NewMaxCharsSSID>\n<NewMinCharsSSID>1</NewMinCharsSSID>\n<NewAllowedCharsSSID>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</NewAllowedCharsSSID>\n<NewMinCharsPSK>64</NewMinCharsPSK>\n<NewMaxCharsPSK>64</NewMaxCharsPSK>\n<NewAllowedCharsPSK>0123456789ABCDEFabcdef</NewAllowedCharsPSK>\n<NewX_AVM-DE_FrequencyBand>2400</NewX_AVM-DE_FrequencyBand>\n<NewX_AVM-DE_WLANGlobalEnable>1</NewX_AVM-DE_WLANGlobalEnable>\n</u:GetInfoResponse>\n<u:GetTotalAssociationsResponse xmlns:u=\"urn:dslforum-org:service:WLANConfiguration:1\">\n<NewTotalAssociations>11</NewTotalAssociations>\n</u:GetTotalAssociationsResponse>\n</s:Body>\n</s:Envelope>\n"
  },
  {
    "path": "plugins/inputs/fritzbox/testdata/testcases/wlan/telegraf.conf",
    "content": "[[inputs.fritzbox]]\n  ## URLs are set dynamically by test\n  # urls = [ ]\n  collect = [ \"wlan\" ]\n  # everything else stays at defaults\n  "
  },
  {
    "path": "plugins/inputs/github/README.md",
    "content": "# GitHub Input Plugin\n\nThis plugin gathers information from projects and repositories hosted on\n[GitHub][github].\n\n> [!NOTE]\n> Telegraf also contains the [webhook input plugin][webhook] which can be used\n> as an alternative method for collecting repository information.\n\n⭐ Telegraf v1.11.0\n🏷️ applications\n💻 all\n\n[github]: https://www.github.com\n[webhook]: /plugins/inputs/webhooks/github\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather repository information from GitHub hosted repositories.\n[[inputs.github]]\n  ## List of repositories to monitor\n  repositories = [\n    \"influxdata/telegraf\",\n    \"influxdata/influxdb\"\n  ]\n\n  ## Github API access token.  Unauthenticated requests are limited to 60 per hour.\n  # access_token = \"\"\n\n  ## Github API enterprise url. Github Enterprise accounts must specify their base url.\n  # enterprise_base_url = \"\"\n\n  ## Timeout for HTTP requests.\n  # http_timeout = \"5s\"\n\n  ## List of additional fields to query.\n  ## NOTE: Getting those fields might involve issuing additional API-calls, so please\n  ##       make sure you do not exceed the rate-limit of GitHub.\n  ##\n  ## Available fields are:\n  ##  - pull-requests -- number of open and closed pull requests (2 API-calls per repository)\n  # additional_fields = []\n```\n\n## Metrics\n\n- github_repository\n  - tags:\n    - name - The repository name\n    - owner - The owner of the repository\n    - language - The primary language of the repository\n    - license - The license set for the repository\n  - fields:\n    - forks (int)\n    - open_issues (int)\n    - networks (int)\n    - size (int)\n    - subscribers (int)\n    - stars (int)\n    - watchers (int)\n\nWhen the [internal][internal] input is enabled:\n\n- internal_github\n  - tags:\n    - access_token - obfuscated reference to access token or \"Unauthenticated\"\n  - fields:\n    - limit - How many requests you are limited to (per hour)\n    - remaining - How many requests you have remaining (per hour)\n    - blocks - How many requests have been blocked due to rate limit\n\nWhen specifying `additional_fields` the plugin will collect the specified\nproperties.  **NOTE:** Querying this additional fields might require to perform\nadditional API-calls.  Please make sure you don't exceed the query rate-limit by\nspecifying too many additional fields.  In the following we list the available\noptions with the required API-calls and the resulting fields\n\n- \"pull-requests\" (2 API-calls per repository)\n  - fields:\n    - open_pull_requests (int)\n    - closed_pull_requests (int)\n\n## Example Output\n\n```text\ngithub_repository,language=Go,license=MIT\\ License,name=telegraf,owner=influxdata forks=2679i,networks=2679i,open_issues=794i,size=23263i,stars=7091i,subscribers=316i,watchers=7091i 1563901372000000000\ninternal_github,access_token=Unauthenticated closed_pull_requests=3522i,rate_limit_remaining=59i,rate_limit_limit=60i,rate_limit_blocks=0i,open_pull_requests=260i 1552653551000000000\n```\n\n[internal]: /plugins/inputs/internal\n"
  },
  {
    "path": "plugins/inputs/github/github.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage github\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/go-github/v32/github\"\n\t\"golang.org/x/oauth2\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype GitHub struct {\n\tRepositories      []string        `toml:\"repositories\"`\n\tAccessToken       string          `toml:\"access_token\"`\n\tAdditionalFields  []string        `toml:\"additional_fields\"`\n\tEnterpriseBaseURL string          `toml:\"enterprise_base_url\"`\n\tHTTPTimeout       config.Duration `toml:\"http_timeout\"`\n\n\tgithubClient    *github.Client\n\tobfuscatedToken string\n\n\trateLimit       selfstat.Stat\n\trateLimitErrors selfstat.Stat\n\trateRemaining   selfstat.Stat\n}\n\nfunc (*GitHub) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (g *GitHub) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\n\tif g.githubClient == nil {\n\t\tgithubClient, err := g.createGitHubClient(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tg.githubClient = githubClient\n\n\t\ttokenTags := map[string]string{\n\t\t\t\"access_token\": g.obfuscatedToken,\n\t\t}\n\n\t\tg.rateLimitErrors = selfstat.Register(\"github\", \"rate_limit_blocks\", tokenTags)\n\t\tg.rateLimit = selfstat.Register(\"github\", \"rate_limit_limit\", tokenTags)\n\t\tg.rateRemaining = selfstat.Register(\"github\", \"rate_limit_remaining\", tokenTags)\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(g.Repositories))\n\n\tfor _, repository := range g.Repositories {\n\t\tgo func(repositoryName string, acc telegraf.Accumulator) {\n\t\t\tdefer wg.Done()\n\n\t\t\towner, repository, err := splitRepositoryName(repositoryName)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trepositoryInfo, response, err := g.githubClient.Repositories.Get(ctx, owner, repository)\n\t\t\tg.handleRateLimit(response, err)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tnow := time.Now()\n\t\t\ttags := getTags(repositoryInfo)\n\t\t\tfields := getFields(repositoryInfo)\n\n\t\t\tfor _, field := range g.AdditionalFields {\n\t\t\t\tswitch field {\n\t\t\t\tcase \"pull-requests\":\n\t\t\t\t\t// Pull request properties\n\t\t\t\t\taddFields, err := g.getPullRequestFields(ctx, owner, repository)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tfor k, v := range addFields {\n\t\t\t\t\t\tfields[k] = v\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"unknown additional field %q\", field))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tacc.AddFields(\"github_repository\", fields, tags, now)\n\t\t}(repository, acc)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (g *GitHub) createGitHubClient(ctx context.Context) (*github.Client, error) {\n\thttpClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tProxy: http.ProxyFromEnvironment,\n\t\t},\n\t\tTimeout: time.Duration(g.HTTPTimeout),\n\t}\n\n\tg.obfuscatedToken = \"Unauthenticated\"\n\n\tif g.AccessToken != \"\" {\n\t\ttokenSource := oauth2.StaticTokenSource(\n\t\t\t&oauth2.Token{AccessToken: g.AccessToken},\n\t\t)\n\t\toauthClient := oauth2.NewClient(ctx, tokenSource)\n\t\t_ = context.WithValue(ctx, oauth2.HTTPClient, oauthClient)\n\n\t\tg.obfuscatedToken = g.AccessToken[0:4] + \"...\" + g.AccessToken[len(g.AccessToken)-3:]\n\n\t\treturn g.newGithubClient(oauthClient)\n\t}\n\n\treturn g.newGithubClient(httpClient)\n}\n\nfunc (g *GitHub) newGithubClient(httpClient *http.Client) (*github.Client, error) {\n\tif g.EnterpriseBaseURL != \"\" {\n\t\treturn github.NewEnterpriseClient(g.EnterpriseBaseURL, \"\", httpClient)\n\t}\n\treturn github.NewClient(httpClient), nil\n}\n\nfunc (g *GitHub) handleRateLimit(response *github.Response, err error) {\n\tvar rlErr *github.RateLimitError\n\tif err == nil {\n\t\tg.rateLimit.Set(int64(response.Rate.Limit))\n\t\tg.rateRemaining.Set(int64(response.Rate.Remaining))\n\t} else if errors.As(err, &rlErr) {\n\t\tg.rateLimitErrors.Incr(1)\n\t}\n}\n\nfunc splitRepositoryName(repositoryName string) (owner, repository string, err error) {\n\tsplits := strings.SplitN(repositoryName, \"/\", 2)\n\n\tif len(splits) != 2 {\n\t\treturn \"\", \"\", fmt.Errorf(\"%v is not of format 'owner/repository'\", repositoryName)\n\t}\n\n\treturn splits[0], splits[1], nil\n}\n\nfunc getLicense(rI *github.Repository) string {\n\tif licenseName := rI.GetLicense().GetName(); licenseName != \"\" {\n\t\treturn licenseName\n\t}\n\n\treturn \"None\"\n}\n\nfunc getTags(repositoryInfo *github.Repository) map[string]string {\n\treturn map[string]string{\n\t\t\"owner\":    repositoryInfo.GetOwner().GetLogin(),\n\t\t\"name\":     repositoryInfo.GetName(),\n\t\t\"language\": repositoryInfo.GetLanguage(),\n\t\t\"license\":  getLicense(repositoryInfo),\n\t}\n}\n\nfunc getFields(repositoryInfo *github.Repository) map[string]interface{} {\n\treturn map[string]interface{}{\n\t\t\"stars\":       repositoryInfo.GetStargazersCount(),\n\t\t\"subscribers\": repositoryInfo.GetSubscribersCount(),\n\t\t\"watchers\":    repositoryInfo.GetWatchersCount(),\n\t\t\"networks\":    repositoryInfo.GetNetworkCount(),\n\t\t\"forks\":       repositoryInfo.GetForksCount(),\n\t\t\"open_issues\": repositoryInfo.GetOpenIssuesCount(),\n\t\t\"size\":        repositoryInfo.GetSize(),\n\t}\n}\n\nfunc (g *GitHub) getPullRequestFields(ctx context.Context, owner, repo string) (map[string]interface{}, error) {\n\toptions := github.SearchOptions{\n\t\tTextMatch: false,\n\t\tListOptions: github.ListOptions{\n\t\t\tPerPage: 100,\n\t\t\tPage:    1,\n\t\t},\n\t}\n\n\tclasses := []string{\"open\", \"closed\"}\n\tfields := make(map[string]interface{})\n\tfor _, class := range classes {\n\t\tq := fmt.Sprintf(\"repo:%s/%s is:pr is:%s\", owner, repo, class)\n\t\tsearchResult, response, err := g.githubClient.Search.Issues(ctx, q, &options)\n\t\tg.handleRateLimit(response, err)\n\t\tif err != nil {\n\t\t\treturn fields, err\n\t\t}\n\n\t\tf := class + \"_pull_requests\"\n\t\tfields[f] = searchResult.GetTotal()\n\t}\n\n\treturn fields, nil\n}\n\nfunc init() {\n\tinputs.Add(\"github\", func() telegraf.Input {\n\t\treturn &GitHub{\n\t\t\tHTTPTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/github/github_test.go",
    "content": "package github\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\tgh \"github.com/google/go-github/v32/github\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewGithubClient(t *testing.T) {\n\thttpClient := &http.Client{}\n\tg := &GitHub{}\n\tclient, err := g.newGithubClient(httpClient)\n\trequire.NoError(t, err)\n\trequire.Contains(t, client.BaseURL.String(), \"api.github.com\")\n\tg.EnterpriseBaseURL = \"api.example.com/\"\n\tenterpriseClient, err := g.newGithubClient(httpClient)\n\trequire.NoError(t, err)\n\trequire.Contains(t, enterpriseClient.BaseURL.String(), \"api.example.com\")\n}\n\nfunc TestSplitRepositoryNameWithWorkingExample(t *testing.T) {\n\tvar validRepositoryNames = []struct {\n\t\tfullName   string\n\t\towner      string\n\t\trepository string\n\t}{\n\t\t{\"influxdata/telegraf\", \"influxdata\", \"telegraf\"},\n\t\t{\"influxdata/influxdb\", \"influxdata\", \"influxdb\"},\n\t\t{\"rawkode/saltstack-dotfiles\", \"rawkode\", \"saltstack-dotfiles\"},\n\t}\n\n\tfor _, tt := range validRepositoryNames {\n\t\tt.Run(tt.fullName, func(t *testing.T) {\n\t\t\towner, repository, err := splitRepositoryName(tt.fullName)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.owner, owner)\n\t\t\trequire.Equal(t, tt.repository, repository)\n\t\t})\n\t}\n}\n\nfunc TestSplitRepositoryNameWithNoSlash(t *testing.T) {\n\tvar invalidRepositoryNames = []string{\n\t\t\"influxdata-influxdb\",\n\t}\n\n\tfor _, tt := range invalidRepositoryNames {\n\t\tt.Run(tt, func(t *testing.T) {\n\t\t\t_, _, err := splitRepositoryName(tt)\n\n\t\t\trequire.Error(t, err)\n\t\t})\n\t}\n}\n\nfunc TestGetLicenseWhenExists(t *testing.T) {\n\tlicenseName := \"MIT\"\n\tlicense := gh.License{Name: &licenseName}\n\trepository := gh.Repository{License: &license}\n\n\tgetLicenseReturn := getLicense(&repository)\n\n\trequire.Equal(t, \"MIT\", getLicenseReturn)\n}\n\nfunc TestGetLicenseWhenMissing(t *testing.T) {\n\trepository := gh.Repository{}\n\n\tgetLicenseReturn := getLicense(&repository)\n\n\trequire.Equal(t, \"None\", getLicenseReturn)\n}\n\nfunc TestGetTags(t *testing.T) {\n\tlicenseName := \"MIT\"\n\tlicense := gh.License{Name: &licenseName}\n\n\townerName := \"influxdata\"\n\towner := gh.User{Login: &ownerName}\n\n\tfullName := \"influxdata/influxdb\"\n\trepositoryName := \"influxdb\"\n\n\tlanguage := \"Go\"\n\n\trepository := gh.Repository{\n\t\tFullName: &fullName,\n\t\tName:     &repositoryName,\n\t\tLicense:  &license,\n\t\tOwner:    &owner,\n\t\tLanguage: &language,\n\t}\n\n\tgetTagsReturn := getTags(&repository)\n\n\tcorrectTagsReturn := map[string]string{\n\t\t\"owner\":    ownerName,\n\t\t\"name\":     repositoryName,\n\t\t\"language\": language,\n\t\t\"license\":  licenseName,\n\t}\n\n\trequire.Equal(t, getTagsReturn, correctTagsReturn)\n}\n\nfunc TestGetFields(t *testing.T) {\n\tstars := 1\n\tforks := 2\n\topenIssues := 3\n\tsize := 4\n\tsubscribers := 5\n\twatchers := 6\n\n\trepository := gh.Repository{\n\t\tStargazersCount:  &stars,\n\t\tForksCount:       &forks,\n\t\tOpenIssuesCount:  &openIssues,\n\t\tSize:             &size,\n\t\tNetworkCount:     &forks,\n\t\tSubscribersCount: &subscribers,\n\t\tWatchersCount:    &watchers,\n\t}\n\n\tgetFieldsReturn := getFields(&repository)\n\n\tcorrectFieldReturn := make(map[string]interface{})\n\n\tcorrectFieldReturn[\"stars\"] = 1\n\tcorrectFieldReturn[\"forks\"] = 2\n\tcorrectFieldReturn[\"networks\"] = 2\n\tcorrectFieldReturn[\"open_issues\"] = 3\n\tcorrectFieldReturn[\"size\"] = 4\n\tcorrectFieldReturn[\"subscribers\"] = 5\n\tcorrectFieldReturn[\"watchers\"] = 6\n\n\trequire.Equal(t, getFieldsReturn, correctFieldReturn)\n}\n"
  },
  {
    "path": "plugins/inputs/github/sample.conf",
    "content": "# Gather repository information from GitHub hosted repositories.\n[[inputs.github]]\n  ## List of repositories to monitor\n  repositories = [\n    \"influxdata/telegraf\",\n    \"influxdata/influxdb\"\n  ]\n\n  ## Github API access token.  Unauthenticated requests are limited to 60 per hour.\n  # access_token = \"\"\n\n  ## Github API enterprise url. Github Enterprise accounts must specify their base url.\n  # enterprise_base_url = \"\"\n\n  ## Timeout for HTTP requests.\n  # http_timeout = \"5s\"\n\n  ## List of additional fields to query.\n  ## NOTE: Getting those fields might involve issuing additional API-calls, so please\n  ##       make sure you do not exceed the rate-limit of GitHub.\n  ##\n  ## Available fields are:\n  ##  - pull-requests -- number of open and closed pull requests (2 API-calls per repository)\n  # additional_fields = []\n"
  },
  {
    "path": "plugins/inputs/gnmi/README.md",
    "content": "# gNMI (gRPC Network Management Interface) Input Plugin\n\nThis plugin consumes telemetry data based on [gNMI][gnmi] subscriptions. TLS is\nsupported for authentication and encryption. This plugin is vendor-agnostic and\nis supported on any platform that supports the gNMI specification.\n\nFor Cisco devices the plugin has been optimized to support gNMI telemetry as\nproduced by Cisco IOS XR (64-bit) version 6.5.1, Cisco NX-OS 9.3 and\nCisco IOS XE 16.12 and later.\n\n⭐ Telegraf v1.15.0\n🏷️ network\n💻 all\n\n[gnmi]: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` options. See the [secret-store documentation][SECRETSTORE] for more\ndetails on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Keepalive settings\n  ## See https://pkg.go.dev/google.golang.org/grpc/keepalive\n  ## The client will ping the server to see if the transport is still alive if it has\n  ## not see any activity for the given time.\n  ## If not set, none of the keep-alive setting (including those below) will be applied.\n  ## If set and set below 10 seconds, the gRPC library will apply a minimum value of 10s will be used instead.\n  # keepalive_time = \"\"\n\n  ## Timeout for seeing any activity after the keep-alive probe was\n  ## sent. If no activity is seen the connection is closed.\n  # keepalive_timeout = \"\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Subtree depth for depth extension (disables if < 1)\n  ## see https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-depth.md\n  # depth = 0\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Only receive updates for the state, also suppresses receiving the initial state\n  # updates_only = false\n\n  ## Emit a metric for \"delete\" messages\n  # emit_delete_metrics = false\n\n  ## Enforces the namespace of the first element as origin for aliases and\n  ## response paths, required for backward compatibility.\n  ## NOTE: Set to 'false' if possible but be aware that this might change the path tag!\n  # enforce_first_namespace_as_origin = true\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## Supported values are\n  ##   none         -- do not add a 'path' tag\n  ##   common path  -- use the common path elements of all fields in an update\n  ##   subscription -- use the subscription path\n  # path_guessing_strategy = \"none\"\n\n  ## Prefix tags from path keys with the path element\n  # prefix_tag_key_with_path = false\n\n  ## Optional client-side TLS to authenticate the device\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## YANG model paths for decoding IETF JSON payloads\n  ## Model files are loaded recursively from the given directories. Disabled if\n  ## no models are specified.\n  # yang_model_paths = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]\n```\n\n## Metrics\n\nEach configured subscription will emit a different measurement.  Each leaf in a\nGNMI SubscribeResponse Update message will produce a field reading in the\nmeasurement. GNMI PathElement keys for leaves will attach tags to the field(s).\n\n## Example Output\n\n```text\nifcounters,path=openconfig-interfaces:/interfaces/interface/state/counters,host=linux,name=MgmtEth0/RP0/CPU0/0,source=10.49.234.115,descr/description=Foo in-multicast-pkts=0i,out-multicast-pkts=0i,out-errors=0i,out-discards=0i,in-broadcast-pkts=0i,out-broadcast-pkts=0i,in-discards=0i,in-unknown-protos=0i,in-errors=0i,out-unicast-pkts=0i,in-octets=0i,out-octets=0i,last-clear=\"2019-05-22T16:53:21Z\",in-unicast-pkts=0i 1559145777425000000\nifcounters,path=openconfig-interfaces:/interfaces/interface/state/counters,host=linux,name=GigabitEthernet0/0/0/0,source=10.49.234.115,descr/description=Bar out-multicast-pkts=0i,out-broadcast-pkts=0i,in-errors=0i,out-errors=0i,in-discards=0i,out-octets=0i,in-unknown-protos=0i,in-unicast-pkts=0i,in-octets=0i,in-multicast-pkts=0i,in-broadcast-pkts=0i,last-clear=\"2019-05-22T16:54:50Z\",out-unicast-pkts=0i,out-discards=0i 1559145777425000000\n```\n\n## Troubleshooting\n\n### Empty metric-name warning\n\nSome devices (e.g. Juniper) report spurious data with response paths not\ncorresponding to any subscription. In those cases, Telegraf will not be able\nto determine the metric name for the response and you get an\n*empty metric-name warning*\n\nFor example if you subscribe to `/junos/system/linecard/cpu/memory` but the\ncorresponding response arrives with path\n`/components/component/properties/property/...` To avoid those issues, you can\nmanually map the response to a metric name using the `aliases` option like\n\n```toml\n[[inputs.gnmi]]\n  addresses     = [\"...\"]\n\n  [inputs.gnmi.aliases]\n    memory = \"/components\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"memory\"\n    origin = \"openconfig\"\n    path = \"/junos/system/linecard/cpu/memory\"\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\"\n```\n\nIf this does *not* solve the issue, please follow the warning instructions and\nopen an issue with the response, your configuration and the metric you expect.\n\n### Missing `path` tag\n\nSome devices (e.g. Arista) omit the prefix and specify the path in the update\nif there is only one value reported. This leads to a missing `path` tag for\nthe resulting metrics. In those cases you should set `path_guessing_strategy`\nto `subscription` to use the subscription path as `path` tag.\n\nOther devices might omit the prefix in updates altogether. Here setting\n`path_guessing_strategy` to `common path` can help to infer the `path` tag by\nusing the part of the path that is common to all values in the update.\n\n### TLS handshake failure\n\nWhen receiving an error like\n\n```text\n2024-01-01T00:00:00Z E! [inputs.gnmi] Error in plugin: failed to setup subscription: rpc error: code = Unavailable desc = connection error: desc = \"transport: authentication handshake failed: remote error: tls: handshake failure\"\n```\n\nthis might be due to insecure TLS configurations in the GNMI server. Please\ncheck the minimum TLS version provided by the server as well as the cipher suite\nused. You might want to use the `tls_min_version` or `tls_cipher_suites` setting\nrespectively to work-around the issue. Please be careful to not undermine the\nsecurity of the connection between the plugin and the device!\n"
  },
  {
    "path": "plugins/inputs/gnmi/extensions/jnpr_gnmi_extention/GnmiJuniperTelemetryHeaderExtension.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n//      protoc-gen-go v1.30.0\n//      protoc        v3.12.4\n// source: GnmiJuniperTelemetryHeaderExtension.proto\n\npackage jnpr_gnmi_extention\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype StreamType int32\n\nconst (\n\tStreamType_INITIAL_SYNC StreamType = 0\n\tStreamType_ONCHANGE     StreamType = 1\n\tStreamType_PERIODIC     StreamType = 2\n)\n\n// Enum value maps for StreamType.\nvar (\n\tStreamType_name = map[int32]string{\n\t\t0: \"INITIAL_SYNC\",\n\t\t1: \"ONCHANGE\",\n\t\t2: \"PERIODIC\",\n\t}\n\tStreamType_value = map[string]int32{\n\t\t\"INITIAL_SYNC\": 0,\n\t\t\"ONCHANGE\":     1,\n\t\t\"PERIODIC\":     2,\n\t}\n)\n\nfunc (x StreamType) Enum() *StreamType {\n\tp := new(StreamType)\n\t*p = x\n\treturn p\n}\n\nfunc (x StreamType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (StreamType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes[0].Descriptor()\n}\n\nfunc (StreamType) Type() protoreflect.EnumType {\n\treturn &file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes[0]\n}\n\nfunc (x StreamType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use StreamType.Descriptor instead.\nfunc (StreamType) EnumDescriptor() ([]byte, []int) {\n\treturn file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP(), []int{0}\n}\n\n// Present as first gNMI update in all packets\ntype GnmiJuniperTelemetryHeaderExtension struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// router name:export IP address\n\tSystemId string `protobuf:\"bytes,1,opt,name=system_id,json=systemId,proto3\" json:\"system_id,omitempty\"`\n\t// line card / RE (slot number)\n\tComponentId uint32 `protobuf:\"varint,2,opt,name=component_id,json=componentId,proto3\" json:\"component_id,omitempty\"`\n\t// PFE (if applicable)\n\tSubComponentId uint32 `protobuf:\"varint,3,opt,name=sub_component_id,json=subComponentId,proto3\" json:\"sub_component_id,omitempty\"`\n\t// Internal sensor name\n\tSensorName string `protobuf:\"bytes,4,opt,name=sensor_name,json=sensorName,proto3\" json:\"sensor_name,omitempty\"`\n\t// Sensor path in the subscribe request\n\tSubscribedPath string `protobuf:\"bytes,5,opt,name=subscribed_path,json=subscribedPath,proto3\" json:\"subscribed_path,omitempty\"`\n\t// Internal sensor path in junos\n\tStreamedPath string `protobuf:\"bytes,6,opt,name=streamed_path,json=streamedPath,proto3\" json:\"streamed_path,omitempty\"`\n\tComponent    string `protobuf:\"bytes,7,opt,name=component,proto3\" json:\"component,omitempty\"`\n\t// Sequence number, monotonically increasing for each\n\tSequenceNumber uint64 `protobuf:\"varint,8,opt,name=sequence_number,json=sequenceNumber,proto3\" json:\"sequence_number,omitempty\"`\n\t// Payload get timestamp in milliseconds\n\tPayloadGetTimestamp int64 `protobuf:\"varint,9,opt,name=payload_get_timestamp,json=payloadGetTimestamp,proto3\" json:\"payload_get_timestamp,omitempty\"`\n\t// Stream creation timestamp in milliseconds\n\tStreamCreationTimestamp int64 `protobuf:\"varint,10,opt,name=stream_creation_timestamp,json=streamCreationTimestamp,proto3\" json:\"stream_creation_timestamp,omitempty\"`\n\t// [Deprecated] Event timestamp in milliseconds\n\t//\n\t// Deprecated: Marked as deprecated in GnmiJuniperTelemetryHeaderExtension.proto.\n\tEventTimestamp int64 `protobuf:\"varint,11,opt,name=event_timestamp,json=eventTimestamp,proto3\" json:\"event_timestamp,omitempty\"`\n\t// Export timestamp in milliseconds\n\tExportTimestamp int64 `protobuf:\"varint,12,opt,name=export_timestamp,json=exportTimestamp,proto3\" json:\"export_timestamp,omitempty\"`\n\t// Subsequence number\n\tSubSequenceNumber uint64 `protobuf:\"varint,13,opt,name=sub_sequence_number,json=subSequenceNumber,proto3\" json:\"sub_sequence_number,omitempty\"`\n\t// End of marker\n\tEom bool `protobuf:\"varint,14,opt,name=eom,proto3\" json:\"eom,omitempty\"`\n\t// Event publish timestamp in milliseconds\n\tEventPublishTimestamp int64 `protobuf:\"varint,15,opt,name=event_publish_timestamp,json=eventPublishTimestamp,proto3\" json:\"event_publish_timestamp,omitempty\"`\n\t// Stream type of packet\n\tStreamId StreamType `protobuf:\"varint,16,opt,name=stream_id,json=streamId,proto3,enum=StreamType\" json:\"stream_id,omitempty\"`\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) Reset() {\n\t*x = GnmiJuniperTelemetryHeaderExtension{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GnmiJuniperTelemetryHeaderExtension) ProtoMessage() {}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) ProtoReflect() protoreflect.Message {\n\tmi := &file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GnmiJuniperTelemetryHeaderExtension.ProtoReflect.Descriptor instead.\nfunc (*GnmiJuniperTelemetryHeaderExtension) Descriptor() ([]byte, []int) {\n\treturn file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSystemId() string {\n\tif x != nil {\n\t\treturn x.SystemId\n\t}\n\treturn \"\"\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetComponentId() uint32 {\n\tif x != nil {\n\t\treturn x.ComponentId\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSubComponentId() uint32 {\n\tif x != nil {\n\t\treturn x.SubComponentId\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSensorName() string {\n\tif x != nil {\n\t\treturn x.SensorName\n\t}\n\treturn \"\"\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSubscribedPath() string {\n\tif x != nil {\n\t\treturn x.SubscribedPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetStreamedPath() string {\n\tif x != nil {\n\t\treturn x.StreamedPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetComponent() string {\n\tif x != nil {\n\t\treturn x.Component\n\t}\n\treturn \"\"\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSequenceNumber() uint64 {\n\tif x != nil {\n\t\treturn x.SequenceNumber\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetPayloadGetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.PayloadGetTimestamp\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetStreamCreationTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.StreamCreationTimestamp\n\t}\n\treturn 0\n}\n\n// Deprecated: Marked as deprecated in GnmiJuniperTelemetryHeaderExtension.proto.\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetEventTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.EventTimestamp\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetExportTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.ExportTimestamp\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetSubSequenceNumber() uint64 {\n\tif x != nil {\n\t\treturn x.SubSequenceNumber\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetEom() bool {\n\tif x != nil {\n\t\treturn x.Eom\n\t}\n\treturn false\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetEventPublishTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.EventPublishTimestamp\n\t}\n\treturn 0\n}\n\nfunc (x *GnmiJuniperTelemetryHeaderExtension) GetStreamId() StreamType {\n\tif x != nil {\n\t\treturn x.StreamId\n\t}\n\treturn StreamType_INITIAL_SYNC\n}\n\nvar File_GnmiJuniperTelemetryHeaderExtension_proto protoreflect.FileDescriptor\n\nvar file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc = []byte{\n\t0x0a, 0x29, 0x47, 0x6e, 0x6d, 0x69, 0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x54, 0x65, 0x6c,\n\t0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65,\n\t0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x05, 0x0a, 0x23,\n\t0x47, 0x6e, 0x6d, 0x69, 0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x65, 0x6d,\n\t0x65, 0x74, 0x72, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,\n\t0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x64,\n\t0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,\n\t0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f,\n\t0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73,\n\t0x75, 0x62, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a,\n\t0x0b, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27,\n\t0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74,\n\t0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,\n\t0x62, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x61,\n\t0x6d, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,\n\t0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09,\n\t0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65,\n\t0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x08, 0x20,\n\t0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x4e, 0x75, 0x6d,\n\t0x62, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x67,\n\t0x65, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x47, 0x65, 0x74, 0x54, 0x69,\n\t0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x74, 0x72, 0x65, 0x61,\n\t0x6d, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73,\n\t0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x17, 0x73, 0x74, 0x72, 0x65,\n\t0x61, 0x6d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,\n\t0x61, 0x6d, 0x70, 0x12, 0x2b, 0x0a, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d,\n\t0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01,\n\t0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,\n\t0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73,\n\t0x74, 0x61, 0x6d, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6f,\n\t0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x73,\n\t0x75, 0x62, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62,\n\t0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x73, 0x75, 0x62, 0x53, 0x65, 0x71,\n\t0x75, 0x65, 0x6e, 0x63, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x65,\n\t0x6f, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6f, 0x6d, 0x12, 0x36, 0x0a,\n\t0x17, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x74,\n\t0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15,\n\t0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65,\n\t0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f,\n\t0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,\n\t0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x2a,\n\t0x3a, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a,\n\t0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12,\n\t0x0c, 0x0a, 0x08, 0x4f, 0x4e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a,\n\t0x08, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x10, 0x02, 0x42, 0x17, 0x5a, 0x15, 0x2e,\n\t0x3b, 0x6a, 0x6e, 0x70, 0x72, 0x5f, 0x67, 0x6e, 0x6d, 0x69, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e,\n\t0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_rawDescOnce sync.Once\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData = file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc\n)\n\nfunc file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP() []byte {\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_rawDescOnce.Do(func() {\n\t\tfile_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData = protoimpl.X.CompressGZIP(file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData)\n\t})\n\treturn file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData\n}\n\nvar file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_GnmiJuniperTelemetryHeaderExtension_proto_goTypes = []interface{}{\n\t(StreamType)(0), // 0: StreamType\n\t(*GnmiJuniperTelemetryHeaderExtension)(nil), // 1: GnmiJuniperTelemetryHeaderExtension\n}\nvar file_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs = []int32{\n\t0, // 0: GnmiJuniperTelemetryHeaderExtension.stream_id:type_name -> StreamType\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_GnmiJuniperTelemetryHeaderExtension_proto_init() }\nfunc file_GnmiJuniperTelemetryHeaderExtension_proto_init() {\n\tif File_GnmiJuniperTelemetryHeaderExtension_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GnmiJuniperTelemetryHeaderExtension); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_GnmiJuniperTelemetryHeaderExtension_proto_goTypes,\n\t\tDependencyIndexes: file_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs,\n\t\tEnumInfos:         file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes,\n\t\tMessageInfos:      file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes,\n\t}.Build()\n\tFile_GnmiJuniperTelemetryHeaderExtension_proto = out.File\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc = nil\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_goTypes = nil\n\tfile_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/gnmi.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage gnmi\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/gnxi/utils/xpath\"\n\t\"github.com/openconfig/gnmi/proto/gnmi\"\n\t\"github.com/openconfig/gnmi/proto/gnmi_ext\"\n\t\"google.golang.org/grpc/keepalive\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/common/yangmodel\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Currently supported GNMI Extensions\nvar supportedExtensions = []string{\"juniper_header\"}\n\n// Define the warning to show if we cannot get a metric name.\nconst emptyNameWarning = `Got empty metric-name for response (field %q), usually\nindicating configuration issues as the response cannot be related to any\nsubscription.Please open an issue on https://github.com/influxdata/telegraf\nincluding your device model and the following response data:\n%+v\nThis message is only printed once.`\n\ntype GNMI struct {\n\tAddresses                     []string          `toml:\"addresses\"`\n\tSubscriptions                 []subscription    `toml:\"subscription\"`\n\tTagSubscriptions              []tagSubscription `toml:\"tag_subscription\"`\n\tAliases                       map[string]string `toml:\"aliases\"`\n\tEncoding                      string            `toml:\"encoding\"`\n\tOrigin                        string            `toml:\"origin\"`\n\tPrefix                        string            `toml:\"prefix\"`\n\tTarget                        string            `toml:\"target\"`\n\tUpdatesOnly                   bool              `toml:\"updates_only\"`\n\tEmitDeleteMetrics             bool              `toml:\"emit_delete_metrics\"`\n\tVendorSpecific                []string          `toml:\"vendor_specific\"`\n\tUsername                      config.Secret     `toml:\"username\"`\n\tPassword                      config.Secret     `toml:\"password\"`\n\tRedial                        config.Duration   `toml:\"redial\"`\n\tMaxMsgSize                    config.Size       `toml:\"max_msg_size\"`\n\tDepth                         int32             `toml:\"depth\"`\n\tTrace                         bool              `toml:\"dump_responses\"`\n\tCanonicalFieldNames           bool              `toml:\"canonical_field_names\"`\n\tTrimFieldNames                bool              `toml:\"trim_field_names\"`\n\tPrefixTagKeyWithPath          bool              `toml:\"prefix_tag_key_with_path\"`\n\tGuessPathStrategy             string            `toml:\"path_guessing_strategy\"`\n\tKeepaliveTime                 config.Duration   `toml:\"keepalive_time\"`\n\tKeepaliveTimeout              config.Duration   `toml:\"keepalive_timeout\"`\n\tYangModelPaths                []string          `toml:\"yang_model_paths\"`\n\tEnforceFirstNamespaceAsOrigin bool              `toml:\"enforce_first_namespace_as_origin\"`\n\tLog                           telegraf.Logger   `toml:\"-\"`\n\tcommon_tls.ClientConfig\n\n\t// Internal state\n\tinternalAliases map[*pathInfo]string\n\tdecoder         *yangmodel.Decoder\n\tcancel          context.CancelFunc\n\twg              sync.WaitGroup\n}\n\ntype subscription struct {\n\tName              string          `toml:\"name\"`\n\tOrigin            string          `toml:\"origin\"`\n\tPath              string          `toml:\"path\"`\n\tSubscriptionMode  string          `toml:\"subscription_mode\"`\n\tSampleInterval    config.Duration `toml:\"sample_interval\"`\n\tSuppressRedundant bool            `toml:\"suppress_redundant\"`\n\tHeartbeatInterval config.Duration `toml:\"heartbeat_interval\"`\n\n\tfullPath *gnmi.Path\n}\n\ntype tagSubscription struct {\n\tsubscription\n\tMatch    string   `toml:\"match\"`\n\tElements []string `toml:\"elements\"`\n}\n\nfunc (*GNMI) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *GNMI) Init() error {\n\t// Check options\n\tswitch c.Encoding {\n\tcase \"\":\n\t\tc.Encoding = \"proto\"\n\tcase \"proto\", \"json\", \"json_ietf\", \"bytes\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported encoding %s\", c.Encoding)\n\t}\n\n\tif time.Duration(c.Redial) <= 0 {\n\t\treturn errors.New(\"redial duration must be positive\")\n\t}\n\n\t// Check vendor_specific options configured by user\n\tif err := choice.CheckSlice(c.VendorSpecific, supportedExtensions); err != nil {\n\t\treturn fmt.Errorf(\"unsupported vendor_specific option: %w\", err)\n\t}\n\n\t// Check path guessing and handle deprecated option\n\tswitch c.GuessPathStrategy {\n\tcase \"\", \"none\", \"common path\", \"subscription\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'path_guessing_strategy' %q\", c.GuessPathStrategy)\n\t}\n\n\t// Use the new TLS option for enabling\n\t// Honor deprecated option\n\tenable := c.ClientConfig.Enable != nil && *c.ClientConfig.Enable\n\tc.ClientConfig.Enable = &enable\n\n\t// Split the subscriptions into \"normal\" and \"tag\" subscription\n\t// and prepare them.\n\tfor i := len(c.Subscriptions) - 1; i >= 0; i-- {\n\t\tsubscription := c.Subscriptions[i]\n\n\t\t// Check the subscription\n\t\tif subscription.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"empty 'name' found for subscription %d\", i+1)\n\t\t}\n\t\tif subscription.Path == \"\" {\n\t\t\treturn fmt.Errorf(\"empty 'path' found for subscription %d\", i+1)\n\t\t}\n\n\t\tif err := subscription.buildFullPath(c); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor idx := range c.TagSubscriptions {\n\t\tif err := c.TagSubscriptions[idx].buildFullPath(c); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch c.TagSubscriptions[idx].Match {\n\t\tcase \"\":\n\t\t\tif len(c.TagSubscriptions[idx].Elements) > 0 {\n\t\t\t\tc.TagSubscriptions[idx].Match = \"elements\"\n\t\t\t} else {\n\t\t\t\tc.TagSubscriptions[idx].Match = \"name\"\n\t\t\t}\n\t\tcase \"unconditional\":\n\t\tcase \"name\":\n\t\tcase \"elements\":\n\t\t\tif len(c.TagSubscriptions[idx].Elements) == 0 {\n\t\t\t\treturn errors.New(\"tag_subscription must have at least one element\")\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown match type %q for tag-subscription %q\", c.TagSubscriptions[idx].Match, c.TagSubscriptions[idx].Name)\n\t\t}\n\t}\n\n\t// Invert explicit alias list and prefill subscription names\n\tc.internalAliases = make(map[*pathInfo]string, len(c.Subscriptions)+len(c.Aliases)+len(c.TagSubscriptions))\n\tfor _, s := range c.Subscriptions {\n\t\tif err := s.buildAlias(c.internalAliases, c.EnforceFirstNamespaceAsOrigin); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, s := range c.TagSubscriptions {\n\t\tif err := s.buildAlias(c.internalAliases, c.EnforceFirstNamespaceAsOrigin); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor alias, encodingPath := range c.Aliases {\n\t\tpath := newInfoFromString(encodingPath)\n\t\tif c.EnforceFirstNamespaceAsOrigin {\n\t\t\tpath.enforceFirstNamespaceAsOrigin()\n\t\t}\n\t\tc.internalAliases[path] = alias\n\t}\n\tc.Log.Debugf(\"Internal alias mapping: %+v\", c.internalAliases)\n\n\t// Warn about configures insecure cipher suites\n\tinsecure := common_tls.InsecureCiphers(c.ClientConfig.TLSCipherSuites)\n\tif len(insecure) > 0 {\n\t\tc.Log.Warnf(\"Configured insecure cipher suites: %s\", strings.Join(insecure, \",\"))\n\t}\n\n\t// Check the TLS configuration\n\tif _, err := c.ClientConfig.TLSConfig(); err != nil {\n\t\tif errors.Is(err, common_tls.ErrCipherUnsupported) {\n\t\t\tsecure, insecure := common_tls.Ciphers()\n\t\t\tc.Log.Info(\"Supported secure ciphers:\")\n\t\t\tfor _, name := range secure {\n\t\t\t\tc.Log.Infof(\"  %s\", name)\n\t\t\t}\n\t\t\tc.Log.Info(\"Supported insecure ciphers:\")\n\t\t\tfor _, name := range insecure {\n\t\t\t\tc.Log.Infof(\"  %s\", name)\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n\n\t// Load the YANG models if specified by the user\n\tif len(c.YangModelPaths) > 0 {\n\t\tdecoder, err := yangmodel.NewDecoder(c.YangModelPaths...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating YANG model decoder failed: %w\", err)\n\t\t}\n\t\tc.decoder = decoder\n\t}\n\n\treturn nil\n}\n\nfunc (c *GNMI) Start(acc telegraf.Accumulator) error {\n\t// Validate configuration\n\trequest, err := c.newSubscribeRequest()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Generate TLS config if enabled\n\ttlscfg, err := c.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Prepare the context, optionally with credentials\n\tvar ctx context.Context\n\tctx, c.cancel = context.WithCancel(context.Background())\n\n\tif !c.Username.Empty() {\n\t\tusernameSecret, err := c.Username.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t\t}\n\t\tusername := usernameSecret.String()\n\t\tusernameSecret.Destroy()\n\n\t\tpasswordSecret, err := c.Password.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t\t}\n\t\tpassword := passwordSecret.String()\n\t\tpasswordSecret.Destroy()\n\n\t\tctx = metadata.AppendToOutgoingContext(ctx, \"username\", username, \"password\", password)\n\t}\n\n\t// Create a goroutine for each device, dial and subscribe\n\tc.wg.Add(len(c.Addresses))\n\tfor _, addr := range c.Addresses {\n\t\tgo func(addr string) {\n\t\t\tdefer c.wg.Done()\n\n\t\t\thost, port, err := net.SplitHostPort(addr)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %s: %w\", addr, err))\n\t\t\t\treturn\n\t\t\t}\n\t\t\th := handler{\n\t\t\t\thost:                          host,\n\t\t\t\tport:                          port,\n\t\t\t\taliases:                       c.internalAliases,\n\t\t\t\ttagsubs:                       c.TagSubscriptions,\n\t\t\t\tmaxMsgSize:                    int(c.MaxMsgSize),\n\t\t\t\tvendorExt:                     c.VendorSpecific,\n\t\t\t\temitDeleteMetrics:             c.EmitDeleteMetrics,\n\t\t\t\ttagStore:                      newTagStore(c.TagSubscriptions),\n\t\t\t\ttrace:                         c.Trace,\n\t\t\t\tcanonicalFieldNames:           c.CanonicalFieldNames,\n\t\t\t\ttrimSlash:                     c.TrimFieldNames,\n\t\t\t\ttagPathPrefix:                 c.PrefixTagKeyWithPath,\n\t\t\t\tguessPathStrategy:             c.GuessPathStrategy,\n\t\t\t\tdecoder:                       c.decoder,\n\t\t\t\tenforceFirstNamespaceAsOrigin: c.EnforceFirstNamespaceAsOrigin,\n\t\t\t\tlog:                           c.Log,\n\t\t\t\tClientParameters: keepalive.ClientParameters{\n\t\t\t\t\tTime:                time.Duration(c.KeepaliveTime),\n\t\t\t\t\tTimeout:             time.Duration(c.KeepaliveTimeout),\n\t\t\t\t\tPermitWithoutStream: false,\n\t\t\t\t},\n\t\t\t}\n\t\t\tfor ctx.Err() == nil {\n\t\t\t\tif err := h.subscribeGNMI(ctx, acc, tlscfg, request); err != nil && ctx.Err() == nil {\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t}\n\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\tcase <-time.After(time.Duration(c.Redial)):\n\t\t\t\t}\n\t\t\t}\n\t\t}(addr)\n\t}\n\treturn nil\n}\n\nfunc (*GNMI) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (c *GNMI) Stop() {\n\tc.cancel()\n\tc.wg.Wait()\n}\n\nfunc (s *subscription) buildSubscription() (*gnmi.Subscription, error) {\n\tgnmiPath, err := parsePath(s.Origin, s.Path, \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmode, ok := gnmi.SubscriptionMode_value[strings.ToUpper(s.SubscriptionMode)]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid subscription mode %s\", s.SubscriptionMode)\n\t}\n\treturn &gnmi.Subscription{\n\t\tPath:              gnmiPath,\n\t\tMode:              gnmi.SubscriptionMode(mode),\n\t\tHeartbeatInterval: uint64(time.Duration(s.HeartbeatInterval).Nanoseconds()),\n\t\tSampleInterval:    uint64(time.Duration(s.SampleInterval).Nanoseconds()),\n\t\tSuppressRedundant: s.SuppressRedundant,\n\t}, nil\n}\n\n// Create a new gNMI SubscribeRequest\nfunc (c *GNMI) newSubscribeRequest() (*gnmi.SubscribeRequest, error) {\n\t// Create subscription objects\n\tsubscriptions := make([]*gnmi.Subscription, 0, len(c.Subscriptions)+len(c.TagSubscriptions))\n\tfor _, subscription := range c.TagSubscriptions {\n\t\tsub, err := subscription.buildSubscription()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubscriptions = append(subscriptions, sub)\n\t}\n\tfor _, subscription := range c.Subscriptions {\n\t\tsub, err := subscription.buildSubscription()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubscriptions = append(subscriptions, sub)\n\t}\n\n\t// Construct subscribe request\n\tgnmiPath, err := parsePath(c.Origin, c.Prefix, c.Target)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Do not provide an empty prefix. Required for Huawei NE40 router v8.21\n\t// (and possibly others). See https://github.com/influxdata/telegraf/issues/12273.\n\tif gnmiPath.Origin == \"\" && gnmiPath.Target == \"\" && len(gnmiPath.Elem) == 0 {\n\t\tgnmiPath = nil\n\t}\n\n\tif c.Encoding != \"proto\" && c.Encoding != \"json\" && c.Encoding != \"json_ietf\" && c.Encoding != \"bytes\" {\n\t\treturn nil, fmt.Errorf(\"unsupported encoding %s\", c.Encoding)\n\t}\n\n\tvar extensions []*gnmi_ext.Extension\n\tif c.Depth > 0 {\n\t\textensions = []*gnmi_ext.Extension{\n\t\t\t{\n\t\t\t\tExt: &gnmi_ext.Extension_Depth{\n\t\t\t\t\tDepth: &gnmi_ext.Depth{\n\t\t\t\t\t\tLevel: uint32(c.Depth),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n\n\treturn &gnmi.SubscribeRequest{\n\t\tRequest: &gnmi.SubscribeRequest_Subscribe{\n\t\t\tSubscribe: &gnmi.SubscriptionList{\n\t\t\t\tPrefix:       gnmiPath,\n\t\t\t\tMode:         gnmi.SubscriptionList_STREAM,\n\t\t\t\tEncoding:     gnmi.Encoding(gnmi.Encoding_value[strings.ToUpper(c.Encoding)]),\n\t\t\t\tSubscription: subscriptions,\n\t\t\t\tUpdatesOnly:  c.UpdatesOnly,\n\t\t\t},\n\t\t},\n\t\tExtension: extensions,\n\t}, nil\n}\n\n// ParsePath from XPath-like string to gNMI path structure\nfunc parsePath(origin, pathToParse, target string) (*gnmi.Path, error) {\n\tgnmiPath, err := xpath.ToGNMIPath(pathToParse)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgnmiPath.Origin = origin\n\tgnmiPath.Target = target\n\treturn gnmiPath, err\n}\n\nfunc (s *subscription) buildFullPath(c *GNMI) error {\n\tvar err error\n\tif s.fullPath, err = xpath.ToGNMIPath(s.Path); err != nil {\n\t\treturn err\n\t}\n\ts.fullPath.Origin = s.Origin\n\ts.fullPath.Target = c.Target\n\tif c.Prefix != \"\" {\n\t\tprefix, err := xpath.ToGNMIPath(c.Prefix)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.fullPath.Elem = append(prefix.Elem, s.fullPath.Elem...)\n\t\tif s.Origin == \"\" && c.Origin != \"\" {\n\t\t\ts.fullPath.Origin = c.Origin\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *subscription) buildAlias(aliases map[*pathInfo]string, enforceFirstNamespaceAsOrigin bool) error {\n\t// Build the subscription path without keys\n\tpath, err := parsePath(s.Origin, s.Path, \"\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tinfo := newInfoFromPathWithoutKeys(path)\n\tif enforceFirstNamespaceAsOrigin {\n\t\tinfo.enforceFirstNamespaceAsOrigin()\n\t}\n\n\t// If the user didn't provide a measurement name, use last path element\n\tname := s.Name\n\tif name == \"\" && len(info.segments) > 0 {\n\t\tname = info.segments[len(info.segments)-1].id\n\t}\n\tif name != \"\" {\n\t\taliases[info] = name\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"gnmi\", func() telegraf.Input {\n\t\treturn &GNMI{\n\t\t\tRedial:                        config.Duration(10 * time.Second),\n\t\t\tEnforceFirstNamespaceAsOrigin: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/gnmi_test.go",
    "content": "package gnmi\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/openconfig/gnmi/proto/gnmi\"\n\t\"github.com/openconfig/gnmi/proto/gnmi_ext\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/gnmi/extensions/jnpr_gnmi_extention\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestParsePath(t *testing.T) {\n\tpath := \"/foo/bar/bla[shoo=woo][shoop=/woop/]/z\"\n\tparsed, err := parsePath(\"theorigin\", path, \"thetarget\")\n\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"theorigin\", parsed.Origin)\n\trequire.Equal(t, \"thetarget\", parsed.Target)\n\trequire.Equal(t, []*gnmi.PathElem{{Name: \"foo\"}, {Name: \"bar\"},\n\t\t{Name: \"bla\", Key: map[string]string{\"shoo\": \"woo\", \"shoop\": \"/woop/\"}}, {Name: \"z\"}}, parsed.Elem)\n\n\tparsed, err = parsePath(\"\", \"\", \"\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, &gnmi.Path{}, parsed)\n\n\tparsed, err = parsePath(\"\", \"/foo[[\", \"\")\n\trequire.Nil(t, parsed)\n\trequire.Error(t, err)\n}\n\ntype mockServer struct {\n\tsubscribeF func(gnmi.GNMI_SubscribeServer) error\n\tgrpcServer *grpc.Server\n}\n\nfunc (*mockServer) Capabilities(context.Context, *gnmi.CapabilityRequest) (*gnmi.CapabilityResponse, error) {\n\treturn nil, nil\n}\n\nfunc (*mockServer) Get(context.Context, *gnmi.GetRequest) (*gnmi.GetResponse, error) {\n\treturn nil, nil\n}\n\nfunc (*mockServer) Set(context.Context, *gnmi.SetRequest) (*gnmi.SetResponse, error) {\n\treturn nil, nil\n}\n\nfunc (s *mockServer) Subscribe(server gnmi.GNMI_SubscribeServer) error {\n\treturn s.subscribeF(server)\n}\n\nfunc TestWaitError(t *testing.T) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tgrpcServer := grpc.NewServer()\n\tgnmiServer := &mockServer{\n\t\tsubscribeF: func(gnmi.GNMI_SubscribeServer) error {\n\t\t\treturn errors.New(\"testerror\")\n\t\t},\n\t\tgrpcServer: grpcServer,\n\t}\n\tgnmi.RegisterGNMIServer(grpcServer, gnmiServer)\n\n\tplugin := &GNMI{\n\t\tLog:       testutil.Logger{},\n\t\tAddresses: []string{listener.Addr().String()},\n\t\tEncoding:  \"proto\",\n\t\tRedial:    config.Duration(1 * time.Second),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\tacc.WaitError(1)\n\tplugin.Stop()\n\tgrpcServer.Stop()\n\twg.Wait()\n\n\t// Check if the expected error text is among the errors\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.Errors[0], \"aborted gNMI subscription: rpc error: code = Unknown desc = testerror\")\n}\n\nfunc TestUsernamePassword(t *testing.T) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tgrpcServer := grpc.NewServer()\n\tgnmiServer := &mockServer{\n\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\tmetadata, ok := metadata.FromIncomingContext(server.Context())\n\t\t\tif !ok {\n\t\t\t\treturn errors.New(\"failed to get metadata\")\n\t\t\t}\n\n\t\t\tusername := metadata.Get(\"username\")\n\t\t\tif len(username) != 1 || username[0] != \"theusername\" {\n\t\t\t\treturn errors.New(\"wrong username\")\n\t\t\t}\n\n\t\t\tpassword := metadata.Get(\"password\")\n\t\t\tif len(password) != 1 || password[0] != \"thepassword\" {\n\t\t\t\treturn errors.New(\"wrong password\")\n\t\t\t}\n\n\t\t\treturn errors.New(\"success\")\n\t\t},\n\t\tgrpcServer: grpcServer,\n\t}\n\tgnmi.RegisterGNMIServer(grpcServer, gnmiServer)\n\n\tplugin := &GNMI{\n\t\tLog:       testutil.Logger{},\n\t\tAddresses: []string{listener.Addr().String()},\n\t\tUsername:  config.NewSecret([]byte(\"theusername\")),\n\t\tPassword:  config.NewSecret([]byte(\"thepassword\")),\n\t\tEncoding:  \"proto\",\n\t\tRedial:    config.Duration(1 * time.Second),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\tacc.WaitError(1)\n\tplugin.Stop()\n\tgrpcServer.Stop()\n\twg.Wait()\n\n\t// Check if the expected error text is among the errors\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.Errors[0], \"aborted gNMI subscription: rpc error: code = Unknown desc = success\")\n}\n\nfunc mockGNMINotification() *gnmi.Notification {\n\treturn &gnmi.Notification{\n\t\tTimestamp: 1543236572000000000,\n\t\tPrefix: &gnmi.Path{\n\t\t\tOrigin: \"type\",\n\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t{\n\t\t\t\t\tName: \"model\",\n\t\t\t\t\tKey:  map[string]string{\"foo\": \"bar\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTarget: \"subscription\",\n\t\t},\n\t\tUpdate: []*gnmi.Update{\n\t\t\t{\n\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t{Name: \"some\"},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"path\",\n\t\t\t\t\t\t\tKey:  map[string]string{\"name\": \"str\", \"uint64\": \"1234\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVal: &gnmi.TypedValue{Value: &gnmi.TypedValue_IntVal{IntVal: 5678}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t{Name: \"other\"},\n\t\t\t\t\t\t{Name: \"path\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVal: &gnmi.TypedValue{Value: &gnmi.TypedValue_StringVal{StringVal: \"foobar\"}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t{Name: \"other\"},\n\t\t\t\t\t\t{Name: \"this\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVal: &gnmi.TypedValue{Value: &gnmi.TypedValue_StringVal{StringVal: \"that\"}},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc TestNotification(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *GNMI\n\t\tserver   *mockServer\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"multiple metrics\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:      testutil.Logger{},\n\t\t\t\tEncoding: \"proto\",\n\t\t\t\tRedial:   config.Duration(1 * time.Second),\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"alias\",\n\t\t\t\t\t\tOrigin:           \"type\",\n\t\t\t\t\t\tPath:             \"/model\",\n\t\t\t\t\t\tSubscriptionMode: \"sample\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\tnotification := mockGNMINotification()\n\t\t\t\t\terr := server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_Update{Update: notification}})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\terr = server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_SyncResponse{SyncResponse: true}})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnotification.Prefix.Elem[0].Key[\"foo\"] = \"bar2\"\n\t\t\t\t\tnotification.Update[0].Path.Elem[1].Key[\"name\"] = \"str2\"\n\t\t\t\t\tnotification.Update[0].Val = &gnmi.TypedValue{Value: &gnmi.TypedValue_JsonVal{JsonVal: []byte{'\"', '1', '2', '3', '\"'}}}\n\t\t\t\t\treturn server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_Update{Update: notification}})\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"alias\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"type:/model\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"foo\":    \"bar\",\n\t\t\t\t\t\t\"name\":   \"str\",\n\t\t\t\t\t\t\"uint64\": \"1234\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"some/path\": int64(5678),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"alias\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"type:/model\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"foo\":    \"bar\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"other/path\": \"foobar\",\n\t\t\t\t\t\t\"other/this\": \"that\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"alias\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"type:/model\",\n\t\t\t\t\t\t\"foo\":    \"bar2\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"name\":   \"str2\",\n\t\t\t\t\t\t\"uint64\": \"1234\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"some/path\": \"123\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"alias\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"type:/model\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"foo\":    \"bar2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"other/path\": \"foobar\",\n\t\t\t\t\t\t\"other/this\": \"that\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"full path field key\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:      testutil.Logger{},\n\t\t\t\tEncoding: \"proto\",\n\t\t\t\tRedial:   config.Duration(1 * time.Second),\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"PHY_COUNTERS\",\n\t\t\t\t\t\tOrigin:           \"type\",\n\t\t\t\t\t\tPath:             \"/state/port[port-id=*]/ethernet/oper-speed\",\n\t\t\t\t\t\tSubscriptionMode: \"sample\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\tresponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1543236572000000000,\n\t\t\t\t\t\t\t\tPrefix: &gnmi.Path{\n\t\t\t\t\t\t\t\t\tOrigin: \"type\",\n\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"state\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"port\",\n\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"port-id\": \"1\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"ethernet\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"oper-speed\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tTarget: \"subscription\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_IntVal{IntVal: 42},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn server.Send(response)\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"PHY_COUNTERS\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":    \"type:/state/port/ethernet/oper-speed\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port_id\": \"1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"oper_speed\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"issue #11011\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:      testutil.Logger{},\n\t\t\t\tEncoding: \"proto\",\n\t\t\t\tRedial:   config.Duration(1 * time.Second),\n\t\t\t\tTagSubscriptions: []tagSubscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tsubscription: subscription{\n\t\t\t\t\t\t\tName:             \"oc-neigh-desc\",\n\t\t\t\t\t\t\tOrigin:           \"openconfig\",\n\t\t\t\t\t\t\tPath:             \"/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/description\",\n\t\t\t\t\t\t\tSubscriptionMode: \"on_change\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tElements: []string{\"network-instance\", \"protocol\", \"neighbor\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"oc-neigh-state\",\n\t\t\t\t\t\tOrigin:           \"openconfig\",\n\t\t\t\t\t\tPath:             \"/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/session-state\",\n\t\t\t\t\t\tSubscriptionMode: \"on_change\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\ttagResponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1543236571000000000,\n\t\t\t\t\t\t\t\tPrefix:    &gnmi.Path{},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tOrigin: \"\",\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"network-instances\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"network-instance\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"name\": \"default\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"protocols\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"protocol\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"name\": \"BGP\", \"identifier\": \"BGP\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"bgp\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"neighbors\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"neighbor\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"neighbor_address\": \"192.0.2.1\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"state\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"description\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tTarget: \"\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_StringVal{StringVal: \"EXAMPLE-PEER\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tif err := server.Send(tagResponse); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif err := server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_SyncResponse{SyncResponse: true}}); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\ttaggedResponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1543236572000000000,\n\t\t\t\t\t\t\t\tPrefix:    &gnmi.Path{},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tOrigin: \"\",\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"network-instances\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"network-instance\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"name\": \"default\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"protocols\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"protocol\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"name\": \"BGP\", \"identifier\": \"BGP\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"bgp\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"neighbors\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"neighbor\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:  map[string]string{\"neighbor_address\": \"192.0.2.1\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"state\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"session-state\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tTarget: \"\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_StringVal{StringVal: \"ESTABLISHED\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\n\t\t\t\t\treturn server.Send(taggedResponse)\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"oc-neigh-state\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":                    \"127.0.0.1\",\n\t\t\t\t\t\t\"neighbor_address\":          \"192.0.2.1\",\n\t\t\t\t\t\t\"name\":                      \"default\",\n\t\t\t\t\t\t\"oc-neigh-desc/description\": \"EXAMPLE-PEER\",\n\t\t\t\t\t\t\"/network-instances/network-instance/protocols/protocol/name\": \"BGP\",\n\t\t\t\t\t\t\"identifier\": \"BGP\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"session_state\": \"ESTABLISHED\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"issue #12257 Arista\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:      testutil.Logger{},\n\t\t\t\tEncoding: \"proto\",\n\t\t\t\tRedial:   config.Duration(1 * time.Second),\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"interfaces\",\n\t\t\t\t\t\tOrigin:           \"openconfig\",\n\t\t\t\t\t\tPath:             \"/interfaces/interface/state/counters\",\n\t\t\t\t\t\tSubscriptionMode: \"sample\",\n\t\t\t\t\t\tSampleInterval:   config.Duration(1 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\tif err := server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_SyncResponse{SyncResponse: true}}); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tresponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1668762813698611837,\n\t\t\t\t\t\t\t\tPrefix: &gnmi.Path{\n\t\t\t\t\t\t\t\t\tOrigin: \"openconfig\",\n\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t{Name: \"interfaces\"},\n\t\t\t\t\t\t\t\t\t\t{Name: \"interface\", Key: map[string]string{\"name\": \"Ethernet1\"}},\n\t\t\t\t\t\t\t\t\t\t{Name: \"state\"},\n\t\t\t\t\t\t\t\t\t\t{Name: \"counters\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tTarget: \"OC-YANG\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"in-broadcast-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"in-discards\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"in-errors\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"in-fcs-errors\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"in-unicast-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-broadcast-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-discards\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-errors\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-multicast-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-octets\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{Elem: []*gnmi.PathElem{{Name: \"out-unicast-pkts\"}}},\n\t\t\t\t\t\t\t\t\t\tVal:  &gnmi.TypedValue{Value: &gnmi.TypedValue_UintVal{UintVal: 0}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn server.Send(response)\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"interfaces\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"openconfig:/interfaces/interface/state/counters\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"name\":   \"Ethernet1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"in_broadcast_pkts\":  uint64(0),\n\t\t\t\t\t\t\"in_discards\":        uint64(0),\n\t\t\t\t\t\t\"in_errors\":          uint64(0),\n\t\t\t\t\t\t\"in_fcs_errors\":      uint64(0),\n\t\t\t\t\t\t\"in_unicast_pkts\":    uint64(0),\n\t\t\t\t\t\t\"out_broadcast_pkts\": uint64(0),\n\t\t\t\t\t\t\"out_discards\":       uint64(0),\n\t\t\t\t\t\t\"out_errors\":         uint64(0),\n\t\t\t\t\t\t\"out_multicast_pkts\": uint64(0),\n\t\t\t\t\t\t\"out_octets\":         uint64(0),\n\t\t\t\t\t\t\"out_pkts\":           uint64(0),\n\t\t\t\t\t\t\"out_unicast_pkts\":   uint64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"issue #12257 Sonic\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:                           testutil.Logger{},\n\t\t\t\tEncoding:                      \"proto\",\n\t\t\t\tRedial:                        config.Duration(1 * time.Second),\n\t\t\t\tEnforceFirstNamespaceAsOrigin: true,\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"temperature\",\n\t\t\t\t\t\tOrigin:           \"openconfig-platform\",\n\t\t\t\t\t\tPath:             \"/components/component[name=TEMP 1]/state\",\n\t\t\t\t\t\tSubscriptionMode: \"sample\",\n\t\t\t\t\t\tSampleInterval:   config.Duration(1 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\tif err := server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_SyncResponse{SyncResponse: true}}); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tresponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1668771585733542546,\n\t\t\t\t\t\t\t\tPrefix: &gnmi.Path{\n\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t{Name: \"openconfig-platform:components\"},\n\t\t\t\t\t\t\t\t\t\t{Name: \"component\", Key: map[string]string{\"name\": \"TEMP 1\"}},\n\t\t\t\t\t\t\t\t\t\t{Name: \"state\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tTarget: \"OC-YANG\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"low-threshold\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_FloatVal{FloatVal: 0},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"timestamp\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_StringVal{StringVal: \"2022-11-18T11:39:26Z\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"warning-status\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_BoolVal{BoolVal: false},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"name\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_StringVal{StringVal: \"CPU On-board\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"critical-high-threshold\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_FloatVal{FloatVal: 94},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"current\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_FloatVal{FloatVal: 29},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"temperature\"},\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"high-threshold\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_FloatVal{FloatVal: 90},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn server.Send(response)\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"temperature\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":   \"openconfig-platform:/components/component/state\",\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"name\":   \"TEMP 1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"temperature/timestamp\":               \"2022-11-18T11:39:26Z\",\n\t\t\t\t\t\t\"temperature/low_threshold\":           float64(0),\n\t\t\t\t\t\t\"temperature/current\":                 float64(29),\n\t\t\t\t\t\t\"temperature/high_threshold\":          float64(90),\n\t\t\t\t\t\t\"temperature/critical_high_threshold\": float64(94),\n\t\t\t\t\t\t\"temperature/warning_status\":          false,\n\t\t\t\t\t\t\"name\":                                \"CPU On-board\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Juniper Extension\",\n\t\t\tplugin: &GNMI{\n\t\t\t\tLog:                           testutil.Logger{},\n\t\t\t\tEncoding:                      \"proto\",\n\t\t\t\tVendorSpecific:                []string{\"juniper_header\"},\n\t\t\t\tRedial:                        config.Duration(1 * time.Second),\n\t\t\t\tEnforceFirstNamespaceAsOrigin: true,\n\t\t\t\tSubscriptions: []subscription{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:             \"type\",\n\t\t\t\t\t\tOrigin:           \"openconfig-platform\",\n\t\t\t\t\t\tPath:             \"/components/component[name=CHASSIS0:FPC0]/state\",\n\t\t\t\t\t\tSubscriptionMode: \"sample\",\n\t\t\t\t\t\tSampleInterval:   config.Duration(1 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tserver: &mockServer{\n\t\t\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\t\tif err := server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_SyncResponse{SyncResponse: true}}); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tresponse := &gnmi.SubscribeResponse{\n\t\t\t\t\t\tResponse: &gnmi.SubscribeResponse_Update{\n\t\t\t\t\t\t\tUpdate: &gnmi.Notification{\n\t\t\t\t\t\t\t\tTimestamp: 1668771585733542546,\n\t\t\t\t\t\t\t\tPrefix: &gnmi.Path{\n\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t{Name: \"openconfig-platform:components\"},\n\t\t\t\t\t\t\t\t\t\t{Name: \"component\", Key: map[string]string{\"name\": \"CHASSIS0:FPC0\"}},\n\t\t\t\t\t\t\t\t\t\t{Name: \"state\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tTarget: \"OC-YANG\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tUpdate: []*gnmi.Update{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPath: &gnmi.Path{\n\t\t\t\t\t\t\t\t\t\t\tElem: []*gnmi.PathElem{\n\t\t\t\t\t\t\t\t\t\t\t\t{Name: \"type\"},\n\t\t\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\t\tVal: &gnmi.TypedValue{\n\t\t\t\t\t\t\t\t\t\t\tValue: &gnmi.TypedValue_StringVal{StringVal: \"LINECARD\"},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExtension: []*gnmi_ext.Extension{{\n\t\t\t\t\t\t\tExt: &gnmi_ext.Extension_RegisteredExt{\n\t\t\t\t\t\t\t\tRegisteredExt: &gnmi_ext.RegisteredExtension{\n\t\t\t\t\t\t\t\t\t// Juniper Header Extension\n\t\t\t\t\t\t\t\t\t// EID_JUNIPER_TELEMETRY_HEADER = 1;\n\t\t\t\t\t\t\t\t\tId: 1,\n\t\t\t\t\t\t\t\t\tMsg: func(jnprExt *jnpr_gnmi_extention.GnmiJuniperTelemetryHeaderExtension) []byte {\n\t\t\t\t\t\t\t\t\t\tb, err := proto.Marshal(jnprExt)\n\t\t\t\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\treturn b\n\t\t\t\t\t\t\t\t\t}(&jnpr_gnmi_extention.GnmiJuniperTelemetryHeaderExtension{ComponentId: 15, SubComponentId: 1, Component: \"PICD\"}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}},\n\t\t\t\t\t}\n\t\t\t\t\treturn server.Send(response)\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"type\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"path\":             \"openconfig-platform:/components/component/state\",\n\t\t\t\t\t\t\"source\":           \"127.0.0.1\",\n\t\t\t\t\t\t\"name\":             \"CHASSIS0:FPC0\",\n\t\t\t\t\t\t\"component_id\":     \"15\",\n\t\t\t\t\t\t\"sub_component_id\": \"1\",\n\t\t\t\t\t\t\"component\":        \"PICD\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"type\": \"LINECARD\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttt.plugin.Addresses = []string{listener.Addr().String()}\n\n\t\t\tgrpcServer := grpc.NewServer()\n\t\t\ttt.server.grpcServer = grpcServer\n\t\t\tgnmi.RegisterGNMIServer(grpcServer, tt.server)\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\t\t\trequire.NoError(t, tt.plugin.Start(&acc))\n\n\t\t\tvar wg sync.WaitGroup\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\t\t\tt.Error(err)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tacc.Wait(len(tt.expected))\n\t\t\ttt.plugin.Stop()\n\t\t\tgrpcServer.Stop()\n\t\t\twg.Wait()\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(),\n\t\t\t\ttestutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRedial(t *testing.T) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tplugin := &GNMI{\n\t\tLog:       testutil.Logger{},\n\t\tAddresses: []string{listener.Addr().String()},\n\t\tEncoding:  \"proto\",\n\t\tRedial:    config.Duration(10 * time.Millisecond),\n\t\tAliases:   map[string]string{\"dummy\": \"type:/model\"},\n\t}\n\n\tgrpcServer := grpc.NewServer()\n\tgnmiServer := &mockServer{\n\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\tnotification := mockGNMINotification()\n\t\t\treturn server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_Update{Update: notification}})\n\t\t},\n\t\tgrpcServer: grpcServer,\n\t}\n\tgnmi.RegisterGNMIServer(grpcServer, gnmiServer)\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tacc.Wait(2)\n\tgrpcServer.Stop()\n\twg.Wait()\n\n\t// Restart gNMI server at the same address\n\tlistener, err = net.Listen(\"tcp\", listener.Addr().String())\n\trequire.NoError(t, err)\n\n\tgrpcServer = grpc.NewServer()\n\tgnmiServer = &mockServer{\n\t\tsubscribeF: func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\tnotification := mockGNMINotification()\n\t\t\tnotification.Prefix.Elem[0].Key[\"foo\"] = \"bar2\"\n\t\t\tnotification.Update[0].Path.Elem[1].Key[\"name\"] = \"str2\"\n\t\t\tnotification.Update[0].Val = &gnmi.TypedValue{Value: &gnmi.TypedValue_BoolVal{BoolVal: false}}\n\t\t\treturn server.Send(&gnmi.SubscribeResponse{Response: &gnmi.SubscribeResponse_Update{Update: notification}})\n\t\t},\n\t\tgrpcServer: grpcServer,\n\t}\n\tgnmi.RegisterGNMIServer(grpcServer, gnmiServer)\n\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}()\n\n\tacc.Wait(4)\n\tplugin.Stop()\n\tgrpcServer.Stop()\n\twg.Wait()\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all testcase directories\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"gnmi\", func() telegraf.Input {\n\t\treturn &GNMI{\n\t\t\tRedial:                        config.Duration(10 * time.Second),\n\t\t\tEnforceFirstNamespaceAsOrigin: true,\n\t\t}\n\t})\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\tinputFilename := filepath.Join(testcasePath, \"responses.json\")\n\t\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t\t// Load the input data\n\t\t\tbuf, err := os.ReadFile(inputFilename)\n\t\t\trequire.NoError(t, err)\n\t\t\tvar entries []json.RawMessage\n\t\t\trequire.NoError(t, json.Unmarshal(buf, &entries))\n\t\t\tresponses := make([]gnmi.SubscribeResponse, len(entries))\n\t\t\tfor i, entry := range entries {\n\t\t\t\trequire.NoError(t, protojson.Unmarshal(entry, &responses[i]))\n\t\t\t}\n\n\t\t\t// Prepare the influx parser for expectations\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Prepare the server response\n\t\t\tresponseFunction := func(server gnmi.GNMI_SubscribeServer) error {\n\t\t\t\tfor i := range responses {\n\t\t\t\t\tif err := server.Send(&responses[i]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Setup a mock server\n\t\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\t\trequire.NoError(t, err)\n\t\t\tgrpcServer := grpc.NewServer()\n\t\t\tgnmiServer := &mockServer{\n\t\t\t\tsubscribeF: responseFunction,\n\t\t\t\tgrpcServer: grpcServer,\n\t\t\t}\n\t\t\tgnmi.RegisterGNMIServer(grpcServer, gnmiServer)\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := cfg.Inputs[0].Input.(*GNMI)\n\t\t\tplugin.Addresses = []string{listener.Addr().String()}\n\t\t\tplugin.Log = testutil.Logger{}\n\n\t\t\t// Start the server\n\t\t\tvar wg sync.WaitGroup\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tif err := grpcServer.Serve(listener); err != nil {\n\t\t\t\t\tt.Error(err)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\n\t\t\trequire.Eventually(t,\n\t\t\t\tfunc() bool {\n\t\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t\t}, 15*time.Second, 100*time.Millisecond)\n\t\t\tplugin.Stop()\n\t\t\tgrpcServer.Stop()\n\t\t\twg.Wait()\n\n\t\t\t// Check for errors\n\t\t\trequire.Len(t, acc.Errors, len(expectedErrors))\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tactualErrorMsgs := make([]string, 0, len(acc.Errors))\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\t\t\t}\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/handler.go",
    "content": "package gnmi\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/openconfig/gnmi/proto/gnmi\"\n\t\"github.com/openconfig/gnmi/proto/gnmi_ext\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/keepalive\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/yangmodel\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/gnmi/extensions/jnpr_gnmi_extention\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\nconst eidJuniperTelemetryHeader = 1\n\ntype handler struct {\n\thost                          string\n\tport                          string\n\taliases                       map[*pathInfo]string\n\ttagsubs                       []tagSubscription\n\tmaxMsgSize                    int\n\temptyNameWarnShown            bool\n\tvendorExt                     []string\n\temitDeleteMetrics             bool\n\ttagStore                      *tagStore\n\ttrace                         bool\n\tcanonicalFieldNames           bool\n\ttrimSlash                     bool\n\ttagPathPrefix                 bool\n\tguessPathStrategy             string\n\tdecoder                       *yangmodel.Decoder\n\tenforceFirstNamespaceAsOrigin bool\n\tlog                           telegraf.Logger\n\tkeepalive.ClientParameters\n}\n\n// SubscribeGNMI and extract telemetry data\nfunc (h *handler) subscribeGNMI(ctx context.Context, acc telegraf.Accumulator, tlscfg *tls.Config, request *gnmi.SubscribeRequest) error {\n\tvar creds credentials.TransportCredentials\n\tif tlscfg != nil {\n\t\tcreds = credentials.NewTLS(tlscfg)\n\t} else {\n\t\tcreds = insecure.NewCredentials()\n\t}\n\topts := []grpc.DialOption{\n\t\tgrpc.WithTransportCredentials(creds),\n\t}\n\n\tif h.maxMsgSize > 0 {\n\t\topts = append(opts, grpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallRecvMsgSize(h.maxMsgSize),\n\t\t))\n\t}\n\n\tif h.ClientParameters.Time > 0 {\n\t\topts = append(opts, grpc.WithKeepaliveParams(h.ClientParameters))\n\t}\n\n\t// Used to report the status of the TCP connection to the device. If the\n\t// GNMI connection goes down, but TCP is still up this will still report\n\t// connected until the TCP connection times out.\n\tconnectStat := selfstat.Register(\"gnmi\", \"grpc_connection_status\", map[string]string{\"source\": h.host})\n\tdefer connectStat.Set(0)\n\n\taddress := net.JoinHostPort(h.host, h.port)\n\tclient, err := grpc.NewClient(address, opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dial: %w\", err)\n\t}\n\tdefer client.Close()\n\n\tsubscribeClient, err := gnmi.NewGNMIClient(client).Subscribe(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to setup subscription: %w\", err)\n\t}\n\n\t// If io.EOF is returned, the stream may have ended and stream status\n\t// can be determined by calling Recv.\n\tif err := subscribeClient.Send(request); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn fmt.Errorf(\"failed to send subscription request: %w\", err)\n\t}\n\tconnectStat.Set(1)\n\th.log.Debugf(\"Connection to gNMI device %s established\", address)\n\n\tdefer h.log.Debugf(\"Connection to gNMI device %s closed\", address)\n\tfor ctx.Err() == nil {\n\t\tvar reply *gnmi.SubscribeResponse\n\t\tif reply, err = subscribeClient.Recv(); err != nil {\n\t\t\tif !errors.Is(err, io.EOF) && ctx.Err() == nil {\n\t\t\t\treturn fmt.Errorf(\"aborted gNMI subscription: %w\", err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif h.trace {\n\t\t\tbuf, err := protojson.Marshal(reply)\n\t\t\tif err != nil {\n\t\t\t\th.log.Debugf(\"Marshal failed: %v\", err)\n\t\t\t} else {\n\t\t\t\tt := reply.GetUpdate().GetTimestamp()\n\t\t\t\th.log.Debugf(\"Got update_%v: %s\", t, string(buf))\n\t\t\t}\n\t\t}\n\n\t\tresponse, ok := reply.Response.(*gnmi.SubscribeResponse_Update)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Extract the metadata\n\t\ttimestamp, tags, prefix := h.handleUpdateMetadata(response.Update, reply.GetExtension())\n\n\t\t// Handle \"update\" notifications contained in the response\n\t\th.handleUpdates(acc, response.Update.Update, timestamp, tags, prefix)\n\n\t\t// Handle \"delete\" notifications contained in the response if requested\n\t\tif h.emitDeleteMetrics {\n\t\t\th.handleDeletes(acc, response.Update.Delete, timestamp, tags, prefix)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (h *handler) handleUpdateMetadata(notification *gnmi.Notification, extension []*gnmi_ext.Extension) (time.Time, map[string]string, *pathInfo) {\n\ttimestamp := time.Unix(0, notification.Timestamp)\n\n\t// Extract tags from potential extension in the update notification\n\theaderTags := map[string]string{\"source\": h.host}\n\n\tfor _, ext := range extension {\n\t\tcurrentExt := ext.GetRegisteredExt().Msg\n\t\tif currentExt == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tswitch ext.GetRegisteredExt().Id {\n\t\tcase eidJuniperTelemetryHeader:\n\t\t\t// Juniper Header extension\n\t\t\t// Decode it only if user requested it\n\t\t\tif choice.Contains(\"juniper_header\", h.vendorExt) {\n\t\t\t\tjuniperHeader := &jnpr_gnmi_extention.GnmiJuniperTelemetryHeaderExtension{}\n\t\t\t\tif err := proto.Unmarshal(currentExt, juniperHeader); err != nil {\n\t\t\t\t\th.log.Errorf(\"unmarshal gnmi Juniper Header extension failed: %v\", err)\n\t\t\t\t} else {\n\t\t\t\t\t// Add only relevant Tags from the Juniper Header extension.\n\t\t\t\t\t// These are required for aggregation\n\t\t\t\t\theaderTags[\"component_id\"] = strconv.FormatUint(uint64(juniperHeader.GetComponentId()), 10)\n\t\t\t\t\theaderTags[\"component\"] = juniperHeader.GetComponent()\n\t\t\t\t\theaderTags[\"sub_component_id\"] = strconv.FormatUint(uint64(juniperHeader.GetSubComponentId()), 10)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n\n\t// Extract the path part valid for the whole set of updates if any\n\tprefix := newInfoFromPath(notification.Prefix)\n\tif h.enforceFirstNamespaceAsOrigin {\n\t\tprefix.enforceFirstNamespaceAsOrigin()\n\t}\n\treturn timestamp, headerTags, prefix\n}\n\n// Handle SubscribeResponse_Update message from gNMI and parse contained telemetry data\nfunc (h *handler) handleUpdates(acc telegraf.Accumulator, updates []*gnmi.Update, timestamp time.Time, headerTags map[string]string, prefix *pathInfo) {\n\tgrouper := metric.NewSeriesGrouper()\n\n\t// Process and remove tag-updates from the response first so we can\n\t// add all available tags to the metrics later.\n\tvar valueFields []updateField\n\tfor _, update := range updates {\n\t\tif update.Path == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(update.Path.Elem) == 0 && prefix.empty() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfullPath := prefix.append(update.Path)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\tprefix.enforceFirstNamespaceAsOrigin()\n\t\t}\n\t\tif update.Path.Origin != \"\" {\n\t\t\tfullPath.origin = update.Path.Origin\n\t\t}\n\n\t\tfields, err := h.newFieldsFromUpdate(fullPath, update)\n\t\tif err != nil {\n\t\t\th.log.Errorf(\"Processing update %v failed: %v\", update, err)\n\t\t}\n\n\t\t// Prepare tags from prefix\n\t\ttags := make(map[string]string, len(headerTags))\n\t\tfor key, val := range headerTags {\n\t\t\ttags[key] = val\n\t\t}\n\t\tfor key, val := range fullPath.tags(h.tagPathPrefix) {\n\t\t\ttags[key] = val\n\t\t}\n\n\t\t// TODO: Handle each field individually to allow in-JSON tags\n\t\tvar tagUpdate bool\n\t\tfor _, tagSub := range h.tagsubs {\n\t\t\tif !fullPath.equalsPathNoKeys(tagSub.fullPath) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\th.log.Debugf(\"Tag-subscription update for %q: %+v\", tagSub.Name, update)\n\t\t\tif err := h.tagStore.insert(tagSub, fullPath, fields, tags); err != nil {\n\t\t\t\th.log.Errorf(\"Inserting tag failed: %v\", err)\n\t\t\t}\n\t\t\ttagUpdate = true\n\t\t\tbreak\n\t\t}\n\t\tif !tagUpdate {\n\t\t\tvalueFields = append(valueFields, fields...)\n\t\t}\n\t}\n\n\t// Some devices do not provide a prefix, so do some guesswork based\n\t// on the paths of the fields\n\tvar path string\n\tif !prefix.empty() {\n\t\tpath = prefix.fullPath()\n\t} else if h.guessPathStrategy == \"common path\" {\n\t\tpaths := make([]*pathInfo, 0, len(valueFields))\n\t\tfor _, f := range valueFields {\n\t\t\tpaths = append(paths, f.path)\n\t\t}\n\t\tif prefixPath := guessPrefix(paths); prefixPath != \"\" {\n\t\t\tpath = prefixPath\n\t\t}\n\t}\n\n\t// Parse individual update message and create measurements\n\tfor _, field := range valueFields {\n\t\tif field.path.empty() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Prepare tags from prefix\n\t\tfieldTags := field.path.tags(h.tagPathPrefix)\n\t\ttags := make(map[string]string, len(headerTags)+len(fieldTags))\n\t\tfor key, val := range headerTags {\n\t\t\ttags[key] = val\n\t\t}\n\t\tif path != \"\" {\n\t\t\ttags[\"path\"] = path\n\t\t}\n\t\tfor key, val := range fieldTags {\n\t\t\ttags[key] = val\n\t\t}\n\n\t\t// Add the tags derived via tag-subscriptions\n\t\tfor k, v := range h.tagStore.lookup(field.path, tags) {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\t// Lookup alias for the metric\n\t\taliasPath, name := h.lookupAlias(field.path)\n\t\tif name == \"\" {\n\t\t\th.log.Debugf(\"No measurement alias for gNMI path: %s\", field.path)\n\t\t\tif !h.emptyNameWarnShown {\n\t\t\t\tif buf, err := json.Marshal(updates); err == nil {\n\t\t\t\t\th.log.Warnf(emptyNameWarning, field.path, string(buf))\n\t\t\t\t} else {\n\t\t\t\t\th.log.Warnf(emptyNameWarning, field.path, updates)\n\t\t\t\t}\n\t\t\t\th.emptyNameWarnShown = true\n\t\t\t}\n\t\t}\n\n\t\taliasInfo := newInfoFromString(aliasPath)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\taliasInfo.enforceFirstNamespaceAsOrigin()\n\t\t}\n\n\t\tif tags[\"path\"] == \"\" && h.guessPathStrategy == \"subscription\" {\n\t\t\ttags[\"path\"] = aliasInfo.String()\n\t\t}\n\n\t\t// Group metrics\n\t\tvar key string\n\t\tif h.canonicalFieldNames {\n\t\t\t// Strip the origin is any for the field names\n\t\t\tfield.path.origin = \"\"\n\t\t\tkey = field.path.String()\n\t\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\t\t} else {\n\t\t\t// If the alias is a subpath of the field path and the alias is\n\t\t\t// shorter than the full path to avoid an empty key, then strip the\n\t\t\t// common part of the field is prefixed with the alias path. Note\n\t\t\t// the origins can match or be empty and be considered equal.\n\t\t\tif relative := aliasInfo.relative(field.path, true); relative != \"\" {\n\t\t\t\tkey = relative\n\t\t\t} else {\n\t\t\t\t// Otherwise use the last path element as the field key\n\t\t\t\tkey = field.path.base()\n\t\t\t}\n\t\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\t\t}\n\t\tif h.trimSlash {\n\t\t\tkey = strings.TrimLeft(key, \"/.\")\n\t\t}\n\t\tif key == \"\" {\n\t\t\th.log.Errorf(\"Invalid empty path %q with alias %q\", field.path.String(), aliasPath)\n\t\t\tcontinue\n\t\t}\n\t\tgrouper.Add(name, tags, timestamp, key, field.value)\n\t}\n\n\t// Add grouped measurements\n\tfor _, metricToAdd := range grouper.Metrics() {\n\t\tacc.AddMetric(metricToAdd)\n\t}\n}\n\nfunc (h *handler) handleDeletes(acc telegraf.Accumulator, deletes []*gnmi.Path, timestamp time.Time, headerTags map[string]string, prefix *pathInfo) {\n\tpaths := make([]*pathInfo, 0, len(deletes))\n\tfor _, del := range deletes {\n\t\tif del == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(del.Elem) == 0 && prefix.empty() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfullPath := prefix.append(del)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\tprefix.enforceFirstNamespaceAsOrigin()\n\t\t}\n\t\tif del.Origin != \"\" {\n\t\t\tfullPath.origin = del.Origin\n\t\t}\n\t\tpaths = append(paths, fullPath)\n\t}\n\n\t// Some devices do not provide a prefix, so do some guesswork based\n\t// on the paths of the fields\n\tvar path string\n\tif !prefix.empty() {\n\t\tpath = prefix.fullPath()\n\t} else if h.guessPathStrategy == \"common path\" {\n\t\tif prefixPath := guessPrefix(paths); prefixPath != \"\" {\n\t\t\tpath = prefixPath\n\t\t}\n\t}\n\n\t// Parse individual update message and create measurements\n\tfor _, field := range paths {\n\t\tif field.empty() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Prepare tags from prefix\n\t\tfieldTags := field.tags(h.tagPathPrefix)\n\t\ttags := make(map[string]string, len(headerTags)+len(fieldTags)+1)\n\t\tfor key, val := range headerTags {\n\t\t\ttags[key] = val\n\t\t}\n\t\tif path != \"\" {\n\t\t\ttags[\"path\"] = path\n\t\t}\n\t\tfor key, val := range fieldTags {\n\t\t\ttags[key] = val\n\t\t}\n\n\t\t// Add the tags derived via tag-subscriptions\n\t\tfor k, v := range h.tagStore.lookup(field, tags) {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\t// Lookup alias for the metric\n\t\taliasPath, name := h.lookupAlias(field)\n\t\tif name == \"\" {\n\t\t\th.log.Debugf(\"No measurement alias for gNMI path: %s\", field)\n\t\t\tif !h.emptyNameWarnShown {\n\t\t\t\tif buf, err := json.Marshal(deletes); err == nil {\n\t\t\t\t\th.log.Warnf(emptyNameWarning, field, string(buf))\n\t\t\t\t} else {\n\t\t\t\t\th.log.Warnf(emptyNameWarning, field, deletes)\n\t\t\t\t}\n\t\t\t\th.emptyNameWarnShown = true\n\t\t\t}\n\t\t}\n\n\t\taliasInfo := newInfoFromString(aliasPath)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\taliasInfo.enforceFirstNamespaceAsOrigin()\n\t\t}\n\n\t\tif tags[\"path\"] == \"\" && h.guessPathStrategy == \"subscription\" {\n\t\t\ttags[\"path\"] = aliasInfo.String()\n\t\t}\n\n\t\tfields := map[string]interface{}{\"operation\": \"delete\"}\n\t\tacc.AddFields(name, fields, tags, timestamp)\n\t}\n}\n\n// Try to find the alias for the given path\ntype aliasCandidate struct {\n\tpath, alias string\n}\n\nfunc (h *handler) lookupAlias(info *pathInfo) (aliasPath, alias string) {\n\tcandidates := make([]aliasCandidate, 0, len(h.aliases))\n\tfor i, a := range h.aliases {\n\t\tif !i.isSubPathOf(info) {\n\t\t\tcontinue\n\t\t}\n\t\tcandidates = append(candidates, aliasCandidate{i.String(), a})\n\t}\n\tif len(candidates) == 0 {\n\t\treturn \"\", \"\"\n\t}\n\n\t// Reverse sort the candidates by path length so we can use the longest match\n\tsort.SliceStable(candidates, func(i, j int) bool {\n\t\treturn len(candidates[i].path) > len(candidates[j].path)\n\t})\n\n\treturn candidates[0].path, candidates[0].alias\n}\n\nfunc guessPrefix(paths []*pathInfo) string {\n\tif len(paths) == 0 {\n\t\treturn \"\"\n\t}\n\tif len(paths) == 1 {\n\t\treturn paths[0].dir()\n\t}\n\tsegments := make([]segment, 0, len(paths[0].segments))\n\tcommonPath := &pathInfo{\n\t\torigin:   paths[0].origin,\n\t\tsegments: append(segments, paths[0].segments...),\n\t}\n\tfor _, f := range paths[1:] {\n\t\tcommonPath.keepCommonPart(f)\n\t}\n\tif commonPath.empty() {\n\t\treturn \"\"\n\t}\n\treturn commonPath.String()\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/path.go",
    "content": "package gnmi\n\nimport (\n\t\"strings\"\n\n\t\"github.com/openconfig/gnmi/proto/gnmi\"\n)\n\ntype keySegment struct {\n\tname string\n\tpath string\n\tkv   map[string]string\n}\n\ntype segment struct {\n\tnamespace string\n\tid        string\n}\n\ntype pathInfo struct {\n\torigin    string\n\ttarget    string\n\tsegments  []segment\n\tkeyValues []keySegment\n}\n\nfunc newInfoFromString(path string) *pathInfo {\n\tif path == \"\" {\n\t\treturn &pathInfo{}\n\t}\n\n\tparts := strings.Split(path, \"/\")\n\n\tvar origin string\n\tif strings.HasSuffix(parts[0], \":\") {\n\t\torigin = strings.TrimSuffix(parts[0], \":\")\n\t\tparts = parts[1:]\n\t}\n\n\tinfo := &pathInfo{origin: origin}\n\tfor _, part := range parts {\n\t\tif part == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tinfo.segments = append(info.segments, segment{id: part})\n\t}\n\tinfo.normalize()\n\n\treturn info\n}\n\nfunc newInfoFromPathWithoutKeys(path *gnmi.Path) *pathInfo {\n\tinfo := &pathInfo{\n\t\torigin:   path.Origin,\n\t\tsegments: make([]segment, 0, len(path.Elem)),\n\t}\n\tfor _, elem := range path.Elem {\n\t\tif elem.Name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tinfo.segments = append(info.segments, segment{id: elem.Name})\n\t}\n\tinfo.normalize()\n\n\treturn info\n}\n\nfunc newInfoFromPath(paths ...*gnmi.Path) *pathInfo {\n\tif len(paths) == 0 {\n\t\treturn nil\n\t}\n\n\tinfo := &pathInfo{}\n\tif paths[0] != nil {\n\t\tinfo.origin = paths[0].Origin\n\t\tinfo.target = paths[0].Target\n\t}\n\n\tfor _, p := range paths {\n\t\tif p == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, elem := range p.Elem {\n\t\t\tif elem.Name != \"\" {\n\t\t\t\tinfo.segments = append(info.segments, segment{id: elem.Name})\n\t\t\t}\n\n\t\t\tif len(elem.Key) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkeyInfo := keySegment{\n\t\t\t\tname: elem.Name,\n\t\t\t\tpath: info.String(),\n\t\t\t\tkv:   make(map[string]string, len(elem.Key)),\n\t\t\t}\n\t\t\tfor k, v := range elem.Key {\n\t\t\t\tkeyInfo.kv[k] = v\n\t\t\t}\n\t\t\tinfo.keyValues = append(info.keyValues, keyInfo)\n\t\t}\n\t}\n\tinfo.normalize()\n\n\treturn info\n}\n\nfunc (pi *pathInfo) empty() bool {\n\treturn len(pi.segments) == 0\n}\n\nfunc (pi *pathInfo) append(paths ...*gnmi.Path) *pathInfo {\n\t// Copy the existing info\n\tsegments := make([]segment, 0, len(pi.segments))\n\tpath := &pathInfo{\n\t\torigin:    pi.origin,\n\t\ttarget:    pi.target,\n\t\tsegments:  append(segments, pi.segments...),\n\t\tkeyValues: make([]keySegment, 0, len(pi.keyValues)),\n\t}\n\tfor _, elem := range pi.keyValues {\n\t\tkeyInfo := keySegment{\n\t\t\tname: elem.name,\n\t\t\tpath: elem.path,\n\t\t\tkv:   make(map[string]string, len(elem.kv)),\n\t\t}\n\t\tfor k, v := range elem.kv {\n\t\t\tkeyInfo.kv[k] = v\n\t\t}\n\t\tpath.keyValues = append(path.keyValues, keyInfo)\n\t}\n\n\t// Add the new segments\n\tfor _, p := range paths {\n\t\tfor _, elem := range p.Elem {\n\t\t\tif elem.Name != \"\" {\n\t\t\t\tpath.segments = append(path.segments, segment{id: elem.Name})\n\t\t\t}\n\n\t\t\tif len(elem.Key) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkeyInfo := keySegment{\n\t\t\t\tname: elem.Name,\n\t\t\t\tpath: path.String(),\n\t\t\t\tkv:   make(map[string]string, len(elem.Key)),\n\t\t\t}\n\t\t\tfor k, v := range elem.Key {\n\t\t\t\tkeyInfo.kv[k] = v\n\t\t\t}\n\t\t\tpath.keyValues = append(path.keyValues, keyInfo)\n\t\t}\n\t}\n\tpath.normalize()\n\n\treturn path\n}\n\nfunc (pi *pathInfo) appendSegments(segments ...string) *pathInfo {\n\t// Copy the existing info\n\tseg := make([]segment, 0, len(segments))\n\tpath := &pathInfo{\n\t\torigin:    pi.origin,\n\t\ttarget:    pi.target,\n\t\tsegments:  append(seg, pi.segments...),\n\t\tkeyValues: make([]keySegment, 0, len(pi.keyValues)),\n\t}\n\tfor _, elem := range pi.keyValues {\n\t\tkeyInfo := keySegment{\n\t\t\tname: elem.name,\n\t\t\tpath: elem.path,\n\t\t\tkv:   make(map[string]string, len(elem.kv)),\n\t\t}\n\t\tfor k, v := range elem.kv {\n\t\t\tkeyInfo.kv[k] = v\n\t\t}\n\t\tpath.keyValues = append(path.keyValues, keyInfo)\n\t}\n\n\t// Add the new segments\n\tfor _, s := range segments {\n\t\tif s == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tpath.segments = append(path.segments, segment{id: s})\n\t}\n\tpath.normalize()\n\n\treturn path\n}\n\nfunc (pi *pathInfo) normalize() {\n\tif len(pi.segments) == 0 {\n\t\treturn\n\t}\n\n\t// Extract namespaces from segments\n\tfor i, s := range pi.segments {\n\t\tif ns, id, found := strings.Cut(s.id, \":\"); found && strings.Count(s.id, \":\") == 1 {\n\t\t\tpi.segments[i].namespace = ns\n\t\t\tpi.segments[i].id = id\n\t\t}\n\t}\n\n\t// Remove empty segments\n\tsegments := make([]segment, 0, len(pi.segments))\n\tfor _, s := range pi.segments {\n\t\tif s.id != \"\" {\n\t\t\tsegments = append(segments, s)\n\t\t}\n\t}\n\tpi.segments = segments\n}\n\nfunc (pi *pathInfo) enforceFirstNamespaceAsOrigin() {\n\tif len(pi.segments) == 0 {\n\t\treturn\n\t}\n\n\t// Some devices supply the origin as part of the first path element,\n\t// so try to find and extract it there.\n\tif pi.segments[0].namespace != \"\" {\n\t\tpi.origin = pi.segments[0].namespace\n\t\tpi.segments[0].namespace = \"\"\n\t}\n}\n\nfunc (pi *pathInfo) equalsPathNoKeys(path *gnmi.Path) bool {\n\tif len(pi.segments) != len(path.Elem) {\n\t\treturn false\n\t}\n\tfor i, s := range pi.segments {\n\t\tif s.id != path.Elem[i].Name {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (pi *pathInfo) isSubPathOf(path *pathInfo) bool {\n\t// If both set an origin it has to match. Otherwise we ignore the origin\n\tif pi.origin != \"\" && path.origin != \"\" && pi.origin != path.origin {\n\t\treturn false\n\t}\n\n\t// The \"parent\" path should have the same length or be shorter than the\n\t// sub-path to have a chance to match\n\tif len(pi.segments) > len(path.segments) {\n\t\treturn false\n\t}\n\n\t// Compare the elements and exit if we find a mismatch\n\tfor i, p := range pi.segments {\n\t\tps := path.segments[i]\n\t\tif p.namespace != \"\" && ps.namespace != \"\" && p.namespace != ps.namespace {\n\t\t\treturn false\n\t\t}\n\t\tif p.id != ps.id {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (pi *pathInfo) relative(path *pathInfo, withNamespace bool) string {\n\tif !pi.isSubPathOf(path) || len(pi.segments) == len(path.segments) {\n\t\treturn \"\"\n\t}\n\n\tsegments := path.segments[len(pi.segments):len(path.segments)]\n\tvar b strings.Builder\n\tif withNamespace && segments[0].namespace != \"\" {\n\t\tb.WriteString(segments[0].namespace)\n\t\tb.WriteString(\":\")\n\t\tb.WriteString(segments[0].id)\n\t} else {\n\t\tb.WriteString(segments[0].id)\n\t}\n\tfor _, s := range segments[1:] {\n\t\tb.WriteString(\"/\")\n\t\tif withNamespace && s.namespace != \"\" {\n\t\t\tb.WriteString(s.namespace)\n\t\t\tb.WriteString(\":\")\n\t\t\tb.WriteString(s.id)\n\t\t} else {\n\t\t\tb.WriteString(s.id)\n\t\t}\n\t}\n\treturn b.String()\n}\n\nfunc (pi *pathInfo) keepCommonPart(path *pathInfo) {\n\tshortestLen := len(pi.segments)\n\tif len(path.segments) < shortestLen {\n\t\tshortestLen = len(path.segments)\n\t}\n\n\t// Compare the elements and stop as soon as they do mismatch\n\tvar matchLen int\n\tfor i, p := range pi.segments[:shortestLen] {\n\t\tif p != path.segments[i] {\n\t\t\tbreak\n\t\t}\n\t\tmatchLen = i + 1\n\t}\n\tif matchLen < 1 {\n\t\tpi.segments = nil\n\t\treturn\n\t}\n\tpi.segments = pi.segments[:matchLen]\n}\n\nfunc (pi *pathInfo) dir() string {\n\tif len(pi.segments) <= 1 {\n\t\treturn \"\"\n\t}\n\n\tvar b strings.Builder\n\tif pi.origin != \"\" {\n\t\tb.WriteString(pi.origin)\n\t\tb.WriteString(\":\")\n\t}\n\tfor _, s := range pi.segments[:len(pi.segments)-1] {\n\t\tb.WriteString(\"/\")\n\t\tif s.namespace != \"\" {\n\t\t\tb.WriteString(s.namespace)\n\t\t\tb.WriteString(\":\")\n\t\t\tb.WriteString(s.id)\n\t\t} else {\n\t\t\tb.WriteString(s.id)\n\t\t}\n\t}\n\treturn b.String()\n}\n\nfunc (pi *pathInfo) base() string {\n\tif len(pi.segments) == 0 {\n\t\treturn \"\"\n\t}\n\n\ts := pi.segments[len(pi.segments)-1]\n\tif s.namespace != \"\" {\n\t\treturn s.namespace + \":\" + s.id\n\t}\n\treturn s.id\n}\n\nfunc (pi *pathInfo) path() (origin, path string) {\n\tif len(pi.segments) == 0 {\n\t\treturn pi.origin, \"/\"\n\t}\n\n\tvar b strings.Builder\n\tfor _, s := range pi.segments {\n\t\tb.WriteString(\"/\")\n\t\tb.WriteString(s.id)\n\t}\n\n\treturn pi.origin, b.String()\n}\n\nfunc (pi *pathInfo) fullPath() string {\n\tvar b strings.Builder\n\tif pi.origin != \"\" {\n\t\tb.WriteString(pi.origin)\n\t\tb.WriteString(\":\")\n\t}\n\tif len(pi.segments) == 0 {\n\t\treturn b.String()\n\t}\n\n\tfor _, s := range pi.segments {\n\t\tb.WriteString(\"/\")\n\t\tif s.namespace != \"\" {\n\t\t\tb.WriteString(s.namespace)\n\t\t\tb.WriteString(\":\")\n\t\t\tb.WriteString(s.id)\n\t\t} else {\n\t\t\tb.WriteString(s.id)\n\t\t}\n\t}\n\n\treturn b.String()\n}\n\nfunc (pi *pathInfo) String() string {\n\tif len(pi.segments) == 0 {\n\t\treturn \"\"\n\t}\n\n\torigin, path := pi.path()\n\tvar b strings.Builder\n\tif origin != \"\" {\n\t\tb.WriteString(origin)\n\t\tb.WriteString(\":\")\n\t}\n\tb.WriteString(path)\n\treturn b.String()\n}\n\nfunc (pi *pathInfo) tags(pathPrefix bool) map[string]string {\n\ttags := make(map[string]string, len(pi.keyValues))\n\tfor _, s := range pi.keyValues {\n\t\tvar prefix string\n\t\tif pathPrefix && s.name != \"\" {\n\t\t\tprefix = s.name + \"_\"\n\t\t}\n\t\t// precompute constant path prefix for this keySegment\n\t\tpathPrefixStr := s.path + \"/\"\n\n\t\tfor k, v := range s.kv {\n\t\t\t// build the key (prefix + k) and sanitize in one builder\n\t\t\tvar kb strings.Builder\n\t\t\tkb.WriteString(prefix)\n\t\t\tkb.WriteString(k)\n\t\t\tkey := strings.ReplaceAll(kb.String(), \"-\", \"_\")\n\n\t\t\t// Use short-form of key if possible\n\t\t\tif _, exists := tags[key]; !exists {\n\t\t\t\ttags[key] = v\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// build full path/key only when needed\n\t\t\tvar fb strings.Builder\n\t\t\tfb.WriteString(pathPrefixStr)\n\t\t\tfb.WriteString(key)\n\t\t\ttags[fb.String()] = v\n\t\t}\n\t}\n\n\treturn tags\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/sample.conf",
    "content": "# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Keepalive settings\n  ## See https://pkg.go.dev/google.golang.org/grpc/keepalive\n  ## The client will ping the server to see if the transport is still alive if it has\n  ## not see any activity for the given time.\n  ## If not set, none of the keep-alive setting (including those below) will be applied.\n  ## If set and set below 10 seconds, the gRPC library will apply a minimum value of 10s will be used instead.\n  # keepalive_time = \"\"\n\n  ## Timeout for seeing any activity after the keep-alive probe was\n  ## sent. If no activity is seen the connection is closed.\n  # keepalive_timeout = \"\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Subtree depth for depth extension (disables if < 1)\n  ## see https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-depth.md\n  # depth = 0\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Only receive updates for the state, also suppresses receiving the initial state\n  # updates_only = false\n\n  ## Emit a metric for \"delete\" messages\n  # emit_delete_metrics = false\n\n  ## Enforces the namespace of the first element as origin for aliases and\n  ## response paths, required for backward compatibility.\n  ## NOTE: Set to 'false' if possible but be aware that this might change the path tag!\n  # enforce_first_namespace_as_origin = true\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## Supported values are\n  ##   none         -- do not add a 'path' tag\n  ##   common path  -- use the common path elements of all fields in an update\n  ##   subscription -- use the subscription path\n  # path_guessing_strategy = \"none\"\n\n  ## Prefix tags from path keys with the path element\n  # prefix_tag_key_with_path = false\n\n  ## Optional client-side TLS to authenticate the device\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## YANG model paths for decoding IETF JSON payloads\n  ## Model files are loaded recursively from the given directories. Disabled if\n  ## no models are specified.\n  # yang_model_paths = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]\n"
  },
  {
    "path": "plugins/inputs/gnmi/sample.conf.in",
    "content": "# gNMI telemetry input plugin\n[[inputs.gnmi]]\n  ## Address and port of the gNMI GRPC server\n  addresses = [\"10.49.234.114:57777\"]\n\n  ## define credentials\n  username = \"cisco\"\n  password = \"cisco\"\n\n  ## gNMI encoding requested (one of: \"proto\", \"json\", \"json_ietf\", \"bytes\")\n  # encoding = \"proto\"\n\n  ## redial in case of failures after\n  # redial = \"10s\"\n\n  ## gRPC Keepalive settings\n  ## See https://pkg.go.dev/google.golang.org/grpc/keepalive\n  ## The client will ping the server to see if the transport is still alive if it has\n  ## not see any activity for the given time.\n  ## If not set, none of the keep-alive setting (including those below) will be applied.\n  ## If set and set below 10 seconds, the gRPC library will apply a minimum value of 10s will be used instead.\n  # keepalive_time = \"\"\n\n  ## Timeout for seeing any activity after the keep-alive probe was\n  ## sent. If no activity is seen the connection is closed.\n  # keepalive_timeout = \"\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Subtree depth for depth extension (disables if < 1)\n  ## see https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-depth.md\n  # depth = 0\n\n  ## Enable to get the canonical path as field-name\n  # canonical_field_names = false\n\n  ## Remove leading slashes and dots in field-name\n  # trim_field_names = false\n\n  ## Only receive updates for the state, also suppresses receiving the initial state\n  # updates_only = false\n\n  ## Emit a metric for \"delete\" messages\n  # emit_delete_metrics = false\n\n  ## Enforces the namespace of the first element as origin for aliases and\n  ## response paths, required for backward compatibility.\n  ## NOTE: Set to 'false' if possible but be aware that this might change the path tag!\n  # enforce_first_namespace_as_origin = true\n\n  ## Guess the path-tag if an update does not contain a prefix-path\n  ## Supported values are\n  ##   none         -- do not add a 'path' tag\n  ##   common path  -- use the common path elements of all fields in an update\n  ##   subscription -- use the subscription path\n  # path_guessing_strategy = \"none\"\n\n  ## Prefix tags from path keys with the path element\n  # prefix_tag_key_with_path = false\n\n  ## Optional client-side TLS to authenticate the device\n{{template \"/plugins/common/tls/client.conf\"}}\n\n  ## gNMI subscription prefix (optional, can usually be left empty)\n  ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n  # origin = \"\"\n  # prefix = \"\"\n  # target = \"\"\n\n  ## Vendor specific options\n  ## This defines what vendor specific options to load.\n  ## * Juniper Header Extension (juniper_header): some sensors are directly managed by\n  ##   Linecard, which adds the Juniper GNMI Header Extension. Enabling this\n  ##   allows the decoding of the Extension header if present. Currently this knob\n  ##   adds component, component_id & sub_component_id as additional tags\n  # vendor_specific = []\n\n  ## YANG model paths for decoding IETF JSON payloads\n  ## Model files are loaded recursively from the given directories. Disabled if\n  ## no models are specified.\n  # yang_model_paths = []\n\n  ## Define additional aliases to map encoding paths to measurement names\n  # [inputs.gnmi.aliases]\n  #   ifcounters = \"openconfig:/interfaces/interface/state/counters\"\n\n  [[inputs.gnmi.subscription]]\n    ## Name of the measurement that will be emitted\n    name = \"ifcounters\"\n\n    ## Origin and path of the subscription\n    ## See: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#222-paths\n    ##\n    ## origin usually refers to a (YANG) data model implemented by the device\n    ## and path to a specific substructure inside it that should be subscribed\n    ## to (similar to an XPath). YANG models can be found e.g. here:\n    ## https://github.com/YangModels/yang/tree/master/vendor/cisco/xr\n    origin = \"openconfig-interfaces\"\n    path = \"/interfaces/interface/state/counters\"\n\n    ## Subscription mode (\"target_defined\", \"sample\", \"on_change\") and interval\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n    ## Suppress redundant transmissions when measured values are unchanged\n    # suppress_redundant = false\n\n    ## If suppression is enabled, send updates at least every X seconds anyway\n    # heartbeat_interval = \"60s\"\n\n  ## Tag subscriptions are applied as tags to other subscriptions.\n  # [[inputs.gnmi.tag_subscription]]\n  #  ## When applying this value as a tag to other metrics, use this tag name\n  #  name = \"descr\"\n  #\n  #  ## All other subscription fields are as normal\n  #  origin = \"openconfig-interfaces\"\n  #  path = \"/interfaces/interface/state\"\n  #  subscription_mode = \"on_change\"\n  #\n  #  ## Match strategy to use for the tag.\n  #  ## Tags are only applied for metrics of the same address. The following\n  #  ## settings are valid:\n  #  ##   unconditional -- always match\n  #  ##   name          -- match by the \"name\" key\n  #  ##                    This resembles the previous 'tag-only' behavior.\n  #  ##   elements      -- match by the keys in the path filtered by the path\n  #  ##                    parts specified `elements` below\n  #  ## By default, 'elements' is used if the 'elements' option is provided,\n  #  ## otherwise match by 'name'.\n  #  # match = \"\"\n  #\n  #  ## For the 'elements' match strategy, at least one path-element name must\n  #  ## be supplied containing at least one key to match on. Multiple path\n  #  ## elements can be specified in any order. All given keys must be equal\n  #  ## for a match.\n  #  # elements = [\"description\", \"interface\"]\n"
  },
  {
    "path": "plugins/inputs/gnmi/tag_store.go",
    "content": "package gnmi\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\ntype tagStore struct {\n\tunconditional map[string]string\n\tnames         map[string]map[string]string\n\telements      elementsStore\n}\n\ntype elementsStore struct {\n\trequired [][]string\n\ttags     map[string]map[string]string\n}\n\nfunc newTagStore(subs []tagSubscription) *tagStore {\n\tstore := tagStore{\n\t\tunconditional: make(map[string]string),\n\t\tnames:         make(map[string]map[string]string),\n\t\telements: elementsStore{\n\t\t\trequired: make([][]string, 0, len(subs)),\n\t\t\ttags:     make(map[string]map[string]string),\n\t\t},\n\t}\n\tfor _, s := range subs {\n\t\tif s.Match == \"elements\" {\n\t\t\tstore.elements.required = append(store.elements.required, s.Elements)\n\t\t}\n\t}\n\n\treturn &store\n}\n\n// Store tags extracted from TagSubscriptions\nfunc (s *tagStore) insert(subscription tagSubscription, path *pathInfo, values []updateField, tags map[string]string) error {\n\tswitch subscription.Match {\n\tcase \"unconditional\":\n\t\tfor _, f := range values {\n\t\t\ttagName := subscription.Name\n\t\t\tif len(f.path.segments) > 0 {\n\t\t\t\tkey := f.path.base()\n\t\t\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\t\t\t\ttagName += \"/\" + key\n\t\t\t}\n\t\t\tsv, err := internal.ToString(f.value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"conversion error for %v: %w\", f.value, err)\n\t\t\t}\n\t\t\tif sv == \"\" {\n\t\t\t\tdelete(s.unconditional, tagName)\n\t\t\t} else {\n\t\t\t\ts.unconditional[tagName] = sv\n\t\t\t}\n\t\t}\n\tcase \"name\":\n\t\t// Get the lookup key\n\t\tkey, found := tags[\"name\"]\n\t\tif !found {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Make sure we have a valid map for the key\n\t\tif _, exists := s.names[key]; !exists {\n\t\t\ts.names[key] = make(map[string]string)\n\t\t}\n\n\t\t// Add the values\n\t\tfor _, f := range values {\n\t\t\ttagName := subscription.Name\n\t\t\tif len(f.path.segments) > 0 {\n\t\t\t\tkey := f.path.base()\n\t\t\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\t\t\t\ttagName += \"/\" + key\n\t\t\t}\n\t\t\tsv, err := internal.ToString(f.value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"conversion error for %v: %w\", f.value, err)\n\t\t\t}\n\t\t\tif sv == \"\" {\n\t\t\t\tdelete(s.names[key], tagName)\n\t\t\t} else {\n\t\t\t\ts.names[key][tagName] = sv\n\t\t\t}\n\t\t}\n\tcase \"elements\":\n\t\tkey, match := getElementsKeys(path, subscription.Elements)\n\t\tif !match || len(values) == 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Make sure we have a valid map for the key\n\t\tif _, exists := s.elements.tags[key]; !exists {\n\t\t\ts.elements.tags[key] = make(map[string]string)\n\t\t}\n\n\t\t// Add the values\n\t\tfor _, f := range values {\n\t\t\ttagName := subscription.Name\n\t\t\tif len(f.path.segments) > 0 {\n\t\t\t\tkey := f.path.base()\n\t\t\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\t\t\t\ttagName += \"/\" + key\n\t\t\t}\n\t\t\tsv, err := internal.ToString(f.value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"conversion error for %v: %w\", f.value, err)\n\t\t\t}\n\t\t\tif sv == \"\" {\n\t\t\t\tdelete(s.elements.tags[key], tagName)\n\t\t\t} else {\n\t\t\t\ts.elements.tags[key][tagName] = sv\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown match strategy %q\", subscription.Match)\n\t}\n\n\treturn nil\n}\n\nfunc (s *tagStore) lookup(path *pathInfo, metricTags map[string]string) map[string]string {\n\t// Add all unconditional tags\n\ttags := make(map[string]string, len(s.unconditional))\n\tfor k, v := range s.unconditional {\n\t\ttags[k] = v\n\t}\n\n\t// Match names\n\tkey, found := metricTags[\"name\"]\n\tif found {\n\t\tfor k, v := range s.names[key] {\n\t\t\ttags[k] = v\n\t\t}\n\t}\n\n\t// Match elements\n\tfor _, requiredKeys := range s.elements.required {\n\t\tkey, match := getElementsKeys(path, requiredKeys)\n\t\tif !match {\n\t\t\tcontinue\n\t\t}\n\t\tfor k, v := range s.elements.tags[key] {\n\t\t\ttags[k] = v\n\t\t}\n\t}\n\n\treturn tags\n}\n\nfunc getElementsKeys(path *pathInfo, elements []string) (string, bool) {\n\t// Search for the required path elements and collect a ordered\n\t// list of their values to in the form\n\t//    elementName1={keyA=valueA,keyB=valueB,...},...,elementNameN={keyY=valueY,keyZ=valueZ}\n\t// where each elements' key-value list is enclosed in curly brackets.\n\tkeyParts := make([]string, 0, len(elements))\n\tfor _, requiredElement := range elements {\n\t\tvar found bool\n\t\tvar elementKVs []string\n\t\tfor _, segment := range path.keyValues {\n\t\t\tif segment.name == requiredElement {\n\t\t\t\tfor k, v := range segment.kv {\n\t\t\t\t\telementKVs = append(elementKVs, k+\"=\"+v)\n\t\t\t\t}\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// The element was not found, but all must match\n\t\tif !found {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\t// We need to order the element's key-value pairs as the map\n\t\t// returns elements in random order\n\t\tsort.Strings(elementKVs)\n\n\t\t// Collect the element\n\t\tkeyParts = append(keyParts, requiredElement+\"={\"+strings.Join(elementKVs, \",\")+\"}\")\n\t}\n\treturn strings.Join(keyParts, \",\"), true\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names/expected.out",
    "content": "interfaces,name=eth42,path=openconfig-interfaces:/interfaces/interface,source=127.0.0.1 /interfaces/interface/descr=\"eth42\",/interfaces/interface/config/id=42425u,/interfaces/interface/state/in_pkts=5678u,/interfaces/interface/state/out_pkts=5125u 1673608605875353770"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1673608605875353770\",\n            \"prefix\": {\n                \"origin\": \"openconfig-interfaces\",\n                \"elem\": [\n                    {\n                        \"name\": \"interfaces\"\n                    },\n                    {\n                        \"name\": \"interface\",\n                        \"key\":{\"name\":\"eth42\"}\n                    }\n                ],\n                \"target\": \"subscription\"\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"descr\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"eth42\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"id\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"42425\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"in-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5678\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"out-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5125\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n  canonical_field_names = true\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/descr\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/config/id\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/state\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names_trim/expected.out",
    "content": "interfaces,name=eth42,path=openconfig-interfaces:/interfaces/interface,source=127.0.0.1 interfaces/interface/descr=\"eth42\",interfaces/interface/config/id=42425u,interfaces/interface/state/in_pkts=5678u,interfaces/interface/state/out_pkts=5125u 1673608605875353770"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names_trim/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1673608605875353770\",\n            \"prefix\": {\n                \"origin\": \"openconfig-interfaces\",\n                \"elem\": [\n                    {\n                        \"name\": \"interfaces\"\n                    },\n                    {\n                        \"name\": \"interface\",\n                        \"key\":{\"name\":\"eth42\"}\n                    }\n                ],\n                \"target\": \"subscription\"\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"descr\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"eth42\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"id\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"42425\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"in-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5678\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"out-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5125\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/canonical_field_names_trim/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n  canonical_field_names = true\n  trim_field_names = true\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/descr\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/config/id\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/state\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11011/expected.out",
    "content": "oc-neigh-state,source=127.0.0.1,neighbor_address=192.0.2.1,name=default,oc-neigh-desc/description=EXAMPLE-PEER,/network-instances/network-instance/protocols/protocol/name=BGP,identifier=BGP session_state=\"ESTABLISHED\" 1543236572000000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11011/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1543236571000000000\",\n            \"prefix\": {},\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"network-instances\"\n                            },\n                            {\n                                \"name\": \"network-instance\",\n                                \"key\": {\n                                    \"name\": \"default\"\n                                }\n                            },\n                            {\n                                \"name\": \"protocols\"\n                            },\n                            {\n                                \"name\": \"protocol\",\n                                \"key\": {\n                                    \"identifier\": \"BGP\",\n                                    \"name\": \"BGP\"\n                                }\n                            },\n                            {\n                                \"name\": \"bgp\"\n                            },\n                            {\n                                \"name\": \"neighbors\"\n                            },\n                            {\n                                \"name\": \"neighbor\",\n                                \"key\": {\n                                    \"neighbor_address\": \"192.0.2.1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"description\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"EXAMPLE-PEER\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"syncResponse\": true\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1543236572000000000\",\n            \"prefix\": {},\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"network-instances\"\n                            },\n                            {\n                                \"name\": \"network-instance\",\n                                \"key\": {\n                                    \"name\": \"default\"\n                                }\n                            },\n                            {\n                                \"name\": \"protocols\"\n                            },\n                            {\n                                \"name\": \"protocol\",\n                                \"key\": {\n                                    \"identifier\": \"BGP\",\n                                    \"name\": \"BGP\"\n                                }\n                            },\n                            {\n                                \"name\": \"bgp\"\n                            },\n                            {\n                                \"name\": \"neighbors\"\n                            },\n                            {\n                                \"name\": \"neighbor\",\n                                \"key\": {\n                                    \"neighbor_address\": \"192.0.2.1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"session-state\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"ESTABLISHED\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"syncResponse\": true\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11011/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"127.0.0.1\"]\n  [[inputs.gnmi.subscription]]\n    name              = \"oc-neigh-state\"\n    origin            = \"openconfig\"\n    path              = \"/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/session-state\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.tag_subscription]]\n    name              = \"oc-neigh-desc\"\n    origin            = \"openconfig\"\n    path              = \"/network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/description\"\n    subscription_mode = \"on_change\"\n    elements          = [\"network-instance\", \"protocol\", \"neighbor\"]\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11778/expected.out",
    "content": "ifcounters,path=openconfig-interfaces:/interfaces/interface/state,name=eth42,descr/description=eth42,source=127.0.0.1 counters=5678i 1673608605875353770"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11778/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1673608605875353770\",\n            \"prefix\": {\n                \"origin\": \"openconfig-interfaces\",\n                \"elem\": [\n                    {\n                        \"name\": \"interfaces\"\n                    },\n                    {\n                        \"name\": \"interface\",\n                        \"key\":{\"name\":\"eth42\"}\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ],\n                \"target\": \"subscription\"\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"counters\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"5678\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"description\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"eth42\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_11778/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"ifcounters\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/state/counters\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.tag_subscription]]\n    name              = \"descr\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/state/description\"\n    subscription_mode = \"on_change\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12831/expected.out",
    "content": "optical_channel,component_name=CM-1,source=127.0.0.1 cpu/openconfig_platform_cpu:utilization/state/avg=13u,cpu/openconfig_platform_cpu:utilization/state/instant=16u,cpu/openconfig_platform_cpu:utilization/state/interval=3600000000000u,cpu/openconfig_platform_cpu:utilization/state/max=17u,cpu/openconfig_platform_cpu:utilization/state/min=8u,name=\"CM-1\",state/memory/available=5041100000u,state/memory/utilized=3099808000u,state/temperature/avg=20.5,state/temperature/instant=20.399999618530273,state/temperature/interval=3600000000000u,state/temperature/max=20.700000762939453,state/temperature/min=20.399999618530273 1714598222912553000\noptical_channel,component_name=AP-1,source=127.0.0.1 name=\"AP-1\",state/temperature/avg=34.099998474121094,state/temperature/instant=34.29999923706055,state/temperature/interval=3600000000000u,state/temperature/max=34.599998474121094,state/temperature/min=33.599998474121094 1714598222912553000\noptical_channel,component_name=LM-1,source=127.0.0.1 name=\"LM-1\",state/temperature/avg=40.79999923706055,state/temperature/instant=40.599998474121094,state/temperature/interval=3600000000000u,state/temperature/max=41.400001525878906,state/temperature/min=40.400001525878906 1714598222912553000\noptical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-1 subcomponents/subcomponent/config/name=\"PORT-1-1\",subcomponents/subcomponent/name=\"PORT-1-1\",subcomponents/subcomponent/state/name=\"PORT-1-1\" 1714598222912553000\noptical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-2 subcomponents/subcomponent/config/name=\"PORT-1-2\",subcomponents/subcomponent/name=\"PORT-1-2\",subcomponents/subcomponent/state/name=\"PORT-1-2\" 1714598222912553000\noptical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-4 subcomponents/subcomponent/config/name=\"PORT-1-4\",subcomponents/subcomponent/name=\"PORT-1-4\",subcomponents/subcomponent/state/name=\"PORT-1-4\" 1714598222912553000\noptical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-12 subcomponents/subcomponent/config/name=\"PORT-1-12\",subcomponents/subcomponent/name=\"PORT-1-12\",subcomponents/subcomponent/state/name=\"PORT-1-12\" 1714598222912553000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12831/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1714598222912553000\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"CM-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 204,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 205,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"min\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 204,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"max\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 207,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"interval\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3600000000000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"memory\"\n                            },\n                            {\n                                \"name\": \"available\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5041100000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"memory\"\n                            },\n                            {\n                                \"name\": \"utilized\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3099808000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"cpu\"\n                            },\n                            {\n                                \"name\": \"openconfig-platform-cpu:utilization\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"16\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"cpu\"\n                            },\n                            {\n                                \"name\": \"openconfig-platform-cpu:utilization\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"13\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"cpu\"\n                            },\n                            {\n                                \"name\": \"openconfig-platform-cpu:utilization\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"min\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"8\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"cpu\"\n                            },\n                            {\n                                \"name\": \"openconfig-platform-cpu:utilization\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"max\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"17\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"CM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"cpu\"\n                            },\n                            {\n                                \"name\": \"openconfig-platform-cpu:utilization\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"interval\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3600000000000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"AP-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 343,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 341,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"min\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 336,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"max\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 346,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"AP-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"interval\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3600000000000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"LM-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 406,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 408,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"min\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 404,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"max\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"decimalVal\": {\n                            \"digits\": 414,\n                            \"precision\": 1\n                        }\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            },\n                            {\n                                \"name\": \"interval\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3600000000000\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-2\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-2\"\n                                }\n                            },\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-2\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-4\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-4\"\n                                }\n                            },\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-4\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-12\"\n                                }\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-12\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-12\"\n                                }\n                            },\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-12\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"openconfig-platform:components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"LM-1\"\n                                }\n                            },\n                            {\n                                \"name\": \"subcomponents\"\n                            },\n                            {\n                                \"name\": \"subcomponent\",\n                                \"key\": {\n                                    \"name\": \"PORT-1-12\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"PORT-1-12\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12831/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  prefix_tag_key_with_path = true\n\n  [[inputs.gnmi.subscription]]\n    name = \"optical_channel\"\n    path = \"/components/component[name=*]\"\n    subscription_mode = \"sample\"\n    origin = \"openconfig-platform\"\n    sample_interval = \"10s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12931/expected.out",
    "content": "interface,name=ethernet-1/1,source=127.0.0.1 interface=1i,transceiver=2i,ethernet=3i,ethernet/flow_control=\"false\",sflow=\"disable\" 1679648530391910312\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12931/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1679648530391910312\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"origin\": \"srl_nokia-interfaces\",\n                        \"elem\": [\n                            {\n                                \"name\": \"interface\",\n                                \"key\":{\"name\":\"ethernet-1/1\"}\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"srl_nokia-interfaces\",\n                        \"elem\": [\n                            {\n                                \"name\": \"interface\",\n                                \"key\":{\"name\":\"ethernet-1/1\"}\n                            },\n                            {\n                                \"name\": \"transceiver\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"srl_nokia-interfaces\",\n                        \"elem\": [\n                            {\n                                \"name\": \"interface\",\n                                \"key\":{\"name\":\"ethernet-1/1\"}\n                            },\n                            {\n                                \"name\": \"ethernet\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"3\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"srl_nokia-interfaces\",\n                        \"elem\": [\n                            {\n                                \"name\": \"interface\",\n                                \"key\":{\"name\":\"ethernet-1/1\"}\n                            },\n                            {\n                                \"name\": \"ethernet\"\n                            },\n                            {\n                                \"name\": \"flow-control\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"false\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"srl_nokia-interfaces\",\n                        \"elem\": [\n                            {\n                                \"name\": \"interface\",\n                                \"key\":{\"name\":\"ethernet-1/1\"}\n                            },\n                            {\n                                \"name\": \"sflow\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"disable\"\n                    }\n                }\n           ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_12931/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"interface\"\n    path = \"/interface\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13052/expected.out",
    "content": "components,/components/component/properties/property/name=mem-util-kernel-size,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=671088216u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=187929304u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-utilization,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=28i 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifd-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=97240u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifd-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=442u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifd-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifd-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifl-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=95272u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifl-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=132u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifl-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-ifl-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-iff-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=38640u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-iff-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=178u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-iff-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-iff-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=82592u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=914609u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=914255u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rtt-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=7212u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rtt-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=25u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rtt-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rtt-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-nh-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=180544u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-nh-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=519u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-nh-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=21u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-nh-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-filter-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=144380u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-filter-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2674u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-filter-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=739u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-filter-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=41488u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=383u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=53u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-halp-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=482008u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-halp-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=102u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-halp-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-cos-halp-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-mac-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=20u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-mac-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-mac-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-rt-mac-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpdl-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=364u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpdl-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=16u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpdl-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=9u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpdl-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=56u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=4u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-syms-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=104u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-syms-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=4u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-syms-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-fpb-syms-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-agent-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=19548u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-agent-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1679742u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-agent-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1679691u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-agent-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-an-stats-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=5503680u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-an-stats-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=10192u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-an-stats-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-an-stats-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-resolve-bind-point-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=72u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-resolve-bind-point-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=12u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-resolve-bind-point-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=6u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-resolve-bind-point-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-entry-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=95436u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-entry-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2812u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-entry-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1435u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-entry-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-tcam-entry-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=33920u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-tcam-entry-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=546u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-tcam-entry-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-tcam-entry-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-id-entry-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=448u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-id-entry-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=40u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-id-entry-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=24u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-id-entry-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-bmap-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=9216u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-bmap-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=62u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-bmap-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=24u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-bmap-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-hw-hdl-rule-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=49172u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-hw-hdl-rule-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2257u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-hw-hdl-rule-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1140u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-hw-hdl-rule-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-lagmatch-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=72u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-lagmatch-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-lagmatch-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-lagmatch-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-cntr-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=372008u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-cntr-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=4444u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-cntr-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1628u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-cntr-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-policer-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=192544u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-policer-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=600u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-policer-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=240u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-policer-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-misc-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=984u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-misc-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=83u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-misc-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=1u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-dfw-misc-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-halp-unknown-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=92u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-halp-unknown-allocations,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=3u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-halp-unknown-frees,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=2u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-kernel-halp-unknown-allocations-failed,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=0u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-dma-size,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=67108864u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-dma-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=4655312u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-dma-utilization,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=6i 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-pkt-dma-desc-size,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=12582912u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-pkt-dma-desc-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=10257712u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-pkt-dma-desc-utilization,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=81i 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-bcm-sdk-size,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=268435456u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-bcm-sdk-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=157163104u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-bcm-sdk-utilization,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=58i 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-packet-dma-size,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=113246208u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-packet-dma-bytes-allocated,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=56030424u 1688641479762000000\ncomponents,/components/component/properties/property/name=mem-util-packet-dma-utilization,name=FPC0:CPU0,path=/components/component/properties,source=127.0.0.1 component/properties/property/state/value=49i 1688641479762000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13052/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1688641479762000000\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"components\"\n                    },\n                    {\n                        \"name\": \"component\",\n                        \"key\": {\n                            \"name\": \"FPC0:CPU0\"\n                        }\n                    },\n                    {\n                        \"name\": \"properties\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-size\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"671088216\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"187929304\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-utilization\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"28\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifd-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"97240\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifd-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"442\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifd-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifd-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifl-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"95272\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifl-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"132\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifl-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-ifl-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-iff-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"38640\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-iff-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"178\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-iff-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-iff-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"82592\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"914609\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"914255\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rtt-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"7212\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rtt-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"25\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rtt-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rtt-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-nh-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"180544\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-nh-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"519\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-nh-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"21\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-nh-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-filter-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"144380\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-filter-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2674\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-filter-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"739\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-filter-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"41488\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"383\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"53\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-halp-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"482008\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-halp-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"102\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-halp-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-cos-halp-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-mac-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"20\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-mac-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-mac-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-rt-mac-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpdl-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"364\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpdl-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"16\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpdl-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"9\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpdl-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"56\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-syms-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"104\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-syms-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-syms-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-fpb-syms-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-agent-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"19548\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-agent-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1679742\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-agent-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1679691\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-agent-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-an-stats-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5503680\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-an-stats-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"10192\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-an-stats-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-an-stats-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-resolve-bind-point-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"72\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-resolve-bind-point-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"12\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-resolve-bind-point-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"6\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-resolve-bind-point-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-entry-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"95436\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-entry-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2812\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-entry-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1435\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-entry-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-tcam-entry-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"33920\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-tcam-entry-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"546\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-tcam-entry-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-tcam-entry-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-id-entry-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"448\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-id-entry-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"40\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-id-entry-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"24\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-id-entry-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-bmap-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"9216\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-bmap-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"62\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-bmap-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"24\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-bmap-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-hw-hdl-rule-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"49172\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-hw-hdl-rule-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2257\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-hw-hdl-rule-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1140\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-hw-hdl-rule-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-lagmatch-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"72\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-lagmatch-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-lagmatch-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-lagmatch-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-cntr-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"372008\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-cntr-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4444\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-cntr-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1628\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-cntr-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-policer-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"192544\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-policer-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"600\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-policer-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"240\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-policer-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-misc-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"984\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-misc-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"83\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-misc-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-dfw-misc-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-halp-unknown-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"92\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-halp-unknown-allocations\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-halp-unknown-frees\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-kernel-halp-unknown-allocations-failed\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-dma-size\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"67108864\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-dma-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4655312\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-dma-utilization\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"6\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-pkt-dma-desc-size\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"12582912\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-pkt-dma-desc-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"10257712\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-pkt-dma-desc-utilization\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"81\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-bcm-sdk-size\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"268435456\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-bcm-sdk-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"157163104\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-bcm-sdk-utilization\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"58\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-packet-dma-size\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"113246208\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-packet-dma-bytes-allocated\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"56030424\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"property\",\n                                \"key\": {\n                                    \"name\": \"mem-util-packet-dma-utilization\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"value\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"49\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13052/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  redial        = \"10s\"\n\n  [inputs.gnmi.aliases]\n    components = \"/components\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"memory\"\n    origin = \"openconfig\"\n    path = \"/junos/system/linecard/cpu/memory\"\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13512/expected.out",
    "content": "interfaces,name=eth42,path=openconfig-interfaces:/interfaces/interface,source=127.0.0.1 descr=\"eth42\",id=42425u,in_pkts=5678u,out_pkts=5125u 1673608605875353770"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13512/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1673608605875353770\",\n            \"prefix\": {\n                \"origin\": \"openconfig-interfaces\",\n                \"elem\": [\n                    {\n                        \"name\": \"interfaces\"\n                    },\n                    {\n                        \"name\": \"interface\",\n                        \"key\":{\"name\":\"eth42\"}\n                    }\n                ],\n                \"target\": \"subscription\"\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"descr\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"eth42\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"config\"\n                            },\n                            {\n                                \"name\": \"id\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"42425\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"in-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5678\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"out-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"5125\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_13512/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/descr\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/config/id\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n  [[inputs.gnmi.subscription]]\n    name              = \"interfaces\"\n    origin            = \"openconfig-interfaces\"\n    path              = \"/interfaces/interface/state\"\n    subscription_mode = \"sample\"\n    sample_interval   = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14044/expected.out",
    "content": "ifdesc,name=FourHundredGigE0/2/0/3,path=openconfig-interfaces:/interfaces/interface/state,source=127.0.0.1 description=\"REDACTED\" 1696324083211000000"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14044/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1696324083211000000\",\n            \"prefix\": {\n                \"origin\": \"openconfig-interfaces\"\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"interfaces\"\n                            },\n                            {\n                                \"name\": \"interface\",\n                                \"key\": {\n                                    \"name\": \"FourHundredGigE0/2/0/3\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"json_ietf_val\": \"eyJkZXNjcmlwdGlvbiI6IlJFREFDVEVEIn0=\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14044/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n  encoding      = \"json_ietf\"\n  path_guessing_strategy = \"common path\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"ifdesc\"\n    origin = \"openconfig-interfaces\"\n    path = '/interfaces/interface[name=FourHundredGigE*]/state/description'\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14063/expected.out",
    "content": "ifcounters,path=oc-if:/interfaces/oc-if:interface/oc-if:state/oc-if:counters,source=127.0.0.1 in_1024_to_1518_octet_pkts=0u,in_128_to_255_octet_pkts=0u,in_1519_to_2047_octet_pkts=0u,in_2048_to_4095_octet_pkts=0u,in_256_to_511_octet_pkts=0u,in_4096_to_9216_octet_pkts=0u,in_512_to_1023_octet_pkts=0u,in_64_octet_pkts=0u,in_65_to_127_octet_pkts=0u,in_broadcast_pkts=0u,in_crc_error_pkts=0u,in_discards=0u,in_discards_octets=0u,in_dropped_octets=0u,in_dropped_pkts=0u,in_errors=0u,in_jabber_pkts=0u,in_multicast_pkts=0u,in_octets=0u,in_oversize_pkts=0u,in_pkts=0u,in_undersize_pkts=0u,in_unicast_pkts=0u,last_clear=1691859140059797458u,link_flap_events=0u,name=\"\\\\\\\"1\\\\\",out_1519_to_2047_octet_pkts=0u,out_2048_to_4095_octet_pkts=0u,out_4096_to_9216_octet_pkts=0u,out_broadcast_pkts=0u,out_errors=0u,out_multicast_pkts=0u,out_octets=0u,out_pkts=0u,out_unicast_pkts=0u 1696617695101000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14063/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1696617695101000000\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"oc-if:interfaces\"\n                    },\n                    {\n                        \"name\": \"oc-if:interface\"\n                    },\n                    {\n                        \"name\": \"oc-if:state\"\n                    },\n                    {\n                        \"name\": \"oc-if:counters\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-1024-to-1518-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-128-to-255-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-1519-to-2047-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-2048-to-4095-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-256-to-511-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-4096-to-9216-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-512-to-1023-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-64-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-65-to-127-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-broadcast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-crc-error-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-discards\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-discards-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-dropped-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-dropped-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-errors\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-jabber-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-multicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-oversize-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-undersize-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"in-unicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"last-clear\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1691859140059797458\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"link-flap-events\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"\\\\\\\"1\\\\\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-1519-to-2047-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-2048-to-4095-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-4096-to-9216-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-broadcast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-errors\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-multicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"out-unicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14063/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  name_override = \"gnmi\"\n  redial        = \"10s\"\n\n  [[inputs.gnmi.subscription]]\n     name = \"ifcounters\"\n     origin = \"openconfig-interfaces\"\n     path = \"/oc-if:interfaces/oc-if:interface/oc-if:state/oc-if:counters\"\n     subscription_mode = \"sample\"\n     sample_interval = \"30s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14530/expected.out",
    "content": "ifcounters,name=Ethernet35,path=/interfaces/interface/state/counters,source=127.0.0.1 in_broadcast_pkts=0u,in_discards=0u,in_errors=0u,in_fcs_errors=0u,in_multicast_pkts=0u,in_octets=0u,in_pkts=0u,in_unicast_pkts=0u,out_broadcast_pkts=0u,out_discards=0u,out_errors=0u,out_multicast_pkts=0u,out_octets=0u,out_pkts=0u,out_unicast_pkts=0u 1704442117721474264\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14530/responses.json",
    "content": "[\n  {\n    \"update\": {\n      \"timestamp\": \"1704442117721474264\",\n      \"prefix\": {\n        \"elem\": [\n          {\n            \"name\": \"interfaces\"\n          },\n          {\n            \"name\": \"interface\",\n            \"key\": {\n              \"name\": \"Ethernet35\"\n            }\n          },\n          {\n            \"name\": \"state\"\n          },\n          {\n            \"name\": \"counters\"\n          }\n        ]\n      },\n      \"update\": [\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-broadcast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-discards\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-errors\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-fcs-errors\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-multicast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-octets\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"in-unicast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-broadcast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-discards\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-errors\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-multicast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-octets\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        },\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"out-unicast-pkts\"\n              }\n            ]\n          },\n          \"val\": {\n            \"uintVal\": \"0\"\n          }\n        }\n      ]\n    }\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14530/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  encoding = \"json_ietf\"\n  tagexclude = [\"path\"]\n\n  [inputs.gnmi.tags]\n    test_tag = \"test\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"ifcounters\"\n    origin = \"openconfig\"\n    path = \"/interfaces/interface/state/counters\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14833/expected.out",
    "content": "interfaces-counter,name=AppGigabitEthernet1/0/1,source=127.0.0.1 discontinuity_time=\"2023-11-15T05:50:40+00:00\" 1708069483623763000\ninterfaces-counter,name=FortyGigabitEthernet1/1/1,source=127.0.0.1 discontinuity_time=\"2023-11-15T05:50:40+00:00\" 1708069483623763000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14833/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1708069483623763000\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"Cisco-IOS-XE-interfaces-oper:interfaces\"\n                            },\n                            {\n                                \"name\": \"interface\",\n                                \"key\": {\n                                    \"name\": \"AppGigabitEthernet1/0/1\"\n                                }\n                            },\n                            {\n                                \"name\": \"statistics\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJkaXNjb250aW51aXR5LXRpbWUiOiIyMDIzLTExLTE1VDA1OjUwOjQwKzAwOjAwIn0K\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"Cisco-IOS-XE-interfaces-oper:interfaces\"\n                            },\n                            {\n                                \"name\": \"interface\",\n                                \"key\": {\n                                    \"name\": \"FortyGigabitEthernet1/1/1\"\n                                }\n                            },\n                            {\n                                \"name\": \"statistics\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJkaXNjb250aW51aXR5LXRpbWUiOiIyMDIzLTExLTE1VDA1OjUwOjQwKzAwOjAwIn0K\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14833/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n\n  [[inputs.gnmi.subscription]]\n    name = \"interfaces-counter\"\n    origin = \"rfc7951\"\n    path = \"/Cisco-IOS-XE-interfaces-oper:interfaces/interface/statistics\"\n    subscription_mode = \"sample\"\n    sample_interval = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946/expected.out",
    "content": "gnmi_sys_memory,path=/system/memory/state,source=127.0.0.1 reserved=6359478272u,used=3479629824u 1709737743568119333\ngnmi_sys_memory,path=/system/memory/state,source=127.0.0.1 used=3479527424u 1709737753565697718\ngnmi_sys_cpu,index=ALL,path=/system/cpus/cpu/state,source=127.0.0.1 hardware_interrupt/min_time=1709805333568034887u 1709805333566280930\ngnmi_sys_cpu,index=ALL,path=/system/cpus/cpu/state,source=127.0.0.1 hardware_interrupt/min_time=1709805343567684412u,idle/avg=89u,idle/instant=90u 1709805343565718902\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1709737743568119333\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"system\"\n                    },\n                    {\n                        \"name\": \"memory\"\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"reserved\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"6359478272\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"used\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3479629824\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709737753565697718\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"system\"\n                            },\n                            {\n                                \"name\": \"memory\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"used\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3479527424\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709805333566280930\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"system\"\n                            },\n                            {\n                                \"name\": \"cpus\"\n                            },\n                            {\n                                \"name\": \"cpu\",\n                                \"key\": {\n                                    \"index\": \"ALL\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"hardware-interrupt\"\n                            },\n                            {\n                                \"name\": \"min-time\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1709805333568034887\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709805343565718902\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"system\"\n                    },\n                    {\n                        \"name\": \"cpus\"\n                    },\n                    {\n                        \"name\": \"cpu\",\n                        \"key\": {\n                            \"index\": \"ALL\"\n                        }\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"hardware-interrupt\"\n                            },\n                            {\n                                \"name\": \"min-time\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1709805343567684412\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"idle\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"89\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"idle\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"90\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  path_guessing_strategy = \"subscription\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"gnmi_sys_cpu\"\n    path = \"/system/cpus/cpu/state\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"gnmi_sys_memory\"\n    path = \"/system/memory/state\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/expected.out",
    "content": "gnmi_sys_memory,path=/system/memory/state,source=127.0.0.1 /system/memory/state/reserved=6359478272u,/system/memory/state/used=3479629824u 1709737743568119333\ngnmi_sys_memory,source=127.0.0.1 /system/memory/state/used=3479527424u 1709737753565697718\ngnmi_sys_cpu,index=ALL,source=127.0.0.1 /system/cpus/cpu/state/hardware_interrupt/min_time=1709805333568034887u 1709805333566280930\ngnmi_sys_cpu,index=ALL,path=/system/cpus/cpu/state,source=127.0.0.1 /system/cpus/cpu/state/hardware_interrupt/min_time=1709805343567684412u,/system/cpus/cpu/state/idle/avg=89u,/system/cpus/cpu/state/idle/instant=90u 1709805343565718902\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1709737743568119333\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"system\"\n                    },\n                    {\n                        \"name\": \"memory\"\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"reserved\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"6359478272\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"used\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3479629824\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709737753565697718\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"system\"\n                            },\n                            {\n                                \"name\": \"memory\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"used\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"3479527424\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709805333566280930\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"system\"\n                            },\n                            {\n                                \"name\": \"cpus\"\n                            },\n                            {\n                                \"name\": \"cpu\",\n                                \"key\": {\n                                    \"index\": \"ALL\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"hardware-interrupt\"\n                            },\n                            {\n                                \"name\": \"min-time\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1709805333568034887\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1709805343565718902\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"system\"\n                    },\n                    {\n                        \"name\": \"cpus\"\n                    },\n                    {\n                        \"name\": \"cpu\",\n                        \"key\": {\n                            \"index\": \"ALL\"\n                        }\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"hardware-interrupt\"\n                            },\n                            {\n                                \"name\": \"min-time\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1709805343567684412\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"idle\"\n                            },\n                            {\n                                \"name\": \"avg\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"89\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"idle\"\n                            },\n                            {\n                                \"name\": \"instant\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"90\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  canonical_field_names = true\n\n  [[inputs.gnmi.subscription]]\n    name = \"gnmi_sys_cpu\"\n    path = \"/system/cpus/cpu/state\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"gnmi_sys_memory\"\n    path = \"/system/memory/state\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/expected.out",
    "content": "psu,name=PowerSupply1/A,path=openconfig:/components/component/power-supply/state,source=127.0.0.1 openconfig_platform_psu:capacity=715,openconfig_platform_psu:enabled=true,openconfig_platform_psu:input_current=0.47099998593330383,openconfig_platform_psu:input_voltage=208.5,openconfig_platform_psu:output_current=1.2029999494552612,openconfig_platform_psu:output_power=68.625,openconfig_platform_psu:output_voltage=56.367000579833984 1711178737105194000\npsu,name=PowerSupply1/B,path=openconfig:/components/component/power-supply/state,source=127.0.0.1 openconfig_platform_psu:capacity=715,openconfig_platform_psu:enabled=true,openconfig_platform_psu:input_current=0.3930000066757202,openconfig_platform_psu:input_voltage=209.75,openconfig_platform_psu:output_current=0.9380000233650208,openconfig_platform_psu:output_power=51.875,openconfig_platform_psu:output_voltage=56.367000579833984 1711178737105194000\ntemp,name=InletTempSensor1,path=openconfig:/components/component/state/temperature,source=127.0.0.1 alarm_severity=\"openconfig-alarm-types:MINOR\",alarm_status=false,alarm_threshold=0,avg=24.000000,instant=35.000000,interval=180000000000u,max=36.000000,min=0.000000 1715838159171548000\ntemp,name=OutletTempSensor1,path=openconfig:/components/component/state/temperature,source=127.0.0.1 alarm_severity=\"openconfig-alarm-types:MINOR\",alarm_status=false,alarm_threshold=0,avg=29.000000,instant=44.000000,interval=180000000000u,max=44.000000,min=0.000000 1715838159171548000\ntemp,name=HotSpotTempSensor1,path=openconfig:/components/component/state/temperature,source=127.0.0.1 alarm_severity=\"openconfig-alarm-types:MINOR\",alarm_status=false,alarm_threshold=0,avg=39.000000,instant=58.000000,interval=180000000000u,max=59.000000,min=0.000000 1715838159171548000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/README.md",
    "content": "<!-- markdownlint-disable -->\nFiles extracted from https://github.com/openconfig/public\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-alarm-types.yang",
    "content": "module openconfig-alarm-types {\n\n  yang-version \"1\";\n\n  // namespace\n  namespace \"http://openconfig.net/yang/alarms/types\";\n\n  prefix \"oc-alarm-types\";\n\n  // import some basic types\n  import openconfig-extensions { prefix oc-ext; }\n\n  // meta\n  organization \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    www.openconfig.net\";\n\n  description\n    \"This module defines operational state data related to alarms\n    that the device is reporting.\n\n    This model reuses some data items defined in the draft IETF\n    YANG Alarm Module:\n    https://tools.ietf.org/html/draft-vallin-netmod-alarm-module-02\n\n    Portions of this code were derived from the draft IETF YANG Alarm\n    Module. Please reproduce this note if possible.\n\n    IETF code is subject to the following copyright and license:\n    Copyright (c) IETF Trust and the persons identified as authors of\n    the code.\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, is permitted pursuant to, and subject to the license\n    terms contained in, the Simplified BSD License set forth in\n    Section 4.c of the IETF Trust's Legal Provisions Relating\n    to IETF Documents (http://trustee.ietf.org/license-info).\";\n\n  oc-ext:openconfig-version \"0.2.1\";\n\n  // OpenConfig specific extensions for module metadata.\n  oc-ext:regexp-posix;\n  oc-ext:catalog-organization \"openconfig\";\n  oc-ext:origin \"openconfig\";\n\n  // identity statements\n\n  identity OPENCONFIG_ALARM_SEVERITY {\n    description\n      \"Base identity for alarm severity profiles. Derived\n      identities are based on contents of the draft\n      IETF YANG Alarm Module\";\n    reference\n      \"IETF YANG Alarm Module: Draft - typedef severity\n      https://tools.ietf.org/html/draft-vallin-netmod-alarm-module-02\";\n\n  }\n\n  identity UNKNOWN {\n    base OPENCONFIG_ALARM_SEVERITY;\n    description\n      \"Indicates that the severity level could not be determined.\n      This level SHOULD be avoided.\";\n  }\n\n  identity MINOR {\n    base OPENCONFIG_ALARM_SEVERITY;\n    description\n      \"Indicates the existence of a non-service affecting fault\n      condition and that corrective action should be taken in\n      order to prevent a more serious (for example, service\n      affecting) fault. Such a severity can be reported, for\n      example, when the detected alarm condition is not currently\n      degrading the capacity of the resource\";\n  }\n\n  identity WARNING {\n    base OPENCONFIG_ALARM_SEVERITY;\n    description\n      \"Indicates the detection of a potential or impending service\n      affecting fault, before any significant effects have been felt.\n      Action should be taken to further diagnose (if necessary) and\n      correct the problem in order to prevent it from becoming a more\n      serious service affecting fault.\";\n  }\n\n  identity MAJOR {\n    base OPENCONFIG_ALARM_SEVERITY;\n    description\n      \"Indicates that a service affecting condition has developed\n      and an urgent corrective action is required. Such a severity\n      can be reported, for example, when there is a severe\n      degradation in the capability of the resource and its full\n      capability must be restored.\";\n  }\n\n  identity CRITICAL {\n    base OPENCONFIG_ALARM_SEVERITY;\n    description\n      \"Indicates that a service affecting condition has occurred\n      and an immediate corrective action is required. Such a\n      severity can be reported, for example, when a resource becomes\n      totally out of service and its capability must be restored.\";\n  }\n\n}"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-extensions.yang",
    "content": "module openconfig-extensions {\n\n  yang-version \"1\";\n\n  // namespace\n  namespace \"http://openconfig.net/yang/openconfig-ext\";\n\n  prefix \"oc-ext\";\n\n  // meta\n  organization \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    www.openconfig.net\";\n\n  description\n    \"This module provides extensions to the YANG language to allow\n    OpenConfig specific functionality and meta-data to be defined.\";\n\n  oc-ext:openconfig-version \"0.5.1\";\n\n  // extension statements\n  extension openconfig-version {\n    argument \"semver\" {\n      yin-element false;\n    }\n    description\n      \"The OpenConfig version number for the module. This is\n      expressed as a semantic version number of the form:\n        x.y.z\n      where:\n        * x corresponds to the major version,\n        * y corresponds to a minor version,\n        * z corresponds to a patch version.\n      This version corresponds to the model file within which it is\n      defined, and does not cover the whole set of OpenConfig models.\n\n      Individual YANG modules are versioned independently -- the\n      semantic version is generally incremented only when there is a\n      change in the corresponding file.  Submodules should always\n      have the same semantic version as their parent modules.\n\n      A major version number of 0 indicates that this model is still\n      in development (whether within OpenConfig or with industry\n      partners), and is potentially subject to change.\n\n      Following a release of major version 1, all modules will\n      increment major revision number where backwards incompatible\n      changes to the model are made.\n\n      The minor version is changed when features are added to the\n      model that do not impact current clients use of the model.\n\n      The patch-level version is incremented when non-feature changes\n      (such as bugfixes or clarifications to human-readable\n      descriptions that do not impact model functionality) are made\n      that maintain backwards compatibility.\n\n      The version number is stored in the module meta-data.\";\n  }\n\n  extension regexp-posix {\n     description\n      \"This extension indicates that the regular expressions included\n      within the YANG module specified are conformant with the POSIX\n      regular expression format rather than the W3C standard that is\n      specified by RFC6020 and RFC7950.\";\n  }\n\n  extension operational {\n    description\n      \"The operational annotation is specified in the context of a\n      grouping, leaf, or leaf-list within a YANG module. It indicates\n      that the nodes within the context are derived state on the device.\n\n      OpenConfig data models divide nodes into the following three categories:\n\n       - intended configuration - these are leaves within a container named\n         'config', and are the writable configuration of a target.\n       - applied configuration - these are leaves within a container named\n         'state' and are the currently running value of the intended configuration.\n       - derived state - these are the values within the 'state' container which\n         are not part of the applied configuration of the device. Typically, they\n         represent state values reflecting underlying operational counters, or\n         protocol statuses.\";\n  }\n\n  extension catalog-organization {\n    argument \"org\" {\n      yin-element false;\n    }\n    description\n      \"This extension specifies the organization name that should be used within\n      the module catalogue on the device for the specified YANG module. It stores\n      a pithy string where the YANG organization statement may contain more\n      details.\";\n  }\n\n  extension origin {\n    argument \"origin\" {\n      yin-element false;\n    }\n    description\n      \"This extension specifies the name of the origin that the YANG module\n      falls within. This allows multiple overlapping schema trees to be used\n      on a single network element without requiring module based prefixing\n      of paths.\";\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform-psu.yang",
    "content": "module openconfig-platform-psu {\n\n  yang-version \"1\";\n\n  // namespace\n  namespace \"http://openconfig.net/yang/platform/psu\";\n\n  prefix \"oc-platform-psu\";\n\n  // import some basic types\n  import openconfig-extensions { prefix oc-ext; }\n  import openconfig-types { prefix oc-types; }\n\n\n  // meta\n  organization \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    www.openconfig.net\";\n\n  description\n    \"This module defines a schema for power supply components in\n    the OpenConfig platform model.\";\n\n  oc-ext:openconfig-version \"0.2.1\";\n\n  // OpenConfig specific extensions for module metadata.\n  oc-ext:regexp-posix;\n  oc-ext:catalog-organization \"openconfig\";\n  oc-ext:origin \"openconfig\";\n\n  grouping psu-config {\n    description\n      \"Configuration data for power supply components\";\n\n    leaf enabled {\n      type boolean;\n      default true;\n      description\n        \"Adminsitrative control on the on/off state of the power\n        supply unit.\";\n    }\n  }\n\n  grouping psu-state {\n    description\n      \"Operational state data for power supply components\";\n\n    leaf capacity {\n      type oc-types:ieeefloat32;\n      units watts;\n      description\n        \"Maximum power capacity of the power supply.\";\n    }\n\n    leaf input-current {\n      type oc-types:ieeefloat32;\n      units amps;\n      description\n        \"The input current draw of the power supply.\";\n    }\n\n    leaf input-voltage {\n      type oc-types:ieeefloat32;\n      units volts;\n      description\n        \"Input voltage to the power supply.\";\n    }\n\n    leaf output-current {\n      type oc-types:ieeefloat32;\n      units amps;\n      description\n        \"The output current supplied by the power supply.\";\n    }\n\n    leaf output-voltage {\n      type oc-types:ieeefloat32;\n      units volts;\n      description\n        \"Output voltage supplied by the power supply.\";\n    }\n\n    leaf output-power {\n      type oc-types:ieeefloat32;\n      units watts;\n      description\n        \"Output power supplied by the power supply.\";\n    }\n  }\n}"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform-types.yang",
    "content": "module openconfig-platform-types {\n\n  yang-version \"1\";\n\n  // namespace\n  namespace \"http://openconfig.net/yang/platform-types\";\n\n  prefix \"oc-platform-types\";\n\n  import openconfig-types { prefix oc-types; }\n  import openconfig-extensions { prefix oc-ext; }\n\n  // meta\n  organization\n    \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    www.openconfig.net\";\n\n  description\n    \"This module defines data types (e.g., YANG identities)\n    to support the OpenConfig component inventory model.\";\n\n  oc-ext:openconfig-version \"1.6.0\";\n\n  // OpenConfig specific extensions for module metadata.\n  oc-ext:regexp-posix;\n  oc-ext:catalog-organization \"openconfig\";\n  oc-ext:origin \"openconfig\";\n\n  // grouping statements\n  grouping avg-min-max-instant-stats-precision1-celsius {\n    description\n      \"Common grouping for recording temperature values in\n      Celsius with 1 decimal precision. Values include the\n      instantaneous, average, minimum, and maximum statistics\";\n\n    leaf instant {\n      type decimal64 {\n        fraction-digits 1;\n      }\n      units celsius;\n      description\n        \"The instantaneous value of the statistic.\";\n    }\n\n    leaf avg {\n      type decimal64 {\n        fraction-digits 1;\n      }\n      units celsius;\n      description\n        \"The arithmetic mean value of the statistic over the\n        sampling period.\";\n    }\n\n    leaf min {\n      type decimal64 {\n        fraction-digits 1;\n      }\n      units celsius;\n      description\n        \"The minimum value of the statistic over the sampling\n        period\";\n    }\n\n    leaf max {\n      type decimal64 {\n        fraction-digits 1;\n      }\n      units celsius;\n      description\n        \"The maximum value of the statistic over the sampling\n        period\";\n    }\n\n    uses oc-types:stat-interval-state;\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform.yang",
    "content": "module openconfig-platform {\n\n  yang-version \"1\";\n\n  // namespace\n  namespace \"http://openconfig.net/yang/platform\";\n\n  prefix \"oc-platform\";\n\n  import openconfig-platform-types { prefix oc-platform-types; }\n  import openconfig-extensions { prefix oc-ext; }\n  import openconfig-alarm-types { prefix oc-alarm-types; }\n\n  // meta\n  organization \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    www.openconfig.net\";\n\n  description\n    \"This module defines a data model for representing a system\n    component inventory, which can include hardware or software\n    elements arranged in an arbitrary structure. The primary\n    relationship supported by the model is containment, e.g.,\n    components containing subcomponents.\n\n    It is expected that this model reflects every field replacable\n    unit on the device at a minimum (i.e., additional information\n    may be supplied about non-replacable components).\n\n    Every element in the inventory is termed a 'component' with each\n    component expected to have a unique name and type, and optionally\n    a unique system-assigned identifier and FRU number.  The\n    uniqueness is guaranteed by the system within the device.\n\n    Components may have properties defined by the system that are\n    modeled as a list of key-value pairs. These may or may not be\n    user-configurable.  The model provides a flag for the system\n    to optionally indicate which properties are user configurable.\n\n    Each component also has a list of 'subcomponents' which are\n    references to other components. Appearance in a list of\n    subcomponents indicates a containment relationship as described\n    above.  For example, a linecard component may have a list of\n    references to port components that reside on the linecard.\n\n    This schema is generic to allow devices to express their own\n    platform-specific structure.  It may be augmented by additional\n    component type-specific schemas that provide a common structure\n    for well-known component types.  In these cases, the system is\n    expected to populate the common component schema, and may\n    optionally also represent the component and its properties in the\n    generic structure.\n\n    The properties for each component may include dynamic values,\n    e.g., in the 'state' part of the schema.  For example, a CPU\n    component may report its utilization, temperature, or other\n    physical properties.  The intent is to capture all platform-\n    specific physical data in one location, including inventory\n    (presence or absence of a component) and state (physical\n    attributes or status).\";\n\n  oc-ext:openconfig-version \"0.24.0\";\n\n    // OpenConfig specific extensions for module metadata.\n  oc-ext:regexp-posix;\n  oc-ext:catalog-organization \"openconfig\";\n  oc-ext:origin \"openconfig\";\n\n  // grouping statements\n\n  grouping platform-component-temp-alarm-state {\n    description\n      \"Temperature alarm data for platform components\";\n\n    // TODO(aashaikh): consider if these leaves could be in a\n    // reusable grouping (not temperature-specific); threshold\n    // may always need to be units specific.\n\n    leaf alarm-status {\n      type boolean;\n      description\n        \"A value of true indicates the alarm has been raised or\n        asserted.  The value should be false when the alarm is\n        cleared.\";\n    }\n\n    leaf alarm-threshold {\n      type uint32;\n      description\n        \"The threshold value that was crossed for this alarm.\";\n    }\n\n    leaf alarm-severity {\n      type identityref {\n        base oc-alarm-types:OPENCONFIG_ALARM_SEVERITY;\n      }\n      description\n        \"The severity of the current alarm.\";\n    }\n  }\n\n  grouping platform-component-temp-state {\n    description\n      \"Temperature state data for device components\";\n\n    container temperature {\n      description\n        \"Temperature in degrees Celsius of the component. Values include\n        the instantaneous, average, minimum, and maximum statistics. If\n        avg/min/max statistics are not supported, the target is expected\n        to just supply the instant value\";\n\n      uses oc-platform-types:avg-min-max-instant-stats-precision1-celsius;\n      uses platform-component-temp-alarm-state;\n    }\n  }\n\n  grouping platform-component-top {\n    description\n      \"Top-level grouping for components in the device inventory\";\n\n    container components {\n      description\n        \"Enclosing container for the components in the system.\";\n\n      list component {\n        key \"name\";\n        description\n          \"List of components, keyed by component name.\";\n\n        leaf name {\n          type leafref {\n            path \"../config/name\";\n          }\n          description\n            \"References the component name\";\n        }\n\n        container state {\n          config false;\n\n          description\n            \"Operational state data for each component\";\n\n          uses platform-component-temp-state;\n        }\n      }\n    }\n  }\n\n\n  // data definition statements\n\n  uses platform-component-top;\n\n\n  // augments\n\n\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-types.yang",
    "content": "module openconfig-types {\n  yang-version \"1\";\n\n  namespace \"http://openconfig.net/yang/openconfig-types\";\n\n  prefix \"oc-types\";\n\n  // import statements\n  import openconfig-extensions { prefix oc-ext; }\n\n  // meta\n  organization\n    \"OpenConfig working group\";\n\n  contact\n    \"OpenConfig working group\n    netopenconfig@googlegroups.com\";\n\n  description\n    \"This module contains a set of general type definitions that\n    are used across OpenConfig models. It can be imported by modules\n    that make use of these types.\";\n\n  oc-ext:openconfig-version \"1.0.0\";\n\n  // OpenConfig specific extensions for module metadata.\n  oc-ext:regexp-posix;\n  oc-ext:catalog-organization \"openconfig\";\n  oc-ext:origin \"openconfig\";\n\n  typedef stat-interval {\n    type uint64;\n    units nanoseconds;\n    description\n      \"A time interval over which a set of statistics is computed.\n      A common usage is to report the interval over which\n      avg/min/max stats are computed and reported.\";\n  }\n\n  grouping stat-interval-state {\n    description\n      \"Reusable leaf definition for stats computation interval\";\n\n    leaf interval {\n      type oc-types:stat-interval;\n      description\n        \"If supported by the system, this reports the time interval\n        over which the min/max/average statistics are computed by\n        the system.\";\n    }\n  }\n\n  typedef ieeefloat32 {\n    type binary {\n      length \"4\";\n    }\n    description\n      \"An IEEE 32-bit floating point number. The format of this number\n      is of the form:\n        1-bit  sign\n        8-bit  exponent\n        23-bit fraction\n      The floating point value is calculated using:\n        (-1)**S * 2**(Exponent-127) * (1+Fraction)\";\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1711178737105194000\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"origin\": \"openconfig\",\n                        \"elem\": [\n                            {\n                                \"name\": \"components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"PowerSupply1/A\"\n                                }\n                            },\n                            {\n                                \"name\": \"power-supply\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTplbmFibGVkIjp0cnVlLCJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTpjYXBhY2l0eSI6IlJETEFBQT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6aW5wdXQtY3VycmVudCI6IlB2RW02UT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6aW5wdXQtdm9sdGFnZSI6IlExQ0FBQT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6b3V0cHV0LWN1cnJlbnQiOiJQNW43NXc9PSIsIm9wZW5jb25maWctcGxhdGZvcm0tcHN1Om91dHB1dC12b2x0YWdlIjoiUW1GM3p3PT0iLCJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTpvdXRwdXQtcG93ZXIiOiJRb2xBQUE9PSJ9\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"openconfig\",\n                        \"elem\": [\n                            {\n                                \"name\": \"components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"PowerSupply1/B\"\n                                }\n                            },\n                            {\n                                \"name\": \"power-supply\"\n                            },\n                            {\n                                \"name\": \"state\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTplbmFibGVkIjp0cnVlLCJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTpjYXBhY2l0eSI6IlJETEFBQT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6aW5wdXQtY3VycmVudCI6IlBzazNUQT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6aW5wdXQtdm9sdGFnZSI6IlExSEFBQT09Iiwib3BlbmNvbmZpZy1wbGF0Zm9ybS1wc3U6b3V0cHV0LWN1cnJlbnQiOiJQM0FneFE9PSIsIm9wZW5jb25maWctcGxhdGZvcm0tcHN1Om91dHB1dC12b2x0YWdlIjoiUW1GM3p3PT0iLCJvcGVuY29uZmlnLXBsYXRmb3JtLXBzdTpvdXRwdXQtcG93ZXIiOiJRaytBQUE9PSJ9\"\n                    }\n                }\n            ]\n        }\n    },\n    {\n        \"update\": {\n            \"timestamp\": \"1715838159171548000\",\n            \"update\": [\n                {\n                    \"path\": {\n                        \"origin\": \"openconfig\",\n                        \"elem\": [\n                            {\n                                \"name\": \"components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"InletTempSensor1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJpbnN0YW50IjoiMzUuMDAwMDAwIiwiYXZnIjoiMjQuMDAwMDAwIiwibWluIjoiMC4wMDAwMDAiLCJtYXgiOiIzNi4wMDAwMDAiLCJpbnRlcnZhbCI6IjE4MDAwMDAwMDAwMCIsImFsYXJtLXN0YXR1cyI6ZmFsc2UsImFsYXJtLXRocmVzaG9sZCI6MCwiYWxhcm0tc2V2ZXJpdHkiOiJvcGVuY29uZmlnLWFsYXJtLXR5cGVzOk1JTk9SIn0=\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"openconfig\",\n                        \"elem\": [\n                            {\n                                \"name\": \"components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"OutletTempSensor1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJpbnN0YW50IjoiNDQuMDAwMDAwIiwiYXZnIjoiMjkuMDAwMDAwIiwibWluIjoiMC4wMDAwMDAiLCJtYXgiOiI0NC4wMDAwMDAiLCJpbnRlcnZhbCI6IjE4MDAwMDAwMDAwMCIsImFsYXJtLXN0YXR1cyI6ZmFsc2UsImFsYXJtLXRocmVzaG9sZCI6MCwiYWxhcm0tc2V2ZXJpdHkiOiJvcGVuY29uZmlnLWFsYXJtLXR5cGVzOk1JTk9SIn0=\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"openconfig\",\n                        \"elem\": [\n                            {\n                                \"name\": \"components\"\n                            },\n                            {\n                                \"name\": \"component\",\n                                \"key\": {\n                                    \"name\": \"HotSpotTempSensor1\"\n                                }\n                            },\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"jsonIetfVal\": \"eyJpbnN0YW50IjoiNTguMDAwMDAwIiwiYXZnIjoiMzkuMDAwMDAwIiwibWluIjoiMC4wMDAwMDAiLCJtYXgiOiI1OS4wMDAwMDAiLCJpbnRlcnZhbCI6IjE4MDAwMDAwMDAwMCIsImFsYXJtLXN0YXR1cyI6ZmFsc2UsImFsYXJtLXRocmVzaG9sZCI6MCwiYWxhcm0tc2V2ZXJpdHkiOiJvcGVuY29uZmlnLWFsYXJtLXR5cGVzOk1JTk9SIn0=\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15046/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  path_guessing_strategy = \"subscription\"\n  yang_model_paths = [\"testcases/issue_15046/models\"]\n\n  [[inputs.gnmi.subscription]]\n    name = \"psu\"\n    origin = \"openconfig\"\n    path = \"/components/component/power-supply/state\"\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"temp\"\n    origin = \"openconfig\"\n    path = \"/components/component/state/temperature\"\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15546/expected.out",
    "content": "event-stats,path=openconfig-system:/system/openconfig-events:event-stats/state,source=127.0.0.1 state/acked=0u,state/cleared=0u,state/events=4u,state/raised=0u 1718942414831832038\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15546/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1718942414831832038\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"openconfig-system:system\"\n                    },\n                    {\n                        \"name\": \"openconfig-events:event-stats\"\n                    },\n                    {\n                        \"name\": \"state\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"acked\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"cleared\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"events\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"raised\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_15546/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  prefix_tag_key_with_path = true\n\n  [[inputs.gnmi.subscription]]\n    name = \"event-stats\"\n    origin = \"openconfig-system\"\n    path = \"/system/event-stats\"\n    subscription_mode = \"sample\"\n    sample_interval = \"10s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16476/expected.out",
    "content": "ifcounters,path=Ciena:/oc-if:interfaces/oc-if:interface/oc-if:state/oc-if:counters,source=127.0.0.1 in_1024_to_1518_octet_pkts=15680405047u,in_128_to_255_octet_pkts=12809649942u,in_1519_to_2047_octet_pkts=35815850565u,in_2048_to_4095_octet_pkts=0u,in_256_to_511_octet_pkts=5257910993u,in_4096_to_9216_octet_pkts=0u,in_512_to_1023_octet_pkts=6139561818u,in_64_octet_pkts=4u,in_65_to_127_octet_pkts=146456592549u,in_broadcast_pkts=167166u,in_crc_error_pkts=0u,in_discards=236u,in_discards_octets=31492u,in_dropped_octets=31492u,in_dropped_pkts=236u,in_errors=0u,in_jabber_pkts=0u,in_multicast_pkts=76815719u,in_octets=95890972327359u,in_oversize_pkts=0u,in_pkts=222159970919u,in_undersize_pkts=0u,in_unicast_pkts=222082988034u,last_clear=1679547185677412529u,link_flap_events=0u,name=\"\\\"1\\\"\",out_1519_to_2047_octet_pkts=211382493634u,out_2048_to_4095_octet_pkts=0u,out_4096_to_9216_octet_pkts=0u,out_broadcast_pkts=2609579674u,out_errors=0u,out_multicast_pkts=332069076u,out_octets=885293268981054u,out_pkts=677379680498u,out_unicast_pkts=674438031748u 1739206587847000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16476/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": 1739206587847000000,\n            \"prefix\": {\n                \"origin\": \"Ciena\",\n                \"elem\": [\n                    {\n                        \"name\": \"oc-if:interfaces\"\n                    },\n                    {\n                        \"name\": \"oc-if:interface\"\n                    },\n                    {\n                        \"name\": \"oc-if:state\"\n                    },\n                    {\n                        \"name\": \"oc-if:counters\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-1024-to-1518-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 15680405047\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-128-to-255-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 12809649942\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-1519-to-2047-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 35815850565\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-2048-to-4095-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-256-to-511-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 5257910993\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-4096-to-9216-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-512-to-1023-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 6139561818\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-64-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 4\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-65-to-127-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 146456592549\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-broadcast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 167166\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-crc-error-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-discards\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 236\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-discards-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 31492\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-dropped-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 31492\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-dropped-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 236\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-errors\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-jabber-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-multicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 76815719\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 95890972327359\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-oversize-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 222159970919\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-undersize-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"in-unicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 222082988034\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"last-clear\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 1679547185677412529\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"link-flap-events\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"\\\"1\\\"\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-1519-to-2047-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 211382493634\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-2048-to-4095-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-4096-to-9216-octet-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-broadcast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 2609579674\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-errors\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 0\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-multicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 332069076\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-octets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 885293268981054\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 677379680498\n                    }\n                },\n                {\n                    \"path\": {\n                        \"origin\": \"Ciena\",\n                        \"elem\": [\n                            {\n                                \"name\": \"out-unicast-pkts\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": 674438031748\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16476/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  enforce_first_namespace_as_origin = false\n\n  [[inputs.gnmi.subscription]]\n     name = \"ifcounters\"\n     origin = \"Ciena\"\n     path = \"/oc-if:interfaces/oc-if:interface/oc-if:state/oc-if:counters\"\n     subscription_mode = \"sample\"\n     sample_interval = \"30s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16515/expected.out",
    "content": "qmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,source=127.0.0.1 state/parent_ae_name=\"\" 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=0,source=127.0.0.1 egress/bytes=25084650213u,egress/packets=97812973u,egress/peak_buffer_occupancy_bytes=416u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=1,source=127.0.0.1 egress/bytes=0u,egress/packets=0u,egress/peak_buffer_occupancy_bytes=0u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=2,source=127.0.0.1 egress/bytes=10957969881u,egress/packets=105352268u,egress/peak_buffer_occupancy_bytes=208u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=3,source=127.0.0.1 egress/bytes=0u,egress/packets=0u,egress/peak_buffer_occupancy_bytes=0u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=4,source=127.0.0.1 egress/bytes=0u,egress/packets=0u,egress/peak_buffer_occupancy_bytes=0u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=5,source=127.0.0.1 egress/bytes=1020800306u,egress/packets=12027619u,egress/peak_buffer_occupancy_bytes=0u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=6,source=127.0.0.1 egress/bytes=1257881347u,egress/packets=4773346u,egress/peak_buffer_occupancy_bytes=624u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=7,source=127.0.0.1 egress/bytes=0u,egress/packets=0u,egress/peak_buffer_occupancy_bytes=0u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=8,source=127.0.0.1 egress/bytes=8898987190u,egress/packets=75415151u,egress/peak_buffer_occupancy_bytes=208u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\nqmon,name=xe-0/0/0:0,path=/junos/system/linecard/qmon-sw,queue_number=9,source=127.0.0.1 egress/bytes=16919364168u,egress/packets=157255632u,egress/peak_buffer_occupancy_bytes=208u,egress/peak_buffer_occupancy_percent=0u,egress/red_drop_bytes_color_0=0u,egress/red_drop_bytes_color_1=0u,egress/red_drop_bytes_color_2=0u,egress/red_drop_bytes_color_3=0u,egress/red_drop_packets_color_0=0u,egress/red_drop_packets_color_1=0u,egress/red_drop_packets_color_2=0u,egress/red_drop_packets_color_3=0u,egress/tail_drop_bytes=0u,egress/tail_drop_packets=0u 1739811071353000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16515/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1739811071353000000\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"junos\"\n                    },\n                    {\n                        \"name\": \"system\"\n                    },\n                    {\n                        \"name\": \"linecard\"\n                    },\n                    {\n                        \"name\": \"qmon-sw\"\n                    },\n                    {\n                        \"key\": {\n                            \"name\": \"xe-0/0/0:0\"\n                        }\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"state\"\n                            },\n                            {\n                                \"name\": \"parent_ae_name\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"416\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"97812973\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"25084650213\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"208\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"105352268\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"10957969881\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"4\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"12027619\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1020800306\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"5\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"624\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"4773346\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"1257881347\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"6\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"7\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"208\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"75415151\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"8898987190\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"8\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"208\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"peak-buffer-occupancy-percent\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"157255632\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"16919364168\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-packets\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"tail-drop-bytes\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-0\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-2\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-packets-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"egress\"\n                            },\n                            {\n                                \"key\": {\n                                    \"queue-number\": \"9\"\n                                }\n                            },\n                            {\n                                \"name\": \"red-drop-bytes-color-3\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                }\n            ]\n        },\n        \"extension\": [\n            {\n                \"registeredExt\": {\n                    \"id\": 1,\n                    \"msg\": \"ChBBQkJWRFBBSjAxLkJSLkJSIgtzZW5zb3JfMTAwNSofL2p1bm9zL3N5c3RlbS9saW5lY2FyZC9xbW9uLXN3LzIfL2p1bm9zL3N5c3RlbS9saW5lY2FyZC9xbW9uLXN3LzoDUEZFQICAgAFggsvIptEy\"\n                }\n            }\n        ]\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_16515/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n\n  [[inputs.gnmi.subscription]]\n    name = \"qmon\"\n    origin = \"openconfig\"\n    path = \"/junos/system/linecard/qmon-sw\"\n    subscription_mode = \"sample\"\n    sample_interval = \"60s\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17154/expected.out",
    "content": "snmp_if_index,component=picd,component_id=0,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 snmp_if_index=513u 1749595672396389842\noptics,component=picd,component_id=0,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 frequency_error=\"NA\",laser_bias_current_high_alarm_threshold=120,laser_bias_current_high_warning_threshold=110,laser_bias_current_low_alarm_threshold=34.84600067138672,laser_bias_current_low_warning_threshold=40.95899963378906,laser_output_power_high_alarm_threshold_dbm=8.09000015258789,laser_output_power_high_warning_threshold_dbm=6.090000152587891,laser_output_power_low_alarm_threshold_dbm=-6.690000057220459,laser_output_power_low_warning_threshold_dbm=-3.690000057220459,laser_rx_power_high_alarm_threshold_dbm=8.09000015258789,laser_rx_power_high_warning_threshold_dbm=6.090000152587891,laser_rx_power_low_alarm_threshold_dbm=-13,laser_rx_power_low_warning_threshold_dbm=-10,module_temp=36.65999984741211,module_temp_high_alarm=false,module_temp_high_alarm_threshold=80,module_temp_high_warning=false,module_temp_high_warning_threshold=75,module_temp_low_alarm=false,module_temp_low_alarm_threshold=-10,module_temp_low_warning=false,module_temp_low_warning_threshold=-5,optics_type=32u,tec_fault=\"NA\",tx_dither=\"NA\",tx_tune_alarm=\"NA\",w_unlocked_alarm=\"NA\",wavelength_channel=\"NA\",wavelength_error=\"NA\",wavelength_setpoint=\"NA\" 1749595672396389842\noptics,component=picd,component_id=0,lane_number=0,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 lanediags/lane/lane_laser_bias_current=90,lanediags/lane/lane_laser_bias_current_high_alarm=false,lanediags/lane/lane_laser_bias_current_high_warning=false,lanediags/lane/lane_laser_bias_current_low_alarm=false,lanediags/lane/lane_laser_bias_current_low_warning=false,lanediags/lane/lane_laser_output_power_dbm=2.319999933242798,lanediags/lane/lane_laser_output_power_high_alarm=false,lanediags/lane/lane_laser_output_power_high_warning=false,lanediags/lane/lane_laser_output_power_low_alarm=false,lanediags/lane/lane_laser_output_power_low_warning=false,lanediags/lane/lane_laser_receiver_power_dbm=-0.07000000029802322,lanediags/lane/lane_laser_receiver_power_high_alarm=false,lanediags/lane/lane_laser_receiver_power_high_warning=false,lanediags/lane/lane_laser_receiver_power_low_alarm=false,lanediags/lane/lane_laser_receiver_power_low_warning=false,lanediags/lane/lane_laser_temperature=55.34000015258789,lanediags/lane/lane_number=0i,lanediags/lane/lane_rx_loss_of_signal_alarm=false,lanediags/lane/lane_tx_laser_disabled_alarm=false,lanediags/lane/lane_tx_loss_of_signal_alarm=false,lanediags/lane/media_fec_corr_bits=0u,lanediags/lane/media_fec_uncorr_blocks=0u 1749595672396389842\noptics,component=picd,component_id=0,lane_number=1,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 lanediags/lane/lane_laser_bias_current=90,lanediags/lane/lane_laser_bias_current_high_alarm=false,lanediags/lane/lane_laser_bias_current_high_warning=false,lanediags/lane/lane_laser_bias_current_low_alarm=false,lanediags/lane/lane_laser_bias_current_low_warning=false,lanediags/lane/lane_laser_output_power_dbm=3.240000009536743,lanediags/lane/lane_laser_output_power_high_alarm=false,lanediags/lane/lane_laser_output_power_high_warning=false,lanediags/lane/lane_laser_output_power_low_alarm=false,lanediags/lane/lane_laser_output_power_low_warning=false,lanediags/lane/lane_laser_receiver_power_dbm=-0.07000000029802322,lanediags/lane/lane_laser_receiver_power_high_alarm=false,lanediags/lane/lane_laser_receiver_power_high_warning=false,lanediags/lane/lane_laser_receiver_power_low_alarm=false,lanediags/lane/lane_laser_receiver_power_low_warning=false,lanediags/lane/lane_laser_temperature=55.34000015258789,lanediags/lane/lane_number=1i,lanediags/lane/lane_rx_loss_of_signal_alarm=false,lanediags/lane/lane_tx_laser_disabled_alarm=false,lanediags/lane/lane_tx_loss_of_signal_alarm=false,lanediags/lane/media_fec_corr_bits=0u,lanediags/lane/media_fec_uncorr_blocks=0u 1749595672396389842\noptics,component=picd,component_id=0,lane_number=2,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 lanediags/lane/lane_laser_bias_current=90,lanediags/lane/lane_laser_bias_current_high_alarm=false,lanediags/lane/lane_laser_bias_current_high_warning=false,lanediags/lane/lane_laser_bias_current_low_alarm=false,lanediags/lane/lane_laser_bias_current_low_warning=false,lanediags/lane/lane_laser_output_power_dbm=2.7699999809265137,lanediags/lane/lane_laser_output_power_high_alarm=false,lanediags/lane/lane_laser_output_power_high_warning=false,lanediags/lane/lane_laser_output_power_low_alarm=false,lanediags/lane/lane_laser_output_power_low_warning=false,lanediags/lane/lane_laser_receiver_power_dbm=0.8199999928474426,lanediags/lane/lane_laser_receiver_power_high_alarm=false,lanediags/lane/lane_laser_receiver_power_high_warning=false,lanediags/lane/lane_laser_receiver_power_low_alarm=false,lanediags/lane/lane_laser_receiver_power_low_warning=false,lanediags/lane/lane_laser_temperature=55.34000015258789,lanediags/lane/lane_number=2i,lanediags/lane/lane_rx_loss_of_signal_alarm=false,lanediags/lane/lane_tx_laser_disabled_alarm=false,lanediags/lane/lane_tx_loss_of_signal_alarm=false,lanediags/lane/media_fec_corr_bits=0u,lanediags/lane/media_fec_uncorr_blocks=0u 1749595672396389842\noptics,component=picd,component_id=0,lane_number=3,name=et-0/0/0,path=/interfaces/interface,source=127.0.0.1,sub_component_id=0 lanediags/lane/lane_laser_bias_current=90,lanediags/lane/lane_laser_bias_current_high_alarm=false,lanediags/lane/lane_laser_bias_current_high_warning=false,lanediags/lane/lane_laser_bias_current_low_alarm=false,lanediags/lane/lane_laser_bias_current_low_warning=false,lanediags/lane/lane_laser_output_power_dbm=2.5199999809265137,lanediags/lane/lane_laser_output_power_high_alarm=false,lanediags/lane/lane_laser_output_power_high_warning=false,lanediags/lane/lane_laser_output_power_low_alarm=false,lanediags/lane/lane_laser_output_power_low_warning=false,lanediags/lane/lane_laser_receiver_power_dbm=1.5299999713897705,lanediags/lane/lane_laser_receiver_power_high_alarm=false,lanediags/lane/lane_laser_receiver_power_high_warning=false,lanediags/lane/lane_laser_receiver_power_low_alarm=false,lanediags/lane/lane_laser_receiver_power_low_warning=false,lanediags/lane/lane_laser_temperature=55.34000015258789,lanediags/lane/lane_number=3i,lanediags/lane/lane_rx_loss_of_signal_alarm=false,lanediags/lane/lane_tx_laser_disabled_alarm=false,lanediags/lane/lane_tx_loss_of_signal_alarm=false,lanediags/lane/media_fec_corr_bits=0u,lanediags/lane/media_fec_uncorr_blocks=0u 1749595672396389842\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17154/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1749595672396389842\",\n            \"prefix\": {\n                \"elem\": [\n                    {\n                        \"name\": \"interfaces\"\n                    },\n                    {\n                        \"name\": \"interface\",\n                        \"key\": {\n                            \"name\": \"et-0/0/0\"\n                        }\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"snmp_if_index\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"513\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"optics_type\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"32\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 36.66\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_high_alarm_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 80\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_low_alarm_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -10\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_high_warning_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 75\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_low_warning_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -5\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_output_power_high_alarm_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 8.09\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_output_power_low_alarm_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -6.69\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_output_power_high_warning_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 6.09\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_output_power_low_warning_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -3.69\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_rx_power_high_alarm_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 8.09\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_rx_power_low_alarm_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -13\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_rx_power_high_warning_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 6.09\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_rx_power_low_warning_threshold_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": -10\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_bias_current_high_alarm_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 120\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_bias_current_low_alarm_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 34.846\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_bias_current_high_warning_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 110\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"laser_bias_current_low_warning_threshold\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 40.959\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"module_temp_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"wavelength_channel\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"wavelength_setpoint\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"tx_dither\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"frequency_error\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"wavelength_error\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"tec_fault\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"w_unlocked_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"tx_tune_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"stringVal\": \"NA\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_number\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 55.34\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"QBR64Q==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"vY9cKQ==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 90\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_rx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_laser_disabled_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_corr_bits\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"0\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_uncorr_blocks\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_number\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"1\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 55.34\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"QE9cKQ==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"vY9cKQ==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 90\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_rx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_laser_disabled_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_corr_bits\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"1\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_uncorr_blocks\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_number\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"2\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 55.34\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"QDFHrg==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"P1HrhQ==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 90\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_rx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_laser_disabled_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_corr_bits\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"2\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_uncorr_blocks\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_number\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"intVal\": \"3\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_temperature\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 55.34\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"QCFHrg==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_dbm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"bytesVal\": \"P8PXCg==\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"floatVal\": 90\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_output_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_receiver_power_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_high_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_laser_bias_current_low_warning\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_rx_loss_of_signal_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"lane_tx_laser_disabled_alarm\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": false\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_corr_bits\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                },\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"optics\"\n                            },\n                            {\n                                \"name\": \"lanediags\"\n                            },\n                            {\n                                \"name\": \"lane\",\n                                \"key\": {\n                                    \"lane_number\": \"3\"\n                                }\n                            },\n                            {\n                                \"name\": \"media_fec_uncorr_blocks\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"uintVal\": \"0\"\n                    }\n                }\n            ],\n            \"atomic\": true\n        },\n        \"extension\": [\n            {\n                \"registeredExt\": {\n                    \"id\": 1,\n                    \"msg\": \"ChZORURMQkJSSjExLkRVS0UuQVQtUkUwIgtzZW5zb3JfMTAwMCoeL2p1bm9zL3N5c3RlbS9saW5lY2FyZC9vcHRpY3MvMh4vanVub3Mvc3lzdGVtL2xpbmVjYXJkL29wdGljcy86BHBpY2RAgICAAWDXnp3g9TI=\"\n                }\n            }\n        ]\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17154/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n  vendor_specific = [\"juniper_header\"]\n\n  [inputs.gnmi.aliases]\n    optics = \"/interfaces/interface/optics\"\n    snmp_if_index = \"/interfaces/interface/snmp_if_index\"\n\n  [[inputs.gnmi.subscription]]\n      name = \"optics\"\n      origin = \"junos\"\n      path = \"/junos/system/linecard/optics\"\n      subscription_mode = \"sample\"\n      sample_interval = \"60s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17279/expected.out",
    "content": "igmpsnooping900,path=eos_native:/Sysdb/bridging/igmpsnooping/forwarding/status/vlanStatus/900/ethGroup/01:00:5e:1e:1e:1e/intf,source=127.0.0.1 900/ethGroup/01:00:5e:1e:1e:1e/intf/Ethernet1=true 1751459159001750895\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17279/responses.json",
    "content": "[\n    {\n        \"update\": {\n            \"timestamp\": \"1751459159001750895\",\n            \"prefix\": {\n                \"origin\": \"eos_native\",\n                \"elem\": [\n                    {\n                        \"name\": \"Sysdb\"\n                    },\n                    {\n                        \"name\": \"bridging\"\n                    },\n                    {\n                        \"name\": \"igmpsnooping\"\n                    },\n                    {\n                        \"name\": \"forwarding\"\n                    },\n                    {\n                        \"name\": \"status\"\n                    },\n                    {\n                        \"name\": \"vlanStatus\"\n                    },\n                    {\n                        \"name\": \"900\"\n                    },\n                    {\n                        \"name\": \"ethGroup\"\n                    },\n                    {\n                        \"name\": \"01:00:5e:1e:1e:1e\"\n                    },\n                    {\n                        \"name\": \"intf\"\n                    }\n                ]\n            },\n            \"update\": [\n                {\n                    \"path\": {\n                        \"elem\": [\n                            {\n                                \"name\": \"Ethernet1\"\n                            }\n                        ]\n                    },\n                    \"val\": {\n                        \"boolVal\": true\n                    }\n                }\n            ]\n        }\n    }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17279/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses = [\"dummy\"]\n\n  [[inputs.gnmi.subscription]]\n    name = \"igmpsnooping900\"\n    origin = \"eos_native\"\n    subscription_mode = \"sample\"\n    path = \"/Sysdb/bridging/igmpsnooping/forwarding/status/vlanStatus\"\n    sample_interval = \"10s\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17412/expected.out",
    "content": "interface_state_change,name=Eth-Trunk5.1234,source=127.0.0.1 oper_status=\"down\" 1753972839609000000\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17412/responses.json",
    "content": "[\n  {\n    \"update\": {\n      \"timestamp\": \"1753972805570000000\",\n      \"update\": [\n        {}\n      ],\n      \"delete\": [\n        {\n          \"elem\": [\n            {\n              \"name\": \"huawei-ifm:ifm\"\n            },\n            {\n              \"name\": \"interfaces\"\n            },\n            {\n              \"name\": \"interface\",\n              \"key\": {\n                \"name\": \"Eth-Trunk5.1234\"\n              }\n            },\n            {\n              \"name\": \"dynamic\"\n            },\n            {\n              \"name\": \"oper-status\"\n            }\n          ]\n        }\n      ]\n    }\n  },\n  {\n    \"update\": {\n      \"timestamp\": \"1753972839609000000\",\n      \"update\": [\n        {\n          \"path\": {\n            \"elem\": [\n              {\n                \"name\": \"huawei-ifm:ifm\"\n              },\n              {\n                \"name\": \"interfaces\"\n              },\n              {\n                \"name\": \"interface\",\n                \"key\": {\n                  \"name\": \"Eth-Trunk5.1234\"\n                }\n              },\n              {\n                \"name\": \"dynamic\"\n              },\n              {\n                \"name\": \"oper-status\"\n              }\n            ]\n          },\n          \"val\": {\n            \"jsonVal\": \"ImRvd24i\"\n          }\n        }\n      ],\n      \"delete\": [\n        {}\n      ]\n    }\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17412/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  redial        = \"10s\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"interface_state_change\"\n    path = \"huawei-ifm:ifm/interfaces/interface/dynamic/oper-status\"\n    subscription_mode = \"on_change\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17622/expected.out",
    "content": "network,name=default,source=127.0.0.1,prefix=192.168.170.170/32 operation=\"delete\" 1772145797466116249"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17622/responses.json",
    "content": "[\n  {\n    \"update\": {\n      \"timestamp\": \"1772145797466116249\",\n      \"delete\": [\n        {\n          \"elem\": [\n            {\n              \"name\": \"network-instances\"\n            },\n            {\n              \"name\": \"network-instance\",\n              \"key\": {\n                \"name\": \"default\"\n              }\n            },\n            {\n              \"name\": \"afts\"\n            },\n            {\n              \"name\": \"ipv4-unicast\"\n            },\n            {\n              \"name\": \"ipv4-entry\",\n              \"key\": {\n                \"prefix\": \"192.168.170.170/32\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  }\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/issue_17622/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  redial        = \"10s\"\n  emit_delete_metrics = true\n\n  [[inputs.gnmi.subscription]]\n    name = \"network\"\n    path = \"network-instances/network-instance\"\n    subscription_mode = \"on_change\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_name_based/expected.out",
    "content": "interfaces_logical_status,descr/description=Loopback,index=0,name=lo0,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667238697959\ninterfaces_logical_status,descr/description=Local:Mgmt,index=312,name=irb,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667241404442\ninterfaces_logical_status,descr/description=Core:GRE:abc-def-dmn1-staging:{GRE_Tunnel},index=2,name=gr-0/0/0,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667243155079\ninterfaces_logical_status,descr/description=Core:PacketFabric:abc-def-dmn1-staging:{PF-BC-DAL-SFO-12345},index=1410,name=xe-0/1/1,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667250570407\ninterfaces_logical_status,descr/description=Core:PacketFabric:uvw-xyz-dmn1-staging:{PF-BC-CHI-SFO-67890},index=16386,name=xe-0/1/5,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"LOWER_LAYER_DOWN\" 1674081667251795605\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_name_based/responses.json",
    "content": "[\n    {\"update\":{\"timestamp\":\"1674081667224189253\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"lo0\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"0\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Loopback\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667226968153\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"irb\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"312\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Local:Mgmt\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667228936729\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"gr-0/0/0\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"3\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Core:GRE:abc-def-dmn1-staging:{GRE_Tunnel}\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667236178737\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1410\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Core:PacketFabric:abc-def-dmn1-staging:{PF-BC-DAL-SFO-12345}\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667236377628\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/5\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1412\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Core:PacketFabric:uvw-xyz-dmn1-staging:{PF-BC-CHI-SFO-67890}\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667238697959\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"lo0\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"0\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667241404442\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"irb\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"312\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667243155079\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"gr-0/0/0\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"2\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667250570407\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1410\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667251795605\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/5\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"16386\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"LOWER_LAYER_DOWN\"}}]}},\n    {\"syncResponse\":true}\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_name_based/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  redial        = \"10s\"\n\n  [[inputs.gnmi.tag_subscription]]\n    name = \"descr\"\n    origin = \"openconfig\"\n    path = \"/interfaces/interface/subinterfaces/subinterface/state/description\"\n    subscription_mode = \"on_change\"\n\n  [[inputs.gnmi.subscription]]\n    name = \"interfaces_logical_status\"\n    origin = \"openconfig\"\n    path = \"/interfaces/interface/subinterfaces/subinterface/state/oper-status\"\n    subscription_mode = \"on_change\""
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_subinterfaces/expected.out",
    "content": "interfaces_logical_status,descr/description=Core:PacketFabric:abc-def-dmn1-staging:{PF-BC-DAL-SFO-12345},index=1410,name=xe-0/1/1,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667250570407\ninterfaces_logical_status,descr/description=Core:PacketFabric:uvw-xyz-dmn1-staging:{PF-BC-CHI-SFO-67890},index=1412,name=xe-0/1/1,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667250784367\ninterfaces_logical_status,index=32767,name=xe-0/1/1,path=/interfaces/interface/subinterfaces/subinterface,source=127.0.0.1 oper_status=\"UP\" 1674081667250994907\n"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_subinterfaces/responses.json",
    "content": "[\n    {\"update\":{\"timestamp\":\"1674081667236178737\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1410\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Core:PacketFabric:abc-def-dmn1-staging:{PF-BC-DAL-SFO-12345}\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667236377628\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1412\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"Core:PacketFabric:uvw-xyz-dmn1-staging:{PF-BC-CHI-SFO-67890}\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667236582084\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"32767\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"description\"}]}, \"val\":{\"stringVal\":\"\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667250570407\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1410\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667250784367\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"1412\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"update\":{\"timestamp\":\"1674081667250994907\", \"prefix\":{\"elem\":[{\"name\":\"interfaces\"}, {\"name\":\"interface\", \"key\":{\"name\":\"xe-0/1/1\"}}, {\"name\":\"subinterfaces\"}, {\"name\":\"subinterface\", \"key\":{\"index\":\"32767\"}}]}, \"update\":[{\"path\":{\"elem\":[{\"name\":\"state\"}, {\"name\":\"oper-status\"}]}, \"val\":{\"stringVal\":\"UP\"}}]}},\n    {\"syncResponse\":true}\n]"
  },
  {
    "path": "plugins/inputs/gnmi/testcases/tagging_subinterfaces/telegraf.conf",
    "content": "[[inputs.gnmi]]\n  addresses     = [\"dummy\"]\n  redial        = \"10s\"\n\n  [[inputs.gnmi.tag_subscription]]\n    name = \"descr\"\n    origin = \"openconfig\"\n    path = \"/interfaces/interface/subinterfaces/subinterface/state/description\"\n    subscription_mode = \"on_change\"\n    elements = [\"interface\", \"subinterface\"]\n\n  [[inputs.gnmi.subscription]]\n    name = \"interfaces_logical_status\"\n    origin = \"openconfig\"\n    path = \"/interfaces/interface/subinterfaces/subinterface/state/oper-status\"\n    subscription_mode = \"on_change\"\n"
  },
  {
    "path": "plugins/inputs/gnmi/update_fields.go",
    "content": "package gnmi\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/openconfig/gnmi/proto/gnmi\"\n\t\"github.com/openconfig/gnmi/value\"\n)\n\ntype keyValuePair struct {\n\tkey   []string\n\tvalue interface{}\n}\n\ntype updateField struct {\n\tpath  *pathInfo\n\tvalue interface{}\n}\n\nfunc (h *handler) newFieldsFromUpdate(path *pathInfo, update *gnmi.Update) ([]updateField, error) {\n\tif update.Val == nil || update.Val.Value == nil {\n\t\treturn []updateField{{path: path}}, nil\n\t}\n\n\t// Apply some special handling for special types\n\tswitch v := update.Val.Value.(type) {\n\tcase *gnmi.TypedValue_AsciiVal: // not handled in ToScalar\n\t\treturn []updateField{{path, v.AsciiVal}}, nil\n\tcase *gnmi.TypedValue_BytesVal:\n\t\t// Try to decode the bytes as float if we do have the right amount of\n\t\t// data. Otherwise, or if the decoding fails, encode the data as base64\n\t\t// to pass it on to later stages.\n\t\tif len(v.BytesVal) == 4 {\n\t\t\treturn []updateField{{path, math.Float32frombits(binary.BigEndian.Uint32(v.BytesVal))}}, nil\n\t\t}\n\t\treturn []updateField{{path, base64.StdEncoding.EncodeToString(v.BytesVal)}}, nil\n\tcase *gnmi.TypedValue_JsonVal: // requires special path handling\n\t\treturn h.processJSON(path, v.JsonVal)\n\tcase *gnmi.TypedValue_JsonIetfVal: // requires special path handling\n\t\treturn h.processJSONIETF(path, v.JsonIetfVal)\n\t}\n\n\t// Convert the protobuf \"oneof\" data to a Golang type.\n\tnativeType, err := value.ToScalar(update.Val)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []updateField{{path, nativeType}}, nil\n}\n\nfunc (h *handler) processJSON(path *pathInfo, data []byte) ([]updateField, error) {\n\tvar nested interface{}\n\tif err := json.Unmarshal(data, &nested); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse JSON value: %w\", err)\n\t}\n\n\t// Flatten the JSON data to get a key-value map\n\tentries := flatten(nested)\n\n\t// Create an update-field with the complete path for all entries\n\tfields := make([]updateField, 0, len(entries))\n\tfor _, entry := range entries {\n\t\tp := path.appendSegments(entry.key...)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\tp.enforceFirstNamespaceAsOrigin()\n\t\t}\n\n\t\tfields = append(fields, updateField{\n\t\t\tpath:  p,\n\t\t\tvalue: entry.value,\n\t\t})\n\t}\n\n\treturn fields, nil\n}\n\nfunc (h *handler) processJSONIETF(path *pathInfo, data []byte) ([]updateField, error) {\n\tvar nested interface{}\n\tif err := json.Unmarshal(data, &nested); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse JSON value: %w\", err)\n\t}\n\n\t// Flatten the JSON data to get a key-value map\n\tentries := flatten(nested)\n\n\t// Lookup the data in the YANG model if any\n\tif h.decoder != nil {\n\t\tfor i, e := range entries {\n\t\t\tvar namespace, identifier string\n\t\t\tfor _, k := range e.key {\n\t\t\t\tif n, _, found := strings.Cut(k, \":\"); found {\n\t\t\t\t\tnamespace = n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// IETF nodes referencing YANG entries require a namespace\n\t\t\tif namespace == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif a, b, found := strings.Cut(e.key[len(e.key)-1], \":\"); !found {\n\t\t\t\tidentifier = a\n\t\t\t} else {\n\t\t\t\tidentifier = b\n\t\t\t}\n\n\t\t\tif decoded, err := h.decoder.DecodeLeafElement(namespace, identifier, e.value); err != nil {\n\t\t\t\th.log.Debugf(\"Decoding %s:%s failed: %v\", namespace, identifier, err)\n\t\t\t} else {\n\t\t\t\tentries[i].value = decoded\n\t\t\t}\n\t\t}\n\t}\n\n\tfields := make([]updateField, 0, len(entries))\n\tfor _, entry := range entries {\n\t\tp := path.appendSegments(entry.key...)\n\t\tif h.enforceFirstNamespaceAsOrigin {\n\t\t\tp.enforceFirstNamespaceAsOrigin()\n\t\t}\n\n\t\t// Try to lookup the full path to decode the field according to the\n\t\t// YANG model if any\n\t\tif h.decoder != nil {\n\t\t\torigin, fieldPath := p.path()\n\t\t\tif decoded, err := h.decoder.DecodePathElement(origin, fieldPath, entry.value); err != nil {\n\t\t\t\th.log.Debugf(\"Decoding %s failed: %v\", p, err)\n\t\t\t} else {\n\t\t\t\tentry.value = decoded\n\t\t\t}\n\t\t}\n\n\t\t// Create an update-field with the complete path for all entries\n\t\tfields = append(fields, updateField{\n\t\t\tpath:  p,\n\t\t\tvalue: entry.value,\n\t\t})\n\t}\n\n\treturn fields, nil\n}\n\nfunc flatten(nested interface{}) []keyValuePair {\n\tvar values []keyValuePair\n\n\tswitch n := nested.(type) {\n\tcase map[string]interface{}:\n\t\tfor k, child := range n {\n\t\t\tfor _, c := range flatten(child) {\n\t\t\t\tvalues = append(values, keyValuePair{\n\t\t\t\t\tkey:   append([]string{k}, c.key...),\n\t\t\t\t\tvalue: c.value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\tcase []interface{}:\n\t\tfor i, child := range n {\n\t\t\tk := strconv.Itoa(i)\n\t\t\tfor _, c := range flatten(child) {\n\t\t\t\tvalues = append(values, keyValuePair{\n\t\t\t\t\tkey:   append([]string{k}, c.key...),\n\t\t\t\t\tvalue: c.value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tvalues = append(values, keyValuePair{value: n})\n\t}\n\n\treturn values\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/README.md",
    "content": "# Google Cloud Storage Input Plugin\n\nThis plugin will collect metrics from the given [Google Cloud Storage][gcs]\nbuckets in any of the supported [data formats][data_formats].\n\n⭐ Telegraf v1.25.0\n🏷️ cloud, datastore\n💻 all\n\n[gcs]: https://cloud.google.com/storage\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather metrics by iterating the files located on a Cloud Storage Bucket.\n[[inputs.google_cloud_storage]]\n  ## Required. Name of Cloud Storage bucket to ingest metrics from.\n  bucket = \"my-bucket\"\n\n  ## Optional. Prefix of Cloud Storage bucket keys to list metrics from.\n  # key_prefix = \"my-bucket\"\n\n  ## Key that will store the offsets in order to pick up where the ingestion was left.\n  offset_key = \"offset_key\"\n\n  ## Key that will store the offsets in order to pick up where the ingestion was left.\n  objects_per_iteration = 10\n\n  ## Required. Data format to consume.\n  ## Each data format has its own unique set of configuration options.\n  ## Read more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Optional. Filepath for GCP credentials JSON file to authorize calls to\n  ## Google Cloud Storage APIs. If not set explicitly, Telegraf will attempt to use\n  ## Application Default Credentials, which is preferred.\n  # credentials_file = \"path/to/my/creds.json\"\n```\n\n## Metrics\n\nMeasurements will reside on Google Cloud Storage with the format specified, for\nexample like\n\n```json\n{\n  \"metrics\": [\n    {\n      \"fields\": {\n        \"cosine\": 10,\n        \"sine\": -1.0975806427415925e-12\n      },\n      \"name\": \"cpu\",\n      \"tags\": {\n        \"datacenter\": \"us-east-1\",\n        \"host\": \"localhost\"\n      },\n      \"timestamp\": 1604148850990\n    }\n  ]\n}\n```\n\nwhen the [data format][data_formats] is set to `json`.\n\n## Example Output\n\n```text\ngoogle_cloud_storage,datacenter=us-east-1,host=localhost cosine=10,sine=-1.0975806427415925e-12 1604148850990000000\n```\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/google_cloud_storage.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage gcs\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"cloud.google.com/go/storage\"\n\t\"golang.org/x/oauth2/google\"\n\t\"google.golang.org/api/iterator\"\n\t\"google.golang.org/api/option\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon_gcp \"github.com/influxdata/telegraf/plugins/common/gcp\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nconst (\n\temulatorHostEnv  = \"STORAGE_EMULATOR_HOST\"\n\tdefaultOffSetKey = \"offset-key.json\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype GCS struct {\n\tCredentialsFile     string          `toml:\"credentials_file\"`\n\tBucket              string          `toml:\"bucket\"`\n\tPrefix              string          `toml:\"key_prefix\"`\n\tOffsetKey           string          `toml:\"offset_key\"`\n\tObjectsPerIteration int             `toml:\"objects_per_iteration\"`\n\tLog                 telegraf.Logger `toml:\"-\"`\n\n\toffSet offSet\n\tparser telegraf.Parser\n\tclient *storage.Client\n\tctx    context.Context\n}\n\ntype offSet struct {\n\tOffSet string `json:\"offSet\"`\n}\n\nfunc (gcs *GCS) Init() error {\n\tgcs.ctx = context.Background()\n\terr := gcs.setUpClient()\n\tif err != nil {\n\t\tgcs.Log.Error(\"Could not create client\", err)\n\t\treturn err\n\t}\n\n\treturn gcs.setOffset()\n}\n\nfunc (*GCS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (gcs *GCS) SetParser(parser telegraf.Parser) {\n\tgcs.parser = parser\n}\n\nfunc (gcs *GCS) Gather(acc telegraf.Accumulator) error {\n\tquery := gcs.createQuery()\n\n\tbucketName := gcs.Bucket\n\tbucket := gcs.client.Bucket(bucketName)\n\tit := bucket.Objects(gcs.ctx, &query)\n\n\tprocessed := 0\n\n\tvar name string\n\tfor {\n\t\tattrs, err := it.Next()\n\n\t\tif errors.Is(err, iterator.Done) {\n\t\t\tgcs.Log.Infof(\"Iterated all the keys\")\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\tgcs.Log.Errorf(\"Error during iteration of keys: %v\", err)\n\t\t\treturn err\n\t\t}\n\n\t\tname = attrs.Name\n\n\t\tif !gcs.shouldIgnore(name) {\n\t\t\tif err := gcs.processMeasurementsInObject(name, bucket, acc); err != nil {\n\t\t\t\tgcs.Log.Errorf(\"Could not process object %q in bucket %q: %v\", name, bucketName, err)\n\t\t\t\tacc.AddError(fmt.Errorf(\"could not process object %q in bucket %q: %w\", name, bucketName, err))\n\t\t\t}\n\t\t}\n\n\t\tprocessed++\n\n\t\tif gcs.reachedThreshlod(processed) {\n\t\t\treturn gcs.updateOffset(bucket, name)\n\t\t}\n\t}\n\n\treturn gcs.updateOffset(bucket, name)\n}\n\nfunc (gcs *GCS) createQuery() storage.Query {\n\tif gcs.offSet.isPresent() {\n\t\treturn storage.Query{Prefix: gcs.Prefix, StartOffset: gcs.offSet.OffSet}\n\t}\n\n\treturn storage.Query{Prefix: gcs.Prefix}\n}\n\nfunc (gcs *GCS) shouldIgnore(name string) bool {\n\treturn gcs.offSet.OffSet == name || gcs.OffsetKey == name\n}\n\nfunc (gcs *GCS) processMeasurementsInObject(name string, bucket *storage.BucketHandle, acc telegraf.Accumulator) error {\n\tgcs.Log.Debugf(\"Fetching key: %s\", name)\n\tr, err := bucket.Object(name).NewReader(gcs.ctx)\n\tdefer gcs.closeReader(r)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmetrics, err := gcs.fetchedMetrics(r)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, metric := range metrics {\n\t\tacc.AddFields(metric.Name(), metric.Fields(), metric.Tags(), metric.Time())\n\t}\n\n\treturn nil\n}\n\nfunc (gcs *GCS) fetchedMetrics(r *storage.Reader) ([]telegraf.Metric, error) {\n\tbuf := new(bytes.Buffer)\n\tif _, err := buf.ReadFrom(r); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn gcs.parser.Parse(buf.Bytes())\n}\n\nfunc (gcs *GCS) reachedThreshlod(processed int) bool {\n\treturn gcs.ObjectsPerIteration != 0 && processed >= gcs.ObjectsPerIteration\n}\n\nfunc (gcs *GCS) updateOffset(bucket *storage.BucketHandle, name string) error {\n\tif gcs.shouldIgnore(name) {\n\t\treturn nil\n\t}\n\n\toffsetModel := newOffset(name)\n\tmarshalled, err := json.Marshal(offsetModel)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffsetKey := bucket.Object(gcs.OffsetKey)\n\twriter := offsetKey.NewWriter(gcs.ctx)\n\twriter.ContentType = \"application/json\"\n\tdefer writer.Close()\n\n\tif _, err := writer.Write(marshalled); err != nil {\n\t\treturn err\n\t}\n\n\tgcs.offSet = *offsetModel\n\n\treturn nil\n}\n\nfunc (gcs *GCS) setUpClient() error {\n\tif endpoint, present := os.LookupEnv(emulatorHostEnv); present {\n\t\treturn gcs.setUpLocalClient(endpoint)\n\t}\n\n\treturn gcs.setUpDefaultClient()\n}\n\nfunc (gcs *GCS) setUpLocalClient(endpoint string) error {\n\tnoAuth := option.WithoutAuthentication()\n\tendpoints := option.WithEndpoint(\"http://\" + endpoint)\n\tclient, err := storage.NewClient(gcs.ctx, noAuth, endpoints)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgcs.client = client\n\treturn nil\n}\n\nfunc (gcs *GCS) setUpDefaultClient() error {\n\tvar credentialsOption option.ClientOption\n\n\tif gcs.CredentialsFile != \"\" {\n\t\tcredType, err := common_gcp.ParseCredentialType(gcs.CredentialsFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse credential file type: %w\", err)\n\t\t}\n\t\tcredentialsOption = option.WithAuthCredentialsFile(option.CredentialsType(credType), gcs.CredentialsFile)\n\t} else {\n\t\tcreds, err := google.FindDefaultCredentials(gcs.ctx, storage.ScopeReadOnly)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"unable to find GCP Application Default Credentials: %v.\"+\n\t\t\t\t\t\"Either set ADC or provide CredentialsFile config\", err)\n\t\t}\n\t\tcredentialsOption = option.WithCredentials(creds)\n\t}\n\n\tclient, err := storage.NewClient(gcs.ctx, credentialsOption)\n\tgcs.client = client\n\treturn err\n}\n\nfunc (gcs *GCS) setOffset() error {\n\tif gcs.client == nil {\n\t\treturn errors.New(\"cannot set offset if client is not set\")\n\t}\n\n\tif gcs.OffsetKey != \"\" {\n\t\tgcs.OffsetKey = gcs.Prefix + gcs.OffsetKey\n\t} else {\n\t\tgcs.OffsetKey = gcs.Prefix + defaultOffSetKey\n\t}\n\n\tbtk := gcs.client.Bucket(gcs.Bucket)\n\tobj := btk.Object(gcs.OffsetKey)\n\n\tvar offSet offSet\n\n\tif r, err := obj.NewReader(gcs.ctx); err == nil {\n\t\tdefer gcs.closeReader(r)\n\t\tbuf := new(bytes.Buffer)\n\n\t\tif _, err := io.Copy(buf, r); err == nil {\n\t\t\tif marshalError := json.Unmarshal(buf.Bytes(), &offSet); marshalError != nil {\n\t\t\t\treturn marshalError\n\t\t\t}\n\t\t}\n\t} else {\n\t\toffSet = *newEmptyOffset()\n\t}\n\n\tgcs.offSet = offSet\n\n\treturn nil\n}\n\nfunc (gcs *GCS) closeReader(r *storage.Reader) {\n\tif err := r.Close(); err != nil {\n\t\tgcs.Log.Errorf(\"Could not close reader: %v\", err)\n\t}\n}\n\nfunc newEmptyOffset() *offSet {\n\treturn &offSet{OffSet: \"\"}\n}\n\nfunc newOffset(offset string) *offSet {\n\treturn &offSet{OffSet: offset}\n}\n\nfunc (offSet *offSet) isPresent() bool {\n\treturn offSet.OffSet != \"\"\n}\n\nfunc init() {\n\tinputs.Add(\"google_cloud_storage\", func() telegraf.Input {\n\t\tgcs := &GCS{}\n\t\treturn gcs\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/google_cloud_storage_test.go",
    "content": "package gcs\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst offSetTemplate = \"{\\\"offSet\\\":\\\"%s\\\"}\"\n\nfunc TestRunSetUpClient(t *testing.T) {\n\tgcs := &GCS{\n\t\tBucket:    \"test-bucket\",\n\t\tPrefix:    \"prefix\",\n\t\tOffsetKey: \"1230405\",\n\t\tLog:       testutil.Logger{},\n\t}\n\n\tif err := gcs.setUpClient(); err != nil {\n\t\tt.Log(err)\n\t}\n}\n\nfunc TestRunInit(t *testing.T) {\n\tsrv := startGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tgcs := &GCS{\n\t\tBucket:    \"test-bucket\",\n\t\tPrefix:    \"prefix/\",\n\t\tOffsetKey: \"offset.json\",\n\t\tLog:       testutil.Logger{},\n\t}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.Equal(t, \"offsetfile\", gcs.offSet.OffSet)\n}\n\nfunc TestRunInitNoOffsetKey(t *testing.T) {\n\tsrv := startGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tgcs := &GCS{\n\t\tBucket: \"test-bucket\",\n\t\tPrefix: \"prefix/\",\n\t\tLog:    testutil.Logger{},\n\t}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.Equal(t, \"offsetfile\", gcs.offSet.OffSet)\n\trequire.Equal(t, \"prefix/offset-key.json\", gcs.OffsetKey)\n}\n\nfunc TestRunGatherOneItem(t *testing.T) {\n\tsrv := startOneItemGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tacc := &testutil.Accumulator{}\n\n\tgcs := &GCS{\n\t\tBucket: \"test-iteration-bucket\",\n\t\tPrefix: \"prefix/\",\n\t\tLog:    testutil.Logger{},\n\t\tparser: createParser(),\n\t}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.NoError(t, gcs.Gather(acc))\n\n\tmetric := acc.Metrics[0]\n\trequire.Equal(t, \"cpu\", metric.Measurement)\n\trequire.Equal(t, \"us-east-1\", metric.Tags[\"tags_datacenter\"])\n\trequire.Equal(t, \"localhost\", metric.Tags[\"tags_host\"])\n\trequire.InDelta(t, 10.0, metric.Fields[\"fields_cosine\"], testutil.DefaultDelta)\n\trequire.InEpsilon(t, -1.0975806427415925e-12, metric.Fields[\"fields_sine\"], testutil.DefaultEpsilon)\n}\n\nfunc TestRunGatherOneIteration(t *testing.T) {\n\tsrv := startMultipleItemGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tgcs := &GCS{\n\t\tBucket:    \"test-iteration-bucket\",\n\t\tPrefix:    \"prefix/\",\n\t\tOffsetKey: \"custom-offset-key.json\",\n\t\tLog:       testutil.Logger{},\n\t\tparser:    createParser(),\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.NoError(t, gcs.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 3)\n}\n\nfunc TestRunGatherIteratiosnWithLimit(t *testing.T) {\n\tsrv := startMultipleItemGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tgcs := &GCS{\n\t\tBucket:              \"test-iteration-bucket\",\n\t\tPrefix:              \"prefix/\",\n\t\tObjectsPerIteration: 1,\n\t\tOffsetKey:           \"custom-offset-key.json\",\n\t\tLog:                 testutil.Logger{},\n\t\tparser:              createParser(),\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.NoError(t, gcs.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.NoError(t, gcs.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 2)\n\trequire.NoError(t, gcs.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 3)\n}\n\nfunc TestRunGatherIterationWithPages(t *testing.T) {\n\tsrv := stateFullGCSServer(t)\n\tdefer srv.Close()\n\n\temulatorSetEnv(t, srv)\n\n\tgcs := &GCS{\n\t\tBucket:    \"test-iteration-bucket\",\n\t\tPrefix:    \"prefix/\",\n\t\tOffsetKey: \"custom-offset-key.json\",\n\t\tLog:       testutil.Logger{},\n\t\tparser:    createParser(),\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, gcs.Init())\n\n\trequire.NoError(t, gcs.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 4)\n\trequire.True(t, gcs.offSet.isPresent())\n\trequire.Equal(t, \"prefix/1604148850994\", gcs.offSet.OffSet)\n\n\temptyAcc := &testutil.Accumulator{}\n\trequire.NoError(t, gcs.Gather(emptyAcc))\n\n\trequire.Empty(t, emptyAcc.Metrics)\n}\n\nfunc createParser() telegraf.Parser {\n\tp := &parsers_json.Parser{\n\t\tMetricName: \"cpu\",\n\t\tQuery:      \"metrics\",\n\t\tTagKeys:    []string{\"tags_datacenter\", \"tags_host\"},\n\t\tTimeKey:    \"timestamp\",\n\t\tTimeFormat: \"unix_ms\",\n\t\tStrict:     true,\n\t}\n\tif err := p.Init(); err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn p\n}\n\nfunc startGCSServer(t *testing.T) *httptest.Server {\n\tsrv := httptest.NewServer(http.NotFoundHandler())\n\n\tcurrentOffSetKey := fmt.Sprintf(offSetTemplate, \"offsetfile\")\n\n\tsrv.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/test-bucket/prefix/offset.json\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(currentOffSetKey)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"/test-bucket/prefix/offset-key.json\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := w.Write([]byte(\"{\\\"offSet\\\":\\\"offsetfile\\\"}\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tfailPath(r.URL.Path, t, w)\n\t\t}\n\t})\n\n\treturn srv\n}\n\nfunc startOneItemGCSServer(t *testing.T) *httptest.Server {\n\tsrv := httptest.NewServer(http.NotFoundHandler())\n\tsingleFileList := readJSON(t, \"testdata/single_file_list.json\")\n\n\tsrv.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/b/test-iteration-bucket/o\":\n\t\t\tserveJSONText(w, singleFileList)\n\t\tdefault:\n\t\t\tserveBlobs(t, w, r.URL.Path, \"\")\n\t\t}\n\t})\n\n\treturn srv\n}\n\nfunc startMultipleItemGCSServer(t *testing.T) *httptest.Server {\n\tobjListing := parseJSONFromFile(t, \"testdata/file_listing.json\")\n\tfirstElement := parseJSONFromFile(t, \"testdata/first_file_listing.json\")\n\tsecondElement := parseJSONFromFile(t, \"testdata/second_file_listing.json\")\n\tthirdElement := parseJSONFromFile(t, \"testdata/third_file_listing.json\")\n\tfourthElement := parseJSONFromFile(t, \"testdata/fourth_file_listing.json\")\n\n\tsrv := httptest.NewServer(http.NotFoundHandler())\n\n\tcurrentOffSetKey := fmt.Sprintf(offSetTemplate, \"prefix/1604148850991\")\n\n\tsrv.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/b/test-iteration-bucket/o\":\n\n\t\t\toffset := r.URL.Query().Get(\"startOffset\")\n\n\t\t\tif offset == \"prefix/1604148850990\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{firstElement, secondElement, thirdElement, fourthElement}\n\t\t\t} else if offset == \"prefix/1604148850991\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{secondElement, thirdElement, fourthElement}\n\t\t\t} else if offset == \"prefix/16041488509912\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{thirdElement, fourthElement}\n\t\t\t} else if offset == \"prefix/16041488509913\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{thirdElement, fourthElement}\n\t\t\t} else {\n\t\t\t\tobjListing[\"items\"] = []interface{}{firstElement, secondElement, thirdElement, fourthElement}\n\t\t\t}\n\n\t\t\tif data, err := json.Marshal(objListing); err == nil {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := w.Write(data); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\tt.Fatalf(\"unexpected path: %s\", r.URL.Path)\n\t\t\t}\n\n\t\tdefault:\n\t\t\tserveBlobs(t, w, r.URL.Path, currentOffSetKey)\n\t\t}\n\t})\n\n\treturn srv\n}\n\nfunc stateFullGCSServer(t *testing.T) *httptest.Server {\n\tsrv := httptest.NewServer(http.NotFoundHandler())\n\n\tfirstElement := parseJSONFromFile(t, \"testdata/first_file_listing.json\")\n\tsecondElement := parseJSONFromFile(t, \"testdata/second_file_listing.json\")\n\tthirdElement := parseJSONFromFile(t, \"testdata/third_file_listing.json\")\n\tfourthElement := parseJSONFromFile(t, \"testdata/fourth_file_listing.json\")\n\tcurrentOffSetKey := fmt.Sprintf(offSetTemplate, \"prefix/1604148850990\")\n\n\tsrv.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/b/test-iteration-bucket/o\":\n\t\t\toffset := r.URL.Query().Get(\"startOffset\")\n\t\t\tobjListing := parseJSONFromFile(t, \"testdata/file_listing.json\")\n\n\t\t\tpageToken := r.URL.Query().Get(\"pageToken\")\n\n\t\t\tif pageToken == \"page2\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{secondElement}\n\t\t\t\tobjListing[\"nextPageToken\"] = \"page3\"\n\t\t\t} else if pageToken == \"page3\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{thirdElement}\n\t\t\t\tobjListing[\"nextPageToken\"] = \"page4\"\n\t\t\t} else if pageToken == \"page4\" {\n\t\t\t\tobjListing[\"items\"] = []interface{}{fourthElement}\n\t\t\t} else if offset == \"prefix/1604148850994\" {\n\t\t\t\tobjListing[\"items\"] = make([]interface{}, 0)\n\t\t\t} else {\n\t\t\t\tobjListing[\"items\"] = []interface{}{firstElement}\n\t\t\t\tobjListing[\"nextPageToken\"] = \"page2\"\n\t\t\t}\n\n\t\t\tif data, err := json.Marshal(objListing); err == nil {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := w.Write(data); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfailPath(r.URL.Path, t, w)\n\t\t\t}\n\t\tcase \"/upload/storage/v1/b/test-iteration-bucket/o\":\n\t\t\t_, params, err := mime.ParseMediaType(r.Header[\"Content-Type\"][0])\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tboundary := params[\"boundary\"]\n\t\t\tcurrentOffSetKey, err = fetchJSON(t, boundary, r.Body)\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tserveBlobs(t, w, r.URL.Path, currentOffSetKey)\n\t\t}\n\t})\n\n\treturn srv\n}\n\nfunc serveBlobs(t *testing.T, w http.ResponseWriter, urlPath, offsetKey string) {\n\tsingleObjectNotFound := readJSON(t, \"testdata/single_object_not_found.json\")\n\tfirstFile := readJSON(t, \"testdata/first_file.json\")\n\tsecondFile := readJSON(t, \"testdata/second_file.json\")\n\tthirdFile := readJSON(t, \"testdata/third_file.json\")\n\tfourthFile := readJSON(t, \"testdata/fourth_file.json\")\n\n\tswitch urlPath {\n\tcase \"/test-iteration-bucket/prefix/offset-key.json\":\n\t\tw.WriteHeader(http.StatusNotFound)\n\t\t_, err := w.Write(singleObjectNotFound)\n\t\trequire.NoError(t, err)\n\tcase \"/test-bucket/prefix/offset.json\":\n\t\tw.WriteHeader(http.StatusOK)\n\t\t_, err := w.Write([]byte(offsetKey))\n\t\trequire.NoError(t, err)\n\tcase \"/test-bucket/prefix/offset-key.json\":\n\t\tw.WriteHeader(http.StatusOK)\n\t\t_, err := w.Write([]byte(\"{\\\"offSet\\\":\\\"offsetfile\\\"}\"))\n\t\trequire.NoError(t, err)\n\tcase \"/test-iteration-bucket/prefix/custom-offset-key.json\":\n\t\tw.WriteHeader(http.StatusOK)\n\t\t_, err := w.Write([]byte(offsetKey))\n\t\trequire.NoError(t, err)\n\tcase \"/test-iteration-bucket/1604148850990\":\n\t\tserveJSONText(w, firstFile)\n\tcase \"/test-iteration-bucket/prefix/1604148850991\":\n\t\tserveJSONText(w, firstFile)\n\tcase \"/test-iteration-bucket/prefix/1604148850992\":\n\t\tserveJSONText(w, secondFile)\n\tcase \"/test-iteration-bucket/prefix/1604148850993\":\n\t\tserveJSONText(w, thirdFile)\n\tcase \"/test-iteration-bucket/prefix/1604148850994\":\n\t\tserveJSONText(w, fourthFile)\n\tcase \"/upload/storage/v1/b/test-iteration-bucket/o\":\n\t\tw.WriteHeader(http.StatusOK)\n\tdefault:\n\t\tfailPath(urlPath, t, w)\n\t}\n}\n\nfunc fetchJSON(t *testing.T, boundary string, rc io.ReadCloser) (string, error) {\n\tdefer rc.Close()\n\tbodyBytes, err := io.ReadAll(rc)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Could not read bytes from offset action\")\n\t\treturn \"\", err\n\t}\n\n\tsplits := strings.Split(string(bodyBytes), boundary)\n\toffsetPart := splits[2]\n\toffsets := strings.Split(offsetPart, \"\\n\")\n\tfmt.Print(offsets[3])\n\treturn offsets[3], nil\n}\n\nfunc serveJSONText(w http.ResponseWriter, jsonText []byte) {\n\tw.WriteHeader(http.StatusOK)\n\tif _, err := w.Write(jsonText); err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n\nfunc failPath(path string, t *testing.T, w http.ResponseWriter) {\n\tw.WriteHeader(http.StatusNotFound)\n\tt.Fatalf(\"unexpected path: %s\", path)\n}\n\nfunc parseJSONFromFile(t *testing.T, jsonFilePath string) map[string]interface{} {\n\tdata := readJSON(t, jsonFilePath)\n\n\tvar element map[string]interface{}\n\tif err := json.Unmarshal(data, &element); err != nil {\n\t\trequire.NoErrorf(t, err, \"could not parse from data file %s\", jsonFilePath)\n\t}\n\n\treturn element\n}\n\nfunc readJSON(t *testing.T, jsonFilePath string) []byte {\n\tdata, err := os.ReadFile(jsonFilePath)\n\trequire.NoErrorf(t, err, \"could not read from data file %s\", jsonFilePath)\n\n\treturn data\n}\n\nfunc emulatorSetEnv(t *testing.T, srv *httptest.Server) {\n\tt.Setenv(\"STORAGE_EMULATOR_HOST\", strings.ReplaceAll(srv.URL, \"http://\", \"\"))\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/sample.conf",
    "content": "# Gather metrics by iterating the files located on a Cloud Storage Bucket.\n[[inputs.google_cloud_storage]]\n  ## Required. Name of Cloud Storage bucket to ingest metrics from.\n  bucket = \"my-bucket\"\n\n  ## Optional. Prefix of Cloud Storage bucket keys to list metrics from.\n  # key_prefix = \"my-bucket\"\n\n  ## Key that will store the offsets in order to pick up where the ingestion was left.\n  offset_key = \"offset_key\"\n\n  ## Key that will store the offsets in order to pick up where the ingestion was left.\n  objects_per_iteration = 10\n\n  ## Required. Data format to consume.\n  ## Each data format has its own unique set of configuration options.\n  ## Read more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Optional. Filepath for GCP credentials JSON file to authorize calls to\n  ## Google Cloud Storage APIs. If not set explicitly, Telegraf will attempt to use\n  ## Application Default Credentials, which is preferred.\n  # credentials_file = \"path/to/my/creds.json\"\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/file_listing.json",
    "content": "{\n  \"kind\": \"storage#objects\"\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/first_file.json",
    "content": "{\n  \"metrics\": [\n    {\n      \"fields\": {\n        \"cosine\": 10,\n        \"sine\": -1.0975806427415925e-12\n      },\n      \"name\": \"cpu\",\n      \"tags\": {\n        \"datacenter\": \"us-east-1\",\n        \"host\": \"localhost\"\n      },\n      \"timestamp\": 1604148850991\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/first_file_listing.json",
    "content": "{\n  \"kind\": \"storage#object\",\n  \"id\": \"test-iteration-bucket/prefix/1604148850991/1604148851353983\",\n  \"selfLink\": \"https://www.googleapis.com/storage/v1/b/test-iteration-bucket/o/1604148850991\",\n  \"mediaLink\": \"https://content-storage.googleapis.com/download/storage/v1/b/test-iteration-bucket/o/1604148850991?generation=1604148851353983&alt=media\",\n  \"name\": \"prefix/1604148850991\",\n  \"bucket\": \"test-iteration-bucket\",\n  \"generation\": \"1604148851353983\",\n  \"metageneration\": \"1\",\n  \"contentType\": \"text/plain; charset=utf-8\",\n  \"storageClass\": \"STANDARD\",\n  \"size\": \"161\",\n  \"md5Hash\": \"y59iuRCTpkm7wpvU5YHUYw==\",\n  \"crc32c\": \"y57reA==\",\n  \"etag\": \"CP/SzpPw3uwCEAE=\",\n  \"timeCreated\": \"2020-10-31T12:54:11.353Z\",\n  \"updated\": \"2020-10-31T12:54:11.353Z\",\n  \"timeStorageClassUpdated\": \"2020-10-31T12:54:11.353Z\"\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/fourth_file.json",
    "content": "{\n  \"metrics\": [\n    {\n      \"fields\": {\n        \"cosine\": 13,\n        \"sine\": -4.0975806427415925e-12\n      },\n      \"name\": \"cpu\",\n      \"tags\": {\n        \"datacenter\": \"us-east-1\",\n        \"host\": \"localhost\"\n      },\n      \"timestamp\": 1604148850994\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/fourth_file_listing.json",
    "content": "{\n  \"kind\": \"storage#object\",\n  \"id\": \"test-iteration-bucket/prefix/1604148850994/1604148851467554\",\n  \"selfLink\": \"https://www.googleapis.com/storage/v1/b/test-iteration-bucket/o/1604148850994\",\n  \"mediaLink\": \"https://content-storage.googleapis.com/download/storage/v1/b/test-iteration-bucket/o/1604148850994?generation=1604148851467554&alt=media\",\n  \"name\": \"prefix/1604148850994\",\n  \"bucket\": \"test-iteration-bucket\",\n  \"generation\": \"1604148851467554\",\n  \"metageneration\": \"1\",\n  \"contentType\": \"text/plain; charset=utf-8\",\n  \"storageClass\": \"STANDARD\",\n  \"size\": \"161\",\n  \"md5Hash\": \"y59iuRCTpkm7wpvU5YHUYw==\",\n  \"crc32c\": \"y57reA==\",\n  \"etag\": \"CKLK1ZPw3uwCEAE=\",\n  \"timeCreated\": \"2020-10-31T12:54:11.467Z\",\n  \"updated\": \"2020-10-31T12:54:11.467Z\",\n  \"timeStorageClassUpdated\": \"2020-10-31T12:54:11.467Z\"\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/second_file.json",
    "content": "{\n  \"metrics\": [\n    {\n      \"fields\": {\n        \"cosine\": 11,\n        \"sine\": -2.0975806427415925e-12\n      },\n      \"name\": \"cpu\",\n      \"tags\": {\n        \"datacenter\": \"us-east-1\",\n        \"host\": \"localhost\"\n      },\n      \"timestamp\": 1604148850992\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/second_file_listing.json",
    "content": "{\n  \"kind\": \"storage#object\",\n  \"id\": \"test-iteration-bucket/prefix/1604148850992/1604148851414237\",\n  \"selfLink\": \"https://www.googleapis.com/storage/v1/b/test-iteration-bucket/o/1604148850992\",\n  \"mediaLink\": \"https://content-storage.googleapis.com/download/storage/v1/b/test-iteration-bucket/o/1604148850992?generation=1604148851414237&alt=media\",\n  \"name\": \"prefix/1604148850992\",\n  \"bucket\": \"test-iteration-bucket\",\n  \"generation\": \"1604148851414237\",\n  \"metageneration\": \"1\",\n  \"contentType\": \"text/plain; charset=utf-8\",\n  \"storageClass\": \"STANDARD\",\n  \"size\": \"161\",\n  \"md5Hash\": \"y59iuRCTpkm7wpvU5YHUYw==\",\n  \"crc32c\": \"y57reA==\",\n  \"etag\": \"CN2p0pPw3uwCEAE=\",\n  \"timeCreated\": \"2020-10-31T12:54:11.414Z\",\n  \"updated\": \"2020-10-31T12:54:11.414Z\",\n  \"timeStorageClassUpdated\": \"2020-10-31T12:54:11.414Z\"\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/single_file_list.json",
    "content": "{\n  \"kind\": \"storage#objects\",\n  \"items\": [\n    {\n      \"kind\": \"storage#object\",\n      \"id\": \"test-iteration-bucket/1604148850990/1604148851295698\",\n      \"selfLink\": \"https://www.googleapis.com/storage/v1/b/1604148850990/o/1604148850990\",\n      \"mediaLink\": \"https://content-storage.googleapis.com/download/storage/v1/b/test-iteration-bucket/o/1604148850990?generation=1604148851295698&alt=media\",\n      \"name\": \"1604148850990\",\n      \"bucket\": \"test-iteration-bucket\",\n      \"generation\": \"1604148851295698\",\n      \"metageneration\": \"1\",\n      \"contentType\": \"text/plain; charset=utf-8\",\n      \"storageClass\": \"STANDARD\",\n      \"size\": \"161\",\n      \"md5Hash\": \"y59iuRCTpkm7wpvU5YHUYw==\",\n      \"crc32c\": \"y57reA==\",\n      \"etag\": \"CNKLy5Pw3uwCEAE=\",\n      \"timeCreated\": \"2020-10-31T12:54:11.295Z\",\n      \"updated\": \"2020-10-31T12:54:11.295Z\",\n      \"timeStorageClassUpdated\": \"2020-10-31T12:54:11.295Z\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/single_object_not_found.json",
    "content": "{\n  \"error\": {\n    \"code\": 404,\n    \"message\": \"No such object: test-iteration-bucket/prefix/offset-key.json\",\n    \"errors\": [\n      {\n        \"message\": \"No such object: test-iteration-bucket/prefix/offset-key.json\",\n        \"domain\": \"global\",\n        \"reason\": \"notFound\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/third_file.json",
    "content": "{\n  \"metrics\": [\n    {\n      \"fields\": {\n        \"cosine\": 12,\n        \"sine\": -3.0975806427415925e-12\n      },\n      \"name\": \"cpu\",\n      \"tags\": {\n        \"datacenter\": \"us-east-1\",\n        \"host\": \"localhost\"\n      },\n      \"timestamp\": 1604148850993\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/google_cloud_storage/testdata/third_file_listing.json",
    "content": "{\n  \"kind\": \"storage#object\",\n  \"id\": \"test-iteration-bucket/prefix/1604148850993/1604148851467554\",\n  \"selfLink\": \"https://www.googleapis.com/storage/v1/b/test-iteration-bucket/o/1604148850993\",\n  \"mediaLink\": \"https://content-storage.googleapis.com/download/storage/v1/b/test-iteration-bucket/o/1604148850993?generation=1604148851467554&alt=media\",\n  \"name\": \"prefix/1604148850993\",\n  \"bucket\": \"test-iteration-bucket\",\n  \"generation\": \"1604148851467554\",\n  \"metageneration\": \"1\",\n  \"contentType\": \"text/plain; charset=utf-8\",\n  \"storageClass\": \"STANDARD\",\n  \"size\": \"161\",\n  \"md5Hash\": \"y59iuRCTpkm7wpvU5YHUYw==\",\n  \"crc32c\": \"y57reA==\",\n  \"etag\": \"CKLK1ZPw3uwCEAE=\",\n  \"timeCreated\": \"2020-10-31T12:54:11.467Z\",\n  \"updated\": \"2020-10-31T12:54:11.467Z\",\n  \"timeStorageClassUpdated\": \"2020-10-31T12:54:11.467Z\"\n}\n"
  },
  {
    "path": "plugins/inputs/graylog/README.md",
    "content": "# GrayLog Input Plugin\n\nThis plugin collects data from [Graylog servers][graylog], currently supporting\ntwo type of end points `multiple`\n(e.g. `http://<host>:9000/api/system/metrics/multiple`) and `namespace`\n(e.g. `http://<host>:9000/api/system/metrics/namespace/{namespace}`).\n\nMultiple endpoint can be queried and mixing `multiple` and serveral `namespace`\nend points is possible. Check `http://<host>:9000/api/api-browser` for the full\nlist of available endpoints.\n\n> [!NOTE]\n> When specifying a `namespace` endpoint without an actual namespace, the\n> metrics array will be ignored.\n\n⭐ Telegraf v1.0.0\n🏷️ logging\n💻 all\n\n[graylog]: https://graylog.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read flattened metrics from one or more GrayLog HTTP endpoints\n[[inputs.graylog]]\n  ## API endpoint, currently supported API:\n  ##\n  ##   - multiple  (e.g. http://<host>:9000/api/system/metrics/multiple)\n  ##   - namespace (e.g. http://<host>:9000/api/system/metrics/namespace/{namespace})\n  ##\n  ## For namespace endpoint, the metrics array will be ignored for that call.\n  ## Endpoint can contain namespace and multiple type calls.\n  ##\n  ## Please check http://[graylog-server-ip]:9000/api/api-browser for full list\n  ## of endpoints\n  servers = [\n    \"http://[graylog-server-ip]:9000/api/system/metrics/multiple\",\n  ]\n\n  ## Set timeout (default 5 seconds)\n  # timeout = \"5s\"\n\n  ## Metrics list\n  ## List of metrics can be found on Graylog webservice documentation.\n  ## Or by hitting the web service api at:\n  ##   http://[graylog-host]:9000/api/system/metrics\n  metrics = [\n    \"jvm.cl.loaded\",\n    \"jvm.memory.pools.Metaspace.committed\"\n  ]\n\n  ## Username and password\n  username = \"\"\n  password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\nPlease refer to GrayLog metrics API browser for full metric end points:\n`http://host:9000/api/api-browser`\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/graylog/graylog.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage graylog\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype GrayLog struct {\n\tServers  []string        `toml:\"servers\"`\n\tMetrics  []string        `toml:\"metrics\"`\n\tUsername string          `toml:\"username\"`\n\tPassword string          `toml:\"password\"`\n\tTimeout  config.Duration `toml:\"timeout\"`\n\n\ttls.ClientConfig\n\tclient httpClient\n}\n\ntype responseMetrics struct {\n\tMetrics []metric `json:\"metrics\"`\n}\n\ntype metric struct {\n\tFullName string                 `json:\"full_name\"`\n\tName     string                 `json:\"name\"`\n\tType     string                 `json:\"type\"`\n\tFields   map[string]interface{} `json:\"metric\"`\n}\n\ntype messageBody struct {\n\tMetrics []string `json:\"metrics\"`\n}\n\ntype realHTTPClient struct {\n\tclient *http.Client\n}\n\ntype httpClient interface {\n\t// Returns the result of an http request\n\t//\n\t// Parameters:\n\t// req: HTTP request object\n\t//\n\t// Returns:\n\t// http.Response:  HTTP response object\n\t// error        :  Any error that may have occurred\n\tmakeRequest(req *http.Request) (*http.Response, error)\n\tsetHTTPClient(client *http.Client)\n\thttpClient() *http.Client\n}\n\nfunc (c *realHTTPClient) makeRequest(req *http.Request) (*http.Response, error) {\n\treturn c.client.Do(req)\n}\n\nfunc (c *realHTTPClient) setHTTPClient(client *http.Client) {\n\tc.client = client\n}\n\nfunc (c *realHTTPClient) httpClient() *http.Client {\n\treturn c.client\n}\n\nfunc (*GrayLog) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *GrayLog) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tif h.client.httpClient() == nil {\n\t\ttlsCfg, err := h.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttr := &http.Transport{\n\t\t\tResponseHeaderTimeout: time.Duration(h.Timeout),\n\t\t\tTLSClientConfig:       tlsCfg,\n\t\t}\n\t\tclient := &http.Client{\n\t\t\tTransport: tr,\n\t\t\tTimeout:   time.Duration(h.Timeout),\n\t\t}\n\t\th.client.setHTTPClient(client)\n\t}\n\n\tfor _, server := range h.Servers {\n\t\twg.Add(1)\n\t\tgo func(server string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(h.gatherServer(acc, server))\n\t\t}(server)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\n// Gathers data from a particular server\n// Parameters:\n//\n//\tacc      : The telegraf Accumulator to use\n//\tserverURL: endpoint to send request to\n//\tservice  : the service being queried\n//\n// Returns:\n//\n//\terror: Any error that may have occurred\nfunc (h *GrayLog) gatherServer(\n\tacc telegraf.Accumulator,\n\tserverURL string,\n) error {\n\tresp, _, err := h.sendRequest(serverURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\trequestURL, err := url.Parse(serverURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to parse address %q: %w\", serverURL, err)\n\t}\n\n\thost, port, err := net.SplitHostPort(requestURL.Host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to parse address host %q: %w\", requestURL.Host, err)\n\t}\n\tvar dat responseMetrics\n\tif err := json.Unmarshal([]byte(resp), &dat); err != nil {\n\t\treturn err\n\t}\n\tfor _, mItem := range dat.Metrics {\n\t\tfields := make(map[string]interface{})\n\t\ttags := map[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"name\":   mItem.Name,\n\t\t\t\"type\":   mItem.Type,\n\t\t}\n\t\th.flatten(mItem.Fields, fields, \"\")\n\t\tacc.AddFields(mItem.FullName, fields, tags)\n\t}\n\treturn nil\n}\n\n// Flatten JSON hierarchy to produce field name and field value\n// Parameters:\n//\n//\titem: Item map to flatten\n//\tfields: Map to store generated fields.\n//\tid: Prefix for top level metric (empty string \"\")\n//\n// Returns:\n//\n//\tvoid\nfunc (h *GrayLog) flatten(item, fields map[string]interface{}, id string) {\n\tif id != \"\" {\n\t\tid = id + \"_\"\n\t}\n\tfor k, i := range item {\n\t\tswitch i := i.(type) {\n\t\tcase int:\n\t\t\tfields[id+k] = float64(i)\n\t\tcase float64:\n\t\t\tfields[id+k] = i\n\t\tcase map[string]interface{}:\n\t\t\th.flatten(i, fields, id+k)\n\t\tdefault:\n\t\t}\n\t}\n}\n\n// Sends an HTTP request to the server using the GrayLog object's httpClient.\n// Parameters:\n//\n//\tserverURL: endpoint to send request to\n//\n// Returns:\n//\n//\tstring: body of the response\n//\terror : Any error that may have occurred\nfunc (h *GrayLog) sendRequest(serverURL string) (string, float64, error) {\n\theaders := map[string]string{\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Accept\":       \"application/json\",\n\t}\n\tmethod := \"GET\"\n\tcontent := bytes.NewBufferString(\"\")\n\theaders[\"Authorization\"] = \"Basic \" + base64.URLEncoding.EncodeToString([]byte(h.Username+\":\"+h.Password))\n\t// Prepare URL\n\trequestURL, err := url.Parse(serverURL)\n\tif err != nil {\n\t\treturn \"\", -1, fmt.Errorf(\"invalid server URL %q\", serverURL)\n\t}\n\t// Add X-Requested-By header\n\theaders[\"X-Requested-By\"] = \"Telegraf\"\n\n\tif strings.Contains(requestURL.String(), \"multiple\") {\n\t\tm := &messageBody{Metrics: h.Metrics}\n\t\thttpBody, err := json.Marshal(m)\n\t\tif err != nil {\n\t\t\treturn \"\", -1, fmt.Errorf(\"invalid list of Metrics %s\", h.Metrics)\n\t\t}\n\t\tmethod = \"POST\"\n\t\tcontent = bytes.NewBuffer(httpBody)\n\t}\n\treq, err := http.NewRequest(method, requestURL.String(), content)\n\tif err != nil {\n\t\treturn \"\", -1, err\n\t}\n\t// Add header parameters\n\tfor k, v := range headers {\n\t\treq.Header.Add(k, v)\n\t}\n\tstart := time.Now()\n\tresp, err := h.client.makeRequest(req)\n\tif err != nil {\n\t\treturn \"\", -1, err\n\t}\n\n\tdefer resp.Body.Close()\n\tresponseTime := time.Since(start).Seconds()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn string(body), responseTime, err\n\t}\n\n\t// Process response\n\tif resp.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"response from url %q has status code %d (%s), expected %d (%s)\",\n\t\t\trequestURL.String(),\n\t\t\tresp.StatusCode,\n\t\t\thttp.StatusText(resp.StatusCode),\n\t\t\thttp.StatusOK,\n\t\t\thttp.StatusText(http.StatusOK))\n\t\treturn string(body), responseTime, err\n\t}\n\treturn string(body), responseTime, err\n}\n\nfunc init() {\n\tinputs.Add(\"graylog\", func() telegraf.Input {\n\t\treturn &GrayLog{\n\t\t\tclient:  &realHTTPClient{},\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/graylog/graylog_test.go",
    "content": "package graylog\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst validJSON = `\n  {\n    \"total\": 3,\n    \"metrics\": [\n      {\n        \"full_name\": \"jvm.cl.loaded\",\n        \"metric\": {\n          \"value\": 18910\n        },\n        \"name\": \"loaded\",\n        \"type\": \"gauge\"\n      },\n      {\n        \"full_name\": \"jvm.memory.pools.Metaspace.committed\",\n        \"metric\": {\n          \"value\": 108040192\n        },\n        \"name\": \"committed\",\n        \"type\": \"gauge\"\n      },\n      {\n        \"full_name\": \"org.graylog2.shared.journal.KafkaJournal.writeTime\",\n        \"metric\": {\n          \"time\": {\n            \"min\": 99\n          },\n          \"rate\": {\n            \"total\": 10,\n            \"mean\": 2\n          },\n          \"duration_unit\": \"microseconds\",\n          \"rate_unit\": \"events/second\"\n        },\n        \"name\": \"writeTime\",\n        \"type\": \"hdrtimer\"\n      }\n    ]\n  }`\n\nvar validTags = map[string]map[string]string{\n\t\"jvm.cl.loaded\": {\n\t\t\"name\":   \"loaded\",\n\t\t\"type\":   \"gauge\",\n\t\t\"port\":   \"12900\",\n\t\t\"server\": \"localhost\",\n\t},\n\t\"jvm.memory.pools.Metaspace.committed\": {\n\t\t\"name\":   \"committed\",\n\t\t\"type\":   \"gauge\",\n\t\t\"port\":   \"12900\",\n\t\t\"server\": \"localhost\",\n\t},\n\t\"org.graylog2.shared.journal.KafkaJournal.writeTime\": {\n\t\t\"name\":   \"writeTime\",\n\t\t\"type\":   \"hdrtimer\",\n\t\t\"port\":   \"12900\",\n\t\t\"server\": \"localhost\",\n\t},\n}\n\nvar expectedFields = map[string]map[string]interface{}{\n\t\"jvm.cl.loaded\": {\n\t\t\"value\": float64(18910),\n\t},\n\t\"jvm.memory.pools.Metaspace.committed\": {\n\t\t\"value\": float64(108040192),\n\t},\n\t\"org.graylog2.shared.journal.KafkaJournal.writeTime\": {\n\t\t\"time_min\":   float64(99),\n\t\t\"rate_total\": float64(10),\n\t\t\"rate_mean\":  float64(2),\n\t},\n}\n\nconst invalidJSON = \"I don't think this is JSON\"\n\nconst empty = \"\"\n\ntype mockHTTPClient struct {\n\tresponseBody string\n\tstatusCode   int\n}\n\n// Mock implementation of MakeRequest. Usually returns an http.Response with\n// hard-coded responseBody and statusCode. However, if the request uses a\n// nonstandard method, it uses status code 405 (method not allowed)\nfunc (c *mockHTTPClient) makeRequest(req *http.Request) (*http.Response, error) {\n\tresp := http.Response{}\n\tresp.StatusCode = c.statusCode\n\n\t// basic error checking on request method\n\tallowedMethods := []string{\"GET\", \"HEAD\", \"POST\", \"PUT\", \"DELETE\", \"TRACE\", \"CONNECT\"}\n\tmethodValid := false\n\tfor _, method := range allowedMethods {\n\t\tif req.Method == method {\n\t\t\tmethodValid = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !methodValid {\n\t\tresp.StatusCode = 405 // Method not allowed\n\t}\n\n\tresp.Body = io.NopCloser(strings.NewReader(c.responseBody))\n\treturn &resp, nil\n}\n\nfunc (*mockHTTPClient) setHTTPClient(*http.Client) {\n}\n\nfunc (*mockHTTPClient) httpClient() *http.Client {\n\treturn nil\n}\n\n// Generates a pointer to an HttpJson object that uses a mock HTTP client.\n// Parameters:\n//\n//\tresponse  : Body of the response that the mock HTTP client should return\n//\tstatusCode: HTTP status code the mock HTTP client should return\n//\n// Returns:\n//\n//\t*HttpJson: Pointer to an HttpJson object that uses the generated mock HTTP client\nfunc genMockGrayLog(response string, statusCode int) []*GrayLog {\n\treturn []*GrayLog{\n\t\t{\n\t\t\tclient: &mockHTTPClient{responseBody: response, statusCode: statusCode},\n\t\t\tServers: []string{\n\t\t\t\t\"http://localhost:12900/system/metrics/multiple\",\n\t\t\t},\n\t\t\tMetrics: []string{\n\t\t\t\t\"jvm.memory.pools.Metaspace.committed\",\n\t\t\t\t\"jvm.cl.loaded\",\n\t\t\t\t\"org.graylog2.shared.journal.KafkaJournal.writeTime\",\n\t\t\t},\n\t\t\tUsername: \"test\",\n\t\t\tPassword: \"test\",\n\t\t},\n\t}\n}\n\n// Test that the proper values are ignored or collected\nfunc TestNormalResponse(t *testing.T) {\n\tgraylog := genMockGrayLog(validJSON, 200)\n\n\tfor _, service := range graylog {\n\t\tvar acc testutil.Accumulator\n\t\terr := acc.GatherError(service.Gather)\n\t\trequire.NoError(t, err)\n\t\tfor k, v := range expectedFields {\n\t\t\tacc.AssertContainsTaggedFields(t, k, v, validTags[k])\n\t\t}\n\t}\n}\n\n// Test response to HTTP 500\nfunc TestHttpJson500(t *testing.T) {\n\tgraylog := genMockGrayLog(validJSON, 500)\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(graylog[0].Gather)\n\n\trequire.Error(t, err)\n\trequire.Equal(t, 0, acc.NFields())\n}\n\n// Test response to malformed JSON\nfunc TestHttpJsonBadJson(t *testing.T) {\n\tgraylog := genMockGrayLog(invalidJSON, 200)\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(graylog[0].Gather)\n\n\trequire.Error(t, err)\n\trequire.Equal(t, 0, acc.NFields())\n}\n\n// Test response to empty string as response objectgT\nfunc TestHttpJsonEmptyResponse(t *testing.T) {\n\tgraylog := genMockGrayLog(empty, 200)\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(graylog[0].Gather)\n\n\trequire.Error(t, err)\n\trequire.Equal(t, 0, acc.NFields())\n}\n"
  },
  {
    "path": "plugins/inputs/graylog/sample.conf",
    "content": "# Read flattened metrics from one or more GrayLog HTTP endpoints\n[[inputs.graylog]]\n  ## API endpoint, currently supported API:\n  ##\n  ##   - multiple  (e.g. http://<host>:9000/api/system/metrics/multiple)\n  ##   - namespace (e.g. http://<host>:9000/api/system/metrics/namespace/{namespace})\n  ##\n  ## For namespace endpoint, the metrics array will be ignored for that call.\n  ## Endpoint can contain namespace and multiple type calls.\n  ##\n  ## Please check http://[graylog-server-ip]:9000/api/api-browser for full list\n  ## of endpoints\n  servers = [\n    \"http://[graylog-server-ip]:9000/api/system/metrics/multiple\",\n  ]\n\n  ## Set timeout (default 5 seconds)\n  # timeout = \"5s\"\n\n  ## Metrics list\n  ## List of metrics can be found on Graylog webservice documentation.\n  ## Or by hitting the web service api at:\n  ##   http://[graylog-host]:9000/api/system/metrics\n  metrics = [\n    \"jvm.cl.loaded\",\n    \"jvm.memory.pools.Metaspace.committed\"\n  ]\n\n  ## Username and password\n  username = \"\"\n  password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/haproxy/README.md",
    "content": "# HAProxy Input Plugin\n\nThis plugin gathers statistics of [HAProxy][haproxy] servers using sockets or\nthe HTTP protocol.\n\n⭐ Telegraf v0.1.5\n🏷️ network, server\n💻 all\n\n[haproxy]: http://www.haproxy.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics of HAProxy, via stats socket or http endpoints\n[[inputs.haproxy]]\n  ## List of stats endpoints. Metrics can be collected from both http and socket\n  ## endpoints. Examples of valid endpoints:\n  ##   - http://myhaproxy.com:1936/haproxy?stats\n  ##   - https://myhaproxy.com:8000/stats\n  ##   - socket:/run/haproxy/admin.sock\n  ##   - /run/haproxy/*.sock\n  ##   - tcp://127.0.0.1:1936\n  ##\n  ## Server addresses not starting with 'http://', 'https://', 'tcp://' will be\n  ## treated as possible sockets. When specifying local socket, glob patterns are\n  ## supported.\n  servers = [\"http://myhaproxy.com:1936/haproxy?stats\"]\n\n  ## By default, some of the fields are renamed from what haproxy calls them.\n  ## Setting this option to true results in the plugin keeping the original\n  ## field names.\n  # keep_field_names = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### HAProxy Configuration\n\nThe following information may be useful when getting started, but please consult\nthe HAProxy documentation for complete and up to date instructions.\n\nThe [`stats enable`][4] option can be used to add unauthenticated access over\nHTTP using the default settings.  To enable the unix socket begin by reading\nabout the [`stats socket`][5] option.\n\n[4]: https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4-stats%20enable\n[5]: https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#3.1-stats%20socket\n\n### servers\n\nServer addresses must explicitly start with 'http' if you wish to use HAProxy\nstatus page.  Otherwise, addresses will be assumed to be an UNIX socket and any\nprotocol (if present) will be discarded.\n\nWhen using socket names, wildcard expansion is supported so plugin can gather\nstats from multiple sockets at once.\n\nTo use HTTP Basic Auth add the username and password in the userinfo section of\nthe URL: `http://user:password@1.2.3.4/haproxy?stats`.  The credentials are sent\nvia the `Authorization` header and not using the request URL.\n\n### keep_field_names\n\nBy default, some of the fields are renamed from what haproxy calls them.\nSetting the `keep_field_names` parameter to `true` will result in the plugin\nkeeping the original field names.\n\nThe following renames are made:\n\n- `pxname` -> `proxy`\n- `svname` -> `sv`\n- `act` -> `active_servers`\n- `bck` -> `backup_servers`\n- `cli_abrt` -> `cli_abort`\n- `srv_abrt` -> `srv_abort`\n- `hrsp_1xx` -> `http_response.1xx`\n- `hrsp_2xx` -> `http_response.2xx`\n- `hrsp_3xx` -> `http_response.3xx`\n- `hrsp_4xx` -> `http_response.4xx`\n- `hrsp_5xx` -> `http_response.5xx`\n- `hrsp_other` -> `http_response.other`\n\n## Metrics\n\nFor more details about collected metrics reference the [HAProxy CSV format\ndocumentation][6].\n\n- haproxy\n  - tags:\n    - `server` - address of the server data was gathered from\n    - `proxy` - proxy name\n    - `sv` - service name\n    - `type` - proxy session type\n  - fields:\n    - `status` (string)\n    - `check_status` (string)\n    - `last_chk` (string)\n    - `mode` (string)\n    - `tracked` (string)\n    - `agent_status` (string)\n    - `last_agt` (string)\n    - `addr` (string)\n    - `cookie` (string)\n    - `lastsess` (int)\n    - **all other stats** (int)\n\n[6]: https://cbonte.github.io/haproxy-dconv/1.8/management.html#9.1\n\n## Example Output\n\n```text\nhaproxy,server=/run/haproxy/admin.sock,proxy=public,sv=FRONTEND,type=frontend http_response.other=0i,req_rate_max=1i,comp_byp=0i,status=\"OPEN\",rate_lim=0i,dses=0i,req_rate=0i,comp_rsp=0i,bout=9287i,comp_in=0i,mode=\"http\",smax=1i,slim=2000i,http_response.1xx=0i,conn_rate=0i,dreq=0i,ereq=0i,iid=2i,rate_max=1i,http_response.2xx=1i,comp_out=0i,intercepted=1i,stot=2i,pid=1i,http_response.5xx=1i,http_response.3xx=0i,http_response.4xx=0i,conn_rate_max=1i,conn_tot=2i,dcon=0i,bin=294i,rate=0i,sid=0i,req_tot=2i,scur=0i,dresp=0i 1513293519000000000\n```\n"
  },
  {
    "path": "plugins/inputs/haproxy/haproxy.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage haproxy\n\nimport (\n\t_ \"embed\"\n\t\"encoding/csv\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\ttypeNames    = []string{\"frontend\", \"backend\", \"server\", \"listener\"}\n\tfieldRenames = map[string]string{\n\t\t\"pxname\":     \"proxy\",\n\t\t\"svname\":     \"sv\",\n\t\t\"act\":        \"active_servers\",\n\t\t\"bck\":        \"backup_servers\",\n\t\t\"cli_abrt\":   \"cli_abort\",\n\t\t\"srv_abrt\":   \"srv_abort\",\n\t\t\"hrsp_1xx\":   \"http_response.1xx\",\n\t\t\"hrsp_2xx\":   \"http_response.2xx\",\n\t\t\"hrsp_3xx\":   \"http_response.3xx\",\n\t\t\"hrsp_4xx\":   \"http_response.4xx\",\n\t\t\"hrsp_5xx\":   \"http_response.5xx\",\n\t\t\"hrsp_other\": \"http_response.other\",\n\t}\n)\n\n// CSV format: https://cbonte.github.io/haproxy-dconv/1.5/configuration.html#9.1\n\ntype HAProxy struct {\n\tServers        []string `toml:\"servers\"`\n\tKeepFieldNames bool     `toml:\"keep_field_names\"`\n\tUsername       string   `toml:\"username\"`\n\tPassword       string   `toml:\"password\"`\n\ttls.ClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*HAProxy) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HAProxy) Gather(acc telegraf.Accumulator) error {\n\tif len(h.Servers) == 0 {\n\t\treturn h.gatherServer(\"http://127.0.0.1:1936/haproxy?stats\", acc)\n\t}\n\n\tendpoints := make([]string, 0, len(h.Servers))\n\n\tfor _, endpoint := range h.Servers {\n\t\tif strings.HasPrefix(endpoint, \"http://\") || strings.HasPrefix(endpoint, \"https://\") || strings.HasPrefix(endpoint, \"tcp://\") {\n\t\t\tendpoints = append(endpoints, endpoint)\n\t\t\tcontinue\n\t\t}\n\n\t\tsocketPath := getSocketAddr(endpoint)\n\n\t\tmatches, err := filepath.Glob(socketPath)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(matches) == 0 {\n\t\t\tendpoints = append(endpoints, socketPath)\n\t\t} else {\n\t\t\tendpoints = append(endpoints, matches...)\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(endpoints))\n\tfor _, server := range endpoints {\n\t\tgo func(serv string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := h.gatherServer(serv, acc); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(server)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (h *HAProxy) gatherServerSocket(addr string, acc telegraf.Accumulator) error {\n\tvar network, address string\n\tif strings.HasPrefix(addr, \"tcp://\") {\n\t\tnetwork = \"tcp\"\n\t\taddress = strings.TrimPrefix(addr, \"tcp://\")\n\t} else {\n\t\tnetwork = \"unix\"\n\t\taddress = getSocketAddr(addr)\n\t}\n\n\tc, err := net.Dial(network, address)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not connect to '%s://%s': %w\", network, address, err)\n\t}\n\n\t_, errw := c.Write([]byte(\"show stat\\n\"))\n\tif errw != nil {\n\t\treturn fmt.Errorf(\"could not write to socket '%s://%s': %w\", network, address, errw)\n\t}\n\n\treturn h.importCsvResult(c, acc, address)\n}\n\nfunc (h *HAProxy) gatherServer(addr string, acc telegraf.Accumulator) error {\n\tif !strings.HasPrefix(addr, \"http\") {\n\t\treturn h.gatherServerSocket(addr, acc)\n\t}\n\n\tif h.client == nil {\n\t\ttlsCfg, err := h.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttr := &http.Transport{\n\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t\tTLSClientConfig:       tlsCfg,\n\t\t}\n\t\tclient := &http.Client{\n\t\t\tTransport: tr,\n\t\t\tTimeout:   4 * time.Second,\n\t\t}\n\t\th.client = client\n\t}\n\n\tif !strings.HasSuffix(addr, \";csv\") {\n\t\taddr += \"/;csv\"\n\t}\n\n\tu, err := url.Parse(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable parse server address %q: %w\", addr, err)\n\t}\n\n\treq, err := http.NewRequest(\"GET\", addr, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create new request %q: %w\", addr, err)\n\t}\n\tif u.User != nil {\n\t\tp, _ := u.User.Password()\n\t\treq.SetBasicAuth(u.User.Username(), p)\n\t\tu.User = &url.Userinfo{}\n\t\taddr = u.String()\n\t}\n\n\tif h.Username != \"\" || h.Password != \"\" {\n\t\treq.SetBasicAuth(h.Username, h.Password)\n\t}\n\n\tres, err := h.client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to haproxy server %q: %w\", addr, err)\n\t}\n\tdefer res.Body.Close()\n\n\tif res.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"unable to get valid stat result from %q, http response code : %d\", addr, res.StatusCode)\n\t}\n\n\tif err := h.importCsvResult(res.Body, acc, u.Host); err != nil {\n\t\treturn fmt.Errorf(\"unable to parse stat result from %q: %w\", addr, err)\n\t}\n\n\treturn nil\n}\n\nfunc getSocketAddr(sock string) string {\n\tsocketAddr := strings.Split(sock, \":\")\n\n\tif len(socketAddr) >= 2 {\n\t\treturn socketAddr[1]\n\t}\n\treturn socketAddr[0]\n}\n\nfunc (h *HAProxy) importCsvResult(r io.Reader, acc telegraf.Accumulator, host string) error {\n\tcsvr := csv.NewReader(r)\n\tnow := time.Now()\n\n\theaders, err := csvr.Read()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(headers[0]) <= 2 || headers[0][:2] != \"# \" {\n\t\treturn errors.New(\"did not receive standard haproxy headers\")\n\t}\n\theaders[0] = headers[0][2:]\n\n\tfor {\n\t\trow, err := csvr.Read()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\ttags := map[string]string{\n\t\t\t\"server\": host,\n\t\t}\n\n\t\tif len(row) != len(headers) {\n\t\t\treturn fmt.Errorf(\"number of columns does not match number of headers. headers=%d columns=%d\", len(headers), len(row))\n\t\t}\n\t\tfor i, v := range row {\n\t\t\tif v == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcolName := headers[i]\n\t\t\tfieldName := colName\n\t\t\tif !h.KeepFieldNames {\n\t\t\t\tif fieldRename, ok := fieldRenames[colName]; ok {\n\t\t\t\t\tfieldName = fieldRename\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch colName {\n\t\t\tcase \"pxname\", \"svname\":\n\t\t\t\ttags[fieldName] = v\n\t\t\tcase \"type\":\n\t\t\t\tvi, err := strconv.ParseInt(v, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"unable to parse type value %q\", v)\n\t\t\t\t}\n\t\t\t\tif vi >= int64(len(typeNames)) {\n\t\t\t\t\treturn fmt.Errorf(\"received unknown type value: %d\", vi)\n\t\t\t\t}\n\t\t\t\ttags[fieldName] = typeNames[vi]\n\t\t\tcase \"check_desc\", \"agent_desc\":\n\t\t\t\t// do nothing. These fields are just a more verbose description of the check_status & agent_status fields\n\t\t\tcase \"status\", \"check_status\", \"last_chk\", \"mode\", \"tracked\", \"agent_status\", \"last_agt\", \"addr\", \"cookie\":\n\t\t\t\t// these are string fields\n\t\t\t\tfields[fieldName] = v\n\t\t\tcase \"lastsess\":\n\t\t\t\tvi, err := strconv.ParseInt(v, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// TODO log the error. And just once (per column) so we don't spam the log\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[fieldName] = vi\n\t\t\tdefault:\n\t\t\t\tvi, err := strconv.ParseUint(v, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// TODO log the error. And just once (per column) so we don't spam the log\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[fieldName] = vi\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"haproxy\", fields, tags, now)\n\t}\n\treturn err\n}\n\nfunc init() {\n\tinputs.Add(\"haproxy\", func() telegraf.Input {\n\t\treturn &HAProxy{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/haproxy/haproxy_test.go",
    "content": "package haproxy\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc serverSocket(l net.Listener) {\n\tfor {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tgo func(c net.Conn) {\n\t\t\tdefer c.Close()\n\n\t\t\tbuf := make([]byte, 1024)\n\t\t\tn, err := c.Read(buf)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdata := buf[:n]\n\t\t\tif string(data) == \"show stat\\n\" {\n\t\t\t\tc.Write(csvOutputSample) //nolint:errcheck // we return anyway\n\t\t\t}\n\t\t}(conn)\n\t}\n}\n\nfunc TestHaproxyGeneratesMetricsWithAuthentication(t *testing.T) {\n\t// We create a fake server to return test data\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tusername, password, ok := r.BasicAuth()\n\t\tif !ok {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tif _, err := fmt.Fprint(w, \"Unauthorized\"); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif username == \"user\" && password == \"password\" {\n\t\t\tif _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tif _, err := fmt.Fprint(w, \"Unauthorized\"); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Now we tested again above server, with our authentication data\n\tr := &HAProxy{\n\t\tServers: []string{strings.Replace(ts.URL, \"http://\", \"http://user:password@\", 1)},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := r.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"server\": ts.Listener.Addr().String(),\n\t\t\"proxy\":  \"git\",\n\t\t\"sv\":     \"www\",\n\t\t\"type\":   \"server\",\n\t}\n\n\tfields := haproxyGetFieldValues()\n\tacc.AssertContainsTaggedFields(t, \"haproxy\", fields, tags)\n\n\t// Here, we should get error because we don't pass authentication data\n\tr = &HAProxy{\n\t\tServers: []string{ts.URL},\n\t}\n\n\trequire.NoError(t, r.Gather(&acc))\n\trequire.NotEmpty(t, acc.Errors)\n}\n\nfunc TestHaproxyGeneratesMetricsWithoutAuthentication(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &HAProxy{\n\t\tServers: []string{ts.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, r.Gather(&acc))\n\n\ttags := map[string]string{\n\t\t\"server\": ts.Listener.Addr().String(),\n\t\t\"proxy\":  \"git\",\n\t\t\"sv\":     \"www\",\n\t\t\"type\":   \"server\",\n\t}\n\n\tfields := haproxyGetFieldValues()\n\tacc.AssertContainsTaggedFields(t, \"haproxy\", fields, tags)\n}\n\nfunc TestHaproxyGeneratesMetricsUsingSocket(t *testing.T) {\n\tvar randomNumber int64\n\tvar sockets [5]net.Listener\n\n\t// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases\n\t// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.\n\t//nolint:usetesting // Ignore \"os.TempDir() could be replaced by t.TempDir() in TestHaproxyGeneratesMetricsUsingSocket\" finding.\n\ttempDir := os.TempDir()\n\t_globmask := filepath.Join(tempDir, \"test-haproxy*.sock\")\n\t_badmask := filepath.Join(tempDir, \"test-fail-haproxy*.sock\")\n\n\tfor i := 0; i < 5; i++ {\n\t\trequire.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))\n\t\tsockname := filepath.Join(tempDir, fmt.Sprintf(\"test-haproxy%d.sock\", randomNumber))\n\n\t\tsock, err := net.Listen(\"unix\", sockname)\n\t\trequire.NoError(t, err, \"Cannot initialize socket\")\n\n\t\tsockets[i] = sock\n\t\tdefer sock.Close() //nolint:revive,gocritic // done on purpose, closing will be executed properly\n\n\t\tgo serverSocket(sock)\n\t}\n\n\tr := &HAProxy{\n\t\tServers: []string{_globmask},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := r.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tfields := haproxyGetFieldValues()\n\n\tfor _, sock := range sockets {\n\t\ttags := map[string]string{\n\t\t\t\"server\": getSocketAddr(sock.Addr().String()),\n\t\t\t\"proxy\":  \"git\",\n\t\t\t\"sv\":     \"www\",\n\t\t\t\"type\":   \"server\",\n\t\t}\n\n\t\tacc.AssertContainsTaggedFields(t, \"haproxy\", fields, tags)\n\t}\n\n\t// This mask should not match any socket\n\tr.Servers = []string{_badmask}\n\n\trequire.NoError(t, r.Gather(&acc))\n\trequire.NotEmpty(t, acc.Errors)\n}\n\nfunc TestHaproxyGeneratesMetricsUsingTcp(t *testing.T) {\n\tl, err := net.Listen(\"tcp\", \"localhost:8192\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer l.Close()\n\n\tgo serverSocket(l)\n\n\tr := &HAProxy{\n\t\tServers: []string{\"tcp://\" + l.Addr().String()},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, r.Gather(&acc))\n\n\tfields := haproxyGetFieldValues()\n\n\ttags := map[string]string{\n\t\t\"server\": l.Addr().String(),\n\t\t\"proxy\":  \"git\",\n\t\t\"sv\":     \"www\",\n\t\t\"type\":   \"server\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"haproxy\", fields, tags)\n\n\trequire.NoError(t, r.Gather(&acc))\n}\n\n// When not passing server config, we default to localhost\n// We just want to make sure we did request stat from localhost\nfunc TestHaproxyDefaultGetFromLocalhost(t *testing.T) {\n\tr := &HAProxy{}\n\n\tvar acc testutil.Accumulator\n\n\terr := r.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"127.0.0.1:1936/haproxy?stats/;csv\")\n}\n\nfunc TestHaproxyKeepFieldNames(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &HAProxy{\n\t\tServers:        []string{ts.URL},\n\t\tKeepFieldNames: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, r.Gather(&acc))\n\n\ttags := map[string]string{\n\t\t\"server\": ts.Listener.Addr().String(),\n\t\t\"pxname\": \"git\",\n\t\t\"svname\": \"www\",\n\t\t\"type\":   \"server\",\n\t}\n\n\tfields := haproxyGetFieldValues()\n\tfields[\"act\"] = fields[\"active_servers\"]\n\tdelete(fields, \"active_servers\")\n\tfields[\"bck\"] = fields[\"backup_servers\"]\n\tdelete(fields, \"backup_servers\")\n\tfields[\"cli_abrt\"] = fields[\"cli_abort\"]\n\tdelete(fields, \"cli_abort\")\n\tfields[\"srv_abrt\"] = fields[\"srv_abort\"]\n\tdelete(fields, \"srv_abort\")\n\tfields[\"hrsp_1xx\"] = fields[\"http_response.1xx\"]\n\tdelete(fields, \"http_response.1xx\")\n\tfields[\"hrsp_2xx\"] = fields[\"http_response.2xx\"]\n\tdelete(fields, \"http_response.2xx\")\n\tfields[\"hrsp_3xx\"] = fields[\"http_response.3xx\"]\n\tdelete(fields, \"http_response.3xx\")\n\tfields[\"hrsp_4xx\"] = fields[\"http_response.4xx\"]\n\tdelete(fields, \"http_response.4xx\")\n\tfields[\"hrsp_5xx\"] = fields[\"http_response.5xx\"]\n\tdelete(fields, \"http_response.5xx\")\n\tfields[\"hrsp_other\"] = fields[\"http_response.other\"]\n\tdelete(fields, \"http_response.other\")\n\n\tacc.AssertContainsTaggedFields(t, \"haproxy\", fields, tags)\n}\n\nfunc mustReadSampleOutput() []byte {\n\tfilePath := \"testdata/sample_output.csv\"\n\tdata, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"could not read from file %s: %w\", filePath, err))\n\t}\n\n\treturn data\n}\n\nfunc haproxyGetFieldValues() map[string]interface{} {\n\tfields := map[string]interface{}{\n\t\t\"active_servers\":      uint64(1),\n\t\t\"backup_servers\":      uint64(0),\n\t\t\"bin\":                 uint64(5228218),\n\t\t\"bout\":                uint64(303747244),\n\t\t\"check_code\":          uint64(200),\n\t\t\"check_duration\":      uint64(3),\n\t\t\"check_fall\":          uint64(3),\n\t\t\"check_health\":        uint64(4),\n\t\t\"check_rise\":          uint64(2),\n\t\t\"check_status\":        \"L7OK\",\n\t\t\"chkdown\":             uint64(84),\n\t\t\"chkfail\":             uint64(559),\n\t\t\"cli_abort\":           uint64(690),\n\t\t\"ctime\":               uint64(1),\n\t\t\"downtime\":            uint64(3352),\n\t\t\"dresp\":               uint64(0),\n\t\t\"econ\":                uint64(0),\n\t\t\"eresp\":               uint64(21),\n\t\t\"http_response.1xx\":   uint64(0),\n\t\t\"http_response.2xx\":   uint64(5668),\n\t\t\"http_response.3xx\":   uint64(8710),\n\t\t\"http_response.4xx\":   uint64(140),\n\t\t\"http_response.5xx\":   uint64(0),\n\t\t\"http_response.other\": uint64(0),\n\t\t\"iid\":                 uint64(4),\n\t\t\"last_chk\":            \"OK\",\n\t\t\"lastchg\":             uint64(1036557),\n\t\t\"lastsess\":            int64(1342),\n\t\t\"lbtot\":               uint64(9481),\n\t\t\"mode\":                \"http\",\n\t\t\"pid\":                 uint64(1),\n\t\t\"qcur\":                uint64(0),\n\t\t\"qmax\":                uint64(0),\n\t\t\"qtime\":               uint64(1268),\n\t\t\"rate\":                uint64(0),\n\t\t\"rate_max\":            uint64(2),\n\t\t\"rtime\":               uint64(2908),\n\t\t\"sid\":                 uint64(1),\n\t\t\"scur\":                uint64(0),\n\t\t\"slim\":                uint64(2),\n\t\t\"smax\":                uint64(2),\n\t\t\"srv_abort\":           uint64(0),\n\t\t\"status\":              \"UP\",\n\t\t\"stot\":                uint64(14539),\n\t\t\"ttime\":               uint64(4500),\n\t\t\"weight\":              uint64(1),\n\t\t\"wredis\":              uint64(0),\n\t\t\"wretr\":               uint64(0),\n\t}\n\treturn fields\n}\n\n// Can obtain from official haproxy demo: 'http://demo.haproxy.org/;csv'\nvar csvOutputSample = mustReadSampleOutput()\n"
  },
  {
    "path": "plugins/inputs/haproxy/sample.conf",
    "content": "# Read metrics of HAProxy, via stats socket or http endpoints\n[[inputs.haproxy]]\n  ## List of stats endpoints. Metrics can be collected from both http and socket\n  ## endpoints. Examples of valid endpoints:\n  ##   - http://myhaproxy.com:1936/haproxy?stats\n  ##   - https://myhaproxy.com:8000/stats\n  ##   - socket:/run/haproxy/admin.sock\n  ##   - /run/haproxy/*.sock\n  ##   - tcp://127.0.0.1:1936\n  ##\n  ## Server addresses not starting with 'http://', 'https://', 'tcp://' will be\n  ## treated as possible sockets. When specifying local socket, glob patterns are\n  ## supported.\n  servers = [\"http://myhaproxy.com:1936/haproxy?stats\"]\n\n  ## By default, some of the fields are renamed from what haproxy calls them.\n  ## Setting this option to true results in the plugin keeping the original\n  ## field names.\n  # keep_field_names = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/haproxy/testdata/sample_output.csv",
    "content": "\n# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,agent_status,agent_code,agent_duration,check_desc,agent_desc,check_rise,check_fall,check_health,agent_rise,agent_fall,agent_health,addr,cookie,mode,algo,conn_rate,conn_rate_max,conn_tot,intercepted,dcon,dses,\nhttp-in,FRONTEND,,,3,100,100,2639994,813557487,65937668635,505252,0,47567,,,,,OPEN,,,,,,,,,1,2,0,,,,0,1,0,157,,,,0,1514640,606647,136264,496535,14948,,1,155,2754255,,,36370569635,17435137766,0,642264,,,,,,,,,,,,,,,,,,,,,http,,1,157,2649922,339471,0,0,\nhttp-in,IPv4-direct,,,3,41,100,349801,57445827,1503928881,269899,0,287,,,,,OPEN,,,,,,,,,1,2,1,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,\nhttp-in,IPv4-cached,,,0,33,100,1786155,644395819,57905460294,60511,0,1,,,,,OPEN,,,,,,,,,1,2,2,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,\nhttp-in,IPv6-direct,,,0,100,100,325619,92414745,6205208728,3399,0,47279,,,,,OPEN,,,,,,,,,1,2,3,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,\nhttp-in,local,,,0,0,100,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,4,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,\nhttp-in,local-https,,,0,5,100,188347,19301096,323070732,171443,0,0,,,,,OPEN,,,,,,,,,1,2,5,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,\nwww,www,0,0,0,20,20,1719698,672044109,64806076656,,0,,0,5285,22,0,UP,1,1,0,561,84,1036557,3356,,1,3,1,,1715117,,2,0,,45,L7OK,200,5,671,1144889,481714,87038,4,0,,,,,105016,167,,,,,5,OK,,0,5,16,1167,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,\nwww,bck,0,0,0,10,10,1483,537137,7544118,,0,,0,0,0,0,UP,1,0,1,4,0,5218087,0,,1,3,2,,1371,,2,0,,17,L7OK,200,2,0,629,99,755,0,0,,,,,16,0,,,,,1036557,OK,,756,1,13,1184,,,,Layer7 check passed,,2,5,6,,,,,,http,,,,,,,,\nwww,BACKEND,0,25,0,46,100,1721835,674684790,64813732170,314,0,,130,5285,22,0,UP,1,1,1,,0,5218087,0,,1,3,0,,1716488,,1,0,,45,,,,0,1145518,481813,88664,5719,121,,,,1721835,105172,167,35669268059,17250148556,0,556042,5,,,0,5,16,1167,,,,,,,,,,,,,,http,,,,,,,,\ngit,www,0,0,0,2,2,14539,5228218,303747244,,0,,0,21,0,0,UP,1,1,0,559,84,1036557,3352,,1,4,1,,9481,,2,0,,2,L7OK,200,3,0,5668,8710,140,0,0,,,,,690,0,,,,,1342,OK,,1268,1,2908,4500,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,\ngit,bck,0,0,0,0,2,0,0,0,,0,,0,0,0,0,UP,1,0,1,2,0,5218087,0,,1,4,2,,0,,2,0,,0,L7OK,200,2,0,0,0,0,0,0,,,,,0,0,,,,,-1,OK,,0,0,0,0,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,\ngit,BACKEND,0,6,0,8,2,14541,8082393,303747668,0,0,,2,21,0,0,UP,1,1,1,,0,5218087,0,,1,4,0,,9481,,1,0,,7,,,,0,5668,8710,140,23,0,,,,14541,690,0,133458298,38104818,0,4379,1342,,,1268,1,2908,4500,,,,,,,,,,,,,,http,,,,,,,,\ndemo,BACKEND,0,0,1,5,20,24063,7876647,659864417,48,0,,1,0,0,0,UP,0,0,0,,0,5218087,,,1,17,0,,0,,1,1,,26,,,,0,23983,21,0,1,57,,,,24062,111,0,567843278,146884392,0,1083,0,,,2706,0,0,887,,,,,,,,,,,,,,http,,,,,,,,\n"
  },
  {
    "path": "plugins/inputs/hddtemp/README.md",
    "content": "# HDDtemp Input Plugin\n\nThis plugin reads data from a [hddtemp][hddtemp] daemon.\n\n> [!IMPORTANT]\n> This plugin requires `hddtemp` to be installed and running as a daemon.\n\nAs the upstream project is not activly maintained anymore and various\ndistributions (e.g. Debian Bookwork and later) don't ship packages for `hddtemp`\nanymore, the binary might not be available (e.g. in Ubuntu 22.04 or later).\n\n> [!TIP]\n> As an alternative consider using the [smartctl][smartctl] relying on\n> SMART information or [sensors][sensors] plugins to retrieve temperature data\n> of your hard-drive.\n\n⭐ Telegraf v1.0.0\n🏷️ hardware, system\n💻 all\n\n[hddtemp]: https://savannah.nongnu.org/projects/hddtemp/\n[smartctl]: /plugins/inputs/smartctl/README.md\n[sensors]: /plugins/inputs/sensors/README.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Monitor disks' temperatures using hddtemp\n[[inputs.hddtemp]]\n  ## By default, telegraf gathers temps data from all disks detected by the\n  ## hddtemp.\n  ##\n  ## Only collect temps from the selected disks.\n  ##\n  ## A * as the device name will return the temperature values of all disks.\n  ##\n  # address = \"127.0.0.1:7634\"\n  # devices = [\"sda\", \"*\"]\n```\n\n## Metrics\n\n- hddtemp\n  - tags:\n    - device\n    - model\n    - unit\n    - status\n    - source\n  - fields:\n    - temperature\n\n## Example Output\n\n```text\nhddtemp,source=server1,unit=C,status=,device=sdb,model=WDC\\ WD740GD-00FLA1 temperature=43i 1481655647000000000\nhddtemp,device=sdc,model=SAMSUNG\\ HD103UI,unit=C,source=server1,status= temperature=38i 148165564700000000\nhddtemp,device=sdd,model=SAMSUNG\\ HD103UI,unit=C,source=server1,status= temperature=36i 1481655647000000000\n```\n"
  },
  {
    "path": "plugins/inputs/hddtemp/go-hddtemp/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Mendelson Gusmão\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "plugins/inputs/hddtemp/go-hddtemp/hddtemp.go",
    "content": "package hddtemp\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Disk contains disk data gathered from hddtemp\ntype Disk struct {\n\tDeviceName  string\n\tModel       string\n\tTemperature int32\n\tUnit        string\n\tStatus      string\n}\n\ntype hddtemp struct{}\n\n// New creates hddtemp\nfunc New() *hddtemp {\n\treturn &hddtemp{}\n}\n\n// Fetch gathers disks data from hddtemp daemon.\nfunc (*hddtemp) Fetch(address string) ([]Disk, error) {\n\tvar (\n\t\terr    error\n\t\tconn   net.Conn\n\t\tbuffer bytes.Buffer\n\t)\n\n\tif conn, err = net.Dial(\"tcp\", address); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif _, err = io.Copy(&buffer, conn); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfields := strings.Split(buffer.String(), \"|\")\n\n\tsize := len(fields) / 5\n\tdisks := make([]Disk, 0, size)\n\tfor index := 0; index < size; index++ {\n\t\tstatus := \"\"\n\t\toffset := index * 5\n\t\tdevice := fields[offset+1]\n\t\tdevice = device[strings.LastIndex(device, \"/\")+1:]\n\n\t\ttemperatureField := fields[offset+3]\n\t\ttemperature, err := strconv.ParseInt(temperatureField, 10, 32)\n\n\t\tif err != nil {\n\t\t\ttemperature = 0\n\t\t\tstatus = temperatureField\n\t\t}\n\n\t\tdisks = append(disks, Disk{\n\t\t\tDeviceName:  device,\n\t\t\tModel:       fields[offset+2],\n\t\t\tTemperature: int32(temperature),\n\t\t\tUnit:        fields[offset+4],\n\t\t\tStatus:      status,\n\t\t})\n\t}\n\n\treturn disks, nil\n}\n"
  },
  {
    "path": "plugins/inputs/hddtemp/go-hddtemp/hddtemp_test.go",
    "content": "package hddtemp\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFetch(t *testing.T) {\n\tl := serve(t, []byte(\"|/dev/sda|foobar|36|C|\"))\n\tdefer l.Close()\n\n\tdisks, err := New().Fetch(l.Addr().String())\n\trequire.NoError(t, err)\n\n\texpected := []Disk{\n\t\t{\n\t\t\tDeviceName:  \"sda\",\n\t\t\tModel:       \"foobar\",\n\t\t\tTemperature: 36,\n\t\t\tUnit:        \"C\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, disks, \"disks' slice is different from expected\")\n}\n\nfunc TestFetchWrongAddress(t *testing.T) {\n\t_, err := New().Fetch(\"127.0.0.1:1\")\n\trequire.Error(t, err)\n}\n\nfunc TestFetchStatus(t *testing.T) {\n\tl := serve(t, []byte(\"|/dev/sda|foobar|SLP|C|\"))\n\tdefer l.Close()\n\n\tdisks, err := New().Fetch(l.Addr().String())\n\trequire.NoError(t, err)\n\n\texpected := []Disk{\n\t\t{\n\t\t\tDeviceName:  \"sda\",\n\t\t\tModel:       \"foobar\",\n\t\t\tTemperature: 0,\n\t\t\tUnit:        \"C\",\n\t\t\tStatus:      \"SLP\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, disks, \"disks' slice is different from expected\")\n}\n\nfunc TestFetchTwoDisks(t *testing.T) {\n\tl := serve(t, []byte(\"|/dev/hda|ST380011A|46|C||/dev/hdd|ST340016A|SLP|*|\"))\n\tdefer l.Close()\n\n\tdisks, err := New().Fetch(l.Addr().String())\n\trequire.NoError(t, err)\n\n\texpected := []Disk{\n\t\t{\n\t\t\tDeviceName:  \"hda\",\n\t\t\tModel:       \"ST380011A\",\n\t\t\tTemperature: 46,\n\t\t\tUnit:        \"C\",\n\t\t},\n\t\t{\n\t\t\tDeviceName:  \"hdd\",\n\t\t\tModel:       \"ST340016A\",\n\t\t\tTemperature: 0,\n\t\t\tUnit:        \"*\",\n\t\t\tStatus:      \"SLP\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, disks, \"disks' slice is different from expected\")\n}\n\nfunc serve(t *testing.T, data []byte) net.Listener {\n\tl, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tgo func(t *testing.T) {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = conn.Write(data); err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tif err = conn.Close(); err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}(t)\n\n\treturn l\n}\n"
  },
  {
    "path": "plugins/inputs/hddtemp/hddtemp.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage hddtemp\n\nimport (\n\t_ \"embed\"\n\t\"net\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tgohddtemp \"github.com/influxdata/telegraf/plugins/inputs/hddtemp/go-hddtemp\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultAddress = \"127.0.0.1:7634\"\n\ntype HDDTemp struct {\n\tAddress string   `toml:\"address\"`\n\tDevices []string `toml:\"devices\"`\n\n\tfetcher fetcher\n}\n\ntype fetcher interface {\n\tFetch(address string) ([]gohddtemp.Disk, error)\n}\n\nfunc (*HDDTemp) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HDDTemp) Gather(acc telegraf.Accumulator) error {\n\tif h.fetcher == nil {\n\t\th.fetcher = gohddtemp.New()\n\t}\n\tsource, _, err := net.SplitHostPort(h.Address)\n\tif err != nil {\n\t\tsource = h.Address\n\t}\n\n\tdisks, err := h.fetcher.Fetch(h.Address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, disk := range disks {\n\t\tfor _, chosenDevice := range h.Devices {\n\t\t\tif chosenDevice == \"*\" || chosenDevice == disk.DeviceName {\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"device\": disk.DeviceName,\n\t\t\t\t\t\"model\":  disk.Model,\n\t\t\t\t\t\"unit\":   disk.Unit,\n\t\t\t\t\t\"status\": disk.Status,\n\t\t\t\t\t\"source\": source,\n\t\t\t\t}\n\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"temperature\": disk.Temperature,\n\t\t\t\t}\n\n\t\t\t\tacc.AddFields(\"hddtemp\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"hddtemp\", func() telegraf.Input {\n\t\treturn &HDDTemp{\n\t\t\tAddress: defaultAddress,\n\t\t\tDevices: []string{\"*\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/hddtemp/hddtemp_test.go",
    "content": "package hddtemp\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/hddtemp/go-hddtemp\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockFetcher struct {\n}\n\nfunc (*mockFetcher) Fetch(string) ([]hddtemp.Disk, error) {\n\treturn []hddtemp.Disk{\n\t\t{\n\t\t\tDeviceName:  \"Disk1\",\n\t\t\tModel:       \"Model1\",\n\t\t\tTemperature: 13,\n\t\t\tUnit:        \"C\",\n\t\t},\n\t\t{\n\t\t\tDeviceName:  \"Disk2\",\n\t\t\tModel:       \"Model2\",\n\t\t\tTemperature: 14,\n\t\t\tUnit:        \"C\",\n\t\t},\n\t}, nil\n}\n\nfunc newMockFetcher() *mockFetcher {\n\treturn &mockFetcher{}\n}\n\nfunc TestFetch(t *testing.T) {\n\thddTemp := &HDDTemp{\n\t\tfetcher: newMockFetcher(),\n\t\tAddress: \"localhost\",\n\t\tDevices: []string{\"*\"},\n\t}\n\n\tacc := &testutil.Accumulator{}\n\terr := hddTemp.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.Equal(t, 2, acc.NFields())\n\n\tvar tests = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temperature\": int32(13),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"Disk1\",\n\t\t\t\t\"model\":  \"Model1\",\n\t\t\t\t\"unit\":   \"C\",\n\t\t\t\t\"status\": \"\",\n\t\t\t\t\"source\": \"localhost\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temperature\": int32(14),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"Disk2\",\n\t\t\t\t\"model\":  \"Model2\",\n\t\t\t\t\"unit\":   \"C\",\n\t\t\t\t\"status\": \"\",\n\t\t\t\t\"source\": \"localhost\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tacc.AssertContainsTaggedFields(t, \"hddtemp\", test.fields, test.tags)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/hddtemp/sample.conf",
    "content": "# Monitor disks' temperatures using hddtemp\n[[inputs.hddtemp]]\n  ## By default, telegraf gathers temps data from all disks detected by the\n  ## hddtemp.\n  ##\n  ## Only collect temps from the selected disks.\n  ##\n  ## A * as the device name will return the temperature values of all disks.\n  ##\n  # address = \"127.0.0.1:7634\"\n  # devices = [\"sda\", \"*\"]\n"
  },
  {
    "path": "plugins/inputs/http/README.md",
    "content": "# HTTP Input Plugin\n\nThis plugin collects metrics from one or more HTTP endpoints providing data in\none of the supported [data formats][data_formats].\n\n⭐ Telegraf v1.6.0\n🏷️ applications, server\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username`, `password`,\n`token`, `headers`, and `cookie_auth_headers` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read formatted metrics from one or more HTTP endpoints\n[[inputs.http]]\n  ## One or more URLs from which to read formatted metrics.\n  urls = [\n    \"http://localhost/metrics\",\n    \"http+unix:///run/user/420/podman/podman.sock:/d/v4.0.0/libpod/pods/json\"\n  ]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP entity-body to send with POST/PUT requests.\n  # body = \"\"\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## Optional Bearer token settings to use for the API calls.\n  ## Use either the token itself or the token file if you need a token.\n  # token = \"eyJhbGc...Qssw5c\"\n  # token_file = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # audience = \"\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"0s\"\n\n  ## List of success status codes\n  # success_status_codes = [200]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n\n```\n\nHTTP requests over Unix domain sockets can be specified via the \"http+unix\" or\n\"https+unix\" schemes.\nRequest URLs should have the following form:\n\n```text\nhttp+unix:///path/to/service.sock:/api/endpoint\n```\n\nNote: The path to the Unix domain socket and the request endpoint are separated\nby a colon (\":\").\n\n## Example Output\n\nThis example output was taken from [this instructional article][1].\n\n[1]: https://docs.influxdata.com/telegraf/v1/configure_plugins/input_plugins/using_http/\n\n```text\ncitibike,station_id=4703 eightd_has_available_keys=false,is_installed=1,is_renting=1,is_returning=1,legacy_id=\"4703\",num_bikes_available=6,num_bikes_disabled=2,num_docks_available=26,num_docks_disabled=0,num_ebikes_available=0,station_status=\"active\" 1641505084000000000\ncitibike,station_id=4704 eightd_has_available_keys=false,is_installed=1,is_renting=1,is_returning=1,legacy_id=\"4704\",num_bikes_available=10,num_bikes_disabled=2,num_docks_available=36,num_docks_disabled=0,num_ebikes_available=0,station_status=\"active\" 1641505084000000000\ncitibike,station_id=4711 eightd_has_available_keys=false,is_installed=1,is_renting=1,is_returning=1,legacy_id=\"4711\",num_bikes_available=9,num_bikes_disabled=0,num_docks_available=36,num_docks_disabled=0,num_ebikes_available=1,station_status=\"active\" 1641505084000000000\n```\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the configured\n`data_format` and the payload returned by the HTTP endpoint(s).\n\nThe default values below are added if the input format does not specify a value:\n\n- http\n  - tags:\n    - url\n\n## Optional Cookie Authentication Settings\n\nThe optional Cookie Authentication Settings will retrieve a cookie from the\ngiven authorization endpoint, and use it in subsequent API requests.  This is\nuseful for services that do not provide OAuth or Basic Auth authentication,\ne.g. the [Tesla Powerwall API][tesla], which uses a Cookie Auth Body to retrieve\nan authorization cookie.  The Cookie Auth Renewal interval will renew the\nauthorization by retrieving a new cookie at the given interval.\n\n[tesla]: https://www.tesla.com/support/energy/powerwall/own/monitoring-from-home-network\n"
  },
  {
    "path": "plugins/inputs/http/http.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage http\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype HTTP struct {\n\tURLs            []string `toml:\"urls\"`\n\tMethod          string   `toml:\"method\"`\n\tBody            string   `toml:\"body\"`\n\tContentEncoding string   `toml:\"content_encoding\"`\n\n\t// Basic authentication\n\tUsername config.Secret `toml:\"username\"`\n\tPassword config.Secret `toml:\"password\"`\n\n\t// Bearer authentication\n\tToken     config.Secret `toml:\"token\"`\n\tTokenFile string        `toml:\"token_file\"`\n\n\tHeaders            map[string]*config.Secret `toml:\"headers\"`\n\tSuccessStatusCodes []int                     `toml:\"success_status_codes\"`\n\tLog                telegraf.Logger           `toml:\"-\"`\n\n\tcommon_http.HTTPClientConfig\n\n\tclient     *http.Client\n\tparserFunc telegraf.ParserFunc\n}\n\nfunc (*HTTP) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HTTP) Init() error {\n\t// We cannot use multiple sources for tokens\n\tif h.TokenFile != \"\" && !h.Token.Empty() {\n\t\treturn errors.New(\"either use 'token_file' or 'token' not both\")\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := h.HTTPClientConfig.CreateClient(ctx, h.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\th.client = client\n\n\t// Set default as [200]\n\tif len(h.SuccessStatusCodes) == 0 {\n\t\th.SuccessStatusCodes = []int{200}\n\t}\n\treturn nil\n}\n\nfunc (h *HTTP) SetParserFunc(fn telegraf.ParserFunc) {\n\th.parserFunc = fn\n}\n\nfunc (*HTTP) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (h *HTTP) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, u := range h.URLs {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := h.gatherURL(acc, url); err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"[url=%s]: %w\", url, err))\n\t\t\t}\n\t\t}(u)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (h *HTTP) Stop() {\n\tif h.client != nil {\n\t\th.client.CloseIdleConnections()\n\t}\n}\n\n// Gathers data from a particular URL\n// Parameters:\n//\n//\tacc    : The telegraf Accumulator to use\n//\turl    : endpoint to send request to\n//\n// Returns:\n//\n//\terror: Any error that may have occurred\nfunc (h *HTTP) gatherURL(acc telegraf.Accumulator, url string) error {\n\tbody := makeRequestBodyReader(h.ContentEncoding, h.Body)\n\tif body != nil {\n\t\tdefer body.Close()\n\t}\n\n\trequest, err := http.NewRequest(h.Method, url, body)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif body != nil && h.ContentEncoding != \"gzip\" {\n\t\trequest.ContentLength = int64(len(h.Body))\n\t}\n\n\tif !h.Token.Empty() {\n\t\ttoken, err := h.Token.Get()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbearer := \"Bearer \" + strings.TrimSpace(token.String())\n\t\ttoken.Destroy()\n\t\trequest.Header.Set(\"Authorization\", bearer)\n\t} else if h.TokenFile != \"\" {\n\t\ttoken, err := os.ReadFile(h.TokenFile)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbearer := \"Bearer \" + strings.Trim(string(token), \"\\n\")\n\t\trequest.Header.Set(\"Authorization\", bearer)\n\t}\n\n\tif h.ContentEncoding == \"gzip\" {\n\t\trequest.Header.Set(\"Content-Encoding\", \"gzip\")\n\t}\n\n\tfor k, v := range h.Headers {\n\t\tsecret, err := v.Get()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\theaderVal := secret.String()\n\t\tif strings.EqualFold(k, \"host\") {\n\t\t\trequest.Host = headerVal\n\t\t} else {\n\t\t\trequest.Header.Add(k, headerVal)\n\t\t}\n\n\t\tsecret.Destroy()\n\t}\n\n\tif err := h.setRequestAuth(request); err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := h.client.Do(request)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tresponseHasSuccessCode := false\n\tfor _, statusCode := range h.SuccessStatusCodes {\n\t\tif resp.StatusCode == statusCode {\n\t\t\tresponseHasSuccessCode = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !responseHasSuccessCode {\n\t\treturn fmt.Errorf(\"received status code %d (%s), expected any value out of %v\",\n\t\t\tresp.StatusCode,\n\t\t\thttp.StatusText(resp.StatusCode),\n\t\t\th.SuccessStatusCodes)\n\t}\n\n\tb, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading body failed: %w\", err)\n\t}\n\n\t// Instantiate a new parser for the new data to avoid trouble with stateful parsers\n\tparser, err := h.parserFunc()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"instantiating parser failed: %w\", err)\n\t}\n\tmetrics, err := parser.Parse(b)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing metrics failed: %w\", err)\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\th.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tfor _, metric := range metrics {\n\t\tif !metric.HasTag(\"url\") {\n\t\t\tmetric.AddTag(\"url\", url)\n\t\t}\n\t\tacc.AddFields(metric.Name(), metric.Fields(), metric.Tags(), metric.Time())\n\t}\n\n\treturn nil\n}\n\nfunc (h *HTTP) setRequestAuth(request *http.Request) error {\n\tif h.Username.Empty() && h.Password.Empty() {\n\t\treturn nil\n\t}\n\n\tusername, err := h.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tdefer username.Destroy()\n\n\tpassword, err := h.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer password.Destroy()\n\n\trequest.SetBasicAuth(username.String(), password.String())\n\n\treturn nil\n}\n\nfunc makeRequestBodyReader(contentEncoding, body string) io.ReadCloser {\n\tif body == \"\" {\n\t\treturn nil\n\t}\n\n\treader := strings.NewReader(body)\n\tif contentEncoding == \"gzip\" {\n\t\treturn internal.CompressWithGzip(reader)\n\t}\n\n\treturn io.NopCloser(reader)\n}\n\nfunc init() {\n\tinputs.Add(\"http\", func() telegraf.Input {\n\t\treturn &HTTP{\n\t\t\tMethod: \"GET\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/http/http_internal_test.go",
    "content": "package http\n\nimport (\n\t\"compress/gzip\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMakeRequestBodyReaderEmptyBody(t *testing.T) {\n\tbody := makeRequestBodyReader(\"\", \"\")\n\trequire.Nil(t, body)\n}\n\nfunc TestMakeRequestBodyReaderNoEncoding(t *testing.T) {\n\tbody := makeRequestBodyReader(\"\", \"payload\")\n\trequire.NotNil(t, body)\n\tt.Cleanup(func() { _ = body.Close() })\n\n\tactual, err := io.ReadAll(body)\n\trequire.NoError(t, err)\n\trequire.Equal(t, []byte(\"payload\"), actual)\n}\n\nfunc TestMakeRequestBodyReaderGzip(t *testing.T) {\n\tbody := makeRequestBodyReader(\"gzip\", \"payload\")\n\trequire.NotNil(t, body)\n\tt.Cleanup(func() { _ = body.Close() })\n\n\treader, err := gzip.NewReader(body)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { _ = reader.Close() })\n\n\tactual, err := io.ReadAll(reader)\n\trequire.NoError(t, err)\n\trequire.Equal(t, []byte(\"payload\"), actual)\n}\n\nfunc TestGatherURLEarlyFailureWithGzipBody(t *testing.T) {\n\th := &HTTP{\n\t\tMethod:          \"BAD METHOD\",\n\t\tBody:            \"payload\",\n\t\tContentEncoding: \"gzip\",\n\t}\n\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\tdone <- h.gatherURL(nil, \"http://example.com\")\n\t}()\n\n\tselect {\n\tcase err := <-done:\n\t\trequire.Error(t, err)\n\tcase <-time.After(2 * time.Second):\n\t\tt.Fatal(\"gatherURL timed out on early failure\")\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/http/http_test.go",
    "content": "package http_test\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/common/oauth\"\n\thttpplugin \"github.com/influxdata/telegraf/plugins/inputs/http\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/csv\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/value\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestHTTPWithJSONFormat(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(simpleJSON)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\tplugin := &httpplugin.HTTP{\n\t\tURLs: []string{address},\n\t\tLog:  testutil.Logger{},\n\t}\n\tmetricName := \"metricName\"\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.Len(t, acc.Metrics, 1)\n\n\t// basic check to see if we got the right field, value and tag\n\tvar metric = acc.Metrics[0]\n\trequire.Equal(t, metric.Measurement, metricName)\n\trequire.Len(t, acc.Metrics[0].Fields, 1)\n\trequire.InDelta(t, 1.2, acc.Metrics[0].Fields[\"a\"], testutil.DefaultDelta)\n\trequire.Equal(t, acc.Metrics[0].Tags[\"url\"], address)\n}\n\nfunc TestHTTPHeaders(t *testing.T) {\n\theader := \"X-Special-Header\"\n\theaderValue := \"Special-Value\"\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif r.Header.Get(header) == headerValue {\n\t\t\t\tif _, err := w.Write([]byte(simpleJSON)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\theaderSecret := config.NewSecret([]byte(headerValue))\n\tplugin := &httpplugin.HTTP{\n\t\tURLs:    []string{address},\n\t\tHeaders: map[string]*config.Secret{header: &headerSecret},\n\t\tLog:     testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestHTTPContentLengthHeader(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif r.Header.Get(\"Content-Length\") != \"\" {\n\t\t\t\tif _, err := w.Write([]byte(simpleJSON)); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\tplugin := &httpplugin.HTTP{\n\t\tURLs:    []string{address},\n\t\tHeaders: map[string]*config.Secret{},\n\t\tBody:    \"{}\",\n\t\tLog:     testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestInvalidStatusCode(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\tplugin := &httpplugin.HTTP{\n\t\tURLs: []string{address},\n\t\tLog:  testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.Error(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestSuccessStatusCodes(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusAccepted)\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\tplugin := &httpplugin.HTTP{\n\t\tURLs:               []string{address},\n\t\tSuccessStatusCodes: []int{200, 202},\n\t\tLog:                testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestMethod(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method == \"POST\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\tplugin := &httpplugin.HTTP{\n\t\tURLs:   []string{fakeServer.URL},\n\t\tMethod: \"POST\",\n\t\tLog:    testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tp := &json.Parser{MetricName: \"metricName\"}\n\t\terr := p.Init()\n\t\treturn p, err\n\t})\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n}\n\nconst simpleJSON = `\n{\n    \"a\": 1.2\n}\n`\nconst simpleCSVWithHeader = `\n# Simple CSV with header(s)\na,b,c\n1.2,3.1415,ok\n`\n\nfunc TestBodyAndContentEncoding(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\taddress := \"http://\" + ts.Listener.Addr().String()\n\n\ttests := []struct {\n\t\tname             string\n\t\tplugin           *httpplugin.HTTP\n\t\tqueryHandlerFunc func(t *testing.T, w http.ResponseWriter, r *http.Request)\n\t}{\n\t\t{\n\t\t\tname: \"no body\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tMethod: \"POST\",\n\t\t\t\tURLs:   []string{address},\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t},\n\t\t\tqueryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\tbody, err := io.ReadAll(r.Body)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, []byte(\"\"), body)\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"post body\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tURLs:   []string{address},\n\t\t\t\tMethod: \"POST\",\n\t\t\t\tBody:   \"test\",\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t},\n\t\t\tqueryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\tbody, err := io.ReadAll(r.Body)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, []byte(\"test\"), body)\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"get method body is sent\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tURLs:   []string{address},\n\t\t\t\tMethod: \"GET\",\n\t\t\t\tBody:   \"test\",\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t},\n\t\t\tqueryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\tbody, err := io.ReadAll(r.Body)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, []byte(\"test\"), body)\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"gzip encoding\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tURLs:            []string{address},\n\t\t\t\tMethod:          \"GET\",\n\t\t\t\tBody:            \"test\",\n\t\t\t\tContentEncoding: \"gzip\",\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t},\n\t\t\tqueryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\trequire.Equal(t, \"gzip\", r.Header.Get(\"Content-Encoding\"))\n\n\t\t\t\tgr, err := gzip.NewReader(r.Body)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tbody, err := io.ReadAll(gr)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, []byte(\"test\"), body)\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\ttt.queryHandlerFunc(t, w, r)\n\t\t\t})\n\n\t\t\ttt.plugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\t\tparser := &influx.Parser{}\n\t\t\t\terr := parser.Init()\n\t\t\t\treturn parser, err\n\t\t\t})\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\t\t\trequire.NoError(t, tt.plugin.Gather(&acc))\n\t\t})\n\t}\n}\n\ntype testHandlerFunc func(t *testing.T, w http.ResponseWriter, r *http.Request)\n\nfunc TestOAuthClientCredentialsGrant(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tvar token = \"2YotnFZFEjr1zCsicMWpAA\"\n\n\tu, err := url.Parse(\"http://\" + ts.Listener.Addr().String())\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname         string\n\t\tplugin       *httpplugin.HTTP\n\t\ttokenHandler testHandlerFunc\n\t\thandler      testHandlerFunc\n\t}{\n\t\t{\n\t\t\tname: \"no credentials\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tURLs: []string{u.String()},\n\t\t\t\tLog:  testutil.Logger{},\n\t\t\t},\n\t\t\thandler: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\trequire.Empty(t, r.Header[\"Authorization\"])\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"success\",\n\t\t\tplugin: &httpplugin.HTTP{\n\t\t\t\tURLs: []string{u.String() + \"/write\"},\n\t\t\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\t\t\tOAuth2Config: oauth.OAuth2Config{\n\t\t\t\t\t\tClientID:     \"howdy\",\n\t\t\t\t\t\tClientSecret: \"secret\",\n\t\t\t\t\t\tTokenURL:     u.String() + \"/token\",\n\t\t\t\t\t\tScopes:       []string{\"urn:opc:idm:__myscopes__\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\ttokenHandler: func(t *testing.T, w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tvalues := url.Values{}\n\t\t\t\tvalues.Add(\"access_token\", token)\n\t\t\t\tvalues.Add(\"token_type\", \"bearer\")\n\t\t\t\tvalues.Add(\"expires_in\", \"3600\")\n\t\t\t\t_, err := w.Write([]byte(values.Encode()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t\thandler: func(t *testing.T, w http.ResponseWriter, r *http.Request) {\n\t\t\t\trequire.Equal(t, []string{\"Bearer \" + token}, r.Header[\"Authorization\"])\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/write\":\n\t\t\t\t\ttt.handler(t, w, r)\n\t\t\t\tcase \"/token\":\n\t\t\t\t\ttt.tokenHandler(t, w, r)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\ttt.plugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\t\t\tp := &value.Parser{\n\t\t\t\t\tMetricName: \"metric\",\n\t\t\t\t\tDataType:   \"string\",\n\t\t\t\t}\n\t\t\t\terr := p.Init()\n\t\t\t\treturn p, err\n\t\t\t})\n\n\t\t\terr = tt.plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr = tt.plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestHTTPWithCSVFormat(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(simpleCSVWithHeader)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\taddress := fakeServer.URL + \"/endpoint\"\n\tplugin := &httpplugin.HTTP{\n\t\tURLs: []string{address},\n\t\tLog:  testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &csv.Parser{\n\t\t\tMetricName:  \"metricName\",\n\t\t\tSkipRows:    3,\n\t\t\tColumnNames: []string{\"a\", \"b\", \"c\"},\n\t\t\tTagColumns:  []string{\"c\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t})\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"metricName\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\": address,\n\t\t\t\t\"c\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": 1.2,\n\t\t\t\t\"b\": 3.1415,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t// Run the parser a second time to test for correct stateful handling\n\tacc.ClearMetrics()\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nconst (\n\thttpOverUnixScheme = \"http+unix\"\n)\n\nfunc TestConnectionOverUnixSocket(t *testing.T) {\n\tts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/data\" {\n\t\t\tw.Header().Set(\"Content-Type\", \"text/csv\")\n\t\t\tif _, err := w.Write([]byte(simpleCSVWithHeader)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\t// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases\n\t// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.\n\t//nolint:usetesting // Ignore \"os.TempDir() could be replaced by t.TempDir() in TestConnectionOverUnixSocket\" finding.\n\tunixListenAddr := filepath.Join(os.TempDir(), fmt.Sprintf(\"httptestserver.%d.sock\", rand.Intn(1_000_000)))\n\tt.Cleanup(func() { os.Remove(unixListenAddr) })\n\n\tunixListener, err := net.Listen(\"unix\", unixListenAddr)\n\trequire.NoError(t, err)\n\n\tts.Listener = unixListener\n\tts.Start()\n\tdefer ts.Close()\n\n\t// NOTE: Remove \":\" from windows filepath and replace all \"\\\" with \"/\".\n\t//       This is *required* so that the unix socket path plays well with unixtransport.\n\treplacer := strings.NewReplacer(\":\", \"\", \"\\\\\", \"/\")\n\tsockPath := replacer.Replace(unixListenAddr)\n\n\taddress := fmt.Sprintf(\"%s://%s:/data\", httpOverUnixScheme, sockPath)\n\tplugin := &httpplugin.HTTP{\n\t\tURLs: []string{address},\n\t\tLog:  testutil.Logger{},\n\t}\n\n\tplugin.SetParserFunc(func() (telegraf.Parser, error) {\n\t\tparser := &csv.Parser{\n\t\t\tMetricName:  \"metricName\",\n\t\t\tSkipRows:    3,\n\t\t\tColumnNames: []string{\"a\", \"b\", \"c\"},\n\t\t\tTagColumns:  []string{\"c\"},\n\t\t}\n\t\terr := parser.Init()\n\t\treturn parser, err\n\t})\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"metricName\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\": address,\n\t\t\t\t\"c\":   \"ok\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"a\": 1.2,\n\t\t\t\t\"b\": 3.1415,\n\t\t\t},\n\t\t\ttime.Unix(22000, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\n\t// Run the parser a second time to test for correct stateful handling\n\tacc.ClearMetrics()\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/http/sample.conf",
    "content": "# Read formatted metrics from one or more HTTP endpoints\n[[inputs.http]]\n  ## One or more URLs from which to read formatted metrics.\n  urls = [\n    \"http://localhost/metrics\",\n    \"http+unix:///run/user/420/podman/podman.sock:/d/v4.0.0/libpod/pods/json\"\n  ]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP entity-body to send with POST/PUT requests.\n  # body = \"\"\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## Optional Bearer token settings to use for the API calls.\n  ## Use either the token itself or the token file if you need a token.\n  # token = \"eyJhbGc...Qssw5c\"\n  # token_file = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## OAuth2 Client Credentials. The options 'client_id', 'client_secret', and 'token_url' are required to use OAuth2.\n  # client_id = \"clientid\"\n  # client_secret = \"secret\"\n  # token_url = \"https://indentityprovider/oauth2/v1/token\"\n  # audience = \"\"\n  # scopes = [\"urn:opc:idm:__myscopes__\"]\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_headers = { Content-Type = \"application/json\", X-MY-HEADER = \"hello\" }\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"0s\"\n\n  ## List of success status codes\n  # success_status_codes = [200]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n\n"
  },
  {
    "path": "plugins/inputs/http/sample.conf.in",
    "content": "# Read formatted metrics from one or more HTTP endpoints\n[[inputs.http]]\n  ## One or more URLs from which to read formatted metrics.\n  urls = [\n    \"http://localhost/metrics\",\n    \"http+unix:///run/user/420/podman/podman.sock:/d/v4.0.0/libpod/pods/json\"\n  ]\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## HTTP entity-body to send with POST/PUT requests.\n  # body = \"\"\n\n  ## HTTP Content-Encoding for write request body, can be set to \"gzip\" to\n  ## compress body or \"identity\" to apply no encoding.\n  # content_encoding = \"identity\"\n\n  ## Optional Bearer token settings to use for the API calls.\n  ## Use either the token itself or the token file if you need a token.\n  # token = \"eyJhbGc...Qssw5c\"\n  # token_file = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n{{template \"/plugins/common/http/client.conf\"}}\n\n  ## List of success status codes\n  # success_status_codes = [200]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n\n"
  },
  {
    "path": "plugins/inputs/http_listener_v2/README.md",
    "content": "# HTTP Listener v2 Input Plugin\n\nThis plugin listens for metrics sent via HTTP in any of the supported\n[data formats][data_formats].\n\n> [!NOTE]\n> If you would like Telegraf to act as a proxy/relay for InfluxDB v1 or\n> InfluxDB v2 it is recommended to use the\n> [influxdb__listener][influxdb_listener] or\n> [influxdb_v2_listener][influxdb_v2_listener] plugin instead.\n\n⭐ Telegraf v1.9.0\n🏷️ server\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n[influxdb_listener]: /plugins/inputs/influxdb_listener/README.md\n[influxdb_v2_listener]: /plugins/inputs/influxdb_v2_listener/README.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n## Metrics\n\nMetrics are collected from the part of the request specified by the\n`data_source` param and are parsed depending on the value of `data_format`.\n\n## Example Output\n\n## Troubleshooting\n\nSend Line Protocol:\n\n```shell\ncurl -i -XPOST 'http://localhost:8080/telegraf' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'\n```\n\nSend JSON:\n\n```shell\ncurl -i -XPOST 'http://localhost:8080/telegraf' --data-binary '{\"value1\": 42, \"value2\": 42}'\n```\n\nSend query params:\n\n```shell\ncurl -i -XGET 'http://localhost:8080/telegraf?host=server01&value=0.42'\n```\n"
  },
  {
    "path": "plugins/inputs/http_listener_v2/http_listener_v2.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage http_listener_v2\n\nimport (\n\t\"compress/gzip\"\n\t\"crypto/subtle\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/golang/snappy\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst (\n\t// defaultMaxBodySize is the default maximum request body size, in bytes.\n\t// if the request body is over this size, we will return an HTTP 413 error.\n\t// 500 MB\n\tdefaultMaxBodySize = 500 * 1024 * 1024\n\tbody               = \"body\"\n\tquery              = \"query\"\n\tpathTag            = \"http_listener_v2_path\"\n)\n\ntype HTTPListenerV2 struct {\n\tServiceAddress string            `toml:\"service_address\"`\n\tSocketMode     string            `toml:\"socket_mode\"`\n\tPaths          []string          `toml:\"paths\"`\n\tPathTag        bool              `toml:\"path_tag\"`\n\tMethods        []string          `toml:\"methods\"`\n\tHTTPHeaders    map[string]string `toml:\"http_headers\"`\n\tDataSource     string            `toml:\"data_source\"`\n\tReadTimeout    config.Duration   `toml:\"read_timeout\"`\n\tWriteTimeout   config.Duration   `toml:\"write_timeout\"`\n\tMaxBodySize    config.Size       `toml:\"max_body_size\"`\n\tSuccessCode    int               `toml:\"http_success_code\"`\n\tBasicUsername  string            `toml:\"basic_username\"`\n\tBasicPassword  string            `toml:\"basic_password\"`\n\tHTTPHeaderTags map[string]string `toml:\"http_header_tags\"`\n\n\tcommon_tls.ServerConfig\n\ttlsConf *tls.Config\n\n\ttimeFunc\n\tLog telegraf.Logger\n\n\twg    sync.WaitGroup\n\tclose chan struct{}\n\n\tlistener net.Listener\n\turl      *url.URL\n\n\ttelegraf.Parser\n\tacc telegraf.Accumulator\n}\n\n// timeFunc provides a timestamp for the metrics\ntype timeFunc func() time.Time\n\nfunc (*HTTPListenerV2) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HTTPListenerV2) Init() error {\n\ttlsConf, err := h.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprotoRegex := regexp.MustCompile(`\\w://`)\n\tif !protoRegex.MatchString(h.ServiceAddress) {\n\t\th.ServiceAddress = \"tcp://\" + h.ServiceAddress\n\t}\n\n\tu, err := url.Parse(h.ServiceAddress)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing address failed: %w\", err)\n\t}\n\n\th.url = u\n\th.tlsConf = tlsConf\n\n\tif h.SuccessCode == 0 {\n\t\th.SuccessCode = http.StatusNoContent\n\t}\n\n\treturn nil\n}\n\nfunc (h *HTTPListenerV2) SetParser(parser telegraf.Parser) {\n\th.Parser = parser\n}\n\nfunc (h *HTTPListenerV2) Start(acc telegraf.Accumulator) error {\n\tu := h.url\n\taddress := u.Host\n\tswitch u.Scheme {\n\tcase \"tcp\":\n\tcase \"unix\":\n\t\tpath := filepath.FromSlash(u.Path)\n\t\tif runtime.GOOS == \"windows\" && strings.Contains(path, \":\") {\n\t\t\tpath = strings.TrimPrefix(path, `\\`)\n\t\t}\n\t\tif err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"removing socket failed: %w\", err)\n\t\t}\n\t\taddress = path\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown protocol %q\", u.Scheme)\n\t}\n\n\tvar listener net.Listener\n\tvar err error\n\tif h.tlsConf != nil {\n\t\tlistener, err = tls.Listen(u.Scheme, address, h.tlsConf)\n\t} else {\n\t\tlistener, err = net.Listen(u.Scheme, address)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\th.listener = listener\n\n\tif u.Scheme == \"unix\" && h.SocketMode != \"\" {\n\t\t// Set permissions on socket\n\t\t// Convert from octal in string to int\n\t\ti, err := strconv.ParseUint(h.SocketMode, 8, 32)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting socket mode failed: %w\", err)\n\t\t}\n\n\t\tperm := os.FileMode(uint32(i))\n\t\tif err := os.Chmod(address, perm); err != nil {\n\t\t\treturn fmt.Errorf(\"changing socket permissions failed: %w\", err)\n\t\t}\n\t}\n\n\tif h.MaxBodySize == 0 {\n\t\th.MaxBodySize = config.Size(defaultMaxBodySize)\n\t}\n\n\tif h.ReadTimeout < config.Duration(time.Second) {\n\t\th.ReadTimeout = config.Duration(time.Second * 10)\n\t}\n\tif h.WriteTimeout < config.Duration(time.Second) {\n\t\th.WriteTimeout = config.Duration(time.Second * 10)\n\t}\n\n\th.acc = acc\n\n\tserver := h.createHTTPServer()\n\n\th.wg.Add(1)\n\tgo func() {\n\t\tdefer h.wg.Done()\n\t\tif err := server.Serve(h.listener); err != nil {\n\t\t\tif !errors.Is(err, net.ErrClosed) {\n\t\t\t\th.Log.Errorf(\"Serve failed: %v\", err)\n\t\t\t}\n\t\t\tclose(h.close)\n\t\t}\n\t}()\n\n\th.Log.Infof(\"Listening on %s\", h.listener.Addr().String())\n\n\treturn nil\n}\n\nfunc (*HTTPListenerV2) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (h *HTTPListenerV2) Stop() {\n\tif h.listener != nil {\n\t\th.listener.Close()\n\t}\n\th.wg.Wait()\n}\n\n// ServeHTTP implements [http.Handler]\nfunc (h *HTTPListenerV2) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\thandler := h.serveWrite\n\n\tif !choice.Contains(req.URL.Path, h.Paths) {\n\t\thandler = http.NotFound\n\t}\n\n\tfor key, value := range h.HTTPHeaders {\n\t\tres.Header().Set(key, value)\n\t}\n\n\th.authenticateIfSet(handler, res, req)\n}\n\nfunc (h *HTTPListenerV2) createHTTPServer() *http.Server {\n\treturn &http.Server{\n\t\tAddr:         h.ServiceAddress,\n\t\tHandler:      h,\n\t\tReadTimeout:  time.Duration(h.ReadTimeout),\n\t\tWriteTimeout: time.Duration(h.WriteTimeout),\n\t\tTLSConfig:    h.tlsConf,\n\t}\n}\n\nfunc (h *HTTPListenerV2) serveWrite(res http.ResponseWriter, req *http.Request) {\n\tselect {\n\tcase <-h.close:\n\t\tres.WriteHeader(http.StatusGone)\n\t\treturn\n\tdefault:\n\t}\n\n\t// Check that the content length is not too large for us to handle.\n\tif req.ContentLength > int64(h.MaxBodySize) {\n\t\tif err := tooLarge(res); err != nil {\n\t\t\th.Log.Debugf(\"error in too-large: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\t// Check if the requested HTTP method was specified in config.\n\tisAcceptedMethod := false\n\tfor _, method := range h.Methods {\n\t\tif req.Method == method {\n\t\t\tisAcceptedMethod = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !isAcceptedMethod {\n\t\tif err := methodNotAllowed(res); err != nil {\n\t\t\th.Log.Debugf(\"error in method-not-allowed: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tvar bytes []byte\n\tvar ok bool\n\n\tswitch strings.ToLower(h.DataSource) {\n\tcase query:\n\t\tbytes, ok = h.collectQuery(res, req)\n\tdefault:\n\t\tbytes, ok = h.collectBody(res, req)\n\t}\n\n\tif !ok {\n\t\treturn\n\t}\n\n\tmetrics, err := h.Parse(bytes)\n\tif err != nil {\n\t\th.Log.Debugf(\"Parse error: %s\", err.Error())\n\t\tif err := badRequest(res); err != nil {\n\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\th.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tfor _, m := range metrics {\n\t\tfor headerName, measurementName := range h.HTTPHeaderTags {\n\t\t\theaderValues := req.Header.Get(headerName)\n\t\t\tif len(headerValues) > 0 {\n\t\t\t\tm.AddTag(measurementName, headerValues)\n\t\t\t}\n\t\t}\n\n\t\tif h.PathTag {\n\t\t\tm.AddTag(pathTag, req.URL.Path)\n\t\t}\n\n\t\th.acc.AddMetric(m)\n\t}\n\n\tres.WriteHeader(h.SuccessCode)\n}\n\nfunc (h *HTTPListenerV2) collectBody(res http.ResponseWriter, req *http.Request) ([]byte, bool) {\n\tencoding := req.Header.Get(\"Content-Encoding\")\n\n\tswitch encoding {\n\tcase \"gzip\":\n\t\tr, err := gzip.NewReader(req.Body)\n\t\tif err != nil {\n\t\t\th.Log.Debug(err.Error())\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t}\n\t\tdefer r.Close()\n\t\tmaxReader := http.MaxBytesReader(res, r, int64(h.MaxBodySize))\n\t\tbytes, err := io.ReadAll(maxReader)\n\t\tif err != nil {\n\t\t\tif err := tooLarge(res); err != nil {\n\t\t\t\th.Log.Debugf(\"error in too-large: %v\", err)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t}\n\t\treturn bytes, true\n\tcase \"snappy\":\n\t\tdefer req.Body.Close()\n\t\tbytes, err := io.ReadAll(req.Body)\n\t\tif err != nil {\n\t\t\th.Log.Debug(err.Error())\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t}\n\t\t// snappy block format is only supported by decode/encode not snappy reader/writer\n\t\tbytes, err = snappy.Decode(nil, bytes)\n\t\tif err != nil {\n\t\t\th.Log.Debug(err.Error())\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t}\n\t\treturn bytes, true\n\tdefault:\n\t\tdefer req.Body.Close()\n\t\tbytes, err := io.ReadAll(req.Body)\n\t\tif err != nil {\n\t\t\th.Log.Debug(err.Error())\n\t\t\tif err := badRequest(res); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t}\n\t\treturn bytes, true\n\t}\n}\n\nfunc (h *HTTPListenerV2) collectQuery(res http.ResponseWriter, req *http.Request) ([]byte, bool) {\n\trawQuery := req.URL.RawQuery\n\n\tquery, err := url.QueryUnescape(rawQuery)\n\tif err != nil {\n\t\th.Log.Debugf(\"Error parsing query: %s\", err.Error())\n\t\tif err := badRequest(res); err != nil {\n\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn nil, false\n\t}\n\n\treturn []byte(query), true\n}\n\nfunc tooLarge(res http.ResponseWriter) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t_, err := res.Write([]byte(`{\"error\":\"http: request body too large\"}`))\n\treturn err\n}\n\nfunc methodNotAllowed(res http.ResponseWriter) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusMethodNotAllowed)\n\t_, err := res.Write([]byte(`{\"error\":\"http: method not allowed\"}`))\n\treturn err\n}\n\nfunc badRequest(res http.ResponseWriter) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.WriteHeader(http.StatusBadRequest)\n\t_, err := res.Write([]byte(`{\"error\":\"http: bad request\"}`))\n\treturn err\n}\n\nfunc (h *HTTPListenerV2) authenticateIfSet(handler http.HandlerFunc, res http.ResponseWriter, req *http.Request) {\n\tif h.BasicUsername != \"\" && h.BasicPassword != \"\" {\n\t\treqUsername, reqPassword, ok := req.BasicAuth()\n\t\tif !ok ||\n\t\t\tsubtle.ConstantTimeCompare([]byte(reqUsername), []byte(h.BasicUsername)) != 1 ||\n\t\t\tsubtle.ConstantTimeCompare([]byte(reqPassword), []byte(h.BasicPassword)) != 1 {\n\t\t\thttp.Error(res, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t\thandler(res, req)\n\t} else {\n\t\thandler(res, req)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"http_listener_v2\", func() telegraf.Input {\n\t\treturn &HTTPListenerV2{\n\t\t\tServiceAddress: \":8080\",\n\t\t\ttimeFunc:       time.Now,\n\t\t\tPaths:          []string{\"/telegraf\"},\n\t\t\tMethods:        []string{\"POST\", \"PUT\"},\n\t\t\tDataSource:     body,\n\t\t\tclose:          make(chan struct{}),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/http_listener_v2/http_listener_v2_test.go",
    "content": "package http_listener_v2\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang/snappy\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/form_urlencoded\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\ttestMsg = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\\n\"\n\n\ttestMsgNoNewline = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\"\n\n\ttestMsgs = `cpu_load_short,host=server02 value=12.0 1422568543702900257\ncpu_load_short,host=server03 value=12.0 1422568543702900257\ncpu_load_short,host=server04 value=12.0 1422568543702900257\ncpu_load_short,host=server05 value=12.0 1422568543702900257\ncpu_load_short,host=server06 value=12.0 1422568543702900257\n`\n\tbadMsg = \"blahblahblah: 42\\n\"\n\n\temptyMsg = \"\"\n\n\tbasicUsername = \"test-username-please-ignore\"\n\tbasicPassword = \"super-secure-password!\"\n)\n\nvar (\n\tpki = testutil.NewPKI(\"../../../testutil/pki\")\n)\n\nfunc newTestHTTPListenerV2() (*HTTPListenerV2, error) {\n\tparser := &influx.Parser{}\n\tif err := parser.Init(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlistener := &HTTPListenerV2{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMethods:        []string{\"POST\"},\n\t\tParser:         parser,\n\t\ttimeFunc:       time.Now,\n\t\tMaxBodySize:    config.Size(70000),\n\t\tDataSource:     \"body\",\n\t\tclose:          make(chan struct{}),\n\t}\n\treturn listener, nil\n}\n\nfunc newTestHTTPAuthListener() (*HTTPListenerV2, error) {\n\tlistener, err := newTestHTTPListenerV2()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlistener.BasicUsername = basicUsername\n\tlistener.BasicPassword = basicPassword\n\treturn listener, nil\n}\n\nfunc newTestHTTPSListenerV2() (*HTTPListenerV2, error) {\n\tparser := &influx.Parser{}\n\tif err := parser.Init(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlistener := &HTTPListenerV2{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMethods:        []string{\"POST\"},\n\t\tParser:         parser,\n\t\tServerConfig:   *pki.TLSServerConfig(),\n\t\ttimeFunc:       time.Now,\n\t\tclose:          make(chan struct{}),\n\t}\n\n\treturn listener, nil\n}\n\nfunc getHTTPSClient() *http.Client {\n\ttlsConfig, err := pki.TLSClientConfig().TLSConfig()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t}\n}\n\nfunc createURL(listener *HTTPListenerV2, scheme, path, rawquery string) string {\n\tvar port int\n\tif strings.HasPrefix(listener.ServiceAddress, \"tcp://\") {\n\t\tport = listener.listener.Addr().(*net.TCPAddr).Port\n\t}\n\tu := url.URL{\n\t\tScheme:   scheme,\n\t\tHost:     \"localhost:\" + strconv.Itoa(port),\n\t\tPath:     path,\n\t\tRawQuery: rawquery,\n\t}\n\treturn u.String()\n}\n\nfunc TestInvalidListenerConfig(t *testing.T) {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tlistener := &HTTPListenerV2{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"address_without_port\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMethods:        []string{\"POST\"},\n\t\tParser:         parser,\n\t\ttimeFunc:       time.Now,\n\t\tMaxBodySize:    config.Size(70000),\n\t\tDataSource:     \"body\",\n\t\tclose:          make(chan struct{}),\n\t}\n\n\trequire.NoError(t, listener.Init())\n\tacc := &testutil.Accumulator{}\n\trequire.Error(t, listener.Start(acc))\n\n\t// Stop is called when any ServiceInput fails to start; it must succeed regardless of state\n\tlistener.Stop()\n}\n\nfunc TestWriteHTTPSNoClientAuth(t *testing.T) {\n\tlistener, err := newTestHTTPSListenerV2()\n\trequire.NoError(t, err)\n\tlistener.TLSAllowedCACerts = nil\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tcas := x509.NewCertPool()\n\tcas.AppendCertsFromPEM([]byte(pki.ReadServerCert()))\n\tnoClientAuthClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tRootCAs: cas,\n\t\t\t},\n\t\t},\n\t}\n\n\t// post single message to listener\n\tresp, err := noClientAuthClient.Post(createURL(listener, \"https\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteHTTPSWithClientAuth(t *testing.T) {\n\tlistener, err := newTestHTTPSListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := getHTTPSClient().Post(createURL(listener, \"https\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteHTTPBasicAuth(t *testing.T) {\n\tlistener, err := newTestHTTPAuthListener()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tclient := &http.Client{}\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.SetBasicAuth(basicUsername, basicPassword)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusNoContent, resp.StatusCode)\n}\n\nfunc TestWriteHTTP(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\"},\n\t)\n\n\t// post multiple message to listener\n\tresp, err = http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgs))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(2)\n\thostTags := []string{\"server02\", \"server03\",\n\t\t\"server04\", \"server05\", \"server06\"}\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag},\n\t\t)\n\t}\n\n\t// Post a gigantic metric to the listener and verify that an error is returned:\n\tresp, err = http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBuffer(hugeMetric))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 413, resp.StatusCode)\n\n\tacc.Wait(3)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\"},\n\t)\n}\n\n// http listener should add request path as configured path_tag\nfunc TestWriteHTTPWithPathTag(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.PathTag = true\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"http_listener_v2_path\": \"/write\"},\n\t)\n}\n\nfunc TestWriteHTTPWithReturnCode(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.SuccessCode = 200\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n}\n\n// http listener should add request path as configured path_tag (trimming it before)\nfunc TestWriteHTTPWithMultiplePaths(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.Paths = append(listener.Paths, \"/alternative_write\")\n\tlistener.PathTag = true\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to /write\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t// post single message to /alternative_write\n\tresp, err = http.Post(createURL(listener, \"http\", \"/alternative_write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"http_listener_v2_path\": \"/write\"},\n\t)\n\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"http_listener_v2_path\": \"/alternative_write\"},\n\t)\n}\n\n// http listener should add a newline at the end of the buffer if it's not there\nfunc TestWriteHTTPNoNewline(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\"},\n\t)\n}\n\nfunc TestWriteHTTPExactMaxBodySize(t *testing.T) {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tlistener := &HTTPListenerV2{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMethods:        []string{\"POST\"},\n\t\tParser:         parser,\n\t\tMaxBodySize:    config.Size(len(hugeMetric)),\n\t\ttimeFunc:       time.Now,\n\t\tclose:          make(chan struct{}),\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBuffer(hugeMetric))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteHTTPVerySmallMaxBody(t *testing.T) {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tlistener := &HTTPListenerV2{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tPaths:          []string{\"/write\"},\n\t\tMethods:        []string{\"POST\"},\n\t\tParser:         parser,\n\t\tMaxBodySize:    config.Size(4096),\n\t\ttimeFunc:       time.Now,\n\t\tclose:          make(chan struct{}),\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBuffer(hugeMetric))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 413, resp.StatusCode)\n}\n\n// test that writing gzipped data works\nfunc TestWriteHTTPGzippedData(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tdata, err := os.ReadFile(\"./testdata/testmsgs.gz\")\n\trequire.NoError(t, err)\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"\"), bytes.NewBuffer(data))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Encoding\", \"gzip\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\thostTags := []string{\"server02\", \"server03\",\n\t\t\"server04\", \"server05\", \"server06\"}\n\tacc.Wait(len(hostTags))\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag},\n\t\t)\n\t}\n}\n\n// test that writing snappy data works\nfunc TestWriteHTTPSnappyData(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\ttestData := \"cpu_load_short,host=server01 value=12.0 1422568543702900257\\n\"\n\tencodedData := snappy.Encode(nil, []byte(testData))\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"\"), bytes.NewBuffer(encodedData))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Encoding\", \"snappy\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tt.Log(\"Test client request failed. Error: \", err)\n\t}\n\trequire.NoErrorf(t, resp.Body.Close(), \"Test client close failed. Error: %v\", err)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\thostTags := []string{\"server01\"}\n\tacc.Wait(1)\n\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag},\n\t\t)\n\t}\n}\n\n// writes 25,000 metrics to the listener with 10 different writers\nfunc TestWriteHTTPHighTraffic(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping due to hang on darwin and windows\")\n\t}\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post many messages to listener\n\tvar wg sync.WaitGroup\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func(innerwg *sync.WaitGroup) {\n\t\t\tdefer innerwg.Done()\n\t\t\tfor i := 0; i < 500; i++ {\n\t\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgs))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif err := resp.Body.Close(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif resp.StatusCode != 204 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(&wg)\n\t}\n\n\twg.Wait()\n\trequire.NoError(t, listener.Gather(acc))\n\n\tacc.Wait(25000)\n\trequire.Equal(t, int64(25000), int64(acc.NMetrics()))\n}\n\nfunc TestReceive404ForInvalidEndpoint(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/foobar\", \"\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 404, resp.StatusCode)\n}\n\nfunc TestWriteHTTPInvalid(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(badMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 400, resp.StatusCode)\n}\n\nfunc TestWriteHTTPEmpty(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(emptyMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteHTTPTransformHeaderValuesToTagsSingleWrite(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.HTTPHeaderTags = map[string]string{\n\t\t\"Present_http_header_1\": \"presentMeasurementKey1\",\n\t\t\"present_http_header_2\": \"presentMeasurementKey2\",\n\t\t\"NOT_PRESENT_HEADER\":    \"notPresentMeasurementKey\",\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Type\", \"\")\n\treq.Header.Set(\"Present_http_header_1\", \"PRESENT_HTTP_VALUE_1\")\n\treq.Header.Set(\"Present_http_header_2\", \"PRESENT_HTTP_VALUE_2\")\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"presentMeasurementKey1\": \"PRESENT_HTTP_VALUE_1\", \"presentMeasurementKey2\": \"PRESENT_HTTP_VALUE_2\"},\n\t)\n\n\t// post single message to listener\n\tresp, err = http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"presentMeasurementKey1\": \"PRESENT_HTTP_VALUE_1\", \"presentMeasurementKey2\": \"PRESENT_HTTP_VALUE_2\"},\n\t)\n}\n\nfunc TestWriteHTTPTransformHeaderValuesToTagsBulkWrite(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.HTTPHeaderTags = map[string]string{\n\t\t\"Present_http_header_1\": \"presentMeasurementKey1\",\n\t\t\"Present_http_header_2\": \"presentMeasurementKey2\",\n\t\t\"NOT_PRESENT_HEADER\":    \"notPresentMeasurementKey\",\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsgs))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Type\", \"\")\n\treq.Header.Set(\"Present_http_header_1\", \"PRESENT_HTTP_VALUE_1\")\n\treq.Header.Set(\"Present_http_header_2\", \"PRESENT_HTTP_VALUE_2\")\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(2)\n\thostTags := []string{\"server02\", \"server03\", \"server04\", \"server05\", \"server06\"}\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag, \"presentMeasurementKey1\": \"PRESENT_HTTP_VALUE_1\", \"presentMeasurementKey2\": \"PRESENT_HTTP_VALUE_2\"},\n\t\t)\n\t}\n}\n\nfunc TestWriteHTTPQueryParams(t *testing.T) {\n\tparser := form_urlencoded.Parser{\n\t\tMetricName: \"query_measurement\",\n\t\tTagKeys:    []string{\"tagKey\"},\n\t}\n\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.DataSource = \"query\"\n\tlistener.Parser = &parser\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"tagKey=tagValue&fieldKey=42\"), \"\", bytes.NewBufferString(emptyMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"query_measurement\",\n\t\tmap[string]interface{}{\"fieldKey\": float64(42)},\n\t\tmap[string]string{\"tagKey\": \"tagValue\"},\n\t)\n}\n\nfunc TestWriteHTTPFormData(t *testing.T) {\n\tparser := form_urlencoded.Parser{\n\t\tMetricName: \"query_measurement\",\n\t\tTagKeys:    []string{\"tagKey\"},\n\t}\n\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tlistener.Parser = &parser\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.PostForm(createURL(listener, \"http\", \"/write\", \"\"), url.Values{\n\t\t\"tagKey\":   {\"tagValue\"},\n\t\t\"fieldKey\": {\"42\"},\n\t})\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"query_measurement\",\n\t\tmap[string]interface{}{\"fieldKey\": float64(42)},\n\t\tmap[string]string{\"tagKey\": \"tagValue\"},\n\t)\n}\n\nfunc TestServerHeaders(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\n\tlistener.HTTPHeaders = map[string]string{\n\t\t\"key\": \"value\",\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\trequire.Equal(t, \"value\", resp.Header.Get(\"key\"))\n}\n\nfunc TestUnixSocket(t *testing.T) {\n\tlistener, err := newTestHTTPListenerV2()\n\trequire.NoError(t, err)\n\tfile, err := os.CreateTemp(t.TempDir(), \"*.socket\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, file.Close())\n\n\tsocketName := file.Name()\n\tif runtime.GOOS == \"windows\" {\n\t\tlistener.ServiceAddress = \"unix:///\" + socketName\n\t} else {\n\t\tlistener.ServiceAddress = \"unix://\" + socketName\n\t}\n\tlistener.SocketMode = \"777\"\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\thttpc := http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: func(_ context.Context, _, _ string) (net.Conn, error) {\n\t\t\t\treturn net.Dial(\"unix\", socketName)\n\t\t\t},\n\t\t},\n\t}\n\tresp, err := httpc.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc mustReadHugeMetric() []byte {\n\tfilePath := \"testdata/huge_metric\"\n\tdata, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"could not read from file %s: %w\", filePath, err))\n\t}\n\n\treturn data\n}\n\n// The term 'master_repl' used here is archaic language from redis\nvar hugeMetric = mustReadHugeMetric()\n"
  },
  {
    "path": "plugins/inputs/http_listener_v2/sample.conf",
    "content": "# Generic HTTP write listener\n[[inputs.http_listener_v2]]\n  ## Address to host HTTP listener on\n  ## can be prefixed by protocol tcp, or unix if not provided defaults to tcp\n  ## if unix network type provided it should be followed by absolute path for unix socket\n  service_address = \"tcp://:8080\"\n  ## service_address = \"tcp://:8443\"\n  ## service_address = \"unix:///tmp/telegraf.sock\"\n\n  ## Permission for unix sockets (only available for unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Paths to listen to.\n  # paths = [\"/telegraf\"]\n\n  ## Save path as http_listener_v2_path tag if set to true\n  # path_tag = false\n\n  ## HTTP methods to accept.\n  # methods = [\"POST\", \"PUT\"]\n\n  ## Optional HTTP headers\n  ## These headers are applied to the server that is listening for HTTP\n  ## requests and included in responses.\n  # http_headers = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## HTTP Return Success Code\n  ## This is the HTTP code that will be returned on success\n  # http_success_code = 204\n\n  ## maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed http request body size in bytes.\n  ## 0 means to use the default of 524,288,000 bytes (500 mebibytes)\n  # max_body_size = \"500MB\"\n\n  ## Part of the request to consume.  Available options are \"body\" and\n  ## \"query\".\n  # data_source = \"body\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Minimal TLS version accepted by the server\n  # tls_min_version = \"TLS12\"\n\n  ## Optional username and password to accept for HTTP basic authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional setting to map http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will be added\n  ## If multiple instances of the http header are present, only the first value will be used\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/http_listener_v2/testdata/huge_metric",
    "content": "super_long_metric,foo=bar clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i\n"
  },
  {
    "path": "plugins/inputs/http_response/README.md",
    "content": "# HTTP Response Input Plugin\n\nThis plugin generates metrics from HTTP responses including the status code and\nresponse statistics.\n\n⭐ Telegraf v0.12.1\n🏷️ server\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# HTTP/HTTPS request given an address a method and a timeout\n[[inputs.http_response]]\n  ## List of urls to query.\n  # urls = [\"http://localhost\"]\n\n  ## Set http_proxy.\n  ## Telegraf uses the system wide proxy settings if it's is not set.\n  # http_proxy = \"http://localhost:8888\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## HTTP Request Method\n  # method = \"GET\"\n\n  ## Whether to follow redirects from the server (defaults to false)\n  # follow_redirects = false\n\n  ## Optional file with Bearer token\n  ## file content is added as an Authorization header\n  # bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional HTTP Request Body\n  # body = '''\n  # {'fake':'data'}\n  # '''\n\n  ## Optional HTTP Request Body Form\n  ## Key value pairs to encode and set at URL form. Can be used with the POST\n  ## method + application/x-www-form-urlencoded content type to replicate the\n  ## POSTFORM method.\n  # body_form = { \"key\": \"value\" }\n\n  ## Optional name of the field that will contain the body of the response.\n  ## By default it is set to an empty String indicating that the body's\n  ## content won't be added\n  # response_body_field = ''\n\n  ## Maximum allowed HTTP response body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  ## If the response body size exceeds this limit a \"body_read_error\" will\n  ## be raised.\n  # response_body_max_size = \"32MiB\"\n\n  ## Optional substring or regex match in body of the response (case sensitive)\n  # response_string_match = \"\\\"service_status\\\": \\\"up\\\"\"\n  # response_string_match = \"ok\"\n  # response_string_match = \"\\\".*_status\\\".?:.?\\\"up\\\"\"\n\n  ## Expected response status code.\n  ## The status code of the response is compared to this value. If they match,\n  ## the field \"response_status_code_match\" will be 1, otherwise it will be 0.\n  ## If the expected status code is 0, the check is disabled and the field\n  ## won't be added.\n  # response_status_code = 0\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"\"\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## HTTP Request Headers (all values must be strings)\n  # [inputs.http_response.headers]\n  #   Host = \"github.com\"\n\n  ## Optional setting to map response http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will\n  ## be added. If multiple instances of the http header are present, only the\n  ## first value will be used.\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Interface to use when dialing an address\n  # interface = \"eth0\"\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n```\n\n## Metrics\n\n- http_response\n  - tags:\n    - server (target URL)\n    - method (request method)\n    - status_code (response status code)\n    - result ([see below](#result--result_code))\n  - fields:\n    - response_time (float, seconds)\n    - content_length (int, response body length)\n    - response_string_match (int, 0 = mismatch / body read error, 1 = match)\n    - response_status_code_match (int, 0 = mismatch, 1 = match)\n    - http_response_code (int, response status code)\n    - result_type (string, deprecated in 1.6: use `result` tag and\n     `result_code` field)\n    - result_code (int, [see below](#result--result_code))\n\n### `result` / `result_code`\n\nUpon finishing polling the target server, the plugin registers the result of the\noperation in the `result` tag, and adds a numeric field called `result_code`\ncorresponding with that tag value.\n\nThis tag is used to expose network and plugin errors. HTTP errors are considered\na successful connection.\n\n|Tag value                     |Corresponding field value|Description|\n|------------------------------|-------------------------|-----------|\n|success                       | 0                       |The HTTP request completed, even if the HTTP code represents an error|\n|response_string_mismatch      | 1                       |The option `response_string_match` was used, and the body of the response didn't match the regex. HTTP errors with content in their body (like 4xx, 5xx) will trigger this error|\n|body_read_error               | 2                       |The option `response_string_match` was used, but the plugin wasn't able to read the body of the response. Responses with empty bodies (like 3xx, HEAD, etc) will trigger this error. Or the option `response_body_field` was used and the content of the response body was not a valid utf-8. Or the size of the body of the response exceeded the `response_body_max_size` |\n|connection_failed             | 3                       |Catch all for any network error not specifically handled by the plugin|\n|timeout                       | 4                       |The plugin timed out while awaiting the HTTP connection to complete|\n|dns_error                     | 5                       |There was a DNS error while attempting to connect to the host|\n|response_status_code_mismatch | 6                       |The option `response_status_code_match` was used, and the status code of the response didn't match the value.|\n\n## Example Output\n\n```text\nhttp_response,method=GET,result=success,server=http://github.com,status_code=200 content_length=87878i,http_response_code=200i,response_time=0.937655534,result_code=0i,result_type=\"success\" 1565839598000000000\n```\n\n## Optional Cookie Authentication Settings\n\nThe optional Cookie Authentication Settings will retrieve a cookie from the\ngiven authorization endpoint, and use it in subsequent API requests.  This is\nuseful for services that do not provide OAuth or Basic Auth authentication,\ne.g. the [Tesla Powerwall API][tesla], which uses a Cookie Auth Body to retrieve\nan authorization cookie.  The Cookie Auth Renewal interval will renew the\nauthorization by retrieving a new cookie at the given interval.\n\n[tesla]: https://www.tesla.com/support/energy/powerwall/own/monitoring-from-home-network\n"
  },
  {
    "path": "plugins/inputs/http_response/http_response.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage http_response\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n\n\t\"github.com/benbjohnson/clock\"\n\t\"github.com/seancfoley/ipaddress-go/ipaddr\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/cookie\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// defaultResponseBodyMaxSize is the default maximum response body size, in bytes.\n\t// if the response body is over this size, we will raise a body_read_error.\n\tdefaultResponseBodyMaxSize = 32 * 1024 * 1024\n)\n\ntype HTTPResponse struct {\n\tURLs            []string            `toml:\"urls\"`\n\tHTTPProxy       string              `toml:\"http_proxy\"`\n\tBody            string              `toml:\"body\"`\n\tBodyForm        map[string][]string `toml:\"body_form\"`\n\tMethod          string              `toml:\"method\"`\n\tResponseTimeout config.Duration     `toml:\"response_timeout\"`\n\tHTTPHeaderTags  map[string]string   `toml:\"http_header_tags\"`\n\tHeaders         map[string]string   `toml:\"headers\"`\n\tFollowRedirects bool                `toml:\"follow_redirects\"`\n\t// Absolute path to file with Bearer token\n\tBearerToken         string      `toml:\"bearer_token\"`\n\tResponseBodyField   string      `toml:\"response_body_field\"`\n\tResponseBodyMaxSize config.Size `toml:\"response_body_max_size\"`\n\tResponseStringMatch string      `toml:\"response_string_match\"`\n\tResponseStatusCode  int         `toml:\"response_status_code\"`\n\tInterface           string      `toml:\"interface\"`\n\t// HTTP Basic Auth Credentials\n\tUsername config.Secret `toml:\"username\"`\n\tPassword config.Secret `toml:\"password\"`\n\ttls.ClientConfig\n\tcookie.CookieAuthConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tcompiledStringMatch *regexp.Regexp\n\tclients             []client\n}\n\ntype client struct {\n\thttpClient httpClient\n\taddress    string\n}\n\ntype httpClient interface {\n\t// Do implements [http.Client]\n\tDo(req *http.Request) (*http.Response, error)\n}\n\nfunc (*HTTPResponse) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HTTPResponse) Init() error {\n\t// Compile the body regex if it exists\n\tif h.ResponseStringMatch != \"\" {\n\t\tvar err error\n\t\th.compiledStringMatch, err = regexp.Compile(h.ResponseStringMatch)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to compile regular expression %q: %w\", h.ResponseStringMatch, err)\n\t\t}\n\t}\n\n\t// Set default values\n\tif h.ResponseTimeout < config.Duration(time.Second) {\n\t\th.ResponseTimeout = config.Duration(time.Second * 5)\n\t}\n\tif h.Method == \"\" {\n\t\th.Method = \"GET\"\n\t}\n\n\tif len(h.URLs) == 0 {\n\t\th.URLs = []string{\"http://localhost\"}\n\t}\n\n\th.clients = make([]client, 0, len(h.URLs))\n\tfor _, u := range h.URLs {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%q is not a valid address: %w\", u, err)\n\t\t}\n\n\t\tif addr.Scheme != \"http\" && addr.Scheme != \"https\" {\n\t\t\treturn fmt.Errorf(\"%q is not a valid address: only http and https types are supported\", u)\n\t\t}\n\n\t\tcl, err := h.createHTTPClient(*addr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\th.clients = append(h.clients, client{httpClient: cl, address: u})\n\t}\n\n\treturn nil\n}\n\nfunc (h *HTTPResponse) Gather(acc telegraf.Accumulator) error {\n\tfor _, c := range h.clients {\n\t\t// Prepare data\n\t\tvar fields map[string]interface{}\n\t\tvar tags map[string]string\n\n\t\t// Gather data\n\t\tfields, tags, err := h.httpGather(c)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add metrics\n\t\tacc.AddFields(\"http_response\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// Set the proxy. A configured proxy overwrites the system-wide proxy.\nfunc getProxyFunc(httpProxy string) func(*http.Request) (*url.URL, error) {\n\tif httpProxy == \"\" {\n\t\treturn http.ProxyFromEnvironment\n\t}\n\tproxyURL, err := url.Parse(httpProxy)\n\tif err != nil {\n\t\treturn func(_ *http.Request) (*url.URL, error) {\n\t\t\treturn nil, errors.New(\"bad proxy: \" + err.Error())\n\t\t}\n\t}\n\treturn func(*http.Request) (*url.URL, error) {\n\t\treturn proxyURL, nil\n\t}\n}\n\n// createHTTPClient creates an http client which will time out at the specified\n// timeout period and can follow redirects if specified\nfunc (h *HTTPResponse) createHTTPClient(address url.URL) (*http.Client, error) {\n\ttlsCfg, err := h.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdialer := &net.Dialer{}\n\n\tif h.Interface != \"\" {\n\t\tdialer.LocalAddr, err = localAddress(h.Interface, address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tProxy:             getProxyFunc(h.HTTPProxy),\n\t\t\tDialContext:       dialer.DialContext,\n\t\t\tDisableKeepAlives: true,\n\t\t\tTLSClientConfig:   tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(h.ResponseTimeout),\n\t}\n\n\tif !h.FollowRedirects {\n\t\tclient.CheckRedirect = func(*http.Request, []*http.Request) error {\n\t\t\treturn http.ErrUseLastResponse\n\t\t}\n\t}\n\n\tif h.CookieAuthConfig.URL != \"\" {\n\t\tif err := h.CookieAuthConfig.Start(client, h.Log, clock.New()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn client, nil\n}\n\nfunc localAddress(interfaceName string, address url.URL) (net.Addr, error) {\n\ti, err := net.InterfaceByName(interfaceName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taddrs, err := i.Addrs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\turlInIPv6, zone := isURLInIPv6(address)\n\tfor _, addr := range addrs {\n\t\tif naddr, ok := addr.(*net.IPNet); ok {\n\t\t\tipNetInIPv6 := isIPNetInIPv6(naddr)\n\n\t\t\t// choose interface address in the same format as server address\n\t\t\tif ipNetInIPv6 == urlInIPv6 {\n\t\t\t\t// leaving port set to zero to let kernel pick, but set zone\n\t\t\t\treturn &net.TCPAddr{IP: naddr.IP, Zone: zone}, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"cannot create local address for interface %q and server address %q\", interfaceName, address.String())\n}\n\n// isURLInIPv6 returns (true, zoneName) only when URL is in IPv6 format.\n// For other cases (host part of url cannot be successfully validated, doesn't contain address at all or is in IPv4 format), it returns (false, \"\").\nfunc isURLInIPv6(address url.URL) (bool, string) {\n\thost := ipaddr.NewHostName(address.Host)\n\tif err := host.Validate(); err != nil {\n\t\treturn false, \"\"\n\t}\n\tif hostAddr := host.AsAddress(); hostAddr != nil {\n\t\tif ipv6 := hostAddr.ToIPv6(); ipv6 != nil {\n\t\t\treturn true, ipv6.GetZone().String()\n\t\t}\n\t}\n\n\treturn false, \"\"\n}\n\n// isIPNetInIPv6 returns true only when IPNet can be represented in IPv6 format.\n// For other cases (address cannot be successfully parsed or is in IPv4 format), it returns false.\nfunc isIPNetInIPv6(address *net.IPNet) bool {\n\tipAddr, err := ipaddr.NewIPAddressFromNetIPNet(address)\n\treturn err == nil && ipAddr.ToIPv6() != nil\n}\n\nfunc setResult(resultString string, fields map[string]interface{}, tags map[string]string) {\n\tresultCodes := map[string]int{\n\t\t\"success\":                       0,\n\t\t\"response_string_mismatch\":      1,\n\t\t\"body_read_error\":               2,\n\t\t\"connection_failed\":             3,\n\t\t\"timeout\":                       4,\n\t\t\"dns_error\":                     5,\n\t\t\"response_status_code_mismatch\": 6,\n\t}\n\n\ttags[\"result\"] = resultString\n\tfields[\"result_type\"] = resultString\n\tfields[\"result_code\"] = resultCodes[resultString]\n}\n\nfunc setError(err error, fields map[string]interface{}, tags map[string]string) error {\n\tvar timeoutError net.Error\n\tif errors.As(err, &timeoutError) && timeoutError.Timeout() {\n\t\tsetResult(\"timeout\", fields, tags)\n\t\treturn timeoutError\n\t}\n\n\tvar urlErr *url.Error\n\tif !errors.As(err, &urlErr) {\n\t\treturn nil\n\t}\n\n\tvar opErr *net.OpError\n\tif errors.As(urlErr, &opErr) {\n\t\tvar dnsErr *net.DNSError\n\t\tvar parseErr *net.ParseError\n\n\t\tif errors.As(opErr, &dnsErr) {\n\t\t\tsetResult(\"dns_error\", fields, tags)\n\t\t\treturn dnsErr\n\t\t} else if errors.As(opErr, &parseErr) {\n\t\t\t// Parse error has to do with parsing of IP addresses, so we\n\t\t\t// group it with address errors\n\t\t\tsetResult(\"address_error\", fields, tags)\n\t\t\treturn parseErr\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// HTTPGather gathers all fields and returns any errors it encounters\nfunc (h *HTTPResponse) httpGather(cl client) (map[string]interface{}, map[string]string, error) {\n\t// Prepare fields and tags\n\tfields := make(map[string]interface{})\n\ttags := map[string]string{\"server\": cl.address, \"method\": h.Method}\n\n\tvar body io.Reader\n\tif h.Body != \"\" {\n\t\tbody = strings.NewReader(h.Body)\n\t} else if len(h.BodyForm) != 0 {\n\t\tvalues := url.Values{}\n\t\tfor k, vs := range h.BodyForm {\n\t\t\tfor _, v := range vs {\n\t\t\t\tvalues.Add(k, v)\n\t\t\t}\n\t\t}\n\t\tbody = strings.NewReader(values.Encode())\n\t}\n\n\trequest, err := http.NewRequest(h.Method, cl.address, body)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif _, uaPresent := h.Headers[\"User-Agent\"]; !uaPresent {\n\t\trequest.Header.Set(\"User-Agent\", internal.ProductToken())\n\t}\n\n\tif h.BearerToken != \"\" {\n\t\ttoken, err := os.ReadFile(h.BearerToken)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tbearer := \"Bearer \" + strings.Trim(string(token), \"\\n\")\n\t\trequest.Header.Add(\"Authorization\", bearer)\n\t}\n\n\tfor key, val := range h.Headers {\n\t\trequest.Header.Add(key, val)\n\t\tif key == \"Host\" {\n\t\t\trequest.Host = val\n\t\t}\n\t}\n\n\tif err := h.setRequestAuth(request); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Start Timer\n\tstart := time.Now()\n\tresp, err := cl.httpClient.Do(request)\n\tresponseTime := time.Since(start).Seconds()\n\n\t// If an error in returned, it means we are dealing with a network error, as\n\t// HTTP error codes do not generate errors in the net/http library\n\tif err != nil {\n\t\t// Log error\n\t\th.Log.Debugf(\"Network error while polling %s: %s\", cl.address, err.Error())\n\n\t\t// Get error details\n\t\tif setError(err, fields, tags) == nil {\n\t\t\t// Any error not recognized by `set_error` is considered a \"connection_failed\"\n\t\t\tsetResult(\"connection_failed\", fields, tags)\n\t\t}\n\n\t\treturn fields, tags, nil\n\t}\n\n\tif _, ok := fields[\"response_time\"]; !ok {\n\t\tfields[\"response_time\"] = responseTime\n\t}\n\n\t// This function closes the response body, as\n\t// required by the net/http library\n\tdefer resp.Body.Close()\n\n\t// Add the response headers\n\tfor headerName, tag := range h.HTTPHeaderTags {\n\t\theaderValues, foundHeader := resp.Header[headerName]\n\t\tif foundHeader && len(headerValues) > 0 {\n\t\t\ttags[tag] = headerValues[0]\n\t\t}\n\t}\n\n\t// Set log the HTTP response code\n\ttags[\"status_code\"] = strconv.Itoa(resp.StatusCode)\n\tfields[\"http_response_code\"] = resp.StatusCode\n\n\tif h.ResponseBodyMaxSize == 0 {\n\t\th.ResponseBodyMaxSize = config.Size(defaultResponseBodyMaxSize)\n\t}\n\tbodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, int64(h.ResponseBodyMaxSize)+1))\n\t// Check first if the response body size exceeds the limit.\n\tif err == nil && int64(len(bodyBytes)) > int64(h.ResponseBodyMaxSize) {\n\t\th.setBodyReadError(\"The body of the HTTP Response is too large\", bodyBytes, fields, tags)\n\t\treturn fields, tags, nil\n\t} else if err != nil {\n\t\th.setBodyReadError(\"Failed to read body of HTTP Response : \"+err.Error(), bodyBytes, fields, tags)\n\t\treturn fields, tags, nil\n\t}\n\n\t// Add the body of the response if expected\n\tif len(h.ResponseBodyField) > 0 {\n\t\t// Check that the content of response contains only valid utf-8 characters.\n\t\tif !utf8.Valid(bodyBytes) {\n\t\t\th.setBodyReadError(\"The body of the HTTP Response is not a valid utf-8 string\", bodyBytes, fields, tags)\n\t\t\treturn fields, tags, nil\n\t\t}\n\t\tfields[h.ResponseBodyField] = string(bodyBytes)\n\t}\n\tfields[\"content_length\"] = len(bodyBytes)\n\n\tvar success = true\n\n\t// Check the response for a regex\n\tif h.ResponseStringMatch != \"\" {\n\t\tif h.compiledStringMatch.Match(bodyBytes) {\n\t\t\tfields[\"response_string_match\"] = 1\n\t\t} else {\n\t\t\tsuccess = false\n\t\t\tsetResult(\"response_string_mismatch\", fields, tags)\n\t\t\tfields[\"response_string_match\"] = 0\n\t\t}\n\t}\n\n\t// Check the response status code\n\tif h.ResponseStatusCode > 0 {\n\t\tif resp.StatusCode == h.ResponseStatusCode {\n\t\t\tfields[\"response_status_code_match\"] = 1\n\t\t} else {\n\t\t\tsuccess = false\n\t\t\tsetResult(\"response_status_code_mismatch\", fields, tags)\n\t\t\tfields[\"response_status_code_match\"] = 0\n\t\t}\n\t}\n\n\tif success {\n\t\tsetResult(\"success\", fields, tags)\n\t}\n\n\treturn fields, tags, nil\n}\n\n// Set result in case of a body read error\nfunc (h *HTTPResponse) setBodyReadError(errorMsg string, bodyBytes []byte, fields map[string]interface{}, tags map[string]string) {\n\th.Log.Debug(errorMsg)\n\tsetResult(\"body_read_error\", fields, tags)\n\tfields[\"content_length\"] = len(bodyBytes)\n\tif h.ResponseStringMatch != \"\" {\n\t\tfields[\"response_string_match\"] = 0\n\t}\n}\n\nfunc (h *HTTPResponse) setRequestAuth(request *http.Request) error {\n\tif h.Username.Empty() || h.Password.Empty() {\n\t\treturn nil\n\t}\n\n\tusername, err := h.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tdefer username.Destroy()\n\tpassword, err := h.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer password.Destroy()\n\trequest.SetBasicAuth(username.String(), password.String())\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"http_response\", func() telegraf.Input {\n\t\treturn &HTTPResponse{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/http_response/http_response_test.go",
    "content": "package http_response\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// Receives a list with fields that are expected to be absent\nfunc checkAbsentFields(t *testing.T, fields []string, acc *testutil.Accumulator) {\n\tfor _, field := range fields {\n\t\tok := acc.HasField(\"http_response\", field)\n\t\trequire.False(t, ok)\n\t}\n}\n\n// Receives a list with tags that are expected to be absent\nfunc checkAbsentTags(t *testing.T, tags []string, acc *testutil.Accumulator) {\n\tfor _, tag := range tags {\n\t\tok := acc.HasTag(\"http_response\", tag)\n\t\trequire.False(t, ok)\n\t}\n}\n\n// Receives a dictionary and with expected fields and their values. If a value is nil, it will only check\n// that the field exists, but not its contents\nfunc checkFields(t *testing.T, fields map[string]interface{}, acc *testutil.Accumulator) {\n\tt.Helper()\n\tfor key, field := range fields {\n\t\tswitch v := field.(type) {\n\t\tcase int:\n\t\t\tvalue, ok := acc.IntField(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, field, value)\n\t\tcase float64:\n\t\t\tvalue, ok := acc.FloatField(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.InDelta(t, field, value, testutil.DefaultDelta)\n\t\tcase string:\n\t\t\tvalue, ok := acc.StringField(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, field, value)\n\t\tcase nil:\n\t\t\tok := acc.HasField(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\tdefault:\n\t\t\tt.Log(\"Unsupported type for field: \", v)\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n\n// Receives a dictionary and with expected tags and their values. If a value is nil, it will only check\n// that the tag exists, but not its contents\nfunc checkTags(t *testing.T, tags map[string]interface{}, acc *testutil.Accumulator) {\n\tfor key, tag := range tags {\n\t\tswitch v := tag.(type) {\n\t\tcase string:\n\t\t\tok := acc.HasTag(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tag, acc.TagValue(\"http_response\", key))\n\t\tcase nil:\n\t\t\tok := acc.HasTag(\"http_response\", key)\n\t\t\trequire.True(t, ok)\n\t\tdefault:\n\t\t\tt.Log(\"Unsupported type for tag: \", v)\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n\nfunc setUpTestMux() http.Handler {\n\tmux := http.NewServeMux()\n\t// Ignore all returned errors below as the tests will fail anyway\n\tmux.HandleFunc(\"/redirect\", func(w http.ResponseWriter, req *http.Request) {\n\t\thttp.Redirect(w, req, \"/good\", http.StatusMovedPermanently)\n\t})\n\tmux.HandleFunc(\"/good\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Server\", \"MyTestServer\")\n\t\tw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\t\tfmt.Fprintf(w, \"hit the good page!\")\n\t})\n\tmux.HandleFunc(\"/form\", func(w http.ResponseWriter, req *http.Request) {\n\t\tbody, err := io.ReadAll(req.Body)\n\t\tdefer req.Body.Close()\n\t\tif err != nil {\n\t\t\thttp.Error(w, \"couldn't read request body\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\tif string(body) != \"list=foobar&list=fizbuzz&test=42\" {\n\t\t\tfmt.Println(string(body))\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}\n\t})\n\tmux.HandleFunc(\"/invalidUTF8\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Write([]byte{0xff, 0xfe, 0xfd}) //nolint:errcheck // ignore the returned error as the test will fail anyway\n\t})\n\tmux.HandleFunc(\"/noheader\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tfmt.Fprintf(w, \"hit the good page!\")\n\t})\n\tmux.HandleFunc(\"/jsonresponse\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tfmt.Fprintf(w, \"\\\"service_status\\\": \\\"up\\\", \\\"healthy\\\" : \\\"true\\\"\")\n\t})\n\tmux.HandleFunc(\"/badredirect\", func(w http.ResponseWriter, req *http.Request) {\n\t\thttp.Redirect(w, req, \"/badredirect\", http.StatusMovedPermanently)\n\t})\n\tmux.HandleFunc(\"/mustbepostmethod\", func(w http.ResponseWriter, req *http.Request) {\n\t\tif req.Method != \"POST\" {\n\t\t\thttp.Error(w, \"method wasn't post\", http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\t\tfmt.Fprintf(w, \"used post correctly!\")\n\t})\n\tmux.HandleFunc(\"/musthaveabody\", func(w http.ResponseWriter, req *http.Request) {\n\t\tbody, err := io.ReadAll(req.Body)\n\t\tdefer req.Body.Close()\n\t\tif err != nil {\n\t\t\thttp.Error(w, \"couldn't read request body\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\tif len(body) == 0 {\n\t\t\thttp.Error(w, \"body was empty\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\tfmt.Fprintf(w, \"sent a body!\")\n\t})\n\tmux.HandleFunc(\"/twosecondnap\", func(http.ResponseWriter, *http.Request) {\n\t\ttime.Sleep(time.Second * 2)\n\t})\n\tmux.HandleFunc(\"/nocontent\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusNoContent)\n\t})\n\treturn mux\n}\n\nfunc checkOutput(t *testing.T, acc *testutil.Accumulator, presentFields, presentTags map[string]interface{}, absentFields, absentTags []string) {\n\tt.Helper()\n\tif presentFields != nil {\n\t\tcheckFields(t, presentFields, acc)\n\t}\n\n\tif presentTags != nil {\n\t\tcheckTags(t, presentTags, acc)\n\t}\n\n\tif absentFields != nil {\n\t\tcheckAbsentFields(t, absentFields, acc)\n\t}\n\n\tif absentTags != nil {\n\t\tcheckAbsentTags(t, absentTags, acc)\n\t}\n}\n\nfunc TestHeaders(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Host != \"Hello\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"Hello\", r.Host)\n\t\t\treturn\n\t\t}\n\t\tif cHeader := r.Header.Get(\"Content-Type\"); cHeader != \"application/json\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"application/json\", cHeader)\n\t\t\treturn\n\t\t}\n\t\tif uaHeader := r.Header.Get(\"User-Agent\"); uaHeader != internal.ProductToken() {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", internal.ProductToken(), uaHeader)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL},\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 2),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"Host\":         \"Hello\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestFields(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestResponseBodyField(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tResponseBodyField: \"my_body_field\",\n\t\tFollowRedirects:   true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t\t\"my_body_field\":      \"hit the good page!\",\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\t// Invalid UTF-8 String\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/invalidUTF8\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tResponseBodyField: \"my_body_field\",\n\t\tFollowRedirects:   true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"result_type\": \"body_read_error\",\n\t\t\"result_code\": 2,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"body_read_error\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestResponseBodyFormField(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:  testutil.Logger{},\n\t\tURLs: []string{ts.URL + \"/form\"},\n\t\tBodyForm: map[string][]string{\n\t\t\t\"test\": {\"42\"},\n\t\t\t\"list\": {\"foobar\", \"fizbuzz\"},\n\t\t},\n\t\tMethod: \"POST\",\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t},\n\t\tResponseTimeout:   config.Duration(time.Second * 20),\n\t\tResponseBodyField: \"my_body_field\",\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t\t\"my_body_field\":      \"\",\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"POST\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestResponseBodyMaxSize(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tResponseBodyMaxSize: config.Size(5),\n\t\tFollowRedirects:     true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"result_type\": \"body_read_error\",\n\t\t\"result_code\": 2,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"body_read_error\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestHTTPHeaderTags(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHTTPHeaderTags:  map[string]string{\"Server\": \"my_server\", \"Content-Type\": \"content_type\"},\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":       nil,\n\t\t\"method\":       \"GET\",\n\t\t\"status_code\":  \"200\",\n\t\t\"result\":       \"success\",\n\t\t\"my_server\":    \"MyTestServer\",\n\t\t\"content_type\": \"application/json; charset=utf-8\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/noheader\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHTTPHeaderTags:  map[string]string{\"Server\": \"my_server\", \"Content-Type\": \"content_type\"},\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedTags = map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\t// Connection failed\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{\"https:/nonexistent.nonexistent\"}, // Any non-routable IP works here\n\t\tBody:            \"\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 5),\n\t\tHTTPHeaderTags:  map[string]string{\"Server\": \"my_server\", \"Content-Type\": \"content_type\"},\n\t\tFollowRedirects: false,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"result_type\": \"connection_failed\",\n\t\t\"result_code\": 3,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"connection_failed\",\n\t}\n\tabsentFields = []string{\"http_response_code\", \"response_time\", \"content_length\", \"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc findInterface() (net.Interface, error) {\n\tpotential, err := net.Interfaces()\n\tif err != nil {\n\t\treturn net.Interface{}, err\n\t}\n\n\tfor _, i := range potential {\n\t\t// we are only interest in loopback interfaces which are up\n\t\tif (i.Flags&net.FlagUp == 0) || (i.Flags&net.FlagLoopback == 0) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif addrs, err := i.Addrs(); err == nil && len(addrs) > 0 {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\n\treturn net.Interface{}, errors.New(\"cannot find suitable loopback interface\")\n}\n\nfunc TestInterface(t *testing.T) {\n\tvar (\n\t\tmux = setUpTestMux()\n\t\tts  = httptest.NewServer(mux)\n\t)\n\n\tdefer ts.Close()\n\n\tintf, err := findInterface()\n\trequire.NoError(t, err)\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t\tInterface:       intf.Name,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestRedirects(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/redirect\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/badredirect\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"result_type\": \"connection_failed\",\n\t\t\"result_code\": 3,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"connection_failed\",\n\t}\n\tabsentFields = []string{\"http_response_code\", \"response_time\", \"response_string_match\"}\n\tabsentTags := []string{\"status_code\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n\n\texpectedFields = map[string]interface{}{\"result_type\": \"connection_failed\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)\n}\n\nfunc TestMethod(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/mustbepostmethod\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"POST\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"POST\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/mustbepostmethod\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"http_response_code\": http.StatusMethodNotAllowed,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"405\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields = []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\t// check that lowercase methods work correctly\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/mustbepostmethod\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"head\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"http_response_code\": http.StatusMethodNotAllowed,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"head\",\n\t\t\"status_code\": \"405\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields = []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestBody(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/musthaveabody\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/musthaveabody\"},\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"http_response_code\": http.StatusBadRequest,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"400\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields = []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestStringMatch(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/good\"},\n\t\tBody:                \"{ 'test': 'data'}\",\n\t\tMethod:              \"GET\",\n\t\tResponseStringMatch: \"hit the good page\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":    http.StatusOK,\n\t\t\"response_string_match\": 1,\n\t\t\"result_type\":           \"success\",\n\t\t\"result_code\":           0,\n\t\t\"response_time\":         nil,\n\t\t\"content_length\":        nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestStringMatchJson(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/jsonresponse\"},\n\t\tBody:                \"{ 'test': 'data'}\",\n\t\tMethod:              \"GET\",\n\t\tResponseStringMatch: \"\\\"service_status\\\": \\\"up\\\"\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":    http.StatusOK,\n\t\t\"response_string_match\": 1,\n\t\t\"result_type\":           \"success\",\n\t\t\"result_code\":           0,\n\t\t\"response_time\":         nil,\n\t\t\"content_length\":        nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestStringMatchFail(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/good\"},\n\t\tBody:                \"{ 'test': 'data'}\",\n\t\tMethod:              \"GET\",\n\t\tResponseStringMatch: \"hit the bad page\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":    http.StatusOK,\n\t\t\"response_string_match\": 0,\n\t\t\"result_type\":           \"response_string_mismatch\",\n\t\t\"result_code\":           1,\n\t\t\"response_time\":         nil,\n\t\t\"content_length\":        nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"response_string_mismatch\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestTimeout(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping test with sleep in short mode.\")\n\t}\n\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/twosecondnap\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"result_type\": \"timeout\",\n\t\t\"result_code\": 4,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"timeout\",\n\t}\n\tabsentFields := []string{\"http_response_code\", \"response_time\", \"content_length\", \"response_string_match\"}\n\tabsentTags := []string{\"status_code\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)\n}\n\nfunc TestBadRegex(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/good\"},\n\t\tBody:                \"{ 'test': 'data'}\",\n\t\tMethod:              \"GET\",\n\t\tResponseStringMatch: \"bad regex:[[\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\trequire.ErrorContains(t, h.Init(), \"failed to compile regular expression\")\n}\n\ntype fakeClient struct {\n\tstatusCode int\n\terr        error\n}\n\nfunc (f *fakeClient) Do(_ *http.Request) (*http.Response, error) {\n\treturn &http.Response{StatusCode: f.statusCode}, f.err\n}\n\nfunc TestNetworkErrors(t *testing.T) {\n\tcl := client{\n\t\thttpClient: &fakeClient{err: &url.Error{Err: &net.OpError{Err: &net.DNSError{Err: \"DNS error\"}}}},\n\t\taddress:    \"\",\n\t}\n\t// DNS error\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{\"https://nonexistent.nonexistent\"}, // Any non-resolvable URL works here\n\t\tBody:            \"\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tFollowRedirects: false,\n\t\tclients:         []client{cl},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"result_type\": \"dns_error\",\n\t\t\"result_code\": 5,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"dns_error\",\n\t}\n\tabsentFields := []string{\"http_response_code\", \"response_time\", \"content_length\", \"response_string_match\"}\n\tabsentTags := []string{\"status_code\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)\n\n\t// Connection failed\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{\"https:/nonexistent.nonexistent\"}, // Any non-routable IP works here\n\t\tBody:            \"\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 5),\n\t\tFollowRedirects: false,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"result_type\": \"connection_failed\",\n\t\t\"result_code\": 3,\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\": nil,\n\t\t\"method\": \"GET\",\n\t\t\"result\": \"connection_failed\",\n\t}\n\tabsentFields = []string{\"http_response_code\", \"response_time\", \"content_length\", \"response_string_match\"}\n\tabsentTags = []string{\"status_code\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)\n}\n\nfunc TestContentLength(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     len([]byte(\"hit the good page!\")),\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n\n\th = &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/musthaveabody\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tFollowRedirects: true,\n\t}\n\n\tacc = testutil.Accumulator{}\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields = map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     len([]byte(\"sent a body!\")),\n\t}\n\texpectedTags = map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields = []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestRedirect(t *testing.T) {\n\tts := httptest.NewServer(http.NotFoundHandler())\n\tdefer ts.Close()\n\n\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Location\", \"http://example.org\")\n\t\tw.WriteHeader(http.StatusMovedPermanently)\n\t\tif _, err := w.Write([]byte(\"test\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t})\n\n\th := &HTTPResponse{\n\t\tURLs:                []string{ts.URL},\n\t\tResponseStringMatch: \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"http_response\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\":      ts.URL,\n\t\t\t\t\"method\":      \"GET\",\n\t\t\t\t\"result\":      \"success\",\n\t\t\t\t\"status_code\": \"301\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"result_code\":           0,\n\t\t\t\t\"result_type\":           \"success\",\n\t\t\t\t\"http_response_code\":    301,\n\t\t\t\t\"response_string_match\": 1,\n\t\t\t\t\"content_length\":        4,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\tfor _, m := range actual {\n\t\tm.RemoveField(\"response_time\")\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestBasicAuth(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif aHeader := r.Header.Get(\"Authorization\"); aHeader != \"Basic bWU6bXlwYXNzd29yZA==\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"Basic bWU6bXlwYXNzd29yZA==\", aHeader)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tBody:            \"{ 'test': 'data'}\",\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tUsername:        config.NewSecret([]byte(\"me\")),\n\t\tPassword:        config.NewSecret([]byte(\"mypassword\")),\n\t\tHeaders: map[string]string{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc TestStatusCodeMatchFail(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                testutil.Logger{},\n\t\tURLs:               []string{ts.URL + \"/nocontent\"},\n\t\tResponseStatusCode: http.StatusOK,\n\t\tResponseTimeout:    config.Duration(time.Second * 20),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":         http.StatusNoContent,\n\t\t\"response_status_code_match\": 0,\n\t\t\"result_type\":                \"response_status_code_mismatch\",\n\t\t\"result_code\":                6,\n\t\t\"response_time\":              nil,\n\t\t\"content_length\":             nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      http.MethodGet,\n\t\t\"status_code\": \"204\",\n\t\t\"result\":      \"response_status_code_mismatch\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestStatusCodeMatch(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                testutil.Logger{},\n\t\tURLs:               []string{ts.URL + \"/nocontent\"},\n\t\tResponseStatusCode: http.StatusNoContent,\n\t\tResponseTimeout:    config.Duration(time.Second * 20),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":         http.StatusNoContent,\n\t\t\"response_status_code_match\": 1,\n\t\t\"result_type\":                \"success\",\n\t\t\"result_code\":                0,\n\t\t\"response_time\":              nil,\n\t\t\"content_length\":             nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      http.MethodGet,\n\t\t\"status_code\": \"204\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestStatusCodeAndStringMatch(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/good\"},\n\t\tResponseStatusCode:  http.StatusOK,\n\t\tResponseStringMatch: \"hit the good page\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":         http.StatusOK,\n\t\t\"response_status_code_match\": 1,\n\t\t\"response_string_match\":      1,\n\t\t\"result_type\":                \"success\",\n\t\t\"result_code\":                0,\n\t\t\"response_time\":              nil,\n\t\t\"content_length\":             nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      http.MethodGet,\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestStatusCodeAndStringMatchFail(t *testing.T) {\n\tmux := setUpTestMux()\n\tts := httptest.NewServer(mux)\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:                 testutil.Logger{},\n\t\tURLs:                []string{ts.URL + \"/nocontent\"},\n\t\tResponseStatusCode:  http.StatusOK,\n\t\tResponseStringMatch: \"hit the good page\",\n\t\tResponseTimeout:     config.Duration(time.Second * 20),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\":         http.StatusNoContent,\n\t\t\"response_status_code_match\": 0,\n\t\t\"response_string_match\":      0,\n\t\t\"result_type\":                \"response_status_code_mismatch\",\n\t\t\"result_code\":                6,\n\t\t\"response_time\":              nil,\n\t\t\"content_length\":             nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      http.MethodGet,\n\t\t\"status_code\": \"204\",\n\t\t\"result\":      \"response_status_code_mismatch\",\n\t}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, nil, nil)\n}\n\nfunc TestSNI(t *testing.T) {\n\tts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.TLS.ServerName != \"super-special-hostname.example.com\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"super-special-hostname.example.com\", r.TLS.ServerName)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\th := &HTTPResponse{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL + \"/good\"},\n\t\tMethod:          \"GET\",\n\t\tResponseTimeout: config.Duration(time.Second * 20),\n\t\tClientConfig: tls.ClientConfig{\n\t\t\tInsecureSkipVerify: true,\n\t\t\tServerName:         \"super-special-hostname.example.com\",\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, h.Init())\n\trequire.NoError(t, h.Gather(&acc))\n\n\texpectedFields := map[string]interface{}{\n\t\t\"http_response_code\": http.StatusOK,\n\t\t\"result_type\":        \"success\",\n\t\t\"result_code\":        0,\n\t\t\"response_time\":      nil,\n\t\t\"content_length\":     nil,\n\t}\n\texpectedTags := map[string]interface{}{\n\t\t\"server\":      nil,\n\t\t\"method\":      \"GET\",\n\t\t\"status_code\": \"200\",\n\t\t\"result\":      \"success\",\n\t}\n\tabsentFields := []string{\"response_string_match\"}\n\tcheckOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)\n}\n\nfunc Test_isURLInIPv6(t *testing.T) {\n\ttests := []struct {\n\t\taddress url.URL\n\t\twant    bool\n\t}{\n\t\t{\n\t\t\taddress: parseURL(t, \"http://[2001:db8:a0b:12f0::1]/index.html\"),\n\t\t\twant:    true,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"http://[2001:db8:a0b:12f0::1]:80/index.html\"),\n\t\t\twant:    true,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"https://[2001:db8:a0b:12f0::1%25eth0]:15000/\"), // `%25` escapes `%`\n\t\t\twant:    true,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"https://2001:0db8:0001:0000:0000:0ab9:C0A8:0102\"),\n\t\t\twant:    true,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"http://[2607:f8b0:4005:802::1007]/\"),\n\t\t\twant:    true,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"https://127.0.0.1\"),\n\t\t\twant:    false,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"https://google.com\"),\n\t\t\twant:    false,\n\t\t}, {\n\t\t\taddress: parseURL(t, \"https://thispagemayexist.ornot/index.html\"),\n\t\t\twant:    false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.address.String(), func(t *testing.T) {\n\t\t\tif got, _ := isURLInIPv6(tt.address); got != tt.want {\n\t\t\t\tt.Errorf(\"isURLInIPv6() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc Test_isIPNetInIPv6(t *testing.T) {\n\ttests := []struct {\n\t\taddress *net.IPNet\n\t\twant    bool\n\t}{\n\t\t{\n\t\t\taddress: &net.IPNet{\n\t\t\t\tIP:   net.IPv4(127, 0, 0, 1),\n\t\t\t\tMask: net.CIDRMask(8, 32),\n\t\t\t},\n\t\t\twant: false,\n\t\t}, {\n\t\t\taddress: &net.IPNet{\n\t\t\t\tIP:   net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},\n\t\t\t\tMask: net.CIDRMask(128, 128),\n\t\t\t},\n\t\t\twant: true,\n\t\t}, {\n\t\t\taddress: &net.IPNet{\n\t\t\t\tIP:   net.IPv4(192, 168, 0, 1),\n\t\t\t\tMask: net.CIDRMask(24, 32),\n\t\t\t},\n\t\t\twant: false,\n\t\t}, {\n\t\t\taddress: &net.IPNet{\n\t\t\t\tIP:   net.ParseIP(\"fe80::43ac:7835:471a:faba\"),\n\t\t\t\tMask: net.CIDRMask(64, 128),\n\t\t\t},\n\t\t\twant: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.address.String(), func(t *testing.T) {\n\t\t\tif got := isIPNetInIPv6(tt.address); got != tt.want {\n\t\t\t\tt.Errorf(\"isIPNetInIPv6() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc parseURL(t *testing.T, address string) url.URL {\n\tu, err := url.Parse(address)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, u)\n\treturn *u\n}\n"
  },
  {
    "path": "plugins/inputs/http_response/sample.conf",
    "content": "# HTTP/HTTPS request given an address a method and a timeout\n[[inputs.http_response]]\n  ## List of urls to query.\n  # urls = [\"http://localhost\"]\n\n  ## Set http_proxy.\n  ## Telegraf uses the system wide proxy settings if it's is not set.\n  # http_proxy = \"http://localhost:8888\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## HTTP Request Method\n  # method = \"GET\"\n\n  ## Whether to follow redirects from the server (defaults to false)\n  # follow_redirects = false\n\n  ## Optional file with Bearer token\n  ## file content is added as an Authorization header\n  # bearer_token = \"/path/to/file\"\n\n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional HTTP Request Body\n  # body = '''\n  # {'fake':'data'}\n  # '''\n\n  ## Optional HTTP Request Body Form\n  ## Key value pairs to encode and set at URL form. Can be used with the POST\n  ## method + application/x-www-form-urlencoded content type to replicate the\n  ## POSTFORM method.\n  # body_form = { \"key\": \"value\" }\n\n  ## Optional name of the field that will contain the body of the response.\n  ## By default it is set to an empty String indicating that the body's\n  ## content won't be added\n  # response_body_field = ''\n\n  ## Maximum allowed HTTP response body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  ## If the response body size exceeds this limit a \"body_read_error\" will\n  ## be raised.\n  # response_body_max_size = \"32MiB\"\n\n  ## Optional substring or regex match in body of the response (case sensitive)\n  # response_string_match = \"\\\"service_status\\\": \\\"up\\\"\"\n  # response_string_match = \"ok\"\n  # response_string_match = \"\\\".*_status\\\".?:.?\\\"up\\\"\"\n\n  ## Expected response status code.\n  ## The status code of the response is compared to this value. If they match,\n  ## the field \"response_status_code_match\" will be 1, otherwise it will be 0.\n  ## If the expected status code is 0, the check is disabled and the field\n  ## won't be added.\n  # response_status_code = 0\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"\"\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## HTTP Request Headers (all values must be strings)\n  # [inputs.http_response.headers]\n  #   Host = \"github.com\"\n\n  ## Optional setting to map response http headers into tags\n  ## If the http header is not present on the request, no corresponding tag will\n  ## be added. If multiple instances of the http header are present, only the\n  ## first value will be used.\n  # http_header_tags = {\"HTTP_HEADER\" = \"TAG_NAME\"}\n\n  ## Interface to use when dialing an address\n  # interface = \"eth0\"\n\n  ## Optional Cookie authentication\n  # cookie_auth_url = \"https://localhost/authMe\"\n  # cookie_auth_method = \"POST\"\n  # cookie_auth_username = \"username\"\n  # cookie_auth_password = \"pa$$word\"\n  # cookie_auth_body = '{\"username\": \"user\", \"password\": \"pa$$word\", \"authenticate\": \"me\"}'\n  ## cookie_auth_renewal not set or set to \"0\" will auth once and never renew the cookie\n  # cookie_auth_renewal = \"5m\"\n"
  },
  {
    "path": "plugins/inputs/huebridge/README.md",
    "content": "# HueBridge Input Plugin\n\nThis plugin gathers status from [Hue Bridge][hue] devices using the\n[CLIP API][hue_api] interface of the devices.\n\n⭐ Telegraf v1.34.0\n🏷️ iot\n💻 all\n\n[hue]: https://www.philips-hue.com/\n[hue_api]: https://developers.meethue.com/develop/hue-api-v2/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather smart home status from Hue Bridge\n[[inputs.huebridge]]\n  ## URL of bridges to query in the form <scheme>://<bridge id>:<user name>@<address>/\n  ## See documentation for available schemes.\n  bridges = [ \"address://<bridge id>:<user name>@<bridge hostname or address>/\" ]\n  \n  ## Manual device to room assignments to apply during status evaluation.\n  ## E.g. for motion sensors which are reported without a room assignment.\n  # room_assignments = { \"Motion sensor 1\" = \"Living room\", \"Motion sensor 2\" = \"Corridor\" }\n  \n  ## Timeout for gathering information\n  # timeout = \"10s\"\n  \n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### Extended bridge access options\n\nThe Hue bridges to query can be defined by URLs of the following form:\n\n```text\n  <locator scheme>://<bridge id>:<user name>@<locator dependent address>/\n```\n\nwhere the `bridge id` is the unique bridge id as returned in\n\n```bash\ncurl -k https://<address>/api/config/0\n```\n\nand the `user name` is the secret user name returned during application\nauthentication.\n\nTo create a new user name issue the following command\nafter pressing the bridge's link button:\n\n```bash\n  curl -k -X POST http://<bridge address>/api \\\n    -H 'Content-Type: application/json' \\\n    -d '{\"devicetype\":\"huebridge-telegraf-plugin\"}'\n```\n\nThe `scheme` can have one of the following values and will also determine the\nstructure of the `address` part.\n\n#### `address` scheme\n\nAddresses a local bridge with `address` being the DNS name or IP address of the\nbridge, e.g.\n\n```text\naddress://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@mybridge/\n```\n\n#### `cloud` scheme\n\nWith this scheme the plugin discovers a bridge via its cloud registration.\nThe `address` part defines the discovery endpoint to use.\nIf not specified otherwise,\nthe [standard discovery endpoint][discovery_url] is used, e.g.\n\n```text\ncloud://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@/\n```\n\n[discovery_url]: https://discovery.meethue.com/\n\n#### `mdns`  scheme\n\nThis scheme uses mDNS to discover the bridge. Leave the `address` part unset\nfor this scheme like\n\n```text\nmdns://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@/\n```\n\n#### `remote` scheme\n\nThis scheme accesses the bridge via the Cloud Remote API. The `address` part\ndefines the cloud API endpoint defaulting to the\n[standard API endpoint][cloud_api_endpoint].\n\n```text\nremote://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@/\n```\n\nIn order to use this method a Hue Developer Account is required, a Remote App\nmust be registered and the corresponding Authorization flow must be completed.\nSee the [Cloud2Cloud Getting Started documentation][cloud_getting_started]\nfor full details.\n\nAdditionally, the `remote_client_id`, `remote_client_secret`, and\n`remote_callback_url` parameters must be set in the plugin configuration\nexactly as used during the App registration.\n\nFurthermore the `remote_token_dir` parameter must point to the directory\ncontaining the persisted token.\n\n[cloud_api_endpoint]: https://api.meethue.com\n[cloud_getting_started]: https://developers.meethue.com/develop/hue-api-v2/cloud2cloud-getting-started/\n\n## Metrics\n\n- `huebridge_light`\n  - tags\n    - `bridge_id` - The bridge id (this metrics has been queried from)\n    - `room` - The name of the room\n    - `device` - The name of the device\n  - fields\n    - `on` (int) - 0: light is off 1: light is on\n- `huebridge_temperature`\n  - tags\n    - `bridge_id` - The bridge id (this metrics has been queried from)\n    - `room` - The name of the room\n    - `device` - The name of the device\n    - `enabled` - The current status of sensor (active: true|false)\n  - fields\n    - `temperature` (float) - The current temperatue (in °Celsius)\n- `huebridge_light_level`\n  - tags\n    - `bridge_id` - The bridge id (this metrics has been queried from)\n    - `room` - The name of the room\n    - `device` - The name of the device\n    - `enabled` - The current status of sensor (active: true|false)\n  - fields\n    - `light_level` (int) - The current light level (in human friendly scale 10.000*log10(lux)+1)\n    - `light_level_lux` (float) - The current light level (in lux)\n- `huebridge_motion_sensor`\n  - tags\n    - `bridge_id` - The bridge id (this metrics has been queried from)\n    - `room` - The name of the room\n    - `device` - The name of the device\n    - `enabled` - The current status of sensor (active: true|false)\n  - fields\n    - `motion` (int) - 0: no motion detected 1: motion detected\n- `huebridge_device_power`\n  - tags\n    - `bridge_id` - The bridge id (this metrics has been queried from)\n    - `room` - The name of the room\n    - `device` - The name of the device\n  - fields\n    - `battery_level` (int) - Power source status (normal, low, critical)\n    - `battery_state` (string) - Battery charge level (in %)\n\n## Example Output\n\n```text\nhuebridge_light,huebridge_bridge_id=0123456789ABCDEF,huebridge_room=Name#15,huebridge_device=Name#3 on=0 1734880329\nhuebridge_temperature,huebridge_room=Name#15,huebridge_device=Name#7,huebridge_device_enabled=true,huebridge_bridge_id=0123456789ABCDEF temperature=17.63 1734880329\nhuebridge_light_level,huebridge_bridge_id=0123456789ABCDEF,huebridge_room=Name#15,huebridge_device=Name#7,huebridge_device_enabled=true light_level=18948,light_level_lux=78.46934003526889 1734880329\nhuebridge_motion_sensor,huebridge_bridge_id=0123456789ABCDEF,huebridge_room=Name#15,huebridge_device=Name#7,huebridge_device_enabled=true motion=0 1734880329\nhuebridge_device_power,huebridge_bridge_id=0123456789ABCDEF,huebridge_room=Name#15,huebridge_device=Name#7 battery_level=100,battery_state=normal 1734880329\n```\n"
  },
  {
    "path": "plugins/inputs/huebridge/bridge.go",
    "content": "package huebridge\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"maps\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tdrn-org/go-hue\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype bridge struct {\n\turl                   *url.URL\n\tconfigRoomAssignments map[string]string\n\tremoteCfg             *remoteClientConfig\n\ttlsCfg                *tls.Config\n\ttimeout               time.Duration\n\tlog                   telegraf.Logger\n\n\tresolvedClient  hue.BridgeClient\n\tresourceTree    map[string]string\n\tdeviceNames     map[string]string\n\troomAssignments map[string]string\n}\n\nfunc (b *bridge) String() string {\n\treturn b.url.Redacted()\n}\n\nfunc (b *bridge) process(acc telegraf.Accumulator) error {\n\tif b.resolvedClient == nil {\n\t\tif err := b.resolve(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tb.log.Tracef(\"Processing bridge %s\", b)\n\tif err := b.fetchMetadata(); err != nil {\n\t\t// Discard previously resolved client and re-resolve on next process call\n\t\tb.resolvedClient = nil\n\t\treturn err\n\t}\n\tacc.AddError(b.processLights(acc))\n\tacc.AddError(b.processTemperatures(acc))\n\tacc.AddError(b.processLightLevels(acc))\n\tacc.AddError(b.processMotionSensors(acc))\n\tacc.AddError(b.processDevicePowers(acc))\n\treturn nil\n}\n\nfunc (b *bridge) processLights(acc telegraf.Accumulator) error {\n\tgetLightsResponse, err := b.resolvedClient.GetLights()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge lights on %s: %w\", b, err)\n\t}\n\tif getLightsResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge lights from %s: %s\", b, getLightsResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getLightsResponse.JSON200.Data\n\tif responseData != nil {\n\t\tfor _, light := range *responseData {\n\t\t\ttags := make(map[string]string)\n\t\t\ttags[\"bridge_id\"] = b.resolvedClient.Bridge().BridgeId\n\t\t\ttags[\"room\"] = b.resolveResourceRoom(*light.Id, *light.Metadata.Name)\n\t\t\ttags[\"device\"] = *light.Metadata.Name\n\t\t\tfields := make(map[string]interface{})\n\t\t\tif *light.On.On {\n\t\t\t\tfields[\"on\"] = 1\n\t\t\t} else {\n\t\t\t\tfields[\"on\"] = 0\n\t\t\t}\n\t\t\tacc.AddGauge(\"huebridge_light\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) processTemperatures(acc telegraf.Accumulator) error {\n\tgetTemperaturesResponse, err := b.resolvedClient.GetTemperatures()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge temperatures on %s: %w\", b, err)\n\t}\n\tif getTemperaturesResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge temperatures from %s: %s\", b, getTemperaturesResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getTemperaturesResponse.JSON200.Data\n\tif responseData != nil {\n\t\tfor _, temperature := range *responseData {\n\t\t\ttemperatureName := b.resolveDeviceName(*temperature.Id)\n\t\t\ttags := make(map[string]string)\n\t\t\ttags[\"bridge_id\"] = b.resolvedClient.Bridge().BridgeId\n\t\t\ttags[\"room\"] = b.resolveResourceRoom(*temperature.Id, temperatureName)\n\t\t\ttags[\"device\"] = temperatureName\n\t\t\ttags[\"enabled\"] = strconv.FormatBool(*temperature.Enabled)\n\t\t\tfields := make(map[string]interface{})\n\t\t\tfields[\"temperature\"] = *temperature.Temperature.TemperatureReport.Temperature\n\t\t\tacc.AddGauge(\"huebridge_temperature\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) processLightLevels(acc telegraf.Accumulator) error {\n\tgetLightLevelsResponse, err := b.resolvedClient.GetLightLevels()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge lights levels on %s: %w\", b, err)\n\t}\n\tif getLightLevelsResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge light levels from %s: %s\", b, getLightLevelsResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getLightLevelsResponse.JSON200.Data\n\tif responseData != nil {\n\t\tfor _, lightLevel := range *responseData {\n\t\t\tlightLevelName := b.resolveDeviceName(*lightLevel.Id)\n\t\t\ttags := make(map[string]string)\n\t\t\ttags[\"bridge_id\"] = b.resolvedClient.Bridge().BridgeId\n\t\t\ttags[\"room\"] = b.resolveResourceRoom(*lightLevel.Id, lightLevelName)\n\t\t\ttags[\"device\"] = lightLevelName\n\t\t\ttags[\"enabled\"] = strconv.FormatBool(*lightLevel.Enabled)\n\t\t\tfields := make(map[string]interface{})\n\t\t\tfields[\"light_level\"] = *lightLevel.Light.LightLevelReport.LightLevel\n\t\t\tfields[\"light_level_lux\"] = math.Pow(10.0, (float64(*lightLevel.Light.LightLevelReport.LightLevel)-1.0)/10000.0)\n\t\t\tacc.AddGauge(\"huebridge_light_level\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) processMotionSensors(acc telegraf.Accumulator) error {\n\tgetMotionSensorsResponse, err := b.resolvedClient.GetMotionSensors()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge motion sensors on %s: %w\", b, err)\n\t}\n\tif getMotionSensorsResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge motion sensors from %s: %s\", b, getMotionSensorsResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getMotionSensorsResponse.JSON200.Data\n\tif responseData != nil {\n\t\tfor _, motionSensor := range *responseData {\n\t\t\tmotionSensorName := b.resolveDeviceName(*motionSensor.Id)\n\t\t\ttags := make(map[string]string)\n\t\t\ttags[\"bridge_id\"] = b.resolvedClient.Bridge().BridgeId\n\t\t\ttags[\"room\"] = b.resolveResourceRoom(*motionSensor.Id, motionSensorName)\n\t\t\ttags[\"device\"] = motionSensorName\n\t\t\ttags[\"enabled\"] = strconv.FormatBool(*motionSensor.Enabled)\n\t\t\tfields := make(map[string]interface{})\n\t\t\tif *motionSensor.Motion.MotionReport.Motion {\n\t\t\t\tfields[\"motion\"] = 1\n\t\t\t} else {\n\t\t\t\tfields[\"motion\"] = 0\n\t\t\t}\n\t\t\tacc.AddGauge(\"huebridge_motion_sensor\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) processDevicePowers(acc telegraf.Accumulator) error {\n\tgetDevicePowersResponse, err := b.resolvedClient.GetDevicePowers()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge device powers on %s: %w\", b, err)\n\t}\n\tif getDevicePowersResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge device powers from %s: %s\", b, getDevicePowersResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getDevicePowersResponse.JSON200.Data\n\tif responseData != nil {\n\t\tfor _, devicePower := range *responseData {\n\t\t\tif devicePower.PowerState.BatteryLevel == nil && devicePower.PowerState.BatteryState == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdevicePowerName := b.resolveDeviceName(*devicePower.Id)\n\t\t\ttags := make(map[string]string)\n\t\t\ttags[\"bridge_id\"] = b.resolvedClient.Bridge().BridgeId\n\t\t\ttags[\"room\"] = b.resolveResourceRoom(*devicePower.Id, devicePowerName)\n\t\t\ttags[\"device\"] = devicePowerName\n\t\t\tfields := make(map[string]interface{})\n\t\t\tfields[\"battery_level\"] = *devicePower.PowerState.BatteryLevel\n\t\t\tfields[\"battery_state\"] = *devicePower.PowerState.BatteryState\n\t\t\tacc.AddGauge(\"huebridge_device_power\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) resolve() error {\n\tif b.resolvedClient != nil {\n\t\treturn nil\n\t}\n\tswitch b.url.Scheme {\n\tcase \"address\":\n\t\treturn b.resolveViaAddress()\n\tcase \"cloud\":\n\t\treturn b.resolveViaCloud()\n\tcase \"mdns\":\n\t\treturn b.resolveViaMDNS()\n\tcase \"remote\":\n\t\treturn b.resolveViaRemote()\n\t}\n\treturn fmt.Errorf(\"unrecognized bridge URL %s\", b)\n}\n\nfunc (b *bridge) resolveViaAddress() error {\n\tlocator, err := hue.NewAddressBridgeLocator(b.url.Host)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn b.resolveLocalBridge(locator)\n}\n\nfunc (b *bridge) resolveViaCloud() error {\n\tlocator := hue.NewCloudBridgeLocator()\n\tif b.url.Host != \"\" {\n\t\tu, err := url.Parse(fmt.Sprintf(\"https://%s/\", b.url.Host))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tlocator.DiscoveryEndpointUrl = u.JoinPath(b.url.Path)\n\t}\n\tlocator.TlsConfig = b.tlsCfg\n\treturn b.resolveLocalBridge(locator)\n}\n\nfunc (b *bridge) resolveViaMDNS() error {\n\tlocator := hue.NewMDNSBridgeLocator()\n\treturn b.resolveLocalBridge(locator)\n}\n\nfunc (b *bridge) resolveLocalBridge(locator hue.BridgeLocator) error {\n\thueBridge, err := locator.Lookup(b.url.User.Username(), b.timeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\turlPassword, _ := b.url.User.Password()\n\tbridgeClient, err := hueBridge.NewClient(hue.NewLocalBridgeAuthenticator(urlPassword), b.timeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.resolvedClient = bridgeClient\n\treturn nil\n}\n\nfunc (b *bridge) resolveViaRemote() error {\n\tvar redirectURL *url.URL\n\tif b.remoteCfg.RemoteCallbackURL != \"\" {\n\t\tu, err := url.Parse(b.remoteCfg.RemoteCallbackURL)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tredirectURL = u\n\t}\n\ttokenFile := filepath.Join(\n\t\tb.remoteCfg.RemoteTokenDir,\n\t\tb.remoteCfg.RemoteClientID,\n\t\tstrings.ToUpper(b.url.User.Username())+\".json\",\n\t)\n\tlocator, err := hue.NewRemoteBridgeLocator(\n\t\tb.remoteCfg.RemoteClientID,\n\t\tb.remoteCfg.RemoteClientSecret,\n\t\tredirectURL,\n\t\ttokenFile,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif b.url.Host != \"\" {\n\t\tu, err := url.Parse(fmt.Sprintf(\"https://%s/\", b.url.Host))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tlocator.EndpointUrl = u.JoinPath(b.url.Path)\n\t}\n\tlocator.TlsConfig = b.tlsCfg\n\treturn b.resolveRemoteBridge(locator)\n}\n\nfunc (b *bridge) resolveRemoteBridge(locator *hue.RemoteBridgeLocator) error {\n\thueBridge, err := locator.Lookup(b.url.User.Username(), b.timeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\turlPassword, _ := b.url.User.Password()\n\tbridgeClient, err := hueBridge.NewClient(hue.NewRemoteBridgeAuthenticator(locator, urlPassword), b.timeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.resolvedClient = bridgeClient\n\treturn nil\n}\n\nfunc (b *bridge) fetchMetadata() error {\n\terr := b.fetchResourceTree()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = b.fetchDeviceNames()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn b.fetchRoomAssignments()\n}\n\nfunc (b *bridge) fetchResourceTree() error {\n\tgetResourcesResponse, err := b.resolvedClient.GetResources()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge resources on %s: %w\", b, err)\n\t}\n\tif getResourcesResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge resources from %s: %s\", b, getResourcesResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getResourcesResponse.JSON200.Data\n\tif responseData == nil {\n\t\tb.resourceTree = make(map[string]string)\n\t\treturn nil\n\t}\n\tb.resourceTree = make(map[string]string, len(*responseData))\n\tfor _, resource := range *responseData {\n\t\tif resource.Owner != nil {\n\t\t\tb.resourceTree[*resource.Id] = *resource.Owner.Rid\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) fetchDeviceNames() error {\n\tgetDevicesResponse, err := b.resolvedClient.GetDevices()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge devices on %s: %w\", b, err)\n\t}\n\tif getDevicesResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge devices from %s: %s\", b, getDevicesResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getDevicesResponse.JSON200.Data\n\tif responseData == nil {\n\t\tb.deviceNames = make(map[string]string)\n\t\treturn nil\n\t}\n\tb.deviceNames = make(map[string]string, len(*responseData))\n\tfor _, device := range *responseData {\n\t\tb.deviceNames[*device.Id] = *device.Metadata.Name\n\t}\n\treturn nil\n}\n\nfunc (b *bridge) fetchRoomAssignments() error {\n\tgetRoomsResponse, err := b.resolvedClient.GetRooms()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to access bridge rooms on %s: %w\", b, err)\n\t}\n\tif getRoomsResponse.HTTPResponse.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to fetch bridge rooms from %s: %s\", b, getRoomsResponse.HTTPResponse.Status)\n\t}\n\tresponseData := getRoomsResponse.JSON200.Data\n\tif responseData == nil {\n\t\tb.roomAssignments = maps.Clone(b.configRoomAssignments)\n\t\treturn nil\n\t}\n\tb.roomAssignments = make(map[string]string, len(*responseData))\n\tfor _, roomGet := range *responseData {\n\t\tfor _, children := range *roomGet.Children {\n\t\t\tb.roomAssignments[*children.Rid] = *roomGet.Metadata.Name\n\t\t}\n\t}\n\tmaps.Copy(b.roomAssignments, b.configRoomAssignments)\n\treturn nil\n}\n\nfunc (b *bridge) resolveResourceRoom(resourceID, resourceName string) string {\n\troomName := b.roomAssignments[resourceName]\n\tif roomName != \"\" {\n\t\treturn roomName\n\t}\n\t// If resource does not have a room assigned directly, iterate upwards via\n\t// its owners until we find a room or there is no more owner. The latter\n\t// may happen (e.g. for Motion Sensors) resulting in room name\n\t// \"<unassigned>\".\n\tcurrentResourceID := resourceID\n\tfor {\n\t\t// Try next owner\n\t\tcurrentResourceID = b.resourceTree[currentResourceID]\n\t\tif currentResourceID == \"\" {\n\t\t\t// No owner left but no room found\n\t\t\tbreak\n\t\t}\n\t\troomName = b.roomAssignments[currentResourceID]\n\t\tif roomName != \"\" {\n\t\t\t// Room name found, done\n\t\t\treturn roomName\n\t\t}\n\t}\n\treturn \"<unassigned>\"\n}\n\nfunc (b *bridge) resolveDeviceName(resourceID string) string {\n\tdeviceName := b.deviceNames[resourceID]\n\tif deviceName != \"\" {\n\t\treturn deviceName\n\t}\n\t// If resource does not have a device name assigned directly, iterate\n\t// upwards via its owners until we find a room or there is no more\n\t// owner. The latter may happen resulting in device name \"<undefined>\".\n\tcurrentResourceID := resourceID\n\tfor {\n\t\t// Try next owner\n\t\tcurrentResourceID = b.resourceTree[currentResourceID]\n\t\tif currentResourceID == \"\" {\n\t\t\t// No owner left but no device found\n\t\t\tbreak\n\t\t}\n\t\tdeviceName = b.deviceNames[currentResourceID]\n\t\tif deviceName != \"\" {\n\t\t\t// Device name found, done\n\t\t\treturn deviceName\n\t\t}\n\t}\n\treturn \"<undefined>\"\n}\n"
  },
  {
    "path": "plugins/inputs/huebridge/huebridge.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage huebridge\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype HueBridge struct {\n\tBridgeUrls      []string          `toml:\"bridges\"`\n\tRoomAssignments map[string]string `toml:\"room_assignments\"`\n\tTimeout         config.Duration   `toml:\"timeout\"`\n\tLog             telegraf.Logger   `toml:\"-\"`\n\tremoteClientConfig\n\ttls.ClientConfig\n\n\tbridges []*bridge\n}\n\ntype remoteClientConfig struct {\n\tRemoteClientID     string `toml:\"remote_client_id\"`\n\tRemoteClientSecret string `toml:\"remote_client_secret\"`\n\tRemoteCallbackURL  string `toml:\"remote_callback_url\"`\n\tRemoteTokenDir     string `toml:\"remote_token_dir\"`\n}\n\nfunc (*HueBridge) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *HueBridge) Init() error {\n\ttlsCfg, err := h.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating TLS configuration failed: %w\", err)\n\t}\n\n\th.bridges = make([]*bridge, 0, len(h.BridgeUrls))\n\tfor _, b := range h.BridgeUrls {\n\t\tu, err := url.Parse(b)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse bridge URL %s: %w\", b, err)\n\t\t}\n\n\t\tswitch u.Scheme {\n\t\tcase \"address\", \"cloud\", \"mdns\":\n\t\t\t// Do nothing, those are valid\n\t\tcase \"remote\":\n\t\t\t// Remote scheme also requires a configured rcc\n\t\t\tif h.RemoteClientID == \"\" || h.RemoteClientSecret == \"\" || h.RemoteTokenDir == \"\" {\n\t\t\t\treturn errors.New(\"missing remote application credentials and/or token director not configured\")\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unrecognized scheme %s in URL %s\", u.Scheme, b)\n\t\t}\n\n\t\t// All schemes require a password in the URL\n\t\tif _, set := u.User.Password(); !set {\n\t\t\treturn fmt.Errorf(\"missing password in URL %s\", u)\n\t\t}\n\n\t\th.bridges = append(h.bridges, &bridge{\n\t\t\turl:                   u,\n\t\t\tconfigRoomAssignments: h.RoomAssignments,\n\t\t\tremoteCfg:             &h.remoteClientConfig,\n\t\t\ttlsCfg:                tlsCfg,\n\t\t\ttimeout:               time.Duration(h.Timeout),\n\t\t\tlog:                   h.Log,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (h *HueBridge) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, bridge := range h.bridges {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(bridge.process(acc))\n\t\t}()\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"huebridge\", func() telegraf.Input {\n\t\treturn &HueBridge{Timeout: config.Duration(10 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/huebridge/huebridge_test.go",
    "content": "package huebridge\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tdrn-org/go-hue/mock\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"testdata/conf/huebridge.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\th, ok := conf.Inputs[0].Input.(*HueBridge)\n\trequire.True(t, ok)\n\n\t// Verify successful Init\n\trequire.NoError(t, h.Init())\n\n\t// Verify everything is setup according to config file\n\trequire.Len(t, h.BridgeUrls, 4)\n\trequire.Equal(t, \"client\", h.RemoteClientID)\n\trequire.Equal(t, \"secret\", h.RemoteClientSecret)\n\trequire.Equal(t, \"url\", h.RemoteCallbackURL)\n\trequire.Equal(t, \"dir\", h.RemoteTokenDir)\n\trequire.Len(t, h.RoomAssignments, 2)\n\trequire.Equal(t, config.Duration(60*time.Second), h.Timeout)\n\trequire.Equal(t, \"secret\", h.TLSKeyPwd)\n\trequire.True(t, h.InsecureSkipVerify)\n}\n\nfunc TestInitSuccess(t *testing.T) {\n\t// Create plugin instance with all types of URL schemes\n\th := &HueBridge{\n\t\tBridgeUrls: []string{\n\t\t\t\"address://12345678:secret@localhost/\",\n\t\t\t\"cloud://12345678:secret@localhost/discovery/\",\n\t\t\t\"mdns://12345678:secret@/\",\n\t\t\t\"remote://12345678:secret@localhost/\",\n\t\t},\n\t\tremoteClientConfig: remoteClientConfig{\n\t\t\tRemoteClientID:     mock.MockClientId,\n\t\t\tRemoteClientSecret: mock.MockClientSecret,\n\t\t\tRemoteTokenDir:     \".\",\n\t\t},\n\t\tClientConfig: tls.ClientConfig{\n\t\t\tInsecureSkipVerify: true,\n\t\t},\n\t\tTimeout: config.Duration(10 * time.Second),\n\t\tLog:     &testutil.Logger{Name: \"huebridge\"},\n\t}\n\n\t// Verify successful Init\n\trequire.NoError(t, h.Init())\n\n\t// Verify successful configuration of all bridge URLs\n\trequire.Len(t, h.bridges, len(h.BridgeUrls))\n}\n\nfunc TestInitIgnoreInvalidUrls(t *testing.T) {\n\ttests := []struct {\n\t\taddr     string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\taddr:     \"invalid://12345678:secret@invalid-scheme.net/\",\n\t\t\texpected: \"unrecognized scheme\",\n\t\t},\n\t\t{\n\t\t\taddr:     \"address://12345678@missing-password.net/\",\n\t\t\texpected: \"missing password in URL\",\n\t\t},\n\t\t{\n\t\t\taddr:     \"cloud://12345678@missing-password.net/\",\n\t\t\texpected: \"missing password in URL\",\n\t\t},\n\t\t{\n\t\t\taddr:     \"mdns://12345678@missing-password.net/\",\n\t\t\texpected: \"missing password in URL\",\n\t\t},\n\t\t{\n\t\t\taddr:     \"remote://12345678@missing-password.net/\",\n\t\t\texpected: \"missing remote application credentials and/or token director not configured\",\n\t\t},\n\t\t{\n\t\t\taddr:     \"remote://12345678:secret@missing-remote-config.net/\",\n\t\t\texpected: \"missing remote application credentials and/or token director not configured\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.addr, func(t *testing.T) {\n\t\t\t// The following URLs are all invalid must all be ignored during Init\n\t\t\tplugin := &HueBridge{\n\t\t\t\tBridgeUrls: []string{tt.addr},\n\t\t\t\tTimeout:    config.Duration(10 * time.Second),\n\t\t\t\tLog:        &testutil.Logger{Name: \"huebridge\"},\n\t\t\t}\n\n\t\t\t// Verify successful Init\n\t\t\trequire.ErrorContains(t, plugin.Init(), tt.expected)\n\n\t\t\t// Verify no bridge have been configured\n\t\t\trequire.Empty(t, plugin.bridges)\n\t\t})\n\t}\n}\n\nfunc TestGatherLocal(t *testing.T) {\n\t// Load the expected metrics\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tfn := filepath.Join(\"testdata\", \"metrics\", \"huebridge.txt\")\n\texpected, err := testutil.ParseMetricsFromFile(fn, parser)\n\trequire.NoError(t, err)\n\tfor i := range expected {\n\t\texpected[i].SetType(telegraf.Gauge)\n\t}\n\n\t// Start mock server and make plugin targing it\n\tbridgeMock := mock.Start()\n\trequire.NotNil(t, bridgeMock)\n\tdefer bridgeMock.Shutdown()\n\n\t// Setup the plugin\n\th := &HueBridge{\n\t\tBridgeUrls: []string{\n\t\t\tfmt.Sprintf(\"address://%s:%s@%s/\", mock.MockBridgeId, mock.MockBridgeUsername, bridgeMock.Server().Host),\n\t\t},\n\t\tRoomAssignments: map[string]string{\"Name#7\": \"Name#15\"},\n\t\tTimeout:         config.Duration(10 * time.Second),\n\t\tLog:             &testutil.Logger{Name: \"huebridge\"},\n\t}\n\trequire.NoError(t, h.Init())\n\n\t// Verify successfull collection\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(h.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/huebridge/sample.conf",
    "content": "# Gather smart home status from Hue Bridge\n[[inputs.huebridge]]\n  ## URL of bridges to query in the form <scheme>://<bridge id>:<user name>@<address>/\n  ## See documentation for available schemes.\n  bridges = [ \"address://<bridge id>:<user name>@<bridge hostname or address>/\" ]\n  \n  ## Manual device to room assignments to apply during status evaluation.\n  ## E.g. for motion sensors which are reported without a room assignment.\n  # room_assignments = { \"Motion sensor 1\" = \"Living room\", \"Motion sensor 2\" = \"Corridor\" }\n  \n  ## Timeout for gathering information\n  # timeout = \"10s\"\n  \n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  # tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false"
  },
  {
    "path": "plugins/inputs/huebridge/testdata/conf/huebridge.conf",
    "content": "# Gather smart home status from Hue Bridge\n[[inputs.huebridge]]\n  ## The Hue bridges to query.\n  ## See README file for all addressing options.\n  bridges = [\n    \"address://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@mybridgenameorip/\",\n    \"cloud://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@discovery.meethue.com/\",\n    \"mdns://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@/\",\n    \"remote://0123456789ABCDEF:sFlEGnMAFXO6RtZV17aViNUB95G2uXWw64texDzD@api.meethue.com/\",\n  ]\n  \n  remote_client_id = \"client\"\n  remote_client_secret = \"secret\"\n  remote_callback_url = \"url\"\n  remote_token_dir = \"dir\"\n  \n  ## Manual device to room assignments to apply during status evaluation.\n  ## E.g. for motion sensors which are reported without a room assignment.\n  room_assignments = { \"Device 1\" = \"Room A\", \"Device 2\" = \"Room B\" }\n  \n  ## Timeout for gathering information\n  timeout = \"1m\"\n  \n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  tls_key_pwd = \"secret\"\n  ## Use TLS but skip chain & host verification\n  insecure_skip_verify = true"
  },
  {
    "path": "plugins/inputs/huebridge/testdata/metrics/huebridge.txt",
    "content": "huebridge_light,bridge_id=0123456789ABCDEF,device=Name#3,room=Name#15 on=0i 1737181537879611000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#8,room=Name#14 on=0i 1737181537879628000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#12,room=Name#16 on=0i 1737181537879632000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#6,room=Name#13 on=0i 1737181537879634000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#1,room=Name#13 on=0i 1737181537879635000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#2,room=Name#13 on=0i 1737181537879637000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#5,room=Name#15 on=0i 1737181537879639000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#9,room=Name#13 on=0i 1737181537879640000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#11,room=Name#15 on=0i 1737181537879642000\nhuebridge_light,bridge_id=0123456789ABCDEF,device=Name#4,room=Name#14 on=0i 1737181537879646000\nhuebridge_temperature,bridge_id=0123456789ABCDEF,device=Name#7,enabled=true,room=Name#15 temperature=17.6299991607666 1737181537879828000\nhuebridge_light_level,bridge_id=0123456789ABCDEF,device=Name#7,enabled=true,room=Name#15 light_level=18948i,light_level_lux=78.46934003526889 1737181537880034000\nhuebridge_motion_sensor,bridge_id=0123456789ABCDEF,device=Name#7,enabled=true,room=Name#15 motion=0i 1737181537880213000\nhuebridge_device_power,bridge_id=0123456789ABCDEF,device=Name#7,room=Name#15 battery_level=100i 1737181537880360000\n"
  },
  {
    "path": "plugins/inputs/hugepages/README.md",
    "content": "# Hugepages Input Plugin\n\nThis plugin gathers metrics from the Linux'\n[Transparent Huge Pages (THP) memory management system][hugetlb] that reduces\nthe overhead of Translation Lookaside Buffer (TLB) lookups on machines with\nlarge amounts of memory.\n\n⭐ Telegraf v1.22.0\n🏷️ system\n💻 linux\n\n[hugetlb]: https://www.kernel.org/doc/html/latest/admin-guide/mm/hugetlbpage.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gathers huge pages measurements.\n# This plugin ONLY supports Linux\n[[inputs.hugepages]]\n  ## Supported huge page types:\n  ##   - \"root\"     - based on root huge page control directory:\n  ##                  /sys/kernel/mm/hugepages\n  ##   - \"per_node\" - based on per NUMA node directories:\n  ##                  /sys/devices/system/node/node[0-9]*/hugepages\n  ##   - \"meminfo\"  - based on /proc/meminfo file\n  # types = [\"root\", \"per_node\"]\n```\n\n## Metrics\n\n### Measurements\n\n**The following measurements are supported by Hugepages plugin:**\n\n- hugepages_root (gathered from `/sys/kernel/mm/hugepages`)\n  - tags:\n    - size_kb (integer, kB)\n  - fields:\n    - free (integer)\n    - mempolicy (integer)\n    - overcommit (integer)\n    - reserved (integer)\n    - surplus (integer)\n    - total (integer)\n- hugepages_per_node (gathered from `/sys/devices/system/node/node[0-9]*/hugepages`)\n  - tags:\n    - size_kb (integer, kB)\n    - node (integer)\n  - fields:\n    - free (integer)\n    - surplus (integer)\n    - total (integer)\n- hugepages_meminfo (gathered from `/proc/meminfo` file)\n  - The fields `total`, `free`, `reserved`, and `surplus` are counts of pages\n    of default size. Fields with suffix `_kb` are in kilobytes.\n  - fields:\n    - anonymous_kb (integer, kB)\n    - file_kb (integer, kB)\n    - free (integer)\n    - reserved (integer)\n    - shared_kb (integer, kB)\n    - size_kb (integer, kB)\n    - surplus (integer)\n    - tlb_kb (integer, kB)\n    - total (integer)\n\n## Example Output\n\n```text\nhugepages_root,host=ubuntu,size_kb=1048576 free=0i,mempolicy=8i,overcommit=0i,reserved=0i,surplus=0i,total=8i 1646258020000000000\nhugepages_root,host=ubuntu,size_kb=2048 free=883i,mempolicy=2048i,overcommit=0i,reserved=0i,surplus=0i,total=2048i 1646258020000000000\nhugepages_per_node,host=ubuntu,size_kb=1048576,node=0 free=0i,surplus=0i,total=4i 1646258020000000000\nhugepages_per_node,host=ubuntu,size_kb=2048,node=0 free=434i,surplus=0i,total=1024i 1646258020000000000\nhugepages_per_node,host=ubuntu,size_kb=1048576,node=1 free=0i,surplus=0i,total=4i 1646258020000000000\nhugepages_per_node,host=ubuntu,size_kb=2048,node=1 free=449i,surplus=0i,total=1024i 1646258020000000000\nhugepages_meminfo,host=ubuntu anonymous_kb=0i,file_kb=0i,free=883i,reserved=0i,shared_kb=0i,size_kb=2048i,surplus=0i,tlb_kb=12582912i,total=2048i 1646258020000000000\n```\n"
  },
  {
    "path": "plugins/inputs/hugepages/hugepages.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage hugepages\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tnewlineByte = []byte(\"\\n\")\n\tcolonByte   = []byte(\":\")\n\n\thugepagesMetricsRoot = map[string]string{\n\t\t\"free_hugepages\":          \"free\",\n\t\t\"nr_hugepages\":            \"total\",\n\t\t\"nr_hugepages_mempolicy\":  \"mempolicy\",\n\t\t\"nr_overcommit_hugepages\": \"overcommit\",\n\t\t\"resv_hugepages\":          \"reserved\",\n\t\t\"surplus_hugepages\":       \"surplus\",\n\t}\n\n\thugepagesMetricsPerNUMANode = map[string]string{\n\t\t\"free_hugepages\":    \"free\",\n\t\t\"nr_hugepages\":      \"total\",\n\t\t\"surplus_hugepages\": \"surplus\",\n\t}\n\n\thugepagesMetricsFromMeminfo = map[string]string{\n\t\t\"HugePages_Total\": \"total\",\n\t\t\"HugePages_Free\":  \"free\",\n\t\t\"HugePages_Rsvd\":  \"reserved\",\n\t\t\"HugePages_Surp\":  \"surplus\",\n\t\t\"Hugepagesize\":    \"size_kb\",\n\t\t\"Hugetlb\":         \"tlb_kb\",\n\t\t\"AnonHugePages\":   \"anonymous_kb\",\n\t\t\"ShmemHugePages\":  \"shared_kb\",\n\t\t\"FileHugePages\":   \"file_kb\",\n\t}\n)\n\nconst (\n\t// path to root huge page control directory\n\trootHugepagePath = \"/sys/kernel/mm/hugepages\"\n\t// path where per NUMA node statistics are kept\n\tnumaNodePath = \"/sys/devices/system/node\"\n\t// path to the meminfo file\n\tmeminfoPath = \"/proc/meminfo\"\n\n\trootHugepages    = \"root\"\n\tperNodeHugepages = \"per_node\"\n\tmeminfoHugepages = \"meminfo\"\n)\n\ntype Hugepages struct {\n\tTypes []string `toml:\"types\"`\n\n\tgatherRoot    bool\n\tgatherPerNode bool\n\tgatherMeminfo bool\n\n\trootHugepagePath string\n\tnumaNodePath     string\n\tmeminfoPath      string\n}\n\nfunc (*Hugepages) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *Hugepages) Init() error {\n\terr := h.parseHugepagesConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\th.rootHugepagePath = rootHugepagePath\n\th.numaNodePath = numaNodePath\n\th.meminfoPath = meminfoPath\n\n\treturn nil\n}\n\nfunc (h *Hugepages) Gather(acc telegraf.Accumulator) error {\n\tif h.gatherRoot {\n\t\tif err := h.gatherRootStats(acc); err != nil {\n\t\t\treturn fmt.Errorf(\"gathering root stats failed: %w\", err)\n\t\t}\n\t}\n\n\tif h.gatherPerNode {\n\t\tif err := h.gatherStatsPerNode(acc); err != nil {\n\t\t\treturn fmt.Errorf(\"gathering per node stats failed: %w\", err)\n\t\t}\n\t}\n\n\tif h.gatherMeminfo {\n\t\tif err := h.gatherStatsFromMeminfo(acc); err != nil {\n\t\t\treturn fmt.Errorf(\"gathering meminfo stats failed: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// gatherStatsPerNode collects root hugepages statistics\nfunc (h *Hugepages) gatherRootStats(acc telegraf.Accumulator) error {\n\treturn gatherFromHugepagePath(acc, \"hugepages_\"+rootHugepages, h.rootHugepagePath, hugepagesMetricsRoot, nil)\n}\n\n// gatherStatsPerNode collects hugepages statistics per NUMA node\nfunc (h *Hugepages) gatherStatsPerNode(acc telegraf.Accumulator) error {\n\tnodeDirs, err := os.ReadDir(h.numaNodePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// read metrics from: node*/hugepages/hugepages-*/*\n\tfor _, nodeDir := range nodeDirs {\n\t\tif !nodeDir.IsDir() || !strings.HasPrefix(nodeDir.Name(), \"node\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tnodeNumber := strings.TrimPrefix(nodeDir.Name(), \"node\")\n\t\t_, err := strconv.Atoi(nodeNumber)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tperNodeTags := map[string]string{\n\t\t\t\"node\": nodeNumber,\n\t\t}\n\t\thugepagesPath := filepath.Join(h.numaNodePath, nodeDir.Name(), \"hugepages\")\n\t\terr = gatherFromHugepagePath(acc, \"hugepages_\"+perNodeHugepages, hugepagesPath, hugepagesMetricsPerNUMANode, perNodeTags)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc gatherFromHugepagePath(acc telegraf.Accumulator, measurement, path string, fileFilter, defaultTags map[string]string) error {\n\t// read metrics from: hugepages/hugepages-*/*\n\thugepagesDirs, err := os.ReadDir(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading root dir failed: %w\", err)\n\t}\n\n\tfor _, hugepagesDir := range hugepagesDirs {\n\t\tif !hugepagesDir.IsDir() || !strings.HasPrefix(hugepagesDir.Name(), \"hugepages-\") {\n\t\t\tcontinue\n\t\t}\n\n\t\thugepagesSize := strings.TrimPrefix(strings.TrimSuffix(hugepagesDir.Name(), \"kB\"), \"hugepages-\")\n\t\t_, err := strconv.Atoi(hugepagesSize)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tmetricsPath := filepath.Join(path, hugepagesDir.Name())\n\t\tmetricFiles, err := os.ReadDir(metricsPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading metric dir failed: %w\", err)\n\t\t}\n\n\t\tmetrics := make(map[string]interface{})\n\t\tfor _, metricFile := range metricFiles {\n\t\t\tmetricName, ok := fileFilter[metricFile.Name()]\n\t\t\tif mode := metricFile.Type(); !mode.IsRegular() || !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmetricFullPath := filepath.Join(metricsPath, metricFile.Name())\n\t\t\tmetricBytes, err := os.ReadFile(metricFullPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tmetricValue, err := strconv.Atoi(string(bytes.TrimSuffix(metricBytes, newlineByte)))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to convert content of %q: %w\", metricFullPath, err)\n\t\t\t}\n\n\t\t\tmetrics[metricName] = metricValue\n\t\t}\n\n\t\tif len(metrics) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := make(map[string]string)\n\t\tfor key, value := range defaultTags {\n\t\t\ttags[key] = value\n\t\t}\n\t\ttags[\"size_kb\"] = hugepagesSize\n\n\t\tacc.AddFields(measurement, metrics, tags)\n\t}\n\treturn nil\n}\n\n// gatherStatsFromMeminfo collects hugepages statistics from meminfo file\nfunc (h *Hugepages) gatherStatsFromMeminfo(acc telegraf.Accumulator) error {\n\tmeminfo, err := os.ReadFile(h.meminfoPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmetrics := make(map[string]interface{})\n\tlines := bytes.Split(meminfo, newlineByte)\n\tfor _, line := range lines {\n\t\tfields := bytes.Fields(line)\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tfieldName := string(bytes.TrimSuffix(fields[0], colonByte))\n\t\tmetricName, ok := hugepagesMetricsFromMeminfo[fieldName]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tfieldValue, err := strconv.Atoi(string(fields[1]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to convert content of %q: %w\", fieldName, err)\n\t\t}\n\n\t\tmetrics[metricName] = fieldValue\n\t}\n\n\tacc.AddFields(\"hugepages_\"+meminfoHugepages, metrics, make(map[string]string))\n\treturn nil\n}\n\nfunc (h *Hugepages) parseHugepagesConfig() error {\n\t// default\n\tif h.Types == nil {\n\t\th.gatherRoot = true\n\t\th.gatherMeminfo = true\n\t\treturn nil\n\t}\n\n\t// empty array\n\tif len(h.Types) == 0 {\n\t\treturn errors.New(\"plugin was configured with nothing to read\")\n\t}\n\n\tfor _, hugepagesType := range h.Types {\n\t\tswitch hugepagesType {\n\t\tcase rootHugepages:\n\t\t\th.gatherRoot = true\n\t\tcase perNodeHugepages:\n\t\t\th.gatherPerNode = true\n\t\tcase meminfoHugepages:\n\t\t\th.gatherMeminfo = true\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"provided hugepages type %q is not valid\", hugepagesType)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"hugepages\", func() telegraf.Input {\n\t\treturn &Hugepages{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/hugepages/hugepages_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage hugepages\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Hugepages struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Hugepages) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *Hugepages) Init() error {\n\th.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Hugepages) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"hugepages\", func() telegraf.Input {\n\t\treturn &Hugepages{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/hugepages/hugepages_test.go",
    "content": "//go:build linux\n\npackage hugepages\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInit(t *testing.T) {\n\tt.Run(\"when no config is provided then all fields should be set to default values\", func(t *testing.T) {\n\t\th := Hugepages{}\n\t\terr := h.Init()\n\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, h.gatherRoot)\n\t\trequire.False(t, h.gatherPerNode)\n\t\trequire.True(t, h.gatherMeminfo)\n\t\trequire.Equal(t, rootHugepagePath, h.rootHugepagePath)\n\t\trequire.Equal(t, numaNodePath, h.numaNodePath)\n\t\trequire.Equal(t, meminfoPath, h.meminfoPath)\n\t})\n\n\tt.Run(\"when empty hugepages types is provided then plugin should fail to initialize\", func(t *testing.T) {\n\t\th := Hugepages{Types: make([]string, 0)}\n\t\terr := h.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"plugin was configured with nothing to read\")\n\t})\n\n\tt.Run(\"when valid hugepages types is provided then proper flags should be set\", func(t *testing.T) {\n\t\th := Hugepages{Types: []string{\"root\", \"per_node\", \"meminfo\"}}\n\t\terr := h.Init()\n\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, h.gatherRoot)\n\t\trequire.True(t, h.gatherPerNode)\n\t\trequire.True(t, h.gatherMeminfo)\n\t})\n\n\tt.Run(\"when hugepages types contains not supported value then plugin should fail to initialize\", func(t *testing.T) {\n\t\th := Hugepages{Types: []string{\"root\", \"per_node\", \"linux_hdd\", \"meminfo\"}}\n\t\terr := h.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided hugepages type\")\n\t})\n}\n\nfunc TestGather(t *testing.T) {\n\tt.Run(\"when root hugepages type is enabled then gather all root metrics successfully\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\trootHugepagePath: \"./testdata/valid/mm/hugepages\",\n\t\t\tgatherRoot:       true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, h.Gather(acc))\n\n\t\texpectedFields := map[string]interface{}{\n\t\t\t\"free\":       883,\n\t\t\t\"reserved\":   0,\n\t\t\t\"surplus\":    0,\n\t\t\t\"mempolicy\":  2048,\n\t\t\t\"total\":      2048,\n\t\t\t\"overcommit\": 0,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_root\", expectedFields, map[string]string{\"size_kb\": \"2048\"})\n\n\t\texpectedFields = map[string]interface{}{\n\t\t\t\"free\":       0,\n\t\t\t\"reserved\":   0,\n\t\t\t\"surplus\":    0,\n\t\t\t\"mempolicy\":  8,\n\t\t\t\"total\":      8,\n\t\t\t\"overcommit\": 0,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_root\", expectedFields, map[string]string{\"size_kb\": \"1048576\"})\n\t})\n\n\tt.Run(\"when per node hugepages type is enabled then gather all per node metrics successfully\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tnumaNodePath:  \"./testdata/valid/node\",\n\t\t\tgatherPerNode: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, h.Gather(acc))\n\n\t\texpectedFields := map[string]interface{}{\n\t\t\t\"free\":    434,\n\t\t\t\"surplus\": 0,\n\t\t\t\"total\":   1024,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_per_node\", expectedFields, map[string]string{\"size_kb\": \"2048\", \"node\": \"0\"})\n\n\t\texpectedFields = map[string]interface{}{\n\t\t\t\"free\":    449,\n\t\t\t\"surplus\": 0,\n\t\t\t\"total\":   1024,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_per_node\", expectedFields, map[string]string{\"size_kb\": \"2048\", \"node\": \"1\"})\n\n\t\texpectedFields = map[string]interface{}{\n\t\t\t\"free\":    0,\n\t\t\t\"surplus\": 0,\n\t\t\t\"total\":   4,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_per_node\", expectedFields, map[string]string{\"size_kb\": \"1048576\", \"node\": \"0\"})\n\n\t\texpectedFields = map[string]interface{}{\n\t\t\t\"free\":    0,\n\t\t\t\"surplus\": 0,\n\t\t\t\"total\":   4,\n\t\t}\n\t\tacc.AssertContainsTaggedFields(t, \"hugepages_per_node\", expectedFields, map[string]string{\"size_kb\": \"1048576\", \"node\": \"1\"})\n\t})\n\n\tt.Run(\"when meminfo hugepages type is enabled then gather all meminfo metrics successfully\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tmeminfoPath:   \"./testdata/valid/meminfo\",\n\t\t\tgatherMeminfo: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, h.Gather(acc))\n\n\t\texpectedFields := map[string]interface{}{\n\t\t\t\"anonymous_kb\": 0,\n\t\t\t\"shared_kb\":    0,\n\t\t\t\"file_kb\":      0,\n\t\t\t\"total\":        2048,\n\t\t\t\"free\":         883,\n\t\t\t\"reserved\":     0,\n\t\t\t\"surplus\":      0,\n\t\t\t\"size_kb\":      2048,\n\t\t\t\"tlb_kb\":       12582912,\n\t\t}\n\t\tacc.AssertContainsFields(t, \"hugepages_meminfo\", expectedFields)\n\t})\n\n\tt.Run(\"when root hugepages type is enabled but path is invalid then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\trootHugepagePath: \"./testdata/not_existing_path\",\n\t\t\tgatherRoot:       true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n\n\tt.Run(\"when root hugepages type is enabled but files/directories don't have proper naming then gather no metrics\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\trootHugepagePath: \"./testdata/invalid/1/node0/hugepages\",\n\t\t\tgatherRoot:       true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, h.Gather(acc))\n\t\trequire.Nil(t, acc.Metrics)\n\t})\n\n\tt.Run(\"when root hugepages type is enabled but metric file doesn't contain number then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\trootHugepagePath: \"./testdata/invalid/2/node1/hugepages\",\n\t\t\tgatherRoot:       true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n\n\tt.Run(\"when per node hugepages type is enabled but path is invalid then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tnumaNodePath:  \"./testdata/not_existing_path\",\n\t\t\tgatherPerNode: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n\n\tt.Run(\"when per node hugepages type is enabled but files/directories don't have proper naming then gather no metrics\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tnumaNodePath:  \"./testdata/invalid/1\",\n\t\t\tgatherPerNode: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, h.Gather(acc))\n\t\trequire.Nil(t, acc.Metrics)\n\t})\n\n\tt.Run(\"when per node hugepages type is enabled but metric file doesn't contain number then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tnumaNodePath:  \"./testdata/invalid/2/\",\n\t\t\tgatherPerNode: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n\n\tt.Run(\"when meminfo hugepages type is enabled but path is invalid then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tmeminfoPath:   \"./testdata/not_existing_path\",\n\t\t\tgatherMeminfo: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n\n\tt.Run(\"when per node hugepages type is enabled but any metric doesn't contain number then return error\", func(t *testing.T) {\n\t\th := Hugepages{\n\t\t\tmeminfoPath:   \"./testdata/invalid/meminfo\",\n\t\t\tgatherMeminfo: true,\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.Error(t, h.Gather(acc))\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/hugepages/sample.conf",
    "content": "# Gathers huge pages measurements.\n# This plugin ONLY supports Linux\n[[inputs.hugepages]]\n  ## Supported huge page types:\n  ##   - \"root\"     - based on root huge page control directory:\n  ##                  /sys/kernel/mm/hugepages\n  ##   - \"per_node\" - based on per NUMA node directories:\n  ##                  /sys/devices/system/node/node[0-9]*/hugepages\n  ##   - \"meminfo\"  - based on /proc/meminfo file\n  # types = [\"root\", \"per_node\"]\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/anode3/dir_lock",
    "content": ""
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-1048576kB/free_hugepages/dir_lock",
    "content": ""
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-1048576kB/nry_hugepages",
    "content": "240\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-2048kB",
    "content": ""
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-aaaa1048576kB/free_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages1048576kB/free_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node1",
    "content": "whatever"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/1/node4b/dir_lock",
    "content": ""
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/2/node1/hugepages/hugepages-1048576kB/nr_hugepages",
    "content": "forty two"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/invalid/meminfo",
    "content": "AnonHugePages:         0 kB\nShmemHugePages:        0 kB\nHugePages_Total:    2048\nHugePages_Free:      sixtynine\nHugePages_Rsvd:        0\nHugePages_Surp:        0\nHugepagesize:       2048 kB\nHugetlb:        12582912 kB\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/meminfo",
    "content": "MemTotal:       264026876 kB\nMemFree:        260102944 kB\nMemAvailable:   260015468 kB\nBuffers:          115268 kB\nCached:          1203416 kB\nSwapCached:            0 kB\nActive:           599752 kB\nInactive:         950072 kB\nActive(anon):       2740 kB\nInactive(anon):   224176 kB\nActive(file):     597012 kB\nInactive(file):   725896 kB\nUnevictable:           0 kB\nMlocked:               0 kB\nSwapTotal:       8388604 kB\nSwapFree:        8388604 kB\nDirty:                 0 kB\nWriteback:             0 kB\nAnonPages:        231220 kB\nMapped:           317748 kB\nShmem:              5848 kB\nKReclaimable:     170796 kB\nSlab:             347860 kB\nSReclaimable:     170796 kB\nSUnreclaim:       177064 kB\nKernelStack:       13776 kB\nPageTables:        10756 kB\nNFS_Unstable:          0 kB\nBounce:                0 kB\nWritebackTmp:          0 kB\nCommitLimit:    140139896 kB\nCommitted_AS:    2661568 kB\nVmallocTotal:   34359738367 kB\nVmallocUsed:      264276 kB\nVmallocChunk:          0 kB\nPercpu:            40896 kB\nHardwareCorrupted:     0 kB\nAnonHugePages:         0 kB\nShmemHugePages:        0 kB\nShmemPmdMapped:        0 kB\nFileHugePages:         0 kB\nFilePmdMapped:         0 kB\nHugePages_Total:    2048\nHugePages_Free:      883\nHugePages_Rsvd:        0\nHugePages_Surp:        0\nHugepagesize:       2048 kB\nHugetlb:        12582912 kB\nDirectMap4k:      312056 kB\nDirectMap2M:     6930432 kB\nDirectMap1G:    263192576 kB\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/free_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_hugepages",
    "content": "8\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_hugepages_mempolicy",
    "content": "8\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_overcommit_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/resv_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/free_hugepages",
    "content": "883\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_hugepages",
    "content": "2048\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_hugepages_mempolicy",
    "content": "2048\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_overcommit_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/resv_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/free_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/nr_hugepages",
    "content": "4\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/free_hugepages",
    "content": "434\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/nr_hugepages",
    "content": "1024\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/free_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/nr_hugepages",
    "content": "4\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/free_hugepages",
    "content": "449\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/nr_hugepages",
    "content": "1024\n"
  },
  {
    "path": "plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/surplus_hugepages",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/icinga2/README.md",
    "content": "# Icinga2 Input Plugin\n\nThis plugin gather services and hosts status information using the\n[Icinga2 remote API][remote_api].\n\n⭐ Telegraf v1.8.0\n🏷️ network, server, system\n💻 all\n\n[remote_api]: https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/icinga2-api\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather Icinga2 status\n[[inputs.icinga2]]\n  ## Required Icinga2 server address\n  # server = \"https://localhost:5665\"\n\n  ## Collected Icinga2 objects (\"services\", \"hosts\")\n  ## Specify at least one object to collect from /v1/objects endpoint.\n  # objects = [\"services\"]\n\n  ## Collect metrics from /v1/status endpoint\n  ## Choose from:\n  ##     \"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"\n  # status = []\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n```\n\n## Metrics\n\n- `icinga2_hosts`\n  - tags\n    - `check_command` - The short name of the check command\n    - `display_name` - The name of the host\n    - `state` - The state: UP/DOWN\n    - `source` - The icinga2 host\n    - `port` - The icinga2 port\n    - `scheme` - The icinga2 protocol (http/https)\n    - `server` - The server the check_command is running for\n  - fields\n    - `name` (string)\n    - `state_code` (int)\n- `icinga2_services`\n  - tags\n    - `check_command` - The short name of the check command\n    - `display_name` - The name of the service\n    - `state` - The state: OK/WARNING/CRITICAL/UNKNOWN for services\n    - `source` - The icinga2 host\n    - `port` - The icinga2 port\n    - `scheme` - The icinga2 protocol (http/https)\n    - `server` - The server the check_command is running for\n  - fields\n    - `name` (string)\n    - `state_code` (int)\n- `icinga2_status`\n  - component:\n    - `ApiListener`\n      - tags\n        - `component` name\n      - fields\n        - `api_num_conn_endpoints`\n        - `api_num_endpoint`\n        - `api_num_http_clients`\n        - `api_num_json_rpc_anonymous_clients`\n        - `api_num_json_rpc_relay_queue_item_rate`\n        - `api_num_json_rpc_relay_queue_items`\n        - `api_num_json_rpc_sync_queue_item_rate`\n        - `api_num_json_rpc_sync_queue_items`\n        - `api_num_json_rpc_work_queue_item_rate`\n        - `api_num_not_conn_endpoints`\n    - `CIB`\n      - tags\n        - `component` name\n      - fields\n        - `active_host_checks`\n        - `active_host_checks_15min`\n        - `active_host_checks_1min`\n        - `active_host_checks_5min`\n        - `active_service_checks`\n        - `active_service_checks_15min`\n        - `active_service_checks_1min`\n        - `active_service_checks_5min`\n        - `avg_execution_time`\n        - `avg_latency`\n        - `current_concurrent_checks`\n        - `current_pending_callbacks`\n        - `max_execution_time`\n        - `max_latency`\n        - `min_execution_time`\n        - `min_latency`\n        - `num_hosts_acknowledged`\n        - `num_hosts_down`\n        - `num_hosts_flapping`\n        - `num_hosts_handled`\n        - `num_hosts_in_downtime`\n        - `num_hosts_pending`\n        - `num_hosts_problem`\n        - `num_hosts_unreachable`\n        - `num_hosts_up`\n        - `num_services_acknowledged`\n        - `num_services_critical`\n        - `num_services_flapping`\n        - `num_services_handled`\n        - `num_services_in_downtime`\n        - `num_services_ok`\n        - `num_services_pending`\n        - `num_services_problem`\n        - `num_services_unknown`\n        - `num_services_unreachable`\n        - `num_services_warning`\n        - `passive_host_checks`\n        - `passive_host_checks_15min`\n        - `passive_host_checks_1min`\n        - `passive_host_checks_5min`\n        - `passive_service_checks`\n        - `passive_service_checks_15min`\n        - `passive_service_checks_1min`\n        - `passive_service_checks_5min`\n        - `remote_check_queue`\n        - `uptime`\n    - `IdoMysqlConnection`\n      - tags\n        - `component` name\n      - fields\n        - `mysql_queries_1min`\n        - `mysql_queries_5mins`\n        - `mysql_queries_15mins`\n        - `mysql_queries_rate`\n        - `mysql_query_queue_item_rate`\n        - `mysql_query_queue_items`\n    - `IdoPgsqlConnection`\n      - tags\n        - `component` name\n      - fields\n        - `pgsql_queries_1min`\n        - `pgsql_queries_5mins`\n        - `pgsql_queries_15mins`\n        - `pgsql_queries_rate`\n        - `pgsql_query_queue_item_rate`\n        - `pgsql_query_queue_items`\n\n## Sample Queries\n\n```sql\nSELECT * FROM \"icinga2_services\" WHERE state_code = 0 AND time > now() - 24h // Service with OK status\nSELECT * FROM \"icinga2_services\" WHERE state_code = 1 AND time > now() - 24h // Service with WARNING status\nSELECT * FROM \"icinga2_services\" WHERE state_code = 2 AND time > now() - 24h // Service with CRITICAL status\nSELECT * FROM \"icinga2_services\" WHERE state_code = 3 AND time > now() - 24h // Service with UNKNOWN status\n```\n\n## Example Output\n\n```text\nicinga2_hosts,display_name=router-fr.eqx.fr,check_command=hostalive-custom,host=test-vm,source=localhost,port=5665,scheme=https,state=ok name=\"router-fr.eqx.fr\",state=0 1492021603000000000\n```\n"
  },
  {
    "path": "plugins/inputs/icinga2/icinga2.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage icinga2\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar levels = []string{\"ok\", \"warning\", \"critical\", \"unknown\"}\n\ntype Icinga2 struct {\n\tServer          string          `toml:\"server\"`\n\tObjects         []string        `toml:\"objects\"`\n\tStatus          []string        `toml:\"status\"`\n\tUsername        string          `toml:\"username\"`\n\tPassword        string          `toml:\"password\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\ttls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient *http.Client\n}\n\ntype resultObject struct {\n\tResults []struct {\n\t\tAttrs struct {\n\t\t\tCheckCommand string  `json:\"check_command\"`\n\t\t\tDisplayName  string  `json:\"display_name\"`\n\t\t\tName         string  `json:\"name\"`\n\t\t\tState        float64 `json:\"state\"`\n\t\t\tHostName     string  `json:\"host_name\"`\n\t\t} `json:\"attrs\"`\n\t\tName  string   `json:\"name\"`\n\t\tJoins struct{} `json:\"joins\"`\n\t\tMeta  struct{} `json:\"meta\"`\n\t\tType  string   `json:\"type\"`\n\t} `json:\"results\"`\n}\n\ntype resultCIB struct {\n\tResults []struct {\n\t\tStatus map[string]interface{} `json:\"status\"`\n\t} `json:\"results\"`\n}\n\ntype resultPerfdata struct {\n\tResults []struct {\n\t\tPerfdata []struct {\n\t\t\tLabel string  `json:\"label\"`\n\t\t\tValue float64 `json:\"value\"`\n\t\t} `json:\"perfdata\"`\n\t} `json:\"results\"`\n}\n\nfunc (*Icinga2) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (i *Icinga2) Init() error {\n\tstatusEndpoints := []string{\"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"}\n\tif err := choice.CheckSlice(i.Status, statusEndpoints); err != nil {\n\t\treturn fmt.Errorf(\"config option 'status': %w\", err)\n\t}\n\n\tif i.ResponseTimeout < config.Duration(time.Second) {\n\t\ti.ResponseTimeout = config.Duration(time.Second * 5)\n\t}\n\n\tclient, err := i.createHTTPClient()\n\tif err != nil {\n\t\treturn err\n\t}\n\ti.client = client\n\n\tobjectEndpoints := []string{\"services\", \"hosts\"}\n\tif err := choice.CheckSlice(i.Objects, objectEndpoints); err != nil {\n\t\treturn fmt.Errorf(\"config option 'objects': %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (i *Icinga2) Gather(acc telegraf.Accumulator) error {\n\t// Collect /v1/objects\n\tfor _, objectType := range i.Objects {\n\t\trequestURL := \"%s/v1/objects/%s?attrs=name&attrs=display_name&attrs=state&attrs=check_command\"\n\n\t\t// Note: attrs=host_name is only valid for 'services' requests, using check.Attrs.HostName for the host\n\t\t//       'hosts' requests will need to use attrs=name only, using check.Attrs.Name for the host\n\t\tif objectType == \"services\" {\n\t\t\trequestURL += \"&attrs=host_name\"\n\t\t}\n\n\t\taddress := fmt.Sprintf(requestURL, i.Server, objectType)\n\n\t\tresp, err := i.icingaRequest(address)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresult := resultObject{}\n\t\terr = parseObjectResponse(resp, &result)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not parse object response: %w\", err)\n\t\t}\n\n\t\ti.gatherObjects(acc, result, objectType)\n\t}\n\n\t// Collect /v1/status\n\tfor _, statusType := range i.Status {\n\t\taddress := fmt.Sprintf(\"%s/v1/status/%s\", i.Server, statusType)\n\n\t\tresp, err := i.icingaRequest(address)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"component\": statusType,\n\t\t}\n\t\tvar fields map[string]interface{}\n\n\t\tswitch statusType {\n\t\tcase \"ApiListener\":\n\t\t\tfields, err = parsePerfdataResponse(resp)\n\t\tcase \"CIB\":\n\t\t\tfields, err = parseCIBResponse(resp)\n\t\tcase \"IdoMysqlConnection\":\n\t\t\tfields, err = parsePerfdataResponse(resp)\n\t\tcase \"IdoPgsqlConnection\":\n\t\t\tfields, err = parsePerfdataResponse(resp)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not parse %s response: %w\", statusType, err)\n\t\t}\n\n\t\tacc.AddFields(\"icinga2_status\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (i *Icinga2) gatherObjects(acc telegraf.Accumulator, checks resultObject, objectType string) {\n\tfor _, check := range checks.Results {\n\t\tserverURL, err := url.Parse(i.Server)\n\t\tif err != nil {\n\t\t\ti.Log.Error(err.Error())\n\t\t\tcontinue\n\t\t}\n\n\t\tstate := int64(check.Attrs.State)\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"name\":       check.Attrs.Name,\n\t\t\t\"state_code\": state,\n\t\t}\n\n\t\t// source is dependent on 'services' or 'hosts' check\n\t\tsource := check.Attrs.Name\n\t\tif objectType == \"services\" {\n\t\t\tsource = check.Attrs.HostName\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"display_name\":  check.Attrs.DisplayName,\n\t\t\t\"check_command\": check.Attrs.CheckCommand,\n\t\t\t\"source\":        source,\n\t\t\t\"state\":         levels[state],\n\t\t\t\"server\":        serverURL.Hostname(),\n\t\t\t\"scheme\":        serverURL.Scheme,\n\t\t\t\"port\":          serverURL.Port(),\n\t\t}\n\n\t\tacc.AddFields(\"icinga2_\"+objectType, fields, tags)\n\t}\n}\n\nfunc (i *Icinga2) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := i.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(i.ResponseTimeout),\n\t}\n\n\treturn client, nil\n}\n\nfunc (i *Icinga2) icingaRequest(address string) (*http.Response, error) {\n\treq, err := http.NewRequest(\"GET\", address, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif i.Username != \"\" {\n\t\treq.SetBasicAuth(i.Username, i.Password)\n\t}\n\n\tresp, err := i.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn resp, nil\n}\n\nfunc parseObjectResponse(resp *http.Response, result *resultObject) error {\n\terr := json.NewDecoder(resp.Body).Decode(&result)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = resp.Body.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc parseCIBResponse(resp *http.Response) (map[string]interface{}, error) {\n\tresult := resultCIB{}\n\n\terr := json.NewDecoder(resp.Body).Decode(&result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif len(result.Results) == 0 {\n\t\treturn nil, errors.New(\"no results in Icinga2 API response\")\n\t}\n\n\treturn result.Results[0].Status, nil\n}\n\nfunc parsePerfdataResponse(resp *http.Response) (map[string]interface{}, error) {\n\tresult := resultPerfdata{}\n\n\terr := json.NewDecoder(resp.Body).Decode(&result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif len(result.Results) == 0 {\n\t\treturn nil, errors.New(\"no results in Icinga2 API response\")\n\t}\n\n\tfields := make(map[string]interface{})\n\tfor _, item := range result.Results[0].Perfdata {\n\t\ti := strings.Index(item.Label, \"-\")\n\t\tif i > 0 {\n\t\t\tfields[item.Label[i+1:]] = item.Value\n\t\t} else {\n\t\t\tfields[item.Label] = item.Value\n\t\t}\n\t}\n\n\treturn fields, nil\n}\n\nfunc init() {\n\tinputs.Add(\"icinga2\", func() telegraf.Input {\n\t\treturn &Icinga2{\n\t\t\tServer:          \"https://localhost:5665\",\n\t\t\tObjects:         []string{\"services\"},\n\t\t\tResponseTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/icinga2/icinga2_test.go",
    "content": "package icinga2\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIcinga2Default(t *testing.T) {\n\t// This test should succeed with the default initialization.\n\ticinga2 := &Icinga2{\n\t\tServer:          \"https://localhost:5665\",\n\t\tObjects:         []string{\"services\"},\n\t\tResponseTimeout: config.Duration(time.Second * 5),\n\t}\n\trequire.NoError(t, icinga2.Init())\n\n\trequire.Equal(t, config.Duration(5*time.Second), icinga2.ResponseTimeout)\n\trequire.Equal(t, \"https://localhost:5665\", icinga2.Server)\n\trequire.Equal(t, []string{\"services\"}, icinga2.Objects)\n}\n\nconst icinga2ServiceResponse = `{\n\t\"results\": [\n\t\t{\n\t\t\t\"attrs\": {\n\t\t\t\t\"check_command\": \"check-bgp-juniper-netconf\",\n\t\t\t\t\"display_name\": \"eq-par.dc2.fr\",\n\t\t\t\t\"host_name\": \"someserverfqdn.net\",\n\t\t\t\t\"name\": \"ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe\",\n\t\t\t\t\"state\": 0\n\t\t\t},\n\t\t\t\"joins\": {},\n\t\t\t\"meta\": {},\n\t\t\t\"name\": \"eq-par.dc2.fr!ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe\",\n\t\t\t\"type\": \"Service\"\n\t\t}\n\t]\n}`\n\nfunc TestGatherServicesStatus(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/v1/objects/services\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tif _, err := w.Write([]byte(icinga2ServiceResponse)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tt.Logf(\"Req: %s %s\\n\", r.Host, r.URL.Path)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tvar icinga2 = &Icinga2{\n\t\tServer:  ts.URL,\n\t\tObjects: []string{\"services\"},\n\t}\n\trequire.NoError(t, icinga2.Init())\n\tvar acc testutil.Accumulator\n\terr := icinga2.Gather(&acc)\n\trequire.NoError(t, err)\n\n\trequestURL, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"name\":       \"ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe\",\n\t\t\"state_code\": int64(0),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"display_name\":  \"eq-par.dc2.fr\",\n\t\t\"check_command\": \"check-bgp-juniper-netconf\",\n\t\t\"state\":         \"ok\",\n\t\t\"source\":        \"someserverfqdn.net\",\n\t\t\"server\":        requestURL.Hostname(),\n\t\t\"port\":          requestURL.Port(),\n\t\t\"scheme\":        \"http\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"icinga2_services\", expectedFields, expectedTags)\n}\n\nconst icinga2HostResponse = `{\n\t\"results\": [\n\t\t{\n\t\t\t\"attrs\": {\n\t\t\t\t\"address\": \"192.168.1.1\",\n\t\t\t\t\"check_command\": \"ping\",\n\t\t\t\t\"display_name\": \"apache\",\n\t\t\t\t\"name\": \"webserver\",\n\t\t\t\t\"state\": 2.0\n\t\t\t},\n\t\t\t\"joins\": {},\n\t\t\t\"meta\": {},\n\t\t\t\"name\": \"webserver\",\n\t\t\t\"type\": \"Host\"\n\t\t}\n\t]\n}\n`\n\nfunc TestGatherHostsStatus(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/v1/objects/hosts\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tif _, err := w.Write([]byte(icinga2HostResponse)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tt.Logf(\"Req: %s %s\\n\", r.Host, r.URL.Path)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tvar icinga2 = &Icinga2{\n\t\tServer:  ts.URL,\n\t\tObjects: []string{\"hosts\"},\n\t}\n\trequire.NoError(t, icinga2.Init())\n\n\trequestURL, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = icinga2.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"name\":       \"webserver\",\n\t\t\"state_code\": int64(2),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"display_name\":  \"apache\",\n\t\t\"check_command\": \"ping\",\n\t\t\"state\":         \"critical\",\n\t\t\"source\":        \"webserver\",\n\t\t\"server\":        requestURL.Hostname(),\n\t\t\"port\":          requestURL.Port(),\n\t\t\"scheme\":        \"http\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"icinga2_hosts\", expectedFields, expectedTags)\n}\n\nconst icinga2StatusCIB = `{\n  \"results\": [\n    {\n      \"name\": \"CIB\",\n      \"perfdata\": [],\n      \"status\": {\n        \"active_host_checks\": 3.6,\n        \"avg_latency\": 2.187678621145969e-06,\n        \"max_latency\": 0.001603841781616211\n      }\n    }\n  ]\n}`\n\nfunc TestGatherStatusCIB(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/v1/status/CIB\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tif _, err := w.Write([]byte(icinga2StatusCIB)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tt.Logf(\"Req: %s %s\\n\", r.Host, r.URL.Path)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tvar icinga2 = &Icinga2{\n\t\tServer: ts.URL,\n\t\tStatus: []string{\"CIB\"},\n\t}\n\trequire.NoError(t, icinga2.Init())\n\n\tvar acc testutil.Accumulator\n\terr := icinga2.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"active_host_checks\": float64(3.6),\n\t\t\"avg_latency\":        float64(2.187678621145969e-06),\n\t\t\"max_latency\":        float64(0.001603841781616211),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"component\": \"CIB\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"icinga2_status\", expectedFields, expectedTags)\n}\n\nconst icinga2StatusPgsql = `{\n  \"results\": [\n    {\n      \"name\": \"IdoPgsqlConnection\",\n      \"perfdata\": [\n        {\n          \"counter\": false,\n          \"crit\": null,\n          \"label\": \"idopgsqlconnection_ido-pgsql_queries_rate\",\n          \"max\": null,\n          \"min\": null,\n          \"type\": \"PerfdataValue\",\n          \"unit\": \"\",\n          \"value\": 649.8666666666667,\n          \"warn\": null\n        },\n        {\n          \"counter\": false,\n          \"crit\": null,\n          \"label\": \"idopgsqlconnection_ido-pgsql_query_queue_item_rate\",\n          \"max\": null,\n          \"min\": null,\n          \"type\": \"PerfdataValue\",\n          \"unit\": \"\",\n          \"value\": 1295.1166666666666,\n          \"warn\": null\n        }\n      ]\n    }\n  ]\n}\n`\n\nfunc TestGatherStatusPgsql(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/v1/status/IdoPgsqlConnection\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tif _, err := w.Write([]byte(icinga2StatusPgsql)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tt.Logf(\"Req: %s %s\\n\", r.Host, r.URL.Path)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tvar icinga2 = &Icinga2{\n\t\tServer: ts.URL,\n\t\tStatus: []string{\"IdoPgsqlConnection\"},\n\t}\n\trequire.NoError(t, icinga2.Init())\n\n\tvar acc testutil.Accumulator\n\terr := icinga2.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpectedFields := map[string]interface{}{\n\t\t\"pgsql_queries_rate\":          float64(649.8666666666667),\n\t\t\"pgsql_query_queue_item_rate\": float64(1295.1166666666666),\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"component\": \"IdoPgsqlConnection\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"icinga2_status\", expectedFields, expectedTags)\n}\n"
  },
  {
    "path": "plugins/inputs/icinga2/sample.conf",
    "content": "# Gather Icinga2 status\n[[inputs.icinga2]]\n  ## Required Icinga2 server address\n  # server = \"https://localhost:5665\"\n\n  ## Collected Icinga2 objects (\"services\", \"hosts\")\n  ## Specify at least one object to collect from /v1/objects endpoint.\n  # objects = [\"services\"]\n\n  ## Collect metrics from /v1/status endpoint\n  ## Choose from:\n  ##     \"ApiListener\", \"CIB\", \"IdoMysqlConnection\", \"IdoPgsqlConnection\"\n  # status = []\n\n  ## Credentials for basic HTTP authentication\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "plugins/inputs/infiniband/README.md",
    "content": "# InfiniBand Input Plugin\n\nThis plugin gathers statistics for all InfiniBand devices and ports on the\nsystem. These are the counters that can be found in\n`/sys/class/infiniband/<dev>/port/<port>/counters/`\nand RDMA counters can be found in\n`/sys/class/infiniband/<dev>/ports/<port>/hw_counters/`\n\n⭐ Telegraf v1.14.0\n🏷️ network\n💻 linux\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gets counters from all InfiniBand cards and ports installed\n# This plugin ONLY supports Linux\n[[inputs.infiniband]]\n  # no configuration\n\n  ## Collect RDMA counters\n  # gather_rdma = false\n```\n\n## Metrics\n\nActual metrics depend on the InfiniBand devices, the plugin uses a simple\nmapping from counter -> counter value.\n\n[Information about the counters][counters] collected is provided by Nvidia.\n\n[counters]: https://enterprise-support.nvidia.com/s/article/understanding-mlx5-linux-counters-and-status-parameters\n\nThe following fields are emitted by the plugin when selecting `counters`:\n\n- infiniband\n  - tags:\n    - device\n    - port\n  - fields:\n\n    ### Infiniband Counters\n\n    - excessive_buffer_overrun_errors (integer)\n    - link_downed (integer)\n    - link_error_recovery (integer)\n    - local_link_integrity_errors (integer)\n    - multicast_rcv_packets (integer)\n    - multicast_xmit_packets (integer)\n    - port_rcv_constraint_errors (integer)\n    - port_rcv_data (integer)\n    - port_rcv_errors (integer)\n    - port_rcv_packets (integer)\n    - port_rcv_remote_physical_errors (integer)\n    - port_rcv_switch_relay_errors (integer)\n    - port_xmit_constraint_errors (integer)\n    - port_xmit_data (integer)\n    - port_xmit_discards (integer)\n    - port_xmit_packets (integer)\n    - port_xmit_wait (integer)\n    - symbol_error (integer)\n    - unicast_rcv_packets (integer)\n    - unicast_xmit_packets (integer)\n    - VL15_dropped (integer)\n\n    ### Infiniband RDMA counters\n\n    - duplicate_request (integer)\n    - implied_nak_seq_err (integer)\n    - lifespan (integer)\n    - local_ack_timeout_err (integer)\n    - np_cnp_sent (integer)\n    - np_ecn_marked_roce_packets (integer)\n    - out_of_buffer (integer)\n    - out_of_sequence (integer)\n    - packet_seq_err (integer)\n    - req_cqe_error (integer)\n    - req_cqe_flush_error (integer)\n    - req_remote_access_errors (integer)\n    - req_remote_invalid_request (integer)\n    - resp_cqe_error (integer)\n    - resp_cqe_flush_error (integer)\n    - resp_local_length_error (integer)\n    - resp_remote_access_errors (integer)\n    - rnr_nak_retry_err (integer)\n    - roce_adp_retrans (integer)\n    - roce_adp_retrans_to (integer)\n    - roce_slow_restart (integer)\n    - roce_slow_restart_cnps (integer)\n    - roce_slow_restart_trans (integer)\n    - rp_cnp_handled (integer)\n    - rp_cnp_ignored (integer)\n    - rx_atomic_requests (integer)\n    - rx_icrc_encapsulated (integer)\n    - rx_read_requests (integer)\n    - rx_write_requests (integer)\n\n## Example Output\n\n```text\ninfiniband,device=mlx5_bond_0,host=hop-r640-12,port=1 port_xmit_data=85378896588i,VL15_dropped=0i,port_rcv_packets=34914071i,port_rcv_data=34600185253i,port_xmit_discards=0i,link_downed=0i,local_link_integrity_errors=0i,symbol_error=0i,link_error_recovery=0i,multicast_rcv_packets=0i,multicast_xmit_packets=0i,unicast_xmit_packets=82002535i,excessive_buffer_overrun_errors=0i,port_rcv_switch_relay_errors=0i,unicast_rcv_packets=34914071i,port_xmit_constraint_errors=0i,port_rcv_errors=0i,port_xmit_wait=0i,port_rcv_remote_physical_errors=0i,port_rcv_constraint_errors=0i,port_xmit_packets=82002535i 1737652060000000000\ninfiniband,device=mlx5_bond_0,host=hop-r640-12,port=1 local_ack_timeout_err=0i,lifespan=10i,out_of_buffer=0i,resp_remote_access_errors=0i,resp_local_length_error=0i,np_cnp_sent=0i,roce_slow_restart=0i,rx_read_requests=6000i,duplicate_request=0i,resp_cqe_error=0i,rx_write_requests=19000i,roce_slow_restart_cnps=0i,rx_icrc_encapsulated=0i,rnr_nak_retry_err=0i,roce_adp_retrans=0i,out_of_sequence=0i,req_remote_access_errors=0i,roce_slow_restart_trans=0i,req_remote_invalid_request=0i,req_cqe_error=0i,resp_cqe_flush_error=0i,packet_seq_err=0i,roce_adp_retrans_to=0i,np_ecn_marked_roce_packets=0i,rp_cnp_handled=0i,implied_nak_seq_err=0i,rp_cnp_ignored=0i,req_cqe_flush_error=0i,rx_atomic_requests=0i 1737652060000000000\n```\n"
  },
  {
    "path": "plugins/inputs/infiniband/infiniband.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage infiniband\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Infiniband struct {\n\tRDMA bool            `toml:\"gather_rdma\"`\n\tLog  telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Infiniband) SampleConfig() string {\n\treturn sampleConfig\n}\n\n// Initialise plugin\nfunc init() {\n\tinputs.Add(\"infiniband\", func() telegraf.Input { return &Infiniband{} })\n}\n"
  },
  {
    "path": "plugins/inputs/infiniband/infiniband_linux.go",
    "content": "//go:build linux\n\npackage infiniband\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/Mellanox/rdmamap\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Gather statistics from our infiniband cards\nfunc (ib *Infiniband) Gather(acc telegraf.Accumulator) error {\n\trdmaDevices := rdmamap.GetRdmaDeviceList()\n\n\tif len(rdmaDevices) == 0 {\n\t\treturn errors.New(\"no InfiniBand devices found in /sys/class/infiniband/\")\n\t}\n\n\tfor _, dev := range rdmaDevices {\n\t\tdevicePorts := rdmamap.GetPorts(dev)\n\t\tfor _, port := range devicePorts {\n\t\t\tportInt, err := strconv.Atoi(port)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tstats, err := rdmamap.GetRdmaSysfsStats(dev, portInt)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\taddStats(dev, port, stats, acc)\n\n\t\t\tif ib.RDMA {\n\t\t\t\tstats, err := rdmamap.GetRdmaSysfsHwStats(dev, portInt)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taddStats(dev, port, stats, acc)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Add the statistics to the accumulator\nfunc addStats(dev, port string, stats []rdmamap.RdmaStatEntry, acc telegraf.Accumulator) {\n\t// Allow users to filter by card and port\n\ttags := map[string]string{\"device\": dev, \"port\": port}\n\tfields := make(map[string]interface{})\n\n\tfor _, entry := range stats {\n\t\tfields[entry.Name] = entry.Value\n\t}\n\n\tacc.AddFields(\"infiniband\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/infiniband/infiniband_notlinux.go",
    "content": "//go:build !linux\n\npackage infiniband\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nfunc (i *Infiniband) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Infiniband) Gather(_ telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"infiniband\", func() telegraf.Input {\n\t\treturn &Infiniband{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/infiniband/infiniband_test.go",
    "content": "//go:build linux\n\npackage infiniband\n\nimport (\n\t\"testing\"\n\n\t\"github.com/Mellanox/rdmamap\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInfiniband(t *testing.T) {\n\tfields := map[string]interface{}{\n\t\t\"excessive_buffer_overrun_errors\": uint64(0),\n\t\t\"link_downed\":                     uint64(0),\n\t\t\"link_error_recovery\":             uint64(0),\n\t\t\"local_link_integrity_errors\":     uint64(0),\n\t\t\"multicast_rcv_packets\":           uint64(0),\n\t\t\"multicast_xmit_packets\":          uint64(0),\n\t\t\"port_rcv_constraint_errors\":      uint64(0),\n\t\t\"port_rcv_data\":                   uint64(237159415345822),\n\t\t\"port_rcv_errors\":                 uint64(0),\n\t\t\"port_rcv_packets\":                uint64(801977655075),\n\t\t\"port_rcv_remote_physical_errors\": uint64(0),\n\t\t\"port_rcv_switch_relay_errors\":    uint64(0),\n\t\t\"port_xmit_constraint_errors\":     uint64(0),\n\t\t\"port_xmit_data\":                  uint64(238334949937759),\n\t\t\"port_xmit_discards\":              uint64(0),\n\t\t\"port_xmit_packets\":               uint64(803162651391),\n\t\t\"port_xmit_wait\":                  uint64(4294967295),\n\t\t\"symbol_error\":                    uint64(0),\n\t\t\"unicast_rcv_packets\":             uint64(801977655075),\n\t\t\"unicast_xmit_packets\":            uint64(803162651391),\n\t\t\"VL15_dropped\":                    uint64(0),\n\t}\n\n\ttags := map[string]string{\n\t\t\"device\": \"m1x5_0\",\n\t\t\"port\":   \"1\",\n\t}\n\n\tsampleRdmastatsEntries := []rdmamap.RdmaStatEntry{\n\t\t{\n\t\t\tName:  \"excessive_buffer_overrun_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"link_downed\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"link_error_recovery\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"local_link_integrity_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"multicast_rcv_packets\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"multicast_xmit_packets\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_constraint_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_data\",\n\t\t\tValue: uint64(237159415345822),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_packets\",\n\t\t\tValue: uint64(801977655075),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_remote_physical_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_rcv_switch_relay_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_xmit_constraint_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_xmit_data\",\n\t\t\tValue: uint64(238334949937759),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_xmit_discards\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_xmit_packets\",\n\t\t\tValue: uint64(803162651391),\n\t\t},\n\t\t{\n\t\t\tName:  \"port_xmit_wait\",\n\t\t\tValue: uint64(4294967295),\n\t\t},\n\t\t{\n\t\t\tName:  \"symbol_error\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"unicast_rcv_packets\",\n\t\t\tValue: uint64(801977655075),\n\t\t},\n\t\t{\n\t\t\tName:  \"unicast_xmit_packets\",\n\t\t\tValue: uint64(803162651391),\n\t\t},\n\t\t{\n\t\t\tName:  \"VL15_dropped\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\taddStats(\"m1x5_0\", \"1\", sampleRdmastatsEntries, &acc)\n\n\tacc.AssertContainsTaggedFields(t, \"infiniband\", fields, tags)\n}\n\nfunc TestInfinibandRDMA(t *testing.T) {\n\tfields := map[string]interface{}{\n\t\t\"duplicate_request\":          uint64(0),\n\t\t\"implied_nak_seq_err\":        uint64(0),\n\t\t\"lifespan\":                   uint64(10),\n\t\t\"local_ack_timeout_err\":      uint64(38),\n\t\t\"np_cnp_sent\":                uint64(10284520),\n\t\t\"np_ecn_marked_roce_packets\": uint64(286733949),\n\t\t\"out_of_buffer\":              uint64(1149772),\n\t\t\"out_of_sequence\":            uint64(44),\n\t\t\"packet_seq_err\":             uint64(1),\n\t\t\"req_cqe_error\":              uint64(10776),\n\t\t\"req_cqe_flush_error\":        uint64(2173),\n\t\t\"req_remote_access_errors\":   uint64(0),\n\t\t\"req_remote_invalid_request\": uint64(0),\n\t\t\"resp_cqe_error\":             uint64(759),\n\t\t\"resp_cqe_flush_error\":       uint64(759),\n\t\t\"resp_local_length_error\":    uint64(0),\n\t\t\"resp_remote_access_errors\":  uint64(0),\n\t\t\"rnr_nak_retry_err\":          uint64(0),\n\t\t\"roce_adp_retrans\":           uint64(0),\n\t\t\"roce_adp_retrans_to\":        uint64(0),\n\t\t\"roce_slow_restart\":          uint64(0),\n\t\t\"roce_slow_restart_cnps\":     uint64(0),\n\t\t\"roce_slow_restart_trans\":    uint64(0),\n\t\t\"rp_cnp_handled\":             uint64(1),\n\t\t\"rp_cnp_ignored\":             uint64(0),\n\t\t\"rx_atomic_requests\":         uint64(0),\n\t\t\"rx_icrc_encapsulated\":       uint64(0),\n\t\t\"rx_read_requests\":           uint64(488228),\n\t\t\"rx_write_requests\":          uint64(3928699),\n\t}\n\n\ttags := map[string]string{\n\t\t\"device\": \"m1x5_0\",\n\t\t\"port\":   \"1\",\n\t}\n\n\tsampleRdmaHwStatsEntries := []rdmamap.RdmaStatEntry{\n\t\t{\n\t\t\tName:  \"duplicate_request\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"implied_nak_seq_err\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"lifespan\",\n\t\t\tValue: uint64(10),\n\t\t},\n\t\t{\n\t\t\tName:  \"local_ack_timeout_err\",\n\t\t\tValue: uint64(38),\n\t\t},\n\t\t{\n\t\t\tName:  \"np_cnp_sent\",\n\t\t\tValue: uint64(10284520),\n\t\t},\n\t\t{\n\t\t\tName:  \"np_ecn_marked_roce_packets\",\n\t\t\tValue: uint64(286733949),\n\t\t},\n\t\t{\n\t\t\tName:  \"out_of_buffer\",\n\t\t\tValue: uint64(1149772),\n\t\t},\n\t\t{\n\t\t\tName:  \"out_of_sequence\",\n\t\t\tValue: uint64(44),\n\t\t},\n\t\t{\n\t\t\tName:  \"packet_seq_err\",\n\t\t\tValue: uint64(1),\n\t\t},\n\t\t{\n\t\t\tName:  \"req_cqe_error\",\n\t\t\tValue: uint64(10776),\n\t\t},\n\t\t{\n\t\t\tName:  \"req_cqe_flush_error\",\n\t\t\tValue: uint64(2173),\n\t\t},\n\t\t{\n\t\t\tName:  \"req_remote_access_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"req_remote_invalid_request\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"resp_cqe_error\",\n\t\t\tValue: uint64(759),\n\t\t},\n\t\t{\n\t\t\tName:  \"resp_cqe_flush_error\",\n\t\t\tValue: uint64(759),\n\t\t},\n\t\t{\n\t\t\tName:  \"resp_local_length_error\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"resp_remote_access_errors\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"rnr_nak_retry_err\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"roce_adp_retrans\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"roce_adp_retrans_to\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"roce_slow_restart\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"roce_slow_restart_cnps\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"roce_slow_restart_trans\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"rp_cnp_handled\",\n\t\t\tValue: uint64(1),\n\t\t},\n\t\t{\n\t\t\tName:  \"rp_cnp_ignored\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"rx_atomic_requests\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"rx_icrc_encapsulated\",\n\t\t\tValue: uint64(0),\n\t\t},\n\t\t{\n\t\t\tName:  \"rx_read_requests\",\n\t\t\tValue: uint64(488228),\n\t\t},\n\t\t{\n\t\t\tName:  \"rx_write_requests\",\n\t\t\tValue: uint64(3928699),\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\taddStats(\"m1x5_0\", \"1\", sampleRdmaHwStatsEntries, &acc)\n\n\tacc.AssertContainsTaggedFields(t, \"infiniband\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/infiniband/sample.conf",
    "content": "# Gets counters from all InfiniBand cards and ports installed\n# This plugin ONLY supports Linux\n[[inputs.infiniband]]\n  # no configuration\n\n  ## Collect RDMA counters\n  # gather_rdma = false\n"
  },
  {
    "path": "plugins/inputs/influxdb/README.md",
    "content": "# InfluxDB Input Plugin\n\nThis plugin collects metrics on the given InfluxDB v1 servers from the\n`/debug/vars` endpoint. Read the [documentation][doc_v1] for detailed\ninformation about `influxdb` metrics.\n\nAdditionally, this plugin can gather metrics from endpoints exposing\nInfluxDB-formatted endpoints.\n\n> [!TIP]\n> To gather [InfluxDB v2 metrics][docs_v2] use the\n> [prometheus plugin][prometheus] with\n>\n> ```toml\n> [[inputs.prometheus]]\n>  urls = [\"http://localhost:8086/metrics\"]\n>  metric_version = 1\n> ```\n\n⭐ Telegraf v0.2.5\n🏷️ datastore\n💻 all\n\n[doc_v1]: https://docs.influxdata.com/platform/monitoring/influxdata-platform/tools/measurements-internal/\n[docs_v2]: https://docs.influxdata.com/influxdb/latest/reference/internals/metrics/\n[prometheus]: /plugins/inputs/prometheus/README.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read InfluxDB-formatted JSON metrics from one or more HTTP endpoints\n[[inputs.influxdb]]\n  ## Works with InfluxDB debug endpoints out of the box,\n  ## but other services can use this format too.\n  ## See the influxdb plugin's README for more details.\n\n  ## Multiple URLs from which to read InfluxDB-formatted JSON\n  ## Default is \"http://localhost:8086/debug/vars\".\n  urls = [\n    \"http://localhost:8086/debug/vars\"\n  ]\n\n  ## Username and password to send using HTTP Basic Authentication.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## http request & header timeout\n  timeout = \"5s\"\n```\n\n## InfluxDB-formatted endpoints\n\nThe influxdb plugin can collect InfluxDB-formatted data from JSON endpoints.\nWhether associated with an Influx database or not.\n\nWith a configuration of:\n\n```toml\n[[inputs.influxdb]]\n  urls = [\n    \"http://127.0.0.1:8086/debug/vars\",\n    \"http://192.168.2.1:8086/debug/vars\"\n  ]\n```\n\n## Metrics\n\n> [!NOTE]\n> The measurements and fields included in this plugin are dynamically\n> built from the InfluxDB source, and may vary between versions.\n\n- **influxdb_ae** _(Enterprise Only)_ : Statistics related to the Anti-Entropy\n  (AE) engine in InfluxDB Enterprise clusters.\n  - **bytesRx**: Number of bytes received by the data node.\n  - **errors**: Total number of anti-entropy jobs that have resulted in errors.\n  - **jobs**: Total number of jobs executed by the data node.\n  - **jobsActive**: Number of active (currently executing) jobs.\n- **influxdb_cluster** _(Enterprise Only)_ : Statistics related to the\n  clustering features of the data nodes in InfluxDB Enterprise clusters.\n  - **copyShardReq**: Number of internal requests made to copy a shard from\n    one data node to another.\n  - **createIteratorReq**: Number of read requests from other data nodes in\n    the cluster.\n  - **expandSourcesReq**: Number of remote node requests made to find\n    measurements on this node that match a particular regular expression.\n  - **fieldDimensionsReq**: Number of remote node requests for information\n    about the fields and associated types, and tag keys of measurements on\n    this data node.\n  - **iteratorCostReq**: Number of internal requests for iterator cost.\n  - **openConnections**: Tracks the number of open connections being handled by\n    the data node (including logical connections multiplexed onto a single\n    yamux connection).\n  - **removeShardReq**: Number of internal requests to delete a shard from this\n    data node. Exclusively incremented by use of the influxd-ctl remove shard\n    command.\n  - **writeShardFail**: Total number of internal write requests from a remote\n    node that failed.\n  - **writeShardPointsReq**: Number of points in every internal write request\n    from any remote node, regardless of success.\n  - **writeShardReq**: Number of internal write requests from a remote data\n    node, regardless of success.\n- **influxdb_cq**: Metrics related to continuous queries (CQs).\n  - **queryFail**: Total number of continuous queries that executed but failed.\n  - **queryOk**: Total number of continuous queries that executed successfully.\n- **influxdb_database**: Database metrics are collected from.\n  - **numMeasurements**: Current number of measurements in the specified\n    database.\n  - **numSeries**: Current series cardinality of the specified database.\n- **influxdb_hh** _(Enterprise Only)_ : Events resulting in new hinted handoff\n  (HH) processors in InfluxDB Enterprise clusters.\n  - **writeShardReq**: Number of initial write requests handled by the hinted\n    handoff engine for a remote node.\n  - **writeShardReqPoints**: Number of write requests for each point in the\n    initial request to the hinted handoff engine for a remote node.\n- **influxdb_hh_database** _(Enterprise Only)_ : Aggregates all hinted handoff\n  queues for a single database and node.\n  - **bytesRead**: Size, in bytes, of points read from the hinted handoff queue\n    and sent to its destination data node.\n  - **bytesWritten**: Total number of bytes written to the hinted handoff queue.\n  - **queueBytes**: Total number of bytes remaining in the hinted handoff queue.\n  - **queueDepth**: Total number of segments in the hinted handoff queue.\n    The HH queue is a sequence of 10MB “segment” files.\n  - **writeBlocked**: Number of writes blocked because the number of concurrent\n    HH requests exceeds the limit.\n  - **writeDropped**: Number of writes dropped from the HH queue because the\n    write appeared to be corrupted.\n  - **writeNodeReq**: Total number of write requests that succeeded in writing\n    a batch to the destination node.\n  - **writeNodeReqFail**: Total number of write requests that failed in writing\n    a batch of data from the hinted handoff queue to the destination node.\n  - **writeNodeReqPoints**: Total number of points successfully written from\n    the HH queue to the destination node fr\n  - **writeShardReq**: Total number of every write batch request enqueued into\n    the hinted handoff queue.\n  - **writeShardReqPoints**: Total number of points enqueued into the hinted\n    handoff queue.\n- **influxdb_hh_processor** _(Enterprise Only)_: Statistics stored for a single\n  queue (shard).\n  - **bytesRead**: Size, in bytes, of points read from the hinted handoff queue\n    and sent to its destination data node.\n  - **bytesWritten**: Total number of bytes written to the hinted handoff queue.\n  - **queueBytes**: Total number of bytes remaining in the hinted handoff queue.\n  - **queueDepth**: Total number of segments in the hinted handoff queue.\n    The HH queue is a sequence of 10MB “segment” files.\n  - **writeBlocked**: Number of writes blocked because the number of concurrent\n    HH requests exceeds the limit.\n  - **writeDropped**: Number of writes dropped from the HH queue because the\n    write appeared to be corrupted.\n  - **writeNodeReq**: Total number of write requests that succeeded in writing\n    a batch to the destination node.\n  - **writeNodeReqFail**: Total number of write requests that failed in writing\n    a batch of data from the hinted handoff queue to the destination node.\n  - **writeNodeReqPoints**: Total number of points successfully written from\n    the HH queue to the destination node fr\n  - **writeShardReq**: Total number of every write batch request enqueued into\n    the hinted handoff queue.\n  - **writeShardReqPoints**: Total number of points enqueued into the hinted\n    handoff queue.\n- **influxdb_httpd**: Metrics related to the InfluxDB HTTP server.\n  - **authFail**: Number of HTTP requests that were aborted due to\n    authentication being required, but not supplied or incorrect.\n  - **clientError**: Number of HTTP responses due to client errors, with\n    a 4XX HTTP status code.\n  - **fluxQueryReq**: Number of Flux query requests served.\n  - **fluxQueryReqDurationNs**: Duration (wall-time), in nanoseconds, spent\n    executing Flux query requests.\n  - **pingReq**: Number of times InfluxDB HTTP server served the /ping HTTP\n    endpoint.\n  - **pointsWrittenDropped**: Number of points dropped by the storage engine.\n  - **pointsWrittenFail**: Number of points accepted by the HTTP /write\n    endpoint, but unable to be persisted.\n  - **pointsWrittenOK**: Number of points successfully accepted and persisted\n    by the HTTP /write endpoint.\n  - **promReadReq**: Number of read requests to the Prometheus /read endpoint.\n  - **promWriteReq**: Number of write requests to the Prometheus /write\n    endpoint.\n  - **queryReq**: Number of query requests.\n  - **queryReqDurationNs**: Total query request duration, in nanosecond (ns).\n  - **queryRespBytes**: Total number of bytes returned in query responses.\n  - **recoveredPanics**: Total number of panics recovered by the HTTP handler.\n  - **req**: Total number of HTTP requests served.\n  - **reqActive**: Number of currently active requests.\n  - **reqDurationNs**: Duration (wall time), in nanoseconds, spent inside HTTP\n    requests.\n  - **serverError**: Number of HTTP responses due to server errors.\n  - **statusReq**: Number of status requests served using the HTTP /status\n    endpoint.\n  - **valuesWrittenOK**: Number of values (fields) successfully accepted and\n    persisted by the HTTP /write endpoint.\n  - **writeReq**: Number of write requests served using the HTTP /write\n    endpoint.\n  - **writeReqActive**: Number of currently active write requests.\n  - **writeReqBytes**: Total number of bytes of line protocol data received by\n    write requests, using the HTTP /write endpoint.\n  - **writeReqDurationNs**: Duration, in nanoseconds, of write requests served\n    using the /write HTTP endpoint.\n- **influxdb_memstats**: Statistics about the memory allocator in the specified\n  database.\n  - **Alloc**: Number of bytes allocated to heap objects.\n  - **BuckHashSys**: Number of bytes of memory in profiling bucket hash tables.\n  - **Frees**: Cumulative count of heap objects freed.\n  - **GCCPUFraction**: fraction of InfluxDB's available CPU time used by the\n    garbage collector (GC) since InfluxDB started.\n  - **GCSys**: Number of bytes of memory in garbage collection metadata.\n  - **HeapAlloc**: Number of bytes of allocated heap objects.\n  - **HeapIdle**: Number of bytes in idle (unused) spans.\n  - **HeapInuse**: Number of bytes in in-use spans.\n  - **HeapObjects**: Number of allocated heap objects.\n  - **HeapReleased**: Number of bytes of physical memory returned to the OS.\n  - **HeapSys**: Number of bytes of heap memory obtained from the OS.\n  - **LastGC**: Time the last garbage collection finished.\n  - **Lookups**: Number of pointer lookups performed by the runtime.\n  - **MCacheInuse**: Number of bytes of allocated mcache structures.\n  - **MCacheSys**: Number of bytes of memory obtained from the OS for mcache\n    structures.\n  - **MSpanInuse**: Number of bytes of allocated mspan structures.\n  - **MSpanSys**: Number of bytes of memory obtained from the OS for mspan\n    structures.\n  - **Mallocs**: Cumulative count of heap objects allocated.\n  - **NextGC**: Target heap size of the next GC cycle.\n  - **NumForcedGC**: Number of GC cycles that were forced by the application\n    calling the GC function.\n  - **NumGC**: Number of completed GC cycles.\n  - **OtherSys**: Number of bytes of memory in miscellaneous off-heap runtime\n    allocations.\n  - **PauseTotalNs**: Cumulative nanoseconds in GC stop-the-world pauses since\n    the program started.\n  - **StackInuse**: Number of bytes in stack spans.\n  - **StackSys**: Number of bytes of stack memory obtained from the OS.\n  - **Sys**: Total bytes of memory obtained from the OS.\n  - **TotalAlloc**: Cumulative bytes allocated for heap objects.\n- **influxdb_queryExecutor**: Metrics related to usage of the Query Executor\n  of the InfluxDB engine.\n  - **queriesActive**: Number of active queries currently being handled.\n  - **queriesExecuted**: Number of queries executed (started).\n  - **queriesFinished**: Number of queries that have finished executing.\n  - **queryDurationNs**: Total duration, in nanoseconds, of executed queries.\n  - **recoveredPanics**: Number of panics recovered by the Query Executor.\n- **influxdb_rpc** _(Enterprise Only)_ : Statistics related to the use of RPC\n  calls within InfluxDB Enterprise clusters.\n  - **idleStreams**: Number of idle multiplexed streams across all live TCP\n    connections.\n  - **liveConnections**: Current number of live TCP connections to other nodes.\n  - **liveStreams**: Current number of live multiplexed streams across all live\n    TCP connections.\n  - **rpcCalls**: Total number of RPC calls made to remote nodes.\n  - **rpcFailures**: Total number of RPC failures, which are RPCs that did\n    not recover.\n  - **rpcReadBytes**: Total number of RPC bytes read.\n  - **rpcRetries**: Total number of RPC calls that retried at least once.\n  - **rpcWriteBytes**: Total number of RPC bytes written.\n  - **singleUse**: Total number of single-use connections opened using Dial.\n  - **singleUseOpen**: Number of single-use connections currently open.\n  - **totalConnections**: Total number of TCP connections that have been\n    established.\n  - **totalStreams**: Total number of streams established.\n- **influxdb_runtime**: Subset of memstat record statistics for the Go memory\n  allocator.\n  - **Alloc**: Currently allocated number of bytes of heap objects.\n  - **Frees**: Cumulative number of freed (live) heap objects.\n  - **HeapAlloc**: Size, in bytes, of all heap objects.\n  - **HeapIdle**: Number of bytes of idle heap objects.\n  - **HeapInUse**: Number of bytes in in-use spans.\n  - **HeapObjects**: Number of allocated heap objects.\n  - **HeapReleased**: Number of bytes of physical memory returned to the OS.\n  - **HeapSys**: Number of bytes of heap memory obtained from the OS. Measures\n    the amount of virtual address space reserved for the heap.\n  - **Lookups**: Number of pointer lookups performed by the runtime. Primarily\n    useful for debugging runtime internals.\n  - **Mallocs**: Total number of heap objects allocated. The total number of\n    live objects is Frees.\n  - **NumGC**: Number of completed GC (garbage collection) cycles.\n  - **NumGoroutine**: Total number of Go routines.\n  - **PauseTotalNs**: Total duration, in nanoseconds, of total GC\n    (garbage collection) pauses.\n  - **Sys**: Total number of bytes of memory obtained from the OS. Measures\n    the virtual address space reserved by the Go runtime for the heap, stacks,\n    and other internal data structures.\n  - **TotalAlloc**: Total number of bytes allocated for heap objects. This\n    statistic does not decrease when objects are freed.\n- **influxdb_shard**: Metrics related to InfluxDB shards.\n  - **diskBytes**: Size, in bytes, of the shard, including the size of the\n    data directory and the WAL directory.\n  - **fieldsCreate**: Number of fields created.\n  - **indexType**: Type of index inmem or tsi1.\n  - **n_shards**: Total number of shards in the specified database.\n  - **seriesCreate**: Number of series created.\n  - **writeBytes**: Number of bytes written to the shard.\n  - **writePointsDropped**: Number of requests to write points t dropped from\n    a write.\n  - **writePointsErr**: Number of requests to write points that failed to be\n    written due to errors.\n  - **writePointsOk**: Number of points written successfully.\n  - **writeReq**: Total number of write requests.\n  - **writeReqErr**: Total number of write requests that failed due to errors.\n  - **writeReqOk**: Total number of successful write requests.\n- **influxdb_subscriber**: InfluxDB subscription metrics.\n  - **createFailures**: Number of subscriptions that failed to be created.\n  - **pointsWritten**: Total number of points that were successfully written\n    to subscribers.\n  - **writeFailures**: Total number of batches that failed to be written\n    to subscribers.\n- **influxdb_tsm1_cache**: TSM cache metrics.\n  - **cacheAgeMs**: Duration, in milliseconds, since the cache was last\n    snapshotted at sample time.\n  - **cachedBytes**: Total number of bytes that have been written into snapshots.\n  - **diskBytes**: Size, in bytes, of on-disk snapshots.\n  - **memBytes**: Size, in bytes, of in-memory cache.\n  - **snapshotCount**: Current level (number) of active snapshots.\n  - **WALCompactionTimeMs**: Duration, in milliseconds, that the commit lock is\n    held while compacting snapshots.\n  - **writeDropped**: Total number of writes dropped due to timeouts.\n  - **writeErr**: Total number of writes that failed.\n  - **writeOk**: Total number of successful writes.\n- **influxdb_tsm1_engine**: TSM storage engine metrics.\n  - **cacheCompactionDuration** Duration (wall time), in nanoseconds, spent in\n    cache compactions.\n  - **cacheCompactionErr** Number of cache compactions that have failed due\n    to errors.\n  - **cacheCompactions** Total number of cache compactions that have ever run.\n  - **cacheCompactionsActive** Number of cache compactions that are currently\n    running.\n  - **tsmFullCompactionDuration** Duration (wall time), in nanoseconds, spent\n    in full compactions.\n  - **tsmFullCompactionErr** Total number of TSM full compactions that have\n    failed due to errors.\n  - **tsmFullCompactionQueue** Current number of pending TMS Full compactions.\n  - **tsmFullCompactions** Total number of TSM full compactions that have\n    ever run.\n  - **tsmFullCompactionsActive** Number of TSM full compactions currently\n    running.\n  - **tsmLevel1CompactionDuration** Duration (wall time), in nanoseconds,\n    spent in TSM level 1 compactions.\n  - **tsmLevel1CompactionErr** Total number of TSM level 1 compactions that\n    have failed due to errors.\n  - **tsmLevel1CompactionQueue** Current number of pending TSM level 1\n    compactions.\n  - **tsmLevel1Compactions** Total number of TSM level 1 compactions that have\n    ever run.\n  - **tsmLevel1CompactionsActive** Number of TSM level 1 compactions that are\n    currently running.\n  - **tsmLevel2CompactionDuration** Duration (wall time), in nanoseconds,\n    spent in TSM level 2 compactions.\n  - **tsmLevel2CompactionErr** Number of TSM level 2 compactions that have\n    failed due to errors.\n  - **tsmLevel2CompactionQueue** Current number of pending TSM level 2\n    compactions.\n  - **tsmLevel2Compactions** Total number of TSM level 2 compactions that\n    have ever run.\n  - **tsmLevel2CompactionsActive** Number of TSM level 2 compactions that\n    are currently running.\n  - **tsmLevel3CompactionDuration** Duration (wall time), in nanoseconds,\n    spent in TSM level 3 compactions.\n  - **tsmLevel3CompactionErr** Number of TSM level 3 compactions that have\n    failed due to errors.\n  - **tsmLevel3CompactionQueue** Current number of pending TSM level 3\n    compactions.\n  - **tsmLevel3Compactions** Total number of TSM level 3 compactions that\n    have ever run.\n  - **tsmLevel3CompactionsActive** Number of TSM level 3 compactions that\n    are currently running.\n  - **tsmOptimizeCompactionDuration** Duration (wall time), in nanoseconds,\n    spent during TSM optimize compactions.\n  - **tsmOptimizeCompactionErr** Total number of TSM optimize compactions\n   that have failed due to errors.\n  - **tsmOptimizeCompactionQueue** Current number of pending TSM optimize\n    compactions.\n  - **tsmOptimizeCompactions** Total number of TSM optimize compactions that\n    have ever run.\n  - **tsmOptimizeCompactionsActive** Number of TSM optimize compactions that\n    are currently running.\n- **influxdb_tsm1_filestore**: The TSM file store metrics.\n  - **diskBytes**: Size, in bytes, of disk usage by the TSM file store.\n  - **numFiles**: Total number of files in the TSM file store.\n- **influxdb_tsm1_wal**: The TSM Write Ahead Log (WAL) metrics.\n  - **currentSegmentDiskBytes**: Current size, in bytes, of the segment disk.\n  - **oldSegmentDiskBytes**: Size, in bytes, of the segment disk.\n  - **writeErr**: Number of writes that failed due to errors.\n  - **writeOK**: Number of writes that succeeded.\n- **influxdb_write**: Metrics related to InfluxDB writes.\n  - **pointReq**: Total number of points requested to be written.\n  - **pointReqHH** _(Enterprise only)_: Total number of points received for\n    write by this node and then enqueued into hinted handoff for the\n    destination node.\n  - **pointReqLocal** _(Enterprise only)_: Total number of point requests that\n    have been attempted to be written into a shard on the same (local) node.\n  - **pointReqRemote** _(Enterprise only)_: Total number of points received for\n    write by this node but needed to be forwarded into a shard on a remote node.\n  - **pointsWrittenOK**: Number of points written to the HTTP /write endpoint\n    and persisted successfully.\n  - **req**: Total number of batches requested to be written.\n  - **subWriteDrop**: Total number of batches that failed to be sent to the\n    subscription dispatcher.\n  - **subWriteOk**: Total number of batches successfully sent to the\n    subscription dispatcher.\n  - **valuesWrittenOK**: Number of values (fields) written to the HTTP\n    /write endpoint and persisted successfully.\n  - **writeDrop**: Total number of write requests for points that have been\n    dropped due to timestamps not matching any existing retention policies.\n  - **writeError**: Total number of batches of points that were not\n    successfully written, due to a failure to write to a local or remote shard.\n  - **writeOk**: Total number of batches of points written at the requested\n    consistency level.\n  - **writePartial** _(Enterprise only)_: Total number of batches written to\n    at least one node, but did not meet the requested consistency level.\n  - **writeTimeout**: Total number of write requests that failed to complete\n    within the default write timeout duration.\n\n## Example Output\n\n```sh\ntelegraf --config ~/ws/telegraf.conf --input-filter influxdb --test\n```\n\n```text\ninfluxdb_database,database=_internal,host=tyrion,url=http://localhost:8086/debug/vars numMeasurements=10,numSeries=29 1463590500247354636\ninfluxdb_httpd,bind=:8086,host=tyrion,url=http://localhost:8086/debug/vars req=7,reqActive=1,reqDurationNs=14227734 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=database,url=http://localhost:8086/debug/vars numSeries=1 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=httpd,url=http://localhost:8086/debug/vars numSeries=1 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=measurement,url=http://localhost:8086/debug/vars numSeries=10 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=runtime,url=http://localhost:8086/debug/vars numSeries=1 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=shard,url=http://localhost:8086/debug/vars numSeries=4 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=subscriber,url=http://localhost:8086/debug/vars numSeries=1 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=tsm1_cache,url=http://localhost:8086/debug/vars numSeries=4 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=tsm1_filestore,url=http://localhost:8086/debug/vars numSeries=2 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=tsm1_wal,url=http://localhost:8086/debug/vars numSeries=4 1463590500247354636\ninfluxdb_measurement,database=_internal,host=tyrion,measurement=write,url=http://localhost:8086/debug/vars numSeries=1 1463590500247354636\ninfluxdb_memstats,host=tyrion,url=http://localhost:8086/debug/vars alloc=7642384i,buck_hash_sys=1463471i,frees=1169558i,gc_sys=653312i,gc_cpu_fraction=0.00003825652361068311,heap_alloc=7642384i,heap_idle=9912320i,heap_inuse=9125888i,heap_objects=48276i,heap_released=0i,heap_sys=19038208i,last_gc=1463590480877651621i,lookups=90i,mallocs=1217834i,mcache_inuse=4800i,mcache_sys=16384i,mspan_inuse=70920i,mspan_sys=81920i,next_gc=11679787i,num_gc=141i,other_sys=1244233i,pause_total_ns=24034027i,stack_inuse=884736i,stack_sys=884736i,sys=23382264i,total_alloc=679012200i 1463590500277918755\ninfluxdb_shard,database=_internal,engine=tsm1,host=tyrion,id=4,path=/Users/sparrc/.influxdb/data/_internal/monitor/4,retentionPolicy=monitor,url=http://localhost:8086/debug/vars fieldsCreate=65,seriesCreate=26,writePointsOk=7274,writeReq=280 1463590500247354636\ninfluxdb_subscriber,host=tyrion,url=http://localhost:8086/debug/vars pointsWritten=7274 1463590500247354636\ninfluxdb_tsm1_cache,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/1,retentionPolicy=monitor,url=http://localhost:8086/debug/vars WALCompactionTimeMs=0,cacheAgeMs=2809192,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0 1463590500247354636\ninfluxdb_tsm1_cache,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://localhost:8086/debug/vars WALCompactionTimeMs=0,cacheAgeMs=2809184,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0 1463590500247354636\ninfluxdb_tsm1_cache,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/3,retentionPolicy=monitor,url=http://localhost:8086/debug/vars WALCompactionTimeMs=0,cacheAgeMs=2809180,cachedBytes=0,diskBytes=0,memBytes=42368,snapshotCount=0 1463590500247354636\ninfluxdb_tsm1_cache,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/4,retentionPolicy=monitor,url=http://localhost:8086/debug/vars WALCompactionTimeMs=0,cacheAgeMs=2799155,cachedBytes=0,diskBytes=0,memBytes=331216,snapshotCount=0 1463590500247354636\ninfluxdb_tsm1_filestore,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/1,retentionPolicy=monitor,url=http://localhost:8086/debug/vars diskBytes=37892 1463590500247354636\ninfluxdb_tsm1_filestore,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://localhost:8086/debug/vars diskBytes=52907 1463590500247354636\ninfluxdb_tsm1_wal,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/wal/_internal/monitor/1,retentionPolicy=monitor,url=http://localhost:8086/debug/vars currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0 1463590500247354636\ninfluxdb_tsm1_wal,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/wal/_internal/monitor/2,retentionPolicy=monitor,url=http://localhost:8086/debug/vars currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0 1463590500247354636\ninfluxdb_tsm1_wal,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/wal/_internal/monitor/3,retentionPolicy=monitor,url=http://localhost:8086/debug/vars currentSegmentDiskBytes=0,oldSegmentsDiskBytes=65651 1463590500247354636\ninfluxdb_tsm1_wal,database=_internal,host=tyrion,path=/Users/sparrc/.influxdb/wal/_internal/monitor/4,retentionPolicy=monitor,url=http://localhost:8086/debug/vars currentSegmentDiskBytes=495687,oldSegmentsDiskBytes=0 1463590500247354636\ninfluxdb_write,host=tyrion,url=http://localhost:8086/debug/vars pointReq=7274,pointReqLocal=7274,req=280,subWriteOk=280,writeOk=280 1463590500247354636\ninfluxdb_shard,host=tyrion n_shards=4i 1463590500247354636\n```\n"
  },
  {
    "path": "plugins/inputs/influxdb/influxdb.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage influxdb\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmaxErrorResponseBodyLength = 1024\n)\n\ntype InfluxDB struct {\n\tURLs     []string        `toml:\"urls\"`\n\tUsername string          `toml:\"username\"`\n\tPassword string          `toml:\"password\"`\n\tTimeout  config.Duration `toml:\"timeout\"`\n\ttls.ClientConfig\n\n\tclient *http.Client\n}\n\ntype apiError struct {\n\tStatusCode  int\n\tReason      string\n\tDescription string `json:\"error\"`\n}\n\nfunc (e *apiError) Error() string {\n\tif e.Description != \"\" {\n\t\treturn e.Reason + \": \" + e.Description\n\t}\n\treturn e.Reason\n}\n\nfunc (*InfluxDB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (i *InfluxDB) Gather(acc telegraf.Accumulator) error {\n\tif len(i.URLs) == 0 {\n\t\ti.URLs = []string{\"http://localhost:8086/debug/vars\"}\n\t}\n\n\tif i.client == nil {\n\t\ttlsCfg, err := i.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ti.client = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tResponseHeaderTimeout: time.Duration(i.Timeout),\n\t\t\t\tTLSClientConfig:       tlsCfg,\n\t\t\t},\n\t\t\tTimeout: time.Duration(i.Timeout),\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, u := range i.URLs {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := i.gatherURL(acc, url); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(u)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\n// Gathers data from a particular URL\n// Parameters:\n//\n//\tacc    : The telegraf Accumulator to use\n//\turl    : endpoint to send request to\n//\n// Returns:\n//\n//\terror: Any error that may have occurred\nfunc (i *InfluxDB) gatherURL(acc telegraf.Accumulator, url string) error {\n\tshardCounter := 0\n\tnow := time.Now()\n\n\t// Get the data\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif i.Username != \"\" || i.Password != \"\" {\n\t\treq.SetBasicAuth(i.Username, i.Password)\n\t}\n\n\treq.Header.Set(\"User-Agent\", \"Telegraf/\"+internal.Version)\n\n\tresp, err := i.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn readResponseError(resp)\n\t}\n\n\t// It would be nice to be able to decode into a map[string]point, but\n\t// we'll get a decoder error like:\n\t// `json: cannot unmarshal array into Go value of type influxdb.point`\n\t// if any of the values aren't objects.\n\t// To avoid that error, we decode by hand.\n\tdec := json.NewDecoder(resp.Body)\n\n\t// Parse beginning of object\n\tif t, err := dec.Token(); err != nil {\n\t\treturn err\n\t} else if t != json.Delim('{') {\n\t\treturn errors.New(\"document root must be a JSON object\")\n\t}\n\n\t// Loop through rest of object\n\tfor dec.More() {\n\t\t// Read in a string key. We don't do anything with the top-level keys,\n\t\t// so it's discarded.\n\t\trawKey, err := dec.Token()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// All variables should be keyed\n\t\tkey, ok := rawKey.(string)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Try to decode known special structs\n\t\tswitch key {\n\t\tcase \"system\":\n\t\t\tvar p system\n\t\t\tif err := dec.Decode(&p); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tacc.AddFields(\"influxdb_system\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"current_time\": p.CurrentTime,\n\t\t\t\t\t\"started\":      p.Started,\n\t\t\t\t\t\"uptime\":       p.Uptime,\n\t\t\t\t},\n\t\t\t\tmap[string]string{\"url\": url},\n\t\t\t\tnow,\n\t\t\t)\n\t\t\tcontinue\n\t\tcase \"memstats\":\n\t\t\tvar m memstats\n\t\t\tif err := dec.Decode(&m); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tacc.AddFields(\"influxdb_memstats\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"alloc\":           m.Alloc,\n\t\t\t\t\t\"total_alloc\":     m.TotalAlloc,\n\t\t\t\t\t\"sys\":             m.Sys,\n\t\t\t\t\t\"lookups\":         m.Lookups,\n\t\t\t\t\t\"mallocs\":         m.Mallocs,\n\t\t\t\t\t\"frees\":           m.Frees,\n\t\t\t\t\t\"heap_alloc\":      m.HeapAlloc,\n\t\t\t\t\t\"heap_sys\":        m.HeapSys,\n\t\t\t\t\t\"heap_idle\":       m.HeapIdle,\n\t\t\t\t\t\"heap_inuse\":      m.HeapInuse,\n\t\t\t\t\t\"heap_released\":   m.HeapReleased,\n\t\t\t\t\t\"heap_objects\":    m.HeapObjects,\n\t\t\t\t\t\"stack_inuse\":     m.StackInuse,\n\t\t\t\t\t\"stack_sys\":       m.StackSys,\n\t\t\t\t\t\"mspan_inuse\":     m.MSpanInuse,\n\t\t\t\t\t\"mspan_sys\":       m.MSpanSys,\n\t\t\t\t\t\"mcache_inuse\":    m.MCacheInuse,\n\t\t\t\t\t\"mcache_sys\":      m.MCacheSys,\n\t\t\t\t\t\"buck_hash_sys\":   m.BuckHashSys,\n\t\t\t\t\t\"gc_sys\":          m.GCSys,\n\t\t\t\t\t\"other_sys\":       m.OtherSys,\n\t\t\t\t\t\"next_gc\":         m.NextGC,\n\t\t\t\t\t\"last_gc\":         m.LastGC,\n\t\t\t\t\t\"pause_total_ns\":  m.PauseTotalNs,\n\t\t\t\t\t\"pause_ns\":        m.PauseNs[(m.NumGC+255)%256],\n\t\t\t\t\t\"num_gc\":          m.NumGC,\n\t\t\t\t\t\"gc_cpu_fraction\": m.GCCPUFraction,\n\t\t\t\t},\n\t\t\t\tmap[string]string{\"url\": url},\n\t\t\t\tnow,\n\t\t\t)\n\t\tcase \"build\":\n\t\t\tvar d build\n\t\t\tif err := dec.Decode(&d); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tacc.AddFields(\"influxdb_build\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"branch\":     d.Branch,\n\t\t\t\t\t\"build_time\": d.BuildTime,\n\t\t\t\t\t\"commit\":     d.Commit,\n\t\t\t\t\t\"version\":    d.Version,\n\t\t\t\t},\n\t\t\t\tmap[string]string{\"url\": url},\n\t\t\t\tnow,\n\t\t\t)\n\t\tcase \"cmdline\":\n\t\t\tvar d []string\n\t\t\tif err := dec.Decode(&d); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tacc.AddFields(\"influxdb_cmdline\",\n\t\t\t\tmap[string]interface{}{\"value\": strings.Join(d, \" \")},\n\t\t\t\tmap[string]string{\"url\": url},\n\t\t\t\tnow,\n\t\t\t)\n\t\tcase \"crypto\":\n\t\t\tvar d crypto\n\t\t\tif err := dec.Decode(&d); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tacc.AddFields(\"influxdb_crypto\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"fips\":           d.FIPS,\n\t\t\t\t\t\"ensure_fips\":    d.EnsureFIPS,\n\t\t\t\t\t\"implementation\": d.Implementation,\n\t\t\t\t\t\"password_hash\":  d.PasswordHash,\n\t\t\t\t},\n\t\t\t\tmap[string]string{\"url\": url},\n\t\t\t\tnow,\n\t\t\t)\n\t\tdefault:\n\t\t\t// Attempt to parse all other entires as an object into a point.\n\t\t\t// Ignore all non-object entries (like a string or array) or\n\t\t\t// entries not conforming to a \"point\" structure and move on.\n\t\t\tvar p point\n\t\t\tif err := dec.Decode(&p); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If the object was a point, but was not fully initialized,\n\t\t\t// ignore it and move on.\n\t\t\tif p.Name == \"\" || p.Values == nil || len(p.Values) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif p.Name == \"shard\" {\n\t\t\t\tshardCounter++\n\t\t\t}\n\n\t\t\t// Add a tag to indicate the source of the data.\n\t\t\tif p.Tags == nil {\n\t\t\t\tp.Tags = make(map[string]string)\n\t\t\t}\n\t\t\tp.Tags[\"url\"] = url\n\n\t\t\tacc.AddFields(\"influxdb_\"+p.Name, p.Values, p.Tags, now)\n\t\t}\n\t}\n\n\t// Add a metric for the number of shards\n\tacc.AddFields(\"influxdb\", map[string]interface{}{\"n_shards\": shardCounter}, nil, now)\n\n\treturn nil\n}\n\nfunc readResponseError(resp *http.Response) error {\n\tapiErr := &apiError{\n\t\tStatusCode: resp.StatusCode,\n\t\tReason:     resp.Status,\n\t}\n\n\tvar buf bytes.Buffer\n\tr := io.LimitReader(resp.Body, maxErrorResponseBodyLength)\n\t_, err := buf.ReadFrom(r)\n\tif err != nil {\n\t\treturn apiErr\n\t}\n\n\terr = json.Unmarshal(buf.Bytes(), apiErr)\n\tif err != nil {\n\t\treturn apiErr\n\t}\n\n\treturn apiErr\n}\n\nfunc init() {\n\tinputs.Add(\"influxdb\", func() telegraf.Input {\n\t\treturn &InfluxDB{\n\t\t\tTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb/influxdb_test.go",
    "content": "package influxdb\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestBasic(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(basicJSON)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{fakeServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.Len(t, acc.Metrics, 3)\n\tfields := map[string]interface{}{\n\t\t// JSON will truncate floats to integer representations.\n\t\t// Since there's no distinction in JSON, we can't assume it's an int.\n\t\t\"i\": -1.0,\n\t\t\"f\": 0.5,\n\t\t\"b\": true,\n\t\t\"s\": \"string\",\n\t}\n\ttags := map[string]string{\n\t\t\"id\":  \"ex1\",\n\t\t\"url\": fakeServer.URL + \"/endpoint\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"influxdb_foo\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"x\": \"x\",\n\t}\n\ttags = map[string]string{\n\t\t\"id\":  \"ex2\",\n\t\t\"url\": fakeServer.URL + \"/endpoint\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"influxdb_bar\", fields, tags)\n\n\tacc.AssertContainsTaggedFields(t, \"influxdb\",\n\t\tmap[string]interface{}{\n\t\t\t\"n_shards\": 0,\n\t\t}, map[string]string{})\n}\n\nfunc TestInfluxDB(t *testing.T) {\n\tinfluxReturn, err := os.ReadFile(\"./testdata/influx_return.json\")\n\trequire.NoError(t, err)\n\n\tfakeInfluxServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write(influxReturn); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeInfluxServer.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{fakeInfluxServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.Len(t, acc.Metrics, 36)\n\n\tfields := map[string]interface{}{\n\t\t\"heap_inuse\":      int64(18046976),\n\t\t\"heap_released\":   int64(3473408),\n\t\t\"mspan_inuse\":     int64(97440),\n\t\t\"total_alloc\":     int64(201739016),\n\t\t\"sys\":             int64(38537464),\n\t\t\"mallocs\":         int64(570251),\n\t\t\"frees\":           int64(381008),\n\t\t\"heap_idle\":       int64(15802368),\n\t\t\"pause_total_ns\":  int64(5132914),\n\t\t\"pause_ns\":        int64(127053),\n\t\t\"lookups\":         int64(77),\n\t\t\"heap_sys\":        int64(33849344),\n\t\t\"mcache_sys\":      int64(16384),\n\t\t\"next_gc\":         int64(20843042),\n\t\t\"gc_cpu_fraction\": float64(4.287178819113636e-05),\n\t\t\"other_sys\":       int64(1229737),\n\t\t\"alloc\":           int64(17034016),\n\t\t\"stack_inuse\":     int64(753664),\n\t\t\"stack_sys\":       int64(753664),\n\t\t\"buck_hash_sys\":   int64(1461583),\n\t\t\"gc_sys\":          int64(1112064),\n\t\t\"num_gc\":          int64(27),\n\t\t\"heap_alloc\":      int64(17034016),\n\t\t\"heap_objects\":    int64(189243),\n\t\t\"mspan_sys\":       int64(114688),\n\t\t\"mcache_inuse\":    int64(4800),\n\t\t\"last_gc\":         int64(1460434886475114239),\n\t}\n\n\ttags := map[string]string{\n\t\t\"url\": fakeInfluxServer.URL + \"/endpoint\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"influxdb_memstats\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"current_time\": \"2023-01-11T16:51:52.723166944Z\",\n\t\t\"started\":      \"2023-01-11T16:51:23.355766023Z\",\n\t\t\"uptime\":       uint64(29),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"influxdb_system\", fields, tags)\n\n\tacc.AssertContainsTaggedFields(t, \"influxdb\",\n\t\tmap[string]interface{}{\n\t\t\t\"n_shards\": 1,\n\t\t}, map[string]string{})\n}\n\nfunc TestInfluxDB2(t *testing.T) {\n\t// InfluxDB 1.0+ with tags: null instead of tags: {}.\n\tinfluxReturn2, err := os.ReadFile(\"./testdata/influx_return2.json\")\n\trequire.NoError(t, err)\n\n\tfakeInfluxServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write(influxReturn2); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeInfluxServer.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{fakeInfluxServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.Len(t, acc.Metrics, 36)\n\n\tacc.AssertContainsTaggedFields(t, \"influxdb\",\n\t\tmap[string]interface{}{\n\t\t\t\"n_shards\": 1,\n\t\t}, map[string]string{})\n\n\tfields := map[string]interface{}{\n\t\t\"current_time\": \"2023-01-11T17:04:59.928454705Z\",\n\t\t\"started\":      \"2023-01-11T16:51:23.355766023Z\",\n\t\t\"uptime\":       uint64(816),\n\t}\n\ttags := map[string]string{\n\t\t\"url\": fakeInfluxServer.URL + \"/endpoint\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"influxdb_system\", fields, tags)\n}\n\nfunc TestCloud1(t *testing.T) {\n\t// Setup a fake endpoint with the input data\n\tinput, err := os.ReadFile(\"./testdata/cloud1.json\")\n\trequire.NoError(t, err)\n\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write(input); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\t// Setup the plugin\n\tplugin := &InfluxDB{\n\t\tURLs: []string{server.URL + \"/endpoint\"},\n\t}\n\n\t// Gather the data\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t// Read the expected data\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tbuf, err := os.ReadFile(\"./testdata/cloud1.influx\")\n\trequire.NoError(t, err)\n\texpected, err := parser.Parse(buf)\n\trequire.NoError(t, err)\n\n\t// Check the output\n\topts := []cmp.Option{testutil.IgnoreTags(\"url\"), testutil.IgnoreTime()}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, opts...)\n}\n\nfunc TestErrorHandling(t *testing.T) {\n\tbadServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(\"not json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer badServer.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{badServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestErrorHandling404(t *testing.T) {\n\tbadServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(basicJSON)); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer badServer.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{badServer.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, acc.GatherError(plugin.Gather))\n}\n\nfunc TestErrorResponse(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\tif _, err := w.Write([]byte(`{\"error\": \"unable to parse authentication credentials\"}`)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tplugin := &InfluxDB{\n\t\tURLs: []string{ts.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpected := []error{\n\t\t&apiError{\n\t\t\tStatusCode:  http.StatusUnauthorized,\n\t\t\tReason:      fmt.Sprintf(\"%d %s\", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),\n\t\t\tDescription: \"unable to parse authentication credentials\",\n\t\t},\n\t}\n\trequire.Equal(t, expected, acc.Errors)\n}\n\nconst basicJSON = `\n{\n  \"_1\": {\n    \"name\": \"foo\",\n    \"tags\": {\n      \"id\": \"ex1\"\n    },\n    \"values\": {\n      \"i\": -1,\n      \"f\": 0.5,\n      \"b\": true,\n      \"s\": \"string\"\n    }\n  },\n  \"ignored\": {\n    \"willBeRecorded\": false\n  },\n  \"ignoredAndNested\": {\n    \"hash\": {\n      \"is\": \"nested\"\n    }\n  },\n  \"array\": [\n   \"makes parsing more difficult than necessary\"\n  ],\n  \"string\": \"makes parsing more difficult than necessary\",\n  \"_2\": {\n    \"name\": \"bar\",\n    \"tags\": {\n      \"id\": \"ex2\"\n    },\n    \"values\": {\n      \"x\": \"x\"\n    }\n  },\n  \"pointWithoutFields_willNotBeIncluded\": {\n    \"name\": \"asdf\",\n    \"tags\": {\n      \"id\": \"ex3\"\n    },\n    \"values\": {}\n  }\n}\n`\n"
  },
  {
    "path": "plugins/inputs/influxdb/sample.conf",
    "content": "# Read InfluxDB-formatted JSON metrics from one or more HTTP endpoints\n[[inputs.influxdb]]\n  ## Works with InfluxDB debug endpoints out of the box,\n  ## but other services can use this format too.\n  ## See the influxdb plugin's README for more details.\n\n  ## Multiple URLs from which to read InfluxDB-formatted JSON\n  ## Default is \"http://localhost:8086/debug/vars\".\n  urls = [\n    \"http://localhost:8086/debug/vars\"\n  ]\n\n  ## Username and password to send using HTTP Basic Authentication.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## http request & header timeout\n  timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/influxdb/testdata/cloud1.influx",
    "content": "influxdb_system,url=http://127.0.0.1:36225/endpoint current_time=\"2024-05-31T12:51:46.089414837Z\",started=\"2024-05-31T07:00:46.920991868Z\",uptime=21059u 1717163790675899148\ninfluxdb_build,url=http://127.0.0.1:36225/endpoint branch=\"unknown\",build_time=\"\",commit=\"d97e21d4473164bb3ba0055ecd1971f2529b6d82\",version=\"v1.11.5\" 1717163790675899148\ninfluxdb_cmdline,url=http://127.0.0.1:36225/endpoint value=\"influxd\" 1717163790675899148\ninfluxdb_crypto,url=http://127.0.0.1:36225/endpoint ensure_fips=false,fips=false,implementation=\"Go\",password_hash=\"bcrypt;cost=10\" 1717163790675899148\ninfluxdb_memstats,url=http://127.0.0.1:36225/endpoint alloc=181164560i,buck_hash_sys=1985478i,frees=123761313i,gc_cpu_fraction=0.0007163177127655092,gc_sys=17702472i,heap_alloc=181164560i,heap_idle=183099392i,heap_inuse=197566464i,heap_objects=1338818i,heap_released=163487744i,heap_sys=380665856i,last_gc=1717159890037272716i,lookups=0i,mallocs=125100131i,mcache_inuse=14400i,mcache_sys=15600i,mspan_inuse=2025760i,mspan_sys=4047360i,next_gc=199979240i,num_gc=1630i,other_sys=2320474i,pause_ns=56843i,pause_total_ns=184808571i,stack_inuse=5210112i,stack_sys=5210112i,sys=411947352i,total_alloc=173073072024i 1717163790675899148\ninfluxdb_runtime,url=http://127.0.0.1:36225/endpoint Alloc=179303856,Frees=123761213,HeapAlloc=179303856,HeapIdle=184877056,HeapInUse=195788800,HeapObjects=1337095,HeapReleased=163487744,HeapSys=380665856,Lookups=0,Mallocs=125098308,NumGC=1630,NumGoroutine=1488,PauseTotalNs=184808571,Sys=411947352,TotalAlloc=173071211320 1717163790675899148\ninfluxdb_queryExecutor,url=http://127.0.0.1:36225/endpoint queriesActive=0,queriesExecuted=6149,queriesFinished=6149,queryDurationNs=747054059,recoveredPanics=0 1717163790675899148\ninfluxdb_database,database=new_db,url=http://127.0.0.1:36225/endpoint numMeasurements=5,numSeries=78 1717163790675899148\ninfluxdb_database,database=c152-zabbix-prd,url=http://127.0.0.1:36225/endpoint numMeasurements=2,numSeries=1501 1717163790675899148\ninfluxdb_database,database=_internal,url=http://127.0.0.1:36225/endpoint numMeasurements=21,numSeries=490 1717163790675899148\ninfluxdb_database,database=chronograf,url=http://127.0.0.1:36225/endpoint numMeasurements=1,numSeries=62 1717163790675899148\ninfluxdb_database,database=export_test_2,url=http://127.0.0.1:36225/endpoint numMeasurements=1,numSeries=36 1717163790675899148\ninfluxdb_database,database=c152-zabbix-hpr,url=http://127.0.0.1:36225/endpoint numMeasurements=1,numSeries=15000 1717163790675899148\ninfluxdb_database,database=autogen,url=http://127.0.0.1:36225/endpoint numMeasurements=4,numSeries=43 1717163790675899148\ninfluxdb_database,database=export_test,url=http://127.0.0.1:36225/endpoint numMeasurements=1,numSeries=37 1717163790675899148\ninfluxdb_database,database=telegraf,url=http://127.0.0.1:36225/endpoint numMeasurements=47,numSeries=618 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=2,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/2 diskBytes=31791,fieldsCreate=0,seriesCreate=18,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=2,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/2 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=2,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/2 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=2,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/2 diskBytes=31791,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=2,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/2,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/2 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=c152-zabbix-hpr,engine=tsm1,id=5241,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241 diskBytes=1518907,fieldsCreate=0,seriesCreate=15000,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=c152-zabbix-hpr,engine=tsm1,id=5241,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=c152-zabbix-hpr,engine=tsm1,id=5241,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=c152-zabbix-hpr,engine=tsm1,id=5241,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241 diskBytes=1518907,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=c152-zabbix-hpr,engine=tsm1,id=5241,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=c152-zabbix-prd,engine=tsm1,id=5242,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242 diskBytes=55826004,fieldsCreate=0,seriesCreate=1501,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=c152-zabbix-prd,engine=tsm1,id=5242,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=c152-zabbix-prd,engine=tsm1,id=5242,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=c152-zabbix-prd,engine=tsm1,id=5242,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242 diskBytes=55826004,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=c152-zabbix-prd,engine=tsm1,id=5242,indexType=inmem,path=/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=telegraf,engine=tsm1,id=5260,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5260,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5260 diskBytes=902338,fieldsCreate=0,seriesCreate=264,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=telegraf,engine=tsm1,id=5260,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5260,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5260 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=telegraf,engine=tsm1,id=5260,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5260,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5260 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=telegraf,engine=tsm1,id=5260,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5260,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5260 diskBytes=902338,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=telegraf,engine=tsm1,id=5260,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5260,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5260 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=telegraf,engine=tsm1,id=5272,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5272,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5272 diskBytes=306602401,fieldsCreate=0,seriesCreate=383,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=telegraf,engine=tsm1,id=5272,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5272,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5272 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=telegraf,engine=tsm1,id=5272,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5272,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5272 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=telegraf,engine=tsm1,id=5272,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5272,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5272 diskBytes=306602401,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=telegraf,engine=tsm1,id=5272,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5272,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5272 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=telegraf,engine=tsm1,id=5286,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5286,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5286 diskBytes=119528786,fieldsCreate=0,seriesCreate=485,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=telegraf,engine=tsm1,id=5286,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5286,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5286 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=telegraf,engine=tsm1,id=5286,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5286,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5286 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=telegraf,engine=tsm1,id=5286,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5286,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5286 diskBytes=119528786,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=telegraf,engine=tsm1,id=5286,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5286,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5286 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=chronograf,engine=tsm1,id=5287,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5287,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5287 diskBytes=976751,fieldsCreate=0,seriesCreate=53,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=chronograf,engine=tsm1,id=5287,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5287,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5287 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=chronograf,engine=tsm1,id=5287,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5287,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5287 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=chronograf,engine=tsm1,id=5287,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5287,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5287 diskBytes=976751,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=chronograf,engine=tsm1,id=5287,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5287,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5287 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test,engine=tsm1,id=5292,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5292,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5292 diskBytes=179683,fieldsCreate=0,seriesCreate=24,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test,engine=tsm1,id=5292,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5292,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5292 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test,engine=tsm1,id=5292,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5292,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5292 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test,engine=tsm1,id=5292,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5292,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5292 diskBytes=179683,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test,engine=tsm1,id=5292,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5292,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5292 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test,engine=tsm1,id=5293,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5293,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5293 diskBytes=4645612,fieldsCreate=0,seriesCreate=32,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test,engine=tsm1,id=5293,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5293,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5293 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test,engine=tsm1,id=5293,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5293,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5293 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test,engine=tsm1,id=5293,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5293,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5293 diskBytes=4645612,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test,engine=tsm1,id=5293,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5293,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5293 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test,engine=tsm1,id=5294,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5294,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5294 diskBytes=1618920,fieldsCreate=0,seriesCreate=1,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test,engine=tsm1,id=5294,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5294,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5294 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test,engine=tsm1,id=5294,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5294,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5294 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test,engine=tsm1,id=5294,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5294,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5294 diskBytes=1618920,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test,engine=tsm1,id=5294,indexType=inmem,path=/var/lib/influxdb/data/export_test/autogen/5294,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test/autogen/5294 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test_2,engine=tsm1,id=5295,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5295,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5295 diskBytes=44956319,fieldsCreate=0,seriesCreate=31,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test_2,engine=tsm1,id=5295,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5295,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5295 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test_2,engine=tsm1,id=5295,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5295,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5295 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test_2,engine=tsm1,id=5295,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5295,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5295 diskBytes=44956319,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test_2,engine=tsm1,id=5295,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5295,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5295 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test_2,engine=tsm1,id=5296,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5296,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5296 diskBytes=169033,fieldsCreate=0,seriesCreate=23,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test_2,engine=tsm1,id=5296,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5296,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5296 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test_2,engine=tsm1,id=5296,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5296,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5296 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test_2,engine=tsm1,id=5296,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5296,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5296 diskBytes=169033,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test_2,engine=tsm1,id=5296,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5296,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5296 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=export_test_2,engine=tsm1,id=5297,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5297,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5297 diskBytes=21805340,fieldsCreate=0,seriesCreate=31,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=export_test_2,engine=tsm1,id=5297,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5297,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5297 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=export_test_2,engine=tsm1,id=5297,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5297,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5297 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=export_test_2,engine=tsm1,id=5297,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5297,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5297 diskBytes=21805340,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=export_test_2,engine=tsm1,id=5297,indexType=inmem,path=/var/lib/influxdb/data/export_test_2/autogen/5297,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/export_test_2/autogen/5297 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=new_db,engine=tsm1,id=5300,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5300,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5300 diskBytes=50109,fieldsCreate=0,seriesCreate=19,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=new_db,engine=tsm1,id=5300,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5300,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5300 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=new_db,engine=tsm1,id=5300,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5300,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5300 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=new_db,engine=tsm1,id=5300,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5300,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5300 diskBytes=50109,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=new_db,engine=tsm1,id=5300,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5300,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5300 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=new_db,engine=tsm1,id=5301,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5301,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5301 diskBytes=216083,fieldsCreate=0,seriesCreate=63,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=new_db,engine=tsm1,id=5301,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5301,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5301 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=new_db,engine=tsm1,id=5301,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5301,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5301 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=new_db,engine=tsm1,id=5301,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5301,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5301 diskBytes=216083,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=new_db,engine=tsm1,id=5301,indexType=inmem,path=/var/lib/influxdb/data/new_db/autogen/5301,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/new_db/autogen/5301 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=autogen,engine=tsm1,id=5303,indexType=inmem,path=/var/lib/influxdb/data/autogen/5301/5303,retentionPolicy=5301,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5301/5303 diskBytes=113590,fieldsCreate=0,seriesCreate=32,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=autogen,engine=tsm1,id=5303,indexType=inmem,path=/var/lib/influxdb/data/autogen/5301/5303,retentionPolicy=5301,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5301/5303 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=autogen,engine=tsm1,id=5303,indexType=inmem,path=/var/lib/influxdb/data/autogen/5301/5303,retentionPolicy=5301,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5301/5303 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=autogen,engine=tsm1,id=5303,indexType=inmem,path=/var/lib/influxdb/data/autogen/5301/5303,retentionPolicy=5301,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5301/5303 diskBytes=113590,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=autogen,engine=tsm1,id=5303,indexType=inmem,path=/var/lib/influxdb/data/autogen/5301/5303,retentionPolicy=5301,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5301/5303 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=autogen,engine=tsm1,id=5304,indexType=inmem,path=/var/lib/influxdb/data/autogen/5300/5304,retentionPolicy=5300,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5300/5304 diskBytes=28869,fieldsCreate=0,seriesCreate=11,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=autogen,engine=tsm1,id=5304,indexType=inmem,path=/var/lib/influxdb/data/autogen/5300/5304,retentionPolicy=5300,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5300/5304 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=autogen,engine=tsm1,id=5304,indexType=inmem,path=/var/lib/influxdb/data/autogen/5300/5304,retentionPolicy=5300,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5300/5304 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=autogen,engine=tsm1,id=5304,indexType=inmem,path=/var/lib/influxdb/data/autogen/5300/5304,retentionPolicy=5300,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5300/5304 diskBytes=28869,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=autogen,engine=tsm1,id=5304,indexType=inmem,path=/var/lib/influxdb/data/autogen/5300/5304,retentionPolicy=5300,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/autogen/5300/5304 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=5306,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5306,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5306 diskBytes=1592566,fieldsCreate=0,seriesCreate=234,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=5306,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5306,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5306 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=5306,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5306,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5306 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=5306,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5306,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5306 diskBytes=1592566,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=5306,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5306,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5306 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=telegraf,engine=tsm1,id=5308,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5308,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5308 diskBytes=100862151,fieldsCreate=0,seriesCreate=530,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=675020,writeReq=5266,writeReqErr=0,writeReqOk=5266,writeValuesOk=3921076 1717163790675899148\ninfluxdb_tsm1_engine,database=telegraf,engine=tsm1,id=5308,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5308,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5308 cacheCompactionDuration=227545878,cacheCompactionErr=0,cacheCompactions=3,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=telegraf,engine=tsm1,id=5308,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5308,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5308 WALCompactionTimeMs=225,cacheAgeMs=4014989,cachedBytes=78680027,diskBytes=0,memBytes=12995909,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=7284 1717163790675899148\ninfluxdb_tsm1_filestore,database=telegraf,engine=tsm1,id=5308,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5308,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5308 diskBytes=89546900,numFiles=8 1717163790675899148\ninfluxdb_tsm1_wal,database=telegraf,engine=tsm1,id=5308,indexType=inmem,path=/var/lib/influxdb/data/telegraf/autogen/5308,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/telegraf/autogen/5308 currentSegmentDiskBytes=801802,oldSegmentsDiskBytes=10513449,writeErr=0,writeOk=5266 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=5310,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5310,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5310 diskBytes=1185091,fieldsCreate=0,seriesCreate=219,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=5310,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5310,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5310 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=5310,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5310,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5310 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=5310,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5310,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5310 diskBytes=1185091,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=5310,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5310,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5310 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=chronograf,engine=tsm1,id=5311,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5311,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5311 diskBytes=9601170,fieldsCreate=0,seriesCreate=61,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=3122,writeReq=803,writeReqErr=0,writeReqOk=803,writeValuesOk=9366 1717163790675899148\ninfluxdb_tsm1_engine,database=chronograf,engine=tsm1,id=5311,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5311,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5311 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=chronograf,engine=tsm1,id=5311,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5311,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5311 WALCompactionTimeMs=0,cacheAgeMs=21058577,cachedBytes=0,diskBytes=0,memBytes=4676116,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=11354 1717163790675899148\ninfluxdb_tsm1_filestore,database=chronograf,engine=tsm1,id=5311,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5311,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5311 diskBytes=0,numFiles=0 1717163790675899148\ninfluxdb_tsm1_wal,database=chronograf,engine=tsm1,id=5311,indexType=inmem,path=/var/lib/influxdb/data/chronograf/autogen/5311,retentionPolicy=autogen,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/chronograf/autogen/5311 currentSegmentDiskBytes=4982276,oldSegmentsDiskBytes=4618894,writeErr=0,writeOk=803 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=5313,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5313,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5313 diskBytes=1978014,fieldsCreate=0,seriesCreate=205,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=5313,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5313,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5313 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=5313,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5313,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5313 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=5313,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5313,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5313 diskBytes=1978014,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=5313,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5313,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5313 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=5314,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5314,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5314 diskBytes=3113562,fieldsCreate=0,seriesCreate=230,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=0,writeReq=0,writeReqErr=0,writeReqOk=0,writeValuesOk=0 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=5314,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5314,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5314 cacheCompactionDuration=0,cacheCompactionErr=0,cacheCompactions=0,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=5314,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5314,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5314 WALCompactionTimeMs=0,cacheAgeMs=0,cachedBytes=0,diskBytes=0,memBytes=0,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=5314,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5314,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5314 diskBytes=3113562,numFiles=1 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=5314,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5314,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5314 currentSegmentDiskBytes=0,oldSegmentsDiskBytes=0,writeErr=0,writeOk=0 1717163790675899148\ninfluxdb_shard,database=_internal,engine=tsm1,id=5316,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5316,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5316 diskBytes=5400093,fieldsCreate=0,seriesCreate=229,writeBytes=0,writePointsDropped=0,writePointsErr=0,writePointsOk=471520,writeReq=8420,writeReqErr=0,writeReqOk=8420,writeValuesOk=3749005 1717163790675899148\ninfluxdb_tsm1_engine,database=_internal,engine=tsm1,id=5316,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5316,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5316 cacheCompactionDuration=137702326,cacheCompactionErr=0,cacheCompactions=3,cacheCompactionsActive=0,tsmFullCompactionDuration=0,tsmFullCompactionErr=0,tsmFullCompactionQueue=0,tsmFullCompactions=0,tsmFullCompactionsActive=0,tsmLevel1CompactionDuration=0,tsmLevel1CompactionErr=0,tsmLevel1CompactionQueue=0,tsmLevel1Compactions=0,tsmLevel1CompactionsActive=0,tsmLevel2CompactionDuration=0,tsmLevel2CompactionErr=0,tsmLevel2CompactionQueue=0,tsmLevel2Compactions=0,tsmLevel2CompactionsActive=0,tsmLevel3CompactionDuration=0,tsmLevel3CompactionErr=0,tsmLevel3CompactionQueue=0,tsmLevel3Compactions=0,tsmLevel3CompactionsActive=0,tsmOptimizeCompactionDuration=0,tsmOptimizeCompactionErr=0,tsmOptimizeCompactionQueue=0,tsmOptimizeCompactions=0,tsmOptimizeCompactionsActive=0 1717163790675899148\ninfluxdb_tsm1_cache,database=_internal,engine=tsm1,id=5316,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5316,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5316 WALCompactionTimeMs=147,cacheAgeMs=234999,cachedBytes=81895372,diskBytes=0,memBytes=1105118,snapshotCount=0,writeDropped=0,writeErr=0,writeOk=11318 1717163790675899148\ninfluxdb_tsm1_filestore,database=_internal,engine=tsm1,id=5316,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5316,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5316 diskBytes=4250699,numFiles=6 1717163790675899148\ninfluxdb_tsm1_wal,database=_internal,engine=tsm1,id=5316,indexType=inmem,path=/var/lib/influxdb/data/_internal/monitor/5316,retentionPolicy=monitor,url=http://127.0.0.1:36225/endpoint,walPath=/var/lib/influxdb/wal/_internal/monitor/5316 currentSegmentDiskBytes=1149394,oldSegmentsDiskBytes=0,writeErr=0,writeOk=8420 1717163790675899148\ninfluxdb_localStore,url=http://127.0.0.1:36225/endpoint pointsWritten=1149662,seriesCreated=0,valuesWritten=7679447 1717163790675899148\ninfluxdb_write,url=http://127.0.0.1:36225/endpoint pointReq=787963,pointReqHH=0,pointReqLocal=577463,pointReqRemote=554308,req=7231,subWriteOk=7231,writeDrop=0,writeError=0,writeOk=11441,writePartial=0,writeTimeout=0 1717163790675899148\ninfluxdb_hh,path=/var/lib/influxdb/hh,url=http://127.0.0.1:36225/endpoint bytesRead=0,bytesWritten=0,queueBytes=0,queueDepth=0,writeBlocked=0,writeDropped=0,writeNodeReq=0,writeNodeReqFail=0,writeNodeReqPoints=0,writeShardReq=0,writeShardReqPoints=0 1717163790675899148\ninfluxdb_hh_processor,node=none,shardID=none,url=http://127.0.0.1:36225/endpoint bytesRead=0,bytesWritten=0,queueBytes=0,queueDepth=0,writeBlocked=0,writeDropped=0,writeNodeReq=0,writeNodeReqFail=0,writeNodeReqPoints=0,writeShardReq=0,writeShardReqPoints=0 1717163790675899148\ninfluxdb_hh_node,node=none,url=http://127.0.0.1:36225/endpoint queueTotalSize=0 1717163790675899148\ninfluxdb_subscriber,url=http://127.0.0.1:36225/endpoint createFailures=0,memUsage=0,pointsWritten=787963,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-sri-rxw-wifi-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-datacenter-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-qos-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=export_test_2,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c152-zabbix-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-rapi_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-rxw_awx-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-genesys-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-qos-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c999-qos-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c023-zabbix-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=_internal,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=monitor,url=http://127.0.0.1:36225/endpoint pointsWritten=444155,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=autogen,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=autogen,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=5301,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c152-zabbix-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-appl_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-supr_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c999-mtroapi-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-opn-carema-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-zabbix-prd-new,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=export_test,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-tech_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-telephonie-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-routeur_npc-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-datacenter-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c999-mtroapi-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=chronograf,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=1586,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=telegraf,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=342222,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-opn-carema-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-opn-opr-dynatrace-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=new_db,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-mtrm_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c700-bcr-sup2_tsdb-prd,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=c152-dncl-hpr,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=autogen,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_subscriber,database=autogen,destination=http://kapacitor:9092,mode=ANY,name=kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9,retention_policy=5300,url=http://127.0.0.1:36225/endpoint pointsWritten=0,writeFailures=0 1717163790675899148\ninfluxdb_rpc,url=http://127.0.0.1:36225/endpoint idleStreams=2,liveConnections=1,liveStreams=2,rpcCalls=146231,rpcFailures=0,rpcReadBytes=3941135770,rpcRetries=0,rpcWriteBytes=185033228,singleUse=0,singleUseOpen=0,totalConnections=1,totalStreams=2 1717163790675899148\ninfluxdb_entitlements,url=http://127.0.0.1:36225/endpoint licenseExpiry=\"2112-01-01T00:00:00Z\",licenseType=\"license-file\" 1717163790675899148\ninfluxdb_cluster,url=http://127.0.0.1:36225/endpoint copyShardReq=0,createIteratorReq=0,expandSourcesReq=0,fieldDimensionsReq=0,iteratorCostReq=0,openConnections=2,removeShardReq=0,storeReadFilterReq=0,storeReadGroupReq=0,storeReadWindowAggregateReq=0,writeShardFail=0,writeShardPointsReq=572199,writeShardReq=7258 1717163790675899148\ninfluxdb_cq,url=http://127.0.0.1:36225/endpoint queryFail=0,queryOk=0 1717163790675899148\ninfluxdb_httpd,bind=:8086,url=http://127.0.0.1:36225/endpoint authFail=0,clientError=0,fluxQueryReq=0,fluxQueryReqDurationNs=0,pingReq=871,pointsWrittenDropped=0,pointsWrittenFail=0,pointsWrittenOK=343808,promReadReq=0,promWriteReq=0,queryReq=6149,queryReqDurationNs=2612667879,queryRespBytes=2331498,recoveredPanics=0,req=12370,reqActive=2,reqDurationNs=9521864530967,serverError=0,statusReq=0,writeReq=3021,writeReqActive=0,writeReqBytes=96773706,writeReqDurationNs=45791403479 1717163790675899148\ninfluxdb_ae,url=http://127.0.0.1:36225/endpoint bytesRx=0,errors=0,jobs=0,jobsActive=0 1717163790675899148\ninfluxdb n_shards=24i 1717163790675899148\n"
  },
  {
    "path": "plugins/inputs/influxdb/testdata/cloud1.json",
    "content": "{\n    \"system\": {\n        \"currentTime\": \"2024-05-31T12:51:46.089414837Z\",\n        \"started\": \"2024-05-31T07:00:46.920991868Z\",\n        \"uptime\": 21059\n    },\n    \"build\": {\n        \"Branch\": \"unknown\",\n        \"Build Time\": \"\",\n        \"Commit\": \"d97e21d4473164bb3ba0055ecd1971f2529b6d82\",\n        \"Version\": \"v1.11.5\"\n    },\n    \"cmdline\": [\n        \"influxd\"\n    ],\n    \"crypto\": {\n        \"FIPS\": false,\n        \"ensureFIPS\": false,\n        \"implementation\": \"Go\",\n        \"passwordHash\": \"bcrypt;cost=10\"\n    },\n    \"memstats\": {\n        \"Alloc\": 181164560,\n        \"TotalAlloc\": 173073072024,\n        \"Sys\": 411947352,\n        \"Lookups\": 0,\n        \"Mallocs\": 125100131,\n        \"Frees\": 123761313,\n        \"HeapAlloc\": 181164560,\n        \"HeapSys\": 380665856,\n        \"HeapIdle\": 183099392,\n        \"HeapInuse\": 197566464,\n        \"HeapReleased\": 163487744,\n        \"HeapObjects\": 1338818,\n        \"StackInuse\": 5210112,\n        \"StackSys\": 5210112,\n        \"MSpanInuse\": 2025760,\n        \"MSpanSys\": 4047360,\n        \"MCacheInuse\": 14400,\n        \"MCacheSys\": 15600,\n        \"BuckHashSys\": 1985478,\n        \"GCSys\": 17702472,\n        \"OtherSys\": 2320474,\n        \"NextGC\": 199979240,\n        \"LastGC\": 1717159890037272716,\n        \"PauseTotalNs\": 184808571,\n        \"PauseNs\": [\n            90105,\n            96780,\n            98685,\n            110866,\n            43622,\n            86643,\n            80693,\n            72689,\n            135023,\n            157708,\n            165553,\n            147419,\n            59658,\n            84428,\n            51192,\n            67990,\n            55840,\n            45036,\n            113197,\n            76906,\n            78754,\n            50792,\n            64332,\n            55946,\n            68650,\n            40240,\n            80888,\n            58882,\n            39855,\n            163340,\n            60017,\n            88636,\n            55467,\n            71131,\n            74005,\n            64615,\n            63567,\n            41400,\n            75625,\n            95529,\n            101166,\n            105538,\n            130147,\n            32939,\n            101761,\n            90186,\n            97740,\n            78940,\n            98295,\n            126541,\n            187049,\n            58125,\n            109663,\n            48468,\n            73325,\n            108477,\n            76491,\n            94228,\n            1054467,\n            149535,\n            83152,\n            49861,\n            103739,\n            128328,\n            48175,\n            115582,\n            110660,\n            58315,\n            52606,\n            76606,\n            65263,\n            81791,\n            97260,\n            71718,\n            126695,\n            83579,\n            97065,\n            33323,\n            86992,\n            86129,\n            74894,\n            89058,\n            76296,\n            42210,\n            104881,\n            94049,\n            169408,\n            82636,\n            104374,\n            59006,\n            110343,\n            102769,\n            58587,\n            56843,\n            84948,\n            635656,\n            64811,\n            58876,\n            87561,\n            106167,\n            79116,\n            92142,\n            74542,\n            124111,\n            166846,\n            88845,\n            109022,\n            183444,\n            116806,\n            76656,\n            88990,\n            77574,\n            172111,\n            3294467,\n            67330,\n            127293,\n            132761,\n            138536,\n            86673,\n            165740,\n            74077,\n            87616,\n            114043,\n            95268,\n            132059,\n            97393,\n            80249,\n            113109,\n            91386,\n            112262,\n            121367,\n            148087,\n            94708,\n            88823,\n            223764,\n            151669,\n            92463,\n            114046,\n            237834,\n            118873,\n            326995,\n            124607,\n            111604,\n            81778,\n            124753,\n            108407,\n            89025,\n            195992,\n            124323,\n            74944,\n            82584,\n            141605,\n            104833,\n            106250,\n            296909,\n            174874,\n            72376,\n            163413,\n            162857,\n            168834,\n            54090,\n            92575,\n            64580,\n            129319,\n            121541,\n            129551,\n            55685,\n            253568,\n            142681,\n            74549,\n            84880,\n            189649,\n            77712,\n            71090,\n            135576,\n            89545,\n            101426,\n            84744,\n            98871,\n            50453,\n            150668,\n            207122,\n            167695,\n            114926,\n            92277,\n            62692,\n            89771,\n            126677,\n            49947,\n            132572,\n            83448,\n            88633,\n            88428,\n            130962,\n            41282,\n            208032,\n            157968,\n            103487,\n            109023,\n            244700,\n            196337,\n            135011,\n            52899,\n            499494,\n            154425,\n            83564,\n            108588,\n            181901,\n            87106,\n            149595,\n            189921,\n            87292,\n            111554,\n            93721,\n            70287,\n            91941,\n            318295,\n            103436,\n            135559,\n            112643,\n            165716,\n            169788,\n            191223,\n            81414,\n            47234,\n            114822,\n            91769,\n            142368,\n            57641,\n            85915,\n            84352,\n            123400,\n            138148,\n            94030,\n            107736,\n            68385,\n            174893,\n            96054,\n            101922,\n            52070,\n            131334,\n            101629,\n            195715,\n            51785,\n            140621,\n            271434,\n            105487,\n            90306,\n            227920,\n            146076,\n            144457,\n            87011,\n            108199,\n            992338,\n            240966,\n            133297\n        ],\n        \"PauseEnd\": [\n            1717158528746325583,\n            1717158538938212298,\n            1717158558751512179,\n            1717158568953085345,\n            1717158588638359666,\n            1717158598806203373,\n            1717158618688741772,\n            1717158628864365845,\n            1717158648673890945,\n            1717158658772717679,\n            1717158668879763492,\n            1717158688702098841,\n            1717158698830453685,\n            1717158718663637047,\n            1717158728806100536,\n            1717158748668427414,\n            1717158758825546739,\n            1717158778682556508,\n            1717158788848347114,\n            1717158808739902689,\n            1717158818932334596,\n            1717158838651497164,\n            1717158848896874615,\n            1717158868677285085,\n            1717158878871224021,\n            1717158898654441361,\n            1717158908870708505,\n            1717158928750197978,\n            1717158938909817631,\n            1717158958700674846,\n            1717158968809765484,\n            1717158988712837471,\n            1717158998821708400,\n            1717159018673393939,\n            1717159028805608988,\n            1717159048702426782,\n            1717159058845657587,\n            1717159078669128024,\n            1717159088868797195,\n            1717159108723698019,\n            1717159118900143411,\n            1717159130087263420,\n            1717159148771042117,\n            1717159160026403232,\n            1717159178798793127,\n            1717159198717652838,\n            1717159218688321235,\n            1717159228867701372,\n            1717159248707115815,\n            1717159268713820458,\n            1717159278869861869,\n            1717159298675579993,\n            1717159318659148943,\n            1717159328832924092,\n            1717159348799784464,\n            1717159368727038051,\n            1717159388627061307,\n            1717159398841804261,\n            1717159418696812753,\n            1717159438742211138,\n            1717159455030504796,\n            1717159468827894194,\n            1717159488734987353,\n            1717159508683658383,\n            1717159518815360770,\n            1717159538747718860,\n            1717159550082150383,\n            1717159568751891228,\n            1717159588727403155,\n            1717159608692868717,\n            1717159618879478466,\n            1717159638769922120,\n            1717159658697742344,\n            1717159670024192076,\n            1717159688716249087,\n            1717159698762494827,\n            1717159708797843950,\n            1717159718691082325,\n            1717159728707379656,\n            1717159738820021085,\n            1717159748716130987,\n            1717159758783668733,\n            1717159768833779617,\n            1717159778843760346,\n            1717159796256917854,\n            1717159808640350009,\n            1717159818681492291,\n            1717159828660210260,\n            1717159838747754581,\n            1717159848670270886,\n            1717159858760384435,\n            1717159868783238960,\n            1717159878795921251,\n            1717159890037272716,\n            1717156338854505270,\n            1717156350081685839,\n            1717156368690384142,\n            1717156378772815641,\n            1717156388901240268,\n            1717156398944595997,\n            1717156418715254893,\n            1717156428754133947,\n            1717156438925506874,\n            1717156455070613610,\n            1717156468744064372,\n            1717156478769076597,\n            1717156488911951865,\n            1717156508664209057,\n            1717156518738910015,\n            1717156528825372421,\n            1717156540050924705,\n            1717156550054021684,\n            1717156568737344380,\n            1717156578832097885,\n            1717156588972898264,\n            1717156608637340910,\n            1717156618767897197,\n            1717156628861681331,\n            1717156640053901974,\n            1717156658725340381,\n            1717156668765606570,\n            1717156678926113290,\n            1717156696840316176,\n            1717156708754934026,\n            1717156718816111887,\n            1717156728877690472,\n            1717156748708342234,\n            1717156758798204442,\n            1717156768933167614,\n            1717156787230035341,\n            1717156798744275474,\n            1717156808836899927,\n            1717156818966375758,\n            1717156838673659809,\n            1717156848749760065,\n            1717156858857254661,\n            1717156868910553949,\n            1717156888652746739,\n            1717156898765297897,\n            1717156908800802583,\n            1717156920091771624,\n            1717156938707696325,\n            1717156948784841172,\n            1717156958933549602,\n            1717156978680071474,\n            1717156988761041329,\n            1717156998837454068,\n            1717157010087289651,\n            1717157028682879237,\n            1717157038802284313,\n            1717157048931352835,\n            1717157068675274496,\n            1717157078750397463,\n            1717157088820254164,\n            1717157100111742091,\n            1717157118740258022,\n            1717157128820470654,\n            1717157140057508717,\n            1717157158684972203,\n            1717157168795678264,\n            1717157178848945357,\n            1717157196857468542,\n            1717157208787307084,\n            1717157218966878921,\n            1717157238677076380,\n            1717157248798191563,\n            1717157258927596099,\n            1717157278654177596,\n            1717157288736595750,\n            1717157298833187177,\n            1717157318644034775,\n            1717157328772399878,\n            1717157338937971722,\n            1717157358653245897,\n            1717157368856728985,\n            1717157385088029918,\n            1717157398732933612,\n            1717157408774948423,\n            1717157420063456259,\n            1717157438784100248,\n            1717157448827082777,\n            1717157460082639894,\n            1717157478702379257,\n            1717157488809002422,\n            1717157505071353390,\n            1717157518750997073,\n            1717157528947134260,\n            1717157548705227671,\n            1717157558773886333,\n            1717157568922799444,\n            1717157588730373296,\n            1717157598845910220,\n            1717157618629377843,\n            1717157628729678458,\n            1717157638828938173,\n            1717157658666434359,\n            1717157668820936680,\n            1717157678945393703,\n            1717157698702223952,\n            1717157708829439072,\n            1717157720067048610,\n            1717157738733503882,\n            1717157748779586478,\n            1717157760051297180,\n            1717157778746136293,\n            1717157788946121571,\n            1717157808686843158,\n            1717157818845924049,\n            1717157828926139849,\n            1717157848730183535,\n            1717157858843748155,\n            1717157878654974700,\n            1717157888792384025,\n            1717157898964528975,\n            1717157918789136728,\n            1717157928931188875,\n            1717157948744900218,\n            1717157958874302932,\n            1717157978716661973,\n            1717157988814946153,\n            1717158008678496169,\n            1717158018773800318,\n            1717158030084025765,\n            1717158048675771185,\n            1717158058832133951,\n            1717158078672955284,\n            1717158088790890126,\n            1717158106953295499,\n            1717158118750217277,\n            1717158129000239659,\n            1717158148761727712,\n            1717158158955982543,\n            1717158178754123995,\n            1717158188857077287,\n            1717158208699159554,\n            1717158218848371136,\n            1717158238684942578,\n            1717158248799803492,\n            1717158268704332709,\n            1717158278822141671,\n            1717158298654844607,\n            1717158308788427883,\n            1717158320074494075,\n            1717158338771030703,\n            1717158348871052305,\n            1717158368712343732,\n            1717158378822258707,\n            1717158398701794584,\n            1717158408820508423,\n            1717158428688158093,\n            1717158438817318407,\n            1717158458648742408,\n            1717158468737851850,\n            1717158480096045554,\n            1717158498781327717,\n            1717158510053011173\n        ],\n        \"NumGC\": 1630,\n        \"NumForcedGC\": 0,\n        \"GCCPUFraction\": 0.0007163177127655092,\n        \"EnableGC\": true,\n        \"DebugGC\": false,\n        \"BySize\": [\n            {\n                \"Size\": 0,\n                \"Mallocs\": 0,\n                \"Frees\": 0\n            },\n            {\n                \"Size\": 8,\n                \"Mallocs\": 797308,\n                \"Frees\": 795058\n            },\n            {\n                \"Size\": 16,\n                \"Mallocs\": 51468998,\n                \"Frees\": 50509285\n            },\n            {\n                \"Size\": 24,\n                \"Mallocs\": 7760387,\n                \"Frees\": 7690779\n            },\n            {\n                \"Size\": 32,\n                \"Mallocs\": 9636564,\n                \"Frees\": 9572913\n            },\n            {\n                \"Size\": 48,\n                \"Mallocs\": 8741288,\n                \"Frees\": 8666828\n            },\n            {\n                \"Size\": 64,\n                \"Mallocs\": 5907340,\n                \"Frees\": 5891334\n            },\n            {\n                \"Size\": 80,\n                \"Mallocs\": 3141812,\n                \"Frees\": 3076069\n            },\n            {\n                \"Size\": 96,\n                \"Mallocs\": 3131131,\n                \"Frees\": 3100403\n            },\n            {\n                \"Size\": 112,\n                \"Mallocs\": 1568633,\n                \"Frees\": 1566257\n            },\n            {\n                \"Size\": 128,\n                \"Mallocs\": 1397034,\n                \"Frees\": 1391152\n            },\n            {\n                \"Size\": 144,\n                \"Mallocs\": 507093,\n                \"Frees\": 500952\n            },\n            {\n                \"Size\": 160,\n                \"Mallocs\": 338497,\n                \"Frees\": 337506\n            },\n            {\n                \"Size\": 176,\n                \"Mallocs\": 123944,\n                \"Frees\": 122792\n            },\n            {\n                \"Size\": 192,\n                \"Mallocs\": 506663,\n                \"Frees\": 506160\n            },\n            {\n                \"Size\": 208,\n                \"Mallocs\": 99248,\n                \"Frees\": 97697\n            },\n            {\n                \"Size\": 224,\n                \"Mallocs\": 88843,\n                \"Frees\": 88518\n            },\n            {\n                \"Size\": 240,\n                \"Mallocs\": 1729997,\n                \"Frees\": 1728387\n            },\n            {\n                \"Size\": 256,\n                \"Mallocs\": 1113931,\n                \"Frees\": 1112414\n            },\n            {\n                \"Size\": 288,\n                \"Mallocs\": 10133675,\n                \"Frees\": 10123190\n            },\n            {\n                \"Size\": 320,\n                \"Mallocs\": 4658954,\n                \"Frees\": 4654429\n            },\n            {\n                \"Size\": 352,\n                \"Mallocs\": 614870,\n                \"Frees\": 614395\n            },\n            {\n                \"Size\": 384,\n                \"Mallocs\": 403757,\n                \"Frees\": 403010\n            },\n            {\n                \"Size\": 416,\n                \"Mallocs\": 141363,\n                \"Frees\": 138960\n            },\n            {\n                \"Size\": 448,\n                \"Mallocs\": 540117,\n                \"Frees\": 539210\n            },\n            {\n                \"Size\": 480,\n                \"Mallocs\": 676388,\n                \"Frees\": 675345\n            },\n            {\n                \"Size\": 512,\n                \"Mallocs\": 230660,\n                \"Frees\": 227546\n            },\n            {\n                \"Size\": 576,\n                \"Mallocs\": 433769,\n                \"Frees\": 433104\n            },\n            {\n                \"Size\": 640,\n                \"Mallocs\": 12331,\n                \"Frees\": 12164\n            },\n            {\n                \"Size\": 704,\n                \"Mallocs\": 140143,\n                \"Frees\": 139954\n            },\n            {\n                \"Size\": 768,\n                \"Mallocs\": 23515,\n                \"Frees\": 23409\n            },\n            {\n                \"Size\": 896,\n                \"Mallocs\": 95206,\n                \"Frees\": 94915\n            },\n            {\n                \"Size\": 1024,\n                \"Mallocs\": 217504,\n                \"Frees\": 215948\n            },\n            {\n                \"Size\": 1152,\n                \"Mallocs\": 282200,\n                \"Frees\": 281783\n            },\n            {\n                \"Size\": 1280,\n                \"Mallocs\": 17248,\n                \"Frees\": 17080\n            },\n            {\n                \"Size\": 1408,\n                \"Mallocs\": 79297,\n                \"Frees\": 78995\n            },\n            {\n                \"Size\": 1536,\n                \"Mallocs\": 33307,\n                \"Frees\": 33191\n            },\n            {\n                \"Size\": 1792,\n                \"Mallocs\": 16122,\n                \"Frees\": 15967\n            },\n            {\n                \"Size\": 2048,\n                \"Mallocs\": 161743,\n                \"Frees\": 160000\n            },\n            {\n                \"Size\": 2304,\n                \"Mallocs\": 140340,\n                \"Frees\": 140188\n            },\n            {\n                \"Size\": 2688,\n                \"Mallocs\": 54749,\n                \"Frees\": 54642\n            },\n            {\n                \"Size\": 3072,\n                \"Mallocs\": 76565,\n                \"Frees\": 76503\n            },\n            {\n                \"Size\": 3200,\n                \"Mallocs\": 788,\n                \"Frees\": 759\n            },\n            {\n                \"Size\": 3456,\n                \"Mallocs\": 350,\n                \"Frees\": 344\n            },\n            {\n                \"Size\": 4096,\n                \"Mallocs\": 135496,\n                \"Frees\": 134672\n            },\n            {\n                \"Size\": 4864,\n                \"Mallocs\": 31285,\n                \"Frees\": 31245\n            },\n            {\n                \"Size\": 5376,\n                \"Mallocs\": 66489,\n                \"Frees\": 66423\n            },\n            {\n                \"Size\": 6144,\n                \"Mallocs\": 19450,\n                \"Frees\": 19419\n            },\n            {\n                \"Size\": 6528,\n                \"Mallocs\": 59061,\n                \"Frees\": 59028\n            },\n            {\n                \"Size\": 6784,\n                \"Mallocs\": 1191,\n                \"Frees\": 1188\n            },\n            {\n                \"Size\": 6912,\n                \"Mallocs\": 63231,\n                \"Frees\": 63197\n            },\n            {\n                \"Size\": 8192,\n                \"Mallocs\": 63357,\n                \"Frees\": 61449\n            },\n            {\n                \"Size\": 9472,\n                \"Mallocs\": 68011,\n                \"Frees\": 67955\n            },\n            {\n                \"Size\": 9728,\n                \"Mallocs\": 8328,\n                \"Frees\": 8320\n            },\n            {\n                \"Size\": 10240,\n                \"Mallocs\": 5390,\n                \"Frees\": 5382\n            },\n            {\n                \"Size\": 10880,\n                \"Mallocs\": 249,\n                \"Frees\": 240\n            },\n            {\n                \"Size\": 12288,\n                \"Mallocs\": 74211,\n                \"Frees\": 74105\n            },\n            {\n                \"Size\": 13568,\n                \"Mallocs\": 10640,\n                \"Frees\": 10638\n            },\n            {\n                \"Size\": 14336,\n                \"Mallocs\": 144,\n                \"Frees\": 111\n            },\n            {\n                \"Size\": 16384,\n                \"Mallocs\": 79481,\n                \"Frees\": 79420\n            },\n            {\n                \"Size\": 18432,\n                \"Mallocs\": 20,\n                \"Frees\": 13\n            }\n        ]\n    },\n    \"runtime\": {\n        \"name\": \"runtime\",\n        \"tags\": {},\n        \"values\": {\n            \"Alloc\": 179303856,\n            \"Frees\": 123761213,\n            \"HeapAlloc\": 179303856,\n            \"HeapIdle\": 184877056,\n            \"HeapInUse\": 195788800,\n            \"HeapObjects\": 1337095,\n            \"HeapReleased\": 163487744,\n            \"HeapSys\": 380665856,\n            \"Lookups\": 0,\n            \"Mallocs\": 125098308,\n            \"NumGC\": 1630,\n            \"NumGoroutine\": 1488,\n            \"PauseTotalNs\": 184808571,\n            \"Sys\": 411947352,\n            \"TotalAlloc\": 173071211320\n        }\n    },\n    \"queryExecutor\": {\n        \"name\": \"queryExecutor\",\n        \"tags\": null,\n        \"values\": {\n            \"queriesActive\": 0,\n            \"queriesExecuted\": 6149,\n            \"queriesFinished\": 6149,\n            \"queryDurationNs\": 747054059,\n            \"recoveredPanics\": 0\n        }\n    },\n    \"database:new_db\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"new_db\"\n        },\n        \"values\": {\n            \"numMeasurements\": 5,\n            \"numSeries\": 78\n        }\n    },\n    \"database:c152-zabbix-prd\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\"\n        },\n        \"values\": {\n            \"numMeasurements\": 2,\n            \"numSeries\": 1501\n        }\n    },\n    \"database:_internal\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"_internal\"\n        },\n        \"values\": {\n            \"numMeasurements\": 21,\n            \"numSeries\": 490\n        }\n    },\n    \"database:chronograf\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"chronograf\"\n        },\n        \"values\": {\n            \"numMeasurements\": 1,\n            \"numSeries\": 62\n        }\n    },\n    \"database:export_test_2\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"export_test_2\"\n        },\n        \"values\": {\n            \"numMeasurements\": 1,\n            \"numSeries\": 36\n        }\n    },\n    \"database:c152-zabbix-hpr\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\"\n        },\n        \"values\": {\n            \"numMeasurements\": 1,\n            \"numSeries\": 15000\n        }\n    },\n    \"database:autogen\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"autogen\"\n        },\n        \"values\": {\n            \"numMeasurements\": 4,\n            \"numSeries\": 43\n        }\n    },\n    \"database:export_test\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"export_test\"\n        },\n        \"values\": {\n            \"numMeasurements\": 1,\n            \"numSeries\": 37\n        }\n    },\n    \"database:telegraf\": {\n        \"name\": \"database\",\n        \"tags\": {\n            \"database\": \"telegraf\"\n        },\n        \"values\": {\n            \"numMeasurements\": 47,\n            \"numSeries\": 618\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/2:2\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"2\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/2\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/2\"\n        },\n        \"values\": {\n            \"diskBytes\": 31791,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 18,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/2:2\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"2\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/2\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/2\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/2:2\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"2\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/2\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/2\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/2:2\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"2\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/2\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/2\"\n        },\n        \"values\": {\n            \"diskBytes\": 31791,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/2:2\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"2\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/2\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/2\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241:5241\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5241\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241\"\n        },\n        \"values\": {\n            \"diskBytes\": 1518907,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 15000,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241:5241\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5241\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241:5241\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5241\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241:5241\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5241\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241\"\n        },\n        \"values\": {\n            \"diskBytes\": 1518907,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241:5241\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5241\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-hpr/autogen/5241\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-hpr/autogen/5241\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242:5242\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5242\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242\"\n        },\n        \"values\": {\n            \"diskBytes\": 55826004,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 1501,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242:5242\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5242\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242:5242\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5242\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242:5242\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5242\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242\"\n        },\n        \"values\": {\n            \"diskBytes\": 55826004,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242:5242\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5242\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/c152-zabbix-prd/autogen/5242\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/c152-zabbix-prd/autogen/5242\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/telegraf/autogen/5260:5260\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5260\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5260\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5260\"\n        },\n        \"values\": {\n            \"diskBytes\": 902338,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 264,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/telegraf/autogen/5260:5260\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5260\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5260\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5260\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/telegraf/autogen/5260:5260\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5260\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5260\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5260\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/telegraf/autogen/5260:5260\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5260\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5260\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5260\"\n        },\n        \"values\": {\n            \"diskBytes\": 902338,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/telegraf/autogen/5260:5260\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5260\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5260\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5260\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/telegraf/autogen/5272:5272\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5272\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5272\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5272\"\n        },\n        \"values\": {\n            \"diskBytes\": 306602401,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 383,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/telegraf/autogen/5272:5272\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5272\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5272\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5272\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/telegraf/autogen/5272:5272\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5272\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5272\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5272\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/telegraf/autogen/5272:5272\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5272\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5272\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5272\"\n        },\n        \"values\": {\n            \"diskBytes\": 306602401,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/telegraf/autogen/5272:5272\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5272\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5272\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5272\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/telegraf/autogen/5286:5286\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5286\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5286\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5286\"\n        },\n        \"values\": {\n            \"diskBytes\": 119528786,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 485,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/telegraf/autogen/5286:5286\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5286\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5286\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5286\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/telegraf/autogen/5286:5286\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5286\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5286\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5286\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/telegraf/autogen/5286:5286\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5286\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5286\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5286\"\n        },\n        \"values\": {\n            \"diskBytes\": 119528786,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/telegraf/autogen/5286:5286\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5286\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5286\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5286\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/chronograf/autogen/5287:5287\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5287\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5287\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5287\"\n        },\n        \"values\": {\n            \"diskBytes\": 976751,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 53,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/chronograf/autogen/5287:5287\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5287\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5287\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5287\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/chronograf/autogen/5287:5287\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5287\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5287\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5287\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/chronograf/autogen/5287:5287\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5287\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5287\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5287\"\n        },\n        \"values\": {\n            \"diskBytes\": 976751,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/chronograf/autogen/5287:5287\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5287\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5287\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5287\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test/autogen/5292:5292\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5292\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5292\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5292\"\n        },\n        \"values\": {\n            \"diskBytes\": 179683,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 24,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test/autogen/5292:5292\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5292\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5292\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5292\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test/autogen/5292:5292\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5292\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5292\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5292\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test/autogen/5292:5292\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5292\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5292\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5292\"\n        },\n        \"values\": {\n            \"diskBytes\": 179683,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test/autogen/5292:5292\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5292\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5292\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5292\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test/autogen/5293:5293\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5293\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5293\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5293\"\n        },\n        \"values\": {\n            \"diskBytes\": 4645612,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 32,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test/autogen/5293:5293\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5293\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5293\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5293\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test/autogen/5293:5293\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5293\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5293\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5293\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test/autogen/5293:5293\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5293\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5293\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5293\"\n        },\n        \"values\": {\n            \"diskBytes\": 4645612,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test/autogen/5293:5293\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5293\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5293\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5293\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test/autogen/5294:5294\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5294\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5294\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5294\"\n        },\n        \"values\": {\n            \"diskBytes\": 1618920,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 1,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test/autogen/5294:5294\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5294\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5294\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5294\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test/autogen/5294:5294\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5294\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5294\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5294\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test/autogen/5294:5294\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5294\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5294\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5294\"\n        },\n        \"values\": {\n            \"diskBytes\": 1618920,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test/autogen/5294:5294\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5294\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test/autogen/5294\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test/autogen/5294\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test_2/autogen/5295:5295\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5295\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5295\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5295\"\n        },\n        \"values\": {\n            \"diskBytes\": 44956319,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 31,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test_2/autogen/5295:5295\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5295\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5295\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5295\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test_2/autogen/5295:5295\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5295\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5295\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5295\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test_2/autogen/5295:5295\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5295\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5295\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5295\"\n        },\n        \"values\": {\n            \"diskBytes\": 44956319,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test_2/autogen/5295:5295\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5295\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5295\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5295\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test_2/autogen/5296:5296\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5296\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5296\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5296\"\n        },\n        \"values\": {\n            \"diskBytes\": 169033,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 23,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test_2/autogen/5296:5296\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5296\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5296\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5296\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test_2/autogen/5296:5296\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5296\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5296\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5296\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test_2/autogen/5296:5296\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5296\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5296\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5296\"\n        },\n        \"values\": {\n            \"diskBytes\": 169033,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test_2/autogen/5296:5296\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5296\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5296\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5296\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/export_test_2/autogen/5297:5297\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5297\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5297\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5297\"\n        },\n        \"values\": {\n            \"diskBytes\": 21805340,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 31,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/export_test_2/autogen/5297:5297\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5297\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5297\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5297\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/export_test_2/autogen/5297:5297\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5297\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5297\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5297\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/export_test_2/autogen/5297:5297\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5297\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5297\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5297\"\n        },\n        \"values\": {\n            \"diskBytes\": 21805340,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/export_test_2/autogen/5297:5297\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5297\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/export_test_2/autogen/5297\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/export_test_2/autogen/5297\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/new_db/autogen/5300:5300\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5300\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5300\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5300\"\n        },\n        \"values\": {\n            \"diskBytes\": 50109,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 19,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/new_db/autogen/5300:5300\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5300\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5300\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5300\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/new_db/autogen/5300:5300\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5300\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5300\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5300\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/new_db/autogen/5300:5300\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5300\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5300\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5300\"\n        },\n        \"values\": {\n            \"diskBytes\": 50109,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/new_db/autogen/5300:5300\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5300\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5300\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5300\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/new_db/autogen/5301:5301\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5301\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5301\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5301\"\n        },\n        \"values\": {\n            \"diskBytes\": 216083,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 63,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/new_db/autogen/5301:5301\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5301\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5301\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5301\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/new_db/autogen/5301:5301\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5301\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5301\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5301\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/new_db/autogen/5301:5301\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5301\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5301\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5301\"\n        },\n        \"values\": {\n            \"diskBytes\": 216083,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/new_db/autogen/5301:5301\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5301\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/new_db/autogen/5301\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/new_db/autogen/5301\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/autogen/5301/5303:5303\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5303\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5301/5303\",\n            \"retentionPolicy\": \"5301\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5301/5303\"\n        },\n        \"values\": {\n            \"diskBytes\": 113590,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 32,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/autogen/5301/5303:5303\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5303\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5301/5303\",\n            \"retentionPolicy\": \"5301\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5301/5303\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/autogen/5301/5303:5303\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5303\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5301/5303\",\n            \"retentionPolicy\": \"5301\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5301/5303\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/autogen/5301/5303:5303\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5303\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5301/5303\",\n            \"retentionPolicy\": \"5301\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5301/5303\"\n        },\n        \"values\": {\n            \"diskBytes\": 113590,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/autogen/5301/5303:5303\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5303\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5301/5303\",\n            \"retentionPolicy\": \"5301\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5301/5303\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/autogen/5300/5304:5304\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5304\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5300/5304\",\n            \"retentionPolicy\": \"5300\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5300/5304\"\n        },\n        \"values\": {\n            \"diskBytes\": 28869,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 11,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/autogen/5300/5304:5304\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5304\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5300/5304\",\n            \"retentionPolicy\": \"5300\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5300/5304\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/autogen/5300/5304:5304\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5304\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5300/5304\",\n            \"retentionPolicy\": \"5300\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5300/5304\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/autogen/5300/5304:5304\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5304\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5300/5304\",\n            \"retentionPolicy\": \"5300\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5300/5304\"\n        },\n        \"values\": {\n            \"diskBytes\": 28869,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/autogen/5300/5304:5304\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5304\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/autogen/5300/5304\",\n            \"retentionPolicy\": \"5300\",\n            \"walPath\": \"/var/lib/influxdb/wal/autogen/5300/5304\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/5306:5306\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5306\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5306\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5306\"\n        },\n        \"values\": {\n            \"diskBytes\": 1592566,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 234,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/5306:5306\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5306\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5306\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5306\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/5306:5306\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5306\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5306\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5306\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/5306:5306\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5306\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5306\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5306\"\n        },\n        \"values\": {\n            \"diskBytes\": 1592566,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/5306:5306\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5306\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5306\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5306\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/telegraf/autogen/5308:5308\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5308\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5308\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5308\"\n        },\n        \"values\": {\n            \"diskBytes\": 100862151,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 530,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 675020,\n            \"writeReq\": 5266,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 5266,\n            \"writeValuesOk\": 3921076\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/telegraf/autogen/5308:5308\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5308\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5308\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5308\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 227545878,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 3,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/telegraf/autogen/5308:5308\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5308\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5308\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5308\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 225,\n            \"cacheAgeMs\": 4014989,\n            \"cachedBytes\": 78680027,\n            \"diskBytes\": 0,\n            \"memBytes\": 12995909,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 7284\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/telegraf/autogen/5308:5308\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5308\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5308\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5308\"\n        },\n        \"values\": {\n            \"diskBytes\": 89546900,\n            \"numFiles\": 8\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/telegraf/autogen/5308:5308\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5308\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/telegraf/autogen/5308\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/telegraf/autogen/5308\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 801802,\n            \"oldSegmentsDiskBytes\": 10513449,\n            \"writeErr\": 0,\n            \"writeOk\": 5266\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/5310:5310\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5310\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5310\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5310\"\n        },\n        \"values\": {\n            \"diskBytes\": 1185091,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 219,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/5310:5310\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5310\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5310\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5310\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/5310:5310\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5310\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5310\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5310\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/5310:5310\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5310\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5310\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5310\"\n        },\n        \"values\": {\n            \"diskBytes\": 1185091,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/5310:5310\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5310\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5310\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5310\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/chronograf/autogen/5311:5311\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5311\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5311\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5311\"\n        },\n        \"values\": {\n            \"diskBytes\": 9601170,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 61,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 3122,\n            \"writeReq\": 803,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 803,\n            \"writeValuesOk\": 9366\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/chronograf/autogen/5311:5311\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5311\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5311\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5311\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/chronograf/autogen/5311:5311\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5311\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5311\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5311\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 21058577,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 4676116,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 11354\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/chronograf/autogen/5311:5311\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5311\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5311\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5311\"\n        },\n        \"values\": {\n            \"diskBytes\": 0,\n            \"numFiles\": 0\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/chronograf/autogen/5311:5311\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5311\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/chronograf/autogen/5311\",\n            \"retentionPolicy\": \"autogen\",\n            \"walPath\": \"/var/lib/influxdb/wal/chronograf/autogen/5311\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 4982276,\n            \"oldSegmentsDiskBytes\": 4618894,\n            \"writeErr\": 0,\n            \"writeOk\": 803\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/5313:5313\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5313\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5313\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5313\"\n        },\n        \"values\": {\n            \"diskBytes\": 1978014,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 205,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/5313:5313\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5313\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5313\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5313\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/5313:5313\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5313\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5313\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5313\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/5313:5313\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5313\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5313\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5313\"\n        },\n        \"values\": {\n            \"diskBytes\": 1978014,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/5313:5313\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5313\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5313\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5313\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/5314:5314\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5314\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5314\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5314\"\n        },\n        \"values\": {\n            \"diskBytes\": 3113562,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 230,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 0,\n            \"writeReq\": 0,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 0,\n            \"writeValuesOk\": 0\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/5314:5314\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5314\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5314\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5314\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 0,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 0,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/5314:5314\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5314\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5314\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5314\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 0,\n            \"cacheAgeMs\": 0,\n            \"cachedBytes\": 0,\n            \"diskBytes\": 0,\n            \"memBytes\": 0,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/5314:5314\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5314\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5314\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5314\"\n        },\n        \"values\": {\n            \"diskBytes\": 3113562,\n            \"numFiles\": 1\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/5314:5314\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5314\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5314\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5314\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 0,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 0\n        }\n    },\n    \"shard:/var/lib/influxdb/data/_internal/monitor/5316:5316\": {\n        \"name\": \"shard\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5316\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5316\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5316\"\n        },\n        \"values\": {\n            \"diskBytes\": 5400093,\n            \"fieldsCreate\": 0,\n            \"seriesCreate\": 229,\n            \"writeBytes\": 0,\n            \"writePointsDropped\": 0,\n            \"writePointsErr\": 0,\n            \"writePointsOk\": 471520,\n            \"writeReq\": 8420,\n            \"writeReqErr\": 0,\n            \"writeReqOk\": 8420,\n            \"writeValuesOk\": 3749005\n        }\n    },\n    \"tsm1_engine:/var/lib/influxdb/data/_internal/monitor/5316:5316\": {\n        \"name\": \"tsm1_engine\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5316\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5316\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5316\"\n        },\n        \"values\": {\n            \"cacheCompactionDuration\": 137702326,\n            \"cacheCompactionErr\": 0,\n            \"cacheCompactions\": 3,\n            \"cacheCompactionsActive\": 0,\n            \"tsmFullCompactionDuration\": 0,\n            \"tsmFullCompactionErr\": 0,\n            \"tsmFullCompactionQueue\": 0,\n            \"tsmFullCompactions\": 0,\n            \"tsmFullCompactionsActive\": 0,\n            \"tsmLevel1CompactionDuration\": 0,\n            \"tsmLevel1CompactionErr\": 0,\n            \"tsmLevel1CompactionQueue\": 0,\n            \"tsmLevel1Compactions\": 0,\n            \"tsmLevel1CompactionsActive\": 0,\n            \"tsmLevel2CompactionDuration\": 0,\n            \"tsmLevel2CompactionErr\": 0,\n            \"tsmLevel2CompactionQueue\": 0,\n            \"tsmLevel2Compactions\": 0,\n            \"tsmLevel2CompactionsActive\": 0,\n            \"tsmLevel3CompactionDuration\": 0,\n            \"tsmLevel3CompactionErr\": 0,\n            \"tsmLevel3CompactionQueue\": 0,\n            \"tsmLevel3Compactions\": 0,\n            \"tsmLevel3CompactionsActive\": 0,\n            \"tsmOptimizeCompactionDuration\": 0,\n            \"tsmOptimizeCompactionErr\": 0,\n            \"tsmOptimizeCompactionQueue\": 0,\n            \"tsmOptimizeCompactions\": 0,\n            \"tsmOptimizeCompactionsActive\": 0\n        }\n    },\n    \"tsm1_cache:/var/lib/influxdb/data/_internal/monitor/5316:5316\": {\n        \"name\": \"tsm1_cache\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5316\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5316\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5316\"\n        },\n        \"values\": {\n            \"WALCompactionTimeMs\": 147,\n            \"cacheAgeMs\": 234999,\n            \"cachedBytes\": 81895372,\n            \"diskBytes\": 0,\n            \"memBytes\": 1105118,\n            \"snapshotCount\": 0,\n            \"writeDropped\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 11318\n        }\n    },\n    \"tsm1_filestore:/var/lib/influxdb/data/_internal/monitor/5316:5316\": {\n        \"name\": \"tsm1_filestore\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5316\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5316\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5316\"\n        },\n        \"values\": {\n            \"diskBytes\": 4250699,\n            \"numFiles\": 6\n        }\n    },\n    \"tsm1_wal:/var/lib/influxdb/data/_internal/monitor/5316:5316\": {\n        \"name\": \"tsm1_wal\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"engine\": \"tsm1\",\n            \"id\": \"5316\",\n            \"indexType\": \"inmem\",\n            \"path\": \"/var/lib/influxdb/data/_internal/monitor/5316\",\n            \"retentionPolicy\": \"monitor\",\n            \"walPath\": \"/var/lib/influxdb/wal/_internal/monitor/5316\"\n        },\n        \"values\": {\n            \"currentSegmentDiskBytes\": 1149394,\n            \"oldSegmentsDiskBytes\": 0,\n            \"writeErr\": 0,\n            \"writeOk\": 8420\n        }\n    },\n    \"localStore\": {\n        \"name\": \"localStore\",\n        \"tags\": null,\n        \"values\": {\n            \"pointsWritten\": 1149662,\n            \"seriesCreated\": 0,\n            \"valuesWritten\": 7679447\n        }\n    },\n    \"write\": {\n        \"name\": \"write\",\n        \"tags\": null,\n        \"values\": {\n            \"pointReq\": 787963,\n            \"pointReqHH\": 0,\n            \"pointReqLocal\": 577463,\n            \"pointReqRemote\": 554308,\n            \"req\": 7231,\n            \"subWriteOk\": 7231,\n            \"writeDrop\": 0,\n            \"writeError\": 0,\n            \"writeOk\": 11441,\n            \"writePartial\": 0,\n            \"writeTimeout\": 0\n        }\n    },\n    \"hh:/var/lib/influxdb/hh\": {\n        \"name\": \"hh\",\n        \"tags\": {\n            \"path\": \"/var/lib/influxdb/hh\"\n        },\n        \"values\": {\n            \"bytesRead\": 0,\n            \"bytesWritten\": 0,\n            \"queueBytes\": 0,\n            \"queueDepth\": 0,\n            \"writeBlocked\": 0,\n            \"writeDropped\": 0,\n            \"writeNodeReq\": 0,\n            \"writeNodeReqFail\": 0,\n            \"writeNodeReqPoints\": 0,\n            \"writeShardReq\": 0,\n            \"writeShardReqPoints\": 0\n        }\n    },\n    \"hh_processor\": {\n        \"name\": \"hh_processor\",\n        \"tags\": {\n            \"node\": \"none\",\n            \"shardID\": \"none\"\n        },\n        \"values\": {\n            \"bytesRead\": 0,\n            \"bytesWritten\": 0,\n            \"queueBytes\": 0,\n            \"queueDepth\": 0,\n            \"writeBlocked\": 0,\n            \"writeDropped\": 0,\n            \"writeNodeReq\": 0,\n            \"writeNodeReqFail\": 0,\n            \"writeNodeReqPoints\": 0,\n            \"writeShardReq\": 0,\n            \"writeShardReqPoints\": 0\n        }\n    },\n    \"hh_node\": {\n        \"name\": \"hh_node\",\n        \"tags\": {\n            \"node\": \"none\"\n        },\n        \"values\": {\n            \"queueTotalSize\": 0\n        }\n    },\n    \"subscriber\": {\n        \"name\": \"subscriber\",\n        \"tags\": null,\n        \"values\": {\n            \"createFailures\": 0,\n            \"memUsage\": 0,\n            \"pointsWritten\": 787963,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-sri-rxw-wifi-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-sri-rxw-wifi-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-datacenter-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-datacenter-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-qos-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-qos-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:export_test_2:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"export_test_2\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c152-zabbix-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-rapi_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-rapi_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-rxw_awx-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-rxw_awx-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-genesys-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-genesys-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-qos-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-qos-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c999-qos-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c999-qos-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c023-zabbix-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c023-zabbix-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:_internal:monitor:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"_internal\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"monitor\"\n        },\n        \"values\": {\n            \"pointsWritten\": 444155,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:autogen:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:autogen:5301:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"5301\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c152-zabbix-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c152-zabbix-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-appl_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-appl_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-supr_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-supr_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c999-mtroapi-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c999-mtroapi-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-opn-carema-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-opn-carema-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-zabbix-prd-new:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-zabbix-prd-new\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:export_test:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"export_test\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-tech_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-tech_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-telephonie-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-telephonie-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-routeur_npc-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-routeur_npc-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-datacenter-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-datacenter-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c999-mtroapi-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c999-mtroapi-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:chronograf:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"chronograf\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 1586,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:telegraf:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"telegraf\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 342222,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-opn-carema-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-opn-carema-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-opn-opr-dynatrace-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-opn-opr-dynatrace-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:new_db:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"new_db\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-mtrm_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-mtrm_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c700-bcr-sup2_tsdb-prd:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c700-bcr-sup2_tsdb-prd\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:c152-dncl-hpr:autogen:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"c152-dncl-hpr\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"autogen\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"subscriber:autogen:5300:kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9:http://kapacitor:9092\": {\n        \"name\": \"subscriber\",\n        \"tags\": {\n            \"database\": \"autogen\",\n            \"destination\": \"http://kapacitor:9092\",\n            \"mode\": \"ANY\",\n            \"name\": \"kapacitor-f39852d3-1f10-40cd-96ba-67d2daee20c9\",\n            \"retention_policy\": \"5300\"\n        },\n        \"values\": {\n            \"pointsWritten\": 0,\n            \"writeFailures\": 0\n        }\n    },\n    \"rpc\": {\n        \"name\": \"rpc\",\n        \"tags\": null,\n        \"values\": {\n            \"idleStreams\": 2,\n            \"liveConnections\": 1,\n            \"liveStreams\": 2,\n            \"rpcCalls\": 146231,\n            \"rpcFailures\": 0,\n            \"rpcReadBytes\": 3941135770,\n            \"rpcRetries\": 0,\n            \"rpcWriteBytes\": 185033228,\n            \"singleUse\": 0,\n            \"singleUseOpen\": 0,\n            \"totalConnections\": 1,\n            \"totalStreams\": 2\n        }\n    },\n    \"entitlements\": {\n        \"name\": \"entitlements\",\n        \"tags\": null,\n        \"values\": {\n            \"licenseExpiry\": \"2112-01-01T00:00:00Z\",\n            \"licenseType\": \"license-file\"\n        }\n    },\n    \"cluster\": {\n        \"name\": \"cluster\",\n        \"tags\": null,\n        \"values\": {\n            \"copyShardReq\": 0,\n            \"createIteratorReq\": 0,\n            \"expandSourcesReq\": 0,\n            \"fieldDimensionsReq\": 0,\n            \"iteratorCostReq\": 0,\n            \"openConnections\": 2,\n            \"removeShardReq\": 0,\n            \"storeReadFilterReq\": 0,\n            \"storeReadGroupReq\": 0,\n            \"storeReadWindowAggregateReq\": 0,\n            \"writeShardFail\": 0,\n            \"writeShardPointsReq\": 572199,\n            \"writeShardReq\": 7258\n        }\n    },\n    \"cq\": {\n        \"name\": \"cq\",\n        \"tags\": null,\n        \"values\": {\n            \"queryFail\": 0,\n            \"queryOk\": 0\n        }\n    },\n    \"httpd::8086\": {\n        \"name\": \"httpd\",\n        \"tags\": {\n            \"bind\": \":8086\"\n        },\n        \"values\": {\n            \"authFail\": 0,\n            \"clientError\": 0,\n            \"fluxQueryReq\": 0,\n            \"fluxQueryReqDurationNs\": 0,\n            \"pingReq\": 871,\n            \"pointsWrittenDropped\": 0,\n            \"pointsWrittenFail\": 0,\n            \"pointsWrittenOK\": 343808,\n            \"promReadReq\": 0,\n            \"promWriteReq\": 0,\n            \"queryReq\": 6149,\n            \"queryReqDurationNs\": 2612667879,\n            \"queryRespBytes\": 2331498,\n            \"recoveredPanics\": 0,\n            \"req\": 12370,\n            \"reqActive\": 2,\n            \"reqDurationNs\": 9521864530967,\n            \"serverError\": 0,\n            \"statusReq\": 0,\n            \"writeReq\": 3021,\n            \"writeReqActive\": 0,\n            \"writeReqBytes\": 96773706,\n            \"writeReqDurationNs\": 45791403479\n        }\n    },\n    \"ae\": {\n        \"name\": \"ae\",\n        \"tags\": null,\n        \"values\": {\n            \"bytesRx\": 0,\n            \"errors\": 0,\n            \"jobs\": 0,\n            \"jobsActive\": 0\n        }\n    }\n}"
  },
  {
    "path": "plugins/inputs/influxdb/testdata/influx_return.json",
    "content": "{\n  \"cluster\": {\n    \"name\": \"cluster\",\n    \"tags\": {},\n    \"values\": {}\n  },\n  \"cmdline\": [\n    \"influxd\"\n  ],\n  \"cq\": {\n    \"name\": \"cq\",\n    \"tags\": {},\n    \"values\": {}\n  },\n  \"database:_internal\": {\n    \"name\": \"database\",\n    \"tags\": {\n      \"database\": \"_internal\"\n    },\n    \"values\": {\n      \"numMeasurements\": 8,\n      \"numSeries\": 12\n    }\n  },\n  \"database:udp\": {\n    \"name\": \"database\",\n    \"tags\": {\n      \"database\": \"udp\"\n    },\n    \"values\": {\n      \"numMeasurements\": 14,\n      \"numSeries\": 38\n    }\n  },\n  \"hh:/Users/csparr/.influxdb/hh\": {\n    \"name\": \"hh\",\n    \"tags\": {\n      \"path\": \"/Users/csparr/.influxdb/hh\"\n    },\n    \"values\": {}\n  },\n  \"httpd::8086\": {\n    \"name\": \"httpd\",\n    \"tags\": {\n      \"bind\": \":8086\"\n    },\n    \"values\": {\n      \"req\": 7,\n      \"reqActive\": 1,\n      \"reqDurationNs\": 4488799\n    }\n  },\n  \"measurement:cpu_idle.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"cpu_idle\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:cpu_usage.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"cpu_usage\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:database._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"database\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:database.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"database\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:httpd.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"httpd\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:measurement.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"measurement\"\n    },\n    \"values\": {\n      \"numSeries\": 22\n    }\n  },\n  \"measurement:mem.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"mem\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:net.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"net\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:runtime._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"runtime\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:runtime.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"runtime\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:shard._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"shard\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:shard.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"shard\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:subscriber._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"subscriber\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:subscriber.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"subscriber\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:swap_used.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"swap_used\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:tsm1_cache._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"tsm1_cache\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_cache.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"tsm1_cache\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_wal._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"tsm1_wal\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_wal.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"tsm1_wal\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:udp._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"udp\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:write._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"write\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:write.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"write\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"system\": {\n    \"currentTime\": \"2023-01-11T16:51:52.723166944Z\",\n    \"started\": \"2023-01-11T16:51:23.355766023Z\",\n    \"uptime\": 29\n  },\n  \"memstats\": {\n    \"Alloc\": 17034016,\n    \"TotalAlloc\": 201739016,\n    \"Sys\": 38537464,\n    \"Lookups\": 77,\n    \"Mallocs\": 570251,\n    \"Frees\": 381008,\n    \"HeapAlloc\": 17034016,\n    \"HeapSys\": 33849344,\n    \"HeapIdle\": 15802368,\n    \"HeapInuse\": 18046976,\n    \"HeapReleased\": 3473408,\n    \"HeapObjects\": 189243,\n    \"StackInuse\": 753664,\n    \"StackSys\": 753664,\n    \"MSpanInuse\": 97440,\n    \"MSpanSys\": 114688,\n    \"MCacheInuse\": 4800,\n    \"MCacheSys\": 16384,\n    \"BuckHashSys\": 1461583,\n    \"GCSys\": 1112064,\n    \"OtherSys\": 1229737,\n    \"NextGC\": 20843042,\n    \"LastGC\": 1460434886475114239,\n    \"PauseTotalNs\": 5132914,\n    \"PauseNs\": [\n      195052,\n      117751,\n      139370,\n      156933,\n      263089,\n      165249,\n      713747,\n      103904,\n      122015,\n      294408,\n      213753,\n      170864,\n      175845,\n      114221,\n      121563,\n      122409,\n      113098,\n      162219,\n      229257,\n      126726,\n      250774,\n      254235,\n      117206,\n      293588,\n      144279,\n      124306,\n      127053,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"PauseEnd\": [\n      1460433856394860455,\n      1460433856398162739,\n      1460433856405888337,\n      1460433856411784017,\n      1460433856417924684,\n      1460433856428385687,\n      1460433856443782908,\n      1460433856456522851,\n      1460433857392743223,\n      1460433866484394564,\n      1460433866494076235,\n      1460433896472438632,\n      1460433957839825106,\n      1460433976473440328,\n      1460434016473413006,\n      1460434096471892794,\n      1460434126470792929,\n      1460434246480428250,\n      1460434366554468369,\n      1460434396471249528,\n      1460434456471205885,\n      1460434476479487292,\n      1460434536471435965,\n      1460434616469784776,\n      1460434736482078216,\n      1460434856544251733,\n      1460434886475114239,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"NumGC\": 27,\n    \"GCCPUFraction\": 4.287178819113636e-05,\n    \"EnableGC\": true,\n    \"DebugGC\": false,\n    \"BySize\": [\n      {\n        \"Size\": 0,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8,\n        \"Mallocs\": 1031,\n        \"Frees\": 955\n      },\n      {\n        \"Size\": 16,\n        \"Mallocs\": 308485,\n        \"Frees\": 142064\n      },\n      {\n        \"Size\": 32,\n        \"Mallocs\": 64937,\n        \"Frees\": 54321\n      },\n      {\n        \"Size\": 48,\n        \"Mallocs\": 33012,\n        \"Frees\": 29754\n      },\n      {\n        \"Size\": 64,\n        \"Mallocs\": 20299,\n        \"Frees\": 18173\n      },\n      {\n        \"Size\": 80,\n        \"Mallocs\": 8186,\n        \"Frees\": 7597\n      },\n      {\n        \"Size\": 96,\n        \"Mallocs\": 9806,\n        \"Frees\": 8982\n      },\n      {\n        \"Size\": 112,\n        \"Mallocs\": 5671,\n        \"Frees\": 4850\n      },\n      {\n        \"Size\": 128,\n        \"Mallocs\": 2972,\n        \"Frees\": 2684\n      },\n      {\n        \"Size\": 144,\n        \"Mallocs\": 4106,\n        \"Frees\": 3719\n      },\n      {\n        \"Size\": 160,\n        \"Mallocs\": 1324,\n        \"Frees\": 911\n      },\n      {\n        \"Size\": 176,\n        \"Mallocs\": 2574,\n        \"Frees\": 2391\n      },\n      {\n        \"Size\": 192,\n        \"Mallocs\": 4053,\n        \"Frees\": 3863\n      },\n      {\n        \"Size\": 208,\n        \"Mallocs\": 442,\n        \"Frees\": 307\n      },\n      {\n        \"Size\": 224,\n        \"Mallocs\": 336,\n        \"Frees\": 172\n      },\n      {\n        \"Size\": 240,\n        \"Mallocs\": 143,\n        \"Frees\": 125\n      },\n      {\n        \"Size\": 256,\n        \"Mallocs\": 542,\n        \"Frees\": 497\n      },\n      {\n        \"Size\": 288,\n        \"Mallocs\": 15971,\n        \"Frees\": 14761\n      },\n      {\n        \"Size\": 320,\n        \"Mallocs\": 245,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 352,\n        \"Mallocs\": 1299,\n        \"Frees\": 1065\n      },\n      {\n        \"Size\": 384,\n        \"Mallocs\": 138,\n        \"Frees\": 2\n      },\n      {\n        \"Size\": 416,\n        \"Mallocs\": 54,\n        \"Frees\": 47\n      },\n      {\n        \"Size\": 448,\n        \"Mallocs\": 75,\n        \"Frees\": 29\n      },\n      {\n        \"Size\": 480,\n        \"Mallocs\": 6,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 512,\n        \"Mallocs\": 452,\n        \"Frees\": 422\n      },\n      {\n        \"Size\": 576,\n        \"Mallocs\": 486,\n        \"Frees\": 395\n      },\n      {\n        \"Size\": 640,\n        \"Mallocs\": 81,\n        \"Frees\": 67\n      },\n      {\n        \"Size\": 704,\n        \"Mallocs\": 421,\n        \"Frees\": 397\n      },\n      {\n        \"Size\": 768,\n        \"Mallocs\": 469,\n        \"Frees\": 468\n      },\n      {\n        \"Size\": 896,\n        \"Mallocs\": 1049,\n        \"Frees\": 1010\n      },\n      {\n        \"Size\": 1024,\n        \"Mallocs\": 1078,\n        \"Frees\": 960\n      },\n      {\n        \"Size\": 1152,\n        \"Mallocs\": 750,\n        \"Frees\": 498\n      },\n      {\n        \"Size\": 1280,\n        \"Mallocs\": 84,\n        \"Frees\": 72\n      },\n      {\n        \"Size\": 1408,\n        \"Mallocs\": 218,\n        \"Frees\": 187\n      },\n      {\n        \"Size\": 1536,\n        \"Mallocs\": 73,\n        \"Frees\": 48\n      },\n      {\n        \"Size\": 1664,\n        \"Mallocs\": 43,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 2048,\n        \"Mallocs\": 153,\n        \"Frees\": 57\n      },\n      {\n        \"Size\": 2304,\n        \"Mallocs\": 41,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 2560,\n        \"Mallocs\": 18,\n        \"Frees\": 15\n      },\n      {\n        \"Size\": 2816,\n        \"Mallocs\": 164,\n        \"Frees\": 157\n      },\n      {\n        \"Size\": 3072,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 3328,\n        \"Mallocs\": 13,\n        \"Frees\": 6\n      },\n      {\n        \"Size\": 4096,\n        \"Mallocs\": 101,\n        \"Frees\": 82\n      },\n      {\n        \"Size\": 4608,\n        \"Mallocs\": 32,\n        \"Frees\": 26\n      },\n      {\n        \"Size\": 5376,\n        \"Mallocs\": 165,\n        \"Frees\": 151\n      },\n      {\n        \"Size\": 6144,\n        \"Mallocs\": 15,\n        \"Frees\": 9\n      },\n      {\n        \"Size\": 6400,\n        \"Mallocs\": 1,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 6656,\n        \"Mallocs\": 1,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 6912,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8192,\n        \"Mallocs\": 13,\n        \"Frees\": 13\n      },\n      {\n        \"Size\": 8448,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8704,\n        \"Mallocs\": 1,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 9472,\n        \"Mallocs\": 6,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 10496,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 12288,\n        \"Mallocs\": 41,\n        \"Frees\": 35\n      },\n      {\n        \"Size\": 13568,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 14080,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 16384,\n        \"Mallocs\": 4,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 16640,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 17664,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      }\n    ]\n  },\n  \"queryExecutor\": {\n    \"name\": \"queryExecutor\",\n    \"tags\": {},\n    \"values\": {}\n  },\n  \"shard:/Users/csparr/.influxdb/data/_internal/monitor/2:2\": {\n    \"name\": \"shard\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"engine\": \"tsm1\",\n      \"id\": \"2\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {}\n  },\n  \"shard:/Users/csparr/.influxdb/data/udp/default/1:1\": {\n    \"name\": \"shard\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"engine\": \"tsm1\",\n      \"id\": \"1\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"fieldsCreate\": 61,\n      \"seriesCreate\": 33,\n      \"writePointsOk\": 3613,\n      \"writeReq\": 110\n    }\n  },\n  \"subscriber\": {\n    \"name\": \"subscriber\",\n    \"tags\": {},\n    \"values\": {\n      \"pointsWritten\": 3613\n    }\n  },\n  \"tsm1_cache:/Users/csparr/.influxdb/data/_internal/monitor/2\": {\n    \"name\": \"tsm1_cache\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {\n      \"WALCompactionTimeMs\": 0,\n      \"cacheAgeMs\": 1103932,\n      \"cachedBytes\": 0,\n      \"diskBytes\": 0,\n      \"memBytes\": 40480,\n      \"snapshotCount\": 0\n    }\n  },\n  \"tsm1_cache:/Users/csparr/.influxdb/data/udp/default/1\": {\n    \"name\": \"tsm1_cache\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"WALCompactionTimeMs\": 0,\n      \"cacheAgeMs\": 1103029,\n      \"cachedBytes\": 0,\n      \"diskBytes\": 0,\n      \"memBytes\": 2359472,\n      \"snapshotCount\": 0\n    }\n  },\n  \"tsm1_filestore:/Users/csparr/.influxdb/data/_internal/monitor/2\": {\n    \"name\": \"tsm1_filestore\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {}\n  },\n  \"tsm1_filestore:/Users/csparr/.influxdb/data/udp/default/1\": {\n    \"name\": \"tsm1_filestore\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {}\n  },\n  \"tsm1_wal:/Users/csparr/.influxdb/wal/_internal/monitor/2\": {\n    \"name\": \"tsm1_wal\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/wal/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {\n      \"currentSegmentDiskBytes\": 0,\n      \"oldSegmentsDiskBytes\": 69532\n    }\n  },\n  \"tsm1_wal:/Users/csparr/.influxdb/wal/udp/default/1\": {\n    \"name\": \"tsm1_wal\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/wal/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"currentSegmentDiskBytes\": 193728,\n      \"oldSegmentsDiskBytes\": 1008330\n    }\n  },\n  \"write\": {\n    \"name\": \"write\",\n    \"tags\": {},\n    \"values\": {\n      \"pointReq\": 3613,\n      \"pointReqLocal\": 3613,\n      \"req\": 110,\n      \"subWriteOk\": 110,\n      \"writeOk\": 110\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb/testdata/influx_return2.json",
    "content": "{\n  \"cluster\": {\n    \"name\": \"cluster\",\n    \"tags\": null,\n    \"values\": {}\n  },\n  \"cmdline\": [\n    \"influxd\"\n  ],\n  \"cq\": {\n    \"name\": \"cq\",\n    \"tags\": null,\n    \"values\": {}\n  },\n  \"database:_internal\": {\n    \"name\": \"database\",\n    \"tags\": {\n      \"database\": \"_internal\"\n    },\n    \"values\": {\n      \"numMeasurements\": 8,\n      \"numSeries\": 12\n    }\n  },\n  \"database:udp\": {\n    \"name\": \"database\",\n    \"tags\": {\n      \"database\": \"udp\"\n    },\n    \"values\": {\n      \"numMeasurements\": 14,\n      \"numSeries\": 38\n    }\n  },\n  \"hh:/Users/csparr/.influxdb/hh\": {\n    \"name\": \"hh\",\n    \"tags\": {\n      \"path\": \"/Users/csparr/.influxdb/hh\"\n    },\n    \"values\": {}\n  },\n  \"httpd::8086\": {\n    \"name\": \"httpd\",\n    \"tags\": {\n      \"bind\": \":8086\"\n    },\n    \"values\": {\n      \"req\": 7,\n      \"reqActive\": 1,\n      \"reqDurationNs\": 4488799\n    }\n  },\n  \"measurement:cpu_idle.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"cpu_idle\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:cpu_usage.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"cpu_usage\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:database._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"database\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:database.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"database\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:httpd.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"httpd\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:measurement.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"measurement\"\n    },\n    \"values\": {\n      \"numSeries\": 22\n    }\n  },\n  \"measurement:mem.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"mem\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:net.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"net\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:runtime._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"runtime\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:runtime.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"runtime\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:shard._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"shard\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:shard.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"shard\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:subscriber._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"subscriber\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:subscriber.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"subscriber\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:swap_used.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"swap_used\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:tsm1_cache._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"tsm1_cache\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_cache.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"tsm1_cache\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_wal._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"tsm1_wal\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:tsm1_wal.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"tsm1_wal\"\n    },\n    \"values\": {\n      \"numSeries\": 2\n    }\n  },\n  \"measurement:udp._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"udp\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:write._internal\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"measurement\": \"write\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"measurement:write.udp\": {\n    \"name\": \"measurement\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"measurement\": \"write\"\n    },\n    \"values\": {\n      \"numSeries\": 1\n    }\n  },\n  \"system\": {\n    \"currentTime\": \"2023-01-11T17:04:59.928454705Z\",\n    \"started\": \"2023-01-11T16:51:23.355766023Z\",\n    \"uptime\": 816\n  },\n  \"memstats\": {\n    \"Alloc\": 17034016,\n    \"TotalAlloc\": 201739016,\n    \"Sys\": 38537464,\n    \"Lookups\": 77,\n    \"Mallocs\": 570251,\n    \"Frees\": 381008,\n    \"HeapAlloc\": 17034016,\n    \"HeapSys\": 33849344,\n    \"HeapIdle\": 15802368,\n    \"HeapInuse\": 18046976,\n    \"HeapReleased\": 3473408,\n    \"HeapObjects\": 189243,\n    \"StackInuse\": 753664,\n    \"StackSys\": 753664,\n    \"MSpanInuse\": 97440,\n    \"MSpanSys\": 114688,\n    \"MCacheInuse\": 4800,\n    \"MCacheSys\": 16384,\n    \"BuckHashSys\": 1461583,\n    \"GCSys\": 1112064,\n    \"OtherSys\": 1229737,\n    \"NextGC\": 20843042,\n    \"LastGC\": 1460434886475114239,\n    \"PauseTotalNs\": 5132914,\n    \"PauseNs\": [\n      195052,\n      117751,\n      139370,\n      156933,\n      263089,\n      165249,\n      713747,\n      103904,\n      122015,\n      294408,\n      213753,\n      170864,\n      175845,\n      114221,\n      121563,\n      122409,\n      113098,\n      162219,\n      229257,\n      126726,\n      250774,\n      254235,\n      117206,\n      293588,\n      144279,\n      124306,\n      127053,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"PauseEnd\": [\n      1460433856394860455,\n      1460433856398162739,\n      1460433856405888337,\n      1460433856411784017,\n      1460433856417924684,\n      1460433856428385687,\n      1460433856443782908,\n      1460433856456522851,\n      1460433857392743223,\n      1460433866484394564,\n      1460433866494076235,\n      1460433896472438632,\n      1460433957839825106,\n      1460433976473440328,\n      1460434016473413006,\n      1460434096471892794,\n      1460434126470792929,\n      1460434246480428250,\n      1460434366554468369,\n      1460434396471249528,\n      1460434456471205885,\n      1460434476479487292,\n      1460434536471435965,\n      1460434616469784776,\n      1460434736482078216,\n      1460434856544251733,\n      1460434886475114239,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"NumGC\": 27,\n    \"GCCPUFraction\": 4.287178819113636e-05,\n    \"EnableGC\": true,\n    \"DebugGC\": false,\n    \"BySize\": [\n      {\n        \"Size\": 0,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8,\n        \"Mallocs\": 1031,\n        \"Frees\": 955\n      },\n      {\n        \"Size\": 16,\n        \"Mallocs\": 308485,\n        \"Frees\": 142064\n      },\n      {\n        \"Size\": 32,\n        \"Mallocs\": 64937,\n        \"Frees\": 54321\n      },\n      {\n        \"Size\": 48,\n        \"Mallocs\": 33012,\n        \"Frees\": 29754\n      },\n      {\n        \"Size\": 64,\n        \"Mallocs\": 20299,\n        \"Frees\": 18173\n      },\n      {\n        \"Size\": 80,\n        \"Mallocs\": 8186,\n        \"Frees\": 7597\n      },\n      {\n        \"Size\": 96,\n        \"Mallocs\": 9806,\n        \"Frees\": 8982\n      },\n      {\n        \"Size\": 112,\n        \"Mallocs\": 5671,\n        \"Frees\": 4850\n      },\n      {\n        \"Size\": 128,\n        \"Mallocs\": 2972,\n        \"Frees\": 2684\n      },\n      {\n        \"Size\": 144,\n        \"Mallocs\": 4106,\n        \"Frees\": 3719\n      },\n      {\n        \"Size\": 160,\n        \"Mallocs\": 1324,\n        \"Frees\": 911\n      },\n      {\n        \"Size\": 176,\n        \"Mallocs\": 2574,\n        \"Frees\": 2391\n      },\n      {\n        \"Size\": 192,\n        \"Mallocs\": 4053,\n        \"Frees\": 3863\n      },\n      {\n        \"Size\": 208,\n        \"Mallocs\": 442,\n        \"Frees\": 307\n      },\n      {\n        \"Size\": 224,\n        \"Mallocs\": 336,\n        \"Frees\": 172\n      },\n      {\n        \"Size\": 240,\n        \"Mallocs\": 143,\n        \"Frees\": 125\n      },\n      {\n        \"Size\": 256,\n        \"Mallocs\": 542,\n        \"Frees\": 497\n      },\n      {\n        \"Size\": 288,\n        \"Mallocs\": 15971,\n        \"Frees\": 14761\n      },\n      {\n        \"Size\": 320,\n        \"Mallocs\": 245,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 352,\n        \"Mallocs\": 1299,\n        \"Frees\": 1065\n      },\n      {\n        \"Size\": 384,\n        \"Mallocs\": 138,\n        \"Frees\": 2\n      },\n      {\n        \"Size\": 416,\n        \"Mallocs\": 54,\n        \"Frees\": 47\n      },\n      {\n        \"Size\": 448,\n        \"Mallocs\": 75,\n        \"Frees\": 29\n      },\n      {\n        \"Size\": 480,\n        \"Mallocs\": 6,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 512,\n        \"Mallocs\": 452,\n        \"Frees\": 422\n      },\n      {\n        \"Size\": 576,\n        \"Mallocs\": 486,\n        \"Frees\": 395\n      },\n      {\n        \"Size\": 640,\n        \"Mallocs\": 81,\n        \"Frees\": 67\n      },\n      {\n        \"Size\": 704,\n        \"Mallocs\": 421,\n        \"Frees\": 397\n      },\n      {\n        \"Size\": 768,\n        \"Mallocs\": 469,\n        \"Frees\": 468\n      },\n      {\n        \"Size\": 896,\n        \"Mallocs\": 1049,\n        \"Frees\": 1010\n      },\n      {\n        \"Size\": 1024,\n        \"Mallocs\": 1078,\n        \"Frees\": 960\n      },\n      {\n        \"Size\": 1152,\n        \"Mallocs\": 750,\n        \"Frees\": 498\n      },\n      {\n        \"Size\": 1280,\n        \"Mallocs\": 84,\n        \"Frees\": 72\n      },\n      {\n        \"Size\": 1408,\n        \"Mallocs\": 218,\n        \"Frees\": 187\n      },\n      {\n        \"Size\": 1536,\n        \"Mallocs\": 73,\n        \"Frees\": 48\n      },\n      {\n        \"Size\": 1664,\n        \"Mallocs\": 43,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 2048,\n        \"Mallocs\": 153,\n        \"Frees\": 57\n      },\n      {\n        \"Size\": 2304,\n        \"Mallocs\": 41,\n        \"Frees\": 30\n      },\n      {\n        \"Size\": 2560,\n        \"Mallocs\": 18,\n        \"Frees\": 15\n      },\n      {\n        \"Size\": 2816,\n        \"Mallocs\": 164,\n        \"Frees\": 157\n      },\n      {\n        \"Size\": 3072,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 3328,\n        \"Mallocs\": 13,\n        \"Frees\": 6\n      },\n      {\n        \"Size\": 4096,\n        \"Mallocs\": 101,\n        \"Frees\": 82\n      },\n      {\n        \"Size\": 4608,\n        \"Mallocs\": 32,\n        \"Frees\": 26\n      },\n      {\n        \"Size\": 5376,\n        \"Mallocs\": 165,\n        \"Frees\": 151\n      },\n      {\n        \"Size\": 6144,\n        \"Mallocs\": 15,\n        \"Frees\": 9\n      },\n      {\n        \"Size\": 6400,\n        \"Mallocs\": 1,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 6656,\n        \"Mallocs\": 1,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 6912,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8192,\n        \"Mallocs\": 13,\n        \"Frees\": 13\n      },\n      {\n        \"Size\": 8448,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8704,\n        \"Mallocs\": 1,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 9472,\n        \"Mallocs\": 6,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 10496,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 12288,\n        \"Mallocs\": 41,\n        \"Frees\": 35\n      },\n      {\n        \"Size\": 13568,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 14080,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 16384,\n        \"Mallocs\": 4,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 16640,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 17664,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      }\n    ]\n  },\n  \"queryExecutor\": {\n    \"name\": \"queryExecutor\",\n    \"tags\": null,\n    \"values\": {}\n  },\n  \"shard:/Users/csparr/.influxdb/data/_internal/monitor/2:2\": {\n    \"name\": \"shard\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"engine\": \"tsm1\",\n      \"id\": \"2\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {}\n  },\n  \"shard:/Users/csparr/.influxdb/data/udp/default/1:1\": {\n    \"name\": \"shard\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"engine\": \"tsm1\",\n      \"id\": \"1\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"fieldsCreate\": 61,\n      \"seriesCreate\": 33,\n      \"writePointsOk\": 3613,\n      \"writeReq\": 110\n    }\n  },\n  \"subscriber\": {\n    \"name\": \"subscriber\",\n    \"tags\": null,\n    \"values\": {\n      \"pointsWritten\": 3613\n    }\n  },\n  \"tsm1_cache:/Users/csparr/.influxdb/data/_internal/monitor/2\": {\n    \"name\": \"tsm1_cache\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {\n      \"WALCompactionTimeMs\": 0,\n      \"cacheAgeMs\": 1103932,\n      \"cachedBytes\": 0,\n      \"diskBytes\": 0,\n      \"memBytes\": 40480,\n      \"snapshotCount\": 0\n    }\n  },\n  \"tsm1_cache:/Users/csparr/.influxdb/data/udp/default/1\": {\n    \"name\": \"tsm1_cache\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"WALCompactionTimeMs\": 0,\n      \"cacheAgeMs\": 1103029,\n      \"cachedBytes\": 0,\n      \"diskBytes\": 0,\n      \"memBytes\": 2359472,\n      \"snapshotCount\": 0\n    }\n  },\n  \"tsm1_filestore:/Users/csparr/.influxdb/data/_internal/monitor/2\": {\n    \"name\": \"tsm1_filestore\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/data/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {}\n  },\n  \"tsm1_filestore:/Users/csparr/.influxdb/data/udp/default/1\": {\n    \"name\": \"tsm1_filestore\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/data/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {}\n  },\n  \"tsm1_wal:/Users/csparr/.influxdb/wal/_internal/monitor/2\": {\n    \"name\": \"tsm1_wal\",\n    \"tags\": {\n      \"database\": \"_internal\",\n      \"path\": \"/Users/csparr/.influxdb/wal/_internal/monitor/2\",\n      \"retentionPolicy\": \"monitor\"\n    },\n    \"values\": {\n      \"currentSegmentDiskBytes\": 0,\n      \"oldSegmentsDiskBytes\": 69532\n    }\n  },\n  \"tsm1_wal:/Users/csparr/.influxdb/wal/udp/default/1\": {\n    \"name\": \"tsm1_wal\",\n    \"tags\": {\n      \"database\": \"udp\",\n      \"path\": \"/Users/csparr/.influxdb/wal/udp/default/1\",\n      \"retentionPolicy\": \"default\"\n    },\n    \"values\": {\n      \"currentSegmentDiskBytes\": 193728,\n      \"oldSegmentsDiskBytes\": 1008330\n    }\n  },\n  \"write\": {\n    \"name\": \"write\",\n    \"tags\": null,\n    \"values\": {\n      \"pointReq\": 3613,\n      \"pointReqLocal\": 3613,\n      \"req\": 110,\n      \"subWriteOk\": 110,\n      \"writeOk\": 110\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb/types.go",
    "content": "package influxdb\n\ntype point struct {\n\tName   string                 `json:\"name\"`\n\tTags   map[string]string      `json:\"tags\"`\n\tValues map[string]interface{} `json:\"values\"`\n}\n\ntype memstats struct {\n\tAlloc         int64      `json:\"Alloc\"`\n\tTotalAlloc    int64      `json:\"TotalAlloc\"`\n\tSys           int64      `json:\"Sys\"`\n\tLookups       int64      `json:\"Lookups\"`\n\tMallocs       int64      `json:\"Mallocs\"`\n\tFrees         int64      `json:\"Frees\"`\n\tHeapAlloc     int64      `json:\"HeapAlloc\"`\n\tHeapSys       int64      `json:\"HeapSys\"`\n\tHeapIdle      int64      `json:\"HeapIdle\"`\n\tHeapInuse     int64      `json:\"HeapInuse\"`\n\tHeapReleased  int64      `json:\"HeapReleased\"`\n\tHeapObjects   int64      `json:\"HeapObjects\"`\n\tStackInuse    int64      `json:\"StackInuse\"`\n\tStackSys      int64      `json:\"StackSys\"`\n\tMSpanInuse    int64      `json:\"MSpanInuse\"`\n\tMSpanSys      int64      `json:\"MSpanSys\"`\n\tMCacheInuse   int64      `json:\"MCacheInuse\"`\n\tMCacheSys     int64      `json:\"MCacheSys\"`\n\tBuckHashSys   int64      `json:\"BuckHashSys\"`\n\tGCSys         int64      `json:\"GCSys\"`\n\tOtherSys      int64      `json:\"OtherSys\"`\n\tNextGC        int64      `json:\"NextGC\"`\n\tLastGC        int64      `json:\"LastGC\"`\n\tPauseTotalNs  int64      `json:\"PauseTotalNs\"`\n\tPauseNs       [256]int64 `json:\"PauseNs\"`\n\tNumGC         int64      `json:\"NumGC\"`\n\tGCCPUFraction float64    `json:\"GCCPUFraction\"`\n}\n\ntype system struct {\n\tCurrentTime string `json:\"currentTime\"`\n\tStarted     string `json:\"started\"`\n\tUptime      uint64 `json:\"uptime\"`\n}\n\ntype build struct {\n\tBranch    string `json:\"Branch\"`\n\tBuildTime string `json:\"Build Time\"`\n\tCommit    string `json:\"Commit\"`\n\tVersion   string `json:\"Version\"`\n}\n\ntype crypto struct {\n\tFIPS           bool   `json:\"FIPS\"`\n\tEnsureFIPS     bool   `json:\"ensureFIPS\"`\n\tImplementation string `json:\"implementation\"`\n\tPasswordHash   string `json:\"passwordHash\"`\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/README.md",
    "content": "# InfluxDB Listener Input Plugin\n\nThis plugin listens for requests sent according to the\n[InfluxDB HTTP v1 API][influxdb_http_api]. This allows Telegraf to serve as a\nproxy/router for the `/write` endpoint of the InfluxDB HTTP API.\n\n> [!NOTE]\n> This plugin was previously known as `http_listener`. If you wish to\n> send general metrics via HTTP it is recommended to use the\n> [`http_listener_v2`][http_listener_v2] instead.\n\nThe `/write` endpoint supports the `precision` query parameter and can be set\nto one of `ns`, `u`, `ms`, `s`, `m`, `h`.  All other parameters are ignored and\ndefer to the output plugins configuration.\n\n> [!IMPORTANT]\n> When chaining Telegraf instances using this plugin, `CREATE DATABASE` requests\n> receive a `200 OK` response with message body `{\"results\":[]}` but they are\n> not relayed. The configuration of the output plugin ultimately submits data\n> to InfluxDB determines the destination database.\n\n⭐ Telegraf v1.9.0\n🏷️ datastore\n💻 all\n\n[influxdb_http_api]: https://docs.influxdata.com/influxdb/v1.8/guides/write_data/\n[http_listener_v2]: /plugins/inputs/http_listener_v2/README.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Accept metrics over InfluxDB 1.x HTTP API\n[[inputs.influxdb_listener]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8186\"\n\n  ## maximum duration before timing out read of the request\n  read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  max_body_size = 0\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  tls_cert = \"/etc/telegraf/cert.pem\"\n  tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional tag name used to store the database name.\n  ## If the write has a database in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  ## If you have a tag that is the same as the one specified below, and supply a database,\n  ## the tag will be overwritten with the database supplied.\n  # database_tag = \"\"\n\n  ## If set the retention policy specified in the write query will be added as\n  ## the value of this tag name.\n  # retention_policy_tag = \"\"\n\n  ## Optional username and password to accept for HTTP basic authentication\n  ## or authentication token.\n  ## You probably want to make sure you have TLS configured above for this.\n  ## Use these options for the authentication token in the form\n  ##   Authentication: Token <basic_username>:<basic_password>\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional JWT token authentication for HTTP requests\n  ## Please see the documentation at\n  ##   https://docs.influxdata.com/influxdb/v1.8/administration/authentication_and_authorization/#authenticate-using-jwt-tokens\n  ## for further details.\n  ## Please note: Token authentication and basic authentication cannot be used\n  ##              at the same time.\n  # token_shared_secret = \"\"\n  # token_username = \"\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n```\n\n## Metrics\n\nMetrics are created from InfluxDB Line Protocol in the request body.\n\n## Example Output\n\nUsing\n\n```sh\ncurl -i -XPOST 'http://localhost:8186/write' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'\n```\n\nwill produce the following metric\n\n```text\ncpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000\n```\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/influxdb_listener.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage influxdb_listener\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx/influx_upstream\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// defaultMaxBodySize is the default maximum request body size, in bytes.\n\t// if the request body is over this size, we will return an HTTP 413 error.\n\tdefaultMaxBodySize = 32 * 1024 * 1024\n)\n\ntype InfluxDBListener struct {\n\tServiceAddress string `toml:\"service_address\"`\n\tport           int\n\tcommon_tls.ServerConfig\n\n\tReadTimeout        config.Duration `toml:\"read_timeout\"`\n\tWriteTimeout       config.Duration `toml:\"write_timeout\"`\n\tMaxBodySize        config.Size     `toml:\"max_body_size\"`\n\tBasicUsername      string          `toml:\"basic_username\"`\n\tBasicPassword      string          `toml:\"basic_password\"`\n\tTokenSharedSecret  string          `toml:\"token_shared_secret\"`\n\tTokenUsername      string          `toml:\"token_username\"`\n\tDatabaseTag        string          `toml:\"database_tag\"`\n\tRetentionPolicyTag string          `toml:\"retention_policy_tag\"`\n\tParserType         string          `toml:\"parser_type\"`\n\n\ttimeFunc influx.TimeFunc\n\n\tlistener net.Listener\n\tserver   http.Server\n\n\tacc telegraf.Accumulator\n\n\tbytesRecv       selfstat.Stat\n\trequestsServed  selfstat.Stat\n\twritesServed    selfstat.Stat\n\tqueriesServed   selfstat.Stat\n\tpingsServed     selfstat.Stat\n\trequestsRecv    selfstat.Stat\n\tnotFoundsServed selfstat.Stat\n\tbuffersCreated  selfstat.Stat\n\tauthFailures    selfstat.Stat\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tmux http.ServeMux\n}\n\nfunc (*InfluxDBListener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (*InfluxDBListener) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (h *InfluxDBListener) Init() error {\n\t// Check the config setting\n\tif (h.BasicUsername != \"\" || h.BasicPassword != \"\") && (h.TokenSharedSecret != \"\" || h.TokenUsername != \"\") {\n\t\treturn errors.New(\"cannot use basic-auth and tokens at the same time\")\n\t}\n\tif h.TokenSharedSecret != \"\" && h.TokenUsername == \"\" || h.TokenSharedSecret == \"\" && h.TokenUsername != \"\" {\n\t\treturn errors.New(\"neither 'token_shared_secret' nor 'token_username' can be empty for token authentication\")\n\t}\n\n\ttags := map[string]string{\n\t\t\"address\": h.ServiceAddress,\n\t}\n\th.bytesRecv = selfstat.Register(\"influxdb_listener\", \"bytes_received\", tags)\n\th.requestsServed = selfstat.Register(\"influxdb_listener\", \"requests_served\", tags)\n\th.writesServed = selfstat.Register(\"influxdb_listener\", \"writes_served\", tags)\n\th.queriesServed = selfstat.Register(\"influxdb_listener\", \"queries_served\", tags)\n\th.pingsServed = selfstat.Register(\"influxdb_listener\", \"pings_served\", tags)\n\th.requestsRecv = selfstat.Register(\"influxdb_listener\", \"requests_received\", tags)\n\th.notFoundsServed = selfstat.Register(\"influxdb_listener\", \"not_founds_served\", tags)\n\th.buffersCreated = selfstat.Register(\"influxdb_listener\", \"buffers_created\", tags)\n\th.authFailures = selfstat.Register(\"influxdb_listener\", \"auth_failures\", tags)\n\th.routes()\n\n\tif h.MaxBodySize == 0 {\n\t\th.MaxBodySize = config.Size(defaultMaxBodySize)\n\t}\n\n\tif h.ReadTimeout < config.Duration(time.Second) {\n\t\th.ReadTimeout = config.Duration(time.Second * 10)\n\t}\n\tif h.WriteTimeout < config.Duration(time.Second) {\n\t\th.WriteTimeout = config.Duration(time.Second * 10)\n\t}\n\n\treturn nil\n}\n\nfunc (h *InfluxDBListener) Start(acc telegraf.Accumulator) error {\n\th.acc = acc\n\n\ttlsConf, err := h.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\th.server = http.Server{\n\t\tAddr:         h.ServiceAddress,\n\t\tHandler:      h,\n\t\tReadTimeout:  time.Duration(h.ReadTimeout),\n\t\tWriteTimeout: time.Duration(h.WriteTimeout),\n\t\tTLSConfig:    tlsConf,\n\t}\n\n\tvar listener net.Listener\n\tif tlsConf != nil {\n\t\tlistener, err = tls.Listen(\"tcp\", h.ServiceAddress, tlsConf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tlistener, err = net.Listen(\"tcp\", h.ServiceAddress)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\th.listener = listener\n\th.port = listener.Addr().(*net.TCPAddr).Port\n\n\tgo func() {\n\t\terr = h.server.Serve(h.listener)\n\t\tif !errors.Is(err, http.ErrServerClosed) {\n\t\t\th.Log.Infof(\"Error serving HTTP on %s\", h.ServiceAddress)\n\t\t}\n\t}()\n\n\th.Log.Infof(\"Started HTTP listener service on %s\", h.ServiceAddress)\n\n\treturn nil\n}\n\nfunc (h *InfluxDBListener) Stop() {\n\terr := h.server.Shutdown(context.Background())\n\tif err != nil {\n\t\th.Log.Infof(\"Error shutting down HTTP server: %v\", err.Error())\n\t}\n}\n\nfunc (h *InfluxDBListener) routes() {\n\tvar authHandler func(http.Handler) http.Handler\n\tif h.TokenSharedSecret != \"\" {\n\t\tauthHandler = internal.JWTAuthHandler(h.TokenSharedSecret, h.TokenUsername,\n\t\t\tfunc(_ http.ResponseWriter) {\n\t\t\t\th.authFailures.Incr(1)\n\t\t\t},\n\t\t)\n\t} else {\n\t\tauthHandler = internal.BasicAuthHandler(h.BasicUsername, h.BasicPassword, \"influxdb\",\n\t\t\tfunc(_ http.ResponseWriter) {\n\t\t\t\th.authFailures.Incr(1)\n\t\t\t},\n\t\t)\n\t}\n\n\th.mux.Handle(\"/write\", authHandler(h.handleWrite()))\n\th.mux.Handle(\"/query\", authHandler(h.handleQuery()))\n\th.mux.Handle(\"/ping\", h.handlePing())\n\th.mux.Handle(\"/\", authHandler(h.handleDefault()))\n}\n\nfunc (h *InfluxDBListener) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\th.requestsRecv.Incr(1)\n\th.mux.ServeHTTP(res, req)\n\th.requestsServed.Incr(1)\n}\n\nfunc (h *InfluxDBListener) handleQuery() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, _ *http.Request) {\n\t\tdefer h.queriesServed.Incr(1)\n\t\t// Deliver a dummy response to the query endpoint, as some InfluxDB\n\t\t// clients test endpoint availability with a query\n\t\tres.Header().Set(\"Content-Type\", \"application/json\")\n\t\tres.Header().Set(\"X-Influxdb-Version\", \"1.0\")\n\t\tres.WriteHeader(http.StatusOK)\n\t\t_, err := res.Write([]byte(\"{\\\"results\\\":[]}\"))\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"error writing result in handleQuery: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBListener) handlePing() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, req *http.Request) {\n\t\tdefer h.pingsServed.Incr(1)\n\t\tverbose := req.URL.Query().Get(\"verbose\")\n\n\t\t// respond to ping requests\n\t\tres.Header().Set(\"X-Influxdb-Version\", \"1.0\")\n\t\tif verbose != \"\" && verbose != \"0\" && verbose != \"false\" {\n\t\t\tres.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tres.WriteHeader(http.StatusOK)\n\t\t\tb, err := json.Marshal(map[string]string{\"version\": \"1.0\"}) // based on header set above\n\t\t\tif err != nil {\n\t\t\t\th.Log.Debugf(\"error marshalling json in handlePing: %v\", err)\n\t\t\t}\n\t\t\tif _, err := res.Write(b); err != nil {\n\t\t\t\th.Log.Debugf(\"error writing result in handlePing: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tres.WriteHeader(http.StatusNoContent)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBListener) handleDefault() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, req *http.Request) {\n\t\tdefer h.notFoundsServed.Incr(1)\n\t\thttp.NotFound(res, req)\n\t}\n}\n\nfunc (h *InfluxDBListener) handleWrite() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, req *http.Request) {\n\t\tif h.ParserType == \"upstream\" {\n\t\t\th.handleWriteUpstreamParser(res, req)\n\t\t} else {\n\t\t\th.handleWriteInternalParser(res, req)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBListener) handleWriteInternalParser(res http.ResponseWriter, req *http.Request) {\n\tdefer h.writesServed.Incr(1)\n\t// Check that the content length is not too large for us to handle.\n\tif req.ContentLength > int64(h.MaxBodySize) {\n\t\tif err := tooLarge(res); err != nil {\n\t\t\th.Log.Debugf(\"error in too-large: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tdb := req.URL.Query().Get(\"db\")\n\trp := req.URL.Query().Get(\"rp\")\n\n\tbody := req.Body\n\tbody = http.MaxBytesReader(res, body, int64(h.MaxBodySize))\n\t// Handle gzip request bodies\n\tif req.Header.Get(\"Content-Encoding\") == \"gzip\" {\n\t\tvar err error\n\t\tbody, err = gzip.NewReader(body)\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"Error decompressing request body: %v\", err.Error())\n\t\t\tif err := badRequest(res, err.Error()); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tdefer body.Close()\n\t}\n\n\tparser := influx.NewStreamParser(body)\n\tparser.SetTimeFunc(h.timeFunc)\n\n\tprecisionStr := req.URL.Query().Get(\"precision\")\n\tif precisionStr != \"\" {\n\t\tprecision := getPrecisionMultiplier(precisionStr)\n\t\tparser.SetTimePrecision(precision)\n\t}\n\n\tvar m telegraf.Metric\n\tvar err error\n\tvar parseErrorCount int\n\tvar lastPos int\n\tvar firstParseErrorStr string\n\tfor {\n\t\tselect {\n\t\tcase <-req.Context().Done():\n\t\t\t// Shutting down before parsing is finished.\n\t\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tm, err = parser.Next()\n\t\tpos := parser.Position()\n\t\th.bytesRecv.Incr(int64(pos - lastPos))\n\t\tlastPos = pos\n\n\t\t// Continue parsing metrics even if some are malformed\n\t\tvar parseErr *influx.ParseError\n\t\tif errors.As(err, &parseErr) {\n\t\t\tparseErrorCount++\n\t\t\terrStr := parseErr.Error()\n\t\t\tif firstParseErrorStr == \"\" {\n\t\t\t\tfirstParseErrorStr = errStr\n\t\t\t}\n\t\t\tcontinue\n\t\t} else if err != nil {\n\t\t\t// Either we're exiting cleanly (err ==\n\t\t\t// influx.EOF) or there's an unexpected error\n\t\t\tbreak\n\t\t}\n\n\t\tif h.DatabaseTag != \"\" && db != \"\" {\n\t\t\tm.AddTag(h.DatabaseTag, db)\n\t\t}\n\n\t\tif h.RetentionPolicyTag != \"\" && rp != \"\" {\n\t\t\tm.AddTag(h.RetentionPolicyTag, rp)\n\t\t}\n\n\t\th.acc.AddMetric(m)\n\t}\n\tif !errors.Is(err, influx.EOF) {\n\t\th.Log.Debugf(\"Error parsing the request body: %v\", err.Error())\n\t\tif err := badRequest(res, err.Error()); err != nil {\n\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\tif parseErrorCount > 0 {\n\t\tvar partialErrorString string\n\t\tswitch parseErrorCount {\n\t\tcase 1:\n\t\t\tpartialErrorString = firstParseErrorStr\n\t\tcase 2:\n\t\t\tpartialErrorString = firstParseErrorStr + \" (and 1 other parse error)\"\n\t\tdefault:\n\t\t\tpartialErrorString = fmt.Sprintf(\"%s (and %d other parse errors)\", firstParseErrorStr, parseErrorCount-1)\n\t\t}\n\t\tif err := partialWrite(res, partialErrorString); err != nil {\n\t\t\th.Log.Debugf(\"error in partial-write: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\t// http request success\n\tres.WriteHeader(http.StatusNoContent)\n}\n\nfunc (h *InfluxDBListener) handleWriteUpstreamParser(res http.ResponseWriter, req *http.Request) {\n\tdefer h.writesServed.Incr(1)\n\t// Check that the content length is not too large for us to handle.\n\tif req.ContentLength > int64(h.MaxBodySize) {\n\t\tif err := tooLarge(res); err != nil {\n\t\t\th.Log.Debugf(\"error in too-large: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tdb := req.URL.Query().Get(\"db\")\n\trp := req.URL.Query().Get(\"rp\")\n\n\tbody := req.Body\n\tbody = http.MaxBytesReader(res, body, int64(h.MaxBodySize))\n\t// Handle gzip request bodies\n\tif req.Header.Get(\"Content-Encoding\") == \"gzip\" {\n\t\tvar err error\n\t\tbody, err = gzip.NewReader(body)\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"Error decompressing request body: %v\", err.Error())\n\t\t\tif err := badRequest(res, err.Error()); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tdefer body.Close()\n\t}\n\n\tparser := influx_upstream.NewStreamParser(body)\n\tparser.SetTimeFunc(influx_upstream.TimeFunc(h.timeFunc))\n\n\tprecisionStr := req.URL.Query().Get(\"precision\")\n\tif precisionStr != \"\" {\n\t\tprecision := getPrecisionMultiplier(precisionStr)\n\t\terr := parser.SetTimePrecision(precision)\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"error in upstream parser: %v\", err)\n\t\t\tif err := badRequest(res, err.Error()); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tif req.ContentLength >= 0 {\n\t\th.bytesRecv.Incr(req.ContentLength)\n\t}\n\n\tvar m telegraf.Metric\n\tvar err error\n\tvar parseErrorCount int\n\tvar firstParseErrorStr string\n\tfor {\n\t\tselect {\n\t\tcase <-req.Context().Done():\n\t\t\t// Shutting down before parsing is finished.\n\t\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tm, err = parser.Next()\n\n\t\t// Continue parsing metrics even if some are malformed\n\t\tvar parseErr *influx_upstream.ParseError\n\t\tif errors.As(err, &parseErr) {\n\t\t\tparseErrorCount++\n\t\t\terrStr := parseErr.Error()\n\t\t\tif firstParseErrorStr == \"\" {\n\t\t\t\tfirstParseErrorStr = errStr\n\t\t\t}\n\t\t\tcontinue\n\t\t} else if err != nil {\n\t\t\t// Either we're exiting cleanly (err ==\n\t\t\t// influx.ErrEOF) or there's an unexpected error\n\t\t\tbreak\n\t\t}\n\n\t\tif h.DatabaseTag != \"\" && db != \"\" {\n\t\t\tm.AddTag(h.DatabaseTag, db)\n\t\t}\n\n\t\tif h.RetentionPolicyTag != \"\" && rp != \"\" {\n\t\t\tm.AddTag(h.RetentionPolicyTag, rp)\n\t\t}\n\n\t\th.acc.AddMetric(m)\n\t}\n\tif !errors.Is(err, io.EOF) {\n\t\th.Log.Debugf(\"Error parsing the request body: %v\", err.Error())\n\t\tif err := badRequest(res, err.Error()); err != nil {\n\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\tif parseErrorCount > 0 {\n\t\tvar partialErrorString string\n\t\tswitch parseErrorCount {\n\t\tcase 1:\n\t\t\tpartialErrorString = firstParseErrorStr\n\t\tcase 2:\n\t\t\tpartialErrorString = firstParseErrorStr + \" (and 1 other parse error)\"\n\t\tdefault:\n\t\t\tpartialErrorString = fmt.Sprintf(\"%s (and %d other parse errors)\", firstParseErrorStr, parseErrorCount-1)\n\t\t}\n\t\tif err := partialWrite(res, partialErrorString); err != nil {\n\t\t\th.Log.Debugf(\"error in partial-write: %v\", err)\n\t\t}\n\t\treturn\n\t}\n\n\t// http request success\n\tres.WriteHeader(http.StatusNoContent)\n}\n\nfunc tooLarge(res http.ResponseWriter) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.Header().Set(\"X-Influxdb-Version\", \"1.0\")\n\tres.Header().Set(\"X-Influxdb-Error\", \"http: request body too large\")\n\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t_, err := res.Write([]byte(`{\"error\":\"http: request body too large\"}`))\n\treturn err\n}\n\nfunc badRequest(res http.ResponseWriter, errString string) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.Header().Set(\"X-Influxdb-Version\", \"1.0\")\n\tif errString == \"\" {\n\t\terrString = \"http: bad request\"\n\t}\n\tres.Header().Set(\"X-Influxdb-Error\", errString)\n\tres.WriteHeader(http.StatusBadRequest)\n\t_, err := fmt.Fprintf(res, `{\"error\":%q}`, errString)\n\treturn err\n}\n\nfunc partialWrite(res http.ResponseWriter, errString string) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.Header().Set(\"X-Influxdb-Version\", \"1.0\")\n\tres.Header().Set(\"X-Influxdb-Error\", errString)\n\tres.WriteHeader(http.StatusBadRequest)\n\t_, err := fmt.Fprintf(res, `{\"error\":%q}`, errString)\n\treturn err\n}\n\nfunc getPrecisionMultiplier(precision string) time.Duration {\n\t// Influxdb defaults silently to nanoseconds if precision isn't\n\t// one of the following:\n\tvar d time.Duration\n\tswitch precision {\n\tcase \"u\":\n\t\td = time.Microsecond\n\tcase \"ms\":\n\t\td = time.Millisecond\n\tcase \"s\":\n\t\td = time.Second\n\tcase \"m\":\n\t\td = time.Minute\n\tcase \"h\":\n\t\td = time.Hour\n\tdefault:\n\t\td = time.Nanosecond\n\t}\n\treturn d\n}\n\nfunc init() {\n\tinputs.Add(\"influxdb_listener\", func() telegraf.Input {\n\t\treturn &InfluxDBListener{\n\t\t\tServiceAddress: \":8186\",\n\t\t\ttimeFunc:       time.Now,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/influxdb_listener_benchmark_test.go",
    "content": "package influxdb_listener\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// newListener is the minimal InfluxDBListener construction to serve writes.\nfunc newListener() *InfluxDBListener {\n\tlistener := &InfluxDBListener{\n\t\ttimeFunc:     time.Now,\n\t\tacc:          &testutil.NopAccumulator{},\n\t\tbytesRecv:    selfstat.Register(\"influxdb_listener\", \"bytes_received\", map[string]string{}),\n\t\twritesServed: selfstat.Register(\"influxdb_listener\", \"writes_served\", map[string]string{}),\n\t\tMaxBodySize:  config.Size(defaultMaxBodySize),\n\t}\n\treturn listener\n}\n\nfunc BenchmarkInfluxDBListener_serveWrite(b *testing.B) {\n\tres := httptest.NewRecorder()\n\taddr := \"http://localhost/write?db=mydb\"\n\n\tbenchmarks := []struct {\n\t\tname  string\n\t\tlines string\n\t}{\n\t\t{\n\t\t\tname:  \"single line, tag, and field\",\n\t\t\tlines: lines(1, 1, 1),\n\t\t},\n\t\t{\n\t\t\tname:  \"single line, 10 tags and fields\",\n\t\t\tlines: lines(1, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"single line, 100 tags and fields\",\n\t\t\tlines: lines(1, 100, 100),\n\t\t},\n\t\t{\n\t\t\tname:  \"1k lines, single tag and field\",\n\t\t\tlines: lines(1000, 1, 1),\n\t\t},\n\t\t{\n\t\t\tname:  \"1k lines, 10 tags and fields\",\n\t\t\tlines: lines(1000, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"10k lines, 10 tags and fields\",\n\t\t\tlines: lines(10000, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"100k lines, 10 tags and fields\",\n\t\t\tlines: lines(100000, 10, 10),\n\t\t},\n\t}\n\n\tfor _, bm := range benchmarks {\n\t\tb.Run(bm.name, func(b *testing.B) {\n\t\t\tlistener := newListener()\n\n\t\t\tb.ResetTimer()\n\t\t\tfor n := 0; n < b.N; n++ {\n\t\t\t\treq, err := http.NewRequest(\"POST\", addr, strings.NewReader(bm.lines))\n\t\t\t\tif err != nil {\n\t\t\t\t\tb.Error(err)\n\t\t\t\t}\n\t\t\t\tlistener.handleWrite()(res, req)\n\t\t\t\tif res.Code != http.StatusNoContent {\n\t\t\t\t\tb.Errorf(\"unexpected status %d\", res.Code)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc lines(lines, numTags, numFields int) string {\n\tlp := make([]string, 0, lines)\n\tfor i := 0; i < lines; i++ {\n\t\ttags := make([]string, 0, numTags)\n\t\tfor j := 0; j < numTags; j++ {\n\t\t\ttags = append(tags, fmt.Sprintf(\"t%d=v%d\", j, j))\n\t\t}\n\n\t\tfields := make([]string, 0, numFields)\n\t\tfor k := 0; k < numFields; k++ {\n\t\t\tfields = append(fields, fmt.Sprintf(\"f%d=%d\", k, k))\n\t\t}\n\n\t\tlp = append(lp, fmt.Sprintf(\"m%d,%s %s\",\n\t\t\ti,\n\t\t\tstrings.Join(tags, \",\"),\n\t\t\tstrings.Join(fields, \",\"),\n\t\t))\n\t}\n\n\treturn strings.Join(lp, \"\\n\")\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/influxdb_listener_test.go",
    "content": "package influxdb_listener\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\ttestMsg = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\\n\"\n\n\ttestMsgNoNewline = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\"\n\n\ttestMsgs = `cpu_load_short,host=server02 value=12.0 1422568543702900257\ncpu_load_short,host=server03 value=12.0 1422568543702900257\ncpu_load_short,host=server04 value=12.0 1422568543702900257\ncpu_load_short,host=server05 value=12.0 1422568543702900257\ncpu_load_short,host=server06 value=12.0 1422568543702900257\n`\n\ttestPartial = `cpu,host=a value1=1\ncpu,host=b value1=1,value2=+Inf,value3=3\ncpu,host=c value1=1`\n\n\tbadMsg = \"blahblahblah: 42\\n\"\n\n\temptyMsg = \"\"\n\n\tbasicUsername = \"test-username-please-ignore\"\n\tbasicPassword = \"super-secure-password!\"\n)\n\nvar (\n\tpki             = testutil.NewPKI(\"../../../testutil/pki\")\n\tparserTestCases = []struct {\n\t\tparser string\n\t}{\n\t\t{\"upstream\"},\n\t\t{\"internal\"},\n\t}\n)\n\nfunc newTestListener() *InfluxDBListener {\n\tlistener := &InfluxDBListener{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\ttimeFunc:       time.Now,\n\t}\n\treturn listener\n}\n\nfunc newTestAuthListener() *InfluxDBListener {\n\tlistener := newTestListener()\n\tlistener.BasicUsername = basicUsername\n\tlistener.BasicPassword = basicPassword\n\treturn listener\n}\n\nfunc newTestSecureListener() *InfluxDBListener {\n\tlistener := &InfluxDBListener{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tServerConfig:   *pki.TLSServerConfig(),\n\t\ttimeFunc:       time.Now,\n\t}\n\n\treturn listener\n}\n\nfunc getSecureClient() *http.Client {\n\ttlsConfig, err := pki.TLSClientConfig().TLSConfig()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t}\n}\n\nfunc createURL(listener *InfluxDBListener, scheme, path, rawquery string) string {\n\tu := url.URL{\n\t\tScheme:   scheme,\n\t\tHost:     \"localhost:\" + strconv.Itoa(listener.port),\n\t\tPath:     path,\n\t\tRawQuery: rawquery,\n\t}\n\treturn u.String()\n}\n\nfunc TestWriteSecureNoClientAuth(t *testing.T) {\n\tlistener := newTestSecureListener()\n\tlistener.TLSAllowedCACerts = nil\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tcas := x509.NewCertPool()\n\tcas.AppendCertsFromPEM([]byte(pki.ReadServerCert()))\n\tnoClientAuthClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tRootCAs: cas,\n\t\t\t},\n\t\t},\n\t}\n\n\t// post single message to listener\n\tresp, err := noClientAuthClient.Post(createURL(listener, \"https\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteSecureWithClientAuth(t *testing.T) {\n\tlistener := newTestSecureListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := getSecureClient().Post(createURL(listener, \"https\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteBasicAuth(t *testing.T) {\n\tlistener := newTestAuthListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tclient := &http.Client{}\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.SetBasicAuth(basicUsername, basicPassword)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusNoContent, resp.StatusCode)\n}\n\nfunc TestWriteToken(t *testing.T) {\n\tplugin := &InfluxDBListener{\n\t\tServiceAddress:    \"localhost:0\",\n\t\tTokenSharedSecret: \"a S3cr3T $sTr1ng\",\n\t\tTokenUsername:     \"John Doe\",\n\t\tLog:               testutil.Logger{},\n\t\ttimeFunc:          time.Now,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Create a valid token\n\ttoken, err := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{\n\t\t\"username\": plugin.TokenUsername,\n\t\t\"exp\":      time.Now().Add(5 * time.Minute).Unix(),\n\t}).SignedString([]byte(plugin.TokenSharedSecret))\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(\"POST\", createURL(plugin, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.Header.Add(\"Authentication\", \"Bearer \"+token)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusNoContent, resp.StatusCode)\n}\n\nfunc TestWriteTokenInvalidUser(t *testing.T) {\n\tplugin := &InfluxDBListener{\n\t\tServiceAddress:    \"localhost:0\",\n\t\tTokenSharedSecret: \"a S3cr3T $sTr1ng\",\n\t\tTokenUsername:     \"John Doe\",\n\t\tLog:               testutil.Logger{},\n\t\ttimeFunc:          time.Now,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Create a valid token\n\ttoken, err := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{\n\t\t\"username\": \"peter\",\n\t\t\"exp\":      time.Now().Add(5 * time.Minute).Unix(),\n\t}).SignedString([]byte(plugin.TokenSharedSecret))\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(\"POST\", createURL(plugin, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.Header.Add(\"Authentication\", \"Bearer \"+token)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusUnauthorized, resp.StatusCode)\n}\n\nfunc TestWriteTokenExpired(t *testing.T) {\n\tplugin := &InfluxDBListener{\n\t\tServiceAddress:    \"localhost:0\",\n\t\tTokenSharedSecret: \"a S3cr3T $sTr1ng\",\n\t\tTokenUsername:     \"John Doe\",\n\t\tLog:               testutil.Logger{},\n\t\ttimeFunc:          time.Now,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Create a valid token\n\ttoken, err := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{\n\t\t\"username\": plugin.TokenUsername,\n\t\t\"exp\":      time.Now().Add(-5 * time.Minute).Unix(),\n\t}).SignedString([]byte(plugin.TokenSharedSecret))\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(\"POST\", createURL(plugin, \"http\", \"/write\", \"db=mydb\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.Header.Add(\"Authentication\", \"Bearer \"+token)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\tbody, err := io.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusUnauthorized, resp.StatusCode)\n\trequire.EqualValues(t, \"token expired\", strings.TrimSpace(string(body)))\n}\n\nfunc TestWriteKeepDatabase(t *testing.T) {\n\ttestMsgWithDB := \"cpu_load_short,host=server01,database=wrongdb value=12.0 1422568543702900257\\n\"\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\t\t\tlistener.DatabaseTag = \"database\"\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\tmap[string]string{\"host\": \"server01\", \"database\": \"mydb\"},\n\t\t\t)\n\n\t\t\t// post single message to listener with a database tag in it already. It should be clobbered.\n\t\t\tresp, err = http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgWithDB))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\tmap[string]string{\"host\": \"server01\", \"database\": \"mydb\"},\n\t\t\t)\n\n\t\t\t// post multiple message to listener\n\t\t\tresp, err = http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgs))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(2)\n\t\t\thostTags := []string{\"server02\", \"server03\",\n\t\t\t\t\"server04\", \"server05\", \"server06\"}\n\t\t\tfor _, hostTag := range hostTags {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\t\tmap[string]string{\"host\": hostTag, \"database\": \"mydb\"},\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestWriteRetentionPolicyTag(t *testing.T) {\n\tlistener := newTestListener()\n\tlistener.RetentionPolicyTag = \"rp\"\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"rp=myrp\"), \"\", bytes.NewBufferString(\"cpu time_idle=42\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.Equal(t, 204, resp.StatusCode)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"rp\": \"myrp\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time_idle\": 42.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tacc.Wait(1)\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\n// http listener should add a newline at the end of the buffer if it's not there\nfunc TestWriteNoNewline(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\tmap[string]string{\"host\": \"server01\"},\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestPartialWrite(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testPartial))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu\",\n\t\t\t\tmap[string]interface{}{\"value1\": float64(1)},\n\t\t\t\tmap[string]string{\"host\": \"a\"},\n\t\t\t)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu\",\n\t\t\t\tmap[string]interface{}{\"value1\": float64(1)},\n\t\t\t\tmap[string]string{\"host\": \"c\"},\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestWriteMaxLineSizeIncrease(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := &InfluxDBListener{\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\tServiceAddress: \"localhost:0\",\n\t\t\t\tParserType:     tc.parser,\n\t\t\t\ttimeFunc:       time.Now,\n\t\t\t}\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// Post a gigantic metric to the listener and verify that it writes OK this time:\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBuffer(hugeMetric))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteVerySmallMaxBody(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := &InfluxDBListener{\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\tServiceAddress: \"localhost:0\",\n\t\t\t\tMaxBodySize:    config.Size(4096),\n\t\t\t\tParserType:     tc.parser,\n\t\t\t\ttimeFunc:       time.Now,\n\t\t\t}\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tfor _, parser := range []string{\"internal\", \"upstream\"} {\n\t\t\t\tlistener.ParserType = parser\n\n\t\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBuffer(hugeMetric))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\t\trequire.EqualValues(t, 413, resp.StatusCode)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestWriteLargeLine(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\thugeMetricString := string(hugeMetric)\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := &InfluxDBListener{\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\tServiceAddress: \"localhost:0\",\n\t\t\t\tParserType:     tc.parser,\n\t\t\t\ttimeFunc: func() time.Time {\n\t\t\t\t\treturn time.Unix(123456789, 0)\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBufferString(hugeMetricString+testMsgs))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\t// TODO: with the new parser, long lines aren't a problem.  Do we need to skip them?\n\t\t\t// require.EqualValues(t, 400, resp.StatusCode)\n\n\t\t\texpected := testutil.MustMetric(\n\t\t\t\t\"super_long_metric\",\n\t\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"clients\":                     42,\n\t\t\t\t\t\"connected_followers\":         43,\n\t\t\t\t\t\"evicted_keys\":                44,\n\t\t\t\t\t\"expired_keys\":                45,\n\t\t\t\t\t\"instantaneous_ops_per_sec\":   46,\n\t\t\t\t\t\"keyspace_hitrate\":            47.0,\n\t\t\t\t\t\"keyspace_hits\":               48,\n\t\t\t\t\t\"keyspace_misses\":             49,\n\t\t\t\t\t\"latest_fork_usec\":            50,\n\t\t\t\t\t\"master_repl_offset\":          51,\n\t\t\t\t\t\"mem_fragmentation_ratio\":     52.58,\n\t\t\t\t\t\"pubsub_channels\":             53,\n\t\t\t\t\t\"pubsub_patterns\":             54,\n\t\t\t\t\t\"rdb_changes_since_last_save\": 55,\n\t\t\t\t\t\"repl_backlog_active\":         56,\n\t\t\t\t\t\"repl_backlog_histlen\":        57,\n\t\t\t\t\t\"repl_backlog_size\":           58,\n\t\t\t\t\t\"sync_full\":                   59,\n\t\t\t\t\t\"sync_partial_err\":            60,\n\t\t\t\t\t\"sync_partial_ok\":             61,\n\t\t\t\t\t\"total_commands_processed\":    62,\n\t\t\t\t\t\"total_connections_received\":  63,\n\t\t\t\t\t\"uptime\":                      64,\n\t\t\t\t\t\"used_cpu_sys\":                65.07,\n\t\t\t\t\t\"used_cpu_sys_children\":       66.0,\n\t\t\t\t\t\"used_cpu_user\":               67.1,\n\t\t\t\t\t\"used_cpu_user_children\":      68.0,\n\t\t\t\t\t\"used_memory\":                 692048,\n\t\t\t\t\t\"used_memory_lua\":             70792,\n\t\t\t\t\t\"used_memory_peak\":            711128,\n\t\t\t\t\t\"used_memory_rss\":             7298144,\n\t\t\t\t},\n\t\t\t\ttime.Unix(123456789, 0),\n\t\t\t)\n\n\t\t\tm, ok := acc.Get(\"super_long_metric\")\n\t\t\trequire.True(t, ok)\n\t\t\ttestutil.RequireMetricEqual(t, expected, testutil.FromTestMetric(m))\n\n\t\t\thostTags := []string{\"server02\", \"server03\",\n\t\t\t\t\"server04\", \"server05\", \"server06\"}\n\t\t\tacc.Wait(len(hostTags))\n\t\t\tfor _, hostTag := range hostTags {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\t\tmap[string]string{\"host\": hostTag},\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// test that writing gzipped data works\nfunc TestWriteGzippedData(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tdata, err := os.ReadFile(\"./testdata/testmsgs.gz\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/write\", \"\"), bytes.NewBuffer(data))\n\t\t\trequire.NoError(t, err)\n\t\t\treq.Header.Set(\"Content-Encoding\", \"gzip\")\n\n\t\t\tclient := &http.Client{}\n\t\t\tresp, err := client.Do(req)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\thostTags := []string{\"server02\", \"server03\",\n\t\t\t\t\"server04\", \"server05\", \"server06\"}\n\t\t\tacc.Wait(len(hostTags))\n\t\t\tfor _, hostTag := range hostTags {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\t\tmap[string]string{\"host\": hostTag},\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// writes 25,000 metrics to the listener with 10 different writers\nfunc TestWriteHighTraffic(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" {\n\t\tt.Skip(\"Skipping due to hang on darwin\")\n\t}\n\t// resource intensive, large test\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping long test in short mode\")\n\t}\n\tlistener := newTestListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post many messages to listener\n\tvar wg sync.WaitGroup\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func(innerwg *sync.WaitGroup) {\n\t\t\tdefer innerwg.Done()\n\t\t\tfor i := 0; i < 500; i++ {\n\t\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(testMsgs))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif err := resp.Body.Close(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif resp.StatusCode != 204 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(&wg)\n\t}\n\n\twg.Wait()\n\trequire.NoError(t, listener.Gather(acc))\n\n\tacc.Wait(25000)\n\trequire.Equal(t, int64(25000), int64(acc.NMetrics()))\n}\n\nfunc TestReceive404ForInvalidEndpoint(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/foobar\", \"\"), \"\", bytes.NewBufferString(testMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 404, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteInvalid(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(badMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteEmpty(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"db=mydb\"), \"\", bytes.NewBufferString(emptyMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestQuery(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post query to listener\n\t\t\tresp, err := http.Post(\n\t\t\t\tcreateURL(listener, \"http\", \"/query\", \"db=&q=CREATE+DATABASE+IF+NOT+EXISTS+%22mydb%22\"), \"\", nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 200, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestPing(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post ping to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/ping\", \"\"), \"\", nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"1.0\", resp.Header[\"X-Influxdb-Version\"][0])\n\t\t\trequire.Empty(t, resp.Header[\"Content-Type\"])\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestPingVerbose(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post ping to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/ping\", \"verbose=1\"), \"\", nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"1.0\", resp.Header[\"X-Influxdb-Version\"][0])\n\t\t\trequire.Equal(t, \"application/json\", resp.Header[\"Content-Type\"][0])\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 200, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteWithPrecision(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tmsg := \"xyzzy value=42 1422568543\\n\"\n\t\t\tresp, err := http.Post(\n\t\t\t\tcreateURL(listener, \"http\", \"/write\", \"precision=s\"), \"\", bytes.NewBufferString(msg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\trequire.Len(t, acc.Metrics, 1)\n\t\t\t// When timestamp is provided, the precision parameter is\n\t\t\t// overloaded to specify the timestamp's unit\n\t\t\trequire.Equal(t, time.Unix(0, 1422568543000000000), acc.Metrics[0].Time)\n\t\t})\n\t}\n}\n\nfunc TestWriteWithPrecisionNoTimestamp(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\t\t\tlistener.timeFunc = func() time.Time {\n\t\t\t\treturn time.Unix(42, 123456789)\n\t\t\t}\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tmsg := \"xyzzy value=42\\n\"\n\t\t\tresp, err := http.Post(\n\t\t\t\tcreateURL(listener, \"http\", \"/write\", \"precision=s\"), \"\", bytes.NewBufferString(msg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\trequire.Len(t, acc.Metrics, 1)\n\t\t\t// When timestamp is omitted, the precision parameter actually\n\t\t\t// specifies the precision.  The timestamp is set to the greatest\n\t\t\t// integer unit less than the provided timestamp (floor).\n\t\t\trequire.Equal(t, time.Unix(42, 0), acc.Metrics[0].Time)\n\t\t})\n\t}\n}\n\nfunc TestWriteUpstreamParseErrors(t *testing.T) {\n\tvar tests = []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"one parse error\",\n\t\t\tinput:    \"foo value=1.0\\nfoo value=2asdf2.0\\nfoo value=3.0\\nfoo value=4.0\",\n\t\t\texpected: `metric parse error: cannot parse value for field key \"value\": invalid float value syntax at 2:11`,\n\t\t},\n\t\t{\n\t\t\tname:     \"two parse errors\",\n\t\t\tinput:    \"foo value=1asdf2.0\\nfoo value=2.0\\nfoo value=3asdf2.0\\nfoo value=4.0\",\n\t\t\texpected: `metric parse error: cannot parse value for field key \"value\": invalid float value syntax at 1:11 (and 1 other parse error)`,\n\t\t},\n\t\t{\n\t\t\tname:     \"three or more parse errors\",\n\t\t\tinput:    \"foo value=1asdf2.0\\nfoo value=2.0\\nfoo value=3asdf2.0\\nfoo value=4asdf2.0\",\n\t\t\texpected: `metric parse error: cannot parse value for field key \"value\": invalid float value syntax at 1:11 (and 2 other parse errors)`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = \"upstream\"\n\n\t\t\tacc := &testutil.NopAccumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBufferString(tt.input))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\t\t\trequire.Equal(t, tt.expected, resp.Header[\"X-Influxdb-Error\"][0])\n\t\t})\n\t}\n}\n\nfunc TestWriteParseErrors(t *testing.T) {\n\tvar tests = []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"one parse error\",\n\t\t\tinput:    \"foo value=1.0\\nfoo value=2asdf2.0\\nfoo value=3.0\\nfoo value=4.0\",\n\t\t\texpected: `metric parse error: expected field at 2:12: \"foo value=2\"`,\n\t\t},\n\t\t{\n\t\t\tname:     \"two parse errors\",\n\t\t\tinput:    \"foo value=1asdf2.0\\nfoo value=2.0\\nfoo value=3asdf2.0\\nfoo value=4.0\",\n\t\t\texpected: `metric parse error: expected field at 1:12: \"foo value=1\" (and 1 other parse error)`,\n\t\t},\n\t\t{\n\t\t\tname:     \"three or more parse errors\",\n\t\t\tinput:    \"foo value=1asdf2.0\\nfoo value=2.0\\nfoo value=3asdf2.0\\nfoo value=4asdf2.0\",\n\t\t\texpected: `metric parse error: expected field at 1:12: \"foo value=1\" (and 2 other parse errors)`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\n\t\t\tacc := &testutil.NopAccumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/write\", \"\"), \"\", bytes.NewBufferString(tt.input))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\t\t\trequire.Equal(t, tt.expected, resp.Header[\"X-Influxdb-Error\"][0])\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/sample.conf",
    "content": "# Accept metrics over InfluxDB 1.x HTTP API\n[[inputs.influxdb_listener]]\n  ## Address and port to host HTTP listener on\n  service_address = \":8186\"\n\n  ## maximum duration before timing out read of the request\n  read_timeout = \"10s\"\n  ## maximum duration before timing out write of the response\n  write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  max_body_size = 0\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  tls_cert = \"/etc/telegraf/cert.pem\"\n  tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional tag name used to store the database name.\n  ## If the write has a database in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  ## If you have a tag that is the same as the one specified below, and supply a database,\n  ## the tag will be overwritten with the database supplied.\n  # database_tag = \"\"\n\n  ## If set the retention policy specified in the write query will be added as\n  ## the value of this tag name.\n  # retention_policy_tag = \"\"\n\n  ## Optional username and password to accept for HTTP basic authentication\n  ## or authentication token.\n  ## You probably want to make sure you have TLS configured above for this.\n  ## Use these options for the authentication token in the form\n  ##   Authentication: Token <basic_username>:<basic_password>\n  # basic_username = \"foobar\"\n  # basic_password = \"barfoo\"\n\n  ## Optional JWT token authentication for HTTP requests\n  ## Please see the documentation at\n  ##   https://docs.influxdata.com/influxdb/v1.8/administration/authentication_and_authorization/#authenticate-using-jwt-tokens\n  ## for further details.\n  ## Please note: Token authentication and basic authentication cannot be used\n  ##              at the same time.\n  # token_shared_secret = \"\"\n  # token_username = \"\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n"
  },
  {
    "path": "plugins/inputs/influxdb_listener/testdata/huge_metric",
    "content": "super_long_metric,foo=bar clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=42i,connected_followers=43i,evicted_keys=44i,expired_keys=45i,instantaneous_ops_per_sec=46i,keyspace_hitrate=47,keyspace_hits=48i,keyspace_misses=49i,latest_fork_usec=50i,master_repl_offset=51i,mem_fragmentation_ratio=52.58,pubsub_channels=53i,pubsub_patterns=54i,rdb_changes_since_last_save=55i,repl_backlog_active=56i,repl_backlog_histlen=57i,repl_backlog_size=58i,sync_full=59i,sync_partial_err=60i,sync_partial_ok=61i,total_commands_processed=62i,total_connections_received=63i,uptime=64i,used_cpu_sys=65.07,used_cpu_sys_children=66,used_cpu_user=67.1,used_cpu_user_children=68,used_memory=692048i,used_memory_lua=70792i,used_memory_peak=711128i,used_memory_rss=7298144i\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/README.md",
    "content": "# InfluxDB V2 Listener Input Plugin\n\nThis plugin listens for requests sent according to the\n[InfluxDB HTTP v2 API][influxdb_http_api]. This allows Telegraf to serve as a\nproxy/router for the `/api/v2/write` endpoint of the InfluxDB HTTP API.\n\nThe `/api/v2/write` endpoint supports the `precision` query parameter and can be\nset to one of `ns`, `us`, `ms`, `s`.  All other parameters are ignored and defer\nto the output plugins configuration.\n\n⭐ Telegraf v1.16.0\n🏷️ datastore\n💻 all\n\n[influxdb_http_api]: https://docs.influxdata.com/influxdb/v2/api/\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `token` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Accept metrics over InfluxDB 2.x HTTP API\n[[inputs.influxdb_v2_listener]]\n  ## Address and port to host InfluxDB listener on\n  ## (Double check the port. Could be 9999 if using OSS Beta)\n  service_address = \":8086\"\n\n  ## Maximum undelivered metrics before rate limit kicks in.\n  ## When the rate limit kicks in, HTTP status 429 will be returned.\n  ## 0 disables rate limiting\n  # max_undelivered_metrics = 0\n\n  ## Maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## Maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  # max_body_size = \"32MiB\"\n\n  ## Optional tag to determine the bucket.\n  ## If the write has a bucket in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  # bucket_tag = \"\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional token to accept for HTTP authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # token = \"some-long-shared-secret-token\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n\n  ## Use new internal metrics. When true, it adds tag for alias if set.\n  # use_internal_statistics = false\n```\n\n## Metrics\n\nMetrics are created from InfluxDB Line Protocol in the request body.\n\n## Example Output\n\nUsing\n\n```sh\ncurl -i -XPOST 'http://localhost:8186/api/v2/write' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'\n```\n\nwill produce the following metric\n\n```text\ncpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000\n```\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/influxdb_v2_listener.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage influxdb_v2_listener\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx/influx_upstream\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// defaultMaxBodySize is the default maximum request body size, in bytes.\n\t// if the request body is over this size, we will return an HTTP 413 error.\n\tdefaultMaxBodySize                 = 32 * 1024 * 1024\n\tdefaultReadTimeout                 = 10 * time.Second\n\tdefaultWriteTimeout                = 10 * time.Second\n\tinternalError       badRequestCode = \"internal error\"\n\tinvalid             badRequestCode = \"invalid\"\n)\n\ntype InfluxDBV2Listener struct {\n\tServiceAddress string `toml:\"service_address\"`\n\tport           int\n\tcommon_tls.ServerConfig\n\n\tMaxUndeliveredMetrics int                 `toml:\"max_undelivered_metrics\"`\n\tReadTimeout           config.Duration     `toml:\"read_timeout\"`\n\tWriteTimeout          config.Duration     `toml:\"write_timeout\"`\n\tMaxBodySize           config.Size         `toml:\"max_body_size\"`\n\tToken                 config.Secret       `toml:\"token\"`\n\tBucketTag             string              `toml:\"bucket_tag\"`\n\tParserType            string              `toml:\"parser_type\"`\n\tUseInternalStatistics bool                `toml:\"use_internal_statistics\"`\n\tStatistics            *selfstat.Collector `toml:\"-\"`\n\tLog                   telegraf.Logger     `toml:\"-\"`\n\n\tctx                 context.Context\n\tcancel              context.CancelFunc\n\ttrackingMetricCount map[telegraf.TrackingID]int64\n\tcountLock           sync.Mutex\n\n\ttotalUndeliveredMetrics atomic.Int64\n\n\ttimeFunc influx.TimeFunc\n\tlistener net.Listener\n\n\tserver http.Server\n\tacc    telegraf.Accumulator\n\n\ttrackingAcc     telegraf.TrackingAccumulator\n\tbytesRecv       selfstat.Stat\n\trequestsServed  selfstat.Stat\n\twritesServed    selfstat.Stat\n\thealthsServed   selfstat.Stat\n\treadysServed    selfstat.Stat\n\trequestsRecv    selfstat.Stat\n\tnotFoundsServed selfstat.Stat\n\tpingsServed     selfstat.Stat\n\n\tauthFailures selfstat.Stat\n\n\tstartTime time.Time\n\n\tmux http.ServeMux\n}\n\n// The badRequestCode constants keep standard error messages\n// see: https://v2.docs.influxdata.com/v2.0/api/#operation/PostWrite\ntype badRequestCode string\n\nfunc (*InfluxDBV2Listener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (h *InfluxDBV2Listener) Init() error {\n\ttags := map[string]string{\n\t\t\"address\": h.ServiceAddress,\n\t}\n\tif !h.UseInternalStatistics {\n\t\th.bytesRecv = selfstat.Register(\"influxdb_v2_listener\", \"bytes_received\", tags)\n\t\th.requestsServed = selfstat.Register(\"influxdb_v2_listener\", \"requests_served\", tags)\n\t\th.writesServed = selfstat.Register(\"influxdb_v2_listener\", \"writes_served\", tags)\n\t\th.healthsServed = selfstat.Register(\"influxdb_v2_listener\", \"healths_served\", tags)\n\t\th.readysServed = selfstat.Register(\"influxdb_v2_listener\", \"readys_served\", tags)\n\t\th.requestsRecv = selfstat.Register(\"influxdb_v2_listener\", \"requests_received\", tags)\n\t\th.notFoundsServed = selfstat.Register(\"influxdb_v2_listener\", \"not_founds_served\", tags)\n\t\th.pingsServed = selfstat.Register(\"influxdb_v2_listener\", \"pings_served\", tags)\n\t\th.authFailures = selfstat.Register(\"influxdb_v2_listener\", \"auth_failures\", tags)\n\t\tconfig.PrintOptionValueDeprecationNotice(\"inputs.influxdb_v2_listener\", \"use_internal_statistics\", false, telegraf.DeprecationInfo{\n\t\t\tSince:     \"1.37.0\",\n\t\t\tRemovalIn: \"1.45.0\",\n\t\t\tNotice:    \"please update to 'use_internal_statistics = true'\",\n\t\t})\n\t} else {\n\t\th.bytesRecv = h.Statistics.Register(\"influxdb_v2_listener\", \"bytes_received\", tags)\n\t\th.requestsServed = h.Statistics.Register(\"influxdb_v2_listener\", \"requests_served\", tags)\n\t\th.writesServed = h.Statistics.Register(\"influxdb_v2_listener\", \"writes_served\", tags)\n\t\th.healthsServed = h.Statistics.Register(\"influxdb_v2_listener\", \"healths_served\", tags)\n\t\th.readysServed = h.Statistics.Register(\"influxdb_v2_listener\", \"readys_served\", tags)\n\t\th.requestsRecv = h.Statistics.Register(\"influxdb_v2_listener\", \"requests_received\", tags)\n\t\th.notFoundsServed = h.Statistics.Register(\"influxdb_v2_listener\", \"not_founds_served\", tags)\n\t\th.pingsServed = h.Statistics.Register(\"influxdb_v2_listener\", \"pings_served\", tags)\n\t\th.authFailures = h.Statistics.Register(\"influxdb_v2_listener\", \"auth_failures\", tags)\n\t}\n\n\tif err := h.routes(); err != nil {\n\t\treturn err\n\t}\n\n\tif h.MaxBodySize == 0 {\n\t\th.MaxBodySize = config.Size(defaultMaxBodySize)\n\t}\n\n\tif h.ReadTimeout < config.Duration(time.Second) {\n\t\th.ReadTimeout = config.Duration(defaultReadTimeout)\n\t}\n\tif h.WriteTimeout < config.Duration(time.Second) {\n\t\th.WriteTimeout = config.Duration(defaultWriteTimeout)\n\t}\n\n\treturn nil\n}\n\nfunc (*InfluxDBV2Listener) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (h *InfluxDBV2Listener) Start(acc telegraf.Accumulator) error {\n\th.acc = acc\n\th.ctx, h.cancel = context.WithCancel(context.Background())\n\tif h.MaxUndeliveredMetrics > 0 {\n\t\th.trackingAcc = h.acc.WithTracking(h.MaxUndeliveredMetrics)\n\t\th.trackingMetricCount = make(map[telegraf.TrackingID]int64, h.MaxUndeliveredMetrics)\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-h.ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase info := <-h.trackingAcc.Delivered():\n\t\t\t\t\th.countLock.Lock()\n\t\t\t\t\tif count, ok := h.trackingMetricCount[info.ID()]; ok {\n\t\t\t\t\t\th.totalUndeliveredMetrics.Add(-count)\n\t\t\t\t\t\tdelete(h.trackingMetricCount, info.ID())\n\t\t\t\t\t}\n\t\t\t\t\th.countLock.Unlock()\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\ttlsConf, err := h.ServerConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\th.server = http.Server{\n\t\tAddr:         h.ServiceAddress,\n\t\tHandler:      h,\n\t\tTLSConfig:    tlsConf,\n\t\tReadTimeout:  time.Duration(h.ReadTimeout),\n\t\tWriteTimeout: time.Duration(h.WriteTimeout),\n\t}\n\n\tvar listener net.Listener\n\tif tlsConf != nil {\n\t\tlistener, err = tls.Listen(\"tcp\", h.ServiceAddress, tlsConf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tlistener, err = net.Listen(\"tcp\", h.ServiceAddress)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\th.listener = listener\n\th.port = listener.Addr().(*net.TCPAddr).Port\n\n\tgo func() {\n\t\terr = h.server.Serve(h.listener)\n\t\tif !errors.Is(err, http.ErrServerClosed) {\n\t\t\th.Log.Infof(\"Error serving HTTP on %s\", h.ServiceAddress)\n\t\t}\n\t}()\n\n\th.startTime = h.timeFunc()\n\n\th.Log.Infof(\"Started HTTP listener service on %s\", h.ServiceAddress)\n\n\treturn nil\n}\n\nfunc (h *InfluxDBV2Listener) Stop() {\n\th.cancel()\n\terr := h.server.Shutdown(context.Background())\n\tif err != nil {\n\t\th.Log.Infof(\"Error shutting down HTTP server: %v\", err.Error())\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) ServeHTTP(res http.ResponseWriter, req *http.Request) {\n\th.requestsRecv.Incr(1)\n\th.mux.ServeHTTP(res, req)\n\th.requestsServed.Incr(1)\n}\n\nfunc (h *InfluxDBV2Listener) routes() error {\n\tcredentials := \"\"\n\tif !h.Token.Empty() {\n\t\tsecBuf, err := h.Token.Get()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcredentials = \"Token \" + secBuf.String()\n\t\tsecBuf.Destroy()\n\t}\n\n\tauthHandler := internal.GenericAuthHandler(credentials,\n\t\tfunc(_ http.ResponseWriter) {\n\t\t\th.authFailures.Incr(1)\n\t\t},\n\t)\n\n\th.mux.Handle(\"/api/v2/write\", authHandler(h.handleWrite()))\n\th.mux.Handle(\"/api/v2/health\", h.handleHealth())\n\th.mux.Handle(\"/api/v2/ready\", h.handleReady())\n\th.mux.Handle(\"/health\", h.handleHealth())\n\th.mux.Handle(\"/ready\", h.handleReady())\n\th.mux.Handle(\"/ping\", h.handlePing())\n\th.mux.Handle(\"/\", authHandler(h.handleDefault()))\n\n\treturn nil\n}\n\nfunc (h *InfluxDBV2Listener) handleHealth() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, _ *http.Request) {\n\t\tdefer h.healthsServed.Incr(1)\n\n\t\tres.Header().Set(\"Content-Type\", \"application/json\")\n\t\tbody := map[string]string{\n\t\t\t\"name\":    \"telegraf\",\n\t\t\t\"commit\":  internal.Commit,\n\t\t\t\"message\": \"ready for queries and writes\",\n\t\t\t\"status\":  \"pass\",\n\t\t\t\"version\": internal.Version,\n\t\t}\n\n\t\tpendingMetrics := h.totalUndeliveredMetrics.Load()\n\t\tif h.MaxUndeliveredMetrics > 0 && pendingMetrics >= int64(h.MaxUndeliveredMetrics) {\n\t\t\tres.WriteHeader(http.StatusServiceUnavailable)\n\t\t\tbody[\"status\"] = \"fail\"\n\t\t\tbody[\"message\"] = fmt.Sprintf(\"pending undelivered metrics (%d) is above limit\", pendingMetrics)\n\t\t} else {\n\t\t\tres.WriteHeader(http.StatusOK)\n\t\t}\n\n\t\tb, err := json.Marshal(body)\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"error marshalling json in handleHealth: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tif _, err := res.Write(b); err != nil {\n\t\t\th.Log.Debugf(\"error writing in handleHealth: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) handleReady() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, _ *http.Request) {\n\t\tdefer h.readysServed.Incr(1)\n\n\t\t// respond to ready requests\n\t\tres.Header().Set(\"Content-Type\", \"application/json\")\n\t\tres.WriteHeader(http.StatusOK)\n\t\tb, err := json.Marshal(map[string]string{\n\t\t\t\"started\": h.startTime.Format(time.RFC3339Nano),\n\t\t\t\"status\":  \"ready\",\n\t\t\t\"up\":      h.timeFunc().Sub(h.startTime).String()})\n\t\tif err != nil {\n\t\t\th.Log.Debugf(\"error marshalling json in handleReady: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tif _, err := res.Write(b); err != nil {\n\t\t\th.Log.Debugf(\"error writing in handleReady: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) handleDefault() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, req *http.Request) {\n\t\tdefer h.notFoundsServed.Incr(1)\n\t\thttp.NotFound(res, req)\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) handlePing() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, _ *http.Request) {\n\t\tdefer h.pingsServed.Incr(1)\n\t\tres.Header().Set(\"X-Influxdb-Build\", \"telegraf\")\n\t\tres.Header().Set(\"X-Influxdb-Version\", internal.FormatFullVersion())\n\t\tres.WriteHeader(http.StatusNoContent)\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) handleWrite() http.HandlerFunc {\n\treturn func(res http.ResponseWriter, req *http.Request) {\n\t\tdefer h.writesServed.Incr(1)\n\n\t\t// Check that the content length is not too large for us to handle.\n\t\tif req.ContentLength > int64(h.MaxBodySize) {\n\t\t\tif err := tooLarge(res, int64(h.MaxBodySize)); err != nil {\n\t\t\t\th.Log.Debugf(\"error in too-large: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tbucket := req.URL.Query().Get(\"bucket\")\n\n\t\tbody := req.Body\n\t\tbody = http.MaxBytesReader(res, body, int64(h.MaxBodySize))\n\t\t// Handle gzip request bodies\n\t\tif req.Header.Get(\"Content-Encoding\") == \"gzip\" {\n\t\t\tvar err error\n\t\t\tbody, err = gzip.NewReader(body)\n\t\t\tif err != nil {\n\t\t\t\th.Log.Debugf(\"Error decompressing request body: %v\", err.Error())\n\t\t\t\tif err := badRequest(res, invalid, err.Error()); err != nil {\n\t\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer body.Close()\n\t\t}\n\n\t\tvar readErr error\n\t\tvar bytes []byte\n\t\tbytes, readErr = io.ReadAll(body)\n\t\tif readErr != nil {\n\t\t\th.Log.Debugf(\"Error parsing the request body: %v\", readErr.Error())\n\t\t\tif err := badRequest(res, internalError, readErr.Error()); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tprecisionStr := req.URL.Query().Get(\"precision\")\n\n\t\tvar metrics []telegraf.Metric\n\t\tvar err error\n\t\tif h.ParserType == \"upstream\" {\n\t\t\tparser := influx_upstream.Parser{}\n\t\t\terr = parser.Init()\n\t\t\tif !errors.Is(err, io.EOF) && err != nil {\n\t\t\t\th.Log.Debugf(\"Error initializing parser: %v\", err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\tparser.SetTimeFunc(influx_upstream.TimeFunc(h.timeFunc))\n\n\t\t\tif precisionStr != \"\" {\n\t\t\t\tprecision := getPrecisionMultiplier(precisionStr)\n\t\t\t\tif err = parser.SetTimePrecision(precision); err != nil {\n\t\t\t\t\th.Log.Debugf(\"Error setting precision of parser: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmetrics, err = parser.Parse(bytes)\n\t\t} else {\n\t\t\tparser := influx.Parser{}\n\t\t\terr = parser.Init()\n\t\t\tif !errors.Is(err, io.EOF) && err != nil {\n\t\t\t\th.Log.Debugf(\"Error initializing parser: %v\", err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\tparser.SetTimeFunc(h.timeFunc)\n\n\t\t\tif precisionStr != \"\" {\n\t\t\t\tprecision := getPrecisionMultiplier(precisionStr)\n\t\t\t\tparser.SetTimePrecision(precision)\n\t\t\t}\n\n\t\t\tmetrics, err = parser.Parse(bytes)\n\t\t}\n\n\t\tif !errors.Is(err, io.EOF) && err != nil {\n\t\t\th.Log.Debugf(\"Error parsing the request body: %v\", err.Error())\n\t\t\tif err := badRequest(res, invalid, err.Error()); err != nil {\n\t\t\t\th.Log.Debugf(\"error in bad-request: %v\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tfor _, m := range metrics {\n\t\t\t// Handle bucket_tag override\n\t\t\tif h.BucketTag != \"\" && bucket != \"\" {\n\t\t\t\tm.AddTag(h.BucketTag, bucket)\n\t\t\t}\n\t\t}\n\n\t\tif h.MaxUndeliveredMetrics > 0 {\n\t\t\th.writeWithTracking(res, metrics)\n\t\t} else {\n\t\t\th.write(res, metrics)\n\t\t}\n\t}\n}\n\nfunc (h *InfluxDBV2Listener) writeWithTracking(res http.ResponseWriter, metrics []telegraf.Metric) {\n\tif len(metrics) > h.MaxUndeliveredMetrics {\n\t\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\t\th.Log.Debugf(\"status %d, always rejecting batch of %d metrics: larger than max_undelivered_metrics %d\",\n\t\t\thttp.StatusRequestEntityTooLarge, len(metrics), h.MaxUndeliveredMetrics)\n\t\treturn\n\t}\n\n\tpending := h.totalUndeliveredMetrics.Load()\n\tremainingUndeliveredMetrics := int64(h.MaxUndeliveredMetrics) - pending\n\tif int64(len(metrics)) > remainingUndeliveredMetrics {\n\t\tres.WriteHeader(http.StatusTooManyRequests)\n\t\th.Log.Debugf(\"status %d, rejecting batch of %d metrics: larger than remaining undelivered metrics %d\",\n\t\t\thttp.StatusTooManyRequests, len(metrics), remainingUndeliveredMetrics)\n\t\treturn\n\t}\n\n\th.countLock.Lock()\n\ttrackingID := h.trackingAcc.AddTrackingMetricGroup(metrics)\n\th.trackingMetricCount[trackingID] = int64(len(metrics))\n\th.totalUndeliveredMetrics.Add(int64(len(metrics)))\n\th.countLock.Unlock()\n\n\tres.WriteHeader(http.StatusNoContent)\n}\n\nfunc (h *InfluxDBV2Listener) write(res http.ResponseWriter, metrics []telegraf.Metric) {\n\tfor _, m := range metrics {\n\t\th.acc.AddMetric(m)\n\t}\n\n\tres.WriteHeader(http.StatusNoContent)\n}\n\nfunc tooLarge(res http.ResponseWriter, maxLength int64) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tres.Header().Set(\"X-Influxdb-Error\", \"http: request body too large\")\n\tres.WriteHeader(http.StatusRequestEntityTooLarge)\n\tb, err := json.Marshal(map[string]string{\n\t\t\"code\":      fmt.Sprint(invalid),\n\t\t\"message\":   \"http: request body too large\",\n\t\t\"maxLength\": strconv.FormatInt(maxLength, 10)})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = res.Write(b)\n\treturn err\n}\n\nfunc badRequest(res http.ResponseWriter, code badRequestCode, errString string) error {\n\tres.Header().Set(\"Content-Type\", \"application/json\")\n\tif errString == \"\" {\n\t\terrString = \"http: bad request\"\n\t}\n\tres.Header().Set(\"X-Influxdb-Error\", errString)\n\tres.WriteHeader(http.StatusBadRequest)\n\tb, err := json.Marshal(map[string]string{\n\t\t\"code\":    fmt.Sprint(code),\n\t\t\"message\": errString,\n\t\t\"op\":      \"\",\n\t\t\"err\":     errString,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = res.Write(b)\n\treturn err\n}\n\nfunc getPrecisionMultiplier(precision string) time.Duration {\n\t// Influxdb defaults silently to nanoseconds if precision isn't\n\t// one of the following:\n\tvar d time.Duration\n\tswitch precision {\n\tcase \"us\":\n\t\td = time.Microsecond\n\tcase \"ms\":\n\t\td = time.Millisecond\n\tcase \"s\":\n\t\td = time.Second\n\tdefault:\n\t\td = time.Nanosecond\n\t}\n\treturn d\n}\n\nfunc init() {\n\tinputs.Add(\"influxdb_v2_listener\", func() telegraf.Input {\n\t\treturn &InfluxDBV2Listener{\n\t\t\tServiceAddress: \":8086\",\n\t\t\ttimeFunc:       time.Now,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/influxdb_v2_listener_benchmark_test.go",
    "content": "package influxdb_v2_listener\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gofrs/uuid/v5\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// newListener is the minimal InfluxDBV2Listener construction to serve writes.\nfunc newListener(b *testing.B) *InfluxDBV2Listener {\n\t// Make sure we do have a unique stats for this instance to avoid side effects\n\tid, err := uuid.NewV4()\n\trequire.NoError(b, err)\n\n\tlistener := &InfluxDBV2Listener{\n\t\ttimeFunc: time.Now,\n\t\tacc:      &testutil.NopAccumulator{},\n\t\tbytesRecv: selfstat.Register(\"influxdb_v2_listener\", \"bytes_received\", map[string]string{\n\t\t\t\"id\": id.String(),\n\t\t}),\n\t\twritesServed: selfstat.Register(\"influxdb_v2_listener\", \"writes_served\", map[string]string{\n\t\t\t\"id\": id.String(),\n\t\t}),\n\t\tMaxBodySize: config.Size(defaultMaxBodySize),\n\t}\n\n\tb.Cleanup(func() {\n\t\tlistener.bytesRecv.Unregister()\n\t\tlistener.writesServed.Unregister()\n\t})\n\n\treturn listener\n}\n\nfunc BenchmarkInfluxDBV2Listener_serveWrite(b *testing.B) {\n\tres := httptest.NewRecorder()\n\taddr := \"http://localhost/api/v2/write?bucket=mybucket\"\n\n\tbenchmarks := []struct {\n\t\tname  string\n\t\tlines string\n\t}{\n\t\t{\n\t\t\tname:  \"single line, tag, and field\",\n\t\t\tlines: lines(1, 1, 1),\n\t\t},\n\t\t{\n\t\t\tname:  \"single line, 10 tags and fields\",\n\t\t\tlines: lines(1, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"single line, 100 tags and fields\",\n\t\t\tlines: lines(1, 100, 100),\n\t\t},\n\t\t{\n\t\t\tname:  \"1k lines, single tag and field\",\n\t\t\tlines: lines(1000, 1, 1),\n\t\t},\n\t\t{\n\t\t\tname:  \"1k lines, 10 tags and fields\",\n\t\t\tlines: lines(1000, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"10k lines, 10 tags and fields\",\n\t\t\tlines: lines(10000, 10, 10),\n\t\t},\n\t\t{\n\t\t\tname:  \"100k lines, 10 tags and fields\",\n\t\t\tlines: lines(100000, 10, 10),\n\t\t},\n\t}\n\n\tfor _, bm := range benchmarks {\n\t\tb.Run(bm.name, func(b *testing.B) {\n\t\t\tlistener := newListener(b)\n\n\t\t\tb.ResetTimer()\n\t\t\tfor n := 0; n < b.N; n++ {\n\t\t\t\treq, err := http.NewRequest(\"POST\", addr, strings.NewReader(bm.lines))\n\t\t\t\trequire.NoError(b, err)\n\t\t\t\tlistener.handleWrite()(res, req)\n\t\t\t\trequire.Equal(b, http.StatusNoContent, res.Code, \"unexpected status\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc lines(lines, numTags, numFields int) string {\n\tlp := make([]string, 0, lines)\n\tfor i := 0; i < lines; i++ {\n\t\ttags := make([]string, 0, numTags)\n\t\tfor j := 0; j < numTags; j++ {\n\t\t\ttags = append(tags, fmt.Sprintf(\"t%d=v%d\", j, j))\n\t\t}\n\n\t\tfields := make([]string, 0, numFields)\n\t\tfor k := 0; k < numFields; k++ {\n\t\t\tfields = append(fields, fmt.Sprintf(\"f%d=%d\", k, k))\n\t\t}\n\n\t\tlp = append(lp, fmt.Sprintf(\"m%d,%s %s\",\n\t\t\ti,\n\t\t\tstrings.Join(tags, \",\"),\n\t\t\tstrings.Join(fields, \",\"),\n\t\t))\n\t}\n\n\treturn strings.Join(lp, \"\\n\")\n}\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/influxdb_v2_listener_test.go",
    "content": "package influxdb_v2_listener\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gofrs/uuid/v5\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\ttestMsg = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\\n\"\n\n\ttestMsgNoNewline = \"cpu_load_short,host=server01 value=12.0 1422568543702900257\"\n\n\ttestMsgs = `cpu_load_short,host=server02 value=12.0 1422568543702900257\ncpu_load_short,host=server03 value=12.0 1422568543702900257\ncpu_load_short,host=server04 value=12.0 1422568543702900257\ncpu_load_short,host=server05 value=12.0 1422568543702900257\ncpu_load_short,host=server06 value=12.0 1422568543702900257\n`\n\ttestPartial = `cpu,host=a value1=1\ncpu,host=b value1=1,value2=+Inf,value3=3\ncpu,host=c value1=1`\n\n\tbadMsg = \"blahblahblah: 42\\n\"\n\n\temptyMsg = \"\"\n\n\ttoken = \"test-token-please-ignore\"\n)\n\nvar (\n\tpki             = testutil.NewPKI(\"../../../testutil/pki\")\n\tparserTestCases = []struct {\n\t\tparser string\n\t}{\n\t\t{\"upstream\"},\n\t\t{\"internal\"},\n\t}\n)\n\nfunc newTestListener() *InfluxDBV2Listener {\n\tlistener := &InfluxDBV2Listener{\n\t\tLog:            testutil.Logger{},\n\t\tServiceAddress: \"localhost:0\",\n\t\tStatistics:     selfstat.NewCollector(nil),\n\t\ttimeFunc:       time.Now,\n\t}\n\treturn listener\n}\n\nfunc newTestAuthListener() *InfluxDBV2Listener {\n\tlistener := newTestListener()\n\tlistener.Token = config.NewSecret([]byte(token))\n\treturn listener\n}\n\nfunc newRateLimitedTestListener(maxUndeliveredMetrics int) *InfluxDBV2Listener {\n\tlistener := newTestListener()\n\tlistener.MaxUndeliveredMetrics = maxUndeliveredMetrics\n\treturn listener\n}\n\nfunc newTestSecureListener() *InfluxDBV2Listener {\n\tlistener := newTestListener()\n\tlistener.ServerConfig = *pki.TLSServerConfig()\n\treturn listener\n}\n\nfunc getSecureClient() *http.Client {\n\ttlsConfig, err := pki.TLSClientConfig().TLSConfig()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsConfig,\n\t\t},\n\t}\n}\n\nfunc createURL(listener *InfluxDBV2Listener, scheme, path, rawquery string) string {\n\tu := url.URL{\n\t\tScheme:   scheme,\n\t\tHost:     \"localhost:\" + strconv.Itoa(listener.port),\n\t\tPath:     path,\n\t\tRawQuery: rawquery,\n\t}\n\treturn u.String()\n}\n\nfunc TestWriteSecureNoClientAuth(t *testing.T) {\n\tlistener := newTestSecureListener()\n\tlistener.TLSAllowedCACerts = nil\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tcas := x509.NewCertPool()\n\tcas.AppendCertsFromPEM([]byte(pki.ReadServerCert()))\n\tnoClientAuthClient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tRootCAs: cas,\n\t\t\t},\n\t\t},\n\t}\n\n\t// post single message to listener\n\tresp, err := noClientAuthClient.Post(createURL(listener, \"https\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteSecureWithClientAuth(t *testing.T) {\n\tlistener := newTestSecureListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := getSecureClient().Post(createURL(listener, \"https\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestWriteTokenAuth(t *testing.T) {\n\tlistener := newTestAuthListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tclient := &http.Client{}\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Authorization\", \"Token \"+token)\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, http.StatusNoContent, resp.StatusCode)\n}\n\nfunc TestWriteKeepBucket(t *testing.T) {\n\ttestMsgWithDB := \"cpu_load_short,host=server01,bucketTag=wrongbucket value=12.0 1422568543702900257\\n\"\n\n\tlistener := newTestListener()\n\tlistener.BucketTag = \"bucketTag\"\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post single message to listener\n\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"bucketTag\": \"mybucket\"},\n\t)\n\n\t// post single message to listener with a database tag in it already. It should be clobbered.\n\tresp, err = http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsgWithDB))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\tmap[string]string{\"host\": \"server01\", \"bucketTag\": \"mybucket\"},\n\t)\n\n\t// post multiple message to listener\n\tresp, err = http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsgs))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(2)\n\thostTags := []string{\"server02\", \"server03\",\n\t\t\"server04\", \"server05\", \"server06\"}\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag, \"bucketTag\": \"mybucket\"},\n\t\t)\n\t}\n}\n\n// http listener should add a newline at the end of the buffer if it's not there\nfunc TestWriteNoNewline(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsgNoNewline))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\t\tmap[string]string{\"host\": \"server01\"},\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestAllOrNothing(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testPartial))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteMaxLineSizeIncrease(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// Post a gigantic metric to the listener and verify that it writes OK this time:\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBuffer(hugeMetric))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteVerySmallMaxBody(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.MaxBodySize = config.Size(4096)\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBuffer(hugeMetric))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 413, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteLargeLine(t *testing.T) {\n\t// The term 'master_repl' used here is archaic language from redis\n\thugeMetric, err := os.ReadFile(\"./testdata/huge_metric\")\n\trequire.NoError(t, err)\n\thugeMetricString := string(hugeMetric)\n\n\tlistener := newTestListener()\n\tlistener.timeFunc = func() time.Time {\n\t\treturn time.Unix(123456789, 0)\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(hugeMetricString+testMsgs))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\t// TODO: with the new parser, long lines aren't a problem.  Do we need to skip them?\n\t// require.EqualValues(t, 400, resp.StatusCode)\n\n\texpected := testutil.MustMetric(\n\t\t\"super_long_metric\",\n\t\tmap[string]string{\"foo\": \"bar\"},\n\t\tmap[string]interface{}{\n\t\t\t\"clients\":                     42,\n\t\t\t\"connected_followers\":         43,\n\t\t\t\"evicted_keys\":                44,\n\t\t\t\"expired_keys\":                45,\n\t\t\t\"instantaneous_ops_per_sec\":   46,\n\t\t\t\"keyspace_hitrate\":            47.0,\n\t\t\t\"keyspace_hits\":               48,\n\t\t\t\"keyspace_misses\":             49,\n\t\t\t\"latest_fork_usec\":            50,\n\t\t\t\"master_repl_offset\":          51,\n\t\t\t\"mem_fragmentation_ratio\":     52.58,\n\t\t\t\"pubsub_channels\":             53,\n\t\t\t\"pubsub_patterns\":             54,\n\t\t\t\"rdb_changes_since_last_save\": 55,\n\t\t\t\"repl_backlog_active\":         56,\n\t\t\t\"repl_backlog_histlen\":        57,\n\t\t\t\"repl_backlog_size\":           58,\n\t\t\t\"sync_full\":                   59,\n\t\t\t\"sync_partial_err\":            60,\n\t\t\t\"sync_partial_ok\":             61,\n\t\t\t\"total_commands_processed\":    62,\n\t\t\t\"total_connections_received\":  63,\n\t\t\t\"uptime\":                      64,\n\t\t\t\"used_cpu_sys\":                65.07,\n\t\t\t\"used_cpu_sys_children\":       66.0,\n\t\t\t\"used_cpu_user\":               67.1,\n\t\t\t\"used_cpu_user_children\":      68.0,\n\t\t\t\"used_memory\":                 692048,\n\t\t\t\"used_memory_lua\":             70792,\n\t\t\t\"used_memory_peak\":            711128,\n\t\t\t\"used_memory_rss\":             7298144,\n\t\t},\n\t\ttime.Unix(123456789, 0),\n\t)\n\n\tm, ok := acc.Get(\"super_long_metric\")\n\trequire.True(t, ok)\n\ttestutil.RequireMetricEqual(t, expected, testutil.FromTestMetric(m))\n\n\thostTags := []string{\"server02\", \"server03\",\n\t\t\"server04\", \"server05\", \"server06\"}\n\tacc.Wait(len(hostTags))\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag},\n\t\t)\n\t}\n}\n\n// test that writing gzipped data works\nfunc TestWriteGzippedData(t *testing.T) {\n\tlistener := newTestListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tdata, err := os.ReadFile(\"./testdata/testmsgs.gz\")\n\trequire.NoError(t, err)\n\n\treq, err := http.NewRequest(\"POST\", createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), bytes.NewBuffer(data))\n\trequire.NoError(t, err)\n\treq.Header.Set(\"Content-Encoding\", \"gzip\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\thostTags := []string{\"server02\", \"server03\",\n\t\t\"server04\", \"server05\", \"server06\"}\n\tacc.Wait(len(hostTags))\n\tfor _, hostTag := range hostTags {\n\t\tacc.AssertContainsTaggedFields(t, \"cpu_load_short\",\n\t\t\tmap[string]interface{}{\"value\": float64(12)},\n\t\t\tmap[string]string{\"host\": hostTag},\n\t\t)\n\t}\n}\n\n// writes 25,000 metrics to the listener with 10 different writers\nfunc TestWriteHighTraffic(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping due to hang on darwin\")\n\t}\n\tlistener := newTestListener()\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// post many messages to listener\n\tvar wg sync.WaitGroup\n\tfor i := 0; i < 10; i++ {\n\t\twg.Add(1)\n\t\tgo func(innerwg *sync.WaitGroup) {\n\t\t\tdefer innerwg.Done()\n\t\t\tfor i := 0; i < 500; i++ {\n\t\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(testMsgs))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif err := resp.Body.Close(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif resp.StatusCode != 204 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(&wg)\n\t}\n\n\twg.Wait()\n\trequire.NoError(t, listener.Gather(acc))\n\n\tacc.Wait(25000)\n\trequire.Equal(t, int64(25000), int64(acc.NMetrics()))\n}\n\nfunc TestReceive404ForInvalidEndpoint(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/foobar\", \"\"), \"\", bytes.NewBufferString(testMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 404, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteInvalid(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(badMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 400, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestWriteEmpty(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\t// post single message to listener\n\t\t\tresp, err := http.Post(createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket\"), \"\", bytes.NewBufferString(emptyMsg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\t\t})\n\t}\n}\n\nfunc TestHealth(t *testing.T) {\n\tlistener := newTestListener()\n\tlistener.timeFunc = func() time.Time {\n\t\treturn time.Unix(42, 123456789)\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// Make sure we do have a unique stats for this instance to avoid side effects\n\tid, err := uuid.NewV4()\n\trequire.NoError(t, err)\n\tlistener.healthsServed = selfstat.Register(\"influxdb_v2_listener\", \"healths_served\", map[string]string{\n\t\t\"address\": listener.ServiceAddress,\n\t\t\"id\":      id.String(),\n\t})\n\tdefer listener.healthsServed.Unregister()\n\n\t// post ping to listener\n\tresp, err := http.Get(createURL(listener, \"http\", \"/api/v2/health\", \"\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"application/json\", resp.Header[\"Content-Type\"][0])\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(bodyBytes), \"\\\"status\\\":\\\"pass\\\"\")\n\trequire.Contains(t, string(bodyBytes), \"\\\"message\\\":\\\"ready for queries and writes\\\"\")\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n\trequire.EqualValues(t, 1, listener.healthsServed.Get())\n\n\t// check when max undelivered is set, but not reached\n\tlistener.MaxUndeliveredMetrics = 1\n\tresp, err = http.Get(createURL(listener, \"http\", \"/api/v2/health\", \"\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n\trequire.EqualValues(t, 2, listener.healthsServed.Get())\n\n\t// and on the documented base endpoint\n\tresp, err = http.Get(createURL(listener, \"http\", \"/health\", \"\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n\trequire.EqualValues(t, 3, listener.healthsServed.Get())\n\n\t// post ping to listener with too many pending metrics\n\tlistener.totalUndeliveredMetrics.Add(1)\n\tresp, err = http.Get(createURL(listener, \"http\", \"/api/v2/health\", \"\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"application/json\", resp.Header[\"Content-Type\"][0])\n\tbodyBytes, err = io.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(bodyBytes), \"\\\"status\\\":\\\"fail\\\"\")\n\trequire.Contains(t, string(bodyBytes), \"\\\"message\\\":\\\"pending undelivered metrics (1) is above limit\\\"\")\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 503, resp.StatusCode)\n\trequire.EqualValues(t, 4, listener.healthsServed.Get())\n}\n\nfunc TestPing(t *testing.T) {\n\tlistener := newTestListener()\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// Make sure we do have a unique stats for this instance to avoid side effects\n\tid, err := uuid.NewV4()\n\trequire.NoError(t, err)\n\tlistener.pingsServed = selfstat.Register(\"influxdb_v2_listener\", \"pings_served\", map[string]string{\n\t\t\"address\": listener.ServiceAddress,\n\t\t\"id\":      id.String(),\n\t})\n\tdefer listener.pingsServed.Unregister()\n\n\tresp, err := http.Get(createURL(listener, \"http\", \"/ping\", \"\"))\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\trequire.EqualValues(t, internal.FormatFullVersion(), resp.Header.Get(\"X-Influxdb-Version\"))\n\trequire.EqualValues(t, \"telegraf\", resp.Header.Get(\"X-Influxdb-Build\"))\n\trequire.EqualValues(t, 1, listener.pingsServed.Get())\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.Empty(t, bodyBytes)\n}\n\nfunc TestReady(t *testing.T) {\n\tlistener := newTestListener()\n\tlistener.timeFunc = func() time.Time {\n\t\treturn time.Unix(42, 123456789)\n\t}\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\t// Make sure we do have a unique stats for this instance to avoid side effects\n\tid, err := uuid.NewV4()\n\trequire.NoError(t, err)\n\tlistener.readysServed = selfstat.Register(\"influxdb_v2_listener\", \"readys_served\", map[string]string{\n\t\t\"address\": listener.ServiceAddress,\n\t\t\"id\":      id.String(),\n\t})\n\tdefer listener.readysServed.Unregister()\n\n\t// post ping to listener\n\tresp, err := http.Get(createURL(listener, \"http\", \"/api/v2/ready\", \"\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"application/json\", resp.Header[\"Content-Type\"][0])\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(bodyBytes), \"\\\"status\\\":\\\"ready\\\"\")\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n\trequire.EqualValues(t, 1, listener.readysServed.Get())\n\n\t// and on the documented base endpoint\n\tresp, err = http.Get(createURL(listener, \"http\", \"/ready\", \"\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 200, resp.StatusCode)\n\trequire.EqualValues(t, 2, listener.readysServed.Get())\n}\n\nfunc TestWriteWithPrecision(t *testing.T) {\n\tfor _, tc := range parserTestCases {\n\t\tt.Run(\"parser \"+tc.parser, func(t *testing.T) {\n\t\t\tlistener := newTestListener()\n\t\t\tlistener.ParserType = tc.parser\n\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\trequire.NoError(t, listener.Init())\n\t\t\tdefer listener.Statistics.UnregisterAll()\n\t\t\trequire.NoError(t, listener.Start(acc))\n\t\t\tdefer listener.Stop()\n\n\t\t\tmsg := \"xyzzy value=42 1422568543\\n\"\n\t\t\tresp, err := http.Post(\n\t\t\t\tcreateURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket&precision=s\"), \"\", bytes.NewBufferString(msg))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, resp.Body.Close())\n\t\t\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\t\t\tacc.Wait(1)\n\t\t\t// When timestamp is provided, the precision parameter is\n\t\t\t// overloaded to specify the timestamp's unit\n\t\t\trequire.Equal(t, time.Unix(0, 1422568543000000000), acc.Metrics[0].Time)\n\t\t})\n\t}\n}\n\nfunc TestWriteWithPrecisionNoTimestamp(t *testing.T) {\n\tlistener := newTestListener()\n\tlistener.timeFunc = func() time.Time {\n\t\treturn time.Unix(42, 123456789)\n\t}\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tmsg := \"xyzzy value=42\\n\"\n\tresp, err := http.Post(\n\t\tcreateURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket&precision=s\"), \"\", bytes.NewBufferString(msg))\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tacc.Wait(1)\n\trequire.Len(t, acc.Metrics, 1)\n\t// When timestamp is omitted, the precision parameter actually\n\t// specifies the precision.  The timestamp is set to the greatest\n\t// integer unit less than the provided timestamp (floor).\n\trequire.Equal(t, time.Unix(42, 0), acc.Metrics[0].Time)\n}\n\nfunc TestRateLimitedConnectionDropsSecondRequest(t *testing.T) {\n\tlistener := newRateLimitedTestListener(1)\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tmsg := \"xyzzy value=42\\n\"\n\tpostURL := createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket&precision=s\")\n\tresp, err := http.Post(postURL, \"\", bytes.NewBufferString(msg)) // #nosec G107 -- url has to be dynamic due to dynamic port number\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tresp, err = http.Post(postURL, \"\", bytes.NewBufferString(msg)) // #nosec G107 -- url has to be dynamic due to dynamic port number\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 429, resp.StatusCode)\n}\n\nfunc TestRateLimitedConnectionAcceptsNewRequestOnDelivery(t *testing.T) {\n\tlistener := newRateLimitedTestListener(1)\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tmsg := \"xyzzy value=42\\n\"\n\tpostURL := createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket&precision=s\")\n\tresp, err := http.Post(postURL, \"\", bytes.NewBufferString(msg)) // #nosec G107 -- url has to be dynamic due to dynamic port number\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n\n\tms := acc.GetTelegrafMetrics()\n\tfor _, m := range ms {\n\t\tm.Accept()\n\t}\n\trequire.Eventually(t, func() bool {\n\t\treturn listener.totalUndeliveredMetrics.Load() == 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tresp, err = http.Post(postURL, \"\", bytes.NewBufferString(msg)) // #nosec G107 -- url has to be dynamic due to dynamic port number\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 204, resp.StatusCode)\n}\n\nfunc TestRateLimitedConnectionRejectsBatchesLargerThanMaxUndeliveredMetrics(t *testing.T) {\n\tlistener := newRateLimitedTestListener(1)\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, listener.Init())\n\tdefer listener.Statistics.UnregisterAll()\n\trequire.NoError(t, listener.Start(acc))\n\tdefer listener.Stop()\n\n\tmsg := \"xyzzy value=42\\nxyzzy value=43\"\n\tpostURL := createURL(listener, \"http\", \"/api/v2/write\", \"bucket=mybucket&precision=s\")\n\tresp, err := http.Post(postURL, \"\", bytes.NewBufferString(msg)) // #nosec G107 -- url has to be dynamic due to dynamic port number\n\trequire.NoError(t, err)\n\trequire.NoError(t, resp.Body.Close())\n\trequire.EqualValues(t, 413, resp.StatusCode)\n}\n\n// The term 'master_repl' used here is archaic language from redis\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/sample.conf",
    "content": "# Accept metrics over InfluxDB 2.x HTTP API\n[[inputs.influxdb_v2_listener]]\n  ## Address and port to host InfluxDB listener on\n  ## (Double check the port. Could be 9999 if using OSS Beta)\n  service_address = \":8086\"\n\n  ## Maximum undelivered metrics before rate limit kicks in.\n  ## When the rate limit kicks in, HTTP status 429 will be returned.\n  ## 0 disables rate limiting\n  # max_undelivered_metrics = 0\n\n  ## Maximum duration before timing out read of the request\n  # read_timeout = \"10s\"\n  ## Maximum duration before timing out write of the response\n  # write_timeout = \"10s\"\n\n  ## Maximum allowed HTTP request body size in bytes.\n  ## 0 means to use the default of 32MiB.\n  # max_body_size = \"32MiB\"\n\n  ## Optional tag to determine the bucket.\n  ## If the write has a bucket in the query string then it will be kept in this tag name.\n  ## This tag can be used in downstream outputs.\n  ## The default value of nothing means it will be off and the database will not be recorded.\n  # bucket_tag = \"\"\n\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Add service certificate and key\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Optional token to accept for HTTP authentication.\n  ## You probably want to make sure you have TLS configured above for this.\n  # token = \"some-long-shared-secret-token\"\n\n  ## Influx line protocol parser\n  ## 'internal' is the default. 'upstream' is a newer parser that is faster\n  ## and more memory efficient.\n  # parser_type = \"internal\"\n\n  ## Use new internal metrics. When true, it adds tag for alias if set.\n  # use_internal_statistics = false\n"
  },
  {
    "path": "plugins/inputs/influxdb_v2_listener/testdata/huge_metric",
    "content": "super_long_metric,foo=bar clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=1i,connected_followers=0i,evicted_keys=0i,expired_keys=0i,instantaneous_ops_per_sec=0i,keyspace_hitrate=0,keyspace_hits=0i,keyspace_misses=2i,latest_fork_usec=0i,master_repl_offset=0i,mem_fragmentation_ratio=3.58,pubsub_channels=0i,pubsub_patterns=0i,rdb_changes_since_last_save=0i,repl_backlog_active=0i,repl_backlog_histlen=0i,repl_backlog_size=1048576i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=4i,total_connections_received=2i,uptime=869i,used_cpu_sys=0.07,used_cpu_sys_children=0,used_cpu_user=0.1,used_cpu_user_children=0,used_memory=502048i,used_memory_lua=33792i,used_memory_peak=501128i,used_memory_rss=1798144i,clients=42i,connected_followers=43i,evicted_keys=44i,expired_keys=45i,instantaneous_ops_per_sec=46i,keyspace_hitrate=47,keyspace_hits=48i,keyspace_misses=49i,latest_fork_usec=50i,master_repl_offset=51i,mem_fragmentation_ratio=52.58,pubsub_channels=53i,pubsub_patterns=54i,rdb_changes_since_last_save=55i,repl_backlog_active=56i,repl_backlog_histlen=57i,repl_backlog_size=58i,sync_full=59i,sync_partial_err=60i,sync_partial_ok=61i,total_commands_processed=62i,total_connections_received=63i,uptime=64i,used_cpu_sys=65.07,used_cpu_sys_children=66,used_cpu_user=67.1,used_cpu_user_children=68,used_memory=692048i,used_memory_lua=70792i,used_memory_peak=711128i,used_memory_rss=7298144i\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/README.md",
    "content": "# Intel Baseband Accelerator Input Plugin\n\nThis plugin collects metrics from both dedicated and integrated Intel devices\nproviding Wireless Baseband hardware acceleration. These devices play a key role\nin accelerating 5G and 4G Virtualized Radio Access Networks (vRAN) workloads,\nincreasing the overall compute capacity of commercial, off-the-shelf platforms\nby integrating e.g.\n\n- Forward Error Correction (FEC) processing,\n- 4G Turbo FEC processing,\n- 5G Low Density Parity Check (LDPC)\n- Fast Fourier Transform (FFT) block providing DFT/iDFT processing offload for\n  the 5G Sounding Reference Signal (SRS)\n\n⭐ Telegraf v1.27.0\n🏷️ hardware, network, system\n💻 linux\n\n## Requirements\n\n- supported Intel Baseband device installed and configured\n- Linux kernel 5.7+\n- [pf-bb-config](https://github.com/intel/pf-bb-config) (version >= v23.03)\n  installed and running\n\nThis plugin supports the following hardware:\n\n- Intel® vRAN Boost integrated accelerators:\n  - 4th Gen Intel® Xeon® Scalable processor with Intel® vRAN Boost\n    (also known as Sapphire Rapids Edge Enhanced / SPR-EE)\n- External expansion cards connected to the PCI bus:\n  - Intel® vRAN Dedicated Accelerator ACC100 SoC (code named Mount Bryce)\n\nFor more information regarding system configuration, please follow DPDK\ninstallation guides:\n\n- [Intel® vRAN Boost Poll Mode Driver (PMD)][VRB1]\n- [Intel® ACC100 5G/4G FEC Poll Mode Drivers][ACC100]\n\n[VRB1]: https://doc.dpdk.org/guides/bbdevs/vrb1.html#installation\n[ACC100]: https://doc.dpdk.org/guides/bbdevs/acc100.html#installation\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Intel Baseband Accelerator Input Plugin collects metrics from both dedicated and integrated\n# Intel devices that provide Wireless Baseband hardware acceleration.\n# This plugin ONLY supports Linux.\n[[inputs.intel_baseband]]\n  ## Path to socket exposed by pf-bb-config for CLI interaction (mandatory).\n  ## In version v23.03 of pf-bb-config the path is created according to the schema:\n  ##   \"/tmp/pf_bb_config.0000\\:<b>\\:<d>.<f>.sock\" where 0000\\:<b>\\:<d>.<f> is the PCI device ID.\n  socket_path = \"\"\n\n  ## Path to log file exposed by pf-bb-config with telemetry to read (mandatory).\n  ## In version v23.03 of pf-bb-config the path is created according to the schema:\n  ##   \"/var/log/pf_bb_cfg_0000\\:<b>\\:<d>.<f>.log\" where 0000\\:<b>\\:<d>.<f> is the PCI device ID.\n  log_file_path = \"\"\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error on startup if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n\n  ## Duration that defines how long the connected socket client will wait for\n  ## a response before terminating connection.\n  ## Since it's local socket access to a fast packet processing application, the timeout should\n  ## be sufficient for most users.\n  ## Setting the value to 0 disables the timeout (not recommended).\n  # socket_access_timeout = \"1s\"\n\n  ## Duration that defines maximum time plugin will wait for pf-bb-config to write telemetry to the log file.\n  ## Timeout may differ depending on the environment.\n  ## Must be equal or larger than 50ms.\n  # wait_for_telemetry_timeout = \"1s\"\n```\n\n## Metrics\n\nDepending on version of Intel Baseband device and version of pf-bb-config,\nsubset of following measurements may be exposed:\n\n**The following tags and fields are supported by Intel Baseband plugin:**\n\n| Tag         | Description                                                 |\n|-------------|-------------------------------------------------------------|\n| `metric`    | Type of metric : \"code_blocks\", \"data_bytes\", \"per_engine\". |\n| `operation` | Type of operation: \"5GUL\", \"5GDL\", \"4GUL\", \"4GDL\", \"FFT\".   |\n| `vf`        | Virtual Function number.                                    |\n| `engine`    | Engine number.                                              |\n\n| Metric name (field)  | Description                                                       |\n|----------------------|-------------------------------------------------------------------|\n| `value`              | Metric value for a given operation (non-negative integer, gauge). |\n\n## Example Output\n\n```text\nintel_baseband,host=ubuntu,metric=code_blocks,operation=5GUL,vf=0 value=54i 1685695885000000000\nintel_baseband,host=ubuntu,metric=code_blocks,operation=5GDL,vf=0 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=code_blocks,operation=FFT,vf=0 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=code_blocks,operation=5GUL,vf=1 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=code_blocks,operation=5GDL,vf=1 value=32i 1685695885000000000\nintel_baseband,host=ubuntu,metric=code_blocks,operation=FFT,vf=1 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=5GUL,vf=0 value=18560i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=5GDL,vf=0 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=FFT,vf=0 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=5GUL,vf=1 value=0i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=5GDL,vf=1 value=86368i 1685695885000000000\nintel_baseband,host=ubuntu,metric=data_bytes,operation=FFT,vf=1 value=0i 1685695885000000000\nintel_baseband,engine=0,host=ubuntu,metric=per_engine,operation=5GUL value=72i 1685695885000000000\nintel_baseband,engine=1,host=ubuntu,metric=per_engine,operation=5GUL value=72i 1685695885000000000\nintel_baseband,engine=2,host=ubuntu,metric=per_engine,operation=5GUL value=72i 1685695885000000000\nintel_baseband,engine=3,host=ubuntu,metric=per_engine,operation=5GUL value=72i 1685695885000000000\nintel_baseband,engine=4,host=ubuntu,metric=per_engine,operation=5GUL value=72i 1685695885000000000\nintel_baseband,engine=0,host=ubuntu,metric=per_engine,operation=5GDL value=132i 1685695885000000000\nintel_baseband,engine=1,host=ubuntu,metric=per_engine,operation=5GDL value=130i 1685695885000000000\nintel_baseband,engine=0,host=ubuntu,metric=per_engine,operation=FFT value=0i 1685695885000000000\n```\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/intel_baseband.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// plugin name. Exposed with all metrics\n\tpluginName = \"intel_baseband\"\n\n\t// VF Metrics\n\tvfCodeBlocks = \"Code Blocks\"\n\tvfDataBlock  = \"Data (Bytes)\"\n\n\t// Engine Metrics\n\tengineBlock = \"Per Engine\"\n\n\t// Socket extensions\n\tsocketExtension  = \".sock\"\n\tlogFileExtension = \".log\"\n\n\t// UnreachableSocketBehavior Values\n\tunreachableSocketBehaviorError  = \"error\"\n\tunreachableSocketBehaviorIgnore = \"ignore\"\n\n\tdefaultAccessSocketTimeout     = config.Duration(time.Second)\n\tdefaultWaitForTelemetryTimeout = config.Duration(time.Second)\n)\n\ntype Baseband struct {\n\t// required params\n\tSocketPath  string `toml:\"socket_path\"`\n\tFileLogPath string `toml:\"log_file_path\"`\n\n\t// optional params\n\tUnreachableSocketBehavior string          `toml:\"unreachable_socket_behavior\"`\n\tSocketAccessTimeout       config.Duration `toml:\"socket_access_timeout\"`\n\tWaitForTelemetryTimeout   config.Duration `toml:\"wait_for_telemetry_timeout\"`\n\n\tLog      telegraf.Logger `toml:\"-\"`\n\tlogConn  *logConnector\n\tsockConn *socketConnector\n}\n\nfunc (*Baseband) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (b *Baseband) Init() error {\n\tif b.SocketAccessTimeout < 0 {\n\t\treturn errors.New(\"socket_access_timeout should be positive number or equal to 0 (to disable timeouts)\")\n\t}\n\n\twaitForTelemetryDuration := time.Duration(b.WaitForTelemetryTimeout)\n\tif waitForTelemetryDuration < 50*time.Millisecond {\n\t\treturn errors.New(\"wait_for_telemetry_timeout should be equal or larger than 50ms\")\n\t}\n\n\t// Filling default values\n\t// Check UnreachableSocketBehavior\n\tswitch b.UnreachableSocketBehavior {\n\tcase \"\":\n\t\tb.UnreachableSocketBehavior = unreachableSocketBehaviorError\n\tcase unreachableSocketBehaviorError, unreachableSocketBehaviorIgnore:\n\t\t// Valid options, do nothing\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown choice for unreachable_socket_behavior: %q\", b.UnreachableSocketBehavior)\n\t}\n\n\tvar err error\n\t// Validate Socket path\n\tif b.SocketPath, err = b.checkFilePath(b.SocketPath, socket); err != nil {\n\t\treturn fmt.Errorf(\"socket_path: %w\", err)\n\t}\n\n\t// Validate log file path\n\tif b.FileLogPath, err = b.checkFilePath(b.FileLogPath, log); err != nil {\n\t\treturn fmt.Errorf(\"log_file_path: %w\", err)\n\t}\n\n\t// Create Log Connector\n\tb.logConn = newLogConnector(b.FileLogPath, waitForTelemetryDuration)\n\n\t// Create Socket Connector\n\tb.sockConn = newSocketConnector(b.SocketPath, time.Duration(b.SocketAccessTimeout))\n\treturn nil\n}\n\nfunc (b *Baseband) Gather(acc telegraf.Accumulator) error {\n\terr := b.sockConn.dumpTelemetryToLog()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Read the log\n\terr = b.logConn.readLogFile()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = b.logConn.readNumVFs()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"couldn't get the number of VFs: %w\", err)\n\t}\n\t// b.numVFs less than 0 means that we are reading the file for the first time (or occurred discontinuity in file availability)\n\tif b.logConn.getNumVFs() <= 0 {\n\t\treturn errors.New(\"error in accessing information about the amount of VF\")\n\t}\n\n\t// rawData eg: 12 0\n\tif err = b.gatherVFMetric(acc, vfCodeBlocks); err != nil {\n\t\treturn fmt.Errorf(\"couldn't get %q metric: %w\", vfCodeBlocks, err)\n\t}\n\n\t// rawData eg: 12 0\n\tif err = b.gatherVFMetric(acc, vfDataBlock); err != nil {\n\t\treturn fmt.Errorf(\"couldn't get %q metric: %w\", vfDataBlock, err)\n\t}\n\n\t// rawData eg: 12 0 0 0 0 0\n\tif err = b.gatherEngineMetric(acc, engineBlock); err != nil {\n\t\treturn fmt.Errorf(\"couldn't get %q metric: %w\", engineBlock, err)\n\t}\n\treturn nil\n}\n\nfunc (b *Baseband) gatherVFMetric(acc telegraf.Accumulator, metricName string) error {\n\tmetrics, err := b.logConn.getMetrics(metricName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error accessing information about the metric %q: %w\", metricName, err)\n\t}\n\n\tfor _, metric := range metrics {\n\t\tif len(metric.data) != b.logConn.getNumVFs() {\n\t\t\treturn fmt.Errorf(\"data is inconsistent, number of metrics in the file for %d VFs, the number of VFs read is %d\",\n\t\t\t\tlen(metric.data), b.logConn.numVFs)\n\t\t}\n\n\t\tfor i := range metric.data {\n\t\t\tvalue, err := logMetricDataToValue(metric.data[i])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"value\": value,\n\t\t\t}\n\t\t\ttags := map[string]string{\n\t\t\t\t\"operation\": metric.operationName,\n\t\t\t\t\"metric\":    metricNameToTagName(metricName),\n\t\t\t\t\"vf\":        strconv.Itoa(i),\n\t\t\t}\n\t\t\tacc.AddGauge(pluginName, fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *Baseband) gatherEngineMetric(acc telegraf.Accumulator, metricName string) error {\n\tmetrics, err := b.logConn.getMetrics(metricName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error in accessing information about the metric %q: %w\", metricName, err)\n\t}\n\n\tfor _, metric := range metrics {\n\t\tfor i := range metric.data {\n\t\t\tvalue, err := logMetricDataToValue(metric.data[i])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"value\": value,\n\t\t\t}\n\t\t\ttags := map[string]string{\n\t\t\t\t\"operation\": metric.operationName,\n\t\t\t\t\"metric\":    metricNameToTagName(metricName),\n\t\t\t\t\"engine\":    strconv.Itoa(i),\n\t\t\t}\n\t\t\tacc.AddGauge(pluginName, fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Validate the provided path and return the clean version of it\n// if UnreachableSocketBehavior = error -> return error, otherwise ignore the error\nfunc (b *Baseband) checkFilePath(path string, fileType fileType) (resultPath string, err error) {\n\tif resultPath, err = validatePath(path, fileType); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = checkFile(path, fileType); err != nil {\n\t\tif b.UnreachableSocketBehavior == unreachableSocketBehaviorError {\n\t\t\treturn \"\", err\n\t\t}\n\t\tb.Log.Warn(err)\n\t}\n\treturn resultPath, nil\n}\n\nfunc newBaseband() *Baseband {\n\treturn &Baseband{\n\t\tSocketAccessTimeout:     defaultAccessSocketTimeout,\n\t\tWaitForTelemetryTimeout: defaultWaitForTelemetryTimeout,\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"intel_baseband\", func() telegraf.Input {\n\t\treturn newBaseband()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/intel_baseband_notamd64linux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux || !amd64\n\npackage intel_baseband\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Baseband struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Baseband) SampleConfig() string { return sampleConfig }\n\nfunc (b *Baseband) Init() error {\n\tb.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\nfunc (*Baseband) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"intel_baseband\", func() telegraf.Input {\n\t\treturn &Baseband{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/intel_baseband_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInit(t *testing.T) {\n\tt.Run(\"with not specified path values Init should return an error\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\terr := baseband.Init()\n\n\t\t// check default variables\n\t\t// check empty values\n\t\trequire.Empty(t, baseband.SocketPath)\n\t\trequire.Empty(t, baseband.FileLogPath)\n\n\t\t// UnreachableSocketBehavior variable should be = unreachableSocketBehaviorError\n\t\trequire.Equal(t, unreachableSocketBehaviorError, baseband.UnreachableSocketBehavior)\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"path not specified\")\n\t})\n\n\tt.Run(\"with only SocketPath provided the plugin should return the error\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\ttempSocket := newTempSocket(t)\n\t\tdefer tempSocket.Close()\n\n\t\tbaseband.SocketPath = tempSocket.pathToSocket\n\t\terr := baseband.Init()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"log_file_path\")\n\t\trequire.ErrorContains(t, err, \"path not specified\")\n\t})\n\n\tt.Run(\"with SocketAccessTimeout less then 0 provided the plugin should return the error\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\tbaseband.SocketAccessTimeout = -1\n\t\terr := baseband.Init()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"socket_access_timeout should be positive number or equal to 0\")\n\t})\n\n\tt.Run(\"with SocketPath and LogPath provided the plugin shouldn't return any errors\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\ttempSocket := newTempSocket(t)\n\t\tdefer tempSocket.Close()\n\n\t\tlogTempFile := newTempLogFile(t)\n\t\tdefer logTempFile.close()\n\n\t\tbaseband.SocketPath = tempSocket.pathToSocket\n\t\tbaseband.FileLogPath = logTempFile.pathToFile\n\t\terr := baseband.Init()\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"with unknown option for UnreachableSocketBehavior plugin should return the error\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\tbaseband.UnreachableSocketBehavior = \"UnknownRandomString\"\n\t\terr := baseband.Init()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"unreachable_socket_behavior\")\n\t})\n\n\tt.Run(\"with error option for UnreachableSocketBehavior plugin should return error\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\tbaseband.UnreachableSocketBehavior = unreachableSocketBehaviorError\n\t\tbaseband.SocketPath = \"/some/random/path/test.sock\"\n\t\tbaseband.FileLogPath = \"/some/random/path/test.log\"\n\n\t\terr := baseband.Init()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"socket_path\")\n\t\trequire.ErrorContains(t, err, \"provided path does not exist\")\n\t})\n\n\tt.Run(\"with ignore option for UnreachableSocketBehavior plugin shouldn't return any errors\", func(t *testing.T) {\n\t\tbaseband := prepareBasebandEnvironment()\n\t\trequire.NotNil(t, baseband)\n\n\t\tbaseband.UnreachableSocketBehavior = unreachableSocketBehaviorIgnore\n\t\tbaseband.SocketPath = \"/some/random/path/test.sock\"\n\t\tbaseband.FileLogPath = \"/some/random/path/test.log\"\n\n\t\terr := baseband.Init()\n\t\trequire.NoError(t, err)\n\t})\n}\n\n// Test Socket\ntype tempSocket struct {\n\tpathToSocket string\n\tsocket       net.Listener\n\n\tdirPath string\n}\n\nfunc (ts *tempSocket) Close() {\n\tvar err error\n\tif err = ts.socket.Close(); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err = os.RemoveAll(ts.dirPath); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc newTempSocket(t *testing.T) *tempSocket {\n\t// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases\n\t// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.\n\t//nolint:usetesting // Ignore \"os.MkdirTemp() could be replaced by t.TempDir() in newTempSocket\" finding.\n\tdirPath, err := os.MkdirTemp(\"\", \"test-socket\")\n\trequire.NoError(t, err)\n\n\tpathToSocket := filepath.Join(dirPath, \"test\"+socketExtension)\n\tsocket, err := net.Listen(\"unix\", pathToSocket)\n\trequire.NoError(t, err)\n\n\treturn &tempSocket{\n\t\tdirPath:      dirPath,\n\t\tpathToSocket: pathToSocket,\n\t\tsocket:       socket,\n\t}\n}\n\ntype tempLogFile struct {\n\tpathToFile string\n\tfile       *os.File\n}\n\nfunc (tlf *tempLogFile) close() {\n\tvar err error\n\tif err = tlf.file.Close(); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err = os.Remove(tlf.pathToFile); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc newTempLogFile(t *testing.T) *tempLogFile {\n\tfile, err := os.CreateTemp(t.TempDir(), \"*.log\")\n\trequire.NoError(t, err)\n\n\treturn &tempLogFile{\n\t\tpathToFile: file.Name(),\n\t\tfile:       file,\n\t}\n}\n\nfunc prepareBasebandEnvironment() *Baseband {\n\tb := newBaseband()\n\tb.Log = testutil.Logger{Name: \"BasebandPluginTest\"}\n\treturn b\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/log_connector.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tinfoLine     = \"INFO:\"\n\tcountersLine = \"counters:\"\n\n\tdeviceStatusStartPrefix = \"Device Status::\"\n\tdeviceStatusEndPrefix   = \"VFs\"\n\n\tclearLogCmdText = \"clear_log\"\n)\n\nvar errFindingSubstring = errors.New(\"couldn't find the substring in the log file\")\n\ntype logConnector struct {\n\t// path to log\n\tpath string\n\n\t// Num of VFs\n\tnumVFs int\n\n\t// Log file data\n\tlines []string\n\n\twaitForTelemetryTimeout time.Duration\n\tlastModTime             time.Time\n}\n\ntype logMetric struct {\n\toperationName string\n\tdata          []string\n}\n\n// Try to read file and fill the .lines field.\nfunc (lc *logConnector) readLogFile() error {\n\terr := lc.checkLogFreshness()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfile, err := os.ReadFile(lc.path)\n\tif err != nil {\n\t\tlc.numVFs = -1\n\t\treturn fmt.Errorf(\"couldn't read log file: %w\", err)\n\t}\n\n\t// Example content of the metric file is located in testdata/example.log\n\t// the minimum acceptable file content consists of three lines:\n\t// - one line for number of VFs\n\t// - two lines for operation (counters name and metrics value)\n\tlines := strings.Split(string(file), \"\\n\")\n\tif len(lines) < 3 {\n\t\treturn errors.New(\"log file is incomplete\")\n\t}\n\n\tlc.lines = lines\n\treturn nil\n}\n\n// function checks whether the data in the log file were updated by checking the last modification date and size\nfunc (lc *logConnector) checkLogFreshness() error {\n\tstart := time.Now()\n\n\t// initial wait for telemetry being written to file\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// check if it was written completely\n\tfor {\n\t\tfileInfo, err := os.Stat(lc.path)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"couldn't stat log file: %w\", err)\n\t\t}\n\t\tcurrModTime := fileInfo.ModTime()\n\n\t\t// pf-bb-config first performs log clearing (which will write clear_log line to this log just before it will be cleared),\n\t\t// and then dumps the newest telemetry to this file.\n\t\t// This checks if:\n\t\t//  - modification time has been changed\n\t\t//  - file is not empty\n\t\t//  - file doesn't contain clear_log command (it may appear for few milliseconds, just before file is cleared)\n\t\tif !lc.lastModTime.Equal(currModTime) && fileInfo.Size() != 0 && !lc.isClearLogContainedInFile() {\n\t\t\t// refreshing succeed\n\t\t\tlc.lastModTime = currModTime\n\t\t\treturn nil\n\t\t}\n\t\tif time.Since(start) >= lc.waitForTelemetryTimeout {\n\t\t\tif fileInfo.Size() == 0 {\n\t\t\t\treturn errors.New(\"log file is empty\")\n\t\t\t}\n\t\t\treturn errors.New(\"failed to refresh telemetry data\")\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n}\n\nfunc (lc *logConnector) isClearLogContainedInFile() bool {\n\tfile, err := os.ReadFile(lc.path)\n\tif err != nil {\n\t\t// for now, error means that \"clear_log\" line is not contained in log\n\t\treturn false\n\t}\n\n\treturn strings.Contains(string(file), clearLogCmdText)\n}\n\n// Try to read file and return lines from it\nfunc (lc *logConnector) getLogLines() []string {\n\treturn lc.lines\n}\n\n// Try to read file and return lines from it\nfunc (lc *logConnector) getLogLinesNum() int {\n\treturn len(lc.lines)\n}\n\n// Return the number of VFs in the log file\nfunc (lc *logConnector) getNumVFs() int {\n\treturn lc.numVFs\n}\n\n// find a line which contains Device Status. Example = Thu Apr 13 13:28:40 2023:INFO:Device Status:: 2 VFs\nfunc (lc *logConnector) readNumVFs() error {\n\tfor _, line := range lc.lines {\n\t\tif !strings.Contains(line, deviceStatusStartPrefix) {\n\t\t\tcontinue\n\t\t}\n\n\t\tnumVFs, err := parseNumVFs(line)\n\t\tif err != nil {\n\t\t\tlc.numVFs = -1\n\t\t\treturn err\n\t\t}\n\t\tlc.numVFs = numVFs\n\t\treturn nil\n\t}\n\n\treturn errors.New(\"numVFs data wasn't found in the log file\")\n}\n\n// Find a line which contains a substring in the log file\nfunc (lc *logConnector) getSubstringLine(offsetLine int, substring string) (int, string, error) {\n\tif len(substring) == 0 {\n\t\treturn 0, \"\", errors.New(\"substring is empty\")\n\t}\n\n\tfor i := offsetLine; i < len(lc.lines); i++ {\n\t\tif !strings.Contains(lc.lines[i], substring) {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn i, lc.lines[i], nil\n\t}\n\treturn 0, \"\", fmt.Errorf(\"%q: %w\", substring, errFindingSubstring)\n}\n\nfunc (lc *logConnector) getMetrics(name string) (metrics []*logMetric, err error) {\n\toffset := 0\n\tfor {\n\t\tcurrOffset, metric, err := lc.getMetric(offset, name)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, errFindingSubstring) || len(metrics) == 0 {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn metrics, nil\n\t\t}\n\t\tmetrics = append(metrics, metric)\n\t\toffset = currOffset\n\t}\n}\n\n// Example of log file:\n// Thu May 18 08:45:15 2023:INFO:5GUL counters: Code Blocks\n// Thu May 18 08:45:15 2023:INFO:0 0\n// Input: offsetLine, metric name (Code Blocks)\n// Func will return: current offset after reading the metric (2), metric with operation name and data(5GUL, [\"0\", \"0\"]) and error\nfunc (lc *logConnector) getMetric(offsetLine int, name string) (int, *logMetric, error) {\n\ti, line, err := lc.getSubstringLine(offsetLine, name)\n\tif err != nil {\n\t\treturn offsetLine, nil, err\n\t}\n\n\toperationName := parseOperationName(line)\n\tif len(operationName) == 0 {\n\t\treturn offsetLine, nil, errors.New(\"valid operation name wasn't found in log\")\n\t}\n\n\tif lc.getLogLinesNum() <= i+1 {\n\t\treturn offsetLine, nil,\n\t\t\tfmt.Errorf(\"the content of the log file is incorrect, line which contains key word %q can't be the last one in log\", countersLine)\n\t}\n\n\t// infoData eg: Thu Apr 13 13:28:40 2023:INFO:12 0\n\tinfoData := strings.Split(lc.lines[i+1], infoLine)\n\tif len(infoData) != 2 {\n\t\t// info data must be in format : some data + keyword \"INFO:\" + metrics\n\t\treturn offsetLine, nil, fmt.Errorf(\"the content of the log file is incorrect, couldn't find %q separator\", infoLine)\n\t}\n\n\tdataRaw := strings.TrimSpace(infoData[1])\n\tif len(dataRaw) == 0 {\n\t\treturn offsetLine, nil, errors.New(\"the content of the log file is incorrect, metric's data is incorrect\")\n\t}\n\n\tdata := strings.Split(dataRaw, \" \")\n\tfor i := range data {\n\t\tif len(data[i]) == 0 {\n\t\t\treturn offsetLine, nil, errors.New(\"the content of the log file is incorrect, metric's data is empty\")\n\t\t}\n\t}\n\treturn i + 2, &logMetric{operationName: operationName, data: data}, nil\n}\n\n// Example value = Thu Apr 13 13:28:40 2023:INFO:Device Status:: 2 VFs\nfunc parseNumVFs(s string) (int, error) {\n\ti := strings.LastIndex(s, deviceStatusStartPrefix)\n\tif i == -1 {\n\t\treturn 0, errors.New(\"couldn't find device status prefix in line\")\n\t}\n\n\tj := strings.Index(s[i:], deviceStatusEndPrefix)\n\tif j == -1 {\n\t\treturn 0, errors.New(\"couldn't find device end prefix in line\")\n\t}\n\n\tstartIndex := i + len(deviceStatusStartPrefix) + 1\n\tendIndex := i + j - 1\n\tif len(s) < startIndex || startIndex >= endIndex {\n\t\treturn 0, errors.New(\"incorrect format of the line\")\n\t}\n\n\treturn strconv.Atoi(s[startIndex:endIndex])\n}\n\n// Parse Operation name\n// Example = Thu Apr 13 13:28:40 2023:INFO:5GUL counters: Code Blocks\n// Output: 5GUL\nfunc parseOperationName(s string) string {\n\ti := strings.Index(s, infoLine)\n\tif i >= 0 {\n\t\tj := strings.Index(s[i:], countersLine)\n\t\tstartIndex := i + len(infoLine)\n\t\tendIndex := i + j - 1\n\t\tif j >= 0 && startIndex < endIndex {\n\t\t\treturn s[startIndex:endIndex]\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc newLogConnector(path string, waitForTelemetryTimeout time.Duration) *logConnector {\n\tlastModTime := time.Time{}\n\tfileInfo, err := os.Stat(path)\n\tif err == nil {\n\t\tlastModTime = fileInfo.ModTime()\n\t}\n\n\treturn &logConnector{\n\t\tpath:                    path,\n\t\twaitForTelemetryTimeout: waitForTelemetryTimeout,\n\t\tnumVFs:                  -1,\n\t\tlastModTime:             lastModTime,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/log_connector_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestReadLogFile(t *testing.T) {\n\ttestCases := []struct {\n\t\tname        string\n\t\ttestLogPath string\n\t\terr         error\n\t}{\n\t\t{\"when file doesn't exist return the error\", \"testdata/logfiles/doesntexist\", errors.New(\"no such file or directory\")},\n\t\t{\"when the file is empty return the error\", \"testdata/logfiles/empty.log\", errors.New(\"log file is empty\")},\n\t\t{\"when the log file is correct, error should be nil\", \"testdata/logfiles/example.log\", nil},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tlogConnector := prepareLogConnMock()\n\t\t\trequire.NotNil(t, logConnector)\n\t\t\tlogConnector.path = tc.testLogPath\n\n\t\t\terr := logConnector.readLogFile()\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tdata := logConnector.getLogLines()\n\t\t\trequire.NotEmpty(t, data)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestGetMetric(t *testing.T) {\n\ttestCases := []struct {\n\t\tname              string\n\t\tinput             []string\n\t\tmetricName        string\n\t\texpectedOperation string\n\t\texpectedData      []string\n\t\terr               error\n\t}{\n\t\t{\"with correct string no error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Code Blocks\", \"Thu May 18 08:45:15 2023:INFO:0 0\"},\n\t\t\tvfCodeBlocks, \"5GUL\", []string{\"0\", \"0\"}, nil},\n\n\t\t{\"with correct string no error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Data (Bytes)\", \"Thu May 18 08:45:15 2023:INFO:0 0\"},\n\t\t\tvfDataBlock, \"5GUL\", []string{\"0\", \"0\"}, nil},\n\n\t\t{\"with correct string no error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Per Engine\", \"Thu May 18 08:45:15 2023:INFO:0 0 3 0 50 0 200 0\"},\n\t\t\tengineBlock, \"5GUL\", []string{\"0\", \"0\", \"3\", \"0\", \"50\", \"0\", \"200\", \"0\"}, nil},\n\n\t\t{\"when the incorrect number of lines provided, error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Per Engine\"},\n\t\t\tengineBlock, \"5GUL\", []string{\"\"}, errors.New(\"the content of the log file is incorrect\")},\n\n\t\t{\"when the incorrect number of lines provided, error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Per Engine\", \"\"},\n\t\t\tengineBlock, \"5GUL\", []string{\"\"}, errors.New(\"the content of the log file is incorrect\")},\n\n\t\t{\"when the incorrect line provided, error should be returned\", []string{\"Something different\"},\n\t\t\t\"\", \"5GUL\", []string{\"\"}, errors.New(\"substring is empty\")},\n\n\t\t{\"when the incorrect line provided error should be returned\", []string{\"Device Status:: 1 VFs\", \"INFO:00counters:\", \"INFO:0  0\"},\n\t\t\t\"I\", \"\", nil, errors.New(\"metric's data is empty\")},\n\n\t\t{\"when the incorrect metric's line provided error should be returned\", []string{\"Device Status:: 1 VFs\", \"INFO:00counters:B\", \"INFO: \"},\n\t\t\t\"B\", \"\", nil, errors.New(\"metric's data is incorrect\")},\n\n\t\t{\"when the operation name wasn't found, error should be returned\", []string{\"Device Status:: 1 VFs\", \"\", \"INFO:countersCode Blocks\"},\n\t\t\t\"B\", \"\", nil, errors.New(\"valid operation name wasn't found in log\")},\n\n\t\t{\"when lines are empty, error should be returned\", []string{\"\"},\n\t\t\t\"something\", \"5GUL\", []string{\"\"}, errors.New(\"couldn't find the substring\")},\n\n\t\t{\"when lines are empty, error should be returned\", nil,\n\t\t\t\"something\", \"5GUL\", []string{\"\"}, errors.New(\"couldn't find the substring\")},\n\t}\n\n\tlogConnector := prepareLogConnMock()\n\trequire.NotNil(t, logConnector)\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tlogConnector.lines = tc.input\n\t\t\toffset, metric, err := logConnector.getMetric(0, tc.metricName)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, 2, offset)\n\t\t\trequire.Equal(t, tc.expectedOperation, metric.operationName)\n\t\t\trequire.ElementsMatch(t, tc.expectedData, metric.data)\n\t\t})\n\t}\n}\n\nfunc TestReadAndGetMetrics(t *testing.T) {\n\ttestCases := []struct {\n\t\tname               string\n\t\tfilePath           string\n\t\tmetricName         string\n\t\texpectedOperations []string\n\t\texpectedData       [][]string\n\t}{\n\t\t{\"with correct values no error should be returned for Code Blocks\",\n\t\t\t\"testdata/logfiles/example.log\",\n\t\t\tvfCodeBlocks, []string{\"5GUL\", \"5GDL\"}, [][]string{{\"0\", \"0\"}, {\"1\", \"0\"}}},\n\t\t{\"with correct values no error should be returned for Data Blocks\",\n\t\t\t\"testdata/logfiles/example.log\",\n\t\t\tvfDataBlock, []string{\"5GUL\", \"5GDL\"}, [][]string{{\"0\", \"0\"}, {\"2699\", \"0\"}}},\n\t\t{\"with correct values no error should be returned for Per Engine Blocks\",\n\t\t\t\"testdata/logfiles/example.log\",\n\t\t\tengineBlock, []string{\"5GUL\", \"5GDL\"}, [][]string{{\"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\"}, {\"1\", \"0\", \"0\"}}},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tlogConnector := prepareLogConnMock()\n\t\t\trequire.NotNil(t, logConnector)\n\t\t\tlogConnector.path = tc.filePath\n\t\t\terr := logConnector.readLogFile()\n\t\t\trequire.NoError(t, err)\n\t\t\tmetrics, err := logConnector.getMetrics(tc.metricName)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, metrics, len(tc.expectedOperations))\n\n\t\t\tfor i := range metrics {\n\t\t\t\trequire.Equal(t, tc.expectedOperations[i], metrics[i].operationName)\n\t\t\t\trequire.ElementsMatch(t, tc.expectedData[i], metrics[i].data)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetMetrics(t *testing.T) {\n\ttestCases := []struct {\n\t\tname               string\n\t\tinput              []string\n\t\tmetricName         string\n\t\texpectedOperations []string\n\t\texpectedData       [][]string\n\t\terr                error\n\t}{\n\t\t{\"with correct values no error should be returned\",\n\t\t\t[]string{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Code Blocks\", \"Thu May 18 08:45:15 2023:INFO:0 0\",\n\t\t\t\t\"Thu May 18 08:45:15 2023:INFO:5GUL counters: XXXX XXXX\", \"Thu May 18 08:45:15 2023:INFO:0 1\", \"sdasadasdsa\",\n\t\t\t\t\"Thu May 18 08:45:15 2023:INFO:5GDL counters: Code Blocks\", \"Thu May 18 08:45:15 2023:INFO:1 1\",\n\t\t\t\t\"Thu May 18 08:45:15 2023:INFO:5GUL counters: XXXX XXXX\", \"Thu May 18 08:45:15 2023:INFO:0 1\", \"sdasadasdsa\"},\n\t\t\tvfCodeBlocks, []string{\"5GUL\", \"5GDL\"}, [][]string{{\"0\", \"0\"}, {\"1\", \"1\"}}, nil},\n\n\t\t{\"when lines are empty, error should be returned\", []string{\"\"},\n\t\t\t\"something\", nil, nil, errors.New(\"couldn't find the substring in the log file\")},\n\n\t\t{\"when lines are nil, error should be returned\", nil,\n\t\t\t\"something\", nil, nil, errors.New(\"couldn't find the substring in the log file\")},\n\t}\n\n\tlogConnector := prepareLogConnMock()\n\trequire.NotNil(t, logConnector)\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tlogConnector.lines = tc.input\n\t\t\tmetrics, err := logConnector.getMetrics(tc.metricName)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, metrics, len(tc.expectedOperations))\n\n\t\t\tfor i := range metrics {\n\t\t\t\trequire.Equal(t, tc.expectedOperations[i], metrics[i].operationName)\n\t\t\t\trequire.ElementsMatch(t, tc.expectedData[i], metrics[i].data)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetNumVFs(t *testing.T) {\n\ttestCases := []struct {\n\t\tname     string\n\t\tinput    []string\n\t\texpected int\n\t\terr      error\n\t}{\n\t\t{\"incorrect format of the line\", []string{\"Device Status::VFs\"}, -1, errors.New(\"incorrect format of the line\")},\n\t\t{\"when the line is correct, no error should be returned\", []string{\"Device Status:: 0 VFs\"}, 0, nil},\n\t\t{\"when the line is correct, no error should be returned\", []string{\"Device Status:: 10 VFs\"}, 10, nil},\n\t\t{\"when the line is correct, no error should be returned\", []string{\"Device Status:: 5000 VFs\"}, 5000, nil},\n\t\t{\"when the value is not int, error should be returned\", []string{\"Device Status:: Nah VFs\"}, -1, errors.New(\"invalid syntax\")},\n\t\t{\"when end prefix isn't found, error should be returned\", []string{\"Device Status:: Nah END\"}, -1, errors.New(\"couldn't find device end prefix\")},\n\t\t{\"when the line is empty, error should be returned\", []string{\"\"}, -1, errors.New(\"numVFs data wasn't found\")},\n\t\t{\"when the line is empty, error should be returned\", nil, -1, errors.New(\"numVFs data wasn't found\")},\n\t}\n\n\tlogConnector := prepareLogConnMock()\n\trequire.NotNil(t, logConnector)\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tlogConnector.lines = tc.input\n\t\t\terr := logConnector.readNumVFs()\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tnumVFs := logConnector.getNumVFs()\n\t\t\trequire.Equal(t, tc.expected, numVFs)\n\t\t\trequire.Equal(t, tc.expected, logConnector.numVFs)\n\t\t})\n\t}\n}\n\nfunc TestParseOperationName(t *testing.T) {\n\ttestCases := []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\"Thu May 18 08:45:15 2023:INFO:5GUL counters: Code Blocks\", \"5GUL\"},\n\t\t{\"May 18 08:45:15 2023:INFO:5GUL counters: Per Engine\", \"5GUL\"},\n\t\t{\"023:INFO:3G counters: Per \", \"3G\"},\n\t\t{\"Device Status:: Nah VFs\", \"\"},\n\t\t{\"\", \"\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(\"expected \"+tc.expected, func(t *testing.T) {\n\t\t\toperationName := parseOperationName(tc.input)\n\t\t\trequire.Equal(t, tc.expected, operationName)\n\t\t})\n\t}\n}\n\nfunc prepareLogConnMock() *logConnector {\n\treturn &logConnector{\n\t\tpath:        \"\",\n\t\tnumVFs:      -1,\n\t\tlastModTime: time.Time{},\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/mocks/conn.go",
    "content": "// Code generated by mockery v2.46.3. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// Conn is an autogenerated mock type for the Conn type\ntype Conn struct {\n\tmock.Mock\n}\n\n// Close provides a mock function with given fields:\nfunc (_m *Conn) Close() error {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Close\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// LocalAddr provides a mock function with given fields:\nfunc (_m *Conn) LocalAddr() net.Addr {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for LocalAddr\")\n\t}\n\n\tvar r0 net.Addr\n\tif rf, ok := ret.Get(0).(func() net.Addr); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(net.Addr)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// Read provides a mock function with given fields: b\nfunc (_m *Conn) Read(b []byte) (int, error) {\n\tret := _m.Called(b)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Read\")\n\t}\n\n\tvar r0 int\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {\n\t\treturn rf(b)\n\t}\n\tif rf, ok := ret.Get(0).(func([]byte) int); ok {\n\t\tr0 = rf(b)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(b)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// RemoteAddr provides a mock function with given fields:\nfunc (_m *Conn) RemoteAddr() net.Addr {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for RemoteAddr\")\n\t}\n\n\tvar r0 net.Addr\n\tif rf, ok := ret.Get(0).(func() net.Addr); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(net.Addr)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// SetDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SetReadDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetReadDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetReadDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SetWriteDeadline provides a mock function with given fields: t\nfunc (_m *Conn) SetWriteDeadline(t time.Time) error {\n\tret := _m.Called(t)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for SetWriteDeadline\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(time.Time) error); ok {\n\t\tr0 = rf(t)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Write provides a mock function with given fields: b\nfunc (_m *Conn) Write(b []byte) (int, error) {\n\tret := _m.Called(b)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for Write\")\n\t}\n\n\tvar r0 int\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {\n\t\treturn rf(b)\n\t}\n\tif rf, ok := ret.Get(0).(func([]byte) int); ok {\n\t\tr0 = rf(b)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(b)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// NewConn creates a new instance of Conn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.\n// The first argument is typically a *testing.T value.\nfunc NewConn(t interface {\n\tmock.TestingT\n\tCleanup(func())\n}) *Conn {\n\tmock := &Conn{}\n\tmock.Mock.Test(t)\n\n\tt.Cleanup(func() { mock.AssertExpectations(t) })\n\n\treturn mock\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/sample.conf",
    "content": "# Intel Baseband Accelerator Input Plugin collects metrics from both dedicated and integrated\n# Intel devices that provide Wireless Baseband hardware acceleration.\n# This plugin ONLY supports Linux.\n[[inputs.intel_baseband]]\n  ## Path to socket exposed by pf-bb-config for CLI interaction (mandatory).\n  ## In version v23.03 of pf-bb-config the path is created according to the schema:\n  ##   \"/tmp/pf_bb_config.0000\\:<b>\\:<d>.<f>.sock\" where 0000\\:<b>\\:<d>.<f> is the PCI device ID.\n  socket_path = \"\"\n\n  ## Path to log file exposed by pf-bb-config with telemetry to read (mandatory).\n  ## In version v23.03 of pf-bb-config the path is created according to the schema:\n  ##   \"/var/log/pf_bb_cfg_0000\\:<b>\\:<d>.<f>.log\" where 0000\\:<b>\\:<d>.<f> is the PCI device ID.\n  log_file_path = \"\"\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error on startup if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n\n  ## Duration that defines how long the connected socket client will wait for\n  ## a response before terminating connection.\n  ## Since it's local socket access to a fast packet processing application, the timeout should\n  ## be sufficient for most users.\n  ## Setting the value to 0 disables the timeout (not recommended).\n  # socket_access_timeout = \"1s\"\n\n  ## Duration that defines maximum time plugin will wait for pf-bb-config to write telemetry to the log file.\n  ## Timeout may differ depending on the environment.\n  ## Must be equal or larger than 50ms.\n  # wait_for_telemetry_timeout = \"1s\"\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/sock_connector.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n)\n\nconst (\n\t// Command code\n\tclearLogCmdID   = 0x4\n\tdeviceDataCmdID = 0x9\n)\n\ntype socketConnector struct {\n\tpathToSocket  string\n\taccessTimeout time.Duration\n\tconnection    net.Conn\n}\n\nfunc (sc *socketConnector) dumpTelemetryToLog() error {\n\t// clean the log to have only the latest metrics in the file\n\terr := sc.sendCommandToSocket(clearLogCmdID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send clear log command: %w\", err)\n\t}\n\n\t// fill the file with the latest metrics\n\terr = sc.sendCommandToSocket(deviceDataCmdID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send device data command: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (sc *socketConnector) sendCommandToSocket(c byte) error {\n\terr := sc.connect()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer sc.close()\n\terr = sc.writeCommandToSocket(c)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (sc *socketConnector) writeCommandToSocket(c byte) error {\n\tif sc.connection == nil {\n\t\treturn errors.New(\"connection had not been established before\")\n\t}\n\tvar err error\n\tif sc.accessTimeout == 0 {\n\t\terr = sc.connection.SetWriteDeadline(time.Time{})\n\t} else {\n\t\terr = sc.connection.SetWriteDeadline(time.Now().Add(sc.accessTimeout))\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set timeout for request: %w\", err)\n\t}\n\n\t_, err = sc.connection.Write([]byte{c, 0x00})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send request to socket: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (sc *socketConnector) connect() error {\n\tconnection, err := net.Dial(\"unix\", sc.pathToSocket)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to connect to the socket: %w\", err)\n\t}\n\n\tsc.connection = connection\n\treturn nil\n}\n\nfunc (sc *socketConnector) close() error {\n\tif sc.connection == nil {\n\t\treturn nil\n\t}\n\n\terr := sc.connection.Close()\n\tsc.connection = nil\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc newSocketConnector(pathToSocket string, accessTimeout time.Duration) *socketConnector {\n\treturn &socketConnector{\n\t\tpathToSocket:  pathToSocket,\n\t\taccessTimeout: accessTimeout,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/sock_connector_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/intel_baseband/mocks\"\n)\n\nfunc TestWriteCommandToSocket(t *testing.T) {\n\tt.Run(\"correct execution of the function\", func(t *testing.T) {\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Write\", mock.Anything).Return(2, nil)\n\t\tconn.On(\"SetWriteDeadline\", mock.Anything).Return(nil)\n\t\tconnector := socketConnector{connection: conn}\n\n\t\terr := connector.writeCommandToSocket(0x00)\n\t\trequire.NoError(t, err)\n\n\t\tdefer conn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"without setting up a connection it should return an error\", func(t *testing.T) {\n\t\tconnector := socketConnector{}\n\n\t\terr := connector.writeCommandToSocket(0x00)\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"connection had not been established before\")\n\t})\n\n\tt.Run(\"handling timeout setting error\", func(t *testing.T) {\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"SetWriteDeadline\", mock.Anything).Return(errors.New(\"deadline set error\"))\n\t\tconnector := socketConnector{connection: conn}\n\n\t\terr := connector.writeCommandToSocket(0x00)\n\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"failed to set timeout for request\")\n\t\trequire.ErrorContains(t, err, \"deadline set error\")\n\t\tdefer conn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"handling net.Write error\", func(t *testing.T) {\n\t\tvar unsupportedCommand byte = 0x99\n\t\tconn := &mocks.Conn{}\n\t\tconn.On(\"Write\", []byte{unsupportedCommand, 0x00}).Return(0, errors.New(\"unsupported command\"))\n\t\tconn.On(\"SetWriteDeadline\", mock.Anything).Return(nil)\n\t\tconnector := socketConnector{connection: conn}\n\n\t\terr := connector.writeCommandToSocket(unsupportedCommand)\n\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"failed to send request to socket\")\n\t\trequire.ErrorContains(t, err, \"unsupported command\")\n\t\tdefer conn.AssertExpectations(t)\n\t})\n}\n\nfunc TestDumpTelemetryToLog(t *testing.T) {\n\tt.Run(\"with correct temporary socket should return only an error related to the inability to refresh telemetry\", func(t *testing.T) {\n\t\ttempSocket := newTempSocket(t)\n\t\tdefer tempSocket.Close()\n\t\ttempLogFile := newTempLogFile(t)\n\t\tdefer tempLogFile.close()\n\t\tconnector := newSocketConnector(tempSocket.pathToSocket, 5*time.Second)\n\n\t\terr := connector.dumpTelemetryToLog()\n\t\trequire.NoError(t, err)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/testdata/logfiles/empty.log",
    "content": ""
  },
  {
    "path": "plugins/inputs/intel_baseband/testdata/logfiles/example.log",
    "content": "Thu May 18 08:45:15 2023:INFO:device_data command received\nThu May 18 08:45:15 2023:INFO:Device Status:: 2 VFs\nThu May 18 08:45:15 2023:INFO:-  VF 0 RTE_BBDEV_DEV_CONFIGURED\nThu May 18 08:45:15 2023:INFO:-  VF 1 RTE_BBDEV_DEV_CONFIGURED\nThu May 18 08:45:15 2023:INFO:5GUL counters: Code Blocks\nThu May 18 08:45:15 2023:INFO:0 0\nThu May 18 08:45:15 2023:INFO:5GUL counters: Data (Bytes)\nThu May 18 08:45:15 2023:INFO:0 0\nThu May 18 08:45:15 2023:INFO:5GUL counters: Per Engine\nThu May 18 08:45:15 2023:INFO:0 0 0 0 0 0 0 0\nThu May 18 08:45:15 2023:INFO:5GDL counters: Code Blocks\nThu May 18 08:45:15 2023:INFO:1 0\nThu May 18 08:45:15 2023:INFO:5GDL counters: Data (Bytes)\nThu May 18 08:45:15 2023:INFO:2699 0\nThu May 18 08:45:15 2023:INFO:5GDL counters: Per Engine\nThu May 18 08:45:15 2023:INFO:1 0 0"
  },
  {
    "path": "plugins/inputs/intel_baseband/utils.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype fileType int\n\nconst (\n\tlog fileType = iota\n\tsocket\n)\n\nfunc validatePath(pathToRead string, ft fileType) (string, error) {\n\tif pathToRead == \"\" {\n\t\treturn \"\", errors.New(\"required path not specified\")\n\t}\n\tcleanPath := path.Clean(pathToRead)\n\tif (ft == log && path.Ext(cleanPath) != logFileExtension) || (ft == socket && path.Ext(cleanPath) != socketExtension) {\n\t\treturn \"\", fmt.Errorf(\"wrong file extension: %q\", cleanPath)\n\t}\n\tif !path.IsAbs(cleanPath) {\n\t\treturn \"\", fmt.Errorf(\"path is not absolute %q\", cleanPath)\n\t}\n\treturn cleanPath, nil\n}\n\nfunc checkFile(pathToFile string, fileType fileType) error {\n\tpathInfo, err := os.Lstat(pathToFile)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"provided path does not exist: %q\", pathToFile)\n\t\t}\n\t\tif errors.Is(err, fs.ErrPermission) {\n\t\t\treturn fmt.Errorf(\"user doesn't have enough privileges to file %q\", pathToFile)\n\t\t}\n\n\t\treturn fmt.Errorf(\"couldn't get system information of file %q: %w\", pathToFile, err)\n\t}\n\n\tmode := pathInfo.Mode()\n\tswitch fileType {\n\tcase socket:\n\t\tif mode&os.ModeSocket != os.ModeSocket {\n\t\t\treturn fmt.Errorf(\"provided path does not point to a socket file: %q\", pathToFile)\n\t\t}\n\tcase log:\n\t\tif !(mode.IsRegular()) {\n\t\t\treturn fmt.Errorf(\"provided path does not point to a log file: %q\", pathToFile)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Replace metric name to snake case\n// Example: Code Blocks -> code_blocks\nfunc metricNameToTagName(metricName string) string {\n\tcleanedStr := strings.Replace(strings.Replace(strings.Replace(metricName, \"(\", \"\", -1), \")\", \"\", -1), \" \", \"_\", -1)\n\treturn strings.ToLower(cleanedStr)\n}\n\nfunc logMetricDataToValue(data string) (int, error) {\n\tvalue, err := strconv.Atoi(data)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif value < 0 {\n\t\treturn 0, errors.New(\"metric can't be negative\")\n\t}\n\n\treturn value, nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_baseband/utils_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_baseband\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMetricNameToTagName(t *testing.T) {\n\ttestCases := []struct {\n\t\tmetricName      string\n\t\texpectedTagName string\n\t}{\n\t\t{vfCodeBlocks, \"code_blocks\"},\n\t\t{vfDataBlock, \"data_bytes\"},\n\t\t{engineBlock, \"per_engine\"},\n\t\t{\"\", \"\"},\n\t}\n\n\tt.Run(\"check the correct transformation metric name\", func(t *testing.T) {\n\t\tfor _, tc := range testCases {\n\t\t\ttagName := metricNameToTagName(tc.metricName)\n\t\t\trequire.Equal(t, tc.expectedTagName, tagName)\n\t\t}\n\t})\n}\n\nfunc TestValidatePath(t *testing.T) {\n\tt.Run(\"with correct file extensions checkFile shouldn't return any errors\", func(t *testing.T) {\n\t\ttestCases := []struct {\n\t\t\tpath         string\n\t\t\tft           fileType\n\t\t\texpectedPath string\n\t\t}{\n\t\t\t{\"/tmp/socket.sock\", socket, \"/tmp/socket.sock\"},\n\t\t\t{\"/foo/../tmp/socket.sock\", socket, \"/tmp/socket.sock\"},\n\t\t\t{\"/tmp/file.log\", log, \"/tmp/file.log\"},\n\t\t\t{\"/foo/../tmp/file.log\", log, \"/tmp/file.log\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\treturnPath, err := validatePath(tc.path, tc.ft)\n\t\t\trequire.Equal(t, tc.expectedPath, returnPath)\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n\tt.Run(\"with empty path specified validate path should return an error\", func(t *testing.T) {\n\t\ttestCases := []struct {\n\t\t\tpath                  string\n\t\t\tft                    fileType\n\t\t\texpectedErrorContains string\n\t\t}{\n\t\t\t{\"\", socket, \"required path not specified\"},\n\t\t\t{\"\", log, \"required path not specified\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\treturnPath, err := validatePath(tc.path, tc.ft)\n\t\t\trequire.Empty(t, returnPath)\n\t\t\trequire.ErrorContains(t, err, tc.expectedErrorContains)\n\t\t}\n\t})\n\tt.Run(\"with wrong extension file validatePath should return an error\", func(t *testing.T) {\n\t\ttestCases := []struct {\n\t\t\tpath                  string\n\t\t\tft                    fileType\n\t\t\texpectedErrorContains string\n\t\t}{\n\t\t\t{\"/tmp/socket.foo\", socket, \"wrong file extension\"},\n\t\t\t{\"/tmp/file.foo\", log, \"wrong file extension\"},\n\t\t\t{\"/tmp/socket.sock\", log, \"wrong file extension\"},\n\t\t\t{\"/tmp/file.log\", socket, \"wrong file extension\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\treturnPath, err := validatePath(tc.path, tc.ft)\n\t\t\trequire.Empty(t, returnPath)\n\t\t\trequire.ErrorContains(t, err, tc.expectedErrorContains)\n\t\t}\n\t})\n\tt.Run(\"with not absolute path validatePath should return the error\", func(t *testing.T) {\n\t\ttestCases := []struct {\n\t\t\tpath                  string\n\t\t\tft                    fileType\n\t\t\texpectedErrorContains string\n\t\t}{\n\t\t\t{\"foo/tmp/socket.sock\", socket, \"path is not absolute\"},\n\t\t\t{\"foo/tmp/file.log\", log, \"path is not absolute\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\treturnPath, err := validatePath(tc.path, tc.ft)\n\t\t\trequire.Empty(t, returnPath)\n\t\t\trequire.ErrorContains(t, err, tc.expectedErrorContains)\n\t\t}\n\t})\n}\n\nfunc TestCheckFile(t *testing.T) {\n\tt.Run(\"with correct file extensions checkFile shouldn't return any errors\", func(t *testing.T) {\n\t\ttempSocket := newTempSocket(t)\n\t\tdefer tempSocket.Close()\n\n\t\ttestCases := []struct {\n\t\t\tpath string\n\t\t\tft   fileType\n\t\t}{\n\t\t\t{\"testdata/logfiles/example.log\", log},\n\t\t\t{tempSocket.pathToSocket, socket},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\terr := checkFile(tc.path, tc.ft)\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n\tt.Run(\"path does not point to the correct file type\", func(t *testing.T) {\n\t\ttempSocket := newTempSocket(t)\n\t\tdefer tempSocket.Close()\n\n\t\ttestCases := []struct {\n\t\t\tpath                  string\n\t\t\tft                    fileType\n\t\t\texpectedErrorContains string\n\t\t}{\n\t\t\t{\"testdata/logfiles/example.log\", socket, \"provided path does not point to a socket file\"},\n\t\t\t{tempSocket.pathToSocket, log, \"provided path does not point to a log file:\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\terr := checkFile(tc.path, tc.ft)\n\t\t\trequire.ErrorContains(t, err, tc.expectedErrorContains)\n\t\t}\n\t})\n\n\tt.Run(\"with path to non existing file checkFile should return the error\", func(t *testing.T) {\n\t\ttestCases := []struct {\n\t\t\tpath                  string\n\t\t\tft                    fileType\n\t\t\texpectedErrorContains string\n\t\t}{\n\t\t\t{\"/foo/example.log\", log, \"provided path does not exist\"},\n\t\t\t{\"/foo/example.sock\", socket, \"provided path does not exist\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\terr := checkFile(tc.path, tc.ft)\n\t\t\trequire.ErrorContains(t, err, tc.expectedErrorContains)\n\t\t}\n\t})\n}\n\nfunc TestLogMetricDataToValue(t *testing.T) {\n\ttestCases := []struct {\n\t\tmetricData    string\n\t\texpectedValue int\n\t\terr           error\n\t}{\n\t\t{\"010\", 10, nil},\n\t\t{\"00\", 0, nil},\n\t\t{\"5\", 5, nil},\n\t\t{\"-010\", 0, errors.New(\"metric can't be negative\")},\n\t\t{\"\", 0, errors.New(\"invalid syntax\")},\n\t\t{\"0Nax10\", 0, errors.New(\"invalid syntax\")},\n\t}\n\n\tt.Run(\"check correct returned values\", func(t *testing.T) {\n\t\tfor _, tc := range testCases {\n\t\t\tvalue, err := logMetricDataToValue(tc.metricData)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tc.expectedValue, value)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/README.md",
    "content": "# Intel® Dynamic Load Balancer Input Plugin\n\nThis plugin collects metrics exposed by applications built with the\n[Data Plane Development Kit][dpdk], an extensive set of open source libraries\ndesigned for accelerating packet processing workloads, plugin is also using\nbifurcated driver. More specifically it's targeted for applications using\nIntel DLB as eventdev devices accessed via bifurcated driver\n(allowing access from kernel and user-space).\n\n⭐ Telegraf v1.25.0\n🏷️ applications\n💻 linux\n\n[dpdk]: https://www.dpdk.org/\n\n## Requirements\n\n- Linux kernel 5.12+\n- [DLB >= v7.4](https://www.intel.com/content/www/us/en/download/686372/intel-dynamic-load-balancer.html)\n- [DPDK >= 20.11.3](http://core.dpdk.org/download/)\n\n> [!NOTE] It may happen that sysfs entries or the socket telemetry interface\n> exposed by DPDK-based app will require root access. This means that either\n> access permissions have to be adjusted for sysfs / socket telemetry\n> interface to allow Telegraf to access it, or Telegraf should run with root\n> privileges.\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n## Reads metrics from DPDK using v2 telemetry interface.\n## This plugin ONLY supports Linux\n[[inputs.intel_dlb]]\n  ## Path to DPDK telemetry socket.\n  # socket_path = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\n  ## Default eventdev command list, it gathers metrics from socket by given commands.\n  ## Supported options:\n  ##   \"/eventdev/dev_xstats\", \"/eventdev/port_xstats\",\n  ##   \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"\n  # eventdev_commands = [\"/eventdev/dev_xstats\", \"/eventdev/port_xstats\", \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"]\n\n  ## Detect DLB devices based on device id.\n  ## Currently, only supported and tested device id is `0x2710`.\n  ## Configuration added to support forward compatibility.\n  # dlb_device_types = [\"0x2710\"]\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error on startup if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n```\n\nDefault configuration allows getting metrics for all metrics\nreported via `/eventdev/` command:\n\n- `/eventdev/dev_xstats`\n- `/eventdev/port_xstats`\n- `/eventdev/queue_xstats`\n- `/eventdev/queue_links`\n\n## Metrics\n\nThere are two sources of metrics:\n\n- DPDK-based app for detailed eventdev metrics per device, per port and per queue\n- Sysfs entries from kernel driver for RAS metrics\n\n## Example Output\n\n```text\nintel_dlb,command=/eventdev/dev_xstats\\,0,host=controller1 dev_dir_pool_size=0i,dev_inflight_events=8192i,dev_ldb_pool_size=8192i,dev_nb_events_limit=8192i,dev_pool_size=0i,dev_rx_drop=0i,dev_rx_interrupt_wait=0i,dev_rx_ok=463126660i,dev_rx_umonitor_umwait=0i,dev_total_polls=78422946i,dev_tx_nospc_dir_hw_credits=0i,dev_tx_nospc_hw_credits=584614i,dev_tx_nospc_inflight_credits=0i,dev_tx_nospc_inflight_max=0i,dev_tx_nospc_ldb_hw_credits=584614i,dev_tx_nospc_new_event_limit=59331982i,dev_tx_ok=694694059i,dev_zero_polls=29667908i 1641996791000000000\nintel_dlb,command=/eventdev/queue_links\\,0\\,1,host=controller1 qid_0=128i,qid_1=128i 1641996791000000000\nintel_dlb_ras,device=pci0000:6d,host=controller1,metric_file=aer_dev_correctable BadDLLP=0i,BadTLP=0i,CorrIntErr=0i,HeaderOF=0i,NonFatalErr=0i,Rollover=0i,RxErr=0i,TOTAL_ERR_COR=0i,Timeout=0i 1641996791000000000\nintel_dlb_ras,device=pci0000:6d,host=controller1,metric_file=aer_dev_fatal ACSViol=0i,AtomicOpBlocked=0i,BlockedTLP=0i,CmpltAbrt=0i,CmpltTO=0i,DLP=0i,ECRC=0i,FCP=0i,MalfTLP=0i,PoisonTLPBlocked=0i,RxOF=0i,SDES=0i,TLP=0i,TLPBlockedErr=0i,TOTAL_ERR_FATAL=0i,UncorrIntErr=0i,Undefined=0i,UnsupReq=0i,UnxCmplt=0i 1641996791000000000\n```\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/intel_dlb.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n// +build linux\n\npackage intel_dlb\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar unreachableSocketBehaviors = []string{\"error\", \"ignore\"}\n\nconst (\n\tdefaultSocketPath      = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\tpluginName             = \"intel_dlb\"\n\teventdevListCommand    = \"/eventdev/dev_list\"\n\tdlbDeviceIDLocation    = \"/sys/devices/*/*/device\"\n\taerCorrectableFileName = \"aer_dev_correctable\"\n\taerFatalFileName       = \"aer_dev_fatal\"\n\taerNonFatalFileName    = \"aer_dev_nonfatal\"\n\tdefaultDLBDevice       = \"0x2710\"\n)\n\ntype IntelDLB struct {\n\tSocketPath                string          `toml:\"socket_path\"`\n\tEventdevCommands          []string        `toml:\"eventdev_commands\"`\n\tDLBDeviceIDs              []string        `toml:\"dlb_device_types\"`\n\tUnreachableSocketBehavior string          `toml:\"unreachable_socket_behavior\"`\n\tLog                       telegraf.Logger `toml:\"-\"`\n\n\tconnection           net.Conn\n\tdevicesDir           []string\n\trasReader            rasReader\n\tmaxInitMessageLength uint32\n}\n\nfunc (*IntelDLB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (d *IntelDLB) Init() error {\n\tvar err error\n\n\tif d.UnreachableSocketBehavior == \"\" {\n\t\td.UnreachableSocketBehavior = \"error\"\n\t}\n\n\tif err = choice.Check(d.UnreachableSocketBehavior, unreachableSocketBehaviors); err != nil {\n\t\treturn fmt.Errorf(\"unreachable_socket_behavior: %w\", err)\n\t}\n\n\tif d.SocketPath == \"\" {\n\t\td.SocketPath = defaultSocketPath\n\t\td.Log.Debugf(\"Using default '%v' path for socket_path\", defaultSocketPath)\n\t}\n\n\terr = checkSocketPath(d.SocketPath)\n\tif err != nil {\n\t\tif d.UnreachableSocketBehavior == \"error\" {\n\t\t\treturn err\n\t\t}\n\t\td.Log.Warn(err)\n\t}\n\n\tif len(d.EventdevCommands) == 0 {\n\t\teventdevDefaultCommands := []string{\"/eventdev/dev_xstats\", \"/eventdev/port_xstats\", \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"}\n\t\td.EventdevCommands = eventdevDefaultCommands\n\t\td.Log.Debugf(\"Using default eventdev commands '%v'\", eventdevDefaultCommands)\n\t}\n\n\tif err := validateEventdevCommands(d.EventdevCommands); err != nil {\n\t\treturn err\n\t}\n\n\tif len(d.DLBDeviceIDs) == 0 {\n\t\td.DLBDeviceIDs = []string{defaultDLBDevice}\n\t\td.Log.Debugf(\"Using default DLB Device ID '%v'\", defaultDLBDevice)\n\t}\n\n\terr = d.checkAndAddDLBDevice()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\td.maxInitMessageLength = 1024\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) Gather(acc telegraf.Accumulator) error {\n\terr := d.gatherMetricsFromSocket(acc)\n\tif err != nil {\n\t\tsocketErr := fmt.Errorf(\"gathering metrics from socket by given commands failed: %w\", err)\n\t\tif d.UnreachableSocketBehavior == \"error\" {\n\t\t\treturn socketErr\n\t\t}\n\t\td.Log.Debug(socketErr)\n\t}\n\n\terr = d.gatherRasMetrics(acc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"gathering RAS metrics failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) gatherRasMetrics(acc telegraf.Accumulator) error {\n\tfor _, devicePath := range d.devicesDir {\n\t\trasTags := map[string]string{\n\t\t\t\"device\": filepath.Base(filepath.Dir(devicePath)),\n\t\t}\n\n\t\taerFilesName := []string{aerCorrectableFileName, aerFatalFileName, aerNonFatalFileName}\n\t\tfor _, fileName := range aerFilesName {\n\t\t\trasTags[\"metric_file\"] = fileName\n\t\t\trasMetrics, err := d.readRasMetrics(devicePath, fileName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tacc.AddFields(\"intel_dlb_ras\", rasMetrics, rasTags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (d *IntelDLB) readRasMetrics(devicePath, metricPath string) (map[string]interface{}, error) {\n\tdeviceMetricPath := filepath.Join(devicePath, metricPath)\n\n\tdata, err := d.rasReader.readFromFile(deviceMetricPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmetrics := strings.Split(strings.TrimSpace(string(data)), \"\\n\")\n\n\trasMetric := make(map[string]interface{})\n\tfor _, metric := range metrics {\n\t\tmetricPart := strings.Split(metric, \" \")\n\t\tif len(metricPart) < 2 {\n\t\t\treturn nil, fmt.Errorf(\"no value to parse: %+q\", metricPart)\n\t\t}\n\n\t\tmetricVal, err := strconv.ParseUint(metricPart[1], 10, 10)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse value %q: %w\", metricPart[1], err)\n\t\t}\n\t\trasMetric[metricPart[0]] = metricVal\n\t}\n\n\treturn rasMetric, nil\n}\n\nfunc (d *IntelDLB) gatherMetricsFromSocket(acc telegraf.Accumulator) error {\n\t// Get device indexes and those indexes to available commands\n\tcommandsWithIndex, err := d.gatherCommandsWithDeviceIndex()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, command := range commandsWithIndex {\n\t\t// Write message to socket, e.g.: \"/eventdev/dev_xstats,0\", then process result and parse it to variable.\n\t\tvar parsedDeviceXstats map[string]map[string]int\n\t\terr := d.gatherCommandsResult(command, &parsedDeviceXstats)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar statsWithValue = make(map[string]interface{})\n\t\tfor _, commandBody := range parsedDeviceXstats {\n\t\t\tfor metricName, metricValue := range commandBody {\n\t\t\t\tstatsWithValue[metricName] = metricValue\n\t\t\t}\n\t\t}\n\n\t\tvar tags = map[string]string{\n\t\t\t\"command\": command,\n\t\t}\n\t\tacc.AddFields(pluginName, statsWithValue, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) gatherCommandsWithDeviceIndex() ([]string, error) {\n\t// Parse message from JSON format to map e.g.: key = \"/eventdev/dev_list\", and value = [0, 1]\n\tvar parsedDeviceIndexes map[string][]int\n\terr := d.gatherCommandsResult(eventdevListCommand, &parsedDeviceIndexes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar commandsWithIndex []string\n\tfor _, deviceIndexes := range parsedDeviceIndexes {\n\t\tfor _, index := range deviceIndexes {\n\t\t\tfor _, command := range d.EventdevCommands {\n\t\t\t\tif !strings.Contains(command, \"dev_\") {\n\t\t\t\t\tsecondDeviceIndexes, err := d.gatherSecondDeviceIndex(index, command)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tcommandsWithIndex = append(commandsWithIndex, secondDeviceIndexes...)\n\t\t\t\t} else {\n\t\t\t\t\t// Append to \"/eventdev/dev_xstats,\" device index eg.: \"/eventdev/dev_xstats\" + \",\" + \"0\"\n\t\t\t\t\tcommandWithIndex := fmt.Sprintf(\"%s,%d\", command, index)\n\t\t\t\t\tcommandsWithIndex = append(commandsWithIndex, commandWithIndex)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn commandsWithIndex, nil\n}\n\nfunc (d *IntelDLB) gatherCommandsResult(command string, deviceToParse interface{}) error {\n\terr := d.ensureConnected()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treplyMsgLen, socketReply, err := d.writeReadSocketMessage(command)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = d.parseJSON(replyMsgLen, socketReply, &deviceToParse)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) gatherSecondDeviceIndex(index int, command string) ([]string, error) {\n\teventdevListWithSecondIndex := []string{\"/eventdev/port_list\", \"/eventdev/queue_list\"}\n\tvar commandsWithIndex []string\n\tfor _, commandToGatherSecondIndex := range eventdevListWithSecondIndex {\n\t\t// get command type e.g.: \"port_xstat\" gives \"port\"\n\t\tcommandType := strings.Split(command, \"_\")\n\t\tif len(commandType) != 2 {\n\t\t\treturn nil, d.closeSocketAndThrowError(\"custom\", fmt.Errorf(\"cannot split command - %s\", commandType))\n\t\t}\n\n\t\tif strings.Contains(commandToGatherSecondIndex, commandType[0]) {\n\t\t\tvar parsedDeviceSecondIndexes map[string][]int\n\t\t\tcommandToGatherWithIndex := fmt.Sprintf(\"%s,%d\", commandToGatherSecondIndex, index)\n\n\t\t\terr := d.gatherCommandsResult(commandToGatherWithIndex, &parsedDeviceSecondIndexes)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tfor _, indexArray := range parsedDeviceSecondIndexes {\n\t\t\t\tfor _, secondIndex := range indexArray {\n\t\t\t\t\tcommandWithIndex := fmt.Sprintf(\"%s,%d,%d\", command, index, secondIndex)\n\t\t\t\t\tcommandsWithIndex = append(commandsWithIndex, commandWithIndex)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn commandsWithIndex, nil\n}\n\nfunc (d *IntelDLB) ensureConnected() error {\n\tvar err error\n\td.maxInitMessageLength = uint32(1024)\n\tif d.connection == nil {\n\t\td.connection, err = net.Dial(\"unixpacket\", d.SocketPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = d.setInitMessageLength()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) setInitMessageLength() error {\n\ttype initMessage struct {\n\t\tVersion      string `json:\"version\"`\n\t\tPid          int    `json:\"pid\"`\n\t\tMaxOutputLen uint32 `json:\"max_output_len\"`\n\t}\n\tbuf := make([]byte, d.maxInitMessageLength)\n\tmessageLength, err := d.connection.Read(buf)\n\tif err != nil {\n\t\treturn d.closeSocketAndThrowError(\"custom\", fmt.Errorf(\"failed to read InitMessage from socket: %w\", err))\n\t}\n\tif messageLength > len(buf) {\n\t\treturn d.closeSocketAndThrowError(\"custom\", errors.New(\"socket reply length is bigger than default buffer length\"))\n\t}\n\n\tvar initMsg initMessage\n\terr = json.Unmarshal(buf[:messageLength], &initMsg)\n\tif err != nil {\n\t\treturn d.closeSocketAndThrowError(\"json\", err)\n\t}\n\tif initMsg.MaxOutputLen == 0 {\n\t\treturn d.closeSocketAndThrowError(\"message\", err)\n\t}\n\n\td.maxInitMessageLength = initMsg.MaxOutputLen\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) writeReadSocketMessage(messageToWrite string) (int, []byte, error) {\n\t_, writeErr := d.connection.Write([]byte(messageToWrite))\n\tif writeErr != nil {\n\t\treturn 0, nil, d.closeSocketAndThrowError(\"write\", writeErr)\n\t}\n\n\t// Read reply, and obtain length of it.\n\tsocketReply := make([]byte, d.maxInitMessageLength)\n\treplyMsgLen, readErr := d.connection.Read(socketReply)\n\tif readErr != nil {\n\t\treturn 0, nil, d.closeSocketAndThrowError(\"read\", readErr)\n\t}\n\n\tif replyMsgLen == 0 {\n\t\treturn 0, nil, d.closeSocketAndThrowError(\"message\", errors.New(\"message length is empty\"))\n\t}\n\n\treturn replyMsgLen, socketReply, nil\n}\n\nfunc (d *IntelDLB) parseJSON(replyMsgLen int, socketReply []byte, parsedDeviceInfo interface{}) error {\n\tif len(socketReply) == 0 {\n\t\treturn d.closeSocketAndThrowError(\"json\", errors.New(\"socket reply is empty\"))\n\t}\n\tif replyMsgLen > len(socketReply) {\n\t\treturn d.closeSocketAndThrowError(\"json\", errors.New(\"socket reply length is bigger than it should be\"))\n\t}\n\tif replyMsgLen == 0 {\n\t\treturn d.closeSocketAndThrowError(\"json\", errors.New(\"socket reply message is empty\"))\n\t}\n\t// Assign reply to variable, e.g.:  {\"/eventdev/dev_list\": [0, 1]}\n\tjsonDeviceIndexes := socketReply[:replyMsgLen]\n\n\t// Parse message from JSON format to map, e.g.: map[string]int. Key = \"/eventdev/dev_list\" Value = Array[int] {0,1}\n\tjsonParseErr := json.Unmarshal(jsonDeviceIndexes, &parsedDeviceInfo)\n\tif jsonParseErr != nil {\n\t\treturn d.closeSocketAndThrowError(\"json\", jsonParseErr)\n\t}\n\n\treturn nil\n}\n\nfunc (d *IntelDLB) closeSocketAndThrowError(errType string, err error) error {\n\tconst (\n\t\twriteErrMsg  = \"failed to send command to socket: '%v'\"\n\t\treadErrMsg   = \"failed to read response of from socket: '%v'\"\n\t\tmsgLenErr    = \"got empty response from socket: '%v'\"\n\t\tjsonParseErr = \"failed to parse json: '%v'\"\n\t\tfailedConErr = \" - and failed to close connection '%v'\"\n\t\tcustomErr    = \"error occurred: '%v'\"\n\t)\n\n\tvar errMsg string\n\tswitch errType {\n\tcase \"write\":\n\t\terrMsg = writeErrMsg\n\tcase \"read\":\n\t\terrMsg = readErrMsg\n\tcase \"message\":\n\t\terrMsg = msgLenErr\n\tcase \"json\":\n\t\terrMsg = jsonParseErr\n\tcase \"custom\":\n\t\terrMsg = customErr\n\t}\n\n\tif d.connection != nil {\n\t\tcloseConnectionErr := d.connection.Close()\n\t\td.connection = nil\n\t\tif closeConnectionErr != nil {\n\t\t\terrCloseMsg := errMsg + failedConErr\n\t\t\treturn fmt.Errorf(errCloseMsg, err, closeConnectionErr)\n\t\t}\n\t}\n\n\treturn fmt.Errorf(errMsg, err)\n}\n\nfunc (d *IntelDLB) checkAndAddDLBDevice() error {\n\tif d.rasReader == nil {\n\t\treturn errors.New(\"rasreader was not initialized\")\n\t}\n\tfilePaths, err := d.rasReader.gatherPaths(dlbDeviceIDLocation)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdeviceIDToDirs := make(map[string][]string)\n\tfor _, path := range filePaths {\n\t\tfileData, err := d.rasReader.readFromFile(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// check if it is DLB device\n\t\ttrimmedDeviceID := strings.TrimSpace(string(fileData))\n\t\tif !choice.Contains(trimmedDeviceID, d.DLBDeviceIDs) {\n\t\t\tcontinue\n\t\t}\n\t\tdeviceDir := filepath.Dir(path)\n\t\tdeviceIDToDirs[trimmedDeviceID] = append(deviceIDToDirs[trimmedDeviceID], deviceDir)\n\t\td.devicesDir = append(d.devicesDir, deviceDir)\n\t}\n\tif len(d.devicesDir) == 0 {\n\t\treturn fmt.Errorf(\"cannot find any of provided IDs on the system - %+q\", d.DLBDeviceIDs)\n\t}\n\tfor _, deviceID := range d.DLBDeviceIDs {\n\t\tif len(deviceIDToDirs[deviceID]) == 0 {\n\t\t\td.Log.Debugf(\"Device %s was not found on system\", deviceID)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc checkSocketPath(path string) error {\n\tpathInfo, err := os.Lstat(path)\n\tif os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"provided path does not exist: '%v'\", path)\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get system information of %q file: %w\", path, err)\n\t}\n\n\tif pathInfo.Mode()&os.ModeSocket != os.ModeSocket {\n\t\treturn fmt.Errorf(\"provided path does not point to a socket file: '%v'\", path)\n\t}\n\n\treturn nil\n}\n\nfunc validateEventdevCommands(commands []string) error {\n\teventdevCommandRegex := regexp.MustCompile(\"^/eventdev/[a-z_]+$\")\n\tfor _, command := range commands {\n\t\tif !eventdevCommandRegex.MatchString(command) {\n\t\t\treturn fmt.Errorf(\"provided command is not valid - %v\", command)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\treturn &IntelDLB{\n\t\t\trasReader: rasReaderImpl{},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/intel_dlb_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage intel_dlb\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IntelDLB struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*IntelDLB) SampleConfig() string { return sampleConfig }\n\nfunc (i *IntelDLB) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\nfunc (*IntelDLB) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"intel_dlb\", func() telegraf.Input {\n\t\treturn &IntelDLB{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/intel_dlb_test.go",
    "content": "//go:build linux\n// +build linux\n\npackage intel_dlb\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/dpdk/mocks\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDLB_Init(t *testing.T) {\n\tt.Run(\"when SocketPath is empty, then set default value\", func(t *testing.T) {\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath: \"\",\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\trequire.Empty(t, dlb.SocketPath)\n\n\t\t//nolint:errcheck // we are just testing that socket path gets set to default, not that default is valid\n\t\tdlb.Init()\n\n\t\trequire.Equal(t, defaultSocketPath, dlb.SocketPath)\n\t})\n\n\tt.Run(\"invalid socket path throws error in Init method when UnreachableSocketBehavior is set to 'error'\", func(t *testing.T) {\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath:                \"/this/is/wrong/path\",\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: \"error\",\n\t\t}\n\t\terr := dlb.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided path does not exist\")\n\t})\n\n\tt.Run(\"not-existing socket path doesn't throw error in Init method when UnreachableSocketBehavior is set to 'ignore'\", func(t *testing.T) {\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath:                \"/socket/is/not/there/yet\",\n\t\t\tLog:                       testutil.Logger{},\n\t\t\tUnreachableSocketBehavior: \"ignore\",\n\t\t}\n\t\terr := dlb.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.NotContains(t, err.Error(), \"provided path does not exist\")\n\t})\n\n\tt.Run(\"wrong UnreachableSocketBehavior option throws error in Init method\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t)\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath:                pathToSocket,\n\t\t\tUnreachableSocketBehavior: \"DAS BOOT\",\n\t\t\tLog:                       testutil.Logger{},\n\t\t}\n\t\terr := dlb.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"unreachable_socket_behavior: unknown choice DAS BOOT\")\n\t})\n\n\tt.Run(\"wrong eventdev command throws error in Init method\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t)\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath:       pathToSocket,\n\t\t\tEventdevCommands: []string{\"/noteventdev/dev_xstats\"},\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := dlb.Init()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided command is not valid - \")\n\t})\n\n\tt.Run(\"wrong eventdev command throws error\", func(t *testing.T) {\n\t\tdlb := IntelDLB{\n\t\t\tEventdevCommands: []string{\"/noteventdev/dev_xstats\"},\n\t\t}\n\t\terr := validateEventdevCommands(dlb.EventdevCommands)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"provided command is not valid - \")\n\t})\n\n\tt.Run(\"validate eventdev command\", func(t *testing.T) {\n\t\tdlb := IntelDLB{\n\t\t\tEventdevCommands: []string{\"/eventdev/dev_xstats\"},\n\t\t}\n\t\terr := validateEventdevCommands(dlb.EventdevCommands)\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"successfully initialize intel_dlb struct\", func(t *testing.T) {\n\t\tpathToSocket, socket := createSocketForTest(t)\n\t\tfileMock := &mockRasReader{}\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath: pathToSocket,\n\t\t\tLog:        testutil.Logger{},\n\t\t\trasReader:  fileMock,\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x2710\"), nil).Once()\n\n\t\terr := dlb.Init()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, []string{\"/eventdev/dev_xstats\", \"/eventdev/port_xstats\", \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"}, dlb.EventdevCommands)\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throw error while initializing dlb plugin when theres no dlb device\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tpathToSocket, socket := createSocketForTest(t)\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\trasReader:  fileMock,\n\t\t\tSocketPath: pathToSocket,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tconst emptyPath = \"\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{emptyPath}, errors.New(\"can't find device folder\")).Once()\n\t\terr := dlb.Init()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"can't find device folder\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_writeReadSocketMessage(t *testing.T) {\n\tt.Run(\"throws custom error message when write error occur\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tmockConn.On(\"Write\", make([]byte, 0)).Return(0, errors.New(\"write error\")).Once().\n\t\t\tOn(\"Close\").Return(nil).Once()\n\n\t\t_, _, err := dlb.writeReadSocketMessage(\"\")\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to send command to socket: 'write error'\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throws custom error message when read error occur\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tsimulateResponse(mockConn, \"\", errors.New(\"read error\"))\n\n\t\t_, _, err := dlb.writeReadSocketMessage(\"\")\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to read response of from socket: 'read error'\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throws custom error message when write error occur\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tmockConn.On(\"Write\", make([]byte, 0)).Return(0, nil).Once().\n\t\t\tOn(\"Read\", mock.Anything).Return(0, nil).\n\t\t\tOn(\"Close\").Return(nil).Once()\n\n\t\t_, _, err := dlb.writeReadSocketMessage(\"\")\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"got empty response from socket: 'message length is empty'\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_parseJSON(t *testing.T) {\n\tvar tests = []struct {\n\t\ttestName    string\n\t\tsocketReply []byte\n\t\treplyMsgLen int\n\t\terrMsg      string\n\t}{\n\t\t{\"wrong json format\", []byte(\"/wrong/json\"), 10, \"invalid character '/' looking for beginning of value\"},\n\t\t{\"socket reply length equal to 0 throws error\", []byte(\"/wrong/json\"), 0, \"socket reply message is empty\"},\n\t\t{\"invalid reply length throws error\", []byte(\"/wrong/json\"), 20, \"socket reply length is bigger than it should be\"},\n\t\t{\"nil socket reply throws error\", nil, 0, \"socket reply is empty\"},\n\t}\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.testName, func(t *testing.T) {\n\t\t\tmockConn := &mocks.Conn{}\n\t\t\tdlb := IntelDLB{\n\t\t\t\tconnection: mockConn,\n\t\t\t\tLog:        testutil.Logger{},\n\t\t\t}\n\t\t\tmockConn.On(\"Close\").Return(nil).Once()\n\n\t\t\terr := dlb.parseJSON(testCase.replyMsgLen, testCase.socketReply, make(map[string]interface{}))\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), testCase.errMsg)\n\t\t\tmockConn.AssertExpectations(t)\n\t\t})\n\t}\n}\n\nfunc TestDLB_getInitMessageLength(t *testing.T) {\n\tt.Run(\"trying to unmarshal invalid JSON throws error\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t\trasReader:  fileMock,\n\t\t}\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, \"\")\n\t\t}).Return(len(\"\"), nil).Once().On(\"Close\").Return(nil).Once()\n\n\t\terr := dlb.setInitMessageLength()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"when init message equals 0 throw error\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t\trasReader:  fileMock,\n\t\t}\n\t\tdlb.maxInitMessageLength = 1024\n\t\tconst initMsgResponse = \"{\\\"version\\\":\\\"DPDK 20.11.3\\\",\\\"pid\\\":208361,\\\"max_output_len\\\":0}\"\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, initMsgResponse)\n\t\t}).Return(len(initMsgResponse), nil).Once().On(\"Close\").Return(nil).Once()\n\n\t\terr := dlb.setInitMessageLength()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"got empty response from socket\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_gatherCommandsResult(t *testing.T) {\n\tt.Run(\"trying connecting to wrong socket throw error\", func(t *testing.T) {\n\t\tpathToSocket := \"/tmp/dpdk-test-socket\"\n\t\tsocket, err := net.Listen(\"unix\", pathToSocket)\n\t\tfileMock := &mockRasReader{}\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\tSocketPath: pathToSocket,\n\t\t\tLog:        testutil.Logger{},\n\t\t\trasReader:  fileMock,\n\t\t}\n\t\trequire.NoError(t, err)\n\n\t\terr = dlb.gatherCommandsResult(\"\", nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"connect: protocol wrong type for socket\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_gatherCommandsWithDeviceIndex(t *testing.T) {\n\tt.Run(\"process wrong commands should throw error\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:       mockConn,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tEventdevCommands: []string{\"/eventdev/dev_xstats\"},\n\t\t}\n\t\tresponse := \"/wrong/JSON\"\n\t\tdlb.maxInitMessageLength = 1024\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil)\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\n\t\t_, err := dlb.gatherCommandsWithDeviceIndex()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process commands should return array with command and device id\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/dev_xstats\"},\n\t\t}\n\t\tresponse := fmt.Sprintf(`{%q: [0, 1]}`, eventdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\texpectedCommands := []string{\"/eventdev/dev_xstats,0\", \"/eventdev/dev_xstats,1\"}\n\n\t\tcommands, err := dlb.gatherCommandsWithDeviceIndex()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCommands, commands)\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process commands should return array with queue and device id\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/queue_links\"},\n\t\t}\n\t\tresponseDevList := fmt.Sprintf(`{%q: [0]}`, eventdevListCommand)\n\t\tsimulateResponse(mockConn, responseDevList, nil)\n\t\tresponseQueueLinks := `{\"0\": [0]}`\n\t\tsimulateResponse(mockConn, responseQueueLinks, nil)\n\n\t\texpectedCommands := []string{\"/eventdev/queue_links,0,0\"}\n\n\t\tcommands, err := dlb.gatherCommandsWithDeviceIndex()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCommands, commands)\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process wrong commands should throw error\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/dev_xstats\", \"/eventdev/wrong\"},\n\t\t}\n\t\tresponse := fmt.Sprintf(`{%q: [0, 1]}`, eventdevListCommand)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil).Once()\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, response)\n\t\t}).Return(len(response), nil).Once().On(\"Close\").Return(nil).Once()\n\n\t\t_, err := dlb.gatherCommandsWithDeviceIndex()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"cannot split command\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_gatherSecondDeviceIndex(t *testing.T) {\n\tt.Run(\"process wrong commands should return error\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:       mockConn,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tEventdevCommands: []string{\"/eventdev/wrong\"},\n\t\t}\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\t\t_, err := dlb.gatherSecondDeviceIndex(0, dlb.EventdevCommands[0])\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"cannot split command -\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process wrong response commands should throw error\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:       mockConn,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tEventdevCommands: []string{\"/eventdev/port_xstats\"},\n\t\t}\n\t\tresponse := \"/wrong/JSON\"\n\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\n\t\t_, err := dlb.gatherSecondDeviceIndex(0, dlb.EventdevCommands[0])\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process wrong response commands should throw error and close socket, after second function call should connect to socket\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tpathToSocket, socket := createSocketForTest(t)\n\t\tdefer socket.Close()\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/port_xstats\"},\n\t\t}\n\n\t\tresponse := \"/wrong/JSON\"\n\n\t\tsimulateResponse(mockConn, response, nil)\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\n\t\t_, err := dlb.gatherSecondDeviceIndex(0, dlb.EventdevCommands[0])\n\t\trequire.Nil(t, dlb.connection)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json\")\n\t\tdlb.SocketPath = pathToSocket\n\t\tgo simulateSocketResponseForGather(socket, t)\n\t\tcommandDeviceIndexes, err := dlb.gatherSecondDeviceIndex(0, dlb.EventdevCommands[0])\n\t\trequire.NoError(t, err)\n\n\t\texpectedCommands := []string{\"/eventdev/port_xstats,0,0\", \"/eventdev/port_xstats,0,1\"}\n\t\tcommands := commandDeviceIndexes\n\n\t\trequire.Equal(t, expectedCommands, commands)\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"process commands should return array with command and second device id\", func(t *testing.T) {\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/port_xstats\"},\n\t\t}\n\t\teventdevListWithSecondIndex := []string{\"/eventdev/port_list\", \"/eventdev/queue_list\"}\n\t\tresponse := fmt.Sprintf(`{%q: [0, 1]}`, eventdevListWithSecondIndex[0])\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\texpectedCommands := []string{\"/eventdev/port_xstats,0,0\", \"/eventdev/port_xstats,0,1\"}\n\n\t\tcommandDeviceIndexes, err := dlb.gatherSecondDeviceIndex(0, dlb.EventdevCommands[0])\n\n\t\tcommands := commandDeviceIndexes\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCommands, commands)\n\t\tmockConn.AssertExpectations(t)\n\t})\n}\n\nfunc TestDLB_processCommandResult(t *testing.T) {\n\tt.Run(\"gather xstats info with valid values\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tEventdevCommands:     []string{\"/eventdev/dev_xstats\"},\n\t\t}\n\t\tresponse := fmt.Sprintf(`{%q: [0]}`, eventdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\tresponse = `{\"/eventdev/dev_xstats\": {\"dev_rx_ok\": 0}}`\n\t\tsimulateResponse(mockConn, response, nil)\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\t\trequire.NoError(t, err)\n\n\t\texpected := []telegraf.Metric{\n\t\t\ttestutil.MustMetric(\n\t\t\t\t\"intel_dlb\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"command\": \"/eventdev/dev_xstats,0\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"dev_rx_ok\": int64(0),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t),\n\t\t}\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\n\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"successfully gather xstats and aer metrics\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tEventdevCommands:     []string{\"/eventdev/dev_xstats\"},\n\t\t\tdevicesDir:           []string{\"/sys/devices/pci0000:00/0000:00:00.0/device\"},\n\t\t\trasReader:            fileMock,\n\t\t\tmaxInitMessageLength: 1024,\n\t\t}\n\t\tresponseGather := fmt.Sprintf(`{%q: [0]}`, eventdevListCommand)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil).Twice()\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, responseGather)\n\t\t}).Return(len(responseGather), nil).Once()\n\t\tresponse := `{\"/eventdev/dev_xstats\": {\"dev_rx_ok\": 0}}`\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, response)\n\t\t}).Return(len(response), nil).Once()\n\t\tfileMock.On(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerCorrectableData), nil).Once().\n\t\t\tOn(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerFatalData), nil).Once().\n\t\t\tOn(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerNonFatalData), nil).Once()\n\t\terr := dlb.Gather(mockAcc)\n\t\trequire.NoError(t, err)\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.SortMetrics()\n\t\tex := expectedTelegrafMetrics\n\t\ttestutil.RequireMetricsEqual(t, ex, actual, testutil.IgnoreTime())\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"invalid JSON throws error in process result function\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:       mockConn,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tEventdevCommands: []string{\"/eventdev/dev_xstats\"},\n\t\t}\n\t\tresponse := fmt.Sprintf(`{%q: [0]}`, eventdevListCommand)\n\t\tsimulateResponse(mockConn, response, nil)\n\n\t\tsimulateResponse(mockConn, \"/wrong/json\", nil)\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throw error when reply message is empty\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tconst response = \"\"\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil)\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, response)\n\t\t}).Return(len(response), nil).Once()\n\t\tmockConn.On(\"Close\").Return(nil)\n\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"got empty response from socket\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throw error when can't read socket reply\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tconst response = \"\"\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil)\n\t\tmockConn.On(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, response)\n\t\t}).Return(len(response), errors.New(\"read error\")).Once()\n\t\tmockConn.On(\"Close\").Return(nil)\n\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to read response of from socket\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throw error when invalid reply was provided\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tmaxInitMessageLength: 1024,\n\t\t\tLog:                  testutil.Logger{},\n\t\t}\n\t\tsimulateResponse(mockConn, \"\\\"string reply\\\"\", nil)\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"json: cannot unmarshal string into Go value of type\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n\n\tt.Run(\"throw error while processing xstats\", func(t *testing.T) {\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tmockConn := &mocks.Conn{}\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection:           mockConn,\n\t\t\tLog:                  testutil.Logger{},\n\t\t\tEventdevCommands:     []string{\"/eventdev/dev_xstats\"},\n\t\t\trasReader:            fileMock,\n\t\t\tmaxInitMessageLength: 1024,\n\t\t}\n\t\tmockConn.On(\"Close\").Return(nil)\n\n\t\tresponseGather := fmt.Sprintf(`{%q: [0]}`, eventdevListCommand)\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil).Once().\n\t\t\tOn(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, responseGather)\n\t\t}).Return(len(responseGather), nil).Once()\n\n\t\twrongResponse := \"/wrong/json\"\n\t\tmockConn.On(\"Write\", mock.Anything).Return(0, nil).Once().\n\t\t\tOn(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\t\telem := arg.Get(0).([]byte)\n\t\t\tcopy(elem, wrongResponse)\n\t\t}).Return(len(wrongResponse), nil).Once()\n\n\t\terr := dlb.gatherMetricsFromSocket(mockAcc)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to parse json:\")\n\t\tmockConn.AssertExpectations(t)\n\t})\n}\n\nfunc Test_checkAndAddDLBDevice(t *testing.T) {\n\tt.Run(\"throw error when dlb validation can't find device folder\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader: fileMock,\n\t\t\tLog:       testutil.Logger{},\n\t\t}\n\t\tfileMock.On(\"gatherPaths\", mock.AnythingOfType(\"string\")).Return(nil, errors.New(\"can't find device folder\")).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"can't find device folder\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"reading file throws error\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader:  fileMock,\n\t\t\tLog:        testutil.Logger{},\n\t\t\tdevicesDir: []string{\"/sys/devices/pci0000:00/0000:00:00.0/device\"},\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x2710\"), errors.New(\"read error while getting device folders\")).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"read error while getting device folders\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"reading file with empty rasreader throws error\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\tLog: testutil.Logger{},\n\t\t}\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"rasreader was not initialized\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"reading file with unused device IDs throws error\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader:    fileMock,\n\t\t\tLog:          testutil.Logger{},\n\t\t\tdevicesDir:   []string{\"/sys/devices/pci0000:00/0000:00:00.0/device\"},\n\t\t\tDLBDeviceIDs: []string{\"0x2710\"},\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x2710\"), errors.New(\"read error while getting device folders\")).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"read error while getting device folders\")\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"no errors when dlb device was found while validating\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader:    fileMock,\n\t\t\tLog:          testutil.Logger{},\n\t\t\tDLBDeviceIDs: []string{\"0x2710\"},\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x2710\"), nil).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.NoError(t, err)\n\n\t\texpected := []string{\"/sys/devices/pci0000:00/0000:00:00.0\"}\n\t\trequire.Equal(t, expected, dlb.devicesDir)\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"no errors when found unused dlb device\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader:    fileMock,\n\t\t\tLog:          testutil.Logger{},\n\t\t\tDLBDeviceIDs: []string{\"0x2710\", \"0x0000\"},\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x2710\"), nil).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.NoError(t, err)\n\n\t\texpected := []string{\"/sys/devices/pci0000:00/0000:00:00.0\"}\n\t\trequire.Equal(t, expected, dlb.devicesDir)\n\t\tfileMock.AssertExpectations(t)\n\t})\n\n\tt.Run(\"error when dlb device was not found while validating\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tmockConn := &mocks.Conn{}\n\t\tdlb := IntelDLB{\n\t\t\tconnection: mockConn,\n\t\t\trasReader:  fileMock,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tconst globPath = \"/sys/devices/pci0000:00/0000:00:00.0/device\"\n\t\tfileMock.On(\"gatherPaths\", mock.Anything).Return([]string{globPath}, nil).Once().\n\t\t\tOn(\"readFromFile\", mock.Anything).Return([]byte(\"0x7100\"), nil).Once()\n\n\t\terr := dlb.checkAndAddDLBDevice()\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"cannot find any of provided IDs on the system - %+q\", dlb.DLBDeviceIDs))\n\t\tfileMock.AssertExpectations(t)\n\t\tmockConn.AssertExpectations(t)\n\t})\n}\n\nfunc Test_readRasMetrics(t *testing.T) {\n\tvar errorTests = []struct {\n\t\tname           string\n\t\treturnResponse []byte\n\t\terr            error\n\t\terrMsg         string\n\t}{\n\t\t{\"error when reading fails\", []byte(aerCorrectableData), errors.New(\"read error\"), \"read error\"},\n\t\t{\"error when empty data is given\", []byte(\"\"), nil, \"no value to parse\"},\n\t\t{\"error when trying to split empty data\", []byte(\"x1 x2\"), nil, \"failed to parse value\"},\n\t}\n\n\tfor _, test := range errorTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tfileMock := &mockRasReader{}\n\t\t\tmockConn := &mocks.Conn{}\n\t\t\tdlb := IntelDLB{\n\t\t\t\tconnection: mockConn,\n\t\t\t\trasReader:  fileMock,\n\t\t\t\tLog:        testutil.Logger{},\n\t\t\t}\n\t\t\tmockConn.On(\"Close\").Return(nil).Once()\n\t\t\tfileMock.On(\"readFromFile\", mock.AnythingOfType(\"string\")).Return(test.returnResponse, test.err).Once()\n\n\t\t\t_, err := dlb.readRasMetrics(\"/dlb\", \"device\")\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), test.errMsg)\n\t\t\tfileMock.AssertExpectations(t)\n\t\t})\n\t}\n\n\tt.Run(\"no error when reading countable error file\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader: fileMock,\n\t\t\tLog:       testutil.Logger{},\n\t\t}\n\n\t\tfileMock.On(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerCorrectableData), nil).Once()\n\n\t\t_, err := dlb.readRasMetrics(\"/dlb\", \"device\")\n\n\t\trequire.NoError(t, err)\n\t\tfileMock.AssertExpectations(t)\n\t})\n}\n\nfunc Test_gatherRasMetrics(t *testing.T) {\n\tvar errorTests = []struct {\n\t\tname           string\n\t\treturnResponse []byte\n\t\terr            error\n\t\terrMsg         string\n\t}{\n\t\t{\"throw error when data in file is invalid\", nil, nil, \"no value to parse\"},\n\t\t{\"throw error when data in file is invalid\", []byte(\"x1 x2\"), nil, \"failed to parse value\"},\n\t}\n\tfor _, test := range errorTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tfileMock := &mockRasReader{}\n\t\t\tmockAcc := &testutil.Accumulator{}\n\t\t\tmockConn := &mocks.Conn{}\n\t\t\tdlb := IntelDLB{\n\t\t\t\tconnection: mockConn,\n\t\t\t\trasReader:  fileMock,\n\t\t\t\tdevicesDir: []string{\"/sys/devices/pci0000:00/0000:00:00.0/device\"},\n\t\t\t\tLog:        testutil.Logger{},\n\t\t\t}\n\t\t\tmockConn.On(\"Close\").Return(nil).Once()\n\t\t\tfileMock.On(\"readFromFile\", mock.AnythingOfType(\"string\")).Return(test.returnResponse, test.err).Once()\n\n\t\t\terr := dlb.gatherRasMetrics(mockAcc)\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), test.errMsg)\n\t\t\tfileMock.AssertExpectations(t)\n\t\t})\n\t}\n\n\tt.Run(\"gather ras metrics and add to accumulator\", func(t *testing.T) {\n\t\tfileMock := &mockRasReader{}\n\t\tmockAcc := &testutil.Accumulator{}\n\t\tdlb := IntelDLB{\n\t\t\trasReader:  fileMock,\n\t\t\tdevicesDir: []string{\"/sys/devices/pci0000:00/0000:00:00.0/device\"},\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\tfileMock.On(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerCorrectableData), nil).Once().\n\t\t\tOn(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerFatalData), nil).Once().\n\t\t\tOn(\"readFromFile\", mock.AnythingOfType(\"string\")).Return([]byte(aerNonFatalData), nil).Once()\n\n\t\terr := dlb.gatherRasMetrics(mockAcc)\n\n\t\trequire.NoError(t, err)\n\n\t\tactual := mockAcc.GetTelegrafMetrics()\n\t\ttestutil.SortMetrics()\n\t\ttestutil.RequireMetricsEqual(t, expectedRasMetrics, actual, testutil.IgnoreTime())\n\t\tfileMock.AssertExpectations(t)\n\t})\n}\n\nfunc Test_rasReader(t *testing.T) {\n\tfile := rasReaderImpl{}\n\t// Create unique temporary file\n\tfileobj, err := os.CreateTemp(t.TempDir(), \"qat\")\n\trequire.NoError(t, err)\n\n\tt.Run(\"tests with existing file\", func(t *testing.T) {\n\t\t// Remove the temporary file after this test\n\t\tdefer os.Remove(fileobj.Name())\n\n\t\t_, err = fileobj.WriteString(testFileContent)\n\t\trequire.NoError(t, err)\n\t\terr = fileobj.Close()\n\t\trequire.NoError(t, err)\n\n\t\t// Check that content returned by read is equal to provided file.\n\t\tdata, err := file.readFromFile(fileobj.Name())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, []byte(testFileContent), data)\n\n\t\t// Error if path is malformed.\n\t\t_, err = file.readFromFile(fileobj.Name() + \"/../..\")\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"not a directory\")\n\t})\n\n\tvar errorTests = []struct {\n\t\tname           string\n\t\tfilePath       string\n\t\texpectedErrMsg string\n\t}{\n\t\t{\"error if file does not exist\", fileobj.Name(), \"no such file or directory\"},\n\t\t{\"error if path does not point to regular file\", t.TempDir(), \"is a directory\"},\n\t\t{\"error if file does not exist\", \"/not/path/unreal/path\", \"no such file or directory\"},\n\t}\n\n\tfor _, test := range errorTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t_, err = file.readFromFile(test.filePath)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), test.expectedErrMsg)\n\t\t})\n\t}\n}\n\nfunc simulateResponse(mockConn *mocks.Conn, response string, readErr error) {\n\tmockConn.On(\"Write\", mock.Anything).Return(0, nil).Once().\n\t\tOn(\"Read\", mock.Anything).Run(func(arg mock.Arguments) {\n\t\telem := arg.Get(0).([]byte)\n\t\tcopy(elem, response)\n\t}).Return(len(response), readErr).Once()\n\n\tif readErr != nil {\n\t\tmockConn.On(\"Close\").Return(nil).Once()\n\t}\n}\n\nfunc simulateSocketResponseForGather(socket net.Listener, t *testing.T) {\n\tconn, err := socket.Accept()\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\ttype initMessage struct {\n\t\tVersion      string `json:\"version\"`\n\t\tPid          int    `json:\"pid\"`\n\t\tMaxOutputLen uint32 `json:\"max_output_len\"`\n\t}\n\tinitMsg, err := json.Marshal(initMessage{\n\t\tVersion:      \"\",\n\t\tPid:          1,\n\t\tMaxOutputLen: 1024,\n\t})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif _, err = conn.Write(initMsg); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\teventdevListWithSecondIndex := []string{\"/eventdev/port_list\", \"/eventdev/queue_list\"}\n\tif _, err = fmt.Fprintf(conn, `{%q: [0, 1]}`, eventdevListWithSecondIndex[0]); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc createSocketForTest(t *testing.T) (string, net.Listener) {\n\tpathToSocket := \"/tmp/dpdk-test-socket\"\n\tsocket, err := net.Listen(\"unixpacket\", pathToSocket)\n\trequire.NoError(t, err)\n\treturn pathToSocket, socket\n}\n\nconst (\n\ttestFileContent = `\nline1\nline2 2\nline3\nline4\nline5\n`\n\taerCorrectableData = `\nRxErr 1\nBadTLP 0\nBadDLLP 0\nRollover 1\nTimeout 0\nNonFatalErr 0\nCorrIntErr 0\nHeaderOF 0\nTOTAL_ERR_COR 0`\n\taerFatalData = `\nUndefined 0\nDLP 1\nSDES 0\nTLP 0\nFCP 0\nCmpltTO 0\nCmpltAbrt 0\nUnxCmplt 0\nRxOF 0\nMalfTLP 0\nECRC 0\nUnsupReq 0\nACSViol 0\nUncorrIntErr 0\nBlockedTLP 0\nAtomicOpBlocked 0\nTLPBlockedErr 0\nPoisonTLPBlocked 0\nTOTAL_ERR_FATAL 3`\n\taerNonFatalData = `\nUndefined 0\nDLP 0\nSDES 0\nTLP 0\nFCP 0\nCmpltTO 2\nCmpltAbrt 0\nUnxCmplt 0\nRxOF 0\nMalfTLP 0\nECRC 0\nUnsupReq 0\nACSViol 0\nUncorrIntErr 0\nBlockedTLP 0\nAtomicOpBlocked 0\nTLPBlockedErr 0\nPoisonTLPBlocked 0\nTOTAL_ERR_NONFATAL 9`\n)\n\nvar (\n\texpectedRasMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"intel_dlb_ras\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":      \"0000:00:00.0\",\n\t\t\t\t\"metric_file\": aerCorrectableFileName,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"RxErr\":         uint64(1),\n\t\t\t\t\"BadTLP\":        uint64(0),\n\t\t\t\t\"BadDLLP\":       uint64(0),\n\t\t\t\t\"Rollover\":      uint64(1),\n\t\t\t\t\"Timeout\":       uint64(0),\n\t\t\t\t\"NonFatalErr\":   uint64(0),\n\t\t\t\t\"CorrIntErr\":    uint64(0),\n\t\t\t\t\"HeaderOF\":      uint64(0),\n\t\t\t\t\"TOTAL_ERR_COR\": uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"intel_dlb_ras\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":      \"0000:00:00.0\",\n\t\t\t\t\"metric_file\": aerFatalFileName,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"Undefined\":        uint64(0),\n\t\t\t\t\"DLP\":              uint64(1),\n\t\t\t\t\"SDES\":             uint64(0),\n\t\t\t\t\"TLP\":              uint64(0),\n\t\t\t\t\"FCP\":              uint64(0),\n\t\t\t\t\"CmpltTO\":          uint64(0),\n\t\t\t\t\"CmpltAbrt\":        uint64(0),\n\t\t\t\t\"UnxCmplt\":         uint64(0),\n\t\t\t\t\"RxOF\":             uint64(0),\n\t\t\t\t\"MalfTLP\":          uint64(0),\n\t\t\t\t\"ECRC\":             uint64(0),\n\t\t\t\t\"UnsupReq\":         uint64(0),\n\t\t\t\t\"ACSViol\":          uint64(0),\n\t\t\t\t\"UncorrIntErr\":     uint64(0),\n\t\t\t\t\"BlockedTLP\":       uint64(0),\n\t\t\t\t\"AtomicOpBlocked\":  uint64(0),\n\t\t\t\t\"TLPBlockedErr\":    uint64(0),\n\t\t\t\t\"PoisonTLPBlocked\": uint64(0),\n\t\t\t\t\"TOTAL_ERR_FATAL\":  uint64(3),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"intel_dlb_ras\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":      \"0000:00:00.0\",\n\t\t\t\t\"metric_file\": aerNonFatalFileName,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"Undefined\":          uint64(0),\n\t\t\t\t\"DLP\":                uint64(0),\n\t\t\t\t\"SDES\":               uint64(0),\n\t\t\t\t\"TLP\":                uint64(0),\n\t\t\t\t\"FCP\":                uint64(0),\n\t\t\t\t\"CmpltTO\":            uint64(2),\n\t\t\t\t\"CmpltAbrt\":          uint64(0),\n\t\t\t\t\"UnxCmplt\":           uint64(0),\n\t\t\t\t\"RxOF\":               uint64(0),\n\t\t\t\t\"MalfTLP\":            uint64(0),\n\t\t\t\t\"ECRC\":               uint64(0),\n\t\t\t\t\"UnsupReq\":           uint64(0),\n\t\t\t\t\"ACSViol\":            uint64(0),\n\t\t\t\t\"UncorrIntErr\":       uint64(0),\n\t\t\t\t\"BlockedTLP\":         uint64(0),\n\t\t\t\t\"AtomicOpBlocked\":    uint64(0),\n\t\t\t\t\"TLPBlockedErr\":      uint64(0),\n\t\t\t\t\"PoisonTLPBlocked\":   uint64(0),\n\t\t\t\t\"TOTAL_ERR_NONFATAL\": uint64(9),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\texpectedTelegrafMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"intel_dlb\",\n\t\t\tmap[string]string{\n\t\t\t\t\"command\": \"/eventdev/dev_xstats,0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"dev_rx_ok\": int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\texpectedRasMetrics[0],\n\t\texpectedRasMetrics[1],\n\t\texpectedRasMetrics[2],\n\t}\n)\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/ras_reader.go",
    "content": "//go:build linux\n// +build linux\n\npackage intel_dlb\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\ntype rasReader interface {\n\tgatherPaths(path string) ([]string, error)\n\treadFromFile(filePath string) ([]byte, error)\n}\n\ntype rasReaderImpl struct {\n}\n\n// gatherPaths gathers all paths based on provided pattern\nfunc (rasReaderImpl) gatherPaths(pattern string) ([]string, error) {\n\tfilePaths, err := filepath.Glob(pattern)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"glob failed for pattern %q: %w\", pattern, err)\n\t}\n\n\tif len(filePaths) == 0 {\n\t\treturn nil, fmt.Errorf(\"no candidates for given pattern: %s\", pattern)\n\t}\n\n\treturn filePaths, nil\n}\n\n// readFromFile reads file content.\nfunc (rasReaderImpl) readFromFile(filePath string) ([]byte, error) {\n\treturn os.ReadFile(filePath)\n}\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/ras_reader_mock.go",
    "content": "// Code generated by mockery v2.46.3. DO NOT EDIT.\n\npackage intel_dlb\n\nimport mock \"github.com/stretchr/testify/mock\"\n\n// mockRasReader is an autogenerated mock type for the rasReader type\ntype mockRasReader struct {\n\tmock.Mock\n}\n\n// gatherPaths provides a mock function with given fields: path\nfunc (_m *mockRasReader) gatherPaths(path string) ([]string, error) {\n\tret := _m.Called(path)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for gatherPaths\")\n\t}\n\n\tvar r0 []string\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func(string) ([]string, error)); ok {\n\t\treturn rf(path)\n\t}\n\tif rf, ok := ret.Get(0).(func(string) []string); ok {\n\t\tr0 = rf(path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]string)\n\t\t}\n\t}\n\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// readFromFile provides a mock function with given fields: filePath\nfunc (_m *mockRasReader) readFromFile(filePath string) ([]byte, error) {\n\tret := _m.Called(filePath)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for readFromFile\")\n\t}\n\n\tvar r0 []byte\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func(string) ([]byte, error)); ok {\n\t\treturn rf(filePath)\n\t}\n\tif rf, ok := ret.Get(0).(func(string) []byte); ok {\n\t\tr0 = rf(filePath)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(filePath)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// newMockRasReader creates a new instance of mockRasReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.\n// The first argument is typically a *testing.T value.\nfunc newMockRasReader(t interface {\n\tmock.TestingT\n\tCleanup(func())\n}) *mockRasReader {\n\tmock := &mockRasReader{}\n\tmock.Mock.Test(t)\n\n\tt.Cleanup(func() { mock.AssertExpectations(t) })\n\n\treturn mock\n}\n"
  },
  {
    "path": "plugins/inputs/intel_dlb/sample.conf",
    "content": "## Reads metrics from DPDK using v2 telemetry interface.\n## This plugin ONLY supports Linux\n[[inputs.intel_dlb]]\n  ## Path to DPDK telemetry socket.\n  # socket_path = \"/var/run/dpdk/rte/dpdk_telemetry.v2\"\n\n  ## Default eventdev command list, it gathers metrics from socket by given commands.\n  ## Supported options:\n  ##   \"/eventdev/dev_xstats\", \"/eventdev/port_xstats\",\n  ##   \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"\n  # eventdev_commands = [\"/eventdev/dev_xstats\", \"/eventdev/port_xstats\", \"/eventdev/queue_xstats\", \"/eventdev/queue_links\"]\n\n  ## Detect DLB devices based on device id.\n  ## Currently, only supported and tested device id is `0x2710`.\n  ## Configuration added to support forward compatibility.\n  # dlb_device_types = [\"0x2710\"]\n\n  ## Specifies plugin behavior regarding unreachable socket (which might not have been initialized yet).\n  ## Available choices:\n  ##   - error: Telegraf will return an error on startup if socket is unreachable\n  ##   - ignore: Telegraf will ignore error regarding unreachable socket on both startup and gather\n  # unreachable_socket_behavior = \"error\"\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/README.md",
    "content": "# Intel® Platform Monitoring Technology Input Plugin\n\nThis plugin collects metrics via the Linux kernel driver for\nIntel® Platform Monitoring Technology (Intel® PMT), an architecture capable of\nenumerating and accessing hardware monitoring capabilities on supported devices.\n\n⭐ Telegraf v1.28.0\n🏷️ hardware, system\n💻 linux\n\n## Requirements\n\n- supported device\n- Linux kernel >= 5.11\n- `intel_pmt_telemetry` module loaded (on kernels 5.11-5.14)\n- `intel_pmt` module loaded (on kernels 5.14+)\n\nThis plugin supports devices exposing PMT, e.g.\n\n- 4th Generation Intel® Xeon® Scalable Processors (Sapphire Rapids / SPR)\n- 6th Generation Intel® Xeon® Scalable Processors (Granite Rapids / GNR)\n\nSupport has been added to the mainline Linux kernel under the platform driver\n(`drivers/platform/x86/intel/pmt`) which exposes the Intel PMT telemetry space\nas a sysfs entry at `/sys/class/intel_pmt/`. Each discovered telemetry\naggregator is exposed as a directory (with a `telem` prefix) containing a `guid`\nidentifying the unique PMT space. This file is associated with a set of XML\nspecification files which can be found in the [Intel-PMT Repository][repo].\nThe XML specification must be specified as an absolute path to the `pmt.xml`\nfile using the `spec` setting .\n\nThis plugin discovers and parses the telemetry data exposed by the kernel driver\nusing the specification inside the XML files. Furthermore, the plugin then reads\nlow level samples/counters and evaluates high level samples/counters according\nto transformation formulas, and then reports the collected values.\n\n> [!IMPORTANT]\n> PMT space is located in `/sys/class/intel_pmt` with `telem` files requiring\n> **root privileges** to be read. If Telegraf is not running as root you should\n> add the following capability to the Telegraf executable:\n>\n> ```sh\n> sudo setcap cap_dac_read_search+ep /usr/bin/telegraf\n> ```\n\n[repo]: https://github.com/intel/Intel-PMT\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Intel Platform Monitoring Technology plugin exposes Intel PMT metrics available through the Intel PMT kernel space.\n# This plugin ONLY supports Linux.\n[[inputs.intel_pmt]]\n  ## Filepath to PMT XML within local copies of XML files from PMT repository.\n  ## The filepath should be absolute.\n  spec = \"/home/telegraf/Intel-PMT/xml/pmt.xml\"\n  \n  ## Enable metrics by their datatype.\n  ## See the Enabling Metrics section in README for more details.\n  ## If empty, all metrics are enabled.\n  ## When used, the alternative option samples_enabled should NOT be used.\n  # datatypes_enabled = []\n  \n  ## Enable metrics by their name.\n  ## See the Enabling Metrics section in README for more details.\n  ## If empty, all metrics are enabled.\n  ## When used, the alternative option datatypes_enabled should NOT be used.\n  # samples_enabled = []\n```\n\n### Enabling metrics\n\nBy default, the plugin collects all available metrics.\n\nTo limit the metrics collected by the plugin,\ntwo options are available for selecting metrics:\n\n- enable by datatype (groups of metrics),\n- enable by name.\n\nIt's important to note that only one enabling option\nshould be chosen at a time.\n\nSee the table below for available datatypes and related metrics:\n\n| Datatype                | Metric name             | Description                                                                                                                 |\n|-------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------|\n| `txtal_strap`           | `XTAL_FREQ`             | Clock rate of the crystal oscillator on this silicon                                                                        |\n| `tdram_energy`          | `DRAM_ENERGY_LOW`       | DRAM energy consumed by all DIMMS in all Channels (uJ)                                                                      |\n|                         | `DRAM_ENERGY_HIGH`      | DRAM energy consumed by all DIMMS in all Channels (uJ)                                                                      |\n| `tbandwidth_32b`        | `C2U_BW`                | Core to Uncore Bandwidth (per core and per uncore)                                                                          |\n|                         | `U2C_BW`                | Uncore to Core Bandwidth (per core and per uncore)                                                                          |\n|                         | `PC2_LOW`               | Time spent in the Package C-State 2 (PC2)                                                                                   |\n|                         | `PC2_HIGH`              | Time spent in the Package C-State 2 (PC2)                                                                                   |\n|                         | `PC6_LOW`               | Time spent in the Package C-State 6 (PC6)                                                                                   |\n|                         | `PC6_HIGH`              | Time spent in the Package C-State 6 (PC6)                                                                                   |\n|                         | `MEM_RD_BW`             | Memory Read Bandwidth (per channel)                                                                                         |\n|                         | `MEM_WR_BW`             | Memory Write Bandwidth (per channel)                                                                                        |\n|                         | `DDRT_READ_BW`          | DDRT Read Bandwidth (per channel)                                                                                           |\n|                         | `DDRT_WR_BW`            | DDRT Write Bandwidth (per channel)                                                                                          |\n|                         | `THRT_COUNT`            | Number of clock ticks when throttling occurred on IMC channel (per channel)                                                 |\n|                         | `PMSUM`                 | Energy accumulated by IMC channel (per channel)                                                                             |\n|                         | `CMD_CNT_CH0`           | Command count for IMC channel subchannel 0 (per channel)                                                                    |\n|                         | `CMD_CNT_CH1`           | Command count for IMC channel subchannel 1 (per channel)                                                                    |\n| `tU32.0`                | `PEM_ANY`               | Duration for which a core frequency excursion occurred due to a listed or unlisted reason                                   |\n|                         | `PEM_THERMAL`           | Duration for which a core frequency excursion occurred due to EMTTM                                                         |\n|                         | `PEM_EXT_PROCHOT`       | Duration for which a core frequency excursion occurred due to an external PROCHOT assertion                                 |\n|                         | `PEM_PBM`               | Duration for which a core frequency excursion occurred due to PBM                                                           |\n|                         | `PEM_PL1`               | Duration for which a core frequency excursion occurred due to PL1                                                           |\n|                         | `PEM_RESERVED`          | PEM Reserved Counter                                                                                                        |\n|                         | `PEM_PL2`               | Duration for which a core frequency excursion occurred due to PL2                                                           |\n|                         | `PEM_PMAX`              | Duration for which a core frequency excursion occurred due to PMAX                                                          |\n| `tbandwidth_28b`        | `C0Residency`           | Core C0 Residency (per core)                                                                                                |\n|                         | `C1Residency`           | Core C1 Residency (per core)                                                                                                |\n| `tratio`                | `FET`                   | Current Frequency Excursion Threshold. Ratio of the core frequency.                                                         |\n| `tbandwidth_24b`        | `UFS_MAX_RING_TRAFFIC`  | IO Bandwidth for DMI or PCIE port (per port)                                                                                |\n| `ttemperature`          | `TEMP`                  | Current temperature of a core (per core)                                                                                    |\n| `tU8.0`                 | `VERSION`               | For SPR, it's 0. New feature versions will uprev this.                                                                      |\n| `tebb_energy`           | `FIVR_HBM_ENERGY`       | FIVR HBM Energy in uJ (per HBM)                                                                                             |\n| `tBOOL`                 | `OOB_PEM_ENABLE`        | 0x0 (Default)=Inband interface for PEM is enabled. 0x1=OOB interface for PEM is enabled.                                    |\n|                         | `ENABLE_PEM`            | 0 (Default): Disable PEM. 1: Enable PEM                                                                                     |\n|                         | `ANY`                   | Set if a core frequency excursion occurs due to a listed or unlisted reason                                                 |\n|                         | `THERMAL`               | Set if a core frequency excursion occurs due to any thermal event in core/uncore                                            |\n|                         | `EXT_PROCHOT`           | Set if a core frequency excursion occurs due to external PROCHOT assertion                                                  |\n|                         | `PBM`                   | Set if a core frequency excursion occurs due to a power limit (socket RAPL and/or platform RAPL)                            |\n|                         | `PL1`                   | Set if a core frequency excursion occurs due to PL1 input from any interfaces                                               |\n|                         | `PL2`                   | Set if a core frequency excursion occurs due to PL2 input from any interfaces                                               |\n|                         | `PMAX`                  | Set if a core frequency excursion occurs due to PMAX                                                                        |\n| `ttsc`                  | `ART`                   | TSC Delta HBM (per HBM)                                                                                                     |\n| `tproduct_id`           | `PRODUCT_ID`            | Product ID                                                                                                                  |\n| `tstring`               | `LOCAL_REVISION`        | Local Revision ID for this product                                                                                          |\n|                         | `RECORD_TYPE`           | Record Type                                                                                                                 |\n| `tcore_state`           | `EN`                    | Core x is enabled (per core)                                                                                                |\n| `thist_counter`         | `FREQ_HIST_R0`          | Frequency histogram range 0 (core in C6) counter (per core)                                                                 |\n|                         | `FREQ_HIST_R1`          | Frequency histogram range 1 (16.67-800 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R2`          | Frequency histogram range 2 (801-1200 MHz) counter (per core)                                                               |\n|                         | `FREQ_HIST_R3`          | Frequency histogram range 3 (1201-1600 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R4`          | Frequency histogram range 4 (1601-2000 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R5`          | Frequency histogram range 5 (2001-2400 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R6`          | Frequency histogram range 6 (2401-2800 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R7`          | Frequency histogram range 7 (2801-3200 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R8`          | Frequency histogram range 8 (3201-3600 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R9`          | Frequency histogram range 9 (3601-4000 MHz) counter (per core)                                                              |\n|                         | `FREQ_HIST_R10`         | Frequency histogram range 10 (4001-4400 MHz) counter (per core)                                                             |\n|                         | `FREQ_HIST_R11`         | Frequency histogram range 11 (greater then 4400 MHz) (per core)                                                             |\n|                         | `VOLT_HIST_R0`          | Voltage histogram range 0 (less then 602 mV) counter (per core)                                                             |\n|                         | `VOLT_HIST_R1`          | Voltage histogram range 1 (602.5-657 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R2`          | Voltage histogram range 2 (657.5-712 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R3`          | Voltage histogram range 3 (712.5-767 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R4`          | Voltage histogram range 4 (767.5-822 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R5`          | Voltage histogram range 5 (822.5-877 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R6`          | Voltage histogram range 6 (877.5-932 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R7`          | Voltage histogram range 7 (932.5-987 mV) counter (per core)                                                                 |\n|                         | `VOLT_HIST_R8`          | Voltage histogram range 8 (987.5-1042 mV) counter (per core)                                                                |\n|                         | `VOLT_HIST_R9`          | Voltage histogram range 9 (1042.5-1097 mV) counter (per core)                                                               |\n|                         | `VOLT_HIST_R10`         | Voltage histogram range 10 (1097.5-1152 mV) counter (per core)                                                              |\n|                         | `VOLT_HIST_R11`         | Voltage histogram range 11 (greater then 1152 mV) counter (per core)                                                        |\n|                         | `TEMP_HIST_R0`          | Temperature histogram range 0 (less then 20°C) counter                                                                      |\n|                         | `TEMP_HIST_R1`          | Temperature histogram range 1 (20.5-27.5°C) counter                                                                         |\n|                         | `TEMP_HIST_R2`          | Temperature histogram range 2 (28-35°C) counter                                                                             |\n|                         | `TEMP_HIST_R3`          | Temperature histogram range 3 (35.5-42.5°C) counter                                                                         |\n|                         | `TEMP_HIST_R4`          | Temperature histogram range 4 (43-50°C) counter                                                                             |\n|                         | `TEMP_HIST_R5`          | Temperature histogram range 5 (50.5-57.5°C) counter                                                                         |\n|                         | `TEMP_HIST_R6`          | Temperature histogram range 6 (58-65°C) counter                                                                             |\n|                         | `TEMP_HIST_R7`          | Temperature histogram range 7 (65.5-72.5°C) counter                                                                         |\n|                         | `TEMP_HIST_R8`          | Temperature histogram range 8 (73-80°C) counter                                                                             |\n|                         | `TEMP_HIST_R9`          | Temperature histogram range 9 (80.5-87.5°C) counter                                                                         |\n|                         | `TEMP_HIST_R10`         | Temperature histogram range 10 (88-95°C) counter                                                                            |\n|                         | `TEMP_HIST_R11`         | Temperature histogram range 11 (greater then 95°C) counter                                                                  |\n| `tpvp_throttle_counter` | `PVP_THROTTLE_64`       | Counter indicating the number of times the core x was throttled in the last 64 cycles window                                |\n|                         | `PVP_THROTTLE_1024`     | Counter indicating the number of times the core x was throttled in the last 1024 cycles window                              |\n| `tpvp_level_res`        | `PVP_LEVEL_RES_128_L0`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 0 of this type of CPU instruction |\n|                         | `PVP_LEVEL_RES_128_L1`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 1 of this type of CPU instruction |\n|                         | `PVP_LEVEL_RES_128_L2`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 2 of this type of CPU instruction |\n|                         | `PVP_LEVEL_RES_128_L3`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 3 of this type of CPU instruction |\n|                         | `PVP_LEVEL_RES_256_L0`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 0 of AVX256 CPU instructions      |\n|                         | `PVP_LEVEL_RES_256_L1`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 1 of AVX256 CPU instructions      |\n|                         | `PVP_LEVEL_RES_256_L2`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 2 of AVX256 CPU instructions      |\n|                         | `PVP_LEVEL_RES_256_L3`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 3 of AVX256 CPU instructions      |\n|                         | `PVP_LEVEL_RES_512_L0`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 0 of AVX512 CPU instructions      |\n|                         | `PVP_LEVEL_RES_512_L1`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 1 of AVX512 CPU instructions      |\n|                         | `PVP_LEVEL_RES_512_L2`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 2 of AVX512 CPU instructions      |\n|                         | `PVP_LEVEL_RES_512_L3`  | Counter indicating the percentage of residency during the last 2 ms measurement for level 3 of AVX512 CPU instructions      |\n|                         | `PVP_LEVEL_RES_TMUL_L0` | Counter indicating the percentage of residency during the last 2 ms measurement for level 0 of TMUL CPU instructions        |\n|                         | `PVP_LEVEL_RES_TMUL_L1` | Counter indicating the percentage of residency during the last 2 ms measurement for level 1 of TMUL CPU instructions        |\n|                         | `PVP_LEVEL_RES_TMUL_L2` | Counter indicating the percentage of residency during the last 2 ms measurement for level 2 of TMUL CPU instructions        |\n|                         | `PVP_LEVEL_RES_TMUL_L3` | Counter indicating the percentage of residency during the last 2 ms measurement for level 3 of TMUL CPU instructions        |\n| `ttsc_timer`            | `TSC_TIMER`             | OOBMSM TSC (Time Stamp Counter) value                                                                                       |\n| `tnum_en_cha`           | `NUM_EN_CHA`            | Number of enabled CHAs                                                                                                      |\n| `trmid_usage_counter`   | `RMID0_RDT_CMT`         | CHA x RMID 0 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID1_RDT_CMT`         | CHA x RMID 1 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID2_RDT_CMT`         | CHA x RMID 2 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID3_RDT_CMT`         | CHA x RMID 3 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID4_RDT_CMT`         | CHA x RMID 4 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID5_RDT_CMT`         | CHA x RMID 5 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID6_RDT_CMT`         | CHA x RMID 6 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID7_RDT_CMT`         | CHA x RMID 7 LLC cache line usage counter (per CHA)                                                                         |\n|                         | `RMID0_RDT_MBM_TOTAL`   | CHA x RMID 0 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID1_RDT_MBM_TOTAL`   | CHA x RMID 1 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID2_RDT_MBM_TOTAL`   | CHA x RMID 2 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID3_RDT_MBM_TOTAL`   | CHA x RMID 3 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID4_RDT_MBM_TOTAL`   | CHA x RMID 4 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID5_RDT_MBM_TOTAL`   | CHA x RMID 5 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID6_RDT_MBM_TOTAL`   | CHA x RMID 6 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID7_RDT_MBM_TOTAL`   | CHA x RMID 7 total memory transactions counter (per CHA)                                                                    |\n|                         | `RMID0_RDT_MBM_LOCAL`   | CHA x RMID 0 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID1_RDT_MBM_LOCAL`   | CHA x RMID 1 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID2_RDT_MBM_LOCAL`   | CHA x RMID 2 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID3_RDT_MBM_LOCAL`   | CHA x RMID 3 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID4_RDT_MBM_LOCAL`   | CHA x RMID 4 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID5_RDT_MBM_LOCAL`   | CHA x RMID 5 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID6_RDT_MBM_LOCAL`   | CHA x RMID 6 local memory transactions counter (per CHA)                                                                    |\n|                         | `RMID7_RDT_MBM_LOCAL`   | CHA x RMID 7 local memory transactions counter (per CHA)                                                                    |\n| `ttw_unit`              | `TW`                    | Time window. Valid TW range is 0 to 17. The unit is calculated as `2.3 * 2^TW` ms (e.g. `2.3 * 2^17` ms = ~302 seconds).    |\n| `tcore_stress_level`    | `STRESS_LEVEL`          | Accumulating counter indicating relative stress level for a core (per core)                                                 |\n\n### Example: C-State residency and temperature with a datatype metric filter\n\nThis configuration allows getting only a subset of metrics\nwith the use of a datatype filter:\n\n```toml\n[[inputs.intel_pmt]]\n  spec = \"/home/telegraf/Intel-PMT/xml/pmt.xml\"\n  datatypes_enabled = [\"tbandwidth_28b\",\"ttemperature\"]\n```\n\n### Example: C-State residency and temperature with a sample metric filter\n\nThis configuration allows getting only a subset of metrics\nwith the use of a sample filter:\n\n```toml\n[[inputs.intel_pmt]]\n  spec = \"/home/telegraf/Intel-PMT/xml/pmt.xml\"\n  samples_enabled = [\"C0Residency\",\"C1Residency\", \"Cx_TEMP\"]\n```\n\n## Metrics\n\nAll metrics have the following tags:\n\n- `guid` (unique id of an Intel PMT space).\n- `numa_node` (NUMA node the sample is collected from).\n- `pci_bdf` (PCI Bus:Device.Function (BDF) the sample is collected from).\n- `sample_name` (name of the gathered sample).\n- `sample_group` (name of a group to which the sample belongs).\n- `datatype_idref` (datatype to which the sample belongs).\n\n`sample_name` prefixed in XMLs with `Cx_` where `x`\nis the core number also have the following tag:\n\n- `core` (core to which the metric relates).\n\n`sample_name` prefixed in XMLs with `CHAx_` where `x`\nis the CHA number also have the following tag:\n\n- `cha` (Caching and Home Agent to which the metric relates).\n\n## Example Output\n\nExample output with `tpvp_throttle_counter` as a datatype metric filter:\n\n```text\nintel_pmt,core=0,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C0_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1886465i 1693766334000000000\nintel_pmt,core=1,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C1_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=2,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C2_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=3,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C3_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=4,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C4_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1357578i 1693766334000000000\nintel_pmt,core=5,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C5_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=6,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C6_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2024801i 1693766334000000000\nintel_pmt,core=7,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C7_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=8,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C8_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1390741i 1693766334000000000\nintel_pmt,core=9,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C9_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=10,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C10_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1536483i 1693766334000000000\nintel_pmt,core=11,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C11_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=12,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C12_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=13,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C13_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=14,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C14_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1604964i 1693766334000000000\nintel_pmt,core=15,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C15_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1168673i 1693766334000000000\nintel_pmt,core=16,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C16_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=17,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C17_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=18,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C18_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1276588i 1693766334000000000\nintel_pmt,core=19,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C19_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1139005i 1693766334000000000\nintel_pmt,core=20,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C20_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=21,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C21_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=22,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C22_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=970698i 1693766334000000000\nintel_pmt,core=23,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C23_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=24,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C24_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=25,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C25_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1178462i 1693766334000000000\nintel_pmt,core=26,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C26_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=27,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C27_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2093384i 1693766334000000000\nintel_pmt,core=28,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C28_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=29,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C29_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=30,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C30_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=31,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C31_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=32,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C32_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2825174i 1693766334000000000\nintel_pmt,core=33,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C33_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2592279i 1693766334000000000\nintel_pmt,core=34,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C34_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=35,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C35_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=36,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C36_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1960662i 1693766334000000000\nintel_pmt,core=37,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C37_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1821914i 1693766334000000000\nintel_pmt,core=38,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C38_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=39,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C39_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=40,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C40_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=41,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C41_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2654651i 1693766334000000000\nintel_pmt,core=42,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C42_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2230984i 1693766334000000000\nintel_pmt,core=43,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C43_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=44,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C44_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=45,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C45_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=46,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C46_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2325520i 1693766334000000000\nintel_pmt,core=47,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C47_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=48,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C48_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=49,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C49_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=50,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C50_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=51,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C51_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=52,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C52_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1468880i 1693766334000000000\nintel_pmt,core=53,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C53_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2151919i 1693766334000000000\nintel_pmt,core=54,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C54_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=55,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C55_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=2065994i 1693766334000000000\nintel_pmt,core=56,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C56_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=57,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C57_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=58,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C58_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1553691i 1693766334000000000\nintel_pmt,core=59,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C59_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=1624177i 1693766334000000000\nintel_pmt,core=60,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C60_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=61,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C61_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=62,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C62_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=63,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C63_PVP_THROTTLE_64,sample_name=PVP_THROTTLE_64 value=0i 1693766334000000000\nintel_pmt,core=0,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C0_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=12977949i 1693766334000000000\nintel_pmt,core=1,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C1_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=2,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C2_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=3,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C3_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=4,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C4_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=7180524i 1693766334000000000\nintel_pmt,core=5,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C5_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=6,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C6_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=8667263i 1693766334000000000\nintel_pmt,core=7,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C7_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=8,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C8_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=5945851i 1693766334000000000\nintel_pmt,core=9,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C9_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=10,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C10_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6669829i 1693766334000000000\nintel_pmt,core=11,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C11_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=12,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C12_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=13,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C13_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=14,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C14_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6579832i 1693766334000000000\nintel_pmt,core=15,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C15_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6101856i 1693766334000000000\nintel_pmt,core=16,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C16_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=17,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C17_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=18,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C18_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=7796183i 1693766334000000000\nintel_pmt,core=19,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C19_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6849098i 1693766334000000000\nintel_pmt,core=20,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C20_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=21,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C21_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=22,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C22_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=12378942i 1693766334000000000\nintel_pmt,core=23,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C23_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=24,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C24_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=25,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C25_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=8299231i 1693766334000000000\nintel_pmt,core=26,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C26_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=27,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C27_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=7986390i 1693766334000000000\nintel_pmt,core=28,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C28_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=29,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C29_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=30,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C30_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=31,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C31_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=32,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C32_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=9876325i 1693766334000000000\nintel_pmt,core=33,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C33_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=8547471i 1693766334000000000\nintel_pmt,core=34,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C34_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=35,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C35_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=36,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C36_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=9231744i 1693766334000000000\nintel_pmt,core=37,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C37_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=8133031i 1693766334000000000\nintel_pmt,core=38,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C38_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=39,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C39_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=40,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C40_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=41,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C41_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6136417i 1693766334000000000\nintel_pmt,core=42,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C42_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6091019i 1693766334000000000\nintel_pmt,core=43,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C43_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=44,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C44_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=45,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C45_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=46,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C46_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=5804639i 1693766334000000000\nintel_pmt,core=47,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C47_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=48,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C48_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=49,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C49_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=50,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C50_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=51,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C51_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=52,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C52_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=5738491i 1693766334000000000\nintel_pmt,core=53,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C53_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=6058504i 1693766334000000000\nintel_pmt,core=54,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C54_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=55,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C55_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=5987093i 1693766334000000000\nintel_pmt,core=56,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C56_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=57,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C57_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=58,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C58_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=10384909i 1693766334000000000\nintel_pmt,core=59,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C59_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=7305786i 1693766334000000000\nintel_pmt,core=60,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C60_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=61,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C61_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=62,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C62_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\nintel_pmt,core=63,datatype_idref=tpvp_throttle_counter,guid=0x87b6fef1,pmt,numa_node=0,pci_bdf=0000:e7:03.1,sample_group=C63_PVP_THROTTLE_1024,sample_name=PVP_THROTTLE_1024 value=0i 1693766334000000000\n```\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/filtering.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"slices\"\n)\n\nvar metricPatternRegex = regexp.MustCompile(`(?P<class>(C|CHA))\\d+_(?P<var>[A-Z0-9_]+)$`)\n\n// verifyNoEmpty checks if all pmt XMLs are not empty.\n//\n// Data for different GUIDs can be empty\n// but data for at least one GUID cannot be empty.\n//\n// Returns:\n//   - nil if at least one pair of XMLs for GUID is not empty.\n//   - an error if all XMLs are empty.\nfunc (p *IntelPMT) verifyNoEmpty() error {\n\temptyAggInterface := true\n\tfor guid := range p.pmtTelemetryFiles {\n\t\tif len(p.pmtAggregatorInterface[guid].AggregatorSamples.AggregatorSample) != 0 {\n\t\t\temptyAggInterface = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif emptyAggInterface {\n\t\treturn errors.New(\"all aggregator interface XMLs are empty\")\n\t}\n\temptyAgg := true\n\tfor guid := range p.pmtTelemetryFiles {\n\t\tif len(p.pmtAggregator[guid].SampleGroup) != 0 {\n\t\t\temptyAgg = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif emptyAgg {\n\t\treturn errors.New(\"all aggregator XMLs are empty\")\n\t}\n\treturn nil\n}\n\n// filterAggregatorByDatatype filters Aggregator XML by provided datatypes.\n//\n// Every sample group in aggregator XML consists of several samples.\n// Every sample in the group has a datatype assigned.\n// This function filters the samples based on their datatype.\n//\n// Parameters:\n//\n//\tdatatypes: string slice of datatypes to include in filtered XML.\nfunc (a *aggregator) filterAggregatorByDatatype(datatypes []string) {\n\tvar newSampleGroup []sampleGroup\n\tfor _, group := range a.SampleGroup {\n\t\tvar tmpAgg []sample\n\t\tfor _, aggSample := range group.Sample {\n\t\t\tif slices.Contains(datatypes, aggSample.DatatypeIDRef) {\n\t\t\t\ttmpAgg = append(tmpAgg, aggSample)\n\t\t\t}\n\t\t}\n\t\tif len(tmpAgg) > 0 {\n\t\t\t// groupSample can have samples with different datatypeIDRef inside\n\t\t\t// so new groupSample needs to be created\n\t\t\t// containing all needed information and filtered samples only.\n\t\t\tnewGroup := sampleGroup{}\n\t\t\tnewGroup.SampleID = group.SampleID\n\t\t\tnewGroup.Sample = tmpAgg\n\t\t\tnewSampleGroup = append(newSampleGroup, newGroup)\n\t\t}\n\t}\n\ta.SampleGroup = newSampleGroup\n}\n\n// filterAggregatorBySampleName filters Aggregator XML by provided sample names.\n//\n// Every sample has a name specified in the XML.\n// This function filters the samples based on their names.\n// The match can be exact or can be based on regex match.\n//\n// Parameters:\n//\n//\tsampleNames: string slice of sample names to include in filtered XML.\nfunc (a *aggregator) filterAggregatorBySampleName(sampleNames []string) {\n\tvar newSampleGroup []sampleGroup\n\tfor _, group := range a.SampleGroup {\n\t\tvar tmpAgg []sample\n\t\tfor _, aggSample := range group.Sample {\n\t\t\tif shouldAddSample(aggSample, sampleNames) {\n\t\t\t\ttmpAgg = append(tmpAgg, aggSample)\n\t\t\t}\n\t\t}\n\n\t\tif len(tmpAgg) > 0 {\n\t\t\tnewGroup := sampleGroup{}\n\t\t\tnewGroup.SampleID = group.SampleID\n\t\t\tnewGroup.Sample = tmpAgg\n\t\t\tnewSampleGroup = append(newSampleGroup, newGroup)\n\t\t}\n\t}\n\ta.SampleGroup = newSampleGroup\n}\n\n// shouldAddSample is a helper function for filterAggregatorBySampleName\n// that checks if the sample should  be added to the sample group.\nfunc shouldAddSample(s sample, sampleNames []string) bool {\n\tmatches := metricPatternRegex.FindStringSubmatch(s.SampleName)\n\tfor _, v := range sampleNames {\n\t\tif s.SampleName == v {\n\t\t\treturn true\n\t\t}\n\t\tif len(matches) == 4 {\n\t\t\tif matches[3] == v {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// filterAggInterfaceByDatatype filter aggregator interface XML by provided datatypes.\n//\n// Aggregator interface XML contains many aggregator samples inside, each with datatype assigned.\n// This function filters aggregator samples based on their datatype.\n//\n// Parameters:\n//\n//\tdatatypes: string slice of datatypes to include in filtered XML.\n//\tdtMetricsFound: a map of found datatypes for all GUIDs.\nfunc (a *aggregatorInterface) filterAggInterfaceByDatatype(datatypes []string, dtMetricsFound map[string]bool) {\n\tnewAggSample := aggregatorSamples{}\n\tfor _, s := range a.AggregatorSamples.AggregatorSample {\n\t\tif slices.Contains(datatypes, s.DatatypeIDRef) {\n\t\t\tdtMetricsFound[s.DatatypeIDRef] = true\n\t\t\tnewAggSample.AggregatorSample = append(newAggSample.AggregatorSample, s)\n\t\t}\n\t}\n\ta.AggregatorSamples = newAggSample\n}\n\n// filterAggInterfaceBySampleName filters aggregator interface XML by sample names.\n//\n// This function filters aggregator samples based on the provided sampleNames.\n// When the name for the sample is unique the match is exact.\n// When the name is per resource (i.e. Cx_) the match is regex based.\n//\n// Parameters:\n//\n//\tsampleNames: string slice of sample names to include in filtered XML.\n//\tsMetricsFound: a map of found metric names for all GUIDs.\nfunc (a *aggregatorInterface) filterAggInterfaceBySampleName(sampleNames []string, sMetricsFound map[string]bool) {\n\tnewAggSample := aggregatorSamples{}\n\tfor _, s := range a.AggregatorSamples.AggregatorSample {\n\t\tif shouldAddAggregatorSample(s, sampleNames, sMetricsFound) {\n\t\t\tnewAggSample.AggregatorSample = append(newAggSample.AggregatorSample, s)\n\t\t}\n\t}\n\ta.AggregatorSamples = newAggSample\n}\n\n// shouldAddAggregatorSample is a helper function for filterAggInterfaceBySampleName\n// that checks if if the sample should be added to the aggregator samples.\nfunc shouldAddAggregatorSample(s aggregatorSample, sampleNames []string, sMetricsFound map[string]bool) bool {\n\tmatches := metricPatternRegex.FindStringSubmatch(s.SampleName)\n\tfor _, userMetricInput := range sampleNames {\n\t\tif s.SampleName == userMetricInput {\n\t\t\tsMetricsFound[userMetricInput] = true\n\t\t\treturn true\n\t\t}\n\t\tif len(matches) == 4 {\n\t\t\tif matches[3] == userMetricInput {\n\t\t\t\tsMetricsFound[userMetricInput] = true\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/filtering_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFilterAggregatorByDatatype(t *testing.T) {\n\tt.Run(\"Filter aggregator, 1 sample group, 2 samples with different DataTypes\", func(t *testing.T) {\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"missing\",\n\t\t\t\t\t\t\tMsb:           0,\n\t\t\t\t\t\t\tLsb:           0,\n\t\t\t\t\t\t\tSampleID:      \"missing\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tp := IntelPMT{\n\t\t\tDatatypeFilter: []string{\"test-datatype\"},\n\t\t}\n\t\texpected := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorByDatatype(p.DatatypeFilter)\n\t\trequire.Equal(t, expected, agg)\n\t})\n\n\tt.Run(\"Filter Aggregator, 2 sample groups, only 1 sample group has expected datatype\", func(t *testing.T) {\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(2),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"missing\",\n\t\t\t\t\t\t\tMsb:           0,\n\t\t\t\t\t\t\tLsb:           0,\n\t\t\t\t\t\t\tSampleID:      \"missing\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tp := IntelPMT{\n\t\t\tDatatypeFilter: []string{\"test-datatype\"},\n\t\t}\n\t\texpected := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorByDatatype(p.DatatypeFilter)\n\t\trequire.Equal(t, expected, agg)\n\t})\n}\n\nfunc TestFilterAggregatorInterfaceByDatatype(t *testing.T) {\n\tt.Run(\"Filter agg interface, 2 Agg samples, only 1 should remain\", func(t *testing.T) {\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"missing\",\n\t\t\t\t\t\tSampleGroup:   \"missing\",\n\t\t\t\t\t\tDatatypeIDRef: \"missing\",\n\t\t\t\t\t\tTransformREF:  \"missing\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"missing\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"missing\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\texpected := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tp := IntelPMT{\n\t\t\tDatatypeFilter: []string{\"test-datatype\"},\n\t\t\tLog:            testutil.Logger{},\n\t\t}\n\t\taggInterface.filterAggInterfaceByDatatype(p.DatatypeFilter, make(map[string]bool))\n\t\trequire.Equal(t, expected, aggInterface)\n\t})\n}\n\nfunc TestFilterAggregatorBySampleName(t *testing.T) {\n\tt.Run(\"Filter aggregator, 2 sample names, with the same datatype, 1 sample name matches exactly\", func(t *testing.T) {\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"exists\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"missing\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           0,\n\t\t\t\t\t\t\tLsb:           0,\n\t\t\t\t\t\t\tSampleID:      \"missing\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tp := IntelPMT{\n\t\t\tSampleFilter: []string{\"exists\"},\n\t\t}\n\t\texpected := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"exists\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorBySampleName(p.SampleFilter)\n\t\trequire.Equal(t, expected, agg)\n\t})\n\n\tt.Run(\"Filter aggregator, 2 sample names, with the same datatype, 1 sample name matches by regex\", func(t *testing.T) {\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"C61_TEMP\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"C61_TEMP_test\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           0,\n\t\t\t\t\t\t\tLsb:           0,\n\t\t\t\t\t\t\tSampleID:      \"missing\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tp := IntelPMT{\n\t\t\tSampleFilter: []string{\"TEMP\"},\n\t\t}\n\t\texpected := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"C61_TEMP\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorBySampleName(p.SampleFilter)\n\t\trequire.Equal(t, expected, agg)\n\t})\n}\n\nfunc TestFilterAggregatorInterfaceBySampleName(t *testing.T) {\n\tt.Run(\"Filter agg interface, 2 Agg samples, 1 sample name matches exactly\", func(t *testing.T) {\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"C36_PVP_LEVEL_RES_128_L1\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"missing\",\n\t\t\t\t\t\tSampleGroup:   \"missing\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"missing\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"missing\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"missing\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\texpected := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"C36_PVP_LEVEL_RES_128_L1\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tp := IntelPMT{\n\t\t\tSampleFilter: []string{\"PVP_LEVEL_RES_128_L1\"},\n\t\t\tLog:          testutil.Logger{},\n\t\t}\n\t\taggInterface.filterAggInterfaceBySampleName(p.SampleFilter, make(map[string]bool))\n\t\trequire.Equal(t, expected, aggInterface)\n\t})\n\n\tt.Run(\"Filter agg interface, 2 Agg samples, 1 sample name matches by regex\", func(t *testing.T) {\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"missing\",\n\t\t\t\t\t\tSampleGroup:   \"missing\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"missing\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"missing\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"missing\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\texpected := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tp := IntelPMT{\n\t\t\tSampleFilter: []string{\"test-sample\"},\n\t\t\tLog:          testutil.Logger{},\n\t\t}\n\t\taggInterface.filterAggInterfaceBySampleName(p.SampleFilter, make(map[string]bool))\n\t\trequire.Equal(t, expected, aggInterface)\n\t})\n}\n\nfunc TestVerifyNoEmpty(t *testing.T) {\n\tt.Run(\"Correct XMLs, no filtering by user\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\"test-guid\": {\n\t\t\t\t\tSampleGroup: []sampleGroup{{}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {\n\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\tAggregatorSample: []aggregatorSample{{}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tp.pmtTelemetryFiles = map[string]pmtFileInfo{\n\t\t\t\"test-guid\": []fileInfo{{}},\n\t\t}\n\t\trequire.NoError(t, p.verifyNoEmpty())\n\t})\n\n\tt.Run(\"Incorrect XMLs, filtering by datatype that doesn't exist\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tDatatypeFilter:    []string{\"doesn't-exist\"},\n\t\t\tLog:               testutil.Logger{},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\"test-guid\": []fileInfo{{}}},\n\t\t}\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\taggInterface.filterAggInterfaceByDatatype(p.DatatypeFilter, make(map[string]bool))\n\t\tp.pmtAggregatorInterface[\"test-guid\"] = aggInterface\n\t\trequire.ErrorContains(t, p.verifyNoEmpty(), \"all aggregator interface XMLs are empty\")\n\t})\n\n\tt.Run(\"Incorrect XMLs, user provided sample names that don't exist\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tSampleFilter:      []string{\"doesn't-exist\"},\n\t\t\tLog:               testutil.Logger{},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\"test-guid\": []fileInfo{{}}},\n\t\t}\n\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\taggInterface.filterAggInterfaceBySampleName(p.SampleFilter, make(map[string]bool))\n\t\tp.pmtAggregatorInterface[\"test-guid\"] = aggInterface\n\t\trequire.ErrorContains(t, p.verifyNoEmpty(), \"XMLs are empty\")\n\t})\n\tt.Run(\"Correct XMLs, user provided correct sample names\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tSampleFilter:      []string{\"test-sample\"},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\"test-guid\": []fileInfo{{}}},\n\t\t}\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorBySampleName(p.SampleFilter)\n\t\taggInterface.filterAggInterfaceBySampleName(p.SampleFilter, make(map[string]bool))\n\t\tp.pmtAggregator[\"test-guid\"] = agg\n\t\tp.pmtAggregatorInterface[\"test-guid\"] = aggInterface\n\t\trequire.NoError(t, p.verifyNoEmpty())\n\t})\n\n\tt.Run(\"Correct XMLs, user provided correct datatype names\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tDatatypeFilter:    []string{\"test-datatype\"},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\"test-guid\": []fileInfo{{}}},\n\t\t}\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorByDatatype(p.DatatypeFilter)\n\t\taggInterface.filterAggInterfaceByDatatype(p.DatatypeFilter, make(map[string]bool))\n\t\tp.pmtAggregator[\"test-guid\"] = agg\n\t\tp.pmtAggregatorInterface[\"test-guid\"] = aggInterface\n\t\trequire.NoError(t, p.verifyNoEmpty())\n\t})\n\n\tt.Run(\"Incorrect XMLs, no datatype metrics found in aggregator sample XML\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\"test-guid\": {},\n\t\t\t},\n\t\t\tDatatypeFilter:    []string{\"test-datatype\"},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\"test-guid\": []fileInfo{{}}},\n\t\t}\n\t\tagg := aggregator{\n\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t{\n\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName: \"test-sample\",\n\t\t\t\t\t\t\t// DatatypeIDREF is wrong\n\t\t\t\t\t\t\tDatatypeIDRef: \"wrong\",\n\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\taggInterface := aggregatorInterface{\n\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t{\n\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tagg.filterAggregatorByDatatype(p.DatatypeFilter)\n\t\taggInterface.filterAggInterfaceByDatatype(p.DatatypeFilter, make(map[string]bool))\n\t\tp.pmtAggregator[\"test-guid\"] = agg\n\t\tp.pmtAggregatorInterface[\"test-guid\"] = aggInterface\n\t\trequire.ErrorContains(t, p.verifyNoEmpty(), \"all aggregator XMLs are empty\")\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/intel_pmt.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"html\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/PaesslerAG/gval\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar hexToDecRegex = regexp.MustCompile(`0x[0-9a-fA-F]+`)\n\nconst (\n\tdefaultPmtBasePath = \"/sys/class/intel_pmt\"\n\tpluginName         = \"intel_pmt\"\n)\n\ntype IntelPMT struct {\n\tPmtSpec        string          `toml:\"spec\"`\n\tDatatypeFilter []string        `toml:\"datatypes_enabled\"`\n\tSampleFilter   []string        `toml:\"samples_enabled\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tpmtBasePath            string\n\treader                 sourceReader\n\tpmtTelemetryFiles      map[string]pmtFileInfo\n\tpmtMetadata            *pmt\n\tpmtAggregator          map[string]aggregator\n\tpmtAggregatorInterface map[string]aggregatorInterface\n\tpmtTransformations     map[string]map[string]transformation\n}\n\ntype pmtFileInfo []fileInfo\n\ntype fileInfo struct {\n\tpath     string\n\tnumaNode string\n\tpciBdf   string // PCI Bus:Device.Function (BDF)\n}\n\nfunc (*IntelPMT) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *IntelPMT) Init() error {\n\terr := p.checkPmtSpec()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = p.explorePmtInSysfs()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error while exploring pmt sysfs: %w\", err)\n\t}\n\n\treturn p.parseXMLs()\n}\n\nfunc (p *IntelPMT) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tvar hasError atomic.Bool\n\tfor guid := range p.pmtTelemetryFiles {\n\t\twg.Add(1)\n\t\tgo func(guid string, fileInfo []fileInfo) {\n\t\t\tdefer wg.Done()\n\t\t\tfor _, info := range fileInfo {\n\t\t\t\tdata, err := os.ReadFile(info.path)\n\t\t\t\tif err != nil {\n\t\t\t\t\thasError.Store(true)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"gathering metrics failed: %w\", err))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\terr = p.aggregateSamples(acc, guid, data, info.numaNode, info.pciBdf)\n\t\t\t\tif err != nil {\n\t\t\t\t\thasError.Store(true)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"gathering metrics failed: %w\", err))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}(guid, p.pmtTelemetryFiles[guid])\n\t}\n\twg.Wait()\n\n\tif hasError.Load() {\n\t\treturn errors.New(\"error(s) occurred while gathering metrics\")\n\t}\n\treturn nil\n}\n\n// checkPmtSpec checks if provided PmtSpec is correct and readable.\n//\n// PmtSpec is expected to be an absolute filepath.\n//\n// Returns:\n//\n//\terror - error if PmtSpec is invalid, not readable, or not absolute.\nfunc (p *IntelPMT) checkPmtSpec() error {\n\tif p.PmtSpec == \"\" {\n\t\treturn errors.New(\"pmt spec is empty\")\n\t}\n\n\tif !isFileReadable(p.PmtSpec) {\n\t\treturn fmt.Errorf(\"provided pmt spec is not readable %q\", p.PmtSpec)\n\t}\n\n\tlastSlash := strings.LastIndex(p.PmtSpec, \"/\")\n\t// if PmtSpec contains no \"/\"\n\tif lastSlash == -1 {\n\t\treturn errors.New(\"provided pmt spec is not an absolute path\")\n\t}\n\tp.pmtBasePath = p.PmtSpec[:lastSlash]\n\tp.reader = fileReader{}\n\n\treturn nil\n}\n\n// explorePmtInSysfs finds necessary paths in pmt sysfs.\n//\n// This method finds \"telem\" files, used to retrieve telemetry values\n// and saves them under their corresponding GUID.\n// It also finds which NUMA node and PCI BDF the samples belong to.\n//\n// Returns:\n//\n//\terror - error if any of the operations failed.\nfunc (p *IntelPMT) explorePmtInSysfs() error {\n\tpmtDirectories, err := os.ReadDir(defaultPmtBasePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading pmt directory: %w\", err)\n\t}\n\tp.pmtTelemetryFiles = make(map[string]pmtFileInfo)\n\tfor _, dir := range pmtDirectories {\n\t\tif !strings.HasPrefix(dir.Name(), \"telem\") {\n\t\t\tcontinue\n\t\t}\n\t\ttelemDirPath := filepath.Join(defaultPmtBasePath, dir.Name())\n\t\tsymlinkInfo, err := os.Stat(telemDirPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error resolving symlink for directory %q: %w\", telemDirPath, err)\n\t\t}\n\t\tif !symlinkInfo.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tpmtGUIDPath := filepath.Join(telemDirPath, \"guid\")\n\t\trawGUID, err := os.ReadFile(pmtGUIDPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot read GUID: %w\", err)\n\t\t}\n\t\t// cut the newline char\n\t\ttID := strings.TrimSpace(string(rawGUID))\n\n\t\ttelemPath := filepath.Join(telemDirPath, \"telem\")\n\t\tif !isFileReadable(telemPath) {\n\t\t\tp.Log.Warnf(\"telem file is not readable %q\", telemPath)\n\t\t\tcontinue\n\t\t}\n\n\t\ttelemDevicePath := filepath.Join(telemDirPath, \"device\")\n\t\ttelemDeviceSymlink, err := filepath.EvalSymlinks(telemDevicePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while evaluating symlink %q: %w\", telemDeviceSymlink, err)\n\t\t}\n\n\t\ttelemDevicePciBdf := filepath.Base(filepath.Join(telemDeviceSymlink, \"..\"))\n\n\t\tnumaNodePath := filepath.Join(telemDeviceSymlink, \"..\", \"numa_node\")\n\n\t\tnumaNode, err := os.ReadFile(numaNodePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while reading numa_node file %q: %w\", numaNodePath, err)\n\t\t}\n\t\tnumaNodeString := strings.TrimSpace(string(numaNode))\n\t\tif numaNodeString == \"\" {\n\t\t\treturn fmt.Errorf(\"numa_node file %q is empty\", numaNodePath)\n\t\t}\n\n\t\tfi := fileInfo{\n\t\t\tpath:     telemPath,\n\t\t\tnumaNode: numaNodeString,\n\t\t\tpciBdf:   telemDevicePciBdf,\n\t\t}\n\t\tp.pmtTelemetryFiles[tID] = append(p.pmtTelemetryFiles[tID], fi)\n\t}\n\tif len(p.pmtTelemetryFiles) == 0 {\n\t\treturn errors.New(\"no telemetry sources found - current platform doesn't support PMT or proper permissions needed to read them\")\n\t}\n\treturn nil\n}\n\nfunc isFileReadable(path string) bool {\n\tif _, err := os.Stat(path); err != nil {\n\t\treturn false\n\t}\n\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\tfile.Close()\n\n\treturn true\n}\n\n// getSampleValues reads all sample values for all sample groups.\n//\n// This method reads all telemetry samples for given GUID from given data\n// and saves it in results map.\n//\n// Parameters:\n//\n//\tguid - GUID saying which Aggregator XML will be read.\n//\tdata - data read from \"telem\" file.\n//\n// Returns:\n//\n//\tmap[string]uint64 - results map with read data.\n//\terror - error if getting any of the values failed.\nfunc (p *IntelPMT) getSampleValues(guid string, data []byte) (map[string]uint64, error) {\n\tresults := make(map[string]uint64)\n\tfor _, group := range p.pmtAggregator[guid].SampleGroup {\n\t\t// Determine starting position of the Sample Group.\n\t\t// Each Sample Group occupies 8 bytes.\n\t\toffset := 8 * group.SampleID\n\t\tfor _, sample := range group.Sample {\n\t\t\tvar err error\n\t\t\tresults[sample.SampleID], err = getTelemSample(sample, data, offset)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\treturn results, nil\n}\n\n// getTelemSample extracts a telemetry sample from a given buffer.\n//\n// This function uses offset as a starting position.\n// Then it uses LSB and MSB from sample to determine which bits\n// to read from the given buffer.\n//\n// Parameters:\n//\n//\ts - sample from Aggregator XML containing LSB and MSB info.\n//\tbuf - the byte buffer containing the telemetry data.\n//\toffset - the starting position (in bytes) in the buffer.\n//\n// Returns:\n//\n//\tuint64 - the extracted sample as a 64-bit unsigned integer.\n//\terror - error if offset+8 exceeds the size of the buffer.\nfunc getTelemSample(s sample, buf []byte, offset uint64) (uint64, error) {\n\tif len(buf) < int(offset+8) {\n\t\treturn 0, fmt.Errorf(\"error reading telemetry sample: insufficient bytes from offset %d in buffer of size %d\", offset, len(buf))\n\t}\n\tdata := binary.LittleEndian.Uint64(buf[offset : offset+8])\n\n\t// Apply mask and shift right\n\tvalue := (data & s.mask) >> s.Lsb\n\treturn value, nil\n}\n\n// aggregateSamples outputs transformed metrics to Telegraf.\n//\n// This method transforms low level samples\n// into high-level samples with appropriate transformation equation.\n// Then it creates fields and tags and adds them to Telegraf Accumulator.\n//\n// Parameters:\n//\n// guid - GUID saying which Aggregator Interface will be read.\n// data - contents of the \"telem\" file.\n// numaNode - which NUMA node this sample belongs to.\n// pciBdf - PCI Bus:Device.Function (BDF) this sample belongs to.\n// acc - Telegraf Accumulator.\n//\n// Returns:\n//\n//\terror - error if getting values has failed, if sample IDref is missing or if equation evaluation has failed.\nfunc (p *IntelPMT) aggregateSamples(acc telegraf.Accumulator, guid string, data []byte, numaNode, pciBdf string) error {\n\tresults, err := p.getSampleValues(guid, data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, sample := range p.pmtAggregatorInterface[guid].AggregatorSamples.AggregatorSample {\n\t\tparameters := make(map[string]interface{})\n\t\tfor _, input := range sample.TransformInputs.TransformInput {\n\t\t\tif _, ok := results[input.SampleIDREF]; !ok {\n\t\t\t\treturn fmt.Errorf(\"sample with IDREF %q has not been found\", input.SampleIDREF)\n\t\t\t}\n\t\t\tparameters[input.VarName] = results[input.SampleIDREF]\n\t\t}\n\t\teq := transformEquation(p.pmtTransformations[guid][sample.TransformREF].Transform)\n\t\tres, err := eval(eq, parameters)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error during eval of sample %q: %w\", sample.SampleName, err)\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": res,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"guid\":           guid,\n\t\t\t\"numa_node\":      numaNode,\n\t\t\t\"pci_bdf\":        pciBdf,\n\t\t\t\"sample_name\":    sample.SampleName,\n\t\t\t\"sample_group\":   sample.SampleGroup,\n\t\t\t\"datatype_idref\": sample.DatatypeIDRef,\n\t\t}\n\t\tif sample.core != \"\" {\n\t\t\ttags[\"core\"] = sample.core\n\t\t}\n\t\tif sample.cha != \"\" {\n\t\t\ttags[\"cha\"] = sample.cha\n\t\t}\n\n\t\tacc.AddFields(pluginName, fields, tags)\n\t}\n\treturn nil\n}\n\n// transformEquation changes the equation string to be ready for eval.\n//\n// This function removes \"$\" signs, which prefixes every parameter in equations.\n// Then escapes special characters from XML\n// like \"&lt;\" into \"<\", \"&amp;\" into \"&\" and \"&gt;\" into \">\"\n// so they can be used in evaluation.\n//\n// Parameters:\n//\n//\teq - string which should be transformed.\n//\n// Returns:\n//\n//\tstring - transformed string.\nfunc transformEquation(eq string) string {\n\twithoutDollar := strings.ReplaceAll(eq, \"$\", \"\")\n\tdecoded := html.UnescapeString(withoutDollar)\n\treturn decoded\n}\n\n// eval calculates the value of given equation for given parameters.\n//\n// This function evaluates arbitrary equations with parameters.\n// It substitutes the parameters in the equation with their values\n// and calculates its value.\n// Example: equation \"a + b\", with params: a: 2, b: 3.\n// a and b will be substituted with their values so the equation becomes \"2 + 3\".\n// If any of the parameters are missing then the equation is invalid and returns an error.\n// Parameters:\n//\n//\teq - equation which should be calculated.\n//\tparams - parameters to substitute in the equation.\n//\n// Returns:\n//\n//\tinterface - the value of calculation.\n//\terror - error if the equation is empty, if hex to dec conversion failed or if the equation is invalid.\nfunc eval(eq string, params map[string]interface{}) (interface{}, error) {\n\tif eq == \"\" {\n\t\treturn nil, errors.New(\"no transformation equation found\")\n\t}\n\t// gval doesn't support hexadecimals\n\teq = hexToDecRegex.ReplaceAllStringFunc(eq, hexToDec)\n\tif eq == \"\" {\n\t\treturn nil, errors.New(\"error during hex to decimal conversion\")\n\t}\n\tresult, err := gval.Evaluate(eq, params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc hexToDec(hexStr string) string {\n\tdec, err := strconv.ParseInt(hexStr, 0, 64)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn strconv.FormatInt(dec, 10)\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\treturn &IntelPMT{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/intel_pmt_notamd64linux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux || !amd64\n\npackage intel_pmt\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IntelPMT struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*IntelPMT) SampleConfig() string { return sampleConfig }\n\nfunc (p *IntelPMT) Init() error {\n\tp.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*IntelPMT) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"intel_pmt\", func() telegraf.Input {\n\t\treturn &IntelPMT{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/intel_pmt_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t_ \"embed\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc createTempFile(t *testing.T, dir, pattern string, data []byte) (*os.File, os.FileInfo) {\n\ttempFile, err := os.CreateTemp(dir, pattern)\n\tif err != nil {\n\t\tt.Fatalf(\"error creating a temporary file %v: %v\", tempFile.Name(), err)\n\t}\n\t_, err = tempFile.Write(data)\n\tif err != nil {\n\t\tt.Fatalf(\"error writing buffer to file %v: %v\", tempFile.Name(), err)\n\t}\n\tfileInfo, err := tempFile.Stat()\n\tif err != nil {\n\t\tt.Fatalf(\"failed to stat a temporary file %v: %v\", tempFile.Name(), err)\n\t}\n\n\treturn tempFile, fileInfo\n}\n\nfunc TestTransformEquation(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"No changes\",\n\t\t\tinput:    \"abc\",\n\t\t\texpected: \"abc\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Remove $ sign\",\n\t\t\tinput:    \"a$b$c\",\n\t\t\texpected: \"abc\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Decode HTML entities\",\n\t\t\tinput:    \"a&amp;b\",\n\t\t\texpected: \"a&b\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Remove $ and decode HTML entities\",\n\t\t\tinput:    \"$a&amp;b$c\",\n\t\t\texpected: \"a&bc\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\toutput := transformEquation(tt.input)\n\t\t\trequire.Equal(t, tt.expected, output)\n\t\t})\n\t}\n}\n\nfunc TestEval(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\teq       string\n\t\tparams   map[string]interface{}\n\t\texpected interface{}\n\t\terr      bool\n\t}{\n\t\t{\n\t\t\tname:     \"empty equation\",\n\t\t\teq:       \"\",\n\t\t\tparams:   nil,\n\t\t\texpected: nil,\n\t\t\terr:      true,\n\t\t},\n\t\t{\n\t\t\tname:     \"Valid equation\",\n\t\t\teq:       \"2 + 2\",\n\t\t\tparams:   nil,\n\t\t\texpected: float64(4),\n\t\t\terr:      false,\n\t\t},\n\t\t{\n\t\t\tname: \"Valid equation with params, valid params\",\n\t\t\teq:   \"a + b\",\n\t\t\tparams: map[string]interface{}{\n\t\t\t\t\"a\": 2,\n\t\t\t\t\"b\": 3,\n\t\t\t},\n\t\t\texpected: float64(5),\n\t\t\terr:      false,\n\t\t},\n\t\t{\n\t\t\tname: \"Valid equation with params, invalid params\",\n\t\t\teq:   \"a + b\",\n\t\t\tparams: map[string]interface{}{\n\t\t\t\t\"a\": 2,\n\t\t\t\t// \"b\" is missing\n\t\t\t},\n\t\t\texpected: nil,\n\t\t\terr:      true,\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid equation\",\n\t\t\teq:       \"2 +\",\n\t\t\tparams:   nil,\n\t\t\texpected: nil,\n\t\t\terr:      true,\n\t\t},\n\t\t{\n\t\t\tname: \"Real equation from PMT - temperature of unused core\",\n\t\t\teq:   \"( ( parameter_0 >> 8 ) & 0xff ) + ( ( parameter_0 & 0xff ) / ( 2 ** 8 ) ) - 64\",\n\t\t\tparams: map[string]interface{}{\n\t\t\t\t\"parameter_0\": 0,\n\t\t\t},\n\t\t\texpected: float64(-64),\n\t\t\terr:      false,\n\t\t},\n\t\t{\n\t\t\tname: \"Real equation from PMT - temperature of working core\",\n\t\t\teq:   \"( ( parameter_0 >> 8 ) & 0xff ) + ( ( parameter_0 & 0xff ) / ( 2 ** 8 ) ) - 64\",\n\t\t\tparams: map[string]interface{}{\n\t\t\t\t\"parameter_0\": 23600,\n\t\t\t},\n\t\t\texpected: float64(28.1875),\n\t\t\terr:      false,\n\t\t},\n\t\t{\n\t\t\tname: \"Badly parsed real equation from PMT - temperature of working core\",\n\t\t\teq:   \"( ( parameter_0 &gt;&gt; 8 ) & 0xff ) + ( ( parameter_0 & 0xff ) / ( 2 ** 8 ) ) - 64\",\n\t\t\tparams: map[string]interface{}{\n\t\t\t\t\"parameter_0\": 23600,\n\t\t\t},\n\t\t\texpected: nil,\n\t\t\terr:      true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult, err := eval(tt.eq, tt.params)\n\t\t\tif tt.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tt.expected, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetTelemSample(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\ts        sample\n\t\tbuf      []byte\n\t\toffset   uint64\n\t\texpected uint64\n\t\terr      bool\n\t}{\n\t\t{\n\t\t\tname:     \"All bits set\",\n\t\t\ts:        sample{Msb: 7, Lsb: 0, mask: 255},\n\t\t\tbuf:      []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\toffset:   0,\n\t\t\texpected: 255,\n\t\t},\n\t\t{\n\t\t\tname:     \"Middle bits set\",\n\t\t\ts:        sample{Msb: 5, Lsb: 2, mask: 60},\n\t\t\tbuf:      []byte{0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3c = 00111100 in binary\n\t\t\toffset:   0,\n\t\t\texpected: 15,\n\t\t},\n\t\t{\n\t\t\tname:     \"Non-zero offset\",\n\t\t\ts:        sample{Msb: 7, Lsb: 0, mask: 255},\n\t\t\tbuf:      []byte{0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\toffset:   3,\n\t\t\texpected: 255,\n\t\t},\n\t\t{\n\t\t\tname:     \"Single bit set\",\n\t\t\ts:        sample{Msb: 4, Lsb: 4, mask: 16},\n\t\t\tbuf:      []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10 = 00010000 in binary\n\t\t\toffset:   0,\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname:     \"Two bytes set\",\n\t\t\ts:        sample{Msb: 14, Lsb: 0, mask: 32767},\n\t\t\tbuf:      []byte{0x30, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5c30 = 23600 in decimal\n\t\t\toffset:   0,\n\t\t\texpected: 23600,\n\t\t},\n\t\t{\n\t\t\tname:     \"Offset larger than buffer size\",\n\t\t\ts:        sample{Msb: 7, Lsb: 0, mask: 255},\n\t\t\tbuf:      []byte{0x00},\n\t\t\toffset:   5,\n\t\t\texpected: 0,\n\t\t\terr:      true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult, err := getTelemSample(tt.s, tt.buf, tt.offset)\n\t\t\tif tt.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tt.expected, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInit(t *testing.T) {\n\tt.Run(\"No PmtSpec\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tPmtSpec: \"\",\n\t\t}\n\t\terr := p.Init()\n\t\trequire.ErrorContains(t, err, \"pmt spec is empty\")\n\t})\n\n\tt.Run(\"Incorrect filepath PmtSpec\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tPmtSpec: \"/this/path/doesntexist\",\n\t\t}\n\t\terr := p.Init()\n\t\trequire.ErrorContains(t, err, \"provided pmt spec is not readable\")\n\t})\n\n\tt.Run(\"Incorrect PmtSpec, random letters\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tPmtSpec: \"loremipsum\",\n\t\t}\n\t\terr := p.Init()\n\t\trequire.ErrorContains(t, err, \"provided pmt spec is not readable\")\n\t})\n\n\tt.Run(\"Correct filepath PmtSpec, no pmt/can't read pmt in sysfs\", func(t *testing.T) {\n\t\ttmp := t.TempDir()\n\t\ttestFile, _ := createTempFile(t, tmp, \"test-file\", []byte(\"<pmt><mappings><mapping></mapping></mappings></pmt>\"))\n\t\tdefer testFile.Close()\n\n\t\tp := &IntelPMT{\n\t\t\tPmtSpec: testFile.Name(),\n\t\t\tLog:     testutil.Logger{},\n\t\t}\n\t\terr := p.Init()\n\t\trequire.ErrorContains(t, err, \"error while exploring pmt sysfs\")\n\t})\n}\n\nfunc TestGather(t *testing.T) {\n\ttype fields struct {\n\t\tPmtSpec                string\n\t\tLog                    telegraf.Logger\n\t\tpmtTelemetryFiles      map[string]pmtFileInfo\n\t\tpmtAggregator          map[string]aggregator\n\t\tpmtAggregatorInterface map[string]aggregatorInterface\n\t\tpmtTransformations     map[string]map[string]transformation\n\t}\n\ttype testFile struct {\n\t\tguid     string\n\t\tcontent  []byte\n\t\tnumaNode string\n\t\tpciBdf   string\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\tfields   fields\n\t\tfiles    []testFile\n\t\texpected []telegraf.Metric\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tname: \"Incorrect gather, results map has no value for sample\",\n\t\t\tfields: fields{\n\t\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\t\t\t\tmask:          16,\n\t\t\t\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tVarName: \"testvar\",\n\t\t\t\t\t\t\t\t\t\t\t\t// missing sampleIDREF\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfiles: []testFile{\n\t\t\t\t{guid: \"test-guid\", content: []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, numaNode: \"0\"},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Failed Gather, no equation for gathered sample\",\n\t\t\tfields: fields{\n\t\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t\t\t{SampleName: \"test-sample\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfiles: []testFile{\n\t\t\t\t{guid: \"test-guid\"},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Correct gather, 2 guids, 2 metrics returned\",\n\t\t\tfields: fields{\n\t\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\t\t\t\tmask:          16,\n\t\t\t\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"test-guid2\": {\n\t\t\t\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype2\",\n\t\t\t\t\t\t\t\t\t\tMsb:           14,\n\t\t\t\t\t\t\t\t\t\tLsb:           0,\n\t\t\t\t\t\t\t\t\t\tmask:          32767,\n\t\t\t\t\t\t\t\t\t\tSampleID:      \"test-sample-ref2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"test-guid2\": {\n\t\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tSampleName:    \"test-sample2\",\n\t\t\t\t\t\t\t\t\tSampleGroup:   \"test-group2\",\n\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype2\",\n\t\t\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref2\",\n\t\t\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tVarName:     \"testv\",\n\t\t\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref2\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpmtTransformations: map[string]map[string]transformation{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\t\"test-transform-ref\": {\n\t\t\t\t\t\t\tTransform: \"testvar + 2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"test-guid2\": {\n\t\t\t\t\t\t\"test-transform-ref2\": {\n\t\t\t\t\t\t\tTransform: \"( ( $testv &gt;&gt; 8 ) &amp; 0xff ) + ( ( $testv &amp; 0xff ) / ( 2 ** 8 ) ) - 64\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"intel_pmt\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"guid\":           \"test-guid\",\n\t\t\t\t\t\t\"numa_node\":      \"0\",\n\t\t\t\t\t\t\"pci_bdf\":        \"0000:00:0a.0\",\n\t\t\t\t\t\t\"sample_name\":    \"test-sample\",\n\t\t\t\t\t\t\"sample_group\":   \"test-group\",\n\t\t\t\t\t\t\"datatype_idref\": \"test-datatype\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t// 1 from buffer, 2 from equation\n\t\t\t\t\t\t\"value\": float64(3),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Time{},\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"intel_pmt\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"guid\":           \"test-guid2\",\n\t\t\t\t\t\t\"numa_node\":      \"1\",\n\t\t\t\t\t\t\"pci_bdf\":        \"0001:00:0a.0\",\n\t\t\t\t\t\t\"sample_name\":    \"test-sample2\",\n\t\t\t\t\t\t\"sample_group\":   \"test-group2\",\n\t\t\t\t\t\t\"datatype_idref\": \"test-datatype2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": float64(28.1875),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Time{},\n\t\t\t\t),\n\t\t\t},\n\t\t\tfiles: []testFile{\n\t\t\t\t{guid: \"test-guid\", content: []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, numaNode: \"0\", pciBdf: \"0000:00:0a.0\"},\n\t\t\t\t{guid: \"test-guid2\", content: []byte{0x30, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, numaNode: \"1\", pciBdf: \"0001:00:0a.0\"},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Correct gather, 1 value returned\",\n\t\t\tfields: fields{\n\t\t\t\tpmtAggregator: map[string]aggregator{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tSampleGroup: []sampleGroup{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSampleID: uint64(0),\n\t\t\t\t\t\t\t\tSample: []sample{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\t\tMsb:           4,\n\t\t\t\t\t\t\t\t\t\tLsb:           4,\n\t\t\t\t\t\t\t\t\t\tmask:          16,\n\t\t\t\t\t\t\t\t\t\tSampleID:      \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpmtAggregatorInterface: map[string]aggregatorInterface{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tSampleName:    \"test-sample\",\n\t\t\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpmtTransformations: map[string]map[string]transformation{\n\t\t\t\t\t\"test-guid\": {\n\t\t\t\t\t\t\"test-transform-ref\": {\n\t\t\t\t\t\t\tTransform: \"testvar + 2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"intel_pmt\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"guid\":           \"test-guid\",\n\t\t\t\t\t\t\"numa_node\":      \"0\",\n\t\t\t\t\t\t\"pci_bdf\":        \"0000:00:0a.0\",\n\t\t\t\t\t\t\"sample_name\":    \"test-sample\",\n\t\t\t\t\t\t\"sample_group\":   \"test-group\",\n\t\t\t\t\t\t\"datatype_idref\": \"test-datatype\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t// 1 from buffer, 2 from equation\n\t\t\t\t\t\t\"value\": float64(3),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Time{},\n\t\t\t\t),\n\t\t\t},\n\t\t\tfiles: []testFile{\n\t\t\t\t{guid: \"test-guid\", content: []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, numaNode: \"0\", pciBdf: \"0000:00:0a.0\"},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tp := &IntelPMT{\n\t\t\t\tPmtSpec:                tt.fields.PmtSpec,\n\t\t\t\tLog:                    testutil.Logger{},\n\t\t\t\tpmtAggregator:          tt.fields.pmtAggregator,\n\t\t\t\tpmtTelemetryFiles:      tt.fields.pmtTelemetryFiles,\n\t\t\t\tpmtAggregatorInterface: tt.fields.pmtAggregatorInterface,\n\t\t\t\tpmtTransformations:     tt.fields.pmtTransformations,\n\t\t\t}\n\t\t\tvar acc testutil.Accumulator\n\t\t\ttelemetryFiles := make(map[string]pmtFileInfo)\n\t\t\ttmp := t.TempDir()\n\t\t\tfor _, file := range tt.files {\n\t\t\t\ttestFile, _ := createTempFile(t, tmp, \"test-file\", file.content)\n\t\t\t\ttelemetryFiles[file.guid] = append(telemetryFiles[file.guid], fileInfo{\n\t\t\t\t\tpath:     testFile.Name(),\n\t\t\t\t\tnumaNode: file.numaNode,\n\t\t\t\t\tpciBdf:   file.pciBdf,\n\t\t\t\t})\n\t\t\t}\n\t\t\tp.pmtTelemetryFiles = telemetryFiles\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, acc.GatherError(p.Gather))\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, acc.GatherError(p.Gather))\n\t\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/sample.conf",
    "content": "# Intel Platform Monitoring Technology plugin exposes Intel PMT metrics available through the Intel PMT kernel space.\n# This plugin ONLY supports Linux.\n[[inputs.intel_pmt]]\n  ## Filepath to PMT XML within local copies of XML files from PMT repository.\n  ## The filepath should be absolute.\n  spec = \"/home/telegraf/Intel-PMT/xml/pmt.xml\"\n  \n  ## Enable metrics by their datatype.\n  ## See the Enabling Metrics section in README for more details.\n  ## If empty, all metrics are enabled.\n  ## When used, the alternative option samples_enabled should NOT be used.\n  # datatypes_enabled = []\n  \n  ## Enable metrics by their name.\n  ## See the Enabling Metrics section in README for more details.\n  ## If empty, all metrics are enabled.\n  ## When used, the alternative option datatypes_enabled should NOT be used.\n  # samples_enabled = []\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/tags_extraction.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport \"regexp\"\n\nvar (\n\t// core in sample name - like C5_\n\tcoreRegex = regexp.MustCompile(\"^C([0-9]+)_\")\n\t// CHA in sample name - like CHA43_\n\tchaRegex = regexp.MustCompile(\"^CHA([0-9]+)_\")\n)\n\nfunc (a *aggregatorInterface) extractTagsFromSample() {\n\tnewAggSample := aggregatorSamples{}\n\tfor _, sample := range a.AggregatorSamples.AggregatorSample {\n\t\tmatches := coreRegex.FindStringSubmatch(sample.SampleName)\n\t\tif len(matches) == 2 {\n\t\t\t// matches[0] is the exact match in the code\n\t\t\t// matches[1] is the captured number (in parentheses)\n\t\t\tsample.core = matches[1]\n\t\t\tsample.SampleName = coreRegex.ReplaceAllString(sample.SampleName, \"\")\n\t\t\tnewAggSample.AggregatorSample = append(newAggSample.AggregatorSample, sample)\n\t\t\tcontinue\n\t\t}\n\t\tmatches = chaRegex.FindStringSubmatch(sample.SampleName)\n\t\tif len(matches) == 2 {\n\t\t\tsample.cha = matches[1]\n\t\t\tsample.SampleName = chaRegex.ReplaceAllString(sample.SampleName, \"\")\n\t\t}\n\t\tnewAggSample.AggregatorSample = append(newAggSample.AggregatorSample, sample)\n\t}\n\ta.AggregatorSamples = newAggSample\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/tags_extraction_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExtractTagsFromSample(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    aggregatorInterface\n\t\texpected aggregatorInterface\n\t}{\n\t\t{\n\t\t\tname: \"Extract core number from sampleName\",\n\t\t\tinput: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"C34_test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tcore:          \"34\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Extract cha number from sample\",\n\t\t\tinput: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"CHA34_test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tcha:           \"34\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"SampleName doesn't contain any matched patterns, no change in sample\",\n\t\t\tinput: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: aggregatorInterface{\n\t\t\t\tAggregatorSamples: aggregatorSamples{\n\t\t\t\t\tAggregatorSample: []aggregatorSample{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSampleName:    \"test\",\n\t\t\t\t\t\t\tSampleGroup:   \"test-group\",\n\t\t\t\t\t\t\tDatatypeIDRef: \"test-datatype\",\n\t\t\t\t\t\t\tTransformREF:  \"test-transform-ref\",\n\t\t\t\t\t\t\tTransformInputs: transformInputs{\n\t\t\t\t\t\t\t\tTransformInput: []transformInput{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVarName:     \"testvar\",\n\t\t\t\t\t\t\t\t\t\tSampleIDREF: \"test-sample-ref\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.input.extractTagsFromSample()\n\t\t\trequire.Equal(t, tt.expected, tt.input)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/xml_parser.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\ntype pmt struct {\n\tXMLName  xml.Name `xml:\"pmt\"`\n\tMappings mappings `xml:\"mappings\"`\n}\ntype mappings struct {\n\tXMLName xml.Name  `xml:\"mappings\"`\n\tMapping []mapping `xml:\"mapping\"`\n}\n\ntype mapping struct {\n\tXMLName xml.Name `xml:\"mapping\"`\n\tGUID    string   `xml:\"guid,attr\"`\n\tXMLSet  xmlset   `xml:\"xmlset\"`\n}\n\ntype xmlset struct {\n\tXMLName             xml.Name `xml:\"xmlset\"`\n\tBasedir             string   `xml:\"basedir\"`\n\tAggregator          string   `xml:\"aggregator\"`\n\tAggregatorInterface string   `xml:\"aggregatorinterface\"`\n}\n\ntype aggregator struct {\n\tXMLName     xml.Name      `xml:\"Aggregator\"`\n\tName        string        `xml:\"name\"`\n\tSampleGroup []sampleGroup `xml:\"SampleGroup\"`\n}\n\ntype sampleGroup struct {\n\tXMLName  xml.Name `xml:\"SampleGroup\"`\n\tSampleID uint64   `xml:\"sampleID,attr\"`\n\tSample   []sample `xml:\"sample\"`\n}\n\ntype sample struct {\n\tXMLName       xml.Name `xml:\"sample\"`\n\tSampleName    string   `xml:\"name,attr\"`\n\tDatatypeIDRef string   `xml:\"datatypeIDREF,attr\"`\n\tSampleID      string   `xml:\"sampleID,attr\"`\n\tLsb           uint64   `xml:\"lsb\"`\n\tMsb           uint64   `xml:\"msb\"`\n\n\tmask uint64\n}\n\ntype aggregatorInterface struct {\n\tXMLName           xml.Name          `xml:\"AggregatorInterface\"`\n\tTransformations   transformations   `xml:\"TransFormations\"`\n\tAggregatorSamples aggregatorSamples `xml:\"AggregatorSamples\"`\n}\n\ntype transformations struct {\n\tXMLName        xml.Name         `xml:\"TransFormations\"`\n\tTransformation []transformation `xml:\"TransFormation\"`\n}\n\ntype transformation struct {\n\tXMLName     xml.Name `xml:\"TransFormation\"`\n\tName        string   `xml:\"name,attr\"`\n\tTransformID string   `xml:\"transformID,attr\"`\n\tTransform   string   `xml:\"transform\"`\n}\n\ntype aggregatorSamples struct {\n\tXMLName          xml.Name           `xml:\"AggregatorSamples\"`\n\tAggregatorSample []aggregatorSample `xml:\"T_AggregatorSample\"`\n}\n\ntype aggregatorSample struct {\n\tXMLName         xml.Name        `xml:\"T_AggregatorSample\"`\n\tSampleName      string          `xml:\"sampleName,attr\"`\n\tSampleGroup     string          `xml:\"sampleGroup,attr\"`\n\tDatatypeIDRef   string          `xml:\"datatypeIDREF,attr\"`\n\tTransformInputs transformInputs `xml:\"TransFormInputs\"`\n\tTransformREF    string          `xml:\"transformREF\"`\n\n\tcore string\n\tcha  string\n}\n\ntype transformInputs struct {\n\tXMLName        xml.Name         `xml:\"TransFormInputs\"`\n\tTransformInput []transformInput `xml:\"TransFormInput\"`\n}\n\ntype transformInput struct {\n\tXMLName     xml.Name `xml:\"TransFormInput\"`\n\tVarName     string   `xml:\"varName,attr\"`\n\tSampleIDREF string   `xml:\"sampleIDREF\"`\n}\n\ntype sourceReader interface {\n\tgetReadCloser(source string) (io.ReadCloser, error)\n}\n\ntype fileReader struct{}\n\nfunc (fileReader) getReadCloser(source string) (io.ReadCloser, error) {\n\treturn os.Open(source)\n}\n\n// parseXMLs reads and parses PMT XMLs.\n//\n// This method retrieves all metadata about known GUIDs from PmtSpec.\n// Then, it explores PMT sysfs to find all readable \"telem\" files and their GUIDs.\n// It then matches found (readable) system GUIDs with GUIDs from metadata and\n// reads corresponding sets of XMLs.\n//\n// Returns:\n//\n//\terror - if PMT spec is empty, if exploring PMT sysfs fails, or if reading XMLs fails.\nfunc (p *IntelPMT) parseXMLs() error {\n\terr := parseXML(p.PmtSpec, p.reader, &p.pmtMetadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(p.pmtMetadata.Mappings.Mapping) == 0 {\n\t\treturn errors.New(\"pmt XML provided contains no mappings\")\n\t}\n\n\terr = p.readXMLs()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.pmtTransformations = make(map[string]map[string]transformation)\n\tfor guid := range p.pmtTelemetryFiles {\n\t\tp.pmtTransformations[guid] = make(map[string]transformation)\n\t\tfor _, transform := range p.pmtAggregatorInterface[guid].Transformations.Transformation {\n\t\t\tp.pmtTransformations[guid][transform.TransformID] = transform\n\t\t}\n\t}\n\treturn nil\n}\n\n// readXMLs function reads all XMLs for found GUIDs.\n//\n// This method reads two required XMLs for each found GUID,\n// checks if any of the provided filtering metrics were not found,\n// and checks if there is at least one non-empty XML set.\n//\n// Returns:\n//\n//\terror - error if reading operation failed or if all XMLs are empty.\nfunc (p *IntelPMT) readXMLs() error {\n\tp.pmtAggregator = make(map[string]aggregator)\n\tp.pmtAggregatorInterface = make(map[string]aggregatorInterface)\n\tdtMetricsFound := make(map[string]bool)\n\tsampleFilterFound := make(map[string]bool)\n\tfor guid := range p.pmtTelemetryFiles {\n\t\terr := p.getAllXMLData(guid, dtMetricsFound, sampleFilterFound)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed reading XMLs: %w\", err)\n\t\t}\n\t}\n\tfor _, dt := range p.DatatypeFilter {\n\t\tif _, ok := dtMetricsFound[dt]; !ok {\n\t\t\tp.Log.Warnf(\"Configured datatype metric %q has not been found\", dt)\n\t\t}\n\t}\n\tfor _, sm := range p.SampleFilter {\n\t\tif _, ok := sampleFilterFound[sm]; !ok {\n\t\t\tp.Log.Warnf(\"Configured sample metric %q has not been found\", sm)\n\t\t}\n\t}\n\n\treturn p.verifyNoEmpty()\n}\n\n// getAllXMLData retrieves two XMLs for given GUID.\n//\n// This method reads where to find the Aggregator and Aggregator interface XMLs\n// from pmt metadata and reads found XMLs.\n// This method also filters read XMLs before saving them\n// and extracts additional tags from the data.\n//\n// Parameters:\n//\n//\tguid - GUID saying which XMLs should be read.\n//\tdtMetricsFound - a map of found datatype metrics for all GUIDs.\n//\tsmFound - a map of found sample names for all GUIDs.\n//\n// Returns:\n//\n//\terror - if reading XML has failed.\nfunc (p *IntelPMT) getAllXMLData(guid string, dtMetricsFound, smFound map[string]bool) error {\n\tfor _, mapping := range p.pmtMetadata.Mappings.Mapping {\n\t\tif mapping.GUID == guid {\n\t\t\tbasedir := mapping.XMLSet.Basedir\n\t\t\tguid := mapping.GUID\n\t\t\tvar aggSource, aggInterfaceSource string\n\n\t\t\taggSource = filepath.Join(p.pmtBasePath, basedir, mapping.XMLSet.Aggregator)\n\t\t\taggInterfaceSource = filepath.Join(p.pmtBasePath, basedir, mapping.XMLSet.AggregatorInterface)\n\n\t\t\ttAgg := aggregator{}\n\t\t\ttAggInterface := aggregatorInterface{}\n\n\t\t\terr := parseXML(aggSource, p.reader, &tAgg)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed reading aggregator XML: %w\", err)\n\t\t\t}\n\t\t\terr = parseXML(aggInterfaceSource, p.reader, &tAggInterface)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed reading aggregator interface XML: %w\", err)\n\t\t\t}\n\t\t\tif len(p.DatatypeFilter) > 0 {\n\t\t\t\ttAgg.filterAggregatorByDatatype(p.DatatypeFilter)\n\t\t\t\ttAggInterface.filterAggInterfaceByDatatype(p.DatatypeFilter, dtMetricsFound)\n\t\t\t}\n\t\t\tif len(p.SampleFilter) > 0 {\n\t\t\t\ttAgg.filterAggregatorBySampleName(p.SampleFilter)\n\t\t\t\ttAggInterface.filterAggInterfaceBySampleName(p.SampleFilter, smFound)\n\t\t\t}\n\t\t\ttAgg.calculateMasks()\n\t\t\tp.pmtAggregator[guid] = tAgg\n\t\t\ttAggInterface.extractTagsFromSample()\n\t\t\tp.pmtAggregatorInterface[guid] = tAggInterface\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (a *aggregator) calculateMasks() {\n\tfor i := range a.SampleGroup {\n\t\tfor j, sample := range a.SampleGroup[i].Sample {\n\t\t\tmask := computeMask(sample.Msb, sample.Lsb)\n\t\t\ta.SampleGroup[i].Sample[j].mask = mask\n\t\t}\n\t}\n}\n\nfunc computeMask(msb, lsb uint64) uint64 {\n\tmsbMask := uint64(0xffffffffffffffff) & ((1 << (msb + 1)) - 1)\n\tlsbMask := uint64(0xffffffffffffffff) & (1<<lsb - 1)\n\treturn msbMask & (^lsbMask)\n}\n\nfunc parseXML(source string, sr sourceReader, v interface{}) error {\n\tif sr == nil {\n\t\treturn errors.New(\"xml reader has not been initialized\")\n\t}\n\treader, err := sr.getReadCloser(source)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading source %q: %w\", source, err)\n\t}\n\tdefer reader.Close()\n\n\tparser := xml.NewDecoder(reader)\n\tparser.AutoClose = xml.HTMLAutoClose\n\tparser.Entity = xml.HTMLEntity\n\t// There are \"&\" in XMLs in entity references.\n\t// Parser sees it as not allowed characters.\n\t// Strict mode disabled to handle that.\n\tparser.Strict = false\n\terr = parser.Decode(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error decoding an XML %q: %w\", source, err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmt/xml_parser_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmt\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype mockReader struct {\n\tdata []byte\n\terr  error\n}\n\nfunc (mr mockReader) getReadCloser(_ string) (io.ReadCloser, error) {\n\tif mr.err != nil {\n\t\treturn nil, mr.err\n\t}\n\treturn io.NopCloser(bytes.NewReader(mr.data)), nil\n}\n\nfunc TestParseXMLs(t *testing.T) {\n\tt.Run(\"Correct filepath PmtSpec, empty spec\", func(t *testing.T) {\n\t\ttestFile, err := os.CreateTemp(t.TempDir(), \"test-file\")\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"error creating a temporary file: %v %v\", testFile.Name(), err)\n\t\t}\n\t\tdefer testFile.Close()\n\n\t\tp := &IntelPMT{\n\t\t\tPmtSpec: testFile.Name(),\n\t\t\treader:  fileReader{},\n\t\t}\n\t\terr = p.parseXMLs()\n\t\trequire.ErrorContains(t, err, \"error decoding an XML\")\n\t})\n}\n\nfunc TestParseXML(t *testing.T) {\n\ttype Person struct {\n\t\tName string `xml:\"name\"`\n\t\tAge  int    `xml:\"age\"`\n\t}\n\n\ttests := []struct {\n\t\tname   string\n\t\tsource string\n\t\tsr     sourceReader\n\t\tv      interface{}\n\t\terr    bool\n\t}{\n\t\t{\n\t\t\tname:   \"Valid XML\",\n\t\t\tsource: \"test\",\n\t\t\tsr:     mockReader{data: []byte(`<Person><name>John</name><age>30</age></Person>`), err: nil},\n\t\t\tv:      &Person{},\n\t\t\terr:    false,\n\t\t},\n\t\t{\n\t\t\tname:   \"Empty XML\",\n\t\t\tsource: \"test\",\n\t\t\tsr:     mockReader{data: []byte(``), err: nil},\n\t\t\tv:      &Person{},\n\t\t\terr:    true,\n\t\t},\n\t\t{\n\t\t\tname:   \"Nil interface parameter\",\n\t\t\tsource: \"test\",\n\t\t\tsr:     mockReader{data: []byte(`<Person><name>John</name><age>30</age></Person>`), err: nil},\n\t\t\tv:      nil,\n\t\t\terr:    true,\n\t\t},\n\t\t{\n\t\t\tname:   \"Error from SourceReader\",\n\t\t\tsource: \"test\",\n\t\t\tsr:     mockReader{data: nil, err: errors.New(\"mock error\")},\n\t\t\tv:      &Person{},\n\t\t\terr:    true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := parseXML(tt.source, tt.sr, tt.v)\n\t\t\tif tt.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestReadXMLs(t *testing.T) {\n\tt.Run(\"Test single PMT GUID, no XMLs found\", func(t *testing.T) {\n\t\tp := &IntelPMT{\n\t\t\tpmtMetadata: &pmt{\n\t\t\t\tMappings: mappings{\n\t\t\t\t\tMapping: []mapping{\n\t\t\t\t\t\t{GUID: \"abc\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\n\t\t\t\t\"abc\": []fileInfo{{path: \"doesn't-exist\"}},\n\t\t\t},\n\t\t\treader: fileReader{},\n\t\t}\n\t\terr := p.readXMLs()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"failed reading XMLs\")\n\t})\n\n\tt.Run(\"Test single PMT GUID, aggregator interface empty\", func(t *testing.T) {\n\t\ttmp := t.TempDir()\n\n\t\tbufAgg := []byte(\"<TELEM:Aggregator><TELEM:SampleGroup></TELEM:SampleGroup></TELEM:Aggregator>\")\n\t\ttestAgg, aggName := createTempFile(t, tmp, \"test-agg\", bufAgg)\n\t\tdefer testAgg.Close()\n\n\t\tbufAggInterface := []byte(\"<TELI:AggregatorInterface></TELI:AggregatorInterface>\")\n\t\ttestAggInterface, aggInterfaceName := createTempFile(t, tmp, \"test-aggInterface\", bufAggInterface)\n\t\tdefer testAggInterface.Close()\n\n\t\tp := &IntelPMT{\n\t\t\tpmtBasePath: tmp,\n\t\t\tpmtMetadata: &pmt{\n\t\t\t\tMappings: mappings{\n\t\t\t\t\tMapping: []mapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tGUID: \"abc\",\n\t\t\t\t\t\t\tXMLSet: xmlset{\n\t\t\t\t\t\t\t\tAggregator:          aggName.Name(),\n\t\t\t\t\t\t\t\tAggregatorInterface: aggInterfaceName.Name(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// This is done just so we enter the loop\n\t\t\tpmtTelemetryFiles: map[string]pmtFileInfo{\n\t\t\t\t\"abc\": []fileInfo{{path: testAgg.Name()}},\n\t\t\t},\n\t\t\treader: fileReader{},\n\t\t}\n\n\t\terr := p.readXMLs()\n\t\trequire.ErrorContains(t, err, \"all aggregator interface XMLs are empty\")\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/README.md",
    "content": "# Intel Performance Monitoring Unit Plugin\n\nThis plugin gathers Intel Performance Monitoring Unit metrics available via the\n[Linux Perf][linux_perf] subsystem.\n\nPMU metrics provide insights into performance and health of IA processors'\ninternal components, including core and uncore units. With the number of cores\nincreasing and processor topology getting more complex the insight into those\nmetrics is vital to assure the best CPU performance and utilization.\n\nPerformance counters are CPU hardware registers that count hardware events such\nas instructions executed, cache-misses suffered, or branches mispredicted. They\nform a basis for profiling applications to trace dynamic control flow and\nidentify hotspots.\n\n⭐ Telegraf v1.21.0\n🏷️ hardware, system\n💻 linux\n\n[linux_perf]: https://perf.wiki.kernel.org/index.php/Main_Page\n\n## Requirements\n\nThe plugin uses the [iaevents library][iaevents_lib] that eases accessing the\nLinux kernel's perf interface.\n\n> [!IMPORTANT]\n> The Intel PMU plugin is only intended for use on **Linux 64-bit** systems.\n\nEvent definition JSON files for specific architectures can be found at the\n[Github repository][repo]. Download the event definitions appropriate for your\nsystem e.g. using the [`event_download.py` PMU tool][pmu_tools] and keep them\nin a safe place on your system.\n\n[iaevents_lib]: https://github.com/intel/iaevents\n[repo]: https://github.com/intel/perfmon\n[pmu_tools]: https://github.com/andikleen/pmu-tools\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Intel Performance Monitoring Unit plugin exposes Intel PMU metrics available through Linux Perf subsystem\n# This plugin ONLY supports Linux on amd64\n[[inputs.intel_pmu]]\n  ## List of filesystem locations of JSON files that contain PMU event definitions.\n  event_definitions = [\"/var/cache/pmu/GenuineIntel-6-55-4-core.json\", \"/var/cache/pmu/GenuineIntel-6-55-4-uncore.json\"]\n\n  ## List of core events measurement entities. There can be more than one core_events sections.\n  [[inputs.intel_pmu.core_events]]\n    ## List of events to be counted. Event names shall match names from event_definitions files.\n    ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers.\n    ## If absent, all core events from provided event_definitions are counted skipping unresolvable ones.\n    events = [\"INST_RETIRED.ANY\", \"CPU_CLK_UNHALTED.THREAD_ANY:config1=0x4043200000000k\"]\n\n    ## Limits the counting of events to core numbers specified.\n    ## If absent, events are counted on all cores.\n    ## Single \"0\", multiple \"0,1,2\" and range \"0-2\" notation is supported for each array element.\n    ##   example: cores = [\"0,2\", \"4\", \"12-16\"]\n    cores = [\"0\"]\n\n    ## Indicator that plugin shall attempt to run core_events.events as a single perf group.\n    ## If absent or set to false, each event is counted individually. Defaults to false.\n    ## This limits the number of events that can be measured to a maximum of available hardware counters per core.\n    ## Could vary depending on type of event, use of fixed counters.\n    # perf_group = false\n\n    ## Optionally set a custom tag value that will be added to every measurement within this events group.\n    ## Can be applied to any group of events, unrelated to perf_group setting.\n    # events_tag = \"\"\n\n  ## List of uncore event measurement entities. There can be more than one uncore_events sections.\n  [[inputs.intel_pmu.uncore_events]]\n    ## List of events to be counted. Event names shall match names from event_definitions files.\n    ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers.\n    ## If absent, all uncore events from provided event_definitions are counted skipping unresolvable ones.\n    events = [\"UNC_CHA_CLOCKTICKS\", \"UNC_CHA_TOR_OCCUPANCY.IA_MISS\"]\n\n    ## Limits the counting of events to specified sockets.\n    ## If absent, events are counted on all sockets.\n    ## Single \"0\", multiple \"0,1\" and range \"0-1\" notation is supported for each array element.\n    ##   example: sockets = [\"0-2\"]\n    sockets = [\"0\"]\n\n    ## Indicator that plugin shall provide an aggregated value for multiple units of same type distributed in an uncore.\n    ## If absent or set to false, events for each unit are exposed as separate metric. Defaults to false.\n    # aggregate_uncore_units = false\n\n    ## Optionally set a custom tag value that will be added to every measurement within this events group.\n    # events_tag = \"\"\n```\n\n### Modifiers\n\nPerf modifiers adjust event-specific perf attribute to fulfill particular\nrequirements.  Details about perf attribute structure could be found in\n[perf_event_open][man]\nsyscall manual.\n\nGeneral schema of configuration's `events` list element:\n\n```regexp\nEVENT_NAME(:(config|config1|config2)=(0x[0-9a-f]{1-16})(p|k|u|h|H|I|G|D))*\n```\n\nwhere:\n\n| Modifier | Underlying attribute            | Description                 |\n|----------|---------------------------------|-----------------------------|\n| config   | perf_event_attr.config          | type-specific configuration |\n| config1  | perf_event_attr.config1         | extension of config         |\n| config2  | perf_event_attr.config2         | extension of config1        |\n| p        | perf_event_attr.precise_ip      | skid constraint             |\n| k        | perf_event_attr.exclude_user    | don't count user            |\n| u        | perf_event_attr.exclude_kernel  | don't count kernel          |\n| h / H    | perf_event_attr.exclude_guest   | don't count in guest        |\n| I        | perf_event_attr.exclude_idle    | don't count when idle       |\n| G        | perf_event_attr.exclude_hv      | don't count hypervisor      |\n| D        | perf_event_attr.pinned          | must always be on PMU       |\n\n## Measuring\n\nPlugin allows measuring both core and uncore events. During plugin\ninitialization the event names provided by user are compared with event\ndefinitions included in JSON files and translated to perf attributes. Next,\nthose events are activated to start counting.  During every telegraf interval,\nthe plugin reads proper measurement for each previously activated event.\n\nEach single core event may be counted severally on every available CPU's\ncore. In contrast, uncore events could be placed in many PMUs within specified\nCPU package. The plugin allows choosing core ids (core events) or socket ids\n(uncore events) on which the counting should be executed.  Uncore events are\nseparately activated on all socket's PMUs, and can be exposed as separate\nmeasurement or to be summed up as one measurement.\n\nObtained measurements are stored as three values: **Raw**, **Enabled** and\n**Running**. Raw is a total count of event. Enabled and running are total time\nthe event was enabled and running.  Normally these are the same. If more events\nare started than available counter slots on the PMU, then multiplexing occurs\nand events only run part of the time. Therefore, the plugin provides a 4-th\nvalue called **scaled** which is calculated using following formula: `raw *\nenabled / running`.\n\nEvents are measured for all running processes.\n\n### Core event groups\n\nPerf allows assembling events as a group. A perf event group is scheduled onto\nthe CPU as a unit: it will be put onto the CPU only if all of the events in the\ngroup can be put onto the CPU.  This means that the values of the member events\ncan be meaningfully compared — added, divided (to get ratios), and so on — with\neach other, since they have counted events for the same set of executed\ninstructions [(source)][man].\n\n> **NOTE:** Be aware that the plugin will throw an error when trying to create\n> core event group of size that exceeds available core PMU counters.  The error\n> message from perf syscall will be shown as \"invalid argument\". If you want to\n> check how many PMUs are supported by your Intel CPU, you can use the\n> [cpuid](https://linux.die.net/man/1/cpuid) command.\n\n### Note about file descriptors\n\nThe plugin opens a number of file descriptors dependent on number of monitored\nCPUs and number of monitored counters. It can easily exceed the default per\nprocess limit of allowed file descriptors. Depending on configuration, it might\nbe required to increase the limit of opened file descriptors allowed.  This can\nbe done for example by using `ulimit -n command`.\n\n## Metrics\n\nOn each Telegraf interval, Intel PMU plugin transmits following data:\n\n### Metric Fields\n\n| Field   | Type   | Description                                                                                                                                   |\n|---------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------|\n| enabled | uint64 | time counter, contains time the associated perf event was enabled                                                                             |\n| running | uint64 | time counter, contains time the event was actually counted                                                                                    |\n| raw     | uint64 | value counter, contains event count value during the time the event was actually counted                                                      |\n| scaled  | uint64 | value counter, contains approximated value of counter if the event was continuously counted, using scaled = raw * (enabled / running) formula |\n\n### Metric Tags - common\n\n| Tag   | Description                  |\n|-------|------------------------------|\n| host  | hostname as read by Telegraf |\n| event | name of the event            |\n\n### Metric Tags - core events\n\n| Tag        | Description                                                                                        |\n|------------|----------------------------------------------------------------------------------------------------|\n| cpu        | CPU id as identified by linux OS (either logical cpu id when HT on or physical cpu id when HT off) |\n| events_tag | (optional) tag as defined in \"intel_pmu.core_events\" configuration element                           |\n\n### Metric Tags - uncore events\n\n| Tag       | Description                                                                                                                                                                                |\n|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| socket    | socket number as identified by linux OS (physical_package_id)                                                                                                                              |\n| unit_type | type of event-capable PMU that the event was counted for, provides category of PMU that the event was counted for, e.g. cbox for uncore_cbox_1, r2pcie for uncore_r2pcie etc.              |\n| unit      | name of event-capable PMU that the event was counted for, as listed in /sys/bus/event_source/devices/ e.g. uncore_cbox_1, uncore_imc_1 etc.  Present for non-aggregated uncore events only |\n| events_tag| (optional) tag as defined in \"intel_pmu.uncore_events\" configuration element                           |\n\n## Example Output\n\nEvent group:\n\n```text\npmu_metric,cpu=0,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871237051i,running=2871237051i,raw=1171711i,scaled=1171711i 1621254096000000000\npmu_metric,cpu=0,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz enabled=2871240713i,running=2871240713i,raw=72340716i,scaled=72340716i 1621254096000000000\npmu_metric,cpu=1,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871118275i,running=2871118275i,raw=1646752i,scaled=1646752i 1621254096000000000\npmu_metric,cpu=1,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz raw=108802421i,scaled=108802421i,enabled=2871120107i,running=2871120107i 1621254096000000000\npmu_metric,cpu=2,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871143950i,running=2871143950i,raw=1316834i,scaled=1316834i 1621254096000000000\npmu_metric,cpu=2,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz enabled=2871074681i,running=2871074681i,raw=68728436i,scaled=68728436i 1621254096000000000\n```\n\nUncore event not aggregated:\n\n```text\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_0,unit_type=cbox enabled=2870630747i,running=2870630747i,raw=183996i,scaled=183996i 1621254096000000000\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_1,unit_type=cbox enabled=2870608194i,running=2870608194i,raw=185703i,scaled=185703i 1621254096000000000\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_2,unit_type=cbox enabled=2870600211i,running=2870600211i,raw=187331i,scaled=187331i 1621254096000000000\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_3,unit_type=cbox enabled=2870593914i,running=2870593914i,raw=184228i,scaled=184228i 1621254096000000000\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_4,unit_type=cbox scaled=195355i,enabled=2870558952i,running=2870558952i,raw=195355i 1621254096000000000\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_5,unit_type=cbox enabled=2870554131i,running=2870554131i,raw=197756i,scaled=197756i 1621254096000000000\n```\n\nUncore event aggregated:\n\n```text\npmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit_type=cbox enabled=13199712335i,running=13199712335i,raw=467485i,scaled=467485i 1621254412000000000\n```\n\nTime multiplexing:\n\n```text\npmu_metric,cpu=0,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,host=xyz raw=2947727i,scaled=4428970i,enabled=2201071844i,running=1464935978i 1621254412000000000\npmu_metric,cpu=0,event=CPU_CLK_UNHALTED.THREAD_P_ANY,host=xyz running=1465155618i,raw=302553190i,scaled=454511623i,enabled=2201035323i 1621254412000000000\npmu_metric,cpu=0,event=CPU_CLK_UNHALTED.REF_XCLK,host=xyz enabled=2200994057i,running=1466812391i,raw=3177535i,scaled=4767982i 1621254412000000000\npmu_metric,cpu=0,event=CPU_CLK_UNHALTED.REF_XCLK_ANY,host=xyz enabled=2200963921i,running=1470523496i,raw=3359272i,scaled=5027894i 1621254412000000000\npmu_metric,cpu=0,event=L1D_PEND_MISS.PENDING_CYCLES_ANY,host=xyz enabled=2200933946i,running=1470322480i,raw=23631950i,scaled=35374798i 1621254412000000000\npmu_metric,cpu=0,event=L1D_PEND_MISS.PENDING_CYCLES,host=xyz raw=18767833i,scaled=28169827i,enabled=2200888514i,running=1466317384i 1621254412000000000\n```\n\n[man]: https://man7.org/linux/man-pages/man2/perf_event_open.2.html\n\n## Changelog\n\n| Version | Description |\n| --- | --- |\n| v1.0.0 | Initial version |\n| v1.1.0 | Added support for [new perfmon event format](https://github.com/intel/perfmon/issues/22). Old event format is still accepted (warn message will be printed in the log) |\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/activators.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\tia \"github.com/intel/iaevents\"\n)\n\ntype placementMaker interface {\n\tmakeCorePlacements(cores []int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error)\n\tmakeUncorePlacements(socket int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error)\n}\n\ntype iaPlacementMaker struct{}\n\nfunc (iaPlacementMaker) makeCorePlacements(cores []int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) {\n\tvar err error\n\tvar corePlacements []ia.PlacementProvider\n\n\tswitch len(cores) {\n\tcase 0:\n\t\treturn nil, errors.New(\"no cores provided\")\n\tcase 1:\n\t\tcorePlacements, err = ia.NewCorePlacements(factory, cores[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\tcorePlacements, err = ia.NewCorePlacements(factory, cores[0], cores[1:]...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn corePlacements, nil\n}\n\nfunc (iaPlacementMaker) makeUncorePlacements(socket int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) {\n\treturn ia.NewUncoreAllPlacements(factory, socket)\n}\n\ntype eventsActivator interface {\n\tactivateEvent(ia.Activator, ia.PlacementProvider, ia.Options) (*ia.ActiveEvent, error)\n\tactivateGroup(ia.PlacementProvider, []ia.CustomizableEvent) (*ia.ActiveEventGroup, error)\n\tactivateMulti(ia.MultiActivator, []ia.PlacementProvider, ia.Options) (*ia.ActiveMultiEvent, error)\n}\n\ntype iaEventsActivator struct{}\n\nfunc (iaEventsActivator) activateEvent(a ia.Activator, p ia.PlacementProvider, o ia.Options) (*ia.ActiveEvent, error) {\n\treturn a.Activate(p, ia.NewEventTargetProcess(-1, 0), o)\n}\n\nfunc (iaEventsActivator) activateGroup(p ia.PlacementProvider, e []ia.CustomizableEvent) (*ia.ActiveEventGroup, error) {\n\treturn ia.ActivateGroup(p, ia.NewEventTargetProcess(-1, 0), e)\n}\n\nfunc (iaEventsActivator) activateMulti(a ia.MultiActivator, p []ia.PlacementProvider, o ia.Options) (*ia.ActiveMultiEvent, error) {\n\treturn a.ActivateMulti(p, ia.NewEventTargetProcess(-1, 0), o)\n}\n\ntype entitiesActivator interface {\n\tactivateEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error\n}\n\ntype iaEntitiesActivator struct {\n\tplacementMaker placementMaker\n\tperfActivator  eventsActivator\n}\n\nfunc (ea *iaEntitiesActivator) activateEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {\n\tfor _, coreEventsEntity := range coreEntities {\n\t\terr := ea.activateCoreEvents(coreEventsEntity)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to activate core events %q: %w\", coreEventsEntity.EventsTag, err)\n\t\t}\n\t}\n\tfor _, uncoreEventsEntity := range uncoreEntities {\n\t\terr := ea.activateUncoreEvents(uncoreEventsEntity)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to activate uncore events %q: %w\", uncoreEventsEntity.EventsTag, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ea *iaEntitiesActivator) activateCoreEvents(entity *coreEventEntity) error {\n\tif entity == nil {\n\t\treturn errors.New(\"core events entity is nil\")\n\t}\n\tif ea.placementMaker == nil {\n\t\treturn errors.New(\"placement maker is nil\")\n\t}\n\tif entity.PerfGroup {\n\t\terr := ea.activateCoreEventsGroup(entity)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to activate core events group: %w\", err)\n\t\t}\n\t} else {\n\t\tfor _, event := range entity.parsedEvents {\n\t\t\tif event == nil {\n\t\t\t\treturn errors.New(\"core parsed event is nil\")\n\t\t\t}\n\t\t\tplacements, err := ea.placementMaker.makeCorePlacements(entity.parsedCores, event.custom.Event)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create core placements for event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tactiveEvents, err := ea.activateEventForPlacements(event, placements)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to activate core event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tentity.activeEvents = append(entity.activeEvents, activeEvents...)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ea *iaEntitiesActivator) activateUncoreEvents(entity *uncoreEventEntity) error {\n\tif entity == nil {\n\t\treturn errors.New(\"uncore events entity is nil\")\n\t}\n\tif ea.perfActivator == nil || ea.placementMaker == nil {\n\t\treturn errors.New(\"events activator or placement maker is nil\")\n\t}\n\tfor _, event := range entity.parsedEvents {\n\t\tif event == nil {\n\t\t\treturn errors.New(\"uncore parsed event is nil\")\n\t\t}\n\t\tperfEvent := event.custom.Event\n\t\tif perfEvent == nil {\n\t\t\treturn fmt.Errorf(\"perf event of %q event is nil\", event.name)\n\t\t}\n\t\toptions := event.custom.Options\n\n\t\tfor _, socket := range entity.parsedSockets {\n\t\t\tplacements, err := ea.placementMaker.makeUncorePlacements(socket, perfEvent)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create uncore placements for event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tactiveMultiEvent, err := ea.perfActivator.activateMulti(perfEvent, placements, options)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to activate multi event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tevents := activeMultiEvent.Events()\n\t\t\tentity.activeMultiEvents = append(entity.activeMultiEvents, multiEvent{events, perfEvent, socket})\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ea *iaEntitiesActivator) activateCoreEventsGroup(entity *coreEventEntity) error {\n\tif ea.perfActivator == nil || ea.placementMaker == nil {\n\t\treturn errors.New(\"missing perf activator or placement maker\")\n\t}\n\tif entity == nil || len(entity.parsedEvents) < 1 {\n\t\treturn errors.New(\"missing parsed events\")\n\t}\n\n\tevents := make([]ia.CustomizableEvent, 0, len(entity.parsedEvents))\n\tfor _, event := range entity.parsedEvents {\n\t\tif event == nil {\n\t\t\treturn errors.New(\"core event is nil\")\n\t\t}\n\t\tevents = append(events, event.custom)\n\t}\n\tleader := entity.parsedEvents[0].custom\n\n\tplacements, err := ea.placementMaker.makeCorePlacements(entity.parsedCores, leader.Event)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to make core placements: %w\", err)\n\t}\n\n\tfor _, plc := range placements {\n\t\tactiveGroup, err := ea.perfActivator.activateGroup(plc, events)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tentity.activeEvents = append(entity.activeEvents, activeGroup.Events()...)\n\t}\n\treturn nil\n}\n\nfunc (ea *iaEntitiesActivator) activateEventForPlacements(event *eventWithQuals, placements []ia.PlacementProvider) ([]*ia.ActiveEvent, error) {\n\tif event == nil {\n\t\treturn nil, errors.New(\"core event is nil\")\n\t}\n\tif ea.perfActivator == nil {\n\t\treturn nil, errors.New(\"missing perf activator\")\n\t}\n\n\tactiveEvents := make([]*ia.ActiveEvent, 0, len(placements))\n\tfor _, placement := range placements {\n\t\tperfEvent := event.custom.Event\n\t\toptions := event.custom.Options\n\n\t\tactiveEvent, err := ea.perfActivator.activateEvent(perfEvent, placement, options)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to activate event %q: %w\", event.name, err)\n\t\t}\n\t\tactiveEvents = append(activeEvents, activeEvent)\n\t}\n\treturn activeEvents, nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/activators_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype mockPlacementFactory struct {\n\terr bool\n}\n\nfunc (m *mockPlacementFactory) NewPlacements(_ string, cpu int, cpus ...int) ([]ia.PlacementProvider, error) {\n\tif m.err {\n\t\treturn nil, errors.New(\"mock error\")\n\t}\n\tplacements := []ia.PlacementProvider{\n\t\t&ia.Placement{CPU: cpu, PMUType: 4},\n\t}\n\tfor _, cpu := range cpus {\n\t\tplacements = append(placements, &ia.Placement{CPU: cpu, PMUType: 4})\n\t}\n\treturn placements, nil\n}\n\nfunc TestActivateEntities(t *testing.T) {\n\tmEntitiesActivator := &iaEntitiesActivator{}\n\n\t// more core test cases in TestActivateCoreEvents\n\tt.Run(\"failed to activate core events\", func(t *testing.T) {\n\t\ttag := \"TAG\"\n\t\tmEntities := []*coreEventEntity{{EventsTag: tag}}\n\t\terr := mEntitiesActivator.activateEntities(mEntities, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to activate core events %q\", tag))\n\t})\n\n\t// more uncore test cases in TestActivateUncoreEvents\n\tt.Run(\"failed to activate uncore events\", func(t *testing.T) {\n\t\ttag := \"TAG\"\n\t\tmEntities := []*uncoreEventEntity{{EventsTag: tag}}\n\t\terr := mEntitiesActivator.activateEntities(nil, mEntities)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to activate uncore events %q\", tag))\n\t})\n\n\tt.Run(\"nothing to do\", func(t *testing.T) {\n\t\terr := mEntitiesActivator.activateEntities(nil, nil)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestActivateUncoreEvents(t *testing.T) {\n\tmActivator := &mockEventsActivator{}\n\tmMaker := &mockPlacementMaker{}\n\terrMock := errors.New(\"error mock\")\n\n\tt.Run(\"entity is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\terr := mEntitiesActivator.activateUncoreEvents(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"uncore events entity is nil\")\n\t})\n\n\tt.Run(\"event is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\tmEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}\n\t\terr := mEntitiesActivator.activateUncoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"uncore parsed event is nil\")\n\t})\n\n\tt.Run(\"perf event is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\tname := \"event name\"\n\t\tmEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{{name: name, custom: ia.CustomizableEvent{Event: nil}}}}\n\t\terr := mEntitiesActivator.activateUncoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"perf event of %q event is nil\", name))\n\t})\n\n\tt.Run(\"placement maker and perf activator is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: nil, perfActivator: nil}\n\t\terr := mEntitiesActivator.activateUncoreEvents(&uncoreEventEntity{})\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"events activator or placement maker is nil\")\n\t})\n\n\tt.Run(\"failed to create placements\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\teventName := \"mock event 1\"\n\t\tparsedEvents := []*eventWithQuals{{name: eventName, custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: eventName}}}}\n\t\tmEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}\n\n\t\tmMaker.On(\"makeUncorePlacements\", parsedEvents[0].custom.Event, mEntity.parsedSockets[0]).Return(nil, errMock).Once()\n\t\terr := mEntitiesActivator.activateUncoreEvents(mEntity)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"ailed to create uncore placements for event %q\", eventName))\n\t\tmMaker.AssertExpectations(t)\n\t})\n\n\tt.Run(\"failed to activate event\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\teventName := \"mock event 1\"\n\t\tparsedEvents := []*eventWithQuals{{name: eventName, custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: eventName}}}}\n\t\tplacements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}}\n\t\tmEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}\n\n\t\tmMaker.On(\"makeUncorePlacements\", parsedEvents[0].custom.Event, mEntity.parsedSockets[0]).Return(placements, nil).Once()\n\t\tmActivator.On(\"activateMulti\", parsedEvents[0].custom.Event, placements, parsedEvents[0].custom.Options).Return(nil, errMock).Once()\n\n\t\terr := mEntitiesActivator.activateUncoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to activate multi event %q\", eventName))\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n\n\tt.Run(\"successfully activate core events\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\n\t\tparsedEvents := []*eventWithQuals{\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 1\", Uncore: true}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 2\", Uncore: true}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 3\", Uncore: true}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 4\", Uncore: true}}},\n\t\t}\n\t\tmEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}\n\t\tplacements := []ia.PlacementProvider{&ia.Placement{}, &ia.Placement{}, &ia.Placement{}}\n\n\t\tvar expectedEvents []multiEvent\n\t\tfor _, event := range parsedEvents {\n\t\t\tfor _, socket := range mEntity.parsedSockets {\n\t\t\t\tmMaker.On(\"makeUncorePlacements\", event.custom.Event, socket).Return(placements, nil).Once()\n\t\t\t\tnewActiveMultiEvent := &ia.ActiveMultiEvent{}\n\t\t\t\texpectedEvents = append(expectedEvents, multiEvent{newActiveMultiEvent.Events(), event.custom.Event, socket})\n\t\t\t\tmActivator.On(\"activateMulti\", event.custom.Event, placements, event.custom.Options).Return(newActiveMultiEvent, nil).Once()\n\t\t\t}\n\t\t}\n\t\terr := mEntitiesActivator.activateUncoreEvents(mEntity)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedEvents, mEntity.activeMultiEvents)\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n}\n\nfunc TestActivateCoreEvents(t *testing.T) {\n\tmMaker := &mockPlacementMaker{}\n\tmActivator := &mockEventsActivator{}\n\terrMock := errors.New(\"error mock\")\n\n\tt.Run(\"entity is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\terr := mEntitiesActivator.activateCoreEvents(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"core events entity is nil\")\n\t})\n\n\tt.Run(\"placement maker is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: nil, perfActivator: mActivator}\n\t\terr := mEntitiesActivator.activateCoreEvents(&coreEventEntity{})\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"placement maker is nil\")\n\t})\n\n\tt.Run(\"event is nil\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\tmEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}\n\t\terr := mEntitiesActivator.activateCoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"core parsed event is nil\")\n\t})\n\n\tt.Run(\"failed to create placements\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\t\tparsedEvents := []*eventWithQuals{{name: \"mock event 1\", custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 1\"}}}}\n\t\tmEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}\n\n\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, parsedEvents[0].custom.Event).Return(nil, errMock).Once()\n\t\terr := mEntitiesActivator.activateCoreEvents(mEntity)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to create core placements for event %q\", parsedEvents[0].name))\n\t\tmMaker.AssertExpectations(t)\n\t})\n\n\tt.Run(\"failed to activate event\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\n\t\tparsedEvents := []*eventWithQuals{{name: \"mock event 1\", custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 1\"}}}}\n\t\tplacements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}}\n\t\tmEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}\n\n\t\tevent := parsedEvents[0]\n\t\tplc := placements[0]\n\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, event.custom.Event).Return(placements, nil).Once()\n\t\tmActivator.On(\"activateEvent\", event.custom.Event, plc, event.custom.Options).Return(nil, errMock).Once()\n\n\t\terr := mEntitiesActivator.activateCoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to activate core event %q\", parsedEvents[0].name))\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n\n\tt.Run(\"failed to activate core events group\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: nil}\n\t\tmEntity := &coreEventEntity{PerfGroup: true, parsedEvents: nil}\n\n\t\terr := mEntitiesActivator.activateCoreEvents(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to activate core events group\")\n\t})\n\n\tt.Run(\"successfully activate core events\", func(t *testing.T) {\n\t\tmEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\n\t\tparsedEvents := []*eventWithQuals{\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 1\"}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 2\"}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 3\"}}},\n\t\t\t{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: \"mock event 4\"}}},\n\t\t}\n\t\tplacements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}, &ia.Placement{CPU: 2}}\n\t\tmEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}\n\n\t\tvar activeEvents []*ia.ActiveEvent\n\t\tfor _, event := range parsedEvents {\n\t\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, event.custom.Event).Return(placements, nil).Once()\n\t\t\tfor _, plc := range placements {\n\t\t\t\tnewActiveEvent := &ia.ActiveEvent{PerfEvent: event.custom.Event}\n\t\t\t\tactiveEvents = append(activeEvents, newActiveEvent)\n\t\t\t\tmActivator.On(\"activateEvent\", event.custom.Event, plc, event.custom.Options).Return(newActiveEvent, nil).Once()\n\t\t\t}\n\t\t}\n\n\t\terr := mEntitiesActivator.activateCoreEvents(mEntity)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, activeEvents, mEntity.activeEvents)\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n}\n\nfunc TestActivateCoreEventsGroup(t *testing.T) {\n\tmMaker := &mockPlacementMaker{}\n\tmActivator := &mockEventsActivator{}\n\teActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}\n\terrMock := errors.New(\"mock error\")\n\n\tleader := &ia.PerfEvent{Name: \"mock event 1\"}\n\tperfEvent2 := &ia.PerfEvent{Name: \"mock event 2\"}\n\n\tparsedEvents := []*eventWithQuals{{custom: ia.CustomizableEvent{Event: leader}}, {custom: ia.CustomizableEvent{Event: perfEvent2}}}\n\tplacements := []ia.PlacementProvider{&ia.Placement{}, &ia.Placement{}}\n\n\t// cannot populate this struct due to unexported events field\n\tactiveGroup := &ia.ActiveEventGroup{}\n\n\tmEntity := &coreEventEntity{\n\t\tEventsTag:    \"mock group\",\n\t\tPerfGroup:    true,\n\t\tparsedEvents: parsedEvents,\n\t\tparsedCores:  nil,\n\t}\n\n\tevents := make([]ia.CustomizableEvent, 0, len(parsedEvents))\n\tfor _, event := range parsedEvents {\n\t\tevents = append(events, event.custom)\n\t}\n\n\tt.Run(\"missing perf activator and placement maker\", func(t *testing.T) {\n\t\tmActivator := &iaEntitiesActivator{}\n\t\terr := mActivator.activateCoreEventsGroup(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"missing perf activator or placement maker\")\n\t})\n\n\tt.Run(\"missing parsed events\", func(t *testing.T) {\n\t\tmActivator := &iaEntitiesActivator{placementMaker: &mockPlacementMaker{}, perfActivator: &mockEventsActivator{}}\n\t\terr := mActivator.activateCoreEventsGroup(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"missing parsed events\")\n\t})\n\n\tt.Run(\"nil in parsed event\", func(t *testing.T) {\n\t\tmEntity := &coreEventEntity{EventsTag: \"Nice tag\", PerfGroup: true, parsedEvents: []*eventWithQuals{nil, nil}}\n\t\terr := eActivator.activateCoreEventsGroup(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"core event is nil\")\n\t})\n\n\tt.Run(\"failed to make core placements\", func(t *testing.T) {\n\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, leader).Return(nil, errMock).Once()\n\t\terr := eActivator.activateCoreEventsGroup(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to make core placements\")\n\t\tmMaker.AssertExpectations(t)\n\t})\n\n\tt.Run(\"failed to activate group\", func(t *testing.T) {\n\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, leader).Return(placements, nil).Once()\n\t\tmActivator.On(\"activateGroup\", placements[0], events).Return(nil, errMock).Once()\n\n\t\terr := eActivator.activateCoreEventsGroup(mEntity)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), errMock.Error())\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n\n\tvar allActive []*ia.ActiveEvent\n\tt.Run(\"successfully activated group\", func(t *testing.T) {\n\t\tmMaker.On(\"makeCorePlacements\", mEntity.parsedCores, leader).Return(placements, nil).Once()\n\t\tfor _, plc := range placements {\n\t\t\tmActivator.On(\"activateGroup\", plc, events).Return(activeGroup, nil).Once()\n\t\t\tallActive = append(allActive, activeGroup.Events()...)\n\t\t}\n\n\t\terr := eActivator.activateCoreEventsGroup(mEntity)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, allActive, mEntity.activeEvents)\n\t\tmMaker.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n}\n\nfunc TestMakeCorePlacements(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tcores     []int\n\t\tperfEvent ia.PlacementFactory\n\t\tresult    []ia.PlacementProvider\n\t\terrMsg    string\n\t}{\n\t\t{\"no cores\", nil, &ia.PerfEvent{}, nil, \"no cores provided\"},\n\t\t{\"one core placement\", []int{1}, &mockPlacementFactory{}, []ia.PlacementProvider{&ia.Placement{CPU: 1, PMUType: 4}}, \"\"},\n\t\t{\"multiple core placement\", []int{1, 2, 4}, &mockPlacementFactory{}, []ia.PlacementProvider{\n\t\t\t&ia.Placement{CPU: 1, PMUType: 4},\n\t\t\t&ia.Placement{CPU: 2, PMUType: 4},\n\t\t\t&ia.Placement{CPU: 4, PMUType: 4}},\n\t\t\t\"\"},\n\t\t{\"placement factory error\", []int{1}, &mockPlacementFactory{true}, nil, \"mock error\"},\n\t\t{\"placement factory error 2\", []int{1, 2, 3}, &mockPlacementFactory{true}, nil, \"mock error\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmaker := &iaPlacementMaker{}\n\t\t\tproviders, err := maker.makeCorePlacements(test.cores, test.perfEvent)\n\t\t\tif len(test.errMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Nil(t, providers)\n\t\t\t\trequire.Contains(t, err.Error(), test.errMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.result, providers)\n\t\t})\n\t}\n}\n\nfunc TestActivateEventForPlacement(t *testing.T) {\n\tplacement1 := &ia.Placement{CPU: 0}\n\tplacement2 := &ia.Placement{CPU: 1}\n\tplacement3 := &ia.Placement{CPU: 2}\n\n\tmPlacements := []ia.PlacementProvider{placement1, placement2, placement3}\n\n\tmPerfEvent := &ia.PerfEvent{Name: \"mock1\"}\n\tmOptions := &ia.PerfEventOptions{}\n\tmEvent := &eventWithQuals{name: mPerfEvent.Name, custom: ia.CustomizableEvent{Event: mPerfEvent, Options: mOptions}}\n\n\tmPerfActivator := &mockEventsActivator{}\n\tmActivator := &iaEntitiesActivator{perfActivator: mPerfActivator}\n\n\tt.Run(\"event is nil\", func(t *testing.T) {\n\t\tactiveEvents, err := mActivator.activateEventForPlacements(nil, mPlacements)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"core event is nil\")\n\t\trequire.Empty(t, activeEvents)\n\t})\n\n\tt.Run(\"perf activator is nil\", func(t *testing.T) {\n\t\tmActivator := &iaEntitiesActivator{}\n\t\tactiveEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"missing perf activator\")\n\t\trequire.Empty(t, activeEvents)\n\t})\n\n\tt.Run(\"placements are nil\", func(t *testing.T) {\n\t\tactiveEvents, err := mActivator.activateEventForPlacements(mEvent, nil)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, activeEvents)\n\t})\n\n\tt.Run(\"activation error\", func(t *testing.T) {\n\t\tmPerfActivator.On(\"activateEvent\", mPerfEvent, placement1, mOptions).Once().Return(nil, errors.New(\"err\"))\n\t\tactiveEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to activate event %q\", mEvent.name))\n\t\trequire.Nil(t, activeEvents)\n\t\tmPerfActivator.AssertExpectations(t)\n\t})\n\n\tt.Run(\"successfully activated\", func(t *testing.T) {\n\t\tmActiveEvent := &ia.ActiveEvent{}\n\t\tmActiveEvent2 := &ia.ActiveEvent{}\n\t\tmActiveEvent3 := &ia.ActiveEvent{}\n\n\t\tmPerfActivator.On(\"activateEvent\", mPerfEvent, placement1, mOptions).Once().Return(mActiveEvent, nil).\n\t\t\tOn(\"activateEvent\", mPerfEvent, placement2, mOptions).Once().Return(mActiveEvent2, nil).\n\t\t\tOn(\"activateEvent\", mPerfEvent, placement3, mOptions).Once().Return(mActiveEvent3, nil)\n\n\t\tactiveEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, activeEvents, len(mPlacements))\n\t\trequire.Contains(t, activeEvents, mActiveEvent)\n\t\trequire.Contains(t, activeEvents, mActiveEvent2)\n\t\tmPerfActivator.AssertExpectations(t)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/config.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Maximum size of core IDs or socket IDs (8192). Based on maximum value of CPUs that linux kernel supports.\nconst maxIDsSize = 1 << 13\n\ntype entitiesParser interface {\n\tparseEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) (err error)\n}\n\ntype configParser struct {\n\tlog telegraf.Logger\n\tsys sysInfoProvider\n}\n\nfunc (cp *configParser) parseEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) (err error) {\n\tif len(coreEntities) == 0 && len(uncoreEntities) == 0 {\n\t\treturn errors.New(\"neither core nor uncore entities configured\")\n\t}\n\n\tfor _, coreEntity := range coreEntities {\n\t\tif coreEntity == nil {\n\t\t\treturn errors.New(\"core entity is nil\")\n\t\t}\n\t\tif coreEntity.Events == nil {\n\t\t\tif cp.log != nil {\n\t\t\t\tcp.log.Debug(\"all core events from provided files will be configured\")\n\t\t\t}\n\t\t\tcoreEntity.allEvents = true\n\t\t} else {\n\t\t\tevents := cp.parseEvents(coreEntity.Events)\n\t\t\tif events == nil {\n\t\t\t\treturn errors.New(\"an empty list of core events was provided\")\n\t\t\t}\n\t\t\tcoreEntity.parsedEvents = events\n\t\t}\n\n\t\tcoreEntity.parsedCores, err = cp.parseCores(coreEntity.Cores)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error during cores parsing: %w\", err)\n\t\t}\n\t}\n\n\tfor _, uncoreEntity := range uncoreEntities {\n\t\tif uncoreEntity == nil {\n\t\t\treturn errors.New(\"uncore entity is nil\")\n\t\t}\n\t\tif uncoreEntity.Events == nil {\n\t\t\tif cp.log != nil {\n\t\t\t\tcp.log.Debug(\"all uncore events from provided files will be configured\")\n\t\t\t}\n\t\t\tuncoreEntity.allEvents = true\n\t\t} else {\n\t\t\tevents := cp.parseEvents(uncoreEntity.Events)\n\t\t\tif events == nil {\n\t\t\t\treturn errors.New(\"an empty list of uncore events was provided\")\n\t\t\t}\n\t\t\tuncoreEntity.parsedEvents = events\n\t\t}\n\n\t\tuncoreEntity.parsedSockets, err = cp.parseSockets(uncoreEntity.Sockets)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error during sockets parsing: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (cp *configParser) parseEvents(events []string) []*eventWithQuals {\n\tif len(events) == 0 {\n\t\treturn nil\n\t}\n\n\tevents, duplications := removeDuplicateStrings(events)\n\tfor _, duplication := range duplications {\n\t\tif cp.log != nil {\n\t\t\tcp.log.Warnf(\"duplicated event %q will be removed\", duplication)\n\t\t}\n\t}\n\treturn parseEventsWithQualifiers(events)\n}\n\nfunc (cp *configParser) parseCores(cores []string) ([]int, error) {\n\tif cores == nil {\n\t\tif cp.log != nil {\n\t\t\tcp.log.Debug(\"all possible cores will be configured\")\n\t\t}\n\t\tif cp.sys == nil {\n\t\t\treturn nil, errors.New(\"system info provider is nil\")\n\t\t}\n\t\tcores, err := cp.sys.allCPUs()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot obtain all cpus: %w\", err)\n\t\t}\n\t\treturn cores, nil\n\t}\n\tif len(cores) == 0 {\n\t\treturn nil, errors.New(\"an empty list of cores was provided\")\n\t}\n\n\tresult, err := cp.parseIntRanges(cores)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc (cp *configParser) parseSockets(sockets []string) ([]int, error) {\n\tif sockets == nil {\n\t\tif cp.log != nil {\n\t\t\tcp.log.Debug(\"all possible sockets will be configured\")\n\t\t}\n\t\tif cp.sys == nil {\n\t\t\treturn nil, errors.New(\"system info provider is nil\")\n\t\t}\n\t\tsockets, err := cp.sys.allSockets()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot obtain all sockets: %w\", err)\n\t\t}\n\t\treturn sockets, nil\n\t}\n\tif len(sockets) == 0 {\n\t\treturn nil, errors.New(\"an empty list of sockets was provided\")\n\t}\n\n\tresult, err := cp.parseIntRanges(sockets)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc (cp *configParser) parseIntRanges(ranges []string) ([]int, error) {\n\tvar ids []int\n\tvar duplicatedIDs []int\n\tvar err error\n\tids, err = parseIDs(ranges)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tids, duplicatedIDs = removeDuplicateValues(ids)\n\tfor _, duplication := range duplicatedIDs {\n\t\tif cp.log != nil {\n\t\t\tcp.log.Warnf(\"duplicated id number `%d` will be removed\", duplication)\n\t\t}\n\t}\n\treturn ids, nil\n}\n\nfunc parseEventsWithQualifiers(events []string) []*eventWithQuals {\n\tresult := make([]*eventWithQuals, 0, len(events))\n\tfor _, event := range events {\n\t\tnewEventWithQualifiers := &eventWithQuals{}\n\n\t\tsplit := strings.Split(event, \":\")\n\t\tnewEventWithQualifiers.name = split[0]\n\n\t\tif len(split) > 1 {\n\t\t\tnewEventWithQualifiers.qualifiers = split[1:]\n\t\t}\n\t\tresult = append(result, newEventWithQualifiers)\n\t}\n\n\treturn result\n}\n\nfunc parseIDs(allIDsStrings []string) ([]int, error) {\n\tvar result []int\n\tfor _, idsString := range allIDsStrings {\n\t\tids := strings.Split(idsString, \",\")\n\n\t\tfor _, id := range ids {\n\t\t\tid := strings.TrimSpace(id)\n\t\t\t// a-b support\n\t\t\tvar start, end uint\n\t\t\tn, err := fmt.Sscanf(id, \"%d-%d\", &start, &end)\n\t\t\tif err == nil && n == 2 {\n\t\t\t\tif start >= end {\n\t\t\t\t\treturn nil, fmt.Errorf(\"`%d` is equal or greater than `%d`\", start, end)\n\t\t\t\t}\n\t\t\t\tfor ; start <= end; start++ {\n\t\t\t\t\tif len(result)+1 > maxIDsSize {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"requested number of IDs exceeds max size `%d`\", maxIDsSize)\n\t\t\t\t\t}\n\t\t\t\t\tresult = append(result, int(start))\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Single value\n\t\t\tnum, err := strconv.Atoi(id)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"wrong format for id number %q: %w\", id, err)\n\t\t\t}\n\t\t\tif len(result)+1 > maxIDsSize {\n\t\t\t\treturn nil, fmt.Errorf(\"requested number of IDs exceeds max size `%d`\", maxIDsSize)\n\t\t\t}\n\t\t\tresult = append(result, num)\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc removeDuplicateValues(intSlice []int) (result, duplicates []int) {\n\tkeys := make(map[int]bool)\n\n\tfor _, entry := range intSlice {\n\t\tif _, value := keys[entry]; !value {\n\t\t\tkeys[entry] = true\n\t\t\tresult = append(result, entry)\n\t\t} else {\n\t\t\tduplicates = append(duplicates, entry)\n\t\t}\n\t}\n\treturn result, duplicates\n}\n\nfunc removeDuplicateStrings(strSlice []string) (result, duplicates []string) {\n\tkeys := make(map[string]bool)\n\n\tfor _, entry := range strSlice {\n\t\tif _, value := keys[entry]; !value {\n\t\t\tkeys[entry] = true\n\t\t\tresult = append(result, entry)\n\t\t} else {\n\t\t\tduplicates = append(duplicates, entry)\n\t\t}\n\t}\n\treturn result, duplicates\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/config_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestConfigParser_parseEntities(t *testing.T) {\n\tmSysInfo := &mockSysInfoProvider{}\n\tmConfigParser := &configParser{\n\t\tsys: mSysInfo,\n\t\tlog: testutil.Logger{},\n\t}\n\te := ia.CustomizableEvent{}\n\n\tt.Run(\"no entities\", func(t *testing.T) {\n\t\terr := mConfigParser.parseEntities(nil, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"neither core nor uncore entities configured\")\n\t})\n\n\t// more specific parsing cases in TestConfigParser_parseIntRanges and TestConfigParser_parseEvents\n\tcoreTests := []struct {\n\t\tname string\n\n\t\tcoreEntity       *coreEventEntity\n\t\tparsedCoreEvents []*eventWithQuals\n\t\tparsedCores      []int\n\t\tcoreAll          bool\n\n\t\tuncoreEntity       *uncoreEventEntity\n\t\tparsedUncoreEvents []*eventWithQuals\n\t\tparsedSockets      []int\n\t\tuncoreAll          bool\n\n\t\tfailMsg string\n\t}{\n\t\t{\"no events provided\",\n\t\t\t&coreEventEntity{Events: nil, Cores: []string{\"1\"}}, nil, []int{1}, true,\n\t\t\t&uncoreEventEntity{Events: nil, Sockets: []string{\"0\"}}, nil, []int{0}, true,\n\t\t\t\"\"},\n\t\t{\"uncore entity is nil\",\n\t\t\t&coreEventEntity{Events: []string{\"EVENT\"}, Cores: []string{\"1,2\"}}, []*eventWithQuals{{\"EVENT\", nil, e}}, []int{1, 2}, false,\n\t\t\tnil, nil, nil, false,\n\t\t\t\"uncore entity is nil\"},\n\t\t{\"core entity is nil\",\n\t\t\tnil, nil, nil, false,\n\t\t\t&uncoreEventEntity{Events: []string{\"EVENT\"}, Sockets: []string{\"1,2\"}}, []*eventWithQuals{{\"EVENT\", nil, e}}, []int{1, 2}, false,\n\t\t\t\"core entity is nil\"},\n\t\t{\"error parsing sockets\",\n\t\t\t&coreEventEntity{Events: nil, Cores: []string{\"1,2\"}}, nil, []int{1, 2}, true,\n\t\t\t&uncoreEventEntity{Events: []string{\"E\"}, Sockets: []string{\"wrong sockets\"}}, []*eventWithQuals{{\"E\", nil, e}}, nil, false,\n\t\t\t\"error during sockets parsing\"},\n\t\t{\"error parsing cores\",\n\t\t\t&coreEventEntity{Events: nil, Cores: []string{\"wrong cpus\"}}, nil, nil, true,\n\t\t\t&uncoreEventEntity{Events: nil, Sockets: []string{\"0,1\"}}, nil, []int{0, 1}, true,\n\t\t\t\"error during cores parsing\"},\n\t\t{\"valid settings\",\n\t\t\t&coreEventEntity{\n\t\t\t\tEvents: []string{\"E1\", \"E2:config=123\"},\n\t\t\t\tCores:  []string{\"1-5\"},\n\t\t\t}, []*eventWithQuals{{\"E1\", nil, e}, {\"E2\", []string{\"config=123\"}, e}}, []int{1, 2, 3, 4, 5}, false,\n\t\t\t&uncoreEventEntity{\n\t\t\t\tEvents:  []string{\"E1\", \"E2\", \"E3\"},\n\t\t\t\tSockets: []string{\"0,2-6\"},\n\t\t\t}, []*eventWithQuals{{\"E1\", nil, e}, {\"E2\", nil, e}, {\"E3\", nil, e}}, []int{0, 2, 3, 4, 5, 6}, false,\n\t\t\t\"\"},\n\t}\n\n\tfor _, test := range coreTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcoreEntities := []*coreEventEntity{test.coreEntity}\n\t\t\tuncoreEntities := []*uncoreEventEntity{test.uncoreEntity}\n\n\t\t\terr := mConfigParser.parseEntities(coreEntities, uncoreEntities)\n\n\t\t\tif len(test.failMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.failMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.coreAll, test.coreEntity.allEvents)\n\t\t\trequire.Equal(t, test.parsedCores, test.coreEntity.parsedCores)\n\t\t\trequire.Equal(t, test.parsedCoreEvents, test.coreEntity.parsedEvents)\n\n\t\t\trequire.Equal(t, test.uncoreAll, test.uncoreEntity.allEvents)\n\t\t\trequire.Equal(t, test.parsedSockets, test.uncoreEntity.parsedSockets)\n\t\t\trequire.Equal(t, test.parsedUncoreEvents, test.uncoreEntity.parsedEvents)\n\t\t})\n\t}\n}\n\nfunc TestConfigParser_parseCores(t *testing.T) {\n\tmSysInfo := &mockSysInfoProvider{}\n\tmConfigParser := &configParser{\n\t\tsys: mSysInfo,\n\t\tlog: testutil.Logger{},\n\t}\n\n\tt.Run(\"no cores provided\", func(t *testing.T) {\n\t\tt.Run(\"system info provider is nil\", func(t *testing.T) {\n\t\t\tresult, err := (&configParser{}).parseCores(nil)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"system info provider is nil\")\n\t\t\trequire.Nil(t, result)\n\t\t})\n\t\tt.Run(\"cannot gather all cpus info\", func(t *testing.T) {\n\t\t\tmSysInfo.On(\"allCPUs\").Return(nil, errors.New(\"all cpus error\")).Once()\n\t\t\tresult, err := mConfigParser.parseCores(nil)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"cannot obtain all cpus\")\n\t\t\trequire.Nil(t, result)\n\t\t\tmSysInfo.AssertExpectations(t)\n\t\t})\n\t\tt.Run(\"all cpus gathering succeeded\", func(t *testing.T) {\n\t\t\tallCPUs := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}\n\n\t\t\tmSysInfo.On(\"allCPUs\").Return(allCPUs, nil).Once()\n\t\t\tresult, err := mConfigParser.parseCores(nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, allCPUs, result)\n\t\t\tmSysInfo.AssertExpectations(t)\n\t\t})\n\t})\n}\n\nfunc TestConfigParser_parseSockets(t *testing.T) {\n\tmSysInfo := &mockSysInfoProvider{}\n\tmConfigParser := &configParser{\n\t\tsys: mSysInfo,\n\t\tlog: testutil.Logger{},\n\t}\n\n\tt.Run(\"no sockets provided\", func(t *testing.T) {\n\t\tt.Run(\"system info provider is nil\", func(t *testing.T) {\n\t\t\tresult, err := (&configParser{}).parseSockets(nil)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"system info provider is nil\")\n\t\t\trequire.Nil(t, result)\n\t\t})\n\t\tt.Run(\"cannot gather all sockets info\", func(t *testing.T) {\n\t\t\tmSysInfo.On(\"allSockets\").Return(nil, errors.New(\"all sockets error\")).Once()\n\t\t\tresult, err := mConfigParser.parseSockets(nil)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"cannot obtain all sockets\")\n\t\t\trequire.Nil(t, result)\n\t\t\tmSysInfo.AssertExpectations(t)\n\t\t})\n\t\tt.Run(\"all cpus gathering succeeded\", func(t *testing.T) {\n\t\t\tallSockets := []int{0, 1, 2, 3, 4}\n\n\t\t\tmSysInfo.On(\"allSockets\").Return(allSockets, nil).Once()\n\t\t\tresult, err := mConfigParser.parseSockets(nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, allSockets, result)\n\t\t\tmSysInfo.AssertExpectations(t)\n\t\t})\n\t})\n}\n\nfunc TestConfigParser_parseEvents(t *testing.T) {\n\tmConfigParser := &configParser{log: testutil.Logger{}}\n\te := ia.CustomizableEvent{}\n\n\ttests := []struct {\n\t\tname   string\n\t\tinput  []string\n\t\tresult []*eventWithQuals\n\t}{\n\t\t{\"no events\", nil, nil},\n\t\t{\"single string\", []string{\"mock string\"}, []*eventWithQuals{{\"mock string\", nil, e}}},\n\t\t{\"two events\", []string{\"EVENT.FIRST\", \"EVENT.SECOND\"}, []*eventWithQuals{{\"EVENT.FIRST\", nil, e}, {\"EVENT.SECOND\", nil, e}}},\n\t\t{\"event with configs\", []string{\"EVENT.SECOND:config1=0x404300k:config2=0x404300k\"},\n\t\t\t[]*eventWithQuals{{\"EVENT.SECOND\", []string{\"config1=0x404300k\", \"config2=0x404300k\"}, e}}},\n\t\t{\"two events with modifiers\", []string{\"EVENT.FIRST:config1=0x200300:config2=0x231100:u:H\", \"EVENT.SECOND:K:p\"},\n\t\t\t[]*eventWithQuals{{\"EVENT.FIRST\", []string{\"config1=0x200300\", \"config2=0x231100\", \"u\", \"H\"}, e}, {\"EVENT.SECOND\", []string{\"K\", \"p\"}, e}}},\n\t\t{\"duplicates\", []string{\"EVENT1\", \"EVENT1\", \"EVENT2\"}, []*eventWithQuals{{\"EVENT1\", nil, e}, {\"EVENT2\", nil, e}}},\n\t\t{\"duplicates with different configs\", []string{\"EVENT1:config1\", \"EVENT1:config2\"},\n\t\t\t[]*eventWithQuals{{\"EVENT1\", []string{\"config1\"}, e}, {\"EVENT1\", []string{\"config2\"}, e}}},\n\t\t{\"duplicates with the same modifiers\", []string{\"EVENT1:config1\", \"EVENT1:config1\"},\n\t\t\t[]*eventWithQuals{{\"EVENT1\", []string{\"config1\"}, e}}},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tresult := mConfigParser.parseEvents(test.input)\n\t\t\trequire.Equal(t, test.result, result)\n\t\t})\n\t}\n}\n\nfunc TestConfigParser_parseIntRanges(t *testing.T) {\n\tmConfigParser := &configParser{log: testutil.Logger{}}\n\ttests := []struct {\n\t\tname    string\n\t\tinput   []string\n\t\tresult  []int\n\t\tfailMsg string\n\t}{\n\t\t{\"coma separated\", []string{\"0,1,2,3,4\"}, []int{0, 1, 2, 3, 4}, \"\"},\n\t\t{\"range\", []string{\"0-10\"}, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, \"\"},\n\t\t{\"mixed\", []string{\"0-3\", \"4\", \"12-16\"}, []int{0, 1, 2, 3, 4, 12, 13, 14, 15, 16}, \"\"},\n\t\t{\"min and max values\", []string{\"-2147483648\", \"2147483647\"}, []int{math.MinInt32, math.MaxInt32}, \"\"},\n\t\t{\"should remove duplicates\", []string{\"1-5\", \"2-6\"}, []int{1, 2, 3, 4, 5, 6}, \"\"},\n\t\t{\"wrong format\", []string{\"1,2,3%$S,-100\"}, nil, \"wrong format for id\"},\n\t\t{\"start is greater than end\", []string{\"10-3\"}, nil, \"`10` is equal or greater than `3\"},\n\t\t{\"too big value\", []string{\"18446744073709551615\"}, nil, \"wrong format for id\"},\n\t\t{\"too much numbers\", []string{fmt.Sprintf(\"0-%d\", maxIDsSize)}, nil,\n\t\t\tfmt.Sprintf(\"requested number of IDs exceeds max size `%d`\", maxIDsSize)},\n\t\t{\"too much numbers mixed\", []string{fmt.Sprintf(\"1-%d\", maxIDsSize), \"0\"}, nil,\n\t\t\tfmt.Sprintf(\"requested number of IDs exceeds max size `%d`\", maxIDsSize)},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tresult, err := mConfigParser.parseIntRanges(test.input)\n\t\t\trequire.Equal(t, test.result, result)\n\t\t\tif len(test.failMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.failMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/intel_pmu.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\tia \"github.com/intel/iaevents\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Linux availability: https://www.kernel.org/doc/Documentation/sysctl/fs.txt\nconst fileMaxPath = \"/proc/sys/fs/file-max\"\n\ntype IntelPMU struct {\n\tEventListPaths []string             `toml:\"event_definitions\"`\n\tCoreEntities   []*coreEventEntity   `toml:\"core_events\"`\n\tUncoreEntities []*uncoreEventEntity `toml:\"uncore_events\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tfileInfo       fileInfoProvider\n\tentitiesReader entitiesValuesReader\n}\n\ntype coreEventEntity struct {\n\tEvents    []string `toml:\"events\"`\n\tCores     []string `toml:\"cores\"`\n\tEventsTag string   `toml:\"events_tag\"`\n\tPerfGroup bool     `toml:\"perf_group\"`\n\n\tparsedEvents []*eventWithQuals\n\tparsedCores  []int\n\tallEvents    bool\n\n\tactiveEvents []*ia.ActiveEvent\n}\n\ntype uncoreEventEntity struct {\n\tEvents    []string `toml:\"events\"`\n\tSockets   []string `toml:\"sockets\"`\n\tAggregate bool     `toml:\"aggregate_uncore_units\"`\n\tEventsTag string   `toml:\"events_tag\"`\n\n\tparsedEvents  []*eventWithQuals\n\tparsedSockets []int\n\tallEvents     bool\n\n\tactiveMultiEvents []multiEvent\n}\n\ntype multiEvent struct {\n\tactiveEvents []*ia.ActiveEvent\n\tperfEvent    *ia.PerfEvent\n\tsocket       int\n}\n\ntype eventWithQuals struct {\n\tname       string\n\tqualifiers []string\n\n\tcustom ia.CustomizableEvent\n}\n\ntype fileInfoProvider interface {\n\treadFile(string) ([]byte, error)\n\tlstat(string) (os.FileInfo, error)\n\tfileLimit() (uint64, error)\n}\n\ntype fileHelper struct{}\n\nfunc (fileHelper) readFile(path string) ([]byte, error) {\n\treturn os.ReadFile(path)\n}\n\nfunc (fileHelper) lstat(path string) (os.FileInfo, error) {\n\treturn os.Lstat(path)\n}\n\nfunc (fileHelper) fileLimit() (uint64, error) {\n\tvar rLimit syscall.Rlimit\n\terr := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)\n\treturn rLimit.Cur, err\n}\n\ntype sysInfoProvider interface {\n\tallCPUs() ([]int, error)\n\tallSockets() ([]int, error)\n}\n\ntype iaSysInfo struct{}\n\nfunc (iaSysInfo) allCPUs() ([]int, error) {\n\treturn ia.AllCPUs()\n}\n\nfunc (iaSysInfo) allSockets() ([]int, error) {\n\treturn ia.AllSockets()\n}\n\nfunc (*IntelPMU) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (i *IntelPMU) Init() error {\n\terr := checkFiles(i.EventListPaths, i.fileInfo)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during event definitions paths validation: %w\", err)\n\t}\n\n\treader, err := newReader(i.Log, i.EventListPaths)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttransformer := ia.NewPerfTransformer()\n\tresolver := &iaEntitiesResolver{reader: reader, transformer: transformer, log: i.Log}\n\tparser := &configParser{log: i.Log, sys: &iaSysInfo{}}\n\tactivator := &iaEntitiesActivator{perfActivator: &iaEventsActivator{}, placementMaker: &iaPlacementMaker{}}\n\n\ti.entitiesReader = &iaEntitiesValuesReader{eventReader: &iaValuesReader{}, timer: &realClock{}}\n\n\treturn i.initialization(parser, resolver, activator)\n}\n\n// Start is required for IntelPMU to implement the telegraf.ServiceInput interface.\n// Necessary initialization and config checking are done in Init.\nfunc (*IntelPMU) Start(_ telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (i *IntelPMU) Gather(acc telegraf.Accumulator) error {\n\tif i.entitiesReader == nil {\n\t\treturn errors.New(\"entities reader is nil\")\n\t}\n\tcoreMetrics, uncoreMetrics, err := i.entitiesReader.readEntities(i.CoreEntities, i.UncoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read entities events values: %w\", err)\n\t}\n\n\tfor id, m := range coreMetrics {\n\t\tscaled := ia.EventScaledValue(m.values)\n\t\tif !scaled.IsUint64() {\n\t\t\treturn fmt.Errorf(\"cannot process %q scaled value %q: exceeds uint64\", m.name, scaled.String())\n\t\t}\n\t\tcoreMetrics[id].scaled = scaled.Uint64()\n\t}\n\tfor id, m := range uncoreMetrics {\n\t\tscaled := ia.EventScaledValue(m.values)\n\t\tif !scaled.IsUint64() {\n\t\t\treturn fmt.Errorf(\"cannot process %q scaled value %q: exceeds uint64\", m.name, scaled.String())\n\t\t}\n\t\tuncoreMetrics[id].scaled = scaled.Uint64()\n\t}\n\n\tpublishCoreMeasurements(coreMetrics, acc)\n\tpublishUncoreMeasurements(uncoreMetrics, acc)\n\n\treturn nil\n}\n\nfunc (i *IntelPMU) Stop() {\n\tfor _, entity := range i.CoreEntities {\n\t\tif entity == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, event := range entity.activeEvents {\n\t\t\tif event == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\terr := event.Deactivate()\n\t\t\tif err != nil {\n\t\t\t\ti.Log.Warnf(\"Failed to deactivate core event %q: %v\", event, err)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, entity := range i.UncoreEntities {\n\t\tif entity == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, multi := range entity.activeMultiEvents {\n\t\t\tfor _, event := range multi.activeEvents {\n\t\t\t\tif event == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\terr := event.Deactivate()\n\t\t\t\tif err != nil {\n\t\t\t\t\ti.Log.Warnf(\"Failed to deactivate uncore event %q: %v\", event, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (i *IntelPMU) initialization(parser entitiesParser, resolver entitiesResolver, activator entitiesActivator) error {\n\tif parser == nil || resolver == nil || activator == nil {\n\t\treturn errors.New(\"entities parser and/or resolver and/or activator is nil\")\n\t}\n\n\terr := parser.parseEntities(i.CoreEntities, i.UncoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during parsing configuration sections: %w\", err)\n\t}\n\n\terr = resolver.resolveEntities(i.CoreEntities, i.UncoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during events resolving: %w\", err)\n\t}\n\n\terr = i.checkFileDescriptors()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during file descriptors checking: %w\", err)\n\t}\n\n\terr = activator.activateEntities(i.CoreEntities, i.UncoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during events activation: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (i *IntelPMU) checkFileDescriptors() error {\n\tcoreFd, err := estimateCoresFd(i.CoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to estimate number of core events file descriptors: %w\", err)\n\t}\n\tuncoreFd, err := estimateUncoreFd(i.UncoreEntities)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to estimate number of uncore events file descriptors: %w\", err)\n\t}\n\tif coreFd > math.MaxUint64-uncoreFd {\n\t\treturn errors.New(\"requested number of file descriptors exceeds uint64\")\n\t}\n\tallFd := coreFd + uncoreFd\n\n\t// maximum file descriptors enforced on a kernel level\n\tmaxFd, err := readMaxFD(i.fileInfo)\n\tif err != nil {\n\t\ti.Log.Warnf(\"Cannot obtain number of available file descriptors: %v\", err)\n\t} else if allFd > maxFd {\n\t\treturn fmt.Errorf(\"required file descriptors number `%d` exceeds maximum number of available file descriptors `%d`\"+\n\t\t\t\": consider increasing the maximum number\", allFd, maxFd)\n\t}\n\n\t// soft limit for current process\n\tlimit, err := i.fileInfo.fileLimit()\n\tif err != nil {\n\t\ti.Log.Warnf(\"Cannot obtain limit value of open files: %v\", err)\n\t} else if allFd > limit {\n\t\treturn fmt.Errorf(\"required file descriptors number `%d` exceeds soft limit of open files `%d`\"+\n\t\t\t\": consider increasing the limit\", allFd, limit)\n\t}\n\n\treturn nil\n}\n\nfunc newReader(log telegraf.Logger, files []string) (*ia.JSONFilesReader, error) {\n\treader := ia.NewFilesReader()\n\tfor _, file := range files {\n\t\terr := reader.AddFiles(file)\n\t\tif err != nil {\n\t\t\tvar deprecatedFormatError *ia.DeprecatedFormatError\n\t\t\tif errors.As(err, &deprecatedFormatError) {\n\t\t\t\tlog.Warnf(\"%v. See the perfmon repo for updated event files\", deprecatedFormatError)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"failed to add files to reader: %w\", err)\n\t\t}\n\t}\n\treturn reader, nil\n}\n\nfunc estimateCoresFd(entities []*coreEventEntity) (uint64, error) {\n\tvar err error\n\tnumber := uint64(0)\n\tfor _, entity := range entities {\n\t\tif entity == nil {\n\t\t\tcontinue\n\t\t}\n\t\tevents := uint64(len(entity.parsedEvents))\n\t\tcores := uint64(len(entity.parsedCores))\n\t\tnumber, err = multiplyAndAdd(events, cores, number)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\treturn number, nil\n}\n\nfunc estimateUncoreFd(entities []*uncoreEventEntity) (uint64, error) {\n\tvar err error\n\tnumber := uint64(0)\n\tfor _, entity := range entities {\n\t\tif entity == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, e := range entity.parsedEvents {\n\t\t\tif e.custom.Event == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpmus := uint64(len(e.custom.Event.PMUTypes))\n\t\t\tsockets := uint64(len(entity.parsedSockets))\n\t\t\tnumber, err = multiplyAndAdd(pmus, sockets, number)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t}\n\t}\n\treturn number, nil\n}\n\nfunc multiplyAndAdd(factorA, factorB, sum uint64) (uint64, error) {\n\tbigA := new(big.Int).SetUint64(factorA)\n\tbigB := new(big.Int).SetUint64(factorB)\n\tactiveEvents := new(big.Int).Mul(bigA, bigB)\n\tif !activeEvents.IsUint64() {\n\t\treturn 0, fmt.Errorf(\"value %q cannot be represented as uint64\", activeEvents.String())\n\t}\n\tif sum > math.MaxUint64-activeEvents.Uint64() {\n\t\treturn 0, fmt.Errorf(\"value %q exceeds uint64\", new(big.Int).Add(activeEvents, new(big.Int).SetUint64(sum)))\n\t}\n\tsum += activeEvents.Uint64()\n\treturn sum, nil\n}\n\nfunc readMaxFD(reader fileInfoProvider) (uint64, error) {\n\tif reader == nil {\n\t\treturn 0, errors.New(\"file reader is nil\")\n\t}\n\tbuf, err := reader.readFile(fileMaxPath)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"cannot open file %q: %w\", fileMaxPath, err)\n\t}\n\tlimit, err := strconv.ParseUint(strings.Trim(string(buf), \"\\n \"), 10, 64)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"cannot parse file content of %q: %w\", fileMaxPath, err)\n\t}\n\treturn limit, nil\n}\n\nfunc checkFiles(paths []string, fileInfo fileInfoProvider) error {\n\t// No event definition JSON locations present\n\tif len(paths) == 0 {\n\t\treturn errors.New(\"no paths were given\")\n\t}\n\tif fileInfo == nil {\n\t\treturn errors.New(\"file info provider is nil\")\n\t}\n\t// Wrong files\n\tfor _, path := range paths {\n\t\tlInfo, err := fileInfo.lstat(path)\n\t\tif err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\treturn fmt.Errorf(\"file %q doesn't exist\", path)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"cannot obtain file info of %q: %w\", path, err)\n\t\t}\n\t\tmode := lInfo.Mode()\n\t\tif mode&os.ModeSymlink != 0 {\n\t\t\treturn fmt.Errorf(\"file %q is a symlink\", path)\n\t\t}\n\t\tif !mode.IsRegular() {\n\t\t\treturn fmt.Errorf(\"file %q doesn't point to a reagular file\", path)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc publishCoreMeasurements(metrics []coreMetric, acc telegraf.Accumulator) {\n\tfor _, m := range metrics {\n\t\tfields := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\tfields[\"raw\"] = m.values.Raw\n\t\tfields[\"enabled\"] = m.values.Enabled\n\t\tfields[\"running\"] = m.values.Running\n\t\tfields[\"scaled\"] = m.scaled\n\n\t\ttags[\"event\"] = m.name\n\t\ttags[\"cpu\"] = strconv.Itoa(m.cpu)\n\n\t\tif len(m.tag) > 0 {\n\t\t\ttags[\"events_tag\"] = m.tag\n\t\t}\n\t\tacc.AddFields(\"pmu_metric\", fields, tags, m.time)\n\t}\n}\n\nfunc publishUncoreMeasurements(metrics []uncoreMetric, acc telegraf.Accumulator) {\n\tfor _, m := range metrics {\n\t\tfields := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\tfields[\"raw\"] = m.values.Raw\n\t\tfields[\"enabled\"] = m.values.Enabled\n\t\tfields[\"running\"] = m.values.Running\n\t\tfields[\"scaled\"] = m.scaled\n\n\t\ttags[\"event\"] = m.name\n\n\t\ttags[\"socket\"] = strconv.Itoa(m.socket)\n\t\ttags[\"unit_type\"] = m.unitType\n\t\tif !m.agg {\n\t\t\ttags[\"unit\"] = m.unit\n\t\t}\n\t\tif len(m.tag) > 0 {\n\t\t\ttags[\"events_tag\"] = m.tag\n\t\t}\n\t\tacc.AddFields(\"pmu_metric\", fields, tags, m.time)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"intel_pmu\", func() telegraf.Input {\n\t\tpmu := IntelPMU{\n\t\t\tfileInfo: &fileHelper{},\n\t\t}\n\t\treturn &pmu\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/intel_pmu_notamd64linux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux || !amd64\n\npackage intel_pmu\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IntelPMU struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*IntelPMU) SampleConfig() string { return sampleConfig }\n\nfunc (i *IntelPMU) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*IntelPMU) Start(_ telegraf.Accumulator) error { return nil }\n\nfunc (*IntelPMU) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc (*IntelPMU) Stop() {}\n\nfunc init() {\n\tinputs.Add(\"intel_pmu\", func() telegraf.Input {\n\t\treturn &IntelPMU{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/intel_pmu_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInitialization(t *testing.T) {\n\tmError := errors.New(\"mock error\")\n\tmParser := &mockEntitiesParser{}\n\tmResolver := &mockEntitiesResolver{}\n\tmActivator := &mockEntitiesActivator{}\n\tmFileInfo := &mockFileInfoProvider{}\n\n\tfile := \"path/to/file\"\n\tpaths := []string{file}\n\n\tt.Run(\"missing parser, resolver or activator\", func(t *testing.T) {\n\t\terr := (&IntelPMU{}).initialization(mParser, nil, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entities parser and/or resolver and/or activator is nil\")\n\t\terr = (&IntelPMU{}).initialization(nil, mResolver, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entities parser and/or resolver and/or activator is nil\")\n\t\terr = (&IntelPMU{}).initialization(nil, nil, mActivator)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entities parser and/or resolver and/or activator is nil\")\n\t})\n\n\tt.Run(\"parse entities error\", func(t *testing.T) {\n\t\tmIntelPMU := &IntelPMU{EventListPaths: paths, fileInfo: mFileInfo}\n\n\t\tmParser.On(\"parseEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(mError).Once()\n\n\t\terr := mIntelPMU.initialization(mParser, mResolver, mActivator)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"error during parsing configuration sections\")\n\t\tmParser.AssertExpectations(t)\n\t})\n\n\tt.Run(\"resolver error\", func(t *testing.T) {\n\t\tmIntelPMU := &IntelPMU{EventListPaths: paths, fileInfo: mFileInfo}\n\n\t\tmParser.On(\"parseEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmResolver.On(\"resolveEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(mError).Once()\n\n\t\terr := mIntelPMU.initialization(mParser, mResolver, mActivator)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"error during events resolving\")\n\t\tmParser.AssertExpectations(t)\n\t})\n\n\tt.Run(\"exceeded file descriptors\", func(t *testing.T) {\n\t\tlimit := []byte(\"10\")\n\t\tuncoreEntities := []*uncoreEventEntity{{parsedEvents: makeEvents(10, 21), parsedSockets: makeIDs(5)}}\n\t\testimation := 1050\n\n\t\tmIntelPMU := IntelPMU{EventListPaths: paths, Log: testutil.Logger{}, fileInfo: mFileInfo, UncoreEntities: uncoreEntities}\n\n\t\tmParser.On(\"parseEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmResolver.On(\"resolveEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmFileInfo.On(\"readFile\", fileMaxPath).Return(limit, nil).Once()\n\n\t\terr := mIntelPMU.initialization(mParser, mResolver, mActivator)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"required file descriptors number `%d` exceeds maximum number of available file descriptors `%d`\"+\n\t\t\t\": consider increasing the maximum number\", estimation, 10))\n\t\tmFileInfo.AssertExpectations(t)\n\t\tmParser.AssertExpectations(t)\n\t\tmResolver.AssertExpectations(t)\n\t})\n\n\tt.Run(\"failed to activate entities\", func(t *testing.T) {\n\t\tmIntelPMU := IntelPMU{EventListPaths: paths, Log: testutil.Logger{}, fileInfo: mFileInfo}\n\n\t\tmParser.On(\"parseEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmResolver.On(\"resolveEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmActivator.On(\"activateEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(mError).Once()\n\t\tmFileInfo.On(\"readFile\", fileMaxPath).Return(nil, mError).\n\t\t\tOn(\"fileLimit\").Return(uint64(0), mError).Once()\n\n\t\terr := mIntelPMU.initialization(mParser, mResolver, mActivator)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"error during events activation\")\n\t\tmFileInfo.AssertExpectations(t)\n\t\tmParser.AssertExpectations(t)\n\t\tmResolver.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n\n\tt.Run(\"everything all right\", func(t *testing.T) {\n\t\tmIntelPMU := IntelPMU{EventListPaths: paths, Log: testutil.Logger{}, fileInfo: mFileInfo}\n\n\t\tmParser.On(\"parseEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmResolver.On(\"resolveEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\t\tmFileInfo.On(\"readFile\", fileMaxPath).Return(nil, mError).\n\t\t\tOn(\"fileLimit\").Return(uint64(0), mError).Once()\n\t\tmActivator.On(\"activateEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).Return(nil).Once()\n\n\t\terr := mIntelPMU.initialization(mParser, mResolver, mActivator)\n\t\trequire.NoError(t, err)\n\t\tmFileInfo.AssertExpectations(t)\n\t\tmParser.AssertExpectations(t)\n\t\tmResolver.AssertExpectations(t)\n\t\tmActivator.AssertExpectations(t)\n\t})\n}\n\nfunc TestGather(t *testing.T) {\n\tmEntitiesValuesReader := &mockEntitiesValuesReader{}\n\tmAcc := &testutil.Accumulator{}\n\n\tmIntelPMU := &IntelPMU{entitiesReader: mEntitiesValuesReader}\n\n\ttype fieldWithTags struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}\n\n\tt.Run(\"entities reader is nil\", func(t *testing.T) {\n\t\terr := (&IntelPMU{entitiesReader: nil}).Gather(mAcc)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entities reader is nil\")\n\t})\n\n\tt.Run(\"error while reading entities\", func(t *testing.T) {\n\t\terrMock := errors.New(\"houston we have a problem\")\n\t\tmEntitiesValuesReader.On(\"readEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).\n\t\t\tReturn(nil, nil, errMock).Once()\n\n\t\terr := mIntelPMU.Gather(mAcc)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to read entities events values: %v\", errMock))\n\t\tmEntitiesValuesReader.AssertExpectations(t)\n\t})\n\n\ttests := []struct {\n\t\tname          string\n\t\tcoreMetrics   []coreMetric\n\t\tuncoreMetrics []uncoreMetric\n\t\tresults       []fieldWithTags\n\t\terrMSg        string\n\t}{\n\t\t{\n\t\t\tname: \"successful readings\",\n\t\t\tcoreMetrics: []coreMetric{\n\t\t\t\t{\n\t\t\t\t\tvalues: ia.CounterValue{Raw: 100, Enabled: 200, Running: 200},\n\t\t\t\t\tname:   \"CORE_EVENT_1\",\n\t\t\t\t\ttag:    \"DOGES\",\n\t\t\t\t\tcpu:    1,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tvalues: ia.CounterValue{Raw: 2100, Enabled: 400, Running: 200},\n\t\t\t\t\tname:   \"CORE_EVENT_2\",\n\t\t\t\t\tcpu:    0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tuncoreMetrics: []uncoreMetric{\n\t\t\t\t{\n\t\t\t\t\tvalues:   ia.CounterValue{Raw: 2134562, Enabled: 1000000, Running: 1000000},\n\t\t\t\t\tname:     \"UNCORE_EVENT_1\",\n\t\t\t\t\ttag:      \"SHIBA\",\n\t\t\t\t\tunitType: \"cbox\",\n\t\t\t\t\tunit:     \"cbox_1\",\n\t\t\t\t\tsocket:   3,\n\t\t\t\t\tagg:      false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tvalues:   ia.CounterValue{Raw: 2134562, Enabled: 3222222, Running: 2100000},\n\t\t\t\t\tname:     \"UNCORE_EVENT_2\",\n\t\t\t\t\tunitType: \"cbox\",\n\t\t\t\t\tsocket:   0,\n\t\t\t\t\tagg:      true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tresults: []fieldWithTags{\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"raw\":     uint64(100),\n\t\t\t\t\t\t\"enabled\": uint64(200),\n\t\t\t\t\t\t\"running\": uint64(200),\n\t\t\t\t\t\t\"scaled\":  uint64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"event\":      \"CORE_EVENT_1\",\n\t\t\t\t\t\t\"cpu\":        \"1\",\n\t\t\t\t\t\t\"events_tag\": \"DOGES\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"raw\":     uint64(2100),\n\t\t\t\t\t\t\"enabled\": uint64(400),\n\t\t\t\t\t\t\"running\": uint64(200),\n\t\t\t\t\t\t\"scaled\":  uint64(4200),\n\t\t\t\t\t},\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"event\": \"CORE_EVENT_2\",\n\t\t\t\t\t\t\"cpu\":   \"0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"raw\":     uint64(2134562),\n\t\t\t\t\t\t\"enabled\": uint64(1000000),\n\t\t\t\t\t\t\"running\": uint64(1000000),\n\t\t\t\t\t\t\"scaled\":  uint64(2134562),\n\t\t\t\t\t},\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"event\":      \"UNCORE_EVENT_1\",\n\t\t\t\t\t\t\"events_tag\": \"SHIBA\",\n\t\t\t\t\t\t\"socket\":     \"3\",\n\t\t\t\t\t\t\"unit_type\":  \"cbox\",\n\t\t\t\t\t\t\"unit\":       \"cbox_1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"raw\":     uint64(2134562),\n\t\t\t\t\t\t\"enabled\": uint64(3222222),\n\t\t\t\t\t\t\"running\": uint64(2100000),\n\t\t\t\t\t\t\"scaled\":  uint64(3275253),\n\t\t\t\t\t},\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"event\":     \"UNCORE_EVENT_2\",\n\t\t\t\t\t\t\"socket\":    \"0\",\n\t\t\t\t\t\t\"unit_type\": \"cbox\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"core scaled value greater then max uint64\",\n\t\t\tcoreMetrics: []coreMetric{\n\t\t\t\t{\n\t\t\t\t\tvalues: ia.CounterValue{Raw: math.MaxUint64, Enabled: 400000, Running: 200000},\n\t\t\t\t\tname:   \"I_AM_TOO_BIG\",\n\t\t\t\t\ttag:    \"BIG_FISH\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrMSg: `cannot process \"I_AM_TOO_BIG\" scaled value \"36893488147419103230\": exceeds uint64`,\n\t\t},\n\t\t{\n\t\t\tname: \"uncore scaled value greater then max uint64\",\n\t\t\tuncoreMetrics: []uncoreMetric{\n\t\t\t\t{\n\t\t\t\t\tvalues: ia.CounterValue{Raw: math.MaxUint64, Enabled: 400000, Running: 200000},\n\t\t\t\t\tname:   \"I_AM_TOO_BIG_UNCORE\",\n\t\t\t\t\ttag:    \"BIG_FISH\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrMSg: `cannot process \"I_AM_TOO_BIG_UNCORE\" scaled value \"36893488147419103230\": exceeds uint64`,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmEntitiesValuesReader.On(\"readEntities\", mIntelPMU.CoreEntities, mIntelPMU.UncoreEntities).\n\t\t\t\tReturn(test.coreMetrics, test.uncoreMetrics, nil).Once()\n\n\t\t\terr := mIntelPMU.Gather(mAcc)\n\n\t\t\tmEntitiesValuesReader.AssertExpectations(t)\n\t\t\tif len(test.errMSg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.errMSg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tfor _, result := range test.results {\n\t\t\t\tmAcc.AssertContainsTaggedFields(t, \"pmu_metric\", result.fields, result.tags)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCheckFileDescriptors(t *testing.T) {\n\ttests := []struct {\n\t\tname       string\n\t\tuncores    []*uncoreEventEntity\n\t\tcores      []*coreEventEntity\n\t\testimation uint64\n\t\tmaxFD      []byte\n\t\tfileLimit  uint64\n\t\terrMsg     string\n\t}{\n\t\t{\"exceed maximum file descriptors number\", []*uncoreEventEntity{\n\t\t\t{parsedEvents: makeEvents(100, 21), parsedSockets: makeIDs(5)},\n\t\t\t{parsedEvents: makeEvents(25, 3), parsedSockets: makeIDs(7)},\n\t\t\t{parsedEvents: makeEvents(2, 7), parsedSockets: makeIDs(20)}},\n\t\t\t[]*coreEventEntity{\n\t\t\t\t{parsedEvents: makeEvents(100, 1), parsedCores: makeIDs(5)},\n\t\t\t\t{parsedEvents: makeEvents(25, 1), parsedCores: makeIDs(7)},\n\t\t\t\t{parsedEvents: makeEvents(2, 1), parsedCores: makeIDs(20)}},\n\t\t\t12020, []byte(\"11000\"), 8000, fmt.Sprintf(\"required file descriptors number `%d` exceeds maximum number of available file descriptors `%d`\"+\n\t\t\t\t\": consider increasing the maximum number\", 12020, 11000),\n\t\t},\n\t\t{\"exceed soft file limit\", []*uncoreEventEntity{{parsedEvents: makeEvents(100, 21), parsedSockets: makeIDs(5)}}, []*coreEventEntity{\n\t\t\t{parsedEvents: makeEvents(100, 1), parsedCores: makeIDs(5)}},\n\t\t\t11000, []byte(\"2515357\"), 800, fmt.Sprintf(\"required file descriptors number `%d` exceeds soft limit of open files `%d`\"+\n\t\t\t\t\": consider increasing the limit\", 11000, 800),\n\t\t},\n\t\t{\"no exceeds\", []*uncoreEventEntity{{parsedEvents: makeEvents(100, 21), parsedSockets: makeIDs(5)}},\n\t\t\t[]*coreEventEntity{{parsedEvents: makeEvents(100, 1), parsedCores: makeIDs(5)}},\n\t\t\t11000, []byte(\"2515357\"), 13000, \"\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmFileInfo := &mockFileInfoProvider{}\n\t\t\tmIntelPMU := IntelPMU{\n\t\t\t\tCoreEntities:   test.cores,\n\t\t\t\tUncoreEntities: test.uncores,\n\t\t\t\tfileInfo:       mFileInfo,\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t}\n\t\t\tmFileInfo.On(\"readFile\", fileMaxPath).Return(test.maxFD, nil).\n\t\t\t\tOn(\"fileLimit\").Return(test.fileLimit, nil).Once()\n\n\t\t\terr := mIntelPMU.checkFileDescriptors()\n\t\t\tif len(test.errMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.errMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tmFileInfo.AssertExpectations(t)\n\t\t})\n\t}\n}\n\nfunc TestEstimateUncoreFd(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tentities []*uncoreEventEntity\n\t\tresult   uint64\n\t}{\n\t\t{\"nil entities\", nil, 0},\n\t\t{\"nil perf event\", []*uncoreEventEntity{{parsedEvents: []*eventWithQuals{{\"\", nil, ia.CustomizableEvent{}}}, parsedSockets: makeIDs(0)}}, 0},\n\t\t{\"one uncore entity\", []*uncoreEventEntity{{parsedEvents: makeEvents(10, 10), parsedSockets: makeIDs(20)}}, 2000},\n\t\t{\"nil entity\", []*uncoreEventEntity{nil, {parsedEvents: makeEvents(1, 8), parsedSockets: makeIDs(1)}}, 8},\n\t\t{\"many core entities\", []*uncoreEventEntity{\n\t\t\t{parsedEvents: makeEvents(100, 21), parsedSockets: makeIDs(5)},\n\t\t\t{parsedEvents: makeEvents(25, 3), parsedSockets: makeIDs(7)},\n\t\t\t{parsedEvents: makeEvents(2, 7), parsedSockets: makeIDs(20)},\n\t\t}, 11305},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmIntelPMU := IntelPMU{UncoreEntities: test.entities}\n\t\t\tresult, err := estimateUncoreFd(mIntelPMU.UncoreEntities)\n\t\t\trequire.Equal(t, test.result, result)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestEstimateCoresFd(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tentities []*coreEventEntity\n\t\tresult   uint64\n\t}{\n\t\t{\"nil entities\", nil, 0},\n\t\t{\"one core entity\", []*coreEventEntity{{parsedEvents: makeEvents(10, 1), parsedCores: makeIDs(20)}}, 200},\n\t\t{\"nil entity\", []*coreEventEntity{nil, {parsedEvents: makeEvents(10, 1), parsedCores: makeIDs(20)}}, 200},\n\t\t{\"many core entities\", []*coreEventEntity{\n\t\t\t{parsedEvents: makeEvents(100, 1), parsedCores: makeIDs(5)},\n\t\t\t{parsedEvents: makeEvents(25, 1), parsedCores: makeIDs(7)},\n\t\t\t{parsedEvents: makeEvents(2, 1), parsedCores: makeIDs(20)},\n\t\t}, 715},\n\t\t{\"1024 events\", []*coreEventEntity{{parsedEvents: makeEvents(1024, 1), parsedCores: makeIDs(12)}}, 12288},\n\t\t{\"big number\", []*coreEventEntity{{parsedEvents: makeEvents(1024, 1), parsedCores: makeIDs(1048576)}}, 1073741824},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmIntelPMU := IntelPMU{CoreEntities: test.entities}\n\t\t\tresult, err := estimateCoresFd(mIntelPMU.CoreEntities)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.result, result)\n\t\t})\n\t}\n}\n\nfunc makeEvents(number, pmusNumber int) []*eventWithQuals {\n\ta := make([]*eventWithQuals, number)\n\tfor i := range a {\n\t\tb := make([]ia.NamedPMUType, pmusNumber)\n\t\tfor j := range b {\n\t\t\tb[j] = ia.NamedPMUType{}\n\t\t}\n\t\ta[i] = &eventWithQuals{fmt.Sprintf(\"EVENT.%d\", i), nil,\n\t\t\tia.CustomizableEvent{Event: &ia.PerfEvent{PMUTypes: b}},\n\t\t}\n\t}\n\treturn a\n}\n\nfunc makeIDs(number int) []int {\n\ta := make([]int, number)\n\tfor i := range a {\n\t\ta[i] = i\n\t}\n\treturn a\n}\n\nfunc TestReadMaxFD(t *testing.T) {\n\tmFileReader := &mockFileInfoProvider{}\n\n\tt.Run(\"reader is nil\", func(t *testing.T) {\n\t\tresult, err := readMaxFD(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"file reader is nil\")\n\t\trequire.Zero(t, result)\n\t})\n\n\topenErrorMsg := fmt.Sprintf(\"cannot open file %q\", fileMaxPath)\n\tparseErrorMsg := fmt.Sprintf(\"cannot parse file content of %q\", fileMaxPath)\n\n\ttests := []struct {\n\t\tname    string\n\t\terr     error\n\t\tcontent []byte\n\t\tmaxFD   uint64\n\t\tfailMsg string\n\t}{\n\t\t{\"read file error\", errors.New(\"mock error\"), nil, 0, openErrorMsg},\n\t\t{\"file content parse error\", nil, []byte(\"wrong format\"), 0, parseErrorMsg},\n\t\t{\"negative value reading\", nil, []byte(\"-10000\"), 0, parseErrorMsg},\n\t\t{\"max uint exceeded\", nil, []byte(\"18446744073709551616\"), 0, parseErrorMsg},\n\t\t{\"reading succeeded\", nil, []byte(\"12343122\"), 12343122, \"\"},\n\t\t{\"min value reading\", nil, []byte(\"0\"), 0, \"\"},\n\t\t{\"max uint 64 reading\", nil, []byte(\"18446744073709551615\"), math.MaxUint64, \"\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tmFileReader.On(\"readFile\", fileMaxPath).Return(test.content, test.err).Once()\n\t\t\tresult, err := readMaxFD(mFileReader)\n\n\t\t\tif len(test.failMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.failMsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\trequire.Equal(t, test.maxFD, result)\n\t\t\tmFileReader.AssertExpectations(t)\n\t\t})\n\t}\n}\n\nfunc TestAddFiles(t *testing.T) {\n\tmFileInfo := &mockFileInfoProvider{}\n\tmError := errors.New(\"mock error\")\n\n\tt.Run(\"no paths\", func(t *testing.T) {\n\t\terr := checkFiles(nil, mFileInfo)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"no paths were given\")\n\t})\n\n\tt.Run(\"no file info provider\", func(t *testing.T) {\n\t\terr := checkFiles([]string{\"path/1, path/2\"}, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"file info provider is nil\")\n\t})\n\n\tt.Run(\"stat error\", func(t *testing.T) {\n\t\tfile := \"path/to/file\"\n\t\tpaths := []string{file}\n\t\tmFileInfo.On(\"lstat\", file).Return(nil, mError).Once()\n\n\t\terr := checkFiles(paths, mFileInfo)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"cannot obtain file info of %q\", file))\n\t\tmFileInfo.AssertExpectations(t)\n\t})\n\n\tt.Run(\"file does not exist\", func(t *testing.T) {\n\t\tfile := \"path/to/file\"\n\t\tpaths := []string{file}\n\t\tmFileInfo.On(\"lstat\", file).Return(nil, os.ErrNotExist).Once()\n\n\t\terr := checkFiles(paths, mFileInfo)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"file %q doesn't exist\", file))\n\t\tmFileInfo.AssertExpectations(t)\n\t})\n\n\tt.Run(\"file is symlink\", func(t *testing.T) {\n\t\tfile := \"path/to/symlink\"\n\t\tpaths := []string{file}\n\t\tfileInfo := fakeFileInfo{fileMode: os.ModeSymlink}\n\t\tmFileInfo.On(\"lstat\", file).Return(fileInfo, nil).Once()\n\n\t\terr := checkFiles(paths, mFileInfo)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"file %q is a symlink\", file))\n\t\tmFileInfo.AssertExpectations(t)\n\t})\n\n\tt.Run(\"file doesn't point to a regular file\", func(t *testing.T) {\n\t\tfile := \"path/to/file\"\n\t\tpaths := []string{file}\n\t\tfileInfo := fakeFileInfo{fileMode: os.ModeDir}\n\t\tmFileInfo.On(\"lstat\", file).Return(fileInfo, nil).Once()\n\n\t\terr := checkFiles(paths, mFileInfo)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"file %q doesn't point to a reagular file\", file))\n\t\tmFileInfo.AssertExpectations(t)\n\t})\n\n\tt.Run(\"checking succeeded\", func(t *testing.T) {\n\t\tpaths := []string{\"path/to/file1\", \"path/to/file2\", \"path/to/file3\"}\n\t\tfileInfo := fakeFileInfo{}\n\n\t\tfor _, file := range paths {\n\t\t\tmFileInfo.On(\"lstat\", file).Return(fileInfo, nil).Once()\n\t\t}\n\n\t\terr := checkFiles(paths, mFileInfo)\n\t\trequire.NoError(t, err)\n\t\tmFileInfo.AssertExpectations(t)\n\t})\n}\n\ntype fakeFileInfo struct {\n\tfileMode os.FileMode\n}\n\nfunc (fakeFileInfo) Name() string        { return \"\" }\nfunc (fakeFileInfo) Size() int64         { return 0 }\nfunc (f fakeFileInfo) Mode() os.FileMode { return f.fileMode }\nfunc (fakeFileInfo) ModTime() time.Time  { return time.Time{} }\nfunc (fakeFileInfo) IsDir() bool         { return false }\nfunc (fakeFileInfo) Sys() interface{}    { return nil }\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/mocks.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"os\"\n\n\t\"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockValuesReader is an autogenerated mock type for the valuesReader type\ntype mockValuesReader struct {\n\tmock.Mock\n}\n\n// readValue provides a mock function with given fields: event\nfunc (_m *mockValuesReader) readValue(event *iaevents.ActiveEvent) (iaevents.CounterValue, error) {\n\tret := _m.Called(event)\n\n\tvar r0 iaevents.CounterValue\n\tif rf, ok := ret.Get(0).(func(*iaevents.ActiveEvent) iaevents.CounterValue); ok {\n\t\tr0 = rf(event)\n\t} else {\n\t\tr0 = ret.Get(0).(iaevents.CounterValue)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(*iaevents.ActiveEvent) error); ok {\n\t\tr1 = rf(event)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// mockEntitiesValuesReader is an autogenerated mock type for the entitiesValuesReader type\ntype mockEntitiesValuesReader struct {\n\tmock.Mock\n}\n\n// readEntities provides a mock function with given fields: _a0, _a1\nfunc (_m *mockEntitiesValuesReader) readEntities(_a0 []*coreEventEntity, _a1 []*uncoreEventEntity) ([]coreMetric, []uncoreMetric, error) {\n\tret := _m.Called(_a0, _a1)\n\n\tvar r0 []coreMetric\n\tif rf, ok := ret.Get(0).(func([]*coreEventEntity, []*uncoreEventEntity) []coreMetric); ok {\n\t\tr0 = rf(_a0, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]coreMetric)\n\t\t}\n\t}\n\n\tvar r1 []uncoreMetric\n\tif rf, ok := ret.Get(1).(func([]*coreEventEntity, []*uncoreEventEntity) []uncoreMetric); ok {\n\t\tr1 = rf(_a0, _a1)\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).([]uncoreMetric)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func([]*coreEventEntity, []*uncoreEventEntity) error); ok {\n\t\tr2 = rf(_a0, _a1)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// mockEntitiesActivator is an autogenerated mock type for the entitiesActivator type\ntype mockEntitiesActivator struct {\n\tmock.Mock\n}\n\n// activateEntities provides a mock function with given fields: coreEntities, uncoreEntities\nfunc (_m *mockEntitiesActivator) activateEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {\n\tret := _m.Called(coreEntities, uncoreEntities)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func([]*coreEventEntity, []*uncoreEventEntity) error); ok {\n\t\tr0 = rf(coreEntities, uncoreEntities)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// mockEntitiesParser is an autogenerated mock type for the entitiesParser type\ntype mockEntitiesParser struct {\n\tmock.Mock\n}\n\n// parseEntities provides a mock function with given fields: coreEntities, uncoreEntities\nfunc (_m *mockEntitiesParser) parseEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {\n\tret := _m.Called(coreEntities, uncoreEntities)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func([]*coreEventEntity, []*uncoreEventEntity) error); ok {\n\t\tr0 = rf(coreEntities, uncoreEntities)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// mockEntitiesResolver is an autogenerated mock type for the entitiesResolver type\ntype mockEntitiesResolver struct {\n\tmock.Mock\n}\n\n// resolveEntities provides a mock function with given fields: coreEntities, uncoreEntities\nfunc (_m *mockEntitiesResolver) resolveEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {\n\tret := _m.Called(coreEntities, uncoreEntities)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func([]*coreEventEntity, []*uncoreEventEntity) error); ok {\n\t\tr0 = rf(coreEntities, uncoreEntities)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// mockEventsActivator is an autogenerated mock type for the eventsActivator type\ntype mockEventsActivator struct {\n\tmock.Mock\n}\n\n// activateEvent provides a mock function with given fields: _a0, _a1, _a2\nfunc (_m *mockEventsActivator) activateEvent(_a0 iaevents.Activator, _a1 iaevents.PlacementProvider, _a2 iaevents.Options) (*iaevents.ActiveEvent, error) {\n\tret := _m.Called(_a0, _a1, _a2)\n\n\tvar r0 *iaevents.ActiveEvent\n\tif rf, ok := ret.Get(0).(func(iaevents.Activator, iaevents.PlacementProvider, iaevents.Options) *iaevents.ActiveEvent); ok {\n\t\tr0 = rf(_a0, _a1, _a2)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*iaevents.ActiveEvent)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(iaevents.Activator, iaevents.PlacementProvider, iaevents.Options) error); ok {\n\t\tr1 = rf(_a0, _a1, _a2)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// activateGroup provides a mock function with given fields: _a0, _a1\nfunc (_m *mockEventsActivator) activateGroup(_a0 iaevents.PlacementProvider, _a1 []iaevents.CustomizableEvent) (*iaevents.ActiveEventGroup, error) {\n\tret := _m.Called(_a0, _a1)\n\n\tvar r0 *iaevents.ActiveEventGroup\n\tif rf, ok := ret.Get(0).(func(iaevents.PlacementProvider, []iaevents.CustomizableEvent) *iaevents.ActiveEventGroup); ok {\n\t\tr0 = rf(_a0, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*iaevents.ActiveEventGroup)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(iaevents.PlacementProvider, []iaevents.CustomizableEvent) error); ok {\n\t\tr1 = rf(_a0, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// activateMulti provides a mock function with given fields: _a0, _a1, _a2\nfunc (_m *mockEventsActivator) activateMulti(\n\t_a0 iaevents.MultiActivator,\n\t_a1 []iaevents.PlacementProvider,\n\t_a2 iaevents.Options,\n) (*iaevents.ActiveMultiEvent, error) {\n\tret := _m.Called(_a0, _a1, _a2)\n\n\tvar r0 *iaevents.ActiveMultiEvent\n\tif rf, ok := ret.Get(0).(func(iaevents.MultiActivator, []iaevents.PlacementProvider, iaevents.Options) *iaevents.ActiveMultiEvent); ok {\n\t\tr0 = rf(_a0, _a1, _a2)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*iaevents.ActiveMultiEvent)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(iaevents.MultiActivator, []iaevents.PlacementProvider, iaevents.Options) error); ok {\n\t\tr1 = rf(_a0, _a1, _a2)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// mockFileInfoProvider is an autogenerated mock type for the fileInfoProvider type\ntype mockFileInfoProvider struct {\n\tmock.Mock\n}\n\n// fileLimit provides a mock function with given fields:\nfunc (_m *mockFileInfoProvider) fileLimit() (uint64, error) {\n\tret := _m.Called()\n\n\tvar r0 uint64\n\tif rf, ok := ret.Get(0).(func() uint64); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(uint64)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// readFile provides a mock function with given fields: _a0\nfunc (_m *mockFileInfoProvider) readFile(_a0 string) ([]byte, error) {\n\tret := _m.Called(_a0)\n\n\tvar r0 []byte\n\tif rf, ok := ret.Get(0).(func(string) []byte); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(_a0)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// lstat provides a mock function with given fields: _a0\nfunc (_m *mockFileInfoProvider) lstat(_a0 string) (os.FileInfo, error) {\n\tret := _m.Called(_a0)\n\n\tvar r0 os.FileInfo\n\tif rf, ok := ret.Get(0).(func(string) os.FileInfo); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(os.FileInfo)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(_a0)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// mockPlacementMaker is an autogenerated mock type for the placementMaker type\ntype mockPlacementMaker struct {\n\tmock.Mock\n}\n\n// makeCorePlacements provides a mock function with given fields: cores, perfEvent\nfunc (_m *mockPlacementMaker) makeCorePlacements(cores []int, factory iaevents.PlacementFactory) ([]iaevents.PlacementProvider, error) {\n\tret := _m.Called(cores, factory)\n\n\tvar r0 []iaevents.PlacementProvider\n\tif rf, ok := ret.Get(0).(func([]int, iaevents.PlacementFactory) []iaevents.PlacementProvider); ok {\n\t\tr0 = rf(cores, factory)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]iaevents.PlacementProvider)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func([]int, iaevents.PlacementFactory) error); ok {\n\t\tr1 = rf(cores, factory)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// makeUncorePlacements provides a mock function with given fields: factory, socket\nfunc (_m *mockPlacementMaker) makeUncorePlacements(socket int, factory iaevents.PlacementFactory) ([]iaevents.PlacementProvider, error) {\n\tret := _m.Called(factory, socket)\n\n\tvar r0 []iaevents.PlacementProvider\n\tif rf, ok := ret.Get(0).(func(iaevents.PlacementFactory, int) []iaevents.PlacementProvider); ok {\n\t\tr0 = rf(factory, socket)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]iaevents.PlacementProvider)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(iaevents.PlacementFactory, int) error); ok {\n\t\tr1 = rf(factory, socket)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// mockSysInfoProvider is an autogenerated mock type for the sysInfoProvider type\ntype mockSysInfoProvider struct {\n\tmock.Mock\n}\n\n// allCPUs provides a mock function with given fields:\nfunc (_m *mockSysInfoProvider) allCPUs() ([]int, error) {\n\tret := _m.Called()\n\n\tvar r0 []int\n\tif rf, ok := ret.Get(0).(func() []int); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]int)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// allSockets provides a mock function with given fields:\nfunc (_m *mockSysInfoProvider) allSockets() ([]int, error) {\n\tret := _m.Called()\n\n\tvar r0 []int\n\tif rf, ok := ret.Get(0).(func() []int); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]int)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// MockTransformer is an autogenerated mock type for the Transformer type\ntype MockTransformer struct {\n\tmock.Mock\n}\n\n// Transform provides a mock function with given fields: reader, matcher\nfunc (_m *MockTransformer) Transform(reader iaevents.Reader, matcher iaevents.Matcher) ([]*iaevents.PerfEvent, error) {\n\tret := _m.Called(reader, matcher)\n\n\tvar r0 []*iaevents.PerfEvent\n\tif rf, ok := ret.Get(0).(func(iaevents.Reader, iaevents.Matcher) []*iaevents.PerfEvent); ok {\n\t\tr0 = rf(reader, matcher)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*iaevents.PerfEvent)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(iaevents.Reader, iaevents.Matcher) error); ok {\n\t\tr1 = rf(reader, matcher)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/reader.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"golang.org/x/sync/errgroup\"\n)\n\ntype coreMetric struct {\n\tvalues ia.CounterValue\n\tscaled uint64\n\n\tname string\n\ttag  string\n\tcpu  int\n\n\ttime time.Time\n}\n\ntype uncoreMetric struct {\n\tvalues ia.CounterValue\n\tscaled uint64\n\n\tname     string\n\tunitType string\n\tunit     string\n\ttag      string\n\tsocket   int\n\n\tagg bool\n\n\ttime time.Time\n}\n\ntype valuesReader interface {\n\treadValue(event *ia.ActiveEvent) (ia.CounterValue, error)\n}\n\ntype iaValuesReader struct{}\n\nfunc (iaValuesReader) readValue(event *ia.ActiveEvent) (ia.CounterValue, error) {\n\treturn event.ReadValue()\n}\n\ntype entitiesValuesReader interface {\n\treadEntities([]*coreEventEntity, []*uncoreEventEntity) ([]coreMetric, []uncoreMetric, error)\n}\n\ntype iaEntitiesValuesReader struct {\n\teventReader valuesReader\n\ttimer       clock\n}\n\ntype clock interface {\n\tnow() time.Time\n}\n\ntype realClock struct{}\n\nfunc (realClock) now() time.Time {\n\treturn time.Now()\n}\n\nfunc (ie *iaEntitiesValuesReader) readEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) ([]coreMetric, []uncoreMetric, error) {\n\tvar coreMetrics []coreMetric\n\tvar uncoreMetrics []uncoreMetric\n\n\tfor _, entity := range coreEntities {\n\t\tnewMetrics, err := ie.readCoreEvents(entity)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tcoreMetrics = append(coreMetrics, newMetrics...)\n\t}\n\tfor _, entity := range uncoreEntities {\n\t\tnewMetrics, err := ie.readUncoreEvents(entity)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tuncoreMetrics = append(uncoreMetrics, newMetrics...)\n\t}\n\treturn coreMetrics, uncoreMetrics, nil\n}\n\nfunc (ie *iaEntitiesValuesReader) readCoreEvents(entity *coreEventEntity) ([]coreMetric, error) {\n\tif ie.eventReader == nil || ie.timer == nil {\n\t\treturn nil, errors.New(\"event values reader or timer is nil\")\n\t}\n\tif entity == nil {\n\t\treturn nil, errors.New(\"entity is nil\")\n\t}\n\tmetrics := make([]coreMetric, len(entity.activeEvents))\n\terrGroup := errgroup.Group{}\n\n\tfor id, actualEvent := range entity.activeEvents {\n\t\tif actualEvent == nil || actualEvent.PerfEvent == nil {\n\t\t\treturn nil, errors.New(\"active event or corresponding perf event is nil\")\n\t\t}\n\n\t\terrGroup.Go(func() error {\n\t\t\tvalues, err := ie.eventReader.readValue(actualEvent)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to read core event %q values: %w\", actualEvent, err)\n\t\t\t}\n\t\t\tcpu, _ := actualEvent.PMUPlacement()\n\t\t\tnewMetric := coreMetric{\n\t\t\t\tvalues: values,\n\t\t\t\ttag:    entity.EventsTag,\n\t\t\t\tcpu:    cpu,\n\t\t\t\tname:   actualEvent.PerfEvent.Name,\n\t\t\t\ttime:   ie.timer.now(),\n\t\t\t}\n\t\t\tmetrics[id] = newMetric\n\t\t\treturn nil\n\t\t})\n\t}\n\terr := errGroup.Wait()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn metrics, nil\n}\n\nfunc (ie *iaEntitiesValuesReader) readUncoreEvents(entity *uncoreEventEntity) ([]uncoreMetric, error) {\n\tif entity == nil {\n\t\treturn nil, errors.New(\"entity is nil\")\n\t}\n\tvar uncoreMetrics []uncoreMetric\n\n\tfor _, event := range entity.activeMultiEvents {\n\t\tif entity.Aggregate {\n\t\t\tnewMetric, err := ie.readMultiEventAgg(event)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tnewMetric.tag = entity.EventsTag\n\t\t\tuncoreMetrics = append(uncoreMetrics, newMetric)\n\t\t} else {\n\t\t\tnewMetrics, err := ie.readMultiEventSeparately(event)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor i := range newMetrics {\n\t\t\t\tnewMetrics[i].tag = entity.EventsTag\n\t\t\t}\n\t\t\tuncoreMetrics = append(uncoreMetrics, newMetrics...)\n\t\t}\n\t}\n\treturn uncoreMetrics, nil\n}\n\nfunc (ie *iaEntitiesValuesReader) readMultiEventSeparately(multiEvent multiEvent) ([]uncoreMetric, error) {\n\tif ie.eventReader == nil || ie.timer == nil {\n\t\treturn nil, errors.New(\"event values reader or timer is nil\")\n\t}\n\tif len(multiEvent.activeEvents) < 1 || multiEvent.perfEvent == nil {\n\t\treturn nil, errors.New(\"no active events or perf event is nil\")\n\t}\n\tactiveEvents := multiEvent.activeEvents\n\tperfEvent := multiEvent.perfEvent\n\n\tmetrics := make([]uncoreMetric, len(activeEvents))\n\tgroup := errgroup.Group{}\n\n\tfor id, actualEvent := range activeEvents {\n\t\tgroup.Go(func() error {\n\t\t\tvalues, err := ie.eventReader.readValue(actualEvent)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to read uncore event %q values: %w\", actualEvent, err)\n\t\t\t}\n\t\t\tnewMetric := uncoreMetric{\n\t\t\t\tvalues:   values,\n\t\t\t\tsocket:   multiEvent.socket,\n\t\t\t\tunitType: perfEvent.PMUName,\n\t\t\t\tname:     perfEvent.Name,\n\t\t\t\tunit:     actualEvent.PMUName(),\n\t\t\t\ttime:     ie.timer.now(),\n\t\t\t}\n\t\t\tmetrics[id] = newMetric\n\t\t\treturn nil\n\t\t})\n\t\terr := group.Wait()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn metrics, nil\n}\n\nfunc (ie *iaEntitiesValuesReader) readMultiEventAgg(multiEvent multiEvent) (uncoreMetric, error) {\n\tif ie.eventReader == nil || ie.timer == nil {\n\t\treturn uncoreMetric{}, errors.New(\"event values reader or timer is nil\")\n\t}\n\tif len(multiEvent.activeEvents) < 1 || multiEvent.perfEvent == nil {\n\t\treturn uncoreMetric{}, errors.New(\"no active events or perf event is nil\")\n\t}\n\tactiveEvents := multiEvent.activeEvents\n\tperfEvent := multiEvent.perfEvent\n\n\tvalues := make([]ia.CounterValue, len(activeEvents))\n\tgroup := errgroup.Group{}\n\n\tfor id, actualEvent := range activeEvents {\n\t\tgroup.Go(func() error {\n\t\t\tvalue, err := ie.eventReader.readValue(actualEvent)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to read uncore event %q values: %w\", actualEvent, err)\n\t\t\t}\n\t\t\tvalues[id] = value\n\t\t\treturn nil\n\t\t})\n\t}\n\terr := group.Wait()\n\tif err != nil {\n\t\treturn uncoreMetric{}, err\n\t}\n\n\tbRaw, bEnabled, bRunning := ia.AggregateValues(values)\n\tif !bRaw.IsUint64() || !bEnabled.IsUint64() || !bRunning.IsUint64() {\n\t\treturn uncoreMetric{}, fmt.Errorf(\"cannot aggregate %q values, uint64 exceeding\", perfEvent)\n\t}\n\taggValues := ia.CounterValue{\n\t\tRaw:     bRaw.Uint64(),\n\t\tEnabled: bEnabled.Uint64(),\n\t\tRunning: bRunning.Uint64(),\n\t}\n\tnewMetric := uncoreMetric{\n\t\tvalues:   aggValues,\n\t\tsocket:   multiEvent.socket,\n\t\tunitType: perfEvent.PMUName,\n\t\tname:     perfEvent.Name,\n\t\ttime:     ie.timer.now(),\n\t}\n\treturn newMetric, nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/reader_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype moonClock struct{}\n\nfunc (moonClock) now() time.Time {\n\treturn time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)\n}\n\ntype eventWithValues struct {\n\tactiveEvent *ia.ActiveEvent\n\tvalues      ia.CounterValue\n}\n\nfunc TestReadCoreEvents(t *testing.T) {\n\tmReader := &mockValuesReader{}\n\tmTimer := &moonClock{}\n\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\n\tt.Run(\"event reader is nil\", func(t *testing.T) {\n\t\tmetrics, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readCoreEvents(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"timer is nil\", func(t *testing.T) {\n\t\tmetrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readCoreEvents(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"entity is nil\", func(t *testing.T) {\n\t\tmetrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}, timer: moonClock{}}).readCoreEvents(nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entity is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"nil events\", func(t *testing.T) {\n\t\tentity := &coreEventEntity{}\n\n\t\tentity.activeEvents = append(entity.activeEvents, nil)\n\t\tmetrics, err := mEntitiesReader.readCoreEvents(entity)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"active event or corresponding perf event is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"reading failed\", func(t *testing.T) {\n\t\terrMock := errors.New(\"mock error\")\n\t\tevent := &ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: \"event1\"}}\n\n\t\tentity := &coreEventEntity{}\n\n\t\tentity.activeEvents = append(entity.activeEvents, event)\n\t\tmReader.On(\"readValue\", event).Return(ia.CounterValue{}, errMock).Once()\n\n\t\tmetrics, err := mEntitiesReader.readCoreEvents(entity)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to read core event %q values: %v\", event, errMock))\n\t\trequire.Nil(t, metrics)\n\t\tmReader.AssertExpectations(t)\n\t})\n\n\tt.Run(\"read active events values\", func(t *testing.T) {\n\t\tentity := &coreEventEntity{}\n\t\tvar expected []coreMetric\n\n\t\ttEvents := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: \"event1\"}}, ia.CounterValue{Raw: 316, Enabled: 182060524, Running: 182060524}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: \"event2\"}}, ia.CounterValue{Raw: 1238901, Enabled: 18234123, Running: 18234123}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: \"event3\"}}, ia.CounterValue{Raw: 412323, Enabled: 1823132, Running: 1823180}},\n\t\t}\n\n\t\tfor _, tc := range tEvents {\n\t\t\tentity.activeEvents = append(entity.activeEvents, tc.activeEvent)\n\t\t\tcpu, _ := tc.activeEvent.PMUPlacement()\n\t\t\tnewMetric := coreMetric{\n\t\t\t\tvalues: tc.values,\n\t\t\t\ttag:    entity.EventsTag,\n\t\t\t\tcpu:    cpu,\n\t\t\t\tname:   tc.activeEvent.PerfEvent.Name,\n\t\t\t\ttime:   mTimer.now(),\n\t\t\t}\n\t\t\texpected = append(expected, newMetric)\n\t\t\tmReader.On(\"readValue\", tc.activeEvent).Return(tc.values, nil).Once()\n\t\t}\n\t\tmetrics, err := mEntitiesReader.readCoreEvents(entity)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, metrics)\n\t\tmReader.AssertExpectations(t)\n\t})\n}\n\nfunc TestReadMultiEventSeparately(t *testing.T) {\n\tmReader := &mockValuesReader{}\n\tmTimer := &moonClock{}\n\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\n\tt.Run(\"event reader is nil\", func(t *testing.T) {\n\t\tevent := multiEvent{}\n\t\tmetrics, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readMultiEventSeparately(event)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"timer is nil\", func(t *testing.T) {\n\t\tevent := multiEvent{}\n\t\tmetrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readMultiEventSeparately(event)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"multi event is nil\", func(t *testing.T) {\n\t\tevent := multiEvent{}\n\t\tmetrics, err := (&iaEntitiesValuesReader{&iaValuesReader{}, moonClock{}}).readMultiEventSeparately(event)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"no active events or perf event is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"reading failed\", func(t *testing.T) {\n\t\terrMock := errors.New(\"mock error\")\n\t\tperfEvent := &ia.PerfEvent{Name: \"event\"}\n\n\t\tevent := &ia.ActiveEvent{PerfEvent: perfEvent}\n\t\tmulti := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}\n\n\t\tmReader.On(\"readValue\", event).Return(ia.CounterValue{}, errMock).Once()\n\n\t\tmetrics, err := mEntitiesReader.readMultiEventSeparately(multi)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to read uncore event %q values: %v\", event, errMock))\n\t\trequire.Nil(t, metrics)\n\t\tmReader.AssertExpectations(t)\n\t})\n\n\tt.Run(\"read active events values\", func(t *testing.T) {\n\t\tperfEvent := &ia.PerfEvent{Name: \"event\", PMUName: \"pmu name\"}\n\t\tmulti := multiEvent{perfEvent: perfEvent}\n\t\tvar expected []uncoreMetric\n\n\t\ttEvents := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 316, Enabled: 182060524, Running: 182060524}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 1238901, Enabled: 18234123, Running: 18234123}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 412323, Enabled: 1823132, Running: 1823180}},\n\t\t}\n\n\t\tfor _, tc := range tEvents {\n\t\t\tmulti.activeEvents = append(multi.activeEvents, tc.activeEvent)\n\t\t\tnewMetric := uncoreMetric{\n\t\t\t\tvalues:   tc.values,\n\t\t\t\tsocket:   multi.socket,\n\t\t\t\tunitType: multi.perfEvent.PMUName,\n\t\t\t\tname:     multi.perfEvent.Name,\n\t\t\t\tunit:     tc.activeEvent.PMUName(),\n\t\t\t\ttime:     mTimer.now(),\n\t\t\t}\n\t\t\texpected = append(expected, newMetric)\n\t\t\tmReader.On(\"readValue\", tc.activeEvent).Return(tc.values, nil).Once()\n\t\t}\n\t\tmetrics, err := mEntitiesReader.readMultiEventSeparately(multi)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, metrics)\n\t\tmReader.AssertExpectations(t)\n\t})\n}\n\nfunc TestReadMultiEventAgg(t *testing.T) {\n\tmReader := &mockValuesReader{}\n\tmTimer := &moonClock{}\n\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\terrMock := errors.New(\"mock error\")\n\n\tt.Run(\"event reader is nil\", func(t *testing.T) {\n\t\tevent := multiEvent{}\n\t\t_, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readMultiEventAgg(event)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t})\n\n\tt.Run(\"timer is nil\", func(t *testing.T) {\n\t\tevent := multiEvent{}\n\t\t_, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readMultiEventAgg(event)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event values reader or timer is nil\")\n\t})\n\n\tperfEvent := &ia.PerfEvent{Name: \"event\", PMUName: \"pmu name\"}\n\n\ttests := []struct {\n\t\tname     string\n\t\tmulti    multiEvent\n\t\tevents   []eventWithValues\n\t\tresult   ia.CounterValue\n\t\treadFail bool\n\t\terrMsg   string\n\t}{\n\t\t{\n\t\t\tname:   \"no events\",\n\t\t\tmulti:  multiEvent{perfEvent: perfEvent},\n\t\t\tevents: nil,\n\t\t\tresult: ia.CounterValue{},\n\t\t\terrMsg: \"no active events or perf event is nil\",\n\t\t},\n\t\t{\n\t\t\tname:   \"no perf event\",\n\t\t\tmulti:  multiEvent{perfEvent: nil, activeEvents: []*ia.ActiveEvent{{}, {}}},\n\t\t\tevents: nil,\n\t\t\tresult: ia.CounterValue{},\n\t\t\terrMsg: \"no active events or perf event is nil\",\n\t\t},\n\t\t{\n\t\t\tname:  \"successful reading and aggregation\",\n\t\t\tmulti: multiEvent{perfEvent: perfEvent},\n\t\t\tevents: []eventWithValues{\n\t\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 5123, Enabled: 1231242, Running: 41123}},\n\t\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4500, Enabled: 1823423, Running: 182343}},\n\t\t\t},\n\t\t\tresult: ia.CounterValue{Raw: 9623, Enabled: 3054665, Running: 223466},\n\t\t\terrMsg: \"\",\n\t\t},\n\t\t{\n\t\t\tname:  \"to big numbers\",\n\t\t\tmulti: multiEvent{perfEvent: perfEvent},\n\t\t\tevents: []eventWithValues{\n\t\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: math.MaxUint64, Enabled: 0, Running: 0}},\n\t\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 1, Enabled: 0, Running: 0}},\n\t\t\t},\n\t\t\tresult: ia.CounterValue{},\n\t\t\terrMsg: fmt.Sprintf(\"cannot aggregate %q values, uint64 exceeding\", perfEvent),\n\t\t},\n\t\t{\n\t\t\tname:  \"reading fail\",\n\t\t\tmulti: multiEvent{perfEvent: perfEvent},\n\t\t\tevents: []eventWithValues{\n\t\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 0, Enabled: 0, Running: 0}},\n\t\t\t},\n\t\t\treadFail: true,\n\t\t\tresult:   ia.CounterValue{},\n\t\t\terrMsg:   \"failed to read uncore event\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tfor _, eventWithValue := range test.events {\n\t\t\t\ttest.multi.activeEvents = append(test.multi.activeEvents, eventWithValue.activeEvent)\n\t\t\t\tif test.readFail {\n\t\t\t\t\tmReader.On(\"readValue\", eventWithValue.activeEvent).Return(ia.CounterValue{}, errMock).Once()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmReader.On(\"readValue\", eventWithValue.activeEvent).Return(eventWithValue.values, nil).Once()\n\t\t\t}\n\t\t\tmetric, err := mEntitiesReader.readMultiEventAgg(test.multi)\n\t\t\tmReader.AssertExpectations(t)\n\n\t\t\tif len(test.errMsg) > 0 {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), test.errMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\texpected := uncoreMetric{\n\t\t\t\tvalues:   test.result,\n\t\t\t\tsocket:   test.multi.socket,\n\t\t\t\tunitType: test.multi.perfEvent.PMUName,\n\t\t\t\tname:     test.multi.perfEvent.Name,\n\t\t\t\ttime:     mTimer.now(),\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, expected, metric)\n\t\t})\n\t}\n}\n\nfunc TestReadUncoreEvents(t *testing.T) {\n\terrMock := errors.New(\"mock error\")\n\n\tt.Run(\"entity is nil\", func(t *testing.T) {\n\t\tmetrics, err := (&iaEntitiesValuesReader{}).readUncoreEvents(nil)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entity is nil\")\n\t\trequire.Nil(t, metrics)\n\t})\n\n\tt.Run(\"read aggregated entities\", func(t *testing.T) {\n\t\tmReader := &mockValuesReader{}\n\t\tmTimer := &moonClock{}\n\t\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\n\t\tperfEvent := &ia.PerfEvent{Name: \"mock event\", PMUName: \"cbox\", PMUTypes: []ia.NamedPMUType{{Name: \"cbox\"}}}\n\t\tperfEvent2 := &ia.PerfEvent{Name: \"mock event2\", PMUName: \"rad\", PMUTypes: []ia.NamedPMUType{{Name: \"rad2\"}}}\n\n\t\tmulti := multiEvent{perfEvent: perfEvent}\n\t\tevents := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 2003}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4005}},\n\t\t}\n\t\tmulti2 := multiEvent{perfEvent: perfEvent2}\n\t\tevents2 := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 2003}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 123005}},\n\t\t}\n\t\tfor _, event := range events {\n\t\t\tmulti.activeEvents = append(multi.activeEvents, event.activeEvent)\n\t\t\tmReader.On(\"readValue\", event.activeEvent).Return(event.values, nil).Once()\n\t\t}\n\t\tfor _, event := range events2 {\n\t\t\tmulti2.activeEvents = append(multi2.activeEvents, event.activeEvent)\n\t\t\tmReader.On(\"readValue\", event.activeEvent).Return(event.values, nil).Once()\n\t\t}\n\t\tnewMetric := uncoreMetric{\n\t\t\tvalues:   ia.CounterValue{Raw: 6008, Enabled: 0, Running: 0},\n\t\t\tsocket:   multi.socket,\n\t\t\tunitType: perfEvent.PMUName,\n\t\t\tname:     perfEvent.Name,\n\t\t\ttime:     mTimer.now(),\n\t\t}\n\t\tnewMetric2 := uncoreMetric{\n\t\t\tvalues:   ia.CounterValue{Raw: 125008, Enabled: 0, Running: 0},\n\t\t\tsocket:   multi2.socket,\n\t\t\tunitType: perfEvent2.PMUName,\n\t\t\tname:     perfEvent2.Name,\n\t\t\ttime:     mTimer.now(),\n\t\t}\n\t\texpected := []uncoreMetric{newMetric, newMetric2}\n\t\tentityAgg := &uncoreEventEntity{Aggregate: true, activeMultiEvents: []multiEvent{multi, multi2}}\n\n\t\tmetrics, err := mEntitiesReader.readUncoreEvents(entityAgg)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, metrics)\n\t\tmReader.AssertExpectations(t)\n\n\t\tt.Run(\"reading error\", func(t *testing.T) {\n\t\t\tevent := &ia.ActiveEvent{PerfEvent: perfEvent}\n\t\t\tmulti := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}\n\n\t\t\tmReader.On(\"readValue\", event).Return(ia.CounterValue{}, errMock).Once()\n\n\t\t\tentityAgg := &uncoreEventEntity{Aggregate: true, activeMultiEvents: []multiEvent{multi}}\n\t\t\tmetrics, err = mEntitiesReader.readUncoreEvents(entityAgg)\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Nil(t, metrics)\n\t\t\tmReader.AssertExpectations(t)\n\t\t})\n\t})\n\n\tt.Run(\"read distributed entities\", func(t *testing.T) {\n\t\tmReader := &mockValuesReader{}\n\t\tmTimer := &moonClock{}\n\t\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\n\t\tperfEvent := &ia.PerfEvent{Name: \"mock event\", PMUName: \"cbox\", PMUTypes: []ia.NamedPMUType{{Name: \"cbox\"}}}\n\t\tperfEvent2 := &ia.PerfEvent{Name: \"mock event2\", PMUName: \"rad\", PMUTypes: []ia.NamedPMUType{{Name: \"rad2\"}}}\n\n\t\tmulti := multiEvent{perfEvent: perfEvent, socket: 2}\n\t\tevents := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 2003}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4005}},\n\t\t}\n\t\tmulti2 := multiEvent{perfEvent: perfEvent2, socket: 1}\n\t\tevents2 := []eventWithValues{\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 2003}},\n\t\t\t{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 123005}},\n\t\t}\n\t\tvar expected []uncoreMetric\n\t\tfor _, event := range events {\n\t\t\tmulti.activeEvents = append(multi.activeEvents, event.activeEvent)\n\t\t\tmReader.On(\"readValue\", event.activeEvent).Return(event.values, nil).Once()\n\n\t\t\tnewMetric := uncoreMetric{\n\t\t\t\tvalues:   event.values,\n\t\t\t\tsocket:   multi.socket,\n\t\t\t\tunitType: perfEvent.PMUName,\n\t\t\t\tname:     perfEvent.Name,\n\t\t\t\tunit:     event.activeEvent.PMUName(),\n\t\t\t\ttime:     mTimer.now(),\n\t\t\t}\n\t\t\texpected = append(expected, newMetric)\n\t\t}\n\t\tfor _, event := range events2 {\n\t\t\tmulti2.activeEvents = append(multi2.activeEvents, event.activeEvent)\n\t\t\tmReader.On(\"readValue\", event.activeEvent).Return(event.values, nil).Once()\n\n\t\t\tnewMetric := uncoreMetric{\n\t\t\t\tvalues:   event.values,\n\t\t\t\tsocket:   multi2.socket,\n\t\t\t\tunitType: perfEvent2.PMUName,\n\t\t\t\tname:     perfEvent2.Name,\n\t\t\t\tunit:     event.activeEvent.PMUName(),\n\t\t\t\ttime:     mTimer.now(),\n\t\t\t}\n\t\t\texpected = append(expected, newMetric)\n\t\t}\n\t\tentity := &uncoreEventEntity{activeMultiEvents: []multiEvent{multi, multi2}}\n\n\t\tmetrics, err := mEntitiesReader.readUncoreEvents(entity)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, metrics)\n\t\tmReader.AssertExpectations(t)\n\n\t\tt.Run(\"reading error\", func(t *testing.T) {\n\t\t\tevent := &ia.ActiveEvent{PerfEvent: perfEvent}\n\t\t\tmulti := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}\n\n\t\t\tmReader.On(\"readValue\", event).Return(ia.CounterValue{}, errMock).Once()\n\n\t\t\tentityAgg := &uncoreEventEntity{activeMultiEvents: []multiEvent{multi}}\n\t\t\tmetrics, err = mEntitiesReader.readUncoreEvents(entityAgg)\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Nil(t, metrics)\n\t\t\tmReader.AssertExpectations(t)\n\t\t})\n\t})\n}\n\nfunc TestReadEntities(t *testing.T) {\n\tmReader := &mockValuesReader{}\n\tmTimer := &moonClock{}\n\tmEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}\n\n\tt.Run(\"read entities\", func(t *testing.T) {\n\t\tvalues := ia.CounterValue{}\n\t\tsocket := 0\n\n\t\tcorePerfEvent := &ia.PerfEvent{Name: \"core event 1\", PMUName: \"cpu\"}\n\t\tactiveCoreEvent := []*ia.ActiveEvent{{PerfEvent: corePerfEvent}}\n\t\tcoreMetric1 := coreMetric{values: values, name: corePerfEvent.Name, time: mTimer.now()}\n\n\t\tcorePerfEvent2 := &ia.PerfEvent{Name: \"core event 2\", PMUName: \"cpu\"}\n\t\tactiveCoreEvent2 := []*ia.ActiveEvent{{PerfEvent: corePerfEvent2}}\n\t\tcoreMetric2 := coreMetric{values: values, name: corePerfEvent2.Name, time: mTimer.now()}\n\n\t\tuncorePerfEvent := &ia.PerfEvent{Name: \"uncore event 1\", PMUName: \"cbox\"}\n\t\tactiveUncoreEvent := []*ia.ActiveEvent{{PerfEvent: uncorePerfEvent}}\n\t\tuncoreMetric1 := uncoreMetric{\n\t\t\tvalues:   values,\n\t\t\tname:     uncorePerfEvent.Name,\n\t\t\tunitType: uncorePerfEvent.PMUName,\n\t\t\tsocket:   socket,\n\t\t\ttime:     mTimer.now(),\n\t\t}\n\n\t\tuncorePerfEvent2 := &ia.PerfEvent{Name: \"uncore event 2\", PMUName: \"rig\"}\n\t\tactiveUncoreEvent2 := []*ia.ActiveEvent{{PerfEvent: uncorePerfEvent2}}\n\t\tuncoreMetric2 := uncoreMetric{\n\t\t\tvalues:   values,\n\t\t\tname:     uncorePerfEvent2.Name,\n\t\t\tunitType: uncorePerfEvent2.PMUName,\n\t\t\tsocket:   socket,\n\t\t\ttime:     mTimer.now(),\n\t\t}\n\n\t\tcoreEntities := []*coreEventEntity{{activeEvents: activeCoreEvent}, {activeEvents: activeCoreEvent2}}\n\n\t\tuncoreEntities := []*uncoreEventEntity{\n\t\t\t{activeMultiEvents: []multiEvent{{activeEvents: activeUncoreEvent, perfEvent: uncorePerfEvent, socket: socket}}},\n\t\t\t{activeMultiEvents: []multiEvent{{activeEvents: activeUncoreEvent2, perfEvent: uncorePerfEvent2, socket: socket}}},\n\t\t}\n\n\t\texpectedCoreMetrics := []coreMetric{coreMetric1, coreMetric2}\n\t\texpectedUncoreMetrics := []uncoreMetric{uncoreMetric1, uncoreMetric2}\n\n\t\tmReader.On(\"readValue\", activeCoreEvent[0]).Return(values, nil).Once()\n\t\tmReader.On(\"readValue\", activeCoreEvent2[0]).Return(values, nil).Once()\n\t\tmReader.On(\"readValue\", activeUncoreEvent[0]).Return(values, nil).Once()\n\t\tmReader.On(\"readValue\", activeUncoreEvent2[0]).Return(values, nil).Once()\n\n\t\tcoreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(coreEntities, uncoreEntities)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCoreMetrics, coreMetrics)\n\t\trequire.NotNil(t, expectedUncoreMetrics, uncoreMetrics)\n\t\tmReader.AssertExpectations(t)\n\t})\n\n\tt.Run(\"core entity reading failed\", func(t *testing.T) {\n\t\tcoreEntities := []*coreEventEntity{nil}\n\t\tcoreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(coreEntities, nil)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entity is nil\")\n\t\trequire.Nil(t, coreMetrics)\n\t\trequire.Nil(t, uncoreMetrics)\n\t})\n\n\tt.Run(\"uncore entity reading failed\", func(t *testing.T) {\n\t\tuncoreEntities := []*uncoreEventEntity{nil}\n\t\tcoreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(nil, uncoreEntities)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"entity is nil\")\n\t\trequire.Nil(t, coreMetrics)\n\t\trequire.Nil(t, uncoreMetrics)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/resolver.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\tia \"github.com/intel/iaevents\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype entitiesResolver interface {\n\tresolveEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error\n}\n\ntype iaEntitiesResolver struct {\n\treader      ia.Reader\n\ttransformer ia.Transformer\n\tlog         telegraf.Logger\n}\n\nfunc (e *iaEntitiesResolver) resolveEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {\n\tfor _, entity := range coreEntities {\n\t\tif entity == nil {\n\t\t\treturn errors.New(\"core entity is nil\")\n\t\t}\n\t\tif entity.allEvents {\n\t\t\tnewEvents, _, err := e.resolveAllEvents()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve all events: %w\", err)\n\t\t\t}\n\t\t\tentity.parsedEvents = newEvents\n\t\t\tcontinue\n\t\t}\n\t\tfor _, event := range entity.parsedEvents {\n\t\t\tif event == nil {\n\t\t\t\treturn errors.New(\"parsed core event is nil\")\n\t\t\t}\n\t\t\tcustomEvent, err := e.resolveEvent(event.name, event.qualifiers)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve core event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tif customEvent.Event.Uncore {\n\t\t\t\treturn fmt.Errorf(\"uncore event %q found in core entity\", event.name)\n\t\t\t}\n\t\t\tevent.custom = customEvent\n\t\t}\n\t}\n\tfor _, entity := range uncoreEntities {\n\t\tif entity == nil {\n\t\t\treturn errors.New(\"uncore entity is nil\")\n\t\t}\n\t\tif entity.allEvents {\n\t\t\t_, newEvents, err := e.resolveAllEvents()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve all events: %w\", err)\n\t\t\t}\n\t\t\tentity.parsedEvents = newEvents\n\t\t\tcontinue\n\t\t}\n\t\tfor _, event := range entity.parsedEvents {\n\t\t\tif event == nil {\n\t\t\t\treturn errors.New(\"parsed uncore event is nil\")\n\t\t\t}\n\t\t\tcustomEvent, err := e.resolveEvent(event.name, event.qualifiers)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve uncore event %q: %w\", event.name, err)\n\t\t\t}\n\t\t\tif !customEvent.Event.Uncore {\n\t\t\t\treturn fmt.Errorf(\"core event %q found in uncore entity\", event.name)\n\t\t\t}\n\t\t\tevent.custom = customEvent\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e *iaEntitiesResolver) resolveAllEvents() (coreEvents, uncoreEvents []*eventWithQuals, err error) {\n\tif e.transformer == nil {\n\t\treturn nil, nil, errors.New(\"transformer is nil\")\n\t}\n\n\tperfEvents, err := e.transformer.Transform(e.reader, ia.NewNameMatcher())\n\tif err != nil {\n\t\tvar re *ia.TransformationError\n\t\tif !errors.As(err, &re) {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif e.log != nil && re != nil {\n\t\t\tvar eventErrs []string\n\t\t\tfor _, eventErr := range re.Errors() {\n\t\t\t\tif eventErr == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\teventErrs = append(eventErrs, eventErr.Error())\n\t\t\t}\n\t\t\terrorsStr := strings.Join(eventErrs, \",\\n\")\n\t\t\te.log.Warnf(\"Cannot resolve all of the events from provided files:\\n%s.\\nSome events may be omitted.\", errorsStr)\n\t\t}\n\t}\n\n\tfor _, perfEvent := range perfEvents {\n\t\tnewEvent := &eventWithQuals{\n\t\t\tname:   perfEvent.Name,\n\t\t\tcustom: ia.CustomizableEvent{Event: perfEvent},\n\t\t}\n\t\t// build options for event\n\t\tnewEvent.custom.Options, err = ia.NewOptions().Build()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to build options for event %q: %w\", perfEvent.Name, err)\n\t\t}\n\t\tif perfEvent.Uncore {\n\t\t\tuncoreEvents = append(uncoreEvents, newEvent)\n\t\t\tcontinue\n\t\t}\n\t\tcoreEvents = append(coreEvents, newEvent)\n\t}\n\treturn coreEvents, uncoreEvents, nil\n}\n\nfunc (e *iaEntitiesResolver) resolveEvent(name string, qualifiers []string) (ia.CustomizableEvent, error) {\n\tvar custom ia.CustomizableEvent\n\tif e.transformer == nil {\n\t\treturn custom, errors.New(\"events transformer is nil\")\n\t}\n\tif name == \"\" {\n\t\treturn custom, errors.New(\"event name is empty\")\n\t}\n\tmatcher := ia.NewNameMatcher(name)\n\tperfEvents, err := e.transformer.Transform(e.reader, matcher)\n\tif err != nil {\n\t\treturn custom, fmt.Errorf(\"failed to transform perf events: %w\", err)\n\t}\n\tif len(perfEvents) < 1 {\n\t\treturn custom, fmt.Errorf(\"failed to resolve unknown event %q\", name)\n\t}\n\t// build options for event\n\toptions, err := ia.NewOptions().SetAttrModifiers(qualifiers).Build()\n\tif err != nil {\n\t\treturn custom, fmt.Errorf(\"failed to build options for event %q: %w\", name, err)\n\t}\n\tcustom = ia.CustomizableEvent{\n\t\tEvent:   perfEvents[0],\n\t\tOptions: options,\n\t}\n\treturn custom, nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/resolver_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_pmu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\tia \"github.com/intel/iaevents\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestResolveEntities(t *testing.T) {\n\terrMock := errors.New(\"mock error\")\n\tmLog := testutil.Logger{}\n\tmTransformer := &MockTransformer{}\n\tmResolver := &iaEntitiesResolver{transformer: mTransformer, log: mLog}\n\n\ttype test struct {\n\t\tperfEvent *ia.PerfEvent\n\t\toptions   ia.Options\n\t\tevent     *eventWithQuals\n\t}\n\n\tt.Run(\"nil entities\", func(t *testing.T) {\n\t\terr := mResolver.resolveEntities([]*coreEventEntity{nil}, nil)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"core entity is nil\")\n\n\t\terr = mResolver.resolveEntities(nil, []*uncoreEventEntity{nil})\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"uncore entity is nil\")\n\t})\n\n\tt.Run(\"nil parsed events\", func(t *testing.T) {\n\t\tmCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}\n\t\tmUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}\n\n\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"parsed core event is nil\")\n\n\t\terr = mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"parsed uncore event is nil\")\n\t})\n\n\tt.Run(\"fail to resolve core events\", func(t *testing.T) {\n\t\tname := \"mock event 1\"\n\t\tmCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{{name: name}}, allEvents: false}\n\t\tmatcher := ia.NewNameMatcher(name)\n\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errMock)\n\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to resolve core event %q\", name))\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"fail to resolve uncore events\", func(t *testing.T) {\n\t\tname := \"mock event 1\"\n\t\tmUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{{name: name}}, allEvents: false}\n\t\tmatcher := ia.NewNameMatcher(name)\n\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errMock)\n\t\terr := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to resolve uncore event %q\", name))\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"resolve all core and uncore events\", func(t *testing.T) {\n\t\tmCoreEntity := &coreEventEntity{allEvents: true}\n\t\tmUncoreEntity := &uncoreEventEntity{allEvents: true}\n\t\tcorePerfEvents := []*ia.PerfEvent{\n\t\t\t{Name: \"core event1\"},\n\t\t\t{Name: \"core event2\"},\n\t\t\t{Name: \"core event3\"},\n\t\t}\n\t\tuncorePerfEvents := []*ia.PerfEvent{\n\t\t\t{Name: \"uncore event1\", Uncore: true},\n\t\t\t{Name: \"uncore event2\", Uncore: true},\n\t\t\t{Name: \"uncore event3\", Uncore: true},\n\t\t}\n\t\tmatcher := ia.NewNameMatcher()\n\n\t\tt.Run(\"fail to resolve all core events\", func(t *testing.T) {\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errMock)\n\t\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"failed to resolve all events\")\n\t\t\tmTransformer.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"fail to resolve all uncore events\", func(t *testing.T) {\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errMock)\n\t\t\terr := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"failed to resolve all events\")\n\t\t\tmTransformer.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"fail to resolve all events with transformationError\", func(t *testing.T) {\n\t\t\ttransformErr := &ia.TransformationError{}\n\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(corePerfEvents, transformErr).Once()\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(uncorePerfEvents, transformErr).Once()\n\n\t\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, mCoreEntity.parsedEvents, len(corePerfEvents))\n\t\t\trequire.Len(t, mUncoreEntity.parsedEvents, len(uncorePerfEvents))\n\t\t\tfor _, coreEvent := range mCoreEntity.parsedEvents {\n\t\t\t\trequire.Contains(t, corePerfEvents, coreEvent.custom.Event)\n\t\t\t}\n\t\t\tfor _, uncoreEvent := range mUncoreEntity.parsedEvents {\n\t\t\t\trequire.Contains(t, uncorePerfEvents, uncoreEvent.custom.Event)\n\t\t\t}\n\t\t\tmTransformer.AssertExpectations(t)\n\t\t})\n\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(corePerfEvents, nil).Once()\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(uncorePerfEvents, nil).Once()\n\n\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, mCoreEntity.parsedEvents, len(corePerfEvents))\n\t\trequire.Len(t, mUncoreEntity.parsedEvents, len(uncorePerfEvents))\n\t\tfor _, coreEvent := range mCoreEntity.parsedEvents {\n\t\t\trequire.Contains(t, corePerfEvents, coreEvent.custom.Event)\n\t\t}\n\t\tfor _, uncoreEvent := range mUncoreEntity.parsedEvents {\n\t\t\trequire.Contains(t, uncorePerfEvents, uncoreEvent.custom.Event)\n\t\t}\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"uncore event found in core entity\", func(t *testing.T) {\n\t\tmQuals := []string{\"config1=0x23h\"}\n\t\teventName := \"uncore event 1\"\n\n\t\ttestCase := test{\n\t\t\tevent:     &eventWithQuals{name: eventName, qualifiers: mQuals},\n\t\t\tperfEvent: &ia.PerfEvent{Name: eventName, Uncore: true},\n\t\t}\n\n\t\tmatcher := ia.NewNameMatcher(eventName)\n\t\tmTransformer.On(\"Transform\", nil, matcher).Return([]*ia.PerfEvent{testCase.perfEvent}, nil).Once()\n\n\t\tmCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{testCase.event}, allEvents: false}\n\t\terr := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)\n\t\trequire.ErrorContains(t, err, fmt.Sprintf(\"uncore event %q found in core entity\", eventName))\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"core event found in uncore entity\", func(t *testing.T) {\n\t\tmQuals := []string{\"config1=0x23h\"}\n\t\teventName := \"core event 1\"\n\n\t\ttestCase := test{\n\t\t\tevent:     &eventWithQuals{name: eventName, qualifiers: mQuals},\n\t\t\tperfEvent: &ia.PerfEvent{Name: eventName, Uncore: false},\n\t\t}\n\n\t\tmatcher := ia.NewNameMatcher(eventName)\n\t\tmTransformer.On(\"Transform\", nil, matcher).Return([]*ia.PerfEvent{testCase.perfEvent}, nil).Once()\n\n\t\tmUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{testCase.event}, allEvents: false}\n\t\terr := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})\n\n\t\trequire.ErrorContains(t, err, fmt.Sprintf(\"core event %q found in uncore entity\", eventName))\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"resolve core and uncore events\", func(t *testing.T) {\n\t\tvar mCoreEvents []*eventWithQuals\n\t\tvar nUncoreEvents []*eventWithQuals\n\n\t\tmQuals := []string{\"config1=0x23h\"}\n\t\tmOptions, err := ia.NewOptions().SetAttrModifiers(mQuals).Build()\n\t\trequire.NoError(t, err)\n\t\temptyOptions, err := ia.NewOptions().Build()\n\t\trequire.NoError(t, err)\n\n\t\tcoreTestCases := []test{\n\t\t\t{event: &eventWithQuals{name: \"core1\", qualifiers: mQuals},\n\t\t\t\toptions:   mOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"core1\"}},\n\t\t\t{event: &eventWithQuals{name: \"core2\", qualifiers: nil},\n\t\t\t\toptions:   emptyOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"core2\"}},\n\t\t\t{event: &eventWithQuals{name: \"core3\", qualifiers: nil},\n\t\t\t\toptions:   emptyOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"core3\"}},\n\t\t}\n\t\tuncoreTestCases := []test{\n\t\t\t{event: &eventWithQuals{name: \"uncore1\", qualifiers: mQuals},\n\t\t\t\toptions:   mOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"uncore1\", Uncore: true}},\n\t\t\t{event: &eventWithQuals{name: \"uncore2\", qualifiers: nil},\n\t\t\t\toptions:   emptyOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"uncore2\", Uncore: true}},\n\t\t\t{event: &eventWithQuals{name: \"uncore3\", qualifiers: nil},\n\t\t\t\toptions:   emptyOptions,\n\t\t\t\tperfEvent: &ia.PerfEvent{Name: \"uncore3\", Uncore: true}},\n\t\t}\n\n\t\tfor _, test := range coreTestCases {\n\t\t\tmatcher := ia.NewNameMatcher(test.event.name)\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Return([]*ia.PerfEvent{test.perfEvent}, nil).Once()\n\t\t\tmCoreEvents = append(mCoreEvents, test.event)\n\t\t}\n\n\t\tfor _, test := range uncoreTestCases {\n\t\t\tmatcher := ia.NewNameMatcher(test.event.name)\n\t\t\tmTransformer.On(\"Transform\", nil, matcher).Return([]*ia.PerfEvent{test.perfEvent}, nil).Once()\n\t\t\tnUncoreEvents = append(nUncoreEvents, test.event)\n\t\t}\n\n\t\tmCoreEntity := &coreEventEntity{parsedEvents: mCoreEvents, allEvents: false}\n\t\tmUncoreEntity := &uncoreEventEntity{parsedEvents: nUncoreEvents, allEvents: false}\n\t\terr = mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})\n\n\t\trequire.NoError(t, err)\n\t\tfor _, test := range append(coreTestCases, uncoreTestCases...) {\n\t\t\trequire.Equal(t, test.perfEvent, test.event.custom.Event)\n\t\t\trequire.Equal(t, test.options, test.event.custom.Options)\n\t\t}\n\t\tmTransformer.AssertExpectations(t)\n\t})\n}\n\nfunc TestResolveAllEvents(t *testing.T) {\n\tmTransformer := &MockTransformer{}\n\n\tmResolver := &iaEntitiesResolver{transformer: mTransformer}\n\n\tt.Run(\"transformer is nil\", func(t *testing.T) {\n\t\tmResolver := &iaEntitiesResolver{transformer: nil}\n\t\t_, _, err := mResolver.resolveAllEvents()\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"transformer returns error\", func(t *testing.T) {\n\t\tmatcher := ia.NewNameMatcher()\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errors.New(\"mock error\"))\n\n\t\t_, _, err := mResolver.resolveAllEvents()\n\t\trequire.Error(t, err)\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"no events\", func(t *testing.T) {\n\t\tmatcher := ia.NewNameMatcher()\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, nil)\n\n\t\t_, _, err := mResolver.resolveAllEvents()\n\t\trequire.NoError(t, err)\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"successfully resolved events\", func(t *testing.T) {\n\t\tperfEvent1 := &ia.PerfEvent{Name: \"mock1\"}\n\t\tperfEvent2 := &ia.PerfEvent{Name: \"mock2\"}\n\t\tuncorePerfEvent1 := &ia.PerfEvent{Name: \"mock3\", Uncore: true}\n\t\tuncorePerfEvent2 := &ia.PerfEvent{Name: \"mock4\", Uncore: true}\n\n\t\toptions, err := ia.NewOptions().Build()\n\t\trequire.NoError(t, err)\n\t\tperfEvents := []*ia.PerfEvent{perfEvent1, perfEvent2, uncorePerfEvent1, uncorePerfEvent2}\n\n\t\texpectedCore := []*eventWithQuals{\n\t\t\t{name: perfEvent1.Name, custom: ia.CustomizableEvent{Event: perfEvent1, Options: options}},\n\t\t\t{name: perfEvent2.Name, custom: ia.CustomizableEvent{Event: perfEvent2, Options: options}},\n\t\t}\n\n\t\texpectedUncore := []*eventWithQuals{\n\t\t\t{name: uncorePerfEvent1.Name, custom: ia.CustomizableEvent{Event: uncorePerfEvent1, Options: options}},\n\t\t\t{name: uncorePerfEvent2.Name, custom: ia.CustomizableEvent{Event: uncorePerfEvent2, Options: options}},\n\t\t}\n\n\t\tmatcher := ia.NewNameMatcher()\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(perfEvents, nil)\n\n\t\tcoreEvents, uncoreEvents, err := mResolver.resolveAllEvents()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCore, coreEvents)\n\t\trequire.Equal(t, expectedUncore, uncoreEvents)\n\n\t\tmTransformer.AssertExpectations(t)\n\t})\n}\n\nfunc TestResolveEvent(t *testing.T) {\n\tmTransformer := &MockTransformer{}\n\tmEvent := \"mock event\"\n\n\tmResolver := &iaEntitiesResolver{transformer: mTransformer}\n\n\tt.Run(\"transformer is nil\", func(t *testing.T) {\n\t\tmResolver := &iaEntitiesResolver{transformer: nil}\n\t\t_, err := mResolver.resolveEvent(\"event\", nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"events transformer is nil\")\n\t})\n\n\tt.Run(\"event is empty\", func(t *testing.T) {\n\t\t_, err := mResolver.resolveEvent(\"\", nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"event name is empty\")\n\t})\n\n\tt.Run(\"transformer returns error\", func(t *testing.T) {\n\t\tmatcher := ia.NewNameMatcher(mEvent)\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, errors.New(\"mock error\"))\n\n\t\t_, err := mResolver.resolveEvent(mEvent, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to transform perf events\")\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"no events transformed\", func(t *testing.T) {\n\t\tmatcher := ia.NewNameMatcher(mEvent)\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(nil, nil)\n\n\t\t_, err := mResolver.resolveEvent(mEvent, nil)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to resolve unknown event\")\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"not valid qualifiers\", func(t *testing.T) {\n\t\tevent := \"mock event 1\"\n\t\tqualifiers := []string{\"wrong modifiers\"}\n\n\t\tmatcher := ia.NewNameMatcher(event)\n\t\tmPerfEvent := &ia.PerfEvent{Name: event}\n\t\tmPerfEvents := []*ia.PerfEvent{mPerfEvent}\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(mPerfEvents, nil)\n\n\t\t_, err := mResolver.resolveEvent(event, qualifiers)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), fmt.Sprintf(\"failed to build options for event %q\", event))\n\t\tmTransformer.AssertExpectations(t)\n\t})\n\n\tt.Run(\"successfully transformed\", func(t *testing.T) {\n\t\tevent := \"mock event 1\"\n\t\tqualifiers := []string{\"config1=0x012h\", \"config2=0x034k\"}\n\n\t\tmatcher := ia.NewNameMatcher(event)\n\n\t\tmPerfEvent := &ia.PerfEvent{Name: event}\n\t\tmPerfEvents := []*ia.PerfEvent{mPerfEvent}\n\n\t\texpectedOptions, err := ia.NewOptions().SetAttrModifiers(qualifiers).Build()\n\t\trequire.NoError(t, err)\n\n\t\tmTransformer.On(\"Transform\", nil, matcher).Once().Return(mPerfEvents, nil)\n\n\t\tcustomEvent, err := mResolver.resolveEvent(event, qualifiers)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, mPerfEvent, customEvent.Event)\n\t\trequire.Equal(t, expectedOptions, customEvent.Options)\n\t\tmTransformer.AssertExpectations(t)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_pmu/sample.conf",
    "content": "# Intel Performance Monitoring Unit plugin exposes Intel PMU metrics available through Linux Perf subsystem\n# This plugin ONLY supports Linux on amd64\n[[inputs.intel_pmu]]\n  ## List of filesystem locations of JSON files that contain PMU event definitions.\n  event_definitions = [\"/var/cache/pmu/GenuineIntel-6-55-4-core.json\", \"/var/cache/pmu/GenuineIntel-6-55-4-uncore.json\"]\n\n  ## List of core events measurement entities. There can be more than one core_events sections.\n  [[inputs.intel_pmu.core_events]]\n    ## List of events to be counted. Event names shall match names from event_definitions files.\n    ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers.\n    ## If absent, all core events from provided event_definitions are counted skipping unresolvable ones.\n    events = [\"INST_RETIRED.ANY\", \"CPU_CLK_UNHALTED.THREAD_ANY:config1=0x4043200000000k\"]\n\n    ## Limits the counting of events to core numbers specified.\n    ## If absent, events are counted on all cores.\n    ## Single \"0\", multiple \"0,1,2\" and range \"0-2\" notation is supported for each array element.\n    ##   example: cores = [\"0,2\", \"4\", \"12-16\"]\n    cores = [\"0\"]\n\n    ## Indicator that plugin shall attempt to run core_events.events as a single perf group.\n    ## If absent or set to false, each event is counted individually. Defaults to false.\n    ## This limits the number of events that can be measured to a maximum of available hardware counters per core.\n    ## Could vary depending on type of event, use of fixed counters.\n    # perf_group = false\n\n    ## Optionally set a custom tag value that will be added to every measurement within this events group.\n    ## Can be applied to any group of events, unrelated to perf_group setting.\n    # events_tag = \"\"\n\n  ## List of uncore event measurement entities. There can be more than one uncore_events sections.\n  [[inputs.intel_pmu.uncore_events]]\n    ## List of events to be counted. Event names shall match names from event_definitions files.\n    ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers.\n    ## If absent, all uncore events from provided event_definitions are counted skipping unresolvable ones.\n    events = [\"UNC_CHA_CLOCKTICKS\", \"UNC_CHA_TOR_OCCUPANCY.IA_MISS\"]\n\n    ## Limits the counting of events to specified sockets.\n    ## If absent, events are counted on all sockets.\n    ## Single \"0\", multiple \"0,1\" and range \"0-1\" notation is supported for each array element.\n    ##   example: sockets = [\"0-2\"]\n    sockets = [\"0\"]\n\n    ## Indicator that plugin shall provide an aggregated value for multiple units of same type distributed in an uncore.\n    ## If absent or set to false, events for each unit are exposed as separate metric. Defaults to false.\n    # aggregate_uncore_units = false\n\n    ## Optionally set a custom tag value that will be added to every measurement within this events group.\n    # events_tag = \"\"\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/README.md",
    "content": "# Intel PowerStat Input Plugin\n\nThis plugin gathers power statistics on Intel-based platforms providing insights\ninto power saving and workload migration. Those are beneficial for Monitoring\nand Analytics systems to take preventive or corrective actions based on platform\nbusyness, CPU temperature, actual CPU utilization and power statistics.\n\n⭐ Telegraf v1.17.0\n🏷️ hardware, system\n💻 linux\n\n## Requirements\n\n### Kernel modules\n\nPlugin is mostly based on Linux Kernel modules that expose specific metrics over\n`sysfs` or `devfs` interfaces. The following dependencies are expected:\n\n- `intel-rapl` kernel module which exposes Intel Runtime Power Limiting metrics over\n  `sysfs` (`/sys/devices/virtual/powercap/intel-rapl`),\n- `msr` kernel module that provides access to processor model specific\n  registers over `devfs` (`/dev/cpu/cpu%d/msr`),\n- `cpufreq` kernel module - which exposes per-CPU Frequency over `sysfs`\n (`/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq`),\n- `intel-uncore-frequency` kernel module exposes Intel uncore frequency metrics\n  over `sysfs` (`/sys/devices/system/cpu/intel_uncore_frequency`).\n\nMake sure the required kernel modules are loaded and running. Modules might have\nto be manually enabled by using `modprobe`. Depending on the kernel version,\nrun the following commands:\n\n```sh\n# rapl modules:\n## kernel < 4.0\nsudo modprobe intel_rapl\n## kernel >= 4.0\nsudo modprobe rapl\nsudo modprobe intel_rapl_common\nsudo modprobe intel_rapl_msr\n\n# msr module:\nsudo modprobe msr\n\n# cpufreq module:\n### integrated in kernel\n\n# intel-uncore-frequency module:\n## only for kernel >= 5.6.0\nsudo modprobe intel-uncore-frequency\n```\n\n### Kernel's perf interface\n\nFor perf-related metrics, when Telegraf is not running as root, the following\ncapability should be added to the Telegraf executable:\n\n```sh\nsudo setcap cap_sys_admin+ep <path_to_telegraf_binary>\n```\n\nAlternatively, `/proc/sys/kernel/perf_event_paranoid` has to be set to value\nless than 1.\n\nDepending on environment and configuration (number of monitored CPUs and number\nof enabled metrics), it might be required to increase the limit on the number of\nopen file descriptors allowed. This can be done for example by using `ulimit -n`\ncommand.\n\n### Root privileges\n\n> [!IMPORTANT]\n> Telegraf with Intel PowerStat plugin enabled may require root privileges to\n> read all the metrics (depending on OS type or configuration).\n\nAlternatively, the following capabilities can be added to the Telegraf\nexecutable:\n\n```sh\n#without perf-related metrics:\nsudo setcap cap_sys_rawio,cap_dac_read_search+ep <path_to_telegraf_binary>\n\n#with perf-related metrics:\nsudo setcap cap_sys_rawio,cap_dac_read_search,cap_sys_admin+ep <path_to_telegraf_binary>\n```\n\n### Supported hardware\n\nSpecific metrics require certain processor features to be present, otherwise\nIntel PowerStat plugin won't be able to read them. The user can detect supported\nprocessor features by reading `/proc/cpuinfo` file.\nPlugin assumes crucial properties are the same for all CPU cores in the system.\n\nThe following `processor` properties are examined in more detail\nin this section:\n\n- `vendor_id`\n- `cpu family`\n- `model`\n- `flags`\n\nThe following processor properties are required by the plugin:\n\n- Processor `vendor_id` must be `GenuineIntel` and `cpu family` must be `6` -\n  since data used by the plugin are Intel-specific.\n- The following processor flags shall be present:\n  - `msr` shall be present for plugin to read platform data from processor\n    model specific registers and collect the following metrics:\n    - `cpu_c0_state_residency`\n    - `cpu_c1_state_residency`\n    - `cpu_c3_state_residency`\n    - `cpu_c6_state_residency`\n    - `cpu_c7_state_residency`\n    - `cpu_busy_frequency`\n    - `cpu_temperature`\n    - `cpu_base_frequency`\n    - `max_turbo_frequency`\n    - `uncore_frequency` (for kernel < 5.18)\n  - `aperfmperf` shall be present to collect the following metrics:\n    - `cpu_c0_state_residency`\n    - `cpu_c1_state_residency`\n    - `cpu_busy_frequency`\n  - `dts` shall be present to collect:\n    - `cpu_temperature`\n- supported CPU model. To see which metrics are supported by your `model`. The\n  following metrics exist:\n  - `cpu_c1_state_residency`\n  - `cpu_c3_state_residency`\n  - `cpu_c6_state_residency`\n  - `cpu_c7_state_residency`\n  - `cpu_temperature`\n  - `cpu_base_frequency`\n  - `uncore_frequency`\n\n### Supported CPU models\n\n| Model number | Processor name                  | `cpu_c1_state_residency`<br/>`cpu_c6_state_residency`<br/>`cpu_temperature`<br/>`cpu_base_frequency` | `cpu_c3_state_residency` | `cpu_c7_state_residency` | `uncore_frequency` |\n|--------------|---------------------------------|:----------------------------------------------------------------------------------------------------:|:------------------------:|:------------------------:|:------------------:|\n| 0x1E         | Intel Nehalem                   |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x1F         | Intel Nehalem-G                 |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x1A         | Intel Nehalem-EP                |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x2E         | Intel Nehalem-EX                |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x25         | Intel Westmere                  |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x2C         | Intel Westmere-EP               |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x2F         | Intel Westmere-EX               |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x2A         | Intel Sandybridge               |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x2D         | Intel Sandybridge-X             |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x3A         | Intel Ivybridge                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x3E         | Intel Ivybridge-X               |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x3C         | Intel Haswell                   |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x3F         | Intel Haswell-X                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x45         | Intel Haswell-L                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x46         | Intel Haswell-G                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x3D         | Intel Broadwell                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x47         | Intel Broadwell-G               |                                                  ✓                                                   |            ✓             |            ✓             |         ✓          |\n| 0x4F         | Intel Broadwell-X               |                                                  ✓                                                   |            ✓             |                          |         ✓          |\n| 0x56         | Intel Broadwell-D               |                                                  ✓                                                   |            ✓             |                          |         ✓          |\n| 0x4E         | Intel Skylake-L                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x5E         | Intel Skylake                   |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x55         | Intel Skylake-X                 |                                                  ✓                                                   |                          |                          |         ✓          |\n| 0x8E         | Intel KabyLake-L                |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x9E         | Intel KabyLake                  |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0xA5         | Intel CometLake                 |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0xA6         | Intel CometLake-L               |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x66         | Intel CannonLake-L              |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x6A         | Intel IceLake-X                 |                                                  ✓                                                   |                          |                          |         ✓          |\n| 0x6C         | Intel IceLake-D                 |                                                  ✓                                                   |                          |                          |         ✓          |\n| 0x7D         | Intel IceLake                   |                                                  ✓                                                   |                          |                          |                    |\n| 0x7E         | Intel IceLake-L                 |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x9D         | Intel IceLake-NNPI              |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0xA7         | Intel RocketLake                |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x8C         | Intel TigerLake-L               |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x8D         | Intel TigerLake                 |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x8F         | Intel Sapphire Rapids X         |                                                  ✓                                                   |                          |                          |         ✓          |\n| 0xCF         | Intel Emerald Rapids X          |                                                  ✓                                                   |                          |                          |         ✓          |\n| 0xAD         | Intel Granite Rapids X          |                                                  ✓                                                   |                          |                          |                    |\n| 0xAE         | Intel Granite Rapids D          |                                                  ✓                                                   |                          |                          |                    |\n| 0x8A         | Intel Lakefield                 |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x97         | Intel AlderLake                 |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0x9A         | Intel AlderLake-L               |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xB7         | Intel RaptorLake                |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xBA         | Intel RaptorLake-P              |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xBF         | Intel RaptorLake-S              |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xAC         | Intel MeteorLake                |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xAA         | Intel MeteorLake-L              |                                                  ✓                                                   |                          |            ✓             |         ✓          |\n| 0xC6         | Intel ArrowLake                 |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0xBD         | Intel LunarLake                 |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x37         | Intel Atom® Bay Trail           |                                                  ✓                                                   |                          |                          |                    |\n| 0x4D         | Intel Atom® Avaton              |                                                  ✓                                                   |                          |                          |                    |\n| 0x4A         | Intel Atom® Merrifield          |                                                  ✓                                                   |                          |                          |                    |\n| 0x5A         | Intel Atom® Moorefield          |                                                  ✓                                                   |                          |                          |                    |\n| 0x4C         | Intel Atom® Airmont             |                                                  ✓                                                   |            ✓             |                          |                    |\n| 0x5C         | Intel Atom® Apollo Lake         |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x5F         | Intel Atom® Denverton           |                                                  ✓                                                   |                          |                          |                    |\n| 0x7A         | Intel Atom® Goldmont            |                                                  ✓                                                   |            ✓             |            ✓             |                    |\n| 0x86         | Intel Atom® Jacobsville         |                                                  ✓                                                   |                          |                          |                    |\n| 0x96         | Intel Atom® Elkhart Lake        |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0x9C         | Intel Atom® Jasper Lake         |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0xBE         | Intel AlderLake-N               |                                                  ✓                                                   |                          |            ✓             |                    |\n| 0xAF         | Intel Sierra Forest             |                                                  ✓                                                   |                          |                          |                    |\n| 0xB6         | Intel Grand Ridge               |                                                  ✓                                                   |                          |                          |                    |\n| 0x57         | Intel Xeon® PHI Knights Landing |                                                  ✓                                                   |                          |                          |                    |\n| 0x85         | Intel Xeon® PHI Knights Mill    |                                                  ✓                                                   |                          |                          |                    |\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Intel PowerStat plugin enables monitoring of platform metrics (power, TDP)\n# and per-CPU metrics like temperature, power and utilization. Please see the\n# plugin readme for details on software and hardware compatibility.\n# This plugin ONLY supports Linux.\n[[inputs.intel_powerstat]]\n  ## The user can choose which package metrics are monitored by the plugin with\n  ## the package_metrics setting:\n  ## - The default, will collect \"current_power_consumption\",\n  ##   \"current_dram_power_consumption\" and \"thermal_design_power\".\n  ## - Leaving this setting empty means no package metrics will be collected.\n  ## - Finally, a user can specify individual metrics to capture from the\n  ##   supported options list.\n  ## Supported options:\n  ##   \"current_power_consumption\", \"current_dram_power_consumption\",\n  ##   \"thermal_design_power\", \"max_turbo_frequency\", \"uncore_frequency\",\n  ##   \"cpu_base_frequency\"\n  # package_metrics = [\"current_power_consumption\", \"current_dram_power_consumption\", \"thermal_design_power\"]\n\n  ## The user can choose which per-CPU metrics are monitored by the plugin in\n  ## cpu_metrics array.\n  ## Empty or missing array means no per-CPU specific metrics will be collected\n  ## by the plugin.\n  ## Supported options:\n  ##   \"cpu_frequency\", \"cpu_c0_state_residency\", \"cpu_c1_state_residency\",\n  ##   \"cpu_c3_state_residency\", \"cpu_c6_state_residency\", \"cpu_c7_state_residency\",\n  ##   \"cpu_temperature\", \"cpu_busy_frequency\", \"cpu_c0_substate_c01\",\n  ##   \"cpu_c0_substate_c02\", \"cpu_c0_substate_c0_wait\"\n  # cpu_metrics = []\n\n  ## CPUs metrics to include from those configured in cpu_metrics array\n  ## Can't be combined with excluded_cpus. Empty means all CPUs are gathered.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # included_cpus = []\n\n  ## CPUs metrics to exclude from those configured in cpu_metrics array\n  ## Can't be combined with included_cpus. Empty means all CPUs are gathered.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # excluded_cpus = []\n\n  ## Filesystem location of JSON file that contains PMU event definitions.\n  ## Mandatory only for perf-related metrics (cpu_c0_substate_c01, cpu_c0_substate_c02, cpu_c0_substate_c0_wait).\n  # event_definitions = \"\"\n\n  ## The user can set the timeout duration for MSR reading.\n  ## Enabling this timeout can be useful in situations where, on heavily loaded systems,\n  ## the code waits too long for a kernel response to MSR read requests.\n  ## 0 disables the timeout (default).\n  # msr_read_timeout = \"0ms\"\n```\n\n1. The configuration of `included_cpus` or `excluded_cpus` may affect the\n   ability to collect `package_metrics`. Some of them\n   (`max_turbo_frequency`, `cpu_base_frequency`, and `uncore_frequency`) need to\n   read data from exactly one processor for each package. If `included_cpus` or\n   `excluded_cpus` exclude all processors from the package, reading th\n   mentioned metrics for that package will not be possible.\n2. `event_definitions` JSON file for specific architecture can be found at\n   [perfmon][perfmon]. A script to download the event definition that is\n   appropriate for current environment (`event_download.py`) is available at\n   [pmu-tools][pmu_tools]. For perf-related metrics supported by this plugin,\n   an event definition JSON file with events for the `core` is required, e.g.\n   `sapphirerapids_core.json` or `GenuineIntel-6-8F-core.json`.\n\n[perfmon]: https://github.com/intel/perfmon\n[pmu_tools]: https://github.com/andikleen/pmu-tools\n\n### Dependencies of metrics on system configuration\n\nDetails of these dependencies are discussed above:\n\n| Configuration option                                                     | Type              | Dependency        |\n|--------------------------------------------------------------------------|-------------------|-------------------|\n| `current_power_consumption`                                              | `package_metrics` | `rapl` module     |\n| `current_dram_power_consumption`                                         | `package_metrics` | `rapl` module     |\n| `thermal_design_power`                                                   | `package_metrics` | `rapl` module     |\n| `max_turbo_frequency`                                                    | `package_metrics` | `msr`  module     |\n| `uncore_frequency`                                                       | `package_metrics` | `intel-uncore-frequency` module* |\n| `cpu_base_frequency`                                                     | `package_metrics` | `msr`  module     |\n| `cpu_frequency`                                                          | `cpu_metrics`     | `cpufreq`  module |\n| `cpu_c0_state_residency`                                                 | `cpu_metrics`     | `msr`  module     |\n| `cpu_c1_state_residency`                                                 | `cpu_metrics`     | `msr`  module     |\n| `cpu_c3_state_residency`                                                 | `cpu_metrics`     | `msr`  module     |\n| `cpu_c6_state_residency`                                                 | `cpu_metrics`     | `msr`  module     |\n| `cpu_c7_state_residency`                                                 | `cpu_metrics`     | `msr`  module     |\n| `cpu_temperature`                                                        | `cpu_metrics`     | `msr`  module     |\n| `cpu_busy_frequency`                                                     | `cpu_metrics`     | `msr`  module     |\n| `cpu_c0_substate_c01`                                                    | `cpu_metrics`     | `perf` interface  |\n| `cpu_c0_substate_c02`                                                    | `cpu_metrics`     | `perf` interface  |\n| `cpu_c0_substate_c0_wait`                                                | `cpu_metrics`     | `perf` interface  |\n\n*for all metrics enabled by the configuration option `uncore_frequency`,\nstarting from kernel version 5.18, only the `intel-uncore-frequency` module\nis required. For older kernel versions, the metric `uncore_frequency_mhz_cur`\nrequires the `msr` module to be enabled.\n\n### Example: Configuration with no per-CPU telemetry\n\nThis configuration allows getting default processor package specific metrics,\nno per-CPU metrics are collected:\n\n```toml\n[[inputs.intel_powerstat]]\n  cpu_metrics = []\n```\n\n### Example: Configuration with no per-CPU telemetry - equivalent case\n\nThis configuration allows getting default processor package specific metrics,\nno per-CPU metrics are collected:\n\n```toml\n[[inputs.intel_powerstat]]\n```\n\n### Example: Configuration for CPU Temperature and CPU Frequency\n\nThis configuration allows getting default processor package specific metrics,\nplus subset of per-CPU metrics (CPU Temperature and CPU Frequency) which will be\ngathered only for `cpu_id = 0`:\n\n```toml\n[[inputs.intel_powerstat]]\n  cpu_metrics = [\"cpu_frequency\", \"cpu_temperature\"]\n  included_cpus = [\"0\"]\n```\n\n### Example: Configuration for CPU Temperature and CPU Frequency without default package metrics\n\nThis configuration allows getting only a subset of per-CPU metrics\n(CPU Temperature and CPU Frequency) which will be gathered for\nall `cpus` except `cpu_id = [\"1-3\"]`:\n\n```toml\n[[inputs.intel_powerstat]]\n  package_metrics = []\n  cpu_metrics = [\"cpu_frequency\", \"cpu_temperature\"]\n  excluded_cpus = [\"1-3\"]\n```\n\n### Example: Configuration with all available metrics\n\nThis configuration allows getting all processor package specific metrics and\nall per-CPU metrics:\n\n```toml\n[[inputs.intel_powerstat]]\n  package_metrics = [\"current_power_consumption\", \"current_dram_power_consumption\", \"thermal_design_power\", \"max_turbo_frequency\", \"uncore_frequency\", \"cpu_base_frequency\"]\n  cpu_metrics = [\"cpu_frequency\", \"cpu_c0_state_residency\", \"cpu_c1_state_residency\", \"cpu_c3_state_residency\", \"cpu_c6_state_residency\", \"cpu_c7_state_residency\", \"cpu_temperature\", \"cpu_busy_frequency\", \"cpu_c0_substate_c01\", \"cpu_c0_substate_c02\", \"cpu_c0_substate_c0_wait\"]\n  event_definitions = \"/home/telegraf/.cache/pmu-events/GenuineIntel-6-8F-core.json\"\n```\n\n## Metrics\n\nAll metrics collected by Intel PowerStat plugin are collected in fixed\nintervals. Metrics that reports processor C-state residency or power are\ncalculated over elapsed intervals.\n\nThe following measurements are supported by Intel PowerStat plugin:\n\n- `powerstat_core`\n  - The following tags are returned by plugin with\n    `powerstat_core` measurements:\n\n      | Tag          | Description                    |\n      |--------------|--------------------------------|\n      | `package_id` | ID of platform package/socket. |\n      | `core_id`    | ID of physical processor core. |\n      | `cpu_id`     | ID of logical processor core.  |\n\n    Measurement `powerstat_core` metrics are collected per-CPU (`cpu_id` is the key)\n    while `core_id` and `package_id` tags are additional topology information.\n\n  - Available metrics for `powerstat_core` measurement:\n\n      | Metric name (field)               | Description                                                                                                                                                               | Units           |\n      |-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|\n      | `cpu_frequency_mhz`               | Current operational frequency of CPU Core.                                                                                                                                | MHz             |\n      | `cpu_busy_frequency_mhz`          | CPU Core Busy Frequency measured as frequency adjusted to CPU Core busy cycles.                                                                                           | MHz             |\n      | `cpu_temperature_celsius`         | Current temperature of CPU Core.                                                                                                                                          | Celsius degrees |\n      | `cpu_c0_state_residency_percent`  | Percentage of time that CPU Core spent in C0 Core residency state.                                                                                                        | %               |\n      | `cpu_c1_state_residency_percent`  | Percentage of time that CPU Core spent in C1 Core residency state.                                                                                                        | %               |\n      | `cpu_c3_state_residency_percent`  | Percentage of time that CPU Core spent in C3 Core residency state.                                                                                                        | %               |\n      | `cpu_c6_state_residency_percent`  | Percentage of time that CPU Core spent in C6 Core residency state.                                                                                                        | %               |\n      | `cpu_c7_state_residency_percent`  | Percentage of time that CPU Core spent in C7 Core residency state.                                                                                                        | %               |\n      | `cpu_c0_substate_c01_percent`     | Percentage of time that CPU Core spent in C0.1 substate out of the total time in the C0 state.                                                                            | %               |\n      | `cpu_c0_substate_c02_percent`     | Percentage of time that CPU Core spent in C0.2 substate out of the total time in the C0 state.                                                                            | %               |\n      | `cpu_c0_substate_c0_wait_percent` | Percentage of time that CPU Core spent in C0_Wait substate out of the total time in the C0 state.                                                                         | %               |\n\n- `powerstat_package`\n  - The following tags are returned by plugin with `powerstat_package` measurements:\n\n      | Tag            | Description                                                                                                                                                                                                                    |\n      |----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n      | `package_id`   | ID of platform package/socket.                                                                                                                                                                                                 |\n      | `active_cores` | Specific tag for `max_turbo_frequency_mhz` metric. The maximum number of activated cores for reachable turbo frequency.                                                                                                        |\n      | `hybrid`       | Specific tag for `max_turbo_frequency_mhz` metric. Available only for hybrid processors. Will be set to `primary` for primary cores of a hybrid architecture, and to `secondary` for secondary cores of a hybrid architecture. |\n      | `die`          | Specific tag for all `uncore_frequency` metrics. Id of die.                                                                                                                                                                    |\n      | `type`         | Specific tag for all `uncore_frequency` metrics. Type of uncore frequency (`current` or `initial`).                                                                                                                            |\n\n    Measurement `powerstat_package` metrics are collected per processor package\n    `package_id` tag indicates which package metric refers to.\n\n  - Available metrics for `powerstat_package` measurement:\n\n      | Metric name (field)                    | Description                                                                                                                                                                                                                                                                                                                                                                  | Units |\n      |----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|\n      | `thermal_design_power_watts`           | Maximum Thermal Design Power (TDP) available for processor package.                                                                                                                                                                                                                                                                                                          | Watts |\n      | `current_power_consumption_watts`      | Current power consumption of processor package.                                                                                                                                                                                                                                                                                                                              | Watts |\n      | `current_dram_power_consumption_watts` | Current power consumption of processor package DRAM subsystem.                                                                                                                                                                                                                                                                                                               | Watts |\n      | `max_turbo_frequency_mhz`              | Maximum reachable turbo frequency for number of cores active.                                                                                                                                                                                                                                                                                                                | MHz   |\n      | `uncore_frequency_limit_mhz_min`       | Minimum uncore frequency limit for die in processor package.                                                                                                                                                                                                                                                                                                                 | MHz   |\n      | `uncore_frequency_limit_mhz_max`       | Maximum uncore frequency limit for die in processor package.                                                                                                                                                                                                                                                                                                                 | MHz   |\n      | `uncore_frequency_mhz_cur`             | Current uncore frequency for die in processor package. Available only with tag `current`. This value is available from `intel-uncore-frequency` module for kernel >= 5.18. For older kernel versions it needs to be accessed via MSR. In case of lack of loaded `msr`, only `uncore_frequency_limit_mhz_min` and `uncore_frequency_limit_mhz_max` metrics will be collected. | MHz   |\n      | `cpu_base_frequency_mhz`               | CPU Base Frequency (maximum non-turbo frequency) for the processor package.                                                                                                                                                                                                                                                                                                  | MHz   |\n\n### Known issues\n\nStarting from Linux kernel version v5.4.77, due to\n[this kernel change][19f6d91b], resources such as\n`/sys/devices/virtual/powercap/intel-rapl//*/energy_uj`\ncan only be accessed by the root user for security reasons.\nTherefore, this plugin requires root privileges to gather\n`rapl` metrics correctly.\n\nIf such strict security restrictions are not relevant, reading permissions for\nfiles in the `/sys/devices/virtual/powercap/intel-rapl/` directory can be\nmanually altered, for example, using the chmod command with custom parameters.\nFor instance, read and execute permissions for all files in the\nintel-rapl directory can be granted to all users using:\n\n```bash\nsudo chmod -R a+rx /sys/devices/virtual/powercap/intel-rapl/\n```\n\n[19f6d91b]: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.4.77&id=19f6d91bdad42200aac557a683c17b1f65ee6c94\n\n## Example Output\n\n```text\npowerstat_package,host=ubuntu,package_id=0 thermal_design_power_watts=160 1606494744000000000\npowerstat_package,host=ubuntu,package_id=0 current_power_consumption_watts=35 1606494744000000000\npowerstat_package,host=ubuntu,package_id=0 cpu_base_frequency_mhz=2400i 1669118424000000000\npowerstat_package,host=ubuntu,package_id=0 current_dram_power_consumption_watts=13.94 1606494744000000000\npowerstat_package,host=ubuntu,package_id=0,active_cores=0 max_turbo_frequency_mhz=3000i 1606494744000000000\npowerstat_package,host=ubuntu,package_id=0,active_cores=1 max_turbo_frequency_mhz=2800i 1606494744000000000\npowerstat_package,die=0,host=ubuntu,package_id=0,type=initial uncore_frequency_limit_mhz_min=800,uncore_frequency_limit_mhz_max=2400 1606494744000000000\npowerstat_package,die=0,host=ubuntu,package_id=0,type=current uncore_frequency_mhz_cur=800i,uncore_frequency_limit_mhz_min=800,uncore_frequency_limit_mhz_max=2400 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_frequency_mhz=1200.29 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_temperature_celsius=34i 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_state_residency_percent=0.8 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c1_state_residency_percent=6.68 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c3_state_residency_percent=0 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c6_state_residency_percent=92.52 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c7_state_residency_percent=0 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_busy_frequency_mhz=1213.24 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c01_percent=0 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c02_percent=5.68 1606494744000000000\npowerstat_core,core_id=0,cpu_id=0,host=ubuntu,package_id=0 cpu_c0_substate_c0_wait_percent=43.74 1606494744000000000\n```\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/fetcher.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\tptel \"github.com/intel/powertelemetry\"\n)\n\n// topologyFetcher fetches topology information of the host.\ntype topologyFetcher interface {\n\t// GetMsrCPUIDs returns a slice with available CPU IDs of the host for which msr will access to.\n\tGetMsrCPUIDs() []int\n\n\t// GetPerfCPUIDs returns a slice with available CPU IDs of the host for which perf will access to.\n\tGetPerfCPUIDs() []int\n\n\t// GetPackageIDs returns a slice with available package IDs of the host.\n\tGetPackageIDs() []int\n\n\t// GetCPUPackageID returns the package ID of the host corresponding to the given CPU ID.\n\tGetCPUPackageID(cpuID int) (int, error)\n\n\t// GetCPUCoreID returns the core ID of the host corresponding to the given CPU ID.\n\tGetCPUCoreID(cpuID int) (int, error)\n\n\t// GetPackageDieIDs returns the die IDs of the host corresponding to the given package ID.\n\tGetPackageDieIDs(packageID int) ([]int, error)\n}\n\n// cpuFreqFetcher fetches supported CPU-related metrics relying on core frequency.\ntype cpuFreqFetcher interface {\n\t// GetCPUFrequency returns the current frequency value of a given CPU ID, in MHz.\n\tGetCPUFrequency(cpuID int) (float64, error)\n}\n\n// cpuMsrFetcher fetches supported CPU-related metrics relying on msr registers.\ntype cpuMsrFetcher interface {\n\t// GetCPUTemperature returns the temperature value of a given CPU ID, in degrees Celsius.\n\tGetCPUTemperature(cpuID int) (uint64, error)\n\n\t// UpdatePerCPUMetrics reads multiple MSR offsets needed to get metric values that are time sensitive.\n\t// Below are the list of methods that need the update to be performed beforehand.\n\tUpdatePerCPUMetrics(cpuID int) error\n\n\t// GetCPUC0StateResidency returns the C0 state residency value of a given CPU ID, as a percentage.\n\tGetCPUC0StateResidency(cpuID int) (float64, error)\n\n\t// GetCPUC1StateResidency returns the C1 state residency value of a given CPU ID, as a percentage.\n\tGetCPUC1StateResidency(cpuID int) (float64, error)\n\n\t// GetCPUC3StateResidency returns the C3 state residency value of a given CPU ID, as a percentage.\n\tGetCPUC3StateResidency(cpuID int) (float64, error)\n\n\t// GetCPUC6StateResidency returns the C6 state residency value of a given CPU ID, as a percentage.\n\tGetCPUC6StateResidency(cpuID int) (float64, error)\n\n\t// GetCPUC7StateResidency returns the C7 state residency value of a given CPU ID, as a percentage.\n\tGetCPUC7StateResidency(cpuID int) (float64, error)\n\n\t// GetCPUBusyFrequencyMhz returns the busy frequency value of a given CPU ID, in MHz.\n\tGetCPUBusyFrequencyMhz(cpuID int) (float64, error)\n}\n\n// cpuPerfFetcher fetches supported CPU-related metrics relying on perf events.\ntype cpuPerfFetcher interface {\n\t// ReadPerfEvents reads values of perf events needed to get C0X state residency metrics.\n\t// Below getter methods that need this operation to be performed previously.\n\tReadPerfEvents() error\n\n\t// DeactivatePerfEvents deactivates perf events. It closes file descriptors used to get perf event values.\n\tDeactivatePerfEvents() error\n\n\t// GetCPUC0SubstateC01Percent takes a CPU ID and returns a value indicating the percentage of time\n\t// the processor spent in its C0.1 substate out of the total time in the C0 state.\n\t// C0.1 is characterized by a light-weight slower wakeup time but more power-saving optimized state.\n\tGetCPUC0SubstateC01Percent(cpuID int) (float64, error)\n\n\t// GetCPUC0SubstateC02Percent takes a CPU ID and returns a value indicating the percentage of time\n\t// the processor spent in its C0.2 substate out of the total time in the C0 state.\n\t// C0.2 is characterized by a light-weight faster wakeup time but less power saving optimized state.\n\tGetCPUC0SubstateC02Percent(cpuID int) (float64, error)\n\n\t// GetCPUC0SubstateC0WaitPercent takes a CPU ID and returns a value indicating the percentage of time\n\t// the processor spent in its C0_Wait substate out of the total time in the C0 state.\n\t// CPU is in C0_Wait substate when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.\n\tGetCPUC0SubstateC0WaitPercent(cpuID int) (float64, error)\n}\n\n// packageRaplFetcher fetches supported package related metrics relying on rapl.\ntype packageRaplFetcher interface {\n\t// GetCurrentPackagePowerConsumptionWatts returns the current package power consumption value of a given package ID, in watts.\n\tGetCurrentPackagePowerConsumptionWatts(packageID int) (float64, error)\n\n\t// GetCurrentDramPowerConsumptionWatts returns the current dram power consumption value of a given package ID, in watts.\n\tGetCurrentDramPowerConsumptionWatts(packageID int) (float64, error)\n\n\t// GetPackageThermalDesignPowerWatts returns the thermal power design value of a given package ID, in watts.\n\tGetPackageThermalDesignPowerWatts(packageID int) (float64, error)\n}\n\n// packageUncoreFreqFetcher fetches supported package related metrics relying on uncore frequency.\ntype packageUncoreFreqFetcher interface {\n\t// GetInitialUncoreFrequencyMin returns the minimum initial uncore frequency value of a given package ID, in MHz.\n\tGetInitialUncoreFrequencyMin(packageID, dieID int) (float64, error)\n\n\t// GetInitialUncoreFrequencyMax returns the maximum initial uncore frequency value of a given package ID, in MHz.\n\tGetInitialUncoreFrequencyMax(packageID, dieID int) (float64, error)\n\n\t// GetCustomizedUncoreFrequencyMin returns the minimum custom uncore frequency value of a given package ID, in MHz.\n\tGetCustomizedUncoreFrequencyMin(packageID, dieID int) (float64, error)\n\n\t// GetCustomizedUncoreFrequencyMax returns the maximum custom uncore frequency value of a given package ID, in MHz.\n\tGetCustomizedUncoreFrequencyMax(packageID, dieID int) (float64, error)\n\n\t// GetCurrentUncoreFrequency returns the current uncore frequency value of a given package ID, in MHz.\n\tGetCurrentUncoreFrequency(packageID, dieID int) (float64, error)\n}\n\n// packageMsrFetcher fetches supported package related metrics relying on msr registers.\ntype packageMsrFetcher interface {\n\t// GetCPUBaseFrequency returns the CPU base frequency value of a given package ID, in MHz.\n\tGetCPUBaseFrequency(packageID int) (uint64, error)\n\n\t// GetMaxTurboFreqList returns a list of max turbo frequencies and related active cores of a given package ID.\n\tGetMaxTurboFreqList(packageID int) ([]ptel.MaxTurboFreq, error)\n}\n\n// metricFetcher fetches metrics supported by this plugin.\ntype metricFetcher interface {\n\ttopologyFetcher\n\n\tcpuFreqFetcher\n\tcpuMsrFetcher\n\tcpuPerfFetcher\n\n\tpackageRaplFetcher\n\tpackageUncoreFreqFetcher\n\tpackageMsrFetcher\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/intel_powerstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/intel/powertelemetry\"\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype PowerStat struct {\n\tCPUMetrics       []cpuMetricType     `toml:\"cpu_metrics\"`\n\tPackageMetrics   []packageMetricType `toml:\"package_metrics\"`\n\tIncludedCPUs     []string            `toml:\"included_cpus\"`\n\tExcludedCPUs     []string            `toml:\"excluded_cpus\"`\n\tEventDefinitions string              `toml:\"event_definitions\"`\n\tMsrReadTimeout   config.Duration     `toml:\"msr_read_timeout\"`\n\tLog              telegraf.Logger     `toml:\"-\"`\n\n\tparsedIncludedCores []int\n\tparsedExcludedCores []int\n\n\tparsedCPUTimedMsrMetrics []cpuMetricType\n\tparsedCPUPerfMetrics     []cpuMetricType\n\tparsedPackageRaplMetrics []packageMetricType\n\tparsedPackageMsrMetrics  []packageMetricType\n\n\toption  optionGenerator\n\tfetcher metricFetcher\n\n\tneedsCoreFreq       bool\n\tneedsMsrCPU         bool\n\tneedsPerf           bool\n\tneedsTimeRelatedMsr bool\n\n\tneedsRapl       bool\n\tneedsMsrPackage bool\n\n\tlogOnce map[string]struct{}\n}\n\nfunc (*PowerStat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *PowerStat) Init() error {\n\tif err := p.disableUnsupportedMetrics(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := p.parseConfig(); err != nil {\n\t\treturn err\n\t}\n\n\tp.option = &optGenerator{}\n\tp.logOnce = make(map[string]struct{})\n\n\treturn nil\n}\n\n// Start initializes the metricFetcher interface of the receiver to gather metrics.\nfunc (p *PowerStat) Start(_ telegraf.Accumulator) error {\n\topts := p.option.generate(optConfig{\n\t\tcpuMetrics:     p.CPUMetrics,\n\t\tpackageMetrics: p.PackageMetrics,\n\t\tincludedCPUs:   p.parsedIncludedCores,\n\t\texcludedCPUs:   p.parsedExcludedCores,\n\t\tperfEventFile:  p.EventDefinitions,\n\t\tmsrReadTimeout: time.Duration(p.MsrReadTimeout),\n\t\tlog:            p.Log,\n\t})\n\n\tvar err error\n\tvar initErr *powertelemetry.MultiError\n\tp.fetcher, err = powertelemetry.New(opts...)\n\tif err != nil {\n\t\tif !errors.As(err, &initErr) {\n\t\t\t// Error caused by failing to get information about the CPU, or CPU is not supported.\n\t\t\treturn fmt.Errorf(\"failed to initialize metric fetcher interface: %w\", err)\n\t\t}\n\n\t\t// One or more modules, needed to get metrics, failed to initialize. The plugin continues its execution, and it will not\n\t\t// gather metrics relying on these modules. Instead, logs the error message including module names that failed to initialize.\n\t\tp.Log.Warnf(\"Plugin started with errors: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *PowerStat) Gather(acc telegraf.Accumulator) error {\n\t// gather CPU metrics relying on coreFreq and msr which share CPU IDs.\n\tif p.needsCoreFreq || p.needsMsrCPU {\n\t\tp.addCPUMetrics(acc)\n\t}\n\n\t// gather CPU metrics relying on perf.\n\tif p.needsPerf {\n\t\tp.addCPUPerfMetrics(acc)\n\t}\n\n\t// gather package metrics.\n\tif len(p.PackageMetrics) != 0 {\n\t\tp.addPackageMetrics(acc)\n\t}\n\n\treturn nil\n}\n\n// Stop deactivates perf events if one or more of the requested metrics rely on perf.\nfunc (p *PowerStat) Stop() {\n\tif !p.needsPerf {\n\t\treturn\n\t}\n\n\tif err := p.fetcher.DeactivatePerfEvents(); err != nil {\n\t\tp.Log.Errorf(\"Failed to deactivate perf events: %v\", err)\n\t}\n}\n\n// parseConfig is a helper method that parses configuration fields from the receiver such as included/excluded CPU IDs.\nfunc (p *PowerStat) parseConfig() error {\n\tif p.MsrReadTimeout < 0 {\n\t\treturn errors.New(\"msr_read_timeout should be positive number or equal to 0 (to disable timeouts)\")\n\t}\n\n\tif err := p.parsePackageMetrics(); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse package metrics: %w\", err)\n\t}\n\n\tif err := p.parseCPUMetrics(); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse cpu metrics: %w\", err)\n\t}\n\n\tif len(p.CPUMetrics) == 0 && len(p.PackageMetrics) == 0 {\n\t\treturn errors.New(\"no metrics were found in the configuration file\")\n\t}\n\n\tp.parseCPUTimeRelatedMsrMetrics()\n\tp.parseCPUPerfMetrics()\n\n\tp.parsePackageRaplMetrics()\n\tp.parsePackageMsrMetrics()\n\n\tif len(p.ExcludedCPUs) != 0 && len(p.IncludedCPUs) != 0 {\n\t\treturn errors.New(\"both 'included_cpus' and 'excluded_cpus' configured; provide only one or none of the two\")\n\t}\n\n\tvar err error\n\tif len(p.ExcludedCPUs) != 0 {\n\t\tp.parsedExcludedCores, err = parseCores(p.ExcludedCPUs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse excluded CPUs: %w\", err)\n\t\t}\n\t}\n\n\tif len(p.IncludedCPUs) != 0 {\n\t\tp.parsedIncludedCores, err = parseCores(p.IncludedCPUs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse included CPUs: %w\", err)\n\t\t}\n\t}\n\n\tp.needsCoreFreq = needsCoreFreq(p.CPUMetrics)\n\tp.needsMsrCPU = needsMsrCPU(p.CPUMetrics)\n\tp.needsPerf = needsPerf(p.CPUMetrics)\n\tp.needsTimeRelatedMsr = needsTimeRelatedMsr(p.CPUMetrics)\n\n\tp.needsRapl = needsRapl(p.PackageMetrics)\n\tp.needsMsrPackage = needsMsrPackage(p.PackageMetrics)\n\n\t// Skip checks on event_definitions file path if perf module is not needed.\n\tif !p.needsPerf {\n\t\treturn nil\n\t}\n\n\t// Check that event_definitions option contains a valid file path.\n\tif len(p.EventDefinitions) == 0 {\n\t\treturn errors.New(\"'event_definitions' contains an empty path\")\n\t}\n\n\tfInfo, err := os.Lstat(p.EventDefinitions)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"'event_definitions' file %q does not exist\", p.EventDefinitions)\n\t\t}\n\t\treturn fmt.Errorf(\"could not get the info for file %q: %w\", p.EventDefinitions, err)\n\t}\n\n\t// Check that file is not a symlink.\n\tif fMode := fInfo.Mode(); fMode&os.ModeSymlink != 0 {\n\t\treturn fmt.Errorf(\"file %q is a symlink\", p.EventDefinitions)\n\t}\n\n\treturn nil\n}\n\n// parsePackageMetrics ensures there are no duplicates in 'package_metrics'.\n// If 'package_metrics' is not provided, the following default package metrics are set:\n// \"current_power_consumption\", \"current_dram_power_consumption\", and \"thermal_design_power\".\nfunc (p *PowerStat) parsePackageMetrics() error {\n\tif p.PackageMetrics == nil {\n\t\t// Sets default package metrics if `package_metrics` config option is an empty list.\n\t\tp.PackageMetrics = []packageMetricType{\n\t\t\tpackageCurrentPowerConsumption,\n\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\tpackageThermalDesignPower,\n\t\t}\n\t\treturn nil\n\t}\n\n\tif hasDuplicate(p.PackageMetrics) {\n\t\treturn errors.New(\"package metrics contains duplicates\")\n\t}\n\treturn nil\n}\n\n// parseCPUMetrics ensures there are no duplicates in 'cpu_metrics'.\nfunc (p *PowerStat) parseCPUMetrics() error {\n\tif hasDuplicate(p.CPUMetrics) {\n\t\treturn errors.New(\"cpu metrics contains duplicates\")\n\t}\n\treturn nil\n}\n\n// parsedCPUTimedMsrMetrics parses only the metrics which depend on time-related MSR offset reads from CPU metrics\n// of the receiver, and sets them to a separate slice.\nfunc (p *PowerStat) parseCPUTimeRelatedMsrMetrics() {\n\tp.parsedCPUTimedMsrMetrics = make([]cpuMetricType, 0)\n\tfor _, m := range p.CPUMetrics {\n\t\tswitch m {\n\t\tcase cpuC0StateResidency:\n\t\tcase cpuC1StateResidency:\n\t\tcase cpuC3StateResidency:\n\t\tcase cpuC6StateResidency:\n\t\tcase cpuC7StateResidency:\n\t\tcase cpuBusyFrequency:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tp.parsedCPUTimedMsrMetrics = append(p.parsedCPUTimedMsrMetrics, m)\n\t}\n}\n\n// parseCPUPerfMetrics parses only the metrics which depend on perf event reads from CPU metrics of the receiver, and sets\n// them to a separate slice.\nfunc (p *PowerStat) parseCPUPerfMetrics() {\n\tp.parsedCPUPerfMetrics = make([]cpuMetricType, 0)\n\tfor _, m := range p.CPUMetrics {\n\t\tswitch m {\n\t\tcase cpuC0SubstateC01Percent:\n\t\tcase cpuC0SubstateC02Percent:\n\t\tcase cpuC0SubstateC0WaitPercent:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tp.parsedCPUPerfMetrics = append(p.parsedCPUPerfMetrics, m)\n\t}\n}\n\n// parsePackageRaplMetrics parses only the metrics which depend on rapl from package metrics of the receiver, and sets\n// them to a separate slice.\nfunc (p *PowerStat) parsePackageRaplMetrics() {\n\tp.parsedPackageRaplMetrics = make([]packageMetricType, 0)\n\tfor _, m := range p.PackageMetrics {\n\t\tswitch m {\n\t\tcase packageCurrentPowerConsumption:\n\t\tcase packageCurrentDramPowerConsumption:\n\t\tcase packageThermalDesignPower:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tp.parsedPackageRaplMetrics = append(p.parsedPackageRaplMetrics, m)\n\t}\n}\n\n// parsePackageMsrMetrics parses only the metrics which depend on msr from package metrics of the receiver, and sets\n// them to a separate slice.\nfunc (p *PowerStat) parsePackageMsrMetrics() {\n\tp.parsedPackageMsrMetrics = make([]packageMetricType, 0)\n\tfor _, m := range p.PackageMetrics {\n\t\tswitch m {\n\t\tcase packageCPUBaseFrequency:\n\t\tcase packageTurboLimit:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tp.parsedPackageMsrMetrics = append(p.parsedPackageMsrMetrics, m)\n\t}\n}\n\n// hasDuplicate takes a slice of a generic type, and returns true\n// if the slice contains duplicates. Otherwise, it returns false.\nfunc hasDuplicate[S ~[]E, E comparable](s S) bool {\n\tm := make(map[E]struct{}, len(s))\n\tfor _, v := range s {\n\t\tif _, ok := m[v]; ok {\n\t\t\treturn true\n\t\t}\n\t\tm[v] = struct{}{}\n\t}\n\treturn false\n}\n\n// parseCores takes a slice of strings where each string represents a group of\n// one or more CPU IDs (e.g. [\"0\", \"1-3\", \"4,5,6\"] or [\"1-3,4\"]). It returns a slice\n// of integers.\nfunc parseCores(cores []string) ([]int, error) {\n\tparsedCores := make([]int, 0, len(cores))\n\tfor _, elem := range cores {\n\t\tpCores, err := parseGroupCores(elem)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse core group: %w\", err)\n\t\t}\n\t\tparsedCores = append(parsedCores, pCores...)\n\t}\n\n\tif hasDuplicate(parsedCores) {\n\t\treturn nil, errors.New(\"core values cannot be duplicated\")\n\t}\n\treturn parsedCores, nil\n}\n\n// parseGroupCores takes a string which represents a group of one or more\n// CPU IDs (e.g. \"0\", \"1-3\", or \"4,5,6\") and returns a slice of integers with\n// all CPU IDs within the group.\nfunc parseGroupCores(coreGroup string) ([]int, error) {\n\tcoreElems := strings.Split(coreGroup, \",\")\n\tcores := make([]int, 0, len(coreElems))\n\n\tfor _, coreElem := range coreElems {\n\t\tif strings.Contains(coreElem, \"-\") {\n\t\t\tpCores, err := parseCoreRange(coreElem)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse core range %q: %w\", coreElem, err)\n\t\t\t}\n\t\t\tcores = append(cores, pCores...)\n\t\t} else {\n\t\t\tsingleCore, err := strconv.Atoi(coreElem)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse single core %q: %w\", coreElem, err)\n\t\t\t}\n\t\t\tcores = append(cores, singleCore)\n\t\t}\n\t}\n\treturn cores, nil\n}\n\n// parseCoreRange takes a string representing a core range (e.g. \"0-4\"), and\n// returns a slice of integers with all elements within this range.\nfunc parseCoreRange(coreRange string) ([]int, error) {\n\trangeVals := strings.Split(coreRange, \"-\")\n\tif len(rangeVals) != 2 {\n\t\treturn nil, errors.New(\"invalid core range format\")\n\t}\n\n\tlow, err := strconv.Atoi(rangeVals[0])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse low bounds' core range: %w\", err)\n\t}\n\n\thigh, err := strconv.Atoi(rangeVals[1])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse high bounds' core range: %w\", err)\n\t}\n\n\tif high < low {\n\t\treturn nil, errors.New(\"high bound of core range cannot be less than low bound\")\n\t}\n\n\tcores := make([]int, high-low+1)\n\tfor i := range cores {\n\t\tcores[i] = i + low\n\t}\n\n\treturn cores, nil\n}\n\n// addCPUMetrics takes an accumulator, and adds to it enabled metrics which rely on\n// coreFreq and msr.\nfunc (p *PowerStat) addCPUMetrics(acc telegraf.Accumulator) {\n\tfor _, cpuID := range p.fetcher.GetMsrCPUIDs() {\n\t\tcoreID, packageID, err := getDataCPUID(p.fetcher, cpuID)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to get coreFreq and/or msr metrics for CPU ID %v: %w\", cpuID, err))\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add requested metrics which rely on coreFreq.\n\t\tif p.needsCoreFreq {\n\t\t\tp.addCPUFrequency(acc, cpuID, coreID, packageID)\n\t\t}\n\n\t\t// Add requested metrics which rely on msr.\n\t\tif p.needsMsrCPU {\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\t\t}\n\t}\n}\n\n// addPerCPUMsrMetrics adds to the accumulator enabled metrics, which rely on msr,\n// for a given CPU ID. MSR-related metrics comprise single-time MSR read and several\n// time-related MSR offset reads.\nfunc (p *PowerStat) addPerCPUMsrMetrics(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\t// cpuTemperature metric is a single MSR offset read.\n\tif slices.Contains(p.CPUMetrics, cpuTemperature) {\n\t\tp.addCPUTemperature(acc, cpuID, coreID, packageID)\n\t}\n\n\tif !p.needsTimeRelatedMsr {\n\t\treturn\n\t}\n\n\t// Read several time-related MSR offsets.\n\tvar moduleErr *powertelemetry.ModuleNotInitializedError\n\terr := p.fetcher.UpdatePerCPUMetrics(cpuID)\n\tif err == nil {\n\t\t// Add time-related MSR offset metrics to the accumulator\n\t\tp.addCPUTimeRelatedMsrMetrics(acc, cpuID, coreID, packageID)\n\t\treturn\n\t}\n\n\t// Always add to the accumulator errors not related to module not initialized.\n\tif !errors.As(err, &moduleErr) {\n\t\tacc.AddError(fmt.Errorf(\"failed to update MSR time-related metrics for CPU ID %v: %w\", cpuID, err))\n\t\treturn\n\t}\n\n\t// Add only once module not initialized error related to msr module and updating time-related msr metrics.\n\tlogErrorOnce(\n\t\tacc,\n\t\tp.logOnce,\n\t\t\"msr_time_related\",\n\t\tfmt.Errorf(\"failed to update MSR time-related metrics: %w\", moduleErr),\n\t)\n}\n\n// addCPUTimeRelatedMsrMetrics adds to the accumulator enabled time-related MSR metrics,\n// for a given CPU ID. NOTE: Requires to run first fetcher.UpdatePerCPUMetrics method\n// to update the values of MSR offsets read.\nfunc (p *PowerStat) addCPUTimeRelatedMsrMetrics(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\tfor _, m := range p.parsedCPUTimedMsrMetrics {\n\t\tswitch m {\n\t\tcase cpuC0StateResidency:\n\t\t\tp.addCPUC0StateResidency(acc, cpuID, coreID, packageID)\n\t\tcase cpuC1StateResidency:\n\t\t\tp.addCPUC1StateResidency(acc, cpuID, coreID, packageID)\n\t\tcase cpuC3StateResidency:\n\t\t\tp.addCPUC3StateResidency(acc, cpuID, coreID, packageID)\n\t\tcase cpuC6StateResidency:\n\t\t\tp.addCPUC6StateResidency(acc, cpuID, coreID, packageID)\n\t\tcase cpuC7StateResidency:\n\t\t\tp.addCPUC7StateResidency(acc, cpuID, coreID, packageID)\n\t\tcase cpuBusyFrequency:\n\t\t\tp.addCPUBusyFrequency(acc, cpuID, coreID, packageID)\n\t\t}\n\t}\n}\n\n// addCPUPerfMetrics takes an accumulator, and adds to it enabled metrics which rely on perf.\nfunc (p *PowerStat) addCPUPerfMetrics(acc telegraf.Accumulator) {\n\tvar moduleErr *powertelemetry.ModuleNotInitializedError\n\n\t// Read events related to perf-related metrics.\n\terr := p.fetcher.ReadPerfEvents()\n\tif err != nil {\n\t\t// Always add to the accumulator errors not related to module not initialized.\n\t\tif !errors.As(err, &moduleErr) {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to read perf events: %w\", err))\n\t\t\treturn\n\t\t}\n\n\t\t// Add only once module not initialized error related to perf module and reading perf-related metrics.\n\t\tlogErrorOnce(\n\t\t\tacc,\n\t\t\tp.logOnce,\n\t\t\t\"perf_read\",\n\t\t\tfmt.Errorf(\"failed to read perf events: %w\", moduleErr),\n\t\t)\n\t\treturn\n\t}\n\n\tfor _, cpuID := range p.fetcher.GetPerfCPUIDs() {\n\t\tcoreID, packageID, err := getDataCPUID(p.fetcher, cpuID)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to get perf metrics for CPU ID %v: %w\", cpuID, err))\n\t\t\tcontinue\n\t\t}\n\n\t\tp.addPerCPUPerfMetrics(acc, cpuID, coreID, packageID)\n\t}\n}\n\n// addPerCPUPerfMetrics adds to the accumulator enabled metrics, which rely on perf, for a given CPU ID.\nfunc (p *PowerStat) addPerCPUPerfMetrics(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\tfor _, m := range p.parsedCPUPerfMetrics {\n\t\tswitch m {\n\t\tcase cpuC0SubstateC01Percent:\n\t\t\tp.addCPUC0SubstateC01Percent(acc, cpuID, coreID, packageID)\n\t\tcase cpuC0SubstateC02Percent:\n\t\t\tp.addCPUC0SubstateC02Percent(acc, cpuID, coreID, packageID)\n\t\tcase cpuC0SubstateC0WaitPercent:\n\t\t\tp.addCPUC0SubstateC0WaitPercent(acc, cpuID, coreID, packageID)\n\t\t}\n\t}\n}\n\n// getDataCPUID takes a topologyFetcher and CPU ID, and returns the core ID and package ID corresponding to the CPU ID.\nfunc getDataCPUID(t topologyFetcher, cpuID int) (coreID, packageID int, err error) {\n\tcoreID, err = t.GetCPUCoreID(cpuID)\n\tif err != nil {\n\t\treturn 0, 0, fmt.Errorf(\"failed to get core ID from CPU ID %v: %w\", cpuID, err)\n\t}\n\n\tpackageID, err = t.GetCPUPackageID(cpuID)\n\tif err != nil {\n\t\treturn 0, 0, fmt.Errorf(\"failed to get package ID from CPU ID %v: %w\", cpuID, err)\n\t}\n\n\treturn coreID, packageID, nil\n}\n\n// addPackageMetrics takes an accumulator, and adds enabled package metrics to it.\nfunc (p *PowerStat) addPackageMetrics(acc telegraf.Accumulator) {\n\tfor _, packageID := range p.fetcher.GetPackageIDs() {\n\t\t// Add requested metrics which rely on rapl.\n\t\tif p.needsRapl {\n\t\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\t\t}\n\n\t\t// Add requested metrics which rely on msr.\n\t\tif p.needsMsrPackage {\n\t\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\t\t}\n\n\t\t// Add uncore frequency metric which relies on both uncoreFreq and msr.\n\t\tif slices.Contains(p.PackageMetrics, packageUncoreFrequency) {\n\t\t\tp.addUncoreFrequency(acc, packageID)\n\t\t}\n\t}\n}\n\n// addPerPackageRaplMetrics adds to the accumulator enabled metrics, which rely on rapl, for a given package ID.\nfunc (p *PowerStat) addPerPackageRaplMetrics(acc telegraf.Accumulator, packageID int) {\n\tfor _, m := range p.parsedPackageRaplMetrics {\n\t\tswitch m {\n\t\tcase packageCurrentPowerConsumption:\n\t\t\tp.addCurrentPackagePower(acc, packageID)\n\t\tcase packageCurrentDramPowerConsumption:\n\t\t\tp.addCurrentDramPower(acc, packageID)\n\t\tcase packageThermalDesignPower:\n\t\t\tp.addThermalDesignPower(acc, packageID)\n\t\t}\n\t}\n}\n\n// addPerPackageMsrMetrics adds to the accumulator enabled metrics, which rely on msr registers, for a given package ID.\nfunc (p *PowerStat) addPerPackageMsrMetrics(acc telegraf.Accumulator, packageID int) {\n\tfor _, m := range p.parsedPackageMsrMetrics {\n\t\tswitch m {\n\t\tcase packageCPUBaseFrequency:\n\t\t\tp.addCPUBaseFrequency(acc, packageID)\n\t\tcase packageTurboLimit:\n\t\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\t\t}\n\t}\n}\n\n// addCPUFrequency fetches CPU frequency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUFrequency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuFrequency,\n\t\t\t\tunits:  \"mhz\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUFrequency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUFrequency fetches CPU temperature metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUTemperature(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[uint64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuTemperature,\n\t\t\t\tunits:  \"celsius\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUTemperature,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC0StateResidency fetches C0 state residency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC0StateResidency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC0StateResidency,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC0StateResidency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC1StateResidency fetches C1 state residency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC1StateResidency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC1StateResidency,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC1StateResidency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC3StateResidency fetches C3 state residency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC3StateResidency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC3StateResidency,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC3StateResidency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC6StateResidency fetches C6 state residency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC6StateResidency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC6StateResidency,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC6StateResidency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC7StateResidency fetches C7 state residency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC7StateResidency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC7StateResidency,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC7StateResidency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUBusyFrequency fetches CPU busy frequency metric for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUBusyFrequency(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuBusyFrequency,\n\t\t\t\tunits:  \"mhz\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUBusyFrequencyMhz,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC0SubstateC01Percent fetches a value indicating the percentage of time the processor spent in its C0.1 substate\n// out of the total time in the C0 state for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC0SubstateC01Percent(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC0SubstateC01Percent,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC0SubstateC01Percent,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC0SubstateC02Percent fetches a value indicating the percentage of time the processor spent in its C0.2 substate\n// out of the total time in the C0 state for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC0SubstateC02Percent(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC0SubstateC02Percent,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC0SubstateC02Percent,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUC0SubstateC0WaitPercent fetches a value indicating the percentage of time the processor spent in its C0_Wait substate\n// out of the total time in the C0 state for a given CPU ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUC0SubstateC0WaitPercent(acc telegraf.Accumulator, cpuID, coreID, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&cpuMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: cpuC0SubstateC0WaitPercent,\n\t\t\t\tunits:  \"percent\",\n\t\t\t},\n\t\t\tcpuID:     cpuID,\n\t\t\tcoreID:    coreID,\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUC0SubstateC0WaitPercent,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCurrentPackagePower fetches the current package power metric for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCurrentPackagePower(acc telegraf.Accumulator, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&packageMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: packageCurrentPowerConsumption,\n\t\t\t\tunits:  \"watts\",\n\t\t\t},\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCurrentPackagePowerConsumptionWatts,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCurrentPackagePower fetches the current dram power metric for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCurrentDramPower(acc telegraf.Accumulator, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&packageMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: packageCurrentDramPowerConsumption,\n\t\t\t\tunits:  \"watts\",\n\t\t\t},\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCurrentDramPowerConsumptionWatts,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCurrentPackagePower fetches the thermal design power metric for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addThermalDesignPower(acc telegraf.Accumulator, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&packageMetric[float64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: packageThermalDesignPower,\n\t\t\t\tunits:  \"watts\",\n\t\t\t},\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetPackageThermalDesignPowerWatts,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addCPUBaseFrequency fetches the CPU base frequency metric for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addCPUBaseFrequency(acc telegraf.Accumulator, packageID int) {\n\taddMetric(\n\t\tacc,\n\t\t&packageMetric[uint64]{\n\t\t\tmetricCommon: metricCommon{\n\t\t\t\tmetric: packageCPUBaseFrequency,\n\t\t\t\tunits:  \"mhz\",\n\t\t\t},\n\t\t\tpackageID: packageID,\n\t\t\tfetchFn:   p.fetcher.GetCPUBaseFrequency,\n\t\t},\n\t\tp.logOnce,\n\t)\n}\n\n// addUncoreFrequency fetches the uncore frequency metrics for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addUncoreFrequency(acc telegraf.Accumulator, packageID int) {\n\tdieIDs, err := p.fetcher.GetPackageDieIDs(packageID)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"failed to get die IDs for package ID %v: %w\", packageID, err))\n\t\treturn\n\t}\n\n\tfor _, dieID := range dieIDs {\n\t\t// Add initial uncore frequency limits.\n\t\tp.addUncoreFrequencyInitialLimits(acc, packageID, dieID)\n\n\t\t// Add current uncore frequency limits and value.\n\t\tp.addUncoreFrequencyCurrentValues(acc, packageID, dieID)\n\t}\n}\n\n// addUncoreFrequencyInitialLimits fetches uncore frequency initial limits for a given pair of package and die ID,\n// and adds it to the accumulator.\nfunc (p *PowerStat) addUncoreFrequencyInitialLimits(acc telegraf.Accumulator, packageID, dieID int) {\n\tinitMin, initMax, err := getUncoreFreqInitialLimits(p.fetcher, packageID, dieID)\n\tif err == nil {\n\t\tacc.AddGauge(\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": round(initMin),\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": round(initMax),\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\treturn\n\t}\n\n\t// Always add to the accumulator errors not related to module not initialized.\n\tvar moduleErr *powertelemetry.ModuleNotInitializedError\n\tif !errors.As(err, &moduleErr) {\n\t\tacc.AddError(fmt.Errorf(\"failed to get initial uncore frequency limits for package ID %v and die ID %v: %w\", packageID, dieID, err))\n\t\treturn\n\t}\n\n\t// Add only once module not initialized error related to uncore_frequency module and uncore frequency initial limits.\n\tlogErrorOnce(\n\t\tacc,\n\t\tp.logOnce,\n\t\tfmt.Sprintf(\"%s_%s_initial\", moduleErr.Name, packageUncoreFrequency),\n\t\tfmt.Errorf(\"failed to get %q initial limits: %w\", packageUncoreFrequency, moduleErr),\n\t)\n}\n\n// addUncoreFrequencyCurrentValues fetches uncore frequency current limits and value for a given pair of package and die ID,\n// and adds it to the accumulator.\nfunc (p *PowerStat) addUncoreFrequencyCurrentValues(acc telegraf.Accumulator, packageID, dieID int) {\n\tval, err := getUncoreFreqCurrentValues(p.fetcher, packageID, dieID)\n\tif err == nil {\n\t\tacc.AddGauge(\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": round(val.currMin),\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": round(val.currMax),\n\t\t\t\t\"uncore_frequency_mhz_cur\":       uint64(val.curr),\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"current\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\treturn\n\t}\n\n\t// Always add to the accumulator errors not related to module not initialized.\n\tvar moduleErr *powertelemetry.ModuleNotInitializedError\n\tif !errors.As(err, &moduleErr) {\n\t\tacc.AddError(fmt.Errorf(\"failed to get current uncore frequency values for package ID %v and die ID %v: %w\", packageID, dieID, err))\n\t\treturn\n\t}\n\n\t// Add only once module not initialized error related to uncore_frequency module and uncore frequency current value and limits.\n\tlogErrorOnce(\n\t\tacc,\n\t\tp.logOnce,\n\t\tfmt.Sprintf(\"%s_%s_current\", moduleErr.Name, packageUncoreFrequency),\n\t\tfmt.Errorf(\"failed to get %q current value and limits: %w\", packageUncoreFrequency, moduleErr),\n\t)\n}\n\n// getUncoreFreqInitialLimits returns the initial uncore frequency limits of a given package ID and die ID.\nfunc getUncoreFreqInitialLimits(fetcher metricFetcher, packageID, dieID int) (initialMin, initialMax float64, err error) {\n\tinitialMin, err = fetcher.GetInitialUncoreFrequencyMin(packageID, dieID)\n\tif err != nil {\n\t\treturn 0.0, 0.0, fmt.Errorf(\"failed to get initial minimum uncore frequency limit: %w\", err)\n\t}\n\n\tinitialMax, err = fetcher.GetInitialUncoreFrequencyMax(packageID, dieID)\n\tif err != nil {\n\t\treturn 0.0, 0.0, fmt.Errorf(\"failed to get initial maximum uncore frequency limit: %w\", err)\n\t}\n\n\treturn initialMin, initialMax, nil\n}\n\ntype uncoreFreqValues struct {\n\tcurrMin float64\n\tcurrMax float64\n\tcurr    float64\n}\n\n// getUncoreFreqCurrentValues returns the current uncore frequency value as well as current min and max uncore frequency limits of a given\n// package ID and die ID.\nfunc getUncoreFreqCurrentValues(fetcher metricFetcher, packageID, dieID int) (uncoreFreqValues, error) {\n\tcurrMin, err := fetcher.GetCustomizedUncoreFrequencyMin(packageID, dieID)\n\tif err != nil {\n\t\treturn uncoreFreqValues{}, fmt.Errorf(\"failed to get current minimum uncore frequency limit: %w\", err)\n\t}\n\n\tcurrMax, err := fetcher.GetCustomizedUncoreFrequencyMax(packageID, dieID)\n\tif err != nil {\n\t\treturn uncoreFreqValues{}, fmt.Errorf(\"failed to get current maximum uncore frequency limit: %w\", err)\n\t}\n\n\tcurrent, err := fetcher.GetCurrentUncoreFrequency(packageID, dieID)\n\tif err != nil {\n\t\treturn uncoreFreqValues{}, fmt.Errorf(\"failed to get current uncore frequency: %w\", err)\n\t}\n\n\treturn uncoreFreqValues{\n\t\tcurrMin: currMin,\n\t\tcurrMax: currMax,\n\t\tcurr:    current,\n\t}, nil\n}\n\n// addMaxTurboFreqLimits fetches the max turbo frequency limits metric for a given package ID, and adds it to the accumulator.\nfunc (p *PowerStat) addMaxTurboFreqLimits(acc telegraf.Accumulator, packageID int) {\n\tvar moduleErr *powertelemetry.ModuleNotInitializedError\n\n\tturboFreqList, err := p.fetcher.GetMaxTurboFreqList(packageID)\n\tif err != nil {\n\t\t// Always add to the accumulator errors not related to module not initialized.\n\t\tif !errors.As(err, &moduleErr) {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to get %q for package ID %v: %w\", packageTurboLimit, packageID, err))\n\t\t\treturn\n\t\t}\n\n\t\t// Add only once module not initialized error related to msr module and max turbo frequency limits metric.\n\t\tlogErrorOnce(\n\t\t\tacc,\n\t\t\tp.logOnce,\n\t\t\tfmt.Sprintf(\"%s_%s\", moduleErr.Name, packageTurboLimit),\n\t\t\tfmt.Errorf(\"failed to get %q: %w\", packageTurboLimit, moduleErr),\n\t\t)\n\t\treturn\n\t}\n\n\tisHybrid := isHybridCPU(turboFreqList)\n\tfor _, v := range turboFreqList {\n\t\ttags := map[string]string{\n\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\"active_cores\": strconv.Itoa(int(v.ActiveCores)),\n\t\t}\n\n\t\tif isHybrid {\n\t\t\tvar hybridTag string\n\t\t\tif v.Secondary {\n\t\t\t\thybridTag = \"secondary\"\n\t\t\t} else {\n\t\t\t\thybridTag = \"primary\"\n\t\t\t}\n\t\t\ttags[\"hybrid\"] = hybridTag\n\t\t}\n\n\t\tacc.AddGauge(\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": v.Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\ttags,\n\t\t)\n\t}\n}\n\n// isHybridCPU is a helper function that takes a slice of MaxTurboFreq structs and returns true if the CPU where these values belong to,\n// is a hybrid CPU. Otherwise, returns false.\nfunc isHybridCPU(turboFreqList []powertelemetry.MaxTurboFreq) bool {\n\tfor _, v := range turboFreqList {\n\t\tif v.Secondary {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// disableUnsupportedMetrics checks whether the processor is capable of gathering specific metrics.\n// In case it is not, disableUnsupportedMetrics will disable the option to gather those metrics.\n// Error is returned if there is an issue with retrieving processor information.\nfunc (p *PowerStat) disableUnsupportedMetrics() error {\n\tcpus, err := cpu.Info()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error occurred while parsing CPU information: %w\", err)\n\t}\n\tif len(cpus) == 0 {\n\t\treturn errors.New(\"no CPUs were found\")\n\t}\n\n\t// First CPU is sufficient for verification\n\tfirstCPU := cpus[0]\n\tcpuModel, err := strconv.Atoi(firstCPU.Model)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error occurred while parsing CPU model: %w\", err)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUC1StateResidencySupported(cpuModel); err != nil {\n\t\tp.disableCPUMetric(cpuC1StateResidency)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUC3StateResidencySupported(cpuModel); err != nil {\n\t\tp.disableCPUMetric(cpuC3StateResidency)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUC6StateResidencySupported(cpuModel); err != nil {\n\t\tp.disableCPUMetric(cpuC6StateResidency)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUC7StateResidencySupported(cpuModel); err != nil {\n\t\tp.disableCPUMetric(cpuC7StateResidency)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUTemperatureSupported(cpuModel); err != nil {\n\t\tp.disableCPUMetric(cpuTemperature)\n\t}\n\n\tif err := powertelemetry.CheckIfCPUBaseFrequencySupported(cpuModel); err != nil {\n\t\tp.disablePackageMetric(packageCPUBaseFrequency)\n\t}\n\n\tallowedModelsForPerfRelated := []int{\n\t\t0x8F, // INTEL_FAM6_SAPPHIRERAPIDS_X\n\t\t0xCF, // INTEL_FAM6_EMERALDRAPIDS_X\n\t}\n\tif !slices.Contains(allowedModelsForPerfRelated, cpuModel) {\n\t\tp.disableCPUMetric(cpuC0SubstateC01Percent)\n\t\tp.disableCPUMetric(cpuC0SubstateC02Percent)\n\t\tp.disableCPUMetric(cpuC0SubstateC0WaitPercent)\n\t}\n\n\tif !slices.Contains(firstCPU.Flags, \"msr\") {\n\t\tp.disableCPUMetric(cpuC0StateResidency)\n\t\tp.disableCPUMetric(cpuC1StateResidency)\n\t\tp.disableCPUMetric(cpuC3StateResidency)\n\t\tp.disableCPUMetric(cpuC6StateResidency)\n\t\tp.disableCPUMetric(cpuC7StateResidency)\n\t\tp.disableCPUMetric(cpuBusyFrequency)\n\t\tp.disableCPUMetric(cpuTemperature)\n\t\tp.disablePackageMetric(packageCPUBaseFrequency)\n\t\tp.disablePackageMetric(packageTurboLimit)\n\t}\n\n\tif !slices.Contains(firstCPU.Flags, \"aperfmperf\") {\n\t\tp.disableCPUMetric(cpuC0StateResidency)\n\t\tp.disableCPUMetric(cpuC1StateResidency)\n\t\tp.disableCPUMetric(cpuBusyFrequency)\n\t}\n\n\tif !slices.Contains(firstCPU.Flags, \"dts\") {\n\t\tp.disableCPUMetric(cpuTemperature)\n\t}\n\n\treturn nil\n}\n\n// disableCPUMetric removes given cpu metric from cpu_metrics.\nfunc (p *PowerStat) disableCPUMetric(metricToDisable cpuMetricType) {\n\tstartLen := len(p.CPUMetrics)\n\tp.CPUMetrics = slices.DeleteFunc(p.CPUMetrics, func(cpuMetric cpuMetricType) bool {\n\t\treturn cpuMetric == metricToDisable\n\t})\n\n\tif len(p.CPUMetrics) < startLen {\n\t\tp.Log.Warnf(\"%q is not supported by CPU, metric will not be gathered.\", metricToDisable)\n\t}\n}\n\n// disablePackageMetric removes given package metric from package_metrics.\nfunc (p *PowerStat) disablePackageMetric(metricToDisable packageMetricType) {\n\tstartLen := len(p.PackageMetrics)\n\tp.PackageMetrics = slices.DeleteFunc(p.PackageMetrics, func(packageMetric packageMetricType) bool {\n\t\treturn packageMetric == metricToDisable\n\t})\n\n\tif len(p.PackageMetrics) < startLen {\n\t\tp.Log.Warnf(\"%q is not supported by CPU, metric will not be gathered.\", metricToDisable)\n\t}\n}\n\n// logErrorOnce takes an accumulator, a key string value error map, a key string and an error. It adds the error to the accumulator only if the\n// key is not in the logOnceMap. Additionally, if the key is not in logOnceMap map, adds the key to it. This is to prevent excessive error messages\n// from flooding the accumulator.\nfunc logErrorOnce(acc telegraf.Accumulator, logOnceMap map[string]struct{}, key string, err error) {\n\tif _, ok := logOnceMap[key]; !ok {\n\t\tacc.AddError(err)\n\t\tlogOnceMap[key] = struct{}{}\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"intel_powerstat\", func() telegraf.Input {\n\t\treturn &PowerStat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/intel_powerstat_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux || !amd64\n\npackage intel_powerstat\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IntelPowerstat struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*IntelPowerstat) SampleConfig() string { return sampleConfig }\n\nfunc (i *IntelPowerstat) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*IntelPowerstat) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"intel_powerstat\", func() telegraf.Input {\n\t\treturn &IntelPowerstat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/intel_powerstat_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\tptel \"github.com/intel/powertelemetry\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype parsePackageMetricTestCase struct {\n\tname    string\n\tmetrics []packageMetricType\n\tparsed  []packageMetricType\n\terr     error\n}\n\ntype parseCPUMetricTestCase struct {\n\tname    string\n\tmetrics []cpuMetricType\n\tparsed  []cpuMetricType\n\terr     error\n}\n\nfunc TestParsePackageMetrics(t *testing.T) {\n\ttestCases := []parsePackageMetricTestCase{\n\t\t{\n\t\t\tname:    \"NilSlice\",\n\t\t\tmetrics: nil,\n\t\t\tparsed: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]packageMetricType, 0),\n\t\t\tparsed:  make([]packageMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"HasDuplicates\",\n\t\t\tmetrics: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower, // duplicate\n\t\t\t},\n\t\t\terr: errors.New(\"package metrics contains duplicates\"),\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tPackageMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\terr := p.parsePackageMetrics()\n\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tc.parsed, p.PackageMetrics)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseCPUMetrics(t *testing.T) {\n\ttestCases := []parseCPUMetricTestCase{\n\t\t{\n\t\t\tname:    \"NilSlice\",\n\t\t\tmetrics: nil,\n\t\t\tparsed:  nil,\n\t\t},\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]cpuMetricType, 0),\n\t\t\tparsed:  make([]cpuMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"HasDuplicates\",\n\t\t\tmetrics: []cpuMetricType{\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuTemperature,\n\t\t\t\tcpuC0StateResidency, // duplicate\n\t\t\t},\n\t\t\terr: errors.New(\"cpu metrics contains duplicates\"),\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\terr := p.parseCPUMetrics()\n\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tc.parsed, p.CPUMetrics)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseCPUTimeRelatedMsrMetrics(t *testing.T) {\n\ttestCases := []parseCPUMetricTestCase{\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]cpuMetricType, 0),\n\t\t\tparsed:  make([]cpuMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"NotFound\",\n\t\t\tmetrics: []cpuMetricType{\n\t\t\t\t// Metric not relying on MSR.\n\t\t\t\tcpuFrequency,\n\n\t\t\t\t// Metric relying on single MSR read.\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics relying on perf events.\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t},\n\t\t\tparsed: make([]cpuMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"Found\",\n\t\t\tmetrics: []cpuMetricType{\n\t\t\t\t// Metric not relying on MSR.\n\t\t\t\tcpuFrequency,\n\n\t\t\t\t// Metric relying on single MSR read.\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics relying on time-related MSR offset reads.\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC3StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuC7StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\n\t\t\t\t// Metrics relying on perf events.\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t},\n\t\t\tparsed: []cpuMetricType{\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC3StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuC7StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\tp.parseCPUTimeRelatedMsrMetrics()\n\t\t\trequire.Equal(t, tc.parsed, p.parsedCPUTimedMsrMetrics)\n\t\t})\n\t}\n}\n\nfunc TestParseCPUPerfMetrics(t *testing.T) {\n\ttestCases := []parseCPUMetricTestCase{\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]cpuMetricType, 0),\n\t\t\tparsed:  make([]cpuMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"NotFound\",\n\t\t\tmetrics: []cpuMetricType{\n\t\t\t\t// Metric not relying on MSR.\n\t\t\t\tcpuFrequency,\n\n\t\t\t\t// Metric relying on single MSR read.\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics relying on time-related MSR offset reads.\n\t\t\t\tcpuC3StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\t\t\tparsed: make([]cpuMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"Found\",\n\t\t\tmetrics: []cpuMetricType{\n\t\t\t\t// Metric not relying on MSR.\n\t\t\t\tcpuFrequency,\n\n\t\t\t\t// Metric relying on single MSR read.\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics relying on perf events.\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\n\t\t\t\t// Metrics relying on time-related MSR offset reads.\n\t\t\t\tcpuC3StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\t\t\tparsed: []cpuMetricType{\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\tp.parseCPUPerfMetrics()\n\t\t\trequire.Equal(t, tc.parsed, p.parsedCPUPerfMetrics)\n\t\t})\n\t}\n}\n\nfunc TestParsePackageRaplMetrics(t *testing.T) {\n\ttestCases := []parsePackageMetricTestCase{\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]packageMetricType, 0),\n\t\t\tparsed:  make([]packageMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"NotFound\",\n\t\t\tmetrics: []packageMetricType{\n\t\t\t\t// Metrics not relying on rapl.\n\t\t\t\tpackageTurboLimit,\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t},\n\t\t\tparsed: make([]packageMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"Found\",\n\t\t\tmetrics: []packageMetricType{\n\t\t\t\t// Metrics not relying on rapl.\n\t\t\t\tpackageTurboLimit,\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\n\t\t\t\t// Metrics relying on rapl.\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t\tparsed: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tPackageMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\tp.parsePackageRaplMetrics()\n\t\t\trequire.Equal(t, tc.parsed, p.parsedPackageRaplMetrics)\n\t\t})\n\t}\n}\n\nfunc TestParsePackageMsrMetrics(t *testing.T) {\n\ttestCases := []parsePackageMetricTestCase{\n\t\t{\n\t\t\tname:    \"EmptySlice\",\n\t\t\tmetrics: make([]packageMetricType, 0),\n\t\t\tparsed:  make([]packageMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"NotFound\",\n\t\t\tmetrics: []packageMetricType{\n\t\t\t\t// Metrics not relying on msr.\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t\tparsed: make([]packageMetricType, 0),\n\t\t},\n\t\t{\n\t\t\tname: \"Found\",\n\t\t\tmetrics: []packageMetricType{\n\t\t\t\t// Metrics not relying on msr.\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\n\t\t\t\t// Metrics relying uniquely on msr.\n\t\t\t\tpackageTurboLimit,\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t},\n\t\t\tparsed: []packageMetricType{\n\t\t\t\tpackageTurboLimit,\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tp := &PowerStat{\n\t\t\t\tPackageMetrics: tc.metrics,\n\t\t\t}\n\n\t\t\tp.parsePackageMsrMetrics()\n\t\t\trequire.Equal(t, tc.parsed, p.parsedPackageMsrMetrics)\n\t\t})\n\t}\n}\n\nfunc TestParseCoreRange(t *testing.T) {\n\ttestCases := []struct {\n\t\tname      string\n\t\tcoreRange string\n\t\tcores     []int\n\t\terr       error\n\t}{\n\t\t{\n\t\t\tname:      \"InvalidFormat\",\n\t\t\tcoreRange: \"1,3\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"invalid core range format\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"LowerBoundNonNumeric\",\n\t\t\tcoreRange: \"a-10\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse low bounds' core range\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"MissingLowerBound\",\n\t\t\tcoreRange: \"-10\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse low bounds' core range\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"HigherBoundNonNumeric\",\n\t\t\tcoreRange: \"0-a\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse high bounds' core range\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"MissingHigherBound\",\n\t\t\tcoreRange: \"0-\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse high bounds' core range\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"InvalidBounds\",\n\t\t\tcoreRange: \"10-1\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"high bound of core range cannot be less than low bound\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"SingleCore\",\n\t\t\tcoreRange: \"1-1\",\n\t\t\tcores:     []int{1},\n\t\t},\n\t\t{\n\t\t\tname:      \"CoreRange\",\n\t\t\tcoreRange: \"5-10\",\n\t\t\tcores:     []int{5, 6, 7, 8, 9, 10},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tcoresOut, err := parseCoreRange(tc.coreRange)\n\n\t\t\trequire.Equal(t, tc.cores, coresOut)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseGroupCores(t *testing.T) {\n\ttestCases := []struct {\n\t\tname      string\n\t\tcoreGroup string\n\t\tcores     []int\n\t\terr       error\n\t}{\n\t\t{\n\t\t\tname:      \"FailedToParseCoreRange\",\n\t\t\tcoreGroup: \"1-a,7,9,11\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse core range \\\"1-a\\\"\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"FailedToParseSingleCore\",\n\t\t\tcoreGroup: \"1-5,7,b,11\",\n\t\t\tcores:     nil,\n\t\t\terr:       errors.New(\"failed to parse single core\"),\n\t\t},\n\t\t{\n\t\t\tname:      \"Ok\",\n\t\t\tcoreGroup: \"1-5,7,9,11\",\n\t\t\tcores:     []int{1, 2, 3, 4, 5, 7, 9, 11},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tcoresOut, err := parseGroupCores(tc.coreGroup)\n\n\t\t\trequire.Equal(t, tc.cores, coresOut)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHasDuplicate(t *testing.T) {\n\tt.Run(\"Int\", func(t *testing.T) {\n\t\tt.Run(\"False\", func(t *testing.T) {\n\t\t\tnums := []int{0, 1, 2, 3}\n\t\t\trequire.False(t, hasDuplicate(nums))\n\t\t})\n\n\t\tt.Run(\"True\", func(t *testing.T) {\n\t\t\tnums := []uint32{0, 1, 2, 3, 4, 5, 6, 1}\n\t\t\trequire.True(t, hasDuplicate(nums))\n\t\t})\n\t})\n\n\tt.Run(\"String\", func(t *testing.T) {\n\t\tt.Run(\"False\", func(t *testing.T) {\n\t\t\tstrs := []string{\"1\", \"2\", \"3\", \"4\"}\n\t\t\trequire.False(t, hasDuplicate(strs))\n\t\t})\n\n\t\tt.Run(\"True\", func(t *testing.T) {\n\t\t\tstrs := []string{\"1\", \"2\", \"3\", \"1\"}\n\t\t\trequire.True(t, hasDuplicate(strs))\n\t\t})\n\t})\n}\n\nfunc TestParseCores(t *testing.T) {\n\ttestCases := []struct {\n\t\tname       string\n\t\tcoreGroups []string\n\t\tcores      []int\n\t\terr        error\n\t}{\n\t\t{\n\t\t\tname:       \"InvalidCoreGroup\",\n\t\t\tcoreGroups: []string{\"1-4,11\", \"10-b\"},\n\t\t\tcores:      nil,\n\t\t\terr:        errors.New(\"failed to parse core group\"),\n\t\t},\n\t\t{\n\t\t\tname:       \"FoundDuplicates\",\n\t\t\tcoreGroups: []string{\"1-4,11\", \"10-12\"},\n\t\t\tcores:      nil,\n\t\t\terr:        errors.New(\"core values cannot be duplicated\"),\n\t\t},\n\t\t{\n\t\t\tname:       \"CoresIsNil\",\n\t\t\tcoreGroups: nil,\n\t\t\tcores:      make([]int, 0),\n\t\t},\n\t\t{\n\t\t\tname:       \"CoresIsEmpty\",\n\t\t\tcoreGroups: make([]string, 0),\n\t\t\tcores:      make([]int, 0),\n\t\t},\n\t\t{\n\t\t\tname:       \"Ok\",\n\t\t\tcoreGroups: []string{\"1-4,6\", \"8\", \"10-12\", \"15,20\"},\n\t\t\tcores:      []int{1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 20},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tcoresOut, err := parseCores(tc.coreGroups)\n\n\t\t\trequire.Equal(t, tc.cores, coresOut)\n\t\t\tif tc.err != nil {\n\t\t\t\trequire.ErrorContains(t, err, tc.err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseConfig(t *testing.T) {\n\tt.Run(\"BothCPUOptionsProvided\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tIncludedCPUs: []string{\"0-10,20-22\"},\n\t\t\tExcludedCPUs: []string{\"0\"},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"both 'included_cpus' and 'excluded_cpus' configured; provide only one or none of the two\")\n\t})\n\n\tt.Run(\"FailedToParseIncludedCPUs\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// has duplicates\n\t\t\tIncludedCPUs: []string{\"1-4,11\", \"10-12\"},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"failed to parse included CPUs\")\n\t})\n\n\tt.Run(\"FailedToParseExcludedCPUs\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// has non-numeric CPU ID\n\t\t\tExcludedCPUs: []string{\"1-4,b\"},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"failed to parse excluded CPUs\")\n\t})\n\n\tt.Run(\"FailedToParseCPUMetrics\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// has duplicates\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuFrequency,\n\t\t\t\tcpuTemperature,\n\t\t\t\tcpuFrequency, // duplicate\n\t\t\t},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"failed to parse cpu metrics\")\n\t})\n\n\tt.Run(\"EventDefinitionsNotProvidedForPerf\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// has duplicates\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"'event_definitions' contains an empty path\")\n\t})\n\n\tt.Run(\"EventDefinitionsDoesNotExist\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// has duplicates\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t},\n\t\t\tEventDefinitions: \"./testdata/doesNotExist.json\",\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"'event_definitions' file \\\"./testdata/doesNotExist.json\\\" does not exist\")\n\t})\n\n\tt.Run(\"NoMetricsProvided\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\t// Disable default package metrics.\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t}\n\n\t\trequire.ErrorContains(t, p.parseConfig(), \"no metrics were found in the configuration file\")\n\t})\n\n\tt.Run(\"DisablePackageMetrics\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\t\t\t// Disable default package metrics.\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\t\trequire.Empty(t, p.PackageMetrics)\n\t\trequire.Len(t, p.CPUMetrics, 1)\n\t})\n\n\tt.Run(\"DefaultPackageMetrics\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: nil, // default package metrics\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\t\trequire.Equal(t,\n\t\t\t[]packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t\tp.PackageMetrics)\n\t})\n\n\tt.Run(\"IncludedCPUs\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tIncludedCPUs: []string{\"0-5\"},\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\t\trequire.Equal(t, []int{0, 1, 2, 3, 4, 5}, p.parsedIncludedCores)\n\t\trequire.Nil(t, p.parsedExcludedCores)\n\t})\n\n\tt.Run(\"ExcludedCPUs\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tExcludedCPUs: []string{\"2-6\", \"8\", \"10\"},\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\t\trequire.Equal(t, []int{2, 3, 4, 5, 6, 8, 10}, p.parsedExcludedCores)\n\t\trequire.Nil(t, p.parsedIncludedCores)\n\t})\n\n\tt.Run(\"MetricsWithIncludedCPUs\", func(t *testing.T) {\n\t\tp := &PowerStat{\n\t\t\tIncludedCPUs: []string{\"0-3,6\"},\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC3StateResidency,\n\t\t\t},\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t\tpackageTurboLimit,\n\t\t\t},\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\t\trequire.Equal(t, []int{0, 1, 2, 3, 6}, p.parsedIncludedCores)\n\n\t\t// Check flags\n\t\trequire.True(t, p.needsMsrCPU)\n\t\trequire.True(t, p.needsTimeRelatedMsr)\n\t\trequire.False(t, p.needsCoreFreq)\n\t\trequire.False(t, p.needsPerf)\n\t})\n}\n\ntype mockOptGenerator struct {\n\tmock.Mock\n}\n\nfunc (m *mockOptGenerator) generate(cfg optConfig) []ptel.Option {\n\targs := m.Called(cfg)\n\treturn args.Get(0).([]ptel.Option)\n}\n\nfunc TestSampleConfig(t *testing.T) {\n\tp := &PowerStat{}\n\trequire.NotEmpty(t, p.SampleConfig())\n}\n\nfunc TestInit(t *testing.T) {\n\tt.Run(\"FailedToDisableUnsupportedMetrics\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/cpu_model_missing\")\n\n\t\tp := &PowerStat{}\n\n\t\trequire.ErrorContains(t, p.Init(), \"error occurred while parsing CPU model\")\n\t})\n\n\tt.Run(\"FailedToParseConfigWithDuplicates\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\t// has duplicates\n\t\t\tIncludedCPUs: []string{\"1-4,11\", \"10-12\"},\n\t\t\tLog:          logger,\n\t\t}\n\n\t\trequire.ErrorContains(t, p.Init(), \"failed to parse included CPUs\")\n\t\trequire.Empty(t, logger.Warnings())\n\t})\n\n\tt.Run(\"FailedToParseConfigWithNegativeTimeout\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\t// negative value\n\t\t\tMsrReadTimeout: -2,\n\t\t\tLog:            logger,\n\t\t}\n\n\t\trequire.ErrorContains(t, p.Init(), \"msr_read_timeout should be positive number or equal to 0 (to disable timeouts)\")\n\t\trequire.Empty(t, logger.Warnings())\n\t})\n}\n\nfunc TestStart(t *testing.T) {\n\tt.Run(\"FailedToStartCPUDoesNotExist\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata\")\n\n\t\tacc := &testutil.Accumulator{}\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\t// has CPU ID out of bounds\n\t\t\tparsedIncludedCores: []int{0, 9},\n\t\t\tLog:                 logger,\n\n\t\t\toption: &optGenerator{},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.Start(acc), \"failed to initialize metric fetcher interface\")\n\t\trequire.Empty(t, logger.Warnings())\n\t})\n\n\tt.Run(\"FailedToStartNotSupportedCPUVendor\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/vendor_not_supported\")\n\n\t\tacc := &testutil.Accumulator{}\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tLog:    logger,\n\t\t\toption: &optGenerator{},\n\t\t}\n\n\t\trequire.ErrorContains(t, p.Start(acc), \"host processor is not supported\")\n\t})\n\n\tt.Run(\"WithWarning\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata\")\n\n\t\tacc := &testutil.Accumulator{}\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tmOptGenerator := &mockOptGenerator{}\n\t\tmOptGenerator.On(\"generate\", mock.AnythingOfType(\"optConfig\")).Return(\n\t\t\t[]ptel.Option{\n\t\t\t\tptel.WithRapl(\"/dummy/path\"),\n\t\t\t},\n\t\t)\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption, // needs rapl\n\t\t\t},\n\t\t\tLog: logger,\n\n\t\t\toption: mOptGenerator,\n\t\t}\n\n\t\trequire.NoError(t, p.Start(acc))\n\t\trequire.Len(t, logger.Warnings(), 1)\n\t\trequire.Contains(t, logger.Warnings()[0], \"Plugin started with errors\")\n\t})\n}\n\nfunc TestGather(t *testing.T) {\n\tt.Run(\"WithoutMetrics\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t}\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t})\n\n\tt.Run(\"WithDefaultPackageMetrics\", func(t *testing.T) {\n\t\tpackageID := 0\n\n\t\tpackagePower := 10.0\n\t\tdramPower := 5.0\n\t\tthermalDesignPower := 20.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return([]int{packageID}).Once()\n\n\t\t// mock getting current package power consumption metric.\n\t\tmFetcher.On(\"GetCurrentPackagePowerConsumptionWatts\", packageID).Return(packagePower, nil).Once()\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(dramPower, nil).Once()\n\n\t\t// mock getting package thermal design power metric.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", packageID).Return(thermalDesignPower, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 3)\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"current_power_consumption_watts\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"current_dram_power_consumption_watts\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"thermal_design_power_watts\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithPackageMetrics\", func(t *testing.T) {\n\t\tpackageIDs := []int{0, 1, 2, 3}\n\n\t\tbaseFreq := uint64(200)\n\t\tpackagePower := 30.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return(packageIDs).Once()\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", mock.AnythingOfType(\"int\")).Return(baseFreq, nil).Times(len(packageIDs))\n\n\t\t// mock getting current package power consumption metric.\n\t\tmFetcher.On(\"GetCurrentPackagePowerConsumptionWatts\", mock.AnythingOfType(\"int\")).Return(packagePower, nil).Times(len(packageIDs))\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t},\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 8)\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"cpu_base_frequency_mhz\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"current_power_consumption_watts\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithCPUMetrics\", func(t *testing.T) {\n\t\tcpuIDs := []int{0, 1, 2, 3}\n\n\t\tcpuFreq := 123.5\n\t\tcpuTemp := uint64(20)\n\t\tcpuBusyFreq := 456.7\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\tmFetcher.On(\"GetMsrCPUIDs\").Return(cpuIDs).Once()\n\n\t\t// mock getting core ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock getting package ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock updating msr time-related metrics for CPU IDs.\n\t\tmFetcher.On(\"UpdatePerCPUMetrics\", mock.AnythingOfType(\"int\")).Return(nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU frequency for CPU IDs.\n\t\tmFetcher.On(\"GetCPUFrequency\", mock.AnythingOfType(\"int\")).Return(cpuFreq, nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU temperature metric for CPU IDs.\n\t\tmFetcher.On(\"GetCPUTemperature\", mock.AnythingOfType(\"int\")).Return(cpuTemp, nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU busy frequency metric for CPU IDs.\n\t\tmFetcher.On(\"GetCPUBusyFrequencyMhz\", mock.AnythingOfType(\"int\")).Return(cpuBusyFreq, nil).Times(len(cpuIDs))\n\n\t\tp := &PowerStat{\n\t\t\t// Disables package metrics\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuFrequency,\n\t\t\t\tcpuTemperature,\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 12)\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_frequency_mhz\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_temperature_celsius\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_busy_frequency_mhz\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithPerfMetrics\", func(t *testing.T) {\n\t\tcpuIDs := []int{0, 1, 2}\n\n\t\tc01 := 0.1\n\t\tc02 := 1.2\n\t\tc0Wait := 2.3\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\tmFetcher.On(\"GetPerfCPUIDs\").Return(cpuIDs).Once()\n\n\t\t// mock getting core ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock getting package ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU C01 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", mock.AnythingOfType(\"int\")).Return(c01, nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU C02 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", mock.AnythingOfType(\"int\")).Return(c02, nil).Times(len(cpuIDs))\n\n\t\t// mock getting CPU C0Wait metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC0WaitPercent\", mock.AnythingOfType(\"int\")).Return(c0Wait, nil).Times(len(cpuIDs))\n\n\t\tp := &PowerStat{\n\t\t\t// Disables package metrics\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t},\n\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 9)\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c0_substate_c01_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c0_substate_c02_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c0_substate_c0_wait_percent\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithPerfAndMsrCPUMetrics\", func(t *testing.T) {\n\t\tcpuIDsMsr := []int{0, 1, 2, 3}\n\t\tcpuIDsPerf := []int{0, 1}\n\n\t\tc1 := 0.5\n\t\tc6 := 1.5\n\t\tc01 := 0.1\n\t\tc02 := 1.2\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available CPU IDs with access to msr registers.\n\t\tmFetcher.On(\"GetMsrCPUIDs\").Return(cpuIDsMsr).Once()\n\n\t\t// mock getting core ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDsMsr) + len(cpuIDsPerf))\n\n\t\t// mock getting package ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDsMsr) + len(cpuIDsPerf))\n\n\t\t// mock updating msr time-related metrics for CPU IDs.\n\t\tmFetcher.On(\"UpdatePerCPUMetrics\", mock.AnythingOfType(\"int\")).Return(nil).Times(len(cpuIDsMsr))\n\n\t\t// mock getting CPU C1 state residency metric for CPU IDs.\n\t\tmFetcher.On(\"GetCPUC1StateResidency\", mock.AnythingOfType(\"int\")).Return(c1, nil).Times(len(cpuIDsMsr))\n\n\t\t// mock getting CPU C6 state residency metric for CPU IDs.\n\t\tmFetcher.On(\"GetCPUC6StateResidency\", mock.AnythingOfType(\"int\")).Return(c6, nil).Times(len(cpuIDsMsr))\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\tmFetcher.On(\"GetPerfCPUIDs\").Return(cpuIDsPerf).Once()\n\n\t\t// mock getting CPU C01 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", mock.AnythingOfType(\"int\")).Return(c01, nil).Times(len(cpuIDsPerf))\n\n\t\t// mock getting CPU C02 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", mock.AnythingOfType(\"int\")).Return(c02, nil).Times(len(cpuIDsPerf))\n\n\t\tp := &PowerStat{\n\t\t\t// Disables package metrics\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t},\n\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 12)\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c0_substate_c01_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c0_substate_c02_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c1_state_residency_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c6_state_residency_percent\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithCPUAndPackageMetrics\", func(t *testing.T) {\n\t\tcpuIDs := []int{10, 12}\n\t\tpackageIDs := []int{0, 1, 2, 3}\n\t\tdieIDs := []int{0, 1}\n\n\t\tc7 := 0.12\n\n\t\tinitMin := 200.0\n\t\tinitMax := 1200.0\n\t\tcurrMin := 300.0\n\t\tcurrMax := 1300.0\n\t\tcurr := 800.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\tmFetcher.On(\"GetMsrCPUIDs\").Return(cpuIDs).Once()\n\n\t\t// mock getting core ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock getting package ID for CPU IDs.\n\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Times(len(cpuIDs))\n\n\t\t// mock updating msr time-related metrics for CPU IDs.\n\t\tmFetcher.On(\"UpdatePerCPUMetrics\", mock.AnythingOfType(\"int\")).Return(nil).Times(len(cpuIDs))\n\n\t\t// mock getting C7 state residency metric for CPU IDs.\n\t\tmFetcher.On(\"GetCPUC7StateResidency\", mock.AnythingOfType(\"int\")).Return(c7, nil).Times(len(cpuIDs))\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return(packageIDs).Once()\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", mock.AnythingOfType(\"int\")).Return(dieIDs, nil).Times(len(packageIDs))\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", mock.AnythingOfType(\"int\"), mock.AnythingOfType(\"int\")).Return(initMin, nil).\n\t\t\tTimes(len(packageIDs) * len(dieIDs))\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", mock.AnythingOfType(\"int\"), mock.AnythingOfType(\"int\")).Return(initMax, nil).\n\t\t\tTimes(len(packageIDs) * len(dieIDs))\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", mock.AnythingOfType(\"int\"), mock.AnythingOfType(\"int\")).Return(currMin, nil).\n\t\t\tTimes(len(packageIDs) * len(dieIDs))\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", mock.AnythingOfType(\"int\"), mock.AnythingOfType(\"int\")).Return(currMax, nil).\n\t\t\tTimes(len(packageIDs) * len(dieIDs))\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", mock.AnythingOfType(\"int\"), mock.AnythingOfType(\"int\")).Return(curr, nil).Times(len(packageIDs) * len(dieIDs))\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t},\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\tcpuC7StateResidency,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\trequire.NoError(t, p.Gather(acc))\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 18)\n\t\trequire.True(t, acc.HasField(\"powerstat_core\", \"cpu_c7_state_residency_percent\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"uncore_frequency_limit_mhz_min\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"uncore_frequency_limit_mhz_max\"))\n\t\trequire.True(t, acc.HasField(\"powerstat_package\", \"uncore_frequency_mhz_cur\"))\n\t\trequire.True(t, acc.HasTag(\"powerstat_package\", \"type\"))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestStop(t *testing.T) {\n\tt.Run(\"NoErrorWithoutPerf\", func(t *testing.T) {\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tLog: logger,\n\n\t\t\tneedsPerf: false,\n\t\t}\n\n\t\tp.Stop()\n\n\t\trequire.Empty(t, logger.Errors())\n\t})\n\n\tt.Run(\"FailedToDeactivatePerfEvents\", func(t *testing.T) {\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock deactivating perf events.\n\t\tmFetcher.On(\"DeactivatePerfEvents\").Return(errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tLog: logger,\n\n\t\t\tfetcher: mFetcher,\n\n\t\t\tneedsPerf: true,\n\t\t}\n\n\t\tp.Stop()\n\n\t\trequire.Len(t, logger.Errors(), 1)\n\t\trequire.Contains(t, logger.Errors()[0], \"Failed to deactivate perf events\")\n\t})\n\n\tt.Run(\"NoErrorWithPerf\", func(t *testing.T) {\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock deactivating perf events.\n\t\tmFetcher.On(\"DeactivatePerfEvents\").Return(nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tLog: logger,\n\n\t\t\tfetcher: mFetcher,\n\n\t\t\tneedsPerf: true,\n\t\t}\n\n\t\tp.Stop()\n\n\t\trequire.Empty(t, logger.Errors())\n\t})\n}\n\nfunc TestDisableUnsupportedMetrics(t *testing.T) {\n\tt.Run(\"ModelMissing\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/cpu_model_missing\")\n\n\t\tp := &PowerStat{}\n\n\t\terr := p.disableUnsupportedMetrics()\n\n\t\trequire.Error(t, err, \"error occurred while parsing CPU model\")\n\t})\n\n\tt.Run(\"MsrFlagNotFound\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/msr_flag_not_found\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics relying on msr flag\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\t\t\t\tcpuTemperature,\n\t\t\t},\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// Metrics relying on msr flag\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageTurboLimit,\n\n\t\t\t\t// Metrics not relying on msr flag\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\n\t\t\tLog: logger,\n\t\t}\n\n\t\trequire.NoError(t, p.disableUnsupportedMetrics())\n\t\trequire.Empty(t, p.CPUMetrics)\n\t\trequire.Len(t, p.PackageMetrics, 2)\n\t\trequire.Contains(t, p.PackageMetrics, packageCurrentPowerConsumption)\n\t\trequire.Contains(t, p.PackageMetrics, packageThermalDesignPower)\n\t\trequire.Len(t, logger.Warnings(), 7)\n\t})\n\n\tt.Run(\"AperfMperfFlagNotFound\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/aperfmperf_flag_not_found\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics relying on aperfmperf flag\n\t\t\t\tcpuC0StateResidency,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuBusyFrequency,\n\n\t\t\t\t// Metrics not relying on aperfmperf flag\n\t\t\t\tcpuTemperature,\n\t\t\t},\n\n\t\t\tLog: logger,\n\t\t}\n\n\t\trequire.NoError(t, p.disableUnsupportedMetrics())\n\t\trequire.Len(t, p.CPUMetrics, 1)\n\t\trequire.Contains(t, p.CPUMetrics, cpuTemperature)\n\t\trequire.Len(t, logger.Warnings(), 3)\n\t})\n\n\tt.Run(\"DtsFlagNotFound\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/dts_flag_not_found\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics relying on dts flag\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics not relying on dts flag\n\t\t\t\tcpuBusyFrequency,\n\t\t\t},\n\t\t\tPackageMetrics: make([]packageMetricType, 0),\n\n\t\t\tLog: logger,\n\t\t}\n\n\t\terr := p.disableUnsupportedMetrics()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, p.CPUMetrics, 1)\n\t\trequire.Contains(t, p.CPUMetrics, cpuBusyFrequency)\n\t\trequire.Len(t, logger.Warnings(), 1)\n\t})\n\n\tt.Run(\"ModelNotSupported\", func(t *testing.T) {\n\t\tt.Setenv(\"HOST_PROC\", \"./testdata/model_not_supported\")\n\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics not supported by CPU\n\t\t\t\tcpuTemperature,\n\t\t\t\tcpuC1StateResidency,\n\t\t\t\tcpuC3StateResidency,\n\t\t\t\tcpuC6StateResidency,\n\t\t\t\tcpuC7StateResidency,\n\t\t\t},\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// Metrics not supported by CPU\n\t\t\t\tpackageCPUBaseFrequency,\n\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t},\n\n\t\t\tLog: logger,\n\t\t}\n\n\t\terr := p.disableUnsupportedMetrics()\n\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, p.CPUMetrics)\n\t\trequire.Contains(t, p.PackageMetrics, packageUncoreFrequency)\n\t\trequire.Len(t, logger.Warnings(), 6)\n\t})\n}\n\nfunc TestDisableCPUMetric(t *testing.T) {\n\tt.Run(\"NoMetricsRemoved\", func(t *testing.T) {\n\t\texpStartLen := 1\n\t\texpEndLen := 1\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{cpuC1StateResidency},\n\t\t\tLog:        logger,\n\t\t}\n\n\t\trequire.Len(t, p.CPUMetrics, expStartLen)\n\t\tp.disableCPUMetric(cpuC3StateResidency)\n\t\trequire.Len(t, p.CPUMetrics, expEndLen)\n\n\t\trequire.Empty(t, logger.Warnings())\n\t})\n\tt.Run(\"TwoMetricsRemoved\", func(t *testing.T) {\n\t\texpStartLen := 3\n\t\texpEndLen := 1\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{cpuC1StateResidency, cpuC3StateResidency, cpuC6StateResidency},\n\t\t\tLog:        logger,\n\t\t}\n\n\t\trequire.Len(t, p.CPUMetrics, expStartLen)\n\t\tp.disableCPUMetric(cpuC3StateResidency)\n\t\tp.disableCPUMetric(cpuC1StateResidency)\n\t\trequire.Len(t, p.CPUMetrics, expEndLen)\n\n\t\trequire.Len(t, logger.Warnings(), 2)\n\t\trequire.Contains(t, logger.Warnings()[0], \"\\\"cpu_c3_state_residency\\\" is not supported by CPU, metric will not be gathered\")\n\t\trequire.Contains(t, logger.Warnings()[1], \"\\\"cpu_c1_state_residency\\\" is not supported by CPU, metric will not be gathered\")\n\t})\n}\n\nfunc TestDisablePackageMetric(t *testing.T) {\n\tt.Run(\"NoMetricsRemoved\", func(t *testing.T) {\n\t\texpStartLen := 1\n\t\texpEndLen := 1\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{packageCurrentPowerConsumption},\n\t\t\tLog:            logger,\n\t\t}\n\n\t\trequire.Len(t, p.PackageMetrics, expStartLen)\n\t\tp.disablePackageMetric(packageCPUBaseFrequency)\n\t\trequire.Len(t, p.PackageMetrics, expEndLen)\n\n\t\trequire.Empty(t, logger.Warnings())\n\t})\n\tt.Run(\"TwoMetricsRemoved\", func(t *testing.T) {\n\t\texpStartLen := 3\n\t\texpEndLen := 1\n\t\tlogger := &testutil.CaptureLogger{}\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{packageCurrentPowerConsumption, packageTurboLimit, packageCPUBaseFrequency},\n\t\t\tLog:            logger,\n\t\t}\n\n\t\trequire.Len(t, p.PackageMetrics, expStartLen)\n\t\tp.disablePackageMetric(packageCPUBaseFrequency)\n\t\tp.disablePackageMetric(packageTurboLimit)\n\t\trequire.Len(t, p.PackageMetrics, expEndLen)\n\n\t\trequire.Len(t, logger.Warnings(), 2)\n\t\trequire.Contains(t, logger.Warnings()[0], \"\\\"cpu_base_frequency\\\" is not supported by CPU, metric will not be gathered\")\n\t\trequire.Contains(t, logger.Warnings()[1], \"\\\"max_turbo_frequency\\\" is not supported by CPU, metric will not be gathered\")\n\t})\n}\n\ntype fetcherMock struct {\n\tmock.Mock\n}\n\nfunc (m *fetcherMock) GetMsrCPUIDs() []int {\n\targs := m.Called()\n\tif args.Get(0) == nil {\n\t\treturn nil\n\t}\n\treturn args.Get(0).([]int)\n}\n\nfunc (m *fetcherMock) GetPerfCPUIDs() []int {\n\targs := m.Called()\n\tif args.Get(0) == nil {\n\t\treturn nil\n\t}\n\treturn args.Get(0).([]int)\n}\n\nfunc (m *fetcherMock) GetPackageIDs() []int {\n\targs := m.Called()\n\tif args.Get(0) == nil {\n\t\treturn nil\n\t}\n\treturn args.Get(0).([]int)\n}\n\nfunc (m *fetcherMock) GetCPUPackageID(cpuID int) (int, error) {\n\targs := m.Called(cpuID)\n\treturn args.Int(0), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUCoreID(cpuID int) (int, error) {\n\targs := m.Called(cpuID)\n\treturn args.Int(0), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetPackageDieIDs(packageID int) ([]int, error) {\n\targs := m.Called(packageID)\n\tif args.Get(0) == nil {\n\t\treturn nil, args.Error(1)\n\t}\n\treturn args.Get(0).([]int), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUFrequency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) UpdatePerCPUMetrics(cpuID int) error {\n\targs := m.Called(cpuID)\n\treturn args.Error(0)\n}\n\nfunc (m *fetcherMock) GetCPUTemperature(cpuID int) (uint64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(uint64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC0StateResidency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC1StateResidency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC3StateResidency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC6StateResidency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC7StateResidency(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUBusyFrequencyMhz(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) ReadPerfEvents() error {\n\targs := m.Called()\n\treturn args.Error(0)\n}\n\nfunc (m *fetcherMock) DeactivatePerfEvents() error {\n\targs := m.Called()\n\treturn args.Error(0)\n}\n\nfunc (m *fetcherMock) GetCPUC0SubstateC01Percent(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC0SubstateC02Percent(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUC0SubstateC0WaitPercent(cpuID int) (float64, error) {\n\targs := m.Called(cpuID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCPUBaseFrequency(packageID int) (uint64, error) {\n\targs := m.Called(packageID)\n\treturn args.Get(0).(uint64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetInitialUncoreFrequencyMin(packageID, dieID int) (float64, error) {\n\targs := m.Called(packageID, dieID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCustomizedUncoreFrequencyMin(packageID, dieID int) (float64, error) {\n\targs := m.Called(packageID, dieID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetInitialUncoreFrequencyMax(packageID, dieID int) (float64, error) {\n\targs := m.Called(packageID, dieID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCustomizedUncoreFrequencyMax(packageID, dieID int) (float64, error) {\n\targs := m.Called(packageID, dieID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCurrentUncoreFrequency(packageID, dieID int) (float64, error) {\n\targs := m.Called(packageID, dieID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCurrentPackagePowerConsumptionWatts(packageID int) (float64, error) {\n\targs := m.Called(packageID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetCurrentDramPowerConsumptionWatts(packageID int) (float64, error) {\n\targs := m.Called(packageID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetPackageThermalDesignPowerWatts(packageID int) (float64, error) {\n\targs := m.Called(packageID)\n\treturn args.Get(0).(float64), args.Error(1)\n}\n\nfunc (m *fetcherMock) GetMaxTurboFreqList(packageID int) ([]ptel.MaxTurboFreq, error) {\n\targs := m.Called(packageID)\n\tif args.Get(0) == nil {\n\t\treturn nil, args.Error(1)\n\t}\n\treturn args.Get(0).([]ptel.MaxTurboFreq), args.Error(1)\n}\n\nfunc TestAddCPUMetrics(t *testing.T) {\n\t// Disable package metrics when parseConfig method is called.\n\tpackageMetrics := make([]packageMetricType, 0)\n\n\tt.Run(\"NoAvailableCPUs\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available CPU IDs with access to msr registers.\n\t\tmFetcher.On(\"GetMsrCPUIDs\").Return(nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\tp.addCPUMetrics(acc)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithDataCPUIDErrors\", func(t *testing.T) {\n\t\tt.Run(\"SingleCPUID\", func(t *testing.T) {\n\t\t\tcpuID := 0\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\t\tmFetcher.On(\"GetMsrCPUIDs\").Return([]int{cpuID}).Once()\n\n\t\t\t// mock getting core ID for CPU ID.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(0, errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\tp.addCPUMetrics(acc)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get coreFreq and/or msr metrics for CPU ID %v\", cpuID))\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"MultipleCPUIDs\", func(t *testing.T) {\n\t\t\tcpuID := 1\n\t\t\tcoreID := 2\n\t\t\tpackageID := 3\n\t\t\tcpuFreq := 500.0\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting available CPU IDs with access to msr registers and coreFreq.\n\t\t\tmFetcher.On(\"GetMsrCPUIDs\").Return([]int{0, cpuID}).Once()\n\n\t\t\t// mock getting core ID for CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", 0).Return(0, errors.New(\"mock error\")).Once()\n\n\t\t\t// mock getting core ID for CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(coreID, nil).Once()\n\n\t\t\t// mock getting package ID for CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(packageID, nil).Once()\n\n\t\t\t// mock getting CPU frequency for CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUFrequency\", cpuID).Return(cpuFreq, nil).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t\t// Metric which relies on coreFreq.\n\t\t\t\t\tcpuFrequency,\n\n\t\t\t\t\t// Metrics which do not rely on coreFreq nor msr.\n\t\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\t},\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addCPUMetrics(acc)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), \"failed to get coreFreq and/or msr metrics for CPU ID 0\")\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_frequency_mhz\": cpuFreq,\n\t\t\t\t},\n\t\t\t\t// tags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\t})\n\n\tt.Run(\"WithCoreFreqMetrics\", func(t *testing.T) {\n\t\tcpuFreq := 500.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available CPU IDs with access to coreFreq.\n\t\tmFetcher.On(\"GetMsrCPUIDs\").Return([]int{0, 1}).Once()\n\n\t\t// mock getting corresponding core ID to CPU IDs 0 and 1.\n\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(0, nil).Twice()\n\n\t\t// mock getting corresponding package ID to CPU IDs 0 and 1.\n\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Twice()\n\n\t\t// mock getting CPU frequency for CPU ID 0.\n\t\tmFetcher.On(\"GetCPUFrequency\", 0).Return(cpuFreq, nil).Once()\n\n\t\t// mock getting CPU frequency for CPU ID 1.\n\t\tmFetcher.On(\"GetCPUFrequency\", 1).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metric which relies on coreFreq.\n\t\t\t\tcpuFrequency,\n\n\t\t\t\t// Metrics which do not rely on coreFreq nor msr\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t},\n\t\t\tPackageMetrics:   packageMetrics,\n\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addCPUMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID 1\", cpuFrequency))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_frequency_mhz\": cpuFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     \"0\",\n\t\t\t\t\"core_id\":    \"0\",\n\t\t\t\t\"package_id\": \"1\",\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithMsrMetrics\", func(t *testing.T) {\n\t\tt.Run(\"SingleRead\", func(t *testing.T) {\n\t\t\tcpuTemp := uint64(18)\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting available CPU IDs with access to msr registers.\n\t\t\tmFetcher.On(\"GetMsrCPUIDs\").Return([]int{0, 1}).Once()\n\n\t\t\t// mock getting corresponding core ID to CPU IDs 0 and 1.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(0, nil).Twice()\n\n\t\t\t// mock getting corresponding package ID to CPU IDs 0 and 1.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Twice()\n\n\t\t\t// mock getting CPU temperature metric for CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUTemperature\", 0).Return(cpuTemp, nil).Once()\n\n\t\t\t// mock getting CPU temperature metric for CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUTemperature\", 1).Return(uint64(0), errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t\t// Metrics which rely on single-read msr registers.\n\t\t\t\t\tcpuTemperature,\n\n\t\t\t\t\t// Metrics which do not rely on coreFreq nor msr\n\t\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\t},\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addCPUMetrics(acc)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID 1\", cpuTemperature))\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_temperature_celsius\": cpuTemp,\n\t\t\t\t},\n\t\t\t\t// tags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     \"0\",\n\t\t\t\t\t\"core_id\":    \"0\",\n\t\t\t\t\t\"package_id\": \"1\",\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"TimeRelated\", func(t *testing.T) {\n\t\t\tcpuBusyFreq := 750.0\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting available CPU IDs with access to msr registers.\n\t\t\tmFetcher.On(\"GetMsrCPUIDs\").Return([]int{0, 1}).Once()\n\n\t\t\t// mock getting corresponding core ID to CPU IDs 0 and 1.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", mock.AnythingOfType(\"int\")).Return(0, nil).Twice()\n\n\t\t\t// mock getting corresponding package ID to CPU IDs 0 and 1.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", mock.AnythingOfType(\"int\")).Return(1, nil).Twice()\n\n\t\t\t// mock updating msr time-related metrics for CPU ID 0.\n\t\t\tmFetcher.On(\"UpdatePerCPUMetrics\", 0).Return(errors.New(\"mock error\")).Once()\n\n\t\t\t// mock updating msr time-related metrics for CPU ID 1.\n\t\t\tmFetcher.On(\"UpdatePerCPUMetrics\", 1).Return(nil).Once()\n\n\t\t\t// mock getting CPU busy frequency metric for CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUBusyFrequencyMhz\", 1).Return(cpuBusyFreq, nil).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t\t// Metrics which rely on time-related msr reads.\n\t\t\t\t\tcpuBusyFrequency,\n\n\t\t\t\t\t// Metrics which do not rely on coreFreq nor msr\n\t\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t\t},\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addCPUMetrics(acc)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), \"failed to update MSR time-related metrics for CPU ID 0\")\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_busy_frequency_mhz\": cpuBusyFreq,\n\t\t\t\t},\n\t\t\t\t// tags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     \"1\",\n\t\t\t\t\t\"core_id\":    \"0\",\n\t\t\t\t\t\"package_id\": \"1\",\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\t})\n}\n\nfunc TestAddPerCPUMsrMetrics(t *testing.T) {\n\t// Disable package metrics when parseConfig method is called.\n\tpackageMetrics := make([]packageMetricType, 0)\n\n\tt.Run(\"WithoutMsrMetrics\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// metrics which do not rely on msr\n\t\t\t\tcpuFrequency,\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t},\n\t\t}\n\n\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t})\n\n\tt.Run(\"WithSingleMsrReadMetrics\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tcpuMetrics := []cpuMetricType{\n\t\t\t// metric that relies on a single msr read.\n\t\t\tcpuTemperature,\n\n\t\t\t// metrics that do not rely on msr.\n\t\t\tcpuFrequency,\n\t\t\tcpuC0SubstateC01Percent,\n\t\t}\n\n\t\tt.Run(\"WithError\", func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting CPU temperature metric.\n\t\t\tmFetcher.On(\"GetCPUTemperature\", cpuID).Return(uint64(0), errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\n\t\t\t\tlogOnce: map[string]struct{}{},\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuTemperature, cpuID))\n\t\t\trequire.Empty(t, p.logOnce)\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"WithModuleNotInitializedError\", func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmErr := &ptel.ModuleNotInitializedError{Name: \"msr\"}\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting CPU temperature metric.\n\t\t\tmFetcher.On(\"GetCPUTemperature\", cpuID).Return(uint64(0), mErr).Twice()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\n\t\t\t\tlogOnce: map[string]struct{}{},\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\t// First call adds the error to the accumulator and logOnce map.\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q: %v\", cpuTemperature, mErr))\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\t\trequire.Len(t, p.logOnce, 1)\n\t\t\trequire.Contains(t, p.logOnce, \"msr_cpu_temperature\")\n\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"WithoutErrors\", func(t *testing.T) {\n\t\t\tcpuTemp := uint64(20)\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock getting CPU temperature metric.\n\t\t\tmFetcher.On(\"GetCPUTemperature\", cpuID).Return(cpuTemp, nil).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Empty(t, acc.Errors)\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_temperature_celsius\": cpuTemp,\n\t\t\t\t},\n\t\t\t\t// tags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\t})\n\n\tt.Run(\"WithTimeRelatedMsrMetrics\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tc1State := 5.15\n\t\tc6State := 8.10\n\n\t\tcpuMetrics := []cpuMetricType{\n\t\t\t// metrics that rely on a time-related msr.\n\t\t\tcpuC1StateResidency,\n\t\t\tcpuC6StateResidency,\n\n\t\t\t// metrics which do not rely on msr.\n\t\t\tcpuFrequency,\n\t\t\tcpuC0SubstateC01Percent,\n\t\t}\n\n\t\tt.Run(\"FailedToUpdate\", func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock updating msr time-related metrics.\n\t\t\tmFetcher.On(\"UpdatePerCPUMetrics\", cpuID).Return(errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to update MSR time-related metrics for CPU ID %v\", cpuID))\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"FailedToUpdateModuleNotInitializedError\", func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmErr := &ptel.ModuleNotInitializedError{Name: \"msr\"}\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock updating msr time-related metrics.\n\t\t\tmFetcher.On(\"UpdatePerCPUMetrics\", cpuID).Return(mErr).Twice()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\n\t\t\t\tlogOnce: map[string]struct{}{},\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\t// First call adds the error to the accumulator and key to logOnce map.\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to update MSR time-related metrics: %v\", mErr))\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\t\trequire.Len(t, p.logOnce, 1)\n\t\t\trequire.Contains(t, p.logOnce, \"msr_time_related\")\n\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"WithoutErrors\", func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock updating msr time-related metrics.\n\t\t\tmFetcher.On(\"UpdatePerCPUMetrics\", cpuID).Return(nil).Once()\n\n\t\t\t// mock getting C1 state residency.\n\t\t\tmFetcher.On(\"GetCPUC1StateResidency\", cpuID).Return(c1State, nil).Once()\n\n\t\t\t// mock getting C6 state residency.\n\t\t\tmFetcher.On(\"GetCPUC6StateResidency\", cpuID).Return(c6State, nil).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics:       cpuMetrics,\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addPerCPUMsrMetrics(acc, cpuID, coreID, packageID)\n\n\t\t\trequire.Empty(t, acc.Errors)\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_c1_state_residency_percent\": c1State,\n\t\t\t\t},\n\t\t\t\t// flags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t},\n\t\t\t)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_c6_state_residency_percent\": c6State,\n\t\t\t\t},\n\t\t\t\t// flags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\t})\n}\n\nfunc TestAddCPUTimeRelatedMsrMetrics(t *testing.T) {\n\tcpuID := 0\n\tcoreID := 1\n\tpackageID := 0\n\n\tc0State := 3.0\n\tc1State := 2.0\n\tc3State := 1.5\n\tc6State := 1.0\n\n\tacc := &testutil.Accumulator{}\n\n\tmFetcher := &fetcherMock{}\n\n\t// mock getting CPU C0 state residency value.\n\tmFetcher.On(\"GetCPUC0StateResidency\", cpuID).Return(c0State, nil).Once()\n\n\t// mock getting CPU C1 state residency value.\n\tmFetcher.On(\"GetCPUC1StateResidency\", cpuID).Return(c1State, nil).Once()\n\n\t// mock getting CPU C3 state residency value.\n\tmFetcher.On(\"GetCPUC3StateResidency\", cpuID).Return(c3State, nil).Once()\n\n\t// mock getting CPU C6 state residency value.\n\tmFetcher.On(\"GetCPUC6StateResidency\", cpuID).Return(c6State, nil).Once()\n\n\tp := &PowerStat{\n\t\tCPUMetrics: []cpuMetricType{\n\t\t\t// Metrics which are not time-related MSR.\n\t\t\tcpuFrequency,\n\t\t\tcpuTemperature,\n\t\t\tcpuC0SubstateC01Percent,\n\n\t\t\t// Time-related MSR metrics.\n\t\t\tcpuC0StateResidency,\n\t\t\tcpuC1StateResidency,\n\t\t\tcpuC3StateResidency,\n\t\t\tcpuC6StateResidency,\n\t\t},\n\t\tPackageMetrics:   make([]packageMetricType, 0),\n\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\tfetcher: mFetcher,\n\t}\n\n\trequire.NoError(t, p.parseConfig())\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\tp.addCPUTimeRelatedMsrMetrics(acc, cpuID, coreID, packageID)\n\n\trequire.Empty(t, acc.Errors)\n\trequire.Len(t, acc.GetTelegrafMetrics(), 4)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c0_state_residency_percent\": c0State,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c1_state_residency_percent\": c1State,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c6_state_residency_percent\": c6State,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c3_state_residency_percent\": c3State,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tmFetcher.AssertExpectations(t)\n}\n\nfunc TestAddCPUPerfMetrics(t *testing.T) {\n\t// Disable package metrics when parseConfig method is called.\n\tpackageMetrics := make([]packageMetricType, 0)\n\n\tt.Run(\"FailedToReadPerfEvents\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\tp.addCPUPerfMetrics(acc)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), \"failed to read perf events\")\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailedToReadPerfEventsModuleNotInitializedError\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmErr := &ptel.ModuleNotInitializedError{Name: \"perf\"}\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(mErr).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\t// First call adds the error to the accumulator and key to logOnce map.\n\t\tp.addCPUPerfMetrics(acc)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addCPUPerfMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to read perf events: %v\", mErr))\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\trequire.Len(t, p.logOnce, 1)\n\t\trequire.Contains(t, p.logOnce, \"perf_read\")\n\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"NoAvailableCPUs\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t// mock getting available CPU IDs for perf events.\n\t\tmFetcher.On(\"GetPerfCPUIDs\").Return(nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics which do not rely on perf.\n\t\t\t\tcpuFrequency,\n\t\t\t\tcpuTemperature,\n\n\t\t\t\t// Metrics which rely on perf.\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t},\n\t\t\tPackageMetrics:   make([]packageMetricType, 0),\n\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addCPUPerfMetrics(acc)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailedToGetDataCPUID\", func(t *testing.T) {\n\t\tt.Run(\"SingleCPUID\", func(t *testing.T) {\n\t\t\tcpuID := 0\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock reading perf events.\n\t\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t\t// mock getting available CPU IDs for perf events.\n\t\t\tmFetcher.On(\"GetPerfCPUIDs\").Return([]int{cpuID}).Once()\n\n\t\t\t// mock getting corresponding core ID to CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(1, nil).Once()\n\n\t\t\t// mock getting corresponding package ID to CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(0, errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t\t// Metrics which do not rely on perf.\n\t\t\t\t\tcpuFrequency,\n\t\t\t\t\tcpuTemperature,\n\n\t\t\t\t\t// Metrics which rely on perf.\n\t\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t\t},\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addCPUPerfMetrics(acc)\n\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get perf metrics for CPU ID %v\", cpuID))\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\n\t\tt.Run(\"MultipleCPUIDs\", func(t *testing.T) {\n\t\t\tcpuID := 0\n\t\t\tcoreID := 2\n\t\t\tpackageID := 3\n\n\t\t\tc01Percent := 0.2\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\tmFetcher := &fetcherMock{}\n\n\t\t\t// mock reading perf events.\n\t\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t\t// mock getting available CPU IDs for perf events.\n\t\t\tmFetcher.On(\"GetPerfCPUIDs\").Return([]int{cpuID, 1}).Once()\n\n\t\t\t// mock getting corresponding core ID to CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(coreID, nil).Once()\n\n\t\t\t// mock getting corresponding package ID to CPU ID 0.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(packageID, nil).Once()\n\n\t\t\t// mock getting CPU C01 metric.\n\t\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", cpuID).Return(c01Percent, nil).Once()\n\n\t\t\t// mock getting corresponding core ID to CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUCoreID\", 1).Return(5, nil).Once()\n\n\t\t\t// mock getting corresponding package ID to CPU ID 1.\n\t\t\tmFetcher.On(\"GetCPUPackageID\", 1).Return(0, errors.New(\"mock error\")).Once()\n\n\t\t\tp := &PowerStat{\n\t\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t\t// Metrics which do not rely on perf.\n\t\t\t\t\tcpuFrequency,\n\t\t\t\t\tcpuTemperature,\n\t\t\t\t\tcpuC6StateResidency,\n\n\t\t\t\t\t// Metrics which rely on perf.\n\t\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\t},\n\t\t\t\tPackageMetrics:   packageMetrics,\n\t\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\t\tfetcher: mFetcher,\n\t\t\t}\n\n\t\t\trequire.NoError(t, p.parseConfig())\n\n\t\t\tp.addCPUPerfMetrics(acc)\n\n\t\t\trequire.Len(t, acc.Errors, 1)\n\t\t\trequire.ErrorContains(t, acc.FirstError(), \"failed to get perf metrics for CPU ID 1\")\n\t\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\t\tacc.AssertContainsTaggedFields(\n\t\t\t\tt,\n\t\t\t\t// measurement\n\t\t\t\t\"powerstat_core\",\n\t\t\t\t// fields\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"cpu_c0_substate_c01_percent\": c01Percent,\n\t\t\t\t},\n\t\t\t\t// tags\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t},\n\t\t\t)\n\t\t\tmFetcher.AssertExpectations(t)\n\t\t})\n\t})\n\n\tt.Run(\"WithError\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tc01Percent := 0.5\n\t\tc0Wait := 2.5\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock reading perf events.\n\t\tmFetcher.On(\"ReadPerfEvents\").Return(nil).Once()\n\n\t\t// mock getting available CPU IDs for perf events.\n\t\tmFetcher.On(\"GetPerfCPUIDs\").Return([]int{cpuID}).Once()\n\n\t\t// mock getting corresponding core ID to CPU ID 0.\n\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(coreID, nil).Once()\n\n\t\t// mock getting corresponding package ID to CPU ID 0.\n\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(packageID, nil).Once()\n\n\t\t// mock getting CPU C01 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", cpuID).Return(c01Percent, nil).Once()\n\n\t\t// mock getting CPU C02 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\t// mock getting CPU C0Wait metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC0WaitPercent\", cpuID).Return(c0Wait, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tCPUMetrics: []cpuMetricType{\n\t\t\t\t// Metrics which do not rely on perf.\n\t\t\t\tcpuFrequency,\n\t\t\t\tcpuTemperature,\n\t\t\t\tcpuC6StateResidency,\n\n\t\t\t\t// Metrics which rely on perf.\n\t\t\t\tcpuC0SubstateC01Percent,\n\t\t\t\tcpuC0SubstateC02Percent,\n\t\t\t\tcpuC0SubstateC0WaitPercent,\n\t\t\t},\n\t\t\tPackageMetrics:   packageMetrics,\n\t\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addCPUPerfMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC0SubstateC02Percent, cpuID))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_substate_c01_percent\": c01Percent,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_substate_c0_wait_percent\": c0Wait,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t})\n}\n\nfunc TestAddPerCPUPerfMetrics(t *testing.T) {\n\tcpuID := 0\n\tcoreID := 1\n\tpackageID := 0\n\n\tc01Percent := 1.09\n\tc02Percent := 2.12\n\n\tacc := &testutil.Accumulator{}\n\n\tmFetcher := &fetcherMock{}\n\n\t// mock getting CPU C01 metric.\n\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", cpuID).Return(c01Percent, nil).Once()\n\n\t// mock getting CPU C02 metric.\n\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", cpuID).Return(c02Percent, nil).Once()\n\n\tp := &PowerStat{\n\t\tCPUMetrics: []cpuMetricType{\n\t\t\t// Metrics which do not rely on perf.\n\t\t\tcpuFrequency,\n\t\t\tcpuTemperature,\n\t\t\tcpuC6StateResidency,\n\n\t\t\t// Metrics which rely on perf.\n\t\t\tcpuC0SubstateC01Percent,\n\t\t\tcpuC0SubstateC02Percent,\n\t\t},\n\t\tPackageMetrics:   make([]packageMetricType, 0),\n\t\tEventDefinitions: \"./testdata/sapphirerapids_core.json\",\n\n\t\tfetcher: mFetcher,\n\t}\n\n\trequire.NoError(t, p.parseConfig())\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\tp.addPerCPUPerfMetrics(acc, cpuID, coreID, packageID)\n\n\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c0_substate_c01_percent\": c01Percent,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t// measurement\n\t\t\"powerstat_core\",\n\t\t// fields\n\t\tmap[string]interface{}{\n\t\t\t\"cpu_c0_substate_c02_percent\": c02Percent,\n\t\t},\n\t\t// tags\n\t\tmap[string]string{\n\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t},\n\t)\n\tmFetcher.AssertExpectations(t)\n}\n\nfunc TestGetDataCPUID(t *testing.T) {\n\tt.Run(\"FailedToGetCoreID\", func(t *testing.T) {\n\t\tcpuID := 1\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting core ID corresponding to the CPU ID.\n\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(0, errors.New(\"mock error\")).Once()\n\n\t\tcoreID, packageID, err := getDataCPUID(mFetcher, cpuID)\n\n\t\trequire.Equal(t, 0, coreID)\n\t\trequire.Equal(t, 0, packageID)\n\t\trequire.ErrorContains(t, err, fmt.Sprintf(\"failed to get core ID from CPU ID %v\", cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailedToGetPackageID\", func(t *testing.T) {\n\t\tcpuID := 1\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting core ID corresponding to the CPU ID.\n\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(1, nil).Once()\n\n\t\t// mock getting package ID corresponding to the CPU ID.\n\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(0, errors.New(\"mock error\")).Once()\n\n\t\tcoreID, packageID, err := getDataCPUID(mFetcher, cpuID)\n\n\t\trequire.Equal(t, 0, coreID)\n\t\trequire.Equal(t, 0, packageID)\n\t\trequire.ErrorContains(t, err, fmt.Sprintf(\"failed to get package ID from CPU ID %v\", cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tcpuID := 1\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting core ID corresponding to the CPU ID.\n\t\tmFetcher.On(\"GetCPUCoreID\", cpuID).Return(1, nil).Once()\n\n\t\t// mock getting package ID corresponding to the CPU ID.\n\t\tmFetcher.On(\"GetCPUPackageID\", cpuID).Return(2, nil).Once()\n\n\t\tcoreID, packageID, err := getDataCPUID(mFetcher, cpuID)\n\n\t\trequire.Equal(t, 1, coreID)\n\t\trequire.Equal(t, 2, packageID)\n\t\trequire.NoError(t, err)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddPackageMetrics(t *testing.T) {\n\tt.Run(\"NoPackageIDs\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return(nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\tp.addPackageMetrics(acc)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t})\n\n\tt.Run(\"WithRaplMetrics\", func(t *testing.T) {\n\t\ttdp := 80.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return([]int{0, 1}).Once()\n\n\t\t// mock getting package thermal design power metric for CPU ID 0.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", 0).Return(tdp, nil).Once()\n\n\t\t// mock getting package thermal design power metric for CPU ID 1.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", 1).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on rapl\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPackageMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID 1\", packageThermalDesignPower))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"thermal_design_power_watts\": tdp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": \"0\",\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithMsrMetrics\", func(t *testing.T) {\n\t\tbaseFreq := uint64(400)\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return([]int{0, 1}).Once()\n\n\t\t// mock getting CPU base frequency metric, for package ID 0.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", 0).Return(uint64(0), errors.New(\"mock error\")).Once()\n\n\t\t// mock getting CPU base frequency metric, for package ID 1.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", 1).Return(baseFreq, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on msr\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPackageMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID 0\", packageCPUBaseFrequency))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_base_frequency_mhz\": baseFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": \"1\",\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithUncoreFreqMetric\", func(t *testing.T) {\n\t\tdieID := 0\n\n\t\tinitMin := 500.0\n\t\tinitMax := 2500.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting available package IDs.\n\t\tmFetcher.On(\"GetPackageIDs\").Return([]int{0, 1}).Once()\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", mock.AnythingOfType(\"int\")).Return([]int{dieID}, nil).Twice()\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", mock.AnythingOfType(\"int\"), dieID).Return(initMin, nil).Twice()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", mock.AnythingOfType(\"int\"), dieID).Return(initMax, nil).Twice()\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", mock.AnythingOfType(\"int\"), dieID).Return(600.0, nil).Twice()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", mock.AnythingOfType(\"int\"), dieID).Return(0.0, errors.New(\"mock error\")).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPackageMetrics(acc)\n\n\t\trequire.Len(t, acc.Errors, 2)\n\t\trequire.ErrorContains(t, acc.Errors[0], fmt.Sprintf(\"failed to get current uncore frequency values for package ID 0 and die ID %v\", dieID))\n\t\trequire.ErrorContains(t, acc.Errors[1], fmt.Sprintf(\"failed to get current uncore frequency values for package ID 1 and die ID %v\", dieID))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": initMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": initMax,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": \"0\",\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": initMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": initMax,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": \"1\",\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddPerPackageRaplMetrics(t *testing.T) {\n\tt.Run(\"WithoutRaplMetrics\", func(t *testing.T) {\n\t\tpackageID := 0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which do not rely on rapl\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t\tpackageTurboLimit,\n\t\t\t},\n\t\t}\n\n\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t})\n\n\tt.Run(\"WithModuleNotInitializedError\", func(t *testing.T) {\n\t\tpackageID := 0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\traplNotInitErr := &ptel.ModuleNotInitializedError{Name: \"rapl\"}\n\t\tmError := fmt.Errorf(\"mock error: %w\", raplNotInitErr)\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(0.0, mError).Twice()\n\n\t\t// mock getting package thermal design power metric.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", packageID).Return(0.0, mError).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on rapl\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\n\t\t\t\t// metrics which do not rely on rapl\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t\tpackageTurboLimit,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\t// First call adds the error to the accumulator and logOnce map.\n\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 2)\n\t\trequire.ErrorContains(t, acc.Errors[0], fmt.Sprintf(\"failed to get %q: %v\", packageCurrentDramPowerConsumption, raplNotInitErr))\n\t\trequire.ErrorContains(t, acc.Errors[1], fmt.Sprintf(\"failed to get %q: %v\", packageThermalDesignPower, raplNotInitErr))\n\n\t\trequire.Len(t, p.logOnce, 2)\n\t\trequire.Contains(t, p.logOnce, \"rapl_current_dram_power_consumption\")\n\t\trequire.Contains(t, p.logOnce, \"rapl_thermal_design_power\")\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithErrors\", func(t *testing.T) {\n\t\tpackageID := 0\n\t\tcurrPower := 30.0\n\t\ttdp := 80.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current package power consumption metric.\n\t\tmFetcher.On(\"GetCurrentPackagePowerConsumptionWatts\", packageID).Return(currPower, nil).Once()\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\t// mock getting package thermal design power metric.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", packageID).Return(tdp, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on rapl\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\n\t\t\t\t// metrics which do not rely on rapl\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t\tpackageTurboLimit,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageCurrentDramPowerConsumption, packageID))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current_power_consumption_watts\": currPower,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"thermal_design_power_watts\": tdp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithoutErrors\", func(t *testing.T) {\n\t\tpackageID := 0\n\t\tcurrPower := 10.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(currPower, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on rapl\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\n\t\t\t\t// metrics which do not rely on rapl\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageUncoreFrequency,\n\t\t\t\tpackageTurboLimit,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPerPackageRaplMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current_dram_power_consumption_watts\": currPower,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddPerPackageMsrMetrics(t *testing.T) {\n\tt.Run(\"WithoutMsrMetrics\", func(t *testing.T) {\n\t\tpackageID := 0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which do not rely on msr\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\t\t}\n\n\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t})\n\n\tt.Run(\"WithModuleNotInitializedError\", func(t *testing.T) {\n\t\tpackageID := 0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmsrNotInitErr := &ptel.ModuleNotInitializedError{Name: \"msr\"}\n\t\tmError := fmt.Errorf(\"mock error: %w\", msrNotInitErr)\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", packageID).Return(uint64(400), mError).Twice()\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(nil, mError).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on msr\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageTurboLimit,\n\n\t\t\t\t// metrics which do not rely on msr\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\t// First call adds the error to the accumulator and logOnce map.\n\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 2)\n\t\trequire.ErrorContains(t, acc.Errors[0], fmt.Sprintf(\"failed to get %q: %v\", packageCPUBaseFrequency, msrNotInitErr))\n\t\trequire.ErrorContains(t, acc.Errors[1], fmt.Sprintf(\"failed to get %q: %v\", packageTurboLimit, msrNotInitErr))\n\n\t\trequire.Len(t, p.logOnce, 2)\n\t\trequire.Contains(t, p.logOnce, \"msr_cpu_base_frequency\")\n\t\trequire.Contains(t, p.logOnce, \"msr_max_turbo_frequency\")\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithErrors\", func(t *testing.T) {\n\t\tpackageID := 0\n\t\tbaseFreq := uint64(400)\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", packageID).Return(baseFreq, nil).Once()\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(nil, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on msr\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageTurboLimit,\n\n\t\t\t\t// metrics which do not rely on msr\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageTurboLimit, packageID))\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_base_frequency_mhz\": baseFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithoutErrors\", func(t *testing.T) {\n\t\tpackageID := 0\n\t\tbaseFreq := uint64(400)\n\t\tmaxTurboFreqList := []ptel.MaxTurboFreq{\n\t\t\t{\n\t\t\t\tValue:       1000,\n\t\t\t\tActiveCores: 10,\n\t\t\t},\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", packageID).Return(baseFreq, nil).Once()\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(maxTurboFreqList, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tPackageMetrics: []packageMetricType{\n\t\t\t\t// metrics which rely on msr\n\t\t\t\tpackageCPUBaseFrequency,\n\t\t\t\tpackageTurboLimit,\n\n\t\t\t\t// metrics which do not rely on msr\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t\tpackageCurrentDramPowerConsumption,\n\t\t\t\tpackageThermalDesignPower,\n\t\t\t},\n\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.NoError(t, p.parseConfig())\n\n\t\tp.addPerPackageMsrMetrics(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_base_frequency_mhz\": baseFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_base_frequency_mhz\": baseFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": maxTurboFreqList[0].Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\t\"active_cores\": strconv.Itoa(int(maxTurboFreqList[0].ActiveCores)),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUFrequency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU frequency metric.\n\t\tmFetcher.On(\"GetCPUFrequency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUFrequency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuFrequency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tcpuFreq := 800.001\n\t\tcpuFreqExp := 800.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU frequency metric.\n\t\tmFetcher.On(\"GetCPUFrequency\", cpuID).Return(cpuFreq, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUFrequency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_frequency_mhz\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_frequency_mhz\": cpuFreqExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUTemperature(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU temperature metric.\n\t\tmFetcher.On(\"GetCPUTemperature\", cpuID).Return(uint64(0), errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUTemperature(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuTemperature, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tcpuTemp := uint64(25)\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting cpu temperature metric.\n\t\tmFetcher.On(\"GetCPUTemperature\", cpuID).Return(cpuTemp, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUTemperature(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasUIntField(\"powerstat_core\", \"cpu_temperature_celsius\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_temperature_celsius\": cpuTemp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC0StateResidency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C0 state residency metric.\n\t\tmFetcher.On(\"GetCPUC0StateResidency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC0StateResidency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc0State := 10.1199\n\t\tc0StateExp := 10.12\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C0 state residency metric.\n\t\tmFetcher.On(\"GetCPUC0StateResidency\", cpuID).Return(c0State, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c0_state_residency_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_state_residency_percent\": c0StateExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC1StateResidency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C1 state residency metric.\n\t\tmFetcher.On(\"GetCPUC1StateResidency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC1StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC1StateResidency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc1State := 10.1144\n\t\tc1StateExp := 10.11\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C1 state residency metric.\n\t\tmFetcher.On(\"GetCPUC1StateResidency\", cpuID).Return(c1State, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC1StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c1_state_residency_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c1_state_residency_percent\": c1StateExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC3StateResidency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C3 state residency metric.\n\t\tmFetcher.On(\"GetCPUC3StateResidency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC3StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC3StateResidency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc3State := 20.1178\n\t\tc3StateExp := 20.12\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C3 state residency metric.\n\t\tmFetcher.On(\"GetCPUC3StateResidency\", cpuID).Return(c3State, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC3StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c3_state_residency_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c3_state_residency_percent\": c3StateExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC6StateResidency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C6 state residency metric.\n\t\tmFetcher.On(\"GetCPUC6StateResidency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC6StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC6StateResidency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc6State := 9.115\n\t\tc6StateExp := 9.12\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C6 state residency metric.\n\t\tmFetcher.On(\"GetCPUC6StateResidency\", cpuID).Return(c6State, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC6StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c6_state_residency_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c6_state_residency_percent\": c6StateExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC7StateResidency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C7 state residency metric.\n\t\tmFetcher.On(\"GetCPUC7StateResidency\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC7StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC7StateResidency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc7State := 9.1149\n\t\tc7StateExp := 9.11\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C7 state residency metric.\n\t\tmFetcher.On(\"GetCPUC7StateResidency\", cpuID).Return(c7State, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC7StateResidency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c7_state_residency_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c7_state_residency_percent\": c7StateExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUBusyFrequency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU busy frequency metric.\n\t\tmFetcher.On(\"GetCPUBusyFrequencyMhz\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUBusyFrequency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuBusyFrequency, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tcpuBusyFreq := 800.119\n\t\tcpuBusyFreqExp := 800.12\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU busy frequency metric.\n\t\tmFetcher.On(\"GetCPUBusyFrequencyMhz\", cpuID).Return(cpuBusyFreq, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUBusyFrequency(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_busy_frequency_mhz\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_busy_frequency_mhz\": cpuBusyFreqExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC0SubstateC01Percent(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C01 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC01Percent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC0SubstateC01Percent, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc01Percent := 5.9229\n\t\tc01PercentExp := 5.92\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C01 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC01Percent\", cpuID).Return(c01Percent, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC01Percent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c0_substate_c01_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_substate_c01_percent\": c01PercentExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC0SubstateC02Percent(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C02 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC02Percent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC0SubstateC02Percent, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc02Percent := 0.001\n\t\tc02PercentExp := 0.0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C02 metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC02Percent\", cpuID).Return(c02Percent, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC02Percent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c0_substate_c02_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_substate_c02_percent\": c02PercentExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUC0SubstateC0WaitPercent(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C0Wait metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC0WaitPercent\", cpuID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC0WaitPercent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics(), 0)\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for CPU ID %v\", cpuC0SubstateC0WaitPercent, cpuID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tcpuID := 0\n\t\tcoreID := 1\n\t\tpackageID := 0\n\t\tc0WaitPercent := 0.995\n\t\tc0WaitPercentExp := 1.0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU C0Wait metric.\n\t\tmFetcher.On(\"GetCPUC0SubstateC0WaitPercent\", cpuID).Return(c0WaitPercent, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUC0SubstateC0WaitPercent(acc, cpuID, coreID, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_core\", \"cpu_c0_substate_c0_wait_percent\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_core\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_c0_substate_c0_wait_percent\": c0WaitPercentExp,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"cpu_id\":     strconv.Itoa(cpuID),\n\t\t\t\t\"core_id\":    strconv.Itoa(coreID),\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCurrentPackagePowerConsumption(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current package power consumption metric.\n\t\tmFetcher.On(\"GetCurrentPackagePowerConsumptionWatts\", packageID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCurrentPackagePower(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageCurrentPowerConsumption, packageID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\t\tcurrPower := float64(30.1999)\n\t\tcurrPowerRounded := float64(30.2)\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current package power consumption metric.\n\t\tmFetcher.On(\"GetCurrentPackagePowerConsumptionWatts\", packageID).Return(currPower, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCurrentPackagePower(acc, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_package\", \"current_power_consumption_watts\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current_power_consumption_watts\": currPowerRounded,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCurrentDramPowerConsumption(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCurrentDramPower(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageCurrentDramPowerConsumption, packageID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\t\tcurrPower := float64(30.8235)\n\t\tcurrPowerRounded := float64(30.82)\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current dram power consumption metric.\n\t\tmFetcher.On(\"GetCurrentDramPowerConsumptionWatts\", packageID).Return(currPower, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCurrentDramPower(acc, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_package\", \"current_dram_power_consumption_watts\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current_dram_power_consumption_watts\": currPowerRounded,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddThermalDesignPower(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting package thermal design power metric.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", packageID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addThermalDesignPower(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageThermalDesignPower, packageID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Rounded\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\t\ttdp := float64(80.1999)\n\t\ttdpRounded := float64(80.2)\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting package thermal design power metric.\n\t\tmFetcher.On(\"GetPackageThermalDesignPowerWatts\", packageID).Return(tdp, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addThermalDesignPower(acc, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasFloatField(\"powerstat_package\", \"thermal_design_power_watts\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"thermal_design_power_watts\": tdpRounded,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddCPUBaseFrequency(t *testing.T) {\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", packageID).Return(uint64(0), errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUBaseFrequency(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageCPUBaseFrequency, packageID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tpackageID := 0\n\t\tbaseFreq := uint64(700)\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting CPU base frequency metric.\n\t\tmFetcher.On(\"GetCPUBaseFrequency\", packageID).Return(baseFreq, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addCPUBaseFrequency(acc, packageID)\n\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\trequire.True(t, acc.HasUIntField(\"powerstat_package\", \"cpu_base_frequency_mhz\"))\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_base_frequency_mhz\": baseFreq,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddUncoreFrequency(t *testing.T) {\n\tpackageID, dieID := 1, 0\n\n\tt.Run(\"FailedToGetDieIDs\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", packageID).Return(nil, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequency(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(\n\t\t\tt,\n\t\t\tacc.FirstError(),\n\t\t\tfmt.Sprintf(\"failed to get die IDs for package ID %v\", packageID),\n\t\t)\n\t})\n\n\tt.Run(\"FailedToGetInitialLimits\", func(t *testing.T) {\n\t\tcurrMin := 500.0\n\t\tcurrMax := 2500.0\n\t\tcurr := 1000.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", packageID).Return([]int{dieID}, nil).Once()\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(800.0, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(currMin, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(currMax, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(curr, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequency(acc, packageID)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(\n\t\t\tt,\n\t\t\tacc.FirstError(),\n\t\t\tfmt.Sprintf(\"failed to get initial uncore frequency limits for package ID %v and die ID %v\", packageID, dieID),\n\t\t)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": currMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": currMax,\n\t\t\t\t\"uncore_frequency_mhz_cur\":       uint64(curr),\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"current\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailedToGetCurrentValues\", func(t *testing.T) {\n\t\tinitMin := 300.0\n\t\tinitMax := 1200.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", packageID).Return([]int{dieID}, nil).Once()\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(initMin, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(initMax, nil).Once()\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(500.0, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(1300.0, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequency(acc, packageID)\n\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(\n\t\t\tt,\n\t\t\tacc.FirstError(),\n\t\t\tfmt.Sprintf(\"failed to get current uncore frequency values for package ID %v and die ID %v\", packageID, dieID),\n\t\t)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": initMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": initMax,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tinitMin := 300.0\n\t\tinitMax := 1200.0\n\t\tcurrMin := 500.0\n\t\tcurrMax := 2500.0\n\t\tcurr := 1000.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting die IDs for package ID.\n\t\tmFetcher.On(\"GetPackageDieIDs\", packageID).Return([]int{dieID}, nil).Once()\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(initMin, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(initMax, nil).Once()\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(currMin, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(currMax, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(curr, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequency(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": initMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": initMax,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": currMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": currMax,\n\t\t\t\t\"uncore_frequency_mhz_cur\":       uint64(curr),\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"current\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddUncoreFrequencyInitialLimits(t *testing.T) {\n\tpackageID, dieID := 0, 0\n\n\tt.Run(\"WithModuleNotInitializedError\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tuncoreFreqErr := &ptel.ModuleNotInitializedError{Name: \"uncore_frequency\"}\n\t\tmError := fmt.Errorf(\"mock error: %w\", uncoreFreqErr)\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(0.0, mError).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\t// First call adds the error to the accumulator and logOnce map.\n\t\tp.addUncoreFrequencyInitialLimits(acc, packageID, dieID)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addUncoreFrequencyInitialLimits(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q initial limits\", packageUncoreFrequency))\n\t\trequire.ErrorContains(t, acc.FirstError(), uncoreFreqErr.Error())\n\n\t\trequire.Len(t, p.logOnce, 1)\n\t\trequire.Contains(t, p.logOnce, fmt.Sprintf(\"%s_%s_initial\", \"uncore_frequency\", packageUncoreFrequency))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithError\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequencyInitialLimits(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(\n\t\t\tt,\n\t\t\tacc.FirstError(),\n\t\t\tfmt.Sprintf(\"failed to get initial uncore frequency limits for package ID %v and die ID %v\", packageID, dieID),\n\t\t)\n\t\trequire.Empty(t, p.logOnce)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tinitMin := 300.0\n\t\tinitMax := 1200.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(initMin, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(initMax, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequencyInitialLimits(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": initMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": initMax,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"initial\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddUncoreFrequencyCurrentValues(t *testing.T) {\n\tpackageID, dieID := 0, 0\n\n\tt.Run(\"WithModuleNotInitializedError\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tuncoreFreqErr := &ptel.ModuleNotInitializedError{Name: \"uncore_frequency\"}\n\t\tmError := fmt.Errorf(\"mock error: %w\", uncoreFreqErr)\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(0.0, mError).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\t// First call adds the error to the accumulator and logOnce map.\n\t\tp.addUncoreFrequencyCurrentValues(acc, packageID, dieID)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addUncoreFrequencyCurrentValues(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q current value and limits\", packageUncoreFrequency))\n\t\trequire.ErrorContains(t, acc.FirstError(), uncoreFreqErr.Error())\n\n\t\trequire.Len(t, p.logOnce, 1)\n\t\trequire.Contains(t, p.logOnce, fmt.Sprintf(\"%s_%s_current\", \"uncore_frequency\", packageUncoreFrequency))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"WithError\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequencyCurrentValues(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(\n\t\t\tt,\n\t\t\tacc.FirstError(),\n\t\t\tfmt.Sprintf(\"failed to get current uncore frequency values for package ID %v and die ID %v\", packageID, dieID),\n\t\t)\n\t\trequire.Empty(t, p.logOnce)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tcurrMin := 500.0\n\t\tcurrMax := 2500.0\n\t\tcurr := 1000.0\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(currMin, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(currMax, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(curr, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addUncoreFrequencyCurrentValues(acc, packageID, dieID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 1)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"uncore_frequency_limit_mhz_min\": currMin,\n\t\t\t\t\"uncore_frequency_limit_mhz_max\": currMax,\n\t\t\t\t\"uncore_frequency_mhz_cur\":       uint64(curr),\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\": strconv.Itoa(packageID),\n\t\t\t\t\"type\":       \"current\",\n\t\t\t\t\"die\":        strconv.Itoa(dieID),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestGetUncoreFreqInitialLimits(t *testing.T) {\n\tpackageID, dieID := 0, 0\n\n\tt.Run(\"FailsToGetInitialMinLimit\", func(t *testing.T) {\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tinitMin, initMax, err := getUncoreFreqInitialLimits(mFetcher, packageID, dieID)\n\n\t\trequire.ErrorContains(t, err, \"failed to get initial minimum uncore frequency limit\")\n\t\trequire.Zero(t, initMin)\n\t\trequire.Zero(t, initMax)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailsToGetInitialMaxLimit\", func(t *testing.T) {\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(800.0, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tinitMin, initMax, err := getUncoreFreqInitialLimits(mFetcher, packageID, dieID)\n\n\t\trequire.ErrorContains(t, err, \"failed to get initial maximum uncore frequency limit\")\n\t\trequire.Zero(t, initMin)\n\t\trequire.Zero(t, initMax)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tinitMinExp := 300.0\n\t\tinitMaxExp := 1500.0\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting initial minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMin\", packageID, dieID).Return(initMinExp, nil).Once()\n\n\t\t// mock getting initial maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetInitialUncoreFrequencyMax\", packageID, dieID).Return(initMaxExp, nil).Once()\n\n\t\tinitMin, initMax, err := getUncoreFreqInitialLimits(mFetcher, packageID, dieID)\n\n\t\trequire.NoError(t, err)\n\t\trequire.InDelta(t, initMinExp, initMin, testutil.DefaultDelta)\n\t\trequire.InDelta(t, initMaxExp, initMax, testutil.DefaultDelta)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestGetUncoreFreqCurrentValues(t *testing.T) {\n\tpackageID, dieID := 0, 0\n\n\tt.Run(\"FailsToGetCurrentMinLimit\", func(t *testing.T) {\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tvalues, err := getUncoreFreqCurrentValues(mFetcher, packageID, dieID)\n\n\t\trequire.ErrorContains(t, err, \"failed to get current minimum uncore frequency limit\")\n\t\trequire.Equal(t, uncoreFreqValues{}, values)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailsToGetCurrentMaxLimit\", func(t *testing.T) {\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting current minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(1000.0, nil).Once()\n\n\t\t// mock getting current maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tvalues, err := getUncoreFreqCurrentValues(mFetcher, packageID, dieID)\n\n\t\trequire.ErrorContains(t, err, \"failed to get current maximum uncore frequency limit\")\n\t\trequire.Equal(t, uncoreFreqValues{}, values)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailsToGetCurrentValue\", func(t *testing.T) {\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(1000.0, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(2000.0, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(0.0, errors.New(\"mock error\")).Once()\n\n\t\tvalues, err := getUncoreFreqCurrentValues(mFetcher, packageID, dieID)\n\n\t\trequire.ErrorContains(t, err, \"failed to get current uncore frequency\")\n\t\trequire.Equal(t, uncoreFreqValues{}, values)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"Ok\", func(t *testing.T) {\n\t\tminUncore := 500.0\n\t\tmaxUncore := 1500.0\n\t\tcurrent := 750.0\n\n\t\tuncoreFreqValExp := uncoreFreqValues{\n\t\t\tcurrMin: minUncore,\n\t\t\tcurrMax: maxUncore,\n\t\t\tcurr:    current,\n\t\t}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting custom minimum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMin\", packageID, dieID).Return(minUncore, nil).Once()\n\n\t\t// mock getting custom maximum uncore frequency limit.\n\t\tmFetcher.On(\"GetCustomizedUncoreFrequencyMax\", packageID, dieID).Return(maxUncore, nil).Once()\n\n\t\t// mock getting current uncore frequency value.\n\t\tmFetcher.On(\"GetCurrentUncoreFrequency\", packageID, dieID).Return(current, nil).Once()\n\n\t\tvalues, err := getUncoreFreqCurrentValues(mFetcher, packageID, dieID)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, uncoreFreqValExp, values)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n\nfunc TestAddMaxTurboFreqLimits(t *testing.T) {\n\tt.Run(\"FailedToGetMetricModuleNotInitializedError\", func(t *testing.T) {\n\t\tpackageID := 1\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmErr := &ptel.ModuleNotInitializedError{Name: \"msr\"}\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(nil, mErr).Twice()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\n\t\t\tlogOnce: map[string]struct{}{},\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\t// First call adds the error to the accumulator and key to logOnce map.\n\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\n\t\t// Second call detects previous error in logOnce map and skips adding it to the accumulator.\n\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q: %v\", packageTurboLimit, mErr))\n\n\t\trequire.Len(t, p.logOnce, 1)\n\t\trequire.Contains(t, p.logOnce, \"msr_max_turbo_frequency\")\n\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"FailedToGetMetric\", func(t *testing.T) {\n\t\tpackageID := 1\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(nil, errors.New(\"mock error\")).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ErrorContains(t, acc.FirstError(), fmt.Sprintf(\"failed to get %q for package ID %v\", packageTurboLimit, packageID))\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"CPUIsHybrid\", func(t *testing.T) {\n\t\tpackageID := 1\n\n\t\tmaxTurboFreqList := []ptel.MaxTurboFreq{\n\t\t\t{\n\t\t\t\tValue:       1000,\n\t\t\t\tActiveCores: 10,\n\t\t\t\tSecondary:   true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tValue:       2000,\n\t\t\t\tActiveCores: 20,\n\t\t\t},\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(maxTurboFreqList, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": maxTurboFreqList[0].Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\t\"active_cores\": strconv.Itoa(int(maxTurboFreqList[0].ActiveCores)),\n\t\t\t\t\"hybrid\":       \"secondary\",\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": maxTurboFreqList[1].Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\t\"active_cores\": strconv.Itoa(int(maxTurboFreqList[1].ActiveCores)),\n\t\t\t\t\"hybrid\":       \"primary\",\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n\n\tt.Run(\"CPUIsNotHybrid\", func(t *testing.T) {\n\t\tpackageID := 1\n\n\t\tmaxTurboFreqList := []ptel.MaxTurboFreq{\n\t\t\t{\n\t\t\t\tValue:       1000,\n\t\t\t\tActiveCores: 10,\n\t\t\t},\n\t\t\t{\n\t\t\t\tValue:       2000,\n\t\t\t\tActiveCores: 20,\n\t\t\t},\n\t\t}\n\n\t\tacc := &testutil.Accumulator{}\n\n\t\tmFetcher := &fetcherMock{}\n\n\t\t// mock getting max turbo frequency list.\n\t\tmFetcher.On(\"GetMaxTurboFreqList\", packageID).Return(maxTurboFreqList, nil).Once()\n\n\t\tp := &PowerStat{\n\t\t\tfetcher: mFetcher,\n\t\t}\n\n\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t\tp.addMaxTurboFreqLimits(acc, packageID)\n\n\t\trequire.Empty(t, acc.Errors)\n\t\trequire.Len(t, acc.GetTelegrafMetrics(), 2)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": maxTurboFreqList[0].Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\t\"active_cores\": strconv.Itoa(int(maxTurboFreqList[0].ActiveCores)),\n\t\t\t},\n\t\t)\n\t\tacc.AssertContainsTaggedFields(\n\t\t\tt,\n\t\t\t// measurement\n\t\t\t\"powerstat_package\",\n\t\t\t// fields\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"max_turbo_frequency_mhz\": maxTurboFreqList[1].Value,\n\t\t\t},\n\t\t\t// tags\n\t\t\tmap[string]string{\n\t\t\t\t\"package_id\":   strconv.Itoa(packageID),\n\t\t\t\t\"active_cores\": strconv.Itoa(int(maxTurboFreqList[1].ActiveCores)),\n\t\t\t},\n\t\t)\n\t\tmFetcher.AssertExpectations(t)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/metrics.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\n\tptel \"github.com/intel/powertelemetry\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// cpuMetricType is an enum type to identify core metrics.\ntype cpuMetricType int\n\n// cpuMetricType enum defines supported core metrics.\nconst (\n\t// metric relying on cpuFreq\n\tcpuFrequency cpuMetricType = iota\n\n\t// metric relying on msr\n\tcpuTemperature\n\n\t// metrics relying on msr with storage\n\tcpuC0StateResidency\n\tcpuC1StateResidency\n\tcpuC3StateResidency\n\tcpuC6StateResidency\n\tcpuC7StateResidency\n\tcpuBusyFrequency\n\n\t// metrics relying on perf\n\tcpuC0SubstateC01Percent\n\tcpuC0SubstateC02Percent\n\tcpuC0SubstateC0WaitPercent\n)\n\n// Helper method to return a string representation of a core metric.\nfunc (m cpuMetricType) String() string {\n\tswitch m {\n\tcase cpuFrequency:\n\t\treturn \"cpu_frequency\"\n\tcase cpuTemperature:\n\t\treturn \"cpu_temperature\"\n\tcase cpuBusyFrequency:\n\t\treturn \"cpu_busy_frequency\"\n\tcase cpuC0StateResidency:\n\t\treturn \"cpu_c0_state_residency\"\n\tcase cpuC1StateResidency:\n\t\treturn \"cpu_c1_state_residency\"\n\tcase cpuC3StateResidency:\n\t\treturn \"cpu_c3_state_residency\"\n\tcase cpuC6StateResidency:\n\t\treturn \"cpu_c6_state_residency\"\n\tcase cpuC7StateResidency:\n\t\treturn \"cpu_c7_state_residency\"\n\tcase cpuC0SubstateC01Percent:\n\t\treturn \"cpu_c0_substate_c01\"\n\tcase cpuC0SubstateC02Percent:\n\t\treturn \"cpu_c0_substate_c02\"\n\tcase cpuC0SubstateC0WaitPercent:\n\t\treturn \"cpu_c0_substate_c0_wait\"\n\t}\n\treturn \"\"\n}\n\n// UnmarshalText parses the cpu metric from the TOML config file\nfunc (m *cpuMetricType) UnmarshalText(data []byte) (err error) {\n\tparsedMetric, err := cpuMetricTypeFromString(string(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*m = parsedMetric\n\treturn nil\n}\n\nfunc cpuMetricTypeFromString(metric string) (cpuMetricType, error) {\n\tswitch metric {\n\tcase \"cpu_frequency\":\n\t\treturn cpuFrequency, nil\n\tcase \"cpu_temperature\":\n\t\treturn cpuTemperature, nil\n\tcase \"cpu_busy_frequency\":\n\t\treturn cpuBusyFrequency, nil\n\tcase \"cpu_c0_state_residency\":\n\t\treturn cpuC0StateResidency, nil\n\tcase \"cpu_c1_state_residency\":\n\t\treturn cpuC1StateResidency, nil\n\tcase \"cpu_c3_state_residency\":\n\t\treturn cpuC3StateResidency, nil\n\tcase \"cpu_c6_state_residency\":\n\t\treturn cpuC6StateResidency, nil\n\tcase \"cpu_c7_state_residency\":\n\t\treturn cpuC7StateResidency, nil\n\tcase \"cpu_c0_substate_c01\":\n\t\treturn cpuC0SubstateC01Percent, nil\n\tcase \"cpu_c0_substate_c02\":\n\t\treturn cpuC0SubstateC02Percent, nil\n\tcase \"cpu_c0_substate_c0_wait\":\n\t\treturn cpuC0SubstateC0WaitPercent, nil\n\t}\n\n\treturn -1, fmt.Errorf(\"invalid cpu metric specified: %q\", metric)\n}\n\n// packageMetricType is an enum type to identify package metrics.\ntype packageMetricType int\n\n// packageMetricType enum defines supported package metrics.\nconst (\n\t// metrics relying on rapl\n\tpackageCurrentPowerConsumption packageMetricType = iota\n\tpackageCurrentDramPowerConsumption\n\tpackageThermalDesignPower\n\n\t// metrics relying on msr\n\tpackageCPUBaseFrequency\n\n\t// hybrid metric relying on uncoreFreq as a primary mechanism and on msr as fallback mechanism.\n\tpackageUncoreFrequency\n\n\t// metrics relying on msr\n\tpackageTurboLimit\n)\n\n// Helper method to return a string representation of a package metric.\nfunc (m packageMetricType) String() string {\n\tswitch m {\n\tcase packageCurrentPowerConsumption:\n\t\treturn \"current_power_consumption\"\n\tcase packageCurrentDramPowerConsumption:\n\t\treturn \"current_dram_power_consumption\"\n\tcase packageThermalDesignPower:\n\t\treturn \"thermal_design_power\"\n\tcase packageCPUBaseFrequency:\n\t\treturn \"cpu_base_frequency\"\n\tcase packageUncoreFrequency:\n\t\treturn \"uncore_frequency\"\n\tcase packageTurboLimit:\n\t\treturn \"max_turbo_frequency\"\n\t}\n\treturn \"\"\n}\n\n// UnmarshalText parses the package metric from the TOML config file\nfunc (m *packageMetricType) UnmarshalText(data []byte) (err error) {\n\tparsedMetric, err := packageMetricTypeFromString(string(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*m = parsedMetric\n\treturn nil\n}\n\nfunc packageMetricTypeFromString(metric string) (packageMetricType, error) {\n\tswitch metric {\n\tcase \"current_power_consumption\":\n\t\treturn packageCurrentPowerConsumption, nil\n\tcase \"current_dram_power_consumption\":\n\t\treturn packageCurrentDramPowerConsumption, nil\n\tcase \"thermal_design_power\":\n\t\treturn packageThermalDesignPower, nil\n\tcase \"cpu_base_frequency\":\n\t\treturn packageCPUBaseFrequency, nil\n\tcase \"uncore_frequency\":\n\t\treturn packageUncoreFrequency, nil\n\tcase \"max_turbo_frequency\":\n\t\treturn packageTurboLimit, nil\n\t}\n\n\treturn -1, fmt.Errorf(\"invalid package metric specified: %q\", metric)\n}\n\n// numeric is a type constraint definition.\ntype numeric interface {\n\tfloat64 | uint64\n}\n\n// metricInfoProvider provides measurement name, fields, and tags needed by the accumulator to add a metric.\ntype metricInfoProvider interface {\n\t// measurement returns a string with the name of measurement.\n\tmeasurement() string\n\n\t// fields returns a map of string keys with metric name and metric values.\n\tfields() (map[string]interface{}, error)\n\n\t// tags returns a map of string key and string value to add additional metric-specific information.\n\ttags() map[string]string\n\n\t// name returns the name of a metric.\n\tname() string\n}\n\n// addMetric takes a metricInfoProvider interface and adds metric information to an accumulator.\nfunc addMetric(acc telegraf.Accumulator, m metricInfoProvider, logOnceMap map[string]struct{}) {\n\tfields, err := m.fields()\n\tif err == nil {\n\t\tacc.AddGauge(\n\t\t\tm.measurement(),\n\t\t\tfields,\n\t\t\tm.tags(),\n\t\t)\n\t\treturn\n\t}\n\n\t// Always add to the accumulator errors not related to module not initialized.\n\tvar moduleErr *ptel.ModuleNotInitializedError\n\tif !errors.As(err, &moduleErr) {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\t// Add only once module not initialized error related to module and metric name.\n\tlogErrorOnce(\n\t\tacc,\n\t\tlogOnceMap,\n\t\tfmt.Sprintf(\"%s_%s\", moduleErr.Name, m.name()),\n\t\tfmt.Errorf(\"failed to get %q: %w\", m.name(), moduleErr),\n\t)\n}\n\n// metricCommon has metric information common to different types.\ntype metricCommon struct {\n\tmetric interface{}\n\tunits  string\n}\n\nfunc (m *metricCommon) name() string {\n\tswitch m.metric.(type) {\n\tcase cpuMetricType:\n\t\treturn m.metric.(cpuMetricType).String()\n\tcase packageMetricType:\n\t\treturn m.metric.(packageMetricType).String()\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (m *metricCommon) measurement() string {\n\tswitch m.metric.(type) {\n\tcase cpuMetricType:\n\t\treturn \"powerstat_core\"\n\tcase packageMetricType:\n\t\treturn \"powerstat_package\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// cpuMetric is a generic type that has the information to identify a CPU-related metric,\n// as well as function to retrieve its value at any time. Implements metricAdder interface.\ntype cpuMetric[T numeric] struct {\n\tmetricCommon\n\n\tcpuID     int\n\tcoreID    int\n\tpackageID int\n\tfetchFn   func(cpuID int) (T, error)\n}\n\nfunc (m *cpuMetric[T]) fields() (map[string]interface{}, error) {\n\tval, err := m.fetchFn(m.cpuID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get %q for CPU ID %v: %w\", m.metric, m.cpuID, err)\n\t}\n\n\treturn map[string]interface{}{\n\t\tfmt.Sprintf(\"%s_%s\", m.metric, m.units): round(val),\n\t}, nil\n}\n\nfunc (m *cpuMetric[T]) tags() map[string]string {\n\treturn map[string]string{\n\t\t\"core_id\":    strconv.Itoa(m.coreID),\n\t\t\"cpu_id\":     strconv.Itoa(m.cpuID),\n\t\t\"package_id\": strconv.Itoa(m.packageID),\n\t}\n}\n\n// packageMetric is a generic type that has the information to identify a package-related metric,\n// as well as the function to retrieve its value at any time. Implements metricAdder interface.\ntype packageMetric[T numeric] struct {\n\tmetricCommon\n\n\tpackageID int\n\tfetchFn   func(packageID int) (T, error)\n}\n\nfunc (m *packageMetric[T]) fields() (map[string]interface{}, error) {\n\tval, err := m.fetchFn(m.packageID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get %q for package ID %v: %w\", m.metric, m.packageID, err)\n\t}\n\n\treturn map[string]interface{}{\n\t\tfmt.Sprintf(\"%s_%s\", m.metric, m.units): round(val),\n\t}, nil\n}\n\nfunc (m *packageMetric[T]) tags() map[string]string {\n\treturn map[string]string{\n\t\t\"package_id\": strconv.Itoa(m.packageID),\n\t}\n}\n\n// round returns the result of rounding the argument, only if it's a 64 bit floating-point type.\nfunc round[T numeric](val T) T {\n\tif v, ok := any(val).(float64); ok {\n\t\tval = T(math.Round(v*100) / 100)\n\t}\n\treturn val\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/metrics_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCoreMetric_String(t *testing.T) {\n\ttestCases := []struct {\n\t\tname       string\n\t\tmetricName string\n\t}{\n\t\t{\n\t\t\tname:       \"CPUFrequency\",\n\t\t\tmetricName: \"cpu_frequency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUTemperature\",\n\t\t\tmetricName: \"cpu_temperature\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC0StateResidency\",\n\t\t\tmetricName: \"cpu_c0_state_residency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC1StateResidency\",\n\t\t\tmetricName: \"cpu_c1_state_residency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC3StateResidency\",\n\t\t\tmetricName: \"cpu_c3_state_residency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC6StateResidency\",\n\t\t\tmetricName: \"cpu_c6_state_residency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC7StateResidency\",\n\t\t\tmetricName: \"cpu_c7_state_residency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUBusyFrequency\",\n\t\t\tmetricName: \"cpu_busy_frequency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC0SubstateC01Percent\",\n\t\t\tmetricName: \"cpu_c0_substate_c01\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC0SubstateC02Percent\",\n\t\t\tmetricName: \"cpu_c0_substate_c02\",\n\t\t},\n\t\t{\n\t\t\tname:       \"CPUC0SubstateC0WaitPercent\",\n\t\t\tmetricName: \"cpu_c0_substate_c0_wait\",\n\t\t},\n\t\t{\n\t\t\tname:       \"Invalid\",\n\t\t\tmetricName: \"\",\n\t\t},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tmetric := cpuMetricType(i)\n\t\t\trequire.Equal(t, tc.metricName, metric.String())\n\t\t})\n\t}\n}\n\nfunc TestPackageMetric_String(t *testing.T) {\n\ttestCases := []struct {\n\t\tname       string\n\t\tmetricName string\n\t}{\n\t\t{\n\t\t\tname:       \"PackageCurrentPowerConsumption\",\n\t\t\tmetricName: \"current_power_consumption\",\n\t\t},\n\t\t{\n\t\t\tname:       \"PackageCurrentDramPowerConsumption\",\n\t\t\tmetricName: \"current_dram_power_consumption\",\n\t\t},\n\t\t{\n\t\t\tname:       \"PackageThermalDesignPower\",\n\t\t\tmetricName: \"thermal_design_power\",\n\t\t},\n\t\t{\n\t\t\tname:       \"PackageCPUBaseFrequency\",\n\t\t\tmetricName: \"cpu_base_frequency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"PackageUncoreFrequency\",\n\t\t\tmetricName: \"uncore_frequency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"PackageTurboLimit\",\n\t\t\tmetricName: \"max_turbo_frequency\",\n\t\t},\n\t\t{\n\t\t\tname:       \"Invalid\",\n\t\t\tmetricName: \"\",\n\t\t},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tmetric := packageMetricType(i)\n\t\t\trequire.Equal(t, tc.metricName, metric.String())\n\t\t})\n\t}\n}\n\nfunc TestCPUMetricTypeFromString(t *testing.T) {\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tfor m := cpuMetricType(0); m < cpuC0SubstateC0WaitPercent+1; m++ {\n\t\t\tval, err := cpuMetricTypeFromString(m.String())\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, m, val)\n\t\t}\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tval, err := cpuMetricTypeFromString(\"invalid\")\n\t\trequire.Error(t, err)\n\t\trequire.Equal(t, cpuMetricType(-1), val)\n\t})\n}\n\nfunc TestPackageMetricTypeFromString(t *testing.T) {\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tfor m := packageMetricType(0); m < packageTurboLimit+1; m++ {\n\t\t\tval, err := packageMetricTypeFromString(m.String())\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, m, val)\n\t\t}\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tval, err := packageMetricTypeFromString(\"invalid\")\n\t\trequire.Error(t, err)\n\t\trequire.Equal(t, packageMetricType(-1), val)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/options.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t\"slices\"\n\t\"time\"\n\n\tptel \"github.com/intel/powertelemetry\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// optConfig represents plugin configuration fields needed to generate options.\ntype optConfig struct {\n\tcpuMetrics     []cpuMetricType\n\tpackageMetrics []packageMetricType\n\tincludedCPUs   []int\n\texcludedCPUs   []int\n\tperfEventFile  string\n\tmsrReadTimeout time.Duration\n\tlog            telegraf.Logger\n}\n\n// optionGenerator takes a struct with the plugin configuration, and generates options\n// needed to gather metrics.\ntype optionGenerator interface {\n\tgenerate(cfg optConfig) []ptel.Option\n}\n\n// optGenerator implements optionGenerator interface.\ntype optGenerator struct{}\n\n// generate takes plugin configuration options and generates options needed\n// to gather requested metrics.\nfunc (*optGenerator) generate(cfg optConfig) []ptel.Option {\n\topts := make([]ptel.Option, 0)\n\tif len(cfg.includedCPUs) != 0 {\n\t\topts = append(opts, ptel.WithIncludedCPUs(cfg.includedCPUs))\n\t}\n\n\tif len(cfg.excludedCPUs) != 0 {\n\t\topts = append(opts, ptel.WithExcludedCPUs(cfg.excludedCPUs))\n\t}\n\n\tif needsMsrCPU(cfg.cpuMetrics) || needsMsrPackage(cfg.packageMetrics) {\n\t\tif cfg.msrReadTimeout == 0 {\n\t\t\topts = append(opts, ptel.WithMsr())\n\t\t} else {\n\t\t\topts = append(opts, ptel.WithMsrTimeout(cfg.msrReadTimeout))\n\t\t}\n\t}\n\n\tif needsRapl(cfg.packageMetrics) {\n\t\topts = append(opts, ptel.WithRapl())\n\t}\n\n\tif needsCoreFreq(cfg.cpuMetrics) {\n\t\topts = append(opts, ptel.WithCoreFrequency())\n\t}\n\n\tif needsUncoreFreq(cfg.packageMetrics) {\n\t\topts = append(opts, ptel.WithUncoreFrequency())\n\t}\n\n\tif needsPerf(cfg.cpuMetrics) {\n\t\topts = append(opts, ptel.WithPerf(cfg.perfEventFile))\n\t}\n\n\tif cfg.log != nil {\n\t\topts = append(opts, ptel.WithLogger(cfg.log))\n\t}\n\n\treturn opts\n}\n\n// needsMsr takes a slice of strings, representing supported metrics, and\n// returns true if any relies on msr registers.\nfunc needsMsrCPU(metrics []cpuMetricType) bool {\n\tfor _, m := range metrics {\n\t\tswitch m {\n\t\tcase cpuTemperature:\n\t\tcase cpuC0StateResidency:\n\t\tcase cpuC1StateResidency:\n\t\tcase cpuC3StateResidency:\n\t\tcase cpuC6StateResidency:\n\t\tcase cpuC7StateResidency:\n\t\tcase cpuBusyFrequency:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n\n// needsMsrPackage takes a slice of strings, representing supported metrics, and\n// returns true if any relies on msr registers.\nfunc needsMsrPackage(metrics []packageMetricType) bool {\n\tfor _, m := range metrics {\n\t\tswitch m {\n\t\tcase packageCPUBaseFrequency:\n\t\tcase packageTurboLimit:\n\t\tcase packageUncoreFrequency:\n\t\t\t// Fallback mechanism retrieves this metric from MSR registers.\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n\n// needsTimeRelatedMsr takes a slice of strings, representing supported metrics, and\n// returns true if any relies on time-related reads of msr registers.\nfunc needsTimeRelatedMsr(metrics []cpuMetricType) bool {\n\tfor _, m := range metrics {\n\t\tswitch m {\n\t\tcase cpuC0StateResidency:\n\t\tcase cpuC1StateResidency:\n\t\tcase cpuC3StateResidency:\n\t\tcase cpuC6StateResidency:\n\t\tcase cpuC7StateResidency:\n\t\tcase cpuBusyFrequency:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n\n// needsRapl takes a slice of strings, representing supported metrics, and\n// returns true if any relies on intel-rapl control zone.\nfunc needsRapl(metrics []packageMetricType) bool {\n\tfor _, m := range metrics {\n\t\tswitch m {\n\t\tcase packageCurrentPowerConsumption:\n\t\tcase packageCurrentDramPowerConsumption:\n\t\tcase packageThermalDesignPower:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n\n// needsCoreFreq takes a slice of strings, representing supported metrics, and\n// returns true if any relies on sysfs \"/sys/devices/system/cpu/\" with global and\n// individual CPU attributes.\nfunc needsCoreFreq(metrics []cpuMetricType) bool {\n\treturn slices.Contains(metrics, cpuFrequency)\n}\n\n// needsUncoreFreq takes a slice of strings, representing supported metrics, and returns\n// true if any relies on sysfs interface \"/sys/devices/system/cpu/intel_uncore_frequency/\"\n// provided by intel_uncore_frequency kernel module.\nfunc needsUncoreFreq(metrics []packageMetricType) bool {\n\treturn slices.Contains(metrics, packageUncoreFrequency)\n}\n\n// needsPerf takes a slice of strings, representing supported metrics, and\n// returns true if any relies on perf_events interface.\nfunc needsPerf(metrics []cpuMetricType) bool {\n\tfor _, m := range metrics {\n\t\tswitch m {\n\t\tcase cpuC0SubstateC01Percent:\n\t\tcase cpuC0SubstateC02Percent:\n\t\tcase cpuC0SubstateC0WaitPercent:\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/options_test.go",
    "content": "//go:build linux && amd64\n\npackage intel_powerstat\n\nimport (\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGenerate(t *testing.T) {\n\tt.Run(\"NoCPUsSpecified\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\tcpuFrequency,            // needs coreFreq\n\t\t\t\tcpuC0SubstateC01Percent, // needs perf\n\t\t\t},\n\t\t\tpackageMetrics: []packageMetricType{\n\t\t\t\tpackageCurrentPowerConsumption, // needs rapl\n\t\t\t\tpackageUncoreFrequency,         // needs uncoreFreq and msr\n\t\t\t},\n\t\t})\n\n\t\trequire.Len(t, opts, 5)\n\t})\n\n\tt.Run(\"ExcludedCPUs\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\texcludedCPUs: []int{0, 1, 2, 3},\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\t// needs msr\n\t\t\t\tcpuTemperature,\n\t\t\t},\n\t\t\tpackageMetrics: []packageMetricType{\n\t\t\t\t// needs rapl\n\t\t\t\tpackageCurrentPowerConsumption,\n\t\t\t},\n\t\t})\n\n\t\trequire.Len(t, opts, 3)\n\t})\n\n\tt.Run(\"IncludedCPUs\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\tincludedCPUs: []int{0, 1, 2, 3},\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\tcpuFrequency,               // needs coreFreq\n\t\t\t\tcpuC0SubstateC0WaitPercent, // needs perf\n\t\t\t},\n\t\t\tpackageMetrics: []packageMetricType{\n\t\t\t\tpackageTurboLimit,                  // needs msr\n\t\t\t\tpackageCurrentDramPowerConsumption, // needs rapl\n\t\t\t\tpackageUncoreFrequency,             // needs uncoreFreq\n\t\t\t},\n\t\t})\n\n\t\trequire.Len(t, opts, 6)\n\t})\n\n\tt.Run(\"WithMsrTimeout\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\tcpuTemperature,\n\t\t\t},\n\t\t\tmsrReadTimeout: time.Second,\n\t\t})\n\n\t\trequire.Len(t, opts, 1)\n\n\t\twithMsrTimeoutUsed := false\n\t\tfor _, opt := range opts {\n\t\t\tif strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), \".WithMsrTimeout.\") {\n\t\t\t\twithMsrTimeoutUsed = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\trequire.True(t, withMsrTimeoutUsed, \"WithMsrTimeout wasn't included in the generated options\")\n\t})\n\n\tt.Run(\"WithMsr\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\tcpuC7StateResidency,\n\t\t\t},\n\t\t\tmsrReadTimeout: 0, // timeout disabled\n\t\t})\n\n\t\trequire.Len(t, opts, 1)\n\n\t\twithMsrUsed := false\n\t\tfor _, opt := range opts {\n\t\t\tif strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), \".WithMsr.\") {\n\t\t\t\twithMsrUsed = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\trequire.True(t, withMsrUsed, \"WithMsr wasn't included in the generated options\")\n\t})\n\n\tt.Run(\"WithLogger\", func(t *testing.T) {\n\t\tg := &optGenerator{}\n\t\topts := g.generate(optConfig{\n\t\t\tcpuMetrics: []cpuMetricType{\n\t\t\t\tcpuC3StateResidency,\n\t\t\t},\n\t\t\tlog: &testutil.Logger{},\n\t\t})\n\n\t\trequire.Len(t, opts, 2)\n\n\t\twithLoggerUsed := false\n\t\tfor _, opt := range opts {\n\t\t\tif strings.Contains(runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name(), \".WithLogger.\") {\n\t\t\t\twithLoggerUsed = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\trequire.True(t, withLoggerUsed, \"WithLogger wasn't included in the generated options\")\n\t})\n}\n\nfunc TestNeedsMsrPackage(t *testing.T) {\n\tpackageMetrics := []packageMetricType{\n\t\tpackageThermalDesignPower,          // needs rapl\n\t\tpackageCurrentDramPowerConsumption, // needs rapl\n\t\tpackageMetricType(420),\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsMsrPackage(packageMetrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tt.Run(\"CPUBaseFreq\", func(t *testing.T) {\n\t\t\tpackageMetrics[len(packageMetrics)-1] = packageCPUBaseFrequency\n\t\t\trequire.True(t, needsMsrPackage(packageMetrics))\n\t\t})\n\n\t\tt.Run(\"PackageTurboLimit\", func(t *testing.T) {\n\t\t\tpackageMetrics[len(packageMetrics)-1] = packageTurboLimit\n\t\t\trequire.True(t, needsMsrPackage(packageMetrics))\n\t\t})\n\n\t\tt.Run(\"PackageUncoreFrequency\", func(t *testing.T) {\n\t\t\tpackageMetrics[len(packageMetrics)-1] = packageUncoreFrequency\n\t\t\trequire.True(t, needsMsrPackage(packageMetrics))\n\t\t})\n\t})\n}\n\nfunc TestNeedsMsrCPU(t *testing.T) {\n\tcpuMetrics := []cpuMetricType{\n\t\tcpuFrequency,            // needs cpuFreq\n\t\tcpuC0SubstateC01Percent, // needs perf\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsMsrCPU(cpuMetrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tt.Run(\"CPUTemperature\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuTemperature\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUC0StateResidency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuC0StateResidency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUC1StateResidency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuC1StateResidency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUC3StateResidency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuC3StateResidency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUC6StateResidency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuC6StateResidency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUC7StateResidency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuC7StateResidency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\n\t\tt.Run(\"CPUBusyFrequency\", func(t *testing.T) {\n\t\t\tcpuMetrics[len(cpuMetrics)-1] = cpuBusyFrequency\n\t\t\trequire.True(t, needsMsrCPU(cpuMetrics))\n\t\t})\n\t})\n}\n\nfunc TestNeedsRapl(t *testing.T) {\n\tmetrics := []packageMetricType{\n\t\tpackageCPUBaseFrequency, // needs msr\n\t\tpackageUncoreFrequency,  // needs uncoreFreq\n\t\tpackageMetricType(420),\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsRapl(metrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tt.Run(\"PackageCurrentPowerConsumption\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = packageCurrentPowerConsumption\n\t\t\trequire.True(t, needsRapl(metrics))\n\t\t})\n\n\t\tt.Run(\"PackageCurrentDramPowerConsumption\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = packageCurrentDramPowerConsumption\n\t\t\trequire.True(t, needsRapl(metrics))\n\t\t})\n\n\t\tt.Run(\"PackageThermalDesignPower\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = packageThermalDesignPower\n\t\t\trequire.True(t, needsRapl(metrics))\n\t\t})\n\t})\n}\n\nfunc TestNeedsCoreFreq(t *testing.T) {\n\tmetrics := []cpuMetricType{\n\t\tcpuTemperature,          // needs msr\n\t\tcpuC1StateResidency,     // needs msr\n\t\tcpuC0SubstateC01Percent, // needs perf\n\t\tcpuMetricType(420),\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsCoreFreq(metrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tmetrics[len(metrics)-1] = cpuFrequency\n\t\trequire.True(t, needsCoreFreq(metrics))\n\t})\n}\n\nfunc TestNeedsUncoreFreq(t *testing.T) {\n\tmetrics := []packageMetricType{\n\t\tpackageCPUBaseFrequency,   // needs msr\n\t\tpackageThermalDesignPower, // needs rapl\n\t\tpackageMetricType(420),\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsUncoreFreq(metrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tmetrics[len(metrics)-1] = packageUncoreFrequency\n\t\trequire.True(t, needsUncoreFreq(metrics))\n\t})\n}\n\nfunc TestNeedsPerf(t *testing.T) {\n\tmetrics := []cpuMetricType{\n\t\tcpuFrequency,        // needs cpuFreq\n\t\tcpuC1StateResidency, // needs msr\n\t\tcpuMetricType(420),\n\t}\n\n\tt.Run(\"False\", func(t *testing.T) {\n\t\trequire.False(t, needsPerf(metrics))\n\t})\n\n\tt.Run(\"True\", func(t *testing.T) {\n\t\tt.Run(\"CPUC0SubstateC01Percent\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = cpuC0SubstateC01Percent\n\t\t\trequire.True(t, needsPerf(metrics))\n\t\t})\n\n\t\tt.Run(\"CPUC0SubstateC02Percent\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = cpuC0SubstateC02Percent\n\t\t\trequire.True(t, needsPerf(metrics))\n\t\t})\n\n\t\tt.Run(\"CPUC0SubstateC0WaitPercent\", func(t *testing.T) {\n\t\t\tmetrics[len(metrics)-1] = cpuC0SubstateC0WaitPercent\n\t\t\trequire.True(t, needsPerf(metrics))\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/sample.conf",
    "content": "# Intel PowerStat plugin enables monitoring of platform metrics (power, TDP)\n# and per-CPU metrics like temperature, power and utilization. Please see the\n# plugin readme for details on software and hardware compatibility.\n# This plugin ONLY supports Linux.\n[[inputs.intel_powerstat]]\n  ## The user can choose which package metrics are monitored by the plugin with\n  ## the package_metrics setting:\n  ## - The default, will collect \"current_power_consumption\",\n  ##   \"current_dram_power_consumption\" and \"thermal_design_power\".\n  ## - Leaving this setting empty means no package metrics will be collected.\n  ## - Finally, a user can specify individual metrics to capture from the\n  ##   supported options list.\n  ## Supported options:\n  ##   \"current_power_consumption\", \"current_dram_power_consumption\",\n  ##   \"thermal_design_power\", \"max_turbo_frequency\", \"uncore_frequency\",\n  ##   \"cpu_base_frequency\"\n  # package_metrics = [\"current_power_consumption\", \"current_dram_power_consumption\", \"thermal_design_power\"]\n\n  ## The user can choose which per-CPU metrics are monitored by the plugin in\n  ## cpu_metrics array.\n  ## Empty or missing array means no per-CPU specific metrics will be collected\n  ## by the plugin.\n  ## Supported options:\n  ##   \"cpu_frequency\", \"cpu_c0_state_residency\", \"cpu_c1_state_residency\",\n  ##   \"cpu_c3_state_residency\", \"cpu_c6_state_residency\", \"cpu_c7_state_residency\",\n  ##   \"cpu_temperature\", \"cpu_busy_frequency\", \"cpu_c0_substate_c01\",\n  ##   \"cpu_c0_substate_c02\", \"cpu_c0_substate_c0_wait\"\n  # cpu_metrics = []\n\n  ## CPUs metrics to include from those configured in cpu_metrics array\n  ## Can't be combined with excluded_cpus. Empty means all CPUs are gathered.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # included_cpus = []\n\n  ## CPUs metrics to exclude from those configured in cpu_metrics array\n  ## Can't be combined with included_cpus. Empty means all CPUs are gathered.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # excluded_cpus = []\n\n  ## Filesystem location of JSON file that contains PMU event definitions.\n  ## Mandatory only for perf-related metrics (cpu_c0_substate_c01, cpu_c0_substate_c02, cpu_c0_substate_c0_wait).\n  # event_definitions = \"\"\n\n  ## The user can set the timeout duration for MSR reading.\n  ## Enabling this timeout can be useful in situations where, on heavily loaded systems,\n  ## the code waits too long for a kernel response to MSR read requests.\n  ## 0 disables the timeout (default).\n  # msr_read_timeout = \"0ms\"\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/aperfmperf_flag_not_found/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/cpu_model_missing/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n\nprocessor       : 1\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 1\ncpu cores       : 56\napicid          : 2\ninitial apicid  : 2\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n\nprocessor       : 2\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 2\ncpu cores       : 56\napicid          : 4\ninitial apicid  : 4\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n\nprocessor       : 3\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 3\ncpu cores       : 56\napicid          : 6\ninitial apicid  : 6\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/dts_flag_not_found/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/model_not_supported/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 14\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/msr_flag_not_found/cpuinfo",
    "content": "processor       : 0\nvendor_id       : GenuineIntel\ncpu family      : 6\nmodel           : 143\nmodel name      : Intel(R) Xeon(R) Platinum 8480+\nstepping        : 8\nmicrocode       : 0xab0000c0\ncpu MHz         : 2000.000\ncache size      : 107520 KB\nphysical id     : 0\nsiblings        : 112\ncore id         : 0\ncpu cores       : 56\napicid          : 0\ninitial apicid  : 0\nfpu             : yes\nfpu_exception   : yes\ncpuid level     : 32\nwp              : yes\nflags           : fpu vme de pse tsc pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr ibt amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities\nvmx flags       : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs pml ept_mode_based_exec tsc_scaling usr_wait_pause\nbugs            : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb\nbogomips        : 4000.00\nclflush size    : 64\ncache_alignment : 64\naddress sizes   : 52 bits physical, 57 bits virtual\npower management:\n"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/sapphirerapids_core.json",
    "content": "{\n  \"Header\": {\n    \"Copyright\": \"Copyright (c) 2001 - 2023 Intel Corporation. All rights reserved.\",\n    \"Info\": \"Performance Monitoring Events for 4th Generation Intel(R) Xeon(R) Processor Scalable Family based on Sapphire Rapids microarchitecture - V1.15\",\n    \"DatePublished\": \"06/28/2023\",\n    \"Version\": \"1.15\",\n    \"Legend\": \"\"\n  },\n  \"Events\": [\n    {\n      \"EventCode\": \"0x00\",\n      \"UMask\": \"0x02\",\n      \"EventName\": \"CPU_CLK_UNHALTED.THREAD\",\n      \"BriefDescription\": \"Core cycles when the thread is not in halt state\",\n      \"PublicDescription\": \"Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events.\",\n      \"Counter\": \"Fixed counter 1\",\n      \"PEBScounters\": \"33\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0x00\",\n      \"UMask\": \"0x03\",\n      \"EventName\": \"CPU_CLK_UNHALTED.REF_TSC\",\n      \"BriefDescription\": \"Reference cycles when the core is not in halt state.\",\n      \"PublicDescription\": \"Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'.  The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'.  After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.\",\n      \"Counter\": \"Fixed counter 2\",\n      \"PEBScounters\": \"34\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0x3c\",\n      \"UMask\": \"0x00\",\n      \"EventName\": \"CPU_CLK_UNHALTED.THREAD_P\",\n      \"BriefDescription\": \"Thread cycles when thread is not in halt state\",\n      \"PublicDescription\": \"This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0x3c\",\n      \"UMask\": \"0x01\",\n      \"EventName\": \"CPU_CLK_UNHALTED.REF_TSC_P\",\n      \"BriefDescription\": \"Reference cycles when the core is not in halt state.\",\n      \"PublicDescription\": \"Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'.  The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'.  After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0x3c\",\n      \"UMask\": \"0x02\",\n      \"EventName\": \"CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE\",\n      \"BriefDescription\": \"Core crystal clock cycles when this thread is unhalted and the other thread is halted.\",\n      \"PublicDescription\": \"Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"25003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0x3c\",\n      \"UMask\": \"0x08\",\n      \"EventName\": \"CPU_CLK_UNHALTED.REF_DISTRIBUTED\",\n      \"BriefDescription\": \"Core crystal clock cycles. Cycle counts are evenly distributed between active threads in the Core.\",\n      \"PublicDescription\": \"This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x02\",\n      \"EventName\": \"CPU_CLK_UNHALTED.DISTRIBUTED\",\n      \"BriefDescription\": \"Cycle counts are evenly distributed between active threads in the Core.\",\n      \"PublicDescription\": \"This event distributes cycle counts between active hyperthreads, i.e., those in C0.  A hyperthread becomes inactive when it executes the HLT or MWAIT instructions.  If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x10\",\n      \"EventName\": \"CPU_CLK_UNHALTED.C01\",\n      \"BriefDescription\": \"Core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.\",\n      \"PublicDescription\": \"Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.  This state can be entered via the TPAUSE or UMWAIT instructions.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x20\",\n      \"EventName\": \"CPU_CLK_UNHALTED.C02\",\n      \"BriefDescription\": \"Core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.\",\n      \"PublicDescription\": \"Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.  This state can be entered via the TPAUSE or UMWAIT instructions.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x40\",\n      \"EventName\": \"CPU_CLK_UNHALTED.PAUSE\",\n      \"BriefDescription\": \"CPU_CLK_UNHALTED.PAUSE\",\n      \"PublicDescription\": \"CPU_CLK_UNHALTED.PAUSE\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x40\",\n      \"EventName\": \"CPU_CLK_UNHALTED.PAUSE_INST\",\n      \"BriefDescription\": \"CPU_CLK_UNHALTED.PAUSE_INST\",\n      \"PublicDescription\": \"CPU_CLK_UNHALTED.PAUSE_INST\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"1\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"1\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    },\n    {\n      \"EventCode\": \"0xec\",\n      \"UMask\": \"0x70\",\n      \"EventName\": \"CPU_CLK_UNHALTED.C0_WAIT\",\n      \"BriefDescription\": \"Core clocks when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.\",\n      \"PublicDescription\": \"Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.\",\n      \"Counter\": \"0,1,2,3,4,5,6,7\",\n      \"PEBScounters\": \"0,1,2,3,4,5,6,7\",\n      \"SampleAfterValue\": \"2000003\",\n      \"MSRIndex\": \"0x00\",\n      \"MSRValue\": \"0x00\",\n      \"CollectPEBSRecord\": \"2\",\n      \"TakenAlone\": \"0\",\n      \"CounterMask\": \"0\",\n      \"Invert\": \"0\",\n      \"EdgeDetect\": \"0\",\n      \"PEBS\": \"0\",\n      \"Data_LA\": \"0\",\n      \"L1_Hit_Indication\": \"0\",\n      \"Errata\": \"null\",\n      \"Offcore\": \"0\",\n      \"Deprecated\": \"0\",\n      \"Speculative\": \"1\"\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/intel_powerstat/testdata/vendor_not_supported/cpuinfo",
    "content": "processor\t: 0\nvendor_id\t: AuthenticAMD\ncpu family\t: 16\nmodel\t\t: 2\nmodel name\t: AMD Phenom(tm) 9550 Quad-Core Processor\nstepping\t: 3\ncpu MHz\t\t: 1100.000\ncache size\t: 512 KB\nphysical id\t: 0\nsiblings\t: 4\ncore id\t\t: 0\ncpu cores\t: 4\napicid\t\t: 0\ninitial apicid\t: 0\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 5\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm 3dnowext 3dnow constant_tsc rep_good nonstop_tsc extd_apicid pni monitor cx16 popcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs\nbogomips\t: 4409.53\nTLB size\t: 1024 4K pages\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 48 bits physical, 48 bits virtual\npower management: ts ttp tm stc 100mhzsteps hwpstate\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/README.md",
    "content": "# Intel RDT Input Plugin\n\nThis plugin collects information provided by monitoring features of the\n[Intel Resource Director Technology][rdt], a hardware framework to monitor and\ncontrol the utilization of shared resources (e.g. last level cache,\nmemory bandwidth).\n\nIntel’s Resource Director Technology (RDT) framework consists of:\n\n- Cache Monitoring Technology (CMT)\n- Memory Bandwidth Monitoring (MBM)\n- Cache Allocation Technology (CAT)\n- Code and Data Prioritization (CDP)\n\nAs multithreaded and multicore platform architectures emerge, the last level\ncache and memory bandwidth are key resources to manage for running workloads in\nsingle-threaded, multithreaded, or complex virtual machine environments. Intel\nintroduces CMT, MBM, CAT and CDP to manage these workloads across shared\nresources.\n\n⭐ Telegraf v1.16.0\n🏷️ hardware, system\n💻 linux, freebsd, macos\n\n[rdt]: https://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html\n\n## Requirements\n\nThe plugin requires the `pqos` cli tool in version 4.0+ to be installed and\nconfigured to work in `OS Interface` mode. The tool is part of the\n[Intel(R) RDT Software Package][cmt_cat].\n\n> [!IMPORTANT]\n> The `pqos` binary needs to run as root. If telegraf is not running as root\n> you need to enable sudo for `pqos` and set the `use_sudo` option to `true`.\n\nTo setup `pqos` correctly check the [installation guide][install]. For help on\nhow to configure the tool visit the [wiki][wiki] and read the\n[resource control documentation][resctl]\n\n[cmt_cat]: https://github.com/intel/intel-cmt-cat\n[install]: https://github.com/intel/intel-cmt-cat/blob/master/INSTALL\n[wiki]: https://github.com/intel/intel-cmt-cat/wiki\n[resctl]: https://github.com/intel/intel-cmt-cat/wiki/resctrl\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Intel RDT metrics\n# This plugin ONLY supports non-Windows\n[[inputs.intel_rdt]]\n  ## Optionally set sampling interval to Nx100ms.\n  ## This value is propagated to pqos tool. Interval format is defined by pqos itself.\n  ## If not provided or provided 0, will be set to 10 = 10x100ms = 1s.\n  # sampling_interval = \"10\"\n\n  ## Optionally specify the path to pqos executable.\n  ## If not provided, auto discovery will be performed.\n  # pqos_path = \"/usr/local/bin/pqos\"\n\n  ## Optionally specify if IPC and LLC_Misses metrics shouldn't be propagated.\n  ## If not provided, default value is false.\n  # shortened_metrics = false\n\n  ## Specify the list of groups of CPU core(s) to be provided as pqos input.\n  ## Mandatory if processes aren't set and forbidden if processes are specified.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # cores = [\"0-3\"]\n\n  ## Specify the list of processes for which Metrics will be collected.\n  ## Mandatory if cores aren't set and forbidden if cores are specified.\n  ## e.g. [\"qemu\", \"pmd\"]\n  # processes = [\"process\"]\n\n  ## Specify if the pqos process should be called with sudo.\n  ## Mandatory if the telegraf process does not run as root.\n  # use_sudo = false\n```\n\n## Troubleshooting\n\nPointing to non-existing cores will lead to throwing an error by _pqos_ and the\nplugin will not work properly. Be sure to check provided core number exists\nwithin desired system.\n\nBe aware, reading Intel RDT metrics by _pqos_ cannot be done simultaneously on\nthe same resource.  Do not use any other _pqos_ instance that is monitoring the\nsame cores or PIDs within the working system.  It is not possible to monitor\nsame cores or PIDs on different groups.\n\nPIDs associated for the given process could be manually checked by `pidof`\ncommand. E.g:\n\n```sh\npidof PROCESS\n```\n\nwhere `PROCESS` is process name.\n\n## Metrics\n\n| Name          | Full name                                     | Description |\n|---------------|-----------------------------------------------|-------------|\n| MBL           | Memory Bandwidth on Local NUMA Node  |     Memory bandwidth utilization by the relevant CPU core/process on the local NUMA memory channel        |\n| MBR           | Memory Bandwidth on Remote NUMA Node |     Memory bandwidth utilization by the relevant CPU core/process on the remote NUMA memory channel        |\n| MBT           | Total Memory Bandwidth               |     Total memory bandwidth utilized by a CPU core/process on local and remote NUMA memory channels        |\n| LLC           | L3 Cache Occupancy                   |     Total Last Level Cache occupancy by a CPU core/process         |\n| LLC_Misses*    | L3 Cache Misses                      |    Total Last Level Cache misses by a CPU core/process       |\n| IPC*           | Instructions Per Cycle               |     Total instructions per cycle executed by a CPU core/process        |\n\n*optional\n\n## Example Output\n\n```text\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=IPC,process=top value=0 1598962030000000000\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=LLC_Misses,process=top value=0 1598962030000000000\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=LLC,process=top value=0 1598962030000000000\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=MBL,process=top value=0 1598962030000000000\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=MBR,process=top value=0 1598962030000000000\nrdt_metric,cores=12\\,19,host=r2-compute-20,name=MBT,process=top value=0 1598962030000000000\n```\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/intel_rdt.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !windows\n\npackage intel_rdt\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar pqosMetricOrder = map[int]string{\n\t0: \"IPC\",        // Instructions Per Cycle\n\t1: \"LLC_Misses\", // Cache Misses\n\t2: \"LLC\",        // L3 Cache Occupancy\n\t3: \"MBL\",        // Memory Bandwidth on Local NUMA Node\n\t4: \"MBR\",        // Memory Bandwidth on Remote NUMA Node\n\t5: \"MBT\",        // Total Memory Bandwidth\n}\n\nconst (\n\ttimestampFormat           = \"2006-01-02 15:04:05\"\n\tdefaultSamplingInterval   = 10\n\tpqosInitOutputLinesNumber = 4\n\tnumberOfMetrics           = 6\n\tsecondsDenominator        = 10\n)\n\ntype IntelRDT struct {\n\tPqosPath         string          `toml:\"pqos_path\"`\n\tCores            []string        `toml:\"cores\"`\n\tProcesses        []string        `toml:\"processes\"`\n\tSamplingInterval int32           `toml:\"sampling_interval\"`\n\tShortenedMetrics bool            `toml:\"shortened_metrics\"`\n\tUseSudo          bool            `toml:\"use_sudo\"`\n\tLog              telegraf.Logger `toml:\"-\"`\n\n\tpublisher        publisher\n\tprocessor        processesHandler\n\tstopPQOSChan     chan bool\n\tquitChan         chan struct{}\n\terrorChan        chan error\n\tparsedCores      []string\n\tprocessesPIDsMap map[string]string\n\tcancel           context.CancelFunc\n\twg               sync.WaitGroup\n}\n\ntype processMeasurement struct {\n\tname        string\n\tmeasurement string\n}\n\ntype splitCSVLine struct {\n\ttimeValue        string\n\tmetricsValues    []string\n\tcoreOrPIDsValues []string\n}\n\nfunc (*IntelRDT) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *IntelRDT) Start(acc telegraf.Accumulator) error {\n\tctx, cancel := context.WithCancel(context.Background())\n\tr.cancel = cancel\n\n\tr.processor = newProcessor()\n\tr.publisher = newPublisher(acc, r.Log, r.ShortenedMetrics)\n\n\terr := r.initialize()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.publisher.publish(ctx)\n\tgo r.errorHandler(ctx)\n\tgo r.scheduler(ctx)\n\n\treturn nil\n}\n\nfunc (*IntelRDT) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (r *IntelRDT) Stop() {\n\tr.cancel()\n\tr.wg.Wait()\n}\n\nfunc (r *IntelRDT) initialize() error {\n\tr.stopPQOSChan = make(chan bool)\n\tr.quitChan = make(chan struct{})\n\tr.errorChan = make(chan error)\n\n\terr := validatePqosPath(r.PqosPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(r.Cores) != 0 && len(r.Processes) != 0 {\n\t\treturn errors.New(\"monitoring start error, process and core tracking can not be done simultaneously\")\n\t}\n\tif len(r.Cores) == 0 && len(r.Processes) == 0 {\n\t\treturn errors.New(\"monitoring start error, at least one of cores or processes must be provided in config\")\n\t}\n\tif r.SamplingInterval == 0 {\n\t\tr.SamplingInterval = defaultSamplingInterval\n\t}\n\tif err := validateInterval(r.SamplingInterval); err != nil {\n\t\treturn err\n\t}\n\tr.parsedCores, err = parseCoresConfig(r.Cores)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr.processesPIDsMap, err = r.associateProcessesWithPIDs(r.Processes)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (r *IntelRDT) errorHandler(ctx context.Context) {\n\tr.wg.Add(1)\n\tdefer r.wg.Done()\n\tfor {\n\t\tselect {\n\t\tcase err := <-r.errorChan:\n\t\t\tif err != nil {\n\t\t\t\tr.Log.Error(fmt.Sprintf(\"Error: %v\", err))\n\t\t\t\tr.quitChan <- struct{}{}\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (r *IntelRDT) scheduler(ctx context.Context) {\n\tr.wg.Add(1)\n\tdefer r.wg.Done()\n\tinterval := time.Duration(r.SamplingInterval)\n\tticker := time.NewTicker(interval * time.Second / secondsDenominator)\n\n\tr.createArgsAndStartPQOS(ctx)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tif len(r.Processes) != 0 {\n\t\t\t\terr := r.checkPIDsAssociation(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\tr.errorChan <- err\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-r.quitChan:\n\t\t\tr.cancel()\n\t\t\treturn\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (r *IntelRDT) checkPIDsAssociation(ctx context.Context) error {\n\tnewProcessesPIDsMap, err := r.associateProcessesWithPIDs(r.Processes)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// change in PIDs association appears\n\tif !cmp.Equal(newProcessesPIDsMap, r.processesPIDsMap) {\n\t\tr.Log.Warnf(\"PIDs association has changed. Refreshing...\")\n\t\tif len(r.processesPIDsMap) != 0 {\n\t\t\tr.stopPQOSChan <- true\n\t\t}\n\t\tr.processesPIDsMap = newProcessesPIDsMap\n\t\tr.createArgsAndStartPQOS(ctx)\n\t}\n\treturn nil\n}\n\nfunc (r *IntelRDT) associateProcessesWithPIDs(providedProcesses []string) (map[string]string, error) {\n\tavailableProcesses, err := r.processor.getAllProcesses()\n\tif err != nil {\n\t\treturn nil, errors.New(\"cannot gather information of all available processes\")\n\t}\n\n\tmapProcessPIDs := make(map[string]string, len(availableProcesses))\n\tfor _, availableProcess := range availableProcesses {\n\t\tif choice.Contains(availableProcess.Name, providedProcesses) {\n\t\t\tpid := availableProcess.PID\n\t\t\tmapProcessPIDs[availableProcess.Name] = mapProcessPIDs[availableProcess.Name] + strconv.Itoa(pid) + \",\"\n\t\t}\n\t}\n\tfor key := range mapProcessPIDs {\n\t\tmapProcessPIDs[key] = strings.TrimSuffix(mapProcessPIDs[key], \",\")\n\t}\n\treturn mapProcessPIDs, nil\n}\n\nfunc (r *IntelRDT) createArgsAndStartPQOS(ctx context.Context) {\n\targs := []string{\"-r\", \"--iface-os\", \"--mon-file-type=csv\", fmt.Sprintf(\"--mon-interval=%d\", r.SamplingInterval)}\n\n\tif len(r.parsedCores) != 0 {\n\t\tcoresArg := createArgCores(r.parsedCores)\n\t\targs = append(args, coresArg)\n\t\tgo r.readData(ctx, args, nil)\n\t} else if len(r.processesPIDsMap) != 0 {\n\t\tprocessArg := createArgProcess(r.processesPIDsMap)\n\t\targs = append(args, processArg)\n\t\tgo r.readData(ctx, args, r.processesPIDsMap)\n\t}\n}\n\nfunc (r *IntelRDT) readData(ctx context.Context, args []string, processesPIDsAssociation map[string]string) {\n\tr.wg.Add(1)\n\tdefer r.wg.Done()\n\n\tcmd := exec.Command(r.PqosPath, args...)\n\n\tif r.UseSudo {\n\t\t// run pqos with `/bin/sh -c \"sudo /path/to/pqos ...\"`\n\t\targs = []string{\"-c\", fmt.Sprintf(\"sudo %s %s\", r.PqosPath, strings.ReplaceAll(strings.Join(args, \" \"), \";\", \"\\\\;\"))}\n\t\tcmd = exec.Command(\"/bin/sh\", args...)\n\t}\n\n\tcmdReader, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\tr.errorChan <- err\n\t}\n\tgo r.processOutput(cmdReader, processesPIDsAssociation)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-r.stopPQOSChan:\n\t\t\t\tif err := shutDownPqos(cmd); err != nil {\n\t\t\t\t\tr.Log.Error(err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\tcase <-ctx.Done():\n\t\t\t\tif err := shutDownPqos(cmd); err != nil {\n\t\t\t\t\tr.Log.Error(err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\terr = cmd.Start()\n\tif err != nil {\n\t\tr.Log.Errorf(\"pqos: %v\", err)\n\t\treturn\n\t}\n\terr = cmd.Wait()\n\tif err != nil {\n\t\tr.Log.Errorf(\"pqos: %v\", err)\n\t}\n}\n\nfunc (r *IntelRDT) processOutput(cmdReader io.ReadCloser, processesPIDsAssociation map[string]string) {\n\treader := bufio.NewScanner(cmdReader)\n\t/*\n\t\tOmit constant, first 4 lines :\n\t\t\"NOTE:  Mixed use of MSR and kernel interfaces to manage\n\t\t\t\tCAT or CMT & MBM may lead to unexpected behavior.\\n\"\n\t\tCMT/MBM reset successful\n\t\t\"Time,Core,IPC,LLC Misses,LLC[KB],MBL[MB/s],MBR[MB/s],MBT[MB/s]\\n\"\n\t*/\n\ttoOmit := pqosInitOutputLinesNumber\n\n\tif len(r.parsedCores) != 0 { // omit first measurements which are zeroes\n\t\ttoOmit = toOmit + len(r.parsedCores)\n\t} else if len(processesPIDsAssociation) != 0 { // specify how many lines should pass before stopping\n\t\ttoOmit = toOmit + len(processesPIDsAssociation)\n\t}\n\tfor omitCounter := 0; omitCounter < toOmit; omitCounter++ {\n\t\treader.Scan()\n\t}\n\tfor reader.Scan() {\n\t\tout := reader.Text()\n\t\t// to handle situation when monitored PID disappear and \"err\" is shown in output\n\t\tif strings.Contains(out, \"err\") {\n\t\t\tcontinue\n\t\t}\n\t\tif len(r.Processes) != 0 {\n\t\t\tnewMetric := processMeasurement{}\n\n\t\t\tpids, err := findPIDsInMeasurement(out)\n\t\t\tif err != nil {\n\t\t\t\tr.Log.Warnf(\"Skipping measurement: %v\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor processName, PIDsProcess := range processesPIDsAssociation {\n\t\t\t\tif pids == PIDsProcess {\n\t\t\t\t\tnewMetric.name = processName\n\t\t\t\t\tnewMetric.measurement = out\n\t\t\t\t}\n\t\t\t}\n\t\t\tr.publisher.bufferChanProcess <- newMetric\n\t\t} else {\n\t\t\tr.publisher.bufferChanCores <- out\n\t\t}\n\t}\n}\n\nfunc shutDownPqos(pqos *exec.Cmd) error {\n\ttimeout := time.Second * 2\n\n\tif pqos.Process != nil {\n\t\t//nolint:errcheck // try to send interrupt signal, ignore err for now\n\t\tpqos.Process.Signal(os.Interrupt)\n\n\t\t// wait and constantly check if pqos is still running\n\t\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\t\tdefer cancel()\n\t\tfor {\n\t\t\tif err := pqos.Process.Signal(syscall.Signal(0)); errors.Is(err, os.ErrProcessDone) {\n\t\t\t\treturn nil\n\t\t\t} else if ctx.Err() != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// if pqos is still running after some period, try to kill it\n\t\t// this will send SIGTERM to pqos, and leave garbage in `/sys/fs/resctrl/mon_groups`\n\t\t// fixed in https://github.com/intel/intel-cmt-cat/issues/197\n\t\terr := pqos.Process.Kill()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to shut down pqos: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc createArgCores(cores []string) string {\n\tallGroupsArg := \"--mon-core=\"\n\tvar b strings.Builder\n\tfor _, coreGroup := range cores {\n\t\targGroup := createArgsForGroups(strings.Split(coreGroup, \",\"))\n\t\tb.WriteString(argGroup)\n\t}\n\treturn allGroupsArg + b.String()\n}\n\nfunc createArgProcess(processPIDs map[string]string) string {\n\tallPIDsArg := \"--mon-pid=\"\n\tvar b strings.Builder\n\tfor _, PIDs := range processPIDs {\n\t\targPIDs := createArgsForGroups(strings.Split(PIDs, \",\"))\n\t\tb.WriteString(argPIDs)\n\t}\n\treturn allPIDsArg + b.String()\n}\n\nfunc createArgsForGroups(coresOrPIDs []string) string {\n\ttemplate := \"all:[%s];mbt:[%s];\"\n\tgroup := \"\"\n\n\tfor _, coreOrPID := range coresOrPIDs {\n\t\tgroup = group + coreOrPID + \",\"\n\t}\n\tif group != \"\" {\n\t\tgroup = strings.TrimSuffix(group, \",\")\n\t\treturn fmt.Sprintf(template, group, group)\n\t}\n\treturn \"\"\n}\n\nfunc validatePqosPath(pqosPath string) error {\n\tif len(pqosPath) == 0 {\n\t\treturn errors.New(\"monitoring start error, can not find pqos executable\")\n\t}\n\tpathInfo, err := os.Stat(pqosPath)\n\tif os.IsNotExist(err) {\n\t\treturn errors.New(\"monitoring start error, provided pqos path not exist\")\n\t}\n\tif mode := pathInfo.Mode(); !mode.IsRegular() {\n\t\treturn errors.New(\"monitoring start error, provided pqos path does not point to a regular file\")\n\t}\n\treturn nil\n}\n\nfunc parseCoresConfig(cores []string) ([]string, error) {\n\tvar allCores []int\n\n\tparsedCores := make([]string, 0, len(cores))\n\tfor _, singleCoreGroup := range cores {\n\t\tvar actualGroupOfCores []int\n\t\tseparatedCores := strings.Split(singleCoreGroup, \",\")\n\n\t\tfor _, coreStr := range separatedCores {\n\t\t\tactualCores, err := validateAndParseCores(coreStr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"wrong cores input config data format: %w\", err)\n\t\t\t}\n\t\t\tif checkForDuplicates(allCores, actualCores) {\n\t\t\t\treturn nil, errors.New(\"wrong cores input config data format: core value cannot be duplicated\")\n\t\t\t}\n\t\t\tactualGroupOfCores = append(actualGroupOfCores, actualCores...)\n\t\t\tallCores = append(allCores, actualGroupOfCores...)\n\t\t}\n\t\tparsedCores = append(parsedCores, arrayToString(actualGroupOfCores))\n\t}\n\n\treturn parsedCores, nil\n}\n\nfunc validateAndParseCores(coreStr string) ([]int, error) {\n\tvar processedCores []int\n\tif strings.Contains(coreStr, \"-\") {\n\t\trangeValues := strings.Split(coreStr, \"-\")\n\n\t\tif len(rangeValues) != 2 {\n\t\t\treturn nil, errors.New(\"more than two values in range\")\n\t\t}\n\n\t\tstartValue, err := strconv.Atoi(rangeValues[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tstopValue, err := strconv.Atoi(rangeValues[1])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif startValue > stopValue {\n\t\t\treturn nil, errors.New(\"first value cannot be higher than second\")\n\t\t}\n\n\t\trangeOfCores := makeRange(startValue, stopValue)\n\t\tprocessedCores = append(processedCores, rangeOfCores...)\n\t} else {\n\t\tnewCore, err := strconv.Atoi(coreStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tprocessedCores = append(processedCores, newCore)\n\t}\n\treturn processedCores, nil\n}\n\nfunc findPIDsInMeasurement(measurements string) (string, error) {\n\t// to distinguish PIDs from Cores (PIDs should be in quotes)\n\tvar insideQuoteRegex = regexp.MustCompile(`\"(.*?)\"`)\n\tpidsMatch := insideQuoteRegex.FindStringSubmatch(measurements)\n\tif len(pidsMatch) < 2 {\n\t\treturn \"\", errors.New(\"cannot find PIDs in measurement line\")\n\t}\n\tpids := pidsMatch[1]\n\treturn pids, nil\n}\n\nfunc splitCSVLineIntoValues(line string) (splitCSVLine, error) {\n\tvalues, err := splitMeasurementLine(line)\n\tif err != nil {\n\t\treturn splitCSVLine{}, err\n\t}\n\n\ttimeValue := values[0]\n\t// Because pqos csv format is broken when many cores are involved in PID or\n\t// group of PIDs, there is need to work around it. E.g.:\n\t// Time,PID,Core,IPC,LLC Misses,LLC[KB],MBL[MB/s],MBR[MB/s],MBT[MB/s]\n\t// 2020-08-12 13:34:36,\"45417,29170,\",37,44,0.00,0,0.0,0.0,0.0,0.0\n\tmetricsValues := values[len(values)-numberOfMetrics:]\n\tcoreOrPIDsValues := values[1 : len(values)-numberOfMetrics]\n\n\treturn splitCSVLine{timeValue, metricsValues, coreOrPIDsValues}, nil\n}\n\nfunc validateInterval(interval int32) error {\n\tif interval < 0 {\n\t\treturn errors.New(\"interval cannot be lower than 0\")\n\t}\n\treturn nil\n}\n\nfunc splitMeasurementLine(line string) ([]string, error) {\n\tvalues := strings.Split(line, \",\")\n\tif len(values) < 8 {\n\t\treturn nil, fmt.Errorf(\"not valid line format from pqos: %s\", values)\n\t}\n\treturn values, nil\n}\n\nfunc parseTime(value string) (time.Time, error) {\n\ttimestamp, err := time.ParseInLocation(timestampFormat, value, time.Local)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\treturn timestamp, nil\n}\n\nfunc parseFloat(value string) (float64, error) {\n\tresult, err := strconv.ParseFloat(value, 64)\n\tif err != nil {\n\t\treturn result, err\n\t}\n\treturn result, nil\n}\n\nfunc arrayToString(array []int) string {\n\tresult := \"\"\n\tfor _, value := range array {\n\t\tresult = fmt.Sprintf(\"%s%d,\", result, value)\n\t}\n\treturn strings.TrimSuffix(result, \",\")\n}\n\nfunc checkForDuplicates(values, valuesToCheck []int) bool {\n\tfor _, value := range values {\n\t\tfor _, valueToCheck := range valuesToCheck {\n\t\t\tif value == valueToCheck {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc makeRange(low, high int) []int {\n\ta := make([]int, high-low+1)\n\tfor i := range a {\n\t\ta[i] = low + i\n\t}\n\treturn a\n}\n\nfunc init() {\n\tinputs.Add(\"intel_rdt\", func() telegraf.Input {\n\t\trdt := IntelRDT{}\n\t\tpathPqos, err := exec.LookPath(\"pqos\")\n\t\tif len(pathPqos) > 0 && err != nil {\n\t\t\trdt.PqosPath = pathPqos\n\t\t}\n\t\treturn &rdt\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/intel_rdt_test.go",
    "content": "//go:build !windows\n\npackage intel_rdt\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockProc struct{}\n\nfunc (*mockProc) getAllProcesses() ([]process, error) {\n\tprocs := []process{\n\t\t{Name: \"process\", PID: 1000},\n\t\t{Name: \"process2\", PID: 1002},\n\t\t{Name: \"process2\", PID: 1003},\n\t}\n\treturn procs, nil\n}\n\nfunc TestAssociateProcessesWithPIDs(t *testing.T) {\n\tlog := testutil.Logger{}\n\tproc := &mockProc{}\n\trdt := IntelRDT{\n\t\tLog:       log,\n\t\tprocessor: proc,\n\t}\n\tprocesses := []string{\"process\"}\n\texpectedPID := \"1000\"\n\tresult, err := rdt.associateProcessesWithPIDs(processes)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedPID, result[processes[0]])\n\n\tprocesses = []string{\"process2\"}\n\texpectedPID = \"1002,1003\"\n\tresult, err = rdt.associateProcessesWithPIDs(processes)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedPID, result[processes[0]])\n\n\tprocesses = []string{\"process1\"}\n\tresult, err = rdt.associateProcessesWithPIDs(processes)\n\trequire.NoError(t, err)\n\trequire.Empty(t, result)\n}\n\nfunc TestSplitCSVLineIntoValues(t *testing.T) {\n\tline := \"2020-08-12 13:34:36,\\\"45417,29170\\\",37,44,0.00,0,0.0,0.0,0.0,0.0\"\n\texpectedTimeValue := \"2020-08-12 13:34:36\"\n\texpectedMetricsValue := []string{\"0.00\", \"0\", \"0.0\", \"0.0\", \"0.0\", \"0.0\"}\n\texpectedCoreOrPidsValue := []string{\"\\\"45417\", \"29170\\\"\", \"37\", \"44\"}\n\n\tsplitCSV, err := splitCSVLineIntoValues(line)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expectedTimeValue, splitCSV.timeValue)\n\trequire.Equal(t, expectedMetricsValue, splitCSV.metricsValues)\n\trequire.Equal(t, expectedCoreOrPidsValue, splitCSV.coreOrPIDsValues)\n\n\twrongLine := \"2020-08-12 13:34:36,37,44,0.00,0,0.0\"\n\tsplitCSV, err = splitCSVLineIntoValues(wrongLine)\n\trequire.Error(t, err)\n\trequire.Empty(t, splitCSV.timeValue)\n\trequire.Nil(t, splitCSV.metricsValues)\n\trequire.Nil(t, splitCSV.coreOrPIDsValues)\n}\n\nfunc TestFindPIDsInMeasurement(t *testing.T) {\n\tline := \"2020-08-12 13:34:36,\\\"45417,29170\\\"\"\n\texpected := \"45417,29170\"\n\tresult, err := findPIDsInMeasurement(line)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expected, result)\n\n\tline = \"pids not included\"\n\tresult, err = findPIDsInMeasurement(line)\n\trequire.Error(t, err)\n\trequire.Empty(t, result)\n}\n\nfunc TestCreateArgsProcesses(t *testing.T) {\n\tprocessesPIDs := map[string]string{\n\t\t\"process\": \"12345, 99999\",\n\t}\n\texpected := \"--mon-pid=all:[12345, 99999];mbt:[12345, 99999];\"\n\tresult := createArgProcess(processesPIDs)\n\trequire.EqualValues(t, expected, result)\n\n\tprocessesPIDs = map[string]string{\n\t\t\"process\":  \"12345, 99999\",\n\t\t\"process2\": \"44444, 11111\",\n\t}\n\texpectedPrefix := \"--mon-pid=\"\n\texpectedSubstring := \"all:[12345, 99999];mbt:[12345, 99999];\"\n\texpectedSubstring2 := \"all:[44444, 11111];mbt:[44444, 11111];\"\n\tresult = createArgProcess(processesPIDs)\n\trequire.Contains(t, result, expectedPrefix)\n\trequire.Contains(t, result, expectedSubstring)\n\trequire.Contains(t, result, expectedSubstring2)\n}\n\nfunc TestCreateArgsCores(t *testing.T) {\n\tcores := []string{\"1,2,3\"}\n\texpected := \"--mon-core=all:[1,2,3];mbt:[1,2,3];\"\n\tresult := createArgCores(cores)\n\trequire.EqualValues(t, expected, result)\n\n\tcores = []string{\"1,2,3\", \"4,5,6\"}\n\texpectedPrefix := \"--mon-core=\"\n\texpectedSubstring := \"all:[1,2,3];mbt:[1,2,3];\"\n\texpectedSubstring2 := \"all:[4,5,6];mbt:[4,5,6];\"\n\tresult = createArgCores(cores)\n\trequire.Contains(t, result, expectedPrefix)\n\trequire.Contains(t, result, expectedSubstring)\n\trequire.Contains(t, result, expectedSubstring2)\n}\n\nfunc TestParseCoresConfig(t *testing.T) {\n\tt.Run(\"empty slice\", func(t *testing.T) {\n\t\tvar configCores []string\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, result)\n\t})\n\n\tt.Run(\"empty string in slice\", func(t *testing.T) {\n\t\tconfigCores := []string{\"\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result)\n\t})\n\n\tt.Run(\"not correct string\", func(t *testing.T) {\n\t\tconfigCores := []string{\"wrong string\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result)\n\t})\n\n\tt.Run(\"not correct string\", func(t *testing.T) {\n\t\tconfigCores := []string{\"1,2\", \"wasd:#$!;\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result)\n\t})\n\n\tt.Run(\"not correct string\", func(t *testing.T) {\n\t\tconfigCores := []string{\"1,2,2\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result)\n\t})\n\n\tt.Run(\"coma separated cores - positive\", func(t *testing.T) {\n\t\tconfigCores := []string{\"0,1,2,3,4,5\"}\n\t\texpected := []string{\"0,1,2,3,4,5\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"0,1,2\", \"3,4,5\"}\n\t\texpected = []string{\"0,1,2\", \"3,4,5\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"0,4,1\", \"2,3,5\", \"9\"}\n\t\texpected = []string{\"0,4,1\", \"2,3,5\", \"9\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\t})\n\n\tt.Run(\"coma separated cores - negative\", func(t *testing.T) {\n\t\t// cannot monitor same cores in different groups\n\t\tconfigCores := []string{\"0,1,2\", \"2\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\tconfigCores = []string{\"0,1,2\", \"2,3,4\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\tconfigCores = []string{\"0,-1,2\", \"2,3,4\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\t})\n\n\tt.Run(\"dash separated cores - positive\", func(t *testing.T) {\n\t\tconfigCores := []string{\"0-5\"}\n\t\texpected := []string{\"0,1,2,3,4,5\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"0-5\", \"7-10\"}\n\t\texpected = []string{\"0,1,2,3,4,5\", \"7,8,9,10\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"5-5\"}\n\t\texpected = []string{\"5\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\t})\n\n\tt.Run(\"dash separated cores - negative\", func(t *testing.T) {\n\t\t// cannot monitor same cores in different groups\n\t\tconfigCores := []string{\"0-5\", \"2-7\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\t// more than two values in range\n\t\tconfigCores = []string{\"0-5-10\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\t// first value cannot be higher than second\n\t\tconfigCores = []string{\"12-5\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\tconfigCores = []string{\"0-\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\t})\n\n\tt.Run(\"mixed separator - positive\", func(t *testing.T) {\n\t\tconfigCores := []string{\"0-5,6,7\"}\n\t\texpected := []string{\"0,1,2,3,4,5,6,7\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"0-5,6,7\", \"8,9,10\"}\n\t\texpected = []string{\"0,1,2,3,4,5,6,7\", \"8,9,10\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\n\t\tconfigCores = []string{\"0-7\", \"8-10\"}\n\t\texpected = []string{\"0,1,2,3,4,5,6,7\", \"8,9,10\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, expected, result)\n\t})\n\n\tt.Run(\"mixed separator - negative\", func(t *testing.T) {\n\t\t// cannot monitor same cores in different groups\n\t\tconfigCores := []string{\"0-5,\", \"2-7\"}\n\t\tresult, err := parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\t// cores cannot be duplicated\n\t\tconfigCores = []string{\"0-5,5\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\n\t\t// more than two values in range\n\t\tconfigCores = []string{\"0-5-6,9\"}\n\t\tresult, err = parseCoresConfig(configCores)\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, result)\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/intel_rdt_windows.go",
    "content": "//go:build windows\n\npackage intel_rdt\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IntelRDT struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*IntelRDT) SampleConfig() string { return sampleConfig }\n\nfunc (i *IntelRDT) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*IntelRDT) Start(_ telegraf.Accumulator) error { return nil }\n\nfunc (*IntelRDT) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc (*IntelRDT) Stop() {}\n\nfunc init() {\n\tinputs.Add(\"intel_rdt\", func() telegraf.Input {\n\t\treturn &IntelRDT{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/processes.go",
    "content": "//go:build !windows\n\npackage intel_rdt\n\nimport \"github.com/prometheus/procfs\"\n\ntype processesHandler interface {\n\tgetAllProcesses() ([]process, error)\n}\n\ntype process struct {\n\tName string\n\tPID  int\n}\n\ntype processManager struct{}\n\nfunc newProcessor() processesHandler {\n\treturn &processManager{}\n}\n\nfunc (*processManager) getAllProcesses() ([]process, error) {\n\tallProcesses, err := procfs.AllProcs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprocesses := make([]process, 0, len(allProcesses))\n\tfor _, proc := range allProcesses {\n\t\tprocComm, err := proc.Comm()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tnewProcess := process{\n\t\t\tPID:  proc.PID,\n\t\t\tName: procComm,\n\t\t}\n\t\tprocesses = append(processes, newProcess)\n\t}\n\treturn processes, nil\n}\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/publisher.go",
    "content": "//go:build !windows\n\npackage intel_rdt\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype parsedCoresMeasurement struct {\n\tcores  string\n\tvalues []float64\n\ttime   time.Time\n}\n\ntype parsedProcessMeasurement struct {\n\tprocess string\n\tcores   string\n\tvalues  []float64\n\ttime    time.Time\n}\n\n// publisher for publish new RDT metrics to telegraf accumulator\ntype publisher struct {\n\tacc               telegraf.Accumulator\n\tlog               telegraf.Logger\n\tshortenedMetrics  bool\n\tbufferChanProcess chan processMeasurement\n\tbufferChanCores   chan string\n\terrChan           chan error\n}\n\nfunc newPublisher(acc telegraf.Accumulator, log telegraf.Logger, shortenedMetrics bool) publisher {\n\treturn publisher{\n\t\tacc:               acc,\n\t\tlog:               log,\n\t\tshortenedMetrics:  shortenedMetrics,\n\t\tbufferChanProcess: make(chan processMeasurement),\n\t\tbufferChanCores:   make(chan string),\n\t\terrChan:           make(chan error),\n\t}\n}\n\nfunc (p *publisher) publish(ctx context.Context) {\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase newMeasurements := <-p.bufferChanCores:\n\t\t\t\tp.publishCores(newMeasurements)\n\t\t\tcase newMeasurements := <-p.bufferChanProcess:\n\t\t\t\tp.publishProcess(newMeasurements)\n\t\t\tcase err := <-p.errChan:\n\t\t\t\tp.log.Error(err)\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (p *publisher) publishCores(measurement string) {\n\tparsedCoresMeasurement, err := parseCoresMeasurement(measurement)\n\tif err != nil {\n\t\tp.errChan <- err\n\t}\n\tp.addToAccumulatorCores(parsedCoresMeasurement)\n}\n\nfunc (p *publisher) publishProcess(measurement processMeasurement) {\n\tparsedProcessMeasurement, err := parseProcessesMeasurement(measurement)\n\tif err != nil {\n\t\tp.errChan <- err\n\t}\n\tp.addToAccumulatorProcesses(parsedProcessMeasurement)\n}\n\nfunc parseCoresMeasurement(measurements string) (parsedCoresMeasurement, error) {\n\tsplitCSV, err := splitCSVLineIntoValues(measurements)\n\tif err != nil {\n\t\treturn parsedCoresMeasurement{}, err\n\t}\n\ttimestamp, err := parseTime(splitCSV.timeValue)\n\tif err != nil {\n\t\treturn parsedCoresMeasurement{}, err\n\t}\n\t// change string slice to one string and separate it by coma\n\tcoresString := strings.Join(splitCSV.coreOrPIDsValues, \",\")\n\t// trim unwanted quotes\n\tcoresString = strings.Trim(coresString, \"\\\"\")\n\n\tvalues := make([]float64, 0, len(splitCSV.metricsValues))\n\tfor _, metric := range splitCSV.metricsValues {\n\t\tparsedValue, err := parseFloat(metric)\n\t\tif err != nil {\n\t\t\treturn parsedCoresMeasurement{}, err\n\t\t}\n\t\tvalues = append(values, parsedValue)\n\t}\n\treturn parsedCoresMeasurement{coresString, values, timestamp}, nil\n}\n\nfunc (p *publisher) addToAccumulatorCores(measurement parsedCoresMeasurement) {\n\tfor i, value := range measurement.values {\n\t\tif p.shortenedMetrics {\n\t\t\t// 0: \"IPC\"\n\t\t\t// 1: \"LLC_Misses\"\n\t\t\tif i == 0 || i == 1 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\ttags := make(map[string]string, 2)\n\t\tfields := make(map[string]interface{}, 1)\n\n\t\ttags[\"cores\"] = measurement.cores\n\t\ttags[\"name\"] = pqosMetricOrder[i]\n\t\tfields[\"value\"] = value\n\n\t\tp.acc.AddFields(\"rdt_metric\", fields, tags, measurement.time)\n\t}\n}\n\nfunc parseProcessesMeasurement(measurement processMeasurement) (parsedProcessMeasurement, error) {\n\tsplitCSV, err := splitCSVLineIntoValues(measurement.measurement)\n\tif err != nil {\n\t\treturn parsedProcessMeasurement{}, err\n\t}\n\tpids, err := findPIDsInMeasurement(measurement.measurement)\n\tif err != nil {\n\t\treturn parsedProcessMeasurement{}, err\n\t}\n\tlenOfPIDs := len(strings.Split(pids, \",\"))\n\tif lenOfPIDs > len(splitCSV.coreOrPIDsValues) {\n\t\treturn parsedProcessMeasurement{}, errors.New(\"detected more pids (quoted) than actual number of pids in csv line\")\n\t}\n\ttimestamp, err := parseTime(splitCSV.timeValue)\n\tif err != nil {\n\t\treturn parsedProcessMeasurement{}, err\n\t}\n\tactualProcess := measurement.name\n\tcores := strings.Trim(strings.Join(splitCSV.coreOrPIDsValues[lenOfPIDs:], \",\"), `\"`)\n\n\tvalues := make([]float64, 0, len(splitCSV.metricsValues))\n\tfor _, metric := range splitCSV.metricsValues {\n\t\tparsedValue, err := parseFloat(metric)\n\t\tif err != nil {\n\t\t\treturn parsedProcessMeasurement{}, err\n\t\t}\n\t\tvalues = append(values, parsedValue)\n\t}\n\treturn parsedProcessMeasurement{actualProcess, cores, values, timestamp}, nil\n}\n\nfunc (p *publisher) addToAccumulatorProcesses(measurement parsedProcessMeasurement) {\n\tfor i, value := range measurement.values {\n\t\tif p.shortenedMetrics {\n\t\t\t// 0: \"IPC\"\n\t\t\t// 1: \"LLC_Misses\"\n\t\t\tif i == 0 || i == 1 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\ttags := make(map[string]string, 3)\n\t\tfields := make(map[string]interface{}, 1)\n\n\t\ttags[\"process\"] = measurement.process\n\t\ttags[\"cores\"] = measurement.cores\n\t\ttags[\"name\"] = pqosMetricOrder[i]\n\t\tfields[\"value\"] = value\n\n\t\tp.acc.AddFields(\"rdt_metric\", fields, tags, measurement.time)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/publisher_test.go",
    "content": "//go:build !windows\n\npackage intel_rdt\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar metricsValues = map[string]float64{\n\t\"IPC\":        0.5,\n\t\"LLC_Misses\": 61650,\n\t\"LLC\":        1632,\n\t\"MBL\":        0.6,\n\t\"MBR\":        0.9,\n\t\"MBT\":        1.9,\n}\n\nfunc TestParseCoresMeasurement(t *testing.T) {\n\ttimestamp := \"2020-08-12 13:34:36\"\n\tcores := \"\\\"37,44\\\"\"\n\n\tt.Run(\"valid measurement string\", func(t *testing.T) {\n\t\tmeasurement := fmt.Sprintf(\"%s,%s,%f,%f,%f,%f,%f,%f\",\n\t\t\ttimestamp,\n\t\t\tcores,\n\t\t\tmetricsValues[\"IPC\"],\n\t\t\tmetricsValues[\"LLC_Misses\"],\n\t\t\tmetricsValues[\"LLC\"],\n\t\t\tmetricsValues[\"MBL\"],\n\t\t\tmetricsValues[\"MBR\"],\n\t\t\tmetricsValues[\"MBT\"])\n\n\t\texpectedCores := \"37,44\"\n\t\texpectedTimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tresult, err := parseCoresMeasurement(measurement)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expectedCores, result.cores)\n\t\trequire.Equal(t, expectedTimestamp, result.time)\n\t\trequire.InDelta(t, result.values[0], metricsValues[\"IPC\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[1], metricsValues[\"LLC_Misses\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[2], metricsValues[\"LLC\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[3], metricsValues[\"MBL\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[4], metricsValues[\"MBR\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[5], metricsValues[\"MBT\"], testutil.DefaultDelta)\n\t})\n\tt.Run(\"not valid measurement string\", func(t *testing.T) {\n\t\tmeasurement := \"not, valid, measurement\"\n\n\t\tresult, err := parseCoresMeasurement(measurement)\n\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result.cores)\n\t\trequire.Nil(t, result.values)\n\t\trequire.Equal(t, time.Time{}, result.time)\n\t})\n\tt.Run(\"not valid values string\", func(t *testing.T) {\n\t\tmeasurement := fmt.Sprintf(\"%s,%s,%s,%s,%f,%f,%f,%f\",\n\t\t\ttimestamp,\n\t\t\tcores,\n\t\t\t\"%d\",\n\t\t\t\"in\",\n\t\t\tmetricsValues[\"LLC\"],\n\t\t\tmetricsValues[\"MBL\"],\n\t\t\tmetricsValues[\"MBR\"],\n\t\t\tmetricsValues[\"MBT\"])\n\n\t\tresult, err := parseCoresMeasurement(measurement)\n\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result.cores)\n\t\trequire.Nil(t, result.values)\n\t\trequire.Equal(t, time.Time{}, result.time)\n\t})\n\tt.Run(\"not valid timestamp format\", func(t *testing.T) {\n\t\tinvalidTimestamp := \"2020-08-12-21 13:34:\"\n\t\tmeasurement := fmt.Sprintf(\"%s,%s,%f,%f,%f,%f,%f,%f\",\n\t\t\tinvalidTimestamp,\n\t\t\tcores,\n\t\t\tmetricsValues[\"IPC\"],\n\t\t\tmetricsValues[\"LLC_Misses\"],\n\t\t\tmetricsValues[\"LLC\"],\n\t\t\tmetricsValues[\"MBL\"],\n\t\t\tmetricsValues[\"MBR\"],\n\t\t\tmetricsValues[\"MBT\"])\n\n\t\tresult, err := parseCoresMeasurement(measurement)\n\n\t\trequire.Error(t, err)\n\t\trequire.Empty(t, result.cores)\n\t\trequire.Nil(t, result.values)\n\t\trequire.Equal(t, time.Time{}, result.time)\n\t})\n}\n\nfunc TestParseProcessesMeasurement(t *testing.T) {\n\ttimestamp := \"2020-08-12 13:34:36\"\n\tcores := \"\\\"37,44\\\"\"\n\tpids := \"\\\"12345,9999\\\"\"\n\tprocessName := \"process_name\"\n\n\tt.Run(\"valid measurement string\", func(t *testing.T) {\n\t\tmeasurement := fmt.Sprintf(\"%s,%s,%s,%f,%f,%f,%f,%f,%f\",\n\t\t\ttimestamp,\n\t\t\tpids,\n\t\t\tcores,\n\t\t\tmetricsValues[\"IPC\"],\n\t\t\tmetricsValues[\"LLC_Misses\"],\n\t\t\tmetricsValues[\"LLC\"],\n\t\t\tmetricsValues[\"MBL\"],\n\t\t\tmetricsValues[\"MBR\"],\n\t\t\tmetricsValues[\"MBT\"])\n\n\t\texpectedCores := \"37,44\"\n\t\texpectedTimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tnewMeasurement := processMeasurement{\n\t\t\tname:        processName,\n\t\t\tmeasurement: measurement,\n\t\t}\n\t\tresult, err := parseProcessesMeasurement(newMeasurement)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, processName, result.process)\n\t\trequire.Equal(t, expectedCores, result.cores)\n\t\trequire.Equal(t, expectedTimestamp, result.time)\n\t\trequire.InDelta(t, result.values[0], metricsValues[\"IPC\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[1], metricsValues[\"LLC_Misses\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[2], metricsValues[\"LLC\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[3], metricsValues[\"MBL\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[4], metricsValues[\"MBR\"], testutil.DefaultDelta)\n\t\trequire.InDelta(t, result.values[5], metricsValues[\"MBT\"], testutil.DefaultDelta)\n\t})\n\n\tinvalidTimestamp := \"2020-20-20-31\"\n\tnegativeTests := []struct {\n\t\tname        string\n\t\tmeasurement string\n\t}{{\n\t\tname:        \"not valid measurement string\",\n\t\tmeasurement: \"invalid,measurement,format\",\n\t}, {\n\t\tname: \"not valid timestamp format\",\n\t\tmeasurement: fmt.Sprintf(\"%s,%s,%s,%f,%f,%f,%f,%f,%f\",\n\t\t\tinvalidTimestamp,\n\t\t\tpids,\n\t\t\tcores,\n\t\t\tmetricsValues[\"IPC\"],\n\t\t\tmetricsValues[\"LLC_Misses\"],\n\t\t\tmetricsValues[\"LLC\"],\n\t\t\tmetricsValues[\"MBL\"],\n\t\t\tmetricsValues[\"MBR\"],\n\t\t\tmetricsValues[\"MBT\"]),\n\t},\n\t\t{\n\t\t\tname: \"not valid values string\",\n\t\t\tmeasurement: fmt.Sprintf(\"%s,%s,%s,%s,%s,%f,%f,%f,%f\",\n\t\t\t\ttimestamp,\n\t\t\t\tpids,\n\t\t\t\tcores,\n\t\t\t\t\"1##\",\n\t\t\t\t\"da\",\n\t\t\t\tmetricsValues[\"LLC\"],\n\t\t\t\tmetricsValues[\"MBL\"],\n\t\t\t\tmetricsValues[\"MBR\"],\n\t\t\t\tmetricsValues[\"MBT\"]),\n\t\t},\n\t\t{\n\t\t\tname:        \"not valid csv line with quotes\",\n\t\t\tmeasurement: \"0000-08-02 0:00:00,,\\\",,,,,,,,,,,,,,,,,,,,,,,,\\\",,\",\n\t\t},\n\t}\n\n\tfor _, test := range negativeTests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tnewMeasurement := processMeasurement{\n\t\t\t\tname:        processName,\n\t\t\t\tmeasurement: test.measurement,\n\t\t\t}\n\t\t\tresult, err := parseProcessesMeasurement(newMeasurement)\n\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Empty(t, result.process)\n\t\t\trequire.Empty(t, result.cores)\n\t\t\trequire.Nil(t, result.values)\n\t\t\trequire.Equal(t, time.Time{}, result.time)\n\t\t})\n\t}\n}\n\nfunc TestAddToAccumulatorCores(t *testing.T) {\n\tt.Run(\"shortened false\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tpublisher := publisher{acc: &acc}\n\n\t\tcores := \"1,2,3\"\n\t\tmetricsValues := []float64{1, 2, 3, 4, 5, 6}\n\t\ttimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tpublisher.addToAccumulatorCores(parsedCoresMeasurement{cores, metricsValues, timestamp})\n\n\t\tfor _, test := range testCoreMetrics {\n\t\t\tacc.AssertContainsTaggedFields(t, \"rdt_metric\", test.fields, test.tags)\n\t\t}\n\t})\n\tt.Run(\"shortened true\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tpublisher := publisher{acc: &acc, shortenedMetrics: true}\n\n\t\tcores := \"1,2,3\"\n\t\tmetricsValues := []float64{1, 2, 3, 4, 5, 6}\n\t\ttimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tpublisher.addToAccumulatorCores(parsedCoresMeasurement{cores, metricsValues, timestamp})\n\n\t\tfor _, test := range testCoreMetricsShortened {\n\t\t\tacc.AssertDoesNotContainsTaggedFields(t, \"rdt_metric\", test.fields, test.tags)\n\t\t}\n\t})\n}\n\nfunc TestAddToAccumulatorProcesses(t *testing.T) {\n\tt.Run(\"shortened false\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tpublisher := publisher{acc: &acc}\n\n\t\tprocess := \"process_name\"\n\t\tcores := \"1,2,3\"\n\t\tmetricsValues := []float64{1, 2, 3, 4, 5, 6}\n\t\ttimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tpublisher.addToAccumulatorProcesses(parsedProcessMeasurement{process, cores, metricsValues, timestamp})\n\n\t\tfor _, test := range testCoreProcesses {\n\t\t\tacc.AssertContainsTaggedFields(t, \"rdt_metric\", test.fields, test.tags)\n\t\t}\n\t})\n\tt.Run(\"shortened true\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tpublisher := publisher{acc: &acc, shortenedMetrics: true}\n\n\t\tprocess := \"process_name\"\n\t\tcores := \"1,2,3\"\n\t\tmetricsValues := []float64{1, 2, 3, 4, 5, 6}\n\t\ttimestamp := time.Date(2020, 8, 12, 13, 34, 36, 0, time.Local)\n\n\t\tpublisher.addToAccumulatorProcesses(parsedProcessMeasurement{process, cores, metricsValues, timestamp})\n\n\t\tfor _, test := range testCoreProcessesShortened {\n\t\t\tacc.AssertDoesNotContainsTaggedFields(t, \"rdt_metric\", test.fields, test.tags)\n\t\t}\n\t})\n}\n\nvar (\n\ttestCoreMetrics = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"IPC\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"LLC_Misses\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(3),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"LLC\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(4),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"MBL\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(5),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"MBR\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(6),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"MBT\",\n\t\t\t},\n\t\t},\n\t}\n\ttestCoreMetricsShortened = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"IPC\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\": \"1,2,3\",\n\t\t\t\t\"name\":  \"LLC_Misses\",\n\t\t\t},\n\t\t},\n\t}\n\ttestCoreProcesses = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"IPC\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"LLC_Misses\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(3),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"LLC\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(4),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"MBL\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(5),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"MBR\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(6),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"MBT\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t}\n\ttestCoreProcessesShortened = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"IPC\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"cores\":   \"1,2,3\",\n\t\t\t\t\"name\":    \"LLC_Misses\",\n\t\t\t\t\"process\": \"process_name\",\n\t\t\t},\n\t\t},\n\t}\n)\n"
  },
  {
    "path": "plugins/inputs/intel_rdt/sample.conf",
    "content": "# Read Intel RDT metrics\n# This plugin ONLY supports non-Windows\n[[inputs.intel_rdt]]\n  ## Optionally set sampling interval to Nx100ms.\n  ## This value is propagated to pqos tool. Interval format is defined by pqos itself.\n  ## If not provided or provided 0, will be set to 10 = 10x100ms = 1s.\n  # sampling_interval = \"10\"\n\n  ## Optionally specify the path to pqos executable.\n  ## If not provided, auto discovery will be performed.\n  # pqos_path = \"/usr/local/bin/pqos\"\n\n  ## Optionally specify if IPC and LLC_Misses metrics shouldn't be propagated.\n  ## If not provided, default value is false.\n  # shortened_metrics = false\n\n  ## Specify the list of groups of CPU core(s) to be provided as pqos input.\n  ## Mandatory if processes aren't set and forbidden if processes are specified.\n  ## e.g. [\"0-3\", \"4,5,6\"] or [\"1-3,4\"]\n  # cores = [\"0-3\"]\n\n  ## Specify the list of processes for which Metrics will be collected.\n  ## Mandatory if cores aren't set and forbidden if cores are specified.\n  ## e.g. [\"qemu\", \"pmd\"]\n  # processes = [\"process\"]\n\n  ## Specify if the pqos process should be called with sudo.\n  ## Mandatory if the telegraf process does not run as root.\n  # use_sudo = false\n"
  },
  {
    "path": "plugins/inputs/internal/README.md",
    "content": "# Telegraf Internal Input Plugin\n\nThis plugin collects metrics about the telegraf agent and its plugins.\n\n> [!NOTE]\n> Some metrics are aggregates across all instances of a plugin type.\n\n⭐ Telegraf v1.2.0\n🏷️ applications\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect statistics about itself\n[[inputs.internal]]\n  ## If true, collect telegraf memory stats.\n  # collect_memstats = true\n\n  ## If true, collect metrics from Go's runtime.metrics. For a full list see:\n  ##   https://pkg.go.dev/runtime/metrics\n  # collect_gostats = false\n\n  ## Collect statistics per plugin instance and not per plugin type\n  # per_instance = false\n```\n\n## Metrics\n\nmemstats are collected using the [Go runtime framework][memstats]\n\n- internal_memstats\n  - alloc_bytes\n  - frees\n  - heap_alloc_bytes\n  - heap_idle_bytes\n  - heap_in_use_bytes\n  - heap_objects_bytes\n  - heap_released_bytes\n  - heap_sys_bytes\n  - mallocs\n  - num_gc\n  - pointer_lookups\n  - sys_bytes\n  - total_alloc_bytes\n\nagent stats collect aggregate stats on all telegraf plugins.\n\n- internal_agent\n  - gather_errors\n  - gather_timeouts\n  - metrics_dropped\n  - metrics_gathered\n  - metrics_written\n\ninternal_gather stats collect aggregate stats on all input plugins\nthat are of the same input type. They are tagged with `input=<plugin_name>`\n`version=<telegraf_version>` and `go_version=<go_build_version>`.\n\n- internal_gather\n  - gather_time_ns\n  - metrics_gathered\n  - gather_timeouts\n\ninternal_write stats collect aggregate stats on all output plugins\nthat are of the same input type. They are tagged with `output=<plugin_name>`\nand `version=<telegraf_version>`.\n\n- internal_write\n  - buffer_limit\n  - buffer_size\n  - metrics_added\n  - metrics_written\n  - metrics_dropped\n  - metrics_filtered\n  - write_time_ns\n\ninternal_<plugin_name> are metrics which are defined on a per-plugin basis, and\nusually contain tags which differentiate each instance of a particular type of\nplugin and `version=<telegraf_version>`.\n\n- internal_<plugin_name>\n  - individual plugin-specific fields, such as requests counts.\n\nAll measurements for specific plugins are tagged with information relevant\nto each particular plugin and with `version=<telegraf_version>`.\n\n[memstats]: https://golang.org/pkg/runtime/#MemStats\n\n## Example Output\n\n```text\ninternal_memstats,host=tyrion alloc_bytes=4457408i,sys_bytes=10590456i,pointer_lookups=7i,mallocs=17642i,frees=7473i,heap_sys_bytes=6848512i,heap_idle_bytes=1368064i,heap_in_use_bytes=5480448i,heap_released_bytes=0i,total_alloc_bytes=6875560i,heap_alloc_bytes=4457408i,heap_objects_bytes=10169i,num_gc=2i 1480682800000000000\ninternal_agent,host=tyrion,go_version=1.12.7,version=1.99.0 metrics_written=18i,metrics_dropped=0i,metrics_gathered=19i,gather_errors=0i,gather_timeouts=0i 1480682800000000000\ninternal_write,output=file,host=tyrion,version=1.99.0 buffer_limit=10000i,write_time_ns=636609i,metrics_added=18i,metrics_written=18i,buffer_size=0i 1480682800000000000\ninternal_gather,input=internal,host=tyrion,version=1.99.0 metrics_gathered=19i,gather_time_ns=442114i,gather_timeouts=0i 1480682800000000000\ninternal_gather,input=http_listener,host=tyrion,version=1.99.0 metrics_gathered=0i,gather_time_ns=167285i,gather_timeouts=0i 1480682800000000000\ninternal_http_listener,address=:8186,host=tyrion,version=1.99.0 queries_received=0i,writes_received=0i,requests_received=0i,buffers_created=0i,requests_served=0i,pings_received=0i,bytes_received=0i,not_founds_served=0i,pings_served=0i,queries_served=0i,writes_served=0i 1480682800000000000\ninternal_mqtt_consumer,host=tyrion,version=1.99.0 messages_received=622i,payload_size=37942i 1657282270000000000\n```\n"
  },
  {
    "path": "plugins/inputs/internal/internal.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage internal\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"runtime/metrics\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\tinter \"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Converts /cpu/classes/gc/mark/assist:cpu-seconds to cpu_classes_gc_mark_assist_cpu_seconds\nvar replacer = strings.NewReplacer(\"/\", \"_\", \":\", \"_\", \"-\", \"_\")\n\ntype Internal struct {\n\tCollectMemstats bool `toml:\"collect_memstats\"`\n\tCollectGostats  bool `toml:\"collect_gostats\"`\n\tPerInstance     bool `toml:\"per_instance\"`\n}\n\nfunc (*Internal) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Internal) Gather(acc telegraf.Accumulator) error {\n\tif s.PerInstance {\n\t\tcollectIndividualPluginStat(acc)\n\t} else {\n\t\tcollectAccumulatedPluginStat(acc)\n\t}\n\n\tif s.CollectMemstats {\n\t\tcollectMemStat(acc)\n\t}\n\n\tif s.CollectGostats {\n\t\tcollectGoStat(acc)\n\t}\n\n\treturn nil\n}\n\nfunc collectIndividualPluginStat(acc telegraf.Accumulator) {\n\tfor _, m := range selfstat.Metrics() {\n\t\tif m.Name() == \"internal_agent\" {\n\t\t\tm.AddTag(\"go_version\", strings.TrimPrefix(runtime.Version(), \"go\"))\n\t\t}\n\t\tm.AddTag(\"version\", inter.Version)\n\t\tacc.AddFields(m.Name(), m.Fields(), m.Tags(), m.Time())\n\t}\n}\n\nfunc collectAccumulatedPluginStat(acc telegraf.Accumulator) {\n\taccumulated := make(map[uint64]telegraf.Metric)\n\tfor _, m := range selfstat.Metrics() {\n\t\tif m.Name() == \"internal_agent\" {\n\t\t\tm.AddTag(\"go_version\", strings.TrimPrefix(runtime.Version(), \"go\"))\n\t\t}\n\t\tm.AddTag(\"version\", inter.Version)\n\t\tkey := m.HashIDWithFieldsFiltered([]string{\"_id\"}, nil)\n\t\tam, found := accumulated[key]\n\t\tif !found {\n\t\t\taccumulated[key] = m.Copy()\n\t\t\taccumulated[key].RemoveTag(\"_id\")\n\t\t\tcontinue\n\t\t}\n\t\tfor _, f := range m.FieldList() {\n\t\t\tvar av int64\n\t\t\tif af, found := am.GetField(f.Key); found {\n\t\t\t\tav = af.(int64)\n\t\t\t}\n\t\t\tam.AddField(f.Key, av+f.Value.(int64))\n\t\t}\n\t}\n\n\tfor _, m := range accumulated {\n\t\tacc.AddMetric(m)\n\t}\n}\n\nfunc collectMemStat(acc telegraf.Accumulator) {\n\tm := &runtime.MemStats{}\n\truntime.ReadMemStats(m)\n\tfields := map[string]any{\n\t\t\"alloc_bytes\":       m.Alloc,      // bytes allocated and not yet freed\n\t\t\"total_alloc_bytes\": m.TotalAlloc, // bytes allocated (even if freed)\n\t\t\"sys_bytes\":         m.Sys,        // bytes obtained from system (sum of XxxSys below)\n\t\t\"pointer_lookups\":   m.Lookups,    // number of pointer lookups\n\t\t\"mallocs\":           m.Mallocs,    // number of mallocs\n\t\t\"frees\":             m.Frees,      // number of frees\n\n\t\t// Main allocation heap statistics.\n\t\t\"heap_alloc_bytes\":    m.HeapAlloc,    // bytes allocated and not yet freed (same as Alloc above)\n\t\t\"heap_sys_bytes\":      m.HeapSys,      // bytes obtained from system\n\t\t\"heap_idle_bytes\":     m.HeapIdle,     // bytes in idle spans\n\t\t\"heap_in_use_bytes\":   m.HeapInuse,    // bytes in non-idle span\n\t\t\"heap_released_bytes\": m.HeapReleased, // bytes released to the OS\n\t\t\"heap_objects\":        m.HeapObjects,  // total number of allocated objects\n\t\t\"num_gc\":              m.NumGC,\n\t}\n\tacc.AddFields(\"internal_memstats\", fields, make(map[string]string))\n}\n\nfunc collectGoStat(acc telegraf.Accumulator) {\n\tdescs := metrics.All()\n\tsamples := make([]metrics.Sample, len(descs))\n\tfor i := range samples {\n\t\tsamples[i].Name = descs[i].Name\n\t}\n\tmetrics.Read(samples)\n\n\tfields := make(map[string]any, len(samples))\n\tfor _, sample := range samples {\n\t\tname := sanitizeName(sample.Name)\n\n\t\tswitch sample.Value.Kind() {\n\t\tcase metrics.KindUint64:\n\t\t\tfields[name] = sample.Value.Uint64()\n\t\tcase metrics.KindFloat64:\n\t\t\tfields[name] = sample.Value.Float64()\n\t\tcase metrics.KindFloat64Histogram:\n\t\t\t// The histogram may be quite large, so let's just pull out\n\t\t\t// a crude estimate for the median for the sake of this example.\n\t\t\tfields[name] = medianBucket(sample.Value.Float64Histogram())\n\t\tdefault:\n\t\t\t// This may happen as new metrics get added.\n\t\t\t//\n\t\t\t// The safest thing to do here is to simply log it somewhere\n\t\t\t// as something to look into, but ignore it for now.\n\t\t\t// In the worst case, you might temporarily miss out on a new metric.\n\t\t\tfmt.Printf(\"%s: unexpected metric Kind: %v\\n\", name, sample.Value.Kind())\n\t\t}\n\t}\n\n\ttags := map[string]string{\n\t\t\"go_version\": strings.TrimPrefix(runtime.Version(), \"go\"),\n\t}\n\tacc.AddFields(\"internal_gostats\", fields, tags)\n}\n\nfunc sanitizeName(name string) string {\n\treturn replacer.Replace(strings.TrimPrefix(name, \"/\"))\n}\n\nfunc medianBucket(h *metrics.Float64Histogram) float64 {\n\ttotal := uint64(0)\n\tfor _, count := range h.Counts {\n\t\ttotal += count\n\t}\n\tthresh := total / 2\n\ttotal = 0\n\tfor i, count := range h.Counts {\n\t\ttotal += count\n\t\tif total >= thresh {\n\t\t\treturn h.Buckets[i]\n\t\t}\n\t}\n\n\t// default value in case something above did not work\n\treturn 0.0\n}\n\nfunc init() {\n\tinputs.Add(\"internal\", func() telegraf.Input {\n\t\treturn &Internal{\n\t\t\tCollectMemstats: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/internal/internal_test.go",
    "content": "package internal\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSelfPlugin(t *testing.T) {\n\ts := Internal{\n\t\tCollectMemstats: true,\n\t}\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, s.Gather(acc))\n\trequire.True(t, acc.HasMeasurement(\"internal_memstats\"))\n\n\t// test that a registered stat is incremented\n\tstat := selfstat.Register(\"mytest\", \"test\", map[string]string{\"test\": \"foo\"})\n\tdefer selfstat.Unregister(\"mytest\", \"test\", map[string]string{\"test\": \"foo\"})\n\tstat.Incr(1)\n\tstat.Incr(2)\n\trequire.NoError(t, s.Gather(acc))\n\n\tacc.AssertContainsTaggedFields(t, \"internal_mytest\",\n\t\tmap[string]interface{}{\n\t\t\t\"test\": int64(3),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test\":    \"foo\",\n\t\t\t\"version\": \"unknown\",\n\t\t},\n\t)\n\tacc.ClearMetrics()\n\n\t// test that a registered stat is set properly\n\tstat.Set(101)\n\trequire.NoError(t, s.Gather(acc))\n\tacc.AssertContainsTaggedFields(t, \"internal_mytest\",\n\t\tmap[string]interface{}{\n\t\t\t\"test\": int64(101),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test\":    \"foo\",\n\t\t\t\"version\": \"unknown\",\n\t\t},\n\t)\n\tacc.ClearMetrics()\n\n\t// test that regular and timing stats can share the same measurement, and\n\t// that timings are set properly.\n\ttiming := selfstat.RegisterTiming(\"mytest\", \"test_ns\", map[string]string{\"test\": \"foo\"})\n\tdefer selfstat.Unregister(\"mytest\", \"test_ns\", map[string]string{\"test\": \"foo\"})\n\ttiming.Incr(100)\n\ttiming.Incr(200)\n\trequire.NoError(t, s.Gather(acc))\n\tacc.AssertContainsTaggedFields(t, \"internal_mytest\",\n\t\tmap[string]interface{}{\n\t\t\t\"test\":    int64(101),\n\t\t\t\"test_ns\": int64(150),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"test\":    \"foo\",\n\t\t\t\"version\": \"unknown\",\n\t\t},\n\t)\n}\n\nfunc TestNoMemStat(t *testing.T) {\n\ts := Internal{\n\t\tCollectMemstats: false,\n\t\tCollectGostats:  false,\n\t}\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, s.Gather(acc))\n\trequire.False(t, acc.HasMeasurement(\"internal_memstats\"))\n\trequire.False(t, acc.HasMeasurement(\"internal_gostats\"))\n}\n\nfunc TestGostats(t *testing.T) {\n\ts := Internal{\n\t\tCollectMemstats: false,\n\t\tCollectGostats:  true,\n\t}\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, s.Gather(acc))\n\trequire.False(t, acc.HasMeasurement(\"internal_memstats\"))\n\trequire.True(t, acc.HasMeasurement(\"internal_gostats\"))\n\n\tvar actual *testutil.Metric\n\tfor _, m := range acc.Metrics {\n\t\tif m.Measurement == \"internal_gostats\" {\n\t\t\tactual = m\n\t\t\tbreak\n\t\t}\n\t}\n\n\trequire.NotNil(t, actual)\n\trequire.Equal(t, \"internal_gostats\", actual.Measurement)\n\trequire.Len(t, actual.Tags, 1)\n\trequire.Contains(t, actual.Tags, \"go_version\")\n\n\tfor name, value := range actual.Fields {\n\t\tswitch value.(type) {\n\t\tcase int64, uint64, float64:\n\t\tdefault:\n\t\t\trequire.Failf(t, \"Wrong type of field\", \"Field %s is of non-numeric type %T\", name, value)\n\t\t}\n\t}\n}\n\nfunc TestPerInstance(t *testing.T) {\n\t// Setup plugin statistics to gather with different plugin IDs\n\tfor i := range 3 {\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"calls\",\n\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t).Incr(int64(100 + i))\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"writes\",\n\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t).Incr(3 * int64(100+i))\n\t}\n\tdefer func() {\n\t\tfor i := range 3 {\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"calls\",\n\t\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t\t)\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"writes\",\n\t\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t\t)\n\t\t}\n\t}()\n\n\t// Setup the internal plugin to collect statistics per plugin _instance_\n\tplugin := Internal{\n\t\tPerInstance: true,\n\t}\n\n\t// Collect\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Check the resulting metrics\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"internal_mytest\",\n\t\t\tmap[string]string{\"_id\": \"id-0\", \"test\": \"foo\", \"version\": \"unknown\"},\n\t\t\tmap[string]interface{}{\"calls\": 100, \"writes\": 300},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"internal_mytest\",\n\t\t\tmap[string]string{\"_id\": \"id-1\", \"test\": \"foo\", \"version\": \"unknown\"},\n\t\t\tmap[string]interface{}{\"calls\": 101, \"writes\": 303},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"internal_mytest\",\n\t\t\tmap[string]string{\"_id\": \"id-2\", \"test\": \"foo\", \"version\": \"unknown\"},\n\t\t\tmap[string]interface{}{\"calls\": 102, \"writes\": 306},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestAccumulatedPerType(t *testing.T) {\n\t// Setup plugin statistics to gather with different plugin IDs\n\tfor i := range 2 {\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"calls\",\n\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t).Incr(int64(10 + i))\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"writes\",\n\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t).Incr(3 * int64(10+i))\n\t}\n\tfor i := range 2 {\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"calls\",\n\t\t\tmap[string]string{\"test\": \"bar\", \"_id\": \"id-\" + strconv.Itoa(10+i)},\n\t\t).Incr(int64(100 + i))\n\t\tselfstat.Register(\n\t\t\t\"mytest\",\n\t\t\t\"writes\",\n\t\t\tmap[string]string{\"test\": \"bar\", \"_id\": \"id-\" + strconv.Itoa(10+i)},\n\t\t).Incr(2 * int64(100+i))\n\t}\n\tdefer func() {\n\t\tfor i := range 2 {\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"calls\",\n\t\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t\t)\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"writes\",\n\t\t\t\tmap[string]string{\"test\": \"foo\", \"_id\": \"id-\" + strconv.Itoa(i)},\n\t\t\t)\n\t\t}\n\t\tfor i := range 2 {\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"calls\",\n\t\t\t\tmap[string]string{\"test\": \"bar\", \"_id\": \"id-\" + strconv.Itoa(10+i)},\n\t\t\t)\n\t\t\tselfstat.Unregister(\n\t\t\t\t\"mytest\",\n\t\t\t\t\"writes\",\n\t\t\t\tmap[string]string{\"test\": \"bar\", \"_id\": \"id-\" + strconv.Itoa(10+i)},\n\t\t\t)\n\t\t}\n\t}()\n\n\t// Setup the internal plugin to collect statistics per plugin _type_ not instance\n\tplugin := Internal{}\n\n\t// Collect\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Check the resulting metrics\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"internal_mytest\",\n\t\t\tmap[string]string{\"test\": \"foo\", \"version\": \"unknown\"},\n\t\t\tmap[string]interface{}{\"calls\": 21, \"writes\": 63},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"internal_mytest\",\n\t\t\tmap[string]string{\"test\": \"bar\", \"version\": \"unknown\"},\n\t\t\tmap[string]interface{}{\"calls\": 201, \"writes\": 402},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/internal/sample.conf",
    "content": "# Collect statistics about itself\n[[inputs.internal]]\n  ## If true, collect telegraf memory stats.\n  # collect_memstats = true\n\n  ## If true, collect metrics from Go's runtime.metrics. For a full list see:\n  ##   https://pkg.go.dev/runtime/metrics\n  # collect_gostats = false\n\n  ## Collect statistics per plugin instance and not per plugin type\n  # per_instance = false\n"
  },
  {
    "path": "plugins/inputs/internet_speed/README.md",
    "content": "# Internet Speed Monitor Input Plugin\n\nThis plugin collects metrics about the internet speed on the system like\ndownload/upload speed, latency etc using the [speedtest.net service][speedtest].\n\n⭐ Telegraf v1.20.0\n🏷️ network\n💻 all\n\n[speedtest]: https://www.speedtest.net/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Monitors internet speed using speedtest.net service\n[[inputs.internet_speed]]\n  ## This plugin downloads many MB of data each time it is run. As such\n  ## consider setting a higher interval for this plugin to reduce the\n  ## demand on your internet connection.\n  # interval = \"60m\"\n\n  ## Enable to reduce memory usage\n  # memory_saving_mode = false\n\n  ## Caches the closest server location\n  # cache = false\n\n  ## Number of concurrent connections\n  ## By default or set to zero, the number of CPU cores is used. Use this to\n  ## reduce the impact on system performance or to increase the connections on\n  ## faster connections to ensure the fastest speed.\n  # connections = 0\n\n  ## Test mode\n  ## By default, a single server is used for testing. This may work for most,\n  ## however, setting to \"multi\" will reach out to multiple servers in an\n  ## attempt to get closer to ideal internet speeds.\n  ## And \"multi\" will use all available servers to calculate average packet loss.\n  # test_mode = \"single\"\n\n  ## Server ID exclude filter\n  ## Allows the user to exclude or include specific server IDs received by\n  ## speedtest-go. Values in the exclude option will be skipped over. Values in\n  ## the include option are the only options that will be picked from.\n  ##\n  ## See the list of servers speedtest-go will return at:\n  ##     https://www.speedtest.net/api/js/servers?engine=js&limit=10\n  ##\n  # server_id_exclude = []\n  # server_id_include = []\n```\n\n> [!TIP]\n> On some systems, the default settings may cause speed tests to fail. If this\n> affects your system, try enabling `memory_saving_mode`, which reduces the\n> memory requirements and the runtime of the test at the cost of a reduced\n> accuracy especially for fast (>30Mb/s) connections. Check the\n> [upstream documentation][docs] for details\n\n[docs]: https://github.com/showwin/speedtest-go#memory-saving-mode\n\n## Metrics\n\nIt collects the following fields:\n\n| Name           | Field Name  | Type    | Unit       |\n|----------------|-------------|---------|------------|\n| Download Speed | download    | float64 | Mbps       |\n| Upload Speed   | upload      | float64 | Mbps       |\n| Latency        | latency     | float64 | ms         |\n| Jitter         | jitter      | float64 | ms         |\n| Packet Loss    | packet_loss | float64 | percentage |\n| Location       | location    | string  | -          |\n\nThe `packet_loss` will return -1, if packet loss not applicable.\n\nAnd the following tags:\n\n| Name      | tag name  |\n|-----------|-----------|\n| Source    | source    |\n| Server ID | server_id |\n| Test Mode | test_mode |\n\n## Example Output\n\n```text\ninternet_speed,source=speedtest02.z4internet.com:8080,server_id=54619,test_mode=single download=318.37580265897725,upload=30.444407341274385,latency=37.73174,jitter=1.99810,packet_loss=0.05377,location=\"Somewhere, TX\" 1675458921000000000\ninternet_speed,source=speedtest02.z4internet.com:8080,server_id=54619,test_mode=multi download=318.37580265897725,upload=30.444407341274385,latency=37.73174,jitter=1.99810,packet_loss=-1,location=\"Somewhere, TX\" 1675458921000000000\n```\n"
  },
  {
    "path": "plugins/inputs/internet_speed/internet_speed.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage internet_speed\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/showwin/speedtest-go/speedtest\"\n\t\"github.com/showwin/speedtest-go/speedtest/transport\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmeasurement    = \"internet_speed\"\n\ttestModeSingle = \"single\"\n\ttestModeMulti  = \"multi\"\n)\n\ntype InternetSpeed struct {\n\tServerIDInclude  []string `toml:\"server_id_include\"`\n\tServerIDExclude  []string `toml:\"server_id_exclude\"`\n\tMemorySavingMode bool     `toml:\"memory_saving_mode\"`\n\tCache            bool     `toml:\"cache\"`\n\tConnections      int      `toml:\"connections\"`\n\tTestMode         string   `toml:\"test_mode\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tserver       *speedtest.Server // The main(best) server\n\tservers      speedtest.Servers // Auxiliary servers\n\tserverFilter filter.Filter\n}\n\nfunc (*InternetSpeed) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (is *InternetSpeed) Init() error {\n\tswitch is.TestMode {\n\tcase testModeSingle, testModeMulti:\n\tcase \"\":\n\t\tis.TestMode = testModeSingle\n\tdefault:\n\t\treturn fmt.Errorf(\"unrecognized test mode: %q\", is.TestMode)\n\t}\n\n\tvar err error\n\tis.serverFilter, err = filter.NewIncludeExcludeFilterDefaults(is.ServerIDInclude, is.ServerIDExclude, true, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error compiling server ID filters: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (is *InternetSpeed) Gather(acc telegraf.Accumulator) error {\n\t// If not caching, go find the closest server each time.\n\t// We will find the best server as the main server. And\n\t// the remaining servers will be auxiliary candidates.\n\tif !is.Cache || is.server == nil {\n\t\tif err := is.findClosestServer(); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to find closest server: %w\", err)\n\t\t}\n\t}\n\n\terr := is.server.PingTest(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ping test failed: %w\", err)\n\t}\n\n\tanalyzer := speedtest.NewPacketLossAnalyzer(&speedtest.PacketLossAnalyzerOptions{\n\t\tPacketSendingInterval: time.Millisecond * 100,\n\t\tSamplingDuration:      time.Second * 15,\n\t})\n\n\tvar pLoss *transport.PLoss\n\n\tif is.TestMode == testModeMulti {\n\t\terr = is.server.MultiDownloadTestContext(context.Background(), is.servers)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"download test failed: %w\", err)\n\t\t}\n\t\terr = is.server.MultiUploadTestContext(context.Background(), is.servers)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"upload test failed: %w\", err)\n\t\t}\n\t\t// Not all servers are applicable for packet loss testing.\n\t\t// If err != nil, we skip it and just report a warning.\n\t\tpLoss, err = analyzer.RunMulti(is.servers.Hosts())\n\t\tif err != nil {\n\t\t\tis.Log.Warnf(\"packet loss test failed: %s\", err)\n\t\t}\n\t} else {\n\t\terr = is.server.DownloadTest()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"download test failed: %w\", err)\n\t\t}\n\t\terr = is.server.UploadTest()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"upload test failed: %w\", err)\n\t\t}\n\t\t// Not all servers are applicable for packet loss testing.\n\t\t// If err != nil, we skip it and just report a warning.\n\t\terr = analyzer.Run(is.server.Host, func(pl *transport.PLoss) {\n\t\t\tpLoss = pl\n\t\t})\n\t\tif err != nil {\n\t\t\tis.Log.Warnf(\"packet loss test failed: %s\", err)\n\t\t}\n\t}\n\n\tpacketLoss := -1.0\n\tif pLoss != nil {\n\t\tpacketLoss = pLoss.LossPercent()\n\t}\n\n\tfields := map[string]any{\n\t\t\"download\":    is.server.DLSpeed.Mbps(),\n\t\t\"upload\":      is.server.ULSpeed.Mbps(),\n\t\t\"latency\":     timeDurationMillisecondToFloat64(is.server.Latency),\n\t\t\"jitter\":      timeDurationMillisecondToFloat64(is.server.Jitter),\n\t\t\"packet_loss\": packetLoss,\n\t\t\"location\":    is.server.Name,\n\t}\n\ttags := map[string]string{\n\t\t\"server_id\": is.server.ID,\n\t\t\"source\":    is.server.Host,\n\t\t\"test_mode\": is.TestMode,\n\t}\n\t// Recycle the history of each test to prevent data backlog.\n\tis.server.Context.Reset()\n\tacc.AddFields(measurement, fields, tags)\n\treturn nil\n}\n\nfunc (is *InternetSpeed) findClosestServer() error {\n\tproto := speedtest.HTTP\n\tif os.Getegid() <= 0 {\n\t\tproto = speedtest.ICMP\n\t}\n\n\tclient := speedtest.New(speedtest.WithUserConfig(&speedtest.UserConfig{\n\t\tUserAgent:  internal.ProductToken(),\n\t\tPingMode:   proto,\n\t\tSavingMode: is.MemorySavingMode,\n\t}))\n\tif is.Connections > 0 {\n\t\tclient.SetNThread(is.Connections)\n\t}\n\n\tvar err error\n\tis.servers, err = client.FetchServers()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetching server list failed: %w\", err)\n\t}\n\n\tif len(is.servers) < 1 {\n\t\treturn errors.New(\"no servers found\")\n\t}\n\n\treturn is.selectServer()\n}\n\nfunc (is *InternetSpeed) selectServer() error {\n\t// Select the server with the lowest latency matching the filter.\n\t// If no server has latency info, use the first match (closest by distance).\n\tvar minLatency int64 = math.MaxInt64\n\tselectIndex := -1\n\tfor index, server := range is.servers {\n\t\tif !is.serverFilter.Match(server.ID) {\n\t\t\tcontinue\n\t\t}\n\t\tif selectIndex == -1 {\n\t\t\t// Select the first server we found and store the latency if it is valid\n\t\t\tselectIndex = index\n\t\t\tif server.Latency > 0 {\n\t\t\t\tminLatency = server.Latency.Milliseconds()\n\t\t\t}\n\t\t} else if server.Latency > 0 && server.Latency.Milliseconds() < minLatency {\n\t\t\t// Select the server if it has a lower latency than the previous one\n\t\t\tselectIndex = index\n\t\t\tminLatency = server.Latency.Milliseconds()\n\t\t}\n\t}\n\n\tif selectIndex == -1 {\n\t\treturn errors.New(\"no server set: filter excluded all servers or no available server found\")\n\t}\n\n\tis.server = is.servers[selectIndex]\n\tis.Log.Debugf(\"using server %s in %s (%s)\\n\", is.server.ID, is.server.Name, is.server.Host)\n\treturn nil\n}\n\nfunc timeDurationMillisecondToFloat64(d time.Duration) float64 {\n\treturn float64(d) / float64(time.Millisecond)\n}\n\nfunc init() {\n\tinputs.Add(\"internet_speed\", func() telegraf.Input {\n\t\treturn &InternetSpeed{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/internet_speed/internet_speed_test.go",
    "content": "package internet_speed\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/showwin/speedtest-go/speedtest\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSelectServer(t *testing.T) {\n\ttests := []struct {\n\t\tname       string\n\t\tinclude    []string\n\t\texclude    []string\n\t\tservers    speedtest.Servers\n\t\texpectedID string\n\t}{\n\t\t{\n\t\t\tname: \"no filter selects lowest latency\",\n\t\t\tservers: speedtest.Servers{\n\t\t\t\t{ID: \"1\", Latency: 50 * time.Millisecond},\n\t\t\t\t{ID: \"2\", Latency: 10 * time.Millisecond},\n\t\t\t\t{ID: \"3\", Latency: 30 * time.Millisecond},\n\t\t\t},\n\t\t\texpectedID: \"2\",\n\t\t},\n\t\t{\n\t\t\tname:    \"include filter selects matching server\",\n\t\t\tinclude: []string{\"3\"},\n\t\t\tservers: speedtest.Servers{\n\t\t\t\t{ID: \"1\", Latency: 10 * time.Millisecond},\n\t\t\t\t{ID: \"2\", Latency: 20 * time.Millisecond},\n\t\t\t\t{ID: \"3\", Latency: 30 * time.Millisecond},\n\t\t\t},\n\t\t\texpectedID: \"3\",\n\t\t},\n\t\t{\n\t\t\tname:    \"include filter with multiple matches selects lowest latency\",\n\t\t\tinclude: []string{\"2\", \"3\"},\n\t\t\tservers: speedtest.Servers{\n\t\t\t\t{ID: \"1\", Latency: 5 * time.Millisecond},\n\t\t\t\t{ID: \"2\", Latency: 30 * time.Millisecond},\n\t\t\t\t{ID: \"3\", Latency: 15 * time.Millisecond},\n\t\t\t},\n\t\t\texpectedID: \"3\",\n\t\t},\n\t\t{\n\t\t\tname:    \"exclude filter skips excluded server\",\n\t\t\texclude: []string{\"1\"},\n\t\t\tservers: speedtest.Servers{\n\t\t\t\t{ID: \"1\", Latency: 5 * time.Millisecond},\n\t\t\t\t{ID: \"2\", Latency: 10 * time.Millisecond},\n\t\t\t\t{ID: \"3\", Latency: 30 * time.Millisecond},\n\t\t\t},\n\t\t\texpectedID: \"2\",\n\t\t},\n\t\t{\n\t\t\tname:    \"no latency info selects first matching server\",\n\t\t\tinclude: []string{\"2\", \"3\"},\n\t\t\tservers: speedtest.Servers{\n\t\t\t\t{ID: \"1\"},\n\t\t\t\t{ID: \"2\"},\n\t\t\t\t{ID: \"3\"},\n\t\t\t},\n\t\t\texpectedID: \"2\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &InternetSpeed{\n\t\t\t\tServerIDInclude: tt.include,\n\t\t\t\tServerIDExclude: tt.exclude,\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\tplugin.servers = tt.servers\n\n\t\t\trequire.NoError(t, plugin.selectServer())\n\t\t\trequire.Equal(t, tt.expectedID, plugin.server.ID)\n\t\t})\n\t}\n}\n\nfunc TestSelectServerError(t *testing.T) {\n\tplugin := &InternetSpeed{\n\t\tServerIDInclude: []string{\"99\"},\n\t\tLog:             testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tplugin.servers = speedtest.Servers{\n\t\t{ID: \"1\", Latency: 10 * time.Millisecond},\n\t\t{ID: \"2\", Latency: 20 * time.Millisecond},\n\t}\n\n\trequire.ErrorContains(t, plugin.selectServer(), \"filter excluded all servers\")\n}\n\nfunc TestGathering(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\tinternetSpeed := &InternetSpeed{\n\t\tMemorySavingMode: true,\n\t\tLog:              testutil.Logger{},\n\t}\n\trequire.NoError(t, internetSpeed.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, internetSpeed.Gather(&acc))\n}\n\nfunc TestDataGen(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping network-dependent test in short mode.\")\n\t}\n\tinternetSpeed := &InternetSpeed{\n\t\tMemorySavingMode: true,\n\t\tLog:              testutil.Logger{},\n\t}\n\trequire.NoError(t, internetSpeed.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, internetSpeed.Gather(&acc))\n\n\tmetric, ok := acc.Get(\"internet_speed\")\n\trequire.True(t, ok)\n\tacc.AssertContainsTaggedFields(t, \"internet_speed\", metric.Fields, metric.Tags)\n}\n"
  },
  {
    "path": "plugins/inputs/internet_speed/sample.conf",
    "content": "# Monitors internet speed using speedtest.net service\n[[inputs.internet_speed]]\n  ## This plugin downloads many MB of data each time it is run. As such\n  ## consider setting a higher interval for this plugin to reduce the\n  ## demand on your internet connection.\n  # interval = \"60m\"\n\n  ## Enable to reduce memory usage\n  # memory_saving_mode = false\n\n  ## Caches the closest server location\n  # cache = false\n\n  ## Number of concurrent connections\n  ## By default or set to zero, the number of CPU cores is used. Use this to\n  ## reduce the impact on system performance or to increase the connections on\n  ## faster connections to ensure the fastest speed.\n  # connections = 0\n\n  ## Test mode\n  ## By default, a single server is used for testing. This may work for most,\n  ## however, setting to \"multi\" will reach out to multiple servers in an\n  ## attempt to get closer to ideal internet speeds.\n  ## And \"multi\" will use all available servers to calculate average packet loss.\n  # test_mode = \"single\"\n\n  ## Server ID exclude filter\n  ## Allows the user to exclude or include specific server IDs received by\n  ## speedtest-go. Values in the exclude option will be skipped over. Values in\n  ## the include option are the only options that will be picked from.\n  ##\n  ## See the list of servers speedtest-go will return at:\n  ##     https://www.speedtest.net/api/js/servers?engine=js&limit=10\n  ##\n  # server_id_exclude = []\n  # server_id_include = []\n"
  },
  {
    "path": "plugins/inputs/interrupts/README.md",
    "content": "# Interrupts Input Plugin\n\nThis plugin gathers metrics about IRQs from interrupts (`/proc/interrupts`) and\nsoft-interrupts (`/proc/softirqs`).\n\n⭐ Telegraf v1.3.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# This plugin gathers interrupts data from /proc/interrupts and /proc/softirqs.\n[[inputs.interrupts]]\n  ## When set to true, cpu metrics are tagged with the cpu.  Otherwise cpu is\n  ## stored as a field.\n  ##\n  ## The default is false for backwards compatibility, and will be changed to\n  ## true in a future version.  It is recommended to set to true on new\n  ## deployments.\n  # cpu_as_tag = false\n\n  ## To filter which IRQs to collect, make use of tagpass / tagdrop:\n  # [inputs.interrupts.tagdrop]\n  #   irq = [ \"NET_RX\", \"TASKLET\" ]\n```\n\n## Metrics\n\nThere are two styles depending on the value of `cpu_as_tag`.\n\nWith `cpu_as_tag = false`:\n\n- interrupts\n  - tags:\n    - irq (IRQ name)\n    - type\n    - device (name of the device that is located at the IRQ)\n    - cpu\n  - fields:\n    - cpu (int, number of interrupts per cpu)\n    - total (int, total number of interrupts)\n\n- soft_interrupts\n  - tags:\n    - irq (IRQ name)\n    - type\n    - device (name of the device that is located at the IRQ)\n    - cpu\n  - fields:\n    - cpu (int, number of interrupts per cpu)\n    - total (int, total number of interrupts)\n\nWith `cpu_as_tag = true`:\n\n- interrupts\n  - tags:\n    - irq (IRQ name)\n    - type\n    - device (name of the device that is located at the IRQ)\n    - cpu\n  - fields:\n    - count (int, number of interrupts)\n\n- soft_interrupts\n  - tags:\n    - irq (IRQ name)\n    - type\n    - device (name of the device that is located at the IRQ)\n    - cpu\n  - fields:\n    - count (int, number of interrupts)\n\n## Example Output\n\nWith `cpu_as_tag = false`:\n\n```text\ninterrupts,irq=0,type=IO-APIC,device=2-edge\\ timer,cpu=cpu0 count=23i 1489346531000000000\ninterrupts,irq=1,type=IO-APIC,device=1-edge\\ i8042,cpu=cpu0 count=9i 1489346531000000000\ninterrupts,irq=30,type=PCI-MSI,device=65537-edge\\ virtio1-input.0,cpu=cpu1 count=1i 1489346531000000000\nsoft_interrupts,irq=NET_RX,cpu=cpu0 count=280879i 1489346531000000000\n```\n\nWith `cpu_as_tag = true`:\n\n```text\ninterrupts,cpu=cpu6,irq=PIW,type=Posted-interrupt\\ wakeup\\ event count=0i 1543539773000000000\ninterrupts,cpu=cpu7,irq=PIW,type=Posted-interrupt\\ wakeup\\ event count=0i 1543539773000000000\nsoft_interrupts,cpu=cpu0,irq=HI count=246441i 1543539773000000000\nsoft_interrupts,cpu=cpu1,irq=HI count=159154i 1543539773000000000\n```\n"
  },
  {
    "path": "plugins/inputs/interrupts/interrupts.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage interrupts\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Interrupts struct {\n\tCPUAsTag bool `toml:\"cpu_as_tag\"`\n}\n\ntype irq struct {\n\tid     string\n\ttyp    string\n\tdevice string\n\ttotal  int64\n\tcpus   []int64\n}\n\nfunc (*Interrupts) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Interrupts) Gather(acc telegraf.Accumulator) error {\n\tfor measurement, file := range map[string]string{\"interrupts\": \"/proc/interrupts\", \"soft_interrupts\": \"/proc/softirqs\"} {\n\t\tirqs, err := parseFile(file)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\t\treportMetrics(measurement, irqs, acc, s.CPUAsTag)\n\t}\n\treturn nil\n}\n\nfunc parseInterrupts(r io.Reader) ([]irq, error) {\n\tvar irqs []irq\n\tvar cpucount int\n\tscanner := bufio.NewScanner(r)\n\tif scanner.Scan() {\n\t\tcpus := strings.Fields(scanner.Text())\n\t\tif cpus[0] != \"CPU0\" {\n\t\t\treturn nil, fmt.Errorf(\"expected first line to start with CPU0, but was %s\", scanner.Text())\n\t\t}\n\t\tcpucount = len(cpus)\n\t}\n\nscan:\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\t\tif !strings.HasSuffix(fields[0], \":\") {\n\t\t\tcontinue\n\t\t}\n\t\tirqid := strings.TrimRight(fields[0], \":\")\n\t\tirq := newIRQ(irqid)\n\t\tirqvals := fields[1:]\n\t\tfor i := 0; i < cpucount; i++ {\n\t\t\tif i < len(irqvals) {\n\t\t\t\tirqval, err := strconv.ParseInt(irqvals[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue scan\n\t\t\t\t}\n\t\t\t\tirq.cpus = append(irq.cpus, irqval)\n\t\t\t}\n\t\t}\n\t\tfor _, irqval := range irq.cpus {\n\t\t\tirq.total += irqval\n\t\t}\n\t\t_, err := strconv.ParseInt(irqid, 10, 64)\n\t\tif err == nil && len(fields) >= cpucount+2 {\n\t\t\tirq.typ = fields[cpucount+1]\n\t\t\tirq.device = strings.Join(fields[cpucount+2:], \" \")\n\t\t} else if len(fields) > cpucount {\n\t\t\tirq.typ = strings.Join(fields[cpucount+1:], \" \")\n\t\t}\n\t\tirqs = append(irqs, *irq)\n\t}\n\tif scanner.Err() != nil {\n\t\treturn nil, fmt.Errorf(\"error scanning file: %w\", scanner.Err())\n\t}\n\treturn irqs, nil\n}\n\nfunc gatherTagsFields(irq irq) (map[string]string, map[string]interface{}) {\n\ttags := map[string]string{\"irq\": irq.id, \"type\": irq.typ, \"device\": irq.device}\n\tfields := map[string]interface{}{\"total\": irq.total}\n\tfor i := 0; i < len(irq.cpus); i++ {\n\t\tcpu := fmt.Sprintf(\"CPU%d\", i)\n\t\tfields[cpu] = irq.cpus[i]\n\t}\n\treturn tags, fields\n}\n\nfunc parseFile(file string) ([]irq, error) {\n\tf, err := os.Open(file)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not open file: %s\", file)\n\t}\n\tdefer f.Close()\n\n\tirqs, err := parseInterrupts(f)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing %q: %w\", file, err)\n\t}\n\treturn irqs, nil\n}\n\nfunc reportMetrics(measurement string, irqs []irq, acc telegraf.Accumulator, cpusAsTags bool) {\n\tfor _, irq := range irqs {\n\t\ttags, fields := gatherTagsFields(irq)\n\t\tif cpusAsTags {\n\t\t\tfor cpu, count := range irq.cpus {\n\t\t\t\tcpuTags := map[string]string{\"cpu\": fmt.Sprintf(\"cpu%d\", cpu)}\n\t\t\t\tfor k, v := range tags {\n\t\t\t\t\tcpuTags[k] = v\n\t\t\t\t}\n\t\t\t\tacc.AddFields(measurement, map[string]interface{}{\"count\": count}, cpuTags)\n\t\t\t}\n\t\t} else {\n\t\t\tacc.AddFields(measurement, fields, tags)\n\t\t}\n\t}\n}\n\nfunc newIRQ(id string) *irq {\n\treturn &irq{id: id}\n}\n\nfunc init() {\n\tinputs.Add(\"interrupts\", func() telegraf.Input {\n\t\treturn &Interrupts{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/interrupts/interrupts_test.go",
    "content": "package interrupts\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// =====================================================================================\n//\tSetup and helper functions\n// =====================================================================================\n\nfunc expectCPUAsTags(m *testutil.Accumulator, t *testing.T, measurement string, irq irq) {\n\tfor idx, value := range irq.cpus {\n\t\tm.AssertContainsTaggedFields(t, measurement,\n\t\t\tmap[string]interface{}{\"count\": value},\n\t\t\tmap[string]string{\"irq\": irq.id, \"type\": irq.typ, \"device\": irq.device, \"cpu\": fmt.Sprintf(\"cpu%d\", idx)},\n\t\t)\n\t}\n}\n\nfunc expectCPUAsFields(m *testutil.Accumulator, t *testing.T, measurement string, irq irq) {\n\tfields := map[string]interface{}{}\n\ttotal := int64(0)\n\tfor idx, count := range irq.cpus {\n\t\tfields[fmt.Sprintf(\"CPU%d\", idx)] = count\n\t\ttotal += count\n\t}\n\tfields[\"total\"] = total\n\n\tm.AssertContainsTaggedFields(t, measurement, fields, map[string]string{\"irq\": irq.id, \"type\": irq.typ, \"device\": irq.device})\n}\n\nfunc setup(t *testing.T, irqString string, cpuAsTags bool) (*testutil.Accumulator, []irq) {\n\tf := bytes.NewBufferString(irqString)\n\tirqs, err := parseInterrupts(f)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, irqs)\n\n\tacc := new(testutil.Accumulator)\n\treportMetrics(\"soft_interrupts\", irqs, acc, cpuAsTags)\n\n\treturn acc, irqs\n}\n\n// =====================================================================================\n//\tSoft interrupts\n// =====================================================================================\n\nconst softIrqsString = `            CPU0       \t\tCPU1\n\t\t\t\t\t\t0:           134 \t    \t   0   IO-APIC-edge      timer\n\t\t\t\t\t\t1:   \t       7\t           3   IO-APIC-edge      i8042\n\t\t\t\t\t\tNMI:           0    \t   \t   0   Non-maskable interrupts\n\t\t\t\t\t\tLOC:  2338608687 \t  2334309625   Local timer interrupts\n\t\t\t\t\t\tMIS:           0\n\t\t\t\t\t\tNET_RX:   867028\t\t\t 225\n\t\t\t\t\t\tTASKLET:\t 205\t\t\t   0`\n\nvar softIrqsExpectedArgs = []irq{\n\t{id: \"0\", typ: \"IO-APIC-edge\", device: \"timer\", cpus: []int64{134, 0}},\n\t{id: \"1\", typ: \"IO-APIC-edge\", device: \"i8042\", cpus: []int64{7, 3}},\n\t{id: \"NMI\", typ: \"Non-maskable interrupts\", cpus: []int64{0, 0}},\n\t{id: \"MIS\", cpus: []int64{0}},\n\t{id: \"NET_RX\", cpus: []int64{867028, 225}},\n\t{id: \"TASKLET\", cpus: []int64{205, 0}},\n}\n\nfunc TestCpuAsTagsSoftIrqs(t *testing.T) {\n\tacc, irqs := setup(t, softIrqsString, true)\n\treportMetrics(\"soft_interrupts\", irqs, acc, true)\n\n\tfor _, irq := range softIrqsExpectedArgs {\n\t\texpectCPUAsTags(acc, t, \"soft_interrupts\", irq)\n\t}\n}\n\nfunc TestCpuAsFieldsSoftIrqs(t *testing.T) {\n\tacc, irqs := setup(t, softIrqsString, false)\n\treportMetrics(\"soft_interrupts\", irqs, acc, false)\n\n\tfor _, irq := range softIrqsExpectedArgs {\n\t\texpectCPUAsFields(acc, t, \"soft_interrupts\", irq)\n\t}\n}\n\n// =====================================================================================\n//\tHW interrupts, tests #4470\n// =====================================================================================\n\nconst hwIrqsString = `     CPU0       CPU1       CPU2       CPU3\n\t\t\t\t 16:          0          0          0          0  bcm2836-timer   0 Edge      arch_timer\n\t\t\t\t 17:  127224250  118424219  127224437  117885416  bcm2836-timer   1 Edge      arch_timer\n\t\t\t\t 21:          0          0          0          0  bcm2836-pmu     9 Edge      arm-pmu\n\t\t\t\t 23:    1549514          0          0          0  ARMCTRL-level   1 Edge      3f00b880.mailbox\n\t\t\t\t 24:          2          0          0          0  ARMCTRL-level   2 Edge      VCHIQ doorbell\n\t\t\t\t 46:          0          0          0          0  ARMCTRL-level  48 Edge      bcm2708_fb dma\n\t\t\t\t 48:          0          0          0          0  ARMCTRL-level  50 Edge      DMA IRQ\n\t\t\t\t 50:          0          0          0          0  ARMCTRL-level  52 Edge      DMA IRQ\n\t\t\t\t 51:        208          0          0          0  ARMCTRL-level  53 Edge      DMA IRQ\n\t\t\t\t 54:     883002          0          0          0  ARMCTRL-level  56 Edge      DMA IRQ\n\t\t\t\t 59:          0          0          0          0  ARMCTRL-level  61 Edge      bcm2835-auxirq\n\t\t\t\t 62:  521451447          0          0          0  ARMCTRL-level  64 Edge      dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1\n\t\t\t\t 86:     857597          0          0          0  ARMCTRL-level  88 Edge      mmc0\n\t\t\t\t 87:       4938          0          0          0  ARMCTRL-level  89 Edge      uart-pl011\n\t\t\t\t 92:       5669          0          0          0  ARMCTRL-level  94 Edge      mmc1\n\t\t\t\t FIQ:              usb_fiq\n\t\t\t\tIPI0:         0          0          0          0  CPU wakeup interrupts\n\t\t\t\tIPI1:         0          0          0          0  Timer broadcast interrupts\n\t\t\t\tIPI2:  23564958   23464876   23531165   23040826  Rescheduling interrupts\n\t\t\t\tIPI3:    148438     639704     644266     588150  Function call interrupts\n\t\t\t\tIPI4:         0          0          0          0  CPU stop interrupts\n\t\t\t\tIPI5:   4348149    1843985    3819457    1822877  IRQ work interrupts\n\t\t\t\tIPI6:         0          0          0          0  completion interrupts`\n\nvar hwIrqsExpectedArgs = []irq{\n\t{id: \"16\", typ: \"bcm2836-timer\", device: \"0 Edge arch_timer\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"17\", typ: \"bcm2836-timer\", device: \"1 Edge arch_timer\", cpus: []int64{127224250, 118424219, 127224437, 117885416}},\n\t{id: \"21\", typ: \"bcm2836-pmu\", device: \"9 Edge arm-pmu\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"23\", typ: \"ARMCTRL-level\", device: \"1 Edge 3f00b880.mailbox\", cpus: []int64{1549514, 0, 0, 0}},\n\t{id: \"24\", typ: \"ARMCTRL-level\", device: \"2 Edge VCHIQ doorbell\", cpus: []int64{2, 0, 0, 0}},\n\t{id: \"46\", typ: \"ARMCTRL-level\", device: \"48 Edge bcm2708_fb dma\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"48\", typ: \"ARMCTRL-level\", device: \"50 Edge DMA IRQ\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"50\", typ: \"ARMCTRL-level\", device: \"52 Edge DMA IRQ\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"51\", typ: \"ARMCTRL-level\", device: \"53 Edge DMA IRQ\", cpus: []int64{208, 0, 0, 0}},\n\t{id: \"54\", typ: \"ARMCTRL-level\", device: \"56 Edge DMA IRQ\", cpus: []int64{883002, 0, 0, 0}},\n\t{id: \"59\", typ: \"ARMCTRL-level\", device: \"61 Edge bcm2835-auxirq\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"62\", typ: \"ARMCTRL-level\", device: \"64 Edge dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1\", cpus: []int64{521451447, 0, 0, 0}},\n\t{id: \"86\", typ: \"ARMCTRL-level\", device: \"88 Edge mmc0\", cpus: []int64{857597, 0, 0, 0}},\n\t{id: \"87\", typ: \"ARMCTRL-level\", device: \"89 Edge uart-pl011\", cpus: []int64{4938, 0, 0, 0}},\n\t{id: \"92\", typ: \"ARMCTRL-level\", device: \"94 Edge mmc1\", cpus: []int64{5669, 0, 0, 0}},\n\t{id: \"IPI0\", typ: \"CPU wakeup interrupts\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"IPI1\", typ: \"Timer broadcast interrupts\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"IPI2\", typ: \"Rescheduling interrupts\", cpus: []int64{23564958, 23464876, 23531165, 23040826}},\n\t{id: \"IPI3\", typ: \"Function call interrupts\", cpus: []int64{148438, 639704, 644266, 588150}},\n\t{id: \"IPI4\", typ: \"CPU stop interrupts\", cpus: []int64{0, 0, 0, 0}},\n\t{id: \"IPI5\", typ: \"IRQ work interrupts\", cpus: []int64{4348149, 1843985, 3819457, 1822877}},\n\t{id: \"IPI6\", typ: \"completion interrupts\", cpus: []int64{0, 0, 0, 0}},\n}\n\nfunc TestCpuAsTagsHwIrqs(t *testing.T) {\n\tacc, irqs := setup(t, hwIrqsString, true)\n\treportMetrics(\"interrupts\", irqs, acc, true)\n\n\tfor _, irq := range hwIrqsExpectedArgs {\n\t\texpectCPUAsTags(acc, t, \"interrupts\", irq)\n\t}\n}\n\nfunc TestCpuAsFieldsHwIrqs(t *testing.T) {\n\tacc, irqs := setup(t, hwIrqsString, false)\n\treportMetrics(\"interrupts\", irqs, acc, false)\n\n\tfor _, irq := range hwIrqsExpectedArgs {\n\t\texpectCPUAsFields(acc, t, \"interrupts\", irq)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/interrupts/sample.conf",
    "content": "# This plugin gathers interrupts data from /proc/interrupts and /proc/softirqs.\n[[inputs.interrupts]]\n  ## When set to true, cpu metrics are tagged with the cpu.  Otherwise cpu is\n  ## stored as a field.\n  ##\n  ## The default is false for backwards compatibility, and will be changed to\n  ## true in a future version.  It is recommended to set to true on new\n  ## deployments.\n  # cpu_as_tag = false\n\n  ## To filter which IRQs to collect, make use of tagpass / tagdrop:\n  # [inputs.interrupts.tagdrop]\n  #   irq = [ \"NET_RX\", \"TASKLET\" ]\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/README.md",
    "content": "# IPMI Sensor Input Plugin\n\nThis plugin gathers metrics from the\n[Intelligent Platform Management Interface][ipmi_spec] using the\n[`ipmitool`][ipmitool] command line utility.\n\n> [!IMPORTANT]\n> The `ipmitool` requires access to the IPMI device. Please check the\n> [permission section](#permissions) for possible solutions.\n\n⭐ Telegraf v0.12.0\n🏷️ hardware, system\n💻 all\n\n[ipmi_spec]: https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf\n[ipmitool]: https://github.com/ipmitool/ipmitool\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from the bare metal servers via IPMI\n[[inputs.ipmi_sensor]]\n  ## Specify the path to the ipmitool executable\n  # path = \"/usr/bin/ipmitool\"\n\n  ## Use sudo\n  ## Setting 'use_sudo' to true will make use of sudo to run ipmitool.\n  ## Sudo must be configured to allow the telegraf user to run ipmitool\n  ## without a password.\n  # use_sudo = false\n\n  ## Servers\n  ## Specify one or more servers via a url. If no servers are specified, local\n  ## machine sensor stats will be queried. Uses the format:\n  ##  [username[:password]@][protocol[(address)]]\n  ##  e.g. root:passwd@lan(127.0.0.1)\n  # servers = [\"USERID:PASSW0RD@lan(192.168.1.1)\"]\n\n  ## Session privilege level\n  ## Choose from: CALLBACK, USER, OPERATOR, ADMINISTRATOR\n  # privilege = \"ADMINISTRATOR\"\n\n  ## Timeout\n  ## Timeout for the ipmitool command to complete.\n  # timeout = \"20s\"\n\n  ## Metric schema version\n  ## See the plugin readme for more information on schema versioning.\n  # metric_version = 1\n\n  ## Sensors to collect\n  ## Choose from:\n  ##   * sdr: default, collects sensor data records\n  ##   * chassis_power_status: collects the power status of the chassis\n  ##   * dcmi_power_reading: collects the power readings from the Data Center Management Interface\n  # sensors = [\"sdr\"]\n\n  ## Hex key\n  ## Optionally provide the hex key for the IMPI connection.\n  # hex_key = \"\"\n\n  ## Cache\n  ## If ipmitool should use a cache\n  ## Using a cache can speed up collection times depending on your device.\n  # use_cache = false\n\n  ## Path to the ipmitools cache file (defaults to OS temp dir)\n  ## The provided path must exist and must be writable\n  # cache_path = \"\"\n```\n\nIf no servers are specified, the plugin will query the local machine sensor\nstats via the following command:\n\n```sh\nipmitool sdr\n```\n\nor with the version 2 schema:\n\n```sh\nipmitool sdr elist\n```\n\nWhen one or more servers are specified, the plugin will use the following\ncommand to collect remote host sensor stats:\n\n```sh\nipmitool -I lan -H SERVER -U USERID -P PASSW0RD sdr\n```\n\nAny of the following parameters will be added to the aforementioned query if\nthey're configured:\n\n```sh\n-y hex_key -L privilege\n```\n\n## Sensors\n\nBy default the plugin collects data via the `sdr` command and returns those\nvalues. However, there are additonal sensor options that be call on:\n\n- `chassis_power_status` - returns 0 or 1 depending on the output of\n  `chassis power status`\n- `dcmi_power_reading` - Returns the watt values from `dcmi power reading`\n\nThese sensor options are not affected by the metric version.\n\n## Metrics\n\nVersion 1 schema:\n\n- ipmi_sensor:\n  - tags:\n    - name\n    - unit\n    - host\n    - server (only when retrieving stats from remote servers)\n  - fields:\n    - status (int, 1=ok status_code/0=anything else)\n    - value (float)\n\nVersion 2 schema:\n\n- ipmi_sensor:\n  - tags:\n    - name\n    - entity_id (can help uniquify duplicate names)\n    - status_code (two letter code from IPMI documentation)\n    - status_desc (extended status description field)\n    - unit (only on analog values)\n    - host\n    - server (only when retrieving stats from remote)\n  - fields:\n    - value (float)\n\n### Permissions\n\nWhen gathering from the local system, Telegraf will need permission to the\nipmi device node.  When using udev you can create the device node giving\n`rw` permissions to the `telegraf` user by adding the following rule to\n`/etc/udev/rules.d/52-telegraf-ipmi.rules`:\n\n```sh\nKERNEL==\"ipmi*\", MODE=\"660\", GROUP=\"telegraf\"\n```\n\nAlternatively, it is possible to use sudo. You will need the following in your\ntelegraf config:\n\n```toml\n[[inputs.ipmi_sensor]]\n  use_sudo = true\n```\n\nYou will also need to update your sudoers file:\n\n```bash\n$ visudo\n# Add the following line:\nCmnd_Alias IPMITOOL = /usr/bin/ipmitool *\ntelegraf  ALL=(root) NOPASSWD: IPMITOOL\nDefaults!IPMITOOL !logfile, !syslog, !pam_session\n```\n\n## Example Output\n\n### Version 1 Schema\n\nWhen retrieving stats from a remote server:\n\n```text\nipmi_sensor,server=10.20.2.203,name=uid_light value=0,status=1i 1517125513000000000\nipmi_sensor,server=10.20.2.203,name=sys._health_led status=1i,value=0 1517125513000000000\nipmi_sensor,server=10.20.2.203,name=power_supply_1,unit=watts status=1i,value=110 1517125513000000000\nipmi_sensor,server=10.20.2.203,name=power_supply_2,unit=watts status=1i,value=120 1517125513000000000\nipmi_sensor,server=10.20.2.203,name=power_supplies value=0,status=1i 1517125513000000000\nipmi_sensor,server=10.20.2.203,name=fan_1,unit=percent status=1i,value=43.12 1517125513000000000\n```\n\nWhen retrieving stats from the local machine (no server specified):\n\n```text\nipmi_sensor,name=uid_light value=0,status=1i 1517125513000000000\nipmi_sensor,name=sys._health_led status=1i,value=0 1517125513000000000\nipmi_sensor,name=power_supply_1,unit=watts status=1i,value=110 1517125513000000000\nipmi_sensor,name=power_supply_2,unit=watts status=1i,value=120 1517125513000000000\nipmi_sensor,name=power_supplies value=0,status=1i 1517125513000000000\nipmi_sensor,name=fan_1,unit=percent status=1i,value=43.12 1517125513000000000\n```\n\n#### Version 2 Schema\n\nWhen retrieving stats from the local machine (no server specified):\n\n```text\nipmi_sensor,name=uid_light,entity_id=23.1,status_code=ok,status_desc=ok value=0 1517125474000000000\nipmi_sensor,name=sys._health_led,entity_id=23.2,status_code=ok,status_desc=ok value=0 1517125474000000000\nipmi_sensor,entity_id=10.1,name=power_supply_1,status_code=ok,status_desc=presence_detected,unit=watts value=110 1517125474000000000\nipmi_sensor,name=power_supply_2,entity_id=10.2,status_code=ok,unit=watts,status_desc=presence_detected value=125 1517125474000000000\nipmi_sensor,name=power_supplies,entity_id=10.3,status_code=ok,status_desc=fully_redundant value=0 1517125474000000000\nipmi_sensor,entity_id=7.1,name=fan_1,status_code=ok,status_desc=transition_to_running,unit=percent value=43.12 1517125474000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/connection.go",
    "content": "package ipmi_sensor\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// connection properties for a Client\ntype connection struct {\n\thostname  string\n\tusername  string\n\tpassword  string\n\tport      int\n\tintf      string\n\tprivilege string\n\thexKey    string\n}\n\nfunc newConnection(server, privilege, hexKey string) *connection {\n\tconn := &connection{\n\t\tprivilege: privilege,\n\t\thexKey:    hexKey,\n\t}\n\tinx1 := strings.LastIndex(server, \"@\")\n\tinx2 := strings.Index(server, \"(\")\n\n\tconnstr := server\n\n\tif inx1 > 0 {\n\t\tsecurity := server[0:inx1]\n\t\tconnstr = server[inx1+1:]\n\t\tup := strings.SplitN(security, \":\", 2)\n\t\tif len(up) == 2 {\n\t\t\tconn.username = up[0]\n\t\t\tconn.password = up[1]\n\t\t}\n\t}\n\n\tif inx2 > 0 {\n\t\tinx2 = strings.Index(connstr, \"(\")\n\t\tinx3 := strings.Index(connstr, \")\")\n\n\t\tconn.intf = connstr[0:inx2]\n\t\tconn.hostname = connstr[inx2+1 : inx3]\n\t}\n\n\treturn conn\n}\n\nfunc (c *connection) options() []string {\n\tintf := c.intf\n\tif intf == \"\" {\n\t\tintf = \"lan\"\n\t}\n\n\toptions := []string{\n\t\t\"-H\", c.hostname,\n\t\t\"-U\", c.username,\n\t\t\"-P\", c.password,\n\t\t\"-I\", intf,\n\t}\n\n\tif c.hexKey != \"\" {\n\t\toptions = append(options, \"-y\", c.hexKey)\n\t}\n\tif c.port != 0 {\n\t\toptions = append(options, \"-p\", strconv.Itoa(c.port))\n\t}\n\tif c.privilege != \"\" {\n\t\toptions = append(options, \"-L\", c.privilege)\n\t}\n\treturn options\n}\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/connection_test.go",
    "content": "package ipmi_sensor\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewConnection(t *testing.T) {\n\ttestData := []struct {\n\t\taddr string\n\t\tcon  *connection\n\t}{\n\t\t{\n\t\t\t\"USERID:PASSW0RD@lan(192.168.1.1)\",\n\t\t\t&connection{\n\t\t\t\thostname:  \"192.168.1.1\",\n\t\t\t\tusername:  \"USERID\",\n\t\t\t\tpassword:  \"PASSW0RD\",\n\t\t\t\tintf:      \"lan\",\n\t\t\t\tprivilege: \"USER\",\n\t\t\t\thexKey:    \"0001\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"USERID:PASS:!@#$%^&*(234)_+W0RD@lan(192.168.1.1)\",\n\t\t\t&connection{\n\t\t\t\thostname:  \"192.168.1.1\",\n\t\t\t\tusername:  \"USERID\",\n\t\t\t\tpassword:  \"PASS:!@#$%^&*(234)_+W0RD\",\n\t\t\t\tintf:      \"lan\",\n\t\t\t\tprivilege: \"USER\",\n\t\t\t\thexKey:    \"0001\",\n\t\t\t},\n\t\t},\n\t\t// test connection doesn't panic if incorrect symbol used\n\t\t{\n\t\t\t\"USERID@PASSW0RD@lan(192.168.1.1)\",\n\t\t\t&connection{\n\t\t\t\thostname:  \"192.168.1.1\",\n\t\t\t\tusername:  \"\",\n\t\t\t\tpassword:  \"\",\n\t\t\t\tintf:      \"lan\",\n\t\t\t\tprivilege: \"USER\",\n\t\t\t\thexKey:    \"0001\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, v := range testData {\n\t\trequire.EqualValues(t, v.con, newConnection(v.addr, \"USER\", \"0001\"))\n\t}\n}\n\nfunc TestGetCommandOptions(t *testing.T) {\n\ttestData := []struct {\n\t\tconnection *connection\n\t\toptions    []string\n\t}{\n\t\t{\n\t\t\t&connection{\n\t\t\t\thostname:  \"192.168.1.1\",\n\t\t\t\tusername:  \"user\",\n\t\t\t\tpassword:  \"password\",\n\t\t\t\tintf:      \"lan\",\n\t\t\t\tprivilege: \"USER\",\n\t\t\t\thexKey:    \"0001\",\n\t\t\t},\n\t\t\t[]string{\"-H\", \"192.168.1.1\", \"-U\", \"user\", \"-P\", \"password\", \"-I\", \"lan\", \"-y\", \"0001\", \"-L\", \"USER\"},\n\t\t},\n\t\t{\n\t\t\t&connection{\n\t\t\t\thostname:  \"192.168.1.1\",\n\t\t\t\tusername:  \"user\",\n\t\t\t\tpassword:  \"password\",\n\t\t\t\tintf:      \"lan\",\n\t\t\t\tprivilege: \"USER\",\n\t\t\t\thexKey:    \"\",\n\t\t\t},\n\t\t\t[]string{\"-H\", \"192.168.1.1\", \"-U\", \"user\", \"-P\", \"password\", \"-I\", \"lan\", \"-L\", \"USER\"},\n\t\t},\n\t}\n\n\tfor _, data := range testData {\n\t\trequire.EqualValues(t, data.options, data.connection.options())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/ipmi_sensor.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ipmi_sensor\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\texecCommand          = exec.Command // execCommand is used to mock commands in tests.\n\treV1ParseLine        = regexp.MustCompile(`^(?P<name>[^|]*)\\|(?P<description>[^|]*)\\|(?P<status_code>.*)`)\n\treV2ParseLine        = regexp.MustCompile(`^(?P<name>[^|]*)\\|[^|]+\\|(?P<status_code>[^|]*)\\|(?P<entity_id>[^|]*)\\|(?:(?P<description>[^|]+))?`)\n\treV2ParseDescription = regexp.MustCompile(`^(?P<analogValue>-?[0-9.]+)\\s(?P<analogUnit>.*)|(?P<status>.+)|^$`)\n\treV2ParseUnit        = regexp.MustCompile(`^(?P<realAnalogUnit>[^,]+)(?:,\\s*(?P<statusDesc>.*))?`)\n\tdcmiPowerReading     = regexp.MustCompile(`^(?P<name>[^|]*)\\:(?P<value>.* Watts)?`)\n)\n\nconst cmd = \"ipmitool\"\n\ntype Ipmi struct {\n\tPath          string          `toml:\"path\"`\n\tPrivilege     string          `toml:\"privilege\"`\n\tHexKey        string          `toml:\"hex_key\"`\n\tServers       []string        `toml:\"servers\"`\n\tSensors       []string        `toml:\"sensors\"`\n\tTimeout       config.Duration `toml:\"timeout\"`\n\tMetricVersion int             `toml:\"metric_version\"`\n\tUseSudo       bool            `toml:\"use_sudo\"`\n\tUseCache      bool            `toml:\"use_cache\"`\n\tCachePath     string          `toml:\"cache_path\"`\n\tLog           telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Ipmi) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Ipmi) Init() error {\n\t// Set defaults\n\tif m.Path == \"\" {\n\t\tpath, err := exec.LookPath(cmd)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"looking up %q failed: %w\", cmd, err)\n\t\t}\n\t\tm.Path = path\n\t}\n\tif m.CachePath == \"\" {\n\t\tm.CachePath = os.TempDir()\n\t}\n\tif len(m.Sensors) == 0 {\n\t\tm.Sensors = []string{\"sdr\"}\n\t}\n\tif err := choice.CheckSlice(m.Sensors, []string{\"sdr\", \"chassis_power_status\", \"dcmi_power_reading\"}); err != nil {\n\t\treturn err\n\t}\n\n\t// Check parameters\n\tif m.Path == \"\" {\n\t\treturn fmt.Errorf(\"no path for %q specified\", cmd)\n\t}\n\n\treturn nil\n}\n\nfunc (m *Ipmi) Gather(acc telegraf.Accumulator) error {\n\tif len(m.Path) == 0 {\n\t\treturn errors.New(\"ipmitool not found: verify that ipmitool is installed and that ipmitool is in your PATH\")\n\t}\n\n\tif len(m.Servers) > 0 {\n\t\twg := sync.WaitGroup{}\n\t\tfor _, server := range m.Servers {\n\t\t\twg.Add(1)\n\t\t\tgo func(a telegraf.Accumulator, s string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tfor _, sensor := range m.Sensors {\n\t\t\t\t\ta.AddError(m.parse(a, s, sensor))\n\t\t\t\t}\n\t\t\t}(acc, server)\n\t\t}\n\t\twg.Wait()\n\t} else {\n\t\tfor _, sensor := range m.Sensors {\n\t\t\terr := m.parse(acc, \"\", sensor)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *Ipmi) parse(acc telegraf.Accumulator, server, sensor string) error {\n\tvar command []string\n\tswitch sensor {\n\tcase \"sdr\":\n\t\tcommand = append(command, \"sdr\")\n\tcase \"chassis_power_status\":\n\t\tcommand = append(command, \"chassis\", \"power\", \"status\")\n\tcase \"dcmi_power_reading\":\n\t\tcommand = append(command, \"dcmi\", \"power\", \"reading\")\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown sensor type %q\", sensor)\n\t}\n\n\topts := make([]string, 0)\n\thostname := \"\"\n\tif server != \"\" {\n\t\tconn := newConnection(server, m.Privilege, m.HexKey)\n\t\thostname = conn.hostname\n\t\topts = conn.options()\n\t}\n\n\topts = append(opts, command...)\n\n\tif m.UseCache {\n\t\tcacheFile := filepath.Join(m.CachePath, server+\"_ipmi_cache\")\n\t\t_, err := os.Stat(cacheFile)\n\t\tif os.IsNotExist(err) {\n\t\t\tdumpOpts := opts\n\t\t\t// init cache file\n\t\t\tdumpOpts = append(dumpOpts, \"dump\", cacheFile)\n\t\t\tname := m.Path\n\t\t\tif m.UseSudo {\n\t\t\t\t// -n - avoid prompting the user for input of any kind\n\t\t\t\tdumpOpts = append([]string{\"-n\", name}, dumpOpts...)\n\t\t\t\tname = \"sudo\"\n\t\t\t}\n\t\t\tcmd := execCommand(name, dumpOpts...)\n\t\t\tout, err := internal.CombinedOutputTimeout(cmd, time.Duration(m.Timeout))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to run command %q: %w - %s\", strings.Join(sanitizeIPMICmd(cmd.Args), \" \"), err, string(out))\n\t\t\t}\n\t\t}\n\t\topts = append(opts, \"-S\", cacheFile)\n\t}\n\tif m.MetricVersion == 2 && sensor == \"sdr\" {\n\t\topts = append(opts, \"elist\")\n\t}\n\tname := m.Path\n\tif m.UseSudo {\n\t\t// -n - avoid prompting the user for input of any kind\n\t\topts = append([]string{\"-n\", name}, opts...)\n\t\tname = \"sudo\"\n\t}\n\tcmd := execCommand(name, opts...)\n\tout, err := internal.CombinedOutputTimeout(cmd, time.Duration(m.Timeout))\n\ttimestamp := time.Now()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to run command %q: %w - %s\", strings.Join(sanitizeIPMICmd(cmd.Args), \" \"), err, string(out))\n\t}\n\n\tswitch sensor {\n\tcase \"sdr\":\n\t\tif m.MetricVersion == 2 {\n\t\t\treturn m.parseV2(acc, hostname, out, timestamp)\n\t\t}\n\t\treturn m.parseV1(acc, hostname, out, timestamp)\n\tcase \"chassis_power_status\":\n\t\treturn parseChassisPowerStatus(acc, hostname, out, timestamp)\n\tcase \"dcmi_power_reading\":\n\t\treturn m.parseDCMIPowerReading(acc, hostname, out, timestamp)\n\t}\n\n\treturn fmt.Errorf(\"unknown sensor type %q\", sensor)\n}\n\nfunc parseChassisPowerStatus(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {\n\t// each line will look something like\n\t// Chassis Power is on\n\t// Chassis Power is off\n\tscanner := bufio.NewScanner(bytes.NewReader(cmdOut))\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.Contains(line, \"Chassis Power is on\") {\n\t\t\tacc.AddFields(\"ipmi_sensor\", map[string]interface{}{\"value\": 1}, map[string]string{\"name\": \"chassis_power_status\", \"server\": hostname}, measuredAt)\n\t\t} else if strings.Contains(line, \"Chassis Power is off\") {\n\t\t\tacc.AddFields(\"ipmi_sensor\", map[string]interface{}{\"value\": 0}, map[string]string{\"name\": \"chassis_power_status\", \"server\": hostname}, measuredAt)\n\t\t}\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (m *Ipmi) parseDCMIPowerReading(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {\n\t// each line will look something like\n\t// Current Power Reading : 0.000\n\tscanner := bufio.NewScanner(bytes.NewReader(cmdOut))\n\tfor scanner.Scan() {\n\t\tipmiFields := m.extractFieldsFromRegex(dcmiPowerReading, scanner.Text())\n\t\tif len(ipmiFields) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"name\": transform(ipmiFields[\"name\"]),\n\t\t}\n\n\t\t// tag the server is we have one\n\t\tif hostname != \"\" {\n\t\t\ttags[\"server\"] = hostname\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tvalunit := strings.Split(ipmiFields[\"value\"], \" \")\n\t\tif len(valunit) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar err error\n\t\tfields[\"value\"], err = aToFloat(valunit[0])\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif len(valunit) > 1 {\n\t\t\ttags[\"unit\"] = transform(valunit[1])\n\t\t}\n\n\t\tacc.AddFields(\"ipmi_sensor\", fields, tags, measuredAt)\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (m *Ipmi) parseV1(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {\n\t// each line will look something like\n\t// Planar VBAT      | 3.05 Volts        | ok\n\tscanner := bufio.NewScanner(bytes.NewReader(cmdOut))\n\tfor scanner.Scan() {\n\t\tipmiFields := m.extractFieldsFromRegex(reV1ParseLine, scanner.Text())\n\t\tif len(ipmiFields) != 3 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"name\": transform(ipmiFields[\"name\"]),\n\t\t}\n\n\t\t// tag the server is we have one\n\t\tif hostname != \"\" {\n\t\t\ttags[\"server\"] = hostname\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tif strings.EqualFold(\"ok\", trim(ipmiFields[\"status_code\"])) {\n\t\t\tfields[\"status\"] = 1\n\t\t} else {\n\t\t\tfields[\"status\"] = 0\n\t\t}\n\n\t\tdescription := ipmiFields[\"description\"]\n\n\t\t// handle hex description field\n\t\tif strings.HasPrefix(description, \"0x\") {\n\t\t\tdescriptionInt, err := strconv.ParseInt(description, 0, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfields[\"value\"] = float64(descriptionInt)\n\t\t} else if strings.Index(description, \" \") > 0 {\n\t\t\t// split middle column into value and unit\n\t\t\tvalunit := strings.SplitN(description, \" \", 2)\n\t\t\tvar err error\n\t\t\tfields[\"value\"], err = aToFloat(valunit[0])\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(valunit) > 1 {\n\t\t\t\ttags[\"unit\"] = transform(valunit[1])\n\t\t\t}\n\t\t} else {\n\t\t\tfields[\"value\"] = 0.0\n\t\t}\n\n\t\tacc.AddFields(\"ipmi_sensor\", fields, tags, measuredAt)\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (m *Ipmi) parseV2(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {\n\t// each line will look something like\n\t// CMOS Battery     | 65h | ok  |  7.1 |\n\t// Temp             | 0Eh | ok  |  3.1 | 55 degrees C\n\t// Drive 0          | A0h | ok  |  7.1 | Drive Present\n\tscanner := bufio.NewScanner(bytes.NewReader(cmdOut))\n\tfor scanner.Scan() {\n\t\tipmiFields := m.extractFieldsFromRegex(reV2ParseLine, scanner.Text())\n\t\tif len(ipmiFields) < 3 || len(ipmiFields) > 4 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"name\": transform(ipmiFields[\"name\"]),\n\t\t}\n\n\t\t// tag the server is we have one\n\t\tif hostname != \"\" {\n\t\t\ttags[\"server\"] = hostname\n\t\t}\n\t\ttags[\"entity_id\"] = transform(ipmiFields[\"entity_id\"])\n\t\ttags[\"status_code\"] = trim(ipmiFields[\"status_code\"])\n\t\tfields := make(map[string]interface{})\n\t\tdescriptionResults := m.extractFieldsFromRegex(reV2ParseDescription, trim(ipmiFields[\"description\"]))\n\t\t// This is an analog value with a unit\n\t\tif descriptionResults[\"analogValue\"] != \"\" && len(descriptionResults[\"analogUnit\"]) >= 1 {\n\t\t\tvar err error\n\t\t\tfields[\"value\"], err = aToFloat(descriptionResults[\"analogValue\"])\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Some implementations add an extra status to their analog units\n\t\t\tunitResults := m.extractFieldsFromRegex(reV2ParseUnit, descriptionResults[\"analogUnit\"])\n\t\t\ttags[\"unit\"] = transform(unitResults[\"realAnalogUnit\"])\n\t\t\tif unitResults[\"statusDesc\"] != \"\" {\n\t\t\t\ttags[\"status_desc\"] = transform(unitResults[\"statusDesc\"])\n\t\t\t}\n\t\t} else {\n\t\t\t// This is a status value\n\t\t\tfields[\"value\"] = 0.0\n\t\t\t// Extended status descriptions aren't required, in which case for consistency re-use the status code\n\t\t\tif descriptionResults[\"status\"] != \"\" {\n\t\t\t\ttags[\"status_desc\"] = transform(descriptionResults[\"status\"])\n\t\t\t} else {\n\t\t\t\ttags[\"status_desc\"] = transform(ipmiFields[\"status_code\"])\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"ipmi_sensor\", fields, tags, measuredAt)\n\t}\n\n\treturn scanner.Err()\n}\n\n// extractFieldsFromRegex consumes a regex with named capture groups and returns a kvp map of strings with the results\nfunc (m *Ipmi) extractFieldsFromRegex(re *regexp.Regexp, input string) map[string]string {\n\tsubmatches := re.FindStringSubmatch(input)\n\tresults := make(map[string]string)\n\tsubexpNames := re.SubexpNames()\n\tif len(subexpNames) > len(submatches) {\n\t\tm.Log.Debugf(\"No matches found in %q\", input)\n\t\treturn results\n\t}\n\tfor i, name := range subexpNames {\n\t\tif name != input && name != \"\" && input != \"\" {\n\t\t\tresults[name] = trim(submatches[i])\n\t\t}\n\t}\n\treturn results\n}\n\n// aToFloat converts string representations of numbers to float64 values\nfunc aToFloat(val string) (float64, error) {\n\tf, err := strconv.ParseFloat(val, 64)\n\tif err != nil {\n\t\treturn 0.0, err\n\t}\n\treturn f, nil\n}\n\nfunc sanitizeIPMICmd(args []string) []string {\n\tfor i, v := range args {\n\t\tif v == \"-P\" {\n\t\t\targs[i+1] = \"REDACTED\"\n\t\t}\n\t}\n\n\treturn args\n}\n\nfunc trim(s string) string {\n\treturn strings.TrimSpace(s)\n}\n\nfunc transform(s string) string {\n\ts = trim(s)\n\ts = strings.ToLower(s)\n\treturn strings.ReplaceAll(s, \" \", \"_\")\n}\n\nfunc init() {\n\tinputs.Add(\"ipmi_sensor\", func() telegraf.Input {\n\t\treturn &Ipmi{Timeout: config.Duration(20 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/ipmi_sensor_test.go",
    "content": "package ipmi_sensor\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\ti := &Ipmi{\n\t\tServers:   []string{\"USERID:PASSW0RD@lan(192.168.1.1)\"},\n\t\tPath:      \"ipmitool\",\n\t\tPrivilege: \"USER\",\n\t\tTimeout:   config.Duration(time.Second * 5),\n\t\tHexKey:    \"1234567F\",\n\t\tLog:       testutil.Logger{},\n\t}\n\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommand\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, i.Init())\n\trequire.NoError(t, acc.GatherError(i.Gather))\n\trequire.EqualValues(t, 262, acc.NFields(), \"non-numeric measurements should be ignored\")\n\n\tconn := newConnection(i.Servers[0], i.Privilege, i.HexKey)\n\trequire.EqualValues(t, \"USERID\", conn.username)\n\trequire.EqualValues(t, \"lan\", conn.intf)\n\trequire.EqualValues(t, \"1234567F\", conn.hexKey)\n\n\tvar testsWithServer = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(20),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"ambient_temp\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"degrees_c\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(80),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"altitude\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"feet\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(210),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"avg_power\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"watts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(4.9),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"planar_5v\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"volts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(3.05),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"planar_vbat\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"volts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(2610),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"fan_1a_tach\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"rpm\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(1775),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"fan_1b_tach\",\n\t\t\t\t\"server\": \"192.168.1.1\",\n\t\t\t\t\"unit\":   \"rpm\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range testsWithServer {\n\t\tacc.AssertContainsTaggedFields(t, \"ipmi_sensor\", test.fields, test.tags)\n\t}\n\n\ti = &Ipmi{\n\t\tPath:    \"ipmitool\",\n\t\tTimeout: config.Duration(time.Second * 5),\n\t\tLog:     testutil.Logger{},\n\t}\n\n\trequire.NoError(t, i.Init())\n\trequire.NoError(t, acc.GatherError(i.Gather))\n\n\tvar testsWithoutServer = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(20),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"ambient_temp\",\n\t\t\t\t\"unit\": \"degrees_c\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(80),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"altitude\",\n\t\t\t\t\"unit\": \"feet\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(210),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"avg_power\",\n\t\t\t\t\"unit\": \"watts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(4.9),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"planar_5v\",\n\t\t\t\t\"unit\": \"volts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(3.05),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"planar_vbat\",\n\t\t\t\t\"unit\": \"volts\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(2610),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"fan_1a_tach\",\n\t\t\t\t\"unit\": \"rpm\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":  float64(1775),\n\t\t\t\t\"status\": 1,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\": \"fan_1b_tach\",\n\t\t\t\t\"unit\": \"rpm\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range testsWithoutServer {\n\t\tacc.AssertContainsTaggedFields(t, \"ipmi_sensor\", test.fields, test.tags)\n\t}\n}\n\n// fakeExecCommand is a helper function that mock\n// the exec.Command call (and call the test binary)\nfunc fakeExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestHelperProcess\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\n// TestHelperProcess isn't a real test. It's used to mock exec.Command\n// For example, if you run:\n// GO_WANT_HELPER_PROCESS=1 go test -test.run=TestHelperProcess -- chrony tracking\n// it returns below mockData.\nfunc TestHelperProcess(_ *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\tmockData := `Ambient Temp     | 20 degrees C      | ok\nAltitude         | 80 feet           | ok\nAvg Power        | 210 Watts         | ok\nPlanar 3.3V      | 3.29 Volts        | ok\nPlanar 5V        | 4.90 Volts        | ok\nPlanar 12V       | 12.04 Volts       | ok\nPlanar VBAT      | 3.05 Volts        | ok\nFan 1A Tach      | 2610 RPM          | ok\nFan 1B Tach      | 1775 RPM          | ok\nFan 2A Tach      | 2001 RPM          | ok\nFan 2B Tach      | 1275 RPM          | ok\nFan 3A Tach      | 2929 RPM          | ok\nFan 3B Tach      | 2125 RPM          | ok\nFan 1            | 0x00              | ok\nFan 2            | 0x00              | ok\nFan 3            | 0x00              | ok\nFront Panel      | 0x00              | ok\nVideo USB        | 0x00              | ok\nDASD Backplane 1 | 0x00              | ok\nSAS Riser        | 0x00              | ok\nPCI Riser 1      | 0x00              | ok\nPCI Riser 2      | 0x00              | ok\nCPU 1            | 0x00              | ok\nCPU 2            | 0x00              | ok\nAll CPUs         | 0x00              | ok\nOne of The CPUs  | 0x00              | ok\nIOH Temp Status  | 0x00              | ok\nCPU 1 OverTemp   | 0x00              | ok\nCPU 2 OverTemp   | 0x00              | ok\nCPU Fault Reboot | 0x00              | ok\nAux Log          | 0x00              | ok\nNMI State        | 0x00              | ok\nABR Status       | 0x00              | ok\nFirmware Error   | 0x00              | ok\nPCIs             | 0x00              | ok\nCPUs             | 0x00              | ok\nDIMMs            | 0x00              | ok\nSys Board Fault  | 0x00              | ok\nPower Supply 1   | 0x00              | ok\nPower Supply 2   | 0x00              | ok\nPS 1 Fan Fault   | 0x00              | ok\nPS 2 Fan Fault   | 0x00              | ok\nVT Fault         | 0x00              | ok\nPwr Rail A Fault | 0x00              | ok\nPwr Rail B Fault | 0x00              | ok\nPwr Rail C Fault | 0x00              | ok\nPwr Rail D Fault | 0x00              | ok\nPwr Rail E Fault | 0x00              | ok\nPS 1 Therm Fault | 0x00              | ok\nPS 2 Therm Fault | 0x00              | ok\nPS1 12V OV Fault | 0x00              | ok\nPS2 12V OV Fault | 0x00              | ok\nPS1 12V UV Fault | 0x00              | ok\nPS2 12V UV Fault | 0x00              | ok\nPS1 12V OC Fault | 0x00              | ok\nPS2 12V OC Fault | 0x00              | ok\nPS 1 VCO Fault   | 0x00              | ok\nPS 2 VCO Fault   | 0x00              | ok\nPower Unit       | 0x00              | ok\nCooling Zone 1   | 0x00              | ok\nCooling Zone 2   | 0x00              | ok\nCooling Zone 3   | 0x00              | ok\nDrive 0          | 0x00              | ok\nDrive 1          | 0x00              | ok\nDrive 2          | 0x00              | ok\nDrive 3          | 0x00              | ok\nDrive 4          | 0x00              | ok\nDrive 5          | 0x00              | ok\nDrive 6          | 0x00              | ok\nDrive 7          | 0x00              | ok\nDrive 8          | 0x00              | ok\nDrive 9          | 0x00              | ok\nDrive 10         | 0x00              | ok\nDrive 11         | 0x00              | ok\nDrive 12         | 0x00              | ok\nDrive 13         | 0x00              | ok\nDrive 14         | 0x00              | ok\nDrive 15         | 0x00              | ok\nAll DIMMS        | 0x00              | ok\nOne of the DIMMs | 0x00              | ok\nDIMM 1           | 0x00              | ok\nDIMM 2           | 0x00              | ok\nDIMM 3           | 0x00              | ok\nDIMM 4           | 0x00              | ok\nDIMM 5           | 0x00              | ok\nDIMM 6           | 0x00              | ok\nDIMM 7           | 0x00              | ok\nDIMM 8           | 0x00              | ok\nDIMM 9           | 0x00              | ok\nDIMM 10          | 0x00              | ok\nDIMM 11          | 0x00              | ok\nDIMM 12          | 0x00              | ok\nDIMM 13          | 0x00              | ok\nDIMM 14          | 0x00              | ok\nDIMM 15          | 0x00              | ok\nDIMM 16          | 0x00              | ok\nDIMM 17          | 0x00              | ok\nDIMM 18          | 0x00              | ok\nDIMM 1 Temp      | 0x00              | ok\nDIMM 2 Temp      | 0x00              | ok\nDIMM 3 Temp      | 0x00              | ok\nDIMM 4 Temp      | 0x00              | ok\nDIMM 5 Temp      | 0x00              | ok\nDIMM 6 Temp      | 0x00              | ok\nDIMM 7 Temp      | 0x00              | ok\nDIMM 8 Temp      | 0x00              | ok\nDIMM 9 Temp      | 0x00              | ok\nDIMM 10 Temp     | 0x00              | ok\nDIMM 11 Temp     | 0x00              | ok\nDIMM 12 Temp     | 0x00              | ok\nDIMM 13 Temp     | 0x00              | ok\nDIMM 14 Temp     | 0x00              | ok\nDIMM 15 Temp     | 0x00              | ok\nDIMM 16 Temp     | 0x00              | ok\nDIMM 17 Temp     | 0x00              | ok\nDIMM 18 Temp     | 0x00              | ok\nPCI 1            | 0x00              | ok\nPCI 2            | 0x00              | ok\nPCI 3            | 0x00              | ok\nPCI 4            | 0x00              | ok\nAll PCI Error    | 0x00              | ok\nOne of PCI Error | 0x00              | ok\nIPMI Watchdog    | 0x00              | ok\nHost Power       | 0x00              | ok\nDASD Backplane 2 | 0x00              | ok\nDASD Backplane 3 | Not Readable      | ns\nDASD Backplane 4 | Not Readable      | ns\nBackup Memory    | 0x00              | ok\nProgress         | 0x00              | ok\nPlanar Fault     | 0x00              | ok\nSEL Fullness     | 0x00              | ok\nPCI 5            | 0x00              | ok\nOS RealTime Mod  | 0x00              | ok\n`\n\n\targs := os.Args\n\n\t// Previous arguments are tests stuff, that looks like :\n\t// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --\n\tcmd := args[3]\n\n\t// Ignore the returned errors for the mocked interface as tests will fail anyway\n\tif cmd != \"ipmitool\" {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\tfmt.Fprint(os.Stdout, mockData)\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n\nfunc TestGatherV2(t *testing.T) {\n\ti := &Ipmi{\n\t\tServers:       []string{\"USERID:PASSW0RD@lan(192.168.1.1)\"},\n\t\tPath:          \"ipmitool\",\n\t\tPrivilege:     \"USER\",\n\t\tTimeout:       config.Duration(time.Second * 5),\n\t\tMetricVersion: 2,\n\t\tHexKey:        \"0000000F\",\n\t\tLog:           testutil.Logger{},\n\t}\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommandV2\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, i.Init())\n\trequire.NoError(t, acc.GatherError(i.Gather))\n\n\tconn := newConnection(i.Servers[0], i.Privilege, i.HexKey)\n\trequire.EqualValues(t, \"USERID\", conn.username)\n\trequire.EqualValues(t, \"lan\", conn.intf)\n\trequire.EqualValues(t, \"0000000F\", conn.hexKey)\n\n\tvar testsWithServer = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t// SEL              | 72h | ns  |  7.1 | No Reading\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"sel\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ns\",\n\t\t\t\t\"status_desc\": \"no_reading\",\n\t\t\t\t\"server\":      \"192.168.1.1\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range testsWithServer {\n\t\tacc.AssertContainsTaggedFields(t, \"ipmi_sensor\", test.fields, test.tags)\n\t}\n\n\ti = &Ipmi{\n\t\tPath:          \"ipmitool\",\n\t\tTimeout:       config.Duration(time.Second * 5),\n\t\tMetricVersion: 2,\n\t\tLog:           testutil.Logger{},\n\t}\n\n\trequire.NoError(t, i.Init())\n\trequire.NoError(t, acc.GatherError(i.Gather))\n\n\tvar testsWithoutServer = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t// SEL              | 72h | ns  |  7.1 | No Reading\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"sel\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ns\",\n\t\t\t\t\"status_desc\": \"no_reading\",\n\t\t\t},\n\t\t},\n\t\t// Intrusion        | 73h | ok  |  7.1 |\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"intrusion\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"status_desc\": \"ok\",\n\t\t\t},\n\t\t},\n\t\t// Fan1             | 30h | ok  |  7.1 | 5040 RPM\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(5040),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"fan1\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"unit\":        \"rpm\",\n\t\t\t},\n\t\t},\n\t\t// Inlet Temp       | 04h | ok  |  7.1 | 25 degrees C\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(25),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"inlet_temp\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"unit\":        \"degrees_c\",\n\t\t\t},\n\t\t},\n\t\t// USB Cable Pres   | 50h | ok  |  7.1 | Connected\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"usb_cable_pres\",\n\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"status_desc\": \"connected\",\n\t\t\t},\n\t\t},\n\t\t// Current 1        | 6Ah | ok  | 10.1 | 7.20 Amps\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(7.2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"current_1\",\n\t\t\t\t\"entity_id\":   \"10.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"unit\":        \"amps\",\n\t\t\t},\n\t\t},\n\t\t// Power Supply 1   | 03h | ok  | 10.1 | 110 Watts, Presence detected\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": float64(110),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":        \"power_supply_1\",\n\t\t\t\t\"entity_id\":   \"10.1\",\n\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\"unit\":        \"watts\",\n\t\t\t\t\"status_desc\": \"presence_detected\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range testsWithoutServer {\n\t\tacc.AssertContainsTaggedFields(t, \"ipmi_sensor\", test.fields, test.tags)\n\t}\n}\n\n// fakeExecCommandV2 is a helper function that mock\n// the exec.Command call (and call the test binary)\nfunc fakeExecCommandV2(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestHelperProcessV2\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\n// TestHelperProcessV2 isn't a real test. It's used to mock exec.Command\n// For example, if you run:\n// GO_WANT_HELPER_PROCESS=1 go test -test.run=TestHelperProcessV2 -- chrony tracking\n// it returns below mockData.\nfunc TestHelperProcessV2(_ *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\t// Curated list of use cases instead of full dumps\n\tmockData := `SEL              | 72h | ns  |  7.1 | No Reading\nIntrusion        | 73h | ok  |  7.1 |\nFan1             | 30h | ok  |  7.1 | 5040 RPM\nInlet Temp       | 04h | ok  |  7.1 | 25 degrees C\nUSB Cable Pres   | 50h | ok  |  7.1 | Connected\nCurrent 1        | 6Ah | ok  | 10.1 | 7.20 Amps\nPower Supply 1   | 03h | ok  | 10.1 | 110 Watts, Presence detected\n`\n\n\targs := os.Args\n\n\t// Previous arguments are tests stuff, that looks like :\n\t// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --\n\tcmd := args[3]\n\n\t// Ignore the returned errors for the mocked interface as tests will fail anyway\n\tif cmd != \"ipmitool\" {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\tfmt.Fprint(os.Stdout, mockData)\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n\nfunc TestExtractFields(t *testing.T) {\n\tv1Data := `Ambient Temp     | 20 degrees C      | ok\nAltitude         | 80 feet           | ok\nAvg Power        | 210 Watts         | ok\nPlanar 3.3V      | 3.29 Volts        | ok\nPlanar 5V        | 4.90 Volts        | ok\nPlanar 12V       | 12.04 Volts       | ok\nB                | 0x00              | ok\nUnable to send command: Invalid argument\nECC Corr Err     | Not Readable      | ns\nUnable to send command: Invalid argument\nECC Uncorr Err   | Not Readable      | ns\nUnable to send command: Invalid argument\n`\n\n\tv2Data := `SEL              | 72h | ns  |  7.1 | No Reading\nIntrusion        | 73h | ok  |  7.1 |\nFan1             | 30h | ok  |  7.1 | 5040 RPM\nInlet Temp       | 04h | ok  |  7.1 | 25 degrees C\nUSB Cable Pres   | 50h | ok  |  7.1 | Connected\nUnable to send command: Invalid argument\nCurrent 1        | 6Ah | ok  | 10.1 | 7.20 Amps\nUnable to send command: Invalid argument\nPower Supply 1   | 03h | ok  | 10.1 | 110 Watts, Presence detected\n`\n\n\ttests := []string{\n\t\tv1Data,\n\t\tv2Data,\n\t}\n\n\tipmi := &Ipmi{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tfor i := range tests {\n\t\tt.Logf(\"Checking v%d data...\", i+1)\n\t\tipmi.extractFieldsFromRegex(reV1ParseLine, tests[i])\n\t\tipmi.extractFieldsFromRegex(reV2ParseLine, tests[i])\n\t}\n}\n\nfunc Test_parseV1(t *testing.T) {\n\ttype args struct {\n\t\thostname   string\n\t\tcmdOut     []byte\n\t\tmeasuredAt time.Time\n\t}\n\ttests := []struct {\n\t\tname       string\n\t\targs       args\n\t\twantFields map[string]interface{}\n\t\twantErr    bool\n\t}{\n\t\t{\n\t\t\tname: \"Test correct V1 parsing with hex code\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t\tcmdOut:     []byte(\"PS1 Status       | 0x02              | ok\"),\n\t\t\t},\n\t\t\twantFields: map[string]interface{}{\"value\": float64(2), \"status\": 1},\n\t\t\twantErr:    false,\n\t\t},\n\t\t{\n\t\t\tname: \"Test correct V1 parsing with value with unit\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t\tcmdOut:     []byte(\"Avg Power        | 210 Watts         | ok\"),\n\t\t\t},\n\t\t\twantFields: map[string]interface{}{\"value\": float64(210), \"status\": 1},\n\t\t\twantErr:    false,\n\t\t},\n\t}\n\n\tipmi := &Ipmi{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\tif err := ipmi.parseV1(&acc, tt.args.hostname, tt.args.cmdOut, tt.args.measuredAt); (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"parseV1() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t}\n\n\t\t\tacc.AssertContainsFields(t, \"ipmi_sensor\", tt.wantFields)\n\t\t})\n\t}\n}\n\nfunc Test_parseV2(t *testing.T) {\n\ttype args struct {\n\t\thostname   string\n\t\tcmdOut     []byte\n\t\tmeasuredAt time.Time\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\targs     args\n\t\texpected []telegraf.Metric\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tname: \"Test correct V2 parsing with analog value with unit\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tcmdOut:     []byte(\"Power Supply 1   | 03h | ok  | 10.1 | 110 Watts, Presence detected\"),\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":        \"power_supply_1\",\n\t\t\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\t\t\"server\":      \"host\",\n\t\t\t\t\t\t\"entity_id\":   \"10.1\",\n\t\t\t\t\t\t\"unit\":        \"watts\",\n\t\t\t\t\t\t\"status_desc\": \"presence_detected\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 110.0},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Test correct V2 parsing without analog value\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tcmdOut:     []byte(\"Intrusion        | 73h | ok  |  7.1 |\"),\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":        \"intrusion\",\n\t\t\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\t\t\"server\":      \"host\",\n\t\t\t\t\t\t\"entity_id\":   \"7.1\",\n\t\t\t\t\t\t\"status_desc\": \"ok\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 0.0},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"parse negative value\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tcmdOut:     []byte(\"DIMM Thrm Mrgn 1 | B0h | ok  |  8.1 | -55 degrees C\"),\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":        \"dimm_thrm_mrgn_1\",\n\t\t\t\t\t\t\"status_code\": \"ok\",\n\t\t\t\t\t\t\"server\":      \"host\",\n\t\t\t\t\t\t\"entity_id\":   \"8.1\",\n\t\t\t\t\t\t\"unit\":        \"degrees_c\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": -55.0},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t}\n\n\tipmi := &Ipmi{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tif err := ipmi.parseV2(&acc, tt.args.hostname, tt.args.cmdOut, tt.args.measuredAt); (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"parseV2() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc Test_parsePowerStatus(t *testing.T) {\n\ttype args struct {\n\t\thostname   string\n\t\tcmdOut     []byte\n\t\tmeasuredAt time.Time\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\targs     args\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"Test correct parse power status off\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tcmdOut:     []byte(\"Chassis Power is off\"),\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":   \"chassis_power_status\",\n\t\t\t\t\t\t\"server\": \"host\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 0},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Test correct parse power status on\",\n\t\t\targs: args{\n\t\t\t\thostname:   \"host\",\n\t\t\t\tcmdOut:     []byte(\"Chassis Power is on\"),\n\t\t\t\tmeasuredAt: time.Now(),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":   \"chassis_power_status\",\n\t\t\t\t\t\t\"server\": \"host\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 1},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr := parseChassisPowerStatus(&acc, tt.args.hostname, tt.args.cmdOut, tt.args.measuredAt)\n\t\t\trequire.NoError(t, err)\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc Test_parsePowerReading(t *testing.T) {\n\toutput := `Instantaneous power reading:                   167 Watts\nMinimum during sampling period:                124 Watts\nMaximum during sampling period:                422 Watts\nAverage power reading over sample period:      156 Watts\nIPMI timestamp:                           Mon Aug  1 21:22:51 2016\nSampling period:                          00699043 Seconds.\nPower reading state is:                   activated\n`\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"instantaneous_power_reading\",\n\t\t\t\t\"server\": \"host\",\n\t\t\t\t\"unit\":   \"watts\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": float64(167)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"minimum_during_sampling_period\",\n\t\t\t\t\"server\": \"host\",\n\t\t\t\t\"unit\":   \"watts\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": float64(124)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"maximum_during_sampling_period\",\n\t\t\t\t\"server\": \"host\",\n\t\t\t\t\"unit\":   \"watts\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": float64(422)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"ipmi_sensor\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":   \"average_power_reading_over_sample_period\",\n\t\t\t\t\"server\": \"host\",\n\t\t\t\t\"unit\":   \"watts\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": float64(156)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tipmi := &Ipmi{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := ipmi.parseDCMIPowerReading(&acc, \"host\", []byte(output), time.Now())\n\trequire.NoError(t, err)\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestSanitizeIPMICmd(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\targs     []string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"default args\",\n\t\t\targs: []string{\n\t\t\t\t\"-H\", \"localhost\",\n\t\t\t\t\"-U\", \"username\",\n\t\t\t\t\"-P\", \"password\",\n\t\t\t\t\"-I\", \"lan\",\n\t\t\t},\n\t\t\texpected: []string{\n\t\t\t\t\"-H\", \"localhost\",\n\t\t\t\t\"-U\", \"username\",\n\t\t\t\t\"-P\", \"REDACTED\",\n\t\t\t\t\"-I\", \"lan\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no password\",\n\t\t\targs: []string{\n\t\t\t\t\"-H\", \"localhost\",\n\t\t\t\t\"-U\", \"username\",\n\t\t\t\t\"-I\", \"lan\",\n\t\t\t},\n\t\t\texpected: []string{\n\t\t\t\t\"-H\", \"localhost\",\n\t\t\t\t\"-U\", \"username\",\n\t\t\t\t\"-I\", \"lan\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty args\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tsanitizedArgs := sanitizeIPMICmd(tt.args)\n\t\t\trequire.Equal(t, tt.expected, sanitizedArgs)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ipmi_sensor/sample.conf",
    "content": "# Read metrics from the bare metal servers via IPMI\n[[inputs.ipmi_sensor]]\n  ## Specify the path to the ipmitool executable\n  # path = \"/usr/bin/ipmitool\"\n\n  ## Use sudo\n  ## Setting 'use_sudo' to true will make use of sudo to run ipmitool.\n  ## Sudo must be configured to allow the telegraf user to run ipmitool\n  ## without a password.\n  # use_sudo = false\n\n  ## Servers\n  ## Specify one or more servers via a url. If no servers are specified, local\n  ## machine sensor stats will be queried. Uses the format:\n  ##  [username[:password]@][protocol[(address)]]\n  ##  e.g. root:passwd@lan(127.0.0.1)\n  # servers = [\"USERID:PASSW0RD@lan(192.168.1.1)\"]\n\n  ## Session privilege level\n  ## Choose from: CALLBACK, USER, OPERATOR, ADMINISTRATOR\n  # privilege = \"ADMINISTRATOR\"\n\n  ## Timeout\n  ## Timeout for the ipmitool command to complete.\n  # timeout = \"20s\"\n\n  ## Metric schema version\n  ## See the plugin readme for more information on schema versioning.\n  # metric_version = 1\n\n  ## Sensors to collect\n  ## Choose from:\n  ##   * sdr: default, collects sensor data records\n  ##   * chassis_power_status: collects the power status of the chassis\n  ##   * dcmi_power_reading: collects the power readings from the Data Center Management Interface\n  # sensors = [\"sdr\"]\n\n  ## Hex key\n  ## Optionally provide the hex key for the IMPI connection.\n  # hex_key = \"\"\n\n  ## Cache\n  ## If ipmitool should use a cache\n  ## Using a cache can speed up collection times depending on your device.\n  # use_cache = false\n\n  ## Path to the ipmitools cache file (defaults to OS temp dir)\n  ## The provided path must exist and must be writable\n  # cache_path = \"\"\n"
  },
  {
    "path": "plugins/inputs/ipset/README.md",
    "content": "# Ipset Input Plugin\n\nThis plugin gathers packets and bytes counters from [Linux IP sets][ipsets]\nusing the `ipset` command line tool.\n\n> [!NOTE]\n> IP sets created without the \"counters\" option are ignored.\n\n⭐ Telegraf v1.6.0\n🏷️ network, system\n💻 linux\n\n[ipsets]: https://ipset.netfilter.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather packets and bytes counters from Linux ipsets\n  [[inputs.ipset]]\n    ## By default, we only show sets which have already matched at least 1 packet.\n    ## set include_unmatched_sets = true to gather them all.\n    # include_unmatched_sets = false\n\n    ## Adjust your sudo settings appropriately if using this option (\"sudo ipset save\")\n    ## You can avoid using sudo or root, by setting appropriate privileges for\n    ## the telegraf.service systemd service.\n    # use_sudo = false\n\n    ## Add number of entries and number of individual IPs (resolve CIDR syntax) for each ipset\n    # count_per_ip_entries = false\n\n    ## The default timeout of 1s for ipset execution can be overridden here:\n    # timeout = \"1s\"\n```\n\n### Permissions\n\nThere are 3 ways to grant telegraf the right to run ipset:\n\n- Run as root (strongly discouraged)\n- Use sudo\n- Configure systemd to run telegraf with CAP_NET_ADMIN and CAP_NET_RAW\n  capabilities\n\n#### Using sudo\n\nTo use sudo set the `use_sudo` option to `true` and update your sudoers file:\n\n```bash\n$ visudo\n# Add the following line:\nCmnd_Alias IPSETSAVE = /sbin/ipset save\ntelegraf  ALL=(root) NOPASSWD: IPSETSAVE\nDefaults!IPSETSAVE !logfile, !syslog, !pam_session\n```\n\n#### Using systemd capabilities\n\nYou may run `systemctl edit telegraf.service` and add the following:\n\n```text\n[Service]\nCapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN\nAmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN\n```\n\n## Metrics\n\n- ipset\n  - tags:\n    - rule\n    - set\n  - fields:\n    - timeout\n    - packets\n    - bytes\n\n- ipset (for `count_per_ip_entries = true`)\n  - tags:\n    - set\n  - fields:\n    - entries\n    - ips\n\n## Example Output\n\n```sh\n$ sudo ipset save\ncreate myset hash:net family inet hashsize 1024 maxelem 65536 counters comment\nadd myset 10.69.152.1 packets 8 bytes 672 comment \"machine A\"\n```\n\n```text\nipset,rule=10.69.152.1,host=trashme,set=myset bytes_total=8i,packets_total=672i 1507615028000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ipset/ipset.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ipset\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar defaultTimeout = config.Duration(time.Second)\n\nconst measurement = \"ipset\"\n\ntype Ipset struct {\n\tIncludeUnmatchedSets bool            `toml:\"include_unmatched_sets\"`\n\tUseSudo              bool            `toml:\"use_sudo\"`\n\tTimeout              config.Duration `toml:\"timeout\"`\n\tCountPerIPEntries    bool\n\n\tlister        setLister\n\tentriesParser ipsetEntries\n}\n\ntype setLister func(Timeout config.Duration, UseSudo bool) (*bytes.Buffer, error)\n\nfunc (*Ipset) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (*Ipset) Init() error {\n\t_, err := exec.LookPath(\"ipset\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (i *Ipset) Gather(acc telegraf.Accumulator) error {\n\tout, e := i.lister(i.Timeout, i.UseSudo)\n\tif e != nil {\n\t\tacc.AddError(e)\n\t}\n\n\tscanner := bufio.NewScanner(out)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif i.CountPerIPEntries {\n\t\t\tacc.AddError(i.entriesParser.addLine(line, acc))\n\t\t}\n\n\t\t// Ignore sets created without the \"counters\" option\n\t\tnocomment := strings.Split(line, \"\\\"\")[0]\n\t\tif !strings.Contains(nocomment, \"packets\") || !strings.Contains(nocomment, \"bytes\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tdata := strings.Fields(line)\n\t\tif len(data) < 7 {\n\t\t\tacc.AddError(fmt.Errorf(\"error parsing line (expected at least 7 fields): %s\", line))\n\t\t\tcontinue\n\t\t}\n\t\tif data[0] == \"add\" && (data[4] != \"0\" || i.IncludeUnmatchedSets) {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"set\":  data[1],\n\t\t\t\t\"rule\": data[2],\n\t\t\t}\n\n\t\t\tfields := make(map[string]interface{}, 3)\n\t\t\tfor i, field := range data {\n\t\t\t\tswitch field {\n\t\t\t\tcase \"timeout\":\n\t\t\t\t\tval, err := strconv.ParseUint(data[i+1], 10, 64)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t}\n\t\t\t\t\tfields[\"timeout\"] = val\n\t\t\t\tcase \"packets\":\n\t\t\t\t\tval, err := strconv.ParseUint(data[i+1], 10, 64)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t}\n\t\t\t\t\tfields[\"packets_total\"] = val\n\t\t\t\tcase \"bytes\":\n\t\t\t\t\tval, err := strconv.ParseUint(data[i+1], 10, 64)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tacc.AddError(err)\n\t\t\t\t\t}\n\t\t\t\t\tfields[\"bytes_total\"] = val\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tacc.AddCounter(measurement, fields, tags)\n\t\t}\n\t}\n\n\ti.entriesParser.commit(acc)\n\n\treturn nil\n}\n\nfunc setList(timeout config.Duration, useSudo bool) (*bytes.Buffer, error) {\n\t// Is ipset installed ?\n\tipsetPath, err := exec.LookPath(\"ipset\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar args []string\n\tcmdName := ipsetPath\n\tif useSudo {\n\t\tcmdName = \"sudo\"\n\t\targs = append(args, ipsetPath)\n\t}\n\targs = append(args, \"save\")\n\n\tcmd := exec.Command(cmdName, args...)\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr = internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn &out, fmt.Errorf(\"error running ipset save: %w\", err)\n\t}\n\n\treturn &out, nil\n}\n\nfunc init() {\n\tinputs.Add(\"ipset\", func() telegraf.Input {\n\t\treturn &Ipset{\n\t\t\tlister:  setList,\n\t\t\tTimeout: defaultTimeout,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ipset/ipset_entries.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ipset\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype ipsetEntries struct {\n\tinitialized bool\n\tsetName     string\n\tentries     int\n\tips         int\n}\n\nfunc getCountInCidr(cidr string) (int, error) {\n\t_, ipNet, err := net.ParseCIDR(cidr)\n\tif err != nil {\n\t\t// check if single IP\n\t\tif net.ParseIP(cidr) == nil {\n\t\t\treturn 0, errors.New(\"invalid IP address format. Not CIDR format and not a single IP address\")\n\t\t}\n\t\treturn 1, nil // Single IP has only one address\n\t}\n\n\tones, bits := ipNet.Mask.Size()\n\tif ones == 0 && bits == 0 {\n\t\treturn 0, errors.New(\"invalid CIDR range\")\n\t}\n\tnumIps := 1 << (bits - ones)\n\n\t// exclude network and broadcast addresses if IPv4 and range > /31\n\tif bits == 32 && numIps > 2 {\n\t\tnumIps -= 2\n\t}\n\n\treturn numIps, nil\n}\n\nfunc (counter *ipsetEntries) addLine(line string, acc telegraf.Accumulator) error {\n\tdata := strings.Fields(line)\n\tif len(data) < 3 {\n\t\treturn fmt.Errorf(\"error parsing line (expected at least 3 fields): %s\", line)\n\t}\n\n\tswitch data[0] {\n\tcase \"create\":\n\t\tcounter.commit(acc)\n\t\tcounter.initialized = true\n\t\tcounter.setName = data[1]\n\t\tcounter.entries = 0\n\t\tcounter.ips = 0\n\tcase \"add\":\n\t\tcounter.entries++\n\t\tcount, err := getCountInCidr(data[2])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcounter.ips += count\n\t}\n\treturn nil\n}\n\nfunc (counter *ipsetEntries) commit(acc telegraf.Accumulator) {\n\tif !counter.initialized {\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"entries\": counter.entries,\n\t\t\"ips\":     counter.ips,\n\t}\n\n\ttags := map[string]string{\n\t\t\"set\": counter.setName,\n\t}\n\n\tacc.AddGauge(measurement, fields, tags)\n\n\t// reset counter and prepare for next usage\n\tcounter.initialized = false\n}\n"
  },
  {
    "path": "plugins/inputs/ipset/ipset_entries_test.go",
    "content": "package ipset\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIpsetEntries(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tlines := []string{\n\t\t\"create mylist hash:net family inet hashsize 16384 maxelem 131072 timeout 300 bucketsize 12 initval 0x4effa9ad\",\n\t\t\"add mylist 89.101.238.143 timeout 161558\",\n\t\t\"add mylist 122.224.15.166 timeout 186758\",\n\t\t\"add mylist 47.128.40.145 timeout 431559\",\n\t}\n\n\tentries := ipsetEntries{}\n\tfor _, line := range lines {\n\t\trequire.NoError(t, entries.addLine(line, &acc))\n\t}\n\tentries.commit(&acc)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"ipset\",\n\t\t\tmap[string]string{\n\t\t\t\t\"set\": \"mylist\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entries\": 3,\n\t\t\t\t\"ips\":     3,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestIpsetEntriesCidr(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tlines := []string{\n\t\t\"create mylist0 hash:net family inet hashsize 16384 maxelem 131072 timeout 300 bucketsize 12 initval 0x4effa9ad\",\n\t\t\"add mylist0 89.101.238.143 timeout 161558\",\n\t\t\"add mylist0 122.224.5.0/24 timeout 186758\",\n\t\t\"add mylist0 47.128.40.145 timeout 431559\",\n\n\t\t\"create mylist1 hash:net family inet hashsize 16384 maxelem 131072 timeout 300 bucketsize 12 initval 0x4effa9ad\",\n\t\t\"add mylist1 90.101.238.143 timeout 161558\",\n\t\t\"add mylist1 44.128.40.145 timeout 431559\",\n\t\t\"add mylist1 122.224.5.0/8 timeout 186758\",\n\t\t\"add mylist1 45.128.40.145 timeout 431560\",\n\t}\n\n\tentries := ipsetEntries{}\n\tfor _, line := range lines {\n\t\trequire.NoError(t, entries.addLine(line, &acc))\n\t}\n\tentries.commit(&acc)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"ipset\",\n\t\t\tmap[string]string{\n\t\t\t\t\"set\": \"mylist0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entries\": 3,\n\t\t\t\t\"ips\":     256,\n\t\t\t},\n\t\t\ttime.Now().Add(time.Millisecond*0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"ipset\",\n\t\t\tmap[string]string{\n\t\t\t\t\"set\": \"mylist1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"entries\": 4,\n\t\t\t\t\"ips\":     16777217,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/ipset/ipset_test.go",
    "content": "package ipset\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIpset(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tvalue  string\n\t\ttags   []map[string]string\n\t\tfields [][]map[string]interface{}\n\t\terr    error\n\t}{\n\t\t{\n\t\t\tname:  \"0 sets, no results\",\n\t\t\tvalue: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"Empty sets, no values\",\n\t\t\tvalue: `create myset hash:net family inet hashsize 1024 maxelem 65536\n\t\t\t\tcreate myset2 hash:net,port family inet hashsize 16384 maxelem 524288 counters comment\n\t\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tname: \"Non-empty sets, but no counters, no results\",\n\t\t\tvalue: `create myset hash:net family inet hashsize 1024 maxelem 65536\n\t\t\t\tadd myset 1.2.3.4\n\t\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tname: \"Line with data but not enough fields\",\n\t\t\tvalue: `create hash:net family inet hashsize 1024 maxelem 65536 counters\n\t\t\t\tadd myset 4.5.6.7 packets 123 bytes\n\t\t\t\t`,\n\t\t\terr: errors.New(\"error parsing line (expected at least 7 fields): \\t\\t\\t\\tadd myset 4.5.6.7 packets 123 bytes\"),\n\t\t},\n\t\t{\n\t\t\tname: \"Non-empty sets, counters, no comment\",\n\t\t\tvalue: `create myset hash:net family inet hashsize 1024 maxelem 65536 counters\n\t\t\t\tadd myset 1.2.3.4 packets 1328 bytes 79680\n\t\t\t\tadd myset 2.3.4.5 packets 0 bytes 0\n\t\t\t\tadd myset 3.4.5.6 packets 3 bytes 222\n\t\t\t\t`,\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"set\": \"myset\", \"rule\": \"1.2.3.4\"},\n\t\t\t\t{\"set\": \"myset\", \"rule\": \"3.4.5.6\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(1328), \"bytes_total\": uint64(79680)}},\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(3), \"bytes_total\": uint64(222)}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Sets with counters and comment\",\n\t\t\tvalue: `create myset hash:net family inet hashsize 1024 maxelem 65536 counters comment\n\t\t\t\tadd myset 1.2.3.4 packets 1328 bytes 79680 comment \"first IP\"\n\t\t\t\tadd myset 2.3.4.5 packets 0 bytes 0 comment \"2nd IP\"\n\t\t\t\tadd myset 3.4.5.6 packets 3 bytes 222 \"3rd IP\"\n\t\t\t\t`,\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"set\": \"myset\", \"rule\": \"1.2.3.4\"},\n\t\t\t\t{\"set\": \"myset\", \"rule\": \"3.4.5.6\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(1328), \"bytes_total\": uint64(79680)}},\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(3), \"bytes_total\": uint64(222)}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Sets with and without timeouts\",\n\t\t\tvalue: `create counter-test hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800 counters\n\t\t\t\tadd counter-test 192.168.1.1 timeout 1792 packets 8 bytes 672\n\t\t\t\tcreate counter-test2 hash:ip family inet hashsize 1024 maxelem 65536 counters\n\t\t\t\tadd counter-test2 192.168.1.1 packets 18 bytes 673\n\t\t\t\t`,\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"set\": \"counter-test\", \"rule\": \"192.168.1.1\"},\n\t\t\t\t{\"set\": \"counter-test2\", \"rule\": \"192.168.1.1\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(8), \"bytes_total\": uint64(672), \"timeout\": uint64(1792)}},\n\t\t\t\t{map[string]interface{}{\"packets_total\": uint64(18), \"bytes_total\": uint64(673)}},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ti++\n\t\t\tips := &Ipset{\n\t\t\t\tlister: func(config.Duration, bool) (*bytes.Buffer, error) {\n\t\t\t\t\treturn bytes.NewBufferString(tt.value), nil\n\t\t\t\t},\n\t\t\t}\n\t\t\tacc := new(testutil.Accumulator)\n\t\t\terr := acc.GatherError(ips.Gather)\n\t\t\tif !reflect.DeepEqual(tt.err, err) {\n\t\t\t\tt.Errorf(\"%d: expected error '%#v' got '%#v'\", i, tt.err, err)\n\t\t\t}\n\t\t\tif len(tt.tags) == 0 {\n\t\t\t\tn := acc.NFields()\n\t\t\t\tif n != 0 {\n\t\t\t\t\tt.Errorf(\"%d: expected 0 values got %d\", i, n)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tn := 0\n\t\t\tfor j, tags := range tt.tags {\n\t\t\t\tfor k, fields := range tt.fields[j] {\n\t\t\t\t\tif len(acc.Metrics) < n+1 {\n\t\t\t\t\t\tt.Errorf(\"%d: expected at least %d values got %d\", i, n+1, len(acc.Metrics))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tm := acc.Metrics[n]\n\t\t\t\t\tif !reflect.DeepEqual(m.Measurement, measurement) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected measurement '%#v' got '%#v'\\n\", i, j, k, measurement, m.Measurement)\n\t\t\t\t\t}\n\t\t\t\t\tif !reflect.DeepEqual(m.Tags, tags) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected tags\\n%#v got\\n%#v\\n\", i, j, k, tags, m.Tags)\n\t\t\t\t\t}\n\t\t\t\t\tif !reflect.DeepEqual(m.Fields, fields) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected fields\\n%#v got\\n%#v\\n\", i, j, k, fields, m.Fields)\n\t\t\t\t\t}\n\t\t\t\t\tn++\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestIpset_Gather_listerError(t *testing.T) {\n\terrFoo := errors.New(\"error foobar\")\n\tips := &Ipset{\n\t\tlister: func(config.Duration, bool) (*bytes.Buffer, error) {\n\t\t\treturn new(bytes.Buffer), errFoo\n\t\t},\n\t}\n\tacc := new(testutil.Accumulator)\n\terr := acc.GatherError(ips.Gather)\n\tif !reflect.DeepEqual(err, errFoo) {\n\t\tt.Errorf(\"Expected error %#v got\\n%#v\\n\", errFoo, err)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ipset/sample.conf",
    "content": "# Gather packets and bytes counters from Linux ipsets\n  [[inputs.ipset]]\n    ## By default, we only show sets which have already matched at least 1 packet.\n    ## set include_unmatched_sets = true to gather them all.\n    # include_unmatched_sets = false\n\n    ## Adjust your sudo settings appropriately if using this option (\"sudo ipset save\")\n    ## You can avoid using sudo or root, by setting appropriate privileges for\n    ## the telegraf.service systemd service.\n    # use_sudo = false\n\n    ## Add number of entries and number of individual IPs (resolve CIDR syntax) for each ipset\n    # count_per_ip_entries = false\n\n    ## The default timeout of 1s for ipset execution can be overridden here:\n    # timeout = \"1s\"\n"
  },
  {
    "path": "plugins/inputs/iptables/README.md",
    "content": "# Iptables Input Plugin\n\nThis plugin gathers packets and bytes counters for rules within a set of table\nand chain from the Linux's iptables firewall.\n\n> [!IMPORTANT]\n> Rules are identified through associated comment, so you must ensure that the\n> rules you want to monitor do have a **unique** comment using the `--comment`\n> flag when adding them. Rules without comments are ignored.\n\nThe rule number cannot be used as identifier as it is not constant and\nmay vary when rules are inserted/deleted at start-up or by automatic tools\n(interactive firewalls, fail2ban, ...).\n\n> [!IMPORTANT]\n> The `iptables` command requires `CAP_NET_ADMIN` and `CAP_NET_RAW`\n> capabilities. Check the [permissions section](#permissions) for ways to\n> grant them.\n\n⭐ Telegraf v1.1.0\n🏷️ network, system\n💻 linux\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather packets and bytes throughput from iptables\n# This plugin ONLY supports Linux\n[[inputs.iptables]]\n  ## iptables require root access on most systems.\n  ## Setting 'use_sudo' to true will make use of sudo to run iptables.\n  ## Users must configure sudo to allow telegraf user to run iptables with\n  ## no password.\n  ## iptables can be restricted to only list command \"iptables -nvL\".\n  # use_sudo = false\n\n  ## Setting 'use_lock' to true runs iptables with the \"-w\" option.\n  ## Adjust your sudo settings appropriately if using this option\n  ## (\"iptables -w 5 -nvl\")\n  # use_lock = false\n\n  ## Define an alternate executable, such as \"ip6tables\". Default is \"iptables\".\n  # binary = \"ip6tables\"\n  ## defines the table to monitor:\n  table = \"filter\"\n\n  ## defines the chains to monitor.\n  ## NOTE: iptables rules without a comment will not be monitored.\n  ## Read the plugin documentation for more information.\n  chains = [ \"INPUT\" ]\n```\n\n### Permissions\n\nThe `iptables` command requires `CAP_NET_ADMIN` and `CAP_NET_RAW capabilities`.\nYou have several options to grant permissions to telegraf:\n\n- Run telegraf as root. This is strongly discouraged.\n- Configure systemd to run telegraf with CAP_NET_ADMIN and CAP_NET_RAW. This is\n  the simplest and recommended option.\n- Configure sudo to grant telegraf to run iptables. This is the most\n  restrictive option, but require sudo setup.\n\n#### Using systemd capabilities\n\nYou may run `systemctl edit telegraf.service` and add the following:\n\n```shell\n[Service]\nCapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN\nAmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN\n```\n\nSince telegraf will fork a process to run iptables, `AmbientCapabilities` is\nrequired to transmit the capabilities bounding set to the forked process.\n\n#### Using sudo\n\nTo use sudo set the `use_sudo` option to `true` and update your sudoers file:\n\n```bash\n$ visudo\n# Add the following line:\nCmnd_Alias IPTABLESSHOW = /usr/bin/iptables -nvL *\ntelegraf  ALL=(root) NOPASSWD: IPTABLESSHOW\nDefaults!IPTABLESSHOW !logfile, !syslog, !pam_session\n```\n\n### Using IPtables lock feature\n\nDefining multiple instances of this plugin in telegraf.conf can lead to\nconcurrent IPtables access resulting in \"ERROR in input [inputs.iptables]: exit\nstatus 4\" messages in telegraf.log and missing metrics. Setting 'use_lock =\ntrue' in the plugin configuration will run IPtables with the '-w' switch,\nallowing a lock usage to prevent this error.\n\n## Metrics\n\n- iptables\n  - tags:\n    - table\n    - chain\n    - ruleid (comment associated to the rule)\n  - fields:\n    - pkts (integer, count)\n    - bytes (integer, bytes)\n\n## Example Output\n\n```shell\niptables -nvL INPUT\n```\n\n```text\nChain INPUT (policy DROP 0 packets, 0 bytes)\npkts bytes target     prot opt in     out     source               destination\n100   1024   ACCEPT     tcp  --  *      *       192.168.0.0/24       0.0.0.0/0            tcp dpt:22 /* ssh */\n 42   2048   ACCEPT     tcp  --  *      *       192.168.0.0/24       0.0.0.0/0            tcp dpt:80 /* httpd */\n```\n\n```text\niptables,table=filter,chain=INPUT,ruleid=ssh pkts=100i,bytes=1024i 1453831884664956455\niptables,table=filter,chain=INPUT,ruleid=httpd pkts=42i,bytes=2048i 1453831884664956455\n```\n"
  },
  {
    "path": "plugins/inputs/iptables/iptables.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage iptables\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\terrParse       = errors.New(\"cannot parse iptables list information\")\n\tchainNameRe    = regexp.MustCompile(`^Chain\\s+(\\S+)`)\n\tfieldsHeaderRe = regexp.MustCompile(`^\\s*pkts\\s+bytes\\s+target`)\n\tvaluesRe       = regexp.MustCompile(`^\\s*(\\d+)\\s+(\\d+)\\s+(\\w+).*?/\\*\\s*(.+?)\\s*\\*/\\s*`)\n)\n\nconst measurement = \"iptables\"\n\ntype Iptables struct {\n\tUseSudo bool     `toml:\"use_sudo\"`\n\tUseLock bool     `toml:\"use_lock\"`\n\tBinary  string   `toml:\"binary\"`\n\tTable   string   `toml:\"table\"`\n\tChains  []string `toml:\"chains\"`\n\n\tlister chainLister\n}\n\ntype chainLister func(table, chain string) (string, error)\n\nfunc (*Iptables) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ipt *Iptables) Gather(acc telegraf.Accumulator) error {\n\tif ipt.Table == \"\" || len(ipt.Chains) == 0 {\n\t\treturn nil\n\t}\n\t// best effort : we continue through the chains even if an error is encountered,\n\t// but we keep track of the last error.\n\tfor _, chain := range ipt.Chains {\n\t\tdata, e := ipt.lister(ipt.Table, chain)\n\t\tif e != nil {\n\t\t\tacc.AddError(e)\n\t\t\tcontinue\n\t\t}\n\t\te = ipt.parseAndGather(data, acc)\n\t\tif e != nil {\n\t\t\tacc.AddError(e)\n\t\t\tcontinue\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ipt *Iptables) chainList(table, chain string) (string, error) {\n\tvar binary string\n\tif ipt.Binary != \"\" {\n\t\tbinary = ipt.Binary\n\t} else {\n\t\tbinary = \"iptables\"\n\t}\n\tiptablePath, err := exec.LookPath(binary)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tvar args []string\n\tname := iptablePath\n\tif ipt.UseSudo {\n\t\tname = \"sudo\"\n\t\targs = append(args, iptablePath)\n\t}\n\tif ipt.UseLock {\n\t\targs = append(args, \"-w\", \"5\")\n\t}\n\targs = append(args, \"-nvL\", chain, \"-t\", table, \"-x\")\n\tc := exec.Command(name, args...)\n\tout, err := c.Output()\n\treturn string(out), err\n}\n\nfunc (ipt *Iptables) parseAndGather(data string, acc telegraf.Accumulator) error {\n\tlines := strings.Split(data, \"\\n\")\n\tif len(lines) < 3 {\n\t\treturn nil\n\t}\n\tmchain := chainNameRe.FindStringSubmatch(lines[0])\n\tif mchain == nil {\n\t\treturn errParse\n\t}\n\tif !fieldsHeaderRe.MatchString(lines[1]) {\n\t\treturn errParse\n\t}\n\tfor _, line := range lines[2:] {\n\t\tmatches := valuesRe.FindStringSubmatch(line)\n\t\tif len(matches) != 5 {\n\t\t\tcontinue\n\t\t}\n\n\t\tpkts := matches[1]\n\t\tbytes := matches[2]\n\t\ttarget := matches[3]\n\t\tcomment := matches[4]\n\n\t\ttags := map[string]string{\"table\": ipt.Table, \"chain\": mchain[1], \"target\": target, \"ruleid\": comment}\n\t\tfields := make(map[string]interface{})\n\n\t\tvar err error\n\t\tfields[\"pkts\"], err = strconv.ParseUint(pkts, 10, 64)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tfields[\"bytes\"], err = strconv.ParseUint(bytes, 10, 64)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tacc.AddFields(measurement, fields, tags)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"iptables\", func() telegraf.Input {\n\t\tipt := &Iptables{}\n\t\tipt.lister = ipt.chainList\n\t\treturn ipt\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/iptables/iptables_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage iptables\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Iptables struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Iptables) SampleConfig() string { return sampleConfig }\n\nfunc (i *Iptables) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Iptables) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"iptables\", func() telegraf.Input {\n\t\treturn &Iptables{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/iptables/iptables_test.go",
    "content": "//go:build linux\n\npackage iptables\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIptables_Gather(t *testing.T) {\n\ttests := []struct {\n\t\ttable  string\n\t\tchains []string\n\t\tvalues []string\n\t\ttags   []map[string]string\n\t\tfields [][]map[string]interface{}\n\t\terr    error\n\t}{\n\t\t{ // 1 - no configured table => no results\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                `},\n\t\t},\n\t\t{ // 2 - no configured chains => no results\n\t\t\ttable: \"filter\",\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                `},\n\t\t},\n\t\t{ // 3 - pkts and bytes are gathered as integers\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0   /* foobar */\n\t\t                `},\n\t\t\ttags: []map[string]string{{\"table\": \"filter\", \"chain\": \"INPUT\", \"target\": \"RETURN\", \"ruleid\": \"foobar\"}},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(57), \"bytes\": uint64(4520)}},\n\t\t\t},\n\t\t},\n\t\t{ // 4 - missing fields header => no results\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)`},\n\t\t},\n\t\t{ // 5 - invalid chain header => error\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{\n\t\t\t\t`INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                `},\n\t\t\terr: errParse,\n\t\t},\n\t\t{ // 6 - invalid fields header => error\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\n\t\t                57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                `},\n\t\t\terr: errParse,\n\t\t},\n\t\t{ // 7 - invalid integer value => best effort, no error\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                K     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n            `},\n\t\t},\n\t\t{ // 8 - Multiple rows, multiple chains => no error\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\", \"FORWARD\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                100     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                200     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0  /* foo */\n\t\t                `,\n\t\t\t\t`Chain FORWARD (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t                300     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0  /* bar */\n\t\t                400     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0\n\t\t                500     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0 /* foobar */\n\t\t                `,\n\t\t\t},\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"table\": \"filter\", \"chain\": \"INPUT\", \"target\": \"RETURN\", \"ruleid\": \"foo\"},\n\t\t\t\t{\"table\": \"filter\", \"chain\": \"FORWARD\", \"target\": \"RETURN\", \"ruleid\": \"bar\"},\n\t\t\t\t{\"table\": \"filter\", \"chain\": \"FORWARD\", \"target\": \"RETURN\", \"ruleid\": \"foobar\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(200), \"bytes\": uint64(4520)}},\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(300), \"bytes\": uint64(4520)}},\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(500), \"bytes\": uint64(4520)}},\n\t\t\t},\n\t\t},\n\t\t{ // 9 - comments are used as ruleid if any\n\t\t\ttable:  \"filter\",\n\t\t\tchains: []string{\"INPUT\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n                        57     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0             tcp dpt:22 /* foobar */\n                        100     4520 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0    tcp dpt:80\n\t\t                `},\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"table\": \"filter\", \"chain\": \"INPUT\", \"target\": \"RETURN\", \"ruleid\": \"foobar\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(57), \"bytes\": uint64(4520)}},\n\t\t\t},\n\t\t},\n\t\t{ // 10 - allow trailing text\n\t\t\ttable:  \"mangle\",\n\t\t\tchains: []string{\"SHAPER\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain SHAPER (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t\t\t\t\t0 0 ACCEPT all -- * * 1.3.5.7 0.0.0.0/0 /* test */\n\t\t\t\t\t\t0 0 CLASSIFY all -- * * 1.3.5.7 0.0.0.0/0 /* test2 */ CLASSIFY set 1:4\n\t\t\t\t\t\t`},\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"table\": \"mangle\", \"chain\": \"SHAPER\", \"target\": \"ACCEPT\", \"ruleid\": \"test\"},\n\t\t\t\t{\"table\": \"mangle\", \"chain\": \"SHAPER\", \"target\": \"CLASSIFY\", \"ruleid\": \"test2\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(0), \"bytes\": uint64(0)}},\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(0), \"bytes\": uint64(0)}},\n\t\t\t},\n\t\t},\n\t\t{ // 11 - invalid pkts/bytes\n\t\t\ttable:  \"mangle\",\n\t\t\tchains: []string{\"SHAPER\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain SHAPER (policy ACCEPT 58 packets, 5096 bytes)\n\t\t                pkts      bytes target     prot opt in     out     source               destination\n\t\t\t\t\t\ta a ACCEPT all -- * * 1.3.5.7 0.0.0.0/0 /* test */\n\t\t\t\t\t\ta a CLASSIFY all -- * * 1.3.5.7 0.0.0.0/0 /* test2 */ CLASSIFY set 1:4\n\t\t\t\t\t\t`},\n\t\t},\n\t\t{ // 11 - all target and ports\n\t\t\ttable:  \"all_recv\",\n\t\t\tchains: []string{\"accountfwd\"},\n\t\t\tvalues: []string{\n\t\t\t\t`Chain accountfwd (1 references)\n\t\t\t\t\t\tpkts bytes target prot opt in   out source    destination\n\t\t\t\t\t\t 123   456        all  --  eth0 *   0.0.0.0/0 0.0.0.0/0   /* all_recv */\n\t\t               `},\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"table\": \"all_recv\", \"chain\": \"accountfwd\", \"target\": \"all\", \"ruleid\": \"all_recv\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"pkts\": uint64(123), \"bytes\": uint64(456)}},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.table, func(t *testing.T) {\n\t\t\ti++\n\t\t\tipt := &Iptables{\n\t\t\t\tTable:  tt.table,\n\t\t\t\tChains: tt.chains,\n\t\t\t\tlister: func(string, string) (string, error) {\n\t\t\t\t\tif len(tt.values) > 0 {\n\t\t\t\t\t\tv := tt.values[0]\n\t\t\t\t\t\ttt.values = tt.values[1:]\n\t\t\t\t\t\treturn v, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn \"\", nil\n\t\t\t\t},\n\t\t\t}\n\t\t\tacc := new(testutil.Accumulator)\n\t\t\terr := acc.GatherError(ipt.Gather)\n\t\t\tif !reflect.DeepEqual(tt.err, err) {\n\t\t\t\tt.Errorf(\"%d: expected error '%#v' got '%#v'\", i, tt.err, err)\n\t\t\t}\n\t\t\tif tt.table == \"\" {\n\t\t\t\tn := acc.NFields()\n\t\t\t\tif n != 0 {\n\t\t\t\t\tt.Errorf(\"%d: expected 0 fields if empty table got %d\", i, n)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif len(tt.chains) == 0 {\n\t\t\t\tn := acc.NFields()\n\t\t\t\tif n != 0 {\n\t\t\t\t\tt.Errorf(\"%d: expected 0 fields if empty chains got %d\", i, n)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif len(tt.tags) == 0 {\n\t\t\t\tn := acc.NFields()\n\t\t\t\tif n != 0 {\n\t\t\t\t\tt.Errorf(\"%d: expected 0 values got %d\", i, n)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tn := 0\n\t\t\tfor j, tags := range tt.tags {\n\t\t\t\tfor k, fields := range tt.fields[j] {\n\t\t\t\t\tif len(acc.Metrics) < n+1 {\n\t\t\t\t\t\tt.Errorf(\"%d: expected at least %d values got %d\", i, n+1, len(acc.Metrics))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tm := acc.Metrics[n]\n\t\t\t\t\tif !reflect.DeepEqual(m.Measurement, measurement) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected measurement '%#v' got '%#v'\\n\", i, j, k, measurement, m.Measurement)\n\t\t\t\t\t}\n\t\t\t\t\tif !reflect.DeepEqual(m.Tags, tags) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected tags\\n%#v got\\n%#v\\n\", i, j, k, tags, m.Tags)\n\t\t\t\t\t}\n\t\t\t\t\tif !reflect.DeepEqual(m.Fields, fields) {\n\t\t\t\t\t\tt.Errorf(\"%d %d %d: expected fields\\n%#v got\\n%#v\\n\", i, j, k, fields, m.Fields)\n\t\t\t\t\t}\n\t\t\t\t\tn++\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestIptables_Gather_listerError(t *testing.T) {\n\terrFoo := errors.New(\"error foobar\")\n\tipt := &Iptables{\n\t\tTable:  \"nat\",\n\t\tChains: []string{\"foo\", \"bar\"},\n\t\tlister: func(string, string) (string, error) {\n\t\t\treturn \"\", errFoo\n\t\t},\n\t}\n\tacc := new(testutil.Accumulator)\n\terr := acc.GatherError(ipt.Gather)\n\tif !reflect.DeepEqual(err, errFoo) {\n\t\tt.Errorf(\"Expected error %#v got\\n%#v\\n\", errFoo, err)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/iptables/sample.conf",
    "content": "# Gather packets and bytes throughput from iptables\n# This plugin ONLY supports Linux\n[[inputs.iptables]]\n  ## iptables require root access on most systems.\n  ## Setting 'use_sudo' to true will make use of sudo to run iptables.\n  ## Users must configure sudo to allow telegraf user to run iptables with\n  ## no password.\n  ## iptables can be restricted to only list command \"iptables -nvL\".\n  # use_sudo = false\n\n  ## Setting 'use_lock' to true runs iptables with the \"-w\" option.\n  ## Adjust your sudo settings appropriately if using this option\n  ## (\"iptables -w 5 -nvl\")\n  # use_lock = false\n\n  ## Define an alternate executable, such as \"ip6tables\". Default is \"iptables\".\n  # binary = \"ip6tables\"\n  ## defines the table to monitor:\n  table = \"filter\"\n\n  ## defines the chains to monitor.\n  ## NOTE: iptables rules without a comment will not be monitored.\n  ## Read the plugin documentation for more information.\n  chains = [ \"INPUT\" ]\n"
  },
  {
    "path": "plugins/inputs/ipvs/README.md",
    "content": "# IPVS Input Plugin\n\nThis plugin gathers metrics about the [IPVS virtual and real servers][ipvs]\nusing the netlink socket interface of the Linux kernel.\n\n> [!IMPORTANT]\n> The plugin requires `CAP_NET_ADMIN` and `CAP_NET_RAW` capabilities.\n> Check the [permissions section](#permissions) for ways to grant them.\n\n⭐ Telegraf v1.9.0\n🏷️ network, system\n💻 linux\n\n[ipvs]: http://www.linuxvirtualserver.org/software/ipvs.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect virtual and real server stats from Linux IPVS\n# This plugin ONLY supports Linux\n[[inputs.ipvs]]\n  # no configuration\n```\n\n### Permissions\n\nAssuming you installed the Telegraf package via one of the published packages,\nthe process will be running as the `telegraf` user. However, in order for this\nplugin to communicate over netlink sockets it needs the telegraf process to have\n`CAP_NET_ADMIN` and `CAP_NET_RAW` capabilities.\n\nThis is the case when running Telegraf as `root` or some user with\n`CAP_NET_ADMIN` and `CAP_NET_RAW`. Alternatively, you can add the capabilities\nwhen starting Telegraf via systemd by running `systemctl edit telegraf.service`\nand add the following:\n\n```shell\n[Service]\nCapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN\nAmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN\n```\n\n## Metrics\n\nServer will contain tags identifying how it was configured, using one of\n`address` + `port` + `protocol` *OR* `fwmark`. This is how one would normally\nconfigure a virtual server using `ipvsadm`.\n\n- ipvs_virtual_server\n  - tags:\n    - sched (the scheduler in use)\n    - netmask (the mask used for determining affinity)\n    - address_family (inet/inet6)\n    - address\n    - port\n    - protocol\n    - fwmark\n  - fields:\n    - connections\n    - pkts_in\n    - pkts_out\n    - bytes_in\n    - bytes_out\n    - pps_in\n    - pps_out\n    - cps\n\n- ipvs_real_server\n  - tags:\n    - address\n    - port\n    - address_family (inet/inet6)\n    - virtual_address\n    - virtual_port\n    - virtual_protocol\n    - virtual_fwmark\n  - fields:\n    - active_connections\n    - inactive_connections\n    - connections\n    - pkts_in\n    - pkts_out\n    - bytes_in\n    - bytes_out\n    - pps_in\n    - pps_out\n    - cps\n\n## Example Output\n\nVirtual server is configured using `fwmark` and backed by 2 real servers:\n\n```text\nipvs_virtual_server,address=172.18.64.234,address_family=inet,netmask=32,port=9000,protocol=tcp,sched=rr bytes_in=0i,bytes_out=0i,pps_in=0i,pps_out=0i,cps=0i,connections=0i,pkts_in=0i,pkts_out=0i 1541019340000000000\nipvs_real_server,address=172.18.64.220,address_family=inet,port=9000,virtual_address=172.18.64.234,virtual_port=9000,virtual_protocol=tcp active_connections=0i,inactive_connections=0i,pkts_in=0i,bytes_out=0i,pps_out=0i,connections=0i,pkts_out=0i,bytes_in=0i,pps_in=0i,cps=0i 1541019340000000000\nipvs_real_server,address=172.18.64.219,address_family=inet,port=9000,virtual_address=172.18.64.234,virtual_port=9000,virtual_protocol=tcp active_connections=0i,inactive_connections=0i,pps_in=0i,pps_out=0i,connections=0i,pkts_in=0i,pkts_out=0i,bytes_in=0i,bytes_out=0i,cps=0i 1541019340000000000\n```\n\nVirtual server is configured using `proto+addr+port` and backed by 2 real\nservers:\n\n```text\nipvs_virtual_server,address_family=inet,fwmark=47,netmask=32,sched=rr cps=0i,connections=0i,pkts_in=0i,pkts_out=0i,bytes_in=0i,bytes_out=0i,pps_in=0i,pps_out=0i 1541019340000000000\nipvs_real_server,address=172.18.64.220,address_family=inet,port=9000,virtual_fwmark=47 inactive_connections=0i,pkts_out=0i,bytes_out=0i,pps_in=0i,cps=0i,active_connections=0i,pkts_in=0i,bytes_in=0i,pps_out=0i,connections=0i 1541019340000000000\nipvs_real_server,address=172.18.64.219,address_family=inet,port=9000,virtual_fwmark=47 cps=0i,active_connections=0i,inactive_connections=0i,connections=0i,pkts_in=0i,bytes_out=0i,pkts_out=0i,bytes_in=0i,pps_in=0i,pps_out=0i 1541019340000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ipvs/ipvs.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage ipvs\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"math/bits\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/moby/ipvs\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/logrus\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype IPVS struct {\n\tLog    telegraf.Logger `toml:\"-\"`\n\thandle *ipvs.Handle\n}\n\nfunc (*IPVS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (i *IPVS) Gather(acc telegraf.Accumulator) error {\n\tif i.handle == nil {\n\t\th, err := ipvs.New(\"\") // TODO: make the namespace configurable\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to open IPVS handle: %w\", err)\n\t\t}\n\t\ti.handle = h\n\t}\n\n\tservices, err := i.handle.GetServices()\n\tif err != nil {\n\t\ti.handle.Close()\n\t\ti.handle = nil // trigger a reopen on next call to gather\n\t\treturn fmt.Errorf(\"failed to list IPVS services: %w\", err)\n\t}\n\tfor _, s := range services {\n\t\tfields := map[string]interface{}{\n\t\t\t\"connections\": s.Stats.Connections,\n\t\t\t\"pkts_in\":     s.Stats.PacketsIn,\n\t\t\t\"pkts_out\":    s.Stats.PacketsOut,\n\t\t\t\"bytes_in\":    s.Stats.BytesIn,\n\t\t\t\"bytes_out\":   s.Stats.BytesOut,\n\t\t\t\"pps_in\":      s.Stats.PPSIn,\n\t\t\t\"pps_out\":     s.Stats.PPSOut,\n\t\t\t\"cps\":         s.Stats.CPS,\n\t\t}\n\t\tacc.AddGauge(\"ipvs_virtual_server\", fields, serviceTags(s))\n\n\t\tdestinations, err := i.handle.GetDestinations(s)\n\t\tif err != nil {\n\t\t\ti.Log.Errorf(\"Failed to list destinations for a virtual server: %v\", err)\n\t\t\tcontinue // move on to the next virtual server\n\t\t}\n\n\t\tfor _, d := range destinations {\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"active_connections\":   d.ActiveConnections,\n\t\t\t\t\"inactive_connections\": d.InactiveConnections,\n\t\t\t\t\"connections\":          d.Stats.Connections,\n\t\t\t\t\"pkts_in\":              d.Stats.PacketsIn,\n\t\t\t\t\"pkts_out\":             d.Stats.PacketsOut,\n\t\t\t\t\"bytes_in\":             d.Stats.BytesIn,\n\t\t\t\t\"bytes_out\":            d.Stats.BytesOut,\n\t\t\t\t\"pps_in\":               d.Stats.PPSIn,\n\t\t\t\t\"pps_out\":              d.Stats.PPSOut,\n\t\t\t\t\"cps\":                  d.Stats.CPS,\n\t\t\t}\n\t\t\tdestTags := destinationTags(d)\n\t\t\tif s.FWMark > 0 {\n\t\t\t\tdestTags[\"virtual_fwmark\"] = strconv.Itoa(int(s.FWMark))\n\t\t\t} else {\n\t\t\t\tdestTags[\"virtual_protocol\"] = protocolToString(s.Protocol)\n\t\t\t\tdestTags[\"virtual_address\"] = s.Address.String()\n\t\t\t\tdestTags[\"virtual_port\"] = strconv.Itoa(int(s.Port))\n\t\t\t}\n\t\t\tacc.AddGauge(\"ipvs_real_server\", fields, destTags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// helper: given a Service, return tags that identify it\nfunc serviceTags(s *ipvs.Service) map[string]string {\n\tret := map[string]string{\n\t\t\"sched\":          s.SchedName,\n\t\t\"netmask\":        strconv.Itoa(bits.OnesCount32(s.Netmask)),\n\t\t\"address_family\": addressFamilyToString(s.AddressFamily),\n\t}\n\t// Per the ipvsadm man page, a virtual service is defined \"based on\n\t// protocol/addr/port or firewall mark\"\n\tif s.FWMark > 0 {\n\t\tret[\"fwmark\"] = strconv.Itoa(int(s.FWMark))\n\t} else {\n\t\tret[\"protocol\"] = protocolToString(s.Protocol)\n\t\tret[\"address\"] = s.Address.String()\n\t\tret[\"port\"] = strconv.Itoa(int(s.Port))\n\t}\n\treturn ret\n}\n\n// helper: given a Destination, return tags that identify it\nfunc destinationTags(d *ipvs.Destination) map[string]string {\n\treturn map[string]string{\n\t\t\"address\":        d.Address.String(),\n\t\t\"port\":           strconv.Itoa(int(d.Port)),\n\t\t\"address_family\": addressFamilyToString(d.AddressFamily),\n\t}\n}\n\n// helper: convert protocol uint16 to human-readable string (if possible)\nfunc protocolToString(p uint16) string {\n\tswitch p {\n\tcase syscall.IPPROTO_TCP:\n\t\treturn \"tcp\"\n\tcase syscall.IPPROTO_UDP:\n\t\treturn \"udp\"\n\tcase syscall.IPPROTO_SCTP:\n\t\treturn \"sctp\"\n\tdefault:\n\t\treturn strconv.FormatUint(uint64(p), 10)\n\t}\n}\n\n// helper: convert addressFamily to a human-readable string\nfunc addressFamilyToString(af uint16) string {\n\tswitch af {\n\tcase syscall.AF_INET:\n\t\treturn \"inet\"\n\tcase syscall.AF_INET6:\n\t\treturn \"inet6\"\n\tdefault:\n\t\treturn strconv.FormatUint(uint64(af), 10)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"ipvs\", func() telegraf.Input {\n\t\tlogrus.InstallHook()\n\t\treturn &IPVS{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ipvs/ipvs_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage ipvs\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Ipvs struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Ipvs) SampleConfig() string { return sampleConfig }\n\nfunc (i *Ipvs) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Ipvs) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"ipvs\", func() telegraf.Input {\n\t\treturn &Ipvs{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ipvs/sample.conf",
    "content": "# Collect virtual and real server stats from Linux IPVS\n# This plugin ONLY supports Linux\n[[inputs.ipvs]]\n  # no configuration\n"
  },
  {
    "path": "plugins/inputs/jenkins/README.md",
    "content": "# Jenkins Input Plugin\n\nThis plugin gathers information about the nodes and jobs running in a\n[Jenkins][jenkins] instance. The plugin uses the Jenkins API and does not\nrequire a plugin on the server.\n\n⭐ Telegraf v1.9.0\n🏷️ applications\n💻 all\n\n[jenkins]: https://www.jenkins.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read jobs and cluster metrics from Jenkins instances\n[[inputs.jenkins]]\n  ## The Jenkins URL in the format \"schema://host:port\"\n  url = \"http://my-jenkins-instance:8080\"\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Set response_timeout\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use SSL but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional Max Job Build Age filter\n  ## Default 1 hour, ignore builds older than max_build_age\n  # max_build_age = \"1h\"\n\n  ## Optional Sub Job Depth filter\n  ## Jenkins can have unlimited layer of sub jobs\n  ## This config will limit the layers of pulling, default value 0 means\n  ## unlimited pulling until no more sub jobs\n  # max_subjob_depth = 0\n\n  ## Optional Sub Job Per Layer\n  ## In workflow-multibranch-plugin, each branch will be created as a sub job.\n  ## This config will limit to call only the lasted branches in each layer,\n  ## empty will use default value 10\n  # max_subjob_per_layer = 10\n\n  ## Jobs to include or exclude from gathering\n  ## When using both lists, job_exclude has priority.\n  ## Wildcards are supported: [ \"jobA/*\", \"jobB/subjob1/*\"]\n  # job_include = [ \"*\" ]\n  # job_exclude = [ ]\n\n  ## Nodes to include or exclude from gathering\n  ## When using both lists, node_exclude has priority.\n  # node_include = [ \"*\" ]\n  # node_exclude = [ ]\n\n  ## Worker pool for jenkins plugin only\n  ## Empty this field will use default value 5\n  # max_connections = 5\n\n  ## When set to true will add node labels as a comma-separated tag. If none,\n  ## are found, then a tag with the value of 'none' is used. Finally, if a\n  ## label contains a comma it is replaced with an underscore.\n  # node_labels_as_tag = false\n```\n\n## Metrics\n\n- jenkins\n  - tags:\n    - source\n    - port\n  - fields:\n    - busy_executors\n    - total_executors\n\n- jenkins_node\n  - tags:\n    - arch\n    - disk_path\n    - temp_path\n    - node_name\n    - status (\"online\", \"offline\")\n    - source\n    - port\n  - fields:\n    - disk_available (Bytes)\n    - temp_available (Bytes)\n    - memory_available (Bytes)\n    - memory_total (Bytes)\n    - swap_available (Bytes)\n    - swap_total (Bytes)\n    - response_time (ms)\n    - num_executors\n\n- jenkins_job\n  - tags:\n    - name\n    - parents\n    - result\n    - source\n    - port\n  - fields:\n    - duration (ms)\n    - number\n    - result_code (0 = SUCCESS, 1 = FAILURE, 2 = NOT_BUILD, 3 = UNSTABLE, 4 = ABORTED)\n\n## Sample Queries\n\n```sql\nSELECT mean(\"memory_available\") AS \"mean_memory_available\", mean(\"memory_total\") AS \"mean_memory_total\", mean(\"temp_available\") AS \"mean_temp_available\" FROM \"jenkins_node\" WHERE time > now() - 15m GROUP BY time(:interval:) FILL(null)\n```\n\n```sql\nSELECT mean(\"duration\") AS \"mean_duration\" FROM \"jenkins_job\" WHERE time > now() - 24h GROUP BY time(:interval:) FILL(null)\n```\n\n## Example Output\n\n```text\njenkins,host=myhost,port=80,source=my-jenkins-instance busy_executors=4i,total_executors=8i 1580418261000000000\njenkins_node,arch=Linux\\ (amd64),disk_path=/var/jenkins_home,temp_path=/tmp,host=myhost,node_name=master,source=my-jenkins-instance,port=8080 swap_total=4294963200,memory_available=586711040,memory_total=6089498624,status=online,response_time=1000i,disk_available=152392036352,temp_available=152392036352,swap_available=3503263744,num_executors=2i 1516031535000000000\njenkins_job,host=myhost,name=JOB1,parents=apps/br1,result=SUCCESS,source=my-jenkins-instance,port=8080 duration=2831i,result_code=0i 1516026630000000000\njenkins_job,host=myhost,name=JOB2,parents=apps/br2,result=SUCCESS,source=my-jenkins-instance,port=8080 duration=2285i,result_code=0i 1516027230000000000\n```\n"
  },
  {
    "path": "plugins/inputs/jenkins/client.go",
    "content": "package jenkins\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nconst maxBuildsPerJob = 20\n\ntype client struct {\n\tbaseURL       string\n\thttpClient    *http.Client\n\tusername      string\n\tpassword      string\n\tsessionCookie *http.Cookie\n\tsemaphore     chan struct{}\n}\n\nfunc newClient(httpClient *http.Client, url, username, password string, maxConnections int) *client {\n\treturn &client{\n\t\tbaseURL:    url,\n\t\thttpClient: httpClient,\n\t\tusername:   username,\n\t\tpassword:   password,\n\t\tsemaphore:  make(chan struct{}, maxConnections),\n\t}\n}\n\nfunc (c *client) init() error {\n\t// get session cookie\n\treq, err := http.NewRequest(\"GET\", c.baseURL, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif c.username != \"\" || c.password != \"\" {\n\t\treq.SetBasicAuth(c.username, c.password)\n\t}\n\tresp, err := c.httpClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\tfor _, cc := range resp.Cookies() {\n\t\tif strings.Contains(cc.Name, \"JSESSIONID\") {\n\t\t\tc.sessionCookie = cc\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// first api fetch\n\treturn c.doGet(context.Background(), jobPath, new(jobResponse))\n}\n\nfunc (c *client) doGet(ctx context.Context, url string, v interface{}) error {\n\treq, err := createGetRequest(c.baseURL+url, c.username, c.password, c.sessionCookie)\n\tif err != nil {\n\t\treturn err\n\t}\n\tselect {\n\tcase c.semaphore <- struct{}{}:\n\t\tbreak\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\tresp, err := c.httpClient.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\t<-c.semaphore\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tresp.Body.Close()\n\t\t<-c.semaphore\n\t}()\n\t// Clear invalid token if unauthorized\n\tif resp.StatusCode == http.StatusUnauthorized {\n\t\tc.sessionCookie = nil\n\t\treturn apiError{\n\t\t\turl:        url,\n\t\t\tstatusCode: resp.StatusCode,\n\t\t\ttitle:      resp.Status,\n\t\t}\n\t}\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn apiError{\n\t\t\turl:        url,\n\t\t\tstatusCode: resp.StatusCode,\n\t\t\ttitle:      resp.Status,\n\t\t}\n\t}\n\tif resp.StatusCode == http.StatusNoContent {\n\t\treturn apiError{\n\t\t\turl:        url,\n\t\t\tstatusCode: resp.StatusCode,\n\t\t\ttitle:      resp.Status,\n\t\t}\n\t}\n\n\treturn json.NewDecoder(resp.Body).Decode(v)\n}\n\ntype apiError struct {\n\turl         string\n\tstatusCode  int\n\ttitle       string\n\tdescription string\n}\n\nfunc (e apiError) Error() string {\n\tif e.description != \"\" {\n\t\treturn fmt.Sprintf(\"[%s] %s: %s\", e.url, e.title, e.description)\n\t}\n\treturn fmt.Sprintf(\"[%s] %s\", e.url, e.title)\n}\n\nfunc createGetRequest(url, username, password string, sessionCookie *http.Cookie) (*http.Request, error) {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif username != \"\" || password != \"\" {\n\t\treq.SetBasicAuth(username, password)\n\t}\n\tif sessionCookie != nil {\n\t\treq.AddCookie(sessionCookie)\n\t}\n\treq.Header.Add(\"Accept\", \"application/json\")\n\treturn req, nil\n}\n\nfunc (c *client) getJobs(ctx context.Context, jr *jobRequest) (js *jobResponse, err error) {\n\tjs = new(jobResponse)\n\turl := jobPath\n\tif jr != nil {\n\t\turl = fmt.Sprintf(\"%s?tree=builds[number,url]{0,%d},lastBuild[number,url],jobs[name,url,color],name\", jr.url(), maxBuildsPerJob)\n\t}\n\terr = c.doGet(ctx, url, js)\n\treturn js, err\n}\n\nfunc (c *client) getBuild(ctx context.Context, jr jobRequest, number int64) (b *buildResponse, err error) {\n\tb = new(buildResponse)\n\turl := jr.buildURL(number)\n\terr = c.doGet(ctx, url, b)\n\treturn b, err\n}\n\nfunc (c *client) getAllNodes(ctx context.Context) (nodeResp *nodeResponse, err error) {\n\tnodeResp = new(nodeResponse)\n\terr = c.doGet(ctx, nodePath, nodeResp)\n\treturn nodeResp, err\n}\n"
  },
  {
    "path": "plugins/inputs/jenkins/jenkins.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage jenkins\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmeasurementJenkins = \"jenkins\"\n\tmeasurementNode    = \"jenkins_node\"\n\tmeasurementJob     = \"jenkins_job\"\n)\n\ntype Jenkins struct {\n\tURL      string `toml:\"url\"`\n\tUsername string `toml:\"username\"`\n\tPassword string `toml:\"password\"`\n\t// HTTP Timeout specified as a string - 3s, 1m, 1h\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\tsource          string\n\tport            string\n\n\tMaxConnections    int             `toml:\"max_connections\"`\n\tMaxBuildAge       config.Duration `toml:\"max_build_age\"`\n\tMaxSubJobDepth    int             `toml:\"max_subjob_depth\"`\n\tMaxSubJobPerLayer int             `toml:\"max_subjob_per_layer\"`\n\tNodeLabelsAsTag   bool            `toml:\"node_labels_as_tag\"`\n\tJobExclude        []string        `toml:\"job_exclude\"`\n\tJobInclude        []string        `toml:\"job_include\"`\n\tjobFilter         filter.Filter\n\n\tNodeExclude []string `toml:\"node_exclude\"`\n\tNodeInclude []string `toml:\"node_include\"`\n\tnodeFilter  filter.Filter\n\n\ttls.ClientConfig\n\tclient *client\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tsemaphore chan struct{}\n}\n\nfunc (*Jenkins) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (j *Jenkins) Gather(acc telegraf.Accumulator) error {\n\tif j.client == nil {\n\t\tclient, err := j.newHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := j.initialize(client); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tj.gatherNodesData(acc)\n\tj.gatherJobs(acc)\n\n\treturn nil\n}\n\nfunc (j *Jenkins) newHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := j.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parse jenkins config %q: %w\", j.URL, err)\n\t}\n\treturn &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t\tMaxIdleConns:    j.MaxConnections,\n\t\t},\n\t\tTimeout: time.Duration(j.ResponseTimeout),\n\t}, nil\n}\n\n// separate the client as dependency to use httptest Client for mocking\nfunc (j *Jenkins) initialize(client *http.Client) error {\n\tvar err error\n\n\t// init jenkins tags\n\tu, err := url.Parse(j.URL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif u.Port() == \"\" {\n\t\tif u.Scheme == \"http\" {\n\t\t\tj.port = \"80\"\n\t\t} else if u.Scheme == \"https\" {\n\t\t\tj.port = \"443\"\n\t\t}\n\t} else {\n\t\tj.port = u.Port()\n\t}\n\tj.source = u.Hostname()\n\n\t// init filters\n\tj.jobFilter, err = filter.NewIncludeExcludeFilter(j.JobInclude, j.JobExclude)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error compiling job filters %q: %w\", j.URL, err)\n\t}\n\tj.nodeFilter, err = filter.NewIncludeExcludeFilter(j.NodeInclude, j.NodeExclude)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error compiling node filters %q: %w\", j.URL, err)\n\t}\n\n\t// init tcp pool with default value\n\tif j.MaxConnections <= 0 {\n\t\tj.MaxConnections = 5\n\t}\n\n\t// default sub jobs can be acquired\n\tif j.MaxSubJobPerLayer <= 0 {\n\t\tj.MaxSubJobPerLayer = 10\n\t}\n\n\tj.semaphore = make(chan struct{}, j.MaxConnections)\n\n\tj.client = newClient(client, j.URL, j.Username, j.Password, j.MaxConnections)\n\n\treturn j.client.init()\n}\n\nfunc (j *Jenkins) gatherNodeData(n node, acc telegraf.Accumulator) error {\n\tif n.DisplayName == \"\" {\n\t\treturn errors.New(\"error empty node name\")\n\t}\n\n\ttags := map[string]string{\"node_name\": n.DisplayName}\n\n\t// filter out excluded or not included node_name\n\tif !j.nodeFilter.Match(tags[\"node_name\"]) {\n\t\treturn nil\n\t}\n\n\tmonitorData := n.MonitorData\n\n\tif monitorData.HudsonNodeMonitorsArchitectureMonitor != \"\" {\n\t\ttags[\"arch\"] = monitorData.HudsonNodeMonitorsArchitectureMonitor\n\t}\n\n\ttags[\"status\"] = \"online\"\n\tif n.Offline {\n\t\ttags[\"status\"] = \"offline\"\n\t}\n\n\ttags[\"source\"] = j.source\n\ttags[\"port\"] = j.port\n\n\tfields := make(map[string]interface{})\n\tfields[\"num_executors\"] = n.NumExecutors\n\n\tif j.NodeLabelsAsTag {\n\t\tlabels := make([]string, 0, len(n.AssignedLabels))\n\t\tfor _, label := range n.AssignedLabels {\n\t\t\tlabels = append(labels, strings.ReplaceAll(label.Name, \",\", \"_\"))\n\t\t}\n\n\t\tif len(labels) == 0 {\n\t\t\ttags[\"labels\"] = \"none\"\n\t\t} else {\n\t\t\tsort.Strings(labels)\n\t\t\ttags[\"labels\"] = strings.Join(labels, \",\")\n\t\t}\n\t}\n\n\tif monitorData.HudsonNodeMonitorsResponseTimeMonitor != nil {\n\t\tfields[\"response_time\"] = monitorData.HudsonNodeMonitorsResponseTimeMonitor.Average\n\t}\n\tif monitorData.HudsonNodeMonitorsDiskSpaceMonitor != nil {\n\t\ttags[\"disk_path\"] = monitorData.HudsonNodeMonitorsDiskSpaceMonitor.Path\n\t\tfields[\"disk_available\"] = monitorData.HudsonNodeMonitorsDiskSpaceMonitor.Size\n\t}\n\tif monitorData.HudsonNodeMonitorsTemporarySpaceMonitor != nil {\n\t\ttags[\"temp_path\"] = monitorData.HudsonNodeMonitorsTemporarySpaceMonitor.Path\n\t\tfields[\"temp_available\"] = monitorData.HudsonNodeMonitorsTemporarySpaceMonitor.Size\n\t}\n\tif monitorData.HudsonNodeMonitorsSwapSpaceMonitor != nil {\n\t\tfields[\"swap_available\"] = monitorData.HudsonNodeMonitorsSwapSpaceMonitor.SwapAvailable\n\t\tfields[\"memory_available\"] = monitorData.HudsonNodeMonitorsSwapSpaceMonitor.MemoryAvailable\n\t\tfields[\"swap_total\"] = monitorData.HudsonNodeMonitorsSwapSpaceMonitor.SwapTotal\n\t\tfields[\"memory_total\"] = monitorData.HudsonNodeMonitorsSwapSpaceMonitor.MemoryTotal\n\t}\n\tacc.AddFields(measurementNode, fields, tags)\n\n\treturn nil\n}\n\nfunc (j *Jenkins) gatherNodesData(acc telegraf.Accumulator) {\n\tnodeResp, err := j.client.getAllNodes(context.Background())\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\t// get total and busy executors\n\ttags := map[string]string{\"source\": j.source, \"port\": j.port}\n\tfields := make(map[string]interface{})\n\tfields[\"busy_executors\"] = nodeResp.BusyExecutors\n\tfields[\"total_executors\"] = nodeResp.TotalExecutors\n\n\tacc.AddFields(measurementJenkins, fields, tags)\n\n\t// get node data\n\tfor _, node := range nodeResp.Computers {\n\t\terr = j.gatherNodeData(node, acc)\n\t\tif err == nil {\n\t\t\tcontinue\n\t\t}\n\t\tacc.AddError(err)\n\t}\n}\n\nfunc (j *Jenkins) gatherJobs(acc telegraf.Accumulator) {\n\tjs, err := j.client.getJobs(context.Background(), nil)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tvar wg sync.WaitGroup\n\tfor _, job := range js.Jobs {\n\t\twg.Add(1)\n\t\tgo func(name string, wg *sync.WaitGroup, acc telegraf.Accumulator) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := j.getJobDetail(jobRequest{\n\t\t\t\tname:  name,\n\t\t\t\tlayer: 0,\n\t\t\t}, acc); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(job.Name, &wg, acc)\n\t}\n\twg.Wait()\n}\n\nfunc (j *Jenkins) getJobDetail(jr jobRequest, acc telegraf.Accumulator) error {\n\tif j.MaxSubJobDepth > 0 && jr.layer == j.MaxSubJobDepth {\n\t\treturn nil\n\t}\n\n\tjs, err := j.client.getJobs(context.Background(), &jr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor k, ij := range js.Jobs {\n\t\tif k < len(js.Jobs)-j.MaxSubJobPerLayer-1 {\n\t\t\tcontinue\n\t\t}\n\t\twg.Add(1)\n\t\t// schedule tcp fetch for inner jobs\n\t\tgo func(ij innerJob, jr jobRequest, acc telegraf.Accumulator) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := j.getJobDetail(jobRequest{\n\t\t\t\tname:    ij.Name,\n\t\t\t\tparents: jr.combined(),\n\t\t\t\tlayer:   jr.layer + 1,\n\t\t\t}, acc); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(ij, jr, acc)\n\t}\n\twg.Wait()\n\n\t// filter out excluded or not included jobs\n\tif !j.jobFilter.Match(jr.hierarchyName()) {\n\t\treturn nil\n\t}\n\n\t// collect build info\n\tbuilds := js.Builds\n\tif len(builds) == 0 {\n\t\tif js.LastBuild.Number < 1 {\n\t\t\treturn nil\n\t\t}\n\t\tbuilds = []jobBuild{js.LastBuild}\n\t}\n\tif len(builds) > maxBuildsPerJob {\n\t\tbuilds = builds[:maxBuildsPerJob]\n\t}\n\n\tcutoff := time.Now().Add(-1 * time.Duration(j.MaxBuildAge))\n\n\tfor _, jb := range builds {\n\t\tif jb.Number < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tbuild, err := j.client.getBuild(context.Background(), jr, jb.Number)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif build.Building {\n\t\t\tj.Log.Debugf(\"Ignore running build on %s, build %v\", jr.name, jb.Number)\n\t\t\tcontinue\n\t\t}\n\n\t\tif build.getTimestamp().Before(cutoff) {\n\t\t\tcontinue\n\t\t}\n\n\t\tj.gatherJobBuild(jr, build, acc)\n\t}\n\treturn nil\n}\n\ntype nodeResponse struct {\n\tComputers      []node `json:\"computer\"`\n\tBusyExecutors  int    `json:\"busyExecutors\"`\n\tTotalExecutors int    `json:\"totalExecutors\"`\n}\n\ntype node struct {\n\tDisplayName    string      `json:\"displayName\"`\n\tOffline        bool        `json:\"offline\"`\n\tNumExecutors   int         `json:\"numExecutors\"`\n\tMonitorData    monitorData `json:\"monitorData\"`\n\tAssignedLabels []label     `json:\"assignedLabels\"`\n}\n\ntype label struct {\n\tName string `json:\"name\"`\n}\n\ntype monitorData struct {\n\tHudsonNodeMonitorsArchitectureMonitor   string               `json:\"hudson.node_monitors.ArchitectureMonitor\"`\n\tHudsonNodeMonitorsDiskSpaceMonitor      *nodeSpaceMonitor    `json:\"hudson.node_monitors.DiskSpaceMonitor\"`\n\tHudsonNodeMonitorsResponseTimeMonitor   *responseTimeMonitor `json:\"hudson.node_monitors.ResponseTimeMonitor\"`\n\tHudsonNodeMonitorsSwapSpaceMonitor      *swapSpaceMonitor    `json:\"hudson.node_monitors.SwapSpaceMonitor\"`\n\tHudsonNodeMonitorsTemporarySpaceMonitor *nodeSpaceMonitor    `json:\"hudson.node_monitors.TemporarySpaceMonitor\"`\n}\n\ntype nodeSpaceMonitor struct {\n\tPath string  `json:\"path\"`\n\tSize float64 `json:\"size\"`\n}\n\ntype responseTimeMonitor struct {\n\tAverage int64 `json:\"average\"`\n}\n\ntype swapSpaceMonitor struct {\n\tSwapAvailable   float64 `json:\"availableSwapSpace\"`\n\tSwapTotal       float64 `json:\"totalSwapSpace\"`\n\tMemoryAvailable float64 `json:\"availablePhysicalMemory\"`\n\tMemoryTotal     float64 `json:\"totalPhysicalMemory\"`\n}\n\ntype jobResponse struct {\n\tLastBuild jobBuild   `json:\"lastBuild\"`\n\tBuilds    []jobBuild `json:\"builds\"`\n\tJobs      []innerJob `json:\"jobs\"`\n\tName      string     `json:\"name\"`\n}\n\ntype innerJob struct {\n\tName  string `json:\"name\"`\n\tURL   string `json:\"url\"`\n\tColor string `json:\"color\"`\n}\n\ntype jobBuild struct {\n\tNumber int64\n\tURL    string\n}\n\ntype buildResponse struct {\n\tBuilding  bool   `json:\"building\"`\n\tDuration  int64  `json:\"duration\"`\n\tNumber    int64  `json:\"number\"`\n\tResult    string `json:\"result\"`\n\tTimestamp int64  `json:\"timestamp\"`\n}\n\nfunc (b *buildResponse) getTimestamp() time.Time {\n\treturn time.Unix(0, b.Timestamp*int64(time.Millisecond))\n}\n\nconst (\n\tnodePath = \"/computer/api/json\"\n\tjobPath  = \"/api/json\"\n)\n\ntype jobRequest struct {\n\tname    string\n\tparents []string\n\tlayer   int\n}\n\nfunc (jr jobRequest) combined() []string {\n\tpath := make([]string, 0, len(jr.parents)+1)\n\tpath = append(path, jr.parents...)\n\treturn append(path, jr.name)\n}\n\nfunc (jr jobRequest) combinedEscaped() []string {\n\tjobs := jr.combined()\n\tfor index, job := range jobs {\n\t\tjobs[index] = url.PathEscape(job)\n\t}\n\treturn jobs\n}\n\nfunc (jr jobRequest) url() string {\n\treturn \"/job/\" + strings.Join(jr.combinedEscaped(), \"/job/\") + jobPath\n}\n\nfunc (jr jobRequest) buildURL(number int64) string {\n\treturn \"/job/\" + strings.Join(jr.combinedEscaped(), \"/job/\") + \"/\" + strconv.Itoa(int(number)) + jobPath\n}\n\nfunc (jr jobRequest) hierarchyName() string {\n\treturn strings.Join(jr.combined(), \"/\")\n}\n\nfunc (jr jobRequest) parentsString() string {\n\treturn strings.Join(jr.parents, \"/\")\n}\n\nfunc (j *Jenkins) gatherJobBuild(jr jobRequest, b *buildResponse, acc telegraf.Accumulator) {\n\ttags := map[string]string{\"name\": jr.name, \"parents\": jr.parentsString(), \"result\": b.Result, \"source\": j.source, \"port\": j.port}\n\tfields := make(map[string]interface{})\n\tfields[\"duration\"] = b.Duration\n\tfields[\"result_code\"] = mapResultCode(b.Result)\n\tfields[\"number\"] = b.Number\n\n\tacc.AddFields(measurementJob, fields, tags, b.getTimestamp())\n}\n\n// perform status mapping\nfunc mapResultCode(s string) int {\n\tswitch strings.ToLower(s) {\n\tcase \"success\":\n\t\treturn 0\n\tcase \"failure\":\n\t\treturn 1\n\tcase \"not_built\":\n\t\treturn 2\n\tcase \"unstable\":\n\t\treturn 3\n\tcase \"aborted\":\n\t\treturn 4\n\t}\n\treturn -1\n}\n\nfunc init() {\n\tinputs.Add(\"jenkins\", func() telegraf.Input {\n\t\treturn &Jenkins{\n\t\t\tMaxBuildAge:       config.Duration(time.Hour),\n\t\t\tMaxConnections:    5,\n\t\t\tMaxSubJobPerLayer: 10,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/jenkins/jenkins_test.go",
    "content": "// Test Suite\npackage jenkins\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestJobRequestHierarchyName(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    jobRequest\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tinput:    jobRequest{},\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"parents\",\n\t\t\tinput: jobRequest{\n\t\t\t\tname:    \"1\",\n\t\t\t\tparents: []string{\"3\", \"2\"},\n\t\t\t},\n\t\t\texpected: \"3/2/1\",\n\t\t},\n\t\t{\n\t\t\tname: \"parents special character\",\n\t\t\tinput: jobRequest{\n\t\t\t\tname:    \"job 3\",\n\t\t\t\tparents: []string{\"job 1\", \"job 2\"},\n\t\t\t},\n\t\t\texpected: \"job 1/job 2/job 3\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.input.hierarchyName())\n\t\t})\n\t}\n}\n\nfunc TestJobRequestURL(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    jobRequest\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"parents\",\n\t\t\tinput: jobRequest{\n\t\t\t\tname:    \"1\",\n\t\t\t\tparents: []string{\"3\", \"2\"},\n\t\t\t},\n\t\t\texpected: \"/job/3/job/2/job/1/api/json\",\n\t\t},\n\t\t{\n\t\t\tname: \"parents special character\",\n\t\t\tinput: jobRequest{\n\t\t\t\tname:    \"job 3\",\n\t\t\t\tparents: []string{\"job 1\", \"job 2\"},\n\t\t\t},\n\t\t\texpected: \"/job/job%201/job/job%202/job/job%203/api/json\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, tt.input.url())\n\t\t})\n\t}\n}\n\nfunc TestResultCode(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected int\n\t}{\n\t\t{\"SUCCESS\", 0},\n\t\t{\"Failure\", 1},\n\t\t{\"NOT_BUILT\", 2},\n\t\t{\"UNSTABLE\", 3},\n\t\t{\"ABORTED\", 4},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.input, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, mapResultCode(tt.input))\n\t\t})\n\t}\n}\n\ntype mockHandler struct {\n\t// responseMap is the path to response interface\n\t// we will output the serialized response in json when serving http\n\t// example '/computer/api/json': *gojenkins.\n\tresponseMap map[string]interface{}\n}\n\nfunc (h mockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\to, ok := h.responseMap[r.URL.EscapedPath()]\n\tif !ok {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\tb, err := json.Marshal(o)\n\tif err != nil {\n\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tif len(b) == 0 {\n\t\tw.WriteHeader(http.StatusNoContent)\n\t\treturn\n\t}\n\n\tw.Write(b) //nolint:errcheck // ignore the returned error as the tests will fail anyway\n}\n\nfunc TestInitFail(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\taddress  string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"bad jenkins config\",\n\t\t\taddress:  \"http://a bad url\",\n\t\t\texpected: `invalid character \" \" in host name`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tURL:             tt.address,\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t}\n\n\t\t\terr := plugin.initialize(&http.Client{Transport: &http.Transport{}})\n\t\t\trequire.ErrorContains(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestInit(t *testing.T) {\n\tmh := mockHandler{\n\t\tresponseMap: map[string]interface{}{\n\t\t\t\"/api/json\": struct{}{},\n\t\t},\n\t}\n\tts := httptest.NewServer(mh)\n\tdefer ts.Close()\n\tmockClient := &http.Client{Transport: &http.Transport{}}\n\ttests := []struct {\n\t\t// name of the test\n\t\tname        string\n\t\tjobInclude  []string\n\t\tjobExclude  []string\n\t\tnodeExclude []string\n\t}{\n\t\t{\n\t\t\tname: \"default\",\n\t\t},\n\t\t{\n\t\t\tname:        \"with filters\",\n\t\t\tjobInclude:  []string{\"jobA\", \"jobB\"},\n\t\t\tjobExclude:  []string{\"job1\", \"job2\"},\n\t\t\tnodeExclude: []string{\"node1\", \"node2\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tURL:             ts.URL,\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t\tJobInclude:      tt.jobInclude,\n\t\t\t\tJobExclude:      tt.jobExclude,\n\t\t\t\tNodeExclude:     tt.nodeExclude,\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.initialize(mockClient))\n\n\t\t\t// Check the default values\n\t\t\trequire.Equal(t, 5, plugin.MaxConnections)\n\t\t\trequire.Equal(t, 10, plugin.MaxSubJobPerLayer)\n\t\t})\n\t}\n}\n\nfunc TestGatherFail(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tresponse map[string]interface{}\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"bad node data\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{},\n\t\t\t\t\t\t{},\n\t\t\t\t\t\t{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"error empty node name\",\n\t\t},\n\t\t{\n\t\t\tname: \"bad inner jobs\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/computer/api/json\": nil,\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"404 Not Found\",\n\t\t},\n\t\t{\n\t\t\tname: \"bad build info\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/computer/api/json\": nil,\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"[/job/job1/1/api/json] 404 Not Found\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup test server\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Lookup the response using the URI\n\t\t\t\tresponse, ok := tt.response[r.URL.EscapedPath()]\n\t\t\t\tif !ok {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Encode the response to JSON\n\t\t\t\tbuf, err := json.Marshal(response)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif len(buf) == 0 {\n\t\t\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Send the response\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\t\t\tt.Fail()\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t\tURL:             ts.URL,\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t}\n\n\t\t\t// Collect the data and check for the expected error\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.ErrorContains(t, acc.GatherError(plugin.Gather), tt.expected)\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\t// Check the resulting metrics\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t\ttestutil.IgnoreTags(\"port\"),\n\t\t\t}\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc TestGatherNodeData(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tresponse map[string]interface{}\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"empty monitor data\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{DisplayName: \"master\"},\n\t\t\t\t\t\t{DisplayName: \"node1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":      \"\",\n\t\t\t\t\t\t\"node_name\": \"master\",\n\t\t\t\t\t\t\"status\":    \"online\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"num_executors\": int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"normal response\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tBusyExecutors:  4,\n\t\t\t\t\tTotalExecutors: 8,\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDisplayName: \"master\",\n\t\t\t\t\t\t\tMonitorData: monitorData{\n\t\t\t\t\t\t\t\tHudsonNodeMonitorsArchitectureMonitor: \"linux\",\n\t\t\t\t\t\t\t\tHudsonNodeMonitorsResponseTimeMonitor: &responseTimeMonitor{\n\t\t\t\t\t\t\t\t\tAverage: 10032,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tHudsonNodeMonitorsDiskSpaceMonitor: &nodeSpaceMonitor{\n\t\t\t\t\t\t\t\t\tPath: \"/path/1\",\n\t\t\t\t\t\t\t\t\tSize: 123,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tHudsonNodeMonitorsTemporarySpaceMonitor: &nodeSpaceMonitor{\n\t\t\t\t\t\t\t\t\tPath: \"/path/2\",\n\t\t\t\t\t\t\t\t\tSize: 245,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tHudsonNodeMonitorsSwapSpaceMonitor: &swapSpaceMonitor{\n\t\t\t\t\t\t\t\t\tSwapAvailable:   212,\n\t\t\t\t\t\t\t\t\tSwapTotal:       500,\n\t\t\t\t\t\t\t\t\tMemoryAvailable: 101,\n\t\t\t\t\t\t\t\t\tMemoryTotal:     500,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tOffline: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  4,\n\t\t\t\t\t\t\"total_executors\": 8,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":      \"\",\n\t\t\t\t\t\t\"node_name\": \"master\",\n\t\t\t\t\t\t\"status\":    \"online\",\n\t\t\t\t\t\t\"arch\":      \"linux\",\n\t\t\t\t\t\t\"disk_path\": \"/path/1\",\n\t\t\t\t\t\t\"temp_path\": \"/path/2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"num_executors\":    int64(0),\n\t\t\t\t\t\t\"response_time\":    int64(10032),\n\t\t\t\t\t\t\"disk_available\":   float64(123),\n\t\t\t\t\t\t\"temp_available\":   float64(245),\n\t\t\t\t\t\t\"swap_available\":   float64(212),\n\t\t\t\t\t\t\"swap_total\":       float64(500),\n\t\t\t\t\t\t\"memory_available\": float64(101),\n\t\t\t\t\t\t\"memory_total\":     float64(500),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"filtered nodes included\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tBusyExecutors:  4,\n\t\t\t\t\tTotalExecutors: 8,\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{DisplayName: \"filtered-1\"},\n\t\t\t\t\t\t{DisplayName: \"filtered-1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  4,\n\t\t\t\t\t\t\"total_executors\": 8,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"filtered nodes excluded\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tBusyExecutors:  4,\n\t\t\t\t\tTotalExecutors: 8,\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{DisplayName: \"ignore-1\"},\n\t\t\t\t\t\t{DisplayName: \"ignore-2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  4,\n\t\t\t\t\t\t\"total_executors\": 8,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"slave offline\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": struct{}{},\n\t\t\t\t\"/computer/api/json\": nodeResponse{\n\t\t\t\t\tBusyExecutors:  4,\n\t\t\t\t\tTotalExecutors: 8,\n\t\t\t\t\tComputers: []node{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDisplayName:  \"slave\",\n\t\t\t\t\t\t\tMonitorData:  monitorData{},\n\t\t\t\t\t\t\tNumExecutors: 1,\n\t\t\t\t\t\t\tOffline:      true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  4,\n\t\t\t\t\t\t\"total_executors\": 8,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_node\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":      \"\",\n\t\t\t\t\t\t\"node_name\": \"slave\",\n\t\t\t\t\t\t\"status\":    \"offline\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"num_executors\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup test server\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Lookup the response using the URI\n\t\t\t\tresponse, ok := tt.response[r.URL.EscapedPath()]\n\t\t\t\tif !ok {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Encode the response to JSON\n\t\t\t\tbuf, err := json.Marshal(response)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif len(buf) == 0 {\n\t\t\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Send the response\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\t\t\tt.Fail()\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t\tURL:             ts.URL,\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t\tNodeExclude:     []string{\"ignore-1\", \"ignore-2\"},\n\t\t\t\tNodeInclude:     []string{\"master\", \"slave\"},\n\t\t\t}\n\n\t\t\t// Collect the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t\t\t// Check the resulting metrics\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t\ttestutil.IgnoreTags(\"port\"),\n\t\t\t}\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc TestGatherLabels(t *testing.T) {\n\tresponse := map[string]interface{}{\n\t\t\"/api/json\": struct{}{},\n\t\t\"/computer/api/json\": nodeResponse{\n\t\t\tBusyExecutors:  4,\n\t\t\tTotalExecutors: 8,\n\t\t\tComputers: []node{\n\t\t\t\t{\n\t\t\t\t\tDisplayName: \"master\",\n\t\t\t\t\tAssignedLabels: []label{\n\t\t\t\t\t\t{\"project_a\"},\n\t\t\t\t\t\t{\"testing\"},\n\t\t\t\t\t},\n\t\t\t\t\tMonitorData: monitorData{\n\t\t\t\t\t\tHudsonNodeMonitorsResponseTimeMonitor: &responseTimeMonitor{\n\t\t\t\t\t\t\tAverage: 54321,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDisplayName: \"secondary\",\n\t\t\t\t\tMonitorData: monitorData{\n\t\t\t\t\t\tHudsonNodeMonitorsResponseTimeMonitor: &responseTimeMonitor{\n\t\t\t\t\t\t\tAverage: 12345,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"jenkins\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\"port\":   \"\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"busy_executors\":  4,\n\t\t\t\t\"total_executors\": 8,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"jenkins_node\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\"port\":      \"\",\n\t\t\t\t\"node_name\": \"master\",\n\t\t\t\t\"status\":    \"online\",\n\t\t\t\t\"labels\":    \"project_a,testing\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"num_executors\": int64(0),\n\t\t\t\t\"response_time\": int64(54321),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"jenkins_node\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\"port\":      \"\",\n\t\t\t\t\"node_name\": \"secondary\",\n\t\t\t\t\"status\":    \"online\",\n\t\t\t\t\"labels\":    \"none\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"num_executors\": int64(0),\n\t\t\t\t\"response_time\": int64(12345),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Setup test server\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Lookup the response using the URI\n\t\tresponse, ok := response[r.URL.EscapedPath()]\n\t\tif !ok {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\t\t// Encode the response to JSON\n\t\tbuf, err := json.Marshal(response)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tif len(buf) == 0 {\n\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\treturn\n\t\t}\n\n\t\t// Send the response\n\t\tif _, err := w.Write(buf); err != nil {\n\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\tt.Fail()\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Setup the plugin\n\tplugin := &Jenkins{\n\t\tLog:             testutil.Logger{},\n\t\tURL:             ts.URL,\n\t\tResponseTimeout: config.Duration(time.Second),\n\t\tNodeLabelsAsTag: true,\n\t}\n\n\t// Collect the data\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t// Check the resulting metrics\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.IgnoreTags(\"port\"),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherJobBuilds(t *testing.T) {\n\ttwoHoursAgo := (time.Now().Unix() - int64((2 * time.Hour).Seconds())) * 1000\n\toneMinAgo := (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000\n\n\ttests := []struct {\n\t\tname     string\n\t\tresponse map[string]interface{}\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"multiple builds\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds: []jobBuild{{Number: 3}, {Number: 2}, {Number: 1}},\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  10000,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/2/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"FAILURE\",\n\t\t\t\t\tDuration:  20000,\n\t\t\t\t\tNumber:    2,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  30000,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(10000),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"FAILURE\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(20000),\n\t\t\t\t\t\t\"number\":      int64(2),\n\t\t\t\t\t\t\"result_code\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(30000),\n\t\t\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"running build skipped\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds: []jobBuild{{Number: 3}, {Number: 2}},\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  true,\n\t\t\t\t\tResult:    \"\",\n\t\t\t\t\tDuration:  0,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: time.Now().Unix() * 1000,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/2/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  15000,\n\t\t\t\t\tNumber:    2,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(15000),\n\t\t\t\t\t\t\"number\":      int64(2),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"max build age filters old builds\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds: []jobBuild{{Number: 3}, {Number: 2}, {Number: 1}},\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  10000,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/2/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  20000,\n\t\t\t\t\tNumber:    2,\n\t\t\t\t\tTimestamp: twoHoursAgo,\n\t\t\t\t},\n\t\t\t\t// Build 1 is also too old, so no metric is emitted for it\n\t\t\t\t\"/job/pipeline/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  30000,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64((3 * time.Hour).Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(10000),\n\t\t\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"last build fallback\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds:    nil,\n\t\t\t\t\tLastBuild: jobBuild{Number: 5},\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/5/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  12000,\n\t\t\t\t\tNumber:    5,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(12000),\n\t\t\t\t\t\t\"number\":      int64(5),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no build when last build invalid\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds:    nil,\n\t\t\t\t\tLastBuild: jobBuild{Number: 0},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// Build 2 is older than MaxBuildAge but builds 1 and 3 are recent.\n\t\t\t// All valid builds should still be reported even if an old build\n\t\t\t// appears between newer ones (i.e. non-descending order).\n\t\t\tname: \"old build among new builds\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"pipeline\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\t\t\tBuilds:    []jobBuild{{Number: 3}, {Number: 2}, {Number: 1}},\n\t\t\t\t\tLastBuild: jobBuild{Number: 3},\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  10000,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/2/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  20000,\n\t\t\t\t\tNumber:    2,\n\t\t\t\t\tTimestamp: twoHoursAgo,\n\t\t\t\t},\n\t\t\t\t\"/job/pipeline/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  30000,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: oneMinAgo,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(10000),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(30000),\n\t\t\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup test server\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tresp, ok := tt.response[r.URL.EscapedPath()]\n\t\t\t\tif !ok {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tbuf, err := json.Marshal(resp)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif len(buf) == 0 {\n\t\t\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\t\t\tt.Fail()\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tURL:             ts.URL,\n\t\t\t\tMaxBuildAge:     config.Duration(time.Hour),\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t}\n\n\t\t\t// Collect the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t\t\t// Check the resulting metrics\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t\ttestutil.SortMetrics(),\n\t\t\t\ttestutil.IgnoreTags(\"port\"),\n\t\t\t}\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc TestGatherBuildFetchErrorPartial(t *testing.T) {\n\t// Build 2 returns an HTTP error, but builds 1 and 3 succeed.\n\t// Metrics should still be emitted for the successful builds,\n\t// and the error should be recorded via acc.AddError.\n\tresponse := map[string]interface{}{\n\t\t\"/api/json\": &jobResponse{\n\t\t\tJobs: []innerJob{\n\t\t\t\t{Name: \"pipeline\"},\n\t\t\t},\n\t\t},\n\t\t\"/computer/api/json\": nodeResponse{},\n\t\t\"/job/pipeline/api/json\": &jobResponse{\n\t\t\tBuilds:    []jobBuild{{Number: 3}, {Number: 2}, {Number: 1}},\n\t\t\tLastBuild: jobBuild{Number: 3},\n\t\t},\n\t\t// Build 2 is deliberately missing from responses, causing a 404\n\t\t\"/job/pipeline/1/api/json\": &buildResponse{\n\t\t\tBuilding:  false,\n\t\t\tResult:    \"SUCCESS\",\n\t\t\tDuration:  10000,\n\t\t\tNumber:    1,\n\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t},\n\t\t\"/job/pipeline/3/api/json\": &buildResponse{\n\t\t\tBuilding:  false,\n\t\t\tResult:    \"SUCCESS\",\n\t\t\tDuration:  30000,\n\t\t\tNumber:    3,\n\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t},\n\t}\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"jenkins\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\"port\":   \"\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\"total_executors\": 0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"jenkins_job\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\"port\":    \"\",\n\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\"parents\": \"\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"duration\":    int64(10000),\n\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\"result_code\": 0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"jenkins_job\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\"port\":    \"\",\n\t\t\t\t\"name\":    \"pipeline\",\n\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\"parents\": \"\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"duration\":    int64(30000),\n\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\"result_code\": 0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Setup test server\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tresp, ok := response[r.URL.EscapedPath()]\n\t\tif !ok {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\t\tbuf, err := json.Marshal(resp)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tif len(buf) == 0 {\n\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err := w.Write(buf); err != nil {\n\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\tt.Fail()\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tplugin := &Jenkins{\n\t\tURL:             ts.URL,\n\t\tMaxBuildAge:     config.Duration(time.Hour),\n\t\tResponseTimeout: config.Duration(time.Second),\n\t\tLog:             testutil.Logger{},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Should have recorded an error for the failed build fetch\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.Errors[0], \"404\")\n\n\t// Metrics for the two successful builds should still be present\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.SortMetrics(),\n\t\ttestutil.IgnoreTags(\"port\"),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestGatherBuildsCappedAt20(t *testing.T) {\n\t// A job has 25 builds, all within MaxBuildAge.\n\t// The plugin should fetch at most 20 build details,\n\t// because getJobs should use a tree parameter to limit\n\t// the builds array returned by Jenkins.\n\tconst totalBuilds = 25\n\tmaxExpectedFetches := maxBuildsPerJob\n\n\tnow := time.Now()\n\n\t// Build the job response with 25 builds (newest-first)\n\tbuilds := make([]jobBuild, totalBuilds)\n\tfor i := 0; i < totalBuilds; i++ {\n\t\tbuilds[i] = jobBuild{Number: int64(totalBuilds - i)}\n\t}\n\n\t// Track how many build-detail requests are made and whether the tree parameter was sent\n\tvar buildFetchCount atomic.Int32\n\tvar treeParameterSeen atomic.Bool\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tpath := r.URL.EscapedPath()\n\t\tvar resp interface{}\n\n\t\tswitch path {\n\t\tcase \"/\", \"/api/json\":\n\t\t\tresp = &jobResponse{\n\t\t\t\tJobs: []innerJob{{Name: \"pipeline\"}},\n\t\t\t}\n\t\tcase \"/computer/api/json\":\n\t\t\tresp = &nodeResponse{}\n\t\tcase \"/job/pipeline/api/json\":\n\t\t\t// Simulate Jenkins honoring the tree parameter:\n\t\t\t// when the request includes tree=...{0,20}, return only 20 builds.\n\t\t\tbuildsToReturn := builds\n\t\t\tif strings.Contains(r.URL.RawQuery, \"tree=\") {\n\t\t\t\ttreeParameterSeen.Store(true)\n\t\t\t\tif len(buildsToReturn) > maxExpectedFetches {\n\t\t\t\t\tbuildsToReturn = buildsToReturn[:maxExpectedFetches]\n\t\t\t\t}\n\t\t\t}\n\t\t\tresp = &jobResponse{\n\t\t\t\tBuilds:    buildsToReturn,\n\t\t\t\tLastBuild: jobBuild{Number: int64(totalBuilds)},\n\t\t\t}\n\t\tdefault:\n\t\t\t// Must be a build detail request like /job/pipeline/<N>/api/json\n\t\t\tbuildFetchCount.Add(1)\n\t\t\tresp = &buildResponse{\n\t\t\t\tBuilding:  false,\n\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\tDuration:  10000,\n\t\t\t\tNumber:    1,\n\t\t\t\tTimestamp: (now.Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t}\n\t\t}\n\n\t\tbuf, err := json.Marshal(resp)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tif _, err := w.Write(buf); err != nil {\n\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\tt.Fail()\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tplugin := &Jenkins{\n\t\tURL:             ts.URL,\n\t\tMaxBuildAge:     config.Duration(time.Hour),\n\t\tResponseTimeout: config.Duration(time.Second),\n\t\tLog:             testutil.Logger{},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.True(t, treeParameterSeen.Load(), \"expected the job request to include a tree query parameter\")\n\trequire.LessOrEqual(t, int(buildFetchCount.Load()), maxExpectedFetches,\n\t\t\"expected at most %d build fetches but got %d\", maxExpectedFetches, buildFetchCount.Load())\n}\n\nfunc TestGatherJobs(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tresponse map[string]interface{}\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"empty job\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"without build\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/api/json\": &jobResponse{},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ignore building job\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ignore old build\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/2/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tTimestamp: 100,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"normal\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job1\"},\n\t\t\t\t\t\t{Name: \"job2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job2/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job1/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  25558,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t\t\"/job/job2/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"FAILURE\",\n\t\t\t\t\tDuration:  1558,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"job1\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(25558),\n\t\t\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"job2\",\n\t\t\t\t\t\t\"result\":  \"FAILURE\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(1558),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with space\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job 1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job%201/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/job%201/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  25558,\n\t\t\t\t\tNumber:    3,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"job 1\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(25558),\n\t\t\t\t\t\t\"number\":      int64(3),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"gather metrics for nested jobs with space exercising append slice behaviour\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"l1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/l1/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"l2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/l1/job/l2/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job 1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/l1/job/l2/job/job%201/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"job 2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/l1/job/l2/job/job%201/job/job%202/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/l1/job/l2/job/job%201/job/job%202/3/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  25558,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"job 2\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"l1/l2/job 1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(25558),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t\t\"number\":      0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"gather sub jobs, jobs filter\",\n\t\t\tresponse: map[string]interface{}{\n\t\t\t\t\"/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"apps\"},\n\t\t\t\t\t\t{Name: \"ignore-1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/ignore-1/api/json\": &jobResponse{},\n\t\t\t\t\"/job/apps/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"k8s-cloud\"},\n\t\t\t\t\t\t{Name: \"chronograf\"},\n\t\t\t\t\t\t{Name: \"ignore-all\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/ignore-all/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"1\"},\n\t\t\t\t\t\t{Name: \"2\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/ignore-all/job/1/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/ignore-all/job/2/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/chronograf/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/api/json\": &jobResponse{\n\t\t\t\t\tJobs: []innerJob{\n\t\t\t\t\t\t{Name: \"PR-100\"},\n\t\t\t\t\t\t{Name: \"PR-101\"},\n\t\t\t\t\t\t{Name: \"PR-ignore2\"},\n\t\t\t\t\t\t{Name: \"PR 1\"},\n\t\t\t\t\t\t{Name: \"PR ignore\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR%20ignore/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR-ignore2/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR-100/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR-101/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 4,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR%201/api/json\": &jobResponse{\n\t\t\t\t\tLastBuild: jobBuild{\n\t\t\t\t\t\tNumber: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/chronograf/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"FAILURE\",\n\t\t\t\t\tDuration:  1558,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR-101/4/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  76558,\n\t\t\t\t\tNumber:    4,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR-100/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  91558,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t\t\"/job/apps/job/k8s-cloud/job/PR%201/1/api/json\": &buildResponse{\n\t\t\t\t\tBuilding:  false,\n\t\t\t\t\tResult:    \"SUCCESS\",\n\t\t\t\t\tDuration:  87832,\n\t\t\t\t\tNumber:    1,\n\t\t\t\t\tTimestamp: (time.Now().Unix() - int64(time.Minute.Seconds())) * 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\": \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":   \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"busy_executors\":  0,\n\t\t\t\t\t\t\"total_executors\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"PR 1\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"apps/k8s-cloud\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(87832),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"PR-100\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"apps/k8s-cloud\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(91558),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"PR-101\",\n\t\t\t\t\t\t\"result\":  \"SUCCESS\",\n\t\t\t\t\t\t\"parents\": \"apps/k8s-cloud\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(76558),\n\t\t\t\t\t\t\"number\":      int64(4),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"jenkins_job\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t\t\"port\":    \"\",\n\t\t\t\t\t\t\"name\":    \"chronograf\",\n\t\t\t\t\t\t\"result\":  \"FAILURE\",\n\t\t\t\t\t\t\"parents\": \"apps\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"duration\":    int64(1558),\n\t\t\t\t\t\t\"number\":      int64(1),\n\t\t\t\t\t\t\"result_code\": 1,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup test server\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Lookup the response using the URI\n\t\t\t\tresponse, ok := tt.response[r.URL.EscapedPath()]\n\t\t\t\tif !ok {\n\t\t\t\t\t// Shortcut unrelated endpoints\n\t\t\t\t\tif r.URL.EscapedPath() != \"/computer/api/json\" {\n\t\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Encode the response to JSON\n\t\t\t\tbuf, err := json.Marshal(response)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif len(buf) == 0 {\n\t\t\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Send the response\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tt.Logf(\"writing failed: %v\", err)\n\t\t\t\t\tt.Fail()\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Jenkins{\n\t\t\t\tURL:             ts.URL,\n\t\t\t\tMaxBuildAge:     config.Duration(time.Hour),\n\t\t\t\tResponseTimeout: config.Duration(time.Second),\n\t\t\t\tJobInclude:      []string{\"*\"},\n\t\t\t\tJobExclude: []string{\n\t\t\t\t\t\"ignore-1\",\n\t\t\t\t\t\"apps/ignore-all/*\",\n\t\t\t\t\t\"apps/k8s-cloud/PR-ignore2\",\n\t\t\t\t\t\"apps/k8s-cloud/PR ignore\",\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t}\n\n\t\t\t// Collect the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t\t\t// Check the resulting metrics\n\t\t\toptions := []cmp.Option{\n\t\t\t\ttestutil.IgnoreTime(),\n\t\t\t\ttestutil.SortMetrics(),\n\t\t\t\ttestutil.IgnoreTags(\"port\"),\n\t\t\t}\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, options...)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/jenkins/sample.conf",
    "content": "# Read jobs and cluster metrics from Jenkins instances\n[[inputs.jenkins]]\n  ## The Jenkins URL in the format \"schema://host:port\"\n  url = \"http://my-jenkins-instance:8080\"\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Set response_timeout\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use SSL but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional Max Job Build Age filter\n  ## Default 1 hour, ignore builds older than max_build_age\n  # max_build_age = \"1h\"\n\n  ## Optional Sub Job Depth filter\n  ## Jenkins can have unlimited layer of sub jobs\n  ## This config will limit the layers of pulling, default value 0 means\n  ## unlimited pulling until no more sub jobs\n  # max_subjob_depth = 0\n\n  ## Optional Sub Job Per Layer\n  ## In workflow-multibranch-plugin, each branch will be created as a sub job.\n  ## This config will limit to call only the lasted branches in each layer,\n  ## empty will use default value 10\n  # max_subjob_per_layer = 10\n\n  ## Jobs to include or exclude from gathering\n  ## When using both lists, job_exclude has priority.\n  ## Wildcards are supported: [ \"jobA/*\", \"jobB/subjob1/*\"]\n  # job_include = [ \"*\" ]\n  # job_exclude = [ ]\n\n  ## Nodes to include or exclude from gathering\n  ## When using both lists, node_exclude has priority.\n  # node_include = [ \"*\" ]\n  # node_exclude = [ ]\n\n  ## Worker pool for jenkins plugin only\n  ## Empty this field will use default value 5\n  # max_connections = 5\n\n  ## When set to true will add node labels as a comma-separated tag. If none,\n  ## are found, then a tag with the value of 'none' is used. Finally, if a\n  ## label contains a comma it is replaced with an underscore.\n  # node_labels_as_tag = false\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/README.md",
    "content": "# Jolokia2 Agent Input Plugin\n\nThis plugin reads JMX metrics from one or more [Jolokia agent][jolokia_agent]\nREST endpoints.\n\n⭐ Telegraf v1.5.0\n🏷️ applications, network\n💻 all\n\n[jolokia_agent]: https://jolokia.org/agent/jvm.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read JMX metrics from a Jolokia REST agent endpoint\n[[inputs.jolokia2_agent]]\n  # default_tag_prefix      = \"\"\n  # default_field_prefix    = \"\"\n  # default_field_separator = \".\"\n\n  # Add agents URLs to query\n  urls = [\"http://localhost:8080/jolokia\"]\n  # username = \"\"\n  # password = \"\"\n  # response_timeout = \"5s\"\n\n  ## Optional origin URL to include as a header in the request. Some endpoints\n  ## may reject an empty origin.\n  # origin = \"\"\n\n  ## Optional TLS config\n  # tls_ca   = \"/var/private/ca.pem\"\n  # tls_cert = \"/var/private/client.pem\"\n  # tls_key  = \"/var/private/client-key.pem\"\n  # insecure_skip_verify = false\n\n  ## Add metrics to read\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n```\n\nOptionally, specify TLS options for communicating with agents:\n\n```toml\n[[inputs.jolokia2_agent]]\n  urls = [\"https://agent:8080/jolokia\"]\n  tls_ca   = \"/var/private/ca.pem\"\n  tls_cert = \"/var/private/client.pem\"\n  tls_key  = \"/var/private/client-key.pem\"\n  #insecure_skip_verify = false\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n```\n\n### Metric Configuration\n\nEach `metric` declaration generates a Jolokia request to fetch telemetry from a\nJMX MBean.\n\n| Key            | Required | Description |\n|----------------|----------|-------------|\n| `mbean`        | yes      | The object name of a JMX MBean. MBean property-key values can contain a wildcard `*`, allowing you to fetch multiple MBeans with one declaration. |\n| `paths`        | no       | A list of MBean attributes to read. |\n| `tag_keys`     | no       | A list of MBean property-key names to convert into tags. The property-key name becomes the tag name, while the property-key value becomes the tag value. |\n| `tag_prefix`   | no       | A string to prepend to the tag names produced by this `metric` declaration. |\n| `field_name`   | no       | A string to set as the name of the field produced by this metric; can contain substitutions. |\n| `field_prefix` | no       | A string to prepend to the field names produced by this `metric` declaration; can contain substitutions. |\n\nUse `paths` to refine which fields to collect.\n\n```toml\n[[inputs.jolokia2_agent.metric]]\n  name  = \"jvm_memory\"\n  mbean = \"java.lang:type=Memory\"\n  paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n```\n\nThe preceding `jvm_memory` `metric` declaration produces the following output:\n\n```text\njvm_memory HeapMemoryUsage.committed=4294967296,HeapMemoryUsage.init=4294967296,HeapMemoryUsage.max=4294967296,HeapMemoryUsage.used=1750658992,NonHeapMemoryUsage.committed=67350528,NonHeapMemoryUsage.init=2555904,NonHeapMemoryUsage.max=-1,NonHeapMemoryUsage.used=65821352,ObjectPendingFinalizationCount=0 1503762436000000000\n```\n\nUse `*` wildcards against `mbean` property-key values to create distinct series\nby capturing values into `tag_keys`.\n\n```toml\n[[inputs.jolokia2_agent.metric]]\n  name     = \"jvm_garbage_collector\"\n  mbean    = \"java.lang:name=*,type=GarbageCollector\"\n  paths    = [\"CollectionTime\", \"CollectionCount\"]\n  tag_keys = [\"name\"]\n```\n\nSince `name=*` matches both `G1 Old Generation` and `G1 Young Generation`, and\n`name` is used as a tag, the preceding `jvm_garbage_collector` `metric`\ndeclaration produces two metrics.\n\n```shell\njvm_garbage_collector,name=G1\\ Old\\ Generation CollectionCount=0,CollectionTime=0 1503762520000000000\njvm_garbage_collector,name=G1\\ Young\\ Generation CollectionTime=32,CollectionCount=2 1503762520000000000\n```\n\nUse `tag_prefix` along with `tag_keys` to add detail to tag names.\n\n```toml\n[[inputs.jolokia2_agent.metric]]\n  name       = \"jvm_memory_pool\"\n  mbean      = \"java.lang:name=*,type=MemoryPool\"\n  paths      = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n  tag_keys   = [\"name\"]\n  tag_prefix = \"pool_\"\n```\n\nThe preceding `jvm_memory_pool` `metric` declaration produces six metrics, each\nwith a distinct `pool_name` tag.\n\n```text\njvm_memory_pool,pool_name=Compressed\\ Class\\ Space PeakUsage.max=1073741824,PeakUsage.committed=3145728,PeakUsage.init=0,Usage.committed=3145728,Usage.init=0,PeakUsage.used=3017976,Usage.max=1073741824,Usage.used=3017976 1503764025000000000\njvm_memory_pool,pool_name=Code\\ Cache PeakUsage.init=2555904,PeakUsage.committed=6291456,Usage.committed=6291456,PeakUsage.used=6202752,PeakUsage.max=251658240,Usage.used=6210368,Usage.max=251658240,Usage.init=2555904 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Eden\\ Space CollectionUsage.max=-1,PeakUsage.committed=56623104,PeakUsage.init=56623104,PeakUsage.used=53477376,Usage.max=-1,Usage.committed=49283072,Usage.used=19922944,CollectionUsage.committed=49283072,CollectionUsage.init=56623104,CollectionUsage.used=0,PeakUsage.max=-1,Usage.init=56623104 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Old\\ Gen CollectionUsage.max=1073741824,CollectionUsage.committed=0,PeakUsage.max=1073741824,PeakUsage.committed=1017118720,PeakUsage.init=1017118720,PeakUsage.used=137032208,Usage.max=1073741824,CollectionUsage.init=1017118720,Usage.committed=1017118720,Usage.init=1017118720,Usage.used=134708752,CollectionUsage.used=0 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Survivor\\ Space Usage.max=-1,Usage.init=0,CollectionUsage.max=-1,CollectionUsage.committed=7340032,CollectionUsage.used=7340032,PeakUsage.committed=7340032,Usage.committed=7340032,Usage.used=7340032,CollectionUsage.init=0,PeakUsage.max=-1,PeakUsage.init=0,PeakUsage.used=7340032 1503764025000000000\njvm_memory_pool,pool_name=Metaspace PeakUsage.init=0,PeakUsage.used=21852224,PeakUsage.max=-1,Usage.max=-1,Usage.committed=22282240,Usage.init=0,Usage.used=21852224,PeakUsage.committed=22282240 1503764025000000000\n```\n\nUse substitutions to create fields and field prefixes with MBean property-keys\ncaptured by wildcards. In the following example, `$1` represents the value of\nthe property-key `name`, and `$2` represents the value of the property-key\n`topic`.\n\n```toml\n[[inputs.jolokia2_agent.metric]]\n  name         = \"kafka_topic\"\n  mbean        = \"kafka.server:name=*,topic=*,type=BrokerTopicMetrics\"\n  field_prefix = \"$1\"\n  tag_keys     = [\"topic\"]\n```\n\nThe preceding `kafka_topic` `metric` declaration produces a metric per Kafka\ntopic. The `name` Mbean property-key is used as a field prefix to aid in\ngathering fields together into the single metric.\n\n```text\nkafka_topic,topic=my-topic BytesOutPerSec.MeanRate=0,FailedProduceRequestsPerSec.MeanRate=0,BytesOutPerSec.EventType=\"bytes\",BytesRejectedPerSec.Count=0,FailedProduceRequestsPerSec.RateUnit=\"SECONDS\",FailedProduceRequestsPerSec.EventType=\"requests\",MessagesInPerSec.RateUnit=\"SECONDS\",BytesInPerSec.EventType=\"bytes\",BytesOutPerSec.RateUnit=\"SECONDS\",BytesInPerSec.OneMinuteRate=0,FailedFetchRequestsPerSec.EventType=\"requests\",TotalFetchRequestsPerSec.MeanRate=146.301533938701,BytesOutPerSec.FifteenMinuteRate=0,TotalProduceRequestsPerSec.MeanRate=0,BytesRejectedPerSec.FifteenMinuteRate=0,MessagesInPerSec.FiveMinuteRate=0,BytesInPerSec.Count=0,BytesRejectedPerSec.MeanRate=0,FailedFetchRequestsPerSec.MeanRate=0,FailedFetchRequestsPerSec.FiveMinuteRate=0,FailedFetchRequestsPerSec.FifteenMinuteRate=0,FailedProduceRequestsPerSec.Count=0,TotalFetchRequestsPerSec.FifteenMinuteRate=128.59314292334466,TotalFetchRequestsPerSec.OneMinuteRate=126.71551273850747,TotalFetchRequestsPerSec.Count=1353483,TotalProduceRequestsPerSec.FifteenMinuteRate=0,FailedFetchRequestsPerSec.OneMinuteRate=0,FailedFetchRequestsPerSec.Count=0,FailedProduceRequestsPerSec.FifteenMinuteRate=0,TotalFetchRequestsPerSec.FiveMinuteRate=130.8516148751592,TotalFetchRequestsPerSec.RateUnit=\"SECONDS\",BytesRejectedPerSec.RateUnit=\"SECONDS\",BytesInPerSec.MeanRate=0,FailedFetchRequestsPerSec.RateUnit=\"SECONDS\",BytesRejectedPerSec.OneMinuteRate=0,BytesOutPerSec.Count=0,BytesOutPerSec.OneMinuteRate=0,MessagesInPerSec.FifteenMinuteRate=0,MessagesInPerSec.MeanRate=0,BytesInPerSec.FiveMinuteRate=0,TotalProduceRequestsPerSec.RateUnit=\"SECONDS\",FailedProduceRequestsPerSec.OneMinuteRate=0,TotalProduceRequestsPerSec.EventType=\"requests\",BytesRejectedPerSec.FiveMinuteRate=0,BytesRejectedPerSec.EventType=\"bytes\",BytesOutPerSec.FiveMinuteRate=0,FailedProduceRequestsPerSec.FiveMinuteRate=0,MessagesInPerSec.Count=0,TotalProduceRequestsPerSec.FiveMinuteRate=0,TotalProduceRequestsPerSec.OneMinuteRate=0,MessagesInPerSec.EventType=\"messages\",MessagesInPerSec.OneMinuteRate=0,TotalFetchRequestsPerSec.EventType=\"requests\",BytesInPerSec.RateUnit=\"SECONDS\",BytesInPerSec.FifteenMinuteRate=0,TotalProduceRequestsPerSec.Count=0 1503767532000000000\n```\n\nThis plugins support default configurations that apply to every `metric`\ndeclaration.\n\n| Key                       | Default Value | Description |\n|---------------------------|---------------|-------------|\n| `default_field_separator` | `.`           | A character to use to join Mbean attributes when creating fields. |\n| `default_field_prefix`    | _None_        | A string to prepend to the field names produced by all `metric` declarations. |\n| `default_tag_prefix`      | _None_        | A string to prepend to the tag names produced by all `metric` declarations. |\n\n## Metrics\n\nThe metrics depend on the definition(s) in the `inputs.jolokia2_agent.metric`\nsection(s).\n\n## Example Output\n\n```text\njvm_memory_pool,pool_name=Compressed\\ Class\\ Space PeakUsage.max=1073741824,PeakUsage.committed=3145728,PeakUsage.init=0,Usage.committed=3145728,Usage.init=0,PeakUsage.used=3017976,Usage.max=1073741824,Usage.used=3017976 1503764025000000000\njvm_memory_pool,pool_name=Code\\ Cache PeakUsage.init=2555904,PeakUsage.committed=6291456,Usage.committed=6291456,PeakUsage.used=6202752,PeakUsage.max=251658240,Usage.used=6210368,Usage.max=251658240,Usage.init=2555904 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Eden\\ Space CollectionUsage.max=-1,PeakUsage.committed=56623104,PeakUsage.init=56623104,PeakUsage.used=53477376,Usage.max=-1,Usage.committed=49283072,Usage.used=19922944,CollectionUsage.committed=49283072,CollectionUsage.init=56623104,CollectionUsage.used=0,PeakUsage.max=-1,Usage.init=56623104 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Old\\ Gen CollectionUsage.max=1073741824,CollectionUsage.committed=0,PeakUsage.max=1073741824,PeakUsage.committed=1017118720,PeakUsage.init=1017118720,PeakUsage.used=137032208,Usage.max=1073741824,CollectionUsage.init=1017118720,Usage.committed=1017118720,Usage.init=1017118720,Usage.used=134708752,CollectionUsage.used=0 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Survivor\\ Space Usage.max=-1,Usage.init=0,CollectionUsage.max=-1,CollectionUsage.committed=7340032,CollectionUsage.used=7340032,PeakUsage.committed=7340032,Usage.committed=7340032,Usage.used=7340032,CollectionUsage.init=0,PeakUsage.max=-1,PeakUsage.init=0,PeakUsage.used=7340032 1503764025000000000\njvm_memory_pool,pool_name=Metaspace PeakUsage.init=0,PeakUsage.used=21852224,PeakUsage.max=-1,Usage.max=-1,Usage.committed=22282240,Usage.init=0,Usage.used=21852224,PeakUsage.committed=22282240 1503764025000000000\n```\n\n## Example Configurations\n\n* [ActiveMQ](/plugins/inputs/jolokia2_agent/examples/activemq.conf)\n* [BitBucket](/plugins/inputs/jolokia2_agent/examples/bitbucket.conf)\n* [Cassandra](/plugins/inputs/jolokia2_agent/examples/cassandra.conf)\n* [Hadoop-HDFS](/plugins/inputs/jolokia2_agent/examples/hadoop-hdfs.conf)\n* [Java JVM](/plugins/inputs/jolokia2_agent/examples/java.conf)\n* [JBoss](/plugins/inputs/jolokia2_agent/examples/jboss.conf)\n* [Kafka](/plugins/inputs/jolokia2_agent/examples/kafka.conf)\n* [Kafka Connect](/plugins/inputs/jolokia2_agent/examples/kafka-connect.conf)\n* [Tomcat](/plugins/inputs/jolokia2_agent/examples/tomcat.conf)\n* [Weblogic](/plugins/inputs/jolokia2_agent/examples/weblogic.conf)\n* [ZooKeeper](/plugins/inputs/jolokia2_agent/examples/zookeeper.conf)\n\nPlease help improve this list and contribute new configuration files by opening\nan issue or pull request.\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/activemq.conf",
    "content": "## Jolokia is bundled with ActiveMQ\n\n[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8161/api/jolokia\"]\n  name_prefix = \"activemq.\"\n  username = \"admin\"\n  password = \"admin\"\n\n  ### JVM Generic\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\",\"SystemLoadAverage\",\"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"jvm_garbage_collector\"\n    mbean    = \"java.lang:name=*,type=GarbageCollector\"\n    paths    = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"jvm_memory_pool\"\n    mbean      = \"java.lang:name=*,type=MemoryPool\"\n    paths      = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys   = [\"name\"]\n    tag_prefix = \"pool_\"\n\n  ### ACTIVEMQ\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"queue\"\n    mbean    = \"org.apache.activemq:brokerName=*,destinationName=*,destinationType=Queue,type=Broker\"\n    paths    = [\"QueueSize\",\"EnqueueCount\",\"ConsumerCount\",\"DispatchCount\",\"DequeueCount\",\"ProducerCount\",\"InFlightCount\"]\n    tag_keys = [\"brokerName\",\"destinationName\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"topic\"\n    mbean    = \"org.apache.activemq:brokerName=*,destinationName=*,destinationType=Topic,type=Broker\"\n    paths    = [\"ProducerCount\",\"DequeueCount\",\"ConsumerCount\",\"QueueSize\",\"EnqueueCount\"]\n    tag_keys = [\"brokerName\",\"destinationName\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"broker\"\n    mbean    = \"org.apache.activemq:brokerName=*,type=Broker\"\n    paths    = [\"TotalConsumerCount\",\"TotalMessageCount\",\"TotalEnqueueCount\",\"TotalDequeueCount\",\"MemoryLimit\",\"MemoryPercentUsage\",\"StoreLimit\",\"StorePercentUsage\",\"TempPercentUsage\",\"TempLimit\"]\n    tag_keys = [\"brokerName\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/bitbucket.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8778/jolokia\"]\n  name_prefix = \"bitbucket.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_operatingsystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_thread\"\n    mbean = \"java.lang:type=Threading\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_class_loading\"\n    mbean = \"java.lang:type=ClassLoading\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory_pool\"\n    mbean = \"java.lang:type=MemoryPool,name=*\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"webhooks\"\n    mbean = \"com.atlassian.webhooks:name=*\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"atlassian\"\n    mbean = \"com.atlassian.bitbucket:name=*\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"thread_pools\"\n    mbean = \"com.atlassian.bitbucket.thread-pools:name=*\"\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/cassandra.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8778/jolokia\"]\n  name_prefix = \"java_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"Memory\"\n    mbean = \"java.lang:type=Memory\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"GarbageCollector\"\n    mbean = \"java.lang:name=*,type=GarbageCollector\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8778/jolokia\"]\n  name_prefix = \"cassandra_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"Cache\"\n    mbean = \"org.apache.cassandra.metrics:name=*,scope=*,type=Cache\"\n    tag_keys = [\"name\", \"scope\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"Client\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=Client\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"ClientRequestMetrics\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=ClientRequestMetrics\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"ClientRequest\"\n    mbean = \"org.apache.cassandra.metrics:name=*,scope=*,type=ClientRequest\"\n    tag_keys = [\"name\", \"scope\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"ColumnFamily\"\n    mbean = \"org.apache.cassandra.metrics:keyspace=*,name=*,scope=*,type=ColumnFamily\"\n    tag_keys = [\"keyspace\", \"name\", \"scope\"]\n    field_prefix = \"$2_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"CommitLog\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=CommitLog\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"Compaction\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=Compaction\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"CQL\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=CQL\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"DroppedMessage\"\n    mbean = \"org.apache.cassandra.metrics:name=*,scope=*,type=DroppedMessage\"\n    tag_keys = [\"name\", \"scope\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"FileCache\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=FileCache\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"ReadRepair\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=ReadRepair\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"Storage\"\n    mbean = \"org.apache.cassandra.metrics:name=*,type=Storage\"\n    tag_keys = [\"name\"]\n    field_prefix = \"$1_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"ThreadPools\"\n    mbean = \"org.apache.cassandra.metrics:name=*,path=*,scope=*,type=ThreadPools\"\n    tag_keys = [\"name\", \"path\", \"scope\"]\n    field_prefix = \"$1_\"\n\n  # Optional per Table metrics\n  #[[inputs.jolokia2_agent.metric]]\n  #  name  = \"Table\"\n  #  mbean = \"org.apache.cassandra.metrics:name=*,keyspace=*,scope=*,type=Table\"\n  #  tag_keys = [\"name\",\"scope\",\"keyspace\"]\n  #  field_prefix = \"$1_\"\n\n  # Optional TableAll metrics\n  #[[inputs.jolokia2_agent.metric]]\n  #  name  = \"TableAll\"\n  #  mbean = \"org.apache.cassandra.metrics:name=*,type=Table\"\n  #  tag_keys = [\"name\"]\n  #  field_prefix = \"$1_\"\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/hadoop-hdfs.conf",
    "content": "################\n# NAMENODE     #\n################\n[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8778/jolokia\"]\n  name_prefix = \"hadoop.hdfs.namenode.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"FSNamesystem\"\n    mbean = \"Hadoop:name=FSNamesystem,service=NameNode\"\n    paths = [\"CapacityTotal\", \"CapacityRemaining\", \"CapacityUsedNonDFS\", \"NumLiveDataNodes\", \"NumDeadDataNodes\", \"NumInMaintenanceDeadDataNodes\", \"NumDecomDeadDataNodes\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"FSNamesystemState\"\n    mbean = \"Hadoop:name=FSNamesystemState,service=NameNode\"\n    paths = [\"VolumeFailuresTotal\", \"UnderReplicatedBlocks\", \"BlocksTotal\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\", \"SystemLoadAverage\", \"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_garbage_collector\"\n    mbean = \"java.lang:name=*,type=GarbageCollector\"\n    paths = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_memory_pool\"\n    mbean = \"java.lang:name=*,type=MemoryPool\"\n    paths = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys = [\"name\"]\n    tag_prefix = \"pool_\"\n\n\n################\n# DATANODE     #\n################\n[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:7778/jolokia\"]\n  name_prefix = \"hadoop.hdfs.datanode.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"FSDatasetState\"\n    mbean = \"Hadoop:name=FSDatasetState,service=DataNode\"\n    paths = [\"Capacity\", \"DfsUsed\", \"Remaining\", \"NumBlocksFailedToUnCache\", \"NumBlocksFailedToCache\", \"NumBlocksCached\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\", \"SystemLoadAverage\", \"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_garbage_collector\"\n    mbean = \"java.lang:name=*,type=GarbageCollector\"\n    paths = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"jvm_memory_pool\"\n    mbean = \"java.lang:name=*,type=MemoryPool\"\n    paths = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys = [\"name\"]\n    tag_prefix = \"pool_\"\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/java.conf",
    "content": "\n[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"java_garbage_collector\"\n    mbean    = \"java.lang:name=*,type=GarbageCollector\"\n    paths    = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_last_garbage_collection\"\n    mbean = \"java.lang:name=G1 Young Generation,type=GarbageCollector\"\n    paths = [\"LastGcInfo/duration\", \"LastGcInfo/GcThreadCount\", \"LastGcInfo/memoryUsageAfterGc\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_threading\"\n    mbean = \"java.lang:type=Threading\"\n    paths = [\"TotalStartedThreadCount\", \"ThreadCount\", \"DaemonThreadCount\", \"PeakThreadCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_class_loading\"\n    mbean = \"java.lang:type=ClassLoading\"\n    paths = [\"LoadedClassCount\", \"UnloadedClassCount\", \"TotalLoadedClassCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"java_memory_pool\"\n    mbean    = \"java.lang:name=*,type=MemoryPool\"\n    paths    = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys = [\"name\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/jboss.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n  name_prefix = \"jboss.\"\n\n  ### JVM Generic\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\",\"SystemLoadAverage\",\"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"jvm_garbage_collector\"\n    mbean    = \"java.lang:name=*,type=GarbageCollector\"\n    paths    = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"jvm_memory_pool\"\n    mbean      = \"java.lang:name=*,type=MemoryPool\"\n    paths      = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys   = [\"name\"]\n    tag_prefix = \"pool_\"\n\n  ### JBOSS\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"connectors.http\"\n    mbean    = \"jboss.as:https-listener=*,server=*,subsystem=undertow\"\n    paths    = [\"bytesReceived\",\"bytesSent\",\"errorCount\",\"requestCount\"]\n    tag_keys = [\"server\",\"https-listener\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"connectors.http\"\n    mbean    = \"jboss.as:http-listener=*,server=*,subsystem=undertow\"\n    paths    = [\"bytesReceived\",\"bytesSent\",\"errorCount\",\"requestCount\"]\n    tag_keys = [\"server\",\"http-listener\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"datasource.jdbc\"\n    mbean    = \"jboss.as:data-source=*,statistics=jdbc,subsystem=datasources\"\n    paths    = [\"PreparedStatementCacheAccessCount\",\"PreparedStatementCacheHitCount\",\"PreparedStatementCacheMissCount\"]\n    tag_keys = [\"data-source\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"datasource.pool\"\n    mbean    = \"jboss.as:data-source=*,statistics=pool,subsystem=datasources\"\n    paths    = [\"AvailableCount\",\"ActiveCount\",\"MaxUsedCount\"]\n    tag_keys = [\"data-source\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/kafka-connect.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n  name_prefix = \"kafka.connect.\"\n\n  [[processors.enum]]\n    [[processors.enum.mapping]]\n      field = \"status\"\n\n      [processors.enum.mapping.value_mappings]\n        paused = 0\n        running = 1\n        unassigned = 2\n        failed = 3\n        destroyed = 4\n\n  [inputs.jolokia2_agent.tags]\n    input_type   = \"kafka-connect\"\n\n  # https://kafka.apache.org/documentation/#connect_monitoring\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectWorkerMetrics\"\n    mbean        = \"kafka.connect:type=connect-worker-metrics\"\n    paths        = [\"connector-count\", \"connector-startup-attempts-total\", \"connector-startup-failure-percentage\", \"connector-startup-failure-total\", \"connector-startup-success-percentage\", \"connector-startup-success-total\", \"task-count\", \"task-startup-attempts-total\", \"task-startup-failure-percentage\", \"task-startup-failure-total\", \"task-startup-success-percentage\", \"task-startup-success-total\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectWorkerMetrics\"\n    mbean        = \"kafka.connect:type=connect-worker-metrics,connector=*\"\n    paths        = [\"connector-destroyed-task-count\", \"connector-failed-task-count\", \"connector-paused-task-count\", \"connector-running-task-count\", \"connector-total-task-count\", \"connector-unassigned-task-count\"]\n    tag_keys     = [\"connector\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectWorkerRebalanceMetrics\"\n    mbean        = \"kafka.connect:type=connect-worker-rebalance-metrics\"\n    paths        = [\"completed-rebalances-total\", \"connect-protocol\", \"epoch\", \"leader-name\", \"rebalance-avg-time-ms\", \"rebalance-max-time-ms\", \"rebalancing\", \"time-since-last-rebalance-ms\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectorMetrics\"\n    mbean        = \"kafka.connect:type=connector-metrics,connector=*\"\n    paths        = [\"connector-class\", \"connector-version\", \"connector-type\", \"status\"]\n    tag_keys     = [\"connector\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectorTaskMetrics\"\n    mbean        = \"kafka.connect:type=connector-task-metrics,connector=*,task=*\"\n    paths        = [\"batch-size-avg\", \"batch-size-max\", \"offset-commit-avg-time-ms\", \"offset-commit-failure-percentage\", \"offset-commit-max-time-ms\", \"offset-commit-success-percentage\", \"pause-ratio\", \"running-ratio\", \"status\"]\n    tag_keys     = [\"connector\", \"task\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"sinkTaskMetrics\"\n    mbean        = \"kafka.connect:type=sink-task-metrics,connector=*,task=*\"\n    paths        = [\"offset-commit-completion-rate\", \"offset-commit-completion-total\", \"offset-commit-seq-no\", \"offset-commit-skip-rate\", \"offset-commit-skip-total\", \"partition-count\", \"put-batch-avg-time-ms\", \"put-batch-max-time-ms\", \"sink-record-active-count\", \"sink-record-active-count-avg\", \"sink-record-active-count-max\", \"sink-record-lag-max\", \"sink-record-read-rate\", \"sink-record-read-total\", \"sink-record-send-rate\", \"sink-record-send-total\"]\n    tag_keys     = [\"connector\", \"task\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"sourceTaskMetrics\"\n    mbean        = \"kafka.connect:type=source-task-metrics,connector=*,task=*\"\n    paths        = [\"poll-batch-avg-time-ms\", \"poll-batch-max-time-ms\", \"source-record-active-count\", \"source-record-active-count-avg\", \"source-record-active-count-max\", \"source-record-poll-rate\", \"source-record-poll-total\", \"source-record-write-rate\", \"source-record-write-total\"]\n    tag_keys     = [\"connector\", \"task\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"taskErrorMetrics\"\n    mbean        = \"kafka.connect:type=task-error-metrics,connector=*,task=*\"\n    paths        = [\"deadletterqueue-produce-failures\", \"deadletterqueue-produce-requests\", \"last-error-timestamp\", \"total-errors-logged\", \"total-record-errors\", \"total-record-failures\", \"total-records-skipped\", \"total-retries\"]\n    tag_keys     = [\"connector\", \"task\"]\n\n  # https://kafka.apache.org/documentation/#selector_monitoring\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectMetrics\"\n    mbean        = \"kafka.connect:type=connect-metrics,client-id=*\"\n    paths        = [\"connection-close-rate\", \"connection-close-total\", \"connection-creation-rate\", \"connection-creation-total\", \"network-io-rate\", \"network-io-total\", \"outgoing-byte-rate\", \"outgoing-byte-total\", \"request-rate\", \"request-total\", \"request-size-avg\", \"request-size-max\", \"incoming-byte-rate\", \"incoming-byte-rate\", \"incoming-byte-total\", \"response-rate\", \"response-total\", \"select-rate\", \"select-total\", \"io-wait-time-ns-avg\", \"io-wait-ratio\", \"io-time-ns-avg\", \"io-ratio\", \"connection-count\", \"successful-authentication-rate\", \"successful-authentication-total\", \"failed-authentication-rate\", \"failed-authentication-total\", \"successful-reauthentication-rate\", \"successful-reauthentication-total\", \"reauthentication-latency-max\", \"reauthentication-latency-avg\", \"failed-reauthentication-rate\", \"failed-reauthentication-total\", \"successful-authentication-no-reauth-total\"]\n    tag_keys     = [\"client-id\"]\n\n  # https://kafka.apache.org/documentation/#common_node_monitoring\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectNodeMetrics\"\n    mbean        = \"kafka.connect:type=connect-node-metrics,client-id=*,node-id=*\"\n    paths        = [\"outgoing-byte-rate\", \"outgoing-byte-total\", \"request-rate\", \"request-total\", \"request-size-avg\", \"request-size-max\", \"incoming-byte-rate\", \"incoming-byte-total\", \"request-latency-avg\", \"request-latency-max\", \"response-rate\", \"response-total\"]\n    tag_keys     = [\"client-id\", \"node-id\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"appInfo\"\n    mbean        = \"kafka.connect:type=app-info,client-id=*\"\n    paths        = [\"start-time-ms\", \"commit-id\", \"version\"]\n    tag_keys     = [\"client-id\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"connectCoordinatorMetrics\"\n    mbean        = \"kafka.connect:type=connect-coordinator-metrics,client-id=*\"\n    paths        = [\"join-time-max\", \"failed-rebalance-rate-per-hour\", \"rebalance-latency-total\", \"sync-time-avg\", \"join-rate\", \"sync-rate\", \"failed-rebalance-total\", \"rebalance-total\", \"last-heartbeat-seconds-ago\", \"heartbeat-rate\", \"join-time-avg\", \"sync-total\", \"rebalance-latency-max\", \"sync-time-max\", \"last-rebalance-seconds-ago\", \"rebalance-rate-per-hour\", \"assigned-connectors\", \"heartbeat-total\", \"assigned-tasks\", \"heartbeat-response-time-max\", \"rebalance-latency-avg\", \"join-total\"]\n    tag_keys     = [\"client-id\"]"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/kafka.conf",
    "content": "\n[[inputs.jolokia2_agent]]\n  name_prefix = \"kafka_\"\n\n  ## If you intend to use \"non_negative_derivative(1s)\" with \"*.count\" fields, you don't need precalculated fields.\n  # fieldexclude   = [\n  #   \"*.EventType\",\n  #   \"*.FifteenMinuteRate\",\n  #   \"*.FiveMinuteRate\",\n  #   \"*.MeanRate\",\n  #   \"*.OneMinuteRate\",\n  #   \"*.RateUnit\",\n  #   \"*.LatencyUnit\",\n  #   \"*.50thPercentile\",\n  #   \"*.75thPercentile\",\n  #   \"*.95thPercentile\",\n  #   \"*.98thPercentile\",\n  #   \"*.99thPercentile\",\n  #   \"*.999thPercentile\",\n  #   \"*.Min\",\n  #   \"*.Mean\",\n  #   \"*.Max\",\n  #   \"*.StdDev\"\n  # ]\n\n  ## jolokia_agent_url tag is not needed if you have only one instance of Kafka on the server.\n  # tagexclude = [\"jolokia_agent_url\"]\n\n  urls = [\"http://localhost:8080/jolokia\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"controller\"\n    mbean        = \"kafka.controller:name=*,type=*\"\n    field_prefix = \"$1.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"replica_manager\"\n    mbean        = \"kafka.server:name=*,type=ReplicaManager\"\n    field_prefix = \"$1.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"purgatory\"\n    mbean        = \"kafka.server:delayedOperation=*,name=*,type=DelayedOperationPurgatory\"\n    field_prefix = \"$1.\"\n    field_name   = \"$2\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"zookeeper\"\n    mbean        = \"kafka.server:name=*,type=SessionExpireListener\"\n    field_prefix = \"$1.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"user\"\n    mbean    = \"kafka.server:user=*,type=Request\"\n    field_prefix = \"\"\n    tag_keys = [\"user\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"request\"\n    mbean        = \"kafka.network:name=*,request=*,type=RequestMetrics\"\n    field_prefix = \"$1.\"\n    tag_keys     = [\"request\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"topics\"\n    mbean        = \"kafka.server:name=*,type=BrokerTopicMetrics\"\n    field_prefix = \"$1.\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name         = \"topic\"\n    mbean        = \"kafka.server:name=*,topic=*,type=BrokerTopicMetrics\"\n    field_prefix = \"$1.\"\n    tag_keys     = [\"topic\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"partition\"\n    mbean      = \"kafka.log:name=*,partition=*,topic=*,type=Log\"\n    field_name = \"$1\"\n    tag_keys   = [\"topic\", \"partition\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"partition\"\n    mbean      = \"kafka.cluster:name=UnderReplicated,partition=*,topic=*,type=Partition\"\n    field_name = \"UnderReplicatedPartitions\"\n    tag_keys   = [\"topic\", \"partition\"]\n\n## If you have multiple instances of Kafka on the server, use 'jolokia_agent_url' as identity of each instance\n# [[processors.rename]]\n#   namepass = [\"kafka_*\"]\n#   order = 1\n#   [[processors.rename.replace]]\n#     tag = \"jolokia_agent_url\"\n#     dest = \"instance\"\n#\n# [[processors.regex]]\n#   namepass = [\"kafka_*\"]\n#   order = 2\n#   [[processors.regex.tags]]\n#     key = \"instance\"\n#     pattern = \"^.+:8080/.+$\"\n#     replacement = \"0\"\n#   [[processors.regex.tags]]\n#     key = \"instance\"\n#     pattern = \"^.+:8081/.+$\"\n#     replacement = \"1\"\n#   [[processors.regex.tags]]\n#     key = \"instance\"\n#     pattern = \"^.+:8082/.+$\"\n#     replacement = \"2\"\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/tomcat.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n  name_prefix = \"tomcat.\"\n\n  ### JVM Generic\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\",\"SystemLoadAverage\",\"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"jvm_garbage_collector\"\n    mbean    = \"java.lang:name=*,type=GarbageCollector\"\n    paths    = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"jvm_memory_pool\"\n    mbean      = \"java.lang:name=*,type=MemoryPool\"\n    paths      = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys   = [\"name\"]\n    tag_prefix = \"pool_\"\n\n  ### TOMCAT\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"GlobalRequestProcessor\"\n    mbean    = \"Catalina:name=*,type=GlobalRequestProcessor\"\n    paths    = [\"requestCount\",\"bytesReceived\",\"bytesSent\",\"processingTime\",\"errorCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"JspMonitor\"\n    mbean    = \"Catalina:J2EEApplication=*,J2EEServer=*,WebModule=*,name=jsp,type=JspMonitor\"\n    paths    = [\"jspReloadCount\",\"jspCount\",\"jspUnloadCount\"]\n    tag_keys = [\"J2EEApplication\",\"J2EEServer\",\"WebModule\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"ThreadPool\"\n    mbean    = \"Catalina:name=*,type=ThreadPool\"\n    paths    = [\"maxThreads\",\"currentThreadCount\",\"currentThreadsBusy\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"Servlet\"\n    mbean    = \"Catalina:J2EEApplication=*,J2EEServer=*,WebModule=*,j2eeType=Servlet,name=*\"\n    paths    = [\"processingTime\",\"errorCount\",\"requestCount\"]\n    tag_keys = [\"name\",\"J2EEApplication\",\"J2EEServer\",\"WebModule\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"Cache\"\n    mbean    = \"Catalina:context=*,host=*,name=Cache,type=WebResourceRoot\"\n    paths    = [\"hitCount\",\"lookupCount\"]\n    tag_keys = [\"context\",\"host\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/weblogic.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n  name_prefix = \"weblogic.\"\n\n  ### JVM Generic\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"OperatingSystem\"\n    mbean = \"java.lang:type=OperatingSystem\"\n    paths = [\"ProcessCpuLoad\",\"SystemLoadAverage\",\"SystemCpuLoad\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"jvm_memory\"\n    mbean = \"java.lang:type=Memory\"\n    paths = [\"HeapMemoryUsage\", \"NonHeapMemoryUsage\", \"ObjectPendingFinalizationCount\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name     = \"jvm_garbage_collector\"\n    mbean    = \"java.lang:name=*,type=GarbageCollector\"\n    paths    = [\"CollectionTime\", \"CollectionCount\"]\n    tag_keys = [\"name\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"jvm_memory_pool\"\n    mbean      = \"java.lang:name=*,type=MemoryPool\"\n    paths      = [\"Usage\", \"PeakUsage\", \"CollectionUsage\"]\n    tag_keys   = [\"name\"]\n    tag_prefix = \"pool_\"\n\n  ### WLS\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"JTARuntime\"\n    mbean      = \"com.bea:Name=JTARuntime,ServerRuntime=*,Type=JTARuntime\"\n    paths      = [\"SecondsActiveTotalCount\",\"TransactionRolledBackTotalCount\",\"TransactionRolledBackSystemTotalCount\",\"TransactionRolledBackAppTotalCount\",\"TransactionRolledBackResourceTotalCount\",\"TransactionHeuristicsTotalCount\",\"TransactionAbandonedTotalCount\",\"TransactionTotalCount\",\"TransactionRolledBackTimeoutTotalCount\",\"ActiveTransactionsTotalCount\",\"TransactionCommittedTotalCount\"]\n    tag_keys   = [\"ServerRuntime\"]\n    tag_prefix = \"wls_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"ThreadPoolRuntime\"\n    mbean      = \"com.bea:Name=ThreadPoolRuntime,ServerRuntime=*,Type=ThreadPoolRuntime\"\n    paths      = [\"StuckThreadCount\",\"CompletedRequestCount\",\"ExecuteThreadTotalCount\",\"ExecuteThreadIdleCount\",\"StandbyThreadCount\",\"Throughput\",\"HoggingThreadCount\",\"PendingUserRequestCount\"]\n    tag_keys   = [\"ServerRuntime\"]\n    tag_prefix = \"wls_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name       = \"JMSRuntime\"\n    mbean      = \"com.bea:Name=*.jms,ServerRuntime=*,Type=JMSRuntime\"\n    paths      = [\"ConnectionsCurrentCount\",\"ConnectionsHighCount\",\"ConnectionsTotalCount\",\"JMSServersCurrentCount\",\"JMSServersHighCount\",\"JMSServersTotalCount\"]\n    tag_keys   = [\"name\",\"ServerRuntime\"]\n    tag_prefix = \"wls_\"\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/examples/zookeeper.conf",
    "content": "[[inputs.jolokia2_agent]]\n  urls = [\"http://localhost:8080/jolokia\"]\n  name_prefix = \"zk_\"\n\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"quorum\"\n    mbean = \"org.apache.ZooKeeperService:name0=*\"\n    tag_keys = [\"name0\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"leader\"\n    mbean = \"org.apache.ZooKeeperService:name0=*,name1=*,name2=Leader\"\n    tag_keys = [\"name1\"]\n\n  [[inputs.jolokia2_agent.metric]]\n    name = \"follower\"\n    mbean = \"org.apache.ZooKeeperService:name0=*,name1=*,name2=Follower\"\n    tag_keys = [\"name1\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/jolokia2_agent.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage jolokia2_agent\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/jolokia2\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype JolokiaAgent struct {\n\tDefaultFieldPrefix    string `toml:\"default_field_prefix\"`\n\tDefaultFieldSeparator string `toml:\"default_field_separator\"`\n\tDefaultTagPrefix      string `toml:\"default_tag_prefix\"`\n\n\tURLs            []string        `toml:\"urls\"`\n\tUsername        string          `toml:\"username\"`\n\tPassword        string          `toml:\"password\"`\n\tOrigin          string          `toml:\"origin\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\n\ttls.ClientConfig\n\n\tMetrics  []common.MetricConfig `toml:\"metric\"`\n\tgatherer *common.Gatherer\n\tclients  []*common.Client\n}\n\nfunc (*JolokiaAgent) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ja *JolokiaAgent) Gather(acc telegraf.Accumulator) error {\n\tif ja.gatherer == nil {\n\t\tja.gatherer = common.NewGatherer(ja.createMetrics())\n\t}\n\n\t// Initialize clients once\n\tif ja.clients == nil {\n\t\tja.clients = make([]*common.Client, 0, len(ja.URLs))\n\t\tfor _, url := range ja.URLs {\n\t\t\tclient, err := ja.createClient(url)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to create client for %q: %w\", url, err))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tja.clients = append(ja.clients, client)\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\n\tfor _, client := range ja.clients {\n\t\twg.Add(1)\n\t\tgo func(client *common.Client) {\n\t\t\tdefer wg.Done()\n\n\t\t\terr := ja.gatherer.Gather(client, acc)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to gather metrics for %q: %w\", client.URL, err))\n\t\t\t}\n\t\t}(client)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (ja *JolokiaAgent) createMetrics() []common.Metric {\n\tmetrics := make([]common.Metric, 0, len(ja.Metrics))\n\tfor _, metricConfig := range ja.Metrics {\n\t\tmetrics = append(metrics, common.NewMetric(metricConfig, ja.DefaultFieldPrefix, ja.DefaultFieldSeparator, ja.DefaultTagPrefix))\n\t}\n\n\treturn metrics\n}\n\nfunc (ja *JolokiaAgent) createClient(url string) (*common.Client, error) {\n\treturn common.NewClient(url, &common.ClientConfig{\n\t\tUsername:        ja.Username,\n\t\tPassword:        ja.Password,\n\t\tOrigin:          ja.Origin,\n\t\tResponseTimeout: time.Duration(ja.ResponseTimeout),\n\t\tClientConfig:    ja.ClientConfig,\n\t})\n}\n\nfunc init() {\n\tinputs.Add(\"jolokia2_agent\", func() telegraf.Input {\n\t\treturn &JolokiaAgent{\n\t\t\tDefaultFieldSeparator: \".\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/jolokia2_agent_test.go",
    "content": "package jolokia2_agent_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/jolokia2\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/jolokia2_agent\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestScalarValues(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"scalar_without_attribute\"\n\t\tmbean = \"scalar_without_attribute\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"scalar_with_attribute\"\n\t\tmbean = \"scalar_with_attribute\"\n\t\tpaths = [\"biz\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"scalar_with_attribute_and_path\"\n\t\tmbean = \"scalar_with_attribute_and_path\"\n\t\tpaths = [\"biz/baz\"]\n\n\t# This should return multiple series with different test tags.\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"scalar_with_key_pattern\"\n\t\tmbean    = \"scalar_with_key_pattern:test=*\"\n\t\ttag_keys = [\"test\"]`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_without_attribute\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t  }, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_with_attribute\",\n\t\t\t\"attribute\": \"biz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 456,\n\t\t\"status\": 200\n\t  }, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_with_attribute_and_path\",\n\t\t\t\"attribute\": \"biz\",\n\t\t\t\"path\": \"baz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 789,\n\t\t\"status\": 200\n\t  }, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_with_key_pattern:test=*\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"scalar_with_key_pattern:test=foo\": 123,\n\t\t\t\"scalar_with_key_pattern:test=bar\": 456\n\t\t},\n\t\t\"status\": 200\n\t  }]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"scalar_without_attribute\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"scalar_with_attribute\", map[string]interface{}{\n\t\t\"biz\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"scalar_with_attribute_and_path\", map[string]interface{}{\n\t\t\"biz.baz\": 789.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"scalar_with_key_pattern\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t\t\"test\":              \"foo\",\n\t})\n\tacc.AssertContainsTaggedFields(t, \"scalar_with_key_pattern\", map[string]interface{}{\n\t\t\"value\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t\t\"test\":              \"bar\",\n\t})\n}\n\nfunc TestObjectValues(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"object_without_attribute\"\n\t\tmbean    = \"object_without_attribute\"\n\t\ttag_keys = [\"foo\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"object_with_attribute\"\n\t\tmbean = \"object_with_attribute\"\n\t\tpaths = [\"biz\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"object_with_attribute_and_path\"\n\t\tmbean = \"object_with_attribute_and_path\"\n\t\tpaths = [\"biz/baz\"]\n\n\t# This will generate two separate request objects.\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"object_with_branching_paths\"\n\t\tmbean = \"object_with_branching_paths\"\n\t\tpaths = [\"foo/fiz\", \"foo/faz\"]\n\n\t# This should return multiple series with different test tags.\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"object_with_key_pattern\"\n\t\tmbean    = \"object_with_key_pattern:test=*\"\n\t\ttag_keys = [\"test\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"ColumnFamily\"\n\t\tmbean = \"org.apache.cassandra.metrics:keyspace=*,name=EstimatedRowSizeHistogram,scope=schema_columns,type=ColumnFamily\"\n\t\ttag_keys = [\"keyspace\", \"name\", \"scope\"]`\n\n\tresponse, err := os.ReadFile(\"./testdata/response.json\")\n\trequire.NoError(t, err)\n\n\tserver := setupServer(string(response))\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"object_without_attribute\", map[string]interface{}{\n\t\t\"biz\": 123.0,\n\t\t\"baz\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"object_with_attribute\", map[string]interface{}{\n\t\t\"biz.fiz\": 123.0,\n\t\t\"biz.faz\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"object_with_attribute_and_path\", map[string]interface{}{\n\t\t\"biz.baz.bing\": 123.0,\n\t\t\"biz.baz.bang\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"object_with_branching_paths\", map[string]interface{}{\n\t\t\"foo.fiz.bing\": 123.0,\n\t\t\"foo.faz.bang\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"object_with_key_pattern\", map[string]interface{}{\n\t\t\"fiz\": 123.0,\n\t}, map[string]string{\n\t\t\"test\":              \"foo\",\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"object_with_key_pattern\", map[string]interface{}{\n\t\t\"biz\": 456.0,\n\t}, map[string]string{\n\t\t\"test\":              \"bar\",\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n}\n\nfunc TestStatusCodes(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"ok\"\n\t\tmbean    = \"ok\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname       = \"not_found\"\n\t\tmbean      = \"not_found\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname       = \"unknown\"\n\t\tmbean      = \"unknown\"`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"ok\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 1,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"not_found\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"status\": 404\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"unknown\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"status\": 500\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"ok\", map[string]interface{}{\n\t\t\"value\": 1.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertDoesNotContainMeasurement(t, \"not_found\")\n\tacc.AssertDoesNotContainMeasurement(t, \"unknown\")\n}\n\nfunc TestTagRenaming(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\tdefault_tag_prefix = \"DEFAULT_PREFIX_\"\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"default_tag_prefix\"\n\t\tmbean    = \"default_tag_prefix:biz=baz,fiz=faz\"\n\t\ttag_keys = [\"biz\", \"fiz\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname       = \"custom_tag_prefix\"\n\t\tmbean      = \"custom_tag_prefix:biz=baz,fiz=faz\"\n\t\ttag_keys   = [\"biz\", \"fiz\"]\n\t\ttag_prefix = \"CUSTOM_PREFIX_\"`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"default_tag_prefix:biz=baz,fiz=faz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"custom_tag_prefix:biz=baz,fiz=faz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"default_tag_prefix\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"DEFAULT_PREFIX_biz\": \"baz\",\n\t\t\"DEFAULT_PREFIX_fiz\": \"faz\",\n\t\t\"jolokia_agent_url\":  server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"custom_tag_prefix\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"CUSTOM_PREFIX_biz\": \"baz\",\n\t\t\"CUSTOM_PREFIX_fiz\": \"faz\",\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n}\n\nfunc TestFieldRenaming(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\tdefault_field_prefix    = \"DEFAULT_PREFIX_\"\n\t\tdefault_field_separator = \"_DEFAULT_SEPARATOR_\"\n\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname  = \"default_field_modifiers\"\n\t\tmbean = \"default_field_modifiers\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname            = \"custom_field_modifiers\"\n\t\tmbean           = \"custom_field_modifiers\"\n\t\tfield_prefix    = \"CUSTOM_PREFIX_\"\n\t\tfield_separator = \"_CUSTOM_SEPARATOR_\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname            = \"field_prefix_substitution\"\n\t\tmbean           = \"field_prefix_substitution:foo=*\"\n\t\tfield_prefix    = \"$1_\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname         = \"field_name_substitution\"\n\t\tmbean        = \"field_name_substitution:foo=*\"\n\t\tfield_prefix = \"\"\n\t\tfield_name   = \"$1\"`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"default_field_modifiers\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"hello\": { \"world\": 123 }\n\t\t},\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"custom_field_modifiers\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"hello\": { \"world\": 123 }\n\t\t},\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"field_prefix_substitution:foo=*\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"field_prefix_substitution:foo=biz\": 123,\n\t\t\t\"field_prefix_substitution:foo=baz\": 456\n\t\t},\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"field_name_substitution:foo=*\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"field_name_substitution:foo=biz\": 123,\n\t\t\t\"field_name_substitution:foo=baz\": 456\n\t\t},\n\t\t\"status\": 200\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"default_field_modifiers\", map[string]interface{}{\n\t\t\"DEFAULT_PREFIX_hello_DEFAULT_SEPARATOR_world\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"custom_field_modifiers\", map[string]interface{}{\n\t\t\"CUSTOM_PREFIX_hello_CUSTOM_SEPARATOR_world\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"field_prefix_substitution\", map[string]interface{}{\n\t\t\"biz_value\": 123.0,\n\t\t\"baz_value\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"field_name_substitution\", map[string]interface{}{\n\t\t\"biz\": 123.0,\n\t\t\"baz\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n}\n\nfunc TestMetricMbeanMatching(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname = \"mbean_name_and_object_keys\"\n\t\tmbean = \"test1:foo=bar,fizz=buzz\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname = \"mbean_name_and_unordered_object_keys\"\n\t\tmbean = \"test2:fizz=buzz,foo=bar\"\n\n\t[[jolokia2_agent.metric]]\n\t\tname = \"mbean_name_and_attributes\"\n\t\tmbean = \"test3\"\n\t\tpaths = [\"foo\", \"bar\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname = \"mbean_name_and_attribute_with_paths\"\n\t\tmbean = \"test4\"\n\t\tpaths = [\"flavor/chocolate\", \"flavor/strawberry\"]\n\t`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test1:foo=bar,fizz=buzz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test2:foo=bar,fizz=buzz\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test3\",\n\t\t\t\"attribute\": \"foo\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test3\",\n\t\t\t\"attribute\": \"bar\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 456,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test4\",\n\t\t\t\"attribute\": \"flavor\",\n\t\t\t\"path\": \"chocolate\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"test4\",\n\t\t\t\"attribute\": \"flavor\",\n\t\t\t\"path\": \"strawberry\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 456,\n\t\t\"status\": 200\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"mbean_name_and_object_keys\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"mbean_name_and_unordered_object_keys\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"mbean_name_and_attributes\", map[string]interface{}{\n\t\t\"foo\": 123.0,\n\t\t\"bar\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"mbean_name_and_attribute_with_paths\", map[string]interface{}{\n\t\t\"flavor.chocolate\":  123.0,\n\t\t\"flavor.strawberry\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n}\n\nfunc TestMetricCompaction(t *testing.T) {\n\tconfig := `\n\t[jolokia2_agent]\n\t\turls = [\"%s\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"compact_metric\"\n\t\tmbean    = \"scalar_value:flavor=chocolate\"\n\t\ttag_keys = [\"flavor\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"compact_metric\"\n\t\tmbean    = \"scalar_value:flavor=vanilla\"\n\t\ttag_keys = [\"flavor\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"compact_metric\"\n\t\tmbean    = \"object_value1:flavor=chocolate\"\n\t\ttag_keys = [\"flavor\"]\n\n\t[[jolokia2_agent.metric]]\n\t\tname     = \"compact_metric\"\n\t\tmbean    = \"object_value2:flavor=chocolate\"\n\t\ttag_keys = [\"flavor\"]`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_value:flavor=chocolate\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"scalar_value:flavor=vanilla\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": 999,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"object_value1:flavor=chocolate\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"foo\": 456\n\t\t},\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"mbean\": \"object_value2:flavor=chocolate\",\n\t\t\t\"type\": \"read\"\n\t\t},\n\t\t\"value\": {\n\t\t\t\"bar\": 789\n\t\t},\n\t\t\"status\": 200\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"compact_metric\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t\t\"foo\":   456.0,\n\t\t\"bar\":   789.0,\n\t}, map[string]string{\n\t\t\"flavor\":            \"chocolate\",\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n\n\tacc.AssertContainsTaggedFields(t, \"compact_metric\", map[string]interface{}{\n\t\t\"value\": 999.0,\n\t}, map[string]string{\n\t\t\"flavor\":            \"vanilla\",\n\t\t\"jolokia_agent_url\": server.URL,\n\t})\n}\n\nfunc TestJolokia2_ClientAuthRequest(t *testing.T) {\n\tvar username string\n\tvar password string\n\tvar requests []map[string]interface{}\n\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tusername, password, _ = r.BasicAuth()\n\n\t\tbody, err := io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tif err := json.Unmarshal(body, &requests); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\tplugin := setupPlugin(t, fmt.Sprintf(`\n\t\t[jolokia2_agent]\n\t\t\turls = [\"%s/jolokia\"]\n\t\t\tusername = \"sally\"\n\t\t\tpassword = \"seashore\"\n\t\t[[jolokia2_agent.metric]]\n\t\t\tname  = \"hello\"\n\t\t\tmbean = \"hello:foo=bar\"\n\t`, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\trequire.EqualValuesf(t, \"sally\", username, \"Expected to post with username %s, but was %s\", \"sally\", username)\n\trequire.EqualValuesf(t, \"seashore\", password, \"Expected to post with password %s, but was %s\", \"seashore\", password)\n\trequire.NotEmpty(t, requests, \"Expected to post a request body, but was empty.\")\n\n\trequest := requests[0][\"mbean\"]\n\trequire.EqualValuesf(t, \"hello:foo=bar\", request, \"Expected to query mbean %s, but was %s\", \"hello:foo=bar\", request)\n}\n\nfunc TestFillFields(t *testing.T) {\n\tcomplexPoint := map[string]interface{}{\"Value\": []interface{}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}\n\tscalarPoint := []interface{}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}\n\n\tresults := map[string]interface{}{}\n\tcommon.NewPointBuilder(common.Metric{Name: \"test\", Mbean: \"complex\"}, []string{\"this\", \"that\"}, \"/\").FillFields(\"\", complexPoint, results)\n\trequire.Equal(t, map[string]interface{}{}, results)\n\n\tresults = map[string]interface{}{}\n\tcommon.NewPointBuilder(common.Metric{Name: \"test\", Mbean: \"scalar\"}, []string{\"this\", \"that\"}, \"/\").FillFields(\"\", scalarPoint, results)\n\trequire.Equal(t, map[string]interface{}{}, results)\n}\n\nfunc TestIntegrationArtemis(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"apache/activemq-artemis\",\n\t\tExposedPorts: []string{\"61616\", \"8161\"},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"Artemis Console available at\"),\n\t\t\twait.ForListeningPort(nat.Port(\"8161\")),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[\"8161\"]\n\tendpoint := \"http://\" + container.Address + \":\" + port + \"/console/jolokia/\"\n\tplugin := &jolokia2_agent.JolokiaAgent{\n\t\tURLs:     []string{endpoint},\n\t\tUsername: \"artemis\",\n\t\tPassword: \"artemis\",\n\t\tMetrics: []common.MetricConfig{\n\t\t\t{\n\t\t\t\tName:    \"artemis\",\n\t\t\t\tMbean:   `org.apache.activemq.artemis:broker=\"*\",component=addresses,address=\"*\",subcomponent=queues,routing-type=\"anycast\",queue=\"*\"`,\n\t\t\t\tTagKeys: []string{\"queue\", \"subcomponent\"},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"artemis\",\n\t\t\tmap[string]string{\n\t\t\t\t\"jolokia_agent_url\": endpoint,\n\t\t\t\t\"queue\":             \"$sys.mqtt.sessions\",\n\t\t\t\t\"subcomponent\":      \"queues\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AcknowledgeAttempts\":             float64(0),\n\t\t\t\t\"Address\":                         \"ExpiryQueue\",\n\t\t\t\t\"AutoDelete\":                      false,\n\t\t\t\t\"ConfigurationManaged\":            false,\n\t\t\t\t\"ConsumerCount\":                   float64(0),\n\t\t\t\t\"ConsumersBeforeDispatch\":         float64(0),\n\t\t\t\t\"DeadLetterAddress\":               \"DLQ\",\n\t\t\t\t\"DelayBeforeDispatch\":             float64(0),\n\t\t\t\t\"DeliveringCount\":                 float64(0),\n\t\t\t\t\"DeliveringSize\":                  float64(0),\n\t\t\t\t\"Durable\":                         false,\n\t\t\t\t\"DurableDeliveringCount\":          float64(0),\n\t\t\t\t\"DurableDeliveringSize\":           float64(0),\n\t\t\t\t\"DurableMessageCount\":             float64(0),\n\t\t\t\t\"DurablePersistentSize\":           float64(0),\n\t\t\t\t\"DurableScheduledCount\":           float64(0),\n\t\t\t\t\"DurableScheduledSize\":            float64(0),\n\t\t\t\t\"Enabled\":                         true,\n\t\t\t\t\"Exclusive\":                       true,\n\t\t\t\t\"ExpiryAddress\":                   \"ExpiryQueue\",\n\t\t\t\t\"FirstMessageAsJSON\":              \"[{}]\",\n\t\t\t\t\"GroupBuckets\":                    float64(0),\n\t\t\t\t\"GroupCount\":                      float64(0),\n\t\t\t\t\"GroupRebalance\":                  false,\n\t\t\t\t\"GroupRebalancePauseDispatch\":     false,\n\t\t\t\t\"ID\":                              float64(0),\n\t\t\t\t\"InternalQueue\":                   false,\n\t\t\t\t\"LastValue\":                       false,\n\t\t\t\t\"LastValueKey\":                    \"\",\n\t\t\t\t\"MaxConsumers\":                    float64(0),\n\t\t\t\t\"MessageCount\":                    float64(0),\n\t\t\t\t\"MessagesAcknowledged\":            float64(0),\n\t\t\t\t\"MessagesAdded\":                   float64(0),\n\t\t\t\t\"MessagesExpired\":                 float64(0),\n\t\t\t\t\"MessagesKilled\":                  float64(0),\n\t\t\t\t\"Name\":                            \"ExpiryQueue\",\n\t\t\t\t\"Paused\":                          false,\n\t\t\t\t\"PersistedPause\":                  false,\n\t\t\t\t\"PersistentSize\":                  float64(0),\n\t\t\t\t\"PreparedTransactionMessageCount\": float64(0),\n\t\t\t\t\"PurgeOnNoConsumers\":              false,\n\t\t\t\t\"RetroactiveResource\":             false,\n\t\t\t\t\"RingSize\":                        float64(0),\n\t\t\t\t\"RoutingType\":                     \"ANYCAST\",\n\t\t\t\t\"ScheduledCount\":                  float64(0),\n\t\t\t\t\"ScheduledSize\":                   float64(0),\n\t\t\t\t\"Temporary\":                       false,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"artemis\",\n\t\t\tmap[string]string{\n\t\t\t\t\"jolokia_agent_url\": endpoint,\n\t\t\t\t\"queue\":             \"ExpiryQueue\",\n\t\t\t\t\"subcomponent\":      \"queues\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AcknowledgeAttempts\":             float64(0),\n\t\t\t\t\"Address\":                         \"ExpiryQueue\",\n\t\t\t\t\"AutoDelete\":                      false,\n\t\t\t\t\"ConfigurationManaged\":            false,\n\t\t\t\t\"ConsumerCount\":                   float64(0),\n\t\t\t\t\"ConsumersBeforeDispatch\":         float64(0),\n\t\t\t\t\"DeadLetterAddress\":               \"DLQ\",\n\t\t\t\t\"DelayBeforeDispatch\":             float64(0),\n\t\t\t\t\"DeliveringCount\":                 float64(0),\n\t\t\t\t\"DeliveringSize\":                  float64(0),\n\t\t\t\t\"Durable\":                         false,\n\t\t\t\t\"DurableDeliveringCount\":          float64(0),\n\t\t\t\t\"DurableDeliveringSize\":           float64(0),\n\t\t\t\t\"DurableMessageCount\":             float64(0),\n\t\t\t\t\"DurablePersistentSize\":           float64(0),\n\t\t\t\t\"DurableScheduledCount\":           float64(0),\n\t\t\t\t\"DurableScheduledSize\":            float64(0),\n\t\t\t\t\"Enabled\":                         true,\n\t\t\t\t\"Exclusive\":                       true,\n\t\t\t\t\"ExpiryAddress\":                   \"ExpiryQueue\",\n\t\t\t\t\"FirstMessageAsJSON\":              \"[{}]\",\n\t\t\t\t\"GroupBuckets\":                    float64(0),\n\t\t\t\t\"GroupCount\":                      float64(0),\n\t\t\t\t\"GroupRebalance\":                  false,\n\t\t\t\t\"GroupRebalancePauseDispatch\":     false,\n\t\t\t\t\"ID\":                              float64(0),\n\t\t\t\t\"InternalQueue\":                   false,\n\t\t\t\t\"LastValue\":                       false,\n\t\t\t\t\"MaxConsumers\":                    float64(0),\n\t\t\t\t\"MessageCount\":                    float64(0),\n\t\t\t\t\"MessagesAcknowledged\":            float64(0),\n\t\t\t\t\"MessagesAdded\":                   float64(0),\n\t\t\t\t\"MessagesExpired\":                 float64(0),\n\t\t\t\t\"MessagesKilled\":                  float64(0),\n\t\t\t\t\"Name\":                            \"ExpiryQueue\",\n\t\t\t\t\"Paused\":                          false,\n\t\t\t\t\"PersistedPause\":                  false,\n\t\t\t\t\"PersistentSize\":                  float64(0),\n\t\t\t\t\"PreparedTransactionMessageCount\": float64(0),\n\t\t\t\t\"PurgeOnNoConsumers\":              false,\n\t\t\t\t\"RetroactiveResource\":             false,\n\t\t\t\t\"RingSize\":                        float64(0),\n\t\t\t\t\"RoutingType\":                     \"ANYCAST\",\n\t\t\t\t\"ScheduledCount\":                  float64(0),\n\t\t\t\t\"ScheduledSize\":                   float64(0),\n\t\t\t\t\"Temporary\":                       false,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"artemis\",\n\t\t\tmap[string]string{\n\t\t\t\t\"jolokia_agent_url\": endpoint,\n\t\t\t\t\"queue\":             \"DLQ\",\n\t\t\t\t\"subcomponent\":      \"queues\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"AcknowledgeAttempts\":             float64(0),\n\t\t\t\t\"Address\":                         \"DLQ\",\n\t\t\t\t\"AutoDelete\":                      false,\n\t\t\t\t\"ConfigurationManaged\":            false,\n\t\t\t\t\"ConsumerCount\":                   float64(0),\n\t\t\t\t\"ConsumersBeforeDispatch\":         float64(0),\n\t\t\t\t\"DeadLetterAddress\":               \"DLQ\",\n\t\t\t\t\"DelayBeforeDispatch\":             float64(0),\n\t\t\t\t\"DeliveringCount\":                 float64(0),\n\t\t\t\t\"DeliveringSize\":                  float64(0),\n\t\t\t\t\"Durable\":                         false,\n\t\t\t\t\"DurableDeliveringCount\":          float64(0),\n\t\t\t\t\"DurableDeliveringSize\":           float64(0),\n\t\t\t\t\"DurableMessageCount\":             float64(0),\n\t\t\t\t\"DurablePersistentSize\":           float64(0),\n\t\t\t\t\"DurableScheduledCount\":           float64(0),\n\t\t\t\t\"DurableScheduledSize\":            float64(0),\n\t\t\t\t\"Enabled\":                         true,\n\t\t\t\t\"Exclusive\":                       true,\n\t\t\t\t\"ExpiryAddress\":                   \"ExpiryQueue\",\n\t\t\t\t\"FirstMessageAsJSON\":              \"[{}]\",\n\t\t\t\t\"GroupBuckets\":                    float64(0),\n\t\t\t\t\"GroupCount\":                      float64(0),\n\t\t\t\t\"GroupRebalance\":                  false,\n\t\t\t\t\"GroupRebalancePauseDispatch\":     false,\n\t\t\t\t\"ID\":                              float64(0),\n\t\t\t\t\"InternalQueue\":                   false,\n\t\t\t\t\"LastValue\":                       false,\n\t\t\t\t\"MaxConsumers\":                    float64(0),\n\t\t\t\t\"MessageCount\":                    float64(0),\n\t\t\t\t\"MessagesAcknowledged\":            float64(0),\n\t\t\t\t\"MessagesAdded\":                   float64(0),\n\t\t\t\t\"MessagesExpired\":                 float64(0),\n\t\t\t\t\"MessagesKilled\":                  float64(0),\n\t\t\t\t\"Name\":                            \"DLQ\",\n\t\t\t\t\"Paused\":                          false,\n\t\t\t\t\"PersistedPause\":                  false,\n\t\t\t\t\"PersistentSize\":                  float64(0),\n\t\t\t\t\"PreparedTransactionMessageCount\": float64(0),\n\t\t\t\t\"PurgeOnNoConsumers\":              false,\n\t\t\t\t\"RetroactiveResource\":             false,\n\t\t\t\t\"RingSize\":                        float64(0),\n\t\t\t\t\"RoutingType\":                     \"ANYCAST\",\n\t\t\t\t\"ScheduledCount\":                  float64(0),\n\t\t\t\t\"ScheduledSize\":                   float64(0),\n\t\t\t\t\"Temporary\":                       false,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc setupServer(resp string) *httptest.Server {\n\treturn httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tfmt.Fprintln(w, resp)\n\t}))\n}\n\nfunc setupPlugin(t *testing.T, conf string) telegraf.Input {\n\ttable, err := toml.Parse([]byte(conf))\n\tif err != nil {\n\t\tt.Fatalf(\"Unable to parse config! %v\", err)\n\t}\n\n\tfor name := range table.Fields {\n\t\tobject := table.Fields[name]\n\t\tif name == \"jolokia2_agent\" {\n\t\t\tplugin := jolokia2_agent.JolokiaAgent{\n\t\t\t\tDefaultFieldSeparator: \".\",\n\t\t\t}\n\n\t\t\tif err := toml.UnmarshalTable(object.(*ast.Table), &plugin); err != nil {\n\t\t\t\tt.Fatalf(\"Unable to parse jolokia_agent plugin config! %v\", err)\n\t\t\t}\n\n\t\t\treturn &plugin\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/sample.conf",
    "content": "# Read JMX metrics from a Jolokia REST agent endpoint\n[[inputs.jolokia2_agent]]\n  # default_tag_prefix      = \"\"\n  # default_field_prefix    = \"\"\n  # default_field_separator = \".\"\n\n  # Add agents URLs to query\n  urls = [\"http://localhost:8080/jolokia\"]\n  # username = \"\"\n  # password = \"\"\n  # response_timeout = \"5s\"\n\n  ## Optional origin URL to include as a header in the request. Some endpoints\n  ## may reject an empty origin.\n  # origin = \"\"\n\n  ## Optional TLS config\n  # tls_ca   = \"/var/private/ca.pem\"\n  # tls_cert = \"/var/private/client.pem\"\n  # tls_key  = \"/var/private/client-key.pem\"\n  # insecure_skip_verify = false\n\n  ## Add metrics to read\n  [[inputs.jolokia2_agent.metric]]\n    name  = \"java_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_agent/testdata/response.json",
    "content": "[\n  {\n    \"request\": {\n      \"mbean\": \"object_without_attribute\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"biz\": 123,\n      \"baz\": 456\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"object_with_attribute\",\n      \"attribute\": \"biz\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"fiz\": 123,\n      \"faz\": 456\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"object_with_branching_paths\",\n      \"attribute\": \"foo\",\n      \"path\": \"fiz\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"bing\": 123\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"object_with_branching_paths\",\n      \"attribute\": \"foo\",\n      \"path\": \"faz\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"bang\": 456\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"object_with_attribute_and_path\",\n      \"attribute\": \"biz\",\n      \"path\": \"baz\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"bing\": 123,\n      \"bang\": 456\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"object_with_key_pattern:test=*\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"object_with_key_pattern:test=foo\": {\n        \"fiz\": 123\n      },\n      \"object_with_key_pattern:test=bar\": {\n        \"biz\": 456\n      }\n    },\n    \"status\": 200\n  },\n  {\n    \"request\": {\n      \"mbean\": \"org.apache.cassandra.metrics:keyspace=*,name=EstimatedRowSizeHistogram,scope=schema_columns,type=ColumnFamily\",\n      \"type\": \"read\"\n    },\n    \"value\": {\n      \"org.apache.cassandra.metrics:keyspace=system,name=EstimatedRowSizeHistogram,scope=schema_columns,type=ColumnFamily\": {\n        \"Value\": [\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          1,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          1,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0,\n          0\n        ]\n      }\n    },\n    \"status\": 200\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/jolokia2_proxy/README.md",
    "content": "# Jolokia2 Proxy Input Plugin\n\nThis plugin reads JMX metrics from one or more _targets_ by interacting with a\n[Jolokia proxy][jolokia_proxy] REST endpoint.\n\n⭐ Telegraf v1.5.0\n🏷️ applications, network\n💻 all\n\n[jolokia_proxy]: https://jolokia.org/features/proxy.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read JMX metrics from a Jolokia REST proxy endpoint\n[[inputs.jolokia2_proxy]]\n  # default_tag_prefix      = \"\"\n  # default_field_prefix    = \"\"\n  # default_field_separator = \".\"\n\n  ## Proxy agent\n  url = \"http://localhost:8080/jolokia\"\n  # username = \"\"\n  # password = \"\"\n  # response_timeout = \"5s\"\n\n  ## Optional origin URL to include as a header in the request. Some endpoints\n  ## may reject an empty origin.\n  # origin = \"\"\n\n  ## Optional TLS config\n  # tls_ca   = \"/var/private/ca.pem\"\n  # tls_cert = \"/var/private/client.pem\"\n  # tls_key  = \"/var/private/client-key.pem\"\n  # insecure_skip_verify = false\n\n  ## Add proxy targets to query\n  # default_target_username = \"\"\n  # default_target_password = \"\"\n  [[inputs.jolokia2_proxy.target]]\n    url = \"service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi\"\n    # username = \"\"\n    # password = \"\"\n\n  ## Add metrics to read\n  [[inputs.jolokia2_proxy.metric]]\n    name  = \"java_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n```\n\nOptionally, specify TLS options for communicating with proxies:\n\n```toml\n[[inputs.jolokia2_proxy]]\n  url = \"https://proxy:8080/jolokia\"\n\n  tls_ca   = \"/var/private/ca.pem\"\n  tls_cert = \"/var/private/client.pem\"\n  tls_key  = \"/var/private/client-key.pem\"\n  #insecure_skip_verify = false\n\n  #default_target_username = \"\"\n  #default_target_password = \"\"\n  [[inputs.jolokia2_proxy.target]]\n    url = \"service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi\"\n    # username = \"\"\n    # password = \"\"\n\n  [[inputs.jolokia2_proxy.metric]]\n    name  = \"jvm_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n```\n\n### Metric Configuration\n\nPlease see\n[Jolokia agent documentation](../jolokia2_agent/README.md#metric-configuration).\n\n## Metrics\n\nThe metrics depend on the definition(s) in the `inputs.jolokia2_proxy.metric`\nsection(s).\n\n## Example Output\n\n```text\njvm_memory_pool,pool_name=Compressed\\ Class\\ Space PeakUsage.max=1073741824,PeakUsage.committed=3145728,PeakUsage.init=0,Usage.committed=3145728,Usage.init=0,PeakUsage.used=3017976,Usage.max=1073741824,Usage.used=3017976 1503764025000000000\njvm_memory_pool,pool_name=Code\\ Cache PeakUsage.init=2555904,PeakUsage.committed=6291456,Usage.committed=6291456,PeakUsage.used=6202752,PeakUsage.max=251658240,Usage.used=6210368,Usage.max=251658240,Usage.init=2555904 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Eden\\ Space CollectionUsage.max=-1,PeakUsage.committed=56623104,PeakUsage.init=56623104,PeakUsage.used=53477376,Usage.max=-1,Usage.committed=49283072,Usage.used=19922944,CollectionUsage.committed=49283072,CollectionUsage.init=56623104,CollectionUsage.used=0,PeakUsage.max=-1,Usage.init=56623104 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Old\\ Gen CollectionUsage.max=1073741824,CollectionUsage.committed=0,PeakUsage.max=1073741824,PeakUsage.committed=1017118720,PeakUsage.init=1017118720,PeakUsage.used=137032208,Usage.max=1073741824,CollectionUsage.init=1017118720,Usage.committed=1017118720,Usage.init=1017118720,Usage.used=134708752,CollectionUsage.used=0 1503764025000000000\njvm_memory_pool,pool_name=G1\\ Survivor\\ Space Usage.max=-1,Usage.init=0,CollectionUsage.max=-1,CollectionUsage.committed=7340032,CollectionUsage.used=7340032,PeakUsage.committed=7340032,Usage.committed=7340032,Usage.used=7340032,CollectionUsage.init=0,PeakUsage.max=-1,PeakUsage.init=0,PeakUsage.used=7340032 1503764025000000000\njvm_memory_pool,pool_name=Metaspace PeakUsage.init=0,PeakUsage.used=21852224,PeakUsage.max=-1,Usage.max=-1,Usage.committed=22282240,Usage.init=0,Usage.used=21852224,PeakUsage.committed=22282240 1503764025000000000\n```\n"
  },
  {
    "path": "plugins/inputs/jolokia2_proxy/jolokia2_proxy.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage jolokia2_proxy\n\nimport (\n\t_ \"embed\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/jolokia2\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype JolokiaProxy struct {\n\tDefaultFieldPrefix    string `toml:\"default_field_prefix\"`\n\tDefaultFieldSeparator string `toml:\"default_field_separator\"`\n\tDefaultTagPrefix      string `toml:\"default_tag_prefix\"`\n\n\tURL                   string                     `toml:\"url\"`\n\tDefaultTargetPassword string                     `toml:\"default_target_password\"`\n\tDefaultTargetUsername string                     `toml:\"default_target_username\"`\n\tTargets               []jolokiaProxyTargetConfig `toml:\"target\"`\n\n\tUsername        string          `toml:\"username\"`\n\tPassword        string          `toml:\"password\"`\n\tOrigin          string          `toml:\"origin\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\ttls.ClientConfig\n\n\tMetrics  []common.MetricConfig `toml:\"metric\"`\n\tclient   *common.Client\n\tgatherer *common.Gatherer\n}\n\ntype jolokiaProxyTargetConfig struct {\n\tURL      string `toml:\"url\"`\n\tUsername string `toml:\"username\"`\n\tPassword string `toml:\"password\"`\n}\n\nfunc (*JolokiaProxy) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (jp *JolokiaProxy) Gather(acc telegraf.Accumulator) error {\n\tif jp.gatherer == nil {\n\t\tjp.gatherer = common.NewGatherer(jp.createMetrics())\n\t}\n\n\tif jp.client == nil {\n\t\tclient, err := jp.createClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tjp.client = client\n\t}\n\n\treturn jp.gatherer.Gather(jp.client, acc)\n}\n\nfunc (jp *JolokiaProxy) createMetrics() []common.Metric {\n\tmetrics := make([]common.Metric, 0, len(jp.Metrics))\n\tfor _, metricConfig := range jp.Metrics {\n\t\tmetrics = append(metrics, common.NewMetric(metricConfig, jp.DefaultFieldPrefix, jp.DefaultFieldSeparator, jp.DefaultTagPrefix))\n\t}\n\n\treturn metrics\n}\n\nfunc (jp *JolokiaProxy) createClient() (*common.Client, error) {\n\tproxyConfig := &common.ProxyConfig{\n\t\tDefaultTargetUsername: jp.DefaultTargetUsername,\n\t\tDefaultTargetPassword: jp.DefaultTargetPassword,\n\t}\n\n\tfor _, target := range jp.Targets {\n\t\tproxyConfig.Targets = append(proxyConfig.Targets, common.ProxyTargetConfig{\n\t\t\tURL:      target.URL,\n\t\t\tUsername: target.Username,\n\t\t\tPassword: target.Password,\n\t\t})\n\t}\n\n\treturn common.NewClient(jp.URL, &common.ClientConfig{\n\t\tUsername:        jp.Username,\n\t\tPassword:        jp.Password,\n\t\tResponseTimeout: time.Duration(jp.ResponseTimeout),\n\t\tClientConfig:    jp.ClientConfig,\n\t\tProxyConfig:     proxyConfig,\n\t})\n}\n\nfunc init() {\n\tinputs.Add(\"jolokia2_proxy\", func() telegraf.Input {\n\t\treturn &JolokiaProxy{\n\t\t\tDefaultFieldSeparator: \".\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/jolokia2_proxy/jolokia2_proxy_test.go",
    "content": "package jolokia2_proxy_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/influxdata/toml\"\n\t\"github.com/influxdata/toml/ast\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon \"github.com/influxdata/telegraf/plugins/common/jolokia2\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/jolokia2_proxy\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestJolokia2_ProxyTargets(t *testing.T) {\n\tconfig := `\n\t[jolokia2_proxy]\n\t\turl = \"%s\"\n\n\t[[jolokia2_proxy.target]]\n\t\turl = \"service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi\"\n\n\t[[jolokia2_proxy.target]]\n\t\turl = \"service:jmx:rmi:///jndi/rmi://target2:9010/jmxrmi\"\n\n\t[[jolokia2_proxy.metric]]\n\t\tname  = \"hello\"\n\t\tmbean = \"hello:foo=bar\"`\n\n\tresponse := `[{\n\t\t\"request\": {\n\t\t\t\"type\": \"read\",\n\t\t\t\"mbean\": \"hello:foo=bar\",\n\t\t\t\"target\": {\n\t\t\t\t\"url\": \"service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi\"\n\t\t\t}\n\t\t},\n\t\t\"value\": 123,\n\t\t\"status\": 200\n\t}, {\n\t\t\"request\": {\n\t\t\t\"type\": \"read\",\n\t\t\t\"mbean\": \"hello:foo=bar\",\n\t\t\t\"target\": {\n\t\t\t\t\"url\": \"service:jmx:rmi:///jndi/rmi://target2:9010/jmxrmi\"\n\t\t\t}\n\t\t},\n\t\t\"value\": 456,\n\t\t\"status\": 200\n\t}]`\n\n\tserver := setupServer(response)\n\tdefer server.Close()\n\tplugin := setupPlugin(t, fmt.Sprintf(config, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsTaggedFields(t, \"hello\", map[string]interface{}{\n\t\t\"value\": 123.0,\n\t}, map[string]string{\n\t\t\"jolokia_proxy_url\": server.URL,\n\t\t\"jolokia_agent_url\": \"service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi\",\n\t})\n\tacc.AssertContainsTaggedFields(t, \"hello\", map[string]interface{}{\n\t\t\"value\": 456.0,\n\t}, map[string]string{\n\t\t\"jolokia_proxy_url\": server.URL,\n\t\t\"jolokia_agent_url\": \"service:jmx:rmi:///jndi/rmi://target2:9010/jmxrmi\",\n\t})\n}\n\nfunc TestJolokia2_ClientProxyAuthRequest(t *testing.T) {\n\tvar requests []map[string]interface{}\n\n\tvar username string\n\tvar password string\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tusername, password, _ = r.BasicAuth()\n\n\t\tbody, err := io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tif err := json.Unmarshal(body, &requests); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err = fmt.Fprintf(w, \"[]\"); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\tplugin := setupPlugin(t, fmt.Sprintf(`\n\t\t[jolokia2_proxy]\n\t\t\turl = \"%s/jolokia\"\n\t\t\tusername = \"sally\"\n\t\t\tpassword = \"seashore\"\n\n\t\t[[jolokia2_proxy.target]]\n\t\t\turl = \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\"\n\t\t\tusername = \"jack\"\n\t\t\tpassword = \"benimble\"\n\n\t\t[[jolokia2_proxy.metric]]\n\t\t\tname  = \"hello\"\n\t\t\tmbean = \"hello:foo=bar\"\n\t`, server.URL))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.EqualValuesf(t, \"sally\", username, \"Expected to post with username %s, but was %s\", \"sally\", username)\n\trequire.EqualValuesf(t, \"seashore\", password, \"Expected to post with password %s, but was %s\", \"seashore\", password)\n\trequire.NotEmpty(t, requests, \"Expected to post a request body, but was empty.\")\n\n\trequest := requests[0]\n\texpected := \"hello:foo=bar\"\n\trequire.EqualValuesf(t, expected, request[\"mbean\"], \"Expected to query mbean %s, but was %s\", expected, request[\"mbean\"])\n\n\ttarget, ok := request[\"target\"].(map[string]interface{})\n\trequire.True(t, ok, \"Expected a proxy target, but was empty.\")\n\n\texpected = \"service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi\"\n\trequire.Equalf(t, expected, target[\"url\"], \"Expected proxy target url %s, but was %s\", expected, target[\"url\"])\n\texpected = \"jack\"\n\trequire.Equalf(t, expected, target[\"user\"], \"Expected proxy target username %s, but was %s\", expected, target[\"user\"])\n\texpected = \"benimble\"\n\trequire.Equalf(t, expected, target[\"password\"], \"Expected proxy target username %s, but was %s\", expected, target[\"password\"])\n}\n\nfunc TestFillFields(t *testing.T) {\n\tcomplexPoint := map[string]interface{}{\"Value\": []interface{}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}\n\tscalarPoint := []interface{}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}\n\n\tresults := map[string]interface{}{}\n\tcommon.NewPointBuilder(common.Metric{Name: \"test\", Mbean: \"complex\"}, []string{\"this\", \"that\"}, \"/\").FillFields(\"\", complexPoint, results)\n\trequire.Equal(t, map[string]interface{}{}, results)\n\n\tresults = map[string]interface{}{}\n\tcommon.NewPointBuilder(common.Metric{Name: \"test\", Mbean: \"scalar\"}, []string{\"this\", \"that\"}, \"/\").FillFields(\"\", scalarPoint, results)\n\trequire.Equal(t, map[string]interface{}{}, results)\n}\n\nfunc setupServer(resp string) *httptest.Server {\n\treturn httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tfmt.Fprintln(w, resp)\n\t}))\n}\n\nfunc setupPlugin(t *testing.T, conf string) telegraf.Input {\n\ttable, err := toml.Parse([]byte(conf))\n\tif err != nil {\n\t\tt.Fatalf(\"Unable to parse config! %v\", err)\n\t}\n\n\tfor name := range table.Fields {\n\t\tobject := table.Fields[name]\n\t\tif name == \"jolokia2_proxy\" {\n\t\t\tplugin := jolokia2_proxy.JolokiaProxy{\n\t\t\t\tDefaultFieldSeparator: \".\",\n\t\t\t}\n\n\t\t\tif err := toml.UnmarshalTable(object.(*ast.Table), &plugin); err != nil {\n\t\t\t\tt.Fatalf(\"Unable to parse jolokia_proxy plugin config! %v\", err)\n\t\t\t}\n\n\t\t\treturn &plugin\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/jolokia2_proxy/sample.conf",
    "content": "# Read JMX metrics from a Jolokia REST proxy endpoint\n[[inputs.jolokia2_proxy]]\n  # default_tag_prefix      = \"\"\n  # default_field_prefix    = \"\"\n  # default_field_separator = \".\"\n\n  ## Proxy agent\n  url = \"http://localhost:8080/jolokia\"\n  # username = \"\"\n  # password = \"\"\n  # response_timeout = \"5s\"\n\n  ## Optional origin URL to include as a header in the request. Some endpoints\n  ## may reject an empty origin.\n  # origin = \"\"\n\n  ## Optional TLS config\n  # tls_ca   = \"/var/private/ca.pem\"\n  # tls_cert = \"/var/private/client.pem\"\n  # tls_key  = \"/var/private/client-key.pem\"\n  # insecure_skip_verify = false\n\n  ## Add proxy targets to query\n  # default_target_username = \"\"\n  # default_target_password = \"\"\n  [[inputs.jolokia2_proxy.target]]\n    url = \"service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi\"\n    # username = \"\"\n    # password = \"\"\n\n  ## Add metrics to read\n  [[inputs.jolokia2_proxy.metric]]\n    name  = \"java_runtime\"\n    mbean = \"java.lang:type=Runtime\"\n    paths = [\"Uptime\"]\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/README.md",
    "content": "# Juniper Telemetry Input Plugin\n\nThis service plugin reads [OpenConfig][openconfig] telemetry data via the\n[Junos Telemetry Interface (JTI)][jti] from configured from listed sensors.\n\n⭐ Telegraf v1.7.0\n🏷️ network, iot\n💻 all\n\n[openconfig]: http://openconfig.net/\n[jti]: https://www.juniper.net/documentation/en_US/junos/topics/concept/junos-telemetry-interface-oveview.html\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Subscribe and receive OpenConfig Telemetry data using JTI\n[[inputs.jti_openconfig_telemetry]]\n  ## List of device addresses to collect telemetry from\n  servers = [\"localhost:1883\"]\n\n  ## Authentication details. Username and password are must if device expects\n  ## authentication. Client ID must be unique when connecting from multiple instances\n  ## of telegraf to the same device\n  username = \"user\"\n  password = \"pass\"\n  client_id = \"telegraf\"\n\n  ## Frequency to get data\n  sample_frequency = \"1000ms\"\n\n  ## Sensors to subscribe for\n  ## A identifier for each sensor can be provided in path by separating with space\n  ## Else sensor path will be used as identifier\n  ## When identifier is used, we can provide a list of space separated sensors.\n  ## A single subscription will be created with all these sensors and data will\n  ## be saved to measurement with this identifier name\n  sensors = [\n   \"/interfaces/\",\n   \"collection /components/ /lldp\",\n  ]\n\n  ## We allow specifying sensor group level reporting rate. To do this, specify the\n  ## reporting rate in Duration at the beginning of sensor paths / collection\n  ## name. For entries without reporting rate, we use configured sample frequency\n  sensors = [\n   \"1000ms customReporting /interfaces /lldp\",\n   \"2000ms collection /components\",\n   \"/interfaces\",\n  ]\n\n  ## Timestamp Source\n  ## Set to 'collection' for time of collection, and 'data' for using the time\n  ## provided by the _timestamp field.\n  # timestamp_source = \"collection\"\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Delay between retry attempts of failed RPC calls or streams. Defaults to 1000ms.\n  ## Failed streams/calls will not be retried if 0 is provided\n  retry_delay = \"1000ms\"\n\n  ## Period for sending keep-alive packets on idle connections\n  ## This is helpful to identify broken connections to the server\n  # keep_alive_period = \"10s\"\n\n  ## To treat all string values as tags, set this to true\n  str_as_tags = false\n```\n\n## Tags\n\n- All measurements are tagged appropriately using the identifier information\n  in incoming data\n\n## Example Output\n\n## Metrics\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/auth/authentication_service.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.27.1\n// \tprotoc        v3.17.3\n// source: auth/authentication_service.proto\n\npackage authentication\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The request message containing the user's name, password and client id\ntype LoginRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUserName string `protobuf:\"bytes,1,opt,name=user_name,json=userName,proto3\" json:\"user_name,omitempty\"`\n\tPassword string `protobuf:\"bytes,2,opt,name=password,proto3\" json:\"password,omitempty\"`\n\tClientId string `protobuf:\"bytes,3,opt,name=client_id,json=clientId,proto3\" json:\"client_id,omitempty\"`\n}\n\nfunc (x *LoginRequest) Reset() {\n\t*x = LoginRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_auth_authentication_service_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *LoginRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LoginRequest) ProtoMessage() {}\n\nfunc (x *LoginRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_auth_authentication_service_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.\nfunc (*LoginRequest) Descriptor() ([]byte, []int) {\n\treturn file_auth_authentication_service_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *LoginRequest) GetUserName() string {\n\tif x != nil {\n\t\treturn x.UserName\n\t}\n\treturn \"\"\n}\n\nfunc (x *LoginRequest) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\nfunc (x *LoginRequest) GetClientId() string {\n\tif x != nil {\n\t\treturn x.ClientId\n\t}\n\treturn \"\"\n}\n\n// The response message containing the result of login attempt.\n// result value of true indicates success and false indicates\n// failure\ntype LoginReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tResult bool `protobuf:\"varint,1,opt,name=result,proto3\" json:\"result,omitempty\"`\n}\n\nfunc (x *LoginReply) Reset() {\n\t*x = LoginReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_auth_authentication_service_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *LoginReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LoginReply) ProtoMessage() {}\n\nfunc (x *LoginReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_auth_authentication_service_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LoginReply.ProtoReflect.Descriptor instead.\nfunc (*LoginReply) Descriptor() ([]byte, []int) {\n\treturn file_auth_authentication_service_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *LoginReply) GetResult() bool {\n\tif x != nil {\n\t\treturn x.Result\n\t}\n\treturn false\n}\n\nvar File_auth_authentication_service_proto protoreflect.FileDescriptor\n\nvar file_auth_authentication_service_proto_rawDesc = []byte{\n\t0x0a, 0x21, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,\n\t0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x0a, 0x09,\n\t0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x24, 0x0a, 0x0a, 0x4c, 0x6f, 0x67,\n\t0x69, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c,\n\t0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32,\n\t0x51, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x48, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x69,\n\t0x6e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,\n\t0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,\n\t0x22, 0x00, 0x42, 0x12, 0x5a, 0x10, 0x2e, 0x3b, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,\n\t0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_auth_authentication_service_proto_rawDescOnce sync.Once\n\tfile_auth_authentication_service_proto_rawDescData = file_auth_authentication_service_proto_rawDesc\n)\n\nfunc file_auth_authentication_service_proto_rawDescGZIP() []byte {\n\tfile_auth_authentication_service_proto_rawDescOnce.Do(func() {\n\t\tfile_auth_authentication_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_authentication_service_proto_rawDescData)\n\t})\n\treturn file_auth_authentication_service_proto_rawDescData\n}\n\nvar file_auth_authentication_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_auth_authentication_service_proto_goTypes = []interface{}{\n\t(*LoginRequest)(nil), // 0: authentication.LoginRequest\n\t(*LoginReply)(nil),   // 1: authentication.LoginReply\n}\nvar file_auth_authentication_service_proto_depIdxs = []int32{\n\t0, // 0: authentication.Login.LoginCheck:input_type -> authentication.LoginRequest\n\t1, // 1: authentication.Login.LoginCheck:output_type -> authentication.LoginReply\n\t1, // [1:2] is the sub-list for method output_type\n\t0, // [0:1] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_auth_authentication_service_proto_init() }\nfunc file_auth_authentication_service_proto_init() {\n\tif File_auth_authentication_service_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_auth_authentication_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*LoginRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_auth_authentication_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*LoginReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_auth_authentication_service_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_auth_authentication_service_proto_goTypes,\n\t\tDependencyIndexes: file_auth_authentication_service_proto_depIdxs,\n\t\tMessageInfos:      file_auth_authentication_service_proto_msgTypes,\n\t}.Build()\n\tFile_auth_authentication_service_proto = out.File\n\tfile_auth_authentication_service_proto_rawDesc = nil\n\tfile_auth_authentication_service_proto_goTypes = nil\n\tfile_auth_authentication_service_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/auth/authentication_service.proto",
    "content": "//\n// Copyrights (c) 2017, Juniper Networks, Inc.\n// All rights reserved.\n//\n\n//\n// Licensed to the Apache Software Foundation (ASF) under one\n// or more contributor license agreements.  See the NOTICE file\n// distributed with this work for additional information\n// regarding copyright ownership.  The ASF licenses this file\n// to you under the Apache License, Version 2.0 (the\n// \"License\"); you may not use this file except in compliance\n// with the License.  You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing,\n// software distributed under the License is distributed on an\n// \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n// KIND, either express or implied.  See the License for the\n// specific language governing permissions and limitations\n// under the License.\n//\n\nsyntax = \"proto3\";\n\npackage authentication;\noption go_package = \".;authentication\";\n\n// The Login service definition.\nservice Login {\n  rpc LoginCheck (LoginRequest) returns (LoginReply) {}\n}\n\n// The request message containing the user's name, password and client id\nmessage LoginRequest {\n  string user_name = 1;\n  string password   = 2;\n  string client_id = 3;\n}\n\n/*\n * The response message containing the result of login attempt.\n * result value of true indicates success and false indicates\n * failure\n */ \nmessage LoginReply {\n  bool result = 1;\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/auth/authentication_service_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage authentication\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\n// LoginClient is the client API for Login service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype LoginClient interface {\n\tLoginCheck(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginReply, error)\n}\n\ntype loginClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewLoginClient(cc grpc.ClientConnInterface) LoginClient {\n\treturn &loginClient{cc}\n}\n\nfunc (c *loginClient) LoginCheck(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginReply, error) {\n\tout := new(LoginReply)\n\terr := c.cc.Invoke(ctx, \"/authentication.Login/LoginCheck\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoginServer is the server API for Login service.\n// All implementations must embed UnimplementedLoginServer\n// for forward compatibility\ntype LoginServer interface {\n\tLoginCheck(context.Context, *LoginRequest) (*LoginReply, error)\n\tmustEmbedUnimplementedLoginServer()\n}\n\n// UnimplementedLoginServer must be embedded to have forward compatible implementations.\ntype UnimplementedLoginServer struct {\n}\n\nfunc (UnimplementedLoginServer) LoginCheck(context.Context, *LoginRequest) (*LoginReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method LoginCheck not implemented\")\n}\nfunc (UnimplementedLoginServer) mustEmbedUnimplementedLoginServer() {}\n\n// UnsafeLoginServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to LoginServer will\n// result in compilation errors.\ntype UnsafeLoginServer interface {\n\tmustEmbedUnimplementedLoginServer()\n}\n\nfunc RegisterLoginServer(s grpc.ServiceRegistrar, srv LoginServer) {\n\ts.RegisterService(&Login_ServiceDesc, srv)\n}\n\nfunc _Login_LoginCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(LoginRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(LoginServer).LoginCheck(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/authentication.Login/LoginCheck\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(LoginServer).LoginCheck(ctx, req.(*LoginRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// Login_ServiceDesc is the grpc.ServiceDesc for Login service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar Login_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"authentication.Login\",\n\tHandlerType: (*LoginServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"LoginCheck\",\n\t\t\tHandler:    _Login_LoginCheck_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"auth/authentication_service.proto\",\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/collection.go",
    "content": "package jti_openconfig_telemetry\n\nimport \"sort\"\n\ntype dataGroup struct {\n\tnumKeys int\n\ttags    map[string]string\n\tdata    map[string]interface{}\n}\n\n// Sort the data groups by number of keys\ntype collectionByKeys []dataGroup\n\nfunc (a collectionByKeys) Len() int           { return len(a) }\nfunc (a collectionByKeys) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a collectionByKeys) Less(i, j int) bool { return a[i].numKeys < a[j].numKeys }\n\n// Checks to see if there is already a group with these tags and returns its index. Returns -1 if unavailable.\nfunc (a collectionByKeys) isAvailable(tags map[string]string) *dataGroup {\n\tsort.Sort(a)\n\n\t// Iterate through all the groups and see if we have group with these tags\n\tfor _, group := range a {\n\t\t// Since already sorted, match with only groups with N keys\n\t\tif group.numKeys < len(tags) {\n\t\t\tcontinue\n\t\t} else if group.numKeys > len(tags) {\n\t\t\tbreak\n\t\t}\n\n\t\tmatchFound := true\n\t\tfor k, v := range tags {\n\t\t\tval, ok := group.tags[k]\n\t\t\tif !ok || val != v {\n\t\t\t\tmatchFound = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif matchFound {\n\t\t\treturn &group\n\t\t}\n\t}\n\treturn nil\n}\n\n// Inserts into already existing group or creates a new group\nfunc (a collectionByKeys) insert(tags map[string]string, data map[string]interface{}) collectionByKeys {\n\t// If there is already a group with this set of tags, insert into it. Otherwise create a new group and insert\n\tif group := a.isAvailable(tags); group != nil {\n\t\tfor k, v := range data {\n\t\t\tgroup.data[k] = v\n\t\t}\n\t} else {\n\t\ta = append(a, dataGroup{len(tags), tags, data})\n\t}\n\n\treturn a\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/gen.go",
    "content": "package jti_openconfig_telemetry\n\n// To run these commands, make sure that protoc-gen-go and protoc-gen-go-grpc are installed\n// > go install google.golang.org/protobuf/cmd/protoc-gen-go\n// > go install google.golang.org/grpc/cmd/protoc-gen-go-grpc\n//\n// Generated files were last generated with:\n// - protoc-gen-go: v1.27.1\n// - protoc-gen-go-grpc: v1.1.0\n//go:generate protoc --go_out=auth/ --go-grpc_out=auth/ auth/authentication_service.proto\n//go:generate protoc --go_out=oc/ --go-grpc_out=oc/ oc/oc.proto\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/jti_openconfig_telemetry.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage jti_openconfig_telemetry\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/keepalive\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tauthentication \"github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry/auth\"\n\ttelemetry \"github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry/oc\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\t// Regex to match and extract data points from path value in received key\n\tkeyPathRegex = regexp.MustCompile(`/([^/]*)\\[([A-Za-z0-9\\-/]*=[^\\[]*)]`)\n)\n\ntype OpenConfigTelemetry struct {\n\tServers         []string        `toml:\"servers\"`\n\tSensors         []string        `toml:\"sensors\"`\n\tUsername        string          `toml:\"username\"`\n\tPassword        string          `toml:\"password\"`\n\tClientID        string          `toml:\"client_id\"`\n\tTimestampSource string          `toml:\"timestamp_source\"`\n\tSampleFrequency config.Duration `toml:\"sample_frequency\"`\n\tStrAsTags       bool            `toml:\"str_as_tags\"`\n\tRetryDelay      config.Duration `toml:\"retry_delay\"`\n\tEnableTLS       bool            `toml:\"enable_tls\"`\n\tKeepAlivePeriod config.Duration `toml:\"keep_alive_period\"`\n\tcommon_tls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tsensorsConfig   []sensorConfig\n\tgrpcClientConns []grpcConnection\n\twg              *sync.WaitGroup\n}\n\n// Structure to hold sensors path list and measurement name\ntype sensorConfig struct {\n\tmeasurementName string\n\tpathList        []*telemetry.Path\n}\n\ntype grpcConnection struct {\n\tconnection *grpc.ClientConn\n\tcancel     context.CancelFunc\n}\n\nfunc (g *grpcConnection) close() {\n\tg.connection.Close()\n\tg.cancel()\n}\n\nfunc (*OpenConfigTelemetry) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *OpenConfigTelemetry) Init() error {\n\tswitch m.TimestampSource {\n\tcase \"\", \"collection\":\n\tcase \"data\":\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown option for timestamp_source: %q\", m.TimestampSource)\n\t}\n\n\treturn nil\n}\n\nfunc (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {\n\t// Build sensors config\n\tif m.splitSensorConfig() == 0 {\n\t\treturn errors.New(\"no valid sensor configuration available\")\n\t}\n\n\t// Parse TLS config\n\tvar creds credentials.TransportCredentials\n\tif m.EnableTLS {\n\t\ttlscfg, err := m.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcreds = credentials.NewTLS(tlscfg)\n\t} else {\n\t\tcreds = insecure.NewCredentials()\n\t}\n\n\t// Setup the basic connection options\n\toptions := []grpc.DialOption{\n\t\tgrpc.WithTransportCredentials(creds),\n\t}\n\n\t// Add keep-alive settings\n\tif m.KeepAlivePeriod > 0 {\n\t\tparams := keepalive.ClientParameters{\n\t\t\tTime:    time.Duration(m.KeepAlivePeriod),\n\t\t\tTimeout: 2 * time.Duration(m.KeepAlivePeriod),\n\t\t}\n\t\toptions = append(options, grpc.WithKeepaliveParams(params))\n\t}\n\n\t// Connect to given list of servers and start collecting data\n\tvar grpcClientConn *grpc.ClientConn\n\tvar wg sync.WaitGroup\n\tm.wg = &wg\n\n\tfor _, server := range m.Servers {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tif len(m.Username) > 0 {\n\t\t\tctx = metadata.AppendToOutgoingContext(\n\t\t\t\tctx,\n\t\t\t\t\"username\", m.Username,\n\t\t\t\t\"password\", m.Password,\n\t\t\t\t\"clientid\", m.ClientID,\n\t\t\t)\n\t\t}\n\n\t\t// Extract device address and port\n\t\tgrpcServer, grpcPort, err := net.SplitHostPort(server)\n\t\tif err != nil {\n\t\t\tm.Log.Errorf(\"Invalid server address: %s\", err.Error())\n\t\t\tcancel()\n\t\t\tcontinue\n\t\t}\n\n\t\tgrpcClientConn, err = grpc.NewClient(server, options...)\n\t\tif err != nil {\n\t\t\tm.Log.Errorf(\"Failed to connect to %s: %s\", server, err.Error())\n\t\t} else {\n\t\t\tm.Log.Debugf(\"Opened a new gRPC session to %s on port %s\", grpcServer, grpcPort)\n\t\t}\n\n\t\t// Add to the list of client connections\n\t\tconnection := grpcConnection{\n\t\t\tconnection: grpcClientConn,\n\t\t\tcancel:     cancel,\n\t\t}\n\t\tm.grpcClientConns = append(m.grpcClientConns, connection)\n\n\t\tif m.Username != \"\" && m.Password != \"\" && m.ClientID != \"\" {\n\t\t\tif err := m.authenticate(ctx, server, grpcClientConn); err != nil {\n\t\t\t\tm.Log.Errorf(\"Error authenticating to %s: %v\", grpcServer, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Subscribe and gather telemetry data\n\t\tm.collectData(ctx, grpcServer, grpcClientConn, acc)\n\t}\n\n\treturn nil\n}\n\nfunc (*OpenConfigTelemetry) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (m *OpenConfigTelemetry) Stop() {\n\tfor _, grpcClientConn := range m.grpcClientConns {\n\t\tgrpcClientConn.close()\n\t}\n\tm.wg.Wait()\n}\n\n// Takes in XML path with predicates and returns list of tags+values along with a final\n// XML path without predicates. If /events/event[id=2]/attributes[key='message']/value\n// is given input, this function will emit /events/event/attributes/value as xmlpath and\n// { /events/event/@id=2, /events/event/attributes/@key='message' } as tags\nfunc spitTagsNPath(xmlpath string) (string, map[string]string) {\n\tsubs := keyPathRegex.FindAllStringSubmatch(xmlpath, -1)\n\ttags := make(map[string]string)\n\n\t// Given XML path, this will spit out final path without predicates\n\tif len(subs) > 0 {\n\t\tfor _, sub := range subs {\n\t\t\ttagKey := strings.Split(xmlpath, sub[0])[0] + \"/\" + strings.TrimSpace(sub[1]) + \"/@\"\n\n\t\t\t// If we have multiple keys in give path like /events/event[id=2 and type=3]/,\n\t\t\t// we must emit multiple tags\n\t\t\tfor _, kv := range strings.Split(sub[2], \" and \") {\n\t\t\t\tkey := tagKey + strings.TrimSpace(strings.Split(kv, \"=\")[0])\n\t\t\t\ttagValue := strings.ReplaceAll(strings.Split(kv, \"=\")[1], \"'\", \"\")\n\t\t\t\ttags[key] = tagValue\n\t\t\t}\n\n\t\t\txmlpath = strings.Replace(xmlpath, sub[0], \"/\"+strings.TrimSpace(sub[1]), 1)\n\t\t}\n\t}\n\n\treturn xmlpath, tags\n}\n\n// Takes in a OC response, extracts tag information from keys and returns a\n// list of groups with unique sets of tags+values\nfunc (m *OpenConfigTelemetry) extractData(r *telemetry.OpenConfigData, grpcServer string) []dataGroup {\n\t// Use empty prefix. We will update this when we iterate over key-value pairs\n\tprefix := \"\"\n\n\tdgroups := make([]dataGroup, 0, 5*len(r.Kv))\n\tfor _, v := range r.Kv {\n\t\tkv := make(map[string]interface{})\n\n\t\tif v.Key == \"__prefix__\" {\n\t\t\tprefix = v.GetStrValue()\n\t\t\tcontinue\n\t\t}\n\n\t\t// Also, lets use prefix if there is one\n\t\txmlpath, finaltags := spitTagsNPath(prefix + v.Key)\n\t\tfinaltags[\"device\"] = grpcServer\n\n\t\tswitch v.Value.(type) {\n\t\tcase *telemetry.KeyValue_StrValue:\n\t\t\t// If StrAsTags is set, we treat all string values as tags\n\t\t\tif m.StrAsTags {\n\t\t\t\tfinaltags[xmlpath] = v.GetStrValue()\n\t\t\t} else {\n\t\t\t\tkv[xmlpath] = v.GetStrValue()\n\t\t\t}\n\t\tcase *telemetry.KeyValue_DoubleValue:\n\t\t\tkv[xmlpath] = v.GetDoubleValue()\n\t\tcase *telemetry.KeyValue_IntValue:\n\t\t\tkv[xmlpath] = v.GetIntValue()\n\t\tcase *telemetry.KeyValue_UintValue:\n\t\t\tkv[xmlpath] = v.GetUintValue()\n\t\tcase *telemetry.KeyValue_SintValue:\n\t\t\tkv[xmlpath] = v.GetSintValue()\n\t\tcase *telemetry.KeyValue_BoolValue:\n\t\t\tkv[xmlpath] = v.GetBoolValue()\n\t\tcase *telemetry.KeyValue_BytesValue:\n\t\t\tkv[xmlpath] = v.GetBytesValue()\n\t\t}\n\n\t\t// Insert other tags from message\n\t\tfinaltags[\"system_id\"] = r.SystemId\n\t\tfinaltags[\"path\"] = r.Path\n\n\t\t// Insert derived key and value\n\t\tdgroups = collectionByKeys(dgroups).insert(finaltags, kv)\n\n\t\t// Insert data from message header\n\t\tdgroups = collectionByKeys(dgroups).insert(finaltags,\n\t\t\tmap[string]interface{}{\"_sequence\": r.SequenceNumber})\n\t\tdgroups = collectionByKeys(dgroups).insert(finaltags,\n\t\t\tmap[string]interface{}{\"_timestamp\": r.Timestamp})\n\t\tdgroups = collectionByKeys(dgroups).insert(finaltags,\n\t\t\tmap[string]interface{}{\"_component_id\": r.ComponentId})\n\t\tdgroups = collectionByKeys(dgroups).insert(finaltags,\n\t\t\tmap[string]interface{}{\"_subcomponent_id\": r.SubComponentId})\n\t}\n\n\treturn dgroups\n}\n\n// Takes in sensor configuration and converts it into slice of sensorConfig objects\nfunc (m *OpenConfigTelemetry) splitSensorConfig() int {\n\tvar pathlist []*telemetry.Path\n\tvar measurementName string\n\tvar reportingRate uint32\n\n\tm.sensorsConfig = make([]sensorConfig, 0)\n\tfor _, sensor := range m.Sensors {\n\t\tspathSplit := strings.Fields(sensor)\n\t\treportingRate = uint32(time.Duration(m.SampleFrequency) / time.Millisecond)\n\n\t\t// Extract measurement name and custom reporting rate if specified. Custom\n\t\t// reporting rate will be specified at the beginning of sensor list,\n\t\t// followed by measurement name like \"1000ms interfaces /interfaces\"\n\t\t// where 1000ms is the custom reporting rate and interfaces is the\n\t\t// measurement name. If 1000ms is not given, we use global reporting rate\n\t\t// from sample_frequency. if measurement name is not given, we use first\n\t\t// sensor name as the measurement name. If first or the word after custom\n\t\t// reporting rate doesn't start with /, we treat it as measurement name\n\t\t// and exclude it from list of sensors to subscribe\n\t\tduration, err := time.ParseDuration(spathSplit[0])\n\t\tif err == nil {\n\t\t\treportingRate = uint32(duration / time.Millisecond)\n\t\t\tspathSplit = spathSplit[1:]\n\t\t}\n\n\t\tif len(spathSplit) == 0 {\n\t\t\tm.Log.Error(\"No sensors are specified\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// Word after custom reporting rate is treated as measurement name\n\t\tmeasurementName = spathSplit[0]\n\n\t\t// If our word after custom reporting rate doesn't start with /, we treat\n\t\t// it as measurement name. Else we treat it as sensor\n\t\tif !strings.HasPrefix(measurementName, \"/\") {\n\t\t\tspathSplit = spathSplit[1:]\n\t\t}\n\n\t\tif len(spathSplit) == 0 {\n\t\t\tm.Log.Error(\"No valid sensors are specified\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// Iterate over our sensors and create pathlist to subscribe\n\t\tpathlist = make([]*telemetry.Path, 0)\n\t\tfor _, path := range spathSplit {\n\t\t\tpathlist = append(pathlist, &telemetry.Path{Path: path,\n\t\t\t\tSampleFrequency: reportingRate})\n\t\t}\n\n\t\tm.sensorsConfig = append(m.sensorsConfig, sensorConfig{\n\t\t\tmeasurementName: measurementName, pathList: pathlist,\n\t\t})\n\t}\n\n\treturn len(m.sensorsConfig)\n}\n\n// Subscribes and collects OpenConfig telemetry data from given server\nfunc (m *OpenConfigTelemetry) collectData(\n\tctx context.Context,\n\tgrpcServer string,\n\tgrpcClientConn *grpc.ClientConn,\n\tacc telegraf.Accumulator,\n) {\n\tc := telemetry.NewOpenConfigTelemetryClient(grpcClientConn)\n\tfor _, sensor := range m.sensorsConfig {\n\t\tm.wg.Add(1)\n\t\tgo func(ctx context.Context, sensor sensorConfig) {\n\t\t\tdefer m.wg.Done()\n\n\t\t\tfor {\n\t\t\t\tstream, err := c.TelemetrySubscribe(\n\t\t\t\t\tctx,\n\t\t\t\t\t&telemetry.SubscriptionRequest{PathList: sensor.pathList},\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\trpcStatus, _ := status.FromError(err)\n\t\t\t\t\tif rpcStatus.Code() == codes.Unauthenticated {\n\t\t\t\t\t\tif m.Username != \"\" && m.Password != \"\" && m.ClientID != \"\" {\n\t\t\t\t\t\t\terr := m.authenticate(ctx, grpcServer, grpcClientConn)\n\t\t\t\t\t\t\tif err == nil {\n\t\t\t\t\t\t\t\ttime.Sleep(1 * time.Second)\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tacc.AddError(fmt.Errorf(\"could not re-authenticate: %w\", err))\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if rpcStatus.Code() != codes.Unavailable {\n\t\t\t\t\t\t// If service is currently unavailable and may come back later, retry\n\t\t\t\t\t\tacc.AddError(fmt.Errorf(\"could not subscribe to %s on %q: %w\", sensor.measurementName, grpcServer, err))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Retry with delay. If delay is not provided, use default\n\t\t\t\t\tif time.Duration(m.RetryDelay) > 0 {\n\t\t\t\t\t\tm.Log.Debugf(\"Retrying %s from %s with timeout %v\", sensor.measurementName, grpcServer, time.Duration(m.RetryDelay))\n\t\t\t\t\t\ttime.Sleep(time.Duration(m.RetryDelay))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tm.Log.Debugf(\"Successfully subscribed to %s on %s\", sensor.measurementName, grpcServer)\n\n\t\t\t\tfor {\n\t\t\t\t\tr, err := stream.Recv()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t// If we encounter error in the stream, break so we can retry\n\t\t\t\t\t\t// the connection\n\t\t\t\t\t\tacc.AddError(fmt.Errorf(\"failed to read from %s from %s: %w\", sensor.measurementName, grpcServer, err))\n\t\t\t\t\t\ttime.Sleep(1 * time.Second)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tm.Log.Debugf(\"Received from %s on %s: %v\", sensor.measurementName, grpcServer, r)\n\n\t\t\t\t\t// Create a point and add to batch\n\t\t\t\t\ttags := make(map[string]string)\n\n\t\t\t\t\t// Insert additional tags\n\t\t\t\t\ttags[\"device\"] = grpcServer\n\n\t\t\t\t\tdgroups := m.extractData(r, grpcServer)\n\n\t\t\t\t\t// Print final data collection\n\t\t\t\t\tm.Log.Debugf(\"Available collection for %s on %s: %v\", sensor.measurementName, grpcServer, dgroups)\n\n\t\t\t\t\ttimestamp := time.Now()\n\t\t\t\t\t// Iterate through data groups and add them\n\t\t\t\t\tfor _, group := range dgroups {\n\t\t\t\t\t\tif m.TimestampSource == \"data\" {\n\t\t\t\t\t\t\t// OpenConfig timestamp is in milliseconds since epoch\n\t\t\t\t\t\t\tts, ok := group.data[\"_timestamp\"].(uint64)\n\t\t\t\t\t\t\tif ok {\n\t\t\t\t\t\t\t\ttimestamp = time.UnixMilli(int64(ts))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tm.Log.Warnf(\"Invalid type %T for _timestamp %v\", group.data[\"_timestamp\"], group.data[\"_timestamp\"])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif len(group.tags) == 0 {\n\t\t\t\t\t\t\tacc.AddFields(sensor.measurementName, group.data, tags, timestamp)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tacc.AddFields(sensor.measurementName, group.data, group.tags, timestamp)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(ctx, sensor)\n\t}\n}\n\nfunc (m *OpenConfigTelemetry) authenticate(ctx context.Context, server string, grpcClientConn *grpc.ClientConn) error {\n\tlc := authentication.NewLoginClient(grpcClientConn)\n\tloginReply, err := lc.LoginCheck(\n\t\tctx,\n\t\t&authentication.LoginRequest{\n\t\t\tUserName: m.Username,\n\t\t\tPassword: m.Password,\n\t\t\tClientId: m.ClientID,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not initiate login check for %s: %w\", server, err)\n\t}\n\n\t// Check if the user is authenticated. Bail if auth error\n\tif !loginReply.Result {\n\t\treturn fmt.Errorf(\"failed to authenticate the user for %s\", server)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"jti_openconfig_telemetry\", func() telegraf.Input {\n\t\treturn &OpenConfigTelemetry{\n\t\t\tRetryDelay:      config.Duration(time.Second),\n\t\t\tKeepAlivePeriod: config.Duration(10 * time.Second),\n\t\t\tStrAsTags:       false,\n\t\t\tTimestampSource: \"collection\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/jti_openconfig_telemetry_test.go",
    "content": "package jti_openconfig_telemetry\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\ttelemetry \"github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry/oc\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar cfg = &OpenConfigTelemetry{\n\tLog:             testutil.Logger{},\n\tServers:         []string{\"127.0.0.1:50051\"},\n\tSampleFrequency: config.Duration(time.Millisecond * 10),\n}\n\nvar data = &telemetry.OpenConfigData{\n\tPath: \"/sensor\",\n\tKv:   []*telemetry.KeyValue{{Key: \"/sensor[tag='tagValue']/intKey\", Value: &telemetry.KeyValue_IntValue{IntValue: 10}}},\n}\n\nvar dataWithPrefix = &telemetry.OpenConfigData{\n\tPath: \"/sensor_with_prefix\",\n\tKv: []*telemetry.KeyValue{{Key: \"__prefix__\", Value: &telemetry.KeyValue_StrValue{StrValue: \"/sensor/prefix/\"}},\n\t\t{Key: \"intKey\", Value: &telemetry.KeyValue_IntValue{IntValue: 10}}},\n}\n\nvar dataWithMultipleTags = &telemetry.OpenConfigData{\n\tPath: \"/sensor_with_multiple_tags\",\n\tKv: []*telemetry.KeyValue{{Key: \"__prefix__\", Value: &telemetry.KeyValue_StrValue{StrValue: \"/sensor/prefix/\"}},\n\t\t{Key: \"tagKey[tag='tagValue']/boolKey\", Value: &telemetry.KeyValue_BoolValue{BoolValue: false}},\n\t\t{Key: \"intKey\", Value: &telemetry.KeyValue_IntValue{IntValue: 10}}},\n}\n\nvar dataWithStringValues = &telemetry.OpenConfigData{\n\tPath: \"/sensor_with_string_values\",\n\tKv: []*telemetry.KeyValue{{Key: \"__prefix__\", Value: &telemetry.KeyValue_StrValue{StrValue: \"/sensor/prefix/\"}},\n\t\t{Key: \"strKey[tag='tagValue']/strValue\", Value: &telemetry.KeyValue_StrValue{StrValue: \"10\"}}},\n}\n\nvar dataWithTimestamp = &telemetry.OpenConfigData{\n\tPath: \"/sensor_with_timestamp\",\n\tKv: []*telemetry.KeyValue{\n\t\t{Key: \"/sensor[tag='tagValue']/intKey\", Value: &telemetry.KeyValue_IntValue{IntValue: 10}},\n\t},\n\tTimestamp: 1676560510002,\n}\n\ntype openConfigTelemetryServer struct {\n\ttelemetry.UnimplementedOpenConfigTelemetryServer\n}\n\nfunc (*openConfigTelemetryServer) TelemetrySubscribe(req *telemetry.SubscriptionRequest, stream telemetry.OpenConfigTelemetry_TelemetrySubscribeServer) error {\n\tpath := req.PathList[0].Path\n\tswitch path {\n\tcase \"/sensor\":\n\t\treturn stream.Send(data)\n\tcase \"/sensor_with_prefix\":\n\t\treturn stream.Send(dataWithPrefix)\n\tcase \"/sensor_with_multiple_tags\":\n\t\treturn stream.Send(dataWithMultipleTags)\n\tcase \"/sensor_with_string_values\":\n\t\treturn stream.Send(dataWithStringValues)\n\tcase \"/sensor_with_timestamp\":\n\t\treturn stream.Send(dataWithTimestamp)\n\t}\n\treturn nil\n}\n\nfunc (*openConfigTelemetryServer) CancelTelemetrySubscription(\n\tcontext.Context,\n\t*telemetry.CancelSubscriptionRequest,\n) (*telemetry.CancelSubscriptionReply, error) {\n\treturn nil, nil\n}\n\nfunc (*openConfigTelemetryServer) GetTelemetrySubscriptions(\n\tcontext.Context,\n\t*telemetry.GetSubscriptionsRequest,\n) (*telemetry.GetSubscriptionsReply, error) {\n\treturn nil, nil\n}\n\nfunc (*openConfigTelemetryServer) GetTelemetryOperationalState(\n\tcontext.Context,\n\t*telemetry.GetOperationalStateRequest,\n) (*telemetry.GetOperationalStateReply, error) {\n\treturn nil, nil\n}\n\nfunc (*openConfigTelemetryServer) GetDataEncodings(context.Context, *telemetry.DataEncodingRequest) (*telemetry.DataEncodingReply, error) {\n\treturn nil, nil\n}\n\nfunc newServer() *openConfigTelemetryServer {\n\ts := new(openConfigTelemetryServer)\n\treturn s\n}\n\nfunc TestOpenConfigTelemetryData(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tcfg.Sensors = []string{\"/sensor\"}\n\terr := cfg.Start(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"device\":       \"127.0.0.1\",\n\t\t\"/sensor/@tag\": \"tagValue\",\n\t\t\"system_id\":    \"\",\n\t\t\"path\":         \"/sensor\",\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"/sensor/intKey\":   int64(10),\n\t\t\"_sequence\":        uint64(0),\n\t\t\"_timestamp\":       uint64(0),\n\t\t\"_component_id\":    uint32(0),\n\t\t\"_subcomponent_id\": uint32(0),\n\t}\n\n\trequire.Eventually(t, func() bool { return acc.HasMeasurement(\"/sensor\") }, 5*time.Second, 10*time.Millisecond)\n\tacc.AssertContainsTaggedFields(t, \"/sensor\", fields, tags)\n}\n\nfunc TestOpenConfigTelemetryData_timestamp(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tcfg.Sensors = []string{\"/sensor_with_timestamp\"}\n\trequire.NoError(t, cfg.Start(&acc))\n\n\ttimestamp := int64(1676560510002)\n\ttags := map[string]string{\n\t\t\"device\":       \"127.0.0.1\",\n\t\t\"/sensor/@tag\": \"tagValue\",\n\t\t\"system_id\":    \"\",\n\t\t\"path\":         \"/sensor_with_timestamp\",\n\t}\n\tfields := map[string]interface{}{\n\t\t\"/sensor/intKey\":   int64(10),\n\t\t\"_sequence\":        uint64(0),\n\t\t\"_timestamp\":       uint64(timestamp),\n\t\t\"_component_id\":    uint32(0),\n\t\t\"_subcomponent_id\": uint32(0),\n\t}\n\n\trequire.Eventually(t, func() bool { return acc.HasMeasurement(\"/sensor_with_timestamp\") }, 5*time.Second, 10*time.Millisecond)\n\tacc.AssertContainsTaggedFields(t, \"/sensor_with_timestamp\", fields, tags)\n}\n\nfunc TestOpenConfigTelemetryDataWithPrefix(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tcfg.Sensors = []string{\"/sensor_with_prefix\"}\n\terr := cfg.Start(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"device\":    \"127.0.0.1\",\n\t\t\"system_id\": \"\",\n\t\t\"path\":      \"/sensor_with_prefix\",\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"/sensor/prefix/intKey\": int64(10),\n\t\t\"_sequence\":             uint64(0),\n\t\t\"_timestamp\":            uint64(0),\n\t\t\"_component_id\":         uint32(0),\n\t\t\"_subcomponent_id\":      uint32(0),\n\t}\n\n\trequire.Eventually(t, func() bool { return acc.HasMeasurement(\"/sensor_with_prefix\") }, 5*time.Second, 10*time.Millisecond)\n\tacc.AssertContainsTaggedFields(t, \"/sensor_with_prefix\", fields, tags)\n}\n\nfunc TestOpenConfigTelemetryDataWithMultipleTags(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tcfg.Sensors = []string{\"/sensor_with_multiple_tags\"}\n\terr := cfg.Start(&acc)\n\trequire.NoError(t, err)\n\n\ttags1 := map[string]string{\n\t\t\"/sensor/prefix/tagKey/@tag\": \"tagValue\",\n\t\t\"device\":                     \"127.0.0.1\",\n\t\t\"system_id\":                  \"\",\n\t\t\"path\":                       \"/sensor_with_multiple_tags\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"/sensor/prefix/tagKey/boolKey\": false,\n\t\t\"_sequence\":                     uint64(0),\n\t\t\"_timestamp\":                    uint64(0),\n\t\t\"_component_id\":                 uint32(0),\n\t\t\"_subcomponent_id\":              uint32(0),\n\t}\n\n\ttags2 := map[string]string{\n\t\t\"device\":    \"127.0.0.1\",\n\t\t\"system_id\": \"\",\n\t\t\"path\":      \"/sensor_with_multiple_tags\",\n\t}\n\n\tfields2 := map[string]interface{}{\n\t\t\"/sensor/prefix/intKey\": int64(10),\n\t\t\"_sequence\":             uint64(0),\n\t\t\"_timestamp\":            uint64(0),\n\t\t\"_component_id\":         uint32(0),\n\t\t\"_subcomponent_id\":      uint32(0),\n\t}\n\n\trequire.Eventually(t, func() bool { return acc.HasMeasurement(\"/sensor_with_multiple_tags\") }, 5*time.Second, 10*time.Millisecond)\n\tacc.AssertContainsTaggedFields(t, \"/sensor_with_multiple_tags\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"/sensor_with_multiple_tags\", fields2, tags2)\n}\n\nfunc TestOpenConfigTelemetryDataWithStringValues(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tcfg.Sensors = []string{\"/sensor_with_string_values\"}\n\terr := cfg.Start(&acc)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\n\t\t\"/sensor/prefix/strKey/@tag\": \"tagValue\",\n\t\t\"device\":                     \"127.0.0.1\",\n\t\t\"system_id\":                  \"\",\n\t\t\"path\":                       \"/sensor_with_string_values\",\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"/sensor/prefix/strKey/strValue\": \"10\",\n\t\t\"_sequence\":                      uint64(0),\n\t\t\"_timestamp\":                     uint64(0),\n\t\t\"_component_id\":                  uint32(0),\n\t\t\"_subcomponent_id\":               uint32(0),\n\t}\n\n\trequire.Eventually(t, func() bool { return acc.HasMeasurement(\"/sensor_with_string_values\") }, 5*time.Second, 10*time.Millisecond)\n\tacc.AssertContainsTaggedFields(t, \"/sensor_with_string_values\", fields, tags)\n}\n\nfunc TestMain(m *testing.M) {\n\tlis, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to listen: %v\", err)\n\t}\n\n\texitCode := 0\n\tdefer func() {\n\t\tos.Exit(exitCode)\n\t}()\n\n\tcfg.Servers = []string{lis.Addr().String()}\n\n\tvar opts []grpc.ServerOption\n\tgrpcServer := grpc.NewServer(opts...)\n\ttelemetry.RegisterOpenConfigTelemetryServer(grpcServer, newServer())\n\tgo func() {\n\t\tgrpcServer.Serve(lis) //nolint:errcheck // ignore the returned error as the tests will fail anyway\n\t}()\n\tdefer grpcServer.Stop()\n\n\texitCode = m.Run()\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/oc/oc.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.27.1\n// \tprotoc        v3.17.3\n// source: oc/oc.proto\n\npackage telemetry\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// Result of the operation\ntype ReturnCode int32\n\nconst (\n\tReturnCode_SUCCESS               ReturnCode = 0\n\tReturnCode_NO_SUBSCRIPTION_ENTRY ReturnCode = 1\n\tReturnCode_UNKNOWN_ERROR         ReturnCode = 2\n)\n\n// Enum value maps for ReturnCode.\nvar (\n\tReturnCode_name = map[int32]string{\n\t\t0: \"SUCCESS\",\n\t\t1: \"NO_SUBSCRIPTION_ENTRY\",\n\t\t2: \"UNKNOWN_ERROR\",\n\t}\n\tReturnCode_value = map[string]int32{\n\t\t\"SUCCESS\":               0,\n\t\t\"NO_SUBSCRIPTION_ENTRY\": 1,\n\t\t\"UNKNOWN_ERROR\":         2,\n\t}\n)\n\nfunc (x ReturnCode) Enum() *ReturnCode {\n\tp := new(ReturnCode)\n\t*p = x\n\treturn p\n}\n\nfunc (x ReturnCode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ReturnCode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_oc_oc_proto_enumTypes[0].Descriptor()\n}\n\nfunc (ReturnCode) Type() protoreflect.EnumType {\n\treturn &file_oc_oc_proto_enumTypes[0]\n}\n\nfunc (x ReturnCode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ReturnCode.Descriptor instead.\nfunc (ReturnCode) EnumDescriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{0}\n}\n\n// Verbosity Level\ntype VerbosityLevel int32\n\nconst (\n\tVerbosityLevel_DETAIL VerbosityLevel = 0\n\tVerbosityLevel_TERSE  VerbosityLevel = 1\n\tVerbosityLevel_BRIEF  VerbosityLevel = 2\n)\n\n// Enum value maps for VerbosityLevel.\nvar (\n\tVerbosityLevel_name = map[int32]string{\n\t\t0: \"DETAIL\",\n\t\t1: \"TERSE\",\n\t\t2: \"BRIEF\",\n\t}\n\tVerbosityLevel_value = map[string]int32{\n\t\t\"DETAIL\": 0,\n\t\t\"TERSE\":  1,\n\t\t\"BRIEF\":  2,\n\t}\n)\n\nfunc (x VerbosityLevel) Enum() *VerbosityLevel {\n\tp := new(VerbosityLevel)\n\t*p = x\n\treturn p\n}\n\nfunc (x VerbosityLevel) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (VerbosityLevel) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_oc_oc_proto_enumTypes[1].Descriptor()\n}\n\nfunc (VerbosityLevel) Type() protoreflect.EnumType {\n\treturn &file_oc_oc_proto_enumTypes[1]\n}\n\nfunc (x VerbosityLevel) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use VerbosityLevel.Descriptor instead.\nfunc (VerbosityLevel) EnumDescriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{1}\n}\n\n// Encoding Type Supported\ntype EncodingType int32\n\nconst (\n\tEncodingType_UNDEFINED EncodingType = 0\n\tEncodingType_XML       EncodingType = 1\n\tEncodingType_JSON_IETF EncodingType = 2\n\tEncodingType_PROTO3    EncodingType = 3\n)\n\n// Enum value maps for EncodingType.\nvar (\n\tEncodingType_name = map[int32]string{\n\t\t0: \"UNDEFINED\",\n\t\t1: \"XML\",\n\t\t2: \"JSON_IETF\",\n\t\t3: \"PROTO3\",\n\t}\n\tEncodingType_value = map[string]int32{\n\t\t\"UNDEFINED\": 0,\n\t\t\"XML\":       1,\n\t\t\"JSON_IETF\": 2,\n\t\t\"PROTO3\":    3,\n\t}\n)\n\nfunc (x EncodingType) Enum() *EncodingType {\n\tp := new(EncodingType)\n\t*p = x\n\treturn p\n}\n\nfunc (x EncodingType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (EncodingType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_oc_oc_proto_enumTypes[2].Descriptor()\n}\n\nfunc (EncodingType) Type() protoreflect.EnumType {\n\treturn &file_oc_oc_proto_enumTypes[2]\n}\n\nfunc (x EncodingType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use EncodingType.Descriptor instead.\nfunc (EncodingType) EnumDescriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{2}\n}\n\n// Message sent for a telemetry subscription request\ntype SubscriptionRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Data associated with a telemetry subscription\n\tInput *SubscriptionInput `protobuf:\"bytes,1,opt,name=input,proto3\" json:\"input,omitempty\"`\n\t// List of data models paths and filters\n\t// which are used in a telemetry operation.\n\tPathList []*Path `protobuf:\"bytes,2,rep,name=path_list,json=pathList,proto3\" json:\"path_list,omitempty\"`\n\t// The below configuration is not defined in Openconfig RPC.\n\t// It is a proposed extension to configure additional\n\t// subscription request features.\n\tAdditionalConfig *SubscriptionAdditionalConfig `protobuf:\"bytes,3,opt,name=additional_config,json=additionalConfig,proto3\" json:\"additional_config,omitempty\"`\n}\n\nfunc (x *SubscriptionRequest) Reset() {\n\t*x = SubscriptionRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscriptionRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscriptionRequest) ProtoMessage() {}\n\nfunc (x *SubscriptionRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscriptionRequest.ProtoReflect.Descriptor instead.\nfunc (*SubscriptionRequest) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SubscriptionRequest) GetInput() *SubscriptionInput {\n\tif x != nil {\n\t\treturn x.Input\n\t}\n\treturn nil\n}\n\nfunc (x *SubscriptionRequest) GetPathList() []*Path {\n\tif x != nil {\n\t\treturn x.PathList\n\t}\n\treturn nil\n}\n\nfunc (x *SubscriptionRequest) GetAdditionalConfig() *SubscriptionAdditionalConfig {\n\tif x != nil {\n\t\treturn x.AdditionalConfig\n\t}\n\treturn nil\n}\n\n// Data associated with a telemetry subscription\ntype SubscriptionInput struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// List of optional collector endpoints to send data for\n\t// this subscription.\n\t// If no collector destinations are specified, the collector\n\t// destination is assumed to be the requester on the rpc channel.\n\tCollectorList []*Collector `protobuf:\"bytes,1,rep,name=collector_list,json=collectorList,proto3\" json:\"collector_list,omitempty\"`\n}\n\nfunc (x *SubscriptionInput) Reset() {\n\t*x = SubscriptionInput{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscriptionInput) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscriptionInput) ProtoMessage() {}\n\nfunc (x *SubscriptionInput) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscriptionInput.ProtoReflect.Descriptor instead.\nfunc (*SubscriptionInput) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *SubscriptionInput) GetCollectorList() []*Collector {\n\tif x != nil {\n\t\treturn x.CollectorList\n\t}\n\treturn nil\n}\n\n// Collector endpoints to send data specified as an ip+port combination.\ntype Collector struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// IP address of collector endpoint\n\tAddress string `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\t// Transport protocol port number for the collector destination.\n\tPort uint32 `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n}\n\nfunc (x *Collector) Reset() {\n\t*x = Collector{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Collector) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Collector) ProtoMessage() {}\n\nfunc (x *Collector) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Collector.ProtoReflect.Descriptor instead.\nfunc (*Collector) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Collector) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\nfunc (x *Collector) GetPort() uint32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\n// Data model path\ntype Path struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Data model path of interest\n\t// Path specification for elements of OpenConfig data models\n\tPath string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\t// Regular expression to be used in filtering state leaves\n\tFilter string `protobuf:\"bytes,2,opt,name=filter,proto3\" json:\"filter,omitempty\"`\n\t// If this is set to true, the target device will only send\n\t// updates to the collector upon a change in data value\n\tSuppressUnchanged bool `protobuf:\"varint,3,opt,name=suppress_unchanged,json=suppressUnchanged,proto3\" json:\"suppress_unchanged,omitempty\"`\n\t// Maximum time in ms the target device may go without sending\n\t// a message to the collector. If this time expires with\n\t// suppress-unchanged set, the target device must send an update\n\t// message regardless if the data values have changed.\n\tMaxSilentInterval uint32 `protobuf:\"varint,4,opt,name=max_silent_interval,json=maxSilentInterval,proto3\" json:\"max_silent_interval,omitempty\"`\n\t// Time in ms between collection and transmission of the\n\t// specified data to the collector platform. The target device\n\t// will sample the corresponding data (e.g,. a counter) and\n\t// immediately send to the collector destination.\n\t//\n\t// If sample-frequency is set to 0, then the network device\n\t// must emit an update upon every datum change.\n\tSampleFrequency uint32 `protobuf:\"varint,5,opt,name=sample_frequency,json=sampleFrequency,proto3\" json:\"sample_frequency,omitempty\"`\n\t// EOM needed for each walk cycle of this path?\n\t//   For periodic sensor, applicable for each complete reap\n\t//   For event sensor, applicable when initial dump is over\n\t//     (same as EOS)\n\t// This feature is not implemented currently.\n\tNeedEom bool `protobuf:\"varint,6,opt,name=need_eom,json=needEom,proto3\" json:\"need_eom,omitempty\"`\n}\n\nfunc (x *Path) Reset() {\n\t*x = Path{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Path) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Path) ProtoMessage() {}\n\nfunc (x *Path) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Path.ProtoReflect.Descriptor instead.\nfunc (*Path) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *Path) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Path) GetFilter() string {\n\tif x != nil {\n\t\treturn x.Filter\n\t}\n\treturn \"\"\n}\n\nfunc (x *Path) GetSuppressUnchanged() bool {\n\tif x != nil {\n\t\treturn x.SuppressUnchanged\n\t}\n\treturn false\n}\n\nfunc (x *Path) GetMaxSilentInterval() uint32 {\n\tif x != nil {\n\t\treturn x.MaxSilentInterval\n\t}\n\treturn 0\n}\n\nfunc (x *Path) GetSampleFrequency() uint32 {\n\tif x != nil {\n\t\treturn x.SampleFrequency\n\t}\n\treturn 0\n}\n\nfunc (x *Path) GetNeedEom() bool {\n\tif x != nil {\n\t\treturn x.NeedEom\n\t}\n\treturn false\n}\n\n// Configure subscription request additional features.\ntype SubscriptionAdditionalConfig struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// limit the number of records sent in the stream\n\tLimitRecords int32 `protobuf:\"varint,1,opt,name=limit_records,json=limitRecords,proto3\" json:\"limit_records,omitempty\"`\n\t// limit the time the stream remains open\n\tLimitTimeSeconds int32 `protobuf:\"varint,2,opt,name=limit_time_seconds,json=limitTimeSeconds,proto3\" json:\"limit_time_seconds,omitempty\"`\n\t// EOS needed for this subscription?\n\tNeedEos bool `protobuf:\"varint,3,opt,name=need_eos,json=needEos,proto3\" json:\"need_eos,omitempty\"`\n}\n\nfunc (x *SubscriptionAdditionalConfig) Reset() {\n\t*x = SubscriptionAdditionalConfig{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscriptionAdditionalConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscriptionAdditionalConfig) ProtoMessage() {}\n\nfunc (x *SubscriptionAdditionalConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscriptionAdditionalConfig.ProtoReflect.Descriptor instead.\nfunc (*SubscriptionAdditionalConfig) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *SubscriptionAdditionalConfig) GetLimitRecords() int32 {\n\tif x != nil {\n\t\treturn x.LimitRecords\n\t}\n\treturn 0\n}\n\nfunc (x *SubscriptionAdditionalConfig) GetLimitTimeSeconds() int32 {\n\tif x != nil {\n\t\treturn x.LimitTimeSeconds\n\t}\n\treturn 0\n}\n\nfunc (x *SubscriptionAdditionalConfig) GetNeedEos() bool {\n\tif x != nil {\n\t\treturn x.NeedEos\n\t}\n\treturn false\n}\n\n// 1. Reply data message sent out using out-of-band channel.\ntype SubscriptionReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Response message to a telemetry subscription creation or\n\t// get request.\n\tResponse *SubscriptionResponse `protobuf:\"bytes,1,opt,name=response,proto3\" json:\"response,omitempty\"`\n\t// List of data models paths and filters\n\t// which are used in a telemetry operation.\n\tPathList []*Path `protobuf:\"bytes,2,rep,name=path_list,json=pathList,proto3\" json:\"path_list,omitempty\"`\n}\n\nfunc (x *SubscriptionReply) Reset() {\n\t*x = SubscriptionReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscriptionReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscriptionReply) ProtoMessage() {}\n\nfunc (x *SubscriptionReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscriptionReply.ProtoReflect.Descriptor instead.\nfunc (*SubscriptionReply) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *SubscriptionReply) GetResponse() *SubscriptionResponse {\n\tif x != nil {\n\t\treturn x.Response\n\t}\n\treturn nil\n}\n\nfunc (x *SubscriptionReply) GetPathList() []*Path {\n\tif x != nil {\n\t\treturn x.PathList\n\t}\n\treturn nil\n}\n\n// Response message to a telemetry subscription creation or get request.\ntype SubscriptionResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Unique id for the subscription on the device. This is\n\t// generated by the device and returned in a subscription\n\t// request or when listing existing subscriptions\n\tSubscriptionId uint32 `protobuf:\"varint,1,opt,name=subscription_id,json=subscriptionId,proto3\" json:\"subscription_id,omitempty\"`\n}\n\nfunc (x *SubscriptionResponse) Reset() {\n\t*x = SubscriptionResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SubscriptionResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubscriptionResponse) ProtoMessage() {}\n\nfunc (x *SubscriptionResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubscriptionResponse.ProtoReflect.Descriptor instead.\nfunc (*SubscriptionResponse) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *SubscriptionResponse) GetSubscriptionId() uint32 {\n\tif x != nil {\n\t\treturn x.SubscriptionId\n\t}\n\treturn 0\n}\n\n//  2. Telemetry data send back on the same connection as the\n//     subscription request.\ntype OpenConfigData struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// router name:export IP address\n\tSystemId string `protobuf:\"bytes,1,opt,name=system_id,json=systemId,proto3\" json:\"system_id,omitempty\"`\n\t// line card / RE (slot number)\n\tComponentId uint32 `protobuf:\"varint,2,opt,name=component_id,json=componentId,proto3\" json:\"component_id,omitempty\"`\n\t// PFE (if applicable)\n\tSubComponentId uint32 `protobuf:\"varint,3,opt,name=sub_component_id,json=subComponentId,proto3\" json:\"sub_component_id,omitempty\"`\n\t// Path specification for elements of OpenConfig data models\n\tPath string `protobuf:\"bytes,4,opt,name=path,proto3\" json:\"path,omitempty\"`\n\t// Sequence number, monotonically increasing for each\n\t// system_id, component_id, sub_component_id + path.\n\tSequenceNumber uint64 `protobuf:\"varint,5,opt,name=sequence_number,json=sequenceNumber,proto3\" json:\"sequence_number,omitempty\"`\n\t// timestamp (milliseconds since epoch)\n\tTimestamp uint64 `protobuf:\"varint,6,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\t// List of key-value pairs\n\tKv []*KeyValue `protobuf:\"bytes,7,rep,name=kv,proto3\" json:\"kv,omitempty\"`\n\t// For delete. If filled, it indicates delete\n\tDelete []*Delete `protobuf:\"bytes,8,rep,name=delete,proto3\" json:\"delete,omitempty\"`\n\t// If filled, it indicates end of marker for the\n\t// respective path in the list.\n\tEom []*Eom `protobuf:\"bytes,9,rep,name=eom,proto3\" json:\"eom,omitempty\"`\n\t// If filled, it indicates end of sync for complete subscription\n\tSyncResponse bool `protobuf:\"varint,10,opt,name=sync_response,json=syncResponse,proto3\" json:\"sync_response,omitempty\"`\n}\n\nfunc (x *OpenConfigData) Reset() {\n\t*x = OpenConfigData{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OpenConfigData) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OpenConfigData) ProtoMessage() {}\n\nfunc (x *OpenConfigData) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OpenConfigData.ProtoReflect.Descriptor instead.\nfunc (*OpenConfigData) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *OpenConfigData) GetSystemId() string {\n\tif x != nil {\n\t\treturn x.SystemId\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenConfigData) GetComponentId() uint32 {\n\tif x != nil {\n\t\treturn x.ComponentId\n\t}\n\treturn 0\n}\n\nfunc (x *OpenConfigData) GetSubComponentId() uint32 {\n\tif x != nil {\n\t\treturn x.SubComponentId\n\t}\n\treturn 0\n}\n\nfunc (x *OpenConfigData) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenConfigData) GetSequenceNumber() uint64 {\n\tif x != nil {\n\t\treturn x.SequenceNumber\n\t}\n\treturn 0\n}\n\nfunc (x *OpenConfigData) GetTimestamp() uint64 {\n\tif x != nil {\n\t\treturn x.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *OpenConfigData) GetKv() []*KeyValue {\n\tif x != nil {\n\t\treturn x.Kv\n\t}\n\treturn nil\n}\n\nfunc (x *OpenConfigData) GetDelete() []*Delete {\n\tif x != nil {\n\t\treturn x.Delete\n\t}\n\treturn nil\n}\n\nfunc (x *OpenConfigData) GetEom() []*Eom {\n\tif x != nil {\n\t\treturn x.Eom\n\t}\n\treturn nil\n}\n\nfunc (x *OpenConfigData) GetSyncResponse() bool {\n\tif x != nil {\n\t\treturn x.SyncResponse\n\t}\n\treturn false\n}\n\n// Simple Key-value, where value could be one of scalar types\ntype KeyValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Key\n\tKey string `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\t// One of possible values\n\t//\n\t// Types that are assignable to Value:\n\t//\t*KeyValue_DoubleValue\n\t//\t*KeyValue_IntValue\n\t//\t*KeyValue_UintValue\n\t//\t*KeyValue_SintValue\n\t//\t*KeyValue_BoolValue\n\t//\t*KeyValue_StrValue\n\t//\t*KeyValue_BytesValue\n\tValue isKeyValue_Value `protobuf_oneof:\"value\"`\n}\n\nfunc (x *KeyValue) Reset() {\n\t*x = KeyValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *KeyValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KeyValue) ProtoMessage() {}\n\nfunc (x *KeyValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KeyValue.ProtoReflect.Descriptor instead.\nfunc (*KeyValue) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *KeyValue) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (m *KeyValue) GetValue() isKeyValue_Value {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\nfunc (x *KeyValue) GetDoubleValue() float64 {\n\tif x, ok := x.GetValue().(*KeyValue_DoubleValue); ok {\n\t\treturn x.DoubleValue\n\t}\n\treturn 0\n}\n\nfunc (x *KeyValue) GetIntValue() int64 {\n\tif x, ok := x.GetValue().(*KeyValue_IntValue); ok {\n\t\treturn x.IntValue\n\t}\n\treturn 0\n}\n\nfunc (x *KeyValue) GetUintValue() uint64 {\n\tif x, ok := x.GetValue().(*KeyValue_UintValue); ok {\n\t\treturn x.UintValue\n\t}\n\treturn 0\n}\n\nfunc (x *KeyValue) GetSintValue() int64 {\n\tif x, ok := x.GetValue().(*KeyValue_SintValue); ok {\n\t\treturn x.SintValue\n\t}\n\treturn 0\n}\n\nfunc (x *KeyValue) GetBoolValue() bool {\n\tif x, ok := x.GetValue().(*KeyValue_BoolValue); ok {\n\t\treturn x.BoolValue\n\t}\n\treturn false\n}\n\nfunc (x *KeyValue) GetStrValue() string {\n\tif x, ok := x.GetValue().(*KeyValue_StrValue); ok {\n\t\treturn x.StrValue\n\t}\n\treturn \"\"\n}\n\nfunc (x *KeyValue) GetBytesValue() []byte {\n\tif x, ok := x.GetValue().(*KeyValue_BytesValue); ok {\n\t\treturn x.BytesValue\n\t}\n\treturn nil\n}\n\ntype isKeyValue_Value interface {\n\tisKeyValue_Value()\n}\n\ntype KeyValue_DoubleValue struct {\n\tDoubleValue float64 `protobuf:\"fixed64,5,opt,name=double_value,json=doubleValue,proto3,oneof\"`\n}\n\ntype KeyValue_IntValue struct {\n\tIntValue int64 `protobuf:\"varint,6,opt,name=int_value,json=intValue,proto3,oneof\"`\n}\n\ntype KeyValue_UintValue struct {\n\tUintValue uint64 `protobuf:\"varint,7,opt,name=uint_value,json=uintValue,proto3,oneof\"`\n}\n\ntype KeyValue_SintValue struct {\n\tSintValue int64 `protobuf:\"zigzag64,8,opt,name=sint_value,json=sintValue,proto3,oneof\"`\n}\n\ntype KeyValue_BoolValue struct {\n\tBoolValue bool `protobuf:\"varint,9,opt,name=bool_value,json=boolValue,proto3,oneof\"`\n}\n\ntype KeyValue_StrValue struct {\n\tStrValue string `protobuf:\"bytes,10,opt,name=str_value,json=strValue,proto3,oneof\"`\n}\n\ntype KeyValue_BytesValue struct {\n\tBytesValue []byte `protobuf:\"bytes,11,opt,name=bytes_value,json=bytesValue,proto3,oneof\"`\n}\n\nfunc (*KeyValue_DoubleValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_IntValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_UintValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_SintValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_BoolValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_StrValue) isKeyValue_Value() {}\n\nfunc (*KeyValue_BytesValue) isKeyValue_Value() {}\n\n// Message indicating delete for a particular path\ntype Delete struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n}\n\nfunc (x *Delete) Reset() {\n\t*x = Delete{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Delete) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Delete) ProtoMessage() {}\n\nfunc (x *Delete) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Delete.ProtoReflect.Descriptor instead.\nfunc (*Delete) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *Delete) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\n// Message indicating EOM for a particular path\ntype Eom struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n}\n\nfunc (x *Eom) Reset() {\n\t*x = Eom{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Eom) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Eom) ProtoMessage() {}\n\nfunc (x *Eom) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Eom.ProtoReflect.Descriptor instead.\nfunc (*Eom) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *Eom) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\n// Message sent for a telemetry subscription cancellation request\ntype CancelSubscriptionRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Subscription identifier as returned by the device when\n\t// subscription was requested\n\tSubscriptionId uint32 `protobuf:\"varint,1,opt,name=subscription_id,json=subscriptionId,proto3\" json:\"subscription_id,omitempty\"`\n}\n\nfunc (x *CancelSubscriptionRequest) Reset() {\n\t*x = CancelSubscriptionRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CancelSubscriptionRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CancelSubscriptionRequest) ProtoMessage() {}\n\nfunc (x *CancelSubscriptionRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CancelSubscriptionRequest.ProtoReflect.Descriptor instead.\nfunc (*CancelSubscriptionRequest) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *CancelSubscriptionRequest) GetSubscriptionId() uint32 {\n\tif x != nil {\n\t\treturn x.SubscriptionId\n\t}\n\treturn 0\n}\n\n// Reply to telemetry subscription cancellation request\ntype CancelSubscriptionReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Return code\n\tCode ReturnCode `protobuf:\"varint,1,opt,name=code,proto3,enum=telemetry.ReturnCode\" json:\"code,omitempty\"`\n\t// Return code string\n\tCodeStr string `protobuf:\"bytes,2,opt,name=code_str,json=codeStr,proto3\" json:\"code_str,omitempty\"`\n}\n\nfunc (x *CancelSubscriptionReply) Reset() {\n\t*x = CancelSubscriptionReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[12]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CancelSubscriptionReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CancelSubscriptionReply) ProtoMessage() {}\n\nfunc (x *CancelSubscriptionReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[12]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CancelSubscriptionReply.ProtoReflect.Descriptor instead.\nfunc (*CancelSubscriptionReply) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *CancelSubscriptionReply) GetCode() ReturnCode {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn ReturnCode_SUCCESS\n}\n\nfunc (x *CancelSubscriptionReply) GetCodeStr() string {\n\tif x != nil {\n\t\treturn x.CodeStr\n\t}\n\treturn \"\"\n}\n\n// Message sent for a telemetry get request\ntype GetSubscriptionsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Subscription identifier as returned by the device when\n\t// subscription was requested\n\t// --- or ---\n\t// 0xFFFFFFFF for all subscription identifiers\n\tSubscriptionId uint32 `protobuf:\"varint,1,opt,name=subscription_id,json=subscriptionId,proto3\" json:\"subscription_id,omitempty\"`\n}\n\nfunc (x *GetSubscriptionsRequest) Reset() {\n\t*x = GetSubscriptionsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[13]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSubscriptionsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSubscriptionsRequest) ProtoMessage() {}\n\nfunc (x *GetSubscriptionsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[13]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSubscriptionsRequest.ProtoReflect.Descriptor instead.\nfunc (*GetSubscriptionsRequest) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *GetSubscriptionsRequest) GetSubscriptionId() uint32 {\n\tif x != nil {\n\t\treturn x.SubscriptionId\n\t}\n\treturn 0\n}\n\n// Reply to telemetry subscription get request\ntype GetSubscriptionsReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// List of current telemetry subscriptions\n\tSubscriptionList []*SubscriptionReply `protobuf:\"bytes,1,rep,name=subscription_list,json=subscriptionList,proto3\" json:\"subscription_list,omitempty\"`\n}\n\nfunc (x *GetSubscriptionsReply) Reset() {\n\t*x = GetSubscriptionsReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[14]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSubscriptionsReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSubscriptionsReply) ProtoMessage() {}\n\nfunc (x *GetSubscriptionsReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[14]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSubscriptionsReply.ProtoReflect.Descriptor instead.\nfunc (*GetSubscriptionsReply) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *GetSubscriptionsReply) GetSubscriptionList() []*SubscriptionReply {\n\tif x != nil {\n\t\treturn x.SubscriptionList\n\t}\n\treturn nil\n}\n\n// Message sent for telemetry agent operational states request\ntype GetOperationalStateRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Per-subscription_id level operational state can be requested.\n\t//\n\t// Subscription identifier as returned by the device when\n\t// subscription was requested\n\t// --- or ---\n\t// 0xFFFFFFFF for all subscription identifiers including agent-level\n\t// operational stats\n\t// --- or ---\n\t// If subscription_id is not present then sent only agent-level\n\t// operational stats\n\tSubscriptionId uint32 `protobuf:\"varint,1,opt,name=subscription_id,json=subscriptionId,proto3\" json:\"subscription_id,omitempty\"`\n\t// Control verbosity of the output\n\tVerbosity VerbosityLevel `protobuf:\"varint,2,opt,name=verbosity,proto3,enum=telemetry.VerbosityLevel\" json:\"verbosity,omitempty\"`\n}\n\nfunc (x *GetOperationalStateRequest) Reset() {\n\t*x = GetOperationalStateRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[15]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetOperationalStateRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetOperationalStateRequest) ProtoMessage() {}\n\nfunc (x *GetOperationalStateRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[15]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetOperationalStateRequest.ProtoReflect.Descriptor instead.\nfunc (*GetOperationalStateRequest) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *GetOperationalStateRequest) GetSubscriptionId() uint32 {\n\tif x != nil {\n\t\treturn x.SubscriptionId\n\t}\n\treturn 0\n}\n\nfunc (x *GetOperationalStateRequest) GetVerbosity() VerbosityLevel {\n\tif x != nil {\n\t\treturn x.Verbosity\n\t}\n\treturn VerbosityLevel_DETAIL\n}\n\n// Reply to telemetry agent operational states request\ntype GetOperationalStateReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// List of key-value pairs where\n\t//     key      = operational state definition\n\t//     value    = operational state value\n\tKv []*KeyValue `protobuf:\"bytes,1,rep,name=kv,proto3\" json:\"kv,omitempty\"`\n}\n\nfunc (x *GetOperationalStateReply) Reset() {\n\t*x = GetOperationalStateReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[16]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetOperationalStateReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetOperationalStateReply) ProtoMessage() {}\n\nfunc (x *GetOperationalStateReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[16]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetOperationalStateReply.ProtoReflect.Descriptor instead.\nfunc (*GetOperationalStateReply) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *GetOperationalStateReply) GetKv() []*KeyValue {\n\tif x != nil {\n\t\treturn x.Kv\n\t}\n\treturn nil\n}\n\n// Message sent for a data encoding request\ntype DataEncodingRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DataEncodingRequest) Reset() {\n\t*x = DataEncodingRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[17]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DataEncodingRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DataEncodingRequest) ProtoMessage() {}\n\nfunc (x *DataEncodingRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[17]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DataEncodingRequest.ProtoReflect.Descriptor instead.\nfunc (*DataEncodingRequest) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{17}\n}\n\n// Reply to data encodings supported request\ntype DataEncodingReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEncodingList []EncodingType `protobuf:\"varint,1,rep,packed,name=encoding_list,json=encodingList,proto3,enum=telemetry.EncodingType\" json:\"encoding_list,omitempty\"`\n}\n\nfunc (x *DataEncodingReply) Reset() {\n\t*x = DataEncodingReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_oc_oc_proto_msgTypes[18]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DataEncodingReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DataEncodingReply) ProtoMessage() {}\n\nfunc (x *DataEncodingReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_oc_oc_proto_msgTypes[18]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DataEncodingReply.ProtoReflect.Descriptor instead.\nfunc (*DataEncodingReply) Descriptor() ([]byte, []int) {\n\treturn file_oc_oc_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *DataEncodingReply) GetEncodingList() []EncodingType {\n\tif x != nil {\n\t\treturn x.EncodingList\n\t}\n\treturn nil\n}\n\nvar File_oc_oc_proto protoreflect.FileDescriptor\n\nvar file_oc_oc_proto_rawDesc = []byte{\n\t0x0a, 0x0b, 0x6f, 0x63, 0x2f, 0x6f, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x74,\n\t0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x53, 0x75, 0x62,\n\t0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x73,\n\t0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x05, 0x69,\n\t0x6e, 0x70, 0x75, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6c, 0x69, 0x73,\n\t0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65,\n\t0x74, 0x72, 0x79, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x08, 0x70, 0x61, 0x74, 0x68, 0x4c, 0x69,\n\t0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,\n\t0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e,\n\t0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,\n\t0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x50, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73,\n\t0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3b, 0x0a,\n\t0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18,\n\t0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,\n\t0x79, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x63, 0x6f, 0x6c,\n\t0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x39, 0x0a, 0x09, 0x43, 0x6f,\n\t0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,\n\t0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,\n\t0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,\n\t0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0xd7, 0x01, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12,\n\t0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,\n\t0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x73, 0x75,\n\t0x70, 0x70, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x75, 0x6e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, 0x73,\n\t0x55, 0x6e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x61, 0x78,\n\t0x5f, 0x73, 0x69, 0x6c, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6d, 0x61, 0x78, 0x53, 0x69, 0x6c, 0x65, 0x6e,\n\t0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x61, 0x6d,\n\t0x70, 0x6c, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20,\n\t0x01, 0x28, 0x0d, 0x52, 0x0f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75,\n\t0x65, 0x6e, 0x63, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x65, 0x6f, 0x6d,\n\t0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x65, 0x65, 0x64, 0x45, 0x6f, 0x6d, 0x22,\n\t0x8c, 0x01, 0x0a, 0x1c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65,\n\t0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x74,\n\t0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x05, 0x52, 0x10, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f,\n\t0x6e, 0x64, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x65, 0x6f, 0x73, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6e, 0x65, 0x65, 0x64, 0x45, 0x6f, 0x73, 0x22, 0x7e,\n\t0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,\n\t0x70, 0x6c, 0x79, 0x12, 0x3b, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,\n\t0x79, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x12, 0x2c, 0x0a, 0x09, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e,\n\t0x50, 0x61, 0x74, 0x68, 0x52, 0x08, 0x70, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3f,\n\t0x0a, 0x14, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,\n\t0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22,\n\t0xec, 0x02, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x61,\n\t0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12,\n\t0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,\n\t0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,\n\t0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x75,\n\t0x62, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,\n\t0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,\n\t0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d,\n\t0x62, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, 0x65, 0x71, 0x75, 0x65,\n\t0x6e, 0x63, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,\n\t0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69,\n\t0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x02, 0x6b, 0x76, 0x18, 0x07, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e,\n\t0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x02, 0x6b, 0x76, 0x12, 0x29, 0x0a, 0x06,\n\t0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74,\n\t0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,\n\t0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x6f, 0x6d, 0x18, 0x09,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,\n\t0x2e, 0x45, 0x6f, 0x6d, 0x52, 0x03, 0x65, 0x6f, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x79, 0x6e,\n\t0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8e,\n\t0x02, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b,\n\t0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a,\n\t0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20,\n\t0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c,\n\t0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,\n\t0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,\n\t0x07, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x09, 0x75, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c,\n\t0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x73, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x18, 0x08, 0x20, 0x01, 0x28, 0x12, 0x48, 0x00, 0x52, 0x09, 0x73, 0x69, 0x6e, 0x74, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x73, 0x74, 0x72, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65,\n\t0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x1c, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74,\n\t0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x19, 0x0a,\n\t0x03, 0x45, 0x6f, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x44, 0x0a, 0x19, 0x43, 0x61, 0x6e, 0x63,\n\t0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e,\n\t0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x5f,\n\t0x0a, 0x17, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,\n\t0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a, 0x04, 0x63, 0x6f, 0x64,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65,\n\t0x74, 0x72, 0x79, 0x2e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04,\n\t0x63, 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x74, 0x72,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x72, 0x22,\n\t0x42, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75,\n\t0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,\n\t0x6e, 0x49, 0x64, 0x22, 0x62, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x11,\n\t0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x73,\n\t0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65,\n\t0x74, 0x72, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x10, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x7e, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4f, 0x70,\n\t0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e,\n\t0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x37,\n\t0x0a, 0x09, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x0e, 0x32, 0x19, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x56, 0x65,\n\t0x72, 0x62, 0x6f, 0x73, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x09, 0x76, 0x65,\n\t0x72, 0x62, 0x6f, 0x73, 0x69, 0x74, 0x79, 0x22, 0x3f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4f, 0x70,\n\t0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,\n\t0x70, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x02, 0x6b, 0x76, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x13, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x52, 0x02, 0x6b, 0x76, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x61, 0x74, 0x61,\n\t0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,\n\t0x51, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52,\n\t0x65, 0x70, 0x6c, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67,\n\t0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x65,\n\t0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67,\n\t0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x69,\n\t0x73, 0x74, 0x2a, 0x47, 0x0a, 0x0a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x6f, 0x64, 0x65,\n\t0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x19, 0x0a,\n\t0x15, 0x4e, 0x4f, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e,\n\t0x5f, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x4b, 0x4e,\n\t0x4f, 0x57, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x2a, 0x32, 0x0a, 0x0e, 0x56,\n\t0x65, 0x72, 0x62, 0x6f, 0x73, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0a, 0x0a,\n\t0x06, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x45, 0x52,\n\t0x53, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x52, 0x49, 0x45, 0x46, 0x10, 0x02, 0x2a,\n\t0x41, 0x0a, 0x0c, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12,\n\t0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07,\n\t0x0a, 0x03, 0x58, 0x4d, 0x4c, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4a, 0x53, 0x4f, 0x4e, 0x5f,\n\t0x49, 0x45, 0x54, 0x46, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x33,\n\t0x10, 0x03, 0x32, 0xfc, 0x03, 0x0a, 0x13, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x12, 0x53, 0x0a, 0x12, 0x74, 0x65,\n\t0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,\n\t0x12, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x75, 0x62,\n\t0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x19, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x4f, 0x70, 0x65,\n\t0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x30, 0x01, 0x12,\n\t0x69, 0x0a, 0x1b, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74,\n\t0x72, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24,\n\t0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65,\n\t0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,\n\t0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x19, 0x67, 0x65,\n\t0x74, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72,\n\t0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65,\n\t0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x65,\n\t0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63,\n\t0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12,\n\t0x6c, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x4f,\n\t0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,\n\t0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4f,\n\t0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74,\n\t0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61,\n\t0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x52, 0x0a,\n\t0x10, 0x67, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67,\n\t0x73, 0x12, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x61,\n\t0x74, 0x61, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x61,\n\t0x74, 0x61, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22,\n\t0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_oc_oc_proto_rawDescOnce sync.Once\n\tfile_oc_oc_proto_rawDescData = file_oc_oc_proto_rawDesc\n)\n\nfunc file_oc_oc_proto_rawDescGZIP() []byte {\n\tfile_oc_oc_proto_rawDescOnce.Do(func() {\n\t\tfile_oc_oc_proto_rawDescData = protoimpl.X.CompressGZIP(file_oc_oc_proto_rawDescData)\n\t})\n\treturn file_oc_oc_proto_rawDescData\n}\n\nvar file_oc_oc_proto_enumTypes = make([]protoimpl.EnumInfo, 3)\nvar file_oc_oc_proto_msgTypes = make([]protoimpl.MessageInfo, 19)\nvar file_oc_oc_proto_goTypes = []interface{}{\n\t(ReturnCode)(0),                      // 0: telemetry.ReturnCode\n\t(VerbosityLevel)(0),                  // 1: telemetry.VerbosityLevel\n\t(EncodingType)(0),                    // 2: telemetry.EncodingType\n\t(*SubscriptionRequest)(nil),          // 3: telemetry.SubscriptionRequest\n\t(*SubscriptionInput)(nil),            // 4: telemetry.SubscriptionInput\n\t(*Collector)(nil),                    // 5: telemetry.Collector\n\t(*Path)(nil),                         // 6: telemetry.Path\n\t(*SubscriptionAdditionalConfig)(nil), // 7: telemetry.SubscriptionAdditionalConfig\n\t(*SubscriptionReply)(nil),            // 8: telemetry.SubscriptionReply\n\t(*SubscriptionResponse)(nil),         // 9: telemetry.SubscriptionResponse\n\t(*OpenConfigData)(nil),               // 10: telemetry.OpenConfigData\n\t(*KeyValue)(nil),                     // 11: telemetry.KeyValue\n\t(*Delete)(nil),                       // 12: telemetry.Delete\n\t(*Eom)(nil),                          // 13: telemetry.Eom\n\t(*CancelSubscriptionRequest)(nil),    // 14: telemetry.CancelSubscriptionRequest\n\t(*CancelSubscriptionReply)(nil),      // 15: telemetry.CancelSubscriptionReply\n\t(*GetSubscriptionsRequest)(nil),      // 16: telemetry.GetSubscriptionsRequest\n\t(*GetSubscriptionsReply)(nil),        // 17: telemetry.GetSubscriptionsReply\n\t(*GetOperationalStateRequest)(nil),   // 18: telemetry.GetOperationalStateRequest\n\t(*GetOperationalStateReply)(nil),     // 19: telemetry.GetOperationalStateReply\n\t(*DataEncodingRequest)(nil),          // 20: telemetry.DataEncodingRequest\n\t(*DataEncodingReply)(nil),            // 21: telemetry.DataEncodingReply\n}\nvar file_oc_oc_proto_depIdxs = []int32{\n\t4,  // 0: telemetry.SubscriptionRequest.input:type_name -> telemetry.SubscriptionInput\n\t6,  // 1: telemetry.SubscriptionRequest.path_list:type_name -> telemetry.Path\n\t7,  // 2: telemetry.SubscriptionRequest.additional_config:type_name -> telemetry.SubscriptionAdditionalConfig\n\t5,  // 3: telemetry.SubscriptionInput.collector_list:type_name -> telemetry.Collector\n\t9,  // 4: telemetry.SubscriptionReply.response:type_name -> telemetry.SubscriptionResponse\n\t6,  // 5: telemetry.SubscriptionReply.path_list:type_name -> telemetry.Path\n\t11, // 6: telemetry.OpenConfigData.kv:type_name -> telemetry.KeyValue\n\t12, // 7: telemetry.OpenConfigData.delete:type_name -> telemetry.Delete\n\t13, // 8: telemetry.OpenConfigData.eom:type_name -> telemetry.Eom\n\t0,  // 9: telemetry.CancelSubscriptionReply.code:type_name -> telemetry.ReturnCode\n\t8,  // 10: telemetry.GetSubscriptionsReply.subscription_list:type_name -> telemetry.SubscriptionReply\n\t1,  // 11: telemetry.GetOperationalStateRequest.verbosity:type_name -> telemetry.VerbosityLevel\n\t11, // 12: telemetry.GetOperationalStateReply.kv:type_name -> telemetry.KeyValue\n\t2,  // 13: telemetry.DataEncodingReply.encoding_list:type_name -> telemetry.EncodingType\n\t3,  // 14: telemetry.OpenConfigTelemetry.telemetrySubscribe:input_type -> telemetry.SubscriptionRequest\n\t14, // 15: telemetry.OpenConfigTelemetry.cancelTelemetrySubscription:input_type -> telemetry.CancelSubscriptionRequest\n\t16, // 16: telemetry.OpenConfigTelemetry.getTelemetrySubscriptions:input_type -> telemetry.GetSubscriptionsRequest\n\t18, // 17: telemetry.OpenConfigTelemetry.getTelemetryOperationalState:input_type -> telemetry.GetOperationalStateRequest\n\t20, // 18: telemetry.OpenConfigTelemetry.getDataEncodings:input_type -> telemetry.DataEncodingRequest\n\t10, // 19: telemetry.OpenConfigTelemetry.telemetrySubscribe:output_type -> telemetry.OpenConfigData\n\t15, // 20: telemetry.OpenConfigTelemetry.cancelTelemetrySubscription:output_type -> telemetry.CancelSubscriptionReply\n\t17, // 21: telemetry.OpenConfigTelemetry.getTelemetrySubscriptions:output_type -> telemetry.GetSubscriptionsReply\n\t19, // 22: telemetry.OpenConfigTelemetry.getTelemetryOperationalState:output_type -> telemetry.GetOperationalStateReply\n\t21, // 23: telemetry.OpenConfigTelemetry.getDataEncodings:output_type -> telemetry.DataEncodingReply\n\t19, // [19:24] is the sub-list for method output_type\n\t14, // [14:19] is the sub-list for method input_type\n\t14, // [14:14] is the sub-list for extension type_name\n\t14, // [14:14] is the sub-list for extension extendee\n\t0,  // [0:14] is the sub-list for field type_name\n}\n\nfunc init() { file_oc_oc_proto_init() }\nfunc file_oc_oc_proto_init() {\n\tif File_oc_oc_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_oc_oc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscriptionRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscriptionInput); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Collector); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Path); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscriptionAdditionalConfig); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscriptionReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SubscriptionResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OpenConfigData); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*KeyValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Delete); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Eom); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CancelSubscriptionRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CancelSubscriptionReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSubscriptionsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSubscriptionsReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetOperationalStateRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetOperationalStateReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DataEncodingRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_oc_oc_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DataEncodingReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_oc_oc_proto_msgTypes[8].OneofWrappers = []interface{}{\n\t\t(*KeyValue_DoubleValue)(nil),\n\t\t(*KeyValue_IntValue)(nil),\n\t\t(*KeyValue_UintValue)(nil),\n\t\t(*KeyValue_SintValue)(nil),\n\t\t(*KeyValue_BoolValue)(nil),\n\t\t(*KeyValue_StrValue)(nil),\n\t\t(*KeyValue_BytesValue)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_oc_oc_proto_rawDesc,\n\t\t\tNumEnums:      3,\n\t\t\tNumMessages:   19,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_oc_oc_proto_goTypes,\n\t\tDependencyIndexes: file_oc_oc_proto_depIdxs,\n\t\tEnumInfos:         file_oc_oc_proto_enumTypes,\n\t\tMessageInfos:      file_oc_oc_proto_msgTypes,\n\t}.Build()\n\tFile_oc_oc_proto = out.File\n\tfile_oc_oc_proto_rawDesc = nil\n\tfile_oc_oc_proto_goTypes = nil\n\tfile_oc_oc_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/oc/oc.proto",
    "content": "//\n// Copyrights (c) 2016, Juniper Networks, Inc.\n// All rights reserved.\n//\n\n//\n// Licensed to the Apache Software Foundation (ASF) under one\n// or more contributor license agreements.  See the NOTICE file\n// distributed with this work for additional information\n// regarding copyright ownership.  The ASF licenses this file\n// to you under the Apache License, Version 2.0 (the\n// \"License\"); you may not use this file except in compliance\n// with the License.  You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing,\n// software distributed under the License is distributed on an\n// \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n// KIND, either express or implied.  See the License for the\n// specific language governing permissions and limitations\n// under the License.\n//\n\n//\n// Nitin Kumar          04/07/2016\n// Abbas Sakarwala      04/07/2016\n//\n// This file defines the Openconfig Telemetry RPC APIs (for gRPC).\n//\n// https://github.com/openconfig/public/blob/master/release/models/rpc/openconfig-rpc-api.yang\n//\n// Version 1.0\n//\n\nsyntax = \"proto3\";\n\npackage telemetry;\noption go_package = \".;telemetry\";\n\n// Interface exported by Agent\nservice OpenConfigTelemetry {\n    // Request an inline subscription for data at the specified path.\n    // The device should send telemetry data back on the same\n    // connection as the subscription request.\n    rpc telemetrySubscribe(SubscriptionRequest)                     returns (stream OpenConfigData) {}\n\n    // Terminates and removes an existing telemetry subscription\n    rpc cancelTelemetrySubscription(CancelSubscriptionRequest)      returns (CancelSubscriptionReply) {}\n\n    // Get the list of current telemetry subscriptions from the\n    // target. This command returns a list of existing subscriptions\n    // not including those that are established via configuration.\n    rpc getTelemetrySubscriptions(GetSubscriptionsRequest)          returns (GetSubscriptionsReply) {}\n\n    // Get Telemetry Agent Operational States\n    rpc getTelemetryOperationalState(GetOperationalStateRequest)    returns (GetOperationalStateReply) {}\n\n    // Return the set of data encodings supported by the device for\n    // telemetry data\n    rpc getDataEncodings(DataEncodingRequest)                       returns (DataEncodingReply) {}\n}\n\n// Message sent for a telemetry subscription request\nmessage SubscriptionRequest {\n    // Data associated with a telemetry subscription\n    SubscriptionInput input                                 = 1;\n\n    // List of data models paths and filters\n    // which are used in a telemetry operation.\n    repeated Path path_list                                 = 2;\n\n    // The below configuration is not defined in Openconfig RPC.\n    // It is a proposed extension to configure additional\n    // subscription request features.\n    SubscriptionAdditionalConfig additional_config          = 3;\n}\n\n// Data associated with a telemetry subscription\nmessage SubscriptionInput {\n    // List of optional collector endpoints to send data for\n    // this subscription.\n    // If no collector destinations are specified, the collector\n    // destination is assumed to be the requester on the rpc channel.\n    repeated Collector  collector_list                      = 1;\n}\n\n// Collector endpoints to send data specified as an ip+port combination.\nmessage Collector {\n    // IP address of collector endpoint\n    string address                                          = 1;\n\n    // Transport protocol port number for the collector destination.\n    uint32 port                                             = 2;\n}\n\n// Data model path\nmessage Path {\n    // Data model path of interest\n    // Path specification for elements of OpenConfig data models\n    string path                                             = 1;\n\n    // Regular expression to be used in filtering state leaves\n    string filter                                           = 2;\n\n    // If this is set to true, the target device will only send\n    // updates to the collector upon a change in data value\n    bool suppress_unchanged                                 = 3;\n\n    // Maximum time in ms the target device may go without sending\n    // a message to the collector. If this time expires with\n    // suppress-unchanged set, the target device must send an update\n    // message regardless if the data values have changed.\n    uint32 max_silent_interval                              = 4;\n\n    // Time in ms between collection and transmission of the\n    // specified data to the collector platform. The target device\n    // will sample the corresponding data (e.g,. a counter) and\n    // immediately send to the collector destination.\n    //\n    // If sample-frequency is set to 0, then the network device\n    // must emit an update upon every datum change.\n    uint32 sample_frequency                                 = 5;\n\n    // EOM needed for each walk cycle of this path?\n    //   For periodic sensor, applicable for each complete reap\n    //   For event sensor, applicable when initial dump is over \n    //     (same as EOS)\n    // This feature is not implemented currently.\n    bool need_eom                                           = 6;\n}\n\n// Configure subscription request additional features.\nmessage SubscriptionAdditionalConfig {\n    // limit the number of records sent in the stream\n    int32 limit_records                                     = 1;\n\n    // limit the time the stream remains open\n    int32 limit_time_seconds                                = 2;\n\n    // EOS needed for this subscription?\n    bool need_eos                                           = 3;\n}\n\n// Reply to inline subscription for data at the specified path is done in\n// two-folds.\n// 1. Reply data message sent out using out-of-band channel.\n// 2. Telemetry data send back on the same connection as the\n//    subscription request.\n\n// 1. Reply data message sent out using out-of-band channel.\nmessage SubscriptionReply {\n    // Response message to a telemetry subscription creation or\n    // get request.\n    SubscriptionResponse response                           = 1;\n\n    // List of data models paths and filters\n    // which are used in a telemetry operation.\n    repeated Path path_list                                 = 2;\n}\n\n// Response message to a telemetry subscription creation or get request.\nmessage SubscriptionResponse {\n    // Unique id for the subscription on the device. This is\n    // generated by the device and returned in a subscription\n    // request or when listing existing subscriptions\n    uint32 subscription_id = 1;\n}\n\n// 2. Telemetry data send back on the same connection as the\n//    subscription request.\nmessage OpenConfigData {\n    // router name:export IP address\n    string system_id                                        = 1;\n\n    // line card / RE (slot number)\n    uint32 component_id                                     = 2;\n\n    // PFE (if applicable)\n    uint32 sub_component_id                                 = 3;\n\n    // Path specification for elements of OpenConfig data models\n    string path                                             = 4;\n\n    // Sequence number, monotonically increasing for each\n    // system_id, component_id, sub_component_id + path.\n    uint64 sequence_number                                  = 5;\n\n    // timestamp (milliseconds since epoch)\n    uint64 timestamp                                        = 6;\n\n    // List of key-value pairs\n    repeated KeyValue kv                                    = 7;\n\n    // For delete. If filled, it indicates delete\n    repeated Delete delete                                  = 8;\n\n    // If filled, it indicates end of marker for the\n    // respective path in the list.\n    repeated Eom eom                                        = 9; \n\n    // If filled, it indicates end of sync for complete subscription\n    bool sync_response                                      = 10;\n}\n\n// Simple Key-value, where value could be one of scalar types\nmessage KeyValue {\n    // Key\n    string key                                              =  1;\n\n    // One of possible values\n    oneof value {\n        double double_value                                 =  5;\n        int64  int_value                                    =  6;\n        uint64 uint_value                                   =  7;\n        sint64 sint_value                                   =  8;\n        bool   bool_value                                   =  9;\n        string str_value                                    = 10;\n        bytes  bytes_value                                  = 11;\n    }\n}\n\n// Message indicating delete for a particular path\nmessage Delete {\n    string path                                             = 1;\n}\n\n// Message indicating EOM for a particular path\nmessage Eom {\n    string path                                             = 1; \n}\n\n// Message sent for a telemetry subscription cancellation request\nmessage CancelSubscriptionRequest {\n    // Subscription identifier as returned by the device when\n    // subscription was requested\n    uint32 subscription_id                                  = 1;\n}\n\n// Reply to telemetry subscription cancellation request\nmessage CancelSubscriptionReply {\n    // Return code\n    ReturnCode code                                         = 1;\n\n    // Return code string\n    string     code_str                                     = 2;\n};\n\n// Result of the operation\nenum ReturnCode {\n    SUCCESS                                                 = 0;\n    NO_SUBSCRIPTION_ENTRY                                   = 1;\n    UNKNOWN_ERROR                                           = 2;\n}\n\n// Message sent for a telemetry get request\nmessage GetSubscriptionsRequest {\n    // Subscription identifier as returned by the device when\n    // subscription was requested\n    // --- or ---\n    // 0xFFFFFFFF for all subscription identifiers\n    uint32 subscription_id                                  = 1;\n}\n\n// Reply to telemetry subscription get request\nmessage GetSubscriptionsReply {\n    // List of current telemetry subscriptions\n    repeated SubscriptionReply subscription_list            = 1;\n}\n\n// Message sent for telemetry agent operational states request\nmessage GetOperationalStateRequest {\n    // Per-subscription_id level operational state can be requested.\n    //\n    // Subscription identifier as returned by the device when\n    // subscription was requested\n    // --- or ---\n    // 0xFFFFFFFF for all subscription identifiers including agent-level\n    // operational stats\n    // --- or ---\n    // If subscription_id is not present then sent only agent-level\n    // operational stats\n    uint32 subscription_id                                  = 1;\n\n    // Control verbosity of the output\n    VerbosityLevel verbosity                                = 2;\n}\n\n// Verbosity Level\nenum VerbosityLevel {\n    DETAIL                                                  = 0;\n    TERSE                                                   = 1;\n    BRIEF                                                   = 2;\n}\n\n// Reply to telemetry agent operational states request\nmessage GetOperationalStateReply {\n    // List of key-value pairs where\n    //     key      = operational state definition\n    //     value    = operational state value\n    repeated KeyValue kv                                    = 1;\n}\n\n// Message sent for a data encoding request\nmessage DataEncodingRequest {\n}\n\n// Reply to data encodings supported request\nmessage DataEncodingReply {\n    repeated EncodingType  encoding_list                    = 1;\n}\n\n// Encoding Type Supported\nenum EncodingType {\n    UNDEFINED                                               = 0;\n    XML                                                     = 1;\n    JSON_IETF                                               = 2;\n    PROTO3                                                  = 3;\n}\n\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/oc/oc_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n\npackage telemetry\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\n// OpenConfigTelemetryClient is the client API for OpenConfigTelemetry service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype OpenConfigTelemetryClient interface {\n\t// Request an inline subscription for data at the specified path.\n\t// The device should send telemetry data back on the same\n\t// connection as the subscription request.\n\tTelemetrySubscribe(ctx context.Context, in *SubscriptionRequest, opts ...grpc.CallOption) (OpenConfigTelemetry_TelemetrySubscribeClient, error)\n\t// Terminates and removes an existing telemetry subscription\n\tCancelTelemetrySubscription(ctx context.Context, in *CancelSubscriptionRequest, opts ...grpc.CallOption) (*CancelSubscriptionReply, error)\n\t// Get the list of current telemetry subscriptions from the\n\t// target. This command returns a list of existing subscriptions\n\t// not including those that are established via configuration.\n\tGetTelemetrySubscriptions(ctx context.Context, in *GetSubscriptionsRequest, opts ...grpc.CallOption) (*GetSubscriptionsReply, error)\n\t// Get Telemetry Agent Operational States\n\tGetTelemetryOperationalState(ctx context.Context, in *GetOperationalStateRequest, opts ...grpc.CallOption) (*GetOperationalStateReply, error)\n\t// Return the set of data encodings supported by the device for\n\t// telemetry data\n\tGetDataEncodings(ctx context.Context, in *DataEncodingRequest, opts ...grpc.CallOption) (*DataEncodingReply, error)\n}\n\ntype openConfigTelemetryClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewOpenConfigTelemetryClient(cc grpc.ClientConnInterface) OpenConfigTelemetryClient {\n\treturn &openConfigTelemetryClient{cc}\n}\n\nfunc (c *openConfigTelemetryClient) TelemetrySubscribe(ctx context.Context, in *SubscriptionRequest, opts ...grpc.CallOption) (OpenConfigTelemetry_TelemetrySubscribeClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &OpenConfigTelemetry_ServiceDesc.Streams[0], \"/telemetry.OpenConfigTelemetry/telemetrySubscribe\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &openConfigTelemetryTelemetrySubscribeClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype OpenConfigTelemetry_TelemetrySubscribeClient interface {\n\tRecv() (*OpenConfigData, error)\n\tgrpc.ClientStream\n}\n\ntype openConfigTelemetryTelemetrySubscribeClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *openConfigTelemetryTelemetrySubscribeClient) Recv() (*OpenConfigData, error) {\n\tm := new(OpenConfigData)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *openConfigTelemetryClient) CancelTelemetrySubscription(ctx context.Context, in *CancelSubscriptionRequest, opts ...grpc.CallOption) (*CancelSubscriptionReply, error) {\n\tout := new(CancelSubscriptionReply)\n\terr := c.cc.Invoke(ctx, \"/telemetry.OpenConfigTelemetry/cancelTelemetrySubscription\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *openConfigTelemetryClient) GetTelemetrySubscriptions(ctx context.Context, in *GetSubscriptionsRequest, opts ...grpc.CallOption) (*GetSubscriptionsReply, error) {\n\tout := new(GetSubscriptionsReply)\n\terr := c.cc.Invoke(ctx, \"/telemetry.OpenConfigTelemetry/getTelemetrySubscriptions\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *openConfigTelemetryClient) GetTelemetryOperationalState(ctx context.Context, in *GetOperationalStateRequest, opts ...grpc.CallOption) (*GetOperationalStateReply, error) {\n\tout := new(GetOperationalStateReply)\n\terr := c.cc.Invoke(ctx, \"/telemetry.OpenConfigTelemetry/getTelemetryOperationalState\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *openConfigTelemetryClient) GetDataEncodings(ctx context.Context, in *DataEncodingRequest, opts ...grpc.CallOption) (*DataEncodingReply, error) {\n\tout := new(DataEncodingReply)\n\terr := c.cc.Invoke(ctx, \"/telemetry.OpenConfigTelemetry/getDataEncodings\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// OpenConfigTelemetryServer is the server API for OpenConfigTelemetry service.\n// All implementations must embed UnimplementedOpenConfigTelemetryServer\n// for forward compatibility\ntype OpenConfigTelemetryServer interface {\n\t// Request an inline subscription for data at the specified path.\n\t// The device should send telemetry data back on the same\n\t// connection as the subscription request.\n\tTelemetrySubscribe(*SubscriptionRequest, OpenConfigTelemetry_TelemetrySubscribeServer) error\n\t// Terminates and removes an existing telemetry subscription\n\tCancelTelemetrySubscription(context.Context, *CancelSubscriptionRequest) (*CancelSubscriptionReply, error)\n\t// Get the list of current telemetry subscriptions from the\n\t// target. This command returns a list of existing subscriptions\n\t// not including those that are established via configuration.\n\tGetTelemetrySubscriptions(context.Context, *GetSubscriptionsRequest) (*GetSubscriptionsReply, error)\n\t// Get Telemetry Agent Operational States\n\tGetTelemetryOperationalState(context.Context, *GetOperationalStateRequest) (*GetOperationalStateReply, error)\n\t// Return the set of data encodings supported by the device for\n\t// telemetry data\n\tGetDataEncodings(context.Context, *DataEncodingRequest) (*DataEncodingReply, error)\n\tmustEmbedUnimplementedOpenConfigTelemetryServer()\n}\n\n// UnimplementedOpenConfigTelemetryServer must be embedded to have forward compatible implementations.\ntype UnimplementedOpenConfigTelemetryServer struct {\n}\n\nfunc (UnimplementedOpenConfigTelemetryServer) TelemetrySubscribe(*SubscriptionRequest, OpenConfigTelemetry_TelemetrySubscribeServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method TelemetrySubscribe not implemented\")\n}\nfunc (UnimplementedOpenConfigTelemetryServer) CancelTelemetrySubscription(context.Context, *CancelSubscriptionRequest) (*CancelSubscriptionReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method CancelTelemetrySubscription not implemented\")\n}\nfunc (UnimplementedOpenConfigTelemetryServer) GetTelemetrySubscriptions(context.Context, *GetSubscriptionsRequest) (*GetSubscriptionsReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetTelemetrySubscriptions not implemented\")\n}\nfunc (UnimplementedOpenConfigTelemetryServer) GetTelemetryOperationalState(context.Context, *GetOperationalStateRequest) (*GetOperationalStateReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetTelemetryOperationalState not implemented\")\n}\nfunc (UnimplementedOpenConfigTelemetryServer) GetDataEncodings(context.Context, *DataEncodingRequest) (*DataEncodingReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetDataEncodings not implemented\")\n}\nfunc (UnimplementedOpenConfigTelemetryServer) mustEmbedUnimplementedOpenConfigTelemetryServer() {}\n\n// UnsafeOpenConfigTelemetryServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to OpenConfigTelemetryServer will\n// result in compilation errors.\ntype UnsafeOpenConfigTelemetryServer interface {\n\tmustEmbedUnimplementedOpenConfigTelemetryServer()\n}\n\nfunc RegisterOpenConfigTelemetryServer(s grpc.ServiceRegistrar, srv OpenConfigTelemetryServer) {\n\ts.RegisterService(&OpenConfigTelemetry_ServiceDesc, srv)\n}\n\nfunc _OpenConfigTelemetry_TelemetrySubscribe_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(SubscriptionRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(OpenConfigTelemetryServer).TelemetrySubscribe(m, &openConfigTelemetryTelemetrySubscribeServer{stream})\n}\n\ntype OpenConfigTelemetry_TelemetrySubscribeServer interface {\n\tSend(*OpenConfigData) error\n\tgrpc.ServerStream\n}\n\ntype openConfigTelemetryTelemetrySubscribeServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *openConfigTelemetryTelemetrySubscribeServer) Send(m *OpenConfigData) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _OpenConfigTelemetry_CancelTelemetrySubscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CancelSubscriptionRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(OpenConfigTelemetryServer).CancelTelemetrySubscription(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/telemetry.OpenConfigTelemetry/cancelTelemetrySubscription\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(OpenConfigTelemetryServer).CancelTelemetrySubscription(ctx, req.(*CancelSubscriptionRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _OpenConfigTelemetry_GetTelemetrySubscriptions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetSubscriptionsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(OpenConfigTelemetryServer).GetTelemetrySubscriptions(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/telemetry.OpenConfigTelemetry/getTelemetrySubscriptions\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(OpenConfigTelemetryServer).GetTelemetrySubscriptions(ctx, req.(*GetSubscriptionsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _OpenConfigTelemetry_GetTelemetryOperationalState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetOperationalStateRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(OpenConfigTelemetryServer).GetTelemetryOperationalState(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/telemetry.OpenConfigTelemetry/getTelemetryOperationalState\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(OpenConfigTelemetryServer).GetTelemetryOperationalState(ctx, req.(*GetOperationalStateRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _OpenConfigTelemetry_GetDataEncodings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(DataEncodingRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(OpenConfigTelemetryServer).GetDataEncodings(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/telemetry.OpenConfigTelemetry/getDataEncodings\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(OpenConfigTelemetryServer).GetDataEncodings(ctx, req.(*DataEncodingRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// OpenConfigTelemetry_ServiceDesc is the grpc.ServiceDesc for OpenConfigTelemetry service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar OpenConfigTelemetry_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"telemetry.OpenConfigTelemetry\",\n\tHandlerType: (*OpenConfigTelemetryServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"cancelTelemetrySubscription\",\n\t\t\tHandler:    _OpenConfigTelemetry_CancelTelemetrySubscription_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"getTelemetrySubscriptions\",\n\t\t\tHandler:    _OpenConfigTelemetry_GetTelemetrySubscriptions_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"getTelemetryOperationalState\",\n\t\t\tHandler:    _OpenConfigTelemetry_GetTelemetryOperationalState_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"getDataEncodings\",\n\t\t\tHandler:    _OpenConfigTelemetry_GetDataEncodings_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"telemetrySubscribe\",\n\t\t\tHandler:       _OpenConfigTelemetry_TelemetrySubscribe_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"oc/oc.proto\",\n}\n"
  },
  {
    "path": "plugins/inputs/jti_openconfig_telemetry/sample.conf",
    "content": "# Subscribe and receive OpenConfig Telemetry data using JTI\n[[inputs.jti_openconfig_telemetry]]\n  ## List of device addresses to collect telemetry from\n  servers = [\"localhost:1883\"]\n\n  ## Authentication details. Username and password are must if device expects\n  ## authentication. Client ID must be unique when connecting from multiple instances\n  ## of telegraf to the same device\n  username = \"user\"\n  password = \"pass\"\n  client_id = \"telegraf\"\n\n  ## Frequency to get data\n  sample_frequency = \"1000ms\"\n\n  ## Sensors to subscribe for\n  ## A identifier for each sensor can be provided in path by separating with space\n  ## Else sensor path will be used as identifier\n  ## When identifier is used, we can provide a list of space separated sensors.\n  ## A single subscription will be created with all these sensors and data will\n  ## be saved to measurement with this identifier name\n  sensors = [\n   \"/interfaces/\",\n   \"collection /components/ /lldp\",\n  ]\n\n  ## We allow specifying sensor group level reporting rate. To do this, specify the\n  ## reporting rate in Duration at the beginning of sensor paths / collection\n  ## name. For entries without reporting rate, we use configured sample frequency\n  sensors = [\n   \"1000ms customReporting /interfaces /lldp\",\n   \"2000ms collection /components\",\n   \"/interfaces\",\n  ]\n\n  ## Timestamp Source\n  ## Set to 'collection' for time of collection, and 'data' for using the time\n  ## provided by the _timestamp field.\n  # timestamp_source = \"collection\"\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Delay between retry attempts of failed RPC calls or streams. Defaults to 1000ms.\n  ## Failed streams/calls will not be retried if 0 is provided\n  retry_delay = \"1000ms\"\n\n  ## Period for sending keep-alive packets on idle connections\n  ## This is helpful to identify broken connections to the server\n  # keep_alive_period = \"10s\"\n\n  ## To treat all string values as tags, set this to true\n  str_as_tags = false\n"
  },
  {
    "path": "plugins/inputs/kafka_consumer/README.md",
    "content": "# Apache Kafka Consumer Input Plugin\n\nThis service plugin consumes messages from [Kafka brokers][kafka] in one of the\nsupported [data formats][data_formats]. The plugin uses\n[consumer groups][consumer_groups] when talking to the Kafka cluster so multiple\ninstances of Telegraf can consume messages from the same topic in parallel.\n\n⭐ Telegraf v0.2.3\n🏷️ messaging\n💻 all\n\n[kafka]: https://kafka.apache.org\n[consumer_groups]: http://godoc.org/github.com/wvanbergen/kafka/consumergroup\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options <!-- @/docs/includes/startup_error_behavior.md -->\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  Telegraf will try to startup the plugin in every gather or write\n            cycle in case of startup errors. The plugin is disabled until\n            the startup succeeds.\n- `probe`:  Telegraf will probe the plugin's function (if possible) and disables\n            the plugin in case probing fails. If the plugin does not support\n            probing, Telegraf will behave as if `ignore` was set instead.\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `sasl_username`,\n`sasl_password` and `sasl_access_token` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from Kafka topics\n[[inputs.kafka_consumer]]\n  ## Kafka brokers.\n  brokers = [\"localhost:9092\"]\n\n  ## Set the minimal supported Kafka version. Should be a string contains\n  ## 4 digits in case if it is 0 version and 3 digits for versions starting\n  ## from 1.0.0 separated by dot. This setting enables the use of new\n  ## Kafka features and APIs. Must be 0.10.2.0(used as default) or greater.\n  ## Please, check the list of supported versions at\n  ## https://pkg.go.dev/github.com/Shopify/sarama#SupportedVersions\n  ##   ex: kafka_version = \"2.6.0\"\n  ##   ex: kafka_version = \"0.10.2.0\"\n  # kafka_version = \"0.10.2.0\"\n\n  ## Topics to consume.\n  topics = [\"telegraf\"]\n\n  ## Topic regular expressions to consume. Matches will be added to topics.\n  ## Example: topic_regexps = [ \"*test\", \"metric[0-9A-z]*\" ]\n  # topic_regexps = [ ]\n\n  ## When set this tag will be added to all metrics with the topic as the value.\n  # topic_tag = \"\"\n\n  ## The list of Kafka message headers that should be pass as metric tags\n  ## works only for Kafka version 0.11+, on lower versions the message headers\n  ## are not available\n  # msg_headers_as_tags = []\n\n  ## The name of kafka message header which value should override the metric name.\n  ## In case when the same header specified in current option and in msg_headers_as_tags\n  ## option, it will be excluded from the msg_headers_as_tags list.\n  # msg_header_as_metric_name = \"\"\n\n  ## Set metric(s) timestamp using the given source.\n  ## Available options are:\n  ##   metric -- do not modify the metric timestamp\n  ##   inner  -- use the inner message timestamp (Kafka v0.10+)\n  ##   outer  -- use the outer (compressed) block timestamp (Kafka v0.10+)\n  # timestamp_source = \"metric\"\n\n  ## Optional Client id\n  # client_id = \"Telegraf\"\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Period between keep alive probes.\n  ## Defaults to the OS configuration if not specified or zero.\n  # keep_alive_period = \"15s\"\n\n  ## SASL authentication credentials. These settings should typically be used\n  ## with TLS encryption enabled\n  # sasl_username = \"\"\n  # sasl_password = \"\"\n\n  ## Optional SASL, one of:\n  ##   OAUTHBEARER, PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, AWS-MSK-IAM\n  # sasl_mechanism = \"\"\n\n  ## used if sasl_mechanism is GSSAPI\n  # sasl_gssapi_service_name = \"\"\n  # ## One of: KRB5_USER_AUTH and KRB5_KEYTAB_AUTH\n  # sasl_gssapi_auth_type = \"KRB5_USER_AUTH\"\n  # sasl_gssapi_kerberos_config_path = \"/\"\n  # sasl_gssapi_realm = \"realm\"\n  # sasl_gssapi_key_tab_path = \"\"\n  # sasl_gssapi_disable_pafxfast = false\n\n  ## used if sasl_mechanism is OAUTHBEARER\n  # sasl_access_token = \"\"\n\n  ## used if sasl_mechanism is AWS-MSK-IAM\n  # sasl_aws_msk_iam_region = \"\"\n  ## for profile based auth\n  ## sasl_aws_msk_iam_profile = \"\"\n  ## for role based auth\n  ## sasl_aws_msk_iam_role = \"\"\n  ## sasl_aws_msk_iam_session = \"\"\n\n  ## Arbitrary key value string pairs to pass as a TOML table. For example:\n  ## {logicalCluster = \"cluster-042\", poolId = \"pool-027\"}\n  # sasl_extensions = {}\n\n  ## SASL protocol version. When connecting to Azure EventHub set to 0.\n  # sasl_version = 1\n\n  # Disable Kafka metadata full fetch\n  # metadata_full = false\n\n  ## Name of the consumer group.\n  # consumer_group = \"telegraf_metrics_consumers\"\n\n  ## Compression codec represents the various compression codecs recognized by\n  ## Kafka in messages.\n  ##  0 : None\n  ##  1 : Gzip\n  ##  2 : Snappy\n  ##  3 : LZ4\n  ##  4 : ZSTD\n  # compression_codec = 0\n  ## Initial offset position; one of \"oldest\" or \"newest\".\n  # offset = \"oldest\"\n\n  ## Consumer group partition assignment strategy; one of \"range\", \"roundrobin\" or \"sticky\".\n  # balance_strategy = \"range\"\n\n  ## Maximum number of retries for metadata operations including\n  ## connecting. Sets Sarama library's Metadata.Retry.Max config value. If 0 or\n  ## unset, use the Sarama default of 3,\n  # metadata_retry_max = 0\n\n  ## Type of retry backoff. Valid options: \"constant\", \"exponential\"\n  # metadata_retry_type = \"constant\"\n\n  ## Amount of time to wait before retrying. When metadata_retry_type is\n  ## \"constant\", each retry is delayed this amount. When \"exponential\", the\n  ## first retry is delayed this amount, and subsequent delays are doubled. If 0\n  ## or unset, use the Sarama default of 250 ms\n  # metadata_retry_backoff = 0\n\n  ## Maximum amount of time to wait before retrying when metadata_retry_type is\n  ## \"exponential\". Ignored for other retry types. If 0, there is no backoff\n  ## limit.\n  # metadata_retry_max_duration = 0\n\n  ## When set to true, this turns each bootstrap broker address into a set of\n  ## IPs, then does a reverse lookup on each one to get its canonical hostname.\n  ## This list of hostnames then replaces the original address list.\n  ## resolve_canonical_bootstrap_servers_only = false\n\n  ## Maximum length of a message to consume, in bytes (default 0/unlimited);\n  ## larger messages are dropped\n  max_message_len = 1000000\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Maximum amount of time the consumer should take to process messages. If\n  ## the debug log prints messages from sarama about 'abandoning subscription\n  ## to [topic] because consuming was taking too long', increase this value to\n  ## longer than the time taken by the output plugin(s).\n  ##\n  ## Note that the effective timeout could be between 'max_processing_time' and\n  ## '2 * max_processing_time'.\n  # max_processing_time = \"100ms\"\n\n  ## The default number of message bytes to fetch from the broker in each\n  ## request (default 1MB). This should be larger than the majority of\n  ## your messages, or else the consumer will spend a lot of time\n  ## negotiating sizes and not actually consuming. Similar to the JVM's\n  ## `fetch.message.max.bytes`.\n  # consumer_fetch_default = \"1MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n```\n\n## Metrics\n\nThe plugin accepts arbitrary input and parses it according to the `data_format`\nsetting. There is no predefined metric format.\n\n## Example Output\n\nThere is no predefined metric format, so output depends on plugin input.\n"
  },
  {
    "path": "plugins/inputs/kafka_consumer/kafka_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kafka_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBM/sarama\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/kafka\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\nconst (\n\tdefaultMaxUndeliveredMessages = 1000\n\tdefaultMaxProcessingTime      = config.Duration(100 * time.Millisecond)\n\tdefaultConsumerGroup          = \"telegraf_metrics_consumers\"\n\treconnectDelay                = 5 * time.Second\n)\n\ntype KafkaConsumer struct {\n\tBrokers                              []string        `toml:\"brokers\"`\n\tVersion                              string          `toml:\"kafka_version\"`\n\tConsumerGroup                        string          `toml:\"consumer_group\"`\n\tMaxMessageLen                        int             `toml:\"max_message_len\"`\n\tMaxUndeliveredMessages               int             `toml:\"max_undelivered_messages\"`\n\tMaxProcessingTime                    config.Duration `toml:\"max_processing_time\"`\n\tOffset                               string          `toml:\"offset\"`\n\tBalanceStrategy                      string          `toml:\"balance_strategy\"`\n\tTopics                               []string        `toml:\"topics\"`\n\tTopicRegexps                         []string        `toml:\"topic_regexps\"`\n\tTopicTag                             string          `toml:\"topic_tag\"`\n\tMsgHeadersAsTags                     []string        `toml:\"msg_headers_as_tags\"`\n\tMsgHeaderAsMetricName                string          `toml:\"msg_header_as_metric_name\"`\n\tTimestampSource                      string          `toml:\"timestamp_source\"`\n\tConsumerFetchDefault                 config.Size     `toml:\"consumer_fetch_default\"`\n\tConnectionStrategy                   string          `toml:\"connection_strategy\" deprecated:\"1.33.0;1.40.0;use 'startup_error_behavior' instead\"`\n\tResolveCanonicalBootstrapServersOnly bool            `toml:\"resolve_canonical_bootstrap_servers_only\"`\n\tLog                                  telegraf.Logger `toml:\"-\"`\n\tkafka.ReadConfig\n\n\tconsumerCreator consumerGroupCreator\n\tconsumer        consumerGroup\n\tconfig          *sarama.Config\n\n\ttopicClient     sarama.Client\n\tregexps         []regexp.Regexp\n\tallWantedTopics []string\n\tfingerprint     string\n\n\tparser    telegraf.Parser\n\ttopicLock sync.Mutex\n\twg        sync.WaitGroup\n\tcancel    context.CancelFunc\n}\n\n// consumerGroupHandler is a sarama.ConsumerGroupHandler implementation.\ntype consumerGroupHandler struct {\n\tmaxMessageLen         int\n\ttopicTag              string\n\tmsgHeadersToTags      map[string]bool\n\tmsgHeaderToMetricName string\n\ttimestampSource       string\n\n\tacc    telegraf.TrackingAccumulator\n\tsem    semaphore\n\tparser telegraf.Parser\n\twg     sync.WaitGroup\n\tcancel context.CancelFunc\n\n\tmu          sync.Mutex\n\tundelivered map[telegraf.TrackingID]message\n\n\tlog telegraf.Logger\n}\n\n// message is an aggregate type binding the Kafka message and the session so that offsets can be updated.\ntype message struct {\n\tmessage *sarama.ConsumerMessage\n\tsession sarama.ConsumerGroupSession\n}\n\ntype (\n\tempty     struct{}\n\tsemaphore chan empty\n)\n\ntype consumerGroup interface {\n\tConsume(ctx context.Context, topics []string, handler sarama.ConsumerGroupHandler) error\n\tErrors() <-chan error\n\tClose() error\n}\n\ntype consumerGroupCreator interface {\n\tcreate(brokers []string, group string, cfg *sarama.Config) (consumerGroup, error)\n}\n\ntype saramaCreator struct{}\n\nfunc (*saramaCreator) create(brokers []string, group string, cfg *sarama.Config) (consumerGroup, error) {\n\treturn sarama.NewConsumerGroup(brokers, group, cfg)\n}\n\nfunc (*KafkaConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *KafkaConsumer) Init() error {\n\tkafka.SetLogger(k.Log.Level())\n\n\tif k.MaxUndeliveredMessages == 0 {\n\t\tk.MaxUndeliveredMessages = defaultMaxUndeliveredMessages\n\t}\n\tif time.Duration(k.MaxProcessingTime) == 0 {\n\t\tk.MaxProcessingTime = defaultMaxProcessingTime\n\t}\n\tif k.ConsumerGroup == \"\" {\n\t\tk.ConsumerGroup = defaultConsumerGroup\n\t}\n\n\tswitch k.TimestampSource {\n\tcase \"\":\n\t\tk.TimestampSource = \"metric\"\n\tcase \"metric\", \"inner\", \"outer\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid timestamp source %q\", k.TimestampSource)\n\t}\n\n\tcfg := sarama.NewConfig()\n\n\t// Kafka version 0.10.2.0 is required for consumer groups.\n\t// Try to parse version from config. If can not, set default\n\tcfg.Version = sarama.V0_10_2_0\n\tif k.Version != \"\" {\n\t\tversion, err := sarama.ParseKafkaVersion(k.Version)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid version: %w\", err)\n\t\t}\n\t\tcfg.Version = version\n\t}\n\n\tif err := k.SetConfig(cfg, k.Log); err != nil {\n\t\treturn fmt.Errorf(\"setting config failed: %w\", err)\n\t}\n\n\tswitch strings.ToLower(k.Offset) {\n\tcase \"oldest\", \"\":\n\t\tcfg.Consumer.Offsets.Initial = sarama.OffsetOldest\n\tcase \"newest\":\n\t\tcfg.Consumer.Offsets.Initial = sarama.OffsetNewest\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid offset %q\", k.Offset)\n\t}\n\n\tswitch strings.ToLower(k.BalanceStrategy) {\n\tcase \"range\", \"\":\n\t\tcfg.Consumer.Group.Rebalance.GroupStrategies = []sarama.BalanceStrategy{sarama.NewBalanceStrategyRange()}\n\tcase \"roundrobin\":\n\t\tcfg.Consumer.Group.Rebalance.GroupStrategies = []sarama.BalanceStrategy{sarama.NewBalanceStrategyRoundRobin()}\n\tcase \"sticky\":\n\t\tcfg.Consumer.Group.Rebalance.GroupStrategies = []sarama.BalanceStrategy{sarama.NewBalanceStrategySticky()}\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid balance strategy %q\", k.BalanceStrategy)\n\t}\n\n\tif k.consumerCreator == nil {\n\t\tk.consumerCreator = &saramaCreator{}\n\t}\n\n\tcfg.Net.ResolveCanonicalBootstrapServers = k.ResolveCanonicalBootstrapServersOnly\n\n\tcfg.Consumer.MaxProcessingTime = time.Duration(k.MaxProcessingTime)\n\n\tif k.ConsumerFetchDefault != 0 {\n\t\tcfg.Consumer.Fetch.Default = int32(k.ConsumerFetchDefault)\n\t}\n\n\tswitch strings.ToLower(k.ConnectionStrategy) {\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid connection strategy %q\", k.ConnectionStrategy)\n\tcase \"defer\", \"startup\", \"\":\n\t}\n\n\tk.config = cfg\n\n\tif len(k.TopicRegexps) == 0 {\n\t\tk.allWantedTopics = k.Topics\n\t} else {\n\t\tif err := k.compileTopicRegexps(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// We have regexps, so we're going to need a client to ask\n\t\t// the broker for topics\n\t\tclient, err := sarama.NewClient(k.Brokers, k.config)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tk.topicClient = client\n\t}\n\n\treturn nil\n}\n\nfunc (k *KafkaConsumer) SetParser(parser telegraf.Parser) {\n\tk.parser = parser\n}\n\nfunc (k *KafkaConsumer) Start(acc telegraf.Accumulator) error {\n\tvar err error\n\n\t// If TopicRegexps is set, add matches to Topics\n\tif len(k.TopicRegexps) > 0 {\n\t\tif err := k.refreshTopics(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tk.cancel = cancel\n\n\tif k.ConnectionStrategy != \"defer\" {\n\t\terr = k.create()\n\t\tif err != nil {\n\t\t\treturn &internal.StartupError{\n\t\t\t\tErr:   fmt.Errorf(\"create consumer: %w\", err),\n\t\t\t\tRetry: errors.Is(err, sarama.ErrOutOfBrokers),\n\t\t\t}\n\t\t}\n\t\tk.startErrorAdder(acc)\n\t}\n\n\t// Start consumer goroutine\n\tk.wg.Add(1)\n\tgo func() {\n\t\tvar err error\n\t\tdefer k.wg.Done()\n\n\t\tif k.consumer == nil {\n\t\t\terr = k.create()\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"create consumer async: %w\", err))\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tk.startErrorAdder(acc)\n\n\t\tfor ctx.Err() == nil {\n\t\t\thandler := newConsumerGroupHandler(acc, k.MaxUndeliveredMessages, k.parser, k.Log)\n\t\t\thandler.maxMessageLen = k.MaxMessageLen\n\t\t\thandler.topicTag = k.TopicTag\n\t\t\thandler.msgHeaderToMetricName = k.MsgHeaderAsMetricName\n\t\t\t// if message headers list specified, put it as map to handler\n\t\t\tmsgHeadersMap := make(map[string]bool, len(k.MsgHeadersAsTags))\n\t\t\tif len(k.MsgHeadersAsTags) > 0 {\n\t\t\t\tfor _, header := range k.MsgHeadersAsTags {\n\t\t\t\t\tif k.MsgHeaderAsMetricName != header {\n\t\t\t\t\t\tmsgHeadersMap[header] = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\thandler.msgHeadersToTags = msgHeadersMap\n\t\t\thandler.timestampSource = k.TimestampSource\n\n\t\t\t// We need to copy allWantedTopics; the Consume() is\n\t\t\t// long-running and we can easily deadlock if our\n\t\t\t// topic-update-checker fires.\n\t\t\ttopics := make([]string, len(k.allWantedTopics))\n\t\t\tk.topicLock.Lock()\n\t\t\tcopy(topics, k.allWantedTopics)\n\t\t\tk.topicLock.Unlock()\n\t\t\terr := k.consumer.Consume(ctx, topics, handler)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"consume: %w\", err))\n\t\t\t\tinternal.SleepContext(ctx, reconnectDelay) //nolint:errcheck // ignore returned error as we cannot do anything about it anyway\n\t\t\t}\n\t\t}\n\t\terr = k.consumer.Close()\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"close: %w\", err))\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (*KafkaConsumer) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (k *KafkaConsumer) Stop() {\n\t// Lock so that a topic refresh cannot start while we are stopping.\n\tk.topicLock.Lock()\n\tif k.topicClient != nil {\n\t\tk.topicClient.Close()\n\t}\n\tk.topicLock.Unlock()\n\n\tk.cancel()\n\tk.wg.Wait()\n}\n\nfunc (k *KafkaConsumer) compileTopicRegexps() error {\n\t// While we can add new topics matching extant regexps, we can't\n\t// update that list on the fly.  We compile them once at startup.\n\t// Changing them is a configuration change and requires a restart.\n\n\tk.regexps = make([]regexp.Regexp, 0, len(k.TopicRegexps))\n\tfor _, r := range k.TopicRegexps {\n\t\tre, err := regexp.Compile(r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"regular expression %q did not compile: '%w\", r, err)\n\t\t}\n\t\tk.regexps = append(k.regexps, *re)\n\t}\n\treturn nil\n}\n\nfunc (k *KafkaConsumer) refreshTopics() error {\n\t// We have instantiated a new generic Kafka client, so we can ask\n\t// it for all the topics it knows about.  Then we build\n\t// regexps from our strings, loop over those, loop over the\n\t// topics, and if we find a match, add that topic to\n\t// out topic set, which then we turn back into a list at the end.\n\n\tif len(k.regexps) == 0 {\n\t\treturn nil\n\t}\n\n\tallDiscoveredTopics, err := k.topicClient.Topics()\n\tif err != nil {\n\t\treturn err\n\t}\n\tk.Log.Debugf(\"discovered topics: %v\", allDiscoveredTopics)\n\n\textantTopicSet := make(map[string]bool, len(allDiscoveredTopics))\n\tfor _, t := range allDiscoveredTopics {\n\t\textantTopicSet[t] = true\n\t}\n\t// Even if a topic specified by a literal string (that is, k.Topics)\n\t// does not appear in the topic list, we want to keep it around, in\n\t// case it pops back up--it is not guaranteed to be matched by any\n\t// of our regular expressions.  Therefore, we pretend that it's in\n\t// extantTopicSet, even if it isn't.\n\t//\n\t// Assuming that literally-specified topics are usually in the topics\n\t// present on the broker, this should not need a resizing (although if\n\t// you have many topics that you don't care about, it will be too big)\n\twantedTopicSet := make(map[string]bool, len(allDiscoveredTopics))\n\tfor _, t := range k.Topics {\n\t\t// Get our pre-specified topics\n\t\tk.Log.Debugf(\"adding literally-specified topic %s\", t)\n\t\twantedTopicSet[t] = true\n\t}\n\tfor _, t := range allDiscoveredTopics {\n\t\t// Add topics that match regexps\n\t\tfor _, r := range k.regexps {\n\t\t\tif r.MatchString(t) {\n\t\t\t\twantedTopicSet[t] = true\n\t\t\t\tk.Log.Debugf(\"adding regexp-matched topic %q\", t)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\ttopicList := make([]string, 0, len(wantedTopicSet))\n\tfor t := range wantedTopicSet {\n\t\ttopicList = append(topicList, t)\n\t}\n\tsort.Strings(topicList)\n\tfingerprint := strings.Join(topicList, \";\")\n\tif fingerprint != k.fingerprint {\n\t\tk.Log.Infof(\"updating topics: replacing %q with %q\", k.allWantedTopics, topicList)\n\t}\n\tk.topicLock.Lock()\n\tk.fingerprint = fingerprint\n\tk.allWantedTopics = topicList\n\tk.topicLock.Unlock()\n\treturn nil\n}\n\nfunc (k *KafkaConsumer) create() error {\n\tvar err error\n\tk.consumer, err = k.consumerCreator.create(\n\t\tk.Brokers,\n\t\tk.ConsumerGroup,\n\t\tk.config,\n\t)\n\n\treturn err\n}\n\nfunc (k *KafkaConsumer) startErrorAdder(acc telegraf.Accumulator) {\n\tk.wg.Add(1)\n\tgo func() {\n\t\tdefer k.wg.Done()\n\t\tfor err := range k.consumer.Errors() {\n\t\t\tacc.AddError(fmt.Errorf(\"channel: %w\", err))\n\t\t}\n\t}()\n}\n\nfunc newConsumerGroupHandler(acc telegraf.Accumulator, maxUndelivered int, parser telegraf.Parser, log telegraf.Logger) *consumerGroupHandler {\n\thandler := &consumerGroupHandler{\n\t\tacc:         acc.WithTracking(maxUndelivered),\n\t\tsem:         make(chan empty, maxUndelivered),\n\t\tundelivered: make(map[telegraf.TrackingID]message, maxUndelivered),\n\t\tparser:      parser,\n\t\tlog:         log,\n\t}\n\treturn handler\n}\n\n// Setup is called once when a new session is opened. It setups up the handler and begins processing delivered messages.\nfunc (h *consumerGroupHandler) Setup(sarama.ConsumerGroupSession) error {\n\th.undelivered = make(map[telegraf.TrackingID]message)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\th.cancel = cancel\n\n\th.wg.Add(1)\n\tgo func() {\n\t\tdefer h.wg.Done()\n\t\th.run(ctx)\n\t}()\n\treturn nil\n}\n\n// ConsumeClaim is called once each claim in a goroutine and must be thread-safe. Should run until the claim is closed.\nfunc (h *consumerGroupHandler) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {\n\tctx := session.Context()\n\n\tfor {\n\t\terr := h.reserve(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase msg, ok := <-claim.Messages():\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\terr := h.handle(session, msg)\n\t\t\tif err != nil {\n\t\t\t\th.acc.AddError(err)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Cleanup stops the internal goroutine and is called after all ConsumeClaim functions have completed.\nfunc (h *consumerGroupHandler) Cleanup(sarama.ConsumerGroupSession) error {\n\th.cancel()\n\th.wg.Wait()\n\treturn nil\n}\n\n// Run processes any delivered metrics during the lifetime of the session.\nfunc (h *consumerGroupHandler) run(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase track := <-h.acc.Delivered():\n\t\t\th.onDelivery(track)\n\t\t}\n\t}\n}\n\nfunc (h *consumerGroupHandler) onDelivery(track telegraf.DeliveryInfo) {\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\tmsg, ok := h.undelivered[track.ID()]\n\tif !ok {\n\t\th.log.Errorf(\"Could not mark message delivered: %d\", track.ID())\n\t\treturn\n\t}\n\n\tif track.Delivered() {\n\t\tmsg.session.MarkMessage(msg.message, \"\")\n\t}\n\n\tdelete(h.undelivered, track.ID())\n\t<-h.sem\n}\n\n// reserve blocks until there is an available slot for a new message.\nfunc (h *consumerGroupHandler) reserve(ctx context.Context) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase h.sem <- empty{}:\n\t\treturn nil\n\t}\n}\n\nfunc (h *consumerGroupHandler) release() {\n\t<-h.sem\n}\n\n// handle processes a message and if successful saves it to be acknowledged after delivery.\nfunc (h *consumerGroupHandler) handle(session sarama.ConsumerGroupSession, msg *sarama.ConsumerMessage) error {\n\tif h.maxMessageLen != 0 && len(msg.Value) > h.maxMessageLen {\n\t\tsession.MarkMessage(msg, \"\")\n\t\th.release()\n\t\treturn fmt.Errorf(\"message exceeds max_message_len (actual %d, max %d)\",\n\t\t\tlen(msg.Value), h.maxMessageLen)\n\t}\n\n\tmetrics, err := h.parser.Parse(msg.Value)\n\tif err != nil {\n\t\tsession.MarkMessage(msg, \"\")\n\t\th.release()\n\t\treturn err\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\th.log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\t// Check if any message header should override metric name or should be pass as tag\n\tif len(h.msgHeadersToTags) > 0 || h.msgHeaderToMetricName != \"\" {\n\t\tfor _, header := range msg.Headers {\n\t\t\t// convert to a string as the header and value are byte arrays.\n\t\t\theaderKey := string(header.Key)\n\t\t\tif _, exists := h.msgHeadersToTags[headerKey]; exists {\n\t\t\t\t// If message header should be pass as tag then add it to the metrics\n\t\t\t\tfor _, metric := range metrics {\n\t\t\t\t\tmetric.AddTag(headerKey, string(header.Value))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif h.msgHeaderToMetricName == headerKey {\n\t\t\t\t\tfor _, metric := range metrics {\n\t\t\t\t\t\tmetric.SetName(string(header.Value))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add topic name as tag with topicTag name specified in the config\n\tif len(h.topicTag) > 0 {\n\t\tfor _, metric := range metrics {\n\t\t\tmetric.AddTag(h.topicTag, msg.Topic)\n\t\t}\n\t}\n\n\t// Do override the metric timestamp if required\n\tswitch h.timestampSource {\n\tcase \"inner\":\n\t\tfor _, metric := range metrics {\n\t\t\tmetric.SetTime(msg.Timestamp)\n\t\t}\n\tcase \"outer\":\n\t\tfor _, metric := range metrics {\n\t\t\tmetric.SetTime(msg.BlockTimestamp)\n\t\t}\n\t}\n\n\th.mu.Lock()\n\tid := h.acc.AddTrackingMetricGroup(metrics)\n\th.undelivered[id] = message{session: session, message: msg}\n\th.mu.Unlock()\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"kafka_consumer\", func() telegraf.Input {\n\t\treturn &KafkaConsumer{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kafka_consumer/kafka_consumer_test.go",
    "content": "package kafka_consumer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBM/sarama\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go\"\n\tkafkacontainer \"github.com/testcontainers/testcontainers-go/modules/kafka\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/common/kafka\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/outputs\"\n\toutputs_kafka \"github.com/influxdata/telegraf/plugins/outputs/kafka\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/value\"\n\tserializers_influx \"github.com/influxdata/telegraf/plugins/serializers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype fakeConsumerGroup struct {\n\tbrokers []string\n\tgroup   string\n\tconfig  *sarama.Config\n\n\thandler sarama.ConsumerGroupHandler\n\terrors  chan error\n}\n\nfunc (g *fakeConsumerGroup) Consume(_ context.Context, _ []string, handler sarama.ConsumerGroupHandler) error {\n\tg.handler = handler\n\treturn g.handler.Setup(nil)\n}\n\nfunc (g *fakeConsumerGroup) Errors() <-chan error {\n\treturn g.errors\n}\n\nfunc (g *fakeConsumerGroup) Close() error {\n\tclose(g.errors)\n\treturn nil\n}\n\ntype fakeCreator struct {\n\tconsumerGroup *fakeConsumerGroup\n}\n\nfunc (c *fakeCreator) create(brokers []string, group string, cfg *sarama.Config) (consumerGroup, error) {\n\tc.consumerGroup.brokers = brokers\n\tc.consumerGroup.group = group\n\tc.consumerGroup.config = cfg\n\treturn c.consumerGroup, nil\n}\n\nfunc TestInit(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tplugin    *KafkaConsumer\n\t\tinitError bool\n\t\tcheck     func(t *testing.T, plugin *KafkaConsumer)\n\t}{\n\t\t{\n\t\t\tname:   \"default config\",\n\t\t\tplugin: &KafkaConsumer{Log: testutil.Logger{}},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.Equal(t, defaultConsumerGroup, plugin.ConsumerGroup)\n\t\t\t\trequire.Equal(t, defaultMaxUndeliveredMessages, plugin.MaxUndeliveredMessages)\n\t\t\t\trequire.Equal(t, \"Telegraf\", plugin.config.ClientID)\n\t\t\t\trequire.Equal(t, sarama.OffsetOldest, plugin.config.Consumer.Offsets.Initial)\n\t\t\t\trequire.Equal(t, 100*time.Millisecond, plugin.config.Consumer.MaxProcessingTime)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"parses valid version string\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tVersion: \"1.0.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.Equal(t, plugin.config.Version, sarama.V1_0_0_0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid version string\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tVersion: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tinitError: true,\n\t\t},\n\t\t{\n\t\t\tname: \"custom client_id\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tClientID: \"custom\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.Equal(t, \"custom\", plugin.config.ClientID)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"custom offset\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tOffset: \"newest\",\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.Equal(t, sarama.OffsetNewest, plugin.config.Consumer.Offsets.Initial)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid offset\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tOffset: \"middle\",\n\t\t\t\tLog:    testutil.Logger{},\n\t\t\t},\n\t\t\tinitError: true,\n\t\t},\n\t\t{\n\t\t\tname: \"default tls without tls config\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.False(t, plugin.config.Net.TLS.Enable)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"enabled tls without tls config\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tEnableTLS: func(b bool) *bool { return &b }(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.True(t, plugin.config.Net.TLS.Enable)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"default tls with a tls config\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tClientConfig: tls.ClientConfig{\n\t\t\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.True(t, plugin.config.Net.TLS.Enable)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Insecure tls\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tReadConfig: kafka.ReadConfig{\n\t\t\t\t\tConfig: kafka.Config{\n\t\t\t\t\t\tClientConfig: tls.ClientConfig{\n\t\t\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tLog: testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.True(t, plugin.config.Net.TLS.Enable)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"custom max_processing_time\",\n\t\t\tplugin: &KafkaConsumer{\n\t\t\t\tMaxProcessingTime: config.Duration(1000 * time.Millisecond),\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, plugin *KafkaConsumer) {\n\t\t\t\trequire.Equal(t, 1000*time.Millisecond, plugin.config.Consumer.MaxProcessingTime)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tcg := &fakeConsumerGroup{}\n\t\t\ttt.plugin.consumerCreator = &fakeCreator{consumerGroup: cg}\n\t\t\terr := tt.plugin.Init()\n\t\t\tif tt.initError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// No error path\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttt.check(t, tt.plugin)\n\t\t})\n\t}\n}\n\nfunc TestStartStop(t *testing.T) {\n\tcg := &fakeConsumerGroup{errors: make(chan error)}\n\tplugin := &KafkaConsumer{\n\t\tconsumerCreator: &fakeCreator{consumerGroup: cg},\n\t\tLog:             testutil.Logger{},\n\t}\n\terr := plugin.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tplugin.Stop()\n}\n\ntype FakeConsumerGroupSession struct {\n\tctx context.Context\n}\n\nfunc (*FakeConsumerGroupSession) Claims() map[string][]int32 {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupSession) MemberID() string {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupSession) GenerationID() int32 {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupSession) MarkOffset(string, int32, int64, string) {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupSession) ResetOffset(string, int32, int64, string) {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupSession) MarkMessage(*sarama.ConsumerMessage, string) {\n}\n\nfunc (s *FakeConsumerGroupSession) Context() context.Context {\n\treturn s.ctx\n}\n\nfunc (*FakeConsumerGroupSession) Commit() {\n}\n\ntype FakeConsumerGroupClaim struct {\n\tmessages chan *sarama.ConsumerMessage\n}\n\nfunc (*FakeConsumerGroupClaim) Topic() string {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupClaim) Partition() int32 {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupClaim) InitialOffset() int64 {\n\tpanic(\"not implemented\")\n}\n\nfunc (*FakeConsumerGroupClaim) HighWaterMarkOffset() int64 {\n\tpanic(\"not implemented\")\n}\n\nfunc (c *FakeConsumerGroupClaim) Messages() <-chan *sarama.ConsumerMessage {\n\treturn c.messages\n}\n\nfunc TestConsumerGroupHandlerLifecycle(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\n\tparser := value.Parser{\n\t\tMetricName: \"cpu\",\n\t\tDataType:   \"int\",\n\t}\n\tcg := newConsumerGroupHandler(acc, 1, &parser, testutil.Logger{})\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\tsession := &FakeConsumerGroupSession{\n\t\tctx: ctx,\n\t}\n\tvar claim FakeConsumerGroupClaim\n\tvar err error\n\n\terr = cg.Setup(session)\n\trequire.NoError(t, err)\n\n\tcancel()\n\t// This produces a flappy testcase probably due to a race between context cancellation and consumption.\n\t// Furthermore, it is not clear what the outcome of this test should be...\n\t// err = cg.ConsumeClaim(session, &claim)\n\t// require.NoError(t, err)\n\t// So stick with the line below for now.\n\t//nolint:errcheck // see above\n\tcg.ConsumeClaim(session, &claim)\n\n\terr = cg.Cleanup(session)\n\trequire.NoError(t, err)\n}\n\nfunc TestConsumerGroupHandlerConsumeClaim(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tparser := value.Parser{\n\t\tMetricName: \"cpu\",\n\t\tDataType:   \"int\",\n\t}\n\trequire.NoError(t, parser.Init())\n\tcg := newConsumerGroupHandler(acc, 1, &parser, testutil.Logger{})\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\tsession := &FakeConsumerGroupSession{ctx: ctx}\n\tclaim := &FakeConsumerGroupClaim{\n\t\tmessages: make(chan *sarama.ConsumerMessage, 1),\n\t}\n\n\terr := cg.Setup(session)\n\trequire.NoError(t, err)\n\n\tclaim.messages <- &sarama.ConsumerMessage{\n\t\tTopic: \"telegraf\",\n\t\tValue: []byte(\"42\"),\n\t}\n\n\tgo func() {\n\t\terr := cg.ConsumeClaim(session, claim)\n\t\tif err == nil {\n\t\t\tt.Error(\"An error was expected.\")\n\t\t\treturn\n\t\t}\n\t\tif err.Error() != \"context canceled\" {\n\t\t\tt.Errorf(\"Expected 'context canceled' error, got: %v\", err)\n\t\t\treturn\n\t\t}\n\t}()\n\n\tacc.Wait(1)\n\tcancel()\n\n\terr = cg.Cleanup(session)\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"cpu\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\": 42,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestConsumerGroupHandlerHandle(t *testing.T) {\n\ttests := []struct {\n\t\tname                string\n\t\tmaxMessageLen       int\n\t\ttopicTag            string\n\t\tmsg                 *sarama.ConsumerMessage\n\t\texpected            []telegraf.Metric\n\t\texpectedHandleError string\n\t}{\n\t\t{\n\t\t\tname: \"happy path\",\n\t\t\tmsg: &sarama.ConsumerMessage{\n\t\t\t\tTopic: \"telegraf\",\n\t\t\t\tValue: []byte(\"42\"),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Now(),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"message to long\",\n\t\t\tmaxMessageLen: 4,\n\t\t\tmsg: &sarama.ConsumerMessage{\n\t\t\t\tTopic: \"telegraf\",\n\t\t\t\tValue: []byte(\"12345\"),\n\t\t\t},\n\t\t\texpectedHandleError: \"message exceeds max_message_len (actual 5, max 4)\",\n\t\t},\n\t\t{\n\t\t\tname: \"parse error\",\n\t\t\tmsg: &sarama.ConsumerMessage{\n\t\t\t\tTopic: \"telegraf\",\n\t\t\t\tValue: []byte(\"not an integer\"),\n\t\t\t},\n\t\t\texpectedHandleError: \"strconv.Atoi: parsing \\\"integer\\\": invalid syntax\",\n\t\t},\n\t\t{\n\t\t\tname:     \"add topic tag\",\n\t\t\ttopicTag: \"topic\",\n\t\t\tmsg: &sarama.ConsumerMessage{\n\t\t\t\tTopic: \"telegraf\",\n\t\t\t\tValue: []byte(\"42\"),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"topic\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Now(),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tacc := &testutil.Accumulator{}\n\t\t\tparser := value.Parser{\n\t\t\t\tMetricName: \"cpu\",\n\t\t\t\tDataType:   \"int\",\n\t\t\t}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tcg := newConsumerGroupHandler(acc, 1, &parser, testutil.Logger{})\n\t\t\tcg.maxMessageLen = tt.maxMessageLen\n\t\t\tcg.topicTag = tt.topicTag\n\n\t\t\tsession := &FakeConsumerGroupSession{ctx: t.Context()}\n\n\t\t\trequire.NoError(t, cg.reserve(t.Context()))\n\t\t\terr := cg.handle(session, tt.msg)\n\t\t\tif tt.expectedHandleError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.EqualValues(t, tt.expectedHandleError, err.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestExponentialBackoff(t *testing.T) {\n\tvar err error\n\n\tbackoff := 10 * time.Millisecond\n\tlimit := 3\n\n\t// get an unused port by listening on next available port, then closing it\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\tport := listener.Addr().(*net.TCPAddr).Port\n\trequire.NoError(t, listener.Close())\n\n\t// try to connect to kafka on that unused port\n\tbrokers := []string{\n\t\tfmt.Sprintf(\"localhost:%d\", port),\n\t}\n\n\tinput := KafkaConsumer{\n\t\tBrokers:                brokers,\n\t\tLog:                    testutil.Logger{},\n\t\tTopics:                 []string{\"topic\"},\n\t\tMaxUndeliveredMessages: 1,\n\n\t\tReadConfig: kafka.ReadConfig{\n\t\t\tConfig: kafka.Config{\n\t\t\t\tMetadataRetryMax:     limit,\n\t\t\t\tMetadataRetryBackoff: config.Duration(backoff),\n\t\t\t\tMetadataRetryType:    \"exponential\",\n\t\t\t},\n\t\t},\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tinput.SetParser(parser)\n\n\t// time how long initialization (connection) takes\n\tstart := time.Now()\n\trequire.NoError(t, input.Init())\n\n\tacc := testutil.Accumulator{}\n\trequire.Error(t, input.Start(&acc))\n\telapsed := time.Since(start)\n\tt.Logf(\"elapsed %d\", elapsed)\n\n\tvar expectedRetryDuration time.Duration\n\tfor i := 0; i < limit; i++ {\n\t\texpectedRetryDuration += backoff * time.Duration(math.Pow(2, float64(i)))\n\t}\n\tt.Logf(\"expected > %d\", expectedRetryDuration)\n\n\t// Other than the expected retry delay, initializing and starting the\n\t// plugin, including initializing a sarama consumer takes some time.\n\t//\n\t// It would be nice to check that the actual time is within an expected\n\t// range, but we don't know how long the non-retry time should be.\n\t//\n\t// For now, just check that elapsed time isn't shorter than we expect the\n\t// retry delays to be\n\trequire.GreaterOrEqual(t, elapsed, expectedRetryDuration)\n\n\tinput.Stop()\n}\n\nfunc TestExponentialBackoffDefault(t *testing.T) {\n\tinput := KafkaConsumer{\n\t\tBrokers:                []string{\"broker\"},\n\t\tLog:                    testutil.Logger{},\n\t\tTopics:                 []string{\"topic\"},\n\t\tMaxUndeliveredMessages: 1,\n\n\t\tReadConfig: kafka.ReadConfig{\n\t\t\tConfig: kafka.Config{\n\t\t\t\tMetadataRetryType: \"exponential\",\n\t\t\t},\n\t\t},\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tinput.SetParser(parser)\n\trequire.NoError(t, input.Init())\n\n\t// We don't need to start the plugin here since we're only testing\n\t// initialization\n\n\t// if input.MetadataRetryBackoff isn't set, it should be 250 ms\n\trequire.Equal(t, input.MetadataRetryBackoff, config.Duration(250*time.Millisecond))\n}\n\nfunc TestKafkaRoundTripIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tvar tests = []struct {\n\t\tname                 string\n\t\tconnectionStrategy   string\n\t\ttopics               []string\n\t\ttopicRegexps         []string\n\t\ttopicRefreshInterval config.Duration\n\t}{\n\t\t{\"connection strategy startup\", \"startup\", []string{\"Test\"}, nil, config.Duration(0)},\n\t\t{\"connection strategy defer\", \"defer\", []string{\"Test\"}, nil, config.Duration(0)},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tkafkaContainer, err := kafkacontainer.Run(t.Context(), \"confluentinc/confluent-local:7.5.0\")\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer kafkaContainer.Terminate(t.Context()) //nolint:errcheck // ignored\n\n\t\t\tbrokers, err := kafkaContainer.Brokers(t.Context())\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Make kafka output\n\t\t\tt.Logf(\"rt: starting output plugin\")\n\t\t\tcreator := outputs.Outputs[\"kafka\"]\n\t\t\toutput, ok := creator().(*outputs_kafka.Kafka)\n\t\t\trequire.True(t, ok)\n\n\t\t\ts := &serializers_influx.Serializer{}\n\t\t\trequire.NoError(t, s.Init())\n\t\t\toutput.SetSerializer(s)\n\t\t\toutput.Brokers = brokers\n\t\t\toutput.Topic = \"Test\"\n\t\t\toutput.Log = testutil.Logger{}\n\n\t\t\trequire.NoError(t, output.Init())\n\t\t\trequire.NoError(t, output.Connect())\n\n\t\t\t// Make kafka input\n\t\t\tt.Logf(\"rt: starting input plugin\")\n\t\t\tinput := KafkaConsumer{\n\t\t\t\tBrokers:                brokers,\n\t\t\t\tLog:                    testutil.Logger{},\n\t\t\t\tTopics:                 tt.topics,\n\t\t\t\tTopicRegexps:           tt.topicRegexps,\n\t\t\t\tMaxUndeliveredMessages: 1,\n\t\t\t\tConnectionStrategy:     tt.connectionStrategy,\n\t\t\t}\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tinput.SetParser(parser)\n\t\t\trequire.NoError(t, input.Init())\n\n\t\t\tacc := testutil.Accumulator{}\n\t\t\trequire.NoError(t, input.Start(&acc))\n\n\t\t\t// Shove some metrics through\n\t\t\texpected := testutil.MockMetrics()\n\t\t\tt.Logf(\"rt: writing\")\n\t\t\trequire.NoError(t, output.Write(expected))\n\n\t\t\t// Check that they were received\n\t\t\tt.Logf(\"rt: expecting\")\n\t\t\tacc.Wait(len(expected))\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n\n\t\t\tt.Logf(\"rt: shutdown\")\n\t\t\trequire.NoError(t, output.Close())\n\t\t\tinput.Stop()\n\n\t\t\tt.Logf(\"rt: done\")\n\t\t})\n\t}\n}\n\nfunc TestKafkaTimestampSourceIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tmetrics := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": 42},\n\t\t\ttime.Unix(1704067200, 0),\n\t\t),\n\t}\n\n\tfor _, source := range []string{\"metric\", \"inner\", \"outer\"} {\n\t\tt.Run(source, func(t *testing.T) {\n\t\t\tkafkaContainer, err := kafkacontainer.Run(t.Context(), \"confluentinc/confluent-local:7.5.0\")\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer kafkaContainer.Terminate(t.Context()) //nolint:errcheck // ignored\n\n\t\t\tbrokers, err := kafkaContainer.Brokers(t.Context())\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Make kafka output\n\t\t\tcreator := outputs.Outputs[\"kafka\"]\n\t\t\toutput, ok := creator().(*outputs_kafka.Kafka)\n\t\t\trequire.True(t, ok)\n\n\t\t\ts := &serializers_influx.Serializer{}\n\t\t\trequire.NoError(t, s.Init())\n\t\t\toutput.SetSerializer(s)\n\t\t\toutput.Brokers = brokers\n\t\t\toutput.Topic = \"Test\"\n\t\t\toutput.Log = &testutil.Logger{}\n\n\t\t\trequire.NoError(t, output.Init())\n\t\t\trequire.NoError(t, output.Connect())\n\t\t\tdefer output.Close()\n\n\t\t\t// Make kafka input\n\t\t\tinput := KafkaConsumer{\n\t\t\t\tBrokers:                brokers,\n\t\t\t\tLog:                    testutil.Logger{},\n\t\t\t\tTopics:                 []string{\"Test\"},\n\t\t\t\tMaxUndeliveredMessages: 1,\n\t\t\t}\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tinput.SetParser(parser)\n\t\t\trequire.NoError(t, input.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, input.Start(&acc))\n\t\t\tdefer input.Stop()\n\n\t\t\t// Send the metrics and check that we got it back\n\t\t\tsendTimestamp := time.Now().Unix()\n\t\t\trequire.NoError(t, output.Write(metrics))\n\t\t\trequire.Eventually(t, func() bool { return acc.NMetrics() > 0 }, 5*time.Second, 100*time.Millisecond)\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, metrics, actual, testutil.IgnoreTime())\n\n\t\t\t// Check the timestamp\n\t\t\tm := actual[0]\n\t\t\tswitch source {\n\t\t\tcase \"metric\":\n\t\t\t\trequire.EqualValues(t, 1704067200, m.Time().Unix())\n\t\t\tcase \"inner\", \"outer\":\n\t\t\t\trequire.GreaterOrEqual(t, sendTimestamp, m.Time().Unix())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestStartupErrorBehaviorErrorIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tcontainer, err := kafkacontainer.Run(t.Context(), \"confluentinc/confluent-local:7.5.0\")\n\trequire.NoError(t, err)\n\tdefer container.Terminate(t.Context()) //nolint:errcheck // ignored\n\n\tbrokers, err := container.Brokers(t.Context())\n\trequire.NoError(t, err)\n\n\t// Pause the container for simulating connectivity issues\n\tcontainerID := container.GetContainerID()\n\tprovider, err := testcontainers.NewDockerProvider()\n\trequire.NoError(t, err)\n\trequire.NoError(t, provider.Client().ContainerPause(t.Context(), containerID))\n\t//nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\tdefer provider.Client().ContainerUnpause(t.Context(), containerID)\n\n\t// Setup the plugin and connect to the broker\n\tplugin := &KafkaConsumer{\n\t\tBrokers:                brokers,\n\t\tLog:                    testutil.Logger{},\n\t\tTopics:                 []string{\"test\"},\n\t\tMaxUndeliveredMessages: 1,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:  \"kafka_consumer\",\n\t\t\tAlias: \"error-test\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Speed up test\n\tplugin.config.Net.DialTimeout = 100 * time.Millisecond\n\tplugin.config.Net.WriteTimeout = 100 * time.Millisecond\n\tplugin.config.Net.ReadTimeout = 100 * time.Millisecond\n\n\t// Starting the plugin will fail with an error because the container is paused.\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, model.Start(&acc), \"client has run out of available brokers to talk to\")\n}\n\nfunc TestStartupErrorBehaviorIgnoreIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tcontainer, err := kafkacontainer.Run(t.Context(), \"confluentinc/confluent-local:7.5.0\")\n\trequire.NoError(t, err)\n\tdefer container.Terminate(t.Context()) //nolint:errcheck // ignored\n\n\tbrokers, err := container.Brokers(t.Context())\n\trequire.NoError(t, err)\n\n\t// Pause the container for simulating connectivity issues\n\tcontainerID := container.GetContainerID()\n\tprovider, err := testcontainers.NewDockerProvider()\n\trequire.NoError(t, err)\n\trequire.NoError(t, provider.Client().ContainerPause(t.Context(), containerID))\n\t//nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\tdefer provider.Client().ContainerUnpause(t.Context(), containerID)\n\n\t// Setup the plugin and connect to the broker\n\tplugin := &KafkaConsumer{\n\t\tBrokers:                brokers,\n\t\tLog:                    testutil.Logger{},\n\t\tTopics:                 []string{\"test\"},\n\t\tMaxUndeliveredMessages: 1,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"kafka_consumer\",\n\t\t\tAlias:                \"ignore-test\",\n\t\t\tStartupErrorBehavior: \"ignore\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Speed up test\n\tplugin.config.Net.DialTimeout = 100 * time.Millisecond\n\tplugin.config.Net.WriteTimeout = 100 * time.Millisecond\n\tplugin.config.Net.ReadTimeout = 100 * time.Millisecond\n\n\t// Starting the plugin will fail because the container is paused.\n\t// The model code should convert it to a fatal error for the agent to remove\n\t// the plugin.\n\tvar acc testutil.Accumulator\n\terr = model.Start(&acc)\n\trequire.ErrorContains(t, err, \"client has run out of available brokers to talk to\")\n\tvar fatalErr *internal.FatalError\n\trequire.ErrorAs(t, err, &fatalErr)\n}\n\nfunc TestStartupErrorBehaviorRetryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tcontainer, err := kafkacontainer.Run(t.Context(), \"confluentinc/confluent-local:7.5.0\")\n\trequire.NoError(t, err)\n\tdefer container.Terminate(t.Context()) //nolint:errcheck // ignored\n\n\tbrokers, err := container.Brokers(t.Context())\n\trequire.NoError(t, err)\n\n\t// Pause the container for simulating connectivity issues\n\tcontainerID := container.GetContainerID()\n\tprovider, err := testcontainers.NewDockerProvider()\n\trequire.NoError(t, err)\n\trequire.NoError(t, provider.Client().ContainerPause(t.Context(), containerID))\n\t//nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\tdefer provider.Client().ContainerUnpause(t.Context(), containerID)\n\n\t// Setup the plugin and connect to the broker\n\tplugin := &KafkaConsumer{\n\t\tBrokers:                brokers,\n\t\tLog:                    testutil.Logger{},\n\t\tTopics:                 []string{\"test\"},\n\t\tMaxUndeliveredMessages: 1,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"kafka_consumer\",\n\t\t\tAlias:                \"retry-test\",\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Speed up test\n\tplugin.config.Net.DialTimeout = 100 * time.Millisecond\n\tplugin.config.Net.WriteTimeout = 100 * time.Millisecond\n\tplugin.config.Net.ReadTimeout = 100 * time.Millisecond\n\n\t// Starting the plugin will not fail but should retry to connect in every gather cycle\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, model.Start(&acc))\n\trequire.EqualValues(t, 1, model.StartupErrors.Get())\n\n\t// There should be no metrics as the plugin is not fully started up yet\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n\trequire.Equal(t, int64(2), model.StartupErrors.Get())\n\n\t// Unpause the container, now writes should succeed\n\trequire.NoError(t, provider.Client().ContainerUnpause(t.Context(), containerID))\n\trequire.NoError(t, model.Gather(&acc))\n\tdefer model.Stop()\n\trequire.Equal(t, int64(2), model.StartupErrors.Get())\n\n\t// Setup a writer\n\tcreator := outputs.Outputs[\"kafka\"]\n\toutput, ok := creator().(*outputs_kafka.Kafka)\n\trequire.True(t, ok)\n\n\ts := &serializers_influx.Serializer{}\n\trequire.NoError(t, s.Init())\n\toutput.SetSerializer(s)\n\toutput.Brokers = brokers\n\toutput.Topic = \"test\"\n\toutput.Log = &testutil.Logger{}\n\n\trequire.NoError(t, output.Init())\n\trequire.NoError(t, output.Connect())\n\tdefer output.Close()\n\n\t// Send some data to the broker so we have something to receive\n\tmetrics := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": 42},\n\t\t\ttime.Unix(1704067200, 0),\n\t\t),\n\t}\n\trequire.NoError(t, output.Write(metrics))\n\n\t// Verify that the metrics were actually written\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= 1\n\t}, 3*time.Second, 100*time.Millisecond)\n\ttestutil.RequireMetricsEqual(t, metrics, acc.GetTelegrafMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/kafka_consumer/sample.conf",
    "content": "# Read metrics from Kafka topics\n[[inputs.kafka_consumer]]\n  ## Kafka brokers.\n  brokers = [\"localhost:9092\"]\n\n  ## Set the minimal supported Kafka version. Should be a string contains\n  ## 4 digits in case if it is 0 version and 3 digits for versions starting\n  ## from 1.0.0 separated by dot. This setting enables the use of new\n  ## Kafka features and APIs. Must be 0.10.2.0(used as default) or greater.\n  ## Please, check the list of supported versions at\n  ## https://pkg.go.dev/github.com/Shopify/sarama#SupportedVersions\n  ##   ex: kafka_version = \"2.6.0\"\n  ##   ex: kafka_version = \"0.10.2.0\"\n  # kafka_version = \"0.10.2.0\"\n\n  ## Topics to consume.\n  topics = [\"telegraf\"]\n\n  ## Topic regular expressions to consume. Matches will be added to topics.\n  ## Example: topic_regexps = [ \"*test\", \"metric[0-9A-z]*\" ]\n  # topic_regexps = [ ]\n\n  ## When set this tag will be added to all metrics with the topic as the value.\n  # topic_tag = \"\"\n\n  ## The list of Kafka message headers that should be pass as metric tags\n  ## works only for Kafka version 0.11+, on lower versions the message headers\n  ## are not available\n  # msg_headers_as_tags = []\n\n  ## The name of kafka message header which value should override the metric name.\n  ## In case when the same header specified in current option and in msg_headers_as_tags\n  ## option, it will be excluded from the msg_headers_as_tags list.\n  # msg_header_as_metric_name = \"\"\n\n  ## Set metric(s) timestamp using the given source.\n  ## Available options are:\n  ##   metric -- do not modify the metric timestamp\n  ##   inner  -- use the inner message timestamp (Kafka v0.10+)\n  ##   outer  -- use the outer (compressed) block timestamp (Kafka v0.10+)\n  # timestamp_source = \"metric\"\n\n  ## Optional Client id\n  # client_id = \"Telegraf\"\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Period between keep alive probes.\n  ## Defaults to the OS configuration if not specified or zero.\n  # keep_alive_period = \"15s\"\n\n  ## SASL authentication credentials. These settings should typically be used\n  ## with TLS encryption enabled\n  # sasl_username = \"\"\n  # sasl_password = \"\"\n\n  ## Optional SASL, one of:\n  ##   OAUTHBEARER, PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, AWS-MSK-IAM\n  # sasl_mechanism = \"\"\n\n  ## used if sasl_mechanism is GSSAPI\n  # sasl_gssapi_service_name = \"\"\n  # ## One of: KRB5_USER_AUTH and KRB5_KEYTAB_AUTH\n  # sasl_gssapi_auth_type = \"KRB5_USER_AUTH\"\n  # sasl_gssapi_kerberos_config_path = \"/\"\n  # sasl_gssapi_realm = \"realm\"\n  # sasl_gssapi_key_tab_path = \"\"\n  # sasl_gssapi_disable_pafxfast = false\n\n  ## used if sasl_mechanism is OAUTHBEARER\n  # sasl_access_token = \"\"\n\n  ## used if sasl_mechanism is AWS-MSK-IAM\n  # sasl_aws_msk_iam_region = \"\"\n  ## for profile based auth\n  ## sasl_aws_msk_iam_profile = \"\"\n  ## for role based auth\n  ## sasl_aws_msk_iam_role = \"\"\n  ## sasl_aws_msk_iam_session = \"\"\n\n  ## Arbitrary key value string pairs to pass as a TOML table. For example:\n  ## {logicalCluster = \"cluster-042\", poolId = \"pool-027\"}\n  # sasl_extensions = {}\n\n  ## SASL protocol version. When connecting to Azure EventHub set to 0.\n  # sasl_version = 1\n\n  # Disable Kafka metadata full fetch\n  # metadata_full = false\n\n  ## Name of the consumer group.\n  # consumer_group = \"telegraf_metrics_consumers\"\n\n  ## Compression codec represents the various compression codecs recognized by\n  ## Kafka in messages.\n  ##  0 : None\n  ##  1 : Gzip\n  ##  2 : Snappy\n  ##  3 : LZ4\n  ##  4 : ZSTD\n  # compression_codec = 0\n  ## Initial offset position; one of \"oldest\" or \"newest\".\n  # offset = \"oldest\"\n\n  ## Consumer group partition assignment strategy; one of \"range\", \"roundrobin\" or \"sticky\".\n  # balance_strategy = \"range\"\n\n  ## Maximum number of retries for metadata operations including\n  ## connecting. Sets Sarama library's Metadata.Retry.Max config value. If 0 or\n  ## unset, use the Sarama default of 3,\n  # metadata_retry_max = 0\n\n  ## Type of retry backoff. Valid options: \"constant\", \"exponential\"\n  # metadata_retry_type = \"constant\"\n\n  ## Amount of time to wait before retrying. When metadata_retry_type is\n  ## \"constant\", each retry is delayed this amount. When \"exponential\", the\n  ## first retry is delayed this amount, and subsequent delays are doubled. If 0\n  ## or unset, use the Sarama default of 250 ms\n  # metadata_retry_backoff = 0\n\n  ## Maximum amount of time to wait before retrying when metadata_retry_type is\n  ## \"exponential\". Ignored for other retry types. If 0, there is no backoff\n  ## limit.\n  # metadata_retry_max_duration = 0\n\n  ## When set to true, this turns each bootstrap broker address into a set of\n  ## IPs, then does a reverse lookup on each one to get its canonical hostname.\n  ## This list of hostnames then replaces the original address list.\n  ## resolve_canonical_bootstrap_servers_only = false\n\n  ## Maximum length of a message to consume, in bytes (default 0/unlimited);\n  ## larger messages are dropped\n  max_message_len = 1000000\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Maximum amount of time the consumer should take to process messages. If\n  ## the debug log prints messages from sarama about 'abandoning subscription\n  ## to [topic] because consuming was taking too long', increase this value to\n  ## longer than the time taken by the output plugin(s).\n  ##\n  ## Note that the effective timeout could be between 'max_processing_time' and\n  ## '2 * max_processing_time'.\n  # max_processing_time = \"100ms\"\n\n  ## The default number of message bytes to fetch from the broker in each\n  ## request (default 1MB). This should be larger than the majority of\n  ## your messages, or else the consumer will spend a lot of time\n  ## negotiating sizes and not actually consuming. Similar to the JVM's\n  ## `fetch.message.max.bytes`.\n  # consumer_fetch_default = \"1MB\"\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/kapacitor/README.md",
    "content": "# Kapacitor Input Plugin\n\nThis plugin collects metrics from the configured\n[InfluxData Kapacitor][kapacitor] instances.\n\n⭐ Telegraf v1.3.0\n🏷️ applications\n💻 all\n\n[kapacitor]: https://www.influxdata.com/time-series-platform/kapacitor/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Kapacitor-formatted JSON metrics from one or more HTTP endpoints\n[[inputs.kapacitor]]\n  ## Multiple URLs from which to read Kapacitor-formatted JSON\n  ## Default is \"http://localhost:9092/kapacitor/v1/debug/vars\".\n  urls = [\n    \"http://localhost:9092/kapacitor/v1/debug/vars\"\n  ]\n\n  ## Time limit for http requests\n  timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n### Measurements and fields\n\n- [kapacitor](#kapacitor)\n  - [num_enabled_tasks](#num_enabled_tasks) _(integer)_\n  - [num_subscriptions](#num_subscriptions) _(integer)_\n  - [num_tasks](#num_tasks) _(integer)_\n- [kapacitor_alert](#kapacitor_alert)\n  - [notification_dropped](#notification-dropped) _(integer)_\n  - [primary-handle-count](#primary-handle-count) _(integer)_\n  - [secondary-handle-count](#secondary-handle-count) _(integer)_\n- (Kapacitor Enterprise only) [kapacitor_cluster](#kapacitor_cluster)\n  _(integer)_\n  - [dropped_member_events](#dropped_member_events) _(integer)_\n  - [dropped_user_events](#dropped_user_events) _(integer)_\n  - [query_handler_errors](#query_handler_errors) _(integer)_\n- [kapacitor_edges](#kapacitor_edges)\n  - [collected](#collected) _(integer)_\n  - [emitted](#emitted) _(integer)_\n- [kapacitor_ingress](#kapacitor_ingress)\n  - [points_received](#points_received) _(integer)_\n- [kapacitor_load](#kapacitor_load)\n  - [errors](#errors) _(integer)_\n- [kapacitor_memstats](#kapacitor_memstats)\n  - [alloc_bytes](#alloc_bytes) _(integer)_\n  - [buck_hash_sys_bytes](#buck_hash_sys_bytes) _(integer)_\n  - [frees](#frees) _(integer)_\n  - [gc_sys_bytes](#gc_sys_bytes) _(integer)_\n  - [gc_cpu_fraction](#gc_cpu_fraction) _(float)_\n  - [heap_alloc_bytes](#heap_alloc_bytes) _(integer)_\n  - [heap_idle_bytes](#heap_idle_bytes) _(integer)_\n  - [heap_in_use_bytes](#heap_in_use_bytes) _(integer)_\n  - [heap_objects](#heap_objects) _(integer)_\n  - [heap_released_bytes](#heap_released_bytes) _(integer)_\n  - [heap_sys_bytes](#heap_sys_bytes) _(integer)_\n  - [last_gc_ns](#last_gc_ns) _(integer)_\n  - [lookups](#lookups) _(integer)_\n  - [mallocs](#mallocs) _(integer)_\n  - [mcache_in_use_bytes](#mcache_in_use_bytes) _(integer)_\n  - [mcache_sys_bytes](#mcache_sys_bytes) _(integer)_\n  - [mspan_in_use_bytes](#mspan_in_use_bytes) _(integer)_\n  - [mspan_sys_bytes](#mspan_sys_bytes) _(integer)_\n  - [next_gc_ns](#next_gc_ns) _(integer)_\n  - [num_gc](#num_gc) _(integer)_\n  - [other_sys_bytes](#other_sys_bytes) _(integer)_\n  - [pause_total_ns](#pause_total_ns) _(integer)_\n  - [stack_in_use_bytes](#stack_in_use_bytes) _(integer)_\n  - [stack_sys_bytes](#stack_sys_bytes) _(integer)_\n  - [sys_bytes](#sys_bytes) _(integer)_\n  - [total_alloc_bytes](#total_alloc_bytes) _(integer)_\n- [kapacitor_nodes](#kapacitor_nodes)\n  - [alerts_inhibited](#alerts_inhibited) _(integer)_\n  - [alerts_triggered](#alerts_triggered) _(integer)_\n  - [avg_exec_time_ns](#avg_exec_time_ns) _(integer)_\n  - [crits_triggered](#crits_triggered) _(integer)_\n  - [errors](#errors) _(integer)_\n  - [infos_triggered](#infos_triggered) _(integer)_\n  - [oks_triggered](#oks_triggered) _(integer)_\n  - [points_written](#points_written) _(integer)_\n  - [warns_triggered](#warns_triggered) _(integer)_\n  - [write_errors](#write_errors) _(integer)_\n- [kapacitor_topics](#kapacitor_topics)\n  - [collected](#collected) _(integer)_\n\n---\n\n## kapacitor\n\nThe `kapacitor` measurement stores fields with information related to\n[Kapacitor tasks][tasks] and [subscriptions][subs].\n\n[tasks]: https://docs.influxdata.com/kapacitor/latest/introduction/getting-started/#kapacitor-tasks\n\n[subs]: https://docs.influxdata.com/kapacitor/latest/administration/subscription-management/\n\n### num_enabled_tasks\n\nThe number of enabled Kapacitor tasks.\n\n### num_subscriptions\n\nThe number of Kapacitor/InfluxDB subscriptions.\n\n### num_tasks\n\nThe total number of Kapacitor tasks.\n\n---\n\n## kapacitor_alert\n\nThe `kapacitor_alert` measurement stores fields with information related to\n[Kapacitor alerts](https://docs.influxdata.com/kapacitor/v1.5/working/alerts/).\n\n### notification-dropped\n\nThe number of internal notifications dropped because they arrive too late from\nanother Kapacitor node.  If this count is increasing, Kapacitor Enterprise nodes\naren't able to communicate fast enough to keep up with the volume of alerts.\n\n### primary-handle-count\n\nThe number of times this node handled an alert as the primary. This count should\nincrease under normal conditions.\n\n### secondary-handle-count\n\nThe number of times this node handled an alert as the secondary. An increase in\nthis counter indicates that the primary is failing to handle alerts in a timely\nmanner.\n\n---\n\n## kapacitor_cluster\n\nThe `kapacitor_cluster` measurement reflects the ability of [Kapacitor nodes to\ncommunicate][cluster] with one another. Specifically, these metrics track the\ngossip communication between the Kapacitor nodes.\n\n[cluster]: https://docs.influxdata.com/enterprise_kapacitor/v1.5/administration/configuration/#cluster-communications\n\n### dropped_member_events\n\nThe number of gossip member events that were dropped.\n\n### dropped_user_events\n\nThe number of gossip user events that were dropped.\n\n### query_handler_errors\n\nThe number of errors from event handlers.\n\n---\n\n## kapacitor_edges\n\nThe `kapacitor_edges` measurement stores fields with information related to\n[edges][] in Kapacitor TICKscripts.\n\n[edges]: https://docs.influxdata.com/kapacitor/latest/tick/introduction/#pipelines\n\n### collected\n\nThe number of messages collected by TICKscript edges.\n\n### emitted\n\nThe number of messages emitted by TICKscript edges.\n\n---\n\n## kapacitor_ingress\n\nThe `kapacitor_ingress` measurement stores fields with information related to\ndata coming into Kapacitor.\n\n### points_received\n\nThe number of points received by Kapacitor.\n\n---\n\n## kapacitor_load\n\nThe `kapacitor_load` measurement stores fields with information related to the\n[Kapacitor Load Directory service][load-dir].\n\n[load-dir]: https://docs.influxdata.com/kapacitor/latest/guides/load_directory/\n\n### errors\n\nThe number of errors reported from the load directory service.\n\n---\n\n## kapacitor_memstats\n\nThe `kapacitor_memstats` measurement stores fields related to Kapacitor memory\nusage.\n\n### alloc_bytes\n\nThe number of bytes of memory allocated by Kapacitor that are still in use.\n\n### buck_hash_sys_bytes\n\nThe number of bytes of memory used by the profiling bucket hash table.\n\n### frees\n\nThe number of heap objects freed.\n\n### gc_sys_bytes\n\nThe number of bytes of memory used for garbage collection system metadata.\n\n### gc_cpu_fraction\n\nThe fraction of Kapacitor's available CPU time used by garbage collection since\nKapacitor started.\n\n### heap_alloc_bytes\n\nThe number of reachable and unreachable heap objects garbage collection has\nnot freed.\n\n### heap_idle_bytes\n\nThe number of heap bytes waiting to be used.\n\n### heap_in_use_bytes\n\nThe number of heap bytes in use.\n\n### heap_objects\n\nThe number of allocated objects.\n\n### heap_released_bytes\n\nThe number of heap bytes released to the operating system.\n\n### heap_sys_bytes\n\nThe number of heap bytes obtained from `system`.\n\n### last_gc_ns\n\nThe nanosecond epoch time of the last garbage collection.\n\n### lookups\n\nThe total number of pointer lookups.\n\n### mallocs\n\nThe total number of mallocs.\n\n### mcache_in_use_bytes\n\nThe number of bytes in use by mcache structures.\n\n### mcache_sys_bytes\n\nThe number of bytes used for mcache structures obtained from `system`.\n\n### mspan_in_use_bytes\n\nThe number of bytes in use by mspan structures.\n\n### mspan_sys_bytes\n\nThe number of bytes used for mspan structures obtained from `system`.\n\n### next_gc_ns\n\nThe nanosecond epoch time of the next garbage collection.\n\n### num_gc\n\nThe number of completed garbage collection cycles.\n\n### other_sys_bytes\n\nThe number of bytes used for other system allocations.\n\n### pause_total_ns\n\nThe total number of nanoseconds spent in garbage collection \"stop-the-world\"\npauses since Kapacitor started.\n\n### stack_in_use_bytes\n\nThe number of bytes in use by the stack allocator.\n\n### stack_sys_bytes\n\nThe number of bytes obtained from `system` for stack allocator.\n\n### sys_bytes\n\nThe number of bytes of memory obtained from `system`.\n\n### total_alloc_bytes\n\nThe total number of bytes allocated, even if freed.\n\n---\n\n## kapacitor_nodes\n\nThe `kapacitor_nodes` measurement stores fields related to events that occur in\n[TICKscript nodes](https://docs.influxdata.com/kapacitor/latest/nodes/).\n\n### alerts_inhibited\n\nThe total number of alerts inhibited by TICKscripts.\n\n### alerts_triggered\n\nThe total number of alerts triggered by TICKscripts.\n\n### avg_exec_time_ns\n\nThe average execution time of TICKscripts in nanoseconds.\n\n### crits_triggered\n\nThe number of critical (`crit`) alerts triggered by TICKscripts.\n\n### errors (from TICKscripts)\n\nThe number of errors caused caused by TICKscripts.\n\n### infos_triggered\n\nThe number of info (`info`) alerts triggered by TICKscripts.\n\n### oks_triggered\n\nThe number of ok (`ok`) alerts triggered by TICKscripts.\n\n#### points_written\n\nThe number of points written to InfluxDB or back to Kapacitor.\n\n#### warns_triggered\n\nThe number of warning (`warn`) alerts triggered by TICKscripts.\n\n#### working_cardinality\n\nThe total number of unique series processed.\n\n#### write_errors\n\nThe number of errors that occurred when writing to InfluxDB or other write\nendpoints.\n\n---\n\n### kapacitor_topics\n\nThe `kapacitor_topics` measurement stores fields related to Kapacitor\ntopics][topics].\n\n[topics]: https://docs.influxdata.com/kapacitor/latest/working/using_alert_topics/\n\n#### collected (kapacitor_topics)\n\nThe number of events collected by Kapacitor topics.\n\n---\n\n__Note:__ The Kapacitor variables `host`, `cluster_id`, and `server_id`\nare currently not recorded due to the potential high cardinality of\nthese values.\n\n## Example Output\n\n```text\nkapacitor_memstats,host=hostname.local,kap_version=1.1.0~rc2,url=http://localhost:9092/kapacitor/v1/debug/vars alloc_bytes=6974808i,buck_hash_sys_bytes=1452609i,frees=207281i,gc_sys_bytes=802816i,gc_cpu_fraction=0.00004693548939673313,heap_alloc_bytes=6974808i,heap_idle_bytes=6742016i,heap_in_use_bytes=9183232i,heap_objects=23216i,heap_released_bytes=0i,heap_sys_bytes=15925248i,last_gc_ns=1478791460012676997i,lookups=88i,mallocs=230497i,mcache_in_use_bytes=9600i,mcache_sys_bytes=16384i,mspan_in_use_bytes=98560i,mspan_sys_bytes=131072i,next_gc_ns=11467528i,num_gc=8i,other_sys_bytes=2236087i,pause_total_ns=2994110i,stack_in_use_bytes=1900544i,stack_sys_bytes=1900544i,sys_bytes=22464760i,total_alloc_bytes=35023600i 1478791462000000000\nkapacitor,host=hostname.local,kap_version=1.1.0~rc2,url=http://localhost:9092/kapacitor/v1/debug/vars num_enabled_tasks=5i,num_subscriptions=5i,num_tasks=5i 1478791462000000000\nkapacitor_edges,child=stream0,host=hostname.local,parent=stream,task=deadman-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=shard,retention_policy=monitor,task_master=main points_received=120 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=subscriber,retention_policy=monitor,task_master=main points_received=60 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=http_out,node=http_out3,task=sys-stats,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=window6,host=hostname.local,parent=derivative5,task=deadman-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=from,node=from1,task=sys-stats,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=stream,node=stream0,task=test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=window,node=window6,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=cq,retention_policy=monitor,task_master=main points_received=10 1478791462000000000\nkapacitor_edges,child=http_out3,host=hostname.local,parent=window2,task=sys-stats,type=batch collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=mean4,host=hostname.local,parent=log3,task=deadman-test,type=batch collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_kapacitor,host=hostname.local,measurement=nodes,retention_policy=autogen,task_master=main points_received=207 1478791462000000000\nkapacitor_edges,child=stream0,host=hostname.local,parent=stream,task=sys-stats,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=log6,host=hostname.local,parent=sum5,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=from1,host=hostname.local,parent=stream0,task=sys-stats,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=alert,node=alert2,task=test,type=stream alerts_triggered=0,avg_exec_time_ns=0i,crits_triggered=0,infos_triggered=0,oks_triggered=0,warns_triggered=0 1478791462000000000\nkapacitor_edges,child=log3,host=hostname.local,parent=derivative2,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_kapacitor,host=hostname.local,measurement=runtime,retention_policy=autogen,task_master=main points_received=9 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=tsm1_filestore,retention_policy=monitor,task_master=main points_received=120 1478791462000000000\nkapacitor_edges,child=derivative2,host=hostname.local,parent=from1,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=stream,node=stream0,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=queryExecutor,retention_policy=monitor,task_master=main points_received=10 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=tsm1_wal,retention_policy=monitor,task_master=main points_received=120 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=log,node=log6,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=stream,host=hostname.local,parent=stats,task=task_master:main,type=stream collected=598,emitted=598 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=write,retention_policy=monitor,task_master=main points_received=10 1478791462000000000\nkapacitor_edges,child=stream0,host=hostname.local,parent=stream,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=log,node=log3,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=from,node=from1,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_kapacitor,host=hostname.local,measurement=ingress,retention_policy=autogen,task_master=main points_received=148 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=eval,node=eval4,task=derivative-test,type=stream avg_exec_time_ns=0i,eval_errors=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=derivative,node=derivative2,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=runtime,retention_policy=monitor,task_master=main points_received=10 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=httpd,retention_policy=monitor,task_master=main points_received=10 1478791462000000000\nkapacitor_edges,child=sum5,host=hostname.local,parent=eval4,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_kapacitor,host=hostname.local,measurement=kapacitor,retention_policy=autogen,task_master=main points_received=9 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=from,node=from1,task=test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=tsm1_engine,retention_policy=monitor,task_master=main points_received=120 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=window,node=window2,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=stream,node=stream0,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=influxdb_out4,host=hostname.local,parent=http_out3,task=sys-stats,type=batch collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=window2,host=hostname.local,parent=from1,task=deadman-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=from,node=from1,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=from1,host=hostname.local,parent=stream0,task=deadman-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=database,retention_policy=monitor,task_master=main points_received=40 1478791462000000000\nkapacitor_edges,child=stream,host=hostname.local,parent=write_points,task=task_master:main,type=stream collected=750,emitted=750 1478791462000000000\nkapacitor_edges,child=log7,host=hostname.local,parent=window6,task=deadman-test,type=batch collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=window2,host=hostname.local,parent=from1,task=sys-stats,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=log,node=log7,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_ingress,database=_kapacitor,host=hostname.local,measurement=edges,retention_policy=autogen,task_master=main points_received=225 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=derivative,node=derivative5,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=from1,host=hostname.local,parent=stream0,task=test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=alert2,host=hostname.local,parent=from1,task=test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=log,node=log3,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=influxdb_out,node=influxdb_out4,task=sys-stats,type=stream avg_exec_time_ns=0i,points_written=0,write_errors=0 1478791462000000000\nkapacitor_edges,child=stream0,host=hostname.local,parent=stream,task=test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=log3,host=hostname.local,parent=window2,task=deadman-test,type=batch collected=0,emitted=0 1478791462000000000\nkapacitor_edges,child=derivative5,host=hostname.local,parent=mean4,task=deadman-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=stream,node=stream0,task=sys-stats,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=window,node=window2,task=sys-stats,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=mean,node=mean4,task=deadman-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=from1,host=hostname.local,parent=stream0,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\nkapacitor_ingress,database=_internal,host=hostname.local,measurement=tsm1_cache,retention_policy=monitor,task_master=main points_received=120 1478791462000000000\nkapacitor_nodes,host=hostname.local,kind=sum,node=sum5,task=derivative-test,type=stream avg_exec_time_ns=0i 1478791462000000000\nkapacitor_edges,child=eval4,host=hostname.local,parent=log3,task=derivative-test,type=stream collected=0,emitted=0 1478791462000000000\n```\n"
  },
  {
    "path": "plugins/inputs/kapacitor/kapacitor.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kapacitor\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultURL = \"http://localhost:9092/kapacitor/v1/debug/vars\"\n)\n\ntype Kapacitor struct {\n\tURLs    []string        `toml:\"urls\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\ttls.ClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*Kapacitor) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *Kapacitor) Gather(acc telegraf.Accumulator) error {\n\tif k.client == nil {\n\t\tclient, err := k.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tk.client = client\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, u := range k.URLs {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := k.gatherURL(acc, url); err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"[url=%s]: %w\", url, err))\n\t\t\t}\n\t\t}(u)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (k *Kapacitor) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := k.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(k.Timeout),\n\t}\n\n\treturn client, nil\n}\n\ntype object struct {\n\tName   string                 `json:\"name\"`\n\tValues map[string]interface{} `json:\"values\"`\n\tTags   map[string]string      `json:\"tags\"`\n}\n\ntype memstats struct {\n\tAlloc         int64   `json:\"Alloc\"`\n\tTotalAlloc    int64   `json:\"TotalAlloc\"`\n\tSys           int64   `json:\"Sys\"`\n\tLookups       int64   `json:\"Lookups\"`\n\tMallocs       int64   `json:\"Mallocs\"`\n\tFrees         int64   `json:\"Frees\"`\n\tHeapAlloc     int64   `json:\"HeapAlloc\"`\n\tHeapSys       int64   `json:\"HeapSys\"`\n\tHeapIdle      int64   `json:\"HeapIdle\"`\n\tHeapInuse     int64   `json:\"HeapInuse\"`\n\tHeapReleased  int64   `json:\"HeapReleased\"`\n\tHeapObjects   int64   `json:\"HeapObjects\"`\n\tStackInuse    int64   `json:\"StackInuse\"`\n\tStackSys      int64   `json:\"StackSys\"`\n\tMSpanInuse    int64   `json:\"MSpanInuse\"`\n\tMSpanSys      int64   `json:\"MSpanSys\"`\n\tMCacheInuse   int64   `json:\"MCacheInuse\"`\n\tMCacheSys     int64   `json:\"MCacheSys\"`\n\tBuckHashSys   int64   `json:\"BuckHashSys\"`\n\tGCSys         int64   `json:\"GCSys\"`\n\tOtherSys      int64   `json:\"OtherSys\"`\n\tNextGC        int64   `json:\"NextGC\"`\n\tLastGC        int64   `json:\"LastGC\"`\n\tPauseTotalNs  int64   `json:\"PauseTotalNs\"`\n\tNumGC         int64   `json:\"NumGC\"`\n\tGCCPUFraction float64 `json:\"GCCPUFraction\"`\n}\n\ntype stats struct {\n\tCmdLine          []string           `json:\"cmdline\"`\n\tClusterID        string             `json:\"cluster_id\"`\n\tHost             string             `json:\"host\"`\n\tKapacitor        *map[string]object `json:\"kapacitor\"`\n\tMemStats         *memstats          `json:\"memstats\"`\n\tNumEnabledTasks  int                `json:\"num_enabled_tasks\"`\n\tNumSubscriptions int                `json:\"num_subscriptions\"`\n\tNumTasks         int                `json:\"num_tasks\"`\n\tProduct          string             `json:\"product\"`\n\tServerID         string             `json:\"server_id\"`\n\tVersion          string             `json:\"version\"`\n}\n\n// Gathers data from a particular URL\n// Parameters:\n//\n//\tacc    : The telegraf Accumulator to use\n//\turl    : endpoint to send request to\n//\n// Returns:\n//\n//\terror: Any error that may have occurred\nfunc (k *Kapacitor) gatherURL(\n\tacc telegraf.Accumulator,\n\turl string,\n) error {\n\tnow := time.Now()\n\n\tresp, err := k.client.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tdec := json.NewDecoder(resp.Body)\n\n\tvar s stats\n\terr = dec.Decode(&s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif s.MemStats != nil {\n\t\tacc.AddFields(\"kapacitor_memstats\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"alloc_bytes\":         s.MemStats.Alloc,\n\t\t\t\t\"buck_hash_sys_bytes\": s.MemStats.BuckHashSys,\n\t\t\t\t\"frees\":               s.MemStats.Frees,\n\t\t\t\t\"gc_cpu_fraction\":     s.MemStats.GCCPUFraction,\n\t\t\t\t\"gc_sys_bytes\":        s.MemStats.GCSys,\n\t\t\t\t\"heap_alloc_bytes\":    s.MemStats.HeapAlloc,\n\t\t\t\t\"heap_idle_bytes\":     s.MemStats.HeapIdle,\n\t\t\t\t\"heap_in_use_bytes\":   s.MemStats.HeapInuse,\n\t\t\t\t\"heap_objects\":        s.MemStats.HeapObjects,\n\t\t\t\t\"heap_released_bytes\": s.MemStats.HeapReleased,\n\t\t\t\t\"heap_sys_bytes\":      s.MemStats.HeapSys,\n\t\t\t\t\"last_gc_ns\":          s.MemStats.LastGC,\n\t\t\t\t\"lookups\":             s.MemStats.Lookups,\n\t\t\t\t\"mallocs\":             s.MemStats.Mallocs,\n\t\t\t\t\"mcache_in_use_bytes\": s.MemStats.MCacheInuse,\n\t\t\t\t\"mcache_sys_bytes\":    s.MemStats.MCacheSys,\n\t\t\t\t\"mspan_in_use_bytes\":  s.MemStats.MSpanInuse,\n\t\t\t\t\"mspan_sys_bytes\":     s.MemStats.MSpanSys,\n\t\t\t\t\"next_gc_ns\":          s.MemStats.NextGC,\n\t\t\t\t\"num_gc\":              s.MemStats.NumGC,\n\t\t\t\t\"other_sys_bytes\":     s.MemStats.OtherSys,\n\t\t\t\t\"pause_total_ns\":      s.MemStats.PauseTotalNs,\n\t\t\t\t\"stack_in_use_bytes\":  s.MemStats.StackInuse,\n\t\t\t\t\"stack_sys_bytes\":     s.MemStats.StackSys,\n\t\t\t\t\"sys_bytes\":           s.MemStats.Sys,\n\t\t\t\t\"total_alloc_bytes\":   s.MemStats.TotalAlloc,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"kap_version\": s.Version,\n\t\t\t\t\"url\":         url,\n\t\t\t},\n\t\t\tnow)\n\t}\n\n\tacc.AddFields(\"kapacitor\",\n\t\tmap[string]interface{}{\n\t\t\t\"num_enabled_tasks\": s.NumEnabledTasks,\n\t\t\t\"num_subscriptions\": s.NumSubscriptions,\n\t\t\t\"num_tasks\":         s.NumTasks,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"kap_version\": s.Version,\n\t\t\t\"url\":         url,\n\t\t},\n\t\tnow)\n\n\tif s.Kapacitor != nil {\n\t\tfor _, obj := range *s.Kapacitor {\n\t\t\t// Strip out high-cardinality or duplicative tags\n\t\t\texcludeTags := []string{\"host\", \"cluster_id\", \"server_id\"}\n\t\t\tfor _, key := range excludeTags {\n\t\t\t\tdelete(obj.Tags, key)\n\t\t\t}\n\n\t\t\t// Convert time-related string field to int\n\t\t\tif _, ok := obj.Values[\"avg_exec_time_ns\"]; ok {\n\t\t\t\td, err := time.ParseDuration(obj.Values[\"avg_exec_time_ns\"].(string))\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tobj.Values[\"avg_exec_time_ns\"] = d.Nanoseconds()\n\t\t\t}\n\n\t\t\tacc.AddFields(\n\t\t\t\t\"kapacitor_\"+obj.Name,\n\t\t\t\tobj.Values,\n\t\t\t\tobj.Tags,\n\t\t\t\tnow,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"kapacitor\", func() telegraf.Input {\n\t\treturn &Kapacitor{\n\t\t\tURLs:    []string{defaultURL},\n\t\t\tTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kapacitor/kapacitor_test.go",
    "content": "package kapacitor_test\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs/kapacitor\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestKapacitor(t *testing.T) {\n\tkapacitorReturn, err := os.ReadFile(\"./testdata/kapacitor_return.json\")\n\trequire.NoError(t, err)\n\n\tfakeInfluxServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write(kapacitorReturn); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer fakeInfluxServer.Close()\n\n\tplugin := &kapacitor.Kapacitor{\n\t\tURLs: []string{fakeInfluxServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\trequire.Len(t, acc.Metrics, 63)\n\n\tfields := map[string]interface{}{\n\t\t\"alloc_bytes\":         int64(6950624),\n\t\t\"buck_hash_sys_bytes\": int64(1446737),\n\t\t\"frees\":               int64(129656),\n\t\t\"gc_cpu_fraction\":     float64(0.006757149597237818),\n\t\t\"gc_sys_bytes\":        int64(575488),\n\t\t\"heap_alloc_bytes\":    int64(6950624),\n\t\t\"heap_idle_bytes\":     int64(499712),\n\t\t\"heap_in_use_bytes\":   int64(9166848),\n\t\t\"heap_objects\":        int64(28070),\n\t\t\"heap_released_bytes\": int64(0),\n\t\t\"heap_sys_bytes\":      int64(9666560),\n\t\t\"last_gc_ns\":          int64(1478813691405406556),\n\t\t\"lookups\":             int64(40),\n\t\t\"mallocs\":             int64(157726),\n\t\t\"mcache_in_use_bytes\": int64(9600),\n\t\t\"mcache_sys_bytes\":    int64(16384),\n\t\t\"mspan_in_use_bytes\":  int64(105600),\n\t\t\"mspan_sys_bytes\":     int64(114688),\n\t\t\"next_gc_ns\":          int64(10996691),\n\t\t\"num_gc\":              int64(4),\n\t\t\"other_sys_bytes\":     int64(1985959),\n\t\t\"pause_total_ns\":      int64(767327),\n\t\t\"stack_in_use_bytes\":  int64(819200),\n\t\t\"stack_sys_bytes\":     int64(819200),\n\t\t\"sys_bytes\":           int64(14625016),\n\t\t\"total_alloc_bytes\":   int64(13475176),\n\t}\n\n\ttags := map[string]string{\n\t\t\"kap_version\": \"1.1.0~rc2\",\n\t\t\"url\":         fakeInfluxServer.URL + \"/endpoint\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kapacitor_memstats\", fields, tags)\n\n\tacc.AssertContainsTaggedFields(t, \"kapacitor\",\n\t\tmap[string]interface{}{\n\t\t\t\"num_enabled_tasks\": 5,\n\t\t\t\"num_subscriptions\": 6,\n\t\t\t\"num_tasks\":         5,\n\t\t}, tags)\n}\n\nfunc TestMissingStats(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := w.Write([]byte(`{}`)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\tplugin := &kapacitor.Kapacitor{\n\t\tURLs: []string{server.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\trequire.False(t, acc.HasField(\"kapacitor_memstats\", \"alloc_bytes\"))\n\trequire.True(t, acc.HasField(\"kapacitor\", \"num_tasks\"))\n}\n\nfunc TestErrorHandling(t *testing.T) {\n\tbadServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path == \"/endpoint\" {\n\t\t\tif _, err := w.Write([]byte(\"not json\")); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer badServer.Close()\n\n\tplugin := &kapacitor.Kapacitor{\n\t\tURLs: []string{badServer.URL + \"/endpoint\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\tacc.WaitError(1)\n\trequire.Equal(t, uint64(0), acc.NMetrics())\n}\n\nfunc TestErrorHandling404(t *testing.T) {\n\tbadServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t}))\n\tdefer badServer.Close()\n\n\tplugin := &kapacitor.Kapacitor{\n\t\tURLs: []string{badServer.URL},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\tacc.WaitError(1)\n\trequire.Equal(t, uint64(0), acc.NMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/kapacitor/sample.conf",
    "content": "# Read Kapacitor-formatted JSON metrics from one or more HTTP endpoints\n[[inputs.kapacitor]]\n  ## Multiple URLs from which to read Kapacitor-formatted JSON\n  ## Default is \"http://localhost:9092/kapacitor/v1/debug/vars\".\n  urls = [\n    \"http://localhost:9092/kapacitor/v1/debug/vars\"\n  ]\n\n  ## Time limit for http requests\n  timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/kapacitor/testdata/kapacitor_return.json",
    "content": "{\n  \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n  \"cmdline\": [\n    \"./build/kapacitord\",\n    \"-config\",\n    \"/Users/ross/.kapacitor/config\"\n  ],\n  \"host\": \"localhost\",\n  \"kapacitor\": {\n    \"4360b884-4f1b-4915-90b9-e40a27cd366a\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"cq\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"b5ca6839-5cda-4330-b7aa-fccc50ce1320\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"type\": \"stream\",\n        \"task\": \"task_master:main\",\n        \"parent\": \"write_points\",\n        \"child\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 72,\n        \"emitted\": 72\n      }\n    },\n    \"e4f4dd29-96fe-41ca-9107-43030f67d47c\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"parent\": \"log3\",\n        \"child\": \"mean4\",\n        \"type\": \"batch\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"f8bb9712-52ea-44c8-a0d9-8b6ee47b9cb8\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"derivative-test\",\n        \"parent\": \"sum5\",\n        \"child\": \"log6\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"340391e7-8fc7-447d-ad07-547c5dd51f2c\": {\n      \"tags\": {\n        \"child\": \"from1\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"sys-stats\",\n        \"parent\": \"stream0\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"2fd00546-3b38-4118-97e6-38489e5732a8\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"sys-stats\",\n        \"parent\": \"stream\",\n        \"child\": \"stream0\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"type\": \"stream\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"5467712d-b3b9-45c5-acae-43a686c345e3\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task\": \"test\",\n        \"parent\": \"stream\",\n        \"child\": \"stream0\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"2ce99d1d-d26f-4daa-8857-36568a9effc1\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"deadman-test\",\n        \"node\": \"window2\",\n        \"type\": \"stream\",\n        \"kind\": \"window\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"975e59b2-d0ab-4ebf-9054-4de9751e0e87\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"deadman-test\",\n        \"parent\": \"derivative5\",\n        \"child\": \"window6\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"14fc028b-bda9-4b29-bf8e-8f682dd42bab\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"derivative-test\",\n        \"node\": \"from1\",\n        \"type\": \"stream\",\n        \"kind\": \"from\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"69f374fb-1289-457a-9ae6-79263e2dc430\": {\n      \"tags\": {\n        \"child\": \"derivative2\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"parent\": \"from1\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"0c0a0463-4588-494b-b871-f20dea1b4c71\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"derivative-test\",\n        \"node\": \"log6\",\n        \"type\": \"stream\",\n        \"kind\": \"log\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"e6eedf33-a07c-4daf-87fb-9429ee38847f\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"kind\": \"from\",\n        \"task\": \"deadman-test\",\n        \"node\": \"from1\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"c8da7d8a-6ea1-4cac-88aa-0804c413eecb\": {\n      \"tags\": {\n        \"child\": \"from1\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"parent\": \"stream0\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"ad4ca70d-1e56-422e-b36d-af565a8e1df0\": {\n      \"tags\": {\n        \"type\": \"stream\",\n        \"kind\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"node\": \"stream0\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\"\n    },\n    \"39fd1e7d-24bf-4cae-9c52-f9d876cc92af\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"test\",\n        \"parent\": \"from1\",\n        \"child\": \"alert2\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"emitted\": 0,\n        \"collected\": 0\n      }\n    },\n    \"1be18262-c33e-4cd6-bd49-7c82b819d4e1\": {\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"node\": \"stream0\",\n        \"type\": \"stream\",\n        \"kind\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      }\n    },\n    \"ce957f67-bef1-4755-acf1-1a335cbf0dcb\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"deadman-test\",\n        \"parent\": \"from1\",\n        \"child\": \"window2\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"c33ac068-6216-4ab2-b10d-b82f08891a10\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"kind\": \"window\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"node\": \"window6\",\n        \"type\": \"stream\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"2ab14f75-6a7d-49a8-a5bd-b829ec7588b5\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"parent\": \"derivative2\",\n        \"child\": \"log3\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"94031aa9-20fa-448a-8952-ba37d69a991a\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"node\": \"eval4\",\n        \"type\": \"stream\",\n        \"kind\": \"eval\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\",\n        \"eval_errors\": 0\n      }\n    },\n    \"d3b76aba-b2a2-4e72-a23d-f54c5037d6ee\": {\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"kind\": \"stream\",\n        \"task\": \"sys-stats\",\n        \"node\": \"stream0\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      }\n    },\n    \"fe2569b7-275d-411f-86f1-4c75127b0a77\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"node\": \"window2\",\n        \"type\": \"stream\",\n        \"kind\": \"window\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"sys-stats\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"067d801e-48de-4fec-98fe-d6691d3db1fe\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"derivative-test\",\n        \"node\": \"sum5\",\n        \"type\": \"stream\",\n        \"kind\": \"sum\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"5bc09b36-f1d7-460f-b533-91aa79b79ee3\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task\": \"test\",\n        \"node\": \"alert2\",\n        \"type\": \"stream\",\n        \"kind\": \"alert\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"warns_triggered\": 0,\n        \"crits_triggered\": 0,\n        \"avg_exec_time_ns\": \"0s\",\n        \"alerts_triggered\": 0,\n        \"oks_triggered\": 0,\n        \"infos_triggered\": 0\n      }\n    },\n    \"874c38c5-380f-4c76-b1ed-af2b7e1bd0f7\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"queryExecutor\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task_master\": \"main\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"38e0634f-9f11-4c3e-8621-96200dfb0ec4\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"node\": \"log3\",\n        \"type\": \"stream\",\n        \"kind\": \"log\",\n        \"task\": \"deadman-test\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"193ccaeb-7206-454d-9acc-457506848a09\": {\n      \"tags\": {\n        \"child\": \"sum5\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"parent\": \"eval4\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"68565c38-e5d2-4563-a2e8-991718154623\": {\n      \"tags\": {\n        \"child\": \"http_out3\",\n        \"type\": \"batch\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"sys-stats\",\n        \"parent\": \"window2\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"dd1dc51c-ae09-43af-b511-e6d23a7b1940\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"runtime\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"1f60fe6b-3dda-4811-a218-4e54cc6ff20f\": {\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"node\": \"log7\",\n        \"type\": \"stream\",\n        \"kind\": \"log\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\"\n    },\n    \"969d3962-ed99-4032-8625-465a2cccb2d9\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"parent\": \"stream\",\n        \"child\": \"stream0\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"5d237ee6-8362-427c-982b-f3be4a901e4b\": {\n      \"tags\": {\n        \"type\": \"stream\",\n        \"kind\": \"derivative\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"node\": \"derivative5\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\"\n    },\n    \"b92a8b07-713f-4d94-8c99-e1311129018a\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"sys-stats\",\n        \"parent\": \"http_out3\",\n        \"child\": \"influxdb_out4\",\n        \"type\": \"batch\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"bba6ca07-a577-46b5-90eb-e034b43e2d72\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"test\",\n        \"node\": \"stream0\",\n        \"type\": \"stream\",\n        \"kind\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"056bca53-554b-43e4-8402-7d5e8441f888\": {\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"parent\": \"window6\",\n        \"child\": \"log7\",\n        \"type\": \"batch\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"bd5a6337-0a7b-44f1-9768-1d3418fd8d66\": {\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\",\n      \"tags\": {\n        \"child\": \"eval4\",\n        \"type\": \"stream\",\n        \"task\": \"derivative-test\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"parent\": \"log3\"\n      }\n    },\n    \"faec1062-7c9a-44bc-aa7a-3b55bf3c0a45\": {\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\",\n        \"points_written\": 0,\n        \"write_errors\": 0\n      },\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"sys-stats\",\n        \"node\": \"influxdb_out4\",\n        \"type\": \"stream\",\n        \"kind\": \"influxdb_out\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      }\n    },\n    \"5cb5470f-da25-4d61-977a-9b50d9a3d2d2\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"tsm1_wal\",\n        \"task_master\": \"main\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"points_received\": 12\n      }\n    },\n    \"c746289f-c2d3-4c15-8cbc-4ceb9ac72ee4\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"measurement\": \"database\"\n      },\n      \"values\": {\n        \"points_received\": 4\n      }\n    },\n    \"b4e6202b-e826-40bf-835b-f3deb413495f\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"write\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"bdb9c35c-8f0f-4c64-b111-5afedde6fe26\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"httpd\",\n        \"task_master\": \"main\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"006be0dc-5861-4fbc-b5af-833d8fccb36c\": {\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"parent\": \"window2\",\n        \"child\": \"log3\",\n        \"type\": \"batch\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\"\n    },\n    \"3fa5469d-4599-4307-b67b-934ae74f9266\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"deadman-test\",\n        \"node\": \"mean4\",\n        \"type\": \"stream\",\n        \"kind\": \"mean\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"9636063d-79d2-4480-a03f-10e1b7680a40\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"kind\": \"http_out\",\n        \"task\": \"sys-stats\",\n        \"node\": \"http_out3\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"1ba6153d-227d-4771-ab83-a7bf9f64d1b0\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"type\": \"stream\",\n        \"task\": \"task_master:main\",\n        \"parent\": \"stats\",\n        \"child\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"e7936e59-313c-4fd1-8ae9-06aa11c0ffcb\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"shard\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\"\n      },\n      \"values\": {\n        \"points_received\": 12\n      }\n    },\n    \"94be0dc3-bee4-4e94-8e3b-7fb856abc490\": {\n      \"tags\": {\n        \"type\": \"stream\",\n        \"kind\": \"log\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"node\": \"log3\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      },\n      \"name\": \"nodes\"\n    },\n    \"7cb4de43-c440-477c-beaa-7b402ab16e06\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"child\": \"window2\",\n        \"type\": \"stream\",\n        \"task\": \"sys-stats\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"parent\": \"from1\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"a2666b71-3057-43d0-887b-8d88ca653b2f\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"subscriber\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"points_received\": 2\n      }\n    },\n    \"56727a9f-6f8e-4c34-af3c-32dfb365a407\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"derivative-test\",\n        \"parent\": \"stream0\",\n        \"child\": \"from1\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"d2840a0c-b140-419b-b10b-bef3f74cc696\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"task\": \"derivative-test\",\n        \"node\": \"derivative2\",\n        \"type\": \"stream\",\n        \"kind\": \"derivative\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"1d223093-e785-4d11-aa9f-8160cf2ddb4d\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"udp\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"points_received\": 1\n      }\n    },\n    \"f1be8ef4-9552-4f6a-83a9-ae2ca0b6e6b5\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"task\": \"deadman-test\",\n        \"parent\": \"mean4\",\n        \"child\": \"derivative5\",\n        \"type\": \"stream\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"c1c380da-60b4-422e-a37b-89aff6d11fd1\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"node\": \"from1\",\n        \"type\": \"stream\",\n        \"kind\": \"from\",\n        \"task\": \"sys-stats\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"29321d3f-9f22-4c37-9d48-b8d60aafe1ba\": {\n      \"name\": \"nodes\",\n      \"tags\": {\n        \"kind\": \"from\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"task\": \"test\",\n        \"node\": \"from1\",\n        \"type\": \"stream\"\n      },\n      \"values\": {\n        \"avg_exec_time_ns\": \"0s\"\n      }\n    },\n    \"901f8a35-b363-47f1-bdfc-c85e3561cc19\": {\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      },\n      \"name\": \"edges\",\n      \"tags\": {\n        \"type\": \"stream\",\n        \"task\": \"test\",\n        \"parent\": \"stream0\",\n        \"child\": \"from1\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      }\n    },\n    \"b729d0a0-474e-4bdb-823b-fa810bba3843\": {\n      \"tags\": {\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\",\n        \"measurement\": \"tsm1_cache\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\"\n      },\n      \"values\": {\n        \"points_received\": 12\n      },\n      \"name\": \"ingress\"\n    },\n    \"d1526a79-a5f0-45f0-836d-53a924457352\": {\n      \"name\": \"edges\",\n      \"tags\": {\n        \"type\": \"stream\",\n        \"task\": \"deadman-test\",\n        \"parent\": \"stream\",\n        \"child\": \"stream0\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"collected\": 0,\n        \"emitted\": 0\n      }\n    },\n    \"fa5165cb-76f0-4127-a9cb-99ab3c34d009\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"tsm1_engine\",\n        \"task_master\": \"main\",\n        \"database\": \"_internal\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n        \"host\": \"localhost\"\n      },\n      \"values\": {\n        \"points_received\": 12\n      }\n    },\n    \"649ffe5d-2682-4675-a943-baec4718fc8f\": {\n      \"name\": \"ingress\",\n      \"tags\": {\n        \"host\": \"localhost\",\n        \"database\": \"_internal\",\n        \"retention_policy\": \"monitor\",\n        \"measurement\": \"tsm1_filestore\",\n        \"task_master\": \"main\",\n        \"cluster_id\": \"aaa1cb78-8277-4886-a8ea-4706bca20842\",\n        \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\"\n      },\n      \"values\": {\n        \"points_received\": 12\n      }\n    }\n  },\n  \"memstats\": {\n    \"Alloc\": 6950624,\n    \"TotalAlloc\": 13475176,\n    \"Sys\": 14625016,\n    \"Lookups\": 40,\n    \"Mallocs\": 157726,\n    \"Frees\": 129656,\n    \"HeapAlloc\": 6950624,\n    \"HeapSys\": 9666560,\n    \"HeapIdle\": 499712,\n    \"HeapInuse\": 9166848,\n    \"HeapReleased\": 0,\n    \"HeapObjects\": 28070,\n    \"StackInuse\": 819200,\n    \"StackSys\": 819200,\n    \"MSpanInuse\": 105600,\n    \"MSpanSys\": 114688,\n    \"MCacheInuse\": 9600,\n    \"MCacheSys\": 16384,\n    \"BuckHashSys\": 1446737,\n    \"GCSys\": 575488,\n    \"OtherSys\": 1985959,\n    \"NextGC\": 10996691,\n    \"LastGC\": 1478813691405406556,\n    \"PauseTotalNs\": 767327,\n    \"PauseNs\": [\n      106224,\n      484338,\n      77201,\n      99564,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"PauseEnd\": [\n      1478813691247788813,\n      1478813691256256020,\n      1478813691262214751,\n      1478813691405406556,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0,\n      0\n    ],\n    \"NumGC\": 4,\n    \"GCCPUFraction\": 0.006757149597237818,\n    \"EnableGC\": true,\n    \"DebugGC\": false,\n    \"BySize\": [\n      {\n        \"Size\": 0,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8,\n        \"Mallocs\": 16193,\n        \"Frees\": 15733\n      },\n      {\n        \"Size\": 16,\n        \"Mallocs\": 54267,\n        \"Frees\": 45512\n      },\n      {\n        \"Size\": 32,\n        \"Mallocs\": 35006,\n        \"Frees\": 25861\n      },\n      {\n        \"Size\": 48,\n        \"Mallocs\": 7130,\n        \"Frees\": 5066\n      },\n      {\n        \"Size\": 64,\n        \"Mallocs\": 3421,\n        \"Frees\": 2554\n      },\n      {\n        \"Size\": 80,\n        \"Mallocs\": 3749,\n        \"Frees\": 3225\n      },\n      {\n        \"Size\": 96,\n        \"Mallocs\": 13973,\n        \"Frees\": 13413\n      },\n      {\n        \"Size\": 112,\n        \"Mallocs\": 1269,\n        \"Frees\": 825\n      },\n      {\n        \"Size\": 128,\n        \"Mallocs\": 1851,\n        \"Frees\": 1755\n      },\n      {\n        \"Size\": 144,\n        \"Mallocs\": 181,\n        \"Frees\": 95\n      },\n      {\n        \"Size\": 160,\n        \"Mallocs\": 558,\n        \"Frees\": 184\n      },\n      {\n        \"Size\": 176,\n        \"Mallocs\": 303,\n        \"Frees\": 249\n      },\n      {\n        \"Size\": 192,\n        \"Mallocs\": 2485,\n        \"Frees\": 278\n      },\n      {\n        \"Size\": 208,\n        \"Mallocs\": 255,\n        \"Frees\": 124\n      },\n      {\n        \"Size\": 224,\n        \"Mallocs\": 316,\n        \"Frees\": 131\n      },\n      {\n        \"Size\": 240,\n        \"Mallocs\": 64,\n        \"Frees\": 28\n      },\n      {\n        \"Size\": 256,\n        \"Mallocs\": 128,\n        \"Frees\": 91\n      },\n      {\n        \"Size\": 288,\n        \"Mallocs\": 734,\n        \"Frees\": 194\n      },\n      {\n        \"Size\": 320,\n        \"Mallocs\": 257,\n        \"Frees\": 15\n      },\n      {\n        \"Size\": 352,\n        \"Mallocs\": 531,\n        \"Frees\": 284\n      },\n      {\n        \"Size\": 384,\n        \"Mallocs\": 63,\n        \"Frees\": 7\n      },\n      {\n        \"Size\": 416,\n        \"Mallocs\": 189,\n        \"Frees\": 66\n      },\n      {\n        \"Size\": 448,\n        \"Mallocs\": 60,\n        \"Frees\": 11\n      },\n      {\n        \"Size\": 480,\n        \"Mallocs\": 19,\n        \"Frees\": 6\n      },\n      {\n        \"Size\": 512,\n        \"Mallocs\": 72,\n        \"Frees\": 56\n      },\n      {\n        \"Size\": 576,\n        \"Mallocs\": 157,\n        \"Frees\": 61\n      },\n      {\n        \"Size\": 640,\n        \"Mallocs\": 27,\n        \"Frees\": 14\n      },\n      {\n        \"Size\": 704,\n        \"Mallocs\": 159,\n        \"Frees\": 146\n      },\n      {\n        \"Size\": 768,\n        \"Mallocs\": 182,\n        \"Frees\": 179\n      },\n      {\n        \"Size\": 896,\n        \"Mallocs\": 82,\n        \"Frees\": 43\n      },\n      {\n        \"Size\": 1024,\n        \"Mallocs\": 108,\n        \"Frees\": 39\n      },\n      {\n        \"Size\": 1152,\n        \"Mallocs\": 245,\n        \"Frees\": 27\n      },\n      {\n        \"Size\": 1280,\n        \"Mallocs\": 49,\n        \"Frees\": 32\n      },\n      {\n        \"Size\": 1408,\n        \"Mallocs\": 70,\n        \"Frees\": 37\n      },\n      {\n        \"Size\": 1536,\n        \"Mallocs\": 61,\n        \"Frees\": 31\n      },\n      {\n        \"Size\": 1664,\n        \"Mallocs\": 29,\n        \"Frees\": 17\n      },\n      {\n        \"Size\": 2048,\n        \"Mallocs\": 102,\n        \"Frees\": 74\n      },\n      {\n        \"Size\": 2304,\n        \"Mallocs\": 27,\n        \"Frees\": 15\n      },\n      {\n        \"Size\": 2560,\n        \"Mallocs\": 17,\n        \"Frees\": 14\n      },\n      {\n        \"Size\": 2816,\n        \"Mallocs\": 92,\n        \"Frees\": 90\n      },\n      {\n        \"Size\": 3072,\n        \"Mallocs\": 4,\n        \"Frees\": 4\n      },\n      {\n        \"Size\": 3328,\n        \"Mallocs\": 20,\n        \"Frees\": 12\n      },\n      {\n        \"Size\": 4096,\n        \"Mallocs\": 85,\n        \"Frees\": 63\n      },\n      {\n        \"Size\": 4608,\n        \"Mallocs\": 25,\n        \"Frees\": 10\n      },\n      {\n        \"Size\": 5376,\n        \"Mallocs\": 50,\n        \"Frees\": 7\n      },\n      {\n        \"Size\": 6144,\n        \"Mallocs\": 13,\n        \"Frees\": 2\n      },\n      {\n        \"Size\": 6400,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 6656,\n        \"Mallocs\": 2,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 6912,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8192,\n        \"Mallocs\": 31,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 8448,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 8704,\n        \"Mallocs\": 1,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 9472,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 10496,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 12288,\n        \"Mallocs\": 5,\n        \"Frees\": 1\n      },\n      {\n        \"Size\": 13568,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 14080,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 16384,\n        \"Mallocs\": 4,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 16640,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      },\n      {\n        \"Size\": 17664,\n        \"Mallocs\": 0,\n        \"Frees\": 0\n      }\n    ]\n  },\n  \"num_enabled_tasks\": 5,\n  \"num_subscriptions\": 6,\n  \"num_tasks\": 5,\n  \"product\": \"kapacitor\",\n  \"server_id\": \"81e38258-5f18-4201-8d47-db603bfceeff\",\n  \"version\": \"1.1.0~rc2\"\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/README.md",
    "content": "# Kernel Input Plugin\n\nThis plugin gathers metrics about the [Linux kernel][kernel] including, among\nothers, the [available entropy][entropy], [Kernel Samepage Merging][ksm] and\n[Pressure Stall Information][psi].\n\n⭐ Telegraf v0.11.0\n🏷️ system\n💻 linux\n\n[kernel]: https://kernel.org/\n[entropy]: https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#random\n[ksm]: https://www.kernel.org/doc/html/latest/mm/ksm.html\n[psi]: https://www.kernel.org/doc/html/latest/accounting/psi.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Plugin to collect various Linux kernel statistics.\n# This plugin ONLY supports Linux\n[[inputs.kernel]]\n  ## Additional gather options\n  ## Possible options include:\n  ## * ksm - kernel same-page merging\n  ## * psi - pressure stall information\n  # collect = []\n```\n\nPlease check the documentation of the underlying kernel interfaces in the\n`/proc/stat` section of the [proc man page][man_proc], as well as in the\n`/proc interfaces` section of the [random man page][man_random].\n\nKernel Samepage Merging is generally documented in the\n[kernel documentation][ksm] and the available metrics exposed via sysfs\nare documented in the [admin guide][ksm_admin].\n\nPressure Stall Information is exposed through `/proc/pressure` and is documented\nin [kernel documentation][psi]. Kernel version 4.20+ is required.\n\n[ksm_admin]: https://www.kernel.org/doc/html/latest/admin-guide/mm/ksm.html#ksm-daemon-sysfs-interface\n[man_proc]: http://man7.org/linux/man-pages/man5/proc.5.html\n[man_random]: https://man7.org/linux/man-pages/man4/random.4.html\n\n## Metrics\n\n- kernel\n  - boot_time              (int) - seconds since epoch, `btime`\n  - context_switches       (int) - number of context switches `ctxt`\n  - disk_pages_in          (int) - `page (0)`\n  - disk_pages_out         (int) - `page (1)`\n  - interrupts             (int) - number of interrupts `intr`\n  - processes_forked       (int) - number of forked processes `processes`\n  - entropy_avail          (int) - entropy currently available `entropy_available`\n  - ksm_full_scans         (int) - number of scans of all mergeable areas `full_scans`\n  - ksm_max_page_sharing   (int) - maximum sharing allowed for each KSM page `max_page_sharing`\n  - ksm_merge_across_nodes (int) - flag for merging of pages across NUMA nodes `merge_across_nodes`\n  - ksm_pages_shared       (int) - number of shared pages are being used `pages_shared`\n  - ksm_pages_sharing      (int) - number of sites sharing pages `pages_sharing`\n  - ksm_pages_to_scan      (int) - number of pages to scan before ksmd  sleep `pages_to_scan`\n  - ksm_pages_unshared     (int) - number of pages unique but repeatedly checked\n                                   for merging `pages_unshared`\n  - ksm_pages_volatile     (int) - number of pages changing too fast to be\n                                   placed in a tree `pages_volatile`\n  - ksm_run                (int) - flag for ksm is running or not `run`\n  - ksm_sleep_millisecs    (int) - sleep time for ksmd between scans `sleep_millisecs`\n  - ksm_stable_node_chains (int) - number of KSM pages hitting the\n                                   max_page_sharing limit `stable_node_chains`\n  - ksm_stable_node_chains_prune_millisecs (int) - frequency for KSM checks of\n                                                   page metadata hitting the\n                                                   deduplication limit `stable_node_chains_prune_millisecs`\n  - ksm_stable_node_dups   (int) - number of duplicated KSM pages, `stable_node_dups`\n  - ksm_use_zero_pages     (int) - flag for empty pages being treated specially\n                                   `use_zero_pages`\n\n- pressure (if `psi` is included in `collect`)\n  - tags:\n    - resource: cpu, memory, or io\n    - type: some or full\n  - floating-point fields: avg10, avg60, avg300\n  - integer fields: total\n\n## Example Output\n\nDefault config:\n\n```text\nkernel boot_time=1690487872i,context_switches=321398652i,entropy_avail=256i,interrupts=141868628i,processes_forked=946492i 1691339564000000000\n```\n\nIf `ksm` is included in `collect`:\n\n```text\nkernel boot_time=1690487872i,context_switches=321252729i,entropy_avail=256i,interrupts=141783427i,ksm_full_scans=0i,ksm_max_page_sharing=256i,ksm_merge_across_nodes=1i,ksm_pages_shared=0i,ksm_pages_sharing=0i,ksm_pages_to_scan=100i,ksm_pages_unshared=0i,ksm_pages_volatile=0i,ksm_run=0i,ksm_sleep_millisecs=20i,ksm_stable_node_chains=0i,ksm_stable_node_chains_prune_millisecs=2000i,ksm_stable_node_dups=0i,ksm_use_zero_pages=0i,processes_forked=946467i 1691339522000000000\n```\n\nIf `psi` is included in `collect`:\n\n```text\npressure,resource=cpu,type=some avg10=1.53,avg60=1.87,avg300=1.73 1700000000000000000\npressure,resource=memory,type=some avg10=0.00,avg60=0.00,avg300=0.00 1700000000000000000\npressure,resource=memory,type=full avg10=0.00,avg60=0.00,avg300=0.00 1700000000000000000\npressure,resource=io,type=some avg10=0.0,avg60=0.0,avg300=0.0 1700000000000000000\npressure,resource=io,type=full avg10=0.0,avg60=0.0,avg300=0.0 1700000000000000000\npressure,resource=cpu,type=some total=1088168194i 1700000000000000000\npressure,resource=memory,type=some total=3463792i 1700000000000000000\npressure,resource=memory,type=full total=1429641i 1700000000000000000\npressure,resource=io,type=some total=68568296i 1700000000000000000\npressure,resource=io,type=full total=54982338i 1700000000000000000\n```\n\nNote that the combination for `resource=cpu,type=full` is omitted because it is\nalways zero.\n"
  },
  {
    "path": "plugins/inputs/kernel/kernel.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage kernel\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/prometheus/procfs\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// /proc/stat file line prefixes to gather stats on:\nvar (\n\tinterrupts      = []byte(\"intr\")\n\tcontextSwitches = []byte(\"ctxt\")\n\tprocessesForked = []byte(\"processes\")\n\tdiskPages       = []byte(\"page\")\n\tbootTime        = []byte(\"btime\")\n)\n\ntype Kernel struct {\n\tConfigCollect []string `toml:\"collect\"`\n\n\toptCollect      map[string]bool\n\tstatFile        string\n\tentropyStatFile string\n\tksmStatsDir     string\n\tpsiDir          string\n\tprocfs          procfs.FS\n}\n\nfunc (*Kernel) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *Kernel) Init() error {\n\tk.optCollect = make(map[string]bool, len(k.ConfigCollect))\n\tfor _, v := range k.ConfigCollect {\n\t\tk.optCollect[v] = true\n\t}\n\n\tif k.optCollect[\"ksm\"] {\n\t\tif _, err := os.Stat(k.ksmStatsDir); os.IsNotExist(err) {\n\t\t\t// ksm probably not enabled in the kernel, bail out early\n\t\t\treturn fmt.Errorf(\"directory %q does not exist. KSM is not enabled in this kernel\", k.ksmStatsDir)\n\t\t}\n\t}\n\tif k.optCollect[\"psi\"] {\n\t\tprocdir := filepath.Dir(k.psiDir)\n\t\tvar err error\n\t\tif k.procfs, err = procfs.NewFS(procdir); err != nil {\n\t\t\t// psi probably not supported in the kernel, bail out early\n\t\t\treturn fmt.Errorf(\"failed to initialize procfs on %s: %w\", procdir, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (k *Kernel) Gather(acc telegraf.Accumulator) error {\n\tdata, err := getProcValueBytes(k.statFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tentropyValue, err := getProcValueInt(k.entropyStatFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields := make(map[string]interface{})\n\n\tfields[\"entropy_avail\"] = entropyValue\n\n\tdataFields := bytes.Fields(data)\n\tfor i, field := range dataFields {\n\t\tswitch {\n\t\tcase bytes.Equal(field, interrupts):\n\t\t\tm, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"interrupts\"] = m\n\t\tcase bytes.Equal(field, contextSwitches):\n\t\t\tm, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"context_switches\"] = m\n\t\tcase bytes.Equal(field, processesForked):\n\t\t\tm, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"processes_forked\"] = m\n\t\tcase bytes.Equal(field, bootTime):\n\t\t\tm, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"boot_time\"] = m\n\t\tcase bytes.Equal(field, diskPages):\n\t\t\tin, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tout, err := strconv.ParseInt(string(dataFields[i+2]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[\"disk_pages_in\"] = in\n\t\t\tfields[\"disk_pages_out\"] = out\n\t\t}\n\t}\n\n\tif k.optCollect[\"ksm\"] {\n\t\tstats := []string{\n\t\t\t\"full_scans\", \"max_page_sharing\",\n\t\t\t\"merge_across_nodes\", \"pages_shared\",\n\t\t\t\"pages_sharing\", \"pages_to_scan\",\n\t\t\t\"pages_unshared\", \"pages_volatile\",\n\t\t\t\"run\", \"sleep_millisecs\",\n\t\t\t\"stable_node_chains\", \"stable_node_chains_prune_millisecs\",\n\t\t\t\"stable_node_dups\", \"use_zero_pages\",\n\t\t}\n\t\t// these exist in very recent Linux versions only, but useful to include if there.\n\t\textraStats := []string{\"general_profit\"}\n\n\t\tfor _, f := range stats {\n\t\t\tm, err := getProcValueInt(filepath.Join(k.ksmStatsDir, f))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields[\"ksm_\"+f] = m\n\t\t}\n\n\t\tfor _, f := range extraStats {\n\t\t\tm, err := getProcValueInt(filepath.Join(k.ksmStatsDir, f))\n\t\t\tif err != nil {\n\t\t\t\t// if an extraStats metric doesn't exist in our kernel version, ignore it.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfields[\"ksm_\"+f] = m\n\t\t}\n\t}\n\tacc.AddCounter(\"kernel\", fields, make(map[string]string))\n\n\tif k.optCollect[\"psi\"] {\n\t\tif err := k.gatherPressure(acc); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc getProcValueBytes(path string) ([]byte, error) {\n\tif _, err := os.Stat(path); os.IsNotExist(err) {\n\t\treturn nil, fmt.Errorf(\"path %q does not exist\", path)\n\t} else if err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read from %q: %w\", path, err)\n\t}\n\n\treturn data, nil\n}\n\nfunc getProcValueInt(path string) (int64, error) {\n\tdata, err := getProcValueBytes(path)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\n\tm, err := strconv.ParseInt(string(bytes.TrimSpace(data)), 10, 64)\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"failed to parse %q as an integer: %w\", data, err)\n\t}\n\n\treturn m, nil\n}\n\nfunc init() {\n\tinputs.Add(\"kernel\", func() telegraf.Input {\n\t\treturn &Kernel{\n\t\t\tstatFile:        \"/proc/stat\",\n\t\t\tentropyStatFile: \"/proc/sys/kernel/random/entropy_avail\",\n\t\t\tksmStatsDir:     \"/sys/kernel/mm/ksm\",\n\t\t\tpsiDir:          \"/proc/pressure\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/kernel_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage kernel\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Kernel struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Kernel) SampleConfig() string { return sampleConfig }\n\nfunc (k *Kernel) Init() error {\n\tk.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Kernel) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"kernel\", func() telegraf.Input {\n\t\treturn &Kernel{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/kernel_test.go",
    "content": "//go:build linux\n\npackage kernel\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGetProcValueInt(t *testing.T) {\n\td, err := getProcValueInt(\"testdata/entropy_stat_file_full\")\n\trequire.NoError(t, err)\n\trequire.IsType(t, int64(1), d)\n}\n\nfunc TestGetProcValueByte(t *testing.T) {\n\td, err := getProcValueBytes(\"testdata/entropy_stat_file_full\")\n\trequire.NoError(t, err)\n\trequire.IsType(t, []byte(\"test\"), d)\n}\n\nfunc TestFullProcFile(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_full\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_full\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, k.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"kernel\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"boot_time\":        int64(1457505775),\n\t\t\t\t\"context_switches\": int64(2626618),\n\t\t\t\t\"disk_pages_in\":    int64(5741),\n\t\t\t\t\"disk_pages_out\":   int64(1808),\n\t\t\t\t\"interrupts\":       int64(1472736),\n\t\t\t\t\"processes_forked\": int64(10673),\n\t\t\t\t\"entropy_avail\":    int64(1024),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\t1,\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestPartialProcFile(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_partial\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_partial\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, k.Gather(&acc))\n\n\tfields := map[string]interface{}{\n\t\t\"boot_time\":        int64(1457505775),\n\t\t\"context_switches\": int64(2626618),\n\t\t\"disk_pages_in\":    int64(5741),\n\t\t\"disk_pages_out\":   int64(1808),\n\t\t\"interrupts\":       int64(1472736),\n\t\t\"entropy_avail\":    int64(1024),\n\t}\n\tacc.AssertContainsFields(t, \"kernel\", fields)\n}\n\nfunc TestInvalidProcFile1(t *testing.T) {\n\t// missing btime measurement\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_invalid\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_invalid\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"invalid syntax\")\n}\n\nfunc TestInvalidProcFile2(t *testing.T) {\n\t// missing second page measurement\n\tk := Kernel{\n\t\tstatFile: \"testdata/stat_file_invalid2\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"does not exist\")\n}\n\nfunc TestNoProcFile(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile: \"testdata/this_file_does_not_exist\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"does not exist\")\n}\n\nfunc TestInvalidCollectOption(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_full\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_full\",\n\t\tConfigCollect:   []string{\"invalidOption\"},\n\t}\n\n\tacc := testutil.Accumulator{}\n\n\trequire.NoError(t, k.Init())\n\trequire.NoError(t, k.Gather(&acc))\n}\n\nfunc TestKsmEnabledValidKsmDirectory(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_full\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_full\",\n\t\tksmStatsDir:     \"testdata/ksm/valid\",\n\t\tConfigCollect:   []string{\"ksm\"},\n\t}\n\n\trequire.NoError(t, k.Init())\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, k.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"kernel\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"boot_time\":                              int64(1457505775),\n\t\t\t\t\"context_switches\":                       int64(2626618),\n\t\t\t\t\"disk_pages_in\":                          int64(5741),\n\t\t\t\t\"disk_pages_out\":                         int64(1808),\n\t\t\t\t\"interrupts\":                             int64(1472736),\n\t\t\t\t\"processes_forked\":                       int64(10673),\n\t\t\t\t\"entropy_avail\":                          int64(1024),\n\t\t\t\t\"ksm_full_scans\":                         int64(123),\n\t\t\t\t\"ksm_max_page_sharing\":                   int64(10000),\n\t\t\t\t\"ksm_merge_across_nodes\":                 int64(1),\n\t\t\t\t\"ksm_pages_shared\":                       int64(12922),\n\t\t\t\t\"ksm_pages_sharing\":                      int64(28384),\n\t\t\t\t\"ksm_pages_to_scan\":                      int64(12928),\n\t\t\t\t\"ksm_pages_unshared\":                     int64(92847),\n\t\t\t\t\"ksm_pages_volatile\":                     int64(2824171),\n\t\t\t\t\"ksm_run\":                                int64(1),\n\t\t\t\t\"ksm_sleep_millisecs\":                    int64(1000),\n\t\t\t\t\"ksm_stable_node_chains\":                 int64(0),\n\t\t\t\t\"ksm_stable_node_chains_prune_millisecs\": int64(0),\n\t\t\t\t\"ksm_stable_node_dups\":                   int64(0),\n\t\t\t\t\"ksm_use_zero_pages\":                     int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\t1,\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestKSMEnabledMissingFile(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"/proc/stat\",\n\t\tentropyStatFile: \"/proc/sys/kernel/random/entropy_avail\",\n\t\tksmStatsDir:     \"testdata/ksm/missing\",\n\t\tConfigCollect:   []string{\"ksm\"},\n\t}\n\n\trequire.NoError(t, k.Init())\n\n\tacc := testutil.Accumulator{}\n\trequire.ErrorContains(t, k.Gather(&acc), \"does not exist\")\n}\n\nfunc TestKSMEnabledWrongDir(t *testing.T) {\n\tk := Kernel{\n\t\tksmStatsDir:   \"testdata/this_file_does_not_exist\",\n\t\tConfigCollect: []string{\"ksm\"},\n\t}\n\n\trequire.ErrorContains(t, k.Init(), \"KSM is not enabled in this kernel\")\n}\n\nfunc TestKSMDisabledNoKSMTags(t *testing.T) {\n\tk := Kernel{\n\t\tstatFile:        \"testdata/stat_file_full\",\n\t\tentropyStatFile: \"testdata/entropy_stat_file_full\",\n\t\tksmStatsDir:     \"testdata/this_file_does_not_exist\",\n\t}\n\n\tacc := testutil.Accumulator{}\n\n\trequire.NoError(t, k.Init())\n\trequire.NoError(t, k.Gather(&acc))\n\trequire.False(t, acc.HasField(\"kernel\", \"ksm_run\"))\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/psi.go",
    "content": "//go:build linux\n\npackage kernel\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/prometheus/procfs\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// Gather PSI metrics\nfunc (k *Kernel) gatherPressure(acc telegraf.Accumulator) error {\n\tfor _, resource := range []string{\"cpu\", \"memory\", \"io\"} {\n\t\tnow := time.Now()\n\t\tpsiStats, err := k.procfs.PSIStatsForResource(resource)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read %s pressure: %w\", resource, err)\n\t\t}\n\n\t\tstats := map[string]*procfs.PSILine{\n\t\t\t\"some\": psiStats.Some,\n\t\t\t\"full\": psiStats.Full,\n\t\t}\n\n\t\tfor _, typ := range []string{\"some\", \"full\"} {\n\t\t\tif resource == \"cpu\" && typ == \"full\" {\n\t\t\t\t// resource=cpu,type=full is omitted because it is always zero\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttags := map[string]string{\n\t\t\t\t\"resource\": resource,\n\t\t\t\t\"type\":     typ,\n\t\t\t}\n\t\t\tstat := stats[typ]\n\n\t\t\tacc.AddCounter(\"pressure\", map[string]interface{}{\n\t\t\t\t\"total\": stat.Total,\n\t\t\t}, tags, now)\n\t\t\tacc.AddGauge(\"pressure\", map[string]interface{}{\n\t\t\t\t\"avg10\":  stat.Avg10,\n\t\t\t\t\"avg60\":  stat.Avg60,\n\t\t\t\t\"avg300\": stat.Avg300,\n\t\t\t}, tags, now)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/psi_test.go",
    "content": "//go:build linux\n\npackage kernel\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestPSIEnabledWrongDir(t *testing.T) {\n\tk := Kernel{\n\t\tpsiDir:        \"testdata/this_directory_does_not_exist/stub\",\n\t\tConfigCollect: []string{\"psi\"},\n\t}\n\n\trequire.ErrorContains(t, k.Init(), \"failed to initialize procfs on \")\n}\n\nfunc TestPSIStats(t *testing.T) {\n\tk := Kernel{\n\t\tpsiDir:        \"testdata/pressure\",\n\t\tConfigCollect: []string{\"psi\"},\n\t}\n\trequire.NoError(t, k.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, k.gatherPressure(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"cpu\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg10\":  float64(10),\n\t\t\t\t\"avg60\":  float64(60),\n\t\t\t\t\"avg300\": float64(300),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"cpu\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\": uint64(114514),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"memory\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg10\":  float64(10),\n\t\t\t\t\"avg60\":  float64(60),\n\t\t\t\t\"avg300\": float64(300),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"memory\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\": uint64(114514),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"io\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg10\":  float64(10),\n\t\t\t\t\"avg60\":  float64(60),\n\t\t\t\t\"avg300\": float64(300),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"io\",\n\t\t\t\t\"type\":     \"some\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\": uint64(114514),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"memory\",\n\t\t\t\t\"type\":     \"full\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg10\":  float64(1),\n\t\t\t\t\"avg60\":  float64(6),\n\t\t\t\t\"avg300\": float64(30),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"memory\",\n\t\t\t\t\"type\":     \"full\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\": uint64(11451),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"io\",\n\t\t\t\t\"type\":     \"full\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"avg10\":  float64(1),\n\t\t\t\t\"avg60\":  float64(6),\n\t\t\t\t\"avg300\": float64(30),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"pressure\",\n\t\t\tmap[string]string{\n\t\t\t\t\"resource\": \"io\",\n\t\t\t\t\"type\":     \"full\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\": uint64(11451),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/kernel/sample.conf",
    "content": "# Plugin to collect various Linux kernel statistics.\n# This plugin ONLY supports Linux\n[[inputs.kernel]]\n  ## Additional gather options\n  ## Possible options include:\n  ## * ksm - kernel same-page merging\n  ## * psi - pressure stall information\n  # collect = []\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/entropy_stat_file_full",
    "content": "1024"
  },
  {
    "path": "plugins/inputs/kernel/testdata/entropy_stat_file_invalid",
    "content": ""
  },
  {
    "path": "plugins/inputs/kernel/testdata/entropy_stat_file_partial",
    "content": "1024"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/full_scans",
    "content": "123A\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/max_page_sharing",
    "content": "10000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/merge_across_nodes",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/pages_shared",
    "content": "12922\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/pages_sharing",
    "content": "28384\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/pages_to_scan",
    "content": "12928\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/pages_unshared",
    "content": "92847\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/pages_volatile",
    "content": "2824171\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/run",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/sleep_millisecs",
    "content": "1000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/stable_node_chains",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/stable_node_chains_prune_millisecs",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/stable_node_dups",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/invalid/use_zero_pages",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/full_scans",
    "content": "123\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/max_page_sharing",
    "content": "10000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/merge_across_nodes",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/pages_shared",
    "content": "12922\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/pages_sharing",
    "content": "28384\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/pages_to_scan",
    "content": "12928\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/pages_unshared",
    "content": "92847\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/pages_volatile",
    "content": "2824171\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/sleep_millisecs",
    "content": "1000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/stable_node_chains",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/stable_node_chains_prune_millisecs",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/stable_node_dups",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/missing/use_zero_pages",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/full_scans",
    "content": "123\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/max_page_sharing",
    "content": "10000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/merge_across_nodes",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/pages_shared",
    "content": "12922\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/pages_sharing",
    "content": "28384\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/pages_to_scan",
    "content": "12928\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/pages_unshared",
    "content": "92847\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/pages_volatile",
    "content": "2824171\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/run",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/sleep_millisecs",
    "content": "1000\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/stable_node_chains",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/stable_node_chains_prune_millisecs",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/stable_node_dups",
    "content": "0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/ksm/valid/use_zero_pages",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/pressure/cpu",
    "content": "some avg10=10.00 avg60=60.00 avg300=300.00 total=114514\nfull avg10=0.00 avg60=0.00 avg300=0.00 total=0\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/pressure/io",
    "content": "some avg10=10.00 avg60=60.00 avg300=300.00 total=114514\nfull avg10=1.00 avg60=6.00 avg300=30.00 total=11451\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/pressure/memory",
    "content": "some avg10=10.00 avg60=60.00 avg300=300.00 total=114514\nfull avg10=1.00 avg60=6.00 avg300=30.00 total=11451\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/stat_file_full",
    "content": "cpu  6796 252 5655 10444977 175 0 101 0 0 0\ncpu0 6796 252 5655 10444977 175 0 101 0 0 0\nintr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\nctxt 2626618\nbtime 1457505775\nprocesses 10673\nprocs_running 2\nprocs_blocked 0\nsoftirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545\npage 5741 1808\nswap 1 0\nentropy_avail 1024\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/stat_file_invalid",
    "content": "cpu  6796 252 5655 10444977 175 0 101 0 0 0\ncpu0 6796 252 5655 10444977 175 0 101 0 0 0\nintr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\nctxt 2626618\nbtime\nprocesses 10673\nprocs_running 2\nprocs_blocked 0\nsoftirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545\npage 5741 1808\nswap 1 0\nentropy_avail 1024\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/stat_file_invalid2",
    "content": "cpu  6796 252 5655 10444977 175 0 101 0 0 0\ncpu0 6796 252 5655 10444977 175 0 101 0 0 0\nintr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\nctxt 2626618\nprocesses 10673\nprocs_running 2\npage 5741\nprocs_blocked 0\nsoftirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545\nentropy_avail 1024 2048\n"
  },
  {
    "path": "plugins/inputs/kernel/testdata/stat_file_partial",
    "content": "cpu  6796 252 5655 10444977 175 0 101 0 0 0\ncpu0 6796 252 5655 10444977 175 0 101 0 0 0\nintr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\nctxt 2626618\nbtime 1457505775\nprocs_running 2\nprocs_blocked 0\nsoftirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545\npage 5741 1808\n"
  },
  {
    "path": "plugins/inputs/kernel_vmstat/README.md",
    "content": "# Kernel VM Statistics Input Plugin\n\nThis plugin gathers virtual memory statistics of the [Linux kernel][kernel] by\nreading `/proc/vmstat`. For a full list of available fields check the\n`/proc/vmstat` section of the [proc man page][man_proc] and for a detailed\ndescription about the fields see the [vmstat man page][man_vmstat].\n\n⭐ Telegraf v1.0.0\n🏷️ system\n💻 linux\n\n[kernel]: https://kernel.org/\n[man_proc]: http://man7.org/linux/man-pages/man5/proc.5.html\n[man_vmstat]: https://man7.org/linux/man-pages/man8/vmstat.8.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get kernel statistics from /proc/vmstat\n# This plugin ONLY supports Linux\n[[inputs.kernel_vmstat]]\n  # no configuration\n```\n\n## Metrics\n\n- kernel_vmstat\n  - nr_free_pages (integer, `nr_free_pages`)\n  - nr_inactive_anon (integer, `nr_inactive_anon`)\n  - nr_active_anon (integer, `nr_active_anon`)\n  - nr_inactive_file (integer, `nr_inactive_file`)\n  - nr_active_file (integer, `nr_active_file`)\n  - nr_unevictable (integer, `nr_unevictable`)\n  - nr_mlock (integer, `nr_mlock`)\n  - nr_anon_pages (integer, `nr_anon_pages`)\n  - nr_mapped (integer, `nr_mapped`)\n  - nr_file_pages (integer, `nr_file_pages`)\n  - nr_dirty (integer, `nr_dirty`)\n  - nr_writeback (integer, `nr_writeback`)\n  - nr_slab_reclaimable (integer, `nr_slab_reclaimable`)\n  - nr_slab_unreclaimable (integer, `nr_slab_unreclaimable`)\n  - nr_page_table_pages (integer, `nr_page_table_pages`)\n  - nr_kernel_stack (integer, `nr_kernel_stack`)\n  - nr_unstable (integer, `nr_unstable`)\n  - nr_bounce (integer, `nr_bounce`)\n  - nr_vmscan_write (integer, `nr_vmscan_write`)\n  - nr_writeback_temp (integer, `nr_writeback_temp`)\n  - nr_isolated_anon (integer, `nr_isolated_anon`)\n  - nr_isolated_file (integer, `nr_isolated_file`)\n  - nr_shmem (integer, `nr_shmem`)\n  - numa_hit (integer, `numa_hit`)\n  - numa_miss (integer, `numa_miss`)\n  - numa_foreign (integer, `numa_foreign`)\n  - numa_interleave (integer, `numa_interleave`)\n  - numa_local (integer, `numa_local`)\n  - numa_other (integer, `numa_other`)\n  - nr_anon_transparent_hugepages (integer, `nr_anon_transparent_hugepages`)\n  - pgpgin (integer, `pgpgin`)\n  - pgpgout (integer, `pgpgout`)\n  - pswpin (integer, `pswpin`)\n  - pswpout (integer, `pswpout`)\n  - pgalloc_dma (integer, `pgalloc_dma`)\n  - pgalloc_dma32 (integer, `pgalloc_dma32`)\n  - pgalloc_normal (integer, `pgalloc_normal`)\n  - pgalloc_movable (integer, `pgalloc_movable`)\n  - pgfree (integer, `pgfree`)\n  - pgactivate (integer, `pgactivate`)\n  - pgdeactivate (integer, `pgdeactivate`)\n  - pgfault (integer, `pgfault`)\n  - pgmajfault (integer, `pgmajfault`)\n  - pgrefill_dma (integer, `pgrefill_dma`)\n  - pgrefill_dma32 (integer, `pgrefill_dma32`)\n  - pgrefill_normal (integer, `pgrefill_normal`)\n  - pgrefill_movable (integer, `pgrefill_movable`)\n  - pgsteal_dma (integer, `pgsteal_dma`)\n  - pgsteal_dma32 (integer, `pgsteal_dma32`)\n  - pgsteal_normal (integer, `pgsteal_normal`)\n  - pgsteal_movable (integer, `pgsteal_movable`)\n  - pgscan_kswapd_dma (integer, `pgscan_kswapd_dma`)\n  - pgscan_kswapd_dma32 (integer, `pgscan_kswapd_dma32`)\n  - pgscan_kswapd_normal (integer, `pgscan_kswapd_normal`)\n  - pgscan_kswapd_movable (integer, `pgscan_kswapd_movable`)\n  - pgscan_direct_dma (integer, `pgscan_direct_dma`)\n  - pgscan_direct_dma32 (integer, `pgscan_direct_dma32`)\n  - pgscan_direct_normal (integer, `pgscan_direct_normal`)\n  - pgscan_direct_movable (integer, `pgscan_direct_movable`)\n  - zone_reclaim_failed (integer, `zone_reclaim_failed`)\n  - pginodesteal (integer, `pginodesteal`)\n  - slabs_scanned (integer, `slabs_scanned`)\n  - kswapd_steal (integer, `kswapd_steal`)\n  - kswapd_inodesteal (integer, `kswapd_inodesteal`)\n  - kswapd_low_wmark_hit_quickly (integer, `kswapd_low_wmark_hit_quickly`)\n  - kswapd_high_wmark_hit_quickly (integer, `kswapd_high_wmark_hit_quickly`)\n  - kswapd_skip_congestion_wait (integer, `kswapd_skip_congestion_wait`)\n  - pageoutrun (integer, `pageoutrun`)\n  - allocstall (integer, `allocstall`)\n  - pgrotated (integer, `pgrotated`)\n  - compact_blocks_moved (integer, `compact_blocks_moved`)\n  - compact_pages_moved (integer, `compact_pages_moved`)\n  - compact_pagemigrate_failed (integer, `compact_pagemigrate_failed`)\n  - compact_stall (integer, `compact_stall`)\n  - compact_fail (integer, `compact_fail`)\n  - compact_success (integer, `compact_success`)\n  - htlb_buddy_alloc_success (integer, `htlb_buddy_alloc_success`)\n  - htlb_buddy_alloc_fail (integer, `htlb_buddy_alloc_fail`)\n  - unevictable_pgs_culled (integer, `unevictable_pgs_culled`)\n  - unevictable_pgs_scanned (integer, `unevictable_pgs_scanned`)\n  - unevictable_pgs_rescued (integer, `unevictable_pgs_rescued`)\n  - unevictable_pgs_mlocked (integer, `unevictable_pgs_mlocked`)\n  - unevictable_pgs_munlocked (integer, `unevictable_pgs_munlocked`)\n  - unevictable_pgs_cleared (integer, `unevictable_pgs_cleared`)\n  - unevictable_pgs_stranded (integer, `unevictable_pgs_stranded`)\n  - unevictable_pgs_mlockfreed (integer, `unevictable_pgs_mlockfreed`)\n  - thp_fault_alloc (integer, `thp_fault_alloc`)\n  - thp_fault_fallback (integer, `thp_fault_fallback`)\n  - thp_collapse_alloc (integer, `thp_collapse_alloc`)\n  - thp_collapse_alloc_failed (integer, `thp_collapse_alloc_failed`)\n  - thp_split (integer, `thp_split`)\n\n## Example Output\n\n```text\nkernel_vmstat allocstall=81496i,compact_blocks_moved=238196i,compact_fail=135220i,compact_pagemigrate_failed=0i,compact_pages_moved=6370588i,compact_stall=142092i,compact_success=6872i,htlb_buddy_alloc_fail=0i,htlb_buddy_alloc_success=0i,kswapd_high_wmark_hit_quickly=25439i,kswapd_inodesteal=29770874i,kswapd_low_wmark_hit_quickly=8756i,kswapd_skip_congestion_wait=0i,kswapd_steal=291534428i,nr_active_anon=2515657i,nr_active_file=2244914i,nr_anon_pages=1358675i,nr_anon_transparent_hugepages=2034i,nr_bounce=0i,nr_dirty=5690i,nr_file_pages=5153546i,nr_free_pages=78730i,nr_inactive_anon=426259i,nr_inactive_file=2366791i,nr_isolated_anon=0i,nr_isolated_file=0i,nr_kernel_stack=579i,nr_mapped=558821i,nr_mlock=0i,nr_page_table_pages=11115i,nr_shmem=541689i,nr_slab_reclaimable=459806i,nr_slab_unreclaimable=47859i,nr_unevictable=0i,nr_unstable=0i,nr_vmscan_write=6206i,nr_writeback=0i,nr_writeback_temp=0i,numa_foreign=0i,numa_hit=5113399878i,numa_interleave=35793i,numa_local=5113399878i,numa_miss=0i,numa_other=0i,pageoutrun=505006i,pgactivate=375664931i,pgalloc_dma=0i,pgalloc_dma32=122480220i,pgalloc_movable=0i,pgalloc_normal=5233176719i,pgdeactivate=122735906i,pgfault=8699921410i,pgfree=5359765021i,pginodesteal=9188431i,pgmajfault=122210i,pgpgin=219717626i,pgpgout=3495885510i,pgrefill_dma=0i,pgrefill_dma32=1180010i,pgrefill_movable=0i,pgrefill_normal=119866676i,pgrotated=60620i,pgscan_direct_dma=0i,pgscan_direct_dma32=12256i,pgscan_direct_movable=0i,pgscan_direct_normal=31501600i,pgscan_kswapd_dma=0i,pgscan_kswapd_dma32=4480608i,pgscan_kswapd_movable=0i,pgscan_kswapd_normal=287857984i,pgsteal_dma=0i,pgsteal_dma32=4466436i,pgsteal_movable=0i,pgsteal_normal=318463755i,pswpin=2092i,pswpout=6206i,slabs_scanned=93775616i,thp_collapse_alloc=24857i,thp_collapse_alloc_failed=102214i,thp_fault_alloc=346219i,thp_fault_fallback=895453i,thp_split=9817i,unevictable_pgs_cleared=0i,unevictable_pgs_culled=1531i,unevictable_pgs_mlocked=6988i,unevictable_pgs_mlockfreed=0i,unevictable_pgs_munlocked=6988i,unevictable_pgs_rescued=5426i,unevictable_pgs_scanned=0i,unevictable_pgs_stranded=0i,zone_reclaim_failed=0i 1459455200071462843\n```\n"
  },
  {
    "path": "plugins/inputs/kernel_vmstat/kernel_vmstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage kernel_vmstat\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype KernelVmstat struct {\n\tstatFile string\n}\n\nfunc (*KernelVmstat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *KernelVmstat) Gather(acc telegraf.Accumulator) error {\n\tdata, err := k.getProcVmstat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields := make(map[string]interface{})\n\n\tdataFields := bytes.Fields(data)\n\tfor i, field := range dataFields {\n\t\t// dataFields is an array of {\"stat1_name\", \"stat1_value\", \"stat2_name\",\n\t\t// \"stat2_value\", ...}\n\t\t// We only want the even number index as that contain the stat name.\n\t\tif i%2 == 0 {\n\t\t\t// Convert the stat value into an integer.\n\t\t\tm, err := strconv.ParseInt(string(dataFields[i+1]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields[string(field)] = m\n\t\t}\n\t}\n\n\tacc.AddFields(\"kernel_vmstat\", fields, make(map[string]string))\n\treturn nil\n}\n\nfunc (k *KernelVmstat) getProcVmstat() ([]byte, error) {\n\tif _, err := os.Stat(k.statFile); os.IsNotExist(err) {\n\t\treturn nil, fmt.Errorf(\"kernel_vmstat: %s does not exist\", k.statFile)\n\t} else if err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := os.ReadFile(k.statFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc init() {\n\tinputs.Add(\"kernel_vmstat\", func() telegraf.Input {\n\t\treturn &KernelVmstat{\n\t\t\tstatFile: \"/proc/vmstat\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kernel_vmstat/kernel_vmstat_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage kernel_vmstat\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype KernelVmstat struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*KernelVmstat) SampleConfig() string { return sampleConfig }\n\nfunc (k *KernelVmstat) Init() error {\n\tk.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*KernelVmstat) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"kernel_vmstat\", func() telegraf.Input {\n\t\treturn &KernelVmstat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kernel_vmstat/kernel_vmstat_test.go",
    "content": "//go:build linux\n\npackage kernel_vmstat\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFullVmStatProcFile(t *testing.T) {\n\ttmpfile := makeFakeVMStatFile(t, []byte(vmStatFileFull))\n\tdefer os.Remove(tmpfile)\n\n\tk := KernelVmstat{\n\t\tstatFile: tmpfile,\n\t}\n\n\tacc := testutil.Accumulator{}\n\trequire.NoError(t, k.Gather(&acc))\n\n\tfields := map[string]interface{}{\n\t\t\"nr_free_pages\":                 int64(78730),\n\t\t\"nr_inactive_anon\":              int64(426259),\n\t\t\"nr_active_anon\":                int64(2515657),\n\t\t\"nr_inactive_file\":              int64(2366791),\n\t\t\"nr_active_file\":                int64(2244914),\n\t\t\"nr_unevictable\":                int64(0),\n\t\t\"nr_mlock\":                      int64(0),\n\t\t\"nr_anon_pages\":                 int64(1358675),\n\t\t\"nr_mapped\":                     int64(558821),\n\t\t\"nr_file_pages\":                 int64(5153546),\n\t\t\"nr_dirty\":                      int64(5690),\n\t\t\"nr_writeback\":                  int64(0),\n\t\t\"nr_slab_reclaimable\":           int64(459806),\n\t\t\"nr_slab_unreclaimable\":         int64(47859),\n\t\t\"nr_page_table_pages\":           int64(11115),\n\t\t\"nr_kernel_stack\":               int64(579),\n\t\t\"nr_unstable\":                   int64(0),\n\t\t\"nr_bounce\":                     int64(0),\n\t\t\"nr_vmscan_write\":               int64(6206),\n\t\t\"nr_writeback_temp\":             int64(0),\n\t\t\"nr_isolated_anon\":              int64(0),\n\t\t\"nr_isolated_file\":              int64(0),\n\t\t\"nr_shmem\":                      int64(541689),\n\t\t\"numa_hit\":                      int64(6690743595),\n\t\t\"numa_miss\":                     int64(0),\n\t\t\"numa_foreign\":                  int64(0),\n\t\t\"numa_interleave\":               int64(35793),\n\t\t\"numa_local\":                    int64(5113399878),\n\t\t\"numa_other\":                    int64(0),\n\t\t\"nr_anon_transparent_hugepages\": int64(2034),\n\t\t\"pgpgin\":                        int64(219717626),\n\t\t\"pgpgout\":                       int64(3495885510),\n\t\t\"pswpin\":                        int64(2092),\n\t\t\"pswpout\":                       int64(6206),\n\t\t\"pgalloc_dma\":                   int64(0),\n\t\t\"pgalloc_dma32\":                 int64(122480220),\n\t\t\"pgalloc_normal\":                int64(5233176719),\n\t\t\"pgalloc_movable\":               int64(0),\n\t\t\"pgfree\":                        int64(5359765021),\n\t\t\"pgactivate\":                    int64(375664931),\n\t\t\"pgdeactivate\":                  int64(122735906),\n\t\t\"pgfault\":                       int64(8699921410),\n\t\t\"pgmajfault\":                    int64(122210),\n\t\t\"pgrefill_dma\":                  int64(0),\n\t\t\"pgrefill_dma32\":                int64(1180010),\n\t\t\"pgrefill_normal\":               int64(119866676),\n\t\t\"pgrefill_movable\":              int64(0),\n\t\t\"pgsteal_dma\":                   int64(0),\n\t\t\"pgsteal_dma32\":                 int64(4466436),\n\t\t\"pgsteal_normal\":                int64(318463755),\n\t\t\"pgsteal_movable\":               int64(0),\n\t\t\"pgscan_kswapd_dma\":             int64(0),\n\t\t\"pgscan_kswapd_dma32\":           int64(4480608),\n\t\t\"pgscan_kswapd_normal\":          int64(287857984),\n\t\t\"pgscan_kswapd_movable\":         int64(0),\n\t\t\"pgscan_direct_dma\":             int64(0),\n\t\t\"pgscan_direct_dma32\":           int64(12256),\n\t\t\"pgscan_direct_normal\":          int64(31501600),\n\t\t\"pgscan_direct_movable\":         int64(0),\n\t\t\"zone_reclaim_failed\":           int64(0),\n\t\t\"pginodesteal\":                  int64(9188431),\n\t\t\"slabs_scanned\":                 int64(93775616),\n\t\t\"kswapd_steal\":                  int64(291534428),\n\t\t\"kswapd_inodesteal\":             int64(29770874),\n\t\t\"kswapd_low_wmark_hit_quickly\":  int64(8756),\n\t\t\"kswapd_high_wmark_hit_quickly\": int64(25439),\n\t\t\"kswapd_skip_congestion_wait\":   int64(0),\n\t\t\"pageoutrun\":                    int64(505006),\n\t\t\"allocstall\":                    int64(81496),\n\t\t\"pgrotated\":                     int64(60620),\n\t\t\"compact_blocks_moved\":          int64(238196),\n\t\t\"compact_pages_moved\":           int64(6370588),\n\t\t\"compact_pagemigrate_failed\":    int64(0),\n\t\t\"compact_stall\":                 int64(142092),\n\t\t\"compact_fail\":                  int64(135220),\n\t\t\"compact_success\":               int64(6872),\n\t\t\"htlb_buddy_alloc_success\":      int64(0),\n\t\t\"htlb_buddy_alloc_fail\":         int64(0),\n\t\t\"unevictable_pgs_culled\":        int64(1531),\n\t\t\"unevictable_pgs_scanned\":       int64(0),\n\t\t\"unevictable_pgs_rescued\":       int64(5426),\n\t\t\"unevictable_pgs_mlocked\":       int64(6988),\n\t\t\"unevictable_pgs_munlocked\":     int64(6988),\n\t\t\"unevictable_pgs_cleared\":       int64(0),\n\t\t\"unevictable_pgs_stranded\":      int64(0),\n\t\t\"unevictable_pgs_mlockfreed\":    int64(0),\n\t\t\"thp_fault_alloc\":               int64(346219),\n\t\t\"thp_fault_fallback\":            int64(895453),\n\t\t\"thp_collapse_alloc\":            int64(24857),\n\t\t\"thp_collapse_alloc_failed\":     int64(102214),\n\t\t\"thp_split\":                     int64(9817),\n\t}\n\tacc.AssertContainsFields(t, \"kernel_vmstat\", fields)\n}\n\nfunc TestPartialVmStatProcFile(t *testing.T) {\n\ttmpfile := makeFakeVMStatFile(t, []byte(vmStatFilePartial))\n\tdefer os.Remove(tmpfile)\n\n\tk := KernelVmstat{\n\t\tstatFile: tmpfile,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"unevictable_pgs_culled\":     int64(1531),\n\t\t\"unevictable_pgs_scanned\":    int64(0),\n\t\t\"unevictable_pgs_rescued\":    int64(5426),\n\t\t\"unevictable_pgs_mlocked\":    int64(6988),\n\t\t\"unevictable_pgs_munlocked\":  int64(6988),\n\t\t\"unevictable_pgs_cleared\":    int64(0),\n\t\t\"unevictable_pgs_stranded\":   int64(0),\n\t\t\"unevictable_pgs_mlockfreed\": int64(0),\n\t\t\"thp_fault_alloc\":            int64(346219),\n\t\t\"thp_fault_fallback\":         int64(895453),\n\t\t\"thp_collapse_alloc\":         int64(24857),\n\t\t\"thp_collapse_alloc_failed\":  int64(102214),\n\t\t\"thp_split\":                  int64(9817),\n\t}\n\tacc.AssertContainsFields(t, \"kernel_vmstat\", fields)\n}\n\nfunc TestInvalidVmStatProcFile1(t *testing.T) {\n\ttmpfile := makeFakeVMStatFile(t, []byte(vmStatFileInvalid))\n\tdefer os.Remove(tmpfile)\n\n\tk := KernelVmstat{\n\t\tstatFile: tmpfile,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"invalid syntax\")\n}\n\nfunc TestNoVmStatProcFile(t *testing.T) {\n\ttmpfile := makeFakeVMStatFile(t, []byte(vmStatFileInvalid))\n\trequire.NoError(t, os.Remove(tmpfile))\n\n\tk := KernelVmstat{\n\t\tstatFile: tmpfile,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"does not exist\")\n}\n\nconst vmStatFileFull = `nr_free_pages 78730\nnr_inactive_anon 426259\nnr_active_anon 2515657\nnr_inactive_file 2366791\nnr_active_file 2244914\nnr_unevictable 0\nnr_mlock 0\nnr_anon_pages 1358675\nnr_mapped 558821\nnr_file_pages 5153546\nnr_dirty 5690\nnr_writeback 0\nnr_slab_reclaimable 459806\nnr_slab_unreclaimable 47859\nnr_page_table_pages 11115\nnr_kernel_stack 579\nnr_unstable 0\nnr_bounce 0\nnr_vmscan_write 6206\nnr_writeback_temp 0\nnr_isolated_anon 0\nnr_isolated_file 0\nnr_shmem 541689\nnuma_hit 6690743595\nnuma_miss 0\nnuma_foreign 0\nnuma_interleave 35793\nnuma_local 5113399878\nnuma_other 0\nnr_anon_transparent_hugepages 2034\npgpgin 219717626\npgpgout 3495885510\npswpin 2092\npswpout 6206\npgalloc_dma 0\npgalloc_dma32 122480220\npgalloc_normal 5233176719\npgalloc_movable 0\npgfree 5359765021\npgactivate 375664931\npgdeactivate 122735906\npgfault 8699921410\npgmajfault 122210\npgrefill_dma 0\npgrefill_dma32 1180010\npgrefill_normal 119866676\npgrefill_movable 0\npgsteal_dma 0\npgsteal_dma32 4466436\npgsteal_normal 318463755\npgsteal_movable 0\npgscan_kswapd_dma 0\npgscan_kswapd_dma32 4480608\npgscan_kswapd_normal 287857984\npgscan_kswapd_movable 0\npgscan_direct_dma 0\npgscan_direct_dma32 12256\npgscan_direct_normal 31501600\npgscan_direct_movable 0\nzone_reclaim_failed 0\npginodesteal 9188431\nslabs_scanned 93775616\nkswapd_steal 291534428\nkswapd_inodesteal 29770874\nkswapd_low_wmark_hit_quickly 8756\nkswapd_high_wmark_hit_quickly 25439\nkswapd_skip_congestion_wait 0\npageoutrun 505006\nallocstall 81496\npgrotated 60620\ncompact_blocks_moved 238196\ncompact_pages_moved 6370588\ncompact_pagemigrate_failed 0\ncompact_stall 142092\ncompact_fail 135220\ncompact_success 6872\nhtlb_buddy_alloc_success 0\nhtlb_buddy_alloc_fail 0\nunevictable_pgs_culled 1531\nunevictable_pgs_scanned 0\nunevictable_pgs_rescued 5426\nunevictable_pgs_mlocked 6988\nunevictable_pgs_munlocked 6988\nunevictable_pgs_cleared 0\nunevictable_pgs_stranded 0\nunevictable_pgs_mlockfreed 0\nthp_fault_alloc 346219\nthp_fault_fallback 895453\nthp_collapse_alloc 24857\nthp_collapse_alloc_failed 102214\nthp_split 9817`\n\nconst vmStatFilePartial = `unevictable_pgs_culled 1531\nunevictable_pgs_scanned 0\nunevictable_pgs_rescued 5426\nunevictable_pgs_mlocked 6988\nunevictable_pgs_munlocked 6988\nunevictable_pgs_cleared 0\nunevictable_pgs_stranded 0\nunevictable_pgs_mlockfreed 0\nthp_fault_alloc 346219\nthp_fault_fallback 895453\nthp_collapse_alloc 24857\nthp_collapse_alloc_failed 102214\nthp_split 9817`\n\n// invalid thp_split measurement\nconst vmStatFileInvalid = `unevictable_pgs_culled 1531\nunevictable_pgs_scanned 0\nunevictable_pgs_rescued 5426\nunevictable_pgs_mlocked 6988\nunevictable_pgs_munlocked 6988\nunevictable_pgs_cleared 0\nunevictable_pgs_stranded 0\nunevictable_pgs_mlockfreed 0\nthp_fault_alloc 346219\nthp_fault_fallback 895453\nthp_collapse_alloc 24857\nthp_collapse_alloc_failed 102214\nthp_split abcd`\n\nfunc makeFakeVMStatFile(t *testing.T, content []byte) string {\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"kernel_vmstat_test\")\n\trequire.NoError(t, err)\n\n\t_, err = tmpfile.Write(content)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, tmpfile.Close())\n\n\treturn tmpfile.Name()\n}\n"
  },
  {
    "path": "plugins/inputs/kernel_vmstat/sample.conf",
    "content": "# Get kernel statistics from /proc/vmstat\n# This plugin ONLY supports Linux\n[[inputs.kernel_vmstat]]\n  # no configuration\n"
  },
  {
    "path": "plugins/inputs/kibana/README.md",
    "content": "# Kibana Input Plugin\n\nThis plugin collects metrics about service status from [Kibana][kibana]\ninstances via the server's API.\n\n> [!NOTE]\n> This plugin requires Kibana version 6.0+.\n\n⭐ Telegraf v1.8.0\n🏷️ applications, server\n💻 all\n\n[kibana]: https://www.elastic.co/kibana\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read status information from one or more Kibana servers\n[[inputs.kibana]]\n  ## Specify a list of one or more Kibana servers\n  servers = [\"http://localhost:5601\"]\n\n  ## Timeout for HTTP requests\n  timeout = \"5s\"\n\n  ## HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n```\n\n## Metrics\n\n- kibana\n  - tags:\n    - name (Kibana reported name)\n    - source (Kibana server hostname or IP)\n    - status (Kibana health: green, yellow, red)\n    - version (Kibana version)\n  - fields:\n    - status_code (integer, green=1 yellow=2 red=3 unknown=0)\n    - heap_total_bytes (integer)\n    - heap_max_bytes (integer; deprecated in 1.13.3: use `heap_total_bytes` field)\n    - heap_used_bytes (integer)\n    - heap_size_limit (integer)\n    - uptime_ms (integer)\n    - response_time_avg_ms (float)\n    - response_time_max_ms (integer)\n    - concurrent_connections (integer)\n    - requests_per_sec (float)\n\n## Example Output\n\n```text\nkibana,host=myhost,name=my-kibana,source=localhost:5601,status=green,version=6.5.4 concurrent_connections=8i,heap_max_bytes=447778816i,heap_total_bytes=447778816i,heap_used_bytes=380603352i,requests_per_sec=1,response_time_avg_ms=57.6,response_time_max_ms=220i,status_code=1i,uptime_ms=6717489805i 1534864502000000000\n```\n\n## Run example environment\n\nRequires the following tools:\n\n- [Docker](https://docs.docker.com/get-docker/)\n- [Docker Compose](https://docs.docker.com/compose/install/)\n\nFrom the root of this project execute the following script:\n`./plugins/inputs/kibana/test_environment/run_test_env.sh`\n\nThis will build the latest Telegraf and then start up Kibana and Elasticsearch,\nTelegraf will begin monitoring Kibana's status and write its results to the file\n`/tmp/metrics.out` in the Telegraf container.\n\nThen you can attach to the telegraf container to inspect the file\n`/tmp/metrics.out` to see if the status is being reported.\n\nThe Visual Studio Code [Remote - Containers][remote] extension provides an easy\nuser interface to attach to the running container.\n\n[remote]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers\n"
  },
  {
    "path": "plugins/inputs/kibana/kibana.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kibana\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst statusPath = \"/api/status\"\n\ntype Kibana struct {\n\tServers  []string `toml:\"servers\"`\n\tUsername string   `toml:\"username\"`\n\tPassword string   `toml:\"password\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient *http.Client\n\tcommon_http.HTTPClientConfig\n}\n\ntype kibanaStatus struct {\n\tName    string  `json:\"name\"`\n\tVersion version `json:\"version\"`\n\tStatus  status  `json:\"status\"`\n\tMetrics metrics `json:\"metrics\"`\n}\n\ntype version struct {\n\tNumber        string `json:\"number\"`\n\tBuildHash     string `json:\"build_hash\"`\n\tBuildNumber   int    `json:\"build_number\"`\n\tBuildSnapshot bool   `json:\"build_snapshot\"`\n}\n\ntype status struct {\n\tOverall  overallStatus `json:\"overall\"`\n\tStatuses interface{}   `json:\"statuses\"`\n}\n\ntype overallStatus struct {\n\t// Legacy field for Kibana < 8.x\n\tState string `json:\"state\"`\n\t// New field for Kibana 8.x+\n\tLevel string `json:\"level\"`\n}\n\ntype metrics struct {\n\tUptimeInMillis             float64       `json:\"uptime_in_millis\"`\n\tConcurrentConnections      int64         `json:\"concurrent_connections\"`\n\tCollectionIntervalInMilles int64         `json:\"collection_interval_in_millis\"`\n\tResponseTimes              responseTimes `json:\"response_times\"`\n\tProcess                    process       `json:\"process\"`\n\tRequests                   requests      `json:\"requests\"`\n}\n\ntype responseTimes struct {\n\tAvgInMillis float64 `json:\"avg_in_millis\"`\n\tMaxInMillis int64   `json:\"max_in_millis\"`\n}\n\ntype process struct {\n\tMem            mem     `json:\"mem\"`\n\tMemory         memory  `json:\"memory\"`\n\tUptimeInMillis float64 `json:\"uptime_in_millis\"`\n}\n\ntype requests struct {\n\tTotal int64 `json:\"total\"`\n}\n\ntype mem struct {\n\tHeapMaxInBytes  int64 `json:\"heap_max_in_bytes\"`\n\tHeapUsedInBytes int64 `json:\"heap_used_in_bytes\"`\n}\n\ntype memory struct {\n\tHeap heap `json:\"heap\"`\n}\n\ntype heap struct {\n\tTotalInBytes int64 `json:\"total_in_bytes\"`\n\tUsedInBytes  int64 `json:\"used_in_bytes\"`\n\tSizeLimit    int64 `json:\"size_limit\"`\n}\n\nfunc (*Kibana) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (*Kibana) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (k *Kibana) Gather(acc telegraf.Accumulator) error {\n\tif k.client == nil {\n\t\tclient, err := k.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tk.client = client\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(k.Servers))\n\n\tfor _, serv := range k.Servers {\n\t\tgo func(baseUrl string, acc telegraf.Accumulator) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := k.gatherKibanaStatus(baseUrl, acc); err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"[url=%s]: %w\", baseUrl, err))\n\t\t\t\treturn\n\t\t\t}\n\t\t}(serv, acc)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (k *Kibana) Stop() {\n\tif k.client != nil {\n\t\tk.client.CloseIdleConnections()\n\t}\n}\n\nfunc (k *Kibana) createHTTPClient() (*http.Client, error) {\n\tctx := context.Background()\n\treturn k.HTTPClientConfig.CreateClient(ctx, k.Log)\n}\n\nfunc (k *Kibana) gatherKibanaStatus(baseURL string, acc telegraf.Accumulator) error {\n\tkibanaStatus := &kibanaStatus{}\n\turl := baseURL + statusPath\n\n\thost, err := k.gatherJSONData(url, kibanaStatus)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\ttags[\"name\"] = kibanaStatus.Name\n\ttags[\"source\"] = host\n\ttags[\"version\"] = kibanaStatus.Version.Number\n\t// Get status value - check both new (8.x+) and legacy (7.x and earlier) formats\n\tstatusValue := getStatusValue(kibanaStatus.Status.Overall)\n\ttags[\"status\"] = statusValue\n\n\tfields[\"status_code\"] = mapHealthStatusToCode(statusValue)\n\tfields[\"concurrent_connections\"] = kibanaStatus.Metrics.ConcurrentConnections\n\tfields[\"response_time_avg_ms\"] = kibanaStatus.Metrics.ResponseTimes.AvgInMillis\n\tfields[\"response_time_max_ms\"] = kibanaStatus.Metrics.ResponseTimes.MaxInMillis\n\tfields[\"requests_per_sec\"] = float64(kibanaStatus.Metrics.Requests.Total) / float64(kibanaStatus.Metrics.CollectionIntervalInMilles) * 1000\n\n\tversionArray := strings.Split(kibanaStatus.Version.Number, \".\")\n\tarrayElement := 1\n\n\tif len(versionArray) > 1 {\n\t\tarrayElement = 2\n\t}\n\tversionNumber, err := strconv.ParseFloat(strings.Join(versionArray[:arrayElement], \".\"), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Same value will be assigned to both the metrics [heap_max_bytes and heap_total_bytes ]\n\t// Which keeps the code backward compatible\n\tif versionNumber >= 6.4 {\n\t\tfields[\"uptime_ms\"] = int64(kibanaStatus.Metrics.Process.UptimeInMillis)\n\t\tfields[\"heap_max_bytes\"] = kibanaStatus.Metrics.Process.Memory.Heap.TotalInBytes\n\t\tfields[\"heap_total_bytes\"] = kibanaStatus.Metrics.Process.Memory.Heap.TotalInBytes\n\t\tfields[\"heap_used_bytes\"] = kibanaStatus.Metrics.Process.Memory.Heap.UsedInBytes\n\t\tfields[\"heap_size_limit\"] = kibanaStatus.Metrics.Process.Memory.Heap.SizeLimit\n\t} else {\n\t\tfields[\"uptime_ms\"] = int64(kibanaStatus.Metrics.UptimeInMillis)\n\t\tfields[\"heap_max_bytes\"] = kibanaStatus.Metrics.Process.Mem.HeapMaxInBytes\n\t\tfields[\"heap_total_bytes\"] = kibanaStatus.Metrics.Process.Mem.HeapMaxInBytes\n\t\tfields[\"heap_used_bytes\"] = kibanaStatus.Metrics.Process.Mem.HeapUsedInBytes\n\t}\n\tacc.AddFields(\"kibana\", fields, tags)\n\n\treturn nil\n}\n\n// getStatusValue returns the status value, supporting both Kibana 8.x+ (level) and legacy (state) formats\nfunc getStatusValue(overall overallStatus) string {\n\t// Kibana 8.x+ uses \"level\" field\n\tif overall.Level != \"\" {\n\t\treturn mapKibana8xStatus(overall.Level)\n\t}\n\t// Legacy Kibana uses \"state\" field\n\tif overall.State != \"\" {\n\t\treturn overall.State\n\t}\n\treturn \"unknown\"\n}\n\n// mapKibana8xStatus maps Kibana 8.x status levels to legacy status values for backward compatibility\nfunc mapKibana8xStatus(level string) string {\n\tswitch strings.ToLower(level) {\n\tcase \"available\":\n\t\treturn \"green\"\n\tcase \"degraded\":\n\t\treturn \"yellow\"\n\tcase \"unavailable\", \"critical\":\n\t\treturn \"red\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\nfunc (k *Kibana) gatherJSONData(url string, v interface{}) (host string, err error) {\n\trequest, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to create new request %q: %w\", url, err)\n\t}\n\n\tif (k.Username != \"\") || (k.Password != \"\") {\n\t\trequest.SetBasicAuth(k.Username, k.Password)\n\t}\n\n\tresponse, err := k.client.Do(request)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer response.Body.Close()\n\n\tif response.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(response.Body, 200))\n\t\treturn request.Host, fmt.Errorf(\"%s returned HTTP status %s: %q\", url, response.Status, body)\n\t}\n\n\tif err := json.NewDecoder(response.Body).Decode(v); err != nil {\n\t\treturn request.Host, err\n\t}\n\n\treturn request.Host, nil\n}\n\n// perform status mapping\nfunc mapHealthStatusToCode(s string) int {\n\tswitch strings.ToLower(s) {\n\tcase \"green\":\n\t\treturn 1\n\tcase \"yellow\":\n\t\treturn 2\n\tcase \"red\":\n\t\treturn 3\n\t}\n\treturn 0\n}\n\nfunc newKibana() *Kibana {\n\treturn &Kibana{\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t},\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"kibana\", func() telegraf.Input {\n\t\treturn newKibana()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kibana/kibana_test.go",
    "content": "package kibana\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc defaulttags63() map[string]string {\n\treturn map[string]string{\n\t\t\"name\":    \"my-kibana\",\n\t\t\"source\":  \"example.com:5601\",\n\t\t\"version\": \"6.3.2\",\n\t\t\"status\":  \"green\",\n\t}\n}\n\nfunc defaulttags65() map[string]string {\n\treturn map[string]string{\n\t\t\"name\":    \"my-kibana\",\n\t\t\"source\":  \"example.com:5601\",\n\t\t\"version\": \"6.5.4\",\n\t\t\"status\":  \"green\",\n\t}\n}\n\nfunc defaulttags815() map[string]string {\n\treturn map[string]string{\n\t\t\"name\":    \"my-kibana\",\n\t\t\"source\":  \"example.com:5601\",\n\t\t\"version\": \"8.15.2\",\n\t\t\"status\":  \"green\", // available maps to green\n\t}\n}\n\nfunc defaulttags815Degraded() map[string]string {\n\treturn map[string]string{\n\t\t\"name\":    \"my-kibana\",\n\t\t\"source\":  \"example.com:5601\",\n\t\t\"version\": \"8.15.2\",\n\t\t\"status\":  \"yellow\", // degraded maps to yellow\n\t}\n}\n\nfunc defaulttags815Unavailable() map[string]string {\n\treturn map[string]string{\n\t\t\"name\":    \"my-kibana\",\n\t\t\"source\":  \"example.com:5601\",\n\t\t\"version\": \"8.15.2\",\n\t\t\"status\":  \"red\", // unavailable maps to red\n\t}\n}\n\ntype transportMock struct {\n\tstatusCode int\n\tbody       string\n}\n\nfunc newTransportMock(statusCode int, body string) http.RoundTripper {\n\treturn &transportMock{\n\t\tstatusCode: statusCode,\n\t\tbody:       body,\n\t}\n}\n\nfunc (t *transportMock) RoundTrip(r *http.Request) (*http.Response, error) {\n\tres := &http.Response{\n\t\tHeader:     make(http.Header),\n\t\tRequest:    r,\n\t\tStatusCode: t.statusCode,\n\t}\n\tres.Header.Set(\"Content-Type\", \"application/json\")\n\tres.Body = io.NopCloser(strings.NewReader(t.body))\n\treturn res, nil\n}\n\nfunc checkKibanaStatusResult(version, statusLevel string, t *testing.T, acc *testutil.Accumulator) {\n\tswitch version {\n\tcase \"6.3.2\":\n\t\ttags := defaulttags63()\n\t\tacc.AssertContainsTaggedFields(t, \"kibana\", kibanastatusexpected63, tags)\n\tcase \"6.5.4\":\n\t\ttags := defaulttags65()\n\t\tacc.AssertContainsTaggedFields(t, \"kibana\", kibanastatusexpected65, tags)\n\tcase \"8.15.2\":\n\t\tswitch statusLevel {\n\t\tcase \"available\":\n\t\t\ttags := defaulttags815()\n\t\t\tacc.AssertContainsTaggedFields(t, \"kibana\", kibanastatusexpected815, tags)\n\t\tcase \"degraded\":\n\t\t\ttags := defaulttags815Degraded()\n\t\t\tacc.AssertContainsTaggedFields(t, \"kibana\", kibanastatusexpected815Degraded, tags)\n\t\tcase \"unavailable\":\n\t\t\ttags := defaulttags815Unavailable()\n\t\t\tacc.AssertContainsTaggedFields(t, \"kibana\", kibanastatusexpected815Unavailable, tags)\n\t\t}\n\t}\n}\n\nfunc TestGather(t *testing.T) {\n\tks := newKibanahWithClient()\n\tks.Servers = []string{\"http://example.com:5601\"}\n\n\t// Unit test for Kibana version < 6.4\n\tks.client.Transport = newTransportMock(http.StatusOK, kibanastatusresponse63)\n\tvar acc1 testutil.Accumulator\n\tif err := acc1.GatherError(ks.Gather); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcheckKibanaStatusResult(defaulttags63()[\"version\"], \"\", t, &acc1)\n\n\t// Unit test for Kibana version >= 6.4\n\tks.client.Transport = newTransportMock(http.StatusOK, kibanastatusresponse65)\n\tvar acc2 testutil.Accumulator\n\tif err := acc2.GatherError(ks.Gather); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcheckKibanaStatusResult(defaulttags65()[\"version\"], \"\", t, &acc2)\n\n\t// Unit test for Kibana 8.x with \"available\" status\n\tks.client.Transport = newTransportMock(http.StatusOK, kibanastatusresponse815)\n\tvar acc3 testutil.Accumulator\n\tif err := acc3.GatherError(ks.Gather); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcheckKibanaStatusResult(defaulttags815()[\"version\"], \"available\", t, &acc3)\n\n\t// Unit test for Kibana 8.x with \"degraded\" status\n\tks.client.Transport = newTransportMock(http.StatusOK, kibanastatusresponse815Degraded)\n\tvar acc4 testutil.Accumulator\n\tif err := acc4.GatherError(ks.Gather); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcheckKibanaStatusResult(defaulttags815()[\"version\"], \"degraded\", t, &acc4)\n\n\t// Unit test for Kibana 8.x with \"unavailable\" status\n\tks.client.Transport = newTransportMock(http.StatusOK, kibanastatusresponse815Unavailable)\n\tvar acc5 testutil.Accumulator\n\tif err := acc5.GatherError(ks.Gather); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcheckKibanaStatusResult(defaulttags815()[\"version\"], \"unavailable\", t, &acc5)\n}\n\n// Test error handling with different HTTP status codes\nfunc TestGatherErrors(t *testing.T) {\n\tks := newKibanahWithClient()\n\tks.Servers = []string{\"http://example.com:5601\"}\n\n\t// Test 500 Internal Server Error\n\tks.client.Transport = newTransportMock(http.StatusInternalServerError, `{\"error\": \"internal server error\"}`)\n\tvar acc1 testutil.Accumulator\n\terr := acc1.GatherError(ks.Gather)\n\tif err == nil {\n\t\tt.Fatal(\"Expected error for 500 status code\")\n\t}\n\n\t// Test 404 Not Found\n\tks.client.Transport = newTransportMock(http.StatusNotFound, `{\"error\": \"not found\"}`)\n\tvar acc2 testutil.Accumulator\n\terr = acc2.GatherError(ks.Gather)\n\tif err == nil {\n\t\tt.Fatal(\"Expected error for 404 status code\")\n\t}\n\n\t// Test 401 Unauthorized\n\tks.client.Transport = newTransportMock(http.StatusUnauthorized, `{\"error\": \"unauthorized\"}`)\n\tvar acc3 testutil.Accumulator\n\terr = acc3.GatherError(ks.Gather)\n\tif err == nil {\n\t\tt.Fatal(\"Expected error for 401 status code\")\n\t}\n\n\t// Test 503 Service Unavailable\n\tks.client.Transport = newTransportMock(http.StatusServiceUnavailable, `{\"error\": \"service unavailable\"}`)\n\tvar acc4 testutil.Accumulator\n\terr = acc4.GatherError(ks.Gather)\n\tif err == nil {\n\t\tt.Fatal(\"Expected error for 503 status code\")\n\t}\n}\n\n// Test invalid JSON response\nfunc TestGatherInvalidJSON(t *testing.T) {\n\tks := newKibanahWithClient()\n\tks.Servers = []string{\"http://example.com:5601\"}\n\n\t// Test invalid JSON\n\tks.client.Transport = newTransportMock(http.StatusOK, `{invalid json}`)\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(ks.Gather)\n\tif err == nil {\n\t\tt.Fatal(\"Expected error for invalid JSON\")\n\t}\n}\n\n// Test status mapping functions specifically\nfunc TestStatusMapping(t *testing.T) {\n\t// Test legacy status mapping (Kibana 7.x and earlier)\n\ttestCases := []struct {\n\t\tinput    string\n\t\texpected int\n\t}{\n\t\t{\"green\", 1},\n\t\t{\"yellow\", 2},\n\t\t{\"red\", 3},\n\t\t{\"unknown\", 0},\n\t\t{\"\", 0},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tresult := mapHealthStatusToCode(tc.input)\n\t\tif result != tc.expected {\n\t\t\tt.Errorf(\"mapHealthStatusToCode(%q) = %d, expected %d\", tc.input, result, tc.expected)\n\t\t}\n\t}\n}\n\n// Test Kibana 8.x status level mapping\nfunc TestKibana8xStatusMapping(t *testing.T) {\n\ttestCases := []struct {\n\t\tlevel    string\n\t\texpected string\n\t}{\n\t\t{\"available\", \"green\"},\n\t\t{\"degraded\", \"yellow\"},\n\t\t{\"unavailable\", \"red\"},\n\t\t{\"critical\", \"red\"},\n\t\t{\"unknown\", \"unknown\"},\n\t\t{\"\", \"unknown\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tresult := mapKibana8xStatus(tc.level)\n\t\tif result != tc.expected {\n\t\t\tt.Errorf(\"mapKibana8xStatus(%q) = %q, expected %q\", tc.level, result, tc.expected)\n\t\t}\n\t}\n}\n\n// Test getStatusValue function with both legacy and new formats\nfunc TestGetStatusValue(t *testing.T) {\n\ttestCases := []struct {\n\t\tname     string\n\t\toverall  overallStatus\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"Legacy green state\",\n\t\t\toverall:  overallStatus{State: \"green\"},\n\t\t\texpected: \"green\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Legacy yellow state\",\n\t\t\toverall:  overallStatus{State: \"yellow\"},\n\t\t\texpected: \"yellow\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Kibana 8.x available level\",\n\t\t\toverall:  overallStatus{Level: \"available\"},\n\t\t\texpected: \"green\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Kibana 8.x degraded level\",\n\t\t\toverall:  overallStatus{Level: \"degraded\"},\n\t\t\texpected: \"yellow\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Kibana 8.x unavailable level\",\n\t\t\toverall:  overallStatus{Level: \"unavailable\"},\n\t\t\texpected: \"red\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Kibana 8.x critical level\",\n\t\t\toverall:  overallStatus{Level: \"critical\"},\n\t\t\texpected: \"red\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Both fields present, level takes precedence\",\n\t\t\toverall:  overallStatus{State: \"green\", Level: \"degraded\"},\n\t\t\texpected: \"yellow\",\n\t\t},\n\t\t{\n\t\t\tname:     \"No fields present\",\n\t\t\toverall:  overallStatus{},\n\t\t\texpected: \"unknown\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tresult := getStatusValue(tc.overall)\n\t\t\tif result != tc.expected {\n\t\t\t\tt.Errorf(\"getStatusValue(%+v) = %q, expected %q\", tc.overall, result, tc.expected)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc newKibanahWithClient() *Kibana {\n\tks := newKibana()\n\tks.client = &http.Client{}\n\treturn ks\n}\n"
  },
  {
    "path": "plugins/inputs/kibana/sample.conf",
    "content": "# Read status information from one or more Kibana servers\n[[inputs.kibana]]\n  ## Specify a list of one or more Kibana servers\n  servers = [\"http://localhost:5601\"]\n\n  ## Timeout for HTTP requests\n  timeout = \"5s\"\n\n  ## HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n"
  },
  {
    "path": "plugins/inputs/kibana/test_environment/basic_kibana_telegraf.conf",
    "content": "# Telegraf Configuration for basic Kibana example\n\n# Configuration for telegraf agent\n[agent]\n  ## Default data collection interval for all inputs\n  interval = \"10s\"\n  ## Rounds collection interval to 'interval'\n  ## ie, if interval=\"10s\" then always collect on :00, :10, :20, etc.\n  round_interval = true\n\n  ## Telegraf will send metrics to outputs in batches of at most\n  ## metric_batch_size metrics.\n  ## This controls the size of writes that Telegraf sends to output plugins.\n  metric_batch_size = 1000\n\n  ## Maximum number of unwritten metrics per output.  Increasing this value\n  ## allows for longer periods of output downtime without dropping metrics at the\n  ## cost of higher maximum memory usage.\n  metric_buffer_limit = 10000\n\n  ## Collection jitter is used to jitter the collection by a random amount.\n  ## Each plugin will sleep for a random time within jitter before collecting.\n  ## This can be used to avoid many plugins querying things like sysfs at the\n  ## same time, which can have a measurable effect on the system.\n  collection_jitter = \"0s\"\n\n  ## Default flushing interval for all outputs. Maximum flush_interval will be\n  ## flush_interval + flush_jitter\n  flush_interval = \"10s\"\n  ## Jitter the flush interval by a random amount. This is primarily to avoid\n  ## large write spikes for users running a large number of telegraf instances.\n  ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s\n  flush_jitter = \"0s\"\n\n  ## By default or when set to \"0s\", precision will be set to the same\n  ## timestamp order as the collection interval, with the maximum being 1s.\n  ##   ie, when interval = \"10s\", precision will be \"1s\"\n  ##       when interval = \"250ms\", precision will be \"1ms\"\n  ## Precision will NOT be used for service inputs. It is up to each individual\n  ## service input to set the timestamp at the appropriate precision.\n  ## Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\".\n  precision = \"\"\n\n  ## Override default hostname, if empty use os.Hostname()\n  hostname = \"\"\n  ## If set to true, do no set the \"host\" tag in the telegraf agent.\n  omit_hostname = false\n\n\n###############################################################################\n#                            OUTPUT PLUGINS                                   #\n###############################################################################\n\n# Send telegraf metrics to file(s)\n[[outputs.file]]\n  ## Files to write to, \"stdout\" is a specially handled file.\n  files = [\"stdout\", \"/tmp/metrics.out\"]\n\n  ## Data format to output.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md\n  data_format = \"influx\"\n\n###############################################################################\n#                            INPUT PLUGINS                                    #\n###############################################################################\n\n# Read status information from one or more Kibana servers\n[[inputs.kibana]]\n  ## Specify a list of one or more Kibana servers\n  servers = [\"http://kib01:5601\"]\n\n  ## Timeout for HTTP requests\n  timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/kibana/test_environment/docker-compose.yml",
    "content": "## Reference: https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run-dev-mode\nversion: '2.2'\nservices:\n  es01:\n    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.1\n    container_name: es01\n    environment:\n      - node.name=es01\n      - cluster.name=es-docker-cluster\n      - cluster.initial_master_nodes=es01\n      - bootstrap.memory_lock=true\n      - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n    ulimits:\n      memlock:\n        soft: -1\n        hard: -1\n    volumes:\n      - data01:/usr/share/elasticsearch/data\n    ports:\n      - 9200:9200\n    networks:\n      - elastic\n\n  kib01:\n    image: docker.elastic.co/kibana/kibana:7.10.1\n    container_name: kib01\n    ports:\n      - 5601:5601\n    environment:\n      ELASTICSEARCH_URL: http://es01:9200\n      ELASTICSEARCH_HOSTS: http://es01:9200\n    networks:\n      - elastic\n\n  telegraf:\n    image: local_telegraf\n    volumes:\n      - ./basic_kibana_telegraf.conf:/etc/telegraf/telegraf.conf:ro\n    networks:\n      - elastic\n\nvolumes:\n  data01:\n    driver: local\n\nnetworks:\n  elastic:\n    driver: bridge\n"
  },
  {
    "path": "plugins/inputs/kibana/test_environment/run_test_env.sh",
    "content": "#!/bin/sh\n\ndocker build -t local_telegraf -f scripts/alpine.docker .\n\ndocker-compose -f plugins/inputs/kibana/test_environment/docker-compose.yml up\n"
  },
  {
    "path": "plugins/inputs/kibana/testdata_test6_3.go",
    "content": "package kibana\n\nconst kibanastatusresponse63 = `\n{\n\t\"name\": \"my-kibana\",\n\t\"uuid\": \"00000000-0000-0000-0000-000000000000\",\n\t\"version\": {\n\t\t\"number\": \"6.3.2\",\n\t\t\"build_hash\": \"53d0c6758ac3fb38a3a1df198c1d4c87765e63f7\",\n\t\t\"build_number\": 17307,\n\t\t\"build_snapshot\": false\n\t},\n\t\"status\": {\n\t\t\"overall\": {\n\t\t\t\"state\": \"green\",\n\t\t\t\"title\": \"Green\",\n\t\t\t\"nickname\": \"Looking good\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.567Z\"\n\t\t},\n\t\t\"statuses\": [{\n\t\t\t\"id\": \"plugin:kibana@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.567Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:elasticsearch@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:04.920Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:xpack_main@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.393Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:searchprofiler@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.395Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:tilemap@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.396Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:watcher@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.397Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:license_management@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.668Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:index_management@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.399Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:timelion@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.912Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:logtrail@0.1.29\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.919Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:monitoring@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.922Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:grokdebugger@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.400Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:dashboard_mode@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.928Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:logstash@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.401Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:apm@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.950Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:console@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.958Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:console_extensions@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.961Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:metrics@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.965Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:reporting@6.3.2\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.402Z\"\n\t\t}]\n\t},\n\t\"metrics\": {\n\t\t\"last_updated\": \"2018-08-21T11:24:25.823Z\",\n\t\t\"collection_interval_in_millis\": 5000,\n\t\t\"uptime_in_millis\": 2173595336,\n\t\t\"process\": {\n\t\t\t\"mem\": {\n\t\t\t\t\"heap_max_in_bytes\": 149954560,\n\t\t\t\t\"heap_used_in_bytes\": 126274392\n\t\t\t}\n\t\t},\n\t\t\"os\": {\n\t\t\t\"cpu\": {\n\t\t\t\t\"load_average\": {\n\t\t\t\t\t\"1m\": 0.1806640625,\n\t\t\t\t\t\"5m\": 0.49658203125,\n\t\t\t\t\t\"15m\": 0.458984375\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"response_times\": {\n\t\t\t\"avg_in_millis\": 12.5,\n\t\t\t\"max_in_millis\": 123\n\t\t},\n\t\t\"requests\": {\n\t\t\t\"total\": 2,\n\t\t\t\"disconnects\": 0,\n\t\t\t\"status_codes\": {\n\t\t\t\t\"200\": 2\n\t\t\t}\n\t\t},\n\t\t\"concurrent_connections\": 10\n\t}\n}\n`\n\nvar kibanastatusexpected63 = map[string]interface{}{\n\t\"status_code\":            1,\n\t\"heap_total_bytes\":       int64(149954560),\n\t\"heap_max_bytes\":         int64(149954560),\n\t\"heap_used_bytes\":        int64(126274392),\n\t\"uptime_ms\":              int64(2173595336),\n\t\"response_time_avg_ms\":   float64(12.5),\n\t\"response_time_max_ms\":   int64(123),\n\t\"concurrent_connections\": int64(10),\n\t\"requests_per_sec\":       float64(0.4),\n}\n"
  },
  {
    "path": "plugins/inputs/kibana/testdata_test6_5.go",
    "content": "package kibana\n\nconst kibanastatusresponse65 = `\n{\n\t\"name\": \"my-kibana\",\n\t\"uuid\": \"00000000-0000-0000-0000-000000000000\",\n\t\"version\": {\n\t\t\"number\": \"6.5.4\",\n\t\t\"build_hash\": \"53d0c6758ac3fb38a3a1df198c1d4c87765e63f7\",\n\t\t\"build_number\": 17307,\n\t\t\"build_snapshot\": false\n\t},\n\t\"status\": {\n\t\t\"overall\": {\n\t\t\t\"state\": \"green\",\n\t\t\t\"title\": \"Green\",\n\t\t\t\"nickname\": \"Looking good\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.567Z\"\n\t\t},\n\t\t\"statuses\": [{\n\t\t\t\"id\": \"plugin:kibana@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.567Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:elasticsearch@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:04.920Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:xpack_main@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.393Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:searchprofiler@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.395Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:tilemap@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.396Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:watcher@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.397Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:license_management@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.668Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:index_management@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.399Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:timelion@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.912Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:logtrail@0.1.29\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.919Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:monitoring@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.922Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:grokdebugger@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.400Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:dashboard_mode@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.928Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:logstash@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.401Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:apm@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.950Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:console@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.958Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:console_extensions@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.961Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:metrics@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-27T07:37:42.965Z\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"plugin:reporting@6.5.4\",\n\t\t\t\"state\": \"green\",\n\t\t\t\"icon\": \"success\",\n\t\t\t\"message\": \"Ready\",\n\t\t\t\"since\": \"2018-07-28T10:07:02.402Z\"\n\t\t}]\n\t},\n\t\"metrics\": {\n\t\t\"last_updated\": \"2020-01-15T09:40:17.733Z\",\n\t\t\"collection_interval_in_millis\": 5000,\n\t\t\"process\": {\n\t\t\t\"memory\": {\n\t\t\t\t\"heap\": {\n          \t\t\t\t\"total_in_bytes\": 149954560,\n          \t\t\t\t\"used_in_bytes\": 126274392,\n          \t\t\t\t\"size_limit\": 1501560832\n        \t\t\t\t},\n        \t\t\t\"resident_set_size_in_bytes\": 286650368\n      \t\t\t\t},\n      \t\t\t\"event_loop_delay\": 0.5314235687255859,\n      \t\t\t\"pid\": 6,\n      \t\t\t\"uptime_in_millis\": 2173595336.9999999998\n    \t\t},\n    \t\t\"os\": {\n      \t\t\t\"load\": {\n        \t\t\t\"1m\": 2.66015625,\n        \t\t\t\"5m\": 2.8173828125,\n        \t\t\t\"15m\": 2.51025390625\n      \t\t\t},\n      \t\t\t\"memory\": {\n        \t\t\t\"total_in_bytes\": 404355756032,\n        \t\t\t\"free_in_bytes\": 294494244864,\n        \t\t\t\"used_in_bytes\": 109861511168\n      \t\t\t},\n      \t\t\t\"uptime_in_millis\": 8220745000,\n      \t\t\t\"cgroup\": {\n        \t\t\t\"cpuacct\": {\n          \t\t\t\t\"control_group\": \"/\",\n          \t\t\t\t\"usage_nanos\": 1086527218898\n        \t\t\t},\n        \t\t\t\"cpu\": {\n          \t\t\t\t\"control_group\": \"/\",\n          \t\t\t\t\"cfs_period_micros\": 100000,\n          \t\t\t\t\"cfs_quota_micros\": -1,\n          \t\t\t\t\"stat\": {\n            \t\t\t\t\t\"number_of_elapsed_periods\": 0,\n            \t\t\t\t\t\"number_of_times_throttled\": 0,\n            \t\t\t\t\t\"time_throttled_nanos\": 0\n          \t\t\t\t\t}\n        \t\t\t\t}\n      \t\t\t\t}\n    \t\t\t},\n    \t\t\"response_times\": {\n      \t\t\t\"avg_in_millis\": 12.5,\n      \t\t\t\"max_in_millis\": 123\n    \t\t},\n    \t\t\"requests\": {\n      \t\t\t\"total\": 2,\n      \t\t\t\"disconnects\": 0,\n      \t\t\t\"status_codes\": {\n        \t\t\t\"200\": 1,\n        \t\t\t\"304\": 1\n      \t\t\t\t}\n    \t\t},\n    \t\t\"concurrent_connections\": 10\n  }\n}\n`\n\nvar kibanastatusexpected65 = map[string]interface{}{\n\t\"status_code\":            1,\n\t\"heap_total_bytes\":       int64(149954560),\n\t\"heap_max_bytes\":         int64(149954560),\n\t\"heap_used_bytes\":        int64(126274392),\n\t\"heap_size_limit\":        int64(1501560832),\n\t\"uptime_ms\":              int64(2173595337),\n\t\"response_time_avg_ms\":   float64(12.5),\n\t\"response_time_max_ms\":   int64(123),\n\t\"concurrent_connections\": int64(10),\n\t\"requests_per_sec\":       float64(0.4),\n}\n"
  },
  {
    "path": "plugins/inputs/kibana/testdata_test8_15.go",
    "content": "package kibana\n\n// Kibana 8.x test data with new \"level\" field\nconst kibanastatusresponse815 = `\n{\n\t\"name\": \"my-kibana\",\n\t\"uuid\": \"00000000-0000-0000-0000-000000000000\",\n\t\"version\": {\n\t\t\"number\": \"8.15.2\",\n\t\t\"build_hash\": \"bd7e2f0e02aa2ff6de58cfc9c70ac1aa6f84b2e7\",\n\t\t\"build_number\": 76543,\n\t\t\"build_snapshot\": false\n\t},\n\t\"status\": {\n\t\t\"overall\": {\n\t\t\t\"level\": \"available\",\n\t\t\t\"summary\": \"Kibana is operating normally\"\n\t\t},\n\t\t\"core\": {\n\t\t\t\"elasticsearch\": {\n\t\t\t\t\"level\": \"available\",\n\t\t\t\t\"summary\": \"Elasticsearch is available\"\n\t\t\t},\n\t\t\t\"savedObjects\": {\n\t\t\t\t\"level\": \"available\", \n\t\t\t\t\"summary\": \"SavedObjects service has completed migrations and is available\"\n\t\t\t}\n\t\t},\n\t\t\"plugins\": {\n\t\t\t\"monitoring\": {\n\t\t\t\t\"level\": \"available\",\n\t\t\t\t\"summary\": \"Ready\"\n\t\t\t},\n\t\t\t\"security\": {\n\t\t\t\t\"level\": \"available\",\n\t\t\t\t\"summary\": \"Ready\"\n\t\t\t}\n\t\t}\n\t},\n\t\"metrics\": {\n\t\t\"last_updated\": \"2025-01-15T09:40:17.733Z\",\n\t\t\"collection_interval_in_millis\": 5000,\n\t\t\"process\": {\n\t\t\t\"memory\": {\n\t\t\t\t\"heap\": {\n\t\t\t\t\t\"total_in_bytes\": 505769984,\n\t\t\t\t\t\"used_in_bytes\": 411445984,\n\t\t\t\t\t\"size_limit\": 2197815296\n\t\t\t\t},\n\t\t\t\t\"resident_set_size_in_bytes\": 625000000\n\t\t\t},\n\t\t\t\"event_loop_delay\": 1.2,\n\t\t\t\"pid\": 1,\n\t\t\t\"uptime_in_millis\": 1039853908\n\t\t},\n\t\t\"os\": {\n\t\t\t\"load\": {\n\t\t\t\t\"1m\": 1.5,\n\t\t\t\t\"5m\": 1.8,\n\t\t\t\t\"15m\": 2.1\n\t\t\t},\n\t\t\t\"memory\": {\n\t\t\t\t\"total_in_bytes\": 8589934592,\n\t\t\t\t\"free_in_bytes\": 4294967296,\n\t\t\t\t\"used_in_bytes\": 4294967296\n\t\t\t},\n\t\t\t\"uptime_in_millis\": 86400000\n\t\t},\n\t\t\"response_times\": {\n\t\t\t\"avg_in_millis\": 6,\n\t\t\t\"max_in_millis\": 11\n\t\t},\n\t\t\"requests\": {\n\t\t\t\"total\": 2,\n\t\t\t\"disconnects\": 0,\n\t\t\t\"status_codes\": {\n\t\t\t\t\"200\": 2\n\t\t\t}\n\t\t},\n\t\t\"concurrent_connections\": 1\n\t}\n}\n`\n\n// Test data for Kibana 8.x with degraded status\nconst kibanastatusresponse815Degraded = `\n{\n\t\"name\": \"my-kibana\",\n\t\"uuid\": \"00000000-0000-0000-0000-000000000000\",\n\t\"version\": {\n\t\t\"number\": \"8.15.2\",\n\t\t\"build_hash\": \"bd7e2f0e02aa2ff6de58cfc9c70ac1aa6f84b2e7\",\n\t\t\"build_number\": 76543,\n\t\t\"build_snapshot\": false\n\t},\n\t\"status\": {\n\t\t\"overall\": {\n\t\t\t\"level\": \"degraded\",\n\t\t\t\"summary\": \"Kibana is degraded\"\n\t\t}\n\t},\n\t\"metrics\": {\n\t\t\"last_updated\": \"2025-01-15T09:40:17.733Z\",\n\t\t\"collection_interval_in_millis\": 5000,\n\t\t\"process\": {\n\t\t\t\"memory\": {\n\t\t\t\t\"heap\": {\n\t\t\t\t\t\"total_in_bytes\": 505769984,\n\t\t\t\t\t\"used_in_bytes\": 411445984,\n\t\t\t\t\t\"size_limit\": 2197815296\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"uptime_in_millis\": 1039853908\n\t\t},\n\t\t\"response_times\": {\n\t\t\t\"avg_in_millis\": 6,\n\t\t\t\"max_in_millis\": 11\n\t\t},\n\t\t\"requests\": {\n\t\t\t\"total\": 2\n\t\t},\n\t\t\"concurrent_connections\": 1\n\t}\n}\n`\n\n// Test data for Kibana 8.x with unavailable status\nconst kibanastatusresponse815Unavailable = `\n{\n\t\"name\": \"my-kibana\",\n\t\"uuid\": \"00000000-0000-0000-0000-000000000000\",\n\t\"version\": {\n\t\t\"number\": \"8.15.2\",\n\t\t\"build_hash\": \"bd7e2f0e02aa2ff6de58cfc9c70ac1aa6f84b2e7\",\n\t\t\"build_number\": 76543,\n\t\t\"build_snapshot\": false\n\t},\n\t\"status\": {\n\t\t\"overall\": {\n\t\t\t\"level\": \"unavailable\",\n\t\t\t\"summary\": \"Kibana is unavailable\"\n\t\t}\n\t},\n\t\"metrics\": {\n\t\t\"last_updated\": \"2025-01-15T09:40:17.733Z\",\n\t\t\"collection_interval_in_millis\": 5000,\n\t\t\"process\": {\n\t\t\t\"memory\": {\n\t\t\t\t\"heap\": {\n\t\t\t\t\t\"total_in_bytes\": 505769984,\n\t\t\t\t\t\"used_in_bytes\": 411445984,\n\t\t\t\t\t\"size_limit\": 2197815296\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"uptime_in_millis\": 1039853908\n\t\t},\n\t\t\"response_times\": {\n\t\t\t\"avg_in_millis\": 6,\n\t\t\t\"max_in_millis\": 11\n\t\t},\n\t\t\"requests\": {\n\t\t\t\"total\": 2\n\t\t},\n\t\t\"concurrent_connections\": 1\n\t}\n}\n`\n\nvar kibanastatusexpected815 = map[string]interface{}{\n\t\"status_code\":            1, // available -> green -> 1\n\t\"heap_total_bytes\":       int64(505769984),\n\t\"heap_max_bytes\":         int64(505769984),\n\t\"heap_used_bytes\":        int64(411445984),\n\t\"heap_size_limit\":        int64(2197815296),\n\t\"uptime_ms\":              int64(1039853908),\n\t\"response_time_avg_ms\":   float64(6),\n\t\"response_time_max_ms\":   int64(11),\n\t\"concurrent_connections\": int64(1),\n\t\"requests_per_sec\":       float64(0.4),\n}\n\nvar kibanastatusexpected815Degraded = map[string]interface{}{\n\t\"status_code\":            2, // degraded -> yellow -> 2\n\t\"heap_total_bytes\":       int64(505769984),\n\t\"heap_max_bytes\":         int64(505769984),\n\t\"heap_used_bytes\":        int64(411445984),\n\t\"heap_size_limit\":        int64(2197815296),\n\t\"uptime_ms\":              int64(1039853908),\n\t\"response_time_avg_ms\":   float64(6),\n\t\"response_time_max_ms\":   int64(11),\n\t\"concurrent_connections\": int64(1),\n\t\"requests_per_sec\":       float64(0.4),\n}\n\nvar kibanastatusexpected815Unavailable = map[string]interface{}{\n\t\"status_code\":            3, // unavailable -> red -> 3\n\t\"heap_total_bytes\":       int64(505769984),\n\t\"heap_max_bytes\":         int64(505769984),\n\t\"heap_used_bytes\":        int64(411445984),\n\t\"heap_size_limit\":        int64(2197815296),\n\t\"uptime_ms\":              int64(1039853908),\n\t\"response_time_avg_ms\":   float64(6),\n\t\"response_time_max_ms\":   int64(11),\n\t\"concurrent_connections\": int64(1),\n\t\"requests_per_sec\":       float64(0.4),\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/README.md",
    "content": "# Kinesis Consumer Input Plugin\n\nThis service input plugin consumes messages from [AWS Kinesis][kinesis] data\nstream in one of the supported [data formats][data_formats].\n\n⭐ Telegraf v1.10.0\n🏷️ messaging, iot\n💻 all\n\n[kinesis]: https://aws.amazon.com/kinesis/\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Configuration for the AWS Kinesis input.\n[[inputs.kinesis_consumer]]\n  ## Amazon REGION of kinesis endpoint.\n  region = \"ap-southeast-2\"\n\n  ## Amazon Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Web identity provider credentials via STS if role_arn and web_identity_token_file are specified\n  ## 2) Assumed credentials via STS if role_arn is specified\n  ## 3) explicit credentials from 'access_key' and 'secret_key'\n  ## 4) shared profile from 'profile'\n  ## 5) environment variables\n  ## 6) shared credentials file\n  ## 7) EC2 Instance Profile\n  # access_key = \"\"\n  # secret_key = \"\"\n  # token = \"\"\n  # role_arn = \"\"\n  # web_identity_token_file = \"\"\n  # role_session_name = \"\"\n  # profile = \"\"\n  # shared_credential_file = \"\"\n\n  ## Endpoint to make request against, the correct endpoint is automatically\n  ## determined and this option should only be set if you wish to override the\n  ## default.\n  ##   ex: endpoint_url = \"http://localhost:8000\"\n  # endpoint_url = \"\"\n\n  ## Kinesis StreamName must exist prior to starting telegraf.\n  streamname = \"StreamName\"\n\n  ## Shard iterator type\n  ## Available options: 'TRIM_HORIZON' (first in non-expired) and 'LATEST'\n  # shard_iterator_type = \"TRIM_HORIZON\"\n\n  ## Interval for checking for new records\n  ## Please consider limits for getting records documented here:\n  ## https://docs.aws.amazon.com/streams/latest/dev/service-sizes-and-limits.html\n  # poll_interval = \"250ms\"\n\n  ## Interval for scanning for new shards created when resharding\n  ## If set to zero, shards are only scanned once on startup.\n  # shard_update_interval = \"30s\"\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Content encoding of the record data\n  ## If you are processing a cloudwatch logs kinesis stream then set this to\n  ## \"gzip\" as AWS compresses cloudwatch log data before it is sent to kinesis.\n  # content_encoding = \"identity\"\n\n  ## Data format of the records to consume\n  ## See https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n\n  ## Optional: Configuration for DynamoDB backend to store positions in the stream\n  # [inputs.kinesis_consumer.checkpoint_dynamodb]\n  #   ## Unique name for this consumer\n  #   app_name = \"default\"\n  #   ## Table to store the sequence numbers in\n  #   table_name = \"default\"\n  #   ## Interval for persisting data to limit write operations\n  #   # interval = \"10s\"\n```\n\n### Required AWS IAM permissions\n\nKinesis:\n\n- DescribeStream\n- GetRecords\n- GetShardIterator\n\nDynamoDB:\n\n- GetItem\n- PutItem\n\n### DynamoDB Checkpoint\n\nThe DynamoDB checkpoint stores the last processed record in a DynamoDB. To\nleverage this functionality, create a table with the following string type keys:\n\n```shell\nPartition key: namespace\nSort key: shard_id\n```\n\n## Metrics\n\nThe plugin accepts arbitrary input and parses it according to the `data_format`\nsetting. There is no predefined metric format.\n\n## Example Output\n\nThere is no predefined metric format, so output depends on plugin input.\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/consumer.go",
    "content": "package kinesis_consumer\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kinesis\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kinesis/types\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype recordHandler func(ctx context.Context, shard string, r *types.Record)\n\ntype shardConsumer struct {\n\tseqnr    string\n\tinterval time.Duration\n\tlog      telegraf.Logger\n\n\tclient *kinesis.Client\n\tparams *kinesis.GetShardIteratorInput\n\n\tonMessage recordHandler\n}\n\nfunc (c *shardConsumer) consume(ctx context.Context, shard string) ([]types.ChildShard, error) {\n\tticker := time.NewTicker(c.interval)\n\tdefer ticker.Stop()\n\n\t// Get the first shard iterator\n\titer, err := c.iterator(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting first shard iterator failed: %w\", err)\n\t}\n\n\tfor {\n\t\t// Get new records from the shard\n\t\tresp, err := c.client.GetRecords(ctx, &kinesis.GetRecordsInput{\n\t\t\tShardIterator: iter,\n\t\t})\n\t\tif err != nil {\n\t\t\t// Handle recoverable errors\n\t\t\tvar throughputErr *types.ProvisionedThroughputExceededException\n\t\t\tvar expiredIterErr *types.ExpiredIteratorException\n\t\t\tswitch {\n\t\t\tcase errors.As(err, &throughputErr):\n\t\t\t\t// Wait a second before trying again as suggested by\n\t\t\t\t// https://docs.aws.amazon.com/streams/latest/dev/service-sizes-and-limits.html\n\t\t\t\tc.log.Tracef(\"throughput exceeded when getting records for shard %s...\", shard)\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\tcase errors.As(err, &expiredIterErr):\n\t\t\t\tc.log.Tracef(\"iterator expired for shard %s...\", shard)\n\t\t\t\tif iter, err = c.iterator(ctx); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"getting shard iterator failed: %w\", err)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\tcase errors.Is(err, context.Canceled):\n\t\t\t\treturn nil, nil\n\t\t\tdefault:\n\t\t\t\tc.log.Tracef(\"get-records error is of type %T\", err)\n\t\t\t\treturn nil, fmt.Errorf(\"getting records failed: %w\", err)\n\t\t\t}\n\t\t}\n\t\tc.log.Tracef(\"read %d records for shard %s...\", len(resp.Records), shard)\n\n\t\t// Check if we fully read the shard\n\t\tif resp.NextShardIterator == nil {\n\t\t\treturn resp.ChildShards, nil\n\t\t}\n\t\titer = resp.NextShardIterator\n\n\t\t// Process the records and keep track of the last sequence number\n\t\t// consumed for recreating the iterator.\n\t\tfor _, r := range resp.Records {\n\t\t\tc.onMessage(ctx, shard, &r)\n\t\t\tc.seqnr = *r.SequenceNumber\n\t\t\tif errors.Is(ctx.Err(), context.Canceled) {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t}\n\n\t\t// Wait for the poll interval to pass or cancel\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, nil\n\t\tcase <-ticker.C:\n\t\t\tcontinue\n\t\t}\n\t}\n}\n\nfunc (c *shardConsumer) iterator(ctx context.Context) (*string, error) {\n\tfor {\n\t\tresp, err := c.client.GetShardIterator(ctx, c.params)\n\t\tif err != nil {\n\t\t\tvar throughputErr *types.ProvisionedThroughputExceededException\n\t\t\tif errors.As(err, &throughputErr) {\n\t\t\t\t// We called the function too often and should wait a bit\n\t\t\t\t// until trying again\n\t\t\t\tc.log.Tracef(\"throughput exceeded when getting iterator for shard %s...\", *c.params.ShardId)\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\t\tc.log.Tracef(\"successfully updated iterator for shard %s (%s)...\", *c.params.ShardId, c.seqnr)\n\t\treturn resp.ShardIterator, nil\n\t}\n}\n\ntype consumer struct {\n\tconfig              aws.Config\n\tstream              string\n\titerType            types.ShardIteratorType\n\tpollInterval        time.Duration\n\tshardUpdateInterval time.Duration\n\tlog                 telegraf.Logger\n\n\tonMessage recordHandler\n\tposition  func(shard string) string\n\n\tclient *kinesis.Client\n\n\tshardsConsumed map[string]bool\n\tshardConsumers map[string]*shardConsumer\n\n\twg sync.WaitGroup\n\n\tsync.Mutex\n}\n\nfunc (c *consumer) init() error {\n\tif c.stream == \"\" {\n\t\treturn errors.New(\"stream cannot be empty\")\n\t}\n\tif c.pollInterval <= 0 {\n\t\treturn errors.New(\"invalid poll interval\")\n\t}\n\n\tif c.onMessage == nil {\n\t\treturn errors.New(\"message handler is undefined\")\n\t}\n\n\tc.shardsConsumed = make(map[string]bool)\n\tc.shardConsumers = make(map[string]*shardConsumer)\n\n\treturn nil\n}\n\nfunc (c *consumer) start(ctx context.Context) {\n\t// Setup the client\n\tc.client = kinesis.NewFromConfig(c.config)\n\n\t// Do the initial discovery of shards\n\tif err := c.updateShardConsumers(ctx); err != nil {\n\t\tc.log.Errorf(\"Initializing shards failed: %v\", err)\n\t}\n\n\t// If the consumer has a shard-update interval, use a ticker to update\n\t// available shards on a regular basis\n\tif c.shardUpdateInterval <= 0 {\n\t\treturn\n\t}\n\tticker := time.NewTicker(c.shardUpdateInterval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t\tif err := c.updateShardConsumers(ctx); err != nil {\n\t\t\t\tc.log.Errorf(\"Updating shards failed: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *consumer) updateShardConsumers(ctx context.Context) error {\n\t// List all shards of the given stream\n\tvar availableShards []types.Shard\n\treq := &kinesis.ListShardsInput{StreamName: aws.String(c.stream)}\n\tfor {\n\t\tresp, err := c.client.ListShards(ctx, req)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"listing shards failed: %w\", err)\n\t\t}\n\t\tavailableShards = append(availableShards, resp.Shards...)\n\n\t\tif resp.NextToken == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treq = &kinesis.ListShardsInput{NextToken: resp.NextToken}\n\t}\n\tc.log.Tracef(\"got %d shards during update\", len(availableShards))\n\n\t// All following operations need to be locked to create a consistent\n\t// state of the shards and consumers\n\tc.Lock()\n\tdefer c.Unlock()\n\n\t// Filter out all shards actively consumed already\n\tinactiveShards := make([]types.Shard, 0, len(availableShards))\n\tavailableShardIDs := make(map[string]bool, len(availableShards))\n\tfor _, shard := range availableShards {\n\t\tid := *shard.ShardId\n\t\tavailableShardIDs[id] = true\n\t\tif _, found := c.shardConsumers[id]; found {\n\t\t\tc.log.Tracef(\"shard %s is actively consumed...\", id)\n\t\t\tcontinue\n\t\t}\n\t\tc.log.Tracef(\"shard %s is not actively consumed...\", id)\n\t\tinactiveShards = append(inactiveShards, shard)\n\t}\n\n\t// Fill the shards already consumed and get the positions if the consumer\n\t// is backed by an iterator store\n\tnewShards := make([]types.Shard, 0, len(inactiveShards))\n\tseqnrs := make(map[string]string, len(inactiveShards))\n\tfor _, shard := range inactiveShards {\n\t\tid := *shard.ShardId\n\n\t\tif c.shardsConsumed[id] {\n\t\t\tc.log.Tracef(\"shard %s is already fully consumed...\", id)\n\t\t\tcontinue\n\t\t}\n\t\tc.log.Tracef(\"shard %s is not fully consumed...\", id)\n\n\t\t// Retrieve the shard position from the store\n\t\tif c.position != nil {\n\t\t\tseqnr := c.position(id)\n\t\t\tif seqnr == \"\" {\n\t\t\t\t// A truely new shard\n\t\t\t\tnewShards = append(newShards, shard)\n\t\t\t\tc.log.Tracef(\"shard %s is new...\", id)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tseqnrs[id] = seqnr\n\n\t\t\t// Check if we already fully consumed for closed shards\n\t\t\tend := shard.SequenceNumberRange.EndingSequenceNumber\n\t\t\tif end != nil && *end == seqnr {\n\t\t\t\tc.log.Tracef(\"shard %s is closed and already fully consumed...\", id)\n\t\t\t\tc.shardsConsumed[id] = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.log.Tracef(\"shard %s is not yet fully consumed...\", id)\n\t\t}\n\n\t\t// The shard is not fully consumed yet so save the sequence number\n\t\t// and the shard as \"new\".\n\t\tnewShards = append(newShards, shard)\n\t}\n\n\t// Filter all shards already fully consumed and create a new consumer for\n\t// every remaining new shard respecting resharding artifacts\n\tfor _, shard := range newShards {\n\t\tid := *shard.ShardId\n\n\t\t// Handle resharding by making sure all parents are consumed already\n\t\t// before starting a consumer on a child shard. If parents are not\n\t\t// consumed fully we ignore this shard here as it will be reported\n\t\t// by the call to `GetRecords` as a child later.\n\t\tif shard.ParentShardId != nil && *shard.ParentShardId != \"\" {\n\t\t\tpid := *shard.ParentShardId\n\n\t\t\t// The parent shard might be expired and thus not available anymore.\n\t\t\t// In those cases, we need to start consuming the child shard\n\t\t\t// instead. Data in the parent shard is lost.\n\t\t\tif availableShardIDs[pid] {\n\t\t\t\tif !c.shardsConsumed[pid] {\n\t\t\t\t\tc.log.Tracef(\"shard %s has parent %s which is not fully consumed yet...\", id, pid)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tc.log.Tracef(\"shard %s has parent %s which is expired...\", id, pid)\n\t\t\t}\n\t\t}\n\t\tif shard.AdjacentParentShardId != nil && *shard.AdjacentParentShardId != \"\" {\n\t\t\tpid := *shard.AdjacentParentShardId\n\t\t\t// The parent shard might be expired and thus not available anymore.\n\t\t\t// In those cases, we need to start consuming the child shard\n\t\t\t// instead. Data in the parent shard is lost.\n\t\t\tif availableShardIDs[pid] {\n\t\t\t\tif !c.shardsConsumed[pid] {\n\t\t\t\t\tc.log.Tracef(\"shard %s has adjacent parent %s which is not fully consumed yet...\", id, pid)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tc.log.Tracef(\"shard %s has adjacent parent %s which is expired...\", id, pid)\n\t\t\t}\n\t\t}\n\n\t\t// Create a new consumer and start it\n\t\tc.wg.Add(1)\n\t\tgo func(shardID string) {\n\t\t\tdefer c.wg.Done()\n\t\t\tc.startShardConsumer(ctx, shardID, seqnrs[shardID])\n\t\t}(id)\n\t}\n\n\treturn nil\n}\n\nfunc (c *consumer) startShardConsumer(ctx context.Context, id, seqnr string) {\n\tc.log.Tracef(\"starting consumer for shard %s at sequence number %q...\", id, seqnr)\n\tsc := &shardConsumer{\n\t\tseqnr:     seqnr,\n\t\tinterval:  c.pollInterval,\n\t\tlog:       c.log,\n\t\tonMessage: c.onMessage,\n\t\tclient:    c.client,\n\t\tparams: &kinesis.GetShardIteratorInput{\n\t\t\tShardId:           &id,\n\t\t\tShardIteratorType: c.iterType,\n\t\t\tStreamName:        &c.stream,\n\t\t},\n\t}\n\tif seqnr != \"\" {\n\t\tsc.params.ShardIteratorType = types.ShardIteratorTypeAfterSequenceNumber\n\t\tsc.params.StartingSequenceNumber = &seqnr\n\t}\n\tc.shardConsumers[id] = sc\n\n\tchilds, err := sc.consume(ctx, id)\n\tif err != nil {\n\t\tc.log.Errorf(\"Consuming shard %s failed: %v\", id, err)\n\t\treturn\n\t}\n\tc.log.Tracef(\"finished consuming shard %s\", id)\n\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tc.shardsConsumed[id] = true\n\tdelete(c.shardConsumers, id)\n\n\tfor _, shard := range childs {\n\t\tcid := *shard.ShardId\n\n\t\tstartable := true\n\t\tfor _, pid := range shard.ParentShards {\n\t\t\tstartable = startable && c.shardsConsumed[pid]\n\t\t}\n\t\tif !startable {\n\t\t\tc.log.Tracef(\"child shard %s of shard %s is not startable as parents are fully consumed yet...\", cid, id)\n\t\t\tcontinue\n\t\t}\n\t\tc.log.Tracef(\"child shard %s of shard %s is startable...\", cid, id)\n\n\t\tvar cseqnr string\n\t\tif c.position != nil {\n\t\t\tcseqnr = c.position(cid)\n\t\t}\n\t\tc.wg.Add(1)\n\t\tgo func() {\n\t\t\tdefer c.wg.Done()\n\t\t\tc.startShardConsumer(ctx, cid, cseqnr)\n\t\t}()\n\t}\n}\n\nfunc (c *consumer) stop() {\n\tc.wg.Wait()\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/encoding.go",
    "content": "package kinesis_consumer\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"compress/zlib\"\n\t\"fmt\"\n\t\"io\"\n)\n\ntype decodingFunc func([]byte) ([]byte, error)\n\nfunc processGzip(data []byte) ([]byte, error) {\n\tzipData, err := gzip.NewReader(bytes.NewReader(data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer zipData.Close()\n\treturn io.ReadAll(zipData)\n}\n\nfunc processZlib(data []byte) ([]byte, error) {\n\tzlibData, err := zlib.NewReader(bytes.NewReader(data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer zlibData.Close()\n\treturn io.ReadAll(zlibData)\n}\n\nfunc processNoOp(data []byte) ([]byte, error) {\n\treturn data, nil\n}\n\nfunc getDecodingFunc(encoding string) (decodingFunc, error) {\n\tswitch encoding {\n\tcase \"gzip\":\n\t\treturn processGzip, nil\n\tcase \"zlib\":\n\t\treturn processZlib, nil\n\tcase \"none\", \"identity\", \"\":\n\t\treturn processNoOp, nil\n\t}\n\treturn nil, fmt.Errorf(\"unknown content encoding %q\", encoding)\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/kinesis_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kinesis_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kinesis/types\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_aws \"github.com/influxdata/telegraf/plugins/common/aws\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype KinesisConsumer struct {\n\tStreamName             string          `toml:\"streamname\"`\n\tShardIteratorType      string          `toml:\"shard_iterator_type\"`\n\tPollInterval           config.Duration `toml:\"poll_interval\"`\n\tShardUpdateInterval    config.Duration `toml:\"shard_update_interval\"`\n\tDynamoDB               *dynamoDB       `toml:\"checkpoint_dynamodb\"`\n\tMaxUndeliveredMessages int             `toml:\"max_undelivered_messages\"`\n\tContentEncoding        string          `toml:\"content_encoding\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\tcommon_aws.CredentialConfig\n\n\tacc    telegraf.TrackingAccumulator\n\tparser telegraf.Parser\n\n\tcfg      aws.Config\n\tconsumer *consumer\n\tcancel   context.CancelFunc\n\tsem      chan struct{}\n\n\titeratorStore *store\n\n\trecords    map[telegraf.TrackingID]iterator\n\trecordsTex sync.Mutex\n\n\twg sync.WaitGroup\n\n\tcontentDecodingFunc decodingFunc\n}\n\ntype dynamoDB struct {\n\tAppName   string          `toml:\"app_name\"`\n\tTableName string          `toml:\"table_name\"`\n\tInterval  config.Duration `toml:\"interval\"`\n}\n\nfunc (*KinesisConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *KinesisConsumer) SetParser(parser telegraf.Parser) {\n\tk.parser = parser\n}\n\nfunc (k *KinesisConsumer) Init() error {\n\t// Set defaults\n\tif k.MaxUndeliveredMessages < 1 {\n\t\tk.MaxUndeliveredMessages = 1000\n\t}\n\n\tif k.ShardIteratorType == \"\" {\n\t\tk.ShardIteratorType = \"TRIM_HORIZON\"\n\t}\n\tif k.ContentEncoding == \"\" {\n\t\tk.ContentEncoding = \"identity\"\n\t}\n\n\t// Check input params\n\tif k.StreamName == \"\" {\n\t\treturn errors.New(\"stream name cannot be empty\")\n\t}\n\n\tf, err := getDecodingFunc(k.ContentEncoding)\n\tif err != nil {\n\t\treturn err\n\t}\n\tk.contentDecodingFunc = f\n\n\tif k.DynamoDB != nil {\n\t\tif k.DynamoDB.Interval <= 0 {\n\t\t\tk.DynamoDB.Interval = config.Duration(10 * time.Second)\n\t\t}\n\t\tk.iteratorStore = newStore(k.DynamoDB.AppName, k.DynamoDB.TableName, time.Duration(k.DynamoDB.Interval), k.Log)\n\t}\n\n\tk.records = make(map[telegraf.TrackingID]iterator, k.MaxUndeliveredMessages)\n\tk.sem = make(chan struct{}, k.MaxUndeliveredMessages)\n\n\t// Setup the client to connect to the Kinesis service\n\tcfg, err := k.CredentialConfig.Credentials()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif k.EndpointURL != \"\" {\n\t\tcfg.BaseEndpoint = &k.EndpointURL\n\t}\n\tif k.Log.Level().Includes(telegraf.Trace) {\n\t\tlogWrapper := &telegrafLoggerWrapper{k.Log}\n\t\tcfg.Logger = logWrapper\n\t\tcfg.ClientLogMode = aws.LogRetries\n\t}\n\tk.cfg = cfg\n\n\treturn nil\n}\n\nfunc (k *KinesisConsumer) Start(acc telegraf.Accumulator) error {\n\tk.acc = acc.WithTracking(k.MaxUndeliveredMessages)\n\n\t// Start the store if necessary\n\tif k.iteratorStore != nil {\n\t\tif err := k.iteratorStore.run(context.Background()); err != nil {\n\t\t\treturn fmt.Errorf(\"starting DynamoDB store failed: %w\", err)\n\t\t}\n\t}\n\n\tctx := context.Background()\n\tctx, k.cancel = context.WithCancel(ctx)\n\n\t// Setup the consumer\n\tk.consumer = &consumer{\n\t\tconfig:              k.cfg,\n\t\tstream:              k.StreamName,\n\t\titerType:            types.ShardIteratorType(k.ShardIteratorType),\n\t\tpollInterval:        time.Duration(k.PollInterval),\n\t\tshardUpdateInterval: time.Duration(k.ShardUpdateInterval),\n\t\tlog:                 k.Log,\n\t\tonMessage: func(ctx context.Context, shard string, r *types.Record) {\n\t\t\t// Checking for number of messages in flight and wait for a free\n\t\t\t// slot in case there are too many\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase k.sem <- struct{}{}:\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif err := k.onMessage(k.acc, shard, r); err != nil {\n\t\t\t\tseqnr := *r.SequenceNumber\n\t\t\t\tk.Log.Errorf(\"Processing message with sequence number %q in shard %s failed: %v\", seqnr, shard, err)\n\t\t\t\t<-k.sem\n\t\t\t}\n\t\t},\n\t}\n\n\t// Link in the backing iterator store\n\tif k.iteratorStore != nil {\n\t\tk.consumer.position = func(shard string) string {\n\t\t\tseqnr, err := k.iteratorStore.get(ctx, k.StreamName, shard)\n\t\t\tif err != nil && !errors.Is(err, errNotFound) {\n\t\t\t\tk.Log.Errorf(\"retrieving sequence number for shard %q failed: %s\", shard, err)\n\t\t\t}\n\n\t\t\treturn seqnr\n\t\t}\n\t}\n\tif err := k.consumer.init(); err != nil {\n\t\treturn fmt.Errorf(\"initializing consumer failed: %w\", err)\n\t}\n\n\t// Start the go-routine handling metrics delivered to the output\n\tk.wg.Add(1)\n\tgo func() {\n\t\tdefer k.wg.Done()\n\t\tk.onDelivery(ctx)\n\t}()\n\n\t// Start the go-routine handling message consumption\n\tk.wg.Add(1)\n\tgo func() {\n\t\tdefer k.wg.Done()\n\t\tk.consumer.start(ctx)\n\t}()\n\n\treturn nil\n}\n\nfunc (*KinesisConsumer) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (k *KinesisConsumer) Stop() {\n\tk.cancel()\n\tk.wg.Wait()\n\tk.consumer.stop()\n\n\tif k.iteratorStore != nil {\n\t\tk.iteratorStore.stop()\n\t}\n}\n\n// onMessage is called for new messages consumed from Kinesis\nfunc (k *KinesisConsumer) onMessage(acc telegraf.TrackingAccumulator, shard string, r *types.Record) error {\n\tdata, err := k.contentDecodingFunc(r.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmetrics, err := k.parser.Parse(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(metrics) == 0 {\n\t\tonce.Do(func() {\n\t\t\tk.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t})\n\t}\n\n\tseqnr := *r.SequenceNumber\n\n\tk.recordsTex.Lock()\n\tdefer k.recordsTex.Unlock()\n\n\tid := acc.AddTrackingMetricGroup(metrics)\n\tk.records[id] = iterator{shard: shard, seqnr: seqnr}\n\n\treturn nil\n}\n\n// onDelivery is called for every metric successfully delivered to the outputs\nfunc (k *KinesisConsumer) onDelivery(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase info := <-k.acc.Delivered():\n\t\t\t// Store the metric iterator in DynamoDB if configured\n\t\t\tif k.iteratorStore != nil {\n\t\t\t\tk.storeDelivered(info.ID())\n\t\t\t}\n\n\t\t\t// Reduce the number of undelivered messages by reading from the channel\n\t\t\t<-k.sem\n\t\t}\n\t}\n}\n\nfunc (k *KinesisConsumer) storeDelivered(id telegraf.TrackingID) {\n\tk.recordsTex.Lock()\n\tdefer k.recordsTex.Unlock()\n\n\t// Find the iterator belonging to the delivered message\n\titer, ok := k.records[id]\n\tif !ok {\n\t\tk.Log.Debugf(\"No iterator found for delivered metric %v!\", id)\n\t\treturn\n\t}\n\n\t// Remove metric\n\tdelete(k.records, id)\n\n\t// Store the iterator in the database\n\tk.iteratorStore.set(k.StreamName, iter.shard, iter.seqnr)\n}\n\nfunc init() {\n\tinputs.Add(\"kinesis_consumer\", func() telegraf.Input {\n\t\treturn &KinesisConsumer{\n\t\t\tPollInterval:        config.Duration(250 * time.Millisecond),\n\t\t\tShardUpdateInterval: config.Duration(30 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/kinesis_consumer_test.go",
    "content": "package kinesis_consumer\n\nimport (\n\t\"encoding/base64\"\n\t\"testing\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kinesis/types\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/json\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInvalidCoding(t *testing.T) {\n\tplugin := &KinesisConsumer{\n\t\tStreamName:      \"foo\",\n\t\tContentEncoding: \"notsupported\",\n\t}\n\trequire.ErrorContains(t, plugin.Init(), \"unknown content encoding\")\n}\n\nfunc TestOnMessage(t *testing.T) {\n\t// Prepare messages\n\tzlibBytpes, err := base64.StdEncoding.DecodeString(\n\t\t\"eF5FjlFrgzAUhf9KuM+2aNB2zdsQ2xe3whQGW8qIeqdhaiSJK0P874u1Y4+Hc/jON0GHxoga858BgUF8fs5fzunHU5Jlj6cEPFDXHvXStGqsrsKWTapq44pW1SetxsF1a8qsRtGt0Yy\" +\n\t\t\t\"FKbUcrFT9UbYWtQH2frntkm/s7RInkNU6t9JpWNE5WBAFPo3CcHeg+9D703OziUOhCg6MQ/yakrspuZsyEjdYfsm+Jg2K1jZEfZLKQWUvFglylBobZXDLwSP8//EGpD4NNj7dUJpT6\" +\n\t\t\t\"hQY3W33h/AhCt84zDBf5l/MDl08\",\n\t)\n\trequire.NoError(t, err)\n\n\tgzippedBytes, err := base64.StdEncoding.DecodeString(\n\t\t\"H4sIAAFXNGAAA0WOUWuDMBSF/0q4z7Zo0HbN2xDbF7fCFAZbyoh6p2FqJIkrQ/zvi7Vjj4dz+M43QYfGiBrznwGBQXx+zl/O6cdTkmWPpwQ8UNce9dK0aqyuwpZNqmrjilbVJ63GwXVr\" +\n\t\t\t\"yqxG0a3RjIUptRysVP1Rtha1AfZ+ue2Sb+ztEieQ1Tq30mlY0TlYEAU+jcJwd6D70PvTc7OJQ6EKDoxD/JqSuym5mzISN1h+yb4mDYrWNkR9kspBZS8WCXKUGhtlcMvBI/z/8QakPg02\" +\n\t\t\t\"Pt1QmlPqFBjdbfeH8CEK3zjMMF/mX0TaxZUpAQAA\",\n\t)\n\trequire.NoError(t, err)\n\n\tnotZippedBytes := []byte(`\n\t{\n\t\t\"messageType\": \"CONTROL_MESSAGE\",\n\t\t\"owner\": \"CloudwatchLogs\",\n\t\t\"logGroup\": \"\",\n\t\t\"logStream\": \"\",\n\t\t\"subscriptionFilters\": [],\n\t\t\"logEvents\": [\n\t\t\t{\n\t\t\t\t\"id\": \"\",\n\t\t\t\t\"timestamp\": 1510254469274,\n\t\t\t\t\"message\": \"{\\\"bob\\\":\\\"CWL CONTROL MESSAGE: Checking health of destination Firehose.\\\", \\\"timestamp\\\":\\\"2021-02-22T22:15:26.794854Z\\\"},\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"\",\n\t\t\t\t\"timestamp\": 1510254469274,\n\t\t\t\t\"message\": \"{\\\"bob\\\":\\\"CWL CONTROL MESSAGE: Checking health of destination Firehose.\\\", \\\"timestamp\\\":\\\"2021-02-22T22:15:26.794854Z\\\"}\"\n\t\t\t}\n\t\t]\n\t}\n  `)\n\n\ttests := []struct {\n\t\tname            string\n\t\tencoding        string\n\t\trecord          *types.Record\n\t\texpectedNumber  int\n\t\texpectedContent string\n\t}{\n\t\t{\n\t\t\tname:     \"test no compression\",\n\t\t\tencoding: \"none\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           notZippedBytes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  2,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname: \"test no compression via empty string for ContentEncoding\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           notZippedBytes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  2,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:     \"test no compression via identity ContentEncoding\",\n\t\t\tencoding: \"identity\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           notZippedBytes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  2,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname: \"test no compression via no ContentEncoding\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           notZippedBytes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  2,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:     \"test gzip compression\",\n\t\t\tencoding: \"gzip\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           gzippedBytes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  1,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:     \"test zlib compression\",\n\t\t\tencoding: \"zlib\",\n\t\t\trecord: &types.Record{\n\t\t\t\tData:           zlibBytpes,\n\t\t\t\tSequenceNumber: aws.String(\"anything\"),\n\t\t\t},\n\t\t\texpectedNumber:  1,\n\t\t\texpectedContent: \"bob\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Prepare JSON parser\n\t\t\tparser := &json.Parser{\n\t\t\t\tMetricName:   \"json_test\",\n\t\t\t\tQuery:        \"logEvents\",\n\t\t\t\tStringFields: []string{\"message\"},\n\t\t\t}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Setup plugin\n\t\t\tplugin := &KinesisConsumer{\n\t\t\t\tStreamName:      \"foo\",\n\t\t\t\tContentEncoding: tt.encoding,\n\t\t\t\tLog:             &testutil.Logger{},\n\t\t\t\tparser:          parser,\n\t\t\t\trecords:         make(map[telegraf.TrackingID]iterator),\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.onMessage(acc.WithTracking(tt.expectedNumber), \"test\", tt.record))\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\trequire.Len(t, actual, tt.expectedNumber)\n\n\t\t\tfor _, metric := range actual {\n\t\t\t\traw, found := metric.GetField(\"message\")\n\t\t\t\trequire.True(t, found, \"no message present\")\n\t\t\t\tmessage, ok := raw.(string)\n\t\t\t\trequire.Truef(t, ok, \"message not a string but %T\", raw)\n\t\t\t\trequire.Contains(t, message, tt.expectedContent)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/logging.go",
    "content": "package kinesis_consumer\n\nimport (\n\t\"github.com/aws/smithy-go/logging\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype telegrafLoggerWrapper struct {\n\ttelegraf.Logger\n}\n\n// Log logs messages at the trace level.\nfunc (t *telegrafLoggerWrapper) Log(args ...interface{}) {\n\tt.Trace(args...)\n}\n\n// Logf logs formatted messages with a specific classification.\nfunc (t *telegrafLoggerWrapper) Logf(classification logging.Classification, format string, v ...interface{}) {\n\tswitch classification {\n\tcase logging.Debug:\n\t\tformat = \"DEBUG \" + format\n\tcase logging.Warn:\n\t\tformat = \"WARN\" + format\n\tdefault:\n\t\tformat = \"INFO \" + format\n\t}\n\tt.Logger.Tracef(format, v...)\n}\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/sample.conf",
    "content": "# Configuration for the AWS Kinesis input.\n[[inputs.kinesis_consumer]]\n  ## Amazon REGION of kinesis endpoint.\n  region = \"ap-southeast-2\"\n\n  ## Amazon Credentials\n  ## Credentials are loaded in the following order\n  ## 1) Web identity provider credentials via STS if role_arn and web_identity_token_file are specified\n  ## 2) Assumed credentials via STS if role_arn is specified\n  ## 3) explicit credentials from 'access_key' and 'secret_key'\n  ## 4) shared profile from 'profile'\n  ## 5) environment variables\n  ## 6) shared credentials file\n  ## 7) EC2 Instance Profile\n  # access_key = \"\"\n  # secret_key = \"\"\n  # token = \"\"\n  # role_arn = \"\"\n  # web_identity_token_file = \"\"\n  # role_session_name = \"\"\n  # profile = \"\"\n  # shared_credential_file = \"\"\n\n  ## Endpoint to make request against, the correct endpoint is automatically\n  ## determined and this option should only be set if you wish to override the\n  ## default.\n  ##   ex: endpoint_url = \"http://localhost:8000\"\n  # endpoint_url = \"\"\n\n  ## Kinesis StreamName must exist prior to starting telegraf.\n  streamname = \"StreamName\"\n\n  ## Shard iterator type\n  ## Available options: 'TRIM_HORIZON' (first in non-expired) and 'LATEST'\n  # shard_iterator_type = \"TRIM_HORIZON\"\n\n  ## Interval for checking for new records\n  ## Please consider limits for getting records documented here:\n  ## https://docs.aws.amazon.com/streams/latest/dev/service-sizes-and-limits.html\n  # poll_interval = \"250ms\"\n\n  ## Interval for scanning for new shards created when resharding\n  ## If set to zero, shards are only scanned once on startup.\n  # shard_update_interval = \"30s\"\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Content encoding of the record data\n  ## If you are processing a cloudwatch logs kinesis stream then set this to\n  ## \"gzip\" as AWS compresses cloudwatch log data before it is sent to kinesis.\n  # content_encoding = \"identity\"\n\n  ## Data format of the records to consume\n  ## See https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n\n  ## Optional: Configuration for DynamoDB backend to store positions in the stream\n  # [inputs.kinesis_consumer.checkpoint_dynamodb]\n  #   ## Unique name for this consumer\n  #   app_name = \"default\"\n  #   ## Table to store the sequence numbers in\n  #   table_name = \"default\"\n  #   ## Interval for persisting data to limit write operations\n  #   # interval = \"10s\"\n"
  },
  {
    "path": "plugins/inputs/kinesis_consumer/store.go",
    "content": "package kinesis_consumer\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/service/dynamodb\"\n\t\"github.com/aws/aws-sdk-go-v2/service/dynamodb/types\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nvar errNotFound = errors.New(\"no iterator found\")\n\ntype iterator struct {\n\tstream   string\n\tshard    string\n\tseqnr    string\n\tmodified bool\n}\n\ntype store struct {\n\tapp      string\n\ttable    string\n\tinterval time.Duration\n\tlog      telegraf.Logger\n\n\tclient    *dynamodb.Client\n\titerators map[string]iterator\n\n\twg     sync.WaitGroup\n\tcancel context.CancelFunc\n\n\tsync.Mutex\n}\n\nfunc newStore(app, table string, interval time.Duration, log telegraf.Logger) *store {\n\ts := &store{\n\t\tapp:      app,\n\t\ttable:    table,\n\t\tinterval: interval,\n\t\tlog:      log,\n\t}\n\n\t// Initialize the iterator states\n\ts.iterators = make(map[string]iterator)\n\n\treturn s\n}\n\nfunc (s *store) run(ctx context.Context) error {\n\trctx, cancel := context.WithCancel(ctx)\n\ts.cancel = cancel\n\n\t// Create a client to connect to DynamoDB\n\tcfg, err := config.LoadDefaultConfig(rctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"loading default config failed: %w\", err)\n\t}\n\ts.client = dynamodb.NewFromConfig(cfg)\n\n\t// Start the go-routine that pushes the states out to DynamoDB on a\n\t// regular interval\n\ts.wg.Add(1)\n\tgo func() {\n\t\tdefer s.wg.Done()\n\n\t\tticker := time.NewTicker(s.interval)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-rctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\ts.write(rctx)\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (s *store) stop() {\n\tctx, cancel := context.WithTimeout(context.Background(), s.interval)\n\tdefer cancel()\n\ts.write(ctx)\n\n\ts.cancel()\n\ts.wg.Wait()\n}\n\nfunc (s *store) write(ctx context.Context) {\n\ts.Lock()\n\tdefer s.Unlock()\n\n\tfor k, iter := range s.iterators {\n\t\t// Only write iterators modified since the last write\n\t\tif !iter.modified {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, err := s.client.PutItem(\n\t\t\tctx,\n\t\t\t&dynamodb.PutItemInput{\n\t\t\t\tTableName: aws.String(s.table),\n\t\t\t\tItem: map[string]types.AttributeValue{\n\t\t\t\t\t\"namespace\":       &types.AttributeValueMemberS{Value: s.app + \"-\" + iter.stream},\n\t\t\t\t\t\"shard_id\":        &types.AttributeValueMemberS{Value: iter.shard},\n\t\t\t\t\t\"sequence_number\": &types.AttributeValueMemberS{Value: iter.seqnr},\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\ts.log.Errorf(\"storing iterator %s-%s/%s/%s failed: %v\", s.app, iter.stream, iter.shard, iter.seqnr, err)\n\t\t}\n\n\t\t// Mark state as saved\n\t\titer.modified = false\n\t\ts.iterators[k] = iter\n\t}\n}\n\nfunc (s *store) set(stream, shard, seqnr string) {\n\ts.Lock()\n\tdefer s.Unlock()\n\n\ts.iterators[stream+\"/\"+shard] = iterator{\n\t\tstream:   stream,\n\t\tshard:    shard,\n\t\tseqnr:    seqnr,\n\t\tmodified: true,\n\t}\n}\n\nfunc (s *store) get(ctx context.Context, stream, shard string) (string, error) {\n\ts.Lock()\n\tdefer s.Unlock()\n\n\t// Return the cached result if possible\n\tif iter, found := s.iterators[stream+\"/\"+shard]; found {\n\t\treturn iter.seqnr, nil\n\t}\n\n\t// Retrieve the information from the database\n\tresp, err := s.client.GetItem(ctx, &dynamodb.GetItemInput{\n\t\tTableName:      aws.String(s.table),\n\t\tConsistentRead: aws.Bool(true),\n\t\tKey: map[string]types.AttributeValue{\n\t\t\t\"namespace\": &types.AttributeValueMemberS{Value: s.app + \"-\" + stream},\n\t\t\t\"shard_id\":  &types.AttributeValueMemberS{Value: shard},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Extract the sequence number\n\traw, found := resp.Item[\"sequence_number\"]\n\tif !found {\n\t\treturn \"\", fmt.Errorf(\"%w for %s-%s/%s\", errNotFound, s.app, stream, shard)\n\t}\n\tseqnr, ok := raw.(*types.AttributeValueMemberS)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"sequence number for %s-%s/%s is of unexpected type %T\", s.app, stream, shard, raw)\n\t}\n\n\t// Fill the cache\n\ts.iterators[stream+\"/\"+shard] = iterator{\n\t\tstream: stream,\n\t\tshard:  shard,\n\t\tseqnr:  seqnr.Value,\n\t}\n\n\treturn seqnr.Value, nil\n}\n"
  },
  {
    "path": "plugins/inputs/knx_listener/README.md",
    "content": "# KNX Input Plugin\n\nThis service plugin listens for messages on the [KNX home-automation bus][knx]\nby connecting via a KNX-IP interface. Information about supported KNX\ndatapoint-types can be found at the underlying [`knx-go` project][knxgo].\n\n⭐ Telegraf v1.19.0\n🏷️ iot\n💻 all\n\n[knx]: https://www.knx.org\n[knxgo]: https://github.com/vapourismo/knx-go\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Listener capable of handling KNX bus messages provided through a KNX-IP Interface.\n[[inputs.knx_listener]]\n  ## Type of KNX-IP interface.\n  ## Can be either \"tunnel_udp\", \"tunnel_tcp\", \"tunnel\" (alias for tunnel_udp) or \"router\".\n  # service_type = \"tunnel\"\n\n  ## Address of the KNX-IP interface.\n  service_address = \"localhost:3671\"\n\n  ## Measurement definition(s)\n  # [[inputs.knx_listener.measurement]]\n  #   ## Name of the measurement\n  #   name = \"temperature\"\n  #   ## Datapoint-Type (DPT) of the KNX messages\n  #   dpt = \"9.001\"\n  #   ## Use the string representation instead of the numerical value for the\n  #   ## datapoint-type and the addresses below\n  #   # as_string = false\n  #   ## List of Group-Addresses (GAs) assigned to the measurement\n  #   addresses = [\"5/5/1\"]\n\n  # [[inputs.knx_listener.measurement]]\n  #   name = \"illumination\"\n  #   dpt = \"9.004\"\n  #   addresses = [\"5/5/3\"]\n```\n\n### Related tools\n\n- [knx-telegraf-config-generator][knx_config_generator]:  generates a Telegraf\n configuration from a KNX project file\n\n[knx_config_generator]: https://github.com/svsool/knx-telegraf-config-generator\n\n### Measurement configurations\n\nEach measurement contains only one datapoint-type (DPT) and assigns a list of\naddresses to this measurement. You can, for example group all temperature sensor\nmessages within a \"temperature\" measurement. However, you are free to split\nmessages of one datapoint-type to multiple measurements.\n\n> [!IMPORTANT]\n> You should not assign a group-address (GA) to multiple measurements!\n\n## Metrics\n\nReceived KNX data is stored in the named measurement as configured above using\nthe \"value\" field. Additional to the value, there are the following tags added\nto the datapoint:\n\n- `groupaddress`: KNX group-address corresponding to the value\n- `unit`:         unit of the value\n- `source`:       KNX physical address sending the value\n\nTo find out about the datatype of the datapoint please check your KNX project,\nthe KNX-specification or the \"knx-go\" project for the corresponding DPT.\n\n## Example Output\n\nThis section shows example output in Line Protocol format.\n\n```text\nillumination,groupaddress=5/5/4,host=Hugin,source=1.1.12,unit=lux value=17.889999389648438 1582132674999013274\ntemperature,groupaddress=5/5/1,host=Hugin,source=1.1.8,unit=°C value=17.799999237060547 1582132663427587361\nwindowopen,groupaddress=1/0/1,host=Hugin,source=1.1.3 value=true 1582132630425581320\n```\n"
  },
  {
    "path": "plugins/inputs/knx_listener/knx_dummy_interface.go",
    "content": "package knx_listener\n\nimport (\n\t\"github.com/vapourismo/knx-go/knx\"\n)\n\ntype knxDummyInterface struct {\n\tinbound chan knx.GroupEvent\n}\n\nfunc newDummyInterface() knxDummyInterface {\n\tdi := knxDummyInterface{}\n\tdi.inbound = make(chan knx.GroupEvent)\n\n\treturn di\n}\n\n// Send simulates sending a GroupEvent over the KNX interface.\nfunc (di *knxDummyInterface) Send(event knx.GroupEvent) {\n\tdi.inbound <- event\n}\n\n// Inbound returns a read-only channel for receiving GroupEvents.\nfunc (di *knxDummyInterface) Inbound() <-chan knx.GroupEvent {\n\treturn di.inbound\n}\n\n// Close closes the inbound channel to simulate shutting down the interface.\nfunc (di *knxDummyInterface) Close() {\n\tclose(di.inbound)\n}\n"
  },
  {
    "path": "plugins/inputs/knx_listener/knx_listener.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage knx_listener\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/vapourismo/knx-go/knx\"\n\t\"github.com/vapourismo/knx-go/knx/dpt\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype KNXListener struct {\n\tServiceType    string          `toml:\"service_type\"`\n\tServiceAddress string          `toml:\"service_address\"`\n\tMeasurements   []measurement   `toml:\"measurement\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tclient      knxInterface\n\tgaTargetMap map[string]addressTarget\n\tgaLogbook   map[string]bool\n\n\twg        sync.WaitGroup\n\tconnected atomic.Bool\n}\n\ntype measurement struct {\n\tName      string   `toml:\"name\"`\n\tDpt       string   `toml:\"dpt\"`\n\tAsString  bool     `toml:\"as_string\"`\n\tAddresses []string `toml:\"addresses\"`\n}\n\ntype addressTarget struct {\n\tmeasurement string\n\tasstring    bool\n\tdatapoint   dpt.Datapoint\n}\n\ntype knxInterface interface {\n\tInbound() <-chan knx.GroupEvent\n\tClose()\n}\n\nfunc (*KNXListener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (kl *KNXListener) Init() error {\n\t// Setup a logbook to track unknown GAs to avoid log-spamming\n\tkl.gaLogbook = make(map[string]bool)\n\n\t// Construct the mapping of Group-addresses (GAs) to DPTs and the name\n\t// of the measurement\n\tkl.gaTargetMap = make(map[string]addressTarget)\n\tfor _, m := range kl.Measurements {\n\t\tkl.Log.Debugf(\"Group-address mapping for measurement %q:\", m.Name)\n\t\tfor _, ga := range m.Addresses {\n\t\t\tkl.Log.Debugf(\"  %s --> %s\", ga, m.Dpt)\n\t\t\tif _, ok := kl.gaTargetMap[ga]; ok {\n\t\t\t\treturn fmt.Errorf(\"duplicate specification of address %q\", ga)\n\t\t\t}\n\t\t\td, ok := dpt.Produce(m.Dpt)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"cannot create datapoint-type %q for address %q\", m.Dpt, ga)\n\t\t\t}\n\t\t\tkl.gaTargetMap[ga] = addressTarget{measurement: m.Name, asstring: m.AsString, datapoint: d}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (kl *KNXListener) Start(acc telegraf.Accumulator) error {\n\t// Connect to the KNX-IP interface\n\tkl.Log.Infof(\"Trying to connect to %q at %q\", kl.ServiceType, kl.ServiceAddress)\n\tswitch kl.ServiceType {\n\tcase \"tunnel\", \"tunnel_udp\":\n\t\ttunnelconfig := knx.DefaultTunnelConfig\n\t\ttunnelconfig.UseTCP = false\n\t\tc, err := knx.NewGroupTunnel(kl.ServiceAddress, tunnelconfig)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tkl.client = &c\n\tcase \"tunnel_tcp\":\n\t\ttunnelconfig := knx.DefaultTunnelConfig\n\t\ttunnelconfig.UseTCP = true\n\t\tc, err := knx.NewGroupTunnel(kl.ServiceAddress, tunnelconfig)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tkl.client = &c\n\tcase \"router\":\n\t\tc, err := knx.NewGroupRouter(kl.ServiceAddress, knx.DefaultRouterConfig)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tkl.client = &c\n\tcase \"dummy\":\n\t\tc := newDummyInterface()\n\t\tkl.client = &c\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid interface type: %s\", kl.ServiceAddress)\n\t}\n\tkl.Log.Infof(\"Connected!\")\n\tkl.connected.Store(true)\n\n\t// Listen to the KNX bus\n\tkl.wg.Add(1)\n\tgo func() {\n\t\tdefer kl.wg.Done()\n\t\tkl.listen(acc)\n\t\tkl.connected.Store(false)\n\t\tacc.AddError(errors.New(\"disconnected from bus\"))\n\t}()\n\n\treturn nil\n}\n\nfunc (kl *KNXListener) Gather(acc telegraf.Accumulator) error {\n\tif !kl.connected.Load() {\n\t\t// We got disconnected for some reason, so try to reconnect in every\n\t\t// gather cycle until we are reconnected\n\t\tif err := kl.Start(acc); err != nil {\n\t\t\treturn fmt.Errorf(\"reconnecting to bus failed: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (kl *KNXListener) Stop() {\n\tif kl.client != nil {\n\t\tkl.client.Close()\n\t\tkl.wg.Wait()\n\t}\n}\n\nfunc (kl *KNXListener) listen(acc telegraf.Accumulator) {\n\tfor msg := range kl.client.Inbound() {\n\t\tif msg.Command == knx.GroupRead {\n\t\t\t// Ignore GroupValue_Read requests as they would either\n\t\t\t// - fail to unpack due to invalid data length (DPT != 1) or\n\t\t\t// - create invalid `false` values as their data always unpacks `0` (DPT 1)\n\t\t\tcontinue\n\t\t}\n\t\t// Match GA to DataPointType and measurement name\n\t\tga := msg.Destination.String()\n\t\ttarget, ok := kl.gaTargetMap[ga]\n\t\tif !ok {\n\t\t\tif !kl.gaLogbook[ga] {\n\t\t\t\tkl.Log.Infof(\"Ignoring message %+v for unknown GA %q\", msg, ga)\n\t\t\t\tkl.gaLogbook[ga] = true\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Extract the value from the data-frame\n\t\tif err := target.datapoint.Unpack(msg.Data); err != nil {\n\t\t\tkl.Log.Errorf(\"Unpacking data failed: %v\", err)\n\t\t\tcontinue\n\t\t}\n\t\tkl.Log.Debugf(\"Matched GA %q to measurement %q with value %v\", ga, target.measurement, target.datapoint)\n\n\t\t// Convert the DatapointValue interface back to its basic type again\n\t\t// as otherwise telegraf will not push out the metrics and eat it\n\t\t// silently.\n\t\tvar value interface{}\n\t\tif !target.asstring {\n\t\t\tvi := reflect.Indirect(reflect.ValueOf(target.datapoint))\n\t\t\tswitch vi.Kind() {\n\t\t\tcase reflect.Bool:\n\t\t\t\tvalue = vi.Bool()\n\t\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\t\tvalue = vi.Int()\n\t\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\t\tvalue = vi.Uint()\n\t\t\tcase reflect.Float32, reflect.Float64:\n\t\t\t\tvalue = vi.Float()\n\t\t\tcase reflect.String:\n\t\t\t\tvalue = vi.String()\n\t\t\tdefault:\n\t\t\t\tkl.Log.Errorf(\"Type conversion %v failed for address %q\", vi.Kind(), ga)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\tvalue = target.datapoint.String()\n\t\t}\n\n\t\t// Compose the actual data to be pushed out\n\t\tfields := map[string]interface{}{\"value\": value}\n\t\ttags := map[string]string{\n\t\t\t\"groupaddress\": ga,\n\t\t\t\"unit\":         target.datapoint.(dpt.DatapointMeta).Unit(),\n\t\t\t\"source\":       msg.Source.String(),\n\t\t}\n\t\tacc.AddFields(target.measurement, fields, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"knx_listener\", func() telegraf.Input { return &KNXListener{ServiceType: \"tunnel\"} })\n}\n"
  },
  {
    "path": "plugins/inputs/knx_listener/knx_listener_test.go",
    "content": "package knx_listener\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/vapourismo/knx-go/knx\"\n\t\"github.com/vapourismo/knx-go/knx/cemi\"\n\t\"github.com/vapourismo/knx-go/knx/dpt\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst epsilon = 1e-3\n\nfunc setValue(data dpt.DatapointValue, value interface{}) error {\n\td := reflect.Indirect(reflect.ValueOf(data))\n\tif !d.CanSet() {\n\t\treturn fmt.Errorf(\"cannot set datapoint %v\", data)\n\t}\n\tswitch v := value.(type) {\n\tcase bool:\n\t\td.SetBool(v)\n\tcase float64:\n\t\td.SetFloat(v)\n\tcase int64:\n\t\td.SetInt(v)\n\tcase uint64:\n\t\td.SetUint(v)\n\tcase string:\n\t\td.SetString(v)\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown type '%T' when setting value for DPT\", value)\n\t}\n\treturn nil\n}\n\ntype message struct {\n\taddress string\n\tdpt     string\n\tvalue   interface{}\n}\n\nfunc produceKnxEvent(t *testing.T, address, datapoint string, value interface{}) *knx.GroupEvent {\n\taddr, err := cemi.NewGroupAddrString(address)\n\trequire.NoError(t, err)\n\n\tdata, ok := dpt.Produce(datapoint)\n\trequire.True(t, ok)\n\terr = setValue(data, value)\n\trequire.NoError(t, err)\n\n\treturn &knx.GroupEvent{\n\t\tCommand:     knx.GroupWrite,\n\t\tDestination: addr,\n\t\tData:        data.Pack(),\n\t}\n}\n\nfunc TestRegularReceives_DPT(t *testing.T) {\n\t// Define the test-cases\n\tvar testcases = []struct {\n\t\taddress  string\n\t\tdpt      string\n\t\tasstring bool\n\t\tvalue    interface{}\n\t\texpected interface{}\n\t}{\n\t\t{\"1/0/1\", \"1.001\", false, true, true},\n\t\t{\"1/0/2\", \"1.002\", false, false, false},\n\t\t{\"1/0/3\", \"1.003\", false, true, true},\n\t\t{\"1/0/9\", \"1.009\", false, false, false},\n\t\t{\"1/1/0\", \"1.010\", false, true, true},\n\t\t{\"1/1/1\", \"1.001\", true, true, \"On\"},\n\t\t{\"1/1/2\", \"1.001\", true, false, \"Off\"},\n\t\t{\"1/1/3\", \"1.002\", true, true, \"True\"},\n\t\t{\"1/1/4\", \"1.002\", true, false, \"False\"},\n\t\t{\"1/1/5\", \"1.003\", true, true, \"Enable\"},\n\t\t{\"1/1/6\", \"1.003\", true, false, \"Disable\"},\n\t\t{\"1/1/7\", \"1.009\", true, true, \"Close\"},\n\t\t{\"1/1/8\", \"1.009\", true, false, \"Open\"},\n\t\t{\"1/2/0\", \"1.010\", true, true, \"Start\"},\n\t\t{\"1/2/1\", \"1.010\", true, false, \"Stop\"},\n\t\t{\"5/0/1\", \"5.001\", false, 12.157, 12.157},\n\t\t{\"5/0/3\", \"5.003\", false, 121.412, 121.412},\n\t\t{\"5/0/4\", \"5.004\", false, uint64(25), uint64(25)},\n\t\t{\"9/0/1\", \"9.001\", false, 18.56, 18.56},\n\t\t{\"9/0/4\", \"9.004\", false, 243.84, 243.84},\n\t\t{\"9/0/5\", \"9.005\", false, 12.01, 12.01},\n\t\t{\"9/0/7\", \"9.007\", false, 59.32, 59.32},\n\t\t{\"13/0/1\", \"13.001\", false, int64(-15), int64(-15)},\n\t\t{\"13/0/2\", \"13.002\", false, int64(183), int64(183)},\n\t\t{\"13/1/0\", \"13.010\", false, int64(-141), int64(-141)},\n\t\t{\"13/1/1\", \"13.011\", false, int64(277), int64(277)},\n\t\t{\"13/1/2\", \"13.012\", false, int64(-4096), int64(-4096)},\n\t\t{\"13/1/3\", \"13.013\", false, int64(8192), int64(8192)},\n\t\t{\"13/1/4\", \"13.014\", false, int64(-65536), int64(-65536)},\n\t\t{\"13/1/5\", \"13.015\", false, int64(2147483647), int64(2147483647)},\n\t\t{\"14/0/0\", \"14.000\", false, -1.31, -1.31},\n\t\t{\"14/0/1\", \"14.001\", false, 0.44, 0.44},\n\t\t{\"14/0/2\", \"14.002\", false, 32.08, 32.08},\n\t\t{\"14/0/3\", \"14.003\", false, 92.69, 92.69},\n\t\t{\"14/0/4\", \"14.004\", false, 1.00794, 1.00794},\n\t\t{\"14/1/0\", \"14.010\", false, 5963.78, 5963.78},\n\t\t{\"14/1/1\", \"14.011\", false, 150.95, 150.95},\n\t\t{\"16/0/0\", \"16.000\", false, \"hello world\", \"hello world\"},\n\t}\n\tacc := &testutil.Accumulator{}\n\n\t// Setup the unit-under-test\n\tmeasurements := make([]measurement, 0, len(testcases))\n\tfor _, testcase := range testcases {\n\t\tmeasurements = append(measurements, measurement{\n\t\t\tName:      \"test\",\n\t\t\tDpt:       testcase.dpt,\n\t\t\tAsString:  testcase.asstring,\n\t\t\tAddresses: []string{testcase.address},\n\t\t})\n\t}\n\tlistener := KNXListener{\n\t\tServiceType:  \"dummy\",\n\t\tMeasurements: measurements,\n\t\tLog:          testutil.Logger{Name: \"knx_listener\"},\n\t}\n\trequire.NoError(t, listener.Init())\n\n\t// Setup the listener to test\n\terr := listener.Start(acc)\n\trequire.NoError(t, err)\n\tclient := listener.client.(*knxDummyInterface)\n\n\ttstart := time.Now()\n\n\t// Send the defined test data\n\tfor _, testcase := range testcases {\n\t\tevent := produceKnxEvent(t, testcase.address, testcase.dpt, testcase.value)\n\t\tclient.Send(*event)\n\t}\n\n\t// Give the accumulator some time to collect the data\n\tacc.Wait(len(testcases))\n\n\t// Stop the listener\n\tlistener.Stop()\n\ttstop := time.Now()\n\n\t// Check if we got what we expected\n\trequire.Len(t, acc.Metrics, len(testcases))\n\tfor i, m := range acc.Metrics {\n\t\trequire.Equal(t, \"test\", m.Measurement)\n\t\trequire.Equal(t, testcases[i].address, m.Tags[\"groupaddress\"])\n\t\trequire.Len(t, m.Fields, 1)\n\t\tswitch v := testcases[i].expected.(type) {\n\t\tcase string, bool, int64, uint64:\n\t\t\trequire.Equal(t, v, m.Fields[\"value\"])\n\t\tcase float64:\n\t\t\trequire.InDelta(t, v, m.Fields[\"value\"], epsilon)\n\t\t}\n\t\trequire.False(t, tstop.Before(m.Time))\n\t\trequire.False(t, tstart.After(m.Time))\n\t}\n}\n\nfunc TestRegularReceives_MultipleMessages(t *testing.T) {\n\tlistener := KNXListener{\n\t\tServiceType: \"dummy\",\n\t\tMeasurements: []measurement{\n\t\t\t{Name: \"temperature\", Dpt: \"1.001\", Addresses: []string{\"1/1/1\"}},\n\t\t},\n\t\tLog: testutil.Logger{Name: \"knx_listener\"},\n\t}\n\trequire.NoError(t, listener.Init())\n\n\tacc := &testutil.Accumulator{}\n\n\t// Setup the listener to test\n\terr := listener.Start(acc)\n\trequire.NoError(t, err)\n\tclient := listener.client.(*knxDummyInterface)\n\n\ttestMessages := []message{\n\t\t{\"1/1/1\", \"1.001\", true},\n\t\t{\"1/1/1\", \"1.001\", false},\n\t\t{\"1/1/2\", \"1.001\", false},\n\t\t{\"1/1/2\", \"1.001\", true},\n\t}\n\n\tfor _, testcase := range testMessages {\n\t\tevent := produceKnxEvent(t, testcase.address, testcase.dpt, testcase.value)\n\t\tclient.Send(*event)\n\t}\n\n\t// Give the accumulator some time to collect the data\n\tacc.Wait(2)\n\n\t// Stop the listener\n\tlistener.Stop()\n\n\t// Check if we got what we expected\n\trequire.Len(t, acc.Metrics, 2)\n\n\trequire.Equal(t, \"temperature\", acc.Metrics[0].Measurement)\n\trequire.Equal(t, \"1/1/1\", acc.Metrics[0].Tags[\"groupaddress\"])\n\trequire.Len(t, acc.Metrics[0].Fields, 1)\n\tv, ok := acc.Metrics[0].Fields[\"value\"].(bool)\n\trequire.Truef(t, ok, \"bool type expected, got '%T' with '%v' value instead\", acc.Metrics[0].Fields[\"value\"], acc.Metrics[0].Fields[\"value\"])\n\trequire.True(t, v)\n\n\trequire.Equal(t, \"temperature\", acc.Metrics[1].Measurement)\n\trequire.Equal(t, \"1/1/1\", acc.Metrics[1].Tags[\"groupaddress\"])\n\trequire.Len(t, acc.Metrics[1].Fields, 1)\n\tv, ok = acc.Metrics[1].Fields[\"value\"].(bool)\n\trequire.Truef(t, ok, \"bool type expected, got '%T' with '%v' value instead\", acc.Metrics[1].Fields[\"value\"], acc.Metrics[1].Fields[\"value\"])\n\trequire.False(t, v)\n}\n\nfunc TestReconnect(t *testing.T) {\n\tlistener := KNXListener{\n\t\tServiceType: \"dummy\",\n\t\tMeasurements: []measurement{\n\t\t\t{Name: \"temperature\", Dpt: \"1.001\", Addresses: []string{\"1/1/1\"}},\n\t\t},\n\t\tLog: testutil.Logger{Name: \"knx_listener\"},\n\t}\n\trequire.NoError(t, listener.Init())\n\n\tvar acc testutil.Accumulator\n\n\t// Setup the listener to test\n\trequire.NoError(t, listener.Start(&acc))\n\tdefer listener.Stop()\n\tclient := listener.client.(*knxDummyInterface)\n\n\ttestMessages := []message{\n\t\t{\"1/1/1\", \"1.001\", true},\n\t\t{\"1/1/1\", \"1.001\", false},\n\t\t{\"1/1/2\", \"1.001\", false},\n\t\t{\"1/1/2\", \"1.001\", true},\n\t}\n\n\tfor _, testcase := range testMessages {\n\t\tevent := produceKnxEvent(t, testcase.address, testcase.dpt, testcase.value)\n\t\tclient.Send(*event)\n\t}\n\n\t// Give the accumulator some time to collect the data\n\trequire.Eventuallyf(t, func() bool {\n\t\treturn acc.NMetrics() >= 2\n\t}, 3*time.Second, 100*time.Millisecond, \"expected 2 metric but got %d\", acc.NMetrics())\n\trequire.True(t, listener.connected.Load())\n\n\tclient.Close()\n\n\trequire.Eventually(t, func() bool {\n\t\treturn !listener.connected.Load()\n\t}, 3*time.Second, 100*time.Millisecond, \"no disconnect\")\n\tacc.Lock()\n\terr := acc.FirstError()\n\tacc.Unlock()\n\trequire.ErrorContains(t, err, \"disconnected from bus\")\n\n\trequire.NoError(t, listener.Gather(&acc))\n\trequire.Eventually(t, func() bool {\n\t\treturn listener.connected.Load()\n\t}, 3*time.Second, 100*time.Millisecond, \"no reconnect\")\n\tclient = listener.client.(*knxDummyInterface)\n\n\tfor _, testcase := range testMessages {\n\t\tevent := produceKnxEvent(t, testcase.address, testcase.dpt, testcase.value)\n\t\tclient.Send(*event)\n\t}\n\n\t// Give the accumulator some time to collect the data\n\trequire.Eventuallyf(t, func() bool {\n\t\treturn acc.NMetrics() >= 2\n\t}, 3*time.Second, 100*time.Millisecond, \"expected 2 metric but got %d\", acc.NMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/knx_listener/sample.conf",
    "content": "# Listener capable of handling KNX bus messages provided through a KNX-IP Interface.\n[[inputs.knx_listener]]\n  ## Type of KNX-IP interface.\n  ## Can be either \"tunnel_udp\", \"tunnel_tcp\", \"tunnel\" (alias for tunnel_udp) or \"router\".\n  # service_type = \"tunnel\"\n\n  ## Address of the KNX-IP interface.\n  service_address = \"localhost:3671\"\n\n  ## Measurement definition(s)\n  # [[inputs.knx_listener.measurement]]\n  #   ## Name of the measurement\n  #   name = \"temperature\"\n  #   ## Datapoint-Type (DPT) of the KNX messages\n  #   dpt = \"9.001\"\n  #   ## Use the string representation instead of the numerical value for the\n  #   ## datapoint-type and the addresses below\n  #   # as_string = false\n  #   ## List of Group-Addresses (GAs) assigned to the measurement\n  #   addresses = [\"5/5/1\"]\n\n  # [[inputs.knx_listener.measurement]]\n  #   name = \"illumination\"\n  #   dpt = \"9.004\"\n  #   addresses = [\"5/5/3\"]\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/README.md",
    "content": "# Kubernetes Inventory Input Plugin\n\nThis plugin gathers metrics from [Kubernetes][kubernetes] resources.\n\n> [!NOTE]\n> This plugin requires Kubernetes version 1.11+.\n\nThe gathered resources include for example daemon sets, deployments, endpoints,\ningress, nodes, persistent volumes and many more.\n\n> [!CRITICAL]\n> This plugin produces high cardinality data, which when not controlled for will\n> cause high load on your database. Please make sure to [filter][filtering] the\n> produced metrics or configure your database to avoid cardinality issues!\n\n⭐ Telegraf v1.10.0\n🏷️ containers\n💻 all\n\n[kubernetes]: https://kubernetes.io/\n[filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from the Kubernetes api\n[[inputs.kube_inventory]]\n  ## URL for the Kubernetes API.\n  ## If empty in-cluster config with POD's service account token will be used.\n  # url = \"\"\n\n  ## URL for the kubelet, if set it will be used to collect the pods resource metrics\n  # url_kubelet = \"http://127.0.0.1:10255\"\n\n  ## Namespace to use. Set to \"\" to use all namespaces.\n  # namespace = \"default\"\n\n  ## Node name to filter to. No filtering by default.\n  # node_name = \"\"\n\n  ## Use bearer token for authorization.\n  ## Ignored if url is empty and in-cluster config is used.\n  # bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional Resources to exclude from gathering\n  ## Leave them with blank with try to gather everything available.\n  ## Values can be - \"daemonsets\", deployments\", \"endpoints\", \"ingress\",\n  ## \"nodes\", \"persistentvolumes\", \"persistentvolumeclaims\", \"pods\", \"services\",\n  ## \"statefulsets\"\n  # resource_exclude = [ \"deployments\", \"nodes\", \"statefulsets\" ]\n\n  ## Optional Resources to include when gathering\n  ## Overrides resource_exclude if both set.\n  # resource_include = [ \"deployments\", \"nodes\", \"statefulsets\" ]\n\n  ## selectors to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all selectors as tags\n  ## selector_exclude overrides selector_include if both set.\n  # selector_include = []\n  # selector_exclude = [\"*\"]\n\n  ## Optional TLS Config\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Uncomment to remove deprecated metrics.\n  # fieldexclude = [\"terminated_reason\"]\n```\n\n## Kubernetes Permissions\n\nIf using [RBAC authorization][rbac], you will need to create a cluster role to\nlist \"persistentvolumes\" and \"nodes\". You will then need to make an [aggregated\nClusterRole][agg] that will eventually be bound to a user or group.\n\n[rbac]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/\n[agg]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles\n\n```yaml\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: influx:cluster:viewer\n  labels:\n    rbac.authorization.k8s.io/aggregate-view-telegraf: \"true\"\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\", \"nodes\"]\n    verbs: [\"get\", \"list\"]\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: influx:telegraf\naggregationRule:\n  clusterRoleSelectors:\n    - matchLabels:\n        rbac.authorization.k8s.io/aggregate-view-telegraf: \"true\"\n    - matchLabels:\n        rbac.authorization.k8s.io/aggregate-to-view: \"true\"\nrules: [] # Rules are automatically filled in by the controller manager.\n```\n\nBind the newly created aggregated ClusterRole with the following config file,\nupdating the subjects as needed.\n\n```yaml\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: influx:telegraf:viewer\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: influx:telegraf\nsubjects:\n  - kind: ServiceAccount\n    name: telegraf\n    namespace: default\n```\n\n## Quickstart in k3s\n\nWhen monitoring [k3s](https://k3s.io) server instances one can re-use already\ngenerated administration token. This is less secure than using the more\nrestrictive dedicated telegraf user but more convenient to set up.\n\n```console\n# replace `telegraf` with the user the telegraf process is running as\n$ install -o telegraf -m400 /var/lib/rancher/k3s/server/token /run/telegraf-kubernetes-token\n$ install -o telegraf -m400 /var/lib/rancher/k3s/server/tls/client-admin.crt /run/telegraf-kubernetes-cert\n$ install -o telegraf -m400 /var/lib/rancher/k3s/server/tls/client-admin.key /run/telegraf-kubernetes-key\n```\n\n```toml\n[kube_inventory]\nbearer_token = \"/run/telegraf-kubernetes-token\"\ntls_cert = \"/run/telegraf-kubernetes-cert\"\ntls_key = \"/run/telegraf-kubernetes-key\"\n```\n\n## Metrics\n\n- kubernetes_daemonset\n  - tags:\n    - daemonset_name\n    - namespace\n    - selector (\\*varies)\n  - fields:\n    - generation\n    - current_number_scheduled\n    - desired_number_scheduled\n    - number_available\n    - number_misscheduled\n    - number_ready\n    - number_unavailable\n    - updated_number_scheduled\n\n- kubernetes_deployment\n  - tags:\n    - deployment_name\n    - namespace\n    - selector (\\*varies)\n  - fields:\n    - replicas_available\n    - replicas_unavailable\n    - created\n\n- kubernetes_endpoints\n  - tags:\n    - endpoint_name\n    - namespace\n    - hostname\n    - node_name\n    - port_name\n    - port_protocol\n    - kind (\\*varies)\n  - fields:\n    - created\n    - generation\n    - ready\n    - port\n\n- kubernetes_ingress\n  - tags:\n    - ingress_name\n    - namespace\n    - hostname\n    - ip\n    - backend_service_name\n    - path\n    - host\n  - fields:\n    - created\n    - generation\n    - backend_service_port\n    - tls\n\n- kubernetes_node\n  - tags:\n    - node_name\n    - status\n    - condition\n    - cluster_namespace\n  - fields:\n    - capacity_cpu_cores\n    - capacity_millicpu_cores\n    - capacity_memory_bytes\n    - capacity_pods\n    - allocatable_cpu_cores\n    - allocatable_millicpu_cores\n    - allocatable_memory_bytes\n    - allocatable_pods\n    - status_condition\n    - spec_unschedulable\n    - node_count\n\n- kubernetes_persistentvolume\n  - tags:\n    - pv_name\n    - phase\n    - storageclass\n  - fields:\n    - phase_type (int, [see below](#pv-phase_type))\n\n- kubernetes_persistentvolumeclaim\n  - tags:\n    - pvc_name\n    - namespace\n    - phase\n    - storageclass\n    - selector (\\*varies)\n  - fields:\n    - phase_type (int, [see below](#pvc-phase_type))\n\n- kubernetes_pod_container\n  - tags:\n    - container_name\n    - namespace\n    - node_name\n    - pod_name\n    - node_selector (\\*varies)\n    - phase\n    - state\n    - readiness\n    - condition\n  - fields:\n    - restarts_total\n    - state_code\n    - state_reason\n    - phase_reason\n    - terminated_reason (string, deprecated in 1.15: use `state_reason` instead)\n    - resource_requests_millicpu_units\n    - resource_requests_memory_bytes\n    - resource_limits_millicpu_units\n    - resource_limits_memory_bytes\n    - status_condition\n\n- kubernetes_service\n  - tags:\n    - service_name\n    - namespace\n    - port_name\n    - port_protocol\n    - external_name\n    - cluster_ip\n    - selector (\\*varies)\n  - fields\n    - created\n    - generation\n    - port\n    - target_port\n\n- kubernetes_statefulset\n  - tags:\n    - statefulset_name\n    - namespace\n    - selector (\\*varies)\n  - fields:\n    - created\n    - generation\n    - replicas\n    - replicas_current\n    - replicas_ready\n    - replicas_updated\n    - spec_replicas\n    - observed_generation\n\n- kubernetes_resourcequota\n  - tags:\n    - resource\n    - namespace\n  - fields:\n    - hard_cpu_limits\n    - hard_cpu_requests\n    - hard_memory_limit\n    - hard_memory_requests\n    - hard_pods\n    - used_cpu_limits\n    - used_cpu_requests\n    - used_memory_limits\n    - used_memory_requests\n    - used_pods\n\n- kubernetes_certificate\n  - tags:\n    - common_name\n    - signature_algorithm\n    - public_key_algorithm\n    - issuer_common_name\n    - san\n    - verification\n    - name\n    - namespace\n  - fields:\n    - age\n    - expiry\n    - startdate\n    - enddate\n    - verification_code\n\n### kubernetes node status `status`\n\nThe node status ready can mean 3 different values.\n\n| Tag value | Corresponding field value | Meaning  |\n| --------- | ------------------------- | -------- |\n| ready     | 0                         | NotReady |\n| ready     | 1                         | Ready    |\n| ready     | 2                         | Unknown  |\n\n### pv `phase_type`\n\nThe persistentvolume \"phase\" is saved in the `phase` tag with a correlated\nnumeric field called `phase_type` corresponding with that tag value.\n\n| Tag value | Corresponding field value |\n| --------- | ------------------------- |\n| bound     | 0                         |\n| failed    | 1                         |\n| pending   | 2                         |\n| released  | 3                         |\n| available | 4                         |\n| unknown   | 5                         |\n\n### pvc `phase_type`\n\nThe persistentvolumeclaim \"phase\" is saved in the `phase` tag with a correlated\nnumeric field called `phase_type` corresponding with that tag value.\n\n| Tag value | Corresponding field value |\n| --------- | ------------------------- |\n| bound     | 0                         |\n| lost      | 1                         |\n| pending   | 2                         |\n| unknown   | 3                         |\n\n## Example Output\n\n```text\nkubernetes_configmap,configmap_name=envoy-config,namespace=default,resource_version=56593031 created=1544103867000000000i 1547597616000000000\nkubernetes_daemonset,daemonset_name=telegraf,selector_select1=s1,namespace=logging number_unavailable=0i,desired_number_scheduled=11i,number_available=11i,number_misscheduled=8i,number_ready=11i,updated_number_scheduled=11i,created=1527758699000000000i,generation=16i,current_number_scheduled=11i 1547597616000000000\nkubernetes_deployment,deployment_name=deployd,selector_select1=s1,namespace=default replicas_unavailable=0i,created=1544103082000000000i,replicas_available=1i 1547597616000000000\nkubernetes_node,host=vjain node_count=8i 1628918652000000000\nkubernetes_node,condition=Ready,host=vjain,node_name=ip-172-17-0-2.internal,status=True status_condition=1i 1629177980000000000\nkubernetes_node,cluster_namespace=tools,condition=Ready,host=vjain,node_name=ip-172-17-0-2.internal,status=True allocatable_cpu_cores=4i,allocatable_memory_bytes=7186567168i,allocatable_millicpu_cores=4000i,allocatable_pods=110i,capacity_cpu_cores=4i,capacity_memory_bytes=7291424768i,capacity_millicpu_cores=4000i,capacity_pods=110i,spec_unschedulable=0i,status_condition=1i 1628918652000000000\nkubernetes_resourcequota,host=vjain,namespace=default,resource=pods-high hard_cpu=1000i,hard_memory=214748364800i,hard_pods=10i,used_cpu=0i,used_memory=0i,used_pods=0i 1629110393000000000\nkubernetes_resourcequota,host=vjain,namespace=default,resource=pods-low hard_cpu=5i,hard_memory=10737418240i,hard_pods=10i,used_cpu=0i,used_memory=0i,used_pods=0i 1629110393000000000\nkubernetes_persistentvolume,phase=Released,pv_name=pvc-aaaaaaaa-bbbb-cccc-1111-222222222222,storageclass=ebs-1-retain phase_type=3i 1547597616000000000\nkubernetes_persistentvolumeclaim,namespace=default,phase=Bound,pvc_name=data-etcd-0,selector_select1=s1,storageclass=ebs-1-retain phase_type=0i 1547597615000000000\nkubernetes_pod,namespace=default,node_name=ip-172-17-0-2.internal,pod_name=tick1 last_transition_time=1547578322000000000i,ready=\"false\" 1547597616000000000\nkubernetes_service,cluster_ip=172.29.61.80,namespace=redis-cache-0001,port_name=redis,port_protocol=TCP,selector_app=myapp,selector_io.kompose.service=redis,selector_role=slave,service_name=redis-slave created=1588690034000000000i,generation=0i,port=6379i,target_port=0i 1547597616000000000\nkubernetes_pod_container,condition=Ready,host=vjain,pod_name=uefi-5997f76f69-xzljt,status=True status_condition=1i 1629177981000000000\nkubernetes_pod_container,container_name=telegraf,namespace=default,node_name=ip-172-17-0-2.internal,node_selector_node-role.kubernetes.io/compute=true,pod_name=tick1,phase=Running,state=running,readiness=ready resource_requests_cpu_units=0.1,resource_limits_memory_bytes=524288000,resource_limits_cpu_units=0.5,restarts_total=0i,state_code=0i,state_reason=\"\",phase_reason=\"\",resource_requests_memory_bytes=524288000 1547597616000000000\nkubernetes_statefulset,namespace=default,selector_select1=s1,statefulset_name=etcd replicas_updated=3i,spec_replicas=3i,observed_generation=1i,created=1544101669000000000i,generation=1i,replicas=3i,replicas_current=3i,replicas_ready=3i 1547597616000000000\n```\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/certificate.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"strings\"\n\t\"time\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectSecrets(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getTLSSecrets(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, i := range list.Items {\n\t\tgatherCertificates(i, acc)\n\t}\n}\n\nfunc getFields(cert *x509.Certificate, now time.Time) map[string]interface{} {\n\tage := int(now.Sub(cert.NotBefore).Seconds())\n\texpiry := int(cert.NotAfter.Sub(now).Seconds())\n\tstartdate := cert.NotBefore.Unix()\n\tenddate := cert.NotAfter.Unix()\n\n\tfields := map[string]interface{}{\n\t\t\"age\":       age,\n\t\t\"expiry\":    expiry,\n\t\t\"startdate\": startdate,\n\t\t\"enddate\":   enddate,\n\t}\n\n\treturn fields\n}\n\nfunc getTags(cert *x509.Certificate) map[string]string {\n\ttags := map[string]string{\n\t\t\"common_name\":          cert.Subject.CommonName,\n\t\t\"signature_algorithm\":  cert.SignatureAlgorithm.String(),\n\t\t\"public_key_algorithm\": cert.PublicKeyAlgorithm.String(),\n\t}\n\ttags[\"issuer_common_name\"] = cert.Issuer.CommonName\n\n\tsan := append(cert.DNSNames, cert.EmailAddresses...)\n\tfor _, ip := range cert.IPAddresses {\n\t\tsan = append(san, ip.String())\n\t}\n\tfor _, uri := range cert.URIs {\n\t\tsan = append(san, uri.String())\n\t}\n\ttags[\"san\"] = strings.Join(san, \",\")\n\n\treturn tags\n}\n\nfunc gatherCertificates(r corev1.Secret, acc telegraf.Accumulator) {\n\tnow := time.Now()\n\n\tfor resourceName, val := range r.Data {\n\t\tif resourceName != \"tls.crt\" {\n\t\t\tcontinue\n\t\t}\n\t\tblock, _ := pem.Decode(val)\n\t\tif block == nil {\n\t\t\treturn\n\t\t}\n\t\tcert, err := x509.ParseCertificate(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tfields := getFields(cert, now)\n\t\ttags := getTags(cert)\n\t\ttags[\"name\"] = r.Name\n\t\ttags[\"namespace\"] = r.Namespace\n\t\topts := x509.VerifyOptions{\n\t\t\tKeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},\n\t\t}\n\t\t_, err = cert.Verify(opts)\n\t\tif err == nil {\n\t\t\ttags[\"verification\"] = \"valid\"\n\t\t\tfields[\"verification_code\"] = 0\n\t\t} else {\n\t\t\ttags[\"verification\"] = \"invalid\"\n\t\t\tfields[\"verification_code\"] = 1\n\t\t}\n\t\tacc.AddFields(certificateMeasurement, fields, tags)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/client.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"time\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\tnetv1 \"k8s.io/api/networking/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\ntype client struct {\n\tnamespace string\n\ttimeout   time.Duration\n\t*kubernetes.Clientset\n}\n\nfunc newClient(baseURL, namespace, bearerTokenFile string, timeout time.Duration, tlsConfig tls.ClientConfig) (*client, error) {\n\tvar clientConfig *rest.Config\n\tvar err error\n\n\tif baseURL == \"\" {\n\t\tclientConfig, err = rest.InClusterConfig()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tclientConfig = &rest.Config{\n\t\t\tTLSClientConfig: rest.TLSClientConfig{\n\t\t\t\tServerName: tlsConfig.ServerName,\n\t\t\t\tInsecure:   tlsConfig.InsecureSkipVerify,\n\t\t\t\tCAFile:     tlsConfig.TLSCA,\n\t\t\t\tCertFile:   tlsConfig.TLSCert,\n\t\t\t\tKeyFile:    tlsConfig.TLSKey,\n\t\t\t},\n\t\t\tHost:          baseURL,\n\t\t\tContentConfig: rest.ContentConfig{},\n\t\t}\n\n\t\tif bearerTokenFile != \"\" {\n\t\t\tclientConfig.BearerTokenFile = bearerTokenFile\n\t\t}\n\t}\n\n\tc, err := kubernetes.NewForConfig(clientConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &client{\n\t\tClientset: c,\n\t\ttimeout:   timeout,\n\t\tnamespace: namespace,\n\t}, nil\n}\n\nfunc newHTTPClient(tlsConfig tls.ClientConfig, bearerTokenFile string, responseTimeout config.Duration) (*http.Client, error) {\n\ttlsCfg, err := tlsConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tclientConfig := &rest.Config{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tContentConfig:   rest.ContentConfig{},\n\t\tTimeout:         time.Duration(responseTimeout),\n\t\tBearerTokenFile: bearerTokenFile,\n\t}\n\treturn rest.HTTPClientFor(clientConfig)\n}\n\nfunc (c *client) getDaemonSets(ctx context.Context) (*appsv1.DaemonSetList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.AppsV1().DaemonSets(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getDeployments(ctx context.Context) (*appsv1.DeploymentList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.AppsV1().Deployments(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getEndpoints(ctx context.Context) (*discoveryv1.EndpointSliceList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.DiscoveryV1().EndpointSlices(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getIngress(ctx context.Context) (*netv1.IngressList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.NetworkingV1().Ingresses(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getNodes(ctx context.Context, name string) (*corev1.NodeList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\tvar fieldSelector string\n\tif name != \"\" {\n\t\tfieldSelector = \"metadata.name=\" + name\n\t}\n\treturn c.CoreV1().Nodes().List(ctx, metav1.ListOptions{FieldSelector: fieldSelector})\n}\n\nfunc (c *client) getPersistentVolumes(ctx context.Context) (*corev1.PersistentVolumeList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.CoreV1().PersistentVolumes().List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getPersistentVolumeClaims(ctx context.Context) (*corev1.PersistentVolumeClaimList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.CoreV1().PersistentVolumeClaims(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getPods(ctx context.Context, nodeName string) (*corev1.PodList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\n\tvar fieldSelector string\n\tif nodeName != \"\" {\n\t\tfieldSelector = \"spec.nodeName=\" + nodeName\n\t}\n\treturn c.CoreV1().Pods(c.namespace).List(ctx, metav1.ListOptions{FieldSelector: fieldSelector})\n}\n\nfunc (c *client) getServices(ctx context.Context) (*corev1.ServiceList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.CoreV1().Services(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getStatefulSets(ctx context.Context) (*appsv1.StatefulSetList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.AppsV1().StatefulSets(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getResourceQuotas(ctx context.Context) (*corev1.ResourceQuotaList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\treturn c.CoreV1().ResourceQuotas(c.namespace).List(ctx, metav1.ListOptions{})\n}\n\nfunc (c *client) getTLSSecrets(ctx context.Context) (*corev1.SecretList, error) {\n\tctx, cancel := context.WithTimeout(ctx, c.timeout)\n\tdefer cancel()\n\tlabelSelector := metav1.LabelSelector{MatchLabels: map[string]string{\"type\": \"kubernetes.io/tls\"}}\n\treturn c.CoreV1().Secrets(c.namespace).List(ctx, metav1.ListOptions{\n\t\tFieldSelector: labels.Set(labelSelector.MatchLabels).String(),\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/client_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n)\n\ntype mockHandler struct {\n\tresponseMap map[string]interface{}\n}\n\nfunc toPtr[T any](v T) *T {\n\treturn &v\n}\n\nfunc TestNewClient(t *testing.T) {\n\t_, err := newClient(\"https://127.0.0.1:443/\", \"default\", \"\", time.Second, tls.ClientConfig{})\n\trequire.NoErrorf(t, err, \"Failed to create new client: %v\", err)\n\n\t_, err = newClient(\"https://127.0.0.1:443/\", \"default\", \"nonexistantFile\", time.Second, tls.ClientConfig{})\n\trequire.Errorf(t, err, \"Failed to read token file \\\"file\\\": open file: no such file or directory: %v\", err)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/daemonset.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\tapps \"k8s.io/api/apps/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectDaemonSets(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getDaemonSets(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range list.Items {\n\t\tki.gatherDaemonSet(&list.Items[i], acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherDaemonSet(d *apps.DaemonSet, acc telegraf.Accumulator) {\n\tfields := map[string]interface{}{\n\t\t\"generation\":               d.Generation,\n\t\t\"current_number_scheduled\": d.Status.CurrentNumberScheduled,\n\t\t\"desired_number_scheduled\": d.Status.DesiredNumberScheduled,\n\t\t\"number_available\":         d.Status.NumberAvailable,\n\t\t\"number_misscheduled\":      d.Status.NumberMisscheduled,\n\t\t\"number_ready\":             d.Status.NumberReady,\n\t\t\"number_unavailable\":       d.Status.NumberUnavailable,\n\t\t\"updated_number_scheduled\": d.Status.UpdatedNumberScheduled,\n\t}\n\ttags := map[string]string{\n\t\t\"daemonset_name\": d.Name,\n\t\t\"namespace\":      d.Namespace,\n\t}\n\tfor key, val := range d.Spec.Selector.MatchLabels {\n\t\tif ki.selectorFilter.Match(key) {\n\t\t\ttags[\"selector_\"+key] = val\n\t\t}\n\t}\n\n\tcreationTS := d.GetCreationTimestamp()\n\tif !creationTS.IsZero() {\n\t\tfields[\"created\"] = d.GetCreationTimestamp().UnixNano()\n\t}\n\n\tacc.AddFields(daemonSetMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/daemonset_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tapps \"k8s.io/api/apps/v1\"\n\tmeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDaemonSet(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no daemon set\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/daemonsets/\": &apps.DaemonSetList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect daemonsets\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/daemonsets/\": &apps.DaemonSetList{\n\t\t\t\t\t\tItems: []apps.DaemonSet{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: apps.DaemonSetStatus{\n\t\t\t\t\t\t\t\t\tCurrentNumberScheduled: 3,\n\t\t\t\t\t\t\t\t\tDesiredNumberScheduled: 5,\n\t\t\t\t\t\t\t\t\tNumberAvailable:        2,\n\t\t\t\t\t\t\t\t\tNumberMisscheduled:     2,\n\t\t\t\t\t\t\t\t\tNumberReady:            1,\n\t\t\t\t\t\t\t\t\tNumberUnavailable:      1,\n\t\t\t\t\t\t\t\t\tUpdatedNumberScheduled: 2,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: meta.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration: 11221,\n\t\t\t\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\t\t\t\tName:       \"daemon1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: meta.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: apps.DaemonSetSpec{\n\t\t\t\t\t\t\t\t\tSelector: &meta.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_daemonset\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"daemonset_name\":   \"daemon1\",\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"generation\":               int64(11221),\n\t\t\t\t\t\t\"current_number_scheduled\": int32(3),\n\t\t\t\t\t\t\"desired_number_scheduled\": int32(5),\n\t\t\t\t\t\t\"number_available\":         int32(2),\n\t\t\t\t\t\t\"number_misscheduled\":      int32(2),\n\t\t\t\t\t\t\"number_ready\":             int32(1),\n\t\t\t\t\t\t\"number_unavailable\":       int32(1),\n\t\t\t\t\t\t\"updated_number_scheduled\": int32(2),\n\t\t\t\t\t\t\"created\":                  now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/daemonsets/\"]).(*apps.DaemonSetList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherDaemonSet(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestDaemonSetSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/daemonsets/\": &apps.DaemonSetList{\n\t\t\tItems: []apps.DaemonSet{\n\t\t\t\t{\n\t\t\t\t\tStatus: apps.DaemonSetStatus{\n\t\t\t\t\t\tCurrentNumberScheduled: 3,\n\t\t\t\t\t\tDesiredNumberScheduled: 5,\n\t\t\t\t\t\tNumberAvailable:        2,\n\t\t\t\t\t\tNumberMisscheduled:     2,\n\t\t\t\t\t\tNumberReady:            1,\n\t\t\t\t\t\tNumberUnavailable:      1,\n\t\t\t\t\t\tUpdatedNumberScheduled: 2,\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: meta.ObjectMeta{\n\t\t\t\t\t\tGeneration: 11221,\n\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\tName:       \"daemon1\",\n\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCreationTimestamp: meta.Time{Time: time.Now()},\n\t\t\t\t\t},\n\t\t\t\t\tSpec: apps.DaemonSetSpec{\n\t\t\t\t\t\tSelector: &meta.LabelSelector{\n\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/daemonsets/\"]).(*apps.DaemonSetList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherDaemonSet(&items[i], acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/deployment.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\t\"k8s.io/api/apps/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectDeployments(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getDeployments(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range list.Items {\n\t\tki.gatherDeployment(&list.Items[i], acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherDeployment(d *v1.Deployment, acc telegraf.Accumulator) {\n\tfields := map[string]interface{}{\n\t\t\"replicas_available\":   d.Status.AvailableReplicas,\n\t\t\"replicas_unavailable\": d.Status.UnavailableReplicas,\n\t\t\"created\":              d.GetCreationTimestamp().UnixNano(),\n\t}\n\ttags := map[string]string{\n\t\t\"deployment_name\": d.Name,\n\t\t\"namespace\":       d.Namespace,\n\t}\n\tfor key, val := range d.Spec.Selector.MatchLabels {\n\t\tif ki.selectorFilter.Match(key) {\n\t\t\ttags[\"selector_\"+key] = val\n\t\t}\n\t}\n\n\tacc.AddFields(deploymentMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/deployment_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"k8s.io/api/apps/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDeployment(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no deployments\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/deployments/\": &v1.DeploymentList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect deployments\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/deployments/\": &v1.DeploymentList{\n\t\t\t\t\t\tItems: []v1.Deployment{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: v1.DeploymentStatus{\n\t\t\t\t\t\t\t\t\tReplicas:            3,\n\t\t\t\t\t\t\t\t\tAvailableReplicas:   1,\n\t\t\t\t\t\t\t\t\tUnavailableReplicas: 4,\n\t\t\t\t\t\t\t\t\tUpdatedReplicas:     2,\n\t\t\t\t\t\t\t\t\tObservedGeneration:  9121,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: v1.DeploymentSpec{\n\t\t\t\t\t\t\t\t\tStrategy: v1.DeploymentStrategy{\n\t\t\t\t\t\t\t\t\t\tRollingUpdate: &v1.RollingUpdateDeployment{\n\t\t\t\t\t\t\t\t\t\t\tMaxUnavailable: &intstr.IntOrString{\n\t\t\t\t\t\t\t\t\t\t\t\tIntVal: 30,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tMaxSurge: &intstr.IntOrString{\n\t\t\t\t\t\t\t\t\t\t\t\tIntVal: 20,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tReplicas: toPtr(int32(4)),\n\t\t\t\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration: 11221,\n\t\t\t\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\t\t\t\tName:       \"deploy1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_deployment\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"deployment_name\":  \"deploy1\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"replicas_available\":   int32(1),\n\t\t\t\t\t\t\"replicas_unavailable\": int32(4),\n\t\t\t\t\t\t\"created\":              now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/deployments/\"]).(*v1.DeploymentList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherDeployment(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestDeploymentSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/deployments/\": &v1.DeploymentList{\n\t\t\tItems: []v1.Deployment{\n\t\t\t\t{\n\t\t\t\t\tStatus: v1.DeploymentStatus{\n\t\t\t\t\t\tReplicas:            3,\n\t\t\t\t\t\tAvailableReplicas:   1,\n\t\t\t\t\t\tUnavailableReplicas: 4,\n\t\t\t\t\t\tUpdatedReplicas:     2,\n\t\t\t\t\t\tObservedGeneration:  9121,\n\t\t\t\t\t},\n\t\t\t\t\tSpec: v1.DeploymentSpec{\n\t\t\t\t\t\tStrategy: v1.DeploymentStrategy{\n\t\t\t\t\t\t\tRollingUpdate: &v1.RollingUpdateDeployment{\n\t\t\t\t\t\t\t\tMaxUnavailable: &intstr.IntOrString{\n\t\t\t\t\t\t\t\t\tIntVal: 30,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tMaxSurge: &intstr.IntOrString{\n\t\t\t\t\t\t\t\t\tIntVal: 20,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tReplicas: toPtr(int32(4)),\n\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\tGeneration: 11221,\n\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\tName:       \"deploy1\",\n\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/deployments/\"]).(*v1.DeploymentList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherDeployment(&items[i], acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/endpoint.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectEndpoints(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getEndpoints(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, i := range list.Items {\n\t\tgatherEndpoint(i, acc)\n\t}\n}\n\nfunc gatherEndpoint(e discoveryv1.EndpointSlice, acc telegraf.Accumulator) {\n\tcreationTS := e.GetCreationTimestamp()\n\tif creationTS.IsZero() {\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"created\":    e.GetCreationTimestamp().UnixNano(),\n\t\t\"generation\": e.Generation,\n\t}\n\n\ttags := map[string]string{\n\t\t\"endpoint_name\": e.Name,\n\t\t\"namespace\":     e.Namespace,\n\t}\n\n\tfor _, endpoint := range e.Endpoints {\n\t\tif endpoint.Conditions.Ready == nil {\n\t\t\tfields[\"ready\"] = true\n\t\t} else {\n\t\t\tfields[\"ready\"] = *endpoint.Conditions.Ready\n\t\t}\n\n\t\tif endpoint.Hostname != nil {\n\t\t\ttags[\"hostname\"] = *endpoint.Hostname\n\t\t}\n\t\tif endpoint.NodeName != nil {\n\t\t\ttags[\"node_name\"] = *endpoint.NodeName\n\t\t}\n\t\tif endpoint.TargetRef != nil {\n\t\t\ttags[strings.ToLower(endpoint.TargetRef.Kind)] = endpoint.TargetRef.Name\n\t\t}\n\n\t\tfor _, port := range e.Ports {\n\t\t\tif port.Port != nil {\n\t\t\t\tfields[\"port\"] = *port.Port\n\t\t\t}\n\n\t\t\ttags[\"port_name\"] = *port.Name\n\t\t\ttags[\"port_protocol\"] = string(*port.Protocol)\n\n\t\t\tacc.AddFields(endpointMeasurement, fields, tags)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/endpoint_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestEndpoint(t *testing.T) {\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no endpoints\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect ready endpoints\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tNodeName: toPtr(\"b.storage.internal\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(true),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"server\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-6\",\n\t\t\t\t\t\t\"node_name\":     \"b.storage.internal\",\n\t\t\t\t\t\t\"port_name\":     \"server\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      true,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect notready endpoints\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tNodeName: toPtr(\"b.storage.internal\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(false),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"server\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-6\",\n\t\t\t\t\t\t\"node_name\":     \"b.storage.internal\",\n\t\t\t\t\t\t\"port_name\":     \"server\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      false,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"endpoints missing node_name\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(false),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-12\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-12\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(true),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"server\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-6\",\n\t\t\t\t\t\t\"port_name\":     \"server\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      false,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-12\",\n\t\t\t\t\t\t\"port_name\":     \"server\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-12\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      true,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"endpoints null\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: nil,\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"server\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput:   make([]telegraf.Metric, 0),\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"default port name\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(false),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-6\",\n\t\t\t\t\t\t\"port_name\":     \"\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      false,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"ports null\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(false),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-12\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-12\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\t\t\t\t\tReady: toPtr(true),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: nil,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput:   make([]telegraf.Metric, 0),\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"endpoints and ports null\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: nil,\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: nil,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput:   make([]telegraf.Metric, 0),\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"empty conditions\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/endpoints/\": &discoveryv1.EndpointSliceList{\n\t\t\t\t\t\tItems: []discoveryv1.EndpointSlice{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostname: toPtr(\"storage-6\"),\n\t\t\t\t\t\t\t\t\t\tTargetRef: &corev1.ObjectReference{\n\t\t\t\t\t\t\t\t\t\t\tKind: \"pod\",\n\t\t\t\t\t\t\t\t\t\t\tName: \"storage-6\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"storage\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tPorts: []discoveryv1.EndpointPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tName:     toPtr(\"\"),\n\t\t\t\t\t\t\t\t\t\tProtocol: toPtr(corev1.Protocol(\"TCP\")),\n\t\t\t\t\t\t\t\t\t\tPort:     toPtr(int32(8080)),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_endpoint\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"endpoint_name\": \"storage\",\n\t\t\t\t\t\t\"namespace\":     \"ns1\",\n\t\t\t\t\t\t\"hostname\":      \"storage-6\",\n\t\t\t\t\t\t\"port_name\":     \"\",\n\t\t\t\t\t\t\"port_protocol\": \"TCP\",\n\t\t\t\t\t\t\"pod\":           \"storage-6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"ready\":      true,\n\t\t\t\t\t\t\"port\":       int32(8080),\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tacc := new(testutil.Accumulator)\n\t\tfor _, endpoint := range ((v.handler.responseMap[\"/endpoints/\"]).(*discoveryv1.EndpointSliceList)).Items {\n\t\t\tgatherEndpoint(endpoint, acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/ingress.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\tnetv1 \"k8s.io/api/networking/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectIngress(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getIngress(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, i := range list.Items {\n\t\tgatherIngress(i, acc)\n\t}\n}\n\nfunc gatherIngress(i netv1.Ingress, acc telegraf.Accumulator) {\n\tcreationTS := i.GetCreationTimestamp()\n\tif creationTS.IsZero() {\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"created\":    i.GetCreationTimestamp().UnixNano(),\n\t\t\"generation\": i.Generation,\n\t}\n\n\ttags := map[string]string{\n\t\t\"ingress_name\": i.Name,\n\t\t\"namespace\":    i.Namespace,\n\t}\n\n\tfor _, ingress := range i.Status.LoadBalancer.Ingress {\n\t\ttags[\"hostname\"] = ingress.Hostname\n\t\ttags[\"ip\"] = ingress.IP\n\n\t\tfor _, rule := range i.Spec.Rules {\n\t\t\tif rule.IngressRuleValue.HTTP == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, path := range rule.IngressRuleValue.HTTP.Paths {\n\t\t\t\tif path.Backend.Service != nil {\n\t\t\t\t\ttags[\"backend_service_name\"] = path.Backend.Service.Name\n\t\t\t\t\tfields[\"backend_service_port\"] = path.Backend.Service.Port.Number\n\t\t\t\t}\n\n\t\t\t\tfields[\"tls\"] = i.Spec.TLS != nil\n\n\t\t\t\ttags[\"path\"] = path.Path\n\t\t\t\ttags[\"host\"] = rule.Host\n\n\t\t\t\tacc.AddFields(ingressMeasurement, fields, tags)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/ingress_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tnetv1 \"k8s.io/api/networking/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIngress(t *testing.T) {\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no ingress\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/ingress/\": netv1.IngressList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect ingress\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/ingress/\": netv1.IngressList{\n\t\t\t\t\t\tItems: []netv1.Ingress{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: netv1.IngressStatus{\n\t\t\t\t\t\t\t\t\tLoadBalancer: netv1.IngressLoadBalancerStatus{\n\t\t\t\t\t\t\t\t\t\tIngress: []netv1.IngressLoadBalancerIngress{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tHostname: \"chron-1\",\n\t\t\t\t\t\t\t\t\t\t\t\tIP:       \"1.0.0.127\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: netv1.IngressSpec{\n\t\t\t\t\t\t\t\t\tRules: []netv1.IngressRule{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tHost: \"ui.internal\",\n\t\t\t\t\t\t\t\t\t\t\tIngressRuleValue: netv1.IngressRuleValue{\n\t\t\t\t\t\t\t\t\t\t\t\tHTTP: &netv1.HTTPIngressRuleValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\tPaths: []netv1.HTTPIngressPath{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPath: \"/\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tBackend: netv1.IngressBackend{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tService: &netv1.IngressServiceBackend{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tName: \"chronografd\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPort: netv1.ServiceBackendPort{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNumber: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"ui-lb\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_ingress\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"ingress_name\":         \"ui-lb\",\n\t\t\t\t\t\t\"namespace\":            \"ns1\",\n\t\t\t\t\t\t\"ip\":                   \"1.0.0.127\",\n\t\t\t\t\t\t\"hostname\":             \"chron-1\",\n\t\t\t\t\t\t\"backend_service_name\": \"chronografd\",\n\t\t\t\t\t\t\"host\":                 \"ui.internal\",\n\t\t\t\t\t\t\"path\":                 \"/\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"tls\":                  false,\n\t\t\t\t\t\t\"backend_service_port\": int32(8080),\n\t\t\t\t\t\t\"generation\":           int64(12),\n\t\t\t\t\t\t\"created\":              now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"no HTTPIngressRuleValue\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/ingress/\": netv1.IngressList{\n\t\t\t\t\t\tItems: []netv1.Ingress{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: netv1.IngressStatus{\n\t\t\t\t\t\t\t\t\tLoadBalancer: netv1.IngressLoadBalancerStatus{\n\t\t\t\t\t\t\t\t\t\tIngress: []netv1.IngressLoadBalancerIngress{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tHostname: \"chron-1\",\n\t\t\t\t\t\t\t\t\t\t\t\tIP:       \"1.0.0.127\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: netv1.IngressSpec{\n\t\t\t\t\t\t\t\t\tRules: []netv1.IngressRule{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tHost: \"ui.internal\",\n\t\t\t\t\t\t\t\t\t\t\tIngressRuleValue: netv1.IngressRuleValue{\n\t\t\t\t\t\t\t\t\t\t\t\tHTTP: nil,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"ui-lb\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"no IngressServiceBackend\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/ingress/\": netv1.IngressList{\n\t\t\t\t\t\tItems: []netv1.Ingress{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: netv1.IngressStatus{\n\t\t\t\t\t\t\t\t\tLoadBalancer: netv1.IngressLoadBalancerStatus{\n\t\t\t\t\t\t\t\t\t\tIngress: []netv1.IngressLoadBalancerIngress{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tHostname: \"chron-1\",\n\t\t\t\t\t\t\t\t\t\t\t\tIP:       \"1.0.0.127\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: netv1.IngressSpec{\n\t\t\t\t\t\t\t\t\tRules: []netv1.IngressRule{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tHost: \"ui.internal\",\n\t\t\t\t\t\t\t\t\t\t\tIngressRuleValue: netv1.IngressRuleValue{\n\t\t\t\t\t\t\t\t\t\t\t\tHTTP: &netv1.HTTPIngressRuleValue{\n\t\t\t\t\t\t\t\t\t\t\t\t\tPaths: []netv1.HTTPIngressPath{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tPath: \"/\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tBackend: netv1.IngressBackend{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tService: nil,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"ui-lb\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_ingress\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"ingress_name\": \"ui-lb\",\n\t\t\t\t\t\t\"namespace\":    \"ns1\",\n\t\t\t\t\t\t\"ip\":           \"1.0.0.127\",\n\t\t\t\t\t\t\"hostname\":     \"chron-1\",\n\t\t\t\t\t\t\"host\":         \"ui.internal\",\n\t\t\t\t\t\t\"path\":         \"/\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"tls\":        false,\n\t\t\t\t\t\t\"generation\": int64(12),\n\t\t\t\t\t\t\"created\":    now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tacc := new(testutil.Accumulator)\n\t\tfor _, ingress := range ((v.handler.responseMap[\"/ingress/\"]).(netv1.IngressList)).Items {\n\t\t\tgatherIngress(ingress, acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/kube_inventory.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kube_inventory\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar availableCollectors = map[string]func(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory){\n\t\"daemonsets\":             collectDaemonSets,\n\t\"deployments\":            collectDeployments,\n\t\"endpoints\":              collectEndpoints,\n\t\"ingress\":                collectIngress,\n\t\"nodes\":                  collectNodes,\n\t\"pods\":                   collectPods,\n\t\"services\":               collectServices,\n\t\"statefulsets\":           collectStatefulSets,\n\t\"persistentvolumes\":      collectPersistentVolumes,\n\t\"persistentvolumeclaims\": collectPersistentVolumeClaims,\n\t\"resourcequotas\":         collectResourceQuotas,\n\t\"secrets\":                collectSecrets,\n}\n\nconst (\n\tdaemonSetMeasurement             = \"kubernetes_daemonset\"\n\tdeploymentMeasurement            = \"kubernetes_deployment\"\n\tendpointMeasurement              = \"kubernetes_endpoint\"\n\tingressMeasurement               = \"kubernetes_ingress\"\n\tnodeMeasurement                  = \"kubernetes_node\"\n\tpersistentVolumeMeasurement      = \"kubernetes_persistentvolume\"\n\tpersistentVolumeClaimMeasurement = \"kubernetes_persistentvolumeclaim\"\n\tpodContainerMeasurement          = \"kubernetes_pod_container\"\n\tserviceMeasurement               = \"kubernetes_service\"\n\tstatefulSetMeasurement           = \"kubernetes_statefulset\"\n\tresourcequotaMeasurement         = \"kubernetes_resourcequota\"\n\tcertificateMeasurement           = \"kubernetes_certificate\"\n\n\tdefaultServiceAccountPath = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n)\n\ntype KubernetesInventory struct {\n\tURL             string          `toml:\"url\"`\n\tKubeletURL      string          `toml:\"url_kubelet\"`\n\tBearerToken     string          `toml:\"bearer_token\"`\n\tNamespace       string          `toml:\"namespace\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"` // Timeout specified as a string - 3s, 1m, 1h\n\tResourceExclude []string        `toml:\"resource_exclude\"`\n\tResourceInclude []string        `toml:\"resource_include\"`\n\tMaxConfigMapAge config.Duration `toml:\"max_config_map_age\"`\n\n\tSelectorInclude []string `toml:\"selector_include\"`\n\tSelectorExclude []string `toml:\"selector_exclude\"`\n\n\tNodeName string          `toml:\"node_name\"`\n\tLog      telegraf.Logger `toml:\"-\"`\n\n\ttls.ClientConfig\n\tclient     *client\n\thttpClient *http.Client\n\n\tselectorFilter filter.Filter\n}\n\nfunc (*KubernetesInventory) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ki *KubernetesInventory) Init() error {\n\t// If bearer_token is not provided, use the default service account.\n\tif ki.BearerToken == \"\" {\n\t\tki.BearerToken = defaultServiceAccountPath\n\t}\n\n\tvar err error\n\tki.client, err = newClient(ki.URL, ki.Namespace, ki.BearerToken, time.Duration(ki.ResponseTimeout), ki.ClientConfig)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ki.ResponseTimeout < config.Duration(time.Second) {\n\t\tki.ResponseTimeout = config.Duration(time.Second * 5)\n\t}\n\t// Only create an http client if we have a kubelet url\n\tif ki.KubeletURL != \"\" {\n\t\tki.httpClient, err = newHTTPClient(ki.ClientConfig, ki.BearerToken, ki.ResponseTimeout)\n\n\t\tif err != nil {\n\t\t\tki.Log.Warnf(\"unable to create http client: %v\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ki *KubernetesInventory) Gather(acc telegraf.Accumulator) (err error) {\n\tresourceFilter, err := filter.NewIncludeExcludeFilter(ki.ResourceInclude, ki.ResourceExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tki.selectorFilter, err = filter.NewIncludeExcludeFilter(ki.SelectorInclude, ki.SelectorExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\twg := sync.WaitGroup{}\n\tctx := context.Background()\n\n\tfor collector, f := range availableCollectors {\n\t\tif resourceFilter.Match(collector) {\n\t\t\twg.Add(1)\n\t\t\tgo func(f func(ctx context.Context, acc telegraf.Accumulator, k *KubernetesInventory)) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tf(ctx, acc, ki)\n\t\t\t}(f)\n\t\t}\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc atoi(s string) int64 {\n\ti, err := strconv.ParseInt(s, 10, 64)\n\tif err != nil {\n\t\treturn 0\n\t}\n\treturn i\n}\n\nfunc (ki *KubernetesInventory) convertQuantity(s string, m float64) int64 {\n\tq, err := resource.ParseQuantity(s)\n\tif err != nil {\n\t\tki.Log.Debugf(\"failed to parse quantity: %s\", err.Error())\n\t\treturn 0\n\t}\n\tf, err := strconv.ParseFloat(fmt.Sprint(q.AsDec()), 64)\n\tif err != nil {\n\t\tki.Log.Debugf(\"failed to parse float: %s\", err.Error())\n\t\treturn 0\n\t}\n\tif m < 1 {\n\t\tm = 1\n\t}\n\treturn int64(f * m)\n}\n\nfunc (ki *KubernetesInventory) queryPodsFromKubelet(url string, v interface{}) error {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating new http request for url %s failed: %w\", url, err)\n\t}\n\n\treq.Header.Add(\"Accept\", \"application/json\")\n\tresp, err := ki.httpClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", url, resp.Status)\n\t}\n\n\tif err := json.NewDecoder(resp.Body).Decode(v); err != nil {\n\t\treturn fmt.Errorf(\"error parsing response: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ki *KubernetesInventory) createSelectorFilters() error {\n\tselectorFilter, err := filter.NewIncludeExcludeFilter(ki.SelectorInclude, ki.SelectorExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tki.selectorFilter = selectorFilter\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"kube_inventory\", func() telegraf.Input {\n\t\treturn &KubernetesInventory{\n\t\t\tResponseTimeout: config.Duration(time.Second * 5),\n\t\t\tNamespace:       \"default\",\n\t\t\tSelectorInclude: make([]string, 0),\n\t\t\tSelectorExclude: []string{\"*\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/node.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectNodes(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getNodes(ctx, ki.NodeName)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tgatherNodeCount(len(list.Items), acc)\n\n\tfor i := range list.Items {\n\t\tki.gatherNode(&list.Items[i], acc)\n\t}\n}\n\nfunc gatherNodeCount(count int, acc telegraf.Accumulator) {\n\tfields := map[string]interface{}{\"node_count\": count}\n\ttags := make(map[string]string)\n\n\tacc.AddFields(nodeMeasurement, fields, tags)\n}\n\nfunc (ki *KubernetesInventory) gatherNode(n *corev1.Node, acc telegraf.Accumulator) {\n\tfields := make(map[string]interface{}, len(n.Status.Capacity)+len(n.Status.Allocatable)+1)\n\ttags := map[string]string{\n\t\t\"node_name\":         n.Name,\n\t\t\"cluster_namespace\": n.Annotations[\"cluster.x-k8s.io/cluster-namespace\"],\n\t\t\"version\":           n.Status.NodeInfo.KubeletVersion,\n\t}\n\n\tfor resourceName, val := range n.Status.Capacity {\n\t\tswitch resourceName {\n\t\tcase \"cpu\":\n\t\t\tfields[\"capacity_cpu_cores\"] = ki.convertQuantity(val.String(), 1)\n\t\t\tfields[\"capacity_millicpu_cores\"] = ki.convertQuantity(val.String(), 1000)\n\t\tcase \"memory\":\n\t\t\tfields[\"capacity_memory_bytes\"] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"pods\":\n\t\t\tfields[\"capacity_pods\"] = atoi(val.String())\n\t\t}\n\t}\n\n\tfor resourceName, val := range n.Status.Allocatable {\n\t\tswitch resourceName {\n\t\tcase \"cpu\":\n\t\t\tfields[\"allocatable_cpu_cores\"] = ki.convertQuantity(val.String(), 1)\n\t\t\tfields[\"allocatable_millicpu_cores\"] = ki.convertQuantity(val.String(), 1000)\n\t\tcase \"memory\":\n\t\t\tfields[\"allocatable_memory_bytes\"] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"pods\":\n\t\t\tfields[\"allocatable_pods\"] = atoi(val.String())\n\t\t}\n\t}\n\n\tfor _, val := range n.Status.Conditions {\n\t\tconditiontags := map[string]string{\n\t\t\t\"status\":    string(val.Status),\n\t\t\t\"condition\": string(val.Type),\n\t\t}\n\t\tfor k, v := range tags {\n\t\t\tconditiontags[k] = v\n\t\t}\n\t\trunning := 0\n\t\tnodeready := 0\n\t\tif val.Status == \"True\" {\n\t\t\tif val.Type == \"Ready\" {\n\t\t\t\tnodeready = 1\n\t\t\t}\n\t\t\trunning = 1\n\t\t} else if val.Status == \"Unknown\" {\n\t\t\tif val.Type == \"Ready\" {\n\t\t\t\tnodeready = 0\n\t\t\t}\n\t\t\trunning = 2\n\t\t}\n\t\tconditionfields := map[string]interface{}{\n\t\t\t\"status_condition\": running,\n\t\t\t\"ready\":            nodeready,\n\t\t}\n\t\tacc.AddFields(nodeMeasurement, conditionfields, conditiontags)\n\t}\n\n\tunschedulable := 0\n\tif n.Spec.Unschedulable {\n\t\tunschedulable = 1\n\t}\n\tfields[\"spec_unschedulable\"] = unschedulable\n\n\tacc.AddFields(nodeMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/node_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNode(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no nodes\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/nodes/\": corev1.NodeList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tnodeMeasurement,\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"node_count\": int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect nodes\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/nodes/\": corev1.NodeList{\n\t\t\t\t\t\tItems: []corev1.Node{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.NodeStatus{\n\t\t\t\t\t\t\t\t\tNodeInfo: corev1.NodeSystemInfo{\n\t\t\t\t\t\t\t\t\t\tKernelVersion:           \"4.14.48-coreos-r2\",\n\t\t\t\t\t\t\t\t\t\tOSImage:                 \"Container Linux by CoreOS 1745.7.0 (Rhyolite)\",\n\t\t\t\t\t\t\t\t\t\tContainerRuntimeVersion: \"docker://18.3.1\",\n\t\t\t\t\t\t\t\t\t\tKubeletVersion:          \"v1.10.3\",\n\t\t\t\t\t\t\t\t\t\tKubeProxyVersion:        \"v1.10.3\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tPhase: \"Running\",\n\t\t\t\t\t\t\t\t\tCapacity: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\":                     resource.MustParse(\"16\"),\n\t\t\t\t\t\t\t\t\t\t\"ephemeral_storage_bytes\": resource.MustParse(\"49536401408\"),\n\t\t\t\t\t\t\t\t\t\t\"hugepages_1Gi_bytes\":     resource.MustParse(\"0\"),\n\t\t\t\t\t\t\t\t\t\t\"hugepages_2Mi_bytes\":     resource.MustParse(\"0\"),\n\t\t\t\t\t\t\t\t\t\t\"memory\":                  resource.MustParse(\"125817904Ki\"),\n\t\t\t\t\t\t\t\t\t\t\"pods\":                    resource.MustParse(\"110\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAllocatable: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\":                     resource.MustParse(\"1000m\"),\n\t\t\t\t\t\t\t\t\t\t\"ephemeral_storage_bytes\": resource.MustParse(\"44582761194\"),\n\t\t\t\t\t\t\t\t\t\t\"hugepages_1Gi_bytes\":     resource.MustParse(\"0\"),\n\t\t\t\t\t\t\t\t\t\t\"hugepages_2Mi_bytes\":     resource.MustParse(\"0\"),\n\t\t\t\t\t\t\t\t\t\t\"memory\":                  resource.MustParse(\"125715504Ki\"),\n\t\t\t\t\t\t\t\t\t\t\"pods\":                    resource.MustParse(\"110\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tConditions: []corev1.NodeCondition{\n\t\t\t\t\t\t\t\t\t\t{Type: \"Ready\", Status: \"True\", LastTransitionTime: metav1.Time{Time: now}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: corev1.NodeSpec{\n\t\t\t\t\t\t\t\t\tProviderID: \"aws:///us-east-1c/i-0c00\",\n\t\t\t\t\t\t\t\t\tTaints: []corev1.Taint{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tKey:    \"k1\",\n\t\t\t\t\t\t\t\t\t\t\tValue:  \"v1\",\n\t\t\t\t\t\t\t\t\t\t\tEffect: \"NoExecute\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tKey:    \"k2\",\n\t\t\t\t\t\t\t\t\t\t\tValue:  \"v2\",\n\t\t\t\t\t\t\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration: 11232,\n\t\t\t\t\t\t\t\t\tName:       \"node1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tNamespace: \"ns1\",\n\t\t\t\t\t\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"cluster.x-k8s.io/cluster-namespace\": \"ns1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tnodeMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"node_name\":         \"node1\",\n\t\t\t\t\t\t\"cluster_namespace\": \"ns1\",\n\t\t\t\t\t\t\"condition\":         \"Ready\",\n\t\t\t\t\t\t\"status\":            \"True\",\n\t\t\t\t\t\t\"version\":           \"v1.10.3\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tnodeMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"node_name\":         \"node1\",\n\t\t\t\t\t\t\"cluster_namespace\": \"ns1\",\n\t\t\t\t\t\t\"version\":           \"v1.10.3\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"capacity_cpu_cores\":         int64(16),\n\t\t\t\t\t\t\"capacity_millicpu_cores\":    int64(16000),\n\t\t\t\t\t\t\"capacity_memory_bytes\":      int64(1.28837533696e+11),\n\t\t\t\t\t\t\"capacity_pods\":              int64(110),\n\t\t\t\t\t\t\"allocatable_cpu_cores\":      int64(1),\n\t\t\t\t\t\t\"allocatable_millicpu_cores\": int64(1000),\n\t\t\t\t\t\t\"allocatable_memory_bytes\":   int64(1.28732676096e+11),\n\t\t\t\t\t\t\"allocatable_pods\":           int64(110),\n\t\t\t\t\t\t\"spec_unschedulable\":         int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/nodes/\"]).(corev1.NodeList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherNode(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\tif v.name == \"no nodes\" {\n\t\t\tnodeCount := len((v.handler.responseMap[\"/nodes/\"]).(corev1.NodeList).Items)\n\t\t\tgatherNodeCount(nodeCount, acc)\n\t\t}\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/persistentvolume.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectPersistentVolumes(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getPersistentVolumes(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range list.Items {\n\t\tgatherPersistentVolume(&list.Items[i], acc)\n\t}\n}\n\nfunc gatherPersistentVolume(pv *corev1.PersistentVolume, acc telegraf.Accumulator) {\n\tphaseType := 5\n\tswitch strings.ToLower(string(pv.Status.Phase)) {\n\tcase \"bound\":\n\t\tphaseType = 0\n\tcase \"failed\":\n\t\tphaseType = 1\n\tcase \"pending\":\n\t\tphaseType = 2\n\tcase \"released\":\n\t\tphaseType = 3\n\tcase \"available\":\n\t\tphaseType = 4\n\t}\n\tfields := map[string]interface{}{\n\t\t\"phase_type\": phaseType,\n\t}\n\ttags := map[string]string{\n\t\t\"pv_name\":      pv.Name,\n\t\t\"phase\":        string(pv.Status.Phase),\n\t\t\"storageclass\": pv.Spec.StorageClassName,\n\t}\n\n\tacc.AddFields(persistentVolumeMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/persistentvolume_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestPersistentVolume(t *testing.T) {\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no pv\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumes/\": &corev1.PersistentVolumeList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect pvs\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumes/\": &corev1.PersistentVolumeList{\n\t\t\t\t\t\tItems: []corev1.PersistentVolume{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.PersistentVolumeStatus{\n\t\t\t\t\t\t\t\t\tPhase: \"pending\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: corev1.PersistentVolumeSpec{\n\t\t\t\t\t\t\t\t\tStorageClassName: \"ebs-1\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tName: \"pv1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_persistentvolume\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pv_name\":      \"pv1\",\n\t\t\t\t\t\t\"storageclass\": \"ebs-1\",\n\t\t\t\t\t\t\"phase\":        \"pending\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_type\": 2,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/persistentvolumes/\"]).(*corev1.PersistentVolumeList)).Items\n\t\tfor i := range items {\n\t\t\tgatherPersistentVolume(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/persistentvolumeclaim.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectPersistentVolumeClaims(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getPersistentVolumeClaims(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, pvc := range list.Items {\n\t\tki.gatherPersistentVolumeClaim(pvc, acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherPersistentVolumeClaim(pvc corev1.PersistentVolumeClaim, acc telegraf.Accumulator) {\n\tphaseType := 3\n\tswitch strings.ToLower(string(pvc.Status.Phase)) {\n\tcase \"bound\":\n\t\tphaseType = 0\n\tcase \"lost\":\n\t\tphaseType = 1\n\tcase \"pending\":\n\t\tphaseType = 2\n\t}\n\tfields := map[string]interface{}{\n\t\t\"phase_type\": phaseType,\n\t}\n\ttags := map[string]string{\n\t\t\"pvc_name\":  pvc.Name,\n\t\t\"namespace\": pvc.Namespace,\n\t\t\"phase\":     string(pvc.Status.Phase),\n\t}\n\tif pvc.Spec.StorageClassName != nil {\n\t\ttags[\"storageclass\"] = *pvc.Spec.StorageClassName\n\t}\n\tif pvc.Spec.Selector != nil {\n\t\tfor key, val := range pvc.Spec.Selector.MatchLabels {\n\t\t\tif ki.selectorFilter.Match(key) {\n\t\t\t\ttags[\"selector_\"+key] = val\n\t\t\t}\n\t\t}\n\t}\n\n\tacc.AddFields(persistentVolumeClaimMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/persistentvolumeclaim_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestPersistentVolumeClaim(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no pv claims\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumeclaims/\": &corev1.PersistentVolumeClaimList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect pv claims\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumeclaims/\": &corev1.PersistentVolumeClaimList{\n\t\t\t\t\t\tItems: []corev1.PersistentVolumeClaim{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.PersistentVolumeClaimStatus{\n\t\t\t\t\t\t\t\t\tPhase: \"bound\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\t\t\t\t\tVolumeName:       \"pvc-dc870fd6-1e08-11e8-b226-02aa4bc06eb8\",\n\t\t\t\t\t\t\t\t\tStorageClassName: toPtr(\"ebs-1\"),\n\t\t\t\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tNamespace: \"ns1\",\n\t\t\t\t\t\t\t\t\tName:      \"pc1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_persistentvolumeclaim\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pvc_name\":         \"pc1\",\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"storageclass\":     \"ebs-1\",\n\t\t\t\t\t\t\"phase\":            \"bound\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_type\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname:     \"no label selectors\",\n\t\t\thasError: false,\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumeclaims/\": &corev1.PersistentVolumeClaimList{\n\t\t\t\t\t\tItems: []corev1.PersistentVolumeClaim{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.PersistentVolumeClaimStatus{\n\t\t\t\t\t\t\t\t\tPhase: \"bound\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\t\t\t\t\tVolumeName:       \"pvc-dc870fd6-1e08-11e8-b226-02aa4bc06eb8\",\n\t\t\t\t\t\t\t\t\tStorageClassName: toPtr(\"ebs-1\"),\n\t\t\t\t\t\t\t\t\tSelector:         nil,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tNamespace: \"ns1\",\n\t\t\t\t\t\t\t\t\tName:      \"pc1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_persistentvolumeclaim\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pvc_name\":     \"pc1\",\n\t\t\t\t\t\t\"namespace\":    \"ns1\",\n\t\t\t\t\t\t\"storageclass\": \"ebs-1\",\n\t\t\t\t\t\t\"phase\":        \"bound\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_type\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no storage class name\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/persistentvolumeclaims/\": &corev1.PersistentVolumeClaimList{\n\t\t\t\t\t\tItems: []corev1.PersistentVolumeClaim{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.PersistentVolumeClaimStatus{\n\t\t\t\t\t\t\t\t\tPhase: \"bound\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\t\t\t\t\tVolumeName:       \"pvc-dc870fd6-1e08-11e8-b226-02aa4bc06eb8\",\n\t\t\t\t\t\t\t\t\tStorageClassName: nil,\n\t\t\t\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tNamespace: \"ns1\",\n\t\t\t\t\t\t\t\t\tName:      \"pc1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_persistentvolumeclaim\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pvc_name\":         \"pc1\",\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"phase\":            \"bound\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_type\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\tfor _, pvc := range ((v.handler.responseMap[\"/persistentvolumeclaims/\"]).(*corev1.PersistentVolumeClaimList)).Items {\n\t\t\tks.gatherPersistentVolumeClaim(pvc, acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestPersistentVolumeClaimSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/persistentvolumeclaims/\": &corev1.PersistentVolumeClaimList{\n\t\t\tItems: []corev1.PersistentVolumeClaim{\n\t\t\t\t{\n\t\t\t\t\tStatus: corev1.PersistentVolumeClaimStatus{\n\t\t\t\t\t\tPhase: \"bound\",\n\t\t\t\t\t},\n\t\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\t\tVolumeName:       \"pvc-dc870fd6-1e08-11e8-b226-02aa4bc06eb8\",\n\t\t\t\t\t\tStorageClassName: toPtr(\"ebs-1\"),\n\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\tNamespace: \"ns1\",\n\t\t\t\t\t\tName:      \"pc1\",\n\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\tfor _, pvc := range ((v.handler.responseMap[\"/persistentvolumeclaims/\"]).(*corev1.PersistentVolumeClaimList)).Items {\n\t\t\tks.gatherPersistentVolumeClaim(pvc, acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/pod.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectPods(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tvar list corev1.PodList\n\tlistRef := &list\n\tvar err error\n\n\tif ki.KubeletURL != \"\" {\n\t\terr = ki.queryPodsFromKubelet(ki.KubeletURL+\"/pods\", listRef)\n\t} else {\n\t\tlistRef, err = ki.client.getPods(ctx, ki.NodeName)\n\t}\n\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range listRef.Items {\n\t\tki.gatherPod(&listRef.Items[i], acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherPod(p *corev1.Pod, acc telegraf.Accumulator) {\n\tcreationTS := p.GetCreationTimestamp()\n\tif creationTS.IsZero() {\n\t\treturn\n\t}\n\n\tcontainerList := make(map[string]*corev1.ContainerStatus, len(p.Status.ContainerStatuses))\n\tfor i := range p.Status.ContainerStatuses {\n\t\tcontainerList[p.Status.ContainerStatuses[i].Name] = &p.Status.ContainerStatuses[i]\n\t}\n\n\tfor _, c := range p.Spec.Containers {\n\t\tcs, ok := containerList[c.Name]\n\t\tif !ok {\n\t\t\tcs = &corev1.ContainerStatus{}\n\t\t}\n\t\tki.gatherPodContainer(p, *cs, c, acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherPodContainer(p *corev1.Pod, cs corev1.ContainerStatus, c corev1.Container, acc telegraf.Accumulator) {\n\tstateCode := 3\n\tstateReason := \"\"\n\tstate := \"unknown\"\n\treadiness := \"unready\"\n\n\tswitch {\n\tcase cs.State.Running != nil:\n\t\tstateCode = 0\n\t\tstate = \"running\"\n\tcase cs.State.Terminated != nil:\n\t\tstateCode = 1\n\t\tstate = \"terminated\"\n\t\tstateReason = cs.State.Terminated.Reason\n\tcase cs.State.Waiting != nil:\n\t\tstateCode = 2\n\t\tstate = \"waiting\"\n\t\tstateReason = cs.State.Waiting.Reason\n\t}\n\n\tif cs.Ready {\n\t\treadiness = \"ready\"\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"restarts_total\": cs.RestartCount,\n\t\t\"state_code\":     stateCode,\n\t}\n\n\t// deprecated in 1.15: use `state_reason` instead\n\tif state == \"terminated\" {\n\t\tfields[\"terminated_reason\"] = stateReason\n\t}\n\n\tif stateReason != \"\" {\n\t\tfields[\"state_reason\"] = stateReason\n\t}\n\n\tphaseReason := p.Status.Reason\n\tif phaseReason != \"\" {\n\t\tfields[\"phase_reason\"] = phaseReason\n\t}\n\n\ttags := map[string]string{\n\t\t\"container_name\": c.Name,\n\t\t\"namespace\":      p.Namespace,\n\t\t\"node_name\":      p.Spec.NodeName,\n\t\t\"pod_name\":       p.Name,\n\t\t\"phase\":          string(p.Status.Phase),\n\t\t\"state\":          state,\n\t\t\"readiness\":      readiness,\n\t}\n\tsplitImage := strings.Split(c.Image, \":\")\n\tif len(splitImage) == 2 {\n\t\ttags[\"version\"] = splitImage[1]\n\t}\n\ttags[\"image\"] = splitImage[0]\n\tfor key, val := range p.Spec.NodeSelector {\n\t\tif ki.selectorFilter.Match(key) {\n\t\t\ttags[\"node_selector_\"+key] = val\n\t\t}\n\t}\n\n\treq := c.Resources.Requests\n\tlim := c.Resources.Limits\n\n\tfor resourceName, val := range req {\n\t\tswitch resourceName {\n\t\tcase \"cpu\":\n\t\t\tfields[\"resource_requests_millicpu_units\"] = ki.convertQuantity(val.String(), 1000)\n\t\tcase \"memory\":\n\t\t\tfields[\"resource_requests_memory_bytes\"] = ki.convertQuantity(val.String(), 1)\n\t\t}\n\t}\n\tfor resourceName, val := range lim {\n\t\tswitch resourceName {\n\t\tcase \"cpu\":\n\t\t\tfields[\"resource_limits_millicpu_units\"] = ki.convertQuantity(val.String(), 1000)\n\t\tcase \"memory\":\n\t\t\tfields[\"resource_limits_memory_bytes\"] = ki.convertQuantity(val.String(), 1)\n\t\t}\n\t}\n\n\tfor _, val := range p.Status.Conditions {\n\t\tconditiontags := map[string]string{\n\t\t\t\"container_name\": c.Name,\n\t\t\t\"image\":          splitImage[0],\n\t\t\t\"status\":         string(val.Status),\n\t\t\t\"namespace\":      p.Namespace,\n\t\t\t\"node_name\":      p.Spec.NodeName,\n\t\t\t\"pod_name\":       p.Name,\n\t\t\t\"condition\":      string(val.Type),\n\t\t}\n\t\tif len(splitImage) == 2 {\n\t\t\tconditiontags[\"version\"] = splitImage[1]\n\t\t}\n\t\trunning := 0\n\t\tpodready := 0\n\t\tif val.Status == \"True\" {\n\t\t\tif val.Type == \"Ready\" {\n\t\t\t\tpodready = 1\n\t\t\t}\n\t\t\trunning = 1\n\t\t} else if val.Status == \"Unknown\" {\n\t\t\tif val.Type == \"Ready\" {\n\t\t\t\tpodready = 0\n\t\t\t}\n\t\t\trunning = 2\n\t\t}\n\t\tconditionfields := map[string]interface{}{\n\t\t\t\"status_condition\": running,\n\t\t\t\"ready\":            podready,\n\t\t}\n\t\tacc.AddFields(podContainerMeasurement, conditionfields, conditiontags)\n\t}\n\n\tacc.AddFields(podContainerMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/pod_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestPod(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tstarted := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-1, 1, 36, 0, now.Location())\n\tcreated := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-2, 1, 0, 0, now.Location())\n\tcond1 := time.Date(now.Year(), 7, 5, 7, 53, 29, 0, now.Location())\n\tcond2 := time.Date(now.Year(), 7, 5, 7, 53, 31, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no pods\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/pods/\": &corev1.PodList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect pods\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/pods/\": &corev1.PodList{\n\t\t\t\t\t\tItems: []corev1.Pod{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\t\t\t\t\tNodeName: \"node1\",\n\t\t\t\t\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"running\",\n\t\t\t\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"completed\",\n\t\t\t\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"waiting\",\n\t\t\t\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"vol1\",\n\t\t\t\t\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\t\t\t\t\tPersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{\n\t\t\t\t\t\t\t\t\t\t\t\t\tClaimName: \"pc1\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"vol2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tNodeSelector: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tStatus: corev1.PodStatus{\n\t\t\t\t\t\t\t\t\tPhase:     \"Running\",\n\t\t\t\t\t\t\t\t\tHostIP:    \"180.12.10.18\",\n\t\t\t\t\t\t\t\t\tPodIP:     \"10.244.2.15\",\n\t\t\t\t\t\t\t\t\tStartTime: &metav1.Time{Time: started},\n\t\t\t\t\t\t\t\t\tConditions: []corev1.PodCondition{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Initialized\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Ready\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond2},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Scheduled\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tContainerStatuses: []corev1.ContainerStatus{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"running\",\n\t\t\t\t\t\t\t\t\t\t\tState: corev1.ContainerState{\n\t\t\t\t\t\t\t\t\t\t\t\tRunning: &corev1.ContainerStateRunning{\n\t\t\t\t\t\t\t\t\t\t\t\t\tStartedAt: metav1.Time{Time: started},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tReady:        true,\n\t\t\t\t\t\t\t\t\t\t\tRestartCount: 3,\n\t\t\t\t\t\t\t\t\t\t\tImage:        \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tImageID:      \"image_id1\",\n\t\t\t\t\t\t\t\t\t\t\tContainerID:  \"docker://54abe32d0094479d3d\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"completed\",\n\t\t\t\t\t\t\t\t\t\t\tState: corev1.ContainerState{\n\t\t\t\t\t\t\t\t\t\t\t\tTerminated: &corev1.ContainerStateTerminated{\n\t\t\t\t\t\t\t\t\t\t\t\t\tStartedAt: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t\t\t\t\t\tExitCode:  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\tReason:    \"Completed\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tReady:        false,\n\t\t\t\t\t\t\t\t\t\t\tRestartCount: 3,\n\t\t\t\t\t\t\t\t\t\t\tImage:        \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tImageID:      \"image_id1\",\n\t\t\t\t\t\t\t\t\t\t\tContainerID:  \"docker://54abe32d0094479d3d\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"waiting\",\n\t\t\t\t\t\t\t\t\t\t\tState: corev1.ContainerState{\n\t\t\t\t\t\t\t\t\t\t\t\tWaiting: &corev1.ContainerStateWaiting{\n\t\t\t\t\t\t\t\t\t\t\t\t\tReason: \"PodUninitialized\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tReady:        false,\n\t\t\t\t\t\t\t\t\t\t\tRestartCount: 3,\n\t\t\t\t\t\t\t\t\t\t\tImage:        \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tImageID:      \"image_id1\",\n\t\t\t\t\t\t\t\t\t\t\tContainerID:  \"docker://54abe32d0094479d3d\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tOwnerReferences: []metav1.OwnerReference{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tAPIVersion: \"apps/v1\",\n\t\t\t\t\t\t\t\t\t\t\tKind:       \"DaemonSet\",\n\t\t\t\t\t\t\t\t\t\t\tName:       \"forwarder\",\n\t\t\t\t\t\t\t\t\t\t\tController: toPtr(true),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tGeneration: 11232,\n\t\t\t\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\t\t\t\tName:       \"pod1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: created},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Initialized\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"running\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Ready\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"running\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Scheduled\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"running\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":             \"ns1\",\n\t\t\t\t\t\t\"container_name\":        \"running\",\n\t\t\t\t\t\t\"node_name\":             \"node1\",\n\t\t\t\t\t\t\"pod_name\":              \"pod1\",\n\t\t\t\t\t\t\"image\":                 \"image1\",\n\t\t\t\t\t\t\"phase\":                 \"Running\",\n\t\t\t\t\t\t\"state\":                 \"running\",\n\t\t\t\t\t\t\"readiness\":             \"ready\",\n\t\t\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"restarts_total\":                   int32(3),\n\t\t\t\t\t\t\"state_code\":                       0,\n\t\t\t\t\t\t\"resource_requests_millicpu_units\": int64(100),\n\t\t\t\t\t\t\"resource_limits_millicpu_units\":   int64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Initialized\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"completed\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Ready\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"completed\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Scheduled\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"completed\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":             \"ns1\",\n\t\t\t\t\t\t\"container_name\":        \"completed\",\n\t\t\t\t\t\t\"image\":                 \"image1\",\n\t\t\t\t\t\t\"node_name\":             \"node1\",\n\t\t\t\t\t\t\"pod_name\":              \"pod1\",\n\t\t\t\t\t\t\"phase\":                 \"Running\",\n\t\t\t\t\t\t\"state\":                 \"terminated\",\n\t\t\t\t\t\t\"readiness\":             \"unready\",\n\t\t\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"restarts_total\":                   int32(3),\n\t\t\t\t\t\t\"state_code\":                       1,\n\t\t\t\t\t\t\"state_reason\":                     \"Completed\",\n\t\t\t\t\t\t\"resource_requests_millicpu_units\": int64(100),\n\t\t\t\t\t\t\"resource_limits_millicpu_units\":   int64(100),\n\t\t\t\t\t\t\"terminated_reason\":                \"Completed\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Initialized\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Ready\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Scheduled\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":             \"ns1\",\n\t\t\t\t\t\t\"container_name\":        \"waiting\",\n\t\t\t\t\t\t\"node_name\":             \"node1\",\n\t\t\t\t\t\t\"image\":                 \"image1\",\n\t\t\t\t\t\t\"pod_name\":              \"pod1\",\n\t\t\t\t\t\t\"phase\":                 \"Running\",\n\t\t\t\t\t\t\"state\":                 \"waiting\",\n\t\t\t\t\t\t\"readiness\":             \"unready\",\n\t\t\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"restarts_total\":                   int32(3),\n\t\t\t\t\t\t\"state_code\":                       2,\n\t\t\t\t\t\t\"state_reason\":                     \"PodUninitialized\",\n\t\t\t\t\t\t\"resource_requests_millicpu_units\": int64(100),\n\t\t\t\t\t\t\"resource_limits_millicpu_units\":   int64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/pods/\"]).(*corev1.PodList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherPod(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestPodSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tstarted := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-1, 1, 36, 0, now.Location())\n\tcreated := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-2, 1, 36, 0, now.Location())\n\tcond1 := time.Date(now.Year(), 7, 5, 7, 53, 29, 0, now.Location())\n\tcond2 := time.Date(now.Year(), 7, 5, 7, 53, 31, 0, now.Location())\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/pods/\": &corev1.PodList{\n\t\t\tItems: []corev1.Pod{\n\t\t\t\t{\n\t\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\t\tNodeName: \"node1\",\n\t\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:  \"forwarder\",\n\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"vol1\",\n\t\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\t\tPersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{\n\t\t\t\t\t\t\t\t\t\tClaimName: \"pc1\",\n\t\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"vol2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tNodeSelector: map[string]string{\n\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tStatus: corev1.PodStatus{\n\t\t\t\t\t\tPhase:     \"Running\",\n\t\t\t\t\t\tHostIP:    \"180.12.10.18\",\n\t\t\t\t\t\tPodIP:     \"10.244.2.15\",\n\t\t\t\t\t\tStartTime: &metav1.Time{Time: started},\n\t\t\t\t\t\tConditions: []corev1.PodCondition{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:               \"Initialized\",\n\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:               \"Ready\",\n\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond2},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType:               \"Scheduled\",\n\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tContainerStatuses: []corev1.ContainerStatus{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"forwarder\",\n\t\t\t\t\t\t\t\tState: corev1.ContainerState{\n\t\t\t\t\t\t\t\t\tRunning: &corev1.ContainerStateRunning{\n\t\t\t\t\t\t\t\t\t\tStartedAt: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tReady:        true,\n\t\t\t\t\t\t\t\tRestartCount: 3,\n\t\t\t\t\t\t\t\tImage:        \"image1\",\n\t\t\t\t\t\t\t\tImageID:      \"image_id1\",\n\t\t\t\t\t\t\t\tContainerID:  \"docker://54abe32d0094479d3d\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\tOwnerReferences: []metav1.OwnerReference{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAPIVersion: \"apps/v1\",\n\t\t\t\t\t\t\t\tKind:       \"DaemonSet\",\n\t\t\t\t\t\t\t\tName:       \"forwarder\",\n\t\t\t\t\t\t\t\tController: toPtr(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tGeneration: 11232,\n\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\tName:       \"pod1\",\n\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: created},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/pods/\"]).(*corev1.PodList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherPod(&items[i], acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"node_selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n\nfunc TestPodPendingContainers(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tstarted := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-1, 1, 36, 0, now.Location())\n\tcreated := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()-2, 1, 36, 0, now.Location())\n\tcond1 := time.Date(now.Year(), 7, 5, 7, 53, 29, 0, now.Location())\n\tcond2 := time.Date(now.Year(), 7, 5, 7, 53, 31, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"collect pods\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/pods/\": &corev1.PodList{\n\t\t\t\t\t\tItems: []corev1.Pod{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\t\t\t\t\tNodeName: \"node1\",\n\t\t\t\t\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"waiting\",\n\t\t\t\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName:  \"terminated\",\n\t\t\t\t\t\t\t\t\t\t\tImage: \"image1\",\n\t\t\t\t\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tContainerPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\t\t\tProtocol:      \"TCP\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cpu\": resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"vol1\",\n\t\t\t\t\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\t\t\t\t\tPersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{\n\t\t\t\t\t\t\t\t\t\t\t\t\tClaimName: \"pc1\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tName: \"vol2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tNodeSelector: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tStatus: corev1.PodStatus{\n\t\t\t\t\t\t\t\t\tPhase:     \"Pending\",\n\t\t\t\t\t\t\t\t\tReason:    \"NetworkNotReady\",\n\t\t\t\t\t\t\t\t\tHostIP:    \"180.12.10.18\",\n\t\t\t\t\t\t\t\t\tPodIP:     \"10.244.2.15\",\n\t\t\t\t\t\t\t\t\tStartTime: &metav1.Time{Time: started},\n\t\t\t\t\t\t\t\t\tConditions: []corev1.PodCondition{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Initialized\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Ready\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond2},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tType:               \"Scheduled\",\n\t\t\t\t\t\t\t\t\t\t\tStatus:             \"True\",\n\t\t\t\t\t\t\t\t\t\t\tLastTransitionTime: metav1.Time{Time: cond1},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tOwnerReferences: []metav1.OwnerReference{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tAPIVersion: \"apps/v1\",\n\t\t\t\t\t\t\t\t\t\t\tKind:       \"DaemonSet\",\n\t\t\t\t\t\t\t\t\t\t\tName:       \"forwarder\",\n\t\t\t\t\t\t\t\t\t\t\tController: toPtr(true),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tGeneration: 11232,\n\t\t\t\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\t\t\t\tName:       \"pod1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: created},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Initialized\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Ready\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Scheduled\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"waiting\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":             \"ns1\",\n\t\t\t\t\t\t\"container_name\":        \"waiting\",\n\t\t\t\t\t\t\"node_name\":             \"node1\",\n\t\t\t\t\t\t\"pod_name\":              \"pod1\",\n\t\t\t\t\t\t\"image\":                 \"image1\",\n\t\t\t\t\t\t\"phase\":                 \"Pending\",\n\t\t\t\t\t\t\"state\":                 \"unknown\",\n\t\t\t\t\t\t\"readiness\":             \"unready\",\n\t\t\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_reason\":                     \"NetworkNotReady\",\n\t\t\t\t\t\t\"restarts_total\":                   int32(0),\n\t\t\t\t\t\t\"state_code\":                       3,\n\t\t\t\t\t\t\"resource_requests_millicpu_units\": int64(100),\n\t\t\t\t\t\t\"resource_limits_millicpu_units\":   int64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Initialized\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"terminated\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Ready\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"terminated\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(1),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"pod_name\":       \"pod1\",\n\t\t\t\t\t\t\"condition\":      \"Scheduled\",\n\t\t\t\t\t\t\"status\":         \"True\",\n\t\t\t\t\t\t\"image\":          \"image1\",\n\t\t\t\t\t\t\"node_name\":      \"node1\",\n\t\t\t\t\t\t\"namespace\":      \"ns1\",\n\t\t\t\t\t\t\"container_name\": \"terminated\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_condition\": int64(1),\n\t\t\t\t\t\t\"ready\":            int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tpodContainerMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":             \"ns1\",\n\t\t\t\t\t\t\"container_name\":        \"terminated\",\n\t\t\t\t\t\t\"node_name\":             \"node1\",\n\t\t\t\t\t\t\"pod_name\":              \"pod1\",\n\t\t\t\t\t\t\"image\":                 \"image1\",\n\t\t\t\t\t\t\"phase\":                 \"Pending\",\n\t\t\t\t\t\t\"state\":                 \"unknown\",\n\t\t\t\t\t\t\"readiness\":             \"unready\",\n\t\t\t\t\t\t\"node_selector_select1\": \"s1\",\n\t\t\t\t\t\t\"node_selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"phase_reason\":                     \"NetworkNotReady\",\n\t\t\t\t\t\t\"restarts_total\":                   int32(0),\n\t\t\t\t\t\t\"state_code\":                       3,\n\t\t\t\t\t\t\"resource_requests_millicpu_units\": int64(100),\n\t\t\t\t\t\t\"resource_limits_millicpu_units\":   int64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/pods/\"]).(*corev1.PodList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherPod(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/resourcequotas.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectResourceQuotas(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getResourceQuotas(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor _, i := range list.Items {\n\t\tki.gatherResourceQuota(i, acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherResourceQuota(r corev1.ResourceQuota, acc telegraf.Accumulator) {\n\tfields := make(map[string]interface{}, len(r.Status.Hard)+len(r.Status.Used))\n\ttags := map[string]string{\n\t\t\"resource\":  r.Name,\n\t\t\"namespace\": r.Namespace,\n\t}\n\n\tfor resourceName, val := range r.Status.Hard {\n\t\tswitch resourceName {\n\t\tcase \"cpu\", \"limits.cpu\", \"requests.cpu\":\n\t\t\tkey := \"hard_cpu\"\n\t\t\tif strings.Contains(string(resourceName), \"limits\") {\n\t\t\t\tkey = key + \"_limits\"\n\t\t\t} else if strings.Contains(string(resourceName), \"requests\") {\n\t\t\t\tkey = key + \"_requests\"\n\t\t\t}\n\t\t\tfields[key] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"memory\", \"limits.memory\", \"requests.memory\":\n\t\t\tkey := \"hard_memory\"\n\t\t\tif strings.Contains(string(resourceName), \"limits\") {\n\t\t\t\tkey = key + \"_limits\"\n\t\t\t} else if strings.Contains(string(resourceName), \"requests\") {\n\t\t\t\tkey = key + \"_requests\"\n\t\t\t}\n\t\t\tfields[key] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"pods\":\n\t\t\tfields[\"hard_pods\"] = atoi(val.String())\n\t\t}\n\t}\n\n\tfor resourceName, val := range r.Status.Used {\n\t\tswitch resourceName {\n\t\tcase \"cpu\", \"requests.cpu\", \"limits.cpu\":\n\t\t\tkey := \"used_cpu\"\n\t\t\tif strings.Contains(string(resourceName), \"limits\") {\n\t\t\t\tkey = key + \"_limits\"\n\t\t\t} else if strings.Contains(string(resourceName), \"requests\") {\n\t\t\t\tkey = key + \"_requests\"\n\t\t\t}\n\t\t\tfields[key] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"memory\", \"requests.memory\", \"limits.memory\":\n\t\t\tkey := \"used_memory\"\n\t\t\tif strings.Contains(string(resourceName), \"limits\") {\n\t\t\t\tkey = key + \"_limits\"\n\t\t\t} else if strings.Contains(string(resourceName), \"requests\") {\n\t\t\t\tkey = key + \"_requests\"\n\t\t\t}\n\t\t\tfields[key] = ki.convertQuantity(val.String(), 1)\n\t\tcase \"pods\":\n\t\t\tfields[\"used_pods\"] = atoi(val.String())\n\t\t}\n\t}\n\n\tacc.AddFields(resourcequotaMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/resourcequotas_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestResourceQuota(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no ressourcequota\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/resourcequotas/\": corev1.ResourceQuotaList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect resourceqota\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/resourcequotas/\": corev1.ResourceQuotaList{\n\t\t\t\t\t\tItems: []corev1.ResourceQuota{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: corev1.ResourceQuotaStatus{\n\t\t\t\t\t\t\t\t\tHard: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\":    resource.MustParse(\"16\"),\n\t\t\t\t\t\t\t\t\t\t\"memory\": resource.MustParse(\"125817904Ki\"),\n\t\t\t\t\t\t\t\t\t\t\"pods\":   resource.MustParse(\"110\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tUsed: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\t\t\"cpu\":    resource.MustParse(\"10\"),\n\t\t\t\t\t\t\t\t\t\t\"memory\": resource.MustParse(\"125715504Ki\"),\n\t\t\t\t\t\t\t\t\t\t\"pods\":   resource.MustParse(\"0\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration: 11232,\n\t\t\t\t\t\t\t\t\tNamespace:  \"ns1\",\n\t\t\t\t\t\t\t\t\tName:       \"rq1\",\n\t\t\t\t\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"lab1\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"lab2\": \"v2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tresourcequotaMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"resource\":  \"rq1\",\n\t\t\t\t\t\t\"namespace\": \"ns1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"hard_cpu\":    int64(16),\n\t\t\t\t\t\t\"hard_memory\": int64(1.28837533696e+11),\n\t\t\t\t\t\t\"hard_pods\":   int64(110),\n\t\t\t\t\t\t\"used_cpu\":    int64(10),\n\t\t\t\t\t\t\"used_memory\": int64(1.28732676096e+11),\n\t\t\t\t\t\t\"used_pods\":   int64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tacc := new(testutil.Accumulator)\n\t\tfor _, quota := range ((v.handler.responseMap[\"/resourcequotas/\"]).(corev1.ResourceQuotaList)).Items {\n\t\t\tks.gatherResourceQuota(quota, acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/sample.conf",
    "content": "# Read metrics from the Kubernetes api\n[[inputs.kube_inventory]]\n  ## URL for the Kubernetes API.\n  ## If empty in-cluster config with POD's service account token will be used.\n  # url = \"\"\n\n  ## URL for the kubelet, if set it will be used to collect the pods resource metrics\n  # url_kubelet = \"http://127.0.0.1:10255\"\n\n  ## Namespace to use. Set to \"\" to use all namespaces.\n  # namespace = \"default\"\n\n  ## Node name to filter to. No filtering by default.\n  # node_name = \"\"\n\n  ## Use bearer token for authorization.\n  ## Ignored if url is empty and in-cluster config is used.\n  # bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional Resources to exclude from gathering\n  ## Leave them with blank with try to gather everything available.\n  ## Values can be - \"daemonsets\", deployments\", \"endpoints\", \"ingress\",\n  ## \"nodes\", \"persistentvolumes\", \"persistentvolumeclaims\", \"pods\", \"services\",\n  ## \"statefulsets\"\n  # resource_exclude = [ \"deployments\", \"nodes\", \"statefulsets\" ]\n\n  ## Optional Resources to include when gathering\n  ## Overrides resource_exclude if both set.\n  # resource_include = [ \"deployments\", \"nodes\", \"statefulsets\" ]\n\n  ## selectors to include and exclude as tags.  Globs accepted.\n  ## Note that an empty array for both will include all selectors as tags\n  ## selector_exclude overrides selector_include if both set.\n  # selector_include = []\n  # selector_exclude = [\"*\"]\n\n  ## Optional TLS Config\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Uncomment to remove deprecated metrics.\n  # fieldexclude = [\"terminated_reason\"]\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/service.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectServices(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getServices(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range list.Items {\n\t\tki.gatherService(&list.Items[i], acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherService(s *corev1.Service, acc telegraf.Accumulator) {\n\tcreationTS := s.GetCreationTimestamp()\n\tif creationTS.IsZero() {\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"created\":    s.GetCreationTimestamp().UnixNano(),\n\t\t\"generation\": s.Generation,\n\t}\n\n\ttags := map[string]string{\n\t\t\"service_name\": s.Name,\n\t\t\"namespace\":    s.Namespace,\n\t}\n\n\tfor key, val := range s.Spec.Selector {\n\t\tif ki.selectorFilter.Match(key) {\n\t\t\ttags[\"selector_\"+key] = val\n\t\t}\n\t}\n\n\tvar getPorts = func() {\n\t\tfor _, port := range s.Spec.Ports {\n\t\t\tfields[\"port\"] = port.Port\n\t\t\tfields[\"target_port\"] = port.TargetPort.IntVal\n\n\t\t\ttags[\"port_name\"] = port.Name\n\t\t\ttags[\"port_protocol\"] = string(port.Protocol)\n\n\t\t\tif s.Spec.Type == \"ExternalName\" {\n\t\t\t\ttags[\"external_name\"] = s.Spec.ExternalName\n\t\t\t} else {\n\t\t\t\ttags[\"cluster_ip\"] = s.Spec.ClusterIP\n\t\t\t}\n\n\t\t\tacc.AddFields(serviceMeasurement, fields, tags)\n\t\t}\n\t}\n\n\tif externIPs := s.Spec.ExternalIPs; externIPs != nil {\n\t\tfor _, ip := range externIPs {\n\t\t\ttags[\"ip\"] = ip\n\n\t\t\tgetPorts()\n\t\t}\n\t} else {\n\t\tgetPorts()\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/service_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestService(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t}{\n\t\t{\n\t\t\tname: \"no service\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/service/\": &corev1.ServiceList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect service\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/service/\": &corev1.ServiceList{\n\t\t\t\t\t\tItems: []corev1.Service{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSpec: corev1.ServiceSpec{\n\t\t\t\t\t\t\t\t\tPorts: []corev1.ServicePort{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tPort: 8080,\n\t\t\t\t\t\t\t\t\t\t\tTargetPort: intstr.IntOrString{\n\t\t\t\t\t\t\t\t\t\t\t\tIntVal: 1234,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tName:     \"diagnostic\",\n\t\t\t\t\t\t\t\t\t\t\tProtocol: \"TCP\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tExternalIPs: []string{\"1.0.0.127\"},\n\t\t\t\t\t\t\t\t\tClusterIP:   \"127.0.0.1\",\n\t\t\t\t\t\t\t\t\tSelector: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"checker\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_service\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"service_name\":     \"checker\",\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"port_name\":        \"diagnostic\",\n\t\t\t\t\t\t\"port_protocol\":    \"TCP\",\n\t\t\t\t\t\t\"cluster_ip\":       \"127.0.0.1\",\n\t\t\t\t\t\t\"ip\":               \"1.0.0.127\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"port\":        int32(8080),\n\t\t\t\t\t\t\"target_port\": int32(1234),\n\t\t\t\t\t\t\"generation\":  int64(12),\n\t\t\t\t\t\t\"created\":     now.UnixNano(),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/service/\"]).(*corev1.ServiceList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherService(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestServiceSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/service/\": &corev1.ServiceList{\n\t\t\tItems: []corev1.Service{\n\t\t\t\t{\n\t\t\t\t\tSpec: corev1.ServiceSpec{\n\t\t\t\t\t\tPorts: []corev1.ServicePort{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tPort: 8080,\n\t\t\t\t\t\t\t\tTargetPort: intstr.IntOrString{\n\t\t\t\t\t\t\t\t\tIntVal: 1234,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tName:     \"diagnostic\",\n\t\t\t\t\t\t\t\tProtocol: \"TCP\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExternalIPs: []string{\"1.0.0.127\"},\n\t\t\t\t\t\tClusterIP:   \"127.0.0.1\",\n\t\t\t\t\t\tSelector: map[string]string{\n\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\tGeneration:        12,\n\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\tName:              \"checker\",\n\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/service/\"]).(*corev1.ServiceList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherService(&items[i], acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/statefulset.go",
    "content": "package kube_inventory\n\nimport (\n\t\"context\"\n\n\t\"k8s.io/api/apps/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nfunc collectStatefulSets(ctx context.Context, acc telegraf.Accumulator, ki *KubernetesInventory) {\n\tlist, err := ki.client.getStatefulSets(ctx)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\tfor i := range list.Items {\n\t\tki.gatherStatefulSet(&list.Items[i], acc)\n\t}\n}\n\nfunc (ki *KubernetesInventory) gatherStatefulSet(s *v1.StatefulSet, acc telegraf.Accumulator) {\n\tstatus := s.Status\n\tfields := map[string]interface{}{\n\t\t\"created\":             s.GetCreationTimestamp().UnixNano(),\n\t\t\"generation\":          s.Generation,\n\t\t\"replicas\":            status.Replicas,\n\t\t\"replicas_current\":    status.CurrentReplicas,\n\t\t\"replicas_ready\":      status.ReadyReplicas,\n\t\t\"replicas_updated\":    status.UpdatedReplicas,\n\t\t\"observed_generation\": s.Status.ObservedGeneration,\n\t}\n\tif s.Spec.Replicas != nil {\n\t\tfields[\"spec_replicas\"] = *s.Spec.Replicas\n\t}\n\ttags := map[string]string{\n\t\t\"statefulset_name\": s.Name,\n\t\t\"namespace\":        s.Namespace,\n\t}\n\tif s.Spec.Selector != nil {\n\t\tfor key, val := range s.Spec.Selector.MatchLabels {\n\t\t\tif ki.selectorFilter.Match(key) {\n\t\t\t\ttags[\"selector_\"+key] = val\n\t\t\t}\n\t\t}\n\t}\n\n\tacc.AddFields(statefulSetMeasurement, fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/kube_inventory/statefulset_test.go",
    "content": "package kube_inventory\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"k8s.io/api/apps/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestStatefulSet(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\toutput   []telegraf.Metric\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname: \"no statefulsets\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/statefulsets/\": &v1.StatefulSetList{},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"collect statefulsets\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/statefulsets/\": &v1.StatefulSetList{\n\t\t\t\t\t\tItems: []v1.StatefulSet{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: v1.StatefulSetStatus{\n\t\t\t\t\t\t\t\t\tReplicas:           2,\n\t\t\t\t\t\t\t\t\tCurrentReplicas:    4,\n\t\t\t\t\t\t\t\t\tReadyReplicas:      1,\n\t\t\t\t\t\t\t\t\tUpdatedReplicas:    3,\n\t\t\t\t\t\t\t\t\tObservedGeneration: 119,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: v1.StatefulSetSpec{\n\t\t\t\t\t\t\t\t\tReplicas: toPtr(int32(3)),\n\t\t\t\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        332,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"sts1\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_statefulset\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"statefulset_name\": \"sts1\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"generation\":          int64(332),\n\t\t\t\t\t\t\"observed_generation\": int64(119),\n\t\t\t\t\t\t\"created\":             now.UnixNano(),\n\t\t\t\t\t\t\"spec_replicas\":       int32(3),\n\t\t\t\t\t\t\"replicas\":            int32(2),\n\t\t\t\t\t\t\"replicas_current\":    int32(4),\n\t\t\t\t\t\t\"replicas_ready\":      int32(1),\n\t\t\t\t\t\t\"replicas_updated\":    int32(3),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"no label selector\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/statefulsets/\": &v1.StatefulSetList{\n\t\t\t\t\t\tItems: []v1.StatefulSet{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: v1.StatefulSetStatus{\n\t\t\t\t\t\t\t\t\tReplicas:           2,\n\t\t\t\t\t\t\t\t\tCurrentReplicas:    4,\n\t\t\t\t\t\t\t\t\tReadyReplicas:      1,\n\t\t\t\t\t\t\t\t\tUpdatedReplicas:    3,\n\t\t\t\t\t\t\t\t\tObservedGeneration: 119,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: v1.StatefulSetSpec{\n\t\t\t\t\t\t\t\t\tReplicas: toPtr(int32(3)),\n\t\t\t\t\t\t\t\t\tSelector: nil,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        332,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"sts1\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_statefulset\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"statefulset_name\": \"sts1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"generation\":          int64(332),\n\t\t\t\t\t\t\"observed_generation\": int64(119),\n\t\t\t\t\t\t\"created\":             now.UnixNano(),\n\t\t\t\t\t\t\"spec_replicas\":       int32(3),\n\t\t\t\t\t\t\"replicas\":            int32(2),\n\t\t\t\t\t\t\"replicas_current\":    int32(4),\n\t\t\t\t\t\t\"replicas_ready\":      int32(1),\n\t\t\t\t\t\t\"replicas_updated\":    int32(3),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"no desired number of replicas\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: map[string]interface{}{\n\t\t\t\t\t\"/statefulsets/\": &v1.StatefulSetList{\n\t\t\t\t\t\tItems: []v1.StatefulSet{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tStatus: v1.StatefulSetStatus{\n\t\t\t\t\t\t\t\t\tReplicas:           2,\n\t\t\t\t\t\t\t\t\tCurrentReplicas:    4,\n\t\t\t\t\t\t\t\t\tReadyReplicas:      1,\n\t\t\t\t\t\t\t\t\tUpdatedReplicas:    3,\n\t\t\t\t\t\t\t\t\tObservedGeneration: 119,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tSpec: v1.StatefulSetSpec{\n\t\t\t\t\t\t\t\t\tReplicas: nil,\n\t\t\t\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\t\t\t\tGeneration:        332,\n\t\t\t\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\t\t\t\tName:              \"sts1\",\n\t\t\t\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toutput: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"kubernetes_statefulset\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"namespace\":        \"ns1\",\n\t\t\t\t\t\t\"statefulset_name\": \"sts1\",\n\t\t\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"generation\":          int64(332),\n\t\t\t\t\t\t\"observed_generation\": int64(119),\n\t\t\t\t\t\t\"created\":             now.UnixNano(),\n\t\t\t\t\t\t\"replicas\":            int32(2),\n\t\t\t\t\t\t\"replicas_current\":    int32(4),\n\t\t\t\t\t\t\"replicas_ready\":      int32(1),\n\t\t\t\t\t\t\"replicas_updated\":    int32(3),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t\thasError: false,\n\t\t},\n\t}\n\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := &testutil.Accumulator{}\n\t\titems := ((v.handler.responseMap[\"/statefulsets/\"]).(*v1.StatefulSetList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherStatefulSet(&items[i], acc)\n\t\t}\n\n\t\terr := acc.FirstError()\n\t\tif v.hasError {\n\t\t\trequire.Errorf(t, err, \"%s failed, should have error\", v.name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// No error case\n\t\trequire.NoErrorf(t, err, \"%s failed, err: %v\", v.name, err)\n\n\t\trequire.Len(t, acc.Metrics, len(v.output))\n\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), v.output, testutil.IgnoreTime())\n\t}\n}\n\nfunc TestStatefulSetSelectorFilter(t *testing.T) {\n\tcli := &client{}\n\tnow := time.Now()\n\tnow = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 1, 36, 0, now.Location())\n\n\tresponseMap := map[string]interface{}{\n\t\t\"/statefulsets/\": &v1.StatefulSetList{\n\t\t\tItems: []v1.StatefulSet{\n\t\t\t\t{\n\t\t\t\t\tStatus: v1.StatefulSetStatus{\n\t\t\t\t\t\tReplicas:           2,\n\t\t\t\t\t\tCurrentReplicas:    4,\n\t\t\t\t\t\tReadyReplicas:      1,\n\t\t\t\t\t\tUpdatedReplicas:    3,\n\t\t\t\t\t\tObservedGeneration: 119,\n\t\t\t\t\t},\n\t\t\t\t\tSpec: v1.StatefulSetSpec{\n\t\t\t\t\t\tReplicas: toPtr(int32(3)),\n\t\t\t\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\t\t\t\"select1\": \"s1\",\n\t\t\t\t\t\t\t\t\"select2\": \"s2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\t\tGeneration:        332,\n\t\t\t\t\t\tNamespace:         \"ns1\",\n\t\t\t\t\t\tName:              \"sts1\",\n\t\t\t\t\t\tCreationTimestamp: metav1.Time{Time: now},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\thandler  *mockHandler\n\t\thasError bool\n\t\tinclude  []string\n\t\texclude  []string\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"nil filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  nil,\n\t\t\texclude:  nil,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty filters equals all selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t\t\"selector_select2\": \"s2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"select1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude filter equals only non-excluded selectors (overrides include filter)\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"select2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"include glob filter equals only include-matched selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\tinclude:  []string{\"*1\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"exclude glob filter equals only non-excluded selectors\",\n\t\t\thandler: &mockHandler{\n\t\t\t\tresponseMap: responseMap,\n\t\t\t},\n\t\t\thasError: false,\n\t\t\texclude:  []string{\"*2\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"selector_select1\": \"s1\",\n\t\t\t},\n\t\t},\n\t}\n\tfor _, v := range tests {\n\t\tks := &KubernetesInventory{\n\t\t\tclient: cli,\n\t\t}\n\t\tks.SelectorInclude = v.include\n\t\tks.SelectorExclude = v.exclude\n\t\trequire.NoError(t, ks.createSelectorFilters())\n\t\tacc := new(testutil.Accumulator)\n\t\titems := ((v.handler.responseMap[\"/statefulsets/\"]).(*v1.StatefulSetList)).Items\n\t\tfor i := range items {\n\t\t\tks.gatherStatefulSet(&items[i], acc)\n\t\t}\n\n\t\t// Grab selector tags\n\t\tactual := map[string]string{}\n\t\tfor _, metric := range acc.Metrics {\n\t\t\tfor key, val := range metric.Tags {\n\t\t\t\tif strings.Contains(key, \"selector_\") {\n\t\t\t\t\tactual[key] = val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trequire.Equalf(t, v.expected, actual,\n\t\t\t\"actual selector tags (%v) do not match expected selector tags (%v)\", actual, v.expected)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/kubernetes/README.md",
    "content": "# Kubernetes Input Plugin\n\nThis plugin gathers metrics about running pods and containers of a\n[Kubernetes][kubernetes] instance via the Kubelet API.\n\n> [!NOTE]\n> This plugin has to run as part of a `daemonset` within a Kubernetes\n> installation.\n> Telegraf must run on every node within the cluster.\n\nYou should configure this plugin to talk to its locally running kubelet.\n\n> [!CRITICAL]\n> This plugin produces high cardinality data, which when not controlled for will\n> cause high load on your database. Please make sure to [filter][filtering] the\n> produced metrics or configure your database to avoid cardinality issues!\n\n⭐ Telegraf v1.1.0\n🏷️ containers\n💻 all\n\n[kubernetes]: https://kubernetes.io/\n[filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from the kubernetes kubelet api\n[[inputs.kubernetes]]\n  ## URL for the kubelet, if empty read metrics from all nodes in the cluster\n  url = \"http://127.0.0.1:10255\"\n\n  ## Use bearer token for authorization. ('bearer_token' takes priority)\n  ## If both of these are empty, we'll use the default serviceaccount:\n  ## at: /var/run/secrets/kubernetes.io/serviceaccount/token\n  ##\n  ## To re-read the token at each interval, please use a file with the\n  ## bearer_token option. If given a string, Telegraf will always use that\n  ## token.\n  # bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n  ## OR\n  # bearer_token_string = \"abc_123\"\n\n  ## Kubernetes Node Metric Name\n  ## The default Kubernetes node metric name (kubernetes_node) is the same\n  ## for the kubernetes and kube_inventory plugins. To avoid conflicts, set this\n  ## option to a different value.\n  # node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags.  An empty array for both include and\n  ## exclude will include all labels.\n  # label_include = []\n  # label_exclude = [\"*\"]\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### Host IP\n\nTo find the ip address of the host you are running on you can issue a command\nlike the following:\n\n```sh\ncurl -s $API_URL/api/v1/namespaces/$POD_NAMESPACE/pods/$HOSTNAME \\\n  --header \"Authorization: Bearer $TOKEN\" \\\n  --insecure | jq -r '.status.hostIP'\n```\n\nThis example uses the downward API to pass in the `$POD_NAMESPACE` and\n`$HOSTNAME` is the hostname of the pod which is set by the kubernetes API.\nSee the [Kubernetes documentation][Kubernetes_docs] for a full example of\ngenerating a bearer token to explore the Kubernetes API.\n\n[Kubernetes_docs]: https://kubernetes.io/docs/tasks/administer-cluster/access-cluster-api/#without-kubectl-proxy\n\n### Daemon-set\n\nFor recommendations on running Telegraf as a daemon-set see the\n[Monitoring Kubernetes Architecture blog post][k8s_telegraf_blog] or check the\nfollowing Helm charts:\n\n- [Telegraf][helm_telegraf]\n- [InfluxDB][helm_influxdb]\n- [Chronograf][helm_chronograf]\n- [Kapacitor][helm_kapacitor]\n\n[k8s_telegraf_blog]: https://www.influxdata.com/blog/monitoring-kubernetes-architecture/\n[helm_telegraf]: https://github.com/helm/charts/tree/master/stable/telegraf\n[helm_influxdb]: https://github.com/helm/charts/tree/master/stable/influxdb\n[helm_chronograf]: https://github.com/helm/charts/tree/master/stable/chronograf\n[helm_kapacitor]: https://github.com/helm/charts/tree/master/stable/kapacitor\n\n## Metrics\n\n- kubernetes_node\n  - tags:\n    - node_name\n  - fields:\n    - cpu_usage_nanocores\n    - cpu_usage_core_nanoseconds\n    - memory_available_bytes\n    - memory_usage_bytes\n    - memory_working_set_bytes\n    - memory_rss_bytes\n    - memory_page_faults\n    - memory_major_page_faults\n    - network_rx_bytes\n    - network_rx_errors\n    - network_tx_bytes\n    - network_tx_errors\n    - fs_available_bytes\n    - fs_capacity_bytes\n    - fs_used_bytes\n    - runtime_image_fs_available_bytes\n    - runtime_image_fs_capacity_bytes\n    - runtime_image_fs_used_bytes\n\n- kubernetes_pod_container\n  - tags:\n    - container_name\n    - namespace\n    - node_name\n    - pod_name\n  - fields:\n    - cpu_usage_nanocores\n    - cpu_usage_core_nanoseconds\n    - memory_usage_bytes\n    - memory_working_set_bytes\n    - memory_rss_bytes\n    - memory_page_faults\n    - memory_major_page_faults\n    - rootfs_available_bytes\n    - rootfs_capacity_bytes\n    - rootfs_used_bytes\n    - logsfs_available_bytes\n    - logsfs_capacity_bytes\n    - logsfs_used_bytes\n\n- kubernetes_pod_volume\n  - tags:\n    - volume_name\n    - namespace\n    - node_name\n    - pod_name\n  - fields:\n    - available_bytes\n    - capacity_bytes\n    - used_bytes\n\n- kubernetes_pod_network\n  - tags:\n    - namespace\n    - node_name\n    - pod_name\n  - fields:\n    - rx_bytes\n    - rx_errors\n    - tx_bytes\n    - tx_errors\n\n## Example Output\n\n```text\nkubernetes_node\nkubernetes_pod_container,container_name=deis-controller,namespace=deis,node_name=ip-10-0-0-0.ec2.internal,pod_name=deis-controller-3058870187-xazsr cpu_usage_core_nanoseconds=2432835i,cpu_usage_nanocores=0i,logsfs_available_bytes=121128271872i,logsfs_capacity_bytes=153567944704i,logsfs_used_bytes=20787200i,memory_major_page_faults=0i,memory_page_faults=175i,memory_rss_bytes=0i,memory_usage_bytes=0i,memory_working_set_bytes=0i,rootfs_available_bytes=121128271872i,rootfs_capacity_bytes=153567944704i,rootfs_used_bytes=1110016i 1476477530000000000\nkubernetes_pod_network,namespace=deis,node_name=ip-10-0-0-0.ec2.internal,pod_name=deis-controller-3058870187-xazsr rx_bytes=120671099i,rx_errors=0i,tx_bytes=102451983i,tx_errors=0i 1476477530000000000\nkubernetes_pod_volume,volume_name=default-token-f7wts,namespace=default,node_name=ip-172-17-0-1.internal,pod_name=storage-7 available_bytes=8415240192i,capacity_bytes=8415252480i,used_bytes=12288i 1546910783000000000\nkubernetes_system_container\n```\n"
  },
  {
    "path": "plugins/inputs/kubernetes/kubernetes.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage kubernetes\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultServiceAccountPath = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n)\n\n// Kubernetes represents the config object for the plugin\ntype Kubernetes struct {\n\tURL             string          `toml:\"url\"`\n\tBearerToken     string          `toml:\"bearer_token\"`\n\tNodeMetricName  string          `toml:\"node_metric_name\"`\n\tLabelInclude    []string        `toml:\"label_include\"`\n\tLabelExclude    []string        `toml:\"label_exclude\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\tLog             telegraf.Logger `toml:\"-\"`\n\n\ttls.ClientConfig\n\n\tlabelFilter filter.Filter\n\thttpClient  *http.Client\n}\n\nfunc (*Kubernetes) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *Kubernetes) Init() error {\n\t// If bearer_token is not provided, use the default service account.\n\tif k.BearerToken == \"\" {\n\t\tk.BearerToken = defaultServiceAccountPath\n\t}\n\n\tlabelFilter, err := filter.NewIncludeExcludeFilter(k.LabelInclude, k.LabelExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tk.labelFilter = labelFilter\n\n\tif k.URL == \"\" {\n\t\tk.InsecureSkipVerify = true\n\t}\n\n\tif k.NodeMetricName == \"\" {\n\t\tk.NodeMetricName = \"kubernetes_node\"\n\t}\n\n\treturn nil\n}\n\nfunc (k *Kubernetes) Gather(acc telegraf.Accumulator) error {\n\tif k.URL != \"\" {\n\t\tacc.AddError(k.gatherSummary(k.URL, acc))\n\t\treturn nil\n\t}\n\n\tvar wg sync.WaitGroup\n\tnodeBaseURLs, err := getNodeURLs(k.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, url := range nodeBaseURLs {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(k.gatherSummary(url, acc))\n\t\t}(url)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc getNodeURLs(log telegraf.Logger) ([]string, error) {\n\tcfg, err := rest.InClusterConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tclient, err := kubernetes.NewForConfig(cfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodes, err := client.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodeUrls := make([]string, 0, len(nodes.Items))\n\tfor i := range nodes.Items {\n\t\tn := &nodes.Items[i]\n\n\t\taddress := getNodeAddress(n.Status.Addresses)\n\t\tif address == \"\" {\n\t\t\tlog.Warnf(\"Unable to node addresses for Node %q\", n.Name)\n\t\t\tcontinue\n\t\t}\n\t\tnodeUrls = append(nodeUrls, \"https://\"+address+\":10250\")\n\t}\n\n\treturn nodeUrls, nil\n}\n\n// Prefer internal addresses, if none found, use ExternalIP\nfunc getNodeAddress(addresses []v1.NodeAddress) string {\n\textAddresses := make([]string, 0, len(addresses))\n\tfor _, addr := range addresses {\n\t\tif addr.Type == v1.NodeInternalIP {\n\t\t\treturn addr.Address\n\t\t}\n\t\textAddresses = append(extAddresses, addr.Address)\n\t}\n\n\tif len(extAddresses) > 0 {\n\t\treturn extAddresses[0]\n\t}\n\treturn \"\"\n}\n\nfunc (k *Kubernetes) gatherSummary(baseURL string, acc telegraf.Accumulator) error {\n\tsummaryMetrics := &summaryMetrics{}\n\terr := k.loadJSON(baseURL+\"/stats/summary\", summaryMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpodInfos, err := k.gatherPodInfo(baseURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbuildSystemContainerMetrics(summaryMetrics, acc)\n\tbuildNodeMetrics(summaryMetrics, acc, k.NodeMetricName)\n\tbuildPodMetrics(summaryMetrics, podInfos, k.labelFilter, acc)\n\treturn nil\n}\n\nfunc buildSystemContainerMetrics(summaryMetrics *summaryMetrics, acc telegraf.Accumulator) {\n\tfor _, container := range summaryMetrics.Node.SystemContainers {\n\t\ttags := map[string]string{\n\t\t\t\"node_name\":      summaryMetrics.Node.NodeName,\n\t\t\t\"container_name\": container.Name,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"cpu_usage_nanocores\"] = container.CPU.UsageNanoCores\n\t\tfields[\"cpu_usage_core_nanoseconds\"] = container.CPU.UsageCoreNanoSeconds\n\t\tfields[\"memory_usage_bytes\"] = container.Memory.UsageBytes\n\t\tfields[\"memory_working_set_bytes\"] = container.Memory.WorkingSetBytes\n\t\tfields[\"memory_rss_bytes\"] = container.Memory.RSSBytes\n\t\tfields[\"memory_page_faults\"] = container.Memory.PageFaults\n\t\tfields[\"memory_major_page_faults\"] = container.Memory.MajorPageFaults\n\t\tfields[\"rootfs_available_bytes\"] = container.RootFS.AvailableBytes\n\t\tfields[\"rootfs_capacity_bytes\"] = container.RootFS.CapacityBytes\n\t\tfields[\"logsfs_available_bytes\"] = container.LogsFS.AvailableBytes\n\t\tfields[\"logsfs_capacity_bytes\"] = container.LogsFS.CapacityBytes\n\t\tacc.AddFields(\"kubernetes_system_container\", fields, tags)\n\t}\n}\n\nfunc buildNodeMetrics(summaryMetrics *summaryMetrics, acc telegraf.Accumulator, metricName string) {\n\ttags := map[string]string{\n\t\t\"node_name\": summaryMetrics.Node.NodeName,\n\t}\n\tfields := make(map[string]interface{})\n\tfields[\"cpu_usage_nanocores\"] = summaryMetrics.Node.CPU.UsageNanoCores\n\tfields[\"cpu_usage_core_nanoseconds\"] = summaryMetrics.Node.CPU.UsageCoreNanoSeconds\n\tfields[\"memory_available_bytes\"] = summaryMetrics.Node.Memory.AvailableBytes\n\tfields[\"memory_usage_bytes\"] = summaryMetrics.Node.Memory.UsageBytes\n\tfields[\"memory_working_set_bytes\"] = summaryMetrics.Node.Memory.WorkingSetBytes\n\tfields[\"memory_rss_bytes\"] = summaryMetrics.Node.Memory.RSSBytes\n\tfields[\"memory_page_faults\"] = summaryMetrics.Node.Memory.PageFaults\n\tfields[\"memory_major_page_faults\"] = summaryMetrics.Node.Memory.MajorPageFaults\n\tfields[\"network_rx_bytes\"] = summaryMetrics.Node.Network.RXBytes\n\tfields[\"network_rx_errors\"] = summaryMetrics.Node.Network.RXErrors\n\tfields[\"network_tx_bytes\"] = summaryMetrics.Node.Network.TXBytes\n\tfields[\"network_tx_errors\"] = summaryMetrics.Node.Network.TXErrors\n\tfields[\"fs_available_bytes\"] = summaryMetrics.Node.FileSystem.AvailableBytes\n\tfields[\"fs_capacity_bytes\"] = summaryMetrics.Node.FileSystem.CapacityBytes\n\tfields[\"fs_used_bytes\"] = summaryMetrics.Node.FileSystem.UsedBytes\n\tfields[\"runtime_image_fs_available_bytes\"] = summaryMetrics.Node.Runtime.ImageFileSystem.AvailableBytes\n\tfields[\"runtime_image_fs_capacity_bytes\"] = summaryMetrics.Node.Runtime.ImageFileSystem.CapacityBytes\n\tfields[\"runtime_image_fs_used_bytes\"] = summaryMetrics.Node.Runtime.ImageFileSystem.UsedBytes\n\tacc.AddFields(metricName, fields, tags)\n}\n\nfunc (k *Kubernetes) gatherPodInfo(baseURL string) ([]item, error) {\n\tvar podAPI pods\n\terr := k.loadJSON(baseURL+\"/pods\", &podAPI)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpodInfos := make([]item, 0, len(podAPI.Items))\n\tpodInfos = append(podInfos, podAPI.Items...)\n\treturn podInfos, nil\n}\n\nfunc (k *Kubernetes) loadJSON(url string, v interface{}) error {\n\tvar req, err = http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar resp *http.Response\n\ttlsCfg, err := k.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif k.httpClient == nil {\n\t\tif k.ResponseTimeout < config.Duration(time.Second) {\n\t\t\tk.ResponseTimeout = config.Duration(time.Second * 5)\n\t\t}\n\t\tk.httpClient = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tTLSClientConfig: tlsCfg,\n\t\t\t},\n\t\t\tCheckRedirect: func(*http.Request, []*http.Request) error {\n\t\t\t\treturn http.ErrUseLastResponse\n\t\t\t},\n\t\t\tTimeout: time.Duration(k.ResponseTimeout),\n\t\t}\n\t}\n\n\t// Read bearer token from file and use it for authorization\n\tvar bearerTokenString string\n\tif k.BearerToken != \"\" {\n\t\ttoken, err := os.ReadFile(k.BearerToken)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbearerTokenString = strings.TrimSpace(string(token))\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+bearerTokenString)\n\treq.Header.Add(\"Accept\", \"application/json\")\n\tresp, err = k.httpClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", url, resp.Status)\n\t}\n\n\terr = json.NewDecoder(resp.Body).Decode(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing response: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc buildPodMetrics(summaryMetrics *summaryMetrics, podInfo []item, labelFilter filter.Filter, acc telegraf.Accumulator) {\n\tfor _, pod := range summaryMetrics.Pods {\n\t\tpodLabels := make(map[string]string)\n\t\tcontainerImages := make(map[string]string)\n\t\tfor _, info := range podInfo {\n\t\t\tif info.Metadata.Name == pod.PodRef.Name && info.Metadata.Namespace == pod.PodRef.Namespace {\n\t\t\t\tfor _, v := range info.Spec.Containers {\n\t\t\t\t\tcontainerImages[v.Name] = v.Image\n\t\t\t\t}\n\t\t\t\tfor k, v := range info.Metadata.Labels {\n\t\t\t\t\tif labelFilter.Match(k) {\n\t\t\t\t\t\tpodLabels[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, container := range pod.Containers {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"node_name\":      summaryMetrics.Node.NodeName,\n\t\t\t\t\"namespace\":      pod.PodRef.Namespace,\n\t\t\t\t\"container_name\": container.Name,\n\t\t\t\t\"pod_name\":       pod.PodRef.Name,\n\t\t\t}\n\t\t\tfor k, v := range containerImages {\n\t\t\t\tif k == container.Name {\n\t\t\t\t\ttags[\"image\"] = v\n\t\t\t\t\ttok := strings.Split(v, \":\")\n\t\t\t\t\tif len(tok) == 2 {\n\t\t\t\t\t\ttags[\"version\"] = tok[1]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor k, v := range podLabels {\n\t\t\t\ttags[k] = v\n\t\t\t}\n\t\t\tfields := make(map[string]interface{})\n\t\t\tfields[\"cpu_usage_nanocores\"] = container.CPU.UsageNanoCores\n\t\t\tfields[\"cpu_usage_core_nanoseconds\"] = container.CPU.UsageCoreNanoSeconds\n\t\t\tfields[\"memory_usage_bytes\"] = container.Memory.UsageBytes\n\t\t\tfields[\"memory_working_set_bytes\"] = container.Memory.WorkingSetBytes\n\t\t\tfields[\"memory_rss_bytes\"] = container.Memory.RSSBytes\n\t\t\tfields[\"memory_page_faults\"] = container.Memory.PageFaults\n\t\t\tfields[\"memory_major_page_faults\"] = container.Memory.MajorPageFaults\n\t\t\tfields[\"rootfs_available_bytes\"] = container.RootFS.AvailableBytes\n\t\t\tfields[\"rootfs_capacity_bytes\"] = container.RootFS.CapacityBytes\n\t\t\tfields[\"rootfs_used_bytes\"] = container.RootFS.UsedBytes\n\t\t\tfields[\"logsfs_available_bytes\"] = container.LogsFS.AvailableBytes\n\t\t\tfields[\"logsfs_capacity_bytes\"] = container.LogsFS.CapacityBytes\n\t\t\tfields[\"logsfs_used_bytes\"] = container.LogsFS.UsedBytes\n\t\t\tacc.AddFields(\"kubernetes_pod_container\", fields, tags)\n\t\t}\n\n\t\tfor _, volume := range pod.Volumes {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"node_name\":   summaryMetrics.Node.NodeName,\n\t\t\t\t\"pod_name\":    pod.PodRef.Name,\n\t\t\t\t\"namespace\":   pod.PodRef.Namespace,\n\t\t\t\t\"volume_name\": volume.Name,\n\t\t\t}\n\t\t\tfor k, v := range podLabels {\n\t\t\t\ttags[k] = v\n\t\t\t}\n\t\t\tfields := make(map[string]interface{})\n\t\t\tfields[\"available_bytes\"] = volume.AvailableBytes\n\t\t\tfields[\"capacity_bytes\"] = volume.CapacityBytes\n\t\t\tfields[\"used_bytes\"] = volume.UsedBytes\n\t\t\tacc.AddFields(\"kubernetes_pod_volume\", fields, tags)\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"node_name\": summaryMetrics.Node.NodeName,\n\t\t\t\"pod_name\":  pod.PodRef.Name,\n\t\t\t\"namespace\": pod.PodRef.Namespace,\n\t\t}\n\t\tfor k, v := range podLabels {\n\t\t\ttags[k] = v\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"rx_bytes\"] = pod.Network.RXBytes\n\t\tfields[\"rx_errors\"] = pod.Network.RXErrors\n\t\tfields[\"tx_bytes\"] = pod.Network.TXBytes\n\t\tfields[\"tx_errors\"] = pod.Network.TXErrors\n\t\tacc.AddFields(\"kubernetes_pod_network\", fields, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"kubernetes\", func() telegraf.Input {\n\t\treturn &Kubernetes{\n\t\t\tLabelExclude: []string{\"*\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/kubernetes/kubernetes_metrics.go",
    "content": "package kubernetes\n\nimport \"time\"\n\n// summaryMetrics represents all the summary data about a particular node retrieved from a kubelet\ntype summaryMetrics struct {\n\tNode nodeMetrics  `json:\"node\"`\n\tPods []podMetrics `json:\"pods\"`\n}\n\n// nodeMetrics represents detailed information about a node\ntype nodeMetrics struct {\n\tNodeName         string             `json:\"nodeName\"`\n\tSystemContainers []containerMetrics `json:\"systemContainers\"`\n\tStartTime        time.Time          `json:\"startTime\"`\n\tCPU              cpuMetrics         `json:\"cpu\"`\n\tMemory           memoryMetrics      `json:\"memory\"`\n\tNetwork          networkMetrics     `json:\"network\"`\n\tFileSystem       fileSystemMetrics  `json:\"fs\"`\n\tRuntime          runtimeMetrics     `json:\"runtime\"`\n}\n\n// containerMetrics represents the metric data collect about a container from the kubelet\ntype containerMetrics struct {\n\tName      string            `json:\"name\"`\n\tStartTime time.Time         `json:\"startTime\"`\n\tCPU       cpuMetrics        `json:\"cpu\"`\n\tMemory    memoryMetrics     `json:\"memory\"`\n\tRootFS    fileSystemMetrics `json:\"rootfs\"`\n\tLogsFS    fileSystemMetrics `json:\"logs\"`\n}\n\n// runtimeMetrics contains metric data on the runtime of the system\ntype runtimeMetrics struct {\n\tImageFileSystem fileSystemMetrics `json:\"imageFs\"`\n}\n\n// cpuMetrics represents the cpu usage data of a pod or node\ntype cpuMetrics struct {\n\tTime                 time.Time `json:\"time\"`\n\tUsageNanoCores       int64     `json:\"usageNanoCores\"`\n\tUsageCoreNanoSeconds int64     `json:\"usageCoreNanoSeconds\"`\n}\n\n// podMetrics contains metric data on a given pod\ntype podMetrics struct {\n\tPodRef     podReference       `json:\"podRef\"`\n\tStartTime  *time.Time         `json:\"startTime\"`\n\tContainers []containerMetrics `json:\"containers\"`\n\tNetwork    networkMetrics     `json:\"network\"`\n\tVolumes    []volumeMetrics    `json:\"volume\"`\n}\n\n// podReference is how a pod is identified\ntype podReference struct {\n\tName      string `json:\"name\"`\n\tNamespace string `json:\"namespace\"`\n}\n\n// memoryMetrics represents the memory metrics for a pod or node\ntype memoryMetrics struct {\n\tTime            time.Time `json:\"time\"`\n\tAvailableBytes  int64     `json:\"availableBytes\"`\n\tUsageBytes      int64     `json:\"usageBytes\"`\n\tWorkingSetBytes int64     `json:\"workingSetBytes\"`\n\tRSSBytes        int64     `json:\"rssBytes\"`\n\tPageFaults      int64     `json:\"pageFaults\"`\n\tMajorPageFaults int64     `json:\"majorPageFaults\"`\n}\n\n// fileSystemMetrics represents disk usage metrics for a pod or node\ntype fileSystemMetrics struct {\n\tAvailableBytes int64 `json:\"availableBytes\"`\n\tCapacityBytes  int64 `json:\"capacityBytes\"`\n\tUsedBytes      int64 `json:\"usedBytes\"`\n}\n\n// networkMetrics represents network usage data for a pod or node\ntype networkMetrics struct {\n\tTime     time.Time `json:\"time\"`\n\tRXBytes  int64     `json:\"rxBytes\"`\n\tRXErrors int64     `json:\"rxErrors\"`\n\tTXBytes  int64     `json:\"txBytes\"`\n\tTXErrors int64     `json:\"txErrors\"`\n}\n\n// volumeMetrics represents the disk usage data for a given volume\ntype volumeMetrics struct {\n\tName           string `json:\"name\"`\n\tAvailableBytes int64  `json:\"availableBytes\"`\n\tCapacityBytes  int64  `json:\"capacityBytes\"`\n\tUsedBytes      int64  `json:\"usedBytes\"`\n}\n"
  },
  {
    "path": "plugins/inputs/kubernetes/kubernetes_pods.go",
    "content": "package kubernetes\n\ntype pods struct {\n\tKind       string `json:\"kind\"`\n\tAPIVersion string `json:\"apiVersion\"`\n\tItems      []item `json:\"items\"`\n}\n\ntype item struct {\n\tMetadata metadata `json:\"metadata\"`\n\tSpec     spec     `json:\"spec\"`\n}\n\ntype metadata struct {\n\tName      string            `json:\"name\"`\n\tNamespace string            `json:\"namespace\"`\n\tLabels    map[string]string `json:\"labels\"`\n}\n\ntype spec struct {\n\tContainers []container `json:\"containers\"`\n}\n\ntype container struct {\n\tName  string `json:\"name\"`\n\tImage string `json:\"image\"`\n}\n"
  },
  {
    "path": "plugins/inputs/kubernetes/kubernetes_test.go",
    "content": "package kubernetes\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestKubernetesStats(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.RequestURI == \"/stats/summary\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := fmt.Fprintln(w, responseStatsSummery); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif r.RequestURI == \"/pods\" {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tif _, err := fmt.Fprintln(w, responsePods); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tlabelFilter, err := filter.NewIncludeExcludeFilter([]string{\"app\", \"superkey\"}, nil)\n\trequire.NoError(t, err)\n\n\tk := &Kubernetes{\n\t\tURL:            ts.URL,\n\t\tlabelFilter:    labelFilter,\n\t\tNodeMetricName: \"kubernetes_node\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(k.Gather)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"cpu_usage_nanocores\":        int64(56652446),\n\t\t\"cpu_usage_core_nanoseconds\": int64(101437561712262),\n\t\t\"memory_usage_bytes\":         int64(62529536),\n\t\t\"memory_working_set_bytes\":   int64(62349312),\n\t\t\"memory_rss_bytes\":           int64(47509504),\n\t\t\"memory_page_faults\":         int64(4769397409),\n\t\t\"memory_major_page_faults\":   int64(13),\n\t\t\"rootfs_available_bytes\":     int64(84379979776),\n\t\t\"rootfs_capacity_bytes\":      int64(105553100800),\n\t\t\"logsfs_available_bytes\":     int64(84379979776),\n\t\t\"logsfs_capacity_bytes\":      int64(105553100800),\n\t}\n\ttags := map[string]string{\n\t\t\"node_name\":      \"node1\",\n\t\t\"container_name\": \"kubelet\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_system_container\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"cpu_usage_nanocores\":              int64(576996212),\n\t\t\"cpu_usage_core_nanoseconds\":       int64(774129887054161),\n\t\t\"memory_usage_bytes\":               int64(12313182208),\n\t\t\"memory_working_set_bytes\":         int64(5081538560),\n\t\t\"memory_rss_bytes\":                 int64(35586048),\n\t\t\"memory_page_faults\":               int64(351742),\n\t\t\"memory_major_page_faults\":         int64(1236),\n\t\t\"memory_available_bytes\":           int64(10726387712),\n\t\t\"network_rx_bytes\":                 int64(213281337459),\n\t\t\"network_rx_errors\":                int64(0),\n\t\t\"network_tx_bytes\":                 int64(292869995684),\n\t\t\"network_tx_errors\":                int64(0),\n\t\t\"fs_available_bytes\":               int64(84379979776),\n\t\t\"fs_capacity_bytes\":                int64(105553100800),\n\t\t\"fs_used_bytes\":                    int64(16754286592),\n\t\t\"runtime_image_fs_available_bytes\": int64(84379979776),\n\t\t\"runtime_image_fs_capacity_bytes\":  int64(105553100800),\n\t\t\"runtime_image_fs_used_bytes\":      int64(5809371475),\n\t}\n\ttags = map[string]string{\n\t\t\"node_name\": \"node1\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_node\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"cpu_usage_nanocores\":        int64(846503),\n\t\t\"cpu_usage_core_nanoseconds\": int64(56507553554),\n\t\t\"memory_usage_bytes\":         int64(30789632),\n\t\t\"memory_working_set_bytes\":   int64(30789632),\n\t\t\"memory_rss_bytes\":           int64(30695424),\n\t\t\"memory_page_faults\":         int64(10761),\n\t\t\"memory_major_page_faults\":   int64(0),\n\t\t\"rootfs_available_bytes\":     int64(84379979776),\n\t\t\"rootfs_capacity_bytes\":      int64(105553100800),\n\t\t\"rootfs_used_bytes\":          int64(57344),\n\t\t\"logsfs_available_bytes\":     int64(84379979776),\n\t\t\"logsfs_capacity_bytes\":      int64(105553100800),\n\t\t\"logsfs_used_bytes\":          int64(24576),\n\t}\n\ttags = map[string]string{\n\t\t\"node_name\":      \"node1\",\n\t\t\"container_name\": \"foocontainer\",\n\t\t\"namespace\":      \"foons\",\n\t\t\"pod_name\":       \"foopod\",\n\t\t\"app\":            \"foo\",\n\t\t\"superkey\":       \"foobar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_pod_container\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"cpu_usage_nanocores\":        int64(846503),\n\t\t\"cpu_usage_core_nanoseconds\": int64(56507553554),\n\t\t\"memory_usage_bytes\":         int64(0),\n\t\t\"memory_working_set_bytes\":   int64(0),\n\t\t\"memory_rss_bytes\":           int64(0),\n\t\t\"memory_page_faults\":         int64(0),\n\t\t\"memory_major_page_faults\":   int64(0),\n\t\t\"rootfs_available_bytes\":     int64(0),\n\t\t\"rootfs_capacity_bytes\":      int64(0),\n\t\t\"rootfs_used_bytes\":          int64(0),\n\t\t\"logsfs_available_bytes\":     int64(0),\n\t\t\"logsfs_capacity_bytes\":      int64(0),\n\t\t\"logsfs_used_bytes\":          int64(0),\n\t}\n\ttags = map[string]string{\n\t\t\"node_name\":      \"node1\",\n\t\t\"container_name\": \"stopped-container\",\n\t\t\"namespace\":      \"foons\",\n\t\t\"pod_name\":       \"stopped-pod\",\n\t\t\"app\":            \"foo-stop\",\n\t\t\"superkey\":       \"superfoo\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_pod_container\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"available_bytes\": int64(7903948800),\n\t\t\"capacity_bytes\":  int64(7903961088),\n\t\t\"used_bytes\":      int64(12288),\n\t}\n\ttags = map[string]string{\n\t\t\"node_name\":   \"node1\",\n\t\t\"volume_name\": \"volume1\",\n\t\t\"namespace\":   \"foons\",\n\t\t\"pod_name\":    \"foopod\",\n\t\t\"app\":         \"foo\",\n\t\t\"superkey\":    \"foobar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_pod_volume\", fields, tags)\n\n\tfields = map[string]interface{}{\n\t\t\"rx_bytes\":  int64(70749124),\n\t\t\"rx_errors\": int64(0),\n\t\t\"tx_bytes\":  int64(47813506),\n\t\t\"tx_errors\": int64(0),\n\t}\n\ttags = map[string]string{\n\t\t\"node_name\": \"node1\",\n\t\t\"namespace\": \"foons\",\n\t\t\"pod_name\":  \"foopod\",\n\t\t\"app\":       \"foo\",\n\t\t\"superkey\":  \"foobar\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"kubernetes_pod_network\", fields, tags)\n}\n\nvar responsePods = `\n{\n  \"kind\": \"PodList\",\n  \"apiVersion\": \"v1\",\n  \"metadata\": {},\n  \"items\": [\n    {\n      \"metadata\": {\n        \"name\": \"foopod\",\n        \"namespace\": \"foons\",\n        \"labels\": {\n          \"superkey\": \"foobar\",\n          \"app\": \"foo\",\n          \"exclude\": \"exclude0\"\n        }\n      }\n    },\n    {\n      \"metadata\": {\n        \"name\": \"stopped-pod\",\n        \"namespace\": \"foons\",\n        \"labels\": {\n          \"superkey\": \"superfoo\",\n          \"app\": \"foo-stop\",\n          \"exclude\": \"exclude1\"\n        }\n      }\n    }\n  ]\n}\n`\n\nvar responseStatsSummery = `\n{\n  \"node\": {\n   \"nodeName\": \"node1\",\n   \"systemContainers\": [\n    {\n     \"name\": \"kubelet\",\n     \"startTime\": \"2016-08-25T18:46:52Z\",\n     \"cpu\": {\n      \"time\": \"2016-09-27T16:57:31Z\",\n      \"usageNanoCores\": 56652446,\n      \"usageCoreNanoSeconds\": 101437561712262\n     },\n     \"memory\": {\n      \"time\": \"2016-09-27T16:57:31Z\",\n      \"usageBytes\": 62529536,\n      \"workingSetBytes\": 62349312,\n      \"rssBytes\": 47509504,\n      \"pageFaults\": 4769397409,\n      \"majorPageFaults\": 13\n     },\n     \"rootfs\": {\n      \"availableBytes\": 84379979776,\n      \"capacityBytes\": 105553100800\n     },\n     \"logs\": {\n      \"availableBytes\": 84379979776,\n      \"capacityBytes\": 105553100800\n     },\n     \"userDefinedMetrics\": null\n   },\n   {\n    \"name\": \"bar\",\n    \"startTime\": \"2016-08-25T18:46:52Z\",\n    \"cpu\": {\n     \"time\": \"2016-09-27T16:57:31Z\",\n     \"usageNanoCores\": 56652446,\n     \"usageCoreNanoSeconds\": 101437561712262\n    },\n    \"memory\": {\n     \"time\": \"2016-09-27T16:57:31Z\",\n     \"usageBytes\": 62529536,\n     \"workingSetBytes\": 62349312,\n     \"rssBytes\": 47509504,\n     \"pageFaults\": 4769397409,\n     \"majorPageFaults\": 13\n    },\n    \"rootfs\": {\n     \"availableBytes\": 84379979776,\n     \"capacityBytes\": 105553100800\n    },\n    \"logs\": {\n     \"availableBytes\": 84379979776,\n     \"capacityBytes\": 105553100800\n    },\n    \"userDefinedMetrics\": null\n   }\n   ],\n   \"startTime\": \"2016-08-25T18:46:52Z\",\n   \"cpu\": {\n    \"time\": \"2016-09-27T16:57:41Z\",\n    \"usageNanoCores\": 576996212,\n    \"usageCoreNanoSeconds\": 774129887054161\n   },\n   \"memory\": {\n    \"time\": \"2016-09-27T16:57:41Z\",\n    \"availableBytes\": 10726387712,\n    \"usageBytes\": 12313182208,\n    \"workingSetBytes\": 5081538560,\n    \"rssBytes\": 35586048,\n    \"pageFaults\": 351742,\n    \"majorPageFaults\": 1236\n   },\n   \"network\": {\n    \"time\": \"2016-09-27T16:57:41Z\",\n    \"rxBytes\": 213281337459,\n    \"rxErrors\": 0,\n    \"txBytes\": 292869995684,\n    \"txErrors\": 0\n   },\n   \"fs\": {\n    \"availableBytes\": 84379979776,\n    \"capacityBytes\": 105553100800,\n    \"usedBytes\": 16754286592\n   },\n   \"runtime\": {\n    \"imageFs\": {\n     \"availableBytes\": 84379979776,\n     \"capacityBytes\": 105553100800,\n     \"usedBytes\": 5809371475\n    }\n   }\n  },\n  \"pods\": [\n   {\n    \"podRef\": {\n     \"name\": \"foopod\",\n     \"namespace\": \"foons\",\n     \"uid\": \"6d305b06-8419-11e6-825c-42010af000ae\"\n    },\n    \"startTime\": \"2016-09-26T18:45:42Z\",\n    \"containers\": [\n     {\n      \"name\": \"foocontainer\",\n      \"startTime\": \"2016-09-26T18:46:43Z\",\n      \"cpu\": {\n       \"time\": \"2016-09-27T16:57:32Z\",\n       \"usageNanoCores\": 846503,\n       \"usageCoreNanoSeconds\": 56507553554\n      },\n      \"memory\": {\n       \"time\": \"2016-09-27T16:57:32Z\",\n       \"usageBytes\": 30789632,\n       \"workingSetBytes\": 30789632,\n       \"rssBytes\": 30695424,\n       \"pageFaults\": 10761,\n       \"majorPageFaults\": 0\n      },\n      \"rootfs\": {\n       \"availableBytes\": 84379979776,\n       \"capacityBytes\": 105553100800,\n       \"usedBytes\": 57344\n      },\n      \"logs\": {\n       \"availableBytes\": 84379979776,\n       \"capacityBytes\": 105553100800,\n       \"usedBytes\": 24576\n      },\n      \"userDefinedMetrics\": null\n     }\n    ],\n    \"network\": {\n     \"time\": \"2016-09-27T16:57:34Z\",\n     \"rxBytes\": 70749124,\n     \"rxErrors\": 0,\n     \"txBytes\": 47813506,\n     \"txErrors\": 0\n    },\n    \"volume\": [\n     {\n      \"availableBytes\": 7903948800,\n      \"capacityBytes\": 7903961088,\n      \"usedBytes\": 12288,\n      \"name\": \"volume1\"\n     },\n     {\n      \"availableBytes\": 7903956992,\n      \"capacityBytes\": 7903961088,\n      \"usedBytes\": 4096,\n      \"name\": \"volume2\"\n     },\n     {\n      \"availableBytes\": 7903948800,\n      \"capacityBytes\": 7903961088,\n      \"usedBytes\": 12288,\n      \"name\": \"volume3\"\n     },\n     {\n      \"availableBytes\": 7903952896,\n      \"capacityBytes\": 7903961088,\n      \"usedBytes\": 8192,\n      \"name\": \"volume4\"\n     }\n    ]\n   },\n   {\n    \"podRef\": {\n     \"name\": \"stopped-pod\",\n     \"namespace\": \"foons\",\n     \"uid\": \"da7c1865-d67d-4688-b679-c485ed44b2aa\"\n    },\n    \"startTime\": null,\n    \"containers\": [\n     {\n      \"name\": \"stopped-container\",\n      \"startTime\": \"2016-09-26T18:46:43Z\",\n      \"cpu\": {\n       \"time\": \"2016-09-27T16:57:32Z\",\n       \"usageNanoCores\": 846503,\n       \"usageCoreNanoSeconds\": 56507553554\n      }\n     }\n    ]\n   }\n  ]\n }`\n"
  },
  {
    "path": "plugins/inputs/kubernetes/sample.conf",
    "content": "# Read metrics from the kubernetes kubelet api\n[[inputs.kubernetes]]\n  ## URL for the kubelet, if empty read metrics from all nodes in the cluster\n  url = \"http://127.0.0.1:10255\"\n\n  ## Use bearer token for authorization. ('bearer_token' takes priority)\n  ## If both of these are empty, we'll use the default serviceaccount:\n  ## at: /var/run/secrets/kubernetes.io/serviceaccount/token\n  ##\n  ## To re-read the token at each interval, please use a file with the\n  ## bearer_token option. If given a string, Telegraf will always use that\n  ## token.\n  # bearer_token = \"/var/run/secrets/kubernetes.io/serviceaccount/token\"\n  ## OR\n  # bearer_token_string = \"abc_123\"\n\n  ## Kubernetes Node Metric Name\n  ## The default Kubernetes node metric name (kubernetes_node) is the same\n  ## for the kubernetes and kube_inventory plugins. To avoid conflicts, set this\n  ## option to a different value.\n  # node_metric_name = \"kubernetes_node\"\n\n  ## Pod labels to be added as tags.  An empty array for both include and\n  ## exclude will include all labels.\n  # label_include = []\n  # label_exclude = [\"*\"]\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/lanz/README.md",
    "content": "# Arista LANZ Consumer Input Plugin\n\nThis service plugin consumes messages from the\n[Arista Networks’ Latency Analyzer (LANZ)][lanz] by receiving the datastream\non TCP (usually through port 50001) on the switch's management IP.\n\n> [!NOTE]\n> You will need to configure LANZ and enable streaming LANZ data, see the\n> [documentation][config_lanz] for more details.\n\n⭐ Telegraf v1.14.0\n🏷️ network\n💻 all\n\n[lanz]: https://www.arista.com/en/um-eos/eos-latency-analyzer-lanz\n[config_lanz]: https://www.arista.com/en/um-eos/eos-section-44-3-configuring-lanz\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics off Arista LANZ, via socket\n[[inputs.lanz]]\n  ## URL to Arista LANZ endpoint\n  servers = [\n    \"tcp://switch1.int.example.com:50001\",\n    \"tcp://switch2.int.example.com:50001\",\n  ]\n```\n\n## Metrics\n\nFor more details on the metrics see the [protocol buffer definition][proto].\n\n- lanz_congestion_record:\n  - tags:\n    - intf_name\n    - switch_id\n    - port_id\n    - entry_type\n    - traffic_class\n    - fabric_peer_intf_name\n    - source\n    - port\n  - fields:\n    - timestamp        (integer)\n    - queue_size       (integer)\n    - time_of_max_qlen (integer)\n    - tx_latency       (integer)\n    - q_drop_count     (integer)\n\n- lanz_global_buffer_usage_record\n  - tags:\n    - entry_type\n    - source\n    - port\n  - fields:\n    - timestamp   (integer)\n    - buffer_size (integer)\n    - duration    (integer)\n\n[proto]: https://github.com/aristanetworks/goarista/blob/master/lanz/proto/lanz.proto\n\n## Sample Queries\n\nGet the max tx_latency for the last hour for all interfaces on all switches.\n\n```sql\nSELECT max(\"tx_latency\") AS \"max_tx_latency\" FROM \"congestion_record\" WHERE time > now() - 1h GROUP BY time(10s), \"hostname\", \"intf_name\"\n```\n\nGet the max tx_latency for the last hour for all interfaces on all switches.\n\n```sql\nSELECT max(\"queue_size\") AS \"max_queue_size\" FROM \"congestion_record\" WHERE time > now() - 1h GROUP BY time(10s), \"hostname\", \"intf_name\"\n```\n\nGet the max buffer_size for over the last hour for all switches.\n\n```sql\nSELECT max(\"buffer_size\") AS \"max_buffer_size\" FROM \"global_buffer_usage_record\" WHERE time > now() - 1h GROUP BY time(10s), \"hostname\"\n```\n\n## Example Output\n\n```text\nlanz_global_buffer_usage_record,entry_type=2,host=telegraf.int.example.com,port=50001,source=switch01.int.example.com timestamp=158334105824919i,buffer_size=505i,duration=0i 1583341058300643815\nlanz_congestion_record,entry_type=2,host=telegraf.int.example.com,intf_name=Ethernet36,port=50001,port_id=61,source=switch01.int.example.com,switch_id=0,traffic_class=1 time_of_max_qlen=0i,tx_latency=564480i,q_drop_count=0i,timestamp=158334105824919i,queue_size=225i 1583341058300636045\nlanz_global_buffer_usage_record,entry_type=2,host=telegraf.int.example.com,port=50001,source=switch01.int.example.com timestamp=158334105824919i,buffer_size=589i,duration=0i 1583341058300457464\nlanz_congestion_record,entry_type=1,host=telegraf.int.example.com,intf_name=Ethernet36,port=50001,port_id=61,source=switch01.int.example.com,switch_id=0,traffic_class=1 q_drop_count=0i,timestamp=158334105824919i,queue_size=232i,time_of_max_qlen=0i,tx_latency=584640i 1583341058300450302\n```\n"
  },
  {
    "path": "plugins/inputs/lanz/lanz.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage lanz\n\nimport (\n\t_ \"embed\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aristanetworks/goarista/lanz\"\n\tpb \"github.com/aristanetworks/goarista/lanz/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Lanz struct {\n\tServers []string `toml:\"servers\"`\n\tclients []lanz.Client\n\twg      sync.WaitGroup\n}\n\nfunc (*Lanz) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *Lanz) Start(acc telegraf.Accumulator) error {\n\tif len(l.Servers) == 0 {\n\t\tl.Servers = append(l.Servers, \"tcp://127.0.0.1:50001\")\n\t}\n\n\tfor _, server := range l.Servers {\n\t\tdeviceURL, err := url.Parse(server)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tclient := lanz.New(\n\t\t\tlanz.WithAddr(deviceURL.Host),\n\t\t\tlanz.WithBackoff(1*time.Second),\n\t\t\tlanz.WithTimeout(10*time.Second),\n\t\t)\n\t\tl.clients = append(l.clients, client)\n\n\t\tin := make(chan *pb.LanzRecord)\n\t\tgo func() {\n\t\t\tclient.Run(in)\n\t\t}()\n\t\tl.wg.Add(1)\n\t\tgo func() {\n\t\t\tl.wg.Done()\n\t\t\treceive(acc, in, deviceURL)\n\t\t}()\n\t}\n\treturn nil\n}\n\nfunc (*Lanz) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (l *Lanz) Stop() {\n\tfor _, client := range l.clients {\n\t\tclient.Stop()\n\t}\n\tl.wg.Wait()\n}\n\nfunc receive(acc telegraf.Accumulator, in <-chan *pb.LanzRecord, deviceURL *url.URL) {\n\t//nolint:staticcheck // for-select used on purpose\n\tfor {\n\t\tselect {\n\t\tcase msg, ok := <-in:\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tmsgToAccumulator(acc, msg, deviceURL)\n\t\t}\n\t}\n}\n\nfunc msgToAccumulator(acc telegraf.Accumulator, msg *pb.LanzRecord, deviceURL *url.URL) {\n\tcr := msg.GetCongestionRecord()\n\tif cr != nil {\n\t\tvals := map[string]interface{}{\n\t\t\t\"timestamp\":        int64(cr.GetTimestamp()),\n\t\t\t\"queue_size\":       int64(cr.GetQueueSize()),\n\t\t\t\"time_of_max_qlen\": int64(cr.GetTimeOfMaxQLen()),\n\t\t\t\"tx_latency\":       int64(cr.GetTxLatency()),\n\t\t\t\"q_drop_count\":     int64(cr.GetQDropCount()),\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"intf_name\":             cr.GetIntfName(),\n\t\t\t\"switch_id\":             strconv.FormatInt(int64(cr.GetSwitchId()), 10),\n\t\t\t\"port_id\":               strconv.FormatInt(int64(cr.GetPortId()), 10),\n\t\t\t\"entry_type\":            strconv.FormatInt(int64(cr.GetEntryType()), 10),\n\t\t\t\"traffic_class\":         strconv.FormatInt(int64(cr.GetTrafficClass()), 10),\n\t\t\t\"fabric_peer_intf_name\": cr.GetFabricPeerIntfName(),\n\t\t\t\"source\":                deviceURL.Hostname(),\n\t\t\t\"port\":                  deviceURL.Port(),\n\t\t}\n\t\tacc.AddFields(\"lanz_congestion_record\", vals, tags)\n\t}\n\n\tgbur := msg.GetGlobalBufferUsageRecord()\n\tif gbur != nil {\n\t\tvals := map[string]interface{}{\n\t\t\t\"timestamp\":   int64(gbur.GetTimestamp()),\n\t\t\t\"buffer_size\": int64(gbur.GetBufferSize()),\n\t\t\t\"duration\":    int64(gbur.GetDuration()),\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"entry_type\": strconv.FormatInt(int64(gbur.GetEntryType()), 10),\n\t\t\t\"source\":     deviceURL.Hostname(),\n\t\t\t\"port\":       deviceURL.Port(),\n\t\t}\n\t\tacc.AddFields(\"lanz_global_buffer_usage_record\", vals, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"lanz\", func() telegraf.Input {\n\t\treturn &Lanz{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/lanz/lanz_test.go",
    "content": "package lanz\n\nimport (\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\n\tpb \"github.com/aristanetworks/goarista/lanz/proto\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar testProtoBufCongestionRecord1 = &pb.LanzRecord{\n\tCongestionRecord: &pb.CongestionRecord{\n\t\tTimestamp:          proto.Uint64(100000000000000),\n\t\tIntfName:           proto.String(\"eth1\"),\n\t\tSwitchId:           proto.Uint32(1),\n\t\tPortId:             proto.Uint32(1),\n\t\tQueueSize:          proto.Uint32(1),\n\t\tEntryType:          pb.CongestionRecord_EntryType.Enum(1),\n\t\tTrafficClass:       proto.Uint32(1),\n\t\tTimeOfMaxQLen:      proto.Uint64(100000000000000),\n\t\tTxLatency:          proto.Uint32(100),\n\t\tQDropCount:         proto.Uint32(1),\n\t\tFabricPeerIntfName: proto.String(\"FabricPeerIntfName1\"),\n\t},\n}\nvar testProtoBufCongestionRecord2 = &pb.LanzRecord{\n\tCongestionRecord: &pb.CongestionRecord{\n\t\tTimestamp:          proto.Uint64(200000000000000),\n\t\tIntfName:           proto.String(\"eth2\"),\n\t\tSwitchId:           proto.Uint32(2),\n\t\tPortId:             proto.Uint32(2),\n\t\tQueueSize:          proto.Uint32(2),\n\t\tEntryType:          pb.CongestionRecord_EntryType.Enum(2),\n\t\tTrafficClass:       proto.Uint32(2),\n\t\tTimeOfMaxQLen:      proto.Uint64(200000000000000),\n\t\tTxLatency:          proto.Uint32(200),\n\t\tQDropCount:         proto.Uint32(2),\n\t\tFabricPeerIntfName: proto.String(\"FabricPeerIntfName2\"),\n\t},\n}\n\nvar testProtoBufGlobalBufferUsageRecord = &pb.LanzRecord{\n\tGlobalBufferUsageRecord: &pb.GlobalBufferUsageRecord{\n\t\tEntryType:  pb.GlobalBufferUsageRecord_EntryType.Enum(1),\n\t\tTimestamp:  proto.Uint64(100000000000000),\n\t\tBufferSize: proto.Uint32(1),\n\t\tDuration:   proto.Uint32(10),\n\t},\n}\n\nfunc TestLanzGeneratesMetrics(t *testing.T) {\n\tl := &Lanz{Servers: []string{\n\t\t\"tcp://switch01.int.example.com:50001\",\n\t\t\"tcp://switch02.int.example.com:50001\",\n\t}}\n\n\tdeviceURL1, err := url.Parse(l.Servers[0])\n\tif err != nil {\n\t\tt.Fail()\n\t}\n\tdeviceURL2, err := url.Parse(l.Servers[1])\n\tif err != nil {\n\t\tt.Fail()\n\t}\n\n\tvar acc testutil.Accumulator\n\tmsgToAccumulator(&acc, testProtoBufCongestionRecord1, deviceURL1)\n\tacc.Wait(1)\n\n\tvals1 := map[string]interface{}{\n\t\t\"timestamp\":        int64(100000000000000),\n\t\t\"queue_size\":       int64(1),\n\t\t\"time_of_max_qlen\": int64(100000000000000),\n\t\t\"tx_latency\":       int64(100),\n\t\t\"q_drop_count\":     int64(1),\n\t}\n\ttags1 := map[string]string{\n\t\t\"intf_name\":             \"eth1\",\n\t\t\"switch_id\":             strconv.FormatInt(int64(1), 10),\n\t\t\"port_id\":               strconv.FormatInt(int64(1), 10),\n\t\t\"entry_type\":            strconv.FormatInt(int64(1), 10),\n\t\t\"traffic_class\":         strconv.FormatInt(int64(1), 10),\n\t\t\"fabric_peer_intf_name\": \"FabricPeerIntfName1\",\n\t\t\"source\":                \"switch01.int.example.com\",\n\t\t\"port\":                  \"50001\",\n\t}\n\n\tacc.AssertContainsFields(t, \"lanz_congestion_record\", vals1)\n\tacc.AssertContainsTaggedFields(t, \"lanz_congestion_record\", vals1, tags1)\n\n\tacc.ClearMetrics()\n\tmsgToAccumulator(&acc, testProtoBufCongestionRecord2, deviceURL2)\n\tacc.Wait(1)\n\n\tvals2 := map[string]interface{}{\n\t\t\"timestamp\":        int64(200000000000000),\n\t\t\"queue_size\":       int64(2),\n\t\t\"time_of_max_qlen\": int64(200000000000000),\n\t\t\"tx_latency\":       int64(200),\n\t\t\"q_drop_count\":     int64(2),\n\t}\n\ttags2 := map[string]string{\n\t\t\"intf_name\":             \"eth2\",\n\t\t\"switch_id\":             strconv.FormatInt(int64(2), 10),\n\t\t\"port_id\":               strconv.FormatInt(int64(2), 10),\n\t\t\"entry_type\":            strconv.FormatInt(int64(2), 10),\n\t\t\"traffic_class\":         strconv.FormatInt(int64(2), 10),\n\t\t\"fabric_peer_intf_name\": \"FabricPeerIntfName2\",\n\t\t\"source\":                \"switch02.int.example.com\",\n\t\t\"port\":                  \"50001\",\n\t}\n\n\tacc.AssertContainsFields(t, \"lanz_congestion_record\", vals2)\n\tacc.AssertContainsTaggedFields(t, \"lanz_congestion_record\", vals2, tags2)\n\n\tacc.ClearMetrics()\n\tmsgToAccumulator(&acc, testProtoBufGlobalBufferUsageRecord, deviceURL1)\n\tacc.Wait(1)\n\n\tgburVals1 := map[string]interface{}{\n\t\t\"timestamp\":   int64(100000000000000),\n\t\t\"buffer_size\": int64(1),\n\t\t\"duration\":    int64(10),\n\t}\n\tgburTags1 := map[string]string{\n\t\t\"entry_type\": strconv.FormatInt(int64(1), 10),\n\t\t\"source\":     \"switch01.int.example.com\",\n\t\t\"port\":       \"50001\",\n\t}\n\n\tacc.AssertContainsFields(t, \"lanz_global_buffer_usage_record\", gburVals1)\n\tacc.AssertContainsTaggedFields(t, \"lanz_global_buffer_usage_record\", gburVals1, gburTags1)\n}\n"
  },
  {
    "path": "plugins/inputs/lanz/sample.conf",
    "content": "# Read metrics off Arista LANZ, via socket\n[[inputs.lanz]]\n  ## URL to Arista LANZ endpoint\n  servers = [\n    \"tcp://switch1.int.example.com:50001\",\n    \"tcp://switch2.int.example.com:50001\",\n  ]\n"
  },
  {
    "path": "plugins/inputs/ldap/389ds.go",
    "content": "package ldap\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-ldap/ldap/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\n// Empty mappings are identity mappings\nvar attrMap389ds = map[string]string{\n\t\"addentryops\":                    \"add_operations\",\n\t\"anonymousbinds\":                 \"anonymous_binds\",\n\t\"bindsecurityerrors\":             \"bind_security_errors\",\n\t\"bytesrecv\":                      \"bytes_received\",\n\t\"bytessent\":                      \"bytes_sent\",\n\t\"cacheentries\":                   \"cache_entries\",\n\t\"cachehits\":                      \"cache_hits\",\n\t\"chainings\":                      \"\",\n\t\"compareops\":                     \"compare_operations\",\n\t\"connections\":                    \"\",\n\t\"connectionsinmaxthreads\":        \"connections_in_max_threads\",\n\t\"connectionsmaxthreadscount\":     \"connections_max_threads\",\n\t\"copyentries\":                    \"copy_entries\",\n\t\"currentconnections\":             \"current_connections\",\n\t\"currentconnectionsatmaxthreads\": \"current_connections_at_max_threads\",\n\t\"dtablesize\":                     \"\",\n\t\"entriesreturned\":                \"entries_returned\",\n\t\"entriessent\":                    \"entries_sent\",\n\t\"errors\":                         \"\",\n\t\"inops\":                          \"in_operations\",\n\t\"listops\":                        \"list_operations\",\n\t\"removeentryops\":                 \"delete_operations\",\n\t\"masterentries\":                  \"master_entries\",\n\t\"maxthreadsperconnhits\":          \"maxthreads_per_conn_hits\",\n\t\"modifyentryops\":                 \"modify_operations\",\n\t\"modifyrdnops\":                   \"modrdn_operations\",\n\t\"nbackends\":                      \"backends\",\n\t\"onelevelsearchops\":              \"onelevel_search_operations\",\n\t\"opscompleted\":                   \"operations_completed\",\n\t\"opsinitiated\":                   \"operations_initiated\",\n\t\"readops\":                        \"read_operations\",\n\t\"readwaiters\":                    \"read_waiters\",\n\t\"referrals\":                      \"referrals\",\n\t\"referralsreturned\":              \"referrals_returned\",\n\t\"searchops\":                      \"search_operations\",\n\t\"securityerrors\":                 \"security_errors\",\n\t\"simpleauthbinds\":                \"simpleauth_binds\",\n\t\"slavehits\":                      \"slave_hits\",\n\t\"strongauthbinds\":                \"strongauth_binds\",\n\t\"threads\":                        \"\",\n\t\"totalconnections\":               \"total_connections\",\n\t\"unauthbinds\":                    \"unauth_binds\",\n\t\"wholesubtreesearchops\":          \"wholesubtree_search_operations\",\n}\n\nfunc (l *LDAP) new389dsConfig() []request {\n\tattributes := make([]string, 0, len(attrMap389ds))\n\tfor k := range attrMap389ds {\n\t\tattributes = append(attributes, k)\n\t}\n\n\treq := ldap.NewSearchRequest(\n\t\t\"cn=Monitor\",\n\t\tldap.ScopeWholeSubtree,\n\t\tldap.NeverDerefAliases,\n\t\t0,\n\t\t0,\n\t\tfalse,\n\t\t\"(objectClass=*)\",\n\t\tattributes,\n\t\tnil,\n\t)\n\treturn []request{{req, l.convert389ds}}\n}\n\nfunc (l *LDAP) convert389ds(result *ldap.SearchResult, ts time.Time) []telegraf.Metric {\n\tfields := make(map[string]interface{})\n\tfor _, entry := range result.Entries {\n\t\tfor _, attr := range entry.Attributes {\n\t\t\tif len(attr.Values[0]) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Map the attribute-name to the field-name\n\t\t\tname := attrMap389ds[attr.Name]\n\t\t\tif name == \"\" {\n\t\t\t\tname = attr.Name\n\t\t\t}\n\t\t\t// Reverse the name if requested\n\t\t\tif l.ReverseFieldNames {\n\t\t\t\tparts := strings.Split(name, \"_\")\n\t\t\t\tfor i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {\n\t\t\t\t\tparts[i], parts[j] = parts[j], parts[i]\n\t\t\t\t}\n\t\t\t\tname = strings.Join(parts, \"_\")\n\t\t\t}\n\n\t\t\t// Convert the number\n\t\t\tif v, err := strconv.ParseInt(attr.Values[0], 10, 64); err == nil {\n\t\t\t\tfields[name] = v\n\t\t\t}\n\t\t}\n\t}\n\n\tm := metric.New(\"389ds\", l.tags, fields, ts)\n\treturn []telegraf.Metric{m}\n}\n"
  },
  {
    "path": "plugins/inputs/ldap/README.md",
    "content": "# LDAP Input Plugin\n\nThis plugin gathers metrics from LDAP servers' monitoring (`cn=Monitor`)\nbackend. Currently this plugin supports [OpenLDAP][openldap] and [389ds][389ds]\nservers.\n\n⭐ Telegraf v1.29.0\n🏷️ network, server\n💻 all\n\n[openldap]: https://www.openldap.org/\n[389ds]: https://www.port389.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# LDAP monitoring plugin\n[[inputs.ldap]]\n  ## Server to monitor\n  ## The scheme determines the mode to use for connection with\n  ##    ldap://...      -- unencrypted (non-TLS) connection\n  ##    ldaps://...     -- TLS connection\n  ##    starttls://...  --  StartTLS connection\n  ##    ldapi://...     -- UNIX socket connection\n  ## If no port is given, the default ports, 389 for ldap and starttls and\n  ## 636 for ldaps, are used, there is no port on UNIX sockets.\n  server = \"ldap://localhost\"\n\n  ## Server dialect, can be \"openldap\" or \"389ds\"\n  # dialect = \"openldap\"\n\n  # What sort of Bind to use\n  ## Empty or \"simple\" means to use a simple LDAP bind, otherwise use a\n  ## specified SASL mechanism (only EXTERNAL currently supported - for TLS\n  ## client certs or UNIX credentials)\n  # bind_mechanism = \"simple\"\n\n  # DN and password to bind with\n  ## If bind_dn is empty an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  ## Reverse the field names constructed from the monitoring DN\n  # reverse_field_names = false\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\nTo use this plugin you must enable the monitoring backend/plugin of your LDAP\nserver. See [OpenLDAP][openldap_monitoring] or [389ds][389ds] documentation for\ndetails.\n\n[openldap_monitoring]: https://www.openldap.org/devel/admin/monitoringslapd.html\n\n## Metrics\n\nDepending on the server dialect, different metrics are produced. The metrics\nare usually named according to the selected dialect.\n\n### Tags\n\n- server -- Server name or IP (except for Unix socket)\n- port   -- Port used for connecting (except for Unix socket)\n- path   -- Path used to connect (when connecting over a Unix socket)\n\n## Example Output\n\nUsing the `openldap` dialect\n\n```text\nopenldap,server=localhost,port=389 operations_completed=63i,operations_initiated=98i,operations_bind_initiated=10i,operations_unbind_initiated=6i,operations_modrdn_completed=0i,operations_delete_initiated=0i,operations_add_completed=2i,operations_delete_completed=0i,operations_abandon_completed=0i,statistics_entries=1516i,threads_open=2i,threads_active=1i,waiters_read=1i,operations_modify_completed=0i,operations_extended_initiated=4i,threads_pending=0i,operations_search_initiated=36i,operations_compare_initiated=0i,connections_max_file_descriptors=4096i,operations_modify_initiated=0i,operations_modrdn_initiated=0i,threads_max=16i,time_uptime=6017i,connections_total=1037i,connections_current=1i,operations_add_initiated=2i,statistics_bytes=162071i,operations_unbind_completed=6i,operations_abandon_initiated=0i,statistics_pdu=1566i,threads_max_pending=0i,threads_backload=1i,waiters_write=0i,operations_bind_completed=10i,operations_search_completed=35i,operations_compare_completed=0i,operations_extended_completed=4i,statistics_referrals=0i,threads_starting=0i 1516912070000000000\n```\n\nUsing the `389ds` dialect\n\n```text\n389ds,port=32805,server=localhost add_operations=0i,anonymous_binds=0i,backends=0i,bind_security_errors=0i,bytes_received=0i,bytes_sent=256i,cache_entries=0i,cache_hits=0i,chainings=0i,compare_operations=0i,connections=1i,connections_in_max_threads=0i,connections_max_threads=0i,copy_entries=0i,current_connections=1i,current_connections_at_max_threads=0i,delete_operations=0i,dtablesize=63936i,entries_returned=2i,entries_sent=2i,errors=2i,in_operations=11i,list_operations=0i,maxthreads_per_conn_hits=0i,modify_operations=1i,modrdn_operations=0i,onelevel_search_operations=0i,operations_completed=10i,operations_initiated=11i,read_operations=0i,read_waiters=0i,referrals=0i,referrals_returned=0i,search_operations=3i,security_errors=0i,simpleauth_binds=1i,strongauth_binds=2i,threads=17i,total_connections=4i,unauth_binds=0i,wholesubtree_search_operations=1i 1695637234047087280\n```\n"
  },
  {
    "path": "plugins/inputs/ldap/ldap.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage ldap\n\nimport (\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-ldap/ldap/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype LDAP struct {\n\tServer            string        `toml:\"server\"`\n\tDialect           string        `toml:\"dialect\"`\n\tBindMech          string        `toml:\"bind_mechanism\"`\n\tBindDn            string        `toml:\"bind_dn\"`\n\tBindPassword      config.Secret `toml:\"bind_password\"`\n\tReverseFieldNames bool          `toml:\"reverse_field_names\"`\n\tcommon_tls.ClientConfig\n\n\ttlsCfg   *tls.Config\n\trequests []request\n\tmode     string\n\thost     string\n\tport     string\n\ttags     map[string]string\n}\n\ntype request struct {\n\tquery   *ldap.SearchRequest\n\tconvert func(*ldap.SearchResult, time.Time) []telegraf.Metric\n}\n\nfunc (*LDAP) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *LDAP) Init() error {\n\tif l.Server == \"\" {\n\t\tl.Server = \"ldap://localhost:389\"\n\t}\n\tdialURL := l.Server\n\n\tvar hostname string\n\t// Work around net/url not accepting %2f in the \"host\" part\n\t// https://github.com/go-ldap/ldap/issues/564\n\tldapiChunk, isLdapi := strings.CutPrefix(l.Server, \"ldapi://\")\n\tif isLdapi {\n\t\tvar err error\n\t\thost, rest, _ := strings.Cut(ldapiChunk, \"/\")\n\t\tif rest != \"\" {\n\t\t\treturn fmt.Errorf(\"extra parameters in LDAP URI: %q\", l.Server)\n\t\t}\n\n\t\thostname, err = url.PathUnescape(host)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing server failed: %w\", err)\n\t\t}\n\t\tdialURL = \"ldapi://\"\n\t}\n\n\tu, err := url.Parse(dialURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing server failed: %w\", err)\n\t}\n\n\t// Verify the server setting and set the defaults\n\tvar tlsEnable bool\n\tswitch u.Scheme {\n\tcase \"ldap\":\n\t\tif u.Port() == \"\" {\n\t\t\tu.Host = u.Host + \":389\"\n\t\t}\n\t\ttlsEnable = false\n\tcase \"ldapi\":\n\t\t// Prepare a form that can be appended to an ldapi:// string for now\n\t\tu.Path = hostname\n\t\tu.Host = u.EscapedPath()\n\tcase \"starttls\":\n\t\tif u.Port() == \"\" {\n\t\t\tu.Host = u.Host + \":389\"\n\t\t}\n\t\ttlsEnable = true\n\tcase \"ldaps\":\n\t\tif u.Port() == \"\" {\n\t\t\tu.Host = u.Host + \":636\"\n\t\t}\n\t\ttlsEnable = true\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid scheme: %q\", u.Scheme)\n\t}\n\tl.mode = u.Scheme\n\tl.Server = u.Host\n\tl.host, l.port = u.Hostname(), u.Port()\n\n\tswitch l.BindMech {\n\tcase \"\", \"simple\":\n\t\tl.BindMech = \"SIMPLE\"\n\tcase \"SIMPLE\", \"EXTERNAL\":\n\t\t// Pass: Valid and implemented\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported bind type: %s\", l.BindMech)\n\t}\n\n\t// Force TLS depending on the selected mode\n\tl.ClientConfig.Enable = &tlsEnable\n\n\t// Setup TLS configuration\n\ttlsCfg, err := l.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating TLS config failed: %w\", err)\n\t}\n\tl.tlsCfg = tlsCfg\n\n\t// Initialize the search request(s)\n\tswitch l.Dialect {\n\tcase \"\", \"openldap\":\n\t\tl.requests = l.newOpenLDAPConfig()\n\tcase \"389ds\":\n\t\tl.requests = l.new389dsConfig()\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid dialect %q\", l.Dialect)\n\t}\n\n\tif l.mode == \"ldapi\" {\n\t\tl.tags = map[string]string{\n\t\t\t\"path\": hostname,\n\t\t}\n\t} else {\n\t\tl.tags = map[string]string{\n\t\t\t\"server\": l.host,\n\t\t\t\"port\":   l.port,\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *LDAP) Gather(acc telegraf.Accumulator) error {\n\t// Connect\n\tconn, err := l.connect()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"connection failed: %w\", err)\n\t}\n\tdefer conn.Close()\n\n\t// Query the server\n\tfor _, req := range l.requests {\n\t\tnow := time.Now()\n\t\tresult, err := conn.Search(req.query)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Collect metrics\n\t\tfor _, m := range req.convert(result, now) {\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *LDAP) connect() (*ldap.Conn, error) {\n\tvar conn *ldap.Conn\n\tswitch l.mode {\n\tcase \"ldap\":\n\t\tvar err error\n\t\tconn, err = ldap.DialURL(\"ldap://\" + l.Server)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase \"ldapi\":\n\t\tvar err error\n\t\tconn, err = ldap.DialURL(\"ldapi://\" + l.Server)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase \"ldaps\":\n\t\tvar err error\n\t\tconn, err = ldap.DialURL(\"ldaps://\"+l.Server, ldap.DialWithTLSConfig(l.tlsCfg))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase \"starttls\":\n\t\tvar err error\n\t\tconn, err = ldap.DialURL(\"ldap://\" + l.Server)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := conn.StartTLS(l.tlsCfg); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid tls_mode: %s\", l.mode)\n\t}\n\n\tif l.BindMech == \"EXTERNAL\" {\n\t\tif err := conn.ExternalBind(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"binding with EXTERNAL mech failed: %w\", err)\n\t\t}\n\t\treturn conn, nil\n\t}\n\n\tif l.BindDn == \"\" && l.BindPassword.Empty() {\n\t\treturn conn, nil\n\t}\n\n\t// Bind username and password\n\tpasswd, err := l.BindPassword.Get()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer passwd.Destroy()\n\n\tif err := conn.Bind(l.BindDn, passwd.String()); err != nil {\n\t\treturn nil, fmt.Errorf(\"binding credentials failed: %w\", err)\n\t}\n\n\treturn conn, nil\n}\n\nfunc init() {\n\tinputs.Add(\"ldap\", func() telegraf.Input { return &LDAP{} })\n}\n"
  },
  {
    "path": "plugins/inputs/ldap/ldap_test.go",
    "content": "package ldap\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/go-ldap/ldap/v3\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tservicePortOpenLDAP       = \"1389\"\n\tservicePortOpenLDAPSecure = \"1636\"\n\n\tservicePort389DS       = \"3389\"\n\tservicePort389DSSecure = \"3636\"\n)\n\nfunc TestMockResult(t *testing.T) {\n\t// mock a query result\n\tmockSearchResult := &ldap.SearchResult{\n\t\tEntries: []*ldap.Entry{\n\t\t\t{\n\t\t\t\tDN:         \"cn=Total,cn=Connections,cn=Monitor\",\n\t\t\t\tAttributes: []*ldap.EntryAttribute{{Name: \"monitorCounter\", Values: []string{\"1\"}}},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Setup the plugin\n\tplugin := &LDAP{}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": \"localhost\",\n\t\t\t\t\"port\":   \"389\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total_connections\": int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Retrieve the converter\n\trequests := plugin.newOpenLDAPConfig()\n\trequire.Len(t, requests, 1)\n\tconverter := requests[0].convert\n\trequire.NotNil(t, converter)\n\n\t// Test metric conversion\n\tactual := converter(mockSearchResult, time.Unix(0, 0))\n\ttestutil.RequireMetricsEqual(t, expected, actual)\n}\n\nfunc TestMockLDAPI(t *testing.T) {\n\t// mock a query result\n\tmockSearchResult := &ldap.SearchResult{\n\t\tEntries: []*ldap.Entry{\n\t\t\t{\n\t\t\t\tDN:         \"cn=Total,cn=Connections,cn=Monitor\",\n\t\t\t\tAttributes: []*ldap.EntryAttribute{{Name: \"monitorCounter\", Values: []string{\"1\"}}},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Setup the plugin\n\tplugin := &LDAP{\n\t\tServer: \"ldapi://%2Ftmp%2Fsocket%3F\",\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"path\": \"/tmp/socket?\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total_connections\": int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Retrieve the converter\n\trequests := plugin.newOpenLDAPConfig()\n\trequire.Len(t, requests, 1)\n\tconverter := requests[0].convert\n\trequire.NotNil(t, converter)\n\n\t// Test metric conversion\n\tactual := converter(mockSearchResult, time.Unix(0, 0))\n\ttestutil.RequireMetricsEqual(t, expected, actual)\n}\n\nfunc TestLdapiURLHandling(t *testing.T) {\n\t// Setup the plugin\n\tplugin := &LDAP{\n\t\tServer: \"ldapi://%2Ftmp%2Fsocket%3F\",\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Test the resulting setting\n\trequire.Equal(t, \"/tmp/socket%3F\", plugin.host)\n\trequire.Empty(t, plugin.port)\n}\n\nfunc TestInvalidTLSMode(t *testing.T) {\n\tplugin := &LDAP{\n\t\tServer: \"foo://localhost\",\n\t}\n\trequire.ErrorContains(t, plugin.Init(), \"invalid scheme\")\n}\n\nfunc TestNoConnection(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Setup the plugin\n\tplugin := &LDAP{Server: \"ldap://nosuchhost\"}\n\trequire.NoError(t, plugin.Init())\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, plugin.Gather(&acc), \"connection failed\")\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n}\n\nfunc TestOpenLDAPIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortOpenLDAP},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortOpenLDAP)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[servicePortOpenLDAP]\n\tplugin := &LDAP{\n\t\tServer:       \"ldap://\" + container.Address + \":\" + port,\n\t\tBindDn:       \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword: config.NewSecret([]byte(\"secret\")),\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": container.Address,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"abandon_operations_completed\":     int64(0),\n\t\t\t\t\"abandon_operations_initiated\":     int64(0),\n\t\t\t\t\"active_threads\":                   int64(0),\n\t\t\t\t\"add_operations_completed\":         int64(0),\n\t\t\t\t\"add_operations_initiated\":         int64(0),\n\t\t\t\t\"backload_threads\":                 int64(0),\n\t\t\t\t\"bind_operations_completed\":        int64(0),\n\t\t\t\t\"bind_operations_initiated\":        int64(0),\n\t\t\t\t\"bytes_statistics\":                 int64(0),\n\t\t\t\t\"compare_operations_completed\":     int64(0),\n\t\t\t\t\"compare_operations_initiated\":     int64(0),\n\t\t\t\t\"current_connections\":              int64(0),\n\t\t\t\t\"delete_operations_completed\":      int64(0),\n\t\t\t\t\"delete_operations_initiated\":      int64(0),\n\t\t\t\t\"entries_statistics\":               int64(0),\n\t\t\t\t\"extended_operations_completed\":    int64(0),\n\t\t\t\t\"extended_operations_initiated\":    int64(0),\n\t\t\t\t\"max_file_descriptors_connections\": int64(0),\n\t\t\t\t\"max_pending_threads\":              int64(0),\n\t\t\t\t\"max_threads\":                      int64(0),\n\t\t\t\t\"modify_operations_completed\":      int64(0),\n\t\t\t\t\"modify_operations_initiated\":      int64(0),\n\t\t\t\t\"modrdn_operations_completed\":      int64(0),\n\t\t\t\t\"modrdn_operations_initiated\":      int64(0),\n\t\t\t\t\"open_threads\":                     int64(0),\n\t\t\t\t\"operations_completed\":             int64(0),\n\t\t\t\t\"operations_initiated\":             int64(0),\n\t\t\t\t\"pdu_statistics\":                   int64(0),\n\t\t\t\t\"pending_threads\":                  int64(0),\n\t\t\t\t\"read_waiters\":                     int64(0),\n\t\t\t\t\"referrals_statistics\":             int64(0),\n\t\t\t\t\"search_operations_completed\":      int64(0),\n\t\t\t\t\"search_operations_initiated\":      int64(0),\n\t\t\t\t\"starting_threads\":                 int64(0),\n\t\t\t\t\"total_connections\":                int64(0),\n\t\t\t\t\"unbind_operations_completed\":      int64(0),\n\t\t\t\t\"unbind_operations_initiated\":      int64(0),\n\t\t\t\t\"uptime_time\":                      int64(0),\n\t\t\t\t\"write_waiters\":                    int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestOpenLDAPReverseDNIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortOpenLDAP},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortOpenLDAP)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[servicePortOpenLDAP]\n\tplugin := &LDAP{\n\t\tServer:            \"ldap://\" + container.Address + \":\" + port,\n\t\tBindDn:            \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword:      config.NewSecret([]byte(\"secret\")),\n\t\tReverseFieldNames: true,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": container.Address,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"connections_max_file_descriptors\": int64(0),\n\t\t\t\t\"connections_total\":                int64(0),\n\t\t\t\t\"connections_current\":              int64(0),\n\t\t\t\t\"operations_bind_initiated\":        int64(0),\n\t\t\t\t\"operations_bind_completed\":        int64(0),\n\t\t\t\t\"operations_completed\":             int64(0),\n\t\t\t\t\"operations_initiated\":             int64(0),\n\t\t\t\t\"operations_unbind_initiated\":      int64(0),\n\t\t\t\t\"operations_unbind_completed\":      int64(0),\n\t\t\t\t\"operations_search_initiated\":      int64(0),\n\t\t\t\t\"operations_search_completed\":      int64(0),\n\t\t\t\t\"operations_compare_initiated\":     int64(0),\n\t\t\t\t\"operations_compare_completed\":     int64(0),\n\t\t\t\t\"operations_modify_initiated\":      int64(0),\n\t\t\t\t\"operations_modify_completed\":      int64(0),\n\t\t\t\t\"operations_modrdn_initiated\":      int64(0),\n\t\t\t\t\"operations_modrdn_completed\":      int64(0),\n\t\t\t\t\"operations_add_initiated\":         int64(0),\n\t\t\t\t\"operations_add_completed\":         int64(0),\n\t\t\t\t\"operations_delete_initiated\":      int64(0),\n\t\t\t\t\"operations_delete_completed\":      int64(0),\n\t\t\t\t\"operations_abandon_initiated\":     int64(0),\n\t\t\t\t\"operations_abandon_completed\":     int64(0),\n\t\t\t\t\"operations_extended_initiated\":    int64(0),\n\t\t\t\t\"operations_extended_completed\":    int64(0),\n\t\t\t\t\"statistics_bytes\":                 int64(0),\n\t\t\t\t\"statistics_pdu\":                   int64(0),\n\t\t\t\t\"statistics_entries\":               int64(0),\n\t\t\t\t\"statistics_referrals\":             int64(0),\n\t\t\t\t\"threads_max\":                      int64(0),\n\t\t\t\t\"threads_max_pending\":              int64(0),\n\t\t\t\t\"threads_open\":                     int64(0),\n\t\t\t\t\"threads_starting\":                 int64(0),\n\t\t\t\t\"threads_active\":                   int64(0),\n\t\t\t\t\"threads_pending\":                  int64(0),\n\t\t\t\t\"threads_backload\":                 int64(0),\n\t\t\t\t\"time_uptime\":                      int64(0),\n\t\t\t\t\"waiters_read\":                     int64(0),\n\t\t\t\t\"waiters_write\":                    int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestOpenLDAPStartTLSIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Setup PKI for TLS testing\n\tpkiPaths, err := testutil.NewPKI(\"../../../testutil/pki\").AbsolutePaths()\n\trequire.NoError(t, err)\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortOpenLDAP},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t\t\"LDAP_ENABLE_TLS\":     \"yes\",\n\t\t\t\"LDAP_TLS_CA_FILE\":    \"server.pem\",\n\t\t\t\"LDAP_TLS_CERT_FILE\":  \"server.crt\",\n\t\t\t\"LDAP_TLS_KEY_FILE\":   \"server.key\",\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/server.pem\": pkiPaths.ServerPem,\n\t\t\t\"/server.crt\": pkiPaths.ServerCert,\n\t\t\t\"/server.key\": pkiPaths.ServerKey,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortOpenLDAP)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[servicePortOpenLDAP]\n\tplugin := &LDAP{\n\t\tServer:       \"starttls://\" + container.Address + \":\" + port,\n\t\tBindDn:       \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword: config.NewSecret([]byte(\"secret\")),\n\t\tClientConfig: common_tls.ClientConfig{\n\t\t\tTLSCA:              pkiPaths.ClientCert,\n\t\t\tInsecureSkipVerify: true,\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": container.Address,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"abandon_operations_completed\":     int64(0),\n\t\t\t\t\"abandon_operations_initiated\":     int64(0),\n\t\t\t\t\"active_threads\":                   int64(0),\n\t\t\t\t\"add_operations_completed\":         int64(0),\n\t\t\t\t\"add_operations_initiated\":         int64(0),\n\t\t\t\t\"backload_threads\":                 int64(0),\n\t\t\t\t\"bind_operations_completed\":        int64(0),\n\t\t\t\t\"bind_operations_initiated\":        int64(0),\n\t\t\t\t\"bytes_statistics\":                 int64(0),\n\t\t\t\t\"compare_operations_completed\":     int64(0),\n\t\t\t\t\"compare_operations_initiated\":     int64(0),\n\t\t\t\t\"current_connections\":              int64(0),\n\t\t\t\t\"delete_operations_completed\":      int64(0),\n\t\t\t\t\"delete_operations_initiated\":      int64(0),\n\t\t\t\t\"entries_statistics\":               int64(0),\n\t\t\t\t\"extended_operations_completed\":    int64(0),\n\t\t\t\t\"extended_operations_initiated\":    int64(0),\n\t\t\t\t\"max_file_descriptors_connections\": int64(0),\n\t\t\t\t\"max_pending_threads\":              int64(0),\n\t\t\t\t\"max_threads\":                      int64(0),\n\t\t\t\t\"modify_operations_completed\":      int64(0),\n\t\t\t\t\"modify_operations_initiated\":      int64(0),\n\t\t\t\t\"modrdn_operations_completed\":      int64(0),\n\t\t\t\t\"modrdn_operations_initiated\":      int64(0),\n\t\t\t\t\"open_threads\":                     int64(0),\n\t\t\t\t\"operations_completed\":             int64(0),\n\t\t\t\t\"operations_initiated\":             int64(0),\n\t\t\t\t\"pdu_statistics\":                   int64(0),\n\t\t\t\t\"pending_threads\":                  int64(0),\n\t\t\t\t\"read_waiters\":                     int64(0),\n\t\t\t\t\"referrals_statistics\":             int64(0),\n\t\t\t\t\"search_operations_completed\":      int64(0),\n\t\t\t\t\"search_operations_initiated\":      int64(0),\n\t\t\t\t\"starting_threads\":                 int64(0),\n\t\t\t\t\"total_connections\":                int64(0),\n\t\t\t\t\"unbind_operations_completed\":      int64(0),\n\t\t\t\t\"unbind_operations_initiated\":      int64(0),\n\t\t\t\t\"uptime_time\":                      int64(0),\n\t\t\t\t\"write_waiters\":                    int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestOpenLDAPLDAPSIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Setup PKI for TLS testing\n\tpkiPaths, err := testutil.NewPKI(\"../../../testutil/pki\").AbsolutePaths()\n\trequire.NoError(t, err)\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortOpenLDAPSecure},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t\t\"LDAP_ENABLE_TLS\":     \"yes\",\n\t\t\t\"LDAP_TLS_CA_FILE\":    \"server.pem\",\n\t\t\t\"LDAP_TLS_CERT_FILE\":  \"server.crt\",\n\t\t\t\"LDAP_TLS_KEY_FILE\":   \"server.key\",\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/server.pem\": pkiPaths.ServerPem,\n\t\t\t\"/server.crt\": pkiPaths.ServerCert,\n\t\t\t\"/server.key\": pkiPaths.ServerKey,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortOpenLDAPSecure)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[servicePortOpenLDAPSecure]\n\tplugin := &LDAP{\n\t\tServer:       \"ldaps://\" + container.Address + \":\" + port,\n\t\tBindDn:       \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword: config.NewSecret([]byte(\"secret\")),\n\t\tClientConfig: common_tls.ClientConfig{\n\t\t\tInsecureSkipVerify: true,\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"openldap\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": container.Address,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"abandon_operations_completed\":     int64(0),\n\t\t\t\t\"abandon_operations_initiated\":     int64(0),\n\t\t\t\t\"active_threads\":                   int64(0),\n\t\t\t\t\"add_operations_completed\":         int64(0),\n\t\t\t\t\"add_operations_initiated\":         int64(0),\n\t\t\t\t\"backload_threads\":                 int64(0),\n\t\t\t\t\"bind_operations_completed\":        int64(0),\n\t\t\t\t\"bind_operations_initiated\":        int64(0),\n\t\t\t\t\"bytes_statistics\":                 int64(0),\n\t\t\t\t\"compare_operations_completed\":     int64(0),\n\t\t\t\t\"compare_operations_initiated\":     int64(0),\n\t\t\t\t\"current_connections\":              int64(0),\n\t\t\t\t\"delete_operations_completed\":      int64(0),\n\t\t\t\t\"delete_operations_initiated\":      int64(0),\n\t\t\t\t\"entries_statistics\":               int64(0),\n\t\t\t\t\"extended_operations_completed\":    int64(0),\n\t\t\t\t\"extended_operations_initiated\":    int64(0),\n\t\t\t\t\"max_file_descriptors_connections\": int64(0),\n\t\t\t\t\"max_pending_threads\":              int64(0),\n\t\t\t\t\"max_threads\":                      int64(0),\n\t\t\t\t\"modify_operations_completed\":      int64(0),\n\t\t\t\t\"modify_operations_initiated\":      int64(0),\n\t\t\t\t\"modrdn_operations_completed\":      int64(0),\n\t\t\t\t\"modrdn_operations_initiated\":      int64(0),\n\t\t\t\t\"open_threads\":                     int64(0),\n\t\t\t\t\"operations_completed\":             int64(0),\n\t\t\t\t\"operations_initiated\":             int64(0),\n\t\t\t\t\"pdu_statistics\":                   int64(0),\n\t\t\t\t\"pending_threads\":                  int64(0),\n\t\t\t\t\"read_waiters\":                     int64(0),\n\t\t\t\t\"referrals_statistics\":             int64(0),\n\t\t\t\t\"search_operations_completed\":      int64(0),\n\t\t\t\t\"search_operations_initiated\":      int64(0),\n\t\t\t\t\"starting_threads\":                 int64(0),\n\t\t\t\t\"total_connections\":                int64(0),\n\t\t\t\t\"unbind_operations_completed\":      int64(0),\n\t\t\t\t\"unbind_operations_initiated\":      int64(0),\n\t\t\t\t\"uptime_time\":                      int64(0),\n\t\t\t\t\"write_waiters\":                    int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc Test389dsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container\n\tcontainer := testutil.Container{\n\t\tImage:        \"389ds/dirsrv\",\n\t\tExposedPorts: []string{servicePort389DS},\n\t\tEnv: map[string]string{\n\t\t\t\"DS_DM_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"389-ds-container started\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort389DS)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tport := container.Ports[servicePort389DS]\n\tplugin := &LDAP{\n\t\tServer:       \"ldap://\" + container.Address + \":\" + port,\n\t\tDialect:      \"389ds\",\n\t\tBindDn:       \"cn=Directory Manager\",\n\t\tBindPassword: config.NewSecret([]byte(\"secret\")),\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Setup the expectations\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"389ds\",\n\t\t\tmap[string]string{\n\t\t\t\t\"server\": container.Address,\n\t\t\t\t\"port\":   port,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"add_operations\":                     int64(0),\n\t\t\t\t\"anonymous_binds\":                    int64(0),\n\t\t\t\t\"backends\":                           int64(0),\n\t\t\t\t\"bind_security_errors\":               int64(0),\n\t\t\t\t\"bytes_received\":                     int64(0),\n\t\t\t\t\"bytes_sent\":                         int64(0),\n\t\t\t\t\"cache_entries\":                      int64(0),\n\t\t\t\t\"cache_hits\":                         int64(0),\n\t\t\t\t\"chainings\":                          int64(0),\n\t\t\t\t\"compare_operations\":                 int64(0),\n\t\t\t\t\"connections\":                        int64(0),\n\t\t\t\t\"connections_in_max_threads\":         int64(0),\n\t\t\t\t\"connections_max_threads\":            int64(0),\n\t\t\t\t\"copy_entries\":                       int64(0),\n\t\t\t\t\"current_connections\":                int64(0),\n\t\t\t\t\"current_connections_at_max_threads\": int64(0),\n\t\t\t\t\"delete_operations\":                  int64(0),\n\t\t\t\t\"dtablesize\":                         int64(0),\n\t\t\t\t\"entries_returned\":                   int64(0),\n\t\t\t\t\"entries_sent\":                       int64(0),\n\t\t\t\t\"errors\":                             int64(0),\n\t\t\t\t\"in_operations\":                      int64(0),\n\t\t\t\t\"list_operations\":                    int64(0),\n\t\t\t\t\"maxthreads_per_conn_hits\":           int64(0),\n\t\t\t\t\"modify_operations\":                  int64(0),\n\t\t\t\t\"modrdn_operations\":                  int64(0),\n\t\t\t\t\"onelevel_search_operations\":         int64(0),\n\t\t\t\t\"operations_completed\":               int64(0),\n\t\t\t\t\"operations_initiated\":               int64(0),\n\t\t\t\t\"read_operations\":                    int64(0),\n\t\t\t\t\"read_waiters\":                       int64(0),\n\t\t\t\t\"referrals\":                          int64(0),\n\t\t\t\t\"referrals_returned\":                 int64(0),\n\t\t\t\t\"search_operations\":                  int64(0),\n\t\t\t\t\"security_errors\":                    int64(0),\n\t\t\t\t\"simpleauth_binds\":                   int64(0),\n\t\t\t\t\"strongauth_binds\":                   int64(0),\n\t\t\t\t\"threads\":                            int64(0),\n\t\t\t\t\"total_connections\":                  int64(0),\n\t\t\t\t\"unauth_binds\":                       int64(0),\n\t\t\t\t\"wholesubtree_search_operations\":     int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsStructureEqual(t, expected, actual, testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/ldap/openldap.go",
    "content": "package ldap\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-ldap/ldap/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nvar attrMapOpenLDAP = map[string]string{\n\t\"monitorCounter\":     \"\",\n\t\"monitoredInfo\":      \"\",\n\t\"monitorOpInitiated\": \"_initiated\",\n\t\"monitorOpCompleted\": \"_completed\",\n\t\"olmMDBPagesMax\":     \"_mdb_pages_max\",\n\t\"olmMDBPagesUsed\":    \"_mdb_pages_used\",\n\t\"olmMDBPagesFree\":    \"_mdb_pages_free\",\n\t\"olmMDBReadersMax\":   \"_mdb_readers_max\",\n\t\"olmMDBReadersUsed\":  \"_mdb_readers_used\",\n\t\"olmMDBEntries\":      \"_mdb_entries\",\n}\n\nfunc (l *LDAP) newOpenLDAPConfig() []request {\n\treq := ldap.NewSearchRequest(\n\t\t\"cn=Monitor\",\n\t\tldap.ScopeWholeSubtree,\n\t\tldap.NeverDerefAliases,\n\t\t0,\n\t\t0,\n\t\tfalse,\n\t\t\"(|(objectClass=monitorCounterObject)(objectClass=monitorOperation)(objectClass=monitoredObject)(objectClass=monitorContainer))\",\n\t\t[]string{\"monitorCounter\", \"monitorOpInitiated\", \"monitorOpCompleted\", \"monitoredInfo\"},\n\t\tnil,\n\t)\n\treturn []request{{req, l.convertOpenLDAP}}\n}\n\nfunc (l *LDAP) convertOpenLDAP(result *ldap.SearchResult, ts time.Time) []telegraf.Metric {\n\tfields := make(map[string]interface{})\n\tfor _, entry := range result.Entries {\n\t\tprefix := openLDAPAttrConvertDN(entry.DN, l.ReverseFieldNames)\n\t\tfor _, attr := range entry.Attributes {\n\t\t\tif len(attr.Values[0]) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif v, err := strconv.ParseInt(attr.Values[0], 10, 64); err == nil {\n\t\t\t\tfields[prefix+attrMapOpenLDAP[attr.Name]] = v\n\t\t\t}\n\t\t}\n\t}\n\n\tm := metric.New(\"openldap\", l.tags, fields, ts)\n\treturn []telegraf.Metric{m}\n}\n\n// Convert a DN to a field prefix, eg cn=Read,cn=Waiters,cn=Monitor becomes waiters_read\n// Assumes the last part of the DN is cn=Monitor and we want to drop it\nfunc openLDAPAttrConvertDN(dn string, reverse bool) string {\n\t// Normalize DN\n\tprefix := strings.TrimSpace(dn)\n\tprefix = strings.ToLower(prefix)\n\tprefix = strings.ReplaceAll(prefix, \" \", \"_\")\n\tprefix = strings.ReplaceAll(prefix, \"cn=\", \"\")\n\n\t// Filter the base\n\tparts := strings.Split(prefix, \",\")\n\tfor i, p := range parts {\n\t\tif p == \"monitor\" {\n\t\t\tparts = append(parts[:i], parts[i+1:]...)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif reverse {\n\t\tfor i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {\n\t\t\tparts[i], parts[j] = parts[j], parts[i]\n\t\t}\n\t}\n\treturn strings.Join(parts, \"_\")\n}\n"
  },
  {
    "path": "plugins/inputs/ldap/sample.conf",
    "content": "# LDAP monitoring plugin\n[[inputs.ldap]]\n  ## Server to monitor\n  ## The scheme determines the mode to use for connection with\n  ##    ldap://...      -- unencrypted (non-TLS) connection\n  ##    ldaps://...     -- TLS connection\n  ##    starttls://...  --  StartTLS connection\n  ##    ldapi://...     -- UNIX socket connection\n  ## If no port is given, the default ports, 389 for ldap and starttls and\n  ## 636 for ldaps, are used, there is no port on UNIX sockets.\n  server = \"ldap://localhost\"\n\n  ## Server dialect, can be \"openldap\" or \"389ds\"\n  # dialect = \"openldap\"\n\n  # What sort of Bind to use\n  ## Empty or \"simple\" means to use a simple LDAP bind, otherwise use a\n  ## specified SASL mechanism (only EXTERNAL currently supported - for TLS\n  ## client certs or UNIX credentials)\n  # bind_mechanism = \"simple\"\n\n  # DN and password to bind with\n  ## If bind_dn is empty an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  ## Reverse the field names constructed from the monitoring DN\n  # reverse_field_names = false\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/ldap/sample.conf.in",
    "content": "# LDAP monitoring plugin\n[[inputs.ldap]]\n  ## Server to monitor\n  ## The scheme determines the mode to use for connection with\n  ##    ldap://...      -- unencrypted (non-TLS) connection\n  ##    ldaps://...     -- TLS connection\n  ##    starttls://...  --  StartTLS connection\n  ##    ldapi://...     -- UNIX socket connection\n  ## If no port is given, the default ports, 389 for ldap and starttls and\n  ## 636 for ldaps, are used, there is no port on UNIX sockets.\n  server = \"ldap://localhost\"\n\n  ## Server dialect, can be \"openldap\" or \"389ds\"\n  # dialect = \"openldap\"\n\n  # What sort of Bind to use\n  ## Empty or \"simple\" means to use a simple LDAP bind, otherwise use a\n  ## specified SASL mechanism (only EXTERNAL currently supported - for TLS\n  ## client certs or UNIX credentials)\n  # bind_mechanism = \"simple\"\n\n  # DN and password to bind with\n  ## If bind_dn is empty an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  ## Reverse the field names constructed from the monitoring DN\n  # reverse_field_names = false\n\n  ## Optional TLS Config\n{{template \"/plugins/common/tls/client.conf\"}}\n"
  },
  {
    "path": "plugins/inputs/leofs/README.md",
    "content": "# LeoFS Input Plugin\n\nThis plugin gathers metrics of the [LEO filesystem][leofs] services\n_LeoGateway_, _LeoManager_, and _LeoStorage_ via SNMP. Check the\n[LeoFS system monitoring documentation][docs] for details.\n\n⭐ Telegraf v0.1.5\n🏷️ network, server\n💻 all\n\n[leofs]: https://leo-project.net/leofs/\n[docs]: https://leo-project.net/leofs/docs/admin/system_admin/monitoring/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from a LeoFS Server via SNMP\n[[inputs.leofs]]\n  ## An array of URLs of the form:\n  ##   host [ \":\" port]\n  servers = [\"127.0.0.1:4010\"]\n```\n\n## Metrics\n\n### Statistics specific to the internals of LeoManager\n\n#### Erlang VM of LeoManager\n\n- 1 min Statistics\n  - num_of_processes\n  - total_memory_usage\n  - system_memory_usage\n  - processes_memory_usage\n  - ets_memory_usage\n  - used_allocated_memory\n  - allocated_memory\n- 5 min Statistics\n  - num_of_processes_5min\n  - total_memory_usage_5min\n  - system_memory_usage_5min\n  - processes_memory_usage_5min\n  - ets_memory_usage_5min\n  - used_allocated_memory_5min\n  - allocated_memory_5min\n\n### Statistics specific to the internals of LeoStorage\n\n### Erlang VM of LeoStorage\n\n- 1 min Statistics\n  - num_of_processes\n  - total_memory_usage\n  - system_memory_usage\n  - processes_memory_usage\n  - ets_memory_usage\n  - used_allocated_memory\n  - allocated_memory\n- 5 min Statistics\n  - num_of_processes_5min\n  - total_memory_usage_5min\n  - system_memory_usage_5min\n  - processes_memory_usage_5min\n  - ets_memory_usage_5min\n  - used_allocated_memory_5min\n  - allocated_memory_5min\n\n### Total Number of Requests for LeoStorage\n\n- 1 min Statistics\n  - num_of_writes\n  - num_of_reads\n  - num_of_deletes\n- 5 min Statistics\n  - num_of_writes_5min\n  - num_of_reads_5min\n  - num_of_deletes_5min\n\n#### Total Number of Objects and Total Size of Objects\n\n- num_of_active_objects\n- total_objects\n- total_size_of_active_objects\n- total_size\n\n#### Total Number of MQ Messages\n\n- num_of_replication_messages,\n- num_of_sync-vnode_messages,\n- num_of_rebalance_messages,\n- mq_num_of_msg_recovery_node\n- mq_num_of_msg_deletion_dir\n- mq_num_of_msg_async_deletion_dir\n- mq_num_of_msg_req_deletion_dir\n- mq_mdcr_num_of_msg_req_comp_metadata\n- mq_mdcr_num_of_msg_req_sync_obj\n\nNote: The following items are available since LeoFS v1.4.0:\n\n- mq_num_of_msg_recovery_node\n- mq_num_of_msg_deletion_dir\n- mq_num_of_msg_async_deletion_dir\n- mq_num_of_msg_req_deletion_dir\n- mq_mdcr_num_of_msg_req_comp_metadata\n- mq_mdcr_num_of_msg_req_sync_obj\n\n#### Data Compaction\n\n- comp_state\n- comp_last_start_datetime\n- comp_last_end_datetime\n- comp_num_of_pending_targets\n- comp_num_of_ongoing_targets\n- comp_num_of_out_of_targets\n\nNote: The all items are available since LeoFS v1.4.0.\n\n### Statistics specific to the internals of LeoGateway\n\n#### Erlang VM of LeoGateway\n\n- 1 min Statistics\n  - num_of_processes\n  - total_memory_usage\n  - system_memory_usage\n  - processes_memory_usage\n  - ets_memory_usage\n  - used_allocated_memory\n  - allocated_memory\n- 5 min Statistics\n  - num_of_processes_5min\n  - total_memory_usage_5min\n  - system_memory_usage_5min\n  - processes_memory_usage_5min\n  - ets_memory_usage_5min\n  - used_allocated_memory_5min\n  - allocated_memory_5min\n\n#### Total Number of Requests for LeoGateway\n\n- 1 min Statistics\n  - num_of_writes\n  - num_of_reads\n  - num_of_deletes\n- 5 min Statistics\n  - num_of_writes_5min\n  - num_of_reads_5min\n  - num_of_deletes_5min\n\n#### Object Cache\n\n- count_of_cache-hit\n- count_of_cache-miss\n- total_of_files\n- total_cached_size\n\n### Tags\n\nAll measurements have the following tags:\n\n- node\n\n## Example Output\n\n### LeoManager\n\n```text\nleofs,host=manager_0,node=manager_0@127.0.0.1 allocated_memory=78255445,allocated_memory_5min=78159025,ets_memory_usage=4611900,ets_memory_usage_5min=4632599,num_of_processes=223,num_of_processes_5min=223,processes_memory_usage=20201316,processes_memory_usage_5min=20186559,system_memory_usage=37172701,system_memory_usage_5min=37189213,total_memory_usage=57373373,total_memory_usage_5min=57374653,used_allocated_memory=67,used_allocated_memory_5min=67 1524105758000000000\n```\n\n### LeoStorage\n\n```text\nleofs,host=storage_0,node=storage_0@127.0.0.1 allocated_memory=63504384,allocated_memory_5min=0,comp_last_end_datetime=0,comp_last_start_datetime=0,comp_num_of_ongoing_targets=0,comp_num_of_out_of_targets=0,comp_num_of_pending_targets=8,comp_state=0,ets_memory_usage=3877824,ets_memory_usage_5min=0,mq_mdcr_num_of_msg_req_comp_metadata=0,mq_mdcr_num_of_msg_req_sync_obj=0,mq_num_of_msg_async_deletion_dir=0,mq_num_of_msg_deletion_dir=0,mq_num_of_msg_recovery_node=0,mq_num_of_msg_req_deletion_dir=0,num_of_active_objects=70,num_of_deletes=0,num_of_deletes_5min=0,num_of_processes=577,num_of_processes_5min=0,num_of_reads=1,num_of_reads_5min=0,num_of_rebalance_messages=0,num_of_replication_messages=0,num_of_sync-vnode_messages=0,num_of_writes=70,num_of_writes_5min=0,processes_memory_usage=20029464,processes_memory_usage_5min=0,system_memory_usage=25900472,system_memory_usage_5min=0,total_memory_usage=45920987,total_memory_usage_5min=0,total_objects=70,total_size=2,total_size_of_active_objects=2,used_allocated_memory=69,used_allocated_memory_5min=0 1524529826000000000\n```\n\n### LeoGateway\n\n```text\nleofs,host=gateway_0,node=gateway_0@127.0.0.1 allocated_memory=87941120,allocated_memory_5min=88067672,count_of_cache-hit=0,count_of_cache-miss=0,ets_memory_usage=4843497,ets_memory_usage_5min=4841574,num_of_deletes=0,num_of_deletes_5min=0,num_of_processes=555,num_of_processes_5min=555,num_of_reads=0,num_of_reads_5min=0,num_of_writes=0,num_of_writes_5min=0,processes_memory_usage=17388052,processes_memory_usage_5min=17413928,system_memory_usage=49531263,system_memory_usage_5min=49577819,total_cached_size=0,total_memory_usage=66917393,total_memory_usage_5min=66989469,total_of_files=0,used_allocated_memory=69,used_allocated_memory_5min=69 1524105894000000000\n```\n"
  },
  {
    "path": "plugins/inputs/leofs/leofs.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage leofs\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\toid = \".1.3.6.1.4.1.35450\"\n\t// For Manager Master\n\tdefaultEndpoint = \"127.0.0.1:4020\"\n)\n\ntype serverType int\n\nconst (\n\tserverTypeManagerMaster serverType = iota\n\tserverTypeManagerSlave\n\tserverTypeStorage\n\tserverTypeGateway\n)\n\ntype LeoFS struct {\n\tServers []string `toml:\"servers\"`\n}\n\nvar keyMapping = map[serverType][]string{\n\tserverTypeManagerMaster: {\n\t\t\"num_of_processes\",\n\t\t\"total_memory_usage\",\n\t\t\"system_memory_usage\",\n\t\t\"processes_memory_usage\",\n\t\t\"ets_memory_usage\",\n\t\t\"num_of_processes_5min\",\n\t\t\"total_memory_usage_5min\",\n\t\t\"system_memory_usage_5min\",\n\t\t\"processes_memory_usage_5min\",\n\t\t\"ets_memory_usage_5min\",\n\t\t\"used_allocated_memory\",\n\t\t\"allocated_memory\",\n\t\t\"used_allocated_memory_5min\",\n\t\t\"allocated_memory_5min\",\n\t},\n\tserverTypeManagerSlave: {\n\t\t\"num_of_processes\",\n\t\t\"total_memory_usage\",\n\t\t\"system_memory_usage\",\n\t\t\"processes_memory_usage\",\n\t\t\"ets_memory_usage\",\n\t\t\"num_of_processes_5min\",\n\t\t\"total_memory_usage_5min\",\n\t\t\"system_memory_usage_5min\",\n\t\t\"processes_memory_usage_5min\",\n\t\t\"ets_memory_usage_5min\",\n\t\t\"used_allocated_memory\",\n\t\t\"allocated_memory\",\n\t\t\"used_allocated_memory_5min\",\n\t\t\"allocated_memory_5min\",\n\t},\n\tserverTypeStorage: {\n\t\t\"num_of_processes\",\n\t\t\"total_memory_usage\",\n\t\t\"system_memory_usage\",\n\t\t\"processes_memory_usage\",\n\t\t\"ets_memory_usage\",\n\t\t\"num_of_processes_5min\",\n\t\t\"total_memory_usage_5min\",\n\t\t\"system_memory_usage_5min\",\n\t\t\"processes_memory_usage_5min\",\n\t\t\"ets_memory_usage_5min\",\n\t\t\"num_of_writes\",\n\t\t\"num_of_reads\",\n\t\t\"num_of_deletes\",\n\t\t\"num_of_writes_5min\",\n\t\t\"num_of_reads_5min\",\n\t\t\"num_of_deletes_5min\",\n\t\t\"num_of_active_objects\",\n\t\t\"total_objects\",\n\t\t\"total_size_of_active_objects\",\n\t\t\"total_size\",\n\t\t\"num_of_replication_messages\",\n\t\t\"num_of_sync-vnode_messages\",\n\t\t\"num_of_rebalance_messages\",\n\t\t\"used_allocated_memory\",\n\t\t\"allocated_memory\",\n\t\t\"used_allocated_memory_5min\",\n\t\t\"allocated_memory_5min\",\n\t\t// following items are since LeoFS v1.4.0\n\t\t\"mq_num_of_msg_recovery_node\",\n\t\t\"mq_num_of_msg_deletion_dir\",\n\t\t\"mq_num_of_msg_async_deletion_dir\",\n\t\t\"mq_num_of_msg_req_deletion_dir\",\n\t\t\"mq_mdcr_num_of_msg_req_comp_metadata\",\n\t\t\"mq_mdcr_num_of_msg_req_sync_obj\",\n\t\t\"comp_state\",\n\t\t\"comp_last_start_datetime\",\n\t\t\"comp_last_end_datetime\",\n\t\t\"comp_num_of_pending_targets\",\n\t\t\"comp_num_of_ongoing_targets\",\n\t\t\"comp_num_of_out_of_targets\",\n\t},\n\tserverTypeGateway: {\n\t\t\"num_of_processes\",\n\t\t\"total_memory_usage\",\n\t\t\"system_memory_usage\",\n\t\t\"processes_memory_usage\",\n\t\t\"ets_memory_usage\",\n\t\t\"num_of_processes_5min\",\n\t\t\"total_memory_usage_5min\",\n\t\t\"system_memory_usage_5min\",\n\t\t\"processes_memory_usage_5min\",\n\t\t\"ets_memory_usage_5min\",\n\t\t\"num_of_writes\",\n\t\t\"num_of_reads\",\n\t\t\"num_of_deletes\",\n\t\t\"num_of_writes_5min\",\n\t\t\"num_of_reads_5min\",\n\t\t\"num_of_deletes_5min\",\n\t\t\"count_of_cache-hit\",\n\t\t\"count_of_cache-miss\",\n\t\t\"total_of_files\",\n\t\t\"total_cached_size\",\n\t\t\"used_allocated_memory\",\n\t\t\"allocated_memory\",\n\t\t\"used_allocated_memory_5min\",\n\t\t\"allocated_memory_5min\",\n\t},\n}\n\nvar serverTypeMapping = map[string]serverType{\n\t\"4020\": serverTypeManagerMaster,\n\t\"4021\": serverTypeManagerSlave,\n\t\"4010\": serverTypeStorage,\n\t\"4011\": serverTypeStorage,\n\t\"4012\": serverTypeStorage,\n\t\"4013\": serverTypeStorage,\n\t\"4000\": serverTypeGateway,\n\t\"4001\": serverTypeGateway,\n}\n\nfunc (*LeoFS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *LeoFS) Gather(acc telegraf.Accumulator) error {\n\tif len(l.Servers) == 0 {\n\t\treturn gatherServer(defaultEndpoint, serverTypeManagerMaster, acc)\n\t}\n\tvar wg sync.WaitGroup\n\tfor _, endpoint := range l.Servers {\n\t\tresults := strings.Split(endpoint, \":\")\n\n\t\tport := \"4020\"\n\t\tif len(results) > 2 {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q\", endpoint))\n\t\t\tcontinue\n\t\t} else if len(results) == 2 {\n\t\t\t_, err := strconv.Atoi(results[1])\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"unable to parse port from %q\", endpoint))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tport = results[1]\n\t\t}\n\n\t\tst, ok := serverTypeMapping[port]\n\t\tif !ok {\n\t\t\tst = serverTypeStorage\n\t\t}\n\t\twg.Add(1)\n\t\tgo func(endpoint string, st serverType) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(gatherServer(endpoint, st, acc))\n\t\t}(endpoint, st)\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc gatherServer(endpoint string, serverType serverType, acc telegraf.Accumulator) error {\n\tcmd := exec.Command(\"snmpwalk\", \"-v2c\", \"-cpublic\", \"-On\", endpoint, oid)\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\tdefer internal.WaitTimeout(cmd, time.Second*5) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\tscanner := bufio.NewScanner(stdout)\n\tif !scanner.Scan() {\n\t\treturn errors.New(\"unable to retrieve the node name\")\n\t}\n\tnodeName, err := retrieveTokenAfterColon(scanner.Text())\n\tif err != nil {\n\t\treturn err\n\t}\n\tnodeNameTrimmed := strings.Trim(nodeName, \"\\\"\")\n\ttags := map[string]string{\n\t\t\"node\": nodeNameTrimmed,\n\t}\n\ti := 0\n\n\tfields := make(map[string]interface{})\n\tfor scanner.Scan() {\n\t\tkey := keyMapping[serverType][i]\n\t\tval, err := retrieveTokenAfterColon(scanner.Text())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfVal, err := strconv.ParseFloat(val, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse the value %q: %w\", val, err)\n\t\t}\n\t\tfields[key] = fVal\n\t\ti++\n\t}\n\tacc.AddFields(\"leofs\", fields, tags)\n\treturn nil\n}\n\nfunc retrieveTokenAfterColon(line string) (string, error) {\n\ttokens := strings.Split(line, \":\")\n\tif len(tokens) != 2 {\n\t\treturn \"\", fmt.Errorf(\"':' not found in the line:%s\", line)\n\t}\n\treturn strings.TrimSpace(tokens[1]), nil\n}\n\nfunc init() {\n\tinputs.Add(\"leofs\", func() telegraf.Input {\n\t\treturn &LeoFS{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/leofs/leofs_test.go",
    "content": "package leofs\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar fakeSNMP4Manager = `\npackage main\n\nimport \"fmt\"\n\nconst output = ` + \"`\" + `.1.3.6.1.4.1.35450.15.1.0 = STRING: \"manager_888@127.0.0.1\"\n.1.3.6.1.4.1.35450.15.2.0 = Gauge32: 186\n.1.3.6.1.4.1.35450.15.3.0 = Gauge32: 46235519\n.1.3.6.1.4.1.35450.15.4.0 = Gauge32: 32168525\n.1.3.6.1.4.1.35450.15.5.0 = Gauge32: 14066068\n.1.3.6.1.4.1.35450.15.6.0 = Gauge32: 5512968\n.1.3.6.1.4.1.35450.15.7.0 = Gauge32: 186\n.1.3.6.1.4.1.35450.15.8.0 = Gauge32: 46269006\n.1.3.6.1.4.1.35450.15.9.0 = Gauge32: 32202867\n.1.3.6.1.4.1.35450.15.10.0 = Gauge32: 14064995\n.1.3.6.1.4.1.35450.15.11.0 = Gauge32: 5492634\n.1.3.6.1.4.1.35450.15.12.0 = Gauge32: 60\n.1.3.6.1.4.1.35450.15.13.0 = Gauge32: 43515904\n.1.3.6.1.4.1.35450.15.14.0 = Gauge32: 60\n.1.3.6.1.4.1.35450.15.15.0 = Gauge32: 43533983` + \"`\" +\n\t`\nfunc main() {\n\tfmt.Println(output)\n}\n`\n\nvar fakeSNMP4Storage = `\npackage main\n\nimport \"fmt\"\n\nconst output = ` + \"`\" + `.1.3.6.1.4.1.35450.56.1.0 = STRING: \"storage_0@127.0.0.1\"\n.1.3.6.1.4.1.35450.56.2.0 = Gauge32: 512\n.1.3.6.1.4.1.35450.56.3.0 = Gauge32: 38126307\n.1.3.6.1.4.1.35450.56.4.0 = Gauge32: 22308716\n.1.3.6.1.4.1.35450.56.5.0 = Gauge32: 15816448\n.1.3.6.1.4.1.35450.56.6.0 = Gauge32: 5232008\n.1.3.6.1.4.1.35450.56.7.0 = Gauge32: 512\n.1.3.6.1.4.1.35450.56.8.0 = Gauge32: 38113176\n.1.3.6.1.4.1.35450.56.9.0 = Gauge32: 22313398\n.1.3.6.1.4.1.35450.56.10.0 = Gauge32: 15798779\n.1.3.6.1.4.1.35450.56.11.0 = Gauge32: 5237315\n.1.3.6.1.4.1.35450.56.12.0 = Gauge32: 191\n.1.3.6.1.4.1.35450.56.13.0 = Gauge32: 824\n.1.3.6.1.4.1.35450.56.14.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.56.15.0 = Gauge32: 50105\n.1.3.6.1.4.1.35450.56.16.0 = Gauge32: 196654\n.1.3.6.1.4.1.35450.56.17.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.56.18.0 = Gauge32: 2052\n.1.3.6.1.4.1.35450.56.19.0 = Gauge32: 50296\n.1.3.6.1.4.1.35450.56.20.0 = Gauge32: 35\n.1.3.6.1.4.1.35450.56.21.0 = Gauge32: 898\n.1.3.6.1.4.1.35450.56.22.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.56.23.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.56.24.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.56.31.0 = Gauge32: 51\n.1.3.6.1.4.1.35450.56.32.0 = Gauge32: 53219328\n.1.3.6.1.4.1.35450.56.33.0 = Gauge32: 51\n.1.3.6.1.4.1.35450.56.34.0 = Gauge32: 53351083\n.1.3.6.1.4.1.35450.56.41.0 = Gauge32: 101\n.1.3.6.1.4.1.35450.56.42.0 = Gauge32: 216\n.1.3.6.1.4.1.35450.56.43.0 = Gauge32: 313\n.1.3.6.1.4.1.35450.56.44.0 = Gauge32: 421\n.1.3.6.1.4.1.35450.56.45.0 = Gauge32: 597\n.1.3.6.1.4.1.35450.56.46.0 = Gauge32: 628\n.1.3.6.1.4.1.35450.56.51.0 = Gauge32: 1\n.1.3.6.1.4.1.35450.56.52.0 = Gauge32: 1522154118\n.1.3.6.1.4.1.35450.56.53.0 = Gauge32: 1522196496\n.1.3.6.1.4.1.35450.56.54.0 = Gauge32: 1\n.1.3.6.1.4.1.35450.56.55.0 = Gauge32: 7\n.1.3.6.1.4.1.35450.56.56.0 = Gauge32: 0` + \"`\" +\n\t`\nfunc main() {\n\tfmt.Println(output)\n}\n`\n\nvar fakeSNMP4Gateway = `\npackage main\n\nimport \"fmt\"\n\nconst output = ` + \"`\" + `.1.3.6.1.4.1.35450.34.1.0 = STRING: \"gateway_0@127.0.0.1\"\n.1.3.6.1.4.1.35450.34.2.0 = Gauge32: 465\n.1.3.6.1.4.1.35450.34.3.0 = Gauge32: 61676335\n.1.3.6.1.4.1.35450.34.4.0 = Gauge32: 46890415\n.1.3.6.1.4.1.35450.34.5.0 = Gauge32: 14785011\n.1.3.6.1.4.1.35450.34.6.0 = Gauge32: 5578855\n.1.3.6.1.4.1.35450.34.7.0 = Gauge32: 465\n.1.3.6.1.4.1.35450.34.8.0 = Gauge32: 61644426\n.1.3.6.1.4.1.35450.34.9.0 = Gauge32: 46880358\n.1.3.6.1.4.1.35450.34.10.0 = Gauge32: 14763002\n.1.3.6.1.4.1.35450.34.11.0 = Gauge32: 5582125\n.1.3.6.1.4.1.35450.34.12.0 = Gauge32: 191\n.1.3.6.1.4.1.35450.34.13.0 = Gauge32: 827\n.1.3.6.1.4.1.35450.34.14.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.34.15.0 = Gauge32: 50105\n.1.3.6.1.4.1.35450.34.16.0 = Gauge32: 196650\n.1.3.6.1.4.1.35450.34.17.0 = Gauge32: 0\n.1.3.6.1.4.1.35450.34.18.0 = Gauge32: 30256\n.1.3.6.1.4.1.35450.34.19.0 = Gauge32: 532158\n.1.3.6.1.4.1.35450.34.20.0 = Gauge32: 34\n.1.3.6.1.4.1.35450.34.21.0 = Gauge32: 1\n.1.3.6.1.4.1.35450.34.31.0 = Gauge32: 53\n.1.3.6.1.4.1.35450.34.32.0 = Gauge32: 55050240\n.1.3.6.1.4.1.35450.34.33.0 = Gauge32: 53\n.1.3.6.1.4.1.35450.34.34.0 = Gauge32: 55186538` + \"`\" +\n\t`\nfunc main() {\n\tfmt.Println(output)\n}\n`\n\nfunc testMain(t *testing.T, code, endpoint string, serverType serverType) {\n\texecutable := \"snmpwalk\"\n\tif runtime.GOOS == \"windows\" {\n\t\texecutable = \"snmpwalk.exe\"\n\t}\n\n\t// Build the fake snmpwalk for test\n\tsrc := filepath.Join(t.TempDir(), \"test.go\")\n\trequire.NoError(t, os.WriteFile(src, []byte(code), 0600))\n\tdefer os.Remove(src)\n\n\trequire.NoError(t, exec.Command(\"go\", \"build\", \"-o\", executable, src).Run())\n\tdefer os.Remove(\"./\" + executable)\n\n\tcurrentWorkingDirectory, err := os.Getwd()\n\trequire.NoError(t, err)\n\n\t// Refer to the fake snmpwalk\n\tt.Setenv(\"PATH\", currentWorkingDirectory)\n\n\tl := &LeoFS{\n\t\tServers: []string{endpoint},\n\t}\n\n\tvar acc testutil.Accumulator\n\tacc.SetDebug(true)\n\n\terr = acc.GatherError(l.Gather)\n\trequire.NoError(t, err)\n\n\tfloatMetrics := keyMapping[serverType]\n\n\tfor _, metric := range floatMetrics {\n\t\trequire.True(t, acc.HasFloatField(\"leofs\", metric), metric)\n\t}\n}\n\nfunc TestLeoFSManagerMasterMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\ttestMain(t, fakeSNMP4Manager, \"localhost:4020\", serverTypeManagerMaster)\n}\n\nfunc TestLeoFSManagerSlaveMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\ttestMain(t, fakeSNMP4Manager, \"localhost:4021\", serverTypeManagerSlave)\n}\n\nfunc TestLeoFSStorageMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\ttestMain(t, fakeSNMP4Storage, \"localhost:4010\", serverTypeStorage)\n}\n\nfunc TestLeoFSGatewayMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\ttestMain(t, fakeSNMP4Gateway, \"localhost:4000\", serverTypeGateway)\n}\n"
  },
  {
    "path": "plugins/inputs/leofs/sample.conf",
    "content": "# Read metrics from a LeoFS Server via SNMP\n[[inputs.leofs]]\n  ## An array of URLs of the form:\n  ##   host [ \":\" port]\n  servers = [\"127.0.0.1:4010\"]\n"
  },
  {
    "path": "plugins/inputs/libvirt/README.md",
    "content": "# Libvirt Input Plugin\n\nThis plugin collects statistics about virtualized guests on a system by using\nthe [libvirt][libvirt] virtualization API. Metrics are gathered directly from\nthe hypervisor on a host system, so Telegraf doesn't have to be installed and\nconfigured on a guest system.\n\n⭐ Telegraf v1.25.0\n🏷️ server\n💻 all\n\n[libvirt]: https://libvirt.org/\n\n## Requirements\n\nFor proper operation of the plugin, it is required that the host system has:\n\n- enabled virtualization options for host CPU\n- libvirtd and its dependencies installed and running\n- [qemu hypervisor][qemu] installed and running\n- at least one virtual machine for statistics monitoring\n\n[qemu]: https://www.qemu.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# The libvirt plugin collects statistics from virtualized guests using virtualization libvirt API.\n[[inputs.libvirt]]\n     ## Domain names from which libvirt gather statistics.\n     ## By default (empty or missing array) the plugin gather statistics from each domain registered in the host system.\n     # domains = []\n\n     ## Libvirt connection URI with hypervisor.\n     ## The plugin supports multiple transport protocols and approaches which are configurable via the URI.\n     ## The general URI form: driver[+transport]://[username@][hostname][:port]/[path][?extraparameters]\n     ## Supported transport protocols: ssh, tcp, tls, unix\n     ## URI examples for each type of transport protocol:\n     ## 1. SSH:  qemu+ssh://<USER@IP_OR_HOSTNAME>/system?keyfile=/<PATH_TO_PRIVATE_KEY>&known_hosts=/<PATH_TO_known_hosts>\n     ## 2. TCP:  qemu+tcp://<IP_OR_HOSTNAME>/system\n     ## 3. TLS:  qemu+tls://<HOSTNAME>/system?pkipath=/certs_dir/<COMMON_LOCATION_OF_CACERT_AND_SERVER_CLIENT_CERTS>\n     ## 4. UNIX: qemu+unix:///system?socket=/<PATH_TO_libvirt-sock>\n     ## Default URI is qemu:///system\n     # libvirt_uri = \"qemu:///system\"\n\n     ## Statistics groups for which libvirt plugin will gather statistics.\n     ## Supported statistics groups: state, cpu_total, balloon, vcpu, interface, block, perf, iothread, memory, dirtyrate\n     ## Empty array means no metrics for statistics groups will be exposed by the plugin.\n     ## By default the plugin will gather all available statistics.\n     # statistics_groups = [\"state\", \"cpu_total\", \"balloon\", \"vcpu\", \"interface\", \"block\", \"perf\", \"iothread\", \"memory\", \"dirtyrate\"]\n\n     ## A list containing additional statistics to be exposed by libvirt plugin.\n     ## Supported additional statistics: vcpu_mapping\n     ## By default (empty or missing array) the plugin will not collect additional statistics.\n     # additional_statistics = []\n\n```\n\nUseful links:\n\n- [Libvirt URI docs](https://libvirt.org/uri.html)\n- [TLS setup for libvirt](https://wiki.libvirt.org/page/TLSSetup)\n\nIn cases when one or more of the following occur:\n\n- the global Telegraf variable `interval` is set to a low value (e.g. 1s),\n- a significant number of VMs are monitored,\n- the medium connecting the plugin to the hypervisor is inefficient,\n\nIt is possible that following warning in the logs appears:\n`Collection took longer than expected`.\n\nFor that case, `interval` should be set inside plugin configuration.\nIts value should be adjusted to plugin's runtime environment.\n\nExample:\n\n```toml\n[[inputs.libvirt]]\n  interval = \"30s\"\n```\n\n### Example configuration\n\n```toml\n[[inputs.libvirt]]\n  domain_names = [\"ubuntu_20\"]\n  libvirt_uri = \"qemu:///system\"\n  libvirt_metrics = [\"state\", \"interface\"]\n  additional_statistics = [\"vcpu_mapping\"]\n```\n\n## Metrics\n\nSee the table below for a list of metrics produced by the plugin.\n\nThe exact metric format depends on the statistics libvirt reports,\nwhich may vary depending on the version of libvirt on your system.\n\nThe metrics are divided into the following groups of statistics:\n\n- state\n- cpu_total\n- balloon\n- vcpu\n- net\n- perf\n- block\n- iothread\n- memory\n- dirtyrate\n- vcpu_mapping - additional statistics\n\nStatistics groups from the plugin corresponds to the grouping of\nmetrics directly read from libvirtd using the `virsh domstats` command.\nMore details about metrics can be found at the links below:\n\n- [Domain statistics](https://libvirt.org/manpages/virsh.html#domstats)\n- [Performance monitoring events](https://libvirt.org/formatdomain.html#performance-monitoring-events)\n\n| **Statistics group** | **Metric name** | **Exposed Telegraf field** | **Description** |\n|:---|:---|:---|:---|\n| **state** | state.state | state | state of the VM, returned as number from virDomainState enum |\n||state.reason | reason | reason for entering given state, returned as int from virDomain*Reason enum corresponding to given state |\n| **cpu_total** | cpu.time | time | total cpu time spent for this domain in nanoseconds |\n|| cpu.user | user | user cpu time spent in nanoseconds |\n|| cpu.system | system | system cpu time spent in nanoseconds |\n|| cpu.haltpoll.success.time | haltpoll_success_time | cpu halt polling success time spent in nanoseconds |\n|| cpu.haltpoll.fail.time | haltpoll_fail_time | cpu halt polling fail time spent in nanoseconds |\n|| cpu.cache.monitor.count |count | the number of cache monitors for this domain |\n|| cpu.cache.monitor.\\<num\\>.name | name | the name of cache monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| cpu.cache.monitor.\\<num\\>.vcpus| vcpus |vcpu list of cache monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| cpu.cache.monitor.\\<num\\>.bank.count | bank_count | the number of cache banks in cache monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| cpu.cache.monitor.\\<num\\>.bank.\\<index\\>.id | id|host allocated cache id for bank \\<index\\> in cache monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| cpu.cache.monitor.\\<num\\>.bank.\\<index\\>.bytes | bytes | the number of bytes of last level cache that the domain is using on cache bank \\<index\\>, not available for kernels from 4.14 upwards|\n| **balloon** | balloon.current | current | the memory in KiB currently used |\n|| balloon.maximum | maximum | the maximum memory in KiB allowed |\n|| balloon.swap_in | swap_in | the amount of data read from swap space (in KiB) |\n|| balloon.swap_out | swap_out | the amount of memory written out to swap space (in KiB) |\n|| balloon.major_fault | major_fault | the number of page faults when disk IO was required |\n|| balloon.minor_fault | minor_fault | the number of other page faults |\n|| balloon.unused | unused | the amount of memory left unused by the system (in KiB) |\n|| balloon.available | available | the amount of usable memory as seen by the domain (in KiB) |\n|| balloon.rss | rss | Resident Set Size of running domain's process (in KiB) |\n|| balloon.usable | usable | the amount of memory which can be reclaimed by balloon without causing host swapping (in KiB) |\n|| balloon.last-update | last_update | timestamp of the last update of statistics (in seconds) |\n|| balloon.disk_caches | disk_caches | the amount of memory that can be reclaimed without additional I/O, typically disk (in KiB) |\n|| balloon.hugetlb_pgalloc | hugetlb_pgalloc | the number of successful huge page allocations from inside the domain via virtio balloon |\n|| balloon.hugetlb_pgfail | hugetlb_pgfail | the number of failed huge page allocations from inside the domain via virtio balloon |\n| **vcpu** | vcpu.current | current | yes current number of online virtual CPUs |\n|| vcpu.maximum | maximum | maximum number of online virtual CPUs |\n|| vcpu.\\<num\\>.state | state | state of the virtual CPU \\<num\\>, as number from virVcpuState enum |\n|| vcpu.\\<num\\>.time | time | virtual cpu time spent by virtual CPU \\<num\\> (in microseconds) |\n|| vcpu.\\<num\\>.wait | wait | virtual cpu time spent by virtual CPU \\<num\\> waiting on I/O (in microseconds) |\n|| vcpu.\\<num\\>.halted | halted | virtual CPU \\<num\\> is halted: yes or no (may indicate the processor is idle or even disabled, depending on the architecture) |\n|| vcpu.\\<num\\>.halted | halted_i | virtual CPU \\<num\\> is halted: 1 (for \"yes\") or 0 (for other values) (may indicate the processor is idle or even disabled, depending on the architecture) |\n|| vcpu.\\<num\\>.delay | delay | time the vCPU \\<num\\> thread was enqueued by the host scheduler, but was waiting in the queue instead of running. Exposed to the VM as a steal time. |\n|| --- | cpu_id | Information about mapping vcpu_id to cpu_id (id of physical cpu). Should only be exposed when statistics_group contains vcpu and additional_statistics contains vcpu_mapping (in config) |\n| **interface** | net.count | count | number of network interfaces on this domain |\n|| net.\\<num\\>.name | name | name of the interface  \\<num\\> |\n|| net.\\<num\\>.rx.bytes | rx_bytes | number of bytes received |\n|| net.\\<num\\>.rx.pkts | rx_pkts | number of packets received |\n|| net.\\<num\\>.rx.errs | rx_errs | number of receive errors |\n|| net.\\<num\\>.rx.drop | rx_drop | number of receive packets dropped |\n|| net.\\<num\\>.tx.bytes | tx_bytes | number of bytes transmitted |\n|| net.\\<num\\>.tx.pkts | tx_pkts | number of packets transmitted |\n|| net.\\<num\\>.tx.errs | tx_errs | number of transmission errors |\n|| net.\\<num\\>.tx.drop | tx_drop | number of transmit packets dropped |\n| **perf** | perf.cmt | cmt | the cache usage in Byte currently used, not available for kernels from 4.14 upwards |\n|| perf.mbmt | mbmt | total system bandwidth from one level of cache, not available for kernels from 4.14 upwards |\n|| perf.mbml | mbml | bandwidth of memory traffic for a memory controller, not available for kernels from 4.14 upwards |\n|| perf.cpu_cycles | cpu_cycles | the count of cpu cycles (total/elapsed) |\n|| perf.instructions | instructions |  the count of instructions |\n|| perf.cache_references | cache_references | the count of cache hits |\n|| perf.cache_misses | cache_misses | the count of caches misses |\n|| perf.branch_instructions | branch_instructions | the count of branch instructions |\n|| perf.branch_misses | branch_misses | the count of branch misses |\n|| perf.bus_cycles | bus_cycles | the count of bus cycles |\n|| perf.stalled_cycles_frontend | stalled_cycles_frontend | the count of stalled frontend cpu cycles |\n|| perf.stalled_cycles_backend | stalled_cycles_backend | the count of stalled backend cpu cycles |\n|| perf.ref_cpu_cycles | ref_cpu_cycles | the count of ref cpu cycles |\n|| perf.cpu_clock | cpu_clock | the count of cpu clock time |\n|| perf.task_clock | task_clock | the count of task clock time |\n|| perf.page_faults | page_faults | the count of page faults |\n|| perf.context_switches | context_switches | the count of context switches |\n|| perf.cpu_migrations | cpu_migrations | the count of cpu migrations |\n|| perf.page_faults_min | page_faults_min | the count of minor page faults |\n|| perf.page_faults_maj | page_faults_maj | the count of major page faults |\n|| perf.alignment_faults | alignment_faults | the count of alignment faults |\n|| perf.emulation_faults | emulation_faults | the count of emulation faults |\n| **block** | block.count | count | number of block devices being listed |\n|| block.\\<num\\>.name | name | name of the target of the block device  \\<num\\> (the same name for multiple entries if --backing is present) |\n|| block.\\<num\\>.backingIndex | backingIndex | when --backing is present, matches up with the \\<backingStore\\> index listed in domain XML for backing files |\n|| block.\\<num\\>.path | path | file source of block device  \\<num\\>, if it is a local file or block device |\n|| block.\\<num\\>.rd.reqs | rd_reqs | number of read requests |\n|| block.\\<num\\>.rd.bytes | rd_bytes | number of read bytes |\n|| block.\\<num\\>.rd.times | rd_times | total time (ns) spent on reads |\n|| block.\\<num\\>.wr.reqs | wr_reqs | number of write requests |\n|| block.\\<num\\>.wr.bytes | wr_bytes | number of written bytes |\n|| block.\\<num\\>.wr.times | wr_times | total time (ns) spent on writes |\n|| block.\\<num\\>.fl.reqs | fl_reqs | total flush requests |\n|| block.\\<num\\>.fl.times | fl_times | total time (ns) spent on cache flushing |\n|| block.\\<num\\>.errors | errors | Xen only: the 'oo_req' value |\n|| block.\\<num\\>.allocation | allocation | offset of highest written sector in bytes |\n|| block.\\<num\\>.capacity | capacity | logical size of source file in bytes |\n|| block.\\<num\\>.physical | physical | physical size of source file in bytes |\n|| block.\\<num\\>.threshold | threshold | threshold (in bytes) for delivering the VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD event. See domblkthreshold |\n| **iothread** | iothread.count | count | maximum number of IOThreads in the subsequent list as unsigned int. Each IOThread in the list will will use it's iothread_id value as the \\<id\\>. There may be fewer \\<id\\> entries than the iothread.count value if the polling values are not supported |\n|| iothread.\\<id\\>.poll-max-ns | poll_max_ns | maximum polling time in nanoseconds used by the \\<id\\> IOThread. A value of 0 (zero) indicates polling is disabled |\n|| iothread.\\<id\\>.poll-grow | poll_grow | polling time grow value. A value of 0 (zero) growth is managed by the hypervisor |\n|| iothread.\\<id\\>.poll-shrink | poll_shrink | polling time shrink value. A value of (zero) indicates shrink is managed by hypervisor |\n| **memory** | memory.bandwidth.monitor.count | count | the number of memory bandwidth monitors for this domain, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.name | name | the name of monitor  \\<num\\>, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.vcpus | vcpus | the vcpu list of monitor  \\<num\\>, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.node.count | node_count | the number of memory controller in monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.node.\\<index\\>.id | id | host allocated memory controller id for controller \\<index\\> of monitor \\<num\\>, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.node.\\<index\\>.bytes.local | bytes_local | the accumulative bytes consumed by \\@vcpus that passing through the memory controller in the same processor that the scheduled host CPU belongs to, not available for kernels from 4.14 upwards |\n|| memory.bandwidth.monitor.\\<num\\>.node.\\<index\\>.bytes.total | bytes_total | the total bytes consumed by \\@vcpus that passing through all memory controllers, either local or remote controller, not available for kernels from 4.14 upwards |\n| **dirtyrate** | dirtyrate.calc_status | calc_status | the status of last memory dirty rate calculation, returned as number from virDomainDirtyRateStatus enum |\n|| dirtyrate.calc_start_time | calc_start_time the | start time of last memory dirty rate calculation |\n|| dirtyrate.calc_period | calc_period | the period of last memory dirty rate calculation |\n|| dirtyrate.megabytes_per_second | megabytes_per_second | the calculated memory dirty rate in MiB/s |\n|| dirtyrate.calc_mode | calc_mode | the calculation mode used last measurement (page-sampling/dirty-bitmap/dirty-ring) |\n|| dirtyrate.vcpu.\\<num\\>.megabytes_per_second | megabytes_per_second | the calculated memory dirty rate for a virtual cpu in MiB/s |\n\n### Additional statistics\n\n| **Statistics group**           | **Exposed Telegraf tag**      | **Exposed Telegraf field**      |**Description**         |\n|:-------------------------------|:-----------------------------:|:-------------------------------:|:-----------------------|\n| **vcpu_mapping** | vcpu_id | --- | ID of Virtual CPU |\n|| --- | cpu_id | Comma separated list (exposed as a string) of Physical CPU IDs |\n\n## Example Output\n\n```text\nlibvirt_cpu_affinity,domain_name=U22,host=localhost,vcpu_id=0 cpu_id=\"1,2,3\" 1662383707000000000\nlibvirt_cpu_affinity,domain_name=U22,host=localhost,vcpu_id=1 cpu_id=\"1,2,3,4,5,6,7,8,9,10\" 1662383707000000000\nlibvirt_balloon,domain_name=U22,host=localhost current=4194304i,maximum=4194304i,swap_in=0i,swap_out=0i,major_fault=0i,minor_fault=0i,unused=3928628i,available=4018480i,rss=1036012i,usable=3808724i,last_update=1654611373i,disk_caches=68820i,hugetlb_pgalloc=0i,hugetlb_pgfail=0i 1662383709000000000\nlibvirt_vcpu_total,domain_name=U22,host=localhost maximum=2i,current=2i 1662383709000000000\nlibvirt_vcpu,domain_name=U22,host=localhost,vcpu_id=0 state=1i,time=17943740000000i,wait=0i,halted=\"no\",halted_i=0i,delay=14246609424i,cpu_id=1i 1662383709000000000\nlibvirt_vcpu,domain_name=U22,host=localhost,vcpu_id=1 state=1i,time=18288400000000i,wait=0i,halted=\"yes\",halted_i=1i,delay=12902231142i,cpu_id=3i 1662383709000000000\nlibvirt_net_total,domain_name=U22,host=localhost count=1i 1662383709000000000\nlibvirt_net,domain_name=U22,host=localhost,interface_id=0 name=\"vnet0\",rx_bytes=110i,rx_pkts=1i,rx_errs=0i,rx_drop=31007i,tx_bytes=0i,tx_pkts=0i,tx_errs=0i,tx_drop=0i 1662383709000000000\nlibvirt_block_total,domain_name=U22,host=localhost count=1i 1662383709000000000\nlibvirt_block,domain_name=U22,host=localhost,block_id=0 rd=17337818234i,path=name=\"vda\",backingIndex=1i,path=\"/tmp/ubuntu_image.img\",rd_reqs=11354i,rd_bytes=330314752i,rd_times=6240559566i,wr_reqs=52440i,wr_bytes=1183828480i,wr_times=21887150375i,fl_reqs=32250i,fl_times=23158998353i,errors=0i,allocation=770048000i,capacity=2361393152i,physical=770052096i,threshold=2147483648i\nlibvirt_perf,domain_name=U22,host=localhost cmt=19087360i,mbmt=77168640i,mbml=67788800i,cpu_cycles=29858995122i,instructions=0i,cache_references=3053301695i,cache_misses=609441024i,branch_instructions=2623890194i,branch_misses=103707961i,bus_cycles=188105628i,stalled_cycles_frontend=0i,stalled_cycles_backend=0i,ref_cpu_cycles=30766094039i,cpu_clock=25166642695i,task_clock=25263578917i,page_faults=2670i,context_switches=294284i,cpu_migrations=17949i,page_faults_min=2670i,page_faults_maj=0i,alignment_faults=0i,emulation_faults=0i 1662383709000000000\nlibvirt_dirtyrate,domain_name=U22,host=localhost calc_status=2i,calc_start_time=348414i,calc_period=1i,dirtyrate.megabytes_per_second=4i,calc_mode=\"dirty-ring\" 1662383709000000000\nlibvirt_dirtyrate_vcpu,domain_name=U22,host=localhost,vcpu_id=0 megabytes_per_second=2i 1662383709000000000\nlibvirt_dirtyrate_vcpu,domain_name=U22,host=localhost,vcpu_id=1 megabytes_per_second=2i 1662383709000000000\nlibvirt_state,domain_name=U22,host=localhost state=1i,reason=5i 1662383709000000000\nlibvirt_cpu,domain_name=U22,host=localhost time=67419144867000i,user=63886161852000i,system=3532983015000i,haltpoll_success_time=516907915i,haltpoll_fail_time=2727253643i 1662383709000000000\nlibvirt_cpu_cache_monitor_total,domain_name=U22,host=localhost count=1i 1662383709000000000\nlibvirt_cpu_cache_monitor,domain_name=U22,host=localhost,cache_monitor_id=0 name=\"any_name_vcpus_0-3\",vcpus=\"0-3\",bank_count=1i 1662383709000000000\nlibvirt_cpu_cache_monitor_bank,domain_name=U22,host=localhost,cache_monitor_id=0,bank_index=0 id=0i,bytes=5406720i 1662383709000000000\nlibvirt_iothread_total,domain_name=U22,host=localhost count=1i 1662383709000000000\nlibvirt_iothread,domain_name=U22,host=localhost,iothread_id=0 poll_max_ns=32768i,poll_grow=0i,poll_shrink=0i 1662383709000000000\nlibvirt_memory_bandwidth_monitor_total,domain_name=U22,host=localhost count=2i 1662383709000000000\nlibvirt_memory_bandwidth_monitor,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=0 name=\"any_name_vcpus_0-4\",vcpus=\"0-4\",node_count=2i 1662383709000000000\nlibvirt_memory_bandwidth_monitor,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=1 name=\"vcpus_7\",vcpus=\"7\",node_count=2i 1662383709000000000\nlibvirt_memory_bandwidth_monitor_node,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=0,controller_index=0 id=0i,bytes_total=10208067584i,bytes_local=4807114752i 1662383709000000000\nlibvirt_memory_bandwidth_monitor_node,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=0,controller_index=1 id=1i,bytes_total=8693735424i,bytes_local=5850161152i 1662383709000000000\nlibvirt_memory_bandwidth_monitor_node,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=1,controller_index=0 id=0i,bytes_total=853811200i,bytes_local=290701312i 1662383709000000000\nlibvirt_memory_bandwidth_monitor_node,domain_name=U22,host=localhost,memory_bandwidth_monitor_id=1,controller_index=1 id=1i,bytes_total=406044672i,bytes_local=229425152i 1662383709000000000\n```\n"
  },
  {
    "path": "plugins/inputs/libvirt/libvirt.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage libvirt\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\tgolibvirt \"github.com/digitalocean/go-libvirt\"\n\tlibvirtutils \"github.com/thomasklein94/packer-plugin-libvirt/libvirt-utils\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdomainStatsState     uint32 = 1\n\tdomainStatsCPUTotal  uint32 = 2\n\tdomainStatsBalloon   uint32 = 4\n\tdomainStatsVCPU      uint32 = 8\n\tdomainStatsInterface uint32 = 16\n\tdomainStatsBlock     uint32 = 32\n\tdomainStatsPerf      uint32 = 64\n\tdomainStatsIothread  uint32 = 128\n\tdomainStatsMemory    uint32 = 256\n\tdomainStatsDirtyrate uint32 = 512\n\tdomainStatsAll       uint32 = 1023\n\tdefaultLibvirtURI           = \"qemu:///system\"\n\tpluginName                  = \"libvirt\"\n)\n\ntype Libvirt struct {\n\tLibvirtURI           string          `toml:\"libvirt_uri\"`\n\tDomains              []string        `toml:\"domains\"`\n\tStatisticsGroups     []string        `toml:\"statistics_groups\"`\n\tAdditionalStatistics []string        `toml:\"additional_statistics\"`\n\tLog                  telegraf.Logger `toml:\"-\"`\n\n\tutils              utils\n\tmetricNumber       uint32\n\tvcpuMappingEnabled bool\n\tdomainsMap         map[string]struct{}\n}\n\nfunc (*Libvirt) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *Libvirt) Init() error {\n\tif len(l.Domains) == 0 {\n\t\tl.Log.Debugf(\"No domains given. Collecting metrics from all available domains.\")\n\t}\n\tl.domainsMap = make(map[string]struct{}, len(l.Domains))\n\tfor _, domain := range l.Domains {\n\t\tl.domainsMap[domain] = struct{}{}\n\t}\n\n\tif l.LibvirtURI == \"\" {\n\t\tl.Log.Debugf(\"Using default libvirt url - %q\", defaultLibvirtURI)\n\t\tl.LibvirtURI = defaultLibvirtURI\n\t}\n\n\tif err := l.validateLibvirtURI(); err != nil {\n\t\treturn err\n\t}\n\n\t// setting to defaults only when statistics_groups is missing in config\n\tif l.StatisticsGroups == nil {\n\t\tl.Log.Debugf(\"Setting libvirt to gather all metrics.\")\n\t\tl.metricNumber = domainStatsAll\n\t} else {\n\t\tif err := l.calculateMetricNumber(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := l.validateAdditionalStatistics(); err != nil {\n\t\treturn err\n\t}\n\n\tif !l.isThereAnythingToGather() {\n\t\treturn errors.New(\"all configuration options are empty or invalid. Did not find anything to gather\")\n\t}\n\n\treturn nil\n}\n\nfunc (l *Libvirt) Gather(acc telegraf.Accumulator) error {\n\tvar err error\n\tif err := l.utils.ensureConnected(l.LibvirtURI); err != nil {\n\t\treturn err\n\t}\n\n\t// Get all available domains\n\tgatheredDomains, err := l.utils.gatherAllDomains()\n\tif handledErr := handleError(err, \"error occurred while gathering all domains\", l.utils); handledErr != nil {\n\t\treturn handledErr\n\t} else if len(gatheredDomains) == 0 {\n\t\tl.Log.Debug(\"Couldn't find any domains on system\")\n\t\treturn nil\n\t}\n\n\t// Exclude domain.\n\tdomains := l.filterDomains(gatheredDomains)\n\tif len(domains) == 0 {\n\t\tl.Log.Debug(\"Configured domains are not available on system\")\n\t\treturn nil\n\t}\n\n\tvar vcpuInfos map[string][]vcpuAffinity\n\tif l.vcpuMappingEnabled {\n\t\tvcpuInfos, err = l.getVcpuMapping(domains)\n\t\tif handledErr := handleError(err, \"error occurred while gathering vcpu mapping\", l.utils); handledErr != nil {\n\t\t\treturn handledErr\n\t\t}\n\t}\n\n\terr = l.gatherMetrics(domains, vcpuInfos, acc)\n\treturn handleError(err, \"error occurred while gathering metrics\", l.utils)\n}\n\nfunc (l *Libvirt) validateLibvirtURI() error {\n\turi := libvirtutils.LibvirtUri{}\n\terr := uri.Unmarshal(l.LibvirtURI)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// dialer not needed, calling this just for validating libvirt URI as soon as possible:\n\t_, err = libvirtutils.NewDialerFromLibvirtUri(uri)\n\treturn err\n}\n\nfunc (l *Libvirt) calculateMetricNumber() error {\n\tvar libvirtMetricNumber = map[string]uint32{\n\t\t\"state\":     domainStatsState,\n\t\t\"cpu_total\": domainStatsCPUTotal,\n\t\t\"balloon\":   domainStatsBalloon,\n\t\t\"vcpu\":      domainStatsVCPU,\n\t\t\"interface\": domainStatsInterface,\n\t\t\"block\":     domainStatsBlock,\n\t\t\"perf\":      domainStatsPerf,\n\t\t\"iothread\":  domainStatsIothread,\n\t\t\"memory\":    domainStatsMemory,\n\t\t\"dirtyrate\": domainStatsDirtyrate}\n\n\tmetricIsSet := make(map[string]bool)\n\tfor _, metricName := range l.StatisticsGroups {\n\t\tmetricNumber, exists := libvirtMetricNumber[metricName]\n\t\tif !exists {\n\t\t\treturn fmt.Errorf(\"unrecognized metrics name %q\", metricName)\n\t\t}\n\t\tif _, ok := metricIsSet[metricName]; ok {\n\t\t\treturn fmt.Errorf(\"duplicated statistics group in config: %q\", metricName)\n\t\t}\n\t\tl.metricNumber += metricNumber\n\t\tmetricIsSet[metricName] = true\n\t}\n\n\treturn nil\n}\n\nfunc (l *Libvirt) validateAdditionalStatistics() error {\n\tfor _, stat := range l.AdditionalStatistics {\n\t\tswitch stat {\n\t\tcase \"vcpu_mapping\":\n\t\t\tif l.vcpuMappingEnabled {\n\t\t\t\treturn fmt.Errorf(\"duplicated additional statistic in config: %q\", stat)\n\t\t\t}\n\t\t\tl.vcpuMappingEnabled = true\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"additional statistics: %v is not supported by this plugin\", stat)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (l *Libvirt) isThereAnythingToGather() bool {\n\treturn l.metricNumber > 0 || len(l.AdditionalStatistics) > 0\n}\n\nfunc handleError(err error, errMessage string, utils utils) error {\n\tif err != nil {\n\t\tif chanErr := utils.disconnect(); chanErr != nil {\n\t\t\treturn fmt.Errorf(\"%s: %w; error occurred when disconnecting: %w\", errMessage, err, chanErr)\n\t\t}\n\t\treturn fmt.Errorf(\"%s: %w\", errMessage, err)\n\t}\n\treturn nil\n}\n\nfunc (l *Libvirt) filterDomains(availableDomains []golibvirt.Domain) []golibvirt.Domain {\n\tif len(l.domainsMap) == 0 {\n\t\treturn availableDomains\n\t}\n\n\tvar filteredDomains []golibvirt.Domain\n\tfor _, domain := range availableDomains {\n\t\tif _, ok := l.domainsMap[domain.Name]; ok {\n\t\t\tfilteredDomains = append(filteredDomains, domain)\n\t\t}\n\t}\n\n\treturn filteredDomains\n}\n\nfunc (l *Libvirt) gatherMetrics(domains []golibvirt.Domain, vcpuInfos map[string][]vcpuAffinity, acc telegraf.Accumulator) error {\n\tstats, err := l.utils.gatherStatsForDomains(domains, l.metricNumber)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tl.addMetrics(stats, vcpuInfos, acc)\n\treturn nil\n}\n\nfunc (l *Libvirt) getVcpuMapping(domains []golibvirt.Domain) (map[string][]vcpuAffinity, error) {\n\tpCPUs, err := l.utils.gatherNumberOfPCPUs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar vcpuInfos = make(map[string][]vcpuAffinity)\n\tgroup := errgroup.Group{}\n\tmutex := &sync.RWMutex{}\n\tfor i := range domains {\n\t\tdomain := domains[i]\n\n\t\t// Executing gatherVcpuMapping can take some time, it is worth to call it in parallel\n\t\tgroup.Go(func() error {\n\t\t\tvcpuInfo, err := l.utils.gatherVcpuMapping(domain, pCPUs, l.shouldGetCurrentPCPU())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tmutex.Lock()\n\t\t\tvcpuInfos[domain.Name] = vcpuInfo\n\t\t\tmutex.Unlock()\n\t\t\treturn nil\n\t\t})\n\t}\n\n\terr = group.Wait()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn vcpuInfos, nil\n}\n\nfunc (l *Libvirt) shouldGetCurrentPCPU() bool {\n\treturn l.vcpuMappingEnabled && (l.metricNumber&domainStatsVCPU) != 0\n}\n\nfunc init() {\n\tinputs.Add(pluginName, func() telegraf.Input {\n\t\treturn &Libvirt{\n\t\t\tutils: &utilsImpl{},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/libvirt/libvirt_metric_format.go",
    "content": "package libvirt\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\n\tgolibvirt \"github.com/digitalocean/go-libvirt\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nvar (\n\tcpuCacheMonitorRegexp            = regexp.MustCompile(`^cache\\.monitor\\..+?\\.(name|vcpus|bank_count)$`)\n\tcpuCacheMonitorBankRegexp        = regexp.MustCompile(`^cache\\.monitor\\..+?\\.bank\\..+?\\.(id|bytes)$`)\n\tmemoryBandwidthMonitorRegexp     = regexp.MustCompile(`^bandwidth\\.monitor\\..+?\\.(name|vcpus|node_count)$`)\n\tmemoryBandwidthMonitorNodeRegexp = regexp.MustCompile(`^bandwidth\\.monitor\\..+?\\.node\\..+?\\.(id|bytes_local|bytes_total)$`)\n)\n\nfunc (l *Libvirt) addMetrics(stats []golibvirt.DomainStatsRecord, vcpuInfos map[string][]vcpuAffinity, acc telegraf.Accumulator) {\n\tdomainsMetrics := translateMetrics(stats)\n\n\tfor domainName, metrics := range domainsMetrics {\n\t\tfor metricType, values := range metrics {\n\t\t\tswitch metricType {\n\t\t\tcase \"state\":\n\t\t\t\taddStateMetrics(values, domainName, acc)\n\t\t\tcase \"cpu\":\n\t\t\t\taddCPUMetrics(values, domainName, acc)\n\t\t\tcase \"balloon\":\n\t\t\t\taddBalloonMetrics(values, domainName, acc)\n\t\t\tcase \"vcpu\":\n\t\t\t\tl.addVcpuMetrics(values, domainName, vcpuInfos[domainName], acc)\n\t\t\tcase \"net\":\n\t\t\t\taddInterfaceMetrics(values, domainName, acc)\n\t\t\tcase \"perf\":\n\t\t\t\taddPerfMetrics(values, domainName, acc)\n\t\t\tcase \"block\":\n\t\t\t\taddBlockMetrics(values, domainName, acc)\n\t\t\tcase \"iothread\":\n\t\t\t\taddIothreadMetrics(values, domainName, acc)\n\t\t\tcase \"memory\":\n\t\t\t\taddMemoryMetrics(values, domainName, acc)\n\t\t\tcase \"dirtyrate\":\n\t\t\t\taddDirtyrateMetrics(values, domainName, acc)\n\t\t\t}\n\t\t}\n\t}\n\n\tif l.vcpuMappingEnabled {\n\t\tfor domainName, vcpuInfo := range vcpuInfos {\n\t\t\tvar tags = make(map[string]string)\n\t\t\tvar fields = make(map[string]interface{})\n\n\t\t\tfor _, vcpu := range vcpuInfo {\n\t\t\t\ttags[\"domain_name\"] = domainName\n\t\t\t\ttags[\"vcpu_id\"] = vcpu.vcpuID\n\t\t\t\tfields[\"cpu_id\"] = vcpu.coresAffinity\n\t\t\t\tacc.AddFields(\"libvirt_cpu_affinity\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc translateMetrics(stats []golibvirt.DomainStatsRecord) map[string]map[string]map[string]golibvirt.TypedParamValue {\n\tmetrics := make(map[string]map[string]map[string]golibvirt.TypedParamValue)\n\tfor _, stat := range stats {\n\t\tif stat.Params != nil {\n\t\t\tif metrics[stat.Dom.Name] == nil {\n\t\t\t\tmetrics[stat.Dom.Name] = make(map[string]map[string]golibvirt.TypedParamValue)\n\t\t\t}\n\n\t\t\tfor _, params := range stat.Params {\n\t\t\t\tstatGroup := strings.Split(params.Field, \".\")[0]\n\t\t\t\tif metrics[stat.Dom.Name][statGroup] == nil {\n\t\t\t\t\tmetrics[stat.Dom.Name][statGroup] = make(map[string]golibvirt.TypedParamValue)\n\t\t\t\t}\n\n\t\t\t\tmetrics[stat.Dom.Name][statGroup][strings.TrimPrefix(params.Field, statGroup+\".\")] = params.Value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn metrics\n}\n\nfunc addStateMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar stateFields = make(map[string]interface{})\n\tvar stateTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"state\", \"reason\":\n\t\t\tstateFields[key] = metric.I\n\t\t}\n\t}\n\n\tif len(stateFields) > 0 {\n\t\tacc.AddFields(\"libvirt_state\", stateFields, stateTags)\n\t}\n}\n\nfunc addCPUMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar cpuFields = make(map[string]interface{})\n\tvar cpuCacheMonitorTotalFields = make(map[string]interface{})\n\n\tvar cpuCacheMonitorData = make(map[string]map[string]interface{})\n\tvar cpuCacheMonitorBankData = make(map[string]map[string]map[string]interface{})\n\n\tvar cpuTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"time\", \"user\", \"system\":\n\t\t\tcpuFields[key] = metric.I\n\t\tcase \"haltpoll.success.time\", \"haltpoll.fail.time\":\n\t\t\tcpuFields[strings.ReplaceAll(key, \".\", \"_\")] = metric.I\n\t\tcase \"cache.monitor.count\":\n\t\t\tcpuCacheMonitorTotalFields[\"count\"] = metric.I\n\t\tdefault:\n\t\t\tif strings.Contains(key, \"bank.count\") {\n\t\t\t\tkey = strings.ReplaceAll(key, \"bank.count\", \"bank_count\")\n\t\t\t}\n\n\t\t\tcpuStat := strings.Split(key, \".\")\n\t\t\tif len(cpuStat) == 4 && cpuCacheMonitorRegexp.MatchString(key) {\n\t\t\t\tcacheMonitorID := cpuStat[2]\n\t\t\t\tcpuCacheMonitorFields, ok := cpuCacheMonitorData[cacheMonitorID]\n\t\t\t\tif !ok {\n\t\t\t\t\tcpuCacheMonitorFields = make(map[string]interface{})\n\t\t\t\t\tcpuCacheMonitorData[cacheMonitorID] = cpuCacheMonitorFields\n\t\t\t\t}\n\n\t\t\t\tcpuCacheMonitorFields[cpuStat[3]] = metric.I\n\t\t\t} else if len(cpuStat) == 6 && cpuCacheMonitorBankRegexp.MatchString(key) {\n\t\t\t\tcacheMonitorID := cpuStat[2]\n\t\t\t\tbankIndex := cpuStat[4]\n\n\t\t\t\tbankData, ok := cpuCacheMonitorBankData[cacheMonitorID]\n\t\t\t\tif !ok {\n\t\t\t\t\tbankData = make(map[string]map[string]interface{})\n\t\t\t\t\tcpuCacheMonitorBankData[cacheMonitorID] = bankData\n\t\t\t\t}\n\n\t\t\t\tbankFields, ok := cpuCacheMonitorBankData[cacheMonitorID][bankIndex]\n\t\t\t\tif !ok {\n\t\t\t\t\tbankFields = make(map[string]interface{})\n\t\t\t\t\tbankData[bankIndex] = bankFields\n\t\t\t\t}\n\n\t\t\t\tbankFields[cpuStat[5]] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(cpuFields) > 0 {\n\t\tacc.AddFields(\"libvirt_cpu\", cpuFields, cpuTags)\n\t}\n\n\tif len(cpuCacheMonitorTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_cpu_cache_monitor_total\", cpuCacheMonitorTotalFields, cpuTags)\n\t}\n\n\tfor cpuID, cpuCacheMonitorFields := range cpuCacheMonitorData {\n\t\tif len(cpuCacheMonitorFields) > 0 {\n\t\t\tcpuCacheMonitorTags := map[string]string{\n\t\t\t\t\"domain_name\":      domainName,\n\t\t\t\t\"cache_monitor_id\": cpuID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_cpu_cache_monitor\", cpuCacheMonitorFields, cpuCacheMonitorTags)\n\t\t}\n\t}\n\n\tfor cacheMonitorID, bankData := range cpuCacheMonitorBankData {\n\t\tfor bankIndex, bankFields := range bankData {\n\t\t\tif len(bankFields) > 0 {\n\t\t\t\tbankTags := map[string]string{\n\t\t\t\t\t\"domain_name\":      domainName,\n\t\t\t\t\t\"cache_monitor_id\": cacheMonitorID,\n\t\t\t\t\t\"bank_index\":       bankIndex,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"libvirt_cpu_cache_monitor_bank\", bankFields, bankTags)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc addBalloonMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar balloonFields = make(map[string]interface{})\n\tvar balloonTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"current\", \"maximum\", \"swap_in\", \"swap_out\", \"major_fault\", \"minor_fault\", \"unused\", \"available\",\n\t\t\t\"rss\", \"usable\", \"disk_caches\", \"hugetlb_pgalloc\", \"hugetlb_pgfail\":\n\t\t\tballoonFields[key] = metric.I\n\t\tcase \"last-update\":\n\t\t\tballoonFields[\"last_update\"] = metric.I\n\t\t}\n\t}\n\n\tif len(balloonFields) > 0 {\n\t\tacc.AddFields(\"libvirt_balloon\", balloonFields, balloonTags)\n\t}\n}\n\nfunc (l *Libvirt) addVcpuMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, vcpuInfos []vcpuAffinity, acc telegraf.Accumulator) {\n\tvar vcpuTotalFields = make(map[string]interface{})\n\tvar vcpuData = make(map[string]map[string]interface{})\n\n\tvar vcpuTotalTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"current\", \"maximum\":\n\t\t\tvcpuTotalFields[key] = metric.I\n\t\tdefault:\n\t\t\tvcpuStat := strings.Split(key, \".\")\n\t\t\tif len(vcpuStat) != 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvcpuID := vcpuStat[0]\n\t\t\tfieldName := vcpuStat[1]\n\t\t\tvcpuFields, ok := vcpuData[vcpuID]\n\t\t\tif !ok {\n\t\t\t\tvcpuFields = make(map[string]interface{})\n\t\t\t\tvcpuData[vcpuID] = vcpuFields\n\t\t\t}\n\n\t\t\tswitch fieldName {\n\t\t\tcase \"halted\":\n\t\t\t\thaltedIntegerValue := 0\n\t\t\t\tif metric.I == \"yes\" {\n\t\t\t\t\thaltedIntegerValue = 1\n\t\t\t\t}\n\n\t\t\t\tvcpuFields[\"halted_i\"] = haltedIntegerValue\n\t\t\t\tfallthrough\n\t\t\tcase \"state\", \"time\", \"wait\", \"delay\":\n\t\t\t\tvcpuFields[fieldName] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(vcpuTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_vcpu_total\", vcpuTotalFields, vcpuTotalTags)\n\t}\n\n\tfor vcpuID, vcpuFields := range vcpuData {\n\t\tif len(vcpuFields) > 0 {\n\t\t\tvcpuTags := map[string]string{\n\t\t\t\t\"domain_name\": domainName,\n\t\t\t\t\"vcpu_id\":     vcpuID,\n\t\t\t}\n\n\t\t\tif pCPUID := l.getCurrentPCPUForVCPU(vcpuID, vcpuInfos); pCPUID >= 0 {\n\t\t\t\tvcpuFields[\"cpu_id\"] = pCPUID\n\t\t\t}\n\n\t\t\tacc.AddFields(\"libvirt_vcpu\", vcpuFields, vcpuTags)\n\t\t}\n\t}\n}\n\nfunc (l *Libvirt) getCurrentPCPUForVCPU(vcpuID string, vcpuInfos []vcpuAffinity) int32 {\n\tif !l.shouldGetCurrentPCPU() {\n\t\treturn -1\n\t}\n\n\tfor _, vcpuInfo := range vcpuInfos {\n\t\tif vcpuInfo.vcpuID == vcpuID {\n\t\t\treturn vcpuInfo.currentPCPUID\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc addInterfaceMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar netTotalFields = make(map[string]interface{})\n\tvar netData = make(map[string]map[string]interface{})\n\n\tvar netTotalTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tif key == \"count\" {\n\t\t\tnetTotalFields[key] = metric.I\n\t\t} else {\n\t\t\tnetStat := strings.SplitN(key, \".\", 2)\n\t\t\tif len(netStat) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tnetID := netStat[0]\n\t\t\tnetFields, ok := netData[netID]\n\t\t\tif !ok {\n\t\t\t\tnetFields = make(map[string]interface{})\n\t\t\t\tnetData[netID] = netFields\n\t\t\t}\n\n\t\t\tfieldName := strings.ReplaceAll(netStat[1], \".\", \"_\")\n\t\t\tswitch fieldName {\n\t\t\tcase \"name\", \"rx_bytes\", \"rx_pkts\", \"rx_errs\", \"rx_drop\", \"tx_bytes\", \"tx_pkts\", \"tx_errs\", \"tx_drop\":\n\t\t\t\tnetFields[fieldName] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(netTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_net_total\", netTotalFields, netTotalTags)\n\t}\n\n\tfor netID, netFields := range netData {\n\t\tif len(netFields) > 0 {\n\t\t\tnetTags := map[string]string{\n\t\t\t\t\"domain_name\":  domainName,\n\t\t\t\t\"interface_id\": netID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_net\", netFields, netTags)\n\t\t}\n\t}\n}\n\nfunc addPerfMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar perfFields = make(map[string]interface{})\n\tvar perfTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"cmt\", \"mbmt\", \"mbml\", \"cpu_cycles\", \"instructions\", \"cache_references\", \"cache_misses\",\n\t\t\t\"branch_instructions\", \"branch_misses\", \"bus_cycles\", \"stalled_cycles_frontend\", \"stalled_cycles_backend\",\n\t\t\t\"ref_cpu_cycles\", \"cpu_clock\", \"task_clock\", \"page_faults\", \"context_switches\",\n\t\t\t\"cpu_migrations\", \"page_faults_min\", \"page_faults_maj\", \"alignment_faults\", \"emulation_faults\":\n\t\t\tperfFields[key] = metric.I\n\t\t}\n\t}\n\n\tif len(perfFields) > 0 {\n\t\tacc.AddFields(\"libvirt_perf\", perfFields, perfTags)\n\t}\n}\n\nfunc addBlockMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar blockTotalFields = make(map[string]interface{})\n\tvar blockData = make(map[string]map[string]interface{})\n\n\tvar blockTotalTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tif key == \"count\" {\n\t\t\tblockTotalFields[\"count\"] = metric.I\n\t\t} else {\n\t\t\tblockStat := strings.SplitN(key, \".\", 2)\n\t\t\tif len(blockStat) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tblockID := blockStat[0]\n\t\t\tblockFields, ok := blockData[blockID]\n\t\t\tif !ok {\n\t\t\t\tblockFields = make(map[string]interface{})\n\t\t\t\tblockData[blockID] = blockFields\n\t\t\t}\n\n\t\t\tfieldName := strings.ReplaceAll(blockStat[1], \".\", \"_\")\n\t\t\tswitch fieldName {\n\t\t\tcase \"name\", \"backingIndex\", \"path\", \"rd_reqs\", \"rd_bytes\", \"rd_times\", \"wr_reqs\", \"wr_bytes\", \"wr_times\",\n\t\t\t\t\"fl_reqs\", \"fl_times\", \"errors\", \"allocation\", \"capacity\", \"physical\", \"threshold\":\n\t\t\t\tblockFields[fieldName] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(blockTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_block_total\", blockTotalFields, blockTotalTags)\n\t}\n\n\tfor blockID, blockFields := range blockData {\n\t\tif len(blockFields) > 0 {\n\t\t\tblockTags := map[string]string{\n\t\t\t\t\"domain_name\": domainName,\n\t\t\t\t\"block_id\":    blockID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_block\", blockFields, blockTags)\n\t\t}\n\t}\n}\n\nfunc addIothreadMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar iothreadTotalFields = make(map[string]interface{})\n\tvar iothreadData = make(map[string]map[string]interface{})\n\n\tvar iothreadTotalTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tif key == \"count\" {\n\t\t\tiothreadTotalFields[\"count\"] = metric.I\n\t\t} else {\n\t\t\tiothreadStat := strings.Split(key, \".\")\n\t\t\tif len(iothreadStat) != 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tiothreadID := iothreadStat[0]\n\t\t\tiothreadFields, ok := iothreadData[iothreadID]\n\t\t\tif !ok {\n\t\t\t\tiothreadFields = make(map[string]interface{})\n\t\t\t\tiothreadData[iothreadID] = iothreadFields\n\t\t\t}\n\n\t\t\tfieldName := strings.ReplaceAll(iothreadStat[1], \"-\", \"_\")\n\t\t\tswitch fieldName {\n\t\t\tcase \"poll_max_ns\", \"poll_grow\", \"poll_shrink\":\n\t\t\t\tiothreadFields[fieldName] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(iothreadTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_iothread_total\", iothreadTotalFields, iothreadTotalTags)\n\t}\n\n\tfor iothreadID, iothreadFields := range iothreadData {\n\t\tif len(iothreadFields) > 0 {\n\t\t\tiothreadTags := map[string]string{\n\t\t\t\t\"domain_name\": domainName,\n\t\t\t\t\"iothread_id\": iothreadID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_iothread\", iothreadFields, iothreadTags)\n\t\t}\n\t}\n}\n\nfunc addMemoryMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar memoryBandwidthMonitorTotalFields = make(map[string]interface{})\n\n\tvar memoryBandwidthMonitorData = make(map[string]map[string]interface{})\n\tvar memoryBandwidthMonitorNodeData = make(map[string]map[string]map[string]interface{})\n\n\tvar memoryBandwidthMonitorTotalTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"bandwidth.monitor.count\":\n\t\t\tmemoryBandwidthMonitorTotalFields[\"count\"] = metric.I\n\t\tdefault:\n\t\t\tif strings.Contains(key, \"node.count\") {\n\t\t\t\tkey = strings.ReplaceAll(key, \"node.count\", \"node_count\")\n\t\t\t} else if strings.Contains(key, \"bytes.local\") {\n\t\t\t\tkey = strings.ReplaceAll(key, \"bytes.local\", \"bytes_local\")\n\t\t\t} else if strings.Contains(key, \"bytes.total\") {\n\t\t\t\tkey = strings.ReplaceAll(key, \"bytes.total\", \"bytes_total\")\n\t\t\t}\n\n\t\t\tmemoryStat := strings.Split(key, \".\")\n\t\t\tif len(memoryStat) == 4 && memoryBandwidthMonitorRegexp.MatchString(key) {\n\t\t\t\tmemoryBandwidthMonitorID := memoryStat[2]\n\t\t\t\tmemoryBandwidthMonitorFields, ok := memoryBandwidthMonitorData[memoryBandwidthMonitorID]\n\t\t\t\tif !ok {\n\t\t\t\t\tmemoryBandwidthMonitorFields = make(map[string]interface{})\n\t\t\t\t\tmemoryBandwidthMonitorData[memoryBandwidthMonitorID] = memoryBandwidthMonitorFields\n\t\t\t\t}\n\n\t\t\t\tmemoryBandwidthMonitorFields[memoryStat[3]] = metric.I\n\t\t\t} else if len(memoryStat) == 6 && memoryBandwidthMonitorNodeRegexp.MatchString(key) {\n\t\t\t\tmemoryBandwidthMonitorID := memoryStat[2]\n\t\t\t\tcontrollerIndex := memoryStat[4]\n\n\t\t\t\tnodeData, ok := memoryBandwidthMonitorNodeData[memoryBandwidthMonitorID]\n\t\t\t\tif !ok {\n\t\t\t\t\tnodeData = make(map[string]map[string]interface{})\n\t\t\t\t\tmemoryBandwidthMonitorNodeData[memoryBandwidthMonitorID] = nodeData\n\t\t\t\t}\n\n\t\t\t\tnodeFields, ok := memoryBandwidthMonitorNodeData[memoryBandwidthMonitorID][controllerIndex]\n\t\t\t\tif !ok {\n\t\t\t\t\tnodeFields = make(map[string]interface{})\n\t\t\t\t\tnodeData[controllerIndex] = nodeFields\n\t\t\t\t}\n\n\t\t\t\tnodeFields[memoryStat[5]] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(memoryBandwidthMonitorTotalFields) > 0 {\n\t\tacc.AddFields(\"libvirt_memory_bandwidth_monitor_total\", memoryBandwidthMonitorTotalFields, memoryBandwidthMonitorTotalTags)\n\t}\n\n\tfor memoryBandwidthMonitorID, memoryFields := range memoryBandwidthMonitorData {\n\t\tif len(memoryFields) > 0 {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"domain_name\":                 domainName,\n\t\t\t\t\"memory_bandwidth_monitor_id\": memoryBandwidthMonitorID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_memory_bandwidth_monitor\", memoryFields, tags)\n\t\t}\n\t}\n\n\tfor memoryBandwidthMonitorID, nodeData := range memoryBandwidthMonitorNodeData {\n\t\tfor controllerIndex, nodeFields := range nodeData {\n\t\t\tif len(nodeFields) > 0 {\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"domain_name\":                 domainName,\n\t\t\t\t\t\"memory_bandwidth_monitor_id\": memoryBandwidthMonitorID,\n\t\t\t\t\t\"controller_index\":            controllerIndex,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"libvirt_memory_bandwidth_monitor_node\", nodeFields, tags)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc addDirtyrateMetrics(metrics map[string]golibvirt.TypedParamValue, domainName string, acc telegraf.Accumulator) {\n\tvar dirtyrateFields = make(map[string]interface{})\n\tvar dirtyrateVcpuData = make(map[string]map[string]interface{})\n\n\tvar dirtyrateTags = map[string]string{\n\t\t\"domain_name\": domainName,\n\t}\n\n\tfor key, metric := range metrics {\n\t\tswitch key {\n\t\tcase \"calc_status\", \"calc_start_time\", \"calc_period\",\n\t\t\t\"megabytes_per_second\", \"calc_mode\":\n\t\t\tdirtyrateFields[key] = metric.I\n\t\tdefault:\n\t\t\tdirtyrateStat := strings.Split(key, \".\")\n\t\t\tif len(dirtyrateStat) == 3 && dirtyrateStat[0] == \"vcpu\" && dirtyrateStat[2] == \"megabytes_per_second\" {\n\t\t\t\tvcpuID := dirtyrateStat[1]\n\t\t\t\tdirtyRateFields, ok := dirtyrateVcpuData[vcpuID]\n\t\t\t\tif !ok {\n\t\t\t\t\tdirtyRateFields = make(map[string]interface{})\n\t\t\t\t\tdirtyrateVcpuData[vcpuID] = dirtyRateFields\n\t\t\t\t}\n\t\t\t\tdirtyRateFields[dirtyrateStat[2]] = metric.I\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(dirtyrateFields) > 0 {\n\t\tacc.AddFields(\"libvirt_dirtyrate\", dirtyrateFields, dirtyrateTags)\n\t}\n\n\tfor vcpuID, dirtyRateFields := range dirtyrateVcpuData {\n\t\tif len(dirtyRateFields) > 0 {\n\t\t\tdirtyRateTags := map[string]string{\n\t\t\t\t\"domain_name\": domainName,\n\t\t\t\t\"vcpu_id\":     vcpuID,\n\t\t\t}\n\t\t\tacc.AddFields(\"libvirt_dirtyrate_vcpu\", dirtyRateFields, dirtyRateTags)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/libvirt/libvirt_test.go",
    "content": "package libvirt\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\tgolibvirt \"github.com/digitalocean/go-libvirt\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestLibvirt_Init(t *testing.T) {\n\tt.Run(\"throw error when user provided duplicated state metric name\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: []string{\"state\", \"state\"},\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.Init()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"duplicated statistics group in config\")\n\t})\n\n\tt.Run(\"throw error when user provided wrong metric name\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: []string{\"statusQvo\"},\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.Init()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"unrecognized metrics name\")\n\t})\n\n\tt.Run(\"throw error when user provided invalid uri\", func(t *testing.T) {\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tLibvirtURI: \"this/is/wrong/uri\",\n\t\t\tutils:      &mockUtils,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\terr := l.Init()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"can't parse\")\n\t})\n\n\tt.Run(\"successfully initialize libvirt on correct user input\", func(t *testing.T) {\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: []string{\"state\", \"cpu_total\", \"vcpu\", \"interface\"},\n\t\t\tutils:            &mockUtils,\n\t\t\tLibvirtURI:       defaultLibvirtURI,\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.Init()\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestLibvirt_Gather(t *testing.T) {\n\tt.Run(\"wrong uri throws error\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tLibvirtURI: \"this/is/wrong/uri\",\n\t\t\tLog:        testutil.Logger{},\n\t\t\tutils:      &mockUtils,\n\t\t}\n\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(errors.New(\"failed to connect\")).Once()\n\t\terr := l.Gather(&acc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"failed to connect\")\n\t\tmockUtils.AssertExpectations(t)\n\t})\n\n\tt.Run(\"error when read error happened in gathering domains\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tutils:            &mockUtils,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tStatisticsGroups: []string{\"state\"},\n\t\t}\n\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(nil).Once().\n\t\t\tOn(\"gatherAllDomains\", mock.Anything).Return(nil, errors.New(\"gather domain error\")).Once().\n\t\t\tOn(\"disconnect\").Return(nil).Once()\n\n\t\terr := l.Gather(&acc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"gather domain error\")\n\t\tmockUtils.AssertExpectations(t)\n\t})\n\n\tt.Run(\"no error when empty list of domains is returned\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tutils:            &mockUtils,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tStatisticsGroups: []string{\"state\"},\n\t\t}\n\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(nil).Once().\n\t\t\tOn(\"gatherAllDomains\", mock.Anything).Return(nil, nil).Once()\n\n\t\terr := l.Gather(&acc)\n\t\trequire.NoError(t, err)\n\t\tmockUtils.AssertExpectations(t)\n\t})\n\n\tt.Run(\"error when gathering metrics by number\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\tmockUtils := mockLibvirtUtils{}\n\t\tl := Libvirt{\n\t\t\tutils:            &mockUtils,\n\t\t\tLog:              testutil.Logger{},\n\t\t\tStatisticsGroups: []string{\"state\"},\n\t\t}\n\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(nil).Once().\n\t\t\tOn(\"gatherAllDomains\", mock.Anything).Return(domains, nil).Once().\n\t\t\tOn(\"gatherStatsForDomains\", mock.Anything, mock.Anything).\n\t\t\tReturn(nil, errors.New(\"gathering metric by number error\")).Once().\n\t\t\tOn(\"disconnect\").Return(nil).Once()\n\n\t\terr := l.Init()\n\t\trequire.NoError(t, err)\n\n\t\terr = l.Gather(&acc)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"gathering metric by number error\")\n\t\tmockUtils.AssertExpectations(t)\n\t})\n\n\tvar successfulTests = []struct {\n\t\ttestName        string\n\t\tallDomains      interface{}\n\t\texcludeDomains  []string\n\t\tstatsForDomains interface{}\n\t\texpectedMetrics []telegraf.Metric\n\t\tvcpuMapping     []vcpuAffinity\n\t}{\n\t\t{\"successfully gather from host that has domains\", domains, nil, domainStats, append(expectedMetrics, expectedVcpuAffinityMetrics...), vcpusMapping},\n\t\t{\n\t\t\t\"successfully gather from host for excluded domain\",\n\t\t\tdomains,\n\t\t\t[]string{\"Droplet-33436\"},\n\t\t\tdomainStats[1:],\n\t\t\tappend(expectedMetrics[1:], expectedVcpuAffinityMetrics[2:]...),\n\t\t\tvcpusMapping,\n\t\t},\n\t}\n\tfor _, test := range successfulTests {\n\t\tt.Run(test.testName, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tmockUtils := mockLibvirtUtils{}\n\t\t\tl := Libvirt{\n\t\t\t\tutils:                &mockUtils,\n\t\t\t\tLog:                  testutil.Logger{},\n\t\t\t\tStatisticsGroups:     []string{\"state\"},\n\t\t\t\tDomains:              test.excludeDomains,\n\t\t\t\tAdditionalStatistics: []string{\"vcpu_mapping\"},\n\t\t\t}\n\t\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(nil).Once().\n\t\t\t\tOn(\"gatherAllDomains\", mock.Anything).Return(test.allDomains, nil).Once().\n\t\t\t\tOn(\"gatherVcpuMapping\", domains[0], mock.Anything, mock.Anything).Return(test.vcpuMapping, nil).Maybe().\n\t\t\t\tOn(\"gatherVcpuMapping\", domains[1], mock.Anything, mock.Anything).Return(test.vcpuMapping, nil).Once().\n\t\t\t\tOn(\"gatherNumberOfPCPUs\").Return(4, nil).Once().\n\t\t\t\tOn(\"gatherStatsForDomains\", mock.Anything, mock.Anything).Return(test.statsForDomains, nil).Once()\n\n\t\t\terr := l.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = l.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\texpected := test.expectedMetrics\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics(), testutil.IgnoreTime())\n\t\t\tmockUtils.AssertExpectations(t)\n\t\t})\n\t}\n}\n\nfunc TestLibvirt_GatherMetrics(t *testing.T) {\n\tvar successfulTests = []struct {\n\t\ttestName        string\n\t\tallDomains      interface{}\n\t\texcludeDomains  []string\n\t\tstatsForDomains interface{}\n\t\texpectedMetrics []telegraf.Metric\n\t\tvcpuMapping     []vcpuAffinity\n\t}{\n\t\t{\"successfully gather memory metrics from host that has domains\", domains, nil, memoryStats, expectedMemoryMetrics, nil},\n\t\t{\"successfully gather balloon metrics from host that has domains\", domains, nil, balloonStats, expectedBalloonMetrics, nil},\n\t\t{\"successfully gather perf metrics from host that has domains\", domains, nil, perfStats, expectedPerfMetrics, nil},\n\t\t{\"successfully gather cpu metrics from host that has domains\", domains, nil, cpuStats, expectedCPUMetrics, nil},\n\t\t{\"successfully gather interface metrics from host that has domains\", domains, nil, interfaceStats, expectedInterfaceMetrics, nil},\n\t\t{\"successfully gather block metrics from host that has domains\", domains, nil, blockStats, expectedBlockMetrics, nil},\n\t\t{\"successfully gather iothread metrics from host that has domains\", domains, nil, iothreadStats, expectedIOThreadMetrics, nil},\n\t\t{\"successfully gather dirtyrate metrics from host that has domains\", domains, nil, dirtyrateStats, expectedDirtyrateMetrics, nil},\n\t\t{\"successfully gather vcpu metrics from host that has domains\", domains, nil, vcpuStats, expectedVCPUMetrics, nil},\n\t\t{\"successfully gather vcpu metrics with vCPU from host that has domains\", domains, nil, vcpuStats, expectedExtendedVCPUMetrics, vcpusMapping},\n\t}\n\tfor _, test := range successfulTests {\n\t\tt.Run(test.testName, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tmockUtils := mockLibvirtUtils{}\n\t\t\tl := Libvirt{\n\t\t\t\tutils:   &mockUtils,\n\t\t\t\tLog:     testutil.Logger{},\n\t\t\t\tDomains: test.excludeDomains,\n\t\t\t}\n\n\t\t\tmockUtils.On(\"ensureConnected\", mock.Anything).Return(nil).Once().\n\t\t\t\tOn(\"gatherAllDomains\", mock.Anything).Return(test.allDomains, nil).Once().\n\t\t\t\tOn(\"gatherStatsForDomains\", mock.Anything, mock.Anything).Return(test.statsForDomains, nil).Once()\n\n\t\t\tif test.vcpuMapping != nil {\n\t\t\t\tl.vcpuMappingEnabled = true\n\t\t\t\tl.metricNumber = domainStatsVCPU\n\t\t\t\tmockUtils.On(\"gatherNumberOfPCPUs\").Return(4, nil).Once().\n\t\t\t\t\tOn(\"gatherVcpuMapping\", domains[0], mock.Anything, mock.Anything).Return(test.vcpuMapping, nil).Once().\n\t\t\t\t\tOn(\"gatherVcpuMapping\", domains[1], mock.Anything, mock.Anything).Return(nil, nil).Once()\n\t\t\t}\n\n\t\t\terr := l.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\texpected := test.expectedMetrics\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics(), testutil.IgnoreTime())\n\t\t\tmockUtils.AssertExpectations(t)\n\t\t})\n\t}\n}\n\nfunc TestLibvirt_validateLibvirtUri(t *testing.T) {\n\tt.Run(\"no error on good uri provided\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tLibvirtURI: defaultLibvirtURI,\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\terr := l.validateLibvirtURI()\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"unmarshal error on bad uri provided\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tLibvirtURI: \"this/is/invalid/uri\",\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\terr := l.validateLibvirtURI()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"can't parse '\"+l.LibvirtURI+\"' as a libvirt uri\")\n\t})\n\n\tt.Run(\"dialer error on bad ssh uri provided\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tLibvirtURI: \"qemu+ssh://invalid@host:666/system\",\n\t\t\tLog:        testutil.Logger{},\n\t\t}\n\t\terr := l.validateLibvirtURI()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"ssh transport requires keyfile parameter\")\n\t})\n}\n\nfunc TestLibvirt_calculateMetricNumber(t *testing.T) {\n\tt.Run(\"error on duplicated metric name\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: []string{\"state\", \"state\"},\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.calculateMetricNumber()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"duplicated statistics group in config\")\n\t})\n\n\tt.Run(\"error on unrecognized metric name\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: []string{\"invalidName\"},\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.calculateMetricNumber()\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"unrecognized metrics name\")\n\t})\n\n\tt.Run(\"correctly calculates metrics number provided\", func(t *testing.T) {\n\t\tmetrics := []string{\"state\", \"cpu_total\", \"vcpu\", \"interface\", \"block\", \"balloon\",\n\t\t\t\"memory\", \"perf\", \"iothread\", \"dirtyrate\"}\n\n\t\tl := Libvirt{\n\t\t\tStatisticsGroups: metrics,\n\t\t\tLog:              testutil.Logger{},\n\t\t}\n\t\terr := l.calculateMetricNumber()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, domainStatsAll, l.metricNumber)\n\t})\n}\n\nfunc TestLibvirt_filterDomains(t *testing.T) {\n\tt.Run(\"success filter domains\", func(t *testing.T) {\n\t\tl := Libvirt{\n\t\t\tDomains: []string{\"Droplet-844329\", \"Droplet-33436\"},\n\t\t\tLog:     testutil.Logger{},\n\t\t}\n\n\t\tresult := l.filterDomains(domains)\n\t\trequire.NotEmpty(t, result)\n\t})\n}\n\nvar (\n\tdomains = []golibvirt.Domain{\n\t\t{Name: \"Droplet-844329\", UUID: golibvirt.UUID{}, ID: 0},\n\t\t{Name: \"Droplet-33436\", UUID: golibvirt.UUID{}, ID: 0},\n\t}\n\n\tdomainStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"state.reason\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"state.state\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tDom: domains[1],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"state.reason\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"state.state\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t},\n\t\t},\n\t}\n\n\tmemoryStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"memory.bandwidth.monitor.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.name\", Value: *golibvirt.NewTypedParamValueString(\"any_name_vcpus_0-4\")},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.vcpus\", Value: *golibvirt.NewTypedParamValueString(\"0-4\")},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.name\", Value: *golibvirt.NewTypedParamValueString(\"vcpus_7\")},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.vcpus\", Value: *golibvirt.NewTypedParamValueString(\"7\")},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.0.id\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.0.bytes.total\", Value: *golibvirt.NewTypedParamValueLlong(10208067584)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.0.bytes.local\", Value: *golibvirt.NewTypedParamValueLlong(4807114752)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.1.id\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.1.bytes.total\", Value: *golibvirt.NewTypedParamValueLlong(8693735424)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.0.node.1.bytes.local\", Value: *golibvirt.NewTypedParamValueLlong(5850161152)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.0.id\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.0.bytes.total\", Value: *golibvirt.NewTypedParamValueLlong(853811200)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.0.bytes.local\", Value: *golibvirt.NewTypedParamValueLlong(290701312)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.1.id\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.1.bytes.total\", Value: *golibvirt.NewTypedParamValueLlong(406044672)},\n\t\t\t\t{Field: \"memory.bandwidth.monitor.1.node.1.bytes.local\", Value: *golibvirt.NewTypedParamValueLlong(229425152)},\n\t\t\t},\n\t\t},\n\t}\n\n\tcpuStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"cpu.time\", Value: *golibvirt.NewTypedParamValueLlong(67419144867000)},\n\t\t\t\t{Field: \"cpu.user\", Value: *golibvirt.NewTypedParamValueLlong(63886161852000)},\n\t\t\t\t{Field: \"cpu.system\", Value: *golibvirt.NewTypedParamValueLlong(3532983015000)},\n\t\t\t\t{Field: \"cpu.haltpoll.success.time\", Value: *golibvirt.NewTypedParamValueLlong(516907915)},\n\t\t\t\t{Field: \"cpu.haltpoll.fail.time\", Value: *golibvirt.NewTypedParamValueLlong(2727253643)},\n\t\t\t\t{Field: \"cpu.cache.monitor.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.name\", Value: *golibvirt.NewTypedParamValueString(\"any_name_vcpus_0-3\")},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.vcpus\", Value: *golibvirt.NewTypedParamValueString(\"0-3\")},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.bank.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.name\", Value: *golibvirt.NewTypedParamValueString(\"vcpus_4-9\")},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.vcpus\", Value: *golibvirt.NewTypedParamValueString(\"4-9\")},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.bank.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.bank.0.id\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.bank.0.bytes\", Value: *golibvirt.NewTypedParamValueLlong(5406720)},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.bank.1.id\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"cpu.cache.monitor.0.bank.1.bytes\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.bank.0.id\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.bank.0.bytes\", Value: *golibvirt.NewTypedParamValueLlong(720896)},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.bank.1.id\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"cpu.cache.monitor.1.bank.1.bytes\", Value: *golibvirt.NewTypedParamValueLlong(8200192)},\n\t\t\t},\n\t\t},\n\t}\n\n\tballoonStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"balloon.current\", Value: *golibvirt.NewTypedParamValueLlong(4194304)},\n\t\t\t\t{Field: \"balloon.maximum\", Value: *golibvirt.NewTypedParamValueLlong(4194304)},\n\t\t\t\t{Field: \"balloon.swap_in\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"balloon.swap_out\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"balloon.major_fault\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"balloon.minor_fault\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"balloon.unused\", Value: *golibvirt.NewTypedParamValueLlong(3928628)},\n\t\t\t\t{Field: \"balloon.available\", Value: *golibvirt.NewTypedParamValueLlong(4018480)},\n\t\t\t\t{Field: \"balloon.rss\", Value: *golibvirt.NewTypedParamValueLlong(1036012)},\n\t\t\t\t{Field: \"balloon.usable\", Value: *golibvirt.NewTypedParamValueLlong(3808724)},\n\t\t\t\t{Field: \"balloon.last-update\", Value: *golibvirt.NewTypedParamValueLlong(1654611373)},\n\t\t\t\t{Field: \"balloon.disk_caches\", Value: *golibvirt.NewTypedParamValueLlong(68820)},\n\t\t\t\t{Field: \"balloon.hugetlb_pgalloc\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"balloon.hugetlb_pgfail\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t},\n\t\t},\n\t}\n\n\tperfStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"perf.cmt\", Value: *golibvirt.NewTypedParamValueLlong(19087360)},\n\t\t\t\t{Field: \"perf.mbmt\", Value: *golibvirt.NewTypedParamValueLlong(77168640)},\n\t\t\t\t{Field: \"perf.mbml\", Value: *golibvirt.NewTypedParamValueLlong(67788800)},\n\t\t\t\t{Field: \"perf.cpu_cycles\", Value: *golibvirt.NewTypedParamValueLlong(29858995122)},\n\t\t\t\t{Field: \"perf.instructions\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"perf.cache_references\", Value: *golibvirt.NewTypedParamValueLlong(3053301695)},\n\t\t\t\t{Field: \"perf.cache_misses\", Value: *golibvirt.NewTypedParamValueLlong(609441024)},\n\t\t\t\t{Field: \"perf.branch_instructions\", Value: *golibvirt.NewTypedParamValueLlong(2623890194)},\n\t\t\t\t{Field: \"perf.branch_misses\", Value: *golibvirt.NewTypedParamValueLlong(103707961)},\n\t\t\t\t{Field: \"perf.bus_cycles\", Value: *golibvirt.NewTypedParamValueLlong(188105628)},\n\t\t\t\t{Field: \"perf.stalled_cycles_frontend\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"perf.stalled_cycles_backend\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"perf.ref_cpu_cycles\", Value: *golibvirt.NewTypedParamValueLlong(30766094039)},\n\t\t\t\t{Field: \"perf.cpu_clock\", Value: *golibvirt.NewTypedParamValueLlong(25166642695)},\n\t\t\t\t{Field: \"perf.task_clock\", Value: *golibvirt.NewTypedParamValueLlong(25263578917)},\n\t\t\t\t{Field: \"perf.page_faults\", Value: *golibvirt.NewTypedParamValueLlong(2670)},\n\t\t\t\t{Field: \"perf.context_switches\", Value: *golibvirt.NewTypedParamValueLlong(294284)},\n\t\t\t\t{Field: \"perf.cpu_migrations\", Value: *golibvirt.NewTypedParamValueLlong(17949)},\n\t\t\t\t{Field: \"perf.page_faults_min\", Value: *golibvirt.NewTypedParamValueLlong(2670)},\n\t\t\t\t{Field: \"perf.page_faults_maj\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"perf.alignment_faults\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"perf.emulation_faults\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t},\n\t\t},\n\t}\n\n\tinterfaceStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"net.count\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"net.0.name\", Value: *golibvirt.NewTypedParamValueString(\"vnet0\")},\n\t\t\t\t{Field: \"net.0.rx.bytes\", Value: *golibvirt.NewTypedParamValueLlong(110)},\n\t\t\t\t{Field: \"net.0.rx.pkts\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"net.0.rx.errs\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"net.0.rx.drop\", Value: *golibvirt.NewTypedParamValueLlong(31007)},\n\t\t\t\t{Field: \"net.0.tx.bytes\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"net.0.tx.pkts\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"net.0.tx.errs\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"net.0.tx.drop\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t},\n\t\t},\n\t}\n\n\tblockStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"block.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"block.0.name\", Value: *golibvirt.NewTypedParamValueString(\"vda\")},\n\t\t\t\t{Field: \"block.0.backingIndex\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"block.0.path\", Value: *golibvirt.NewTypedParamValueString(\"/tmp/ubuntu_image.img\")},\n\t\t\t\t{Field: \"block.0.rd.reqs\", Value: *golibvirt.NewTypedParamValueLlong(11354)},\n\t\t\t\t{Field: \"block.0.rd.bytes\", Value: *golibvirt.NewTypedParamValueLlong(330314752)},\n\t\t\t\t{Field: \"block.0.rd.times\", Value: *golibvirt.NewTypedParamValueLlong(6240559566)},\n\t\t\t\t{Field: \"block.0.wr.reqs\", Value: *golibvirt.NewTypedParamValueLlong(52440)},\n\t\t\t\t{Field: \"block.0.wr.bytes\", Value: *golibvirt.NewTypedParamValueLlong(1183828480)},\n\t\t\t\t{Field: \"block.0.wr.times\", Value: *golibvirt.NewTypedParamValueLlong(21887150375)},\n\t\t\t\t{Field: \"block.0.fl.reqs\", Value: *golibvirt.NewTypedParamValueLlong(32250)},\n\t\t\t\t{Field: \"block.0.fl.times\", Value: *golibvirt.NewTypedParamValueLlong(23158998353)},\n\t\t\t\t{Field: \"block.0.errors\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"block.0.allocation\", Value: *golibvirt.NewTypedParamValueLlong(770048000)},\n\t\t\t\t{Field: \"block.0.capacity\", Value: *golibvirt.NewTypedParamValueLlong(2361393152)},\n\t\t\t\t{Field: \"block.0.physical\", Value: *golibvirt.NewTypedParamValueLlong(770052096)},\n\t\t\t\t{Field: \"block.0.threshold\", Value: *golibvirt.NewTypedParamValueLlong(2147483648)},\n\t\t\t\t{Field: \"block.1.name\", Value: *golibvirt.NewTypedParamValueString(\"vda1\")},\n\t\t\t\t{Field: \"block.1.backingIndex\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"block.1.path\", Value: *golibvirt.NewTypedParamValueString(\"/tmp/ubuntu_image1.img\")},\n\t\t\t\t{Field: \"block.1.rd.reqs\", Value: *golibvirt.NewTypedParamValueLlong(11354)},\n\t\t\t\t{Field: \"block.1.rd.bytes\", Value: *golibvirt.NewTypedParamValueLlong(330314752)},\n\t\t\t\t{Field: \"block.1.rd.times\", Value: *golibvirt.NewTypedParamValueLlong(6240559566)},\n\t\t\t\t{Field: \"block.1.wr.reqs\", Value: *golibvirt.NewTypedParamValueLlong(52440)},\n\t\t\t\t{Field: \"block.1.wr.bytes\", Value: *golibvirt.NewTypedParamValueLlong(1183828480)},\n\t\t\t\t{Field: \"block.1.wr.times\", Value: *golibvirt.NewTypedParamValueLlong(21887150375)},\n\t\t\t\t{Field: \"block.1.fl.reqs\", Value: *golibvirt.NewTypedParamValueLlong(32250)},\n\t\t\t\t{Field: \"block.1.fl.times\", Value: *golibvirt.NewTypedParamValueLlong(23158998353)},\n\t\t\t\t{Field: \"block.1.errors\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"block.1.allocation\", Value: *golibvirt.NewTypedParamValueLlong(770048000)},\n\t\t\t\t{Field: \"block.1.capacity\", Value: *golibvirt.NewTypedParamValueLlong(2361393152)},\n\t\t\t\t{Field: \"block.1.physical\", Value: *golibvirt.NewTypedParamValueLlong(770052096)},\n\t\t\t\t{Field: \"block.1.threshold\", Value: *golibvirt.NewTypedParamValueLlong(2147483648)},\n\t\t\t},\n\t\t},\n\t}\n\n\tiothreadStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"iothread.count\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"iothread.0.poll-max-ns\", Value: *golibvirt.NewTypedParamValueLlong(32768)},\n\t\t\t\t{Field: \"iothread.0.poll-grow\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"iothread.0.poll-shrink\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"iothread.1.poll-max-ns\", Value: *golibvirt.NewTypedParamValueLlong(32769)},\n\t\t\t\t{Field: \"iothread.1.poll-grow\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"iothread.1.poll-shrink\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t},\n\t\t},\n\t}\n\n\tdirtyrateStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"dirtyrate.calc_status\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t\t{Field: \"dirtyrate.calc_start_time\", Value: *golibvirt.NewTypedParamValueLlong(348414)},\n\t\t\t\t{Field: \"dirtyrate.calc_period\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"dirtyrate.megabytes_per_second\", Value: *golibvirt.NewTypedParamValueLlong(4)},\n\t\t\t\t{Field: \"dirtyrate.calc_mode\", Value: *golibvirt.NewTypedParamValueString(\"dirty-ring\")},\n\t\t\t\t{Field: \"dirtyrate.vcpu.0.megabytes_per_second\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"dirtyrate.vcpu.1.megabytes_per_second\", Value: *golibvirt.NewTypedParamValueLlong(2)},\n\t\t\t},\n\t\t},\n\t}\n\n\tvcpuStats = []golibvirt.DomainStatsRecord{\n\t\t{\n\t\t\tDom: domains[0],\n\t\t\tParams: []golibvirt.TypedParam{\n\t\t\t\t{Field: \"vcpu.current\", Value: *golibvirt.NewTypedParamValueLlong(3)},\n\t\t\t\t{Field: \"vcpu.maximum\", Value: *golibvirt.NewTypedParamValueLlong(3)},\n\t\t\t\t{Field: \"vcpu.0.state\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"vcpu.0.time\", Value: *golibvirt.NewTypedParamValueLlong(17943740000000)},\n\t\t\t\t{Field: \"vcpu.0.wait\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"vcpu.0.halted\", Value: *golibvirt.NewTypedParamValueString(\"no\")},\n\t\t\t\t{Field: \"vcpu.0.delay\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"vcpu.1.state\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"vcpu.1.time\", Value: *golibvirt.NewTypedParamValueLlong(17943740000000)},\n\t\t\t\t{Field: \"vcpu.1.wait\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"vcpu.1.halted\", Value: *golibvirt.NewTypedParamValueString(\"yes\")},\n\t\t\t\t{Field: \"vcpu.1.delay\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"vcpu.2.state\", Value: *golibvirt.NewTypedParamValueLlong(1)},\n\t\t\t\t{Field: \"vcpu.2.time\", Value: *golibvirt.NewTypedParamValueLlong(17943740000000)},\n\t\t\t\t{Field: \"vcpu.2.wait\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t\t{Field: \"vcpu.2.delay\", Value: *golibvirt.NewTypedParamValueLlong(0)},\n\t\t\t},\n\t\t},\n\t}\n\n\tvcpusMapping = []vcpuAffinity{\n\t\t{\"0\", \"0,1,2,3\", 0},\n\t\t{\"1\", \"1,2,3,4\", 1},\n\t}\n\n\texpectedMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_state\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reason\": 2,\n\t\t\t\t\"state\":  1,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_state\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-33436\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reason\": 1,\n\t\t\t\t\"state\":  1,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedMemoryMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor_total\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":       \"any_name_vcpus_0-4\",\n\t\t\t\t\"vcpus\":      \"0-4\",\n\t\t\t\t\"node_count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":       \"vcpus_7\",\n\t\t\t\t\"vcpus\":      \"7\",\n\t\t\t\t\"node_count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor_node\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"0\", \"controller_index\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":          0,\n\t\t\t\t\"bytes_total\": int64(10208067584),\n\t\t\t\t\"bytes_local\": int64(4807114752),\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor_node\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"0\", \"controller_index\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"bytes_total\": int64(8693735424),\n\t\t\t\t\"bytes_local\": int64(5850161152),\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor_node\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"1\", \"controller_index\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":          0,\n\t\t\t\t\"bytes_total\": 853811200,\n\t\t\t\t\"bytes_local\": 290701312,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_memory_bandwidth_monitor_node\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"memory_bandwidth_monitor_id\": \"1\", \"controller_index\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"bytes_total\": 406044672,\n\t\t\t\t\"bytes_local\": 229425152,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedCPUMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_cpu\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"time\":                  int64(67419144867000),\n\t\t\t\t\"user\":                  int64(63886161852000),\n\t\t\t\t\"system\":                int64(3532983015000),\n\t\t\t\t\"haltpoll_success_time\": 516907915,\n\t\t\t\t\"haltpoll_fail_time\":    int64(2727253643),\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor_total\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":       \"any_name_vcpus_0-3\",\n\t\t\t\t\"vcpus\":      \"0-3\",\n\t\t\t\t\"bank_count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":       \"vcpus_4-9\",\n\t\t\t\t\"vcpus\":      \"4-9\",\n\t\t\t\t\"bank_count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor_bank\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"0\", \"bank_index\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":    0,\n\t\t\t\t\"bytes\": 5406720,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor_bank\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"0\", \"bank_index\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":    1,\n\t\t\t\t\"bytes\": 0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor_bank\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"1\", \"bank_index\": \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":    0,\n\t\t\t\t\"bytes\": 720896,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_cache_monitor_bank\",\n\t\t\tmap[string]string{\"domain_name\": \"Droplet-844329\", \"cache_monitor_id\": \"1\", \"bank_index\": \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"id\":    1,\n\t\t\t\t\"bytes\": 8200192,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedVcpuAffinityMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"0,1,2,3\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"1,2,3,4\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-33436\",\n\t\t\t\t\"vcpu_id\":     \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"0,1,2,3\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-33436\",\n\t\t\t\t\"vcpu_id\":     \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"1,2,3,4\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedBalloonMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_balloon\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current\":         4194304,\n\t\t\t\t\"maximum\":         4194304,\n\t\t\t\t\"swap_in\":         0,\n\t\t\t\t\"swap_out\":        0,\n\t\t\t\t\"major_fault\":     0,\n\t\t\t\t\"minor_fault\":     0,\n\t\t\t\t\"unused\":          3928628,\n\t\t\t\t\"available\":       4018480,\n\t\t\t\t\"rss\":             1036012,\n\t\t\t\t\"usable\":          3808724,\n\t\t\t\t\"last_update\":     1654611373,\n\t\t\t\t\"disk_caches\":     68820,\n\t\t\t\t\"hugetlb_pgalloc\": 0,\n\t\t\t\t\"hugetlb_pgfail\":  0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedPerfMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_perf\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cmt\":                     19087360,\n\t\t\t\t\"mbmt\":                    77168640,\n\t\t\t\t\"mbml\":                    67788800,\n\t\t\t\t\"cpu_cycles\":              int64(29858995122),\n\t\t\t\t\"instructions\":            0,\n\t\t\t\t\"cache_references\":        int64(3053301695),\n\t\t\t\t\"cache_misses\":            609441024,\n\t\t\t\t\"branch_instructions\":     int64(2623890194),\n\t\t\t\t\"branch_misses\":           103707961,\n\t\t\t\t\"bus_cycles\":              188105628,\n\t\t\t\t\"stalled_cycles_frontend\": 0,\n\t\t\t\t\"stalled_cycles_backend\":  0,\n\t\t\t\t\"ref_cpu_cycles\":          int64(30766094039),\n\t\t\t\t\"cpu_clock\":               int64(25166642695),\n\t\t\t\t\"task_clock\":              int64(25263578917),\n\t\t\t\t\"page_faults\":             2670,\n\t\t\t\t\"context_switches\":        294284,\n\t\t\t\t\"cpu_migrations\":          17949,\n\t\t\t\t\"page_faults_min\":         2670,\n\t\t\t\t\"page_faults_maj\":         0,\n\t\t\t\t\"alignment_faults\":        0,\n\t\t\t\t\"emulation_faults\":        0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedInterfaceMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_net_total\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\": 1,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_net\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\":  \"Droplet-844329\",\n\t\t\t\t\"interface_id\": \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":     \"vnet0\",\n\t\t\t\t\"rx_bytes\": 110,\n\t\t\t\t\"rx_pkts\":  1,\n\t\t\t\t\"rx_errs\":  0,\n\t\t\t\t\"rx_drop\":  31007,\n\t\t\t\t\"tx_bytes\": 0,\n\t\t\t\t\"tx_pkts\":  0,\n\t\t\t\t\"tx_errs\":  0,\n\t\t\t\t\"tx_drop\":  0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedBlockMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_block_total\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_block\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"block_id\":    \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":         \"vda\",\n\t\t\t\t\"backingIndex\": 1,\n\t\t\t\t\"path\":         \"/tmp/ubuntu_image.img\",\n\t\t\t\t\"rd_reqs\":      11354,\n\t\t\t\t\"rd_bytes\":     330314752,\n\t\t\t\t\"rd_times\":     int64(6240559566),\n\t\t\t\t\"wr_reqs\":      52440,\n\t\t\t\t\"wr_bytes\":     1183828480,\n\t\t\t\t\"wr_times\":     int64(21887150375),\n\t\t\t\t\"fl_reqs\":      32250,\n\t\t\t\t\"fl_times\":     int64(23158998353),\n\t\t\t\t\"errors\":       0,\n\t\t\t\t\"allocation\":   770048000,\n\t\t\t\t\"capacity\":     int64(2361393152),\n\t\t\t\t\"physical\":     770052096,\n\t\t\t\t\"threshold\":    int64(2147483648),\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_block\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"block_id\":    \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\":         \"vda1\",\n\t\t\t\t\"backingIndex\": 1,\n\t\t\t\t\"path\":         \"/tmp/ubuntu_image1.img\",\n\t\t\t\t\"rd_reqs\":      11354,\n\t\t\t\t\"rd_bytes\":     330314752,\n\t\t\t\t\"rd_times\":     int64(6240559566),\n\t\t\t\t\"wr_reqs\":      52440,\n\t\t\t\t\"wr_bytes\":     1183828480,\n\t\t\t\t\"wr_times\":     int64(21887150375),\n\t\t\t\t\"fl_reqs\":      32250,\n\t\t\t\t\"fl_times\":     int64(23158998353),\n\t\t\t\t\"errors\":       0,\n\t\t\t\t\"allocation\":   770048000,\n\t\t\t\t\"capacity\":     int64(2361393152),\n\t\t\t\t\"physical\":     770052096,\n\t\t\t\t\"threshold\":    int64(2147483648),\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedIOThreadMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_iothread_total\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"count\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_iothread\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"iothread_id\": \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"poll_max_ns\": 32768,\n\t\t\t\t\"poll_grow\":   0,\n\t\t\t\t\"poll_shrink\": 0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_iothread\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"iothread_id\": \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"poll_max_ns\": 32769,\n\t\t\t\t\"poll_grow\":   0,\n\t\t\t\t\"poll_shrink\": 0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedDirtyrateMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_dirtyrate\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"calc_status\":          2,\n\t\t\t\t\"calc_start_time\":      348414,\n\t\t\t\t\"calc_period\":          1,\n\t\t\t\t\"megabytes_per_second\": 4,\n\t\t\t\t\"calc_mode\":            \"dirty-ring\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_dirtyrate_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"megabytes_per_second\": 1,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_dirtyrate_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"megabytes_per_second\": 2,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedVCPUMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_vcpu_total\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current\": 3,\n\t\t\t\t\"maximum\": 3,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\":    1,\n\t\t\t\t\"time\":     int64(17943740000000),\n\t\t\t\t\"wait\":     0,\n\t\t\t\t\"halted\":   \"no\",\n\t\t\t\t\"halted_i\": 0,\n\t\t\t\t\"delay\":    0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\":    1,\n\t\t\t\t\"time\":     int64(17943740000000),\n\t\t\t\t\"wait\":     0,\n\t\t\t\t\"halted\":   \"yes\",\n\t\t\t\t\"halted_i\": 1,\n\t\t\t\t\"delay\":    0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\": 1,\n\t\t\t\t\"time\":  int64(17943740000000),\n\t\t\t\t\"wait\":  0,\n\t\t\t\t\"delay\": 0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n\n\texpectedExtendedVCPUMetrics = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"0,1,2,3\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_cpu_affinity\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"cpu_id\": \"1,2,3,4\",\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu_total\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"current\": 3,\n\t\t\t\t\"maximum\": 3,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\":    1,\n\t\t\t\t\"time\":     int64(17943740000000),\n\t\t\t\t\"wait\":     0,\n\t\t\t\t\"halted\":   \"no\",\n\t\t\t\t\"halted_i\": 0,\n\t\t\t\t\"delay\":    0,\n\t\t\t\t\"cpu_id\":   0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\":    1,\n\t\t\t\t\"time\":     int64(17943740000000),\n\t\t\t\t\"wait\":     0,\n\t\t\t\t\"halted\":   \"yes\",\n\t\t\t\t\"halted_i\": 1,\n\t\t\t\t\"delay\":    0,\n\t\t\t\t\"cpu_id\":   1,\n\t\t\t},\n\t\t\ttime.Now()),\n\t\ttestutil.MustMetric(\"libvirt_vcpu\",\n\t\t\tmap[string]string{\n\t\t\t\t\"domain_name\": \"Droplet-844329\",\n\t\t\t\t\"vcpu_id\":     \"2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"state\": 1,\n\t\t\t\t\"time\":  int64(17943740000000),\n\t\t\t\t\"wait\":  0,\n\t\t\t\t\"delay\": 0,\n\t\t\t},\n\t\t\ttime.Now()),\n\t}\n)\n"
  },
  {
    "path": "plugins/inputs/libvirt/libvirt_utils.go",
    "content": "package libvirt\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\tgolibvirt \"github.com/digitalocean/go-libvirt\"\n\tlibvirtutils \"github.com/thomasklein94/packer-plugin-libvirt/libvirt-utils\"\n)\n\ntype utils interface {\n\tgatherAllDomains() (domains []golibvirt.Domain, err error)\n\tgatherStatsForDomains(domains []golibvirt.Domain, metricNumber uint32) ([]golibvirt.DomainStatsRecord, error)\n\tgatherNumberOfPCPUs() (int, error)\n\tgatherVcpuMapping(domain golibvirt.Domain, pCPUs int, shouldGetCurrentPCPU bool) ([]vcpuAffinity, error)\n\tensureConnected(libvirtURI string) error\n\tdisconnect() error\n}\n\ntype utilsImpl struct {\n\tlibvirt *golibvirt.Libvirt\n}\n\ntype vcpuAffinity struct {\n\tvcpuID        string\n\tcoresAffinity string\n\tcurrentPCPUID int32\n}\n\n// gatherAllDomains gathers all domains on system\nfunc (l *utilsImpl) gatherAllDomains() (domains []golibvirt.Domain, err error) {\n\tallDomainStatesFlag := golibvirt.ConnectListDomainsRunning + golibvirt.ConnectListDomainsPaused +\n\t\tgolibvirt.ConnectListDomainsShutoff + golibvirt.ConnectListDomainsOther\n\n\tdomains, _, err = l.libvirt.ConnectListAllDomains(1, allDomainStatesFlag)\n\treturn domains, err\n}\n\n// gatherStatsForDomains gathers stats for given domains based on number that was previously calculated\nfunc (l *utilsImpl) gatherStatsForDomains(domains []golibvirt.Domain, metricNumber uint32) ([]golibvirt.DomainStatsRecord, error) {\n\tif metricNumber == 0 {\n\t\t// do not need to do expensive call if no stats were set to gather\n\t\treturn nil, nil\n\t}\n\n\tallDomainStatesFlag := golibvirt.ConnectGetAllDomainsStatsRunning + golibvirt.ConnectGetAllDomainsStatsPaused +\n\t\tgolibvirt.ConnectGetAllDomainsStatsShutoff + golibvirt.ConnectGetAllDomainsStatsOther\n\n\treturn l.libvirt.ConnectGetAllDomainStats(domains, metricNumber, uint32(allDomainStatesFlag))\n}\n\nfunc (l *utilsImpl) gatherNumberOfPCPUs() (int, error) {\n\t//nolint:dogsled //Using only needed values from library function\n\t_, _, _, _, nodes, sockets, cores, threads, err := l.libvirt.NodeGetInfo()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn int(nodes * sockets * cores * threads), nil\n}\n\n// gatherVcpuMapping is based on official go-libvirt library:\n// https://github.com/libvirt/libvirt-go-module/blob/268a5d02e00cc9b3d5d7fa6c08d753071e7d14b8/domain.go#L4516\n// (this library cannot be used here because of C bindings)\nfunc (l *utilsImpl) gatherVcpuMapping(domain golibvirt.Domain, pCPUs int, shouldGetCurrentPCPU bool) ([]vcpuAffinity, error) {\n\t//nolint:dogsled //Using only needed values from library function\n\t_, _, _, vCPUs, _, err := l.libvirt.DomainGetInfo(domain)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbytesToHoldPCPUs := (pCPUs + 7) / 8\n\n\tcpuInfo, vcpuPinInfo, err := l.libvirt.DomainGetVcpus(domain, int32(vCPUs), int32(bytesToHoldPCPUs))\n\tif err != nil {\n\t\t// DomainGetVcpus gets not only affinity (1:N mapping from VCPU to PCPU)\n\t\t// but also realtime 1:1 mapping from VCPU to PCPU\n\t\t// Unfortunately it will return nothing (only error) for inactive domains -> for that case use\n\t\t// DomainGetVcpuPinInfo (which only gets affinity but even for inactive domains)\n\n\t\tvcpuPinInfo, _, err = l.libvirt.DomainGetVcpuPinInfo(domain, int32(vCPUs), int32(bytesToHoldPCPUs), uint32(golibvirt.DomainAffectCurrent))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar vcpuAffinities []vcpuAffinity\n\tfor i := 0; i < int(vCPUs); i++ {\n\t\tvar coresAffinity []string\n\t\tfor j := 0; j < pCPUs; j++ {\n\t\t\taByte := (i * bytesToHoldPCPUs) + (j / 8)\n\t\t\taBit := j % 8\n\n\t\t\tif (vcpuPinInfo[aByte] & (1 << uint(aBit))) != 0 {\n\t\t\t\tcoresAffinity = append(coresAffinity, strconv.Itoa(j))\n\t\t\t}\n\t\t}\n\n\t\tvcpu := vcpuAffinity{\n\t\t\tvcpuID:        strconv.FormatInt(int64(i), 10),\n\t\t\tcoresAffinity: strings.Join(coresAffinity, \",\"),\n\t\t\tcurrentPCPUID: -1,\n\t\t}\n\n\t\tif shouldGetCurrentPCPU && i < len(cpuInfo) {\n\t\t\tvcpu.currentPCPUID = cpuInfo[i].CPU\n\t\t}\n\n\t\tif len(coresAffinity) > 0 {\n\t\t\tvcpuAffinities = append(vcpuAffinities, vcpu)\n\t\t}\n\t}\n\n\treturn vcpuAffinities, nil\n}\n\nfunc (l *utilsImpl) ensureConnected(libvirtURI string) error {\n\tif isConnected(l.libvirt) {\n\t\treturn nil\n\t}\n\n\tdriver, err := libvirtutils.ConnectByUriString(libvirtURI)\n\tif err != nil {\n\t\treturn err\n\t}\n\tl.libvirt = driver\n\treturn nil\n}\n\nfunc (l *utilsImpl) disconnect() error {\n\tl.libvirt = nil\n\treturn nil\n}\n\nfunc isConnected(driver *golibvirt.Libvirt) bool {\n\tif driver == nil {\n\t\treturn false\n\t}\n\n\tselect {\n\tcase <-driver.Disconnected():\n\t\treturn false\n\tdefault:\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "plugins/inputs/libvirt/libvirt_utils_mock.go",
    "content": "// Code generated by mockery v2.46.3. DO NOT EDIT.\n\npackage libvirt\n\nimport (\n\tgo_libvirt \"github.com/digitalocean/go-libvirt\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// mockLibvirtUtils is an autogenerated mock type for the utils type\ntype mockLibvirtUtils struct {\n\tmock.Mock\n}\n\n// disconnect provides a mock function with given fields:\nfunc (_m *mockLibvirtUtils) disconnect() error {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for disconnect\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// ensureConnected provides a mock function with given fields: libvirtURI\nfunc (_m *mockLibvirtUtils) ensureConnected(libvirtURI string) error {\n\tret := _m.Called(libvirtURI)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for ensureConnected\")\n\t}\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(string) error); ok {\n\t\tr0 = rf(libvirtURI)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// gatherAllDomains provides a mock function with given fields:\nfunc (_m *mockLibvirtUtils) gatherAllDomains() ([]go_libvirt.Domain, error) {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for gatherAllDomains\")\n\t}\n\n\tvar r0 []go_libvirt.Domain\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func() ([]go_libvirt.Domain, error)); ok {\n\t\treturn rf()\n\t}\n\tif rf, ok := ret.Get(0).(func() []go_libvirt.Domain); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]go_libvirt.Domain)\n\t\t}\n\t}\n\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// gatherNumberOfPCPUs provides a mock function with given fields:\nfunc (_m *mockLibvirtUtils) gatherNumberOfPCPUs() (int, error) {\n\tret := _m.Called()\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for gatherNumberOfPCPUs\")\n\t}\n\n\tvar r0 int\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func() (int, error)); ok {\n\t\treturn rf()\n\t}\n\tif rf, ok := ret.Get(0).(func() int); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// gatherStatsForDomains provides a mock function with given fields: domains, metricNumber\nfunc (_m *mockLibvirtUtils) gatherStatsForDomains(domains []go_libvirt.Domain, metricNumber uint32) ([]go_libvirt.DomainStatsRecord, error) {\n\tret := _m.Called(domains, metricNumber)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for gatherStatsForDomains\")\n\t}\n\n\tvar r0 []go_libvirt.DomainStatsRecord\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func([]go_libvirt.Domain, uint32) ([]go_libvirt.DomainStatsRecord, error)); ok {\n\t\treturn rf(domains, metricNumber)\n\t}\n\tif rf, ok := ret.Get(0).(func([]go_libvirt.Domain, uint32) []go_libvirt.DomainStatsRecord); ok {\n\t\tr0 = rf(domains, metricNumber)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]go_libvirt.DomainStatsRecord)\n\t\t}\n\t}\n\n\tif rf, ok := ret.Get(1).(func([]go_libvirt.Domain, uint32) error); ok {\n\t\tr1 = rf(domains, metricNumber)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// gatherVcpuMapping provides a mock function with given fields: domain, pCPUs, shouldGetCurrentPCPU\nfunc (_m *mockLibvirtUtils) gatherVcpuMapping(domain go_libvirt.Domain, pCPUs int, shouldGetCurrentPCPU bool) ([]vcpuAffinity, error) {\n\tret := _m.Called(domain, pCPUs, shouldGetCurrentPCPU)\n\n\tif len(ret) == 0 {\n\t\tpanic(\"no return value specified for gatherVcpuMapping\")\n\t}\n\n\tvar r0 []vcpuAffinity\n\tvar r1 error\n\tif rf, ok := ret.Get(0).(func(go_libvirt.Domain, int, bool) ([]vcpuAffinity, error)); ok {\n\t\treturn rf(domain, pCPUs, shouldGetCurrentPCPU)\n\t}\n\tif rf, ok := ret.Get(0).(func(go_libvirt.Domain, int, bool) []vcpuAffinity); ok {\n\t\tr0 = rf(domain, pCPUs, shouldGetCurrentPCPU)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]vcpuAffinity)\n\t\t}\n\t}\n\n\tif rf, ok := ret.Get(1).(func(go_libvirt.Domain, int, bool) error); ok {\n\t\tr1 = rf(domain, pCPUs, shouldGetCurrentPCPU)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// newMockLibvirtUtils creates a new instance of mockLibvirtUtils. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.\n// The first argument is typically a *testing.T value.\nfunc newMockLibvirtUtils(t interface {\n\tmock.TestingT\n\tCleanup(func())\n}) *mockLibvirtUtils {\n\tmock := &mockLibvirtUtils{}\n\tmock.Mock.Test(t)\n\n\tt.Cleanup(func() { mock.AssertExpectations(t) })\n\n\treturn mock\n}\n"
  },
  {
    "path": "plugins/inputs/libvirt/sample.conf",
    "content": "# The libvirt plugin collects statistics from virtualized guests using virtualization libvirt API.\n[[inputs.libvirt]]\n     ## Domain names from which libvirt gather statistics.\n     ## By default (empty or missing array) the plugin gather statistics from each domain registered in the host system.\n     # domains = []\n\n     ## Libvirt connection URI with hypervisor.\n     ## The plugin supports multiple transport protocols and approaches which are configurable via the URI.\n     ## The general URI form: driver[+transport]://[username@][hostname][:port]/[path][?extraparameters]\n     ## Supported transport protocols: ssh, tcp, tls, unix\n     ## URI examples for each type of transport protocol:\n     ## 1. SSH:  qemu+ssh://<USER@IP_OR_HOSTNAME>/system?keyfile=/<PATH_TO_PRIVATE_KEY>&known_hosts=/<PATH_TO_known_hosts>\n     ## 2. TCP:  qemu+tcp://<IP_OR_HOSTNAME>/system\n     ## 3. TLS:  qemu+tls://<HOSTNAME>/system?pkipath=/certs_dir/<COMMON_LOCATION_OF_CACERT_AND_SERVER_CLIENT_CERTS>\n     ## 4. UNIX: qemu+unix:///system?socket=/<PATH_TO_libvirt-sock>\n     ## Default URI is qemu:///system\n     # libvirt_uri = \"qemu:///system\"\n\n     ## Statistics groups for which libvirt plugin will gather statistics.\n     ## Supported statistics groups: state, cpu_total, balloon, vcpu, interface, block, perf, iothread, memory, dirtyrate\n     ## Empty array means no metrics for statistics groups will be exposed by the plugin.\n     ## By default the plugin will gather all available statistics.\n     # statistics_groups = [\"state\", \"cpu_total\", \"balloon\", \"vcpu\", \"interface\", \"block\", \"perf\", \"iothread\", \"memory\", \"dirtyrate\"]\n\n     ## A list containing additional statistics to be exposed by libvirt plugin.\n     ## Supported additional statistics: vcpu_mapping\n     ## By default (empty or missing array) the plugin will not collect additional statistics.\n     # additional_statistics = []\n\n"
  },
  {
    "path": "plugins/inputs/linux_cpu/README.md",
    "content": "# Linux CPU Input Plugin\n\nThis plugin gathers CPU metrics exposed on [Linux][kernel] systems.\n\n⭐ Telegraf v1.24.0\n🏷️ system\n💻 linux\n\n[kernel]: https://kernel.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Provides Linux CPU metrics\n# This plugin ONLY supports Linux\n[[inputs.linux_cpu]]\n  ## Path for sysfs filesystem.\n  ## See https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt\n  ## Defaults:\n  # host_sys = \"/sys\"\n\n  ## CPU metrics collected by the plugin.\n  ## Supported options:\n  ## \"cpufreq\", \"thermal\"\n  ## Defaults:\n  # metrics = [\"cpufreq\"]\n```\n\n## Metrics\n\nThe following tags are emitted by the plugin under the name `linux_cpu`:\n\n| Tag   | Description           |\n|-------|-----------------------|\n| `cpu` | Identifier of the CPU |\n\nThe following fields are emitted by the plugin when selecting `cpufreq`:\n\n| Metric name (field) | Description                                                | Units |\n|---------------------|------------------------------------------------------------|-------|\n| `scaling_cur_freq`  | Current frequency of the CPU as determined by CPUFreq      | KHz   |\n| `scaling_min_freq`  | Minimum frequency the governor can scale to                | KHz   |\n| `scaling_max_freq`  | Maximum frequency the governor can scale to                | KHz   |\n| `cpuinfo_cur_freq`  | Current frequency of the CPU as determined by the hardware | KHz   |\n| `cpuinfo_min_freq`  | Minimum operating frequency of the CPU                     | KHz   |\n| `cpuinfo_max_freq`  | Maximum operating frequency of the CPU                     | KHz   |\n\nThe following fields are emitted by the plugin when selecting `thermal`:\n\n| Metric name (field)   | Description                                                 | Units |\n|-----------------------|-------------------------------------------------------------|-------|\n| `throttle_count`      | Number of thermal throttle events reported by the CPU       |       |\n| `throttle_max_time`   | Maximum amount of time CPU was in throttled state           | ms    |\n| `throtlle_total_time` | Cumulative time during which the CPU was in throttled state | ms    |\n\n## Example Output\n\n```text\nlinux_cpu,cpu=0,host=go scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=803157i,scaling_min_freq=400000i 1617621150000000000\nlinux_cpu,cpu=1,host=go throttle_total_time=0i,scaling_cur_freq=802939i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i 1617621150000000000\nlinux_cpu,cpu=10,host=go throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=838343i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i 1617621150000000000\nlinux_cpu,cpu=11,host=go cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=800054i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i 1617621150000000000\nlinux_cpu,cpu=2,host=go throttle_total_time=0i,scaling_cur_freq=800404i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i 1617621150000000000\nlinux_cpu,cpu=3,host=go throttle_total_time=0i,scaling_cur_freq=800126i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i 1617621150000000000\nlinux_cpu,cpu=4,host=go cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=800359i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i 1617621150000000000\nlinux_cpu,cpu=5,host=go throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=800093i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i 1617621150000000000\nlinux_cpu,cpu=6,host=go cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=741646i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i 1617621150000000000\nlinux_cpu,cpu=7,host=go scaling_cur_freq=700006i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i 1617621150000000000\nlinux_cpu,cpu=8,host=go throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=700046i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i,throttle_count=0i 1617621150000000000\nlinux_cpu,cpu=9,host=go throttle_count=0i,throttle_max_time=0i,throttle_total_time=0i,scaling_cur_freq=700075i,scaling_min_freq=400000i,scaling_max_freq=4700000i,cpuinfo_min_freq=400000i,cpuinfo_max_freq=4700000i 1617621150000000000\n```\n"
  },
  {
    "path": "plugins/inputs/linux_cpu/linux_cpu.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage linux_cpu\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultHostSys = \"/sys\"\n\tcpufreq        = \"cpufreq\"\n\tthermal        = \"thermal\"\n)\n\ntype LinuxCPU struct {\n\tPathSysfs string          `toml:\"host_sys\"`\n\tMetrics   []string        `toml:\"metrics\"`\n\tLog       telegraf.Logger `toml:\"-\"`\n\tcpus      []cpu\n}\n\ntype cpu struct {\n\tid    string\n\tpath  string\n\tprops map[string]string\n}\n\ntype prop struct {\n\tname     string\n\tpath     string\n\toptional bool\n}\n\nfunc (*LinuxCPU) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (g *LinuxCPU) Init() error {\n\tif g.PathSysfs == \"\" {\n\t\tg.PathSysfs = defaultHostSys\n\t}\n\n\tif len(g.Metrics) == 0 {\n\t\t// The user has not enabled any of the metrics\n\t\treturn errors.New(\"no metrics selected\")\n\t}\n\n\tcpus, err := g.discoverCpus()\n\tif err != nil {\n\t\treturn err\n\t} else if len(cpus) == 0 {\n\t\t// Although the user has specified metrics to collect, `discoverCpus` failed to find the required metrics\n\t\treturn errors.New(\"no CPUs detected to track\")\n\t}\n\tg.cpus = cpus\n\n\treturn nil\n}\n\nfunc (g *LinuxCPU) Gather(acc telegraf.Accumulator) error {\n\tfor _, cpu := range g.cpus {\n\t\tfields := make(map[string]interface{})\n\t\ttags := map[string]string{\"cpu\": cpu.id}\n\n\t\tfailed := false\n\t\tfor name, propPath := range cpu.props {\n\t\t\tv, err := readUintFromFile(propPath)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\tfailed = true\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tfields[name] = v\n\t\t}\n\n\t\tif !failed {\n\t\t\tacc.AddFields(\"linux_cpu\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (g *LinuxCPU) discoverCpus() ([]cpu, error) {\n\tvar cpus []cpu\n\n\tglob := path.Join(g.PathSysfs, \"devices/system/cpu/cpu[0-9]*\")\n\tcpuDirs, err := filepath.Glob(glob)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(cpuDirs) == 0 {\n\t\treturn nil, fmt.Errorf(\"no CPUs detected at: %s\", glob)\n\t}\n\n\tfor _, dir := range cpuDirs {\n\t\t_, cpuName := filepath.Split(dir)\n\t\tcpuNum := strings.TrimPrefix(cpuName, \"cpu\")\n\n\t\tcpu := cpu{\n\t\t\tid:    cpuNum,\n\t\t\tpath:  dir,\n\t\t\tprops: make(map[string]string),\n\t\t}\n\n\t\tvar props []prop\n\n\t\tif choice.Contains(cpufreq, g.Metrics) {\n\t\t\tprops = append(props,\n\t\t\t\tprop{name: \"scaling_cur_freq\", path: \"cpufreq/scaling_cur_freq\", optional: false},\n\t\t\t\tprop{name: \"scaling_min_freq\", path: \"cpufreq/scaling_min_freq\", optional: false},\n\t\t\t\tprop{name: \"scaling_max_freq\", path: \"cpufreq/scaling_max_freq\", optional: false},\n\t\t\t\tprop{name: \"cpuinfo_cur_freq\", path: \"cpufreq/cpuinfo_cur_freq\", optional: true},\n\t\t\t\tprop{name: \"cpuinfo_min_freq\", path: \"cpufreq/cpuinfo_min_freq\", optional: true},\n\t\t\t\tprop{name: \"cpuinfo_max_freq\", path: \"cpufreq/cpuinfo_max_freq\", optional: true},\n\t\t\t)\n\t\t}\n\n\t\tif choice.Contains(thermal, g.Metrics) {\n\t\t\tprops = append(\n\t\t\t\tprops,\n\t\t\t\tprop{name: \"throttle_count\", path: \"thermal_throttle/core_throttle_count\", optional: false},\n\t\t\t\tprop{name: \"throttle_max_time\", path: \"thermal_throttle/core_throttle_max_time_ms\", optional: false},\n\t\t\t\tprop{name: \"throttle_total_time\", path: \"thermal_throttle/core_throttle_total_time_ms\", optional: false},\n\t\t\t)\n\t\t}\n\n\t\tvar failed = false\n\t\tfor _, prop := range props {\n\t\t\tpropPath := filepath.Join(dir, prop.path)\n\t\t\terr := validatePath(propPath)\n\t\t\tif err != nil {\n\t\t\t\tif prop.optional {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tg.Log.Warnf(\"Failed to load property %s: %v\", propPath, err)\n\t\t\t\tfailed = true\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcpu.props[prop.name] = propPath\n\t\t}\n\n\t\tif len(cpu.props) == 0 {\n\t\t\tg.Log.Warnf(\"No properties enabled/loaded for CPU %s\", cpuNum)\n\t\t\tfailed = true\n\t\t}\n\n\t\tif !failed {\n\t\t\tcpus = append(cpus, cpu)\n\t\t}\n\t}\n\treturn cpus, nil\n}\n\nfunc validatePath(propPath string) error {\n\tf, err := os.Open(propPath)\n\tif os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"file with CPU property does not exist: %q\", propPath)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get system information for CPU property %q: %w\", propPath, err)\n\t}\n\n\t_ = f.Close() // File is not written to, closing should be safe\n\treturn nil\n}\n\nfunc readUintFromFile(propPath string) (uint64, error) {\n\tf, err := os.Open(propPath)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer f.Close()\n\n\tbuffer := make([]byte, 22)\n\n\tn, err := f.Read(buffer)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn 0, fmt.Errorf(\"error on reading file: %w\", err)\n\t} else if n == 0 {\n\t\treturn 0, errors.New(\"error on reading file: file is empty\")\n\t}\n\n\treturn strconv.ParseUint(string(buffer[:n-1]), 10, 64)\n}\n\nfunc init() {\n\tinputs.Add(\"linux_cpu\", func() telegraf.Input {\n\t\treturn &LinuxCPU{\n\t\t\tMetrics: []string{\"cpufreq\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/linux_cpu/linux_cpu_nonlinux.go",
    "content": "//go:build !linux\n\npackage linux_cpu\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype LinuxCPU struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*LinuxCPU) SampleConfig() string { return sampleConfig }\n\nfunc (l *LinuxCPU) Init() error {\n\tl.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*LinuxCPU) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"linux_cpu\", func() telegraf.Input {\n\t\treturn &LinuxCPU{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/linux_cpu/linux_cpu_test.go",
    "content": "//go:build linux\n\npackage linux_cpu\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNoMetrics(t *testing.T) {\n\tplugin := &LinuxCPU{}\n\trequire.Error(t, plugin.Init())\n}\n\nfunc TestNoCPUs(t *testing.T) {\n\ttd := t.TempDir()\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"cpufreq\"},\n\t\tPathSysfs: td,\n\t}\n\trequire.Error(t, plugin.Init())\n}\n\nfunc TestNoCPUMetrics(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu0/cpufreq\", 0750))\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"cpufreq\"},\n\t\tPathSysfs: td,\n\t}\n\trequire.Error(t, plugin.Init())\n}\n\nfunc TestGatherCPUFreq(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu0/cpufreq\", 0750))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq\", []byte(\"250\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_min_freq\", []byte(\"100\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_max_freq\", []byte(\"255\\n\"), 0640))\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu1/cpufreq\", 0750))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq\", []byte(\"123\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu1/cpufreq/scaling_min_freq\", []byte(\"80\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu1/cpufreq/scaling_max_freq\", []byte(\"230\\n\"), 0640))\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"cpufreq\"},\n\t\tPathSysfs: td,\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\ttags1 := map[string]string{\n\t\t\"cpu\": \"0\",\n\t}\n\n\ttags2 := map[string]string{\n\t\t\"cpu\": \"1\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"scaling_cur_freq\": uint64(250),\n\t\t\"scaling_min_freq\": uint64(100),\n\t\t\"scaling_max_freq\": uint64(255),\n\t}\n\n\tfields2 := map[string]interface{}{\n\t\t\"scaling_cur_freq\": uint64(123),\n\t\t\"scaling_min_freq\": uint64(80),\n\t\t\"scaling_max_freq\": uint64(230),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"linux_cpu\", fields1, tags1)\n\tacc.AssertContainsTaggedFields(t, \"linux_cpu\", fields2, tags2)\n}\n\nfunc TestGatherThermal(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu0/thermal_throttle\", 0750))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/thermal_throttle/core_throttle_count\", []byte(\"250\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/thermal_throttle/core_throttle_max_time_ms\", []byte(\"100\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/thermal_throttle/core_throttle_total_time_ms\", []byte(\"255\\n\"), 0640))\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"thermal\"},\n\t\tPathSysfs: td,\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\tacc.AssertContainsFields(t, \"linux_cpu\", map[string]interface{}{\n\t\t\"throttle_count\":      uint64(250),\n\t\t\"throttle_max_time\":   uint64(100),\n\t\t\"throttle_total_time\": uint64(255),\n\t})\n}\n\nfunc TestGatherPropertyRemoved(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu0/cpufreq\", 0750))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq\", []byte(\"250\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_min_freq\", []byte(\"100\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_max_freq\", []byte(\"255\\n\"), 0640))\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"cpufreq\"},\n\t\tPathSysfs: td,\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\t// Remove one of the properties\n\trequire.NoError(t, os.RemoveAll(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_max_freq\"))\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\ttags1 := map[string]string{\n\t\t\"cpu\": \"0\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"scaling_cur_freq\": uint64(250),\n\t\t\"scaling_min_freq\": uint64(100),\n\t\t\"scaling_max_freq\": uint64(255),\n\t}\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"linux_cpu\", fields1, tags1)\n\trequire.NotEmpty(t, acc.Errors)\n}\n\nfunc TestGatherPropertyInvalid(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.MkdirAll(td+\"/devices/system/cpu/cpu0/cpufreq\", 0750))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq\", []byte(\"ABC\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_min_freq\", []byte(\"100\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/devices/system/cpu/cpu0/cpufreq/scaling_max_freq\", []byte(\"255\\n\"), 0640))\n\n\tplugin := &LinuxCPU{\n\t\tLog:       testutil.Logger{Name: \"LinuxCPUPluginTest\"},\n\t\tMetrics:   []string{\"cpufreq\"},\n\t\tPathSysfs: td,\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\ttags1 := map[string]string{\n\t\t\"cpu\": \"0\",\n\t}\n\n\tfields1 := map[string]interface{}{\n\t\t\"scaling_cur_freq\": uint64(250),\n\t\t\"scaling_min_freq\": uint64(100),\n\t\t\"scaling_max_freq\": uint64(255),\n\t}\n\n\tacc.AssertDoesNotContainsTaggedFields(t, \"linux_cpu\", fields1, tags1)\n\trequire.NotEmpty(t, acc.Errors)\n}\n"
  },
  {
    "path": "plugins/inputs/linux_cpu/sample.conf",
    "content": "# Provides Linux CPU metrics\n# This plugin ONLY supports Linux\n[[inputs.linux_cpu]]\n  ## Path for sysfs filesystem.\n  ## See https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt\n  ## Defaults:\n  # host_sys = \"/sys\"\n\n  ## CPU metrics collected by the plugin.\n  ## Supported options:\n  ## \"cpufreq\", \"thermal\"\n  ## Defaults:\n  # metrics = [\"cpufreq\"]\n"
  },
  {
    "path": "plugins/inputs/linux_sysctl_fs/README.md",
    "content": "# Linux Sysctl Filesystem Input Plugin\n\nThis plugin gathers metrics by reading the [system filesystem][sysfs] files on\n[Linux][kernel] systems.\n\n⭐ Telegraf v1.24.0\n🏷️ system\n💻 linux\n\n[kernel]: https://kernel.org/\n[sysfs]: https://www.kernel.org/doc/Documentation/sysctl/fs.txt\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Provides Linux sysctl fs metrics\n[[inputs.linux_sysctl_fs]]\n  # no configuration\n```\n\n## Metrics\n\n`linux_sysctl_fs` metric:\n\n- tags: _none_\n- fields:\n  - `aio-max-nr` (unsigned integer)\n  - `aio-nr` (unsigned integer)\n  - `dentry-age-limit` (unsigned integer)\n  - `dentry-nr` (unsigned integer)\n  - `dentry-unused-nr` (unsigned integer)\n  - `dentry-want-pages` (unsigned integer)\n  - `dquot-max` (unsigned integer)\n  - `dquot-nr` (unsigned integer)\n  - `inode-free-nr` (unsigned integer)\n  - `inode-nr` (unsigned integer)\n  - `inode-preshrink-nr` (unsigned integer)\n  - `super-max` (unsigned integer)\n  - `super-nr` (unsigned integer)\n  - `file-max` (unsigned integer)\n  - `file-nr` (unsigned integer)\n\n## Example Output\n\n```text\n> linux_sysctl_fs,host=foo dentry-want-pages=0i,file-max=44222i,aio-max-nr=65536i,inode-preshrink-nr=0i,dentry-nr=64340i,dentry-unused-nr=55274i,file-nr=1568i,aio-nr=0i,inode-nr=35952i,inode-free-nr=12957i,dentry-age-limit=45i 1490982022000000000\n```\n"
  },
  {
    "path": "plugins/inputs/linux_sysctl_fs/linux_sysctl_fs.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage linux_sysctl_fs\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype SysctlFS struct {\n\tpath string\n}\n\nfunc (*SysctlFS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (sfs *SysctlFS) Gather(acc telegraf.Accumulator) error {\n\tfields := make(map[string]interface{})\n\n\tfor _, n := range []string{\"aio-nr\", \"aio-max-nr\", \"dquot-nr\", \"dquot-max\", \"super-nr\", \"super-max\"} {\n\t\tif err := sfs.gatherOne(n, fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr := sfs.gatherList(\"inode-state\", fields, \"inode-nr\", \"inode-free-nr\", \"inode-preshrink-nr\")\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = sfs.gatherList(\"dentry-state\", fields, \"dentry-nr\", \"dentry-unused-nr\", \"dentry-age-limit\", \"dentry-want-pages\")\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = sfs.gatherList(\"file-nr\", fields, \"file-nr\", \"\", \"file-max\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\"linux_sysctl_fs\", fields, nil)\n\treturn nil\n}\n\nfunc (sfs *SysctlFS) gatherList(file string, fields map[string]interface{}, fieldNames ...string) error {\n\tbs, err := os.ReadFile(sfs.path + \"/\" + file)\n\tif err != nil {\n\t\t// Ignore non-existing entries\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tbsplit := bytes.Split(bytes.TrimRight(bs, \"\\n\"), []byte{'\\t'})\n\tfor i, name := range fieldNames {\n\t\tif i >= len(bsplit) {\n\t\t\tbreak\n\t\t}\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tv, err := strconv.ParseUint(string(bsplit[i]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfields[name] = v\n\t}\n\n\treturn nil\n}\n\nfunc (sfs *SysctlFS) gatherOne(name string, fields map[string]interface{}) error {\n\tbs, err := os.ReadFile(sfs.path + \"/\" + name)\n\tif err != nil {\n\t\t// Ignore non-existing entries\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tv, err := strconv.ParseUint(string(bytes.TrimRight(bs, \"\\n\")), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields[name] = v\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"linux_sysctl_fs\", func() telegraf.Input {\n\t\treturn &SysctlFS{\n\t\t\tpath: path.Join(internal.GetProcPath(), \"/sys/fs\"),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/linux_sysctl_fs/linux_sysctl_fs_test.go",
    "content": "package linux_sysctl_fs\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSysctlFSGather(t *testing.T) {\n\ttd := t.TempDir()\n\n\trequire.NoError(t, os.WriteFile(td+\"/aio-nr\", []byte(\"100\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/aio-max-nr\", []byte(\"101\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/super-nr\", []byte(\"102\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/super-max\", []byte(\"103\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/file-nr\", []byte(\"104\\t0\\t106\\n\"), 0640))\n\trequire.NoError(t, os.WriteFile(td+\"/inode-state\", []byte(\"107\\t108\\t109\\t0\\t0\\t0\\t0\\n\"), 0640))\n\n\tsfs := &SysctlFS{\n\t\tpath: td,\n\t}\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, sfs.Gather(&acc))\n\n\tacc.AssertContainsFields(t, \"linux_sysctl_fs\", map[string]interface{}{\n\t\t\"aio-nr\":             uint64(100),\n\t\t\"aio-max-nr\":         uint64(101),\n\t\t\"super-nr\":           uint64(102),\n\t\t\"super-max\":          uint64(103),\n\t\t\"file-nr\":            uint64(104),\n\t\t\"file-max\":           uint64(106),\n\t\t\"inode-nr\":           uint64(107),\n\t\t\"inode-free-nr\":      uint64(108),\n\t\t\"inode-preshrink-nr\": uint64(109),\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/linux_sysctl_fs/sample.conf",
    "content": "# Provides Linux sysctl fs metrics\n[[inputs.linux_sysctl_fs]]\n  # no configuration\n"
  },
  {
    "path": "plugins/inputs/logql/README.md",
    "content": "# LogQL Input Plugin\n\nThis plugin gathers metrics from a [Loki][loki] endpoint using\n[LogQL queries][logql] via the [HTTP API][http_api].\n\n⭐ Telegraf v1.37.0\n🏷️ datastore\n💻 all\n\n[loki]: https://grafana.com/oss/loki/\n[logql]: https://grafana.com/docs/loki/latest/query/\n[http_api]: https://grafana.com/docs/loki/latest/reference/loki-http-api/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username`, `password`\nand `token` option. See the [secret-store documentation][SECRETSTORE] for\nmore details on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Query Loki endpoints using LogQL\n[[inputs.logql]]\n  ## URL of the Loki endpoint\n  # url = \"http://localhost:3100\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Organization IDs for the queries in multi-tenant setups\n  # organizations = []\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.logql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = 'count_over_time({job=\"varlogs\"}[24h])'\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.logql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = '{job=\"varlogs\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   # step = \"0s\"\n  #   # interval = \"0s\"\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n```\n\n> [!NOTE]\n> You can either use no authentication _or_ basic authentication _or_ Bearer\n> token based authentication. Uncommenting both basic and Bearer token based\n> authentication will fail.\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the specified queries.\nHowever, the resulting metrics will have the following structure for the\nreturned results.\n\n### Vector and Matrix Results\n\nVector and metric results will produce one or more metrics with the metric named\nbeing either `logql` or the `name` specified in the query.\nLabels of the results will be kept as tags if they are not internal (not\nstarting and ending with a double underscore `__<label>__`).\nThe returned value for each sample will be stored in a field called `value` and\nthe provided Loki timestamp will be used as metric timestamp.\n\n### Stream Results\n\nA stream result will produce one or more metrics with the metric named being\neither `logql` or the `name` specified in the query.\nLabels of the results will be kept as tags if they are not internal (not\nstarting and ending with a double underscore `__<label>__`).\nThe returned log-line for each sample will be stored in a field called `message`\nand the provided Loki timestamp will be used as metric timestamp.\n\n## Example Output\n\nFor example, the instant query\n\n```logql\nsum(rate({job=\"varlogs\"}[5m])) by (detected_level)\n```\n\nreturns\n\n```text\nlogql,detected_level=error,host=Hugin value=0.5833333333333334 1762943358000000000\nlogql,detected_level=info,host=Hugin value=45.8 1762943358000000000\nlogql,detected_level=unknown,host=Hugin value=741.71 1762943358000000000\nlogql,detected_level=warn,host=Hugin value=16.566666666666666 1762943358000000000\n```\n\nThe example range-query\n\n```logql\ncount by(detected_level) (rate({job=\"varlogs\", filename=\"/var/log/Xorg.0.log\"} [5m]))\n```\n\nwith a range of 30 minutes ago to now and one minute stepping results in\n\n```text\nlogql,detected_level=error,host=Hugin value=1 1762943220000000000\nlogql,detected_level=error,host=Hugin value=1 1762943280000000000\nlogql,detected_level=error,host=Hugin value=1 1762943340000000000\nlogql,detected_level=error,host=Hugin value=1 1762943400000000000\nlogql,detected_level=error,host=Hugin value=1 1762943460000000000\nlogql,detected_level=info,host=Hugin value=1 1762943220000000000\nlogql,detected_level=info,host=Hugin value=1 1762943280000000000\nlogql,detected_level=info,host=Hugin value=1 1762943340000000000\nlogql,detected_level=info,host=Hugin value=1 1762943400000000000\nlogql,detected_level=info,host=Hugin value=1 1762943460000000000\nlogql,detected_level=unknown,host=Hugin value=1 1762943220000000000\nlogql,detected_level=unknown,host=Hugin value=1 1762943280000000000\nlogql,detected_level=unknown,host=Hugin value=1 1762943340000000000\nlogql,detected_level=unknown,host=Hugin value=1 1762943400000000000\nlogql,detected_level=unknown,host=Hugin value=1 1762943460000000000\n```\n\nWhen querying raw log entries (stream results), for example:\n\n```logql\n{job=\"varlogs\", filename=\"/var/log/Xorg.0.log\"}\n```\n\nwith `sorting = \"forward\"` and `limit = 5`, the plugin returns the following:\n\n```text\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,host=Hugin,job=varlogs,service_name=varlogs message=\"[     6.806] (--) Log file renamed from \\\"/var/log/Xorg.pid-693.log\\\" to \\\"/var/log/Xorg.0.log\\\"\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,host=Hugin,job=varlogs,service_name=varlogs message=\"[     6.807] \" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,host=Hugin,job=varlogs,service_name=varlogs message=\"X.Org X Server 1.21.1.14\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,host=Hugin,job=varlogs,service_name=varlogs message=\"X Protocol Version 11, Revision 0\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,host=Hugin,job=varlogs,service_name=varlogs message=\"[     6.807] Current Operating System: Linux Hugin 6.12.1-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 22 Nov 2024 16:04:27 +0000 x86_64\" 1762943173000000000\n```\n"
  },
  {
    "path": "plugins/inputs/logql/client.go",
    "content": "package logql\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\tpromcfg \"github.com/prometheus/common/config\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n)\n\ntype client struct {\n\turl      string\n\tusername config.Secret\n\tpassword config.Secret\n\ttoken    config.Secret\n\torg      string\n\ttimeout  time.Duration\n\tcfg      common_http.TransportConfig\n\n\tclient *http.Client\n}\n\nfunc (c *client) init() error {\n\t// Create a round-tripper suitable for the given configuration based on the\n\t// http-client transport...\n\ttransport, err := c.cfg.CreateTransport()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating transport failed: %w\", err)\n\t}\n\trt := promcfg.NewUserAgentRoundTripper(internal.ProductToken(), transport)\n\tif !c.username.Empty() {\n\t\trt = promcfg.NewBasicAuthRoundTripper(\n\t\t\t&secretReader{\"username\", &c.username},\n\t\t\t&secretReader{\"password\", &c.password},\n\t\t\trt,\n\t\t)\n\t} else if !c.token.Empty() {\n\t\trt = promcfg.NewAuthorizationCredentialsRoundTripper(\n\t\t\t\"Bearer\",\n\t\t\t&secretReader{\"token\", &c.token},\n\t\t\trt,\n\t\t)\n\t}\n\n\t// Create HTTP client for API requests\n\tc.client = &http.Client{Transport: rt, Timeout: c.timeout}\n\n\treturn nil\n}\n\nfunc (c *client) ready(ctx context.Context) (bool, string, error) {\n\t// Construct the URL\n\tu, err := url.Parse(c.url)\n\tif err != nil {\n\t\treturn false, \"\", fmt.Errorf(\"parsing URL %q failed: %w\", c.url, err)\n\t}\n\tu = u.JoinPath(\"ready\")\n\n\t// Issue the request and check the returned status\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)\n\tif err != nil {\n\t\treturn false, \"\", fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\tif c.org != \"\" {\n\t\treq.Header.Set(\"X-Scope-OrgID\", c.org)\n\t}\n\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn false, \"\", fmt.Errorf(\"executing request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// Read the body and if the query was successful\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn false, \"\", fmt.Errorf(\"reading response body failed: %w\", err)\n\t}\n\n\treturn resp.StatusCode == 200, string(body), nil\n}\n\nfunc (c *client) execute(ctx context.Context, u string) (interface{}, error) {\n\t// Prepare the request\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\tif c.org != \"\" {\n\t\treq.Header.Set(\"X-Scope-OrgID\", c.org)\n\t}\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\t// Execute the query\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"executing request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// Read the body and if the query was successful\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading response body failed: %w\", err)\n\t}\n\n\tif resp.StatusCode < 200 || resp.StatusCode > 299 {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"querying failed with status %d (%s): %s\",\n\t\t\tresp.StatusCode, http.StatusText(resp.StatusCode), string(body),\n\t\t)\n\t}\n\n\t// Parse the response\n\tvar r response\n\tif err := json.Unmarshal(body, &r); err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding query response failed: %w\", err)\n\t}\n\n\treturn r.parse()\n}\n\nfunc (c *client) close() {\n\tif c.client != nil {\n\t\tc.client.CloseIdleConnections()\n\t}\n}\n\n// Wrapper for reading secrets from Prometheus API client\ntype secretReader struct {\n\tdesc   string\n\tsecret *config.Secret\n}\n\n// Fetch implements the Prometheus secret-reader API\nfunc (r *secretReader) Fetch(context.Context) (string, error) {\n\traw, err := r.secret.Get()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting %s failed: %w\", r.desc, err)\n\t}\n\ts := raw.String()\n\traw.Destroy()\n\n\treturn s, nil\n}\n\n// Description implements the Prometheus secret-reader API\nfunc (r *secretReader) Description() string {\n\treturn r.desc\n}\n\n// Immutable implements the Prometheus secret-reader API\nfunc (*secretReader) Immutable() bool {\n\treturn true\n}\n"
  },
  {
    "path": "plugins/inputs/logql/logql.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage logql\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype LogQL struct {\n\tURL            string          `toml:\"url\"`\n\tUsername       config.Secret   `toml:\"username\"`\n\tPassword       config.Secret   `toml:\"password\"`\n\tToken          config.Secret   `toml:\"token\"`\n\tOrganizations  []string        `toml:\"organizations\"`\n\tTimeout        config.Duration `toml:\"timeout\"`\n\tInstantQueries []InstantQuery  `toml:\"instant\"`\n\tRangeQueries   []RangeQuery    `toml:\"range\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\tcommon_http.TransportConfig\n\n\tclient *client\n}\n\nfunc (*LogQL) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *LogQL) Init() error {\n\t// Check settings\n\tif l.URL == \"\" {\n\t\tl.URL = \"http://localhost:3100\"\n\t}\n\n\tif l.Username.Empty() && !l.Password.Empty() {\n\t\treturn errors.New(\"expecting username for basic authentication\")\n\t}\n\n\tif !l.Username.Empty() && !l.Token.Empty() {\n\t\treturn errors.New(\"cannot use both basic and bearer authentication\")\n\t}\n\n\tif len(l.InstantQueries)+len(l.RangeQueries) == 0 {\n\t\treturn errors.New(\"no queries configured\")\n\t}\n\n\t// Setup the API client\n\tl.client = &client{\n\t\turl:      l.URL,\n\t\tusername: l.Username,\n\t\tpassword: l.Password,\n\t\ttoken:    l.Token,\n\t\torg:      strings.Join(l.Organizations, \"|\"), // see https://grafana.com/docs/loki/latest/operations/multi-tenancy\n\t\tcfg:      l.TransportConfig,\n\t\ttimeout:  time.Duration(l.Timeout),\n\t}\n\n\t// Setup queries\n\tfor i := range l.InstantQueries {\n\t\tif err := l.InstantQueries[i].init(l.client, l.Log); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := range l.RangeQueries {\n\t\tif err := l.RangeQueries[i].init(l.client, l.Log); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *LogQL) Start(telegraf.Accumulator) error {\n\t// Initialize the API client\n\tif err := l.client.init(); err != nil {\n\t\treturn fmt.Errorf(\"initializing API client failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (l *LogQL) Stop() {\n\tif l.client != nil {\n\t\tl.client.close()\n\t}\n}\n\nfunc (l *LogQL) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\tif l.Timeout > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, time.Duration(l.Timeout))\n\t\tdefer cancel()\n\t}\n\n\t// Check if the server is ready\n\tif ready, msg, err := l.client.ready(ctx); err != nil {\n\t\treturn fmt.Errorf(\"checking readiness failed: %w\", err)\n\t} else if !ready {\n\t\treturn fmt.Errorf(\"server at %q is not ready: %s\", l.URL, msg)\n\t}\n\n\tt := time.Now()\n\n\t// Do the queries\n\tfor _, q := range l.InstantQueries {\n\t\tacc.AddError(q.execute(ctx, acc, t))\n\t}\n\tfor _, q := range l.RangeQueries {\n\t\tacc.AddError(q.execute(ctx, acc, t))\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"logql\", func() telegraf.Input {\n\t\treturn &LogQL{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/logql/logql_test.go",
    "content": "package logql\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInitSuccess(t *testing.T) {\n\tusername := config.NewSecret([]byte(\"john\"))\n\tpassword := config.NewSecret([]byte(\"secret\"))\n\ttoken := config.NewSecret([]byte(\"a token\"))\n\tdefer username.Destroy()\n\tdefer password.Destroy()\n\tdefer token.Destroy()\n\n\ttests := []struct {\n\t\tname   string\n\t\tplugin *LogQL\n\t}{\n\t\t{\n\t\t\tname: \"no authentication\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic auth without password\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tUsername:       username,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic auth with password\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tUsername:       username,\n\t\t\t\tPassword:       password,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"token auth\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tToken:          token,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"time range mix\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tStart: config.Duration(5 * time.Minute),\n\t\t\t\t\t\tEnd:   config.Duration(-1 * time.Minute),\n\t\t\t\t\t\tquery: query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\t\t\trequire.Equal(t, \"http://localhost:3100\", tt.plugin.URL)\n\t\t})\n\t}\n}\n\nfunc TestInitFail(t *testing.T) {\n\tusername := config.NewSecret([]byte(\"john\"))\n\tpassword := config.NewSecret([]byte(\"secret\"))\n\ttoken := config.NewSecret([]byte(\"a token\"))\n\tdefer username.Destroy()\n\tdefer password.Destroy()\n\tdefer token.Destroy()\n\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *LogQL\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no queries\",\n\t\t\tplugin:   &LogQL{},\n\t\t\texpected: \"no queries configured\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid sorting\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`, Sorting: \"random\"}}},\n\t\t\t},\n\t\t\texpected: \"invalid sorting direction\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid time range zero\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tquery: query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"invalid range\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid time range past\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tStart: config.Duration(5 * time.Minute),\n\t\t\t\t\t\tEnd:   config.Duration(15 * time.Minute),\n\t\t\t\t\t\tquery: query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"invalid range\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid time range future\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tStart: config.Duration(-5 * time.Minute),\n\t\t\t\t\t\tquery: query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"invalid range\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid stepping\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tStart: config.Duration(5 * time.Minute),\n\t\t\t\t\t\tStep:  config.Duration(-1 * time.Minute),\n\t\t\t\t\t\tquery: query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"'step' must be non-negative for query\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid interval\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tStart:    config.Duration(5 * time.Minute),\n\t\t\t\t\t\tInterval: config.Duration(-5 * time.Minute),\n\t\t\t\t\t\tquery:    query{Query: `{job=\"varlogs\"}`},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"'interval' must be non-negative for query\",\n\t\t},\n\t\t{\n\t\t\tname: \"password without username\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tPassword:       password,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t\texpected: \"expecting username for basic authentication\",\n\t\t},\n\t\t{\n\t\t\tname: \"basic and token auth\",\n\t\t\tplugin: &LogQL{\n\t\t\t\tUsername:       username,\n\t\t\t\tToken:          token,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\t\t},\n\t\t\texpected: \"cannot use both basic and bearer authentication\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.ErrorContains(t, tt.plugin.Init(), tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestSigleTenant(t *testing.T) {\n\t// Start a mock server\n\tvar orgs []string\n\tvar orgMu sync.Mutex\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Mark the server as ready\n\t\tif r.URL.Path == \"/ready\" {\n\t\t\tif _, err := w.Write([]byte(\"ready\")); err != nil {\n\t\t\t\tt.Logf(\"writing 'ready' response failed: %v\", err)\n\t\t\t\tt.Fail()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\t// Store the query\n\t\torgMu.Lock()\n\t\torgs = r.Header.Values(\"X-Scope-OrgID\")\n\t\torgMu.Unlock()\n\n\t\t// Send the response\n\t\tw.WriteHeader(http.StatusTooManyRequests)\n\t}))\n\tdefer ts.Close()\n\n\t// Configure and initialize the plugin\n\tplugin := &LogQL{\n\t\tURL:            ts.URL,\n\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\tLog:            &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin and collect data\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Check the query including the parameters\n\torgMu.Lock()\n\tdefer orgMu.Unlock()\n\trequire.Empty(t, orgs)\n}\n\nfunc TestMultiTenant(t *testing.T) {\n\t// Start a mock server\n\tvar orgs []string\n\tvar orgMu sync.Mutex\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Mark the server as ready\n\t\tif r.URL.Path == \"/ready\" {\n\t\t\tif _, err := w.Write([]byte(\"ready\")); err != nil {\n\t\t\t\tt.Logf(\"writing 'ready' response failed: %v\", err)\n\t\t\t\tt.Fail()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\t// Store the query\n\t\torgMu.Lock()\n\t\torgs = r.Header.Values(\"X-Scope-OrgID\")\n\t\torgMu.Unlock()\n\n\t\t// Send the response\n\t\tw.WriteHeader(http.StatusTooManyRequests)\n\t}))\n\tdefer ts.Close()\n\n\t// Configure and initialize the plugin\n\tplugin := &LogQL{\n\t\tURL:            ts.URL,\n\t\tOrganizations:  []string{\"CompanyA\", \"CompanyB\"},\n\t\tInstantQueries: []InstantQuery{{query: query{Query: `{job=\"varlogs\"}`}}},\n\t\tLog:            &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Start the plugin and collect data\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Check the query including the parameters\n\torgMu.Lock()\n\tdefer orgMu.Unlock()\n\trequire.Equal(t, []string{\"CompanyA|CompanyB\"}, orgs)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"logql\", func() telegraf.Input {\n\t\treturn &LogQL{Timeout: config.Duration(5 * time.Second)}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedQueryFilename := filepath.Join(testcasePath, \"expected.query\")\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tmatches, err := filepath.Glob(filepath.Join(testcasePath, \"response_*.json\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresponses := make(map[string][]byte, len(matches))\n\t\t\tfor _, fn := range matches {\n\t\t\t\tresponse, err := os.ReadFile(fn)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tendpoint := filepath.Base(fn)\n\t\t\t\tendpoint = strings.TrimSuffix(strings.TrimPrefix(endpoint, \"response_\"), \".json\")\n\t\t\t\tresponses[\"/loki/api/v1/\"+endpoint] = response\n\t\t\t}\n\n\t\t\t// Read the expected output and query\n\t\t\texpected, err := testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\trequire.NoError(t, err)\n\t\t\texpectedQuery, err := os.ReadFile(expectedQueryFilename)\n\t\t\trequire.NoError(t, err)\n\t\t\texpectedURL, err := url.Parse(strings.TrimSpace(string(expectedQuery)))\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Start a mock server\n\t\t\tvar query string\n\t\t\tvar queryMu sync.Mutex\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Mark the server as ready\n\t\t\t\tif r.URL.Path == \"/ready\" {\n\t\t\t\t\tif _, err := w.Write([]byte(\"ready\")); err != nil {\n\t\t\t\t\t\tt.Logf(\"writing 'ready' response failed: %v\", err)\n\t\t\t\t\t\tt.Fail()\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Store the query\n\t\t\t\tqueryMu.Lock()\n\t\t\t\tquery = r.URL.String()\n\t\t\t\tqueryMu.Unlock()\n\n\t\t\t\t// Send the response\n\t\t\t\tresponse, found := responses[r.URL.Path]\n\t\t\t\tif !found {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif _, err := w.Write(response); err != nil {\n\t\t\t\t\tt.Logf(\"writing 'ready' response failed: %v\", err)\n\t\t\t\t\tt.Fail()\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\t// Configure and initialize the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\t\t\tplugin := cfg.Inputs[0].Input.(*LogQL)\n\t\t\tplugin.URL = ts.URL\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Start the plugin and collect data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\t// Check the query including the parameters\n\t\t\tqueryMu.Lock()\n\t\t\tactualQuery := query\n\t\t\tqueryMu.Unlock()\n\n\t\t\tactualURL, err := url.Parse(actualQuery)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Wipe actual time values\n\t\t\tactualParams := actualURL.Query()\n\t\t\tfor _, k := range []string{\"time\", \"start\", \"end\"} {\n\t\t\t\tif actualParams.Has(k) {\n\t\t\t\t\tactualParams.Set(k, \"\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.Equal(t, expectedURL.Path, actualURL.Path, \"query path differs\")\n\t\t\trequire.Equal(t, actualParams, expectedURL.Query(), \"query parameters differ\")\n\n\t\t\t// Check the received metrics\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), options...)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/logql/query.go",
    "content": "package logql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype query struct {\n\tName    string `toml:\"name\"`\n\tQuery   string `toml:\"query\"`\n\tSorting string `toml:\"sorting\"`\n\tLimit   uint64 `toml:\"limit\"`\n\n\tclient *client\n\turl    *url.URL\n\tvalues *url.Values\n\tlog    telegraf.Logger\n}\n\nfunc (q *query) init(c *client, log telegraf.Logger) error {\n\tif q.Query == \"\" {\n\t\treturn fmt.Errorf(\"'query' cannot be empty for %q\", c.url)\n\t}\n\n\tswitch q.Sorting {\n\tcase \"\", \"forward\", \"backward\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid sorting direction %q\", q.Sorting)\n\t}\n\n\t// Prepare the query information from the URL and given parameters\n\tu, err := url.Parse(c.url)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing URL %q failed: %w\", c.url, err)\n\t}\n\n\tq.client = c\n\tq.url = u\n\tq.log = log\n\n\tq.values = &url.Values{}\n\tq.values.Set(\"query\", q.Query)\n\tif q.Sorting != \"\" {\n\t\tq.values.Set(\"direction\", q.Sorting)\n\t}\n\tif q.Limit > 0 {\n\t\tq.values.Set(\"limit\", strconv.FormatUint(q.Limit, 10))\n\t}\n\treturn nil\n}\n\ntype InstantQuery struct {\n\tquery\n}\n\nfunc (q *InstantQuery) init(c *client, log telegraf.Logger) error {\n\t// Init the underlying query\n\tif err := q.query.init(c, log); err != nil {\n\t\treturn err\n\t}\n\n\t// Set instant-query specific values\n\tq.query.url = q.query.url.JoinPath(\"loki\", \"api\", \"v1\", \"query\")\n\n\treturn nil\n}\n\nfunc (q *InstantQuery) execute(ctx context.Context, acc telegraf.Accumulator, t time.Time) error {\n\tq.query.values.Set(\"time\", t.Format(time.RFC3339Nano))\n\tq.query.url.RawQuery = q.query.values.Encode()\n\n\tresult, err := q.client.execute(ctx, q.query.url.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", q.client.url, err)\n\t}\n\n\treturn q.convertResult(acc, result)\n}\n\ntype RangeQuery struct {\n\tquery\n\tStart    config.Duration `toml:\"start\"`\n\tEnd      config.Duration `toml:\"end\"`\n\tStep     config.Duration `toml:\"step\"`\n\tInterval config.Duration `toml:\"interval\"`\n}\n\nfunc (q *RangeQuery) init(c *client, log telegraf.Logger) error {\n\t// Check the parameters\n\tif q.Start <= q.End {\n\t\treturn fmt.Errorf(\"invalid range %v to %v for query %q\", q.Start, q.End, q.Query)\n\t}\n\tif q.Step < 0 {\n\t\treturn fmt.Errorf(\"'step' must be non-negative for query %q\", q.query.Query)\n\t}\n\tif q.Interval < 0 {\n\t\treturn fmt.Errorf(\"'interval' must be non-negative for query %q\", q.query.Query)\n\t}\n\n\t// Init the underlying query\n\tif err := q.query.init(c, log); err != nil {\n\t\treturn err\n\t}\n\n\t// Set range-query specific values\n\tq.query.url = q.query.url.JoinPath(\"loki\", \"api\", \"v1\", \"query_range\")\n\tif q.Step > 0 {\n\t\tq.query.values.Set(\"step\", time.Duration(q.Step).String())\n\t}\n\tif q.Interval > 0 {\n\t\tq.query.values.Set(\"interval\", time.Duration(q.Interval).String())\n\t}\n\n\treturn nil\n}\n\nfunc (q *RangeQuery) execute(ctx context.Context, acc telegraf.Accumulator, t time.Time) error {\n\tq.query.values.Set(\"start\", t.Add(-time.Duration(q.Start)).Format(time.RFC3339Nano))\n\tq.query.values.Set(\"end\", t.Add(-time.Duration(q.End)).Format(time.RFC3339Nano))\n\tq.query.url.RawQuery = q.query.values.Encode()\n\n\tresult, err := q.client.execute(ctx, q.query.url.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", q.client.url, err)\n\t}\n\n\treturn q.convertResult(acc, result)\n}\n\nfunc (q *query) convertResult(acc telegraf.Accumulator, result interface{}) error {\n\t// Determine the default name\n\tname := \"logql\"\n\tif q.Name != \"\" {\n\t\tname = q.Name\n\t}\n\n\tswitch entries := result.(type) {\n\tcase []vector:\n\t\tfor _, r := range entries {\n\t\t\t// Cleanup labels\n\t\t\tmaps.DeleteFunc(r.Labels, isInternal)\n\n\t\t\tfields := map[string]interface{}{\"value\": r.Value.value}\n\t\t\tacc.AddFields(name, fields, r.Labels, r.Value.timestamp)\n\t\t}\n\tcase []matrix:\n\t\tfor _, r := range entries {\n\t\t\t// Cleanup labels\n\t\t\tmaps.DeleteFunc(r.Labels, isInternal)\n\n\t\t\tfor _, v := range r.Values {\n\t\t\t\tfields := map[string]interface{}{\"value\": v.value}\n\t\t\t\tacc.AddFields(name, fields, r.Labels, v.timestamp)\n\t\t\t}\n\t\t}\n\tcase []stream:\n\t\tfor _, r := range entries {\n\t\t\t// Cleanup labels\n\t\t\tmaps.DeleteFunc(r.Labels, isInternal)\n\n\t\t\tfor _, v := range r.Lines {\n\t\t\t\tfields := map[string]interface{}{\"message\": v.message}\n\t\t\t\tacc.AddFields(name, fields, r.Labels, v.timestamp)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown result type %T\", entries)\n\t}\n\n\treturn nil\n}\n\nfunc isInternal(label, _ string) bool {\n\treturn strings.HasPrefix(label, \"__\") && strings.HasSuffix(label, \"__\")\n}\n"
  },
  {
    "path": "plugins/inputs/logql/response.go",
    "content": "package logql\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n)\n\ntype response struct {\n\tStatus string `json:\"status\"`\n\tData   struct {\n\t\tResultType string          `json:\"resultType\"`\n\t\tResult     json.RawMessage `json:\"result\"`\n\t} `json:\"data\"`\n}\n\ntype stream struct {\n\tLabels map[string]string `json:\"stream\"`\n\tLines  []logline         `json:\"values\"`\n}\n\ntype vector struct {\n\tLabels map[string]string `json:\"metric\"`\n\tValue  value             `json:\"value\"`\n}\n\ntype matrix struct {\n\tLabels map[string]string `json:\"metric\"`\n\tValues []value           `json:\"values\"`\n}\n\ntype value struct {\n\ttimestamp time.Time\n\tvalue     float64\n}\n\n// UnmarshalJSON customizes the JSON parsing to decode the raw pair-array into\n// timestamp and the numeric value\nfunc (v *value) UnmarshalJSON(data []byte) error {\n\tvar raw []interface{}\n\tif err := json.Unmarshal(data, &raw); err != nil {\n\t\treturn err\n\t}\n\n\tif len(raw) != 2 {\n\t\treturn fmt.Errorf(\"unexpected number of entries (%d) in %v\", len(raw), string(data))\n\t}\n\n\tts, ok := raw[0].(float64)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T for timestamp %v\", raw[0], raw[0])\n\t}\n\tv.timestamp = time.Unix(0, int64(ts*1e9))\n\n\trawValue, ok := raw[1].(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T for value %v\", raw[1], raw[1])\n\t}\n\tvalue, err := strconv.ParseFloat(rawValue, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing value failed: %w\", err)\n\t}\n\tv.value = value\n\n\treturn nil\n}\n\ntype logline struct {\n\ttimestamp time.Time\n\tmessage   string\n}\n\n// UnmarshalJSON customizes the JSON parsing to decode the raw string pair-array\n// into timestamp and message\nfunc (l *logline) UnmarshalJSON(data []byte) error {\n\tvar raw []string\n\tif err := json.Unmarshal(data, &raw); err != nil {\n\t\treturn err\n\t}\n\n\tif len(raw) != 2 {\n\t\treturn fmt.Errorf(\"unexpected number of entries (%d) in %v\", len(raw), string(data))\n\t}\n\n\tts, err := strconv.ParseInt(raw[0], 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing timestamp failed: %w\", err)\n\t}\n\tl.timestamp = time.Unix(0, ts)\n\tl.message = raw[1]\n\n\treturn nil\n}\n\nfunc (r *response) parse() (interface{}, error) {\n\tif r.Status != \"success\" {\n\t\treturn nil, fmt.Errorf(\"invalid status %q\", r.Status)\n\t}\n\n\tswitch r.Data.ResultType {\n\tcase \"vector\":\n\t\tvar v []vector\n\t\tif err := json.Unmarshal(r.Data.Result, &v); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding %q result failed: %w\", r.Data.ResultType, err)\n\t\t}\n\t\treturn v, nil\n\tcase \"matrix\":\n\t\tvar m []matrix\n\t\tif err := json.Unmarshal(r.Data.Result, &m); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding %q result failed: %w\", r.Data.ResultType, err)\n\t\t}\n\t\treturn m, nil\n\tcase \"streams\":\n\t\tvar s []stream\n\t\tif err := json.Unmarshal(r.Data.Result, &s); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding %q result failed: %w\", r.Data.ResultType, err)\n\t\t}\n\t\treturn s, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown result type %q\", r.Data.ResultType)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/logql/sample.conf",
    "content": "# Query Loki endpoints using LogQL\n[[inputs.logql]]\n  ## URL of the Loki endpoint\n  # url = \"http://localhost:3100\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Organization IDs for the queries in multi-tenant setups\n  # organizations = []\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.logql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = 'count_over_time({job=\"varlogs\"}[24h])'\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.logql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = '{job=\"varlogs\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   # step = \"0s\"\n  #   # interval = \"0s\"\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n"
  },
  {
    "path": "plugins/inputs/logql/sample.conf.in",
    "content": "# Query Loki endpoints using LogQL\n[[inputs.logql]]\n  ## URL of the Loki endpoint\n  # url = \"http://localhost:3100\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Organization IDs for the queries in multi-tenant setups\n  # organizations = []\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n{{template \"/plugins/common/http/transport.conf\"}}\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.logql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = 'count_over_time({job=\"varlogs\"}[24h])'\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.logql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"logql\"\n  #\n  #   ## Query to execute\n  #   query = '{job=\"varlogs\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   # step = \"0s\"\n  #   # interval = \"0s\"\n  #\n  #   ## Sorting direction of logs, either \"forward\" or \"backward\"\n  #   # sorting = \"backward\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/instant_vector/expected.out",
    "content": "logql,detected_level=error value=0.004050925925925926 1762955195000000000\nlogql,detected_level=info value=0.31805555555555554 1762955195000000000\nlogql,detected_level=unknown value=5.150763888888889 1762955195000000000\nlogql,detected_level=warn value=0.1150462962962963 1762955195000000000\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/instant_vector/expected.query",
    "content": "/loki/api/v1/query?query=sum%28rate%28%7Bjob%3D%22varlogs%22%7D%5B5m%5D%29%29+by+%28detected_level%29&time="
  },
  {
    "path": "plugins/inputs/logql/testcases/instant_vector/response_query.json",
    "content": "{\n    \"status\": \"success\",\n    \"data\": {\n        \"resultType\": \"vector\",\n        \"result\": [\n            {\n                \"metric\": {\n                    \"detected_level\": \"error\"\n                },\n                \"value\": [\n                    1762955194.594,\n                    \"0.004050925925925926\"\n                ]\n            },\n            {\n                \"metric\": {\n                    \"detected_level\": \"info\"\n                },\n                \"value\": [\n                    1762955194.594,\n                    \"0.31805555555555554\"\n                ]\n            },\n            {\n                \"metric\": {\n                    \"detected_level\": \"unknown\"\n                },\n                \"value\": [\n                    1762955194.594,\n                    \"5.150763888888889\"\n                ]\n            },\n            {\n                \"metric\": {\n                    \"detected_level\": \"warn\"\n                },\n                \"value\": [\n                    1762955194.594,\n                    \"0.1150462962962963\"\n                ]\n            }\n        ],\n        \"stats\": {\n            \"summary\": {\n                \"bytesProcessedPerSecond\": 364870950,\n                \"linesProcessedPerSecond\": 2730825,\n                \"totalBytesProcessed\": 64507314,\n                \"totalLinesProcessed\": 482796,\n                \"execTime\": 0.176794875,\n                \"queueTime\": 0.157362648,\n                \"subqueries\": 0,\n                \"totalEntriesReturned\": 4,\n                \"splits\": 24,\n                \"shards\": 24,\n                \"totalPostFilterLines\": 482796,\n                \"totalStructuredMetadataBytesProcessed\": 14483880\n            },\n            \"querier\": {\n                \"store\": {\n                    \"totalChunksRef\": 25,\n                    \"totalChunksDownloaded\": 25,\n                    \"chunksDownloadTime\": 2017579,\n                    \"queryReferencedStructuredMetadata\": true,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 64507314,\n                        \"decompressedLines\": 482796,\n                        \"compressedBytes\": 8854995,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 482796,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 14483880\n                    },\n                    \"chunkRefsFetchTime\": 1538457,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"ingester\": {\n                \"totalReached\": 3,\n                \"totalChunksMatched\": 0,\n                \"totalBatches\": 3,\n                \"totalLinesSent\": 0,\n                \"store\": {\n                    \"totalChunksRef\": 0,\n                    \"totalChunksDownloaded\": 0,\n                    \"chunksDownloadTime\": 0,\n                    \"queryReferencedStructuredMetadata\": false,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 0,\n                        \"decompressedLines\": 0,\n                        \"compressedBytes\": 0,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 0,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 0\n                    },\n                    \"chunkRefsFetchTime\": 165661,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"cache\": {\n                \"chunk\": {\n                    \"entriesFound\": 13,\n                    \"entriesRequested\": 25,\n                    \"entriesStored\": 24,\n                    \"bytesReceived\": 4438121,\n                    \"bytesSent\": 4429011,\n                    \"requests\": 4,\n                    \"downloadTime\": 39590,\n                    \"queryLengthServed\": 0\n                },\n                \"index\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"result\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"statsResult\": {\n                    \"entriesFound\": 13,\n                    \"entriesRequested\": 24,\n                    \"entriesStored\": 24,\n                    \"bytesReceived\": 2561,\n                    \"bytesSent\": 0,\n                    \"requests\": 48,\n                    \"downloadTime\": 214793,\n                    \"queryLengthServed\": 3600000000000\n                },\n                \"volumeResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"seriesResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"labelResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"instantMetricResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                }\n            },\n            \"index\": {\n                \"totalChunks\": 0,\n                \"postFilterChunks\": 0,\n                \"shardsDuration\": 0,\n                \"usedBloomFilters\": false\n            }\n        }\n    }\n}"
  },
  {
    "path": "plugins/inputs/logql/testcases/instant_vector/telegraf.conf",
    "content": "[[inputs.logql]]\n  url = \"dummy\"\n\n  [[inputs.logql.instant]]\n    query = 'sum(rate({job=\"varlogs\"}[5m])) by (detected_level)'"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_matrix/expected.out",
    "content": "logql,detected_level=error value=1 1762943400000000000\nlogql,detected_level=info value=1 1762943400000000000\nlogql,detected_level=unknown value=1 1762943400000000000\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_matrix/expected.query",
    "content": "/loki/api/v1/query_range?end=&query=count+by%28detected_level%29+%28rate%28%7Bjob%3D%22varlogs%22%2C+filename%3D%22%2Fvar%2Flog%2FXorg.0.log%22%7D+%5B10m%5D%29%29&start=&step=10m0s\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_matrix/response_query_range.json",
    "content": "{\n    \"status\": \"success\",\n    \"data\": {\n        \"resultType\": \"matrix\",\n        \"result\": [\n            {\n                \"metric\": {\n                    \"detected_level\": \"error\"\n                },\n                \"values\": [\n                    [\n                        1762943400,\n                        \"1\"\n                    ]\n                ]\n            },\n            {\n                \"metric\": {\n                    \"detected_level\": \"info\"\n                },\n                \"values\": [\n                    [\n                        1762943400,\n                        \"1\"\n                    ]\n                ]\n            },\n            {\n                \"metric\": {\n                    \"detected_level\": \"unknown\"\n                },\n                \"values\": [\n                    [\n                        1762943400,\n                        \"1\"\n                    ]\n                ]\n            }\n        ],\n        \"stats\": {\n            \"summary\": {\n                \"bytesProcessedPerSecond\": 8285271,\n                \"linesProcessedPerSecond\": 68681,\n                \"totalBytesProcessed\": 59955,\n                \"totalLinesProcessed\": 497,\n                \"execTime\": 0.007236335,\n                \"queueTime\": 0.004703647,\n                \"subqueries\": 0,\n                \"totalEntriesReturned\": 3,\n                \"splits\": 7,\n                \"shards\": 7,\n                \"totalPostFilterLines\": 497,\n                \"totalStructuredMetadataBytesProcessed\": 14910\n            },\n            \"querier\": {\n                \"store\": {\n                    \"totalChunksRef\": 1,\n                    \"totalChunksDownloaded\": 1,\n                    \"chunksDownloadTime\": 142710,\n                    \"queryReferencedStructuredMetadata\": false,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 59955,\n                        \"decompressedLines\": 497,\n                        \"compressedBytes\": 9647,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 497,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 14910\n                    },\n                    \"chunkRefsFetchTime\": 388040,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"ingester\": {\n                \"totalReached\": 3,\n                \"totalChunksMatched\": 0,\n                \"totalBatches\": 3,\n                \"totalLinesSent\": 0,\n                \"store\": {\n                    \"totalChunksRef\": 0,\n                    \"totalChunksDownloaded\": 0,\n                    \"chunksDownloadTime\": 0,\n                    \"queryReferencedStructuredMetadata\": false,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 0,\n                        \"decompressedLines\": 0,\n                        \"compressedBytes\": 0,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 0,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 0\n                    },\n                    \"chunkRefsFetchTime\": 234280,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"cache\": {\n                \"chunk\": {\n                    \"entriesFound\": 1,\n                    \"entriesRequested\": 1,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 10027,\n                    \"bytesSent\": 0,\n                    \"requests\": 2,\n                    \"downloadTime\": 18840,\n                    \"queryLengthServed\": 0\n                },\n                \"index\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"result\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"statsResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 6,\n                    \"entriesStored\": 6,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 12,\n                    \"downloadTime\": 242980,\n                    \"queryLengthServed\": 0\n                },\n                \"volumeResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"seriesResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"labelResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"instantMetricResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                }\n            },\n            \"index\": {\n                \"totalChunks\": 0,\n                \"postFilterChunks\": 0,\n                \"shardsDuration\": 0,\n                \"usedBloomFilters\": false\n            }\n        }\n    }\n}"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_matrix/telegraf.conf",
    "content": "[[inputs.logql]]\n  url = \"dummy\"\n\n  [[inputs.logql.range]]\n    query = 'count by(detected_level) (rate({job=\"varlogs\", filename=\"/var/log/Xorg.0.log\"} [10m]))'\n    start = \"6h\"\n    step = \"10m\"\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_stream/expected.out",
    "content": "logql,detected_level=unknown,filename=/var/log/Xorg.0.log,job=varlogs,service_name=varlogs message=\"[     6.806] (--) Log file renamed from \\\"/var/log/Xorg.pid-693.log\\\" to \\\"/var/log/Xorg.0.log\\\"\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,job=varlogs,service_name=varlogs message=\"[     6.807] \" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,job=varlogs,service_name=varlogs message=\"X.Org X Server 1.21.1.14\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,job=varlogs,service_name=varlogs message=\"X Protocol Version 11, Revision 0\" 1762943173000000000\nlogql,detected_level=unknown,filename=/var/log/Xorg.0.log,job=varlogs,service_name=varlogs message=\"[     6.807] Current Operating System: Linux Hugin 6.12.1-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 22 Nov 2024 16:04:27 +0000 x86_64\""
  },
  {
    "path": "plugins/inputs/logql/testcases/range_stream/expected.query",
    "content": "/loki/api/v1/query_range?direction=forward&end=&limit=5&query=%7Bjob%3D%22varlogs%22%2C+filename%3D%22%2Fvar%2Flog%2FXorg.0.log%22%7D&start=\n"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_stream/response_query_range.json",
    "content": "{\n    \"status\": \"success\",\n    \"data\": {\n        \"resultType\": \"streams\",\n        \"result\": [\n            {\n                \"stream\": {\n                    \"detected_level\": \"unknown\",\n                    \"filename\": \"/var/log/Xorg.0.log\",\n                    \"job\": \"varlogs\",\n                    \"service_name\": \"varlogs\"\n                },\n                \"values\": [\n                    [\n                        \"1762943172891887962\",\n                        \"[     6.806] (--) Log file renamed from \\\"/var/log/Xorg.pid-693.log\\\" to \\\"/var/log/Xorg.0.log\\\"\"\n                    ],\n                    [\n                        \"1762943172891890282\",\n                        \"[     6.807] \"\n                    ],\n                    [\n                        \"1762943172891896732\",\n                        \"X.Org X Server 1.21.1.14\"\n                    ],\n                    [\n                        \"1762943172892086695\",\n                        \"X Protocol Version 11, Revision 0\"\n                    ],\n                    [\n                        \"1762943172892116545\",\n                        \"[     6.807] Current Operating System: Linux Hugin 6.12.1-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 22 Nov 2024 16:04:27 +0000 x86_64\"\n                    ]\n                ]\n            }\n        ],\n        \"stats\": {\n            \"summary\": {\n                \"bytesProcessedPerSecond\": 105996,\n                \"linesProcessedPerSecond\": 873,\n                \"totalBytesProcessed\": 728,\n                \"totalLinesProcessed\": 6,\n                \"execTime\": 0.006868,\n                \"queueTime\": 0.00136,\n                \"subqueries\": 0,\n                \"totalEntriesReturned\": 5,\n                \"splits\": 9,\n                \"shards\": 9,\n                \"totalPostFilterLines\": 6,\n                \"totalStructuredMetadataBytesProcessed\": 180\n            },\n            \"querier\": {\n                \"store\": {\n                    \"totalChunksRef\": 1,\n                    \"totalChunksDownloaded\": 1,\n                    \"chunksDownloadTime\": 80819,\n                    \"queryReferencedStructuredMetadata\": false,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 728,\n                        \"decompressedLines\": 6,\n                        \"compressedBytes\": 9647,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 6,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 180\n                    },\n                    \"chunkRefsFetchTime\": 450513,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"ingester\": {\n                \"totalReached\": 0,\n                \"totalChunksMatched\": 0,\n                \"totalBatches\": 0,\n                \"totalLinesSent\": 0,\n                \"store\": {\n                    \"totalChunksRef\": 0,\n                    \"totalChunksDownloaded\": 0,\n                    \"chunksDownloadTime\": 0,\n                    \"queryReferencedStructuredMetadata\": false,\n                    \"chunk\": {\n                        \"headChunkBytes\": 0,\n                        \"headChunkLines\": 0,\n                        \"decompressedBytes\": 0,\n                        \"decompressedLines\": 0,\n                        \"compressedBytes\": 0,\n                        \"totalDuplicates\": 0,\n                        \"postFilterLines\": 0,\n                        \"headChunkStructuredMetadataBytes\": 0,\n                        \"decompressedStructuredMetadataBytes\": 0\n                    },\n                    \"chunkRefsFetchTime\": 0,\n                    \"congestionControlLatency\": 0,\n                    \"pipelineWrapperFilteredLines\": 0\n                }\n            },\n            \"cache\": {\n                \"chunk\": {\n                    \"entriesFound\": 1,\n                    \"entriesRequested\": 1,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 10027,\n                    \"bytesSent\": 0,\n                    \"requests\": 2,\n                    \"downloadTime\": 17010,\n                    \"queryLengthServed\": 0\n                },\n                \"index\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"result\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"statsResult\": {\n                    \"entriesFound\": 9,\n                    \"entriesRequested\": 9,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 2160,\n                    \"bytesSent\": 0,\n                    \"requests\": 9,\n                    \"downloadTime\": 59339,\n                    \"queryLengthServed\": 30122000000000\n                },\n                \"volumeResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"seriesResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"labelResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                },\n                \"instantMetricResult\": {\n                    \"entriesFound\": 0,\n                    \"entriesRequested\": 0,\n                    \"entriesStored\": 0,\n                    \"bytesReceived\": 0,\n                    \"bytesSent\": 0,\n                    \"requests\": 0,\n                    \"downloadTime\": 0,\n                    \"queryLengthServed\": 0\n                }\n            },\n            \"index\": {\n                \"totalChunks\": 0,\n                \"postFilterChunks\": 0,\n                \"shardsDuration\": 0,\n                \"usedBloomFilters\": false\n            }\n        }\n    }\n}"
  },
  {
    "path": "plugins/inputs/logql/testcases/range_stream/telegraf.conf",
    "content": "[[inputs.logql]]\n  url = \"dummy\"\n\n  [[inputs.logql.range]]\n    query = '{job=\"varlogs\", filename=\"/var/log/Xorg.0.log\"}'\n    start = \"12h\"\n    sorting = \"forward\"\n    limit = 5\n"
  },
  {
    "path": "plugins/inputs/logstash/README.md",
    "content": "# Logstash Input Plugin\n\nThis plugin gathers metrics from a [Logstash][logstash] endpoint using the\n[Monitoring API][logstash_api].\n\n> [!NOTE]\n> This plugin supports Logstash 5+.\n\n⭐ Telegraf v1.12.0\n🏷️ server\n💻 all\n\n[logstash]: https://www.elastic.co/logstash\n[logstash_api]: https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics exposed by Logstash\n[[inputs.logstash]]\n  ## The URL of the exposed Logstash API endpoint.\n  url = \"http://127.0.0.1:9600\"\n\n  ## Use Logstash 5 single pipeline API, set to true when monitoring\n  ## Logstash 5.\n  # single_pipeline = false\n\n  ## Enable optional collection components.  Can contain\n  ## \"pipelines\", \"process\", and \"jvm\".\n  # collect = [\"pipelines\", \"process\", \"jvm\"]\n\n  ## Timeout for HTTP requests.\n  # timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials.\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config.\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification.\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## Optional HTTP headers.\n  # [inputs.logstash.headers]\n  #   \"X-Special-Header\" = \"Special-Value\"\n```\n\n## Metrics\n\nAdditional plugin stats may be collected (because logstash doesn't consistently\nexpose all stats)\n\n- logstash_jvm\n  - tags:\n    - node_id\n    - node_name\n    - node_host\n    - node_version\n  - fields:\n    - threads_peak_count\n    - mem_pools_survivor_peak_max_in_bytes\n    - mem_pools_survivor_max_in_bytes\n    - mem_pools_old_peak_used_in_bytes\n    - mem_pools_young_used_in_bytes\n    - mem_non_heap_committed_in_bytes\n    - threads_count\n    - mem_pools_old_committed_in_bytes\n    - mem_pools_young_peak_max_in_bytes\n    - mem_heap_used_percent\n    - gc_collectors_young_collection_time_in_millis\n    - mem_pools_survivor_peak_used_in_bytes\n    - mem_pools_young_committed_in_bytes\n    - gc_collectors_old_collection_time_in_millis\n    - gc_collectors_old_collection_count\n    - mem_pools_survivor_used_in_bytes\n    - mem_pools_old_used_in_bytes\n    - mem_pools_young_max_in_bytes\n    - mem_heap_max_in_bytes\n    - mem_non_heap_used_in_bytes\n    - mem_pools_survivor_committed_in_bytes\n    - mem_pools_old_max_in_bytes\n    - mem_heap_committed_in_bytes\n    - mem_pools_old_peak_max_in_bytes\n    - mem_pools_young_peak_used_in_bytes\n    - mem_heap_used_in_bytes\n    - gc_collectors_young_collection_count\n    - uptime_in_millis\n\n- logstash_process\n  - tags:\n    - node_id\n    - node_name\n    - source\n    - node_version\n  - fields:\n    - open_file_descriptors\n    - cpu_load_average_1m\n    - cpu_load_average_5m\n    - cpu_load_average_15m\n    - cpu_total_in_millis\n    - cpu_percent\n    - peak_open_file_descriptors\n    - max_file_descriptors\n    - mem_total_virtual_in_bytes\n    - mem_total_virtual_in_bytes\n\n- logstash_events\n  - tags:\n    - node_id\n    - node_name\n    - source\n    - node_version\n    - pipeline (for Logstash 6+)\n  - fields:\n    - queue_push_duration_in_millis\n    - duration_in_millis\n    - in\n    - filtered\n    - out\n\n- logstash_plugins\n  - tags:\n    - node_id\n    - node_name\n    - source\n    - node_version\n    - pipeline (for Logstash 6+)\n    - plugin_id\n    - plugin_name\n    - plugin_type\n  - fields:\n    - queue_push_duration_in_millis (for input plugins only)\n    - duration_in_millis\n    - in\n    - out\n    - failures(if exists)\n    - bulk_requests_failures (for Logstash 7+)\n    - bulk_requests_with_errors (for Logstash 7+)\n    - documents_successes (for logstash 7+)\n    - documents_retryable_failures (for logstash 7+)\n\n- logstash_queue\n  - tags:\n    - node_id\n    - node_name\n    - source\n    - node_version\n    - pipeline (for Logstash 6+)\n    - queue_type\n  - fields:\n    - events\n    - free_space_in_bytes\n    - max_queue_size_in_bytes\n    - max_unread_events\n    - page_capacity_in_bytes\n    - queue_size_in_bytes\n\n## Example Output\n\n```text\nlogstash_jvm,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,source=debian-stretch-logstash6.virt gc_collectors_old_collection_count=2,gc_collectors_old_collection_time_in_millis=100,gc_collectors_young_collection_count=26,gc_collectors_young_collection_time_in_millis=1028,mem_heap_committed_in_bytes=1056309248,mem_heap_max_in_bytes=1056309248,mem_heap_used_in_bytes=207216328,mem_heap_used_percent=19,mem_non_heap_committed_in_bytes=160878592,mem_non_heap_used_in_bytes=140838184,mem_pools_old_committed_in_bytes=899284992,mem_pools_old_max_in_bytes=899284992,mem_pools_old_peak_max_in_bytes=899284992,mem_pools_old_peak_used_in_bytes=189468088,mem_pools_old_used_in_bytes=189468088,mem_pools_survivor_committed_in_bytes=17432576,mem_pools_survivor_max_in_bytes=17432576,mem_pools_survivor_peak_max_in_bytes=17432576,mem_pools_survivor_peak_used_in_bytes=17432576,mem_pools_survivor_used_in_bytes=12572640,mem_pools_young_committed_in_bytes=139591680,mem_pools_young_max_in_bytes=139591680,mem_pools_young_peak_max_in_bytes=139591680,mem_pools_young_peak_used_in_bytes=139591680,mem_pools_young_used_in_bytes=5175600,threads_count=20,threads_peak_count=24,uptime_in_millis=739089 1566425244000000000\nlogstash_process,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,source=debian-stretch-logstash6.virt cpu_load_average_15m=0.03,cpu_load_average_1m=0.01,cpu_load_average_5m=0.04,cpu_percent=0,cpu_total_in_millis=83230,max_file_descriptors=16384,mem_total_virtual_in_bytes=3689132032,open_file_descriptors=118,peak_open_file_descriptors=118 1566425244000000000\nlogstash_events,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,pipeline=main,source=debian-stretch-logstash6.virt duration_in_millis=0,filtered=0,in=0,out=0,queue_push_duration_in_millis=0 1566425244000000000\nlogstash_plugins,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,pipeline=main,plugin_id=2807cb8610ba7854efa9159814fcf44c3dda762b43bd088403b30d42c88e69ab,plugin_name=beats,plugin_type=input,source=debian-stretch-logstash6.virt out=0,queue_push_duration_in_millis=0 1566425244000000000\nlogstash_plugins,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,pipeline=main,plugin_id=7a6c973366186a695727c73935634a00bccd52fceedf30d0746983fce572d50c,plugin_name=file,plugin_type=output,source=debian-stretch-logstash6.virt duration_in_millis=0,in=0,out=0 1566425244000000000\nlogstash_queue,node_id=3da53ed0-a946-4a33-9cdb-33013f2273f6,node_name=debian-stretch-logstash6.virt,node_version=6.8.1,pipeline=main,queue_type=memory,source=debian-stretch-logstash6.virt events=0 1566425244000000000\n```\n"
  },
  {
    "path": "plugins/inputs/logstash/logstash.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage logstash\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tjvmStatsNode       = \"/_node/stats/jvm\"\n\tprocessStatsNode   = \"/_node/stats/process\"\n\tpipelinesStatsNode = \"/_node/stats/pipelines\"\n\tpipelineStatsNode  = \"/_node/stats/pipeline\"\n)\n\ntype Logstash struct {\n\tURL string `toml:\"url\"`\n\n\tSinglePipeline bool     `toml:\"single_pipeline\"`\n\tCollect        []string `toml:\"collect\"`\n\n\tUsername string            `toml:\"username\"`\n\tPassword string            `toml:\"password\"`\n\tHeaders  map[string]string `toml:\"headers\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient *http.Client\n\tcommon_http.HTTPClientConfig\n}\n\ntype processStats struct {\n\tID      string      `json:\"id\"`\n\tProcess interface{} `json:\"process\"`\n\tName    string      `json:\"name\"`\n\tHost    string      `json:\"host\"`\n\tVersion string      `json:\"version\"`\n}\n\ntype jvmStats struct {\n\tID      string      `json:\"id\"`\n\tJVM     interface{} `json:\"jvm\"`\n\tName    string      `json:\"name\"`\n\tHost    string      `json:\"host\"`\n\tVersion string      `json:\"version\"`\n}\n\ntype pipelinesStats struct {\n\tID        string              `json:\"id\"`\n\tPipelines map[string]pipeline `json:\"pipelines\"`\n\tName      string              `json:\"name\"`\n\tHost      string              `json:\"host\"`\n\tVersion   string              `json:\"version\"`\n}\n\ntype pipelineStats struct {\n\tID       string   `json:\"id\"`\n\tPipeline pipeline `json:\"pipeline\"`\n\tName     string   `json:\"name\"`\n\tHost     string   `json:\"host\"`\n\tVersion  string   `json:\"version\"`\n}\n\ntype pipeline struct {\n\tEvents  interface{}     `json:\"events\"`\n\tPlugins pipelinePlugins `json:\"plugins\"`\n\tReloads interface{}     `json:\"reloads\"`\n\tQueue   pipelineQueue   `json:\"queue\"`\n}\n\ntype plugin struct {\n\tID           string                 `json:\"id\"`\n\tEvents       interface{}            `json:\"events\"`\n\tName         string                 `json:\"name\"`\n\tFailures     *int64                 `json:\"failures,omitempty\"`\n\tBulkRequests map[string]interface{} `json:\"bulk_requests\"`\n\tDocuments    map[string]interface{} `json:\"documents\"`\n}\n\ntype pipelinePlugins struct {\n\tInputs  []plugin `json:\"inputs\"`\n\tFilters []plugin `json:\"filters\"`\n\tOutputs []plugin `json:\"outputs\"`\n}\n\ntype pipelineQueue struct {\n\tEvents              float64     `json:\"events\"`\n\tEventsCount         *float64    `json:\"events_count\"`\n\tType                string      `json:\"type\"`\n\tCapacity            interface{} `json:\"capacity\"`\n\tData                interface{} `json:\"data\"`\n\tQueueSizeInBytes    *float64    `json:\"queue_size_in_bytes\"`\n\tMaxQueueSizeInBytes *float64    `json:\"max_queue_size_in_bytes\"`\n}\n\nfunc (*Logstash) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (logstash *Logstash) Init() error {\n\terr := choice.CheckSlice(logstash.Collect, []string{\"pipelines\", \"process\", \"jvm\"})\n\tif err != nil {\n\t\treturn fmt.Errorf(`cannot verify \"collect\" setting: %w`, err)\n\t}\n\treturn nil\n}\n\nfunc (*Logstash) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (logstash *Logstash) Gather(accumulator telegraf.Accumulator) error {\n\tif logstash.client == nil {\n\t\tclient, err := logstash.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tlogstash.client = client\n\t}\n\n\tif choice.Contains(\"jvm\", logstash.Collect) {\n\t\tjvmURL, err := url.Parse(logstash.URL + jvmStatsNode)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := logstash.gatherJVMStats(jvmURL.String(), accumulator); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif choice.Contains(\"process\", logstash.Collect) {\n\t\tprocessURL, err := url.Parse(logstash.URL + processStatsNode)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := logstash.gatherProcessStats(processURL.String(), accumulator); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif choice.Contains(\"pipelines\", logstash.Collect) {\n\t\tif logstash.SinglePipeline {\n\t\t\tpipelineURL, err := url.Parse(logstash.URL + pipelineStatsNode)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := logstash.gatherPipelineStats(pipelineURL.String(), accumulator); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tpipelinesURL, err := url.Parse(logstash.URL + pipelinesStatsNode)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := logstash.gatherPipelinesStats(pipelinesURL.String(), accumulator); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (logstash *Logstash) Stop() {\n\tif logstash.client != nil {\n\t\tlogstash.client.CloseIdleConnections()\n\t}\n}\n\n// createHTTPClient create a clients to access API\nfunc (logstash *Logstash) createHTTPClient() (*http.Client, error) {\n\tctx := context.Background()\n\treturn logstash.HTTPClientConfig.CreateClient(ctx, logstash.Log)\n}\n\n// gatherJSONData query the data source and parse the response JSON\nfunc (logstash *Logstash) gatherJSONData(address string, value interface{}) error {\n\trequest, err := http.NewRequest(\"GET\", address, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif (logstash.Username != \"\") || (logstash.Password != \"\") {\n\t\trequest.SetBasicAuth(logstash.Username, logstash.Password)\n\t}\n\n\tfor header, value := range logstash.Headers {\n\t\tif strings.EqualFold(header, \"host\") {\n\t\t\trequest.Host = value\n\t\t} else {\n\t\t\trequest.Header.Add(header, value)\n\t\t}\n\t}\n\n\tresponse, err := logstash.client.Do(request)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer response.Body.Close()\n\tif response.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(response.Body, 200))\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s: %q\", address, response.Status, body)\n\t}\n\n\terr = json.NewDecoder(response.Body).Decode(value)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// gatherJVMStats gather the JVM metrics and add results to the accumulator\nfunc (logstash *Logstash) gatherJVMStats(address string, accumulator telegraf.Accumulator) error {\n\tjvmStats := &jvmStats{}\n\n\terr := logstash.gatherJSONData(address, jvmStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := map[string]string{\n\t\t\"node_id\":      jvmStats.ID,\n\t\t\"node_name\":    jvmStats.Name,\n\t\t\"node_version\": jvmStats.Version,\n\t\t\"source\":       jvmStats.Host,\n\t}\n\n\tflattener := parsers_json.JSONFlattener{}\n\terr = flattener.FlattenJSON(\"\", jvmStats.JVM)\n\tif err != nil {\n\t\treturn err\n\t}\n\taccumulator.AddFields(\"logstash_jvm\", flattener.Fields, tags)\n\n\treturn nil\n}\n\n// gatherProcessStats gather the Process metrics and add results to the accumulator\nfunc (logstash *Logstash) gatherProcessStats(address string, accumulator telegraf.Accumulator) error {\n\tprocessStats := &processStats{}\n\n\terr := logstash.gatherJSONData(address, processStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := map[string]string{\n\t\t\"node_id\":      processStats.ID,\n\t\t\"node_name\":    processStats.Name,\n\t\t\"node_version\": processStats.Version,\n\t\t\"source\":       processStats.Host,\n\t}\n\n\tflattener := parsers_json.JSONFlattener{}\n\terr = flattener.FlattenJSON(\"\", processStats.Process)\n\tif err != nil {\n\t\treturn err\n\t}\n\taccumulator.AddFields(\"logstash_process\", flattener.Fields, tags)\n\n\treturn nil\n}\n\n// gatherPluginsStats go through a list of plugins and add their metrics to the accumulator\nfunc gatherPluginsStats(plugins []plugin, pluginType string, tags map[string]string, accumulator telegraf.Accumulator) error {\n\tfor _, plugin := range plugins {\n\t\tpluginTags := map[string]string{\n\t\t\t\"plugin_name\": plugin.Name,\n\t\t\t\"plugin_id\":   plugin.ID,\n\t\t\t\"plugin_type\": pluginType,\n\t\t}\n\t\tfor tag, value := range tags {\n\t\t\tpluginTags[tag] = value\n\t\t}\n\t\tflattener := parsers_json.JSONFlattener{}\n\t\terr := flattener.FlattenJSON(\"\", plugin.Events)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\taccumulator.AddFields(\"logstash_plugins\", flattener.Fields, pluginTags)\n\t\tif plugin.Failures != nil {\n\t\t\tfailuresFields := map[string]interface{}{\"failures\": *plugin.Failures}\n\t\t\taccumulator.AddFields(\"logstash_plugins\", failuresFields, pluginTags)\n\t\t}\n\t\t/*\n\t\t\tThe elasticsearch & opensearch output produces additional stats\n\t\t\taround bulk requests and document writes (that are elasticsearch\n\t\t\tand opensearch specific). Collect those below:\n\t\t*/\n\t\tif pluginType == \"output\" && (plugin.Name == \"elasticsearch\" || plugin.Name == \"opensearch\") {\n\t\t\t/*\n\t\t\t\tThe \"bulk_requests\" section has details about batch writes\n\t\t\t\tinto Elasticsearch\n\n\t\t\t\t  \"bulk_requests\" : {\n\t\t\t\t\t\"successes\" : 2870,\n\t\t\t\t\t\"responses\" : {\n\t\t\t\t\t  \"200\" : 2870\n\t\t\t\t\t},\n\t\t\t\t\t\"failures\": 262,\n\t\t\t\t\t\"with_errors\": 9089\n\t\t\t\t  },\n\t\t\t*/\n\t\t\tflattener := parsers_json.JSONFlattener{}\n\t\t\terr := flattener.FlattenJSON(\"\", plugin.BulkRequests)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor k, v := range flattener.Fields {\n\t\t\t\tif strings.HasPrefix(k, \"bulk_requests\") {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnewKey := \"bulk_requests_\" + k\n\t\t\t\tflattener.Fields[newKey] = v\n\t\t\t\tdelete(flattener.Fields, k)\n\t\t\t}\n\t\t\taccumulator.AddFields(\"logstash_plugins\", flattener.Fields, pluginTags)\n\n\t\t\t/*\n\t\t\t\tThe \"documents\" section has counts of individual documents\n\t\t\t\twritten/retried/etc.\n\t\t\t\t  \"documents\" : {\n\t\t\t\t\t\"successes\" : 2665549,\n\t\t\t\t\t\"retryable_failures\": 13733\n\t\t\t\t  }\n\t\t\t*/\n\t\t\tflattener = parsers_json.JSONFlattener{}\n\t\t\terr = flattener.FlattenJSON(\"\", plugin.Documents)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor k, v := range flattener.Fields {\n\t\t\t\tif strings.HasPrefix(k, \"documents\") {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnewKey := \"documents_\" + k\n\t\t\t\tflattener.Fields[newKey] = v\n\t\t\t\tdelete(flattener.Fields, k)\n\t\t\t}\n\t\t\taccumulator.AddFields(\"logstash_plugins\", flattener.Fields, pluginTags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc gatherQueueStats(queue pipelineQueue, tags map[string]string, acc telegraf.Accumulator) error {\n\tqueueTags := map[string]string{\n\t\t\"queue_type\": queue.Type,\n\t}\n\tfor tag, value := range tags {\n\t\tqueueTags[tag] = value\n\t}\n\n\tevents := queue.Events\n\tif queue.EventsCount != nil {\n\t\tevents = *queue.EventsCount\n\t}\n\n\tqueueFields := map[string]interface{}{\n\t\t\"events\": events,\n\t}\n\n\tif queue.Type != \"memory\" {\n\t\tflattener := parsers_json.JSONFlattener{}\n\t\terr := flattener.FlattenJSON(\"\", queue.Capacity)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = flattener.FlattenJSON(\"\", queue.Data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor field, value := range flattener.Fields {\n\t\t\tqueueFields[field] = value\n\t\t}\n\n\t\tif queue.MaxQueueSizeInBytes != nil {\n\t\t\tqueueFields[\"max_queue_size_in_bytes\"] = *queue.MaxQueueSizeInBytes\n\t\t}\n\n\t\tif queue.QueueSizeInBytes != nil {\n\t\t\tqueueFields[\"queue_size_in_bytes\"] = *queue.QueueSizeInBytes\n\t\t}\n\t}\n\n\tacc.AddFields(\"logstash_queue\", queueFields, queueTags)\n\n\treturn nil\n}\n\n// gatherPipelineStats gather the Pipeline metrics and add results to the accumulator (for Logstash < 6)\nfunc (logstash *Logstash) gatherPipelineStats(address string, accumulator telegraf.Accumulator) error {\n\tpipelineStats := &pipelineStats{}\n\n\terr := logstash.gatherJSONData(address, pipelineStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := map[string]string{\n\t\t\"node_id\":      pipelineStats.ID,\n\t\t\"node_name\":    pipelineStats.Name,\n\t\t\"node_version\": pipelineStats.Version,\n\t\t\"source\":       pipelineStats.Host,\n\t}\n\n\tflattener := parsers_json.JSONFlattener{}\n\terr = flattener.FlattenJSON(\"\", pipelineStats.Pipeline.Events)\n\tif err != nil {\n\t\treturn err\n\t}\n\taccumulator.AddFields(\"logstash_events\", flattener.Fields, tags)\n\n\terr = gatherPluginsStats(pipelineStats.Pipeline.Plugins.Inputs, \"input\", tags, accumulator)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = gatherPluginsStats(pipelineStats.Pipeline.Plugins.Filters, \"filter\", tags, accumulator)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = gatherPluginsStats(pipelineStats.Pipeline.Plugins.Outputs, \"output\", tags, accumulator)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = gatherQueueStats(pipelineStats.Pipeline.Queue, tags, accumulator)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// gatherPipelinesStats gather the Pipelines metrics and add results to the accumulator (for Logstash >= 6)\nfunc (logstash *Logstash) gatherPipelinesStats(address string, accumulator telegraf.Accumulator) error {\n\tpipelinesStats := &pipelinesStats{}\n\n\terr := logstash.gatherJSONData(address, pipelinesStats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor pipelineName, pipeline := range pipelinesStats.Pipelines {\n\t\ttags := map[string]string{\n\t\t\t\"node_id\":      pipelinesStats.ID,\n\t\t\t\"node_name\":    pipelinesStats.Name,\n\t\t\t\"node_version\": pipelinesStats.Version,\n\t\t\t\"pipeline\":     pipelineName,\n\t\t\t\"source\":       pipelinesStats.Host,\n\t\t}\n\n\t\tflattener := parsers_json.JSONFlattener{}\n\t\terr := flattener.FlattenJSON(\"\", pipeline.Events)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\taccumulator.AddFields(\"logstash_events\", flattener.Fields, tags)\n\n\t\terr = gatherPluginsStats(pipeline.Plugins.Inputs, \"input\", tags, accumulator)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = gatherPluginsStats(pipeline.Plugins.Filters, \"filter\", tags, accumulator)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = gatherPluginsStats(pipeline.Plugins.Outputs, \"output\", tags, accumulator)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = gatherQueueStats(pipeline.Queue, tags, accumulator)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc newLogstash() *Logstash {\n\treturn &Logstash{\n\t\tURL:     \"http://127.0.0.1:9600\",\n\t\tCollect: []string{\"pipelines\", \"process\", \"jvm\"},\n\t\tHeaders: make(map[string]string),\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t},\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"logstash\", func() telegraf.Input {\n\t\treturn newLogstash()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/logstash/logstash_test.go",
    "content": "package logstash\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar logstashTest = newLogstash()\n\nvar (\n\tlogstash5accPipelineStats  testutil.Accumulator\n\tlogstash6accPipelinesStats testutil.Accumulator\n\tlogstash7accPipelinesStats testutil.Accumulator\n\tlogstash5accProcessStats   testutil.Accumulator\n\tlogstash6accProcessStats   testutil.Accumulator\n\tlogstash5accJVMStats       testutil.Accumulator\n\tlogstash6accJVMStats       testutil.Accumulator\n)\n\nfunc Test_Logstash5GatherProcessStats(test *testing.T) {\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash5ProcessJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherProcessStats(logstashTest.URL+processStatsNode, &logstash5accProcessStats)\n\trequire.NoError(test, err, \"Can't gather Process stats\")\n\n\tlogstash5accProcessStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_process\",\n\t\tmap[string]interface{}{\n\t\t\t\"open_file_descriptors\":      float64(89.0),\n\t\t\t\"max_file_descriptors\":       float64(1.048576e+06),\n\t\t\t\"cpu_percent\":                float64(3.0),\n\t\t\t\"cpu_load_average_5m\":        float64(0.61),\n\t\t\t\"cpu_load_average_15m\":       float64(0.54),\n\t\t\t\"mem_total_virtual_in_bytes\": float64(4.809506816e+09),\n\t\t\t\"cpu_total_in_millis\":        float64(1.5526e+11),\n\t\t\t\"cpu_load_average_1m\":        float64(0.49),\n\t\t\t\"peak_open_file_descriptors\": float64(100.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash6GatherProcessStats(test *testing.T) {\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash6ProcessJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherProcessStats(logstashTest.URL+processStatsNode, &logstash6accProcessStats)\n\trequire.NoError(test, err, \"Can't gather Process stats\")\n\n\tlogstash6accProcessStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_process\",\n\t\tmap[string]interface{}{\n\t\t\t\"open_file_descriptors\":      float64(133.0),\n\t\t\t\"max_file_descriptors\":       float64(262144.0),\n\t\t\t\"cpu_percent\":                float64(0.0),\n\t\t\t\"cpu_load_average_5m\":        float64(42.4),\n\t\t\t\"cpu_load_average_15m\":       float64(38.95),\n\t\t\t\"mem_total_virtual_in_bytes\": float64(17923452928.0),\n\t\t\t\"cpu_total_in_millis\":        float64(5841460),\n\t\t\t\"cpu_load_average_1m\":        float64(48.2),\n\t\t\t\"peak_open_file_descriptors\": float64(145.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash5GatherPipelineStats(test *testing.T) {\n\tlogstash5accPipelineStats.SetDebug(true)\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash5PipelineJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherPipelineStats(logstashTest.URL+pipelineStatsNode, &logstash5accPipelineStats)\n\trequire.NoError(test, err, \"Can't gather Pipeline stats\")\n\n\tlogstash5accPipelineStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_events\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(1151.0),\n\t\t\t\"in\":                 float64(1269.0),\n\t\t\t\"filtered\":           float64(1269.0),\n\t\t\t\"out\":                float64(1269.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t},\n\t)\n\n\tfields := make(map[string]interface{})\n\tfields[\"queue_push_duration_in_millis\"] = float64(32.0)\n\tfields[\"out\"] = float64(2.0)\n\n\tlogstash5accPipelineStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tfields,\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t\t\"plugin_name\":  string(\"beats\"),\n\t\t\t\"plugin_id\":    string(\"a35197a509596954e905e38521bae12b1498b17d-1\"),\n\t\t\t\"plugin_type\":  string(\"input\"),\n\t\t},\n\t)\n\n\tlogstash5accPipelineStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(360.0),\n\t\t\t\"in\":                 float64(1269.0),\n\t\t\t\"out\":                float64(1269.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t\t\"plugin_name\":  string(\"stdout\"),\n\t\t\t\"plugin_id\":    string(\"582d5c2becb582a053e1e9a6bcc11d49b69a6dfd-2\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\n\tlogstash5accPipelineStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(228.0),\n\t\t\t\"in\":                 float64(1269.0),\n\t\t\t\"out\":                float64(1269.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t\t\"plugin_name\":  string(\"s3\"),\n\t\t\t\"plugin_id\":    string(\"582d5c2becb582a053e1e9a6bcc11d49b69a6dfd-3\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash6GatherPipelinesStats(test *testing.T) {\n\tlogstash6accPipelinesStats.SetDebug(true)\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash6PipelinesJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherPipelinesStats(logstashTest.URL+pipelineStatsNode, &logstash6accPipelinesStats)\n\trequire.NoError(test, err, \"Can't gather Pipeline stats\")\n\n\tfields := make(map[string]interface{})\n\tfields[\"duration_in_millis\"] = float64(8540751.0)\n\tfields[\"queue_push_duration_in_millis\"] = float64(366.0)\n\tfields[\"in\"] = float64(180659.0)\n\tfields[\"filtered\"] = float64(180659.0)\n\tfields[\"out\"] = float64(180659.0)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_events\",\n\t\tfields,\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t},\n\t)\n\n\tfields = make(map[string]interface{})\n\tfields[\"queue_push_duration_in_millis\"] = float64(366.0)\n\tfields[\"out\"] = float64(180659.0)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tfields,\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"kafka\"),\n\t\t\t\"plugin_id\":    string(\"input-kafka\"),\n\t\t\t\"plugin_type\":  string(\"input\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(2117.0),\n\t\t\t\"in\":                 float64(27641.0),\n\t\t\t\"out\":                float64(27641.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"155b0ad18abbf3df1e0cb7bddef0d77c5ba699efe5a0f8a28502d140549baf54\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(2117.0),\n\t\t\t\"in\":                 float64(27641.0),\n\t\t\t\"out\":                float64(27641.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"155b0ad18abbf3df1e0cb7bddef0d77c5ba699efe5a0f8a28502d140549baf54\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(13149.0),\n\t\t\t\"in\":                 float64(180659.0),\n\t\t\t\"out\":                float64(177549.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"date\"),\n\t\t\t\"plugin_id\":    string(\"d079424bb6b7b8c7c61d9c5e0ddae445e92fa9ffa2e8690b0a669f7c690542f0\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"failures\": int64(2),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"date\"),\n\t\t\t\"plugin_id\":    string(\"d079424bb6b7b8c7c61d9c5e0ddae445e92fa9ffa2e8690b0a669f7c690542f0\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(2814.0),\n\t\t\t\"in\":                 float64(76602.0),\n\t\t\t\"out\":                float64(76602.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"25afa60ab6dc30512fe80efa3493e4928b5b1b109765b7dc46a3e4bbf293d2d4\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(9.0),\n\t\t\t\"in\":                 float64(934.0),\n\t\t\t\"out\":                float64(934.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"2d9fa8f74eeb137bfa703b8050bad7d76636fface729e4585b789b5fc9bed668\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(173.0),\n\t\t\t\"in\":                 float64(3110.0),\n\t\t\t\"out\":                float64(0.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"drop\"),\n\t\t\t\"plugin_id\":    string(\"4ed14c9ef0198afe16c31200041e98d321cb5c2e6027e30b077636b8c4842110\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(5605.0),\n\t\t\t\"in\":                 float64(75482.0),\n\t\t\t\"out\":                float64(75482.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"358ce1eb387de7cd5711c2fb4de64cd3b12e5ca9a4c45f529516bcb053a31df4\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(313992.0),\n\t\t\t\"in\":                 float64(180659.0),\n\t\t\t\"out\":                float64(180659.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"csv\"),\n\t\t\t\"plugin_id\":    string(\"82a9bbb02fff37a63c257c1f146b0a36273c7cbbebe83c0a51f086e5280bf7bb\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(0.0),\n\t\t\t\"in\":                 float64(0.0),\n\t\t\t\"out\":                float64(0.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"mutate\"),\n\t\t\t\"plugin_id\":    string(\"8fb13a8cdd4257b52724d326aa1549603ffdd4e4fde6d20720c96b16238c18c3\"),\n\t\t\t\"plugin_type\":  string(\"filter\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(651386.0),\n\t\t\t\"in\":                 float64(177549.0),\n\t\t\t\"out\":                float64(177549.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"elasticsearch\"),\n\t\t\t\"plugin_id\":    string(\"output-elk\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(186751.0),\n\t\t\t\"in\":                 float64(177549.0),\n\t\t\t\"out\":                float64(177549.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"kafka\"),\n\t\t\t\"plugin_id\":    string(\"output-kafka1\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(7335196.0),\n\t\t\t\"in\":                 float64(177549.0),\n\t\t\t\"out\":                float64(177549.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"plugin_name\":  string(\"kafka\"),\n\t\t\t\"plugin_id\":    string(\"output-kafka2\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\n\tlogstash6accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_queue\",\n\t\tmap[string]interface{}{\n\t\t\t\"events\":                  float64(103),\n\t\t\t\"free_space_in_bytes\":     float64(36307369984),\n\t\t\t\"max_queue_size_in_bytes\": float64(1073741824),\n\t\t\t\"max_unread_events\":       float64(0),\n\t\t\t\"page_capacity_in_bytes\":  float64(67108864),\n\t\t\t\"queue_size_in_bytes\":     float64(1872391),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t\t\"pipeline\":     string(\"main\"),\n\t\t\t\"queue_type\":   string(\"persisted\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash5GatherJVMStats(test *testing.T) {\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash5JvmJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherJVMStats(logstashTest.URL+jvmStatsNode, &logstash5accJVMStats)\n\trequire.NoError(test, err, \"Can't gather JVM stats\")\n\n\tlogstash5accJVMStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_jvm\",\n\t\tmap[string]interface{}{\n\t\t\t\"mem_pools_young_max_in_bytes\":                  float64(5.5836672e+08),\n\t\t\t\"mem_pools_young_committed_in_bytes\":            float64(1.43261696e+08),\n\t\t\t\"mem_heap_committed_in_bytes\":                   float64(5.1904512e+08),\n\t\t\t\"threads_count\":                                 float64(29.0),\n\t\t\t\"mem_pools_old_peak_used_in_bytes\":              float64(1.27900864e+08),\n\t\t\t\"mem_pools_old_peak_max_in_bytes\":               float64(7.2482816e+08),\n\t\t\t\"mem_heap_used_percent\":                         float64(16.0),\n\t\t\t\"gc_collectors_young_collection_time_in_millis\": float64(3235.0),\n\t\t\t\"mem_pools_survivor_committed_in_bytes\":         float64(1.7825792e+07),\n\t\t\t\"mem_pools_young_used_in_bytes\":                 float64(7.6049384e+07),\n\t\t\t\"mem_non_heap_committed_in_bytes\":               float64(2.91487744e+08),\n\t\t\t\"mem_pools_survivor_peak_max_in_bytes\":          float64(3.4865152e+07),\n\t\t\t\"mem_pools_young_peak_max_in_bytes\":             float64(2.7918336e+08),\n\t\t\t\"uptime_in_millis\":                              float64(4.803461e+06),\n\t\t\t\"mem_pools_survivor_peak_used_in_bytes\":         float64(8.912896e+06),\n\t\t\t\"mem_pools_survivor_max_in_bytes\":               float64(6.9730304e+07),\n\t\t\t\"gc_collectors_old_collection_count\":            float64(2.0),\n\t\t\t\"mem_pools_survivor_used_in_bytes\":              float64(9.419672e+06),\n\t\t\t\"mem_pools_old_used_in_bytes\":                   float64(2.55801728e+08),\n\t\t\t\"mem_pools_old_max_in_bytes\":                    float64(1.44965632e+09),\n\t\t\t\"mem_pools_young_peak_used_in_bytes\":            float64(7.1630848e+07),\n\t\t\t\"mem_heap_used_in_bytes\":                        float64(3.41270784e+08),\n\t\t\t\"mem_heap_max_in_bytes\":                         float64(2.077753344e+09),\n\t\t\t\"gc_collectors_young_collection_count\":          float64(616.0),\n\t\t\t\"threads_peak_count\":                            float64(31.0),\n\t\t\t\"mem_pools_old_committed_in_bytes\":              float64(3.57957632e+08),\n\t\t\t\"gc_collectors_old_collection_time_in_millis\":   float64(114.0),\n\t\t\t\"mem_non_heap_used_in_bytes\":                    float64(2.68905936e+08),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"a360d8cf-6289-429d-8419-6145e324b574\"),\n\t\t\t\"node_name\":    string(\"node-5-test\"),\n\t\t\t\"source\":       string(\"node-5\"),\n\t\t\t\"node_version\": string(\"5.3.0\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash6GatherJVMStats(test *testing.T) {\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := fmt.Fprintf(writer, \"%s\", logstash6JvmJSON); err != nil {\n\t\t\twriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\trequire.NoErrorf(test, err, \"Can't connect to: %s\", logstashTest.URL)\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\t\trequire.NoError(test, err, \"Can't createHTTPClient\")\n\t\tlogstashTest.client = client\n\t}\n\n\terr = logstashTest.gatherJVMStats(logstashTest.URL+jvmStatsNode, &logstash6accJVMStats)\n\trequire.NoError(test, err, \"Can't gather JVM stats\")\n\n\tlogstash6accJVMStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_jvm\",\n\t\tmap[string]interface{}{\n\t\t\t\"mem_pools_young_max_in_bytes\":                  float64(1605304320.0),\n\t\t\t\"mem_pools_young_committed_in_bytes\":            float64(71630848.0),\n\t\t\t\"mem_heap_committed_in_bytes\":                   float64(824963072.0),\n\t\t\t\"threads_count\":                                 float64(60.0),\n\t\t\t\"mem_pools_old_peak_used_in_bytes\":              float64(696572600.0),\n\t\t\t\"mem_pools_old_peak_max_in_bytes\":               float64(6583418880.0),\n\t\t\t\"mem_heap_used_percent\":                         float64(2.0),\n\t\t\t\"gc_collectors_young_collection_time_in_millis\": float64(107321.0),\n\t\t\t\"mem_pools_survivor_committed_in_bytes\":         float64(8912896.0),\n\t\t\t\"mem_pools_young_used_in_bytes\":                 float64(11775120.0),\n\t\t\t\"mem_non_heap_committed_in_bytes\":               float64(222986240.0),\n\t\t\t\"mem_pools_survivor_peak_max_in_bytes\":          float64(200605696),\n\t\t\t\"mem_pools_young_peak_max_in_bytes\":             float64(1605304320.0),\n\t\t\t\"uptime_in_millis\":                              float64(281850926.0),\n\t\t\t\"mem_pools_survivor_peak_used_in_bytes\":         float64(8912896.0),\n\t\t\t\"mem_pools_survivor_max_in_bytes\":               float64(200605696.0),\n\t\t\t\"gc_collectors_old_collection_count\":            float64(37.0),\n\t\t\t\"mem_pools_survivor_used_in_bytes\":              float64(835008.0),\n\t\t\t\"mem_pools_old_used_in_bytes\":                   float64(189750576.0),\n\t\t\t\"mem_pools_old_max_in_bytes\":                    float64(6583418880.0),\n\t\t\t\"mem_pools_young_peak_used_in_bytes\":            float64(71630848.0),\n\t\t\t\"mem_heap_used_in_bytes\":                        float64(202360704.0),\n\t\t\t\"mem_heap_max_in_bytes\":                         float64(8389328896.0),\n\t\t\t\"gc_collectors_young_collection_count\":          float64(2094.0),\n\t\t\t\"threads_peak_count\":                            float64(62.0),\n\t\t\t\"mem_pools_old_committed_in_bytes\":              float64(744419328.0),\n\t\t\t\"gc_collectors_old_collection_time_in_millis\":   float64(7492.0),\n\t\t\t\"mem_non_heap_used_in_bytes\":                    float64(197878896.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"3044f675-21ce-4335-898a-8408aa678245\"),\n\t\t\t\"node_name\":    string(\"node-6-test\"),\n\t\t\t\"source\":       string(\"node-6\"),\n\t\t\t\"node_version\": string(\"6.4.2\"),\n\t\t},\n\t)\n}\n\nfunc Test_Logstash7GatherPipelinesQueueStats(test *testing.T) {\n\tfakeServer := httptest.NewUnstartedServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {\n\t\twriter.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_, err := fmt.Fprintf(writer, \"%s\", string(logstash7PipelinesJSON))\n\t\tif err != nil {\n\t\t\ttest.Logf(\"Can't print test json\")\n\t\t}\n\t}))\n\trequestURL, err := url.Parse(logstashTest.URL)\n\tif err != nil {\n\t\ttest.Logf(\"Can't connect to: %s\", logstashTest.URL)\n\t}\n\tfakeServer.Listener, err = net.Listen(\"tcp\", fmt.Sprintf(\"%s:%s\", requestURL.Hostname(), requestURL.Port()))\n\trequire.NoError(test, err)\n\tfakeServer.Start()\n\tdefer fakeServer.Close()\n\n\tif logstashTest.client == nil {\n\t\tclient, err := logstashTest.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\ttest.Logf(\"Can't createHTTPClient\")\n\t\t}\n\t\tlogstashTest.client = client\n\t}\n\n\tif err := logstashTest.gatherPipelinesStats(logstashTest.URL+pipelineStatsNode, &logstash7accPipelinesStats); err != nil {\n\t\ttest.Logf(\"Can't gather Pipeline stats\")\n\t}\n\n\tfields := make(map[string]interface{})\n\tfields[\"duration_in_millis\"] = float64(3032875.0)\n\tfields[\"queue_push_duration_in_millis\"] = float64(13300.0)\n\tfields[\"in\"] = float64(2665549.0)\n\tfields[\"filtered\"] = float64(2665549.0)\n\tfields[\"out\"] = float64(2665549.0)\n\n\tlogstash7accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_events\",\n\t\tfields,\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"28580380-ad2c-4032-934b-76359125edca\"),\n\t\t\t\"node_name\":    string(\"HOST01.local\"),\n\t\t\t\"source\":       string(\"HOST01.local\"),\n\t\t\t\"node_version\": string(\"7.4.2\"),\n\t\t\t\"pipeline\":     string(\"infra\"),\n\t\t},\n\t)\n\n\tlogstash7accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"duration_in_millis\": float64(2802177.0),\n\t\t\t\"in\":                 float64(2665549.0),\n\t\t\t\"out\":                float64(2665549.0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"28580380-ad2c-4032-934b-76359125edca\"),\n\t\t\t\"node_name\":    string(\"HOST01.local\"),\n\t\t\t\"source\":       string(\"HOST01.local\"),\n\t\t\t\"node_version\": string(\"7.4.2\"),\n\t\t\t\"pipeline\":     string(\"infra\"),\n\t\t\t\"plugin_name\":  string(\"elasticsearch\"),\n\t\t\t\"plugin_id\":    string(\"38967f09bbd2647a95aa00702b6b557bdbbab31da6a04f991d38abe5629779e3\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\tlogstash7accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"bulk_requests_successes\":     float64(2870),\n\t\t\t\"bulk_requests_responses_200\": float64(2870),\n\t\t\t\"bulk_requests_failures\":      float64(262),\n\t\t\t\"bulk_requests_with_errors\":   float64(9089),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"28580380-ad2c-4032-934b-76359125edca\"),\n\t\t\t\"node_name\":    string(\"HOST01.local\"),\n\t\t\t\"source\":       string(\"HOST01.local\"),\n\t\t\t\"node_version\": string(\"7.4.2\"),\n\t\t\t\"pipeline\":     string(\"infra\"),\n\t\t\t\"plugin_name\":  string(\"elasticsearch\"),\n\t\t\t\"plugin_id\":    string(\"38967f09bbd2647a95aa00702b6b557bdbbab31da6a04f991d38abe5629779e3\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\tlogstash7accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_plugins\",\n\t\tmap[string]interface{}{\n\t\t\t\"documents_successes\":          float64(2665549),\n\t\t\t\"documents_retryable_failures\": float64(13733),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"28580380-ad2c-4032-934b-76359125edca\"),\n\t\t\t\"node_name\":    string(\"HOST01.local\"),\n\t\t\t\"source\":       string(\"HOST01.local\"),\n\t\t\t\"node_version\": string(\"7.4.2\"),\n\t\t\t\"pipeline\":     string(\"infra\"),\n\t\t\t\"plugin_name\":  string(\"elasticsearch\"),\n\t\t\t\"plugin_id\":    string(\"38967f09bbd2647a95aa00702b6b557bdbbab31da6a04f991d38abe5629779e3\"),\n\t\t\t\"plugin_type\":  string(\"output\"),\n\t\t},\n\t)\n\n\tlogstash7accPipelinesStats.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"logstash_queue\",\n\t\tmap[string]interface{}{\n\t\t\t\"events\":                  float64(0),\n\t\t\t\"max_queue_size_in_bytes\": float64(4294967296),\n\t\t\t\"queue_size_in_bytes\":     float64(32028566),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"node_id\":      string(\"28580380-ad2c-4032-934b-76359125edca\"),\n\t\t\t\"node_name\":    string(\"HOST01.local\"),\n\t\t\t\"source\":       string(\"HOST01.local\"),\n\t\t\t\"node_version\": string(\"7.4.2\"),\n\t\t\t\"pipeline\":     string(\"infra\"),\n\t\t\t\"queue_type\":   string(\"persisted\"),\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "plugins/inputs/logstash/sample.conf",
    "content": "# Read metrics exposed by Logstash\n[[inputs.logstash]]\n  ## The URL of the exposed Logstash API endpoint.\n  url = \"http://127.0.0.1:9600\"\n\n  ## Use Logstash 5 single pipeline API, set to true when monitoring\n  ## Logstash 5.\n  # single_pipeline = false\n\n  ## Enable optional collection components.  Can contain\n  ## \"pipelines\", \"process\", and \"jvm\".\n  # collect = [\"pipelines\", \"process\", \"jvm\"]\n\n  ## Timeout for HTTP requests.\n  # timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials.\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config.\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n\n  ## Use TLS but skip chain & host verification.\n  # insecure_skip_verify = false\n\n  ## If 'use_system_proxy' is set to true, Telegraf will check env vars such as\n  ## HTTP_PROXY, HTTPS_PROXY, and NO_PROXY (or their lowercase counterparts).\n  ## If 'use_system_proxy' is set to false (default) and 'http_proxy_url' is\n  ## provided, Telegraf will use the specified URL as HTTP proxy.\n  # use_system_proxy = false\n  # http_proxy_url = \"http://localhost:8888\"\n\n  ## Optional HTTP headers.\n  # [inputs.logstash.headers]\n  #   \"X-Special-Header\" = \"Special-Value\"\n"
  },
  {
    "path": "plugins/inputs/logstash/samples_logstash5.go",
    "content": "package logstash\n\nconst logstash5ProcessJSON = `\n{\n  \"host\" : \"node-5\",\n  \"version\" : \"5.3.0\",\n  \"http_address\" : \"0.0.0.0:9600\",\n  \"id\" : \"a360d8cf-6289-429d-8419-6145e324b574\",\n  \"name\" : \"node-5-test\",\n  \"process\" : {\n    \"open_file_descriptors\" : 89,\n    \"peak_open_file_descriptors\" : 100,\n    \"max_file_descriptors\" : 1048576,\n    \"mem\" : {\n      \"total_virtual_in_bytes\" : 4809506816\n    },\n    \"cpu\" : {\n      \"total_in_millis\" : 155260000000,\n      \"percent\" : 3,\n      \"load_average\" : {\n        \"1m\" : 0.49,\n        \"5m\" : 0.61,\n        \"15m\" : 0.54\n      }\n    }\n  }\n}\n`\n\nconst logstash5JvmJSON = `\n{\n  \"host\" : \"node-5\",\n  \"version\" : \"5.3.0\",\n  \"http_address\" : \"0.0.0.0:9600\",\n  \"id\" : \"a360d8cf-6289-429d-8419-6145e324b574\",\n  \"name\" : \"node-5-test\",\n  \"jvm\" : {\n    \"threads\" : {\n      \"count\" : 29,\n      \"peak_count\" : 31\n    },\n    \"mem\" : {\n      \"heap_used_in_bytes\" : 341270784,\n      \"heap_used_percent\" : 16,\n      \"heap_committed_in_bytes\" : 519045120,\n      \"heap_max_in_bytes\" : 2077753344,\n      \"non_heap_used_in_bytes\" : 268905936,\n      \"non_heap_committed_in_bytes\" : 291487744,\n      \"pools\" : {\n        \"survivor\" : {\n          \"peak_used_in_bytes\" : 8912896,\n          \"used_in_bytes\" : 9419672,\n          \"peak_max_in_bytes\" : 34865152,\n          \"max_in_bytes\" : 69730304,\n          \"committed_in_bytes\" : 17825792\n        },\n        \"old\" : {\n          \"peak_used_in_bytes\" : 127900864,\n          \"used_in_bytes\" : 255801728,\n          \"peak_max_in_bytes\" : 724828160,\n          \"max_in_bytes\" : 1449656320,\n          \"committed_in_bytes\" : 357957632\n        },\n        \"young\" : {\n          \"peak_used_in_bytes\" : 71630848,\n          \"used_in_bytes\" : 76049384,\n          \"peak_max_in_bytes\" : 279183360,\n          \"max_in_bytes\" : 558366720,\n          \"committed_in_bytes\" : 143261696\n        }\n      }\n    },\n    \"gc\" : {\n      \"collectors\" : {\n        \"old\" : {\n          \"collection_time_in_millis\" : 114,\n          \"collection_count\" : 2\n        },\n        \"young\" : {\n          \"collection_time_in_millis\" : 3235,\n          \"collection_count\" : 616\n        }\n      }\n    },\n    \"uptime_in_millis\" : 4803461\n  }\n}\n`\n\nconst logstash5PipelineJSON = `\n{\n  \"host\" : \"node-5\",\n  \"version\" : \"5.3.0\",\n  \"http_address\" : \"0.0.0.0:9600\",\n  \"id\" : \"a360d8cf-6289-429d-8419-6145e324b574\",\n  \"name\" : \"node-5-test\",\n  \"pipeline\" : {\n    \"events\" : {\n      \"duration_in_millis\" : 1151,\n      \"in\" : 1269,\n      \"filtered\" : 1269,\n      \"out\" : 1269\n    },\n    \"plugins\" : {\n      \"inputs\" : [ {\n        \"id\" : \"a35197a509596954e905e38521bae12b1498b17d-1\",\n        \"events\" : {\n          \"out\" : 2,\n          \"queue_push_duration_in_millis\" : 32\n        },\n        \"name\" : \"beats\"\n      } ],\n      \"filters\" : [ ],\n      \"outputs\" : [ {\n        \"id\" : \"582d5c2becb582a053e1e9a6bcc11d49b69a6dfd-3\",\n        \"events\" : {\n          \"duration_in_millis\" : 228,\n          \"in\" : 1269,\n          \"out\" : 1269\n        },\n        \"name\" : \"s3\"\n      }, {\n        \"id\" : \"582d5c2becb582a053e1e9a6bcc11d49b69a6dfd-2\",\n        \"events\" : {\n          \"duration_in_millis\" : 360,\n          \"in\" : 1269,\n          \"out\" : 1269\n        },\n        \"name\" : \"stdout\"\n      } ]\n    },\n    \"reloads\" : {\n      \"last_error\" : null,\n      \"successes\" : 0,\n      \"last_success_timestamp\" : null,\n      \"last_failure_timestamp\" : null,\n      \"failures\" : 0\n    },\n    \"queue\" : {\n      \"events\" : 208,\n      \"type\" : \"persisted\",\n      \"capacity\" : {\n        \"page_capacity_in_bytes\" : 262144000,\n        \"max_queue_size_in_bytes\" : 8589934592,\n        \"max_unread_events\" : 0\n      },\n      \"data\" : {\n        \"path\" : \"/path/to/data/queue\",\n        \"free_space_in_bytes\" : 89280552960,\n        \"storage_type\" : \"hfs\"\n      }\n    },\n    \"id\" : \"main\"\n  }\n}\n`\n"
  },
  {
    "path": "plugins/inputs/logstash/samples_logstash6.go",
    "content": "package logstash\n\nconst logstash6ProcessJSON = `\n{\n  \"host\" : \"node-6\",\n  \"version\" : \"6.4.2\",\n  \"http_address\" : \"127.0.0.1:9600\",\n  \"id\" : \"3044f675-21ce-4335-898a-8408aa678245\",\n  \"name\" : \"node-6-test\",\n  \"process\" : {\n    \"open_file_descriptors\" : 133,\n    \"peak_open_file_descriptors\" : 145,\n    \"max_file_descriptors\" : 262144,\n    \"mem\" : {\n      \"total_virtual_in_bytes\" : 17923452928\n    },\n    \"cpu\" : {\n      \"total_in_millis\" : 5841460,\n      \"percent\" : 0,\n      \"load_average\" : {\n        \"1m\" : 48.2,\n        \"5m\" : 42.4,\n        \"15m\" : 38.95\n      }\n    }\n  }\n}\n`\nconst logstash6JvmJSON = `\n{\n  \"host\" : \"node-6\",\n  \"version\" : \"6.4.2\",\n  \"http_address\" : \"127.0.0.1:9600\",\n  \"id\" : \"3044f675-21ce-4335-898a-8408aa678245\",\n  \"name\" : \"node-6-test\",\n  \"jvm\" : {\n    \"threads\" : {\n      \"count\" : 60,\n      \"peak_count\" : 62\n    },\n    \"mem\" : {\n      \"heap_used_percent\" : 2,\n      \"heap_committed_in_bytes\" : 824963072,\n      \"heap_max_in_bytes\" : 8389328896,\n      \"heap_used_in_bytes\" : 202360704,\n      \"non_heap_used_in_bytes\" : 197878896,\n      \"non_heap_committed_in_bytes\" : 222986240,\n      \"pools\" : {\n        \"survivor\" : {\n          \"peak_used_in_bytes\" : 8912896,\n          \"used_in_bytes\" : 835008,\n          \"peak_max_in_bytes\" : 200605696,\n          \"max_in_bytes\" : 200605696,\n          \"committed_in_bytes\" : 8912896\n        },\n        \"old\" : {\n          \"peak_used_in_bytes\" : 696572600,\n          \"used_in_bytes\" : 189750576,\n          \"peak_max_in_bytes\" : 6583418880,\n          \"max_in_bytes\" : 6583418880,\n          \"committed_in_bytes\" : 744419328\n        },\n        \"young\" : {\n          \"peak_used_in_bytes\" : 71630848,\n          \"used_in_bytes\" : 11775120,\n          \"peak_max_in_bytes\" : 1605304320,\n          \"max_in_bytes\" : 1605304320,\n          \"committed_in_bytes\" : 71630848\n        }\n      }\n    },\n    \"gc\" : {\n      \"collectors\" : {\n        \"old\" : {\n          \"collection_time_in_millis\" : 7492,\n          \"collection_count\" : 37\n        },\n        \"young\" : {\n          \"collection_time_in_millis\" : 107321,\n          \"collection_count\" : 2094\n        }\n      }\n    },\n    \"uptime_in_millis\" : 281850926\n  }\n}\n`\n\nconst logstash6PipelinesJSON = `\n{\n  \"host\" : \"node-6\",\n  \"version\" : \"6.4.2\",\n  \"http_address\" : \"127.0.0.1:9600\",\n  \"id\" : \"3044f675-21ce-4335-898a-8408aa678245\",\n  \"name\" : \"node-6-test\",\n  \"pipelines\" : {\n    \"main\" : {\n      \"events\" : {\n        \"duration_in_millis\" : 8540751,\n        \"in\" : 180659,\n        \"out\" : 180659,\n        \"filtered\" : 180659,\n        \"queue_push_duration_in_millis\" : 366\n      },\n      \"plugins\" : {\n        \"inputs\" : [\n          {\n            \"id\" : \"input-kafka\",\n            \"events\" : {\n              \"out\" : 180659,\n              \"queue_push_duration_in_millis\" : 366\n            },\n            \"name\" : \"kafka\"\n          }\n        ],\n        \"filters\" : [\n          {\n            \"id\" : \"155b0ad18abbf3df1e0cb7bddef0d77c5ba699efe5a0f8a28502d140549baf54\",\n            \"events\" : {\n              \"duration_in_millis\" : 2117,\n              \"in\" : 27641,\n              \"out\" : 27641\n            },\n            \"name\" : \"mutate\"\n          },\n          {\n            \"id\" : \"d079424bb6b7b8c7c61d9c5e0ddae445e92fa9ffa2e8690b0a669f7c690542f0\",\n            \"events\" : {\n              \"duration_in_millis\" : 13149,\n              \"in\" : 180659,\n              \"out\" : 177549\n            },\n            \"matches\" : 177546,\n            \"failures\" : 2,\n            \"name\" : \"date\"\n          },\n          {\n            \"id\" : \"25afa60ab6dc30512fe80efa3493e4928b5b1b109765b7dc46a3e4bbf293d2d4\",\n            \"events\" : {\n              \"duration_in_millis\" : 2814,\n              \"in\" : 76602,\n              \"out\" : 76602\n            },\n            \"name\" : \"mutate\"\n          },\n          {\n            \"id\" : \"2d9fa8f74eeb137bfa703b8050bad7d76636fface729e4585b789b5fc9bed668\",\n            \"events\" : {\n              \"duration_in_millis\" : 9,\n              \"in\" : 934,\n              \"out\" : 934\n            },\n            \"name\" : \"mutate\"\n          },\n          {\n            \"id\" : \"4ed14c9ef0198afe16c31200041e98d321cb5c2e6027e30b077636b8c4842110\",\n            \"events\" : {\n              \"duration_in_millis\" : 173,\n              \"in\" : 3110,\n              \"out\" : 0\n            },\n            \"name\" : \"drop\"\n          },\n          {\n            \"id\" : \"358ce1eb387de7cd5711c2fb4de64cd3b12e5ca9a4c45f529516bcb053a31df4\",\n            \"events\" : {\n              \"duration_in_millis\" : 5605,\n              \"in\" : 75482,\n              \"out\" : 75482\n            },\n            \"name\" : \"mutate\"\n          },\n          {\n            \"id\" : \"82a9bbb02fff37a63c257c1f146b0a36273c7cbbebe83c0a51f086e5280bf7bb\",\n            \"events\" : {\n              \"duration_in_millis\" : 313992,\n              \"in\" : 180659,\n              \"out\" : 180659\n            },\n            \"name\" : \"csv\"\n          },\n          {\n            \"id\" : \"8fb13a8cdd4257b52724d326aa1549603ffdd4e4fde6d20720c96b16238c18c3\",\n            \"events\" : {\n              \"duration_in_millis\" : 0,\n              \"in\" : 0,\n              \"out\" : 0\n            },\n            \"name\" : \"mutate\"\n          }\n        ],\n        \"outputs\" : [\n          {\n            \"id\" : \"output-elk\",\n            \"documents\" : {\n              \"successes\" : 221\n            },\n            \"events\" : {\n              \"duration_in_millis\" : 651386,\n              \"in\" : 177549,\n              \"out\" : 177549\n            },\n            \"bulk_requests\" : {\n              \"successes\" : 1,\n              \"responses\" : {\n                \"200\" : 748\n              }\n            },\n            \"name\" : \"elasticsearch\"\n          },\n          {\n            \"id\" : \"output-kafka1\",\n            \"events\" : {\n              \"duration_in_millis\" : 186751,\n              \"in\" : 177549,\n              \"out\" : 177549\n            },\n            \"name\" : \"kafka\"\n          },\n          {\n            \"id\" : \"output-kafka2\",\n            \"events\" : {\n              \"duration_in_millis\" : 7335196,\n              \"in\" : 177549,\n              \"out\" : 177549\n            },\n            \"name\" : \"kafka\"\n          }\n        ]\n      },\n      \"reloads\" : {\n        \"last_error\" : null,\n        \"successes\" : 0,\n        \"last_success_timestamp\" : null,\n        \"last_failure_timestamp\" : null,\n        \"failures\" : 0\n      },\n      \"queue\": {\n        \"events\": 103,\n        \"type\": \"persisted\",\n        \"capacity\": {\n          \"queue_size_in_bytes\": 1872391,\n          \"page_capacity_in_bytes\": 67108864,\n          \"max_queue_size_in_bytes\": 1073741824,\n          \"max_unread_events\": 0\n        },\n        \"data\": {\n          \"path\": \"/var/lib/logstash/queue/main\",\n          \"free_space_in_bytes\": 36307369984,\n          \"storage_type\": \"ext4\"\n        }\n      }\n    }\n  }\n}\n`\n"
  },
  {
    "path": "plugins/inputs/logstash/samples_logstash7.go",
    "content": "package logstash\n\nconst logstash7PipelinesJSON = `\n{\n  \"host\" : \"HOST01.local\",\n  \"version\" : \"7.4.2\",\n  \"http_address\" : \"127.0.0.1:9600\",\n  \"id\" : \"28580380-ad2c-4032-934b-76359125edca\",\n  \"name\" : \"HOST01.local\",\n  \"ephemeral_id\" : \"bd95ff6b-3fa8-42ae-be32-098a4e4ea1ec\",\n  \"status\" : \"green\",\n  \"snapshot\" : true,\n  \"pipeline\" : {\n    \"workers\" : 8,\n    \"batch_size\" : 125,\n    \"batch_delay\" : 50\n  },\n  \"pipelines\" : {\n    \"infra\" : {\n      \"events\" : {\n        \"in\" : 2665549,\n        \"out\" : 2665549,\n        \"duration_in_millis\" : 3032875,\n        \"filtered\" : 2665549,\n        \"queue_push_duration_in_millis\" : 13300\n      },\n      \"plugins\" : {\n        \"inputs\" : [ {\n          \"id\" : \"8526dc80bc2257ab08f96018f96b0c68dd03abc5695bb22fb9e96339a8dfb4f86\",\n          \"events\" : {\n            \"out\" : 2665549,\n            \"queue_push_duration_in_millis\" : 13300\n          },\n          \"peak_connections\" : 1,\n          \"name\" : \"beats\",\n          \"current_connections\" : 1\n        } ],\n        \"codecs\" : [ {\n          \"id\" : \"plain_7312c097-1e7f-41db-983b-4f5a87a9eba2\",\n          \"encode\" : {\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          },\n          \"name\" : \"plain\",\n          \"decode\" : {\n            \"out\" : 0,\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          }\n        }, {\n          \"id\" : \"rubydebug_e958e3dc-10f6-4dd6-b7c5-ae3de2892afb\",\n          \"encode\" : {\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          },\n          \"name\" : \"rubydebug\",\n          \"decode\" : {\n            \"out\" : 0,\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          }\n        }, {\n          \"id\" : \"plain_addb97be-fb77-4cbc-b45c-0424cd5d0ac7\",\n          \"encode\" : {\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          },\n          \"name\" : \"plain\",\n          \"decode\" : {\n            \"out\" : 0,\n            \"duration_in_millis\" : 0,\n            \"writes_in\" : 0\n          }\n        } ],\n        \"filters\" : [ {\n          \"id\" : \"9e8297a6ee7b61864f77853317dccde83d29952ef869010c385dcfc9064ab8b8\",\n          \"events\" : {\n            \"in\" : 2665549,\n            \"out\" : 2665549,\n            \"duration_in_millis\" : 8648\n          },\n          \"name\" : \"date\",\n          \"matches\" : 2665549\n        }, {\n          \"id\" : \"bec0c77b3f53a78c7878449c72ec59f97be31c1f12f9621f61ed2d4563bad869\",\n          \"events\" : {\n            \"in\" : 2665549,\n            \"out\" : 2665549,\n            \"duration_in_millis\" : 195138\n          },\n          \"name\" : \"fingerprint\"\n        } ],\n        \"outputs\" : [ {\n          \"id\" : \"df59066a933f038354c1845ba44de692f70dbd0d2009ab07a12b98b776be7e3f\",\n          \"events\" : {\n            \"in\" : 0,\n            \"out\" : 0,\n            \"duration_in_millis\" : 25\n          },\n          \"name\" : \"stdout\"\n        }, {\n          \"id\" : \"38967f09bbd2647a95aa00702b6b557bdbbab31da6a04f991d38abe5629779e3\",\n          \"events\" : {\n            \"in\" : 2665549,\n            \"out\" : 2665549,\n            \"duration_in_millis\" : 2802177\n          },\n          \"name\" : \"elasticsearch\",\n          \"bulk_requests\" : {\n            \"successes\" : 2870,\n            \"responses\" : {\n              \"200\" : 2870\n            },\n            \"failures\": 262,\n            \"with_errors\": 9089\n          },\n          \"documents\" : {\n            \"successes\" : 2665549,\n            \"retryable_failures\": 13733\n          }\n        } ]\n      },\n      \"reloads\" : {\n        \"successes\" : 4,\n        \"last_error\" : null,\n        \"failures\" : 0,\n        \"last_success_timestamp\" : \"2020-06-05T08:06:12.538Z\",\n        \"last_failure_timestamp\" : null\n      },\n      \"queue\" : {\n        \"type\" : \"persisted\",\n        \"events_count\" : 0,\n        \"queue_size_in_bytes\" : 32028566,\n        \"max_queue_size_in_bytes\" : 4294967296\n      },\n      \"hash\" : \"5bc589ae4b02cb3e436626429b50928b9d99360639c84dc7fc69268ac01a9fd0\",\n      \"ephemeral_id\" : \"4bcacefa-6cbf-461e-b14e-184edd9ebdf3\"\n    }\n  }\n}`\n"
  },
  {
    "path": "plugins/inputs/lustre2/README.md",
    "content": "# Lustre Input Plugin\n\nThis plugin gathers metrics for the [Lustre® file system][lustre] using its\nentries in the `proc` filesystem. Reference the\n[Lustre Monitoring and Statistics Guide][guide] for the reported information.\n\n> [!NOTE] This plugin doesn't report _all_ information available but only a\n> limited set of items. Check the [metrics section](#metrics).\n\n⭐ Telegraf v0.1.5\n🏷️ system\n💻 linux\n\n[lustre]: http://lustre.org/\n[guide]: http://wiki.lustre.org/Lustre_Monitoring_and_Statistics_Guide\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from local Lustre service on OST, MDS\n# This plugin ONLY supports Linux\n[[inputs.lustre2]]\n  ## An array of /proc globs to search for Lustre stats\n  ## If not specified, the default will work on Lustre 2.12.x\n  ##\n  # mgs_procfiles = [\n  #   \"/sys/fs/lustre/mgs/*/eviction_count\",\n  # ]\n  # ost_procfiles = [\n  #   \"/proc/fs/lustre/obdfilter/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/stats\",\n  #   \"/proc/fs/lustre/obdfilter/*/job_stats\",\n  #   \"/proc/fs/lustre/obdfilter/*/exports/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n  #   \"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n  #   \"/sys/fs/lustre/odbfilter/*/eviction_count\",\n  # ]\n  # mds_procfiles = [\n  #   \"/proc/fs/lustre/mdt/*/md_stats\",\n  #   \"/proc/fs/lustre/mdt/*/job_stats\",\n  #   \"/proc/fs/lustre/mdt/*/exports/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n  #   \"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n  #   \"/sys/fs/lustre/mdt/*/eviction_count\",\n  # ]\n```\n\n## Metrics\n\nFrom `/sys/fs/lustre/health_check`:\n\n- lustre2\n  - tags:\n  - fields:\n    - health\n\nFrom `/proc/fs/lustre/obdfilter/*/stats` and\n`/proc/fs/lustre/osd-ldiskfs/*/stats`:\n\n- lustre2\n  - tags:\n    - name\n  - fields:\n    - write_bytes\n    - write_calls\n    - read_bytes\n    - read_calls\n    - cache_hit\n    - cache_miss\n    - cache_access\n\nFrom `/proc/fs/lustre/obdfilter/*/exports/*/stats`:\n\n- lustre2\n  - tags:\n    - name\n    - client\n  - fields:\n    - write_bytes\n    - write_calls\n    - read_bytes\n    - read_calls\n\nFrom `/proc/fs/lustre/obdfilter/*/job_stats`:\n\n- lustre2\n  - tags:\n    - name\n    - jobid\n  - fields:\n    - jobstats_ost_getattr\n    - jobstats_ost_setattr\n    - jobstats_ost_sync\n    - jobstats_punch\n    - jobstats_destroy\n    - jobstats_create\n    - jobstats_ost_statfs\n    - jobstats_get_info\n    - jobstats_set_info\n    - jobstats_quotactl\n    - jobstats_read_bytes\n    - jobstats_read_calls\n    - jobstats_read_max_size\n    - jobstats_read_min_size\n    - jobstats_write_bytes\n    - jobstats_write_calls\n    - jobstats_write_max_size\n    - jobstats_write_min_size\n\nFrom `/proc/fs/lustre/mdt/*/md_stats`:\n\n- lustre2\n  - tags:\n    - name\n  - fields:\n    - open\n    - close\n    - mknod\n    - link\n    - unlink\n    - mkdir\n    - rmdir\n    - rename\n    - getattr\n    - setattr\n    - getxattr\n    - setxattr\n    - statfs\n    - sync\n    - samedir_rename\n    - crossdir_rename\n\nFrom `/proc/fs/lustre/mdt/*/exports/*/stats`:\n\n- lustre2\n  - tags:\n    - name\n    - client\n  - fields:\n    - open\n    - close\n    - mknod\n    - link\n    - unlink\n    - mkdir\n    - rmdir\n    - rename\n    - getattr\n    - setattr\n    - getxattr\n    - setxattr\n    - statfs\n    - sync\n    - samedir_rename\n    - crossdir_rename\n\nFrom `/proc/fs/lustre/mdt/*/job_stats`:\n\n- lustre2\n  - tags:\n    - name\n    - jobid\n  - fields:\n    - jobstats_close\n    - jobstats_crossdir_rename\n    - jobstats_getattr\n    - jobstats_getxattr\n    - jobstats_link\n    - jobstats_mkdir\n    - jobstats_mknod\n    - jobstats_open\n    - jobstats_rename\n    - jobstats_rmdir\n    - jobstats_samedir_rename\n    - jobstats_setattr\n    - jobstats_setxattr\n    - jobstats_statfs\n    - jobstats_sync\n    - jobstats_unlink\n\nFrom `/proc/fs/lustre/*/*/eviction_count`:\n\n- lustre2\n  - tags:\n    - name\n  - fields:\n    - evictions\n\n## Example Output\n\n```text\nlustre2,host=oss2,jobid=42990218,name=wrk-OST0041 jobstats_ost_setattr=0i,jobstats_ost_sync=0i,jobstats_punch=0i,jobstats_read_bytes=4096i,jobstats_read_calls=1i,jobstats_read_max_size=4096i,jobstats_read_min_size=4096i,jobstats_write_bytes=310206488i,jobstats_write_calls=7423i,jobstats_write_max_size=53048i,jobstats_write_min_size=8820i 1556525847000000000\nlustre2,host=mds1,jobid=42992017,name=wrk-MDT0000 jobstats_close=31798i,jobstats_crossdir_rename=0i,jobstats_getattr=34146i,jobstats_getxattr=15i,jobstats_link=0i,jobstats_mkdir=658i,jobstats_mknod=0i,jobstats_open=31797i,jobstats_rename=0i,jobstats_rmdir=0i,jobstats_samedir_rename=0i,jobstats_setattr=1788i,jobstats_setxattr=0i,jobstats_statfs=0i,jobstats_sync=0i,jobstats_unlink=0i 1556525828000000000\n```\n"
  },
  {
    "path": "plugins/inputs/lustre2/lustre2.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\n// Package lustre2 (doesn't aim for Windows)\n// Lustre 2.x Telegraf plugin\n// Lustre (http://lustre.org/) is an open-source, parallel file system\n// for HPC environments. It stores statistics about its activity in /proc\npackage lustre2\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Lustre2 struct {\n\t// Lustre proc files can change between versions, so we want to future-proof by letting people choose what to look at.\n\tMgsProcfiles []string        `toml:\"mgs_procfiles\"`\n\tOstProcfiles []string        `toml:\"ost_procfiles\"`\n\tMdsProcfiles []string        `toml:\"mds_procfiles\"`\n\tLog          telegraf.Logger `toml:\"-\"`\n\n\t// used by the testsuite to generate mock sysfs and procfs files\n\trootdir string\n\n\t// allFields maps an OST name to the metric fields associated with that OST\n\tallFields map[tags]map[string]interface{}\n}\n\ntype tags struct {\n\tname, brwSection, bucket, job, client string\n}\n\nfunc (*Lustre2) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (l *Lustre2) Gather(acc telegraf.Accumulator) error {\n\tl.allFields = make(map[tags]map[string]interface{})\n\n\terr := l.getLustreHealth()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(l.MgsProcfiles) == 0 {\n\t\tl.MgsProcfiles = []string{\n\t\t\t// eviction count\n\t\t\t\"/sys/fs/lustre/mgs/*/eviction_count\",\n\t\t}\n\t}\n\n\tif len(l.OstProcfiles) == 0 {\n\t\tl.OstProcfiles = []string{\n\t\t\t// read/write bytes are in obdfilter/<ost_name>/stats\n\t\t\t\"/proc/fs/lustre/obdfilter/*/stats\",\n\t\t\t// cache counters are in osd-ldiskfs/<ost_name>/stats\n\t\t\t\"/proc/fs/lustre/osd-ldiskfs/*/stats\",\n\t\t\t// per job statistics are in obdfilter/<ost_name>/job_stats\n\t\t\t\"/proc/fs/lustre/obdfilter/*/job_stats\",\n\t\t\t// bulk read/write statistics for ldiskfs\n\t\t\t\"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n\t\t\t// bulk read/write statistics for zfs\n\t\t\t\"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n\t\t\t// eviction count\n\t\t\t\"/sys/fs/lustre/obdfilter/*/eviction_count\",\n\t\t}\n\t}\n\n\tif len(l.MdsProcfiles) == 0 {\n\t\tl.MdsProcfiles = []string{\n\t\t\t// Metadata server stats\n\t\t\t\"/proc/fs/lustre/mdt/*/md_stats\",\n\t\t\t// Metadata target job stats\n\t\t\t\"/proc/fs/lustre/mdt/*/job_stats\",\n\t\t\t// eviction count\n\t\t\t\"/sys/fs/lustre/mdt/*/eviction_count\",\n\t\t}\n\t}\n\n\tfor _, procfile := range l.MgsProcfiles {\n\t\tif !strings.HasSuffix(procfile, \"eviction_count\") {\n\t\t\treturn fmt.Errorf(\"no handler found for mgs procfile pattern \\\"%s\\\"\", procfile)\n\t\t}\n\t\terr := l.getLustreEvictionCount(procfile)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, procfile := range l.OstProcfiles {\n\t\tif strings.HasSuffix(procfile, \"brw_stats\") {\n\t\t\terr := l.getLustreProcBrwStats(procfile, wantedBrwstatsFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if strings.HasSuffix(procfile, \"job_stats\") {\n\t\t\terr := l.getLustreProcStats(procfile, wantedOstJobstatsFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if strings.HasSuffix(procfile, \"eviction_count\") {\n\t\t\terr := l.getLustreEvictionCount(procfile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\terr := l.getLustreProcStats(procfile, wantedOstFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor _, procfile := range l.MdsProcfiles {\n\t\tif strings.HasSuffix(procfile, \"brw_stats\") {\n\t\t\terr := l.getLustreProcBrwStats(procfile, wantedBrwstatsFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if strings.HasSuffix(procfile, \"job_stats\") {\n\t\t\terr := l.getLustreProcStats(procfile, wantedMdtJobstatsFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if strings.HasSuffix(procfile, \"eviction_count\") {\n\t\t\terr := l.getLustreEvictionCount(procfile)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\terr := l.getLustreProcStats(procfile, wantedMdsFields)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tfor tgs, fields := range l.allFields {\n\t\ttags := make(map[string]string, 5)\n\t\tif len(tgs.name) > 0 {\n\t\t\ttags[\"name\"] = tgs.name\n\t\t}\n\t\tif len(tgs.brwSection) > 0 {\n\t\t\ttags[\"brw_section\"] = tgs.brwSection\n\t\t}\n\t\tif len(tgs.bucket) > 0 {\n\t\t\ttags[\"bucket\"] = tgs.bucket\n\t\t}\n\t\tif len(tgs.job) > 0 {\n\t\t\ttags[\"jobid\"] = tgs.job\n\t\t}\n\t\tif len(tgs.client) > 0 {\n\t\t\ttags[\"client\"] = tgs.client\n\t\t}\n\t\tacc.AddFields(\"lustre2\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (l *Lustre2) getLustreHealth() error {\n\t// the linter complains about using an element containing '/' in filepath.Join()\n\t// so we explicitly set the rootdir default to '/' in this function rather than\n\t// starting the second element with a '/'.\n\trootdir := l.rootdir\n\tif rootdir == \"\" {\n\t\trootdir = \"/\"\n\t}\n\n\tfilename := filepath.Join(rootdir, \"sys\", \"fs\", \"lustre\", \"health_check\")\n\tif _, err := os.Stat(filename); err != nil {\n\t\t// try falling back to the old procfs location\n\t\t// it was moved in https://github.com/lustre/lustre-release/commit/5d368bd0b2\n\t\tfilename = filepath.Join(rootdir, \"proc\", \"fs\", \"lustre\", \"health_check\")\n\t\tif _, err = os.Stat(filename); err != nil {\n\t\t\treturn nil //nolint:nilerr // we don't want to return an error if the file doesn't exist\n\t\t}\n\t}\n\tcontents, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalue := strings.TrimSpace(string(contents))\n\tvar health uint64\n\tif value == \"healthy\" {\n\t\thealth = 1\n\t}\n\n\tt := tags{}\n\tvar fields map[string]interface{}\n\tfields, ok := l.allFields[t]\n\tif !ok {\n\t\tfields = make(map[string]interface{})\n\t\tl.allFields[t] = fields\n\t}\n\n\tfields[\"health\"] = health\n\treturn nil\n}\n\nfunc (l *Lustre2) getLustreProcStats(fileglob string, wantedFields []*mapping) error {\n\tfiles, err := filepath.Glob(filepath.Join(l.rootdir, fileglob))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfieldSplitter := regexp.MustCompile(`[ :]+`)\n\n\tfor _, file := range files {\n\t\t/* From /proc/fs/lustre/obdfilter/<ost_name>/stats and similar\n\t\t * extract the object store target name,\n\t\t * and for per-client files under\n\t\t * /proc/fs/lustre/obdfilter/<ost_name>/exports/<client_nid>/stats\n\t\t * and similar the client NID\n\t\t * Assumption: the target name is fourth to last\n\t\t * for per-client files and second to last otherwise\n\t\t * and the client NID is always second to last,\n\t\t * which is true in Lustre 2.1->2.14\n\t\t */\n\t\tpath := strings.Split(file, \"/\")\n\t\tvar name, client string\n\t\tif strings.Contains(file, \"/exports/\") {\n\t\t\tname = path[len(path)-4]\n\t\t\tclient = path[len(path)-2]\n\t\t} else {\n\t\t\tname = path[len(path)-2]\n\t\t\tclient = \"\"\n\t\t}\n\n\t\twholeFile, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(wholeFile) == 0 {\n\t\t\tl.Log.Debugf(\"Skipping empty file %s\", file)\n\t\t\tcontinue\n\t\t}\n\n\t\tjobs := strings.Split(string(wholeFile), \"- \")\n\t\tfor _, job := range jobs {\n\t\t\tlines := strings.Split(job, \"\\n\")\n\t\t\tjobid := \"\"\n\n\t\t\t// figure out if the data should be tagged with job_id here\n\t\t\tparts := strings.Fields(lines[0])\n\t\t\tif strings.TrimSuffix(parts[0], \":\") == \"job_id\" {\n\t\t\t\tjobid = parts[1]\n\t\t\t}\n\n\t\t\tfor _, line := range lines {\n\t\t\t\t// skip any empty lines\n\t\t\t\tif len(line) < 1 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tparts := fieldSplitter.Split(line, -1)\n\t\t\t\tif len(parts[0]) == 0 {\n\t\t\t\t\tparts = parts[1:]\n\t\t\t\t}\n\n\t\t\t\tvar fields map[string]interface{}\n\t\t\t\tfields, ok := l.allFields[tags{name, \"\", \"\", jobid, client}]\n\t\t\t\tif !ok {\n\t\t\t\t\tfields = make(map[string]interface{})\n\t\t\t\t\tl.allFields[tags{name, \"\", \"\", jobid, client}] = fields\n\t\t\t\t}\n\n\t\t\t\tfor _, wanted := range wantedFields {\n\t\t\t\t\tvar data uint64\n\t\t\t\t\tif parts[0] == wanted.inProc {\n\t\t\t\t\t\twantedField := wanted.field\n\t\t\t\t\t\t// if not set, assume field[1]. Shouldn't be field[0], as\n\t\t\t\t\t\t// that's a string\n\t\t\t\t\t\tif wantedField == 0 {\n\t\t\t\t\t\t\twantedField = 1\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata, err = strconv.ParseUint(strings.TrimSuffix(parts[wantedField], \",\"), 10, 64)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\treportName := wanted.inProc\n\t\t\t\t\t\tif wanted.reportAs != \"\" {\n\t\t\t\t\t\t\treportName = wanted.reportAs\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfields[reportName] = data\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (l *Lustre2) getLustreProcBrwStats(fileglob string, wantedFields []*mapping) error {\n\tfiles, err := filepath.Glob(filepath.Join(l.rootdir, fileglob))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find files matching glob %s: %w\", fileglob, err)\n\t}\n\n\tfor _, file := range files {\n\t\t// Turn /proc/fs/lustre/obdfilter/<ost_name>/stats and similar into just the object store target name\n\t\t// This assumes that the target name is always second to last, which is true in Lustre 2.1->2.12\n\t\tpath := strings.Split(file, \"/\")\n\t\tif len(path) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tname := path[len(path)-2]\n\n\t\twholeFile, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, os.ErrPermission) {\n\t\t\t\tl.Log.Debugf(\"%s\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to read file %s: %w\", file, err)\n\t\t}\n\t\tlines := strings.Split(string(wholeFile), \"\\n\")\n\n\t\tvar headerName string\n\t\tfor _, line := range lines {\n\t\t\t// There are four types of lines in a brw_stats file:\n\t\t\t// 1. Header lines - contain the category of metric (e.g. disk I/Os in flight, disk I/O time)\n\t\t\t// 2. Bucket lines - follow headers, contain the bucket value (e.g. 4K, 1M) and metric values\n\t\t\t// 3. Empty lines - these will simply be filtered out\n\t\t\t// 4. snapshot_time line - this will be filtered out, as it \"looks\" like a bucket line\n\t\t\tif len(line) < 1 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tparts := strings.Fields(line)\n\n\t\t\t// This is a header line\n\t\t\t// Set report name for use by the buckets that follow\n\t\t\tif !strings.Contains(parts[0], \":\") {\n\t\t\t\tnameParts := strings.Split(line, \"  \")\n\t\t\t\theaderName = nameParts[0]\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// snapshot_time should be discarded\n\t\t\tif strings.Contains(parts[0], \"snapshot_time\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// This is a bucket for a given header\n\t\t\tfor _, wanted := range wantedFields {\n\t\t\t\tif headerName != wanted.inProc {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbucket := strings.TrimSuffix(parts[0], \":\")\n\n\t\t\t\t// brw_stats columns are static and don't need configurable fields\n\t\t\t\treadIos, err := strconv.ParseUint(parts[1], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse read_ios: %w\", err)\n\t\t\t\t}\n\t\t\t\treadPercent, err := strconv.ParseUint(parts[2], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse read_percent: %w\", err)\n\t\t\t\t}\n\t\t\t\twriteIos, err := strconv.ParseUint(parts[5], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse write_ios: %w\", err)\n\t\t\t\t}\n\t\t\t\twritePercent, err := strconv.ParseUint(parts[6], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse write_percent: %w\", err)\n\t\t\t\t}\n\t\t\t\treportName := headerName\n\t\t\t\tif wanted.reportAs != \"\" {\n\t\t\t\t\treportName = wanted.reportAs\n\t\t\t\t}\n\n\t\t\t\ttag := tags{name, reportName, bucket, \"\", \"\"}\n\t\t\t\tfields, ok := l.allFields[tag]\n\t\t\t\tif !ok {\n\t\t\t\t\tfields = make(map[string]interface{})\n\t\t\t\t\tl.allFields[tag] = fields\n\t\t\t\t}\n\n\t\t\t\tfields[\"read_ios\"] = readIos\n\t\t\t\tfields[\"read_percent\"] = readPercent\n\t\t\t\tfields[\"write_ios\"] = writeIos\n\t\t\t\tfields[\"write_percent\"] = writePercent\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (l *Lustre2) getLustreEvictionCount(fileglob string) error {\n\tfiles, err := filepath.Glob(filepath.Join(l.rootdir, fileglob))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find files matching glob %s: %w\", fileglob, err)\n\t}\n\n\tfor _, file := range files {\n\t\t// Turn /sys/fs/lustre/*/<mgt/mdt/ost_name>/eviction_count into just the object store target name\n\t\t// This assumes that the target name is always second to last, which is true in Lustre 2.1->2.12\n\t\tpath := strings.Split(file, \"/\")\n\t\tif len(path) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tname := path[len(path)-2]\n\n\t\tcontents, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read file %s: %w\", file, err)\n\t\t}\n\n\t\tvalue, err := strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse file %s: %w\", file, err)\n\t\t}\n\n\t\ttag := tags{name, \"\", \"\", \"\", \"\"}\n\t\tfields, ok := l.allFields[tag]\n\t\tif !ok {\n\t\t\tfields = make(map[string]interface{})\n\t\t\tl.allFields[tag] = fields\n\t\t}\n\n\t\tfields[\"evictions\"] = value\n\t}\n\treturn nil\n}\n\n// The wanted fields would be a []string, if not for the lines that start with read_bytes/write_bytes\n// and contain both the byte count and the function call count\ntype mapping struct {\n\tinProc   string // What to look for at the start of a line in /proc/fs/lustre/*\n\tfield    uint32 // which field to extract from that line\n\treportAs string // What measurement name to use\n}\n\nvar wantedBrwstatsFields = []*mapping{\n\t{\n\t\tinProc:   \"pages per bulk r/w\",\n\t\treportAs: \"pages_per_bulk_rw\",\n\t},\n\t{\n\t\tinProc:   \"discontiguous pages\",\n\t\treportAs: \"discontiguous_pages\",\n\t},\n\t{\n\t\tinProc:   \"disk I/Os in flight\",\n\t\treportAs: \"disk_ios_in_flight\",\n\t},\n\t{\n\t\tinProc:   \"I/O time (1/1000s)\",\n\t\treportAs: \"io_time\",\n\t},\n\t{\n\t\tinProc:   \"disk I/O size\",\n\t\treportAs: \"disk_io_size\",\n\t},\n}\n\nvar wantedOstFields = []*mapping{\n\t{\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    6,\n\t\treportAs: \"write_bytes\",\n\t},\n\t{ // line starts with 'write_bytes', but value write_calls is in second column\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    1,\n\t\treportAs: \"write_calls\",\n\t},\n\t{\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    6,\n\t\treportAs: \"read_bytes\",\n\t},\n\t{ // line starts with 'read_bytes', but value read_calls is in second column\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    1,\n\t\treportAs: \"read_calls\",\n\t},\n\t{\n\t\tinProc: \"cache_hit\",\n\t},\n\t{\n\t\tinProc: \"cache_miss\",\n\t},\n\t{\n\t\tinProc: \"cache_access\",\n\t},\n}\n\nvar wantedOstJobstatsFields = []*mapping{\n\t{ // The read line has several fields, so we need to differentiate what they are\n\t\tinProc:   \"read\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_read_calls\",\n\t},\n\t{\n\t\tinProc:   \"read\",\n\t\tfield:    7,\n\t\treportAs: \"jobstats_read_min_size\",\n\t},\n\t{\n\t\tinProc:   \"read\",\n\t\tfield:    9,\n\t\treportAs: \"jobstats_read_max_size\",\n\t},\n\t{\n\t\tinProc:   \"read\",\n\t\tfield:    11,\n\t\treportAs: \"jobstats_read_bytes\",\n\t},\n\t{ // Different inProc for newer versions\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_read_calls\",\n\t},\n\t{\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    7,\n\t\treportAs: \"jobstats_read_min_size\",\n\t},\n\t{\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    9,\n\t\treportAs: \"jobstats_read_max_size\",\n\t},\n\t{\n\t\tinProc:   \"read_bytes\",\n\t\tfield:    11,\n\t\treportAs: \"jobstats_read_bytes\",\n\t},\n\t{ // We need to do the same for the write fields\n\t\tinProc:   \"write\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_write_calls\",\n\t},\n\t{\n\t\tinProc:   \"write\",\n\t\tfield:    7,\n\t\treportAs: \"jobstats_write_min_size\",\n\t},\n\t{\n\t\tinProc:   \"write\",\n\t\tfield:    9,\n\t\treportAs: \"jobstats_write_max_size\",\n\t},\n\t{\n\t\tinProc:   \"write\",\n\t\tfield:    11,\n\t\treportAs: \"jobstats_write_bytes\",\n\t},\n\t{ // Different inProc for newer versions\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_write_calls\",\n\t},\n\t{\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    7,\n\t\treportAs: \"jobstats_write_min_size\",\n\t},\n\t{\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    9,\n\t\treportAs: \"jobstats_write_max_size\",\n\t},\n\t{\n\t\tinProc:   \"write_bytes\",\n\t\tfield:    11,\n\t\treportAs: \"jobstats_write_bytes\",\n\t},\n\t{\n\t\tinProc:   \"getattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_ost_getattr\",\n\t},\n\t{\n\t\tinProc:   \"setattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_ost_setattr\",\n\t},\n\t{\n\t\tinProc:   \"punch\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_punch\",\n\t},\n\t{\n\t\tinProc:   \"sync\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_ost_sync\",\n\t},\n\t{\n\t\tinProc:   \"destroy\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_destroy\",\n\t},\n\t{\n\t\tinProc:   \"create\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_create\",\n\t},\n\t{\n\t\tinProc:   \"statfs\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_ost_statfs\",\n\t},\n\t{\n\t\tinProc:   \"get_info\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_get_info\",\n\t},\n\t{\n\t\tinProc:   \"set_info\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_set_info\",\n\t},\n\t{\n\t\tinProc:   \"quotactl\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_quotactl\",\n\t},\n}\n\nvar wantedMdsFields = []*mapping{\n\t{\n\t\tinProc: \"open\",\n\t},\n\t{\n\t\tinProc: \"close\",\n\t},\n\t{\n\t\tinProc: \"mknod\",\n\t},\n\t{\n\t\tinProc: \"link\",\n\t},\n\t{\n\t\tinProc: \"unlink\",\n\t},\n\t{\n\t\tinProc: \"mkdir\",\n\t},\n\t{\n\t\tinProc: \"rmdir\",\n\t},\n\t{\n\t\tinProc: \"rename\",\n\t},\n\t{\n\t\tinProc: \"getattr\",\n\t},\n\t{\n\t\tinProc: \"setattr\",\n\t},\n\t{\n\t\tinProc: \"getxattr\",\n\t},\n\t{\n\t\tinProc: \"setxattr\",\n\t},\n\t{\n\t\tinProc: \"statfs\",\n\t},\n\t{\n\t\tinProc: \"sync\",\n\t},\n\t{\n\t\tinProc: \"samedir_rename\",\n\t},\n\t{\n\t\tinProc: \"crossdir_rename\",\n\t},\n}\n\nvar wantedMdtJobstatsFields = []*mapping{\n\t{\n\t\tinProc:   \"open\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_open\",\n\t},\n\t{\n\t\tinProc:   \"close\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_close\",\n\t},\n\t{\n\t\tinProc:   \"mknod\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_mknod\",\n\t},\n\t{\n\t\tinProc:   \"link\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_link\",\n\t},\n\t{\n\t\tinProc:   \"unlink\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_unlink\",\n\t},\n\t{\n\t\tinProc:   \"mkdir\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_mkdir\",\n\t},\n\t{\n\t\tinProc:   \"rmdir\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_rmdir\",\n\t},\n\t{\n\t\tinProc:   \"rename\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_rename\",\n\t},\n\t{\n\t\tinProc:   \"getattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_getattr\",\n\t},\n\t{\n\t\tinProc:   \"setattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_setattr\",\n\t},\n\t{\n\t\tinProc:   \"getxattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_getxattr\",\n\t},\n\t{\n\t\tinProc:   \"setxattr\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_setxattr\",\n\t},\n\t{\n\t\tinProc:   \"statfs\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_statfs\",\n\t},\n\t{\n\t\tinProc:   \"sync\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_sync\",\n\t},\n\t{\n\t\tinProc:   \"samedir_rename\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_samedir_rename\",\n\t},\n\t{\n\t\tinProc:   \"crossdir_rename\",\n\t\tfield:    3,\n\t\treportAs: \"jobstats_crossdir_rename\",\n\t},\n}\n\nfunc init() {\n\tinputs.Add(\"lustre2\", func() telegraf.Input {\n\t\treturn &Lustre2{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/lustre2/lustre2_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage lustre2\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Lustre2 struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Lustre2) SampleConfig() string { return sampleConfig }\n\nfunc (l *Lustre2) Init() error {\n\tl.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Lustre2) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"lustre2\", func() telegraf.Input {\n\t\treturn &Lustre2{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/lustre2/lustre2_test.go",
    "content": "//go:build linux\n\npackage lustre2\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"lustre2\", func() telegraf.Input {\n\t\treturn &Lustre2{}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Load the configuration\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup and start the plugin\n\t\t\tplugin := cfg.Inputs[0].Input.(*Lustre2)\n\t\t\tplugin.rootdir = testcasePath\n\n\t\t\t// Gather the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/lustre2/sample.conf",
    "content": "# Read metrics from local Lustre service on OST, MDS\n# This plugin ONLY supports Linux\n[[inputs.lustre2]]\n  ## An array of /proc globs to search for Lustre stats\n  ## If not specified, the default will work on Lustre 2.12.x\n  ##\n  # mgs_procfiles = [\n  #   \"/sys/fs/lustre/mgs/*/eviction_count\",\n  # ]\n  # ost_procfiles = [\n  #   \"/proc/fs/lustre/obdfilter/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/stats\",\n  #   \"/proc/fs/lustre/obdfilter/*/job_stats\",\n  #   \"/proc/fs/lustre/obdfilter/*/exports/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n  #   \"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n  #   \"/sys/fs/lustre/odbfilter/*/eviction_count\",\n  # ]\n  # mds_procfiles = [\n  #   \"/proc/fs/lustre/mdt/*/md_stats\",\n  #   \"/proc/fs/lustre/mdt/*/job_stats\",\n  #   \"/proc/fs/lustre/mdt/*/exports/*/stats\",\n  #   \"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n  #   \"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n  #   \"/sys/fs/lustre/mdt/*/eviction_count\",\n  # ]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/expected.out",
    "content": "lustre2,name=OST0001 cache_access=19047063027u,cache_hit=7393729777u,cache_miss=11653333250u,close=873243496u,crossdir_rename=369571u,getattr=1503663097u,getxattr=6145349681u,link=445u,mkdir=705499u,mknod=349042u,open=1024577037u,read_bytes=78026117632000u,read_calls=203238095u,rename=629196u,rmdir=227434u,samedir_rename=259625u,setattr=1898364u,setxattr=83969u,statfs=2916320u,sync=434081u,unlink=3549417u,write_bytes=15201500833981u,write_calls=71893382u 1761849467928697857\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/mdt/OST0001/exports/10.2.4.27@o2ib1/stats",
    "content": "snapshot_time             1438693238.20113 secs.usecs\nopen                      1024577037 samples [reqs]\nclose                     873243496 samples [reqs]\nmknod                     349042 samples [reqs]\nlink                      445 samples [reqs]\nunlink                    3549417 samples [reqs]\nmkdir                     705499 samples [reqs]\nrmdir                     227434 samples [reqs]\nrename                    629196 samples [reqs]\ngetattr                   1503663097 samples [reqs]\nsetattr                   1898364 samples [reqs]\ngetxattr                  6145349681 samples [reqs]\nsetxattr                  83969 samples [reqs]\nstatfs                    2916320 samples [reqs]\nsync                      434081 samples [reqs]\nsamedir_rename            259625 samples [reqs]\ncrossdir_rename           369571 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/mdt/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  open:            { samples:           5, unit:  reqs }\n  close:           { samples:           4, unit:  reqs }\n  mknod:           { samples:           6, unit:  reqs }\n  link:            { samples:           8, unit:  reqs }\n  unlink:          { samples:          90, unit:  reqs }\n  mkdir:           { samples:         521, unit:  reqs }\n  rmdir:           { samples:         520, unit:  reqs }\n  rename:          { samples:           9, unit:  reqs }\n  getattr:         { samples:          11, unit:  reqs }\n  setattr:         { samples:           1, unit:  reqs }\n  getxattr:        { samples:           3, unit:  reqs }\n  setxattr:        { samples:           4, unit:  reqs }\n  statfs:          { samples:        1205, unit:  reqs }\n  sync:            { samples:           2, unit:  reqs }\n  samedir_rename:  { samples:         705, unit:  reqs }\n  crossdir_rename: { samples:         200, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  open:            { samples:           6, unit:  reqs }\n  close:           { samples:           7, unit:  reqs }\n  mknod:           { samples:           8, unit:  reqs }\n  link:            { samples:           9, unit:  reqs }\n  unlink:          { samples:          20, unit:  reqs }\n  mkdir:           { samples:         200, unit:  reqs }\n  rmdir:           { samples:         210, unit:  reqs }\n  rename:          { samples:           8, unit:  reqs }\n  getattr:         { samples:          10, unit:  reqs }\n  setattr:         { samples:           2, unit:  reqs }\n  getxattr:        { samples:           4, unit:  reqs }\n  setxattr:        { samples:           5, unit:  reqs }\n  statfs:          { samples:        1207, unit:  reqs }\n  sync:            { samples:           3, unit:  reqs }\n  samedir_rename:  { samples:         706, unit:  reqs }\n  crossdir_rename: { samples:         201, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/mdt/OST0001/md_stats",
    "content": "snapshot_time             1438693238.20113 secs.usecs\nopen                      1024577037 samples [reqs]\nclose                     873243496 samples [reqs]\nmknod                     349042 samples [reqs]\nlink                      445 samples [reqs]\nunlink                    3549417 samples [reqs]\nmkdir                     705499 samples [reqs]\nrmdir                     227434 samples [reqs]\nrename                    629196 samples [reqs]\ngetattr                   1503663097 samples [reqs]\nsetattr                   1898364 samples [reqs]\ngetxattr                  6145349681 samples [reqs]\nsetxattr                  83969 samples [reqs]\nstatfs                    2916320 samples [reqs]\nsync                      434081 samples [reqs]\nsamedir_rename            259625 samples [reqs]\ncrossdir_rename           369571 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/obdfilter/OST0001/exports/10.2.4.27@o2ib1/stats",
    "content": "snapshot_time             1438693064.430544 secs.usecs\nread_bytes                203238095 samples [bytes] 4096 1048576 78026117632000\nwrite_bytes               71893382 samples [bytes] 1 1048576 15201500833981\nget_info                  1182008495 samples [reqs]\nset_info_async            2 samples [reqs]\nconnect                   1117 samples [reqs]\nreconnect                 1160 samples [reqs]\ndisconnect                1084 samples [reqs]\nstatfs                    3575885 samples [reqs]\ncreate                    698 samples [reqs]\ndestroy                   3190060 samples [reqs]\nsetattr                   605647 samples [reqs]\npunch                     805187 samples [reqs]\nsync                      6608753 samples [reqs]\npreprw                    275131477 samples [reqs]\ncommitrw                  275131477 samples [reqs]\nquotactl                  229231 samples [reqs]\nping                      78020757 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/obdfilter/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    4096, max:    4096, sum:            4096 }\n  write_bytes:     { samples:          25, unit: bytes, min: 1048576, max:16777216, sum:        26214400 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    1024, max:    1024, sum:            1024 }\n  write_bytes:     { samples:          25, unit: bytes, min:    2048, max:    2048, sum:           51200 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/obdfilter/OST0001/stats",
    "content": "snapshot_time             1438693064.430544 secs.usecs\nread_bytes                203238095 samples [bytes] 4096 1048576 78026117632000\nwrite_bytes               71893382 samples [bytes] 1 1048576 15201500833981\nget_info                  1182008495 samples [reqs]\nset_info_async            2 samples [reqs]\nconnect                   1117 samples [reqs]\nreconnect                 1160 samples [reqs]\ndisconnect                1084 samples [reqs]\nstatfs                    3575885 samples [reqs]\ncreate                    698 samples [reqs]\ndestroy                   3190060 samples [reqs]\nsetattr                   605647 samples [reqs]\npunch                     805187 samples [reqs]\nsync                      6608753 samples [reqs]\npreprw                    275131477 samples [reqs]\ncommitrw                  275131477 samples [reqs]\nquotactl                  229231 samples [reqs]\nping                      78020757 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/osd-ldiskfs/OST0001/brw_stats",
    "content": "snapshot_time:         1589909588.327213269 (secs.nsecs)\n                           read      |     write\npages per bulk r/w     rpcs  % cum % |  rpcs        % cum %\n1:                    5271   0   0   | 337023  22  22\n2:                    3030   0   0   | 5672   0  23\n4:                    4449   0   0   | 255983  17  40\n8:                    2780   0   0   | 33612   2  42\n                           read      |     write\ndiscontiguous pages    rpcs  % cum % |  rpcs        % cum %\n0:                43942683 100 100   | 337023  22  22\n1:                       0   0 100   | 5672   0  23\n2:                       0   0 100   | 28016   1  24\n3:                       0   0 100   | 227967  15  40\n4:                       0   0 100   | 12869   0  41\n                           read      |     write\ndisk I/Os in flight    ios   % cum % |  ios         % cum %\n1:                 2892221   6   6   | 1437946  96  96\n2:                 2763141   6  12   | 44373   2  99\n3:                 3014304   6  19   | 2677   0  99\n4:                 3212360   7  27   |  183   0  99\n                           read      |     write\nI/O time (1/1000s)     ios   % cum % |  ios         % cum %\n1:                  521780   1   1   |    0   0   0\n16:                6035560  16  22   |    0   0   0\n128:               5044958  14  98   |    0   0   0\n1K:                    651   0  99   |    0   0   0\n                           read      |     write\ndisk I/O size          ios   % cum % |  ios         % cum %\n1:                       0   0   0   | 327301  22  22\n16:                      0   0   0   |    0   0  22\n128:                    35   0   0   |  209   0  22\n1K:                      0   0   0   | 1703   0  22\n16K:                  4449   0   0   | 255983  17  40\n128K:                  855   0   0   |   23   0  42\n1M:               43866371  99 100   | 850248  57 100\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/host_proc/fs/lustre/osd-ldiskfs/OST0001/stats",
    "content": "snapshot_time             1438693135.640551 secs.usecs\nget_page                  275132812 samples [usec] 0 3147 1320420955 22041662259\ncache_access              19047063027 samples [pages] 1 1 19047063027\ncache_hit                 7393729777 samples [pages] 1 1 7393729777\ncache_miss                11653333250 samples [pages] 1 1 11653333250\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/custom_locations/telegraf.conf",
    "content": "[[inputs.lustre2]]\n  ost_procfiles = [\n    \"/host_proc/fs/lustre/obdfilter/*/stats\",\n    \"/host_proc/fs/lustre/osd-ldiskfs/*/stats\",\n  ]\n  mds_procfiles = [\n    \"/host_proc/fs/lustre/mdt/*/md_stats\",\n  ]"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/expected.out",
    "content": "lustre2,jobid=cluster-testjob1,name=OST0001 jobstats_close=4u,jobstats_create=0u,jobstats_crossdir_rename=200u,jobstats_destroy=0u,jobstats_get_info=0u,jobstats_getattr=11u,jobstats_getxattr=3u,jobstats_link=8u,jobstats_mkdir=521u,jobstats_mknod=6u,jobstats_open=5u,jobstats_ost_getattr=0u,jobstats_ost_setattr=0u,jobstats_ost_statfs=0u,jobstats_ost_sync=0u,jobstats_punch=1u,jobstats_quotactl=0u,jobstats_read_bytes=4096u,jobstats_read_calls=1u,jobstats_read_max_size=4096u,jobstats_read_min_size=4096u,jobstats_rename=9u,jobstats_rmdir=520u,jobstats_samedir_rename=705u,jobstats_set_info=0u,jobstats_setattr=1u,jobstats_setxattr=4u,jobstats_statfs=1205u,jobstats_sync=2u,jobstats_unlink=90u,jobstats_write_bytes=26214400u,jobstats_write_calls=25u,jobstats_write_max_size=16777216u,jobstats_write_min_size=1048576u\nlustre2,brw_section=discontiguous_pages,bucket=4,name=OST0001 read_ios=0u,read_percent=0u,write_ios=12869u,write_percent=0u\nlustre2,brw_section=discontiguous_pages,bucket=3,name=OST0001 read_ios=0u,read_percent=0u,write_ios=227967u,write_percent=15u\nlustre2,name=OST0001 cache_access=19047063027u,cache_hit=7393729777u,cache_miss=11653333250u,close=873243496u,crossdir_rename=369571u,getattr=1503663097u,getxattr=6145349681u,link=445u,mkdir=705499u,mknod=349042u,open=1024577037u,read_bytes=78026117632000u,read_calls=203238095u,rename=629196u,rmdir=227434u,samedir_rename=259625u,setattr=1898364u,setxattr=83969u,statfs=2916320u,sync=434081u,unlink=3549417u,write_bytes=15201500833981u,write_calls=71893382u\nlustre2,jobid=testjob2,name=OST0001 jobstats_close=7u,jobstats_create=0u,jobstats_crossdir_rename=201u,jobstats_destroy=0u,jobstats_get_info=0u,jobstats_getattr=10u,jobstats_getxattr=4u,jobstats_link=9u,jobstats_mkdir=200u,jobstats_mknod=8u,jobstats_open=6u,jobstats_ost_getattr=0u,jobstats_ost_setattr=0u,jobstats_ost_statfs=0u,jobstats_ost_sync=0u,jobstats_punch=1u,jobstats_quotactl=0u,jobstats_read_bytes=1024u,jobstats_read_calls=1u,jobstats_read_max_size=1024u,jobstats_read_min_size=1024u,jobstats_rename=8u,jobstats_rmdir=210u,jobstats_samedir_rename=706u,jobstats_set_info=0u,jobstats_setattr=2u,jobstats_setxattr=5u,jobstats_statfs=1207u,jobstats_sync=3u,jobstats_unlink=20u,jobstats_write_bytes=51200u,jobstats_write_calls=25u,jobstats_write_max_size=2048u,jobstats_write_min_size=2048u\nlustre2,brw_section=pages_per_bulk_rw,bucket=4,name=OST0001 read_ios=4449u,read_percent=0u,write_ios=255983u,write_percent=17u\nlustre2,brw_section=disk_ios_in_flight,bucket=1,name=OST0001 read_ios=2892221u,read_percent=6u,write_ios=1437946u,write_percent=96u\nlustre2,brw_section=io_time,bucket=1,name=OST0001 read_ios=521780u,read_percent=1u,write_ios=0u,write_percent=0u\nlustre2,client=10.2.4.27@o2ib1,name=OST0001 close=873243496u,crossdir_rename=369571u,getattr=1503663097u,getxattr=6145349681u,link=445u,mkdir=705499u,mknod=349042u,open=1024577037u,read_bytes=78026117632000u,read_calls=203238095u,rename=629196u,rmdir=227434u,samedir_rename=259625u,setattr=1898364u,setxattr=83969u,statfs=2916320u,sync=434081u,unlink=3549417u,write_bytes=15201500833981u,write_calls=71893382u\nlustre2,brw_section=disk_io_size,bucket=128,name=OST0001 read_ios=35u,read_percent=0u,write_ios=209u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1K,name=OST0001 read_ios=0u,read_percent=0u,write_ios=1703u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=128K,name=OST0001 read_ios=855u,read_percent=0u,write_ios=23u,write_percent=0u\nlustre2,brw_section=pages_per_bulk_rw,bucket=1,name=OST0001 read_ios=5271u,read_percent=0u,write_ios=337023u,write_percent=22u\nlustre2,brw_section=disk_ios_in_flight,bucket=4,name=OST0001 read_ios=3212360u,read_percent=7u,write_ios=183u,write_percent=0u\nlustre2,brw_section=io_time,bucket=128,name=OST0001 read_ios=5044958u,read_percent=14u,write_ios=0u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1M,name=OST0001 read_ios=43866371u,read_percent=99u,write_ios=850248u,write_percent=57u\nlustre2,brw_section=pages_per_bulk_rw,bucket=8,name=OST0001 read_ios=2780u,read_percent=0u,write_ios=33612u,write_percent=2u\nlustre2,brw_section=discontiguous_pages,bucket=0,name=OST0001 read_ios=43942683u,read_percent=100u,write_ios=337023u,write_percent=22u\nlustre2 health=1u\nlustre2,name=MGS evictions=202u\nlustre2,brw_section=pages_per_bulk_rw,bucket=2,name=OST0001 read_ios=3030u,read_percent=0u,write_ios=5672u,write_percent=0u\nlustre2,brw_section=io_time,bucket=16,name=OST0001 read_ios=6035560u,read_percent=16u,write_ios=0u,write_percent=0u\nlustre2,brw_section=io_time,bucket=1K,name=OST0001 read_ios=651u,read_percent=0u,write_ios=0u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=16K,name=OST0001 read_ios=4449u,read_percent=0u,write_ios=255983u,write_percent=17u\nlustre2,brw_section=discontiguous_pages,bucket=1,name=OST0001 read_ios=0u,read_percent=0u,write_ios=5672u,write_percent=0u\nlustre2,name=fs-OST0001 evictions=303u\nlustre2,name=fs-MDT0000 evictions=101u\nlustre2,brw_section=discontiguous_pages,bucket=2,name=OST0001 read_ios=0u,read_percent=0u,write_ios=28016u,write_percent=1u\nlustre2,brw_section=disk_ios_in_flight,bucket=2,name=OST0001 read_ios=2763141u,read_percent=6u,write_ios=44373u,write_percent=2u\nlustre2,brw_section=disk_ios_in_flight,bucket=3,name=OST0001 read_ios=3014304u,read_percent=6u,write_ios=2677u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1,name=OST0001 read_ios=0u,read_percent=0u,write_ios=327301u,write_percent=22u\nlustre2,brw_section=disk_io_size,bucket=16,name=OST0001 read_ios=0u,read_percent=0u,write_ios=0u,write_percent=0u\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/mdt/OST0001/exports/10.2.4.27@o2ib1/stats",
    "content": "snapshot_time             1438693238.20113 secs.usecs\nopen                      1024577037 samples [reqs]\nclose                     873243496 samples [reqs]\nmknod                     349042 samples [reqs]\nlink                      445 samples [reqs]\nunlink                    3549417 samples [reqs]\nmkdir                     705499 samples [reqs]\nrmdir                     227434 samples [reqs]\nrename                    629196 samples [reqs]\ngetattr                   1503663097 samples [reqs]\nsetattr                   1898364 samples [reqs]\ngetxattr                  6145349681 samples [reqs]\nsetxattr                  83969 samples [reqs]\nstatfs                    2916320 samples [reqs]\nsync                      434081 samples [reqs]\nsamedir_rename            259625 samples [reqs]\ncrossdir_rename           369571 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/mdt/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  open:            { samples:           5, unit:  reqs }\n  close:           { samples:           4, unit:  reqs }\n  mknod:           { samples:           6, unit:  reqs }\n  link:            { samples:           8, unit:  reqs }\n  unlink:          { samples:          90, unit:  reqs }\n  mkdir:           { samples:         521, unit:  reqs }\n  rmdir:           { samples:         520, unit:  reqs }\n  rename:          { samples:           9, unit:  reqs }\n  getattr:         { samples:          11, unit:  reqs }\n  setattr:         { samples:           1, unit:  reqs }\n  getxattr:        { samples:           3, unit:  reqs }\n  setxattr:        { samples:           4, unit:  reqs }\n  statfs:          { samples:        1205, unit:  reqs }\n  sync:            { samples:           2, unit:  reqs }\n  samedir_rename:  { samples:         705, unit:  reqs }\n  crossdir_rename: { samples:         200, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  open:            { samples:           6, unit:  reqs }\n  close:           { samples:           7, unit:  reqs }\n  mknod:           { samples:           8, unit:  reqs }\n  link:            { samples:           9, unit:  reqs }\n  unlink:          { samples:          20, unit:  reqs }\n  mkdir:           { samples:         200, unit:  reqs }\n  rmdir:           { samples:         210, unit:  reqs }\n  rename:          { samples:           8, unit:  reqs }\n  getattr:         { samples:          10, unit:  reqs }\n  setattr:         { samples:           2, unit:  reqs }\n  getxattr:        { samples:           4, unit:  reqs }\n  setxattr:        { samples:           5, unit:  reqs }\n  statfs:          { samples:        1207, unit:  reqs }\n  sync:            { samples:           3, unit:  reqs }\n  samedir_rename:  { samples:         706, unit:  reqs }\n  crossdir_rename: { samples:         201, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/mdt/OST0001/md_stats",
    "content": "snapshot_time             1438693238.20113 secs.usecs\nopen                      1024577037 samples [reqs]\nclose                     873243496 samples [reqs]\nmknod                     349042 samples [reqs]\nlink                      445 samples [reqs]\nunlink                    3549417 samples [reqs]\nmkdir                     705499 samples [reqs]\nrmdir                     227434 samples [reqs]\nrename                    629196 samples [reqs]\ngetattr                   1503663097 samples [reqs]\nsetattr                   1898364 samples [reqs]\ngetxattr                  6145349681 samples [reqs]\nsetxattr                  83969 samples [reqs]\nstatfs                    2916320 samples [reqs]\nsync                      434081 samples [reqs]\nsamedir_rename            259625 samples [reqs]\ncrossdir_rename           369571 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/obdfilter/OST0001/exports/10.2.4.27@o2ib1/stats",
    "content": "snapshot_time             1438693064.430544 secs.usecs\nread_bytes                203238095 samples [bytes] 4096 1048576 78026117632000\nwrite_bytes               71893382 samples [bytes] 1 1048576 15201500833981\nget_info                  1182008495 samples [reqs]\nset_info_async            2 samples [reqs]\nconnect                   1117 samples [reqs]\nreconnect                 1160 samples [reqs]\ndisconnect                1084 samples [reqs]\nstatfs                    3575885 samples [reqs]\ncreate                    698 samples [reqs]\ndestroy                   3190060 samples [reqs]\nsetattr                   605647 samples [reqs]\npunch                     805187 samples [reqs]\nsync                      6608753 samples [reqs]\npreprw                    275131477 samples [reqs]\ncommitrw                  275131477 samples [reqs]\nquotactl                  229231 samples [reqs]\nping                      78020757 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/obdfilter/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    4096, max:    4096, sum:            4096 }\n  write_bytes:     { samples:          25, unit: bytes, min: 1048576, max:16777216, sum:        26214400 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    1024, max:    1024, sum:            1024 }\n  write_bytes:     { samples:          25, unit: bytes, min:    2048, max:    2048, sum:           51200 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/obdfilter/OST0001/stats",
    "content": "snapshot_time             1438693064.430544 secs.usecs\nread_bytes                203238095 samples [bytes] 4096 1048576 78026117632000\nwrite_bytes               71893382 samples [bytes] 1 1048576 15201500833981\nget_info                  1182008495 samples [reqs]\nset_info_async            2 samples [reqs]\nconnect                   1117 samples [reqs]\nreconnect                 1160 samples [reqs]\ndisconnect                1084 samples [reqs]\nstatfs                    3575885 samples [reqs]\ncreate                    698 samples [reqs]\ndestroy                   3190060 samples [reqs]\nsetattr                   605647 samples [reqs]\npunch                     805187 samples [reqs]\nsync                      6608753 samples [reqs]\npreprw                    275131477 samples [reqs]\ncommitrw                  275131477 samples [reqs]\nquotactl                  229231 samples [reqs]\nping                      78020757 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/osd-ldiskfs/OST0001/brw_stats",
    "content": "snapshot_time:         1589909588.327213269 (secs.nsecs)\n                           read      |     write\npages per bulk r/w     rpcs  % cum % |  rpcs        % cum %\n1:                    5271   0   0   | 337023  22  22\n2:                    3030   0   0   | 5672   0  23\n4:                    4449   0   0   | 255983  17  40\n8:                    2780   0   0   | 33612   2  42\n                           read      |     write\ndiscontiguous pages    rpcs  % cum % |  rpcs        % cum %\n0:                43942683 100 100   | 337023  22  22\n1:                       0   0 100   | 5672   0  23\n2:                       0   0 100   | 28016   1  24\n3:                       0   0 100   | 227967  15  40\n4:                       0   0 100   | 12869   0  41\n                           read      |     write\ndisk I/Os in flight    ios   % cum % |  ios         % cum %\n1:                 2892221   6   6   | 1437946  96  96\n2:                 2763141   6  12   | 44373   2  99\n3:                 3014304   6  19   | 2677   0  99\n4:                 3212360   7  27   |  183   0  99\n                           read      |     write\nI/O time (1/1000s)     ios   % cum % |  ios         % cum %\n1:                  521780   1   1   |    0   0   0\n16:                6035560  16  22   |    0   0   0\n128:               5044958  14  98   |    0   0   0\n1K:                    651   0  99   |    0   0   0\n                           read      |     write\ndisk I/O size          ios   % cum % |  ios         % cum %\n1:                       0   0   0   | 327301  22  22\n16:                      0   0   0   |    0   0  22\n128:                    35   0   0   |  209   0  22\n1K:                      0   0   0   | 1703   0  22\n16K:                  4449   0   0   | 255983  17  40\n128K:                  855   0   0   |   23   0  42\n1M:               43866371  99 100   | 850248  57 100\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/proc/fs/lustre/osd-ldiskfs/OST0001/stats",
    "content": "snapshot_time             1438693135.640551 secs.usecs\nget_page                  275132812 samples [usec] 0 3147 1320420955 22041662259\ncache_access              19047063027 samples [pages] 1 1 19047063027\ncache_hit                 7393729777 samples [pages] 1 1 7393729777\ncache_miss                11653333250 samples [pages] 1 1 11653333250\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/sys/fs/lustre/health_check",
    "content": "healthy\n\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/sys/fs/lustre/mdt/fs-MDT0000/eviction_count",
    "content": "101\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/sys/fs/lustre/mgs/MGS/eviction_count",
    "content": "202\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/sys/fs/lustre/obdfilter/fs-OST0001/eviction_count",
    "content": "303\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12/telegraf.conf",
    "content": "[[inputs.lustre2]]\n  ost_procfiles = [\n    \"/proc/fs/lustre/osd-ldiskfs/*/stats\",\n    \"/proc/fs/lustre/osd-ldiskfs/*/brw_stats\",\n    \"/proc/fs/lustre/obdfilter/*/stats\",\n    \"/proc/fs/lustre/obdfilter/*/job_stats\",\n    \"/proc/fs/lustre/obdfilter/*/exports/*/stats\",\n    \"/proc/fs/lustre/osd-zfs/*/brw_stats\",\n    \"/sys/fs/lustre/obdfilter/*/eviction_count\"\n  ]\n\n  mds_procfiles = [\n    \"/proc/fs/lustre/mdt/*/md_stats\",\n    \"/proc/fs/lustre/mdt/*/job_stats\",\n    \"/proc/fs/lustre/mdt/*/exports/*/stats\",\n    \"/sys/fs/lustre/mdt/*/eviction_count\"\n  ]"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/expected.out",
    "content": "lustre2,jobid=cluster-testjob1,name=OST0001 jobstats_close=4u,jobstats_create=0u,jobstats_crossdir_rename=200u,jobstats_destroy=0u,jobstats_get_info=0u,jobstats_getattr=11u,jobstats_getxattr=3u,jobstats_link=8u,jobstats_mkdir=521u,jobstats_mknod=6u,jobstats_open=5u,jobstats_ost_getattr=0u,jobstats_ost_setattr=0u,jobstats_ost_statfs=0u,jobstats_ost_sync=0u,jobstats_punch=1u,jobstats_quotactl=0u,jobstats_read_bytes=4096u,jobstats_read_calls=1u,jobstats_read_max_size=4096u,jobstats_read_min_size=4096u,jobstats_rename=9u,jobstats_rmdir=520u,jobstats_samedir_rename=705u,jobstats_set_info=0u,jobstats_setattr=1u,jobstats_setxattr=4u,jobstats_statfs=1205u,jobstats_sync=2u,jobstats_unlink=90u,jobstats_write_bytes=26214400u,jobstats_write_calls=25u,jobstats_write_max_size=16777216u,jobstats_write_min_size=1048576u\nlustre2,brw_section=discontiguous_pages,bucket=4,name=OST0001 read_ios=0u,read_percent=0u,write_ios=12869u,write_percent=0u\nlustre2,brw_section=discontiguous_pages,bucket=3,name=OST0001 read_ios=0u,read_percent=0u,write_ios=227967u,write_percent=15u\nlustre2,name=OST0001 cache_access=19047063027u,cache_hit=7393729777u,cache_miss=11653333250u,close=873243496u,crossdir_rename=369571u,getattr=1503663097u,getxattr=6145349681u,link=445u,mkdir=705499u,mknod=349042u,open=1024577037u,read_bytes=78026117632000u,read_calls=203238095u,rename=629196u,rmdir=227434u,samedir_rename=259625u,setattr=1898364u,setxattr=83969u,statfs=2916320u,sync=434081u,unlink=3549417u,write_bytes=15201500833981u,write_calls=71893382u\nlustre2,jobid=testjob2,name=OST0001 jobstats_close=7u,jobstats_create=0u,jobstats_crossdir_rename=201u,jobstats_destroy=0u,jobstats_get_info=0u,jobstats_getattr=10u,jobstats_getxattr=4u,jobstats_link=9u,jobstats_mkdir=200u,jobstats_mknod=8u,jobstats_open=6u,jobstats_ost_getattr=0u,jobstats_ost_setattr=0u,jobstats_ost_statfs=0u,jobstats_ost_sync=0u,jobstats_punch=1u,jobstats_quotactl=0u,jobstats_read_bytes=1024u,jobstats_read_calls=1u,jobstats_read_max_size=1024u,jobstats_read_min_size=1024u,jobstats_rename=8u,jobstats_rmdir=210u,jobstats_samedir_rename=706u,jobstats_set_info=0u,jobstats_setattr=2u,jobstats_setxattr=5u,jobstats_statfs=1207u,jobstats_sync=3u,jobstats_unlink=20u,jobstats_write_bytes=51200u,jobstats_write_calls=25u,jobstats_write_max_size=2048u,jobstats_write_min_size=2048u\nlustre2,brw_section=pages_per_bulk_rw,bucket=4,name=OST0001 read_ios=4449u,read_percent=0u,write_ios=255983u,write_percent=17u\nlustre2,brw_section=disk_ios_in_flight,bucket=1,name=OST0001 read_ios=2892221u,read_percent=6u,write_ios=1437946u,write_percent=96u\nlustre2,brw_section=io_time,bucket=1,name=OST0001 read_ios=521780u,read_percent=1u,write_ios=0u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=128,name=OST0001 read_ios=35u,read_percent=0u,write_ios=209u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1K,name=OST0001 read_ios=0u,read_percent=0u,write_ios=1703u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=128K,name=OST0001 read_ios=855u,read_percent=0u,write_ios=23u,write_percent=0u\nlustre2,brw_section=pages_per_bulk_rw,bucket=1,name=OST0001 read_ios=5271u,read_percent=0u,write_ios=337023u,write_percent=22u\nlustre2,brw_section=disk_ios_in_flight,bucket=4,name=OST0001 read_ios=3212360u,read_percent=7u,write_ios=183u,write_percent=0u\nlustre2,brw_section=io_time,bucket=128,name=OST0001 read_ios=5044958u,read_percent=14u,write_ios=0u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1M,name=OST0001 read_ios=43866371u,read_percent=99u,write_ios=850248u,write_percent=57u\nlustre2,brw_section=pages_per_bulk_rw,bucket=8,name=OST0001 read_ios=2780u,read_percent=0u,write_ios=33612u,write_percent=2u\nlustre2,brw_section=discontiguous_pages,bucket=0,name=OST0001 read_ios=43942683u,read_percent=100u,write_ios=337023u,write_percent=22u\nlustre2 health=1u\nlustre2,name=MGS evictions=202u\nlustre2,brw_section=pages_per_bulk_rw,bucket=2,name=OST0001 read_ios=3030u,read_percent=0u,write_ios=5672u,write_percent=0u\nlustre2,brw_section=io_time,bucket=16,name=OST0001 read_ios=6035560u,read_percent=16u,write_ios=0u,write_percent=0u\nlustre2,brw_section=io_time,bucket=1K,name=OST0001 read_ios=651u,read_percent=0u,write_ios=0u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=16K,name=OST0001 read_ios=4449u,read_percent=0u,write_ios=255983u,write_percent=17u\nlustre2,brw_section=discontiguous_pages,bucket=1,name=OST0001 read_ios=0u,read_percent=0u,write_ios=5672u,write_percent=0u\nlustre2,name=fs-OST0001 evictions=303u\nlustre2,name=fs-MDT0000 evictions=101u\nlustre2,brw_section=discontiguous_pages,bucket=2,name=OST0001 read_ios=0u,read_percent=0u,write_ios=28016u,write_percent=1u\nlustre2,brw_section=disk_ios_in_flight,bucket=2,name=OST0001 read_ios=2763141u,read_percent=6u,write_ios=44373u,write_percent=2u\nlustre2,brw_section=disk_ios_in_flight,bucket=3,name=OST0001 read_ios=3014304u,read_percent=6u,write_ios=2677u,write_percent=0u\nlustre2,brw_section=disk_io_size,bucket=1,name=OST0001 read_ios=0u,read_percent=0u,write_ios=327301u,write_percent=22u\nlustre2,brw_section=disk_io_size,bucket=16,name=OST0001 read_ios=0u,read_percent=0u,write_ios=0u,write_percent=0u\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/mdt/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  open:            { samples:           5, unit:  reqs }\n  close:           { samples:           4, unit:  reqs }\n  mknod:           { samples:           6, unit:  reqs }\n  link:            { samples:           8, unit:  reqs }\n  unlink:          { samples:          90, unit:  reqs }\n  mkdir:           { samples:         521, unit:  reqs }\n  rmdir:           { samples:         520, unit:  reqs }\n  rename:          { samples:           9, unit:  reqs }\n  getattr:         { samples:          11, unit:  reqs }\n  setattr:         { samples:           1, unit:  reqs }\n  getxattr:        { samples:           3, unit:  reqs }\n  setxattr:        { samples:           4, unit:  reqs }\n  statfs:          { samples:        1205, unit:  reqs }\n  sync:            { samples:           2, unit:  reqs }\n  samedir_rename:  { samples:         705, unit:  reqs }\n  crossdir_rename: { samples:         200, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  open:            { samples:           6, unit:  reqs }\n  close:           { samples:           7, unit:  reqs }\n  mknod:           { samples:           8, unit:  reqs }\n  link:            { samples:           9, unit:  reqs }\n  unlink:          { samples:          20, unit:  reqs }\n  mkdir:           { samples:         200, unit:  reqs }\n  rmdir:           { samples:         210, unit:  reqs }\n  rename:          { samples:           8, unit:  reqs }\n  getattr:         { samples:          10, unit:  reqs }\n  setattr:         { samples:           2, unit:  reqs }\n  getxattr:        { samples:           4, unit:  reqs }\n  setxattr:        { samples:           5, unit:  reqs }\n  statfs:          { samples:        1207, unit:  reqs }\n  sync:            { samples:           3, unit:  reqs }\n  samedir_rename:  { samples:         706, unit:  reqs }\n  crossdir_rename: { samples:         201, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/mdt/OST0001/md_stats",
    "content": "snapshot_time             1438693238.20113 secs.usecs\nopen                      1024577037 samples [reqs]\nclose                     873243496 samples [reqs]\nmknod                     349042 samples [reqs]\nlink                      445 samples [reqs]\nunlink                    3549417 samples [reqs]\nmkdir                     705499 samples [reqs]\nrmdir                     227434 samples [reqs]\nrename                    629196 samples [reqs]\ngetattr                   1503663097 samples [reqs]\nsetattr                   1898364 samples [reqs]\ngetxattr                  6145349681 samples [reqs]\nsetxattr                  83969 samples [reqs]\nstatfs                    2916320 samples [reqs]\nsync                      434081 samples [reqs]\nsamedir_rename            259625 samples [reqs]\ncrossdir_rename           369571 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/obdfilter/OST0001/job_stats",
    "content": "job_stats:\n- job_id:          cluster-testjob1\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    4096, max:    4096, sum:            4096 }\n  write_bytes:     { samples:          25, unit: bytes, min: 1048576, max:16777216, sum:        26214400 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n- job_id:          testjob2\n  snapshot_time:   1461772761\n  read_bytes:      { samples:           1, unit: bytes, min:    1024, max:    1024, sum:            1024 }\n  write_bytes:     { samples:          25, unit: bytes, min:    2048, max:    2048, sum:           51200 }\n  getattr:         { samples:           0, unit:  reqs }\n  setattr:         { samples:           0, unit:  reqs }\n  punch:           { samples:           1, unit:  reqs }\n  sync:            { samples:           0, unit:  reqs }\n  destroy:         { samples:           0, unit:  reqs }\n  create:          { samples:           0, unit:  reqs }\n  statfs:          { samples:           0, unit:  reqs }\n  get_info:        { samples:           0, unit:  reqs }\n  set_info:        { samples:           0, unit:  reqs }\n  quotactl:        { samples:           0, unit:  reqs }\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/obdfilter/OST0001/stats",
    "content": "snapshot_time             1438693064.430544 secs.usecs\nread_bytes                203238095 samples [bytes] 4096 1048576 78026117632000\nwrite_bytes               71893382 samples [bytes] 1 1048576 15201500833981\nget_info                  1182008495 samples [reqs]\nset_info_async            2 samples [reqs]\nconnect                   1117 samples [reqs]\nreconnect                 1160 samples [reqs]\ndisconnect                1084 samples [reqs]\nstatfs                    3575885 samples [reqs]\ncreate                    698 samples [reqs]\ndestroy                   3190060 samples [reqs]\nsetattr                   605647 samples [reqs]\npunch                     805187 samples [reqs]\nsync                      6608753 samples [reqs]\npreprw                    275131477 samples [reqs]\ncommitrw                  275131477 samples [reqs]\nquotactl                  229231 samples [reqs]\nping                      78020757 samples [reqs]\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/osd-ldiskfs/OST0001/brw_stats",
    "content": "snapshot_time:         1589909588.327213269 (secs.nsecs)\n                           read      |     write\npages per bulk r/w     rpcs  % cum % |  rpcs        % cum %\n1:                    5271   0   0   | 337023  22  22\n2:                    3030   0   0   | 5672   0  23\n4:                    4449   0   0   | 255983  17  40\n8:                    2780   0   0   | 33612   2  42\n                           read      |     write\ndiscontiguous pages    rpcs  % cum % |  rpcs        % cum %\n0:                43942683 100 100   | 337023  22  22\n1:                       0   0 100   | 5672   0  23\n2:                       0   0 100   | 28016   1  24\n3:                       0   0 100   | 227967  15  40\n4:                       0   0 100   | 12869   0  41\n                           read      |     write\ndisk I/Os in flight    ios   % cum % |  ios         % cum %\n1:                 2892221   6   6   | 1437946  96  96\n2:                 2763141   6  12   | 44373   2  99\n3:                 3014304   6  19   | 2677   0  99\n4:                 3212360   7  27   |  183   0  99\n                           read      |     write\nI/O time (1/1000s)     ios   % cum % |  ios         % cum %\n1:                  521780   1   1   |    0   0   0\n16:                6035560  16  22   |    0   0   0\n128:               5044958  14  98   |    0   0   0\n1K:                    651   0  99   |    0   0   0\n                           read      |     write\ndisk I/O size          ios   % cum % |  ios         % cum %\n1:                       0   0   0   | 327301  22  22\n16:                      0   0   0   |    0   0  22\n128:                    35   0   0   |  209   0  22\n1K:                      0   0   0   | 1703   0  22\n16K:                  4449   0   0   | 255983  17  40\n128K:                  855   0   0   |   23   0  42\n1M:               43866371  99 100   | 850248  57 100\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/proc/fs/lustre/osd-ldiskfs/OST0001/stats",
    "content": "snapshot_time             1438693135.640551 secs.usecs\nget_page                  275132812 samples [usec] 0 3147 1320420955 22041662259\ncache_access              19047063027 samples [pages] 1 1 19047063027\ncache_hit                 7393729777 samples [pages] 1 1 7393729777\ncache_miss                11653333250 samples [pages] 1 1 11653333250\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/sys/fs/lustre/health_check",
    "content": "healthy\n\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/sys/fs/lustre/mdt/fs-MDT0000/eviction_count",
    "content": "101\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/sys/fs/lustre/mgs/MGS/eviction_count",
    "content": "202\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/sys/fs/lustre/obdfilter/fs-OST0001/eviction_count",
    "content": "303\n"
  },
  {
    "path": "plugins/inputs/lustre2/testcases/v2.12_no_client_stats/telegraf.conf",
    "content": "[[inputs.lustre2]]"
  },
  {
    "path": "plugins/inputs/lvm/README.md",
    "content": "# Logical Volume Manager Input Plugin\n\nThis plugin collects information about physical volumes, volume groups and\nlogical volumes from the Logical Volume Management (LVM) of the\n[Linux kernel][kernel].\n\n⭐ Telegraf v1.21.0\n🏷️ system\n💻 linux\n\n[kernel]: https://www.kernel.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about LVM physical volumes, volume groups, logical volumes.\n[[inputs.lvm]]\n  ## Use sudo to run LVM commands\n  use_sudo = false\n\n  ## The default location of the pvs binary can be overridden with:\n  #pvs_binary = \"/usr/sbin/pvs\"\n\n  ## The default location of the vgs binary can be overridden with:\n  #vgs_binary = \"/usr/sbin/vgs\"\n\n  ## The default location of the lvs binary can be overridden with:\n  #lvs_binary = \"/usr/sbin/lvs\"\n```\n\nThe LVM commands requires elevated permissions. If the user has configured sudo\nwith the ability to run these commands, then set the `use_sudo` to true.\n\n### Using sudo\n\nIf your account does not already have the ability to run commands\nwith passwordless sudo then updates to the sudoers file are required. Below\nis an example to allow the requires LVM commands:\n\nFirst, use the `visudo` command to start editing the sudoers file. Then add\nthe following content, where `<username>` is the username of the user that\nneeds this access:\n\n```text\nCmnd_Alias LVM = /usr/sbin/pvs *, /usr/sbin/vgs *, /usr/sbin/lvs *\n<username>  ALL=(root) NOPASSWD: LVM\nDefaults!LVM !logfile, !syslog, !pam_session\n```\n\nPath to binaries must match those from config file (pvs_binary, vgs_binary and\nlvs_binary)\n\n## Metrics\n\nMetrics are broken out by physical volume (pv), volume group (vg), and logical\nvolume (lv):\n\n- lvm_physical_vol\n  - tags\n    - path\n    - vol_group\n  - fields\n    - size\n    - free\n    - used\n    - used_percent\n- lvm_vol_group\n  - tags\n    - name\n  - fields\n    - size\n    - free\n    - used_percent\n    - physical_volume_count\n    - logical_volume_count\n    - snapshot_count\n- lvm_logical_vol\n  - tags\n    - name\n    - vol_group\n  - fields\n    - size\n    - data_percent\n    - metadata_percent\n    - sync_percent\n\n## Example Output\n\nThe following example shows a system with the root partition on an LVM group\nas well as with a Docker thin-provisioned LVM group on a second drive:\n\n```text\nlvm_physical_vol,path=/dev/sda2,vol_group=vgroot free=0i,size=249510756352i,used=249510756352i,used_percent=100 1631823026000000000\nlvm_physical_vol,path=/dev/sdb,vol_group=docker free=3858759680i,size=128316342272i,used=124457582592i,used_percent=96.99277612525741 1631823026000000000\nlvm_vol_group,name=vgroot free=0i,logical_volume_count=1i,physical_volume_count=1i,size=249510756352i,snapshot_count=0i,used_percent=100 1631823026000000000\nlvm_vol_group,name=docker free=3858759680i,logical_volume_count=1i,physical_volume_count=1i,size=128316342272i,snapshot_count=0i,used_percent=96.99277612525741 1631823026000000000\nlvm_logical_vol,name=lvroot,vol_group=vgroot data_percent=0,metadata_percent=0,size=249510756352i 1631823026000000000\nlvm_logical_vol,name=thinpool,vol_group=docker data_percent=0.36000001430511475,metadata_percent=1.3300000429153442,size=121899057152i 1631823026000000000\n```\n"
  },
  {
    "path": "plugins/inputs/lvm/lvm.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage lvm\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\texecCommand = exec.Command\n)\n\ntype LVM struct {\n\tUseSudo   bool   `toml:\"use_sudo\"`\n\tPVSBinary string `toml:\"pvs_binary\"`\n\tVGSBinary string `toml:\"vgs_binary\"`\n\tLVSBinary string `toml:\"lvs_binary\"`\n}\n\nfunc (*LVM) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (lvm *LVM) Gather(acc telegraf.Accumulator) error {\n\tif err := lvm.gatherPhysicalVolumes(acc); err != nil {\n\t\treturn err\n\t} else if err := lvm.gatherVolumeGroups(acc); err != nil {\n\t\treturn err\n\t} else if err := lvm.gatherLogicalVolumes(acc); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (lvm *LVM) gatherPhysicalVolumes(acc telegraf.Accumulator) error {\n\targs := []string{\n\t\t\"--reportformat\", \"json\", \"--units\", \"b\", \"--nosuffix\",\n\t\t\"-o\", \"pv_name,vg_name,pv_size,pv_free,pv_used\",\n\t}\n\tout, err := lvm.runCmd(lvm.PVSBinary, args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar report pvsReport\n\terr = json.Unmarshal(out, &report)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal physical volume JSON: %w\", err)\n\t}\n\n\tif len(report.Report) > 0 {\n\t\tfor _, pv := range report.Report[0].Pv {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"path\":      pv.Name,\n\t\t\t\t\"vol_group\": pv.VolGroup,\n\t\t\t}\n\n\t\t\tsize, err := strconv.ParseUint(pv.Size, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfree, err := strconv.ParseUint(pv.Free, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tused, err := strconv.ParseUint(pv.Used, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tusedPercent := float64(used) / float64(size) * 100\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"size\":         size,\n\t\t\t\t\"free\":         free,\n\t\t\t\t\"used\":         used,\n\t\t\t\t\"used_percent\": usedPercent,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"lvm_physical_vol\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (lvm *LVM) gatherVolumeGroups(acc telegraf.Accumulator) error {\n\targs := []string{\n\t\t\"--reportformat\", \"json\", \"--units\", \"b\", \"--nosuffix\",\n\t\t\"-o\", \"vg_name,pv_count,lv_count,snap_count,vg_size,vg_free\",\n\t}\n\tout, err := lvm.runCmd(lvm.VGSBinary, args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar report vgsReport\n\terr = json.Unmarshal(out, &report)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal vol group JSON: %w\", err)\n\t}\n\n\tif len(report.Report) > 0 {\n\t\tfor _, vg := range report.Report[0].Vg {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"name\": vg.Name,\n\t\t\t}\n\n\t\t\tsize, err := strconv.ParseUint(vg.Size, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfree, err := strconv.ParseUint(vg.Free, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tpvCount, err := strconv.ParseUint(vg.PvCount, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlvCount, err := strconv.ParseUint(vg.LvCount, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tsnapCount, err := strconv.ParseUint(vg.SnapCount, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tusedPercent := (float64(size) - float64(free)) / float64(size) * 100\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"size\":                  size,\n\t\t\t\t\"free\":                  free,\n\t\t\t\t\"used_percent\":          usedPercent,\n\t\t\t\t\"physical_volume_count\": pvCount,\n\t\t\t\t\"logical_volume_count\":  lvCount,\n\t\t\t\t\"snapshot_count\":        snapCount,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"lvm_vol_group\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (lvm *LVM) gatherLogicalVolumes(acc telegraf.Accumulator) error {\n\targs := []string{\n\t\t\"--reportformat\", \"json\", \"--units\", \"b\", \"--nosuffix\",\n\t\t\"-o\", \"lv_name,vg_name,lv_size,data_percent,metadata_percent,sync_percent\",\n\t}\n\tout, err := lvm.runCmd(lvm.LVSBinary, args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar report lvsReport\n\terr = json.Unmarshal(out, &report)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal logical vol JSON: %w\", err)\n\t}\n\n\tif len(report.Report) > 0 {\n\t\tfor _, lv := range report.Report[0].Lv {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"name\":      lv.Name,\n\t\t\t\t\"vol_group\": lv.VolGroup,\n\t\t\t}\n\n\t\t\tsize, err := strconv.ParseUint(lv.Size, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Does not apply to all logical volumes, set default value\n\t\t\tif lv.DataPercent == \"\" {\n\t\t\t\tlv.DataPercent = \"0.0\"\n\t\t\t}\n\t\t\tdataPercent, err := strconv.ParseFloat(lv.DataPercent, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Does not apply to all logical volumes, set default value\n\t\t\tif lv.MetadataPercent == \"\" {\n\t\t\t\tlv.MetadataPercent = \"0.0\"\n\t\t\t}\n\t\t\tmetadataPercent, err := strconv.ParseFloat(lv.MetadataPercent, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Only provided if sync in progress, default completed\n\t\t\tif lv.SyncPercent == \"\" {\n\t\t\t\tlv.SyncPercent = \"100.0\"\n\t\t\t}\n\t\t\tsyncPercent, err := strconv.ParseFloat(lv.SyncPercent, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"size\":             size,\n\t\t\t\t\"data_percent\":     dataPercent,\n\t\t\t\t\"metadata_percent\": metadataPercent,\n\t\t\t\t\"sync_percent\":     syncPercent,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"lvm_logical_vol\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (lvm *LVM) runCmd(cmd string, args []string) ([]byte, error) {\n\texecCmd := execCommand(cmd, args...)\n\tif lvm.UseSudo {\n\t\texecCmd = execCommand(\"sudo\", append([]string{\"-n\", cmd}, args...)...)\n\t}\n\n\tout, err := internal.StdOutputTimeout(execCmd, 5*time.Second)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"failed to run command %s: %w - %s\", strings.Join(execCmd.Args, \" \"), err, string(out),\n\t\t)\n\t}\n\n\treturn out, nil\n}\n\n// Represents info about physical volume command, pvs, output\ntype pvsReport struct {\n\tReport []struct {\n\t\tPv []struct {\n\t\t\tName     string `json:\"pv_name\"`\n\t\t\tVolGroup string `json:\"vg_name\"`\n\t\t\tSize     string `json:\"pv_size\"`\n\t\t\tFree     string `json:\"pv_free\"`\n\t\t\tUsed     string `json:\"pv_used\"`\n\t\t} `json:\"pv\"`\n\t} `json:\"report\"`\n}\n\n// Represents info about volume group command, vgs, output\ntype vgsReport struct {\n\tReport []struct {\n\t\tVg []struct {\n\t\t\tName      string `json:\"vg_name\"`\n\t\t\tSize      string `json:\"vg_size\"`\n\t\t\tFree      string `json:\"vg_free\"`\n\t\t\tLvCount   string `json:\"lv_count\"`\n\t\t\tPvCount   string `json:\"pv_count\"`\n\t\t\tSnapCount string `json:\"snap_count\"`\n\t\t} `json:\"vg\"`\n\t} `json:\"report\"`\n}\n\n// Represents info about logical volume command, lvs, output\ntype lvsReport struct {\n\tReport []struct {\n\t\tLv []struct {\n\t\t\tName            string `json:\"lv_name\"`\n\t\t\tVolGroup        string `json:\"vg_name\"`\n\t\t\tSize            string `json:\"lv_size\"`\n\t\t\tDataPercent     string `json:\"data_percent\"`\n\t\t\tMetadataPercent string `json:\"metadata_percent\"`\n\t\t\tSyncPercent     string `json:\"sync_percent\"`\n\t\t} `json:\"lv\"`\n\t} `json:\"report\"`\n}\n\nfunc init() {\n\tinputs.Add(\"lvm\", func() telegraf.Input {\n\t\treturn &LVM{\n\t\t\tPVSBinary: \"/usr/sbin/pvs\",\n\t\t\tVGSBinary: \"/usr/sbin/vgs\",\n\t\t\tLVSBinary: \"/usr/sbin/lvs\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/lvm/lvm_test.go",
    "content": "package lvm\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tlvm := LVM{\n\t\tPVSBinary: \"/usr/sbin/pvs\",\n\t\tVGSBinary: \"/usr/sbin/vgs\",\n\t\tLVSBinary: \"/usr/sbin/lvs\",\n\t}\n\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommand\n\terr := lvm.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tpvsTags := map[string]string{\n\t\t\"path\":      \"/dev/sdb\",\n\t\t\"vol_group\": \"docker\",\n\t}\n\tpvsFields := map[string]interface{}{\n\t\t\"size\":         uint64(128316342272),\n\t\t\"free\":         uint64(3858759680),\n\t\t\"used\":         uint64(124457582592),\n\t\t\"used_percent\": 96.99277612525741,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"lvm_physical_vol\", pvsFields, pvsTags)\n\n\tvgsTags := map[string]string{\n\t\t\"name\": \"docker\",\n\t}\n\tvgsFields := map[string]interface{}{\n\t\t\"size\":                  uint64(128316342272),\n\t\t\"free\":                  uint64(3858759680),\n\t\t\"used_percent\":          96.99277612525741,\n\t\t\"physical_volume_count\": uint64(1),\n\t\t\"logical_volume_count\":  uint64(1),\n\t\t\"snapshot_count\":        uint64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"lvm_vol_group\", vgsFields, vgsTags)\n\n\tlvsTags := map[string]string{\n\t\t\"name\":      \"thinpool\",\n\t\t\"vol_group\": \"docker\",\n\t}\n\tlvsFields := map[string]interface{}{\n\t\t\"size\":             uint64(121899057152),\n\t\t\"data_percent\":     0.36000001430511475,\n\t\t\"metadata_percent\": 1.3300000429153442,\n\t\t\"sync_percent\":     100.0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"lvm_logical_vol\", lvsFields, lvsTags)\n\n\tlvsTags2 := map[string]string{\n\t\t\"name\":      \"lv\",\n\t\t\"vol_group\": \"vg\",\n\t}\n\tlvsFields2 := map[string]interface{}{\n\t\t\"size\":             uint64(200000000000000),\n\t\t\"data_percent\":     0.0,\n\t\t\"metadata_percent\": 0.0,\n\t\t\"sync_percent\":     39.4900016784668,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"lvm_logical_vol\", lvsFields2, lvsTags2)\n}\n\n// Used as a helper function that mock the exec.Command call\nfunc fakeExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestHelperProcess\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\n// Used to mock exec.Command output\nfunc TestHelperProcess(_ *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\tmockPVSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"pv\": [\n\t\t\t\t\t{\"pv_name\":\"/dev/sdb\", \"vg_name\":\"docker\", \"pv_size\":\"128316342272\", \"pv_free\":\"3858759680\", \"pv_used\":\"124457582592\"}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\tmockVGSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"vg\": [\n\t\t\t\t\t{\"vg_name\":\"docker\", \"pv_count\":\"1\", \"lv_count\":\"1\", \"snap_count\":\"0\", \"vg_size\":\"128316342272\", \"vg_free\":\"3858759680\"}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\tmockLVSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"lv\": [\n\t\t\t\t\t{\"lv_name\":\"thinpool\", \"vg_name\":\"docker\", \"lv_size\":\"121899057152\", \"data_percent\":\"0.36\", \"metadata_percent\":\"1.33\", \"sync_percent\":\"\"},\n\t\t\t\t\t{\"lv_name\":\"lv\", \"vg_name\":\"vg\", \"lv_size\":\"200000000000000\", \"data_percent\":\"\", \"metadata_percent\":\"\", \"sync_percent\":\"39.49\"}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\t// Previous arguments are tests stuff, that looks like :\n\t// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --\n\targs := os.Args\n\tcmd := args[3]\n\tif cmd == \"/usr/sbin/pvs\" {\n\t\tfmt.Fprint(os.Stdout, mockPVSData)\n\t} else if cmd == \"/usr/sbin/vgs\" {\n\t\tfmt.Fprint(os.Stdout, mockVGSData)\n\t} else if cmd == \"/usr/sbin/lvs\" {\n\t\tfmt.Fprint(os.Stdout, mockLVSData)\n\t} else {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n\n// test when no lvm devices exist\nfunc TestGatherNoLVM(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnoLVM := LVM{\n\t\tPVSBinary: \"/usr/sbin/pvs\",\n\t\tVGSBinary: \"/usr/sbin/vgs\",\n\t\tLVSBinary: \"/usr/sbin/lvs\",\n\t}\n\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommandNoLVM\n\terr := noLVM.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tacc.AssertDoesNotContainMeasurement(t, \"lvm_physical_vol\")\n\tacc.AssertDoesNotContainMeasurement(t, \"lvm_vol_group\")\n\tacc.AssertDoesNotContainMeasurement(t, \"lvm_logical_vol\")\n}\n\n// Used as a helper function that mock the exec.Command call\nfunc fakeExecCommandNoLVM(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestHelperProcessNoLVM\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\n// Used to mock exec.Command output\nfunc TestHelperProcessNoLVM(_ *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\tmockPVSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"pv\": [\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\tmockVGSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"vg\": [\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\tmockLVSData := `{\n\t\t\"report\": [\n\t\t\t{\n\t\t\t\t\"lv\": [\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n`\n\n\t// Previous arguments are tests stuff, that looks like :\n\t// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --\n\targs := os.Args\n\tcmd := args[3]\n\tif cmd == \"/usr/sbin/pvs\" {\n\t\tfmt.Fprint(os.Stdout, mockPVSData)\n\t} else if cmd == \"/usr/sbin/vgs\" {\n\t\tfmt.Fprint(os.Stdout, mockVGSData)\n\t} else if cmd == \"/usr/sbin/lvs\" {\n\t\tfmt.Fprint(os.Stdout, mockLVSData)\n\t} else {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n"
  },
  {
    "path": "plugins/inputs/lvm/sample.conf",
    "content": "# Read metrics about LVM physical volumes, volume groups, logical volumes.\n[[inputs.lvm]]\n  ## Use sudo to run LVM commands\n  use_sudo = false\n\n  ## The default location of the pvs binary can be overridden with:\n  #pvs_binary = \"/usr/sbin/pvs\"\n\n  ## The default location of the vgs binary can be overridden with:\n  #vgs_binary = \"/usr/sbin/vgs\"\n\n  ## The default location of the lvs binary can be overridden with:\n  #lvs_binary = \"/usr/sbin/lvs\"\n"
  },
  {
    "path": "plugins/inputs/mailchimp/README.md",
    "content": "# Mailchimp Input Plugin\n\nThis plugin gathers metrics from the [Mailchimp][mailchimp] service using the\n[Mailchimp API][api].\n\n⭐ Telegraf v0.2.4\n🏷️ cloud, web\n💻 all\n\n[mailchimp]: https://mailchimp.com\n[api]: https://developer.mailchimp.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gathers metrics from the /3.0/reports MailChimp API\n[[inputs.mailchimp]]\n  ## MailChimp API key\n  ## get from https://admin.mailchimp.com/account/api/\n  api_key = \"\" # required\n\n  ## Reports for campaigns sent more than days_old ago will not be collected.\n  ## 0 means collect all and is the default value.\n  days_old = 0\n\n  ## Campaign ID to get, if empty gets all campaigns, this option overrides days_old\n  # campaign_id = \"\"\n```\n\n## Metrics\n\n- mailchimp\n  - tags:\n    - id\n    - campaign_title\n  - fields:\n    - emails_sent (integer, emails)\n    - abuse_reports (integer, reports)\n    - unsubscribed (integer, unsubscribes)\n    - hard_bounces (integer, emails)\n    - soft_bounces (integer, emails)\n    - syntax_errors (integer, errors)\n    - forwards_count (integer, emails)\n    - forwards_opens (integer, emails)\n    - opens_total (integer, emails)\n    - unique_opens (integer, emails)\n    - open_rate (double, percentage)\n    - clicks_total (integer, clicks)\n    - unique_clicks (integer, clicks)\n    - unique_subscriber_clicks (integer, clicks)\n    - click_rate (double, percentage)\n    - facebook_recipient_likes (integer, likes)\n    - facebook_unique_likes (integer, likes)\n    - facebook_likes (integer, likes)\n    - industry_type (string, type)\n    - industry_open_rate (double, percentage)\n    - industry_click_rate (double, percentage)\n    - industry_bounce_rate (double, percentage)\n    - industry_unopen_rate (double, percentage)\n    - industry_unsub_rate (double, percentage)\n    - industry_abuse_rate (double, percentage)\n    - list_stats_sub_rate (double, percentage)\n    - list_stats_unsub_rate (double, percentage)\n    - list_stats_open_rate (double, percentage)\n    - list_stats_click_rate (double, percentage)\n\n## Example Output\n\n```text\nmailchimp,campaign_title=Freddie's\\ Jokes\\ Vol.\\ 1,id=42694e9e57 abuse_reports=0i,click_rate=42,clicks_total=42i,emails_sent=200i,facebook_likes=42i,facebook_recipient_likes=5i,facebook_unique_likes=8i,forwards_count=0i,forwards_opens=0i,hard_bounces=0i,industry_abuse_rate=0.00021111996110887,industry_bounce_rate=0.0063767751251474,industry_click_rate=0.027431311866951,industry_open_rate=0.17076777144396,industry_type=\"Social Networks and Online Communities\",industry_unopen_rate=0.82285545343089,industry_unsub_rate=0.001436957032815,list_stats_click_rate=42,list_stats_open_rate=42,list_stats_sub_rate=10,list_stats_unsub_rate=20,open_rate=42,opens_total=186i,soft_bounces=2i,syntax_errors=0i,unique_clicks=400i,unique_opens=100i,unique_subscriber_clicks=42i,unsubscribed=2i 1741188555526302348\n```\n"
  },
  {
    "path": "plugins/inputs/mailchimp/chimp_api.go",
    "content": "package mailchimp\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nconst (\n\treportsEndpoint         string = \"/3.0/reports\"\n\treportsEndpointCampaign string = \"/3.0/reports/%s\"\n)\n\nvar mailchimpDatacenter = regexp.MustCompile(\"[a-z]+[0-9]+$\")\n\ntype chimpAPI struct {\n\ttransport http.RoundTripper\n\tdebug     bool\n\n\tsync.Mutex\n\n\turl *url.URL\n\tlog telegraf.Logger\n}\n\ntype reportsParams struct {\n\tcount          string\n\toffset         string\n\tsinceSendTime  string\n\tbeforeSendTime string\n}\n\nfunc (p *reportsParams) String() string {\n\tv := url.Values{}\n\tif p.count != \"\" {\n\t\tv.Set(\"count\", p.count)\n\t}\n\tif p.offset != \"\" {\n\t\tv.Set(\"offset\", p.offset)\n\t}\n\tif p.beforeSendTime != \"\" {\n\t\tv.Set(\"before_send_time\", p.beforeSendTime)\n\t}\n\tif p.sinceSendTime != \"\" {\n\t\tv.Set(\"since_send_time\", p.sinceSendTime)\n\t}\n\treturn v.Encode()\n}\n\nfunc newChimpAPI(apiKey string, log telegraf.Logger) *chimpAPI {\n\tu := &url.URL{}\n\tu.Scheme = \"https\"\n\tu.Host = mailchimpDatacenter.FindString(apiKey) + \".api.mailchimp.com\"\n\tu.User = url.UserPassword(\"\", apiKey)\n\treturn &chimpAPI{url: u, log: log}\n}\n\ntype apiError struct {\n\tStatus   int    `json:\"status\"`\n\tType     string `json:\"type\"`\n\tTitle    string `json:\"title\"`\n\tDetail   string `json:\"detail\"`\n\tInstance string `json:\"instance\"`\n}\n\nfunc (e apiError) Error() string {\n\treturn fmt.Sprintf(\"ERROR %v: %v. See %v\", e.Status, e.Title, e.Type)\n}\n\nfunc chimpErrorCheck(body []byte) error {\n\tvar e apiError\n\tif err := json.Unmarshal(body, &e); err != nil {\n\t\treturn err\n\t}\n\tif e.Title != \"\" || e.Status != 0 {\n\t\treturn e\n\t}\n\treturn nil\n}\n\nfunc (a *chimpAPI) getReports(params reportsParams) (reportsResponse, error) {\n\ta.Lock()\n\tdefer a.Unlock()\n\ta.url.Path = reportsEndpoint\n\n\tvar response reportsResponse\n\trawjson, err := a.runChimp(params)\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\terr = json.Unmarshal(rawjson, &response)\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (a *chimpAPI) getReport(campaignID string) (report, error) {\n\ta.Lock()\n\tdefer a.Unlock()\n\ta.url.Path = fmt.Sprintf(reportsEndpointCampaign, campaignID)\n\n\tvar response report\n\trawjson, err := a.runChimp(reportsParams{})\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\terr = json.Unmarshal(rawjson, &response)\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (a *chimpAPI) runChimp(params reportsParams) ([]byte, error) {\n\tclient := &http.Client{\n\t\tTransport: a.transport,\n\t\tTimeout:   4 * time.Second,\n\t}\n\n\tvar b bytes.Buffer\n\treq, err := http.NewRequest(\"GET\", a.url.String(), &b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.URL.RawQuery = params.String()\n\treq.Header.Set(\"User-Agent\", \"Telegraf-MailChimp-Plugin\")\n\tif a.debug {\n\t\ta.log.Debugf(\"request URL: %s\", req.URL.String())\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 200))\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s: %q\", a.url.String(), resp.Status, body)\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif a.debug {\n\t\ta.log.Debugf(\"response Body: %q\", string(body))\n\t}\n\n\tif err := chimpErrorCheck(body); err != nil {\n\t\treturn nil, err\n\t}\n\treturn body, nil\n}\n\ntype reportsResponse struct {\n\tReports    []report `json:\"reports\"`\n\tTotalItems int      `json:\"total_items\"`\n}\n\ntype report struct {\n\tID            string `json:\"id\"`\n\tCampaignTitle string `json:\"campaign_title\"`\n\tType          string `json:\"type\"`\n\tEmailsSent    int    `json:\"emails_sent\"`\n\tAbuseReports  int    `json:\"abuse_reports\"`\n\tUnsubscribed  int    `json:\"unsubscribed\"`\n\tSendTime      string `json:\"send_time\"`\n\n\tTimeSeries    []timeSeries\n\tBounces       bounces       `json:\"bounces\"`\n\tForwards      forwards      `json:\"forwards\"`\n\tOpens         opens         `json:\"opens\"`\n\tClicks        clicks        `json:\"clicks\"`\n\tFacebookLikes facebookLikes `json:\"facebook_likes\"`\n\tIndustryStats industryStats `json:\"industry_stats\"`\n\tListStats     listStats     `json:\"list_stats\"`\n}\n\ntype bounces struct {\n\tHardBounces  int `json:\"hard_bounces\"`\n\tSoftBounces  int `json:\"soft_bounces\"`\n\tSyntaxErrors int `json:\"syntax_errors\"`\n}\n\ntype forwards struct {\n\tForwardsCount int `json:\"forwards_count\"`\n\tForwardsOpens int `json:\"forwards_opens\"`\n}\n\ntype opens struct {\n\tOpensTotal  int     `json:\"opens_total\"`\n\tUniqueOpens int     `json:\"unique_opens\"`\n\tOpenRate    float64 `json:\"open_rate\"`\n\tLastOpen    string  `json:\"last_open\"`\n}\n\ntype clicks struct {\n\tClicksTotal            int     `json:\"clicks_total\"`\n\tUniqueClicks           int     `json:\"unique_clicks\"`\n\tUniqueSubscriberClicks int     `json:\"unique_subscriber_clicks\"`\n\tClickRate              float64 `json:\"click_rate\"`\n\tLastClick              string  `json:\"last_click\"`\n}\n\ntype facebookLikes struct {\n\tRecipientLikes int `json:\"recipient_likes\"`\n\tUniqueLikes    int `json:\"unique_likes\"`\n\tFacebookLikes  int `json:\"facebook_likes\"`\n}\n\ntype industryStats struct {\n\tType       string  `json:\"type\"`\n\tOpenRate   float64 `json:\"open_rate\"`\n\tClickRate  float64 `json:\"click_rate\"`\n\tBounceRate float64 `json:\"bounce_rate\"`\n\tUnopenRate float64 `json:\"unopen_rate\"`\n\tUnsubRate  float64 `json:\"unsub_rate\"`\n\tAbuseRate  float64 `json:\"abuse_rate\"`\n}\n\ntype listStats struct {\n\tSubRate   float64 `json:\"sub_rate\"`\n\tUnsubRate float64 `json:\"unsub_rate\"`\n\tOpenRate  float64 `json:\"open_rate\"`\n\tClickRate float64 `json:\"click_rate\"`\n}\n\ntype timeSeries struct {\n\tTimeStamp       string `json:\"timestamp\"`\n\tEmailsSent      int    `json:\"emails_sent\"`\n\tUniqueOpens     int    `json:\"unique_opens\"`\n\tRecipientsClick int    `json:\"recipients_click\"`\n}\n"
  },
  {
    "path": "plugins/inputs/mailchimp/mailchimp.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mailchimp\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype MailChimp struct {\n\tAPIKey     string          `toml:\"api_key\"`\n\tDaysOld    int             `toml:\"days_old\"`\n\tCampaignID string          `toml:\"campaign_id\"`\n\tLog        telegraf.Logger `toml:\"-\"`\n\n\tapi *chimpAPI\n}\n\nfunc (*MailChimp) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *MailChimp) Init() error {\n\tm.api = newChimpAPI(m.APIKey, m.Log)\n\n\treturn nil\n}\n\nfunc (m *MailChimp) Gather(acc telegraf.Accumulator) error {\n\tif m.CampaignID == \"\" {\n\t\tsince := \"\"\n\t\tif m.DaysOld > 0 {\n\t\t\tnow := time.Now()\n\t\t\td, err := time.ParseDuration(fmt.Sprintf(\"%dh\", 24*m.DaysOld))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tsince = now.Add(-d).Format(time.RFC3339)\n\t\t}\n\n\t\treports, err := m.api.getReports(reportsParams{\n\t\t\tsinceSendTime: since,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnow := time.Now()\n\n\t\tfor _, report := range reports.Reports {\n\t\t\tgatherReport(acc, report, now)\n\t\t}\n\t} else {\n\t\treport, err := m.api.getReport(m.CampaignID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnow := time.Now()\n\t\tgatherReport(acc, report, now)\n\t}\n\n\treturn nil\n}\n\nfunc gatherReport(acc telegraf.Accumulator, report report, now time.Time) {\n\ttags := make(map[string]string)\n\ttags[\"id\"] = report.ID\n\ttags[\"campaign_title\"] = report.CampaignTitle\n\tfields := map[string]interface{}{\n\t\t\"emails_sent\":              report.EmailsSent,\n\t\t\"abuse_reports\":            report.AbuseReports,\n\t\t\"unsubscribed\":             report.Unsubscribed,\n\t\t\"hard_bounces\":             report.Bounces.HardBounces,\n\t\t\"soft_bounces\":             report.Bounces.SoftBounces,\n\t\t\"syntax_errors\":            report.Bounces.SyntaxErrors,\n\t\t\"forwards_count\":           report.Forwards.ForwardsCount,\n\t\t\"forwards_opens\":           report.Forwards.ForwardsOpens,\n\t\t\"opens_total\":              report.Opens.OpensTotal,\n\t\t\"unique_opens\":             report.Opens.UniqueOpens,\n\t\t\"open_rate\":                report.Opens.OpenRate,\n\t\t\"clicks_total\":             report.Clicks.ClicksTotal,\n\t\t\"unique_clicks\":            report.Clicks.UniqueClicks,\n\t\t\"unique_subscriber_clicks\": report.Clicks.UniqueSubscriberClicks,\n\t\t\"click_rate\":               report.Clicks.ClickRate,\n\t\t\"facebook_recipient_likes\": report.FacebookLikes.RecipientLikes,\n\t\t\"facebook_unique_likes\":    report.FacebookLikes.UniqueLikes,\n\t\t\"facebook_likes\":           report.FacebookLikes.FacebookLikes,\n\t\t\"industry_type\":            report.IndustryStats.Type,\n\t\t\"industry_open_rate\":       report.IndustryStats.OpenRate,\n\t\t\"industry_click_rate\":      report.IndustryStats.ClickRate,\n\t\t\"industry_bounce_rate\":     report.IndustryStats.BounceRate,\n\t\t\"industry_unopen_rate\":     report.IndustryStats.UnopenRate,\n\t\t\"industry_unsub_rate\":      report.IndustryStats.UnsubRate,\n\t\t\"industry_abuse_rate\":      report.IndustryStats.AbuseRate,\n\t\t\"list_stats_sub_rate\":      report.ListStats.SubRate,\n\t\t\"list_stats_unsub_rate\":    report.ListStats.UnsubRate,\n\t\t\"list_stats_open_rate\":     report.ListStats.OpenRate,\n\t\t\"list_stats_click_rate\":    report.ListStats.ClickRate,\n\t}\n\tacc.AddFields(\"mailchimp\", fields, tags, now)\n}\n\nfunc init() {\n\tinputs.Add(\"mailchimp\", func() telegraf.Input {\n\t\treturn &MailChimp{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mailchimp/mailchimp_test.go",
    "content": "package mailchimp\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMailChimpGatherReports(t *testing.T) {\n\tts := httptest.NewServer(\n\t\thttp.HandlerFunc(\n\t\t\tfunc(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := fmt.Fprintln(w, sampleReports); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t},\n\t\t))\n\tdefer ts.Close()\n\n\tu, err := url.ParseRequestURI(ts.URL)\n\trequire.NoError(t, err)\n\n\tapi := &chimpAPI{\n\t\turl:   u,\n\t\tdebug: true,\n\t\tlog:   testutil.Logger{},\n\t}\n\tm := MailChimp{\n\t\tapi: api,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = m.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags := make(map[string]string)\n\ttags[\"id\"] = \"42694e9e57\"\n\ttags[\"campaign_title\"] = \"Freddie's Jokes Vol. 1\"\n\n\tfields := map[string]interface{}{\n\t\t\"emails_sent\":              200,\n\t\t\"abuse_reports\":            0,\n\t\t\"unsubscribed\":             2,\n\t\t\"hard_bounces\":             0,\n\t\t\"soft_bounces\":             2,\n\t\t\"syntax_errors\":            0,\n\t\t\"forwards_count\":           0,\n\t\t\"forwards_opens\":           0,\n\t\t\"opens_total\":              186,\n\t\t\"unique_opens\":             100,\n\t\t\"clicks_total\":             42,\n\t\t\"unique_clicks\":            400,\n\t\t\"unique_subscriber_clicks\": 42,\n\t\t\"facebook_recipient_likes\": 5,\n\t\t\"facebook_unique_likes\":    8,\n\t\t\"facebook_likes\":           42,\n\t\t\"open_rate\":                float64(42),\n\t\t\"click_rate\":               float64(42),\n\t\t\"industry_open_rate\":       float64(0.17076777144396),\n\t\t\"industry_click_rate\":      float64(0.027431311866951),\n\t\t\"industry_bounce_rate\":     float64(0.0063767751251474),\n\t\t\"industry_unopen_rate\":     float64(0.82285545343089),\n\t\t\"industry_unsub_rate\":      float64(0.001436957032815),\n\t\t\"industry_abuse_rate\":      float64(0.00021111996110887),\n\t\t\"list_stats_sub_rate\":      float64(10),\n\t\t\"list_stats_unsub_rate\":    float64(20),\n\t\t\"list_stats_open_rate\":     float64(42),\n\t\t\"list_stats_click_rate\":    float64(42),\n\t\t\"industry_type\":            \"Social Networks and Online Communities\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"mailchimp\", fields, tags)\n}\n\nfunc TestMailChimpGatherReport(t *testing.T) {\n\tts := httptest.NewServer(\n\t\thttp.HandlerFunc(\n\t\t\tfunc(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := fmt.Fprintln(w, sampleReport); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t},\n\t\t))\n\tdefer ts.Close()\n\n\tu, err := url.ParseRequestURI(ts.URL)\n\trequire.NoError(t, err)\n\n\tapi := &chimpAPI{\n\t\turl:   u,\n\t\tdebug: true,\n\t\tlog:   testutil.Logger{},\n\t}\n\tm := MailChimp{\n\t\tapi:        api,\n\t\tCampaignID: \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = m.Gather(&acc)\n\trequire.NoError(t, err)\n\n\ttags := make(map[string]string)\n\ttags[\"id\"] = \"42694e9e57\"\n\ttags[\"campaign_title\"] = \"Freddie's Jokes Vol. 1\"\n\n\tfields := map[string]interface{}{\n\t\t\"emails_sent\":              int(200),\n\t\t\"abuse_reports\":            int(0),\n\t\t\"unsubscribed\":             int(2),\n\t\t\"hard_bounces\":             int(0),\n\t\t\"soft_bounces\":             int(2),\n\t\t\"syntax_errors\":            int(0),\n\t\t\"forwards_count\":           int(0),\n\t\t\"forwards_opens\":           int(0),\n\t\t\"opens_total\":              int(186),\n\t\t\"unique_opens\":             int(100),\n\t\t\"clicks_total\":             int(42),\n\t\t\"unique_clicks\":            int(400),\n\t\t\"unique_subscriber_clicks\": int(42),\n\t\t\"facebook_recipient_likes\": int(5),\n\t\t\"facebook_unique_likes\":    int(8),\n\t\t\"facebook_likes\":           int(42),\n\t\t\"open_rate\":                float64(42),\n\t\t\"click_rate\":               float64(42),\n\t\t\"industry_open_rate\":       float64(0.17076777144396),\n\t\t\"industry_click_rate\":      float64(0.027431311866951),\n\t\t\"industry_bounce_rate\":     float64(0.0063767751251474),\n\t\t\"industry_unopen_rate\":     float64(0.82285545343089),\n\t\t\"industry_unsub_rate\":      float64(0.001436957032815),\n\t\t\"industry_abuse_rate\":      float64(0.00021111996110887),\n\t\t\"list_stats_sub_rate\":      float64(10),\n\t\t\"list_stats_unsub_rate\":    float64(20),\n\t\t\"list_stats_open_rate\":     float64(42),\n\t\t\"list_stats_click_rate\":    float64(42),\n\t\t\"industry_type\":            \"Social Networks and Online Communities\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"mailchimp\", fields, tags)\n}\n\nfunc TestMailChimpGatherError(t *testing.T) {\n\tts := httptest.NewServer(\n\t\thttp.HandlerFunc(\n\t\t\tfunc(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\tif _, err := fmt.Fprintln(w, sampleError); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t},\n\t\t))\n\tdefer ts.Close()\n\n\tu, err := url.ParseRequestURI(ts.URL)\n\trequire.NoError(t, err)\n\n\tapi := &chimpAPI{\n\t\turl:   u,\n\t\tdebug: true,\n\t\tlog:   testutil.Logger{},\n\t}\n\tm := MailChimp{\n\t\tapi:        api,\n\t\tCampaignID: \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = m.Gather(&acc)\n\trequire.Error(t, err)\n}\n\nvar sampleReports = `\n{\n  \"reports\": [\n    {\n      \"id\": \"42694e9e57\",\n      \"campaign_title\": \"Freddie's Jokes Vol. 1\",\n      \"type\": \"regular\",\n      \"emails_sent\": 200,\n      \"abuse_reports\": 0,\n      \"unsubscribed\": 2,\n      \"send_time\": \"2015-09-15T19:05:51+00:00\",\n      \"bounces\": {\n        \"hard_bounces\": 0,\n        \"soft_bounces\": 2,\n        \"syntax_errors\": 0\n      },\n      \"forwards\": {\n        \"forwards_count\": 0,\n        \"forwards_opens\": 0\n      },\n      \"opens\": {\n        \"opens_total\": 186,\n        \"unique_opens\": 100,\n        \"open_rate\": 42,\n        \"last_open\": \"2015-09-15T19:15:47+00:00\"\n      },\n      \"clicks\": {\n        \"clicks_total\": 42,\n        \"unique_clicks\": 400,\n        \"unique_subscriber_clicks\": 42,\n        \"click_rate\": 42,\n        \"last_click\": \"2015-09-15T19:15:47+00:00\"\n      },\n      \"facebook_likes\": {\n        \"recipient_likes\": 5,\n        \"unique_likes\": 8,\n        \"facebook_likes\": 42\n      },\n      \"industry_stats\": {\n        \"type\": \"Social Networks and Online Communities\",\n        \"open_rate\": 0.17076777144396,\n        \"click_rate\": 0.027431311866951,\n        \"bounce_rate\": 0.0063767751251474,\n        \"unopen_rate\": 0.82285545343089,\n        \"unsub_rate\": 0.001436957032815,\n        \"abuse_rate\": 0.00021111996110887\n      },\n      \"list_stats\": {\n        \"sub_rate\": 10,\n        \"unsub_rate\": 20,\n        \"open_rate\": 42,\n        \"click_rate\": 42\n      },\n      \"timeseries\": [\n        {\n          \"timestamp\": \"2015-09-15T19:00:00+00:00\",\n          \"emails_sent\": 198,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-15T20:00:00+00:00\",\n          \"emails_sent\": 2,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-15T21:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-15T22:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-15T23:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T00:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T01:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T02:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T03:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T04:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T05:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T06:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T07:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T08:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T09:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T10:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T11:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T12:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T13:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T14:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T15:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T16:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T17:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        },\n        {\n          \"timestamp\": \"2015-09-16T18:00:00+00:00\",\n          \"emails_sent\": 0,\n          \"unique_opens\": 0,\n          \"recipients_clicks\": 0\n        }\n      ],\n      \"share_report\": {\n        \"share_url\": \"http://usX.vip-reports.net/reports/summary?u=xxxx&id=xxxx\",\n        \"share_password\": \"freddielikesjokes\"\n      },\n      \"delivery_status\": {\n        \"enabled\": false\n      },\n      \"_links\": [\n        {\n          \"rel\": \"parent\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Collection.json\",\n          \"schema\": \"https://api.mailchimp.com/schema/3.0/CollectionLinks/Reports.json\"\n        },\n        {\n          \"rel\": \"self\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Instance.json\"\n        },\n        {\n          \"rel\": \"campaign\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/campaigns/42694e9e57\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Campaigns/Instance.json\"\n        },\n        {\n          \"rel\": \"sub-reports\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/sub-reports\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Sub/Collection.json\"\n        },\n        {\n          \"rel\": \"abuse-reports\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/abuse-reports\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Abuse/Collection.json\"\n        },\n        {\n          \"rel\": \"advice\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/advice\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Advice/Collection.json\"\n        },\n        {\n          \"rel\": \"click-details\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/click-details\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/ClickDetails/Collection.json\"\n        },\n        {\n          \"rel\": \"domain-performance\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/domain-performance\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/DomainPerformance/Collection.json\"\n        },\n        {\n          \"rel\": \"eepurl\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/eepurl\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Eepurl/Collection.json\"\n        },\n        {\n          \"rel\": \"email-activity\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/email-activity\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/EmailActivity/Collection.json\"\n        },\n        {\n          \"rel\": \"locations\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/locations\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Locations/Collection.json\"\n        },\n        {\n          \"rel\": \"sent-to\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/sent-to\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/SentTo/Collection.json\"\n        },\n        {\n          \"rel\": \"unsubscribed\",\n          \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/unsubscribed\",\n          \"method\": \"GET\",\n          \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Unsubs/Collection.json\"\n        }\n      ]\n    }\n  ],\n  \"_links\": [\n    {\n      \"rel\": \"parent\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Root.json\"\n    },\n    {\n      \"rel\": \"self\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Collection.json\",\n      \"schema\": \"https://api.mailchimp.com/schema/3.0/CollectionLinks/Reports.json\"\n    }\n  ],\n  \"total_items\": 1\n}\n`\n\nvar sampleReport = `\n{\n  \"id\": \"42694e9e57\",\n  \"campaign_title\": \"Freddie's Jokes Vol. 1\",\n  \"type\": \"regular\",\n  \"emails_sent\": 200,\n  \"abuse_reports\": 0,\n  \"unsubscribed\": 2,\n  \"send_time\": \"2015-09-15T19:05:51+00:00\",\n  \"bounces\": {\n    \"hard_bounces\": 0,\n    \"soft_bounces\": 2,\n    \"syntax_errors\": 0\n  },\n  \"forwards\": {\n    \"forwards_count\": 0,\n    \"forwards_opens\": 0\n  },\n  \"opens\": {\n    \"opens_total\": 186,\n    \"unique_opens\": 100,\n    \"open_rate\": 42,\n    \"last_open\": \"2015-09-15T19:15:47+00:00\"\n  },\n  \"clicks\": {\n    \"clicks_total\": 42,\n    \"unique_clicks\": 400,\n    \"unique_subscriber_clicks\": 42,\n    \"click_rate\": 42,\n    \"last_click\": \"2015-09-15T19:15:47+00:00\"\n  },\n  \"facebook_likes\": {\n    \"recipient_likes\": 5,\n    \"unique_likes\": 8,\n    \"facebook_likes\": 42\n  },\n  \"industry_stats\": {\n    \"type\": \"Social Networks and Online Communities\",\n    \"open_rate\": 0.17076777144396,\n    \"click_rate\": 0.027431311866951,\n    \"bounce_rate\": 0.0063767751251474,\n    \"unopen_rate\": 0.82285545343089,\n    \"unsub_rate\": 0.001436957032815,\n    \"abuse_rate\": 0.00021111996110887\n  },\n  \"list_stats\": {\n    \"sub_rate\": 10,\n    \"unsub_rate\": 20,\n    \"open_rate\": 42,\n    \"click_rate\": 42\n  },\n  \"timeseries\": [\n    {\n      \"timestamp\": \"2015-09-15T19:00:00+00:00\",\n      \"emails_sent\": 198,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-15T20:00:00+00:00\",\n      \"emails_sent\": 2,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-15T21:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-15T22:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-15T23:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T00:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T01:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T02:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T03:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T04:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T05:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T06:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T07:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T08:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T09:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T10:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T11:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T12:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T13:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T14:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T15:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T16:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T17:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    },\n    {\n      \"timestamp\": \"2015-09-16T18:00:00+00:00\",\n      \"emails_sent\": 0,\n      \"unique_opens\": 0,\n      \"recipients_clicks\": 0\n    }\n  ],\n  \"share_report\": {\n    \"share_url\": \"http://usX.vip-reports.net/reports/summary?u=xxxx&id=xxxx\",\n    \"share_password\": \"freddielikesjokes\"\n  },\n  \"delivery_status\": {\n    \"enabled\": false\n  },\n  \"_links\": [\n    {\n      \"rel\": \"parent\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Collection.json\",\n      \"schema\": \"https://api.mailchimp.com/schema/3.0/CollectionLinks/Reports.json\"\n    },\n    {\n      \"rel\": \"self\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Instance.json\"\n    },\n    {\n      \"rel\": \"campaign\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/campaigns/42694e9e57\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Campaigns/Instance.json\"\n    },\n    {\n      \"rel\": \"sub-reports\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/sub-reports\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Sub/Collection.json\"\n    },\n    {\n      \"rel\": \"abuse-reports\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/abuse-reports\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Abuse/Collection.json\"\n    },\n    {\n      \"rel\": \"advice\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/advice\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Advice/Collection.json\"\n    },\n    {\n      \"rel\": \"click-details\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/click-details\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/ClickDetails/Collection.json\"\n    },\n    {\n      \"rel\": \"domain-performance\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/domain-performance\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/DomainPerformance/Collection.json\"\n    },\n    {\n      \"rel\": \"eepurl\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/eepurl\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Eepurl/Collection.json\"\n    },\n    {\n      \"rel\": \"email-activity\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/email-activity\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/EmailActivity/Collection.json\"\n    },\n    {\n      \"rel\": \"locations\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/locations\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Locations/Collection.json\"\n    },\n    {\n      \"rel\": \"sent-to\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/sent-to\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/SentTo/Collection.json\"\n    },\n    {\n      \"rel\": \"unsubscribed\",\n      \"href\": \"https://usX.api.mailchimp.com/3.0/reports/42694e9e57/unsubscribed\",\n      \"method\": \"GET\",\n      \"targetSchema\": \"https://api.mailchimp.com/schema/3.0/Reports/Unsubs/Collection.json\"\n    }\n  ]\n}\n`\n\nvar sampleError = `\n{\n    \"type\": \"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/\",\n    \"title\": \"API Key Invalid\",\n    \"status\": 401,\n    \"detail\": \"Your API key may be invalid, or you've attempted to access the wrong datacenter.\",\n    \"instance\": \"\"\n}\n`\n"
  },
  {
    "path": "plugins/inputs/mailchimp/sample.conf",
    "content": "# Gathers metrics from the /3.0/reports MailChimp API\n[[inputs.mailchimp]]\n  ## MailChimp API key\n  ## get from https://admin.mailchimp.com/account/api/\n  api_key = \"\" # required\n\n  ## Reports for campaigns sent more than days_old ago will not be collected.\n  ## 0 means collect all and is the default value.\n  days_old = 0\n\n  ## Campaign ID to get, if empty gets all campaigns, this option overrides days_old\n  # campaign_id = \"\"\n"
  },
  {
    "path": "plugins/inputs/marklogic/README.md",
    "content": "# MarkLogic Input Plugin\n\nThis plugin gathers health status metrics from one or more [MarkLogic][marklogic]\nhosts.\n\n⭐ Telegraf v1.12.0\n🏷️ server\n💻 all\n\n[marklogic]: https://www.progress.com/marklogic\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Retrieves information on a specific host in a MarkLogic Cluster\n[[inputs.marklogic]]\n  ## Base URL of the MarkLogic HTTP Server.\n  url = \"http://localhost:8002\"\n\n  ## List of specific hostnames to retrieve information. At least (1) required.\n  # hosts = [\"hostname1\", \"hostname2\"]\n\n  ## Using HTTP Basic Authentication. Management API requires 'manage-user' role privileges\n  # username = \"myuser\"\n  # password = \"mypassword\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- marklogic\n  - tags:\n    - source (the hostname of the server address, ex. `ml1.local`)\n    - id (the host node unique id ex. `2592913110757471141`)\n  - fields:\n    - online\n    - total_load\n    - total_rate\n    - ncpus\n    - ncores\n    - total_cpu_stat_user\n    - total_cpu_stat_system\n    - total_cpu_stat_idle\n    - total_cpu_stat_iowait\n    - memory_process_size\n    - memory_process_rss\n    - memory_system_total\n    - memory_system_free\n    - memory_process_swap_size\n    - memory_size\n    - host_size\n    - log_device_space\n    - data_dir_space\n    - query_read_bytes\n    - query_read_load\n    - merge_read_bytes\n    - merge_write_load\n    - http_server_receive_bytes\n    - http_server_send_bytes\n\n## Example Output\n\n```text\nmarklogic,host=localhost,id=2592913110757471141,source=ml1.local total_cpu_stat_iowait=0.0125649003311992,memory_process_swap_size=0i,host_size=380i,data_dir_space=28216i,query_read_load=0i,ncpus=1i,log_device_space=28216i,query_read_bytes=13947332i,merge_write_load=0i,http_server_receive_bytes=225893i,online=true,ncores=4i,total_cpu_stat_user=0.150778993964195,total_cpu_stat_system=0.598927974700928,total_cpu_stat_idle=99.2210006713867,memory_system_total=3947i,memory_system_free=2669i,memory_size=4096i,total_rate=14.7697010040283,http_server_send_bytes=0i,memory_process_size=903i,memory_process_rss=486i,merge_read_load=0i,total_load=0.00502600101754069 1566373000000000000\n```\n"
  },
  {
    "path": "plugins/inputs/marklogic/marklogic.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage marklogic\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// MarkLogic v2 management api endpoints for hosts status\n\tstatsPath  = \"/manage/v2/hosts/\"\n\tviewFormat = \"view=status&format=json\"\n)\n\ntype Marklogic struct {\n\tURL      string   `toml:\"url\"`\n\tHosts    []string `toml:\"hosts\"`\n\tUsername string   `toml:\"username\"`\n\tPassword string   `toml:\"password\"`\n\ttls.ClientConfig\n\n\tclient  *http.Client\n\tsources []string\n}\n\ntype mlPointInt struct {\n\tValue int `json:\"value\"`\n}\n\ntype mlPointFloat struct {\n\tValue float64 `json:\"value\"`\n}\n\ntype mlPointBool struct {\n\tValue bool `json:\"value\"`\n}\n\ntype mlHost struct {\n\tHostStatus struct {\n\t\tID               string `json:\"id\"`\n\t\tName             string `json:\"name\"`\n\t\tStatusProperties struct {\n\t\t\tOnline         mlPointBool `json:\"online\"`\n\t\t\tLoadProperties struct {\n\t\t\t\tTotalLoad mlPointFloat `json:\"total-load\"`\n\t\t\t} `json:\"load-properties\"`\n\t\t\tRateProperties struct {\n\t\t\t\tTotalRate mlPointFloat `json:\"total-rate\"`\n\t\t\t} `json:\"rate-properties\"`\n\t\t\tStatusDetail struct {\n\t\t\t\tCpus                   mlPointInt `json:\"cpus\"`\n\t\t\t\tCores                  mlPointInt `json:\"cores\"`\n\t\t\t\tTotalCPUStatUser       float64    `json:\"total-cpu-stat-user\"`\n\t\t\t\tTotalCPUStatSystem     float64    `json:\"total-cpu-stat-system\"`\n\t\t\t\tTotalCPUStatIdle       float64    `json:\"total-cpu-stat-idle\"`\n\t\t\t\tTotalCPUStatIowait     float64    `json:\"total-cpu-stat-iowait\"`\n\t\t\t\tMemoryProcessSize      mlPointInt `json:\"memory-process-size\"`\n\t\t\t\tMemoryProcessRss       mlPointInt `json:\"memory-process-rss\"`\n\t\t\t\tMemorySystemTotal      mlPointInt `json:\"memory-system-total\"`\n\t\t\t\tMemorySystemFree       mlPointInt `json:\"memory-system-free\"`\n\t\t\t\tMemoryProcessSwapSize  mlPointInt `json:\"memory-process-swap-size\"`\n\t\t\t\tMemorySize             mlPointInt `json:\"memory-size\"`\n\t\t\t\tHostSize               mlPointInt `json:\"host-size\"`\n\t\t\t\tLogDeviceSpace         mlPointInt `json:\"log-device-space\"`\n\t\t\t\tDataDirSpace           mlPointInt `json:\"data-dir-space\"`\n\t\t\t\tQueryReadBytes         mlPointInt `json:\"query-read-bytes\"`\n\t\t\t\tQueryReadLoad          mlPointInt `json:\"query-read-load\"`\n\t\t\t\tMergeReadLoad          mlPointInt `json:\"merge-read-load\"`\n\t\t\t\tMergeWriteLoad         mlPointInt `json:\"merge-write-load\"`\n\t\t\t\tHTTPServerReceiveBytes mlPointInt `json:\"http-server-receive-bytes\"`\n\t\t\t\tHTTPServerSendBytes    mlPointInt `json:\"http-server-send-bytes\"`\n\t\t\t} `json:\"status-detail\"`\n\t\t} `json:\"status-properties\"`\n\t} `json:\"host-status\"`\n}\n\nfunc (*Marklogic) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (c *Marklogic) Init() error {\n\tif len(c.URL) == 0 {\n\t\tc.URL = \"http://localhost:8002/\"\n\t}\n\n\tfor _, u := range c.Hosts {\n\t\tbase, err := url.Parse(c.URL)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbase.Path = path.Join(base.Path, statsPath, u)\n\t\taddr := base.ResolveReference(base)\n\n\t\taddr.RawQuery = viewFormat\n\t\tu := addr.String()\n\t\tc.sources = append(c.sources, u)\n\t}\n\treturn nil\n}\n\nfunc (c *Marklogic) Gather(accumulator telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tif c.client == nil {\n\t\tclient, err := c.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc.client = client\n\t}\n\n\t// Range over all source URL's appended to the struct\n\tfor _, serv := range c.sources {\n\t\twg.Add(1)\n\t\tgo func(serv string) {\n\t\t\tdefer wg.Done()\n\t\t\tif err := c.fetchAndInsertData(accumulator, serv); err != nil {\n\t\t\t\taccumulator.AddError(fmt.Errorf(\"[host=%s]: %w\", serv, err))\n\t\t\t}\n\t\t}(serv)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (c *Marklogic) fetchAndInsertData(acc telegraf.Accumulator, address string) error {\n\tml := &mlHost{}\n\tif err := c.gatherJSONData(address, ml); err != nil {\n\t\treturn err\n\t}\n\n\t// Build a map of tags\n\ttags := map[string]string{\n\t\t\"source\": ml.HostStatus.Name,\n\t\t\"id\":     ml.HostStatus.ID,\n\t}\n\n\t// Build a map of field values\n\tfields := map[string]interface{}{\n\t\t\"online\":                    ml.HostStatus.StatusProperties.Online.Value,\n\t\t\"total_load\":                ml.HostStatus.StatusProperties.LoadProperties.TotalLoad.Value,\n\t\t\"total_rate\":                ml.HostStatus.StatusProperties.RateProperties.TotalRate.Value,\n\t\t\"ncpus\":                     ml.HostStatus.StatusProperties.StatusDetail.Cpus.Value,\n\t\t\"ncores\":                    ml.HostStatus.StatusProperties.StatusDetail.Cores.Value,\n\t\t\"total_cpu_stat_user\":       ml.HostStatus.StatusProperties.StatusDetail.TotalCPUStatUser,\n\t\t\"total_cpu_stat_system\":     ml.HostStatus.StatusProperties.StatusDetail.TotalCPUStatSystem,\n\t\t\"total_cpu_stat_idle\":       ml.HostStatus.StatusProperties.StatusDetail.TotalCPUStatIdle,\n\t\t\"total_cpu_stat_iowait\":     ml.HostStatus.StatusProperties.StatusDetail.TotalCPUStatIowait,\n\t\t\"memory_process_size\":       ml.HostStatus.StatusProperties.StatusDetail.MemoryProcessSize.Value,\n\t\t\"memory_process_rss\":        ml.HostStatus.StatusProperties.StatusDetail.MemoryProcessRss.Value,\n\t\t\"memory_system_total\":       ml.HostStatus.StatusProperties.StatusDetail.MemorySystemTotal.Value,\n\t\t\"memory_system_free\":        ml.HostStatus.StatusProperties.StatusDetail.MemorySystemFree.Value,\n\t\t\"memory_process_swap_size\":  ml.HostStatus.StatusProperties.StatusDetail.MemoryProcessSwapSize.Value,\n\t\t\"memory_size\":               ml.HostStatus.StatusProperties.StatusDetail.MemorySize.Value,\n\t\t\"host_size\":                 ml.HostStatus.StatusProperties.StatusDetail.HostSize.Value,\n\t\t\"log_device_space\":          ml.HostStatus.StatusProperties.StatusDetail.LogDeviceSpace.Value,\n\t\t\"data_dir_space\":            ml.HostStatus.StatusProperties.StatusDetail.DataDirSpace.Value,\n\t\t\"query_read_bytes\":          ml.HostStatus.StatusProperties.StatusDetail.QueryReadBytes.Value,\n\t\t\"query_read_load\":           ml.HostStatus.StatusProperties.StatusDetail.QueryReadLoad.Value,\n\t\t\"merge_read_load\":           ml.HostStatus.StatusProperties.StatusDetail.MergeReadLoad.Value,\n\t\t\"merge_write_load\":          ml.HostStatus.StatusProperties.StatusDetail.MergeWriteLoad.Value,\n\t\t\"http_server_receive_bytes\": ml.HostStatus.StatusProperties.StatusDetail.HTTPServerReceiveBytes.Value,\n\t\t\"http_server_send_bytes\":    ml.HostStatus.StatusProperties.StatusDetail.HTTPServerSendBytes.Value,\n\t}\n\n\t// Accumulate the tags and values\n\tacc.AddFields(\"marklogic\", fields, tags)\n\n\treturn nil\n}\n\nfunc (c *Marklogic) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := c.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: 5 * time.Second,\n\t}\n\n\treturn client, nil\n}\n\nfunc (c *Marklogic) gatherJSONData(address string, v interface{}) error {\n\treq, err := http.NewRequest(\"GET\", address, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif c.Username != \"\" || c.Password != \"\" {\n\t\treq.SetBasicAuth(c.Username, c.Password)\n\t}\n\n\tresponse, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer response.Body.Close()\n\tif response.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"marklogic: API responded with status-code %d, expected %d\",\n\t\t\tresponse.StatusCode, http.StatusOK)\n\t}\n\n\treturn json.NewDecoder(response.Body).Decode(v)\n}\n\nfunc init() {\n\tinputs.Add(\"marklogic\", func() telegraf.Input {\n\t\treturn &Marklogic{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/marklogic/marklogic_test.go",
    "content": "package marklogic\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMarklogic(t *testing.T) {\n\t// Create a test server with the const response JSON\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif _, err := fmt.Fprintln(w, response); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Parse the URL of the test server, used to verify the expected host\n\t_, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\t// Create a new Marklogic instance with our given test server\n\n\tml := &Marklogic{\n\t\tHosts: []string{\"example1\"},\n\t\tURL:   ts.URL,\n\t\t// sources: []string{\"http://localhost:8002/manage/v2/hosts/hostname1?view=status&format=json\"},\n\t}\n\n\t// Create a test accumulator\n\tacc := &testutil.Accumulator{}\n\n\t// Init() call to parse all source URL's\n\terr = ml.Init()\n\trequire.NoError(t, err)\n\n\t// Gather data from the test server\n\terr = ml.Gather(acc)\n\trequire.NoError(t, err)\n\n\t// Expect the correct values for all known keys\n\texpectFields := map[string]interface{}{\n\t\t\"online\":                    true,\n\t\t\"total_load\":                0.00429263804107904,\n\t\t\"ncpus\":                     1,\n\t\t\"ncores\":                    4,\n\t\t\"total_rate\":                15.6527042388916,\n\t\t\"total_cpu_stat_user\":       0.276381999254227,\n\t\t\"total_cpu_stat_system\":     0.636515974998474,\n\t\t\"total_cpu_stat_idle\":       99.0578002929688,\n\t\t\"total_cpu_stat_iowait\":     0.0125628001987934,\n\t\t\"memory_process_size\":       1234,\n\t\t\"memory_process_rss\":        815,\n\t\t\"memory_system_total\":       3947,\n\t\t\"memory_system_free\":        2761,\n\t\t\"memory_process_swap_size\":  0,\n\t\t\"memory_size\":               4096,\n\t\t\"host_size\":                 64,\n\t\t\"log_device_space\":          34968,\n\t\t\"data_dir_space\":            34968,\n\t\t\"query_read_bytes\":          11492428,\n\t\t\"query_read_load\":           0,\n\t\t\"merge_read_load\":           0,\n\t\t\"merge_write_load\":          0,\n\t\t\"http_server_receive_bytes\": 285915,\n\t\t\"http_server_send_bytes\":    0,\n\t}\n\t// Expect the correct values for all tags\n\texpectTags := map[string]string{\n\t\t\"source\": \"ml1.local\",\n\t\t\"id\":     \"2592913110757471141\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"marklogic\", expectFields, expectTags)\n}\n\nvar response = `\n{\n  \"host-status\": {\n    \"id\": \"2592913110757471141\",\n    \"name\": \"ml1.local\",\n    \"version\": \"10.0-1\",\n    \"effective-version\": 10000100,\n    \"host-mode\": \"normal\",\n    \"host-mode-description\": \"\",\n    \"meta\": {\n      \"uri\": \"/manage/v2/hosts/ml1.local?view=status\",\n      \"current-time\": \"2019-07-28T22:32:19.056203Z\",\n      \"elapsed-time\": {\n        \"units\": \"sec\",\n        \"value\": 0.013035\n      }\n    },\n    \"relations\": {\n      \"relation-group\": [\n        {\n          \"uriref\": \"/manage/v2/forests?view=status&host-id=ml1.local\",\n          \"typeref\": \"forests\",\n          \"relation\": [\n            {\n              \"uriref\": \"/manage/v2/forests/App-Services\",\n              \"idref\": \"8573569457346659714\",\n              \"nameref\": \"App-Services\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Documents\",\n              \"idref\": \"17189472171231792168\",\n              \"nameref\": \"Documents\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Extensions\",\n              \"idref\": \"1510244530748962553\",\n              \"nameref\": \"Extensions\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Fab\",\n              \"idref\": \"16221965829238302106\",\n              \"nameref\": \"Fab\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Last-Login\",\n              \"idref\": \"1093671762706318022\",\n              \"nameref\": \"Last-Login\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Meters\",\n              \"idref\": \"1573439446779995954\",\n              \"nameref\": \"Meters\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Modules\",\n              \"idref\": \"18320951141685848719\",\n              \"nameref\": \"Modules\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Schemas\",\n              \"idref\": \"18206720449696085936\",\n              \"nameref\": \"Schemas\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Security\",\n              \"idref\": \"9348728036360382939\",\n              \"nameref\": \"Security\"\n            },\n            {\n              \"uriref\": \"/manage/v2/forests/Triggers\",\n              \"idref\": \"10142793547905338229\",\n              \"nameref\": \"Triggers\"\n            }\n          ]\n        },\n        {\n          \"typeref\": \"groups\",\n          \"relation\": [\n            {\n              \"uriref\": \"/manage/v2/groups/Default?view=status\",\n              \"idref\": \"16808579782544283978\",\n              \"nameref\": \"Default\"\n            }\n          ]\n        }\n      ]\n    },\n    \"status-properties\": {\n      \"online\": {\n        \"units\": \"bool\",\n        \"value\": true\n      },\n      \"secure\": {\n        \"units\": \"bool\",\n        \"value\": false\n      },\n      \"cache-properties\": {\n        \"cache-detail\": {\n          \"compressed-tree-cache-partition\": [\n            {\n              \"partition-size\": 64,\n              \"partition-table\": 3.40000009536743,\n              \"partition-used\": 29.7000007629395,\n              \"partition-free\": 70.1999969482422,\n              \"partition-overhead\": 0.100000001490116\n            }\n          ],\n          \"expanded-tree-cache-partition\": [\n            {\n              \"partition-size\": 128,\n              \"partition-table\": 6.19999980926514,\n              \"partition-busy\": 0,\n              \"partition-used\": 87.3000030517578,\n              \"partition-free\": 12.3999996185303,\n              \"partition-overhead\": 0.300000011920929\n            }\n          ],\n          \"triple-cache-partition\": [\n            {\n              \"partition-size\": 64,\n              \"partition-busy\": 0,\n              \"partition-used\": 0,\n              \"partition-free\": 100\n            }\n          ],\n          \"triple-value-cache-partition\": [\n            {\n              \"partition-size\": 128,\n              \"partition-busy\": 0,\n              \"partition-used\": 0,\n              \"partition-free\": 100,\n              \"value-count\": 0,\n              \"value-bytes-total\": 0,\n              \"value-bytes-average\": 0\n            }\n          ]\n        }\n      },\n      \"load-properties\": {\n        \"total-load\": {\n          \"units\": \"sec/sec\",\n          \"value\": 0.00429263804107904\n        },\n        \"load-detail\": {\n          \"query-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"journal-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"save-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"merge-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"merge-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"backup-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"backup-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"restore-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"restore-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"large-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"large-write-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"external-binary-read-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"xdqp-client-receive-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"xdqp-client-send-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"xdqp-server-receive-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"xdqp-server-send-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-client-receive-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-client-send-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-server-receive-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-server-send-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"read-lock-wait-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"read-lock-hold-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"write-lock-wait-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          },\n          \"write-lock-hold-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0.00429263804107904\n          },\n          \"deadlock-wait-load\": {\n            \"units\": \"sec/sec\",\n            \"value\": 0\n          }\n        }\n      },\n      \"rate-properties\": {\n        \"total-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 15.6527042388916\n        },\n        \"rate-detail\": {\n          \"memory-system-pagein-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"memory-system-pageout-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 15.6420001983643\n          },\n          \"memory-system-swapin-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"memory-system-swapout-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"query-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"journal-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0.00372338597662747\n          },\n          \"save-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0.0024786819703877\n          },\n          \"merge-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"merge-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"backup-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"backup-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"restore-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"restore-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"large-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"large-write-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"external-binary-read-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"xdqp-client-receive-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"xdqp-client-send-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0.00293614692054689\n          },\n          \"xdqp-server-receive-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0.00156576896551996\n          },\n          \"xdqp-server-send-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-client-receive-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-client-send-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-server-receive-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"foreign-xdqp-server-send-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"read-lock-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          },\n          \"write-lock-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0.251882910728455\n          },\n          \"deadlock-rate\": {\n            \"units\": \"MB/sec\",\n            \"value\": 0\n          }\n        }\n      },\n      \"status-detail\": {\n        \"bind-port\": 7999,\n        \"connect-port\": 7999,\n        \"ssl-fips-enabled\": {\n          \"units\": \"bool\",\n          \"value\": true\n        },\n        \"foreign-bind-port\": 7998,\n        \"foreign-connect-port\": 7998,\n        \"background-io-limit\": {\n          \"units\": \"quantity\",\n          \"value\": 0\n        },\n        \"metering-enabled\": {\n          \"units\": \"bool\",\n          \"value\": true\n        },\n        \"meters-database\": {\n          \"units\": \"quantity\",\n          \"value\": \"11952918530142281790\"\n        },\n        \"performance-metering-enabled\": {\n          \"units\": \"bool\",\n          \"value\": true\n        },\n        \"performance-metering-period\": {\n          \"units\": \"second\",\n          \"value\": 60\n        },\n        \"performance-metering-retain-raw\": {\n          \"units\": \"day\",\n          \"value\": 7\n        },\n        \"performance-metering-retain-hourly\": {\n          \"units\": \"day\",\n          \"value\": 30\n        },\n        \"performance-metering-retain-daily\": {\n          \"units\": \"day\",\n          \"value\": 90\n        },\n        \"last-startup\": {\n          \"units\": \"datetime\",\n          \"value\": \"2019-07-26T17:23:36.412644Z\"\n        },\n        \"version\": \"10.0-1\",\n        \"effective-version\": {\n          \"units\": \"quantity\",\n          \"value\": 10000100\n        },\n        \"software-version\": {\n          \"units\": \"quantity\",\n          \"value\": 10000100\n        },\n        \"os-version\": \"NA\",\n        \"converters-version\": \"10.0-1\",\n        \"host-mode\": {\n          \"units\": \"enum\",\n          \"value\": \"normal\"\n        },\n        \"architecture\": \"x86_64\",\n        \"platform\": \"linux\",\n        \"license-key\": \"000-000-000-000-000-000-000\",\n        \"licensee\": \"NA\",\n        \"license-key-expires\": {\n          \"units\": \"datetime\",\n          \"value\": \"2999-01-23T00:00:00Z\"\n        },\n        \"license-key-cpus\": {\n          \"units\": \"quantity\",\n          \"value\": 0\n        },\n        \"license-key-cores\": {\n          \"units\": \"quantity\",\n          \"value\": 0\n        },\n        \"license-key-size\": {\n          \"units\": \"MB\",\n          \"value\": 0\n        },\n        \"license-key-option\": [\n          {\n            \"units\": \"enum\",\n            \"value\": \"conversion\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"failover\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"alerting\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"geospatial\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"flexible replication\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"tiered storage\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"semantics\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"French\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Italian\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"German\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Spanish\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Traditional Chinese\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Simplified Chinese\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Arabic\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Russian\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Dutch\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Korean\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Persian\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Japanese\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"Portuguese\"\n          },\n          {\n            \"units\": \"enum\",\n            \"value\": \"English\"\n          }\n        ],\n        \"edition\": {\n          \"units\": \"enum\",\n          \"value\": \"Enterprise Edition\"\n        },\n        \"environment\": {\n          \"units\": \"enum\",\n          \"value\": \"developer\"\n        },\n        \"cpus\": {\n          \"units\": \"quantity\",\n          \"value\": 1\n        },\n        \"cores\": {\n          \"units\": \"quantity\",\n          \"value\": 4\n        },\n        \"core-threads\": {\n          \"units\": \"quantity\",\n          \"value\": 4\n        },\n        \"total-cpu-stat-user\": 0.276381999254227,\n        \"total-cpu-stat-nice\": 0,\n        \"total-cpu-stat-system\": 0.636515974998474,\n        \"total-cpu-stat-idle\": 99.0578002929688,\n        \"total-cpu-stat-iowait\": 0.0125628001987934,\n        \"total-cpu-stat-irq\": 0,\n        \"total-cpu-stat-softirq\": 0.0167504008859396,\n        \"total-cpu-stat-steal\": 0,\n        \"total-cpu-stat-guest\": 0,\n        \"total-cpu-stat-guest-nice\": 0,\n        \"memory-process-size\": {\n          \"units\": \"fraction\",\n          \"value\": 1234\n        },\n        \"memory-process-rss\": {\n          \"units\": \"fraction\",\n          \"value\": 815\n        },\n        \"memory-process-anon\": {\n          \"units\": \"fraction\",\n          \"value\": 743\n        },\n        \"memory-process-rss-hwm\": {\n          \"units\": \"fraction\",\n          \"value\": 1072\n        },\n        \"memory-process-swap-size\": {\n          \"units\": \"fraction\",\n          \"value\": 0\n        },\n        \"memory-process-huge-pages-size\": {\n          \"units\": \"fraction\",\n          \"value\": 0\n        },\n        \"memory-system-total\": {\n          \"units\": \"fraction\",\n          \"value\": 3947\n        },\n        \"memory-system-free\": {\n          \"units\": \"fraction\",\n          \"value\": 2761\n        },\n        \"memory-system-pagein-rate\": {\n          \"units\": \"fraction\",\n          \"value\": 0\n        },\n        \"memory-system-pageout-rate\": {\n          \"units\": \"fraction\",\n          \"value\": 15.6420001983643\n        },\n        \"memory-system-swapin-rate\": {\n          \"units\": \"fraction\",\n          \"value\": 0\n        },\n        \"memory-system-swapout-rate\": {\n          \"units\": \"fraction\",\n          \"value\": 0\n        },\n        \"memory-size\": {\n          \"units\": \"quantity\",\n          \"value\": 4096\n        },\n        \"memory-file-size\": {\n          \"units\": \"quantity\",\n          \"value\": 5\n        },\n        \"memory-forest-size\": {\n          \"units\": \"quantity\",\n          \"value\": 849\n        },\n        \"memory-unclosed-size\": {\n          \"units\": \"quantity\",\n          \"value\": 0\n        },\n        \"memory-cache-size\": {\n          \"units\": \"quantity\",\n          \"value\": 320\n        },\n        \"memory-registry-size\": {\n          \"units\": \"quantity\",\n          \"value\": 1\n        },\n        \"memory-join-size\": {\n          \"units\": \"quantity\",\n          \"value\": 0\n        },\n        \"host-size\": {\n          \"units\": \"MB\",\n          \"value\": 64\n        },\n        \"host-large-data-size\": {\n          \"units\": \"MB\",\n          \"value\": 0\n        },\n        \"log-device-space\": {\n          \"units\": \"MB\",\n          \"value\": 34968\n        },\n        \"data-dir-space\": {\n          \"units\": \"MB\",\n          \"value\": 34968\n        },\n        \"query-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 11492428\n        },\n        \"query-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0.141471S\"\n        },\n        \"query-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"query-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"journal-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 285717868\n        },\n        \"journal-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT17.300832S\"\n        },\n        \"journal-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0.00372338597662747\n        },\n        \"journal-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"save-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 95818597\n        },\n        \"save-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT2.972855S\"\n        },\n        \"save-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0.0024786819703877\n        },\n        \"save-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"merge-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 55374848\n        },\n        \"merge-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0.535705S\"\n        },\n        \"merge-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"merge-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"merge-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 146451731\n        },\n        \"merge-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT5.392288S\"\n        },\n        \"merge-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"merge-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"backup-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"backup-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"backup-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"backup-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"backup-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"backup-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"backup-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"backup-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"restore-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"restore-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"restore-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"restore-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"restore-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"restore-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"restore-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"restore-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"large-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"large-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"large-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"large-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"large-write-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"large-write-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"large-write-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"large-write-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"external-binary-read-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"external-binary-read-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"external-binary-read-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"external-binary-read-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"webDAV-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"webDAV-server-receive-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"webDAV-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"webDAV-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"webDAV-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"webDAV-server-send-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"webDAV-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"webDAV-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"http-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 285915\n        },\n        \"http-server-receive-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0.02028S\"\n        },\n        \"http-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"http-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"http-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"http-server-send-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"http-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"http-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdbc-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"xdbc-server-receive-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"xdbc-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"xdbc-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdbc-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"xdbc-server-send-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"xdbc-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"xdbc-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"odbc-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"odbc-server-receive-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"odbc-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"odbc-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"odbc-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"odbc-server-send-time\": {\n          \"units\": \"sec\",\n          \"value\": \"PT0S\"\n        },\n        \"odbc-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"odbc-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdqp-client-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 3020032\n        },\n        \"xdqp-client-receive-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0.046612S\"\n        },\n        \"xdqp-client-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"xdqp-client-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdqp-client-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 163513952\n        },\n        \"xdqp-client-send-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT22.700289S\"\n        },\n        \"xdqp-client-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0.00293614692054689\n        },\n        \"xdqp-client-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdqp-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 131973888\n        },\n        \"xdqp-server-receive-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT3.474521S\"\n        },\n        \"xdqp-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0.00156576896551996\n        },\n        \"xdqp-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdqp-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 10035300\n        },\n        \"xdqp-server-send-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT4.275597S\"\n        },\n        \"xdqp-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"xdqp-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"xdqp-server-request-time\": {\n          \"units\": \"milliseconds\",\n          \"value\": 0.743777990341187\n        },\n        \"xdqp-server-request-rate\": {\n          \"units\": \"requests/sec\",\n          \"value\": 0.371862411499023\n        },\n        \"foreign-xdqp-client-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-client-receive-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"foreign-xdqp-client-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-client-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-client-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-client-send-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"foreign-xdqp-client-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-client-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-receive-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-receive-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"foreign-xdqp-server-receive-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-receive-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-send-bytes\": {\n          \"units\": \"bytes\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-send-time\": {\n          \"units\": \"time\",\n          \"value\": \"PT0S\"\n        },\n        \"foreign-xdqp-server-send-rate\": {\n          \"units\": \"MB/sec\",\n          \"value\": 0\n        },\n        \"foreign-xdqp-server-send-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"read-lock-count\": {\n          \"units\": \"locks\",\n          \"value\": 104\n        },\n        \"read-lock-wait-time\": {\n          \"units\": \"seconds\",\n          \"value\": \"PT0.001464S\"\n        },\n        \"read-lock-hold-time\": {\n          \"units\": \"seconds\",\n          \"value\": \"PT3.022913S\"\n        },\n        \"read-lock-rate\": {\n          \"units\": \"locks/sec\",\n          \"value\": 0\n        },\n        \"read-lock-wait-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"read-lock-hold-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"write-lock-count\": {\n          \"units\": \"locks\",\n          \"value\": 15911\n        },\n        \"write-lock-wait-time\": {\n          \"units\": \"seconds\",\n          \"value\": \"PT0.317098S\"\n        },\n        \"write-lock-hold-time\": {\n          \"units\": \"seconds\",\n          \"value\": \"PT11M46.9923759S\"\n        },\n        \"write-lock-rate\": {\n          \"units\": \"locks/sec\",\n          \"value\": 0.251882910728455\n        },\n        \"write-lock-wait-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"write-lock-hold-load\": {\n          \"units\": \"\",\n          \"value\": 0.00429263804107904\n        },\n        \"deadlock-count\": {\n          \"units\": \"locks\",\n          \"value\": 0\n        },\n        \"deadlock-wait-time\": {\n          \"units\": \"seconds\",\n          \"value\": \"PT0S\"\n        },\n        \"deadlock-rate\": {\n          \"units\": \"locks/sec\",\n          \"value\": 0\n        },\n        \"deadlock-wait-load\": {\n          \"units\": \"\",\n          \"value\": 0\n        },\n        \"external-kms-request-rate\": {\n          \"units\": \"requests/sec\",\n          \"value\": 0\n        },\n        \"external-kms-request-time\": {\n          \"units\": \"milliseconds\",\n          \"value\": 0\n        },\n        \"keystore-status\": \"normal\",\n        \"ldap-request-rate\": {\n          \"units\": \"requests/sec\",\n          \"value\": 0\n        },\n        \"ldap-request-time\": {\n          \"units\": \"milliseconds\",\n          \"value\": 0\n        }\n      }\n    },\n    \"related-views\": {\n      \"related-view\": [\n        {\n          \"view-type\": \"item\",\n          \"view-name\": \"default\",\n          \"view-uri\": \"/manage/v2/hosts/example\"\n        }\n      ]\n    }\n  }\n}\n`\n"
  },
  {
    "path": "plugins/inputs/marklogic/sample.conf",
    "content": "# Retrieves information on a specific host in a MarkLogic Cluster\n[[inputs.marklogic]]\n  ## Base URL of the MarkLogic HTTP Server.\n  url = \"http://localhost:8002\"\n\n  ## List of specific hostnames to retrieve information. At least (1) required.\n  # hosts = [\"hostname1\", \"hostname2\"]\n\n  ## Using HTTP Basic Authentication. Management API requires 'manage-user' role privileges\n  # username = \"myuser\"\n  # password = \"mypassword\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/mavlink/README.md",
    "content": "# MavLink Input Plugin\n\nThis plugin collects metrics from [MavLink][mavlink]-compatible flight\ncontrollers such as [ArduPilot][ardupilot] or [PX4][px4] to live ingest\nflight metrics from unmanned systems (drones, planes, boats, etc.)\nCurrently the ArduPilot-specific Mavlink dialect is used, check the\n[Mavlink documentation][mavlink_docs] for more details and the various\nmessages available.\n\n> [!WARNING]\n> This plugin potentially generates a large amount of data. If your output\n> plugin cannot handle the rate of messages, use\n> [Metric filters][metric_filters] to limit the metrics written to outputs,\n> and/or the `filters` configuration parameter to limit which Mavlink messages\n> this plugin parses.\n\n⭐ Telegraf v1.35.0\n🏷️ iot\n💻 all\n\n[ardupilot]: https://ardupilot.org/\n[mavlink]: https://mavlink.io/\n[mavlink_docs]: https://mavlink.io/en/messages/ardupilotmega.html\n[metric_filters]: ../../../docs/CONFIGURATION.md#metric-filtering\n[px4]: https://px4.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from a Mavlink flight controller.\n[[inputs.mavlink]]\n  ## Flight controller URL supporting serial port, UDP and TCP connections.\n  ## Options are documented at\n  ##   https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.\n  ##\n  ## Examples:\n  ## - Serial port: serial:///dev/ttyACM0:57600\n  ## - TCP client:  tcp://192.168.1.12:5760\n  ## - UDP client:  udp://192.168.1.12:14550\n  ## - TCP server:  tcpserver://:5760\n  ## - UDP server:  udpserver://:14550\n  # url = \"tcp://127.0.0.1:5760\"\n\n  ## Filter to specific messages. Only the messages in this list will be parsed.\n  ## If blank or unset, all messages will be accepted. Glob syntax is accepted.\n  ## Each message in this list should be lowercase camel_case, with \"message_\"\n  ## prefix removed, eg: \"global_position_int\", \"attitude\"\n  # filter = []\n\n  ## Mavlink system ID for Telegraf. Only used if the mavlink plugin is sending\n  ## messages, eg. when `stream_request_frequency` is 0 (see below.)\n  # system_id = 254\n\n  ## Determines whether the plugin sends requests to subscribe to data.\n  ## In mavlink, stream rates must be configured before data is received.\n  ## This config item sets the rate in Hz, with 0 disabling the request.\n  ##\n  ## This frequency should be set to 0 if your software already controls the\n  ## rates using REQUEST_DATA_STREAM or MAV_CMD_SET_MESSAGE_INTERVAL\n  ## (See https://mavlink.io/en/mavgen_python/howto_requestmessages.html)\n  # stream_request_frequency = 4\n```\n\n## Metrics\n\nEach supported Mavlink message translates to one metric group, and fields\non the Mavlink message are converted to fields in telegraf.\n\nThe name of the Mavlink message is translated into lowercase and any\nleading text `message_` is dropped.\n\nFor example, the message [ATTITUDE][attitude] will become an `attitude` metric,\nwith all fields copied from its Mavlink message definition.\n\n[attitude]: https://mavlink.io/en/messages/common.html#ATTITUDE\n\n## Example Output\n\n```text\nsystem_time,source=udp://:5760,sys_id=1 time_unix_usec=1732901334516981i,time_boot_ms=1731552i\nekf_status_report,source=udp://:5760,sys_id=1 velocity_variance=0.006436665542423725,pos_horiz_variance=0.006062425673007965,pos_vert_variance=0.0029854460153728724,compass_variance=0.010930062271654606,terrain_alt_variance=0,airspeed_variance=0\nlocal_position_ned,source=udp://:5760,sys_id=1 time_boot_ms=1731552i,x=-0.010437906719744205,y=-0.02162001095712185,z=-0.0037050051614642143,vx=-0.011906237341463566,vy=-0.02467793971300125,vz=0.012739507481455803\nvibration,source=udp://:5760,sys_id=1 time_usec=1731552102i,vibration_x=0.0028534166049212217,vibration_y=0.002792230574414134,vibration_z=0.0028329004999250174,clipping_0=0i,clipping_1=0i,clipping_2=0i\nbattery_status,source=udp://:5760,sys_id=1 id=0i,temperature=32767i,current_battery=0i,current_consumed=0i,energy_consumed=0i,battery_remaining=100i,time_remaining=0i\nahrs,source=udp://:5760,sys_id=1 omegaix=-0.0012698185164481401,omegaiy=-0.0011798597406595945,omegaiz=-0.0017210562946274877,accel_weight=0,renorm_val=0,error_rp=0.002372326795011759,error_yaw=0.0014012008905410767\nahrs2,source=udp://:5760,sys_id=1 roll=-0.0015893152449280024,pitch=-0.0018129277741536498,yaw=-1.2297048568725586,altitude=0.22999998927116394,lat=450469223i,lng=-834024728i\nattitude,source=udp://:5760,sys_id=1 time_boot_ms=1731811i,roll=-0.0011288427049294114,pitch=-0.0013485358795151114,yaw=-1.2430261373519897,rollspeed=-0.00023304438218474388,pitchspeed=-0.00023194786626845598,yawspeed=-0.0008081073756329715 0\nglobal_position_int,source=udp://:5760,sys_id=1 time_boot_ms=1731811i,lat=450469223i,lon=-834024730i,alt=0i,relative_alt=-115i,vx=-1i,vy=-2i,vz=1i,hdg=28878i\ngps_raw_int,source=udp://:5760,sys_id=1 time_usec=1731635000i,lat=450469223i,lon=-834024728i,alt=0i,eph=121i,epv=200i,vel=0i,cog=0i,satellites_visible=10i,alt_ellipsoid=0i,hacc=300i,vacc=300i,vel_acc=40i,hdg_acc=0i,yaw=0i\n```\n"
  },
  {
    "path": "plugins/inputs/mavlink/mavlink.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mavlink\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/bluenviron/gomavlib/v3\"\n\t\"github.com/bluenviron/gomavlib/v3/pkg/dialects/ardupilotmega\"\n\t\"github.com/bluenviron/gomavlib/v3/pkg/frame\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype Mavlink struct {\n\tURL                    string          `toml:\"url\"`\n\tSystemID               uint8           `toml:\"system_id\"`\n\tFilterPattern          []string        `toml:\"filter\"`\n\tStreamRequestFrequency uint16          `toml:\"stream_request_frequency\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\n\tfilter         filter.Filter\n\tconnection     *gomavlib.Node\n\tendpointConfig gomavlib.EndpointConf\n\tcancel         context.CancelFunc\n\twg             sync.WaitGroup\n}\n\n//go:embed sample.conf\nvar sampleConfig string\n\nfunc (*Mavlink) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Mavlink) Init() error {\n\t// Set default values\n\tif m.URL == \"\" {\n\t\tm.URL = \"tcp://127.0.0.1:5760\"\n\t}\n\n\t// Handle the different Mavlink endpoint schemata\n\tu, err := url.Parse(m.URL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid url: %w\", err)\n\t}\n\n\tswitch u.Scheme {\n\tcase \"serial\":\n\t\t// Parse serial URL by hand, because it is not a compliant URL.\n\t\t// Use the default baudrate if not specified\n\t\tbaudRate := 57600\n\t\tdevice, rate, found := strings.Cut(strings.TrimPrefix(m.URL, \"serial://\"), \":\")\n\t\tif found {\n\t\t\tr, err := strconv.Atoi(rate)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"serial baud rate not valid: %w\", err)\n\t\t\t}\n\t\t\tbaudRate = r\n\t\t}\n\n\t\tm.endpointConfig = gomavlib.EndpointSerial{\n\t\t\tDevice: device,\n\t\t\tBaud:   baudRate,\n\t\t}\n\n\tcase \"tcp\":\n\t\t// Use default TCP port if it was not specified\n\t\tport := u.Port()\n\t\tif port == \"\" {\n\t\t\tport = \"5760\"\n\t\t}\n\n\t\tif u.Hostname() == \"\" {\n\t\t\treturn errors.New(\"tcp client requires a hostname\")\n\t\t}\n\n\t\tm.endpointConfig = gomavlib.EndpointTCPClient{\n\t\t\tAddress: net.JoinHostPort(u.Hostname(), port),\n\t\t}\n\n\tcase \"tcpserver\":\n\t\t// Use default TCP port if it was not specified\n\t\tport := u.Port()\n\t\tif port == \"\" {\n\t\t\tport = \"5760\"\n\t\t}\n\n\t\t// Use default host 0.0.0.0 (bind on all interfaces)\n\t\t// if host was not specified\n\t\thostname := u.Hostname()\n\t\tif hostname == \"\" {\n\t\t\thostname = \"0.0.0.0\"\n\t\t}\n\n\t\tm.endpointConfig = gomavlib.EndpointTCPServer{\n\t\t\tAddress: net.JoinHostPort(hostname, port),\n\t\t}\n\n\tcase \"udp\":\n\t\t// Use default UDP port if it was not specified\n\t\tport := u.Port()\n\t\tif port == \"\" {\n\t\t\tport = \"14550\"\n\t\t}\n\n\t\tif u.Hostname() == \"\" {\n\t\t\treturn errors.New(\"udp client requires a hostname\")\n\t\t}\n\n\t\tm.endpointConfig = gomavlib.EndpointUDPClient{\n\t\t\tAddress: net.JoinHostPort(u.Hostname(), port),\n\t\t}\n\n\tcase \"udpserver\":\n\t\t// Use default UDP port if it was not specified\n\t\tport := u.Port()\n\t\tif port == \"\" {\n\t\t\tport = \"14550\"\n\t\t}\n\n\t\t// Use default host 0.0.0.0 (bind on all interfaces)\n\t\t// if host was not specified\n\t\thostname := u.Hostname()\n\t\tif hostname == \"\" {\n\t\t\thostname = \"0.0.0.0\"\n\t\t}\n\n\t\tm.endpointConfig = gomavlib.EndpointUDPServer{\n\t\t\tAddress: net.JoinHostPort(hostname, port),\n\t\t}\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown scheme %q\", u.Scheme)\n\t}\n\n\t// Compile filter\n\tm.filter, err = filter.Compile(m.FilterPattern)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"compiling filter failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (m *Mavlink) Start(acc telegraf.Accumulator) error {\n\t// Start MAVLink endpoint\n\tconnection := &gomavlib.Node{\n\t\tEndpoints:              []gomavlib.EndpointConf{m.endpointConfig},\n\t\tDialect:                ardupilotmega.Dialect,\n\t\tOutVersion:             gomavlib.V2,\n\t\tOutSystemID:            m.SystemID,\n\t\tStreamRequestEnable:    m.StreamRequestFrequency > 0,\n\t\tStreamRequestFrequency: int(m.StreamRequestFrequency),\n\t}\n\tif err := connection.Initialize(); err != nil {\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"connecting to mavlink endpoint %s failed: %w\", m.URL, err),\n\t\t\tRetry: true,\n\t\t}\n\t}\n\tm.connection = connection\n\tctx, cancelFunc := context.WithCancel(context.Background())\n\tm.cancel = cancelFunc\n\n\t// Start routine to connect to Mavlink and stream out data async\n\tm.wg.Add(1)\n\tgo func(ctx context.Context) {\n\t\tdefer m.connection.Close()\n\t\tdefer m.wg.Done()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase evt := <-m.connection.Events():\n\t\t\t\tswitch evt := evt.(type) {\n\t\t\t\tcase *gomavlib.EventFrame:\n\t\t\t\t\tm.handleFrame(acc, evt.Frame)\n\t\t\t\tcase *gomavlib.EventChannelOpen:\n\t\t\t\t\tm.Log.Tracef(\"Mavlink channel opened\")\n\t\t\t\tcase *gomavlib.EventChannelClose:\n\t\t\t\t\tm.Log.Tracef(\"Mavlink channel closed\")\n\t\t\t\tcase *gomavlib.EventParseError:\n\t\t\t\t\tm.Log.Tracef(\"Mavlink parse error: %v\", evt.Error)\n\t\t\t\tcase *gomavlib.EventStreamRequested:\n\t\t\t\t\tm.Log.Tracef(\"Issued stream request to system %d, component %d\", evt.SystemID, evt.ComponentID)\n\t\t\t\tdefault:\n\t\t\t\t\tm.Log.Tracef(\"Unhandled Mavlink event type: %T\", evt)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ctx)\n\n\treturn nil\n}\n\nfunc (*Mavlink) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (m *Mavlink) Stop() {\n\tm.cancel()\n\tm.wg.Wait()\n}\n\n// Convert a Mavlink frame into a telegraf Metric.\nfunc (m *Mavlink) handleFrame(acc telegraf.Accumulator, frm frame.Frame) {\n\tv := reflect.Indirect(reflect.ValueOf(frm.GetMessage()))\n\tt := v.Type()\n\n\tname := internal.SnakeCase(strings.TrimPrefix(t.Name(), \"Message\"))\n\tif m.filter != nil && !m.filter.Match(name) {\n\t\treturn\n\t}\n\n\ttags := map[string]string{\n\t\t\"sys_id\": strconv.FormatUint(uint64(frm.GetSystemID()), 10),\n\t\t\"source\": m.URL,\n\t}\n\tfields := make(map[string]interface{}, t.NumField())\n\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tfield := t.Field(i)\n\t\tvalue := v.Field(i)\n\t\tfieldName := internal.SnakeCase(field.Name)\n\n\t\tif value.Kind() == reflect.Slice || value.Kind() == reflect.Array {\n\t\t\t// Split array types into individual primitive values\n\t\t\t// with _<n> appended to the key\n\t\t\tfor j := 0; j < value.Len(); j++ {\n\t\t\t\tindexedFieldName := fmt.Sprintf(\"%s_%d\", fieldName, j+1)\n\t\t\t\tfields[indexedFieldName] = value.Index(j).Interface()\n\t\t\t}\n\t\t} else {\n\t\t\tfields[fieldName] = value.Interface()\n\t\t}\n\t}\n\n\tacc.AddFields(name, fields, tags)\n}\n\nfunc init() {\n\tinputs.Add(\"mavlink\", func() telegraf.Input {\n\t\treturn &Mavlink{\n\t\t\tSystemID:               254,\n\t\t\tStreamRequestFrequency: 4,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mavlink/mavlink_test.go",
    "content": "package mavlink\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bluenviron/gomavlib/v3\"\n\t\"github.com/bluenviron/gomavlib/v3/pkg/dialects/common\"\n\t\"github.com/bluenviron/gomavlib/v3/pkg/frame\"\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// Test that all URL types can be parsed successfully\nfunc TestParseURL(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\turl      string\n\t\texpected gomavlib.EndpointConf\n\t}{\n\t\t{\n\t\t\tname: \"serial Linux\",\n\t\t\turl:  \"serial:///dev/ttyACM0:115200\",\n\t\t\texpected: gomavlib.EndpointSerial{\n\t\t\t\tDevice: \"/dev/ttyACM0\",\n\t\t\t\tBaud:   115200,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"serial Linux with default baudrate\",\n\t\t\turl:  \"serial:///dev/ttyACM0\",\n\t\t\texpected: gomavlib.EndpointSerial{\n\t\t\t\tDevice: \"/dev/ttyACM0\",\n\t\t\t\tBaud:   57600,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"serial Windows\",\n\t\t\turl:  \"serial://COM1:115200\",\n\t\t\texpected: gomavlib.EndpointSerial{\n\t\t\t\tDevice: \"COM1\",\n\t\t\t\tBaud:   115200,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"serial Windows with default baudrate\",\n\t\t\turl:  \"serial://COM1\",\n\t\t\texpected: gomavlib.EndpointSerial{\n\t\t\t\tDevice: \"COM1\",\n\t\t\t\tBaud:   57600,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP client\",\n\t\t\turl:  \"udp://192.168.1.12:14550\",\n\t\t\texpected: gomavlib.EndpointUDPClient{\n\t\t\t\tAddress: \"192.168.1.12:14550\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP client with default port\",\n\t\t\turl:  \"udp://192.168.1.12\",\n\t\t\texpected: gomavlib.EndpointUDPClient{\n\t\t\t\tAddress: \"192.168.1.12:14550\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP server\",\n\t\t\turl:  \"udpserver://:14550\",\n\t\t\texpected: gomavlib.EndpointUDPServer{\n\t\t\t\tAddress: \"0.0.0.0:14550\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP server with default port\",\n\t\t\turl:  \"udpserver://\",\n\t\t\texpected: gomavlib.EndpointUDPServer{\n\t\t\t\tAddress: \"0.0.0.0:14550\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP server on localhost\",\n\t\t\turl:  \"udpserver://127.0.0.1\",\n\t\t\texpected: gomavlib.EndpointUDPServer{\n\t\t\t\tAddress: \"127.0.0.1:14550\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP client\",\n\t\t\turl:  \"tcp://192.168.1.12:5760\",\n\t\t\texpected: gomavlib.EndpointTCPClient{\n\t\t\t\tAddress: \"192.168.1.12:5760\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP client with default port\",\n\t\t\turl:  \"tcp://192.168.1.12\",\n\t\t\texpected: gomavlib.EndpointTCPClient{\n\t\t\t\tAddress: \"192.168.1.12:5760\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP server\",\n\t\t\turl:  \"tcpserver://:5761\",\n\t\t\texpected: gomavlib.EndpointTCPServer{\n\t\t\t\tAddress: \"0.0.0.0:5761\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP server with default port\",\n\t\t\turl:  \"tcpserver://\",\n\t\t\texpected: gomavlib.EndpointTCPServer{\n\t\t\t\tAddress: \"0.0.0.0:5760\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP server on localhost\",\n\t\t\turl:  \"tcpserver://127.0.0.1\",\n\t\t\texpected: gomavlib.EndpointTCPServer{\n\t\t\t\tAddress: \"127.0.0.1:5760\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Default connection\",\n\t\t\turl:  \"\",\n\t\t\texpected: gomavlib.EndpointTCPClient{\n\t\t\t\tAddress: \"127.0.0.1:5760\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Mavlink{URL: tt.url}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Check the resulting endpoint configuration\n\t\t\trequire.EqualValues(t, tt.expected, plugin.endpointConfig)\n\t\t})\n\t}\n}\n\n// Test that some mavlink messages are correctly decoded into telegraf metrics.\nfunc TestMavlinkDecoding(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    *frame.V2Frame\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"Heartbeat\",\n\t\t\tinput: &frame.V2Frame{\n\t\t\t\tSequenceNumber: 1,\n\t\t\t\tSystemID:       1,\n\t\t\t\tComponentID:    1,\n\t\t\t\tMessage: &common.MessageHeartbeat{\n\t\t\t\t\tType:           0,\n\t\t\t\t\tAutopilot:      1,\n\t\t\t\t\tBaseMode:       2,\n\t\t\t\t\tCustomMode:     3,\n\t\t\t\t\tSystemStatus:   4,\n\t\t\t\t\tMavlinkVersion: 5,\n\t\t\t\t},\n\t\t\t\tChecksum: 0,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{metric.New(\n\t\t\t\t\"heartbeat\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"sys_id\": \"1\",\n\t\t\t\t\t\"source\": \"udpserver://\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"custom_mode\":     uint32(3),\n\t\t\t\t\t\"mavlink_version\": uint8(5),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t)},\n\t\t},\n\t\t{\n\t\t\tname: \"Attitude\",\n\t\t\tinput: &frame.V2Frame{\n\t\t\t\tSequenceNumber: 1,\n\t\t\t\tSystemID:       1,\n\t\t\t\tComponentID:    1,\n\t\t\t\tMessage: &common.MessageAttitude{\n\t\t\t\t\tTimeBootMs: uint32(123),\n\t\t\t\t\tRoll:       float32(1.234),\n\t\t\t\t\tPitch:      float32(0.463),\n\t\t\t\t\tYaw:        float32(-0.112),\n\t\t\t\t\tRollspeed:  float32(0.001),\n\t\t\t\t\tPitchspeed: float32(0.002),\n\t\t\t\t\tYawspeed:   float32(0.003),\n\t\t\t\t},\n\t\t\t\tChecksum: 0,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{metric.New(\n\t\t\t\t\"attitude\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"sys_id\": \"1\",\n\t\t\t\t\t\"source\": \"udpserver://\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"pitch\":        float32(0.463),\n\t\t\t\t\t\"roll\":         float32(1.234),\n\t\t\t\t\t\"yaw\":          float32(-0.112),\n\t\t\t\t\t\"pitchspeed\":   float32(0.002),\n\t\t\t\t\t\"rollspeed\":    float32(0.001),\n\t\t\t\t\t\"yawspeed\":     float32(0.003),\n\t\t\t\t\t\"time_boot_ms\": uint32(123),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t)},\n\t\t},\n\t\t{\n\t\t\tname: \"ESC Status\",\n\t\t\tinput: &frame.V2Frame{\n\t\t\t\tSequenceNumber: 1,\n\t\t\t\tSystemID:       1,\n\t\t\t\tComponentID:    1,\n\t\t\t\tMessage: &common.MessageEscStatus{\n\t\t\t\t\tIndex:    uint8(0),\n\t\t\t\t\tTimeUsec: uint64(12345),\n\t\t\t\t\tRpm:      [4]int32{0, 1, 2, 3},\n\t\t\t\t\tVoltage:  [4]float32{10.0, 11.0, 12.0, 13.0},\n\t\t\t\t\tCurrent:  [4]float32{14.0, 15.0, 16.0, 17.0},\n\t\t\t\t},\n\t\t\t\tChecksum: 0,\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{metric.New(\n\t\t\t\t\"esc_status\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"sys_id\": \"1\",\n\t\t\t\t\t\"source\": \"udpserver://\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"index\":     uint8(0),\n\t\t\t\t\t\"time_usec\": uint64(12345),\n\t\t\t\t\t\"current_1\": float32(14.0),\n\t\t\t\t\t\"current_2\": float32(15.0),\n\t\t\t\t\t\"current_3\": float32(16.0),\n\t\t\t\t\t\"current_4\": float32(17.0),\n\t\t\t\t\t\"rpm_1\":     int32(0),\n\t\t\t\t\t\"rpm_2\":     int32(1),\n\t\t\t\t\t\"rpm_3\":     int32(2),\n\t\t\t\t\t\"rpm_4\":     int32(3),\n\t\t\t\t\t\"voltage_1\": float32(10.0),\n\t\t\t\t\t\"voltage_2\": float32(11.0),\n\t\t\t\t\t\"voltage_3\": float32(12.0),\n\t\t\t\t\t\"voltage_4\": float32(13.0),\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t)},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Mavlink{URL: \"udpserver://\"}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\tacc := testutil.Accumulator{}\n\n\t\t\tplugin.handleFrame(&acc, tt.input)\n\n\t\t\t// Check that accumulator contains the metric\n\t\t\ttestutil.RequireMetricsStructureEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\n// Test that the plugin can interface with a real ArduPilot container.\nfunc TestArduPilotIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Start the docker container for ArduPilot\n\tcontainer := testutil.Container{\n\t\tImage:        \"radarku/ardupilot-sitl\",\n\t\tExposedPorts: []string{\"5760\"},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(\"5760\")),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start ardupilot container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin\n\tplugin := Mavlink{\n\t\tURL:                    \"tcp://127.0.0.1:\" + container.Ports[\"5760\"],\n\t\tSystemID:               254,\n\t\tStreamRequestFrequency: 4,\n\t\tLog:                    testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Collect the metrics and compare\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Expect to have received more than 10 metrics. The exact metrics received\n\t// is non-deterministic because ArduPilot's startup may vary between runs,\n\t// but should be on the order of 100 metrics in 5 seconds.\n\t// Content of metrics is not tested here as we don't know what to expect.\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= 10\n\t}, 10*time.Second, 100*time.Millisecond, \"less than 10 metrics received\")\n}\n"
  },
  {
    "path": "plugins/inputs/mavlink/sample.conf",
    "content": "# Read metrics from a Mavlink flight controller.\n[[inputs.mavlink]]\n  ## Flight controller URL supporting serial port, UDP and TCP connections.\n  ## Options are documented at\n  ##   https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.\n  ##\n  ## Examples:\n  ## - Serial port: serial:///dev/ttyACM0:57600\n  ## - TCP client:  tcp://192.168.1.12:5760\n  ## - UDP client:  udp://192.168.1.12:14550\n  ## - TCP server:  tcpserver://:5760\n  ## - UDP server:  udpserver://:14550\n  # url = \"tcp://127.0.0.1:5760\"\n\n  ## Filter to specific messages. Only the messages in this list will be parsed.\n  ## If blank or unset, all messages will be accepted. Glob syntax is accepted.\n  ## Each message in this list should be lowercase camel_case, with \"message_\"\n  ## prefix removed, eg: \"global_position_int\", \"attitude\"\n  # filter = []\n\n  ## Mavlink system ID for Telegraf. Only used if the mavlink plugin is sending\n  ## messages, eg. when `stream_request_frequency` is 0 (see below.)\n  # system_id = 254\n\n  ## Determines whether the plugin sends requests to subscribe to data.\n  ## In mavlink, stream rates must be configured before data is received.\n  ## This config item sets the rate in Hz, with 0 disabling the request.\n  ##\n  ## This frequency should be set to 0 if your software already controls the\n  ## rates using REQUEST_DATA_STREAM or MAV_CMD_SET_MESSAGE_INTERVAL\n  ## (See https://mavlink.io/en/mavgen_python/howto_requestmessages.html)\n  # stream_request_frequency = 4\n"
  },
  {
    "path": "plugins/inputs/mcrouter/README.md",
    "content": "# Mcrouter Input Plugin\n\nThis plugin gathers statistics data from [Mcrouter][mcrouter] instances, a\nprotocol router, developed and maintained by Facebook, for scaling\n[memcached][memcached] deployments.\n\n⭐ Telegraf v1.7.0\n🏷️ applications, network\n💻 all\n\n[mcrouter]: https://github.com/facebook/mcrouter\n[memcached]: http://memcached.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many mcrouter servers.\n[[inputs.mcrouter]]\n  ## An array of address to gather stats about. Specify an ip or hostname\n  ## with port. ie tcp://localhost:11211, tcp://10.0.0.1:11211, etc.\n  servers = [\"tcp://localhost:11211\", \"unix:///var/run/mcrouter.sock\"]\n\n  ## Timeout for metric collections from all servers.  Minimum timeout is \"1s\".\n  # timeout = \"5s\"\n```\n\n## Metrics\n\nThe fields from this plugin are gathered in the *mcrouter* measurement.\n\nDescription of gathered fields can be found in the [project wiki][wiki].\n\nFields:\n\n* uptime\n* num_servers\n* num_servers_new\n* num_servers_up\n* num_servers_down\n* num_servers_closed\n* num_clients\n* num_suspect_servers\n* destination_batches_sum\n* destination_requests_sum\n* outstanding_route_get_reqs_queued\n* outstanding_route_update_reqs_queued\n* outstanding_route_get_avg_queue_size\n* outstanding_route_update_avg_queue_size\n* outstanding_route_get_avg_wait_time_sec\n* outstanding_route_update_avg_wait_time_sec\n* retrans_closed_connections\n* destination_pending_reqs\n* destination_inflight_reqs\n* destination_batch_size\n* asynclog_requests\n* proxy_reqs_processing\n* proxy_reqs_waiting\n* client_queue_notify_period\n* rusage_system\n* rusage_user\n* ps_num_minor_faults\n* ps_num_major_faults\n* ps_user_time_sec\n* ps_system_time_sec\n* ps_vsize\n* ps_rss\n* fibers_allocated\n* fibers_pool_size\n* fibers_stack_high_watermark\n* successful_client_connections\n* duration_us\n* destination_max_pending_reqs\n* destination_max_inflight_reqs\n* retrans_per_kbyte_max\n* cmd_get_count\n* cmd_delete_out\n* cmd_lease_get\n* cmd_set\n* cmd_get_out_all\n* cmd_get_out\n* cmd_lease_set_count\n* cmd_other_out_all\n* cmd_lease_get_out\n* cmd_set_count\n* cmd_lease_set_out\n* cmd_delete_count\n* cmd_other\n* cmd_delete\n* cmd_get\n* cmd_lease_set\n* cmd_set_out\n* cmd_lease_get_count\n* cmd_other_out\n* cmd_lease_get_out_all\n* cmd_set_out_all\n* cmd_other_count\n* cmd_delete_out_all\n* cmd_lease_set_out_all\n\n[wiki]: https://github.com/facebook/mcrouter/wiki/Stats-list\n\n## Tags\n\n* Mcrouter measurements have the following tags:\n  * server (the host name from which metrics are gathered)\n\n## Example Output\n\n```text\nmcrouter,server=localhost:11211 uptime=166,num_servers=1,num_servers_new=1,num_servers_up=0,num_servers_down=0,num_servers_closed=0,num_clients=1,num_suspect_servers=0,destination_batches_sum=0,destination_requests_sum=0,outstanding_route_get_reqs_queued=0,outstanding_route_update_reqs_queued=0,outstanding_route_get_avg_queue_size=0,outstanding_route_update_avg_queue_size=0,outstanding_route_get_avg_wait_time_sec=0,outstanding_route_update_avg_wait_time_sec=0,retrans_closed_connections=0,destination_pending_reqs=0,destination_inflight_reqs=0,destination_batch_size=0,asynclog_requests=0,proxy_reqs_processing=1,proxy_reqs_waiting=0,client_queue_notify_period=0,rusage_system=0.040966,rusage_user=0.020483,ps_num_minor_faults=2490,ps_num_major_faults=11,ps_user_time_sec=0.02,ps_system_time_sec=0.04,ps_vsize=697741312,ps_rss=10563584,fibers_allocated=0,fibers_pool_size=0,fibers_stack_high_watermark=0,successful_client_connections=18,duration_us=0,destination_max_pending_reqs=0,destination_max_inflight_reqs=0,retrans_per_kbyte_max=0,cmd_get_count=0,cmd_delete_out=0,cmd_lease_get=0,cmd_set=0,cmd_get_out_all=0,cmd_get_out=0,cmd_lease_set_count=0,cmd_other_out_all=0,cmd_lease_get_out=0,cmd_set_count=0,cmd_lease_set_out=0,cmd_delete_count=0,cmd_other=0,cmd_delete=0,cmd_get=0,cmd_lease_set=0,cmd_set_out=0,cmd_lease_get_count=0,cmd_other_out=0,cmd_lease_get_out_all=0,cmd_set_out_all=0,cmd_other_count=0,cmd_delete_out_all=0,cmd_lease_set_out_all=0 1453831884664956455\n```\n"
  },
  {
    "path": "plugins/inputs/mcrouter/mcrouter.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mcrouter\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// enum for statType\ntype statType int\n\nconst (\n\ttypeInt   statType = iota\n\ttypeFloat statType = iota\n)\n\nvar (\n\tdefaultTimeout   = 5 * time.Second\n\tdefaultServerURL = url.URL{\n\t\tScheme: \"tcp\",\n\t\tHost:   \"localhost:11211\",\n\t}\n\t// The list of metrics that should be sent\n\tsendMetrics = map[string]statType{\n\t\t\"uptime\":                                     typeInt,\n\t\t\"num_servers\":                                typeInt,\n\t\t\"num_servers_new\":                            typeInt,\n\t\t\"num_servers_up\":                             typeInt,\n\t\t\"num_servers_down\":                           typeInt,\n\t\t\"num_servers_closed\":                         typeInt,\n\t\t\"num_clients\":                                typeInt,\n\t\t\"num_suspect_servers\":                        typeInt,\n\t\t\"destination_batches_sum\":                    typeInt,\n\t\t\"destination_requests_sum\":                   typeInt,\n\t\t\"outstanding_route_get_reqs_queued\":          typeInt,\n\t\t\"outstanding_route_update_reqs_queued\":       typeInt,\n\t\t\"outstanding_route_get_avg_queue_size\":       typeInt,\n\t\t\"outstanding_route_update_avg_queue_size\":    typeInt,\n\t\t\"outstanding_route_get_avg_wait_time_sec\":    typeInt,\n\t\t\"outstanding_route_update_avg_wait_time_sec\": typeInt,\n\t\t\"retrans_closed_connections\":                 typeInt,\n\t\t\"destination_pending_reqs\":                   typeInt,\n\t\t\"destination_inflight_reqs\":                  typeInt,\n\t\t\"destination_batch_size\":                     typeInt,\n\t\t\"asynclog_requests\":                          typeInt,\n\t\t\"proxy_reqs_processing\":                      typeInt,\n\t\t\"proxy_reqs_waiting\":                         typeInt,\n\t\t\"client_queue_notify_period\":                 typeInt,\n\t\t\"rusage_system\":                              typeFloat,\n\t\t\"rusage_user\":                                typeFloat,\n\t\t\"ps_num_minor_faults\":                        typeInt,\n\t\t\"ps_num_major_faults\":                        typeInt,\n\t\t\"ps_user_time_sec\":                           typeFloat,\n\t\t\"ps_system_time_sec\":                         typeFloat,\n\t\t\"ps_vsize\":                                   typeInt,\n\t\t\"ps_rss\":                                     typeInt,\n\t\t\"fibers_allocated\":                           typeInt,\n\t\t\"fibers_pool_size\":                           typeInt,\n\t\t\"fibers_stack_high_watermark\":                typeInt,\n\t\t\"successful_client_connections\":              typeInt,\n\t\t\"duration_us\":                                typeInt,\n\t\t\"destination_max_pending_reqs\":               typeInt,\n\t\t\"destination_max_inflight_reqs\":              typeInt,\n\t\t\"retrans_per_kbyte_max\":                      typeInt,\n\t\t\"cmd_get_count\":                              typeInt,\n\t\t\"cmd_delete_out\":                             typeInt,\n\t\t\"cmd_lease_get\":                              typeInt,\n\t\t\"cmd_set\":                                    typeInt,\n\t\t\"cmd_get_out_all\":                            typeInt,\n\t\t\"cmd_get_out\":                                typeInt,\n\t\t\"cmd_lease_set_count\":                        typeInt,\n\t\t\"cmd_other_out_all\":                          typeInt,\n\t\t\"cmd_lease_get_out\":                          typeInt,\n\t\t\"cmd_set_count\":                              typeInt,\n\t\t\"cmd_lease_set_out\":                          typeInt,\n\t\t\"cmd_delete_count\":                           typeInt,\n\t\t\"cmd_other\":                                  typeInt,\n\t\t\"cmd_delete\":                                 typeInt,\n\t\t\"cmd_get\":                                    typeInt,\n\t\t\"cmd_lease_set\":                              typeInt,\n\t\t\"cmd_set_out\":                                typeInt,\n\t\t\"cmd_lease_get_count\":                        typeInt,\n\t\t\"cmd_other_out\":                              typeInt,\n\t\t\"cmd_lease_get_out_all\":                      typeInt,\n\t\t\"cmd_set_out_all\":                            typeInt,\n\t\t\"cmd_other_count\":                            typeInt,\n\t\t\"cmd_delete_out_all\":                         typeInt,\n\t\t\"cmd_lease_set_out_all\":                      typeInt,\n\t}\n)\n\ntype Mcrouter struct {\n\tServers []string        `toml:\"servers\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n}\n\nfunc (*Mcrouter) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Mcrouter) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\n\tif m.Timeout < config.Duration(1*time.Second) {\n\t\tm.Timeout = config.Duration(defaultTimeout)\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, time.Duration(m.Timeout))\n\tdefer cancel()\n\n\tif len(m.Servers) == 0 {\n\t\tm.Servers = []string{defaultServerURL.String()}\n\t}\n\n\tfor _, serverAddress := range m.Servers {\n\t\tacc.AddError(gatherServer(ctx, serverAddress, acc))\n\t}\n\n\treturn nil\n}\n\n// parseAddress parses an address string into 'host:port' and 'protocol' parts\nfunc parseAddress(address string) (parsedAddress, protocol string, err error) {\n\tvar host string\n\tvar port string\n\n\tparsedAddress = address\n\n\tu, parseError := url.Parse(parsedAddress)\n\n\tif parseError != nil {\n\t\treturn \"\", \"\", errors.New(\"invalid server address\")\n\t}\n\n\tif u.Scheme != \"tcp\" && u.Scheme != \"unix\" {\n\t\treturn \"\", \"\", errors.New(\"invalid server protocol\")\n\t}\n\n\tprotocol = u.Scheme\n\n\tif protocol == \"unix\" {\n\t\tif u.Path == \"\" {\n\t\t\treturn \"\", \"\", errors.New(\"invalid unix socket path\")\n\t\t}\n\n\t\tparsedAddress = u.Path\n\t} else {\n\t\tif u.Host == \"\" {\n\t\t\treturn \"\", \"\", errors.New(\"invalid host\")\n\t\t}\n\n\t\thost = u.Hostname()\n\t\tport = u.Port()\n\n\t\tif host == \"\" {\n\t\t\thost = defaultServerURL.Hostname()\n\t\t}\n\n\t\tif port == \"\" {\n\t\t\tport = defaultServerURL.Port()\n\t\t}\n\n\t\tparsedAddress = host + \":\" + port\n\t}\n\n\treturn parsedAddress, protocol, nil\n}\n\nfunc gatherServer(ctx context.Context, address string, acc telegraf.Accumulator) error {\n\tvar conn net.Conn\n\tvar err error\n\tvar protocol string\n\tvar dialer net.Dialer\n\n\taddress, protocol, err = parseAddress(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err = dialer.DialContext(ctx, protocol, address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close()\n\n\t// Extend connection\n\tdeadline, ok := ctx.Deadline()\n\n\tif ok {\n\t\tif err := conn.SetDeadline(deadline); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Read and write buffer\n\treader := bufio.NewReader(conn)\n\tscanner := bufio.NewScanner(reader)\n\n\t// Send command\n\tif _, err := fmt.Fprint(conn, \"stats\\r\\n\"); err != nil {\n\t\treturn err\n\t}\n\n\tvalues, err := parseResponse(scanner)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Add server address as a tag\n\ttags := map[string]string{\"server\": address}\n\n\t// Process values\n\tfields := make(map[string]interface{})\n\tfor key, sType := range sendMetrics {\n\t\tif value, ok := values[key]; ok {\n\t\t\tswitch sType {\n\t\t\tcase typeInt:\n\t\t\t\tif v, errParse := strconv.ParseInt(value, 10, 64); errParse == nil {\n\t\t\t\t\tfields[key] = v\n\t\t\t\t}\n\t\t\tcase typeFloat:\n\t\t\t\tif v, errParse := strconv.ParseFloat(value, 64); errParse == nil {\n\t\t\t\t\tfields[key] = v\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"mcrouter\", fields, tags)\n\treturn nil\n}\n\nfunc parseResponse(r *bufio.Scanner) (map[string]string, error) {\n\tvalues := make(map[string]string)\n\n\tfor r.Scan() {\n\t\t// Read line\n\t\tline := r.Text()\n\n\t\t// Done\n\t\tif line == \"END\" {\n\t\t\tbreak\n\t\t}\n\n\t\t// Read values\n\t\ts := strings.SplitN(line, \" \", 3)\n\n\t\tif len(s) != 3 || s[0] != \"STAT\" {\n\t\t\treturn nil, fmt.Errorf(\"unexpected line in stats response: %s\", line)\n\t\t}\n\n\t\t// Save values\n\t\tvalues[s[1]] = s[2]\n\t}\n\n\treturn values, nil\n}\n\nfunc init() {\n\tinputs.Add(\"mcrouter\", func() telegraf.Input {\n\t\treturn &Mcrouter{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mcrouter/mcrouter_test.go",
    "content": "package mcrouter\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAddressParsing(t *testing.T) {\n\tvar acceptTests = [][3]string{\n\t\t{\"tcp://localhost:8086\", \"localhost:8086\", \"tcp\"},\n\t\t{\"tcp://localhost\", \"localhost:\" + defaultServerURL.Port(), \"tcp\"},\n\t\t{\"tcp://localhost:\", \"localhost:\" + defaultServerURL.Port(), \"tcp\"},\n\t\t{\"tcp://:8086\", defaultServerURL.Hostname() + \":8086\", \"tcp\"},\n\t\t{\"tcp://:\", defaultServerURL.Host, \"tcp\"},\n\t}\n\n\tvar rejectTests = []string{\n\t\t\"tcp://\",\n\t}\n\n\tfor _, args := range acceptTests {\n\t\taddress, protocol, err := parseAddress(args[0])\n\n\t\trequire.NoError(t, err, args[0])\n\t\trequire.Equal(t, args[1], address, args[0])\n\t\trequire.Equal(t, args[2], protocol, args[0])\n\t}\n\n\tfor _, addr := range rejectTests {\n\t\taddress, protocol, err := parseAddress(addr)\n\n\t\trequire.Error(t, err, addr)\n\t\trequire.Empty(t, address, addr)\n\t\trequire.Empty(t, protocol, addr)\n\t}\n}\n\nfunc TestMcrouterGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tservicePort := \"11211\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"memcached\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(nat.Port(servicePort)),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tm := &Mcrouter{\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\t// wait for the uptime stat to show up\n\trequire.Eventually(t, func() bool {\n\t\terr = acc.GatherError(m.Gather)\n\t\trequire.NoError(t, err)\n\t\treturn acc.HasInt64Field(\"mcrouter\", \"uptime\")\n\t}, 5*time.Second, 10*time.Millisecond)\n\n\tintMetrics := []string{\n\t\t\"uptime\",\n\t\t\"cmd_set\",\n\t\t\"cmd_get\",\n\t}\n\n\tfloatMetrics := []string{\n\t\t\"rusage_system\",\n\t\t\"rusage_user\",\n\t}\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"mcrouter\", metric), metric)\n\t}\n\n\tfor _, metric := range floatMetrics {\n\t\trequire.True(t, acc.HasFloatField(\"mcrouter\", metric), metric)\n\t}\n}\n\nfunc TestMcrouterParseMetrics(t *testing.T) {\n\tfilePath := \"testdata/mcrouter_stats\"\n\tfile, err := os.Open(filePath)\n\trequire.NoErrorf(t, err, \"could not read from file %s\", filePath)\n\n\tr := bufio.NewReader(file)\n\tscanner := bufio.NewScanner(r)\n\tvalues, err := parseResponse(scanner)\n\trequire.NoError(t, err, \"Error parsing mcrouter response\")\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue string\n\t}{\n\t\t{\"uptime\", \"166\"},\n\t\t{\"num_servers\", \"1\"},\n\t\t{\"num_servers_new\", \"1\"},\n\t\t{\"num_servers_up\", \"0\"},\n\t\t{\"num_servers_down\", \"0\"},\n\t\t{\"num_servers_closed\", \"0\"},\n\t\t{\"num_clients\", \"1\"},\n\t\t{\"num_suspect_servers\", \"0\"},\n\t\t{\"destination_batches_sum\", \"0\"},\n\t\t{\"destination_requests_sum\", \"0\"},\n\t\t{\"outstanding_route_get_reqs_queued\", \"0\"},\n\t\t{\"outstanding_route_update_reqs_queued\", \"0\"},\n\t\t{\"outstanding_route_get_avg_queue_size\", \"0\"},\n\t\t{\"outstanding_route_update_avg_queue_size\", \"0\"},\n\t\t{\"outstanding_route_get_avg_wait_time_sec\", \"0\"},\n\t\t{\"outstanding_route_update_avg_wait_time_sec\", \"0\"},\n\t\t{\"retrans_closed_connections\", \"0\"},\n\t\t{\"destination_pending_reqs\", \"0\"},\n\t\t{\"destination_inflight_reqs\", \"0\"},\n\t\t{\"destination_batch_size\", \"0\"},\n\t\t{\"asynclog_requests\", \"0\"},\n\t\t{\"proxy_reqs_processing\", \"1\"},\n\t\t{\"proxy_reqs_waiting\", \"0\"},\n\t\t{\"client_queue_notify_period\", \"0\"},\n\t\t{\"rusage_system\", \"0.040966\"},\n\t\t{\"rusage_user\", \"0.020483\"},\n\t\t{\"ps_num_minor_faults\", \"2490\"},\n\t\t{\"ps_num_major_faults\", \"11\"},\n\t\t{\"ps_user_time_sec\", \"0.02\"},\n\t\t{\"ps_system_time_sec\", \"0.04\"},\n\t\t{\"ps_vsize\", \"697741312\"},\n\t\t{\"ps_rss\", \"10563584\"},\n\t\t{\"fibers_allocated\", \"0\"},\n\t\t{\"fibers_pool_size\", \"0\"},\n\t\t{\"fibers_stack_high_watermark\", \"0\"},\n\t\t{\"successful_client_connections\", \"18\"},\n\t\t{\"duration_us\", \"0\"},\n\t\t{\"destination_max_pending_reqs\", \"0\"},\n\t\t{\"destination_max_inflight_reqs\", \"0\"},\n\t\t{\"retrans_per_kbyte_max\", \"0\"},\n\t\t{\"cmd_get_count\", \"0\"},\n\t\t{\"cmd_delete_out\", \"0\"},\n\t\t{\"cmd_lease_get\", \"0\"},\n\t\t{\"cmd_set\", \"0\"},\n\t\t{\"cmd_get_out_all\", \"0\"},\n\t\t{\"cmd_get_out\", \"0\"},\n\t\t{\"cmd_lease_set_count\", \"0\"},\n\t\t{\"cmd_other_out_all\", \"0\"},\n\t\t{\"cmd_lease_get_out\", \"0\"},\n\t\t{\"cmd_set_count\", \"0\"},\n\t\t{\"cmd_lease_set_out\", \"0\"},\n\t\t{\"cmd_delete_count\", \"0\"},\n\t\t{\"cmd_other\", \"0\"},\n\t\t{\"cmd_delete\", \"0\"},\n\t\t{\"cmd_get\", \"0\"},\n\t\t{\"cmd_lease_set\", \"0\"},\n\t\t{\"cmd_set_out\", \"0\"},\n\t\t{\"cmd_lease_get_count\", \"0\"},\n\t\t{\"cmd_other_out\", \"0\"},\n\t\t{\"cmd_lease_get_out_all\", \"0\"},\n\t\t{\"cmd_set_out_all\", \"0\"},\n\t\t{\"cmd_other_count\", \"0\"},\n\t\t{\"cmd_delete_out_all\", \"0\"},\n\t\t{\"cmd_lease_set_out_all\", \"0\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\tif !ok {\n\t\t\tt.Errorf(\"Did not find key for metric %s in values\", test.key)\n\t\t\tcontinue\n\t\t}\n\t\tif value != test.value {\n\t\t\tt.Errorf(\"Metric: %s, Expected: %s, actual: %s\",\n\t\t\t\ttest.key, test.value, value)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/mcrouter/sample.conf",
    "content": "# Read metrics from one or many mcrouter servers.\n[[inputs.mcrouter]]\n  ## An array of address to gather stats about. Specify an ip or hostname\n  ## with port. ie tcp://localhost:11211, tcp://10.0.0.1:11211, etc.\n  servers = [\"tcp://localhost:11211\", \"unix:///var/run/mcrouter.sock\"]\n\n  ## Timeout for metric collections from all servers.  Minimum timeout is \"1s\".\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/mcrouter/testdata/mcrouter_stats",
    "content": "STAT version 36.0.0 mcrouter\nSTAT commandargs --port 11211 --config-file /etc/mcrouter/mcrouter.json --async-dir /var/spool/mcrouter --log-path /var/log/mcrouter/mcrouter.log --stats-root /var/mcrouter/stats --server-timeout 100 --reset-inactive-connection-interval 10000 --proxy-threads auto\nSTAT pid 21357\nSTAT parent_pid 1\nSTAT time 1524673265\nSTAT uptime 166\nSTAT num_servers 1\nSTAT num_servers_new 1\nSTAT num_servers_up 0\nSTAT num_servers_down 0\nSTAT num_servers_closed 0\nSTAT num_clients 1\nSTAT num_suspect_servers 0\nSTAT destination_batches_sum 0\nSTAT destination_requests_sum 0\nSTAT outstanding_route_get_reqs_queued 0\nSTAT outstanding_route_update_reqs_queued 0\nSTAT outstanding_route_get_avg_queue_size 0\nSTAT outstanding_route_update_avg_queue_size 0\nSTAT outstanding_route_get_avg_wait_time_sec 0\nSTAT outstanding_route_update_avg_wait_time_sec 0\nSTAT retrans_closed_connections 0\nSTAT destination_pending_reqs 0\nSTAT destination_inflight_reqs 0\nSTAT destination_batch_size 0\nSTAT asynclog_requests 0\nSTAT proxy_reqs_processing 1\nSTAT proxy_reqs_waiting 0\nSTAT client_queue_notify_period 0\nSTAT rusage_system 0.040966\nSTAT rusage_user 0.020483\nSTAT ps_num_minor_faults 2490\nSTAT ps_num_major_faults 11\nSTAT ps_user_time_sec 0.02\nSTAT ps_system_time_sec 0.04\nSTAT ps_vsize 697741312\nSTAT ps_rss 10563584\nSTAT fibers_allocated 0\nSTAT fibers_pool_size 0\nSTAT fibers_stack_high_watermark 0\nSTAT successful_client_connections 18\nSTAT duration_us 0\nSTAT destination_max_pending_reqs 0\nSTAT destination_max_inflight_reqs 0\nSTAT retrans_per_kbyte_max 0\nSTAT cmd_get_count 0\nSTAT cmd_delete_out 0\nSTAT cmd_lease_get 0\nSTAT cmd_set 0\nSTAT cmd_get_out_all 0\nSTAT cmd_get_out 0\nSTAT cmd_lease_set_count 0\nSTAT cmd_other_out_all 0\nSTAT cmd_lease_get_out 0\nSTAT cmd_set_count 0\nSTAT cmd_lease_set_out 0\nSTAT cmd_delete_count 0\nSTAT cmd_other 0\nSTAT cmd_delete 0\nSTAT cmd_get 0\nSTAT cmd_lease_set 0\nSTAT cmd_set_out 0\nSTAT cmd_lease_get_count 0\nSTAT cmd_other_out 0\nSTAT cmd_lease_get_out_all 0\nSTAT cmd_set_out_all 0\nSTAT cmd_other_count 0\nSTAT cmd_delete_out_all 0\nSTAT cmd_lease_set_out_all 0\nEND\n"
  },
  {
    "path": "plugins/inputs/mdstat/README.md",
    "content": "# MD RAID Statistics Input Plugin\n\nThis plugin gathers statistics about any [Linux MD RAID arrays][mdraid]\nconfigured on the host by reading `/proc/mdstat`. For a full list of available\nfields see the `/proc/mdstat` section of the [proc man page][man_proc]. For\ndetails on the fields check the [mdstat wiki][mdstat_wiki].\n\n⭐ Telegraf v1.20.0\n🏷️ system\n💻 linux\n\n[mdraid]: https://docs.kernel.org/admin-guide/md.html\n[man_proc]: http://man7.org/linux/man-pages/man5/proc.5.html\n[mdstat_wiki]: https://raid.wiki.kernel.org/index.php/Mdstat\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get kernel statistics from /proc/mdstat\n# This plugin ONLY supports Linux\n[[inputs.mdstat]]\n  ## Sets file path\n  ## If not specified, then default is /proc/mdstat\n  # file_name = \"/proc/mdstat\"\n```\n\n## Metrics\n\n- `mdstat` metric\n  - tags:\n    - ActivityState (`active` or `inactive`)\n    - Devices (comma separated list of devices that make up the array)\n    - Name (name of the array)\n  - fields:\n    - BlocksSynced (if the array is rebuilding/checking, this is the count of\n      blocks that have been scanned)\n    - BlocksSyncedFinishTime (the expected finish time of the rebuild scan,\n      listed in minutes remaining)\n    - BlocksSyncedPct (the percentage of the rebuild scan left)\n    - BlocksSyncedSpeed (the current speed the rebuild is running at, listed\n      in K/sec)\n    - BlocksTotal (the total count of blocks in the array)\n    - DisksActive (the number of disks that are currently considered healthy\n      in the array)\n    - DisksFailed (the current count of failed disks in the array)\n    - DisksSpare (the current count of \"spare\" disks in the array)\n    - DisksTotal (total count of disks in the array)\n\n## Example Output\n\n```text\nmdstat,ActivityState=active,Devices=sdm1\\,sdn1,Name=md1 BlocksSynced=231299072i,BlocksSyncedFinishTime=0,BlocksSyncedPct=0,BlocksSyncedSpeed=0,BlocksTotal=231299072i,DisksActive=2i,DisksFailed=0i,DisksSpare=0i,DisksTotal=2i,DisksDown=0i 1617814276000000000\nmdstat,ActivityState=active,Devices=sdm5\\,sdn5,Name=md2 BlocksSynced=2996224i,BlocksSyncedFinishTime=0,BlocksSyncedPct=0,BlocksSyncedSpeed=0,BlocksTotal=2996224i,DisksActive=2i,DisksFailed=0i,DisksSpare=0i,DisksTotal=2i,DisksDown=0i 1617814276000000000\n```\n"
  },
  {
    "path": "plugins/inputs/mdstat/mdstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\n// Copyright 2018 The Prometheus Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Code has been changed since initial import.\n\npackage mdstat\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tstatusLineRE         = regexp.MustCompile(`(\\d+) blocks .*\\[(\\d+)/(\\d+)\\] \\[([U_]+)\\]`)\n\trecoveryLineBlocksRE = regexp.MustCompile(`\\((\\d+)/\\d+\\)`)\n\trecoveryLinePctRE    = regexp.MustCompile(`= +(.+)%`)\n\trecoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)\n\trecoveryLineSpeedRE  = regexp.MustCompile(`speed=(.+)[A-Z]`)\n\tcomponentDeviceRE    = regexp.MustCompile(`(.*)\\[\\d+\\]`)\n)\n\ntype Mdstat struct {\n\tFileName string `toml:\"file_name\"`\n}\n\ntype statusLine struct {\n\tactive int64\n\ttotal  int64\n\tsize   int64\n\tdown   int64\n}\n\ntype recoveryLine struct {\n\tsyncedBlocks int64\n\tpct          float64\n\tfinish       float64\n\tspeed        float64\n}\n\nfunc evalStatusLine(deviceLine, statusLineStr string) (statusLine, error) {\n\tsizeFields := strings.Fields(statusLineStr)\n\tif len(sizeFields) < 1 {\n\t\treturn statusLine{active: 0, total: 0, down: 0, size: 0},\n\t\t\tfmt.Errorf(\"statusLine empty? %q\", statusLineStr)\n\t}\n\tsizeStr := sizeFields[0]\n\tsize, err := strconv.ParseInt(sizeStr, 10, 64)\n\tif err != nil {\n\t\treturn statusLine{active: 0, total: 0, down: 0, size: 0},\n\t\t\tfmt.Errorf(\"unexpected statusLine %q: %w\", statusLineStr, err)\n\t}\n\n\tif strings.Contains(deviceLine, \"raid0\") || strings.Contains(deviceLine, \"linear\") {\n\t\t// In the device deviceLine, only disks have a number associated with them in [].\n\t\ttotal := int64(strings.Count(deviceLine, \"[\"))\n\t\treturn statusLine{active: total, total: total, down: 0, size: size}, nil\n\t}\n\n\tif strings.Contains(deviceLine, \"inactive\") {\n\t\treturn statusLine{active: 0, total: 0, down: 0, size: size}, nil\n\t}\n\n\tmatches := statusLineRE.FindStringSubmatch(statusLineStr)\n\tif len(matches) != 5 {\n\t\treturn statusLine{active: 0, total: 0, down: 0, size: size},\n\t\t\tfmt.Errorf(\"couldn't find all the substring matches: %s\", statusLineStr)\n\t}\n\ttotal, err := strconv.ParseInt(matches[2], 10, 64)\n\tif err != nil {\n\t\treturn statusLine{active: 0, total: 0, down: 0, size: size},\n\t\t\tfmt.Errorf(\"unexpected statusLine %q: %w\", statusLineStr, err)\n\t}\n\tactive, err := strconv.ParseInt(matches[3], 10, 64)\n\tif err != nil {\n\t\treturn statusLine{active: 0, total: total, down: 0, size: size},\n\t\t\tfmt.Errorf(\"unexpected statusLine %q: %w\", statusLineStr, err)\n\t}\n\tdown := int64(strings.Count(matches[4], \"_\"))\n\n\treturn statusLine{active: active, total: total, size: size, down: down}, nil\n}\n\nfunc evalRecoveryLine(recoveryLineStr string) (recoveryLine, error) {\n\t// Get count of completed vs. total blocks\n\tmatches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLineStr)\n\tif len(matches) != 2 {\n\t\treturn recoveryLine{syncedBlocks: 0, pct: 0, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"unexpected recoveryLine matching syncedBlocks: %s\", recoveryLineStr)\n\t}\n\tsyncedBlocks, err := strconv.ParseInt(matches[1], 10, 64)\n\tif err != nil {\n\t\treturn recoveryLine{syncedBlocks: 0, pct: 0, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"error parsing int from recoveryLine %q: %w\", recoveryLineStr, err)\n\t}\n\n\t// Get percentage complete\n\tmatches = recoveryLinePctRE.FindStringSubmatch(recoveryLineStr)\n\tif len(matches) != 2 {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: 0, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"unexpected recoveryLine matching percentage: %s\", recoveryLineStr)\n\t}\n\tpct, err := strconv.ParseFloat(matches[1], 64)\n\tif err != nil {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: 0, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"error parsing float from recoveryLine %q: %w\", recoveryLineStr, err)\n\t}\n\n\t// Get time expected left to complete\n\tmatches = recoveryLineFinishRE.FindStringSubmatch(recoveryLineStr)\n\tif len(matches) != 2 {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: pct, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"unexpected recoveryLine matching est. finish time: %s\", recoveryLineStr)\n\t}\n\tfinish, err := strconv.ParseFloat(matches[1], 64)\n\tif err != nil {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: pct, finish: 0, speed: 0},\n\t\t\tfmt.Errorf(\"error parsing float from recoveryLine %q: %w\", recoveryLineStr, err)\n\t}\n\n\t// Get recovery speed\n\tmatches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLineStr)\n\tif len(matches) != 2 {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: pct, finish: finish, speed: 0},\n\t\t\tfmt.Errorf(\"unexpected recoveryLine matching speed: %s\", recoveryLineStr)\n\t}\n\tspeed, err := strconv.ParseFloat(matches[1], 64)\n\tif err != nil {\n\t\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: pct, finish: finish, speed: 0},\n\t\t\tfmt.Errorf(\"error parsing float from recoveryLine %q: %w\", recoveryLineStr, err)\n\t}\n\treturn recoveryLine{syncedBlocks: syncedBlocks, pct: pct, finish: finish, speed: speed}, nil\n}\n\nfunc evalComponentDevices(deviceFields []string) string {\n\tmdComponentDevices := make([]string, 0)\n\tif len(deviceFields) > 3 {\n\t\tfor _, field := range deviceFields[4:] {\n\t\t\tmatch := componentDeviceRE.FindStringSubmatch(field)\n\t\t\tif match == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmdComponentDevices = append(mdComponentDevices, match[1])\n\t\t}\n\t}\n\n\t// Ensure no churn on tag ordering change\n\tsort.Strings(mdComponentDevices)\n\treturn strings.Join(mdComponentDevices, \",\")\n}\n\nfunc (*Mdstat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (k *Mdstat) Gather(acc telegraf.Accumulator) error {\n\tdata, err := k.getProcMdstat()\n\tif err != nil {\n\t\treturn err\n\t}\n\tlines := strings.Split(string(data), \"\\n\")\n\t// empty file should return nothing\n\tif len(lines) < 3 {\n\t\treturn nil\n\t}\n\tfor i, line := range lines {\n\t\tif strings.TrimSpace(line) == \"\" || line[0] == ' ' || strings.HasPrefix(line, \"Personalities\") || strings.HasPrefix(line, \"unused\") {\n\t\t\tcontinue\n\t\t}\n\t\tdeviceFields := strings.Fields(line)\n\t\tif len(deviceFields) < 3 || len(lines) <= i+3 {\n\t\t\treturn fmt.Errorf(\"not enough fields in mdline (expected at least 3): %s\", line)\n\t\t}\n\t\tmdName := deviceFields[0] // mdx\n\t\tstate := deviceFields[2]  // active or inactive\n\n\t\t/*\n\t\t\tFailed disks have the suffix (F) & Spare disks have the suffix (S).\n\t\t\tFailed disks may also not be marked separately...\n\t\t*/\n\t\tfail := int64(strings.Count(line, \"(F)\"))\n\t\tspare := int64(strings.Count(line, \"(S)\"))\n\n\t\tsts, err := evalStatusLine(lines[i], lines[i+1])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing md device lines: %w\", err)\n\t\t}\n\n\t\tsyncLineIdx := i + 2\n\t\tif strings.Contains(lines[i+2], \"bitmap\") { // skip bitmap line\n\t\t\tsyncLineIdx++\n\t\t}\n\n\t\tvar rcvry recoveryLine\n\t\t// If device is syncing at the moment, get the number of currently\n\t\t// synced bytes, otherwise that number equals the size of the device.\n\t\trcvry.syncedBlocks = sts.size\n\t\trecovering := strings.Contains(lines[syncLineIdx], \"recovery\")\n\t\tresyncing := strings.Contains(lines[syncLineIdx], \"resync\")\n\t\tchecking := strings.Contains(lines[syncLineIdx], \"check\")\n\n\t\t// Append recovery and resyncing state info.\n\t\tif recovering || resyncing || checking {\n\t\t\tif recovering {\n\t\t\t\tstate = \"recovering\"\n\t\t\t} else if checking {\n\t\t\t\tstate = \"checking\"\n\t\t\t} else {\n\t\t\t\tstate = \"resyncing\"\n\t\t\t}\n\n\t\t\t// Handle case when resync=PENDING or resync=DELAYED.\n\t\t\tif strings.Contains(lines[syncLineIdx], \"PENDING\") || strings.Contains(lines[syncLineIdx], \"DELAYED\") {\n\t\t\t\trcvry.syncedBlocks = 0\n\t\t\t} else {\n\t\t\t\tvar err error\n\t\t\t\trcvry, err = evalRecoveryLine(lines[syncLineIdx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error parsing sync line in md device %q: %w\", mdName, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"DisksActive\":            sts.active,\n\t\t\t\"DisksFailed\":            fail,\n\t\t\t\"DisksSpare\":             spare,\n\t\t\t\"DisksTotal\":             sts.total,\n\t\t\t\"DisksDown\":              sts.down,\n\t\t\t\"BlocksTotal\":            sts.size,\n\t\t\t\"BlocksSynced\":           rcvry.syncedBlocks,\n\t\t\t\"BlocksSyncedPct\":        rcvry.pct,\n\t\t\t\"BlocksSyncedFinishTime\": rcvry.finish,\n\t\t\t\"BlocksSyncedSpeed\":      rcvry.speed,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"Name\":          mdName,\n\t\t\t\"ActivityState\": state,\n\t\t\t\"Devices\":       evalComponentDevices(deviceFields),\n\t\t}\n\t\tacc.AddFields(\"mdstat\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (k *Mdstat) getProcMdstat() ([]byte, error) {\n\tvar mdStatFile string\n\tif k.FileName == \"\" {\n\t\tmdStatFile = internal.GetProcPath() + \"/mdstat\"\n\t} else {\n\t\tmdStatFile = k.FileName\n\t}\n\tif _, err := os.Stat(mdStatFile); os.IsNotExist(err) {\n\t\treturn nil, fmt.Errorf(\"mdstat: %s does not exist\", mdStatFile)\n\t} else if err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := os.ReadFile(mdStatFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc init() {\n\tinputs.Add(\"mdstat\", func() telegraf.Input { return &Mdstat{} })\n}\n"
  },
  {
    "path": "plugins/inputs/mdstat/mdstat_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage mdstat\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Mdstat struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Mdstat) SampleConfig() string { return sampleConfig }\n\nfunc (m *Mdstat) Init() error {\n\tm.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Mdstat) Gather(telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"mdstat\", func() telegraf.Input {\n\t\treturn &Mdstat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mdstat/mdstat_test.go",
    "content": "//go:build linux\n\npackage mdstat\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFullMdstatProcFile(t *testing.T) {\n\tfilename := makeFakeMDStatFile([]byte(mdStatFileFull))\n\tdefer os.Remove(filename)\n\tk := Mdstat{\n\t\tFileName: filename,\n\t}\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"BlocksSynced\":           int64(10620027200),\n\t\t\"BlocksSyncedFinishTime\": float64(101.6),\n\t\t\"BlocksSyncedPct\":        float64(94.3),\n\t\t\"BlocksSyncedSpeed\":      float64(103517),\n\t\t\"BlocksTotal\":            int64(11251451904),\n\t\t\"DisksActive\":            int64(12),\n\t\t\"DisksFailed\":            int64(0),\n\t\t\"DisksSpare\":             int64(0),\n\t\t\"DisksTotal\":             int64(12),\n\t\t\"DisksDown\":              int64(0),\n\t}\n\tacc.AssertContainsFields(t, \"mdstat\", fields)\n}\n\nfunc TestMdstatSyncStart(t *testing.T) {\n\tfilename := makeFakeMDStatFile([]byte(mdStatSyncStart))\n\tdefer os.Remove(filename)\n\tk := Mdstat{\n\t\tFileName: filename,\n\t}\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"BlocksSynced\":           int64(10620027200),\n\t\t\"BlocksSyncedFinishTime\": float64(101.6),\n\t\t\"BlocksSyncedPct\":        float64(1.5),\n\t\t\"BlocksSyncedSpeed\":      float64(103517),\n\t\t\"BlocksTotal\":            int64(11251451904),\n\t\t\"DisksActive\":            int64(12),\n\t\t\"DisksFailed\":            int64(0),\n\t\t\"DisksSpare\":             int64(0),\n\t\t\"DisksTotal\":             int64(12),\n\t\t\"DisksDown\":              int64(0),\n\t}\n\tacc.AssertContainsFields(t, \"mdstat\", fields)\n}\n\nfunc TestFailedDiskMdStatProcFile1(t *testing.T) {\n\tfilename := makeFakeMDStatFile([]byte(mdStatFileFailedDisk))\n\tdefer os.Remove(filename)\n\n\tk := Mdstat{\n\t\tFileName: filename,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"BlocksSynced\":           int64(5860144128),\n\t\t\"BlocksSyncedFinishTime\": float64(0),\n\t\t\"BlocksSyncedPct\":        float64(0),\n\t\t\"BlocksSyncedSpeed\":      float64(0),\n\t\t\"BlocksTotal\":            int64(5860144128),\n\t\t\"DisksActive\":            int64(3),\n\t\t\"DisksFailed\":            int64(0),\n\t\t\"DisksSpare\":             int64(0),\n\t\t\"DisksTotal\":             int64(4),\n\t\t\"DisksDown\":              int64(1),\n\t}\n\tacc.AssertContainsFields(t, \"mdstat\", fields)\n}\n\nfunc TestEmptyMdStatProcFile1(t *testing.T) {\n\tfilename := makeFakeMDStatFile([]byte(mdStatFileEmpty))\n\tdefer os.Remove(filename)\n\n\tk := Mdstat{\n\t\tFileName: filename,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.NoError(t, err)\n}\n\nfunc TestInvalidMdStatProcFile1(t *testing.T) {\n\tfilename := makeFakeMDStatFile([]byte(mdStatFileInvalid))\n\tdefer os.Remove(filename)\n\n\tk := Mdstat{\n\t\tFileName: filename,\n\t}\n\n\tacc := testutil.Accumulator{}\n\terr := k.Gather(&acc)\n\trequire.Error(t, err)\n}\n\nconst mdStatFileFull = `\nPersonalities : [raid1] [raid10] [linear] [multipath] [raid0] [raid6] [raid5] [raid4]\nmd2 : active raid10 sde[2] sdl[9] sdf[3] sdk[8] sdh[5] sdd[1] sdg[4] sdn[11] sdm[10] sdj[7] sdc[0] sdi[6]\n      11251451904 blocks super 1.2 512K chunks 2 near-copies [12/12] [UUUUUUUUUUUU]\n      [==================>..]  check = 94.3% (10620027200/11251451904) finish=101.6min speed=103517K/sec\n      bitmap: 35/84 pages [140KB], 65536KB chunk\n\nmd1 : active raid1 sdb2[2] sda2[0]\n      5909504 blocks super 1.2 [2/2] [UU]\n\nmd0 : active raid1 sdb1[2] sda1[0]\n      244005888 blocks super 1.2 [2/2] [UU]\n      bitmap: 1/2 pages [4KB], 65536KB chunk\n\nunused devices: <none>\n`\n\nconst mdStatSyncStart = `\nPersonalities : [raid1] [raid10] [linear] [multipath] [raid0] [raid6] [raid5] [raid4]\nmd2 : active raid10 sde[2] sdl[9] sdf[3] sdk[8] sdh[5] sdd[1] sdg[4] sdn[11] sdm[10] sdj[7] sdc[0] sdi[6]\n      11251451904 blocks super 1.2 512K chunks 2 near-copies [12/12] [UUUUUUUUUUUU]\n      [>....................]  check =  1.5% (10620027200/11251451904) finish=101.6min speed=103517K/sec\n      bitmap: 35/84 pages [140KB], 65536KB chunk\n\nmd1 : active raid1 sdb2[2] sda2[0]\n      5909504 blocks super 1.2 [2/2] [UU]\n\nmd0 : active raid1 sdb1[2] sda1[0]\n      244005888 blocks super 1.2 [2/2] [UU]\n      bitmap: 1/2 pages [4KB], 65536KB chunk\n\nunused devices: <none>\n`\n\nconst mdStatFileFailedDisk = `\nPersonalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]\nmd0 : active raid5 sdd1[3] sdb1[1] sda1[0]\n      5860144128 blocks super 1.2 level 5, 64k chunk, algorithm 2 [4/3] [UUU_]\n      bitmap: 8/15 pages [32KB], 65536KB chunk\n\nunused devices: <none>\n`\n\nconst mdStatFileEmpty = `\nPersonalities :\nunused devices: <none>\n`\n\nconst mdStatFileInvalid = `\nPersonalities :\n\nmdf1: testman actve\n\nmd0 : active raid1 sdb1[2] sda1[0]\n      244005888 blocks super 1.2 [2/2] [UU]\n      bitmap: 1/2 pages [4KB], 65536KB chunk\n\nunused devices: <none>\n`\n\nfunc makeFakeMDStatFile(content []byte) (filename string) {\n\tfileobj, err := os.CreateTemp(\"\", \"mdstat\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif _, err = fileobj.Write(content); err != nil {\n\t\tpanic(err)\n\t}\n\tif err := fileobj.Close(); err != nil {\n\t\tpanic(err)\n\t}\n\treturn fileobj.Name()\n}\n"
  },
  {
    "path": "plugins/inputs/mdstat/sample.conf",
    "content": "# Get kernel statistics from /proc/mdstat\n# This plugin ONLY supports Linux\n[[inputs.mdstat]]\n  ## Sets file path\n  ## If not specified, then default is /proc/mdstat\n  # file_name = \"/proc/mdstat\"\n"
  },
  {
    "path": "plugins/inputs/mem/README.md",
    "content": "# Memory Input Plugin\n\nThis plugin collects metrics about the system memory.\n\n> [!TIP]\n> For an explanation of the difference between *used* and *actual_used*\n> RAM, see [Linux ate my ram][linux_ate_my_ram].\n\n⭐ Telegraf v0.1.5\n🏷️ system\n💻 all\n\n[linux_ate_my_ram]: http://www.linuxatemyram.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics about memory usage\n[[inputs.mem]]\n  # no configuration\n```\n\n## Metrics\n\nAvailable fields are dependent on platform.\n\n- mem\n  - fields:\n    - active (integer, Darwin, FreeBSD, Linux, OpenBSD)\n    - available (integer)\n    - available_percent (float)\n    - buffered (integer, FreeBSD, Linux)\n    - cached (integer, FreeBSD, Linux, OpenBSD)\n    - commit_limit (integer, Linux)\n    - committed_as (integer, Linux)\n    - dirty (integer, Linux)\n    - free (integer, Darwin, FreeBSD, Linux, OpenBSD)\n    - high_free (integer, Linux)\n    - high_total (integer, Linux)\n    - huge_pages_free (integer, Linux)\n    - huge_page_size (integer, Linux)\n    - huge_pages_total (integer, Linux)\n    - inactive (integer, Darwin, FreeBSD, Linux, OpenBSD)\n    - laundry (integer, FreeBSD)\n    - low_free (integer, Linux)\n    - low_total (integer, Linux)\n    - mapped (integer, Linux)\n    - page_tables (integer, Linux)\n    - shared (integer, Linux)\n    - slab (integer, Linux)\n    - sreclaimable (integer, Linux)\n    - sunreclaim (integer, Linux)\n    - swap_cached (integer, Linux)\n    - swap_free (integer, Linux)\n    - swap_total (integer, Linux)\n    - total (integer)\n    - used (integer)\n    - used_percent (float)\n    - vmalloc_chunk (integer, Linux)\n    - vmalloc_total (integer, Linux)\n    - vmalloc_used (integer, Linux)\n    - wired (integer, Darwin, FreeBSD, OpenBSD)\n    - write_back (integer, Linux)\n    - write_back_tmp (integer, Linux)\n\n## Example Output\n\n```text\nmem active=9299595264i,available=16818249728i,available_percent=80.41654254645131,buffered=2383761408i,cached=13316689920i,commit_limit=14751920128i,committed_as=11781156864i,dirty=122880i,free=1877688320i,high_free=0i,high_total=0i,huge_page_size=2097152i,huge_pages_free=0i,huge_pages_total=0i,inactive=7549939712i,low_free=0i,low_total=0i,mapped=416763904i,page_tables=19787776i,shared=670679040i,slab=2081071104i,sreclaimable=1923395584i,sunreclaim=157675520i,swap_cached=1302528i,swap_free=4286128128i,swap_total=4294963200i,total=20913917952i,used=3335778304i,used_percent=15.95004011996231,vmalloc_chunk=0i,vmalloc_total=35184372087808i,vmalloc_used=0i,wired=0i,write_back=0i,write_back_tmp=0i 1574712869000000000\n```\n"
  },
  {
    "path": "plugins/inputs/mem/mem.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mem\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"runtime\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Mem struct {\n\tps       psutil.PS\n\tplatform string\n}\n\nfunc (*Mem) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ms *Mem) Init() error {\n\tms.platform = runtime.GOOS\n\treturn nil\n}\n\nfunc (ms *Mem) Gather(acc telegraf.Accumulator) error {\n\tvm, err := ms.ps.VMStat()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting virtual memory info: %w\", err)\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"total\":             vm.Total,\n\t\t\"available\":         vm.Available,\n\t\t\"used\":              vm.Used,\n\t\t\"used_percent\":      100 * float64(vm.Used) / float64(vm.Total),\n\t\t\"available_percent\": 100 * float64(vm.Available) / float64(vm.Total),\n\t}\n\n\tswitch ms.platform {\n\tcase \"darwin\":\n\t\tfields[\"active\"] = vm.Active\n\t\tfields[\"free\"] = vm.Free\n\t\tfields[\"inactive\"] = vm.Inactive\n\t\tfields[\"wired\"] = vm.Wired\n\tcase \"openbsd\":\n\t\tfields[\"active\"] = vm.Active\n\t\tfields[\"cached\"] = vm.Buffers\n\t\tfields[\"free\"] = vm.Free\n\t\tfields[\"inactive\"] = vm.Inactive\n\t\tfields[\"wired\"] = vm.Wired\n\tcase \"freebsd\":\n\t\tfields[\"active\"] = vm.Active\n\t\tfields[\"buffered\"] = vm.Buffers\n\t\tfields[\"cached\"] = vm.Cached\n\t\tfields[\"free\"] = vm.Free\n\t\tfields[\"inactive\"] = vm.Inactive\n\t\tfields[\"laundry\"] = vm.Laundry\n\t\tfields[\"wired\"] = vm.Wired\n\tcase \"linux\":\n\t\tfields[\"active\"] = vm.Active\n\t\tfields[\"buffered\"] = vm.Buffers\n\t\tfields[\"cached\"] = vm.Cached\n\t\tfields[\"commit_limit\"] = vm.CommitLimit\n\t\tfields[\"committed_as\"] = vm.CommittedAS\n\t\tfields[\"dirty\"] = vm.Dirty\n\t\tfields[\"free\"] = vm.Free\n\t\tfields[\"high_free\"] = vm.HighFree\n\t\tfields[\"high_total\"] = vm.HighTotal\n\t\tfields[\"huge_pages_free\"] = vm.HugePagesFree\n\t\tfields[\"huge_page_size\"] = vm.HugePageSize\n\t\tfields[\"huge_pages_total\"] = vm.HugePagesTotal\n\t\tfields[\"inactive\"] = vm.Inactive\n\t\tfields[\"low_free\"] = vm.LowFree\n\t\tfields[\"low_total\"] = vm.LowTotal\n\t\tfields[\"mapped\"] = vm.Mapped\n\t\tfields[\"page_tables\"] = vm.PageTables\n\t\tfields[\"shared\"] = vm.Shared\n\t\tfields[\"slab\"] = vm.Slab\n\t\tfields[\"sreclaimable\"] = vm.Sreclaimable\n\t\tfields[\"sunreclaim\"] = vm.Sunreclaim\n\t\tfields[\"swap_cached\"] = vm.SwapCached\n\t\tfields[\"swap_free\"] = vm.SwapFree\n\t\tfields[\"swap_total\"] = vm.SwapTotal\n\t\tfields[\"vmalloc_chunk\"] = vm.VmallocChunk\n\t\tfields[\"vmalloc_total\"] = vm.VmallocTotal\n\t\tfields[\"vmalloc_used\"] = vm.VmallocUsed\n\t\tfields[\"write_back_tmp\"] = vm.WriteBackTmp\n\t\tfields[\"write_back\"] = vm.WriteBack\n\t}\n\n\tacc.AddGauge(\"mem\", fields, nil)\n\n\treturn nil\n}\n\nfunc init() {\n\tps := psutil.NewSystemPS()\n\tinputs.Add(\"mem\", func() telegraf.Input {\n\t\treturn &Mem{ps: ps}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mem/mem_test.go",
    "content": "package mem\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/mem\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMemStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tvar err error\n\tdefer mps.AssertExpectations(t)\n\tvar acc testutil.Accumulator\n\n\tvms := &mem.VirtualMemoryStat{\n\t\tTotal:     12400,\n\t\tAvailable: 7600,\n\t\tUsed:      5000,\n\t\tFree:      1235,\n\t\tActive:    8134,\n\t\tInactive:  1124,\n\t\tSlab:      1234,\n\t\tWired:     134,\n\t\t// Buffers:     771,\n\t\t// Cached:      4312,\n\t\t// Shared:      2142,\n\t\tCommitLimit:    1,\n\t\tCommittedAS:    118680,\n\t\tDirty:          4,\n\t\tHighFree:       0,\n\t\tHighTotal:      0,\n\t\tHugePageSize:   4096,\n\t\tHugePagesFree:  0,\n\t\tHugePagesTotal: 0,\n\t\tLowFree:        69936,\n\t\tLowTotal:       255908,\n\t\tMapped:         42236,\n\t\tPageTables:     1236,\n\t\tShared:         0,\n\t\tSreclaimable:   1923022848,\n\t\tSunreclaim:     157728768,\n\t\tSwapCached:     0,\n\t\tSwapFree:       524280,\n\t\tSwapTotal:      524280,\n\t\tVmallocChunk:   3872908,\n\t\tVmallocTotal:   3874808,\n\t\tVmallocUsed:    1416,\n\t\tWriteBack:      0,\n\t\tWriteBackTmp:   0,\n\t}\n\n\tmps.On(\"VMStat\").Return(vms, nil)\n\tplugin := &Mem{ps: &mps}\n\n\terr = plugin.Init()\n\trequire.NoError(t, err)\n\n\tplugin.platform = \"linux\"\n\n\trequire.NoError(t, err)\n\terr = plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"mem\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"total\":             uint64(12400),\n\t\t\t\t\"available\":         uint64(7600),\n\t\t\t\t\"used\":              uint64(5000),\n\t\t\t\t\"available_percent\": float64(7600) / float64(12400) * 100,\n\t\t\t\t\"used_percent\":      float64(5000) / float64(12400) * 100,\n\t\t\t\t\"free\":              uint64(1235),\n\t\t\t\t\"cached\":            uint64(0),\n\t\t\t\t\"buffered\":          uint64(0),\n\t\t\t\t\"active\":            uint64(8134),\n\t\t\t\t\"inactive\":          uint64(1124),\n\t\t\t\t// \"wired\":             uint64(134),\n\t\t\t\t\"slab\":             uint64(1234),\n\t\t\t\t\"commit_limit\":     uint64(1),\n\t\t\t\t\"committed_as\":     uint64(118680),\n\t\t\t\t\"dirty\":            uint64(4),\n\t\t\t\t\"high_free\":        uint64(0),\n\t\t\t\t\"high_total\":       uint64(0),\n\t\t\t\t\"huge_page_size\":   uint64(4096),\n\t\t\t\t\"huge_pages_free\":  uint64(0),\n\t\t\t\t\"huge_pages_total\": uint64(0),\n\t\t\t\t\"low_free\":         uint64(69936),\n\t\t\t\t\"low_total\":        uint64(255908),\n\t\t\t\t\"mapped\":           uint64(42236),\n\t\t\t\t\"page_tables\":      uint64(1236),\n\t\t\t\t\"shared\":           uint64(0),\n\t\t\t\t\"sreclaimable\":     uint64(1923022848),\n\t\t\t\t\"sunreclaim\":       uint64(157728768),\n\t\t\t\t\"swap_cached\":      uint64(0),\n\t\t\t\t\"swap_free\":        uint64(524280),\n\t\t\t\t\"swap_total\":       uint64(524280),\n\t\t\t\t\"vmalloc_chunk\":    uint64(3872908),\n\t\t\t\t\"vmalloc_total\":    uint64(3874808),\n\t\t\t\t\"vmalloc_used\":     uint64(1416),\n\t\t\t\t\"write_back\":       uint64(0),\n\t\t\t\t\"write_back_tmp\":   uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/mem/sample.conf",
    "content": "# Read metrics about memory usage\n[[inputs.mem]]\n  # no configuration\n"
  },
  {
    "path": "plugins/inputs/memcached/README.md",
    "content": "# Memcached Input Plugin\n\nThis plugin gathers statistics data from [Memcached][memcached] instances.\n\n⭐ Telegraf v0.1.2\n🏷️ server\n💻 all\n\n[memcached]: https://memcached.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many memcached servers.\n[[inputs.memcached]]\n  # An array of address to gather stats about. Specify an ip on hostname\n  # with optional port. ie localhost, 10.0.0.1:11211, etc.\n  servers = [\"localhost:11211\"]\n  # An array of unix memcached sockets to gather stats about.\n  # unix_sockets = [\"/var/run/memcached.sock\"]\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## If false, skip chain & host verification\n  # insecure_skip_verify = true\n```\n\n## Metrics\n\nThe fields from this plugin are gathered in the *memcached* measurement.\n\nFields:\n\n* accepting_conns - Whether or not server is accepting conns\n* auth_cmds - Number of authentication commands handled, success or failure\n* auth_errors - Number of failed authentications\n* bytes - Current number of bytes used to store items\n* bytes_read - Total number of bytes read by this server from network\n* bytes_written - Total number of bytes sent by this server to network\n* cas_badval - Number of CAS reqs for which a key was found, but the CAS value\n  did not match\n* cas_hits - Number of successful CAS reqs\n* cas_misses - Number of CAS reqs against missing keys\n* cmd_flush - Cumulative number of flush reqs\n* cmd_get - Cumulative number of retrieval reqs\n* cmd_set - Cumulative number of storage reqs\n* cmd_touch - Cumulative number of touch reqs\n* conn_yields - Number of times any connection yielded to another due to\n  hitting the -R limit\n* connection_structures - Number of connection structures allocated by the\n  server\n* curr_connections - Number of open connections\n* curr_items - Current number of items stored\n* decr_hits - Number of successful decr reqs\n* decr_misses - Number of decr reqs against missing keys\n* delete_hits - Number of deletion reqs resulting in an item being removed\n* delete_misses - Number of deletions reqs for missing keys\n* evicted_active - Items evicted from LRU that had been hit recently but did\n  not jump to top of LRU\n* evicted_unfetched - Items evicted from LRU that were never touched by\n  get/incr/append/etc\n* evictions - Number of valid items removed from cache to free memory for\n  new items\n* expired_unfetched - Items pulled from LRU that were never touched by\n  get/incr/append/etc before expiring\n* extstore_compact_lost - The number of objects lost during the compaction\n                          process. This happens when objects couldn't be rescued\n                          or moved to other pages before they were overwritten\n                          or evicted.\n* extstore_compact_rescues - The total number of objects successfully rescued\n                             during the compaction process, meaning they were\n                             moved to another page instead of being discarded.\n* extstore_compact_resc_cold - The number of cold objects (rarely accessed)\n                               rescued during the compaction process.\n* extstore_compact_resc_old - The number of older objects (likely less\n                              frequently accessed) rescued during the compaction\n                              process.\n* extstore_compact_skipped - The number of compaction operations skipped, often\n                             due to the page not requiring compaction or other\n                             conditions preventing it.\n* extstore_page_allocs - The total number of pages allocated in the external\n                         storage system.\n* extstore_page_evictions - The total number of pages evicted (removed) from\n                            external storage, generally to free up space.\n* extstore_page_reclaims - The total number of previously evicted pages that\n                           were reclaimed and reused.\n* extstore_pages_free - The number of pages currently free (unallocated) in the\n                        external storage.\n* extstore_pages_used - The number of pages currently in use in the external\n                        storage system.\n* extstore_objects_evicted - The total number of objects evicted from external\n                             storage, typically to free up space.\n* extstore_objects_read - The total number of objects read from external storage.\n* extstore_objects_written - The total number of objects written to external storage.\n* extstore_objects_used - The number of active objects currently in use in the\n                          external storage.\n* extstore_bytes_evicted - The total number of bytes evicted from external storage.\n* extstore_bytes_written - The total number of bytes written to external storage.\n* extstore_bytes_read - The total number of bytes read from external storage.\n* extstore_bytes_used - The total number of bytes currently in use in external storage.\n* extstore_bytes_fragmented - The total number of fragmented bytes in external\n                              storage, representing space that is allocated but\n                              not fully utilized.\n* extstore_limit_maxbytes - The maximum limit of bytes that external storage can\n                            use.\n* extstore_io_queue - The current length of the I/O queue, representing pending\n                      input/output operations for external storage.\n* get_expired - Number of items that have been requested but had already\n  expired\n* get_flushed - Number of items that have been requested but have been flushed\n  via flush_all\n* get_hits - Number of keys that have been requested and found present\n* get_misses - Number of items that have been requested and not found\n* hash_bytes - Bytes currently used by hash tables\n* hash_is_expanding - Indicates if the hash table is being grown to a new size\n* hash_power_level - Current size multiplier for hash table\n* incr_hits - Number of successful incr reqs\n* incr_misses - Number of incr reqs against missing keys\n* limit_maxbytes - Number of bytes this server is allowed to use for storage\n* listen_disabled_num - Number of times server has stopped accepting new\n  connections (maxconns)\n* max_connections - Max number of simultaneous connections\n* reclaimed - Number of times an entry was stored using memory from an\n  expired entry\n* rejected_connections - Conns rejected in maxconns_fast mode\n* store_no_memory - Number of rejected storage requests caused by exhaustion\n  of the memory limit when evictions are disabled\n* store_too_large - Number of rejected storage requests caused by attempting\n  to write a value larger than the item size limit\n* threads - Number of worker threads requested\n* total_connections - Total number of connections opened since the server\n  started running\n* total_items - Total number of items stored since the server started\n* touch_hits - Number of keys that have been touched with a new expiration time\n* touch_misses - Number of items that have been touched and not found\n* uptime - Number of secs since the server started\n\nDescription of gathered fields taken from [memcached protocol docs][protocol].\n\n[protocol]: https://github.com/memcached/memcached/blob/master/doc/protocol.txt\n\n## Tags\n\n* Memcached measurements have the following tags:\n  * server (the host name from which metrics are gathered)\n\n## Sample Queries\n\nYou can use the following query to get the average get hit and miss ratio, as\nwell as the total average size of cached items, number of cached items and\naverage connection counts per server.\n\n```sql\nSELECT mean(get_hits) / mean(cmd_get) as get_ratio, mean(get_misses) / mean(cmd_get) as get_misses_ratio, mean(bytes), mean(curr_items), mean(curr_connections) FROM memcached WHERE time > now() - 1h GROUP BY server\n```\n\n## Example Output\n\n```text\nmemcached,server=localhost:11211 accepting_conns=1i,auth_cmds=0i,auth_errors=0i,bytes=0i,bytes_read=7i,bytes_written=0i,cas_badval=0i,cas_hits=0i,cas_misses=0i,cmd_flush=0i,cmd_get=0i,cmd_set=0i,cmd_touch=0i,conn_yields=0i,connection_structures=3i,curr_connections=2i,curr_items=0i,decr_hits=0i,decr_misses=0i,delete_hits=0i,delete_misses=0i,evicted_active=0i,evicted_unfetched=0i,evictions=0i,expired_unfetched=0i,get_expired=0i,get_flushed=0i,get_hits=0i,get_misses=0i,hash_bytes=524288i,hash_is_expanding=0i,hash_power_level=16i,incr_hits=0i,incr_misses=0i,limit_maxbytes=67108864i,listen_disabled_num=0i,max_connections=1024i,reclaimed=0i,rejected_connections=0i,store_no_memory=0i,store_too_large=0i,threads=4i,total_connections=3i,total_items=0i,touch_hits=0i,touch_misses=0i,uptime=3i 1644771989000000000\n```\n"
  },
  {
    "path": "plugins/inputs/memcached/memcached.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage memcached\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"golang.org/x/net/proxy\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultTimeout = 5 * time.Second\n\n\t// The list of metrics that should be sent\n\tsendMetrics = []string{\n\t\t\"accepting_conns\",\n\t\t\"auth_cmds\",\n\t\t\"auth_errors\",\n\t\t\"bytes\",\n\t\t\"bytes_read\",\n\t\t\"bytes_written\",\n\t\t\"cas_badval\",\n\t\t\"cas_hits\",\n\t\t\"cas_misses\",\n\t\t\"cmd_flush\",\n\t\t\"cmd_get\",\n\t\t\"cmd_set\",\n\t\t\"cmd_touch\",\n\t\t\"conn_yields\",\n\t\t\"connection_structures\",\n\t\t\"curr_connections\",\n\t\t\"curr_items\",\n\t\t\"decr_hits\",\n\t\t\"decr_misses\",\n\t\t\"delete_hits\",\n\t\t\"delete_misses\",\n\t\t\"evicted_active\",\n\t\t\"evicted_unfetched\",\n\t\t\"evictions\",\n\t\t\"expired_unfetched\",\n\t\t\"extstore_compact_lost\",\n\t\t\"extstore_compact_rescues\",\n\t\t\"extstore_compact_resc_cold\",\n\t\t\"extstore_compact_resc_old\",\n\t\t\"extstore_compact_skipped\",\n\t\t\"extstore_page_allocs\",\n\t\t\"extstore_page_evictions\",\n\t\t\"extstore_page_reclaims\",\n\t\t\"extstore_pages_free\",\n\t\t\"extstore_pages_used\",\n\t\t\"extstore_objects_evicted\",\n\t\t\"extstore_objects_read\",\n\t\t\"extstore_objects_written\",\n\t\t\"extstore_objects_used\",\n\t\t\"extstore_bytes_evicted\",\n\t\t\"extstore_bytes_written\",\n\t\t\"extstore_bytes_read\",\n\t\t\"extstore_bytes_used\",\n\t\t\"extstore_bytes_fragmented\",\n\t\t\"extstore_limit_maxbytes\",\n\t\t\"extstore_io_queue\",\n\t\t\"get_expired\",\n\t\t\"get_flushed\",\n\t\t\"get_hits\",\n\t\t\"get_misses\",\n\t\t\"hash_bytes\",\n\t\t\"hash_is_expanding\",\n\t\t\"hash_power_level\",\n\t\t\"incr_hits\",\n\t\t\"incr_misses\",\n\t\t\"limit_maxbytes\",\n\t\t\"listen_disabled_num\",\n\t\t\"max_connections\",\n\t\t\"reclaimed\",\n\t\t\"rejected_connections\",\n\t\t\"store_no_memory\",\n\t\t\"store_too_large\",\n\t\t\"threads\",\n\t\t\"total_connections\",\n\t\t\"total_items\",\n\t\t\"touch_hits\",\n\t\t\"touch_misses\",\n\t\t\"uptime\",\n\t}\n)\n\ntype Memcached struct {\n\tServers     []string `toml:\"servers\"`\n\tUnixSockets []string `toml:\"unix_sockets\"`\n\tEnableTLS   bool     `toml:\"enable_tls\"`\n\tcommon_tls.ClientConfig\n}\n\nfunc (*Memcached) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Memcached) Gather(acc telegraf.Accumulator) error {\n\tif len(m.Servers) == 0 && len(m.UnixSockets) == 0 {\n\t\treturn m.gatherServer(\":11211\", false, acc)\n\t}\n\n\tfor _, serverAddress := range m.Servers {\n\t\tacc.AddError(m.gatherServer(serverAddress, false, acc))\n\t}\n\n\tfor _, unixAddress := range m.UnixSockets {\n\t\tacc.AddError(m.gatherServer(unixAddress, true, acc))\n\t}\n\n\treturn nil\n}\n\nfunc (m *Memcached) gatherServer(address string, unix bool, acc telegraf.Accumulator) error {\n\tvar conn net.Conn\n\tvar err error\n\tvar dialer proxy.Dialer\n\n\tdialer = &net.Dialer{Timeout: defaultTimeout}\n\tif m.EnableTLS {\n\t\ttlsCfg, err := m.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdialer = &tls.Dialer{\n\t\t\tNetDialer: dialer.(*net.Dialer),\n\t\t\tConfig:    tlsCfg,\n\t\t}\n\t}\n\n\tif unix {\n\t\tconn, err = dialer.Dial(\"unix\", address)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer conn.Close()\n\t} else {\n\t\t_, _, err = net.SplitHostPort(address)\n\t\tif err != nil {\n\t\t\taddress = address + \":11211\"\n\t\t}\n\n\t\tconn, err = dialer.Dial(\"tcp\", address)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer conn.Close()\n\t}\n\n\tif conn == nil {\n\t\treturn errors.New(\"failed to create net connection\")\n\t}\n\n\t// Extend connection\n\tif err := conn.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\t// Read and write buffer\n\trw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))\n\n\t// Send command\n\tif _, err := fmt.Fprint(rw, \"stats\\r\\n\"); err != nil {\n\t\treturn err\n\t}\n\tif err := rw.Flush(); err != nil {\n\t\treturn err\n\t}\n\n\tvalues, err := parseResponse(rw.Reader)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Add server address as a tag\n\ttags := map[string]string{\"server\": address}\n\n\t// Process values\n\tfields := make(map[string]interface{})\n\tfor _, key := range sendMetrics {\n\t\tif value, ok := values[key]; ok {\n\t\t\t// Mostly it is the number\n\t\t\tif iValue, errParse := strconv.ParseInt(value, 10, 64); errParse == nil {\n\t\t\t\tfields[key] = iValue\n\t\t\t} else {\n\t\t\t\tfields[key] = value\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"memcached\", fields, tags)\n\treturn nil\n}\n\nfunc parseResponse(r *bufio.Reader) (map[string]string, error) {\n\tvalues := make(map[string]string)\n\n\tfor {\n\t\t// Read line\n\t\tline, _, errRead := r.ReadLine()\n\t\tif errRead != nil {\n\t\t\treturn values, errRead\n\t\t}\n\t\t// Done\n\t\tif bytes.Equal(line, []byte(\"END\")) {\n\t\t\tbreak\n\t\t}\n\t\t// Read values\n\t\ts := bytes.SplitN(line, []byte(\" \"), 3)\n\t\tif len(s) != 3 || !bytes.Equal(s[0], []byte(\"STAT\")) {\n\t\t\treturn values, fmt.Errorf(\"unexpected line in stats response: %q\", line)\n\t\t}\n\n\t\t// Save values\n\t\tvalues[string(s[1])] = string(s[2])\n\t}\n\treturn values, nil\n}\n\nfunc init() {\n\tinputs.Add(\"memcached\", func() telegraf.Input {\n\t\treturn &Memcached{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/memcached/memcached_test.go",
    "content": "package memcached\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMemcachedGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tservicePort := \"11211\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"memcached\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(nat.Port(servicePort)),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tm := &Memcached{\n\t\tServers: []string{fmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort])},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(m.Gather)\n\trequire.NoError(t, err)\n\n\tintMetrics := []string{\"get_hits\", \"get_misses\", \"evictions\",\n\t\t\"limit_maxbytes\", \"bytes\", \"uptime\", \"curr_items\", \"total_items\",\n\t\t\"curr_connections\", \"total_connections\", \"connection_structures\", \"cmd_get\",\n\t\t\"cmd_set\", \"delete_hits\", \"delete_misses\", \"incr_hits\", \"incr_misses\",\n\t\t\"decr_hits\", \"decr_misses\", \"cas_hits\", \"cas_misses\",\n\t\t\"bytes_read\", \"bytes_written\", \"threads\", \"conn_yields\"}\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"memcached\", metric), metric)\n\t}\n}\n\nfunc TestMemcachedParseMetrics(t *testing.T) {\n\tr := bufio.NewReader(strings.NewReader(memcachedStats))\n\tvalues, err := parseResponse(r)\n\trequire.NoError(t, err, \"Error parsing memcached response\")\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue string\n\t}{\n\t\t{\"pid\", \"5619\"},\n\t\t{\"uptime\", \"11\"},\n\t\t{\"time\", \"1644765868\"},\n\t\t{\"version\", \"1.6.14_5_ge03751b\"},\n\t\t{\"libevent\", \"2.1.11-stable\"},\n\t\t{\"pointer_size\", \"64\"},\n\t\t{\"rusage_user\", \"0.080905\"},\n\t\t{\"rusage_system\", \"0.059330\"},\n\t\t{\"max_connections\", \"1024\"},\n\t\t{\"curr_connections\", \"2\"},\n\t\t{\"total_connections\", \"3\"},\n\t\t{\"rejected_connections\", \"0\"},\n\t\t{\"connection_structures\", \"3\"},\n\t\t{\"response_obj_oom\", \"0\"},\n\t\t{\"response_obj_count\", \"1\"},\n\t\t{\"response_obj_bytes\", \"16384\"},\n\t\t{\"read_buf_count\", \"2\"},\n\t\t{\"read_buf_bytes\", \"32768\"},\n\t\t{\"read_buf_bytes_free\", \"0\"},\n\t\t{\"read_buf_oom\", \"0\"},\n\t\t{\"reserved_fds\", \"20\"},\n\t\t{\"cmd_get\", \"0\"},\n\t\t{\"cmd_set\", \"0\"},\n\t\t{\"cmd_flush\", \"0\"},\n\t\t{\"cmd_touch\", \"0\"},\n\t\t{\"cmd_meta\", \"0\"},\n\t\t{\"get_hits\", \"0\"},\n\t\t{\"get_misses\", \"0\"},\n\t\t{\"get_expired\", \"0\"},\n\t\t{\"get_flushed\", \"0\"},\n\t\t{\"delete_misses\", \"0\"},\n\t\t{\"delete_hits\", \"0\"},\n\t\t{\"incr_misses\", \"0\"},\n\t\t{\"incr_hits\", \"0\"},\n\t\t{\"decr_misses\", \"0\"},\n\t\t{\"decr_hits\", \"0\"},\n\t\t{\"cas_misses\", \"0\"},\n\t\t{\"cas_hits\", \"0\"},\n\t\t{\"cas_badval\", \"0\"},\n\t\t{\"touch_hits\", \"0\"},\n\t\t{\"touch_misses\", \"0\"},\n\t\t{\"store_too_large\", \"0\"},\n\t\t{\"store_no_memory\", \"0\"},\n\t\t{\"auth_cmds\", \"0\"},\n\t\t{\"auth_errors\", \"0\"},\n\t\t{\"bytes_read\", \"6\"},\n\t\t{\"bytes_written\", \"0\"},\n\t\t{\"limit_maxbytes\", \"67108864\"},\n\t\t{\"accepting_conns\", \"1\"},\n\t\t{\"listen_disabled_num\", \"0\"},\n\t\t{\"time_in_listen_disabled_us\", \"0\"},\n\t\t{\"threads\", \"4\"},\n\t\t{\"conn_yields\", \"0\"},\n\t\t{\"hash_power_level\", \"16\"},\n\t\t{\"hash_bytes\", \"524288\"},\n\t\t{\"hash_is_expanding\", \"0\"},\n\t\t{\"slab_reassign_rescues\", \"0\"},\n\t\t{\"slab_reassign_chunk_rescues\", \"0\"},\n\t\t{\"slab_reassign_evictions_nomem\", \"0\"},\n\t\t{\"slab_reassign_inline_reclaim\", \"0\"},\n\t\t{\"slab_reassign_busy_items\", \"0\"},\n\t\t{\"slab_reassign_busy_deletes\", \"0\"},\n\t\t{\"slab_reassign_running\", \"0\"},\n\t\t{\"slabs_moved\", \"0\"},\n\t\t{\"lru_crawler_running\", \"0\"},\n\t\t{\"lru_crawler_starts\", \"1\"},\n\t\t{\"lru_maintainer_juggles\", \"60\"},\n\t\t{\"malloc_fails\", \"0\"},\n\t\t{\"log_worker_dropped\", \"0\"},\n\t\t{\"log_worker_written\", \"0\"},\n\t\t{\"log_watcher_skipped\", \"0\"},\n\t\t{\"log_watcher_sent\", \"0\"},\n\t\t{\"log_watchers\", \"0\"},\n\t\t{\"extstore_compact_lost\", \"3287\"},\n\t\t{\"extstore_compact_rescues\", \"47014\"},\n\t\t{\"extstore_compact_resc_cold\", \"0\"},\n\t\t{\"extstore_compact_resc_old\", \"0\"},\n\t\t{\"extstore_compact_skipped\", \"0\"},\n\t\t{\"extstore_page_allocs\", \"30047\"},\n\t\t{\"extstore_page_evictions\", \"25315\"},\n\t\t{\"extstore_page_reclaims\", \"29247\"},\n\t\t{\"extstore_pages_free\", \"0\"},\n\t\t{\"extstore_pages_used\", \"800\"},\n\t\t{\"extstore_objects_evicted\", \"1243091\"},\n\t\t{\"extstore_objects_read\", \"938410\"},\n\t\t{\"extstore_objects_written\", \"1487003\"},\n\t\t{\"extstore_objects_used\", \"39319\"},\n\t\t{\"extstore_bytes_evicted\", \"1638804587744\"},\n\t\t{\"extstore_bytes_written\", \"1951205770118\"},\n\t\t{\"extstore_bytes_read\", \"1249921752566\"},\n\t\t{\"extstore_bytes_used\", \"51316205305\"},\n\t\t{\"extstore_bytes_fragmented\", \"2370885895\"},\n\t\t{\"extstore_limit_maxbytes\", \"53687091200\"},\n\t\t{\"extstore_io_queue\", \"0\"},\n\t\t{\"unexpected_napi_ids\", \"0\"},\n\t\t{\"round_robin_fallback\", \"0\"},\n\t\t{\"bytes\", \"0\"},\n\t\t{\"curr_items\", \"0\"},\n\t\t{\"total_items\", \"0\"},\n\t\t{\"slab_global_page_pool\", \"0\"},\n\t\t{\"expired_unfetched\", \"0\"},\n\t\t{\"evicted_unfetched\", \"0\"},\n\t\t{\"evicted_active\", \"0\"},\n\t\t{\"evictions\", \"0\"},\n\t\t{\"reclaimed\", \"0\"},\n\t\t{\"crawler_reclaimed\", \"0\"},\n\t\t{\"crawler_items_checked\", \"0\"},\n\t\t{\"lrutail_reflocked\", \"0\"},\n\t\t{\"moves_to_cold\", \"0\"},\n\t\t{\"moves_to_warm\", \"0\"},\n\t\t{\"moves_within_lru\", \"0\"},\n\t\t{\"direct_reclaims\", \"0\"},\n\t\t{\"lru_bumps_dropped\", \"0\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\tif !ok {\n\t\t\tt.Errorf(\"Did not find key for metric %s in values\", test.key)\n\t\t\tcontinue\n\t\t}\n\t\tif value != test.value {\n\t\t\tt.Errorf(\"Metric: %s, Expected: %s, actual: %s\",\n\t\t\t\ttest.key, test.value, value)\n\t\t}\n\t}\n}\n\nvar memcachedStats = `STAT pid 5619\nSTAT uptime 11\nSTAT time 1644765868\nSTAT version 1.6.14_5_ge03751b\nSTAT libevent 2.1.11-stable\nSTAT pointer_size 64\nSTAT rusage_user 0.080905\nSTAT rusage_system 0.059330\nSTAT max_connections 1024\nSTAT curr_connections 2\nSTAT total_connections 3\nSTAT rejected_connections 0\nSTAT connection_structures 3\nSTAT response_obj_oom 0\nSTAT response_obj_count 1\nSTAT response_obj_bytes 16384\nSTAT read_buf_count 2\nSTAT read_buf_bytes 32768\nSTAT read_buf_bytes_free 0\nSTAT read_buf_oom 0\nSTAT reserved_fds 20\nSTAT cmd_get 0\nSTAT cmd_set 0\nSTAT cmd_flush 0\nSTAT cmd_touch 0\nSTAT cmd_meta 0\nSTAT get_hits 0\nSTAT get_misses 0\nSTAT get_expired 0\nSTAT get_flushed 0\nSTAT delete_misses 0\nSTAT delete_hits 0\nSTAT incr_misses 0\nSTAT incr_hits 0\nSTAT decr_misses 0\nSTAT decr_hits 0\nSTAT cas_misses 0\nSTAT cas_hits 0\nSTAT cas_badval 0\nSTAT touch_hits 0\nSTAT touch_misses 0\nSTAT store_too_large 0\nSTAT store_no_memory 0\nSTAT auth_cmds 0\nSTAT auth_errors 0\nSTAT bytes_read 6\nSTAT bytes_written 0\nSTAT limit_maxbytes 67108864\nSTAT accepting_conns 1\nSTAT listen_disabled_num 0\nSTAT time_in_listen_disabled_us 0\nSTAT threads 4\nSTAT conn_yields 0\nSTAT hash_power_level 16\nSTAT hash_bytes 524288\nSTAT hash_is_expanding 0\nSTAT slab_reassign_rescues 0\nSTAT slab_reassign_chunk_rescues 0\nSTAT slab_reassign_evictions_nomem 0\nSTAT slab_reassign_inline_reclaim 0\nSTAT slab_reassign_busy_items 0\nSTAT slab_reassign_busy_deletes 0\nSTAT slab_reassign_running 0\nSTAT slabs_moved 0\nSTAT lru_crawler_running 0\nSTAT lru_crawler_starts 1\nSTAT lru_maintainer_juggles 60\nSTAT malloc_fails 0\nSTAT log_worker_dropped 0\nSTAT log_worker_written 0\nSTAT log_watcher_skipped 0\nSTAT log_watcher_sent 0\nSTAT log_watchers 0\nSTAT extstore_compact_lost 3287\nSTAT extstore_compact_rescues 47014\nSTAT extstore_compact_resc_cold 0\nSTAT extstore_compact_resc_old 0\nSTAT extstore_compact_skipped 0\nSTAT extstore_page_allocs 30047\nSTAT extstore_page_evictions 25315\nSTAT extstore_page_reclaims 29247\nSTAT extstore_pages_free 0\nSTAT extstore_pages_used 800\nSTAT extstore_objects_evicted 1243091\nSTAT extstore_objects_read 938410\nSTAT extstore_objects_written 1487003\nSTAT extstore_objects_used 39319\nSTAT extstore_bytes_evicted 1638804587744\nSTAT extstore_bytes_written 1951205770118\nSTAT extstore_bytes_read 1249921752566\nSTAT extstore_bytes_used 51316205305\nSTAT extstore_bytes_fragmented 2370885895\nSTAT extstore_limit_maxbytes 53687091200\nSTAT extstore_io_queue 0\nSTAT unexpected_napi_ids 0\nSTAT round_robin_fallback 0\nSTAT bytes 0\nSTAT curr_items 0\nSTAT total_items 0\nSTAT slab_global_page_pool 0\nSTAT expired_unfetched 0\nSTAT evicted_unfetched 0\nSTAT evicted_active 0\nSTAT evictions 0\nSTAT reclaimed 0\nSTAT crawler_reclaimed 0\nSTAT crawler_items_checked 0\nSTAT lrutail_reflocked 0\nSTAT moves_to_cold 0\nSTAT moves_to_warm 0\nSTAT moves_within_lru 0\nSTAT direct_reclaims 0\nSTAT lru_bumps_dropped 0\nEND\n`\n"
  },
  {
    "path": "plugins/inputs/memcached/sample.conf",
    "content": "# Read metrics from one or many memcached servers.\n[[inputs.memcached]]\n  # An array of address to gather stats about. Specify an ip on hostname\n  # with optional port. ie localhost, 10.0.0.1:11211, etc.\n  servers = [\"localhost:11211\"]\n  # An array of unix memcached sockets to gather stats about.\n  # unix_sockets = [\"/var/run/memcached.sock\"]\n\n  ## Optional TLS Config\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## If false, skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "plugins/inputs/mesos/README.md",
    "content": "# Apache Mesos Input Plugin\n\nThis plugin gathers metrics from [Apache Mesos][mesos] instances. For more\ninformation, please check the [Mesos Observability Metrics][monitoring] page.\n\n⭐ Telegraf v0.10.3\n🏷️ containers\n💻 all\n\n[mesos]:https://mesos.apache.org/\n[monitoring]: http://mesos.apache.org/documentation/latest/monitoring/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Telegraf plugin for gathering metrics from N Mesos masters\n[[inputs.mesos]]\n  ## Timeout, in ms.\n  timeout = 100\n\n  ## A list of Mesos masters.\n  masters = [\"http://localhost:5050\"]\n\n  ## Master metrics groups to be collected, by default, all enabled.\n  master_collections = [\n    \"resources\",\n    \"master\",\n    \"system\",\n    \"agents\",\n    \"frameworks\",\n    \"framework_offers\",\n    \"tasks\",\n    \"messages\",\n    \"evqueue\",\n    \"registrar\",\n    \"allocator\",\n  ]\n\n  ## A list of Mesos slaves, default is []\n  # slaves = []\n\n  ## Slave metrics groups to be collected, by default, all enabled.\n  # slave_collections = [\n  #   \"resources\",\n  #   \"agent\",\n  #   \"system\",\n  #   \"executors\",\n  #   \"tasks\",\n  #   \"messages\",\n  # ]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\nBy default this plugin is not configured to gather metrics from mesos. Since a\nmesos cluster can be deployed in numerous ways it does not provide any default\nvalues. User needs to specify master/slave nodes this plugin will gather metrics\nfrom.\n\n## Metrics\n\nMesos master metric groups\n\n- resources\n  - master/cpus_percent\n  - master/cpus_used\n  - master/cpus_total\n  - master/cpus_revocable_percent\n  - master/cpus_revocable_total\n  - master/cpus_revocable_used\n  - master/disk_percent\n  - master/disk_used\n  - master/disk_total\n  - master/disk_revocable_percent\n  - master/disk_revocable_total\n  - master/disk_revocable_used\n  - master/gpus_percent\n  - master/gpus_used\n  - master/gpus_total\n  - master/gpus_revocable_percent\n  - master/gpus_revocable_total\n  - master/gpus_revocable_used\n  - master/mem_percent\n  - master/mem_used\n  - master/mem_total\n  - master/mem_revocable_percent\n  - master/mem_revocable_total\n  - master/mem_revocable_used\n\n- master\n  - master/elected\n  - master/uptime_secs\n\n- system\n  - system/cpus_total\n  - system/load_15min\n  - system/load_5min\n  - system/load_1min\n  - system/mem_free_bytes\n  - system/mem_total_bytes\n\n- slaves\n  - master/slave_registrations\n  - master/slave_removals\n  - master/slave_reregistrations\n  - master/slave_shutdowns_scheduled\n  - master/slave_shutdowns_canceled\n  - master/slave_shutdowns_completed\n  - master/slaves_active\n  - master/slaves_connected\n  - master/slaves_disconnected\n  - master/slaves_inactive\n  - master/slave_unreachable_canceled\n  - master/slave_unreachable_completed\n  - master/slave_unreachable_scheduled\n  - master/slaves_unreachable\n\n- frameworks\n  - master/frameworks_active\n  - master/frameworks_connected\n  - master/frameworks_disconnected\n  - master/frameworks_inactive\n  - master/outstanding_offers\n\n- framework offers\n  - master/frameworks/subscribed\n  - master/frameworks/calls_total\n  - master/frameworks/calls\n  - master/frameworks/events_total\n  - master/frameworks/events\n  - master/frameworks/operations_total\n  - master/frameworks/operations\n  - master/frameworks/tasks/active\n  - master/frameworks/tasks/terminal\n  - master/frameworks/offers/sent\n  - master/frameworks/offers/accepted\n  - master/frameworks/offers/declined\n  - master/frameworks/offers/rescinded\n  - master/frameworks/roles/suppressed\n\n- tasks\n  - master/tasks_error\n  - master/tasks_failed\n  - master/tasks_finished\n  - master/tasks_killed\n  - master/tasks_lost\n  - master/tasks_running\n  - master/tasks_staging\n  - master/tasks_starting\n  - master/tasks_dropped\n  - master/tasks_gone\n  - master/tasks_gone_by_operator\n  - master/tasks_killing\n  - master/tasks_unreachable\n\n- messages\n  - master/invalid_executor_to_framework_messages\n  - master/invalid_framework_to_executor_messages\n  - master/invalid_status_update_acknowledgements\n  - master/invalid_status_updates\n  - master/dropped_messages\n  - master/messages_authenticate\n  - master/messages_deactivate_framework\n  - master/messages_decline_offers\n  - master/messages_executor_to_framework\n  - master/messages_exited_executor\n  - master/messages_framework_to_executor\n  - master/messages_kill_task\n  - master/messages_launch_tasks\n  - master/messages_reconcile_tasks\n  - master/messages_register_framework\n  - master/messages_register_slave\n  - master/messages_reregister_framework\n  - master/messages_reregister_slave\n  - master/messages_resource_request\n  - master/messages_revive_offers\n  - master/messages_status_update\n  - master/messages_status_update_acknowledgement\n  - master/messages_unregister_framework\n  - master/messages_unregister_slave\n  - master/messages_update_slave\n  - master/recovery_slave_removals\n  - master/slave_removals/reason_registered\n  - master/slave_removals/reason_unhealthy\n  - master/slave_removals/reason_unregistered\n  - master/valid_framework_to_executor_messages\n  - master/valid_status_update_acknowledgements\n  - master/valid_status_updates\n  - master/task_lost/source_master/reason_invalid_offers\n  - master/task_lost/source_master/reason_slave_removed\n  - master/task_lost/source_slave/reason_executor_terminated\n  - master/valid_executor_to_framework_messages\n  - master/invalid_operation_status_update_acknowledgements\n  - master/messages_operation_status_update_acknowledgement\n  - master/messages_reconcile_operations\n  - master/messages_suppress_offers\n  - master/valid_operation_status_update_acknowledgements\n\n- evqueue\n  - master/event_queue_dispatches\n  - master/event_queue_http_requests\n  - master/event_queue_messages\n  - master/operator_event_stream_subscribers\n\n- registrar\n  - registrar/state_fetch_ms\n  - registrar/state_store_ms\n  - registrar/state_store_ms/max\n  - registrar/state_store_ms/min\n  - registrar/state_store_ms/p50\n  - registrar/state_store_ms/p90\n  - registrar/state_store_ms/p95\n  - registrar/state_store_ms/p99\n  - registrar/state_store_ms/p999\n  - registrar/state_store_ms/p9999\n  - registrar/state_store_ms/count\n  - registrar/log/ensemble_size\n  - registrar/log/recovered\n  - registrar/queued_operations\n  - registrar/registry_size_bytes\n\n- allocator\n  - allocator/allocation_run_ms\n  - allocator/allocation_run_ms/count\n  - allocator/allocation_run_ms/max\n  - allocator/allocation_run_ms/min\n  - allocator/allocation_run_ms/p50\n  - allocator/allocation_run_ms/p90\n  - allocator/allocation_run_ms/p95\n  - allocator/allocation_run_ms/p99\n  - allocator/allocation_run_ms/p999\n  - allocator/allocation_run_ms/p9999\n  - allocator/allocation_runs\n  - allocator/allocation_run_latency_ms\n  - allocator/allocation_run_latency_ms/count\n  - allocator/allocation_run_latency_ms/max\n  - allocator/allocation_run_latency_ms/min\n  - allocator/allocation_run_latency_ms/p50\n  - allocator/allocation_run_latency_ms/p90\n  - allocator/allocation_run_latency_ms/p95\n  - allocator/allocation_run_latency_ms/p99\n  - allocator/allocation_run_latency_ms/p999\n  - allocator/allocation_run_latency_ms/p9999\n  - allocator/roles/shares/dominant\n  - allocator/event_queue_dispatches\n  - allocator/offer_filters/roles/active\n  - allocator/quota/roles/resources/offered_or_allocated\n  - allocator/quota/roles/resources/guarantee\n  - allocator/resources/cpus/offered_or_allocated\n  - allocator/resources/cpus/total\n  - allocator/resources/disk/offered_or_allocated\n  - allocator/resources/disk/total\n  - allocator/resources/mem/offered_or_allocated\n  - allocator/resources/mem/total\n\nMesos slave metric groups\n\n- resources\n  - slave/cpus_percent\n  - slave/cpus_used\n  - slave/cpus_total\n  - slave/cpus_revocable_percent\n  - slave/cpus_revocable_total\n  - slave/cpus_revocable_used\n  - slave/disk_percent\n  - slave/disk_used\n  - slave/disk_total\n  - slave/disk_revocable_percent\n  - slave/disk_revocable_total\n  - slave/disk_revocable_used\n  - slave/gpus_percent\n  - slave/gpus_used\n  - slave/gpus_total,\n  - slave/gpus_revocable_percent\n  - slave/gpus_revocable_total\n  - slave/gpus_revocable_used\n  - slave/mem_percent\n  - slave/mem_used\n  - slave/mem_total\n  - slave/mem_revocable_percent\n  - slave/mem_revocable_total\n  - slave/mem_revocable_used\n\n- agent\n  - slave/registered\n  - slave/uptime_secs\n\n- system\n  - system/cpus_total\n  - system/load_15min\n  - system/load_5min\n  - system/load_1min\n  - system/mem_free_bytes\n  - system/mem_total_bytes\n\n- executors\n  - containerizer/mesos/container_destroy_errors\n  - slave/container_launch_errors\n  - slave/executors_preempted\n  - slave/frameworks_active\n  - slave/executor_directory_max_allowed_age_secs\n  - slave/executors_registering\n  - slave/executors_running\n  - slave/executors_terminated\n  - slave/executors_terminating\n  - slave/recovery_errors\n\n- tasks\n  - slave/tasks_failed\n  - slave/tasks_finished\n  - slave/tasks_killed\n  - slave/tasks_lost\n  - slave/tasks_running\n  - slave/tasks_staging\n  - slave/tasks_starting\n\n- messages\n  - slave/invalid_framework_messages\n  - slave/invalid_status_updates\n  - slave/valid_framework_messages\n  - slave/valid_status_updates\n\n## Tags\n\n- All master/slave measurements have the following tags:\n  - server (network location of server: `host:port`)\n  - url (URL origin of server: `scheme://host:port`)\n  - role (master/slave)\n\n- All master measurements have the extra tags:\n  - state (leader/follower)\n\n## Example Output\n\n```text\nmesos,role=master,state=leader,host=172.17.8.102,server=172.17.8.101\nallocator/event_queue_dispatches=0,master/cpus_percent=0,\nmaster/cpus_revocable_percent=0,master/cpus_revocable_total=0,\nmaster/cpus_revocable_used=0,master/cpus_total=2,\nmaster/cpus_used=0,master/disk_percent=0,master/disk_revocable_percent=0,\nmaster/disk_revocable_total=0,master/disk_revocable_used=0,master/disk_total=10823,\nmaster/disk_used=0,master/dropped_messages=2,master/elected=1,\nmaster/event_queue_dispatches=10,master/event_queue_http_requests=0,\nmaster/event_queue_messages=0,master/frameworks_active=2,master/frameworks_connected=2,\nmaster/frameworks_disconnected=0,master/frameworks_inactive=0,\nmaster/invalid_executor_to_framework_messages=0,\nmaster/invalid_framework_to_executor_messages=0,\nmaster/invalid_status_update_acknowledgements=0,master/invalid_status_updates=0,master/mem_percent=0,\nmaster/mem_revocable_percent=0,master/mem_revocable_total=0,\nmaster/mem_revocable_used=0,master/mem_total=1002,\nmaster/mem_used=0,master/messages_authenticate=0,\nmaster/messages_deactivate_framework=0 ...\n```\n"
  },
  {
    "path": "plugins/inputs/mesos/mesos.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mesos\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\tparsers_json \"github.com/influxdata/telegraf/plugins/parsers/json\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype role string\n\nconst (\n\tmaster role = \"master\"\n\tslave  role = \"slave\"\n)\n\nvar allMetrics = map[role][]string{\n\tmaster: {\"resources\", \"master\", \"system\", \"agents\", \"frameworks\", \"framework_offers\", \"tasks\", \"messages\", \"evqueue\", \"registrar\", \"allocator\"},\n\tslave:  {\"resources\", \"agent\", \"system\", \"executors\", \"tasks\", \"messages\"},\n}\n\ntype Mesos struct {\n\tTimeout    int      `toml:\"timeout\"`\n\tMasters    []string `toml:\"masters\"`\n\tMasterCols []string `toml:\"master_collections\"`\n\tSlaves     []string `toml:\"slaves\"`\n\tSlaveCols  []string `toml:\"slave_collections\"`\n\ttls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tinitialized bool\n\tclient      *http.Client\n\tmasterURLs  []*url.URL\n\tslaveURLs   []*url.URL\n}\n\nfunc (*Mesos) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Mesos) Gather(acc telegraf.Accumulator) error {\n\tif !m.initialized {\n\t\terr := m.initialize()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tm.initialized = true\n\t}\n\n\tvar wg sync.WaitGroup\n\n\tfor _, mstr := range m.masterURLs {\n\t\twg.Add(1)\n\t\tgo func(mstr *url.URL) {\n\t\t\tacc.AddError(m.gatherMainMetrics(mstr, master, acc))\n\t\t\twg.Done()\n\t\t}(mstr)\n\t}\n\n\tfor _, slv := range m.slaveURLs {\n\t\twg.Add(1)\n\t\tgo func(slv *url.URL) {\n\t\t\tacc.AddError(m.gatherMainMetrics(slv, slave, acc))\n\t\t\twg.Done()\n\t\t}(slv)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (m *Mesos) parseURL(s string, role role) (*url.URL, error) {\n\tif !strings.HasPrefix(s, \"http://\") && !strings.HasPrefix(s, \"https://\") {\n\t\thost, port, err := net.SplitHostPort(s)\n\t\t// no port specified\n\t\tif err != nil {\n\t\t\thost = s\n\t\t\tswitch role {\n\t\t\tcase master:\n\t\t\t\tport = \"5050\"\n\t\t\tcase slave:\n\t\t\t\tport = \"5051\"\n\t\t\t}\n\t\t}\n\n\t\ts = \"http://\" + host + \":\" + port\n\t\tm.Log.Warnf(\"using %q as connection URL; please update your configuration to use an URL\", s)\n\t}\n\n\treturn url.Parse(s)\n}\n\nfunc (m *Mesos) initialize() error {\n\tif len(m.MasterCols) == 0 {\n\t\tm.MasterCols = allMetrics[master]\n\t}\n\n\tif len(m.SlaveCols) == 0 {\n\t\tm.SlaveCols = allMetrics[slave]\n\t}\n\n\tif m.Timeout == 0 {\n\t\tm.Log.Info(\"Missing timeout value, setting default value (100ms)\")\n\t\tm.Timeout = 100\n\t}\n\n\trawQuery := \"timeout=\" + strconv.Itoa(m.Timeout) + \"ms\"\n\n\tm.masterURLs = make([]*url.URL, 0, len(m.Masters))\n\tfor _, mstr := range m.Masters {\n\t\tu, err := m.parseURL(mstr, master)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tu.RawQuery = rawQuery\n\t\tm.masterURLs = append(m.masterURLs, u)\n\t}\n\n\tm.slaveURLs = make([]*url.URL, 0, len(m.Slaves))\n\tfor _, slv := range m.Slaves {\n\t\tu, err := m.parseURL(slv, slave)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tu.RawQuery = rawQuery\n\t\tm.slaveURLs = append(m.slaveURLs, u)\n\t}\n\n\tclient, err := m.createHTTPClient()\n\tif err != nil {\n\t\treturn err\n\t}\n\tm.client = client\n\n\treturn nil\n}\n\nfunc (m *Mesos) createHTTPClient() (*http.Client, error) {\n\ttlsCfg, err := m.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tProxy:           http.ProxyFromEnvironment,\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: 4 * time.Second,\n\t}\n\n\treturn client, nil\n}\n\n// metricsDiff() returns set names for removal\nfunc metricsDiff(role role, w []string) []string {\n\tb := make([]string, 0, len(allMetrics[role]))\n\ts := make(map[string]bool)\n\n\tif len(w) == 0 {\n\t\treturn b\n\t}\n\n\tfor _, v := range w {\n\t\ts[v] = true\n\t}\n\n\tfor _, d := range allMetrics[role] {\n\t\tif _, ok := s[d]; !ok {\n\t\t\tb = append(b, d)\n\t\t}\n\t}\n\n\treturn b\n}\n\n// masterBlocks serves as kind of metrics registry grouping them in sets\nfunc (m *Mesos) getMetrics(role role, group string) []string {\n\tmetrics := make(map[string][]string)\n\n\tif role == master {\n\t\tmetrics[\"resources\"] = []string{\n\t\t\t\"master/cpus_percent\",\n\t\t\t\"master/cpus_used\",\n\t\t\t\"master/cpus_total\",\n\t\t\t\"master/cpus_revocable_percent\",\n\t\t\t\"master/cpus_revocable_total\",\n\t\t\t\"master/cpus_revocable_used\",\n\t\t\t\"master/disk_percent\",\n\t\t\t\"master/disk_used\",\n\t\t\t\"master/disk_total\",\n\t\t\t\"master/disk_revocable_percent\",\n\t\t\t\"master/disk_revocable_total\",\n\t\t\t\"master/disk_revocable_used\",\n\t\t\t\"master/gpus_percent\",\n\t\t\t\"master/gpus_used\",\n\t\t\t\"master/gpus_total\",\n\t\t\t\"master/gpus_revocable_percent\",\n\t\t\t\"master/gpus_revocable_total\",\n\t\t\t\"master/gpus_revocable_used\",\n\t\t\t\"master/mem_percent\",\n\t\t\t\"master/mem_used\",\n\t\t\t\"master/mem_total\",\n\t\t\t\"master/mem_revocable_percent\",\n\t\t\t\"master/mem_revocable_total\",\n\t\t\t\"master/mem_revocable_used\",\n\t\t}\n\n\t\tmetrics[\"master\"] = []string{\n\t\t\t\"master/elected\",\n\t\t\t\"master/uptime_secs\",\n\t\t}\n\n\t\tmetrics[\"system\"] = []string{\n\t\t\t\"system/cpus_total\",\n\t\t\t\"system/load_15min\",\n\t\t\t\"system/load_5min\",\n\t\t\t\"system/load_1min\",\n\t\t\t\"system/mem_free_bytes\",\n\t\t\t\"system/mem_total_bytes\",\n\t\t}\n\n\t\tmetrics[\"agents\"] = []string{\n\t\t\t\"master/slave_registrations\",\n\t\t\t\"master/slave_removals\",\n\t\t\t\"master/slave_reregistrations\",\n\t\t\t\"master/slave_shutdowns_scheduled\",\n\t\t\t\"master/slave_shutdowns_canceled\",\n\t\t\t\"master/slave_shutdowns_completed\",\n\t\t\t\"master/slaves_active\",\n\t\t\t\"master/slaves_connected\",\n\t\t\t\"master/slaves_disconnected\",\n\t\t\t\"master/slaves_inactive\",\n\t\t\t\"master/slave_unreachable_canceled\",\n\t\t\t\"master/slave_unreachable_completed\",\n\t\t\t\"master/slave_unreachable_scheduled\",\n\t\t\t\"master/slaves_unreachable\",\n\t\t}\n\n\t\tmetrics[\"frameworks\"] = []string{\n\t\t\t\"master/frameworks_active\",\n\t\t\t\"master/frameworks_connected\",\n\t\t\t\"master/frameworks_disconnected\",\n\t\t\t\"master/frameworks_inactive\",\n\t\t\t\"master/outstanding_offers\",\n\t\t}\n\n\t\t// framework_offers and allocator metrics have unpredictable names, so they can't be listed here.\n\t\t// These empty groups are included to prevent the \"unknown metrics group\" info log below.\n\t\t// filterMetrics() filters these metrics by looking for names with the corresponding prefix.\n\t\tmetrics[\"framework_offers\"] = make([]string, 0)\n\t\tmetrics[\"allocator\"] = make([]string, 0)\n\n\t\tmetrics[\"tasks\"] = []string{\n\t\t\t\"master/tasks_error\",\n\t\t\t\"master/tasks_failed\",\n\t\t\t\"master/tasks_finished\",\n\t\t\t\"master/tasks_killed\",\n\t\t\t\"master/tasks_lost\",\n\t\t\t\"master/tasks_running\",\n\t\t\t\"master/tasks_staging\",\n\t\t\t\"master/tasks_starting\",\n\t\t\t\"master/tasks_dropped\",\n\t\t\t\"master/tasks_gone\",\n\t\t\t\"master/tasks_gone_by_operator\",\n\t\t\t\"master/tasks_killing\",\n\t\t\t\"master/tasks_unreachable\",\n\t\t}\n\n\t\tmetrics[\"messages\"] = []string{\n\t\t\t\"master/invalid_executor_to_framework_messages\",\n\t\t\t\"master/invalid_framework_to_executor_messages\",\n\t\t\t\"master/invalid_status_update_acknowledgements\",\n\t\t\t\"master/invalid_status_updates\",\n\t\t\t\"master/dropped_messages\",\n\t\t\t\"master/messages_authenticate\",\n\t\t\t\"master/messages_deactivate_framework\",\n\t\t\t\"master/messages_decline_offers\",\n\t\t\t\"master/messages_executor_to_framework\",\n\t\t\t\"master/messages_exited_executor\",\n\t\t\t\"master/messages_framework_to_executor\",\n\t\t\t\"master/messages_kill_task\",\n\t\t\t\"master/messages_launch_tasks\",\n\t\t\t\"master/messages_reconcile_tasks\",\n\t\t\t\"master/messages_register_framework\",\n\t\t\t\"master/messages_register_slave\",\n\t\t\t\"master/messages_reregister_framework\",\n\t\t\t\"master/messages_reregister_slave\",\n\t\t\t\"master/messages_resource_request\",\n\t\t\t\"master/messages_revive_offers\",\n\t\t\t\"master/messages_status_update\",\n\t\t\t\"master/messages_status_update_acknowledgement\",\n\t\t\t\"master/messages_unregister_framework\",\n\t\t\t\"master/messages_unregister_slave\",\n\t\t\t\"master/messages_update_slave\",\n\t\t\t\"master/recovery_slave_removals\",\n\t\t\t\"master/slave_removals/reason_registered\",\n\t\t\t\"master/slave_removals/reason_unhealthy\",\n\t\t\t\"master/slave_removals/reason_unregistered\",\n\t\t\t\"master/valid_framework_to_executor_messages\",\n\t\t\t\"master/valid_status_update_acknowledgements\",\n\t\t\t\"master/valid_status_updates\",\n\t\t\t\"master/task_lost/source_master/reason_invalid_offers\",\n\t\t\t\"master/task_lost/source_master/reason_slave_removed\",\n\t\t\t\"master/task_lost/source_slave/reason_executor_terminated\",\n\t\t\t\"master/valid_executor_to_framework_messages\",\n\t\t\t\"master/invalid_operation_status_update_acknowledgements\",\n\t\t\t\"master/messages_operation_status_update_acknowledgement\",\n\t\t\t\"master/messages_reconcile_operations\",\n\t\t\t\"master/messages_suppress_offers\",\n\t\t\t\"master/valid_operation_status_update_acknowledgements\",\n\t\t}\n\n\t\tmetrics[\"evqueue\"] = []string{\n\t\t\t\"master/event_queue_dispatches\",\n\t\t\t\"master/event_queue_http_requests\",\n\t\t\t\"master/event_queue_messages\",\n\t\t\t\"master/operator_event_stream_subscribers\",\n\t\t}\n\n\t\tmetrics[\"registrar\"] = []string{\n\t\t\t\"registrar/state_fetch_ms\",\n\t\t\t\"registrar/state_store_ms\",\n\t\t\t\"registrar/state_store_ms/max\",\n\t\t\t\"registrar/state_store_ms/min\",\n\t\t\t\"registrar/state_store_ms/p50\",\n\t\t\t\"registrar/state_store_ms/p90\",\n\t\t\t\"registrar/state_store_ms/p95\",\n\t\t\t\"registrar/state_store_ms/p99\",\n\t\t\t\"registrar/state_store_ms/p999\",\n\t\t\t\"registrar/state_store_ms/p9999\",\n\t\t\t\"registrar/log/ensemble_size\",\n\t\t\t\"registrar/log/recovered\",\n\t\t\t\"registrar/queued_operations\",\n\t\t\t\"registrar/registry_size_bytes\",\n\t\t\t\"registrar/state_store_ms/count\",\n\t\t}\n\t} else if role == slave {\n\t\tmetrics[\"resources\"] = []string{\n\t\t\t\"slave/cpus_percent\",\n\t\t\t\"slave/cpus_used\",\n\t\t\t\"slave/cpus_total\",\n\t\t\t\"slave/cpus_revocable_percent\",\n\t\t\t\"slave/cpus_revocable_total\",\n\t\t\t\"slave/cpus_revocable_used\",\n\t\t\t\"slave/disk_percent\",\n\t\t\t\"slave/disk_used\",\n\t\t\t\"slave/disk_total\",\n\t\t\t\"slave/disk_revocable_percent\",\n\t\t\t\"slave/disk_revocable_total\",\n\t\t\t\"slave/disk_revocable_used\",\n\t\t\t\"slave/gpus_percent\",\n\t\t\t\"slave/gpus_used\",\n\t\t\t\"slave/gpus_total\",\n\t\t\t\"slave/gpus_revocable_percent\",\n\t\t\t\"slave/gpus_revocable_total\",\n\t\t\t\"slave/gpus_revocable_used\",\n\t\t\t\"slave/mem_percent\",\n\t\t\t\"slave/mem_used\",\n\t\t\t\"slave/mem_total\",\n\t\t\t\"slave/mem_revocable_percent\",\n\t\t\t\"slave/mem_revocable_total\",\n\t\t\t\"slave/mem_revocable_used\",\n\t\t}\n\n\t\tmetrics[\"agent\"] = []string{\n\t\t\t\"slave/registered\",\n\t\t\t\"slave/uptime_secs\",\n\t\t}\n\n\t\tmetrics[\"system\"] = []string{\n\t\t\t\"system/cpus_total\",\n\t\t\t\"system/load_15min\",\n\t\t\t\"system/load_5min\",\n\t\t\t\"system/load_1min\",\n\t\t\t\"system/mem_free_bytes\",\n\t\t\t\"system/mem_total_bytes\",\n\t\t}\n\n\t\tmetrics[\"executors\"] = []string{\n\t\t\t\"containerizer/mesos/container_destroy_errors\",\n\t\t\t\"slave/container_launch_errors\",\n\t\t\t\"slave/executors_preempted\",\n\t\t\t\"slave/frameworks_active\",\n\t\t\t\"slave/executor_directory_max_allowed_age_secs\",\n\t\t\t\"slave/executors_registering\",\n\t\t\t\"slave/executors_running\",\n\t\t\t\"slave/executors_terminated\",\n\t\t\t\"slave/executors_terminating\",\n\t\t\t\"slave/recovery_errors\",\n\t\t}\n\n\t\tmetrics[\"tasks\"] = []string{\n\t\t\t\"slave/tasks_failed\",\n\t\t\t\"slave/tasks_finished\",\n\t\t\t\"slave/tasks_killed\",\n\t\t\t\"slave/tasks_lost\",\n\t\t\t\"slave/tasks_running\",\n\t\t\t\"slave/tasks_staging\",\n\t\t\t\"slave/tasks_starting\",\n\t\t}\n\n\t\tmetrics[\"messages\"] = []string{\n\t\t\t\"slave/invalid_framework_messages\",\n\t\t\t\"slave/invalid_status_updates\",\n\t\t\t\"slave/valid_framework_messages\",\n\t\t\t\"slave/valid_status_updates\",\n\t\t}\n\t}\n\n\tret, ok := metrics[group]\n\tif !ok {\n\t\tm.Log.Infof(\"Unknown role %q metrics group: %s\", role, group)\n\t\treturn nil\n\t}\n\n\treturn ret\n}\n\nfunc (m *Mesos) filterMetrics(role role, metrics *map[string]interface{}) {\n\tvar ok bool\n\tvar selectedMetrics []string\n\n\tif role == master {\n\t\tselectedMetrics = m.MasterCols\n\t} else if role == slave {\n\t\tselectedMetrics = m.SlaveCols\n\t}\n\n\tfor _, k := range metricsDiff(role, selectedMetrics) {\n\t\tswitch k {\n\t\t// allocator and framework_offers metrics have unpredictable names, so we have to identify them by name prefix.\n\t\tcase \"allocator\":\n\t\t\tfor m := range *metrics {\n\t\t\t\tif strings.HasPrefix(m, \"allocator/\") {\n\t\t\t\t\tdelete(*metrics, m)\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"framework_offers\":\n\t\t\tfor m := range *metrics {\n\t\t\t\tif strings.HasPrefix(m, \"master/frameworks/\") || strings.HasPrefix(m, \"frameworks/\") {\n\t\t\t\t\tdelete(*metrics, m)\n\t\t\t\t}\n\t\t\t}\n\n\t\t// All other metrics have predictable names. We can use getMetrics() to retrieve them.\n\t\tdefault:\n\t\t\tfor _, v := range m.getMetrics(role, k) {\n\t\t\t\tif _, ok = (*metrics)[v]; ok {\n\t\t\t\t\tdelete(*metrics, v)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc withPath(u *url.URL, path string) *url.URL {\n\tc := *u\n\tc.Path = path\n\treturn &c\n}\n\nfunc urlTag(u *url.URL) string {\n\tc := *u\n\tc.Path = \"\"\n\tc.User = nil\n\tc.RawQuery = \"\"\n\treturn c.String()\n}\n\n// This should not belong to the object\nfunc (m *Mesos) gatherMainMetrics(u *url.URL, role role, acc telegraf.Accumulator) error {\n\tvar jsonOut map[string]interface{}\n\n\ttags := map[string]string{\n\t\t\"server\": u.Hostname(),\n\t\t\"url\":    urlTag(u),\n\t\t\"role\":   string(role),\n\t}\n\n\tresp, err := m.client.Get(withPath(u, \"/metrics/snapshot\").String())\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdata, err := io.ReadAll(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = json.Unmarshal(data, &jsonOut); err != nil {\n\t\treturn errors.New(\"error decoding JSON response\")\n\t}\n\n\tm.filterMetrics(role, &jsonOut)\n\n\tjf := parsers_json.JSONFlattener{}\n\n\terr = jf.FlattenJSON(\"\", jsonOut)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif role == master {\n\t\tif jf.Fields[\"master/elected\"] != 0.0 {\n\t\t\ttags[\"state\"] = \"leader\"\n\t\t} else {\n\t\t\ttags[\"state\"] = \"standby\"\n\t\t}\n\t}\n\n\tacc.AddFields(\"mesos\", jf.Fields, tags)\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"mesos\", func() telegraf.Input {\n\t\treturn &Mesos{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mesos/mesos_test.go",
    "content": "package mesos\n\nimport (\n\t\"encoding/json\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar masterMetrics map[string]interface{}\nvar masterTestServer *httptest.Server\nvar slaveMetrics map[string]interface{}\n\nvar slaveTestServer *httptest.Server\n\n// master metrics that will be returned by generateMetrics()\nvar masterMetricNames = []string{\n\t// resources\n\t\"master/cpus_percent\",\n\t\"master/cpus_used\",\n\t\"master/cpus_total\",\n\t\"master/cpus_revocable_percent\",\n\t\"master/cpus_revocable_total\",\n\t\"master/cpus_revocable_used\",\n\t\"master/disk_percent\",\n\t\"master/disk_used\",\n\t\"master/disk_total\",\n\t\"master/disk_revocable_percent\",\n\t\"master/disk_revocable_total\",\n\t\"master/disk_revocable_used\",\n\t\"master/gpus_percent\",\n\t\"master/gpus_used\",\n\t\"master/gpus_total\",\n\t\"master/gpus_revocable_percent\",\n\t\"master/gpus_revocable_total\",\n\t\"master/gpus_revocable_used\",\n\t\"master/mem_percent\",\n\t\"master/mem_used\",\n\t\"master/mem_total\",\n\t\"master/mem_revocable_percent\",\n\t\"master/mem_revocable_total\",\n\t\"master/mem_revocable_used\",\n\t// master\n\t\"master/elected\",\n\t\"master/uptime_secs\",\n\t// system\n\t\"system/cpus_total\",\n\t\"system/load_15min\",\n\t\"system/load_5min\",\n\t\"system/load_1min\",\n\t\"system/mem_free_bytes\",\n\t\"system/mem_total_bytes\",\n\t// agents\n\t\"master/slave_registrations\",\n\t\"master/slave_removals\",\n\t\"master/slave_reregistrations\",\n\t\"master/slave_shutdowns_scheduled\",\n\t\"master/slave_shutdowns_canceled\",\n\t\"master/slave_shutdowns_completed\",\n\t\"master/slaves_active\",\n\t\"master/slaves_connected\",\n\t\"master/slaves_disconnected\",\n\t\"master/slaves_inactive\",\n\t\"master/slave_unreachable_canceled\",\n\t\"master/slave_unreachable_completed\",\n\t\"master/slave_unreachable_scheduled\",\n\t\"master/slaves_unreachable\",\n\t// frameworks\n\t\"master/frameworks_active\",\n\t\"master/frameworks_connected\",\n\t\"master/frameworks_disconnected\",\n\t\"master/frameworks_inactive\",\n\t\"master/outstanding_offers\",\n\t// framework offers\n\t\"master/frameworks/marathon/abc-123/calls\",\n\t\"master/frameworks/marathon/abc-123/calls/accept\",\n\t\"master/frameworks/marathon/abc-123/events\",\n\t\"master/frameworks/marathon/abc-123/events/error\",\n\t\"master/frameworks/marathon/abc-123/offers/sent\",\n\t\"master/frameworks/marathon/abc-123/operations\",\n\t\"master/frameworks/marathon/abc-123/operations/create\",\n\t\"master/frameworks/marathon/abc-123/roles/*/suppressed\",\n\t\"master/frameworks/marathon/abc-123/subscribed\",\n\t\"master/frameworks/marathon/abc-123/tasks/active/task_killing\",\n\t\"master/frameworks/marathon/abc-123/tasks/active/task_dropped\",\n\t\"master/frameworks/marathon/abc-123/tasks/terminal/task_dropped\",\n\t\"master/frameworks/marathon/abc-123/unknown/unknown\", // test case for unknown metric type\n\t// tasks\n\t\"master/tasks_error\",\n\t\"master/tasks_failed\",\n\t\"master/tasks_finished\",\n\t\"master/tasks_killed\",\n\t\"master/tasks_lost\",\n\t\"master/tasks_running\",\n\t\"master/tasks_staging\",\n\t\"master/tasks_starting\",\n\t\"master/tasks_dropped\",\n\t\"master/tasks_gone\",\n\t\"master/tasks_gone_by_operator\",\n\t\"master/tasks_killing\",\n\t\"master/tasks_unreachable\",\n\t// messages\n\t\"master/invalid_executor_to_framework_messages\",\n\t\"master/invalid_framework_to_executor_messages\",\n\t\"master/invalid_status_update_acknowledgements\",\n\t\"master/invalid_status_updates\",\n\t\"master/dropped_messages\",\n\t\"master/messages_authenticate\",\n\t\"master/messages_deactivate_framework\",\n\t\"master/messages_decline_offers\",\n\t\"master/messages_executor_to_framework\",\n\t\"master/messages_exited_executor\",\n\t\"master/messages_framework_to_executor\",\n\t\"master/messages_kill_task\",\n\t\"master/messages_launch_tasks\",\n\t\"master/messages_reconcile_tasks\",\n\t\"master/messages_register_framework\",\n\t\"master/messages_register_slave\",\n\t\"master/messages_reregister_framework\",\n\t\"master/messages_reregister_slave\",\n\t\"master/messages_resource_request\",\n\t\"master/messages_revive_offers\",\n\t\"master/messages_status_update\",\n\t\"master/messages_status_update_acknowledgement\",\n\t\"master/messages_unregister_framework\",\n\t\"master/messages_unregister_slave\",\n\t\"master/messages_update_slave\",\n\t\"master/recovery_slave_removals\",\n\t\"master/slave_removals/reason_registered\",\n\t\"master/slave_removals/reason_unhealthy\",\n\t\"master/slave_removals/reason_unregistered\",\n\t\"master/valid_framework_to_executor_messages\",\n\t\"master/valid_status_update_acknowledgements\",\n\t\"master/valid_status_updates\",\n\t\"master/task_lost/source_master/reason_invalid_offers\",\n\t\"master/task_lost/source_master/reason_slave_removed\",\n\t\"master/task_lost/source_slave/reason_executor_terminated\",\n\t\"master/valid_executor_to_framework_messages\",\n\t\"master/invalid_operation_status_update_acknowledgements\",\n\t\"master/messages_operation_status_update_acknowledgement\",\n\t\"master/messages_reconcile_operations\",\n\t\"master/messages_suppress_offers\",\n\t\"master/valid_operation_status_update_acknowledgements\",\n\t// evgqueue\n\t\"master/event_queue_dispatches\",\n\t\"master/event_queue_http_requests\",\n\t\"master/event_queue_messages\",\n\t\"master/operator_event_stream_subscribers\",\n\t// registrar\n\t\"registrar/log/ensemble_size\",\n\t\"registrar/log/recovered\",\n\t\"registrar/queued_operations\",\n\t\"registrar/registry_size_bytes\",\n\t\"registrar/state_fetch_ms\",\n\t\"registrar/state_store_ms\",\n\t\"registrar/state_store_ms/max\",\n\t\"registrar/state_store_ms/min\",\n\t\"registrar/state_store_ms/p50\",\n\t\"registrar/state_store_ms/p90\",\n\t\"registrar/state_store_ms/p95\",\n\t\"registrar/state_store_ms/p99\",\n\t\"registrar/state_store_ms/p999\",\n\t\"registrar/state_store_ms/p9999\",\n\t\"registrar/state_store_ms/count\",\n\t// allocator\n\t\"allocator/mesos/allocation_run_ms\",\n\t\"allocator/mesos/allocation_run_ms/count\",\n\t\"allocator/mesos/allocation_run_ms/max\",\n\t\"allocator/mesos/allocation_run_ms/min\",\n\t\"allocator/mesos/allocation_run_ms/p50\",\n\t\"allocator/mesos/allocation_run_ms/p90\",\n\t\"allocator/mesos/allocation_run_ms/p95\",\n\t\"allocator/mesos/allocation_run_ms/p99\",\n\t\"allocator/mesos/allocation_run_ms/p999\",\n\t\"allocator/mesos/allocation_run_ms/p9999\",\n\t\"allocator/mesos/allocation_runs\",\n\t\"allocator/mesos/allocation_run_latency_ms\",\n\t\"allocator/mesos/allocation_run_latency_ms/count\",\n\t\"allocator/mesos/allocation_run_latency_ms/max\",\n\t\"allocator/mesos/allocation_run_latency_ms/min\",\n\t\"allocator/mesos/allocation_run_latency_ms/p50\",\n\t\"allocator/mesos/allocation_run_latency_ms/p90\",\n\t\"allocator/mesos/allocation_run_latency_ms/p95\",\n\t\"allocator/mesos/allocation_run_latency_ms/p99\",\n\t\"allocator/mesos/allocation_run_latency_ms/p999\",\n\t\"allocator/mesos/allocation_run_latency_ms/p9999\",\n\t\"allocator/mesos/roles/*/shares/dominant\",\n\t\"allocator/mesos/event_queue_dispatches\",\n\t\"allocator/mesos/offer_filters/roles/*/active\",\n\t\"allocator/mesos/quota/roles/*/resources/disk/offered_or_allocated\",\n\t\"allocator/mesos/quota/roles/*/resources/mem/guarantee\",\n\t\"allocator/mesos/quota/roles/*/resources/disk/guarantee\",\n\t\"allocator/mesos/resources/cpus/offered_or_allocated\",\n\t\"allocator/mesos/resources/cpus/total\",\n\t\"allocator/mesos/resources/disk/offered_or_allocated\",\n\t\"allocator/mesos/resources/disk/total\",\n\t\"allocator/mesos/resources/mem/offered_or_allocated\",\n\t\"allocator/mesos/resources/mem/total\",\n}\n\n// slave metrics that will be returned by generateMetrics()\nvar slaveMetricNames = []string{\n\t// resources\n\t\"slave/cpus_percent\",\n\t\"slave/cpus_used\",\n\t\"slave/cpus_total\",\n\t\"slave/cpus_revocable_percent\",\n\t\"slave/cpus_revocable_total\",\n\t\"slave/cpus_revocable_used\",\n\t\"slave/disk_percent\",\n\t\"slave/disk_used\",\n\t\"slave/disk_total\",\n\t\"slave/disk_revocable_percent\",\n\t\"slave/disk_revocable_total\",\n\t\"slave/disk_revocable_used\",\n\t\"slave/gpus_percent\",\n\t\"slave/gpus_used\",\n\t\"slave/gpus_total\",\n\t\"slave/gpus_revocable_percent\",\n\t\"slave/gpus_revocable_total\",\n\t\"slave/gpus_revocable_used\",\n\t\"slave/mem_percent\",\n\t\"slave/mem_used\",\n\t\"slave/mem_total\",\n\t\"slave/mem_revocable_percent\",\n\t\"slave/mem_revocable_total\",\n\t\"slave/mem_revocable_used\",\n\t// agent\n\t\"slave/registered\",\n\t\"slave/uptime_secs\",\n\t// system\n\t\"system/cpus_total\",\n\t\"system/load_15min\",\n\t\"system/load_5min\",\n\t\"system/load_1min\",\n\t\"system/mem_free_bytes\",\n\t\"system/mem_total_bytes\",\n\t// executors\n\t\"containerizer/mesos/container_destroy_errors\",\n\t\"slave/container_launch_errors\",\n\t\"slave/executors_preempted\",\n\t\"slave/frameworks_active\",\n\t\"slave/executor_directory_max_allowed_age_secs\",\n\t\"slave/executors_registering\",\n\t\"slave/executors_running\",\n\t\"slave/executors_terminated\",\n\t\"slave/executors_terminating\",\n\t\"slave/recovery_errors\",\n\t// tasks\n\t\"slave/tasks_failed\",\n\t\"slave/tasks_finished\",\n\t\"slave/tasks_killed\",\n\t\"slave/tasks_lost\",\n\t\"slave/tasks_running\",\n\t\"slave/tasks_staging\",\n\t\"slave/tasks_starting\",\n\t// messages\n\t\"slave/invalid_framework_messages\",\n\t\"slave/invalid_status_updates\",\n\t\"slave/valid_framework_messages\",\n\t\"slave/valid_status_updates\",\n}\n\nfunc generateMetrics() {\n\tmasterMetrics = make(map[string]interface{})\n\tfor _, k := range masterMetricNames {\n\t\tmasterMetrics[k] = rand.Float64()\n\t}\n\n\tslaveMetrics = make(map[string]interface{})\n\tfor _, k := range slaveMetricNames {\n\t\tslaveMetrics[k] = rand.Float64()\n\t}\n}\n\nfunc TestMain(m *testing.M) {\n\tgenerateMetrics()\n\n\tmasterRouter := http.NewServeMux()\n\tmasterRouter.HandleFunc(\"/metrics/snapshot\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tjson.NewEncoder(w).Encode(masterMetrics) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\t})\n\tmasterTestServer = httptest.NewServer(masterRouter)\n\n\tslaveRouter := http.NewServeMux()\n\tslaveRouter.HandleFunc(\"/metrics/snapshot\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tjson.NewEncoder(w).Encode(slaveMetrics) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\t})\n\tslaveTestServer = httptest.NewServer(slaveRouter)\n\n\trc := m.Run()\n\n\tmasterTestServer.Close()\n\tslaveTestServer.Close()\n\tos.Exit(rc)\n}\n\nfunc TestMesosMaster(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tm := Mesos{\n\t\tLog:     testutil.Logger{},\n\t\tMasters: []string{masterTestServer.Listener.Addr().String()},\n\t\tTimeout: 10,\n\t}\n\n\trequire.NoError(t, acc.GatherError(m.Gather))\n\n\tacc.AssertContainsFields(t, \"mesos\", masterMetrics)\n}\n\nfunc TestMasterFilter(t *testing.T) {\n\tm := Mesos{\n\t\tLog: testutil.Logger{},\n\t\tMasterCols: []string{\n\t\t\t\"resources\", \"master\", \"registrar\", \"allocator\",\n\t\t},\n\t}\n\tb := []string{\n\t\t\"system\", \"agents\", \"frameworks\",\n\t\t\"messages\", \"evqueue\", \"tasks\",\n\t}\n\n\tm.filterMetrics(master, &masterMetrics)\n\n\t// Assert expected metrics are present.\n\tfor _, v := range m.MasterCols {\n\t\tfor _, x := range m.getMetrics(master, v) {\n\t\t\t_, ok := masterMetrics[x]\n\t\t\trequire.Truef(t, ok, \"Didn't find key %s, it should present.\", x)\n\t\t}\n\t}\n\t// m.MasterCols includes \"allocator\", so allocator metrics should be present.\n\t// allocator metrics have unpredictable names, so we can't rely on the list of metrics returned from\n\t// getMetrics(). We have to find them by checking name prefixes.\n\tfor _, x := range masterMetricNames {\n\t\tif strings.HasPrefix(x, \"allocator/\") {\n\t\t\t_, ok := masterMetrics[x]\n\t\t\trequire.Truef(t, ok, \"Didn't find key %s, it should present.\", x)\n\t\t}\n\t}\n\n\t// Assert unexpected metrics are not present.\n\tfor _, v := range b {\n\t\tfor _, x := range m.getMetrics(master, v) {\n\t\t\t_, ok := masterMetrics[x]\n\t\t\trequire.Falsef(t, ok, \"Found key %s, it should be gone.\", x)\n\t\t}\n\t}\n\t// m.MasterCols does not include \"framework_offers\", so framework_offers metrics should not be present.\n\t// framework_offers metrics have unpredictable names, so we can't rely on the list of metrics returned from\n\t// getMetrics(). We have to find them by checking name prefixes.\n\tfor k := range masterMetrics {\n\t\tif strings.HasPrefix(k, \"master/frameworks/\") || strings.HasPrefix(k, \"frameworks/\") {\n\t\t\trequire.Failf(t, \"Wrong key\", \"Found key %s, it should be gone.\", k)\n\t\t}\n\t}\n}\n\nfunc TestMesosSlave(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tm := Mesos{\n\t\tLog:    testutil.Logger{},\n\t\tSlaves: []string{slaveTestServer.Listener.Addr().String()},\n\t\t// SlaveTasks: true,\n\t\tTimeout: 10,\n\t}\n\n\trequire.NoError(t, acc.GatherError(m.Gather))\n\n\tacc.AssertContainsFields(t, \"mesos\", slaveMetrics)\n}\n\nfunc TestSlaveFilter(t *testing.T) {\n\tm := Mesos{\n\t\tLog: testutil.Logger{},\n\t\tSlaveCols: []string{\n\t\t\t\"resources\", \"agent\", \"tasks\",\n\t\t},\n\t}\n\tb := []string{\n\t\t\"system\", \"executors\", \"messages\",\n\t}\n\n\tm.filterMetrics(slave, &slaveMetrics)\n\n\tfor _, v := range b {\n\t\tfor _, x := range m.getMetrics(slave, v) {\n\t\t\t_, ok := slaveMetrics[x]\n\t\t\trequire.Falsef(t, ok, \"Found key %s, it should be gone.\", x)\n\t\t}\n\t}\n\tfor _, v := range m.MasterCols {\n\t\tfor _, x := range m.getMetrics(slave, v) {\n\t\t\t_, ok := slaveMetrics[x]\n\t\t\trequire.Truef(t, ok, \"Didn't find key %s, it should present.\", x)\n\t\t}\n\t}\n}\n\nfunc TestWithPathDoesNotModify(t *testing.T) {\n\tu, err := url.Parse(\"http://localhost:5051\")\n\trequire.NoError(t, err)\n\tv := withPath(u, \"/xyzzy\")\n\trequire.Equal(t, \"http://localhost:5051\", u.String())\n\trequire.Equal(t, \"http://localhost:5051/xyzzy\", v.String())\n}\n\nfunc TestURLTagDoesNotModify(t *testing.T) {\n\tu, err := url.Parse(\"http://a:b@localhost:5051?timeout=1ms\")\n\trequire.NoError(t, err)\n\tv := urlTag(u)\n\trequire.Equal(t, \"http://a:b@localhost:5051?timeout=1ms\", u.String())\n\trequire.Equal(t, \"http://localhost:5051\", v)\n}\n"
  },
  {
    "path": "plugins/inputs/mesos/sample.conf",
    "content": "# Telegraf plugin for gathering metrics from N Mesos masters\n[[inputs.mesos]]\n  ## Timeout, in ms.\n  timeout = 100\n\n  ## A list of Mesos masters.\n  masters = [\"http://localhost:5050\"]\n\n  ## Master metrics groups to be collected, by default, all enabled.\n  master_collections = [\n    \"resources\",\n    \"master\",\n    \"system\",\n    \"agents\",\n    \"frameworks\",\n    \"framework_offers\",\n    \"tasks\",\n    \"messages\",\n    \"evqueue\",\n    \"registrar\",\n    \"allocator\",\n  ]\n\n  ## A list of Mesos slaves, default is []\n  # slaves = []\n\n  ## Slave metrics groups to be collected, by default, all enabled.\n  # slave_collections = [\n  #   \"resources\",\n  #   \"agent\",\n  #   \"system\",\n  #   \"executors\",\n  #   \"tasks\",\n  #   \"messages\",\n  # ]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/minecraft/README.md",
    "content": "# Minecraft Input Plugin\n\nThis plugin collects score metrics from a [Minecraft][minecraft] server using\nthe RCON protocol.\n\n> [!NOTE]\n> This plugin supports Minecraft Java Edition versions 1.11 - 1.14. When using\n> a version earlier than 1.13, be aware that the values for some criteria has\n> changed and need to be modified.\n\n⭐ Telegraf v1.4.0\n🏷️ server\n💻 all\n\n[minecraft]: https://www.minecraft.net/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collects scores from a Minecraft server's scoreboard using the RCON protocol\n[[inputs.minecraft]]\n  ## Address of the Minecraft server.\n  # server = \"localhost\"\n\n  ## Server RCON Port.\n  # port = \"25575\"\n\n  ## Server RCON Password.\n  password = \"\"\n\n  ## Uncomment to remove deprecated metric components.\n  # tagdrop = [\"server\"]\n```\n\n### Server Setup\n\nEnable [RCON][rcon] on the Minecraft server and add the following to your\n[`server.properties`][propfile] file:\n\n```conf\nenable-rcon=true\nrcon.password=<your password>\nrcon.port=<1-65535>\n```\n\nScoreboard [objectives][objectives] must be added using the server console for\nthe plugin to collect. These can be added in game by players with op status,\nfrom the server console, or over an RCON connection.\n\nWhen getting started pick an easy to test objective.  This command will add an\nobjective that counts the number of times a player has jumped:\n\n```sh\n/scoreboard objectives add jumps minecraft.custom:minecraft.jump\n```\n\nOnce a player has triggered the event they will be added to the scoreboard,\nyou can then list all players with recorded scores:\n\n```sh\n/scoreboard players list\n```\n\nView the current scores with a command, substituting your player name:\n\n```sh\n/scoreboard players list Etho\n```\n\n[rcon]: http://wiki.vg/RCON\n[propfile]: https://minecraft.gamepedia.com/Server.properties\n[objectives]: https://minecraft.gamepedia.com/Scoreboard#Objectives\n\n## Metrics\n\n- minecraft\n  - tags:\n    - player\n    - port (port of the server)\n    - server (hostname:port, deprecated in 1.11; use `source` and `port` tags)\n    - source (hostname of the server)\n  - fields:\n    - `<objective_name>` (integer, count)\n\n## Example Output\n\n```text\nminecraft,player=notch,source=127.0.0.1,port=25575 jumps=178i 1498261397000000000\nminecraft,player=dinnerbone,source=127.0.0.1,port=25575 deaths=1i,jumps=1999i,cow_kills=1i 1498261397000000000\nminecraft,player=jeb,source=127.0.0.1,port=25575 d_pickaxe=1i,damage_dealt=80i,d_sword=2i,hunger=20i,health=20i,kills=1i,level=33i,jumps=264i,armor=15i 1498261397000000000\n```\n"
  },
  {
    "path": "plugins/inputs/minecraft/client.go",
    "content": "package minecraft\n\nimport (\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gorcon/rcon\"\n)\n\nvar (\n\tscoreboardRegexLegacy = regexp.MustCompile(`(?U):\\s(?P<value>\\d+)\\s\\((?P<name>.*)\\)`)\n\tscoreboardRegex       = regexp.MustCompile(`\\[(?P<name>[^\\]]+)\\]: (?P<value>\\d+)`)\n)\n\n// connection is an established connection to the Minecraft server.\ntype connection interface {\n\t// Execute runs a command.\n\tExecute(command string) (string, error)\n}\n\n// conn is used to create connections to the Minecraft server.\ntype conn interface {\n\t// connect establishes a connection to the server.\n\tconnect() (connection, error)\n}\n\nfunc newConnector(hostname, port, password string) *connector {\n\treturn &connector{\n\t\thostname: hostname,\n\t\tport:     port,\n\t\tpassword: password,\n\t}\n}\n\ntype connector struct {\n\thostname string\n\tport     string\n\tpassword string\n}\n\nfunc (c *connector) connect() (connection, error) {\n\tclient, err := rcon.Dial(c.hostname+\":\"+c.port, c.password)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn client, nil\n}\n\nfunc newClient(connector conn) *client {\n\treturn &client{connector: connector}\n}\n\ntype client struct {\n\tconnector conn\n\tconn      connection\n}\n\nfunc (c *client) connect() error {\n\tconn, err := c.connector.connect()\n\tif err != nil {\n\t\treturn err\n\t}\n\tc.conn = conn\n\treturn nil\n}\n\nfunc (c *client) players() ([]string, error) {\n\tif c.conn == nil {\n\t\terr := c.connect()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tresp, err := c.conn.Execute(\"scoreboard players list\")\n\tif err != nil {\n\t\tc.conn = nil\n\t\treturn nil, err\n\t}\n\n\treturn parsePlayers(resp), nil\n}\n\nfunc (c *client) scores(player string) ([]score, error) {\n\tif c.conn == nil {\n\t\terr := c.connect()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tresp, err := c.conn.Execute(\"scoreboard players list \" + player)\n\tif err != nil {\n\t\tc.conn = nil\n\t\treturn nil, err\n\t}\n\n\treturn parseScores(resp), nil\n}\n\nfunc parsePlayers(input string) []string {\n\tparts := strings.SplitAfterN(input, \":\", 2)\n\tif len(parts) != 2 {\n\t\treturn nil\n\t}\n\n\tnames := strings.Split(parts[1], \",\")\n\n\t// Detect Minecraft <= 1.12\n\tif strings.Contains(parts[0], \"players on the scoreboard\") && len(names) > 0 {\n\t\t// Split the last two player names: ex: \"notch and dinnerbone\"\n\t\thead := names[:len(names)-1]\n\t\ttail := names[len(names)-1]\n\t\tnames = append(head, strings.SplitN(tail, \" and \", 2)...)\n\t}\n\n\tplayers := make([]string, 0, len(names))\n\tfor _, name := range names {\n\t\tname := strings.TrimSpace(name)\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tplayers = append(players, name)\n\t}\n\treturn players\n}\n\n// score is an individual tracked scoreboard stat.\ntype score struct {\n\tname  string\n\tvalue int64\n}\n\nfunc parseScores(input string) []score {\n\tif strings.Contains(input, \"has no scores\") {\n\t\treturn nil\n\t}\n\n\t// Detect Minecraft <= 1.12\n\tvar re *regexp.Regexp\n\tif strings.Contains(input, \"tracked objective\") {\n\t\tre = scoreboardRegexLegacy\n\t} else {\n\t\tre = scoreboardRegex\n\t}\n\n\tmatches := re.FindAllStringSubmatch(input, -1)\n\tscores := make([]score, 0, len(matches))\n\tfor _, match := range matches {\n\t\tscore := score{}\n\t\tfor i, subexp := range re.SubexpNames() {\n\t\t\tswitch subexp {\n\t\t\tcase \"name\":\n\t\t\t\tscore.name = match[i]\n\t\t\tcase \"value\":\n\t\t\t\tvalue, err := strconv.ParseInt(match[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tscore.value = value\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tscores = append(scores, score)\n\t}\n\n\treturn scores\n}\n"
  },
  {
    "path": "plugins/inputs/minecraft/client_test.go",
    "content": "package minecraft\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype mockConnection struct {\n\tcommands map[string]string\n}\n\nfunc (c *mockConnection) Execute(command string) (string, error) {\n\treturn c.commands[command], nil\n}\n\ntype mockConnector struct {\n\tconn *mockConnection\n}\n\nfunc (c *mockConnector) connect() (connection, error) {\n\treturn c.conn, nil\n}\n\nfunc TestClient_Player(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcommands map[string]string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"minecraft 1.12 no players\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"There are no tracked players on the scoreboard\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.12 single player\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"Showing 1 tracked players on the scoreboard:Etho\",\n\t\t\t},\n\t\t\texpected: []string{\"Etho\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.12 two players\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"Showing 2 tracked players on the scoreboard:Etho and torham\",\n\t\t\t},\n\t\t\texpected: []string{\"Etho\", \"torham\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.12 three players\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"Showing 3 tracked players on the scoreboard:Etho, notch and torham\",\n\t\t\t},\n\t\t\texpected: []string{\"Etho\", \"notch\", \"torham\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.12 players space in username\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"Showing 4 tracked players on the scoreboard:with space, Etho, notch and torham\",\n\t\t\t},\n\t\t\texpected: []string{\"with space\", \"Etho\", \"notch\", \"torham\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.12 players and in username\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"Showing 5 tracked players on the scoreboard:left and right, with space,Etho, notch and torham\",\n\t\t\t},\n\t\t\texpected: []string{\"left and right\", \"with space\", \"Etho\", \"notch\", \"torham\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.13 no players\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"There are no tracked entities\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.13 single player\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"There are 1 tracked entities: torham\",\n\t\t\t},\n\t\t\texpected: []string{\"torham\"},\n\t\t},\n\t\t{\n\t\t\tname: \"minecraft 1.13 multiple player\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list\": \"There are 3 tracked entities: Etho, notch, torham\",\n\t\t\t},\n\t\t\texpected: []string{\"Etho\", \"notch\", \"torham\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconnector := &mockConnector{\n\t\t\t\tconn: &mockConnection{commands: tt.commands},\n\t\t\t}\n\n\t\t\tclient := newClient(connector)\n\t\t\tactual, err := client.players()\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestClient_Scores(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tplayer   string\n\t\tcommands map[string]string\n\t\texpected []score\n\t}{\n\t\t{\n\t\t\tname:   \"minecraft 1.12 player with no scores\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Player Etho has no scores recorded\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"minecraft 1.12 player with one score\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Showing 1 tracked objective(s) for Etho:- jump: 2 (jump)\",\n\t\t\t},\n\t\t\texpected: []score{\n\t\t\t\t{name: \"jump\", value: 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"minecraft 1.12 player with many scores\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Showing 3 tracked objective(s) for Etho:- hopper: 2 (hopper)- dropper: 2 (dropper)- redstone: 1 (redstone)\",\n\t\t\t},\n\t\t\texpected: []score{\n\t\t\t\t{name: \"hopper\", value: 2},\n\t\t\t\t{name: \"dropper\", value: 2},\n\t\t\t\t{name: \"redstone\", value: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"minecraft 1.13 player with no scores\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Etho has no scores to show\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"minecraft 1.13 player with one score\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Etho has 1 scores:[jumps]: 1\",\n\t\t\t},\n\t\t\texpected: []score{\n\t\t\t\t{name: \"jumps\", value: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"minecraft 1.13 player with many scores\",\n\t\t\tplayer: \"Etho\",\n\t\t\tcommands: map[string]string{\n\t\t\t\t\"scoreboard players list Etho\": \"Etho has 3 scores:[hopper]: 2[dropper]: 2[redstone]: 1\",\n\t\t\t},\n\t\t\texpected: []score{\n\t\t\t\t{name: \"hopper\", value: 2},\n\t\t\t\t{name: \"dropper\", value: 2},\n\t\t\t\t{name: \"redstone\", value: 1},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconnector := &mockConnector{\n\t\t\t\tconn: &mockConnection{commands: tt.commands},\n\t\t\t}\n\n\t\t\tclient := newClient(connector)\n\t\t\tactual, err := client.scores(tt.player)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/minecraft/minecraft.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage minecraft\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Minecraft struct {\n\tServer   string `toml:\"server\"`\n\tPort     string `toml:\"port\"`\n\tPassword string `toml:\"password\"`\n\n\tclient cli\n}\n\n// cli is a client for the Minecraft server.\ntype cli interface {\n\t// connect establishes a connection to the server.\n\tconnect() error\n\n\t// players returns the players on the scoreboard.\n\tplayers() ([]string, error)\n\n\t// scores returns the objective scores for a player.\n\tscores(player string) ([]score, error)\n}\n\nfunc (*Minecraft) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Minecraft) Gather(acc telegraf.Accumulator) error {\n\tif s.client == nil {\n\t\tconnector := newConnector(s.Server, s.Port, s.Password)\n\t\ts.client = newClient(connector)\n\t}\n\n\tplayers, err := s.client.players()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, player := range players {\n\t\tscores, err := s.client.scores(player)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"player\": player,\n\t\t\t\"server\": s.Server + \":\" + s.Port,\n\t\t\t\"source\": s.Server,\n\t\t\t\"port\":   s.Port,\n\t\t}\n\n\t\tvar fields = make(map[string]interface{}, len(scores))\n\t\tfor _, score := range scores {\n\t\t\tfields[score.name] = score.value\n\t\t}\n\n\t\tacc.AddFields(\"minecraft\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"minecraft\", func() telegraf.Input {\n\t\treturn &Minecraft{\n\t\t\tServer: \"localhost\",\n\t\t\tPort:   \"25575\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/minecraft/minecraft_test.go",
    "content": "package minecraft\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype mockClient struct {\n\tconnectF func() error\n\tplayersF func() ([]string, error)\n\tscoresF  func(player string) ([]score, error)\n}\n\nfunc (c *mockClient) connect() error {\n\treturn c.connectF()\n}\n\nfunc (c *mockClient) players() ([]string, error) {\n\treturn c.playersF()\n}\n\nfunc (c *mockClient) scores(player string) ([]score, error) {\n\treturn c.scoresF(player)\n}\n\nfunc TestGather(t *testing.T) {\n\tnow := time.Unix(0, 0)\n\n\ttests := []struct {\n\t\tname    string\n\t\tclient  *mockClient\n\t\tmetrics []telegraf.Metric\n\t\terr     error\n\t}{\n\t\t{\n\t\t\tname: \"no players\",\n\t\t\tclient: &mockClient{\n\t\t\t\tconnectF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tplayersF: func() ([]string, error) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"one player without scores\",\n\t\t\tclient: &mockClient{\n\t\t\t\tconnectF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tplayersF: func() ([]string, error) {\n\t\t\t\t\treturn []string{\"Etho\"}, nil\n\t\t\t\t},\n\t\t\t\tscoresF: func(player string) ([]score, error) {\n\t\t\t\t\tswitch player {\n\t\t\t\t\tcase \"Etho\":\n\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanic(\"unknown player\")\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"one player with scores\",\n\t\t\tclient: &mockClient{\n\t\t\t\tconnectF: func() error {\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tplayersF: func() ([]string, error) {\n\t\t\t\t\treturn []string{\"Etho\"}, nil\n\t\t\t\t},\n\t\t\t\tscoresF: func(player string) ([]score, error) {\n\t\t\t\t\tswitch player {\n\t\t\t\t\tcase \"Etho\":\n\t\t\t\t\t\treturn []score{{name: \"jumps\", value: 42}}, nil\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanic(\"unknown player\")\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tmetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"minecraft\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"player\": \"Etho\",\n\t\t\t\t\t\t\"server\": \"example.org:25575\",\n\t\t\t\t\t\t\"source\": \"example.org\",\n\t\t\t\t\t\t\"port\":   \"25575\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"jumps\": 42,\n\t\t\t\t\t},\n\t\t\t\t\tnow,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &Minecraft{\n\t\t\t\tServer:   \"example.org\",\n\t\t\t\tPort:     \"25575\",\n\t\t\t\tPassword: \"xyzzy\",\n\t\t\t\tclient:   tt.client,\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\tacc.TimeFunc = func() time.Time { return now }\n\n\t\t\terr := plugin.Gather(&acc)\n\n\t\t\trequire.Equal(t, tt.err, err)\n\t\t\ttestutil.RequireMetricsEqual(t, tt.metrics, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/minecraft/sample.conf",
    "content": "# Collects scores from a Minecraft server's scoreboard using the RCON protocol\n[[inputs.minecraft]]\n  ## Address of the Minecraft server.\n  # server = \"localhost\"\n\n  ## Server RCON Port.\n  # port = \"25575\"\n\n  ## Server RCON Password.\n  password = \"\"\n\n  ## Uncomment to remove deprecated metric components.\n  # tagdrop = [\"server\"]\n"
  },
  {
    "path": "plugins/inputs/mock/README.md",
    "content": "# Mock Data Input Plugin\n\nThe plugin generates mock-metrics based on different algorithms like sine-wave\nfunctions, random numbers and more with the configured names and tags. Those\nmetrics are usefull during testing (e.g. processors) or if random data is\nrequired.\n\n⭐ Telegraf v1.22.0\n🏷️ testing\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Generate metrics for test and demonstration purposes\n[[inputs.mock]]\n  ## Set the metric name to use for reporting\n  metric_name = \"mock\"\n\n  ## Optional string key-value pairs of tags to add to all metrics\n  # [inputs.mock.tags]\n  # \"key\" = \"value\"\n\n  ## One or more mock data fields *must* be defined.\n  # [[inputs.mock.constant]]\n  #   name = \"constant\"\n  #   value = value_of_any_type\n  # [[inputs.mock.random]]\n  #   name = \"rand\"\n  #   min = 1.0\n  #   max = 6.0\n  # [[inputs.mock.sine_wave]]\n  #   name = \"wave\"\n  #   amplitude = 1.0\n  #   period = 0.5\n  #   phase = 20.0\n  #   base_line = 0.0\n  # [[inputs.mock.step]]\n  #   name = \"plus_one\"\n  #   start = 0.0\n  #   step = 1.0\n  # [[inputs.mock.stock]]\n  #   name = \"abc\"\n  #   price = 50.00\n  #   volatility = 0.2\n```\n\nThe mock plugin only requires that:\n\n1) Metric name is set\n2) One of the data field algorithms is defined\n\n## Available Algorithms\n\nThe available algorithms for generating mock data include:\n\n* `constant`: generate a field with the given value of type string, float, int\n  or bool\n* `random`: generate a random float, inclusive of min and max\n* `sine_wave`: produce a sine wave with a certain amplitude, period and baseline\n* `step`: always add the step value, negative values accepted\n* `stock`: generate fake, stock-like price values based on a volatility variable\n\n## Metrics\n\nMetrics are entirely based on the user's own configuration and settings.\n\n## Example Output\n\nThe following example shows all available algorithms configured with an\nadditional two tags as well:\n\n```text\nmock_sensors,building=5A,site=FTC random=4.875966794516125,abc=50,wave=0,plus_one=0 1632170840000000000\nmock_sensors,building=5A,site=FTC random=5.738651873834452,abc=45.095549448434774,wave=5.877852522924732,plus_one=1 1632170850000000000\nmock_sensors,building=5A,site=FTC random=1.0429328917205203,abc=51.928560083072924,wave=9.510565162951535,plus_one=2 1632170860000000000\nmock_sensors,building=5A,site=FTC random=5.290188595384418,abc=44.41090520217027,wave=9.510565162951536,plus_one=3 1632170870000000000\nmock_sensors,building=5A,site=FTC random=2.0724967227069135,abc=47.212167806890314,wave=5.877852522924733,plus_one=4 1632170880000000000\n```\n"
  },
  {
    "path": "plugins/inputs/mock/mock.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mock\n\nimport (\n\t_ \"embed\"\n\t\"math\"\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Mock struct {\n\tMetricName string            `toml:\"metric_name\"`\n\tTags       map[string]string `toml:\"tags\"`\n\n\tConstant []*constant `toml:\"constant\"`\n\tRandom   []*random   `toml:\"random\"`\n\tStep     []*step     `toml:\"step\"`\n\tStock    []*stock    `toml:\"stock\"`\n\tSineWave []*sineWave `toml:\"sine_wave\"`\n\n\tcounter int64\n\trand    *rand.Rand\n}\n\ntype constant struct {\n\tName  string      `toml:\"name\"`\n\tValue interface{} `toml:\"value\"`\n}\n\ntype random struct {\n\tName string  `toml:\"name\"`\n\tMin  float64 `toml:\"min\"`\n\tMax  float64 `toml:\"max\"`\n}\n\ntype sineWave struct {\n\tName      string  `toml:\"name\"`\n\tAmplitude float64 `toml:\"amplitude\"`\n\tPeriod    float64 `toml:\"period\"`\n\tPhase     float64 `toml:\"phase\"`\n\tBaseLine  float64 `toml:\"base_line\"`\n}\n\ntype step struct {\n\tName  string  `toml:\"name\"`\n\tStart float64 `toml:\"start\"`\n\tStep  float64 `toml:\"step\"`\n\n\tMin float64 `toml:\"min\" deprecated:\"1.28.2;1.35.0;use 'start' instead\"`\n\tMax float64 `toml:\"max\" deprecated:\"1.28.2;1.35.0;use 'step' instead\"`\n\n\tlatest float64\n}\n\ntype stock struct {\n\tName       string  `toml:\"name\"`\n\tPrice      float64 `toml:\"price\"`\n\tVolatility float64 `toml:\"volatility\"`\n\n\tlatest float64\n}\n\nfunc (*Mock) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Mock) Init() error {\n\tm.rand = rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec // G404: not security critical\n\n\t// backward compatibility\n\tfor _, step := range m.Step {\n\t\tif step.Min != 0 && step.Start == 0 {\n\t\t\tstep.Start = step.Min\n\t\t}\n\t\tif step.Max != 0 && step.Step == 0 {\n\t\t\tstep.Step = step.Max\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *Mock) Gather(acc telegraf.Accumulator) error {\n\tfields := make(map[string]interface{})\n\tm.generateRandomFloat64(fields)\n\tm.generateStockPrice(fields)\n\tm.generateSineWave(fields)\n\tm.generateStep(fields)\n\n\tfor _, c := range m.Constant {\n\t\tfields[c.Name] = c.Value\n\t}\n\n\ttags := make(map[string]string)\n\tfor key, value := range m.Tags {\n\t\ttags[key] = value\n\t}\n\n\tacc.AddFields(m.MetricName, fields, tags)\n\n\tm.counter++\n\n\treturn nil\n}\n\n// Generate random value between min and max, inclusively\nfunc (m *Mock) generateRandomFloat64(fields map[string]interface{}) {\n\tfor _, random := range m.Random {\n\t\tfields[random.Name] = random.Min + m.rand.Float64()*(random.Max-random.Min)\n\t}\n}\n\n// Create sine waves\nfunc (m *Mock) generateSineWave(fields map[string]interface{}) {\n\tfor _, field := range m.SineWave {\n\t\tfields[field.Name] = math.Sin((float64(m.counter)+field.Phase)*field.Period*math.Pi)*field.Amplitude + field.BaseLine\n\t}\n}\n\n// Begin at start value and then add step value every tick\nfunc (m *Mock) generateStep(fields map[string]interface{}) {\n\tfor _, step := range m.Step {\n\t\tif m.counter == 0 {\n\t\t\tstep.latest = step.Start\n\t\t} else {\n\t\t\tstep.latest += step.Step\n\t\t}\n\n\t\tfields[step.Name] = step.latest\n\t}\n}\n\n// Begin at start price and then generate random value\nfunc (m *Mock) generateStockPrice(fields map[string]interface{}) {\n\tfor _, stock := range m.Stock {\n\t\tif stock.latest == 0.0 {\n\t\t\tstock.latest = stock.Price\n\t\t} else {\n\t\t\tnoise := 2 * (m.rand.Float64() - 0.5)\n\t\t\tstock.latest = stock.latest + (stock.latest * stock.Volatility * noise)\n\n\t\t\t// avoid going below zero\n\t\t\tif stock.latest < 1.0 {\n\t\t\t\tstock.latest = 1.0\n\t\t\t}\n\t\t}\n\n\t\tfields[stock.Name] = stock.latest\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"mock\", func() telegraf.Input {\n\t\treturn &Mock{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mock/mock_test.go",
    "content": "package mock\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\ttestConstantString := &constant{\n\t\tName:  \"constant_string\",\n\t\tValue: \"a string\",\n\t}\n\ttestConstantFloat := &constant{\n\t\tName:  \"constant_float\",\n\t\tValue: 3.1415,\n\t}\n\ttestConstantInt := &constant{\n\t\tName:  \"constant_int\",\n\t\tValue: 42,\n\t}\n\ttestConstantBool := &constant{\n\t\tName:  \"constant_bool\",\n\t\tValue: true,\n\t}\n\ttestRandom := &random{\n\t\tName: \"random\",\n\t\tMin:  1.0,\n\t\tMax:  6.0,\n\t}\n\ttestSineWave := &sineWave{\n\t\tName:      \"sine\",\n\t\tAmplitude: 1.0,\n\t\tPeriod:    0.5,\n\t\tBaseLine:  2.0,\n\t}\n\ttestStep := &step{\n\t\tName:  \"step\",\n\t\tStart: 0.0,\n\t\tStep:  1.0,\n\t}\n\ttestStock := &stock{\n\t\tName:       \"abc\",\n\t\tPrice:      50.00,\n\t\tVolatility: 0.2,\n\t}\n\n\ttags := map[string]string{\n\t\t\"buildling\": \"tbd\",\n\t\t\"site\":      \"nowhere\",\n\t}\n\n\tm := &Mock{\n\t\tMetricName: \"test\",\n\t\tTags:       tags,\n\n\t\tConstant: []*constant{testConstantString, testConstantFloat, testConstantInt, testConstantBool},\n\t\tRandom:   []*random{testRandom},\n\t\tSineWave: []*sineWave{testSineWave},\n\t\tStep:     []*step{testStep},\n\t\tStock:    []*stock{testStock},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, m.Init())\n\trequire.NoError(t, m.Gather(&acc))\n\n\trequire.Len(t, acc.Metrics, 1)\n\n\tmetric := acc.Metrics[0]\n\trequire.Equal(t, \"test\", metric.Measurement)\n\trequire.Equal(t, tags, metric.Tags)\n\tfor k, v := range metric.Fields {\n\t\tswitch k {\n\t\tcase \"abc\":\n\t\t\trequire.InDelta(t, 50.0, v, testutil.DefaultDelta)\n\t\tcase \"constant_string\":\n\t\t\trequire.Equal(t, testConstantString.Value, v)\n\t\tcase \"constant_float\":\n\t\t\trequire.Equal(t, testConstantFloat.Value, v)\n\t\tcase \"constant_int\":\n\t\t\trequire.Equal(t, testConstantInt.Value, v)\n\t\tcase \"constant_bool\":\n\t\t\trequire.Equal(t, testConstantBool.Value, v)\n\t\tcase \"random\":\n\t\t\trequire.GreaterOrEqual(t, 6.0, v)\n\t\t\trequire.LessOrEqual(t, 1.0, v)\n\t\tcase \"sine\":\n\t\t\trequire.InDelta(t, 2.0, v, testutil.DefaultDelta)\n\t\tcase \"step\":\n\t\t\trequire.InDelta(t, 0.0, v, testutil.DefaultDelta)\n\t\tdefault:\n\t\t\trequire.Failf(t, \"Unexpected field\", \"Extra field: %q\", k)\n\t\t}\n\t}\n}\n\nfunc TestGatherEmpty(t *testing.T) {\n\tm := &Mock{\n\t\tMetricName: \"test_empty\",\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, m.Init())\n\trequire.NoError(t, m.Gather(&acc))\n\n\tacc.AssertDoesNotContainMeasurement(t, \"test_empty\")\n}\n"
  },
  {
    "path": "plugins/inputs/mock/sample.conf",
    "content": "# Generate metrics for test and demonstration purposes\n[[inputs.mock]]\n  ## Set the metric name to use for reporting\n  metric_name = \"mock\"\n\n  ## Optional string key-value pairs of tags to add to all metrics\n  # [inputs.mock.tags]\n  # \"key\" = \"value\"\n\n  ## One or more mock data fields *must* be defined.\n  # [[inputs.mock.constant]]\n  #   name = \"constant\"\n  #   value = value_of_any_type\n  # [[inputs.mock.random]]\n  #   name = \"rand\"\n  #   min = 1.0\n  #   max = 6.0\n  # [[inputs.mock.sine_wave]]\n  #   name = \"wave\"\n  #   amplitude = 1.0\n  #   period = 0.5\n  #   phase = 20.0\n  #   base_line = 0.0\n  # [[inputs.mock.step]]\n  #   name = \"plus_one\"\n  #   start = 0.0\n  #   step = 1.0\n  # [[inputs.mock.stock]]\n  #   name = \"abc\"\n  #   price = 50.00\n  #   volatility = 0.2\n"
  },
  {
    "path": "plugins/inputs/modbus/README.md",
    "content": "<!-- markdownlint-disable MD024 -->\n# Modbus Input Plugin\n\nThis plugin collects data from [Modbus][modbus] registers using e.g. Modbus TCP\nor serial interfaces with Modbus RTU or Modbus ASCII.\n\n⭐ Telegraf v1.14.0\n🏷️ iot\n💻 all\n\n[modbus]: https://www.modbus.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample_general_begin.conf @sample_register.conf @sample_request.conf @sample_metric.conf @sample_general_end.conf\n# Retrieve data from MODBUS slave devices\n[[inputs.modbus]]\n  ## Connection Configuration\n  ##\n  ## The plugin supports connections to PLCs via MODBUS/TCP, RTU over TCP, ASCII over TCP or\n  ## via serial line communication in binary (RTU) or readable (ASCII) encoding\n  ##\n  ## Device name\n  name = \"Device\"\n\n  ## Slave ID - addresses a MODBUS device on the bus\n  ## Range: 0 - 255 [0 = broadcast; 248 - 255 = reserved]\n  slave_id = 1\n\n  ## Timeout for each request\n  timeout = \"1s\"\n\n  ## Maximum number of retries and the time to wait between retries\n  ## when a slave-device is busy.\n  # busy_retries = 0\n  # busy_retries_wait = \"100ms\"\n\n  # TCP - connect via Modbus/TCP\n  controller = \"tcp://localhost:502\"\n\n  ## Serial (RS485; RS232)\n  ## For RS485 specific setting check the end of the configuration.\n  ## For unix-like operating systems use:\n  # controller = \"file:///dev/ttyUSB0\"\n  ## For Windows operating systems use:\n  # controller = \"COM1\"\n  # baud_rate = 9600\n  # data_bits = 8\n  # parity = \"N\"\n  # stop_bits = 1\n\n  ## Transmission mode for Modbus packets depending on the controller type.\n  ## For Modbus over TCP you can choose between \"TCP\" , \"RTUoverTCP\" and\n  ## \"ASCIIoverTCP\".\n  ## For Serial controllers you can choose between \"RTU\" and \"ASCII\".\n  ## By default this is set to \"auto\" selecting \"TCP\" for ModbusTCP connections\n  ## and \"RTU\" for serial connections.\n  # transmission_mode = \"auto\"\n\n  ## Trace the connection to the modbus device\n  # log_level = \"trace\"\n\n  ## Define the configuration schema\n  ##  |---register -- define fields per register type in the original style (only supports one slave ID)\n  ##  |---request  -- define fields on a requests base\n  ##  |---metric   -- define fields on a metric base\n  configuration_type = \"register\"\n\n  ## Exclude the register type tag\n  ## Please note, this will also influence the grouping of metrics as you won't\n  ## see one metric per register type anymore!\n  # exclude_register_type_tag = false\n\n  ## --- \"register\" configuration style ---\n\n  ## Measurements\n  ##\n\n  ## Digital Variables, Discrete Inputs and Coils\n  ## measurement - the (optional) measurement name, defaults to \"modbus\"\n  ## name        - the variable name\n  ## data_type   - the (optional) output type, can be BOOL or UINT16 (default)\n  ## address     - variable address\n\n  discrete_inputs = [\n    { name = \"start\",          address = [0]},\n    { name = \"stop\",           address = [1]},\n    { name = \"reset\",          address = [2]},\n    { name = \"emergency_stop\", address = [3]},\n  ]\n  coils = [\n    { name = \"motor1_run\",     address = [0]},\n    { name = \"motor1_jog\",     address = [1]},\n    { name = \"motor1_stop\",    address = [2]},\n  ]\n\n  ## Analog Variables, Input Registers and Holding Registers\n  ## measurement - the (optional) measurement name, defaults to \"modbus\"\n  ## name        - the variable name\n  ## byte_order  - the ordering of bytes\n  ##  |---AB, ABCD   - Big Endian\n  ##  |---BA, DCBA   - Little Endian\n  ##  |---BADC       - Mid-Big Endian\n  ##  |---CDAB       - Mid-Little Endian\n  ## data_type   - BIT (single bit of a register)\n  ##               INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n  ##               INT16, UINT16, INT32, UINT32, INT64, UINT64,\n  ##               FLOAT16-IEEE, FLOAT32-IEEE, FLOAT64-IEEE (IEEE 754 binary representation)\n  ##               FIXED, UFIXED (fixed-point representation on input)\n  ##               STRING (byte-sequence converted to string)\n  ## bit         - (optional) bit of the register, ONLY valid for BIT type\n  ## scale       - the final numeric variable representation\n  ## address     - variable address\n\n  holding_registers = [\n    { name = \"power_factor\", byte_order = \"AB\",   data_type = \"FIXED\", scale=0.01,  address = [8]},\n    { name = \"voltage\",      byte_order = \"AB\",   data_type = \"FIXED\", scale=0.1,   address = [0]},\n    { name = \"energy\",       byte_order = \"ABCD\", data_type = \"FIXED\", scale=0.001, address = [5,6]},\n    { name = \"current\",      byte_order = \"ABCD\", data_type = \"FIXED\", scale=0.001, address = [1,2]},\n    { name = \"frequency\",    byte_order = \"AB\",   data_type = \"UFIXED\", scale=0.1,  address = [7]},\n    { name = \"power\",        byte_order = \"ABCD\", data_type = \"UFIXED\", scale=0.1,  address = [3,4]},\n    { name = \"firmware\",     byte_order = \"AB\",   data_type = \"STRING\", address = [5, 6, 7, 8, 9, 10, 11, 12]},\n  ]\n  input_registers = [\n    { name = \"tank_level\",   byte_order = \"AB\",   data_type = \"INT16\",   scale=1.0,     address = [0]},\n    { name = \"tank_ph\",      byte_order = \"AB\",   data_type = \"INT16\",   scale=1.0,     address = [1]},\n    { name = \"pump1_speed\",  byte_order = \"ABCD\", data_type = \"INT32\",   scale=1.0,     address = [3,4]},\n  ]\n\n  ## --- \"request\" configuration style ---\n\n  ## Per request definition\n  ##\n\n  ## Define a request sent to the device\n  ## Multiple of those requests can be defined. Data will be collated into metrics at the end of data collection.\n  [[inputs.modbus.request]]\n    ## ID of the modbus slave device to query.\n    ## If you need to query multiple slave-devices, create several \"request\" definitions.\n    slave_id = 1\n\n    ## Byte order of the data.\n    ##  |---ABCD -- Big Endian (Motorola)\n    ##  |---DCBA -- Little Endian (Intel)\n    ##  |---BADC -- Big Endian with byte swap\n    ##  |---CDAB -- Little Endian with byte swap\n    byte_order = \"ABCD\"\n\n    ## Type of the register for the request\n    ## Can be \"coil\", \"discrete\", \"holding\" or \"input\"\n    register = \"coil\"\n\n    ## Name of the measurement.\n    ## Can be overridden by the individual field definitions. Defaults to \"modbus\"\n    # measurement = \"modbus\"\n\n    ## Request optimization algorithm.\n    ##  |---none       -- Do not perform any optimization and use the given layout(default)\n    ##  |---shrink     -- Shrink requests to actually requested fields\n    ##  |                 by stripping leading and trailing omits\n    ##  |---rearrange  -- Rearrange request boundaries within consecutive address ranges\n    ##  |                 to reduce the number of requested registers by keeping\n    ##  |                 the number of requests.\n    ##  |---max_insert -- Rearrange request keeping the number of extra fields below the value\n    ##                    provided in \"optimization_max_register_fill\". It is not necessary to define 'omitted'\n    ##                    fields as the optimisation will add such field only where needed.\n    # optimization = \"none\"\n\n    ## Maximum number register the optimizer is allowed to insert between two fields to\n    ## save requests.\n    ## This option is only used for the 'max_insert' optimization strategy.\n    ## NOTE: All omitted fields are ignored, so this option denotes the effective hole\n    ## size to fill.\n    # optimization_max_register_fill = 50\n\n    ## Field definitions\n    ## Analog Variables, Input Registers and Holding Registers\n    ## address        - address of the register to query. For coil and discrete inputs this is the bit address.\n    ## name *1        - field name\n    ## type *1,2      - type of the modbus field, can be\n    ##                  BIT (single bit of a register)\n    ##                  INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n    ##                  INT16, UINT16, INT32, UINT32, INT64, UINT64 and\n    ##                  FLOAT16, FLOAT32, FLOAT64 (IEEE 754 binary representation)\n    ##                  STRING (byte-sequence converted to string)\n    ## length *1,2    - (optional) number of registers, ONLY valid for STRING type\n    ## bit *1,2       - (optional) bit of the register, ONLY valid for BIT type\n    ## scale *1,2,4   - (optional) factor to scale the variable with\n    ## output *1,3,4  - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64.\n    ##                  Defaults to FLOAT64 for numeric fields if \"scale\" is provided.\n    ##                  Otherwise the input \"type\" class is used (e.g. INT* -> INT64).\n    ## measurement *1 - (optional) measurement name, defaults to the setting of the request\n    ## omit           - (optional) omit this field. Useful to leave out single values when querying many registers\n    ##                  with a single request. Defaults to \"false\".\n    ##\n    ## *1: These fields are ignored if field is omitted (\"omit\"=true)\n    ## *2: These fields are ignored for both \"coil\" and \"discrete\"-input type of registers.\n    ## *3: This field can only be \"UINT16\" or \"BOOL\" if specified for both \"coil\"\n    ##     and \"discrete\"-input type of registers. By default the fields are\n    ##     output as zero or one in UINT16 format unless \"BOOL\" is used.\n    ## *4: These fields cannot be used with \"STRING\"-type fields.\n\n    ## Coil / discrete input example\n    fields = [\n      { address=0, name=\"motor1_run\" },\n      { address=1, name=\"jog\", measurement=\"motor\" },\n      { address=2, name=\"motor1_stop\", omit=true },\n      { address=3, name=\"motor1_overheating\", output=\"BOOL\" },\n      { address=4, name=\"firmware\", type=\"STRING\", length=8 },\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n\n  [[inputs.modbus.request]]\n    ## Holding example\n    ## All of those examples will result in FLOAT64 field outputs\n    slave_id = 1\n    byte_order = \"DCBA\"\n    register = \"holding\"\n    fields = [\n      { address=0, name=\"voltage\",      type=\"INT16\",   scale=0.1   },\n      { address=1, name=\"current\",      type=\"INT32\",   scale=0.001 },\n      { address=3, name=\"power\",        type=\"UINT32\",  omit=true   },\n      { address=5, name=\"energy\",       type=\"FLOAT32\", scale=0.001, measurement=\"W\" },\n      { address=7, name=\"frequency\",    type=\"UINT32\",  scale=0.1   },\n      { address=8, name=\"power_factor\", type=\"INT64\",   scale=0.01  },\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n\n  [[inputs.modbus.request]]\n    ## Input example with type conversions\n    slave_id = 1\n    byte_order = \"ABCD\"\n    register = \"input\"\n    fields = [\n      { address=0, name=\"rpm\",         type=\"INT16\"                   },  # will result in INT64 field\n      { address=1, name=\"temperature\", type=\"INT16\", scale=0.1        },  # will result in FLOAT64 field\n      { address=2, name=\"force\",       type=\"INT32\", output=\"FLOAT64\" },  # will result in FLOAT64 field\n      { address=4, name=\"hours\",       type=\"UINT32\"                  },  # will result in UIN64 field\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n\n  ## --- \"metric\" configuration style ---\n\n  ## Per metric definition\n  ##\n\n  ## Request optimization algorithm across metrics\n  ##  |---none       -- Do not perform any optimization and just group requests\n  ##  |                 within metrics (default)\n  ##  |---max_insert -- Collate registers across all defined metrics and fill in\n  ##                    holes to optimize the number of requests.\n  # optimization = \"none\"\n\n  ## Maximum number of registers the optimizer is allowed to insert between\n  ## non-consecutive registers to save requests.\n  ## This option is only used for the 'max_insert' optimization strategy and\n  ## effectively denotes the hole size between registers to fill.\n  # optimization_max_register_fill = 50\n\n  ## Define a metric produced by the requests to the device\n  ## Multiple of those metrics can be defined. The referenced registers will\n  ## be collated into requests send to the device\n  [[inputs.modbus.metric]]\n    ## ID of the modbus slave device to query\n    ## If you need to query multiple slave-devices, create several \"metric\" definitions.\n    slave_id = 1\n\n    ## Byte order of the data\n    ##  |---ABCD -- Big Endian (Motorola)\n    ##  |---DCBA -- Little Endian (Intel)\n    ##  |---BADC -- Big Endian with byte swap\n    ##  |---CDAB -- Little Endian with byte swap\n    # byte_order = \"ABCD\"\n\n    ## Name of the measurement\n    # measurement = \"modbus\"\n\n    ## Field definitions\n    ## register    - type of the modbus register, can be \"coil\", \"discrete\",\n    ##               \"holding\" or \"input\". Defaults to \"holding\".\n    ## address     - address of the register to query. For coil and discrete inputs this is the bit address.\n    ## name        - field name\n    ## type *1     - type of the modbus field, can be\n    ##                 BIT (single bit of a register)\n    ##                 INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n    ##                 INT16, UINT16, INT32, UINT32, INT64, UINT64 and\n    ##                 FLOAT16, FLOAT32, FLOAT64 (IEEE 754 binary representation)\n    ##                 STRING (byte-sequence converted to string)\n    ## length *1   - (optional) number of registers, ONLY valid for STRING type\n    ## bit *1,2    - (optional) bit of the register, ONLY valid for BIT type\n    ## scale *1,3  - (optional) factor to scale the variable with\n    ## output *2,3 - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64. Defaults to FLOAT64 if\n    ##               \"scale\" is provided and to the input \"type\" class otherwise (INT* -> INT64, etc).\n    ##\n    ## *1: These fields are ignored for both \"coil\" and \"discrete\"-input type of registers.\n    ## *2: This field can only be \"UINT16\" or \"BOOL\" if specified for both \"coil\"\n    ##     and \"discrete\"-input type of registers. By default the fields are\n    ##     output as zero or one in UINT16 format unless \"BOOL\" is used.\n    ## *3: These fields cannot be used with \"STRING\"-type fields.\n    fields = [\n      { register=\"coil\",    address=0, name=\"door_open\"},\n      { register=\"coil\",    address=1, name=\"status_ok\"},\n      { register=\"holding\", address=0, name=\"voltage\",      type=\"INT16\"   },\n      { address=1, name=\"current\",      type=\"INT32\",   scale=0.001 },\n      { address=5, name=\"energy\",       type=\"FLOAT32\", scale=0.001 },\n      { address=7, name=\"frequency\",    type=\"UINT32\",  scale=0.1   },\n      { address=8, name=\"power_factor\", type=\"INT64\",   scale=0.01  },\n      { address=9, name=\"firmware\",     type=\"STRING\",  length=8    },\n    ]\n\n    ## Tags assigned to the metric\n    # [inputs.modbus.metric.tags]\n    #   machine = \"impresser\"\n    #   location = \"main building\"\n\n  ## RS485 specific settings. Only take effect for serial controllers.\n  ## Note: This has to be at the end of the modbus configuration due to\n  ## TOML constraints.\n  # [inputs.modbus.rs485]\n    ## Delay RTS prior to sending\n    # delay_rts_before_send = \"0ms\"\n    ## Delay RTS after to sending\n    # delay_rts_after_send = \"0ms\"\n    ## Pull RTS line to high during sending\n    # rts_high_during_send = false\n    ## Pull RTS line to high after sending\n    # rts_high_after_send = false\n    ## Enabling receiving (Rx) during transmission (Tx)\n    # rx_during_tx = false\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.modbus.workarounds]\n    ## Pause after connect delays the first request by the specified time.\n    ## This might be necessary for (slow) devices.\n    # pause_after_connect = \"0ms\"\n\n    ## Pause between read requests sent to the device.\n    ## This might be necessary for (slow) serial devices.\n    # pause_between_requests = \"0ms\"\n\n    ## Close the connection after every gather cycle.\n    ## Usually the plugin closes the connection after a certain idle-timeout,\n    ## however, if you query a device with limited simultaneous connectivity\n    ## (e.g. serial devices) from multiple instances you might want to only\n    ## stay connected during gather and disconnect afterwards.\n    # close_connection_after_gather = false\n\n    ## Force the plugin to read each field in a separate request.\n    ## This might be necessary for devices not conforming to the spec,\n    ## see https://github.com/influxdata/telegraf/issues/12071.\n    # one_request_per_field = false\n\n    ## Enforce the starting address to be zero for the first request on\n    ## coil registers. This is necessary for some devices see\n    ## https://github.com/influxdata/telegraf/issues/8905\n    # read_coils_starting_at_zero = false\n\n    ## String byte-location in registers AFTER byte-order conversion\n    ## Some device (e.g. EM340) place the string byte in only the upper or\n    ## lower byte location of a register see\n    ## https://github.com/influxdata/telegraf/issues/14748\n    ## Available settings:\n    ##   lower -- use only lower byte of the register (00XX 00XX 00XX 00XX)\n    ##   upper -- use only upper byte of the register (XX00 XX00 XX00 XX00)\n    ## By default both bytes of the register are used (XXXX XXXX).\n    # string_register_location = \"\"\n```\n\n## Notes\n\nYou can debug Modbus connection issues by enabling `debug_connection`. To see\nthose debug messages, Telegraf has to be started with debugging enabled\n(with the `--debug` option). Please be aware that connection tracing will\nproduce a lot of messages and should __NOT__ be used in production environments.\n\nPlease use `pause_after_connect` / `pause_between_requests` with care. Ensure\nthe total gather time, including the pause(s), does not exceed the configured\ncollection interval. Note that pauses add up if multiple requests are sent!\n\n## Configuration styles\n\nThe modbus plugin supports multiple configuration styles that can be set using\nthe `configuration_type` setting. The different styles are described\nbelow. Please note that styles cannot be mixed.\nOnly the settings belonging to the configured `configuration_type` are used for constructing _modbus_\nrequests and creation of metrics.\n\nDirectly jump to the styles:\n\n- [original / register plugin style](#register-configuration-style)\n- [per-request style](#request-configuration-style)\n- [per-metrict style](#metric-configuration-style)\n\n---\n\n### `register` configuration style\n\nThis is the original style used by this plugin. It allows a per-register\nconfiguration for a single slave-device.\n\n> [!NOTE]\n> For legacy reasons this configuration style is not completely consistent with\n> the other styles.\n\n#### Usage of `data_type`\n\nThe field `data_type` defines the representation of the data value on input from\nthe modbus registers.  The input values are then converted from the given\n`data_type` to a type that is appropriate when sending the value to the output\nplugin. These output types are usually an integer or floating-point-number. The\nsize of the output type is assumed to be large enough for all supported input\ntypes. The mapping from the input type to the output type is fixed and cannot\nbe configured.\n\n##### Booleans: `BOOL`\n\nThis type is only valid for _coil_ and _discrete_ registers. The value will be\n`true` if the register has a non-zero (ON) value and `false` otherwise.\n\n##### Integers: `INT8L`, `INT8H`, `UINT8L`, `UINT8H`\n\nThese types are used for 8-bit integer values. Select the one that matches your\nmodbus data source. The `L` and `H` suffix denotes the low- and high byte of\nthe register respectively.\n\n##### Integers: `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64`, `UINT64`\n\nThese types are used for integer input values. Select the one that matches your\nmodbus data source. For _coil_ and _discrete_ registers only `UINT16` is valid.\n\n##### Floating Point: `FLOAT16-IEEE`, `FLOAT32-IEEE`, `FLOAT64-IEEE`\n\nUse these types if your modbus registers contain a value that is encoded in this\nformat. These types always include the sign, therefore no variant exists.\n\n##### Fixed Point: `FIXED`, `UFIXED`\n\nThese types are handled as an integer type on input, but are converted to\nfloating point representation for further processing (e.g. scaling). Use one of\nthese types when the input value is a decimal fixed point representation of a\nnon-integer value.\n\nSelect the type `UFIXED` when the input type is declared to hold unsigned\ninteger values, which cannot be negative. The documentation of your modbus\ndevice should indicate this by a term like 'uint16 containing fixed-point\nrepresentation with N decimal places'.\n\nSelect the type `FIXED` when the input type is declared to hold signed integer\nvalues. Your documentation of the modbus device should indicate this with a term\nlike 'int32 containing fixed-point representation with N decimal places'.\n\n##### String: `STRING`\n\nThis type is used to query the number of registers specified in the `address`\nsetting and convert the byte-sequence to a string. Please note, if the\nbyte-sequence contains a `null` byte, the string is truncated at this position.\nYou cannot use the `scale` setting for string fields.\n\n##### Bit: `BIT`\n\nThis type is used to query a single bit of a register specified in the `address`\nsetting and convert the value to an unsigned integer. This type __requires__ the\n`bit` setting to be specified.\n\n---\n\n### `request` configuration style\n\nThis style can be used to specify the modbus requests directly. It enables\nspecifying multiple `[[inputs.modbus.request]]` sections including multiple\nslave-devices. This way, _modbus_ gateway devices can be queried. Please note\nthat _requests_ might be split for non-consecutive addresses. If you want to\navoid this behavior please add _fields_ with the `omit` flag set filling the\ngaps between addresses.\n\n#### Slave device\n\nYou can use the `slave_id` setting to specify the ID of the slave device to\nquery. It should be specified for each request, otherwise it defaults to\nzero. Please note, only one `slave_id` can be specified per request.\n\n#### Byte order of the register\n\nThe `byte_order` setting specifies the byte and word-order of the registers. It\ncan be set to `ABCD` for _big endian (Motorola)_ or `DCBA` for _little endian\n(Intel)_ format as well as `BADC` and `CDAB` for _big endian_ or _little endian_\nwith _byte swap_.\n\n#### Register type\n\nThe `register` setting specifies the modbus register-set to query and can be set\nto `coil`, `discrete`, `holding` or `input`.\n\n#### Per-request measurement setting\n\nYou can specify the name of the measurement for the following field definitions\nusing the `measurement` setting. If the setting is omitted `modbus` is\nused. Furthermore, the measurement value can be overridden by each field\nindividually.\n\n#### Optimization setting\n\n__Please only use request optimization if you do understand the implications!__\nThe `optimization` setting can be used to optimize the actual requests sent to\nthe device. The following algorithms are available\n\n##### `none` (_default_)\n\nDo not perform any optimization. Please note that the requests are still obeying\nthe maximum request sizes. Furthermore, completely empty requests (where all\nfields specify `omit=true`) are removed. Otherwise, the requests are sent as\nspecified by the user including request of omitted fields. This setting should\nbe used if you want full control over the requests e.g. to accommodate for\ndevice constraints.\n\n##### `shrink`\n\nThis optimization allows to remove leading and trailing fields from requests if\nthose fields are omitted. This can shrink the request number and sizes in cases\nwhere you specify large amounts of omitted fields, e.g. for documentation\npurposes.\n\n##### `rearrange`\n\nRequests are processed similar to `shrink` but the request boundaries are\nrearranged such that usually less registers are being read while keeping the\nnumber of requests. This optimization algorithm only works on consecutive\naddress ranges and respects user-defined gaps in the field addresses.\n\n__Please note:__ This optimization might take long in case of many\nnon-consecutive, non-omitted fields!\n\n##### `max_insert`\n\nFields are assigned to the same request as long as the hole between the fields\ndo not exceed the maximum fill size given in `optimization_max_register_fill`.\nUser-defined omitted fields are ignored and interpreted as holes, so the best\npractice is to not manually insert omitted fields for this optimizer. This\nallows to specify only actually used fields and let the optimizer figure out\nthe request organization which can dramatically improve query time. The\ntrade-off here is between the cost of reading additional registers trashed\nlater and the cost of many requests.\n\n__Please note:__ The optimal value for `optimization_max_register_fill` depends\non the network and the queried device. It is hence recommended to test several\nvalues and assess performance in order to find the best value. Use the\n`--test --debug` flags to monitor how may requests are sent and the number of\ntouched registers.\n\n#### Field definitions\n\nEach `request` can contain a list of fields to collect from the modbus device.\n\n##### address\n\nA field is identified by an `address` that reflects the modbus register\naddress. You can usually find the address values for the different data-points\nin the datasheet of your modbus device. This is a mandatory setting.\n\nFor _coil_ and _discrete input_ registers this setting specifies the __bit__\ncontaining the value of the field.\n\n##### name\n\nUsing the `name` setting you can specify the field-name in the metric as output\nby the plugin. This setting is ignored if the field's `omit` is set to `true`\nand can be omitted in this case.\n\n__Please note:__ There cannot be multiple fields with the same `name` in one\nmetric identified by `measurement`, `slave_id` and `register`.\n\n##### register datatype\n\nThe `type` setting specifies the datatype of the modbus register and can be\nset to `INT8L`, `INT8H`, `UINT8L`, `UINT8H` where `L` is the lower byte of the\nregister and `H` is the higher byte.\nFurthermore, the types `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64` or `UINT64`\nfor integer types or `FLOAT16`, `FLOAT32` and `FLOAT64` for IEEE 754 binary\nrepresentations of floating point values exist. `FLOAT16` denotes a\nhalf-precision float with a 16-bit representation.\nUsually the datatype of the register is listed in the datasheet of your modbus\ndevice in relation to the `address` described above.\n\nThe `STRING` datatype is special in that it requires the `length` setting to\nbe specified containing the length (in terms of number of registers) containing\nthe string. The returned byte-sequence is interpreted as string and truncated\nto the first `null` byte found if any. The `scale` and `output` setting cannot\nbe used for this `type`.\n\nThis setting is ignored if the field's `omit` is set to `true` or if the\n`register` type is a bit-type (`coil` or `discrete`) and can be omitted in\nthese cases.\n\n##### scaling\n\nYou can use the `scale` setting to scale the register values, e.g. if the\nregister contains a fix-point values in `UINT32` format with two decimal places\nfor example. To convert the read register value to the actual value you can set\nthe `scale=0.01`. The scale is used as a factor e.g. `field_value * scale`.\n\nThis setting is ignored if the field's `omit` is set to `true` or if the\n`register` type is a bit-type (`coil` or `discrete`) and can be omitted in these\ncases.\n\n__Please note:__ The resulting field-type will be set to `FLOAT64` if no output\nformat is specified.\n\n##### output datatype\n\nUsing the `output` setting you can explicitly specify the output\nfield-datatype. The `output` type can be `INT64`, `UINT64` or `FLOAT64`. If not\nset explicitly, the output type is guessed as follows: If `scale` is set to a\nnon-zero value, the output type is `FLOAT64`. Otherwise, the output type\ncorresponds to the register datatype _class_ (`INT*` will result in\n`INT64`, `UINT*` in `UINT64`, and `FLOAT*` in `FLOAT64`).\n\nThis setting is ignored if the field's `omit` is set to `true` and can be\nomitted. In case the `register` type is a bit-type (`coil` or `discrete`) only\n`UINT16` or `BOOL` are valid with the former being the default if omitted.\nFor `coil` and `discrete` registers the field-value is output as zero or one in\n`UINT16` format or as `true` and `false` in `BOOL` format.\n\n#### per-field measurement setting\n\nThe `measurement` setting can be used to override the measurement name on a\nper-field basis. This might be useful if you want to split the fields in one\nrequest to multiple measurements. If not specified, the value specified in the\n[`request` section](#per-request-measurement-setting) or, if also omitted,\n`modbus` is used.\n\nThis setting is ignored if the field's `omit` is set to `true` and can be\nomitted in this case.\n\n#### omitting a field\n\nWhen specifying `omit=true`, the corresponding field will be ignored when\ncollecting the metric but is taken into account when constructing the modbus\nrequests. This way, you can fill \"holes\" in the addresses to construct\nconsecutive address ranges resulting in a single request. Using a single modbus\nrequest can be beneficial as the values are all collected at the same point in\ntime.\n\n#### Tags definitions\n\nEach `request` can be accompanied by tags valid for this request.\n\n__Please note:__ These tags take precedence over predefined tags such as `name`,\n`type` or `slave_id`.\n\n---\n\n### `metric` configuration style\n\nThis style can be used to specify the desired metrics directly instead of\nfocusing on the modbus view. Multiple `[[inputs.modbus.metric]]` sections\nincluding multiple slave-devices can be specified. This way, _modbus_ gateway\ndevices can be queried. The plugin automatically collects registers across\nthe specified metrics, groups them per slave and register-type and (optionally)\noptimizes the resulting requests for non-consecutive addresses.\n\n#### Slave device\n\nYou can use the `slave_id` setting to specify the ID of the slave device to\nquery. It should be specified for each metric section, otherwise it defaults to\nzero. Please note, only one `slave_id` can be specified per metric section.\n\n#### Byte order of the registers\n\nThe `byte_order` setting specifies the byte and word-order of the registers. It\ncan be set to `ABCD` for _big endian (Motorola)_ or `DCBA` for _little endian\n(Intel)_ format as well as `BADC` and `CDAB` for _big endian_ or _little endian_\nwith _byte swap_.\n\n#### Measurement name\n\nYou can specify the name of the measurement for the fields defined in the\ngiven section using the `measurement` setting. If the setting is omitted\n`modbus` is used.\n\n#### Optimization setting\n\n__Please only use request optimization if you do understand the implications!__\nThe `optimization` setting can be specified globally (__NOT__ per metric\nsection) and is used to optimize the actual requests sent to the device. Here,\nthe optimization is applied across _all metric sections_! The following\nalgorithms are available\n\n##### `none` (_default_)\n\nDo not perform any optimization. Please note that consecutive registers are\nstill grouped into one requests while obeying the maximum request sizes. This\nsetting should be used if you want to touch as less registers as possible at\nthe cost of more requests sent to the device.\n\n##### `max_insert`\n\nFields are assigned to the same request as long as the hole between the touched\nregisters does not exceed the maximum fill size given via\n`optimization_max_register_fill`. This optimization might lead to a drastically\nreduced request number and thus an improved query time. The trade-off here is\nbetween the cost of reading additional registers trashed later and the cost of\nmany requests.\n\n__Please note:__ The optimal value for `optimization_max_register_fill` depends\non the network and the queried device. It is hence recommended to test several\nvalues and assess performance in order to find the best value. Use the\n`--test --debug` flags to monitor how may requests are sent and the number of\ntouched registers.\n\n#### Field definitions\n\nEach `metric` can contain a list of fields to collect from the modbus device.\nThe specified fields directly corresponds to the fields of the resulting metric.\n\n##### register\n\nThe `register` setting specifies the modbus register-set to query and can be set\nto `coil`, `discrete`, `holding` or `input`.\n\n##### address\n\nA field is identified by an `address` that reflects the modbus register\naddress. You can usually find the address values for the different data-points\nin the datasheet of your modbus device. This is a mandatory setting.\n\nFor _coil_ and _discrete input_ registers this setting specifies the __bit__\ncontaining the value of the field.\n\n##### name\n\nUsing the `name` setting you can specify the field-name in the metric as output\nby the plugin.\n\n__Please note:__ There cannot be multiple fields with the same `name` in one\nmetric identified by `measurement`, `slave_id`, `register` and tag-set.\n\n##### register datatype\n\nThe `type` setting specifies the datatype of the modbus register and can be\nset to `INT8L`, `INT8H`, `UINT8L`, `UINT8H` where `L` is the lower byte of the\nregister and `H` is the higher byte.\nFurthermore, the types `INT16`, `UINT16`, `INT32`, `UINT32`, `INT64` or `UINT64`\nfor integer types or `FLOAT16`, `FLOAT32` and `FLOAT64` for IEEE 754 binary\nrepresentations of floating point values exist. `FLOAT16` denotes a\nhalf-precision float with a 16-bit representation.\nUsually the datatype of the register is listed in the datasheet of your modbus\ndevice in relation to the `address` described above.\n\nThe `STRING` datatype is special in that it requires the `length` setting to\nbe specified containing the length (in terms of number of registers) containing\nthe string. The returned byte-sequence is interpreted as string and truncated\nto the first `null` byte found if any. The `scale` and `output` setting cannot\nbe used for this `type`.\n\nThis setting is ignored if the `register` is a bit-type (`coil` or `discrete`)\nand can be omitted in these cases.\n\n##### scaling\n\nYou can use the `scale` setting to scale the register values, e.g. if the\nregister contains a fix-point values in `UINT32` format with two decimal places\nfor example. To convert the read register value to the actual value you can set\nthe `scale=0.01`. The scale is used as a factor e.g. `field_value * scale`.\n\nThis setting is ignored if the `register` is a bit-type (`coil` or `discrete`)\nand can be omitted in these cases.\n\n__Please note:__ The resulting field-type will be set to `FLOAT64` if no output\nformat is specified.\n\n##### output datatype\n\nUsing the `output` setting you can explicitly specify the output\nfield-datatype. The `output` type can be `INT64`, `UINT64` or `FLOAT64`. If not\nset explicitly, the output type is guessed as follows: If `scale` is set to a\nnon-zero value, the output type is `FLOAT64`. Otherwise, the output type\ncorresponds to the register datatype _class_ (`INT*` will result in\n`INT64`, `UINT*` in `UINT64`, and `FLOAT*` in `FLOAT64`).\n\nIn case the `register` is a bit-type (`coil` or `discrete`) only `UINT16` or\n`BOOL` are valid with the former being the default if omitted. For `coil` and\n`discrete` registers the field-value is output as zero or one in `UINT16` format\nor as `true` and `false` in `BOOL` format.\n\n#### Tags definitions\n\nEach `metric` can be accompanied by a set of tag. These tags directly correspond\nto the tags of the resulting metric.\n\n__Please note:__ These tags take precedence over predefined tags such as `name`,\n`type` or `slave_id`.\n\n---\n\n## Troubleshooting\n\n### Strange data\n\nModbus documentation is often a mess. People confuse memory-address (starts at\none) and register address (starts at zero) or are unsure about the word-order\nused. Furthermore, there are some non-standard implementations that also swap\nthe bytes within the register word (16-bit).\n\nIf you get an error or don't get the expected values from your device, you can\ntry the following steps (assuming a 32-bit value).\n\nIf you are using a serial device and get a `permission denied` error, check the\npermissions of your serial device and change them accordingly.\n\nIn case you get an `exception '2' (illegal data address)` error you might try to\noffset your `address` entries by minus one as it is very likely that there is\nconfusion between memory and register addresses.\n\nIf you see strange values, the `byte_order` might be wrong. You can either probe\nall combinations (`ABCD`, `CDBA`, `BADC` or `DCBA`) or set `byte_order=\"ABCD\"\ndata_type=\"UINT32\"` and use the resulting value(s) in an online converter like\n[this][online-converter]. This especially makes sense if you don't want to mess\nwith the device, deal with 64-bit values and/or don't know the `data_type` of\nyour register (e.g. fix-point floating values vs. IEEE floating point).\n\nIf your data still looks corrupted, please post your configuration, error\nmessage and/or the output of `byte_order=\"ABCD\" data_type=\"UINT32\"` to one of\nthe telegraf support channels (forum, slack or as an issue).  If nothing helps,\nplease post your configuration, error message and/or the output of\n`byte_order=\"ABCD\" data_type=\"UINT32\"` to one of the telegraf support channels\n(forum, slack or as an issue).\n\n[online-converter]: https://www.scadacore.com/tools/programming-calculators/online-hex-converter/\n\n### Workarounds\n\nSome Modbus devices need special read characteristics when reading data and will\nfail otherwise. For example, some serial devices need a pause between register\nread requests. Others might only support a limited number of simultaneously\nconnected devices, like serial devices or some ModbusTCP devices. In case you\nneed to access those devices in parallel you might want to disconnect\nimmediately after the plugin finishes reading.\n\nTo enable this plugin to also handle those \"special\" devices, there is the\n`workarounds` configuration option. In case your documentation states certain\nread requirements or you get read timeouts or other read errors, you might want\nto try one or more workaround options.  If you find that other/more workarounds\nare required for your device, please let us know.\n\nIn case your device needs a workaround that is not yet implemented, please open\nan issue or submit a pull-request.\n\n## Metrics\n\nThe plugin reads the configured registers and constructs metrics based on the\nspecified configuration. There is no predefined metric format.\n\n## Example Output\n\n```text\nmodbus,name=device,slave_id=1,type=holding_register energy=3254.5,power=23.5,frequency=49,97 1701777274026591864\n```\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration.go",
    "content": "package modbus\n\nimport \"fmt\"\n\nconst (\n\tmaxQuantityDiscreteInput    = uint16(2000)\n\tmaxQuantityCoils            = uint16(2000)\n\tmaxQuantityInputRegisters   = uint16(125)\n\tmaxQuantityHoldingRegisters = uint16(125)\n)\n\ntype configuration interface {\n\tcheck() error\n\tprocess() (map[byte]requestSet, error)\n\tsampleConfigPart() string\n}\n\nfunc removeDuplicates(elements []uint16) []uint16 {\n\tencountered := make(map[uint16]bool, len(elements))\n\tresult := make([]uint16, 0, len(elements))\n\n\tfor _, addr := range elements {\n\t\tif !encountered[addr] {\n\t\t\tencountered[addr] = true\n\t\t\tresult = append(result, addr)\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc normalizeInputDatatype(dataType string) (string, error) {\n\tswitch dataType {\n\tcase \"BIT\", \"INT8L\", \"INT8H\", \"UINT8L\", \"UINT8H\",\n\t\t\"INT16\", \"UINT16\", \"INT32\", \"UINT32\", \"INT64\", \"UINT64\",\n\t\t\"FLOAT16\", \"FLOAT32\", \"FLOAT64\", \"STRING\":\n\t\treturn dataType, nil\n\t}\n\treturn \"unknown\", fmt.Errorf(\"unknown input type %q\", dataType)\n}\n\nfunc normalizeOutputDatatype(dataType string) (string, error) {\n\tswitch dataType {\n\tcase \"\", \"native\":\n\t\treturn \"native\", nil\n\tcase \"INT64\", \"UINT64\", \"FLOAT64\", \"STRING\":\n\t\treturn dataType, nil\n\t}\n\treturn \"unknown\", fmt.Errorf(\"unknown output type %q\", dataType)\n}\n\nfunc normalizeByteOrder(byteOrder string) (string, error) {\n\tswitch byteOrder {\n\tcase \"ABCD\", \"MSW-BE\", \"MSW\": // Big endian (Motorola)\n\t\treturn \"ABCD\", nil\n\tcase \"BADC\", \"MSW-LE\": // Big endian with bytes swapped\n\t\treturn \"BADC\", nil\n\tcase \"CDAB\", \"LSW-BE\": // Little endian with bytes swapped\n\t\treturn \"CDAB\", nil\n\tcase \"DCBA\", \"LSW-LE\", \"LSW\": // Little endian (Intel)\n\t\treturn \"DCBA\", nil\n\t}\n\treturn \"unknown\", fmt.Errorf(\"unknown byte-order %q\", byteOrder)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_metric.go",
    "content": "package modbus\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/maphash\"\n\t\"math\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n//go:embed sample_metric.conf\nvar sampleConfigPartPerMetric string\n\ntype metricFieldDefinition struct {\n\tRegisterType string  `toml:\"register\"`\n\tAddress      uint16  `toml:\"address\"`\n\tLength       uint16  `toml:\"length\"`\n\tName         string  `toml:\"name\"`\n\tInputType    string  `toml:\"type\"`\n\tScale        float64 `toml:\"scale\"`\n\tOutputType   string  `toml:\"output\"`\n\tBit          uint8   `toml:\"bit\"`\n}\n\ntype metricDefinition struct {\n\tSlaveID     byte                    `toml:\"slave_id\"`\n\tByteOrder   string                  `toml:\"byte_order\"`\n\tMeasurement string                  `toml:\"measurement\"`\n\tFields      []metricFieldDefinition `toml:\"fields\"`\n\tTags        map[string]string       `toml:\"tags\"`\n}\n\ntype configurationPerMetric struct {\n\tOptimization      string             `toml:\"optimization\"`\n\tMaxExtraRegisters uint16             `toml:\"optimization_max_register_fill\"`\n\tMetrics           []metricDefinition `toml:\"metric\"`\n\n\tworkarounds         workarounds\n\texcludeRegisterType bool\n\tlogger              telegraf.Logger\n}\n\nfunc (*configurationPerMetric) sampleConfigPart() string {\n\treturn sampleConfigPartPerMetric\n}\n\nfunc (c *configurationPerMetric) check() error {\n\tswitch c.workarounds.StringRegisterLocation {\n\tcase \"\", \"both\", \"lower\", \"upper\":\n\t\t// Do nothing as those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'string_register_location' %q\", c.workarounds.StringRegisterLocation)\n\t}\n\n\tseed := maphash.MakeSeed()\n\tseenFields := make(map[uint64]bool)\n\n\t// Check optimization algorithm\n\tswitch c.Optimization {\n\tcase \"\", \"none\":\n\t\tc.Optimization = \"none\"\n\tcase \"max_insert\":\n\t\tif c.MaxExtraRegisters == 0 {\n\t\t\tc.MaxExtraRegisters = 50\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown optimization %q\", c.Optimization)\n\t}\n\n\tfor defidx, def := range c.Metrics {\n\t\t// Check byte order of the data\n\t\tswitch def.ByteOrder {\n\t\tcase \"\":\n\t\t\tdef.ByteOrder = \"ABCD\"\n\t\tcase \"ABCD\", \"DCBA\", \"BADC\", \"CDAB\", \"MSW-BE\", \"MSW-LE\", \"LSW-LE\", \"LSW-BE\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown byte-order %q\", def.ByteOrder)\n\t\t}\n\n\t\t// Set the default for measurement if required\n\t\tif def.Measurement == \"\" {\n\t\t\tdef.Measurement = \"modbus\"\n\t\t}\n\n\t\t// Reject any configuration without fields as it\n\t\t// makes no sense to not define anything but a request.\n\t\tif len(def.Fields) == 0 {\n\t\t\treturn errors.New(\"found request section without fields\")\n\t\t}\n\n\t\t// Check the fields\n\t\tfor fidx, f := range def.Fields {\n\t\t\t// Name is mandatory\n\t\t\tif f.Name == \"\" {\n\t\t\t\treturn fmt.Errorf(\"empty field name in request for slave %d\", def.SlaveID)\n\t\t\t}\n\n\t\t\t// Check register type\n\t\t\tswitch f.RegisterType {\n\t\t\tcase \"\":\n\t\t\t\tf.RegisterType = \"holding\"\n\t\t\tcase \"coil\", \"discrete\", \"holding\", \"input\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown register-type %q for field %q\", f.RegisterType, f.Name)\n\t\t\t}\n\n\t\t\t// Check the input and output type for all fields as we later need\n\t\t\t// it to determine the number of registers to query.\n\t\t\tswitch f.RegisterType {\n\t\t\tcase \"holding\", \"input\":\n\t\t\t\t// Check the input type\n\t\t\t\tswitch f.InputType {\n\t\t\t\tcase \"\":\n\t\t\t\tcase \"INT8L\", \"INT8H\", \"INT16\", \"INT32\", \"INT64\",\n\t\t\t\t\t\"UINT8L\", \"UINT8H\", \"UINT16\", \"UINT32\", \"UINT64\",\n\t\t\t\t\t\"FLOAT16\", \"FLOAT32\", \"FLOAT64\":\n\t\t\t\t\tif f.Length != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"length option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Bit != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"bit option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType == \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"cannot output field %q as string\", f.Name)\n\t\t\t\t\t}\n\t\t\t\tcase \"STRING\":\n\t\t\t\t\tif f.Length < 1 {\n\t\t\t\t\t\treturn fmt.Errorf(\"missing length for string field %q\", f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Bit != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"bit option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Scale != 0.0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"scale option cannot be used for string field %q\", f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType != \"\" && f.OutputType != \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid output type %q for string field %q\", f.OutputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\tcase \"BIT\":\n\t\t\t\t\tif f.Length != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"length option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType == \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"cannot output field %q as string\", f.Name)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown register data-type %q for field %q\", f.InputType, f.Name)\n\t\t\t\t}\n\n\t\t\t\t// Check output type\n\t\t\t\tswitch f.OutputType {\n\t\t\t\tcase \"\", \"INT64\", \"UINT64\", \"FLOAT64\", \"STRING\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown output data-type %q for field %q\", f.OutputType, f.Name)\n\t\t\t\t}\n\t\t\tcase \"coil\", \"discrete\":\n\t\t\t\t// Bit register types can only be UINT64 or BOOL\n\t\t\t\tswitch f.OutputType {\n\t\t\t\tcase \"\", \"UINT16\", \"BOOL\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown output data-type %q for field %q\", f.OutputType, f.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdef.Fields[fidx] = f\n\n\t\t\t// Check for duplicate field definitions\n\t\t\tid := c.fieldID(seed, def, f)\n\t\t\tif seenFields[id] {\n\t\t\t\treturn fmt.Errorf(\"field %q duplicated in measurement %q (slave %d)\", f.Name, def.Measurement, def.SlaveID)\n\t\t\t}\n\t\t\tseenFields[id] = true\n\t\t}\n\t\tc.Metrics[defidx] = def\n\t}\n\n\treturn nil\n}\n\nfunc (c *configurationPerMetric) process() (map[byte]requestSet, error) {\n\tcollection := make(map[byte]map[string][]field)\n\n\t// Collect the requested registers across metrics and transform them into\n\t// requests. This will produce one request per slave and register-type\n\tfor _, def := range c.Metrics {\n\t\t// Make sure we have a set to work with\n\t\tset, found := collection[def.SlaveID]\n\t\tif !found {\n\t\t\tset = make(map[string][]field)\n\t\t}\n\n\t\tfor _, fdef := range def.Fields {\n\t\t\t// Construct the field from the field definition\n\t\t\tf, err := c.newField(fdef, def)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"initializing field %q of measurement %q failed: %w\", fdef.Name, def.Measurement, err)\n\t\t\t}\n\n\t\t\t// Attach the field to the correct set\n\t\t\tset[fdef.RegisterType] = append(set[fdef.RegisterType], f)\n\t\t}\n\t\tcollection[def.SlaveID] = set\n\t}\n\n\tresult := make(map[byte]requestSet)\n\n\tparams := groupingParams{\n\t\toptimization:      c.Optimization,\n\t\tmaxExtraRegisters: c.MaxExtraRegisters,\n\t\tlog:               c.logger,\n\t}\n\tfor sid, scollection := range collection {\n\t\tvar set requestSet\n\t\tfor registerType, fields := range scollection {\n\t\t\tswitch registerType {\n\t\t\tcase \"coil\":\n\t\t\t\tparams.maxBatchSize = maxQuantityCoils\n\t\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\t\tparams.maxBatchSize = 1\n\t\t\t\t}\n\t\t\t\tparams.enforceFromZero = c.workarounds.ReadCoilsStartingAtZero\n\t\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\t\tset.coil = append(set.coil, requests...)\n\t\t\tcase \"discrete\":\n\t\t\t\tparams.maxBatchSize = maxQuantityDiscreteInput\n\t\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\t\tparams.maxBatchSize = 1\n\t\t\t\t}\n\t\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\t\tset.discrete = append(set.discrete, requests...)\n\t\t\tcase \"holding\":\n\t\t\t\tparams.maxBatchSize = maxQuantityHoldingRegisters\n\t\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\t\tparams.maxBatchSize = 1\n\t\t\t\t}\n\t\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\t\tset.holding = append(set.holding, requests...)\n\t\t\tcase \"input\":\n\t\t\t\tparams.maxBatchSize = maxQuantityInputRegisters\n\t\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\t\tparams.maxBatchSize = 1\n\t\t\t\t}\n\t\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\t\tset.input = append(set.input, requests...)\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unknown register type %q\", registerType)\n\t\t\t}\n\t\t}\n\t\tif !set.empty() {\n\t\t\tresult[sid] = set\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc (c *configurationPerMetric) newField(def metricFieldDefinition, mdef metricDefinition) (field, error) {\n\ttyped := def.RegisterType == \"holding\" || def.RegisterType == \"input\"\n\n\tfieldLength := uint16(1)\n\tif typed {\n\t\tvar err error\n\t\tif fieldLength, err = c.determineFieldLength(def.InputType, def.Length); err != nil {\n\t\t\treturn field{}, err\n\t\t}\n\t}\n\n\t// Check for address overflow\n\tif def.Address > math.MaxUint16-fieldLength {\n\t\treturn field{}, fmt.Errorf(\"%w for field %q\", errAddressOverflow, def.Name)\n\t}\n\n\t// Initialize the field\n\tf := field{\n\t\tmeasurement: mdef.Measurement,\n\t\tname:        def.Name,\n\t\taddress:     def.Address,\n\t\tlength:      fieldLength,\n\t\ttags:        mdef.Tags,\n\t}\n\n\t// Handle type conversions for coil and discrete registers\n\tif !typed {\n\t\tvar err error\n\t\tf.converter, err = determineUntypedConverter(def.OutputType)\n\t\tif err != nil {\n\t\t\treturn field{}, err\n\t\t}\n\t\t// No more processing for un-typed (coil and discrete registers) fields\n\t\treturn f, nil\n\t}\n\n\t// Automagically determine the output type...\n\tif def.OutputType == \"\" {\n\t\tif def.Scale == 0.0 {\n\t\t\t// For non-scaling cases we should choose the output corresponding to the input class\n\t\t\t// i.e. INT64 for INT*, UINT64 for UINT* etc.\n\t\t\tvar err error\n\t\t\tif def.OutputType, err = c.determineOutputDatatype(def.InputType); err != nil {\n\t\t\t\treturn field{}, err\n\t\t\t}\n\t\t} else {\n\t\t\t// For scaling cases we always want FLOAT64 by default except for\n\t\t\t// string fields\n\t\t\tif def.InputType != \"STRING\" {\n\t\t\t\tdef.OutputType = \"FLOAT64\"\n\t\t\t} else {\n\t\t\t\tdef.OutputType = \"STRING\"\n\t\t\t}\n\t\t}\n\t}\n\n\t// Setting default byte-order\n\tbyteOrder := mdef.ByteOrder\n\tif byteOrder == \"\" {\n\t\tbyteOrder = \"ABCD\"\n\t}\n\n\t// Normalize the data relevant for determining the converter\n\tinType, err := normalizeInputDatatype(def.InputType)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\toutType, err := normalizeOutputDatatype(def.OutputType)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\torder, err := normalizeByteOrder(byteOrder)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\n\tf.converter, err = determineConverter(inType, order, outType, def.Scale, def.Bit, c.workarounds.StringRegisterLocation)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\n\treturn f, nil\n}\n\nfunc (c *configurationPerMetric) fieldID(seed maphash.Seed, def metricDefinition, field metricFieldDefinition) uint64 {\n\tvar mh maphash.Hash\n\tmh.SetSeed(seed)\n\n\tmh.WriteByte(def.SlaveID)\n\tmh.WriteByte(0)\n\tif !c.excludeRegisterType {\n\t\tmh.WriteString(field.RegisterType)\n\t\tmh.WriteByte(0)\n\t}\n\tmh.WriteString(def.Measurement)\n\tmh.WriteByte(0)\n\tmh.WriteString(field.Name)\n\tmh.WriteByte(0)\n\n\t// tags\n\tfor k, v := range def.Tags {\n\t\tmh.WriteString(k)\n\t\tmh.WriteByte('=')\n\t\tmh.WriteString(v)\n\t\tmh.WriteByte(':')\n\t}\n\tmh.WriteByte(0)\n\n\treturn mh.Sum64()\n}\n\nfunc (*configurationPerMetric) determineOutputDatatype(input string) (string, error) {\n\t// Handle our special types\n\tswitch input {\n\tcase \"INT8L\", \"INT8H\", \"INT16\", \"INT32\", \"INT64\":\n\t\treturn \"INT64\", nil\n\tcase \"BIT\", \"UINT8L\", \"UINT8H\", \"UINT16\", \"UINT32\", \"UINT64\":\n\t\treturn \"UINT64\", nil\n\tcase \"FLOAT16\", \"FLOAT32\", \"FLOAT64\":\n\t\treturn \"FLOAT64\", nil\n\tcase \"STRING\":\n\t\treturn \"STRING\", nil\n\t}\n\treturn \"unknown\", fmt.Errorf(\"invalid input datatype %q for determining output\", input)\n}\n\nfunc (*configurationPerMetric) determineFieldLength(input string, length uint16) (uint16, error) {\n\t// Handle our special types\n\tswitch input {\n\tcase \"BIT\", \"INT8L\", \"INT8H\", \"UINT8L\", \"UINT8H\":\n\t\treturn 1, nil\n\tcase \"INT16\", \"UINT16\", \"FLOAT16\":\n\t\treturn 1, nil\n\tcase \"INT32\", \"UINT32\", \"FLOAT32\":\n\t\treturn 2, nil\n\tcase \"INT64\", \"UINT64\", \"FLOAT64\":\n\t\treturn 4, nil\n\tcase \"STRING\":\n\t\treturn length, nil\n\t}\n\treturn 0, fmt.Errorf(\"invalid input datatype %q for determining field length\", input)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_metric_test.go",
    "content": "package modbus\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\tmb \"github.com/grid-x/modbus\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tbrandon/mbserver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMetric(t *testing.T) {\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"metric\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tplugin.Metrics = []metricDefinition{\n\t\t{\n\t\t\tSlaveID:     1,\n\t\t\tByteOrder:   \"ABCD\",\n\t\t\tMeasurement: \"test\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-0\",\n\t\t\t\t\tAddress:      uint16(0),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-1\",\n\t\t\t\t\tAddress:      uint16(1),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"holding-1\",\n\t\t\t\t\tAddress:      uint16(1),\n\t\t\t\t\tInputType:    \"UINT16\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:   1,\n\t\t\tByteOrder: \"ABCD\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-0\",\n\t\t\t\t\tAddress:      uint16(2),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-1\",\n\t\t\t\t\tAddress:      uint16(3),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:       \"holding-0\",\n\t\t\t\t\tAddress:    uint16(2),\n\t\t\t\t\tInputType:  \"INT64\",\n\t\t\t\t\tScale:      1.2,\n\t\t\t\t\tOutputType: \"FLOAT64\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"mydevice\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID: 2,\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-6\",\n\t\t\t\t\tAddress:      uint16(6),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-7\",\n\t\t\t\t\tAddress:      uint16(7),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"discrete-0\",\n\t\t\t\t\tAddress:      uint16(0),\n\t\t\t\t\tRegisterType: \"discrete\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-99\",\n\t\t\t\t\tAddress:   uint16(99),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID: 2,\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-4\",\n\t\t\t\t\tAddress:      uint16(4),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"coil-5\",\n\t\t\t\t\tAddress:      uint16(5),\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"input-0\",\n\t\t\t\t\tAddress:      uint16(0),\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tInputType:    \"UINT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"input-1\",\n\t\t\t\t\tAddress:      uint16(2),\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tInputType:    \"UINT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-9\",\n\t\t\t\t\tAddress:   uint16(9),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"mydevice\",\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\trequire.NotEmpty(t, plugin.requests)\n\n\trequire.NotNil(t, plugin.requests[1])\n\trequire.Len(t, plugin.requests[1].coil, 1, \"coil 1\")\n\trequire.Len(t, plugin.requests[1].holding, 1, \"holding 1\")\n\trequire.Empty(t, plugin.requests[1].discrete)\n\trequire.Empty(t, plugin.requests[1].input)\n\n\trequire.NotNil(t, plugin.requests[2])\n\trequire.Len(t, plugin.requests[2].coil, 1, \"coil 2\")\n\trequire.Len(t, plugin.requests[2].holding, 2, \"holding 2\")\n\trequire.Len(t, plugin.requests[2].discrete, 1, \"discrete 2\")\n\trequire.Len(t, plugin.requests[2].input, 2, \"input 2\")\n}\n\nfunc TestMetricResult(t *testing.T) {\n\tdata := []byte{\n\t\t0x00, 0x0A, // 10\n\t\t0x00, 0x2A, // 42\n\t\t0x00, 0x00, 0x08, 0x98, // 2200\n\t\t0x00, 0x00, 0x08, 0x99, // 2201\n\t\t0x00, 0x00, 0x08, 0x9A, // 2202\n\t\t0x40, 0x49, 0x0f, 0xdb, // float32 of 3.1415927410125732421875\n\t\t0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, // String \"Modbus String\"\n\t}\n\n\t// Write the data to a fake server\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tquantity := uint16(len(data) / 2)\n\t_, err := client.WriteMultipleRegisters(1, quantity, data)\n\trequire.NoError(t, err)\n\n\t// Setup the plugin\n\tplugin := Modbus{\n\t\tName:              \"FAKEMETER\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"metric\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tplugin.Metrics = []metricDefinition{\n\t\t{\n\t\t\tSlaveID:     1,\n\t\t\tByteOrder:   \"ABCD\",\n\t\t\tMeasurement: \"machine\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"hours\",\n\t\t\t\t\tAddress:      uint16(1),\n\t\t\t\t\tInputType:    \"UINT16\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"temperature\",\n\t\t\t\t\tAddress:      uint16(2),\n\t\t\t\t\tInputType:    \"INT16\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:         \"comment\",\n\t\t\t\t\tAddress:      uint16(11),\n\t\t\t\t\tLength:       7,\n\t\t\t\t\tInputType:    \"STRING\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"machine A\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:     1,\n\t\t\tByteOrder:   \"ABCD\",\n\t\t\tMeasurement: \"machine\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"hours\",\n\t\t\t\t\tAddress:   uint16(3),\n\t\t\t\t\tInputType: \"UINT32\",\n\t\t\t\t\tScale:     0.01,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"temperature\",\n\t\t\t\t\tAddress:   uint16(5),\n\t\t\t\t\tInputType: \"INT32\",\n\t\t\t\t\tScale:     0.02,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"output\",\n\t\t\t\t\tAddress:   uint16(7),\n\t\t\t\t\tInputType: \"UINT32\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"machine B\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID: 1,\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"pi\",\n\t\t\t\t\tAddress:   uint16(9),\n\t\t\t\t\tInputType: \"FLOAT32\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:     1,\n\t\t\tMeasurement: \"bitvalues\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"bit 0\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"BIT\",\n\t\t\t\t\tBit:       0,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"bit 1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"BIT\",\n\t\t\t\t\tBit:       1,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"bit 2\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"BIT\",\n\t\t\t\t\tBit:       2,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"bit 3\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"BIT\",\n\t\t\t\t\tBit:       3,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Check the generated requests\n\trequire.Len(t, plugin.requests, 1)\n\trequire.NotNil(t, plugin.requests[1])\n\trequire.Len(t, plugin.requests[1].holding, 5)\n\trequire.Empty(t, plugin.requests[1].coil)\n\trequire.Empty(t, plugin.requests[1].discrete)\n\trequire.Empty(t, plugin.requests[1].input)\n\n\t// Gather the data and verify the resulting metrics\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":     \"FAKEMETER\",\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"machine A\",\n\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\"type\":     \"holding_register\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"hours\":       uint64(10),\n\t\t\t\t\"temperature\": int64(42),\n\t\t\t\t\"comment\":     \"Modbus String\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"machine\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":     \"FAKEMETER\",\n\t\t\t\t\"location\": \"main building\",\n\t\t\t\t\"device\":   \"machine B\",\n\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\"type\":     \"holding_register\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"hours\":       float64(22.0),\n\t\t\t\t\"temperature\": float64(44.02),\n\t\t\t\t\"output\":      uint64(2202),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":     \"FAKEMETER\",\n\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\"type\":     \"holding_register\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\"pi\": float64(3.1415927410125732421875)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"bitvalues\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":     \"FAKEMETER\",\n\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\"type\":     \"holding_register\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bit 0\": uint64(0),\n\t\t\t\t\"bit 1\": uint64(1),\n\t\t\t\t\"bit 2\": uint64(0),\n\t\t\t\t\"bit 3\": uint64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestMetricAddressOverflow(t *testing.T) {\n\tlogger := &testutil.CaptureLogger{}\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"metric\",\n\t\tLog:               logger,\n\t\tWorkarounds:       workarounds{ReadCoilsStartingAtZero: true},\n\t}\n\tplugin.Metrics = []metricDefinition{\n\t\t{\n\t\t\tSlaveID:     1,\n\t\t\tByteOrder:   \"ABCD\",\n\t\t\tMeasurement: \"test\",\n\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:         \"field\",\n\t\t\t\t\tAddress:      uint16(65534),\n\t\t\t\t\tInputType:    \"UINT64\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.ErrorIs(t, plugin.Init(), errAddressOverflow)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_register.go",
    "content": "package modbus\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n//go:embed sample_register.conf\nvar sampleConfigPartPerRegister string\n\ntype fieldDefinition struct {\n\tMeasurement string   `toml:\"measurement\"`\n\tName        string   `toml:\"name\"`\n\tByteOrder   string   `toml:\"byte_order\"`\n\tDataType    string   `toml:\"data_type\"`\n\tScale       float64  `toml:\"scale\"`\n\tAddress     []uint16 `toml:\"address\"`\n\tBit         uint8    `toml:\"bit\"`\n}\n\ntype configurationOriginal struct {\n\tSlaveID          byte              `toml:\"slave_id\"`\n\tDiscreteInputs   []fieldDefinition `toml:\"discrete_inputs\"`\n\tCoils            []fieldDefinition `toml:\"coils\"`\n\tHoldingRegisters []fieldDefinition `toml:\"holding_registers\"`\n\tInputRegisters   []fieldDefinition `toml:\"input_registers\"`\n\tworkarounds      workarounds\n\tlogger           telegraf.Logger\n}\n\nfunc (*configurationOriginal) sampleConfigPart() string {\n\treturn sampleConfigPartPerRegister\n}\n\nfunc (c *configurationOriginal) check() error {\n\tswitch c.workarounds.StringRegisterLocation {\n\tcase \"\", \"both\", \"lower\", \"upper\":\n\t\t// Do nothing as those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'string_register_location' %q\", c.workarounds.StringRegisterLocation)\n\t}\n\n\tif err := validateFieldDefinitions(c.DiscreteInputs, cDiscreteInputs); err != nil {\n\t\treturn err\n\t}\n\n\tif err := validateFieldDefinitions(c.Coils, cCoils); err != nil {\n\t\treturn err\n\t}\n\n\tif err := validateFieldDefinitions(c.HoldingRegisters, cHoldingRegisters); err != nil {\n\t\treturn err\n\t}\n\n\treturn validateFieldDefinitions(c.InputRegisters, cInputRegisters)\n}\n\nfunc (c *configurationOriginal) process() (map[byte]requestSet, error) {\n\tmaxQuantity := uint16(1)\n\tif !c.workarounds.OnRequestPerField {\n\t\tmaxQuantity = maxQuantityCoils\n\t}\n\tcoil, err := c.initRequests(c.Coils, maxQuantity, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !c.workarounds.OnRequestPerField {\n\t\tmaxQuantity = maxQuantityDiscreteInput\n\t}\n\tdiscrete, err := c.initRequests(c.DiscreteInputs, maxQuantity, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !c.workarounds.OnRequestPerField {\n\t\tmaxQuantity = maxQuantityHoldingRegisters\n\t}\n\tholding, err := c.initRequests(c.HoldingRegisters, maxQuantity, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !c.workarounds.OnRequestPerField {\n\t\tmaxQuantity = maxQuantityInputRegisters\n\t}\n\tinput, err := c.initRequests(c.InputRegisters, maxQuantity, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn map[byte]requestSet{\n\t\tc.SlaveID: {\n\t\t\tcoil:     coil,\n\t\t\tdiscrete: discrete,\n\t\t\tholding:  holding,\n\t\t\tinput:    input,\n\t\t},\n\t}, nil\n}\n\nfunc (c *configurationOriginal) initRequests(fieldDefs []fieldDefinition, maxQuantity uint16, typed bool) ([]request, error) {\n\tfields, err := c.initFields(fieldDefs, typed)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tparams := groupingParams{\n\t\tmaxBatchSize:    maxQuantity,\n\t\toptimization:    \"none\",\n\t\tenforceFromZero: c.workarounds.ReadCoilsStartingAtZero,\n\t\tlog:             c.logger,\n\t}\n\n\treturn groupFieldsToRequests(fields, params), nil\n}\n\nfunc (c *configurationOriginal) initFields(fieldDefs []fieldDefinition, typed bool) ([]field, error) {\n\t// Construct the fields from the field definitions\n\tfields := make([]field, 0, len(fieldDefs))\n\tfor _, def := range fieldDefs {\n\t\tf, err := c.newFieldFromDefinition(def, typed)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"initializing field %q failed: %w\", def.Name, err)\n\t\t}\n\t\tfields = append(fields, f)\n\t}\n\n\treturn fields, nil\n}\n\nfunc (c *configurationOriginal) newFieldFromDefinition(def fieldDefinition, typed bool) (field, error) {\n\t// Check if the addresses are consecutive\n\texpected := def.Address[0]\n\tfor _, current := range def.Address[1:] {\n\t\texpected++\n\t\tif current != expected {\n\t\t\treturn field{}, fmt.Errorf(\"addresses of field %q are not consecutive\", def.Name)\n\t\t}\n\t}\n\n\t// Initialize the field\n\tf := field{\n\t\tmeasurement: def.Measurement,\n\t\tname:        def.Name,\n\t\taddress:     def.Address[0],\n\t\tlength:      uint16(len(def.Address)),\n\t}\n\n\t// Handle coil and discrete registers which do have a limited datatype set\n\tif !typed {\n\t\tvar err error\n\t\tf.converter, err = determineUntypedConverter(def.DataType)\n\t\tif err != nil {\n\t\t\treturn field{}, err\n\t\t}\n\t\treturn f, nil\n\t}\n\n\tif def.DataType != \"\" {\n\t\tinType, err := c.normalizeInputDatatype(def.DataType, len(def.Address))\n\t\tif err != nil {\n\t\t\treturn f, err\n\t\t}\n\t\toutType, err := c.normalizeOutputDatatype(def.DataType)\n\t\tif err != nil {\n\t\t\treturn f, err\n\t\t}\n\t\tbyteOrder, err := c.normalizeByteOrder(def.ByteOrder)\n\t\tif err != nil {\n\t\t\treturn f, err\n\t\t}\n\n\t\tf.converter, err = determineConverter(inType, byteOrder, outType, def.Scale, def.Bit, c.workarounds.StringRegisterLocation)\n\t\tif err != nil {\n\t\t\treturn f, err\n\t\t}\n\t}\n\n\treturn f, nil\n}\n\nfunc validateFieldDefinitions(fieldDefs []fieldDefinition, registerType string) error {\n\tnameEncountered := make(map[string]bool, len(fieldDefs))\n\tfor _, item := range fieldDefs {\n\t\t// check empty name\n\t\tif item.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"empty name in %q\", registerType)\n\t\t}\n\n\t\t// search name duplicate\n\t\tcanonicalName := item.Measurement + \".\" + item.Name\n\t\tif nameEncountered[canonicalName] {\n\t\t\treturn fmt.Errorf(\"name %q is duplicated in measurement %q %q - %q\", item.Name, item.Measurement, registerType, item.Name)\n\t\t}\n\t\tnameEncountered[canonicalName] = true\n\n\t\tif registerType == cInputRegisters || registerType == cHoldingRegisters {\n\t\t\t// search byte order\n\t\t\tswitch item.ByteOrder {\n\t\t\tcase \"AB\", \"BA\", \"ABCD\", \"CDAB\", \"BADC\", \"DCBA\", \"ABCDEFGH\", \"HGFEDCBA\", \"BADCFEHG\", \"GHEFCDAB\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"invalid byte order %q in %q - %q\", item.ByteOrder, registerType, item.Name)\n\t\t\t}\n\n\t\t\t// search data type\n\t\t\tswitch item.DataType {\n\t\t\tcase \"INT8L\", \"INT8H\", \"UINT8L\", \"UINT8H\",\n\t\t\t\t\"UINT16\", \"INT16\", \"UINT32\", \"INT32\", \"UINT64\", \"INT64\",\n\t\t\t\t\"FLOAT16-IEEE\", \"FLOAT32-IEEE\", \"FLOAT64-IEEE\", \"FLOAT32\", \"FIXED\", \"UFIXED\":\n\t\t\t\t// Check scale\n\t\t\t\tif item.Scale == 0.0 {\n\t\t\t\t\treturn fmt.Errorf(\"invalid scale '%f' in %q - %q\", item.Scale, registerType, item.Name)\n\t\t\t\t}\n\t\t\tcase \"BIT\", \"STRING\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"invalid data type %q in %q - %q\", item.DataType, registerType, item.Name)\n\t\t\t}\n\t\t} else {\n\t\t\t// Bit-registers do have less data types\n\t\t\tswitch item.DataType {\n\t\t\tcase \"\", \"UINT16\", \"BOOL\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"invalid data type %q in %q - %q\", item.DataType, registerType, item.Name)\n\t\t\t}\n\t\t}\n\n\t\t// Special address checking for special types\n\t\tswitch item.DataType {\n\t\tcase \"STRING\":\n\t\t\tcontinue\n\t\tcase \"BIT\":\n\t\t\tif len(item.Address) != 1 {\n\t\t\t\treturn fmt.Errorf(\"address '%v' has length '%v' bit should be one in %q - %q\", item.Address, len(item.Address), registerType, item.Name)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check address\n\t\tif len(item.Address) != 1 && len(item.Address) != 2 && len(item.Address) != 4 {\n\t\t\treturn fmt.Errorf(\"invalid address '%v' length '%v' in %q - %q\", item.Address, len(item.Address), registerType, item.Name)\n\t\t}\n\n\t\tif registerType == cInputRegisters || registerType == cHoldingRegisters {\n\t\t\tif 2*len(item.Address) != len(item.ByteOrder) {\n\t\t\t\treturn fmt.Errorf(\"invalid byte order %q and address '%v'  in %q - %q\", item.ByteOrder, item.Address, registerType, item.Name)\n\t\t\t}\n\n\t\t\t// Check for the request size corresponding to the data-type\n\t\t\tvar requiredAddresses int\n\t\t\tswitch item.DataType {\n\t\t\tcase \"INT8L\", \"INT8H\", \"UINT8L\", \"UINT8H\", \"UINT16\", \"INT16\", \"FLOAT16-IEEE\":\n\t\t\t\trequiredAddresses = 1\n\t\t\tcase \"UINT32\", \"INT32\", \"FLOAT32-IEEE\":\n\t\t\t\trequiredAddresses = 2\n\t\t\tcase \"UINT64\", \"INT64\", \"FLOAT64-IEEE\":\n\t\t\t\trequiredAddresses = 4\n\t\t\t}\n\t\t\tif requiredAddresses > 0 && len(item.Address) != requiredAddresses {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"invalid address '%v' length '%v'in %q - %q, expecting %d entries for datatype\",\n\t\t\t\t\titem.Address, len(item.Address), registerType, item.Name, requiredAddresses,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// search duplicated\n\t\t\tif len(item.Address) > len(removeDuplicates(item.Address)) {\n\t\t\t\treturn fmt.Errorf(\"duplicate address '%v'  in %q - %q\", item.Address, registerType, item.Name)\n\t\t\t}\n\t\t} else if len(item.Address) != 1 {\n\t\t\treturn fmt.Errorf(\"invalid address '%v' length '%v'in %q - %q\", item.Address, len(item.Address), registerType, item.Name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (*configurationOriginal) normalizeInputDatatype(dataType string, words int) (string, error) {\n\t// Handle our special types\n\tswitch dataType {\n\tcase \"FIXED\":\n\t\tswitch words {\n\t\tcase 1:\n\t\t\treturn \"INT16\", nil\n\t\tcase 2:\n\t\t\treturn \"INT32\", nil\n\t\tcase 4:\n\t\t\treturn \"INT64\", nil\n\t\tdefault:\n\t\t\treturn \"unknown\", fmt.Errorf(\"invalid length %d for type %q\", words, dataType)\n\t\t}\n\tcase \"UFIXED\":\n\t\tswitch words {\n\t\tcase 1:\n\t\t\treturn \"UINT16\", nil\n\t\tcase 2:\n\t\t\treturn \"UINT32\", nil\n\t\tcase 4:\n\t\t\treturn \"UINT64\", nil\n\t\tdefault:\n\t\t\treturn \"unknown\", fmt.Errorf(\"invalid length %d for type %q\", words, dataType)\n\t\t}\n\tcase \"FLOAT16-IEEE\":\n\t\treturn \"FLOAT16\", nil\n\tcase \"FLOAT32-IEEE\":\n\t\treturn \"FLOAT32\", nil\n\tcase \"FLOAT64-IEEE\":\n\t\treturn \"FLOAT64\", nil\n\tcase \"STRING\":\n\t\treturn \"STRING\", nil\n\tcase \"BIT\":\n\t\treturn \"BIT\", nil\n\t}\n\treturn normalizeInputDatatype(dataType)\n}\n\nfunc (*configurationOriginal) normalizeOutputDatatype(dataType string) (string, error) {\n\t// Handle our special types\n\tswitch dataType {\n\tcase \"FIXED\", \"FLOAT32\", \"UFIXED\":\n\t\treturn \"FLOAT64\", nil\n\t}\n\treturn normalizeOutputDatatype(\"native\")\n}\n\nfunc (*configurationOriginal) normalizeByteOrder(byteOrder string) (string, error) {\n\t// Handle our special types\n\tswitch byteOrder {\n\tcase \"AB\", \"ABCDEFGH\":\n\t\treturn \"ABCD\", nil\n\tcase \"BADCFEHG\":\n\t\treturn \"BADC\", nil\n\tcase \"GHEFCDAB\":\n\t\treturn \"CDAB\", nil\n\tcase \"BA\", \"HGFEDCBA\":\n\t\treturn \"DCBA\", nil\n\t}\n\treturn normalizeByteOrder(byteOrder)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_register_test.go",
    "content": "package modbus\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\tmb \"github.com/grid-x/modbus\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tbrandon/mbserver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRegister(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"TestRetryFailExhausted\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"register\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"coil\",\n\t\t\tAddress: []uint16{0},\n\t\t},\n\t}\n\tmodbus.DiscreteInputs = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"discrete\",\n\t\t\tAddress: []uint16{0},\n\t\t},\n\t}\n\tmodbus.HoldingRegisters = []fieldDefinition{\n\t\t{\n\t\t\tName:      \"holding\",\n\t\t\tAddress:   []uint16{0},\n\t\t\tDataType:  \"INT16\",\n\t\t\tByteOrder: \"AB\",\n\t\t\tScale:     1.0,\n\t\t},\n\t}\n\tmodbus.InputRegisters = []fieldDefinition{\n\t\t{\n\t\t\tName:      \"input\",\n\t\t\tAddress:   []uint16{0},\n\t\t\tDataType:  \"INT16\",\n\t\t\tByteOrder: \"AB\",\n\t\t\tScale:     1.0,\n\t\t},\n\t}\n\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NotNil(t, modbus.requests[1])\n\trequire.Len(t, modbus.requests[1].coil, len(modbus.Coils))\n\trequire.Len(t, modbus.requests[1].discrete, len(modbus.DiscreteInputs))\n\trequire.Len(t, modbus.requests[1].holding, len(modbus.HoldingRegisters))\n\trequire.Len(t, modbus.requests[1].input, len(modbus.InputRegisters))\n}\n\nfunc TestRegisterCoils(t *testing.T) {\n\tvar coilTests = []struct {\n\t\tname     string\n\t\taddress  uint16\n\t\tdtype    string\n\t\tquantity uint16\n\t\twrite    []byte\n\t\tread     interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"coil0_turn_off\",\n\t\t\taddress:  0,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil0_turn_on\",\n\t\t\taddress:  0,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil1_turn_on\",\n\t\t\taddress:  1,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil2_turn_on\",\n\t\t\taddress:  2,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil3_turn_on\",\n\t\t\taddress:  3,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil1_turn_off\",\n\t\t\taddress:  1,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil2_turn_off\",\n\t\t\taddress:  2,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil3_turn_off\",\n\t\t\taddress:  3,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil4_turn_off\",\n\t\t\taddress:  4,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil4_turn_on\",\n\t\t\taddress:  4,\n\t\t\tquantity: 1,\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:     \"coil4_turn_off_bool\",\n\t\t\taddress:  4,\n\t\t\tquantity: 1,\n\t\t\tdtype:    \"BOOL\",\n\t\t\twrite:    []byte{0x00},\n\t\t\tread:     false,\n\t\t},\n\t\t{\n\t\t\tname:     \"coil4_turn_on_bool\",\n\t\t\taddress:  4,\n\t\t\tquantity: 1,\n\t\t\tdtype:    \"BOOL\",\n\t\t\twrite:    []byte{0x01},\n\t\t\tread:     true,\n\t\t},\n\t}\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfor _, ct := range coilTests {\n\t\tt.Run(ct.name, func(t *testing.T) {\n\t\t\t_, err := client.WriteMultipleCoils(ct.address, ct.quantity, ct.write)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodbus := Modbus{\n\t\t\t\tName:       \"TestCoils\",\n\t\t\t\tController: \"tcp://localhost:1502\",\n\t\t\t\tLog:        testutil.Logger{},\n\t\t\t}\n\t\t\tmodbus.SlaveID = 1\n\t\t\tmodbus.Coils = []fieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:     ct.name,\n\t\t\t\t\tAddress:  []uint16{ct.address},\n\t\t\t\t\tDataType: ct.dtype,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"type\":     cCoils,\n\t\t\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\t\t\"name\":     modbus.Name,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ct.name: ct.read},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, modbus.Init())\n\t\t\trequire.NotEmpty(t, modbus.requests)\n\t\t\trequire.NoError(t, modbus.Gather(&acc))\n\t\t\tacc.Wait(len(expected))\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRegisterHoldingRegisters(t *testing.T) {\n\tvar holdingRegisterTests = []struct {\n\t\tname      string\n\t\taddress   []uint16\n\t\tquantity  uint16\n\t\tbit       uint8\n\t\tbyteOrder string\n\t\tdataType  string\n\t\tscale     float64\n\t\twrite     []byte\n\t\tread      interface{}\n\t}{\n\t\t{\n\t\t\tname:      \"register5_bit3\",\n\t\t\taddress:   []uint16{5},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"BIT\",\n\t\t\tbit:       3,\n\t\t\twrite:     []byte{0x18, 0x0d},\n\t\t\tread:      uint8(1),\n\t\t},\n\t\t{\n\t\t\tname:      \"register5_bit14\",\n\t\t\taddress:   []uint16{5},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"BIT\",\n\t\t\tbit:       14,\n\t\t\twrite:     []byte{0x18, 0x0d},\n\t\t\tread:      uint8(0),\n\t\t},\n\t\t{\n\t\t\tname:      \"register0_ab_float\",\n\t\t\taddress:   []uint16{0},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"FIXED\",\n\t\t\tscale:     0.1,\n\t\t\twrite:     []byte{0xFF, 0xD6},\n\t\t\tread:      float64(-4.2),\n\t\t},\n\t\t{\n\t\t\tname:      \"register1_ba_ufloat\",\n\t\t\taddress:   []uint16{1},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"BA\",\n\t\t\tdataType:  \"UFIXED\",\n\t\t\tscale:     0.1,\n\t\t\twrite:     []byte{0xD8, 0xFF},\n\t\t\tread:      float64(6549.6),\n\t\t},\n\t\t{\n\t\t\tname:      \"register4_register5_abcd_float\",\n\t\t\taddress:   []uint16{4, 5},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"FIXED\",\n\t\t\tscale:     0.1,\n\t\t\twrite:     []byte{0xFF, 0xFF, 0xFF, 0xD6},\n\t\t\tread:      float64(-4.2),\n\t\t},\n\t\t{\n\t\t\tname:      \"register5_register6_dcba_ufloat\",\n\t\t\taddress:   []uint16{5, 6},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"DCBA\",\n\t\t\tdataType:  \"UFIXED\",\n\t\t\tscale:     0.001,\n\t\t\twrite:     []byte{0xD8, 0xFF, 0xFF, 0xFF},\n\t\t\tread:      float64(4294967.256),\n\t\t},\n\t\t{\n\t\t\tname:      \"register5_to_register8_abcdefgh_float\",\n\t\t\taddress:   []uint16{5, 6, 7, 8},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"FIXED\",\n\t\t\tscale:     0.000001,\n\t\t\twrite:     []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD6},\n\t\t\tread:      float64(-0.000042),\n\t\t},\n\t\t{\n\t\t\tname:      \"register6_to_register9_hgfedcba_ufloat\",\n\t\t\taddress:   []uint16{6, 7, 8, 9},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"HGFEDCBA\",\n\t\t\tdataType:  \"UFIXED\",\n\t\t\tscale:     0.000000001,\n\t\t\twrite:     []byte{0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},\n\t\t\tread:      float64(18441921395.520346504),\n\t\t},\n\t\t{\n\t\t\tname:      \"register20_uint16\",\n\t\t\taddress:   []uint16{10},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8L\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(13),\n\t\t},\n\t\t{\n\t\t\tname:      \"register20_uint16-scale_.1\",\n\t\t\taddress:   []uint16{10},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8L\",\n\t\t\tscale:     .1,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(1),\n\t\t},\n\t\t{\n\t\t\tname:      \"register20_uint16_scale_10\",\n\t\t\taddress:   []uint16{10},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8L\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(130),\n\t\t},\n\t\t{\n\t\t\tname:      \"register11_uint8H\",\n\t\t\taddress:   []uint16{11},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8H\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(24),\n\t\t},\n\t\t{\n\t\t\tname:      \"register11_uint8L-scale_.1\",\n\t\t\taddress:   []uint16{11},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8H\",\n\t\t\tscale:     .1,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(2),\n\t\t},\n\t\t{\n\t\t\tname:      \"register11_uint8L_scale_10\",\n\t\t\taddress:   []uint16{11},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT8H\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x18, 0x0D},\n\t\t\tread:      uint8(240),\n\t\t},\n\t\t{\n\t\t\tname:      \"register12_int8L\",\n\t\t\taddress:   []uint16{12},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8L\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x98, 0x8D},\n\t\t\tread:      int8(-115),\n\t\t},\n\t\t{\n\t\t\tname:      \"register12_int8L-scale_.1\",\n\t\t\taddress:   []uint16{12},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8L\",\n\t\t\tscale:     .1,\n\t\t\twrite:     []byte{0x98, 0x8D},\n\t\t\tread:      int8(-11),\n\t\t},\n\t\t{\n\t\t\tname:      \"register12_int8L_scale_10\",\n\t\t\taddress:   []uint16{12},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8L\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x98, 0xF8},\n\t\t\tread:      int8(-80),\n\t\t},\n\t\t{\n\t\t\tname:      \"register13_int8H\",\n\t\t\taddress:   []uint16{13},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8H\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x98, 0x8D},\n\t\t\tread:      int8(-104),\n\t\t},\n\t\t{\n\t\t\tname:      \"register13_int8H-scale_.1\",\n\t\t\taddress:   []uint16{13},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8H\",\n\t\t\tscale:     .1,\n\t\t\twrite:     []byte{0x98, 0x8D},\n\t\t\tread:      int8(-10),\n\t\t},\n\t\t{\n\t\t\tname:      \"register13_int8H_scale_10\",\n\t\t\taddress:   []uint16{13},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT8H\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0xFD, 0x8D},\n\t\t\tread:      int8(-30),\n\t\t},\n\t\t{\n\t\t\tname:      \"register15_ab_uint16\",\n\t\t\taddress:   []uint16{15},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT16\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAB, 0xCD},\n\t\t\tread:      uint16(43981),\n\t\t},\n\t\t{\n\t\t\tname:      \"register15_ab_uint16-scale_.1\",\n\t\t\taddress:   []uint16{15},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT16\",\n\t\t\tscale:     .1,\n\t\t\twrite:     []byte{0xAB, 0xCD},\n\t\t\tread:      uint16(4398),\n\t\t},\n\t\t{\n\t\t\tname:      \"register15_ab_uint16_scale_10\",\n\t\t\taddress:   []uint16{15},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"UINT16\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x00, 0x2A},\n\t\t\tread:      uint16(420),\n\t\t},\n\t\t{\n\t\t\tname:      \"register20_ba_uint16\",\n\t\t\taddress:   []uint16{20},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"BA\",\n\t\t\tdataType:  \"UINT16\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAB, 0xCD},\n\t\t\tread:      uint16(52651),\n\t\t},\n\t\t{\n\t\t\tname:      \"register30_ab_int16\",\n\t\t\taddress:   []uint16{20},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"INT16\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAB, 0xCD},\n\t\t\tread:      int16(-21555),\n\t\t},\n\t\t{\n\t\t\tname:      \"register40_ba_int16\",\n\t\t\taddress:   []uint16{40},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"BA\",\n\t\t\tdataType:  \"INT16\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAB, 0xCD},\n\t\t\tread:      int16(-12885),\n\t\t},\n\t\t{\n\t\t\tname:      \"register50_register51_abcd_int32_scaled\",\n\t\t\taddress:   []uint16{50, 51},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"INT32\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x00, 0x00, 0xAB, 0xCD},\n\t\t\tread:      int32(439810),\n\t\t},\n\t\t{\n\t\t\tname:      \"register50_register51_abcd_int32\",\n\t\t\taddress:   []uint16{50, 51},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"INT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      int32(-1430532899),\n\t\t},\n\t\t{\n\t\t\tname:      \"register60_register61_dcba_int32\",\n\t\t\taddress:   []uint16{60, 61},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"DCBA\",\n\t\t\tdataType:  \"INT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      int32(-573785174),\n\t\t},\n\t\t{\n\t\t\tname:      \"register70_register71_badc_int32\",\n\t\t\taddress:   []uint16{70, 71},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"BADC\",\n\t\t\tdataType:  \"INT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      int32(-1146430004),\n\t\t},\n\t\t{\n\t\t\tname:      \"register80_register81_cdab_int32\",\n\t\t\taddress:   []uint16{80, 81},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"CDAB\",\n\t\t\tdataType:  \"INT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      int32(-857888069),\n\t\t},\n\t\t{\n\t\t\tname:      \"register90_register91_abcd_uint32\",\n\t\t\taddress:   []uint16{90, 91},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"UINT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      uint32(2864434397),\n\t\t},\n\t\t{\n\t\t\tname:      \"register100_register101_dcba_uint32\",\n\t\t\taddress:   []uint16{100, 101},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"DCBA\",\n\t\t\tdataType:  \"UINT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      uint32(3721182122),\n\t\t},\n\t\t{\n\t\t\tname:      \"register110_register111_badc_uint32\",\n\t\t\taddress:   []uint16{110, 111},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"BADC\",\n\t\t\tdataType:  \"UINT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      uint32(3148537292),\n\t\t},\n\t\t{\n\t\t\tname:      \"register120_register121_cdab_uint32\",\n\t\t\taddress:   []uint16{120, 121},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"CDAB\",\n\t\t\tdataType:  \"UINT32\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      uint32(3437079227),\n\t\t},\n\t\t{\n\t\t\tname:      \"register130_register131_abcd_float32_ieee\",\n\t\t\taddress:   []uint16{130, 131},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"FLOAT32-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      float32(-3.3360025e-13),\n\t\t},\n\t\t{\n\t\t\tname:      \"register130_register131_abcd_float32_ieee_scaled\",\n\t\t\taddress:   []uint16{130, 131},\n\t\t\tquantity:  2,\n\t\t\tbyteOrder: \"ABCD\",\n\t\t\tdataType:  \"FLOAT32-IEEE\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0xAA, 0xBB, 0xCC, 0xDD},\n\t\t\tread:      float32(-3.3360025e-12),\n\t\t},\n\t\t{\n\t\t\tname:      \"register140_to_register143_abcdefgh_int64_scaled\",\n\t\t\taddress:   []uint16{140, 141, 142, 143},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"INT64\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},\n\t\t\tread:      int64(10995116717570),\n\t\t},\n\t\t{\n\t\t\tname:      \"register140_to_register143_abcdefgh_int64\",\n\t\t\taddress:   []uint16{140, 141, 142, 143},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"INT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},\n\t\t\tread:      int64(1099511671757),\n\t\t},\n\t\t{\n\t\t\tname:      \"register150_to_register153_hgfedcba_int64\",\n\t\t\taddress:   []uint16{150, 151, 152, 153},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"HGFEDCBA\",\n\t\t\tdataType:  \"INT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x84, 0xF6, 0x45, 0xF9, 0xBC, 0xFE, 0xFF, 0xFF},\n\t\t\tread:      int64(-1387387292028),\n\t\t},\n\t\t{\n\t\t\tname:      \"register160_to_register163_badcfehg_int64\",\n\t\t\taddress:   []uint16{160, 161, 162, 163},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"BADCFEHG\",\n\t\t\tdataType:  \"INT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xFF, 0xFF, 0xBC, 0xFE, 0x45, 0xF9, 0x84, 0xF6},\n\t\t\tread:      int64(-1387387292028),\n\t\t},\n\t\t{\n\t\t\tname:      \"register170_to_register173_ghefcdab_int64\",\n\t\t\taddress:   []uint16{170, 171, 172, 173},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"GHEFCDAB\",\n\t\t\tdataType:  \"INT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xF6, 0x84, 0xF9, 0x45, 0xFE, 0xBC, 0xFF, 0xFF},\n\t\t\tread:      int64(-1387387292028),\n\t\t},\n\t\t{\n\t\t\tname:      \"register180_to_register183_abcdefgh_uint64_scaled\",\n\t\t\taddress:   []uint16{180, 181, 182, 183},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"UINT64\",\n\t\t\tscale:     10,\n\t\t\twrite:     []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},\n\t\t\tread:      uint64(10995116717570),\n\t\t},\n\t\t{\n\t\t\tname:      \"register180_to_register183_abcdefgh_uint64\",\n\t\t\taddress:   []uint16{180, 181, 182, 183},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"UINT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB, 0xCD},\n\t\t\tread:      uint64(1099511671757),\n\t\t},\n\t\t{\n\t\t\tname:      \"register190_to_register193_hgfedcba_uint64\",\n\t\t\taddress:   []uint16{190, 191, 192, 193},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"HGFEDCBA\",\n\t\t\tdataType:  \"UINT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x84, 0xF6, 0x45, 0xF9, 0xBC, 0xFE, 0xFF, 0xFF},\n\t\t\tread:      uint64(18446742686322259968),\n\t\t},\n\t\t{\n\t\t\tname:      \"register200_to_register203_badcfehg_uint64\",\n\t\t\taddress:   []uint16{200, 201, 202, 203},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"BADCFEHG\",\n\t\t\tdataType:  \"UINT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xFF, 0xFF, 0xBC, 0xFE, 0x45, 0xF9, 0x84, 0xF6},\n\t\t\tread:      uint64(18446742686322259968),\n\t\t},\n\t\t{\n\t\t\tname:      \"register210_to_register213_ghefcdab_uint64\",\n\t\t\taddress:   []uint16{210, 211, 212, 213},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"GHEFCDAB\",\n\t\t\tdataType:  \"UINT64\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xF6, 0x84, 0xF9, 0x45, 0xFE, 0xBC, 0xFF, 0xFF},\n\t\t\tread:      uint64(18446742686322259968),\n\t\t},\n\t\t{\n\t\t\tname:      \"register214_to_register217_abcdefgh_float64_ieee\",\n\t\t\taddress:   []uint16{214, 215, 216, 217},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xBF, 0x9C, 0x6A, 0x40, 0xC3, 0x47, 0x8F, 0x55},\n\t\t\tread:      float64(-0.02774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register214_to_register217_abcdefgh_float64_ieee_scaled\",\n\t\t\taddress:   []uint16{214, 215, 216, 217},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     0.1,\n\t\t\twrite:     []byte{0xBF, 0x9C, 0x6A, 0x40, 0xC3, 0x47, 0x8F, 0x55},\n\t\t\tread:      float64(-0.002774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register218_to_register221_abcdefgh_float64_ieee_pos\",\n\t\t\taddress:   []uint16{218, 219, 220, 221},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"ABCDEFGH\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x3F, 0x9C, 0x6A, 0x40, 0xC3, 0x47, 0x8F, 0x55},\n\t\t\tread:      float64(0.02774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register222_to_register225_hgfecdba_float64_ieee\",\n\t\t\taddress:   []uint16{222, 223, 224, 225},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"HGFEDCBA\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x55, 0x8F, 0x47, 0xC3, 0x40, 0x6A, 0x9C, 0xBF},\n\t\t\tread:      float64(-0.02774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register226_to_register229_badcfehg_float64_ieee\",\n\t\t\taddress:   []uint16{226, 227, 228, 229},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"BADCFEHG\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x9C, 0xBF, 0x40, 0x6A, 0x47, 0xC3, 0x55, 0x8F},\n\t\t\tread:      float64(-0.02774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register230_to_register233_ghefcdab_float64_ieee\",\n\t\t\taddress:   []uint16{230, 231, 232, 233},\n\t\t\tquantity:  4,\n\t\t\tbyteOrder: \"GHEFCDAB\",\n\t\t\tdataType:  \"FLOAT64-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x8F, 0x55, 0xC3, 0x47, 0x6A, 0x40, 0xBF, 0x9C},\n\t\t\tread:      float64(-0.02774907295123737),\n\t\t},\n\t\t{\n\t\t\tname:      \"register240_abcd_float16\",\n\t\t\taddress:   []uint16{240},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"FLOAT16-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0xb8, 0x14},\n\t\t\tread:      float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:      \"register240_dcba_float16\",\n\t\t\taddress:   []uint16{240},\n\t\t\tquantity:  1,\n\t\t\tbyteOrder: \"BA\",\n\t\t\tdataType:  \"FLOAT16-IEEE\",\n\t\t\tscale:     1,\n\t\t\twrite:     []byte{0x14, 0xb8},\n\t\t\tread:      float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:      \"register250_abcd_string\",\n\t\t\taddress:   []uint16{250, 251, 252, 253, 254, 255, 256},\n\t\t\tquantity:  7,\n\t\t\tbyteOrder: \"AB\",\n\t\t\tdataType:  \"STRING\",\n\t\t\twrite:     []byte{0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00},\n\t\t\tread:      \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:      \"register250_dcba_string\",\n\t\t\taddress:   []uint16{250, 251, 252, 253, 254, 255, 256},\n\t\t\tquantity:  7,\n\t\t\tbyteOrder: \"BA\",\n\t\t\tdataType:  \"STRING\",\n\t\t\twrite:     []byte{0x6f, 0x4d, 0x62, 0x64, 0x73, 0x75, 0x53, 0x20, 0x72, 0x74, 0x6e, 0x69, 0x00, 0x67},\n\t\t\tread:      \"Modbus String\",\n\t\t},\n\t}\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfor _, hrt := range holdingRegisterTests {\n\t\tt.Run(hrt.name, func(t *testing.T) {\n\t\t\t_, err := client.WriteMultipleRegisters(hrt.address[0], hrt.quantity, hrt.write)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodbus := Modbus{\n\t\t\t\tName:       \"TestHoldingRegisters\",\n\t\t\t\tController: \"tcp://localhost:1502\",\n\t\t\t\tLog:        testutil.Logger{},\n\t\t\t}\n\t\t\tmodbus.SlaveID = 1\n\t\t\tmodbus.HoldingRegisters = []fieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      hrt.name,\n\t\t\t\t\tByteOrder: hrt.byteOrder,\n\t\t\t\t\tDataType:  hrt.dataType,\n\t\t\t\t\tScale:     hrt.scale,\n\t\t\t\t\tAddress:   hrt.address,\n\t\t\t\t\tBit:       hrt.bit,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\t\t\"name\":     modbus.Name,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{hrt.name: hrt.read},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, modbus.Init())\n\t\t\trequire.NotEmpty(t, modbus.requests)\n\t\t\trequire.NoError(t, modbus.Gather(&acc))\n\t\t\tacc.Wait(len(expected))\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRegisterReadMultipleCoilWithHole(t *testing.T) {\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfcs := make([]fieldDefinition, 0, 26)\n\texpectedFields := make(map[string]interface{})\n\twriteValue := uint16(0)\n\treadValue := uint16(0)\n\tfor i := 0; i < 14; i++ {\n\t\tfc := fieldDefinition{}\n\t\tfc.Name = fmt.Sprintf(\"coil-%v\", i)\n\t\tfc.Address = []uint16{uint16(i)}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleCoil(fc.Address[0], writeValue)\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = readValue\n\t\twriteValue = 65280 - writeValue\n\t\treadValue = 1 - readValue\n\t}\n\tfor i := 15; i < 18; i++ {\n\t\tfc := fieldDefinition{}\n\t\tfc.Name = fmt.Sprintf(\"coil-%v\", i)\n\t\tfc.Address = []uint16{uint16(i)}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleCoil(fc.Address[0], writeValue)\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = readValue\n\t\twriteValue = 65280 - writeValue\n\t\treadValue = 1 - readValue\n\t}\n\tfor i := 24; i < 33; i++ {\n\t\tfc := fieldDefinition{}\n\t\tfc.Name = fmt.Sprintf(\"coil-%v\", i)\n\t\tfc.Address = []uint16{uint16(i)}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleCoil(fc.Address[0], writeValue)\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = readValue\n\t\twriteValue = 65280 - writeValue\n\t\treadValue = 1 - readValue\n\t}\n\trequire.Len(t, expectedFields, len(fcs))\n\n\tmodbus := Modbus{\n\t\tName:       \"TestReadMultipleCoilWithHole\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tLog:        testutil.Logger{Name: \"modbus:MultipleCoilWithHole\"},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = fcs\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cCoils,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\texpectedFields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRegisterReadMultipleCoilLimit(t *testing.T) {\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfcs := make([]fieldDefinition, 0, 4000)\n\texpectedFields := make(map[string]interface{})\n\twriteValue := uint16(0)\n\treadValue := uint16(0)\n\tfor i := 0; i < 4000; i++ {\n\t\tfc := fieldDefinition{}\n\t\tfc.Name = fmt.Sprintf(\"coil-%v\", i)\n\t\tfc.Address = []uint16{uint16(i)}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleCoil(fc.Address[0], writeValue)\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = readValue\n\t\twriteValue = 65280 - writeValue\n\t\treadValue = 1 - readValue\n\t}\n\trequire.Len(t, expectedFields, len(fcs))\n\n\tmodbus := Modbus{\n\t\tName:       \"TestReadCoils\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tLog:        testutil.Logger{},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = fcs\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cCoils,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\texpectedFields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRegisterReadMultipleHoldingRegisterWithHole(t *testing.T) {\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfcs := make([]fieldDefinition, 0, 20)\n\texpectedFields := make(map[string]interface{})\n\tfor i := 0; i < 10; i++ {\n\t\tfc := fieldDefinition{\n\t\t\tName:      fmt.Sprintf(\"HoldingRegister-%v\", i),\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tScale:     1.0,\n\t\t\tAddress:   []uint16{uint16(i)},\n\t\t}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleRegister(fc.Address[0], uint16(i))\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = int64(i)\n\t}\n\tfor i := 20; i < 30; i++ {\n\t\tfc := fieldDefinition{\n\t\t\tName:      fmt.Sprintf(\"HoldingRegister-%v\", i),\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tScale:     1.0,\n\t\t\tAddress:   []uint16{uint16(i)},\n\t\t}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleRegister(fc.Address[0], uint16(i))\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = int64(i)\n\t}\n\trequire.Len(t, expectedFields, len(fcs))\n\n\tmodbus := Modbus{\n\t\tName:       \"TestHoldingRegister\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tLog:        testutil.Logger{},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.HoldingRegisters = fcs\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\texpectedFields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRegisterReadMultipleHoldingRegisterLimit(t *testing.T) {\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfcs := make([]fieldDefinition, 0, 401)\n\texpectedFields := make(map[string]interface{})\n\tfor i := 0; i <= 400; i++ {\n\t\tfc := fieldDefinition{}\n\t\tfc.Name = fmt.Sprintf(\"HoldingRegister-%v\", i)\n\t\tfc.ByteOrder = \"AB\"\n\t\tfc.DataType = \"INT16\"\n\t\tfc.Scale = 1.0\n\t\tfc.Address = []uint16{uint16(i)}\n\t\tfcs = append(fcs, fc)\n\n\t\t_, err := client.WriteSingleRegister(fc.Address[0], uint16(i))\n\t\trequire.NoError(t, err)\n\n\t\texpectedFields[fc.Name] = int64(i)\n\t}\n\n\tmodbus := Modbus{\n\t\tName:       \"TestHoldingRegister\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tLog:        testutil.Logger{},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.HoldingRegisters = fcs\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\texpectedFields,\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRegisterHighAddresses(t *testing.T) {\n\t// Test case for issue https://github.com/influxdata/telegraf/issues/15138\n\n\t// Setup a server\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\t// Write the register values\n\tdata := []byte{\n\t\t0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53,\n\t\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x48, 0x65,\n\t\t0x6c, 0x6c, 0x6f, 0x00,\n\t}\n\t_, err := client.WriteMultipleRegisters(65524, 10, data)\n\trequire.NoError(t, err)\n\t_, err = client.WriteMultipleRegisters(65534, 1, []byte{0x10, 0x92})\n\trequire.NoError(t, err)\n\n\tmodbus := Modbus{\n\t\tName:       \"Issue-15138\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tLog:        testutil.Logger{},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.HoldingRegisters = []fieldDefinition{\n\t\t{\n\t\t\tName:      \"DeviceName\",\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"STRING\",\n\t\t\tAddress:   []uint16{65524, 65525, 65526, 65527, 65528, 65529, 65530, 65531, 65532, 65533},\n\t\t},\n\t\t{\n\t\t\tName:      \"DeviceConnectionStatus\",\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"UINT16\",\n\t\t\tAddress:   []uint16{65534},\n\t\t\tScale:     1,\n\t\t},\n\t}\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"DeviceName\":             \"Modbus String Hello\",\n\t\t\t\t\"DeviceConnectionStatus\": uint16(4242),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.Len(t, modbus.requests[1].holding, 1)\n\trequire.NoError(t, modbus.Gather(&acc))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_request.go",
    "content": "package modbus\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/maphash\"\n\t\"math\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n//go:embed sample_request.conf\nvar sampleConfigPartPerRequest string\n\ntype requestFieldDefinition struct {\n\tAddress     uint16  `toml:\"address\"`\n\tName        string  `toml:\"name\"`\n\tInputType   string  `toml:\"type\"`\n\tLength      uint16  `toml:\"length\"`\n\tScale       float64 `toml:\"scale\"`\n\tOutputType  string  `toml:\"output\"`\n\tMeasurement string  `toml:\"measurement\"`\n\tOmit        bool    `toml:\"omit\"`\n\tBit         uint8   `toml:\"bit\"`\n}\n\ntype requestDefinition struct {\n\tSlaveID           byte                     `toml:\"slave_id\"`\n\tByteOrder         string                   `toml:\"byte_order\"`\n\tRegisterType      string                   `toml:\"register\"`\n\tMeasurement       string                   `toml:\"measurement\"`\n\tOptimization      string                   `toml:\"optimization\"`\n\tMaxExtraRegisters uint16                   `toml:\"optimization_max_register_fill\"`\n\tFields            []requestFieldDefinition `toml:\"fields\"`\n\tTags              map[string]string        `toml:\"tags\"`\n}\n\ntype configurationPerRequest struct {\n\tRequests []requestDefinition `toml:\"request\"`\n\n\tworkarounds         workarounds\n\texcludeRegisterType bool\n\tlogger              telegraf.Logger\n}\n\nfunc (*configurationPerRequest) sampleConfigPart() string {\n\treturn sampleConfigPartPerRequest\n}\n\nfunc (c *configurationPerRequest) check() error {\n\tswitch c.workarounds.StringRegisterLocation {\n\tcase \"\", \"both\", \"lower\", \"upper\":\n\t\t// Do nothing as those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'string_register_location' %q\", c.workarounds.StringRegisterLocation)\n\t}\n\n\tseed := maphash.MakeSeed()\n\tseenFields := make(map[uint64]bool)\n\n\tfor _, def := range c.Requests {\n\t\t// Check byte order of the data\n\t\tswitch def.ByteOrder {\n\t\tcase \"\":\n\t\t\tdef.ByteOrder = \"ABCD\"\n\t\tcase \"ABCD\", \"DCBA\", \"BADC\", \"CDAB\", \"MSW-BE\", \"MSW-LE\", \"LSW-LE\", \"LSW-BE\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown byte-order %q\", def.ByteOrder)\n\t\t}\n\n\t\t// Check register type\n\t\tswitch def.RegisterType {\n\t\tcase \"\":\n\t\t\tdef.RegisterType = \"holding\"\n\t\tcase \"coil\", \"discrete\", \"holding\", \"input\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown register-type %q\", def.RegisterType)\n\t\t}\n\t\t// Check for valid optimization\n\t\tswitch def.Optimization {\n\t\tcase \"\", \"none\", \"shrink\", \"rearrange\":\n\t\tcase \"max_insert\":\n\t\t\tswitch def.RegisterType {\n\t\t\tcase \"coil\":\n\t\t\t\tif def.MaxExtraRegisters <= 0 || def.MaxExtraRegisters > maxQuantityCoils {\n\t\t\t\t\treturn fmt.Errorf(\"optimization_max_register_fill has to be between 1 and %d\", maxQuantityCoils)\n\t\t\t\t}\n\t\t\tcase \"discrete\":\n\t\t\t\tif def.MaxExtraRegisters <= 0 || def.MaxExtraRegisters > maxQuantityDiscreteInput {\n\t\t\t\t\treturn fmt.Errorf(\"optimization_max_register_fill has to be between 1 and %d\", maxQuantityDiscreteInput)\n\t\t\t\t}\n\t\t\tcase \"holding\":\n\t\t\t\tif def.MaxExtraRegisters <= 0 || def.MaxExtraRegisters > maxQuantityHoldingRegisters {\n\t\t\t\t\treturn fmt.Errorf(\"optimization_max_register_fill has to be between 1 and %d\", maxQuantityHoldingRegisters)\n\t\t\t\t}\n\t\t\tcase \"input\":\n\t\t\t\tif def.MaxExtraRegisters <= 0 || def.MaxExtraRegisters > maxQuantityInputRegisters {\n\t\t\t\t\treturn fmt.Errorf(\"optimization_max_register_fill has to be between 1 and %d\", maxQuantityInputRegisters)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown optimization %q\", def.Optimization)\n\t\t}\n\t\t// Set the default for measurement if required\n\t\tif def.Measurement == \"\" {\n\t\t\tdef.Measurement = \"modbus\"\n\t\t}\n\n\t\t// Reject any configuration without fields as it\n\t\t// makes no sense to not define anything but a request.\n\t\tif len(def.Fields) == 0 {\n\t\t\treturn errors.New(\"found request section without fields\")\n\t\t}\n\n\t\t// Check the fields\n\t\tfor fidx, f := range def.Fields {\n\t\t\t// Check the input type for all fields except the bit-field ones.\n\t\t\t// We later need the type (even for omitted fields) to determine the length.\n\t\t\tif def.RegisterType == \"holding\" || def.RegisterType == \"input\" {\n\t\t\t\tswitch f.InputType {\n\t\t\t\tcase \"\":\n\t\t\t\tcase \"INT8L\", \"INT8H\", \"INT16\", \"INT32\", \"INT64\",\n\t\t\t\t\t\"UINT8L\", \"UINT8H\", \"UINT16\", \"UINT32\", \"UINT64\",\n\t\t\t\t\t\"FLOAT16\", \"FLOAT32\", \"FLOAT64\":\n\t\t\t\t\tif f.Length != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"length option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Bit != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"bit option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType == \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"cannot output field %q as string\", f.Name)\n\t\t\t\t\t}\n\t\t\t\tcase \"STRING\":\n\t\t\t\t\tif f.Length < 1 {\n\t\t\t\t\t\treturn fmt.Errorf(\"missing length for string field %q\", f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Bit != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"bit option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.Scale != 0.0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"scale option cannot be used for string field %q\", f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType != \"\" && f.OutputType != \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid output type %q for string field %q\", f.OutputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\tcase \"BIT\":\n\t\t\t\t\tif f.Length != 0 {\n\t\t\t\t\t\treturn fmt.Errorf(\"length option cannot be used for type %q of field %q\", f.InputType, f.Name)\n\t\t\t\t\t}\n\t\t\t\t\tif f.OutputType == \"STRING\" {\n\t\t\t\t\t\treturn fmt.Errorf(\"cannot output field %q as string\", f.Name)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown register data-type %q for field %q\", f.InputType, f.Name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Other properties don't need to be checked for omitted fields\n\t\t\tif f.Omit {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Name is mandatory\n\t\t\tif f.Name == \"\" {\n\t\t\t\treturn fmt.Errorf(\"empty field name in request for slave %d\", def.SlaveID)\n\t\t\t}\n\n\t\t\t// Check output type\n\t\t\tif def.RegisterType == \"holding\" || def.RegisterType == \"input\" {\n\t\t\t\tswitch f.OutputType {\n\t\t\t\tcase \"\", \"INT64\", \"UINT64\", \"FLOAT64\", \"STRING\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown output data-type %q for field %q\", f.OutputType, f.Name)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Bit register types can only be UINT64 or BOOL\n\t\t\t\tswitch f.OutputType {\n\t\t\t\tcase \"\", \"UINT16\", \"BOOL\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown output data-type %q for field %q\", f.OutputType, f.Name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle the default for measurement\n\t\t\tif f.Measurement == \"\" {\n\t\t\t\tf.Measurement = def.Measurement\n\t\t\t}\n\t\t\tdef.Fields[fidx] = f\n\n\t\t\t// Check for duplicate field definitions\n\t\t\tid := c.fieldID(seed, def, f)\n\t\t\tif seenFields[id] {\n\t\t\t\treturn fmt.Errorf(\"field %q duplicated in measurement %q (slave %d/%q)\", f.Name, f.Measurement, def.SlaveID, def.RegisterType)\n\t\t\t}\n\t\t\tseenFields[id] = true\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *configurationPerRequest) process() (map[byte]requestSet, error) {\n\tresult := make(map[byte]requestSet, len(c.Requests))\n\tfor _, def := range c.Requests {\n\t\t// Set default\n\t\tif def.RegisterType == \"\" {\n\t\t\tdef.RegisterType = \"holding\"\n\t\t}\n\n\t\t// Construct the fields\n\t\tisTyped := def.RegisterType == \"holding\" || def.RegisterType == \"input\"\n\t\tfields, err := c.initFields(def.Fields, isTyped, def.ByteOrder)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Make sure we have a set to work with\n\t\tset, found := result[def.SlaveID]\n\t\tif !found {\n\t\t\tset = requestSet{}\n\t\t}\n\n\t\tparams := groupingParams{\n\t\t\tmaxExtraRegisters: def.MaxExtraRegisters,\n\t\t\toptimization:      def.Optimization,\n\t\t\ttags:              def.Tags,\n\t\t\tlog:               c.logger,\n\t\t}\n\t\tswitch def.RegisterType {\n\t\tcase \"coil\":\n\t\t\tparams.maxBatchSize = maxQuantityCoils\n\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\tparams.maxBatchSize = 1\n\t\t\t}\n\t\t\tparams.enforceFromZero = c.workarounds.ReadCoilsStartingAtZero\n\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\tset.coil = append(set.coil, requests...)\n\t\tcase \"discrete\":\n\t\t\tparams.maxBatchSize = maxQuantityDiscreteInput\n\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\tparams.maxBatchSize = 1\n\t\t\t}\n\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\tset.discrete = append(set.discrete, requests...)\n\t\tcase \"holding\":\n\t\t\tparams.maxBatchSize = maxQuantityHoldingRegisters\n\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\tparams.maxBatchSize = 1\n\t\t\t}\n\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\tset.holding = append(set.holding, requests...)\n\t\tcase \"input\":\n\t\t\tparams.maxBatchSize = maxQuantityInputRegisters\n\t\t\tif c.workarounds.OnRequestPerField {\n\t\t\t\tparams.maxBatchSize = 1\n\t\t\t}\n\t\t\trequests := groupFieldsToRequests(fields, params)\n\t\t\tset.input = append(set.input, requests...)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown register type %q\", def.RegisterType)\n\t\t}\n\t\tif !set.empty() {\n\t\t\tresult[def.SlaveID] = set\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc (c *configurationPerRequest) initFields(fieldDefs []requestFieldDefinition, typed bool, byteOrder string) ([]field, error) {\n\t// Construct the fields from the field definitions\n\tfields := make([]field, 0, len(fieldDefs))\n\tfor _, def := range fieldDefs {\n\t\tf, err := c.newFieldFromDefinition(def, typed, byteOrder)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"initializing field %q failed: %w\", def.Name, err)\n\t\t}\n\t\tfields = append(fields, f)\n\t}\n\n\treturn fields, nil\n}\n\nfunc (c *configurationPerRequest) newFieldFromDefinition(def requestFieldDefinition, typed bool, byteOrder string) (field, error) {\n\tvar err error\n\n\tfieldLength := uint16(1)\n\tif typed {\n\t\tif fieldLength, err = determineFieldLength(def.InputType, def.Length); err != nil {\n\t\t\treturn field{}, err\n\t\t}\n\t}\n\n\t// Check for address overflow\n\tif def.Address > math.MaxUint16-fieldLength {\n\t\treturn field{}, fmt.Errorf(\"%w for field %q\", errAddressOverflow, def.Name)\n\t}\n\n\t// Initialize the field\n\tf := field{\n\t\tmeasurement: def.Measurement,\n\t\tname:        def.Name,\n\t\taddress:     def.Address,\n\t\tlength:      fieldLength,\n\t\tomit:        def.Omit,\n\t}\n\n\t// Handle type conversions for coil and discrete registers\n\tif !typed {\n\t\tf.converter, err = determineUntypedConverter(def.OutputType)\n\t\tif err != nil {\n\t\t\treturn field{}, err\n\t\t}\n\t}\n\n\t// No more processing for un-typed (coil and discrete registers) or omitted fields\n\tif !typed || def.Omit {\n\t\treturn f, nil\n\t}\n\n\t// Automagically determine the output type...\n\tif def.OutputType == \"\" {\n\t\tif def.Scale == 0.0 {\n\t\t\t// For non-scaling cases we should choose the output corresponding to the input class\n\t\t\t// i.e. INT64 for INT*, UINT64 for UINT* etc.\n\t\t\tvar err error\n\t\t\tif def.OutputType, err = determineOutputDatatype(def.InputType); err != nil {\n\t\t\t\treturn field{}, err\n\t\t\t}\n\t\t} else {\n\t\t\t// For scaling cases we always want FLOAT64 by default except for\n\t\t\t// string fields\n\t\t\tif def.InputType != \"STRING\" {\n\t\t\t\tdef.OutputType = \"FLOAT64\"\n\t\t\t} else {\n\t\t\t\tdef.OutputType = \"STRING\"\n\t\t\t}\n\t\t}\n\t}\n\n\t// Setting default byte-order\n\tif byteOrder == \"\" {\n\t\tbyteOrder = \"ABCD\"\n\t}\n\n\t// Normalize the data relevant for determining the converter\n\tinType, err := normalizeInputDatatype(def.InputType)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\toutType, err := normalizeOutputDatatype(def.OutputType)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\torder, err := normalizeByteOrder(byteOrder)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\n\tf.converter, err = determineConverter(inType, order, outType, def.Scale, def.Bit, c.workarounds.StringRegisterLocation)\n\tif err != nil {\n\t\treturn field{}, err\n\t}\n\n\treturn f, nil\n}\n\nfunc (c *configurationPerRequest) fieldID(seed maphash.Seed, def requestDefinition, field requestFieldDefinition) uint64 {\n\tvar mh maphash.Hash\n\tmh.SetSeed(seed)\n\n\tmh.WriteByte(def.SlaveID)\n\tmh.WriteByte(0)\n\tif !c.excludeRegisterType {\n\t\tmh.WriteString(def.RegisterType)\n\t\tmh.WriteByte(0)\n\t}\n\tmh.WriteString(field.Measurement)\n\tmh.WriteByte(0)\n\tmh.WriteString(field.Name)\n\tmh.WriteByte(0)\n\n\t// tags\n\tfor k, v := range def.Tags {\n\t\tmh.WriteString(k)\n\t\tmh.WriteByte('=')\n\t\tmh.WriteString(v)\n\t\tmh.WriteByte(':')\n\t}\n\tmh.WriteByte(0)\n\n\treturn mh.Sum64()\n}\n\nfunc determineOutputDatatype(input string) (string, error) {\n\t// Handle our special types\n\tswitch input {\n\tcase \"INT8L\", \"INT8H\", \"INT16\", \"INT32\", \"INT64\":\n\t\treturn \"INT64\", nil\n\tcase \"BIT\", \"UINT8L\", \"UINT8H\", \"UINT16\", \"UINT32\", \"UINT64\":\n\t\treturn \"UINT64\", nil\n\tcase \"FLOAT16\", \"FLOAT32\", \"FLOAT64\":\n\t\treturn \"FLOAT64\", nil\n\tcase \"STRING\":\n\t\treturn \"STRING\", nil\n\t}\n\treturn \"unknown\", fmt.Errorf(\"invalid input datatype %q for determining output\", input)\n}\n\nfunc determineFieldLength(input string, length uint16) (uint16, error) {\n\t// Handle our special types\n\tswitch input {\n\tcase \"BIT\", \"INT8L\", \"INT8H\", \"UINT8L\", \"UINT8H\":\n\t\treturn 1, nil\n\tcase \"INT16\", \"UINT16\", \"FLOAT16\":\n\t\treturn 1, nil\n\tcase \"INT32\", \"UINT32\", \"FLOAT32\":\n\t\treturn 2, nil\n\tcase \"INT64\", \"UINT64\", \"FLOAT64\":\n\t\treturn 4, nil\n\tcase \"STRING\":\n\t\treturn length, nil\n\t}\n\treturn 0, fmt.Errorf(\"invalid input datatype %q for determining field length\", input)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/configuration_request_test.go",
    "content": "package modbus\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tmb \"github.com/grid-x/modbus\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tbrandon/mbserver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRequest(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"coil\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-0\",\n\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-1\",\n\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-3\",\n\t\t\t\t\tAddress:     uint16(3),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"BOOL\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tRegisterType: \"coil\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-4\",\n\t\t\t\t\tAddress: uint16(6),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-5\",\n\t\t\t\t\tAddress: uint16(7),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-6\",\n\t\t\t\t\tAddress:     uint16(8),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-7\",\n\t\t\t\t\tAddress:     uint16(9),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"BOOL\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"discrete\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"discrete-0\",\n\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"discrete-1\",\n\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"discrete-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"discrete-3\",\n\t\t\t\t\tAddress:     uint16(3),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"BOOL\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"holding-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"FLOAT64\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"input\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"input-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"input-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"input-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"FLOAT64\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NotNil(t, modbus.requests[1])\n\trequire.Len(t, modbus.requests[1].coil, 2)\n\trequire.Len(t, modbus.requests[1].discrete, 1)\n\trequire.Len(t, modbus.requests[1].holding, 1)\n\trequire.Len(t, modbus.requests[1].input, 1)\n}\n\nfunc TestRequestWithTags(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"coil\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-0\",\n\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-1\",\n\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"first\":  \"a\",\n\t\t\t\t\"second\": \"bb\",\n\t\t\t\t\"third\":  \"ccc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tRegisterType: \"coil\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-3\",\n\t\t\t\t\tAddress: uint16(6),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-4\",\n\t\t\t\t\tAddress: uint16(7),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"coil-5\",\n\t\t\t\t\tAddress:     uint16(8),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"first\":  \"a\",\n\t\t\t\t\"second\": \"bb\",\n\t\t\t\t\"third\":  \"ccc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"discrete\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"discrete-0\",\n\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"discrete-1\",\n\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\tOmit:    true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"discrete-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"UINT16\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"first\":  \"a\",\n\t\t\t\t\"second\": \"bb\",\n\t\t\t\t\"third\":  \"ccc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"holding-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"FLOAT64\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"first\":  \"a\",\n\t\t\t\t\"second\": \"bb\",\n\t\t\t\t\"third\":  \"ccc\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"input\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"input-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"input-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:        \"input-2\",\n\t\t\t\t\tAddress:     uint16(2),\n\t\t\t\t\tInputType:   \"INT64\",\n\t\t\t\t\tScale:       1.2,\n\t\t\t\t\tOutputType:  \"FLOAT64\",\n\t\t\t\t\tMeasurement: \"modbus\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: map[string]string{\n\t\t\t\t\"first\":  \"a\",\n\t\t\t\t\"second\": \"bb\",\n\t\t\t\t\"third\":  \"ccc\",\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NotNil(t, modbus.requests[1])\n\trequire.Len(t, modbus.requests[1].coil, 2)\n\trequire.Len(t, modbus.requests[1].discrete, 1)\n\trequire.Len(t, modbus.requests[1].holding, 1)\n\trequire.Len(t, modbus.requests[1].input, 1)\n\n\texpectedTags := map[string]string{\n\t\t\"first\":  \"a\",\n\t\t\"second\": \"bb\",\n\t\t\"third\":  \"ccc\",\n\t}\n\trequire.Equal(t, expectedTags, modbus.requests[1].coil[0].fields[0].tags)\n\trequire.Equal(t, expectedTags, modbus.requests[1].coil[1].fields[0].tags)\n\trequire.Equal(t, expectedTags, modbus.requests[1].discrete[0].fields[0].tags)\n\trequire.Equal(t, expectedTags, modbus.requests[1].holding[0].fields[0].tags)\n\trequire.Equal(t, expectedTags, modbus.requests[1].input[0].fields[0].tags)\n}\n\nfunc TestRequestTypesCoil(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\taddress     uint16\n\t\tdataTypeOut string\n\t\twrite       uint16\n\t\tread        interface{}\n\t}{\n\t\t{\n\t\t\tname:    \"coil-1-off\",\n\t\t\taddress: 1,\n\t\t\twrite:   0,\n\t\t\tread:    uint16(0),\n\t\t},\n\t\t{\n\t\t\tname:    \"coil-2-on\",\n\t\t\taddress: 2,\n\t\t\twrite:   0xFF00,\n\t\t\tread:    uint16(1),\n\t\t},\n\t\t{\n\t\t\tname:        \"coil-3-false\",\n\t\t\taddress:     3,\n\t\t\tdataTypeOut: \"BOOL\",\n\t\t\twrite:       0,\n\t\t\tread:        false,\n\t\t},\n\t\t{\n\t\t\tname:        \"coil-4-true\",\n\t\t\taddress:     4,\n\t\t\tdataTypeOut: \"BOOL\",\n\t\t\twrite:       0xFF00,\n\t\t\tread:        true,\n\t\t},\n\t}\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfor _, hrt := range tests {\n\t\tt.Run(hrt.name, func(t *testing.T) {\n\t\t\t_, err := client.WriteSingleCoil(hrt.address, hrt.write)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodbus := Modbus{\n\t\t\t\tName:              \"TestRequestTypesCoil\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tmodbus.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       hrt.name,\n\t\t\t\t\t\t\tOutputType: hrt.dataTypeOut,\n\t\t\t\t\t\t\tAddress:    hrt.address,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"type\":     cCoils,\n\t\t\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\t\t\"name\":     modbus.Name,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{hrt.name: hrt.read},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, modbus.Init())\n\t\t\trequire.NotEmpty(t, modbus.requests)\n\t\t\trequire.NoError(t, modbus.Gather(&acc))\n\t\t\tacc.Wait(len(expected))\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRequestTypesHoldingABCD(t *testing.T) {\n\tbyteOrder := \"ABCD\"\n\ttests := []struct {\n\t\tname        string\n\t\taddress     uint16\n\t\tbit         uint8\n\t\tlength      uint16\n\t\tbyteOrder   string\n\t\tdataTypeIn  string\n\t\tdataTypeOut string\n\t\tscale       float64\n\t\twrite       []byte\n\t\tread        interface{}\n\t}{\n\t\t{\n\t\t\tname:       \"register5_bit3\",\n\t\t\taddress:    5,\n\t\t\tdataTypeIn: \"BIT\",\n\t\t\tbit:        3,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(1),\n\t\t},\n\t\t{\n\t\t\tname:       \"register5_bit14\",\n\t\t\taddress:    5,\n\t\t\tdataTypeIn: \"BIT\",\n\t\t\tbit:        14,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(0),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L-scale_.1\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(1.3),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L_scale_10\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(130),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_uint64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        uint64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_int64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        int64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_float64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L_float64_scale\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L-scale_.1\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(1.3),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L_scale_10\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(130),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_uint64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        uint64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_int64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        int64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_float64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L_float64_scale\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       uint16(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16-scale_.1\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(220),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16_scale_10\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(22000),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_uint64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        uint64(2200),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_int64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        int64(2200),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_float64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        float64(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16_float64_scale\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       int16(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16-scale_.1\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-189.60000000000002),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16_scale_10\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-18960),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_uint64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        uint64(18446744073709549720),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_int64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        int64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_float64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        float64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16_float64_scale\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       uint32(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32-scale_.1\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(16849614.1),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32_scale_10\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(1684961410),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_uint64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        uint64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_int64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        int64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_float64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        float64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32_float64_scale\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       int32(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32-scale_.1\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-9993931.5),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32_scale_10\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-999393150),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_uint64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        uint64(18446744073609612301),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_int64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        int64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_float64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        float64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32_float64_scale\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       uint64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64-scale_.1\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(72368541533306905.8),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64_scale_10\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(7236854153330690000), // quantization error\n\t\t},\n\t\t{\n\t\t\tname:        \"register60_uint64_int64\",\n\t\t\taddress:     60,\n\t\t\tdataTypeIn:  \"UINT64\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        int64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:        \"register60_uint64_float64\",\n\t\t\taddress:     60,\n\t\t\tdataTypeIn:  \"UINT64\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        float64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64_float64_scale\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       int64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64-scale_.1\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-42923608927377791.8),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64_scale_10\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-4292360892737779180),\n\t\t},\n\t\t{\n\t\t\tname:        \"register70_int64_uint64\",\n\t\t\taddress:     70,\n\t\t\tdataTypeIn:  \"INT64\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        uint64(18017507984435773698),\n\t\t},\n\t\t{\n\t\t\tname:        \"register70_int64_float64\",\n\t\t\taddress:     70,\n\t\t\tdataTypeIn:  \"INT64\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        float64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64_float64_scale\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float32(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32-scale_.1\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(0.31415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32_scale_10\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(31.415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:        \"register80_float32_float64\",\n\t\t\taddress:     80,\n\t\t\tdataTypeIn:  \"FLOAT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:        float64(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32_float64_scale\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(3.14159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64-scale_.1\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(0.314159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64_scale_10\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(31.4159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64_float64_scale\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(3.14159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16-scale_.1\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.0509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16_scale_10\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-5.09765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16_float64_scale\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register110_string\",\n\t\t\taddress:    110,\n\t\t\tdataTypeIn: \"STRING\",\n\t\t\tlength:     7,\n\t\t\twrite:      []byte{0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00},\n\t\t\tread:       \"Modbus String\",\n\t\t},\n\t}\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfor _, hrt := range tests {\n\t\tt.Run(hrt.name, func(t *testing.T) {\n\t\t\tquantity := uint16(len(hrt.write) / 2)\n\t\t\t_, err := client.WriteMultipleRegisters(hrt.address, quantity, hrt.write)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodbus := Modbus{\n\t\t\t\tName:              \"TestRequestTypesHoldingABCD\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tmodbus.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    byteOrder,\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       hrt.name,\n\t\t\t\t\t\t\tInputType:  hrt.dataTypeIn,\n\t\t\t\t\t\t\tOutputType: hrt.dataTypeOut,\n\t\t\t\t\t\t\tScale:      hrt.scale,\n\t\t\t\t\t\t\tAddress:    hrt.address,\n\t\t\t\t\t\t\tLength:     hrt.length,\n\t\t\t\t\t\t\tBit:        hrt.bit,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\t\t\"name\":     modbus.Name,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{hrt.name: hrt.read},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, modbus.Init())\n\t\t\trequire.NotEmpty(t, modbus.requests)\n\t\t\trequire.NoError(t, modbus.Gather(&acc))\n\t\t\tacc.Wait(len(expected))\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRequestTypesHoldingDCBA(t *testing.T) {\n\tbyteOrder := \"DCBA\"\n\ttests := []struct {\n\t\tname        string\n\t\taddress     uint16\n\t\tlength      uint16\n\t\tbyteOrder   string\n\t\tdataTypeIn  string\n\t\tdataTypeOut string\n\t\tscale       float64\n\t\twrite       []byte\n\t\tread        interface{}\n\t}{\n\t\t{\n\t\t\tname:       \"register10_uint8L\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L-scale_.1\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(1.3),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L_scale_10\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(130),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_uint64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        uint64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_int64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        int64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register10_uint8L_float64\",\n\t\t\taddress:     10,\n\t\t\tdataTypeIn:  \"UINT8L\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register10_uint8L_float64_scale\",\n\t\t\taddress:    10,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"UINT8L\",\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       uint8(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L-scale_.1\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(1.3),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L_scale_10\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(130),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_uint64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        uint64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_int64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        int64(13),\n\t\t},\n\t\t{\n\t\t\tname:        \"register15_int8L_float64\",\n\t\t\taddress:     15,\n\t\t\tdataTypeIn:  \"INT8L\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x18, 0x0d},\n\t\t\tread:        float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register15_int8L_float64_scale\",\n\t\t\taddress:    15,\n\t\t\tdataTypeIn: \"INT8L\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x18, 0x0d},\n\t\t\tread:       float64(13),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       uint16(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16-scale_.1\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(220),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16_scale_10\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(22000),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_uint64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        uint64(2200),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_int64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        int64(2200),\n\t\t},\n\t\t{\n\t\t\tname:        \"register20_uint16_float64\",\n\t\t\taddress:     20,\n\t\t\tdataTypeIn:  \"UINT16\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x08, 0x98},\n\t\t\tread:        float64(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register20_uint16_float64_scale\",\n\t\t\taddress:    20,\n\t\t\tdataTypeIn: \"UINT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x08, 0x98},\n\t\t\tread:       float64(2200),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       int16(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16-scale_.1\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-189.60000000000002),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16_scale_10\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-18960),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_uint64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        uint64(18446744073709549720),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_int64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        int64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:        \"register30_int16_float64\",\n\t\t\taddress:     30,\n\t\t\tdataTypeIn:  \"INT16\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xf8, 0x98},\n\t\t\tread:        float64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register30_int16_float64_scale\",\n\t\t\taddress:    30,\n\t\t\tdataTypeIn: \"INT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xf8, 0x98},\n\t\t\tread:       float64(-1896),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       uint32(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32-scale_.1\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(16849614.1),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32_scale_10\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(1684961410),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_uint64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        uint64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_int64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        int64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:        \"register40_uint32_float64\",\n\t\t\taddress:     40,\n\t\t\tdataTypeIn:  \"UINT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        float64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register40_uint32_float64_scale\",\n\t\t\taddress:    40,\n\t\t\tdataTypeIn: \"UINT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(168496141),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       int32(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32-scale_.1\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-9993931.5),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32_scale_10\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-999393150),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_uint64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        uint64(18446744073609612301),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_int64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        int64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:        \"register50_int32_float64\",\n\t\t\taddress:     50,\n\t\t\tdataTypeIn:  \"INT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:        float64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register50_int32_float64_scale\",\n\t\t\taddress:    50,\n\t\t\tdataTypeIn: \"INT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d},\n\t\t\tread:       float64(-99939315),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       uint64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64-scale_.1\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(72368541533306905.8),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64_scale_10\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(7236854153330690000), // quantization error\n\t\t},\n\t\t{\n\t\t\tname:        \"register60_uint64_int64\",\n\t\t\taddress:     60,\n\t\t\tdataTypeIn:  \"UINT64\",\n\t\t\tdataTypeOut: \"INT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        int64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:        \"register60_uint64_float64\",\n\t\t\taddress:     60,\n\t\t\tdataTypeIn:  \"UINT64\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        float64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register60_uint64_float64_scale\",\n\t\t\taddress:    60,\n\t\t\tdataTypeIn: \"UINT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(723685415333069058),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       int64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64-scale_.1\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-42923608927377791.8),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64_scale_10\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-4292360892737779180),\n\t\t},\n\t\t{\n\t\t\tname:        \"register70_int64_uint64\",\n\t\t\taddress:     70,\n\t\t\tdataTypeIn:  \"INT64\",\n\t\t\tdataTypeOut: \"UINT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        uint64(18017507984435773698),\n\t\t},\n\t\t{\n\t\t\tname:        \"register70_int64_float64\",\n\t\t\taddress:     70,\n\t\t\tdataTypeIn:  \"INT64\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:        float64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register70_int64_float64_scale\",\n\t\t\taddress:    70,\n\t\t\tdataTypeIn: \"INT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xfa, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x02},\n\t\t\tread:       float64(-429236089273777918),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float32(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32-scale_.1\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(0.31415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32_scale_10\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(31.415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:        \"register80_float32_float64\",\n\t\t\taddress:     80,\n\t\t\tdataTypeIn:  \"FLOAT32\",\n\t\t\tdataTypeOut: \"FLOAT64\",\n\t\t\twrite:       []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:        float64(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register80_float32_float64_scale\",\n\t\t\taddress:    80,\n\t\t\tdataTypeIn: \"FLOAT32\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x40, 0x49, 0x0f, 0xdb},\n\t\t\tread:       float64(3.1415927410125732421875),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(3.14159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64-scale_.1\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(0.314159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64_scale_10\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(31.4159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register90_float64_float64_scale\",\n\t\t\taddress:    90,\n\t\t\tdataTypeIn: \"FLOAT64\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea},\n\t\t\tread:       float64(3.14159265359000006156975359772),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16-scale_.1\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      .1,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.0509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16_scale_10\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      10,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-5.09765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register100_float16_float64_scale\",\n\t\t\taddress:    100,\n\t\t\tdataTypeIn: \"FLOAT16\",\n\t\t\tscale:      1.0,\n\t\t\twrite:      []byte{0xb8, 0x14},\n\t\t\tread:       float64(-0.509765625),\n\t\t},\n\t\t{\n\t\t\tname:       \"register110_string\",\n\t\t\taddress:    110,\n\t\t\tdataTypeIn: \"STRING\",\n\t\t\tlength:     7,\n\t\t\twrite:      []byte{0x6f, 0x4d, 0x62, 0x64, 0x73, 0x75, 0x53, 0x20, 0x72, 0x74, 0x6e, 0x69, 0x00, 0x67},\n\t\t\tread:       \"Modbus String\",\n\t\t},\n\t}\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\n\tfor _, hrt := range tests {\n\t\tt.Run(hrt.name, func(t *testing.T) {\n\t\t\tquantity := uint16(len(hrt.write) / 2)\n\t\t\tinvert := make([]byte, 0, len(hrt.write))\n\t\t\tif hrt.dataTypeIn != \"STRING\" {\n\t\t\t\tfor i := len(hrt.write) - 1; i >= 0; i-- {\n\t\t\t\t\tinvert = append(invert, hrt.write[i])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Put in raw data for strings\n\t\t\t\tinvert = append(invert, hrt.write...)\n\t\t\t}\n\t\t\t_, err := client.WriteMultipleRegisters(hrt.address, quantity, invert)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodbus := Modbus{\n\t\t\t\tName:              \"TestRequestTypesHoldingDCBA\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tmodbus.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    byteOrder,\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       hrt.name,\n\t\t\t\t\t\t\tInputType:  hrt.dataTypeIn,\n\t\t\t\t\t\t\tOutputType: hrt.dataTypeOut,\n\t\t\t\t\t\t\tScale:      hrt.scale,\n\t\t\t\t\t\t\tAddress:    hrt.address,\n\t\t\t\t\t\t\tLength:     hrt.length,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\t\t\"name\":     modbus.Name,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{hrt.name: hrt.read},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, modbus.Init())\n\t\t\trequire.NotEmpty(t, modbus.requests)\n\t\t\trequire.NoError(t, modbus.Gather(&acc))\n\t\t\tacc.Wait(len(expected))\n\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestRequestFail(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\trequests []requestDefinition\n\t\terrormsg string\n\t}{\n\t\t{\n\t\t\tname: \"empty field name (coil)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: uint16(15),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"empty field name in request for slave 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid byte-order (coil)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"AB\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"unknown byte-order \\\"AB\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields (coil)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"coil-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"coil-0\",\n\t\t\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"coil-0\\\" duplicated in measurement \\\"modbus\\\" (slave 1/\\\"coil\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields multiple requests (coil)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"coil-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"coil\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"coil-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"coil-0\\\" duplicated in measurement \\\"foo\\\" (slave 1/\\\"coil\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid byte-order (discrete)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"AB\",\n\t\t\t\t\tRegisterType: \"discrete\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"unknown byte-order \\\"AB\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields (discrete)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"discrete\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"discrete-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"discrete-0\",\n\t\t\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"discrete-0\\\" duplicated in measurement \\\"modbus\\\" (slave 1/\\\"discrete\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields multiple requests (discrete)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"discrete\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"discrete-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"discrete\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"discrete-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"discrete-0\\\" duplicated in measurement \\\"foo\\\" (slave 1/\\\"discrete\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid byte-order (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"AB\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"unknown byte-order \\\"AB\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field name (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"empty field name in request for slave 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field input type (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"holding-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"initializing field \\\"holding-0\\\" failed: invalid input datatype \\\"\\\" for determining field length\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field output type (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       \"holding-0\",\n\t\t\t\t\t\t\tAddress:    uint16(0),\n\t\t\t\t\t\t\tInputType:  \"UINT16\",\n\t\t\t\t\t\t\tOutputType: \"UINT8\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: `unknown output data-type \"UINT8\" for field \"holding-0\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"holding-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"holding-0\",\n\t\t\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"holding-0\\\" duplicated in measurement \\\"modbus\\\" (slave 1/\\\"holding\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields multiple requests (holding)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"holding-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"holding-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"holding-0\\\" duplicated in measurement \\\"foo\\\" (slave 1/\\\"holding\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid byte-order (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"AB\",\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"unknown byte-order \\\"AB\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field name (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"empty field name in request for slave 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field input type (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"input-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"initializing field \\\"input-0\\\" failed: invalid input datatype \\\"\\\" for determining field length\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid field output type (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       \"input-0\",\n\t\t\t\t\t\t\tAddress:    uint16(0),\n\t\t\t\t\t\t\tInputType:  \"UINT16\",\n\t\t\t\t\t\t\tOutputType: \"UINT8\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: `unknown output data-type \"UINT8\" for field \"input-0\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"input-0\",\n\t\t\t\t\t\t\tAddress: uint16(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"input-0\",\n\t\t\t\t\t\t\tAddress: uint16(1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"input-0\\\" duplicated in measurement \\\"modbus\\\" (slave 1/\\\"input\\\")\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields multiple requests (input)\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"input-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"input\",\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"input-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"field \\\"input-0\\\" duplicated in measurement \\\"foo\\\" (slave 1/\\\"input\\\")\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tplugin.Requests = tt.requests\n\n\t\t\trequire.ErrorContains(t, plugin.Init(), tt.errormsg)\n\t\t\trequire.Empty(t, plugin.requests)\n\t\t})\n\t}\n}\n\nfunc TestRequestStartingWithOmits(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-2\",\n\t\t\t\t\tAddress:   uint16(2),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NotNil(t, modbus.requests[1])\n\trequire.Equal(t, uint16(0), modbus.requests[1].holding[0].address)\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\trequire.NoError(t, handler.Connect())\n\tdefer handler.Close()\n\tclient := mb.NewClient(handler)\n\t_, err := client.WriteMultipleRegisters(uint16(0), 3, []byte{0x00, 0x01, 0x00, 0x02, 0x00, 0x03})\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.Requests[0].SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\tmap[string]interface{}{\"holding-2\": int16(3)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRequestWithOmittedFieldsOnly(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-2\",\n\t\t\t\t\tAddress:   uint16(2),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, modbus.Init())\n\trequire.Empty(t, modbus.requests)\n}\n\nfunc TestRequestGroupWithOmittedFieldsOnly(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"UINT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-2\",\n\t\t\t\t\tAddress:   uint16(2),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t\tOmit:      true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-8\",\n\t\t\t\t\tAddress:   uint16(8),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, modbus.Init())\n\trequire.Len(t, modbus.requests, 1)\n\trequire.NotNil(t, modbus.requests[1])\n\trequire.Len(t, modbus.requests[1].holding, 1)\n\trequire.Equal(t, uint16(8), modbus.requests[1].holding[0].address)\n\trequire.Equal(t, uint16(1), modbus.requests[1].holding[0].length)\n}\n\nfunc TestRequestEmptyFields(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t},\n\t}\n\terr := modbus.Init()\n\trequire.ErrorContains(t, err, `found request section without fields`)\n}\n\nfunc TestRequestMultipleSlavesOneFail(t *testing.T) {\n\tmodbus := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tRetries:           1,\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t}\n\tmodbus.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      2,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tSlaveID:      3,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-0\",\n\t\t\t\t\tAddress:   uint16(0),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, modbus.Init())\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\tserv.RegisterFunctionHandler(3,\n\t\tfunc(_ *mbserver.Server, frame mbserver.Framer) ([]byte, *mbserver.Exception) {\n\t\t\ttcpframe, ok := frame.(*mbserver.TCPFrame)\n\t\t\tif !ok {\n\t\t\t\treturn nil, &mbserver.IllegalFunction\n\t\t\t}\n\n\t\t\tif tcpframe.Device == 2 {\n\t\t\t\t// Simulate device 2 being unavailable\n\t\t\t\treturn nil, &mbserver.GatewayTargetDeviceFailedtoRespond\n\t\t\t}\n\t\t\treturn []byte{0x02, 0x00, 0x42}, &mbserver.Success\n\t\t},\n\t)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\tmap[string]interface{}{\"holding-0\": int16(0x42)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cHoldingRegisters,\n\t\t\t\t\"slave_id\": \"3\",\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\tmap[string]interface{}{\"holding-0\": int16(0x42)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.FirstError(), `slave 2 on controller \"tcp://localhost:1502\": modbus: exception '11' (gateway target device failed to respond)`)\n}\n\nfunc TestRequestOptimizationShrink(t *testing.T) {\n\tmaxsize := maxQuantityHoldingRegisters\n\ttests := []struct {\n\t\tname     string\n\t\tinputs   []rangeDefinition\n\t\texpected []requestExpectation\n\t}{\n\t\t{\n\t\t\tname: \"no omit\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 2 * maxQuantityHoldingRegisters, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 0, count: maxsize, length: 1}},\n\t\t\t\t\treq:    request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize, count: maxsize, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize, length: maxsize},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"borders\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 1, 2, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize - 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t\t{start: maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize, count: 1, length: 1},\n\t\t\t\t\t\t{start: 2*maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize, length: maxsize},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"borders with gap\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 1, 2, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 1, 4, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize - 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t\t{start: maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize, length: 1},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2*maxsize - 1, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2*maxsize - 1, length: 1},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 18, count: 3, length: 1}},\n\t\t\t\t\treq:    request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize - 2, count: 5, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize - 2, length: 5},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize + 42, count: 2, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, 17, 1, 1, \"INT16\", true},\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t\t{start: 18, count: 3, length: 1},\n\t\t\t\t\t\t{start: maxsize - 2, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize, count: 3, length: 1},\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize, length: 44},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled with offset\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 18, count: 3, length: 1},\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 18, length: 110},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize + 42, count: 2, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"worst case\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, maxsize, 2, 1, \"INT16\", false},\n\t\t\t\t{1, maxsize, 2, 1, \"INT16\", true},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 0, count: maxsize/2 + 1, increment: 2, length: 1}},\n\t\t\t\t\treq:    request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize + 1, count: maxsize / 2, increment: 2, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize + 1, length: maxsize - 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"from PR #11106\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 2, 1, 1, \"INT16\", true},\n\t\t\t\t{2, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{3, 2*maxsize + 1, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize + 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2, length: 1},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2*maxsize + 1, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2*maxsize + 1, length: 1},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Generate the input structure and the expectation\n\t\t\trequestFields := generateRequestDefinitions(tt.inputs)\n\t\t\texpected := generateExpectation(tt.expected)\n\n\t\t\t// Setup the plugin\n\t\t\tslaveID := byte(1)\n\t\t\tplugin := Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tplugin.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      slaveID,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tOptimization: \"shrink\",\n\t\t\t\t\tFields:       requestFields,\n\t\t\t\t},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NotEmpty(t, plugin.requests)\n\t\t\trequire.Contains(t, plugin.requests, slaveID)\n\t\t\trequireEqualRequests(t, expected, plugin.requests[slaveID].holding)\n\t\t})\n\t}\n}\n\nfunc TestRequestOptimizationRearrange(t *testing.T) {\n\tmaxsize := maxQuantityHoldingRegisters\n\ttests := []struct {\n\t\tname     string\n\t\tinputs   []rangeDefinition\n\t\texpected []requestExpectation\n\t}{\n\t\t{\n\t\t\tname: \"no omit\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 2 * maxQuantityHoldingRegisters, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 0, count: maxsize, length: 1}},\n\t\t\t\t\treq:    request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize, count: maxsize, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize, length: maxsize},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"borders\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 1, 2, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize - 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t\t{start: maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: maxsize},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize, count: 1, length: 1},\n\t\t\t\t\t\t{start: 2*maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize, length: maxsize},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"borders with gap\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, maxsize - 2, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 1, 2, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 1, 4, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize - 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 0, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 0, length: 1},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 1, count: 1, length: 1},\n\t\t\t\t\t\t{start: maxsize, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 1, length: 2},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2*maxsize - 1, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2*maxsize - 1, length: 1},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 18, count: 3, length: 1}},\n\t\t\t\t\treq:    request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize - 2, count: 5, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize - 2, length: 5},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: maxsize + 42, count: 2, length: 1}},\n\t\t\t\t\treq:    request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, 17, 1, 1, \"INT16\", true},\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t\t{start: 18, count: 3, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: 21},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 2, length: 46},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled with offset\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 18, count: 3, length: 1}},\n\t\t\t\t\treq:    request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 2, length: 46},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"from PR #11106\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 2, 1, 1, \"INT16\", true},\n\t\t\t\t{2, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{3, 2*maxsize + 1, 1, 1, \"INT16\", true},\n\t\t\t\t{2*maxsize + 1, 1, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2, length: 1},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 2*maxsize + 1, count: 1, length: 1}},\n\t\t\t\t\treq:    request{address: 2*maxsize + 1, length: 1},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Generate the input structure and the expectation\n\t\t\trequestFields := generateRequestDefinitions(tt.inputs)\n\t\t\texpected := generateExpectation(tt.expected)\n\n\t\t\t// Setup the plugin\n\t\t\tslaveID := byte(1)\n\t\t\tplugin := Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tplugin.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:      slaveID,\n\t\t\t\t\tByteOrder:    \"ABCD\",\n\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\tOptimization: \"rearrange\",\n\t\t\t\t\tFields:       requestFields,\n\t\t\t\t},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NotEmpty(t, plugin.requests)\n\t\t\trequire.Contains(t, plugin.requests, slaveID)\n\t\t\trequireEqualRequests(t, expected, plugin.requests[slaveID].holding)\n\t\t})\n\t}\n}\n\nfunc TestRequestOptimizationMaxExtraRegisterFail(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\trequests []requestDefinition\n\t\terrormsg string\n\t}{{\n\t\tname: \"MaxExtraRegister too large\",\n\t\trequests: []requestDefinition{\n\t\t\t{\n\t\t\t\tSlaveID:           1,\n\t\t\t\tByteOrder:         \"ABCD\",\n\t\t\t\tRegisterType:      \"input\",\n\t\t\t\tOptimization:      \"max_insert\",\n\t\t\t\tMaxExtraRegisters: 5000,\n\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"input-0\",\n\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\terrormsg: \"optimization_max_register_fill has to be between 1 and 125\",\n\t},\n\t\t{\n\t\t\tname: \"MaxExtraRegister too small\",\n\t\t\trequests: []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:           1,\n\t\t\t\t\tByteOrder:         \"ABCD\",\n\t\t\t\t\tRegisterType:      \"input\",\n\t\t\t\t\tOptimization:      \"max_insert\",\n\t\t\t\t\tMaxExtraRegisters: 0,\n\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        \"input-0\",\n\t\t\t\t\t\t\tAddress:     uint16(0),\n\t\t\t\t\t\t\tMeasurement: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\terrormsg: \"optimization_max_register_fill has to be between 1 and 125\",\n\t\t}}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tplugin.Requests = tt.requests\n\n\t\t\trequire.ErrorContains(t, plugin.Init(), tt.errormsg)\n\t\t\trequire.Empty(t, plugin.requests)\n\t\t})\n\t}\n}\n\nfunc TestRequestOptimizationMaxInsertSmall(t *testing.T) {\n\tmaxsize := maxQuantityHoldingRegisters\n\tmaxExtraRegisters := uint16(5)\n\ttests := []struct {\n\t\tname     string\n\t\tinputs   []rangeDefinition\n\t\texpected []requestExpectation\n\t}{\n\t\t{\n\t\t\tname: \"large gaps\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 18, count: 3, length: 1}},\n\t\t\t\t\treq:    request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 2, length: 5},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{0, 1, 1, 1, \"INT16\", false},\n\t\t\t\t{1, 17, 1, 1, \"INT16\", true},\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 0, count: 1, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 0, length: 1},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: 18, count: 3, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 2, length: 5},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"large gaps filled with offset\",\n\t\t\tinputs: []rangeDefinition{\n\t\t\t\t{18, 3, 1, 1, \"INT16\", false},\n\t\t\t\t{21, maxsize - 23, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize - 2, 5, 1, 1, \"INT16\", false},\n\t\t\t\t{maxsize + 3, 39, 1, 1, \"INT16\", true},\n\t\t\t\t{maxsize + 42, 2, 1, 1, \"INT16\", false},\n\t\t\t},\n\t\t\texpected: []requestExpectation{\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{{start: 18, count: 3, length: 1}},\n\t\t\t\t\treq:    request{address: 18, length: 3},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize - 2, count: 5, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize - 2, length: 5},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfields: []rangeDefinition{\n\t\t\t\t\t\t{start: maxsize + 42, count: 2, length: 1},\n\t\t\t\t\t},\n\t\t\t\t\treq: request{address: maxsize + 42, length: 2},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Generate the input structure and the expectation\n\t\t\trequestFields := generateRequestDefinitions(tt.inputs)\n\t\t\texpected := generateExpectation(tt.expected)\n\n\t\t\t// Setup the plugin\n\t\t\tslaveID := byte(1)\n\t\t\tplugin := Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{},\n\t\t\t}\n\t\t\tplugin.Requests = []requestDefinition{\n\t\t\t\t{\n\t\t\t\t\tSlaveID:           slaveID,\n\t\t\t\t\tByteOrder:         \"ABCD\",\n\t\t\t\t\tRegisterType:      \"holding\",\n\t\t\t\t\tOptimization:      \"max_insert\",\n\t\t\t\t\tMaxExtraRegisters: maxExtraRegisters,\n\t\t\t\t\tFields:            requestFields,\n\t\t\t\t},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NotEmpty(t, plugin.requests)\n\t\t\trequire.Contains(t, plugin.requests, slaveID)\n\t\t\trequireEqualRequests(t, expected, plugin.requests[slaveID].holding)\n\t\t})\n\t}\n}\nfunc TestRequestWorkaroundsOneRequestPerField(t *testing.T) {\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t\tWorkarounds:       workarounds{OnRequestPerField: true},\n\t}\n\tplugin.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tByteOrder:    \"ABCD\",\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-1\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-2\",\n\t\t\t\t\tAddress:   uint16(2),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-3\",\n\t\t\t\t\tAddress:   uint16(3),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-4\",\n\t\t\t\t\tAddress:   uint16(4),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"holding-5\",\n\t\t\t\t\tAddress:   uint16(5),\n\t\t\t\t\tInputType: \"INT16\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.Len(t, plugin.requests[1].holding, len(plugin.Requests[0].Fields))\n}\n\nfunc TestRequestWorkaroundsReadCoilsStartingAtZeroRequest(t *testing.T) {\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{},\n\t\tWorkarounds:       workarounds{ReadCoilsStartingAtZero: true},\n\t}\n\tplugin.SlaveID = 1\n\tplugin.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tRegisterType: \"coil\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-8\",\n\t\t\t\t\tAddress: uint16(8),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"coil-new-group\",\n\t\t\t\t\tAddress: maxQuantityCoils,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.Len(t, plugin.requests[1].coil, 2)\n\n\t// First group should now start at zero and have the cumulated length\n\trequire.Equal(t, uint16(0), plugin.requests[1].coil[0].address)\n\trequire.Equal(t, uint16(9), plugin.requests[1].coil[0].length)\n\n\t// The second field should form a new group as the previous request\n\t// is now too large (beyond max-coils-per-read) after zero enforcement.\n\trequire.Equal(t, maxQuantityCoils, plugin.requests[1].coil[1].address)\n\trequire.Equal(t, uint16(1), plugin.requests[1].coil[1].length)\n}\n\nfunc TestRequestOverlap(t *testing.T) {\n\tlogger := &testutil.CaptureLogger{}\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               logger,\n\t\tWorkarounds:       workarounds{ReadCoilsStartingAtZero: true},\n\t}\n\tplugin.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:           1,\n\t\t\tRegisterType:      \"holding\",\n\t\t\tOptimization:      \"max_insert\",\n\t\t\tMaxExtraRegisters: 16,\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"field-1\",\n\t\t\t\t\tInputType: \"UINT32\",\n\t\t\t\t\tAddress:   uint16(1),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"field-2\",\n\t\t\t\t\tInputType: \"UINT64\",\n\t\t\t\t\tAddress:   uint16(3),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"field-3\",\n\t\t\t\t\tInputType: \"UINT32\",\n\t\t\t\t\tAddress:   uint16(5),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"field-4\",\n\t\t\t\t\tInputType: \"UINT32\",\n\t\t\t\t\tAddress:   uint16(7),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\trequire.Eventually(t, func() bool {\n\t\treturn len(logger.Warnings()) > 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tvar found bool\n\tfor _, w := range logger.Warnings() {\n\t\tif strings.Contains(w, \"Request at 3 with length 4 overlaps with next request at 5\") {\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.True(t, found, \"Overlap warning not found!\")\n\n\trequire.Len(t, plugin.requests, 1)\n\trequire.Len(t, plugin.requests[1].holding, 1)\n}\n\nfunc TestRequestAddressOverflow(t *testing.T) {\n\tlogger := &testutil.CaptureLogger{}\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               logger,\n\t\tWorkarounds:       workarounds{ReadCoilsStartingAtZero: true},\n\t}\n\tplugin.Requests = []requestDefinition{\n\t\t{\n\t\t\tSlaveID:      1,\n\t\t\tRegisterType: \"holding\",\n\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t{\n\t\t\t\t\tName:      \"field\",\n\t\t\t\t\tInputType: \"UINT64\",\n\t\t\t\t\tAddress:   uint16(65534),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.ErrorIs(t, plugin.Init(), errAddressOverflow)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/modbus.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage modbus\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tmb \"github.com/grid-x/modbus\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample_general_begin.conf\nvar sampleConfigStart string\n\n//go:embed sample_general_end.conf\nvar sampleConfigEnd string\n\nvar errAddressOverflow = errors.New(\"address overflow\")\n\nconst (\n\tcDiscreteInputs   = \"discrete_input\"\n\tcCoils            = \"coil\"\n\tcHoldingRegisters = \"holding_register\"\n\tcInputRegisters   = \"input_register\"\n)\n\ntype Modbus struct {\n\tName                   string          `toml:\"name\"`\n\tController             string          `toml:\"controller\"`\n\tTransmissionMode       string          `toml:\"transmission_mode\"`\n\tBaudRate               int             `toml:\"baud_rate\"`\n\tDataBits               int             `toml:\"data_bits\"`\n\tParity                 string          `toml:\"parity\"`\n\tStopBits               int             `toml:\"stop_bits\"`\n\tRS485                  *rs485Config    `toml:\"rs485\"`\n\tTimeout                config.Duration `toml:\"timeout\"`\n\tRetries                int             `toml:\"busy_retries\"`\n\tRetriesWaitTime        config.Duration `toml:\"busy_retries_wait\"`\n\tDebugConnection        bool            `toml:\"debug_connection\" deprecated:\"1.35.0;use 'log_level' 'trace' instead\"`\n\tWorkarounds            workarounds     `toml:\"workarounds\"`\n\tConfigurationType      string          `toml:\"configuration_type\"`\n\tExcludeRegisterTypeTag bool            `toml:\"exclude_register_type_tag\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\n\t// configuration type specific settings\n\tconfigurationOriginal\n\tconfigurationPerRequest\n\tconfigurationPerMetric\n\n\t// Connection handling\n\tclient      mb.Client\n\thandler     mb.ClientHandler\n\tisConnected bool\n\t// Request handling\n\trequests map[byte]requestSet\n}\n\ntype workarounds struct {\n\tAfterConnectPause       config.Duration `toml:\"pause_after_connect\"`\n\tPollPause               config.Duration `toml:\"pause_between_requests\"`\n\tCloseAfterGather        bool            `toml:\"close_connection_after_gather\"`\n\tOnRequestPerField       bool            `toml:\"one_request_per_field\"`\n\tReadCoilsStartingAtZero bool            `toml:\"read_coils_starting_at_zero\"`\n\tStringRegisterLocation  string          `toml:\"string_register_location\"`\n}\n\n// According to github.com/grid-x/serial\ntype rs485Config struct {\n\tDelayRtsBeforeSend config.Duration `toml:\"delay_rts_before_send\"`\n\tDelayRtsAfterSend  config.Duration `toml:\"delay_rts_after_send\"`\n\tRtsHighDuringSend  bool            `toml:\"rts_high_during_send\"`\n\tRtsHighAfterSend   bool            `toml:\"rts_high_after_send\"`\n\tRxDuringTx         bool            `toml:\"rx_during_tx\"`\n}\n\ntype fieldConverterFunc func(bytes []byte) interface{}\n\ntype requestSet struct {\n\tcoil     []request\n\tdiscrete []request\n\tholding  []request\n\tinput    []request\n}\n\nfunc (r requestSet) empty() bool {\n\tl := len(r.coil)\n\tl += len(r.discrete)\n\tl += len(r.holding)\n\tl += len(r.input)\n\treturn l == 0\n}\n\ntype field struct {\n\tmeasurement string\n\tname        string\n\taddress     uint16\n\tlength      uint16\n\tomit        bool\n\tconverter   fieldConverterFunc\n\tvalue       interface{}\n\ttags        map[string]string\n}\n\nfunc (m *Modbus) SampleConfig() string {\n\tconfigs := []configuration{\n\t\t&m.configurationOriginal,\n\t\t&m.configurationPerRequest,\n\t\t&m.configurationPerMetric,\n\t}\n\n\tvar b strings.Builder\n\tb.WriteString(sampleConfigStart)\n\tfor _, c := range configs {\n\t\tb.WriteString(c.sampleConfigPart())\n\t\tb.WriteString(\"\\n\")\n\t}\n\tb.WriteString(\"\\n\")\n\tb.WriteString(sampleConfigEnd)\n\treturn b.String()\n}\n\nfunc (m *Modbus) Init() error {\n\t// check device name\n\tif m.Name == \"\" {\n\t\treturn errors.New(\"device name is empty\")\n\t}\n\n\tif m.Retries < 0 {\n\t\treturn fmt.Errorf(\"retries cannot be negative in device %q\", m.Name)\n\t}\n\n\t// Determine the configuration style\n\tvar cfg configuration\n\tswitch m.ConfigurationType {\n\tcase \"\", \"register\":\n\t\tm.configurationOriginal.workarounds = m.Workarounds\n\t\tm.configurationOriginal.logger = m.Log\n\t\tcfg = &m.configurationOriginal\n\tcase \"request\":\n\t\tm.configurationPerRequest.workarounds = m.Workarounds\n\t\tm.configurationPerRequest.excludeRegisterType = m.ExcludeRegisterTypeTag\n\t\tm.configurationPerRequest.logger = m.Log\n\t\tcfg = &m.configurationPerRequest\n\tcase \"metric\":\n\t\tm.configurationPerMetric.workarounds = m.Workarounds\n\t\tm.configurationPerMetric.excludeRegisterType = m.ExcludeRegisterTypeTag\n\t\tm.configurationPerMetric.logger = m.Log\n\t\tcfg = &m.configurationPerMetric\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown configuration type %q in device %q\", m.ConfigurationType, m.Name)\n\t}\n\n\t// Check and process the configuration\n\tif err := cfg.check(); err != nil {\n\t\treturn fmt.Errorf(\"configuration invalid for device %q: %w\", m.Name, err)\n\t}\n\n\tr, err := cfg.process()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot process configuration for device %q: %w\", m.Name, err)\n\t}\n\tm.requests = r\n\n\t// Setup client\n\tif err := m.initClient(); err != nil {\n\t\treturn fmt.Errorf(\"initializing client failed for controller %q: %w\", m.Controller, err)\n\t}\n\tfor slaveID, rqs := range m.requests {\n\t\tvar nHoldingRegs, nInputsRegs, nDiscreteRegs, nCoilRegs uint16\n\t\tvar nHoldingFields, nInputsFields, nDiscreteFields, nCoilFields int\n\n\t\tfor _, r := range rqs.holding {\n\t\t\tnHoldingRegs += r.length\n\t\t\tnHoldingFields += len(r.fields)\n\t\t}\n\t\tfor _, r := range rqs.input {\n\t\t\tnInputsRegs += r.length\n\t\t\tnInputsFields += len(r.fields)\n\t\t}\n\t\tfor _, r := range rqs.discrete {\n\t\t\tnDiscreteRegs += r.length\n\t\t\tnDiscreteFields += len(r.fields)\n\t\t}\n\t\tfor _, r := range rqs.coil {\n\t\t\tnCoilRegs += r.length\n\t\t\tnCoilFields += len(r.fields)\n\t\t}\n\t\tm.Log.Infof(\"Got %d request(s) touching %d holding registers for %d fields (slave %d) on device %q\",\n\t\t\tlen(rqs.holding), nHoldingRegs, nHoldingFields, slaveID, m.Name)\n\t\tfor i, r := range rqs.holding {\n\t\t\tm.Log.Debugf(\"    #%d: @%d with length %d\", i+1, r.address, r.length)\n\t\t}\n\t\tm.Log.Infof(\"Got %d request(s) touching %d inputs registers for %d fields (slave %d) on device %q\",\n\t\t\tlen(rqs.input), nInputsRegs, nInputsFields, slaveID, m.Name)\n\t\tfor i, r := range rqs.input {\n\t\t\tm.Log.Debugf(\"    #%d: @%d with length %d\", i+1, r.address, r.length)\n\t\t}\n\t\tm.Log.Infof(\"Got %d request(s) touching %d discrete registers for %d fields (slave %d) on device %q\",\n\t\t\tlen(rqs.discrete), nDiscreteRegs, nDiscreteFields, slaveID, m.Name)\n\t\tfor i, r := range rqs.discrete {\n\t\t\tm.Log.Debugf(\"    #%d: @%d with length %d\", i+1, r.address, r.length)\n\t\t}\n\t\tm.Log.Infof(\"Got %d request(s) touching %d coil registers for %d fields (slave %d) on device %q\",\n\t\t\tlen(rqs.coil), nCoilRegs, nCoilFields, slaveID, m.Name)\n\t\tfor i, r := range rqs.coil {\n\t\t\tm.Log.Debugf(\"    #%d: @%d with length %d\", i+1, r.address, r.length)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *Modbus) Gather(acc telegraf.Accumulator) error {\n\tif !m.isConnected {\n\t\tif err := m.connect(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor slaveID, requests := range m.requests {\n\t\tm.Log.Debugf(\"Reading slave %d for %s...\", slaveID, m.Controller)\n\t\tif err := m.readSlaveData(slaveID, requests); err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"slave %d on controller %q: %w\", slaveID, m.Controller, err))\n\t\t\tvar mbErr *mb.Error\n\t\t\tif !errors.As(err, &mbErr) || mbErr.ExceptionCode != mb.ExceptionCodeServerDeviceBusy {\n\t\t\t\tm.Log.Debugf(\"Reconnecting to %s...\", m.Controller)\n\t\t\t\tif err := m.disconnect(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"disconnecting failed for controller %q: %w\", m.Controller, err)\n\t\t\t\t}\n\t\t\t\tif err := m.connect(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"slave %d on controller %q: connecting failed: %w\", slaveID, m.Controller, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\ttimestamp := time.Now()\n\n\t\tgrouper := metric.NewSeriesGrouper()\n\t\ttags := map[string]string{\n\t\t\t\"name\":     m.Name,\n\t\t\t\"slave_id\": strconv.Itoa(int(slaveID)),\n\t\t}\n\n\t\tif !m.ExcludeRegisterTypeTag {\n\t\t\ttags[\"type\"] = cCoils\n\t\t}\n\t\tcollectFields(grouper, timestamp, tags, requests.coil)\n\n\t\tif !m.ExcludeRegisterTypeTag {\n\t\t\ttags[\"type\"] = cDiscreteInputs\n\t\t}\n\t\tcollectFields(grouper, timestamp, tags, requests.discrete)\n\n\t\tif !m.ExcludeRegisterTypeTag {\n\t\t\ttags[\"type\"] = cHoldingRegisters\n\t\t}\n\t\tcollectFields(grouper, timestamp, tags, requests.holding)\n\n\t\tif !m.ExcludeRegisterTypeTag {\n\t\t\ttags[\"type\"] = cInputRegisters\n\t\t}\n\t\tcollectFields(grouper, timestamp, tags, requests.input)\n\n\t\t// Add the metrics grouped by series to the accumulator\n\t\tfor _, x := range grouper.Metrics() {\n\t\t\tacc.AddMetric(x)\n\t\t}\n\t}\n\n\t// Disconnect after read if configured\n\tif m.Workarounds.CloseAfterGather {\n\t\treturn m.disconnect()\n\t}\n\n\treturn nil\n}\n\nfunc (m *Modbus) initClient() error {\n\tu, err := url.Parse(m.Controller)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar tracelog mb.Logger\n\tif m.Log.Level().Includes(telegraf.Trace) || m.DebugConnection { // for backward compatibility\n\t\ttracelog = m\n\t}\n\n\tswitch u.Scheme {\n\tcase \"tcp\":\n\t\thost, port, err := net.SplitHostPort(u.Host)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch m.TransmissionMode {\n\t\tcase \"\", \"auto\", \"TCP\":\n\t\t\thandler := mb.NewTCPClientHandler(host + \":\" + port)\n\t\t\thandler.Timeout = time.Duration(m.Timeout)\n\t\t\thandler.Logger = tracelog\n\t\t\tm.handler = handler\n\t\tcase \"RTUoverTCP\":\n\t\t\thandler := mb.NewRTUOverTCPClientHandler(host + \":\" + port)\n\t\t\thandler.Timeout = time.Duration(m.Timeout)\n\t\t\thandler.Logger = tracelog\n\t\t\tm.handler = handler\n\t\tcase \"ASCIIoverTCP\":\n\t\t\thandler := mb.NewASCIIOverTCPClientHandler(host + \":\" + port)\n\t\t\thandler.Timeout = time.Duration(m.Timeout)\n\t\t\thandler.Logger = tracelog\n\t\t\tm.handler = handler\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid transmission mode %q for %q on device %q\", m.TransmissionMode, u.Scheme, m.Name)\n\t\t}\n\tcase \"\", \"file\":\n\t\tpath := filepath.Join(u.Host, u.Path)\n\t\tif path == \"\" {\n\t\t\treturn fmt.Errorf(\"invalid path for controller %q\", m.Controller)\n\t\t}\n\t\tswitch m.TransmissionMode {\n\t\tcase \"\", \"auto\", \"RTU\":\n\t\t\thandler := mb.NewRTUClientHandler(path)\n\t\t\thandler.Timeout = time.Duration(m.Timeout)\n\t\t\thandler.BaudRate = m.BaudRate\n\t\t\thandler.DataBits = m.DataBits\n\t\t\thandler.Parity = m.Parity\n\t\t\thandler.StopBits = m.StopBits\n\t\t\thandler.Logger = tracelog\n\t\t\tif m.RS485 != nil {\n\t\t\t\thandler.RS485.Enabled = true\n\t\t\t\thandler.RS485.DelayRtsBeforeSend = time.Duration(m.RS485.DelayRtsBeforeSend)\n\t\t\t\thandler.RS485.DelayRtsAfterSend = time.Duration(m.RS485.DelayRtsAfterSend)\n\t\t\t\thandler.RS485.RtsHighDuringSend = m.RS485.RtsHighDuringSend\n\t\t\t\thandler.RS485.RtsHighAfterSend = m.RS485.RtsHighAfterSend\n\t\t\t\thandler.RS485.RxDuringTx = m.RS485.RxDuringTx\n\t\t\t}\n\t\t\tm.handler = handler\n\t\tcase \"ASCII\":\n\t\t\thandler := mb.NewASCIIClientHandler(path)\n\t\t\thandler.Timeout = time.Duration(m.Timeout)\n\t\t\thandler.BaudRate = m.BaudRate\n\t\t\thandler.DataBits = m.DataBits\n\t\t\thandler.Parity = m.Parity\n\t\t\thandler.StopBits = m.StopBits\n\t\t\thandler.Logger = tracelog\n\t\t\tif m.RS485 != nil {\n\t\t\t\thandler.RS485.Enabled = true\n\t\t\t\thandler.RS485.DelayRtsBeforeSend = time.Duration(m.RS485.DelayRtsBeforeSend)\n\t\t\t\thandler.RS485.DelayRtsAfterSend = time.Duration(m.RS485.DelayRtsAfterSend)\n\t\t\t\thandler.RS485.RtsHighDuringSend = m.RS485.RtsHighDuringSend\n\t\t\t\thandler.RS485.RtsHighAfterSend = m.RS485.RtsHighAfterSend\n\t\t\t\thandler.RS485.RxDuringTx = m.RS485.RxDuringTx\n\t\t\t}\n\t\t\tm.handler = handler\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid transmission mode %q for %q on device %q\", m.TransmissionMode, u.Scheme, m.Name)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid controller %q\", m.Controller)\n\t}\n\n\tm.client = mb.NewClient(m.handler)\n\tm.isConnected = false\n\n\treturn nil\n}\n\n// Connect to a MODBUS Slave device via Modbus/[TCP|RTU|ASCII]\nfunc (m *Modbus) connect() error {\n\terr := m.handler.Connect()\n\tm.isConnected = err == nil\n\tif m.isConnected && m.Workarounds.AfterConnectPause != 0 {\n\t\tnextRequest := time.Now().Add(time.Duration(m.Workarounds.AfterConnectPause))\n\t\ttime.Sleep(time.Until(nextRequest))\n\t}\n\treturn err\n}\n\nfunc (m *Modbus) disconnect() error {\n\terr := m.handler.Close()\n\tm.isConnected = false\n\treturn err\n}\n\nfunc (m *Modbus) readSlaveData(slaveID byte, requests requestSet) error {\n\tm.handler.SetSlave(slaveID)\n\n\tfor retry := 0; retry < m.Retries; retry++ {\n\t\terr := m.gatherFields(requests)\n\t\tif err == nil {\n\t\t\t// Reading was successful\n\t\t\treturn nil\n\t\t}\n\n\t\t// Exit in case a non-recoverable error occurred\n\t\tvar mbErr *mb.Error\n\t\tif !errors.As(err, &mbErr) || mbErr.ExceptionCode != mb.ExceptionCodeServerDeviceBusy {\n\t\t\treturn err\n\t\t}\n\n\t\t// Wait some time and try again reading the slave.\n\t\tm.Log.Infof(\"Device busy! Retrying %d more time(s) on controller %q...\", m.Retries-retry, m.Controller)\n\t\ttime.Sleep(time.Duration(m.RetriesWaitTime))\n\t}\n\treturn m.gatherFields(requests)\n}\n\nfunc (m *Modbus) gatherFields(requests requestSet) error {\n\tif err := m.gatherRequestsCoil(requests.coil); err != nil {\n\t\treturn err\n\t}\n\tif err := m.gatherRequestsDiscrete(requests.discrete); err != nil {\n\t\treturn err\n\t}\n\tif err := m.gatherRequestsHolding(requests.holding); err != nil {\n\t\treturn err\n\t}\n\treturn m.gatherRequestsInput(requests.input)\n}\n\nfunc (m *Modbus) gatherRequestsCoil(requests []request) error {\n\tfor _, request := range requests {\n\t\tm.Log.Debugf(\"trying to read coil@%v[%v]...\", request.address, request.length)\n\t\tbytes, err := m.client.ReadCoils(request.address, request.length)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnextRequest := time.Now().Add(time.Duration(m.Workarounds.PollPause))\n\t\tm.Log.Debugf(\"got coil@%v[%v]: %v\", request.address, request.length, bytes)\n\n\t\t// Bit value handling\n\t\tfor i, field := range request.fields {\n\t\t\toffset := field.address - request.address\n\t\t\tidx := offset / 8\n\t\t\tbit := offset % 8\n\n\t\t\tv := (bytes[idx] >> bit) & 0x01\n\t\t\trequest.fields[i].value = field.converter([]byte{v})\n\t\t\tm.Log.Debugf(\"  field %s with bit %d @ byte %d: %v --> %v\", field.name, bit, idx, v, request.fields[i].value)\n\t\t}\n\n\t\t// Some (serial) devices require a pause between requests...\n\t\ttime.Sleep(time.Until(nextRequest))\n\t}\n\treturn nil\n}\n\nfunc (m *Modbus) gatherRequestsDiscrete(requests []request) error {\n\tfor _, request := range requests {\n\t\tm.Log.Debugf(\"trying to read discrete@%v[%v]...\", request.address, request.length)\n\t\tbytes, err := m.client.ReadDiscreteInputs(request.address, request.length)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnextRequest := time.Now().Add(time.Duration(m.Workarounds.PollPause))\n\t\tm.Log.Debugf(\"got discrete@%v[%v]: %v\", request.address, request.length, bytes)\n\n\t\t// Bit value handling\n\t\tfor i, field := range request.fields {\n\t\t\toffset := field.address - request.address\n\t\t\tidx := offset / 8\n\t\t\tbit := offset % 8\n\n\t\t\tv := (bytes[idx] >> bit) & 0x01\n\t\t\trequest.fields[i].value = field.converter([]byte{v})\n\t\t\tm.Log.Debugf(\"  field %s with bit %d @ byte %d: %v --> %v\", field.name, bit, idx, v, request.fields[i].value)\n\t\t}\n\n\t\t// Some (serial) devices require a pause between requests...\n\t\ttime.Sleep(time.Until(nextRequest))\n\t}\n\treturn nil\n}\n\nfunc (m *Modbus) gatherRequestsHolding(requests []request) error {\n\tfor _, request := range requests {\n\t\tm.Log.Debugf(\"trying to read holding@%v[%v]...\", request.address, request.length)\n\t\tbytes, err := m.client.ReadHoldingRegisters(request.address, request.length)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnextRequest := time.Now().Add(time.Duration(m.Workarounds.PollPause))\n\t\tm.Log.Debugf(\"got holding@%v[%v]: %v\", request.address, request.length, bytes)\n\n\t\t// Non-bit value handling\n\t\tfor i, field := range request.fields {\n\t\t\t// Determine the offset of the field values in the read array\n\t\t\toffset := 2 * uint32(field.address-request.address) // registers are 16bit = 2 byte\n\t\t\tlength := 2 * uint32(field.length)                  // field length is in registers a 16bit\n\n\t\t\t// Convert the actual value\n\t\t\trequest.fields[i].value = field.converter(bytes[offset : offset+length])\n\t\t\tm.Log.Debugf(\"  field %s with offset %d with len %d: %v --> %v\", field.name, offset, length, bytes[offset:offset+length], request.fields[i].value)\n\t\t}\n\n\t\t// Some (serial) devices require a pause between requests...\n\t\ttime.Sleep(time.Until(nextRequest))\n\t}\n\treturn nil\n}\n\nfunc (m *Modbus) gatherRequestsInput(requests []request) error {\n\tfor _, request := range requests {\n\t\tm.Log.Debugf(\"trying to read input@%v[%v]...\", request.address, request.length)\n\t\tbytes, err := m.client.ReadInputRegisters(request.address, request.length)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnextRequest := time.Now().Add(time.Duration(m.Workarounds.PollPause))\n\t\tm.Log.Debugf(\"got input@%v[%v]: %v\", request.address, request.length, bytes)\n\n\t\t// Non-bit value handling\n\t\tfor i, field := range request.fields {\n\t\t\t// Determine the offset of the field values in the read array\n\t\t\toffset := 2 * uint32(field.address-request.address) // registers are 16bit = 2 byte\n\t\t\tlength := 2 * uint32(field.length)                  // field length is in registers a 16bit\n\n\t\t\t// Convert the actual value\n\t\t\trequest.fields[i].value = field.converter(bytes[offset : offset+length])\n\t\t\tm.Log.Debugf(\"  field %s with offset %d with len %d: %v --> %v\", field.name, offset, length, bytes[offset:offset+length], request.fields[i].value)\n\t\t}\n\n\t\t// Some (serial) devices require a pause between requests...\n\t\ttime.Sleep(time.Until(nextRequest))\n\t}\n\treturn nil\n}\n\nfunc collectFields(grouper *metric.SeriesGrouper, timestamp time.Time, tags map[string]string, requests []request) {\n\tfor _, request := range requests {\n\t\tfor _, field := range request.fields {\n\t\t\t// Collect tags from global and per-request\n\t\t\tftags := make(map[string]string, len(tags)+len(field.tags))\n\t\t\tfor k, v := range tags {\n\t\t\t\tftags[k] = v\n\t\t\t}\n\t\t\tfor k, v := range field.tags {\n\t\t\t\tftags[k] = v\n\t\t\t}\n\t\t\t// In case no measurement was specified we use \"modbus\" as default\n\t\t\tmeasurement := \"modbus\"\n\t\t\tif field.measurement != \"\" {\n\t\t\t\tmeasurement = field.measurement\n\t\t\t}\n\n\t\t\t// Group the data by series\n\t\t\tgrouper.Add(measurement, ftags, timestamp, field.name, field.value)\n\t\t}\n\t}\n}\n\n// Printf implements the logger interface of the modbus client\nfunc (m *Modbus) Printf(format string, v ...interface{}) {\n\tm.Log.Tracef(format, v...)\n}\n\n// Add this plugin to telegraf\nfunc init() {\n\tinputs.Add(\"modbus\", func() telegraf.Input { return &Modbus{} })\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/modbus_test.go",
    "content": "package modbus\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\tmb \"github.com/grid-x/modbus\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tbrandon/mbserver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestControllers(t *testing.T) {\n\tvar tests = []struct {\n\t\tname       string\n\t\tcontroller string\n\t\tmode       string\n\t\terrmsg     string\n\t}{\n\t\t{\n\t\t\tname:       \"TCP host\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP mode auto\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"auto\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP mode TCP\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"TCP\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP mode RTUoverTCP\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"RTUoverTCP\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP mode ASCIIoverTCP\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"ASCIIoverTCP\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP invalid host\",\n\t\t\tcontroller: \"tcp://localhost\",\n\t\t\terrmsg:     \"address localhost: missing port in address\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP invalid mode RTU\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"RTU\",\n\t\t\terrmsg:     \"invalid transmission mode\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP invalid mode ASCII\",\n\t\t\tcontroller: \"tcp://localhost:502\",\n\t\t\tmode:       \"ASCII\",\n\t\t\terrmsg:     \"invalid transmission mode\",\n\t\t},\n\t\t{\n\t\t\tname:       \"absolute file path\",\n\t\t\tcontroller: \"file:///dev/ttyUSB0\",\n\t\t},\n\t\t{\n\t\t\tname:       \"relative file path\",\n\t\t\tcontroller: \"file://dev/ttyUSB0\",\n\t\t},\n\t\t{\n\t\t\tname:       \"relative file path with dot\",\n\t\t\tcontroller: \"file://./dev/ttyUSB0\",\n\t\t},\n\t\t{\n\t\t\tname:       \"Windows COM-port\",\n\t\t\tcontroller: \"COM2\",\n\t\t},\n\t\t{\n\t\t\tname:       \"Windows COM-port file path\",\n\t\t\tcontroller: \"file://com2\",\n\t\t},\n\t\t{\n\t\t\tname:       \"serial mode auto\",\n\t\t\tcontroller: \"file:///dev/ttyUSB0\",\n\t\t\tmode:       \"auto\",\n\t\t},\n\t\t{\n\t\t\tname:       \"serial mode RTU\",\n\t\t\tcontroller: \"file:///dev/ttyUSB0\",\n\t\t\tmode:       \"RTU\",\n\t\t},\n\t\t{\n\t\t\tname:       \"serial mode ASCII\",\n\t\t\tcontroller: \"file:///dev/ttyUSB0\",\n\t\t\tmode:       \"ASCII\",\n\t\t},\n\t\t{\n\t\t\tname:       \"empty file path\",\n\t\t\tcontroller: \"file://\",\n\t\t\terrmsg:     \"invalid path for controller\",\n\t\t},\n\t\t{\n\t\t\tname:       \"empty controller\",\n\t\t\tcontroller: \"\",\n\t\t\terrmsg:     \"invalid path for controller\",\n\t\t},\n\t\t{\n\t\t\tname:       \"invalid scheme\",\n\t\t\tcontroller: \"foo://bar\",\n\t\t\terrmsg:     \"invalid controller\",\n\t\t},\n\t\t{\n\t\t\tname:       \"serial invalid mode TCP\",\n\t\t\tcontroller: \"file:///dev/ttyUSB0\",\n\t\t\tmode:       \"TCP\",\n\t\t\terrmsg:     \"invalid transmission mode\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Modbus{\n\t\t\t\tName:             \"dummy\",\n\t\t\t\tController:       tt.controller,\n\t\t\t\tTransmissionMode: tt.mode,\n\t\t\t\tLog:              testutil.Logger{Quiet: true},\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRetrySuccessful(t *testing.T) {\n\tretries := 0\n\tmaxretries := 2\n\tvalue := 1\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\t// Make read on coil-registers fail for some trials by making the device to appear busy\n\tserv.RegisterFunctionHandler(1,\n\t\tfunc(*mbserver.Server, mbserver.Framer) ([]byte, *mbserver.Exception) {\n\t\t\tdata := make([]byte, 2)\n\t\t\tdata[0] = byte(1)\n\t\t\tdata[1] = byte(value)\n\n\t\t\texcept := &mbserver.SlaveDeviceBusy\n\t\t\tif retries >= maxretries {\n\t\t\t\texcept = &mbserver.Success\n\t\t\t}\n\t\t\tretries++\n\n\t\t\treturn data, except\n\t\t})\n\n\tmodbus := Modbus{\n\t\tName:       \"TestRetry\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tRetries:    maxretries,\n\t\tLog:        testutil.Logger{Quiet: true},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"retry_success\",\n\t\t\tAddress: []uint16{0},\n\t\t},\n\t}\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"modbus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"type\":     cCoils,\n\t\t\t\t\"slave_id\": strconv.Itoa(int(modbus.SlaveID)),\n\t\t\t\t\"name\":     modbus.Name,\n\t\t\t},\n\t\t\tmap[string]interface{}{\"retry_success\": uint16(value)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\trequire.NoError(t, modbus.Gather(&acc))\n\tacc.Wait(len(expected))\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestRetryFailExhausted(t *testing.T) {\n\tmaxretries := 2\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\t// Make the read on coils fail with busy\n\tserv.RegisterFunctionHandler(1,\n\t\tfunc(*mbserver.Server, mbserver.Framer) ([]byte, *mbserver.Exception) {\n\t\t\tdata := make([]byte, 2)\n\t\t\tdata[0] = byte(1)\n\t\t\tdata[1] = byte(0)\n\n\t\t\treturn data, &mbserver.SlaveDeviceBusy\n\t\t})\n\n\tmodbus := Modbus{\n\t\tName:       \"TestRetryFailExhausted\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tRetries:    maxretries,\n\t\tLog:        testutil.Logger{Quiet: true},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"retry_fail\",\n\t\t\tAddress: []uint16{0},\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\n\trequire.NoError(t, modbus.Gather(&acc))\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.FirstError(), `slave 1 on controller \"tcp://localhost:1502\": modbus: exception '6' (server device busy)`)\n}\n\nfunc TestRetryFailIllegal(t *testing.T) {\n\tmaxretries := 2\n\n\tserv := mbserver.NewServer()\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\t// Make the read on coils fail with illegal function preventing retry\n\tcounter := 0\n\tserv.RegisterFunctionHandler(1,\n\t\tfunc(*mbserver.Server, mbserver.Framer) ([]byte, *mbserver.Exception) {\n\t\t\tcounter++\n\t\t\tdata := make([]byte, 2)\n\t\t\tdata[0] = byte(1)\n\t\t\tdata[1] = byte(0)\n\n\t\t\treturn data, &mbserver.IllegalFunction\n\t\t},\n\t)\n\n\tmodbus := Modbus{\n\t\tName:       \"TestRetryFailExhausted\",\n\t\tController: \"tcp://localhost:1502\",\n\t\tRetries:    maxretries,\n\t\tLog:        testutil.Logger{Quiet: true},\n\t}\n\tmodbus.SlaveID = 1\n\tmodbus.Coils = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"retry_fail\",\n\t\t\tAddress: []uint16{0},\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, modbus.Init())\n\trequire.NotEmpty(t, modbus.requests)\n\n\trequire.NoError(t, modbus.Gather(&acc))\n\trequire.Len(t, acc.Errors, 1)\n\trequire.ErrorContains(t, acc.FirstError(), `slave 1 on controller \"tcp://localhost:1502\": modbus: exception '1' (illegal function)`)\n\trequire.Equal(t, 1, counter)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\t// Compare options\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.SortMetrics(),\n\t}\n\n\t// Register the plugin\n\tinputs.Add(\"modbus\", func() telegraf.Input { return &Modbus{} })\n\n\t// Define a function to return the register value as data\n\treadFunc := func(_ *mbserver.Server, frame mbserver.Framer) ([]byte, *mbserver.Exception) {\n\t\tdata := frame.GetData()\n\t\tregister := binary.BigEndian.Uint16(data[0:2])\n\t\tnumRegs := binary.BigEndian.Uint16(data[2:4])\n\n\t\t// Add the length in bytes and the register to the returned data\n\t\tbuf := make([]byte, 2*numRegs+1)\n\t\tbuf[0] = byte(2 * numRegs)\n\t\tswitch numRegs {\n\t\tcase 1: // 16-bit\n\t\t\tbinary.BigEndian.PutUint16(buf[1:], register)\n\t\tcase 2: // 32-bit\n\t\t\tbinary.BigEndian.PutUint32(buf[1:], uint32(register))\n\t\tcase 4: // 64-bit\n\t\t\tbinary.BigEndian.PutUint64(buf[1:], uint64(register))\n\t\t}\n\t\treturn buf, &mbserver.Success\n\t}\n\n\t// Setup a Modbus server to test against\n\tserv := mbserver.NewServer()\n\tserv.RegisterFunctionHandler(mb.FuncCodeReadInputRegisters, readFunc)\n\tserv.RegisterFunctionHandler(mb.FuncCodeReadHoldingRegisters, readFunc)\n\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\tdefer serv.Close()\n\n\t// Run the test cases\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedOutputFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\t\tinitErrorFilename := filepath.Join(testcasePath, \"init.err\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the expected error for the init call if any\n\t\t\tvar expectedInitError string\n\t\t\tif _, err := os.Stat(initErrorFilename); err == nil {\n\t\t\t\te, err := testutil.ParseLinesFromFile(initErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, e, 1)\n\t\t\t\texpectedInitError = e[0]\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedOutputFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedOutputFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected error if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\te, err := testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, e)\n\t\t\t\texpectedErrors = e\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Extract the plugin and make sure it connects to our dummy\n\t\t\t// server\n\t\t\tplugin := cfg.Inputs[0].Input.(*Modbus)\n\t\t\tplugin.Controller = \"tcp://localhost:1502\"\n\n\t\t\t// Init the plugin.\n\t\t\terr := plugin.Init()\n\t\t\tif expectedInitError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, expectedInitError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Gather data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tactualErrorMsgs := make([]string, 0, len(acc.Errors))\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\t\t\t}\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\ntype rangeDefinition struct {\n\tstart     uint16\n\tcount     uint16\n\tincrement uint16\n\tlength    uint16\n\tdtype     string\n\tomit      bool\n}\n\ntype requestExpectation struct {\n\tfields []rangeDefinition\n\treq    request\n}\n\nfunc generateRequestDefinitions(ranges []rangeDefinition) []requestFieldDefinition {\n\tvar fields []requestFieldDefinition\n\n\tid := 0\n\tfor _, r := range ranges {\n\t\tif r.increment == 0 {\n\t\t\tr.increment = r.length\n\t\t}\n\t\tfor i := uint16(0); i < r.count; i++ {\n\t\t\tf := requestFieldDefinition{\n\t\t\t\tName:      fmt.Sprintf(\"holding-%d\", id),\n\t\t\t\tAddress:   r.start + i*r.increment,\n\t\t\t\tInputType: r.dtype,\n\t\t\t\tOmit:      r.omit,\n\t\t\t}\n\t\t\tfields = append(fields, f)\n\t\t\tid++\n\t\t}\n\t}\n\treturn fields\n}\n\nfunc generateExpectation(defs []requestExpectation) []request {\n\trequests := make([]request, 0, len(defs))\n\tfor _, def := range defs {\n\t\tr := def.req\n\t\tr.fields = make([]field, 0)\n\t\tfor _, d := range def.fields {\n\t\t\tif d.increment == 0 {\n\t\t\t\td.increment = d.length\n\t\t\t}\n\t\t\tfor i := uint16(0); i < d.count; i++ {\n\t\t\t\tf := field{\n\t\t\t\t\taddress: d.start + i*d.increment,\n\t\t\t\t\tlength:  d.length,\n\t\t\t\t}\n\t\t\t\tr.fields = append(r.fields, f)\n\t\t\t}\n\t\t}\n\t\trequests = append(requests, r)\n\t}\n\treturn requests\n}\n\nfunc requireEqualRequests(t *testing.T, expected, actual []request) {\n\trequire.Len(t, actual, len(expected), \"request size mismatch\")\n\n\tfor i, e := range expected {\n\t\ta := actual[i]\n\t\trequire.Equalf(t, e.address, a.address, \"address mismatch in request %d\", i)\n\t\trequire.Equalf(t, e.length, a.length, \"length mismatch in request %d\", i)\n\t\trequire.Lenf(t, a.fields, len(e.fields), \"no. fields mismatch in request %d\", i)\n\t\tfor j, ef := range e.fields {\n\t\t\taf := a.fields[j]\n\t\t\trequire.Equalf(t, ef.address, af.address, \"address mismatch in field %d of request %d\", j, i)\n\t\t\trequire.Equalf(t, ef.length, af.length, \"length mismatch in field %d of request %d\", j, i)\n\t\t}\n\t}\n}\n\nfunc TestRegisterWorkaroundsOneRequestPerField(t *testing.T) {\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"register\",\n\t\tLog:               testutil.Logger{Quiet: true},\n\t\tWorkarounds:       workarounds{OnRequestPerField: true},\n\t}\n\tplugin.SlaveID = 1\n\tplugin.HoldingRegisters = []fieldDefinition{\n\t\t{\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tName:      \"holding-1\",\n\t\t\tAddress:   []uint16{1},\n\t\t\tScale:     1.0,\n\t\t},\n\t\t{\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tName:      \"holding-2\",\n\t\t\tAddress:   []uint16{2},\n\t\t\tScale:     1.0,\n\t\t},\n\t\t{\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tName:      \"holding-3\",\n\t\t\tAddress:   []uint16{3},\n\t\t\tScale:     1.0,\n\t\t},\n\t\t{\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tName:      \"holding-4\",\n\t\t\tAddress:   []uint16{4},\n\t\t\tScale:     1.0,\n\t\t},\n\t\t{\n\t\t\tByteOrder: \"AB\",\n\t\t\tDataType:  \"INT16\",\n\t\t\tName:      \"holding-5\",\n\t\t\tAddress:   []uint16{5},\n\t\t\tScale:     1.0,\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.Len(t, plugin.requests[1].holding, len(plugin.HoldingRegisters))\n}\n\nfunc TestRequestsWorkaroundsReadCoilsStartingAtZeroRegister(t *testing.T) {\n\tplugin := Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"register\",\n\t\tLog:               testutil.Logger{Quiet: true},\n\t\tWorkarounds:       workarounds{ReadCoilsStartingAtZero: true},\n\t}\n\tplugin.SlaveID = 1\n\tplugin.Coils = []fieldDefinition{\n\t\t{\n\t\t\tName:    \"coil-8\",\n\t\t\tAddress: []uint16{8},\n\t\t},\n\t\t{\n\t\t\tName:    \"coil-new-group\",\n\t\t\tAddress: []uint16{maxQuantityCoils},\n\t\t},\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.Len(t, plugin.requests[1].coil, 2)\n\n\t// First group should now start at zero and have the cumulated length\n\trequire.Equal(t, uint16(0), plugin.requests[1].coil[0].address)\n\trequire.Equal(t, uint16(9), plugin.requests[1].coil[0].length)\n\n\t// The second field should form a new group as the previous request\n\t// is now too large (beyond max-coils-per-read) after zero enforcement.\n\trequire.Equal(t, maxQuantityCoils, plugin.requests[1].coil[1].address)\n\trequire.Equal(t, uint16(1), plugin.requests[1].coil[1].length)\n}\n\nfunc TestWorkaroundsStringRegisterLocation(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tlocation string\n\t\torder    string\n\t\tcontent  []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:  \"default big-endian\",\n\t\t\torder: \"ABCD\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53,\n\t\t\t\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:  \"default little-endian\",\n\t\t\torder: \"DCBA\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x6f, 0x4d, 0x62, 0x64, 0x73, 0x75, 0x53, 0x20,\n\t\t\t\t0x72, 0x74, 0x6e, 0x69, 0x00, 0x67,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"both big-endian\",\n\t\t\tlocation: \"both\",\n\t\t\torder:    \"ABCD\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x4d, 0x6f, 0x64, 0x62, 0x75, 0x73, 0x20, 0x53,\n\t\t\t\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"both little-endian\",\n\t\t\tlocation: \"both\",\n\t\t\torder:    \"DCBA\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x6f, 0x4d, 0x62, 0x64, 0x73, 0x75, 0x53, 0x20,\n\t\t\t\t0x72, 0x74, 0x6e, 0x69, 0x00, 0x67,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"lower big-endian\",\n\t\t\tlocation: \"lower\",\n\t\t\torder:    \"ABCD\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x00, 0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x62,\n\t\t\t\t0x00, 0x75, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53,\n\t\t\t\t0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e,\n\t\t\t\t0x00, 0x67, 0x00, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"lower little-endian\",\n\t\t\tlocation: \"lower\",\n\t\t\torder:    \"DCBA\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x62, 0x00,\n\t\t\t\t0x75, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00,\n\t\t\t\t0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,\n\t\t\t\t0x67, 0x00, 0x00, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"upper big-endian\",\n\t\t\tlocation: \"upper\",\n\t\t\torder:    \"ABCD\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x62, 0x00,\n\t\t\t\t0x75, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00,\n\t\t\t\t0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,\n\t\t\t\t0x67, 0x00, 0x00, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t\t{\n\t\t\tname:     \"upper little-endian\",\n\t\t\tlocation: \"upper\",\n\t\t\torder:    \"DCBA\",\n\t\t\tcontent: []byte{\n\t\t\t\t0x00, 0x4d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x62,\n\t\t\t\t0x00, 0x75, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53,\n\t\t\t\t0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e,\n\t\t\t\t0x00, 0x67, 0x00, 0x00,\n\t\t\t},\n\t\t\texpected: \"Modbus String\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tconst addr = uint16(8)\n\t\t\tlength := uint16(len(tt.content) / 2)\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"modbus\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":     \"Test\",\n\t\t\t\t\t\t\"slave_id\": \"1\",\n\t\t\t\t\t\t\"type\":     \"holding_register\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": tt.expected,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tplugin := &Modbus{\n\t\t\t\tName:              \"Test\",\n\t\t\t\tController:        \"tcp://localhost:1502\",\n\t\t\t\tConfigurationType: \"request\",\n\t\t\t\tLog:               testutil.Logger{Quiet: true},\n\t\t\t\tWorkarounds:       workarounds{StringRegisterLocation: tt.location},\n\t\t\t\tconfigurationPerRequest: configurationPerRequest{\n\t\t\t\t\tRequests: []requestDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSlaveID:      1,\n\t\t\t\t\t\t\tByteOrder:    tt.order,\n\t\t\t\t\t\t\tRegisterType: \"holding\",\n\t\t\t\t\t\t\tFields: []requestFieldDefinition{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAddress:   addr,\n\t\t\t\t\t\t\t\t\tName:      \"value\",\n\t\t\t\t\t\t\t\t\tInputType: \"STRING\",\n\t\t\t\t\t\t\t\t\tLength:    length,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Create a mock server and fill in the data\n\t\t\tserv := mbserver.NewServer()\n\t\t\trequire.NoError(t, serv.ListenTCP(\"localhost:1502\"))\n\t\t\tdefer serv.Close()\n\n\t\t\thandler := mb.NewTCPClientHandler(\"localhost:1502\")\n\t\t\trequire.NoError(t, handler.Connect())\n\t\t\tdefer handler.Close()\n\t\t\tclient := mb.NewClient(handler)\n\t\t\t_, err := client.WriteMultipleRegisters(addr, length, tt.content)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Gather the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\t// Compare\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestWorkaroundsStringRegisterLocationInvalid(t *testing.T) {\n\tplugin := &Modbus{\n\t\tName:              \"Test\",\n\t\tController:        \"tcp://localhost:1502\",\n\t\tConfigurationType: \"request\",\n\t\tLog:               testutil.Logger{Quiet: true},\n\t\tWorkarounds:       workarounds{StringRegisterLocation: \"foo\"},\n\t}\n\trequire.ErrorContains(t, plugin.Init(), `invalid 'string_register_location'`)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/request.go",
    "content": "package modbus\n\nimport (\n\t\"math\"\n\t\"sort\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype request struct {\n\taddress uint16\n\tlength  uint16\n\tfields  []field\n}\n\nfunc countRegisters(requests []request) uint64 {\n\tvar l uint64\n\tfor _, r := range requests {\n\t\tl += uint64(r.length)\n\t}\n\treturn l\n}\n\n// Only split too-large groups, but ignore all optimization potential\nfunc splitMaxBatchSize(g request, maxBatchSize uint16) []request {\n\tvar requests []request\n\n\tidx := 0\n\tfor start := g.address; start < g.address+g.length; {\n\t\tcurrent := request{\n\t\t\taddress: start,\n\t\t}\n\n\t\t// Initialize the end to a safe value avoiding infinite loops\n\t\tend := g.address + g.length\n\t\tvar batchEnd uint16\n\t\tif start >= math.MaxUint16-maxBatchSize {\n\t\t\tbatchEnd = math.MaxUint16\n\t\t} else {\n\t\t\tbatchEnd = start + maxBatchSize\n\t\t}\n\t\tfor _, f := range g.fields[idx:] {\n\t\t\t// If the current field exceeds the batch size we need to split\n\t\t\t// the request here\n\t\t\tif f.address+f.length > batchEnd {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// End of field still fits into the batch so add it to the request\n\t\t\tcurrent.fields = append(current.fields, f)\n\t\t\tend = f.address + f.length\n\t\t\tidx++\n\t\t}\n\n\t\tif end > g.address+g.length {\n\t\t\tend = g.address + g.length\n\t\t}\n\t\tif idx >= len(g.fields) || g.fields[idx].address >= end {\n\t\t\tcurrent.length = end - start\n\t\t} else {\n\t\t\tcurrent.length = g.fields[idx].address - start\n\t\t}\n\t\tstart = end\n\n\t\tif len(current.fields) > 0 {\n\t\t\trequests = append(requests, current)\n\t\t}\n\t}\n\n\treturn requests\n}\n\nfunc shrinkGroup(g request, maxBatchSize uint16) []request {\n\tvar requests []request\n\tvar current request\n\n\tfor _, f := range g.fields {\n\t\t// Just add the field and update length if we are still\n\t\t// within the maximum batch-size\n\t\tif current.length > 0 && f.address+f.length <= current.address+maxBatchSize {\n\t\t\tcurrent.fields = append(current.fields, f)\n\t\t\tcurrent.length = f.address - current.address + f.length\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ignore completely empty requests\n\t\tif len(current.fields) > 0 {\n\t\t\trequests = append(requests, current)\n\t\t}\n\n\t\t// Create a new request\n\t\tcurrent = request{\n\t\t\tfields:  []field{f},\n\t\t\taddress: f.address,\n\t\t\tlength:  f.length,\n\t\t}\n\t}\n\tif len(current.fields) > 0 {\n\t\trequests = append(requests, current)\n\t}\n\n\treturn requests\n}\n\nfunc optimizeGroup(g request, maxBatchSize uint16) []request {\n\tif len(g.fields) == 0 {\n\t\treturn nil\n\t}\n\n\trequests := shrinkGroup(g, maxBatchSize)\n\tlength := countRegisters(requests)\n\n\tfor i := 1; i < len(g.fields)-1; i++ {\n\t\t// Always keep consecutive fields as they are known to be optimal\n\t\tif g.fields[i-1].address+g.fields[i-1].length == g.fields[i].address {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Perform the split and check if it is better\n\t\t// Note: This involves recursive optimization of the right side of the split.\n\t\tcurrent := shrinkGroup(request{fields: g.fields[:i]}, maxBatchSize)\n\t\tcurrent = append(current, optimizeGroup(request{fields: g.fields[i:]}, maxBatchSize)...)\n\t\tcurrentLength := countRegisters(current)\n\n\t\t// Do not allow for more requests\n\t\tif len(current) > len(requests) {\n\t\t\tcontinue\n\t\t}\n\t\t// Try to reduce the number of registers we are trying to access\n\t\tif currentLength >= length {\n\t\t\tcontinue\n\t\t}\n\n\t\t// We found a better solution\n\t\trequests = current\n\t\tlength = currentLength\n\t}\n\n\treturn requests\n}\n\nfunc optimizeGroupWithinLimits(g request, params groupingParams) []request {\n\tif len(g.fields) == 0 {\n\t\treturn nil\n\t}\n\n\tvar requests []request\n\tcurrentRequest := request{\n\t\tfields:  []field{g.fields[0]},\n\t\taddress: g.fields[0].address,\n\t\tlength:  g.fields[0].length,\n\t}\n\tfor i := 1; i <= len(g.fields)-1; i++ {\n\t\t// Check if we need to interrupt the current chunk and require a new one\n\t\tholeSize := g.fields[i].address - (g.fields[i-1].address + g.fields[i-1].length)\n\t\tif g.fields[i].address < g.fields[i-1].address+g.fields[i-1].length {\n\t\t\tparams.log.Warnf(\n\t\t\t\t\"Request at %d with length %d overlaps with next request at %d\",\n\t\t\t\tg.fields[i-1].address, g.fields[i-1].length, g.fields[i].address,\n\t\t\t)\n\t\t\tholeSize = 0\n\t\t}\n\t\tneedInterrupt := holeSize > params.maxExtraRegisters                                                     // too far apart\n\t\tneedInterrupt = needInterrupt || currentRequest.length+holeSize+g.fields[i].length > params.maxBatchSize // too large\n\t\tif !needInterrupt {\n\t\t\t// Still safe to add the field to the current request\n\t\t\tcurrentRequest.length = g.fields[i].address + g.fields[i].length - currentRequest.address\n\t\t\tcurrentRequest.fields = append(currentRequest.fields, g.fields[i])\n\t\t\tcontinue\n\t\t}\n\t\t// Finish the current request, add it to the list and construct a new one\n\t\trequests = append(requests, currentRequest)\n\t\tcurrentRequest = request{\n\t\t\tfields:  []field{g.fields[i]},\n\t\t\taddress: g.fields[i].address,\n\t\t\tlength:  g.fields[i].length,\n\t\t}\n\t}\n\trequests = append(requests, currentRequest)\n\treturn requests\n}\n\ntype groupingParams struct {\n\t// Maximum size of a request in registers\n\tmaxBatchSize uint16\n\t// optimization to use for grouping register groups to requests, Also put potential optimization parameters here\n\toptimization      string\n\tmaxExtraRegisters uint16\n\t// Will force reads to start at zero (if possible) while respecting the max-batch size.\n\tenforceFromZero bool\n\t// tags to add for the requests\n\ttags map[string]string\n\t// log facility to inform the user\n\tlog telegraf.Logger\n}\n\nfunc groupFieldsToRequests(fields []field, params groupingParams) []request {\n\tif len(fields) == 0 {\n\t\treturn nil\n\t}\n\n\t// Sort the fields by address (ascending) and length\n\tsort.Slice(fields, func(i, j int) bool {\n\t\taddrI := fields[i].address\n\t\taddrJ := fields[j].address\n\t\treturn addrI < addrJ || (addrI == addrJ && fields[i].length > fields[j].length)\n\t})\n\n\t// Construct the consecutive register chunks for the addresses and construct Modbus requests.\n\t// For field addresses like [1, 2, 3, 5, 6, 10, 11, 12, 14] we should construct the following\n\t// requests (1, 3) , (5, 2) , (10, 3), (14 , 1). Furthermore, we should respect field boundaries\n\t// and the given maximum chunk sizes.\n\tvar groups []request\n\tvar current request\n\tfor _, f := range fields {\n\t\t// Add tags from higher up\n\t\tif f.tags == nil {\n\t\t\tf.tags = make(map[string]string, len(params.tags))\n\t\t}\n\t\tfor k, v := range params.tags {\n\t\t\tf.tags[k] = v\n\t\t}\n\n\t\t// Check if we need to interrupt the current chunk and require a new one\n\t\tif current.length > 0 && f.address == current.address+current.length {\n\t\t\t// Still safe to add the field to the current request\n\t\t\tcurrent.length += f.length\n\t\t\tif !f.omit {\n\t\t\t\tcurrent.fields = append(current.fields, f)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Finish the current request, add it to the list and construct a new one\n\t\tif current.length > 0 && len(fields) > 0 {\n\t\t\tgroups = append(groups, current)\n\t\t}\n\t\tcurrent = request{\n\t\t\taddress: f.address,\n\t\t\tlength:  f.length,\n\t\t}\n\t\tif !f.omit {\n\t\t\tcurrent.fields = append(current.fields, f)\n\t\t}\n\t}\n\tif current.length > 0 && len(fields) > 0 {\n\t\tgroups = append(groups, current)\n\t}\n\n\tif len(groups) == 0 {\n\t\treturn nil\n\t}\n\n\t// Enforce the first read to start at zero if the option is set\n\tif params.enforceFromZero {\n\t\tgroups[0].length += groups[0].address\n\t\tgroups[0].address = 0\n\t}\n\n\tvar requests []request\n\tswitch params.optimization {\n\tcase \"shrink\":\n\t\t// Shrink request by striping leading and trailing fields with an omit flag set\n\t\tfor _, g := range groups {\n\t\t\tif len(g.fields) > 0 {\n\t\t\t\trequests = append(requests, shrinkGroup(g, params.maxBatchSize)...)\n\t\t\t}\n\t\t}\n\tcase \"rearrange\":\n\t\t// Allow rearranging fields between request in order to reduce the number of touched\n\t\t// registers while keeping the number of requests\n\t\tfor _, g := range groups {\n\t\t\tif len(g.fields) > 0 {\n\t\t\t\trequests = append(requests, optimizeGroup(g, params.maxBatchSize)...)\n\t\t\t}\n\t\t}\n\tcase \"max_insert\":\n\t\t// Allow rearranging fields similar to \"rearrange\" but allow mixing of groups\n\t\t// This keeps the number of touched registers below a threshold\n\t\tvar total request\n\t\tfor _, g := range groups {\n\t\t\tif len(g.fields) > 0 {\n\t\t\t\ttotal.fields = append(total.fields, g.fields...)\n\t\t\t}\n\t\t}\n\t\trequests = optimizeGroupWithinLimits(total, params)\n\tdefault:\n\t\t// no optimization\n\t\tfor _, g := range groups {\n\t\t\tif len(g.fields) > 0 {\n\t\t\t\trequests = append(requests, splitMaxBatchSize(g, params.maxBatchSize)...)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn requests\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/sample_general_begin.conf",
    "content": "# Retrieve data from MODBUS slave devices\n[[inputs.modbus]]\n  ## Connection Configuration\n  ##\n  ## The plugin supports connections to PLCs via MODBUS/TCP, RTU over TCP, ASCII over TCP or\n  ## via serial line communication in binary (RTU) or readable (ASCII) encoding\n  ##\n  ## Device name\n  name = \"Device\"\n\n  ## Slave ID - addresses a MODBUS device on the bus\n  ## Range: 0 - 255 [0 = broadcast; 248 - 255 = reserved]\n  slave_id = 1\n\n  ## Timeout for each request\n  timeout = \"1s\"\n\n  ## Maximum number of retries and the time to wait between retries\n  ## when a slave-device is busy.\n  # busy_retries = 0\n  # busy_retries_wait = \"100ms\"\n\n  # TCP - connect via Modbus/TCP\n  controller = \"tcp://localhost:502\"\n\n  ## Serial (RS485; RS232)\n  ## For RS485 specific setting check the end of the configuration.\n  ## For unix-like operating systems use:\n  # controller = \"file:///dev/ttyUSB0\"\n  ## For Windows operating systems use:\n  # controller = \"COM1\"\n  # baud_rate = 9600\n  # data_bits = 8\n  # parity = \"N\"\n  # stop_bits = 1\n\n  ## Transmission mode for Modbus packets depending on the controller type.\n  ## For Modbus over TCP you can choose between \"TCP\" , \"RTUoverTCP\" and\n  ## \"ASCIIoverTCP\".\n  ## For Serial controllers you can choose between \"RTU\" and \"ASCII\".\n  ## By default this is set to \"auto\" selecting \"TCP\" for ModbusTCP connections\n  ## and \"RTU\" for serial connections.\n  # transmission_mode = \"auto\"\n\n  ## Trace the connection to the modbus device\n  # log_level = \"trace\"\n\n  ## Define the configuration schema\n  ##  |---register -- define fields per register type in the original style (only supports one slave ID)\n  ##  |---request  -- define fields on a requests base\n  ##  |---metric   -- define fields on a metric base\n  configuration_type = \"register\"\n\n  ## Exclude the register type tag\n  ## Please note, this will also influence the grouping of metrics as you won't\n  ## see one metric per register type anymore!\n  # exclude_register_type_tag = false\n"
  },
  {
    "path": "plugins/inputs/modbus/sample_general_end.conf",
    "content": "  ## RS485 specific settings. Only take effect for serial controllers.\n  ## Note: This has to be at the end of the modbus configuration due to\n  ## TOML constraints.\n  # [inputs.modbus.rs485]\n    ## Delay RTS prior to sending\n    # delay_rts_before_send = \"0ms\"\n    ## Delay RTS after to sending\n    # delay_rts_after_send = \"0ms\"\n    ## Pull RTS line to high during sending\n    # rts_high_during_send = false\n    ## Pull RTS line to high after sending\n    # rts_high_after_send = false\n    ## Enabling receiving (Rx) during transmission (Tx)\n    # rx_during_tx = false\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.modbus.workarounds]\n    ## Pause after connect delays the first request by the specified time.\n    ## This might be necessary for (slow) devices.\n    # pause_after_connect = \"0ms\"\n\n    ## Pause between read requests sent to the device.\n    ## This might be necessary for (slow) serial devices.\n    # pause_between_requests = \"0ms\"\n\n    ## Close the connection after every gather cycle.\n    ## Usually the plugin closes the connection after a certain idle-timeout,\n    ## however, if you query a device with limited simultaneous connectivity\n    ## (e.g. serial devices) from multiple instances you might want to only\n    ## stay connected during gather and disconnect afterwards.\n    # close_connection_after_gather = false\n\n    ## Force the plugin to read each field in a separate request.\n    ## This might be necessary for devices not conforming to the spec,\n    ## see https://github.com/influxdata/telegraf/issues/12071.\n    # one_request_per_field = false\n\n    ## Enforce the starting address to be zero for the first request on\n    ## coil registers. This is necessary for some devices see\n    ## https://github.com/influxdata/telegraf/issues/8905\n    # read_coils_starting_at_zero = false\n\n    ## String byte-location in registers AFTER byte-order conversion\n    ## Some device (e.g. EM340) place the string byte in only the upper or\n    ## lower byte location of a register see\n    ## https://github.com/influxdata/telegraf/issues/14748\n    ## Available settings:\n    ##   lower -- use only lower byte of the register (00XX 00XX 00XX 00XX)\n    ##   upper -- use only upper byte of the register (XX00 XX00 XX00 XX00)\n    ## By default both bytes of the register are used (XXXX XXXX).\n    # string_register_location = \"\"\n"
  },
  {
    "path": "plugins/inputs/modbus/sample_metric.conf",
    "content": "  ## --- \"metric\" configuration style ---\n\n  ## Per metric definition\n  ##\n\n  ## Request optimization algorithm across metrics\n  ##  |---none       -- Do not perform any optimization and just group requests\n  ##  |                 within metrics (default)\n  ##  |---max_insert -- Collate registers across all defined metrics and fill in\n  ##                    holes to optimize the number of requests.\n  # optimization = \"none\"\n\n  ## Maximum number of registers the optimizer is allowed to insert between\n  ## non-consecutive registers to save requests.\n  ## This option is only used for the 'max_insert' optimization strategy and\n  ## effectively denotes the hole size between registers to fill.\n  # optimization_max_register_fill = 50\n\n  ## Define a metric produced by the requests to the device\n  ## Multiple of those metrics can be defined. The referenced registers will\n  ## be collated into requests send to the device\n  [[inputs.modbus.metric]]\n    ## ID of the modbus slave device to query\n    ## If you need to query multiple slave-devices, create several \"metric\" definitions.\n    slave_id = 1\n\n    ## Byte order of the data\n    ##  |---ABCD -- Big Endian (Motorola)\n    ##  |---DCBA -- Little Endian (Intel)\n    ##  |---BADC -- Big Endian with byte swap\n    ##  |---CDAB -- Little Endian with byte swap\n    # byte_order = \"ABCD\"\n\n    ## Name of the measurement\n    # measurement = \"modbus\"\n\n    ## Field definitions\n    ## register    - type of the modbus register, can be \"coil\", \"discrete\",\n    ##               \"holding\" or \"input\". Defaults to \"holding\".\n    ## address     - address of the register to query. For coil and discrete inputs this is the bit address.\n    ## name        - field name\n    ## type *1     - type of the modbus field, can be\n    ##                 BIT (single bit of a register)\n    ##                 INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n    ##                 INT16, UINT16, INT32, UINT32, INT64, UINT64 and\n    ##                 FLOAT16, FLOAT32, FLOAT64 (IEEE 754 binary representation)\n    ##                 STRING (byte-sequence converted to string)\n    ## length *1   - (optional) number of registers, ONLY valid for STRING type\n    ## bit *1,2    - (optional) bit of the register, ONLY valid for BIT type\n    ## scale *1,3  - (optional) factor to scale the variable with\n    ## output *2,3 - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64. Defaults to FLOAT64 if\n    ##               \"scale\" is provided and to the input \"type\" class otherwise (INT* -> INT64, etc).\n    ##\n    ## *1: These fields are ignored for both \"coil\" and \"discrete\"-input type of registers.\n    ## *2: This field can only be \"UINT16\" or \"BOOL\" if specified for both \"coil\"\n    ##     and \"discrete\"-input type of registers. By default the fields are\n    ##     output as zero or one in UINT16 format unless \"BOOL\" is used.\n    ## *3: These fields cannot be used with \"STRING\"-type fields.\n    fields = [\n      { register=\"coil\",    address=0, name=\"door_open\"},\n      { register=\"coil\",    address=1, name=\"status_ok\"},\n      { register=\"holding\", address=0, name=\"voltage\",      type=\"INT16\"   },\n      { address=1, name=\"current\",      type=\"INT32\",   scale=0.001 },\n      { address=5, name=\"energy\",       type=\"FLOAT32\", scale=0.001 },\n      { address=7, name=\"frequency\",    type=\"UINT32\",  scale=0.1   },\n      { address=8, name=\"power_factor\", type=\"INT64\",   scale=0.01  },\n      { address=9, name=\"firmware\",     type=\"STRING\",  length=8    },\n    ]\n\n    ## Tags assigned to the metric\n    # [inputs.modbus.metric.tags]\n    #   machine = \"impresser\"\n    #   location = \"main building\"\n"
  },
  {
    "path": "plugins/inputs/modbus/sample_register.conf",
    "content": "  ## --- \"register\" configuration style ---\n\n  ## Measurements\n  ##\n\n  ## Digital Variables, Discrete Inputs and Coils\n  ## measurement - the (optional) measurement name, defaults to \"modbus\"\n  ## name        - the variable name\n  ## data_type   - the (optional) output type, can be BOOL or UINT16 (default)\n  ## address     - variable address\n\n  discrete_inputs = [\n    { name = \"start\",          address = [0]},\n    { name = \"stop\",           address = [1]},\n    { name = \"reset\",          address = [2]},\n    { name = \"emergency_stop\", address = [3]},\n  ]\n  coils = [\n    { name = \"motor1_run\",     address = [0]},\n    { name = \"motor1_jog\",     address = [1]},\n    { name = \"motor1_stop\",    address = [2]},\n  ]\n\n  ## Analog Variables, Input Registers and Holding Registers\n  ## measurement - the (optional) measurement name, defaults to \"modbus\"\n  ## name        - the variable name\n  ## byte_order  - the ordering of bytes\n  ##  |---AB, ABCD   - Big Endian\n  ##  |---BA, DCBA   - Little Endian\n  ##  |---BADC       - Mid-Big Endian\n  ##  |---CDAB       - Mid-Little Endian\n  ## data_type   - BIT (single bit of a register)\n  ##               INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n  ##               INT16, UINT16, INT32, UINT32, INT64, UINT64,\n  ##               FLOAT16-IEEE, FLOAT32-IEEE, FLOAT64-IEEE (IEEE 754 binary representation)\n  ##               FIXED, UFIXED (fixed-point representation on input)\n  ##               STRING (byte-sequence converted to string)\n  ## bit         - (optional) bit of the register, ONLY valid for BIT type\n  ## scale       - the final numeric variable representation\n  ## address     - variable address\n\n  holding_registers = [\n    { name = \"power_factor\", byte_order = \"AB\",   data_type = \"FIXED\", scale=0.01,  address = [8]},\n    { name = \"voltage\",      byte_order = \"AB\",   data_type = \"FIXED\", scale=0.1,   address = [0]},\n    { name = \"energy\",       byte_order = \"ABCD\", data_type = \"FIXED\", scale=0.001, address = [5,6]},\n    { name = \"current\",      byte_order = \"ABCD\", data_type = \"FIXED\", scale=0.001, address = [1,2]},\n    { name = \"frequency\",    byte_order = \"AB\",   data_type = \"UFIXED\", scale=0.1,  address = [7]},\n    { name = \"power\",        byte_order = \"ABCD\", data_type = \"UFIXED\", scale=0.1,  address = [3,4]},\n    { name = \"firmware\",     byte_order = \"AB\",   data_type = \"STRING\", address = [5, 6, 7, 8, 9, 10, 11, 12]},\n  ]\n  input_registers = [\n    { name = \"tank_level\",   byte_order = \"AB\",   data_type = \"INT16\",   scale=1.0,     address = [0]},\n    { name = \"tank_ph\",      byte_order = \"AB\",   data_type = \"INT16\",   scale=1.0,     address = [1]},\n    { name = \"pump1_speed\",  byte_order = \"ABCD\", data_type = \"INT32\",   scale=1.0,     address = [3,4]},\n  ]\n"
  },
  {
    "path": "plugins/inputs/modbus/sample_request.conf",
    "content": "  ## --- \"request\" configuration style ---\n\n  ## Per request definition\n  ##\n\n  ## Define a request sent to the device\n  ## Multiple of those requests can be defined. Data will be collated into metrics at the end of data collection.\n  [[inputs.modbus.request]]\n    ## ID of the modbus slave device to query.\n    ## If you need to query multiple slave-devices, create several \"request\" definitions.\n    slave_id = 1\n\n    ## Byte order of the data.\n    ##  |---ABCD -- Big Endian (Motorola)\n    ##  |---DCBA -- Little Endian (Intel)\n    ##  |---BADC -- Big Endian with byte swap\n    ##  |---CDAB -- Little Endian with byte swap\n    byte_order = \"ABCD\"\n\n    ## Type of the register for the request\n    ## Can be \"coil\", \"discrete\", \"holding\" or \"input\"\n    register = \"coil\"\n\n    ## Name of the measurement.\n    ## Can be overridden by the individual field definitions. Defaults to \"modbus\"\n    # measurement = \"modbus\"\n\n    ## Request optimization algorithm.\n    ##  |---none       -- Do not perform any optimization and use the given layout(default)\n    ##  |---shrink     -- Shrink requests to actually requested fields\n    ##  |                 by stripping leading and trailing omits\n    ##  |---rearrange  -- Rearrange request boundaries within consecutive address ranges\n    ##  |                 to reduce the number of requested registers by keeping\n    ##  |                 the number of requests.\n    ##  |---max_insert -- Rearrange request keeping the number of extra fields below the value\n    ##                    provided in \"optimization_max_register_fill\". It is not necessary to define 'omitted'\n    ##                    fields as the optimisation will add such field only where needed.\n    # optimization = \"none\"\n\n    ## Maximum number register the optimizer is allowed to insert between two fields to\n    ## save requests.\n    ## This option is only used for the 'max_insert' optimization strategy.\n    ## NOTE: All omitted fields are ignored, so this option denotes the effective hole\n    ## size to fill.\n    # optimization_max_register_fill = 50\n\n    ## Field definitions\n    ## Analog Variables, Input Registers and Holding Registers\n    ## address        - address of the register to query. For coil and discrete inputs this is the bit address.\n    ## name *1        - field name\n    ## type *1,2      - type of the modbus field, can be\n    ##                  BIT (single bit of a register)\n    ##                  INT8L, INT8H, UINT8L, UINT8H (low and high byte variants)\n    ##                  INT16, UINT16, INT32, UINT32, INT64, UINT64 and\n    ##                  FLOAT16, FLOAT32, FLOAT64 (IEEE 754 binary representation)\n    ##                  STRING (byte-sequence converted to string)\n    ## length *1,2    - (optional) number of registers, ONLY valid for STRING type\n    ## bit *1,2       - (optional) bit of the register, ONLY valid for BIT type\n    ## scale *1,2,4   - (optional) factor to scale the variable with\n    ## output *1,3,4  - (optional) type of resulting field, can be INT64, UINT64 or FLOAT64.\n    ##                  Defaults to FLOAT64 for numeric fields if \"scale\" is provided.\n    ##                  Otherwise the input \"type\" class is used (e.g. INT* -> INT64).\n    ## measurement *1 - (optional) measurement name, defaults to the setting of the request\n    ## omit           - (optional) omit this field. Useful to leave out single values when querying many registers\n    ##                  with a single request. Defaults to \"false\".\n    ##\n    ## *1: These fields are ignored if field is omitted (\"omit\"=true)\n    ## *2: These fields are ignored for both \"coil\" and \"discrete\"-input type of registers.\n    ## *3: This field can only be \"UINT16\" or \"BOOL\" if specified for both \"coil\"\n    ##     and \"discrete\"-input type of registers. By default the fields are\n    ##     output as zero or one in UINT16 format unless \"BOOL\" is used.\n    ## *4: These fields cannot be used with \"STRING\"-type fields.\n\n    ## Coil / discrete input example\n    fields = [\n      { address=0, name=\"motor1_run\" },\n      { address=1, name=\"jog\", measurement=\"motor\" },\n      { address=2, name=\"motor1_stop\", omit=true },\n      { address=3, name=\"motor1_overheating\", output=\"BOOL\" },\n      { address=4, name=\"firmware\", type=\"STRING\", length=8 },\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n\n  [[inputs.modbus.request]]\n    ## Holding example\n    ## All of those examples will result in FLOAT64 field outputs\n    slave_id = 1\n    byte_order = \"DCBA\"\n    register = \"holding\"\n    fields = [\n      { address=0, name=\"voltage\",      type=\"INT16\",   scale=0.1   },\n      { address=1, name=\"current\",      type=\"INT32\",   scale=0.001 },\n      { address=3, name=\"power\",        type=\"UINT32\",  omit=true   },\n      { address=5, name=\"energy\",       type=\"FLOAT32\", scale=0.001, measurement=\"W\" },\n      { address=7, name=\"frequency\",    type=\"UINT32\",  scale=0.1   },\n      { address=8, name=\"power_factor\", type=\"INT64\",   scale=0.01  },\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n\n  [[inputs.modbus.request]]\n    ## Input example with type conversions\n    slave_id = 1\n    byte_order = \"ABCD\"\n    register = \"input\"\n    fields = [\n      { address=0, name=\"rpm\",         type=\"INT16\"                   },  # will result in INT64 field\n      { address=1, name=\"temperature\", type=\"INT16\", scale=0.1        },  # will result in FLOAT64 field\n      { address=2, name=\"force\",       type=\"INT32\", output=\"FLOAT64\" },  # will result in FLOAT64 field\n      { address=4, name=\"hours\",       type=\"UINT32\"                  },  # will result in UIN64 field\n    ]\n\n    [inputs.modbus.request.tags]\n      machine = \"impresser\"\n      location = \"main building\"\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_registers/init.err",
    "content": "duplicated in measurement \"modbus\""
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_registers/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  controller = \"tcp://localhost:502\"\n  configuration_type = \"request\"\n  exclude_register_type_tag = true\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 1},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 4},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 7},\n    ]\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"input\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 2},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 5},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 8},\n    ]\n\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_slave/expected.out",
    "content": "V,slave_id=1,element=EleMeter\\ 1,name=Device,type=input_register Voltage=200i\nV,slave_id=2,element=EleMeter\\ 2,name=Device,type=input_register Voltage=200i"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_slave/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  timeout = \"1s\"\n  controller = \"tcp://localhost:502\"\n\n  configuration_type = \"request\"\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    byte_order = \"ABCD\"\n    register = \"input\"\n    fields = [\n      {address=200, name=\"Voltage\", type=\"INT32\", measurement=\"V\", omit=false},\n    ]\n\n    [inputs.modbus.request.tags]\n      element = \"EleMeter 1\"\n\n  [[inputs.modbus.request]]\n    slave_id = 2\n    byte_order = \"ABCD\"\n    register = \"input\"\n    fields = [\n      {address=200, name=\"Voltage\", type=\"INT32\", measurement=\"V\", omit=false},\n    ]\n\n    [inputs.modbus.request.tags]\n      element = \"EleMeter 2\"\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_tags/expected.out",
    "content": "modbus,slave_id=1,name=Device,type=holding_register,location=Zone\\ 1 humidity=1,temperature=4,active=7\nmodbus,slave_id=1,name=Device,type=holding_register,location=Zone\\ 2 humidity=2,temperature=5,active=8\nmodbus,slave_id=1,name=Device,type=holding_register,location=Zone\\ 3 humidity=3,temperature=6,active=9\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_different_tags/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  controller = \"tcp://localhost:502\"\n  configuration_type = \"request\"\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 1},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 4},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 7},\n    ]\n\n    [inputs.modbus.request.tags]\n      location = 'Zone 1'\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 2},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 5},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 8},\n    ]\n\n    [inputs.modbus.request.tags]\n      location = 'Zone 2'\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 3},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 6},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 9},\n    ]\n\n    [inputs.modbus.request.tags]\n      location = 'Zone 3'"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_issue_12091/expected.out",
    "content": "Bitfield,name=EAP,resource=30KTL,slave_id=9,type=holding_register Alarm1=0u,Alarm2=0u,Alarm3=0u,State1=32000u,State2=0u,State3=0u\nCurrent,name=EAP,resource=30KTL,slave_id=9,type=holding_register PV1=0,PV2=0,PV3=0,PV4=0\nPower,name=EAP,resource=30KTL,slave_id=9,type=holding_register AC=32080,DC=32064,Efficiency=0\nResistance,name=EAP,resource=30KTL,slave_id=9,type=holding_register Insulation=0\nStatus,name=EAP,resource=30KTL,slave_id=9,type=holding_register Device=32086u\nTemp,name=EAP,resource=30KTL,slave_id=9,type=holding_register Internal=0\nVoltage,name=EAP,resource=30KTL,slave_id=9,type=holding_register PV1=0,PV2=0,PV3=0,PV4=0"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_issue_12091/telegraf.conf",
    "content": "# Retrieve data from MODBUS slave devices\n[[inputs.modbus]]\n\n  # Hiermit wird auch _time auf 60s (also ganze Minuten) gerundet\n  # Sollten (nach der Timestamp Rundung) mehrere Abfragen auf denselben Timestamp (_time)\n  # kommen wird kein Fehler geworfen, sondern der bestehende Wert wird einfach upgedated!\n  precision = \"60s\"\n\n\n  ## Connection Configuration\n  ##\n  ## The plugin supports connections to PLCs via MODBUS/TCP, RTU over TCP, ASCII over TCP or\n  ## via serial line communication in binary (RTU) or readable (ASCII) encoding\n  ##\n  ## Device name\n  name = \"EAP\"\n\n  ## Timeout for each request\n  timeout = \"500ms\"\n\n  ## Maximum number of retries and the time to wait between retries\n  ## when a slave-device is busy.\n  busy_retries = 3\n  busy_retries_wait = \"200ms\"\n\n  # TCP - connect via Modbus/TCP\n  controller = \"tcp://192.168.254.223:502\"\n\n  ## Trace the connection to the modbus device as debug messages\n  ## Note: You have to enable telegraf's debug mode to see those messages!\n  debug_connection = true\n\n  ## Define the configuration schema\n  ##  |---register -- define fields per register type in the original style (only supports one slave ID)\n  ##  |---request  -- define fields on a requests base\n  configuration_type = \"request\"\n\n  ## --- \"request\" configuration style ---\n\n  ## Per request definition\n  ##\n\n  ## Define a request sent to the device\n  [[inputs.modbus.request]]\n    slave_id = 9\n    byte_order = \"ABCD\"\n    register = \"holding\"\n    fields = [\n      { address=32000, measurement=\"Bitfield\", name=\"State1\", type=\"UINT16\" },\n      { address=32002, measurement=\"Bitfield\", name=\"State2\", type=\"UINT16\" },\n      { address=32003, measurement=\"Bitfield\", name=\"State3\", type=\"UINT32\" },\n      { address=32008, measurement=\"Bitfield\", name=\"Alarm1\", type=\"UINT16\" },\n      { address=32009, measurement=\"Bitfield\", name=\"Alarm2\", type=\"UINT16\" },\n      { address=32010, measurement=\"Bitfield\", name=\"Alarm3\", type=\"UINT16\" },\n      { address=32016, measurement=\"Voltage\", name=\"PV1\", type=\"INT16\", scale=0.1, output=\"FLOAT64\" },\n      { address=32017, measurement=\"Current\", name=\"PV1\", type=\"INT16\", scale=0.01, output=\"FLOAT64\" },\n      { address=32018, measurement=\"Voltage\", name=\"PV2\", type=\"INT16\", scale=0.1, output=\"FLOAT64\" },\n      { address=32019, measurement=\"Current\", name=\"PV2\", type=\"INT16\", scale=0.01, output=\"FLOAT64\" },\n      { address=32020, measurement=\"Voltage\", name=\"PV3\", type=\"INT16\", scale=0.1, output=\"FLOAT64\" },\n      { address=32021, measurement=\"Current\", name=\"PV3\", type=\"INT16\", scale=0.01, output=\"FLOAT64\" },\n      { address=32022, measurement=\"Voltage\", name=\"PV4\", type=\"INT16\", scale=0.1, output=\"FLOAT64\" },\n      { address=32023, measurement=\"Current\", name=\"PV4\", type=\"INT16\", scale=0.01, output=\"FLOAT64\" },\n      { address=32064, measurement=\"Power\", name=\"DC\", type=\"INT32\", output=\"FLOAT64\" },\n      { address=32080, measurement=\"Power\", name=\"AC\", type=\"INT32\", output=\"FLOAT64\" },\n      { address=32086, measurement=\"Power\", name=\"Efficiency\", type=\"UINT16\", scale=0.01, output=\"FLOAT64\" },\n      { address=32087, measurement=\"Temp\", name=\"Internal\", type=\"INT16\", scale=0.1, output=\"FLOAT64\" },\n      { address=32088, measurement=\"Resistance\", name=\"Insulation\", type=\"UINT16\", scale=0.001, output=\"FLOAT64\" },\n      { address=32089, measurement=\"Status\", name=\"Device\", type=\"UINT16\" },\n    ]\n    [inputs.modbus.request.tags]\n      resource = \"30KTL\""
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_same_slave_and_request/init.err",
    "content": "field \"Voltage\" duplicated in measurement \"V\""
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_same_slave_and_request/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  timeout = \"1s\"\n  controller = \"tcp://localhost:1502\"\n\n  configuration_type = \"request\"\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    byte_order = \"ABCD\"\n    register = \"input\"\n    fields = [\n      {address=200, name=\"Voltage\", type=\"FLOAT32\", measurement=\"V\", omit=false},\n      {address=200, name=\"Voltage\", type=\"FLOAT32\", measurement=\"V\", omit=false},\n    ]\n\n    [inputs.modbus.request.tags]\n      element = \"EleMeter 1\"\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_same_tags/init.err",
    "content": "duplicated in measurement \"modbus\""
  },
  {
    "path": "plugins/inputs/modbus/testcases/duplicate_fields_same_tags/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  controller = \"tcp://localhost:502\"\n  configuration_type = \"request\"\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 1},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 4},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 7},\n    ]\n\n    [inputs.modbus.request.tags]\n      location = 'Zone 1'\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    register = \"holding\"\n    fields = [\n      { name = \"humidity\", type = \"INT16\", scale=1.0, address = 2},\n      { name = \"temperature\", type = \"INT16\", scale=1.0, address = 5},\n      { name = \"active\", type = \"INT16\", scale=1.0, address = 8},\n    ]\n\n    [inputs.modbus.request.tags]\n      location = 'Zone 1'\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/field_request_too_short_issue_13482/init.err",
    "content": "invalid address"
  },
  {
    "path": "plugins/inputs/modbus/testcases/field_request_too_short_issue_13482/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name = \"Device\"\n  slave_id = 1\n  timeout = \"1s\"\n  controller = \"tcp://localhost:502\"\n\n  holding_registers = [\n    { name = \"data\", byte_order = \"DCBA\",   data_type = \"UINT64\", scale=0.01, address = [0, 1]}\n  ]\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/metric_style_issue_16031/expected.out",
    "content": "modbus,name=modbus,slave_id=1 3x0135:INT=134i,4x0102:INT=0i,4x0103:INT=101i 1729239973009490185\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/metric_style_issue_16031/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name_override = \"modbus\"\n  name = \"modbus\"\n  timeout = \"1s\"\n  controller = \"tcp://172.16.2.31:502\"\n  configuration_type = \"metric\"\n  exclude_register_type_tag = true\n  [[inputs.modbus.metric]]\n    slave_id = 1\n    byte_order = \"ABCD\"\n    fields = [\n      {register = \"holding\", address = 101, name = '4x0102:INT', type = 'INT16'},\n      {register = \"holding\", address = 102, name = '4x0103:INT', type = 'INT16'},\n      {register = \"input\", address = 134, name = '3x0135:INT', type = 'INT16'},\n    ]\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/overflow_issue_14387/expected.out",
    "content": "modbus,name=device-fqdn.com,slave_id=1,type=holding_register energy-10=0,energy-100=0,energy-102=0,energy-104=0,energy-106=0,energy-108=0,energy-110=0,energy-112=0,energy-114=0,energy-116=0,energy-118=0,energy-12=0,energy-120=0,energy-122=0,energy-124=0,energy-126=0,energy-128=0,energy-130=0,energy-132=0,energy-134=0,energy-136=0,energy-138=0,energy-14=0,energy-140=0,energy-142=0,energy-144=0,energy-146=0,energy-148=0,energy-150=0,energy-152=0,energy-154=0,energy-156=0,energy-158=0,energy-16=0,energy-160=0,energy-162=0,energy-164=0,energy-166=0,energy-168=0,energy-170=0,energy-172=0,energy-174=0,energy-176=0,energy-178=0,energy-18=0,energy-180=0,energy-182=0,energy-184=0,energy-186=0,energy-188=0,energy-190=0,energy-192=0,energy-194=0,energy-196=0,energy-198=0,energy-2=0,energy-20=0,energy-200=0,energy-202=0,energy-204=0,energy-206=0,energy-208=0,energy-210=0,energy-212=0,energy-214=0,energy-216=0,energy-22=0,energy-24=0,energy-26=0,energy-28=0,energy-30=0,energy-32=0,energy-34=0,energy-36=0,energy-38=0,energy-4=0,energy-40=0,energy-42=0,energy-44=0,energy-46=0,energy-48=0,energy-50=0,energy-52=0,energy-54=0,energy-56=0,energy-58=0,energy-6=0,energy-60=0,energy-62=0,energy-64=0,energy-66=0,energy-68=0,energy-70=0,energy-72=0,energy-74=0,energy-76=0,energy-78=0,energy-8=0,energy-80=0,energy-82=0,energy-84=0,energy-86=0,energy-88=0,energy-90=0,energy-92=0,energy-94=0,energy-96=0,energy-98=0 1701777274026591864\n"
  },
  {
    "path": "plugins/inputs/modbus/testcases/overflow_issue_14387/telegraf.conf",
    "content": "[[inputs.modbus]]\n  name=\"device-fqdn.com\"\n  timeout = \"1s\"\n  interval = \"900s\"\n  busy_retries = 0\n  busy_retries_wait = \"100ms\"\n  controller = \"tcp://localhost:502\"\n  configuration_type = \"request\"\n\n  [[inputs.modbus.request]]\n    slave_id = 1\n    byte_order = \"ABCD\"\n    register = \"holding\"\n    fields = [\n      { address=12800, type=\"UINT32\", name=\"energy-2\", scale=10.0 },\n      { address=12802, type=\"UINT32\", name=\"energy-4\", scale=10.0 },\n      { address=12804, type=\"UINT32\", name=\"energy-6\", scale=10.0 },\n      { address=12806, type=\"UINT32\", name=\"energy-8\", scale=10.0 },\n      { address=12808, type=\"UINT32\", name=\"energy-10\", scale=10.0 },\n      { address=12810, type=\"UINT32\", name=\"energy-12\", scale=10.0 },\n      { address=12812, type=\"UINT32\", name=\"energy-14\", scale=10.0 },\n      { address=12814, type=\"UINT32\", name=\"energy-16\", scale=10.0 },\n      { address=12816, type=\"UINT32\", name=\"energy-18\", scale=10.0 },\n      { address=12818, type=\"UINT32\", name=\"energy-20\", scale=10.0 },\n      { address=12820, type=\"UINT32\", name=\"energy-22\", scale=10.0 },\n      { address=12822, type=\"UINT32\", name=\"energy-24\", scale=10.0 },\n      { address=12824, type=\"UINT32\", name=\"energy-26\", scale=10.0 },\n      { address=12826, type=\"UINT32\", name=\"energy-28\", scale=10.0 },\n      { address=12828, type=\"UINT32\", name=\"energy-178\", scale=10.0 },\n      { address=12830, type=\"UINT32\", name=\"energy-30\", scale=10.0 },\n      { address=12832, type=\"UINT32\", name=\"energy-32\", scale=10.0 },\n      { address=12834, type=\"UINT32\", name=\"energy-34\", scale=10.0 },\n      { address=12836, type=\"UINT32\", name=\"energy-36\", scale=10.0 },\n      { address=12838, type=\"UINT32\", name=\"energy-38\", scale=10.0 },\n      { address=12840, type=\"UINT32\", name=\"energy-40\", scale=10.0 },\n      { address=12842, type=\"UINT32\", name=\"energy-42\", scale=10.0 },\n      { address=12844, type=\"UINT32\", name=\"energy-44\", scale=10.0 },\n      { address=12846, type=\"UINT32\", name=\"energy-46\", scale=10.0 },\n      { address=12848, type=\"UINT32\", name=\"energy-48\", scale=10.0 },\n      { address=12850, type=\"UINT32\", name=\"energy-50\", scale=10.0 },\n      { address=12852, type=\"UINT32\", name=\"energy-52\", scale=10.0 },\n      { address=12854, type=\"UINT32\", name=\"energy-54\", scale=10.0 },\n      { address=12856, type=\"UINT32\", name=\"energy-56\", scale=10.0 },\n      { address=12858, type=\"UINT32\", name=\"energy-58\", scale=10.0 },\n      { address=12860, type=\"UINT32\", name=\"energy-60\", scale=10.0 },\n      { address=12862, type=\"UINT32\", name=\"energy-62\", scale=10.0 },\n      { address=12864, type=\"UINT32\", name=\"energy-64\", scale=10.0 },\n      { address=12866, type=\"UINT32\", name=\"energy-66\", scale=10.0 },\n      { address=12868, type=\"UINT32\", name=\"energy-68\", scale=10.0 },\n      { address=12870, type=\"UINT32\", name=\"energy-70\", scale=10.0 },\n      { address=12872, type=\"UINT32\", name=\"energy-72\", scale=10.0 },\n      { address=12874, type=\"UINT32\", name=\"energy-74\", scale=10.0 },\n      { address=12876, type=\"UINT32\", name=\"energy-76\", scale=10.0 },\n      { address=12878, type=\"UINT32\", name=\"energy-78\", scale=10.0 },\n      { address=12880, type=\"UINT32\", name=\"energy-80\", scale=10.0 },\n      { address=12882, type=\"UINT32\", name=\"energy-82\", scale=10.0 },\n      { address=12884, type=\"UINT32\", name=\"energy-84\", scale=10.0 },\n      { address=12886, type=\"UINT32\", name=\"energy-86\", scale=10.0 },\n      { address=12888, type=\"UINT32\", name=\"energy-88\", scale=10.0 },\n      { address=12890, type=\"UINT32\", name=\"energy-90\", scale=10.0 },\n      { address=12892, type=\"UINT32\", name=\"energy-92\", scale=10.0 },\n      { address=12894, type=\"UINT32\", name=\"energy-94\", scale=10.0 },\n      { address=12896, type=\"UINT32\", name=\"energy-96\", scale=10.0 },\n      { address=12898, type=\"UINT32\", name=\"energy-98\", scale=10.0 },\n      { address=12900, type=\"UINT32\", name=\"energy-100\", scale=10.0 },\n      { address=12902, type=\"UINT32\", name=\"energy-102\", scale=10.0 },\n      { address=12904, type=\"UINT32\", name=\"energy-104\", scale=10.0 },\n      { address=12906, type=\"UINT32\", name=\"energy-106\", scale=10.0 },\n      { address=12908, type=\"UINT32\", name=\"energy-108\", scale=10.0 },\n      { address=12910, type=\"UINT32\", name=\"energy-110\", scale=10.0 },\n      { address=12912, type=\"UINT32\", name=\"energy-112\", scale=10.0 },\n      { address=12914, type=\"UINT32\", name=\"energy-114\", scale=10.0 },\n      { address=12916, type=\"UINT32\", name=\"energy-116\", scale=10.0 },\n      { address=12918, type=\"UINT32\", name=\"energy-118\", scale=10.0 },\n      { address=12920, type=\"UINT32\", name=\"energy-120\", scale=10.0 },\n      { address=12922, type=\"UINT32\", name=\"energy-122\", scale=10.0 },\n\n      { address=12924, type=\"UINT32\", name=\"energy-124\", scale=10.0 },\n\n      { address=12926, type=\"UINT32\", name=\"energy-126\", scale=10.0 },\n      { address=12928, type=\"UINT32\", name=\"energy-128\", scale=10.0 },\n      { address=12930, type=\"UINT32\", name=\"energy-130\", scale=10.0 },\n      { address=12932, type=\"UINT32\", name=\"energy-132\", scale=10.0 },\n      { address=12934, type=\"UINT32\", name=\"energy-134\", scale=10.0 },\n      { address=12936, type=\"UINT32\", name=\"energy-136\", scale=10.0 },\n      { address=12938, type=\"UINT32\", name=\"energy-138\", scale=10.0 },\n      { address=12940, type=\"UINT32\", name=\"energy-140\", scale=10.0 },\n      { address=12942, type=\"UINT32\", name=\"energy-142\", scale=10.0 },\n      { address=12944, type=\"UINT32\", name=\"energy-144\", scale=10.0 },\n      { address=12946, type=\"UINT32\", name=\"energy-146\", scale=10.0 },\n      { address=12948, type=\"UINT32\", name=\"energy-148\", scale=10.0 },\n      { address=12950, type=\"UINT32\", name=\"energy-150\", scale=10.0 },\n      { address=12952, type=\"UINT32\", name=\"energy-152\", scale=10.0 },\n      { address=12954, type=\"UINT32\", name=\"energy-154\", scale=10.0 },\n      { address=12956, type=\"UINT32\", name=\"energy-156\", scale=10.0 },\n      { address=12958, type=\"UINT32\", name=\"energy-158\", scale=10.0 },\n      { address=12960, type=\"UINT32\", name=\"energy-160\", scale=10.0 },\n      { address=12962, type=\"UINT32\", name=\"energy-162\", scale=10.0 },\n      { address=12964, type=\"UINT32\", name=\"energy-164\", scale=10.0 },\n      { address=12966, type=\"UINT32\", name=\"energy-166\", scale=10.0 },\n      { address=12968, type=\"UINT32\", name=\"energy-168\", scale=10.0 },\n      { address=12970, type=\"UINT32\", name=\"energy-170\", scale=10.0 },\n      { address=12972, type=\"UINT32\", name=\"energy-172\", scale=10.0 },\n      { address=12974, type=\"UINT32\", name=\"energy-174\", scale=10.0 },\n      { address=12976, type=\"UINT32\", name=\"energy-176\", scale=10.0 },\n      { address=12978, type=\"UINT32\", name=\"energy-180\", scale=10.0 },\n      { address=12980, type=\"UINT32\", name=\"energy-182\", scale=10.0 },\n      { address=12982, type=\"UINT32\", name=\"energy-184\", scale=10.0 },\n      { address=12984, type=\"UINT32\", name=\"energy-186\", scale=10.0 },\n      { address=12986, type=\"UINT32\", name=\"energy-188\", scale=10.0 },\n      { address=12988, type=\"UINT32\", name=\"energy-190\", scale=10.0 },\n      { address=12990, type=\"UINT32\", name=\"energy-192\", scale=10.0 },\n      { address=12992, type=\"UINT32\", name=\"energy-194\", scale=10.0 },\n      { address=12994, type=\"UINT32\", name=\"energy-196\", scale=10.0 },\n      { address=12996, type=\"UINT32\", name=\"energy-198\", scale=10.0 },\n      { address=12998, type=\"UINT32\", name=\"energy-200\", scale=10.0 },\n      { address=13000, type=\"UINT32\", name=\"energy-202\", scale=10.0 },\n      { address=13002, type=\"UINT32\", name=\"energy-204\", scale=10.0 },\n      { address=13004, type=\"UINT32\", name=\"energy-206\", scale=10.0 },\n      { address=13006, type=\"UINT32\", name=\"energy-208\", scale=10.0 },\n      { address=13008, type=\"UINT32\", name=\"energy-210\", scale=10.0 },\n      { address=13010, type=\"UINT32\", name=\"energy-212\", scale=10.0 },\n      { address=13012, type=\"UINT32\", name=\"energy-214\", scale=10.0 },\n      { address=13014, type=\"UINT32\", name=\"energy-216\", scale=10.0 },\n    ]\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions.go",
    "content": "package modbus\n\nimport (\n\t\"fmt\"\n)\n\nfunc determineUntypedConverter(outType string) (fieldConverterFunc, error) {\n\tswitch outType {\n\tcase \"\", \"UINT16\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint16(b[0])\n\t\t}, nil\n\tcase \"BOOL\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn b[0] != 0\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\nfunc determineConverter(inType, byteOrder, outType string, scale float64, bit uint8, strloc string) (fieldConverterFunc, error) {\n\tswitch inType {\n\tcase \"STRING\":\n\t\tswitch strloc {\n\t\tcase \"\", \"both\":\n\t\t\treturn determineConverterString(byteOrder)\n\t\tcase \"lower\":\n\t\t\treturn determineConverterStringLow(byteOrder)\n\t\tcase \"upper\":\n\t\t\treturn determineConverterStringHigh(byteOrder)\n\t\t}\n\tcase \"BIT\":\n\t\treturn determineConverterBit(byteOrder, bit)\n\t}\n\n\tif scale != 0.0 {\n\t\treturn determineConverterScale(inType, byteOrder, outType, scale)\n\t}\n\treturn determineConverterNoScale(inType, byteOrder, outType)\n}\n\nfunc determineConverterScale(inType, byteOrder, outType string, scale float64) (fieldConverterFunc, error) {\n\tswitch inType {\n\tcase \"INT8L\":\n\t\treturn determineConverterI8LScale(outType, byteOrder, scale)\n\tcase \"INT8H\":\n\t\treturn determineConverterI8HScale(outType, byteOrder, scale)\n\tcase \"UINT8L\":\n\t\treturn determineConverterU8LScale(outType, byteOrder, scale)\n\tcase \"UINT8H\":\n\t\treturn determineConverterU8HScale(outType, byteOrder, scale)\n\tcase \"INT16\":\n\t\treturn determineConverterI16Scale(outType, byteOrder, scale)\n\tcase \"UINT16\":\n\t\treturn determineConverterU16Scale(outType, byteOrder, scale)\n\tcase \"INT32\":\n\t\treturn determineConverterI32Scale(outType, byteOrder, scale)\n\tcase \"UINT32\":\n\t\treturn determineConverterU32Scale(outType, byteOrder, scale)\n\tcase \"INT64\":\n\t\treturn determineConverterI64Scale(outType, byteOrder, scale)\n\tcase \"UINT64\":\n\t\treturn determineConverterU64Scale(outType, byteOrder, scale)\n\tcase \"FLOAT16\":\n\t\treturn determineConverterF16Scale(outType, byteOrder, scale)\n\tcase \"FLOAT32\":\n\t\treturn determineConverterF32Scale(outType, byteOrder, scale)\n\tcase \"FLOAT64\":\n\t\treturn determineConverterF64Scale(outType, byteOrder, scale)\n\t}\n\treturn nil, fmt.Errorf(\"invalid input data-type: %s\", inType)\n}\n\nfunc determineConverterNoScale(inType, byteOrder, outType string) (fieldConverterFunc, error) {\n\tswitch inType {\n\tcase \"INT8L\":\n\t\treturn determineConverterI8L(outType, byteOrder)\n\tcase \"INT8H\":\n\t\treturn determineConverterI8H(outType, byteOrder)\n\tcase \"UINT8L\":\n\t\treturn determineConverterU8L(outType, byteOrder)\n\tcase \"UINT8H\":\n\t\treturn determineConverterU8H(outType, byteOrder)\n\tcase \"INT16\":\n\t\treturn determineConverterI16(outType, byteOrder)\n\tcase \"UINT16\":\n\t\treturn determineConverterU16(outType, byteOrder)\n\tcase \"INT32\":\n\t\treturn determineConverterI32(outType, byteOrder)\n\tcase \"UINT32\":\n\t\treturn determineConverterU32(outType, byteOrder)\n\tcase \"INT64\":\n\t\treturn determineConverterI64(outType, byteOrder)\n\tcase \"UINT64\":\n\t\treturn determineConverterU64(outType, byteOrder)\n\tcase \"FLOAT16\":\n\t\treturn determineConverterF16(outType, byteOrder)\n\tcase \"FLOAT32\":\n\t\treturn determineConverterF32(outType, byteOrder)\n\tcase \"FLOAT64\":\n\t\treturn determineConverterF64(outType, byteOrder)\n\t}\n\treturn nil, fmt.Errorf(\"invalid input data-type: %s\", inType)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions16.go",
    "content": "package modbus\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\n\t\"github.com/x448/float16\"\n)\n\ntype convert16 func([]byte) uint16\n\nfunc endiannessConverter16(byteOrder string) (convert16, error) {\n\tswitch byteOrder {\n\tcase \"ABCD\", \"CDAB\": // Big endian (Motorola)\n\t\treturn binary.BigEndian.Uint16, nil\n\tcase \"DCBA\", \"BADC\": // Little endian (Intel)\n\t\treturn binary.LittleEndian.Uint16, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid byte-order: %s\", byteOrder)\n}\n\n// I16 - no scale\nfunc determineConverterI16(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int16(tohost(b))\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(int16(tohost(b)))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(int16(tohost(b)))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(int16(tohost(b)))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U16 - no scale\nfunc determineConverterU16(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn tohost(b)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(tohost(b))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(tohost(b))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(tohost(b))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F16 - no scale\nfunc determineConverterF16(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\treturn float16.Frombits(raw).Float32()\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := float16.Frombits(raw).Float32()\n\t\t\treturn float64(in)\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I16 - scale\nfunc determineConverterI16Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int16(tohost(b))\n\t\t\treturn int16(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int16(tohost(b))\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int16(tohost(b))\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int16(tohost(b))\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U16 - scale\nfunc determineConverterU16Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint16(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F16 - scale\nfunc determineConverterF16Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := float16.Frombits(raw)\n\t\t\treturn in.Float32() * float32(scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := float16.Frombits(raw)\n\t\t\treturn float64(in.Float32()) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions32.go",
    "content": "package modbus\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n)\n\ntype convert32 func([]byte) uint32\n\nfunc binaryMSWLEU32(b []byte) uint32 {\n\t_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808\n\treturn uint32(binary.LittleEndian.Uint16(b[0:]))<<16 | uint32(binary.LittleEndian.Uint16(b[2:]))\n}\n\nfunc binaryLSWBEU32(b []byte) uint32 {\n\t_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808\n\treturn uint32(binary.BigEndian.Uint16(b[2:]))<<16 | uint32(binary.BigEndian.Uint16(b[0:]))\n}\n\nfunc endiannessConverter32(byteOrder string) (convert32, error) {\n\tswitch byteOrder {\n\tcase \"ABCD\": // Big endian (Motorola)\n\t\treturn binary.BigEndian.Uint32, nil\n\tcase \"BADC\": // Big endian with bytes swapped\n\t\treturn binaryMSWLEU32, nil\n\tcase \"CDAB\": // Little endian with bytes swapped\n\t\treturn binaryLSWBEU32, nil\n\tcase \"DCBA\": // Little endian (Intel)\n\t\treturn binary.LittleEndian.Uint32, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid byte-order: %s\", byteOrder)\n}\n\n// I32 - no scale\nfunc determineConverterI32(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int32(tohost(b))\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(int32(tohost(b)))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(int32(tohost(b)))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(int32(tohost(b)))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U32 - no scale\nfunc determineConverterU32(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn tohost(b)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(tohost(b))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(tohost(b))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(tohost(b))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F32 - no scale\nfunc determineConverterF32(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\treturn math.Float32frombits(raw)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := math.Float32frombits(raw)\n\t\t\treturn float64(in)\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I32 - scale\nfunc determineConverterI32Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int32(tohost(b))\n\t\t\treturn int32(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int32(tohost(b))\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int32(tohost(b))\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int32(tohost(b))\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U32 - scale\nfunc determineConverterU32Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint32(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F32 - scale\nfunc determineConverterF32Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter32(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := math.Float32frombits(raw)\n\t\t\treturn float32(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := math.Float32frombits(raw)\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions64.go",
    "content": "package modbus\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n)\n\ntype convert64 func([]byte) uint64\n\nfunc binaryMSWLEU64(b []byte) uint64 {\n\t_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808\n\treturn uint64(binary.LittleEndian.Uint16(b[0:]))<<48 | uint64(binary.LittleEndian.Uint16(b[2:]))<<32 |\n\t\tuint64(binary.LittleEndian.Uint16(b[4:]))<<16 | uint64(binary.LittleEndian.Uint16(b[6:]))\n}\n\nfunc binaryLSWBEU64(b []byte) uint64 {\n\t_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808\n\treturn uint64(binary.BigEndian.Uint16(b[6:]))<<48 | uint64(binary.BigEndian.Uint16(b[4:]))<<32 |\n\t\tuint64(binary.BigEndian.Uint16(b[2:]))<<16 | uint64(binary.BigEndian.Uint16(b[0:]))\n}\n\nfunc endiannessConverter64(byteOrder string) (convert64, error) {\n\tswitch byteOrder {\n\tcase \"ABCD\": // Big endian (Motorola)\n\t\treturn binary.BigEndian.Uint64, nil\n\tcase \"BADC\": // Big endian with bytes swapped\n\t\treturn binaryMSWLEU64, nil\n\tcase \"CDAB\": // Little endian with bytes swapped\n\t\treturn binaryLSWBEU64, nil\n\tcase \"DCBA\": // Little endian (Intel)\n\t\treturn binary.LittleEndian.Uint64, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid byte-order: %s\", byteOrder)\n}\n\n// I64 - no scale\nfunc determineConverterI64(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\", \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(tohost(b))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn uint64(in)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn float64(in)\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U64 - no scale\nfunc determineConverterU64(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(tohost(b))\n\t\t}, nil\n\tcase \"native\", \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn tohost(b)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(tohost(b))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F64 - no scale\nfunc determineConverterF64(outType, byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\", \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\treturn math.Float64frombits(raw)\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I64 - scale\nfunc determineConverterI64Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int64(tohost(b))\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U64 - scale\nfunc determineConverterU64Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := tohost(b)\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// F64 - scale\nfunc determineConverterF64Scale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter64(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\", \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\traw := tohost(b)\n\t\t\tin := math.Float64frombits(raw)\n\t\t\treturn in * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions8.go",
    "content": "package modbus\n\nimport (\n\t\"fmt\"\n)\n\nfunc endiannessIndex8(byteOrder string, low bool) (int, error) {\n\tswitch byteOrder {\n\tcase \"ABCD\": // Big endian (Motorola)\n\t\tif low {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase \"DCBA\": // Little endian (Intel)\n\t\tif low {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturn 1, nil\n\t}\n\treturn -1, fmt.Errorf(\"invalid byte-order: %s\", byteOrder)\n}\n\n// I8 lower byte - no scale\nfunc determineConverterI8L(outType, byteOrder string) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int8(b[idx])\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(int8(b[idx]))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(int8(b[idx]))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(int8(b[idx]))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I8 higher byte - no scale\nfunc determineConverterI8H(outType, byteOrder string) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int8(b[idx])\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(int8(b[idx]))\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(int8(b[idx]))\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(int8(b[idx]))\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U8 lower byte - no scale\nfunc determineConverterU8L(outType, byteOrder string) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn b[idx]\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(b[idx])\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(b[idx])\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(b[idx])\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U8 higher byte - no scale\nfunc determineConverterU8H(outType, byteOrder string) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn b[idx]\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(b[idx])\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(b[idx])\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(b[idx])\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I8 lower byte - scale\nfunc determineConverterI8LScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn int8(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// I8 higher byte - scale\nfunc determineConverterI8HScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn int8(float64(in) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn int64(float64(in) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn uint64(float64(in) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\tin := int8(b[idx])\n\t\t\treturn float64(in) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U8 lower byte - scale\nfunc determineConverterU8LScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint8(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(b[idx]) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n\n// U8 higher byte - scale\nfunc determineConverterU8HScale(outType, byteOrder string, scale float64) (fieldConverterFunc, error) {\n\tidx, err := endiannessIndex8(byteOrder, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch outType {\n\tcase \"native\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint8(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"INT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn int64(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"UINT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn uint64(float64(b[idx]) * scale)\n\t\t}, nil\n\tcase \"FLOAT64\":\n\t\treturn func(b []byte) interface{} {\n\t\t\treturn float64(b[idx]) * scale\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid output data-type: %s\", outType)\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions_bit.go",
    "content": "package modbus\n\nfunc determineConverterBit(byteOrder string, bit uint8) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn func(b []byte) interface{} {\n\t\t// Swap the bytes according to endianness\n\t\tv := tohost(b)\n\t\treturn uint8(v >> bit & 0x01)\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/modbus/type_conversions_string.go",
    "content": "package modbus\n\nimport (\n\t\"bytes\"\n)\n\nfunc determineConverterString(byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn func(b []byte) interface{} {\n\t\t// Swap the bytes according to endianness\n\t\tvar buf bytes.Buffer\n\t\tfor i := 0; i < len(b); i += 2 {\n\t\t\tv := tohost(b[i : i+2])\n\t\t\tbuf.WriteByte(byte(v >> 8))\n\t\t\tbuf.WriteByte(byte(v & 0xFF))\n\t\t}\n\t\t// Remove everything after null-termination\n\t\ts, _ := bytes.CutSuffix(buf.Bytes(), []byte{0x00})\n\t\treturn string(s)\n\t}, nil\n}\n\nfunc determineConverterStringLow(byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn func(b []byte) interface{} {\n\t\t// Swap the bytes according to endianness\n\t\tvar buf bytes.Buffer\n\t\tfor i := 0; i < len(b); i += 2 {\n\t\t\tv := tohost(b[i : i+2])\n\t\t\tbuf.WriteByte(byte(v & 0xFF))\n\t\t}\n\t\t// Remove everything after null-termination\n\t\ts, _ := bytes.CutSuffix(buf.Bytes(), []byte{0x00})\n\t\treturn string(s)\n\t}, nil\n}\n\nfunc determineConverterStringHigh(byteOrder string) (fieldConverterFunc, error) {\n\ttohost, err := endiannessConverter16(byteOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn func(b []byte) interface{} {\n\t\t// Swap the bytes according to endianness\n\t\tvar buf bytes.Buffer\n\t\tfor i := 0; i < len(b); i += 2 {\n\t\t\tv := tohost(b[i : i+2])\n\t\t\tbuf.WriteByte(byte(v >> 8))\n\t\t}\n\t\t// Remove everything after null-termination\n\t\ts, _ := bytes.CutSuffix(buf.Bytes(), []byte{0x00})\n\t\treturn string(s)\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/README.md",
    "content": "# MongoDB Input Plugin\n\nThis plugin collects metrics about [MongoDB][mongodb] server instances by\nrunning database commands.\n\n> [!NOTE]\n> This plugin supports all versions marked as supported in the\n> [MongoDB Software Lifecycle Schedules][lifecycles].\n\n⭐ Telegraf v0.1.5\n🏷️ datastore\n💻 all\n\n[mongodb]: https://www.mongodb.com\n[lifecycles]: https://www.mongodb.com/support-policy/lifecycles\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many MongoDB servers\n[[inputs.mongodb]]\n  ## An array of URLs of the form:\n  ##   \"mongodb://\" [user \":\" pass \"@\"] host [ \":\" port]\n  ## For example:\n  ##   mongodb://user:auth_key@10.10.3.30:27017,\n  ##   mongodb://10.10.3.33:18832,\n  ##\n  ## If connecting to a cluster, users must include the \"?connect=direct\" in\n  ## the URL to ensure that the connection goes directly to the specified node\n  ## and not have all connections passed to the master node.\n  servers = [\"mongodb://127.0.0.1:27017/?connect=direct\"]\n\n  ## When true, collect cluster status.\n  ## Note that the query that counts jumbo chunks triggers a COLLSCAN, which\n  ## may have an impact on performance.\n  # gather_cluster_status = true\n\n  ## When true, collect per database stats\n  # gather_perdb_stats = false\n\n  ## When true, collect per collection stats\n  # gather_col_stats = false\n\n  ## When true, collect usage statistics for each collection\n  ## (insert, update, queries, remove, getmore, commands etc...).\n  # gather_top_stat = false\n\n  ## List of db where collections stats are collected\n  ## If empty, all db are concerned\n  # col_stats_dbs = [\"local\"]\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Specifies plugin behavior regarding disconnected servers\n  ## Available choices :\n  ##   - error: telegraf will return an error on startup if one the servers is unreachable\n  ##   - skip: telegraf will skip unreachable servers on both startup and gather\n  # disconnected_servers_behavior = \"error\"\n```\n\n### Permissions\n\nIf your MongoDB instance has access control enabled you will need to connect\nas a user with sufficient rights.\n\nWith MongoDB 3.4 and higher, the `clusterMonitor` role can be used.  In\nversion 3.2 you may also need these additional permissions:\n\n```shell\n> db.grantRolesToUser(\"user\", [{role: \"read\", actions: \"find\", db: \"local\"}])\n```\n\nIf the user is missing required privileges you may see an error in the\nTelegraf logs similar to:\n\n```shell\nError in input [mongodb]: not authorized on admin to execute command { serverStatus: 1, recordStats: 0 }\n```\n\nSome permission related errors are logged at debug level, you can check these\nmessages by setting `debug = true` in the agent section of the configuration or\nby running Telegraf with the `--debug` argument.\n\n## Metrics\n\n- mongodb\n  - tags:\n    - hostname\n    - node_type\n    - rs_name\n  - fields:\n    - active_reads (integer)\n    - active_writes (integer)\n    - aggregate_command_failed (integer)\n    - aggregate_command_total (integer)\n    - assert_msg (integer)\n    - assert_regular (integer)\n    - assert_rollovers (integer)\n    - assert_user (integer)\n    - assert_warning (integer)\n    - available_reads (integer)\n    - available_writes (integer)\n    - commands (integer)\n    - connections_available (integer)\n    - connections_current (integer)\n    - connections_total_created (integer)\n    - count_command_failed (integer)\n    - count_command_total (integer)\n    - cursor_no_timeout_count (integer)\n    - cursor_pinned_count (integer)\n    - cursor_timed_out_count (integer)\n    - cursor_total_count (integer)\n    - delete_command_failed (integer)\n    - delete_command_total (integer)\n    - deletes (integer)\n    - distinct_command_failed (integer)\n    - distinct_command_total (integer)\n    - document_deleted (integer)\n    - document_inserted (integer)\n    - document_returned (integer)\n    - document_updated (integer)\n    - find_and_modify_command_failed (integer)\n    - find_and_modify_command_total (integer)\n    - find_command_failed (integer)\n    - find_command_total (integer)\n    - flushes (integer)\n    - flushes_total_time_ns (integer)\n    - get_more_command_failed (integer)\n    - get_more_command_total (integer)\n    - getmores (integer)\n    - insert_command_failed (integer)\n    - insert_command_total (integer)\n    - inserts (integer)\n    - jumbo_chunks (integer)\n    - latency_commands_count (integer)\n    - latency_commands (integer)\n    - latency_reads_count (integer)\n    - latency_reads (integer)\n    - latency_writes_count (integer)\n    - latency_writes (integer)\n    - member_status (string)\n    - net_in_bytes_count (integer)\n    - net_out_bytes_count (integer)\n    - open_connections (integer)\n    - operation_scan_and_order (integer)\n    - operation_write_conflicts (integer)\n    - page_faults (integer)\n    - percent_cache_dirty (float)\n    - percent_cache_used (float)\n    - queries (integer)\n    - queued_reads (integer)\n    - queued_writes (integer)\n    - repl_apply_batches_num (integer)\n    - repl_apply_batches_total_millis (integer)\n    - repl_apply_ops (integer)\n    - repl_buffer_count (integer)\n    - repl_buffer_size_bytes (integer)\n    - repl_commands (integer)\n    - repl_deletes (integer)\n    - repl_executor_pool_in_progress_count (integer)\n    - repl_executor_queues_network_in_progress (integer)\n    - repl_executor_queues_sleepers (integer)\n    - repl_executor_unsignaled_events (integer)\n    - repl_getmores (integer)\n    - repl_inserts (integer)\n    - repl_lag (integer)\n    - repl_network_bytes (integer)\n    - repl_network_getmores_num (integer)\n    - repl_network_getmores_total_millis (integer)\n    - repl_network_ops (integer)\n    - repl_queries (integer)\n    - repl_updates (integer)\n    - repl_oplog_window_sec (integer)\n    - repl_state (integer)\n    - repl_member_health (integer)\n    - repl_health_avg (float)\n    - resident_megabytes (integer)\n    - state (string)\n    - storage_freelist_search_bucket_exhausted (integer)\n    - storage_freelist_search_requests (integer)\n    - storage_freelist_search_scanned (integer)\n    - tcmalloc_central_cache_free_bytes (integer)\n    - tcmalloc_current_allocated_bytes (integer)\n    - tcmalloc_current_total_thread_cache_bytes (integer)\n    - tcmalloc_heap_size (integer)\n    - tcmalloc_max_total_thread_cache_bytes (integer)\n    - tcmalloc_pageheap_commit_count (integer)\n    - tcmalloc_pageheap_committed_bytes (integer)\n    - tcmalloc_pageheap_decommit_count (integer)\n    - tcmalloc_pageheap_free_bytes (integer)\n    - tcmalloc_pageheap_reserve_count (integer)\n    - tcmalloc_pageheap_scavenge_count (integer)\n    - tcmalloc_pageheap_total_commit_bytes (integer)\n    - tcmalloc_pageheap_total_decommit_bytes (integer)\n    - tcmalloc_pageheap_total_reserve_bytes (integer)\n    - tcmalloc_pageheap_unmapped_bytes (integer)\n    - tcmalloc_spinlock_total_delay_ns (integer)\n    - tcmalloc_thread_cache_free_bytes (integer)\n    - tcmalloc_total_free_bytes (integer)\n    - tcmalloc_transfer_cache_free_bytes (integer)\n    - total_available (integer)\n    - total_created (integer)\n    - total_docs_scanned (integer)\n    - total_in_use (integer)\n    - total_keys_scanned (integer)\n    - total_refreshing (integer)\n    - total_tickets_reads (integer)\n    - total_tickets_writes (integer)\n    - ttl_deletes (integer)\n    - ttl_passes (integer)\n    - update_command_failed (integer)\n    - update_command_total (integer)\n    - updates (integer)\n    - uptime_ns (integer)\n    - version (string)\n    - vsize_megabytes (integer)\n    - wt_connection_files_currently_open (integer)\n    - wt_data_handles_currently_active (integer)\n    - wtcache_app_threads_page_read_count (integer)\n    - wtcache_app_threads_page_read_time (integer)\n    - wtcache_app_threads_page_write_count (integer)\n    - wtcache_bytes_read_into (integer)\n    - wtcache_bytes_written_from (integer)\n    - wtcache_pages_read_into (integer)\n    - wtcache_pages_requested_from (integer)\n    - wtcache_current_bytes (integer)\n    - wtcache_max_bytes_configured (integer)\n    - wtcache_internal_pages_evicted (integer)\n    - wtcache_modified_pages_evicted (integer)\n    - wtcache_unmodified_pages_evicted (integer)\n    - wtcache_pages_evicted_by_app_thread (integer)\n    - wtcache_pages_queued_for_eviction (integer)\n    - wtcache_server_evicting_pages (integer)\n    - wtcache_tracked_dirty_bytes (integer)\n    - wtcache_worker_thread_evictingpages (integer)\n    - commands_per_sec (integer, deprecated in 1.10; use `commands`))\n    - cursor_no_timeout (integer, opened/sec, deprecated in 1.10; use `cursor_no_timeout_count`))\n    - cursor_pinned (integer, opened/sec, deprecated in 1.10; use `cursor_pinned_count`))\n    - cursor_timed_out (integer, opened/sec, deprecated in 1.10; use `cursor_timed_out_count`))\n    - cursor_total (integer, opened/sec, deprecated in 1.10; use `cursor_total_count`))\n    - deletes_per_sec (integer, deprecated in 1.10; use `deletes`))\n    - flushes_per_sec (integer, deprecated in 1.10; use `flushes`))\n    - getmores_per_sec (integer, deprecated in 1.10; use `getmores`))\n    - inserts_per_sec (integer, deprecated in 1.10; use `inserts`))\n    - net_in_bytes (integer, bytes/sec, deprecated in 1.10; use `net_out_bytes_count`))\n    - net_out_bytes (integer, bytes/sec, deprecated in 1.10; use `net_out_bytes_count`))\n    - queries_per_sec (integer, deprecated in 1.10; use `queries`))\n    - repl_commands_per_sec (integer, deprecated in 1.10; use `repl_commands`))\n    - repl_deletes_per_sec (integer, deprecated in 1.10; use `repl_deletes`)\n    - repl_getmores_per_sec (integer, deprecated in 1.10; use `repl_getmores`)\n    - repl_inserts_per_sec (integer, deprecated in 1.10; use `repl_inserts`))\n    - repl_queries_per_sec (integer, deprecated in 1.10; use `repl_queries`))\n    - repl_updates_per_sec (integer, deprecated in 1.10; use `repl_updates`))\n    - ttl_deletes_per_sec (integer, deprecated in 1.10; use `ttl_deletes`))\n    - ttl_passes_per_sec (integer, deprecated in 1.10; use `ttl_passes`))\n    - updates_per_sec (integer, deprecated in 1.10; use `updates`))\n\n- mongodb_db_stats\n  - tags:\n    - db_name\n    - hostname\n  - fields:\n    - avg_obj_size (float)\n    - collections (integer)\n    - data_size (integer)\n    - index_size (integer)\n    - indexes (integer)\n    - num_extents (integer)\n    - objects (integer)\n    - ok (integer)\n    - storage_size (integer)\n    - type (string)\n    - fs_used_size (integer)\n    - fs_total_size (integer)\n\n- mongodb_col_stats\n  - tags:\n    - hostname\n    - collection\n    - db_name\n  - fields:\n    - size (integer)\n    - avg_obj_size (integer)\n    - storage_size (integer)\n    - total_index_size (integer)\n    - ok (integer)\n    - count (integer)\n    - type (string)\n\n- mongodb_shard_stats\n  - tags:\n    - hostname\n  - fields:\n    - in_use (integer)\n    - available (integer)\n    - created (integer)\n    - refreshing (integer)\n\n- mongodb_top_stats\n  - tags:\n    - collection\n  - fields:\n    - total_time (integer)\n    - total_count (integer)\n    - read_lock_time (integer)\n    - read_lock_count (integer)\n    - write_lock_time (integer)\n    - write_lock_count (integer)\n    - queries_time (integer)\n    - queries_count (integer)\n    - get_more_time (integer)\n    - get_more_count (integer)\n    - insert_time (integer)\n    - insert_count (integer)\n    - update_time (integer)\n    - update_count (integer)\n    - remove_time (integer)\n    - remove_count (integer)\n    - commands_time (integer)\n    - commands_count (integer)\n\n## Example Output\n\n```text\nmongodb,hostname=127.0.0.1:27017 active_reads=1i,active_writes=0i,aggregate_command_failed=0i,aggregate_command_total=0i,assert_msg=0i,assert_regular=0i,assert_rollovers=0i,assert_user=0i,assert_warning=0i,available_reads=127i,available_writes=128i,commands=65i,commands_per_sec=4i,connections_available=51199i,connections_current=1i,connections_total_created=5i,count_command_failed=0i,count_command_total=7i,cursor_no_timeout=0i,cursor_no_timeout_count=0i,cursor_pinned=0i,cursor_pinned_count=0i,cursor_timed_out=0i,cursor_timed_out_count=0i,cursor_total=0i,cursor_total_count=0i,delete_command_failed=0i,delete_command_total=1i,deletes=1i,deletes_per_sec=0i,distinct_command_failed=0i,distinct_command_total=0i,document_deleted=0i,document_inserted=0i,document_returned=0i,document_updated=0i,find_and_modify_command_failed=0i,find_and_modify_command_total=0i,find_command_failed=0i,find_command_total=1i,flushes=52i,flushes_per_sec=0i,flushes_total_time_ns=364000000i,get_more_command_failed=0i,get_more_command_total=0i,getmores=0i,getmores_per_sec=0i,insert_command_failed=0i,insert_command_total=0i,inserts=0i,inserts_per_sec=0i,jumbo_chunks=0i,latency_commands=5740i,latency_commands_count=46i,latency_reads=348i,latency_reads_count=7i,latency_writes=0i,latency_writes_count=0i,net_in_bytes=296i,net_in_bytes_count=4262i,net_out_bytes=29322i,net_out_bytes_count=242103i,open_connections=1i,operation_scan_and_order=0i,operation_write_conflicts=0i,page_faults=1i,percent_cache_dirty=0,percent_cache_used=0,queries=1i,queries_per_sec=0i,queued_reads=0i,queued_writes=0i,resident_megabytes=33i,storage_freelist_search_bucket_exhausted=0i,storage_freelist_search_requests=0i,storage_freelist_search_scanned=0i,tcmalloc_central_cache_free_bytes=0i,tcmalloc_current_allocated_bytes=0i,tcmalloc_current_total_thread_cache_bytes=0i,tcmalloc_heap_size=0i,tcmalloc_max_total_thread_cache_bytes=0i,tcmalloc_pageheap_commit_count=0i,tcmalloc_pageheap_committed_bytes=0i,tcmalloc_pageheap_decommit_count=0i,tcmalloc_pageheap_free_bytes=0i,tcmalloc_pageheap_reserve_count=0i,tcmalloc_pageheap_scavenge_count=0i,tcmalloc_pageheap_total_commit_bytes=0i,tcmalloc_pageheap_total_decommit_bytes=0i,tcmalloc_pageheap_total_reserve_bytes=0i,tcmalloc_pageheap_unmapped_bytes=0i,tcmalloc_spinlock_total_delay_ns=0i,tcmalloc_thread_cache_free_bytes=0i,tcmalloc_total_free_bytes=0i,tcmalloc_transfer_cache_free_bytes=0i,total_available=0i,total_created=0i,total_docs_scanned=0i,total_in_use=0i,total_keys_scanned=0i,total_refreshing=0i,total_tickets_reads=128i,total_tickets_writes=128i,ttl_deletes=0i,ttl_deletes_per_sec=0i,ttl_passes=51i,ttl_passes_per_sec=0i,update_command_failed=0i,update_command_total=0i,updates=0i,updates_per_sec=0i,uptime_ns=6135152000000i,version=\"4.0.19\",vsize_megabytes=5088i,wt_connection_files_currently_open=13i,wt_data_handles_currently_active=18i,wtcache_app_threads_page_read_count=99i,wtcache_app_threads_page_read_time=44528i,wtcache_app_threads_page_write_count=19i,wtcache_bytes_read_into=3248195i,wtcache_bytes_written_from=170612i,wtcache_current_bytes=3648788i,wtcache_internal_pages_evicted=0i,wtcache_max_bytes_configured=8053063680i,wtcache_modified_pages_evicted=0i,wtcache_pages_evicted_by_app_thread=0i,wtcache_pages_queued_for_eviction=0i,wtcache_pages_read_into=234i,wtcache_pages_requested_from=18235i,wtcache_server_evicting_pages=0i,wtcache_tracked_dirty_bytes=0i,wtcache_unmodified_pages_evicted=0i,wtcache_worker_thread_evictingpages=0i 1595691605000000000\nmongodb,hostname=127.0.0.1:27017,node_type=PRI,rs_name=rs0 active_reads=1i,active_writes=0i,aggregate_command_failed=0i,aggregate_command_total=0i,assert_msg=0i,assert_regular=0i,assert_rollovers=0i,assert_user=25i,assert_warning=0i,available_reads=127i,available_writes=128i,commands=345i,commands_per_sec=4i,connections_available=838853i,connections_current=7i,connections_total_created=13i,count_command_failed=0i,count_command_total=5i,cursor_no_timeout=0i,cursor_no_timeout_count=0i,cursor_pinned=0i,cursor_pinned_count=2i,cursor_timed_out=0i,cursor_timed_out_count=0i,cursor_total=0i,cursor_total_count=4i,delete_command_failed=0i,delete_command_total=0i,deletes=0i,deletes_per_sec=0i,distinct_command_failed=0i,distinct_command_total=0i,document_deleted=0i,document_inserted=2i,document_returned=56i,document_updated=0i,find_and_modify_command_failed=0i,find_and_modify_command_total=0i,find_command_failed=0i,find_command_total=23i,flushes=4i,flushes_per_sec=0i,flushes_total_time_ns=43000000i,get_more_command_failed=0i,get_more_command_total=88i,getmores=88i,getmores_per_sec=0i,insert_command_failed=0i,insert_command_total=2i,inserts=2i,inserts_per_sec=0i,jumbo_chunks=0i,latency_commands=82532i,latency_commands_count=337i,latency_reads=30633i,latency_reads_count=111i,latency_writes=0i,latency_writes_count=0i,member_status=\"PRI\",net_in_bytes=636i,net_in_bytes_count=172300i,net_out_bytes=38849i,net_out_bytes_count=335459i,open_connections=7i,operation_scan_and_order=1i,operation_write_conflicts=0i,page_faults=1i,percent_cache_dirty=0,percent_cache_used=0,queries=23i,queries_per_sec=2i,queued_reads=0i,queued_writes=0i,repl_apply_batches_num=0i,repl_apply_batches_total_millis=0i,repl_apply_ops=0i,repl_buffer_count=0i,repl_buffer_size_bytes=0i,repl_commands=0i,repl_commands_per_sec=0i,repl_deletes=0i,repl_deletes_per_sec=0i,repl_executor_pool_in_progress_count=0i,repl_executor_queues_network_in_progress=0i,repl_executor_queues_sleepers=3i,repl_executor_unsignaled_events=0i,repl_getmores=0i,repl_getmores_per_sec=0i,repl_inserts=0i,repl_inserts_per_sec=0i,repl_lag=0i,repl_network_bytes=0i,repl_network_getmores_num=0i,repl_network_getmores_total_millis=0i,repl_network_ops=0i,repl_oplog_window_sec=140i,repl_queries=0i,repl_queries_per_sec=0i,repl_state=1i,repl_updates=0i,repl_updates_per_sec=0i,resident_megabytes=81i,state=\"PRIMARY\",storage_freelist_search_bucket_exhausted=0i,storage_freelist_search_requests=0i,storage_freelist_search_scanned=0i,tcmalloc_central_cache_free_bytes=322128i,tcmalloc_current_allocated_bytes=143566680i,tcmalloc_current_total_thread_cache_bytes=1098968i,tcmalloc_heap_size=181317632i,tcmalloc_max_total_thread_cache_bytes=260046848i,tcmalloc_pageheap_commit_count=53i,tcmalloc_pageheap_committed_bytes=149106688i,tcmalloc_pageheap_decommit_count=1i,tcmalloc_pageheap_free_bytes=3244032i,tcmalloc_pageheap_reserve_count=51i,tcmalloc_pageheap_scavenge_count=1i,tcmalloc_pageheap_total_commit_bytes=183074816i,tcmalloc_pageheap_total_decommit_bytes=33968128i,tcmalloc_pageheap_total_reserve_bytes=181317632i,tcmalloc_pageheap_unmapped_bytes=32210944i,tcmalloc_spinlock_total_delay_ns=0i,tcmalloc_thread_cache_free_bytes=1098968i,tcmalloc_total_free_bytes=2295976i,tcmalloc_transfer_cache_free_bytes=874880i,total_available=0i,total_created=0i,total_docs_scanned=56i,total_in_use=0i,total_keys_scanned=2i,total_refreshing=0i,total_tickets_reads=128i,total_tickets_writes=128i,ttl_deletes=0i,ttl_deletes_per_sec=0i,ttl_passes=2i,ttl_passes_per_sec=0i,update_command_failed=0i,update_command_total=0i,updates=0i,updates_per_sec=0i,uptime_ns=166481000000i,version=\"4.0.19\",vsize_megabytes=1482i,wt_connection_files_currently_open=26i,wt_data_handles_currently_active=44i,wtcache_app_threads_page_read_count=0i,wtcache_app_threads_page_read_time=0i,wtcache_app_threads_page_write_count=56i,wtcache_bytes_read_into=0i,wtcache_bytes_written_from=130403i,wtcache_current_bytes=100312i,wtcache_internal_pages_evicted=0i,wtcache_max_bytes_configured=506462208i,wtcache_modified_pages_evicted=0i,wtcache_pages_evicted_by_app_thread=0i,wtcache_pages_queued_for_eviction=0i,wtcache_pages_read_into=0i,wtcache_pages_requested_from=2085i,wtcache_server_evicting_pages=0i,wtcache_tracked_dirty_bytes=63929i,wtcache_unmodified_pages_evicted=0i,wtcache_worker_thread_evictingpages=0i 1595691605000000000\nmongodb_db_stats,db_name=admin,hostname=127.0.0.1:27017 avg_obj_size=241,collections=2i,data_size=723i,index_size=49152i,indexes=3i,num_extents=0i,objects=3i,ok=1i,storage_size=53248i,type=\"db_stat\" 1547159491000000000\nmongodb_db_stats,db_name=local,hostname=127.0.0.1:27017 avg_obj_size=813.9705882352941,collections=6i,data_size=55350i,index_size=102400i,indexes=5i,num_extents=0i,objects=68i,ok=1i,storage_size=204800i,type=\"db_stat\" 1547159491000000000\nmongodb_col_stats,collection=foo,db_name=local,hostname=127.0.0.1:27017 size=375005928i,avg_obj_size=5494,type=\"col_stat\",storage_size=249307136i,total_index_size=2138112i,ok=1i,count=68251i 1547159491000000000\nmongodb_shard_stats,hostname=127.0.0.1:27017,in_use=3i,available=3i,created=4i,refreshing=0i 1522799074000000000\nmongodb_top_stats,collection=foo,total_time=1471,total_count=158,read_lock_time=49614,read_lock_count=657,write_lock_time=49125456,write_lock_count=9841,queries_time=174,queries_count=495,get_more_time=498,get_more_count=46,insert_time=2651,insert_count=1265,update_time=0,update_count=0,remove_time=0,remove_count=0,commands_time=498611,commands_count=4615\n```\n"
  },
  {
    "path": "plugins/inputs/mongodb/dev/docker-compose.yml",
    "content": "version: '3'\nservices:\n    mongodb:\n        image: mongo\n\n    telegraf:\n        image: glinton/scratch\n        volumes:\n          - ./telegraf.conf:/telegraf.conf\n          - ../../../../telegraf:/telegraf\n        depends_on:\n          - mongodb\n        entrypoint:\n          - /telegraf\n          - --config\n          - /telegraf.conf\n"
  },
  {
    "path": "plugins/inputs/mongodb/dev/telegraf.conf",
    "content": "[agent]\n  interval=\"1s\"\n  flush_interval=\"3s\"\n\n[[inputs.mongodb]]\n  servers = [\"mongodb://mongodb:27017\"]\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongodb.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage mongodb\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.mongodb.org/mongo-driver/mongo\"\n\t\"go.mongodb.org/mongo-driver/mongo/options\"\n\t\"go.mongodb.org/mongo-driver/mongo/readpref\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar disconnectedServersBehaviors = []string{\"error\", \"skip\"}\n\ntype MongoDB struct {\n\tServers                     []string `toml:\"servers\"`\n\tGatherClusterStatus         bool     `toml:\"gather_cluster_status\"`\n\tGatherPerDBStats            bool     `toml:\"gather_perdb_stats\"`\n\tGatherColStats              bool     `toml:\"gather_col_stats\"`\n\tGatherTopStat               bool     `toml:\"gather_top_stat\"`\n\tDisconnectedServersBehavior string   `toml:\"disconnected_servers_behavior\"`\n\tColStatsDBs                 []string `toml:\"col_stats_dbs\"`\n\tcommon_tls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclients   []*server\n\ttlsConfig *tls.Config\n}\n\nfunc (*MongoDB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *MongoDB) Init() error {\n\tif m.DisconnectedServersBehavior == \"\" {\n\t\tm.DisconnectedServersBehavior = \"error\"\n\t}\n\n\tif err := choice.Check(m.DisconnectedServersBehavior, disconnectedServersBehaviors); err != nil {\n\t\treturn fmt.Errorf(\"disconnected_servers_behavior: %w\", err)\n\t}\n\n\ttlsConfig, err := m.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\tm.tlsConfig = tlsConfig\n\n\tif len(m.Servers) == 0 {\n\t\tm.Servers = []string{\"mongodb://127.0.0.1:27017\"}\n\t}\n\n\treturn nil\n}\n\n// Start runs after init and setup mongodb connections\nfunc (m *MongoDB) Start(telegraf.Accumulator) error {\n\tfor _, connURL := range m.Servers {\n\t\tif err := m.setupConnection(connURL); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *MongoDB) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, client := range m.clients {\n\t\twg.Add(1)\n\t\tgo func(srv *server) {\n\t\t\tdefer wg.Done()\n\t\t\tif m.DisconnectedServersBehavior == \"skip\" {\n\t\t\t\tif err := srv.ping(); err != nil {\n\t\t\t\t\tm.Log.Debugf(\"Failed to ping server: %s\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\terr := srv.gatherData(acc, m.GatherClusterStatus, m.GatherPerDBStats, m.GatherColStats, m.GatherTopStat, m.ColStatsDBs)\n\t\t\tif err != nil {\n\t\t\t\tm.Log.Errorf(\"Failed to gather data: %s\", err)\n\t\t\t}\n\t\t}(client)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\n// Stop disconnects mongo connections when stop or reload\nfunc (m *MongoDB) Stop() {\n\tfor _, server := range m.clients {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tif err := server.client.Disconnect(ctx); err != nil {\n\t\t\tm.Log.Errorf(\"Disconnecting from %q failed: %v\", server.hostname, err)\n\t\t}\n\t\tcancel()\n\t}\n}\n\nfunc (m *MongoDB) setupConnection(connURL string) error {\n\tif !strings.HasPrefix(connURL, \"mongodb://\") && !strings.HasPrefix(connURL, \"mongodb+srv://\") {\n\t\t// Preserve backwards compatibility for hostnames without a\n\t\t// scheme, broken in go 1.8. Remove in Telegraf 2.0\n\t\tconnURL = \"mongodb://\" + connURL\n\t\tm.Log.Warnf(\"Using %q as connection URL; please update your configuration to use an URL\", connURL)\n\t}\n\n\tu, err := url.Parse(connURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to parse connection URL: %w\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\topts := options.Client().ApplyURI(connURL)\n\topts.TLSConfig = m.tlsConfig\n\tif opts.ReadPreference == nil {\n\t\topts.ReadPreference = readpref.Nearest()\n\t}\n\n\tclient, err := mongo.Connect(ctx, opts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to MongoDB: %w\", err)\n\t}\n\n\terr = client.Ping(ctx, opts.ReadPreference)\n\tif err != nil {\n\t\tif m.DisconnectedServersBehavior == \"error\" {\n\t\t\treturn fmt.Errorf(\"unable to ping MongoDB: %w\", err)\n\t\t}\n\n\t\tm.Log.Errorf(\"Unable to ping MongoDB: %s\", err)\n\t}\n\n\tserver := &server{\n\t\tclient:   client,\n\t\thostname: u.Host,\n\t\tlog:      m.Log,\n\t}\n\tm.clients = append(m.clients, server)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"mongodb\", func() telegraf.Input {\n\t\treturn &MongoDB{\n\t\t\tGatherClusterStatus: true,\n\t\t\tGatherPerDBStats:    false,\n\t\t\tGatherColStats:      false,\n\t\t\tGatherTopStat:       false,\n\t\t\tColStatsDBs:         []string{\"local\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongodb_data.go",
    "content": "package mongodb\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype mongoDBData struct {\n\tStatLine      *statLine\n\tFields        map[string]interface{}\n\tTags          map[string]string\n\tDBData        []bbData\n\tColData       []colData\n\tShardHostData []bbData\n\tTopStatsData  []bbData\n}\n\ntype bbData struct {\n\tName   string\n\tFields map[string]interface{}\n}\n\ntype colData struct {\n\tName   string\n\tDBName string\n\tFields map[string]interface{}\n}\n\nfunc newMongodbData(statLine *statLine, tags map[string]string) *mongoDBData {\n\treturn &mongoDBData{\n\t\tStatLine: statLine,\n\t\tTags:     tags,\n\t\tFields:   make(map[string]interface{}),\n\t}\n}\n\nvar defaultStats = map[string]string{\n\t\"uptime_ns\":                 \"UptimeNanos\",\n\t\"inserts\":                   \"InsertCnt\",\n\t\"inserts_per_sec\":           \"Insert\",\n\t\"queries\":                   \"QueryCnt\",\n\t\"queries_per_sec\":           \"Query\",\n\t\"updates\":                   \"UpdateCnt\",\n\t\"updates_per_sec\":           \"Update\",\n\t\"deletes\":                   \"DeleteCnt\",\n\t\"deletes_per_sec\":           \"Delete\",\n\t\"getmores\":                  \"GetMoreCnt\",\n\t\"getmores_per_sec\":          \"GetMore\",\n\t\"commands\":                  \"CommandCnt\",\n\t\"commands_per_sec\":          \"Command\",\n\t\"flushes\":                   \"FlushesCnt\",\n\t\"flushes_per_sec\":           \"Flushes\",\n\t\"flushes_total_time_ns\":     \"FlushesTotalTime\",\n\t\"vsize_megabytes\":           \"Virtual\",\n\t\"resident_megabytes\":        \"Resident\",\n\t\"queued_reads\":              \"QueuedReaders\",\n\t\"queued_writes\":             \"QueuedWriters\",\n\t\"active_reads\":              \"ActiveReaders\",\n\t\"active_writes\":             \"ActiveWriters\",\n\t\"available_reads\":           \"AvailableReaders\",\n\t\"available_writes\":          \"AvailableWriters\",\n\t\"total_tickets_reads\":       \"TotalTicketsReaders\",\n\t\"total_tickets_writes\":      \"TotalTicketsWriters\",\n\t\"net_in_bytes_count\":        \"NetInCnt\",\n\t\"net_in_bytes\":              \"NetIn\",\n\t\"net_out_bytes_count\":       \"NetOutCnt\",\n\t\"net_out_bytes\":             \"NetOut\",\n\t\"open_connections\":          \"NumConnections\",\n\t\"ttl_deletes\":               \"DeletedDocumentsCnt\",\n\t\"ttl_deletes_per_sec\":       \"DeletedDocuments\",\n\t\"ttl_passes\":                \"PassesCnt\",\n\t\"ttl_passes_per_sec\":        \"Passes\",\n\t\"cursor_timed_out\":          \"TimedOutC\",\n\t\"cursor_timed_out_count\":    \"TimedOutCCnt\",\n\t\"cursor_no_timeout\":         \"NoTimeoutC\",\n\t\"cursor_no_timeout_count\":   \"NoTimeoutCCnt\",\n\t\"cursor_pinned\":             \"PinnedC\",\n\t\"cursor_pinned_count\":       \"PinnedCCnt\",\n\t\"cursor_total\":              \"TotalC\",\n\t\"cursor_total_count\":        \"TotalCCnt\",\n\t\"document_deleted\":          \"DeletedD\",\n\t\"document_inserted\":         \"InsertedD\",\n\t\"document_returned\":         \"ReturnedD\",\n\t\"document_updated\":          \"UpdatedD\",\n\t\"connections_current\":       \"CurrentC\",\n\t\"connections_available\":     \"AvailableC\",\n\t\"connections_total_created\": \"TotalCreatedC\",\n\t\"operation_scan_and_order\":  \"ScanAndOrderOp\",\n\t\"operation_write_conflicts\": \"WriteConflictsOp\",\n\t\"total_keys_scanned\":        \"TotalKeysScanned\",\n\t\"total_docs_scanned\":        \"TotalObjectsScanned\",\n}\n\nvar defaultAssertsStats = map[string]string{\n\t\"assert_regular\":   \"Regular\",\n\t\"assert_warning\":   \"Warning\",\n\t\"assert_msg\":       \"Msg\",\n\t\"assert_user\":      \"User\",\n\t\"assert_rollovers\": \"Rollovers\",\n}\n\nvar defaultCommandsStats = map[string]string{\n\t\"aggregate_command_total\":        \"AggregateCommandTotal\",\n\t\"aggregate_command_failed\":       \"AggregateCommandFailed\",\n\t\"count_command_total\":            \"CountCommandTotal\",\n\t\"count_command_failed\":           \"CountCommandFailed\",\n\t\"delete_command_total\":           \"DeleteCommandTotal\",\n\t\"delete_command_failed\":          \"DeleteCommandFailed\",\n\t\"distinct_command_total\":         \"DistinctCommandTotal\",\n\t\"distinct_command_failed\":        \"DistinctCommandFailed\",\n\t\"find_command_total\":             \"FindCommandTotal\",\n\t\"find_command_failed\":            \"FindCommandFailed\",\n\t\"find_and_modify_command_total\":  \"FindAndModifyCommandTotal\",\n\t\"find_and_modify_command_failed\": \"FindAndModifyCommandFailed\",\n\t\"get_more_command_total\":         \"GetMoreCommandTotal\",\n\t\"get_more_command_failed\":        \"GetMoreCommandFailed\",\n\t\"insert_command_total\":           \"InsertCommandTotal\",\n\t\"insert_command_failed\":          \"InsertCommandFailed\",\n\t\"update_command_total\":           \"UpdateCommandTotal\",\n\t\"update_command_failed\":          \"UpdateCommandFailed\",\n}\n\nvar defaultLatencyStats = map[string]string{\n\t\"latency_writes_count\":   \"WriteOpsCnt\",\n\t\"latency_writes\":         \"WriteLatency\",\n\t\"latency_reads_count\":    \"ReadOpsCnt\",\n\t\"latency_reads\":          \"ReadLatency\",\n\t\"latency_commands_count\": \"CommandOpsCnt\",\n\t\"latency_commands\":       \"CommandLatency\",\n}\n\nvar defaultReplStats = map[string]string{\n\t\"repl_inserts\":                             \"InsertRCnt\",\n\t\"repl_inserts_per_sec\":                     \"InsertR\",\n\t\"repl_queries\":                             \"QueryRCnt\",\n\t\"repl_queries_per_sec\":                     \"QueryR\",\n\t\"repl_updates\":                             \"UpdateRCnt\",\n\t\"repl_updates_per_sec\":                     \"UpdateR\",\n\t\"repl_deletes\":                             \"DeleteRCnt\",\n\t\"repl_deletes_per_sec\":                     \"DeleteR\",\n\t\"repl_getmores\":                            \"GetMoreRCnt\",\n\t\"repl_getmores_per_sec\":                    \"GetMoreR\",\n\t\"repl_commands\":                            \"CommandRCnt\",\n\t\"repl_commands_per_sec\":                    \"CommandR\",\n\t\"member_status\":                            \"NodeType\",\n\t\"state\":                                    \"NodeState\",\n\t\"repl_state\":                               \"NodeStateInt\",\n\t\"repl_member_health\":                       \"NodeHealthInt\",\n\t\"repl_health_avg\":                          \"ReplHealthAvg\",\n\t\"repl_lag\":                                 \"ReplLag\",\n\t\"repl_network_bytes\":                       \"ReplNetworkBytes\",\n\t\"repl_network_getmores_num\":                \"ReplNetworkGetmoresNum\",\n\t\"repl_network_getmores_total_millis\":       \"ReplNetworkGetmoresTotalMillis\",\n\t\"repl_network_ops\":                         \"ReplNetworkOps\",\n\t\"repl_buffer_count\":                        \"ReplBufferCount\",\n\t\"repl_buffer_size_bytes\":                   \"ReplBufferSizeBytes\",\n\t\"repl_apply_batches_num\":                   \"ReplApplyBatchesNum\",\n\t\"repl_apply_batches_total_millis\":          \"ReplApplyBatchesTotalMillis\",\n\t\"repl_apply_ops\":                           \"ReplApplyOps\",\n\t\"repl_executor_pool_in_progress_count\":     \"ReplExecutorPoolInProgressCount\",\n\t\"repl_executor_queues_network_in_progress\": \"ReplExecutorQueuesNetworkInProgress\",\n\t\"repl_executor_queues_sleepers\":            \"ReplExecutorQueuesSleepers\",\n\t\"repl_executor_unsignaled_events\":          \"ReplExecutorUnsignaledEvents\",\n}\n\nvar defaultClusterStats = map[string]string{\n\t\"jumbo_chunks\": \"JumboChunksCount\",\n}\n\nvar defaultShardStats = map[string]string{\n\t\"total_in_use\":     \"TotalInUse\",\n\t\"total_available\":  \"TotalAvailable\",\n\t\"total_created\":    \"TotalCreated\",\n\t\"total_refreshing\": \"TotalRefreshing\",\n}\n\nvar shardHostStats = map[string]string{\n\t\"in_use\":     \"InUse\",\n\t\"available\":  \"Available\",\n\t\"created\":    \"Created\",\n\t\"refreshing\": \"Refreshing\",\n}\n\nvar mmapStats = map[string]string{\n\t\"mapped_megabytes\":     \"Mapped\",\n\t\"non-mapped_megabytes\": \"NonMapped\",\n\t\"page_faults\":          \"FaultsCnt\",\n\t\"page_faults_per_sec\":  \"Faults\",\n}\n\nvar wiredTigerStats = map[string]string{\n\t\"percent_cache_dirty\": \"CacheDirtyPercent\",\n\t\"percent_cache_used\":  \"CacheUsedPercent\",\n}\n\nvar wiredTigerExtStats = map[string]string{\n\t\"wtcache_tracked_dirty_bytes\":          \"TrackedDirtyBytes\",\n\t\"wtcache_current_bytes\":                \"CurrentCachedBytes\",\n\t\"wtcache_max_bytes_configured\":         \"MaxBytesConfigured\",\n\t\"wtcache_app_threads_page_read_count\":  \"AppThreadsPageReadCount\",\n\t\"wtcache_app_threads_page_read_time\":   \"AppThreadsPageReadTime\",\n\t\"wtcache_app_threads_page_write_count\": \"AppThreadsPageWriteCount\",\n\t\"wtcache_bytes_written_from\":           \"BytesWrittenFrom\",\n\t\"wtcache_bytes_read_into\":              \"BytesReadInto\",\n\t\"wtcache_pages_evicted_by_app_thread\":  \"PagesEvictedByAppThread\",\n\t\"wtcache_pages_queued_for_eviction\":    \"PagesQueuedForEviction\",\n\t\"wtcache_pages_read_into\":              \"PagesReadIntoCache\",\n\t\"wtcache_pages_written_from\":           \"PagesWrittenFromCache\",\n\t\"wtcache_pages_requested_from\":         \"PagesRequestedFromCache\",\n\t\"wtcache_server_evicting_pages\":        \"ServerEvictingPages\",\n\t\"wtcache_worker_thread_evictingpages\":  \"WorkerThreadEvictingPages\",\n\t\"wtcache_internal_pages_evicted\":       \"InternalPagesEvicted\",\n\t\"wtcache_modified_pages_evicted\":       \"ModifiedPagesEvicted\",\n\t\"wtcache_unmodified_pages_evicted\":     \"UnmodifiedPagesEvicted\",\n}\n\nvar wiredTigerConnectionStats = map[string]string{\n\t\"wt_connection_files_currently_open\": \"FilesCurrentlyOpen\",\n}\n\nvar wiredTigerDataHandleStats = map[string]string{\n\t\"wt_data_handles_currently_active\": \"DataHandlesCurrentlyActive\",\n}\n\nvar defaultTCMallocStats = map[string]string{\n\t\"tcmalloc_current_allocated_bytes\":          \"TCMallocCurrentAllocatedBytes\",\n\t\"tcmalloc_heap_size\":                        \"TCMallocHeapSize\",\n\t\"tcmalloc_central_cache_free_bytes\":         \"TCMallocCentralCacheFreeBytes\",\n\t\"tcmalloc_current_total_thread_cache_bytes\": \"TCMallocCurrentTotalThreadCacheBytes\",\n\t\"tcmalloc_max_total_thread_cache_bytes\":     \"TCMallocMaxTotalThreadCacheBytes\",\n\t\"tcmalloc_total_free_bytes\":                 \"TCMallocTotalFreeBytes\",\n\t\"tcmalloc_transfer_cache_free_bytes\":        \"TCMallocTransferCacheFreeBytes\",\n\t\"tcmalloc_thread_cache_free_bytes\":          \"TCMallocThreadCacheFreeBytes\",\n\t\"tcmalloc_spinlock_total_delay_ns\":          \"TCMallocSpinLockTotalDelayNanos\",\n\t\"tcmalloc_pageheap_free_bytes\":              \"TCMallocPageheapFreeBytes\",\n\t\"tcmalloc_pageheap_unmapped_bytes\":          \"TCMallocPageheapUnmappedBytes\",\n\t\"tcmalloc_pageheap_committed_bytes\":         \"TCMallocPageheapComittedBytes\",\n\t\"tcmalloc_pageheap_scavenge_count\":          \"TCMallocPageheapScavengeCount\",\n\t\"tcmalloc_pageheap_commit_count\":            \"TCMallocPageheapCommitCount\",\n\t\"tcmalloc_pageheap_total_commit_bytes\":      \"TCMallocPageheapTotalCommitBytes\",\n\t\"tcmalloc_pageheap_decommit_count\":          \"TCMallocPageheapDecommitCount\",\n\t\"tcmalloc_pageheap_total_decommit_bytes\":    \"TCMallocPageheapTotalDecommitBytes\",\n\t\"tcmalloc_pageheap_reserve_count\":           \"TCMallocPageheapReserveCount\",\n\t\"tcmalloc_pageheap_total_reserve_bytes\":     \"TCMallocPageheapTotalReserveBytes\",\n}\n\nvar defaultStorageStats = map[string]string{\n\t\"storage_freelist_search_bucket_exhausted\": \"StorageFreelistSearchBucketExhausted\",\n\t\"storage_freelist_search_requests\":         \"StorageFreelistSearchRequests\",\n\t\"storage_freelist_search_scanned\":          \"StorageFreelistSearchScanned\",\n}\n\nvar dbDataStats = map[string]string{\n\t\"collections\":   \"Collections\",\n\t\"objects\":       \"Objects\",\n\t\"avg_obj_size\":  \"AvgObjSize\",\n\t\"data_size\":     \"DataSize\",\n\t\"storage_size\":  \"StorageSize\",\n\t\"num_extents\":   \"NumExtents\",\n\t\"indexes\":       \"Indexes\",\n\t\"index_size\":    \"IndexSize\",\n\t\"ok\":            \"Ok\",\n\t\"fs_used_size\":  \"FsUsedSize\",\n\t\"fs_total_size\": \"FsTotalSize\",\n}\n\nvar colDataStats = map[string]string{\n\t\"count\":            \"Count\",\n\t\"size\":             \"Size\",\n\t\"avg_obj_size\":     \"AvgObjSize\",\n\t\"storage_size\":     \"StorageSize\",\n\t\"total_index_size\": \"TotalIndexSize\",\n\t\"ok\":               \"Ok\",\n}\n\nvar topDataStats = map[string]string{\n\t\"total_time\":       \"TotalTime\",\n\t\"total_count\":      \"TotalCount\",\n\t\"read_lock_time\":   \"ReadLockTime\",\n\t\"read_lock_count\":  \"ReadLockCount\",\n\t\"write_lock_time\":  \"WriteLockTime\",\n\t\"write_lock_count\": \"WriteLockCount\",\n\t\"queries_time\":     \"QueriesTime\",\n\t\"queries_count\":    \"QueriesCount\",\n\t\"get_more_time\":    \"GetMoreTime\",\n\t\"get_more_count\":   \"GetMoreCount\",\n\t\"insert_time\":      \"InsertTime\",\n\t\"insert_count\":     \"InsertCount\",\n\t\"update_time\":      \"UpdateTime\",\n\t\"update_count\":     \"UpdateCount\",\n\t\"remove_time\":      \"RemoveTime\",\n\t\"remove_count\":     \"RemoveCount\",\n\t\"commands_time\":    \"CommandsTime\",\n\t\"commands_count\":   \"CommandsCount\",\n}\n\nfunc (d *mongoDBData) addDBStats() {\n\tfor i := range d.StatLine.DBStatsLines {\n\t\tdbStat := d.StatLine.DBStatsLines[i]\n\t\tdbStatLine := reflect.ValueOf(&dbStat).Elem()\n\t\tnewDBData := &bbData{\n\t\t\tName:   dbStat.Name,\n\t\t\tFields: make(map[string]interface{}),\n\t\t}\n\t\tnewDBData.Fields[\"type\"] = \"db_stat\"\n\t\tfor key, value := range dbDataStats {\n\t\t\tval := dbStatLine.FieldByName(value).Interface()\n\t\t\tnewDBData.Fields[key] = val\n\t\t}\n\t\td.DBData = append(d.DBData, *newDBData)\n\t}\n}\n\nfunc (d *mongoDBData) addColStats() {\n\tfor i := range d.StatLine.ColStatsLines {\n\t\tcolstat := d.StatLine.ColStatsLines[i]\n\t\tcolStatLine := reflect.ValueOf(&colstat).Elem()\n\t\tnewColData := &colData{\n\t\t\tName:   colstat.Name,\n\t\t\tDBName: colstat.DBName,\n\t\t\tFields: make(map[string]interface{}),\n\t\t}\n\t\tnewColData.Fields[\"type\"] = \"col_stat\"\n\t\tfor key, value := range colDataStats {\n\t\t\tval := colStatLine.FieldByName(value).Interface()\n\t\t\tnewColData.Fields[key] = val\n\t\t}\n\t\td.ColData = append(d.ColData, *newColData)\n\t}\n}\n\nfunc (d *mongoDBData) addShardHostStats() {\n\tfor host := range d.StatLine.ShardHostStatsLines {\n\t\thostStat := d.StatLine.ShardHostStatsLines[host]\n\t\thostStatLine := reflect.ValueOf(&hostStat).Elem()\n\t\tnewDBData := &bbData{\n\t\t\tName:   host,\n\t\t\tFields: make(map[string]interface{}),\n\t\t}\n\t\tnewDBData.Fields[\"type\"] = \"shard_host_stat\"\n\t\tfor k, v := range shardHostStats {\n\t\t\tval := hostStatLine.FieldByName(v).Interface()\n\t\t\tnewDBData.Fields[k] = val\n\t\t}\n\t\td.ShardHostData = append(d.ShardHostData, *newDBData)\n\t}\n}\n\nfunc (d *mongoDBData) addTopStats() {\n\tfor i := range d.StatLine.TopStatLines {\n\t\ttopStat := d.StatLine.TopStatLines[i]\n\t\ttopStatLine := reflect.ValueOf(&topStat).Elem()\n\t\tnewTopStatData := &bbData{\n\t\t\tName:   topStat.CollectionName,\n\t\t\tFields: make(map[string]interface{}),\n\t\t}\n\t\tnewTopStatData.Fields[\"type\"] = \"top_stat\"\n\t\tfor key, value := range topDataStats {\n\t\t\tval := topStatLine.FieldByName(value).Interface()\n\t\t\tnewTopStatData.Fields[key] = val\n\t\t}\n\t\td.TopStatsData = append(d.TopStatsData, *newTopStatData)\n\t}\n}\n\nfunc (d *mongoDBData) addDefaultStats() {\n\tstatLine := reflect.ValueOf(d.StatLine).Elem()\n\td.addStat(statLine, defaultStats)\n\tif d.StatLine.NodeType != \"\" {\n\t\td.addStat(statLine, defaultReplStats)\n\t\td.Tags[\"node_type\"] = d.StatLine.NodeType\n\t}\n\n\tif d.StatLine.ReadLatency > 0 {\n\t\td.addStat(statLine, defaultLatencyStats)\n\t}\n\n\tif d.StatLine.ReplSetName != \"\" {\n\t\td.Tags[\"rs_name\"] = d.StatLine.ReplSetName\n\t}\n\n\tif d.StatLine.OplogStats != nil {\n\t\td.add(\"repl_oplog_window_sec\", d.StatLine.OplogStats.TimeDiff)\n\t}\n\n\tif d.StatLine.Version != \"\" {\n\t\td.add(\"version\", d.StatLine.Version)\n\t}\n\n\td.addStat(statLine, defaultAssertsStats)\n\td.addStat(statLine, defaultClusterStats)\n\td.addStat(statLine, defaultCommandsStats)\n\td.addStat(statLine, defaultShardStats)\n\td.addStat(statLine, defaultStorageStats)\n\td.addStat(statLine, defaultTCMallocStats)\n\n\tif d.StatLine.StorageEngine == \"mmapv1\" || d.StatLine.StorageEngine == \"rocksdb\" {\n\t\td.addStat(statLine, mmapStats)\n\t} else if d.StatLine.StorageEngine == \"wiredTiger\" {\n\t\tfor key, value := range wiredTigerStats {\n\t\t\tval := statLine.FieldByName(value).Interface()\n\t\t\tpercentVal := fmt.Sprintf(\"%.1f\", val.(float64)*100)\n\t\t\t//nolint:errcheck // guaranteed to be formatted properly because of the above\n\t\t\tfloatVal, _ := strconv.ParseFloat(percentVal, 64)\n\t\t\td.add(key, floatVal)\n\t\t}\n\t\td.addStat(statLine, wiredTigerExtStats)\n\t\td.addStat(statLine, wiredTigerConnectionStats)\n\t\td.addStat(statLine, wiredTigerDataHandleStats)\n\t\td.add(\"page_faults\", d.StatLine.FaultsCnt)\n\t}\n}\n\nfunc (d *mongoDBData) addStat(statLine reflect.Value, stats map[string]string) {\n\tfor key, value := range stats {\n\t\tval := statLine.FieldByName(value).Interface()\n\t\td.add(key, val)\n\t}\n}\n\nfunc (d *mongoDBData) add(key string, val interface{}) {\n\td.Fields[key] = val\n}\n\nfunc (d *mongoDBData) flush(acc telegraf.Accumulator) {\n\tacc.AddFields(\n\t\t\"mongodb\",\n\t\td.Fields,\n\t\td.Tags,\n\t\td.StatLine.Time,\n\t)\n\td.Fields = make(map[string]interface{})\n\n\tfor _, db := range d.DBData {\n\t\td.Tags[\"db_name\"] = db.Name\n\t\tacc.AddFields(\n\t\t\t\"mongodb_db_stats\",\n\t\t\tdb.Fields,\n\t\t\td.Tags,\n\t\t\td.StatLine.Time,\n\t\t)\n\t\tdb.Fields = make(map[string]interface{})\n\t}\n\tfor _, col := range d.ColData {\n\t\td.Tags[\"collection\"] = col.Name\n\t\td.Tags[\"db_name\"] = col.DBName\n\t\tacc.AddFields(\n\t\t\t\"mongodb_col_stats\",\n\t\t\tcol.Fields,\n\t\t\td.Tags,\n\t\t\td.StatLine.Time,\n\t\t)\n\t\tcol.Fields = make(map[string]interface{})\n\t}\n\tfor _, host := range d.ShardHostData {\n\t\td.Tags[\"hostname\"] = host.Name\n\t\tacc.AddFields(\n\t\t\t\"mongodb_shard_stats\",\n\t\t\thost.Fields,\n\t\t\td.Tags,\n\t\t\td.StatLine.Time,\n\t\t)\n\t\thost.Fields = make(map[string]interface{})\n\t}\n\tfor _, col := range d.TopStatsData {\n\t\td.Tags[\"collection\"] = col.Name\n\t\tacc.AddFields(\n\t\t\t\"mongodb_top_stats\",\n\t\t\tcol.Fields,\n\t\t\td.Tags,\n\t\t\td.StatLine.Time,\n\t\t)\n\t\tcol.Fields = make(map[string]interface{})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongodb_data_test.go",
    "content": "package mongodb\n\nimport (\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar tags = make(map[string]string)\n\nfunc TestAddNonReplStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tStorageEngine:       \"\",\n\t\t\tTime:                time.Now(),\n\t\t\tUptimeNanos:         0,\n\t\t\tInsert:              0,\n\t\t\tQuery:               0,\n\t\t\tUpdate:              0,\n\t\t\tUpdateCnt:           0,\n\t\t\tDelete:              0,\n\t\t\tGetMore:             0,\n\t\t\tCommand:             0,\n\t\t\tFlushes:             0,\n\t\t\tFlushesCnt:          0,\n\t\t\tVirtual:             0,\n\t\t\tResident:            0,\n\t\t\tQueuedReaders:       0,\n\t\t\tQueuedWriters:       0,\n\t\t\tActiveReaders:       0,\n\t\t\tActiveWriters:       0,\n\t\t\tAvailableReaders:    0,\n\t\t\tAvailableWriters:    0,\n\t\t\tTotalTicketsReaders: 0,\n\t\t\tTotalTicketsWriters: 0,\n\t\t\tNetIn:               0,\n\t\t\tNetOut:              0,\n\t\t\tNumConnections:      0,\n\t\t\tPasses:              0,\n\t\t\tDeletedDocuments:    0,\n\t\t\tTimedOutC:           0,\n\t\t\tNoTimeoutC:          0,\n\t\t\tPinnedC:             0,\n\t\t\tTotalC:              0,\n\t\t\tDeletedD:            0,\n\t\t\tInsertedD:           0,\n\t\t\tReturnedD:           0,\n\t\t\tUpdatedD:            0,\n\t\t\tCurrentC:            0,\n\t\t\tAvailableC:          0,\n\t\t\tTotalCreatedC:       0,\n\t\t\tScanAndOrderOp:      0,\n\t\t\tWriteConflictsOp:    0,\n\t\t\tTotalKeysScanned:    0,\n\t\t\tTotalObjectsScanned: 0,\n\t\t},\n\t\ttags,\n\t)\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultStats {\n\t\trequire.True(t, acc.HasFloatField(\"mongodb\", key) || acc.HasInt64Field(\"mongodb\", key), key)\n\t}\n}\n\nfunc TestAddReplStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tStorageEngine: \"mmapv1\",\n\t\t\tMapped:        0,\n\t\t\tNonMapped:     0,\n\t\t\tFaults:        0,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range mmapStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key), key)\n\t}\n}\n\nfunc TestAddWiredTigerStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tStorageEngine:              \"wiredTiger\",\n\t\t\tCacheDirtyPercent:          0,\n\t\t\tCacheUsedPercent:           0,\n\t\t\tTrackedDirtyBytes:          0,\n\t\t\tCurrentCachedBytes:         0,\n\t\t\tMaxBytesConfigured:         0,\n\t\t\tAppThreadsPageReadCount:    0,\n\t\t\tAppThreadsPageReadTime:     0,\n\t\t\tAppThreadsPageWriteCount:   0,\n\t\t\tBytesWrittenFrom:           0,\n\t\t\tBytesReadInto:              0,\n\t\t\tPagesEvictedByAppThread:    0,\n\t\t\tPagesQueuedForEviction:     0,\n\t\t\tServerEvictingPages:        0,\n\t\t\tWorkerThreadEvictingPages:  0,\n\t\t\tPagesReadIntoCache:         0,\n\t\t\tPagesRequestedFromCache:    0,\n\t\t\tPagesWrittenFromCache:      1247,\n\t\t\tInternalPagesEvicted:       0,\n\t\t\tModifiedPagesEvicted:       0,\n\t\t\tUnmodifiedPagesEvicted:     0,\n\t\t\tFilesCurrentlyOpen:         0,\n\t\t\tDataHandlesCurrentlyActive: 0,\n\t\t\tFaultsCnt:                  204,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range wiredTigerStats {\n\t\trequire.True(t, acc.HasFloatField(\"mongodb\", key), key)\n\t}\n\n\tfor key := range wiredTigerExtStats {\n\t\trequire.True(t, acc.HasFloatField(\"mongodb\", key) || acc.HasInt64Field(\"mongodb\", key), key)\n\t}\n\n\trequire.True(t, acc.HasInt64Field(\"mongodb\", \"page_faults\"))\n}\n\nfunc TestAddShardStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tTotalInUse:      0,\n\t\t\tTotalAvailable:  0,\n\t\t\tTotalCreated:    0,\n\t\t\tTotalRefreshing: 0,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultShardStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddLatencyStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tCommandOpsCnt:  73,\n\t\t\tCommandLatency: 364,\n\t\t\tReadOpsCnt:     113,\n\t\t\tReadLatency:    201,\n\t\t\tWriteOpsCnt:    7,\n\t\t\tWriteLatency:   55,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultLatencyStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddAssertsStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tRegular:   3,\n\t\t\tWarning:   9,\n\t\t\tMsg:       2,\n\t\t\tUser:      34,\n\t\t\tRollovers: 0,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultAssertsStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddCommandsStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tAggregateCommandTotal:      12,\n\t\t\tAggregateCommandFailed:     2,\n\t\t\tCountCommandTotal:          18,\n\t\t\tCountCommandFailed:         5,\n\t\t\tDeleteCommandTotal:         73,\n\t\t\tDeleteCommandFailed:        364,\n\t\t\tDistinctCommandTotal:       87,\n\t\t\tDistinctCommandFailed:      19,\n\t\t\tFindCommandTotal:           113,\n\t\t\tFindCommandFailed:          201,\n\t\t\tFindAndModifyCommandTotal:  7,\n\t\t\tFindAndModifyCommandFailed: 55,\n\t\t\tGetMoreCommandTotal:        4,\n\t\t\tGetMoreCommandFailed:       55,\n\t\t\tInsertCommandTotal:         34,\n\t\t\tInsertCommandFailed:        65,\n\t\t\tUpdateCommandTotal:         23,\n\t\t\tUpdateCommandFailed:        6,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultCommandsStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddTCMallocStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tTCMallocCurrentAllocatedBytes:        5877253096,\n\t\t\tTCMallocHeapSize:                     8067108864,\n\t\t\tTCMallocPageheapFreeBytes:            1054994432,\n\t\t\tTCMallocPageheapUnmappedBytes:        677859328,\n\t\t\tTCMallocMaxTotalThreadCacheBytes:     1073741824,\n\t\t\tTCMallocCurrentTotalThreadCacheBytes: 80405312,\n\t\t\tTCMallocTotalFreeBytes:               457002008,\n\t\t\tTCMallocCentralCacheFreeBytes:        375131800,\n\t\t\tTCMallocTransferCacheFreeBytes:       1464896,\n\t\t\tTCMallocThreadCacheFreeBytes:         80405312,\n\t\t\tTCMallocPageheapComittedBytes:        7389249536,\n\t\t\tTCMallocPageheapScavengeCount:        396394,\n\t\t\tTCMallocPageheapCommitCount:          641765,\n\t\t\tTCMallocPageheapTotalCommitBytes:     102248751104,\n\t\t\tTCMallocPageheapDecommitCount:        396394,\n\t\t\tTCMallocPageheapTotalDecommitBytes:   94859501568,\n\t\t\tTCMallocPageheapReserveCount:         6179,\n\t\t\tTCMallocPageheapTotalReserveBytes:    8067108864,\n\t\t\tTCMallocSpinLockTotalDelayNanos:      2344453860,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultTCMallocStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddStorageStats(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tStorageFreelistSearchBucketExhausted: 0,\n\t\t\tStorageFreelistSearchRequests:        0,\n\t\t\tStorageFreelistSearchScanned:         0,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\n\tfor key := range defaultStorageStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\nfunc TestAddShardHostStats(t *testing.T) {\n\texpectedHosts := []string{\"hostA\", \"hostB\"}\n\thostStatLines := map[string]shardHostStatLine{}\n\tfor _, host := range expectedHosts {\n\t\thostStatLines[host] = shardHostStatLine{\n\t\t\tInUse:      0,\n\t\t\tAvailable:  0,\n\t\t\tCreated:    0,\n\t\t\tRefreshing: 0,\n\t\t}\n\t}\n\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tShardHostStatsLines: hostStatLines,\n\t\t},\n\t\tmap[string]string{}, // Use empty tags, so we don't break existing tests\n\t)\n\n\tvar acc testutil.Accumulator\n\td.addShardHostStats()\n\td.flush(&acc)\n\n\thostsFound := make([]string, 0, len(hostStatLines))\n\tfor host := range hostStatLines {\n\t\tfor key := range shardHostStats {\n\t\t\trequire.True(t, acc.HasInt64Field(\"mongodb_shard_stats\", key))\n\t\t}\n\n\t\trequire.True(t, acc.HasTag(\"mongodb_shard_stats\", \"hostname\"))\n\t\thostsFound = append(hostsFound, host)\n\t}\n\tsort.Strings(hostsFound)\n\tsort.Strings(expectedHosts)\n\trequire.Equal(t, expectedHosts, hostsFound)\n}\n\nfunc TestStateTag(t *testing.T) {\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tStorageEngine: \"\",\n\t\t\tTime:          time.Now(),\n\t\t\tInsert:        0,\n\t\t\tQuery:         0,\n\t\t\tNodeType:      \"PRI\",\n\t\t\tNodeState:     \"PRIMARY\",\n\t\t\tReplSetName:   \"rs1\",\n\t\t\tVersion:       \"3.6.17\",\n\t\t},\n\t\ttags,\n\t)\n\n\tstateTags := make(map[string]string)\n\tstateTags[\"node_type\"] = \"PRI\"\n\tstateTags[\"rs_name\"] = \"rs1\"\n\n\tvar acc testutil.Accumulator\n\n\td.addDefaultStats()\n\td.flush(&acc)\n\tfields := map[string]interface{}{\n\t\t\"active_reads\":                              int64(0),\n\t\t\"active_writes\":                             int64(0),\n\t\t\"aggregate_command_failed\":                  int64(0),\n\t\t\"aggregate_command_total\":                   int64(0),\n\t\t\"assert_msg\":                                int64(0),\n\t\t\"assert_regular\":                            int64(0),\n\t\t\"assert_rollovers\":                          int64(0),\n\t\t\"assert_user\":                               int64(0),\n\t\t\"assert_warning\":                            int64(0),\n\t\t\"available_reads\":                           int64(0),\n\t\t\"available_writes\":                          int64(0),\n\t\t\"commands\":                                  int64(0),\n\t\t\"commands_per_sec\":                          int64(0),\n\t\t\"connections_available\":                     int64(0),\n\t\t\"connections_current\":                       int64(0),\n\t\t\"connections_total_created\":                 int64(0),\n\t\t\"count_command_failed\":                      int64(0),\n\t\t\"count_command_total\":                       int64(0),\n\t\t\"cursor_no_timeout\":                         int64(0),\n\t\t\"cursor_no_timeout_count\":                   int64(0),\n\t\t\"cursor_pinned\":                             int64(0),\n\t\t\"cursor_pinned_count\":                       int64(0),\n\t\t\"cursor_timed_out\":                          int64(0),\n\t\t\"cursor_timed_out_count\":                    int64(0),\n\t\t\"cursor_total\":                              int64(0),\n\t\t\"cursor_total_count\":                        int64(0),\n\t\t\"delete_command_failed\":                     int64(0),\n\t\t\"delete_command_total\":                      int64(0),\n\t\t\"deletes\":                                   int64(0),\n\t\t\"deletes_per_sec\":                           int64(0),\n\t\t\"distinct_command_failed\":                   int64(0),\n\t\t\"distinct_command_total\":                    int64(0),\n\t\t\"document_deleted\":                          int64(0),\n\t\t\"document_inserted\":                         int64(0),\n\t\t\"document_returned\":                         int64(0),\n\t\t\"document_updated\":                          int64(0),\n\t\t\"find_and_modify_command_failed\":            int64(0),\n\t\t\"find_and_modify_command_total\":             int64(0),\n\t\t\"find_command_failed\":                       int64(0),\n\t\t\"find_command_total\":                        int64(0),\n\t\t\"flushes\":                                   int64(0),\n\t\t\"flushes_per_sec\":                           int64(0),\n\t\t\"flushes_total_time_ns\":                     int64(0),\n\t\t\"get_more_command_failed\":                   int64(0),\n\t\t\"get_more_command_total\":                    int64(0),\n\t\t\"getmores\":                                  int64(0),\n\t\t\"getmores_per_sec\":                          int64(0),\n\t\t\"insert_command_failed\":                     int64(0),\n\t\t\"insert_command_total\":                      int64(0),\n\t\t\"inserts\":                                   int64(0),\n\t\t\"inserts_per_sec\":                           int64(0),\n\t\t\"jumbo_chunks\":                              int64(0),\n\t\t\"member_status\":                             \"PRI\",\n\t\t\"net_in_bytes\":                              int64(0),\n\t\t\"net_in_bytes_count\":                        int64(0),\n\t\t\"net_out_bytes\":                             int64(0),\n\t\t\"net_out_bytes_count\":                       int64(0),\n\t\t\"open_connections\":                          int64(0),\n\t\t\"operation_scan_and_order\":                  int64(0),\n\t\t\"operation_write_conflicts\":                 int64(0),\n\t\t\"queries\":                                   int64(0),\n\t\t\"queries_per_sec\":                           int64(0),\n\t\t\"queued_reads\":                              int64(0),\n\t\t\"queued_writes\":                             int64(0),\n\t\t\"repl_apply_batches_num\":                    int64(0),\n\t\t\"repl_apply_batches_total_millis\":           int64(0),\n\t\t\"repl_apply_ops\":                            int64(0),\n\t\t\"repl_buffer_count\":                         int64(0),\n\t\t\"repl_buffer_size_bytes\":                    int64(0),\n\t\t\"repl_commands\":                             int64(0),\n\t\t\"repl_commands_per_sec\":                     int64(0),\n\t\t\"repl_deletes\":                              int64(0),\n\t\t\"repl_deletes_per_sec\":                      int64(0),\n\t\t\"repl_executor_pool_in_progress_count\":      int64(0),\n\t\t\"repl_executor_queues_network_in_progress\":  int64(0),\n\t\t\"repl_executor_queues_sleepers\":             int64(0),\n\t\t\"repl_executor_unsignaled_events\":           int64(0),\n\t\t\"repl_getmores\":                             int64(0),\n\t\t\"repl_getmores_per_sec\":                     int64(0),\n\t\t\"repl_inserts\":                              int64(0),\n\t\t\"repl_inserts_per_sec\":                      int64(0),\n\t\t\"repl_lag\":                                  int64(0),\n\t\t\"repl_network_bytes\":                        int64(0),\n\t\t\"repl_network_getmores_num\":                 int64(0),\n\t\t\"repl_network_getmores_total_millis\":        int64(0),\n\t\t\"repl_network_ops\":                          int64(0),\n\t\t\"repl_queries\":                              int64(0),\n\t\t\"repl_queries_per_sec\":                      int64(0),\n\t\t\"repl_updates\":                              int64(0),\n\t\t\"repl_updates_per_sec\":                      int64(0),\n\t\t\"repl_state\":                                int64(0),\n\t\t\"repl_member_health\":                        int64(0),\n\t\t\"repl_health_avg\":                           float64(0),\n\t\t\"resident_megabytes\":                        int64(0),\n\t\t\"state\":                                     \"PRIMARY\",\n\t\t\"storage_freelist_search_bucket_exhausted\":  int64(0),\n\t\t\"storage_freelist_search_requests\":          int64(0),\n\t\t\"storage_freelist_search_scanned\":           int64(0),\n\t\t\"tcmalloc_central_cache_free_bytes\":         int64(0),\n\t\t\"tcmalloc_current_allocated_bytes\":          int64(0),\n\t\t\"tcmalloc_current_total_thread_cache_bytes\": int64(0),\n\t\t\"tcmalloc_heap_size\":                        int64(0),\n\t\t\"tcmalloc_max_total_thread_cache_bytes\":     int64(0),\n\t\t\"tcmalloc_pageheap_commit_count\":            int64(0),\n\t\t\"tcmalloc_pageheap_committed_bytes\":         int64(0),\n\t\t\"tcmalloc_pageheap_decommit_count\":          int64(0),\n\t\t\"tcmalloc_pageheap_free_bytes\":              int64(0),\n\t\t\"tcmalloc_pageheap_reserve_count\":           int64(0),\n\t\t\"tcmalloc_pageheap_scavenge_count\":          int64(0),\n\t\t\"tcmalloc_pageheap_total_commit_bytes\":      int64(0),\n\t\t\"tcmalloc_pageheap_total_decommit_bytes\":    int64(0),\n\t\t\"tcmalloc_pageheap_total_reserve_bytes\":     int64(0),\n\t\t\"tcmalloc_pageheap_unmapped_bytes\":          int64(0),\n\t\t\"tcmalloc_spinlock_total_delay_ns\":          int64(0),\n\t\t\"tcmalloc_thread_cache_free_bytes\":          int64(0),\n\t\t\"tcmalloc_total_free_bytes\":                 int64(0),\n\t\t\"tcmalloc_transfer_cache_free_bytes\":        int64(0),\n\t\t\"total_available\":                           int64(0),\n\t\t\"total_created\":                             int64(0),\n\t\t\"total_docs_scanned\":                        int64(0),\n\t\t\"total_in_use\":                              int64(0),\n\t\t\"total_keys_scanned\":                        int64(0),\n\t\t\"total_refreshing\":                          int64(0),\n\t\t\"total_tickets_reads\":                       int64(0),\n\t\t\"total_tickets_writes\":                      int64(0),\n\t\t\"ttl_deletes\":                               int64(0),\n\t\t\"ttl_deletes_per_sec\":                       int64(0),\n\t\t\"ttl_passes\":                                int64(0),\n\t\t\"ttl_passes_per_sec\":                        int64(0),\n\t\t\"update_command_failed\":                     int64(0),\n\t\t\"update_command_total\":                      int64(0),\n\t\t\"updates\":                                   int64(0),\n\t\t\"updates_per_sec\":                           int64(0),\n\t\t\"uptime_ns\":                                 int64(0),\n\t\t\"version\":                                   \"3.6.17\",\n\t\t\"vsize_megabytes\":                           int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"mongodb\", fields, stateTags)\n}\n\nfunc TestAddTopStats(t *testing.T) {\n\tcollections := []string{\"collectionOne\", \"collectionTwo\"}\n\ttopStatLines := make([]topStatLine, 0, len(collections))\n\tfor _, collection := range collections {\n\t\ttopStatLine := topStatLine{\n\t\t\tCollectionName: collection,\n\t\t\tTotalTime:      0,\n\t\t\tTotalCount:     0,\n\t\t\tReadLockTime:   0,\n\t\t\tReadLockCount:  0,\n\t\t\tWriteLockTime:  0,\n\t\t\tWriteLockCount: 0,\n\t\t\tQueriesTime:    0,\n\t\t\tQueriesCount:   0,\n\t\t\tGetMoreTime:    0,\n\t\t\tGetMoreCount:   0,\n\t\t\tInsertTime:     0,\n\t\t\tInsertCount:    0,\n\t\t\tUpdateTime:     0,\n\t\t\tUpdateCount:    0,\n\t\t\tRemoveTime:     0,\n\t\t\tRemoveCount:    0,\n\t\t\tCommandsTime:   0,\n\t\t\tCommandsCount:  0,\n\t\t}\n\t\ttopStatLines = append(topStatLines, topStatLine)\n\t}\n\n\td := newMongodbData(\n\t\t&statLine{\n\t\t\tTopStatLines: topStatLines,\n\t\t},\n\t\ttags,\n\t)\n\n\tvar acc testutil.Accumulator\n\td.addTopStats()\n\td.flush(&acc)\n\n\tfor range topStatLines {\n\t\tfor key := range topDataStats {\n\t\t\trequire.True(t, acc.HasInt64Field(\"mongodb_top_stats\", key))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongodb_server.go",
    "content": "package mongodb\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.mongodb.org/mongo-driver/bson\"\n\t\"go.mongodb.org/mongo-driver/bson/primitive\"\n\t\"go.mongodb.org/mongo-driver/mongo\"\n\t\"go.mongodb.org/mongo-driver/mongo/options\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype server struct {\n\tclient     *mongo.Client\n\thostname   string\n\tlastResult *mongoStatus\n\n\tlog telegraf.Logger\n}\n\ntype oplogEntry struct {\n\tTimestamp primitive.Timestamp `bson:\"ts\"`\n}\n\nfunc isAuthorization(err error) bool {\n\treturn strings.Contains(err.Error(), \"not authorized\")\n}\n\nfunc (s *server) getDefaultTags() map[string]string {\n\ttags := make(map[string]string)\n\ttags[\"hostname\"] = s.hostname\n\treturn tags\n}\n\nfunc (s *server) ping() error {\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\treturn s.client.Ping(ctx, nil)\n}\n\nfunc (s *server) authLog(err error) {\n\tif isAuthorization(err) {\n\t\ts.log.Debug(err.Error())\n\t} else {\n\t\ts.log.Error(err.Error())\n\t}\n}\n\nfunc (s *server) runCommand(database string, cmd, result interface{}) error {\n\tr := s.client.Database(database).RunCommand(context.Background(), cmd)\n\tif r.Err() != nil {\n\t\treturn r.Err()\n\t}\n\treturn r.Decode(result)\n}\n\nfunc (s *server) gatherServerStatus() (*serverStatus, error) {\n\tserverStatus := &serverStatus{}\n\terr := s.runCommand(\"admin\", bson.D{\n\t\t{\n\t\t\tKey:   \"serverStatus\",\n\t\t\tValue: 1,\n\t\t},\n\t\t{\n\t\t\tKey:   \"recordStats\",\n\t\t\tValue: 0,\n\t\t},\n\t}, serverStatus)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn serverStatus, nil\n}\n\nfunc (s *server) gatherReplSetStatus() (*replSetStatus, error) {\n\treplSetStatus := &replSetStatus{}\n\terr := s.runCommand(\"admin\", bson.D{\n\t\t{\n\t\t\tKey:   \"replSetGetStatus\",\n\t\t\tValue: 1,\n\t\t},\n\t}, replSetStatus)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn replSetStatus, nil\n}\n\nfunc (s *server) gatherTopStatData() (*topStats, error) {\n\tvar dest map[string]interface{}\n\terr := s.runCommand(\"admin\", bson.D{\n\t\t{\n\t\t\tKey:   \"top\",\n\t\t\tValue: 1,\n\t\t},\n\t}, &dest)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed running admin cmd: %w\", err)\n\t}\n\n\ttotals, ok := dest[\"totals\"].(map[string]interface{})\n\tif !ok {\n\t\treturn nil, errors.New(\"collection totals not found or not a map\")\n\t}\n\tdelete(totals, \"note\")\n\n\trecorded, err := bson.Marshal(totals)\n\tif err != nil {\n\t\treturn nil, errors.New(\"unable to marshal totals\")\n\t}\n\n\ttopInfo := make(map[string]topStatCollection)\n\tif err := bson.Unmarshal(recorded, &topInfo); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed unmarshalling records: %w\", err)\n\t}\n\n\treturn &topStats{Totals: topInfo}, nil\n}\n\nfunc (s *server) gatherClusterStatus() (*clusterStatus, error) {\n\tchunkCount, err := s.client.Database(\"config\").Collection(\"chunks\").CountDocuments(context.Background(), bson.M{\"jumbo\": true})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &clusterStatus{\n\t\tJumboChunksCount: chunkCount,\n\t}, nil\n}\n\nfunc poolStatsCommand(version string) (string, error) {\n\tmajorPart := string(version[0])\n\tmajor, err := strconv.ParseInt(majorPart, 10, 64)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif major >= 5 {\n\t\treturn \"connPoolStats\", nil\n\t}\n\treturn \"shardConnPoolStats\", nil\n}\n\nfunc (s *server) gatherShardConnPoolStats(version string) (*shardStats, error) {\n\tcommand, err := poolStatsCommand(version)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tshardStats := &shardStats{}\n\terr = s.runCommand(\"admin\", bson.D{\n\t\t{\n\t\t\tKey:   command,\n\t\t\tValue: 1,\n\t\t},\n\t}, &shardStats)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn shardStats, nil\n}\n\nfunc (s *server) gatherDBStats(name string) (*db, error) {\n\tstats := &dbStatsData{}\n\terr := s.runCommand(name, bson.D{\n\t\t{\n\t\t\tKey:   \"dbStats\",\n\t\t\tValue: 1,\n\t\t},\n\t}, stats)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &db{\n\t\tName:        name,\n\t\tDBStatsData: stats,\n\t}, nil\n}\n\nfunc (s *server) getOplogReplLag(collection string) (*oplogStats, error) {\n\tquery := bson.M{\"ts\": bson.M{\"$exists\": true}}\n\n\tvar first oplogEntry\n\tfirstResult := s.client.Database(\"local\").Collection(collection).FindOne(context.Background(), query, options.FindOne().SetSort(bson.M{\"$natural\": 1}))\n\tif firstResult.Err() != nil {\n\t\treturn nil, firstResult.Err()\n\t}\n\tif err := firstResult.Decode(&first); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar last oplogEntry\n\tlastResult := s.client.Database(\"local\").Collection(collection).FindOne(context.Background(), query, options.FindOne().SetSort(bson.M{\"$natural\": -1}))\n\tif lastResult.Err() != nil {\n\t\treturn nil, lastResult.Err()\n\t}\n\tif err := lastResult.Decode(&last); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfirstTime := time.Unix(int64(first.Timestamp.T), 0)\n\tlastTime := time.Unix(int64(last.Timestamp.T), 0)\n\tstats := &oplogStats{\n\t\tTimeDiff: int64(lastTime.Sub(firstTime).Seconds()),\n\t}\n\treturn stats, nil\n}\n\n// The \"oplog.rs\" collection is stored on all replica set members.\n//\n// The \"oplog.$main\" collection is created on the master node of a\n// master-slave replicated deployment.  As of MongoDB 3.2, master-slave\n// replication has been deprecated.\nfunc (s *server) gatherOplogStats() (*oplogStats, error) {\n\tstats, err := s.getOplogReplLag(\"oplog.rs\")\n\tif err == nil {\n\t\treturn stats, nil\n\t}\n\n\treturn s.getOplogReplLag(\"oplog.$main\")\n}\n\nfunc (s *server) gatherCollectionStats(colStatsDBs []string) (*colStats, error) {\n\tnames, err := s.client.ListDatabaseNames(context.Background(), bson.D{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresults := &colStats{}\n\tfor _, dbName := range names {\n\t\tif slices.Contains(colStatsDBs, dbName) || len(colStatsDBs) == 0 {\n\t\t\t// skip views as they fail on collStats below\n\t\t\tfilter := bson.M{\"type\": bson.M{\"$in\": bson.A{\"collection\", \"timeseries\"}}}\n\n\t\t\tvar colls []string\n\t\t\tcolls, err = s.client.Database(dbName).ListCollectionNames(context.Background(), filter)\n\t\t\tif err != nil {\n\t\t\t\ts.log.Errorf(\"Error getting collection names: %s\", err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, colName := range colls {\n\t\t\t\tcolStatLine := &colStatsData{}\n\t\t\t\terr = s.runCommand(dbName, bson.D{\n\t\t\t\t\t{\n\t\t\t\t\t\tKey:   \"collStats\",\n\t\t\t\t\t\tValue: colName,\n\t\t\t\t\t},\n\t\t\t\t}, colStatLine)\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.authLog(fmt.Errorf(\"error getting col stats from %q: %w\", colName, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tcollection := &collection{\n\t\t\t\t\tName:         colName,\n\t\t\t\t\tDBName:       dbName,\n\t\t\t\t\tColStatsData: colStatLine,\n\t\t\t\t}\n\t\t\t\tresults.Collections = append(results.Collections, *collection)\n\t\t\t}\n\t\t}\n\t}\n\treturn results, nil\n}\n\nfunc (s *server) gatherData(acc telegraf.Accumulator, gatherClusterStatus, gatherDBStats, gatherColStats, gatherTopStat bool, colStatsDBs []string) error {\n\tserverStatus, err := s.gatherServerStatus()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Get replica set status, an error indicates that the server is not a\n\t// member of a replica set.\n\treplSetStatus, err := s.gatherReplSetStatus()\n\tif err != nil {\n\t\ts.log.Debugf(\"Unable to gather replica set status: %s\", err.Error())\n\t}\n\n\t// Gather the oplog if we are a member of a replica set.  Non-replica set\n\t// members do not have the oplog collections.\n\tvar oplogStats *oplogStats\n\tif replSetStatus != nil {\n\t\toplogStats, err = s.gatherOplogStats()\n\t\tif err != nil {\n\t\t\ts.authLog(fmt.Errorf(\"unable to get oplog stats: %w\", err))\n\t\t}\n\t}\n\n\tvar clusterStatus *clusterStatus\n\tif gatherClusterStatus {\n\t\tstatus, err := s.gatherClusterStatus()\n\t\tif err != nil {\n\t\t\ts.log.Debugf(\"Unable to gather cluster status: %s\", err.Error())\n\t\t}\n\t\tclusterStatus = status\n\t}\n\n\tshardStats, err := s.gatherShardConnPoolStats(serverStatus.Version)\n\tif err != nil {\n\t\ts.authLog(fmt.Errorf(\"unable to gather shard connection pool stats: %w\", err))\n\t}\n\n\tvar collectionStats *colStats\n\tif gatherColStats {\n\t\tstats, err := s.gatherCollectionStats(colStatsDBs)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcollectionStats = stats\n\t}\n\n\tdbStats := &dbStats{}\n\tif gatherDBStats {\n\t\tnames, err := s.client.ListDatabaseNames(context.Background(), bson.D{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, name := range names {\n\t\t\tdb, err := s.gatherDBStats(name)\n\t\t\tif err != nil {\n\t\t\t\ts.log.Errorf(\"Error getting db stats from %q: %v\", name, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdbStats.DBs = append(dbStats.DBs, *db)\n\t\t}\n\t}\n\n\ttopStatData := &topStats{}\n\tif gatherTopStat {\n\t\ttopStats, err := s.gatherTopStatData()\n\t\tif err != nil {\n\t\t\ts.log.Debugf(\"Unable to gather top stat data: %s\", err.Error())\n\t\t\treturn err\n\t\t}\n\t\ttopStatData = topStats\n\t}\n\n\tresult := &mongoStatus{\n\t\tServerStatus:  serverStatus,\n\t\tReplSetStatus: replSetStatus,\n\t\tClusterStatus: clusterStatus,\n\t\tDBStats:       dbStats,\n\t\tColStats:      collectionStats,\n\t\tShardStats:    shardStats,\n\t\tOplogStats:    oplogStats,\n\t\tTopStats:      topStatData,\n\t}\n\n\tresult.SampleTime = time.Now()\n\tif s.lastResult != nil {\n\t\tduration := result.SampleTime.Sub(s.lastResult.SampleTime)\n\t\tdurationInSeconds := int64(duration.Seconds())\n\t\tif durationInSeconds == 0 {\n\t\t\tdurationInSeconds = 1\n\t\t}\n\t\tdata := newMongodbData(\n\t\t\tnewStatLine(*s.lastResult, *result, s.hostname, durationInSeconds),\n\t\t\ts.getDefaultTags(),\n\t\t)\n\t\tdata.addDefaultStats()\n\t\tdata.addDBStats()\n\t\tdata.addColStats()\n\t\tdata.addShardHostStats()\n\t\tdata.addTopStats()\n\t\tdata.flush(acc)\n\t}\n\n\ts.lastResult = result\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongodb_server_test.go",
    "content": "package mongodb\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar servicePort = \"27017\"\nvar unreachableMongoEndpoint = \"mongodb://user:pass@127.0.0.1:27017/nop\"\n\nfunc createTestServer(t *testing.T) *testutil.Container {\n\tcontainer := testutil.Container{\n\t\tImage:        \"mongo\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForLog(\"Waiting for connections\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\n\treturn &container\n}\n\nfunc TestGetDefaultTagsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := createTestServer(t)\n\tdefer container.Terminate()\n\n\tm := &MongoDB{\n\t\tLog: testutil.Logger{},\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"mongodb://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t}\n\terr := m.Init()\n\trequire.NoError(t, err)\n\tvar acc testutil.Accumulator\n\terr = m.Start(&acc)\n\trequire.NoError(t, err)\n\n\tserver := m.clients[0]\n\n\tvar tagTests = []struct {\n\t\tin  string\n\t\tout string\n\t}{\n\t\t{\"hostname\", server.hostname},\n\t}\n\tdefaultTags := server.getDefaultTags()\n\tfor _, tt := range tagTests {\n\t\tif defaultTags[tt.in] != tt.out {\n\t\t\tt.Errorf(\"expected %q, got %q\", tt.out, defaultTags[tt.in])\n\t\t}\n\t}\n}\n\nfunc TestAddDefaultStatsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := createTestServer(t)\n\tdefer container.Terminate()\n\n\tm := &MongoDB{\n\t\tLog: testutil.Logger{},\n\t\tServers: []string{\n\t\t\tfmt.Sprintf(\"mongodb://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t},\n\t}\n\terr := m.Init()\n\trequire.NoError(t, err)\n\tvar acc testutil.Accumulator\n\terr = m.Start(&acc)\n\trequire.NoError(t, err)\n\n\tserver := m.clients[0]\n\n\terr = server.gatherData(&acc, false, true, true, true, []string{\"local\"})\n\trequire.NoError(t, err)\n\n\t// need to call this twice so it can perform the diff\n\terr = server.gatherData(&acc, false, true, true, true, []string{\"local\"})\n\trequire.NoError(t, err)\n\n\tfor key := range defaultStats {\n\t\trequire.True(t, acc.HasInt64Field(\"mongodb\", key))\n\t}\n}\n\n// Verify that when set to skip, telegraf will init, start, and collect while\n// ignoring connection errors.\nfunc TestSkipBehaviorIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tm := &MongoDB{\n\t\tLog:     &testutil.CaptureLogger{},\n\t\tServers: []string{unreachableMongoEndpoint},\n\t}\n\n\tm.DisconnectedServersBehavior = \"skip\"\n\terr := m.Init()\n\trequire.NoError(t, err)\n\tvar acc testutil.Accumulator\n\terr = m.Start(&acc)\n\trequire.NoError(t, err)\n\n\terr = m.Gather(&acc)\n\trequire.NoError(t, err)\n}\n\n// Verify that when set to error, telegraf will error out on start as expected\nfunc TestErrorBehaviorIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tm := &MongoDB{\n\t\tLog:                         &testutil.CaptureLogger{},\n\t\tServers:                     []string{unreachableMongoEndpoint},\n\t\tDisconnectedServersBehavior: \"error\",\n\t}\n\n\terr := m.Init()\n\trequire.NoError(t, err)\n\tvar acc testutil.Accumulator\n\terr = m.Start(&acc)\n\trequire.Error(t, err)\n}\n\nfunc TestPoolStatsVersionCompatibility(t *testing.T) {\n\ttests := []struct {\n\t\tname            string\n\t\tversion         string\n\t\texpectedCommand string\n\t\terr             bool\n\t}{\n\t\t{\n\t\t\tname:            \"mongodb v3\",\n\t\t\tversion:         \"3.0.0\",\n\t\t\texpectedCommand: \"shardConnPoolStats\",\n\t\t},\n\t\t{\n\t\t\tname:            \"mongodb v4\",\n\t\t\tversion:         \"4.0.0\",\n\t\t\texpectedCommand: \"shardConnPoolStats\",\n\t\t},\n\t\t{\n\t\t\tname:            \"mongodb v5\",\n\t\t\tversion:         \"5.0.0\",\n\t\t\texpectedCommand: \"connPoolStats\",\n\t\t},\n\t\t{\n\t\t\tname:            \"mongodb v6\",\n\t\t\tversion:         \"6.0.0\",\n\t\t\texpectedCommand: \"connPoolStats\",\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid version\",\n\t\t\tversion: \"v4\",\n\t\t\terr:     true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcommand, err := poolStatsCommand(test.version)\n\t\t\trequire.Equal(t, test.expectedCommand, command)\n\t\t\tif test.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongostat.go",
    "content": "// The code contained here came from https://github.com/mongodb/mongo-tools/blob/master/mongostat/stat_types.go\n// and contains modifications so that no other dependency from that project is needed. Other modifications included\n// removing unnecessary code specific to formatting the output and determine the current state of the database. It\n// is licensed under Apache Version 2.0, http://www.apache.org/licenses/LICENSE-2.0.html\n\npackage mongodb\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tmongosProcess = \"mongos\"\n)\n\ntype mongoStatus struct {\n\tSampleTime    time.Time\n\tServerStatus  *serverStatus\n\tReplSetStatus *replSetStatus\n\tClusterStatus *clusterStatus\n\tDBStats       *dbStats\n\tColStats      *colStats\n\tShardStats    *shardStats\n\tOplogStats    *oplogStats\n\tTopStats      *topStats\n}\n\ntype serverStatus struct {\n\tSampleTime         time.Time              `bson:\"\"`\n\tFlattened          map[string]interface{} `bson:\"\"`\n\tHost               string                 `bson:\"host\"`\n\tVersion            string                 `bson:\"version\"`\n\tProcess            string                 `bson:\"process\"`\n\tPid                int64                  `bson:\"pid\"`\n\tUptime             int64                  `bson:\"uptime\"`\n\tUptimeMillis       int64                  `bson:\"uptimeMillis\"`\n\tUptimeEstimate     int64                  `bson:\"uptimeEstimate\"`\n\tLocalTime          time.Time              `bson:\"localTime\"`\n\tAsserts            *assertsStats          `bson:\"asserts\"`\n\tBackgroundFlushing *flushStats            `bson:\"backgroundFlushing\"`\n\tExtraInfo          *extraInfo             `bson:\"extra_info\"`\n\tConnections        *connectionStats       `bson:\"connections\"`\n\tDur                *durStats              `bson:\"dur\"`\n\tGlobalLock         *globalLockStats       `bson:\"globalLock\"`\n\tLocks              map[string]lockStats   `bson:\"locks,omitempty\"`\n\tNetwork            *networkStats          `bson:\"network\"`\n\tOpcounters         *opcountStats          `bson:\"opcounters\"`\n\tOpcountersRepl     *opcountStats          `bson:\"opcountersRepl\"`\n\tOpLatencies        *opLatenciesStats      `bson:\"opLatencies\"`\n\tRecordStats        *dbRecordStats         `bson:\"recordStats\"`\n\tMem                *memStats              `bson:\"mem\"`\n\tRepl               *replStatus            `bson:\"repl\"`\n\tShardCursorType    map[string]interface{} `bson:\"shardCursorType\"`\n\tStorageEngine      *storageEngine         `bson:\"storageEngine\"`\n\tWiredTiger         *wiredTiger            `bson:\"wiredTiger\"`\n\tMetrics            *metricsStats          `bson:\"metrics\"`\n\tTCMallocStats      *tcMallocStats         `bson:\"tcmalloc\"`\n}\n\n// dbStats stores stats from all dbs\ntype dbStats struct {\n\tDBs []db\n}\n\n// db represent a single DB\ntype db struct {\n\tName        string\n\tDBStatsData *dbStatsData\n}\n\n// dbStatsData stores stats from a db\ntype dbStatsData struct {\n\tDB          string      `bson:\"db\"`\n\tCollections int64       `bson:\"collections\"`\n\tObjects     int64       `bson:\"objects\"`\n\tAvgObjSize  float64     `bson:\"avgObjSize\"`\n\tDataSize    int64       `bson:\"dataSize\"`\n\tStorageSize int64       `bson:\"storageSize\"`\n\tNumExtents  int64       `bson:\"numExtents\"`\n\tIndexes     int64       `bson:\"indexes\"`\n\tIndexSize   int64       `bson:\"indexSize\"`\n\tOk          int64       `bson:\"ok\"`\n\tGleStats    interface{} `bson:\"gleStats\"`\n\tFsUsedSize  int64       `bson:\"fsUsedSize\"`\n\tFsTotalSize int64       `bson:\"fsTotalSize\"`\n}\n\ntype colStats struct {\n\tCollections []collection\n}\n\ntype collection struct {\n\tName         string\n\tDBName       string\n\tColStatsData *colStatsData\n}\n\ntype colStatsData struct {\n\tCollection     string  `bson:\"ns\"`\n\tCount          int64   `bson:\"count\"`\n\tSize           int64   `bson:\"size\"`\n\tAvgObjSize     float64 `bson:\"avgObjSize\"`\n\tStorageSize    int64   `bson:\"storageSize\"`\n\tTotalIndexSize int64   `bson:\"totalIndexSize\"`\n\tOk             int64   `bson:\"ok\"`\n}\n\n// clusterStatus stores information related to the whole cluster\ntype clusterStatus struct {\n\tJumboChunksCount int64\n}\n\n// replSetStatus stores information from replSetGetStatus\ntype replSetStatus struct {\n\tMembers []replSetMember `bson:\"members\"`\n\tMyState int64           `bson:\"myState\"`\n}\n\n// oplogStats stores information from getReplicationInfo\ntype oplogStats struct {\n\tTimeDiff int64\n}\n\n// replSetMember stores information related to a replica set member\ntype replSetMember struct {\n\tName       string    `bson:\"name\"`\n\tHealth     int64     `bson:\"health\"`\n\tState      int64     `bson:\"state\"`\n\tStateStr   string    `bson:\"stateStr\"`\n\tOptimeDate time.Time `bson:\"optimeDate\"`\n}\n\n// wiredTiger stores information related to the wiredTiger storage engine.\ntype wiredTiger struct {\n\tTransaction transactionStats       `bson:\"transaction\"`\n\tConcurrent  concurrentTransactions `bson:\"concurrentTransactions\"`\n\tCache       cacheStats             `bson:\"cache\"`\n\tConnection  wtConnectionStats      `bson:\"connection\"`\n\tDataHandle  dataHandleStats        `bson:\"data-handle\"`\n}\n\n// shardStats stores information from shardConnPoolStats.\ntype shardStats struct {\n\tshardStatsData `bson:\",inline\"`\n\tHosts          map[string]shardHostStatsData `bson:\"hosts\"`\n}\n\n// shardStatsData is the total Shard Stats from shardConnPoolStats database command.\ntype shardStatsData struct {\n\tTotalInUse      int64 `bson:\"totalInUse\"`\n\tTotalAvailable  int64 `bson:\"totalAvailable\"`\n\tTotalCreated    int64 `bson:\"totalCreated\"`\n\tTotalRefreshing int64 `bson:\"totalRefreshing\"`\n}\n\n// shardHostStatsData is the host-specific stats from shardConnPoolStats database command.\ntype shardHostStatsData struct {\n\tInUse      int64 `bson:\"inUse\"`\n\tAvailable  int64 `bson:\"available\"`\n\tCreated    int64 `bson:\"created\"`\n\tRefreshing int64 `bson:\"refreshing\"`\n}\n\ntype topStats struct {\n\tTotals map[string]topStatCollection `bson:\"totals\"`\n}\n\ntype topStatCollection struct {\n\tTotal     topStatCollectionData `bson:\"total\"`\n\tReadLock  topStatCollectionData `bson:\"readLock\"`\n\tWriteLock topStatCollectionData `bson:\"writeLock\"`\n\tQueries   topStatCollectionData `bson:\"queries\"`\n\tGetMore   topStatCollectionData `bson:\"getmore\"`\n\tInsert    topStatCollectionData `bson:\"insert\"`\n\tUpdate    topStatCollectionData `bson:\"update\"`\n\tRemove    topStatCollectionData `bson:\"remove\"`\n\tCommands  topStatCollectionData `bson:\"commands\"`\n}\n\ntype topStatCollectionData struct {\n\tTime  int64 `bson:\"time\"`\n\tCount int64 `bson:\"count\"`\n}\n\ntype concurrentTransactions struct {\n\tWrite concurrentTransStats `bson:\"write\"`\n\tRead  concurrentTransStats `bson:\"read\"`\n}\n\ntype concurrentTransStats struct {\n\tOut          int64 `bson:\"out\"`\n\tAvailable    int64 `bson:\"available\"`\n\tTotalTickets int64 `bson:\"totalTickets\"`\n}\n\n// assertsStats stores information related to assertions raised since the MongoDB process started\ntype assertsStats struct {\n\tRegular   int64 `bson:\"regular\"`\n\tWarning   int64 `bson:\"warning\"`\n\tMsg       int64 `bson:\"msg\"`\n\tUser      int64 `bson:\"user\"`\n\tRollovers int64 `bson:\"rollovers\"`\n}\n\n// cacheStats stores cache statistics for wiredTiger.\ntype cacheStats struct {\n\tTrackedDirtyBytes         int64 `bson:\"tracked dirty bytes in the cache\"`\n\tCurrentCachedBytes        int64 `bson:\"bytes currently in the cache\"`\n\tMaxBytesConfigured        int64 `bson:\"maximum bytes configured\"`\n\tAppThreadsPageReadCount   int64 `bson:\"application threads page read from disk to cache count\"`\n\tAppThreadsPageReadTime    int64 `bson:\"application threads page read from disk to cache time (usecs)\"`\n\tAppThreadsPageWriteCount  int64 `bson:\"application threads page write from cache to disk count\"`\n\tAppThreadsPageWriteTime   int64 `bson:\"application threads page write from cache to disk time (usecs)\"`\n\tBytesWrittenFrom          int64 `bson:\"bytes written from cache\"`\n\tBytesReadInto             int64 `bson:\"bytes read into cache\"`\n\tPagesEvictedByAppThread   int64 `bson:\"pages evicted by application threads\"`\n\tPagesQueuedForEviction    int64 `bson:\"pages queued for eviction\"`\n\tPagesReadIntoCache        int64 `bson:\"pages read into cache\"`\n\tPagesWrittenFromCache     int64 `bson:\"pages written from cache\"`\n\tPagesRequestedFromCache   int64 `bson:\"pages requested from the cache\"`\n\tServerEvictingPages       int64 `bson:\"eviction server evicting pages\"`\n\tWorkerThreadEvictingPages int64 `bson:\"eviction worker thread evicting pages\"`\n\tInternalPagesEvicted      int64 `bson:\"internal pages evicted\"`\n\tModifiedPagesEvicted      int64 `bson:\"modified pages evicted\"`\n\tUnmodifiedPagesEvicted    int64 `bson:\"unmodified pages evicted\"`\n}\n\ntype storageEngine struct {\n\tName string `bson:\"name\"`\n}\n\n// transactionStats stores transaction checkpoints in wiredTiger.\ntype transactionStats struct {\n\tTransCheckpointsTotalTimeMsecs int64 `bson:\"transaction checkpoint total time (msecs)\"`\n\tTransCheckpoints               int64 `bson:\"transaction checkpoints\"`\n}\n\n// wtConnectionStats stores statistics on wiredTiger connections\ntype wtConnectionStats struct {\n\tFilesCurrentlyOpen int64 `bson:\"files currently open\"`\n}\n\n// dataHandleStats stores statistics for wiredTiger data-handles\ntype dataHandleStats struct {\n\tDataHandlesCurrentlyActive int64 `bson:\"connection data handles currently active\"`\n}\n\n// replStatus stores data related to replica sets.\ntype replStatus struct {\n\tSetName           string      `bson:\"setName\"`\n\tIsWritablePrimary interface{} `bson:\"isWritablePrimary\"` // mongodb 5.x\n\tIsMaster          interface{} `bson:\"ismaster\"`\n\tSecondary         interface{} `bson:\"secondary\"`\n\tIsReplicaSet      interface{} `bson:\"isreplicaset\"`\n\tArbiterOnly       interface{} `bson:\"arbiterOnly\"`\n\tHosts             []string    `bson:\"hosts\"`\n\tPassives          []string    `bson:\"passives\"`\n\tMe                string      `bson:\"me\"`\n}\n\n// dbRecordStats stores data related to memory operations across databases.\ntype dbRecordStats struct {\n\tAccessesNotInMemory       int64                     `bson:\"accessesNotInMemory\"`\n\tPageFaultExceptionsThrown int64                     `bson:\"pageFaultExceptionsThrown\"`\n\tDBRecordAccesses          map[string]recordAccesses `bson:\",inline\"`\n}\n\n// recordAccesses stores data related to memory operations scoped to a database.\ntype recordAccesses struct {\n\tAccessesNotInMemory       int64 `bson:\"accessesNotInMemory\"`\n\tPageFaultExceptionsThrown int64 `bson:\"pageFaultExceptionsThrown\"`\n}\n\n// memStats stores data related to memory statistics.\ntype memStats struct {\n\tBits              int64       `bson:\"bits\"`\n\tResident          int64       `bson:\"resident\"`\n\tVirtual           int64       `bson:\"virtual\"`\n\tSupported         interface{} `bson:\"supported\"`\n\tMapped            int64       `bson:\"mapped\"`\n\tMappedWithJournal int64       `bson:\"mappedWithJournal\"`\n}\n\n// flushStats stores information about memory flushes.\ntype flushStats struct {\n\tFlushes      int64     `bson:\"flushes\"`\n\tTotalMs      int64     `bson:\"total_ms\"`\n\tAverageMs    float64   `bson:\"average_ms\"`\n\tLastMs       int64     `bson:\"last_ms\"`\n\tLastFinished time.Time `bson:\"last_finished\"`\n}\n\n// connectionStats stores information related to incoming database connections.\ntype connectionStats struct {\n\tCurrent      int64 `bson:\"current\"`\n\tAvailable    int64 `bson:\"available\"`\n\tTotalCreated int64 `bson:\"totalCreated\"`\n}\n\n// durTiming stores information related to journaling.\ntype durTiming struct {\n\tDt               int64 `bson:\"dt\"`\n\tPrepLogBuffer    int64 `bson:\"prepLogBuffer\"`\n\tWriteToJournal   int64 `bson:\"writeToJournal\"`\n\tWriteToDataFiles int64 `bson:\"writeToDataFiles\"`\n\tRemapPrivateView int64 `bson:\"remapPrivateView\"`\n}\n\n// durStats stores information related to journaling statistics.\ntype durStats struct {\n\tCommits            float64 `bson:\"commits\"`\n\tJournaledMB        float64 `bson:\"journaledMB\"`\n\tWriteToDataFilesMB float64 `bson:\"writeToDataFilesMB\"`\n\tCompression        float64 `bson:\"compression\"`\n\tCommitsInWriteLock float64 `bson:\"commitsInWriteLock\"`\n\tEarlyCommits       float64 `bson:\"earlyCommits\"`\n\tTimeMs             durTiming\n}\n\n// queueStats stores the number of queued read/write operations.\ntype queueStats struct {\n\tTotal   int64 `bson:\"total\"`\n\tReaders int64 `bson:\"readers\"`\n\tWriters int64 `bson:\"writers\"`\n}\n\n// clientStats stores the number of active read/write operations.\ntype clientStats struct {\n\tTotal   int64 `bson:\"total\"`\n\tReaders int64 `bson:\"readers\"`\n\tWriters int64 `bson:\"writers\"`\n}\n\n// globalLockStats stores information related locks in the MMAP storage engine.\ntype globalLockStats struct {\n\tTotalTime     int64        `bson:\"totalTime\"`\n\tLockTime      int64        `bson:\"lockTime\"`\n\tCurrentQueue  *queueStats  `bson:\"currentQueue\"`\n\tActiveClients *clientStats `bson:\"activeClients\"`\n}\n\n// networkStats stores information related to network traffic.\ntype networkStats struct {\n\tBytesIn     int64 `bson:\"bytesIn\"`\n\tBytesOut    int64 `bson:\"bytesOut\"`\n\tNumRequests int64 `bson:\"numRequests\"`\n}\n\n// opcountStats stores information related to commands and basic CRUD operations.\ntype opcountStats struct {\n\tInsert  int64 `bson:\"insert\"`\n\tQuery   int64 `bson:\"query\"`\n\tUpdate  int64 `bson:\"update\"`\n\tDelete  int64 `bson:\"delete\"`\n\tGetMore int64 `bson:\"getmore\"`\n\tCommand int64 `bson:\"command\"`\n}\n\n// opLatenciesStats stores information related to operation latencies for the database as a whole\ntype opLatenciesStats struct {\n\tReads    *latencyStats `bson:\"reads\"`\n\tWrites   *latencyStats `bson:\"writes\"`\n\tCommands *latencyStats `bson:\"commands\"`\n}\n\n// latencyStats lists total latency in microseconds and count of operations, enabling you to obtain an average\ntype latencyStats struct {\n\tLatency int64 `bson:\"latency\"`\n\tOps     int64 `bson:\"ops\"`\n}\n\n// metricsStats stores information related to metrics\ntype metricsStats struct {\n\tTTL           *ttlStats           `bson:\"ttl\"`\n\tCursor        *cursorStats        `bson:\"cursor\"`\n\tDocument      *documentStats      `bson:\"document\"`\n\tCommands      *commandsStats      `bson:\"commands\"`\n\tOperation     *operationStats     `bson:\"operation\"`\n\tQueryExecutor *queryExecutorStats `bson:\"queryExecutor\"`\n\tRepl          *replStats          `bson:\"repl\"`\n\tStorage       *storageStats       `bson:\"storage\"`\n}\n\n// ttlStats stores information related to documents with a ttl index.\ntype ttlStats struct {\n\tDeletedDocuments int64 `bson:\"deletedDocuments\"`\n\tPasses           int64 `bson:\"passes\"`\n}\n\n// cursorStats stores information related to cursor metrics.\ntype cursorStats struct {\n\tTimedOut int64            `bson:\"timedOut\"`\n\tOpen     *openCursorStats `bson:\"open\"`\n}\n\n// documentStats stores information related to document metrics.\ntype documentStats struct {\n\tDeleted  int64 `bson:\"deleted\"`\n\tInserted int64 `bson:\"inserted\"`\n\tReturned int64 `bson:\"returned\"`\n\tUpdated  int64 `bson:\"updated\"`\n}\n\n// commandsStats stores information related to document metrics.\ntype commandsStats struct {\n\tAggregate     *commandsStatsValue `bson:\"aggregate\"`\n\tCount         *commandsStatsValue `bson:\"count\"`\n\tDelete        *commandsStatsValue `bson:\"delete\"`\n\tDistinct      *commandsStatsValue `bson:\"distinct\"`\n\tFind          *commandsStatsValue `bson:\"find\"`\n\tFindAndModify *commandsStatsValue `bson:\"findAndModify\"`\n\tGetMore       *commandsStatsValue `bson:\"getMore\"`\n\tInsert        *commandsStatsValue `bson:\"insert\"`\n\tUpdate        *commandsStatsValue `bson:\"update\"`\n}\n\ntype commandsStatsValue struct {\n\tFailed int64 `bson:\"failed\"`\n\tTotal  int64 `bson:\"total\"`\n}\n\n// openCursorStats stores information related to open cursor metrics\ntype openCursorStats struct {\n\tNoTimeout int64 `bson:\"noTimeout\"`\n\tPinned    int64 `bson:\"pinned\"`\n\tTotal     int64 `bson:\"total\"`\n}\n\n// operationStats stores information related to query operations\n// using special operation types\ntype operationStats struct {\n\tScanAndOrder   int64 `bson:\"scanAndOrder\"`\n\tWriteConflicts int64 `bson:\"writeConflicts\"`\n}\n\n// queryExecutorStats stores information related to query execution\ntype queryExecutorStats struct {\n\tScanned        int64 `bson:\"scanned\"`\n\tScannedObjects int64 `bson:\"scannedObjects\"`\n}\n\n// replStats stores information related to replication process\ntype replStats struct {\n\tApply    *replApplyStats    `bson:\"apply\"`\n\tBuffer   *replBufferStats   `bson:\"buffer\"`\n\tExecutor *replExecutorStats `bson:\"executor,omitempty\"`\n\tNetwork  *replNetworkStats  `bson:\"network\"`\n}\n\n// replApplyStats stores information related to oplog application process\ntype replApplyStats struct {\n\tBatches *basicStats `bson:\"batches\"`\n\tOps     int64       `bson:\"ops\"`\n}\n\n// replBufferStats stores information related to oplog buffer\ntype replBufferStats struct {\n\tCount     int64 `bson:\"count\"`\n\tSizeBytes int64 `bson:\"sizeBytes\"`\n}\n\n// replExecutorStats stores information related to replication executor\ntype replExecutorStats struct {\n\tPool             map[string]int64 `bson:\"pool\"`\n\tQueues           map[string]int64 `bson:\"queues\"`\n\tUnsignaledEvents int64            `bson:\"unsignaledEvents\"`\n}\n\n// replNetworkStats stores information related to network usage by replication process\ntype replNetworkStats struct {\n\tBytes    int64       `bson:\"bytes\"`\n\tGetMores *basicStats `bson:\"getmores\"`\n\tOps      int64       `bson:\"ops\"`\n}\n\n// basicStats stores information about an operation\ntype basicStats struct {\n\tNum         int64 `bson:\"num\"`\n\tTotalMillis int64 `bson:\"totalMillis\"`\n}\n\n// readWriteLockTimes stores time spent holding read/write locks.\ntype readWriteLockTimes struct {\n\tRead       int64 `bson:\"R\"`\n\tWrite      int64 `bson:\"W\"`\n\tReadLower  int64 `bson:\"r\"`\n\tWriteLower int64 `bson:\"w\"`\n}\n\n// lockStats stores information related to time spent acquiring/holding locks for a given database.\ntype lockStats struct {\n\tTimeLockedMicros    readWriteLockTimes `bson:\"timeLockedMicros\"`\n\tTimeAcquiringMicros readWriteLockTimes `bson:\"timeAcquiringMicros\"`\n\n\t// AcquireCount and AcquireWaitCount are new fields of the lock stats only populated on 3.0 or newer.\n\t// Typed as a pointer so that if it is nil, mongostat can assume the field is not populated\n\t// with real namespace data.\n\tAcquireCount     *readWriteLockTimes `bson:\"acquireCount,omitempty\"`\n\tAcquireWaitCount *readWriteLockTimes `bson:\"acquireWaitCount,omitempty\"`\n}\n\n// extraInfo stores additional platform specific information.\ntype extraInfo struct {\n\tPageFaults *int64 `bson:\"page_faults\"`\n}\n\n// tcMallocStats stores information related to TCMalloc memory allocator metrics\ntype tcMallocStats struct {\n\tGeneric  *genericTCMAllocStats  `bson:\"generic\"`\n\tTCMalloc *detailedTCMallocStats `bson:\"tcmalloc\"`\n}\n\n// genericTCMAllocStats stores generic TCMalloc memory allocator metrics\ntype genericTCMAllocStats struct {\n\tCurrentAllocatedBytes int64 `bson:\"current_allocated_bytes\"`\n\tHeapSize              int64 `bson:\"heap_size\"`\n}\n\n// detailedTCMallocStats stores detailed TCMalloc memory allocator metrics\ntype detailedTCMallocStats struct {\n\tPageheapFreeBytes            int64 `bson:\"pageheap_free_bytes\"`\n\tPageheapUnmappedBytes        int64 `bson:\"pageheap_unmapped_bytes\"`\n\tMaxTotalThreadCacheBytes     int64 `bson:\"max_total_thread_cache_bytes\"`\n\tCurrentTotalThreadCacheBytes int64 `bson:\"current_total_thread_cache_bytes\"`\n\tTotalFreeBytes               int64 `bson:\"total_free_bytes\"`\n\tCentralCacheFreeBytes        int64 `bson:\"central_cache_free_bytes\"`\n\tTransferCacheFreeBytes       int64 `bson:\"transfer_cache_free_bytes\"`\n\tThreadCacheFreeBytes         int64 `bson:\"thread_cache_free_bytes\"`\n\tPageheapComittedBytes        int64 `bson:\"pageheap_committed_bytes\"`\n\tPageheapScavengeCount        int64 `bson:\"pageheap_scavenge_count\"`\n\tPageheapCommitCount          int64 `bson:\"pageheap_commit_count\"`\n\tPageheapTotalCommitBytes     int64 `bson:\"pageheap_total_commit_bytes\"`\n\tPageheapDecommitCount        int64 `bson:\"pageheap_decommit_count\"`\n\tPageheapTotalDecommitBytes   int64 `bson:\"pageheap_total_decommit_bytes\"`\n\tPageheapReserveCount         int64 `bson:\"pageheap_reserve_count\"`\n\tPageheapTotalReserveBytes    int64 `bson:\"pageheap_total_reserve_bytes\"`\n\tSpinLockTotalDelayNanos      int64 `bson:\"spinlock_total_delay_ns\"`\n}\n\n// storageStats stores information related to record allocations\ntype storageStats struct {\n\tFreelistSearchBucketExhausted int64 `bson:\"freelist.search.bucketExhausted\"`\n\tFreelistSearchRequests        int64 `bson:\"freelist.search.requests\"`\n\tFreelistSearchScanned         int64 `bson:\"freelist.search.scanned\"`\n}\n\n// lockUsage stores information related to a namespace's lock usage.\ntype lockUsage struct {\n\tNamespace string\n\tReads     int64\n\tWrites    int64\n}\n\ntype lockUsages []lockUsage\n\nfunc percentageInt64(value, outOf int64) float64 {\n\tif value == 0 || outOf == 0 {\n\t\treturn 0\n\t}\n\treturn 100 * (float64(value) / float64(outOf))\n}\n\nfunc averageInt64(value, outOf int64) int64 {\n\tif value == 0 || outOf == 0 {\n\t\treturn 0\n\t}\n\treturn value / outOf\n}\n\nfunc (slice lockUsages) Len() int {\n\treturn len(slice)\n}\n\nfunc (slice lockUsages) Less(i, j int) bool {\n\treturn slice[i].Reads+slice[i].Writes < slice[j].Reads+slice[j].Writes\n}\n\nfunc (slice lockUsages) Swap(i, j int) {\n\tslice[i], slice[j] = slice[j], slice[i]\n}\n\n// collectionLockStatus stores a collection's lock statistics.\ntype collectionLockStatus struct {\n\tReadAcquireWaitsPercentage  float64\n\tWriteAcquireWaitsPercentage float64\n\tReadAcquireTimeMicros       int64\n\tWriteAcquireTimeMicros      int64\n}\n\n// lockStatus stores a database's lock statistics.\ntype lockStatus struct {\n\tDBName     string\n\tPercentage float64\n\tGlobal     bool\n}\n\n// statLine is a wrapper for all metrics reported by mongostat for monitored hosts.\ntype statLine struct {\n\tKey string\n\t// What storage engine is being used for the node with this stat line\n\tStorageEngine string\n\n\tError    error\n\tIsMongos bool\n\tHost     string\n\tVersion  string\n\n\tUptimeNanos int64\n\n\t// The time at which this statLine was generated.\n\tTime time.Time\n\n\t// The last time at which this statLine was printed to output.\n\tLastPrinted time.Time\n\n\t// Opcounter fields\n\tInsert, InsertCnt   int64\n\tQuery, QueryCnt     int64\n\tUpdate, UpdateCnt   int64\n\tDelete, DeleteCnt   int64\n\tGetMore, GetMoreCnt int64\n\tCommand, CommandCnt int64\n\n\t// Asserts fields\n\tRegular   int64\n\tWarning   int64\n\tMsg       int64\n\tUser      int64\n\tRollovers int64\n\n\t// OpLatency fields\n\tWriteOpsCnt    int64\n\tWriteLatency   int64\n\tReadOpsCnt     int64\n\tReadLatency    int64\n\tCommandOpsCnt  int64\n\tCommandLatency int64\n\n\t// TTL fields\n\tPasses, PassesCnt                     int64\n\tDeletedDocuments, DeletedDocumentsCnt int64\n\n\t// Cursor fields\n\tTimedOutC, TimedOutCCnt   int64\n\tNoTimeoutC, NoTimeoutCCnt int64\n\tPinnedC, PinnedCCnt       int64\n\tTotalC, TotalCCnt         int64\n\n\t// Document fields\n\tDeletedD, InsertedD, ReturnedD, UpdatedD int64\n\n\t// Commands fields\n\tAggregateCommandTotal, AggregateCommandFailed         int64\n\tCountCommandTotal, CountCommandFailed                 int64\n\tDeleteCommandTotal, DeleteCommandFailed               int64\n\tDistinctCommandTotal, DistinctCommandFailed           int64\n\tFindCommandTotal, FindCommandFailed                   int64\n\tFindAndModifyCommandTotal, FindAndModifyCommandFailed int64\n\tGetMoreCommandTotal, GetMoreCommandFailed             int64\n\tInsertCommandTotal, InsertCommandFailed               int64\n\tUpdateCommandTotal, UpdateCommandFailed               int64\n\n\t// Operation fields\n\tScanAndOrderOp, WriteConflictsOp int64\n\n\t// Query Executor fields\n\tTotalKeysScanned, TotalObjectsScanned int64\n\n\t// Connection fields\n\tCurrentC, AvailableC, TotalCreatedC int64\n\n\t// Collection locks (3.0 mmap only)\n\tCollectionLocks *collectionLockStatus\n\n\t// Cache utilization (wiredtiger only)\n\tCacheDirtyPercent float64\n\tCacheUsedPercent  float64\n\n\t// Cache utilization extended (wiredtiger only)\n\tTrackedDirtyBytes         int64\n\tCurrentCachedBytes        int64\n\tMaxBytesConfigured        int64\n\tAppThreadsPageReadCount   int64\n\tAppThreadsPageReadTime    int64\n\tAppThreadsPageWriteCount  int64\n\tBytesWrittenFrom          int64\n\tBytesReadInto             int64\n\tPagesEvictedByAppThread   int64\n\tPagesQueuedForEviction    int64\n\tPagesReadIntoCache        int64\n\tPagesWrittenFromCache     int64\n\tPagesRequestedFromCache   int64\n\tServerEvictingPages       int64\n\tWorkerThreadEvictingPages int64\n\tInternalPagesEvicted      int64\n\tModifiedPagesEvicted      int64\n\tUnmodifiedPagesEvicted    int64\n\n\t// Connection statistics (wiredtiger only)\n\tFilesCurrentlyOpen int64\n\n\t// Data handles statistics (wiredtiger only)\n\tDataHandlesCurrentlyActive int64\n\n\t// Replicated Opcounter fields\n\tInsertR, InsertRCnt                      int64\n\tQueryR, QueryRCnt                        int64\n\tUpdateR, UpdateRCnt                      int64\n\tDeleteR, DeleteRCnt                      int64\n\tGetMoreR, GetMoreRCnt                    int64\n\tCommandR, CommandRCnt                    int64\n\tReplLag                                  int64\n\tOplogStats                               *oplogStats\n\tFlushes, FlushesCnt                      int64\n\tFlushesTotalTime                         int64\n\tMapped, Virtual, Resident, NonMapped     int64\n\tFaults, FaultsCnt                        int64\n\tHighestLocked                            *lockStatus\n\tQueuedReaders, QueuedWriters             int64\n\tActiveReaders, ActiveWriters             int64\n\tAvailableReaders, AvailableWriters       int64\n\tTotalTicketsReaders, TotalTicketsWriters int64\n\tNetIn, NetInCnt                          int64\n\tNetOut, NetOutCnt                        int64\n\tNumConnections                           int64\n\tReplSetName                              string\n\tReplHealthAvg                            float64\n\tNodeType                                 string\n\tNodeState                                string\n\tNodeStateInt                             int64\n\tNodeHealthInt                            int64\n\n\t// Replicated Metrics fields\n\tReplNetworkBytes                    int64\n\tReplNetworkGetmoresNum              int64\n\tReplNetworkGetmoresTotalMillis      int64\n\tReplNetworkOps                      int64\n\tReplBufferCount                     int64\n\tReplBufferSizeBytes                 int64\n\tReplApplyBatchesNum                 int64\n\tReplApplyBatchesTotalMillis         int64\n\tReplApplyOps                        int64\n\tReplExecutorPoolInProgressCount     int64\n\tReplExecutorQueuesNetworkInProgress int64\n\tReplExecutorQueuesSleepers          int64\n\tReplExecutorUnsignaledEvents        int64\n\n\t// Cluster fields\n\tJumboChunksCount int64\n\n\t// DB stats field\n\tDBStatsLines []dbStatLine\n\n\t// Col Stats field\n\tColStatsLines []colStatLine\n\n\t// Shard stats\n\tTotalInUse, TotalAvailable, TotalCreated, TotalRefreshing int64\n\n\t// Shard Hosts stats field\n\tShardHostStatsLines map[string]shardHostStatLine\n\n\tTopStatLines []topStatLine\n\n\t// TCMalloc stats field\n\tTCMallocCurrentAllocatedBytes        int64\n\tTCMallocHeapSize                     int64\n\tTCMallocCentralCacheFreeBytes        int64\n\tTCMallocCurrentTotalThreadCacheBytes int64\n\tTCMallocMaxTotalThreadCacheBytes     int64\n\tTCMallocTotalFreeBytes               int64\n\tTCMallocTransferCacheFreeBytes       int64\n\tTCMallocThreadCacheFreeBytes         int64\n\tTCMallocSpinLockTotalDelayNanos      int64\n\tTCMallocPageheapFreeBytes            int64\n\tTCMallocPageheapUnmappedBytes        int64\n\tTCMallocPageheapComittedBytes        int64\n\tTCMallocPageheapScavengeCount        int64\n\tTCMallocPageheapCommitCount          int64\n\tTCMallocPageheapTotalCommitBytes     int64\n\tTCMallocPageheapDecommitCount        int64\n\tTCMallocPageheapTotalDecommitBytes   int64\n\tTCMallocPageheapReserveCount         int64\n\tTCMallocPageheapTotalReserveBytes    int64\n\n\t// Storage stats field\n\tStorageFreelistSearchBucketExhausted int64\n\tStorageFreelistSearchRequests        int64\n\tStorageFreelistSearchScanned         int64\n}\n\ntype dbStatLine struct {\n\tName        string\n\tCollections int64\n\tObjects     int64\n\tAvgObjSize  float64\n\tDataSize    int64\n\tStorageSize int64\n\tNumExtents  int64\n\tIndexes     int64\n\tIndexSize   int64\n\tOk          int64\n\tFsUsedSize  int64\n\tFsTotalSize int64\n}\ntype colStatLine struct {\n\tName           string\n\tDBName         string\n\tCount          int64\n\tSize           int64\n\tAvgObjSize     float64\n\tStorageSize    int64\n\tTotalIndexSize int64\n\tOk             int64\n}\n\ntype shardHostStatLine struct {\n\tInUse      int64\n\tAvailable  int64\n\tCreated    int64\n\tRefreshing int64\n}\n\ntype topStatLine struct {\n\tCollectionName                string\n\tTotalTime, TotalCount         int64\n\tReadLockTime, ReadLockCount   int64\n\tWriteLockTime, WriteLockCount int64\n\tQueriesTime, QueriesCount     int64\n\tGetMoreTime, GetMoreCount     int64\n\tInsertTime, InsertCount       int64\n\tUpdateTime, UpdateCount       int64\n\tRemoveTime, RemoveCount       int64\n\tCommandsTime, CommandsCount   int64\n}\n\nfunc parseLocks(stat serverStatus) map[string]lockUsage {\n\treturnVal := make(map[string]lockUsage, len(stat.Locks))\n\tfor namespace, lockInfo := range stat.Locks {\n\t\treturnVal[namespace] = lockUsage{\n\t\t\tnamespace,\n\t\t\tlockInfo.TimeLockedMicros.Read + lockInfo.TimeLockedMicros.ReadLower,\n\t\t\tlockInfo.TimeLockedMicros.Write + lockInfo.TimeLockedMicros.WriteLower,\n\t\t}\n\t}\n\treturn returnVal\n}\n\nfunc computeLockDiffs(prevLocks, curLocks map[string]lockUsage) []lockUsage {\n\tlockUsages := lockUsages(make([]lockUsage, 0, len(curLocks)))\n\tfor namespace, curUsage := range curLocks {\n\t\tprevUsage, hasKey := prevLocks[namespace]\n\t\tif !hasKey {\n\t\t\t// This namespace didn't appear in the previous batch of lock info,\n\t\t\t// so we can't compute a diff for it - skip it.\n\t\t\tcontinue\n\t\t}\n\t\t// Calculate diff of lock usage for this namespace and add to the list\n\t\tlockUsages = append(lockUsages,\n\t\t\tlockUsage{\n\t\t\t\tnamespace,\n\t\t\t\tcurUsage.Reads - prevUsage.Reads,\n\t\t\t\tcurUsage.Writes - prevUsage.Writes,\n\t\t\t})\n\t}\n\t// Sort the array in order of least to most locked\n\tsort.Sort(lockUsages)\n\treturn lockUsages\n}\n\nfunc diff(newVal, oldVal, sampleTime int64) (avg, newValue int64) {\n\td := newVal - oldVal\n\tif d < 0 {\n\t\td = newVal\n\t}\n\treturn d / sampleTime, newVal\n}\n\n// newStatLine constructs a statLine object from two mongoStatus objects.\nfunc newStatLine(oldMongo, newMongo mongoStatus, key string, sampleSecs int64) *statLine {\n\toldStat := *oldMongo.ServerStatus\n\tnewStat := *newMongo.ServerStatus\n\n\treturnVal := &statLine{\n\t\tKey:       key,\n\t\tHost:      newStat.Host,\n\t\tVersion:   newStat.Version,\n\t\tMapped:    -1,\n\t\tVirtual:   -1,\n\t\tResident:  -1,\n\t\tNonMapped: -1,\n\t\tFaults:    -1,\n\t}\n\n\treturnVal.UptimeNanos = 1000 * 1000 * newStat.UptimeMillis\n\n\t// set connection info\n\treturnVal.CurrentC = newStat.Connections.Current\n\treturnVal.AvailableC = newStat.Connections.Available\n\treturnVal.TotalCreatedC = newStat.Connections.TotalCreated\n\n\t// set the storage engine appropriately\n\tif newStat.StorageEngine != nil && newStat.StorageEngine.Name != \"\" {\n\t\treturnVal.StorageEngine = newStat.StorageEngine.Name\n\t} else {\n\t\treturnVal.StorageEngine = \"mmapv1\"\n\t}\n\n\tif newStat.Opcounters != nil && oldStat.Opcounters != nil {\n\t\treturnVal.Insert, returnVal.InsertCnt = diff(newStat.Opcounters.Insert, oldStat.Opcounters.Insert, sampleSecs)\n\t\treturnVal.Query, returnVal.QueryCnt = diff(newStat.Opcounters.Query, oldStat.Opcounters.Query, sampleSecs)\n\t\treturnVal.Update, returnVal.UpdateCnt = diff(newStat.Opcounters.Update, oldStat.Opcounters.Update, sampleSecs)\n\t\treturnVal.Delete, returnVal.DeleteCnt = diff(newStat.Opcounters.Delete, oldStat.Opcounters.Delete, sampleSecs)\n\t\treturnVal.GetMore, returnVal.GetMoreCnt = diff(newStat.Opcounters.GetMore, oldStat.Opcounters.GetMore, sampleSecs)\n\t\treturnVal.Command, returnVal.CommandCnt = diff(newStat.Opcounters.Command, oldStat.Opcounters.Command, sampleSecs)\n\t}\n\n\tif newStat.OpLatencies != nil {\n\t\tif newStat.OpLatencies.Reads != nil {\n\t\t\treturnVal.ReadOpsCnt = newStat.OpLatencies.Reads.Ops\n\t\t\treturnVal.ReadLatency = newStat.OpLatencies.Reads.Latency\n\t\t}\n\t\tif newStat.OpLatencies.Writes != nil {\n\t\t\treturnVal.WriteOpsCnt = newStat.OpLatencies.Writes.Ops\n\t\t\treturnVal.WriteLatency = newStat.OpLatencies.Writes.Latency\n\t\t}\n\t\tif newStat.OpLatencies.Commands != nil {\n\t\t\treturnVal.CommandOpsCnt = newStat.OpLatencies.Commands.Ops\n\t\t\treturnVal.CommandLatency = newStat.OpLatencies.Commands.Latency\n\t\t}\n\t}\n\n\tif newStat.Asserts != nil {\n\t\treturnVal.Regular = newStat.Asserts.Regular\n\t\treturnVal.Warning = newStat.Asserts.Warning\n\t\treturnVal.Msg = newStat.Asserts.Msg\n\t\treturnVal.User = newStat.Asserts.User\n\t\treturnVal.Rollovers = newStat.Asserts.Rollovers\n\t}\n\n\tif newStat.TCMallocStats != nil {\n\t\tif newStat.TCMallocStats.Generic != nil {\n\t\t\treturnVal.TCMallocCurrentAllocatedBytes = newStat.TCMallocStats.Generic.CurrentAllocatedBytes\n\t\t\treturnVal.TCMallocHeapSize = newStat.TCMallocStats.Generic.HeapSize\n\t\t}\n\t\tif newStat.TCMallocStats.TCMalloc != nil {\n\t\t\treturnVal.TCMallocCentralCacheFreeBytes = newStat.TCMallocStats.TCMalloc.CentralCacheFreeBytes\n\t\t\treturnVal.TCMallocCurrentTotalThreadCacheBytes = newStat.TCMallocStats.TCMalloc.CurrentTotalThreadCacheBytes\n\t\t\treturnVal.TCMallocMaxTotalThreadCacheBytes = newStat.TCMallocStats.TCMalloc.MaxTotalThreadCacheBytes\n\t\t\treturnVal.TCMallocTransferCacheFreeBytes = newStat.TCMallocStats.TCMalloc.TransferCacheFreeBytes\n\t\t\treturnVal.TCMallocThreadCacheFreeBytes = newStat.TCMallocStats.TCMalloc.ThreadCacheFreeBytes\n\t\t\treturnVal.TCMallocTotalFreeBytes = newStat.TCMallocStats.TCMalloc.TotalFreeBytes\n\t\t\treturnVal.TCMallocSpinLockTotalDelayNanos = newStat.TCMallocStats.TCMalloc.SpinLockTotalDelayNanos\n\n\t\t\treturnVal.TCMallocPageheapFreeBytes = newStat.TCMallocStats.TCMalloc.PageheapFreeBytes\n\t\t\treturnVal.TCMallocPageheapUnmappedBytes = newStat.TCMallocStats.TCMalloc.PageheapUnmappedBytes\n\t\t\treturnVal.TCMallocPageheapComittedBytes = newStat.TCMallocStats.TCMalloc.PageheapComittedBytes\n\t\t\treturnVal.TCMallocPageheapScavengeCount = newStat.TCMallocStats.TCMalloc.PageheapScavengeCount\n\t\t\treturnVal.TCMallocPageheapCommitCount = newStat.TCMallocStats.TCMalloc.PageheapCommitCount\n\t\t\treturnVal.TCMallocPageheapTotalCommitBytes = newStat.TCMallocStats.TCMalloc.PageheapTotalCommitBytes\n\t\t\treturnVal.TCMallocPageheapDecommitCount = newStat.TCMallocStats.TCMalloc.PageheapDecommitCount\n\t\t\treturnVal.TCMallocPageheapTotalDecommitBytes = newStat.TCMallocStats.TCMalloc.PageheapTotalDecommitBytes\n\t\t\treturnVal.TCMallocPageheapReserveCount = newStat.TCMallocStats.TCMalloc.PageheapReserveCount\n\t\t\treturnVal.TCMallocPageheapTotalReserveBytes = newStat.TCMallocStats.TCMalloc.PageheapTotalReserveBytes\n\t\t}\n\t}\n\n\tif newStat.Metrics != nil && oldStat.Metrics != nil {\n\t\tif newStat.Metrics.TTL != nil && oldStat.Metrics.TTL != nil {\n\t\t\treturnVal.Passes, returnVal.PassesCnt = diff(newStat.Metrics.TTL.Passes, oldStat.Metrics.TTL.Passes, sampleSecs)\n\t\t\treturnVal.DeletedDocuments, returnVal.DeletedDocumentsCnt = diff(\n\t\t\t\tnewStat.Metrics.TTL.DeletedDocuments,\n\t\t\t\toldStat.Metrics.TTL.DeletedDocuments,\n\t\t\t\tsampleSecs,\n\t\t\t)\n\t\t}\n\t\tif newStat.Metrics.Cursor != nil && oldStat.Metrics.Cursor != nil {\n\t\t\treturnVal.TimedOutC, returnVal.TimedOutCCnt = diff(newStat.Metrics.Cursor.TimedOut, oldStat.Metrics.Cursor.TimedOut, sampleSecs)\n\t\t\tif newStat.Metrics.Cursor.Open != nil && oldStat.Metrics.Cursor.Open != nil {\n\t\t\t\treturnVal.NoTimeoutC, returnVal.NoTimeoutCCnt = diff(newStat.Metrics.Cursor.Open.NoTimeout, oldStat.Metrics.Cursor.Open.NoTimeout, sampleSecs)\n\t\t\t\treturnVal.PinnedC, returnVal.PinnedCCnt = diff(newStat.Metrics.Cursor.Open.Pinned, oldStat.Metrics.Cursor.Open.Pinned, sampleSecs)\n\t\t\t\treturnVal.TotalC, returnVal.TotalCCnt = diff(newStat.Metrics.Cursor.Open.Total, oldStat.Metrics.Cursor.Open.Total, sampleSecs)\n\t\t\t}\n\t\t}\n\t\tif newStat.Metrics.Document != nil {\n\t\t\treturnVal.DeletedD = newStat.Metrics.Document.Deleted\n\t\t\treturnVal.InsertedD = newStat.Metrics.Document.Inserted\n\t\t\treturnVal.ReturnedD = newStat.Metrics.Document.Returned\n\t\t\treturnVal.UpdatedD = newStat.Metrics.Document.Updated\n\t\t}\n\n\t\tif newStat.Metrics.Commands != nil {\n\t\t\tif newStat.Metrics.Commands.Aggregate != nil {\n\t\t\t\treturnVal.AggregateCommandTotal = newStat.Metrics.Commands.Aggregate.Total\n\t\t\t\treturnVal.AggregateCommandFailed = newStat.Metrics.Commands.Aggregate.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Count != nil {\n\t\t\t\treturnVal.CountCommandTotal = newStat.Metrics.Commands.Count.Total\n\t\t\t\treturnVal.CountCommandFailed = newStat.Metrics.Commands.Count.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Delete != nil {\n\t\t\t\treturnVal.DeleteCommandTotal = newStat.Metrics.Commands.Delete.Total\n\t\t\t\treturnVal.DeleteCommandFailed = newStat.Metrics.Commands.Delete.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Distinct != nil {\n\t\t\t\treturnVal.DistinctCommandTotal = newStat.Metrics.Commands.Distinct.Total\n\t\t\t\treturnVal.DistinctCommandFailed = newStat.Metrics.Commands.Distinct.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Find != nil {\n\t\t\t\treturnVal.FindCommandTotal = newStat.Metrics.Commands.Find.Total\n\t\t\t\treturnVal.FindCommandFailed = newStat.Metrics.Commands.Find.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.FindAndModify != nil {\n\t\t\t\treturnVal.FindAndModifyCommandTotal = newStat.Metrics.Commands.FindAndModify.Total\n\t\t\t\treturnVal.FindAndModifyCommandFailed = newStat.Metrics.Commands.FindAndModify.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.GetMore != nil {\n\t\t\t\treturnVal.GetMoreCommandTotal = newStat.Metrics.Commands.GetMore.Total\n\t\t\t\treturnVal.GetMoreCommandFailed = newStat.Metrics.Commands.GetMore.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Insert != nil {\n\t\t\t\treturnVal.InsertCommandTotal = newStat.Metrics.Commands.Insert.Total\n\t\t\t\treturnVal.InsertCommandFailed = newStat.Metrics.Commands.Insert.Failed\n\t\t\t}\n\t\t\tif newStat.Metrics.Commands.Update != nil {\n\t\t\t\treturnVal.UpdateCommandTotal = newStat.Metrics.Commands.Update.Total\n\t\t\t\treturnVal.UpdateCommandFailed = newStat.Metrics.Commands.Update.Failed\n\t\t\t}\n\t\t}\n\n\t\tif newStat.Metrics.Operation != nil {\n\t\t\treturnVal.ScanAndOrderOp = newStat.Metrics.Operation.ScanAndOrder\n\t\t\treturnVal.WriteConflictsOp = newStat.Metrics.Operation.WriteConflicts\n\t\t}\n\n\t\tif newStat.Metrics.QueryExecutor != nil {\n\t\t\treturnVal.TotalKeysScanned = newStat.Metrics.QueryExecutor.Scanned\n\t\t\treturnVal.TotalObjectsScanned = newStat.Metrics.QueryExecutor.ScannedObjects\n\t\t}\n\n\t\tif newStat.Metrics.Repl != nil {\n\t\t\tif newStat.Metrics.Repl.Apply != nil {\n\t\t\t\treturnVal.ReplApplyBatchesNum = newStat.Metrics.Repl.Apply.Batches.Num\n\t\t\t\treturnVal.ReplApplyBatchesTotalMillis = newStat.Metrics.Repl.Apply.Batches.TotalMillis\n\t\t\t\treturnVal.ReplApplyOps = newStat.Metrics.Repl.Apply.Ops\n\t\t\t}\n\t\t\tif newStat.Metrics.Repl.Buffer != nil {\n\t\t\t\treturnVal.ReplBufferCount = newStat.Metrics.Repl.Buffer.Count\n\t\t\t\treturnVal.ReplBufferSizeBytes = newStat.Metrics.Repl.Buffer.SizeBytes\n\t\t\t}\n\t\t\tif newStat.Metrics.Repl.Executor != nil {\n\t\t\t\treturnVal.ReplExecutorPoolInProgressCount = newStat.Metrics.Repl.Executor.Pool[\"inProgressCount\"]\n\t\t\t\treturnVal.ReplExecutorQueuesNetworkInProgress = newStat.Metrics.Repl.Executor.Queues[\"networkInProgress\"]\n\t\t\t\treturnVal.ReplExecutorQueuesSleepers = newStat.Metrics.Repl.Executor.Queues[\"sleepers\"]\n\t\t\t\treturnVal.ReplExecutorUnsignaledEvents = newStat.Metrics.Repl.Executor.UnsignaledEvents\n\t\t\t}\n\t\t\tif newStat.Metrics.Repl.Network != nil {\n\t\t\t\treturnVal.ReplNetworkBytes = newStat.Metrics.Repl.Network.Bytes\n\t\t\t\tif newStat.Metrics.Repl.Network.GetMores != nil {\n\t\t\t\t\treturnVal.ReplNetworkGetmoresNum = newStat.Metrics.Repl.Network.GetMores.Num\n\t\t\t\t\treturnVal.ReplNetworkGetmoresTotalMillis = newStat.Metrics.Repl.Network.GetMores.TotalMillis\n\t\t\t\t}\n\t\t\t\treturnVal.ReplNetworkOps = newStat.Metrics.Repl.Network.Ops\n\t\t\t}\n\t\t}\n\n\t\tif newStat.Metrics.Storage != nil {\n\t\t\treturnVal.StorageFreelistSearchBucketExhausted = newStat.Metrics.Storage.FreelistSearchBucketExhausted\n\t\t\treturnVal.StorageFreelistSearchRequests = newStat.Metrics.Storage.FreelistSearchRequests\n\t\t\treturnVal.StorageFreelistSearchScanned = newStat.Metrics.Storage.FreelistSearchScanned\n\t\t}\n\t}\n\n\tif newStat.OpcountersRepl != nil && oldStat.OpcountersRepl != nil {\n\t\treturnVal.InsertR, returnVal.InsertRCnt = diff(newStat.OpcountersRepl.Insert, oldStat.OpcountersRepl.Insert, sampleSecs)\n\t\treturnVal.QueryR, returnVal.QueryRCnt = diff(newStat.OpcountersRepl.Query, oldStat.OpcountersRepl.Query, sampleSecs)\n\t\treturnVal.UpdateR, returnVal.UpdateRCnt = diff(newStat.OpcountersRepl.Update, oldStat.OpcountersRepl.Update, sampleSecs)\n\t\treturnVal.DeleteR, returnVal.DeleteRCnt = diff(newStat.OpcountersRepl.Delete, oldStat.OpcountersRepl.Delete, sampleSecs)\n\t\treturnVal.GetMoreR, returnVal.GetMoreRCnt = diff(newStat.OpcountersRepl.GetMore, oldStat.OpcountersRepl.GetMore, sampleSecs)\n\t\treturnVal.CommandR, returnVal.CommandRCnt = diff(newStat.OpcountersRepl.Command, oldStat.OpcountersRepl.Command, sampleSecs)\n\t}\n\n\treturnVal.CacheDirtyPercent = -1\n\treturnVal.CacheUsedPercent = -1\n\tif newStat.WiredTiger != nil {\n\t\treturnVal.CacheDirtyPercent = float64(newStat.WiredTiger.Cache.TrackedDirtyBytes) / float64(newStat.WiredTiger.Cache.MaxBytesConfigured)\n\t\treturnVal.CacheUsedPercent = float64(newStat.WiredTiger.Cache.CurrentCachedBytes) / float64(newStat.WiredTiger.Cache.MaxBytesConfigured)\n\n\t\treturnVal.TrackedDirtyBytes = newStat.WiredTiger.Cache.TrackedDirtyBytes\n\t\treturnVal.CurrentCachedBytes = newStat.WiredTiger.Cache.CurrentCachedBytes\n\t\treturnVal.MaxBytesConfigured = newStat.WiredTiger.Cache.MaxBytesConfigured\n\t\treturnVal.AppThreadsPageReadCount = newStat.WiredTiger.Cache.AppThreadsPageReadCount\n\t\treturnVal.AppThreadsPageReadTime = newStat.WiredTiger.Cache.AppThreadsPageReadTime\n\t\treturnVal.AppThreadsPageWriteCount = newStat.WiredTiger.Cache.AppThreadsPageWriteCount\n\t\treturnVal.BytesWrittenFrom = newStat.WiredTiger.Cache.BytesWrittenFrom\n\t\treturnVal.BytesReadInto = newStat.WiredTiger.Cache.BytesReadInto\n\t\treturnVal.PagesEvictedByAppThread = newStat.WiredTiger.Cache.PagesEvictedByAppThread\n\t\treturnVal.PagesQueuedForEviction = newStat.WiredTiger.Cache.PagesQueuedForEviction\n\t\treturnVal.PagesReadIntoCache = newStat.WiredTiger.Cache.PagesReadIntoCache\n\t\treturnVal.PagesWrittenFromCache = newStat.WiredTiger.Cache.PagesWrittenFromCache\n\t\treturnVal.PagesRequestedFromCache = newStat.WiredTiger.Cache.PagesRequestedFromCache\n\t\treturnVal.ServerEvictingPages = newStat.WiredTiger.Cache.ServerEvictingPages\n\t\treturnVal.WorkerThreadEvictingPages = newStat.WiredTiger.Cache.WorkerThreadEvictingPages\n\n\t\treturnVal.InternalPagesEvicted = newStat.WiredTiger.Cache.InternalPagesEvicted\n\t\treturnVal.ModifiedPagesEvicted = newStat.WiredTiger.Cache.ModifiedPagesEvicted\n\t\treturnVal.UnmodifiedPagesEvicted = newStat.WiredTiger.Cache.UnmodifiedPagesEvicted\n\n\t\treturnVal.FlushesTotalTime = newStat.WiredTiger.Transaction.TransCheckpointsTotalTimeMsecs * int64(time.Millisecond)\n\n\t\treturnVal.FilesCurrentlyOpen = newStat.WiredTiger.Connection.FilesCurrentlyOpen\n\n\t\treturnVal.DataHandlesCurrentlyActive = newStat.WiredTiger.DataHandle.DataHandlesCurrentlyActive\n\t}\n\tif newStat.WiredTiger != nil && oldStat.WiredTiger != nil {\n\t\treturnVal.Flushes, returnVal.FlushesCnt = diff(\n\t\t\tnewStat.WiredTiger.Transaction.TransCheckpoints,\n\t\t\toldStat.WiredTiger.Transaction.TransCheckpoints,\n\t\t\tsampleSecs,\n\t\t)\n\t} else if newStat.BackgroundFlushing != nil && oldStat.BackgroundFlushing != nil {\n\t\treturnVal.Flushes, returnVal.FlushesCnt = diff(newStat.BackgroundFlushing.Flushes, oldStat.BackgroundFlushing.Flushes, sampleSecs)\n\t}\n\n\treturnVal.Time = newMongo.SampleTime\n\treturnVal.IsMongos =\n\t\tnewStat.ShardCursorType != nil || strings.HasPrefix(newStat.Process, mongosProcess)\n\n\t// BEGIN code modification\n\tif oldStat.Mem.Supported.(bool) {\n\t\t// END code modification\n\t\tif !returnVal.IsMongos {\n\t\t\treturnVal.Mapped = newStat.Mem.Mapped\n\t\t}\n\t\treturnVal.Virtual = newStat.Mem.Virtual\n\t\treturnVal.Resident = newStat.Mem.Resident\n\n\t\tif !returnVal.IsMongos {\n\t\t\treturnVal.NonMapped = newStat.Mem.Virtual - newStat.Mem.Mapped\n\t\t}\n\t}\n\n\tif newStat.Repl != nil {\n\t\treturnVal.ReplSetName = newStat.Repl.SetName\n\t\t// BEGIN code modification\n\t\tif val, ok := newStat.Repl.IsMaster.(bool); ok && val {\n\t\t\treturnVal.NodeType = \"PRI\"\n\t\t} else if val, ok := newStat.Repl.IsWritablePrimary.(bool); ok && val {\n\t\t\treturnVal.NodeType = \"PRI\"\n\t\t} else if val, ok := newStat.Repl.Secondary.(bool); ok && val {\n\t\t\treturnVal.NodeType = \"SEC\"\n\t\t} else if val, ok := newStat.Repl.ArbiterOnly.(bool); ok && val {\n\t\t\treturnVal.NodeType = \"ARB\"\n\t\t} else {\n\t\t\treturnVal.NodeType = \"UNK\"\n\t\t} // END code modification\n\t} else if returnVal.IsMongos {\n\t\treturnVal.NodeType = \"RTR\"\n\t}\n\n\tif oldStat.ExtraInfo != nil && newStat.ExtraInfo != nil &&\n\t\toldStat.ExtraInfo.PageFaults != nil && newStat.ExtraInfo.PageFaults != nil {\n\t\treturnVal.Faults, returnVal.FaultsCnt = diff(*(newStat.ExtraInfo.PageFaults), *(oldStat.ExtraInfo.PageFaults), sampleSecs)\n\t}\n\tif !returnVal.IsMongos && oldStat.Locks != nil && newStat.Locks != nil {\n\t\tglobalCheckOld, hasGlobalOld := oldStat.Locks[\"Global\"]\n\t\tglobalCheckNew, hasGlobalNew := newStat.Locks[\"Global\"]\n\t\tif hasGlobalOld && globalCheckOld.AcquireCount != nil && hasGlobalNew && globalCheckNew.AcquireCount != nil {\n\t\t\t// This appears to be a 3.0+ server so the data in these fields do *not* refer to\n\t\t\t// actual namespaces and thus we can't compute lock %.\n\t\t\treturnVal.HighestLocked = nil\n\n\t\t\t// Check if it's a 3.0+ MMAP server so we can still compute collection locks\n\t\t\tcollectionCheckOld, hasCollectionOld := oldStat.Locks[\"Collection\"]\n\t\t\tcollectionCheckNew, hasCollectionNew := newStat.Locks[\"Collection\"]\n\t\t\tif hasCollectionOld && collectionCheckOld.AcquireWaitCount != nil && hasCollectionNew && collectionCheckNew.AcquireWaitCount != nil {\n\t\t\t\treadWaitCountDiff := newStat.Locks[\"Collection\"].AcquireWaitCount.Read - oldStat.Locks[\"Collection\"].AcquireWaitCount.Read\n\t\t\t\treadTotalCountDiff := newStat.Locks[\"Collection\"].AcquireCount.Read - oldStat.Locks[\"Collection\"].AcquireCount.Read\n\t\t\t\twriteWaitCountDiff := newStat.Locks[\"Collection\"].AcquireWaitCount.Write - oldStat.Locks[\"Collection\"].AcquireWaitCount.Write\n\t\t\t\twriteTotalCountDiff := newStat.Locks[\"Collection\"].AcquireCount.Write - oldStat.Locks[\"Collection\"].AcquireCount.Write\n\t\t\t\treadAcquireTimeDiff := newStat.Locks[\"Collection\"].TimeAcquiringMicros.Read - oldStat.Locks[\"Collection\"].TimeAcquiringMicros.Read\n\t\t\t\twriteAcquireTimeDiff := newStat.Locks[\"Collection\"].TimeAcquiringMicros.Write - oldStat.Locks[\"Collection\"].TimeAcquiringMicros.Write\n\t\t\t\treturnVal.CollectionLocks = &collectionLockStatus{\n\t\t\t\t\tReadAcquireWaitsPercentage:  percentageInt64(readWaitCountDiff, readTotalCountDiff),\n\t\t\t\t\tWriteAcquireWaitsPercentage: percentageInt64(writeWaitCountDiff, writeTotalCountDiff),\n\t\t\t\t\tReadAcquireTimeMicros:       averageInt64(readAcquireTimeDiff, readWaitCountDiff),\n\t\t\t\t\tWriteAcquireTimeMicros:      averageInt64(writeAcquireTimeDiff, writeWaitCountDiff),\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tprevLocks := parseLocks(oldStat)\n\t\t\tcurLocks := parseLocks(newStat)\n\t\t\tlockdiffs := computeLockDiffs(prevLocks, curLocks)\n\t\t\tif len(lockdiffs) == 0 {\n\t\t\t\tif newStat.GlobalLock != nil {\n\t\t\t\t\treturnVal.HighestLocked = &lockStatus{\n\t\t\t\t\t\tDBName:     \"\",\n\t\t\t\t\t\tPercentage: percentageInt64(newStat.GlobalLock.LockTime, newStat.GlobalLock.TotalTime),\n\t\t\t\t\t\tGlobal:     true,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Get the entry with the highest lock\n\t\t\t\thighestLocked := lockdiffs[len(lockdiffs)-1]\n\n\t\t\t\ttimeDiffMillis := newStat.UptimeMillis - oldStat.UptimeMillis\n\t\t\t\tlockToReport := highestLocked.Writes\n\n\t\t\t\t// if the highest locked namespace is not '.'\n\t\t\t\tif highestLocked.Namespace != \".\" {\n\t\t\t\t\tfor _, namespaceLockInfo := range lockdiffs {\n\t\t\t\t\t\tif namespaceLockInfo.Namespace == \".\" {\n\t\t\t\t\t\t\tlockToReport += namespaceLockInfo.Writes\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// lock data is in microseconds and uptime is in milliseconds - so\n\t\t\t\t// divide by 1000 so that they units match\n\t\t\t\tlockToReport /= 1000\n\n\t\t\t\treturnVal.HighestLocked = &lockStatus{\n\t\t\t\t\tDBName:     highestLocked.Namespace,\n\t\t\t\t\tPercentage: percentageInt64(lockToReport, timeDiffMillis),\n\t\t\t\t\tGlobal:     false,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturnVal.HighestLocked = nil\n\t}\n\n\tif newStat.GlobalLock != nil {\n\t\thasWT := newStat.WiredTiger != nil && oldStat.WiredTiger != nil\n\t\t// If we have wiredtiger stats, use those instead\n\t\tif newStat.GlobalLock.CurrentQueue != nil {\n\t\t\tif hasWT {\n\t\t\t\treturnVal.QueuedReaders = newStat.GlobalLock.CurrentQueue.Readers + newStat.GlobalLock.ActiveClients.Readers -\n\t\t\t\t\tnewStat.WiredTiger.Concurrent.Read.Out\n\t\t\t\treturnVal.QueuedWriters = newStat.GlobalLock.CurrentQueue.Writers + newStat.GlobalLock.ActiveClients.Writers -\n\t\t\t\t\tnewStat.WiredTiger.Concurrent.Write.Out\n\t\t\t\tif returnVal.QueuedReaders < 0 {\n\t\t\t\t\treturnVal.QueuedReaders = 0\n\t\t\t\t}\n\t\t\t\tif returnVal.QueuedWriters < 0 {\n\t\t\t\t\treturnVal.QueuedWriters = 0\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturnVal.QueuedReaders = newStat.GlobalLock.CurrentQueue.Readers\n\t\t\t\treturnVal.QueuedWriters = newStat.GlobalLock.CurrentQueue.Writers\n\t\t\t}\n\t\t}\n\n\t\tif hasWT {\n\t\t\treturnVal.ActiveReaders = newStat.WiredTiger.Concurrent.Read.Out\n\t\t\treturnVal.ActiveWriters = newStat.WiredTiger.Concurrent.Write.Out\n\t\t\treturnVal.AvailableReaders = newStat.WiredTiger.Concurrent.Read.Available\n\t\t\treturnVal.AvailableWriters = newStat.WiredTiger.Concurrent.Write.Available\n\t\t\treturnVal.TotalTicketsReaders = newStat.WiredTiger.Concurrent.Read.TotalTickets\n\t\t\treturnVal.TotalTicketsWriters = newStat.WiredTiger.Concurrent.Write.TotalTickets\n\t\t} else if newStat.GlobalLock.ActiveClients != nil {\n\t\t\treturnVal.ActiveReaders = newStat.GlobalLock.ActiveClients.Readers\n\t\t\treturnVal.ActiveWriters = newStat.GlobalLock.ActiveClients.Writers\n\t\t}\n\t}\n\n\tif oldStat.Network != nil && newStat.Network != nil {\n\t\treturnVal.NetIn, returnVal.NetInCnt = diff(newStat.Network.BytesIn, oldStat.Network.BytesIn, sampleSecs)\n\t\treturnVal.NetOut, returnVal.NetOutCnt = diff(newStat.Network.BytesOut, oldStat.Network.BytesOut, sampleSecs)\n\t}\n\n\tif newStat.Connections != nil {\n\t\treturnVal.NumConnections = newStat.Connections.Current\n\t}\n\n\tif newMongo.ReplSetStatus != nil {\n\t\tnewReplStat := *newMongo.ReplSetStatus\n\n\t\tif newReplStat.Members != nil {\n\t\t\tmyName := newStat.Repl.Me\n\t\t\t// Find the master and myself\n\t\t\tmaster := replSetMember{}\n\t\t\tme := replSetMember{}\n\t\t\tfor _, member := range newReplStat.Members {\n\t\t\t\tif member.Name == myName {\n\t\t\t\t\t// Store my state string\n\t\t\t\t\treturnVal.NodeState = member.StateStr\n\t\t\t\t\t// Store my state integer\n\t\t\t\t\treturnVal.NodeStateInt = member.State\n\t\t\t\t\t// Store my health integer\n\t\t\t\t\treturnVal.NodeHealthInt = member.Health\n\n\t\t\t\t\tif member.State == 1 {\n\t\t\t\t\t\t// I'm the master\n\t\t\t\t\t\treturnVal.ReplLag = 0\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\t// I'm secondary\n\t\t\t\t\tme = member\n\t\t\t\t} else if member.State == 1 {\n\t\t\t\t\t// Master found\n\t\t\t\t\tmaster = member\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif me.State == 2 {\n\t\t\t\t// OptimeDate.Unix() type is int64\n\t\t\t\tlag := master.OptimeDate.Unix() - me.OptimeDate.Unix()\n\t\t\t\tif lag < 0 {\n\t\t\t\t\treturnVal.ReplLag = 0\n\t\t\t\t} else {\n\t\t\t\t\treturnVal.ReplLag = lag\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Preparations for the average health state of the replica-set\n\t\t\treplMemberCount := len(newReplStat.Members)\n\t\t\treplMemberHealthyCount := 0\n\n\t\t\t// Second for-loop is needed, because of break-construct above\n\t\t\tfor _, member := range newReplStat.Members {\n\t\t\t\t// Count only healthy members for the average health state of the replica-set\n\t\t\t\tif member.Health == 1 {\n\t\t\t\t\treplMemberHealthyCount++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Calculate the average health state of the replica-set (For precise monitoring alerts)\n\t\t\t// To detect if a member is unhealthy from the perspective of another member and also how bad the replica-set health is\n\t\t\tif replMemberCount > 0 {\n\t\t\t\treturnVal.ReplHealthAvg = float64(replMemberHealthyCount) / float64(replMemberCount)\n\t\t\t} else {\n\t\t\t\treturnVal.ReplHealthAvg = 0.00\n\t\t\t}\n\t\t}\n\t}\n\n\tif newMongo.ClusterStatus != nil {\n\t\tnewClusterStat := *newMongo.ClusterStatus\n\t\treturnVal.JumboChunksCount = newClusterStat.JumboChunksCount\n\t}\n\n\tif newMongo.OplogStats != nil {\n\t\treturnVal.OplogStats = newMongo.OplogStats\n\t}\n\n\tif newMongo.DBStats != nil {\n\t\tnewDBStats := *newMongo.DBStats\n\t\tfor _, db := range newDBStats.DBs {\n\t\t\tdbStatsData := db.DBStatsData\n\t\t\t// mongos doesn't have the db key, so setting the db name\n\t\t\tif dbStatsData.DB == \"\" {\n\t\t\t\tdbStatsData.DB = db.Name\n\t\t\t}\n\t\t\tdbStatLine := &dbStatLine{\n\t\t\t\tName:        dbStatsData.DB,\n\t\t\t\tCollections: dbStatsData.Collections,\n\t\t\t\tObjects:     dbStatsData.Objects,\n\t\t\t\tAvgObjSize:  dbStatsData.AvgObjSize,\n\t\t\t\tDataSize:    dbStatsData.DataSize,\n\t\t\t\tStorageSize: dbStatsData.StorageSize,\n\t\t\t\tNumExtents:  dbStatsData.NumExtents,\n\t\t\t\tIndexes:     dbStatsData.Indexes,\n\t\t\t\tIndexSize:   dbStatsData.IndexSize,\n\t\t\t\tOk:          dbStatsData.Ok,\n\t\t\t\tFsTotalSize: dbStatsData.FsTotalSize,\n\t\t\t\tFsUsedSize:  dbStatsData.FsUsedSize,\n\t\t\t}\n\t\t\treturnVal.DBStatsLines = append(returnVal.DBStatsLines, *dbStatLine)\n\t\t}\n\t}\n\n\tif newMongo.ColStats != nil {\n\t\tfor _, col := range newMongo.ColStats.Collections {\n\t\t\tcolStatsData := col.ColStatsData\n\t\t\t// mongos doesn't have the db key, so setting the db name\n\t\t\tif colStatsData.Collection == \"\" {\n\t\t\t\tcolStatsData.Collection = col.Name\n\t\t\t}\n\t\t\tcolStatLine := &colStatLine{\n\t\t\t\tName:           colStatsData.Collection,\n\t\t\t\tDBName:         col.DBName,\n\t\t\t\tCount:          colStatsData.Count,\n\t\t\t\tSize:           colStatsData.Size,\n\t\t\t\tAvgObjSize:     colStatsData.AvgObjSize,\n\t\t\t\tStorageSize:    colStatsData.StorageSize,\n\t\t\t\tTotalIndexSize: colStatsData.TotalIndexSize,\n\t\t\t\tOk:             colStatsData.Ok,\n\t\t\t}\n\t\t\treturnVal.ColStatsLines = append(returnVal.ColStatsLines, *colStatLine)\n\t\t}\n\t}\n\n\t// Set shard stats\n\tif newMongo.ShardStats != nil {\n\t\tnewShardStats := *newMongo.ShardStats\n\t\treturnVal.TotalInUse = newShardStats.TotalInUse\n\t\treturnVal.TotalAvailable = newShardStats.TotalAvailable\n\t\treturnVal.TotalCreated = newShardStats.TotalCreated\n\t\treturnVal.TotalRefreshing = newShardStats.TotalRefreshing\n\t\treturnVal.ShardHostStatsLines = make(map[string]shardHostStatLine, len(newShardStats.Hosts))\n\t\tfor host, stats := range newShardStats.Hosts {\n\t\t\tshardStatLine := &shardHostStatLine{\n\t\t\t\tInUse:      stats.InUse,\n\t\t\t\tAvailable:  stats.Available,\n\t\t\t\tCreated:    stats.Created,\n\t\t\t\tRefreshing: stats.Refreshing,\n\t\t\t}\n\n\t\t\treturnVal.ShardHostStatsLines[host] = *shardStatLine\n\t\t}\n\t}\n\n\tif newMongo.TopStats != nil {\n\t\tfor collection, data := range newMongo.TopStats.Totals {\n\t\t\ttopStatDataLine := &topStatLine{\n\t\t\t\tCollectionName: collection,\n\t\t\t\tTotalTime:      data.Total.Time,\n\t\t\t\tTotalCount:     data.Total.Count,\n\t\t\t\tReadLockTime:   data.ReadLock.Time,\n\t\t\t\tReadLockCount:  data.ReadLock.Count,\n\t\t\t\tWriteLockTime:  data.WriteLock.Time,\n\t\t\t\tWriteLockCount: data.WriteLock.Count,\n\t\t\t\tQueriesTime:    data.Queries.Time,\n\t\t\t\tQueriesCount:   data.Queries.Count,\n\t\t\t\tGetMoreTime:    data.GetMore.Time,\n\t\t\t\tGetMoreCount:   data.GetMore.Count,\n\t\t\t\tInsertTime:     data.Insert.Time,\n\t\t\t\tInsertCount:    data.Insert.Count,\n\t\t\t\tUpdateTime:     data.Update.Time,\n\t\t\t\tUpdateCount:    data.Update.Count,\n\t\t\t\tRemoveTime:     data.Remove.Time,\n\t\t\t\tRemoveCount:    data.Remove.Count,\n\t\t\t\tCommandsTime:   data.Commands.Time,\n\t\t\t\tCommandsCount:  data.Commands.Count,\n\t\t\t}\n\t\t\treturnVal.TopStatLines = append(returnVal.TopStatLines, *topStatDataLine)\n\t\t}\n\t}\n\n\treturn returnVal\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/mongostat_test.go",
    "content": "package mongodb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLatencyStats(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t\tOpLatencies: &opLatenciesStats{\n\t\t\t\t\tReads: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tWrites: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tCommands: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Equal(t, int64(0), sl.CommandLatency)\n\trequire.Equal(t, int64(0), sl.ReadLatency)\n\trequire.Equal(t, int64(0), sl.WriteLatency)\n\trequire.Equal(t, int64(0), sl.CommandOpsCnt)\n\trequire.Equal(t, int64(0), sl.ReadOpsCnt)\n\trequire.Equal(t, int64(0), sl.WriteOpsCnt)\n}\n\nfunc TestLatencyStatsDiffZero(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t\tOpLatencies: &opLatenciesStats{\n\t\t\t\t\tReads: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tWrites: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tCommands: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t\tOpLatencies: &opLatenciesStats{\n\t\t\t\t\tReads: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tWrites: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t\tCommands: &latencyStats{\n\t\t\t\t\t\tOps:     0,\n\t\t\t\t\t\tLatency: 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Equal(t, int64(0), sl.CommandLatency)\n\trequire.Equal(t, int64(0), sl.ReadLatency)\n\trequire.Equal(t, int64(0), sl.WriteLatency)\n\trequire.Equal(t, int64(0), sl.CommandOpsCnt)\n\trequire.Equal(t, int64(0), sl.ReadOpsCnt)\n\trequire.Equal(t, int64(0), sl.WriteOpsCnt)\n}\n\nfunc TestLatencyStatsDiff(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t\tOpLatencies: &opLatenciesStats{\n\t\t\t\t\tReads: &latencyStats{\n\t\t\t\t\t\tOps:     4189041956,\n\t\t\t\t\t\tLatency: 2255922322753,\n\t\t\t\t\t},\n\t\t\t\t\tWrites: &latencyStats{\n\t\t\t\t\t\tOps:     1691019457,\n\t\t\t\t\t\tLatency: 494478256915,\n\t\t\t\t\t},\n\t\t\t\t\tCommands: &latencyStats{\n\t\t\t\t\t\tOps:     1019150402,\n\t\t\t\t\t\tLatency: 59177710371,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tBits:              0,\n\t\t\t\t\tResident:          0,\n\t\t\t\t\tVirtual:           0,\n\t\t\t\t\tSupported:         false,\n\t\t\t\t\tMapped:            0,\n\t\t\t\t\tMappedWithJournal: 0,\n\t\t\t\t},\n\t\t\t\tOpLatencies: &opLatenciesStats{\n\t\t\t\t\tReads: &latencyStats{\n\t\t\t\t\t\tOps:     4189049884,\n\t\t\t\t\t\tLatency: 2255946760057,\n\t\t\t\t\t},\n\t\t\t\t\tWrites: &latencyStats{\n\t\t\t\t\t\tOps:     1691021287,\n\t\t\t\t\t\tLatency: 494479456987,\n\t\t\t\t\t},\n\t\t\t\t\tCommands: &latencyStats{\n\t\t\t\t\t\tOps:     1019152861,\n\t\t\t\t\t\tLatency: 59177981552,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Equal(t, int64(59177981552), sl.CommandLatency)\n\trequire.Equal(t, int64(2255946760057), sl.ReadLatency)\n\trequire.Equal(t, int64(494479456987), sl.WriteLatency)\n\trequire.Equal(t, int64(1019152861), sl.CommandOpsCnt)\n\trequire.Equal(t, int64(4189049884), sl.ReadOpsCnt)\n\trequire.Equal(t, int64(1691021287), sl.WriteOpsCnt)\n}\n\nfunc TestLocksStatsNilWhenLocksMissingInOldStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenGlobalLockStatsMissingInOldStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenGlobalLockStatsEmptyInOldStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenCollectionLockStatsMissingInOldStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenCollectionLockStatsEmptyInOldStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t\t\"Collection\": {},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenLocksMissingInNewStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenGlobalLockStatsMissingInNewStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenGlobalLockStatsEmptyInNewStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenCollectionLockStatsMissingInNewStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsNilWhenCollectionLockStatsEmptyInNewStat(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t\t\"Collection\": {},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\trequire.Nil(t, sl.CollectionLocks)\n}\n\nfunc TestLocksStatsPopulated(t *testing.T) {\n\tsl := newStatLine(\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t\t\"Collection\": {\n\t\t\t\t\t\tAcquireWaitCount: &readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  1,\n\t\t\t\t\t\t\tWrite: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  5,\n\t\t\t\t\t\t\tWrite: 10,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTimeAcquiringMicros: readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  100,\n\t\t\t\t\t\t\tWrite: 200,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmongoStatus{\n\t\t\tServerStatus: &serverStatus{\n\t\t\t\tConnections: &connectionStats{},\n\t\t\t\tMem: &memStats{\n\t\t\t\t\tSupported: false,\n\t\t\t\t},\n\t\t\t\tLocks: map[string]lockStats{\n\t\t\t\t\t\"Global\": {\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{},\n\t\t\t\t\t},\n\t\t\t\t\t\"Collection\": {\n\t\t\t\t\t\tAcquireWaitCount: &readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  2,\n\t\t\t\t\t\t\tWrite: 4,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAcquireCount: &readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  10,\n\t\t\t\t\t\t\tWrite: 30,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTimeAcquiringMicros: readWriteLockTimes{\n\t\t\t\t\t\t\tRead:  250,\n\t\t\t\t\t\t\tWrite: 310,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"foo\",\n\t\t60,\n\t)\n\n\texpected := &collectionLockStatus{\n\t\tReadAcquireWaitsPercentage:  20,\n\t\tWriteAcquireWaitsPercentage: 10,\n\t\tReadAcquireTimeMicros:       150,\n\t\tWriteAcquireTimeMicros:      55,\n\t}\n\n\trequire.Equal(t, expected, sl.CollectionLocks)\n}\n"
  },
  {
    "path": "plugins/inputs/mongodb/sample.conf",
    "content": "# Read metrics from one or many MongoDB servers\n[[inputs.mongodb]]\n  ## An array of URLs of the form:\n  ##   \"mongodb://\" [user \":\" pass \"@\"] host [ \":\" port]\n  ## For example:\n  ##   mongodb://user:auth_key@10.10.3.30:27017,\n  ##   mongodb://10.10.3.33:18832,\n  ##\n  ## If connecting to a cluster, users must include the \"?connect=direct\" in\n  ## the URL to ensure that the connection goes directly to the specified node\n  ## and not have all connections passed to the master node.\n  servers = [\"mongodb://127.0.0.1:27017/?connect=direct\"]\n\n  ## When true, collect cluster status.\n  ## Note that the query that counts jumbo chunks triggers a COLLSCAN, which\n  ## may have an impact on performance.\n  # gather_cluster_status = true\n\n  ## When true, collect per database stats\n  # gather_perdb_stats = false\n\n  ## When true, collect per collection stats\n  # gather_col_stats = false\n\n  ## When true, collect usage statistics for each collection\n  ## (insert, update, queries, remove, getmore, commands etc...).\n  # gather_top_stat = false\n\n  ## List of db where collections stats are collected\n  ## If empty, all db are concerned\n  # col_stats_dbs = [\"local\"]\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Specifies plugin behavior regarding disconnected servers\n  ## Available choices :\n  ##   - error: telegraf will return an error on startup if one the servers is unreachable\n  ##   - skip: telegraf will skip unreachable servers on both startup and gather\n  # disconnected_servers_behavior = \"error\"\n"
  },
  {
    "path": "plugins/inputs/mongodb/sample.conf.in",
    "content": "# Read metrics from one or many MongoDB servers\n[[inputs.mongodb]]\n  ## An array of URLs of the form:\n  ##   \"mongodb://\" [user \":\" pass \"@\"] host [ \":\" port]\n  ## For example:\n  ##   mongodb://user:auth_key@10.10.3.30:27017,\n  ##   mongodb://10.10.3.33:18832,\n  ##\n  ## If connecting to a cluster, users must include the \"?connect=direct\" in\n  ## the URL to ensure that the connection goes directly to the specified node\n  ## and not have all connections passed to the master node.\n  servers = [\"mongodb://127.0.0.1:27017/?connect=direct\"]\n\n  ## When true, collect cluster status.\n  ## Note that the query that counts jumbo chunks triggers a COLLSCAN, which\n  ## may have an impact on performance.\n  # gather_cluster_status = true\n\n  ## When true, collect per database stats\n  # gather_perdb_stats = false\n\n  ## When true, collect per collection stats\n  # gather_col_stats = false\n\n  ## When true, collect usage statistics for each collection\n  ## (insert, update, queries, remove, getmore, commands etc...).\n  # gather_top_stat = false\n\n  ## List of db where collections stats are collected\n  ## If empty, all db are concerned\n  # col_stats_dbs = [\"local\"]\n\n  ## Optional TLS Config\n{{template \"/plugins/common/tls/client.conf\"}}\n\n  ## Specifies plugin behavior regarding disconnected servers\n  ## Available choices :\n  ##   - error: telegraf will return an error on startup if one the servers is unreachable\n  ##   - skip: telegraf will skip unreachable servers on both startup and gather\n  # disconnected_servers_behavior = \"error\"\n"
  },
  {
    "path": "plugins/inputs/monit/README.md",
    "content": "# Monit Input Plugin\n\nThis plugin gathers metrics and status information about local processes,\nremote hosts, files, file systems, directories and network interfaces managed\nand watched over by [Monit][monit].\n\n> [!NOTE]\n> The plugin supports Monit version 5.16+.\n> To use this plugin you have to enable the [HTTPD TCP port][httpd] in Monit.\n\n⭐ Telegraf v1.14.0\n🏷️ network\n💻 all\n\n[monit]: https://mmonit.com/\n[httpd]: https://mmonit.com/monit/documentation/monit.html#TCP-PORT\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics and status information about processes managed by Monit\n[[inputs.monit]]\n  ## Monit HTTPD address\n  address = \"http://127.0.0.1:2812\"\n\n  ## Username and Password for Monit\n  # username = \"\"\n  # password = \"\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- monit_filesystem\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - mode\n    - block_percent\n    - block_usage\n    - block_total\n    - inode_percent\n    - inode_usage\n    - inode_total\n\n- monit_directory\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - permissions\n\n- monit_file\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - size\n    - permissions\n\n- monit_process\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - cpu_percent\n    - cpu_percent_total\n    - mem_kb\n    - mem_kb_total\n    - mem_percent\n    - mem_percent_total\n    - pid\n    - parent_pid\n    - threads\n    - children\n\n- monit_remote_host\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - hostname\n    - port_number\n    - request\n    - response_time\n    - protocol\n    - type\n\n- monit_system\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - cpu_system\n    - cpu_user\n    - cpu_wait\n    - cpu_load_avg_1m\n    - cpu_load_avg_5m\n    - cpu_load_avg_15m\n    - mem_kb\n    - mem_percent\n    - swap_kb\n    - swap_percent\n\n- monit_fifo\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n    - permissions\n\n- monit_program\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n\n- monit_network\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n\n- monit_program\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n\n- monit_network\n  - tags:\n    - address\n    - version\n    - service\n    - platform_name\n    - status\n    - monitoring_status\n    - monitoring_mode\n  - fields:\n    - status_code\n    - monitoring_status_code\n    - monitoring_mode_code\n\n## Example Output\n\n```text\nmonit_file,monitoring_mode=active,monitoring_status=monitored,pending_action=none,platform_name=Linux,service=rsyslog_pid,source=xyzzy.local,status=running,version=5.20.0 mode=644i,monitoring_mode_code=0i,monitoring_status_code=1i,pending_action_code=0i,size=3i,status_code=0i 1579735047000000000\nmonit_process,monitoring_mode=active,monitoring_status=monitored,pending_action=none,platform_name=Linux,service=rsyslog,source=xyzzy.local,status=running,version=5.20.0 children=0i,cpu_percent=0,cpu_percent_total=0,mem_kb=3148i,mem_kb_total=3148i,mem_percent=0.2,mem_percent_total=0.2,monitoring_mode_code=0i,monitoring_status_code=1i,parent_pid=1i,pending_action_code=0i,pid=318i,status_code=0i,threads=4i 1579735047000000000\nmonit_program,monitoring_mode=active,monitoring_status=initializing,pending_action=none,platform_name=Linux,service=echo,source=xyzzy.local,status=running,version=5.20.0 monitoring_mode_code=0i,monitoring_status_code=2i,pending_action_code=0i,program_started=0i,program_status=0i,status_code=0i 1579735047000000000\nmonit_system,monitoring_mode=active,monitoring_status=monitored,pending_action=none,platform_name=Linux,service=debian-stretch-monit.virt,source=xyzzy.local,status=running,version=5.20.0 cpu_load_avg_15m=0,cpu_load_avg_1m=0,cpu_load_avg_5m=0,cpu_system=0,cpu_user=0,cpu_wait=0,mem_kb=42852i,mem_percent=2.1,monitoring_mode_code=0i,monitoring_status_code=1i,pending_action_code=0i,status_code=0i,swap_kb=0,swap_percent=0 1579735047000000000\nmonit_remote_host,dc=new-12,host=palladium,monitoring_mode=active,monitoring_status=monitored,pending_action=none,platform_name=Linux,rack=rack-0,service=blog.kalvad.com,source=palladium,status=running,version=5.27.0 monitoring_status_code=1i,monitoring_mode_code=0i,response_time=0.664412,type=\"TCP\",pending_action_code=0i,remote_hostname=\"blog.kalvad.com\",port_number=443i,request=\"/\",protocol=\"HTTP\",status_code=0i 1599138990000000000\n```\n"
  },
  {
    "path": "plugins/inputs/monit/monit.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage monit\n\nimport (\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"golang.org/x/net/html/charset\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar pendingActions = []string{\"ignore\", \"alert\", \"restart\", \"stop\", \"exec\", \"unmonitor\", \"start\", \"monitor\"}\n\nconst (\n\tfileSystem = \"0\"\n\tdirectory  = \"1\"\n\tfile       = \"2\"\n\tprocess    = \"3\"\n\tremoteHost = \"4\"\n\tsstm       = \"5\"\n\tfifo       = \"6\"\n\tprgrm      = \"7\"\n\tnetwork    = \"8\"\n)\n\ntype Monit struct {\n\tAddress  string          `toml:\"address\"`\n\tUsername string          `toml:\"username\"`\n\tPassword string          `toml:\"password\"`\n\tTimeout  config.Duration `toml:\"timeout\"`\n\tclient   http.Client\n\ttls.ClientConfig\n}\n\ntype status struct {\n\tServer   server    `xml:\"server\"`\n\tPlatform platform  `xml:\"platform\"`\n\tServices []service `xml:\"service\"`\n}\n\ntype server struct {\n\tID            string `xml:\"id\"`\n\tVersion       string `xml:\"version\"`\n\tUptime        int64  `xml:\"uptime\"`\n\tPoll          int    `xml:\"poll\"`\n\tLocalHostname string `xml:\"localhostname\"`\n\tStartDelay    int    `xml:\"startdelay\"`\n\tControlFile   string `xml:\"controlfile\"`\n}\n\ntype platform struct {\n\tName    string `xml:\"name\"`\n\tRelease string `xml:\"release\"`\n\tVersion string `xml:\"version\"`\n\tMachine string `xml:\"machine\"`\n\tCPU     int    `xml:\"cpu\"`\n\tMemory  int    `xml:\"memory\"`\n\tSwap    int    `xml:\"swap\"`\n}\n\ntype service struct {\n\tType             string  `xml:\"type,attr\"`\n\tName             string  `xml:\"name\"`\n\tStatus           int     `xml:\"status\"`\n\tMonitoringStatus int     `xml:\"monitor\"`\n\tMonitorMode      int     `xml:\"monitormode\"`\n\tPendingAction    int     `xml:\"pendingaction\"`\n\tMemory           memory  `xml:\"memory\"`\n\tCPU              cpu     `xml:\"cpu\"`\n\tSystem           system  `xml:\"system\"`\n\tSize             int64   `xml:\"size\"`\n\tMode             int     `xml:\"mode\"`\n\tProgram          program `xml:\"program\"`\n\tBlock            block   `xml:\"block\"`\n\tInode            inode   `xml:\"inode\"`\n\tPid              int64   `xml:\"pid\"`\n\tParentPid        int64   `xml:\"ppid\"`\n\tThreads          int     `xml:\"threads\"`\n\tChildren         int     `xml:\"children\"`\n\tPort             port    `xml:\"port\"`\n\tLink             link    `xml:\"link\"`\n}\n\ntype link struct {\n\tState    int      `xml:\"state\"`\n\tSpeed    int64    `xml:\"speed\"`\n\tDuplex   int      `xml:\"duplex\"`\n\tDownload download `xml:\"download\"`\n\tUpload   upload   `xml:\"upload\"`\n}\n\ntype download struct {\n\tPackets struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"packets\"`\n\tBytes struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"bytes\"`\n\tErrors struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"errors\"`\n}\n\ntype upload struct {\n\tPackets struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"packets\"`\n\tBytes struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"bytes\"`\n\tErrors struct {\n\t\tNow   int64 `xml:\"now\"`\n\t\tTotal int64 `xml:\"total\"`\n\t} `xml:\"errors\"`\n}\n\ntype port struct {\n\tHostname     string  `xml:\"hostname\"`\n\tPortNumber   int64   `xml:\"portnumber\"`\n\tRequest      string  `xml:\"request\"`\n\tResponseTime float64 `xml:\"responsetime\"`\n\tProtocol     string  `xml:\"protocol\"`\n\tType         string  `xml:\"type\"`\n}\n\ntype block struct {\n\tPercent float64 `xml:\"percent\"`\n\tUsage   float64 `xml:\"usage\"`\n\tTotal   float64 `xml:\"total\"`\n}\n\ntype inode struct {\n\tPercent float64 `xml:\"percent\"`\n\tUsage   float64 `xml:\"usage\"`\n\tTotal   float64 `xml:\"total\"`\n}\n\ntype program struct {\n\tStarted int64 `xml:\"started\"`\n\tStatus  int   `xml:\"status\"`\n}\n\ntype memory struct {\n\tPercent       float64 `xml:\"percent\"`\n\tPercentTotal  float64 `xml:\"percenttotal\"`\n\tKilobyte      int64   `xml:\"kilobyte\"`\n\tKilobyteTotal int64   `xml:\"kilobytetotal\"`\n}\n\ntype cpu struct {\n\tPercent      float64 `xml:\"percent\"`\n\tPercentTotal float64 `xml:\"percenttotal\"`\n}\n\ntype system struct {\n\tLoad struct {\n\t\tAvg01 float64 `xml:\"avg01\"`\n\t\tAvg05 float64 `xml:\"avg05\"`\n\t\tAvg15 float64 `xml:\"avg15\"`\n\t} `xml:\"load\"`\n\tCPU struct {\n\t\tUser   float64 `xml:\"user\"`\n\t\tSystem float64 `xml:\"system\"`\n\t\tWait   float64 `xml:\"wait\"`\n\t} `xml:\"cpu\"`\n\tMemory struct {\n\t\tPercent  float64 `xml:\"percent\"`\n\t\tKilobyte int64   `xml:\"kilobyte\"`\n\t} `xml:\"memory\"`\n\tSwap struct {\n\t\tPercent  float64 `xml:\"percent\"`\n\t\tKilobyte float64 `xml:\"kilobyte\"`\n\t} `xml:\"swap\"`\n}\n\nfunc (*Monit) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Monit) Init() error {\n\ttlsCfg, err := m.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tm.client = http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t\tProxy:           http.ProxyFromEnvironment,\n\t\t},\n\t\tTimeout: time.Duration(m.Timeout),\n\t}\n\treturn nil\n}\n\nfunc (m *Monit) Gather(acc telegraf.Accumulator) error {\n\treq, err := http.NewRequest(\"GET\", m.Address+\"/_status?format=xml\", nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(m.Username) > 0 || len(m.Password) > 0 {\n\t\treq.SetBasicAuth(m.Username, m.Password)\n\t}\n\n\tresp, err := m.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"received status code %d (%s), expected 200\", resp.StatusCode, http.StatusText(resp.StatusCode))\n\t}\n\n\tvar status status\n\tdecoder := xml.NewDecoder(resp.Body)\n\tdecoder.CharsetReader = charset.NewReaderLabel\n\tif err := decoder.Decode(&status); err != nil {\n\t\treturn fmt.Errorf(\"error parsing input: %w\", err)\n\t}\n\n\ttags := map[string]string{\n\t\t\"version\":       status.Server.Version,\n\t\t\"source\":        status.Server.LocalHostname,\n\t\t\"platform_name\": status.Platform.Name,\n\t}\n\n\tfor _, service := range status.Services {\n\t\tfields := make(map[string]interface{})\n\t\ttags[\"status\"] = serviceStatus(service)\n\t\tfields[\"status_code\"] = service.Status\n\t\ttags[\"pending_action\"] = pendingAction(service)\n\t\tfields[\"pending_action_code\"] = service.PendingAction\n\t\ttags[\"monitoring_status\"] = monitoringStatus(service)\n\t\tfields[\"monitoring_status_code\"] = service.MonitoringStatus\n\t\ttags[\"monitoring_mode\"] = monitoringMode(service)\n\t\tfields[\"monitoring_mode_code\"] = service.MonitorMode\n\t\ttags[\"service\"] = service.Name\n\t\tif service.Type == fileSystem {\n\t\t\tfields[\"mode\"] = service.Mode\n\t\t\tfields[\"block_percent\"] = service.Block.Percent\n\t\t\tfields[\"block_usage\"] = service.Block.Usage\n\t\t\tfields[\"block_total\"] = service.Block.Total\n\t\t\tfields[\"inode_percent\"] = service.Inode.Percent\n\t\t\tfields[\"inode_usage\"] = service.Inode.Usage\n\t\t\tfields[\"inode_total\"] = service.Inode.Total\n\t\t\tacc.AddFields(\"monit_filesystem\", fields, tags)\n\t\t} else if service.Type == directory {\n\t\t\tfields[\"mode\"] = service.Mode\n\t\t\tacc.AddFields(\"monit_directory\", fields, tags)\n\t\t} else if service.Type == file {\n\t\t\tfields[\"size\"] = service.Size\n\t\t\tfields[\"mode\"] = service.Mode\n\t\t\tacc.AddFields(\"monit_file\", fields, tags)\n\t\t} else if service.Type == process {\n\t\t\tfields[\"cpu_percent\"] = service.CPU.Percent\n\t\t\tfields[\"cpu_percent_total\"] = service.CPU.PercentTotal\n\t\t\tfields[\"mem_kb\"] = service.Memory.Kilobyte\n\t\t\tfields[\"mem_kb_total\"] = service.Memory.KilobyteTotal\n\t\t\tfields[\"mem_percent\"] = service.Memory.Percent\n\t\t\tfields[\"mem_percent_total\"] = service.Memory.PercentTotal\n\t\t\tfields[\"pid\"] = service.Pid\n\t\t\tfields[\"parent_pid\"] = service.ParentPid\n\t\t\tfields[\"threads\"] = service.Threads\n\t\t\tfields[\"children\"] = service.Children\n\t\t\tacc.AddFields(\"monit_process\", fields, tags)\n\t\t} else if service.Type == remoteHost {\n\t\t\tfields[\"remote_hostname\"] = service.Port.Hostname\n\t\t\tfields[\"port_number\"] = service.Port.PortNumber\n\t\t\tfields[\"request\"] = service.Port.Request\n\t\t\tfields[\"response_time\"] = service.Port.ResponseTime\n\t\t\tfields[\"protocol\"] = service.Port.Protocol\n\t\t\tfields[\"type\"] = service.Port.Type\n\t\t\tacc.AddFields(\"monit_remote_host\", fields, tags)\n\t\t} else if service.Type == sstm {\n\t\t\tfields[\"cpu_system\"] = service.System.CPU.System\n\t\t\tfields[\"cpu_user\"] = service.System.CPU.User\n\t\t\tfields[\"cpu_wait\"] = service.System.CPU.Wait\n\t\t\tfields[\"cpu_load_avg_1m\"] = service.System.Load.Avg01\n\t\t\tfields[\"cpu_load_avg_5m\"] = service.System.Load.Avg05\n\t\t\tfields[\"cpu_load_avg_15m\"] = service.System.Load.Avg15\n\t\t\tfields[\"mem_kb\"] = service.System.Memory.Kilobyte\n\t\t\tfields[\"mem_percent\"] = service.System.Memory.Percent\n\t\t\tfields[\"swap_kb\"] = service.System.Swap.Kilobyte\n\t\t\tfields[\"swap_percent\"] = service.System.Swap.Percent\n\t\t\tacc.AddFields(\"monit_system\", fields, tags)\n\t\t} else if service.Type == fifo {\n\t\t\tfields[\"mode\"] = service.Mode\n\t\t\tacc.AddFields(\"monit_fifo\", fields, tags)\n\t\t} else if service.Type == prgrm {\n\t\t\tfields[\"program_started\"] = service.Program.Started * 10000000\n\t\t\tfields[\"program_status\"] = service.Program.Status\n\t\t\tacc.AddFields(\"monit_program\", fields, tags)\n\t\t} else if service.Type == network {\n\t\t\tfields[\"link_state\"] = service.Link.State\n\t\t\tfields[\"link_speed\"] = service.Link.Speed\n\t\t\tfields[\"link_mode\"] = linkMode(service)\n\t\t\tfields[\"download_packets_now\"] = service.Link.Download.Packets.Now\n\t\t\tfields[\"download_packets_total\"] = service.Link.Download.Packets.Total\n\t\t\tfields[\"download_bytes_now\"] = service.Link.Download.Bytes.Now\n\t\t\tfields[\"download_bytes_total\"] = service.Link.Download.Bytes.Total\n\t\t\tfields[\"download_errors_now\"] = service.Link.Download.Errors.Now\n\t\t\tfields[\"download_errors_total\"] = service.Link.Download.Errors.Total\n\t\t\tfields[\"upload_packets_now\"] = service.Link.Upload.Packets.Now\n\t\t\tfields[\"upload_packets_total\"] = service.Link.Upload.Packets.Total\n\t\t\tfields[\"upload_bytes_now\"] = service.Link.Upload.Bytes.Now\n\t\t\tfields[\"upload_bytes_total\"] = service.Link.Upload.Bytes.Total\n\t\t\tfields[\"upload_errors_now\"] = service.Link.Upload.Errors.Now\n\t\t\tfields[\"upload_errors_total\"] = service.Link.Upload.Errors.Total\n\t\t\tacc.AddFields(\"monit_network\", fields, tags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc linkMode(s service) string {\n\tif s.Link.Duplex == 1 {\n\t\treturn \"duplex\"\n\t} else if s.Link.Duplex == 0 {\n\t\treturn \"simplex\"\n\t}\n\treturn \"unknown\"\n}\n\nfunc serviceStatus(s service) string {\n\tif s.Status == 0 {\n\t\treturn \"running\"\n\t}\n\treturn \"failure\"\n}\n\nfunc pendingAction(s service) string {\n\tif s.PendingAction > 0 {\n\t\tif s.PendingAction >= len(pendingActions) {\n\t\t\treturn \"unknown\"\n\t\t}\n\t\treturn pendingActions[s.PendingAction-1]\n\t}\n\treturn \"none\"\n}\n\nfunc monitoringMode(s service) string {\n\tswitch s.MonitorMode {\n\tcase 0:\n\t\treturn \"active\"\n\tcase 1:\n\t\treturn \"passive\"\n\t}\n\treturn \"unknown\"\n}\n\nfunc monitoringStatus(s service) string {\n\tswitch s.MonitoringStatus {\n\tcase 1:\n\t\treturn \"monitored\"\n\tcase 2:\n\t\treturn \"initializing\"\n\tcase 4:\n\t\treturn \"waiting\"\n\t}\n\treturn \"not_monitored\"\n}\n\nfunc init() {\n\tinputs.Add(\"monit\", func() telegraf.Input {\n\t\treturn &Monit{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/monit/monit_test.go",
    "content": "package monit\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype transportMock struct {\n}\n\nfunc (*transportMock) RoundTrip(*http.Request) (*http.Response, error) {\n\terrorString := \"get http://127.0.0.1:2812/_status?format=xml: \" +\n\t\t\"read tcp 192.168.10.2:55610->127.0.0.1:2812: \" +\n\t\t\"read: connection reset by peer\"\n\treturn nil, errors.New(errorString)\n}\n\nfunc TestServiceType(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:     \"check filesystem service type\",\n\t\t\tfilename: \"testdata/response_servicetype_0.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_filesystem\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"mode\":                   555,\n\t\t\t\t\t\t\"block_percent\":          29.5,\n\t\t\t\t\t\t\"block_usage\":            4424.0,\n\t\t\t\t\t\t\"block_total\":            14990.0,\n\t\t\t\t\t\t\"inode_percent\":          0.8,\n\t\t\t\t\t\t\"inode_usage\":            59674.0,\n\t\t\t\t\t\t\"inode_total\":            7680000.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check directory service type\",\n\t\t\tfilename: \"testdata/response_servicetype_1.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_directory\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"mode\":                   755,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check file service type\",\n\t\t\tfilename: \"testdata/response_servicetype_2.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_file\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"mode\":                   644,\n\t\t\t\t\t\t\"size\":                   1565,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check process service type\",\n\t\t\tfilename: \"testdata/response_servicetype_3.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"cpu_percent\":            0.0,\n\t\t\t\t\t\t\"cpu_percent_total\":      0.0,\n\t\t\t\t\t\t\"mem_kb\":                 22892,\n\t\t\t\t\t\t\"mem_kb_total\":           22892,\n\t\t\t\t\t\t\"mem_percent\":            0.1,\n\t\t\t\t\t\t\"mem_percent_total\":      0.1,\n\t\t\t\t\t\t\"pid\":                    5959,\n\t\t\t\t\t\t\"parent_pid\":             1,\n\t\t\t\t\t\t\"threads\":                31,\n\t\t\t\t\t\t\"children\":               0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check remote host service type\",\n\t\t\tfilename: \"testdata/response_servicetype_4.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_remote_host\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"remote_hostname\":        \"192.168.1.10\",\n\t\t\t\t\t\t\"port_number\":            2812,\n\t\t\t\t\t\t\"request\":                \"\",\n\t\t\t\t\t\t\"protocol\":               \"DEFAULT\",\n\t\t\t\t\t\t\"type\":                   \"TCP\",\n\t\t\t\t\t\t\"response_time\":          0.000145,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check system service type\",\n\t\t\tfilename: \"testdata/response_servicetype_5.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_system\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"cpu_system\":             0.1,\n\t\t\t\t\t\t\"cpu_user\":               0.0,\n\t\t\t\t\t\t\"cpu_wait\":               0.0,\n\t\t\t\t\t\t\"cpu_load_avg_1m\":        0.00,\n\t\t\t\t\t\t\"cpu_load_avg_5m\":        0.00,\n\t\t\t\t\t\t\"cpu_load_avg_15m\":       0.00,\n\t\t\t\t\t\t\"mem_kb\":                 259668,\n\t\t\t\t\t\t\"mem_percent\":            1.5,\n\t\t\t\t\t\t\"swap_kb\":                0.0,\n\t\t\t\t\t\t\"swap_percent\":           0.0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check fifo service type\",\n\t\t\tfilename: \"testdata/response_servicetype_6.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_fifo\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"mode\":                   664,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check program service type\",\n\t\t\tfilename: \"testdata/response_servicetype_7.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_program\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"program_status\":         0,\n\t\t\t\t\t\t\"program_started\":        int64(15728504980000000),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check network service type\",\n\t\t\tfilename: \"testdata/response_servicetype_8.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_network\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"link_speed\":             1000000000,\n\t\t\t\t\t\t\"link_mode\":              \"duplex\",\n\t\t\t\t\t\t\"link_state\":             1,\n\t\t\t\t\t\t\"download_packets_now\":   0,\n\t\t\t\t\t\t\"download_packets_total\": 15243,\n\t\t\t\t\t\t\"download_bytes_now\":     0,\n\t\t\t\t\t\t\"download_bytes_total\":   5506778,\n\t\t\t\t\t\t\"download_errors_now\":    0,\n\t\t\t\t\t\t\"download_errors_total\":  0,\n\t\t\t\t\t\t\"upload_packets_now\":     0,\n\t\t\t\t\t\t\"upload_packets_total\":   8822,\n\t\t\t\t\t\t\"upload_bytes_now\":       0,\n\t\t\t\t\t\t\"upload_bytes_total\":     1287240,\n\t\t\t\t\t\t\"upload_errors_now\":      0,\n\t\t\t\t\t\t\"upload_errors_total\":    0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/_status\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.filename)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Monit{\n\t\t\t\tAddress: ts.URL,\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestMonitFailure(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:     \"check monit failure status\",\n\t\t\tfilename: \"testdata/response_servicetype_8_failure.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_network\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"failure\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            8388608,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"link_speed\":             -1,\n\t\t\t\t\t\t\"link_mode\":              \"unknown\",\n\t\t\t\t\t\t\"link_state\":             0,\n\t\t\t\t\t\t\"download_packets_now\":   0,\n\t\t\t\t\t\t\"download_packets_total\": 0,\n\t\t\t\t\t\t\"download_bytes_now\":     0,\n\t\t\t\t\t\t\"download_bytes_total\":   0,\n\t\t\t\t\t\t\"download_errors_now\":    0,\n\t\t\t\t\t\t\"download_errors_total\":  0,\n\t\t\t\t\t\t\"upload_packets_now\":     0,\n\t\t\t\t\t\t\"upload_packets_total\":   0,\n\t\t\t\t\t\t\"upload_bytes_now\":       0,\n\t\t\t\t\t\t\"upload_bytes_total\":     0,\n\t\t\t\t\t\t\"upload_errors_now\":      0,\n\t\t\t\t\t\t\"upload_errors_total\":    0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check passive mode\",\n\t\t\tfilename: \"testdata/response_servicetype_8_passivemode.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_network\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"passive\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   1,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"link_speed\":             1000000000,\n\t\t\t\t\t\t\"link_mode\":              \"duplex\",\n\t\t\t\t\t\t\"link_state\":             1,\n\t\t\t\t\t\t\"download_packets_now\":   0,\n\t\t\t\t\t\t\"download_packets_total\": 15243,\n\t\t\t\t\t\t\"download_bytes_now\":     0,\n\t\t\t\t\t\t\"download_bytes_total\":   5506778,\n\t\t\t\t\t\t\"download_errors_now\":    0,\n\t\t\t\t\t\t\"download_errors_total\":  0,\n\t\t\t\t\t\t\"upload_packets_now\":     0,\n\t\t\t\t\t\t\"upload_packets_total\":   8822,\n\t\t\t\t\t\t\"upload_bytes_now\":       0,\n\t\t\t\t\t\t\"upload_bytes_total\":     1287240,\n\t\t\t\t\t\t\"upload_errors_now\":      0,\n\t\t\t\t\t\t\"upload_errors_total\":    0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check initializing status\",\n\t\t\tfilename: \"testdata/response_servicetype_8_initializingmode.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_network\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"initializing\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"none\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 2,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    0,\n\t\t\t\t\t\t\"link_speed\":             1000000000,\n\t\t\t\t\t\t\"link_mode\":              \"duplex\",\n\t\t\t\t\t\t\"link_state\":             1,\n\t\t\t\t\t\t\"download_packets_now\":   0,\n\t\t\t\t\t\t\"download_packets_total\": 15243,\n\t\t\t\t\t\t\"download_bytes_now\":     0,\n\t\t\t\t\t\t\"download_bytes_total\":   5506778,\n\t\t\t\t\t\t\"download_errors_now\":    0,\n\t\t\t\t\t\t\"download_errors_total\":  0,\n\t\t\t\t\t\t\"upload_packets_now\":     0,\n\t\t\t\t\t\t\"upload_packets_total\":   8822,\n\t\t\t\t\t\t\"upload_bytes_now\":       0,\n\t\t\t\t\t\t\"upload_bytes_total\":     1287240,\n\t\t\t\t\t\t\"upload_errors_now\":      0,\n\t\t\t\t\t\t\"upload_errors_total\":    0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"check pending action\",\n\t\t\tfilename: \"testdata/response_servicetype_8_pendingaction.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"monit_network\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"version\":           \"5.17.1\",\n\t\t\t\t\t\t\"source\":            \"localhost\",\n\t\t\t\t\t\t\"platform_name\":     \"Linux\",\n\t\t\t\t\t\t\"service\":           \"test\",\n\t\t\t\t\t\t\"status\":            \"running\",\n\t\t\t\t\t\t\"monitoring_status\": \"monitored\",\n\t\t\t\t\t\t\"monitoring_mode\":   \"active\",\n\t\t\t\t\t\t\"pending_action\":    \"exec\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"status_code\":            0,\n\t\t\t\t\t\t\"monitoring_status_code\": 1,\n\t\t\t\t\t\t\"monitoring_mode_code\":   0,\n\t\t\t\t\t\t\"pending_action_code\":    5,\n\t\t\t\t\t\t\"link_speed\":             1000000000,\n\t\t\t\t\t\t\"link_mode\":              \"duplex\",\n\t\t\t\t\t\t\"link_state\":             1,\n\t\t\t\t\t\t\"download_packets_now\":   0,\n\t\t\t\t\t\t\"download_packets_total\": 15243,\n\t\t\t\t\t\t\"download_bytes_now\":     0,\n\t\t\t\t\t\t\"download_bytes_total\":   5506778,\n\t\t\t\t\t\t\"download_errors_now\":    0,\n\t\t\t\t\t\t\"download_errors_total\":  0,\n\t\t\t\t\t\t\"upload_packets_now\":     0,\n\t\t\t\t\t\t\"upload_packets_total\":   8822,\n\t\t\t\t\t\t\"upload_bytes_now\":       0,\n\t\t\t\t\t\t\"upload_bytes_total\":     1287240,\n\t\t\t\t\t\t\"upload_errors_now\":      0,\n\t\t\t\t\t\t\"upload_errors_total\":    0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/_status\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.filename)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Monit{\n\t\t\t\tAddress: ts.URL,\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc checkAuth(r *http.Request, username, password string) bool {\n\tuser, pass, ok := r.BasicAuth()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn user == username && pass == password\n}\n\nfunc TestAllowHosts(t *testing.T) {\n\tr := &Monit{\n\t\tAddress:  \"http://127.0.0.1:2812\",\n\t\tUsername: \"test\",\n\t\tPassword: \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tr.client.Transport = &transportMock{}\n\n\terr := r.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"read: connection reset by peer\")\n}\n\nfunc TestConnection(t *testing.T) {\n\tr := &Monit{\n\t\tAddress:  \"http://127.0.0.1:2812\",\n\t\tUsername: \"test\",\n\t\tPassword: \"test\",\n\t}\n\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\n\terr := r.Gather(&acc)\n\trequire.Error(t, err)\n\n\tvar urlErr *url.Error\n\trequire.ErrorAs(t, err, &urlErr)\n}\n\nfunc TestInvalidUsernameOrPassword(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"testing\", \"testing\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tif r.URL.Path != \"/_status\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"/_status\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\t\thttp.ServeFile(w, r, \"testdata/response_servicetype_0.xml\")\n\t}))\n\n\tdefer ts.Close()\n\n\tr := &Monit{\n\t\tAddress:  ts.URL,\n\t\tUsername: \"test\",\n\t\tPassword: \"test\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, r.Init())\n\n\terr := r.Gather(&acc)\n\trequire.EqualError(t, err, \"received status code 401 (Unauthorized), expected 200\")\n}\n\nfunc TestNoUsernameOrPasswordConfiguration(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"testing\", \"testing\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tif r.URL.Path != \"/_status\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"/_status\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\t\thttp.ServeFile(w, r, \"testdata/response_servicetype_0.xml\")\n\t}))\n\n\tdefer ts.Close()\n\n\tr := &Monit{\n\t\tAddress: ts.URL,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, r.Init())\n\n\terr := r.Gather(&acc)\n\trequire.EqualError(t, err, \"received status code 401 (Unauthorized), expected 200\")\n}\n\nfunc TestInvalidXMLAndInvalidTypes(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t}{\n\t\t{\n\t\t\tname:     \"check filesystem service type\",\n\t\t\tfilename: \"testdata/response_invalidxml_1.xml\",\n\t\t},\n\t\t{\n\t\t\tname:     \"check filesystem service type\",\n\t\t\tfilename: \"testdata/response_invalidxml_2.xml\",\n\t\t},\n\t\t{\n\t\t\tname:     \"check filesystem service type\",\n\t\t\tfilename: \"testdata/response_invalidxml_3.xml\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/_status\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.filename)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Monit{\n\t\t\t\tAddress: ts.URL,\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\terr := plugin.Gather(&acc)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"error parsing input:\")\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/monit/sample.conf",
    "content": "# Read metrics and status information about processes managed by Monit\n[[inputs.monit]]\n  ## Monit HTTPD address\n  address = \"http://127.0.0.1:2812\"\n\n  ## Username and Password for Monit\n  # username = \"\"\n  # password = \"\"\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_invalidxml_1.xml",
    "content": "<!--Missing element <block> closed-->\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"0\">\n        <name>test</name>\n        <collected_sec>1572850498</collected_sec>\n        <collected_usec>709694</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>555</mode>\n        <uid>0</uid>\n        <gid>0</gid>\n        <flags>4096</flags>\n        <block>\n            <percent>29.5</percent>\n            <usage>4424.0</usage>\n            <total>14990.0</total>\n        <inode>\n            <percent>0.8</percent>\n            <usage>59674</usage>\n            <total>7680000</total>\n        </inode>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_invalidxml_2.xml",
    "content": "<!--Wrong status type-->\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"0\">\n        <name>test</name>\n        <collected_sec>1572850498</collected_sec>\n        <collected_usec>709694</collected_usec>\n        <status>0.0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>555</mode>\n        <uid>0</uid>\n        <gid>0</gid>\n        <flags>4096</flags>\n        <block>\n            <percent>29.5</percent>\n            <usage>4424.0</usage>\n            <total>14990.0</total>\n        </block>\n        <inode>\n            <percent>0.8</percent>\n            <usage>59674</usage>\n            <total>7680000</total>\n        </inode>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_invalidxml_3.xml",
    "content": "<!--Unsupported encoding type-->\n<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"0\">\n        <name>test</name>\n        <collected_sec>1572850498</collected_sec>\n        <collected_usec>709694</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>555</mode>\n        <uid>0</uid>\n        <gid>0</gid>\n        <flags>4096</flags>\n        <block>\n            <percent>29.5</percent>\n            <usage>4424.0</usage>\n            <total>14990.0</total>\n        </block>\n        <inode>\n            <percent>0.8</percent>\n            <usage>59674</usage>\n            <total>7680000</total>\n        </inode>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_0.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"0\">\n        <name>test</name>\n        <collected_sec>1572850498</collected_sec>\n        <collected_usec>709694</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>555</mode>\n        <uid>0</uid>\n        <gid>0</gid>\n        <flags>4096</flags>\n        <block>\n            <percent>29.5</percent>\n            <usage>4424.0</usage>\n            <total>14990.0</total>\n        </block>\n        <inode>\n            <percent>0.8</percent>\n            <usage>59674</usage>\n            <total>7680000</total>\n        </inode>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"1\">\n        <name>test</name>\n        <collected_sec>1572850342</collected_sec>\n        <collected_usec>546082</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>755</mode>\n        <uid>0</uid>\n        <gid>0</gid>\n        <timestamp>1572272434</timestamp>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"2\">\n        <name>test</name>\n        <collected_sec>1476628305</collected_sec>\n        <collected_usec>302669</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>644</mode>\n        <uid>1000</uid>\n        <gid>1000</gid>\n        <timestamp>1476518441</timestamp>\n        <size>1565</size>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_3.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"3\">\n        <name>test</name>\n        <collected_sec>1476628305</collected_sec>\n        <collected_usec>302552</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <pid>5959</pid>\n        <ppid>1</ppid>\n        <uptime>109870</uptime>\n        <children>0</children>\n        <threads>31</threads>\n        <memory>\n            <percent>0.1</percent>\n            <percenttotal>0.1</percenttotal>\n            <kilobyte>22892</kilobyte>\n            <kilobytetotal>22892</kilobytetotal>\n        </memory>\n        <cpu>\n            <percent>0.0</percent>\n            <percenttotal>0.0</percenttotal>\n        </cpu>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_4.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"4\">\n        <name>test</name>\n        <collected_sec>1572862451</collected_sec>\n        <collected_usec>947671</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <port>\n            <hostname>192.168.1.10</hostname>\n            <portnumber>2812</portnumber>\n            <request></request>\n            <protocol>DEFAULT</protocol>\n            <type>TCP</type>\n            <responsetime>0.000145</responsetime>\n        </port>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_5.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"5\">\n        <name>test</name>\n        <collected_sec>1476628305</collected_sec>\n        <collected_usec>302682</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <system>\n            <load>\n                <avg01>0.00</avg01>\n                <avg05>0.00</avg05>\n                <avg15>0.00</avg15>\n            </load>\n            <cpu>\n                <user>0.0</user>\n                <system>0.1</system>\n                <wait>0.0</wait>\n            </cpu>\n            <memory>\n                <percent>1.5</percent>\n                <kilobyte>259668</kilobyte>\n            </memory>\n            <swap>\n                <percent>0.0</percent>\n                <kilobyte>0</kilobyte>\n            </swap>\n        </system>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_6.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"6\">\n        <name>test</name>\n        <collected_sec>1572862451</collected_sec>\n        <collected_usec>947495</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <mode>664</mode>\n        <uid>1000</uid>\n        <gid>1000</gid>\n        <timestamp>1572271731</timestamp>\n    </service>\n</monit>"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_7.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"7\">\n        <name>test</name>\n        <collected_sec>1572850498</collected_sec>\n        <collected_usec>710675</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <program>\n            <started>1572850498</started>\n            <status>0</status>\n            <output>Stats health check successful.</output>\n        </program>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_8.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"8\">\n        <name>test</name>\n        <collected_sec>1572869770</collected_sec>\n        <collected_usec>807562</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <link>\n            <state>1</state>\n            <speed>1000000000</speed>\n            <duplex>1</duplex>\n            <download>\n                <packets>\n                    <now>0</now>\n                    <total>15243</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>5506778</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </download>\n            <upload>\n                <packets>\n                    <now>0</now>\n                    <total>8822</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>1287240</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </upload>\n        </link>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_8_failure.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"8\">\n        <name>test</name>\n        <collected_sec>1572869770</collected_sec>\n        <collected_usec>807562</collected_usec>\n        <status>8388608</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <link>\n            <state>0</state>\n            <speed>-1</speed>\n            <duplex>-1</duplex>\n            <download>\n                <packets>\n                    <now>0</now>\n                    <total>0</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>0</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </download>\n            <upload>\n                <packets>\n                    <now>0</now>\n                    <total>0</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>0</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </upload>\n        </link>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_8_initializingmode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"8\">\n        <name>test</name>\n        <collected_sec>1572869770</collected_sec>\n        <collected_usec>807562</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>2</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>0</pendingaction>\n        <link>\n            <state>1</state>\n            <speed>1000000000</speed>\n            <duplex>1</duplex>\n            <download>\n                <packets>\n                    <now>0</now>\n                    <total>15243</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>5506778</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </download>\n            <upload>\n                <packets>\n                    <now>0</now>\n                    <total>8822</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>1287240</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </upload>\n        </link>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_8_passivemode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"8\">\n        <name>test</name>\n        <collected_sec>1572869770</collected_sec>\n        <collected_usec>807562</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>1</monitormode>\n        <pendingaction>0</pendingaction>\n        <link>\n            <state>1</state>\n            <speed>1000000000</speed>\n            <duplex>1</duplex>\n            <download>\n                <packets>\n                    <now>0</now>\n                    <total>15243</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>5506778</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </download>\n            <upload>\n                <packets>\n                    <now>0</now>\n                    <total>8822</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>1287240</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </upload>\n        </link>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/monit/testdata/response_servicetype_8_pendingaction.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<monit>\n    <server>\n        <id>0ed39c522be4c3971541412c43141613</id>\n        <incarnation>1476518435</incarnation>\n        <version>5.17.1</version>\n        <uptime>109878</uptime>\n        <poll>10</poll>\n        <startdelay>0</startdelay>\n        <localhostname>localhost</localhostname>\n        <controlfile>/var/vcap/bosh/etc/monitrc</controlfile>\n        <httpd>\n            <address>127.0.0.1</address>\n            <port>2822</port>\n            <ssl>0</ssl>\n        </httpd>\n    </server>\n    <platform>\n        <name>Linux</name>\n        <release>4.15.0-65-generic</release>\n        <version>#74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019</version>\n        <machine>x86_64</machine>\n        <cpu>8</cpu>\n        <memory>16432272</memory>\n        <swap>16432268</swap>\n    </platform>\n    <service type=\"8\">\n        <name>test</name>\n        <collected_sec>1572869770</collected_sec>\n        <collected_usec>807562</collected_usec>\n        <status>0</status>\n        <status_hint>0</status_hint>\n        <monitor>1</monitor>\n        <monitormode>0</monitormode>\n        <pendingaction>5</pendingaction>\n        <link>\n            <state>1</state>\n            <speed>1000000000</speed>\n            <duplex>1</duplex>\n            <download>\n                <packets>\n                    <now>0</now>\n                    <total>15243</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>5506778</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </download>\n            <upload>\n                <packets>\n                    <now>0</now>\n                    <total>8822</total>\n                </packets>\n                <bytes>\n                    <now>0</now>\n                    <total>1287240</total>\n                </bytes>\n                <errors>\n                    <now>0</now>\n                    <total>0</total>\n                </errors>\n            </upload>\n        </link>\n    </service>\n</monit>\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/README.md",
    "content": "# MQTT Consumer Input Plugin\n\nThis service plugin consumes messages from [MQTT][mqtt] brokers for the\nconfigured topics in one of the supported [data formats][data_formats].\n\n⭐ Telegraf v0.10.3\n🏷️ messaging\n💻 all\n\n[mqtt]: https://mqtt.org\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options <!-- @/docs/includes/startup_error_behavior.md -->\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  Telegraf will try to startup the plugin in every gather or write\n            cycle in case of startup errors. The plugin is disabled until\n            the startup succeeds.\n- `probe`:  Telegraf will probe the plugin's function (if possible) and disables\n            the plugin in case probing fails. If the plugin does not support\n            probing, Telegraf will behave as if `ignore` was set instead.\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from MQTT topic(s)\n[[inputs.mqtt_consumer]]\n  ## Broker URLs for the MQTT server or cluster.  To connect to multiple\n  ## clusters or standalone servers, use a separate plugin instance.\n  ##   example: servers = [\"tcp://localhost:1883\"]\n  ##            servers = [\"ssl://localhost:1883\"]\n  ##            servers = [\"ws://localhost:1883\"]\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Topics that will be subscribed to.\n  topics = [\n    \"telegraf/host01/cpu\",\n    \"telegraf/+/mem\",\n    \"sensors/#\",\n  ]\n\n  ## The message topic will be stored in a tag specified by this value.  If set\n  ## to the empty string no topic tag will be created.\n  # topic_tag = \"topic\"\n\n  ## QoS policy for messages\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  ##\n  ## When using a QoS of 1 or 2, you should enable persistent_session to allow\n  ## resuming unacknowledged messages.\n  # qos = 0\n\n  ## Connection timeout for initial connection in seconds\n  # connection_timeout = \"30s\"\n\n  ## Maximum interval between reconnection attempts after a connection loss.\n  ## The MQTT library uses exponential backoff starting at 1 second up to this\n  ## ceiling. The library default is 10 minutes, which can cause long delays\n  ## before message flow resumes after a network outage.\n  # max_reconnect_interval = \"30s\"\n\n  ## Interval and ping timeout for keep-alive messages\n  ## The sum of those options defines when a connection loss is detected.\n  ## Note: The keep-alive interval needs to be greater or equal one second and\n  ## fractions of a second are not supported.\n  # keepalive = \"60s\"\n  # ping_timeout = \"10s\"\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Persistent session disables clearing of the client session on connection.\n  ## In order for this option to work you must also set client_id to identify\n  ## the client.  To receive messages that arrived while the client is offline,\n  ## also set the qos option to 1 or 2 and don't forget to also set the QoS when\n  ## publishing. Finally, using a persistent session will use the initial\n  ## connection topics and not subscribe to any new topics even after\n  ## reconnecting or restarting without a change in client ID.\n  # persistent_session = false\n\n  ## If unset, a random client ID will be generated.\n  # client_id = \"\"\n\n  ## Username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Enable extracting tag values from MQTT topics\n  ## _ denotes an ignored entry in the topic path,\n  ## # denotes a variable length path element (can only be used once per setting)\n  # [[inputs.mqtt_consumer.topic_parsing]]\n  #   topic = \"\"\n  #   measurement = \"\"\n  #   tags = \"\"\n  #   fields = \"\"\n  ## Value supported is int, float, unit\n  #   [inputs.mqtt_consumer.topic_parsing.types]\n  #      key = type\n```\n\n## Example Output\n\n```text\nmqtt_consumer,host=pop-os,topic=telegraf/host01/cpu value=45i 1653579140440951943\nmqtt_consumer,host=pop-os,topic=telegraf/host01/cpu value=100i 1653579153147395661\n```\n\n## About Topic Parsing\n\nThe MQTT topic as a whole is stored as a tag, but this can be far too coarse to\nbe easily used when utilizing the data further down the line. This change allows\ntag values to be extracted from the MQTT topic letting you store the information\nprovided in the topic in a meaningful way. An `_` denotes an ignored entry in\nthe topic path. Please see the following example.\n\n### Topic Parsing Example\n\n```toml\n[[inputs.mqtt_consumer]]\n  ## Broker URLs for the MQTT server or cluster.  To connect to multiple\n  ## clusters or standalone servers, use a separate plugin instance.\n  ##   example: servers = [\"tcp://localhost:1883\"]\n  ##            servers = [\"ssl://localhost:1883\"]\n  ##            servers = [\"ws://localhost:1883\"]\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Topics that will be subscribed to.\n  topics = [\n    \"telegraf/+/cpu/23\",\n  ]\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"value\"\n  data_type = \"float\"\n\n  [[inputs.mqtt_consumer.topic_parsing]]\n    topic = \"telegraf/one/cpu/23\"\n    measurement = \"_/_/measurement/_\"\n    tags = \"tag/_/_/_\"\n    fields = \"_/_/_/test\"\n    [inputs.mqtt_consumer.topic_parsing.types]\n      test = \"int\"\n```\n\nWill result in the following metric:\n\n```text\ncpu,host=pop-os,tag=telegraf,topic=telegraf/one/cpu/23 value=45,test=23i 1637014942460689291\n```\n\n## Field Pivoting Example\n\nYou can use the pivot processor to rotate single valued metrics into a\nmulti-field metric. For more info check out the [pivot processor][plugin_pivot].\n\nFor this example these are the topics:\n\n```text\n/sensors/CLE/v1/device5/temp\n/sensors/CLE/v1/device5/rpm\n/sensors/CLE/v1/device5/ph\n/sensors/CLE/v1/device5/spin\n```\n\nAnd these are the metrics:\n\n```text\nsensors,site=CLE,version=v1,device_name=device5,field=temp value=390\nsensors,site=CLE,version=v1,device_name=device5,field=rpm value=45.0\nsensors,site=CLE,version=v1,device_name=device5,field=ph value=1.45\n```\n\nUsing pivot in the config will rotate the metrics into a multi field metric.\nThe config:\n\n```toml\n[[inputs.mqtt_consumer]]\n    ....\n    topics = \"/sensors/#\"\n    [[inputs.mqtt_consumer.topic_parsing]]\n        measurement = \"/measurement/_/_/_/_\"\n        tags = \"/_/site/version/device_name/field\"\n[[processors.pivot]]\n    tag_key = \"field\"\n    value_key = \"value\"\n```\n\nWill result in the following metric:\n\n```text\nsensors,site=CLE,version=v1,device_name=device5 temp=390,rpm=45.0,ph=1.45\n```\n\n[plugin_pivot]: /plugins/processors/pivot/README.md\n\n## Metrics\n\n- All measurements are tagged with the incoming topic, ie\n`topic=telegraf/host01/cpu`\n\n- example when [[inputs.mqtt_consumer.topic_parsing]] is set\n\n- when [[inputs.internal]] is set:\n  - payload_size (int): get the cumulative size in bytes that have been received\n                        from incoming messages\n  - messages_received (int): count of the number of messages that have been\n                            received from mqtt\n\nThis will result in the following metric:\n\n```text\ninternal_mqtt_consumer host=pop-os version=1.24.0 messages_received=622i payload_size=37942i 1657282270000000000\n```\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/mqtt_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mqtt_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tmqtt \"github.com/eclipse/paho.mqtt.golang\"\n\t\"github.com/eclipse/paho.mqtt.golang/packets\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tonce sync.Once\n\t// 30 Seconds is the default used by paho.mqtt.golang\n\tdefaultConnectionTimeout      = config.Duration(30 * time.Second)\n\tdefaultMaxReconnectInterval   = config.Duration(30 * time.Second)\n\tdefaultMaxUndeliveredMessages = 1000\n)\n\ntype MQTTConsumer struct {\n\tServers                []string             `toml:\"servers\"`\n\tTopics                 []string             `toml:\"topics\"`\n\tTopicTag               *string              `toml:\"topic_tag\"`\n\tTopicParserConfig      []topicParsingConfig `toml:\"topic_parsing\"`\n\tUsername               config.Secret        `toml:\"username\"`\n\tPassword               config.Secret        `toml:\"password\"`\n\tQoS                    int                  `toml:\"qos\"`\n\tConnectionTimeout      config.Duration      `toml:\"connection_timeout\"`\n\tMaxReconnectInterval   config.Duration      `toml:\"max_reconnect_interval\"`\n\tKeepAliveInterval      config.Duration      `toml:\"keepalive\"`\n\tPingTimeout            config.Duration      `toml:\"ping_timeout\"`\n\tMaxUndeliveredMessages int                  `toml:\"max_undelivered_messages\"`\n\tPersistentSession      bool                 `toml:\"persistent_session\"`\n\tClientTrace            bool                 `toml:\"client_trace\"`\n\tClientID               string               `toml:\"client_id\"`\n\tLog                    telegraf.Logger      `toml:\"-\"`\n\ttls.ClientConfig\n\n\tparser        telegraf.Parser\n\tclientFactory clientFactory\n\tclient        client\n\topts          *mqtt.ClientOptions\n\tacc           telegraf.TrackingAccumulator\n\tsem           semaphore\n\tmessages      map[telegraf.TrackingID]mqtt.Message\n\tmessagesMutex sync.Mutex\n\ttopicTagParse string\n\ttopicParsers  []*topicParser\n\tctx           context.Context\n\tcancel        context.CancelFunc\n\tpayloadSize   selfstat.Stat\n\tmessagesRecv  selfstat.Stat\n\twg            sync.WaitGroup\n}\n\ntype client interface {\n\tConnect() mqtt.Token\n\tSubscribeMultiple(filters map[string]byte, callback mqtt.MessageHandler) mqtt.Token\n\tAddRoute(topic string, callback mqtt.MessageHandler)\n\tDisconnect(quiesce uint)\n\tIsConnected() bool\n}\n\ntype empty struct{}\ntype semaphore chan empty\ntype clientFactory func(o *mqtt.ClientOptions) client\n\nfunc (*MQTTConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *MQTTConsumer) Init() error {\n\tif m.ClientTrace {\n\t\tlog := &mqttLogger{m.Log}\n\t\tmqtt.ERROR = log\n\t\tmqtt.CRITICAL = log\n\t\tmqtt.WARN = log\n\t\tmqtt.DEBUG = log\n\t}\n\n\tif m.PersistentSession && m.ClientID == \"\" {\n\t\treturn errors.New(\"persistent_session requires client_id\")\n\t}\n\tif m.QoS > 2 || m.QoS < 0 {\n\t\treturn fmt.Errorf(\"qos value must be 0, 1, or 2: %d\", m.QoS)\n\t}\n\tif time.Duration(m.ConnectionTimeout) < 1*time.Second {\n\t\treturn fmt.Errorf(\"connection_timeout must be greater than 1s: %s\", time.Duration(m.ConnectionTimeout))\n\t}\n\tm.topicTagParse = \"topic\"\n\tif m.TopicTag != nil {\n\t\tm.topicTagParse = *m.TopicTag\n\t}\n\topts, err := m.createOpts()\n\tif err != nil {\n\t\treturn err\n\t}\n\tm.opts = opts\n\tm.messages = make(map[telegraf.TrackingID]mqtt.Message)\n\n\tm.topicParsers = make([]*topicParser, 0, len(m.TopicParserConfig))\n\tfor _, cfg := range m.TopicParserConfig {\n\t\tp, err := cfg.newParser()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"config error topic parsing: %w\", err)\n\t\t}\n\t\tm.topicParsers = append(m.topicParsers, p)\n\t}\n\n\tm.payloadSize = selfstat.Register(\"mqtt_consumer\", \"payload_size\", make(map[string]string))\n\tm.messagesRecv = selfstat.Register(\"mqtt_consumer\", \"messages_received\", make(map[string]string))\n\treturn nil\n}\n\nfunc (m *MQTTConsumer) SetParser(parser telegraf.Parser) {\n\tm.parser = parser\n}\n\nfunc (m *MQTTConsumer) Start(acc telegraf.Accumulator) error {\n\tm.acc = acc.WithTracking(m.MaxUndeliveredMessages)\n\tm.sem = make(semaphore, m.MaxUndeliveredMessages)\n\tm.ctx, m.cancel = context.WithCancel(context.Background())\n\n\tm.wg.Add(1)\n\tgo func() {\n\t\tdefer m.wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-m.ctx.Done():\n\t\t\t\treturn\n\t\t\tcase track := <-m.acc.Delivered():\n\t\t\t\tm.onDelivered(track)\n\t\t\t}\n\t\t}\n\t}()\n\n\tif err := m.connect(); err != nil {\n\t\tm.Stop()\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (*MQTTConsumer) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (m *MQTTConsumer) Stop() {\n\tif m.client != nil {\n\t\t// Disconnect is safe to call on an already-disconnected client;\n\t\t// paho logs a warning and returns early in that case.\n\t\tm.Log.Debugf(\"Disconnecting %v\", m.Servers)\n\t\tm.client.Disconnect(200)\n\t\tm.Log.Debugf(\"Disconnected %v\", m.Servers)\n\t}\n\tif m.cancel != nil {\n\t\tm.cancel()\n\t}\n\tm.wg.Wait()\n}\n\nfunc (m *MQTTConsumer) connect() error {\n\tm.client = m.clientFactory(m.opts)\n\t// AddRoute sets up the function for handling messages. These need to be\n\t// added in case we find a persistent session containing subscriptions so we\n\t// know where to dispatch persisted and new messages to. In the alternate\n\t// case that we need to create the subscriptions these will be replaced.\n\tfor _, topic := range m.Topics {\n\t\tm.client.AddRoute(topic, m.onMessage)\n\t}\n\ttoken := m.client.Connect()\n\tif token.Wait() && token.Error() != nil {\n\t\tif ct, ok := token.(*mqtt.ConnectToken); ok && ct.ReturnCode() == packets.ErrNetworkError {\n\t\t\treturn &internal.StartupError{\n\t\t\t\tErr:   token.Error(),\n\t\t\t\tRetry: true,\n\t\t\t}\n\t\t}\n\t\treturn token.Error()\n\t}\n\t// Logging and subscribing are handled by onConnect(), which paho\n\t// invokes on every successful connection including the initial one.\n\treturn nil\n}\n\nfunc (m *MQTTConsumer) onConnect(_ mqtt.Client) {\n\tm.Log.Infof(\"Connected %v\", m.Servers)\n\ttopics := make(map[string]byte)\n\tfor _, topic := range m.Topics {\n\t\ttopics[topic] = byte(m.QoS)\n\t}\n\tsubscribeToken := m.client.SubscribeMultiple(topics, m.onMessage)\n\tsubscribeToken.Wait()\n\tif subscribeToken.Error() != nil {\n\t\tm.acc.AddError(fmt.Errorf(\"subscription error: topics %q: %w\", strings.Join(m.Topics, \",\"), subscribeToken.Error()))\n\t}\n}\n\nfunc (m *MQTTConsumer) onConnectionLost(_ mqtt.Client, err error) {\n\tm.acc.AddError(fmt.Errorf(\"connection lost: %w\", err))\n\tm.Log.Debugf(\"Disconnected %v\", m.Servers)\n}\n\nfunc (m *MQTTConsumer) onDelivered(track telegraf.DeliveryInfo) {\n\t<-m.sem\n\n\tm.messagesMutex.Lock()\n\tdefer m.messagesMutex.Unlock()\n\n\tmsg, ok := m.messages[track.ID()]\n\tif !ok {\n\t\tm.Log.Errorf(\"could not mark message delivered: %d\", track.ID())\n\t\treturn\n\t}\n\n\tif track.Delivered() && m.PersistentSession {\n\t\tmsg.Ack()\n\t}\n\n\tdelete(m.messages, track.ID())\n}\n\nfunc (m *MQTTConsumer) onMessage(_ mqtt.Client, msg mqtt.Message) {\n\tm.sem <- empty{}\n\n\tpayloadBytes := len(msg.Payload())\n\tm.payloadSize.Incr(int64(payloadBytes))\n\tm.messagesRecv.Incr(1)\n\n\tmetrics, err := m.parser.Parse(msg.Payload())\n\tif err != nil || len(metrics) == 0 {\n\t\tif len(metrics) == 0 {\n\t\t\tonce.Do(func() {\n\t\t\t\tm.Log.Warn(internal.NoMetricsCreatedMsg)\n\t\t\t})\n\t\t}\n\n\t\tif m.PersistentSession {\n\t\t\tmsg.Ack()\n\t\t}\n\t\tm.acc.AddError(err)\n\t\t<-m.sem\n\t\treturn\n\t}\n\n\tfor _, metric := range metrics {\n\t\tif m.topicTagParse != \"\" {\n\t\t\tmetric.AddTag(m.topicTagParse, msg.Topic())\n\t\t}\n\t\tfor _, p := range m.topicParsers {\n\t\t\tif err := p.parse(metric, msg.Topic()); err != nil {\n\t\t\t\tif m.PersistentSession {\n\t\t\t\t\tmsg.Ack()\n\t\t\t\t}\n\t\t\t\tm.acc.AddError(err)\n\t\t\t\t<-m.sem\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\tm.messagesMutex.Lock()\n\tid := m.acc.AddTrackingMetricGroup(metrics)\n\tm.messages[id] = msg\n\tm.messagesMutex.Unlock()\n}\n\nfunc (m *MQTTConsumer) createOpts() (*mqtt.ClientOptions, error) {\n\topts := mqtt.NewClientOptions()\n\topts.ConnectTimeout = time.Duration(m.ConnectionTimeout)\n\tif m.ClientID == \"\" {\n\t\trandomString, err := internal.RandomString(5)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"generating random string for client ID failed: %w\", err)\n\t\t}\n\t\topts.SetClientID(\"Telegraf-Consumer-\" + randomString)\n\t} else {\n\t\topts.SetClientID(m.ClientID)\n\t}\n\ttlsCfg, err := m.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif tlsCfg != nil {\n\t\topts.SetTLSConfig(tlsCfg)\n\t}\n\tif !m.Username.Empty() {\n\t\tuser, err := m.Username.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting username failed: %w\", err)\n\t\t}\n\t\topts.SetUsername(user.String())\n\t\tuser.Destroy()\n\t}\n\n\tif !m.Password.Empty() {\n\t\tpassword, err := m.Password.Get()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting password failed: %w\", err)\n\t\t}\n\t\topts.SetPassword(password.String())\n\t\tpassword.Destroy()\n\t}\n\tif len(m.Servers) == 0 {\n\t\treturn opts, errors.New(\"could not get host information\")\n\t}\n\tfor _, server := range m.Servers {\n\t\t// Preserve support for host:port style servers; deprecated in Telegraf 1.4.4\n\t\tif !strings.Contains(server, \"://\") {\n\t\t\tm.Log.Warnf(\"Server %q should be updated to use `scheme://host:port` format\", server)\n\t\t\tif tlsCfg == nil {\n\t\t\t\tserver = \"tcp://\" + server\n\t\t\t} else {\n\t\t\t\tserver = \"ssl://\" + server\n\t\t\t}\n\t\t}\n\t\topts.AddBroker(server)\n\t}\n\topts.SetAutoReconnect(true)\n\topts.SetMaxReconnectInterval(time.Duration(m.MaxReconnectInterval))\n\topts.SetKeepAlive(time.Duration(m.KeepAliveInterval))\n\topts.SetPingTimeout(time.Duration(m.PingTimeout))\n\topts.SetCleanSession(!m.PersistentSession)\n\topts.SetAutoAckDisabled(m.PersistentSession)\n\topts.SetConnectionLostHandler(m.onConnectionLost)\n\topts.SetOnConnectHandler(m.onConnect)\n\treturn opts, nil\n}\n\nfunc newMQTTConsumer(factory clientFactory) *MQTTConsumer {\n\treturn &MQTTConsumer{\n\t\tServers:                []string{\"tcp://127.0.0.1:1883\"},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      defaultConnectionTimeout,\n\t\tMaxReconnectInterval:   defaultMaxReconnectInterval,\n\t\tKeepAliveInterval:      config.Duration(60 * time.Second),\n\t\tPingTimeout:            config.Duration(10 * time.Second),\n\t\tclientFactory:          factory,\n\t}\n}\nfunc init() {\n\tinputs.Add(\"mqtt_consumer\", func() telegraf.Input {\n\t\treturn newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\t\treturn mqtt.NewClient(o)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/mqtt_consumer_test.go",
    "content": "package mqtt_consumer\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\tmqtt \"github.com/eclipse/paho.mqtt.golang\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype fakeClient struct {\n\tconnectF           func() mqtt.Token\n\tsubscribeMultipleF func() mqtt.Token\n\taddRouteF          func(callback mqtt.MessageHandler)\n\tdisconnectF        func()\n\topts               *mqtt.ClientOptions\n\n\tconnectCallCount    int\n\tsubscribeCallCount  int\n\taddRouteCallCount   int\n\tdisconnectCallCount int\n\n\tconnected bool\n}\n\nfunc (c *fakeClient) Connect() mqtt.Token {\n\tc.connectCallCount++\n\ttoken := c.connectF()\n\tc.connected = token.Error() == nil\n\tif c.connected && c.opts != nil && c.opts.OnConnect != nil {\n\t\tc.opts.OnConnect(nil)\n\t}\n\treturn token\n}\n\nfunc (c *fakeClient) SubscribeMultiple(map[string]byte, mqtt.MessageHandler) mqtt.Token {\n\tc.subscribeCallCount++\n\treturn c.subscribeMultipleF()\n}\n\nfunc (c *fakeClient) AddRoute(_ string, callback mqtt.MessageHandler) {\n\tc.addRouteCallCount++\n\tc.addRouteF(callback)\n}\n\nfunc (c *fakeClient) Disconnect(uint) {\n\tc.disconnectCallCount++\n\tc.disconnectF()\n\tc.connected = false\n}\n\nfunc (c *fakeClient) IsConnected() bool {\n\treturn c.connected\n}\n\ntype fakeParser struct{}\n\n// fakeParser satisfies telegraf.Parser\nvar _ telegraf.Parser = &fakeParser{}\n\nfunc (*fakeParser) Parse([]byte) ([]telegraf.Metric, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (*fakeParser) ParseLine(string) (telegraf.Metric, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (*fakeParser) SetDefaultTags(map[string]string) {\n\tpanic(\"not implemented\")\n}\n\ntype fakeToken struct {\n\tsessionPresent bool\n\tcomplete       chan struct{}\n}\n\n// fakeToken satisfies mqtt.Token\nvar _ mqtt.Token = &fakeToken{}\n\nfunc (*fakeToken) Wait() bool {\n\treturn true\n}\n\nfunc (*fakeToken) WaitTimeout(time.Duration) bool {\n\treturn true\n}\n\nfunc (*fakeToken) Error() error {\n\treturn nil\n}\n\nfunc (t *fakeToken) SessionPresent() bool {\n\treturn t.sessionPresent\n}\n\nfunc (t *fakeToken) Done() <-chan struct{} {\n\treturn t.complete\n}\n\n// Test the basic lifecycle transitions of the plugin.\nfunc TestLifecycleSanity(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tfClient := &fakeClient{\n\t\tconnectF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\taddRouteF: func(mqtt.MessageHandler) {\n\t\t},\n\t\tsubscribeMultipleF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\tdisconnectF: func() {\n\t\t},\n\t}\n\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\tfClient.opts = o\n\t\treturn fClient\n\t})\n\tplugin.Log = testutil.Logger{}\n\tplugin.Servers = []string{\"tcp://127.0.0.1\"}\n\n\tparser := &fakeParser{}\n\tplugin.SetParser(parser)\n\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n}\n\n// Test that default client has random ID\nfunc TestRandomClientID(t *testing.T) {\n\tvar err error\n\n\tm1 := newMQTTConsumer(nil)\n\tm1.Log = testutil.Logger{}\n\terr = m1.Init()\n\trequire.NoError(t, err)\n\n\tm2 := newMQTTConsumer(nil)\n\tm2.Log = testutil.Logger{}\n\terr = m2.Init()\n\trequire.NoError(t, err)\n\n\trequire.NotEqual(t, m1.opts.ClientID, m2.opts.ClientID)\n}\n\n// PersistentSession requires ClientID\nfunc TestPersistentClientIDFail(t *testing.T) {\n\tplugin := newMQTTConsumer(nil)\n\tplugin.Log = testutil.Logger{}\n\tplugin.PersistentSession = true\n\n\terr := plugin.Init()\n\trequire.Error(t, err)\n}\n\ntype message struct {\n\ttopic string\n\tqos   byte\n}\n\nfunc (*message) Duplicate() bool {\n\tpanic(\"not implemented\")\n}\n\nfunc (m *message) Qos() byte {\n\treturn m.qos\n}\n\nfunc (*message) Retained() bool {\n\tpanic(\"not implemented\")\n}\n\nfunc (m *message) Topic() string {\n\treturn m.topic\n}\n\nfunc (*message) MessageID() uint16 {\n\tpanic(\"not implemented\")\n}\n\nfunc (*message) Payload() []byte {\n\treturn []byte(\"cpu time_idle=42i\")\n}\n\nfunc (*message) Ack() {\n\tpanic(\"not implemented\")\n}\n\nfunc TestTopicTag(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\ttopic         string\n\t\ttopicTag      func() *string\n\t\texpectedError string\n\t\ttopicParsing  []topicParsingConfig\n\t\texpected      []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:  \"default topic when topic tag is unset for backwards compatibility\",\n\t\t\ttopic: \"telegraf\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"topic\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"time_idle\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"use topic tag when set\",\n\t\t\ttopic: \"telegraf\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"topic_tag\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"topic_tag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"time_idle\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"no topic tag is added when topic tag is set to the empty string\",\n\t\t\ttopic: \"telegraf\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"time_idle\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured\",\n\t\t\ttopic: \"telegraf/123/test\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"telegraf/123/test\",\n\t\t\t\t\tMeasurement: \"_/_/measurement\",\n\t\t\t\t\tTags:        \"testTag/_/_\",\n\t\t\t\t\tFields:      \"_/testNumber/_\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured with a mqtt wild card `+`\",\n\t\t\ttopic: \"telegraf/123/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"telegraf/+/test/hello\",\n\t\t\t\t\tMeasurement: \"_/_/measurement/_\",\n\t\t\t\t\tTags:        \"testTag/_/_/_\",\n\t\t\t\t\tFields:      \"_/testNumber/_/testString\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"testString\": \"hello\",\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured incorrectly\",\n\t\t\ttopic: \"telegraf/123/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\texpectedError: \"config error topic parsing: fields length does not equal topic length\",\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"telegraf/+/test/hello\",\n\t\t\t\t\tMeasurement: \"_/_/measurement/_\",\n\t\t\t\t\tTags:        \"testTag/_/_/_\",\n\t\t\t\t\tFields:      \"_/_/testNumber:int/_/testString:string\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"testString\": \"hello\",\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured without fields\",\n\t\t\ttopic: \"telegraf/123/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"telegraf/+/test/hello\",\n\t\t\t\t\tMeasurement: \"_/_/measurement/_\",\n\t\t\t\t\tTags:        \"testTag/_/_/_\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"time_idle\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured without measurement\",\n\t\t\ttopic: \"telegraf/123/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:  \"telegraf/+/test/hello\",\n\t\t\t\t\tTags:   \"testTag/_/_/_\",\n\t\t\t\t\tFields: \"_/testNumber/_/testString\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"testString\": \"hello\",\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing configured topic with a prefix `/`\",\n\t\t\ttopic: \"/telegraf/123/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"/telegraf/+/test/hello\",\n\t\t\t\t\tMeasurement: \"/_/_/measurement/_\",\n\t\t\t\t\tTags:        \"/testTag/_/_/_\",\n\t\t\t\t\tFields:      \"/_/testNumber/_/testString\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"testString\": \"hello\",\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing with variable length\",\n\t\t\ttopic: \"/telegraf/123/foo/test/hello\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"/telegraf/#/test/hello\",\n\t\t\t\t\tMeasurement: \"/#/measurement/_\",\n\t\t\t\t\tTags:        \"/testTag/#/moreTag/_/_\",\n\t\t\t\t\tFields:      \"/_/testNumber/#/testString\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"testTag\": \"telegraf\",\n\t\t\t\t\t\t\"moreTag\": \"foo\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"testNumber\": 123,\n\t\t\t\t\t\t\"testString\": \"hello\",\n\t\t\t\t\t\t\"time_idle\":  42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"topic parsing with variable length too short\",\n\t\t\ttopic: \"/telegraf/123\",\n\t\t\ttopicTag: func() *string {\n\t\t\t\ttag := \"\"\n\t\t\t\treturn &tag\n\t\t\t},\n\t\t\ttopicParsing: []topicParsingConfig{\n\t\t\t\t{\n\t\t\t\t\tTopic:       \"/telegraf/#\",\n\t\t\t\t\tMeasurement: \"/#/measurement/_\",\n\t\t\t\t\tTags:        \"/testTag/#/moreTag/_/_\",\n\t\t\t\t\tFields:      \"/_/testNumber/#/testString\",\n\t\t\t\t\tFieldTypes: map[string]string{\n\t\t\t\t\t\t\"testNumber\": \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"cpu\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"time_idle\": 42,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar handler mqtt.MessageHandler\n\t\t\tfClient := &fakeClient{\n\t\t\t\tconnectF: func() mqtt.Token {\n\t\t\t\t\treturn &fakeToken{}\n\t\t\t\t},\n\t\t\t\taddRouteF: func(callback mqtt.MessageHandler) {\n\t\t\t\t\thandler = callback\n\t\t\t\t},\n\t\t\t\tsubscribeMultipleF: func() mqtt.Token {\n\t\t\t\t\treturn &fakeToken{}\n\t\t\t\t},\n\t\t\t\tdisconnectF: func() {\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\t\t\tfClient.opts = o\n\t\t\t\treturn fClient\n\t\t\t})\n\t\t\tplugin.Log = testutil.Logger{}\n\t\t\tplugin.Topics = []string{tt.topic}\n\t\t\tplugin.TopicTag = tt.topicTag()\n\t\t\tplugin.TopicParserConfig = tt.topicParsing\n\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tplugin.SetParser(parser)\n\n\t\t\terr := plugin.Init()\n\t\t\tif tt.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\n\t\t\tvar m message\n\t\t\tm.topic = tt.topic\n\n\t\t\thandler(nil, &m)\n\n\t\t\tplugin.Stop()\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestAddRouteCalledForEachTopic(t *testing.T) {\n\tfClient := &fakeClient{\n\t\tconnectF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\taddRouteF: func(mqtt.MessageHandler) {\n\t\t},\n\t\tsubscribeMultipleF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\tdisconnectF: func() {\n\t\t},\n\t}\n\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\tfClient.opts = o\n\t\treturn fClient\n\t})\n\tplugin.Log = testutil.Logger{}\n\tplugin.Topics = []string{\"a\", \"b\"}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tplugin.Stop()\n\n\trequire.Equal(t, 2, fClient.addRouteCallCount)\n}\n\nfunc TestSubscribeCalledIfNoSession(t *testing.T) {\n\tfClient := &fakeClient{\n\t\tconnectF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\taddRouteF: func(mqtt.MessageHandler) {\n\t\t},\n\t\tsubscribeMultipleF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\tdisconnectF: func() {\n\t\t},\n\t}\n\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\tfClient.opts = o\n\t\treturn fClient\n\t})\n\tplugin.Log = testutil.Logger{}\n\tplugin.Topics = []string{\"b\"}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\n\tplugin.Stop()\n\n\trequire.Equal(t, 1, fClient.subscribeCallCount)\n}\n\nfunc TestResubscribeOnReconnect(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tfClient := &fakeClient{\n\t\tconnectF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\taddRouteF:          func(mqtt.MessageHandler) {},\n\t\tsubscribeMultipleF: func() mqtt.Token { return &fakeToken{} },\n\t\tdisconnectF:        func() {},\n\t}\n\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\tfClient.opts = o\n\t\treturn fClient\n\t})\n\tplugin.Log = testutil.Logger{}\n\tplugin.Servers = []string{\"tcp://127.0.0.1\"}\n\tplugin.SetParser(&fakeParser{})\n\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\n\t// First connection triggers subscribe via onConnect\n\trequire.Equal(t, 1, fClient.subscribeCallCount)\n\n\t// Simulate paho auto-reconnect calling OnConnect again\n\tfClient.opts.OnConnect(nil)\n\n\trequire.Equal(t, 2, fClient.subscribeCallCount)\n\n\tplugin.Stop()\n}\n\nfunc TestSubscribeCalledWithSession(t *testing.T) {\n\tfClient := &fakeClient{\n\t\tconnectF: func() mqtt.Token {\n\t\t\treturn &fakeToken{sessionPresent: true}\n\t\t},\n\t\taddRouteF: func(mqtt.MessageHandler) {\n\t\t},\n\t\tsubscribeMultipleF: func() mqtt.Token {\n\t\t\treturn &fakeToken{}\n\t\t},\n\t\tdisconnectF: func() {\n\t\t},\n\t}\n\tplugin := newMQTTConsumer(func(o *mqtt.ClientOptions) client {\n\t\tfClient.opts = o\n\t\treturn fClient\n\t})\n\tplugin.Log = testutil.Logger{}\n\tplugin.Topics = []string{\"b\"}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tplugin.Stop()\n\n\t// Subscribe is always called, even with persistent sessions, to ensure\n\t// subscriptions are restored after reconnection.\n\trequire.Equal(t, 1, fClient.subscribeCallCount)\n}\n\nfunc TestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tconf, err := filepath.Abs(filepath.Join(\"testdata\", \"mosquitto.conf\"))\n\trequire.NoError(t, err, \"missing file mosquitto.conf\")\n\n\tconst servicePort = \"1883\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"eclipse-mosquitto:2\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(servicePort),\n\t\tFiles: map[string]string{\n\t\t\t\"/mosquitto/config/mosquitto.conf\": conf,\n\t\t},\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin and connect to the broker\n\turl := fmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\ttopic := \"/telegraf/test\"\n\tfactory := func(o *mqtt.ClientOptions) client { return mqtt.NewClient(o) }\n\tplugin := &MQTTConsumer{\n\t\tServers:                []string{url},\n\t\tTopics:                 []string{topic},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      config.Duration(5 * time.Second),\n\t\tKeepAliveInterval:      config.Duration(1 * time.Second),\n\t\tPingTimeout:            config.Duration(100 * time.Millisecond),\n\t\tLog:                    testutil.Logger{Name: \"mqtt-integration-test\"},\n\t\tclientFactory:          factory,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Setup a producer to send some metrics to the broker\n\tproducerOpts := mqtt.NewClientOptions().AddBroker(url).SetConnectTimeout(5 * time.Second)\n\tproducer := mqtt.NewClient(producerOpts)\n\ttoken := producer.Connect()\n\ttoken.Wait()\n\trequire.NoError(t, token.Error())\n\tdefer producer.Disconnect(100)\n\n\t// Setup the metrics\n\tmetrics := []string{\n\t\t\"test,source=A value=0i 1712780301000000000\",\n\t\t\"test,source=B value=1i 1712780301000000100\",\n\t\t\"test,source=C value=2i 1712780301000000200\",\n\t}\n\texpected := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, x := range metrics {\n\t\tmetrics, err := parser.Parse([]byte(x))\n\t\tfor i := range metrics {\n\t\t\tmetrics[i].AddTag(\"topic\", topic)\n\t\t}\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, metrics...)\n\t}\n\n\t// Write metrics\n\tfor _, x := range metrics {\n\t\txtoken := producer.Publish(topic, byte(plugin.QoS), false, []byte(x))\n\t\trequire.NoError(t, xtoken.Error())\n\t}\n\n\t// Verify that the metrics were actually written\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tproducer.Disconnect(100)\n\tplugin.Stop()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestStartupErrorBehaviorErrorIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tconf, err := filepath.Abs(filepath.Join(\"testdata\", \"mosquitto.conf\"))\n\trequire.NoError(t, err, \"missing file mosquitto.conf\")\n\n\tconst servicePort = \"1883\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"eclipse-mosquitto:2\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(servicePort),\n\t\tFiles: map[string]string{\n\t\t\t\"/mosquitto/config/mosquitto.conf\": conf,\n\t\t},\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin and connect to the broker\n\turl := fmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\ttopic := \"/telegraf/test\"\n\tfactory := func(o *mqtt.ClientOptions) client { return mqtt.NewClient(o) }\n\tplugin := &MQTTConsumer{\n\t\tServers:                []string{url},\n\t\tTopics:                 []string{topic},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      config.Duration(5 * time.Second),\n\t\tKeepAliveInterval:      config.Duration(1 * time.Second),\n\t\tPingTimeout:            config.Duration(100 * time.Millisecond),\n\t\tLog:                    testutil.Logger{Name: \"mqtt-integration-test\"},\n\t\tclientFactory:          factory,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:  \"mqtt_consumer\",\n\t\t\tAlias: \"error-test\", // required to get a unique error stats instance\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail with an error because the container is paused.\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, model.Start(&acc), \"network Error\")\n}\n\nfunc TestStartupErrorBehaviorIgnoreIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tconf, err := filepath.Abs(filepath.Join(\"testdata\", \"mosquitto.conf\"))\n\trequire.NoError(t, err, \"missing file mosquitto.conf\")\n\n\tconst servicePort = \"1883\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"eclipse-mosquitto:2\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(servicePort),\n\t\tFiles: map[string]string{\n\t\t\t\"/mosquitto/config/mosquitto.conf\": conf,\n\t\t},\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin and connect to the broker\n\turl := fmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\ttopic := \"/telegraf/test\"\n\tfactory := func(o *mqtt.ClientOptions) client { return mqtt.NewClient(o) }\n\tplugin := &MQTTConsumer{\n\t\tServers:                []string{url},\n\t\tTopics:                 []string{topic},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      config.Duration(5 * time.Second),\n\t\tKeepAliveInterval:      config.Duration(1 * time.Second),\n\t\tPingTimeout:            config.Duration(100 * time.Millisecond),\n\t\tLog:                    testutil.Logger{Name: \"mqtt-integration-test\"},\n\t\tclientFactory:          factory,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"mqtt_consumer\",\n\t\t\tAlias:                \"ignore-test\", // required to get a unique error stats instance\n\t\t\tStartupErrorBehavior: \"ignore\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail because the container is paused.\n\t// The model code should convert it to a fatal error for the agent to remove\n\t// the plugin.\n\tvar acc testutil.Accumulator\n\terr = model.Start(&acc)\n\trequire.ErrorContains(t, err, \"network Error\")\n\tvar fatalErr *internal.FatalError\n\trequire.ErrorAs(t, err, &fatalErr)\n}\n\nfunc TestStartupErrorBehaviorRetryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tconf, err := filepath.Abs(filepath.Join(\"testdata\", \"mosquitto.conf\"))\n\trequire.NoError(t, err, \"missing file mosquitto.conf\")\n\n\tconst servicePort = \"1883\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"eclipse-mosquitto:2\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(servicePort),\n\t\tFiles: map[string]string{\n\t\t\t\"/mosquitto/config/mosquitto.conf\": conf,\n\t\t},\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Pause the container for simulating connectivity issues\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Setup the plugin and connect to the broker\n\turl := fmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\ttopic := \"/telegraf/test\"\n\tfactory := func(o *mqtt.ClientOptions) client { return mqtt.NewClient(o) }\n\tplugin := &MQTTConsumer{\n\t\tServers:                []string{url},\n\t\tTopics:                 []string{topic},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      config.Duration(5 * time.Second),\n\t\tKeepAliveInterval:      config.Duration(1 * time.Second),\n\t\tPingTimeout:            config.Duration(100 * time.Millisecond),\n\t\tLog:                    testutil.Logger{Name: \"mqtt-integration-test\"},\n\t\tclientFactory:          factory,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a model to be able to use the startup retry strategy\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"mqtt_consumer\",\n\t\t\tAlias:                \"retry-test\", // required to get a unique error stats instance\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, model.Start(&acc))\n\n\t// There should be no metrics as the plugin is not fully started up yet\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n\trequire.Equal(t, int64(2), model.StartupErrors.Get())\n\n\t// Unpause the container, now writes should succeed\n\trequire.NoError(t, container.Resume())\n\trequire.NoError(t, model.Gather(&acc))\n\tdefer model.Stop()\n\n\t// Setup a producer to send some metrics to the broker\n\tproducerOpts := mqtt.NewClientOptions().AddBroker(url).SetConnectTimeout(5 * time.Second)\n\tproducer := mqtt.NewClient(producerOpts)\n\tptoken := producer.Connect()\n\tptoken.Wait()\n\trequire.NoError(t, ptoken.Error())\n\tdefer producer.Disconnect(100)\n\n\t// Setup the metrics\n\tmetrics := []string{\n\t\t\"test,source=A value=0i 1712780301000000000\",\n\t\t\"test,source=B value=1i 1712780301000000100\",\n\t\t\"test,source=C value=2i 1712780301000000200\",\n\t}\n\texpected := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, x := range metrics {\n\t\tmetrics, err := parser.Parse([]byte(x))\n\t\tfor i := range metrics {\n\t\t\tmetrics[i].AddTag(\"topic\", topic)\n\t\t}\n\t\trequire.NoError(t, err)\n\t\texpected = append(expected, metrics...)\n\t}\n\n\t// Write metrics\n\tfor _, x := range metrics {\n\t\txtoken := producer.Publish(topic, byte(plugin.QoS), false, []byte(x))\n\t\trequire.NoError(t, xtoken.Error())\n\t}\n\n\t// Verify that the metrics were actually written\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tproducer.Disconnect(100)\n\tplugin.Stop()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestReconnectIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tconf, err := filepath.Abs(filepath.Join(\"testdata\", \"mosquitto.conf\"))\n\trequire.NoError(t, err, \"missing file mosquitto.conf\")\n\n\tconst servicePort = \"1883\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"eclipse-mosquitto:2\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(servicePort),\n\t\tFiles: map[string]string{\n\t\t\t\"/mosquitto/config/mosquitto.conf\": conf,\n\t\t},\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Setup the plugin and connect to the broker\n\turl := fmt.Sprintf(\"tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\ttopic := \"/telegraf/test\"\n\tfactory := func(o *mqtt.ClientOptions) client { return mqtt.NewClient(o) }\n\tplugin := &MQTTConsumer{\n\t\tServers:                []string{url},\n\t\tTopics:                 []string{topic},\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tConnectionTimeout:      config.Duration(5 * time.Second),\n\t\tKeepAliveInterval:      config.Duration(1 * time.Second),\n\t\tPingTimeout:            config.Duration(100 * time.Millisecond),\n\t\tLog:                    testutil.Logger{Name: \"mqtt-integration-test\"},\n\t\tclientFactory:          factory,\n\t}\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Pause the container to simulate losing connection\n\trequire.NoError(t, container.Pause())\n\tdefer container.Resume() //nolint:errcheck // Ignore the returned error as we cannot do anything about it anyway\n\n\t// Wait until onConnectionLost fires (detected via the accumulator error).\n\t// We cannot reliably poll IsConnected() because paho's auto-reconnect may\n\t// flip it back to true before the next poll tick.\n\trequire.Eventually(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn len(acc.Errors) > 0\n\t}, 10*time.Second, 100*time.Millisecond)\n\n\t// Unpause the container; paho's auto-reconnect should restore the connection\n\trequire.NoError(t, container.Resume())\n\n\t// Wait for paho to auto-reconnect\n\trequire.Eventually(t, func() bool {\n\t\treturn plugin.client.IsConnected()\n\t}, 10*time.Second, 200*time.Millisecond)\n\n\t// Setup a producer to send metrics after reconnection\n\tproducerOpts := mqtt.NewClientOptions().AddBroker(url).SetConnectTimeout(5 * time.Second)\n\tproducer := mqtt.NewClient(producerOpts)\n\ttoken := producer.Connect()\n\ttoken.Wait()\n\trequire.NoError(t, token.Error())\n\tdefer producer.Disconnect(100)\n\n\t// Publish metrics and verify they are received after reconnection\n\tmetrics := []string{\n\t\t\"test,source=A value=0i 1712780301000000000\",\n\t\t\"test,source=B value=1i 1712780301000000100\",\n\t}\n\texpected := make([]telegraf.Metric, 0, len(metrics))\n\tfor _, x := range metrics {\n\t\tparsed, err := parser.Parse([]byte(x))\n\t\trequire.NoError(t, err)\n\t\tfor i := range parsed {\n\t\t\tparsed[i].AddTag(\"topic\", topic)\n\t\t}\n\t\texpected = append(expected, parsed...)\n\t}\n\tfor _, x := range metrics {\n\t\txtoken := producer.Publish(topic, byte(plugin.QoS), false, []byte(x))\n\t\trequire.NoError(t, xtoken.Error())\n\t}\n\n\t// Verify that the metrics were received after reconnection\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 5*time.Second, 100*time.Millisecond)\n\n\tproducer.Disconnect(100)\n\tplugin.Stop()\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/mqtt_logger.go",
    "content": "package mqtt_consumer\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype mqttLogger struct {\n\ttelegraf.Logger\n}\n\n// Printf implements mqtt.Logger\nfunc (l mqttLogger) Printf(fmt string, args ...interface{}) {\n\tl.Logger.Debugf(fmt, args...)\n}\n\n// Println implements mqtt.Logger\nfunc (l mqttLogger) Println(args ...interface{}) {\n\tl.Logger.Debug(args...)\n}\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/sample.conf",
    "content": "# Read metrics from MQTT topic(s)\n[[inputs.mqtt_consumer]]\n  ## Broker URLs for the MQTT server or cluster.  To connect to multiple\n  ## clusters or standalone servers, use a separate plugin instance.\n  ##   example: servers = [\"tcp://localhost:1883\"]\n  ##            servers = [\"ssl://localhost:1883\"]\n  ##            servers = [\"ws://localhost:1883\"]\n  servers = [\"tcp://127.0.0.1:1883\"]\n\n  ## Topics that will be subscribed to.\n  topics = [\n    \"telegraf/host01/cpu\",\n    \"telegraf/+/mem\",\n    \"sensors/#\",\n  ]\n\n  ## The message topic will be stored in a tag specified by this value.  If set\n  ## to the empty string no topic tag will be created.\n  # topic_tag = \"topic\"\n\n  ## QoS policy for messages\n  ##   0 = at most once\n  ##   1 = at least once\n  ##   2 = exactly once\n  ##\n  ## When using a QoS of 1 or 2, you should enable persistent_session to allow\n  ## resuming unacknowledged messages.\n  # qos = 0\n\n  ## Connection timeout for initial connection in seconds\n  # connection_timeout = \"30s\"\n\n  ## Maximum interval between reconnection attempts after a connection loss.\n  ## The MQTT library uses exponential backoff starting at 1 second up to this\n  ## ceiling. The library default is 10 minutes, which can cause long delays\n  ## before message flow resumes after a network outage.\n  # max_reconnect_interval = \"30s\"\n\n  ## Interval and ping timeout for keep-alive messages\n  ## The sum of those options defines when a connection loss is detected.\n  ## Note: The keep-alive interval needs to be greater or equal one second and\n  ## fractions of a second are not supported.\n  # keepalive = \"60s\"\n  # ping_timeout = \"10s\"\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Persistent session disables clearing of the client session on connection.\n  ## In order for this option to work you must also set client_id to identify\n  ## the client.  To receive messages that arrived while the client is offline,\n  ## also set the qos option to 1 or 2 and don't forget to also set the QoS when\n  ## publishing. Finally, using a persistent session will use the initial\n  ## connection topics and not subscribe to any new topics even after\n  ## reconnecting or restarting without a change in client ID.\n  # persistent_session = false\n\n  ## If unset, a random client ID will be generated.\n  # client_id = \"\"\n\n  ## Username and password to connect MQTT server.\n  # username = \"telegraf\"\n  # password = \"metricsmetricsmetricsmetrics\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the MQTT\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n\n  ## Enable extracting tag values from MQTT topics\n  ## _ denotes an ignored entry in the topic path,\n  ## # denotes a variable length path element (can only be used once per setting)\n  # [[inputs.mqtt_consumer.topic_parsing]]\n  #   topic = \"\"\n  #   measurement = \"\"\n  #   tags = \"\"\n  #   fields = \"\"\n  ## Value supported is int, float, unit\n  #   [inputs.mqtt_consumer.topic_parsing.types]\n  #      key = type\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/testdata/mosquitto.conf",
    "content": "listener 1883 0.0.0.0\nallow_anonymous true\nconnection_messages true\n"
  },
  {
    "path": "plugins/inputs/mqtt_consumer/topic_parser.go",
    "content": "package mqtt_consumer\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype topicParsingConfig struct {\n\tTopic       string            `toml:\"topic\"`\n\tMeasurement string            `toml:\"measurement\"`\n\tTags        string            `toml:\"tags\"`\n\tFields      string            `toml:\"fields\"`\n\tFieldTypes  map[string]string `toml:\"types\"`\n}\n\ntype topicParser struct {\n\ttopicIndices   map[string]int\n\ttopicVarLength bool\n\ttopicMinLength int\n\n\textractMeasurement bool\n\tmeasurementIndex   int\n\ttagIndices         map[string]int\n\tfieldIndices       map[string]int\n\tfieldTypes         map[string]string\n}\n\nfunc (cfg *topicParsingConfig) newParser() (*topicParser, error) {\n\tp := &topicParser{\n\t\tfieldTypes: cfg.FieldTypes,\n\t}\n\n\t// Build a check list for topic elements\n\tvar topicMinLength int\n\tvar topicInvert bool\n\ttopicParts := strings.Split(cfg.Topic, \"/\")\n\tp.topicIndices = make(map[string]int, len(topicParts))\n\tfor i, k := range topicParts {\n\t\tswitch k {\n\t\tcase \"+\":\n\t\t\ttopicMinLength++\n\t\tcase \"#\":\n\t\t\tif p.topicVarLength {\n\t\t\t\treturn nil, errors.New(\"topic can only contain one hash\")\n\t\t\t}\n\t\t\tp.topicVarLength = true\n\t\t\ttopicInvert = true\n\t\tdefault:\n\t\t\tif !topicInvert {\n\t\t\t\tp.topicIndices[k] = i\n\t\t\t} else {\n\t\t\t\tp.topicIndices[k] = i - len(topicParts)\n\t\t\t}\n\t\t\ttopicMinLength++\n\t\t}\n\t}\n\n\t// Determine metric name selection\n\tvar measurementMinLength int\n\tvar measurementInvert bool\n\tmeasurementParts := strings.Split(cfg.Measurement, \"/\")\n\tfor i, k := range measurementParts {\n\t\tif k == \"_\" || k == \"\" {\n\t\t\tmeasurementMinLength++\n\t\t\tcontinue\n\t\t}\n\n\t\tif k == \"#\" {\n\t\t\tmeasurementInvert = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif p.extractMeasurement {\n\t\t\treturn nil, errors.New(\"measurement can only contain one element\")\n\t\t}\n\n\t\tif !measurementInvert {\n\t\t\tp.measurementIndex = i\n\t\t} else {\n\t\t\tp.measurementIndex = i - len(measurementParts)\n\t\t}\n\t\tp.extractMeasurement = true\n\t\tmeasurementMinLength++\n\t}\n\n\t// Determine tag selections\n\tvar tagMinLength int\n\tvar tagInvert bool\n\ttagParts := strings.Split(cfg.Tags, \"/\")\n\tp.tagIndices = make(map[string]int, len(tagParts))\n\tfor i, k := range tagParts {\n\t\tif k == \"_\" || k == \"\" {\n\t\t\ttagMinLength++\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"#\" {\n\t\t\ttagInvert = true\n\t\t\tcontinue\n\t\t}\n\t\tif !tagInvert {\n\t\t\tp.tagIndices[k] = i\n\t\t} else {\n\t\t\tp.tagIndices[k] = i - len(tagParts)\n\t\t}\n\t\ttagMinLength++\n\t}\n\n\t// Determine tag selections\n\tvar fieldMinLength int\n\tvar fieldInvert bool\n\tfieldParts := strings.Split(cfg.Fields, \"/\")\n\tp.fieldIndices = make(map[string]int, len(fieldParts))\n\tfor i, k := range fieldParts {\n\t\tif k == \"_\" || k == \"\" {\n\t\t\tfieldMinLength++\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"#\" {\n\t\t\tfieldInvert = true\n\t\t\tcontinue\n\t\t}\n\t\tif !fieldInvert {\n\t\t\tp.fieldIndices[k] = i\n\t\t} else {\n\t\t\tp.fieldIndices[k] = i - len(fieldParts)\n\t\t}\n\t\tfieldMinLength++\n\t}\n\n\tif !p.topicVarLength {\n\t\tif measurementMinLength != topicMinLength && p.extractMeasurement {\n\t\t\treturn nil, errors.New(\"measurement length does not equal topic length\")\n\t\t}\n\n\t\tif fieldMinLength != topicMinLength && cfg.Fields != \"\" {\n\t\t\treturn nil, errors.New(\"fields length does not equal topic length\")\n\t\t}\n\n\t\tif tagMinLength != topicMinLength && cfg.Tags != \"\" {\n\t\t\treturn nil, errors.New(\"tags length does not equal topic length\")\n\t\t}\n\t}\n\n\tp.topicMinLength = max(topicMinLength, measurementMinLength, tagMinLength, fieldMinLength)\n\n\treturn p, nil\n}\n\nfunc (p *topicParser) parse(metric telegraf.Metric, topic string) error {\n\t// Split the actual topic into its elements and check for a match\n\ttopicParts := strings.Split(topic, \"/\")\n\tif p.topicVarLength && len(topicParts) < p.topicMinLength || !p.topicVarLength && len(topicParts) != p.topicMinLength {\n\t\treturn nil\n\t}\n\tfor expected, i := range p.topicIndices {\n\t\tif i >= 0 && topicParts[i] != expected || i < 0 && topicParts[len(topicParts)+i] != expected {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Extract the measurement name\n\tvar measurement string\n\tif p.extractMeasurement {\n\t\tif p.measurementIndex >= 0 {\n\t\t\tmeasurement = topicParts[p.measurementIndex]\n\t\t} else {\n\t\t\tmeasurement = topicParts[len(topicParts)+p.measurementIndex]\n\t\t}\n\t\tmetric.SetName(measurement)\n\t}\n\n\t// Extract the tags\n\tfor k, i := range p.tagIndices {\n\t\tif i >= 0 {\n\t\t\tmetric.AddTag(k, topicParts[i])\n\t\t} else {\n\t\t\tmetric.AddTag(k, topicParts[len(topicParts)+i])\n\t\t}\n\t}\n\n\t// Extract the fields\n\tfor k, i := range p.fieldIndices {\n\t\tvar raw string\n\t\tif i >= 0 {\n\t\t\traw = topicParts[i]\n\t\t} else {\n\t\t\traw = topicParts[len(topicParts)+i]\n\t\t}\n\t\tv, err := p.convertToFieldType(raw, k)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmetric.AddField(k, v)\n\t}\n\n\treturn nil\n}\n\nfunc (p *topicParser) convertToFieldType(value, key string) (interface{}, error) {\n\t// If the user configured inputs.mqtt_consumer.topic.types, check for the desired type\n\tdesiredType, ok := p.fieldTypes[key]\n\tif !ok {\n\t\treturn value, nil\n\t}\n\n\tvar v interface{}\n\tvar err error\n\tswitch desiredType {\n\tcase \"uint\":\n\t\tif v, err = strconv.ParseUint(value, 10, 64); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to convert field %q to type uint: %w\", value, err)\n\t\t}\n\tcase \"int\":\n\t\tif v, err = strconv.ParseInt(value, 10, 64); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to convert field %q to type int: %w\", value, err)\n\t\t}\n\tcase \"float\":\n\t\tif v, err = strconv.ParseFloat(value, 64); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to convert field %q to type float: %w\", value, err)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"converting to the type %s is not supported: use int, uint, or float\", desiredType)\n\t}\n\n\treturn v, nil\n}\n"
  },
  {
    "path": "plugins/inputs/multifile/README.md",
    "content": "# Multifile Input Plugin\n\nThis plugin reads the combined data from multiple files into a single metric,\ncreating one field or tag per file.  This is often useful creating custom\nmetrics from the `/sys` or `/proc` filesystems.\n\n> [!NOTE]\n> To parse metrics from a single file you should use the [file][file_plugin]\n> input plugin instead.\n\n⭐ Telegraf v1.10.0\n🏷️ system\n💻 all\n\n[file_plugin]: /plugins/inputs/file/README.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Aggregates the contents of multiple files into a single point\n[[inputs.multifile]]\n  ## Base directory where telegraf will look for files.\n  ## Omit this option to use absolute paths.\n  base_dir = \"/sys/bus/i2c/devices/1-0076/iio:device0\"\n\n  ## If true discard all data when a single file can't be read.\n  ## Else, Telegraf omits the field generated from this file.\n  # fail_early = true\n\n  ## Files to parse each interval.\n  [[inputs.multifile.file]]\n    file = \"in_pressure_input\"\n    dest = \"pressure\"\n    conversion = \"float\"\n  [[inputs.multifile.file]]\n    file = \"in_temp_input\"\n    dest = \"temperature\"\n    conversion = \"float(3)\"\n  [[inputs.multifile.file]]\n    file = \"in_humidityrelative_input\"\n    dest = \"humidityrelative\"\n    conversion = \"float(3)\"\n```\n\n## Metrics\n\nEach file table can contain the following options:\n\n* `file`:\nPath of the file to be parsed, relative to the `base_dir`.\n* `dest`:\nName of the field/tag key, defaults to `$(basename file)`.\n* `conversion`:\nData format used to parse the file contents:\n  * `float(X)`: Converts the input value into a float and divides by the Xth\n    power of 10. Effectively just moves the decimal left X places. For example\n    a value of `123` with `float(2)` will result in `1.23`.\n  * `float`: Converts the value into a float with no adjustment.\n    Same as `float(0)`.\n  * `int`: Converts the value into an integer.\n  * `string`, `\"\"`: No conversion.\n  * `bool`: Converts the value into a boolean.\n  * `tag`: File content is used as a tag.\n\n## Example Output\n\nThis example shows a BME280 connected to a Raspberry Pi, using the sample\nconfig.\n\n```text\nmultifile pressure=101.343285156,temperature=20.4,humidityrelative=48.9 1547202076000000000\n```\n\nTo reproduce this, connect a BMP280 to the board's GPIO pins and register the\nBME280 device driver\n\n```sh\ncd /sys/bus/i2c/devices/i2c-1\necho bme280 0x76 > new_device\n```\n\nThe kernel driver provides the following files in\n`/sys/bus/i2c/devices/1-0076/iio:device0`:\n\n* `in_humidityrelative_input`: `48900`\n* `in_pressure_input`: `101.343285156`\n* `in_temp_input`: `20400`\n"
  },
  {
    "path": "plugins/inputs/multifile/multifile.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage multifile\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype MultiFile struct {\n\tBaseDir   string `toml:\"base_dir\"`\n\tFailEarly bool   `toml:\"fail_early\"`\n\tFiles     []file `toml:\"file\"`\n}\n\ntype file struct {\n\tName       string `toml:\"file\"`\n\tDest       string `toml:\"dest\"`\n\tConversion string `toml:\"conversion\"`\n}\n\nfunc (*MultiFile) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *MultiFile) Init() error {\n\tfor i, file := range m.Files {\n\t\tif m.BaseDir != \"\" {\n\t\t\tm.Files[i].Name = path.Join(m.BaseDir, file.Name)\n\t\t}\n\t\tif file.Dest == \"\" {\n\t\t\tm.Files[i].Dest = path.Base(file.Name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *MultiFile) Gather(acc telegraf.Accumulator) error {\n\tnow := time.Now()\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\n\tfor _, file := range m.Files {\n\t\tfileContents, err := os.ReadFile(file.Name)\n\n\t\tif err != nil {\n\t\t\tif m.FailEarly {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tvStr := string(bytes.TrimSpace(bytes.Trim(fileContents, \"\\x00\")))\n\n\t\tif file.Conversion == \"tag\" {\n\t\t\ttags[file.Dest] = vStr\n\t\t\tcontinue\n\t\t}\n\n\t\tvar value interface{}\n\n\t\tvar d int\n\t\tif _, errfmt := fmt.Sscanf(file.Conversion, \"float(%d)\", &d); errfmt == nil || file.Conversion == \"float\" {\n\t\t\tvar v float64\n\t\t\tv, err = strconv.ParseFloat(vStr, 64)\n\t\t\tvalue = v / math.Pow10(d)\n\t\t}\n\n\t\tif file.Conversion == \"int\" {\n\t\t\tvalue, err = strconv.ParseInt(vStr, 10, 64)\n\t\t}\n\n\t\tif file.Conversion == \"string\" || file.Conversion == \"\" {\n\t\t\tvalue = vStr\n\t\t}\n\n\t\tif file.Conversion == \"bool\" {\n\t\t\tvalue, err = strconv.ParseBool(vStr)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif m.FailEarly {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif value == nil {\n\t\t\treturn fmt.Errorf(\"invalid conversion %v\", file.Conversion)\n\t\t}\n\n\t\tfields[file.Dest] = value\n\t}\n\n\tacc.AddGauge(\"multifile\", fields, tags, now)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"multifile\", func() telegraf.Input {\n\t\treturn &MultiFile{\n\t\t\tFailEarly: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/multifile/multifile_test.go",
    "content": "package multifile\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFileTypes(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\n\tm := MultiFile{\n\t\tBaseDir:   path.Join(wd, `testdata`),\n\t\tFailEarly: true,\n\t\tFiles: []file{\n\t\t\t{Name: `bool.txt`, Dest: `examplebool`, Conversion: `bool`},\n\t\t\t{Name: `float.txt`, Dest: `examplefloat`, Conversion: `float`},\n\t\t\t{Name: `int.txt`, Dest: `examplefloatX`, Conversion: `float(3)`},\n\t\t\t{Name: `int.txt`, Dest: `exampleint`, Conversion: `int`},\n\t\t\t{Name: `string.txt`, Dest: `examplestring`},\n\t\t\t{Name: `tag.txt`, Dest: `exampletag`, Conversion: `tag`},\n\t\t\t{Name: `int.txt`, Conversion: `int`},\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, m.Init())\n\trequire.NoError(t, m.Gather(&acc))\n\trequire.Equal(t, map[string]string{\"exampletag\": \"test\"}, acc.Metrics[0].Tags)\n\trequire.Equal(t, map[string]interface{}{\n\t\t\"examplebool\":   true,\n\t\t\"examplestring\": \"hello world\",\n\t\t\"exampleint\":    int64(123456),\n\t\t\"int.txt\":       int64(123456),\n\t\t\"examplefloat\":  123.456,\n\t\t\"examplefloatX\": 123.456,\n\t}, acc.Metrics[0].Fields)\n}\n\nfunc failEarly(failEarly bool, t *testing.T) error {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\n\tm := MultiFile{\n\t\tBaseDir:   path.Join(wd, `testdata`),\n\t\tFailEarly: failEarly,\n\t\tFiles: []file{\n\t\t\t{Name: `int.txt`, Dest: `exampleint`, Conversion: `int`},\n\t\t\t{Name: `int.txt`, Dest: `exampleerror`, Conversion: `bool`},\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, m.Init())\n\terr = m.Gather(&acc)\n\n\tif err == nil {\n\t\trequire.Equal(t, map[string]interface{}{\n\t\t\t\"exampleint\": int64(123456),\n\t\t}, acc.Metrics[0].Fields)\n\t}\n\n\treturn err\n}\n\nfunc TestFailEarly(t *testing.T) {\n\terr := failEarly(false, t)\n\trequire.NoError(t, err)\n\terr = failEarly(true, t)\n\trequire.Error(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/multifile/sample.conf",
    "content": "# Aggregates the contents of multiple files into a single point\n[[inputs.multifile]]\n  ## Base directory where telegraf will look for files.\n  ## Omit this option to use absolute paths.\n  base_dir = \"/sys/bus/i2c/devices/1-0076/iio:device0\"\n\n  ## If true discard all data when a single file can't be read.\n  ## Else, Telegraf omits the field generated from this file.\n  # fail_early = true\n\n  ## Files to parse each interval.\n  [[inputs.multifile.file]]\n    file = \"in_pressure_input\"\n    dest = \"pressure\"\n    conversion = \"float\"\n  [[inputs.multifile.file]]\n    file = \"in_temp_input\"\n    dest = \"temperature\"\n    conversion = \"float(3)\"\n  [[inputs.multifile.file]]\n    file = \"in_humidityrelative_input\"\n    dest = \"humidityrelative\"\n    conversion = \"float(3)\"\n"
  },
  {
    "path": "plugins/inputs/multifile/testdata/bool.txt",
    "content": "true\n"
  },
  {
    "path": "plugins/inputs/multifile/testdata/float.txt",
    "content": "123.456\n"
  },
  {
    "path": "plugins/inputs/multifile/testdata/int.txt",
    "content": "123456\n"
  },
  {
    "path": "plugins/inputs/multifile/testdata/string.txt",
    "content": " hello world\n"
  },
  {
    "path": "plugins/inputs/multifile/testdata/tag.txt",
    "content": "test\n"
  },
  {
    "path": "plugins/inputs/mysql/README.md",
    "content": "# MySQL Input Plugin\n\nThis plugin gathers statistics from [MySQL][mysql] server instances.\n\n> [!NOTE]\n> To gather metrics from the performance schema, it must first be enabled in\n> MySQL. See the performance schema [quick start][quick-start] for details.\n\n⭐ Telegraf v0.1.1\n🏷️ datastore\n💻 all\n\n[mysql]: https://www.mysql.com/\n[quick-start]: https://dev.mysql.com/doc/refman/8.0/en/performance-schema-quick-start.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many mysql servers\n[[inputs.mysql]]\n  ## specify servers via a url matching:\n  ##  [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify|custom]]\n  ##  see https://github.com/go-sql-driver/mysql#dsn-data-source-name\n  ##  e.g.\n  ##    servers = [\"user:passwd@tcp(127.0.0.1:3306)/?tls=false\"]\n  ##    servers = [\"user@tcp(127.0.0.1:3306)/?tls=false\"]\n  #\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"tcp(127.0.0.1:3306)/\"]\n\n  ## Selects the metric output format.\n  ##\n  ## This option exists to maintain backwards compatibility, if you have\n  ## existing metrics do not set or change this value until you are ready to\n  ## migrate to the new format.\n  ##\n  ## If you do not have existing metrics from this plugin set to the latest\n  ## version.\n  ##\n  ## Telegraf >=1.6: metric_version = 2\n  ##           <1.6: metric_version = 1 (or unset)\n  metric_version = 2\n\n  ## if the list is empty, then metrics are gathered from all database tables\n  # table_schema_databases = []\n\n  ## gather metrics from INFORMATION_SCHEMA.TABLES for databases provided\n  ## in the list above\n  # gather_table_schema = false\n\n  ## gather thread state counts from INFORMATION_SCHEMA.PROCESSLIST\n  # gather_process_list = false\n\n  ## gather user statistics from INFORMATION_SCHEMA.USER_STATISTICS\n  # gather_user_statistics = false\n\n  ## gather auto_increment columns and max values from information schema\n  # gather_info_schema_auto_inc = false\n\n  ## gather metrics from INFORMATION_SCHEMA.INNODB_METRICS\n  # gather_innodb_metrics = false\n\n  ## gather metrics from all channels from SHOW SLAVE STATUS command output\n  # gather_all_slave_channels = false\n\n  ## gather metrics from SHOW SLAVE STATUS command output\n  # gather_slave_status = false\n\n  ## gather metrics from SHOW REPLICA STATUS command output\n  # gather_replica_status = false\n\n  ## use SHOW ALL SLAVES STATUS command output for MariaDB\n  ## use SHOW ALL REPLICAS STATUS command if enable gather replica status\n  # mariadb_dialect = false\n\n  ## gather metrics from SHOW BINARY LOGS command output\n  # gather_binary_logs = false\n\n  ## gather metrics from SHOW GLOBAL VARIABLES command output\n  # gather_global_variables = true\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_TABLE\n  # gather_table_io_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_LOCK_WAITS\n  # gather_table_lock_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_INDEX_USAGE\n  # gather_index_io_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENT_WAITS\n  # gather_event_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME\n  # gather_file_events_stats = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_DIGEST\n  # gather_perf_events_statements             = false\n  #\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME\n  # gather_perf_sum_per_acc_per_event         = false\n  #\n  ## list of events to be gathered for gather_perf_sum_per_acc_per_event\n  ## in case of empty list all events will be gathered\n  # perf_summary_events                       = []\n\n  ## the limits for metrics form perf_events_statements\n  # perf_events_statements_digest_text_limit = 120\n  # perf_events_statements_limit = 250\n  # perf_events_statements_time_limit = 86400\n\n  ## Some queries we may want to run less often (such as SHOW GLOBAL VARIABLES)\n  ##   example: interval_slow = \"30m\"\n  # interval_slow = \"\"\n\n  ## Optional TLS Config (used if tls=custom parameter specified in server uri)\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### String Data\n\nSome fields may return string data. This is unhelpful for some outputs where\nnumeric data is required (e.g. Prometheus). In these cases, users can make use\nof the enum processor to convert string values to numeric values. Below is an\nexample using the `slave_slave_io_running` field, which can have a variety of\nstring values:\n\n```toml\n[[processors.enum]]\n  namepass = \"mysql\"\n  [[processors.enum.mapping]]\n    field = \"slave_slave_io_running\"\n    dest = \"slave_slave_io_running_int\"\n    default = 4\n    [processors.enum.mapping.value_mappings]\n      Yes = 0\n      No = 1\n      Preparing = 2\n      Connecting = 3\n```\n\n### Metric Version\n\nWhen `metric_version = 2`, a variety of field type issues are corrected as well\nas naming inconsistencies.  If you have existing data on the original version\nenabling this feature will cause a `field type error` when inserted into\nInfluxDB due to the change of types.  For this reason, you should keep the\n`metric_version` unset until you are ready to migrate to the new format.\n\nIf preserving your old data is not required you may wish to drop conflicting\nmeasurements:\n\n```sql\nDROP SERIES from mysql\nDROP SERIES from mysql_variables\nDROP SERIES from mysql_innodb\n```\n\nOtherwise, migration can be performed using the following steps:\n\n1. Duplicate your `mysql` plugin configuration and add a `name_suffix` and\n`metric_version = 2`, this will result in collection using both the old and new\nstyle concurrently:\n\n   ```toml\n   [[inputs.mysql]]\n     servers = [\"tcp(127.0.0.1:3306)/\"]\n\n   [[inputs.mysql]]\n     name_suffix = \"_v2\"\n     metric_version = 2\n\n     servers = [\"tcp(127.0.0.1:3306)/\"]\n   ```\n\n2. Upgrade all affected Telegraf clients to version >=1.6.\n\n   New measurements will be created with the `name_suffix`, for example::\n   * `mysql_v2`\n   * `mysql_variables_v2`\n\n3. Update charts, alerts, and other supporting code to the new format.\n4. You can now remove the old `mysql` plugin configuration and remove old\n   measurements.\n\nIf you wish to remove the `name_suffix` you may use Kapacitor to copy the\nhistorical data to the default name.  Do this only after retiring the old\nmeasurement name.\n\n1. Use the technique described above to write to multiple locations:\n\n   ```toml\n   [[inputs.mysql]]\n     servers = [\"tcp(127.0.0.1:3306)/\"]\n     metric_version = 2\n\n   [[inputs.mysql]]\n     name_suffix = \"_v2\"\n     metric_version = 2\n\n     servers = [\"tcp(127.0.0.1:3306)/\"]\n   ```\n\n2. Create a TICKScript to copy the historical data:\n\n   ```sql\n   dbrp \"telegraf\".\"autogen\"\n\n   batch\n       |query('''\n           SELECT * FROM \"telegraf\".\"autogen\".\"mysql_v2\"\n       ''')\n           .period(5m)\n           .every(5m)\n           |influxDBOut()\n                   .database('telegraf')\n                   .retentionPolicy('autogen')\n                   .measurement('mysql')\n   ```\n\n3. Define a task for your script:\n\n   ```sh\n   kapacitor define copy-measurement -tick copy-measurement.task\n   ```\n\n4. Run the task over the data you would like to migrate:\n\n   ```sh\n   kapacitor replay-live batch -start 2018-03-30T20:00:00Z -stop 2018-04-01T12:00:00Z -rec-time -task copy-measurement\n   ```\n\n5. Verify copied data and repeat for other measurements.\n\n## Metrics\n\n* Global statuses - all numeric and boolean values of `SHOW GLOBAL STATUSES`\n  * wsrep_evs_repl_latency - a complex field containing multiple values is split\n      into separate fields\n    * wsrep_evs_repl_latency_min(float, seconds)\n    * wsrep_evs_repl_latency_avg(float, seconds)\n    * wsrep_evs_repl_latency_max(float, seconds)\n    * wsrep_evs_repl_latency_stdev(float, seconds)\n    * wsrep_evs_repl_latency_sample_size(float, number)\n* Global variables - all numeric and boolean values of `SHOW GLOBAL VARIABLES`\n  * wsrep_provider_options - a complex field containing multiple values is split\n      into separate fields\n    * gcache_size(int, bytes)\n* Slave status - metrics from `SHOW SLAVE STATUS` the metrics are gathered when\nthe single-source replication is on. If the multi-source replication is set,\nthen everything works differently, this metric does not work with multi-source\nreplication, unless you set `gather_all_slave_channels = true`. For MariaDB,\n`mariadb_dialect = true` should be set to address the field names and commands\ndifferences. If enable `gather_replica_status` metrics gather from command\n`SHOW REPLICA STATUS`, for MariaDB will be `SHOW ALL REPLICAS STATUS`\n  * slave_[column name]\n* Binary logs - all metrics including size and count of all binary files.\nRequires to be turned on in configuration.\n  * binary_size_bytes(int, number)\n  * binary_files_count(int, number)\n* Process list - connection metrics from processlist for each user. It has the\n  following tags\n  * connections(int, number)\n* User Statistics - connection metrics from user statistics for each user.\n  It has the following fields\n  * access_denied\n  * binlog_bytes_written\n  * busy_time\n  * bytes_received\n  * bytes_sent\n  * commit_transactions\n  * concurrent_connections\n  * connected_time\n  * cpu_time\n  * denied_connections\n  * empty_queries\n  * hostlost_connections\n  * other_commands\n  * rollback_transactions\n  * rows_fetched\n  * rows_updated\n  * select_commands\n  * server\n  * table_rows_read\n  * total_connections\n  * total_ssl_connections\n  * update_commands\n  * user\n* Perf Table IO waits - total count and time of I/O waits event for each table\nand process. It has following fields:\n  * table_io_waits_total_fetch(float, number)\n  * table_io_waits_total_insert(float, number)\n  * table_io_waits_total_update(float, number)\n  * table_io_waits_total_delete(float, number)\n  * table_io_waits_seconds_total_fetch(float, milliseconds)\n  * table_io_waits_seconds_total_insert(float, milliseconds)\n  * table_io_waits_seconds_total_update(float, milliseconds)\n  * table_io_waits_seconds_total_delete(float, milliseconds)\n* Perf index IO waits - total count and time of I/O waits event for each index\nand process. It has following fields:\n  * index_io_waits_total_fetch(float, number)\n  * index_io_waits_seconds_total_fetch(float, milliseconds)\n  * index_io_waits_total_insert(float, number)\n  * index_io_waits_total_update(float, number)\n  * index_io_waits_total_delete(float, number)\n  * index_io_waits_seconds_total_insert(float, milliseconds)\n  * index_io_waits_seconds_total_update(float, milliseconds)\n  * index_io_waits_seconds_total_delete(float, milliseconds)\n* Info schema autoincrement statuses - autoincrement fields and max values\nfor them. It has following fields:\n  * auto_increment_column(int, number)\n  * auto_increment_column_max(int, number)\n* InnoDB metrics - all metrics of information_schema.INNODB_METRICS with a\n  status \"enabled\". For MariaDB, `mariadb_dialect = true` to use `ENABLED=1`.\n* Perf table lock waits - gathers total number and time for SQL and external\nlock waits events for each table and operation. It has following fields.\nThe unit of fields varies by the tags.\n  * read_normal(float, number/milliseconds)\n  * read_with_shared_locks(float, number/milliseconds)\n  * read_high_priority(float, number/milliseconds)\n  * read_no_insert(float, number/milliseconds)\n  * write_normal(float, number/milliseconds)\n  * write_allow_write(float, number/milliseconds)\n  * write_concurrent_insert(float, number/milliseconds)\n  * write_low_priority(float, number/milliseconds)\n  * read(float, number/milliseconds)\n  * write(float, number/milliseconds)\n* Perf events waits - gathers total time and number of event waits\n  * events_waits_total(float, number)\n  * events_waits_seconds_total(float, milliseconds)\n* Perf file events statuses - gathers file events statuses\n  * file_events_total(float,number)\n  * file_events_seconds_total(float, milliseconds)\n  * file_events_bytes_total(float, bytes)\n* Perf events statements - gathers attributes of each event\n  * events_statements_total(float, number)\n  * events_statements_seconds_total(float, millieconds)\n  * events_statements_errors_total(float, number)\n  * events_statements_warnings_total(float, number)\n  * events_statements_rows_affected_total(float, number)\n  * events_statements_rows_sent_total(float, number)\n  * events_statements_rows_examined_total(float, number)\n  * events_statements_tmp_tables_total(float, number)\n  * events_statements_tmp_disk_tables_total(float, number)\n  * events_statements_sort_merge_passes_totals(float, number)\n  * events_statements_sort_rows_total(float, number)\n  * events_statements_no_index_used_total(float, number)\n* Table schema - gathers statistics per schema. It has following measurements\n  * info_schema_table_rows(float, number)\n  * info_schema_table_size_data_length(float, number)\n  * info_schema_table_size_index_length(float, number)\n  * info_schema_table_size_data_free(float, number)\n  * info_schema_table_version(float, number)\n\n## Tags\n\n* All measurements has following tags\n  * server (the host name from which the metrics are gathered)\n* Process list measurement has following tags\n  * user (username for whom the metrics are gathered)\n* User Statistics measurement has following tags\n  * user (username for whom the metrics are gathered)\n* Perf table IO waits measurement has following tags\n  * schema\n  * name (object name for event or process)\n* Perf index IO waits has following tags\n  * schema\n  * name\n  * index\n* Info schema autoincrement statuses has following tags\n  * schema\n  * table\n  * column\n* Perf table lock waits has following tags\n  * schema\n  * table\n  * sql_lock_waits_total(fields including this tag have numeric unit)\n  * external_lock_waits_total(fields including this tag have numeric unit)\n  * sql_lock_waits_seconds_total(fields including this tag have millisecond unit)\n  * external_lock_waits_seconds_total(fields including this tag have\n    millisecond unit)\n* Perf events statements has following tags\n  * event_name\n* Perf file events statuses has following tags\n  * event_name\n  * mode\n* Perf file events statements has following tags\n  * schema\n  * digest\n  * digest_text\n* Table schema has following tags\n  * schema\n  * table\n  * component\n  * type\n  * engine\n  * row_format\n  * create_options\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/mysql/dev/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mysql:\n    image: mysql:5.7\n    restart: always\n    environment:\n      MYSQL_ROOT_PASSWORD: telegraf\n      MYSQL_DATABASE: telegraf\n      MYSQL_USER: telegraf\n      MYSQL_PASSWORD: telegraf\n  maria:\n    image: mariadb\n    restart: always\n    environment:\n      MYSQL_ROOT_PASSWORD: telegraf\n      MYSQL_DATABASE: telegraf\n      MYSQL_USER: telegraf\n      MYSQL_PASSWORD: telegraf\n    command: mysqld --userstat=1\n  percona:\n    image: percona\n    restart: always\n    environment:\n      MYSQL_ROOT_PASSWORD: telegraf\n      MYSQL_DATABASE: telegraf\n      MYSQL_USER: telegraf\n      MYSQL_PASSWORD: telegraf\n\n  telegraf:\n    image: glinton/scratch\n    depends_on:\n      - mysql\n      - maria\n      - percona\n    volumes:\n      - ./telegraf.conf:/telegraf.conf\n      - ../../../../telegraf:/telegraf\n    entrypoint:\n      - /telegraf\n      - --config\n      - /telegraf.conf\n"
  },
  {
    "path": "plugins/inputs/mysql/dev/telegraf.conf",
    "content": "# Uncomment each input as needed to test plugin\n\n## mysql\n#[[inputs.mysql]]\n#  servers = [\"root:telegraf@tcp(mysql:3306)/\"]\n#  gather_table_schema = true\n#  gather_process_list = true\n#  gather_user_statistics = true\n#  gather_info_schema_auto_inc = true\n#  gather_innodb_metrics = true\n#  gather_slave_status = true\n#  gather_binary_logs = false\n#  gather_table_io_waits = true\n#  gather_table_lock_waits = true\n#  gather_index_io_waits = true\n#  gather_event_waits = true\n#  gather_file_events_stats = true\n#  gather_perf_events_statements = true\n#  interval_slow = \"30m\"\n#  table_schema_databases = []\n#\n## mariadb\n#[[inputs.mysql]]\n#  servers = [\"root:telegraf@tcp(maria:3306)/\"]\n#  gather_table_schema = true\n#  gather_process_list = true\n#  gather_user_statistics = true\n#  gather_info_schema_auto_inc = true\n#  gather_innodb_metrics = true\n#  gather_slave_status = true\n#  gather_binary_logs = false\n#  gather_table_io_waits = true\n#  gather_table_lock_waits = true\n#  gather_index_io_waits = true\n#  gather_event_waits = true\n#  gather_file_events_stats = true\n#  gather_perf_events_statements = true\n#  interval_slow = \"30m\"\n#  table_schema_databases = []\n\n# percona\n[[inputs.mysql]]\n  servers = [\"root:telegraf@tcp(percona:3306)/\"]\n  gather_table_schema = true\n  gather_process_list = true\n  gather_user_statistics = true\n  gather_info_schema_auto_inc = true\n  gather_innodb_metrics = true\n  gather_slave_status = true\n  gather_binary_logs = false\n  gather_table_io_waits = true\n  gather_table_lock_waits = true\n  gather_index_io_waits = true\n  gather_event_waits = true\n  gather_file_events_stats = true\n  gather_perf_events_statements = true\n  interval_slow = \"30m\"\n  table_schema_databases = []\n\n[[outputs.file]]\n  files = [\"stdout\"]\n"
  },
  {
    "path": "plugins/inputs/mysql/mysql.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage mysql\n\nimport (\n\t\"database/sql\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-sql-driver/mysql\"\n\t\"github.com/gofrs/uuid/v5\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/mysql/v1\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/mysql/v2\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar tlsRe = regexp.MustCompile(`([\\?&])(?:tls=custom)($|&)`)\n\nconst (\n\tdefaultPerfEventsStatementsDigestTextLimit = 120\n\tdefaultPerfEventsStatementsLimit           = 250\n\tdefaultPerfEventsStatementsTimeLimit       = 86400\n\tdefaultGatherGlobalVars                    = true\n\tlocalhost                                  = \"\"\n)\n\ntype Mysql struct {\n\tServers                             []*config.Secret `toml:\"servers\"`\n\tPerfEventsStatementsDigestTextLimit int64            `toml:\"perf_events_statements_digest_text_limit\"`\n\tPerfEventsStatementsLimit           int64            `toml:\"perf_events_statements_limit\"`\n\tPerfEventsStatementsTimeLimit       int64            `toml:\"perf_events_statements_time_limit\"`\n\tTableSchemaDatabases                []string         `toml:\"table_schema_databases\"`\n\tGatherProcessList                   bool             `toml:\"gather_process_list\"`\n\tGatherUserStatistics                bool             `toml:\"gather_user_statistics\"`\n\tGatherInfoSchemaAutoInc             bool             `toml:\"gather_info_schema_auto_inc\"`\n\tGatherInnoDBMetrics                 bool             `toml:\"gather_innodb_metrics\"`\n\tGatherSlaveStatus                   bool             `toml:\"gather_slave_status\"`\n\tGatherReplicaStatus                 bool             `toml:\"gather_replica_status\"`\n\tGatherAllSlaveChannels              bool             `toml:\"gather_all_slave_channels\"`\n\tMariadbDialect                      bool             `toml:\"mariadb_dialect\"`\n\tGatherBinaryLogs                    bool             `toml:\"gather_binary_logs\"`\n\tGatherTableIOWaits                  bool             `toml:\"gather_table_io_waits\"`\n\tGatherTableLockWaits                bool             `toml:\"gather_table_lock_waits\"`\n\tGatherIndexIOWaits                  bool             `toml:\"gather_index_io_waits\"`\n\tGatherEventWaits                    bool             `toml:\"gather_event_waits\"`\n\tGatherTableSchema                   bool             `toml:\"gather_table_schema\"`\n\tGatherFileEventsStats               bool             `toml:\"gather_file_events_stats\"`\n\tGatherPerfEventsStatements          bool             `toml:\"gather_perf_events_statements\"`\n\tGatherGlobalVars                    bool             `toml:\"gather_global_variables\"`\n\tGatherPerfSummaryPerAccountPerEvent bool             `toml:\"gather_perf_sum_per_acc_per_event\"`\n\tPerfSummaryEvents                   []string         `toml:\"perf_summary_events\"`\n\tIntervalSlow                        config.Duration  `toml:\"interval_slow\"`\n\tMetricVersion                       int              `toml:\"metric_version\"`\n\tLog                                 telegraf.Logger  `toml:\"-\"`\n\ttls.ClientConfig\n\n\tlastT               time.Time\n\tgetStatusQuery      string\n\tloggedConvertFields map[string]bool\n}\n\nfunc (*Mysql) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Mysql) Init() error {\n\tswitch {\n\tcase m.MariadbDialect && m.GatherReplicaStatus:\n\t\tm.getStatusQuery = replicaStatusQueryMariadb\n\tcase m.MariadbDialect:\n\t\tm.getStatusQuery = slaveStatusQueryMariadb\n\tcase m.GatherReplicaStatus:\n\t\tm.getStatusQuery = replicaStatusQuery\n\tdefault:\n\t\tm.getStatusQuery = slaveStatusQuery\n\t}\n\t// Default to localhost if nothing specified.\n\tif len(m.Servers) == 0 {\n\t\ts := config.NewSecret([]byte(localhost))\n\t\tm.Servers = append(m.Servers, &s)\n\t}\n\n\tm.loggedConvertFields = make(map[string]bool)\n\n\t// Register the TLS configuration. Due to the registry being a global\n\t// one for the mysql package, we need to define unique IDs to avoid\n\t// side effects and races between different plugin instances. Therefore,\n\t// we decorate the \"custom\" naming of the \"tls\" parameter with an UUID.\n\ttlsuuid, err := uuid.NewV7()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot create UUID: %w\", err)\n\t}\n\ttlsid := \"custom-\" + tlsuuid.String()\n\ttlsConfig, err := m.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"registering TLS config: %w\", err)\n\t}\n\tif tlsConfig != nil {\n\t\tif err := mysql.RegisterTLSConfig(tlsid, tlsConfig); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Adapt the DSN string\n\tfor i, server := range m.Servers {\n\t\tdsnSecret, err := server.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting server %d failed: %w\", i, err)\n\t\t}\n\t\tdsn := dsnSecret.String()\n\t\tdsnSecret.Destroy()\n\n\t\t// Reference the custom TLS config of _THIS_ plugin instance\n\t\tif tlsRe.MatchString(dsn) {\n\t\t\tdsn = tlsRe.ReplaceAllString(dsn, \"${1}tls=\"+tlsid+\"${2}\")\n\t\t}\n\n\t\tconf, err := mysql.ParseDSN(dsn)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing %q failed: %w\", dsn, err)\n\t\t}\n\n\t\t// Set the default timeout if none specified\n\t\tif conf.Timeout == 0 {\n\t\t\tconf.Timeout = time.Second * 5\n\t\t}\n\n\t\tif err := server.Set([]byte(conf.FormatDSN())); err != nil {\n\t\t\treturn fmt.Errorf(\"replacing server %q failed: %w\", dsn, err)\n\t\t}\n\n\t\tm.Servers[i] = server\n\t}\n\n\treturn nil\n}\n\nfunc (m *Mysql) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Loop through each server and collect metrics\n\tfor _, server := range m.Servers {\n\t\twg.Add(1)\n\t\tgo func(s *config.Secret) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(m.gatherServer(s, acc))\n\t\t}(server)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\n// These are const but can't be declared as such because golang doesn't allow const maps\nvar (\n\t// status counter\n\tgeneralThreadStates = map[string]uint32{\n\t\t\"after create\":              uint32(0),\n\t\t\"altering table\":            uint32(0),\n\t\t\"analyzing\":                 uint32(0),\n\t\t\"checking permissions\":      uint32(0),\n\t\t\"checking table\":            uint32(0),\n\t\t\"cleaning up\":               uint32(0),\n\t\t\"closing tables\":            uint32(0),\n\t\t\"converting heap to myisam\": uint32(0),\n\t\t\"copying to tmp table\":      uint32(0),\n\t\t\"creating sort index\":       uint32(0),\n\t\t\"creating table\":            uint32(0),\n\t\t\"creating tmp table\":        uint32(0),\n\t\t\"deleting\":                  uint32(0),\n\t\t\"executing\":                 uint32(0),\n\t\t\"execution of init_command\": uint32(0),\n\t\t\"end\":                       uint32(0),\n\t\t\"freeing items\":             uint32(0),\n\t\t\"flushing tables\":           uint32(0),\n\t\t\"fulltext initialization\":   uint32(0),\n\t\t\"idle\":                      uint32(0),\n\t\t\"init\":                      uint32(0),\n\t\t\"killed\":                    uint32(0),\n\t\t\"waiting for lock\":          uint32(0),\n\t\t\"logging slow query\":        uint32(0),\n\t\t\"login\":                     uint32(0),\n\t\t\"manage keys\":               uint32(0),\n\t\t\"opening tables\":            uint32(0),\n\t\t\"optimizing\":                uint32(0),\n\t\t\"preparing\":                 uint32(0),\n\t\t\"reading from net\":          uint32(0),\n\t\t\"removing duplicates\":       uint32(0),\n\t\t\"removing tmp table\":        uint32(0),\n\t\t\"reopen tables\":             uint32(0),\n\t\t\"repair by sorting\":         uint32(0),\n\t\t\"repair done\":               uint32(0),\n\t\t\"repair with keycache\":      uint32(0),\n\t\t\"replication master\":        uint32(0),\n\t\t\"rolling back\":              uint32(0),\n\t\t\"searching rows for update\": uint32(0),\n\t\t\"sending data\":              uint32(0),\n\t\t\"sorting for group\":         uint32(0),\n\t\t\"sorting for order\":         uint32(0),\n\t\t\"sorting index\":             uint32(0),\n\t\t\"sorting result\":            uint32(0),\n\t\t\"statistics\":                uint32(0),\n\t\t\"updating\":                  uint32(0),\n\t\t\"waiting for tables\":        uint32(0),\n\t\t\"waiting for table flush\":   uint32(0),\n\t\t\"waiting on cond\":           uint32(0),\n\t\t\"writing to net\":            uint32(0),\n\t\t\"other\":                     uint32(0),\n\t}\n\t// plaintext statuses\n\tstateStatusMappings = map[string]string{\n\t\t\"user sleep\":     \"idle\",\n\t\t\"creating index\": \"altering table\",\n\t\t\"committing alter table to storage engine\": \"altering table\",\n\t\t\"discard or import tablespace\":             \"altering table\",\n\t\t\"rename\":                                   \"altering table\",\n\t\t\"setup\":                                    \"altering table\",\n\t\t\"renaming result table\":                    \"altering table\",\n\t\t\"preparing for alter table\":                \"altering table\",\n\t\t\"copying to group table\":                   \"copying to tmp table\",\n\t\t\"copy to tmp table\":                        \"copying to tmp table\",\n\t\t\"query end\":                                \"end\",\n\t\t\"update\":                                   \"updating\",\n\t\t\"updating main table\":                      \"updating\",\n\t\t\"updating reference tables\":                \"updating\",\n\t\t\"system lock\":                              \"waiting for lock\",\n\t\t\"user lock\":                                \"waiting for lock\",\n\t\t\"table lock\":                               \"waiting for lock\",\n\t\t\"deleting from main table\":                 \"deleting\",\n\t\t\"deleting from reference tables\":           \"deleting\",\n\t}\n)\n\n// Math constants\nconst (\n\tpicoSeconds = 1e12\n)\n\n// metric queries\nconst (\n\tglobalStatusQuery          = `SHOW GLOBAL STATUS`\n\tglobalVariablesQuery       = `SHOW GLOBAL VARIABLES`\n\tslaveStatusQuery           = `SHOW SLAVE STATUS`\n\treplicaStatusQuery         = `SHOW REPLICA STATUS`\n\tslaveStatusQueryMariadb    = `SHOW ALL SLAVES STATUS`\n\treplicaStatusQueryMariadb  = `SHOW ALL REPLICAS STATUS`\n\tbinaryLogsQuery            = `SHOW BINARY LOGS`\n\tinfoSchemaProcessListQuery = `\n        SELECT COALESCE(command,''),COALESCE(state,''),count(*)\n        FROM information_schema.processlist\n        WHERE ID != connection_id()\n        GROUP BY command,state\n        ORDER BY null`\n\tinfoSchemaUserStatisticsQuery = `\n        SELECT *\n        FROM information_schema.user_statistics`\n\tinfoSchemaAutoIncQuery = `\n        SELECT table_schema, table_name, column_name, auto_increment,\n          CAST(pow(2, case data_type\n            when 'tinyint'   then 7\n            when 'smallint'  then 15\n            when 'mediumint' then 23\n            when 'int'       then 31\n            when 'bigint'    then 63\n            end+(column_type like '% unsigned'))-1 as decimal(19)) as max_int\n          FROM information_schema.tables t\n          JOIN information_schema.columns c USING (table_schema,table_name)\n          WHERE c.extra = 'auto_increment' AND t.auto_increment IS NOT NULL\n    `\n\tinnoDBMetricsQuery = `\n        SELECT NAME, COUNT\n        FROM information_schema.INNODB_METRICS\n        WHERE status='enabled'\n    `\n\tinnoDBMetricsQueryMariadb = `\n        EXECUTE IMMEDIATE CONCAT(\"\n            SELECT NAME, COUNT\n            FROM information_schema.INNODB_METRICS\n            WHERE \", IF(version() REGEXP '10\\.[1-4]\\\\..*',\"status='enabled'\", \"ENABLED=1\"), \"\n        \");\n\t`\n\tperfTableIOWaitsQuery = `\n        SELECT OBJECT_SCHEMA, OBJECT_NAME, COUNT_FETCH, COUNT_INSERT, COUNT_UPDATE, COUNT_DELETE,\n        SUM_TIMER_FETCH, SUM_TIMER_INSERT, SUM_TIMER_UPDATE, SUM_TIMER_DELETE\n        FROM performance_schema.table_io_waits_summary_by_table\n        WHERE OBJECT_SCHEMA NOT IN ('mysql', 'performance_schema')\n    `\n\tperfIndexIOWaitsQuery = `\n        SELECT OBJECT_SCHEMA, OBJECT_NAME, ifnull(INDEX_NAME, 'NONE') as INDEX_NAME,\n        COUNT_FETCH, COUNT_INSERT, COUNT_UPDATE, COUNT_DELETE,\n        SUM_TIMER_FETCH, SUM_TIMER_INSERT, SUM_TIMER_UPDATE, SUM_TIMER_DELETE\n        FROM performance_schema.table_io_waits_summary_by_index_usage\n        WHERE OBJECT_SCHEMA NOT IN ('mysql', 'performance_schema')\n    `\n\tperfTableLockWaitsQuery = `\n        SELECT\n            OBJECT_SCHEMA,\n            OBJECT_NAME,\n            COUNT_READ_NORMAL,\n            COUNT_READ_WITH_SHARED_LOCKS,\n            COUNT_READ_HIGH_PRIORITY,\n            COUNT_READ_NO_INSERT,\n            COUNT_READ_EXTERNAL,\n            COUNT_WRITE_ALLOW_WRITE,\n            COUNT_WRITE_CONCURRENT_INSERT,\n            COUNT_WRITE_LOW_PRIORITY,\n            COUNT_WRITE_NORMAL,\n            COUNT_WRITE_EXTERNAL,\n            SUM_TIMER_READ_NORMAL,\n            SUM_TIMER_READ_WITH_SHARED_LOCKS,\n            SUM_TIMER_READ_HIGH_PRIORITY,\n            SUM_TIMER_READ_NO_INSERT,\n            SUM_TIMER_READ_EXTERNAL,\n            SUM_TIMER_WRITE_ALLOW_WRITE,\n            SUM_TIMER_WRITE_CONCURRENT_INSERT,\n            SUM_TIMER_WRITE_LOW_PRIORITY,\n            SUM_TIMER_WRITE_NORMAL,\n            SUM_TIMER_WRITE_EXTERNAL\n        FROM performance_schema.table_lock_waits_summary_by_table\n        WHERE OBJECT_SCHEMA NOT IN ('mysql', 'performance_schema', 'information_schema')\n    `\n\tperfEventsStatementsQuery = `\n        SELECT\n            ifnull(SCHEMA_NAME, 'NONE') as SCHEMA_NAME,\n            DIGEST,\n            LEFT(DIGEST_TEXT, %d) as DIGEST_TEXT,\n            COUNT_STAR,\n            SUM_TIMER_WAIT,\n            SUM_ERRORS,\n            SUM_WARNINGS,\n            SUM_ROWS_AFFECTED,\n            SUM_ROWS_SENT,\n            SUM_ROWS_EXAMINED,\n            SUM_CREATED_TMP_DISK_TABLES,\n            SUM_CREATED_TMP_TABLES,\n            SUM_SORT_MERGE_PASSES,\n            SUM_SORT_ROWS,\n            SUM_NO_INDEX_USED\n        FROM performance_schema.events_statements_summary_by_digest\n        WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'information_schema')\n            AND last_seen > DATE_SUB(NOW(), INTERVAL %d SECOND)\n        ORDER BY SUM_TIMER_WAIT DESC\n        LIMIT %d\n    `\n\tperfEventWaitsQuery = `\n        SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT\n        FROM performance_schema.events_waits_summary_global_by_event_name\n    `\n\tperfFileEventsQuery = `\n        SELECT\n            EVENT_NAME,\n            COUNT_READ, SUM_TIMER_READ, SUM_NUMBER_OF_BYTES_READ,\n            COUNT_WRITE, SUM_TIMER_WRITE, SUM_NUMBER_OF_BYTES_WRITE,\n            COUNT_MISC, SUM_TIMER_MISC\n        FROM performance_schema.file_summary_by_event_name\n    `\n\ttableSchemaQuery = `\n        SELECT\n            TABLE_SCHEMA,\n            TABLE_NAME,\n            TABLE_TYPE,\n            ifnull(ENGINE, 'NONE') as ENGINE,\n            ifnull(VERSION, '0') as VERSION,\n            ifnull(ROW_FORMAT, 'NONE') as ROW_FORMAT,\n            ifnull(TABLE_ROWS, '0') as TABLE_ROWS,\n            ifnull(DATA_LENGTH, '0') as DATA_LENGTH,\n            ifnull(INDEX_LENGTH, '0') as INDEX_LENGTH,\n            ifnull(DATA_FREE, '0') as DATA_FREE,\n            ifnull(CREATE_OPTIONS, 'NONE') as CREATE_OPTIONS\n        FROM information_schema.tables\n        WHERE TABLE_SCHEMA = '%s'\n    `\n\tdbListQuery = `\n        SELECT\n            SCHEMA_NAME\n            FROM information_schema.schemata\n        WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'information_schema')\n    `\n\tperfSchemaTablesQuery = `\n\t\tSELECT\n\t\t\ttable_name\n\t\t\tFROM information_schema.tables\n\t\tWHERE table_schema = 'performance_schema' AND table_name = ?\n\t`\n\n\tperfSummaryPerAccountPerEvent = `\n        SELECT\n\t\t\tcoalesce(user, \"unknown\"),\n\t\t\tcoalesce(host, \"unknown\"),\n\t\t\tcoalesce(event_name, \"unknown\"),\n\t\t\tcount_star,\n\t\t\tsum_timer_wait,\n\t\t\tmin_timer_wait,\n\t\t\tavg_timer_wait,\n\t\t\tmax_timer_wait,\n\t\t\tsum_lock_time,\n\t\t\tsum_errors,\n\t\t\tsum_warnings,\n\t\t\tsum_rows_affected,\n\t\t\tsum_rows_sent,\n\t\t\tsum_rows_examined,\n\t\t\tsum_created_tmp_disk_tables,\n\t\t\tsum_created_tmp_tables,\n\t\t\tsum_select_full_join,\n\t\t\tsum_select_full_range_join,\n\t\t\tsum_select_range,\n\t\t\tsum_select_range_check,\n\t\t\tsum_select_scan,\n\t\t\tsum_sort_merge_passes,\n\t\t\tsum_sort_range,\n\t\t\tsum_sort_rows,\n\t\t\tsum_sort_scan,\n\t\t\tsum_no_index_used,\n\t\t\tsum_no_good_index_used\n\t\tFROM performance_schema.events_statements_summary_by_account_by_event_name\n\t`\n)\n\nfunc (m *Mysql) gatherServer(server *config.Secret, acc telegraf.Accumulator) error {\n\tdsnSecret, err := server.Get()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdsn := dsnSecret.String()\n\tdsnSecret.Destroy()\n\tservtag := getDSNTag(dsn)\n\n\tdb, err := sql.Open(\"mysql\", dsn)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer db.Close()\n\n\terr = m.gatherGlobalStatuses(db, servtag, acc)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif m.GatherGlobalVars {\n\t\t// Global Variables may be gathered less often\n\t\tinterval := time.Duration(m.IntervalSlow)\n\t\tif interval >= time.Second && time.Since(m.lastT) >= interval {\n\t\t\tif err := m.gatherGlobalVariables(db, servtag, acc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tm.lastT = time.Now()\n\t\t}\n\t}\n\n\tif m.GatherBinaryLogs {\n\t\terr = gatherBinaryLogs(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherProcessList {\n\t\terr = m.gatherProcessListStatuses(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherUserStatistics {\n\t\terr = m.gatherUserStatisticsStatuses(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherSlaveStatus || m.GatherReplicaStatus {\n\t\terr = m.gatherSlaveStatuses(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherInfoSchemaAutoInc {\n\t\terr = m.gatherInfoSchemaAutoIncStatuses(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherInnoDBMetrics {\n\t\terr = m.gatherInnoDBMetrics(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherPerfSummaryPerAccountPerEvent {\n\t\terr = m.gatherPerfSummaryPerAccountPerEvent(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherTableIOWaits {\n\t\terr = gatherPerfTableIOWaits(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherIndexIOWaits {\n\t\terr = gatherPerfIndexIOWaits(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherTableLockWaits {\n\t\terr = gatherPerfTableLockWaits(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherEventWaits {\n\t\terr = gatherPerfEventWaits(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherFileEventsStats {\n\t\terr = gatherPerfFileEventsStatuses(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherPerfEventsStatements {\n\t\terr = m.gatherPerfEventsStatements(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.GatherTableSchema {\n\t\terr = m.gatherTableSchema(db, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherGlobalVariables can be used to fetch all global variables from\n// MySQL environment.\nfunc (m *Mysql) gatherGlobalVariables(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\trows, err := db.Query(globalVariablesQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar key string\n\tvar val sql.RawBytes\n\n\t// parse DSN and save server tag\n\ttags := map[string]string{\"server\": servtag}\n\tfields := make(map[string]interface{})\n\tfor rows.Next() {\n\t\tif err := rows.Scan(&key, &val); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tkey = strings.ToLower(key)\n\n\t\t// parse mysql version and put into field and tag\n\t\tif strings.Contains(key, \"version\") {\n\t\t\tfields[key] = string(val)\n\t\t\ttags[key] = string(val)\n\t\t}\n\n\t\tvalue, err := m.parseGlobalVariables(key, val)\n\t\tif err != nil {\n\t\t\terrString := fmt.Errorf(\"error parsing mysql global variable %q=%q: %w\", key, string(val), err)\n\t\t\tif m.MetricVersion < 2 {\n\t\t\t\tm.Log.Debug(errString)\n\t\t\t} else {\n\t\t\t\tacc.AddError(errString)\n\t\t\t}\n\t\t} else {\n\t\t\t// v2.ConvertGlobalVariables can parse \"complex\" multi-value fields, e.g. wsrep_provider_options\n\t\t\tparseKeyValues(fields, key, value)\n\t\t}\n\n\t\t// Send 20 fields at a time\n\t\tif len(fields) >= 20 {\n\t\t\tacc.AddFields(\"mysql_variables\", fields, tags)\n\t\t\tfields = make(map[string]interface{})\n\t\t}\n\t}\n\t// Send any remaining fields\n\tif len(fields) > 0 {\n\t\tacc.AddFields(\"mysql_variables\", fields, tags)\n\t}\n\treturn nil\n}\n\nfunc (m *Mysql) parseGlobalVariables(key string, value sql.RawBytes) (interface{}, error) {\n\tif m.MetricVersion < 2 {\n\t\treturn v1.ParseValue(value)\n\t}\n\treturn v2.ConvertGlobalVariables(key, value)\n}\n\n// gatherSlaveStatuses can be used to get replication analytics\n// When the server is slave, then it returns only one row.\n// If the multi-source replication is set, then everything works differently\n// This code does not work with multi-source replication.\nfunc (m *Mysql) gatherSlaveStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\tvar rows *sql.Rows\n\tvar err error\n\n\trows, err = db.Query(m.getStatusQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\ttags := map[string]string{\"server\": servtag}\n\tfields := make(map[string]interface{})\n\n\t// for each channel record\n\tfor rows.Next() {\n\t\t// to save the column names as a field key\n\t\t// scanning keys and values separately\n\n\t\t// get columns names, and create an array with its length\n\t\tcols, err := rows.ColumnTypes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvals := make([]sql.RawBytes, len(cols))\n\t\tvalPtrs := make([]interface{}, len(cols))\n\t\t// fill the array with sql.Rawbytes\n\t\tfor i := range vals {\n\t\t\tvals[i] = sql.RawBytes{}\n\t\t\tvalPtrs[i] = &vals[i]\n\t\t}\n\t\tif err := rows.Scan(valPtrs...); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// range over columns, and try to parse values\n\t\tfor i, col := range cols {\n\t\t\tcolName := col.Name()\n\n\t\t\tif m.MetricVersion >= 2 {\n\t\t\t\tcolName = strings.ToLower(colName)\n\t\t\t}\n\n\t\t\tcolValue := vals[i]\n\n\t\t\tif m.GatherAllSlaveChannels &&\n\t\t\t\t(strings.EqualFold(colName, \"channel_name\") || strings.EqualFold(colName, \"connection_name\")) {\n\t\t\t\t// Since the default channel name is empty, we need this block\n\t\t\t\tchannelName := \"default\"\n\t\t\t\tif len(colValue) > 0 {\n\t\t\t\t\tchannelName = string(colValue)\n\t\t\t\t}\n\t\t\t\ttags[\"channel\"] = channelName\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif len(colValue) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvalue, err := m.parseValueByDatabaseTypeName(colValue, col.DatabaseTypeName())\n\t\t\tif err != nil {\n\t\t\t\terrString := fmt.Errorf(\"error parsing mysql slave status %q=%q: %w\", colName, string(colValue), err)\n\t\t\t\tif m.MetricVersion < 2 {\n\t\t\t\t\tm.Log.Debug(errString)\n\t\t\t\t} else {\n\t\t\t\t\tacc.AddError(errString)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfields[\"slave_\"+colName] = value\n\t\t}\n\t\tacc.AddFields(\"mysql\", fields, tags)\n\n\t\t// Only the first row is relevant if not all slave-channels should be gathered,\n\t\t// so break here and skip the remaining rows\n\t\tif !m.GatherAllSlaveChannels {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// gatherBinaryLogs can be used to collect size and count of all binary files\n// binlogs metric requires the MySQL server to turn it on in configuration\nfunc gatherBinaryLogs(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\trows, err := db.Query(binaryLogsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\t// parse DSN and save host as a tag\n\ttags := map[string]string{\"server\": servtag}\n\tvar (\n\t\tsize      uint64\n\t\tcount     uint64\n\t\tfileSize  uint64\n\t\tfileName  string\n\t\tencrypted string\n\t\talgorithm string\n\t)\n\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn err\n\t}\n\tnumColumns := len(columns)\n\n\t// iterate over rows and count the size and count of files\n\tfor rows.Next() {\n\t\tswitch numColumns {\n\t\tcase 3:\n\t\t\tif err := rows.Scan(&fileName, &fileSize, &encrypted); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase 4: // Compatible with versions that include encryption algorithms.\n\t\t\tif err := rows.Scan(&fileName, &fileSize, &encrypted, &algorithm); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := rows.Scan(&fileName, &fileSize); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tsize += fileSize\n\t\tcount++\n\t}\n\tfields := map[string]interface{}{\n\t\t\"binary_size_bytes\":  size,\n\t\t\"binary_files_count\": count,\n\t}\n\n\tacc.AddFields(\"mysql\", fields, tags)\n\treturn nil\n}\n\n// gatherGlobalStatuses can be used to get MySQL status metrics\n// the mappings of actual names and names of each status to be exported\n// to output is provided on mappings variable\nfunc (m *Mysql) gatherGlobalStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\trows, err := db.Query(globalStatusQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\t// parse the DSN and save host name as a tag\n\ttags := map[string]string{\"server\": servtag}\n\tfields := make(map[string]interface{})\n\tfor rows.Next() {\n\t\tvar key string\n\t\tvar val sql.RawBytes\n\n\t\tif err := rows.Scan(&key, &val); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif m.MetricVersion < 2 {\n\t\t\tvar found bool\n\t\t\tfor _, mapped := range v1.Mappings {\n\t\t\t\tif strings.HasPrefix(key, mapped.OnServer) {\n\t\t\t\t\t// convert numeric values to integer\n\t\t\t\t\tvar i int\n\t\t\t\t\tv := string(val)\n\t\t\t\t\tswitch v {\n\t\t\t\t\tcase \"ON\", \"true\":\n\t\t\t\t\t\ti = 1\n\t\t\t\t\tcase \"OFF\", \"false\":\n\t\t\t\t\t\ti = 0\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif i, err = strconv.Atoi(v); err != nil {\n\t\t\t\t\t\t\t// Make the value a <nil> value to prevent adding\n\t\t\t\t\t\t\t// the field containing nonsense values.\n\t\t\t\t\t\t\ti = 0\n\t\t\t\t\t\t\tif !m.loggedConvertFields[key] {\n\t\t\t\t\t\t\t\tm.Log.Warnf(\"Cannot convert value %q for key %q to integer outputting zero...\", v, key)\n\t\t\t\t\t\t\t\tm.loggedConvertFields[key] = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfields[mapped.InExport+key[len(mapped.OnServer):]] = i\n\t\t\t\t\tfound = true\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Send 20 fields at a time\n\t\t\tif len(fields) >= 20 {\n\t\t\t\tacc.AddFields(\"mysql\", fields, tags)\n\t\t\t\tfields = make(map[string]interface{})\n\t\t\t}\n\t\t\tif found {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// search for specific values\n\t\t\tswitch key {\n\t\t\tcase \"Queries\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"queries\"] = i\n\t\t\t\t}\n\t\t\tcase \"Questions\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"questions\"] = i\n\t\t\t\t}\n\t\t\tcase \"Slow_queries\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"slow_queries\"] = i\n\t\t\t\t}\n\t\t\tcase \"Connections\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"connections\"] = i\n\t\t\t\t}\n\t\t\tcase \"Syncs\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"syncs\"] = i\n\t\t\t\t}\n\t\t\tcase \"Uptime\":\n\t\t\t\ti, err := strconv.ParseInt(string(val), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql %q int value: %w\", key, err))\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"uptime\"] = i\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tkey = strings.ToLower(key)\n\t\t\tvalue, err := v2.ConvertGlobalStatus(key, val)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql global status %q=%q: %w\", key, string(val), err))\n\t\t\t} else {\n\t\t\t\t// v2.ConvertGlobalStatus can parse \"complex\" multi-value fields, e.g. wsrep_evs_repl_latency\n\t\t\t\tparseKeyValues(fields, key, value)\n\t\t\t}\n\t\t}\n\n\t\t// Send 20 fields at a time\n\t\tif len(fields) >= 20 {\n\t\t\tacc.AddFields(\"mysql\", fields, tags)\n\t\t\tfields = make(map[string]interface{})\n\t\t}\n\t}\n\t// Send any remaining fields\n\tif len(fields) > 0 {\n\t\tacc.AddFields(\"mysql\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// GatherProcessList can be used to collect metrics on each running command\n// and its state with its running count\nfunc (m *Mysql) gatherProcessListStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\trows, err := db.Query(infoSchemaProcessListQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\tcommand string\n\t\tstate   string\n\t\tcount   uint32\n\t)\n\n\tfields := make(map[string]interface{})\n\n\t// mapping of state with its counts\n\tstateCounts := make(map[string]uint32, len(generalThreadStates))\n\t// set map with keys and default values\n\tfor k, v := range generalThreadStates {\n\t\tstateCounts[k] = v\n\t}\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(&command, &state, &count)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// each state has its mapping\n\t\tfoundState := findThreadState(command, state)\n\t\t// count each state\n\t\tstateCounts[foundState] += count\n\t}\n\n\ttags := map[string]string{\"server\": servtag}\n\tfor s, c := range stateCounts {\n\t\tfields[newNamespace(\"threads\", s)] = c\n\t}\n\tif m.MetricVersion < 2 {\n\t\tacc.AddFields(\"mysql_info_schema\", fields, tags)\n\t} else {\n\t\tacc.AddFields(\"mysql_process_list\", fields, tags)\n\t}\n\n\t// get count of connections from each user\n\tconnRows, err := db.Query(\"SELECT user, sum(1) AS connections FROM INFORMATION_SCHEMA.PROCESSLIST GROUP BY user\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer connRows.Close()\n\n\tfor connRows.Next() {\n\t\tvar user string\n\t\tvar connections int64\n\n\t\terr = connRows.Scan(&user, &connections)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\"server\": servtag, \"user\": user}\n\t\tfields := make(map[string]interface{})\n\n\t\tfields[\"connections\"] = connections\n\t\tacc.AddFields(\"mysql_users\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// GatherUserStatisticsStatuses can be used to collect metrics on each running command\n// and its state with its running count\nfunc (m *Mysql) gatherUserStatisticsStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// run query\n\trows, err := db.Query(infoSchemaUserStatisticsQuery)\n\tif err != nil {\n\t\t// disable collecting if table is not found (mysql specific error)\n\t\t// (suppresses repeat errors)\n\t\tif strings.Contains(err.Error(), \"nknown table 'user_statistics'\") {\n\t\t\tm.GatherUserStatistics = false\n\t\t}\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tcols, err := columnsToLower(rows.Columns())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tread, err := getColSlice(rows)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(read...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\"server\": servtag, \"user\": *read[0].(*string)}\n\t\tfields := make(map[string]interface{}, len(cols))\n\n\t\tfor i := range cols {\n\t\t\tif i == 0 {\n\t\t\t\tcontinue // skip \"user\"\n\t\t\t}\n\t\t\tswitch v := read[i].(type) {\n\t\t\tcase *int64:\n\t\t\t\tfields[cols[i]] = *v\n\t\t\tcase *float64:\n\t\t\t\tfields[cols[i]] = *v\n\t\t\tcase *string:\n\t\t\t\tfields[cols[i]] = *v\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown column type - %T\", v)\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"mysql_user_stats\", fields, tags)\n\t}\n\treturn nil\n}\n\n// parseKeyValues converts multi-value maps to a per-value entry in fields\nfunc parseKeyValues(fields map[string]interface{}, key string, value interface{}) {\n\tif valueToMap, ok := value.(map[string]interface{}); ok {\n\t\tfor mapKey, mapValue := range valueToMap {\n\t\t\tfields[key+\"_\"+mapKey] = mapValue\n\t\t}\n\t} else {\n\t\tfields[key] = value\n\t}\n}\n\n// columnsToLower converts selected column names to lowercase.\nfunc columnsToLower(s []string, e error) ([]string, error) {\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\td := make([]string, len(s))\n\n\tfor i := range s {\n\t\td[i] = strings.ToLower(s[i])\n\t}\n\treturn d, nil\n}\n\n// getColSlice returns an in interface slice that can be used in the row.Scan().\nfunc getColSlice(rows *sql.Rows) ([]interface{}, error) {\n\tcolumnTypes, err := rows.ColumnTypes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tl := len(columnTypes)\n\n\t// list of all possible column names\n\tvar (\n\t\tuser                     string\n\t\ttotalConnections         int64\n\t\tconcurrentConnections    int64\n\t\tconnectedTime            int64\n\t\tbusyTime                 int64\n\t\tcpuTime                  int64\n\t\tbytesReceived            int64\n\t\tbytesSent                int64\n\t\tbinlogBytesWritten       int64\n\t\trowsRead                 int64\n\t\trowsSent                 int64\n\t\trowsDeleted              int64\n\t\trowsInserted             int64\n\t\trowsUpdated              int64\n\t\tselectCommands           int64\n\t\tupdateCommands           int64\n\t\totherCommands            int64\n\t\tcommitTransactions       int64\n\t\trollbackTransactions     int64\n\t\tdeniedConnections        int64\n\t\tlostConnections          int64\n\t\taccessDenied             int64\n\t\temptyQueries             int64\n\t\ttotalSslConnections      int64\n\t\tmaxStatementTimeExceeded int64\n\t\t// maria specific\n\t\tfbusyTime float64\n\t\tfcpuTime  float64\n\t\t// percona specific\n\t\trowsFetched   int64\n\t\ttableRowsRead int64\n\t)\n\n\tswitch l {\n\tcase 23: // maria5\n\t\treturn []interface{}{\n\t\t\t&user,\n\t\t\t&totalConnections,\n\t\t\t&concurrentConnections,\n\t\t\t&connectedTime,\n\t\t\t&fbusyTime,\n\t\t\t&fcpuTime,\n\t\t\t&bytesReceived,\n\t\t\t&bytesSent,\n\t\t\t&binlogBytesWritten,\n\t\t\t&rowsRead,\n\t\t\t&rowsSent,\n\t\t\t&rowsDeleted,\n\t\t\t&rowsInserted,\n\t\t\t&rowsUpdated,\n\t\t\t&selectCommands,\n\t\t\t&updateCommands,\n\t\t\t&otherCommands,\n\t\t\t&commitTransactions,\n\t\t\t&rollbackTransactions,\n\t\t\t&deniedConnections,\n\t\t\t&lostConnections,\n\t\t\t&accessDenied,\n\t\t\t&emptyQueries,\n\t\t}, nil\n\tcase 25: // maria10\n\t\treturn []interface{}{\n\t\t\t&user,\n\t\t\t&totalConnections,\n\t\t\t&concurrentConnections,\n\t\t\t&connectedTime,\n\t\t\t&fbusyTime,\n\t\t\t&fcpuTime,\n\t\t\t&bytesReceived,\n\t\t\t&bytesSent,\n\t\t\t&binlogBytesWritten,\n\t\t\t&rowsRead,\n\t\t\t&rowsSent,\n\t\t\t&rowsDeleted,\n\t\t\t&rowsInserted,\n\t\t\t&rowsUpdated,\n\t\t\t&selectCommands,\n\t\t\t&updateCommands,\n\t\t\t&otherCommands,\n\t\t\t&commitTransactions,\n\t\t\t&rollbackTransactions,\n\t\t\t&deniedConnections,\n\t\t\t&lostConnections,\n\t\t\t&accessDenied,\n\t\t\t&emptyQueries,\n\t\t\t&totalSslConnections,\n\t\t\t&maxStatementTimeExceeded,\n\t\t}, nil\n\tcase 21: // mysql 5.5\n\t\treturn []interface{}{\n\t\t\t&user,\n\t\t\t&totalConnections,\n\t\t\t&concurrentConnections,\n\t\t\t&connectedTime,\n\t\t\t&busyTime,\n\t\t\t&cpuTime,\n\t\t\t&bytesReceived,\n\t\t\t&bytesSent,\n\t\t\t&binlogBytesWritten,\n\t\t\t&rowsFetched,\n\t\t\t&rowsUpdated,\n\t\t\t&tableRowsRead,\n\t\t\t&selectCommands,\n\t\t\t&updateCommands,\n\t\t\t&otherCommands,\n\t\t\t&commitTransactions,\n\t\t\t&rollbackTransactions,\n\t\t\t&deniedConnections,\n\t\t\t&lostConnections,\n\t\t\t&accessDenied,\n\t\t\t&emptyQueries,\n\t\t}, nil\n\tcase 22: // percona\n\t\tcols := make([]interface{}, 0, 22)\n\t\tfor i, ct := range columnTypes {\n\t\t\t// The first column is the user and has to be a string\n\t\t\tif i == 0 {\n\t\t\t\tcols = append(cols, new(string))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Percona 8 has some special fields that are float instead of ints\n\t\t\t// see: https://github.com/influxdata/telegraf/issues/7360\n\t\t\tswitch ct.ScanType().Kind() {\n\t\t\tcase reflect.Float32, reflect.Float64:\n\t\t\t\tcols = append(cols, new(float64))\n\t\t\tdefault:\n\t\t\t\t// Keep old type for backward compatibility\n\t\t\t\tcols = append(cols, new(int64))\n\t\t\t}\n\t\t}\n\n\t\treturn cols, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"not Supported - %d columns\", l)\n}\n\n// gatherPerfTableIOWaits can be used to get total count and time of I/O wait event for each table and process\nfunc gatherPerfTableIOWaits(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(perfTableIOWaitsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rows.Close()\n\tvar (\n\t\tobjSchema, objName                                string\n\t\tcountFetch, countInsert, countUpdate, countDelete float64\n\t\ttimeFetch, timeInsert, timeUpdate, timeDelete     float64\n\t)\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(&objSchema, &objName,\n\t\t\t&countFetch, &countInsert, &countUpdate, &countDelete,\n\t\t\t&timeFetch, &timeInsert, &timeUpdate, &timeDelete,\n\t\t)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"server\": servtag,\n\t\t\t\"schema\": objSchema,\n\t\t\t\"name\":   objName,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"table_io_waits_total_fetch\":          countFetch,\n\t\t\t\"table_io_waits_total_insert\":         countInsert,\n\t\t\t\"table_io_waits_total_update\":         countUpdate,\n\t\t\t\"table_io_waits_total_delete\":         countDelete,\n\t\t\t\"table_io_waits_seconds_total_fetch\":  timeFetch / picoSeconds,\n\t\t\t\"table_io_waits_seconds_total_insert\": timeInsert / picoSeconds,\n\t\t\t\"table_io_waits_seconds_total_update\": timeUpdate / picoSeconds,\n\t\t\t\"table_io_waits_seconds_total_delete\": timeDelete / picoSeconds,\n\t\t}\n\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherPerfIndexIOWaits can be used to get total count and time of I/O wait event for each index and process\nfunc gatherPerfIndexIOWaits(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(perfIndexIOWaitsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\tobjSchema, objName, indexName                     string\n\t\tcountFetch, countInsert, countUpdate, countDelete float64\n\t\ttimeFetch, timeInsert, timeUpdate, timeDelete     float64\n\t)\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(&objSchema, &objName, &indexName,\n\t\t\t&countFetch, &countInsert, &countUpdate, &countDelete,\n\t\t\t&timeFetch, &timeInsert, &timeUpdate, &timeDelete,\n\t\t)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"server\": servtag,\n\t\t\t\"schema\": objSchema,\n\t\t\t\"name\":   objName,\n\t\t\t\"index\":  indexName,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"index_io_waits_total_fetch\":         countFetch,\n\t\t\t\"index_io_waits_seconds_total_fetch\": timeFetch / picoSeconds,\n\t\t}\n\n\t\t// update write columns only when index is NONE\n\t\tif indexName == \"NONE\" {\n\t\t\tfields[\"index_io_waits_total_insert\"] = countInsert\n\t\t\tfields[\"index_io_waits_total_update\"] = countUpdate\n\t\t\tfields[\"index_io_waits_total_delete\"] = countDelete\n\n\t\t\tfields[\"index_io_waits_seconds_total_insert\"] = timeInsert / picoSeconds\n\t\t\tfields[\"index_io_waits_seconds_total_update\"] = timeUpdate / picoSeconds\n\t\t\tfields[\"index_io_waits_seconds_total_delete\"] = timeDelete / picoSeconds\n\t\t}\n\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherInfoSchemaAutoIncStatuses can be used to get auto incremented values of the column\nfunc (m *Mysql) gatherInfoSchemaAutoIncStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(infoSchemaAutoIncQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\tschema, table, column string\n\t\tincValue, maxInt      uint64\n\t)\n\n\tfor rows.Next() {\n\t\tif err := rows.Scan(&schema, &table, &column, &incValue, &maxInt); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"server\": servtag,\n\t\t\t\"schema\": schema,\n\t\t\t\"table\":  table,\n\t\t\t\"column\": column,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"auto_increment_column\"] = incValue\n\t\tfields[\"auto_increment_column_max\"] = maxInt\n\n\t\tif m.MetricVersion < 2 {\n\t\t\tacc.AddFields(\"mysql_info_schema\", fields, tags)\n\t\t} else {\n\t\t\tacc.AddFields(\"mysql_table_schema\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherInnoDBMetrics can be used to fetch enabled metrics from\n// information_schema.INNODB_METRICS\nfunc (m *Mysql) gatherInnoDBMetrics(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\tvar (\n\t\tquery string\n\t)\n\n\tif m.MariadbDialect {\n\t\tquery = innoDBMetricsQueryMariadb\n\t} else {\n\t\tquery = innoDBMetricsQuery\n\t}\n\n\t// run query\n\trows, err := db.Query(query)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\t// parse DSN and save server tag\n\ttags := map[string]string{\"server\": servtag}\n\tfields := make(map[string]interface{})\n\tfor rows.Next() {\n\t\tvar key string\n\t\tvar val sql.RawBytes\n\t\tif err := rows.Scan(&key, &val); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tkey = strings.ToLower(key)\n\t\tvalue, err := m.parseValueByDatabaseTypeName(val, \"BIGINT\")\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error parsing mysql InnoDB metric %q=%q: %w\", key, string(val), err))\n\t\t\tcontinue\n\t\t}\n\n\t\tfields[key] = value\n\n\t\t// Send 20 fields at a time\n\t\tif len(fields) >= 20 {\n\t\t\tacc.AddFields(\"mysql_innodb\", fields, tags)\n\t\t\tfields = make(map[string]interface{})\n\t\t}\n\t}\n\t// Send any remaining fields\n\tif len(fields) > 0 {\n\t\tacc.AddFields(\"mysql_innodb\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherPerfSummaryPerAccountPerEvent can be used to fetch enabled metrics from\n// performance_schema.events_statements_summary_by_account_by_event_name\nfunc (m *Mysql) gatherPerfSummaryPerAccountPerEvent(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\tvar rows *sql.Rows\n\tvar err error\n\n\tvar (\n\t\tsrcUser                 string\n\t\tsrcHost                 string\n\t\teventName               string\n\t\tcountStar               float64\n\t\tsumTimerWait            float64\n\t\tminTimerWait            float64\n\t\tavgTimerWait            float64\n\t\tmaxTimerWait            float64\n\t\tsumLockTime             float64\n\t\tsumErrors               float64\n\t\tsumWarnings             float64\n\t\tsumRowsAffected         float64\n\t\tsumRowsSent             float64\n\t\tsumRowsExamined         float64\n\t\tsumCreatedTmpDiskTables float64\n\t\tsumCreatedTmpTables     float64\n\t\tsumSelectFullJoin       float64\n\t\tsumSelectFullRangeJoin  float64\n\t\tsumSelectRange          float64\n\t\tsumSelectRangeCheck     float64\n\t\tsumSelectScan           float64\n\t\tsumSortMergePasses      float64\n\t\tsumSortRange            float64\n\t\tsumSortRows             float64\n\t\tsumSortScan             float64\n\t\tsumNoIndexUsed          float64\n\t\tsumNoGoodIndexUsed      float64\n\t)\n\n\tvar events []interface{}\n\t// if we have perf_summary_events set - select only listed events (adding filter criteria for rows)\n\tif len(m.PerfSummaryEvents) > 0 {\n\t\tvar sqlQueryBuilder strings.Builder\n\t\tsqlQueryBuilder.WriteString(perfSummaryPerAccountPerEvent)\n\t\tsqlQueryBuilder.WriteString(\" WHERE EVENT_NAME IN (\")\n\t\tfor i, eventName := range m.PerfSummaryEvents {\n\t\t\tif i > 0 {\n\t\t\t\tsqlQueryBuilder.WriteString(\", \")\n\t\t\t}\n\t\t\tsqlQueryBuilder.WriteString(\"?\")\n\t\t\tevents = append(events, eventName)\n\t\t}\n\t\tsqlQueryBuilder.WriteString(\")\")\n\n\t\trows, err = db.Query(sqlQueryBuilder.String(), events...)\n\t} else {\n\t\t// otherwise no filter, hence, select all rows\n\t\trows, err = db.Query(perfSummaryPerAccountPerEvent)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\t// parse DSN and save server tag\n\ttags := map[string]string{\"server\": servtag}\n\tfor rows.Next() {\n\t\tif err := rows.Scan(\n\t\t\t&srcUser,\n\t\t\t&srcHost,\n\t\t\t&eventName,\n\t\t\t&countStar,\n\t\t\t&sumTimerWait,\n\t\t\t&minTimerWait,\n\t\t\t&avgTimerWait,\n\t\t\t&maxTimerWait,\n\t\t\t&sumLockTime,\n\t\t\t&sumErrors,\n\t\t\t&sumWarnings,\n\t\t\t&sumRowsAffected,\n\t\t\t&sumRowsSent,\n\t\t\t&sumRowsExamined,\n\t\t\t&sumCreatedTmpDiskTables,\n\t\t\t&sumCreatedTmpTables,\n\t\t\t&sumSelectFullJoin,\n\t\t\t&sumSelectFullRangeJoin,\n\t\t\t&sumSelectRange,\n\t\t\t&sumSelectRangeCheck,\n\t\t\t&sumSelectScan,\n\t\t\t&sumSortMergePasses,\n\t\t\t&sumSortRange,\n\t\t\t&sumSortRows,\n\t\t\t&sumSortScan,\n\t\t\t&sumNoIndexUsed,\n\t\t\t&sumNoGoodIndexUsed,\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsrcUser = strings.ToLower(srcUser)\n\t\tsrcHost = strings.ToLower(srcHost)\n\n\t\tsqlLWTags := copyTags(tags)\n\t\tsqlLWTags[\"src_user\"] = srcUser\n\t\tsqlLWTags[\"src_host\"] = srcHost\n\t\tsqlLWTags[\"event\"] = eventName\n\t\tsqlLWFields := map[string]interface{}{\n\t\t\t\"count_star\":                  countStar,\n\t\t\t\"sum_timer_wait\":              sumTimerWait,\n\t\t\t\"min_timer_wait\":              minTimerWait,\n\t\t\t\"avg_timer_wait\":              avgTimerWait,\n\t\t\t\"max_timer_wait\":              maxTimerWait,\n\t\t\t\"sum_lock_time\":               sumLockTime,\n\t\t\t\"sum_errors\":                  sumErrors,\n\t\t\t\"sum_warnings\":                sumWarnings,\n\t\t\t\"sum_rows_affected\":           sumRowsAffected,\n\t\t\t\"sum_rows_sent\":               sumRowsSent,\n\t\t\t\"sum_rows_examined\":           sumRowsExamined,\n\t\t\t\"sum_created_tmp_disk_tables\": sumCreatedTmpDiskTables,\n\t\t\t\"sum_created_tmp_tables\":      sumCreatedTmpTables,\n\t\t\t\"sum_select_full_join\":        sumSelectFullJoin,\n\t\t\t\"sum_select_full_range_join\":  sumSelectFullRangeJoin,\n\t\t\t\"sum_select_range\":            sumSelectRange,\n\t\t\t\"sum_select_range_check\":      sumSelectRangeCheck,\n\t\t\t\"sum_select_scan\":             sumSelectScan,\n\t\t\t\"sum_sort_merge_passes\":       sumSortMergePasses,\n\t\t\t\"sum_sort_range\":              sumSortRange,\n\t\t\t\"sum_sort_rows\":               sumSortRows,\n\t\t\t\"sum_sort_scan\":               sumSortScan,\n\t\t\t\"sum_no_index_used\":           sumNoIndexUsed,\n\t\t\t\"sum_no_good_index_used\":      sumNoGoodIndexUsed,\n\t\t}\n\t\tacc.AddFields(\"mysql_perf_acc_event\", sqlLWFields, sqlLWTags)\n\t}\n\n\treturn nil\n}\n\n// gatherPerfTableLockWaits can be used to get\n// the total number and time for SQL and external lock wait events\n// for each table and operation\n// requires the MySQL server to be enabled to save this metric\nfunc gatherPerfTableLockWaits(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\t// check if table exists,\n\t// if performance_schema is not enabled, tables do not exist\n\t// then there is no need to scan them\n\tvar tableName string\n\terr := db.QueryRow(perfSchemaTablesQuery, \"table_lock_waits_summary_by_table\").Scan(&tableName)\n\tswitch {\n\tcase errors.Is(err, sql.ErrNoRows):\n\t\treturn nil\n\tcase err != nil:\n\t\treturn err\n\t}\n\n\trows, err := db.Query(perfTableLockWaitsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\tobjectSchema               string\n\t\tobjectName                 string\n\t\tcountReadNormal            float64\n\t\tcountReadWithSharedLocks   float64\n\t\tcountReadHighPriority      float64\n\t\tcountReadNoInsert          float64\n\t\tcountReadExternal          float64\n\t\tcountWriteAllowWrite       float64\n\t\tcountWriteConcurrentInsert float64\n\t\tcountWriteLowPriority      float64\n\t\tcountWriteNormal           float64\n\t\tcountWriteExternal         float64\n\t\ttimeReadNormal             float64\n\t\ttimeReadWithSharedLocks    float64\n\t\ttimeReadHighPriority       float64\n\t\ttimeReadNoInsert           float64\n\t\ttimeReadExternal           float64\n\t\ttimeWriteAllowWrite        float64\n\t\ttimeWriteConcurrentInsert  float64\n\t\ttimeWriteLowPriority       float64\n\t\ttimeWriteNormal            float64\n\t\ttimeWriteExternal          float64\n\t)\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(\n\t\t\t&objectSchema,\n\t\t\t&objectName,\n\t\t\t&countReadNormal,\n\t\t\t&countReadWithSharedLocks,\n\t\t\t&countReadHighPriority,\n\t\t\t&countReadNoInsert,\n\t\t\t&countReadExternal,\n\t\t\t&countWriteAllowWrite,\n\t\t\t&countWriteConcurrentInsert,\n\t\t\t&countWriteLowPriority,\n\t\t\t&countWriteNormal,\n\t\t\t&countWriteExternal,\n\t\t\t&timeReadNormal,\n\t\t\t&timeReadWithSharedLocks,\n\t\t\t&timeReadHighPriority,\n\t\t\t&timeReadNoInsert,\n\t\t\t&timeReadExternal,\n\t\t\t&timeWriteAllowWrite,\n\t\t\t&timeWriteConcurrentInsert,\n\t\t\t&timeWriteLowPriority,\n\t\t\t&timeWriteNormal,\n\t\t\t&timeWriteExternal,\n\t\t)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"server\": servtag,\n\t\t\t\"schema\": objectSchema,\n\t\t\t\"table\":  objectName,\n\t\t}\n\n\t\tsqlLWTags := copyTags(tags)\n\t\tsqlLWTags[\"perf_query\"] = \"sql_lock_waits_total\"\n\t\tsqlLWFields := map[string]interface{}{\n\t\t\t\"read_normal\":             countReadNormal,\n\t\t\t\"read_with_shared_locks\":  countReadWithSharedLocks,\n\t\t\t\"read_high_priority\":      countReadHighPriority,\n\t\t\t\"read_no_insert\":          countReadNoInsert,\n\t\t\t\"write_normal\":            countWriteNormal,\n\t\t\t\"write_allow_write\":       countWriteAllowWrite,\n\t\t\t\"write_concurrent_insert\": countWriteConcurrentInsert,\n\t\t\t\"write_low_priority\":      countWriteLowPriority,\n\t\t}\n\t\tacc.AddFields(\"mysql_perf_schema\", sqlLWFields, sqlLWTags)\n\n\t\texternalLWTags := copyTags(tags)\n\t\texternalLWTags[\"perf_query\"] = \"external_lock_waits_total\"\n\t\texternalLWFields := map[string]interface{}{\n\t\t\t\"read\":  countReadExternal,\n\t\t\t\"write\": countWriteExternal,\n\t\t}\n\t\tacc.AddFields(\"mysql_perf_schema\", externalLWFields, externalLWTags)\n\n\t\tsqlLWSecTotalTags := copyTags(tags)\n\t\tsqlLWSecTotalTags[\"perf_query\"] = \"sql_lock_waits_seconds_total\"\n\t\tsqlLWSecTotalFields := map[string]interface{}{\n\t\t\t\"read_normal\":             timeReadNormal / picoSeconds,\n\t\t\t\"read_with_shared_locks\":  timeReadWithSharedLocks / picoSeconds,\n\t\t\t\"read_high_priority\":      timeReadHighPriority / picoSeconds,\n\t\t\t\"read_no_insert\":          timeReadNoInsert / picoSeconds,\n\t\t\t\"write_normal\":            timeWriteNormal / picoSeconds,\n\t\t\t\"write_allow_write\":       timeWriteAllowWrite / picoSeconds,\n\t\t\t\"write_concurrent_insert\": timeWriteConcurrentInsert / picoSeconds,\n\t\t\t\"write_low_priority\":      timeWriteLowPriority / picoSeconds,\n\t\t}\n\t\tacc.AddFields(\"mysql_perf_schema\", sqlLWSecTotalFields, sqlLWSecTotalTags)\n\n\t\texternalLWSecTotalTags := copyTags(tags)\n\t\texternalLWSecTotalTags[\"perf_query\"] = \"external_lock_waits_seconds_total\"\n\t\texternalLWSecTotalFields := map[string]interface{}{\n\t\t\t\"read\":  timeReadExternal / picoSeconds,\n\t\t\t\"write\": timeWriteExternal / picoSeconds,\n\t\t}\n\t\tacc.AddFields(\"mysql_perf_schema\", externalLWSecTotalFields, externalLWSecTotalTags)\n\t}\n\treturn nil\n}\n\n// gatherPerfEventWaits can be used to get total time and number of event waits\nfunc gatherPerfEventWaits(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(perfEventWaitsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\tevent               string\n\t\tstarCount, timeWait float64\n\t)\n\n\ttags := map[string]string{\n\t\t\"server\": servtag,\n\t}\n\tfor rows.Next() {\n\t\tif err := rows.Scan(&event, &starCount, &timeWait); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags[\"event_name\"] = event\n\t\tfields := map[string]interface{}{\n\t\t\t\"events_waits_total\":         starCount,\n\t\t\t\"events_waits_seconds_total\": timeWait / picoSeconds,\n\t\t}\n\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherPerfFileEvents can be used to get stats on file events\nfunc gatherPerfFileEventsStatuses(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(perfFileEventsQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rows.Close()\n\n\tvar (\n\t\teventName                                 string\n\t\tcountRead, countWrite, countMisc          float64\n\t\tsumTimerRead, sumTimerWrite, sumTimerMisc float64\n\t\tsumNumBytesRead, sumNumBytesWrite         float64\n\t)\n\n\ttags := map[string]string{\n\t\t\"server\": servtag,\n\t}\n\tfor rows.Next() {\n\t\terr = rows.Scan(\n\t\t\t&eventName,\n\t\t\t&countRead, &sumTimerRead, &sumNumBytesRead,\n\t\t\t&countWrite, &sumTimerWrite, &sumNumBytesWrite,\n\t\t\t&countMisc, &sumTimerMisc,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttags[\"event_name\"] = eventName\n\t\tfields := make(map[string]interface{})\n\n\t\tmiscTags := copyTags(tags)\n\t\tmiscTags[\"mode\"] = \"misc\"\n\t\tfields[\"file_events_total\"] = countWrite\n\t\tfields[\"file_events_seconds_total\"] = sumTimerMisc / picoSeconds\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, miscTags)\n\n\t\treadTags := copyTags(tags)\n\t\treadTags[\"mode\"] = \"read\"\n\t\tfields[\"file_events_total\"] = countRead\n\t\tfields[\"file_events_seconds_total\"] = sumTimerRead / picoSeconds\n\t\tfields[\"file_events_bytes_totals\"] = sumNumBytesRead\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, readTags)\n\n\t\twriteTags := copyTags(tags)\n\t\twriteTags[\"mode\"] = \"write\"\n\t\tfields[\"file_events_total\"] = countWrite\n\t\tfields[\"file_events_seconds_total\"] = sumTimerWrite / picoSeconds\n\t\tfields[\"file_events_bytes_totals\"] = sumNumBytesWrite\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, writeTags)\n\t}\n\n\treturn nil\n}\n\n// gatherPerfEventsStatements can be used to get attributes of each event\nfunc (m *Mysql) gatherPerfEventsStatements(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\tquery := fmt.Sprintf(\n\t\tperfEventsStatementsQuery,\n\t\tm.PerfEventsStatementsDigestTextLimit,\n\t\tm.PerfEventsStatementsTimeLimit,\n\t\tm.PerfEventsStatementsLimit,\n\t)\n\n\trows, err := db.Query(query)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rows.Close()\n\n\tvar (\n\t\tschemaName, digest, digestText       string\n\t\tcount, queryTime, errs, warnings     float64\n\t\trowsAffected, rowsSent, rowsExamined float64\n\t\ttmpTables, tmpDiskTables             float64\n\t\tsortMergePasses, sortRows            float64\n\t\tnoIndexUsed                          float64\n\t)\n\n\ttags := map[string]string{\n\t\t\"server\": servtag,\n\t}\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(\n\t\t\t&schemaName, &digest, &digestText,\n\t\t\t&count, &queryTime, &errs, &warnings,\n\t\t\t&rowsAffected, &rowsSent, &rowsExamined,\n\t\t\t&tmpTables, &tmpDiskTables,\n\t\t\t&sortMergePasses, &sortRows,\n\t\t\t&noIndexUsed,\n\t\t)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags[\"schema\"] = schemaName\n\t\ttags[\"digest\"] = digest\n\t\ttags[\"digest_text\"] = digestText\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"events_statements_total\":                   count,\n\t\t\t\"events_statements_seconds_total\":           queryTime / picoSeconds,\n\t\t\t\"events_statements_errors_total\":            errs,\n\t\t\t\"events_statements_warnings_total\":          warnings,\n\t\t\t\"events_statements_rows_affected_total\":     rowsAffected,\n\t\t\t\"events_statements_rows_sent_total\":         rowsSent,\n\t\t\t\"events_statements_rows_examined_total\":     rowsExamined,\n\t\t\t\"events_statements_tmp_tables_total\":        tmpTables,\n\t\t\t\"events_statements_tmp_disk_tables_total\":   tmpDiskTables,\n\t\t\t\"events_statements_sort_merge_passes_total\": sortMergePasses,\n\t\t\t\"events_statements_sort_rows_total\":         sortRows,\n\t\t\t\"events_statements_no_index_used_total\":     noIndexUsed,\n\t\t}\n\n\t\tacc.AddFields(\"mysql_perf_schema\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherTableSchema can be used to gather stats on each schema\nfunc (m *Mysql) gatherTableSchema(db *sql.DB, servtag string, acc telegraf.Accumulator) error {\n\tvar dbList []string\n\n\t// if the list of databases if empty, then get all databases\n\tif len(m.TableSchemaDatabases) == 0 {\n\t\trows, err := db.Query(dbListQuery)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer rows.Close()\n\n\t\tvar database string\n\t\tfor rows.Next() {\n\t\t\terr = rows.Scan(&database)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdbList = append(dbList, database)\n\t\t}\n\t} else {\n\t\tdbList = m.TableSchemaDatabases\n\t}\n\n\tfor _, database := range dbList {\n\t\terr := m.gatherSchemaForDB(db, database, servtag, acc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *Mysql) gatherSchemaForDB(db *sql.DB, database, servtag string, acc telegraf.Accumulator) error {\n\trows, err := db.Query(fmt.Sprintf(tableSchemaQuery, database))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tvar (\n\t\ttableSchema   string\n\t\ttableName     string\n\t\ttableType     string\n\t\tengine        string\n\t\tversion       float64\n\t\trowFormat     string\n\t\ttableRows     float64\n\t\tdataLength    float64\n\t\tindexLength   float64\n\t\tdataFree      float64\n\t\tcreateOptions string\n\t)\n\n\tfor rows.Next() {\n\t\terr = rows.Scan(\n\t\t\t&tableSchema,\n\t\t\t&tableName,\n\t\t\t&tableType,\n\t\t\t&engine,\n\t\t\t&version,\n\t\t\t&rowFormat,\n\t\t\t&tableRows,\n\t\t\t&dataLength,\n\t\t\t&indexLength,\n\t\t\t&dataFree,\n\t\t\t&createOptions,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags := map[string]string{\"server\": servtag}\n\t\ttags[\"schema\"] = tableSchema\n\t\ttags[\"table\"] = tableName\n\n\t\tif m.MetricVersion < 2 {\n\t\t\tacc.AddFields(newNamespace(\"info_schema\", \"table_rows\"),\n\t\t\t\tmap[string]interface{}{\"value\": tableRows}, tags)\n\n\t\t\tdlTags := copyTags(tags)\n\t\t\tdlTags[\"component\"] = \"data_length\"\n\t\t\tacc.AddFields(newNamespace(\"info_schema\", \"table_size\", \"data_length\"),\n\t\t\t\tmap[string]interface{}{\"value\": dataLength}, dlTags)\n\n\t\t\tilTags := copyTags(tags)\n\t\t\tilTags[\"component\"] = \"index_length\"\n\t\t\tacc.AddFields(newNamespace(\"info_schema\", \"table_size\", \"index_length\"),\n\t\t\t\tmap[string]interface{}{\"value\": indexLength}, ilTags)\n\n\t\t\tdfTags := copyTags(tags)\n\t\t\tdfTags[\"component\"] = \"data_free\"\n\t\t\tacc.AddFields(newNamespace(\"info_schema\", \"table_size\", \"data_free\"),\n\t\t\t\tmap[string]interface{}{\"value\": dataFree}, dfTags)\n\t\t} else {\n\t\t\tacc.AddFields(\"mysql_table_schema\",\n\t\t\t\tmap[string]interface{}{\"rows\": tableRows}, tags)\n\n\t\t\tacc.AddFields(\"mysql_table_schema\",\n\t\t\t\tmap[string]interface{}{\"data_length\": dataLength}, tags)\n\n\t\t\tacc.AddFields(\"mysql_table_schema\",\n\t\t\t\tmap[string]interface{}{\"index_length\": indexLength}, tags)\n\n\t\t\tacc.AddFields(\"mysql_table_schema\",\n\t\t\t\tmap[string]interface{}{\"data_free\": dataFree}, tags)\n\t\t}\n\n\t\tversionTags := copyTags(tags)\n\t\tversionTags[\"type\"] = tableType\n\t\tversionTags[\"engine\"] = engine\n\t\tversionTags[\"row_format\"] = rowFormat\n\t\tversionTags[\"create_options\"] = createOptions\n\n\t\tif m.MetricVersion < 2 {\n\t\t\tacc.AddFields(newNamespace(\"info_schema\", \"table_version\"),\n\t\t\t\tmap[string]interface{}{\"value\": version}, versionTags)\n\t\t} else {\n\t\t\tacc.AddFields(\"mysql_table_schema_version\",\n\t\t\t\tmap[string]interface{}{\"table_version\": version}, versionTags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *Mysql) parseValueByDatabaseTypeName(value sql.RawBytes, databaseTypeName string) (interface{}, error) {\n\tif m.MetricVersion < 2 {\n\t\treturn v1.ParseValue(value)\n\t}\n\n\tswitch databaseTypeName {\n\tcase \"INT\":\n\t\treturn v2.ParseInt(value)\n\tcase \"BIGINT\":\n\t\treturn v2.ParseUint(value)\n\tcase \"VARCHAR\":\n\t\treturn v2.ParseString(value)\n\tdefault:\n\t\tm.Log.Debugf(\"unknown database type name %q in parseValueByDatabaseTypeName\", databaseTypeName)\n\t\treturn v2.ParseValue(value)\n\t}\n}\n\n// findThreadState can be used to find thread state by command and plain state\nfunc findThreadState(rawCommand, rawState string) string {\n\tvar (\n\t\t// replace '_' symbol with space\n\t\tcommand = strings.ReplaceAll(strings.ToLower(rawCommand), \"_\", \" \")\n\t\tstate   = strings.ReplaceAll(strings.ToLower(rawState), \"_\", \" \")\n\t)\n\t// if the state is already valid, then return it\n\tif _, ok := generalThreadStates[state]; ok {\n\t\treturn state\n\t}\n\n\t// if state is plain, return the mapping\n\tif mappedState, ok := stateStatusMappings[state]; ok {\n\t\treturn mappedState\n\t}\n\t// if the state is any lock, return the special state\n\tif strings.Contains(state, \"waiting for\") && strings.Contains(state, \"lock\") {\n\t\treturn \"waiting for lock\"\n\t}\n\n\tif command == \"sleep\" && state == \"\" {\n\t\treturn \"idle\"\n\t}\n\n\tif command == \"query\" {\n\t\treturn \"executing\"\n\t}\n\n\tif command == \"binlog dump\" {\n\t\treturn \"replication master\"\n\t}\n\t// if no mappings found and state is invalid, then return \"other\" state\n\treturn \"other\"\n}\n\n// newNamespace can be used to make a namespace\nfunc newNamespace(words ...string) string {\n\treturn strings.ReplaceAll(strings.Join(words, \"_\"), \" \", \"_\")\n}\n\nfunc copyTags(in map[string]string) map[string]string {\n\tout := make(map[string]string)\n\tfor k, v := range in {\n\t\tout[k] = v\n\t}\n\treturn out\n}\n\nfunc getDSNTag(dsn string) string {\n\tconf, err := mysql.ParseDSN(dsn)\n\tif err != nil {\n\t\treturn \"127.0.0.1:3306\"\n\t}\n\treturn conf.Addr\n}\n\nfunc init() {\n\tinputs.Add(\"mysql\", func() telegraf.Input {\n\t\treturn &Mysql{\n\t\t\tPerfEventsStatementsDigestTextLimit: defaultPerfEventsStatementsDigestTextLimit,\n\t\t\tPerfEventsStatementsLimit:           defaultPerfEventsStatementsLimit,\n\t\t\tPerfEventsStatementsTimeLimit:       defaultPerfEventsStatementsTimeLimit,\n\t\t\tGatherGlobalVars:                    defaultGatherGlobalVars,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/mysql/mysql_test.go",
    "content": "package mysql\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst servicePort = \"3306\"\n\nfunc TestMysqlDefaultsToLocalIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage: \"mysql\",\n\t\tEnv: map[string]string{\n\t\t\t\"MYSQL_ALLOW_EMPTY_PASSWORD\": \"yes\",\n\t\t},\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"/usr/sbin/mysqld: ready for connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\tdsn := fmt.Sprintf(\"root@tcp(%s:%s)/\", container.Address, container.Ports[servicePort])\n\ts := config.NewSecret([]byte(dsn))\n\tdefer s.Destroy()\n\tm := &Mysql{\n\t\tServers: []*config.Secret{&s},\n\t\tLog:     &testutil.Logger{},\n\t}\n\trequire.NoError(t, m.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, m.Gather(&acc))\n\trequire.Empty(t, acc.Errors)\n\n\trequire.True(t, acc.HasMeasurement(\"mysql\"))\n}\n\nfunc TestMysqlMultipleInstancesIntegration(t *testing.T) {\n\t// Invoke Gather() from two separate configurations and\n\t//  confirm they don't interfere with each other\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage: \"mysql\",\n\t\tEnv: map[string]string{\n\t\t\t\"MYSQL_ALLOW_EMPTY_PASSWORD\": \"yes\",\n\t\t},\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"/usr/sbin/mysqld: ready for connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\tdsn := fmt.Sprintf(\"root@tcp(%s:%s)/?tls=false\", container.Address, container.Ports[servicePort])\n\ts := config.NewSecret([]byte(dsn))\n\tdefer s.Destroy()\n\tm := &Mysql{\n\t\tServers:          []*config.Secret{&s},\n\t\tIntervalSlow:     config.Duration(30 * time.Second),\n\t\tGatherGlobalVars: true,\n\t\tMetricVersion:    2,\n\t\tLog:              &testutil.Logger{},\n\t}\n\trequire.NoError(t, m.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, m.Gather(&acc))\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasMeasurement(\"mysql\"))\n\t// acc should have global variables\n\trequire.True(t, acc.HasMeasurement(\"mysql_variables\"))\n\n\ts2 := config.NewSecret([]byte(dsn))\n\tm2 := &Mysql{\n\t\tServers:       []*config.Secret{&s2},\n\t\tMetricVersion: 2,\n\t\tLog:           &testutil.Logger{},\n\t}\n\trequire.NoError(t, m2.Init())\n\n\tvar acc2 testutil.Accumulator\n\trequire.NoError(t, m2.Gather(&acc2))\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc2.HasMeasurement(\"mysql\"))\n\t// acc2 should not have global variables\n\trequire.False(t, acc2.HasMeasurement(\"mysql_variables\"))\n}\n\nfunc TestPercona8Integration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage: \"percona:8\",\n\t\tEnv: map[string]string{\n\t\t\t\"MYSQL_ROOT_PASSWORD\": \"secret\",\n\t\t},\n\t\tCmd:          []string{\"--userstat=ON\"},\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"/usr/sbin/mysqld: ready for connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\tdsn := fmt.Sprintf(\"root:secret@tcp(%s:%s)/\", container.Address, container.Ports[servicePort])\n\ts := config.NewSecret([]byte(dsn))\n\tdefer s.Destroy()\n\tplugin := &Mysql{\n\t\tServers:              []*config.Secret{&s},\n\t\tGatherUserStatistics: true,\n\t\tLog:                  &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasMeasurement(\"mysql_user_stats\"))\n\trequire.True(t, acc.HasFloatField(\"mysql_user_stats\", \"connected_time\"))\n\trequire.True(t, acc.HasFloatField(\"mysql_user_stats\", \"cpu_time\"))\n\trequire.True(t, acc.HasFloatField(\"mysql_user_stats\", \"busy_time\"))\n}\n\nfunc TestGaleraIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/mariadb-galera\",\n\t\tEnv:          map[string]string{\"ALLOW_EMPTY_PASSWORD\": \"yes\"},\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"Synchronized with group, ready for connections\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\tdsn := fmt.Sprintf(\"root@tcp(%s:%s)/\", container.Address, container.Ports[servicePort])\n\ts := config.NewSecret([]byte(dsn))\n\tdefer s.Destroy()\n\tplugin := &Mysql{\n\t\tServers: []*config.Secret{&s},\n\t\tLog:     &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.Errors)\n\trequire.True(t, acc.HasIntField(\"mysql\", \"wsrep_ready\"))\n\tfor _, m := range acc.GetTelegrafMetrics() {\n\t\tif v, found := m.GetField(\"wsrep_ready\"); found {\n\t\t\trequire.EqualValues(t, 1, v, \"invalid value for field wsrep_ready\")\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc TestMysqlGetDSNTag(t *testing.T) {\n\ttests := []struct {\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t{\n\t\t\t\"\",\n\t\t\t\"127.0.0.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"localhost\",\n\t\t\t\"127.0.0.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"127.0.0.1\",\n\t\t\t\"127.0.0.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"tcp(192.168.1.1:3306)/\",\n\t\t\t\"192.168.1.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"tcp(localhost)/\",\n\t\t\t\"localhost:3306\",\n\t\t},\n\t\t{\n\t\t\t\"root:passwd@tcp(192.168.1.1:3306)/?tls=false\",\n\t\t\t\"192.168.1.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"root@tcp(127.0.0.1:3306)/?tls=false\",\n\t\t\t\"127.0.0.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"root:passwd@tcp(localhost:3036)/dbname?allowOldPasswords=1\",\n\t\t\t\"localhost:3036\",\n\t\t},\n\t\t{\n\t\t\t\"root:foo@bar@tcp(192.1.1.1:3306)/?tls=false\",\n\t\t\t\"192.1.1.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"root:f00@b4r@tcp(192.1.1.1:3306)/?tls=false\",\n\t\t\t\"192.1.1.1:3306\",\n\t\t},\n\t\t{\n\t\t\t\"root:fl!p11@tcp(192.1.1.1:3306)/?tls=false\",\n\t\t\t\"192.1.1.1:3306\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\toutput := getDSNTag(test.input)\n\t\tif output != test.output {\n\t\t\tt.Errorf(\"Input: %s Expected %s, got %s\\n\", test.input, test.output, output)\n\t\t}\n\t}\n}\n\nfunc TestMysqlDNSAddTimeout(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t{\n\t\t\t\"empty\",\n\t\t\t\"\",\n\t\t\t\"tcp(127.0.0.1:3306)/?timeout=5s\",\n\t\t},\n\t\t{\n\t\t\t\"no timeout\",\n\t\t\t\"tcp(192.168.1.1:3306)/\",\n\t\t\t\"tcp(192.168.1.1:3306)/?timeout=5s\",\n\t\t},\n\t\t{\n\t\t\t\"no timeout with credentials\",\n\t\t\t\"root:passwd@tcp(192.168.1.1:3306)/?tls=false\",\n\t\t\t\"root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=false\",\n\t\t},\n\t\t{\n\t\t\t\"with timeout and credentials\",\n\t\t\t\"root:passwd@tcp(192.168.1.1:3306)/?tls=false&timeout=10s\",\n\t\t\t\"root:passwd@tcp(192.168.1.1:3306)/?timeout=10s&tls=false\",\n\t\t},\n\t\t{\n\t\t\t\"no timeout different IP\",\n\t\t\t\"tcp(10.150.1.123:3306)/\",\n\t\t\t\"tcp(10.150.1.123:3306)/?timeout=5s\",\n\t\t},\n\t\t{\n\t\t\t\"no timeout with bracket credentials\",\n\t\t\t\"root:@!~(*&$#%(&@#(@&#Password@tcp(10.150.1.123:3306)/\",\n\t\t\t\"root:@!~(*&$#%(&@#(@&#Password@tcp(10.150.1.123:3306)/?timeout=5s\",\n\t\t},\n\t\t{\n\t\t\t\"no timeout with strange credentials\",\n\t\t\t\"root:Test3a#@!@tcp(10.150.1.123:3306)/\",\n\t\t\t\"root:Test3a#@!@tcp(10.150.1.123:3306)/?timeout=5s\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ts := config.NewSecret([]byte(tt.input))\n\t\t\tm := &Mysql{\n\t\t\t\tServers: []*config.Secret{&s},\n\t\t\t}\n\t\t\trequire.NoError(t, m.Init())\n\t\t\trequire.Len(t, m.Servers, 1)\n\t\t\tdsn, err := m.Servers[0].Get()\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer dsn.Destroy()\n\t\t\trequire.Equal(t, tt.output, dsn.TemporaryString())\n\t\t})\n\t}\n}\n\nfunc TestMysqlTLSCustomization(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t\terrmsg   string\n\t}{\n\t\t{\n\t\t\tname:     \"custom only param\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=custom-<id>\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom start param\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom&timeout=20s\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom end param\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>\",\n\t\t},\n\t\t{\n\t\t\tname:     \"custom middle param\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom&foo=bar\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>&foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param false\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=false\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=false\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param true\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=true\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=true\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param skip-verify\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=skip-verify\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=skip-verify\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param preferred\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=preferred\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?allowFallbackToPlaintext=true&timeout=5s&tls=preferred\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param customcfg\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=customcfg\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?tls=customcfg\",\n\t\t\terrmsg:   \"invalid value / unknown config name: customcfg\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param custom-cfg\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg\",\n\t\t\terrmsg:   \"invalid value / unknown config name: custom-cfg\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param custom-cfg and following\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg&timeout=20s\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg&timeout=20s\",\n\t\t\terrmsg:   \"invalid value / unknown config name: custom-cfg\",\n\t\t},\n\t\t{\n\t\t\tname:     \"non-custom param notls keyword\",\n\t\t\tinput:    \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&notls=custom\",\n\t\t\texpected: \"root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&notls=custom\",\n\t\t},\n\t}\n\n\tcustomIDRe := regexp.MustCompile(`[\\?&]tls=custom-([\\w-]*)(?:$|&)`)\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\ts := config.NewSecret([]byte(test.input))\n\t\t\tplugin := &Mysql{\n\t\t\t\tServers:      []*config.Secret{&s},\n\t\t\t\tClientConfig: tls.ClientConfig{InsecureSkipVerify: true},\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\tif test.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, test.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\trequire.Len(t, plugin.Servers, 1)\n\t\t\trs, err := plugin.Servers[0].Get()\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer rs.Destroy()\n\n\t\t\t// Replace the `<id>` part with a potential actual ID\n\t\t\tactual := rs.String()\n\t\t\texpected := test.expected\n\t\t\tif strings.Contains(expected, \"<id>\") {\n\t\t\t\tmatches := customIDRe.FindStringSubmatch(actual)\n\t\t\t\tif len(matches) == 2 {\n\t\t\t\t\texpected = strings.Replace(expected, \"<id>\", matches[1], 1)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.Equal(t, expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestGatherGlobalVariables(t *testing.T) {\n\tdb, mock, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tdefer db.Close()\n\n\tm := Mysql{\n\t\tLog:           testutil.Logger{},\n\t\tMetricVersion: 2,\n\t}\n\trequire.NoError(t, m.Init())\n\n\tcolumns := []string{\"Variable_name\", \"Value\"}\n\tmeasurement := \"mysql_variables\"\n\n\ttype fields []struct {\n\t\tkey         string\n\t\trawValue    string\n\t\tparsedValue interface{}\n\t}\n\ttype tags map[string]string\n\ttestCases := []struct {\n\t\tname   string\n\t\tfields fields\n\t\ttags   tags\n\t}{\n\t\t{\n\t\t\t\"basic variables\",\n\t\t\tfields{\n\t\t\t\t{\"__test__string_variable\", \"text\", \"text\"},\n\t\t\t\t{\"__test__int_variable\", \"5\", int64(5)},\n\t\t\t\t{\"__test__off_variable\", \"OFF\", int64(0)},\n\t\t\t\t{\"__test__on_variable\", \"ON\", int64(1)},\n\t\t\t\t{\"__test__empty_variable\", \"\", nil},\n\t\t\t},\n\t\t\ttags{\"server\": \"127.0.0.1:3306\"},\n\t\t},\n\t\t{\n\t\t\t\"version tag is present\",\n\t\t\tfields{\n\t\t\t\t{\"__test__string_variable\", \"text\", \"text\"},\n\t\t\t\t{\"version\", \"8.0.27-0ubuntu0.20.04.1\", \"8.0.27-0ubuntu0.20.04.1\"},\n\t\t\t},\n\t\t\ttags{\"server\": \"127.0.0.1:3306\", \"version\": \"8.0.27-0ubuntu0.20.04.1\"},\n\t\t},\n\n\t\t{\"\", fields{{\"delay_key_write\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"delay_key_write\", \"ON\", \"ON\"}}, nil},\n\t\t{\"\", fields{{\"delay_key_write\", \"ALL\", \"ALL\"}}, nil},\n\t\t{\"\", fields{{\"enforce_gtid_consistency\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"enforce_gtid_consistency\", \"ON\", \"ON\"}}, nil},\n\t\t{\"\", fields{{\"enforce_gtid_consistency\", \"WARN\", \"WARN\"}}, nil},\n\t\t{\"\", fields{{\"event_scheduler\", \"NO\", \"NO\"}}, nil},\n\t\t{\"\", fields{{\"event_scheduler\", \"YES\", \"YES\"}}, nil},\n\t\t{\"\", fields{{\"event_scheduler\", \"DISABLED\", \"DISABLED\"}}, nil},\n\t\t{\"\", fields{{\"have_ssl\", \"DISABLED\", int64(0)}}, nil},\n\t\t{\"\", fields{{\"have_ssl\", \"YES\", int64(1)}}, nil},\n\t\t{\"\", fields{{\"have_symlink\", \"NO\", int64(0)}}, nil},\n\t\t{\"\", fields{{\"have_symlink\", \"DISABLED\", int64(0)}}, nil},\n\t\t{\"\", fields{{\"have_symlink\", \"YES\", int64(1)}}, nil},\n\t\t{\"\", fields{{\"session_track_gtids\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"session_track_gtids\", \"OWN_GTID\", \"OWN_GTID\"}}, nil},\n\t\t{\"\", fields{{\"session_track_gtids\", \"ALL_GTIDS\", \"ALL_GTIDS\"}}, nil},\n\t\t{\"\", fields{{\"session_track_transaction_info\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"session_track_transaction_info\", \"STATE\", \"STATE\"}}, nil},\n\t\t{\"\", fields{{\"session_track_transaction_info\", \"CHARACTERISTICS\", \"CHARACTERISTICS\"}}, nil},\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"0\", \"0\"}}, nil}, // TODO: map this to OFF or vice versa using integers\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"1\", \"1\"}}, nil}, // TODO: map this to ON or vice versa using integers\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"2\", \"2\"}}, nil}, // TODO: map this to STRICT or vice versa using integers\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"ON\", \"ON\"}}, nil},\n\t\t{\"\", fields{{\"ssl_fips_mode\", \"STRICT\", \"STRICT\"}}, nil},\n\t\t{\"\", fields{{\"use_secondary_engine\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"use_secondary_engine\", \"ON\", \"ON\"}}, nil},\n\t\t{\"\", fields{{\"use_secondary_engine\", \"FORCED\", \"FORCED\"}}, nil},\n\t\t{\"\", fields{{\"transaction_write_set_extraction\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"transaction_write_set_extraction\", \"MURMUR32\", \"MURMUR32\"}}, nil},\n\t\t{\"\", fields{{\"transaction_write_set_extraction\", \"XXHASH64\", \"XXHASH64\"}}, nil},\n\t\t{\"\", fields{{\"slave_skip_errors\", \"OFF\", \"OFF\"}}, nil},\n\t\t{\"\", fields{{\"slave_skip_errors\", \"0\", \"0\"}}, nil},\n\t\t{\"\", fields{{\"slave_skip_errors\", \"1007,1008,1050\", \"1007,1008,1050\"}}, nil},\n\t\t{\"\", fields{{\"slave_skip_errors\", \"all\", \"all\"}}, nil},\n\t\t{\"\", fields{{\"slave_skip_errors\", \"ddl_exist_errors\", \"ddl_exist_errors\"}}, nil},\n\t\t{\"\", fields{{\"gtid_mode\", \"OFF\", int64(0)}}, nil},\n\t\t{\"\", fields{{\"gtid_mode\", \"OFF_PERMISSIVE\", int64(0)}}, nil},\n\t\t{\"\", fields{{\"gtid_mode\", \"ON\", int64(1)}}, nil},\n\t\t{\"\", fields{{\"gtid_mode\", \"ON_PERMISSIVE\", int64(1)}}, nil},\n\t}\n\n\tfor i, testCase := range testCases {\n\t\tif testCase.name == \"\" {\n\t\t\ttestCase.name = fmt.Sprintf(\"#%d\", i)\n\t\t}\n\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\trows := sqlmock.NewRows(columns)\n\t\t\tfor _, field := range testCase.fields {\n\t\t\t\trows.AddRow(field.key, field.rawValue)\n\t\t\t}\n\n\t\t\tmock.ExpectQuery(globalVariablesQuery).WillReturnRows(rows).RowsWillBeClosed()\n\n\t\t\tacc := &testutil.Accumulator{}\n\n\t\t\terr := m.gatherGlobalVariables(db, getDSNTag(\"test\"), acc)\n\t\t\trequire.NoErrorf(t, err, \"err on gatherGlobalVariables (test case %q)\", testCase.name)\n\n\t\t\tfoundFields := map[string]bool{}\n\n\t\t\tfor _, metric := range acc.Metrics {\n\t\t\t\trequire.Equalf(t, measurement, metric.Measurement, \"wrong measurement (test case %q)\", testCase.name)\n\n\t\t\t\tif testCase.tags != nil {\n\t\t\t\t\trequire.Equalf(t, testCase.tags, tags(metric.Tags), \"wrong tags (test case %q)\", testCase.name)\n\t\t\t\t}\n\n\t\t\t\tfor key, value := range metric.Fields {\n\t\t\t\t\tfor _, field := range testCase.fields {\n\t\t\t\t\t\tif field.key == key {\n\t\t\t\t\t\t\trequire.Falsef(t, foundFields[key], \"field %s observed multiple times (test case %q)\", key, testCase.name)\n\t\t\t\t\t\t\trequire.Equalf(t, field.parsedValue, value, \"wrong value for field %s (test case %q)\", key, testCase.name)\n\t\t\t\t\t\t\tfoundFields[key] = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\trequire.Truef(t, foundFields[key], \"unexpected field %s=%v (test case %q)\", key, value, testCase.name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, field := range testCase.fields {\n\t\t\t\trequire.Truef(t, foundFields[field.key], \"missing field %s=%v (test case %q)\", field.key, field.parsedValue, testCase.name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestNewNamespace(t *testing.T) {\n\ttestCases := []struct {\n\t\twords     []string\n\t\tnamespace string\n\t}{\n\t\t{\n\t\t\t[]string{\"thread\", \"info_scheme\", \"query update\"},\n\t\t\t\"thread_info_scheme_query_update\",\n\t\t},\n\t\t{\n\t\t\t[]string{\"thread\", \"info_scheme\", \"query_update\"},\n\t\t\t\"thread_info_scheme_query_update\",\n\t\t},\n\t\t{\n\t\t\t[]string{\"thread\", \"info\", \"scheme\", \"query\", \"update\"},\n\t\t\t\"thread_info_scheme_query_update\",\n\t\t},\n\t}\n\tfor _, cases := range testCases {\n\t\tif got := newNamespace(cases.words...); got != cases.namespace {\n\t\t\tt.Errorf(\"want %s, got %s\", cases.namespace, got)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/mysql/sample.conf",
    "content": "# Read metrics from one or many mysql servers\n[[inputs.mysql]]\n  ## specify servers via a url matching:\n  ##  [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify|custom]]\n  ##  see https://github.com/go-sql-driver/mysql#dsn-data-source-name\n  ##  e.g.\n  ##    servers = [\"user:passwd@tcp(127.0.0.1:3306)/?tls=false\"]\n  ##    servers = [\"user@tcp(127.0.0.1:3306)/?tls=false\"]\n  #\n  ## If no servers are specified, then localhost is used as the host.\n  servers = [\"tcp(127.0.0.1:3306)/\"]\n\n  ## Selects the metric output format.\n  ##\n  ## This option exists to maintain backwards compatibility, if you have\n  ## existing metrics do not set or change this value until you are ready to\n  ## migrate to the new format.\n  ##\n  ## If you do not have existing metrics from this plugin set to the latest\n  ## version.\n  ##\n  ## Telegraf >=1.6: metric_version = 2\n  ##           <1.6: metric_version = 1 (or unset)\n  metric_version = 2\n\n  ## if the list is empty, then metrics are gathered from all database tables\n  # table_schema_databases = []\n\n  ## gather metrics from INFORMATION_SCHEMA.TABLES for databases provided\n  ## in the list above\n  # gather_table_schema = false\n\n  ## gather thread state counts from INFORMATION_SCHEMA.PROCESSLIST\n  # gather_process_list = false\n\n  ## gather user statistics from INFORMATION_SCHEMA.USER_STATISTICS\n  # gather_user_statistics = false\n\n  ## gather auto_increment columns and max values from information schema\n  # gather_info_schema_auto_inc = false\n\n  ## gather metrics from INFORMATION_SCHEMA.INNODB_METRICS\n  # gather_innodb_metrics = false\n\n  ## gather metrics from all channels from SHOW SLAVE STATUS command output\n  # gather_all_slave_channels = false\n\n  ## gather metrics from SHOW SLAVE STATUS command output\n  # gather_slave_status = false\n\n  ## gather metrics from SHOW REPLICA STATUS command output\n  # gather_replica_status = false\n\n  ## use SHOW ALL SLAVES STATUS command output for MariaDB\n  ## use SHOW ALL REPLICAS STATUS command if enable gather replica status\n  # mariadb_dialect = false\n\n  ## gather metrics from SHOW BINARY LOGS command output\n  # gather_binary_logs = false\n\n  ## gather metrics from SHOW GLOBAL VARIABLES command output\n  # gather_global_variables = true\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_TABLE\n  # gather_table_io_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_LOCK_WAITS\n  # gather_table_lock_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_INDEX_USAGE\n  # gather_index_io_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENT_WAITS\n  # gather_event_waits = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME\n  # gather_file_events_stats = false\n\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_DIGEST\n  # gather_perf_events_statements             = false\n  #\n  ## gather metrics from PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME\n  # gather_perf_sum_per_acc_per_event         = false\n  #\n  ## list of events to be gathered for gather_perf_sum_per_acc_per_event\n  ## in case of empty list all events will be gathered\n  # perf_summary_events                       = []\n\n  ## the limits for metrics form perf_events_statements\n  # perf_events_statements_digest_text_limit = 120\n  # perf_events_statements_limit = 250\n  # perf_events_statements_time_limit = 86400\n\n  ## Some queries we may want to run less often (such as SHOW GLOBAL VARIABLES)\n  ##   example: interval_slow = \"30m\"\n  # interval_slow = \"\"\n\n  ## Optional TLS Config (used if tls=custom parameter specified in server uri)\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/mysql/v1/mysql.go",
    "content": "package v1\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"strconv\"\n)\n\n// Mapping represents a mapping between server and export names.\ntype Mapping struct {\n\tOnServer string\n\tInExport string\n}\n\n// Mappings is a list of predefined mappings between server and export names.\nvar Mappings = []*Mapping{\n\t{\n\t\tOnServer: \"Aborted_\",\n\t\tInExport: \"aborted_\",\n\t},\n\t{\n\t\tOnServer: \"Bytes_\",\n\t\tInExport: \"bytes_\",\n\t},\n\t{\n\t\tOnServer: \"Com_\",\n\t\tInExport: \"commands_\",\n\t},\n\t{\n\t\tOnServer: \"Created_\",\n\t\tInExport: \"created_\",\n\t},\n\t{\n\t\tOnServer: \"Handler_\",\n\t\tInExport: \"handler_\",\n\t},\n\t{\n\t\tOnServer: \"Innodb_\",\n\t\tInExport: \"innodb_\",\n\t},\n\t{\n\t\tOnServer: \"Key_\",\n\t\tInExport: \"key_\",\n\t},\n\t{\n\t\tOnServer: \"Open_\",\n\t\tInExport: \"open_\",\n\t},\n\t{\n\t\tOnServer: \"Opened_\",\n\t\tInExport: \"opened_\",\n\t},\n\t{\n\t\tOnServer: \"Qcache_\",\n\t\tInExport: \"qcache_\",\n\t},\n\t{\n\t\tOnServer: \"Table_\",\n\t\tInExport: \"table_\",\n\t},\n\t{\n\t\tOnServer: \"Tokudb_\",\n\t\tInExport: \"tokudb_\",\n\t},\n\t{\n\t\tOnServer: \"Threads_\",\n\t\tInExport: \"threads_\",\n\t},\n\t{\n\t\tOnServer: \"Access_\",\n\t\tInExport: \"access_\",\n\t},\n\t{\n\t\tOnServer: \"Aria__\",\n\t\tInExport: \"aria_\",\n\t},\n\t{\n\t\tOnServer: \"Binlog__\",\n\t\tInExport: \"binlog_\",\n\t},\n\t{\n\t\tOnServer: \"Busy_\",\n\t\tInExport: \"busy_\",\n\t},\n\t{\n\t\tOnServer: \"Connection_\",\n\t\tInExport: \"connection_\",\n\t},\n\t{\n\t\tOnServer: \"Delayed_\",\n\t\tInExport: \"delayed_\",\n\t},\n\t{\n\t\tOnServer: \"Empty_\",\n\t\tInExport: \"empty_\",\n\t},\n\t{\n\t\tOnServer: \"Executed_\",\n\t\tInExport: \"executed_\",\n\t},\n\t{\n\t\tOnServer: \"Executed_\",\n\t\tInExport: \"executed_\",\n\t},\n\t{\n\t\tOnServer: \"Feature_\",\n\t\tInExport: \"feature_\",\n\t},\n\t{\n\t\tOnServer: \"Flush_\",\n\t\tInExport: \"flush_\",\n\t},\n\t{\n\t\tOnServer: \"Last_\",\n\t\tInExport: \"last_\",\n\t},\n\t{\n\t\tOnServer: \"Master_\",\n\t\tInExport: \"master_\",\n\t},\n\t{\n\t\tOnServer: \"Max_\",\n\t\tInExport: \"max_\",\n\t},\n\t{\n\t\tOnServer: \"Memory_\",\n\t\tInExport: \"memory_\",\n\t},\n\t{\n\t\tOnServer: \"Not_\",\n\t\tInExport: \"not_\",\n\t},\n\t{\n\t\tOnServer: \"Performance_\",\n\t\tInExport: \"performance_\",\n\t},\n\t{\n\t\tOnServer: \"Prepared_\",\n\t\tInExport: \"prepared_\",\n\t},\n\t{\n\t\tOnServer: \"Rows_\",\n\t\tInExport: \"rows_\",\n\t},\n\t{\n\t\tOnServer: \"Rpl_\",\n\t\tInExport: \"rpl_\",\n\t},\n\t{\n\t\tOnServer: \"Select_\",\n\t\tInExport: \"select_\",\n\t},\n\t{\n\t\tOnServer: \"Slave_\",\n\t\tInExport: \"slave_\",\n\t},\n\t{\n\t\tOnServer: \"Slow_\",\n\t\tInExport: \"slow_\",\n\t},\n\t{\n\t\tOnServer: \"Sort_\",\n\t\tInExport: \"sort_\",\n\t},\n\t{\n\t\tOnServer: \"Subquery_\",\n\t\tInExport: \"subquery_\",\n\t},\n\t{\n\t\tOnServer: \"Tc_\",\n\t\tInExport: \"tc_\",\n\t},\n\t{\n\t\tOnServer: \"Threadpool_\",\n\t\tInExport: \"threadpool_\",\n\t},\n\t{\n\t\tOnServer: \"wsrep_\",\n\t\tInExport: \"wsrep_\",\n\t},\n\t{\n\t\tOnServer: \"Uptime_\",\n\t\tInExport: \"uptime_\",\n\t},\n}\n\n// ParseValue parses a SQL raw byte value into a float64.\n// It converts \"Yes\"/\"ON\" to 1, \"No\"/\"OFF\" to 0, and attempts to parse other values as float64.\nfunc ParseValue(value sql.RawBytes) (float64, error) {\n\tif bytes.Equal(value, []byte(\"Yes\")) || bytes.Equal(value, []byte(\"ON\")) {\n\t\treturn 1, nil\n\t}\n\n\tif bytes.Equal(value, []byte(\"No\")) || bytes.Equal(value, []byte(\"OFF\")) {\n\t\treturn 0, nil\n\t}\n\tn, err := strconv.ParseFloat(string(value), 64)\n\treturn n, err\n}\n"
  },
  {
    "path": "plugins/inputs/mysql/v2/convert.go",
    "content": "package v2\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype conversionFunc func(value sql.RawBytes) (interface{}, error)\n\n// ParseInt parses the given sql.RawBytes value into an int64.\n// It returns the parsed value and an error if the parsing fails.\nfunc ParseInt(value sql.RawBytes) (interface{}, error) {\n\tv, err := strconv.ParseInt(string(value), 10, 64)\n\n\t// Ignore ErrRange.  When this error is set the returned value is \"the\n\t// maximum magnitude integer of the appropriate bitSize and sign.\"\n\tvar numErr *strconv.NumError\n\tif errors.As(err, &numErr) && errors.Is(numErr, strconv.ErrRange) {\n\t\treturn v, nil\n\t}\n\n\treturn v, err\n}\n\n// ParseUint parses the given sql.RawBytes value into an uint64.\n// It returns the parsed value and an error if the parsing fails.\nfunc ParseUint(value sql.RawBytes) (interface{}, error) {\n\treturn strconv.ParseUint(string(value), 10, 64)\n}\n\n// ParseFloat parses the given sql.RawBytes value into a float64.\n// It returns the parsed value and an error if the parsing fails.\nfunc ParseFloat(value sql.RawBytes) (interface{}, error) {\n\treturn strconv.ParseFloat(string(value), 64)\n}\n\n// ParseBoolAsInteger parses the given sql.RawBytes value into an int64\n// representing a boolean value. It returns 1 for \"YES\" or \"ON\" and 0 otherwise.\nfunc ParseBoolAsInteger(value sql.RawBytes) (interface{}, error) {\n\tif bytes.EqualFold(value, []byte(\"YES\")) || bytes.EqualFold(value, []byte(\"ON\")) {\n\t\treturn int64(1), nil\n\t}\n\n\treturn int64(0), nil\n}\n\n// ParseString parses the given sql.RawBytes value into a string.\n// It returns the parsed value and an error if the parsing fails.\nfunc ParseString(value sql.RawBytes) (interface{}, error) {\n\treturn string(value), nil\n}\n\n// parseWsrepLatency parses the given sql.RawBytes value into a map\n// containing 5 distinct float64 values. These represent min/avg/max/stdev/sample_size.\n// It returns an error if the value is unrecognized.\nfunc parseWsrepLatency(value sql.RawBytes) (interface{}, error) {\n\tkeys := []string{\"min\", \"avg\", \"max\", \"stdev\", \"sample_size\"}\n\tparts := strings.Split(string(value), \"/\")\n\tif len(parts) != len(keys) {\n\t\treturn nil, fmt.Errorf(\"unsupported amount of values in wsrep_evs_repl_latency, got %d expected %d\", len(parts), len(keys))\n\t}\n\n\tresult := make(map[string]interface{}, len(keys))\n\n\tfor i, key := range keys {\n\t\tval, err := strconv.ParseFloat(parts[i], 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse %s value: %w\", key, err)\n\t\t}\n\t\tresult[key] = val\n\t}\n\n\treturn result, nil\n}\n\n// ParseWsrepProviderOptions parses the given sql.RawBytes value into a map\n// containing all wsrep Provider options settings.\nfunc parseWsrepProviderOptions(value sql.RawBytes) (interface{}, error) {\n\tparts := strings.Split(strings.TrimSpace(string(value)), \";\")\n\tresult := make(map[string]interface{})\n\tfor _, setting := range parts {\n\t\tkey, data, found := strings.Cut(setting, \"=\")\n\n\t\t// empty string at the end of the field, skip\n\t\tif len(setting) != 0 && !found {\n\t\t\treturn nil, fmt.Errorf(\"invalid key-value pair for %q\", setting)\n\t\t}\n\n\t\tkey = strings.TrimSpace(key)\n\t\tdata = strings.TrimSpace(data)\n\t\tif len(data) == 0 {\n\t\t\tcontinue // empty value, no point in continuing\n\t\t}\n\n\t\t// Only process gcache.size for now\n\t\tif key != \"gcache.size\" {\n\t\t\tcontinue\n\t\t}\n\t\tkey = strings.Replace(key, \".\", \"_\", -1)\n\n\t\t// Extract the size suffix for values like 128M\n\t\tsuffix := data[len(data)-1:]\n\t\tvalue := data[:len(data)-1]\n\n\t\t// Determine the scaling factor from the suffix\n\t\tvar factor uint64\n\t\tswitch strings.ToUpper(suffix) {\n\t\tcase \"K\":\n\t\t\tfactor = 1024\n\t\tcase \"M\":\n\t\t\tfactor = 1024 * 1024\n\t\tcase \"G\":\n\t\t\tfactor = 1024 * 1024 * 1024\n\t\tcase \"T\":\n\t\t\tfactor = 1024 * 1024 * 1024 * 1024\n\t\tcase \"P\":\n\t\t\tfactor = 1024 * 1024 * 1024 * 1024 * 1024\n\t\tcase \"E\":\n\t\t\tfactor = 1024 * 1024 * 1024 * 1024 * 1024 * 1024\n\t\tdefault:\n\t\t\t// We got no known unit so parse the whole data as value\n\t\t\tvalue = data\n\t\t\tfactor = 1\n\t\t}\n\n\t\t// Compute the actual value\n\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse value %q: %w\", data, err)\n\t\t}\n\t\tresult[key] = v * factor\n\t}\n\treturn result, nil\n}\n\n// ParseGTIDMode parses the given sql.RawBytes value into an int64\n// representing the GTID mode. It returns an error if the value is unrecognized.\nfunc ParseGTIDMode(value sql.RawBytes) (interface{}, error) {\n\t// https://dev.mysql.com/doc/refman/8.0/en/replication-mode-change-online-concepts.html\n\tv := string(value)\n\tswitch v {\n\tcase \"OFF\":\n\t\treturn int64(0), nil\n\tcase \"ON\":\n\t\treturn int64(1), nil\n\tcase \"OFF_PERMISSIVE\":\n\t\treturn int64(0), nil\n\tcase \"ON_PERMISSIVE\":\n\t\treturn int64(1), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unrecognized gtid_mode: %q\", v)\n\t}\n}\n\n// ParseValue attempts to parse the given sql.RawBytes value into an appropriate type.\n// It returns the parsed value and an error if the parsing fails.\nfunc ParseValue(value sql.RawBytes) (interface{}, error) {\n\tif bytes.EqualFold(value, []byte(\"YES\")) || bytes.Equal(value, []byte(\"ON\")) {\n\t\treturn int64(1), nil\n\t}\n\n\tif bytes.EqualFold(value, []byte(\"NO\")) || bytes.Equal(value, []byte(\"OFF\")) {\n\t\treturn int64(0), nil\n\t}\n\n\tif val, err := strconv.ParseInt(string(value), 10, 64); err == nil {\n\t\treturn val, nil\n\t}\n\tif val, err := strconv.ParseUint(string(value), 10, 64); err == nil {\n\t\treturn val, nil\n\t}\n\tif val, err := strconv.ParseFloat(string(value), 64); err == nil {\n\t\treturn val, nil\n\t}\n\n\tif len(string(value)) > 0 {\n\t\treturn string(value), nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unconvertible value: %q\", string(value))\n}\n\nvar globalStatusConversions = map[string]conversionFunc{\n\t\"innodb_available_undo_logs\":    ParseUint,\n\t\"innodb_buffer_pool_pages_misc\": ParseUint,\n\t\"innodb_data_pending_fsyncs\":    ParseUint,\n\t\"ssl_ctx_verify_depth\":          ParseUint,\n\t\"ssl_verify_depth\":              ParseUint,\n\n\t// see https://galeracluster.com/library/documentation/galera-status-variables.html\n\t\"wsrep_apply_oooe\":           ParseFloat,\n\t\"wsrep_apply_oool\":           ParseFloat,\n\t\"wsrep_apply_window\":         ParseFloat,\n\t\"wsrep_cert_deps_distance\":   ParseFloat,\n\t\"wsrep_cert_interval\":        ParseFloat,\n\t\"wsrep_commit_oooe\":          ParseFloat,\n\t\"wsrep_commit_oool\":          ParseFloat,\n\t\"wsrep_commit_window\":        ParseFloat,\n\t\"wsrep_evs_repl_latency\":     parseWsrepLatency,\n\t\"wsrep_flow_control_paused\":  ParseFloat,\n\t\"wsrep_local_index\":          ParseUint,\n\t\"wsrep_local_recv_queue_avg\": ParseFloat,\n\t\"wsrep_local_send_queue_avg\": ParseFloat,\n}\n\nvar globalVariableConversions = map[string]conversionFunc{\n\t// see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html\n\t// see https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html\n\t\"delay_key_write\":                ParseString,        // ON, OFF, ALL\n\t\"enforce_gtid_consistency\":       ParseString,        // ON, OFF, WARN\n\t\"event_scheduler\":                ParseString,        // YES, NO, DISABLED\n\t\"have_openssl\":                   ParseBoolAsInteger, // alias for have_ssl\n\t\"have_ssl\":                       ParseBoolAsInteger, // YES, DISABLED\n\t\"have_symlink\":                   ParseBoolAsInteger, // YES, NO, DISABLED\n\t\"session_track_gtids\":            ParseString,\n\t\"session_track_transaction_info\": ParseString,\n\t\"ssl_fips_mode\":                  ParseString,\n\t\"use_secondary_engine\":           ParseString,\n\n\t// https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html\n\t// https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html\n\t\"transaction_write_set_extraction\": ParseString,\n\n\t// https://dev.mysql.com/doc/refman/5.7/en/replication-options-replica.html\n\t// https://dev.mysql.com/doc/refman/8.0/en/replication-options-replica.html\n\t\"slave_skip_errors\": ParseString,\n\n\t// https://dev.mysql.com/doc/refman/5.7/en/replication-options-gtids.html\n\t// https://dev.mysql.com/doc/refman/8.0/en/replication-options-gtids.html\n\t\"gtid_mode\": ParseGTIDMode,\n\n\t// https://galeracluster.com/documentation/html_docs_proto-12/documentation/mysql-wsrep-options.html#wsrep-provider-options\n\t\"wsrep_provider_options\": parseWsrepProviderOptions,\n}\n\n// ConvertGlobalStatus converts the given key and sql.RawBytes value into an appropriate type based on globalStatusConversions.\n// It returns the converted value and an error if the conversion fails.\nfunc ConvertGlobalStatus(key string, value sql.RawBytes) (interface{}, error) {\n\tif bytes.Equal(value, []byte(\"\")) {\n\t\treturn nil, nil\n\t}\n\n\tif conv, ok := globalStatusConversions[key]; ok {\n\t\treturn conv(value)\n\t}\n\n\treturn ParseValue(value)\n}\n\n// ConvertGlobalVariables converts the given key and sql.RawBytes value into an appropriate type based on globalVariableConversions.\n// It returns the converted value and an error if the conversion fails.\nfunc ConvertGlobalVariables(key string, value sql.RawBytes) (interface{}, error) {\n\tif bytes.Equal(value, []byte(\"\")) {\n\t\treturn nil, nil\n\t}\n\n\tif conv, ok := globalVariableConversions[key]; ok {\n\t\treturn conv(value)\n\t}\n\n\treturn ParseValue(value)\n}\n"
  },
  {
    "path": "plugins/inputs/mysql/v2/convert_test.go",
    "content": "package v2\n\nimport (\n\t\"database/sql\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestConvertGlobalStatus(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tkey         string\n\t\tvalue       sql.RawBytes\n\t\texpected    interface{}\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname:        \"default\",\n\t\t\tkey:         \"ssl_ctx_verify_depth\",\n\t\t\tvalue:       []byte(\"0\"),\n\t\t\texpected:    uint64(0),\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname:        \"overflow int64\",\n\t\t\tkey:         \"ssl_ctx_verify_depth\",\n\t\t\tvalue:       []byte(\"18446744073709551615\"),\n\t\t\texpected:    uint64(18446744073709551615),\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname:        \"defined variable but unset\",\n\t\t\tkey:         \"ssl_ctx_verify_depth\",\n\t\t\tvalue:       []byte(\"\"),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"multiple values in one metric converted to a map\",\n\t\t\tkey:   \"wsrep_evs_repl_latency\",\n\t\t\tvalue: []byte(\"0.000160108/0.000386178/0.00964884/0.000488261/816\"),\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"min\":         0.000160108,\n\t\t\t\t\"avg\":         0.000386178,\n\t\t\t\t\"max\":         0.00964884,\n\t\t\t\t\"stdev\":       0.000488261,\n\t\t\t\t\"sample_size\": 816.0,\n\t\t\t},\n\t\t\texpectedErr: nil,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := ConvertGlobalStatus(tt.key, tt.value)\n\t\t\trequire.Equal(t, tt.expectedErr, err)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestConvertGlobalVariables(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tkey         string\n\t\tvalue       sql.RawBytes\n\t\texpected    interface{}\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname:        \"boolean type mysql<=5.6\",\n\t\t\tkey:         \"gtid_mode\",\n\t\t\tvalue:       []byte(\"ON\"),\n\t\t\texpected:    int64(1),\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname:        \"enum type mysql>=5.7\",\n\t\t\tkey:         \"gtid_mode\",\n\t\t\tvalue:       []byte(\"ON_PERMISSIVE\"),\n\t\t\texpected:    int64(1),\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname:        \"defined variable but unset\",\n\t\t\tkey:         \"ssl_ctx_verify_depth\",\n\t\t\tvalue:       []byte(\"\"),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple values in one metric converted to a map\",\n\t\t\tkey:  \"wsrep_provider_options\",\n\t\t\tvalue: []byte(\n\t\t\t\t\"allocator.disk_pages_encryption = no; allocator.encryption_cache_page_size = 32K; allocator.encryption_cache_size = 16777216; \" +\n\t\t\t\t\t\"base_dir = /var/lib/mysql; base_host = 192.168.1.1; base_port = 4567; cert.log_conflicts = no; cert.optimistic_pa = NO; debug = no; \" +\n\t\t\t\t\t\"evs.auto_evict = 0; evs.causal_keepalive_period = PT1S; evs.debug_log_mask = 0x1; evs.delay_margin = PT1S; \" +\n\t\t\t\t\t\"evs.delayed_keep_period = PT30S; evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S; evs.info_log_mask = 0; \" +\n\t\t\t\t\t\"evs.install_timeout = PT7.5S; evs.join_retrans_period = PT1S; evs.keepalive_period = PT1S; evs.max_install_timeouts = 3; \" +\n\t\t\t\t\t\"evs.send_window = 10; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S; evs.use_aggregate = true; evs.user_send_window = 4; \" +\n\t\t\t\t\t\"evs.version = 1; evs.view_forget_timeout = P1D; gcache.dir = /var/lib/mysql; gcache.encryption = no; \" +\n\t\t\t\t\t\"gcache.encryption_cache_page_size = 32K; gcache.encryption_cache_size = 16777216; gcache.freeze_purge_at_seqno = -1; \" +\n\t\t\t\t\t\"gcache.keep_pages_count = 0; gcache.keep_pages_size = 0; gcache.mem_size = 0; gcache.name = galera.cache; gcache.page_size = 128M; \" +\n\t\t\t\t\t\"gcache.recover = yes; gcache.size = 128M; gcomm.thread_prio = ; gcs.fc_auto_evict_threshold = 0.75; gcs.fc_auto_evict_window = 0; \" +\n\t\t\t\t\t\"gcs.fc_debug = 0; gcs.fc_factor = 1.0; gcs.fc_limit = 100; gcs.fc_master_slave = no; gcs.fc_single_primary = no; \" +\n\t\t\t\t\t\"gcs.max_packet_size = 64500; gcs.max_throttle = 0.25; gcs.recv_q_hard_limit = 9223372036854775807; gcs.recv_q_soft_limit = 0.25; \" +\n\t\t\t\t\t\"gcs.sync_donor = no; gmcast.listen_addr = tcp://0.0.0.0:4567; gmcast.mcast_addr = ; gmcast.mcast_ttl = 1; gmcast.peer_timeout = PT3S; \" +\n\t\t\t\t\t\"gmcast.segment = 0; gmcast.time_wait = PT5S; gmcast.version = 0; ist.recv_addr = 192.168.1.1; pc.announce_timeout = PT3S; \" +\n\t\t\t\t\t\"pc.checksum = false; pc.ignore_quorum = false; pc.ignore_sb = false; pc.linger = PT20S; pc.npvo = false; pc.recovery = true; \" +\n\t\t\t\t\t\"pc.version = 0; pc.wait_prim = true; pc.wait_prim_timeout = PT30S; pc.wait_restored_prim_timeout = PT0S; pc.weight = 1; \" +\n\t\t\t\t\t\"protonet.backend = asio; protonet.version = 0; repl.causal_read_timeout = PT30S; repl.commit_order = 3; repl.key_format = FLAT8; \" +\n\t\t\t\t\t\"repl.max_ws_size = 2147483647; repl.proto_max = 11; socket.checksum = 2; socket.recv_buf_size = auto; socket.send_buf_size = auto; \",\n\t\t\t),\n\t\t\texpected: map[string]interface{}{\n\t\t\t\t\"gcache_size\": uint64(134217728),\n\t\t\t},\n\t\t\texpectedErr: nil,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := ConvertGlobalVariables(tt.key, tt.value)\n\t\t\trequire.Equal(t, tt.expectedErr, err)\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestParseValue(t *testing.T) {\n\ttestCases := []struct {\n\t\trawByte sql.RawBytes\n\t\toutput  interface{}\n\t\terr     string\n\t}{\n\t\t{sql.RawBytes(\"123\"), int64(123), \"\"},\n\t\t{sql.RawBytes(\"abc\"), \"abc\", \"\"},\n\t\t{sql.RawBytes(\"10.1\"), 10.1, \"\"},\n\t\t{sql.RawBytes(\"ON\"), int64(1), \"\"},\n\t\t{sql.RawBytes(\"OFF\"), int64(0), \"\"},\n\t\t{sql.RawBytes(\"NO\"), int64(0), \"\"},\n\t\t{sql.RawBytes(\"YES\"), int64(1), \"\"},\n\t\t{sql.RawBytes(\"No\"), int64(0), \"\"},\n\t\t{sql.RawBytes(\"Yes\"), int64(1), \"\"},\n\t\t{sql.RawBytes(\"-794\"), int64(-794), \"\"},\n\t\t{sql.RawBytes(\"2147483647\"), int64(2147483647), \"\"},                       // max int32\n\t\t{sql.RawBytes(\"2147483648\"), int64(2147483648), \"\"},                       // too big for int32\n\t\t{sql.RawBytes(\"9223372036854775807\"), int64(9223372036854775807), \"\"},     // max int64\n\t\t{sql.RawBytes(\"9223372036854775808\"), uint64(9223372036854775808), \"\"},    // too big for int64\n\t\t{sql.RawBytes(\"18446744073709551615\"), uint64(18446744073709551615), \"\"},  // max uint64\n\t\t{sql.RawBytes(\"18446744073709551616\"), float64(18446744073709552000), \"\"}, // too big for uint64\n\t\t{sql.RawBytes(\"18446744073709552333\"), float64(18446744073709552000), \"\"}, // too big for uint64\n\t\t{sql.RawBytes(\"\"), nil, \"unconvertible value\"},\n\t}\n\tfor _, cases := range testCases {\n\t\tgot, err := ParseValue(cases.rawByte)\n\n\t\tif err != nil && cases.err == \"\" {\n\t\t\tt.Errorf(\"for %q got unexpected error: %q\", string(cases.rawByte), err.Error())\n\t\t} else if err != nil && !strings.HasPrefix(err.Error(), cases.err) {\n\t\t\tt.Errorf(\"for %q wanted error %q, got %q\", string(cases.rawByte), cases.err, err.Error())\n\t\t} else if err == nil && cases.err != \"\" {\n\t\t\tt.Errorf(\"for %q did not get expected error: %s\", string(cases.rawByte), cases.err)\n\t\t} else if got != cases.output {\n\t\t\tt.Errorf(\"for %q wanted %#v (%T), got %#v (%T)\", string(cases.rawByte), cases.output, cases.output, got, got)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/nats/README.md",
    "content": "# NATS Server Monitoring Input Plugin\n\nThis plugin gathers metrics of a [NATS][nats] server instance using its\n[monitoring endpoints][nats_monitoring].\n\n⭐ Telegraf v1.6.0\n🏷️ server\n💻 all\n\n[nats]: http://www.nats.io\n[nats_monitoring]: https://docs.nats.io/running-a-nats-service/nats_admin/monitoring\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Provides metrics about the state of a NATS server\n# This plugin does NOT support FreeBSD\n[[inputs.nats]]\n  ## The address of the monitoring endpoint of the NATS server\n  server = \"http://localhost:8222\"\n\n  ## Maximum time to receive response\n  # response_timeout = \"5s\"\n```\n\n## Metrics\n\n- nats\n  - tags\n    - server\n  - fields:\n    - uptime (integer, nanoseconds)\n    - mem (integer, bytes)\n    - subscriptions (integer, count)\n    - out_bytes (integer, bytes)\n    - connections (integer, count)\n    - in_msgs (integer, bytes)\n    - total_connections (integer, count)\n    - cores (integer, count)\n    - cpu (integer, count)\n    - slow_consumers (integer, count)\n    - routes (integer, count)\n    - remotes (integer, count)\n    - out_msgs (integer, count)\n    - in_bytes (integer, bytes)\n\n## Example Output\n\n```text\nnats,server=http://localhost:8222 uptime=117158348682i,mem=6647808i,subscriptions=0i,out_bytes=0i,connections=0i,in_msgs=0i,total_connections=0i,cores=2i,cpu=0,slow_consumers=0i,routes=0i,remotes=0i,out_msgs=0i,in_bytes=0i 1517015107000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nats/nats.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !freebsd || (freebsd && cgo)\n\npackage nats\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"time\"\n\n\tgnatsd \"github.com/nats-io/nats-server/v2/server\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Nats struct {\n\tServer          string          `toml:\"server\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\n\tclient *http.Client\n}\n\nfunc (*Nats) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Nats) Gather(acc telegraf.Accumulator) error {\n\taddress, err := url.Parse(n.Server)\n\tif err != nil {\n\t\treturn err\n\t}\n\taddress.Path = path.Join(address.Path, \"varz\")\n\n\tif n.client == nil {\n\t\tn.client = n.createHTTPClient()\n\t}\n\tresp, err := n.client.Get(address.String())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tbytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstats := new(gnatsd.Varz)\n\terr = json.Unmarshal(bytes, &stats)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\"nats\",\n\t\tmap[string]interface{}{\n\t\t\t\"in_msgs\":           stats.InMsgs,\n\t\t\t\"out_msgs\":          stats.OutMsgs,\n\t\t\t\"in_bytes\":          stats.InBytes,\n\t\t\t\"out_bytes\":         stats.OutBytes,\n\t\t\t\"uptime\":            stats.Now.Sub(stats.Start).Nanoseconds(),\n\t\t\t\"cores\":             stats.Cores,\n\t\t\t\"cpu\":               stats.CPU,\n\t\t\t\"mem\":               stats.Mem,\n\t\t\t\"connections\":       stats.Connections,\n\t\t\t\"total_connections\": stats.TotalConnections,\n\t\t\t\"subscriptions\":     stats.Subscriptions,\n\t\t\t\"slow_consumers\":    stats.SlowConsumers,\n\t\t\t\"routes\":            stats.Routes,\n\t\t\t\"remotes\":           stats.Remotes,\n\t\t},\n\t\tmap[string]string{\"server\": n.Server},\n\t\ttime.Now())\n\n\treturn nil\n}\n\nfunc (n *Nats) createHTTPClient() *http.Client {\n\ttransport := &http.Transport{\n\t\tProxy: http.ProxyFromEnvironment,\n\t}\n\ttimeout := time.Duration(n.ResponseTimeout)\n\tif timeout == time.Duration(0) {\n\t\ttimeout = 5 * time.Second\n\t}\n\treturn &http.Client{\n\t\tTransport: transport,\n\t\tTimeout:   timeout,\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"nats\", func() telegraf.Input {\n\t\treturn &Nats{\n\t\t\tServer: \"http://localhost:8222\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nats/nats_freebsd.go",
    "content": "//go:build freebsd && !cgo\n\npackage nats\n"
  },
  {
    "path": "plugins/inputs/nats/nats_test.go",
    "content": "//go:build !freebsd || (freebsd && cgo)\n\npackage nats\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar sampleVarz = `\n{\n  \"server_id\": \"n2afhLHLl64Gcaj7S7jaNa\",\n  \"version\": \"1.0.0\",\n  \"go\": \"go1.8\",\n  \"host\": \"0.0.0.0\",\n  \"auth_required\": false,\n  \"ssl_required\": false,\n  \"tls_required\": false,\n  \"tls_verify\": false,\n  \"addr\": \"0.0.0.0\",\n  \"max_connections\": 65536,\n  \"ping_interval\": 120000000000,\n  \"ping_max\": 2,\n  \"http_host\": \"0.0.0.0\",\n  \"http_port\": 1337,\n  \"https_port\": 0,\n  \"auth_timeout\": 1,\n  \"max_control_line\": 1024,\n  \"cluster\": {\n    \"addr\": \"0.0.0.0\",\n    \"cluster_port\": 0,\n    \"auth_timeout\": 1\n  },\n  \"tls_timeout\": 0.5,\n  \"port\": 4222,\n  \"max_payload\": 1048576,\n  \"start\": \"1861-04-12T10:15:26.841483489-05:00\",\n  \"now\": \"2011-10-05T15:24:23.722084098-07:00\",\n  \"uptime\": \"150y5md237h8m57s\",\n  \"mem\": 15581184,\n  \"cores\": 48,\n  \"cpu\": 9,\n  \"connections\": 5,\n  \"total_connections\": 109,\n  \"routes\": 1,\n  \"remotes\": 2,\n  \"in_msgs\": 74148556,\n  \"out_msgs\": 68863261,\n  \"in_bytes\": 946267004717,\n  \"out_bytes\": 948110960598,\n  \"slow_consumers\": 2,\n  \"subscriptions\": 4,\n  \"http_req_stats\": {\n    \"/\": 1,\n    \"/connz\": 100847,\n    \"/routez\": 0,\n    \"/subsz\": 1,\n    \"/varz\": 205785\n  },\n  \"config_load_time\": \"2017-07-24T10:15:26.841483489-05:00\"\n}\n`\n\nfunc TestMetricsCorrect(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/varz\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/varz\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err := fmt.Fprintln(w, sampleVarz); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer srv.Close()\n\n\tn := &Nats{Server: srv.URL}\n\trequire.NoError(t, n.Gather(&acc))\n\n\tfields := map[string]interface{}{\n\t\t\"in_msgs\":           int64(74148556),\n\t\t\"out_msgs\":          int64(68863261),\n\t\t\"in_bytes\":          int64(946267004717),\n\t\t\"out_bytes\":         int64(948110960598),\n\t\t\"uptime\":            int64(4748742536880600609),\n\t\t\"cores\":             48,\n\t\t\"cpu\":               float64(9),\n\t\t\"mem\":               int64(15581184),\n\t\t\"connections\":       int(5),\n\t\t\"total_connections\": uint64(109),\n\t\t\"subscriptions\":     uint32(4),\n\t\t\"slow_consumers\":    int64(2),\n\t\t\"routes\":            int(1),\n\t\t\"remotes\":           int(2),\n\t}\n\ttags := map[string]string{\n\t\t\"server\": srv.URL,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"nats\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/nats/sample.conf",
    "content": "# Provides metrics about the state of a NATS server\n# This plugin does NOT support FreeBSD\n[[inputs.nats]]\n  ## The address of the monitoring endpoint of the NATS server\n  server = \"http://localhost:8222\"\n\n  ## Maximum time to receive response\n  # response_timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/nats_consumer/README.md",
    "content": "# NATS Consumer Input Plugin\n\nThis service plugin consumes messages from [NATS][nats] instances in one of the\nsupported [data formats][data_formats]. A [Queue Group][queue_group] is used\nwhen subscribing to subjects so multiple instances of telegraf can consume\nmessages in parallel.\nThe plugin supports authenticating via [username/password][userpass], a\n[credentials file][creds] (NATS 2.0), or an [nkey seed file][nkey] (NATS 2.0).\n\n⭐ Telegraf v0.10.3\n🏷️ messaging\n💻 all\n\n[nats]: https://www.nats.io/about/\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n[queue_group]: https://www.nats.io/documentation/concepts/nats-queueing/\n[userpass]: https://docs.nats.io/using-nats/developer/connecting/userpass\n[creds]: https://docs.nats.io/using-nats/developer/connecting/creds\n[nkey]: https://docs.nats.io/using-nats/developer/connecting/nkey\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from NATS subject(s)\n[[inputs.nats_consumer]]\n  ## urls of NATS servers\n  servers = [\"nats://localhost:4222\"]\n\n  ## subject(s) to consume\n  ## If you use jetstream you need to set the subjects\n  ## in jetstream_subjects\n  subjects = [\"telegraf\"]\n\n  ## jetstream subjects\n  ## jetstream is a streaming technology inside of nats.\n  ## With jetstream the nats-server persists messages and\n  ## a consumer can consume historical messages. This is\n  ## useful when telegraf needs to restart it don't miss a\n  ## message. You need to configure the nats-server.\n  ## https://docs.nats.io/nats-concepts/jetstream.\n  jetstream_subjects = [\"js_telegraf\"]\n\n  ## explicitly specify the jetstream stream name\n  ## useful for sourced streams where there is no subject defined and\n  ## thus jetstream_subjects won't work\n  jetstream_stream = \"\"\n\n  ## name a queue group\n  queue_group = \"telegraf_consumers\"\n\n  ## Optional authentication with username and password credentials\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional authentication with NATS credentials file (NATS 2.0)\n  # credentials = \"/etc/telegraf/nats.creds\"\n\n  ## Optional authentication with nkey seed file (NATS 2.0)\n  # nkey_seed = \"/etc/telegraf/seed.txt\"\n\n  ## Use Transport Layer Security\n  # secure = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Sets the limits for pending msgs and bytes for each subscription\n  ## These shouldn't need to be adjusted except in very high throughput scenarios\n  # pending_message_limit = 65536\n  # pending_bytes_limit = 67108864\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n## Metrics\n\nWhich data you will get depends on the subjects you consume from nats\n\n## Example Output\n\nDepends on the nats subject input\nnats_consumer,host=foo,subject=recvsubj value=1.9 1655972309339341000\n"
  },
  {
    "path": "plugins/inputs/nats_consumer/nats_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nats_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/nats-io/nats.go\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tonce                          sync.Once\n\tdefaultMaxUndeliveredMessages = 1000\n)\n\ntype NatsConsumer struct {\n\tQueueGroup             string          `toml:\"queue_group\"`\n\tSubjects               []string        `toml:\"subjects\"`\n\tServers                []string        `toml:\"servers\"`\n\tSecure                 bool            `toml:\"secure\"`\n\tUsername               string          `toml:\"username\"`\n\tPassword               string          `toml:\"password\"`\n\tCredentials            string          `toml:\"credentials\"`\n\tNkeySeed               string          `toml:\"nkey_seed\"`\n\tJsSubjects             []string        `toml:\"jetstream_subjects\"`\n\tJsStream               string          `toml:\"jetstream_stream\"`\n\tPendingMessageLimit    int             `toml:\"pending_message_limit\"`\n\tPendingBytesLimit      int             `toml:\"pending_bytes_limit\"`\n\tMaxUndeliveredMessages int             `toml:\"max_undelivered_messages\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\tconn   *nats.Conn\n\tjsConn nats.JetStreamContext\n\tsubs   []*nats.Subscription\n\tjsSubs []*nats.Subscription\n\n\tparser telegraf.Parser\n\t// channel for all incoming NATS messages\n\tin          chan *nats.Msg\n\tundelivered map[telegraf.TrackingID]*nats.Msg\n\t// channel for all NATS read errors\n\terrs   chan error\n\tacc    telegraf.TrackingAccumulator\n\tsem    semaphore\n\twg     sync.WaitGroup\n\tcancel context.CancelFunc\n\tsync.Mutex\n}\n\ntype (\n\tempty     struct{}\n\tsemaphore chan empty\n)\n\ntype natsError struct {\n\tconn *nats.Conn\n\tsub  *nats.Subscription\n\terr  error\n}\n\nfunc (e natsError) Error() string {\n\treturn fmt.Sprintf(\"%s url:%s id:%s sub:%s queue:%s\",\n\t\te.err.Error(), e.conn.ConnectedUrl(), e.conn.ConnectedServerId(), e.sub.Subject, e.sub.Queue)\n}\n\nfunc (*NatsConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NatsConsumer) SetParser(parser telegraf.Parser) {\n\tn.parser = parser\n}\n\n// Start the nats consumer. Caller must call *NatsConsumer.Stop() to clean up.\nfunc (n *NatsConsumer) Start(acc telegraf.Accumulator) error {\n\tn.sem = make(semaphore, n.MaxUndeliveredMessages)\n\tn.acc = acc.WithTracking(n.MaxUndeliveredMessages)\n\tn.undelivered = make(map[telegraf.TrackingID]*nats.Msg, n.MaxUndeliveredMessages)\n\n\toptions := []nats.Option{\n\t\tnats.MaxReconnects(-1),\n\t\tnats.ErrorHandler(n.natsErrHandler),\n\t}\n\n\t// override authentication, if any was specified\n\tif n.Username != \"\" && n.Password != \"\" {\n\t\toptions = append(options, nats.UserInfo(n.Username, n.Password))\n\t}\n\n\tif n.Credentials != \"\" {\n\t\toptions = append(options, nats.UserCredentials(n.Credentials))\n\t}\n\n\tif n.NkeySeed != \"\" {\n\t\topt, err := nats.NkeyOptionFromSeed(n.NkeySeed)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\toptions = append(options, opt)\n\t}\n\n\tif n.Secure {\n\t\ttlsConfig, err := n.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\toptions = append(options, nats.Secure(tlsConfig))\n\t}\n\n\tif n.conn == nil || n.conn.IsClosed() {\n\t\tvar connectErr error\n\t\tn.conn, connectErr = nats.Connect(strings.Join(n.Servers, \",\"), options...)\n\t\tif connectErr != nil {\n\t\t\treturn connectErr\n\t\t}\n\n\t\t// Setup message and error channels\n\t\tn.errs = make(chan error)\n\n\t\tn.in = make(chan *nats.Msg, n.PendingMessageLimit)\n\t\tfor _, subj := range n.Subjects {\n\t\t\tsub, err := n.conn.QueueSubscribe(subj, n.QueueGroup, func(m *nats.Msg) {\n\t\t\t\tn.in <- m\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// set the subscription pending limits\n\t\t\terr = sub.SetPendingLimits(n.PendingMessageLimit, n.PendingBytesLimit)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tn.subs = append(n.subs, sub)\n\t\t}\n\n\t\tif len(n.JsSubjects) > 0 {\n\t\t\tvar connErr error\n\t\t\tsubOptions := []nats.SubOpt{\n\t\t\t\tnats.ManualAck(),\n\t\t\t}\n\t\t\tif n.JsStream != \"\" {\n\t\t\t\tsubOptions = append(subOptions, nats.BindStream(n.JsStream))\n\t\t\t}\n\t\t\tn.jsConn, connErr = n.conn.JetStream(nats.PublishAsyncMaxPending(256))\n\t\t\tif connErr != nil {\n\t\t\t\treturn connErr\n\t\t\t}\n\n\t\t\tif n.jsConn != nil {\n\t\t\t\tfor _, jsSub := range n.JsSubjects {\n\t\t\t\t\tsub, err := n.jsConn.QueueSubscribe(jsSub, n.QueueGroup, func(m *nats.Msg) {\n\t\t\t\t\t\tn.in <- m\n\t\t\t\t\t}, subOptions...)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\t// set the subscription pending limits\n\t\t\t\t\terr = sub.SetPendingLimits(n.PendingMessageLimit, n.PendingBytesLimit)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tn.jsSubs = append(n.jsSubs, sub)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tn.cancel = cancel\n\n\t// Start goroutine to handle delivery notifications from accumulator.\n\tn.wg.Add(1)\n\tgo func() {\n\t\tdefer n.wg.Done()\n\t\tn.waitForDelivery(ctx)\n\t}()\n\n\t// Start the message reader\n\tn.wg.Add(1)\n\tgo func() {\n\t\tdefer n.wg.Done()\n\t\tgo n.receiver(ctx)\n\t}()\n\n\tn.Log.Infof(\"Started the NATS consumer service, nats: %v, subjects: %v, jssubjects: %v, queue: %v\",\n\t\tn.conn.ConnectedUrl(), n.Subjects, n.JsSubjects, n.QueueGroup)\n\n\treturn nil\n}\n\nfunc (*NatsConsumer) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (n *NatsConsumer) Stop() {\n\tn.cancel()\n\tn.wg.Wait()\n\tn.clean()\n}\n\nfunc (n *NatsConsumer) natsErrHandler(c *nats.Conn, s *nats.Subscription, e error) {\n\tselect {\n\tcase n.errs <- natsError{conn: c, sub: s, err: e}:\n\tdefault:\n\t\treturn\n\t}\n}\n\n// receiver() reads all incoming messages from NATS, and parses them into\n// telegraf metrics.\nfunc (n *NatsConsumer) receiver(ctx context.Context) {\n\tfor {\n\t\t// Acquire a semaphore to block consumption if the number of undelivered messages\n\t\t// reached it's limit\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase n.sem <- empty{}:\n\t\t}\n\n\t\t// Consume messages and errors\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase err := <-n.errs:\n\t\t\tn.Log.Error(err)\n\t\tcase msg := <-n.in:\n\t\t\tjetstreamMsg := slices.Contains(n.jsSubs, msg.Sub)\n\n\t\t\tif jetstreamMsg {\n\t\t\t\tif err := msg.InProgress(); err != nil {\n\t\t\t\t\tn.Log.Warnf(\"Failed to mark JetStream message as in progress on subject %s: %v\", msg.Subject, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Parse the metric and add it to the accumulator\n\t\t\tmetrics, err := n.parser.Parse(msg.Data)\n\t\t\tif err != nil {\n\t\t\t\tn.acc.AddError(fmt.Errorf(\"failed to handle message on subject %s: %w\", msg.Subject, err))\n\t\t\t}\n\t\t\tif len(metrics) == 0 {\n\t\t\t\tonce.Do(func() {\n\t\t\t\t\tn.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t\t\t})\n\t\t\t\t<-n.sem\n\t\t\t\tif jetstreamMsg {\n\t\t\t\t\tif err := msg.Ack(); err != nil {\n\t\t\t\t\t\tn.acc.AddError(fmt.Errorf(\"failed to acknowledge JetStream message on subject %s: %w\", msg.Subject, err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor _, m := range metrics {\n\t\t\t\t\tm.AddTag(\"subject\", msg.Subject)\n\t\t\t\t}\n\t\t\t\tid := n.acc.AddTrackingMetricGroup(metrics)\n\n\t\t\t\t// Make sure we manually acknowledge the messages later on delivery to Telegraf output(s)\n\t\t\t\tif jetstreamMsg {\n\t\t\t\t\tn.Lock()\n\t\t\t\t\tn.undelivered[id] = msg\n\t\t\t\t\tn.Unlock()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (n *NatsConsumer) waitForDelivery(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase track := <-n.acc.Delivered():\n\t\t\t// Get the tracked metric if any. Please remember, only Jetstream messages support a manual ACK\n\t\t\tn.Lock()\n\t\t\tmsg, ok := n.undelivered[track.ID()]\n\t\t\tdelete(n.undelivered, track.ID())\n\t\t\tn.Unlock()\n\n\t\t\tif !ok {\n\t\t\t\t<-n.sem\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif track.Delivered() {\n\t\t\t\tif err := msg.Ack(); err != nil {\n\t\t\t\t\tn.Log.Errorf(\"Failed to acknowledge JetStream message on subject %s: %v\", msg.Subject, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := msg.Term(); err != nil {\n\t\t\t\t\tn.Log.Errorf(\"Failed to terminate JetStream message on subject %s: %v\", msg.Subject, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\t<-n.sem\n\t\t}\n\t}\n}\n\nfunc (n *NatsConsumer) clean() {\n\tfor _, sub := range n.subs {\n\t\tif err := sub.Unsubscribe(); err != nil {\n\t\t\tn.Log.Errorf(\"Error unsubscribing from subject %s in queue %s: %s\",\n\t\t\t\tsub.Subject, sub.Queue, err)\n\t\t}\n\t}\n\n\tfor _, sub := range n.jsSubs {\n\t\tif err := sub.Unsubscribe(); err != nil {\n\t\t\tn.Log.Errorf(\"Error unsubscribing from subject %s in queue %s: %s\",\n\t\t\t\tsub.Subject, sub.Queue, err)\n\t\t}\n\t}\n\n\tif n.conn != nil && !n.conn.IsClosed() {\n\t\tn.conn.Close()\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"nats_consumer\", func() telegraf.Input {\n\t\treturn &NatsConsumer{\n\t\t\tServers:                []string{\"nats://localhost:4222\"},\n\t\t\tSubjects:               []string{\"telegraf\"},\n\t\t\tQueueGroup:             \"telegraf_consumers\",\n\t\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nats_consumer/nats_consumer_test.go",
    "content": "package nats_consumer\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nats-io/nats.go\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIntegrationStartStop(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"nats\",\n\t\tExposedPorts: []string{\"4222\"},\n\t\tWaitingFor:   wait.ForLog(\"Server is ready\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\tplugin := &NatsConsumer{\n\t\tServers:                []string{\"nats://\" + container.Address + \":\" + container.Ports[\"4222\"]},\n\t\tSubjects:               []string{\"telegraf\"},\n\t\tQueueGroup:             \"telegraf_consumers\",\n\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tLog:                    testutil.Logger{},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tplugin.Stop()\n}\n\nfunc TestIntegrationSendReceive(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"nats\",\n\t\tExposedPorts: []string{\"4222\"},\n\t\tWaitingFor:   wait.ForLog(\"Server is ready\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\taddr := \"nats://\" + container.Address + \":\" + container.Ports[\"4222\"]\n\n\ttests := []struct {\n\t\tname     string\n\t\tmsgs     map[string][]string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"single message\",\n\t\t\tmsgs: map[string][]string{\n\t\t\t\t\"telegraf\": {\"test,source=foo value=42i\"},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"foo\",\n\t\t\t\t\t\t\"subject\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": int64(42)},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple message\",\n\t\t\tmsgs: map[string][]string{\n\t\t\t\t\"telegraf\": {\n\t\t\t\t\t\"test,source=foo value=42i\",\n\t\t\t\t\t\"test,source=bar value=23i\",\n\t\t\t\t},\n\t\t\t\t\"hitchhiker\": {\n\t\t\t\t\t\"wale,part=front named=true\",\n\t\t\t\t\t\"wale,part=back named=false\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"foo\",\n\t\t\t\t\t\t\"subject\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": int64(42)},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"test\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":  \"bar\",\n\t\t\t\t\t\t\"subject\": \"telegraf\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": int64(23)},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"wale\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"part\":    \"front\",\n\t\t\t\t\t\t\"subject\": \"hitchhiker\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"named\": true},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"wale\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"part\":    \"back\",\n\t\t\t\t\t\t\"subject\": \"hitchhiker\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"named\": false},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tsubjects := make([]string, 0, len(tt.msgs))\n\t\t\tfor k := range tt.msgs {\n\t\t\t\tsubjects = append(subjects, k)\n\t\t\t}\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &NatsConsumer{\n\t\t\t\tServers:                []string{addr},\n\t\t\t\tSubjects:               subjects,\n\t\t\t\tQueueGroup:             \"telegraf_consumers\",\n\t\t\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\t\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\t\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\t\t\tLog:                    testutil.Logger{},\n\t\t\t}\n\n\t\t\t// Add a line-protocol parser\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tplugin.SetParser(parser)\n\n\t\t\t// Startup the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Send all messages to the topics (random order due to Golang map)\n\t\t\tpublisher := &sender{addr: addr}\n\t\t\trequire.NoError(t, publisher.connect())\n\t\t\tdefer publisher.disconnect()\n\t\t\tfor topic, msgs := range tt.msgs {\n\t\t\t\tfor _, msg := range msgs {\n\t\t\t\t\trequire.NoError(t, publisher.send(topic, msg))\n\t\t\t\t}\n\t\t\t}\n\t\t\tpublisher.disconnect()\n\n\t\t\t// Wait for the metrics to be collected\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, time.Second, 100*time.Millisecond)\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n\n\t\t\tplugin.Lock()\n\t\t\tdefer plugin.Unlock()\n\t\t\trequire.Empty(t, plugin.undelivered)\n\t\t})\n\t}\n}\n\nfunc TestJetStreamIntegrationSendReceive(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"nats\",\n\t\tExposedPorts: []string{\"4222\"},\n\t\tCmd:          []string{\"-js\"},\n\t\tWaitingFor:   wait.ForLog(\"Server is ready\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\taddr := \"nats://\" + container.Address + \":\" + container.Ports[\"4222\"]\n\n\t// Add a JetStream stream for testing\n\tnc, err := nats.Connect(addr)\n\trequire.NoError(t, err)\n\tdefer nc.Close()\n\tjs, err := nc.JetStream()\n\trequire.NoError(t, err)\n\n\tstreamName := \"TESTSTREAM\"\n\tsubject := \"telegraf\"\n\t_, err = js.AddStream(&nats.StreamConfig{\n\t\tName:     streamName,\n\t\tSubjects: []string{subject},\n\t})\n\trequire.NoError(t, err)\n\n\t// Setup the plugin for JetStream\n\tlog := testutil.CaptureLogger{}\n\tplugin := &NatsConsumer{\n\t\tServers:                []string{addr},\n\t\tJsSubjects:             []string{subject},\n\t\tJsStream:               streamName,\n\t\tQueueGroup:             \"telegraf_consumers\",\n\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tLog:                    &log,\n\t}\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Publish a message to JetStream\n\tmsg := \"test,source=js value=99i\"\n\t_, err = js.Publish(subject, []byte(msg))\n\trequire.NoError(t, err)\n\n\t// Wait for the metric to be collected\n\trequire.Eventually(t, func() bool {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.NMetrics() >= 1\n\t}, time.Second, 100*time.Millisecond)\n\n\tactual := acc.GetTelegrafMetrics()\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":  \"js\",\n\t\t\t\t\"subject\": subject,\n\t\t\t},\n\t\t\tmap[string]interface{}{\"value\": int64(99)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())\n\n\t// Acknowledge the message and check undelivered tracking\n\tlog.Clear()\n\tplugin.Lock()\n\trequire.Len(t, plugin.undelivered, 1)\n\tplugin.Unlock()\n\tfor _, m := range actual {\n\t\tm.Accept()\n\t}\n\n\trequire.Eventually(t, func() bool {\n\t\tplugin.Lock()\n\t\tdefer plugin.Unlock()\n\t\treturn len(plugin.undelivered) == 0\n\t}, time.Second, 100*time.Millisecond, \"undelivered messages not cleared\")\n\n\trequire.Empty(t, log.Messages(), \"no warnings or errors should be logged\")\n}\n\nfunc TestJetStreamIntegrationSourcedStreamNotFound(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"nats\",\n\t\tExposedPorts: []string{\"4222\"},\n\t\tCmd:          []string{\"-js\"},\n\t\tWaitingFor:   wait.ForLog(\"Server is ready\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\taddr := \"nats://\" + container.Address + \":\" + container.Ports[\"4222\"]\n\n\t// Add a JetStream stream for testing\n\tnc, err := nats.Connect(addr)\n\trequire.NoError(t, err)\n\tdefer nc.Close()\n\tjs, err := nc.JetStream()\n\trequire.NoError(t, err)\n\n\t// Create a stream with no subject\n\tstreamName := \"TESTSTREAM\"\n\t_, err = js.AddStream(&nats.StreamConfig{\n\t\tName: streamName,\n\t\tSources: []*nats.StreamSource{\n\t\t\t{Name: \"NONEXISTENT\"},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\n\t// Setup the plugin for JetStream\n\tplugin := &NatsConsumer{\n\t\tServers:                []string{addr},\n\t\tJsSubjects:             []string{\"TESTSTREAM\"},\n\t\tQueueGroup:             \"telegraf_consumers\",\n\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tLog:                    testutil.Logger{},\n\t}\n\n\t// Add a line-protocol parser\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Startup the plugin\n\tvar acc testutil.Accumulator\n\terr = plugin.Start(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"no stream matches subject\")\n}\n\nfunc TestJetStreamIntegrationSourcedStreamFound(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"nats\",\n\t\tExposedPorts: []string{\"4222\"},\n\t\tCmd:          []string{\"-js\"},\n\t\tWaitingFor:   wait.ForLog(\"Server is ready\"),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\taddr := \"nats://\" + container.Address + \":\" + container.Ports[\"4222\"]\n\n\t// Add a JetStream stream for testing\n\tnc, err := nats.Connect(addr)\n\trequire.NoError(t, err)\n\tdefer nc.Close()\n\tjs, err := nc.JetStream()\n\trequire.NoError(t, err)\n\n\t// Create a stream with no subject\n\tstreamName := \"TESTSTREAM\"\n\t_, err = js.AddStream(&nats.StreamConfig{\n\t\tName: streamName,\n\t\tSources: []*nats.StreamSource{\n\t\t\t{Name: \"NONEXISTENT\"},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\n\t// Setup the plugin for JetStream\n\tplugin := &NatsConsumer{\n\t\tServers:                []string{addr},\n\t\tJsSubjects:             []string{\"TESTSTREAM\"},\n\t\tJsStream:               streamName,\n\t\tQueueGroup:             \"telegraf_consumers\",\n\t\tPendingBytesLimit:      nats.DefaultSubPendingBytesLimit,\n\t\tPendingMessageLimit:    nats.DefaultSubPendingMsgsLimit,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tLog:                    testutil.Logger{},\n\t}\n\n\t// Add a line-protocol parser\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Startup the plugin\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tplugin.Stop()\n}\n\ntype sender struct {\n\taddr string\n\tconn *nats.Conn\n}\n\nfunc (s *sender) connect() error {\n\tconn, err := nats.Connect(s.addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.conn = conn\n\n\treturn nil\n}\n\nfunc (s *sender) disconnect() {\n\tif s.conn != nil && !s.conn.IsClosed() {\n\t\t_ = s.conn.Flush()\n\t\ts.conn.Close()\n\t}\n\ts.conn = nil\n}\n\nfunc (s *sender) send(topic, msg string) error {\n\treturn s.conn.Publish(topic, []byte(msg))\n}\n"
  },
  {
    "path": "plugins/inputs/nats_consumer/sample.conf",
    "content": "# Read metrics from NATS subject(s)\n[[inputs.nats_consumer]]\n  ## urls of NATS servers\n  servers = [\"nats://localhost:4222\"]\n\n  ## subject(s) to consume\n  ## If you use jetstream you need to set the subjects\n  ## in jetstream_subjects\n  subjects = [\"telegraf\"]\n\n  ## jetstream subjects\n  ## jetstream is a streaming technology inside of nats.\n  ## With jetstream the nats-server persists messages and\n  ## a consumer can consume historical messages. This is\n  ## useful when telegraf needs to restart it don't miss a\n  ## message. You need to configure the nats-server.\n  ## https://docs.nats.io/nats-concepts/jetstream.\n  jetstream_subjects = [\"js_telegraf\"]\n\n  ## explicitly specify the jetstream stream name\n  ## useful for sourced streams where there is no subject defined and\n  ## thus jetstream_subjects won't work\n  jetstream_stream = \"\"\n\n  ## name a queue group\n  queue_group = \"telegraf_consumers\"\n\n  ## Optional authentication with username and password credentials\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional authentication with NATS credentials file (NATS 2.0)\n  # credentials = \"/etc/telegraf/nats.creds\"\n\n  ## Optional authentication with nkey seed file (NATS 2.0)\n  # nkey_seed = \"/etc/telegraf/seed.txt\"\n\n  ## Use Transport Layer Security\n  # secure = false\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Sets the limits for pending msgs and bytes for each subscription\n  ## These shouldn't need to be adjusted except in very high throughput scenarios\n  # pending_message_limit = 65536\n  # pending_bytes_limit = 67108864\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/README.md",
    "content": "# Neoom Beaam Input Plugin\n\nThis plugin gathers metrics from a [Neoom Beaam gateway][beaam] using the\n[Beaam API][beaam_api] with access token that can be created in the Neoom web\ninterface. Please follow the [developer instructions][devpage] to create the\ntoken.\n\n⭐ Telegraf v1.33.0\n🏷️ iot\n💻 all\n\n[beaam]: https://neoom.com/en/products/beaam\n[beaam_api]: https://developer.neoom.com/reference/concepts-terms-1\n[devpage]:https://neoom.com/developers\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `token` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read energy data from the local Neoom Beaam gateway\n[[inputs.neoom_beaam]]\n  ## Address of the gateway\n  # address = \"https://10.10.10.10\"\n\n  ## Bearer token for accessing the data\n  # token = \"\"\n\n  ## Enforce refreshing the site configuration in each gather cycle\n  # refresh_configuration = false\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Example Output\n\nFor energy flow metrics:\n\n```text\nneoom_beaam_energy_flow,datapoint=SELF_SUFFICIENCY,source=127.0.0.1,unit=% value=100 1723883145024999936\nneoom_beaam_energy_flow,datapoint=POWER_PRODUCTION,source=127.0.0.1,unit=W value=1184 1723883150001999872\nneoom_beaam_energy_flow,datapoint=POWER_GRID,source=127.0.0.1,unit=W value=15 1723883150001999872\nneoom_beaam_energy_flow,datapoint=POWER_STORAGE,source=127.0.0.1,unit=W value=3504 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_PRODUCED,source=127.0.0.1,unit=Wh value=639300 1723882905007000064\nneoom_beaam_energy_flow,datapoint=ENERGY_IMPORTED,source=127.0.0.1,unit=Wh value=22696.926152777138 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_EXPORTED,source=127.0.0.1,unit=Wh value=237421.33112499933 1723883135003000064\nneoom_beaam_energy_flow,datapoint=ENERGY_CHARGED,source=127.0.0.1,unit=Wh value=215200 1723882765001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_DISCHARGED,source=127.0.0.1,unit=Wh value=144800 1723880490004999936\nneoom_beaam_energy_flow,datapoint=STATE_OF_CHARGE,source=127.0.0.1,unit=% value=59 1723883090001999872\nneoom_beaam_energy_flow,datapoint=POWER_CONSUMPTION_CALC,source=127.0.0.1,unit=W value=4703 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_CONSUMED_CALC,source=127.0.0.1,unit=Wh value=354175.59502777783 1723883150001999872\n```\n\nfor thing (aka device) metrics\n\n```text\nneoom_beaam_thing,datapoint=CONNECTION,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=None value=true 1723890960060000000\nneoom_beaam_thing,datapoint=VOLTAGE_P1,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=245 1723905135056000000\nneoom_beaam_thing,datapoint=VOLTAGE_P2,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=242.3 1723905135056000000\nneoom_beaam_thing,datapoint=VOLTAGE_P3,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=245.5 1723905135056000000\nneoom_beaam_thing,datapoint=FREQUENCY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Hz value=49.98 1723905135056000000\nneoom_beaam_thing,datapoint=ACTIVE_POWER,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-826 1723905135056000000\nneoom_beaam_thing,datapoint=OUTPUT_ENERGY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Wh value=241826.44736444377 1723905135075000064\nneoom_beaam_thing,datapoint=INPUT_ENERGY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Wh value=22988.396324999278 1723904090096000000\nneoom_beaam_thing,datapoint=POWER_P1,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-305 1723905135056000000\nneoom_beaam_thing,datapoint=POWER_P2,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-268 1723905135056000000\nneoom_beaam_thing,datapoint=POWER_P3,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-214 1723905135056000000\n```\n\n## Metrics\n\n- neoom_beaam_energy_flow\n  - tags:\n    - source (address of gateway)\n    - datapoint (name of the datapoint)\n    - unit (unit of the measurement)\n  - fields:\n    - value (value of the datapoint)\n\n- neoom_beaam_thing\n  - tags:\n    - source (address of gateway)\n    - thing (name of the device)\n    - datapoint (name of the datapoint)\n    - unit (unit of the measurement)\n  - fields:\n    - value (value of the datapoint)\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/neoom_beaam.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage neoom_beaam\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tchttp \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NeoomBeaam struct {\n\tAddress       string          `toml:\"address\"`\n\tToken         config.Secret   `toml:\"token\"`\n\tRefreshConfig bool            `toml:\"refresh_configuration\"`\n\tLog           telegraf.Logger `toml:\"-\"`\n\tchttp.HTTPClientConfig\n\n\tsource string\n\tconfig site\n\tclient *http.Client\n}\n\nfunc (*NeoomBeaam) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NeoomBeaam) Init() error {\n\tif n.Address == \"\" {\n\t\tn.Address = \"https://10.10.10.10\"\n\t}\n\tn.Address = strings.TrimRight(n.Address, \"/\")\n\n\tu, err := url.Parse(n.Address)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing of address %q failed: %w\", n.Address, err)\n\t}\n\tn.source = u.Hostname()\n\n\treturn nil\n}\n\nfunc (n *NeoomBeaam) Start(telegraf.Accumulator) error {\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\tn.client = client\n\n\t// Initialize configuration\n\treturn n.updateConfiguration()\n}\n\nfunc (n *NeoomBeaam) Gather(acc telegraf.Accumulator) error {\n\t// Refresh the config if requested\n\tif n.RefreshConfig {\n\t\tif err := n.updateConfiguration(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Query the energy flow\n\tif err := n.queryEnergyFlow(acc); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"querying site state failed: %w\", err))\n\t}\n\n\t// Query all known things\n\tfor _, thing := range n.config.Things {\n\t\tif err := n.queryThing(acc, thing); err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"querying thing %q (%s) failed: %w\", thing.Name, thing.id, err))\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *NeoomBeaam) Stop() {\n\tif n.client != nil {\n\t\tn.client.CloseIdleConnections()\n\t}\n}\n\nfunc (n *NeoomBeaam) updateConfiguration() error {\n\tendpoint := n.Address + \"/api/v1/site/configuration\"\n\trequest, err := http.NewRequest(\"GET\", endpoint, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating configuration request failed: %w\", err)\n\t}\n\n\tif !n.Token.Empty() {\n\t\ttoken, err := n.Token.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting token failed: %w\", err)\n\t\t}\n\t\tbearer := \"Bearer \" + strings.TrimSpace(token.String())\n\t\ttoken.Destroy()\n\t\trequest.Header.Set(\"Authorization\", bearer)\n\t}\n\trequest.Header.Set(\"Accept\", \"application/json\")\n\n\t// Update the configuration\n\tresponse, err := n.client.Do(request)\n\tif err != nil {\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"querying configuration failed: %w\", err),\n\t\t\tRetry: true,\n\t\t}\n\t}\n\tdefer response.Body.Close()\n\n\tbody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading body failed: %w\", err)\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"configuration query returned %q: %s\", response.Status, string(body)),\n\t\t\tRetry: 400 <= response.StatusCode && response.StatusCode <= 499,\n\t\t}\n\t}\n\n\tif err := json.Unmarshal(body, &n.config); err != nil {\n\t\treturn fmt.Errorf(\"decoding configuration failed: %w\", err)\n\t}\n\n\tfor id, thing := range n.config.Things {\n\t\tthing.id = id\n\t\tn.config.Things[id] = thing\n\t}\n\n\treturn nil\n}\n\nfunc (n *NeoomBeaam) queryEnergyFlow(acc telegraf.Accumulator) error {\n\t// Create the request\n\tendpoint := n.Address + \"/api/v1/site/state\"\n\trequest, err := http.NewRequest(\"GET\", endpoint, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\n\tif !n.Token.Empty() {\n\t\ttoken, err := n.Token.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting token failed: %w\", err)\n\t\t}\n\t\tbearer := \"Bearer \" + strings.TrimSpace(token.String())\n\t\ttoken.Destroy()\n\t\trequest.Header.Set(\"Authorization\", bearer)\n\t}\n\trequest.Header.Set(\"Accept\", \"application/json\")\n\n\t// Execute query\n\tresponse, err := n.client.Do(request)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying failed: %w\", err)\n\t}\n\tdefer response.Body.Close()\n\n\t// Handle response\n\tbody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading body failed: %w\", err)\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"query returned %q: %s\", response.Status, string(body))\n\t}\n\n\t// Decode the data and create metric\n\tvar data siteState\n\tif err := json.Unmarshal(body, &data); err != nil {\n\t\treturn fmt.Errorf(\"decoding failed: %w\", err)\n\t}\n\n\tfor _, s := range data.EnergyFlow.States {\n\t\tif s.Value == nil {\n\t\t\tn.Log.Debugf(\"omitting data point %q (%s) due to 'null' value\", s.Key, s.DataPointID)\n\t\t\tcontinue\n\t\t}\n\n\t\tdp, ok := n.config.EnergyFlow.DataPoints[s.DataPointID]\n\t\tif !ok {\n\t\t\tn.Log.Errorf(\"no data point definition for ID %q\", s.DataPointID)\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"source\":    n.source,\n\t\t\t\"datapoint\": s.Key,\n\t\t\t\"unit\":      dp.Unit,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": s.Value,\n\t\t}\n\t\tts := time.Unix(0, int64(s.Timestamp*float64(time.Millisecond)))\n\t\tacc.AddFields(\"neoom_beaam_energy_flow\", fields, tags, ts)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NeoomBeaam) queryThing(acc telegraf.Accumulator, thing thingDefinition) error {\n\t// Create the request\n\tendpoint := n.Address + \"/api/v1/things/\" + thing.id + \"/states\"\n\trequest, err := http.NewRequest(\"GET\", endpoint, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\n\tif !n.Token.Empty() {\n\t\ttoken, err := n.Token.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting token failed: %w\", err)\n\t\t}\n\t\tbearer := \"Bearer \" + strings.TrimSpace(token.String())\n\t\ttoken.Destroy()\n\t\trequest.Header.Set(\"Authorization\", bearer)\n\t}\n\trequest.Header.Set(\"Accept\", \"application/json\")\n\n\t// Execute query\n\tresponse, err := n.client.Do(request)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying failed: %w\", err)\n\t}\n\tdefer response.Body.Close()\n\n\t// Handle response\n\tbody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading body failed: %w\", err)\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"query returned %q: %s\", response.Status, string(body))\n\t}\n\n\t// Decode the data and create metric\n\tvar data thingState\n\tif err := json.Unmarshal(body, &data); err != nil {\n\t\treturn fmt.Errorf(\"decoding failed: %w\", err)\n\t}\n\n\tfor _, s := range data.States {\n\t\tif s.Value == nil {\n\t\t\tn.Log.Debugf(\"omitting data point %q (%s) due to 'null' value\", s.Key, s.DataPointID)\n\t\t\tcontinue\n\t\t}\n\n\t\tdp, ok := thing.DataPoints[s.DataPointID]\n\t\tif !ok {\n\t\t\tn.Log.Errorf(\"no data point definition for ID %q\", s.DataPointID)\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"source\":    n.source,\n\t\t\t\"thing\":     thing.Name,\n\t\t\t\"datapoint\": s.Key,\n\t\t\t\"unit\":      dp.Unit,\n\t\t}\n\t\tvar fields map[string]interface{}\n\t\tif elements, ok := s.Value.([]interface{}); ok {\n\t\t\tfields = make(map[string]interface{}, len(elements))\n\t\t\tfor i, v := range elements {\n\t\t\t\tfields[\"value_\"+strconv.Itoa(i)] = v\n\t\t\t}\n\t\t} else {\n\t\t\tfields = map[string]interface{}{\n\t\t\t\t\"value\": s.Value,\n\t\t\t}\n\t\t}\n\n\t\tts := time.Unix(0, int64(s.Timestamp*float64(time.Millisecond)))\n\t\tacc.AddFields(\"neoom_beaam_thing\", fields, tags, ts)\n\t}\n\n\treturn nil\n}\n\n// Register the plugin\nfunc init() {\n\tinputs.Add(\"neoom_beaam\", func() telegraf.Input {\n\t\treturn &NeoomBeaam{\n\t\t\tHTTPClientConfig: chttp.HTTPClientConfig{\n\t\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\t\tTransportConfig: chttp.TransportConfig{\n\t\t\t\t\tResponseHeaderTimeout: config.Duration(5 * time.Second),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/neoom_beaam_test.go",
    "content": "package neoom_beaam\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"neoom_beaam\", func() telegraf.Input {\n\t\treturn &NeoomBeaam{}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\tinputFiles := filepath.Join(testcasePath, \"*.json\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tmatches, err := filepath.Glob(inputFiles)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, matches)\n\t\t\tsort.Strings(matches)\n\t\t\tendpoints := make(map[string][]byte, len(matches))\n\t\t\tfor _, fn := range matches {\n\t\t\t\tbuf, err := os.ReadFile(fn)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tkey := strings.TrimSuffix(filepath.Base(fn), filepath.Ext(fn))\n\t\t\t\tif strings.HasPrefix(key, \"thing_\") {\n\t\t\t\t\tendpoints[\"/api/v1/things/\"+strings.TrimPrefix(key, \"thing_\")+\"/states\"] = buf\n\t\t\t\t} else {\n\t\t\t\t\tendpoints[\"/api/v1/site/\"+key] = buf\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Create a fake API server\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif msg, ok := endpoints[r.URL.Path]; ok {\n\t\t\t\t\tif _, err := w.Write(msg); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Load the configuration\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup and start the plugin\n\t\t\tplugin := cfg.Inputs[0].Input.(*NeoomBeaam)\n\t\t\tplugin.Address = server.URL\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(nil))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Gather the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/sample.conf",
    "content": "# Read energy data from the local Neoom Beaam gateway\n[[inputs.neoom_beaam]]\n  ## Address of the gateway\n  # address = \"https://10.10.10.10\"\n\n  ## Bearer token for accessing the data\n  # token = \"\"\n\n  ## Enforce refreshing the site configuration in each gather cycle\n  # refresh_configuration = false\n\n  ## Optional TLS Config\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/sample.conf.in",
    "content": "# Read energy data from the local Neoom Beaam gateway\n[[inputs.neoom_beaam]]\n  ## Address of the gateway\n  # address = \"https://10.10.10.10\"\n\n  ## Bearer token for accessing the data\n  # token = \"\"\n\n  ## Enforce refreshing the site configuration in each gather cycle\n  # refresh_configuration = false\n\n  ## Optional TLS Config\n{{template \"/plugins/common/tls/client.conf\"}}\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/configuration.json",
    "content": "{\n    \"siteId\": \"11111111-aaaa-1111-aaaa-222222222222\",\n    \"versionTimestamp\": 1721051934,\n    \"siteInfo\": {\n        \"gridConnections\": {},\n        \"geoCoordinates\": {\n            \"latitude\": 48.488256,\n            \"longitude\": 14.4954532\n        }\n    },\n    \"things\": {\n        \"22222222-bbbb-2222-bbbb-222222222222\": {\n            \"type\": \"INVERTER\",\n            \"dataPoints\": {\n                \"f788ab8b-96d0-5efb-bda7-5214a92418f1\": {\n                    \"key\": \"CONNECTION\",\n                    \"dataType\": \"BOOLEAN\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"3d2cf2d0-9c79-583b-b915-f980d0c64817\": {\n                    \"key\": \"GRID_FEED_IN_LIMIT\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"fb898be0-82f0-5a04-a6f4-e303754cb00c\": {\n                    \"key\": \"MAX_POWER_GENERATION_AC\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"c0aecdd7-e7f2-52ac-a972-35909c1ac938\": {\n                    \"key\": \"STATE_CODE\",\n                    \"dataType\": \"STRING\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"a8aa1122-af0b-5239-9236-73a61d435687\": {\n                    \"key\": \"ACTIVE_POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"15353bf6-cff1-5182-b299-22cc20762b29\": {\n                    \"key\": \"REACTIVE_POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"VAr\"\n                },\n                \"ade3343d-333e-58e5-94d6-14d54d44620d\": {\n                    \"key\": \"INPUTS_POWER\",\n                    \"dataType\": \"NUMBER_ARRAY[]\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"15de38ea-2c10-5f64-a991-3a3f011c6c23\": {\n                    \"key\": \"PRODUCED_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                }\n            }\n        },\n        \"33333333-cccc-3333-cccc-333333333333\": {\n            \"type\": \"BATTERY\",\n            \"dataPoints\": {\n                \"7748ed36-8535-530c-bf4d-de0f300a8adb\": {\n                    \"key\": \"CONNECTION\",\n                    \"dataType\": \"BOOLEAN\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"b4d3ceeb-71f9-5677-ba4f-ac368b8dbd3b\": {\n                    \"key\": \"EPS_MODE_ACTIVE\",\n                    \"dataType\": \"BOOLEAN\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"f968a39d-b988-523c-a6d7-ccd1436bfb77\": {\n                    \"key\": \"MAX_CURRENT_CHARGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"A\"\n                },\n                \"d51f9cea-4ed0-556d-ba7c-e8f82ceaf7d0\": {\n                    \"key\": \"MAX_CURRENT_DISCHARGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"A\"\n                },\n                \"5e0188c0-0d26-5158-b837-536a1d8c715f\": {\n                    \"key\": \"OPERATING_MODE\",\n                    \"dataType\": \"STRING\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"9df68d84-f679-528c-ad41-4e041d46b6f8\": {\n                    \"key\": \"OPERATING_MODES\",\n                    \"dataType\": \"STRING_ARRAY[]\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"8eeb33e5-5c2e-59fa-9d91-c9d12dc833f4\": {\n                    \"key\": \"MIN_SOC_SELF_CONSUMPTION_OPT\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"%\"\n                },\n                \"f2ea90d0-ca70-5b2d-a5fe-7a62b180e987\": {\n                    \"key\": \"MIN_SOC\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"%\"\n                },\n                \"d7917007-a8cd-5d8e-8e92-f80237406aad\": {\n                    \"key\": \"TARGET_POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"94c7f11d-2489-5973-8eaf-57de93426d1b\": {\n                    \"key\": \"VOLTAGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"V\"\n                },\n                \"932f9b7f-4e10-5506-a73a-e8679c3e699f\": {\n                    \"key\": \"CURRENT\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"A\"\n                },\n                \"9c64cb00-b204-5f1a-8a58-a10d4343fb12\": {\n                    \"key\": \"POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"a8725a08-f4b5-5cd3-b54f-bd1a879754c9\": {\n                    \"key\": \"CELL_TEMPERATURE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"°C\"\n                },\n                \"61740954-99e3-5bd2-a530-c0aa59501d2b\": {\n                    \"key\": \"STATE_OF_CHARGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"%\"\n                },\n                \"899099f9-6ebe-5040-93a6-de0db44f19fb\": {\n                    \"key\": \"ERROR_CODES\",\n                    \"dataType\": \"STRING_ARRAY[]\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"6187ec40-ba60-5ec4-9e8a-a4daf5288124\": {\n                    \"key\": \"CHARGED_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                },\n                \"1e1b3efa-f957-51b6-8d35-2de5d682f554\": {\n                    \"key\": \"DISCHARGED_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                },\n                \"a82404ae-a4a5-5a08-86ba-c487dcad55ef\": {\n                    \"key\": \"MAX_POWER_CHARGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"59821d14-13c8-5363-87c1-508095feb2b7\": {\n                    \"key\": \"MAX_POWER_DISCHARGE\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"f57323b8-4874-58a6-91f9-a9f7c5568a67\": {\n                    \"key\": \"DESIRED_SOC\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"%\"\n                }\n            }\n        },\n        \"44444444-dddd-4444-dddd-444444444444\": {\n            \"type\": \"PV\",\n            \"dataPoints\": {\n                \"244fa23e-cdbc-5d7d-a3e9-788af3ab43d2\": {\n                    \"key\": \"CONNECTIONS\",\n                    \"dataType\": \"BOOLEAN_ARRAY[]\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"d064a7fc-4b9a-5cf4-a55f-eeda5289afac\": {\n                    \"key\": \"POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"44763dab-6224-5b2a-aadf-d5afd781cdd5\": {\n                    \"key\": \"PRODUCED_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                },\n                \"892e0390-252d-5fb5-9857-04924f1770e1\": {\n                    \"key\": \"VOLTAGES\",\n                    \"dataType\": \"NUMBER_ARRAY[]\",\n                    \"unitOfMeasure\": \"V\"\n                },\n                \"a153ab79-3cf2-5f17-ab40-9af3c38d7e60\": {\n                    \"key\": \"CURRENTS\",\n                    \"dataType\": \"NUMBER_ARRAY[]\",\n                    \"unitOfMeasure\": \"A\"\n                }\n            }\n        },\n        \"55555555-eeee-5555-eeee-555555555555\": {\n            \"type\": \"ELECTRICITY_METER_AC\",\n            \"dataPoints\": {\n                \"094a8ac0-914f-5f0d-a376-d2e3abfdc75e\": {\n                    \"key\": \"CONNECTION\",\n                    \"dataType\": \"BOOLEAN\",\n                    \"unitOfMeasure\": \"None\"\n                },\n                \"22911bdc-0b2f-5008-9d42-c551d4fa53c7\": {\n                    \"key\": \"VOLTAGE_P1\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"V\"\n                },\n                \"4e34e4eb-0859-5253-81ae-9d536e75c003\": {\n                    \"key\": \"VOLTAGE_P2\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"V\"\n                },\n                \"a45c0fe9-42e8-5091-9007-ff73d55a149b\": {\n                    \"key\": \"VOLTAGE_P3\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"V\"\n                },\n                \"755e91d4-f6c6-5570-a2bf-623b20055816\": {\n                    \"key\": \"FREQUENCY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Hz\"\n                },\n                \"c7b812ba-e08b-5f4a-bcd4-97616c8130bc\": {\n                    \"key\": \"ACTIVE_POWER\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"3f4105ab-bdf8-5d0b-88ba-9859dcf3f111\": {\n                    \"key\": \"OUTPUT_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                },\n                \"6ddbb838-0557-5df0-bdeb-489f426248fb\": {\n                    \"key\": \"INPUT_ENERGY\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"Wh\"\n                },\n                \"b89fda1c-f19a-5da0-bcbd-4277eb377b3a\": {\n                    \"key\": \"POWER_P1\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"64fd2faa-13ca-5cc4-8302-3085f13775c8\": {\n                    \"key\": \"POWER_P2\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                },\n                \"eca4dacc-1858-50f1-ac46-30cddcde75a2\": {\n                    \"key\": \"POWER_P3\",\n                    \"dataType\": \"NUMBER\",\n                    \"unitOfMeasure\": \"W\"\n                }\n            }\n        }\n    },\n    \"energyFlow\": {\n        \"dataPoints\": {\n            \"27291fe9-b44a-5530-92cf-1fad478f6f66\": {\n                \"key\": \"SELF_SUFFICIENCY\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"%\"\n            },\n            \"211f490a-af77-5c33-af3f-fd2e67e40b3f\": {\n                \"key\": \"POWER_PRODUCTION\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"58d84d20-ba7c-5218-9045-459e4a946080\": {\n                \"key\": \"POWER_CONSUMPTION\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"2548caa8-0288-559c-9e75-50b964f4bf01\": {\n                \"key\": \"POWER_GRID\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"b9399b12-e3bb-5515-9b1a-640bd51c1c1b\": {\n                \"key\": \"POWER_STORAGE\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"49764da7-5486-52bf-9867-66643445d7fb\": {\n                \"key\": \"ENERGY_PRODUCED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"eb0f0b1f-73cc-5cb8-864d-baa11b8628c4\": {\n                \"key\": \"ENERGY_CONSUMED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"3dd29b23-eb88-538a-8220-ccd7192d4fef\": {\n                \"key\": \"ENERGY_IMPORTED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"804a496b-267b-5783-850d-b43ecc1b6f9c\": {\n                \"key\": \"ENERGY_EXPORTED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"25aac409-c380-575f-8429-6a33de6bec3e\": {\n                \"key\": \"ENERGY_CHARGED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"42aebe59-8b2c-58fa-a222-991e88451376\": {\n                \"key\": \"ENERGY_DISCHARGED\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            },\n            \"d40db932-df55-57c9-955b-2528a4df4d73\": {\n                \"key\": \"STATE_OF_CHARGE\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"%\"\n            },\n            \"6a7fe53b-65c1-576b-8159-bd79d1fd7651\": {\n                \"key\": \"POWER_CONSUMPTION_CALC\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"adf97bab-6a8f-543a-8dab-a7459cc977e7\": {\n                \"key\": \"POWER_GRID_REMAINING\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"W\"\n            },\n            \"df4668c6-6d3f-5837-a7c7-e7aaa408f068\": {\n                \"key\": \"ENERGY_CONSUMED_CALC\",\n                \"dataType\": \"NUMBER\",\n                \"unitOfMeasure\": \"Wh\"\n            }\n        }\n    },\n    \"externalPlantControls\": {}\n}"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/expected.out",
    "content": "neoom_beaam_energy_flow,datapoint=SELF_SUFFICIENCY,source=127.0.0.1,unit=% value=100 1723883145024999936\nneoom_beaam_energy_flow,datapoint=POWER_PRODUCTION,source=127.0.0.1,unit=W value=1184 1723883150001999872\nneoom_beaam_energy_flow,datapoint=POWER_GRID,source=127.0.0.1,unit=W value=15 1723883150001999872\nneoom_beaam_energy_flow,datapoint=POWER_STORAGE,source=127.0.0.1,unit=W value=3504 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_PRODUCED,source=127.0.0.1,unit=Wh value=639300 1723882905007000064\nneoom_beaam_energy_flow,datapoint=ENERGY_IMPORTED,source=127.0.0.1,unit=Wh value=22696.926152777138 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_EXPORTED,source=127.0.0.1,unit=Wh value=237421.33112499933 1723883135003000064\nneoom_beaam_energy_flow,datapoint=ENERGY_CHARGED,source=127.0.0.1,unit=Wh value=215200 1723882765001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_DISCHARGED,source=127.0.0.1,unit=Wh value=144800 1723880490004999936\nneoom_beaam_energy_flow,datapoint=STATE_OF_CHARGE,source=127.0.0.1,unit=% value=59 1723883090001999872\nneoom_beaam_energy_flow,datapoint=POWER_CONSUMPTION_CALC,source=127.0.0.1,unit=W value=4703 1723883150001999872\nneoom_beaam_energy_flow,datapoint=ENERGY_CONSUMED_CALC,source=127.0.0.1,unit=Wh value=354175.59502777783 1723883150001999872\nneoom_beaam_thing,datapoint=CONNECTION,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=None value=true 1723890960060000000\nneoom_beaam_thing,datapoint=VOLTAGE_P1,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=245 1723905135056000000\nneoom_beaam_thing,datapoint=VOLTAGE_P2,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=242.3 1723905135056000000\nneoom_beaam_thing,datapoint=VOLTAGE_P3,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=V value=245.5 1723905135056000000\nneoom_beaam_thing,datapoint=FREQUENCY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Hz value=49.98 1723905135056000000\nneoom_beaam_thing,datapoint=ACTIVE_POWER,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-826 1723905135056000000\nneoom_beaam_thing,datapoint=OUTPUT_ENERGY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Wh value=241826.44736444377 1723905135075000064\nneoom_beaam_thing,datapoint=INPUT_ENERGY,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=Wh value=22988.396324999278 1723904090096000000\nneoom_beaam_thing,datapoint=POWER_P1,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-305 1723905135056000000\nneoom_beaam_thing,datapoint=POWER_P2,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-268 1723905135056000000\nneoom_beaam_thing,datapoint=POWER_P3,source=127.0.0.1,thing=ELECTRICITY_METER_AC,unit=W value=-214 1723905135056000000\nneoom_beaam_thing,datapoint=CONNECTIONS,source=127.0.0.1,thing=PV,unit=None value_0=true,value_1=true 1723890960060000000\nneoom_beaam_thing,datapoint=POWER,source=127.0.0.1,thing=PV,unit=W value=245 1723890960060000000\nneoom_beaam_thing,datapoint=PRODUCED_ENERGY,source=127.0.0.1,thing=PV,unit=Wh value=335423.1124235639 1723890960060000000\nneoom_beaam_thing,datapoint=VOLTAGES,source=127.0.0.1,thing=PV,unit=V value_0=231.42,value_1=302.25 1723890960060000000\nneoom_beaam_thing,datapoint=CURRENTS,source=127.0.0.1,thing=PV,unit=A value_0=10.889292196,value_1=69.4789081886 1723890960060000000\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/state.json",
    "content": "{\n    \"energyFlow\": {\n        \"states\": [\n            {\n                \"dataPointId\": \"27291fe9-b44a-5530-92cf-1fad478f6f66\",\n                \"key\": \"SELF_SUFFICIENCY\",\n                \"value\": 100,\n                \"ts\": 1723883145025\n            },\n            {\n                \"dataPointId\": \"211f490a-af77-5c33-af3f-fd2e67e40b3f\",\n                \"key\": \"POWER_PRODUCTION\",\n                \"value\": 1184,\n                \"ts\": 1723883150002\n            },\n            {\n                \"dataPointId\": \"58d84d20-ba7c-5218-9045-459e4a946080\",\n                \"key\": \"POWER_CONSUMPTION\",\n                \"value\": null,\n                \"ts\": 1723877138187\n            },\n            {\n                \"dataPointId\": \"2548caa8-0288-559c-9e75-50b964f4bf01\",\n                \"key\": \"POWER_GRID\",\n                \"value\": 15,\n                \"ts\": 1723883150002\n            },\n            {\n                \"dataPointId\": \"b9399b12-e3bb-5515-9b1a-640bd51c1c1b\",\n                \"key\": \"POWER_STORAGE\",\n                \"value\": 3504,\n                \"ts\": 1723883150002\n            },\n            {\n                \"dataPointId\": \"49764da7-5486-52bf-9867-66643445d7fb\",\n                \"key\": \"ENERGY_PRODUCED\",\n                \"value\": 639300,\n                \"ts\": 1723882905007\n            },\n            {\n                \"dataPointId\": \"eb0f0b1f-73cc-5cb8-864d-baa11b8628c4\",\n                \"key\": \"ENERGY_CONSUMED\",\n                \"value\": null,\n                \"ts\": 1723877138187\n            },\n            {\n                \"dataPointId\": \"3dd29b23-eb88-538a-8220-ccd7192d4fef\",\n                \"key\": \"ENERGY_IMPORTED\",\n                \"value\": 22696.926152777138,\n                \"ts\": 1723883150002\n            },\n            {\n                \"dataPointId\": \"804a496b-267b-5783-850d-b43ecc1b6f9c\",\n                \"key\": \"ENERGY_EXPORTED\",\n                \"value\": 237421.33112499933,\n                \"ts\": 1723883135003\n            },\n            {\n                \"dataPointId\": \"25aac409-c380-575f-8429-6a33de6bec3e\",\n                \"key\": \"ENERGY_CHARGED\",\n                \"value\": 215200,\n                \"ts\": 1723882765002\n            },\n            {\n                \"dataPointId\": \"42aebe59-8b2c-58fa-a222-991e88451376\",\n                \"key\": \"ENERGY_DISCHARGED\",\n                \"value\": 144800,\n                \"ts\": 1723880490005\n            },\n            {\n                \"dataPointId\": \"d40db932-df55-57c9-955b-2528a4df4d73\",\n                \"key\": \"STATE_OF_CHARGE\",\n                \"value\": 59,\n                \"ts\": 1723883090002\n            },\n            {\n                \"dataPointId\": \"6a7fe53b-65c1-576b-8159-bd79d1fd7651\",\n                \"key\": \"POWER_CONSUMPTION_CALC\",\n                \"value\": 4703,\n                \"ts\": 1723883150002\n            },\n            {\n                \"dataPointId\": \"adf97bab-6a8f-543a-8dab-a7459cc977e7\",\n                \"key\": \"POWER_GRID_REMAINING\",\n                \"value\": null,\n                \"ts\": 1723877138187\n            },\n            {\n                \"dataPointId\": \"df4668c6-6d3f-5837-a7c7-e7aaa408f068\",\n                \"key\": \"ENERGY_CONSUMED_CALC\",\n                \"value\": 354175.59502777783,\n                \"ts\": 1723883150002\n            }\n        ]\n    }\n}"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/telegraf.conf",
    "content": "[[inputs.neoom_beaam]]\n  address = \"dummy\""
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/thing_22222222-bbbb-2222-bbbb-222222222222.json",
    "content": "{}\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/thing_33333333-cccc-3333-cccc-333333333333.json",
    "content": "{}\n"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/thing_44444444-dddd-4444-dddd-444444444444.json",
    "content": "{\n    \"thingId\": \"44444444-dddd-4444-dddd-444444444444\",\n    \"states\": [\n        {\n            \"dataPointId\": \"244fa23e-cdbc-5d7d-a3e9-788af3ab43d2\",\n            \"key\": \"CONNECTIONS\",\n            \"value\": [true, true],\n            \"ts\": 1723890960060\n        },\n        {\n            \"dataPointId\": \"d064a7fc-4b9a-5cf4-a55f-eeda5289afac\",\n            \"key\": \"POWER\",\n            \"value\": 245,\n            \"ts\": 1723890960060\n        },\n        {\n            \"dataPointId\": \"44763dab-6224-5b2a-aadf-d5afd781cdd5\",\n            \"key\": \"PRODUCED_ENERGY\",\n            \"value\": 335423.11242356391,\n            \"ts\": 1723890960060\n        },\n        {\n            \"dataPointId\": \"892e0390-252d-5fb5-9857-04924f1770e1\",\n            \"key\": \"VOLTAGES\",\n            \"value\": [231.42, 302.25],\n            \"ts\": 1723890960060\n        },\n        {\n            \"dataPointId\": \"a153ab79-3cf2-5f17-ab40-9af3c38d7e60\",\n            \"key\": \"CURRENTS\",\n            \"value\": [10.889292196, 69.4789081886],\n            \"ts\": 1723890960060\n        }\n    ]\n}"
  },
  {
    "path": "plugins/inputs/neoom_beaam/testcases/small/thing_55555555-eeee-5555-eeee-555555555555.json",
    "content": "{\n    \"thingId\": \"55555555-eeee-5555-eeee-555555555555\",\n    \"states\": [\n        {\n            \"dataPointId\": \"094a8ac0-914f-5f0d-a376-d2e3abfdc75e\",\n            \"key\": \"CONNECTION\",\n            \"value\": true,\n            \"ts\": 1723890960060\n        },\n        {\n            \"dataPointId\": \"22911bdc-0b2f-5008-9d42-c551d4fa53c7\",\n            \"key\": \"VOLTAGE_P1\",\n            \"value\": 245,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"4e34e4eb-0859-5253-81ae-9d536e75c003\",\n            \"key\": \"VOLTAGE_P2\",\n            \"value\": 242.3,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"a45c0fe9-42e8-5091-9007-ff73d55a149b\",\n            \"key\": \"VOLTAGE_P3\",\n            \"value\": 245.5,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"755e91d4-f6c6-5570-a2bf-623b20055816\",\n            \"key\": \"FREQUENCY\",\n            \"value\": 49.98,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"c7b812ba-e08b-5f4a-bcd4-97616c8130bc\",\n            \"key\": \"ACTIVE_POWER\",\n            \"value\": -826,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"3f4105ab-bdf8-5d0b-88ba-9859dcf3f111\",\n            \"key\": \"OUTPUT_ENERGY\",\n            \"value\": 241826.44736444377,\n            \"ts\": 1723905135075\n        },\n        {\n            \"dataPointId\": \"6ddbb838-0557-5df0-bdeb-489f426248fb\",\n            \"key\": \"INPUT_ENERGY\",\n            \"value\": 22988.396324999278,\n            \"ts\": 1723904090096\n        },\n        {\n            \"dataPointId\": \"b89fda1c-f19a-5da0-bcbd-4277eb377b3a\",\n            \"key\": \"POWER_P1\",\n            \"value\": -305,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"64fd2faa-13ca-5cc4-8302-3085f13775c8\",\n            \"key\": \"POWER_P2\",\n            \"value\": -268,\n            \"ts\": 1723905135056\n        },\n        {\n            \"dataPointId\": \"eca4dacc-1858-50f1-ac46-30cddcde75a2\",\n            \"key\": \"POWER_P3\",\n            \"value\": -214,\n            \"ts\": 1723905135056\n        }\n    ]\n}"
  },
  {
    "path": "plugins/inputs/neoom_beaam/types.go",
    "content": "package neoom_beaam\n\ntype site struct {\n\tEnergyFlow struct {\n\t\tDataPoints map[string]datapoint `json:\"dataPoints\"`\n\t} `json:\"energyFlow\"`\n\tThings map[string]thingDefinition `json:\"things\"`\n}\n\ntype siteState struct {\n\tEnergyFlow struct {\n\t\tStates []state `json:\"states\"`\n\t} `json:\"energyFlow\"`\n}\n\ntype thingDefinition struct {\n\tid         string\n\tName       string               `json:\"type\"`\n\tDataPoints map[string]datapoint `json:\"dataPoints\"`\n}\n\ntype thingState struct {\n\tID     string  `json:\"thingId\"`\n\tStates []state `json:\"states\"`\n}\n\ntype datapoint struct {\n\tKey      string `json:\"key\"`\n\tDataType string `json:\"dataType\"`\n\tUnit     string `json:\"unitOfMeasure\"`\n}\n\ntype state struct {\n\tKey         string      `json:\"key\"`\n\tValue       interface{} `json:\"value\"`\n\tDataPointID string      `json:\"dataPointId\"`\n\tTimestamp   float64     `json:\"ts\"`\n}\n"
  },
  {
    "path": "plugins/inputs/neptune_apex/README.md",
    "content": "# Neptune Apex Input Plugin\n\nThis plugin gathers metrics from [Neptune Apex controller][neptune] instances,\nallowing aquarium hobbyists to monitor and control their tanks based on various\nprobes.\n\n⭐ Telegraf v1.10.0\n🏷️ iot\n💻 all\n\n[neptune]: https://www.neptunesystems.com\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Neptune Apex data collector\n[[inputs.neptune_apex]]\n  ## The Neptune Apex plugin reads the publicly available status.xml data from a local Apex.\n  ## Measurements will be logged under \"apex\".\n\n  ## The base URL of the local Apex(es). If you specify more than one server, they will\n  ## be differentiated by the \"source\" tag.\n  servers = [\n    \"http://apex.local\",\n  ]\n\n  ## The response_timeout specifies how long to wait for a reply from the Apex.\n  #response_timeout = \"5s\"\n\n```\n\n## Troubleshooting\n\n### sendRequest failure\n\nThis indicates a problem communicating with the local Apex controller. If on\nMac/Linux, try curl:\n\n```sh\ncurl apex.local/cgi-bin/status.xml\n```\n\nto isolate the problem.\n\n### parseXML errors\n\nEnsure the XML being returned is valid. If you get valid XML back, open a bug\nrequest.\n\n### Missing fields/data\n\nThe neptune_apex plugin is strict on its input to prevent any conversion\nerrors. If you have fields in the status.xml output that are not converted to a\nmetric, open a feature request and paste your whole status.xml\n\n## Metrics\n\nThe Neptune Apex controller family allows an aquarium hobbyist to monitor and\ncontrol their tanks based on various probes. The data is taken directly from the\n/cgi-bin/status.xml at the interval specified in the telegraf.conf configuration\nfile.\n\nNo manipulation is done on any of the fields to ensure future changes to the\nstatus.xml do not introduce conversion bugs to this plugin. When reasonable and\npredictable, some tags are derived to make graphing easier and without front-end\nprogramming. These tags are clearly marked in the list below and should be\nconsidered a convenience rather than authoritative.\n\n- neptune_apex (All metrics have this measurement name)\n  - tags:\n    - host        (mandatory, string) - host on which telegraf runs\n    - source      (mandatory, string) - contains the hostname of the apex device\n                                        This can be used to differentiate between\n                                        different units. By using the source\n                                        instead of the serial number, replacements\n                                        units won't disturb graphs.\n    - type        (mandatory, string) - maps to the different data types\n                                        Values can be \"controller\" (The Apex\n                                        controller itself), \"probe\" for the\n                                        different input probes, or \"output\" for any\n                                        physical or virtual outputs. The Watt and\n                                        Amp probes attached to the physical 120V\n                                        outlets are aggregated under the output type.\n    - hardware    (mandatory, string) - controller hardware version\n    - software    (mandatory, string) - software version\n    - probe_type  (optional, string)  - contains the probe type as reported by Apex\n    - name        (optional, string)  - contains the name of the probe or output\n    - output_id   (optional, string)  - represents the internal unique output ID\n                                        This is different from the device_id.\n    - device_id   (optional, string)  - maps to either the aquabus address or\n                                        internal reference\n    - output_type (optional, string)  - categorizes the output into different\n                                        categories. This tag is DERIVED from the\n                                        device_id. Possible values are:\n                                        \"variable\" for the 0-10V signal ports,\n                                        \"outlet\" for physical 120V sockets,\n                                        \"alert\" for alarms (email, sound),\n                                        \"virtual\" for user-defined outputs, and\n                                        \"unknown\" for everything else\n  - fields:\n    - value          (float, various unit)     - represents the probe reading.\n    - state          (string)                  - represents the output state as\n                                                 defined by the Apex. Examples\n                                                 include \"AOF\" for Auto (OFF),\n                                                 \"TBL\" for operating according\n                                                 to a table, and \"PF*\" for\n                                                 different programs\n    - amp            (float, Ampere)           - amount of current flowing\n                                                 through the 120V outlet\n    - watt           (float, Watt)             - amount of energy flowing\n                                                 through the 120V outlet\n    - xstatus        (string)                  - xstatus of an outlet, found on\n                                                 wireless Vortech devices\n    - power_failed   (int64, Unix epoch in ns) - last power loss of the controller\n                                                 Omitted if the apex reports it\n                                                 as \"none\".\n    - power_restored (int64, Unix epoch in ns) - last powered on of the controller\n                                                 Omitted if the apex reports it\n                                                 as \"none\"\n    - serial         (string, serial number)\n  - time:\n    - metric time as parsed from the status.xml page. This helps when\n      cross-referencing events with the local system of Apex Fusion. Since the\n      Apex uses NTP, this should not matter in most scenarios.\n\n## Example Output\n\n```text\nneptune_apex,hardware=1.0,host=ubuntu,software=5.04_7A18,source=apex,type=controller power_failed=1544814000000000000i,power_restored=1544833875000000000i,serial=\"AC5:12345\" 1545978278000000000\nneptune_apex,device_id=base_Var1,hardware=1.0,host=ubuntu,name=VarSpd1_I1,output_id=0,output_type=variable,software=5.04_7A18,source=apex,type=output state=\"PF1\" 1545978278000000000\nneptune_apex,device_id=base_Var2,hardware=1.0,host=ubuntu,name=VarSpd2_I2,output_id=1,output_type=variable,software=5.04_7A18,source=apex,type=output state=\"PF2\" 1545978278000000000\nneptune_apex,device_id=base_Var3,hardware=1.0,host=ubuntu,name=VarSpd3_I3,output_id=2,output_type=variable,software=5.04_7A18,source=apex,type=output state=\"PF3\" 1545978278000000000\nneptune_apex,device_id=base_Var4,hardware=1.0,host=ubuntu,name=VarSpd4_I4,output_id=3,output_type=variable,software=5.04_7A18,source=apex,type=output state=\"PF4\" 1545978278000000000\nneptune_apex,device_id=base_Alarm,hardware=1.0,host=ubuntu,name=SndAlm_I6,output_id=4,output_type=alert,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=base_Warn,hardware=1.0,host=ubuntu,name=SndWrn_I7,output_id=5,output_type=alert,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=base_email,hardware=1.0,host=ubuntu,name=EmailAlm_I5,output_id=6,output_type=alert,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=base_email2,hardware=1.0,host=ubuntu,name=Email2Alm_I9,output_id=7,output_type=alert,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=2_1,hardware=1.0,host=ubuntu,name=RETURN_2_1,output_id=8,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0.3,state=\"AON\",watt=34 1545978278000000000\nneptune_apex,device_id=2_2,hardware=1.0,host=ubuntu,name=Heater1_2_2,output_id=9,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AOF\",watt=0 1545978278000000000\nneptune_apex,device_id=2_3,hardware=1.0,host=ubuntu,name=FREE_2_3,output_id=10,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"OFF\",watt=1 1545978278000000000\nneptune_apex,device_id=2_4,hardware=1.0,host=ubuntu,name=LIGHT_2_4,output_id=11,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"OFF\",watt=1 1545978278000000000\nneptune_apex,device_id=2_5,hardware=1.0,host=ubuntu,name=LHead_2_5,output_id=12,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=4 1545978278000000000\nneptune_apex,device_id=2_6,hardware=1.0,host=ubuntu,name=SKIMMER_2_6,output_id=13,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0.1,state=\"AON\",watt=12 1545978278000000000\nneptune_apex,device_id=2_7,hardware=1.0,host=ubuntu,name=FREE_2_7,output_id=14,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"OFF\",watt=1 1545978278000000000\nneptune_apex,device_id=2_8,hardware=1.0,host=ubuntu,name=CABLIGHT_2_8,output_id=15,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=1 1545978278000000000\nneptune_apex,device_id=2_9,hardware=1.0,host=ubuntu,name=LinkA_2_9,output_id=16,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=2_10,hardware=1.0,host=ubuntu,name=LinkB_2_10,output_id=17,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=3_1,hardware=1.0,host=ubuntu,name=RVortech_3_1,output_id=18,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"TBL\",xstatus=\"OK\" 1545978278000000000\nneptune_apex,device_id=3_2,hardware=1.0,host=ubuntu,name=LVortech_3_2,output_id=19,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"TBL\",xstatus=\"OK\" 1545978278000000000\nneptune_apex,device_id=4_1,hardware=1.0,host=ubuntu,name=OSMOLATO_4_1,output_id=20,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AOF\",watt=0 1545978278000000000\nneptune_apex,device_id=4_2,hardware=1.0,host=ubuntu,name=HEATER2_4_2,output_id=21,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AOF\",watt=0 1545978278000000000\nneptune_apex,device_id=4_3,hardware=1.0,host=ubuntu,name=NUC_4_3,output_id=22,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0.1,state=\"AON\",watt=8 1545978278000000000\nneptune_apex,device_id=4_4,hardware=1.0,host=ubuntu,name=CABFAN_4_4,output_id=23,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=1 1545978278000000000\nneptune_apex,device_id=4_5,hardware=1.0,host=ubuntu,name=RHEAD_4_5,output_id=24,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=3 1545978278000000000\nneptune_apex,device_id=4_6,hardware=1.0,host=ubuntu,name=FIRE_4_6,output_id=25,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=3 1545978278000000000\nneptune_apex,device_id=4_7,hardware=1.0,host=ubuntu,name=LightGW_4_7,output_id=26,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=1 1545978278000000000\nneptune_apex,device_id=4_8,hardware=1.0,host=ubuntu,name=GBSWITCH_4_8,output_id=27,output_type=outlet,software=5.04_7A18,source=apex,type=output amp=0,state=\"AON\",watt=0 1545978278000000000\nneptune_apex,device_id=4_9,hardware=1.0,host=ubuntu,name=LinkA_4_9,output_id=28,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=4_10,hardware=1.0,host=ubuntu,name=LinkB_4_10,output_id=29,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=5_1,hardware=1.0,host=ubuntu,name=LinkA_5_1,output_id=30,output_type=unknown,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=Cntl_A1,hardware=1.0,host=ubuntu,name=ATO_EMPTY,output_id=31,output_type=virtual,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=Cntl_A2,hardware=1.0,host=ubuntu,name=LEAK,output_id=32,output_type=virtual,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,device_id=Cntl_A3,hardware=1.0,host=ubuntu,name=SKMR_NOPWR,output_id=33,output_type=virtual,software=5.04_7A18,source=apex,type=output state=\"AOF\" 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=Tmp,probe_type=Temp,software=5.04_7A18,source=apex,type=probe value=78.1 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=pH,probe_type=pH,software=5.04_7A18,source=apex,type=probe value=7.93 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=ORP,probe_type=ORP,software=5.04_7A18,source=apex,type=probe value=191 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=Salt,probe_type=Cond,software=5.04_7A18,source=apex,type=probe value=29.4 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=Volt_2,software=5.04_7A18,source=apex,type=probe value=117 1545978278000000000\nneptune_apex,hardware=1.0,host=ubuntu,name=Volt_4,software=5.04_7A18,source=apex,type=probe value=118 1545978278000000000\n```\n\n## Contributing\n\nThis plugin is used for mission-critical aquatic life support. A bug could very\nwell result in the death of animals. Neptune does not publish a schema file and\nas such, we have made this plugin very strict on input with no provisions for\nautomatically adding fields. We are also careful to not add default values when\nnone are presented to prevent automation errors.\n\nWhen writing unit tests, use actual Apex output to run tests. It's acceptable to\nabridge the number of repeated fields but never inner fields or parameters.\n"
  },
  {
    "path": "plugins/inputs/neptune_apex/neptune_apex.go",
    "content": "// Package neptune_apex implements an input plugin for the Neptune Apex\n// aquarium controller.\n//\n//go:generate ../../../tools/readme_config_includer/generator\npackage neptune_apex\n\nimport (\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Measurement is constant across all metrics.\nconst Measurement = \"neptune_apex\"\n\ntype NeptuneApex struct {\n\tServers         []string        `toml:\"servers\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\thttpClient      *http.Client\n}\n\ntype xmlReply struct {\n\tSoftwareVersion string   `xml:\"software,attr\"`\n\tHardwareVersion string   `xml:\"hardware,attr\"`\n\tHostname        string   `xml:\"hostname\"`\n\tSerial          string   `xml:\"serial\"`\n\tTimezone        float64  `xml:\"timezone\"`\n\tDate            string   `xml:\"date\"`\n\tPowerFailed     string   `xml:\"power>failed\"`\n\tPowerRestored   string   `xml:\"power>restored\"`\n\tProbe           []probe  `xml:\"probes>probe\"`\n\tOutlet          []outlet `xml:\"outlets>outlet\"`\n}\n\ntype probe struct {\n\tName  string  `xml:\"name\"`\n\tValue string  `xml:\"value\"`\n\tType  *string `xml:\"type\"`\n}\n\ntype outlet struct {\n\tName     string  `xml:\"name\"`\n\tOutputID string  `xml:\"outputID\"`\n\tState    string  `xml:\"state\"`\n\tDeviceID string  `xml:\"deviceID\"`\n\tXstatus  *string `xml:\"xstatus\"`\n}\n\nfunc (*NeptuneApex) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NeptuneApex) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, server := range n.Servers {\n\t\twg.Add(1)\n\t\tgo func(server string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherServer(acc, server))\n\t\t}(server)\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NeptuneApex) gatherServer(\n\tacc telegraf.Accumulator, server string) error {\n\tresp, err := n.sendRequest(server)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn parseXML(acc, resp)\n}\n\n// parseXML is strict on the input and does not do best-effort parsing.\n// This is because of the life-support nature of the Neptune Apex.\nfunc parseXML(acc telegraf.Accumulator, data []byte) error {\n\tr := xmlReply{}\n\terr := xml.Unmarshal(data, &r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to unmarshal XML: %w\\nXML DATA: %q\", err, data)\n\t}\n\n\tmainFields := map[string]interface{}{\n\t\t\"serial\": r.Serial,\n\t}\n\tvar reportTime time.Time\n\n\tif reportTime, err = parseTime(r.Date, r.Timezone); err != nil {\n\t\treturn err\n\t}\n\tif val, err := parseTime(r.PowerFailed, r.Timezone); err == nil {\n\t\tmainFields[\"power_failed\"] = val.UnixNano()\n\t}\n\tif val, err := parseTime(r.PowerRestored, r.Timezone); err == nil {\n\t\tmainFields[\"power_restored\"] = val.UnixNano()\n\t}\n\n\tacc.AddFields(Measurement, mainFields,\n\t\tmap[string]string{\n\t\t\t\"source\":   r.Hostname,\n\t\t\t\"type\":     \"controller\",\n\t\t\t\"software\": r.SoftwareVersion,\n\t\t\t\"hardware\": r.HardwareVersion,\n\t\t},\n\t\treportTime)\n\n\t// Outlets.\n\tfor _, o := range r.Outlet {\n\t\ttags := map[string]string{\n\t\t\t\"source\":    r.Hostname,\n\t\t\t\"output_id\": o.OutputID,\n\t\t\t\"device_id\": o.DeviceID,\n\t\t\t\"name\":      o.Name,\n\t\t\t\"type\":      \"output\",\n\t\t\t\"software\":  r.SoftwareVersion,\n\t\t\t\"hardware\":  r.HardwareVersion,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"state\": o.State,\n\t\t}\n\t\t// Find Amp and Watt probes and add them as fields.\n\t\t// Remove the redundant probe.\n\t\tif pos := findProbe(o.Name+\"W\", r.Probe); pos > -1 {\n\t\t\tvalue, err := strconv.ParseFloat(\n\t\t\t\tstrings.TrimSpace(r.Probe[pos].Value), 64)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(\n\t\t\t\t\tfmt.Errorf(\"cannot convert string value %q to float64: %w\", r.Probe[pos].Value, err))\n\t\t\t\tcontinue // Skip the whole outlet.\n\t\t\t}\n\t\t\tfields[\"watt\"] = value\n\t\t\tr.Probe[pos] = r.Probe[len(r.Probe)-1]\n\t\t\tr.Probe = r.Probe[:len(r.Probe)-1]\n\t\t}\n\t\tif pos := findProbe(o.Name+\"A\", r.Probe); pos > -1 {\n\t\t\tvalue, err := strconv.ParseFloat(\n\t\t\t\tstrings.TrimSpace(r.Probe[pos].Value), 64)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(\n\t\t\t\t\tfmt.Errorf(\"cannot convert string value %q to float64: %w\", r.Probe[pos].Value, err))\n\t\t\t\tbreak // // Skip the whole outlet.\n\t\t\t}\n\t\t\tfields[\"amp\"] = value\n\t\t\tr.Probe[pos] = r.Probe[len(r.Probe)-1]\n\t\t\tr.Probe = r.Probe[:len(r.Probe)-1]\n\t\t}\n\t\tif o.Xstatus != nil {\n\t\t\tfields[\"xstatus\"] = *o.Xstatus\n\t\t}\n\t\t// Try to determine outlet type. Focus on accuracy, leaving the outlet_type \"unknown\" when ambiguous. 24v and vortech cannot be determined.\n\t\tswitch {\n\t\tcase strings.HasPrefix(o.DeviceID, \"base_Var\"):\n\t\t\ttags[\"output_type\"] = \"variable\"\n\t\tcase o.DeviceID == \"base_Alarm\":\n\t\t\tfallthrough\n\t\tcase o.DeviceID == \"base_Warn\":\n\t\t\tfallthrough\n\t\tcase strings.HasPrefix(o.DeviceID, \"base_email\"):\n\t\t\ttags[\"output_type\"] = \"alert\"\n\t\tcase fields[\"watt\"] != nil || fields[\"amp\"] != nil:\n\t\t\ttags[\"output_type\"] = \"outlet\"\n\t\tcase strings.HasPrefix(o.DeviceID, \"Cntl_\"):\n\t\t\ttags[\"output_type\"] = \"virtual\"\n\t\tdefault:\n\t\t\ttags[\"output_type\"] = \"unknown\"\n\t\t}\n\n\t\tacc.AddFields(Measurement, fields, tags, reportTime)\n\t}\n\n\t// Probes.\n\tfor _, p := range r.Probe {\n\t\tvalue, err := strconv.ParseFloat(strings.TrimSpace(p.Value), 64)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"cannot convert string value %q to float64: %w\", p.Value, err))\n\t\t\tcontinue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": value,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"source\":   r.Hostname,\n\t\t\t\"type\":     \"probe\",\n\t\t\t\"name\":     p.Name,\n\t\t\t\"software\": r.SoftwareVersion,\n\t\t\t\"hardware\": r.HardwareVersion,\n\t\t}\n\t\tif p.Type != nil {\n\t\t\ttags[\"probe_type\"] = *p.Type\n\t\t}\n\t\tacc.AddFields(Measurement, fields, tags, reportTime)\n\t}\n\n\treturn nil\n}\n\nfunc findProbe(probe string, probes []probe) int {\n\tfor i, p := range probes {\n\t\tif p.Name == probe {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// parseTime takes a Neptune Apex date/time string with a timezone and\n// returns a time.Time struct.\nfunc parseTime(val string, tz float64) (time.Time, error) {\n\t// Magic time constant from https://golang.org/pkg/time/#Parse\n\tconst timeLayout = \"01/02/2006 15:04:05 -0700\"\n\n\t// Timezone offset needs to be explicit\n\tsign := '+'\n\tif tz < 0 {\n\t\tsign = '-'\n\t}\n\n\t// Build a time string with the timezone in a format Go can parse.\n\ttzs := fmt.Sprintf(\"%c%04d\", sign, int(math.Abs(tz))*100)\n\tts := fmt.Sprintf(\"%s %s\", val, tzs)\n\tt, err := time.Parse(timeLayout, ts)\n\tif err != nil {\n\t\treturn time.Now(), fmt.Errorf(\"unable to parse %q: %w\", ts, err)\n\t}\n\treturn t, nil\n}\n\nfunc (n *NeptuneApex) sendRequest(server string) ([]byte, error) {\n\turl := server + \"/cgi-bin/status.xml\"\n\tresp, err := n.httpClient.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"http GET failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"response from server URL %q returned %d (%s), expected %d (%s)\",\n\t\t\turl, resp.StatusCode, http.StatusText(resp.StatusCode),\n\t\t\thttp.StatusOK, http.StatusText(http.StatusOK))\n\t}\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to read output from %q: %w\", url, err)\n\t}\n\treturn body, nil\n}\n\nfunc init() {\n\tinputs.Add(\"neptune_apex\", func() telegraf.Input {\n\t\treturn &NeptuneApex{\n\t\t\thttpClient: &http.Client{\n\t\t\t\tTimeout: 5 * time.Second,\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/neptune_apex/neptune_apex_test.go",
    "content": "package neptune_apex\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\th := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := w.Write([]byte(\"data\")); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusNotFound)\n\t})\n\tc, destroy := fakeHTTPClient(h)\n\tdefer destroy()\n\tn := &NeptuneApex{\n\t\thttpClient: c,\n\t}\n\ttests := []struct {\n\t\tname    string\n\t\tservers []string\n\t}{\n\t\t{\n\t\t\tname:    \"Good case, 2 servers\",\n\t\t\tservers: []string{\"http://abc\", \"https://def\"},\n\t\t},\n\t\t{\n\t\t\tname: \"Good case, 0 servers\",\n\t\t},\n\t\t{\n\t\t\tname:    \"Good case nil\",\n\t\t\tservers: nil,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\tn.Servers = test.servers\n\t\t\trequire.NoError(t, n.Gather(&acc))\n\t\t\trequire.Lenf(t, acc.Errors, len(test.servers),\n\t\t\t\t\"Number of servers mismatch. got=%d, want=%d\", len(acc.Errors), len(test.servers))\n\t\t})\n\t}\n}\n\nfunc TestParseXML(t *testing.T) {\n\tgoodTime := time.Date(2018, 12, 22, 21, 55, 37, 0, time.FixedZone(\"PST\", 3600*-8))\n\ttests := []struct {\n\t\tname        string\n\t\txmlResponse []byte\n\t\twantMetrics []telegraf.Metric\n\t\twantAccErr  bool\n\t\twantErr     bool\n\t}{\n\t\t{\n\t\t\tname:        \"Good test\",\n\t\t\txmlResponse: []byte(apex2016),\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"apex\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"software\": \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\": \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":         \"AC5:12345\",\n\t\t\t\t\t\t\"power_failed\":   int64(1544814000000000000),\n\t\t\t\t\t\t\"power_restored\": int64(1544833875000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"0\",\n\t\t\t\t\t\t\"device_id\":   \"base_Var1\",\n\t\t\t\t\t\t\"name\":        \"VarSpd1_I1\",\n\t\t\t\t\t\t\"output_type\": \"variable\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"state\": \"PF1\"},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"6\",\n\t\t\t\t\t\t\"device_id\":   \"base_email\",\n\t\t\t\t\t\t\"name\":        \"EmailAlm_I5\",\n\t\t\t\t\t\t\"output_type\": \"alert\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"state\": \"AOF\"},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"8\",\n\t\t\t\t\t\t\"device_id\":   \"2_1\",\n\t\t\t\t\t\t\"name\":        \"RETURN_2_1\",\n\t\t\t\t\t\t\"output_type\": \"outlet\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"state\": \"AON\",\n\t\t\t\t\t\t\"watt\":  35.0,\n\t\t\t\t\t\t\"amp\":   0.3,\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"18\",\n\t\t\t\t\t\t\"device_id\":   \"3_1\",\n\t\t\t\t\t\t\"name\":        \"RVortech_3_1\",\n\t\t\t\t\t\t\"output_type\": \"unknown\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"state\":   \"TBL\",\n\t\t\t\t\t\t\"xstatus\": \"OK\",\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"28\",\n\t\t\t\t\t\t\"device_id\":   \"4_9\",\n\t\t\t\t\t\t\"name\":        \"LinkA_4_9\",\n\t\t\t\t\t\t\"output_type\": \"unknown\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"state\": \"AOF\"},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"apex\",\n\t\t\t\t\t\t\"output_id\":   \"32\",\n\t\t\t\t\t\t\"device_id\":   \"Cntl_A2\",\n\t\t\t\t\t\t\"name\":        \"LEAK\",\n\t\t\t\t\t\t\"output_type\": \"virtual\",\n\t\t\t\t\t\t\"type\":        \"output\",\n\t\t\t\t\t\t\"software\":    \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":    \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"state\": \"AOF\"},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":     \"apex\",\n\t\t\t\t\t\t\"name\":       \"Salt\",\n\t\t\t\t\t\t\"type\":       \"probe\",\n\t\t\t\t\t\t\"probe_type\": \"Cond\",\n\t\t\t\t\t\t\"software\":   \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\":   \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 30.1},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"apex\",\n\t\t\t\t\t\t\"name\":     \"Volt_2\",\n\t\t\t\t\t\t\"type\":     \"probe\",\n\t\t\t\t\t\t\"software\": \"5.04_7A18\",\n\t\t\t\t\t\t\"hardware\": \"1.0\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\"value\": 115.0},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Unmarshal error\",\n\t\t\txmlResponse: []byte(\"Invalid\"),\n\t\t\twantErr:     true,\n\t\t},\n\t\t{\n\t\t\tname:        \"Report time failure\",\n\t\t\txmlResponse: []byte(`<status><date>abc</date></status>`),\n\t\t\twantErr:     true,\n\t\t},\n\t\t{\n\t\t\tname: \"Power Failed time failure\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<status><date>12/22/2018 21:55:37</date>\n\t\t\t\t<timezone>-8.0</timezone><power><failed>a</failed>\n\t\t\t\t<restored>12/22/2018 22:55:37</restored></power></status>`),\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"hardware\": \"\",\n\t\t\t\t\t\t\"software\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":         \"\",\n\t\t\t\t\t\t\"power_restored\": int64(1545548137000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Power restored time failure\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<status><date>12/22/2018 21:55:37</date>\n\t\t\t\t<timezone>-8.0</timezone><power><restored>a</restored>\n\t\t\t\t<failed>12/22/2018 22:55:37</failed></power></status>`),\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"hardware\": \"\",\n\t\t\t\t\t\t\"software\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":       \"\",\n\t\t\t\t\t\t\"power_failed\": int64(1545548137000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Power failed failure\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<status><power><failed>abc</failed></power></status>`),\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"Failed to parse watt to float\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<?xml version=\"1.0\"?><status>\n\t\t\t\t<date>12/22/2018 21:55:37</date><timezone>-8.0</timezone>\n\t\t\t\t<power><failed>12/22/2018 21:55:37</failed>\n\t\t\t\t<restored>12/22/2018 21:55:37</restored></power>\n\t\t\t\t<outlets><outlet><name>o1</name></outlet></outlets>\n\t\t\t\t<probes><probe><name>o1W</name><value>abc</value></probe>\n\t\t\t\t</probes></status>`),\n\t\t\twantAccErr: true,\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"hardware\": \"\",\n\t\t\t\t\t\t\"software\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":         \"\",\n\t\t\t\t\t\t\"power_failed\":   int64(1545544537000000000),\n\t\t\t\t\t\t\"power_restored\": int64(1545544537000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Failed to parse amp to float\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<?xml version=\"1.0\"?><status>\n\t\t\t\t<date>12/22/2018 21:55:37</date><timezone>-8.0</timezone>\n\t\t\t\t<power><failed>12/22/2018 21:55:37</failed>\n\t\t\t\t<restored>12/22/2018 21:55:37</restored></power>\n\t\t\t\t<outlets><outlet><name>o1</name></outlet></outlets>\n\t\t\t\t<probes><probe><name>o1A</name><value>abc</value></probe>\n\t\t\t\t</probes></status>`),\n\t\t\twantAccErr: true,\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"hardware\": \"\",\n\t\t\t\t\t\t\"software\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":         \"\",\n\t\t\t\t\t\t\"power_failed\":   int64(1545544537000000000),\n\t\t\t\t\t\t\"power_restored\": int64(1545544537000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Failed to parse probe value to float\",\n\t\t\txmlResponse: []byte(\n\t\t\t\t`<?xml version=\"1.0\"?><status>\n\t\t\t\t<date>12/22/2018 21:55:37</date><timezone>-8.0</timezone>\n\t\t\t\t<power><failed>12/22/2018 21:55:37</failed>\n\t\t\t\t<restored>12/22/2018 21:55:37</restored></power>\n\t\t\t\t<probes><probe><name>p1</name><value>abc</value></probe>\n\t\t\t\t</probes></status>`),\n\t\t\twantAccErr: true,\n\t\t\twantMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\tMeasurement,\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":   \"\",\n\t\t\t\t\t\t\"type\":     \"controller\",\n\t\t\t\t\t\t\"hardware\": \"\",\n\t\t\t\t\t\t\"software\": \"\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"serial\":         \"\",\n\t\t\t\t\t\t\"power_failed\":   int64(1545544537000000000),\n\t\t\t\t\t\t\"power_restored\": int64(1545544537000000000),\n\t\t\t\t\t},\n\t\t\t\t\tgoodTime,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr := parseXML(&acc, test.xmlResponse)\n\t\t\tif test.wantErr {\n\t\t\t\trequire.Error(t, err, \"expected error but got <nil>\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// No error case\n\t\t\trequire.NoErrorf(t, err, \"expected no error but got: %v\", err)\n\t\t\trequire.Equalf(t, test.wantAccErr, len(acc.Errors) > 0,\n\t\t\t\t\"Accumulator errors. got=%v, want=%t\", acc.Errors, test.wantAccErr)\n\n\t\t\ttestutil.RequireMetricsEqual(t, acc.GetTelegrafMetrics(), test.wantMetrics)\n\t\t})\n\t}\n}\n\nfunc TestSendRequest(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname       string\n\t\tstatusCode int\n\t\twantErr    bool\n\t}{\n\t\t{\n\t\t\tname:       \"Good case\",\n\t\t\tstatusCode: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:       \"Get error\",\n\t\t\tstatusCode: http.StatusNotFound,\n\t\t\twantErr:    true,\n\t\t},\n\t\t{\n\t\t\tname:       \"Status 301\",\n\t\t\tstatusCode: http.StatusMovedPermanently,\n\t\t\twantErr:    true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\th := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.WriteHeader(test.statusCode)\n\t\t\t\tif _, err := w.Write([]byte(\"data\")); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t})\n\t\t\tc, destroy := fakeHTTPClient(h)\n\t\t\tdefer destroy()\n\t\t\tn := &NeptuneApex{\n\t\t\t\thttpClient: c,\n\t\t\t}\n\t\t\tresp, err := n.sendRequest(\"http://abc\")\n\t\t\tif test.wantErr {\n\t\t\t\trequire.Error(t, err, \"expected error but got <nil>\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// No error case\n\t\t\trequire.NoErrorf(t, err, \"expected no error but got: %v\", err)\n\t\t\trequire.Equalf(t, resp, []byte(\"data\"), \"Response data mismatch. got=%q, want=%q\", resp, \"data\")\n\t\t})\n\t}\n}\n\nfunc TestParseTime(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\ttimeZone float64\n\t\twantTime time.Time\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tname:     \"Good case - Timezone positive\",\n\t\t\tinput:    \"01/01/2023 12:34:56\",\n\t\t\ttimeZone: 5,\n\t\t\twantTime: time.Date(2023, 1, 1, 12, 34, 56, 0,\n\t\t\t\ttime.FixedZone(\"a\", 3600*5)),\n\t\t},\n\t\t{\n\t\t\tname:     \"Good case - Timezone negative\",\n\t\t\tinput:    \"01/01/2023 12:34:56\",\n\t\t\ttimeZone: -8,\n\t\t\twantTime: time.Date(2023, 1, 1, 12, 34, 56, 0,\n\t\t\t\ttime.FixedZone(\"a\", 3600*-8)),\n\t\t},\n\t\t{\n\t\t\tname:    \"Cannot parse\",\n\t\t\tinput:   \"Not a date\",\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tres, err := parseTime(test.input, test.timeZone)\n\t\t\tif test.wantErr {\n\t\t\t\trequire.Error(t, err, \"expected error but got <nil>\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// No error case\n\t\t\trequire.NoErrorf(t, err, \"expected no error but got: %v\", err)\n\t\t\trequire.Truef(t, test.wantTime.Equal(res), \"time mismatch. got=%q, want=%q\", res, test.wantTime)\n\t\t})\n\t}\n}\n\nfunc TestFindProbe(t *testing.T) {\n\tt.Parallel()\n\n\tfakeProbes := []probe{\n\t\t{\n\t\t\tName: \"test1\",\n\t\t},\n\t\t{\n\t\t\tName: \"good\",\n\t\t},\n\t}\n\ttests := []struct {\n\t\tname      string\n\t\tprobeName string\n\t\twantIndex int\n\t}{\n\t\t{\n\t\t\tname:      \"Good case - Found\",\n\t\t\tprobeName: \"good\",\n\t\t\twantIndex: 1,\n\t\t},\n\t\t{\n\t\t\tname:      \"Not found\",\n\t\t\tprobeName: \"bad\",\n\t\t\twantIndex: -1,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tindex := findProbe(test.probeName, fakeProbes)\n\t\t\trequire.Equalf(t, test.wantIndex, index, \"probe index mismatch; got=%d, want %d\", index, test.wantIndex)\n\t\t})\n\t}\n}\n\n// This fakeHttpClient creates a server and binds a client to it.\n// That way, it is possible to control the http\n// output from within the test without changes to the main code.\nfunc fakeHTTPClient(h http.Handler) (*http.Client, func()) {\n\ts := httptest.NewServer(h)\n\tc := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: func(\n\t\t\t\t_ context.Context, network, _ string) (net.Conn, error) {\n\t\t\t\treturn net.Dial(network, s.Listener.Addr().String())\n\t\t\t},\n\t\t},\n\t}\n\treturn c, s.Close\n}\n\n// Sample configuration from a 2016 version Neptune Apex.\nconst apex2016 = `<?xml version=\"1.0\"?>\n<status software=\"5.04_7A18\" hardware=\"1.0\">\n<hostname>apex</hostname>\n<serial>AC5:12345</serial>\n<timezone>-8.00</timezone>\n<date>12/22/2018 21:55:37</date>\n<power><failed>12/14/2018 11:00:00</failed>\n<restored>12/14/2018 16:31:15</restored></power>\n<probes>\n<probe>\n <name>Salt</name> <value>30.1 </value>\n <type>Cond</type></probe><probe>\n <name>RETURN_2_1A</name> <value>0.3  </value>\n</probe><probe>\n <name>RETURN_2_1W</name> <value>  35 </value>\n</probe><probe>\n <name>Volt_2</name> <value>115  </value>\n</probe></probes>\n<outlets>\n<outlet>\n <name>VarSpd1_I1</name>\n <outputID>0</outputID>\n <state>PF1</state>\n <deviceID>base_Var1</deviceID>\n</outlet>\n<outlet>\n <name>EmailAlm_I5</name>\n <outputID>6</outputID>\n <state>AOF</state>\n <deviceID>base_email</deviceID>\n</outlet>\n<outlet>\n <name>RETURN_2_1</name>\n <outputID>8</outputID>\n <state>AON</state>\n <deviceID>2_1</deviceID>\n</outlet>\n<outlet>\n <name>RVortech_3_1</name>\n <outputID>18</outputID>\n <state>TBL</state>\n <deviceID>3_1</deviceID>\n<xstatus>OK</xstatus></outlet>\n<outlet>\n <name>LinkA_4_9</name>\n <outputID>28</outputID>\n <state>AOF</state>\n <deviceID>4_9</deviceID>\n</outlet>\n<outlet>\n <name>LEAK</name>\n <outputID>32</outputID>\n <state>AOF</state>\n <deviceID>Cntl_A2</deviceID>\n</outlet>\n</outlets></status>\n`\n"
  },
  {
    "path": "plugins/inputs/neptune_apex/sample.conf",
    "content": "# Neptune Apex data collector\n[[inputs.neptune_apex]]\n  ## The Neptune Apex plugin reads the publicly available status.xml data from a local Apex.\n  ## Measurements will be logged under \"apex\".\n\n  ## The base URL of the local Apex(es). If you specify more than one server, they will\n  ## be differentiated by the \"source\" tag.\n  servers = [\n    \"http://apex.local\",\n  ]\n\n  ## The response_timeout specifies how long to wait for a reply from the Apex.\n  #response_timeout = \"5s\"\n\n"
  },
  {
    "path": "plugins/inputs/net/README.md",
    "content": "# Network Input Plugin\n\nThis plugin gathers metrics about network interface and protocol usage.\n\n⭐ Telegraf v0.1.1\n🏷️ network\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather metrics about network interfaces\n[[inputs.net]]\n  ## By default, telegraf gathers stats from any up interface (excluding loopback)\n  ## Setting interfaces will tell it to gather these explicit interfaces,\n  ## regardless of status. When specifying an interface, glob-style\n  ## patterns are also supported.\n  # interfaces = [\"eth*\", \"enp0s[0-1]\", \"lo\"]\n```\n\n## Metrics\n\nThe fields from this plugin are gathered in the _net_ measurement.\n\nFields (all platforms):\n\n* bytes_sent - The total number of bytes sent by the interface\n* bytes_recv - The total number of bytes received by the interface\n* packets_sent - The total number of packets sent by the interface\n* packets_recv - The total number of packets received by the interface\n* err_in - The total number of receive errors detected by the interface\n* err_out - The total number of transmit errors detected by the interface\n* drop_in - The total number of received packets dropped by the interface\n* drop_out - The total number of transmitted packets dropped by the interface\n* speed - The interface's latest or current speed value, in Mbits/sec. May be\n          -1 if unsupported by the interface\n\nDifferent platforms gather the data above with different mechanisms. Telegraf\nuses the ([gopsutil](https://github.com/shirou/gopsutil)) package, which under\nLinux reads the /proc/net/dev file.  Under freebsd/openbsd and darwin the plugin\nuses netstat.\n\nAdditionally, for the time being _only under Linux_, the plugin gathers system\nwide stats for different network protocols using /proc/net/snmp (tcp, udp, icmp,\netc.).  Explanation of the different metrics exposed by snmp is out of the scope\nof this document. The best way to find information would be tracing the\nconstants in the [Linux kernel source][source] and their usage. If\n/proc/net/snmp cannot be read for some reason, telegraf ignores the error\nsilently.\n\n[source]: https://elixir.bootlin.com/linux/latest/source/net/ipv4/proc.c\n\nTags:\n\n* Net measurements have the following tags:\n  * interface (the interface from which metrics are gathered)\n\nUnder Linux the system wide protocol metrics have the interface=all tag.\n\n## Example Output\n\nAll platforms provide metrics like the following:\n\n```text\nnet,interface=eth0,host=HOST bytes_sent=451838509i,bytes_recv=3284081640i,packets_sent=2663590i,packets_recv=3585442i,err_in=0i,err_out=0i,drop_in=4i,drop_out=0i 1492834180000000000\n```\n\nOn Linux additional metrics might be provided:\n\n```text\nnet,interface=eth0,host=HOST bytes_sent=451838509i,bytes_recv=3284081640i,packets_sent=2663590i,packets_recv=3585442i,err_in=0i,err_out=0i,drop_in=4i,drop_out=0i 1492834180000000000\nnet,interface=all,host=HOST ip_reasmfails=0i,icmp_insrcquenchs=0i,icmp_outtimestamps=0i,ip_inhdrerrors=0i,ip_inunknownprotos=0i,icmp_intimeexcds=10i,icmp_outaddrmasks=0i,icmp_indestunreachs=11005i,icmpmsg_outtype0=6i,tcp_retranssegs=14669i,udplite_outdatagrams=0i,ip_reasmtimeout=0i,ip_outnoroutes=2577i,ip_inaddrerrors=186i,icmp_outaddrmaskreps=0i,tcp_incsumerrors=0i,tcp_activeopens=55965i,ip_reasmoks=0i,icmp_inechos=6i,icmp_outdestunreachs=9417i,ip_reasmreqds=0i,icmp_outtimestampreps=0i,tcp_rtoalgorithm=1i,icmpmsg_intype3=11005i,icmpmsg_outtype69=129i,tcp_outsegs=2777459i,udplite_rcvbuferrors=0i,ip_fragoks=0i,icmp_inmsgs=13398i,icmp_outerrors=0i,tcp_outrsts=14951i,udplite_noports=0i,icmp_outmsgs=11517i,icmp_outechoreps=6i,icmpmsg_intype11=10i,icmp_inparmprobs=0i,ip_forwdatagrams=0i,icmp_inechoreps=1909i,icmp_outredirects=0i,icmp_intimestampreps=0i,icmpmsg_intype5=468i,tcp_rtomax=120000i,tcp_maxconn=-1i,ip_fragcreates=0i,ip_fragfails=0i,icmp_inredirects=468i,icmp_outtimeexcds=0i,icmp_outechos=1965i,icmp_inaddrmasks=0i,tcp_inerrs=389i,tcp_rtomin=200i,ip_defaultttl=64i,ip_outrequests=3366408i,ip_forwarding=2i,udp_incsumerrors=0i,udp_indatagrams=522136i,udplite_incsumerrors=0i,ip_outdiscards=871i,icmp_inerrors=958i,icmp_outsrcquenchs=0i,icmpmsg_intype0=1909i,tcp_insegs=3580226i,udp_outdatagrams=577265i,udp_rcvbuferrors=0i,udplite_sndbuferrors=0i,icmp_incsumerrors=0i,icmp_outparmprobs=0i,icmpmsg_outtype3=9417i,tcp_attemptfails=2652i,udplite_inerrors=0i,udplite_indatagrams=0i,ip_inreceives=4172969i,icmpmsg_outtype8=1965i,tcp_currestab=59i,udp_noports=5961i,ip_indelivers=4099279i,ip_indiscards=0i,tcp_estabresets=5818i,udp_sndbuferrors=3i,icmp_intimestamps=0i,icmpmsg_intype8=6i,udp_inerrors=0i,icmp_inaddrmaskreps=0i,tcp_passiveopens=452i 1492831540000000000\n```\n"
  },
  {
    "path": "plugins/inputs/net/net.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage net\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Net struct {\n\tInterfaces          []string `toml:\"interfaces\"`\n\tIgnoreProtocolStats bool     `toml:\"ignore_protocol_stats\" deprecated:\"1.37.0;1.45.0;option is ignored\"`\n\n\tfilter     filter.Filter\n\tps         psutil.PS\n\tskipChecks bool\n}\n\nfunc (*Net) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Net) Init() error {\n\t// So not use the interface list of the system if the HOST_PROC variable is\n\t// set as the interfaces are determined by a syscall and therefore might\n\t// differ especially in container environments.\n\tn.skipChecks = os.Getenv(\"HOST_PROC\") != \"\"\n\n\treturn nil\n}\n\nfunc (n *Net) Gather(acc telegraf.Accumulator) error {\n\tnetio, err := n.ps.NetIO()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting net io info: %w\", err)\n\t}\n\n\tif n.filter == nil {\n\t\tif n.filter, err = filter.Compile(n.Interfaces); err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling filter: %w\", err)\n\t\t}\n\t}\n\n\tinterfaces, err := net.Interfaces()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting list of interfaces: %w\", err)\n\t}\n\tinterfacesByName := make(map[string]net.Interface, len(interfaces))\n\tfor _, iface := range interfaces {\n\t\tinterfacesByName[iface.Name] = iface\n\t}\n\n\tfor _, io := range netio {\n\t\tif len(n.Interfaces) != 0 {\n\t\t\tvar found bool\n\n\t\t\tif n.filter.Match(io.Name) {\n\t\t\t\tfound = true\n\t\t\t}\n\n\t\t\tif !found {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else if !n.skipChecks {\n\t\t\tiface, ok := interfacesByName[io.Name]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif iface.Flags&net.FlagLoopback == net.FlagLoopback {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif iface.Flags&net.FlagUp == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"interface\": io.Name,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"bytes_sent\":   io.BytesSent,\n\t\t\t\"bytes_recv\":   io.BytesRecv,\n\t\t\t\"packets_sent\": io.PacketsSent,\n\t\t\t\"packets_recv\": io.PacketsRecv,\n\t\t\t\"err_in\":       io.Errin,\n\t\t\t\"err_out\":      io.Errout,\n\t\t\t\"drop_in\":      io.Dropin,\n\t\t\t\"drop_out\":     io.Dropout,\n\t\t\t\"speed\":        getInterfaceSpeed(io.Name),\n\t\t}\n\t\tacc.AddCounter(\"net\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// Get the interface speed from /sys/class/net/*/speed file. returns -1 if unsupported\nfunc getInterfaceSpeed(ioName string) int64 {\n\tsysPath := internal.GetSysPath()\n\n\traw, err := os.ReadFile(filepath.Join(sysPath, \"class\", \"net\", ioName, \"speed\"))\n\tif err != nil {\n\t\treturn -1\n\t}\n\n\tspeed, err := strconv.ParseInt(strings.TrimSuffix(string(raw), \"\\n\"), 10, 64)\n\tif err != nil {\n\t\treturn -1\n\t}\n\treturn speed\n}\n\nfunc init() {\n\tinputs.Add(\"net\", func() telegraf.Input {\n\t\treturn &Net{ps: psutil.NewSystemPS()}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/net/net_test.go",
    "content": "package net\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/net\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNetIOStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\n\tnetio := net.IOCountersStat{\n\t\tName:        \"eth0\",\n\t\tBytesSent:   1123,\n\t\tBytesRecv:   8734422,\n\t\tPacketsSent: 781,\n\t\tPacketsRecv: 23456,\n\t\tErrin:       832,\n\t\tErrout:      8,\n\t\tDropin:      7,\n\t\tDropout:     1,\n\t}\n\n\tmps.On(\"NetIO\").Return([]net.IOCountersStat{netio}, nil)\n\n\tt.Setenv(\"HOST_SYS\", filepath.Join(\"testdata\", \"general\", \"sys\"))\n\n\tplugin := &Net{ps: &mps, skipChecks: true}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"net\",\n\t\t\tmap[string]string{\"interface\": \"eth0\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes_sent\":   uint64(1123),\n\t\t\t\t\"bytes_recv\":   uint64(8734422),\n\t\t\t\t\"packets_sent\": uint64(781),\n\t\t\t\t\"packets_recv\": uint64(23456),\n\t\t\t\t\"err_in\":       uint64(832),\n\t\t\t\t\"err_out\":      uint64(8),\n\t\t\t\t\"drop_in\":      uint64(7),\n\t\t\t\t\"drop_out\":     uint64(1),\n\t\t\t\t\"speed\":        int64(100),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestNetIOStatsSpeedUnsupported(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\n\tnetio := net.IOCountersStat{\n\t\tName:        \"eth1\",\n\t\tBytesSent:   1123,\n\t\tBytesRecv:   8734422,\n\t\tPacketsSent: 781,\n\t\tPacketsRecv: 23456,\n\t\tErrin:       832,\n\t\tErrout:      8,\n\t\tDropin:      7,\n\t\tDropout:     1,\n\t}\n\n\tmps.On(\"NetIO\").Return([]net.IOCountersStat{netio}, nil)\n\n\tt.Setenv(\"HOST_SYS\", filepath.Join(\"testdata\", \"general\", \"sys\"))\n\n\tplugin := &Net{ps: &mps, skipChecks: true}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"net\",\n\t\t\tmap[string]string{\"interface\": \"eth1\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes_sent\":   uint64(1123),\n\t\t\t\t\"bytes_recv\":   uint64(8734422),\n\t\t\t\t\"packets_sent\": uint64(781),\n\t\t\t\t\"packets_recv\": uint64(23456),\n\t\t\t\t\"err_in\":       uint64(832),\n\t\t\t\t\"err_out\":      uint64(8),\n\t\t\t\t\"drop_in\":      uint64(7),\n\t\t\t\t\"drop_out\":     uint64(1),\n\t\t\t\t\"speed\":        int64(-1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestNetIOStatsNoSpeedFile(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\n\tnetio := net.IOCountersStat{\n\t\tName:        \"eth2\",\n\t\tBytesSent:   1123,\n\t\tBytesRecv:   8734422,\n\t\tPacketsSent: 781,\n\t\tPacketsRecv: 23456,\n\t\tErrin:       832,\n\t\tErrout:      8,\n\t\tDropin:      7,\n\t\tDropout:     1,\n\t}\n\n\tmps.On(\"NetIO\").Return([]net.IOCountersStat{netio}, nil)\n\n\tt.Setenv(\"HOST_SYS\", filepath.Join(\"testdata\", \"general\", \"sys\"))\n\n\tplugin := &Net{ps: &mps, skipChecks: true}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"net\",\n\t\t\tmap[string]string{\"interface\": \"eth2\"},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes_sent\":   uint64(1123),\n\t\t\t\t\"bytes_recv\":   uint64(8734422),\n\t\t\t\t\"packets_sent\": uint64(781),\n\t\t\t\t\"packets_recv\": uint64(23456),\n\t\t\t\t\"err_in\":       uint64(832),\n\t\t\t\t\"err_out\":      uint64(8),\n\t\t\t\t\"drop_in\":      uint64(7),\n\t\t\t\t\"drop_out\":     uint64(1),\n\t\t\t\t\"speed\":        int64(-1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/net/sample.conf",
    "content": "# Gather metrics about network interfaces\n[[inputs.net]]\n  ## By default, telegraf gathers stats from any up interface (excluding loopback)\n  ## Setting interfaces will tell it to gather these explicit interfaces,\n  ## regardless of status. When specifying an interface, glob-style\n  ## patterns are also supported.\n  # interfaces = [\"eth*\", \"enp0s[0-1]\", \"lo\"]\n"
  },
  {
    "path": "plugins/inputs/net/testdata/general/sys/class/net/eth0/speed",
    "content": "100\n"
  },
  {
    "path": "plugins/inputs/net/testdata/general/sys/class/net/eth1/speed",
    "content": "-1\n"
  },
  {
    "path": "plugins/inputs/net_response/README.md",
    "content": "# Network Response Input Plugin\n\nThis plugin tests UDP/TCP connection and produces metrics from the result, the\nresponse time and optionally verifies text in the response.\n\n⭐ Telegraf v0.10.3\n🏷️ network\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect response time of a TCP or UDP connection\n[[inputs.net_response]]\n  ## Protocol, must be \"tcp\" or \"udp\"\n  ## NOTE: because the \"udp\" protocol does not respond to requests, it requires\n  ## a send/expect string pair (see below).\n  protocol = \"tcp\"\n  ## Server address (default localhost)\n  address = \"localhost:80\"\n\n  ## Set timeout\n  # timeout = \"1s\"\n\n  ## Set read timeout (only used if expecting a response)\n  # read_timeout = \"1s\"\n\n  ## The following options are required for UDP checks. For TCP, they are\n  ## optional. The plugin will send the given string to the server and then\n  ## expect to receive the given 'expect' string back.\n  ## string sent to the server\n  # send = \"ssh\"\n  ## expected string in answer\n  # expect = \"ssh\"\n\n  ## Uncomment to remove deprecated fields; recommended for new deploys\n  # fieldexclude = [\"result_type\", \"string_found\"]\n```\n\n## Metrics\n\n- net_response\n  - tags:\n    - server\n    - port\n    - protocol\n    - result\n  - fields:\n    - response_time (float, seconds)\n    - result_code (int) success = 0, timeout = 1, connection_failed = 2,\n                        read_failed = 3, string_mismatch = 4\n    - result_type (string) **DEPRECATED in 1.7; use result tag**\n    - string_found (boolean) **DEPRECATED in 1.4; use result tag**\n\n## Example Output\n\n```text\nnet_response,port=8086,protocol=tcp,result=success,server=localhost response_time=0.000092948,result_code=0i,result_type=\"success\" 1525820185000000000\nnet_response,port=8080,protocol=tcp,result=connection_failed,server=localhost result_code=2i,result_type=\"connection_failed\" 1525820088000000000\nnet_response,port=8080,protocol=udp,result=read_failed,server=localhost result_code=3i,result_type=\"read_failed\",string_found=false 1525820088000000000\n```\n"
  },
  {
    "path": "plugins/inputs/net_response/net_response.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage net_response\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/textproto\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype resultType uint64\n\nconst (\n\tsuccess          resultType = 0\n\ttimeout          resultType = 1\n\tconnectionFailed resultType = 2\n\treadFailed       resultType = 3\n\tstringMismatch   resultType = 4\n)\n\ntype NetResponse struct {\n\tAddress     string          `toml:\"address\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\tReadTimeout config.Duration `toml:\"read_timeout\"`\n\tSend        string          `toml:\"send\"`\n\tExpect      string          `toml:\"expect\"`\n\tProtocol    string          `toml:\"protocol\"`\n}\n\nfunc (*NetResponse) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NetResponse) Init() error {\n\t// Set default values\n\tif n.Timeout == 0 {\n\t\tn.Timeout = config.Duration(time.Second)\n\t}\n\tif n.ReadTimeout == 0 {\n\t\tn.ReadTimeout = config.Duration(time.Second)\n\t}\n\t// Check send and expected string\n\tif n.Protocol == \"udp\" && n.Send == \"\" {\n\t\treturn errors.New(\"send string cannot be empty\")\n\t}\n\tif n.Protocol == \"udp\" && n.Expect == \"\" {\n\t\treturn errors.New(\"expected string cannot be empty\")\n\t}\n\t// Prepare host and port\n\thost, port, err := net.SplitHostPort(n.Address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif host == \"\" {\n\t\tn.Address = \"localhost:\" + port\n\t}\n\tif port == \"\" {\n\t\treturn errors.New(\"bad port in config option address\")\n\t}\n\n\tif err := choice.Check(n.Protocol, []string{\"tcp\", \"udp\"}); err != nil {\n\t\treturn fmt.Errorf(\"config option protocol: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NetResponse) Gather(acc telegraf.Accumulator) error {\n\t// Prepare host and port\n\thost, port, err := net.SplitHostPort(n.Address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Prepare data\n\ttags := map[string]string{\"server\": host, \"port\": port}\n\tvar fields map[string]interface{}\n\tvar returnTags map[string]string\n\n\t// Gather data\n\tswitch n.Protocol {\n\tcase \"tcp\":\n\t\treturnTags, fields, err = n.tcpGather()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags[\"protocol\"] = \"tcp\"\n\tcase \"udp\":\n\t\treturnTags, fields, err = n.udpGather()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttags[\"protocol\"] = \"udp\"\n\t}\n\n\t// Merge the tags\n\tfor k, v := range returnTags {\n\t\ttags[k] = v\n\t}\n\t// Add metrics\n\tacc.AddFields(\"net_response\", fields, tags)\n\treturn nil\n}\n\nfunc (n *NetResponse) tcpGather() (map[string]string, map[string]interface{}, error) {\n\t// Prepare returns\n\ttags := make(map[string]string)\n\tfields := make(map[string]interface{})\n\t// Start Timer\n\tstart := time.Now()\n\t// Connecting\n\tconn, err := net.DialTimeout(\"tcp\", n.Address, time.Duration(n.Timeout))\n\t// Stop timer\n\tresponseTime := time.Since(start).Seconds()\n\t// Handle error\n\tif err != nil {\n\t\tvar e net.Error\n\t\tif errors.As(err, &e) && e.Timeout() {\n\t\t\tsetResult(timeout, fields, tags, n.Expect)\n\t\t} else {\n\t\t\tsetResult(connectionFailed, fields, tags, n.Expect)\n\t\t}\n\t\treturn tags, fields, nil\n\t}\n\tdefer conn.Close()\n\t// Send string if needed\n\tif n.Send != \"\" {\n\t\tmsg := []byte(n.Send)\n\t\tif _, gerr := conn.Write(msg); gerr != nil {\n\t\t\treturn nil, nil, gerr\n\t\t}\n\t\t// Stop timer\n\t\tresponseTime = time.Since(start).Seconds()\n\t}\n\t// Read string if needed\n\tif n.Expect != \"\" {\n\t\t// Set read timeout\n\t\tif gerr := conn.SetReadDeadline(time.Now().Add(time.Duration(n.ReadTimeout))); gerr != nil {\n\t\t\treturn nil, nil, gerr\n\t\t}\n\t\t// Prepare reader\n\t\treader := bufio.NewReader(conn)\n\t\ttp := textproto.NewReader(reader)\n\t\t// Read\n\t\tdata, err := tp.ReadLine()\n\t\t// Stop timer\n\t\tresponseTime = time.Since(start).Seconds()\n\t\t// Handle error\n\t\tif err != nil {\n\t\t\tsetResult(readFailed, fields, tags, n.Expect)\n\t\t} else {\n\t\t\t// Looking for string in answer\n\t\t\tregEx := regexp.MustCompile(`.*` + n.Expect + `.*`)\n\t\t\tfind := regEx.FindString(data)\n\t\t\tif find != \"\" {\n\t\t\t\tsetResult(success, fields, tags, n.Expect)\n\t\t\t} else {\n\t\t\t\tsetResult(stringMismatch, fields, tags, n.Expect)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tsetResult(success, fields, tags, n.Expect)\n\t}\n\tfields[\"response_time\"] = responseTime\n\treturn tags, fields, nil\n}\n\nfunc (n *NetResponse) udpGather() (map[string]string, map[string]interface{}, error) {\n\t// Prepare returns\n\ttags := make(map[string]string)\n\tfields := make(map[string]interface{})\n\t// Start Timer\n\tstart := time.Now()\n\t// Resolving\n\tudpAddr, err := net.ResolveUDPAddr(\"udp\", n.Address)\n\t// Handle error\n\tif err != nil {\n\t\tsetResult(connectionFailed, fields, tags, n.Expect)\n\t\treturn tags, fields, nil\n\t}\n\t// Connecting\n\tconn, err := net.DialUDP(\"udp\", nil, udpAddr)\n\t// Handle error\n\tif err != nil {\n\t\tsetResult(connectionFailed, fields, tags, n.Expect)\n\t\treturn tags, fields, nil\n\t}\n\tdefer conn.Close()\n\t// Send string\n\tmsg := []byte(n.Send)\n\tif _, gerr := conn.Write(msg); gerr != nil {\n\t\treturn nil, nil, gerr\n\t}\n\t// Read string\n\t// Set read timeout\n\tif gerr := conn.SetReadDeadline(time.Now().Add(time.Duration(n.ReadTimeout))); gerr != nil {\n\t\treturn nil, nil, gerr\n\t}\n\t// Read\n\tbuf := make([]byte, 1024)\n\t_, _, err = conn.ReadFromUDP(buf)\n\t// Stop timer\n\tresponseTime := time.Since(start).Seconds()\n\t// Handle error\n\tif err != nil {\n\t\tsetResult(readFailed, fields, tags, n.Expect)\n\t\treturn tags, fields, nil\n\t}\n\n\t// Looking for string in answer\n\tregEx := regexp.MustCompile(`.*` + n.Expect + `.*`)\n\tfind := regEx.FindString(string(buf))\n\tif find != \"\" {\n\t\tsetResult(success, fields, tags, n.Expect)\n\t} else {\n\t\tsetResult(stringMismatch, fields, tags, n.Expect)\n\t}\n\n\tfields[\"response_time\"] = responseTime\n\n\treturn tags, fields, nil\n}\n\nfunc setResult(result resultType, fields map[string]interface{}, tags map[string]string, expect string) {\n\tvar tag string\n\tswitch result {\n\tcase success:\n\t\ttag = \"success\"\n\tcase timeout:\n\t\ttag = \"timeout\"\n\tcase connectionFailed:\n\t\ttag = \"connection_failed\"\n\tcase readFailed:\n\t\ttag = \"read_failed\"\n\tcase stringMismatch:\n\t\ttag = \"string_mismatch\"\n\t}\n\n\ttags[\"result\"] = tag\n\tfields[\"result_code\"] = uint64(result)\n\n\t// deprecated in 1.7; use result tag\n\tfields[\"result_type\"] = tag\n\n\t// deprecated in 1.4; use result tag\n\tif expect != \"\" {\n\t\tfields[\"string_found\"] = result == success\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"net_response\", func() telegraf.Input {\n\t\treturn &NetResponse{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/net_response/net_response_test.go",
    "content": "package net_response\n\nimport (\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestBadProtocol(t *testing.T) {\n\t// Init plugin\n\tc := NetResponse{\n\t\tProtocol: \"unknownprotocol\",\n\t\tAddress:  \":9999\",\n\t}\n\t// Error\n\terr := c.Init()\n\trequire.Error(t, err)\n\trequire.Equal(t, \"config option protocol: unknown choice unknownprotocol\", err.Error())\n}\n\nfunc TestNoPort(t *testing.T) {\n\tc := NetResponse{\n\t\tProtocol: \"tcp\",\n\t\tAddress:  \":\",\n\t}\n\terr := c.Init()\n\trequire.Error(t, err)\n\trequire.Equal(t, \"bad port in config option address\", err.Error())\n}\n\nfunc TestAddressOnly(t *testing.T) {\n\tc := NetResponse{\n\t\tProtocol: \"tcp\",\n\t\tAddress:  \"127.0.0.1\",\n\t}\n\terr := c.Init()\n\trequire.Error(t, err)\n\trequire.Equal(t, \"address 127.0.0.1: missing port in address\", err.Error())\n}\n\nfunc TestSendExpectStrings(t *testing.T) {\n\ttc := NetResponse{\n\t\tProtocol: \"udp\",\n\t\tAddress:  \"127.0.0.1:7\",\n\t\tSend:     \"\",\n\t\tExpect:   \"toast\",\n\t}\n\tuc := NetResponse{\n\t\tProtocol: \"udp\",\n\t\tAddress:  \"127.0.0.1:7\",\n\t\tSend:     \"toast\",\n\t\tExpect:   \"\",\n\t}\n\terr := tc.Init()\n\trequire.Error(t, err)\n\trequire.Equal(t, \"send string cannot be empty\", err.Error())\n\terr = uc.Init()\n\trequire.Error(t, err)\n\trequire.Equal(t, \"expected string cannot be empty\", err.Error())\n}\n\nfunc TestTCPError(t *testing.T) {\n\tvar acc testutil.Accumulator\n\t// Init plugin\n\tc := NetResponse{\n\t\tProtocol: \"tcp\",\n\t\tAddress:  \":9999\",\n\t\tTimeout:  config.Duration(time.Second * 30),\n\t}\n\trequire.NoError(t, c.Init())\n\t// Gather\n\trequire.NoError(t, c.Gather(&acc))\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"net_response\",\n\t\tmap[string]interface{}{\n\t\t\t\"result_code\": uint64(2),\n\t\t\t\"result_type\": \"connection_failed\",\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\":   \"localhost\",\n\t\t\t\"port\":     \"9999\",\n\t\t\t\"protocol\": \"tcp\",\n\t\t\t\"result\":   \"connection_failed\",\n\t\t},\n\t)\n}\n\nfunc TestTCPOK1(t *testing.T) {\n\tvar wg sync.WaitGroup\n\tvar acc testutil.Accumulator\n\t// Init plugin\n\tc := NetResponse{\n\t\tAddress:     \"127.0.0.1:2004\",\n\t\tSend:        \"test\",\n\t\tExpect:      \"test\",\n\t\tReadTimeout: config.Duration(time.Second * 3),\n\t\tTimeout:     config.Duration(time.Second),\n\t\tProtocol:    \"tcp\",\n\t}\n\trequire.NoError(t, c.Init())\n\t// Start TCP server\n\twg.Add(1)\n\tgo tcpServer(t, &wg)\n\twg.Wait() // Wait for the server to spin up\n\twg.Add(1)\n\t// Connect\n\trequire.NoError(t, c.Gather(&acc))\n\tacc.Wait(1)\n\n\t// Override response time\n\tfor _, p := range acc.Metrics {\n\t\tp.Fields[\"response_time\"] = 1.0\n\t}\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"net_response\",\n\t\tmap[string]interface{}{\n\t\t\t\"result_code\":   uint64(0),\n\t\t\t\"result_type\":   \"success\",\n\t\t\t\"string_found\":  true,\n\t\t\t\"response_time\": 1.0,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"result\":   \"success\",\n\t\t\t\"server\":   \"127.0.0.1\",\n\t\t\t\"port\":     \"2004\",\n\t\t\t\"protocol\": \"tcp\",\n\t\t},\n\t)\n\t// Waiting TCPserver\n\twg.Wait()\n}\n\nfunc TestTCPOK2(t *testing.T) {\n\tvar wg sync.WaitGroup\n\tvar acc testutil.Accumulator\n\t// Init plugin\n\tc := NetResponse{\n\t\tAddress:     \"127.0.0.1:2004\",\n\t\tSend:        \"test\",\n\t\tExpect:      \"test2\",\n\t\tReadTimeout: config.Duration(time.Second * 3),\n\t\tTimeout:     config.Duration(time.Second),\n\t\tProtocol:    \"tcp\",\n\t}\n\trequire.NoError(t, c.Init())\n\t// Start TCP server\n\twg.Add(1)\n\tgo tcpServer(t, &wg)\n\twg.Wait()\n\twg.Add(1)\n\n\t// Connect\n\trequire.NoError(t, c.Gather(&acc))\n\tacc.Wait(1)\n\n\t// Override response time\n\tfor _, p := range acc.Metrics {\n\t\tp.Fields[\"response_time\"] = 1.0\n\t}\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"net_response\",\n\t\tmap[string]interface{}{\n\t\t\t\"result_code\":   uint64(4),\n\t\t\t\"result_type\":   \"string_mismatch\",\n\t\t\t\"string_found\":  false,\n\t\t\t\"response_time\": 1.0,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"result\":   \"string_mismatch\",\n\t\t\t\"server\":   \"127.0.0.1\",\n\t\t\t\"port\":     \"2004\",\n\t\t\t\"protocol\": \"tcp\",\n\t\t},\n\t)\n\t// Waiting TCPserver\n\twg.Wait()\n}\n\nfunc TestUDPError(t *testing.T) {\n\tvar acc testutil.Accumulator\n\t// Init plugin\n\tc := NetResponse{\n\t\tAddress:  \":9999\",\n\t\tSend:     \"test\",\n\t\tExpect:   \"test\",\n\t\tProtocol: \"udp\",\n\t}\n\trequire.NoError(t, c.Init())\n\t// Gather\n\trequire.NoError(t, c.Gather(&acc))\n\tacc.Wait(1)\n\n\t// Override response time\n\tfor _, p := range acc.Metrics {\n\t\tp.Fields[\"response_time\"] = 1.0\n\t}\n\t// Error\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"net_response\",\n\t\tmap[string]interface{}{\n\t\t\t\"result_code\":   uint64(3),\n\t\t\t\"result_type\":   \"read_failed\",\n\t\t\t\"response_time\": 1.0,\n\t\t\t\"string_found\":  false,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"result\":   \"read_failed\",\n\t\t\t\"server\":   \"localhost\",\n\t\t\t\"port\":     \"9999\",\n\t\t\t\"protocol\": \"udp\",\n\t\t},\n\t)\n}\n\nfunc TestUDPOK1(t *testing.T) {\n\tvar wg sync.WaitGroup\n\tvar acc testutil.Accumulator\n\t// Init plugin\n\tc := NetResponse{\n\t\tAddress:     \"127.0.0.1:2004\",\n\t\tSend:        \"test\",\n\t\tExpect:      \"test\",\n\t\tReadTimeout: config.Duration(time.Second * 3),\n\t\tTimeout:     config.Duration(time.Second),\n\t\tProtocol:    \"udp\",\n\t}\n\trequire.NoError(t, c.Init())\n\t// Start UDP server\n\twg.Add(1)\n\tgo udpServer(t, &wg)\n\twg.Wait()\n\twg.Add(1)\n\n\t// Connect\n\trequire.NoError(t, c.Gather(&acc))\n\tacc.Wait(1)\n\n\t// Override response time\n\tfor _, p := range acc.Metrics {\n\t\tp.Fields[\"response_time\"] = 1.0\n\t}\n\tacc.AssertContainsTaggedFields(t,\n\t\t\"net_response\",\n\t\tmap[string]interface{}{\n\t\t\t\"result_code\":   uint64(0),\n\t\t\t\"result_type\":   \"success\",\n\t\t\t\"string_found\":  true,\n\t\t\t\"response_time\": 1.0,\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"result\":   \"success\",\n\t\t\t\"server\":   \"127.0.0.1\",\n\t\t\t\"port\":     \"2004\",\n\t\t\t\"protocol\": \"udp\",\n\t\t},\n\t)\n\t// Waiting TCPserver\n\twg.Wait()\n}\n\nfunc udpServer(t *testing.T, wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\tudpAddr, err := net.ResolveUDPAddr(\"udp\", \"127.0.0.1:2004\")\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tconn, err := net.ListenUDP(\"udp\", udpAddr)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\twg.Done()\n\tbuf := make([]byte, 1024)\n\t_, remoteaddr, err := conn.ReadFromUDP(buf)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif _, err = conn.WriteToUDP(buf, remoteaddr); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif err = conn.Close(); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc tcpServer(t *testing.T, wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", \"127.0.0.1:2004\")\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\ttcpServer, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\twg.Done()\n\tconn, err := tcpServer.AcceptTCP()\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tbuf := make([]byte, 1024)\n\tif _, err = conn.Read(buf); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif _, err = conn.Write(buf); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif err = conn.CloseWrite(); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif err = tcpServer.Close(); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/net_response/sample.conf",
    "content": "# Collect response time of a TCP or UDP connection\n[[inputs.net_response]]\n  ## Protocol, must be \"tcp\" or \"udp\"\n  ## NOTE: because the \"udp\" protocol does not respond to requests, it requires\n  ## a send/expect string pair (see below).\n  protocol = \"tcp\"\n  ## Server address (default localhost)\n  address = \"localhost:80\"\n\n  ## Set timeout\n  # timeout = \"1s\"\n\n  ## Set read timeout (only used if expecting a response)\n  # read_timeout = \"1s\"\n\n  ## The following options are required for UDP checks. For TCP, they are\n  ## optional. The plugin will send the given string to the server and then\n  ## expect to receive the given 'expect' string back.\n  ## string sent to the server\n  # send = \"ssh\"\n  ## expected string in answer\n  # expect = \"ssh\"\n\n  ## Uncomment to remove deprecated fields; recommended for new deploys\n  # fieldexclude = [\"result_type\", \"string_found\"]\n"
  },
  {
    "path": "plugins/inputs/netflow/README.md",
    "content": "# Netflow Input Plugin\n\nThis service plugin acts as a collector for Netflow v5, Netflow v9 and IPFIX\nflow information. The Layer 4 protocol numbers are gathered from the\n[official IANA assignments][IANA assignments].\nThe internal field mappings for Netflow v5 fields are defined according to\n[Cisco's Netflow v5 documentation][CISCO NF5], Netflow v9 fields are defined\naccording to [Cisco's Netflow v9 documentation][CISCO NF9] and the\n[ASA extensions][ASA extensions].\nDefinitions for IPFIX are according to [IANA assignment document][IPFIX doc].\n\n⭐ Telegraf v1.25.0\n🏷️ network\n💻 all\n\n[IANA assignments]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml\n[CISCO NF5]:        https://www.cisco.com/c/en/us/td/docs/net_mgmt/netflow_collection_engine/3-6/user/guide/format.html#wp1006186\n[CISCO NF9]:        https://www.cisco.com/en/US/technologies/tk648/tk362/technologies_white_paper09186a00800a3db9.html\n[ASA extensions]:   https://www.cisco.com/c/en/us/td/docs/security/asa/special/netflow/asa_netflow.html\n[IPFIX doc]:        https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-nat-type\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Netflow v5, Netflow v9 and IPFIX collector\n[[inputs.netflow]]\n  ## Address to listen for netflow,ipfix or sflow packets.\n  ##   example: service_address = \"udp://:2055\"\n  ##            service_address = \"udp4://:2055\"\n  ##            service_address = \"udp6://:2055\"\n  service_address = \"udp://:2055\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  ## Uses the system's default if not set.\n  # read_buffer_size = \"\"\n\n  ## Protocol version to use for decoding.\n  ## Available options are\n  ##   \"ipfix\"      -- IPFIX / Netflow v10 protocol (also works for Netflow v9)\n  ##   \"netflow v5\" -- Netflow v5 protocol\n  ##   \"netflow v9\" -- Netflow v9 protocol (also works for IPFIX)\n  ##   \"sflow v5\"   -- sFlow v5 protocol\n  # protocol = \"ipfix\"\n\n  ## Private Enterprise Numbers (PEN) mappings for decoding\n  ## This option allows to specify vendor-specific mapping files to use during\n  ## decoding.\n  # private_enterprise_number_files = []\n\n  ## Log incoming packets for tracing issues\n  # log_level = \"trace\"\n```\n\n## Private Enterprise Number mapping\n\nUsing the `private_enterprise_number_files` option you can specify mappings for\nvendor-specific element-IDs with a PEN specification. The mapping has to be a\ncomma-separated-file (CSV) containing the element's `ID`, its `name` and the\n`data-type`. A comma (`,`) is used as separator and comments are allowed using\nthe hash (`#`) prefix.\nThe element `ID` has the form `<pen-number>.<element-id>`, the `name` has to be\na valid field-name and `data-type` denotes the mapping of the raw-byte value to\nthe field's type. For example\n\n```csv\n# PEN.ID, name, data type\n35632.349,in_src_osi_sap,hex\n35632.471,nprobe_ipv4_address,ip\n35632.1028,protocol_ntop,string\n35632.1036,l4_srv_port,uint\n```\n\nspecify four elements (`349`, `471`, `1028` and `1036`) for PEN `35632` (ntop)\nwith the corresponding name and data-type.\n\nCurrently the following `data-type`s are supported:\n\n- `bool`    TruthValue according to [RFC5101][RFC5101]\n- `int`     signed integer with 8, 16, 32 or 64 bit\n- `uint`    unsigned integer with 8, 16, 32 or 64 bit\n- `float32` double-precision floating-point number (32 bit)\n- `float64` double-precision floating-point number (64 bit)\n- `hex`     hex-encoding of the raw byte sequence with `0x` prefix\n- `string`  string interpretation of the raw byte sequence\n- `mac`     MAC address\n- `ip`      IPv4 or IPv6 address\n- `proto`   mapping of layer-4 protocol numbers to names\n\n[RFC5101]: https://www.rfc-editor.org/rfc/rfc5101#section-6.1.5\n\n## Troubleshooting\n\n### `Error template not found` warnings\n\nThose warnings usually occur in cases where Telegraf is restarted or reloaded\nwhile the flow-device is already streaming data.\nAs background, the Netflow and IPFIX protocols rely on templates sent by the\nflow-device to decode fields. Without those templates, it is not clear what the\ndata-type and size of the payload is and this makes it impossible to correctly\ninterpret the data. However, templates are sent by the flow-device, usually at\nthe start of streaming and in regular intervals (configurable in the device) and\nTelegraf has no means to trigger sending of the templates. Therefore, we need to\nskip the packets until the templates are resent by the device.\n\n## Metrics are missing at the output\n\nThe metrics produced by this plugin are not tagged in a connection specific\nmanner, therefore outputs relying on unique series key (e.g. InfluxDB) require\nthe metrics to contain tags for the protocol, the connection source and the\nconnection destination. Otherwise, metrics might be overwritten and are thus\nmissing.\n\nThe required tagging can be achieved using the `converter` processor\n\n```toml\n[[processors.converter]]\n  [processors.converter.fields]\n    tag = [\"protocol\", \"src\", \"src_port\", \"dst\", \"dst_port\"]\n```\n\n__Please be careful as this will produce metrics with high cardinality!__\n\n## Metrics\n\nMetrics depend on the format used as well as on the information provided\nby the exporter. Furthermore, proprietary information might be sent requiring\nfurther decoding information. Most exporters should provide at least the\nfollowing information\n\n- netflow\n  - tags:\n    - source (IP of the exporter sending the data)\n    - version (flow protocol version)\n  - fields:\n    - src (IP address, address of the source of the packets)\n    - src_mask (uint64, mask for the IP address in bits)\n    - dst (IP address, address of the destination of the packets)\n    - dst_mask (uint64, mask for the IP address in bits)\n    - src_port (uint64, source port)\n    - dst_port (uint64, destination port)\n    - protocol (string, Layer 4 protocol name)\n    - in_bytes (uint64, number of incoming bytes)\n    - in_packets (uint64, number of incoming packets)\n    - tcp_flags (string, TCP flags for the flow)\n\n## Example Output\n\nThe specific fields vary for the different protocol versions, here are some\nexamples\n\n### IPFIX\n\n```text\nnetflow,source=127.0.0.1,version=IPFIX protocol=\"tcp\",vlan_src=0u,src_tos=\"0x00\",flow_end_ms=1666345513807u,src=\"192.168.119.100\",dst=\"44.233.90.52\",src_port=51008u,total_bytes_exported=0u,flow_end_reason=\"end of flow\",flow_start_ms=1666345513807u,in_total_bytes=52u,in_total_packets=1u,dst_port=443u\nnetflow,source=127.0.0.1,version=IPFIX src_tos=\"0x00\",src_port=54330u,rev_total_bytes_exported=0u,last_switched=9u,vlan_src=0u,flow_start_ms=1666345513807u,in_total_packets=1u,flow_end_reason=\"end of flow\",flow_end_ms=1666345513816u,in_total_bytes=40u,dst_port=443u,src=\"192.168.119.100\",dst=\"104.17.240.92\",total_bytes_exported=0u,protocol=\"tcp\"\nnetflow,source=127.0.0.1,version=IPFIX flow_start_ms=1666345513807u,flow_end_ms=1666345513977u,src=\"192.168.119.100\",dst_port=443u,total_bytes_exported=0u,last_switched=170u,src_tos=\"0x00\",in_total_bytes=40u,dst=\"44.233.90.52\",src_port=51024u,protocol=\"tcp\",flow_end_reason=\"end of flow\",in_total_packets=1u,rev_total_bytes_exported=0u,vlan_src=0u\nnetflow,source=127.0.0.1,version=IPFIX src_port=58246u,total_bytes_exported=1u,flow_start_ms=1666345513806u,flow_end_ms=1666345513806u,in_total_bytes=156u,src=\"192.168.119.100\",rev_total_bytes_exported=0u,last_switched=0u,flow_end_reason=\"forced end\",dst=\"192.168.119.17\",dst_port=53u,protocol=\"udp\",in_total_packets=2u,vlan_src=0u,src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=IPFIX protocol=\"udp\",vlan_src=0u,src_port=58879u,dst_port=53u,flow_end_ms=1666345513832u,src_tos=\"0x00\",src=\"192.168.119.100\",total_bytes_exported=1u,rev_total_bytes_exported=0u,flow_end_reason=\"forced end\",last_switched=33u,in_total_bytes=221u,in_total_packets=2u,flow_start_ms=1666345513799u,dst=\"192.168.119.17\"\n```\n\n### Netflow v5\n\n```text\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.121.3\",src_port=443u,dst=\"192.168.119.100\",dst_port=55516u,flows=8u,in_bytes=87477u,in_packets=78u,first_switched=86400660u,last_switched=86403316u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.121.6\",src_port=443u,dst=\"192.168.119.100\",dst_port=36408u,flows=8u,in_bytes=5009u,in_packets=21u,first_switched=86400447u,last_switched=86403267u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.112.22\",src_port=443u,dst=\"192.168.119.100\",dst_port=39638u,flows=8u,in_bytes=925u,in_packets=6u,first_switched=86400324u,last_switched=86403214u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.114.26\",src_port=443u,dst=\"192.168.119.100\",dst_port=49398u,flows=8u,in_bytes=250u,in_packets=2u,first_switched=86403131u,last_switched=86403362u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=55516u,dst=\"140.82.121.3\",dst_port=443u,flows=8u,in_bytes=4969u,in_packets=37u,first_switched=86400652u,last_switched=86403269u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=36408u,dst=\"140.82.121.6\",dst_port=443u,flows=8u,in_bytes=2736u,in_packets=21u,first_switched=86400438u,last_switched=86403258u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=39638u,dst=\"140.82.112.22\",dst_port=443u,flows=8u,in_bytes=1560u,in_packets=6u,first_switched=86400225u,last_switched=86403255u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=49398u,dst=\"140.82.114.26\",dst_port=443u,flows=8u,in_bytes=697u,in_packets=4u,first_switched=86403030u,last_switched=86403362u,tcp_flags=\"...PA...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\n```\n\n### Netflow v9\n\n```text\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.121.3\",src_port=443u,dst=\"192.168.119.100\",dst_port=55516u,in_bytes=87477u,in_packets=78u,flow_start_ms=1666350478660u,flow_end_ms=1666350481316u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.121.6\",src_port=443u,dst=\"192.168.119.100\",dst_port=36408u,in_bytes=5009u,in_packets=21u,flow_start_ms=1666350478447u,flow_end_ms=1666350481267u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.112.22\",src_port=443u,dst=\"192.168.119.100\",dst_port=39638u,in_bytes=925u,in_packets=6u,flow_start_ms=1666350478324u,flow_end_ms=1666350481214u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.114.26\",src_port=443u,dst=\"192.168.119.100\",dst_port=49398u,in_bytes=250u,in_packets=2u,flow_start_ms=1666350481131u,flow_end_ms=1666350481362u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=55516u,dst=\"140.82.121.3\",dst_port=443u,in_bytes=4969u,in_packets=37u,flow_start_ms=1666350478652u,flow_end_ms=1666350481269u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=36408u,dst=\"140.82.121.6\",dst_port=443u,in_bytes=2736u,in_packets=21u,flow_start_ms=1666350478438u,flow_end_ms=1666350481258u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=39638u,dst=\"140.82.112.22\",dst_port=443u,in_bytes=1560u,in_packets=6u,flow_start_ms=1666350478225u,flow_end_ms=1666350481255u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=49398u,dst=\"140.82.114.26\",dst_port=443u,in_bytes=697u,in_packets=4u,flow_start_ms=1666350481030u,flow_end_ms=1666350481362u,tcp_flags=\"...PA...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\n```\n\n### sFlow v5\n\n```text\nnetflow,source=127.0.0.1,version=sFlowV5 out_errors=0i,out_bytes=3946i,status=\"up\",in_unknown_protocol=4294967295i,out_unicast_packets_total=29i,agent_subid=100000i,interface_type=6i,in_unicast_packets_total=28i,out_dropped_packets=0i,in_bytes=3910i,in_broadcast_packets_total=4294967295i,ip_version=\"IPv4\",agent_ip=\"192.168.119.184\",in_snmp=3i,in_errors=0i,promiscuous=0i,interface=3i,in_mcast_packets_total=4294967295i,in_dropped_packets=0i,sys_uptime=12414i,seq_number=2i,speed=1000000000i,out_mcast_packets_total=4294967295i,out_broadcast_packets_total=4294967295i 12414000000\nnetflow,source=127.0.0.1,version=sFlowV5 sys_uptime=17214i,agent_ip=\"192.168.119.184\",agent_subid=100000i,seq_number=2i,in_phy_interface=1i,ip_version=\"IPv4\" 17214000000\nnetflow,source=127.0.0.1,version=sFlowV5 in_errors=0i,out_unicast_packets_total=36i,interface=3i,in_broadcast_packets_total=4294967295i,ip_version=\"IPv4\",speed=1000000000i,out_bytes=4408i,out_mcast_packets_total=4294967295i,status=\"up\",in_snmp=3i,in_mcast_packets_total=4294967295i,out_broadcast_packets_total=4294967295i,promiscuous=0i,in_bytes=5568i,out_dropped_packets=0i,sys_uptime=22014i,agent_subid=100000i,in_unknown_protocol=4294967295i,interface_type=6i,in_dropped_packets=0i,in_unicast_packets_total=37i,out_errors=0i,agent_ip=\"192.168.119.184\",seq_number=3i 22014000000\n\n```\n"
  },
  {
    "path": "plugins/inputs/netflow/ipv4_options.csv",
    "content": "Number,Name\n0,EOOL\n1,NOP\n2,SEC\n3,LSR\n4,TS\n5,E-SEC\n6,CIPSO\n7,RR\n8,SID\n9,SSR\n10,ZSU\n11,MTUP\n12,MTUR\n13,FINN\n14,VISA\n15,ENCODE\n16,IMITD\n17,EIP\n18,TR\n19,ADDEXT\n20,RTRALT\n21,SDB\n23,DPS\n24,UMP\n25,QS\n30,EXP\n"
  },
  {
    "path": "plugins/inputs/netflow/layer4_protocol_numbers.csv",
    "content": "Decimal,Keyword\n0,HOPOPT\n1,ICMP\n2,IGMP\n3,GGP\n4,IPv4\n5,ST\n6,TCP\n7,CBT\n8,EGP\n9,IGP\n10,BBN-RCC-MON\n11,NVP-II\n12,PUP\n13,ARGUS\n14,EMCON\n15,XNET\n16,CHAOS\n17,UDP\n18,MUX\n19,DCN-MEAS\n20,HMP\n21,PRM\n22,XNS-IDP\n23,TRUNK-1\n24,TRUNK-2\n25,LEAF-1\n26,LEAF-2\n27,RDP\n28,IRTP\n29,ISO-TP4\n30,NETBLT\n31,MFE-NSP\n32,MERIT-INP\n33,DCCP\n34,3PC\n35,IDPR\n36,XTP\n37,DDP\n38,IDPR-CMTP\n39,TP++\n40,IL\n41,IPv6\n42,SDRP\n43,IPv6-Route\n44,IPv6-Frag\n45,IDRP\n46,RSVP\n47,GRE\n48,DSR\n49,BNA\n50,ESP\n51,AH\n52,I-NLSP\n53,SWIPE (deprecated)\n54,NARP\n55,MOBILE\n56,TLSP\n57,SKIP\n58,IPv6-ICMP\n59,IPv6-NoNxt\n60,IPv6-Opts\n61,host internal\n62,CFTP\n63,local network\n64,SAT-EXPAK\n65,KRYPTOLAN\n66,RVD\n67,IPPC\n68,distributed FS\n69,SAT-MON\n70,VISA\n71,IPCV\n72,CPNX\n73,CPHB\n74,WSN\n75,PVP\n76,BR-SAT-MON\n77,SUN-ND\n78,WB-MON\n79,WB-EXPAK\n80,ISO-IP\n81,VMTP\n82,SECURE-VMTP\n83,VINES\n84,TTP\n84,IPTM\n85,NSFNET-IGP\n86,DGP\n87,TCF\n88,EIGRP\n89,OSPFIGP\n90,Sprite-RPC\n91,LARP\n92,MTP\n93,AX.25\n94,IPIP\n95,MICP (deprecated)\n96,SCC-SP\n97,ETHERIP\n98,ENCAP\n99,private encryption scheme\n100,GMTP\n101,IFMP\n102,PNNI\n103,PIM\n104,ARIS\n105,SCPS\n106,QNX\n107,A/N\n108,IPComp\n109,SNP\n110,Compaq-Peer\n111,IPX-in-IP\n112,VRRP\n113,PGM\n114,0-hop\n115,L2TP\n116,DDX\n117,IATP\n118,STP\n119,SRP\n120,UTI\n121,SMP\n122,SM (deprecated)\n123,PTP\n124,ISIS over IPv4\n125,FIRE\n126,CRTP\n127,CRUDP\n128,SSCOPMCE\n129,IPLT\n130,SPS\n131,PIPE\n132,SCTP\n133,FC\n134,RSVP-E2E-IGNORE\n135,Mobility Header\n136,UDPLite\n137,MPLS-in-IP\n138,manet\n139,HIP\n140,Shim6\n141,WESP\n142,ROHC\n143,Ethernet\n144,AGGFRAG\n145-252,\n253,experimental\n254,experimental\n255,Reserved\n"
  },
  {
    "path": "plugins/inputs/netflow/mappings.go",
    "content": "package netflow\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n)\n\nvar funcMapping = map[string]decoderFunc{\n\t\"bool\":    decodeBool,\n\t\"int\":     decodeInt,\n\t\"uint\":    decodeUint,\n\t\"float32\": decodeFloat32,\n\t\"float64\": decodeFloat64,\n\t\"hex\":     decodeHex,\n\t\"string\":  decodeString,\n\t\"mac\":     decodeMAC,\n\t\"ip\":      decodeIP,\n\t\"proto\":   decodeL4Proto,\n}\n\nfunc loadMapping(filename string) (map[string]fieldMapping, error) {\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"opening %q failed: %w\", filename, err)\n\t}\n\tdefer file.Close()\n\n\treader := csv.NewReader(file)\n\treader.Comma = ','\n\treader.Comment = '#'\n\treader.TrimLeadingSpace = true\n\trecords, err := reader.ReadAll()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading csv failed: %w\", err)\n\t}\n\n\tmappings := make(map[string]fieldMapping, len(records))\n\tfor _, r := range records {\n\t\tid, name, dtype := r[0], r[1], r[2]\n\t\tfun, found := funcMapping[dtype]\n\t\tif !found {\n\t\t\treturn nil, fmt.Errorf(\"unknown data-type %q for id %q\", dtype, id)\n\t\t}\n\t\tmappings[id] = fieldMapping{name, fun}\n\t}\n\n\treturn mappings, nil\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/mappings_ipfix_pen/ntop-35632.csv",
    "content": "# The following data is extracted from\n#   https://www.ntop.org/guides/nprobe/flow_information_elements.html\n# and contains IPFIX element definitions for Private Enterprise Number (PEN)\n# 35632 (ntop)\n#\n# PEN.ID, name, data type\n35632.1028,protocol_ntop,string\n35632.1031,l4_src_port_name,string\n35632.1035,l4_dst_port_name,string\n35632.1036,l4_srv_port,uint\n35632.1037,l4_srv_port_name,string\n35632.80,src_fragments,uint\n35632.81,dst_fragments,uint\n35632.123,client_nw_latency_ms,uint\n35632.124,server_nw_latency_ms,uint\n35632.78,client_tcp_flags,uint\n35632.79,server_tcp_flags,uint\n35632.125,app_latency_ms,uint\n35632.471,nprobe_ipv4_address,ip\n35632.82,src_to_dst_max_throughput,uint\n35632.83,src_to_dst_min_throughput,uint\n35632.84,src_to_dst_avg_throughput,uint\n35632.85,dst_to_src_max_throughput,uint\n35632.86,dst_to_src_min_throughput,uint\n35632.87,dst_to_src_avg_throughput,uint\n35632.88,pkts_up_to_128_bytes,uint\n35632.89,pkts_128_to_256_bytes,uint\n35632.90,pkts_256_to_512_bytes,uint\n35632.91,pkts_512_to_1024_bytes,uint\n35632.92,pkts_1024_to_1514_bytes,uint\n35632.93,pkts_over_1514_bytes,uint\n35632.98,cumulative_icmp_type,uint\n35632.101,src_ip_country,string\n35632.102,src_ip_city,string\n35632.103,dst_ip_country,string\n35632.104,dst_ip_city,string\n35632.448,src_ip_long,hex\n35632.449,src_ip_lat,hex\n35632.450,dst_ip_long,hex\n35632.451,dst_ip_lat,hex\n35632.105,flow_proto_port,uint\n35632.106,upstream_tunnel_id,uint\n35632.446,upstream_session_id,uint\n35632.107,longest_flow_pkt,uint\n35632.108,shortest_flow_pkt,uint\n35632.127,retransmitted_in_bytes,uint\n35632.109,retransmitted_in_pkts,uint\n35632.128,retransmitted_out_bytes,uint\n35632.110,retransmitted_out_pkts,uint\n35632.111,ooorder_in_pkts,uint\n35632.112,ooorder_out_pkts,uint\n35632.113,untunneled_protocol,proto\n35632.114,untunneled_ipv4_src_addr,ip\n35632.115,untunneled_l4_src_port,uint\n35632.116,untunneled_ipv4_dst_addr,ip\n35632.117,untunneled_l4_dst_port,uint\n35632.118,l7_proto,uint\n35632.119,l7_proto_name,string\n35632.120,downstream_tunnel_id,uint\n35632.447,downstream_session_id,uint\n35632.188,ssl_server_name,string\n35632.189,bittorrent_hash,string\n35632.121,flow_user_name,string\n35632.122,flow_server_name,string\n35632.126,plugin_name,string\n35632.396,untunneled_ipv6_src_addr,ip\n35632.397,untunneled_ipv6_dst_addr,ip\n35632.347,pkts_ttl_eq_1,uint\n35632.346,pkts_ttl_2_5,uint\n35632.334,pkts_ttl_5_32,uint\n35632.335,pkts_ttl_32_64,uint\n35632.336,pkts_ttl_64_96,uint\n35632.337,pkts_ttl_96_128,uint\n35632.338,pkts_ttl_128_160,uint\n35632.339,pkts_ttl_160_192,uint\n35632.340,pkts_ttl_192_224,uint\n35632.341,pkts_ttl_224_255,uint\n35632.349,in_src_osi_sap,hex\n35632.350,out_dst_osi_sap,hex\n35632.391,duration_in,uint\n35632.392,duration_out,uint\n35632.415,tcp_win_min_in,uint\n35632.416,tcp_win_max_in,uint\n35632.417,tcp_win_mss_in,uint\n35632.418,tcp_win_scale_in,uint\n35632.419,tcp_win_min_out,uint\n35632.420,tcp_win_max_out,uint\n35632.421,tcp_win_mss_out,uint\n35632.422,tcp_win_scale_out,uint\n35632.438,payload_hash,uint\n35632.443,src_as_name,string\n35632.444,dst_as_name,string\n35632.472,src_to_dst_second_bytes,uint\n35632.473,dst_to_src_second_bytes,uint\n35632.489,ja3c_hash,string\n35632.490,ja3s_hash,string\n35632.491,src_host_name,string\n35632.492,dst_host_name,string\n35632.493,ssl_cipher,uint\n35632.494,ssl_unsafe_cipher,uint\n35632.495,ssl_version,uint\n"
  },
  {
    "path": "plugins/inputs/netflow/netflow.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage netflow\n\nimport (\n\t_ \"embed\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NetFlow struct {\n\tServiceAddress string          `toml:\"service_address\"`\n\tReadBufferSize config.Size     `toml:\"read_buffer_size\"`\n\tProtocol       string          `toml:\"protocol\"`\n\tDumpPackets    bool            `toml:\"dump_packets\" deprecated:\"1.35.0;use 'log_level' 'trace' instead\"`\n\tPENFiles       []string        `toml:\"private_enterprise_number_files\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tconn    *net.UDPConn\n\tdecoder protocolDecoder\n\twg      sync.WaitGroup\n}\n\ntype protocolDecoder interface {\n\tinit() error\n\tdecode(net.IP, []byte) ([]telegraf.Metric, error)\n}\n\nfunc (*NetFlow) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NetFlow) Init() error {\n\tif n.ServiceAddress == \"\" {\n\t\treturn errors.New(\"service_address required\")\n\t}\n\tu, err := url.Parse(n.ServiceAddress)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid service address %q: %w\", n.ServiceAddress, err)\n\t}\n\tswitch u.Scheme {\n\tcase \"udp\", \"udp4\", \"udp6\":\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid scheme %q, should be 'udp', 'udp4' or 'udp6'\", u.Scheme)\n\t}\n\n\tswitch strings.ToLower(n.Protocol) {\n\tcase \"netflow v9\":\n\t\tif len(n.PENFiles) != 0 {\n\t\t\tn.Log.Warn(\"'private_enterprise_number_files' option will be ignored in 'netflow v9'\")\n\t\t}\n\t\tn.decoder = &netflowDecoder{\n\t\t\tlog: n.Log,\n\t\t}\n\tcase \"\", \"ipfix\":\n\t\tn.decoder = &netflowDecoder{\n\t\t\tpenFiles: n.PENFiles,\n\t\t\tlog:      n.Log,\n\t\t}\n\tcase \"netflow v5\":\n\t\tif len(n.PENFiles) != 0 {\n\t\t\tn.Log.Warn(\"'private_enterprise_number_files' option will be ignored in 'netflow v5'\")\n\t\t}\n\t\tn.decoder = &netflowv5Decoder{}\n\tcase \"sflow\", \"sflow v5\":\n\t\tn.decoder = &sflowv5Decoder{log: n.Log}\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid protocol %q, only supports 'sflow', 'netflow v5', 'netflow v9' and 'ipfix'\", n.Protocol)\n\t}\n\n\treturn n.decoder.init()\n}\n\nfunc (n *NetFlow) Start(acc telegraf.Accumulator) error {\n\tu, err := url.Parse(n.ServiceAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\taddr, err := net.ResolveUDPAddr(u.Scheme, u.Host)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err := net.ListenUDP(u.Scheme, addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\tn.conn = conn\n\n\tif n.ReadBufferSize > 0 {\n\t\tif err := conn.SetReadBuffer(int(n.ReadBufferSize)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tn.Log.Infof(\"Listening on %s://%s\", n.conn.LocalAddr().Network(), n.conn.LocalAddr().String())\n\n\tn.wg.Add(1)\n\tgo func() {\n\t\tdefer n.wg.Done()\n\t\tn.read(acc)\n\t}()\n\n\treturn nil\n}\n\nfunc (*NetFlow) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (n *NetFlow) Stop() {\n\tif n.conn != nil {\n\t\t_ = n.conn.Close()\n\t}\n\tn.wg.Wait()\n}\n\nfunc (n *NetFlow) read(acc telegraf.Accumulator) {\n\tbuf := make([]byte, 64*1024) // 64kB\n\tfor {\n\t\tcount, src, err := n.conn.ReadFromUDP(buf)\n\t\tif err != nil {\n\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tn.Log.Debugf(\"received %d bytes\\n\", count)\n\t\tif count < 1 {\n\t\t\tcontinue\n\t\t}\n\t\tif n.Log.Level().Includes(telegraf.Trace) || n.DumpPackets { // for backward compatibility\n\t\t\tn.Log.Tracef(\"raw data: %s\", hex.EncodeToString(buf[:count]))\n\t\t}\n\t\tmetrics, err := n.decoder.decode(src.IP, buf[:count])\n\t\tif err != nil {\n\t\t\terrWithData := fmt.Errorf(\"%w; raw data: %s\", err, hex.EncodeToString(buf[:count]))\n\t\t\tacc.AddError(errWithData)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, m := range metrics {\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t}\n}\n\n// Register the plugin\nfunc init() {\n\tinputs.Add(\"netflow\", func() telegraf.Input {\n\t\treturn &NetFlow{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/netflow_decoder.go",
    "content": "package netflow\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/netsampler/goflow2/v2/decoders/netflow\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nvar regexpIPFIXPENMapping = regexp.MustCompile(`\\d+\\.\\d+`)\n\ntype decoderFunc func([]byte) (interface{}, error)\n\ntype fieldMapping struct {\n\tname    string\n\tdecoder decoderFunc\n}\n\n// Default field mappings common for Netflow version 9 and IPFIX\n// From documentations at\n// - https://www.cisco.com/en/US/technologies/tk648/tk362/technologies_white_paper09186a00800a3db9.html\n// - https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-information-elements\nvar fieldMappingsNetflowCommon = map[uint16][]fieldMapping{\n\t// 0: reserved\n\t1:  {{\"in_bytes\", decodeUint}},          // IN_BYTES / octetDeltaCount\n\t2:  {{\"in_packets\", decodeUint}},        // IN_PKTS / packetDeltaCount\n\t3:  {{\"flows\", decodeUint}},             // FLOWS / deltaFlowCount\n\t4:  {{\"protocol\", decodeL4Proto}},       // PROTOCOL / protocolIdentifier\n\t5:  {{\"src_tos\", decodeHex}},            // SRC_TOS / ipClassOfService\n\t6:  {{\"tcp_flags\", decodeTCPFlags}},     // TCP_FLAGS / tcpControlBits\n\t7:  {{\"src_port\", decodeUint}},          // L4_SRC_PORT / sourceTransportPort\n\t8:  {{\"src\", decodeIP}},                 // IPV4_SRC_ADDR / sourceIPv4Address\n\t9:  {{\"src_mask\", decodeUint}},          // SRC_MASK / sourceIPv4PrefixLength\n\t10: {{\"in_snmp\", decodeUint}},           // INPUT_SNMP / ingressInterface\n\t11: {{\"dst_port\", decodeUint}},          // L4_DST_PORT / destinationTransportPort\n\t12: {{\"dst\", decodeIP}},                 // IPV4_DST_ADDR / destinationIPv4Address\n\t13: {{\"dst_mask\", decodeUint}},          // DST_MASK / destinationIPv4PrefixLength\n\t14: {{\"out_snmp\", decodeUint}},          // OUTPUT_SNMP / egressInterface\n\t15: {{\"next_hop\", decodeIP}},            // IPV4_NEXT_HOP / ipNextHopIPv4Address\n\t16: {{\"bgp_src_as\", decodeUint}},        // SRC_AS / bgpSourceAsNumber\n\t17: {{\"bgp_dst_as\", decodeUint}},        // DST_AS / bgpDestinationAsNumber\n\t18: {{\"bgp_next_hop\", decodeIP}},        // BGP_IPV4_NEXT_HOP / bgpNextHopIPv4Address\n\t19: {{\"out_mcast_packets\", decodeUint}}, // MUL_DST_PKTS / postMCastPacketDeltaCount\n\t20: {{\"out_mcast_bytes\", decodeUint}},   // MUL_DST_BYTES / postMCastOctetDeltaCount\n\t21: {{\"last_switched\", decodeUint}},     // LAST_SWITCHED / flowEndSysUpTime\n\t22: {{\"first_switched\", decodeUint}},    // FIRST_SWITCHED / flowStartSysUpTime\n\t23: {{\"out_bytes\", decodeUint}},         // OUT_BYTES / postOctetDeltaCount\n\t24: {{\"out_packets\", decodeUint}},       // OUT_PKTS / postPacketDeltaCount\n\t25: {{\"min_packet_len\", decodeUint}},    // MIN_PKT_LNGTH / minimumIpTotalLength\n\t26: {{\"max_packet_len\", decodeUint}},    // MAX_PKT_LNGTH / maximumIpTotalLength\n\t27: {{\"src\", decodeIP}},                 // IPV6_SRC_ADDR / sourceIPv6Address\n\t28: {{\"dst\", decodeIP}},                 // IPV6_DST_ADDR / destinationIPv6Address\n\t29: {{\"src_mask\", decodeUint}},          // IPV6_SRC_MASK / sourceIPv6PrefixLength\n\t30: {{\"dst_mask\", decodeUint}},          // IPV6_DST_MASK / destinationIPv6PrefixLength\n\t31: {{\"flow_label\", decodeHex}},         // IPV6_FLOW_LABEL / flowLabelIPv6\n\t32: {\n\t\t{\"icmp_type\", decodeByteFunc(0)}, // ICMP_TYPE / icmpTypeCodeIPv4\n\t\t{\"icmp_code\", decodeByteFunc(1)},\n\t},\n\t33: {{\"igmp_type\", decodeUint}},               // MUL_IGMP_TYPE / igmpType\n\t34: {{\"sampling_interval\", decodeUint}},       // SAMPLING_INTERVAL / samplingInterval (deprecated)\n\t35: {{\"sampling_algo\", decodeSampleAlgo}},     // SAMPLING_ALGORITHM / samplingAlgorithm (deprecated)\n\t36: {{\"flow_active_timeout\", decodeUint}},     // FLOW_ACTIVE_TIMEOUT / flowActiveTimeout\n\t37: {{\"flow_inactive_timeout\", decodeUint}},   // FLOW_INACTIVE_TIMEOUT / flowIdleTimeout\n\t38: {{\"engine_type\", decodeEngineType}},       // ENGINE_TYPE / engineType (deprecated)\n\t39: {{\"engine_id\", decodeHex}},                // ENGINE_ID / engineId (deprecated)\n\t40: {{\"total_bytes_exported\", decodeUint}},    // TOTAL_BYTES_EXP / exportedOctetTotalCount\n\t41: {{\"total_messages_exported\", decodeUint}}, // TOTAL_PKTS_EXP / exportedMessageTotalCount\n\t42: {{\"total_flows_exported\", decodeUint}},    // TOTAL_FLOWS_EXP / exportedFlowRecordTotalCount\n\t// 43: vendor proprietary / deprecated\n\t44: {{\"ipv4_src_prefix\", decodeIP}},           // IPV4_SRC_PREFIX / sourceIPv4Prefix\n\t45: {{\"ipv4_dst_prefix\", decodeIP}},           // IPV4_DST_PREFIX / destinationIPv4Prefix\n\t46: {{\"mpls_top_label_type\", decodeMPLSType}}, // MPLS_TOP_LABEL_TYPE / mplsTopLabelType\n\t47: {{\"mpls_top_label_ip\", decodeIP}},         // MPLS_TOP_LABEL_IP_ADDR / mplsTopLabelIPv4Address\n\t48: {{\"flow_sampler_id\", decodeUint}},         // FLOW_SAMPLER_ID / samplerId (deprecated)\n\t49: {{\"flow_sampler_mode\", decodeSampleAlgo}}, // FLOW_SAMPLER_MODE / samplerMode (deprecated)\n\t50: {{\"flow_sampler_interval\", decodeUint}},   // FLOW_SAMPLER_RANDOM_INTERVAL / samplerRandomInterval (deprecated)\n\t// 51: vendor proprietary / deprecated\n\t52: {{\"min_ttl\", decodeUint}},         // MIN_TTL / minimumTTL\n\t53: {{\"max_ttl\", decodeUint}},         // MAX_TTL / maximumTTL\n\t54: {{\"fragment_id\", decodeHex}},      // IPV4_IDENT / fragmentIdentification\n\t55: {{\"dst_tos\", decodeHex}},          // DST_TOS / postIpClassOfService\n\t56: {{\"in_src_mac\", decodeMAC}},       // IN_SRC_MAC / sourceMacAddress\n\t57: {{\"out_dst_mac\", decodeMAC}},      // OUT_DST_MAC / postDestinationMacAddress\n\t58: {{\"vlan_src\", decodeUint}},        // SRC_VLAN / vlanId\n\t59: {{\"vlan_dst\", decodeUint}},        // DST_VLAN / postVlanId\n\t60: {{\"ip_version\", decodeIPVersion}}, // IP_PROTOCOL_VERSION / ipVersion\n\t61: {{\"direction\", decodeDirection}},  // DIRECTION / flowDirection\n\t62: {{\"next_hop\", decodeIP}},          // IPV6_NEXT_HOP / ipNextHopIPv6Address\n\t63: {{\"bgp_next_hop\", decodeIP}},      // BPG_IPV6_NEXT_HOP / bgpNextHopIPv6Address\n\t64: {{\"ipv6_extensions\", decodeHex}},  // IPV6_OPTION_HEADERS / ipv6ExtensionHeaders\n\t// 65 - 69: vendor proprietary\n\t70: {{\"mpls_label_1\", decodeHex}},      // MPLS_LABEL_1 / mplsTopLabelStackSection\n\t71: {{\"mpls_label_2\", decodeHex}},      // MPLS_LABEL_2 / mplsLabelStackSection2\n\t72: {{\"mpls_label_3\", decodeHex}},      // MPLS_LABEL_3 / mplsLabelStackSection3\n\t73: {{\"mpls_label_4\", decodeHex}},      // MPLS_LABEL_4 / mplsLabelStackSection4\n\t74: {{\"mpls_label_5\", decodeHex}},      // MPLS_LABEL_5 / mplsLabelStackSection5\n\t75: {{\"mpls_label_6\", decodeHex}},      // MPLS_LABEL_6 / mplsLabelStackSection6\n\t76: {{\"mpls_label_7\", decodeHex}},      // MPLS_LABEL_7 / mplsLabelStackSection7\n\t77: {{\"mpls_label_8\", decodeHex}},      // MPLS_LABEL_8 / mplsLabelStackSection8\n\t78: {{\"mpls_label_9\", decodeHex}},      // MPLS_LABEL_9 / mplsLabelStackSection9\n\t79: {{\"mpls_label_10\", decodeHex}},     // MPLS_LABEL_10 / mplsLabelStackSection10\n\t80: {{\"in_dst_mac\", decodeMAC}},        // IN_DST_MAC / destinationMacAddress\n\t81: {{\"out_src_mac\", decodeMAC}},       // OUT_SRC_MAC / postSourceMacAddress\n\t82: {{\"interface\", decodeString}},      // IF_NAME / interfaceName\n\t83: {{\"interface_desc\", decodeString}}, // IF_DESC / interfaceDescription\n\t84: {{\"sampler_name\", decodeString}},   // SAMPLER_NAME / samplerName\n\t85: {{\"in_total_bytes\", decodeUint}},   // IN_PERMANENT_BYTES / octetTotalCount\n\t86: {{\"in_total_packets\", decodeUint}}, // IN_PERMANENT_PKTS / packetTotalCount\n\t// 87: vendor proprietary\n\t88: {{\"fragment_offset\", decodeUint}}, // FRAGMENT_OFFSET / fragmentOffset\n\t89: {\n\t\t{\"fwd_status\", decodeFwdStatus}, // FORWARDING STATUS / forwardingStatus\n\t\t{\"fwd_reason\", decodeFwdReason},\n\t},\n\t90: {{\"mpls_vpn_rd\", decodeHex}},        // MPLS PAL RD / mplsVpnRouteDistinguisher\n\t91: {{\"mpls_prefix_len\", decodeUint}},   // MPLS PREFIX LEN / mplsTopLabelPrefixLength\n\t92: {{\"src_traffic_index\", decodeUint}}, // SRC TRAFFIC INDEX / srcTrafficIndex\n\t93: {{\"dst_traffic_index\", decodeUint}}, // DST TRAFFIC INDEX / dstTrafficIndex\n\t94: {{\"app_desc\", decodeString}},        // APPLICATION DESCRIPTION / applicationDescription\n\t95: {{\"app_id\", decodeHex}},             // APPLICATION TAG / applicationId\n\t96: {{\"app_name\", decodeString}},        // APPLICATION NAME / applicationName\n\t// 97: undefined\n\t98: {{\"out_dscp\", decodeUint}},           // postipDiffServCodePoint / postIpDiffServCodePoint\n\t99: {{\"replication_factor\", decodeUint}}, // replication factor / multicastReplicationFactor\n\t// 100: deprecated / className\n\t101: {{\"classification_engine_id\", decodeUint}}, // undefined / classificationEngineId\n\t102: {{\"l2_packet_section_offset\", decodeUint}}, // layer2packetSectionOffset\n\t103: {{\"l2_packet_section_size\", decodeUint}},   // layer2packetSectionSize\n\t104: {{\"l2_packet_section_data\", decodeHex}},    // layer2packetSectionData\n\t// 105 - 127:  reserved\n\n\t// Common between Netflow v9 ASA extension\n\t// https://www.cisco.com/c/en/us/td/docs/security/asa/special/netflow/asa_netflow.html\n\t// and IPFIX.\n\t148: {{\"flow_id\", decodeUint}},         // flowId\n\t152: {{\"flow_start_ms\", decodeUint}},   // NF_F_FLOW_CREATE_TIME_MSEC / flowStartMilliseconds\n\t153: {{\"flow_end_ms\", decodeUint}},     // NF_F_FLOW_END_TIME_MSEC / flowEndMilliseconds\n\t176: {{\"icmp_type\", decodeUint}},       // NF_F_ICMP_TYPE / icmpTypeIPv4\n\t177: {{\"icmp_code\", decodeUint}},       // NF_F_ICMP_CODE / icmpCodeIPv4\n\t178: {{\"icmp_type\", decodeUint}},       // NF_F_ICMP_TYPE_IPV6 / icmpTypeIPv6\n\t179: {{\"icmp_code\", decodeUint}},       // NF_F_ICMP_CODE_IPV6 / icmpCodeIPv6\n\t225: {{\"xlat_src\", decodeIP}},          // NF_F_XLATE_SRC_ADDR_IPV4 / postNATSourceIPv4Address\n\t226: {{\"xlat_dst\", decodeIP}},          // NF_F_XLATE_DST_ADDR_IPV4 / postNATDestinationIPv4Address\n\t227: {{\"xlat_src_port\", decodeUint}},   // NF_F_XLATE_SRC_PORT / postNAPTSourceTransportPort\n\t228: {{\"xlat_dst_port\", decodeUint}},   // NF_F_XLATE_DST_PORT / postNAPTDestinationTransportPort\n\t231: {{\"initiator_bytes\", decodeUint}}, // NF_F_FWD_FLOW_DELTA_BYTES / initiatorOctets\n\t232: {{\"responder_bytes\", decodeUint}}, // NF_F_REV_FLOW_DELTA_BYTES / responderOctets\n\t233: {{\"fw_event\", decodeFWEvent}},     // NF_F_FW_EVENT / firewallEvent\n\t281: {{\"xlat_src\", decodeIP}},          // NF_F_XLATE_SRC_ADDR_IPV6 / postNATSourceIPv6Address\n\t282: {{\"xlat_dst\", decodeIP}},          // NF_F_XLATE_DST_ADDR_IPV6 / postNATDestinationIPv6Address\n\t323: {{\"event_time_ms\", decodeUint}},   // NF_F_EVENT_TIME_MSEC / observationTimeMilliseconds\n\t324: {{\"event_time_us\", decodeUint}},   // NF_F_EVENT_TIME_USEC / observationTimeMicroseconds\n\t325: {{\"event_time_ns\", decodeUint}},   // NF_F_EVENT_TIME_NSEC / observationTimeNanoseconds\n}\n\n// Default field mappings specific to Netflow version 9\n// From documentation at https://www.cisco.com/c/en/us/td/docs/security/asa/special/netflow/asa_netflow.html\nvar fieldMappingsNetflowV9 = map[uint16][]fieldMapping{\n\t33000: {{\"in_acl_id\", decodeHex}},    // NF_F_INGRESS_ACL_ID\n\t33001: {{\"out_acl_id\", decodeHex}},   // NF_F_EGRESS_ACL_ID\n\t33002: {{\"fw_event_ext\", decodeHex}}, // NF_F_FW_EXT_EVENT\n\t40000: {{\"username\", decodeString}},  // NF_F_USERNAME\n}\n\n// Default field mappings specific to Netflow version 9\n// From documentation at\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-information-elements\nvar fieldMappingsIPFIX = map[uint16][]fieldMapping{\n\t128: {{\"bgp_next_as\", decodeUint}},              // bgpNextAdjacentAsNumber\n\t129: {{\"bgp_prev_as\", decodeUint}},              // bgpPrevAdjacentAsNumber\n\t130: {{\"exporter\", decodeIP}},                   // exporterIPv4Address\n\t131: {{\"exporter\", decodeIP}},                   // exporterIPv6Address\n\t132: {{\"dropped_bytes\", decodeUint}},            // droppedOctetDeltaCount\n\t133: {{\"dropped_packets\", decodeUint}},          // droppedPacketDeltaCount\n\t134: {{\"dropped_bytes_total\", decodeUint}},      // droppedOctetTotalCount\n\t135: {{\"dropped_packets_total\", decodeUint}},    // droppedPacketTotalCount\n\t136: {{\"flow_end_reason\", decodeFlowEndReason}}, // flowEndReason\n\t137: {{\"common_properties_id\", decodeUint}},     // commonPropertiesId\n\t138: {{\"observation_point_id\", decodeUint}},     // observationPointId\n\t139: {\n\t\t{\"icmp_type\", decodeByteFunc(0)}, // icmpTypeCodeIPv6\n\t\t{\"icmp_code\", decodeByteFunc(1)},\n\t},\n\t140: {{\"mpls_top_label_ip\", decodeIP}}, // mplsTopLabelIPv6Address\n\t141: {{\"linecard_id\", decodeUint}},     // lineCardId\n\t142: {{\"port_id\", decodeUint}},         // portId\n\t143: {{\"metering_pid\", decodeUint}},    // meteringProcessId\n\t144: {{\"exporting_pid\", decodeUint}},   // exportingProcessId\n\t145: {{\"template_id\", decodeUint}},     // templateId\n\t146: {{\"wlan_channel\", decodeUint}},    // wlanChannelId\n\t147: {{\"wlan_ssid\", decodeString}},     // wlanSSID\n\t// 148: common\n\t149: {{\"observation_domain_id\", decodeUint}}, // observationDomainId\n\t150: {{\"flow_start\", decodeUint}},            // flowStartSeconds\n\t151: {{\"flow_end\", decodeUint}},              // flowEndSeconds\n\t// 152 - 153: common\n\t154: {{\"flow_start_us\", decodeUint}},            // flowStartMicroseconds\n\t155: {{\"flow_end_us\", decodeUint}},              // flowEndMicroseconds\n\t156: {{\"flow_start_ns\", decodeUint}},            // flowStartNanoseconds\n\t157: {{\"flow_end_ns\", decodeUint}},              // flowEndNanoseconds\n\t158: {{\"flow_start_delta_us\", decodeUint}},      // flowStartDeltaMicroseconds\n\t159: {{\"flow_end_delta_us\", decodeUint}},        // flowEndDeltaMicroseconds\n\t160: {{\"system_init_ms\", decodeUint}},           // systemInitTimeMilliseconds\n\t161: {{\"flow_duration_ms\", decodeUint}},         // flowDurationMilliseconds\n\t162: {{\"flow_duration_us\", decodeUint}},         // flowDurationMicroseconds\n\t163: {{\"flow_count_total\", decodeUint}},         // observedFlowTotalCount\n\t164: {{\"ignored_packet_total\", decodeUint}},     // ignoredPacketTotalCount\n\t165: {{\"ignored_bytes_total\", decodeUint}},      // ignoredOctetTotalCount\n\t166: {{\"notsent_flow_count_total\", decodeUint}}, // notSentFlowTotalCount\n\t167: {{\"notsent_packet_total\", decodeUint}},     // notSentPacketTotalCount\n\t168: {{\"notsent_bytes_total\", decodeUint}},      // notSentOctetTotalCount\n\t169: {{\"ipv6_dst_prefix\", decodeIP}},            // destinationIPv6Prefix\n\t170: {{\"ipv6_src_prefix\", decodeIP}},            // sourceIPv6Prefix\n\t171: {{\"out_bytes_total\", decodeUint}},          // postOctetTotalCount\n\t172: {{\"out_packets_total\", decodeUint}},        // postPacketTotalCount\n\t173: {{\"flow_key_indicator\", decodeHex}},        // flowKeyIndicator\n\t174: {{\"out_mcast_packets_total\", decodeUint}},  // postMCastPacketTotalCount\n\t175: {{\"out_mcast_bytes_total\", decodeUint}},    // postMCastOctetTotalCount\n\t// 176 - 179: common\n\t180: {{\"udp_src_port\", decodeUint}},             // udpSourcePort\n\t181: {{\"udp_dst_port\", decodeUint}},             // udpDestinationPort\n\t182: {{\"tcp_src_port\", decodeUint}},             // tcpSourcePort\n\t183: {{\"tcp_dst_port\", decodeUint}},             // tcpDestinationPort\n\t184: {{\"tcp_seq_number\", decodeUint}},           // tcpSequenceNumber\n\t185: {{\"tcp_ack_number\", decodeUint}},           // tcpAcknowledgementNumber\n\t186: {{\"tcp_window_size\", decodeUint}},          // tcpWindowSize\n\t187: {{\"tcp_urgent_ptr\", decodeUint}},           // tcpUrgentPointer\n\t188: {{\"tcp_header_len\", decodeUint}},           // tcpHeaderLength\n\t189: {{\"ip_header_len\", decodeUint}},            // ipHeaderLength\n\t190: {{\"ipv4_total_len\", decodeUint}},           // totalLengthIPv4\n\t191: {{\"ipv6_payload_len\", decodeUint}},         // payloadLengthIPv6\n\t192: {{\"ttl\", decodeUint}},                      // ipTTL\n\t193: {{\"ipv6_next_header\", decodeUint}},         // nextHeaderIPv6\n\t194: {{\"mpls_payload_len\", decodeUint}},         // mplsPayloadLength\n\t195: {{\"dscp\", decodeUint}},                     // ipDiffServCodePoint\n\t196: {{\"precedence\", decodeUint}},               // ipPrecedence\n\t197: {{\"fragment_flags\", decodeFragmentFlags}},  // fragmentFlags\n\t198: {{\"bytes_sqr_sum\", decodeUint}},            // octetDeltaSumOfSquares\n\t199: {{\"bytes_sqr_sum_total\", decodeUint}},      // octetTotalSumOfSquares\n\t200: {{\"mpls_top_label_ttl\", decodeUint}},       // mplsTopLabelTTL\n\t201: {{\"mpls_stack_len\", decodeUint}},           // mplsLabelStackLength\n\t202: {{\"mpls_stack_depth\", decodeUint}},         // mplsLabelStackDepth\n\t203: {{\"mpls_top_label_exp\", decodeUint}},       // mplsTopLabelExp\n\t204: {{\"ip_payload_len\", decodeUint}},           // ipPayloadLength\n\t205: {{\"udp_msg_len\", decodeUint}},              // udpMessageLength\n\t206: {{\"mcast\", decodeUint}},                    // isMulticast\n\t207: {{\"ipv4_inet_header_len\", decodeUint}},     // ipv4IHL\n\t208: {{\"ipv4_options\", decodeIPv4Options}},      // ipv4Options\n\t209: {{\"tcp_options\", decodeHex}},               // tcpOptions\n\t210: {{\"padding\", decodeHex}},                   // paddingOctets\n\t211: {{\"collector\", decodeIP}},                  // collectorIPv4Address\n\t212: {{\"collector\", decodeIP}},                  // collectorIPv6Address\n\t213: {{\"export_interface\", decodeUint}},         // exportInterface\n\t214: {{\"export_proto_version\", decodeUint}},     // exportProtocolVersion\n\t215: {{\"export_transport_proto\", decodeUint}},   // exportTransportProtocol\n\t216: {{\"collector_transport_port\", decodeUint}}, // collectorTransportPort\n\t217: {{\"exporter_transport_port\", decodeUint}},  // exporterTransportPort\n\t218: {{\"tcp_syn_total\", decodeUint}},            // tcpSynTotalCount\n\t219: {{\"tcp_fin_total\", decodeUint}},            // tcpFinTotalCount\n\t220: {{\"tcp_rst_total\", decodeUint}},            // tcpRstTotalCount\n\t221: {{\"tcp_psh_total\", decodeUint}},            // tcpPshTotalCount\n\t222: {{\"tcp_ack_total\", decodeUint}},            // tcpAckTotalCount\n\t223: {{\"tcp_urg_total\", decodeUint}},            // tcpUrgTotalCount\n\t224: {{\"ip_total_len\", decodeUint}},             // ipTotalLength\n\t// 225 - 228: common\n\t229: {{\"nat_origin_addr_realm\", decodeUint}}, // natOriginatingAddressRealm\n\t230: {{\"nat_event\", decodeUint}},             // natEvent\n\t// 231 - 233: common\n\t234: {{\"in_vrf_id\", decodeUint}},                      // ingressVRFID\n\t235: {{\"out_vrf_id\", decodeUint}},                     // egressVRFID\n\t236: {{\"vrf_name\", decodeString}},                     // VRFname\n\t237: {{\"out_mpls_top_label_exp\", decodeUint}},         // postMplsTopLabelExp\n\t238: {{\"tcp_window_scale\", decodeUint}},               // tcpWindowScale\n\t239: {{\"biflow_direction\", decodeBiflowDirection}},    // biflowDirection\n\t240: {{\"eth_header_len\", decodeUint}},                 // ethernetHeaderLength\n\t241: {{\"eth_payload_len\", decodeUint}},                // ethernetPayloadLength\n\t242: {{\"eth_total_len\", decodeUint}},                  // ethernetTotalLength\n\t243: {{\"vlan_id\", decodeUint}},                        // dot1qVlanId\n\t244: {{\"vlan_priority\", decodeUint}},                  // dot1qPriority\n\t245: {{\"vlan_customer_id\", decodeUint}},               // dot1qCustomerVlanId\n\t246: {{\"vlan_customer_priority\", decodeUint}},         // dot1qCustomerPriority\n\t247: {{\"metro_evc_id\", decodeString}},                 // metroEvcId\n\t248: {{\"metro_evc_type\", decodeUint}},                 // metroEvcType\n\t249: {{\"pseudo_wire_id\", decodeUint}},                 // pseudoWireId\n\t250: {{\"pseudo_wire_type\", decodeHex}},                // pseudoWireType\n\t251: {{\"pseudo_wire_ctrl_word\", decodeHex}},           // pseudoWireControlWord\n\t252: {{\"in_phy_interface\", decodeUint}},               // ingressPhysicalInterface\n\t253: {{\"out_phy_interface\", decodeUint}},              // egressPhysicalInterface\n\t254: {{\"out_vlan_id\", decodeUint}},                    // postDot1qVlanId\n\t255: {{\"out_vlan_customer_id\", decodeUint}},           // postDot1qCustomerVlanId\n\t256: {{\"eth_type\", decodeHex}},                        // ethernetType\n\t257: {{\"out_precedence\", decodeUint}},                 // postIpPrecedence\n\t258: {{\"collection_time_ms\", decodeUint}},             // collectionTimeMilliseconds\n\t259: {{\"export_sctp_stream_id\", decodeUint}},          // exportSctpStreamId\n\t260: {{\"max_export_time\", decodeUint}},                // maxExportSeconds\n\t261: {{\"max_flow_end_time\", decodeUint}},              // maxFlowEndSeconds\n\t262: {{\"msg_md5\", decodeHex}},                         // messageMD5Checksum\n\t263: {{\"msg_scope\", decodeUint}},                      // messageScope\n\t264: {{\"min_export_time\", decodeUint}},                // minExportSeconds\n\t265: {{\"min_flow_start_time\", decodeUint}},            // minFlowStartSeconds\n\t266: {{\"opaque_bytes\", decodeUint}},                   // opaqueOctets\n\t267: { /* MUST BE IGNORED according to standard */ },  // sessionScope\n\t268: {{\"max_flow_end_time_us\", decodeUint}},           // maxFlowEndMicroseconds\n\t269: {{\"max_flow_end_time_ms\", decodeUint}},           // maxFlowEndMilliseconds\n\t270: {{\"max_flow_end_time_ns\", decodeUint}},           // maxFlowEndNanoseconds\n\t271: {{\"min_flow_start_time_us\", decodeUint}},         // minFlowStartMicroseconds\n\t272: {{\"min_flow_start_time_ms\", decodeUint}},         // minFlowStartMilliseconds\n\t273: {{\"min_flow_start_time_ns\", decodeUint}},         // minFlowStartNanoseconds\n\t274: {{\"collector_cert\", decodeString}},               // collectorCertificate\n\t275: {{\"exporter_cert\", decodeString}},                // exporterCertificate\n\t276: {{\"data_records_reliability\", decodeBool}},       // dataRecordsReliability\n\t277: {{\"observation_point_type\", decodeOpsPointType}}, // observationPointType\n\t278: {{\"connection_new_count\", decodeUint}},           // newConnectionDeltaCount\n\t279: {{\"connection_duration_sum\", decodeUint}},        // connectionSumDurationSeconds\n\t280: {{\"connection_transaction_id\", decodeUint}},      // connectionTransactionId\n\t// 281 - 282: common\n\t283: {{\"nat_pool_id\", decodeUint}},     // natPoolId\n\t284: {{\"nat_pool_name\", decodeString}}, // natPoolName\n\t285: {\n\t\t{\"anon_stability_class\", decodeAnonStabilityClass}, // anonymizationFlags\n\t\t{\"anon_flags\", decodeAnonFlags},\n\t},\n\t286: {{\"anon_technique\", decodeAnonTechnique}},         // anonymizationTechnique\n\t287: {{\"information_element\", decodeUint}},             // informationElementIndex\n\t288: {{\"p2p\", decodeTechnology}},                       // p2pTechnology\n\t289: {{\"tunnel\", decodeTechnology}},                    // tunnelTechnology\n\t290: {{\"encryption\", decodeTechnology}},                // encryptedTechnology\n\t291: { /* IGNORED for parse-ability */ },               // basicList\n\t292: { /* IGNORED for parse-ability */ },               // subTemplateList\n\t293: { /* IGNORED for parse-ability */ },               // subTemplateMultiList\n\t294: {{\"bgp_validity_state\", decodeUint}},              // bgpValidityState\n\t295: {{\"ipsec_spi\", decodeUint}},                       // IPSecSPI\n\t296: {{\"gre_key\", decodeUint}},                         // greKey\n\t297: {{\"nat_type\", decodeIPNatType}},                   // natType\n\t298: {{\"initiator_packets\", decodeUint}},               // initiatorPackets\n\t299: {{\"responder_packets\", decodeUint}},               // responderPackets\n\t300: {{\"observation_domain_name\", decodeString}},       // observationDomainName\n\t301: {{\"observation_seq_id\", decodeUint}},              // selectionSequenceId\n\t302: {{\"selector_id\", decodeUint}},                     // selectorId\n\t303: {{\"information_elem_id\", decodeUint}},             // informationElementId\n\t304: {{\"selector_algo\", decodeSelectorAlgorithm}},      // selectorAlgorithm\n\t305: {{\"sampling_packet_interval\", decodeUint}},        // samplingPacketInterval\n\t306: {{\"sampling_packet_space\", decodeUint}},           // samplingPacketSpace\n\t307: {{\"sampling_time_interval_us\", decodeUint}},       // samplingTimeInterval\n\t308: {{\"sampling_time_space_us\", decodeUint}},          // samplingTimeSpace\n\t309: {{\"sampling_size\", decodeUint}},                   // samplingSize\n\t310: {{\"sampling_population\", decodeUint}},             // samplingPopulation\n\t311: {{\"sampling_probability\", decodeFloat64}},         // samplingProbability\n\t312: {{\"datalink_frame_size\", decodeUint}},             // dataLinkFrameSize\n\t313: {{\"ip_header_packet_section\", decodeHex}},         // ipHeaderPacketSection\n\t314: {{\"ip_payload_packet_section\", decodeHex}},        // ipPayloadPacketSection\n\t315: {{\"datalink_frame_section\", decodeHex}},           // dataLinkFrameSection\n\t316: {{\"mpls_label_stack_section\", decodeHex}},         // mplsLabelStackSection\n\t317: {{\"mpls_payload_packet_section\", decodeHex}},      // mplsPayloadPacketSection\n\t318: {{\"selector_total_packets_observed\", decodeUint}}, // selectorIdTotalPktsObserved\n\t319: {{\"selector_total_packets_selected\", decodeUint}}, // selectorIdTotalPktsSelected\n\t320: {{\"absolute_error\", decodeFloat64}},               // absoluteError\n\t321: {{\"relative_error\", decodeFloat64}},               // relativeError\n\t322: {{\"event_time\", decodeUint}},                      // observationTimeSeconds\n\t// 323 - 325: common\n\t326: {{\"hash_digest\", decodeHex}},                         // digestHashValue\n\t327: {{\"hash_ip_payload_offset\", decodeUint}},             // hashIPPayloadOffset\n\t328: {{\"hash_ip_payload_size\", decodeUint}},               // hashIPPayloadSize\n\t329: {{\"hash_out_range_min\", decodeUint}},                 // hashOutputRangeMin\n\t330: {{\"hash_out_range_max\", decodeUint}},                 // hashOutputRangeMax\n\t331: {{\"hash_selected_range_min\", decodeUint}},            // hashSelectedRangeMin\n\t332: {{\"hash_selected_range_max\", decodeUint}},            // hashSelectedRangeMax\n\t333: {{\"hash_digest_out\", decodeBool}},                    // hashDigestOutput\n\t334: {{\"hash_init_val\", decodeUint}},                      // hashInitialiserValue\n\t335: {{\"selector_name\", decodeString}},                    // selectorName\n\t336: {{\"upper_confidence_interval_limit\", decodeFloat64}}, // upperCILimit\n\t337: {{\"lower_confidence_interval_limit\", decodeFloat64}}, // upperCILimit\n\t338: {{\"confidence_level\", decodeFloat64}},                // confidenceLevel\n\t// 339 - 346: information element fields, do not map for now\n\t347: {{\"virtual_station_interface_id\", decodeHex}},      // virtualStationInterfaceId\n\t348: {{\"virtual_station_interface_name\", decodeString}}, // virtualStationInterfaceName\n\t349: {{\"virtual_station_uuid\", decodeHex}},              // virtualStationUUID\n\t350: {{\"virtual_station_name\", decodeString}},           // virtualStationName\n\t351: {{\"l2_segment_id\", decodeUint}},                    // layer2SegmentId\n\t352: {{\"l2_bytes\", decodeUint}},                         // layer2OctetDeltaCount\n\t353: {{\"l2_bytes_total\", decodeUint}},                   // layer2OctetTotalCount\n\t354: {{\"in_unicast_packets_total\", decodeUint}},         // ingressUnicastPacketTotalCount\n\t355: {{\"in_mcast_packets_total\", decodeUint}},           // ingressMulticastPacketTotalCount\n\t356: {{\"in_broadcast_packets_total\", decodeUint}},       // ingressBroadcastPacketTotalCount\n\t357: {{\"out_unicast_packets_total\", decodeUint}},        // egressUnicastPacketTotalCount\n\t358: {{\"out_broadcast_packets_total\", decodeUint}},      // egressBroadcastPacketTotalCount\n\t359: {{\"monitoring_interval_start_ms\", decodeUint}},     // monitoringIntervalStartMilliSeconds\n\t360: {{\"monitoring_interval_end_ms\", decodeUint}},       // monitoringIntervalEndMilliSeconds\n\t361: {{\"port_range_start\", decodeUint}},                 // portRangeStart\n\t362: {{\"port_range_end\", decodeUint}},                   // portRangeEnd\n\t363: {{\"port_range_step_size\", decodeUint}},             // portRangeStepSize\n\t364: {{\"port_range_ports\", decodeUint}},                 // portRangeNumPorts\n\t365: {{\"station_mac\", decodeMAC}},                       // staMacAddress\n\t366: {{\"station\", decodeIP}},                            // staIPv4Address\n\t367: {{\"wtp_mac\", decodeMAC}},                           // wtpMacAddress\n\t368: {{\"in_interface_type\", decodeUint}},                // ingressInterfaceType\n\t369: {{\"out_interface_type\", decodeUint}},               // egressInterfaceType\n\t370: {{\"rtp_seq_number\", decodeUint}},                   // rtpSequenceNumber\n\t371: {{\"username\", decodeString}},                       // userName\n\t372: {{\"app_category\", decodeString}},                   // applicationCategoryName\n\t373: {{\"app_subcategory\", decodeHex}},                   // applicationSubCategoryName\n\t374: {{\"app_group\", decodeString}},                      // applicationGroupName\n\t375: {{\"flows_original_present\", decodeUint}},           // originalFlowsPresent\n\t376: {{\"flows_original_initiated\", decodeUint}},         // originalFlowsInitiated\n\t377: {{\"flows_original_completed\", decodeUint}},         // originalFlowsCompleted\n\t378: {{\"flow_src_ip_count\", decodeUint}},                // distinctCountOfSourceIPAddress\n\t379: {{\"flow_dst_ip_count\", decodeUint}},                // distinctCountOfDestinationIPAddress\n\t380: {{\"flow_src_ipv4_count\", decodeUint}},              // distinctCountOfSourceIPv4Address\n\t381: {{\"flow_dst_ipv4_count\", decodeUint}},              // distinctCountOfDestinationIPv4Address\n\t382: {{\"flow_src_ipv6_count\", decodeUint}},              // distinctCountOfSourceIPv6Address\n\t383: {{\"flow_dst_ipv6_count\", decodeUint}},              // distinctCountOfDestinationIPv6Address\n\t384: {{\"value_dist_method\", decodeValueDistMethod}},     // valueDistributionMethod\n\t385: {{\"rfc3550_jitter_ms\", decodeUint}},                // rfc3550JitterMilliseconds\n\t386: {{\"rfc3550_jitter_us\", decodeUint}},                // rfc3550JitterMicroseconds\n\t387: {{\"rfc3550_jitter_ns\", decodeUint}},                // rfc3550JitterNanoseconds\n\t388: {{\"vlan_dei\", decodeBool}},                         // dot1qDEI\n\t389: {{\"vlan_customer_dei\", decodeUint}},                // dot1qCustomerDEI\n\t390: {{\"flow_selector_algo\", decodeSelectorAlgorithm}},  // flowSelectorAlgorithm\n\t391: {{\"flow_selected_byte_count\", decodeUint}},         // flowSelectedOctetDeltaCount\n\t392: {{\"flow_selected_packet_count\", decodeUint}},       // flowSelectedOctetDeltaCount\n\t393: {{\"flow_selected_count\", decodeUint}},              // flowSelectedFlowDeltaCount\n\t394: {{\"selector_id_flows_observed_total\", decodeUint}}, // selectorIDTotalFlowsObserved\n\t395: {{\"selector_id_flows_selected_total\", decodeUint}}, // selectorIDTotalFlowsSelected\n\t396: {{\"sampling_flow_interval_count\", decodeUint}},     // samplingFlowInterval\n\t397: {{\"sampling_flow_spacing_count\", decodeUint}},      // samplingFlowSpacing\n\t398: {{\"sampling_flow_interval_ms\", decodeUint}},        // flowSamplingTimeInterval\n\t399: {{\"sampling_flow_spacing_ms\", decodeUint}},         // flowSamplingTimeSpacing\n\t400: {{\"flow_domain_hash_element_id\", decodeUint}},      // hashFlowDomain\n\t401: {{\"transport_byte_count\", decodeUint}},             // transportOctetDeltaCount\n\t402: {{\"transport_packet_count\", decodeUint}},           // transportPacketDeltaCount\n\t403: {{\"exporter_original_ip\", decodeUint}},             // originalExporterIPv4Address\n\t404: {{\"exporter_original_ip\", decodeUint}},             // originalExporterIPv6Address\n\t405: {{\"exporter_original_domain\", decodeHex}},          // originalObservationDomainId\n\t406: {{\"intermediate_process_id\", decodeHex}},           // intermediateProcessId\n\t407: {{\"ignored_data_records_total\", decodeUint}},       // ignoredDataRecordTotalCount\n\t408: {{\"datalink_frame_type\", decodeDataLinkFrameType}}, // dataLinkFrameType\n\t409: {{\"section_offset\", decodeUint}},                   // sectionOffset\n\t410: {{\"section_exported_bytes\", decodeUint}},           // sectionExportedOctets\n\t411: {{\"vlan_service_instance_tag\", decodeHex}},         // dot1qServiceInstanceTag\n\t412: {{\"vlan_service_instance_id\", decodeUint}},         // dot1qServiceInstanceId\n\t413: {{\"vlan_service_instance_priority\", decodeUint}},   // dot1qServiceInstancePriority\n\t414: {{\"vlan_customer_src_mac\", decodeMAC}},             // dot1qCustomerSourceMacAddress\n\t415: {{\"vlan_customer_dst_mac\", decodeMAC}},             // dot1qCustomerDestinationMacAddress\n\t// 416: deprecated\n\t417: {{\"post_layer2_bytes\", decodeUint}},       // postLayer2OctetDeltaCount\n\t418: {{\"post_mcast_layer2_bytes\", decodeUint}}, // postMCastLayer2OctetDeltaCount\n\t// 419: deprecated\n\t420: {{\"post_layer2_bytes_total\", decodeUint}},                    // postLayer2OctetTotalCount\n\t421: {{\"post_mcast_layer2_bytes_total\", decodeUint}},              // postMCastLayer2OctetTotalCount\n\t422: {{\"min_layer2_total_length\", decodeUint}},                    // minimumLayer2TotalLength\n\t423: {{\"max_layer2_total_length\", decodeUint}},                    // maximumLayer2TotalLength\n\t424: {{\"dropped_layer2_bytes\", decodeUint}},                       // droppedLayer2OctetDeltaCount\n\t425: {{\"dropped_layer2_bytes_total\", decodeUint}},                 // droppedLayer2OctetTotalCount\n\t426: {{\"ignored_layer2_bytes_total\", decodeUint}},                 // ignoredLayer2OctetTotalCount\n\t427: {{\"not_sent_layer2_bytes_total\", decodeUint}},                // notSentLayer2OctetTotalCount\n\t428: {{\"layer2_bytes_sumsqr\", decodeUint}},                        // layer2OctetDeltaSumOfSquares\n\t429: {{\"layer2_bytes_total_sumsqr\", decodeUint}},                  // layer2OctetTotalSumOfSquares\n\t430: {{\"layer2_frames\", decodeUint}},                              // layer2FrameDeltaCount\n\t431: {{\"layer2_frames_total\", decodeUint}},                        // layer2FrameTotalCount\n\t432: {{\"pseudo_wire_dst\", decodeIP}},                              // pseudoWireDestinationIPv4Address\n\t433: {{\"ignored_layer2_frames_total\", decodeUint}},                // ignoredLayer2FrameTotalCount\n\t434: {{\"mib_obj_value_int\", decodeInt}},                           // mibObjectValueInteger\n\t435: {{\"mib_obj_value_str\", decodeString}},                        // mibObjectValueOctetString\n\t436: {{\"mib_obj_value_oid\", decodeHex}},                           // mibObjectValueOID\n\t437: {{\"mib_obj_value_bits\", decodeHex}},                          // mibObjectValueBits\n\t438: {{\"mib_obj_value_ip\", decodeIP}},                             // mibObjectValueIPAddress\n\t439: {{\"mib_obj_value_counter\", decodeUint}},                      // mibObjectValueCounter\n\t440: {{\"mib_obj_value_gauge\", decodeUint}},                        // mibObjectValueGauge\n\t441: {{\"mib_obj_value_time\", decodeUint}},                         // mibObjectValueTimeTicks\n\t442: {{\"mib_obj_value_uint\", decodeUint}},                         // mibObjectValueUnsigned\n\t443: {{\"mib_obj_value_table\", decodeHex}},                         // mibObjectValueTable\n\t444: {{\"mib_obj_value_row\", decodeHex}},                           // mibObjectValueRow\n\t445: {{\"mib_oid\", decodeHex}},                                     // mibObjectIdentifier\n\t446: {{\"mib_sub_id\", decodeUint}},                                 // mibSubIdentifier\n\t447: {{\"mib_index_indicator\", decodeHex}},                         // mibIndexIndicator\n\t448: {{\"mib_capture_time_semantics\", decodeCaptureTimeSemantics}}, // mibCaptureTimeSemantics\n\t449: {{\"mib_context_engine_id\", decodeHex}},                       // mibContextEngineID\n\t450: {{\"mib_context_name\", decodeString}},                         // mibContextName\n\t451: {{\"mib_obj_name\", decodeString}},                             // mibObjectName\n\t452: {{\"mib_obj_desc\", decodeString}},                             // mibObjectDescription\n\t453: {{\"mib_obj_syntax\", decodeString}},                           // mibObjectSyntax\n\t454: {{\"mib_module_name\", decodeString}},                          // mibModuleName\n\t455: {{\"imsi\", decodeString}},                                     // mobileIMSI\n\t456: {{\"msisdn\", decodeString}},                                   // mobileMSISDN\n\t457: {{\"http_status_code\", decodeUint}},                           // httpStatusCode\n\t458: {{\"src_transport_port_limit\", decodeUint}},                   // sourceTransportPortsLimit\n\t459: {{\"http_request_method\", decodeString}},                      // httpRequestMethod\n\t460: {{\"http_request_host\", decodeString}},                        // httpRequestHost\n\t461: {{\"http_request_target\", decodeString}},                      // httpRequestTarget\n\t462: {{\"http_msg_version\", decodeString}},                         // httpMessageVersion\n\t463: {{\"nat_instance_id\", decodeUint}},                            // natInstanceID\n\t464: {{\"internal_addr_realm\", decodeHex}},                         // internalAddressRealm\n\t465: {{\"external_addr_realm\", decodeHex}},                         // externalAddressRealm\n\t466: {{\"nat_quota_exceeded_event\", decodeUint}},                   // natQuotaExceededEvent\n\t467: {{\"nat_threshold_event\", decodeUint}},                        // natThresholdEvent\n\t468: {{\"http_user_agent\", decodeString}},                          // httpUserAgent\n\t469: {{\"http_content_type\", decodeString}},                        // httpContentType\n\t470: {{\"http_reason_phrase\", decodeString}},                       // httpReasonPhrase\n\t471: {{\"max_session_entries\", decodeUint}},                        // maxSessionEntries\n\t472: {{\"max_bib_entries\", decodeUint}},                            // maxBIBEntries\n\t473: {{\"max_entries_per_user\", decodeUint}},                       // maxEntriesPerUser\n\t474: {{\"max_subscribers\", decodeUint}},                            // maxSubscribers\n\t475: {{\"max_fragments_pending_reassembly\", decodeUint}},           // maxFragmentsPendingReassembly\n\t476: {{\"addr_pool_threshold_high\", decodeUint}},                   // addressPoolHighThreshold\n\t477: {{\"addr_pool_threshold_low\", decodeUint}},                    // addressPoolLowThreshold\n\t478: {{\"addr_port_mapping_threshold_high\", decodeUint}},           // addressPortMappingHighThreshold\n\t479: {{\"addr_port_mapping_threshold_low\", decodeUint}},            // addressPortMappingLowThreshold\n\t480: {{\"addr_port_mapping_per_user_threshold_high\", decodeUint}},  // addressPortMappingPerUserHighThreshold\n\t481: {{\"global_addr_mapping_threshold_high\", decodeUint}},         // globalAddressMappingHighThreshold\n\t482: {{\"vpn_identifier\", decodeIP}},                               // vpnIdentifier\n\t483: {{\"bgp_community\", decodeUint}},                              // bgpCommunity\n\t484: {{\"bgp_src_community_list\", decodeHex}},                      // bgpSourceCommunityList\n\t485: {{\"bgp_dst_community_list\", decodeHex}},                      // bgpDestinationCommunityList\n\t486: {{\"bgp_extended_community\", decodeHex}},                      // bgpExtendedCommunity\n\t487: {{\"bgp_src_extended_community_list\", decodeHex}},             // bgpSourceExtendedCommunityList\n\t488: {{\"bgp_dst_extended_community_list\", decodeHex}},             // bgpDestinationExtendedCommunityList\n\t489: {{\"bgp_large_community\", decodeHex}},                         // bgpLargeCommunity\n\t490: {{\"bgp_src_large_community_list\", decodeHex}},                // bgpSourceLargeCommunityList\n\t491: {{\"bgp_dst_large_community_list\", decodeHex}},                // bgpDestinationLargeCommunityList\n}\n\n// Decoder structure\ntype netflowDecoder struct {\n\tpenFiles []string\n\tlog      telegraf.Logger\n\n\ttemplates     map[string]netflow.NetFlowTemplateSystem\n\tmappingsV9    map[uint16]fieldMapping\n\tmappingsIPFIX map[uint16]fieldMapping\n\tmappingsPEN   map[string]fieldMapping\n\n\tlogged map[string]bool\n\tsync.Mutex\n}\n\nfunc (d *netflowDecoder) decode(srcIP net.IP, payload []byte) ([]telegraf.Metric, error) {\n\tvar metrics []telegraf.Metric\n\n\tt := time.Now()\n\tsrc := srcIP.String()\n\n\t// Prepare the templates used to decode the messages\n\td.Lock()\n\tif _, ok := d.templates[src]; !ok {\n\t\td.templates[src] = netflow.CreateTemplateSystem()\n\t}\n\ttemplates := d.templates[src]\n\td.Unlock()\n\n\t// Decode the overall message\n\tvar msg9 netflow.NFv9Packet\n\tvar msg10 netflow.IPFIXPacket\n\tbuf := bytes.NewBuffer(payload)\n\tif err := netflow.DecodeMessageVersion(buf, templates, &msg9, &msg10); err != nil {\n\t\tif errors.Is(err, netflow.ErrorTemplateNotFound) {\n\t\t\tmsg := \"Skipping packet until the device resends the required template...\"\n\t\t\td.log.Warnf(\"%v. %s\", err, msg)\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"decoding message failed: %w\", err)\n\t}\n\n\t// Extract metrics\n\tswitch {\n\tcase msg9.Version == 9:\n\t\tmsg := msg9\n\t\tfor _, flowsets := range msg.FlowSets {\n\t\t\tswitch fs := flowsets.(type) {\n\t\t\tcase netflow.TemplateFlowSet:\n\t\t\tcase netflow.NFv9OptionsTemplateFlowSet:\n\t\t\tcase netflow.OptionsDataFlowSet:\n\t\t\t\tfor _, record := range fs.Records {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"source\":  src,\n\t\t\t\t\t\t\"version\": \"NetFlowV9\",\n\t\t\t\t\t}\n\t\t\t\t\tfields := make(map[string]interface{})\n\t\t\t\t\tfor _, value := range record.ScopesValues {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueV9(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding option record %+v failed: %v\", record, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor _, value := range record.OptionsValues {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueV9(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding option record %+v failed: %v\", record, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmetrics = append(metrics, metric.New(\"netflow_options\", tags, fields, t))\n\t\t\t\t}\n\t\t\tcase netflow.DataFlowSet:\n\t\t\t\tfor _, record := range fs.Records {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"source\":  src,\n\t\t\t\t\t\t\"version\": \"NetFlowV9\",\n\t\t\t\t\t}\n\t\t\t\t\tfields := make(map[string]interface{})\n\t\t\t\t\tfor _, value := range record.Values {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueV9(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding record %+v failed: %v\", record, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase msg10.Version == 10:\n\t\tmsg := msg10\n\t\tfor _, flowsets := range msg.FlowSets {\n\t\t\tswitch fs := flowsets.(type) {\n\t\t\tcase netflow.TemplateFlowSet:\n\t\t\tcase netflow.IPFIXOptionsTemplateFlowSet:\n\t\t\tcase netflow.OptionsDataFlowSet:\n\t\t\t\tfor _, record := range fs.Records {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"source\":  src,\n\t\t\t\t\t\t\"version\": \"IPFIX\",\n\t\t\t\t\t}\n\t\t\t\t\tfields := make(map[string]interface{})\n\t\t\t\t\tfor _, value := range record.ScopesValues {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueIPFIX(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding option record %+v failed: %v\", record, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor _, value := range record.OptionsValues {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueIPFIX(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding option record %+v failed: %v\", record, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmetrics = append(metrics, metric.New(\"netflow_options\", tags, fields, t))\n\t\t\t\t}\n\t\t\tcase netflow.DataFlowSet:\n\t\t\t\tfor _, record := range fs.Records {\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"source\":  srcIP.String(),\n\t\t\t\t\t\t\"version\": \"IPFIX\",\n\t\t\t\t\t}\n\t\t\t\t\tfields := make(map[string]interface{})\n\t\t\t\t\tt := time.Now()\n\t\t\t\t\tfor _, value := range record.Values {\n\t\t\t\t\t\tdecodedFields, err := d.decodeValueIPFIX(value)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\td.log.Errorf(\"decoding value %+v failed: %v\", value, err)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, field := range decodedFields {\n\t\t\t\t\t\t\tfields[field.Key] = field.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn nil, errors.New(\"invalid message of type\")\n\t}\n\n\treturn metrics, nil\n}\n\nfunc (d *netflowDecoder) init() error {\n\tif err := initL4ProtoMapping(); err != nil {\n\t\treturn fmt.Errorf(\"initializing layer 4 protocol mapping failed: %w\", err)\n\t}\n\tif err := initIPv4OptionMapping(); err != nil {\n\t\treturn fmt.Errorf(\"initializing IPv4 options mapping failed: %w\", err)\n\t}\n\n\td.templates = make(map[string]netflow.NetFlowTemplateSystem)\n\td.mappingsV9 = make(map[uint16]fieldMapping)\n\td.mappingsIPFIX = make(map[uint16]fieldMapping)\n\td.mappingsPEN = make(map[string]fieldMapping)\n\tfor _, fn := range d.penFiles {\n\t\td.log.Debugf(\"Loading PEN mapping file %q...\", fn)\n\t\tmappings, err := loadMapping(fn)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor k, v := range mappings {\n\t\t\tif !regexpIPFIXPENMapping.MatchString(k) {\n\t\t\t\treturn fmt.Errorf(\"key %q in file %q does not match pattern <PEN>.<element-id>; maybe wrong file\", k, fn)\n\t\t\t}\n\t\t\tif _, found := d.mappingsPEN[k]; found {\n\t\t\t\treturn fmt.Errorf(\"duplicate entries for ID %q\", k)\n\t\t\t}\n\t\t\td.mappingsPEN[k] = v\n\t\t}\n\t}\n\td.log.Infof(\"Loaded %d PEN mappings...\", len(d.mappingsPEN))\n\n\td.logged = make(map[string]bool)\n\n\treturn nil\n}\n\nfunc (d *netflowDecoder) decodeValueV9(field netflow.DataField) ([]telegraf.Field, error) {\n\traw := field.Value.([]byte)\n\telementID := field.Type\n\n\t// Check the user-specified mapping\n\tif m, found := d.mappingsV9[elementID]; found {\n\t\tv, err := m.decoder(raw)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []telegraf.Field{{Key: m.name, Value: v}}, nil\n\t}\n\n\t// Check the version specific default field mappings\n\tif mappings, found := fieldMappingsNetflowV9[elementID]; found {\n\t\tfields := make([]telegraf.Field, 0, len(mappings))\n\t\tfor _, m := range mappings {\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfields = append(fields, telegraf.Field{Key: m.name, Value: v})\n\t\t}\n\t\treturn fields, nil\n\t}\n\n\t// Check the common default field mappings\n\tif mappings, found := fieldMappingsNetflowCommon[elementID]; found {\n\t\tfields := make([]telegraf.Field, 0, len(mappings))\n\t\tfor _, m := range mappings {\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfields = append(fields, telegraf.Field{Key: m.name, Value: v})\n\t\t}\n\t\treturn fields, nil\n\t}\n\n\t// Fallback to IPFIX mappings as some devices seem to send IPFIX elements in\n\t// Netflow v9 packets. See https://github.com/influxdata/telegraf/issues/14902\n\t// and https://github.com/influxdata/telegraf/issues/14903.\n\tif mappings, found := fieldMappingsIPFIX[elementID]; found {\n\t\tfields := make([]telegraf.Field, 0, len(mappings))\n\t\tfor _, m := range mappings {\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfields = append(fields, telegraf.Field{Key: m.name, Value: v})\n\t\t}\n\t\treturn fields, nil\n\t}\n\n\t// Return the raw data if no mapping was found\n\tkey := fmt.Sprintf(\"type_%d\", elementID)\n\tif !d.logged[key] {\n\t\td.log.Debugf(\"unknown Netflow v9 data field %v\", field)\n\t\td.logged[key] = true\n\t}\n\tv, err := decodeHex(raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn []telegraf.Field{{Key: key, Value: v}}, nil\n}\n\nfunc (d *netflowDecoder) decodeValueIPFIX(field netflow.DataField) ([]telegraf.Field, error) {\n\traw := field.Value.([]byte)\n\n\t// Checking for reverse elements according to RFC5103\n\tvar prefix string\n\telementID := field.Type\n\tif field.Type&0x4000 != 0 {\n\t\tprefix = \"rev_\"\n\t\telementID = field.Type & (0x4000 ^ 0xffff)\n\t}\n\n\t// Handle messages with Private Enterprise Numbers (PENs)\n\tif field.PenProvided {\n\t\tkey := fmt.Sprintf(\"%d.%d\", field.Pen, elementID)\n\t\tif m, found := d.mappingsPEN[key]; found {\n\t\t\tname := prefix + m.name\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []telegraf.Field{{Key: name, Value: v}}, nil\n\t\t}\n\t\tif !d.logged[key] {\n\t\t\td.log.Debugf(\"unknown IPFIX PEN data field %v\", field)\n\t\t\td.logged[key] = true\n\t\t}\n\t\tname := fmt.Sprintf(\"type_%d_%s%d\", field.Pen, prefix, elementID)\n\t\tv, err := decodeHex(raw)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []telegraf.Field{{Key: name, Value: v}}, nil\n\t}\n\n\t// Check the user-specified mapping\n\tif m, found := d.mappingsIPFIX[elementID]; found {\n\t\tv, err := m.decoder(raw)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []telegraf.Field{{Key: prefix + m.name, Value: v}}, nil\n\t}\n\n\t// Check the version specific default field mappings\n\tif mappings, found := fieldMappingsIPFIX[elementID]; found {\n\t\tfields := make([]telegraf.Field, 0, len(mappings))\n\t\tfor _, m := range mappings {\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfields = append(fields, telegraf.Field{Key: prefix + m.name, Value: v})\n\t\t}\n\t\treturn fields, nil\n\t}\n\n\t// Check the common default field mappings\n\tif mappings, found := fieldMappingsNetflowCommon[elementID]; found {\n\t\tfields := make([]telegraf.Field, 0, len(mappings))\n\t\tfor _, m := range mappings {\n\t\t\tv, err := m.decoder(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfields = append(fields, telegraf.Field{Key: prefix + m.name, Value: v})\n\t\t}\n\t\treturn fields, nil\n\t}\n\n\t// Return the raw data if no mapping was found\n\tkey := fmt.Sprintf(\"type_%d\", elementID)\n\tif !d.logged[key] {\n\t\td.log.Debugf(\"unknown IPFIX data field %v\", field)\n\t\td.logged[key] = true\n\t}\n\tv, err := decodeHex(raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []telegraf.Field{{Key: key, Value: v}}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/netflow_test.go",
    "content": "package netflow\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/netsampler/goflow2/v2/decoders/netflow\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInit(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\taddress  string\n\t\tprotocol string\n\t\terrmsg   string\n\t}{\n\t\t{\n\t\t\tname:     \"Netflow v5\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Netflow v5 (uppercase)\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"Netflow v5\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Netflow v9\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"netflow v9\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Netflow v9 (uppercase)\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"Netflow v9\",\n\t\t},\n\t\t{\n\t\t\tname:     \"IPFIX\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"ipfix\",\n\t\t},\n\t\t{\n\t\t\tname:     \"IPFIX (uppercase)\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"IPFIX\",\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid protocol\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"foo\",\n\t\t\terrmsg:   \"invalid protocol\",\n\t\t},\n\t\t{\n\t\t\tname:     \"UDP\",\n\t\t\taddress:  \"udp://:2055\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t},\n\t\t{\n\t\t\tname:     \"UDP4\",\n\t\t\taddress:  \"udp4://:2055\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t},\n\t\t{\n\t\t\tname:     \"UDP6\",\n\t\t\taddress:  \"udp6://:2055\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty service address\",\n\t\t\taddress:  \"\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t\terrmsg:   \"service_address required\",\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid address scheme\",\n\t\t\taddress:  \"tcp://:2055\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t\terrmsg:   \"invalid scheme\",\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid service address\",\n\t\t\taddress:  \"udp://198.168.1.290:la\",\n\t\t\tprotocol: \"netflow v5\",\n\t\t\terrmsg:   \"invalid service address\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &NetFlow{\n\t\t\t\tServiceAddress: tt.address,\n\t\t\t\tProtocol:       tt.protocol,\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\tif tt.errmsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.errmsg)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMissingTemplate(t *testing.T) {\n\traw := \"000a00bc646b84c000000000000000e7010500ac000000000001dbe100000000\"\n\traw += \"0000038a060018bdeac0a802c8000000000001bb6810f9f90000000000000000\"\n\traw += \"000157b8c40155f28a00005056b3e365005056b3a7f804646b8471646b84e600\"\n\traw += \"00018843fd5cf60000018843ff232e000000000000000e00000000000007bc00\"\n\traw += \"000005000009560000000300dc00000000000000000000000000000e3130342e\"\n\traw += \"31362e3234392e3234390e3130342e31362e3234392e323439000000\"\n\tmsg, err := hex.DecodeString(raw)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tvar logger testutil.CaptureLogger\n\tplugin := &NetFlow{\n\t\tServiceAddress: \"udp://127.0.0.1:0\",\n\t\tLog:            &logger,\n\t}\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Create a client without TLS\n\taddr := plugin.conn.LocalAddr()\n\tclient, err := createClient(plugin.ServiceAddress, addr)\n\trequire.NoError(t, err)\n\n\t// Write the message\n\t_, err = client.Write(msg)\n\trequire.NoErrorf(t, err, \"writing message failed: %v\", err)\n\trequire.NoError(t, client.Close())\n\n\t// We expect a warning here\n\trequire.Eventually(t, func() bool {\n\t\treturn len(logger.Warnings()) > 0\n\t}, 3*time.Second, 100*time.Millisecond, \"did not receive expected warnings\")\n\n\tvar found bool\n\tfor _, w := range logger.Warnings() {\n\t\tfound = found || strings.Contains(w, netflow.ErrorTemplateNotFound.Error())\n\t}\n\trequire.True(t, found, \"warning not found\")\n}\n\nfunc TestWrongMapping(t *testing.T) {\n\tvar logger testutil.CaptureLogger\n\tplugin := &NetFlow{\n\t\tServiceAddress: \"udp://127.0.0.1:0\",\n\t\tProtocol:       \"ipfix\",\n\t\tPENFiles:       []string{\"testcases/netflow_mapping.csv\"},\n\t\tLog:            &logger,\n\t}\n\trequire.ErrorContains(t, plugin.Init(), \"does not match pattern\")\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"netflow\", func() telegraf.Input {\n\t\treturn &NetFlow{}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\tinputFiles := filepath.Join(testcasePath, \"*.bin\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tvar messages [][]byte\n\t\t\tmatches, err := filepath.Glob(inputFiles)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, matches)\n\t\t\tsort.Strings(matches)\n\t\t\tfor _, fn := range matches {\n\t\t\t\tm, err := os.ReadFile(fn)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tmessages = append(messages, m)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup and start the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := cfg.Inputs[0].Input.(*NetFlow)\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a client without TLS\n\t\t\taddr := plugin.conn.LocalAddr()\n\t\t\tclient, err := createClient(plugin.ServiceAddress, addr)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Write the given sequence\n\t\t\tfor i, msg := range messages {\n\t\t\t\t_, err := client.Write(msg)\n\t\t\t\trequire.NoErrorf(t, err, \"writing message from %q failed: %v\", matches[i], err)\n\t\t\t}\n\t\t\trequire.NoError(t, client.Close())\n\n\t\t\tgetNErrors := func() int {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn len(acc.Errors)\n\t\t\t}\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\treturn getNErrors() >= len(expectedErrors)\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"did not receive errors (%d/%d)\", getNErrors(), len(expectedErrors))\n\n\t\t\trequire.Lenf(t, acc.Errors, len(expectedErrors), \"got errors: %v\", acc.Errors)\n\t\t\tsort.SliceStable(acc.Errors, func(i, j int) bool {\n\t\t\t\treturn acc.Errors[i].Error() < acc.Errors[j].Error()\n\t\t\t})\n\t\t\tfor i, err := range acc.Errors {\n\t\t\t\trequire.ErrorContains(t, err, expectedErrors[i])\n\t\t\t}\n\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"did not receive metrics (%d/%d)\", acc.NMetrics(), len(expected))\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc createClient(endpoint string, addr net.Addr) (net.Conn, error) {\n\t// Determine the protocol in a crude fashion\n\tparts := strings.SplitN(endpoint, \"://\", 2)\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid endpoint %q\", endpoint)\n\t}\n\tprotocol := parts[0]\n\treturn net.Dial(protocol, addr.String())\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/netflow_v5.go",
    "content": "package netflow\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/netsampler/goflow2/v2/decoders/netflowlegacy\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\n// Decoder structure\ntype netflowv5Decoder struct{}\n\nfunc (*netflowv5Decoder) init() error {\n\tif err := initL4ProtoMapping(); err != nil {\n\t\treturn fmt.Errorf(\"initializing layer 4 protocol mapping failed: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (*netflowv5Decoder) decode(srcIP net.IP, payload []byte) ([]telegraf.Metric, error) {\n\tsrc := srcIP.String()\n\n\t// Decode the message\n\tvar msg netflowlegacy.PacketNetFlowV5\n\tbuf := bytes.NewBuffer(payload)\n\tif err := netflowlegacy.DecodeMessageVersion(buf, &msg); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Extract metrics\n\tt := time.Unix(int64(msg.UnixSecs), int64(msg.UnixNSecs))\n\tmetrics := make([]telegraf.Metric, 0, len(msg.Records))\n\tfor _, record := range msg.Records {\n\t\ttags := map[string]string{\n\t\t\t\"source\":  src,\n\t\t\t\"version\": \"NetFlowV5\",\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"flows\":             msg.Count,\n\t\t\t\"sys_uptime\":        msg.SysUptime,\n\t\t\t\"seq_number\":        msg.FlowSequence,\n\t\t\t\"engine_type\":       mapEngineType(msg.EngineType),\n\t\t\t\"sampling_interval\": msg.SamplingInterval,\n\t\t\t\"in_snmp\":           record.Input,\n\t\t\t\"out_snmp\":          record.Output,\n\t\t\t\"in_packets\":        record.DPkts,\n\t\t\t\"in_bytes\":          record.DOctets,\n\t\t\t\"first_switched\":    record.First,\n\t\t\t\"last_switched\":     record.Last,\n\t\t\t\"src_port\":          record.SrcPort,\n\t\t\t\"dst_port\":          record.DstPort,\n\t\t\t\"tcp_flags\":         mapTCPFlags(record.TCPFlags),\n\t\t\t\"protocol\":          mapL4Proto(record.Proto),\n\t\t\t\"bgp_src_as\":        record.SrcAS,\n\t\t\t\"bgp_dst_as\":        record.DstAS,\n\t\t\t\"src_mask\":          record.SrcMask,\n\t\t\t\"dst_mask\":          record.DstMask,\n\t\t}\n\n\t\tvar err error\n\t\tfields[\"engine_id\"], err = decodeHex([]byte{msg.EngineId})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding 'engine_id' failed: %w\", err)\n\t\t}\n\t\tfields[\"src\"], err = decodeIPFromUint32(uint32(record.SrcAddr))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding 'src' failed: %w\", err)\n\t\t}\n\t\tfields[\"dst\"], err = decodeIPFromUint32(uint32(record.DstAddr))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding 'dst' failed: %w\", err)\n\t\t}\n\t\tfields[\"next_hop\"], err = decodeIPFromUint32(uint32(record.NextHop))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding 'next_hop' failed: %w\", err)\n\t\t}\n\t\tfields[\"src_tos\"], err = decodeHex([]byte{record.Tos})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding 'src_tos' failed: %w\", err)\n\t\t}\n\n\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t}\n\n\treturn metrics, nil\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/sample.conf",
    "content": "# Netflow v5, Netflow v9 and IPFIX collector\n[[inputs.netflow]]\n  ## Address to listen for netflow,ipfix or sflow packets.\n  ##   example: service_address = \"udp://:2055\"\n  ##            service_address = \"udp4://:2055\"\n  ##            service_address = \"udp6://:2055\"\n  service_address = \"udp://:2055\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  ## Uses the system's default if not set.\n  # read_buffer_size = \"\"\n\n  ## Protocol version to use for decoding.\n  ## Available options are\n  ##   \"ipfix\"      -- IPFIX / Netflow v10 protocol (also works for Netflow v9)\n  ##   \"netflow v5\" -- Netflow v5 protocol\n  ##   \"netflow v9\" -- Netflow v9 protocol (also works for IPFIX)\n  ##   \"sflow v5\"   -- sFlow v5 protocol\n  # protocol = \"ipfix\"\n\n  ## Private Enterprise Numbers (PEN) mappings for decoding\n  ## This option allows to specify vendor-specific mapping files to use during\n  ## decoding.\n  # private_enterprise_number_files = []\n\n  ## Log incoming packets for tracing issues\n  # log_level = \"trace\"\n"
  },
  {
    "path": "plugins/inputs/netflow/sflow_v5.go",
    "content": "package netflow\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n\t\"github.com/netsampler/goflow2/v2/decoders/sflow\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\n// Decoder structure\ntype sflowv5Decoder struct {\n\tlog telegraf.Logger\n\n\twarnedCounterRaw map[uint32]bool\n\twarnedFlowRaw    map[int64]bool\n}\n\nfunc (d *sflowv5Decoder) init() error {\n\tif err := initL4ProtoMapping(); err != nil {\n\t\treturn fmt.Errorf(\"initializing layer 4 protocol mapping failed: %w\", err)\n\t}\n\td.warnedCounterRaw = make(map[uint32]bool)\n\td.warnedFlowRaw = make(map[int64]bool)\n\n\treturn nil\n}\n\nfunc (d *sflowv5Decoder) decode(srcIP net.IP, payload []byte) ([]telegraf.Metric, error) {\n\tt := time.Now()\n\tsrc := srcIP.String()\n\n\t// Decode the message\n\tvar msg sflow.Packet\n\tbuf := bytes.NewBuffer(payload)\n\tif err := sflow.DecodeMessageVersion(buf, &msg); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Extract metrics\n\tmetrics := make([]telegraf.Metric, 0, len(msg.Samples))\n\tfor _, s := range msg.Samples {\n\t\ttags := map[string]string{\n\t\t\t\"source\":  src,\n\t\t\t\"version\": \"sFlowV5\",\n\t\t}\n\n\t\tswitch sample := s.(type) {\n\t\tcase sflow.FlowSample:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"ip_version\":        decodeSflowIPVersion(msg.IPVersion),\n\t\t\t\t\"sys_uptime\":        msg.Uptime,\n\t\t\t\t\"agent_subid\":       msg.SubAgentId,\n\t\t\t\t\"seq_number\":        sample.Header.SampleSequenceNumber,\n\t\t\t\t\"sampling_interval\": sample.SamplingRate,\n\t\t\t\t\"in_total_packets\":  sample.SamplePool,\n\t\t\t\t\"sampling_drops\":    sample.Drops,\n\t\t\t\t\"in_snmp\":           sample.Input,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tfields[\"agent_ip\"], err = decodeIP(msg.AgentIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'agent_ip' failed: %w\", err)\n\t\t\t}\n\n\t\t\tif sample.Output>>31 == 0 {\n\t\t\t\tfields[\"out_snmp\"] = sample.Output & 0x7fffffff\n\t\t\t}\n\t\t\t// Decode the source information\n\t\t\tif name := decodeSflowSourceInterface(sample.Header.SourceIdType); name != \"\" {\n\t\t\t\tfields[name] = sample.Header.SourceIdValue\n\t\t\t}\n\t\t\t// Decode the sampling direction\n\t\t\tif sample.Header.SourceIdValue == sample.Input {\n\t\t\t\tfields[\"direction\"] = \"ingress\"\n\t\t\t} else {\n\t\t\t\tfields[\"direction\"] = \"egress\"\n\t\t\t}\n\t\t\trecordFields, err := d.decodeFlowRecords(sample.Records)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range recordFields {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t\tcase sflow.ExpandedFlowSample:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"ip_version\":        decodeSflowIPVersion(msg.IPVersion),\n\t\t\t\t\"sys_uptime\":        msg.Uptime,\n\t\t\t\t\"agent_subid\":       msg.SubAgentId,\n\t\t\t\t\"seq_number\":        sample.Header.SampleSequenceNumber,\n\t\t\t\t\"sampling_interval\": sample.SamplingRate,\n\t\t\t\t\"in_total_packets\":  sample.SamplePool,\n\t\t\t\t\"sampling_drops\":    sample.Drops,\n\t\t\t\t\"in_snmp\":           sample.InputIfValue,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tfields[\"agent_ip\"], err = decodeIP(msg.AgentIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'agent_ip' failed: %w\", err)\n\t\t\t}\n\n\t\t\tif sample.OutputIfFormat == 0 {\n\t\t\t\tfields[\"out_snmp\"] = sample.OutputIfValue\n\t\t\t}\n\t\t\t// Decode the source information\n\t\t\tif name := decodeSflowSourceInterface(sample.Header.SourceIdType); name != \"\" {\n\t\t\t\tfields[name] = sample.Header.SourceIdValue\n\t\t\t}\n\t\t\t// Decode the sampling direction\n\t\t\tif sample.Header.SourceIdValue == sample.InputIfValue {\n\t\t\t\tfields[\"direction\"] = \"ingress\"\n\t\t\t} else {\n\t\t\t\tfields[\"direction\"] = \"egress\"\n\t\t\t}\n\t\t\trecordFields, err := d.decodeFlowRecords(sample.Records)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range recordFields {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t\tcase sflow.CounterSample:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"ip_version\":  decodeSflowIPVersion(msg.IPVersion),\n\t\t\t\t\"sys_uptime\":  msg.Uptime,\n\t\t\t\t\"agent_subid\": msg.SubAgentId,\n\t\t\t\t\"seq_number\":  sample.Header.SampleSequenceNumber,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tfields[\"agent_ip\"], err = decodeIP(msg.AgentIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'agent_ip' failed: %w\", err)\n\t\t\t}\n\n\t\t\t// Decode the source information\n\t\t\tif name := decodeSflowSourceInterface(sample.Header.SourceIdType); name != \"\" {\n\t\t\t\tfields[name] = sample.Header.SourceIdValue\n\t\t\t}\n\t\t\trecordFields, err := d.decodeCounterRecords(sample.Records)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range recordFields {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\t\tcase sflow.DropSample:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"ip_version\":     decodeSflowIPVersion(msg.IPVersion),\n\t\t\t\t\"sys_uptime\":     msg.Uptime,\n\t\t\t\t\"agent_subid\":    msg.SubAgentId,\n\t\t\t\t\"seq_number\":     sample.Header.SampleSequenceNumber,\n\t\t\t\t\"sampling_drops\": sample.Drops,\n\t\t\t\t\"in_snmp\":        sample.Input,\n\t\t\t\t\"out_snmp\":       sample.Output,\n\t\t\t\t\"reason\":         sample.Reason,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tfields[\"agent_ip\"], err = decodeIP(msg.AgentIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'agent_ip' failed: %w\", err)\n\t\t\t}\n\n\t\t\t// Decode the source information\n\t\t\tif name := decodeSflowSourceInterface(sample.Header.SourceIdType); name != \"\" {\n\t\t\t\tfields[name] = sample.Header.SourceIdValue\n\t\t\t}\n\t\t\t// Decode the sampling direction\n\t\t\tif sample.Header.SourceIdValue == sample.Input {\n\t\t\t\tfields[\"direction\"] = \"ingress\"\n\t\t\t} else {\n\t\t\t\tfields[\"direction\"] = \"egress\"\n\t\t\t}\n\t\t\trecordFields, err := d.decodeFlowRecords(sample.Records)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range recordFields {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\t\tmetrics = append(metrics, metric.New(\"netflow\", tags, fields, t))\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown record type %T\", s)\n\t\t}\n\t}\n\n\treturn metrics, nil\n}\n\nfunc (d *sflowv5Decoder) decodeFlowRecords(records []sflow.FlowRecord) (map[string]interface{}, error) {\n\tfields := make(map[string]interface{})\n\tfor _, r := range records {\n\t\tif r.Data == nil {\n\t\t\tcontinue\n\t\t}\n\t\tswitch record := r.Data.(type) {\n\t\tcase sflow.SampledHeader:\n\t\t\tfields[\"l2_protocol\"] = decodeSflowHeaderProtocol(record.Protocol)\n\t\t\tfields[\"l2_bytes\"] = record.FrameLength\n\t\t\tpktfields, err := d.decodeRawHeaderSample(&record)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range pktfields {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\tcase sflow.SampledEthernet:\n\t\t\tvar err error\n\t\t\tfields[\"eth_total_len\"] = record.Length\n\t\t\tfields[\"in_src_mac\"], err = decodeMAC(record.SrcMac)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'in_src_mac' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"out_dst_mac\"], err = decodeMAC(record.DstMac)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'out_dst_mac' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"datalink_frame_type\"] = layers.EthernetType(record.EthType & 0x0000ffff).String()\n\t\tcase sflow.SampledIPv4:\n\t\t\tvar err error\n\t\t\tfields[\"ipv4_total_len\"] = record.Length\n\t\t\tfields[\"protocol\"] = mapL4Proto(uint8(record.Protocol & 0x000000ff))\n\t\t\tfields[\"src\"], err = decodeIP(record.SrcIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'src' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"dst\"], err = decodeIP(record.DstIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'dst' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"src_port\"] = record.SrcPort\n\t\t\tfields[\"dst_port\"] = record.DstPort\n\t\t\tfields[\"src_tos\"] = record.Tos\n\t\t\tfields[\"tcp_flags\"], err = decodeTCPFlags([]byte{byte(record.TcpFlags & 0x000000ff)})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'tcp_flags' failed: %w\", err)\n\t\t\t}\n\t\tcase sflow.SampledIPv6:\n\t\t\tvar err error\n\t\t\tfields[\"ipv6_total_len\"] = record.Length\n\t\t\tfields[\"protocol\"] = mapL4Proto(uint8(record.Protocol & 0x000000ff))\n\t\t\tfields[\"src\"], err = decodeIP(record.SrcIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'src' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"dst\"], err = decodeIP(record.DstIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'dst' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"src_port\"] = record.SrcPort\n\t\t\tfields[\"dst_port\"] = record.DstPort\n\t\t\tfields[\"tcp_flags\"], err = decodeTCPFlags([]byte{byte(record.TcpFlags & 0x000000ff)})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'tcp_flags' failed: %w\", err)\n\t\t\t}\n\t\tcase sflow.ExtendedSwitch:\n\t\t\tfields[\"vlan_src\"] = record.SrcVlan\n\t\t\tfields[\"vlan_src_priority\"] = record.SrcPriority\n\t\t\tfields[\"vlan_dst\"] = record.DstVlan\n\t\t\tfields[\"vlan_dst_priority\"] = record.DstPriority\n\t\tcase sflow.ExtendedRouter:\n\t\t\tvar err error\n\t\t\tfields[\"next_hop\"], err = decodeIP(record.NextHop)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'next_hop' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"src_mask\"] = record.SrcMaskLen\n\t\t\tfields[\"dst_mask\"] = record.DstMaskLen\n\t\tcase sflow.ExtendedGateway:\n\t\t\tvar err error\n\t\t\tfields[\"next_hop_ip_version\"] = record.NextHopIPVersion\n\t\t\tfields[\"next_hop\"], err = decodeIP(record.NextHop)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'next_hop' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"bgp_as\"] = record.AS\n\t\t\tfields[\"bgp_src_as\"] = record.SrcAS\n\t\t\tfields[\"bgp_dst_as\"] = record.ASDestinations\n\t\t\tfields[\"bgp_as_path_type\"] = record.ASPathType\n\t\t\tfields[\"bgp_as_path_length\"] = record.ASPathLength\n\t\t\tfields[\"bgp_next_hop\"], err = decodeIP(record.NextHop)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"decoding 'bgp_next_hop' failed: %w\", err)\n\t\t\t}\n\t\t\tfields[\"bgp_prev_as\"] = record.SrcPeerAS\n\t\t\tif len(record.ASPath) > 0 {\n\t\t\t\tfields[\"bgp_next_as\"] = record.ASPath[0]\n\t\t\t}\n\t\t\tfields[\"community_length\"] = record.CommunitiesLength\n\t\t\tparts := make([]string, 0, len(record.Communities))\n\t\t\tfor _, c := range record.Communities {\n\t\t\t\tparts = append(parts, \"0x\"+strconv.FormatUint(uint64(c), 16))\n\t\t\t}\n\t\t\tfields[\"communities\"] = strings.Join(parts, \",\")\n\t\t\tfields[\"local_pref\"] = record.LocalPref\n\t\tcase sflow.EgressQueue:\n\t\t\tfields[\"out_queue\"] = record.Queue\n\t\tcase sflow.ExtendedACL:\n\t\t\tfields[\"acl_id\"] = record.Number\n\t\t\tfields[\"acl_name\"] = record.Name\n\t\t\tswitch record.Direction {\n\t\t\tcase 1:\n\t\t\t\tfields[\"direction\"] = \"ingress\"\n\t\t\tcase 2:\n\t\t\t\tfields[\"direction\"] = \"egress\"\n\t\t\tdefault:\n\t\t\t\tfields[\"direction\"] = \"unknown\"\n\t\t\t}\n\t\tcase sflow.ExtendedFunction:\n\t\t\tfields[\"function\"] = record.Symbol\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unhandled flow record type %T\", r.Data)\n\t\t}\n\t}\n\treturn fields, nil\n}\n\nfunc (d *sflowv5Decoder) decodeRawHeaderSample(record *sflow.SampledHeader) (map[string]interface{}, error) {\n\tvar packet gopacket.Packet\n\tswitch record.Protocol {\n\tcase 1: // ETHERNET-ISO8023\n\t\tpacket = gopacket.NewPacket(record.HeaderData, layers.LayerTypeEthernet, gopacket.Default)\n\tcase 2: // ISO88024-TOKENBUS\n\t\tfallthrough\n\tcase 3: // ISO88025-TOKENRING\n\t\tfallthrough\n\tcase 4: // FDDI\n\t\tfallthrough\n\tcase 5: // FRAME-RELAY\n\t\tfallthrough\n\tcase 6: // X25\n\t\tfallthrough\n\tcase 7: // PPP\n\t\tfallthrough\n\tcase 8: // SMDS\n\t\tfallthrough\n\tcase 9: // AAL5\n\t\tfallthrough\n\tcase 10: // AAL5-IP\n\t\tfallthrough\n\tcase 11: // IPv4\n\t\tfallthrough\n\tcase 12: // IPv6\n\t\tfallthrough\n\tcase 13: // MPLS\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unhandled protocol %d\", record.Protocol)\n\t}\n\n\tfields := make(map[string]interface{})\n\tfor _, pkt := range packet.Layers() {\n\t\tswitch l := pkt.(type) {\n\t\tcase *layers.Ethernet:\n\t\t\tfields[\"in_src_mac\"] = l.SrcMAC.String()\n\t\t\tfields[\"out_dst_mac\"] = l.DstMAC.String()\n\t\t\tfields[\"datalink_frame_type\"] = l.EthernetType.String()\n\t\t\tif l.Length > 0 {\n\t\t\t\tfields[\"eth_header_len\"] = l.Length\n\t\t\t}\n\t\tcase *layers.Dot1Q:\n\t\t\tfields[\"vlan_id\"] = l.VLANIdentifier\n\t\t\tfields[\"vlan_priority\"] = l.Priority\n\t\t\tfields[\"vlan_drop_eligible\"] = l.DropEligible\n\t\tcase *layers.IPv4:\n\t\t\tfields[\"ip_version\"] = decodePacketIPVersion(l.Version)\n\t\t\tfields[\"ipv4_inet_header_len\"] = l.IHL\n\t\t\tfields[\"src_tos\"] = l.TOS\n\t\t\tfields[\"ipv4_total_len\"] = l.Length\n\t\t\tfields[\"ipv4_id\"] = l.Id // ?\n\t\t\tfields[\"ttl\"] = l.TTL\n\t\t\tfields[\"protocol\"] = mapL4Proto(uint8(l.Protocol))\n\t\t\tfields[\"src\"] = l.SrcIP.String()\n\t\t\tfields[\"dst\"] = l.DstIP.String()\n\n\t\t\tflags := []byte(\"........\")\n\t\t\tif l.Flags&layers.IPv4EvilBit > 0 {\n\t\t\t\tflags[7] = byte('E')\n\t\t\t}\n\t\t\tif l.Flags&layers.IPv4DontFragment > 0 {\n\t\t\t\tflags[6] = byte('D')\n\t\t\t}\n\t\t\tif l.Flags&layers.IPv4MoreFragments > 0 {\n\t\t\t\tflags[5] = byte('M')\n\t\t\t}\n\t\t\tfields[\"fragment_flags\"] = string(flags)\n\t\t\tfields[\"fragment_offset\"] = l.FragOffset\n\t\t\tfields[\"ip_total_len\"] = l.Length\n\t\tcase *layers.IPv6:\n\t\t\tfields[\"ip_version\"] = decodePacketIPVersion(l.Version)\n\t\t\tfields[\"ipv6_total_len\"] = l.Length\n\t\t\tfields[\"ttl\"] = l.HopLimit\n\t\t\tfields[\"protocol\"] = mapL4Proto(uint8(l.NextHeader))\n\t\t\tfields[\"src\"] = l.SrcIP.String()\n\t\t\tfields[\"dst\"] = l.DstIP.String()\n\t\t\tfields[\"ip_total_len\"] = l.Length\n\t\tcase *layers.TCP:\n\t\t\tfields[\"src_port\"] = uint16(l.SrcPort)\n\t\t\tfields[\"dst_port\"] = uint16(l.DstPort)\n\t\t\tfields[\"tcp_seq_number\"] = l.Seq\n\t\t\tfields[\"tcp_ack_number\"] = l.Ack\n\t\t\tfields[\"tcp_window_size\"] = l.Window\n\t\t\tfields[\"tcp_urgent_ptr\"] = l.Urgent\n\t\t\tflags := []byte(\"........\")\n\t\t\tif l.FIN {\n\t\t\t\tflags[7] = byte('F')\n\t\t\t}\n\t\t\tif l.SYN {\n\t\t\t\tflags[6] = byte('S')\n\t\t\t}\n\t\t\tif l.RST {\n\t\t\t\tflags[5] = byte('R')\n\t\t\t}\n\t\t\tif l.PSH {\n\t\t\t\tflags[4] = byte('P')\n\t\t\t}\n\t\t\tif l.ACK {\n\t\t\t\tflags[3] = byte('A')\n\t\t\t}\n\t\t\tif l.URG {\n\t\t\t\tflags[2] = byte('U')\n\t\t\t}\n\t\t\tif l.ECE {\n\t\t\t\tflags[1] = byte('E')\n\t\t\t}\n\t\t\tif l.CWR {\n\t\t\t\tflags[0] = byte('C')\n\t\t\t}\n\t\t\tfields[\"tcp_flags\"] = string(flags)\n\t\tcase *layers.UDP:\n\t\t\tfields[\"src_port\"] = uint16(l.SrcPort)\n\t\t\tfields[\"dst_port\"] = uint16(l.DstPort)\n\t\t\tfields[\"ip_total_len\"] = l.Length\n\t\tcase *gopacket.Payload:\n\t\t\t// Ignore the payload\n\t\tdefault:\n\t\t\tltype := int64(pkt.LayerType())\n\t\t\tif !d.warnedFlowRaw[ltype] {\n\t\t\t\tcontents := hex.EncodeToString(pkt.LayerContents())\n\t\t\t\tpayload := hex.EncodeToString(pkt.LayerPayload())\n\t\t\t\td.log.Warnf(\"Unknown flow raw flow message %s (%d):\", pkt.LayerType().String(), pkt.LayerType())\n\t\t\t\td.log.Warnf(\"  contents: %s\", contents)\n\t\t\t\td.log.Warnf(\"  payload:  %s\", payload)\n\n\t\t\t\td.log.Warn(\"This message is only printed once.\")\n\t\t\t}\n\t\t\td.warnedFlowRaw[ltype] = true\n\t\t}\n\t}\n\treturn fields, nil\n}\n\nfunc (d *sflowv5Decoder) decodeCounterRecords(records []sflow.CounterRecord) (map[string]interface{}, error) {\n\tfor _, r := range records {\n\t\tif r.Data == nil {\n\t\t\tcontinue\n\t\t}\n\t\tswitch record := r.Data.(type) {\n\t\tcase sflow.IfCounters:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"interface\":                   record.IfIndex,\n\t\t\t\t\"interface_type\":              record.IfType,\n\t\t\t\t\"speed\":                       record.IfSpeed,\n\t\t\t\t\"in_bytes\":                    record.IfInOctets,\n\t\t\t\t\"in_unicast_packets_total\":    record.IfInUcastPkts,\n\t\t\t\t\"in_mcast_packets_total\":      record.IfInMulticastPkts,\n\t\t\t\t\"in_broadcast_packets_total\":  record.IfInBroadcastPkts,\n\t\t\t\t\"in_dropped_packets\":          record.IfInDiscards,\n\t\t\t\t\"in_errors\":                   record.IfInErrors,\n\t\t\t\t\"in_unknown_protocol\":         record.IfInUnknownProtos,\n\t\t\t\t\"out_bytes\":                   record.IfOutOctets,\n\t\t\t\t\"out_unicast_packets_total\":   record.IfOutUcastPkts,\n\t\t\t\t\"out_mcast_packets_total\":     record.IfOutMulticastPkts,\n\t\t\t\t\"out_broadcast_packets_total\": record.IfOutBroadcastPkts,\n\t\t\t\t\"out_dropped_packets\":         record.IfOutDiscards,\n\t\t\t\t\"out_errors\":                  record.IfOutErrors,\n\t\t\t\t\"promiscuous\":                 record.IfPromiscuousMode,\n\t\t\t}\n\t\t\tif record.IfStatus == 0 {\n\t\t\t\tfields[\"status\"] = \"down\"\n\t\t\t} else {\n\t\t\t\tfields[\"status\"] = \"up\"\n\t\t\t}\n\t\t\treturn fields, nil\n\t\tcase sflow.EthernetCounters:\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"type\":                    \"IEEE 802.3\",\n\t\t\t\t\"collision_frames_single\": record.Dot3StatsSingleCollisionFrames,\n\t\t\t\t\"collision_frames_multi\":  record.Dot3StatsMultipleCollisionFrames,\n\t\t\t\t\"collisions_late\":         record.Dot3StatsLateCollisions,\n\t\t\t\t\"collisions_excessive\":    record.Dot3StatsExcessiveCollisions,\n\t\t\t\t\"deferred\":                record.Dot3StatsDeferredTransmissions,\n\t\t\t\t\"errors_alignment\":        record.Dot3StatsAlignmentErrors,\n\t\t\t\t\"errors_fcs\":              record.Dot3StatsFCSErrors,\n\t\t\t\t\"errors_sqetest\":          record.Dot3StatsSQETestErrors,\n\t\t\t\t\"errors_internal_mac_tx\":  record.Dot3StatsInternalMacTransmitErrors,\n\t\t\t\t\"errors_internal_mac_rx\":  record.Dot3StatsInternalMacReceiveErrors,\n\t\t\t\t\"errors_carrier_sense\":    record.Dot3StatsCarrierSenseErrors,\n\t\t\t\t\"errors_frame_too_long\":   record.Dot3StatsFrameTooLongs,\n\t\t\t\t\"errors_symbols\":          record.Dot3StatsSymbolErrors,\n\t\t\t}\n\t\t\treturn fields, nil\n\t\tcase sflow.RawRecord:\n\t\t\tswitch r.Header.DataFormat {\n\t\t\tcase 1005:\n\t\t\t\t// Openflow port-name\n\t\t\t\tif len(record.Data) < 4 {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid data for raw counter %+v\", r)\n\t\t\t\t}\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"port_name\": string(record.Data[4:]),\n\t\t\t\t}\n\t\t\t\treturn fields, nil\n\t\t\tdefault:\n\t\t\t\tif !d.warnedCounterRaw[r.Header.DataFormat] {\n\t\t\t\t\tdata := hex.EncodeToString(record.Data)\n\t\t\t\t\td.log.Warnf(\"Unknown counter raw flow message %d: %s\", r.Header.DataFormat, data)\n\t\t\t\t\td.log.Warn(\"This message is only printed once.\")\n\t\t\t\t}\n\t\t\t\td.warnedCounterRaw[r.Header.DataFormat] = true\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unhandled counter record type %T\", r.Data)\n\t\t}\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_example/expected.out",
    "content": "netflow,source=127.0.0.1,version=IPFIX protocol=\"tcp\",dst_port=443u,in_total_bytes=52u,src_tos=\"0x00\",dst=\"44.233.90.52\",src_port=51008u,flow_end_reason=\"end of flow\",in_total_packets=1u,src=\"192.168.119.100\",type_6871_40=\"0x0000\",flow_start_ms=1666345513807u,vlan_src=0u,flow_end_ms=1666345513807u 1684917213504248417\nnetflow,source=127.0.0.1,version=IPFIX type_29305_5=\"0x00\",in_total_bytes=80u,type_29305_86=\"0x00000001\",in_total_packets=2u,type_29305_85=\"0x00000028\",flow_end_reason=\"end of flow\",vlan_src=0u,src=\"192.168.119.100\",flow_end_ms=1666345513816u,dst_port=443u,protocol=\"tcp\",type_6871_21=\"0x00000009\",dst=\"104.17.240.92\",type_29305_58=\"0x0000\",type_6871_40=\"0x0000\",type_6871_rev_40=\"0x0000\",flow_start_ms=1666345513807u,src_port=54330u,src_tos=\"0x00\" 1684917213504502791\nnetflow,source=127.0.0.1,version=IPFIX src=\"192.168.119.100\",dst=\"44.233.90.52\",type_6871_rev_40=\"0x0000\",dst_port=443u,type_6871_21=\"0x000000aa\",type_6871_40=\"0x0000\",flow_end_reason=\"end of flow\",flow_end_ms=1666345513977u,type_29305_85=\"0x00000028\",type_29305_5=\"0x00\",vlan_src=0u,flow_start_ms=1666345513807u,src_tos=\"0x00\",protocol=\"tcp\",src_port=51024u,type_29305_86=\"0x00000001\",in_total_bytes=52u,in_total_packets=1u,type_29305_58=\"0x0000\" 1684917213504688593\nnetflow,source=127.0.0.1,version=IPFIX flow_end_reason=\"forced end\",src_port=58246u,src=\"192.168.119.100\",flow_end_ms=1666345513806u,dst_port=53u,flow_start_ms=1666345513806u,in_total_packets=2u,src_tos=\"0x00\",type_29305_58=\"0x0000\",in_total_bytes=140u,type_6871_21=\"0x00000000\",protocol=\"udp\",type_6871_rev_40=\"0x0000\",vlan_src=0u,type_6871_40=\"0x0001\",type_29305_5=\"0x00\",type_29305_85=\"0x0000009c\",type_29305_86=\"0x00000002\",dst=\"192.168.119.17\" 1684917213504857795\nnetflow,source=127.0.0.1,version=IPFIX type_29305_86=\"0x00000002\",type_29305_58=\"0x0000\",protocol=\"udp\",type_29305_85=\"0x000000dd\",dst=\"192.168.119.17\",in_total_packets=2u,type_6871_rev_40=\"0x0000\",flow_end_ms=1666345513832u,src=\"192.168.119.100\",src_port=58879u,type_6871_21=\"0x00000021\",vlan_src=0u,flow_end_reason=\"forced end\",type_6871_40=\"0x0001\",flow_start_ms=1666345513799u,type_29305_5=\"0x00\",dst_port=53u,src_tos=\"0x00\",in_total_bytes=112u 1684917213505013747\nnetflow,source=127.0.0.1,version=IPFIX protocol=\"udp\",type_6871_rev_40=\"0x0000\",vlan_src=0u,type_6871_40=\"0x0001\",type_29305_58=\"0x0000\",type_29305_5=\"0x00\",dst=\"192.168.119.17\",type_29305_86=\"0x00000002\",src=\"192.168.119.100\",flow_end_ms=1666345514167u,type_29305_85=\"0x0000020a\",dst_port=53u,flow_end_reason=\"forced end\",type_6871_21=\"0x00000000\",src_tos=\"0x00\",src_port=56439u,flow_start_ms=1666345514150u,in_total_packets=2u,in_total_bytes=154u 1684917213505160049\nnetflow,source=127.0.0.1,version=IPFIX type_6871_rev_40=\"0x0000\",type_29305_85=\"0x00011254\",dst_port=443u,type_29305_86=\"0x00000044\",flow_start_ms=1666345513832u,src=\"192.168.119.100\",in_total_bytes=5853u,protocol=\"udp\",flow_end_reason=\"forced end\",vlan_src=0u,in_total_packets=43u,type_29305_58=\"0x0000\",type_6871_40=\"0x0000\",flow_end_ms=1666345514328u,src_tos=\"0x00\",src_port=57795u,dst=\"34.149.140.181\",type_29305_5=\"0x00\",type_6871_21=\"0x00000012\" 1684917213505306401\nnetflow,source=127.0.0.1,version=IPFIX src_tos=\"0x00\",flow_start_ms=1666345512753u,dst=\"239.255.255.250\",src=\"192.168.119.100\",type_6871_40=\"0x0001\",dst_port=1900u,protocol=\"udp\",vlan_src=0u,src_port=57622u,flow_end_ms=1666345515756u,flow_end_reason=\"forced end\",in_total_bytes=784u,in_total_packets=4u 1684917213505453773\nnetflow,source=127.0.0.1,version=IPFIX protocol=\"udp\",type_29305_5=\"0x00\",flow_start_ms=1666345512531u,type_6871_21=\"0x00000011\",type_29305_86=\"0x00000066\",type_29305_58=\"0x0000\",flow_end_ms=1666345519408u,dst=\"216.58.212.132\",flow_end_reason=\"forced end\",in_total_bytes=6105u,type_6871_rev_40=\"0x0000\",in_total_packets=60u,vlan_src=0u,src_tos=\"0x00\",dst_port=443u,src_port=54458u,type_6871_40=\"0x0000\",type_29305_85=\"0x00016837\",src=\"192.168.119.100\" 1684917213505487043\nnetflow,source=127.0.0.1,version=IPFIX type_6871_rev_40=\"0x0000\",type_29305_86=\"0x00000001\",flow_start_ms=1666345519932u,src_tos=\"0x00\",in_total_bytes=52u,flow_end_ms=1666345519942u,type_29305_58=\"0x0000\",type_6871_21=\"0x0000000a\",in_total_packets=1u,dst=\"13.32.99.76\",src=\"192.168.119.100\",vlan_src=0u,protocol=\"tcp\",src_port=60758u,type_6871_40=\"0x0000\",type_29305_5=\"0x00\",dst_port=443u,flow_end_reason=\"forced end\",type_29305_85=\"0x00000034\" 1684917213505641375\nnetflow,source=127.0.0.1,version=IPFIX type_29305_58=\"0x0000\",protocol=\"tcp\",type_6871_21=\"0x0000000a\",src=\"192.168.119.100\",src_tos=\"0x00\",in_total_packets=1u,type_6871_40=\"0x0000\",flow_end_ms=1666345519942u,type_6871_rev_40=\"0x0000\",flow_start_ms=1666345519932u,type_29305_86=\"0x00000001\",in_total_bytes=40u,dst_port=443u,vlan_src=0u,type_29305_5=\"0x00\",type_29305_85=\"0x00000028\",flow_end_reason=\"forced end\",dst=\"104.17.146.91\",src_port=58432u 1684917213505792347\nnetflow,source=127.0.0.1,version=IPFIX type_6871_rev_40=\"0x0000\",src_port=36397u,flow_start_ms=1666345521006u,type_29305_5=\"0x00\",src_tos=\"0x00\",in_total_bytes=138u,type_29305_85=\"0x0000011c\",type_6871_21=\"0x00000000\",type_6871_40=\"0x0001\",vlan_src=0u,protocol=\"udp\",dst_port=53u,src=\"192.168.119.100\",type_29305_58=\"0x0000\",in_total_packets=2u,type_29305_86=\"0x00000002\",flow_end_ms=1666345521006u,dst=\"192.168.119.17\",flow_end_reason=\"forced end\" 1684917213505948399\nnetflow,source=127.0.0.1,version=IPFIX type_29305_58=\"0x0000\",src=\"192.168.119.100\",type_29305_86=\"0x00000002\",flow_end_reason=\"forced end\",in_total_packets=2u,type_6871_21=\"0x00000000\",flow_start_ms=1666345520998u,type_6871_40=\"0x0001\",vlan_src=0u,protocol=\"udp\",type_6871_rev_40=\"0x0000\",src_port=39786u,type_29305_85=\"0x000000c1\",in_total_bytes=112u,dst_port=53u,dst=\"192.168.119.17\",src_tos=\"0x00\",type_29305_5=\"0x00\",flow_end_ms=1666345521019u 1684917213506093831\nnetflow,source=127.0.0.1,version=IPFIX dst_port=443u,type_6871_21=\"0x00000009\",flow_start_ms=1666345521006u,vlan_src=0u,type_29305_58=\"0x0000\",src_tos=\"0x00\",src=\"192.168.119.100\",type_6871_40=\"0x0000\",flow_end_ms=1666345521032u,src_port=52370u,type_29305_85=\"0x0000028d\",in_total_bytes=860u,type_6871_rev_40=\"0x0000\",type_29305_5=\"0x00\",flow_end_reason=\"forced end\",type_29305_86=\"0x00000004\",in_total_packets=5u,protocol=\"tcp\",dst=\"185.199.109.154\" 1684917213506254733\nnetflow,source=127.0.0.1,version=IPFIX flow_end_ms=1666345521742u,vlan_src=0u,type_6871_40=\"0x0001\",in_total_packets=2u,type_29305_58=\"0x0000\",src_tos=\"0x00\",src_port=44461u,dst=\"192.168.119.17\",type_29305_5=\"0x00\",type_29305_86=\"0x00000002\",type_6871_21=\"0x00000000\",type_29305_85=\"0x00000146\",flow_start_ms=1666345521742u,in_total_bytes=150u,type_6871_rev_40=\"0x0000\",src=\"192.168.119.100\",protocol=\"udp\",dst_port=53u,flow_end_reason=\"forced end\" 1684917213506407245\nnetflow,source=127.0.0.1,version=IPFIX src=\"192.168.119.100\",in_total_packets=5u,protocol=\"tcp\",flow_end_reason=\"forced end\",flow_start_ms=1666345521742u,type_6871_21=\"0x00000009\",vlan_src=0u,dst=\"185.199.109.154\",type_6871_40=\"0x0000\",type_29305_58=\"0x0000\",type_29305_85=\"0x0000028d\",dst_port=443u,type_29305_5=\"0x00\",flow_end_ms=1666345521771u,in_total_bytes=860u,src_port=52376u,type_29305_86=\"0x00000004\",src_tos=\"0x00\",type_6871_rev_40=\"0x0000\" 1684917213506554437\nnetflow,source=127.0.0.1,version=IPFIX type_6871_21=\"0x00000000\",vlan_src=0u,src_tos=\"0x00\",flow_end_reason=\"forced end\",flow_start_ms=1666345521780u,flow_end_ms=1666345521780u,type_6871_40=\"0x0001\",src=\"192.168.119.100\",type_29305_86=\"0x00000002\",protocol=\"udp\",dst_port=53u,type_29305_5=\"0x00\",dst=\"192.168.119.17\",type_29305_58=\"0x0000\",in_total_packets=2u,in_total_bytes=158u,src_port=51858u,type_6871_rev_40=\"0x0000\",type_29305_85=\"0x0000014e\" 1684917213506702419\nnetflow,source=127.0.0.1,version=IPFIX type_29305_5=\"0x00\",vlan_src=0u,in_total_bytes=150u,flow_start_ms=1666345521780u,protocol=\"udp\",in_total_packets=2u,dst_port=53u,dst=\"192.168.119.17\",src=\"192.168.119.100\",type_29305_86=\"0x00000002\",src_port=34970u,flow_end_reason=\"forced end\",type_6871_40=\"0x0001\",type_29305_58=\"0x0000\",type_29305_85=\"0x00000158\",type_6871_rev_40=\"0x0000\",src_tos=\"0x00\",flow_end_ms=1666345521794u,type_6871_21=\"0x0000000d\" 1684917213506851241\nnetflow,source=127.0.0.1,version=IPFIX type_29305_58=\"0x0000\",vlan_src=0u,type_29305_5=\"0x00\",dst_port=53u,flow_end_ms=1666345521836u,src_port=52794u,type_6871_40=\"0x0001\",flow_start_ms=1666345521813u,type_6871_rev_40=\"0x0000\",in_total_bytes=144u,in_total_packets=2u,type_6871_21=\"0x00000017\",protocol=\"udp\",flow_end_reason=\"forced end\",src_tos=\"0x00\",type_29305_86=\"0x00000002\",type_29305_85=\"0x00000122\",dst=\"192.168.119.17\",src=\"192.168.119.100\" 1684917213507002733\nnetflow,source=127.0.0.1,version=IPFIX in_total_bytes=142u,in_total_packets=2u,src_port=43629u,src_tos=\"0x00\",dst=\"192.168.119.17\",type_6871_rev_40=\"0x0000\",vlan_src=0u,protocol=\"udp\",type_6871_40=\"0x0001\",type_29305_58=\"0x0000\",dst_port=53u,flow_end_ms=1666345522050u,type_6871_21=\"0x0000000b\",type_29305_5=\"0x00\",src=\"192.168.119.100\",type_29305_86=\"0x00000002\",flow_end_reason=\"forced end\",flow_start_ms=1666345522036u,type_29305_85=\"0x0000013e\" 1684917213507151155\nnetflow,source=127.0.0.1,version=IPFIX src_port=48781u,dst_port=53u,protocol=\"udp\",dst=\"192.168.119.17\",type_29305_85=\"0x00000117\",type_29305_5=\"0x00\",src=\"192.168.119.100\",type_6871_40=\"0x0001\",flow_start_ms=1666345522229u,type_6871_21=\"0x00000000\",type_29305_86=\"0x00000002\",type_6871_rev_40=\"0x0000\",flow_end_reason=\"forced end\",vlan_src=0u,src_tos=\"0x00\",in_total_bytes=132u,flow_end_ms=1666345522240u,in_total_packets=2u,type_29305_58=\"0x0000\" 1684917213507318937\nnetflow,source=127.0.0.1,version=IPFIX src_tos=\"0x00\",type_29305_58=\"0x0000\",in_total_bytes=120u,src_port=43078u,flow_start_ms=1666345522279u,vlan_src=0u,flow_end_ms=1666345522291u,type_29305_5=\"0x00\",type_6871_rev_40=\"0x0000\",dst_port=53u,type_29305_85=\"0x000000c9\",type_6871_21=\"0x00000000\",in_total_packets=2u,type_29305_86=\"0x00000002\",type_6871_40=\"0x0001\",src=\"192.168.119.100\",protocol=\"udp\",flow_end_reason=\"forced end\",dst=\"192.168.119.17\" 1684917213507703742\nnetflow,source=127.0.0.1,version=IPFIX type_29305_58=\"0x0000\",type_29305_86=\"0x00000062\",dst=\"185.199.111.133\",type_6871_rev_40=\"0x0000\",dst_port=443u,flow_start_ms=1666345521806u,vlan_src=0u,type_6871_40=\"0x0000\",type_29305_5=\"0x00\",type_29305_85=\"0x00004b0d\",in_total_bytes=11855u,src_tos=\"0x00\",type_6871_21=\"0x00000008\",in_total_packets=80u,flow_end_ms=1666345525312u,src=\"192.168.119.100\",src_port=49880u,flow_end_reason=\"forced end\",protocol=\"tcp\" 1684917213507860084\nnetflow,source=127.0.0.1,version=IPFIX type_6871_21=\"0x00000066\",type_29305_58=\"0x0000\",type_29305_5=\"0x00\",type_6871_rev_40=\"0x0000\",type_29305_85=\"0x0000161c\",src_tos=\"0x00\",in_total_packets=16u,flow_end_reason=\"forced end\",dst_port=443u,type_29305_86=\"0x0000000f\",flow_end_ms=1666345525417u,src_port=43438u,protocol=\"tcp\",type_6871_40=\"0x0000\",src=\"192.168.119.100\",flow_start_ms=1666345522240u,in_total_bytes=4552u,dst=\"140.82.113.21\",vlan_src=0u 1684917213508012376\nnetflow,source=127.0.0.1,version=IPFIX vlan_src=0u,protocol=\"tcp\",src_tos=\"0x00\",flow_start_ms=1666345522291u,flow_end_ms=1666345525576u,src=\"192.168.119.100\",type_29305_86=\"0x00000032\",in_total_packets=63u,src_port=59884u,dst_port=443u,type_29305_85=\"0x000025ce\",type_29305_58=\"0x0000\",type_29305_5=\"0x00\",dst=\"140.82.121.6\",type_6871_40=\"0x0000\",type_6871_21=\"0x00000009\",in_total_bytes=58028u,flow_end_reason=\"forced end\",type_6871_rev_40=\"0x0000\" 1684917213508167138\nnetflow,source=127.0.0.1,version=IPFIX type_29305_86=\"0x00000009\",flow_end_ms=1666345525645u,protocol=\"tcp\",src_port=443u,type_29305_85=\"0x00000f38\",type_29305_5=\"0x00\",flow_end_reason=\"forced end\",dst_port=49448u,dst=\"192.168.119.100\",in_total_packets=7u,type_6871_rev_40=\"0x0000\",src=\"140.82.113.25\",src_tos=\"0x00\",flow_start_ms=1666345518733u,vlan_src=0u,in_total_bytes=659u,type_6871_21=\"0x00000000\",type_29305_58=\"0x0000\",type_6871_40=\"0x0000\" 1684917213508315850\nnetflow,source=127.0.0.1,version=IPFIX vlan_src=0u,type_29305_85=\"0x00001590\",src=\"192.168.119.100\",protocol=\"udp\",dst_port=443u,type_29305_58=\"0x0000\",type_29305_86=\"0x00000015\",flow_start_ms=1666345514168u,src_tos=\"0x00\",type_6871_rev_40=\"0x0000\",dst=\"142.250.186.170\",in_total_packets=17u,src_port=58246u,type_6871_21=\"0x00000012\",flow_end_ms=1666345525871u,flow_end_reason=\"forced end\",type_29305_5=\"0x00\",type_6871_40=\"0x0000\",in_total_bytes=3248u 1684917213508463452\nnetflow,source=127.0.0.1,version=IPFIX dst=\"140.82.121.3\",flow_start_ms=1666345521019u,type_29305_86=\"0x000000d4\",type_6871_40=\"0x0000\",type_29305_85=\"0x0003e1d9\",in_total_packets=125u,protocol=\"tcp\",flow_end_reason=\"forced end\",in_total_bytes=16640u,type_29305_58=\"0x0000\",flow_end_ms=1666345525880u,type_6871_21=\"0x00000009\",type_29305_5=\"0x00\",dst_port=443u,src_tos=\"0x00\",type_6871_rev_40=\"0x0000\",vlan_src=0u,src=\"192.168.119.100\",src_port=37792u 1684917213508608204\nnetflow,source=127.0.0.1,version=IPFIX type_6871_40=\"0x0001\",src=\"192.168.119.100\",vlan_src=0u,type_6871_rev_40=\"0x0000\",type_29305_58=\"0x0000\",src_port=50077u,flow_end_ms=1666345527739u,type_29305_5=\"0x00\",flow_start_ms=1666345527739u,in_total_packets=2u,src_tos=\"0x00\",flow_end_reason=\"forced end\",type_6871_21=\"0x00000000\",type_29305_86=\"0x00000002\",dst_port=53u,in_total_bytes=120u,type_29305_85=\"0x000000a4\",protocol=\"udp\",dst=\"192.168.119.17\" 1684917213508754156\nnetflow_options,source=127.0.0.1,version=IPFIX dropped_packets_total=0u,event_time=1666725027u,exporter=\"192.168.119.100\",exporting_pid=66602u,ignored_packet_total=22u,in_total_packets=1070u,notsent_packet_total=0u,observation_domain_id=0u,system_init_ms=1666725027000u,total_flows_exported=29u,type_6871_32868=\"0x00000000\",type_6871_32869=\"0x00000000\",type_6871_32870=\"0x00001d1f\",type_6871_32871=\"0x00043278\",type_6871_32872=\"0x00000004\",type_6871_32873=\"0x0000001a\" 1715165599875551764\nnetflow_options,source=127.0.0.1,version=IPFIX event_time=1666725027u,exporting_pid=66602u,observation_domain_id=0u,padding=\"0x000000000000\",type_6871_33318=\"0x00000000\",type_6871_33319=\"0x0000\",type_6871_33322=\"0x00d00500000001635834a3\" 1715165599878686750"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_example/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_options/expected.out",
    "content": "netflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Third Party Connect Protocol\",app_id=\"0x01000022\",app_name=\"3pc\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Active Networks\",app_id=\"0x0100006b\",app_name=\"an\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"any host internal protocol\",app_id=\"0x0100003d\",app_name=\"any-host-internal\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"ARGUS\",app_id=\"0x0100000d\",app_name=\"argus\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"ARIS\",app_id=\"0x01000068\",app_name=\"aris\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"AX.25 Frames\",app_id=\"0x0100005d\",app_name=\"ax25\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"BBN RCC Monitoring\",app_id=\"0x0100000a\",app_name=\"bbnrccmon\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"BNA\",app_id=\"0x01000031\",app_name=\"bna\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Backroom SATNET Monitoring\",app_id=\"0x0100004c\",app_name=\"br-sat-mon\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"CBT\",app_id=\"0x01000007\",app_name=\"cbt\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"CFTP\",app_id=\"0x0100003e\",app_name=\"cftp\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Chaos\",app_id=\"0x01000010\",app_name=\"chaos\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Compaq Peer Protocol\",app_id=\"0x0100006e\",app_name=\"compaq-peer\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Computer Protocol Heart Beat\",app_id=\"0x01000049\",app_name=\"cphb\" 1715165504617351694\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Computer Protocol Network Executive\",app_id=\"0x01000048\",app_name=\"cpnx\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Combat Radio Transport Protocol\",app_id=\"0x0100007e\",app_name=\"crtp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Combat Radio User Datagram\",app_id=\"0x0100007f\",app_name=\"crudp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Datagram Congestion Control Protocol\",app_id=\"0x01000021\",app_name=\"dccp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DCN Measurement Subsystems\",app_id=\"0x01000013\",app_name=\"dcn-meas\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Datagram Delivery Protocol\",app_id=\"0x01000025\",app_name=\"ddp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"D-II Data Exchange\",app_id=\"0x01000074\",app_name=\"ddx\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Dissimilar Gateway Protocol\",app_id=\"0x01000056\",app_name=\"dgp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Dynamic Source Routing Protocol\",app_id=\"0x01000030\",app_name=\"dsr\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Exterior Gateway Protocol\",app_id=\"0x01000008\",app_name=\"egp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Enhanced Interior Gateway Routing Protocol\",app_id=\"0x01000058\",app_name=\"eigrp\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"EMCON\",app_id=\"0x0100000e\",app_name=\"emcon\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Encapsulation Header\",app_id=\"0x01000062\",app_name=\"encap\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Ethernet-within-IP Encapsulation\",app_id=\"0x01000061\",app_name=\"etherip\" 1715165504617776018\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Fibre Channel\",app_id=\"0x01000085\",app_name=\"fc\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"FIRE\",app_id=\"0x0100007d\",app_name=\"fire\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Gateway-to-Gateway\",app_id=\"0x01000003\",app_name=\"ggp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"graphical Media Transfer Protocol \",app_id=\"0x01000064\",app_name=\"gmtp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"General Routing Encapsulation\",app_id=\"0x0100002f\",app_name=\"gre\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Host Identity Protocol\",app_id=\"0x0100008b\",app_name=\"hip\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Host Monitoring\",app_id=\"0x01000014\",app_name=\"hmp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DEPRECATED, traffic will not match\",app_id=\"0x01000000\",app_name=\"hopopt\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Integrated Net Layer Security TUBA\",app_id=\"0x01000034\",app_name=\"i-nlsp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Interactive Agent Transfer Protocol\",app_id=\"0x01000075\",app_name=\"iatp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Internet Control Message Protocol\",app_id=\"0x01000001\",app_name=\"icmp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Inter-Domain Policy Routing Protocol\",app_id=\"0x01000023\",app_name=\"idpr\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IDPR Control Message Transport Proto\",app_id=\"0x01000026\",app_name=\"idpr-cmtp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Inter-Domain Routing Protocol\",app_id=\"0x0100002d\",app_name=\"idrp\" 1715165504618074830\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Ipsilon Flow Management Protocol\",app_id=\"0x01000065\",app_name=\"ifmp\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Cisco interior gateway \",app_id=\"0x01000009\",app_name=\"igrp\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IL Transport Protocol\",app_id=\"0x01000028\",app_name=\"il\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IP Payload Compression Protocol\",app_id=\"0x0100006c\",app_name=\"ipcomp\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Internet Packet Core Utility\",app_id=\"0x01000047\",app_name=\"ipcv\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IP in IP\",app_id=\"0x01000004\",app_name=\"ipinip\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IP-within-IP Encapsulation Protocol\",app_id=\"0x0100005e\",app_name=\"ipip\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IPLT\",app_id=\"0x01000081\",app_name=\"iplt\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Internet Pluribus Packet Core\",app_id=\"0x01000043\",app_name=\"ippc\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DEPRECATED, traffic will not match\",app_id=\"0x0100002c\",app_name=\"ipv6-frag\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"ICMP for IPv6\",app_id=\"0x0100003a\",app_name=\"ipv6-icmp\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DEPRECATED, traffic will not match\",app_id=\"0x0100003b\",app_name=\"ipv6-nonxt\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DEPRECATED, traffic will not match\",app_id=\"0x0100003c\",app_name=\"ipv6-opts\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"DEPRECATED, traffic will not match\",app_id=\"0x0100002b\",app_name=\"ipv6-route\" 1715165504618379393\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Ipv6 encapsulated\",app_id=\"0x01000029\",app_name=\"ipv6inip\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IPX in IP\",app_id=\"0x0100006f\",app_name=\"ipx-in-ip\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Internet Reliable Transaction\",app_id=\"0x0100001c\",app_name=\"irtp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Intermediate System-to-Intermediate System (ISIS) over \",app_id=\"0x0100007c\",app_name=\"isis\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"ISO Transport Protocol Class 4\",app_id=\"0x0100001d\",app_name=\"iso-tp4\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Layer 2 Tunneling Protocol\",app_id=\"0x01000073\",app_name=\"l2tp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Locus Address Resolution Protocol\",app_id=\"0x0100005b\",app_name=\"larp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Leaf-1\",app_id=\"0x01000019\",app_name=\"leaf-1\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Leaf-2\",app_id=\"0x0100001a\",app_name=\"leaf-2\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"MANET Protocols\",app_id=\"0x0100008a\",app_name=\"manet\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"MERIT Internodal Protocol\",app_id=\"0x01000020\",app_name=\"merit-inp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"MFE Network Services Protocol\",app_id=\"0x0100001f\",app_name=\"mfe-nsp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Mobile Internetworking Control Pro.\",app_id=\"0x0100005f\",app_name=\"micp\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IP Mobility\",app_id=\"0x01000037\",app_name=\"mobile\" 1715165504618664785\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"MPLS-in-IP\",app_id=\"0x01000089\",app_name=\"mpls-in-ip\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Multicast Transport Protocol\",app_id=\"0x0100005c\",app_name=\"mtp\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Multiplexing\",app_id=\"0x01000012\",app_name=\"mux\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"NBMA Address Resolution Protocol\",app_id=\"0x01000036\",app_name=\"narp\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Bulk Data Transfer Protocol\",app_id=\"0x0100001e\",app_name=\"netblt\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"NSFNET-IGP\",app_id=\"0x01000055\",app_name=\"nsfnet-igp\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Network Voice Protocol\",app_id=\"0x0100000b\",app_name=\"nvp-ii\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Open Shortest Path First\",app_id=\"0x01000059\",app_name=\"ospf\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"PGM Reliable Transport Protocol\",app_id=\"0x01000071\",app_name=\"pgm\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Protocol Independent Multicast\",app_id=\"0x01000067\",app_name=\"pim\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Private IP Encapsulation within IP\",app_id=\"0x01000083\",app_name=\"pipe\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"PNNI over IP\",app_id=\"0x01000066\",app_name=\"pnni\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Packet Radio Measurement\",app_id=\"0x01000015\",app_name=\"prm\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Performance Transparency Protocol\",app_id=\"0x0100007b\",app_name=\"ptp\" 1715165504618966128\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"PUP\",app_id=\"0x0100000c\",app_name=\"pup\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Packet Video Protocol\",app_id=\"0x0100004b\",app_name=\"pvp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"QNX\",app_id=\"0x0100006a\",app_name=\"qnx\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Reliable Data Protocol\",app_id=\"0x0100001b\",app_name=\"rdp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Resource Reservation Protocol\",app_id=\"0x0100002e\",app_name=\"rsvp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"RSVP-E2E-IGNORE\",app_id=\"0x01000086\",app_name=\"rsvp-e2e-ignore\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"MIT Remote Virtual Disk Protocol\",app_id=\"0x01000042\",app_name=\"rvd\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SATNET and Backroom EXPAK\",app_id=\"0x01000040\",app_name=\"sat-expak\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SATNET Monitoring\",app_id=\"0x01000045\",app_name=\"sat-mon\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Semaphore Communications Sec. Pro.\",app_id=\"0x01000060\",app_name=\"scc-sp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Schedule Transfer Protocol\",app_id=\"0x01000076\",app_name=\"schedule-transfer\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SCPS\",app_id=\"0x01000069\",app_name=\"scps\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Stream Control Transmission Protocol\",app_id=\"0x01000084\",app_name=\"sctp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Source Demand Routing Protocol\",app_id=\"0x0100002a\",app_name=\"sdrp\" 1715165504619268091\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SECURE-VMTP\",app_id=\"0x01000052\",app_name=\"secure-vmtp\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SKIP\",app_id=\"0x01000039\",app_name=\"skip\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SM\",app_id=\"0x0100007a\",app_name=\"sm\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Simple Message Protocol\",app_id=\"0x01000079\",app_name=\"smp\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Sitara Networks Protocol\",app_id=\"0x0100006d\",app_name=\"snp\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Sprite RPC Protocol\",app_id=\"0x0100005a\",app_name=\"sprite-rpc\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Secure Packet Shield\",app_id=\"0x01000082\",app_name=\"sps\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SpectraLink Radio Protocol\",app_id=\"0x01000077\",app_name=\"srp\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SSCOPMCE\",app_id=\"0x01000080\",app_name=\"sscopmce\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Stream\",app_id=\"0x01000005\",app_name=\"st\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"SUN ND PROTOCOL-Temporary\",app_id=\"0x0100004d\",app_name=\"sun-nd\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"IP with Encryption\",app_id=\"0x01000035\",app_name=\"swipe\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"TCF\",app_id=\"0x01000057\",app_name=\"tcf\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Transport Layer Security Protocol\",app_id=\"0x01000038\",app_name=\"tlsp\" 1715165504619574503\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"TP++ Transport Protocol\",app_id=\"0x01000027\",app_name=\"tp++\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Trunk-1\",app_id=\"0x01000017\",app_name=\"trunk-1\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Trunk-2\",app_id=\"0x01000018\",app_name=\"trunk-2\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"TTP\",app_id=\"0x01000054\",app_name=\"ttp\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"UDPLite, Lightweight connectionless User Datagram Proto\",app_id=\"0x01000088\",app_name=\"udplite\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"UTI\",app_id=\"0x01000078\",app_name=\"uti\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"VISA Protocol\",app_id=\"0x01000046\",app_name=\"visa\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"VMTP\",app_id=\"0x01000051\",app_name=\"vmtp\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Virtual Router Redundancy Protocol\",app_id=\"0x01000070\",app_name=\"vrrp\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"WIDEBAND EXPAK\",app_id=\"0x0100004f\",app_name=\"wb-expak\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"WIDEBAND Monitoring\",app_id=\"0x0100004e\",app_name=\"wb-mon\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Wang Span Network\",app_id=\"0x0100004a\",app_name=\"wsn\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"Cross Net Debugger\",app_id=\"0x0100000f\",app_name=\"xnet\" 1715165504619894286\nnetflow_options,source=127.0.0.1,version=IPFIX app_desc=\"XEROX NS IDP\",app_id=\"0x01000016\",app_name=\"xns-idp\" 1715165504619894286"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_options/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_pen_35632/expected.out",
    "content": "netflow,source=127.0.0.1,version=IPFIX app_latency_ms=0u,flow_end_ms=1684767922502u,ssl_unsafe_cipher=0u,src_mask=0u,dst_port=44400u,in_src_mac=\"00:50:56:b3:86:e7\",src_tos=\"0x00\",ja3c_hash=\"\",server_nw_latency_ms=0u,l7_proto=37u,last_switched=22474460u,tcp_flags=\"........\",ja3s_hash=\"\",in_snmp=0u,flow_start_ms=1684767922502u,ssl_version=0u,client_nw_latency_ms=0u,out_dst_mac=\"00:50:56:b3:a7:f8\",src=\"192.168.2.203\",dst_mask=0u,next_hop=\"0.0.0.0\",flow_end=1684767922u,ssl_cipher=0u,src_port=51413u,dst_tos=\"0x00\",ip_version=\"IPv4\",retransmitted_out_bytes=0u,in_bytes=122u,out_snmp=0u,protocol=\"udp\",first_switched=22474460u,retransmitted_in_pkts=0u,dst=\"189.127.188.175\",retransmitted_in_bytes=0u,flow_start=1684767922u,ssl_server_name=\"\",retransmitted_out_pkts=0u,in_packets=1u 1684928292858572674\nnetflow,source=127.0.0.1,version=IPFIX app_latency_ms=0u,out_dst_mac=\"00:50:56:b3:a7:f8\",protocol=\"udp\",ja3c_hash=\"\",ssl_unsafe_cipher=0u,dst_mask=0u,retransmitted_in_pkts=0u,out_snmp=0u,flow_start_ms=1684767922502u,ssl_cipher=0u,l7_proto=37u,in_snmp=0u,retransmitted_in_bytes=0u,src_tos=\"0x00\",last_switched=22474460u,ssl_version=0u,in_packets=1u,first_switched=22474460u,flow_end=1684767922u,src=\"192.168.2.203\",retransmitted_out_pkts=0u,src_port=51413u,client_nw_latency_ms=0u,next_hop=\"0.0.0.0\",dst=\"177.234.165.79\",server_nw_latency_ms=0u,tcp_flags=\"........\",flow_start=1684767922u,src_mask=0u,dst_port=47707u,ssl_server_name=\"\",ip_version=\"IPv4\",retransmitted_out_bytes=0u,dst_tos=\"0x00\",in_bytes=86u,flow_end_ms=1684767922502u,ja3s_hash=\"\",in_src_mac=\"00:50:56:b3:86:e7\" 1684928292858831665\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/ipfix_pen_35632/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n  private_enterprise_number_files = [\"mappings_ipfix_pen/ntop-35632.csv\"]\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/issue_13305/expected.out",
    "content": "netflow,source=127.0.0.1,version=IPFIX ip_version=\"IPv4\",dst_port=44400u,dst_tos=\"0x00\",flow_end_ms=1684767922502u,type_35632_127=\"0x00000000\",flow_start=1684767922u,src=\"192.168.2.203\",flow_end=1684767922u,type_35632_493=\"0x0000\",first_switched=22474460u,type_35632_188=\"\",protocol=\"udp\",in_src_mac=\"00:50:56:b3:86:e7\",type_35632_128=\"0x00000000\",in_snmp=0u,src_mask=0u,out_snmp=0u,type_35632_124=\"0x00000000\",type_35632_494=\"0x00\",in_bytes=122u,type_35632_110=\"0x00000000\",out_dst_mac=\"00:50:56:b3:a7:f8\",type_35632_490=\"\",dst_mask=0u,type_35632_495=\"0x0000\",last_switched=22474460u,in_packets=1u,type_35632_123=\"0x00000000\",dst=\"189.127.188.175\",src_tos=\"0x00\",type_35632_118=\"0x0025\",type_35632_125=\"0x00000000\",next_hop=\"0.0.0.0\",src_port=51413u,tcp_flags=\"........\",flow_start_ms=1684767922502u,type_35632_489=\"\",type_35632_109=\"0x00000000\" 1684848566299341667\nnetflow,source=127.0.0.1,version=IPFIX src_mask=0u,out_snmp=0u,type_35632_188=\"\",type_35632_118=\"0x0025\",type_35632_109=\"0x00000000\",type_35632_124=\"0x00000000\",in_packets=1u,dst=\"177.234.165.79\",dst_port=47707u,type_35632_125=\"0x00000000\",tcp_flags=\"........\",flow_end=1684767922u,type_35632_128=\"0x00000000\",protocol=\"udp\",type_35632_490=\"\",dst_mask=0u,last_switched=22474460u,flow_end_ms=1684767922502u,type_35632_489=\"\",in_bytes=86u,type_35632_123=\"0x00000000\",next_hop=\"0.0.0.0\",ip_version=\"IPv4\",src_port=51413u,dst_tos=\"0x00\",type_35632_494=\"0x00\",src=\"192.168.2.203\",type_35632_127=\"0x00000000\",flow_start_ms=1684767922502u,type_35632_493=\"0x0000\",in_src_mac=\"00:50:56:b3:86:e7\",flow_start=1684767922u,first_switched=22474460u,out_dst_mac=\"00:50:56:b3:a7:f8\",src_tos=\"0x00\",type_35632_110=\"0x00000000\",type_35632_495=\"0x0000\",in_snmp=0u 1684848566299737019\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/issue_13305/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/issue_14370/expected.out",
    "content": "netflow,source=127.0.0.1,version=IPFIX bgp_dst_as=2152u,bgp_src_as=65535u,direction=\"ingress\",dst=\"101.104.199.17\",dst_port=50202u,flow_end=0u,flow_start=0u,flows=1u,in_bytes=256u,in_packets=1u,in_snmp=101u,out_snmp=201u,protocol=\"tcp\",src=\"0.0.0.0\",src_port=443u 1701440347872006922\nnetflow,source=127.0.0.1,version=IPFIX bgp_dst_as=2152u,bgp_src_as=65535u,direction=\"ingress\",dst=\"2001:db8:0:1::1\",dst_port=50202u,flow_end=0u,flow_start=0u,flows=1u,in_bytes=256u,in_packets=1u,in_snmp=101u,out_snmp=201u,protocol=\"tcp\",src=\"::6568:c711:0:0:6568:c711\",src_port=443u 1701440347872025552"
  },
  {
    "path": "plugins/inputs/netflow/testcases/issue_14370/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_mapping.csv",
    "content": "58500,protocol_ntop,string\n58503,l4_src_port_name,string\n58507,l4_dst_port_name,string\n58508,l4_srv_port,uint\n58509,l4_srv_port_name,string\n57552,src_fragments,uint\n57553,dst_fragments,uint\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v5_example/expected.out",
    "content": "netflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.121.3\",src_port=443u,dst=\"192.168.119.100\",dst_port=55516u,flows=8u,in_bytes=87477u,in_packets=78u,first_switched=86400660u,last_switched=86403316u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.121.6\",src_port=443u,dst=\"192.168.119.100\",dst_port=36408u,flows=8u,in_bytes=5009u,in_packets=21u,first_switched=86400447u,last_switched=86403267u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.112.22\",src_port=443u,dst=\"192.168.119.100\",dst_port=39638u,flows=8u,in_bytes=925u,in_packets=6u,first_switched=86400324u,last_switched=86403214u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"140.82.114.26\",src_port=443u,dst=\"192.168.119.100\",dst_port=49398u,flows=8u,in_bytes=250u,in_packets=2u,first_switched=86403131u,last_switched=86403362u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=55516u,dst=\"140.82.121.3\",dst_port=443u,flows=8u,in_bytes=4969u,in_packets=37u,first_switched=86400652u,last_switched=86403269u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=36408u,dst=\"140.82.121.6\",dst_port=443u,flows=8u,in_bytes=2736u,in_packets=21u,first_switched=86400438u,last_switched=86403258u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=39638u,dst=\"140.82.112.22\",dst_port=443u,flows=8u,in_bytes=1560u,in_packets=6u,first_switched=86400225u,last_switched=86403255u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u\nnetflow,source=127.0.0.1,version=NetFlowV5 protocol=\"tcp\",src=\"192.168.119.100\",src_port=49398u,dst=\"140.82.114.26\",dst_port=443u,flows=8u,in_bytes=697u,in_packets=4u,first_switched=86403030u,last_switched=86403362u,tcp_flags=\"...AP...\",engine_type=\"19\",engine_id=\"0x56\",sys_uptime=90003000u,src_tos=\"0x00\",bgp_src_as=0u,bgp_dst_as=0u,src_mask=0u,dst_mask=0u,in_snmp=0u,out_snmp=0u,next_hop=\"0.0.0.0\",seq_number=0u,sampling_interval=0u"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v5_example/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n  protocol = \"netflow v5\""
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v9_example/expected.out",
    "content": "netflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.121.3\",src_port=443u,dst=\"192.168.119.100\",dst_port=55516u,in_bytes=87477u,in_packets=78u,flow_start_ms=1666350478660u,flow_end_ms=1666350481316u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.121.6\",src_port=443u,dst=\"192.168.119.100\",dst_port=36408u,in_bytes=5009u,in_packets=21u,flow_start_ms=1666350478447u,flow_end_ms=1666350481267u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.112.22\",src_port=443u,dst=\"192.168.119.100\",dst_port=39638u,in_bytes=925u,in_packets=6u,flow_start_ms=1666350478324u,flow_end_ms=1666350481214u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"140.82.114.26\",src_port=443u,dst=\"192.168.119.100\",dst_port=49398u,in_bytes=250u,in_packets=2u,flow_start_ms=1666350481131u,flow_end_ms=1666350481362u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=55516u,dst=\"140.82.121.3\",dst_port=443u,in_bytes=4969u,in_packets=37u,flow_start_ms=1666350478652u,flow_end_ms=1666350481269u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=36408u,dst=\"140.82.121.6\",dst_port=443u,in_bytes=2736u,in_packets=21u,flow_start_ms=1666350478438u,flow_end_ms=1666350481258u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=39638u,dst=\"140.82.112.22\",dst_port=443u,in_bytes=1560u,in_packets=6u,flow_start_ms=1666350478225u,flow_end_ms=1666350481255u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\nnetflow,source=127.0.0.1,version=NetFlowV9 protocol=\"tcp\",src=\"192.168.119.100\",src_port=49398u,dst=\"140.82.114.26\",dst_port=443u,in_bytes=697u,in_packets=4u,flow_start_ms=1666350481030u,flow_end_ms=1666350481362u,tcp_flags=\"...AP...\",engine_type=\"17\",engine_id=\"0x01\",icmp_type=0u,icmp_code=0u,fwd_status=\"unknown\",fwd_reason=\"unknown\",src_tos=\"0x00\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v9_example/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v9_options/expected.out",
    "content": "netflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=1u,interface=\"Te0/0/0\",interface_desc=\"TenGigabitEthernet0/0/0\",out_snmp=1u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=2u,interface=\"Te0/0/1\",interface_desc=\"TenGigabitEthernet0/0/1\",out_snmp=2u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=3u,interface=\"Te0/0/2\",interface_desc=\"TenGigabitEthernet0/0/2\",out_snmp=3u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=4u,interface=\"Te0/0/3\",interface_desc=\"TenGigabitEthernet0/0/3\",out_snmp=4u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=5u,interface=\"Te0/0/4\",interface_desc=\"TenGigabitEthernet0/0/4\",out_snmp=5u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=6u,interface=\"Te0/0/5\",interface_desc=\"TenGigabitEthernet0/0/5\",out_snmp=6u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=7u,interface=\"Gi0\",interface_desc=\"GigabitEthernet0\",out_snmp=7u 1713379378304536264\nnetflow_options,source=127.0.0.1,version=NetFlowV9 in_bytes=169952189u,in_snmp=10u,interface=\"Lo0\",interface_desc=\"Loopback0\",out_snmp=10u 1713379378304536264\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/netflow_v9_options/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_issue_15375/expected.out",
    "content": "netflow,source=127.0.0.1,version=sFlowV5 sys_uptime=12414u,agent_ip=\"192.168.119.184\",agent_subid=100000u,seq_number=2u,direction=\"ingress\",in_snmp=1u,out_snmp=2u,out_queue=42u,reason=1u,sampling_drops=256u,ip_version=\"IPv4\" 12414000000\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_issue_15375/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n  protocol = \"sflow v5\""
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_issue_15918/expected.out",
    "content": "netflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,in_broadcast_packets_total=2502106u,in_bytes=21286022420858u,in_dropped_packets=0u,in_errors=0u,in_mcast_packets_total=81495048u,in_snmp=101u,in_unicast_packets_total=1153749508u,in_unknown_protocol=0u,interface=101u,interface_type=6u,ip_version=\"IPv4\",out_broadcast_packets_total=1251275u,out_bytes=8929238553590u,out_dropped_packets=0u,out_errors=0u,out_mcast_packets_total=3753944u,out_unicast_packets_total=3892490465u,promiscuous=0u,seq_number=300415u,speed=1000000000u,status=\"up\",sys_uptime=2042523538u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv4\",direction=\"ingress\",dst=\"192.168.101.2\",dst_port=2055u,fragment_flags=\"........\",fragment_offset=0u,in_snmp=96u,in_src_mac=\"00:09:0f:09:00:01\",in_total_packets=687103949u,ip_total_len=1248u,ip_version=\"IPv4\",ipv4_id=49746u,ipv4_inet_header_len=5u,ipv4_total_len=1268u,l2_bytes=1286u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"48:21:0b:3b:76:59\",out_snmp=95u,protocol=\"udp\",sampling_drops=8731u,sampling_interval=200u,seq_number=2404916u,src=\"192.168.227.2\",src_port=49469u,src_tos=0u,sys_uptime=2042523538u,ttl=63u,vlan_dst=154u,vlan_dst_priority=0u,vlan_src=154u,vlan_src_priority=0u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv4\",direction=\"egress\",dst=\"192.168.100.104\",dst_port=52851u,fragment_flags=\"......D.\",fragment_offset=0u,in_snmp=60u,in_src_mac=\"dc:2c:6e:b9:1a:c6\",in_total_packets=804503573u,ip_total_len=525u,ip_version=\"IPv4\",ipv4_id=0u,ipv4_inet_header_len=5u,ipv4_total_len=545u,l2_bytes=563u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"00:09:0f:09:00:00\",out_snmp=60u,protocol=\"udp\",sampling_drops=14255907u,sampling_interval=200u,seq_number=20451226u,src=\"142.250.200.99\",src_port=443u,src_tos=0u,sys_uptime=2042523538u,ttl=51u,vlan_dst=250u,vlan_dst_priority=0u,vlan_src=250u,vlan_src_priority=4294967295u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv6\",direction=\"egress\",dst=\"ff02::16\",in_snmp=76u,in_src_mac=\"00:e0:4c:68:00:5c\",in_total_packets=1062946518u,ip_total_len=56u,ip_version=\"IPv6\",ipv6_total_len=56u,l2_bytes=114u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"33:33:00:00:00:16\",protocol=\"hopopt\",sampling_drops=30750u,sampling_interval=200u,seq_number=899357u,src=\"fe80::f3a8:9738:cab4:2286\",sys_uptime=2042523538u,ttl=1u,vlan_dst=153u,vlan_dst_priority=0u,vlan_src=153u,vlan_src_priority=4294967295u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv4\",direction=\"egress\",dst=\"142.250.185.14\",dst_port=443u,fragment_flags=\"......D.\",fragment_offset=0u,in_snmp=101u,in_src_mac=\"00:09:0f:09:00:00\",in_total_packets=840275157u,ip_total_len=39u,ip_version=\"IPv4\",ipv4_id=40468u,ipv4_inet_header_len=5u,ipv4_total_len=59u,l2_bytes=77u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"00:00:5e:00:01:7b\",out_snmp=101u,protocol=\"udp\",sampling_drops=14100530u,sampling_interval=200u,seq_number=20640786u,src=\"192.168.153.106\",src_port=64969u,src_tos=0u,sys_uptime=2042523538u,ttl=127u,vlan_dst=250u,vlan_dst_priority=0u,vlan_src=250u,vlan_src_priority=4294967295u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv4\",direction=\"ingress\",dst=\"192.168.153.106\",dst_port=64969u,fragment_flags=\"......D.\",fragment_offset=0u,in_snmp=6u,in_src_mac=\"00:09:0f:09:00:08\",in_total_packets=774315870u,ip_total_len=681u,ip_version=\"IPv4\",ipv4_id=0u,ipv4_inet_header_len=5u,ipv4_total_len=701u,l2_bytes=719u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"7c:8a:e1:be:20:52\",out_snmp=97u,protocol=\"udp\",sampling_drops=2262938u,sampling_interval=200u,seq_number=17418932u,src=\"142.250.185.14\",src_port=443u,src_tos=0u,sys_uptime=2042523538u,ttl=50u,vlan_dst=153u,vlan_dst_priority=0u,vlan_src=153u,vlan_src_priority=0u 1728660319352704090\nnetflow,source=127.0.0.1,version=sFlowV5 agent_ip=\"192.168.227.2\",agent_subid=0u,datalink_frame_type=\"IPv6\",direction=\"egress\",dst=\"ff02::1:3\",dst_port=5355u,in_snmp=72u,in_src_mac=\"00:e0:4c:68:00:5c\",in_total_packets=1172072178u,ip_total_len=35u,ip_version=\"IPv6\",ipv6_total_len=35u,l2_bytes=93u,l2_protocol=\"ETHERNET-ISO8023\",out_dst_mac=\"33:33:00:01:00:03\",protocol=\"udp\",sampling_drops=27512u,sampling_interval=200u,seq_number=704213u,src=\"fe80::f3a8:9738:cab4:2286\",src_port=49770u,sys_uptime=2042523538u,ttl=1u,vlan_dst=153u,vlan_dst_priority=0u,vlan_src=153u,vlan_src_priority=4294967295u 1728660319352704090\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_issue_15918/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n  protocol = \"sflow v5\""
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_v5_example/expected.out",
    "content": "netflow,source=127.0.0.1,version=sFlowV5 sys_uptime=12414u,agent_ip=\"192.168.119.184\",agent_subid=100000u,seq_number=2u,in_snmp=3u,port_name=\"eno1\",ip_version=\"IPv4\" 12414000000\n"
  },
  {
    "path": "plugins/inputs/netflow/testcases/sflow_v5_example/telegraf.conf",
    "content": "[[inputs.netflow]]\n  service_address = \"udp://127.0.0.1:0\"\n  protocol = \"sflow v5\""
  },
  {
    "path": "plugins/inputs/netflow/type_conversion.go",
    "content": "package netflow\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"encoding/csv\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// From https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml\n//\n//go:embed layer4_protocol_numbers.csv\nvar l4ProtoFile []byte\n\n// From https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml\n//\n//go:embed ipv4_options.csv\nvar ip4OptionFile []byte\n\nvar l4ProtoMapping map[uint8]string\nvar ipv4OptionMapping []string\n\nfunc initL4ProtoMapping() error {\n\tbuf := bytes.NewBuffer(l4ProtoFile)\n\treader := csv.NewReader(buf)\n\trecords, err := reader.ReadAll()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(records) < 2 {\n\t\treturn errors.New(\"empty file\")\n\t}\n\n\tl4ProtoMapping = make(map[uint8]string)\n\tfor _, r := range records[1:] {\n\t\tif len(r) != 2 {\n\t\t\treturn fmt.Errorf(\"invalid record: %v\", r)\n\t\t}\n\t\tname := strings.ToLower(r[1])\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tid, err := strconv.ParseUint(r[0], 10, 8)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %v\", err, r)\n\t\t}\n\t\tl4ProtoMapping[uint8(id)] = name\n\t}\n\n\treturn nil\n}\n\nfunc initIPv4OptionMapping() error {\n\tbuf := bytes.NewBuffer(ip4OptionFile)\n\treader := csv.NewReader(buf)\n\trecords, err := reader.ReadAll()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(records) < 2 {\n\t\treturn errors.New(\"empty file\")\n\t}\n\n\tipv4OptionMapping = make([]string, 32)\n\tfor _, r := range records[1:] {\n\t\tif len(r) != 2 {\n\t\t\treturn fmt.Errorf(\"invalid record: %v\", r)\n\t\t}\n\t\tidx, err := strconv.ParseUint(r[0], 10, 8)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %v\", err, r)\n\t\t}\n\t\tipv4OptionMapping[idx] = r[1]\n\t}\n\n\treturn nil\n}\n\nfunc decodeInt(b []byte) (interface{}, error) {\n\tswitch len(b) {\n\tcase 0:\n\t\treturn int64(0), nil\n\tcase 1:\n\t\treturn int64(int8(b[0])), nil\n\tcase 2:\n\t\treturn int64(int16(binary.BigEndian.Uint16(b))), nil\n\tcase 4:\n\t\treturn int64(int32(binary.BigEndian.Uint32(b))), nil\n\tcase 8:\n\t\treturn int64(binary.BigEndian.Uint64(b)), nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid length for int buffer %v\", b)\n}\n\nfunc decodeUint(b []byte) (interface{}, error) {\n\tswitch len(b) {\n\tcase 0:\n\t\treturn uint64(0), nil\n\tcase 1:\n\t\treturn uint64(b[0]), nil\n\tcase 2:\n\t\treturn uint64(binary.BigEndian.Uint16(b)), nil\n\tcase 4:\n\t\treturn uint64(binary.BigEndian.Uint32(b)), nil\n\tcase 8:\n\t\treturn binary.BigEndian.Uint64(b), nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid length for uint buffer %v\", b)\n}\n\nfunc decodeFloat32(b []byte) (interface{}, error) {\n\traw := binary.BigEndian.Uint32(b)\n\treturn math.Float32frombits(raw), nil\n}\n\nfunc decodeFloat64(b []byte) (interface{}, error) {\n\traw := binary.BigEndian.Uint64(b)\n\treturn math.Float64frombits(raw), nil\n}\n\n// According to https://www.rfc-editor.org/rfc/rfc5101#section-6.1.5\nfunc decodeBool(b []byte) (interface{}, error) {\n\tif len(b) == 0 {\n\t\treturn nil, errors.New(\"empty data\")\n\t}\n\tif b[0] == 1 {\n\t\treturn true, nil\n\t}\n\tif b[0] == 2 {\n\t\treturn false, nil\n\t}\n\treturn b[0], nil\n}\n\nfunc decodeHex(b []byte) (interface{}, error) {\n\tif len(b) == 0 {\n\t\treturn \"\", nil\n\t}\n\treturn \"0x\" + hex.EncodeToString(b), nil\n}\n\nfunc decodeString(b []byte) (interface{}, error) {\n\treturn strings.TrimRight(string(b), \"\\x00\"), nil\n}\n\nfunc decodeMAC(b []byte) (interface{}, error) {\n\tmac := net.HardwareAddr(b)\n\treturn mac.String(), nil\n}\n\nfunc decodeIP(b []byte) (interface{}, error) {\n\tip := net.IP(b)\n\treturn ip.String(), nil\n}\n\nfunc decodeIPFromUint32(a uint32) (interface{}, error) {\n\tb := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(b, a)\n\treturn decodeIP(b)\n}\n\nfunc decodeL4Proto(b []byte) (interface{}, error) {\n\treturn mapL4Proto(b[0]), nil\n}\n\nfunc mapL4Proto(id uint8) string {\n\tname, found := l4ProtoMapping[id]\n\tif found {\n\t\treturn name\n\t}\n\treturn strconv.FormatUint(uint64(id), 10)\n}\n\nfunc decodeIPv4Options(b []byte) (interface{}, error) {\n\tflags := binary.BigEndian.Uint32(b)\n\n\tvar result []string\n\tfor i := 0; i < 32; i++ {\n\t\tname := ipv4OptionMapping[i]\n\t\tif name == \"\" {\n\t\t\tname = fmt.Sprintf(\"UA%d\", i)\n\t\t}\n\t\tif (flags>>i)&0x01 != 0 {\n\t\t\tresult = append(result, name)\n\t\t}\n\t}\n\n\treturn strings.Join(result, \",\"), nil\n}\n\nfunc decodeTCPFlags(b []byte) (interface{}, error) {\n\tif len(b) == 0 {\n\t\treturn \"\", nil\n\t}\n\n\tif len(b) == 1 {\n\t\treturn mapTCPFlags(b[0]), nil\n\t}\n\n\t// IPFIX has more flags\n\tresults := make([]string, 0, 8)\n\tfor i := 7; i >= 0; i-- {\n\t\tif (b[0]>>i)&0x01 != 0 {\n\t\t\t// Currently all flags are reserved so denote the bit set\n\t\t\tresults = append(results, \"*\")\n\t\t} else {\n\t\t\tresults = append(results, \".\")\n\t\t}\n\t}\n\n\t//nolint:gosec // False positive (b[1] is not out of range - it is ensured by above checks)\n\treturn strings.Join(results, \"\") + mapTCPFlags(b[1]), nil\n}\n\nfunc mapTCPFlags(flags uint8) string {\n\tflagMapping := []string{\n\t\t\"F\", // FIN\n\t\t\"S\", // SYN\n\t\t\"R\", // RST\n\t\t\"P\", // PSH\n\t\t\"A\", // ACK\n\t\t\"U\", // URG\n\t\t\"E\", // ECE\n\t\t\"C\", // CWR\n\t}\n\n\tresult := make([]string, 0, 8)\n\n\tfor i := 7; i >= 0; i-- {\n\t\tif (flags>>i)&0x01 != 0 {\n\t\t\tresult = append(result, flagMapping[i])\n\t\t} else {\n\t\t\tresult = append(result, \".\")\n\t\t}\n\t}\n\n\treturn strings.Join(result, \"\")\n}\n\nfunc decodeFragmentFlags(b []byte) (interface{}, error) {\n\tflagMapping := []string{\n\t\t\"*\", // do not care\n\t\t\"*\", // do not care\n\t\t\"*\", // do not care\n\t\t\"*\", // do not care\n\t\t\"*\", // do not care\n\t\t\"M\", // MF -- more fragments\n\t\t\"D\", // DF -- don't fragment\n\t\t\"R\", // RS -- reserved\n\t}\n\n\tflags := b[0]\n\tresult := make([]string, 0, 8)\n\tfor i := 7; i >= 0; i-- {\n\t\tif (flags>>i)&0x01 != 0 {\n\t\t\tresult = append(result, flagMapping[i])\n\t\t} else {\n\t\t\tresult = append(result, \".\")\n\t\t}\n\t}\n\n\treturn strings.Join(result, \"\"), nil\n}\n\nfunc decodeSampleAlgo(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 1:\n\t\treturn \"deterministic\", nil\n\tcase 2:\n\t\treturn \"random\", nil\n\t}\n\treturn strconv.FormatUint(uint64(b[0]), 10), nil\n}\n\nfunc decodeEngineType(b []byte) (interface{}, error) {\n\treturn mapEngineType(b[0]), nil\n}\n\nfunc mapEngineType(b uint8) string {\n\tswitch b {\n\tcase 0:\n\t\treturn \"RP\"\n\tcase 1:\n\t\treturn \"VIP/linecard\"\n\tcase 2:\n\t\treturn \"PFC/DFC\"\n\t}\n\treturn strconv.FormatUint(uint64(b), 10)\n}\n\nfunc decodeMPLSType(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"unknown\", nil\n\tcase 1:\n\t\treturn \"TE-MIDPT\", nil\n\tcase 2:\n\t\treturn \"Pseudowire\", nil\n\tcase 3:\n\t\treturn \"VPN\", nil\n\tcase 4:\n\t\treturn \"BGP\", nil\n\tcase 5:\n\t\treturn \"LDP\", nil\n\tcase 6:\n\t\treturn \"Path computation element\", nil\n\tcase 7:\n\t\treturn \"OSPFv2\", nil\n\tcase 8:\n\t\treturn \"OSPFv3\", nil\n\tcase 9:\n\t\treturn \"IS-IS\", nil\n\tcase 10:\n\t\treturn \"BGP segment routing Prefix-SID\", nil\n\t}\n\treturn strconv.FormatUint(uint64(b[0]), 10), nil\n}\n\nfunc decodeIPVersion(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 4:\n\t\treturn \"IPv4\", nil\n\tcase 6:\n\t\treturn \"IPv6\", nil\n\t}\n\treturn strconv.FormatUint(uint64(b[0]), 10), nil\n}\n\nfunc decodePacketIPVersion(v uint8) string {\n\tswitch v {\n\tcase 4:\n\t\treturn \"IPv4\"\n\tcase 6:\n\t\treturn \"IPv6\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\nfunc decodeDirection(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"ingress\", nil\n\tcase 1:\n\t\treturn \"egress\", nil\n\t}\n\treturn strconv.FormatUint(uint64(b[0]), 10), nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-forwarding-status\nfunc decodeFwdStatus(b []byte) (interface{}, error) {\n\tswitch b[0] >> 6 {\n\tcase 0:\n\t\treturn \"unknown\", nil\n\tcase 1:\n\t\treturn \"forwarded\", nil\n\tcase 2:\n\t\treturn \"dropped\", nil\n\tcase 3:\n\t\treturn \"consumed\", nil\n\t}\n\treturn \"invalid\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-forwarding-status\nfunc decodeFwdReason(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\t// unknown\n\tcase 0:\n\t\treturn \"unknown\", nil\n\t// forwarded\n\tcase 64:\n\t\treturn \"unknown\", nil\n\tcase 65:\n\t\treturn \"fragmented\", nil\n\tcase 66:\n\t\treturn \"not fragmented\", nil\n\t// dropped\n\tcase 128:\n\t\treturn \"unknown\", nil\n\tcase 129:\n\t\treturn \"ACL deny\", nil\n\tcase 130:\n\t\treturn \"ACL drop\", nil\n\tcase 131:\n\t\treturn \"unroutable\", nil\n\tcase 132:\n\t\treturn \"adjacency\", nil\n\tcase 133:\n\t\treturn \"fragmentation and DF set\", nil\n\tcase 134:\n\t\treturn \"bad header checksum\", nil\n\tcase 135:\n\t\treturn \"bad total length\", nil\n\tcase 136:\n\t\treturn \"bad header length\", nil\n\tcase 137:\n\t\treturn \"bad TTL\", nil\n\tcase 138:\n\t\treturn \"policer\", nil\n\tcase 139:\n\t\treturn \"WRED\", nil\n\tcase 140:\n\t\treturn \"RPF\", nil\n\tcase 141:\n\t\treturn \"for us\", nil\n\tcase 142:\n\t\treturn \"bad output interface\", nil\n\tcase 143:\n\t\treturn \"hardware\", nil\n\t// consumed\n\tcase 192:\n\t\treturn \"unknown\", nil\n\tcase 193:\n\t\treturn \"terminate punt adjacency\", nil\n\tcase 194:\n\t\treturn \"terminate incomplete adjacency\", nil\n\tcase 195:\n\t\treturn \"terminate for us\", nil\n\tcase 14:\n\t\treturn \"\", nil\n\t}\n\treturn \"invalid\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-firewall-event\nfunc decodeFWEvent(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"ignore\", nil\n\tcase 1:\n\t\treturn \"flow created\", nil\n\tcase 2:\n\t\treturn \"flow deleted\", nil\n\tcase 3:\n\t\treturn \"flow denied\", nil\n\tcase 4:\n\t\treturn \"flow alert\", nil\n\tcase 5:\n\t\treturn \"flow update\", nil\n\t}\n\treturn strconv.FormatUint(uint64(b[0]), 10), nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-flow-end-reason\nfunc decodeFlowEndReason(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"reserved\", nil\n\tcase 1:\n\t\treturn \"idle timeout\", nil\n\tcase 2:\n\t\treturn \"active timeout\", nil\n\tcase 3:\n\t\treturn \"end of flow\", nil\n\tcase 4:\n\t\treturn \"forced end\", nil\n\tcase 5:\n\t\treturn \"lack of resources\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-biflow-direction\nfunc decodeBiflowDirection(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"arbitrary\", nil\n\tcase 1:\n\t\treturn \"initiator\", nil\n\tcase 2:\n\t\treturn \"reverse initiator\", nil\n\tcase 3:\n\t\treturn \"perimeter\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-observation-point-type\nfunc decodeOpsPointType(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"invalid\", nil\n\tcase 1:\n\t\treturn \"physical port\", nil\n\tcase 2:\n\t\treturn \"port channel\", nil\n\tcase 3:\n\t\treturn \"vlan\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\nfunc decodeAnonStabilityClass(b []byte) (interface{}, error) {\n\tswitch b[1] & 0x03 {\n\tcase 1:\n\t\treturn \"session\", nil\n\tcase 2:\n\t\treturn \"exporter-collector\", nil\n\tcase 3:\n\t\treturn \"stable\", nil\n\t}\n\treturn \"undefined\", nil\n}\n\nfunc decodeAnonFlags(b []byte) (interface{}, error) {\n\tvar result []string\n\tif b[0]&(1<<2) != 0 {\n\t\tresult = append(result, \"PmA\")\n\t}\n\n\tif b[0]&(1<<3) != 0 {\n\t\tresult = append(result, \"LOR\")\n\t}\n\n\treturn strings.Join(result, \",\"), nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-anonymization-technique\nfunc decodeAnonTechnique(b []byte) (interface{}, error) {\n\ttech := binary.BigEndian.Uint16(b)\n\tswitch tech {\n\tcase 0:\n\t\treturn \"undefined\", nil\n\tcase 1:\n\t\treturn \"none\", nil\n\tcase 2:\n\t\treturn \"precision degradation\", nil\n\tcase 3:\n\t\treturn \"binning\", nil\n\tcase 4:\n\t\treturn \"enumeration\", nil\n\tcase 5:\n\t\treturn \"permutation\", nil\n\tcase 6:\n\t\treturn \"structure permutation\", nil\n\tcase 7:\n\t\treturn \"reverse truncation\", nil\n\tcase 8:\n\t\treturn \"noise\", nil\n\tcase 9:\n\t\treturn \"offset\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\nfunc decodeTechnology(b []byte) (interface{}, error) {\n\tswitch string(b) {\n\tcase \"yes\", \"y\", \"1\":\n\t\treturn \"yes\", nil\n\tcase \"no\", \"n\", \"2\":\n\t\treturn \"no\", nil\n\tcase \"unassigned\", \"u\", \"0\":\n\t\treturn \"unassigned\", nil\n\t}\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"unassigned\", nil\n\tcase 1:\n\t\treturn \"yes\", nil\n\tcase 2:\n\t\treturn \"no\", nil\n\t}\n\treturn \"undefined\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-nat-type\nfunc decodeIPNatType(b []byte) (interface{}, error) {\n\ttech := binary.BigEndian.Uint16(b)\n\tswitch tech {\n\tcase 0:\n\t\treturn \"unknown\", nil\n\tcase 1:\n\t\treturn \"NAT44\", nil\n\tcase 2:\n\t\treturn \"NAT64\", nil\n\tcase 3:\n\t\treturn \"NAT46\", nil\n\tcase 4:\n\t\treturn \"IPv4 no NAT\", nil\n\tcase 5:\n\t\treturn \"NAT66\", nil\n\tcase 6:\n\t\treturn \"IPv6 no NAT\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/psamp-parameters/psamp-parameters.xhtml\nfunc decodeSelectorAlgorithm(b []byte) (interface{}, error) {\n\ttech := binary.BigEndian.Uint16(b)\n\tswitch tech {\n\tcase 0:\n\t\treturn \"reserved\", nil\n\tcase 1:\n\t\treturn \"systematic count-based sampling\", nil\n\tcase 2:\n\t\treturn \"systematic time-based sampling\", nil\n\tcase 3:\n\t\treturn \"random n-out-of-N sampling\", nil\n\tcase 4:\n\t\treturn \"uniform probabilistic sampling\", nil\n\tcase 5:\n\t\treturn \"property match filtering\", nil\n\tcase 6:\n\t\treturn \"hash based filtering using BOB\", nil\n\tcase 7:\n\t\treturn \"hash based filtering using IPSX\", nil\n\tcase 8:\n\t\treturn \"hash based filtering using CRC\", nil\n\tcase 9:\n\t\treturn \"flow-state dependent\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-value-distribution-method\nfunc decodeValueDistMethod(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"unspecified\", nil\n\tcase 1:\n\t\treturn \"start interval\", nil\n\tcase 2:\n\t\treturn \"end interval\", nil\n\tcase 3:\n\t\treturn \"mid interval\", nil\n\tcase 4:\n\t\treturn \"simple uniform distribution\", nil\n\tcase 5:\n\t\treturn \"proportional uniform distribution\", nil\n\tcase 6:\n\t\treturn \"simulated process\", nil\n\tcase 7:\n\t\treturn \"direct\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-data-link-frame-type\nfunc decodeDataLinkFrameType(b []byte) (interface{}, error) {\n\tswitch binary.BigEndian.Uint16(b) {\n\tcase 0x0001:\n\t\treturn \"IEEE802.3 ethernet\", nil\n\tcase 0x0002:\n\t\treturn \"IEEE802.11 MAC\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\n// https://www.iana.org/assignments/ipfix/ipfix.xhtml#ipfix-mib-capture-time-semantics\nfunc decodeCaptureTimeSemantics(b []byte) (interface{}, error) {\n\tswitch b[0] {\n\tcase 0:\n\t\treturn \"undefined\", nil\n\tcase 1:\n\t\treturn \"begin\", nil\n\tcase 2:\n\t\treturn \"end\", nil\n\tcase 3:\n\t\treturn \"export\", nil\n\tcase 4:\n\t\treturn \"average\", nil\n\t}\n\treturn \"unassigned\", nil\n}\n\nfunc decodeSflowIPVersion(v uint32) string {\n\tswitch v {\n\tcase 0:\n\t\treturn \"unknown\"\n\tcase 1:\n\t\treturn \"IPv4\"\n\tcase 2:\n\t\treturn \"IPv6\"\n\t}\n\treturn strconv.FormatUint(uint64(v), 10)\n}\n\nfunc decodeSflowSourceInterface(t uint32) string {\n\tswitch t {\n\tcase 0:\n\t\treturn \"in_snmp\"\n\tcase 1:\n\t\treturn \"in_vlan_id\"\n\tcase 2:\n\t\treturn \"in_phy_interface\"\n\t}\n\treturn \"\"\n}\n\nfunc decodeSflowHeaderProtocol(t uint32) string {\n\tswitch t {\n\tcase 1:\n\t\treturn \"ETHERNET-ISO8023\"\n\tcase 2:\n\t\treturn \"ISO88024-TOKENBUS\"\n\tcase 3:\n\t\treturn \"ISO88025-TOKENRING\"\n\tcase 4:\n\t\treturn \"FDDI\"\n\tcase 5:\n\t\treturn \"FRAME-RELAY\"\n\tcase 6:\n\t\treturn \"X25\"\n\tcase 7:\n\t\treturn \"PPP\"\n\tcase 8:\n\t\treturn \"SMDS\"\n\tcase 9:\n\t\treturn \"AAL5\"\n\tcase 10:\n\t\treturn \"AAL5-IP\"\n\tcase 11:\n\t\treturn \"IPv4\"\n\tcase 12:\n\t\treturn \"IPv6\"\n\tcase 13:\n\t\treturn \"MPLS\"\n\t}\n\treturn \"unassigned\"\n}\n\nfunc decodeByteFunc(idx int) decoderFunc {\n\treturn func(b []byte) (interface{}, error) { return b[idx], nil }\n}\n"
  },
  {
    "path": "plugins/inputs/netflow/type_conversion_test.go",
    "content": "package netflow\n\nimport (\n\t\"encoding/binary\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDecodeInt32(t *testing.T) {\n\tbuf := []byte{0x82, 0xad, 0x80, 0x86}\n\tv, err := decodeInt(buf)\n\trequire.NoError(t, err)\n\tout, ok := v.(int64)\n\trequire.True(t, ok)\n\trequire.Equal(t, int64(-2102558586), out)\n}\n\nfunc TestDecodeUint(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tin       []byte\n\t\texpected uint64\n\t}{\n\t\t{\n\t\t\tname:     \"uint8\",\n\t\t\tin:       []byte{0x42},\n\t\t\texpected: 66,\n\t\t},\n\t\t{\n\t\t\tname:     \"uint16\",\n\t\t\tin:       []byte{0x0A, 0x42},\n\t\t\texpected: 2626,\n\t\t},\n\t\t{\n\t\t\tname:     \"uint32\",\n\t\t\tin:       []byte{0x82, 0xad, 0x80, 0x86},\n\t\t\texpected: 2192408710,\n\t\t},\n\t\t{\n\t\t\tname:     \"uint64\",\n\t\t\tin:       []byte{0x00, 0x00, 0x23, 0x42, 0x8f, 0xad, 0x80, 0x86},\n\t\t\texpected: 38768785326214,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tv, err := decodeUint(tt.in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(uint64)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeUintInvalid(t *testing.T) {\n\t_, err := decodeUint([]byte{0x00, 0x00, 0x00})\n\trequire.ErrorContains(t, err, \"invalid length\")\n}\n\nfunc TestDecodeFloat64(t *testing.T) {\n\tbuf := []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea}\n\tv, err := decodeFloat64(buf)\n\trequire.NoError(t, err)\n\tout, ok := v.(float64)\n\trequire.True(t, ok)\n\trequire.InDelta(t, float64(3.14159265359), out, testutil.DefaultDelta)\n}\n\nfunc TestDecodeBool(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tin       []byte\n\t\texpected interface{}\n\t}{\n\t\t{\n\t\t\tname:     \"zero\",\n\t\t\tin:       []byte{0x00},\n\t\t\texpected: uint8(0),\n\t\t},\n\t\t{\n\t\t\tname:     \"true\",\n\t\t\tin:       []byte{0x01},\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"false\",\n\t\t\tin:       []byte{0x02},\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tname:     \"other\",\n\t\t\tin:       []byte{0x23},\n\t\t\texpected: uint8(35),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := decodeBool(tt.in)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeHex(t *testing.T) {\n\tbuf := []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2e, 0xea}\n\tv, err := decodeHex(buf)\n\trequire.NoError(t, err)\n\tout, ok := v.(string)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"0x400921fb54442eea\", out)\n}\n\nfunc TestDecodeString(t *testing.T) {\n\tbuf := []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x65, 0x6c, 0x65, 0x67, 0x72, 0x61, 0x66}\n\tv, err := decodeString(buf)\n\trequire.NoError(t, err)\n\tout, ok := v.(string)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"hello telegraf\", out)\n}\n\nfunc TestDecodeMAC(t *testing.T) {\n\tbuf := []byte{0x2c, 0xf0, 0x5d, 0xe9, 0x04, 0x42}\n\tv, err := decodeMAC(buf)\n\trequire.NoError(t, err)\n\tout, ok := v.(string)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"2c:f0:5d:e9:04:42\", out)\n}\n\nfunc TestDecodeIP(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tin       []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"localhost IPv4\",\n\t\t\tin:       []byte{0x7f, 0x00, 0x00, 0x01},\n\t\t\texpected: \"127.0.0.1\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unrouted IPv4\",\n\t\t\tin:       []byte{0xc0, 0xa8, 0x04, 0x42},\n\t\t\texpected: \"192.168.4.66\",\n\t\t},\n\t\t{\n\t\t\tname:     \"localhost IPv6\",\n\t\t\tin:       []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},\n\t\t\texpected: \"::1\",\n\t\t},\n\t\t{\n\t\t\tname:     \"local network IPv6\",\n\t\t\tin:       []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0xd6, 0x8e, 0x07, 0x7f, 0x59, 0x5a, 0x23, 0xf1},\n\t\t\texpected: \"::fe80:d68e:77f:595a:23f1\",\n\t\t},\n\t\t{\n\t\t\tname:     \"google.com IPv6\",\n\t\t\tin:       []byte{0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x14, 0x50, 0x40, 0x01, 0x08, 0x11, 0x00, 0x00, 0x20, 0x0e},\n\t\t\texpected: \"::2a00:1450:4001:811:0:200e\",\n\t\t},\n\t\t{\n\t\t\tname:     \"stripped in between IPv6\",\n\t\t\tin:       []byte{0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x50, 0x40, 0x01, 0x08, 0x11, 0x00, 0x01, 0x20, 0x0e},\n\t\t\texpected: \"2a00::1450:4001:811:1:200e\",\n\t\t},\n\t\t{\n\t\t\tname:     \"IPv6 not enough bytes\",\n\t\t\tin:       []byte{0x00, 0x00, 0x00, 0xff, 0x00, 0x01},\n\t\t\texpected: \"?000000ff0001\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tv, err := decodeIP(tt.in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(string)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeIPFromUint32(t *testing.T) {\n\tin := uint32(0x7f000001)\n\tv, err := decodeIPFromUint32(in)\n\trequire.NoError(t, err)\n\tout, ok := v.(string)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"127.0.0.1\", out)\n}\n\nfunc TestDecodeLayer4ProtocolNumber(t *testing.T) {\n\trequire.NoError(t, initL4ProtoMapping())\n\n\ttests := []struct {\n\t\tname     string\n\t\tin       []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"ICMP 1\",\n\t\t\tin:       []byte{0x01},\n\t\t\texpected: \"icmp\",\n\t\t},\n\t\t{\n\t\t\tname:     \"IPv4 4\",\n\t\t\tin:       []byte{0x04},\n\t\t\texpected: \"ipv4\",\n\t\t},\n\t\t{\n\t\t\tname:     \"IPv6 41\",\n\t\t\tin:       []byte{0x29},\n\t\t\texpected: \"ipv6\",\n\t\t},\n\t\t{\n\t\t\tname:     \"L2TP 115\",\n\t\t\tin:       []byte{0x73},\n\t\t\texpected: \"l2tp\",\n\t\t},\n\t\t{\n\t\t\tname:     \"PTP 123\",\n\t\t\tin:       []byte{0x7b},\n\t\t\texpected: \"ptp\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unassigned 201\",\n\t\t\tin:       []byte{0xc9},\n\t\t\texpected: \"201\",\n\t\t},\n\t\t{\n\t\t\tname:     \"experimental 254\",\n\t\t\tin:       []byte{0xfe},\n\t\t\texpected: \"experimental\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Reserved 255\",\n\t\t\tin:       []byte{0xff},\n\t\t\texpected: \"reserved\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tv, err := decodeL4Proto(tt.in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(string)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeIPv4Options(t *testing.T) {\n\trequire.NoError(t, initIPv4OptionMapping())\n\n\ttests := []struct {\n\t\tname     string\n\t\tbits     []int\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"none\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"all\",\n\t\t\tbits: []int{\n\t\t\t\t0, 1, 2, 3, 4, 5, 6, 7,\n\t\t\t\t8, 9, 10, 11, 12, 13, 14, 15,\n\t\t\t\t16, 17, 18, 19, 20, 21, 22, 23,\n\t\t\t\t24, 25, 26, 27, 28, 29, 30, 31,\n\t\t\t},\n\t\t\texpected: \"EOOL,NOP,SEC,LSR,TS,E-SEC,CIPSO,RR,SID,SSR,ZSU,MTUP,\" +\n\t\t\t\t\"MTUR,FINN,VISA,ENCODE,IMITD,EIP,TR,ADDEXT,RTRALT,SDB,\" +\n\t\t\t\t\"UA22,DPS,UMP,QS,UA26,UA27,UA28,UA29,EXP,UA31\",\n\t\t},\n\t\t{\n\t\t\tname:     \"EOOL\",\n\t\t\tbits:     []int{0},\n\t\t\texpected: \"EOOL\",\n\t\t},\n\t\t{\n\t\t\tname:     \"SSR\",\n\t\t\tbits:     []int{9},\n\t\t\texpected: \"SSR\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar options uint32\n\t\t\tfor _, bit := range tt.bits {\n\t\t\t\toptions |= 1 << bit\n\t\t\t}\n\t\t\tin := make([]byte, 4)\n\t\t\tbinary.BigEndian.PutUint32(in, options)\n\n\t\t\tv, err := decodeIPv4Options(in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(string)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeTCPFlags(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tbits     []int\n\t\texpected string\n\t\tipfix    bool\n\t}{\n\t\t{\n\t\t\tname:     \"none\",\n\t\t\texpected: \"........\",\n\t\t},\n\t\t{\n\t\t\tname:     \"none IPFIX\",\n\t\t\texpected: \"................\",\n\t\t\tipfix:    true,\n\t\t},\n\t\t{\n\t\t\tname:     \"all\",\n\t\t\tbits:     []int{0, 1, 2, 3, 4, 5, 6, 7},\n\t\t\texpected: \"CEUAPRSF\",\n\t\t},\n\t\t{\n\t\t\tname:     \"all IPFIX\",\n\t\t\tbits:     []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},\n\t\t\texpected: \"********CEUAPRSF\",\n\t\t\tipfix:    true,\n\t\t},\n\t\t{\n\t\t\tname:     \"SYN\",\n\t\t\tbits:     []int{1},\n\t\t\texpected: \"......S.\",\n\t\t},\n\t\t{\n\t\t\tname:     \"SYN/ACK\",\n\t\t\tbits:     []int{1, 4},\n\t\t\texpected: \"...A..S.\",\n\t\t},\n\t\t{\n\t\t\tname:     \"ACK\",\n\t\t\tbits:     []int{4},\n\t\t\texpected: \"...A....\",\n\t\t},\n\t\t{\n\t\t\tname:     \"FIN\",\n\t\t\tbits:     []int{0},\n\t\t\texpected: \".......F\",\n\t\t},\n\t\t{\n\t\t\tname:     \"FIN/ACK\",\n\t\t\tbits:     []int{0, 4},\n\t\t\texpected: \"...A...F\",\n\t\t},\n\t\t{\n\t\t\tname:     \"ACK IPFIX\",\n\t\t\tbits:     []int{4},\n\t\t\texpected: \"...........A....\",\n\t\t\tipfix:    true,\n\t\t},\n\t\t{\n\t\t\tname:     \"FIN IPFIX\",\n\t\t\tbits:     []int{0},\n\t\t\texpected: \"...............F\",\n\t\t\tipfix:    true,\n\t\t},\n\t\t{\n\t\t\tname:     \"ECN Nounce Sum IPFIX\",\n\t\t\tbits:     []int{8},\n\t\t\texpected: \".......*........\",\n\t\t\tipfix:    true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar in []byte\n\n\t\t\tif tt.ipfix {\n\t\t\t\tvar options uint16\n\t\t\t\tfor _, bit := range tt.bits {\n\t\t\t\t\toptions |= 1 << bit\n\t\t\t\t}\n\t\t\t\tin = make([]byte, 2)\n\t\t\t\tbinary.BigEndian.PutUint16(in, options)\n\t\t\t} else {\n\t\t\t\tvar options uint8\n\t\t\t\tfor _, bit := range tt.bits {\n\t\t\t\t\toptions |= 1 << bit\n\t\t\t\t}\n\t\t\t\tin = []byte{options}\n\t\t\t}\n\t\t\tv, err := decodeTCPFlags(in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(string)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n\nfunc TestDecodeFragmentFlags(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tbits     []int\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"none\",\n\t\t\texpected: \"........\",\n\t\t},\n\t\t{\n\t\t\tname:     \"all\",\n\t\t\tbits:     []int{0, 1, 2, 3, 4, 5, 6, 7},\n\t\t\texpected: \"RDM*****\",\n\t\t},\n\t\t{\n\t\t\tname:     \"RS\",\n\t\t\tbits:     []int{7},\n\t\t\texpected: \"R.......\",\n\t\t},\n\t\t{\n\t\t\tname:     \"DF\",\n\t\t\tbits:     []int{6},\n\t\t\texpected: \".D......\",\n\t\t},\n\t\t{\n\t\t\tname:     \"MF\",\n\t\t\tbits:     []int{5},\n\t\t\texpected: \"..M.....\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Bit 7 (LSB)\",\n\t\t\tbits:     []int{0},\n\t\t\texpected: \".......*\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar flags uint8\n\t\t\tfor _, bit := range tt.bits {\n\t\t\t\tflags |= 1 << bit\n\t\t\t}\n\t\t\tin := []byte{flags}\n\t\t\tv, err := decodeFragmentFlags(in)\n\t\t\trequire.NoError(t, err)\n\t\t\tout, ok := v.(string)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tt.expected, out)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/netstat/README.md",
    "content": "# Network Connection Statistics Input Plugin\n\nThis plugin collects statistics about TCP connection states and UDP socket\ncounts.\n\n⭐ Telegraf v0.2.0\n🏷️ network\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read TCP metrics such as established, time wait and sockets counts.\n[[inputs.netstat]]\n  # no configuration\n```\n\n## Metrics\n\nSupported TCP Connection states are follows.\n\n- established\n- syn_sent\n- syn_recv\n- fin_wait1\n- fin_wait2\n- time_wait\n- close\n- close_wait\n- last_ack\n- listen\n- closing\n- none\n\n### TCP Connection State measurements\n\nMeta:\n\n- units: counts\n\nMeasurement names:\n\n- tcp_established\n- tcp_syn_sent\n- tcp_syn_recv\n- tcp_fin_wait1\n- tcp_fin_wait2\n- tcp_time_wait\n- tcp_close\n- tcp_close_wait\n- tcp_last_ack\n- tcp_listen\n- tcp_closing\n- tcp_none\n\nIf there are no connection on the state, the metric is not counted.\n\n### UDP socket counts measurements\n\nMeta:\n\n- units: counts\n\nMeasurement names:\n\n- udp_socket\n\n## Example Output\n\n```text\nnetstat tcp_close=0i,tcp_close_wait=0i,tcp_closing=0i,tcp_established=14i,tcp_fin_wait1=0i,tcp_fin_wait2=0i,tcp_last_ack=0i,tcp_listen=1i,tcp_none=46i,tcp_syn_recv=0i,tcp_syn_sent=0i,tcp_time_wait=0i,udp_socket=10i 1668520568000000000\n```\n"
  },
  {
    "path": "plugins/inputs/netstat/netstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage netstat\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"syscall\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NetStat struct {\n\tps psutil.PS\n}\n\nfunc (*NetStat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ns *NetStat) Gather(acc telegraf.Accumulator) error {\n\tnetconns, err := ns.ps.NetConnections()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting net connections info: %w\", err)\n\t}\n\tcounts := make(map[string]int)\n\tcounts[\"UDP\"] = 0\n\n\t// TODO: add family to tags or else\n\ttags := make(map[string]string)\n\tfor _, netcon := range netconns {\n\t\tif netcon.Type == syscall.SOCK_DGRAM {\n\t\t\tcounts[\"UDP\"]++\n\t\t\tcontinue // UDP has no status\n\t\t}\n\t\tc, ok := counts[netcon.Status]\n\t\tif !ok {\n\t\t\tcounts[netcon.Status] = 0\n\t\t}\n\t\tcounts[netcon.Status] = c + 1\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"tcp_established\": counts[\"ESTABLISHED\"],\n\t\t\"tcp_syn_sent\":    counts[\"SYN_SENT\"],\n\t\t\"tcp_syn_recv\":    counts[\"SYN_RECV\"],\n\t\t\"tcp_fin_wait1\":   counts[\"FIN_WAIT1\"],\n\t\t\"tcp_fin_wait2\":   counts[\"FIN_WAIT2\"],\n\t\t\"tcp_time_wait\":   counts[\"TIME_WAIT\"],\n\t\t\"tcp_close\":       counts[\"CLOSE\"],\n\t\t\"tcp_close_wait\":  counts[\"CLOSE_WAIT\"],\n\t\t\"tcp_last_ack\":    counts[\"LAST_ACK\"],\n\t\t\"tcp_listen\":      counts[\"LISTEN\"],\n\t\t\"tcp_closing\":     counts[\"CLOSING\"],\n\t\t\"tcp_none\":        counts[\"NONE\"],\n\t\t\"udp_socket\":      counts[\"UDP\"],\n\t}\n\tacc.AddFields(\"netstat\", fields, tags)\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"netstat\", func() telegraf.Input {\n\t\treturn &NetStat{ps: psutil.NewSystemPS()}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/netstat/netstat_test.go",
    "content": "package netstat\n\nimport (\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/net\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/psutil\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNetStats(t *testing.T) {\n\tvar mps psutil.MockPS\n\tdefer mps.AssertExpectations(t)\n\tmps.On(\"NetConnections\").Return([]net.ConnectionStat{\n\t\t{\n\t\t\tType: syscall.SOCK_DGRAM,\n\t\t},\n\t\t{\n\t\t\tStatus: \"ESTABLISHED\",\n\t\t},\n\t\t{\n\t\t\tStatus: \"ESTABLISHED\",\n\t\t},\n\t\t{\n\t\t\tStatus: \"CLOSE\",\n\t\t},\n\t}, nil)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, (&NetStat{ps: &mps}).Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"netstat\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"tcp_established\": 2,\n\t\t\t\t\"tcp_syn_sent\":    0,\n\t\t\t\t\"tcp_syn_recv\":    0,\n\t\t\t\t\"tcp_fin_wait1\":   0,\n\t\t\t\t\"tcp_fin_wait2\":   0,\n\t\t\t\t\"tcp_time_wait\":   0,\n\t\t\t\t\"tcp_close\":       1,\n\t\t\t\t\"tcp_close_wait\":  0,\n\t\t\t\t\"tcp_last_ack\":    0,\n\t\t\t\t\"tcp_listen\":      0,\n\t\t\t\t\"tcp_closing\":     0,\n\t\t\t\t\"tcp_none\":        0,\n\t\t\t\t\"udp_socket\":      1,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t,\n\t\texpected,\n\t\tacc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t)\n}\n"
  },
  {
    "path": "plugins/inputs/netstat/sample.conf",
    "content": "# Read TCP metrics such as established, time wait and sockets counts.\n[[inputs.netstat]]\n  # no configuration\n"
  },
  {
    "path": "plugins/inputs/nfsclient/README.md",
    "content": "# Network Filesystem Input Plugin\n\nThis plugin collects metrics about operations on [Network Filesystem][nfs]\nmounts. By default, only a limited number of general system-level metrics are\ncollected, including basic read/write counts but more detailed metrics can be\nenabled.\n\n> [!NOTE]\n> Many of the metrics, even if tagged with a mount point, are really\n> _per-server_. E.g. if you mount two shares: `nfs01:/vol/foo/bar` and\n> `nfs01:/vol/foo/baz`, there will be two near identical entries in\n> `/proc/self/mountstats`. This is a limitation of the metrics exposed by the\n> kernel, not by this plugin.\n\n⭐ Telegraf v1.18.0\n🏷️ network, system\n💻 all\n\n[nfs]: https://www.ietf.org/rfc/rfc1813.txt?number=1813\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read per-mount NFS client metrics from /proc/self/mountstats\n[[inputs.nfsclient]]\n  ## Read more low-level metrics (optional, defaults to false)\n  # fullstat = false\n\n  ## List of mounts to explicitly include or exclude (optional)\n  ## The pattern (Go regexp) is matched against the mount point (not the\n  ## device being mounted).  If include_mounts is set, all mounts are ignored\n  ## unless present in the list. If a mount is listed in both include_mounts\n  ## and exclude_mounts, it is excluded.  Go regexp patterns can be used.\n  # include_mounts = []\n  # exclude_mounts = []\n\n  ## List of operations to include or exclude from collecting.  This applies\n  ## only when fullstat=true.  Semantics are similar to {include,exclude}_mounts:\n  ## the default is to collect everything; when include_operations is set, only\n  ## those OPs are collected; when exclude_operations is set, all are collected\n  ## except those listed.  If include and exclude are set, the OP is excluded.\n  ## See /proc/self/mountstats for a list of valid operations; note that\n  ## NFSv3 and NFSv4 have different lists.  While it is not possible to\n  ## have different include/exclude lists for NFSv3/4, unused elements\n  ## in the list should be okay.  It is possible to have different lists\n  ## for different mountpoints:  use multiple [[input.nfsclient]] stanzas,\n  ## with their own lists.  See \"include_mounts\" above, and be careful of\n  ## duplicate metrics.\n  # include_operations = []\n  # exclude_operations = []\n```\n\n### Configuration Options\n\n- `fullstat`: Collect per-operation type metrics. Defaults to false.\n- `include_mounts`: gather metrics for only these mounts. Default is to watch\n    all mounts.\n- `exclude_mounts`: gather metrics for all mounts, except those listed in this\n    option. Excludes take precedence over includes.\n- `include_operations`: List of specific NFS operations to track. See\n    `/proc/self/mountstats` (the \"per-op statistics\" section) for a complete\n    lists of valid options for NFSv3 and NFSV4. The default is to gather all\n    metrics, but this is almost certainly _not_ what you want (there are\n    22 operations for NFSv3, and well over 50 for NFSv4). A suggested 'minimal'\n    list of operations to collect for basic usage:\n    `['READ','WRITE','ACCESS','GETATTR','READDIR','LOOKUP','LOOKUP']`\n- `exclude_operations`: Gather all metrics, except those listed. Excludes take\n    precedence over includes.\n\n> [!NOTE]\n> The `include_mounts` and `exclude_mounts` arguments are both applied to the\n> local mount location (e.g. /mnt/NFS), not the server export (e.g.\n> nfsserver:/vol/NFS). Go regexp patterns can be used in either.\n\n## Location of mountstats\n\nIf you have mounted the `/proc` file system in a container, to tell this plugin\nwhere to find the new location, set the `MOUNT_PROC` environment variable. For\nexample, in a Docker compose file, if `/proc` is mounted to `/host/proc`, then\nuse:\n\n```yaml\nMOUNT_PROC: /host/proc/self/mountstats\n```\n\n## Metrics\n\nFields:\n\n- nfsstat\n  - bytes (integer, bytes) - The total number of bytes exchanged doing this\n      operation. This is bytes sent _and_ received, including overhead _and_\n      payload (`bytes = OP_bytes_sent + OP_bytes_recv`). See `nfs_ops` below.\n  - ops (integer, count) - The number of operations of this type executed.\n  - retrans (integer, count) - The number of times an operation had to be\n      (`retried retrans = OP_trans - OP_ops`).  See `nfs_ops` below.\n  - exe (integer, milliseconds) - The number of milliseconds it took to process\n      the operations.\n  - rtt (integer, milliseconds) - The total round-trip time for all operations.\n  - rtt_per_op (float, milliseconds) - The average round-trip time per operation.\n\nIn addition enabling `fullstat` will make many more metrics available.\n\nTags:\n\n- All measurements have the following tags:\n  - mountpoint - The local mountpoint, for instance: \"/var/www\"\n  - serverexport - The full server export, for instance: \"nfsserver.example.org:/export\"\n\n- Measurements nfsstat and nfs_ops will also include:\n  - operation - the NFS operation in question.  `READ` or `WRITE` for nfsstat,\n                but potentially one of ~20 or ~50, depending on NFS version. A\n                complete list of operations supported is visible in\n                `/proc/self/mountstats`.\n\n### Additional metrics\n\nWhen `fullstat` is true, additional measurements are collected.  Tags are the\nsame as above.\n\nNFS Operations:\n\nMost descriptions come from [Reference][ref] and `nfs_iostat.h`.  Field order\nand names are the same as in `/proc/self/mountstats` and the Kernel source.\n\nPlease refer to `/proc/self/mountstats` for a list of supported NFS operations,\nas it changes occasionally.\n\n- nfs_bytes\n  - fields:\n    - normalreadbytes (int, bytes): Bytes read from the server via `read()`\n    - normalwritebytes (int, bytes): Bytes written to the server via `write()`\n    - directreadbytes (int, bytes): Bytes read with O_DIRECT set\n    - directwritebytes (int, bytes): Bytes written with O_DIRECT set\n    - serverreadbytes (int, bytes): Bytes read via NFS READ (via `mmap()`)\n    - serverwritebytes (int, bytes): Bytes written via NFS WRITE (via `mmap()`)\n    - readpages (int, count): Number of pages read\n    - writepages (int, count): Number of pages written\n\n- nfs_events (Per-event metrics)\n  - fields:\n    - inoderevalidates (int, count):  How many times cached inode attributes have\n                                      to be re-validated from the server.\n    - dentryrevalidates (int, count): How many times cached dentry nodes have to\n                                      be re-validated.\n    - datainvalidates (int, count):   How many times an inode had its cached\n                                      data thrown out.\n    - attrinvalidates (int, count):   How many times an inode has had cached\n                                      inode attributes invalidated.\n    - vfsopen (int, count):           How many times files or directories have\n                                      been `open()`'d.\n    - vfslookup (int, count):         How many name lookups in directories there\n                                      have been.\n    - vfsaccess (int, count):         Number of calls to `access()`. (formerly\n                                      called \"vfspermission\")\n    - vfsupdatepage (int, count):     Count of updates (and potential writes) to\n                                      pages.\n    - vfsreadpage (int, count):       Number of pages read.\n    - vfsreadpages (int, count):      Count of how many times a _group_ of pages\n                                      was read (possibly via `mmap()`?).\n    - vfswritepage (int, count):      Number of pages written.\n    - vfswritepages (int, count):     Count of how many times a _group_ of pages\n                                      was written (possibly via `mmap()`?)\n    - vfsgetdents (int, count):       Count of directory entry reads with\n                                      getdents(). These reads can be served from\n                                      cache and don't necessarily imply actual\n                                      NFS requests. (formerly called \"vfsreaddir\")\n    - vfssetattr (int, count):        How many times we've set attributes on inodes.\n    - vfsflush (int, count):          Count of times pending writes have been\n                                      forcibly flushed to the server.\n    - vfsfsync (int, count):          Count of calls to `fsync()` on directories\n                                      and files.\n    - vfslock (int, count):           Number of times a lock was attempted on a\n                                      file (regardless of success or not).\n    - vfsrelease (int, count):        Number of calls to `close()`.\n    - congestionwait (int, count):    Believe unused by the Linux kernel, but it\n                                      is part of the NFS spec.\n    - setattrtrunc (int, count):      How many times files have had their size truncated.\n    - extendwrite (int, count):       How many times a file has been grown\n                                      because you're writing beyond the existing\n                                      end of the file.\n    - sillyrenames (int, count):      Number of times an in-use file was removed\n                                      (thus creating a temporary \".nfsXXXXXX\" file)\n    - shortreads (int, count):        Number of times the NFS server returned\n                                      less data than requested.\n    - shortwrites (int, count):       Number of times NFS server reports it\n                                      wrote less data than requested.\n    - delay (int, count):             Occurrences of EJUKEBOX (\"Jukebox Delay\",\n                                      probably unused)\n    - pnfsreads (int, count):         Count of NFS v4.1+ pNFS reads.\n    - pnfswrites (int, count):        Count of NFS v4.1+ pNFS writes.\n\n- nfs_xprt_tcp\n  - fields:\n    - bind_count (int, count):     Number of_completely new_ mounts to this\n                                   server (sometimes 0?)\n    - connect_count (int, count):  How many times the client has connected to\n                                   the server in question\n    - connect_time (int, jiffies): How long the NFS client has spent waiting for\n                                   its connection(s) to the server to be established.\n    - idle_time (int, seconds):    How long (in seconds) since the NFS mount saw\n                                   any RPC traffic.\n    - rpcsends (int, count):       How many RPC requests this mount has sent to\n                                   the server.\n    - rpcreceives (int, count):    How many RPC replies this mount has received\n                                   from the server.\n    - badxids (int, count):        Count of XIDs sent by the server that the\n                                   client doesn't know about.\n    - inflightsends (int, count):  Number of outstanding requests; always >1.\n                                   (See reference #4 for comment on this field)\n    - backlogutil (int, count):    Cumulative backlog count\n\n- nfs_xprt_udp\n  - fields:\n    - [same as nfs_xprt_tcp, except for connect_count, connect_time, and idle_time]\n\n- nfs_ops\n  - fields with the `operations` tag being set to the uppercase name of the NFS\n    operation in all cases , _e.g._ \"READ\", \"FSINFO\", _etc_. See\n    `/proc/self/mountstats` for a full list:\n    - ops (int, count):                  Total operations of this type.\n    - trans (int, count):                Total transmissions of this type,\n                                         including retransmissions (lower is better):\n                                         `OP_ops - OP_trans = total_retransmissions`.\n    - timeouts (int, count):             Number of major timeouts.\n    - bytes_sent (int, count):           Bytes sent, including headers (should\n                                         also be close to on-wire size).\n    - bytes_recv (int, count):           Bytes received, including headers\n                                         (should be close to on-wire size).\n    - queue_time (int, milliseconds):    Cumulative time a request waited in the\n                                         queue before sending this OP type.\n    - response_time (int, milliseconds): Cumulative time waiting for a response\n                                         for this OP type.\n    - total_time (int, milliseconds):    Cumulative time a request waited in the\n                                         queue before sending.\n    - errors (int, count):               Total number operations that complete\n                                         with tk_status < 0 (usually errors).\n                                         This is a new field, present in\n                                         kernel >=5.3, mountstats version 1.1\n\n[ref]: https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex\n\n## Example Output\n\nFor basic metrics showing server-wise read and write data.\n\n```text\nnfsstat,mountpoint=/NFS,operation=READ,serverexport=1.2.3.4:/storage/NFS ops=600i,retrans=1i,bytes=1207i,rtt=606i,exe=607i 1612651512000000000\nnfsstat,mountpoint=/NFS,operation=WRITE,serverexport=1.2.3.4:/storage/NFS bytes=1407i,rtt=706i,exe=707i,ops=700i,retrans=1i 1612651512000000000\n\n```\n\nFor `fullstat=true` metrics, which includes additional measurements for\n`nfs_bytes`, `nfs_events`, and `nfs_xprt_tcp` (and `nfs_xprt_udp` if present).\nAdditionally, per-OP metrics are collected, with examples for READ, LOOKUP, and\nNULL shown.  Please refer to `/proc/self/mountstats` for a list of supported NFS\noperations, as it changes as it changes periodically.\n\n```text\nnfs_bytes,mountpoint=/home,serverexport=nfs01:/vol/home directreadbytes=0i,directwritebytes=0i,normalreadbytes=42648757667i,normalwritebytes=0i,readpages=10404603i,serverreadbytes=42617098139i,serverwritebytes=0i,writepages=0i 1608787697000000000\nnfs_events,mountpoint=/home,serverexport=nfs01:/vol/home attrinvalidates=116i,congestionwait=0i,datainvalidates=65i,delay=0i,dentryrevalidates=5911243i,extendwrite=0i,inoderevalidates=200378i,pnfsreads=0i,pnfswrites=0i,setattrtrunc=0i,shortreads=0i,shortwrites=0i,sillyrenames=0i,vfsaccess=7203852i,vfsflush=117405i,vfsfsync=0i,vfsgetdents=3368i,vfslock=0i,vfslookup=740i,vfsopen=157281i,vfsreadpage=16i,vfsreadpages=86874i,vfsrelease=155526i,vfssetattr=0i,vfsupdatepage=0i,vfswritepage=0i,vfswritepages=215514i 1608787697000000000\nnfs_xprt_tcp,mountpoint=/home,serverexport=nfs01:/vol/home backlogutil=0i,badxids=0i,bind_count=1i,connect_count=1i,connect_time=0i,idle_time=0i,inflightsends=15659826i,rpcreceives=2173896i,rpcsends=2173896i 1608787697000000000\n\nnfs_ops,mountpoint=/NFS,operation=NULL,serverexport=1.2.3.4:/storage/NFS trans=0i,timeouts=0i,bytes_sent=0i,bytes_recv=0i,queue_time=0i,response_time=0i,total_time=0i,ops=0i 1612651512000000000\nnfs_ops,mountpoint=/NFS,operation=READ,serverexport=1.2.3.4:/storage/NFS bytes=1207i,timeouts=602i,total_time=607i,exe=607i,trans=601i,bytes_sent=603i,bytes_recv=604i,queue_time=605i,ops=600i,retrans=1i,rtt=606i,response_time=606i 1612651512000000000\nnfs_ops,mountpoint=/NFS,operation=WRITE,serverexport=1.2.3.4:/storage/NFS ops=700i,bytes=1407i,exe=707i,trans=701i,timeouts=702i,response_time=706i,total_time=707i,retrans=1i,rtt=706i,bytes_sent=703i,bytes_recv=704i,queue_time=705i 1612651512000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nfsclient/nfsclient.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nfsclient\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NFSClient struct {\n\tFullstat          bool            `toml:\"fullstat\"`\n\tIncludeMounts     []string        `toml:\"include_mounts\"`\n\tExcludeMounts     []string        `toml:\"exclude_mounts\"`\n\tIncludeOperations []string        `toml:\"include_operations\"`\n\tExcludeOperations []string        `toml:\"exclude_operations\"`\n\tLog               telegraf.Logger `toml:\"-\"`\n\tnfs3Ops           map[string]bool\n\tnfs4Ops           map[string]bool\n\tmountstatsPath    string\n\t// Add compiled regex patterns\n\tincludeMountRegex []*regexp.Regexp\n\texcludeMountRegex []*regexp.Regexp\n}\n\nfunc (*NFSClient) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NFSClient) Init() error {\n\tvar nfs3Fields = []string{\n\t\t\"NULL\",\n\t\t\"GETATTR\",\n\t\t\"SETATTR\",\n\t\t\"LOOKUP\",\n\t\t\"ACCESS\",\n\t\t\"READLINK\",\n\t\t\"READ\",\n\t\t\"WRITE\",\n\t\t\"CREATE\",\n\t\t\"MKDIR\",\n\t\t\"SYMLINK\",\n\t\t\"MKNOD\",\n\t\t\"REMOVE\",\n\t\t\"RMDIR\",\n\t\t\"RENAME\",\n\t\t\"LINK\",\n\t\t\"READDIR\",\n\t\t\"READDIRPLUS\",\n\t\t\"FSSTAT\",\n\t\t\"FSINFO\",\n\t\t\"PATHCONF\",\n\t\t\"COMMIT\",\n\t}\n\n\tvar nfs4Fields = []string{\n\t\t\"NULL\",\n\t\t\"READ\",\n\t\t\"WRITE\",\n\t\t\"COMMIT\",\n\t\t\"OPEN\",\n\t\t\"OPEN_CONFIRM\",\n\t\t\"OPEN_NOATTR\",\n\t\t\"OPEN_DOWNGRADE\",\n\t\t\"CLOSE\",\n\t\t\"SETATTR\",\n\t\t\"FSINFO\",\n\t\t\"RENEW\",\n\t\t\"SETCLIENTID\",\n\t\t\"SETCLIENTID_CONFIRM\",\n\t\t\"LOCK\",\n\t\t\"LOCKT\",\n\t\t\"LOCKU\",\n\t\t\"ACCESS\",\n\t\t\"GETATTR\",\n\t\t\"LOOKUP\",\n\t\t\"LOOKUP_ROOT\",\n\t\t\"REMOVE\",\n\t\t\"RENAME\",\n\t\t\"LINK\",\n\t\t\"SYMLINK\",\n\t\t\"CREATE\",\n\t\t\"PATHCONF\",\n\t\t\"STATFS\",\n\t\t\"READLINK\",\n\t\t\"READDIR\",\n\t\t\"SERVER_CAPS\",\n\t\t\"DELEGRETURN\",\n\t\t\"GETACL\",\n\t\t\"SETACL\",\n\t\t\"FS_LOCATIONS\",\n\t\t\"RELEASE_LOCKOWNER\",\n\t\t\"SECINFO\",\n\t\t\"FSID_PRESENT\",\n\t\t\"EXCHANGE_ID\",\n\t\t\"CREATE_SESSION\",\n\t\t\"DESTROY_SESSION\",\n\t\t\"SEQUENCE\",\n\t\t\"GET_LEASE_TIME\",\n\t\t\"RECLAIM_COMPLETE\",\n\t\t\"LAYOUTGET\",\n\t\t\"GETDEVICEINFO\",\n\t\t\"LAYOUTCOMMIT\",\n\t\t\"LAYOUTRETURN\",\n\t\t\"SECINFO_NO_NAME\",\n\t\t\"TEST_STATEID\",\n\t\t\"FREE_STATEID\",\n\t\t\"GETDEVICELIST\",\n\t\t\"BIND_CONN_TO_SESSION\",\n\t\t\"DESTROY_CLIENTID\",\n\t\t\"SEEK\",\n\t\t\"ALLOCATE\",\n\t\t\"DEALLOCATE\",\n\t\t\"LAYOUTSTATS\",\n\t\t\"CLONE\",\n\t\t\"COPY\",\n\t\t\"OFFLOAD_CANCEL\",\n\t\t\"LOOKUPP\",\n\t\t\"LAYOUTERROR\",\n\t\t\"COPY_NOTIFY\",\n\t\t\"GETXATTR\",\n\t\t\"SETXATTR\",\n\t\t\"LISTXATTRS\",\n\t\t\"REMOVEXATTR\",\n\t}\n\n\tnfs3Ops := make(map[string]bool)\n\tnfs4Ops := make(map[string]bool)\n\n\tn.mountstatsPath = n.getMountStatsPath()\n\n\tif len(n.IncludeOperations) == 0 {\n\t\tfor _, Op := range nfs3Fields {\n\t\t\tnfs3Ops[Op] = true\n\t\t}\n\t\tfor _, Op := range nfs4Fields {\n\t\t\tnfs4Ops[Op] = true\n\t\t}\n\t} else {\n\t\tfor _, Op := range n.IncludeOperations {\n\t\t\tnfs3Ops[Op] = true\n\t\t}\n\t\tfor _, Op := range n.IncludeOperations {\n\t\t\tnfs4Ops[Op] = true\n\t\t}\n\t}\n\n\tif len(n.ExcludeOperations) > 0 {\n\t\tfor _, Op := range n.ExcludeOperations {\n\t\t\tif nfs3Ops[Op] {\n\t\t\t\tdelete(nfs3Ops, Op)\n\t\t\t}\n\t\t\tif nfs4Ops[Op] {\n\t\t\t\tdelete(nfs4Ops, Op)\n\t\t\t}\n\t\t}\n\t}\n\n\tn.nfs3Ops = nfs3Ops\n\tn.nfs4Ops = nfs4Ops\n\n\tif len(n.IncludeMounts) > 0 {\n\t\tn.Log.Debugf(\"Including these mount patterns: %v\", n.IncludeMounts)\n\t} else {\n\t\tn.Log.Debugf(\"Including all mounts.\")\n\t}\n\n\tif len(n.ExcludeMounts) > 0 {\n\t\tn.Log.Debugf(\"Excluding these mount patterns: %v\", n.ExcludeMounts)\n\t} else {\n\t\tn.Log.Debugf(\"Not excluding any mounts.\")\n\t}\n\n\tif len(n.IncludeOperations) > 0 {\n\t\tn.Log.Debugf(\"Including these operations: %v\", n.IncludeOperations)\n\t} else {\n\t\tn.Log.Debugf(\"Including all operations.\")\n\t}\n\n\tif len(n.ExcludeOperations) > 0 {\n\t\tn.Log.Debugf(\"Excluding these mount patterns: %v\", n.ExcludeOperations)\n\t} else {\n\t\tn.Log.Debugf(\"Not excluding any operations.\")\n\t}\n\n\t// Compile include mount patterns\n\tif len(n.IncludeMounts) > 0 {\n\t\tn.includeMountRegex = make([]*regexp.Regexp, 0, len(n.IncludeMounts))\n\t\tfor _, pattern := range n.IncludeMounts {\n\t\t\tcompiled, err := regexp.Compile(pattern)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to compile include mount pattern %q: %w\", pattern, err)\n\t\t\t}\n\t\t\tn.includeMountRegex = append(n.includeMountRegex, compiled)\n\t\t}\n\t}\n\n\t// Compile exclude mount patterns\n\tif len(n.ExcludeMounts) > 0 {\n\t\tn.excludeMountRegex = make([]*regexp.Regexp, 0, len(n.ExcludeMounts))\n\t\tfor _, pattern := range n.ExcludeMounts {\n\t\t\tcompiled, err := regexp.Compile(pattern)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to compile exclude mount pattern %q: %w\", pattern, err)\n\t\t\t}\n\t\t\tn.excludeMountRegex = append(n.excludeMountRegex, compiled)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *NFSClient) Gather(acc telegraf.Accumulator) error {\n\tif _, err := os.Stat(n.mountstatsPath); os.IsNotExist(err) {\n\t\treturn err\n\t}\n\n\t// Attempt to read the file to see if we have permissions before opening\n\t// which can lead to a panic\n\tif _, err := os.ReadFile(n.mountstatsPath); err != nil {\n\t\treturn err\n\t}\n\n\tfile, err := os.Open(n.mountstatsPath)\n\tif err != nil {\n\t\tn.Log.Errorf(\"Failed opening the %q file: %v \", file.Name(), err)\n\t\treturn err\n\t}\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\tif err := n.processText(scanner, acc); err != nil {\n\t\treturn err\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (n *NFSClient) parseStat(mountpoint, export, version string, line []string, acc telegraf.Accumulator) error {\n\ttags := map[string]string{\"mountpoint\": mountpoint, \"serverexport\": export}\n\tnline, err := convertToUint64(line)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(nline) == 0 {\n\t\tn.Log.Warnf(\"Parsing Stat line with one field: %s\\n\", line)\n\t\treturn nil\n\t}\n\n\tfirst := strings.Replace(line[0], \":\", \"\", 1)\n\n\tvar eventsFields = []string{\n\t\t\"inoderevalidates\",\n\t\t\"dentryrevalidates\",\n\t\t\"datainvalidates\",\n\t\t\"attrinvalidates\",\n\t\t\"vfsopen\",\n\t\t\"vfslookup\",\n\t\t\"vfsaccess\",\n\t\t\"vfsupdatepage\",\n\t\t\"vfsreadpage\",\n\t\t\"vfsreadpages\",\n\t\t\"vfswritepage\",\n\t\t\"vfswritepages\",\n\t\t\"vfsgetdents\",\n\t\t\"vfssetattr\",\n\t\t\"vfsflush\",\n\t\t\"vfsfsync\",\n\t\t\"vfslock\",\n\t\t\"vfsrelease\",\n\t\t\"congestionwait\",\n\t\t\"setattrtrunc\",\n\t\t\"extendwrite\",\n\t\t\"sillyrenames\",\n\t\t\"shortreads\",\n\t\t\"shortwrites\",\n\t\t\"delay\",\n\t\t\"pnfsreads\",\n\t\t\"pnfswrites\",\n\t}\n\n\tvar bytesFields = []string{\n\t\t\"normalreadbytes\",\n\t\t\"normalwritebytes\",\n\t\t\"directreadbytes\",\n\t\t\"directwritebytes\",\n\t\t\"serverreadbytes\",\n\t\t\"serverwritebytes\",\n\t\t\"readpages\",\n\t\t\"writepages\",\n\t}\n\n\tvar xprtudpFields = []string{\n\t\t\"bind_count\",\n\t\t\"rpcsends\",\n\t\t\"rpcreceives\",\n\t\t\"badxids\",\n\t\t\"inflightsends\",\n\t\t\"backlogutil\",\n\t}\n\n\tvar xprttcpFields = []string{\n\t\t\"bind_count\",\n\t\t\"connect_count\",\n\t\t\"connect_time\",\n\t\t\"idle_time\",\n\t\t\"rpcsends\",\n\t\t\"rpcreceives\",\n\t\t\"badxids\",\n\t\t\"inflightsends\",\n\t\t\"backlogutil\",\n\t}\n\n\tvar nfsopFields = []string{\n\t\t\"ops\",\n\t\t\"trans\",\n\t\t\"timeouts\",\n\t\t\"bytes_sent\",\n\t\t\"bytes_recv\",\n\t\t\"queue_time\",\n\t\t\"response_time\",\n\t\t\"total_time\",\n\t\t\"errors\",\n\t}\n\n\tvar fields = make(map[string]interface{})\n\n\tswitch first {\n\tcase \"READ\", \"WRITE\":\n\t\tfields[\"ops\"] = nline[0]\n\t\tfields[\"retrans\"] = nline[1] - nline[0]\n\t\tfields[\"bytes\"] = nline[3] + nline[4]\n\t\tfields[\"rtt\"] = nline[6]\n\t\tfields[\"exe\"] = nline[7]\n\t\tfields[\"rtt_per_op\"] = 0.0\n\t\tif nline[0] > 0 {\n\t\t\tfields[\"rtt_per_op\"] = float64(nline[6]) / float64(nline[0])\n\t\t}\n\t\ttags[\"operation\"] = first\n\t\tacc.AddFields(\"nfsstat\", fields, tags)\n\t}\n\n\tif n.Fullstat {\n\t\tswitch first {\n\t\tcase \"events\":\n\t\t\tif len(nline) >= len(eventsFields) {\n\t\t\t\tfor i, t := range eventsFields {\n\t\t\t\t\tfields[t] = nline[i]\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"nfs_events\", fields, tags)\n\t\t\t}\n\n\t\tcase \"bytes\":\n\t\t\tif len(nline) >= len(bytesFields) {\n\t\t\t\tfor i, t := range bytesFields {\n\t\t\t\t\tfields[t] = nline[i]\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"nfs_bytes\", fields, tags)\n\t\t\t}\n\n\t\tcase \"xprt\":\n\t\t\tif len(line) > 1 {\n\t\t\t\tswitch line[1] {\n\t\t\t\tcase \"tcp\":\n\t\t\t\t\tif len(nline)+2 >= len(xprttcpFields) {\n\t\t\t\t\t\tfor i, t := range xprttcpFields {\n\t\t\t\t\t\t\tfields[t] = nline[i+2]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tacc.AddFields(\"nfs_xprt_tcp\", fields, tags)\n\t\t\t\t\t}\n\t\t\t\tcase \"udp\":\n\t\t\t\t\tif len(nline)+2 >= len(xprtudpFields) {\n\t\t\t\t\t\tfor i, t := range xprtudpFields {\n\t\t\t\t\t\t\tfields[t] = nline[i+2]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tacc.AddFields(\"nfs_xprt_udp\", fields, tags)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (version == \"3\" && n.nfs3Ops[first]) || (version == \"4\" && n.nfs4Ops[first]) {\n\t\t\ttags[\"operation\"] = first\n\t\t\tif len(nline) <= len(nfsopFields) {\n\t\t\t\tfor i, t := range nline {\n\t\t\t\t\tfields[nfsopFields[i]] = t\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"nfs_ops\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *NFSClient) processText(scanner *bufio.Scanner, acc telegraf.Accumulator) error {\n\tvar mount string\n\tvar version string\n\tvar export string\n\tvar skip bool\n\n\tfor scanner.Scan() {\n\t\tline := strings.Fields(scanner.Text())\n\t\tlineLength := len(line)\n\n\t\tif lineLength == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tskip = false\n\n\t\t// This denotes a new mount has been found, so set\n\t\t// mount and export, and stop skipping (for now)\n\t\tif lineLength > 4 && choice.Contains(\"fstype\", line) && (choice.Contains(\"nfs\", line) || choice.Contains(\"nfs4\", line)) {\n\t\t\tmount = line[4]\n\t\t\texport = line[1]\n\t\t} else if lineLength > 5 && (choice.Contains(\"(nfs)\", line) || choice.Contains(\"(nfs4)\", line)) {\n\t\t\tversion = strings.Split(line[5], \"/\")[1]\n\t\t}\n\n\t\tif mount == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check include patterns using compiled regex\n\t\tif len(n.includeMountRegex) > 0 {\n\t\t\tskip = true\n\t\t\tfor _, regex := range n.includeMountRegex {\n\t\t\t\tif regex.MatchString(mount) {\n\t\t\t\t\tskip = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check exclude patterns using compiled regex\n\t\tif !skip && len(n.excludeMountRegex) > 0 {\n\t\t\tfor _, regex := range n.excludeMountRegex {\n\t\t\t\tif regex.MatchString(mount) {\n\t\t\t\t\tskip = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !skip {\n\t\t\terr := n.parseStat(mount, export, version, line, acc)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"could not parseStat: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *NFSClient) getMountStatsPath() string {\n\tpath := \"/proc/self/mountstats\"\n\tif os.Getenv(\"MOUNT_PROC\") != \"\" {\n\t\tpath = os.Getenv(\"MOUNT_PROC\")\n\t}\n\tn.Log.Debugf(\"using [%s] for mountstats\", path)\n\treturn path\n}\n\nfunc convertToUint64(line []string) ([]uint64, error) {\n\t/* A \"line\" of input data (a pre-split array of strings) is\n\t   processed one field at a time.  Each field is converted to\n\t   an uint64 value, and appended to an array of return values.\n\t   On an error, check for ErrRange, and returns an error\n\t   if found.  This situation indicates a pretty major issue in\n\t   the /proc/self/mountstats file, and returning faulty data\n\t   is worse than no data.  Other errors are ignored, and append\n\t   whatever we got in the first place (probably 0).\n\t   Yes, this is ugly. */\n\n\tif len(line) < 2 {\n\t\treturn nil, nil\n\t}\n\n\tnline := make([]uint64, 0, len(line[1:]))\n\t// Skip the first field; it's handled specially as the \"first\" variable\n\tfor _, l := range line[1:] {\n\t\tval, err := strconv.ParseUint(l, 10, 64)\n\t\tif err != nil {\n\t\t\tvar numError *strconv.NumError\n\t\t\tif errors.As(err, &numError) {\n\t\t\t\tif errors.Is(numError.Err, strconv.ErrRange) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"errrange: line:[%v] raw:[%v] -> parsed:[%v]\", line, l, val)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tnline = append(nline, val)\n\t}\n\treturn nline, nil\n}\n\nfunc init() {\n\tinputs.Add(\"nfsclient\", func() telegraf.Input {\n\t\treturn &NFSClient{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nfsclient/nfsclient_test.go",
    "content": "package nfsclient\n\nimport (\n\t\"bufio\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc getMountStatsPath() string {\n\tpath := \"./testdata/mountstats\"\n\tif os.Getenv(\"MOUNT_PROC\") != \"\" {\n\t\tpath = os.Getenv(\"MOUNT_PROC\")\n\t}\n\n\treturn path\n}\n\nfunc TestNFSClientParsev3(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnfsclient := NFSClient{Fullstat: true}\n\tnfsclient.nfs3Ops = map[string]bool{\"READLINK\": true, \"GETATTR\": false}\n\tnfsclient.nfs4Ops = map[string]bool{\"READLINK\": true, \"GETATTR\": false}\n\tdata := strings.Fields(\"         READLINK: 500 501 502 503 504 505 506 507\")\n\terr := nfsclient.parseStat(\"1.2.3.4:/storage/NFS\", \"/A\", \"3\", data, &acc)\n\trequire.NoError(t, err)\n\n\tfieldsOps := map[string]interface{}{\n\t\t\"ops\":           uint64(500),\n\t\t\"trans\":         uint64(501),\n\t\t\"timeouts\":      uint64(502),\n\t\t\"bytes_sent\":    uint64(503),\n\t\t\"bytes_recv\":    uint64(504),\n\t\t\"queue_time\":    uint64(505),\n\t\t\"response_time\": uint64(506),\n\t\t\"total_time\":    uint64(507),\n\t}\n\tacc.AssertContainsFields(t, \"nfs_ops\", fieldsOps)\n}\n\nfunc TestNFSClientParsev4(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnfsclient := NFSClient{Fullstat: true}\n\tnfsclient.nfs3Ops = map[string]bool{\"DESTROY_SESSION\": true, \"GETATTR\": false}\n\tnfsclient.nfs4Ops = map[string]bool{\"DESTROY_SESSION\": true, \"GETATTR\": false}\n\tdata := strings.Fields(\"    DESTROY_SESSION: 500 501 502 503 504 505 506 507\")\n\terr := nfsclient.parseStat(\"2.2.2.2:/nfsdata/\", \"/B\", \"4\", data, &acc)\n\trequire.NoError(t, err)\n\n\tfieldsOps := map[string]interface{}{\n\t\t\"ops\":           uint64(500),\n\t\t\"trans\":         uint64(501),\n\t\t\"timeouts\":      uint64(502),\n\t\t\"bytes_sent\":    uint64(503),\n\t\t\"bytes_recv\":    uint64(504),\n\t\t\"queue_time\":    uint64(505),\n\t\t\"response_time\": uint64(506),\n\t\t\"total_time\":    uint64(507),\n\t}\n\tacc.AssertContainsFields(t, \"nfs_ops\", fieldsOps)\n}\n\nfunc TestNFSClientParseLargeValue(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnfsclient := NFSClient{Fullstat: true}\n\tnfsclient.nfs3Ops = map[string]bool{\"SETCLIENTID\": true, \"GETATTR\": false}\n\tnfsclient.nfs4Ops = map[string]bool{\"SETCLIENTID\": true, \"GETATTR\": false}\n\tdata := strings.Fields(\"    SETCLIENTID: 218 216 0 53568 12960 18446744073709531008 134 197\")\n\terr := nfsclient.parseStat(\"2.2.2.2:/nfsdata/\", \"/B\", \"4\", data, &acc)\n\trequire.NoError(t, err)\n\n\tfieldsOps := map[string]interface{}{\n\t\t\"ops\":           uint64(218),\n\t\t\"trans\":         uint64(216),\n\t\t\"timeouts\":      uint64(0),\n\t\t\"bytes_sent\":    uint64(53568),\n\t\t\"bytes_recv\":    uint64(12960),\n\t\t\"queue_time\":    uint64(18446744073709531008),\n\t\t\"response_time\": uint64(134),\n\t\t\"total_time\":    uint64(197),\n\t}\n\tacc.AssertContainsFields(t, \"nfs_ops\", fieldsOps)\n}\n\nfunc TestNFSClientProcessStat(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnfsclient := NFSClient{}\n\tnfsclient.Fullstat = false\n\n\tfile, err := os.Open(getMountStatsPath())\n\trequire.NoError(t, err)\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\n\terr = nfsclient.processText(scanner, &acc)\n\trequire.NoError(t, err)\n\n\tfieldsReadstat := map[string]interface{}{\n\t\t\"ops\":        uint64(600),\n\t\t\"retrans\":    uint64(1),\n\t\t\"bytes\":      uint64(1207),\n\t\t\"rtt\":        uint64(606),\n\t\t\"exe\":        uint64(607),\n\t\t\"rtt_per_op\": float64(1.01),\n\t}\n\n\treadTags := map[string]string{\n\t\t\"serverexport\": \"1.2.3.4:/storage/NFS\",\n\t\t\"mountpoint\":   \"/A\",\n\t\t\"operation\":    \"READ\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"nfsstat\", fieldsReadstat, readTags)\n\n\tfieldsWritestat := map[string]interface{}{\n\t\t\"ops\":        uint64(700),\n\t\t\"retrans\":    uint64(1),\n\t\t\"bytes\":      uint64(1407),\n\t\t\"rtt\":        uint64(706),\n\t\t\"exe\":        uint64(707),\n\t\t\"rtt_per_op\": float64(1.0085714285714287),\n\t}\n\n\twriteTags := map[string]string{\n\t\t\"serverexport\": \"1.2.3.4:/storage/NFS\",\n\t\t\"mountpoint\":   \"/A\",\n\t\t\"operation\":    \"WRITE\",\n\t}\n\tacc.AssertContainsTaggedFields(t, \"nfsstat\", fieldsWritestat, writeTags)\n}\n\nfunc TestNFSClientProcessFull(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tnfsclient := NFSClient{}\n\tnfsclient.Fullstat = true\n\n\tfile, err := os.Open(getMountStatsPath())\n\trequire.NoError(t, err)\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\n\terr = nfsclient.processText(scanner, &acc)\n\trequire.NoError(t, err)\n\n\tfieldsEvents := map[string]interface{}{\n\t\t\"inoderevalidates\":  uint64(301736),\n\t\t\"dentryrevalidates\": uint64(22838),\n\t\t\"datainvalidates\":   uint64(410979),\n\t\t\"attrinvalidates\":   uint64(26188427),\n\t\t\"vfsopen\":           uint64(27525),\n\t\t\"vfslookup\":         uint64(9140),\n\t\t\"vfsaccess\":         uint64(114420),\n\t\t\"vfsupdatepage\":     uint64(30785253),\n\t\t\"vfsreadpage\":       uint64(5308856),\n\t\t\"vfsreadpages\":      uint64(5364858),\n\t\t\"vfswritepage\":      uint64(30784819),\n\t\t\"vfswritepages\":     uint64(79832668),\n\t\t\"vfsgetdents\":       uint64(170),\n\t\t\"vfssetattr\":        uint64(64),\n\t\t\"vfsflush\":          uint64(18194),\n\t\t\"vfsfsync\":          uint64(29294718),\n\t\t\"vfslock\":           uint64(0),\n\t\t\"vfsrelease\":        uint64(18279),\n\t\t\"congestionwait\":    uint64(0),\n\t\t\"setattrtrunc\":      uint64(2),\n\t\t\"extendwrite\":       uint64(785551),\n\t\t\"sillyrenames\":      uint64(0),\n\t\t\"shortreads\":        uint64(0),\n\t\t\"shortwrites\":       uint64(0),\n\t\t\"delay\":             uint64(0),\n\t\t\"pnfsreads\":         uint64(0),\n\t\t\"pnfswrites\":        uint64(0),\n\t}\n\tfieldsBytes := map[string]interface{}{\n\t\t\"normalreadbytes\":  uint64(204440464584),\n\t\t\"normalwritebytes\": uint64(110857586443),\n\t\t\"directreadbytes\":  uint64(783170354688),\n\t\t\"directwritebytes\": uint64(296174954496),\n\t\t\"serverreadbytes\":  uint64(1134399088816),\n\t\t\"serverwritebytes\": uint64(407107155723),\n\t\t\"readpages\":        uint64(85749323),\n\t\t\"writepages\":       uint64(30784819),\n\t}\n\tfieldsXprtTCP := map[string]interface{}{\n\t\t\"bind_count\":    uint64(1),\n\t\t\"connect_count\": uint64(1),\n\t\t\"connect_time\":  uint64(0),\n\t\t\"idle_time\":     uint64(0),\n\t\t\"rpcsends\":      uint64(96172963),\n\t\t\"rpcreceives\":   uint64(96172963),\n\t\t\"badxids\":       uint64(0),\n\t\t\"inflightsends\": uint64(620878754),\n\t\t\"backlogutil\":   uint64(0),\n\t}\n\n\tacc.AssertContainsFields(t, \"nfs_events\", fieldsEvents)\n\tacc.AssertContainsFields(t, \"nfs_bytes\", fieldsBytes)\n\tacc.AssertContainsFields(t, \"nfs_xprt_tcp\", fieldsXprtTCP)\n}\n\nfunc TestNFSClientFileDoesNotExist(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tnfsclient := NFSClient{Fullstat: true}\n\tnfsclient.mountstatsPath = \"/does_not_exist\"\n\trequire.Error(t, nfsclient.Gather(&acc))\n}\n\nfunc TestNFSClientProcessTextWithIncludeExclude(t *testing.T) {\n\t// Test cases for different include/exclude scenarios\n\ttestCases := []struct {\n\t\tname             string\n\t\tincludeMounts    []string\n\t\texcludeMounts    []string\n\t\texpectedMounts   []string\n\t\tunexpectedMounts []string\n\t}{\n\t\t{\n\t\t\tname:           \"No filters\",\n\t\t\tincludeMounts:  nil,\n\t\t\texcludeMounts:  nil,\n\t\t\texpectedMounts: []string{\"/A\", \"/B\"}, // All mounts should be included\n\t\t},\n\t\t{\n\t\t\tname:             \"Exclude one mount\",\n\t\t\tincludeMounts:    nil,\n\t\t\texcludeMounts:    []string{\"^/A$\"},\n\t\t\texpectedMounts:   []string{\"/B\"},\n\t\t\tunexpectedMounts: []string{\"/A\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"Include one mount\",\n\t\t\tincludeMounts:    []string{\"^/A$\"},\n\t\t\texcludeMounts:    nil,\n\t\t\texpectedMounts:   []string{\"/A\"},\n\t\t\tunexpectedMounts: []string{\"/B\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"Include and exclude with regex\",\n\t\t\tincludeMounts:    []string{\"^/\"},\n\t\t\texcludeMounts:    []string{\"^/A$\"},\n\t\t\texpectedMounts:   []string{\"/B\"},\n\t\t\tunexpectedMounts: []string{\"/A\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"Exclude with prefix pattern\",\n\t\t\tincludeMounts:    nil,\n\t\t\texcludeMounts:    []string{\"^/A\"},\n\t\t\texpectedMounts:   []string{\"/B\"},\n\t\t\tunexpectedMounts: []string{\"/A\"},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t// Create NFS client with test configuration\n\t\t\tnfsclient := NFSClient{\n\t\t\t\tIncludeMounts: tc.includeMounts,\n\t\t\t\tExcludeMounts: tc.excludeMounts,\n\t\t\t\tFullstat:      true,\n\t\t\t\tLog:           testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, nfsclient.Init())\n\n\t\t\t// Open the test data\n\t\t\tfile, err := os.Open(getMountStatsPath())\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer file.Close()\n\n\t\t\tscanner := bufio.NewScanner(file)\n\n\t\t\t// Process the data\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, nfsclient.processText(scanner, &acc))\n\n\t\t\t// Verify expected mounts are present\n\t\t\tfor _, mount := range tc.expectedMounts {\n\t\t\t\tfound := false\n\t\t\t\tfor _, metric := range acc.Metrics {\n\t\t\t\t\tif mountpoint, exists := metric.Tags[\"mountpoint\"]; exists && mountpoint == mount {\n\t\t\t\t\t\tfound = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trequire.True(t, found, \"Expected mount %s not found\", mount)\n\t\t\t}\n\n\t\t\t// Verify unexpected mounts are absent\n\t\t\tfor _, mount := range tc.unexpectedMounts {\n\t\t\t\tfound := false\n\t\t\t\tfor _, metric := range acc.Metrics {\n\t\t\t\t\tif mountpoint, exists := metric.Tags[\"mountpoint\"]; exists && mountpoint == mount {\n\t\t\t\t\t\tfound = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trequire.False(t, found, \"Unexpected mount %s found\", mount)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestNFSClientInvalidIncludeRegex(t *testing.T) {\n\t// Test that invalid include regex patterns are properly reported as errors during Init\n\tnfsclient := &NFSClient{\n\t\tIncludeMounts: []string{\"[invalid\"},\n\t\tExcludeMounts: nil,\n\t\tFullstat:      true,\n\t\tLog:           testutil.Logger{},\n\t}\n\n\t// Init should fail with an error due to invalid regex\n\terr := nfsclient.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"failed to compile include mount pattern\")\n}\n\nfunc TestNFSClientInvalidExcludeRegex(t *testing.T) {\n\t// Test that invalid exclude regex patterns are properly reported as errors during Init\n\tnfsclient := &NFSClient{\n\t\tIncludeMounts: nil,\n\t\tExcludeMounts: []string{\"[also-invalid\"},\n\t\tFullstat:      true,\n\t\tLog:           testutil.Logger{},\n\t}\n\n\t// Init should fail with an error due to invalid regex\n\terr := nfsclient.Init()\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"failed to compile exclude mount pattern\")\n}\n"
  },
  {
    "path": "plugins/inputs/nfsclient/sample.conf",
    "content": "# Read per-mount NFS client metrics from /proc/self/mountstats\n[[inputs.nfsclient]]\n  ## Read more low-level metrics (optional, defaults to false)\n  # fullstat = false\n\n  ## List of mounts to explicitly include or exclude (optional)\n  ## The pattern (Go regexp) is matched against the mount point (not the\n  ## device being mounted).  If include_mounts is set, all mounts are ignored\n  ## unless present in the list. If a mount is listed in both include_mounts\n  ## and exclude_mounts, it is excluded.  Go regexp patterns can be used.\n  # include_mounts = []\n  # exclude_mounts = []\n\n  ## List of operations to include or exclude from collecting.  This applies\n  ## only when fullstat=true.  Semantics are similar to {include,exclude}_mounts:\n  ## the default is to collect everything; when include_operations is set, only\n  ## those OPs are collected; when exclude_operations is set, all are collected\n  ## except those listed.  If include and exclude are set, the OP is excluded.\n  ## See /proc/self/mountstats for a list of valid operations; note that\n  ## NFSv3 and NFSv4 have different lists.  While it is not possible to\n  ## have different include/exclude lists for NFSv3/4, unused elements\n  ## in the list should be okay.  It is possible to have different lists\n  ## for different mountpoints:  use multiple [[input.nfsclient]] stanzas,\n  ## with their own lists.  See \"include_mounts\" above, and be careful of\n  ## duplicate metrics.\n  # include_operations = []\n  # exclude_operations = []\n"
  },
  {
    "path": "plugins/inputs/nfsclient/testdata/mountstats",
    "content": "device rootfs mounted on / with fstype rootfs\ndevice proc mounted on /proc with fstype proc\ndevice sysfs mounted on /sys with fstype sysfs\ndevice devtmpfs mounted on /dev with fstype devtmpfs\ndevice devpts mounted on /dev/pts with fstype devpts\ndevice tmpfs mounted on /dev/shm with fstype tmpfs\ndevice /dev/loop0 mounted on /dev/.initramfs/live with fstype iso9660\ndevice /dev/loop6 mounted on / with fstype ext4\ndevice /proc/bus/usb mounted on /proc/bus/usb with fstype usbfs\ndevice none mounted on /proc/sys/fs/binfmt_misc with fstype binfmt_misc\ndevice /tmp mounted on /tmp with fstype tmpfs\ndevice /home mounted on /home with fstype tmpfs\ndevice /var mounted on /var with fstype tmpfs\ndevice /etc mounted on /etc with fstype tmpfs\ndevice /dev/ram1 mounted on /root with fstype ext2\ndevice cgroup mounted on /cgroup/cpuset with fstype cgroup\ndevice cgroup mounted on /cgroup/cpu with fstype cgroup\ndevice cgroup mounted on /cgroup/cpuacct with fstype cgroup\ndevice cgroup mounted on /cgroup/memory with fstype cgroup\ndevice cgroup mounted on /cgroup/devices with fstype cgroup\ndevice cgroup mounted on /cgroup/freezer with fstype cgroup\ndevice cgroup mounted on /cgroup/net_cls with fstype cgroup\ndevice cgroup mounted on /cgroup/blkio with fstype cgroup\ndevice sunrpc mounted on /var/lib/nfs/rpc_pipefs with fstype rpc_pipefs\ndevice /etc/auto.misc mounted on /misc with fstype autofs\ndevice -hosts mounted on /net with fstype autofs\ndevice 1.2.3.4:/storage/NFS mounted on /A with fstype nfs statvers=1.1\n    opts:   rw,vers=3,rsize=32768,wsize=32768,namlen=255,acregmin=60,acregmax=60,acdirmin=60,acdirmax=60,hard,nolock,noacl,nordirplus,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=1.2.3.4,mountvers=3,mountport=49193,mountproto=tcp,local_lock=all\n    age:    1136770\n    caps:   caps=0x3fe6,wtmult=512,dtsize=8192,bsize=0,namlen=255\n    sec:    flavor=1,pseudoflavor=1\n    events: 301736 22838 410979 26188427 27525 9140 114420 30785253 5308856 5364858 30784819 79832668 170 64 18194 29294718 0 18279 0 2 785551 0 0 0 0 0 0\n    bytes:  204440464584 110857586443 783170354688 296174954496 1134399088816 407107155723 85749323 30784819\n    RPC iostats version: 1.0  p/v: 100003/3 (nfs)\n    xprt:   tcp 733 1 1 0 0 96172963 96172963 0 620878754 0 690 196347132 524706275\n    per-op statistics\n            NULL: 0 0 0 0 0 0 0 0\n         GETATTR: 100 101 102 103 104 105 106 107\n         SETATTR: 200 201 202 203 204 205 206 207\n          LOOKUP: 300 301 302 303 304 305 306 307\n          ACCESS: 400 401 402 403 404 405 406 407\n        READLINK: 500 501 502 503 504 505 506 507\n            READ: 600 601 602 603 604 605 606 607\n           WRITE: 700 701 702 703 704 705 706 707\n          CREATE: 800 801 802 803 804 805 806 807\n           MKDIR: 900 901 902 903 904 905 906 907\n         SYMLINK: 1000 1001 1002 1003 1004 1005 1006 1007\n           MKNOD: 1100 1101 1102 1103 1104 1105 1106 1107\n          REMOVE: 1200 1201 1202 1203 1204 1205 1206 1207\n           RMDIR: 1300 1301 1302 1303 1304 1305 1306 1307\n          RENAME: 1400 1401 1402 1403 1404 1405 1406 1407\n            LINK: 1500 1501 1502 1503 1504 1505 1506 1507\n         READDIR: 1600 1601 1602 1603 1604 1605 1606 1607\n     READDIRPLUS: 1700 1701 1702 1703 1704 1705 1706 1707\n          FSSTAT: 1800 1801 1802 1803 1804 1805 1806 1807\n          FSINFO: 1900 1901 1902 1903 1904 1905 1906 1907\n        PATHCONF: 2000 2001 2002 2003 2004 2005 2006 2007\n          COMMIT: 2100 2101 2102 2103 2104 2105 2106 2107\n\ndevice 2.2.2.2:/nfsdata/ mounted on /B with fstype nfs4 statvers=1.1\n    opts:    rw,vers=4,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60, acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys, clientaddr=3.3.3.3,minorversion=0,local_lock=none\n    age:    19\n    caps:    caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255\n    nfsv4:    bm0=0xfdffafff,bm1=0xf9be3e,acl=0x0\n    sec:    flavor=1,pseudoflavor=1\n    events:    0 168232 0 0 0 10095 217808 0 2 9797 0 9739 0 0 19739 19739 0 19739 0 0 0 0 0 0 0 0 0\n    bytes:    1612840960 0 0 0 627536112 0 158076 0\n    RPC iostats version: 1.0  p/v: 100003/4 (nfs)\n    xprt:    tcp 737 0 1 0 0 69698 69697 0 81817 0 2 1082 12119\n    per-op statistics\n            NULL: 0 0 0 0 0 0 0 0\n            READ: 9797 9797 0 1000 2000 71 7953 8200\n           WRITE: 0 0 0 0 0 0 0 0\n          COMMIT: 0 0 0 0 0 0 0 0\n            OPEN: 19740 19740 0 4737600 7343280 505 3449 4172\n    OPEN_CONFIRM: 10211 10211 0 1552072 694348 74 836 1008\n     OPEN_NOATTR: 0 0 0 0 0 0 0 0\n    OPEN_DOWNGRADE: 0 0 0 0 0 0 0 0\n           CLOSE: 19739 19739 0 3316152 2605548 334 3045 3620\n         SETATTR: 0 0 0 0 0 0 0 0\n          FSINFO: 1 1 0 132 108 0 0 0\n           RENEW: 0 0 0 0 0 0 0 0\n     SETCLIENTID: 0 0 0 0 0 0 0 0\n    SETCLIENTID_CONFIRM: 0 0 0 0 0 0 0 0\n            LOCK: 0 0 0 0 0 0 0 0\n           LOCKT: 0 0 0 0 0 0 0 0\n           LOCKU: 0 0 0 0 0 0 0 0\n          ACCESS: 96 96 0 14584 19584 0 8 10\n         GETATTR: 1 1 0 132 188 0 0 0\n          LOOKUP: 10095 10095 0 1655576 2382420 36 898 1072\n     LOOKUP_ROOT: 0 0 0 0 0 0 0 0\n          REMOVE: 0 0 0 0 0 0 0 0\n          RENAME: 0 0 0 0 0 0 0 0\n            LINK: 0 0 0 0 0 0 0 0\n         SYMLINK: 0 0 0 0 0 0 0 0\n          CREATE: 0 0 0 0 0 0 0 0\n        PATHCONF: 1 1 0 128 72 0 0 0\n          STATFS: 0 0 0 0 0 0 0 0\n        READLINK: 0 0 0 0 0 0 0 0\n         READDIR: 0 0 0 0 0 0 0 0\n     SERVER_CAPS: 2 2 0 256 176 0 0 0\n     DELEGRETURN: 0 0 0 0 0 0 0 0\n          GETACL: 0 0 0 0 0 0 0 0\n          SETACL: 0 0 0 0 0 0 0 0\n    FS_LOCATIONS: 0 0 0 0 0 0 0 0\n    RELEASE_LOCKOWNER: 0 0 0 0 0 0 0 0\n         SECINFO: 0 0 0 0 0 0 0 0\n     EXCHANGE_ID: 0 0 0 0 0 0 0 0\n    CREATE_SESSION: 0 0 0 0 0 0 0 0\n    DESTROY_SESSION: 500 501 502 503 504 505 506 507\n        SEQUENCE: 0 0 0 0 0 0 0 0\n    GET_LEASE_TIME: 0 0 0 0 0 0 0 0\n    RECLAIM_COMPLETE: 0 0 0 0 0 0 0 0\n       LAYOUTGET: 0 0 0 0 0 0 0 0\n    GETDEVICEINFO: 0 0 0 0 0 0 0 0\n    LAYOUTCOMMIT: 0 0 0 0 0 0 0 0\n\ndevice nfsserver1:/vol/export1/bread_recipes mounted on /C with fstype nfs statvers=1.1\n\topts:\trw,vers=3,rsize=65536,wsize=65536,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=5.4.3.2,mountvers=3,mountport=635,mountproto=udp,local_lock=none\n\tage:\t1084700\n\tcaps:\tcaps=0x3fc7,wtmult=512,dtsize=32768,bsize=0,namlen=255\n\tsec:\tflavor=1,pseudoflavor=1\n\tevents:\t145712 48345501 0 2476 804 1337 49359047 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\tbytes:\t0 0 0 0 0 0 0 0\n\tRPC iostats version: 1.0  p/v: 100003/3 (nfs)\n\txprt:\ttcp 871 1 1 0 0 181124336 181124308 28 1971647851 0 1100 807885669 90279840\n\tper-op statistics\n\t        NULL: 1 2 0 44 24 0 0 0\n\t     GETATTR: 145712 145712 0 22994472 16319744 532 107480 109969\n\t     SETATTR: 0 0 0 0 0 0 0 0\n\t      LOOKUP: 2553 2553 0 385932 476148 9 1695 1739\n\t      ACCESS: 596338 596338 0 79281020 71560560 2375 228286 237993\n\t    READLINK: 0 0 0 0 0 0 0 0\n\t        READ: 0 0 0 0 0 0 0 0\n\t       WRITE: 0 0 0 0 0 0 0 0\n\t      CREATE: 0 0 0 0 0 0 0 0\n\t       MKDIR: 0 0 0 0 0 0 0 0\n\t     SYMLINK: 0 0 0 0 0 0 0 0\n\t       MKNOD: 0 0 0 0 0 0 0 0\n\t      REMOVE: 0 0 0 0 0 0 0 0\n\t       RMDIR: 0 0 0 0 0 0 0 0\n\t      RENAME: 0 0 0 0 0 0 0 0\n\t        LINK: 0 0 0 0 0 0 0 0\n\t     READDIR: 0 0 0 0 0 0 0 0\n\t READDIRPLUS: 0 0 0 0 0 0 0 0\n\t      FSSTAT: 1698 1698 0 250080 285264 6 929 951\n\t      FSINFO: 34 34 0 4352 5576 0 5 5\n\t    PATHCONF: 1 1 0 128 140 0 0 0\n\t      COMMIT: 0 0 0 0 0 0 0 0\n\ndevice nfsserver2:/tank/os2warp mounted on /D with fstype nfs4 statvers=1.1\n\topts:\trw,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.66.88.239,local_lock=none\n\tage:\t2\n\timpl_id:\tname='',domain='',date='0,0'\n\tcaps:\tcaps=0xffbfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255\n\tnfsv4:\tbm0=0xfdffafff,bm1=0x40f9be3e,bm2=0x28803,acl=0x0,sessions,pnfs=not configured,lease_time=90,lease_expired=0\n\tsec:\tflavor=1,pseudoflavor=1\n\tevents:\t1 112 0 0 1 3 117 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\tbytes:\t0 0 0 0 0 0 0 0\n\tRPC iostats version: 1.1  p/v: 100003/4 (nfs)\n\txprt:\ttcp 763 0 2 0 2 39 39 0 42 0 2 0 3\n\tper-op statistics\n\t        NULL: 1 1 0 44 24 0 0 1 0\n\t        READ: 0 0 0 0 0 0 0 0 0\n\t       WRITE: 0 0 0 0 0 0 0 0 0\n\t      COMMIT: 0 0 0 0 0 0 0 0 0\n\t        OPEN: 0 0 0 0 0 0 0 0 0\n\tOPEN_CONFIRM: 0 0 0 0 0 0 0 0 0\n\t OPEN_NOATTR: 0 0 0 0 0 0 0 0 0\n\tOPEN_DOWNGRADE: 0 0 0 0 0 0 0 0 0\n\t       CLOSE: 0 0 0 0 0 0 0 0 0\n\t     SETATTR: 0 0 0 0 0 0 0 0 0\n\t      FSINFO: 1 1 0 168 164 0 0 0 0\n\t       RENEW: 0 0 0 0 0 0 0 0 0\n\t SETCLIENTID: 0 0 0 0 0 0 0 0 0\n\tSETCLIENTID_CONFIRM: 0 0 0 0 0 0 0 0 0\n\t        LOCK: 0 0 0 0 0 0 0 0 0\n\t       LOCKT: 0 0 0 0 0 0 0 0 0\n\t       LOCKU: 0 0 0 0 0 0 0 0 0\n\t      ACCESS: 3 3 0 600 504 0 1 1 0\n\t     GETATTR: 2 2 0 364 480 0 1 1 0\n\t      LOOKUP: 3 3 0 628 484 0 1 1 2\n\t LOOKUP_ROOT: 0 0 0 0 0 0 0 0 0\n\t      REMOVE: 0 0 0 0 0 0 0 0 0\n\t      RENAME: 0 0 0 0 0 0 0 0 0\n\t        LINK: 0 0 0 0 0 0 0 0 0\n\t     SYMLINK: 0 0 0 0 0 0 0 0 0\n\t      CREATE: 0 0 0 0 0 0 0 0 0\n\t    PATHCONF: 1 1 0 160 116 0 0 0 0\n\t      STATFS: 1 1 0 164 160 0 0 0 0\n\t    READLINK: 0 0 0 0 0 0 0 0 0\n\t     READDIR: 1 1 0 224 11968 0 1 1 0\n\t SERVER_CAPS: 2 2 0 336 328 0 1 1 0\n\t DELEGRETURN: 0 0 0 0 0 0 0 0 0\n\t      GETACL: 0 0 0 0 0 0 0 0 0\n\t      SETACL: 0 0 0 0 0 0 0 0 0\n\tFS_LOCATIONS: 0 0 0 0 0 0 0 0 0\n\tRELEASE_LOCKOWNER: 0 0 0 0 0 0 0 0 0\n\t     SECINFO: 0 0 0 0 0 0 0 0 0\n\tFSID_PRESENT: 0 0 0 0 0 0 0 0 0\n\t EXCHANGE_ID: 2 2 0 480 200 0 2 2 0\n\tCREATE_SESSION: 1 1 0 200 124 0 0 0 0\n\tDESTROY_SESSION: 0 0 0 0 0 0 0 0 0\n\t    SEQUENCE: 0 0 0 0 0 0 0 0 0\n\tGET_LEASE_TIME: 0 0 0 0 0 0 0 0 0\n\tRECLAIM_COMPLETE: 1 1 0 128 88 0 107 107 0\n\t   LAYOUTGET: 0 0 0 0 0 0 0 0 0\n\tGETDEVICEINFO: 0 0 0 0 0 0 0 0 0\n\tLAYOUTCOMMIT: 0 0 0 0 0 0 0 0 0\n\tLAYOUTRETURN: 0 0 0 0 0 0 0 0 0\n\tSECINFO_NO_NAME: 0 0 0 0 0 0 0 0 0\n\tTEST_STATEID: 0 0 0 0 0 0 0 0 0\n\tFREE_STATEID: 0 0 0 0 0 0 0 0 0\n\tGETDEVICELIST: 0 0 0 0 0 0 0 0 0\n\tBIND_CONN_TO_SESSION: 0 0 0 0 0 0 0 0 0\n\tDESTROY_CLIENTID: 0 0 0 0 0 0 0 0 0\n\t        SEEK: 0 0 0 0 0 0 0 0 0\n\t    ALLOCATE: 0 0 0 0 0 0 0 0 0\n\t  DEALLOCATE: 0 0 0 0 0 0 0 0 0\n\t LAYOUTSTATS: 0 0 0 0 0 0 0 0 0\n\t       CLONE: 0 0 0 0 0 0 0 0 0\n\t        COPY: 0 0 0 0 0 0 0 0 0\n\tOFFLOAD_CANCEL: 0 0 0 0 0 0 0 0 0\n\t     LOOKUPP: 0 0 0 0 0 0 0 0 0\n\t LAYOUTERROR: 0 0 0 0 0 0 0 0 0\n\t COPY_NOTIFY: 0 0 0 0 0 0 0 0 0\n\t    GETXATTR: 0 0 0 0 0 0 0 0 0\n\t    SETXATTR: 0 0 0 0 0 0 0 0 0\n\t  LISTXATTRS: 0 0 0 0 0 0 0 0 0\n\t REMOVEXATTR: 0 0 0 0 0 0 0 0 0\n        LAYOUTRETURN: 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "plugins/inputs/nftables/README.md",
    "content": "# Nftables Plugin\n\nThis plugin gathers packets and bytes counters for rules within\nLinux's [nftables][nftables] firewall, as well as set element counts.\n\n⭐ Telegraf v1.37.0\n🏷️ network, system\n💻 linux\n\n[nftables]: https://wiki.nftables.org/wiki-nftables/index.php/Main_Page\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n[[inputs.nftables]]\n  ## Use the specified binary which will be looked-up in PATH\n  # binary = \"nft\"\n\n  ## Use sudo for command execution, can be restricted to\n  ## \"nft --json list table\"\n  # use_sudo = false\n\n  ## Tables to monitor (may use \"family table\" format, e.g., \"inet filter\")\n  # tables = [ \"filter\" ]\n\n  ## Kinds of objects to monitor: \"counters\" (named counters), \"sets\",\n  ## (named sets), \"anonymous-counters\" (on commented rules).\n  # include = [\"anonymous-counters\"]\n```\n\nSince telegraf will fork a process to run nftables, `AmbientCapabilities` is\nrequired to transmit the capabilities bounding set to the forked process.\n\n### Using sudo\n\nYou may edit your sudo configuration with the following:\n\n```sudo\ntelegraf ALL=(root) NOPASSWD: /usr/bin/nft --json list table *\n```\n\n## Metrics\n\nCounters (when `counters` included):\n\n* nftables\n  * tags:\n    * table\n    * counter\n  * fields:\n    * pkts (integer, count)\n    * bytes (integer, bytes)\n\nSets (when `sets` included):\n\n* nftables\n  * tags:\n    * table\n    * set\n  * field:\n    * count (integer, count)\n\nAnonymous counters on commented rules (when `anonymous-counters` included):\n\n* nftables\n  * tags:\n    * table\n    * chain\n    * rule -- comment associated to the rule\n  * fields:\n    * pkts (integer, count)\n    * bytes (integer, bytes)\n\n## Example Output\n\n```text\n> nftables,host=my_hostname,counter=my_counter,table=filter bytes=48968i,pkts=48i 1757367516000000000\n> nftables,host=my_hostname,set=my_set,table=filter count=10i 1757367516000000000\n> nftables,chain=incoming,host=my_hostname,rule=comment_val_1,table=filter bytes=66435845i,pkts=133882i 1757367516000000000\n> nftables,chain=outgoing,host=my_hostname,rule=comment_val_2,table=filter bytes=25596512i,pkts=145129i 1757367516000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nftables/nftables.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage nftables\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Nftables struct {\n\tUseSudo bool     `toml:\"use_sudo\"`\n\tBinary  string   `toml:\"binary\"`\n\tTables  []string `toml:\"tables\"`\n\tInclude []string `toml:\"include\"`\n\n\targs []string\n}\n\nfunc (*Nftables) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Nftables) Init() error {\n\t// Set defaults\n\tif len(n.Tables) == 0 {\n\t\tn.Tables = []string{\"filter\"}\n\t}\n\tif n.Binary == \"\" {\n\t\tn.Binary = \"nft\"\n\t}\n\tif len(n.Include) == 0 {\n\t\tn.Include = []string{\"anonymous-counters\"}\n\t}\n\n\t// Check includes\n\tincludesSet := make(map[string]bool, len(n.Include))\n\tfor _, include := range n.Include {\n\t\tif includesSet[include] {\n\t\t\treturn fmt.Errorf(\"duplicate include %q\", include)\n\t\t}\n\t\tincludesSet[include] = true\n\t\tswitch include {\n\t\tcase \"anonymous-counters\", \"counters\", \"sets\":\n\t\t\t// Do nothing, those are valid\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown include %q\", include)\n\t\t}\n\t}\n\n\t// Construct the command\n\tn.args = make([]string, 0, 3)\n\tif n.UseSudo {\n\t\tn.args = append(n.args, n.Binary)\n\t\tn.Binary = \"sudo\"\n\t}\n\tn.args = append(n.args, \"--json\", \"list\", \"table\")\n\treturn nil\n}\n\nfunc (n *Nftables) Gather(acc telegraf.Accumulator) error {\n\tfor _, table := range n.Tables {\n\t\tacc.AddError(n.gatherTable(acc, table))\n\t}\n\treturn nil\n}\n\nfunc (n *Nftables) gatherTable(acc telegraf.Accumulator, name string) error {\n\t// Run the nft command\n\targs := append(n.args, name)\n\tc := exec.Command(n.Binary, args...)\n\tout, err := c.Output()\n\tif err != nil {\n\t\tvar oserr *exec.ExitError\n\t\tif errors.As(err, &oserr) {\n\t\t\tbuf, _, _ := bytes.Cut(oserr.Stderr, []byte(\"\\n\"))\n\t\t\tmsg := string(bytes.TrimSpace(buf))\n\t\t\tif msg == \"Error: No such file or directory\" {\n\t\t\t\treturn fmt.Errorf(\"table %q does not exist\", name)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"error executing nft command: %w (%s)\", err, msg)\n\t\t}\n\t\treturn fmt.Errorf(\"error executing nft command: %w\", err)\n\t}\n\n\t// Parse the result into metrics and add them to the accumulator\n\tvar nftable table\n\tif err := json.Unmarshal(out, &nftable); err != nil {\n\t\treturn fmt.Errorf(\"parsing command output failed: %w\", err)\n\t}\n\n\tfor _, include := range n.Include {\n\t\tswitch include {\n\t\tcase \"anonymous-counters\":\n\t\t\tfor _, rule := range nftable.Rules {\n\t\t\t\tif len(rule.Comment) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor _, expr := range rule.Exprs {\n\t\t\t\t\tif expr.Cntr == nil || expr.Cntr.isNamedRef {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\t\"bytes\": expr.Cntr.Bytes,\n\t\t\t\t\t\t\"pkts\":  expr.Cntr.Packets,\n\t\t\t\t\t}\n\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\"table\": rule.Table,\n\t\t\t\t\t\t\"chain\": rule.Chain,\n\t\t\t\t\t\t\"rule\":  rule.Comment,\n\t\t\t\t\t}\n\t\t\t\t\tacc.AddFields(\"nftables\", fields, tags)\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"counters\":\n\t\t\tfor _, counter := range nftable.Counters {\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"bytes\": counter.Bytes,\n\t\t\t\t\t\"pkts\":  counter.Packets,\n\t\t\t\t}\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"table\":   counter.Table,\n\t\t\t\t\t\"counter\": counter.Name,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"nftables\", fields, tags)\n\t\t\t}\n\t\tcase \"sets\":\n\t\t\tfor _, set := range nftable.Sets {\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"count\": len(set.Elem),\n\t\t\t\t}\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"table\": set.Table,\n\t\t\t\t\t\"set\":   set.Name,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"nftables\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"nftables\", func() telegraf.Input {\n\t\treturn &Nftables{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/nftables_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage nftables\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Nftables struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Nftables) SampleConfig() string { return sampleConfig }\n\nfunc (i *Nftables) Init() error {\n\ti.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Nftables) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"nftables\", func() telegraf.Input {\n\t\treturn &Nftables{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/nftables_test.go",
    "content": "//go:build linux\n\npackage nftables\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"nftables\", func() telegraf.Input {\n\t\treturn &Nftables{}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Determine the executable name of the test-binary used to mock the\n\t\t\t// nft command. See TestMain\n\t\t\texe, err := os.Executable()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Mock the nft executable\n\t\t\tplugin := cfg.Inputs[0].Input.(*Nftables)\n\t\t\tplugin.Binary = exe\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\tplugin.args = append([]string{\"--mock\", \"--testcase\", testcasePath}, plugin.args...)\n\n\t\t\t// Gather the metrics and compare the output\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tactualErrorMsgs := make([]string, 0, len(acc.Errors))\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\t\t\t}\n\t\t\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), options...)\n\t\t})\n\t}\n}\n\nfunc TestMain(m *testing.M) {\n\t// Mimic the nft command line arguments\n\tvar mock, jsonMode bool\n\tvar testcase string\n\tflag.BoolVar(&mock, \"mock\", false, \"run test as mock\")\n\tflag.StringVar(&testcase, \"testcase\", \"\", \"path to the test directory\")\n\tflag.BoolVar(&jsonMode, \"json\", false, \"output as JSON\")\n\tflag.Parse()\n\n\tif !mock {\n\t\t// Run the normal test mode\n\t\tos.Exit(m.Run())\n\t}\n\n\t// Run as a mock program\n\tif !jsonMode {\n\t\tfmt.Fprintln(os.Stderr, \"JSON mode not set\")\n\t\tos.Exit(1)\n\t}\n\n\targs := flag.Args()\n\tif nargs := len(args); nargs != 3 {\n\t\tfmt.Fprintf(os.Stderr, \"invalid number of arguments, expected 3 got %d\\n\", nargs)\n\t\tos.Exit(1)\n\t}\n\tif args[0] != \"list\" {\n\t\tfmt.Fprintf(os.Stderr, \"expected \\\"list\\\" command got %q\\n\", args[0])\n\t\tos.Exit(1)\n\t}\n\tif args[1] != \"table\" {\n\t\tfmt.Fprintf(os.Stderr, \"expected \\\"list\\\" command got %q\\n\", args[0])\n\t\tos.Exit(1)\n\t}\n\n\tfilename := filepath.Join(testcase, \"table_\"+args[2]+\".json\")\n\tbuf, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\tfmt.Fprintln(os.Stderr, \"Error: No such file or directory\")\n\t\t\tfmt.Fprintln(os.Stderr, \"list table\", args[1])\n\t\t\tfmt.Fprintln(os.Stderr, \"          \", strings.Repeat(\"^\", len(args[1])))\n\t\t} else {\n\t\t\tfmt.Fprintf(os.Stderr, \"reading file %q failed: %v\", filename, err)\n\t\t}\n\t\tos.Exit(1)\n\t}\n\t// This mimics the command output, do not remove!\n\tfmt.Print(string(buf))\n\tos.Exit(0)\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/sample.conf",
    "content": "[[inputs.nftables]]\n  ## Use the specified binary which will be looked-up in PATH\n  # binary = \"nft\"\n\n  ## Use sudo for command execution, can be restricted to\n  ## \"nft --json list table\"\n  # use_sudo = false\n\n  ## Tables to monitor (may use \"family table\" format, e.g., \"inet filter\")\n  # tables = [ \"filter\" ]\n\n  ## Kinds of objects to monitor: \"counters\" (named counters), \"sets\",\n  ## (named sets), \"anonymous-counters\" (on commented rules).\n  # include = [\"anonymous-counters\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_output/expected.err",
    "content": "parsing command output failed: invalid character 'a' in literal true (expecting 'r')"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_output/table_test.json",
    "content": "table test {\n        chain output {\n                ip daddr 8.8.8.8 counter packets 0 bytes 0\n        }\n}"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_output/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"test\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_empty/expected.err",
    "content": "parsing command output failed: unable to parse rule: json: cannot unmarshal string into Go value of type nftables.rule"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_empty/table_test.json",
    "content": "{ \"nftables\": [\n    {\n      \"rule\": {}\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_empty/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"test\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_list/expected.err",
    "content": "parsing command output failed: unable to parse rule: json: cannot unmarshal array into Go value of type nftables.rule"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_list/table_test.json",
    "content": "{ \"nftables\": [\n    {\n      \"rule\": []\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_list/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"test\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_string/expected.err",
    "content": "parsing command output failed: unable to parse rule: json: cannot unmarshal string into Go value of type nftables.rule"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_string/table_test.json",
    "content": "{ \"nftables\": [\n    {\n      \"rule\": \"bad\"\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/nftables/testcases/bad_rule_string/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"test\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/mixed_counters/expected.out",
    "content": "nftables,chain=input,rule=rule_with_anonymous_counter,table=mixed bytes=25000i,pkts=500i\nnftables,table=mixed,counter=my_named_counter bytes=50000i,pkts=1000i\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/mixed_counters/table_mixed.json",
    "content": "{\n  \"nftables\": [\n    {\n      \"metainfo\": {\n        \"version\": \"1.1.6\",\n        \"release_name\": \"Test\",\n        \"json_schema_version\": 1\n      }\n    },\n    {\n      \"table\": {\n        \"family\": \"inet\",\n        \"name\": \"mixed\",\n        \"handle\": 1\n      }\n    },\n    {\n      \"chain\": {\n        \"family\": \"inet\",\n        \"table\": \"mixed\",\n        \"name\": \"input\",\n        \"handle\": 1,\n        \"type\": \"filter\",\n        \"hook\": \"input\",\n        \"prio\": 0,\n        \"policy\": \"drop\"\n      }\n    },\n    {\n      \"counter\": {\n        \"family\": \"inet\",\n        \"name\": \"my_named_counter\",\n        \"table\": \"mixed\",\n        \"handle\": 2,\n        \"packets\": 1000,\n        \"bytes\": 50000\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"mixed\",\n        \"chain\": \"input\",\n        \"handle\": 3,\n        \"comment\": \"rule_with_named_counter\",\n        \"expr\": [\n          {\n            \"counter\": \"my_named_counter\"\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"mixed\",\n        \"chain\": \"input\",\n        \"handle\": 4,\n        \"comment\": \"rule_with_anonymous_counter\",\n        \"expr\": [\n          {\n            \"counter\": {\n              \"packets\": 500,\n              \"bytes\": 25000\n            }\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/mixed_counters/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"mixed\"]\n  include = [\"anonymous-counters\", \"counters\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/named_counter/expected.out",
    "content": "nftables,table=example,counter=named_counter bytes=55119375i,pkts=45470i\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/named_counter/table_inet example.json",
    "content": "{\n    \"nftables\": [\n        {\n            \"metainfo\": {\n                \"version\": \"1.1.6\",\n                \"release_name\": \"Commodore Bullmoose #7\",\n                \"json_schema_version\": 1\n            }\n        },\n        {\n            \"table\": {\n                \"family\": \"inet\",\n                \"name\": \"example\",\n                \"handle\": 7\n            }\n        },\n        {\n            \"chain\": {\n                \"family\": \"inet\",\n                \"table\": \"example\",\n                \"name\": \"input\",\n                \"handle\": 1,\n                \"type\": \"filter\",\n                \"hook\": \"input\",\n                \"prio\": 0,\n                \"policy\": \"drop\"\n            }\n        },\n        {\n            \"counter\": {\n                \"family\": \"inet\",\n                \"name\": \"named_counter\",\n                \"table\": \"example\",\n                \"handle\": 2,\n                \"comment\": \"named counter comment\",\n                \"packets\": 45470,\n                \"bytes\": 55119375\n            }\n        },\n        {\n            \"rule\": {\n                \"family\": \"inet\",\n                \"table\": \"example\",\n                \"chain\": \"input\",\n                \"handle\": 3,\n                \"expr\": [\n                    {\n                        \"counter\": \"named_counter\"\n                    },\n                    {\n                        \"accept\": null\n                    }\n                ]\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/named_counter/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"inet example\"]\n  include = [\"counters\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/non_existent_table/expected.err",
    "content": "table \"nonexistant\" does not exist"
  },
  {
    "path": "plugins/inputs/nftables/testcases/non_existent_table/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"nonexistant\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/valid/expected.out",
    "content": "nftables,chain=test-chain,rule=test1,table=test bytes=2i,pkts=1i 1763040447356073265\nnftables,chain=test-chain,rule=test2,table=test bytes=1412296i,pkts=24468i 1763040447356078375\nnftables,set=non_empty_set,table=test count=5i 1763040447356078375\nnftables,set=empty_set,table=test count=0i 1763040447356078375\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/valid/table_test.json",
    "content": "{\n  \"nftables\": [\n    {\n      \"metainfo\": {\n        \"version\": \"1.0.2\",\n        \"release_name\": \"Lester Gooch\",\n        \"json_schema_version\": 1\n      }\n    },\n    {\n      \"table\": {\n        \"family\": \"inet\",\n        \"name\": \"test\",\n        \"handle\": 5\n      }\n    },\n    {\n      \"chain\": {\n        \"family\": \"inet\",\n        \"table\": \"test\",\n        \"name\": \"test-chain\",\n        \"handle\": 1,\n        \"type\": \"filter\",\n        \"hook\": \"input\",\n        \"prio\": 0,\n        \"policy\": \"accept\"\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"test\",\n        \"chain\": \"no_counter\",\n        \"handle\": 2,\n        \"comment\": \"test1\",\n        \"expr\": [\n          {\n            \"match\": {\n              \"op\": \"==\",\n              \"left\": {\n                \"payload\": {\n                  \"protocol\": \"tcp\",\n                  \"field\": \"dport\"\n                }\n              },\n              \"right\": 22\n            }\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"test\",\n        \"chain\": \"test-chain\",\n        \"handle\": 2,\n        \"comment\": \"test1\",\n        \"expr\": [\n          {\n            \"match\": {\n              \"op\": \"==\",\n              \"left\": {\n                \"payload\": {\n                  \"protocol\": \"tcp\",\n                  \"field\": \"dport\"\n                }\n              },\n              \"right\": 22\n            }\n          },\n          {\n            \"counter\": {\n              \"packets\": 1,\n              \"bytes\": 2\n            }\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"test\",\n        \"chain\": \"no_comment\",\n        \"handle\": 2,\n        \"expr\": [\n          {\n            \"match\": {\n              \"op\": \"==\",\n              \"left\": {\n                \"payload\": {\n                  \"protocol\": \"tcp\",\n                  \"field\": \"dport\"\n                }\n              },\n              \"right\": 22\n            }\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    },\n    {\n      \"rule\": {\n        \"family\": \"inet\",\n        \"table\": \"test\",\n        \"chain\": \"test-chain\",\n        \"handle\": 2,\n        \"comment\": \"test2\",\n        \"expr\": [\n          {\n            \"match\": {\n              \"op\": \"==\",\n              \"left\": {\n                \"payload\": {\n                  \"protocol\": \"tcp\",\n                  \"field\": \"dport\"\n                }\n              },\n              \"right\": 22\n            }\n          },\n          {\n            \"counter\": {\n              \"packets\": 24468,\n              \"bytes\": 1412296\n            }\n          },\n          {\n            \"accept\": null\n          }\n        ]\n      }\n    },\n    {\n      \"set\": {\n        \"family\": \"inet\",\n        \"name\": \"non_empty_set\",\n        \"table\": \"test\",\n        \"type\": \"ipv6_addr\",\n        \"handle\": 6,\n        \"size\": 65536,\n        \"flags\": [\"timeout\"],\n        \"timeout\": 300,\n        \"elem\": [\n          {\n            \"elem\": {\n              \"val\": \"::1\",\n              \"expires\": 99\n            }\n          },\n          {\n            \"elem\": {\n              \"val\": \"::2\",\n              \"expires\": 277\n            }\n          },\n          {\n            \"elem\": {\n              \"val\": \"::3\",\n              \"expires\": 280\n            }\n          },\n          {\n            \"elem\": {\n              \"val\": \"::4\",\n              \"expires\": 284\n            }\n          },\n          {\n            \"elem\": {\n              \"val\": \"::5\",\n              \"expires\": 287\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"set\": {\n        \"family\": \"inet\",\n        \"name\": \"empty_set\",\n        \"table\": \"test\",\n        \"type\": \"ipv4_addr\",\n        \"handle\": 7,\n        \"comment\": \"comment\",\n        \"size\": 65536,\n        \"flags\": [\"timeout\"],\n        \"timeout\": 300\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/nftables/testcases/valid/telegraf.conf",
    "content": "[[inputs.nftables]]\n  tables = [\"test\"]\n  include = [\"anonymous-counters\", \"counters\", \"sets\"]\n"
  },
  {
    "path": "plugins/inputs/nftables/types.go",
    "content": "//go:build linux\n\npackage nftables\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\ntype table struct {\n\tMetainfo          *metainfo\n\tRules             []*rule\n\tCounters          []*namedCounter\n\tSets              []*namedSet\n\tJSONSchemaVersion int `json:\"json_schema_version\"`\n}\n\n// UnmarshalJSON handles custom parsing of the nftables JSON output which uses\n// a generic structure incompatible that standard JSON unmarshaling.\nfunc (nftable *table) UnmarshalJSON(b []byte) error {\n\tvar rawTable map[string][]map[string]json.RawMessage\n\tif err := json.Unmarshal(b, &rawTable); err != nil {\n\t\treturn fmt.Errorf(\"unable to unmarshal: %s\", b)\n\t}\n\n\t// Get the top-level structure which should be of type []map[string]interface\n\tnfthings := rawTable[\"nftables\"]\n\tfor _, nfthing := range nfthings {\n\t\tif _, found := nfthing[\"metainfo\"]; found {\n\t\t\tvar mi metainfo\n\t\t\tif err := json.Unmarshal(nfthing[\"metainfo\"], &mi); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to parse metadata: %w\", err)\n\t\t\t}\n\t\t\tnftable.Metainfo = &mi\n\t\t} else if _, found := nfthing[\"rule\"]; found {\n\t\t\tvar r rule\n\t\t\tif err := json.Unmarshal(nfthing[\"rule\"], &r); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to parse rule: %w\", err)\n\t\t\t}\n\t\t\tnftable.Rules = append(nftable.Rules, &r)\n\t\t} else if _, found := nfthing[\"counter\"]; found {\n\t\t\tvar c namedCounter\n\t\t\tif err := json.Unmarshal(nfthing[\"counter\"], &c); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to parse counter: %w\", err)\n\t\t\t}\n\t\t\tnftable.Counters = append(nftable.Counters, &c)\n\t\t} else if _, found := nfthing[\"set\"]; found {\n\t\t\tvar s namedSet\n\t\t\tif err := json.Unmarshal(nfthing[\"set\"], &s); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to parse set: %w\", err)\n\t\t\t}\n\t\t\tnftable.Sets = append(nftable.Sets, &s)\n\t\t}\n\t}\n\treturn nil\n}\n\ntype metainfo struct {\n\tVersion     string `json:\"version\"`\n\tReleaseName string `json:\"release_name\"`\n}\n\ntype rule struct {\n\tFamily  string `json:\"family\"`\n\tTable   string `json:\"table\"`\n\tChain   string `json:\"chain\"`\n\tComment string `json:\"comment\"`\n\tExprs   []expr `json:\"expr\"`\n}\n\ntype expr struct {\n\tCntr *anonymousCounter `json:\"counter,omitempty\"`\n}\n\ntype anonymousCounter struct {\n\tPackets    int64 `json:\"packets\"`\n\tBytes      int64 `json:\"bytes\"`\n\tisNamedRef bool\n}\n\n// UnmarshalJSON handles both anonymous counters (objects with packets/bytes)\n// and named counter references (strings). Named references are marked with\n// isNamedRef flag since they don't contain inline statistics.\nfunc (c *anonymousCounter) UnmarshalJSON(b []byte) error {\n\tif len(b) > 0 && b[0] == '\"' {\n\t\t// Named counter reference - mark it and return\n\t\tc.isNamedRef = true\n\t\treturn nil\n\t}\n\t// Anonymous counter - parse the object using type alias to avoid\n\t// infinite recursion (alias has no methods, so json.Unmarshal uses\n\t// default struct unmarshaling instead of calling this method again)\n\ttype anonymousCounterAlias anonymousCounter\n\treturn json.Unmarshal(b, (*anonymousCounterAlias)(c))\n}\n\ntype namedCounter struct {\n\tFamily  string `json:\"family\"`\n\tName    string `json:\"name\"`\n\tTable   string `json:\"table\"`\n\tPackets int64  `json:\"packets\"`\n\tBytes   int64  `json:\"bytes\"`\n}\n\ntype namedSet struct {\n\tFamily string `json:\"family\"`\n\tName   string `json:\"name\"`\n\tTable  string `json:\"table\"`\n\tElem   []elem `json:\"elem,omitempty\"`\n}\n\ntype elem struct{}\n"
  },
  {
    "path": "plugins/inputs/nginx/README.md",
    "content": "# Nginx Input Plugin\n\nThis plugin gathers metrics from the open source [Nginx web server][nginx].\nNginx Plus is a commercial version. For more information about differences\nbetween Nginx (F/OSS) and Nginx Plus, see the Nginx [documentation][diff_doc].\n\n⭐ Telegraf v0.1.5\n🏷️ server, web\n💻 all\n\n[nginx]: https://www.nginx.com\n[diff_doc]: https://www.nginx.com/blog/whats-difference-nginx-foss-nginx-plus/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Nginx's basic status information (ngx_http_stub_status_module)\n[[inputs.nginx]]\n  ## An array of Nginx stub_status URI to gather stats.\n  urls = [\"http://localhost/server_status\", \"http+unix:///var/run/nginx.sock:/server_status\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n```\n\n## Metrics\n\n- Measurement\n  - accepts\n  - active\n  - handled\n  - reading\n  - requests\n  - waiting\n  - writing\n\n## Tags\n\n- All measurements have the following tags:\n  - port\n  - server\n\n## Example Output\n\nUsing this configuration:\n\n```toml\n[[inputs.nginx]]\n  ## An array of Nginx stub_status URI to gather stats.\n  urls = [\"http://localhost/status\"]\n```\n\nWhen run with:\n\n```sh\n./telegraf --config telegraf.conf --input-filter nginx --test\n```\n\nIt produces:\n\n```text\nnginx,port=80,server=localhost accepts=605i,active=2i,handled=605i,reading=0i,requests=12132i,waiting=1i,writing=1i 1456690994701784331\n```\n"
  },
  {
    "path": "plugins/inputs/nginx/nginx.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Nginx struct {\n\tUrls []string        `toml:\"urls\"`\n\tLog  telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\t// HTTP client\n\tclient *http.Client\n}\n\nfunc (*Nginx) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Nginx) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Create an HTTP client that is re-used for each\n\t// collection interval\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *Nginx) createHTTPClient() (*http.Client, error) {\n\tif n.HTTPClientConfig.ResponseHeaderTimeout < config.Duration(time.Second) {\n\t\tn.HTTPClientConfig.ResponseHeaderTimeout = config.Duration(time.Second * 5)\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\nfunc (n *Nginx) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tresp, err := n.client.Get(addr.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", addr.String(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\tr := bufio.NewReader(resp.Body)\n\n\t// Active connections\n\t_, err = r.ReadString(':')\n\tif err != nil {\n\t\treturn err\n\t}\n\tline, err := r.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\tactive, err := strconv.ParseUint(strings.TrimSpace(line), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Server accepts handled requests\n\t_, err = r.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\tline, err = r.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\tdata := strings.Fields(line)\n\taccepts, err := strconv.ParseUint(data[0], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thandled, err := strconv.ParseUint(data[1], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\trequests, err := strconv.ParseUint(data[2], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Reading/Writing/Waiting\n\tline, err = r.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\tdata = strings.Fields(line)\n\treading, err := strconv.ParseUint(data[1], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\twriting, err := strconv.ParseUint(data[3], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\twaiting, err := strconv.ParseUint(data[5], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\tfields := map[string]interface{}{\n\t\t\"active\":   active,\n\t\t\"accepts\":  accepts,\n\t\t\"handled\":  handled,\n\t\t\"requests\": requests,\n\t\t\"reading\":  reading,\n\t\t\"writing\":  writing,\n\t\t\"waiting\":  waiting,\n\t}\n\tacc.AddFields(\"nginx\", fields, tags)\n\n\treturn nil\n}\n\n// Get tag(s) for the nginx plugin\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"server\": host, \"port\": port}\n}\n\nfunc init() {\n\tinputs.Add(\"nginx\", func() telegraf.Input {\n\t\treturn &Nginx{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx/nginx_test.go",
    "content": "package nginx\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst nginxSampleResponse = `\nActive connections: 585\nserver accepts handled requests\n 85340 85340 35085\nReading: 4 Writing: 135 Waiting: 446\n`\nconst tengineSampleResponse = `\nActive connections: 403\nserver accepts handled requests request_time\n 853 8533 3502 1546565864\nReading: 8 Writing: 125 Waiting: 946\n`\n\n// Verify that nginx tags are properly parsed based on the server\nfunc TestNginxTags(t *testing.T) {\n\turls := []string{\"http://localhost/endpoint\", \"http://localhost:80/endpoint\", \"http+unix://localhost/endpoint\"}\n\tfor _, url1 := range urls {\n\t\taddr, err := url.Parse(url1)\n\t\trequire.NoError(t, err)\n\t\ttagMap := getTags(addr)\n\t\trequire.Contains(t, tagMap[\"server\"], \"localhost\")\n\t}\n}\n\nfunc TestNginxGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar rsp string\n\n\t\tif r.URL.Path == \"/stub_status\" {\n\t\t\trsp = nginxSampleResponse\n\t\t} else if r.URL.Path == \"/tengine_status\" {\n\t\t\trsp = tengineSampleResponse\n\t\t} else {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, unknown path\")\n\t\t\treturn\n\t\t}\n\n\t\tif _, err := fmt.Fprintln(w, rsp); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &Nginx{\n\t\tUrls: []string{ts.URL + \"/stub_status\"},\n\t}\n\n\tnt := &Nginx{\n\t\tUrls: []string{ts.URL + \"/tengine_status\"},\n\t}\n\n\tvar accNginx testutil.Accumulator\n\tvar accTengine testutil.Accumulator\n\n\trequire.NoError(t, accNginx.GatherError(n.Gather))\n\trequire.NoError(t, accTengine.GatherError(nt.Gather))\n\n\tfieldsNginx := map[string]interface{}{\n\t\t\"active\":   uint64(585),\n\t\t\"accepts\":  uint64(85340),\n\t\t\"handled\":  uint64(85340),\n\t\t\"requests\": uint64(35085),\n\t\t\"reading\":  uint64(4),\n\t\t\"writing\":  uint64(135),\n\t\t\"waiting\":  uint64(446),\n\t}\n\n\tfieldsTengine := map[string]interface{}{\n\t\t\"active\":   uint64(403),\n\t\t\"accepts\":  uint64(853),\n\t\t\"handled\":  uint64(8533),\n\t\t\"requests\": uint64(3502),\n\t\t\"reading\":  uint64(8),\n\t\t\"writing\":  uint64(125),\n\t\t\"waiting\":  uint64(946),\n\t}\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\ttags := map[string]string{\"server\": host, \"port\": port}\n\taccNginx.AssertContainsTaggedFields(t, \"nginx\", fieldsNginx, tags)\n\taccTengine.AssertContainsTaggedFields(t, \"nginx\", fieldsTengine, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/nginx/sample.conf",
    "content": "# Read Nginx's basic status information (ngx_http_stub_status_module)\n[[inputs.nginx]]\n  ## An array of Nginx stub_status URI to gather stats.\n  urls = [\"http://localhost/server_status\", \"http+unix:///var/run/nginx.sock:/server_status\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/nginx_plus/README.md",
    "content": "# Nginx Plus Input Plugin\n\nThis plugin gathers metrics from the commercial\n[Nginx Plus web server][nginx_plus] via the [status module][status_module].\n\n> [!NOTE]\n> Using this plugin requires a license.\n\nFor more information about differences between Nginx (F/OSS) and Nginx Plus, see\nthe Nginx [documentation][diff_doc].\n\n⭐ Telegraf v1.5.0\n🏷️ server, web\n💻 all\n\n[nginx_plus]: https://www.f5.com/products/nginx/nginx-plus\n[status_module]: http://nginx.org/en/docs/http/ngx_http_status_module.html\n[diff_doc]: https://www.nginx.com/blog/whats-difference-nginx-foss-nginx-plus/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Nginx Plus' advanced status information\n[[inputs.nginx_plus]]\n  ## An array of Nginx status URIs to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  # HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- nginx_plus_processes\n  - respawned\n- nginx_plus_connections\n  - accepted\n  - dropped\n  - active\n  - idle\n- nginx_plus_ssl\n  - handshakes\n  - handshakes_failed\n  - session_reuses\n- nginx_plus_requests\n  - total\n  - current\n- nginx_plus_upstream, nginx_plus_stream_upstream\n  - keepalive\n  - zombies\n- nginx_plus_upstream_peer, nginx_plus_stream_upstream_peer\n  - requests\n  - unavail\n  - healthchecks_checks\n  - header_time\n  - response_time\n  - state\n  - active\n  - downstart\n  - healthchecks_last_passed\n  - weight\n  - responses_1xx\n  - responses_2xx\n  - responses_3xx\n  - responses_4xx\n  - responses_5xx\n  - received\n  - selected\n  - healthchecks_fails\n  - healthchecks_unhealthy\n  - backup\n  - responses_total\n  - sent\n  - fails\n  - downtime\n\n### Tags\n\n- nginx_plus_processes, nginx_plus_connections, nginx_plus_ssl, nginx_plus_requests\n  - server\n  - port\n\n- nginx_plus_upstream, nginx_plus_stream_upstream\n  - upstream\n  - server\n  - port\n\n- nginx_plus_upstream_peer, nginx_plus_stream_upstream_peer\n  - id\n  - upstream\n  - server\n  - port\n  - upstream_address\n\n## Example Output\n\nUsing this configuration:\n\n```toml\n[[inputs.nginx_plus]]\n  ## An array of Nginx Plus status URIs to gather stats.\n  urls = [\"http://localhost/status\"]\n```\n\nWhen run with:\n\n```sh\n./telegraf -config telegraf.conf -input-filter nginx_plus -test\n```\n\nIt produces:\n\n```text\n* Plugin: inputs.nginx_plus, Collection 1\n> nginx_plus_processes,server=localhost,port=12021,host=word.local respawned=0i 1505782513000000000\n> nginx_plus_connections,server=localhost,port=12021,host=word.local accepted=5535735212i,dropped=10140186i,active=9541i,idle=67540i 1505782513000000000\n> nginx_plus_ssl,server=localhost,port=12021,host=word.local handshakes=0i,handshakes_failed=0i,session_reuses=0i 1505782513000000000\n> nginx_plus_requests,server=localhost,port=12021,host=word.local total=186780541173i,current=9037i 1505782513000000000\n> nginx_plus_upstream,port=12021,host=word.local,upstream=dataserver80,server=localhost keepalive=0i,zombies=0i 1505782513000000000\n> nginx_plus_upstream_peer,upstream=dataserver80,upstream_address=10.10.102.181:80,id=0,server=localhost,port=12021,host=word.local sent=53806910399i,received=7516943964i,fails=207i,downtime=2325979i,selected=1505782512000i,backup=false,active=6i,responses_4xx=6935i,header_time=80i,response_time=80i,healthchecks_last_passed=true,responses_1xx=0i,responses_2xx=36299890i,responses_5xx=360450i,responses_total=36667275i,unavail=154i,downstart=0i,state=\"up\",requests=36673741i,responses_3xx=0i,healthchecks_unhealthy=5i,weight=1i,healthchecks_checks=177209i,healthchecks_fails=29i 1505782513000000000\n> nginx_plus_stream_upstream,server=localhost,port=12021,host=word.local,upstream=dataserver443 zombies=0i 1505782513000000000\n> nginx_plus_stream_upstream_peer,server=localhost,upstream_address=10.10.102.181:443,id=0,port=12021,host=word.local,upstream=dataserver443 active=1i,healthchecks_unhealthy=1i,weight=1i,unavail=0i,connect_time=24i,first_byte_time=78i,healthchecks_last_passed=true,state=\"up\",sent=4457713140i,received=698065272i,fails=0i,healthchecks_checks=178421i,downstart=0i,selected=1505782512000i,response_time=5156i,backup=false,connections=56251i,healthchecks_fails=20i,downtime=391017i 1505782513000000000\n```\n\n### Reference material\n\nSubsequent versions of status response structure available here:\n\n- [version 1](http://web.archive.org/web/20130805111222/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n\n- [version 2](http://web.archive.org/web/20131218101504/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n\n- version 3 - not available\n\n- [version 4](http://web.archive.org/web/20141218170938/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n\n- [version 5](http://web.archive.org/web/20150414043916/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n\n- [version 6](http://web.archive.org/web/20150918163811/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n\n- [version 7](http://web.archive.org/web/20161107221028/http://nginx.org/en/docs/http/ngx_http_status_module.html)\n"
  },
  {
    "path": "plugins/inputs/nginx_plus/nginx_plus.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx_plus\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NginxPlus struct {\n\tUrls []string        `toml:\"urls\"`\n\tLog  telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*NginxPlus) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NginxPlus) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Create an HTTP client that is re-used for each\n\t// collection interval\n\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NginxPlus) createHTTPClient() (*http.Client, error) {\n\tif n.HTTPClientConfig.ResponseHeaderTimeout < config.Duration(time.Second) {\n\t\tn.HTTPClientConfig.ResponseHeaderTimeout = config.Duration(time.Second * 5)\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\nfunc (n *NginxPlus) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tresp, err := n.client.Get(addr.String())\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", addr.String(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\tcontentType := strings.Split(resp.Header.Get(\"Content-Type\"), \";\")[0]\n\tswitch contentType {\n\tcase \"application/json\":\n\t\treturn gatherStatusURL(bufio.NewReader(resp.Body), getTags(addr), acc)\n\tdefault:\n\t\treturn fmt.Errorf(\"%s returned unexpected content type %s\", addr.String(), contentType)\n\t}\n}\n\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"server\": host, \"port\": port}\n}\n\ntype responseStats struct {\n\tResponses1xx int64 `json:\"1xx\"`\n\tResponses2xx int64 `json:\"2xx\"`\n\tResponses3xx int64 `json:\"3xx\"`\n\tResponses4xx int64 `json:\"4xx\"`\n\tResponses5xx int64 `json:\"5xx\"`\n\tTotal        int64 `json:\"total\"`\n}\n\ntype basicHitStats struct {\n\tResponses int64 `json:\"responses\"`\n\tBytes     int64 `json:\"bytes\"`\n}\n\ntype extendedHitStats struct {\n\tbasicHitStats\n\tResponsesWritten int64 `json:\"responses_written\"`\n\tBytesWritten     int64 `json:\"bytes_written\"`\n}\n\ntype healthCheckStats struct {\n\tChecks     int64 `json:\"checks\"`\n\tFails      int64 `json:\"fails\"`\n\tUnhealthy  int64 `json:\"unhealthy\"`\n\tLastPassed *bool `json:\"last_passed\"`\n}\n\ntype status struct {\n\tVersion       int    `json:\"version\"`\n\tNginxVersion  string `json:\"nginx_version\"`\n\tAddress       string `json:\"address\"`\n\tGeneration    *int   `json:\"generation\"`     // added in version 5\n\tLoadTimestamp *int64 `json:\"load_timestamp\"` // added in version 2\n\tTimestamp     int64  `json:\"timestamp\"`\n\tPid           *int   `json:\"pid\"` // added in version 6\n\n\tProcesses *struct { // added in version 5\n\t\tRespawned *int `json:\"respawned\"`\n\t} `json:\"processes\"`\n\n\tConnections struct {\n\t\tAccepted int64 `json:\"accepted\"`\n\t\tDropped  int64 `json:\"dropped\"`\n\t\tActive   int64 `json:\"active\"`\n\t\tIdle     int64 `json:\"idle\"`\n\t} `json:\"connections\"`\n\n\tSsl *struct { // added in version 6\n\t\tHandshakes       int64 `json:\"handshakes\"`\n\t\tHandshakesFailed int64 `json:\"handshakes_failed\"`\n\t\tSessionReuses    int64 `json:\"session_reuses\"`\n\t} `json:\"ssl\"`\n\n\tRequests struct {\n\t\tTotal   int64 `json:\"total\"`\n\t\tCurrent int   `json:\"current\"`\n\t} `json:\"requests\"`\n\n\tServerZones map[string]struct { // added in version 2\n\t\tProcessing int           `json:\"processing\"`\n\t\tRequests   int64         `json:\"requests\"`\n\t\tResponses  responseStats `json:\"responses\"`\n\t\tDiscarded  *int64        `json:\"discarded\"` // added in version 6\n\t\tReceived   int64         `json:\"received\"`\n\t\tSent       int64         `json:\"sent\"`\n\t} `json:\"server_zones\"`\n\n\tUpstreams map[string]struct {\n\t\tPeers []struct {\n\t\t\tID           *int             `json:\"id\"` // added in version 3\n\t\t\tServer       string           `json:\"server\"`\n\t\t\tBackup       bool             `json:\"backup\"`\n\t\t\tWeight       int              `json:\"weight\"`\n\t\t\tState        string           `json:\"state\"`\n\t\t\tActive       int              `json:\"active\"`\n\t\t\tKeepalive    *int             `json:\"keepalive\"` // removed in version 5\n\t\t\tMaxConns     *int             `json:\"max_conns\"` // added in version 3\n\t\t\tRequests     int64            `json:\"requests\"`\n\t\t\tResponses    responseStats    `json:\"responses\"`\n\t\t\tSent         int64            `json:\"sent\"`\n\t\t\tReceived     int64            `json:\"received\"`\n\t\t\tFails        int64            `json:\"fails\"`\n\t\t\tUnavail      int64            `json:\"unavail\"`\n\t\t\tHealthChecks healthCheckStats `json:\"health_checks\"`\n\t\t\tDowntime     int64            `json:\"downtime\"`\n\t\t\tDownstart    int64            `json:\"downstart\"`\n\t\t\tSelected     *int64           `json:\"selected\"`      // added in version 4\n\t\t\tHeaderTime   *int64           `json:\"header_time\"`   // added in version 5\n\t\t\tResponseTime *int64           `json:\"response_time\"` // added in version 5\n\t\t} `json:\"peers\"`\n\t\tKeepalive int       `json:\"keepalive\"`\n\t\tZombies   int       `json:\"zombies\"` // added in version 6\n\t\tQueue     *struct { // added in version 6\n\t\t\tSize      int   `json:\"size\"`\n\t\t\tMaxSize   int   `json:\"max_size\"`\n\t\t\tOverflows int64 `json:\"overflows\"`\n\t\t} `json:\"queue\"`\n\t} `json:\"upstreams\"`\n\n\tCaches map[string]struct { // added in version 2\n\t\tSize        int64            `json:\"size\"`\n\t\tMaxSize     int64            `json:\"max_size\"`\n\t\tCold        bool             `json:\"cold\"`\n\t\tHit         basicHitStats    `json:\"hit\"`\n\t\tStale       basicHitStats    `json:\"stale\"`\n\t\tUpdating    basicHitStats    `json:\"updating\"`\n\t\tRevalidated *basicHitStats   `json:\"revalidated\"` // added in version 3\n\t\tMiss        extendedHitStats `json:\"miss\"`\n\t\tExpired     extendedHitStats `json:\"expired\"`\n\t\tBypass      extendedHitStats `json:\"bypass\"`\n\t} `json:\"caches\"`\n\n\tStream struct {\n\t\tServerZones map[string]struct {\n\t\t\tProcessing  int            `json:\"processing\"`\n\t\t\tConnections int            `json:\"connections\"`\n\t\t\tSessions    *responseStats `json:\"sessions\"`\n\t\t\tDiscarded   *int64         `json:\"discarded\"` // added in version 7\n\t\t\tReceived    int64          `json:\"received\"`\n\t\t\tSent        int64          `json:\"sent\"`\n\t\t} `json:\"server_zones\"`\n\t\tUpstreams map[string]struct {\n\t\t\tPeers []struct {\n\t\t\t\tID            int              `json:\"id\"`\n\t\t\t\tServer        string           `json:\"server\"`\n\t\t\t\tBackup        bool             `json:\"backup\"`\n\t\t\t\tWeight        int              `json:\"weight\"`\n\t\t\t\tState         string           `json:\"state\"`\n\t\t\t\tActive        int              `json:\"active\"`\n\t\t\t\tConnections   int64            `json:\"connections\"`\n\t\t\t\tConnectTime   *int             `json:\"connect_time\"`\n\t\t\t\tFirstByteTime *int             `json:\"first_byte_time\"`\n\t\t\t\tResponseTime  *int             `json:\"response_time\"`\n\t\t\t\tSent          int64            `json:\"sent\"`\n\t\t\t\tReceived      int64            `json:\"received\"`\n\t\t\t\tFails         int64            `json:\"fails\"`\n\t\t\t\tUnavail       int64            `json:\"unavail\"`\n\t\t\t\tHealthChecks  healthCheckStats `json:\"health_checks\"`\n\t\t\t\tDowntime      int64            `json:\"downtime\"`\n\t\t\t\tDownstart     int64            `json:\"downstart\"`\n\t\t\t\tSelected      int64            `json:\"selected\"`\n\t\t\t} `json:\"peers\"`\n\t\t\tZombies int `json:\"zombies\"`\n\t\t} `json:\"upstreams\"`\n\t} `json:\"stream\"`\n}\n\nfunc gatherStatusURL(r *bufio.Reader, tags map[string]string, acc telegraf.Accumulator) error {\n\tdec := json.NewDecoder(r)\n\tstatus := &status{}\n\tif err := dec.Decode(status); err != nil {\n\t\treturn errors.New(\"error while decoding JSON response\")\n\t}\n\tstatus.gather(tags, acc)\n\treturn nil\n}\n\nfunc (s *status) gather(tags map[string]string, acc telegraf.Accumulator) {\n\ts.gatherProcessesMetrics(tags, acc)\n\ts.gatherConnectionsMetrics(tags, acc)\n\ts.gatherSslMetrics(tags, acc)\n\ts.gatherRequestMetrics(tags, acc)\n\ts.gatherZoneMetrics(tags, acc)\n\ts.gatherUpstreamMetrics(tags, acc)\n\ts.gatherCacheMetrics(tags, acc)\n\ts.gatherStreamMetrics(tags, acc)\n}\n\nfunc (s *status) gatherProcessesMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tvar respawned int\n\n\tif s.Processes.Respawned != nil {\n\t\trespawned = *s.Processes.Respawned\n\t}\n\n\tacc.AddFields(\n\t\t\"nginx_plus_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"respawned\": respawned,\n\t\t},\n\t\ttags,\n\t)\n}\n\nfunc (s *status) gatherConnectionsMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tacc.AddFields(\n\t\t\"nginx_plus_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": s.Connections.Accepted,\n\t\t\t\"dropped\":  s.Connections.Dropped,\n\t\t\t\"active\":   s.Connections.Active,\n\t\t\t\"idle\":     s.Connections.Idle,\n\t\t},\n\t\ttags,\n\t)\n}\n\nfunc (s *status) gatherSslMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tacc.AddFields(\n\t\t\"nginx_plus_ssl\",\n\t\tmap[string]interface{}{\n\t\t\t\"handshakes\":        s.Ssl.Handshakes,\n\t\t\t\"handshakes_failed\": s.Ssl.HandshakesFailed,\n\t\t\t\"session_reuses\":    s.Ssl.SessionReuses,\n\t\t},\n\t\ttags,\n\t)\n}\n\nfunc (s *status) gatherRequestMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tacc.AddFields(\n\t\t\"nginx_plus_requests\",\n\t\tmap[string]interface{}{\n\t\t\t\"total\":   s.Requests.Total,\n\t\t\t\"current\": s.Requests.Current,\n\t\t},\n\t\ttags,\n\t)\n}\n\nfunc (s *status) gatherZoneMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tfor zoneName, zone := range s.ServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_zone\",\n\t\t\tfunc() map[string]interface{} {\n\t\t\t\tresult := map[string]interface{}{\n\t\t\t\t\t\"processing\":      zone.Processing,\n\t\t\t\t\t\"requests\":        zone.Requests,\n\t\t\t\t\t\"responses_1xx\":   zone.Responses.Responses1xx,\n\t\t\t\t\t\"responses_2xx\":   zone.Responses.Responses2xx,\n\t\t\t\t\t\"responses_3xx\":   zone.Responses.Responses3xx,\n\t\t\t\t\t\"responses_4xx\":   zone.Responses.Responses4xx,\n\t\t\t\t\t\"responses_5xx\":   zone.Responses.Responses5xx,\n\t\t\t\t\t\"responses_total\": zone.Responses.Total,\n\t\t\t\t\t\"received\":        zone.Received,\n\t\t\t\t\t\"sent\":            zone.Sent,\n\t\t\t\t}\n\t\t\t\tif zone.Discarded != nil {\n\t\t\t\t\tresult[\"discarded\"] = *zone.Discarded\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t}(),\n\t\t\tzoneTags,\n\t\t)\n\t}\n}\n\nfunc (s *status) gatherUpstreamMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tfor upstreamName, upstream := range s.Upstreams {\n\t\tupstreamTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tupstreamTags[k] = v\n\t\t}\n\t\tupstreamTags[\"upstream\"] = upstreamName\n\t\tupstreamFields := map[string]interface{}{\n\t\t\t\"keepalive\": upstream.Keepalive,\n\t\t\t\"zombies\":   upstream.Zombies,\n\t\t}\n\t\tif upstream.Queue != nil {\n\t\t\tupstreamFields[\"queue_size\"] = upstream.Queue.Size\n\t\t\tupstreamFields[\"queue_max_size\"] = upstream.Queue.MaxSize\n\t\t\tupstreamFields[\"queue_overflows\"] = upstream.Queue.Overflows\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_upstream\",\n\t\t\tupstreamFields,\n\t\t\tupstreamTags,\n\t\t)\n\t\tfor _, peer := range upstream.Peers {\n\t\t\tvar selected int64\n\n\t\t\tif peer.Selected != nil {\n\t\t\t\tselected = *peer.Selected\n\t\t\t}\n\n\t\t\tpeerFields := map[string]interface{}{\n\t\t\t\t\"backup\":                 peer.Backup,\n\t\t\t\t\"weight\":                 peer.Weight,\n\t\t\t\t\"state\":                  peer.State,\n\t\t\t\t\"active\":                 peer.Active,\n\t\t\t\t\"requests\":               peer.Requests,\n\t\t\t\t\"responses_1xx\":          peer.Responses.Responses1xx,\n\t\t\t\t\"responses_2xx\":          peer.Responses.Responses2xx,\n\t\t\t\t\"responses_3xx\":          peer.Responses.Responses3xx,\n\t\t\t\t\"responses_4xx\":          peer.Responses.Responses4xx,\n\t\t\t\t\"responses_5xx\":          peer.Responses.Responses5xx,\n\t\t\t\t\"responses_total\":        peer.Responses.Total,\n\t\t\t\t\"sent\":                   peer.Sent,\n\t\t\t\t\"received\":               peer.Received,\n\t\t\t\t\"fails\":                  peer.Fails,\n\t\t\t\t\"unavail\":                peer.Unavail,\n\t\t\t\t\"healthchecks_checks\":    peer.HealthChecks.Checks,\n\t\t\t\t\"healthchecks_fails\":     peer.HealthChecks.Fails,\n\t\t\t\t\"healthchecks_unhealthy\": peer.HealthChecks.Unhealthy,\n\t\t\t\t\"downtime\":               peer.Downtime,\n\t\t\t\t\"downstart\":              peer.Downstart,\n\t\t\t\t\"selected\":               selected,\n\t\t\t}\n\t\t\tif peer.HealthChecks.LastPassed != nil {\n\t\t\t\tpeerFields[\"healthchecks_last_passed\"] = *peer.HealthChecks.LastPassed\n\t\t\t}\n\t\t\tif peer.HeaderTime != nil {\n\t\t\t\tpeerFields[\"header_time\"] = *peer.HeaderTime\n\t\t\t}\n\t\t\tif peer.ResponseTime != nil {\n\t\t\t\tpeerFields[\"response_time\"] = *peer.ResponseTime\n\t\t\t}\n\t\t\tif peer.MaxConns != nil {\n\t\t\t\tpeerFields[\"max_conns\"] = *peer.MaxConns\n\t\t\t}\n\t\t\tpeerTags := make(map[string]string, len(upstreamTags)+2)\n\t\t\tfor k, v := range upstreamTags {\n\t\t\t\tpeerTags[k] = v\n\t\t\t}\n\t\t\tpeerTags[\"upstream_address\"] = peer.Server\n\t\t\tif peer.ID != nil {\n\t\t\t\tpeerTags[\"id\"] = strconv.Itoa(*peer.ID)\n\t\t\t}\n\t\t\tacc.AddFields(\"nginx_plus_upstream_peer\", peerFields, peerTags)\n\t\t}\n\t}\n}\n\nfunc (s *status) gatherCacheMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tfor cacheName, cache := range s.Caches {\n\t\tcacheTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tcacheTags[k] = v\n\t\t}\n\t\tcacheTags[\"cache\"] = cacheName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_cache\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"size\":                      cache.Size,\n\t\t\t\t\"max_size\":                  cache.MaxSize,\n\t\t\t\t\"cold\":                      cache.Cold,\n\t\t\t\t\"hit_responses\":             cache.Hit.Responses,\n\t\t\t\t\"hit_bytes\":                 cache.Hit.Bytes,\n\t\t\t\t\"stale_responses\":           cache.Stale.Responses,\n\t\t\t\t\"stale_bytes\":               cache.Stale.Bytes,\n\t\t\t\t\"updating_responses\":        cache.Updating.Responses,\n\t\t\t\t\"updating_bytes\":            cache.Updating.Bytes,\n\t\t\t\t\"revalidated_responses\":     cache.Revalidated.Responses,\n\t\t\t\t\"revalidated_bytes\":         cache.Revalidated.Bytes,\n\t\t\t\t\"miss_responses\":            cache.Miss.Responses,\n\t\t\t\t\"miss_bytes\":                cache.Miss.Bytes,\n\t\t\t\t\"miss_responses_written\":    cache.Miss.ResponsesWritten,\n\t\t\t\t\"miss_bytes_written\":        cache.Miss.BytesWritten,\n\t\t\t\t\"expired_responses\":         cache.Expired.Responses,\n\t\t\t\t\"expired_bytes\":             cache.Expired.Bytes,\n\t\t\t\t\"expired_responses_written\": cache.Expired.ResponsesWritten,\n\t\t\t\t\"expired_bytes_written\":     cache.Expired.BytesWritten,\n\t\t\t\t\"bypass_responses\":          cache.Bypass.Responses,\n\t\t\t\t\"bypass_bytes\":              cache.Bypass.Bytes,\n\t\t\t\t\"bypass_responses_written\":  cache.Bypass.ResponsesWritten,\n\t\t\t\t\"bypass_bytes_written\":      cache.Bypass.BytesWritten,\n\t\t\t},\n\t\t\tcacheTags,\n\t\t)\n\t}\n}\n\nfunc (s *status) gatherStreamMetrics(tags map[string]string, acc telegraf.Accumulator) {\n\tfor zoneName, zone := range s.Stream.ServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx.stream.zone\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"processing\":  zone.Processing,\n\t\t\t\t\"connections\": zone.Connections,\n\t\t\t\t\"received\":    zone.Received,\n\t\t\t\t\"sent\":        zone.Sent,\n\t\t\t},\n\t\t\tzoneTags,\n\t\t)\n\t}\n\tfor upstreamName, upstream := range s.Stream.Upstreams {\n\t\tupstreamTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tupstreamTags[k] = v\n\t\t}\n\t\tupstreamTags[\"upstream\"] = upstreamName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_stream_upstream\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"zombies\": upstream.Zombies,\n\t\t\t},\n\t\t\tupstreamTags,\n\t\t)\n\t\tfor _, peer := range upstream.Peers {\n\t\t\tpeerFields := map[string]interface{}{\n\t\t\t\t\"backup\":                 peer.Backup,\n\t\t\t\t\"weight\":                 peer.Weight,\n\t\t\t\t\"state\":                  peer.State,\n\t\t\t\t\"active\":                 peer.Active,\n\t\t\t\t\"connections\":            peer.Connections,\n\t\t\t\t\"sent\":                   peer.Sent,\n\t\t\t\t\"received\":               peer.Received,\n\t\t\t\t\"fails\":                  peer.Fails,\n\t\t\t\t\"unavail\":                peer.Unavail,\n\t\t\t\t\"healthchecks_checks\":    peer.HealthChecks.Checks,\n\t\t\t\t\"healthchecks_fails\":     peer.HealthChecks.Fails,\n\t\t\t\t\"healthchecks_unhealthy\": peer.HealthChecks.Unhealthy,\n\t\t\t\t\"downtime\":               peer.Downtime,\n\t\t\t\t\"downstart\":              peer.Downstart,\n\t\t\t\t\"selected\":               peer.Selected,\n\t\t\t}\n\t\t\tif peer.HealthChecks.LastPassed != nil {\n\t\t\t\tpeerFields[\"healthchecks_last_passed\"] = *peer.HealthChecks.LastPassed\n\t\t\t}\n\t\t\tif peer.ConnectTime != nil {\n\t\t\t\tpeerFields[\"connect_time\"] = *peer.ConnectTime\n\t\t\t}\n\t\t\tif peer.FirstByteTime != nil {\n\t\t\t\tpeerFields[\"first_byte_time\"] = *peer.FirstByteTime\n\t\t\t}\n\t\t\tif peer.ResponseTime != nil {\n\t\t\t\tpeerFields[\"response_time\"] = *peer.ResponseTime\n\t\t\t}\n\t\t\tpeerTags := make(map[string]string, len(upstreamTags)+2)\n\t\t\tfor k, v := range upstreamTags {\n\t\t\t\tpeerTags[k] = v\n\t\t\t}\n\t\t\tpeerTags[\"upstream_address\"] = peer.Server\n\t\t\tpeerTags[\"id\"] = strconv.Itoa(peer.ID)\n\t\t\tacc.AddFields(\"nginx_plus_stream_upstream_peer\", peerFields, peerTags)\n\t\t}\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"nginx_plus\", func() telegraf.Input {\n\t\treturn &NginxPlus{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus/nginx_plus_test.go",
    "content": "package nginx_plus\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleStatusResponse = `\n{\n    \"version\": 6,\n    \"nginx_version\":  \"1.22.333\",\n    \"address\":        \"1.2.3.4\",\n    \"generation\":     88,\n    \"load_timestamp\": 1451606400000,\n    \"timestamp\":      1451606400000,\n    \"pid\":            9999,\n    \"processes\": {\n        \"respawned\": 9999\n     },\n    \"connections\": {\n        \"accepted\": 1234567890000,\n        \"dropped\":  2345678900000,\n        \"active\":   345,\n        \"idle\":     567\n    },\n    \"ssl\": {\n        \"handshakes\":        1234567800000,\n        \"handshakes_failed\": 5432100000000,\n        \"session_reuses\":    6543210000000\n    },\n    \"requests\": {\n        \"total\":   9876543210000,\n        \"current\": 98\n    },\n    \"server_zones\": {\n        \"zone.a_80\": {\n            \"processing\": 12,\n            \"requests\": 34,\n            \"responses\": {\n                \"1xx\": 111,\n                \"2xx\": 222,\n                \"3xx\": 333,\n                \"4xx\": 444,\n                \"5xx\": 555,\n                \"total\": 999\n            },\n            \"discarded\": 11,\n            \"received\": 22,\n            \"sent\": 33\n        },\n        \"zone.a_443\": {\n            \"processing\": 45,\n            \"requests\": 67,\n            \"responses\": {\n                \"1xx\": 1111,\n                \"2xx\": 2222,\n                \"3xx\": 3333,\n                \"4xx\": 4444,\n                \"5xx\": 5555,\n                \"total\": 999\n            },\n            \"discarded\": 44,\n            \"received\": 55,\n            \"sent\": 66\n        }\n    },\n    \"upstreams\": {\n        \"first_upstream\": {\n            \"peers\": [\n                {\n                    \"id\": 0,\n                    \"server\": \"1.2.3.123:80\",\n                    \"backup\": false,\n                    \"weight\": 1,\n                    \"state\": \"up\",\n                    \"active\": 0,\n                    \"requests\": 9876,\n                    \"responses\": {\n                        \"1xx\": 1111,\n                        \"2xx\": 2222,\n                        \"3xx\": 3333,\n                        \"4xx\": 4444,\n                        \"5xx\": 5555,\n                        \"total\": 987654\n                    },\n                    \"sent\": 987654321,\n                    \"received\": 87654321,\n                    \"fails\": 98,\n                    \"unavail\": 65,\n                    \"health_checks\": {\n                        \"checks\": 54,\n                        \"fails\": 32,\n                        \"unhealthy\": 21\n                    },\n                    \"downtime\": 5432,\n                    \"downstart\": 4321,\n                    \"selected\": 1451606400000\n                },\n                {\n                    \"id\": 1,\n                    \"server\": \"1.2.3.123:80\",\n                    \"backup\": true,\n                    \"weight\": 1,\n                    \"state\": \"up\",\n                    \"active\": 0,\n                    \"requests\": 8765,\n                    \"responses\": {\n                        \"1xx\": 1112,\n                        \"2xx\": 2223,\n                        \"3xx\": 3334,\n                        \"4xx\": 4445,\n                        \"5xx\": 5556,\n                        \"total\": 987655\n                    },\n                    \"sent\": 987654322,\n                    \"received\": 87654322,\n                    \"fails\": 99,\n                    \"unavail\": 88,\n                    \"health_checks\": {\n                        \"checks\": 77,\n                        \"fails\": 66,\n                        \"unhealthy\": 55\n                    },\n                    \"downtime\": 5433,\n                    \"downstart\": 4322,\n                    \"selected\": 1451606400000\n                }\n            ],\n            \"keepalive\": 1,\n            \"zombies\": 2\n        }\n    },\n    \"caches\": {\n        \"cache_01\": {\n            \"size\": 12,\n            \"max_size\": 23,\n            \"cold\": false,\n            \"hit\": {\n                \"responses\": 34,\n                \"bytes\": 45\n            },\n            \"stale\": {\n                \"responses\": 56,\n                \"bytes\": 67\n            },\n            \"updating\": {\n                \"responses\": 78,\n                \"bytes\": 89\n            },\n            \"revalidated\": {\n                \"responses\": 90,\n                \"bytes\": 98\n            },\n            \"miss\": {\n                \"responses\": 87,\n                \"bytes\": 76,\n                \"responses_written\": 65,\n                \"bytes_written\": 54\n            },\n            \"expired\": {\n                \"responses\": 43,\n                \"bytes\": 32,\n                \"responses_written\": 21,\n                \"bytes_written\": 10\n            },\n            \"bypass\": {\n                \"responses\": 13,\n                \"bytes\": 35,\n                \"responses_written\": 57,\n                \"bytes_written\": 79\n            }\n        }\n    },\n    \"stream\": {\n        \"server_zones\": {\n            \"stream.zone.01\": {\n                \"processing\": 24,\n                \"connections\": 46,\n                \"received\": 68,\n                \"sent\": 80\n            },\n            \"stream.zone.02\": {\n                \"processing\": 96,\n                \"connections\": 63,\n                \"received\": 31,\n                \"sent\": 25\n            }\n        },\n        \"upstreams\": {\n            \"upstream.01\": {\n                \"peers\": [\n                    {\n                        \"id\": 0,\n                        \"server\": \"4.3.2.1:2345\",\n                        \"backup\": false,\n                        \"weight\": 1,\n                        \"state\": \"up\",\n                        \"active\": 0,\n                        \"connections\": 0,\n                        \"sent\": 0,\n                        \"received\": 0,\n                        \"fails\": 0,\n                        \"unavail\": 0,\n                        \"health_checks\": {\n                            \"checks\": 40848,\n                            \"fails\": 0,\n                            \"unhealthy\": 0,\n                            \"last_passed\": true\n                        },\n                        \"downtime\": 0,\n                        \"downstart\": 0,\n                        \"selected\": 0\n                    },\n                    {\n                        \"id\": 1,\n                        \"server\": \"5.4.3.2:2345\",\n                        \"backup\": false,\n                        \"weight\": 1,\n                        \"state\": \"up\",\n                        \"active\": 0,\n                        \"connections\": 0,\n                        \"sent\": 0,\n                        \"received\": 0,\n                        \"fails\": 0,\n                        \"unavail\": 0,\n                        \"health_checks\": {\n                            \"checks\": 40851,\n                            \"fails\": 0,\n                            \"unhealthy\": 0,\n                            \"last_passed\": true\n                        },\n                        \"downtime\": 0,\n                        \"downstart\": 0,\n                        \"selected\": 0\n                    }\n                ],\n                \"zombies\": 0\n            }\n        }\n    }\n}`\n\nfunc TestNginxPlusGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/status\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/status\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(w, sampleStatusResponse); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxPlus{\n\t\tUrls: []string{ts.URL + \"/status\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terrNginx := n.Gather(&acc)\n\trequire.NoError(t, errNginx)\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"respawned\": int(9999),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": int64(1234567890000),\n\t\t\t\"dropped\":  int64(2345678900000),\n\t\t\t\"active\":   int64(345),\n\t\t\t\"idle\":     int64(567),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_ssl\",\n\t\tmap[string]interface{}{\n\t\t\t\"handshakes\":        int64(1234567800000),\n\t\t\t\"handshakes_failed\": int64(5432100000000),\n\t\t\t\"session_reuses\":    int64(6543210000000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_requests\",\n\t\tmap[string]interface{}{\n\t\t\t\"total\":   int64(9876543210000),\n\t\t\t\"current\": int(98),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_zone\",\n\t\tmap[string]interface{}{\n\t\t\t\"processing\":      int(12),\n\t\t\t\"requests\":        int64(34),\n\t\t\t\"responses_1xx\":   int64(111),\n\t\t\t\"responses_2xx\":   int64(222),\n\t\t\t\"responses_3xx\":   int64(333),\n\t\t\t\"responses_4xx\":   int64(444),\n\t\t\t\"responses_5xx\":   int64(555),\n\t\t\t\"responses_total\": int64(999),\n\t\t\t\"discarded\":       int64(11),\n\t\t\t\"received\":        int64(22),\n\t\t\t\"sent\":            int64(33),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"zone.a_80\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"keepalive\": int(1),\n\t\t\t\"zombies\":   int(2),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\":   host,\n\t\t\t\"port\":     port,\n\t\t\t\"upstream\": \"first_upstream\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_upstream_peer\",\n\t\tmap[string]interface{}{\n\t\t\t\"backup\":                 false,\n\t\t\t\"weight\":                 int(1),\n\t\t\t\"state\":                  \"up\",\n\t\t\t\"active\":                 int(0),\n\t\t\t\"requests\":               int64(9876),\n\t\t\t\"responses_1xx\":          int64(1111),\n\t\t\t\"responses_2xx\":          int64(2222),\n\t\t\t\"responses_3xx\":          int64(3333),\n\t\t\t\"responses_4xx\":          int64(4444),\n\t\t\t\"responses_5xx\":          int64(5555),\n\t\t\t\"responses_total\":        int64(987654),\n\t\t\t\"sent\":                   int64(987654321),\n\t\t\t\"received\":               int64(87654321),\n\t\t\t\"fails\":                  int64(98),\n\t\t\t\"unavail\":                int64(65),\n\t\t\t\"healthchecks_checks\":    int64(54),\n\t\t\t\"healthchecks_fails\":     int64(32),\n\t\t\t\"healthchecks_unhealthy\": int64(21),\n\t\t\t\"downtime\":               int64(5432),\n\t\t\t\"downstart\":              int64(4321),\n\t\t\t\"selected\":               int64(1451606400000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"server\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"first_upstream\",\n\t\t\t\"upstream_address\": \"1.2.3.123:80\",\n\t\t\t\"id\":               \"0\",\n\t\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus/sample.conf",
    "content": "# Read Nginx Plus' advanced status information\n[[inputs.nginx_plus]]\n  ## An array of Nginx status URIs to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  # HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/README.md",
    "content": "# Nginx Plus API Input Plugin\n\nThis plugin gathers metrics from the commercial\n[Nginx Plus web server][nginx_plus] via the [REST API][api].\n\n> [!NOTE]\n> Using this plugin requires a license.\n\nFor more information about differences between Nginx (F/OSS) and Nginx Plus, see\nthe Nginx [documentation][diff_doc].\n\n⭐ Telegraf v1.9.0\n🏷️ server, web\n💻 all\n\n[nginx_plus]: https://www.f5.com/products/nginx/nginx-plus\n[api]: https://demo.nginx.com/swagger-ui/\n[diff_doc]: https://www.nginx.com/blog/whats-difference-nginx-foss-nginx-plus/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Nginx Plus API advanced status information\n[[inputs.nginx_plus_api]]\n  ## An array of Nginx API URIs to gather stats.\n  urls = [\"http://localhost/api\", \"http+unix:///var/run/nginx.sock:/api\"]\n  # Nginx API version, default: 3\n  # api_version = 3\n\n  # HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Migration from Nginx Plus (Status) input plugin\n\n| Nginx Plus                      | Nginx Plus API                       |\n|---------------------------------|--------------------------------------|\n| nginx_plus_processes            | nginx_plus_api_processes             |\n| nginx_plus_connections          | nginx_plus_api_connections           |\n| nginx_plus_ssl                  | nginx_plus_api_ssl                   |\n| nginx_plus_requests             | nginx_plus_api_http_requests         |\n| nginx_plus_zone                 | nginx_plus_api_http_server_zones     |\n| nginx_plus_upstream             | nginx_plus_api_http_upstreams        |\n| nginx_plus_upstream_peer        | nginx_plus_api_http_upstream_peers   |\n| nginx_plus_cache                | nginx_plus_api_http_caches           |\n| nginx_plus_stream_upstream      | nginx_plus_api_stream_upstreams      |\n| nginx_plus_stream_upstream_peer | nginx_plus_api_stream_upstream_peers |\n| nginx.stream.zone               | nginx_plus_api_stream_server_zones   |\n\n## Measurements by API version\n\n| Measurement                          | API version (api_version) |\n|--------------------------------------|---------------------------|\n| nginx_plus_api_processes             | >= 3                      |\n| nginx_plus_api_connections           | >= 3                      |\n| nginx_plus_api_ssl                   | >= 3                      |\n| nginx_plus_api_slabs_pages           | >= 3                      |\n| nginx_plus_api_slabs_slots           | >= 3                      |\n| nginx_plus_api_http_requests         | >= 3                      |\n| nginx_plus_api_http_server_zones     | >= 3                      |\n| nginx_plus_api_http_upstreams        | >= 3                      |\n| nginx_plus_api_http_upstream_peers   | >= 3                      |\n| nginx_plus_api_http_caches           | >= 3                      |\n| nginx_plus_api_stream_upstreams      | >= 3                      |\n| nginx_plus_api_stream_upstream_peers | >= 3                      |\n| nginx_plus_api_stream_server_zones   | >= 3                      |\n| nginx_plus_api_http_location_zones   | >= 5                      |\n| nginx_plus_api_resolver_zones        | >= 5                      |\n| nginx_plus_api_http_limit_reqs       | >= 6                      |\n\n## Metrics\n\n- nginx_plus_api_processes\n  - respawned\n- nginx_plus_api_connections\n  - accepted\n  - dropped\n  - active\n  - idle\n- nginx_plus_api_slabs_pages\n  - used\n  - free\n- nginx_plus_api_slabs_slots\n  - used\n  - free\n  - reqs\n  - fails\n- nginx_plus_api_ssl\n  - handshakes\n  - handshakes_failed\n  - session_reuses\n- nginx_plus_api_http_requests\n  - total\n  - current\n- nginx_plus_api_http_server_zones\n  - processing\n  - requests\n  - responses_1xx\n  - responses_2xx\n  - responses_3xx\n  - responses_4xx\n  - responses_5xx\n  - responses_total\n  - received\n  - sent\n  - discarded\n- nginx_plus_api_http_upstreams\n  - keepalive\n  - zombies\n- nginx_plus_api_http_upstream_peers\n  - requests\n  - unavail\n  - healthchecks_checks\n  - header_time\n  - state\n  - response_time\n  - active\n  - healthchecks_last_passed\n  - weight\n  - responses_1xx\n  - responses_2xx\n  - responses_3xx\n  - responses_4xx\n  - responses_5xx\n  - received\n  - healthchecks_fails\n  - healthchecks_unhealthy\n  - backup\n  - responses_total\n  - sent\n  - fails\n  - downtime\n- nginx_plus_api_http_caches\n  - size\n  - max_size\n  - cold\n  - hit_responses\n  - hit_bytes\n  - stale_responses\n  - stale_bytes\n  - updating_responses\n  - updating_bytes\n  - revalidated_responses\n  - revalidated_bytes\n  - miss_responses\n  - miss_bytes\n  - miss_responses_written\n  - miss_bytes_written\n  - expired_responses\n  - expired_bytes\n  - expired_responses_written\n  - expired_bytes_written\n  - bypass_responses\n  - bypass_bytes\n  - bypass_responses_written\n  - bypass_bytes_written\n- nginx_plus_api_stream_upstreams\n  - zombies\n- nginx_plus_api_stream_upstream_peers\n  - unavail\n  - healthchecks_checks\n  - healthchecks_fails\n  - healthchecks_unhealthy\n  - healthchecks_last_passed\n  - response_time\n  - state\n  - active\n  - weight\n  - received\n  - backup\n  - sent\n  - fails\n  - downtime\n- nginx_plus_api_stream_server_zones\n  - processing\n  - connections\n  - received\n  - sent\n- nginx_plus_api_location_zones\n  - requests\n  - responses_1xx\n  - responses_2xx\n  - responses_3xx\n  - responses_4xx\n  - responses_5xx\n  - responses_total\n  - received\n  - sent\n  - discarded\n- nginx_plus_api_resolver_zones\n  - name\n  - srv\n  - addr\n  - noerror\n  - formerr\n  - servfail\n  - nxdomain\n  - notimp\n  - refused\n  - timedout\n  - unknown\n- nginx_plus_api_http_limit_reqs\n  - passed\n  - delayed\n  - rejected\n  - delayed_dry_run\n  - rejected_dry_run\n\n### Tags\n\n- nginx_plus_api_processes, nginx_plus_api_connections, nginx_plus_api_ssl, nginx_plus_api_http_requests\n  - source\n  - port\n\n- nginx_plus_api_http_upstreams, nginx_plus_api_stream_upstreams\n  - upstream\n  - source\n  - port\n\n- nginx_plus_api_http_server_zones, nginx_plus_api_upstream_server_zones,\n  nginx_plus_api_http_location_zones, nginx_plus_api_resolver_zones,\n  nginx_plus_api_slabs_pages\n  - source\n  - port\n  - zone\n\n- nginx_plus_api_slabs_slots\n  - source\n  - port\n  - zone\n  - slot\n\n- nginx_plus_api_upstream_peers, nginx_plus_api_stream_upstream_peers\n  - id\n  - upstream\n  - source\n  - port\n  - upstream_address\n\n- nginx_plus_api_http_caches\n  - source\n  - port\n\n- nginx_plus_api_http_limit_reqs\n  - source\n  - port\n  - limit\n\n## Example Output\n\nUsing this configuration:\n\n```toml\n[[inputs.nginx_plus_api]]\n  ## An array of Nginx Plus API URIs to gather stats.\n  urls = [\"http://localhost/api\"]\n```\n\nWhen run with:\n\n```sh\n./telegraf -config telegraf.conf -input-filter nginx_plus_api -test\n```\n\nIt produces:\n\n```text\nnginx_plus_api_processes,port=80,source=demo.nginx.com respawned=0i 1570696321000000000\nnginx_plus_api_connections,port=80,source=demo.nginx.com accepted=68998606i,active=7i,dropped=0i,idle=57i 1570696322000000000\nnginx_plus_api_slabs_pages,port=80,source=demo.nginx.com,zone=hg.nginx.org used=1i,free=503i 1570696322000000000\nnginx_plus_api_slabs_pages,port=80,source=demo.nginx.com,zone=trac.nginx.org used=3i,free=500i 1570696322000000000\nnginx_plus_api_slabs_slots,port=80,source=demo.nginx.com,zone=hg.nginx.org,slot=8 used=1i,free=503i,reqs=10i,fails=0i 1570696322000000000\nnginx_plus_api_slabs_slots,port=80,source=demo.nginx.com,zone=hg.nginx.org,slot=16 used=3i,free=500i,reqs=1024i,fails=0i 1570696322000000000\nnginx_plus_api_slabs_slots,port=80,source=demo.nginx.com,zone=trac.nginx.org,slot=8 used=1i,free=503i,reqs=10i,fails=0i 1570696322000000000\nnginx_plus_api_slabs_slots,port=80,source=demo.nginx.com,zone=trac.nginx.org,slot=16 used=0i,free=1520i,reqs=0i,fails=1i 1570696322000000000\nnginx_plus_api_ssl,port=80,source=demo.nginx.com handshakes=9398978i,handshakes_failed=289353i,session_reuses=1004389i 1570696322000000000\nnginx_plus_api_http_requests,port=80,source=demo.nginx.com current=51i,total=264649353i 1570696322000000000\nnginx_plus_api_http_server_zones,port=80,source=demo.nginx.com,zone=hg.nginx.org discarded=5i,processing=0i,received=24123604i,requests=60138i,responses_1xx=0i,responses_2xx=59353i,responses_3xx=531i,responses_4xx=249i,responses_5xx=0i,responses_total=60133i,sent=830165221i 1570696322000000000\nnginx_plus_api_http_server_zones,port=80,source=demo.nginx.com,zone=trac.nginx.org discarded=250i,processing=0i,received=2184618i,requests=12404i,responses_1xx=0i,responses_2xx=8579i,responses_3xx=2513i,responses_4xx=583i,responses_5xx=479i,responses_total=12154i,sent=139384159i 1570696322000000000\nnginx_plus_api_http_server_zones,port=80,source=demo.nginx.com,zone=lxr.nginx.org discarded=1i,processing=0i,received=1011701i,requests=4523i,responses_1xx=0i,responses_2xx=4332i,responses_3xx=28i,responses_4xx=39i,responses_5xx=123i,responses_total=4522i,sent=72631354i 1570696322000000000\nnginx_plus_api_http_upstreams,port=80,source=demo.nginx.com,upstream=trac-backend keepalive=0i,zombies=0i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=trac-backend,upstream_address=10.0.0.1:8080 active=0i,backup=false,downtime=0i,fails=0i,header_time=235i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=88581178i,requests=3180i,response_time=235i,responses_1xx=0i,responses_2xx=3168i,responses_3xx=5i,responses_4xx=6i,responses_5xx=0i,responses_total=3179i,sent=1321720i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=1,port=80,source=demo.nginx.com,upstream=trac-backend,upstream_address=10.0.0.1:8081 active=0i,backup=true,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_upstreams,port=80,source=demo.nginx.com,upstream=hg-backend keepalive=0i,zombies=0i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=hg-backend,upstream_address=10.0.0.1:8088 active=0i,backup=false,downtime=0i,fails=0i,header_time=22i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=909402572i,requests=18514i,response_time=88i,responses_1xx=0i,responses_2xx=17799i,responses_3xx=531i,responses_4xx=179i,responses_5xx=0i,responses_total=18509i,sent=10608107i,state=\"up\",unavail=0i,weight=5i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=1,port=80,source=demo.nginx.com,upstream=hg-backend,upstream_address=10.0.0.1:8089 active=0i,backup=true,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_upstreams,port=80,source=demo.nginx.com,upstream=lxr-backend keepalive=0i,zombies=0i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=lxr-backend,upstream_address=unix:/tmp/cgi.sock active=0i,backup=false,downtime=0i,fails=123i,header_time=91i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=71782888i,requests=4354i,response_time=91i,responses_1xx=0i,responses_2xx=4230i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=4230i,sent=3088656i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=1,port=80,source=demo.nginx.com,upstream=lxr-backend,upstream_address=unix:/tmp/cgib.sock active=0i,backup=true,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,max_conns=42i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_upstreams,port=80,source=demo.nginx.com,upstream=demo-backend keepalive=0i,zombies=0i 1570696322000000000\nnginx_plus_api_http_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=demo-backend,upstream_address=10.0.0.2:15431 active=0i,backup=false,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,requests=0i,responses_1xx=0i,responses_2xx=0i,responses_3xx=0i,responses_4xx=0i,responses_5xx=0i,responses_total=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696322000000000\nnginx_plus_api_http_caches,cache=http_cache,port=80,source=demo.nginx.com bypass_bytes=0i,bypass_bytes_written=0i,bypass_responses=0i,bypass_responses_written=0i,cold=false,expired_bytes=381518640i,expired_bytes_written=363449785i,expired_responses=42114i,expired_responses_written=39954i,hit_bytes=6321885979i,hit_responses=596730i,max_size=536870912i,miss_bytes=48512185i,miss_bytes_written=155600i,miss_responses=6052i,miss_responses_written=136i,revalidated_bytes=0i,revalidated_responses=0i,size=765952i,stale_bytes=0i,stale_responses=0i,updating_bytes=0i,updating_responses=0i 1570696323000000000\nnginx_plus_api_stream_server_zones,port=80,source=demo.nginx.com,zone=postgresql_loadbalancer connections=0i,processing=0i,received=0i,sent=0i 1570696323000000000\nnginx_plus_api_stream_server_zones,port=80,source=demo.nginx.com,zone=dns_loadbalancer connections=0i,processing=0i,received=0i,sent=0i 1570696323000000000\nnginx_plus_api_stream_upstreams,port=80,source=demo.nginx.com,upstream=postgresql_backends zombies=0i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=postgresql_backends,upstream_address=10.0.0.2:15432 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=1,port=80,source=demo.nginx.com,upstream=postgresql_backends,upstream_address=10.0.0.2:15433 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=2,port=80,source=demo.nginx.com,upstream=postgresql_backends,upstream_address=10.0.0.2:15434 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=3,port=80,source=demo.nginx.com,upstream=postgresql_backends,upstream_address=10.0.0.2:15435 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"down\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstreams,port=80,source=demo.nginx.com,upstream=dns_udp_backends zombies=0i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=0,port=80,source=demo.nginx.com,upstream=dns_udp_backends,upstream_address=10.0.0.5:53 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"up\",unavail=0i,weight=2i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=1,port=80,source=demo.nginx.com,upstream=dns_udp_backends,upstream_address=10.0.0.2:53 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"up\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstream_peers,id=2,port=80,source=demo.nginx.com,upstream=dns_udp_backends,upstream_address=10.0.0.7:53 active=0i,backup=false,connections=0i,downtime=0i,fails=0i,healthchecks_checks=0i,healthchecks_fails=0i,healthchecks_unhealthy=0i,received=0i,sent=0i,state=\"down\",unavail=0i,weight=1i 1570696323000000000\nnginx_plus_api_stream_upstreams,port=80,source=demo.nginx.com,upstream=unused_tcp_backends zombies=0i 1570696323000000000\nnginx_plus_api_http_location_zones,port=80,source=demo.nginx.com,zone=swagger discarded=0i,received=1622i,requests=8i,responses_1xx=0i,responses_2xx=7i,responses_3xx=0i,responses_4xx=1i,responses_5xx=0i,responses_total=8i,sent=638333i 1570696323000000000\nnginx_plus_api_http_location_zones,port=80,source=demo.nginx.com,zone=api-calls discarded=64i,received=337530181i,requests=1726513i,responses_1xx=0i,responses_2xx=1726428i,responses_3xx=0i,responses_4xx=21i,responses_5xx=0i,responses_total=1726449i,sent=1902577668i 1570696323000000000\nnginx_plus_api_resolver_zones,port=80,source=demo.nginx.com,zone=resolver1 addr=0i,formerr=0i,name=0i,noerror=0i,notimp=0i,nxdomain=0i,refused=0i,servfail=0i,srv=0i,timedout=0i,unknown=0i 1570696324000000000\nnginx_plus_api_http_limit_reqs,port=80,source=demo.nginx.com,limit=limit_1 delayed=0i,delayed_dry_run=0i,passed=6i,rejected=9i,rejected_dry_run=0i 1570696322000000000\nnginx_plus_api_http_limit_reqs,port=80,source=demo.nginx.com,limit=limit_2 delayed=13i,delayed_dry_run=3i,passed=6i,rejected=1i,rejected_dry_run=31i 1570696322000000000\n```\n\n### Reference material\n\n- [api documentation](http://demo.nginx.com/swagger-ui/#/)\n- [nginx_api_module documentation](http://nginx.org/en/docs/http/ngx_http_api_module.html)\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/nginx_plus_api.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx_plus_api\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// Default settings\n\tdefaultAPIVersion = 3\n\n\t// Paths\n\tprocessesPath   = \"processes\"\n\tconnectionsPath = \"connections\"\n\tslabsPath       = \"slabs\"\n\tsslPath         = \"ssl\"\n\n\thttpRequestsPath      = \"http/requests\"\n\thttpServerZonesPath   = \"http/server_zones\"\n\thttpLocationZonesPath = \"http/location_zones\"\n\thttpUpstreamsPath     = \"http/upstreams\"\n\thttpCachesPath        = \"http/caches\"\n\thttpLimitReqsPath     = \"http/limit_reqs\"\n\tresolverZonesPath     = \"resolvers\"\n\n\tstreamServerZonesPath = \"stream/server_zones\"\n\tstreamUpstreamsPath   = \"stream/upstreams\"\n)\n\ntype NginxPlusAPI struct {\n\tUrls       []string        `toml:\"urls\"`\n\tAPIVersion int64           `toml:\"api_version\"`\n\tLog        telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*NginxPlusAPI) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NginxPlusAPI) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Create an HTTP client that is re-used for each\n\t// collection interval\n\n\tif n.APIVersion == 0 {\n\t\tn.APIVersion = defaultAPIVersion\n\t}\n\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tn.gatherMetrics(addr, acc)\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) createHTTPClient() (*http.Client, error) {\n\tif n.HTTPClientConfig.ResponseHeaderTimeout < config.Duration(time.Second) {\n\t\tn.HTTPClientConfig.ResponseHeaderTimeout = config.Duration(time.Second * 5)\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\nfunc init() {\n\tinputs.Add(\"nginx_plus_api\", func() telegraf.Input {\n\t\treturn &NginxPlusAPI{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/nginx_plus_api_metrics.go",
    "content": "package nginx_plus_api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nvar (\n\t// errNotFound signals that the NGINX API routes does not exist.\n\terrNotFound = errors.New(\"not found\")\n)\n\nfunc (n *NginxPlusAPI) gatherMetrics(addr *url.URL, acc telegraf.Accumulator) {\n\taddError(acc, n.gatherProcessesMetrics(addr, acc))\n\taddError(acc, n.gatherConnectionsMetrics(addr, acc))\n\taddError(acc, n.gatherSlabsMetrics(addr, acc))\n\taddError(acc, n.gatherSslMetrics(addr, acc))\n\taddError(acc, n.gatherHTTPRequestsMetrics(addr, acc))\n\taddError(acc, n.gatherHTTPServerZonesMetrics(addr, acc))\n\taddError(acc, n.gatherHTTPUpstreamsMetrics(addr, acc))\n\taddError(acc, n.gatherHTTPCachesMetrics(addr, acc))\n\taddError(acc, n.gatherStreamServerZonesMetrics(addr, acc))\n\taddError(acc, n.gatherStreamUpstreamsMetrics(addr, acc))\n\n\tif n.APIVersion >= 5 {\n\t\taddError(acc, n.gatherHTTPLocationZonesMetrics(addr, acc))\n\t\taddError(acc, n.gatherResolverZonesMetrics(addr, acc))\n\t}\n\tif n.APIVersion >= 6 {\n\t\taddError(acc, n.gatherHTTPLimitReqsMetrics(addr, acc))\n\t}\n}\n\nfunc addError(acc telegraf.Accumulator, err error) {\n\t// This plugin has hardcoded API resource paths it checks that may not\n\t// be in the nginx.conf.  Currently, this is to prevent logging of\n\t// paths that are not configured.\n\t//\n\t// The correct solution is to do a GET to /api to get the available paths\n\t// on the server rather than simply ignore.\n\tif !errors.Is(err, errNotFound) {\n\t\tacc.AddError(err)\n\t}\n}\n\nfunc (n *NginxPlusAPI) gatherURL(addr *url.URL, path string) ([]byte, error) {\n\taddress := fmt.Sprintf(\"%s/%d/%s\", addr.String(), n.APIVersion, path)\n\tresp, err := n.client.Get(address)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error making HTTP request to %q: %w\", address, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\tcase http.StatusNotFound:\n\t\t// format as special error to catch and ignore as some nginx API\n\t\t// features are either optional, or only available in some versions\n\t\treturn nil, errNotFound\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s\", address, resp.Status)\n\t}\n\n\tcontentType := strings.Split(resp.Header.Get(\"Content-Type\"), \";\")[0]\n\tswitch contentType {\n\tcase \"application/json\":\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn body, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%s returned unexpected content type %s\", address, contentType)\n\t}\n}\n\nfunc (n *NginxPlusAPI) gatherProcessesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, processesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar processes = &processes{}\n\n\tif err := json.Unmarshal(body, processes); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\n\t\t\"nginx_plus_api_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"respawned\": processes.Respawned,\n\t\t},\n\t\tgetTags(addr),\n\t)\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherConnectionsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, connectionsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar connections = &connections{}\n\n\tif err := json.Unmarshal(body, connections); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\n\t\t\"nginx_plus_api_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": connections.Accepted,\n\t\t\t\"dropped\":  connections.Dropped,\n\t\t\t\"active\":   connections.Active,\n\t\t\t\"idle\":     connections.Idle,\n\t\t},\n\t\tgetTags(addr),\n\t)\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherSlabsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, slabsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar slabs slabs\n\n\tif err := json.Unmarshal(body, &slabs); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor zoneName, slab := range slabs {\n\t\tslabTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tslabTags[k] = v\n\t\t}\n\t\tslabTags[\"zone\"] = zoneName\n\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_slabs_pages\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"used\": slab.Pages.Used,\n\t\t\t\t\"free\": slab.Pages.Free,\n\t\t\t},\n\t\t\tslabTags,\n\t\t)\n\n\t\tfor slotID, slot := range slab.Slots {\n\t\t\tslotTags := make(map[string]string, len(slabTags)+1)\n\t\t\tfor k, v := range slabTags {\n\t\t\t\tslotTags[k] = v\n\t\t\t}\n\t\t\tslotTags[\"slot\"] = slotID\n\n\t\t\tacc.AddFields(\n\t\t\t\t\"nginx_plus_api_slabs_slots\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"used\":  slot.Used,\n\t\t\t\t\t\"free\":  slot.Free,\n\t\t\t\t\t\"reqs\":  slot.Reqs,\n\t\t\t\t\t\"fails\": slot.Fails,\n\t\t\t\t},\n\t\t\t\tslotTags,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherSslMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, sslPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar ssl = &ssl{}\n\n\tif err := json.Unmarshal(body, ssl); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\n\t\t\"nginx_plus_api_ssl\",\n\t\tmap[string]interface{}{\n\t\t\t\"handshakes\":        ssl.Handshakes,\n\t\t\t\"handshakes_failed\": ssl.HandshakesFailed,\n\t\t\t\"session_reuses\":    ssl.SessionReuses,\n\t\t},\n\t\tgetTags(addr),\n\t)\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherHTTPRequestsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpRequestsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpRequests = &httpRequests{}\n\n\tif err := json.Unmarshal(body, httpRequests); err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(\n\t\t\"nginx_plus_api_http_requests\",\n\t\tmap[string]interface{}{\n\t\t\t\"total\":   httpRequests.Total,\n\t\t\t\"current\": httpRequests.Current,\n\t\t},\n\t\tgetTags(addr),\n\t)\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherHTTPServerZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpServerZonesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpServerZones httpServerZones\n\n\tif err := json.Unmarshal(body, &httpServerZones); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\tfor zoneName, zone := range httpServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_http_server_zones\",\n\t\t\tfunc() map[string]interface{} {\n\t\t\t\tresult := map[string]interface{}{\n\t\t\t\t\t\"processing\":      zone.Processing,\n\t\t\t\t\t\"requests\":        zone.Requests,\n\t\t\t\t\t\"responses_1xx\":   zone.Responses.Responses1xx,\n\t\t\t\t\t\"responses_2xx\":   zone.Responses.Responses2xx,\n\t\t\t\t\t\"responses_3xx\":   zone.Responses.Responses3xx,\n\t\t\t\t\t\"responses_4xx\":   zone.Responses.Responses4xx,\n\t\t\t\t\t\"responses_5xx\":   zone.Responses.Responses5xx,\n\t\t\t\t\t\"responses_total\": zone.Responses.Total,\n\t\t\t\t\t\"received\":        zone.Received,\n\t\t\t\t\t\"sent\":            zone.Sent,\n\t\t\t\t}\n\t\t\t\tif zone.Discarded != nil {\n\t\t\t\t\tresult[\"discarded\"] = *zone.Discarded\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t}(),\n\t\t\tzoneTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\n// Added in 5 API version\nfunc (n *NginxPlusAPI) gatherHTTPLocationZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpLocationZonesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpLocationZones httpLocationZones\n\n\tif err := json.Unmarshal(body, &httpLocationZones); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor zoneName, zone := range httpLocationZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_http_location_zones\",\n\t\t\tfunc() map[string]interface{} {\n\t\t\t\tresult := map[string]interface{}{\n\t\t\t\t\t\"requests\":        zone.Requests,\n\t\t\t\t\t\"responses_1xx\":   zone.Responses.Responses1xx,\n\t\t\t\t\t\"responses_2xx\":   zone.Responses.Responses2xx,\n\t\t\t\t\t\"responses_3xx\":   zone.Responses.Responses3xx,\n\t\t\t\t\t\"responses_4xx\":   zone.Responses.Responses4xx,\n\t\t\t\t\t\"responses_5xx\":   zone.Responses.Responses5xx,\n\t\t\t\t\t\"responses_total\": zone.Responses.Total,\n\t\t\t\t\t\"received\":        zone.Received,\n\t\t\t\t\t\"sent\":            zone.Sent,\n\t\t\t\t}\n\t\t\t\tif zone.Discarded != nil {\n\t\t\t\t\tresult[\"discarded\"] = *zone.Discarded\n\t\t\t\t}\n\t\t\t\treturn result\n\t\t\t}(),\n\t\t\tzoneTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherHTTPUpstreamsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpUpstreamsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpUpstreams httpUpstreams\n\n\tif err := json.Unmarshal(body, &httpUpstreams); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor upstreamName, upstream := range httpUpstreams {\n\t\tupstreamTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tupstreamTags[k] = v\n\t\t}\n\t\tupstreamTags[\"upstream\"] = upstreamName\n\t\tupstreamFields := map[string]interface{}{\n\t\t\t\"keepalive\": upstream.Keepalive,\n\t\t\t\"zombies\":   upstream.Zombies,\n\t\t}\n\t\tif upstream.Queue != nil {\n\t\t\tupstreamFields[\"queue_size\"] = upstream.Queue.Size\n\t\t\tupstreamFields[\"queue_max_size\"] = upstream.Queue.MaxSize\n\t\t\tupstreamFields[\"queue_overflows\"] = upstream.Queue.Overflows\n\t\t}\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_http_upstreams\",\n\t\t\tupstreamFields,\n\t\t\tupstreamTags,\n\t\t)\n\t\tfor _, peer := range upstream.Peers {\n\t\t\tpeerFields := map[string]interface{}{\n\t\t\t\t\"backup\":                 peer.Backup,\n\t\t\t\t\"weight\":                 peer.Weight,\n\t\t\t\t\"state\":                  peer.State,\n\t\t\t\t\"active\":                 peer.Active,\n\t\t\t\t\"requests\":               peer.Requests,\n\t\t\t\t\"responses_1xx\":          peer.Responses.Responses1xx,\n\t\t\t\t\"responses_2xx\":          peer.Responses.Responses2xx,\n\t\t\t\t\"responses_3xx\":          peer.Responses.Responses3xx,\n\t\t\t\t\"responses_4xx\":          peer.Responses.Responses4xx,\n\t\t\t\t\"responses_5xx\":          peer.Responses.Responses5xx,\n\t\t\t\t\"responses_total\":        peer.Responses.Total,\n\t\t\t\t\"sent\":                   peer.Sent,\n\t\t\t\t\"received\":               peer.Received,\n\t\t\t\t\"fails\":                  peer.Fails,\n\t\t\t\t\"unavail\":                peer.Unavail,\n\t\t\t\t\"healthchecks_checks\":    peer.HealthChecks.Checks,\n\t\t\t\t\"healthchecks_fails\":     peer.HealthChecks.Fails,\n\t\t\t\t\"healthchecks_unhealthy\": peer.HealthChecks.Unhealthy,\n\t\t\t\t\"downtime\":               peer.Downtime,\n\t\t\t\t// \"selected\":               peer.Selected.toInt64,\n\t\t\t\t// \"downstart\":              peer.Downstart.toInt64,\n\t\t\t}\n\t\t\tif peer.HealthChecks.LastPassed != nil {\n\t\t\t\tpeerFields[\"healthchecks_last_passed\"] = *peer.HealthChecks.LastPassed\n\t\t\t}\n\t\t\tif peer.HeaderTime != nil {\n\t\t\t\tpeerFields[\"header_time\"] = *peer.HeaderTime\n\t\t\t}\n\t\t\tif peer.ResponseTime != nil {\n\t\t\t\tpeerFields[\"response_time\"] = *peer.ResponseTime\n\t\t\t}\n\t\t\tif peer.MaxConns != nil {\n\t\t\t\tpeerFields[\"max_conns\"] = *peer.MaxConns\n\t\t\t}\n\t\t\tpeerTags := make(map[string]string, len(upstreamTags)+2)\n\t\t\tfor k, v := range upstreamTags {\n\t\t\t\tpeerTags[k] = v\n\t\t\t}\n\t\t\tpeerTags[\"upstream_address\"] = peer.Server\n\t\t\tif peer.ID != nil {\n\t\t\t\tpeerTags[\"id\"] = strconv.Itoa(*peer.ID)\n\t\t\t}\n\t\t\tacc.AddFields(\"nginx_plus_api_http_upstream_peers\", peerFields, peerTags)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherHTTPCachesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpCachesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpCaches httpCaches\n\n\tif err := json.Unmarshal(body, &httpCaches); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor cacheName, cache := range httpCaches {\n\t\tcacheTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tcacheTags[k] = v\n\t\t}\n\t\tcacheTags[\"cache\"] = cacheName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_http_caches\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"size\":                      cache.Size,\n\t\t\t\t\"max_size\":                  cache.MaxSize,\n\t\t\t\t\"cold\":                      cache.Cold,\n\t\t\t\t\"hit_responses\":             cache.Hit.Responses,\n\t\t\t\t\"hit_bytes\":                 cache.Hit.Bytes,\n\t\t\t\t\"stale_responses\":           cache.Stale.Responses,\n\t\t\t\t\"stale_bytes\":               cache.Stale.Bytes,\n\t\t\t\t\"updating_responses\":        cache.Updating.Responses,\n\t\t\t\t\"updating_bytes\":            cache.Updating.Bytes,\n\t\t\t\t\"revalidated_responses\":     cache.Revalidated.Responses,\n\t\t\t\t\"revalidated_bytes\":         cache.Revalidated.Bytes,\n\t\t\t\t\"miss_responses\":            cache.Miss.Responses,\n\t\t\t\t\"miss_bytes\":                cache.Miss.Bytes,\n\t\t\t\t\"miss_responses_written\":    cache.Miss.ResponsesWritten,\n\t\t\t\t\"miss_bytes_written\":        cache.Miss.BytesWritten,\n\t\t\t\t\"expired_responses\":         cache.Expired.Responses,\n\t\t\t\t\"expired_bytes\":             cache.Expired.Bytes,\n\t\t\t\t\"expired_responses_written\": cache.Expired.ResponsesWritten,\n\t\t\t\t\"expired_bytes_written\":     cache.Expired.BytesWritten,\n\t\t\t\t\"bypass_responses\":          cache.Bypass.Responses,\n\t\t\t\t\"bypass_bytes\":              cache.Bypass.Bytes,\n\t\t\t\t\"bypass_responses_written\":  cache.Bypass.ResponsesWritten,\n\t\t\t\t\"bypass_bytes_written\":      cache.Bypass.BytesWritten,\n\t\t\t},\n\t\t\tcacheTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherStreamServerZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, streamServerZonesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar streamServerZones streamServerZones\n\n\tif err := json.Unmarshal(body, &streamServerZones); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor zoneName, zone := range streamServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_stream_server_zones\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"processing\":  zone.Processing,\n\t\t\t\t\"connections\": zone.Connections,\n\t\t\t\t\"received\":    zone.Received,\n\t\t\t\t\"sent\":        zone.Sent,\n\t\t\t},\n\t\t\tzoneTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\n// Added in 5 API version\nfunc (n *NginxPlusAPI) gatherResolverZonesMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, resolverZonesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar resolverZones resolverZones\n\n\tif err := json.Unmarshal(body, &resolverZones); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor zoneName, resolver := range resolverZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_resolver_zones\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"name\": resolver.Requests.Name,\n\t\t\t\t\"srv\":  resolver.Requests.Srv,\n\t\t\t\t\"addr\": resolver.Requests.Addr,\n\n\t\t\t\t\"noerror\":  resolver.Responses.Noerror,\n\t\t\t\t\"formerr\":  resolver.Responses.Formerr,\n\t\t\t\t\"servfail\": resolver.Responses.Servfail,\n\t\t\t\t\"nxdomain\": resolver.Responses.Nxdomain,\n\t\t\t\t\"notimp\":   resolver.Responses.Notimp,\n\t\t\t\t\"refused\":  resolver.Responses.Refused,\n\t\t\t\t\"timedout\": resolver.Responses.Timedout,\n\t\t\t\t\"unknown\":  resolver.Responses.Unknown,\n\t\t\t},\n\t\t\tzoneTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NginxPlusAPI) gatherStreamUpstreamsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, streamUpstreamsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar streamUpstreams streamUpstreams\n\n\tif err := json.Unmarshal(body, &streamUpstreams); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor upstreamName, upstream := range streamUpstreams {\n\t\tupstreamTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tupstreamTags[k] = v\n\t\t}\n\t\tupstreamTags[\"upstream\"] = upstreamName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_stream_upstreams\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"zombies\": upstream.Zombies,\n\t\t\t},\n\t\t\tupstreamTags,\n\t\t)\n\t\tfor _, peer := range upstream.Peers {\n\t\t\tpeerFields := map[string]interface{}{\n\t\t\t\t\"backup\":                 peer.Backup,\n\t\t\t\t\"weight\":                 peer.Weight,\n\t\t\t\t\"state\":                  peer.State,\n\t\t\t\t\"active\":                 peer.Active,\n\t\t\t\t\"connections\":            peer.Connections,\n\t\t\t\t\"sent\":                   peer.Sent,\n\t\t\t\t\"received\":               peer.Received,\n\t\t\t\t\"fails\":                  peer.Fails,\n\t\t\t\t\"unavail\":                peer.Unavail,\n\t\t\t\t\"healthchecks_checks\":    peer.HealthChecks.Checks,\n\t\t\t\t\"healthchecks_fails\":     peer.HealthChecks.Fails,\n\t\t\t\t\"healthchecks_unhealthy\": peer.HealthChecks.Unhealthy,\n\t\t\t\t\"downtime\":               peer.Downtime,\n\t\t\t}\n\t\t\tif peer.HealthChecks.LastPassed != nil {\n\t\t\t\tpeerFields[\"healthchecks_last_passed\"] = *peer.HealthChecks.LastPassed\n\t\t\t}\n\t\t\tif peer.ConnectTime != nil {\n\t\t\t\tpeerFields[\"connect_time\"] = *peer.ConnectTime\n\t\t\t}\n\t\t\tif peer.FirstByteTime != nil {\n\t\t\t\tpeerFields[\"first_byte_time\"] = *peer.FirstByteTime\n\t\t\t}\n\t\t\tif peer.ResponseTime != nil {\n\t\t\t\tpeerFields[\"response_time\"] = *peer.ResponseTime\n\t\t\t}\n\t\t\tpeerTags := make(map[string]string, len(upstreamTags)+2)\n\t\t\tfor k, v := range upstreamTags {\n\t\t\t\tpeerTags[k] = v\n\t\t\t}\n\t\t\tpeerTags[\"upstream_address\"] = peer.Server\n\t\t\tpeerTags[\"id\"] = strconv.Itoa(peer.ID)\n\n\t\t\tacc.AddFields(\"nginx_plus_api_stream_upstream_peers\", peerFields, peerTags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Added in 6 API version\nfunc (n *NginxPlusAPI) gatherHTTPLimitReqsMetrics(addr *url.URL, acc telegraf.Accumulator) error {\n\tbody, err := n.gatherURL(addr, httpLimitReqsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar httpLimitReqs httpLimitReqs\n\n\tif err := json.Unmarshal(body, &httpLimitReqs); err != nil {\n\t\treturn err\n\t}\n\n\ttags := getTags(addr)\n\n\tfor limitReqName, limit := range httpLimitReqs {\n\t\tlimitReqsTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tlimitReqsTags[k] = v\n\t\t}\n\t\tlimitReqsTags[\"limit\"] = limitReqName\n\t\tacc.AddFields(\n\t\t\t\"nginx_plus_api_http_limit_reqs\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"passed\":           limit.Passed,\n\t\t\t\t\"delayed\":          limit.Delayed,\n\t\t\t\t\"rejected\":         limit.Rejected,\n\t\t\t\t\"delayed_dry_run\":  limit.DelayedDryRun,\n\t\t\t\t\"rejected_dry_run\": limit.RejectedDryRun,\n\t\t\t},\n\t\t\tlimitReqsTags,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"source\": host, \"port\": port}\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/nginx_plus_api_metrics_test.go",
    "content": "package nginx_plus_api\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst processesPayload = `\n{\n\t\"respawned\": 0\n}\n`\n\nconst connectionsPayload = `\n{\n\t\"accepted\": 1234567890000,\n\t\"dropped\":  2345678900000,\n\t\"active\":   345,\n\t\"idle\":     567\n}\n`\n\nconst slabsPayload = `\n{\n  \"zone1\":{\n    \"pages\":{\n      \"used\":7,\n      \"free\":56\n    },\n    \"slots\":{\n      \"8\":{\n        \"used\":1,\n        \"free\":503,\n        \"reqs\":1,\n        \"fails\":0\n      },\n      \"16\":{\n        \"used\":1,\n        \"free\":253,\n        \"reqs\":1,\n        \"fails\":0\n      },\n      \"32\":{\n        \"used\":3,\n        \"free\":124,\n        \"reqs\":3,\n        \"fails\":0\n      },\n      \"64\":{\n        \"used\":3,\n        \"free\":61,\n        \"reqs\":3,\n        \"fails\":0\n      },\n      \"128\":{\n        \"used\":6,\n        \"free\":26,\n        \"reqs\":6,\n        \"fails\":0\n      },\n      \"256\":{\n        \"used\":0,\n        \"free\":0,\n        \"reqs\":0,\n        \"fails\":0\n      },\n      \"512\":{\n        \"used\":2,\n        \"free\":6,\n        \"reqs\":2,\n        \"fails\":0\n      },\n      \"1024\":{\n        \"used\":2,\n        \"free\":2,\n        \"reqs\":2,\n        \"fails\":0\n      },\n      \"2048\":{\n        \"used\":0,\n        \"free\":0,\n        \"reqs\":0,\n        \"fails\":0\n      }\n    }\n  },\n  \"zone2\":{\n    \"pages\":{\n      \"used\":2218,\n      \"free\":252290\n    },\n    \"slots\":{\n      \"8\":{\n        \"used\":1,\n        \"free\":503,\n        \"reqs\":4,\n        \"fails\":0\n      },\n      \"16\":{\n        \"used\":0,\n        \"free\":0,\n        \"reqs\":0,\n        \"fails\":0\n      },\n      \"32\":{\n        \"used\":8,\n        \"free\":119,\n        \"reqs\":98,\n        \"fails\":0\n      },\n      \"64\":{\n        \"used\":10899,\n        \"free\":45,\n        \"reqs\":124255,\n        \"fails\":0\n      },\n      \"128\":{\n        \"used\":1,\n        \"free\":31,\n        \"reqs\":1,\n        \"fails\":0\n      },\n      \"256\":{\n        \"used\":10901,\n        \"free\":11,\n        \"reqs\":124270,\n        \"fails\":0\n      },\n      \"512\":{\n        \"used\":10893,\n        \"free\":3,\n        \"reqs\":124245,\n        \"fails\":0\n      },\n      \"1024\":{\n        \"used\":0,\n        \"free\":0,\n        \"reqs\":0,\n        \"fails\":0\n      },\n      \"2048\":{\n        \"used\":0,\n        \"free\":0,\n        \"reqs\":10,\n        \"fails\":0\n      }\n    }\n  }\n}\n`\n\nconst sslPayload = `\n{\n\t\"handshakes\": 79572,\n\t\"handshakes_failed\": 21025,\n\t\"session_reuses\": 15762\n}\n`\n\nconst resolverZonesPayload = `\n{\n  \"resolver_zone1\": {\n    \"requests\": {\n      \"name\": 25460,\n      \"srv\": 130,\n      \"addr\": 2580\n    },\n    \"responses\": {\n      \"noerror\": 26499,\n      \"formerr\": 0,\n      \"servfail\": 3,\n      \"nxdomain\": 0,\n      \"notimp\": 0,\n      \"refused\": 0,\n      \"timedout\": 243,\n      \"unknown\": 478\n    }\n  },\n  \"resolver_zone2\": {\n    \"requests\": {\n      \"name\": 325460,\n      \"srv\": 1130,\n      \"addr\": 12580\n    },\n    \"responses\": {\n      \"noerror\": 226499,\n      \"formerr\": 0,\n      \"servfail\": 283,\n      \"nxdomain\": 0,\n      \"notimp\": 0,\n      \"refused\": 0,\n      \"timedout\": 743,\n      \"unknown\": 1478\n    }\n  }\n}\n`\n\nconst httpRequestsPayload = `\n{\n\t\"total\": 10624511,\n\t\"current\": 4\n}\n`\n\nconst httpServerZonesPayload = `\n{\n\t\"site1\": {\n\t\t\"processing\": 2,\n\t\t\"requests\": 736395,\n\t\t\"responses\": {\n\t\t\t\"1xx\": 0,\n\t\t\t\"2xx\": 727290,\n\t\t\t\"3xx\": 4614,\n\t\t\t\"4xx\": 934,\n\t\t\t\"5xx\": 1535,\n\t\t\t\"total\": 734373\n\t\t},\n\t\t\"discarded\": 2020,\n\t\t\"received\": 180157219,\n\t\t\"sent\": 20183175459\n\t},\n\t\"site2\": {\n\t\t\"processing\": 1,\n\t\t\"requests\": 185307,\n\t\t\"responses\": {\n\t\t\t\"1xx\": 0,\n\t\t\t\"2xx\": 112674,\n\t\t\t\"3xx\": 45383,\n\t\t\t\"4xx\": 2504,\n\t\t\t\"5xx\": 4419,\n\t\t\t\"total\": 164980\n\t\t},\n\t\t\"discarded\": 20326,\n\t\t\"received\": 51575327,\n\t\t\"sent\": 2983241510\n\t}\n}\n`\n\nconst httpLimitReqsPayload = `\n{\n        \"limit_1\": {\n                \"passed\": 2,\n                \"delayed\": 9,\n                \"rejected\": 4,\n                \"delayed_dry_run\": 100,\n                \"rejected_dry_run\": 330\n        },\n        \"limit_2\": {\n                \"passed\": 451,\n                \"delayed\": 10,\n                \"rejected\": 0,\n                \"delayed_dry_run\": 10,\n                \"rejected_dry_run\": 32\n        }\n}\n`\n\nconst httpLocationZonesPayload = `\n{\n  \"site1\": {\n    \"requests\": 736395,\n    \"responses\": {\n      \"1xx\": 0,\n      \"2xx\": 727290,\n      \"3xx\": 4614,\n      \"4xx\": 934,\n      \"5xx\": 1535,\n      \"total\": 734373\n    },\n    \"discarded\": 2020,\n    \"received\": 180157219,\n    \"sent\": 20183175459\n  },\n  \"site2\": {\n    \"requests\": 185307,\n    \"responses\": {\n      \"1xx\": 0,\n      \"2xx\": 112674,\n      \"3xx\": 45383,\n      \"4xx\": 2504,\n      \"5xx\": 4419,\n      \"total\": 164980\n    },\n    \"discarded\": 20326,\n    \"received\": 51575327,\n    \"sent\": 2983241510\n  }\n}\n`\n\nconst httpUpstreamsPayload = `\n{\n\t\"trac-backend\": {\n\t\t\"peers\": [\n\t\t{\n\t\t\t\"id\": 0,\n\t\t\t\"server\": \"10.0.0.1:8088\",\n\t\t\t\"name\": \"10.0.0.1:8088\",\n\t\t\t\"backup\": false,\n\t\t\t\"weight\": 5,\n\t\t\t\"state\": \"up\",\n\t\t\t\"active\": 0,\n\t\t\t\"requests\": 667231,\n\t\t\t\"header_time\": 20,\n\t\t\t\"response_time\": 36,\n\t\t\t\"responses\": {\n\t\t\t\t\"1xx\": 0,\n\t\t\t\t\"2xx\": 666310,\n\t\t\t\t\"3xx\": 0,\n\t\t\t\t\"4xx\": 915,\n\t\t\t\t\"5xx\": 6,\n\t\t\t\t\"total\": 667231\n\t\t\t},\n\t\t\t\"sent\": 251946292,\n\t\t\t\"received\": 19222475454,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26214,\n\t\t\t\t\"fails\": 0,\n\t\t\t\t\"unhealthy\": 0,\n\t\t\t\t\"last_passed\": true\n\t\t\t},\n\t\t\t\"downtime\": 0,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t},\n\t\t{\n\t\t\t\"id\": 1,\n\t\t\t\"server\": \"10.0.0.1:8089\",\n\t\t\t\"name\": \"10.0.0.1:8089\",\n\t\t\t\"backup\": true,\n\t\t\t\"weight\": 1,\n\t\t\t\"state\": \"unhealthy\",\n\t\t\t\"active\": 0,\n\t\t\t\"requests\": 0,\n\t\t\t\"responses\": {\n\t\t\t\t\"1xx\": 0,\n\t\t\t\t\"2xx\": 0,\n\t\t\t\t\"3xx\": 0,\n\t\t\t\t\"4xx\": 0,\n\t\t\t\t\"5xx\": 0,\n\t\t\t\t\"total\": 0\n\t\t\t},\n\t\t\t\"sent\": 0,\n\t\t\t\"received\": 0,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26284,\n\t\t\t\t\"fails\": 26284,\n\t\t\t\t\"unhealthy\": 1,\n\t\t\t\t\"last_passed\": false\n\t\t\t},\n\t\t\t\"downtime\": 262925617,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t}\n\t\t],\n\t\t\"keepalive\": 0,\n\t\t\"zombies\": 0,\n\t\t\"zone\": \"trac-backend\"\n\t},\n\t\"hg-backend\": {\n\t\t\"peers\": [\n\t\t{\n\t\t\t\"id\": 0,\n\t\t\t\"server\": \"10.0.0.1:8088\",\n\t\t\t\"name\": \"10.0.0.1:8088\",\n\t\t\t\"backup\": false,\n\t\t\t\"weight\": 5,\n\t\t\t\"state\": \"up\",\n\t\t\t\"active\": 0,\n\t\t\t\"requests\": 667231,\n\t\t\t\"header_time\": 20,\n\t\t\t\"response_time\": 36,\n\t\t\t\"responses\": {\n\t\t\t\t\"1xx\": 0,\n\t\t\t\t\"2xx\": 666310,\n\t\t\t\t\"3xx\": 0,\n\t\t\t\t\"4xx\": 915,\n\t\t\t\t\"5xx\": 6,\n\t\t\t\t\"total\": 667231\n\t\t\t},\n\t\t\t\"sent\": 251946292,\n\t\t\t\"received\": 19222475454,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26214,\n\t\t\t\t\"fails\": 0,\n\t\t\t\t\"unhealthy\": 0,\n\t\t\t\t\"last_passed\": true\n\t\t\t},\n\t\t\t\"downtime\": 0,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t},\n\t\t{\n\t\t\t\"id\": 1,\n\t\t\t\"server\": \"10.0.0.1:8089\",\n\t\t\t\"name\": \"10.0.0.1:8089\",\n\t\t\t\"backup\": true,\n\t\t\t\"weight\": 1,\n\t\t\t\"state\": \"unhealthy\",\n\t\t\t\"active\": 0,\n\t\t\t\"requests\": 0,\n\t\t\t\"responses\": {\n\t\t\t\t\"1xx\": 0,\n\t\t\t\t\"2xx\": 0,\n\t\t\t\t\"3xx\": 0,\n\t\t\t\t\"4xx\": 0,\n\t\t\t\t\"5xx\": 0,\n\t\t\t\t\"total\": 0\n\t\t\t},\n\t\t\t\"sent\": 0,\n\t\t\t\"received\": 0,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26284,\n\t\t\t\t\"fails\": 26284,\n\t\t\t\t\"unhealthy\": 1,\n\t\t\t\t\"last_passed\": false\n\t\t\t},\n\t\t\t\"downtime\": 262925617,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t}\n\t\t],\n\t\t\"keepalive\": 0,\n\t\t\"zombies\": 0,\n\t\t\"zone\": \"hg-backend\"\n\t}\n}\n`\n\nconst httpCachesPayload = `\n{\n\t\"http-cache\": {\n\t\t\"size\": 530915328,\n\t\t\"max_size\": 536870912,\n\t\t\"cold\": false,\n\t\t\"hit\": {\n\t\t\t\"responses\": 254032,\n\t\t\t\"bytes\": 6685627875\n\t\t},\n\t\t\"stale\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"updating\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"revalidated\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"miss\": {\n\t\t\t\"responses\": 1619201,\n\t\t\t\"bytes\": 53841943822\n\t\t},\n\t\t\"expired\": {\n\t\t\t\"responses\": 45859,\n\t\t\t\"bytes\": 1656847080,\n\t\t\t\"responses_written\": 44992,\n\t\t\t\"bytes_written\": 1641825173\n\t\t},\n\t\t\"bypass\": {\n\t\t\t\"responses\": 200187,\n\t\t\t\"bytes\": 5510647548,\n\t\t\t\"responses_written\": 200173,\n\t\t\t\"bytes_written\": 44992\n\t\t}\n\t},\n\t\"frontend-cache\": {\n\t\t\"size\": 530915328,\n\t\t\"max_size\": 536870912,\n\t\t\"cold\": false,\n\t\t\"hit\": {\n\t\t\t\"responses\": 254032,\n\t\t\t\"bytes\": 6685627875\n\t\t},\n\t\t\"stale\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"updating\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"revalidated\": {\n\t\t\t\"responses\": 0,\n\t\t\t\"bytes\": 0\n\t\t},\n\t\t\"miss\": {\n\t\t\t\"responses\": 1619201,\n\t\t\t\"bytes\": 53841943822\n\t\t},\n\t\t\"expired\": {\n\t\t\t\"responses\": 45859,\n\t\t\t\"bytes\": 1656847080,\n\t\t\t\"responses_written\": 44992,\n\t\t\t\"bytes_written\": 1641825173\n\t\t},\n\t\t\"bypass\": {\n\t\t\t\"responses\": 200187,\n\t\t\t\"bytes\": 5510647548,\n\t\t\t\"responses_written\": 200173,\n\t\t\t\"bytes_written\": 44992\n\t\t}\n\t}\n}\n`\n\nconst streamUpstreamsPayload = `\n{\n\t\"mysql_backends\": {\n\t\t\"peers\": [\n\t\t{\n\t\t\t\"id\": 0,\n\t\t\t\"server\": \"10.0.0.1:12345\",\n\t\t\t\"name\": \"10.0.0.1:12345\",\n\t\t\t\"backup\": false,\n\t\t\t\"weight\": 5,\n\t\t\t\"state\": \"up\",\n\t\t\t\"active\": 0,\n\t\t\t\"max_conns\": 30,\n\t\t\t\"connecions\": 1231,\n\t\t\t\"sent\": 251946292,\n\t\t\t\"received\": 19222475454,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26214,\n\t\t\t\t\"fails\": 0,\n\t\t\t\t\"unhealthy\": 0,\n\t\t\t\t\"last_passed\": true\n\t\t\t},\n\t\t\t\"downtime\": 0,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t},\n\t\t{\n\t\t\t\"id\": 1,\n\t\t\t\"server\": \"10.0.0.1:12346\",\n\t\t\t\"name\": \"10.0.0.1:12346\",\n\t\t\t\"backup\": true,\n\t\t\t\"weight\": 1,\n\t\t\t\"state\": \"unhealthy\",\n\t\t\t\"active\": 0,\n\t\t\t\"max_conns\": 30,\n\t\t\t\"connections\": 0,\n\t\t\t\"sent\": 0,\n\t\t\t\"received\": 0,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26284,\n\t\t\t\t\"fails\": 26284,\n\t\t\t\t\"unhealthy\": 1,\n\t\t\t\t\"last_passed\": false\n\t\t\t},\n\t\t\t\"downtime\": 262925617,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t}\n\t\t],\n\t\t\"zombies\": 0,\n\t\t\"zone\": \"mysql_backends\"\n\t},\n\t\"dns\": {\n\t\t\"peers\": [\n\t\t{\n\t\t\t\"id\": 0,\n\t\t\t\"server\": \"10.0.0.1:12347\",\n\t\t\t\"name\": \"10.0.0.1:12347\",\n\t\t\t\"backup\": false,\n\t\t\t\"weight\": 5,\n\t\t\t\"state\": \"up\",\n\t\t\t\"active\": 0,\n\t\t\t\"max_conns\": 30,\n\t\t\t\"connections\": 667231,\n\t\t\t\"sent\": 251946292,\n\t\t\t\"received\": 19222475454,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26214,\n\t\t\t\t\"fails\": 0,\n\t\t\t\t\"unhealthy\": 0,\n\t\t\t\t\"last_passed\": true\n\t\t\t},\n\t\t\t\"downtime\": 0,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t},\n\t\t{\n\t\t\t\"id\": 1,\n\t\t\t\"server\": \"10.0.0.1:12348\",\n\t\t\t\"name\": \"10.0.0.1:12348\",\n\t\t\t\"backup\": true,\n\t\t\t\"weight\": 1,\n\t\t\t\"state\": \"unhealthy\",\n\t\t\t\"active\": 0,\n\t\t\t\"connections\": 0,\n\t\t\t\"max_conns\": 30,\n\t\t\t\"sent\": 0,\n\t\t\t\"received\": 0,\n\t\t\t\"fails\": 0,\n\t\t\t\"unavail\": 0,\n\t\t\t\"health_checks\": {\n\t\t\t\t\"checks\": 26284,\n\t\t\t\t\"fails\": 26284,\n\t\t\t\t\"unhealthy\": 1,\n\t\t\t\t\"last_passed\": false\n\t\t\t},\n\t\t\t\"downtime\": 262925617,\n\t\t\t\"downstart\": {},\n\t\t\t\"selected\": {}\n\t\t}\n\t\t],\n\t\t\"zombies\": 0,\n\t\t\"zone\": \"dns\"\n\t}\n}\n`\n\nconst streamServerZonesPayload = `\n{\n\t\"mysql-frontend\": {\n\t\t\"processing\": 2,\n\t\t\"connections\": 270925,\n\t\t\"sessions\": {\n\t\t\t\"2xx\": 155564,\n\t\t\t\"4xx\": 0,\n\t\t\t\"5xx\": 0,\n\t\t\t\"total\": 270925\n\t\t},\n\t\t\"discarded\": 0,\n\t\t\"received\": 28988975,\n\t\t\"sent\": 3879346317\n\t},\n\t\"dns\": {\n\t\t\"processing\": 1,\n\t\t\"connections\": 155569,\n\t\t\"sessions\": {\n\t\t\t\"2xx\": 155564,\n\t\t\t\"4xx\": 0,\n\t\t\t\"5xx\": 0,\n\t\t\t\"total\": 155569\n\t\t},\n\t\t\"discarded\": 0,\n\t\t\"received\": 4200363,\n\t\t\"sent\": 20489184\n\t}\n}\n`\n\nfunc TestGatherProcessesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, processesPath, processesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherProcessesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_processes\",\n\t\tmap[string]interface{}{\n\t\t\t\"respawned\": int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n}\n\nfunc TestGatherConnectionsMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, connectionsPath, connectionsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherConnectionsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": int64(1234567890000),\n\t\t\t\"dropped\":  int64(2345678900000),\n\t\t\t\"active\":   int64(345),\n\t\t\t\"idle\":     int64(567),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n}\n\nfunc TestGatherSlabsMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, slabsPath, slabsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherSlabsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_slabs_pages\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\": int64(7),\n\t\t\t\"free\": int64(56),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"zone1\",\n\t\t})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_slabs_pages\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\": int64(2218),\n\t\t\t\"free\": int64(252290),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"zone2\",\n\t\t})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_slabs_slots\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\":  int64(1),\n\t\t\t\"free\":  int64(503),\n\t\t\t\"reqs\":  int64(1),\n\t\t\t\"fails\": int64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"zone1\",\n\t\t\t\"slot\":   \"8\",\n\t\t})\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_slabs_slots\",\n\t\tmap[string]interface{}{\n\t\t\t\"used\":  int64(10893),\n\t\t\t\"free\":  int64(3),\n\t\t\t\"reqs\":  int64(124245),\n\t\t\t\"fails\": int64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"zone2\",\n\t\t\t\"slot\":   \"512\",\n\t\t})\n}\n\nfunc TestGatherSslMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, sslPath, sslPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherSslMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_ssl\",\n\t\tmap[string]interface{}{\n\t\t\t\"handshakes\":        int64(79572),\n\t\t\t\"handshakes_failed\": int64(21025),\n\t\t\t\"session_reuses\":    int64(15762),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n}\n\nfunc TestGatherHttpRequestsMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpRequestsPath, httpRequestsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPRequestsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_requests\",\n\t\tmap[string]interface{}{\n\t\t\t\"total\":   int64(10624511),\n\t\t\t\"current\": int64(4),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n}\n\nfunc TestGatherHttpServerZonesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpServerZonesPath, httpServerZonesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPServerZonesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_server_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"discarded\":       int64(2020),\n\t\t\t\"processing\":      int(2),\n\t\t\t\"received\":        int64(180157219),\n\t\t\t\"requests\":        int64(736395),\n\t\t\t\"responses_1xx\":   int64(0),\n\t\t\t\"responses_2xx\":   int64(727290),\n\t\t\t\"responses_3xx\":   int64(4614),\n\t\t\t\"responses_4xx\":   int64(934),\n\t\t\t\"responses_5xx\":   int64(1535),\n\t\t\t\"responses_total\": int64(734373),\n\t\t\t\"sent\":            int64(20183175459),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"site1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_server_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"discarded\":       int64(20326),\n\t\t\t\"processing\":      int(1),\n\t\t\t\"received\":        int64(51575327),\n\t\t\t\"requests\":        int64(185307),\n\t\t\t\"responses_1xx\":   int64(0),\n\t\t\t\"responses_2xx\":   int64(112674),\n\t\t\t\"responses_3xx\":   int64(45383),\n\t\t\t\"responses_4xx\":   int64(2504),\n\t\t\t\"responses_5xx\":   int64(4419),\n\t\t\t\"responses_total\": int64(164980),\n\t\t\t\"sent\":            int64(2983241510),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"site2\",\n\t\t})\n}\n\nfunc TestGatherHttpLimitReqsMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpLimitReqsPath, httpLimitReqsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPLimitReqsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_limit_reqs\",\n\t\tmap[string]interface{}{\n\t\t\t\"passed\":           int64(2),\n\t\t\t\"delayed\":          int64(9),\n\t\t\t\"rejected\":         int64(4),\n\t\t\t\"delayed_dry_run\":  int64(100),\n\t\t\t\"rejected_dry_run\": int64(330),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"limit\":  \"limit_1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_limit_reqs\",\n\t\tmap[string]interface{}{\n\t\t\t\"passed\":           int64(451),\n\t\t\t\"delayed\":          int64(10),\n\t\t\t\"rejected\":         int64(0),\n\t\t\t\"delayed_dry_run\":  int64(10),\n\t\t\t\"rejected_dry_run\": int64(32),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"limit\":  \"limit_2\",\n\t\t})\n}\n\nfunc TestGatherHttpLocationZonesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpLocationZonesPath, httpLocationZonesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPLocationZonesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_location_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"discarded\":       int64(2020),\n\t\t\t\"received\":        int64(180157219),\n\t\t\t\"requests\":        int64(736395),\n\t\t\t\"responses_1xx\":   int64(0),\n\t\t\t\"responses_2xx\":   int64(727290),\n\t\t\t\"responses_3xx\":   int64(4614),\n\t\t\t\"responses_4xx\":   int64(934),\n\t\t\t\"responses_5xx\":   int64(1535),\n\t\t\t\"responses_total\": int64(734373),\n\t\t\t\"sent\":            int64(20183175459),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"site1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_location_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"discarded\":       int64(20326),\n\t\t\t\"received\":        int64(51575327),\n\t\t\t\"requests\":        int64(185307),\n\t\t\t\"responses_1xx\":   int64(0),\n\t\t\t\"responses_2xx\":   int64(112674),\n\t\t\t\"responses_3xx\":   int64(45383),\n\t\t\t\"responses_4xx\":   int64(2504),\n\t\t\t\"responses_5xx\":   int64(4419),\n\t\t\t\"responses_total\": int64(164980),\n\t\t\t\"sent\":            int64(2983241510),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"site2\",\n\t\t})\n}\n\nfunc TestGatherHttpUpstreamsMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpUpstreamsPath, httpUpstreamsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPUpstreamsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstreams\",\n\t\tmap[string]interface{}{\n\t\t\t\"keepalive\": int(0),\n\t\t\t\"zombies\":   int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":   host,\n\t\t\t\"port\":     port,\n\t\t\t\"upstream\": \"trac-backend\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstreams\",\n\t\tmap[string]interface{}{\n\t\t\t\"keepalive\": int(0),\n\t\t\t\"zombies\":   int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":   host,\n\t\t\t\"port\":     port,\n\t\t\t\"upstream\": \"hg-backend\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   false,\n\t\t\t\"downtime\":                 int64(0),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"header_time\":              int64(20),\n\t\t\t\"healthchecks_checks\":      int64(26214),\n\t\t\t\"healthchecks_fails\":       int64(0),\n\t\t\t\"healthchecks_last_passed\": true,\n\t\t\t\"healthchecks_unhealthy\":   int64(0),\n\t\t\t\"received\":                 int64(19222475454),\n\t\t\t\"requests\":                 int64(667231),\n\t\t\t\"response_time\":            int64(36),\n\t\t\t\"responses_1xx\":            int64(0),\n\t\t\t\"responses_2xx\":            int64(666310),\n\t\t\t\"responses_3xx\":            int64(0),\n\t\t\t\"responses_4xx\":            int64(915),\n\t\t\t\"responses_5xx\":            int64(6),\n\t\t\t\"responses_total\":          int64(667231),\n\t\t\t\"sent\":                     int64(251946292),\n\t\t\t\"state\":                    \"up\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(5),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"trac-backend\",\n\t\t\t\"upstream_address\": \"10.0.0.1:8088\",\n\t\t\t\"id\":               \"0\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   true,\n\t\t\t\"downtime\":                 int64(262925617),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26284),\n\t\t\t\"healthchecks_fails\":       int64(26284),\n\t\t\t\"healthchecks_last_passed\": false,\n\t\t\t\"healthchecks_unhealthy\":   int64(1),\n\t\t\t\"received\":                 int64(0),\n\t\t\t\"requests\":                 int64(0),\n\t\t\t\"responses_1xx\":            int64(0),\n\t\t\t\"responses_2xx\":            int64(0),\n\t\t\t\"responses_3xx\":            int64(0),\n\t\t\t\"responses_4xx\":            int64(0),\n\t\t\t\"responses_5xx\":            int64(0),\n\t\t\t\"responses_total\":          int64(0),\n\t\t\t\"sent\":                     int64(0),\n\t\t\t\"state\":                    \"unhealthy\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(1),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"trac-backend\",\n\t\t\t\"upstream_address\": \"10.0.0.1:8089\",\n\t\t\t\"id\":               \"1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   false,\n\t\t\t\"downtime\":                 int64(0),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"header_time\":              int64(20),\n\t\t\t\"healthchecks_checks\":      int64(26214),\n\t\t\t\"healthchecks_fails\":       int64(0),\n\t\t\t\"healthchecks_last_passed\": true,\n\t\t\t\"healthchecks_unhealthy\":   int64(0),\n\t\t\t\"received\":                 int64(19222475454),\n\t\t\t\"requests\":                 int64(667231),\n\t\t\t\"response_time\":            int64(36),\n\t\t\t\"responses_1xx\":            int64(0),\n\t\t\t\"responses_2xx\":            int64(666310),\n\t\t\t\"responses_3xx\":            int64(0),\n\t\t\t\"responses_4xx\":            int64(915),\n\t\t\t\"responses_5xx\":            int64(6),\n\t\t\t\"responses_total\":          int64(667231),\n\t\t\t\"sent\":                     int64(251946292),\n\t\t\t\"state\":                    \"up\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(5),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"hg-backend\",\n\t\t\t\"upstream_address\": \"10.0.0.1:8088\",\n\t\t\t\"id\":               \"0\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   true,\n\t\t\t\"downtime\":                 int64(262925617),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26284),\n\t\t\t\"healthchecks_fails\":       int64(26284),\n\t\t\t\"healthchecks_last_passed\": false,\n\t\t\t\"healthchecks_unhealthy\":   int64(1),\n\t\t\t\"received\":                 int64(0),\n\t\t\t\"requests\":                 int64(0),\n\t\t\t\"responses_1xx\":            int64(0),\n\t\t\t\"responses_2xx\":            int64(0),\n\t\t\t\"responses_3xx\":            int64(0),\n\t\t\t\"responses_4xx\":            int64(0),\n\t\t\t\"responses_5xx\":            int64(0),\n\t\t\t\"responses_total\":          int64(0),\n\t\t\t\"sent\":                     int64(0),\n\t\t\t\"state\":                    \"unhealthy\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(1),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"hg-backend\",\n\t\t\t\"upstream_address\": \"10.0.0.1:8089\",\n\t\t\t\"id\":               \"1\",\n\t\t})\n}\n\nfunc TestGatherHttpCachesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, httpCachesPath, httpCachesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherHTTPCachesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_caches\",\n\t\tmap[string]interface{}{\n\t\t\t\"bypass_bytes\":              int64(5510647548),\n\t\t\t\"bypass_bytes_written\":      int64(44992),\n\t\t\t\"bypass_responses\":          int64(200187),\n\t\t\t\"bypass_responses_written\":  int64(200173),\n\t\t\t\"cold\":                      false,\n\t\t\t\"expired_bytes\":             int64(1656847080),\n\t\t\t\"expired_bytes_written\":     int64(1641825173),\n\t\t\t\"expired_responses\":         int64(45859),\n\t\t\t\"expired_responses_written\": int64(44992),\n\t\t\t\"hit_bytes\":                 int64(6685627875),\n\t\t\t\"hit_responses\":             int64(254032),\n\t\t\t\"max_size\":                  int64(536870912),\n\t\t\t\"miss_bytes\":                int64(53841943822),\n\t\t\t\"miss_bytes_written\":        int64(0),\n\t\t\t\"miss_responses\":            int64(1619201),\n\t\t\t\"miss_responses_written\":    int64(0),\n\t\t\t\"revalidated_bytes\":         int64(0),\n\t\t\t\"revalidated_responses\":     int64(0),\n\t\t\t\"size\":                      int64(530915328),\n\t\t\t\"stale_bytes\":               int64(0),\n\t\t\t\"stale_responses\":           int64(0),\n\t\t\t\"updating_bytes\":            int64(0),\n\t\t\t\"updating_responses\":        int64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"cache\":  \"http-cache\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_http_caches\",\n\t\tmap[string]interface{}{\n\t\t\t\"bypass_bytes\":              int64(5510647548),\n\t\t\t\"bypass_bytes_written\":      int64(44992),\n\t\t\t\"bypass_responses\":          int64(200187),\n\t\t\t\"bypass_responses_written\":  int64(200173),\n\t\t\t\"cold\":                      false,\n\t\t\t\"expired_bytes\":             int64(1656847080),\n\t\t\t\"expired_bytes_written\":     int64(1641825173),\n\t\t\t\"expired_responses\":         int64(45859),\n\t\t\t\"expired_responses_written\": int64(44992),\n\t\t\t\"hit_bytes\":                 int64(6685627875),\n\t\t\t\"hit_responses\":             int64(254032),\n\t\t\t\"max_size\":                  int64(536870912),\n\t\t\t\"miss_bytes\":                int64(53841943822),\n\t\t\t\"miss_bytes_written\":        int64(0),\n\t\t\t\"miss_responses\":            int64(1619201),\n\t\t\t\"miss_responses_written\":    int64(0),\n\t\t\t\"revalidated_bytes\":         int64(0),\n\t\t\t\"revalidated_responses\":     int64(0),\n\t\t\t\"size\":                      int64(530915328),\n\t\t\t\"stale_bytes\":               int64(0),\n\t\t\t\"stale_responses\":           int64(0),\n\t\t\t\"updating_bytes\":            int64(0),\n\t\t\t\"updating_responses\":        int64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"cache\":  \"frontend-cache\",\n\t\t})\n}\n\nfunc TestGatherResolverZonesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, resolverZonesPath, resolverZonesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherResolverZonesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_resolver_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"name\":     int64(25460),\n\t\t\t\"srv\":      int64(130),\n\t\t\t\"addr\":     int64(2580),\n\t\t\t\"noerror\":  int64(26499),\n\t\t\t\"formerr\":  int64(0),\n\t\t\t\"servfail\": int64(3),\n\t\t\t\"nxdomain\": int64(0),\n\t\t\t\"notimp\":   int64(0),\n\t\t\t\"refused\":  int64(0),\n\t\t\t\"timedout\": int64(243),\n\t\t\t\"unknown\":  int64(478),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"resolver_zone1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_resolver_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"name\":     int64(325460),\n\t\t\t\"srv\":      int64(1130),\n\t\t\t\"addr\":     int64(12580),\n\t\t\t\"noerror\":  int64(226499),\n\t\t\t\"formerr\":  int64(0),\n\t\t\t\"servfail\": int64(283),\n\t\t\t\"nxdomain\": int64(0),\n\t\t\t\"notimp\":   int64(0),\n\t\t\t\"refused\":  int64(0),\n\t\t\t\"timedout\": int64(743),\n\t\t\t\"unknown\":  int64(1478),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"resolver_zone2\",\n\t\t})\n}\n\nfunc TestGatherStreamUpstreams(t *testing.T) {\n\tts, n := prepareEndpoint(t, streamUpstreamsPath, streamUpstreamsPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherStreamUpstreamsMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstreams\",\n\t\tmap[string]interface{}{\n\t\t\t\"zombies\": int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":   host,\n\t\t\t\"port\":     port,\n\t\t\t\"upstream\": \"mysql_backends\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstreams\",\n\t\tmap[string]interface{}{\n\t\t\t\"zombies\": int(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":   host,\n\t\t\t\"port\":     port,\n\t\t\t\"upstream\": \"dns\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   false,\n\t\t\t\"connections\":              int64(0),\n\t\t\t\"downtime\":                 int64(0),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26214),\n\t\t\t\"healthchecks_fails\":       int64(0),\n\t\t\t\"healthchecks_last_passed\": true,\n\t\t\t\"healthchecks_unhealthy\":   int64(0),\n\t\t\t\"received\":                 int64(19222475454),\n\t\t\t\"sent\":                     int64(251946292),\n\t\t\t\"state\":                    \"up\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(5),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"mysql_backends\",\n\t\t\t\"upstream_address\": \"10.0.0.1:12345\",\n\t\t\t\"id\":               \"0\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   true,\n\t\t\t\"connections\":              int64(0),\n\t\t\t\"downtime\":                 int64(262925617),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26284),\n\t\t\t\"healthchecks_fails\":       int64(26284),\n\t\t\t\"healthchecks_last_passed\": false,\n\t\t\t\"healthchecks_unhealthy\":   int64(1),\n\t\t\t\"received\":                 int64(0),\n\t\t\t\"sent\":                     int64(0),\n\t\t\t\"state\":                    \"unhealthy\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(1),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"mysql_backends\",\n\t\t\t\"upstream_address\": \"10.0.0.1:12346\",\n\t\t\t\"id\":               \"1\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   false,\n\t\t\t\"connections\":              int64(667231),\n\t\t\t\"downtime\":                 int64(0),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26214),\n\t\t\t\"healthchecks_fails\":       int64(0),\n\t\t\t\"healthchecks_last_passed\": true,\n\t\t\t\"healthchecks_unhealthy\":   int64(0),\n\t\t\t\"received\":                 int64(19222475454),\n\t\t\t\"sent\":                     int64(251946292),\n\t\t\t\"state\":                    \"up\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(5),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"dns\",\n\t\t\t\"upstream_address\": \"10.0.0.1:12347\",\n\t\t\t\"id\":               \"0\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_upstream_peers\",\n\t\tmap[string]interface{}{\n\t\t\t\"active\":                   int(0),\n\t\t\t\"backup\":                   true,\n\t\t\t\"connections\":              int64(0),\n\t\t\t\"downtime\":                 int64(262925617),\n\t\t\t\"fails\":                    int64(0),\n\t\t\t\"healthchecks_checks\":      int64(26284),\n\t\t\t\"healthchecks_fails\":       int64(26284),\n\t\t\t\"healthchecks_last_passed\": false,\n\t\t\t\"healthchecks_unhealthy\":   int64(1),\n\t\t\t\"received\":                 int64(0),\n\t\t\t\"sent\":                     int64(0),\n\t\t\t\"state\":                    \"unhealthy\",\n\t\t\t\"unavail\":                  int64(0),\n\t\t\t\"weight\":                   int(1),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"dns\",\n\t\t\t\"upstream_address\": \"10.0.0.1:12348\",\n\t\t\t\"id\":               \"1\",\n\t\t})\n}\n\nfunc TestGatherStreamServerZonesMetrics(t *testing.T) {\n\tts, n := prepareEndpoint(t, streamServerZonesPath, streamServerZonesPayload)\n\tdefer ts.Close()\n\n\tvar acc testutil.Accumulator\n\taddr, host, port := prepareAddr(t, ts)\n\n\trequire.NoError(t, n.gatherStreamServerZonesMetrics(addr, &acc))\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_server_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"connections\": int(270925),\n\t\t\t\"processing\":  int(2),\n\t\t\t\"received\":    int64(28988975),\n\t\t\t\"sent\":        int64(3879346317),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"mysql-frontend\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_plus_api_stream_server_zones\",\n\t\tmap[string]interface{}{\n\t\t\t\"connections\": int(155569),\n\t\t\t\"processing\":  int(1),\n\t\t\t\"received\":    int64(4200363),\n\t\t\t\"sent\":        int64(20489184),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"dns\",\n\t\t})\n}\n\nfunc TestUnavailableEndpoints(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusNotFound)\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxPlusAPI{\n\t\tclient: ts.Client(),\n\t}\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tn.gatherMetrics(addr, &acc)\n\trequire.NoError(t, acc.FirstError())\n}\n\nfunc TestServerError(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusInternalServerError)\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxPlusAPI{\n\t\tclient: ts.Client(),\n\t}\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tn.gatherMetrics(addr, &acc)\n\trequire.Error(t, acc.FirstError())\n}\n\nfunc TestMalformedJSON(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\t\tif _, err := fmt.Fprintln(w, \"this is not JSON\"); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxPlusAPI{\n\t\tclient: ts.Client(),\n\t}\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tn.gatherMetrics(addr, &acc)\n\trequire.Error(t, acc.FirstError())\n}\n\nfunc TestUnknownContentType(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxPlusAPI{\n\t\tclient: ts.Client(),\n\t}\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\tn.gatherMetrics(addr, &acc)\n\trequire.Error(t, acc.FirstError())\n}\n\nfunc prepareAddr(t *testing.T, ts *httptest.Server) (addr *url.URL, host, port string) {\n\tt.Helper()\n\taddr, err := url.Parse(ts.URL + \"/api\")\n\trequire.NoError(t, err)\n\n\thost, port, err = net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\treturn addr, host, port\n}\n\nfunc prepareEndpoint(t *testing.T, path, payload string) (*httptest.Server, *NginxPlusAPI) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tfullPath := fmt.Sprintf(\"/api/%d/%s\", defaultAPIVersion, path)\n\t\tif r.URL.Path != fullPath {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Unknown request path, expected: %q, actual: %q\", fullPath, r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(w, payload); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\n\tn := &NginxPlusAPI{\n\t\tUrls:       []string{ts.URL + \"/api\"},\n\t\tAPIVersion: defaultAPIVersion,\n\t}\n\n\tclient, err := n.createHTTPClient()\n\trequire.NoError(t, err)\n\n\tn.client = client\n\n\treturn ts, n\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/nginx_plus_api_types.go",
    "content": "package nginx_plus_api\n\ntype processes struct {\n\tRespawned int `json:\"respawned\"`\n}\n\ntype connections struct {\n\tAccepted int64 `json:\"accepted\"`\n\tDropped  int64 `json:\"dropped\"`\n\tActive   int64 `json:\"active\"`\n\tIdle     int64 `json:\"idle\"`\n}\n\ntype slabs map[string]struct {\n\tPages struct {\n\t\tUsed int64 `json:\"used\"`\n\t\tFree int64 `json:\"free\"`\n\t} `json:\"pages\"`\n\tSlots map[string]struct {\n\t\tUsed  int64 `json:\"used\"`\n\t\tFree  int64 `json:\"free\"`\n\t\tReqs  int64 `json:\"reqs\"`\n\t\tFails int64 `json:\"fails\"`\n\t} `json:\"slots\"`\n}\n\ntype ssl struct { // added in version 6\n\tHandshakes       int64 `json:\"handshakes\"`\n\tHandshakesFailed int64 `json:\"handshakes_failed\"`\n\tSessionReuses    int64 `json:\"session_reuses\"`\n}\n\ntype resolverZones map[string]struct {\n\tRequests struct {\n\t\tName int64 `json:\"name\"`\n\t\tSrv  int64 `json:\"srv\"`\n\t\tAddr int64 `json:\"addr\"`\n\t} `json:\"requests\"`\n\tResponses struct {\n\t\tNoerror  int64 `json:\"noerror\"`\n\t\tFormerr  int64 `json:\"formerr\"`\n\t\tServfail int64 `json:\"servfail\"`\n\t\tNxdomain int64 `json:\"nxdomain\"`\n\t\tNotimp   int64 `json:\"notimp\"`\n\t\tRefused  int64 `json:\"refused\"`\n\t\tTimedout int64 `json:\"timedout\"`\n\t\tUnknown  int64 `json:\"unknown\"`\n\t} `json:\"responses\"`\n}\n\ntype httpRequests struct {\n\tTotal   int64 `json:\"total\"`\n\tCurrent int64 `json:\"current\"`\n}\n\ntype responseStats struct {\n\tResponses1xx int64 `json:\"1xx\"`\n\tResponses2xx int64 `json:\"2xx\"`\n\tResponses3xx int64 `json:\"3xx\"`\n\tResponses4xx int64 `json:\"4xx\"`\n\tResponses5xx int64 `json:\"5xx\"`\n\tTotal        int64 `json:\"total\"`\n}\n\ntype httpServerZones map[string]struct {\n\tProcessing int           `json:\"processing\"`\n\tRequests   int64         `json:\"requests\"`\n\tResponses  responseStats `json:\"responses\"`\n\tDiscarded  *int64        `json:\"discarded\"` // added in version 6\n\tReceived   int64         `json:\"received\"`\n\tSent       int64         `json:\"sent\"`\n}\n\ntype httpLocationZones map[string]struct {\n\tRequests  int64         `json:\"requests\"`\n\tResponses responseStats `json:\"responses\"`\n\tDiscarded *int64        `json:\"discarded\"` // added in version 6\n\tReceived  int64         `json:\"received\"`\n\tSent      int64         `json:\"sent\"`\n}\n\ntype healthCheckStats struct {\n\tChecks     int64 `json:\"checks\"`\n\tFails      int64 `json:\"fails\"`\n\tUnhealthy  int64 `json:\"unhealthy\"`\n\tLastPassed *bool `json:\"last_passed\"`\n}\n\ntype httpUpstreams map[string]struct {\n\tPeers []struct {\n\t\tID           *int             `json:\"id\"` // added in version 3\n\t\tServer       string           `json:\"server\"`\n\t\tBackup       bool             `json:\"backup\"`\n\t\tWeight       int              `json:\"weight\"`\n\t\tState        string           `json:\"state\"`\n\t\tActive       int              `json:\"active\"`\n\t\tKeepalive    *int             `json:\"keepalive\"` // removed in version 5\n\t\tMaxConns     *int             `json:\"max_conns\"` // added in version 3\n\t\tRequests     int64            `json:\"requests\"`\n\t\tResponses    responseStats    `json:\"responses\"`\n\t\tSent         int64            `json:\"sent\"`\n\t\tReceived     int64            `json:\"received\"`\n\t\tFails        int64            `json:\"fails\"`\n\t\tUnavail      int64            `json:\"unavail\"`\n\t\tHealthChecks healthCheckStats `json:\"health_checks\"`\n\t\tDowntime     int64            `json:\"downtime\"`\n\t\tHeaderTime   *int64           `json:\"header_time\"`   // added in version 5\n\t\tResponseTime *int64           `json:\"response_time\"` // added in version 5\n\t} `json:\"peers\"`\n\tKeepalive int       `json:\"keepalive\"`\n\tZombies   int       `json:\"zombies\"` // added in version 6\n\tQueue     *struct { // added in version 6\n\t\tSize      int   `json:\"size\"`\n\t\tMaxSize   int   `json:\"max_size\"`\n\t\tOverflows int64 `json:\"overflows\"`\n\t} `json:\"queue\"`\n}\n\ntype streamServerZones map[string]struct {\n\tProcessing  int            `json:\"processing\"`\n\tConnections int            `json:\"connections\"`\n\tSessions    *responseStats `json:\"sessions\"`\n\tDiscarded   *int64         `json:\"discarded\"` // added in version 7\n\tReceived    int64          `json:\"received\"`\n\tSent        int64          `json:\"sent\"`\n}\n\ntype streamUpstreams map[string]struct {\n\tPeers []struct {\n\t\tID            int              `json:\"id\"`\n\t\tServer        string           `json:\"server\"`\n\t\tBackup        bool             `json:\"backup\"`\n\t\tWeight        int              `json:\"weight\"`\n\t\tState         string           `json:\"state\"`\n\t\tActive        int              `json:\"active\"`\n\t\tConnections   int64            `json:\"connections\"`\n\t\tConnectTime   *int             `json:\"connect_time\"`\n\t\tFirstByteTime *int             `json:\"first_byte_time\"`\n\t\tResponseTime  *int             `json:\"response_time\"`\n\t\tSent          int64            `json:\"sent\"`\n\t\tReceived      int64            `json:\"received\"`\n\t\tFails         int64            `json:\"fails\"`\n\t\tUnavail       int64            `json:\"unavail\"`\n\t\tHealthChecks  healthCheckStats `json:\"health_checks\"`\n\t\tDowntime      int64            `json:\"downtime\"`\n\t} `json:\"peers\"`\n\tZombies int `json:\"zombies\"`\n}\n\ntype basicHitStats struct {\n\tResponses int64 `json:\"responses\"`\n\tBytes     int64 `json:\"bytes\"`\n}\n\ntype extendedHitStats struct {\n\tbasicHitStats\n\tResponsesWritten int64 `json:\"responses_written\"`\n\tBytesWritten     int64 `json:\"bytes_written\"`\n}\n\ntype httpCaches map[string]struct { // added in version 2\n\tSize        int64            `json:\"size\"`\n\tMaxSize     int64            `json:\"max_size\"`\n\tCold        bool             `json:\"cold\"`\n\tHit         basicHitStats    `json:\"hit\"`\n\tStale       basicHitStats    `json:\"stale\"`\n\tUpdating    basicHitStats    `json:\"updating\"`\n\tRevalidated *basicHitStats   `json:\"revalidated\"` // added in version 3\n\tMiss        extendedHitStats `json:\"miss\"`\n\tExpired     extendedHitStats `json:\"expired\"`\n\tBypass      extendedHitStats `json:\"bypass\"`\n}\n\ntype httpLimitReqs map[string]struct {\n\tPassed         int64 `json:\"passed\"`\n\tDelayed        int64 `json:\"delayed\"`\n\tRejected       int64 `json:\"rejected\"`\n\tDelayedDryRun  int64 `json:\"delayed_dry_run\"`\n\tRejectedDryRun int64 `json:\"rejected_dry_run\"`\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_plus_api/sample.conf",
    "content": "# Read Nginx Plus API advanced status information\n[[inputs.nginx_plus_api]]\n  ## An array of Nginx API URIs to gather stats.\n  urls = [\"http://localhost/api\", \"http+unix:///var/run/nginx.sock:/api\"]\n  # Nginx API version, default: 3\n  # api_version = 3\n\n  # HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nginx_sts/README.md",
    "content": "# Nginx Stream Server Traffic Input Plugin\n\nThis plugin gathers metrics from the [Nginx web server][nginx] using the\n[external stream server traffic status module][ssts_module]. This module provides\naccess to stream host status information containing the current status of\nservers, upstreams and caches, similar to the live activity monitoring of\nNginx plus. For module configuration details please see the\n[module documentation][module_doc].\n\n⭐ Telegraf v1.15.0\n🏷️ server, web\n💻 all\n\n[nginx]: https://www.nginx.com\n[ssts_module]: https://github.com/vozlt/nginx-module-sts\n[module_doc]: https://github.com/vozlt/nginx-module-sts#synopsis\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Nginx virtual host traffic status module information (nginx-module-sts)\n[[inputs.nginx_sts]]\n  ## An array of ngx_http_status_module or status URI to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- nginx_sts_connections\n  - tags:\n    - source\n    - port\n  - fields:\n    - active\n    - reading\n    - writing\n    - waiting\n    - accepted\n    - handled\n    - requests\n\n- nginx_sts_server\n  - tags:\n    - source\n    - port\n    - zone\n  - fields:\n    - connects\n    - in_bytes\n    - out_bytes\n    - response_1xx_count\n    - response_2xx_count\n    - response_3xx_count\n    - response_4xx_count\n    - response_5xx_count\n    - session_msec_counter\n    - session_msec\n\n- nginx_sts_filter\n  - tags:\n    - source\n    - port\n    - filter_name\n    - filter_key\n  - fields:\n    - connects\n    - in_bytes\n    - out_bytes\n    - response_1xx_count\n    - response_2xx_count\n    - response_3xx_count\n    - response_4xx_count\n    - response_5xx_count\n    - session_msec_counter\n    - session_msec\n\n- nginx_sts_upstream\n  - tags:\n    - source\n    - port\n    - upstream\n    - upstream_address\n  - fields:\n    - connects\n    - in_bytes\n    - out_bytes\n    - response_1xx_count\n    - response_2xx_count\n    - response_3xx_count\n    - response_4xx_count\n    - response_5xx_count\n    - session_msec_counter\n    - session_msec\n    - upstream_session_msec_counter\n    - upstream_session_msec\n    - upstream_connect_msec_counter\n    - upstream_connect_msec\n    - upstream_firstbyte_msec_counter\n    - upstream_firstbyte_msec\n    - weight\n    - max_fails\n    - fail_timeout\n    - backup\n    - down\n\n## Example Output\n\n```text\nnginx_sts_upstream,host=localhost,port=80,source=127.0.0.1,upstream=backend_cluster,upstream_address=1.2.3.4:8080 upstream_connect_msec_counter=0i,out_bytes=0i,down=false,connects=0i,session_msec=0i,upstream_session_msec=0i,upstream_session_msec_counter=0i,upstream_connect_msec=0i,upstream_firstbyte_msec_counter=0i,response_3xx_count=0i,session_msec_counter=0i,weight=1i,max_fails=1i,backup=false,upstream_firstbyte_msec=0i,in_bytes=0i,response_1xx_count=0i,response_2xx_count=0i,response_4xx_count=0i,response_5xx_count=0i,fail_timeout=10i 1584699180000000000\nnginx_sts_upstream,host=localhost,port=80,source=127.0.0.1,upstream=backend_cluster,upstream_address=9.8.7.6:8080 upstream_firstbyte_msec_counter=0i,response_2xx_count=0i,down=false,upstream_session_msec_counter=0i,out_bytes=0i,response_5xx_count=0i,weight=1i,max_fails=1i,fail_timeout=10i,connects=0i,session_msec_counter=0i,upstream_session_msec=0i,in_bytes=0i,response_1xx_count=0i,response_3xx_count=0i,response_4xx_count=0i,session_msec=0i,upstream_connect_msec=0i,upstream_connect_msec_counter=0i,upstream_firstbyte_msec=0i,backup=false 1584699180000000000\nnginx_sts_server,host=localhost,port=80,source=127.0.0.1,zone=* response_2xx_count=0i,response_4xx_count=0i,response_5xx_count=0i,session_msec_counter=0i,in_bytes=0i,out_bytes=0i,session_msec=0i,response_1xx_count=0i,response_3xx_count=0i,connects=0i 1584699180000000000\nnginx_sts_connections,host=localhost,port=80,source=127.0.0.1 waiting=1i,accepted=146i,handled=146i,requests=13421i,active=3i,reading=0i,writing=2i 1584699180000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nginx_sts/nginx_sts.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx_sts\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NginxSTS struct {\n\tUrls []string        `toml:\"urls\"`\n\tLog  telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*NginxSTS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NginxSTS) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Create an HTTP client that is re-used for each\n\t// collection interval\n\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NginxSTS) createHTTPClient() (*http.Client, error) {\n\tif n.HTTPClientConfig.ResponseHeaderTimeout < config.Duration(time.Second) {\n\t\tn.HTTPClientConfig.ResponseHeaderTimeout = config.Duration(time.Second * 5)\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\nfunc (n *NginxSTS) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tresp, err := n.client.Get(addr.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", addr.String(), err)\n\t}\n\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\tcontentType := strings.Split(resp.Header.Get(\"Content-Type\"), \";\")[0]\n\tswitch contentType {\n\tcase \"application/json\":\n\t\treturn gatherStatusURL(bufio.NewReader(resp.Body), getTags(addr), acc)\n\tdefault:\n\t\treturn fmt.Errorf(\"%s returned unexpected content type %s\", addr.String(), contentType)\n\t}\n}\n\ntype nginxSTSResponse struct {\n\tConnections struct {\n\t\tActive   uint64 `json:\"active\"`\n\t\tReading  uint64 `json:\"reading\"`\n\t\tWriting  uint64 `json:\"writing\"`\n\t\tWaiting  uint64 `json:\"waiting\"`\n\t\tAccepted uint64 `json:\"accepted\"`\n\t\tHandled  uint64 `json:\"handled\"`\n\t\tRequests uint64 `json:\"requests\"`\n\t} `json:\"connections\"`\n\tHostname            string                       `json:\"hostName\"`\n\tStreamFilterZones   map[string]map[string]server `json:\"streamFilterZones\"`\n\tStreamServerZones   map[string]server            `json:\"streamServerZones\"`\n\tStreamUpstreamZones map[string][]upstream        `json:\"streamUpstreamZones\"`\n}\n\ntype server struct {\n\tConnectCounter     uint64 `json:\"connectCounter\"`\n\tInBytes            uint64 `json:\"inBytes\"`\n\tOutBytes           uint64 `json:\"outBytes\"`\n\tSessionMsecCounter uint64 `json:\"sessionMsecCounter\"`\n\tSessionMsec        uint64 `json:\"sessionMsec\"`\n\tResponses          struct {\n\t\tOneXx   uint64 `json:\"1xx\"`\n\t\tTwoXx   uint64 `json:\"2xx\"`\n\t\tThreeXx uint64 `json:\"3xx\"`\n\t\tFourXx  uint64 `json:\"4xx\"`\n\t\tFiveXx  uint64 `json:\"5xx\"`\n\t} `json:\"responses\"`\n}\n\ntype upstream struct {\n\tServer         string `json:\"server\"`\n\tConnectCounter uint64 `json:\"connectCounter\"`\n\tInBytes        uint64 `json:\"inBytes\"`\n\tOutBytes       uint64 `json:\"outBytes\"`\n\tResponses      struct {\n\t\tOneXx   uint64 `json:\"1xx\"`\n\t\tTwoXx   uint64 `json:\"2xx\"`\n\t\tThreeXx uint64 `json:\"3xx\"`\n\t\tFourXx  uint64 `json:\"4xx\"`\n\t\tFiveXx  uint64 `json:\"5xx\"`\n\t} `json:\"responses\"`\n\tSessionMsecCounter    uint64 `json:\"sessionMsecCounter\"`\n\tSessionMsec           uint64 `json:\"sessionMsec\"`\n\tUSessionMsecCounter   uint64 `json:\"uSessionMsecCounter\"`\n\tUSessionMsec          uint64 `json:\"uSessionMsec\"`\n\tUConnectMsecCounter   uint64 `json:\"uConnectMsecCounter\"`\n\tUConnectMsec          uint64 `json:\"uConnectMsec\"`\n\tUFirstByteMsecCounter uint64 `json:\"uFirstByteMsecCounter\"`\n\tUFirstByteMsec        uint64 `json:\"uFirstByteMsec\"`\n\tWeight                uint64 `json:\"weight\"`\n\tMaxFails              uint64 `json:\"maxFails\"`\n\tFailTimeout           uint64 `json:\"failTimeout\"`\n\tBackup                bool   `json:\"backup\"`\n\tDown                  bool   `json:\"down\"`\n}\n\nfunc gatherStatusURL(r *bufio.Reader, tags map[string]string, acc telegraf.Accumulator) error {\n\tdec := json.NewDecoder(r)\n\tstatus := &nginxSTSResponse{}\n\tif err := dec.Decode(status); err != nil {\n\t\treturn errors.New(\"error while decoding JSON response\")\n\t}\n\n\tacc.AddFields(\"nginx_sts_connections\", map[string]interface{}{\n\t\t\"active\":   status.Connections.Active,\n\t\t\"reading\":  status.Connections.Reading,\n\t\t\"writing\":  status.Connections.Writing,\n\t\t\"waiting\":  status.Connections.Waiting,\n\t\t\"accepted\": status.Connections.Accepted,\n\t\t\"handled\":  status.Connections.Handled,\n\t\t\"requests\": status.Connections.Requests,\n\t}, tags)\n\n\tfor zoneName, zone := range status.StreamServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\n\t\tacc.AddFields(\"nginx_sts_server\", map[string]interface{}{\n\t\t\t\"connects\":             zone.ConnectCounter,\n\t\t\t\"in_bytes\":             zone.InBytes,\n\t\t\t\"out_bytes\":            zone.OutBytes,\n\t\t\t\"session_msec_counter\": zone.SessionMsecCounter,\n\t\t\t\"session_msec\":         zone.SessionMsec,\n\n\t\t\t\"response_1xx_count\": zone.Responses.OneXx,\n\t\t\t\"response_2xx_count\": zone.Responses.TwoXx,\n\t\t\t\"response_3xx_count\": zone.Responses.ThreeXx,\n\t\t\t\"response_4xx_count\": zone.Responses.FourXx,\n\t\t\t\"response_5xx_count\": zone.Responses.FiveXx,\n\t\t}, zoneTags)\n\t}\n\n\tfor filterName, filters := range status.StreamFilterZones {\n\t\tfor filterKey, upstream := range filters {\n\t\t\tfilterTags := make(map[string]string, len(tags)+2)\n\t\t\tfor k, v := range tags {\n\t\t\t\tfilterTags[k] = v\n\t\t\t}\n\t\t\tfilterTags[\"filter_key\"] = filterKey\n\t\t\tfilterTags[\"filter_name\"] = filterName\n\n\t\t\tacc.AddFields(\"nginx_sts_filter\", map[string]interface{}{\n\t\t\t\t\"connects\":             upstream.ConnectCounter,\n\t\t\t\t\"in_bytes\":             upstream.InBytes,\n\t\t\t\t\"out_bytes\":            upstream.OutBytes,\n\t\t\t\t\"session_msec_counter\": upstream.SessionMsecCounter,\n\t\t\t\t\"session_msec\":         upstream.SessionMsec,\n\n\t\t\t\t\"response_1xx_count\": upstream.Responses.OneXx,\n\t\t\t\t\"response_2xx_count\": upstream.Responses.TwoXx,\n\t\t\t\t\"response_3xx_count\": upstream.Responses.ThreeXx,\n\t\t\t\t\"response_4xx_count\": upstream.Responses.FourXx,\n\t\t\t\t\"response_5xx_count\": upstream.Responses.FiveXx,\n\t\t\t}, filterTags)\n\t\t}\n\t}\n\n\tfor upstreamName, upstreams := range status.StreamUpstreamZones {\n\t\tfor _, upstream := range upstreams {\n\t\t\tupstreamServerTags := make(map[string]string, len(tags)+2)\n\t\t\tfor k, v := range tags {\n\t\t\t\tupstreamServerTags[k] = v\n\t\t\t}\n\t\t\tupstreamServerTags[\"upstream\"] = upstreamName\n\t\t\tupstreamServerTags[\"upstream_address\"] = upstream.Server\n\t\t\tacc.AddFields(\"nginx_sts_upstream\", map[string]interface{}{\n\t\t\t\t\"connects\":                        upstream.ConnectCounter,\n\t\t\t\t\"session_msec\":                    upstream.SessionMsec,\n\t\t\t\t\"session_msec_counter\":            upstream.SessionMsecCounter,\n\t\t\t\t\"upstream_session_msec\":           upstream.USessionMsec,\n\t\t\t\t\"upstream_session_msec_counter\":   upstream.USessionMsecCounter,\n\t\t\t\t\"upstream_connect_msec\":           upstream.UConnectMsec,\n\t\t\t\t\"upstream_connect_msec_counter\":   upstream.UConnectMsecCounter,\n\t\t\t\t\"upstream_firstbyte_msec\":         upstream.UFirstByteMsec,\n\t\t\t\t\"upstream_firstbyte_msec_counter\": upstream.UFirstByteMsecCounter,\n\t\t\t\t\"in_bytes\":                        upstream.InBytes,\n\t\t\t\t\"out_bytes\":                       upstream.OutBytes,\n\n\t\t\t\t\"response_1xx_count\": upstream.Responses.OneXx,\n\t\t\t\t\"response_2xx_count\": upstream.Responses.TwoXx,\n\t\t\t\t\"response_3xx_count\": upstream.Responses.ThreeXx,\n\t\t\t\t\"response_4xx_count\": upstream.Responses.FourXx,\n\t\t\t\t\"response_5xx_count\": upstream.Responses.FiveXx,\n\n\t\t\t\t\"weight\":       upstream.Weight,\n\t\t\t\t\"max_fails\":    upstream.MaxFails,\n\t\t\t\t\"fail_timeout\": upstream.FailTimeout,\n\t\t\t\t\"backup\":       upstream.Backup,\n\t\t\t\t\"down\":         upstream.Down,\n\t\t\t}, upstreamServerTags)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Get tag(s) for the nginx plugin\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"source\": host, \"port\": port}\n}\n\nfunc init() {\n\tinputs.Add(\"nginx_sts\", func() telegraf.Input {\n\t\treturn &NginxSTS{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_sts/nginx_sts_test.go",
    "content": "package nginx_sts\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleStatusResponse = `\n{\n    \"hostName\": \"test.example.com\",\n    \"nginxVersion\": \"1.12.2\",\n    \"loadMsec\": 1518180328331,\n    \"nowMsec\": 1518256058416,\n    \"connections\": {\n        \"active\": 111,\n        \"reading\": 222,\n        \"writing\": 333,\n        \"waiting\": 444,\n        \"accepted\": 555,\n        \"handled\": 666,\n        \"requests\": 777\n    },\n    \"streamServerZones\": {\n        \"example.com\": {\n            \"connectCounter\": 1415887,\n            \"inBytes\": 1296356607,\n            \"outBytes\": 4404939605,\n            \"responses\": {\n                \"1xx\": 100,\n                \"2xx\": 200,\n                \"3xx\": 300,\n                \"4xx\": 400,\n                \"5xx\": 500\n            },\n            \"sessionMsecCounter\": 13,\n            \"sessionMsec\": 14\n        },\n        \"other.example.com\": {\n            \"connectCounter\": 505,\n            \"inBytes\": 171388,\n            \"outBytes\": 1273382,\n            \"responses\": {\n                \"1xx\": 101,\n                \"2xx\": 201,\n                \"3xx\": 301,\n                \"4xx\": 401,\n                \"5xx\": 501\n            },\n            \"sessionMsecCounter\": 12,\n            \"sessionMsec\": 15\n        }\n    },\n\t\"streamFilterZones\": {\n\t\t\"country\": {\n\t\t\t\"FI\": {\n\t\t\t\t\"connectCounter\": 60,\n\t\t\t\t\"inBytes\": 2570,\n\t\t\t\t\"outBytes\": 53597,\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"1xx\": 106,\n\t\t\t\t\t\"2xx\": 206,\n\t\t\t\t\t\"3xx\": 306,\n\t\t\t\t\t\"4xx\": 406,\n\t\t\t\t\t\"5xx\": 506\n\t\t\t\t},\n                \"sessionMsecCounter\": 12,\n                \"sessionMsec\": 15\n\t\t\t}\n\t\t}\n\t},\n    \"streamUpstreamZones\": {\n        \"backend_cluster\": [\n            {\n                \"server\": \"127.0.0.1:6000\",\n                \"connectCounter\": 2103849,\n                \"inBytes\": 1774680141,\n                \"outBytes\": 11727669190,\n                \"responses\": {\n                    \"1xx\": 103,\n                    \"2xx\": 203,\n                    \"3xx\": 303,\n                    \"4xx\": 403,\n                    \"5xx\": 503\n                },\n                \"sessionMsecCounter\": 31,\n                \"sessionMsec\": 131,\n                \"uSessionMsecCounter\": 32,\n                \"uSessionMsec\": 132,\n                \"uConnectMsecCounter\": 33,\n                \"uConnectMsec\": 130,\n                \"uFirstByteMsecCounter\": 34,\n                \"uFirstByteMsec\": 129,\n                \"weight\": 32,\n                \"maxFails\": 33,\n                \"failTimeout\": 34,\n                \"backup\": false,\n                \"down\": false\n\t\t\t}\n        ],\n        \"::nogroups\": [\n            {\n                \"server\": \"127.0.0.1:4433\",\n                \"connectCounter\": 8,\n                \"inBytes\": 5013,\n                \"outBytes\": 487585,\n                \"responses\": {\n                    \"1xx\": 104,\n                    \"2xx\": 204,\n                    \"3xx\": 304,\n                    \"4xx\": 404,\n                    \"5xx\": 504\n                },\n                \"sessionMsecCounter\": 31,\n                \"sessionMsec\": 131,\n                \"uSessionMsecCounter\": 32,\n                \"uSessionMsec\": 132,\n                \"uConnectMsecCounter\": 33,\n                \"uConnectMsec\": 130,\n                \"uFirstByteMsecCounter\": 34,\n                \"uFirstByteMsec\": 129,\n                \"weight\": 36,\n                \"maxFails\": 37,\n                \"failTimeout\": 38,\n                \"backup\": true,\n                \"down\": false\n            },\n            {\n                \"server\": \"127.0.0.1:8080\",\n                \"connectCounter\": 7,\n                \"inBytes\": 2926,\n                \"outBytes\": 3846638,\n                \"responses\": {\n                    \"1xx\": 105,\n                    \"2xx\": 205,\n                    \"3xx\": 305,\n                    \"4xx\": 405,\n                    \"5xx\": 505\n                },\n                \"sessionMsecCounter\": 31,\n                \"sessionMsec\": 131,\n                \"uSessionMsecCounter\": 32,\n                \"uSessionMsec\": 132,\n                \"uConnectMsecCounter\": 33,\n                \"uConnectMsec\": 130,\n                \"uFirstByteMsecCounter\": 34,\n                \"uFirstByteMsec\": 129,\n                \"weight\": 41,\n                \"maxFails\": 42,\n                \"failTimeout\": 43,\n                \"backup\": true,\n                \"down\": true\n            }\n        ]\n    }\n}`\n\nfunc TestNginxPlusGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/status\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/status\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(w, sampleStatusResponse); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxSTS{\n\t\tUrls: []string{ts.URL + \"/status\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := n.Gather(&acc)\n\trequire.NoError(t, err)\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": uint64(555),\n\t\t\t\"active\":   uint64(111),\n\t\t\t\"handled\":  uint64(666),\n\t\t\t\"reading\":  uint64(222),\n\t\t\t\"requests\": uint64(777),\n\t\t\t\"waiting\":  uint64(444),\n\t\t\t\"writing\":  uint64(333),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_server\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":             uint64(1415887),\n\t\t\t\"in_bytes\":             uint64(1296356607),\n\t\t\t\"out_bytes\":            uint64(4404939605),\n\t\t\t\"session_msec_counter\": uint64(13),\n\t\t\t\"session_msec\":         uint64(14),\n\n\t\t\t\"response_1xx_count\": uint64(100),\n\t\t\t\"response_2xx_count\": uint64(200),\n\t\t\t\"response_3xx_count\": uint64(300),\n\t\t\t\"response_4xx_count\": uint64(400),\n\t\t\t\"response_5xx_count\": uint64(500),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"example.com\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_filter\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":             uint64(60),\n\t\t\t\"in_bytes\":             uint64(2570),\n\t\t\t\"out_bytes\":            uint64(53597),\n\t\t\t\"session_msec_counter\": uint64(12),\n\t\t\t\"session_msec\":         uint64(15),\n\n\t\t\t\"response_1xx_count\": uint64(106),\n\t\t\t\"response_2xx_count\": uint64(206),\n\t\t\t\"response_3xx_count\": uint64(306),\n\t\t\t\"response_4xx_count\": uint64(406),\n\t\t\t\"response_5xx_count\": uint64(506),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":      host,\n\t\t\t\"port\":        port,\n\t\t\t\"filter_key\":  \"FI\",\n\t\t\t\"filter_name\": \"country\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_server\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":             uint64(505),\n\t\t\t\"in_bytes\":             uint64(171388),\n\t\t\t\"out_bytes\":            uint64(1273382),\n\t\t\t\"session_msec_counter\": uint64(12),\n\t\t\t\"session_msec\":         uint64(15),\n\n\t\t\t\"response_1xx_count\": uint64(101),\n\t\t\t\"response_2xx_count\": uint64(201),\n\t\t\t\"response_3xx_count\": uint64(301),\n\t\t\t\"response_4xx_count\": uint64(401),\n\t\t\t\"response_5xx_count\": uint64(501),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"other.example.com\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":  uint64(2103849),\n\t\t\t\"in_bytes\":  uint64(1774680141),\n\t\t\t\"out_bytes\": uint64(11727669190),\n\n\t\t\t\"response_1xx_count\": uint64(103),\n\t\t\t\"response_2xx_count\": uint64(203),\n\t\t\t\"response_3xx_count\": uint64(303),\n\t\t\t\"response_4xx_count\": uint64(403),\n\t\t\t\"response_5xx_count\": uint64(503),\n\n\t\t\t\"session_msec_counter\":            uint64(31),\n\t\t\t\"session_msec\":                    uint64(131),\n\t\t\t\"upstream_session_msec_counter\":   uint64(32),\n\t\t\t\"upstream_session_msec\":           uint64(132),\n\t\t\t\"upstream_connect_msec_counter\":   uint64(33),\n\t\t\t\"upstream_connect_msec\":           uint64(130),\n\t\t\t\"upstream_firstbyte_msec_counter\": uint64(34),\n\t\t\t\"upstream_firstbyte_msec\":         uint64(129),\n\n\t\t\t\"weight\":       uint64(32),\n\t\t\t\"max_fails\":    uint64(33),\n\t\t\t\"fail_timeout\": uint64(34),\n\t\t\t\"backup\":       bool(false),\n\t\t\t\"down\":         bool(false),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"backend_cluster\",\n\t\t\t\"upstream_address\": \"127.0.0.1:6000\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":  uint64(8),\n\t\t\t\"in_bytes\":  uint64(5013),\n\t\t\t\"out_bytes\": uint64(487585),\n\n\t\t\t\"response_1xx_count\": uint64(104),\n\t\t\t\"response_2xx_count\": uint64(204),\n\t\t\t\"response_3xx_count\": uint64(304),\n\t\t\t\"response_4xx_count\": uint64(404),\n\t\t\t\"response_5xx_count\": uint64(504),\n\n\t\t\t\"session_msec_counter\":            uint64(31),\n\t\t\t\"session_msec\":                    uint64(131),\n\t\t\t\"upstream_session_msec_counter\":   uint64(32),\n\t\t\t\"upstream_session_msec\":           uint64(132),\n\t\t\t\"upstream_connect_msec_counter\":   uint64(33),\n\t\t\t\"upstream_connect_msec\":           uint64(130),\n\t\t\t\"upstream_firstbyte_msec_counter\": uint64(34),\n\t\t\t\"upstream_firstbyte_msec\":         uint64(129),\n\n\t\t\t\"weight\":       uint64(36),\n\t\t\t\"max_fails\":    uint64(37),\n\t\t\t\"fail_timeout\": uint64(38),\n\t\t\t\"backup\":       bool(true),\n\t\t\t\"down\":         bool(false),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"::nogroups\",\n\t\t\t\"upstream_address\": \"127.0.0.1:4433\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_sts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"connects\":  uint64(7),\n\t\t\t\"in_bytes\":  uint64(2926),\n\t\t\t\"out_bytes\": uint64(3846638),\n\n\t\t\t\"response_1xx_count\": uint64(105),\n\t\t\t\"response_2xx_count\": uint64(205),\n\t\t\t\"response_3xx_count\": uint64(305),\n\t\t\t\"response_4xx_count\": uint64(405),\n\t\t\t\"response_5xx_count\": uint64(505),\n\n\t\t\t\"session_msec_counter\":            uint64(31),\n\t\t\t\"session_msec\":                    uint64(131),\n\t\t\t\"upstream_session_msec_counter\":   uint64(32),\n\t\t\t\"upstream_session_msec\":           uint64(132),\n\t\t\t\"upstream_connect_msec_counter\":   uint64(33),\n\t\t\t\"upstream_connect_msec\":           uint64(130),\n\t\t\t\"upstream_firstbyte_msec_counter\": uint64(34),\n\t\t\t\"upstream_firstbyte_msec\":         uint64(129),\n\n\t\t\t\"weight\":       uint64(41),\n\t\t\t\"max_fails\":    uint64(42),\n\t\t\t\"fail_timeout\": uint64(43),\n\t\t\t\"backup\":       bool(true),\n\t\t\t\"down\":         bool(true),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"::nogroups\",\n\t\t\t\"upstream_address\": \"127.0.0.1:8080\",\n\t\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_sts/sample.conf",
    "content": "# Read Nginx virtual host traffic status module information (nginx-module-sts)\n[[inputs.nginx_sts]]\n  ## An array of ngx_http_status_module or status URI to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nginx_upstream_check/README.md",
    "content": "# Nginx Upstream Check Input Plugin\n\nThis plugin gathers metrics from the [Nginx web server][nginx] using the\n[upstream check module][upstream_check_module]. This module periodically sends\nthe configured requests to servers in the Nginx's upstream determining their\navailability.\n\n⭐ Telegraf v1.10.0\n🏷️ server, web\n💻 all\n\n[nginx]: https://www.nginx.com\n[upstream_check_module]: https://github.com/yaoweibin/nginx_upstream_check_module\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read nginx_upstream_check module status information (https://github.com/yaoweibin/nginx_upstream_check_module)\n[[inputs.nginx_upstream_check]]\n  ## An URL where Nginx Upstream check module is enabled\n  ## It should be set to return a JSON formatted response\n  url = \"http://127.0.0.1/status?format=json\"\n  ## You can also point it at a unix socket too\n  # url = \"http+unix:///var/run/nginx.sock:/status?format=json\"\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Override HTTP \"Host\" header\n  # host_header = \"check.example.com\"\n\n  ## Timeout for HTTP requests\n  timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- Measurement\n  - fall (The number of failed server check attempts, counter)\n  - rise (The number of successful server check attempts, counter)\n  - status (The reporter server status as a string)\n  - status_code (The server status code. 1 - up, 2 - down, 0 - other)\n\nThe \"status_code\" field most likely will be the most useful one because it\nallows you to determine the current state of every server and, possible, add\nsome monitoring to watch over it. InfluxDB can use string values and the\n\"status\" field can be used instead, but for most other monitoring solutions the\ninteger code will be appropriate.\n\n### Tags\n\n- All measurements have the following tags:\n  - name (The hostname or IP of the upstream server)\n  - port (The alternative check port, 0 if the default one is used)\n  - type (The check type, http/tcp)\n  - upstream (The name of the upstream block in the Nginx configuration)\n  - url (The status url used by telegraf)\n\n## Example Output\n\nWhen run with:\n\n```sh\n./telegraf --config telegraf.conf --input-filter nginx_upstream_check --test\n```\n\nIt produces:\n\n```text\nnginx_upstream_check,host=node1,name=192.168.0.1:8080,port=0,type=http,upstream=my_backends,url=http://127.0.0.1:80/status?format\\=json fall=0i,rise=100i,status=\"up\",status_code=1i 1529088524000000000\nnginx_upstream_check,host=node2,name=192.168.0.2:8080,port=0,type=http,upstream=my_backends,url=http://127.0.0.1:80/status?format\\=json fall=100i,rise=0i,status=\"down\",status_code=2i 1529088524000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nginx_upstream_check/nginx_upstream_check.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx_upstream_check\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NginxUpstreamCheck struct {\n\tURL string `toml:\"url\"`\n\n\tUsername   string            `toml:\"username\"`\n\tPassword   string            `toml:\"password\"`\n\tMethod     string            `toml:\"method\"`\n\tHeaders    map[string]string `toml:\"headers\"`\n\tHostHeader string            `toml:\"host_header\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n}\n\ntype nginxUpstreamCheckData struct {\n\tServers struct {\n\t\tTotal      uint64                     `json:\"total\"`\n\t\tGeneration uint64                     `json:\"generation\"`\n\t\tServer     []nginxUpstreamCheckServer `json:\"server\"`\n\t} `json:\"servers\"`\n}\n\ntype nginxUpstreamCheckServer struct {\n\tIndex    uint64 `json:\"index\"`\n\tUpstream string `json:\"upstream\"`\n\tName     string `json:\"name\"`\n\tStatus   string `json:\"status\"`\n\tRise     uint64 `json:\"rise\"`\n\tFall     uint64 `json:\"fall\"`\n\tType     string `json:\"type\"`\n\tPort     uint16 `json:\"port\"`\n}\n\nfunc (*NginxUpstreamCheck) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (check *NginxUpstreamCheck) Gather(accumulator telegraf.Accumulator) error {\n\tif check.client == nil {\n\t\tclient, err := check.createHTTPClient()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcheck.client = client\n\t}\n\n\tstatusURL, err := url.Parse(check.URL)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = check.gatherStatusData(statusURL.String(), accumulator)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// createHTTPClient create a clients to access API\nfunc (check *NginxUpstreamCheck) createHTTPClient() (*http.Client, error) {\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := check.HTTPClientConfig.CreateClient(ctx, check.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\n// gatherJSONData query the data source and parse the response JSON\nfunc (check *NginxUpstreamCheck) gatherJSONData(address string, value interface{}) error {\n\tvar method string\n\tif check.Method != \"\" {\n\t\tmethod = check.Method\n\t} else {\n\t\tmethod = \"GET\"\n\t}\n\n\trequest, err := http.NewRequest(method, address, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif (check.Username != \"\") || (check.Password != \"\") {\n\t\trequest.SetBasicAuth(check.Username, check.Password)\n\t}\n\tfor header, value := range check.Headers {\n\t\trequest.Header.Add(header, value)\n\t}\n\tif check.HostHeader != \"\" {\n\t\trequest.Host = check.HostHeader\n\t}\n\n\tresponse, err := check.client.Do(request)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer response.Body.Close()\n\tif response.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(response.Body, 200))\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s: %q\", address, response.Status, body)\n\t}\n\n\terr = json.NewDecoder(response.Body).Decode(value)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (check *NginxUpstreamCheck) gatherStatusData(address string, accumulator telegraf.Accumulator) error {\n\tcheckData := &nginxUpstreamCheckData{}\n\n\terr := check.gatherJSONData(address, checkData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, server := range checkData.Servers.Server {\n\t\ttags := map[string]string{\n\t\t\t\"upstream\": server.Upstream,\n\t\t\t\"type\":     server.Type,\n\t\t\t\"name\":     server.Name,\n\t\t\t\"port\":     strconv.Itoa(int(server.Port)),\n\t\t\t\"url\":      address,\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"status\":      server.Status,\n\t\t\t\"status_code\": getStatusCode(server.Status),\n\t\t\t\"rise\":        server.Rise,\n\t\t\t\"fall\":        server.Fall,\n\t\t}\n\n\t\taccumulator.AddFields(\"nginx_upstream_check\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc getStatusCode(status string) uint8 {\n\tswitch status {\n\tcase \"up\":\n\t\treturn 1\n\tcase \"down\":\n\t\treturn 2\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nfunc newNginxUpstreamCheck() *NginxUpstreamCheck {\n\treturn &NginxUpstreamCheck{\n\t\tURL:        \"http://127.0.0.1/status?format=json\",\n\t\tMethod:     \"GET\",\n\t\tHeaders:    make(map[string]string),\n\t\tHostHeader: \"\",\n\t\tHTTPClientConfig: common_http.HTTPClientConfig{\n\t\t\tTimeout: config.Duration(time.Second * 5),\n\t\t},\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"nginx_upstream_check\", func() telegraf.Input {\n\t\treturn newNginxUpstreamCheck()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_upstream_check/nginx_upstream_check_test.go",
    "content": "package nginx_upstream_check\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleStatusResponse = `\n{\n  \"servers\": {\n    \"total\": 2,\n    \"generation\": 1,\n    \"server\": [\n      {\n        \"index\": 0,\n        \"upstream\": \"upstream-1\",\n        \"name\": \"127.0.0.1:8081\",\n        \"status\": \"up\",\n        \"rise\": 1000,\n        \"fall\": 0,\n        \"type\": \"http\",\n        \"port\": 0\n      },\n      {\n        \"index\": 1,\n        \"upstream\": \"upstream-2\",\n        \"name\": \"127.0.0.1:8082\",\n        \"status\": \"down\",\n        \"rise\": 0,\n        \"fall\": 2000,\n        \"type\": \"tcp\",\n        \"port\": 8080\n      }\n    ]\n  }\n}`\n\nfunc TestNginxUpstreamCheckData(test *testing.T) {\n\ttestServer := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {\n\t\tif request.URL.Path != \"/status\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/status\", request.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tresponseWriter.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(responseWriter, sampleStatusResponse); err != nil {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer testServer.Close()\n\n\tcheck := newNginxUpstreamCheck()\n\tcheck.URL = testServer.URL + \"/status\"\n\n\tvar accumulator testutil.Accumulator\n\n\tcheckError := check.Gather(&accumulator)\n\trequire.NoError(test, checkError)\n\n\taccumulator.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"nginx_upstream_check\",\n\t\tmap[string]interface{}{\n\t\t\t\"status\":      \"up\",\n\t\t\t\"status_code\": uint8(1),\n\t\t\t\"rise\":        uint64(1000),\n\t\t\t\"fall\":        uint64(0),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"upstream\": \"upstream-1\",\n\t\t\t\"type\":     \"http\",\n\t\t\t\"name\":     \"127.0.0.1:8081\",\n\t\t\t\"port\":     \"0\",\n\t\t\t\"url\":      testServer.URL + \"/status\",\n\t\t})\n\n\taccumulator.AssertContainsTaggedFields(\n\t\ttest,\n\t\t\"nginx_upstream_check\",\n\t\tmap[string]interface{}{\n\t\t\t\"status\":      \"down\",\n\t\t\t\"status_code\": uint8(2),\n\t\t\t\"rise\":        uint64(0),\n\t\t\t\"fall\":        uint64(2000),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"upstream\": \"upstream-2\",\n\t\t\t\"type\":     \"tcp\",\n\t\t\t\"name\":     \"127.0.0.1:8082\",\n\t\t\t\"port\":     \"8080\",\n\t\t\t\"url\":      testServer.URL + \"/status\",\n\t\t})\n}\n\nfunc TestNginxUpstreamCheckRequest(test *testing.T) {\n\ttestServer := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {\n\t\tif request.URL.Path != \"/status\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/status\", request.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tresponseWriter.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(responseWriter, sampleStatusResponse); err != nil {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tif request.Method != \"POST\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Not equal, expected: %q, actual: %q\", \"POST\", request.Method)\n\t\t\treturn\n\t\t}\n\t\tif request.Header.Get(\"X-Test\") != \"test-value\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Not equal, expected: %q, actual: %q\", \"test-value\", request.Header.Get(\"X-Test\"))\n\t\t\treturn\n\t\t}\n\t\tif request.Header.Get(\"Authorization\") != \"Basic dXNlcjpwYXNzd29yZA==\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Not equal, expected: %q, actual: %q\", \"Basic dXNlcjpwYXNzd29yZA==\", request.Header.Get(\"Authorization\"))\n\t\t\treturn\n\t\t}\n\t\tif request.Host != \"status.local\" {\n\t\t\tresponseWriter.WriteHeader(http.StatusInternalServerError)\n\t\t\ttest.Errorf(\"Not equal, expected: %q, actual: %q\", \"status.local\", request.Host)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer testServer.Close()\n\n\tcheck := newNginxUpstreamCheck()\n\tcheck.URL = testServer.URL + \"/status\"\n\tcheck.Headers[\"X-test\"] = \"test-value\"\n\tcheck.HostHeader = \"status.local\"\n\tcheck.Username = \"user\"\n\tcheck.Password = \"password\"\n\tcheck.Method = \"POST\"\n\n\tvar accumulator testutil.Accumulator\n\n\tcheckError := check.Gather(&accumulator)\n\trequire.NoError(test, checkError)\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_upstream_check/sample.conf",
    "content": "# Read nginx_upstream_check module status information (https://github.com/yaoweibin/nginx_upstream_check_module)\n[[inputs.nginx_upstream_check]]\n  ## An URL where Nginx Upstream check module is enabled\n  ## It should be set to return a JSON formatted response\n  url = \"http://127.0.0.1/status?format=json\"\n  ## You can also point it at a unix socket too\n  # url = \"http+unix:///var/run/nginx.sock:/status?format=json\"\n\n  ## HTTP method\n  # method = \"GET\"\n\n  ## Optional HTTP headers\n  # headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Override HTTP \"Host\" header\n  # host_header = \"check.example.com\"\n\n  ## Timeout for HTTP requests\n  timeout = \"5s\"\n\n  ## Optional HTTP Basic Auth credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nginx_vts/README.md",
    "content": "# Nginx Virtual Host Traffic Input Plugin\n\nThis plugin gathers metrics from the [Nginx web server][nginx] using the\n[external virtual host traffic status module][vhts_module]. This module provides\naccess to virtual host status information containing the current status of\nservers, upstreams and caches, similar to the live activity monitoring of\nNginx plus. For module configuration details please see the\n[module documentation][module_doc].\n\n⭐ Telegraf v1.9.0\n🏷️ server, web\n💻 all\n\n[nginx]: https://www.nginx.com\n[vhts_module]: https://github.com/vozlt/nginx-module-vts\n[module_doc]: https://github.com/vozlt/nginx-module-vts#synopsis\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read Nginx virtual host traffic status module information (nginx-module-vts)\n[[inputs.nginx_vts]]\n  ## An array of ngx_http_status_module or status URI to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- nginx_vts_connections\n  - active\n  - reading\n  - writing\n  - waiting\n  - accepted\n  - handled\n  - requests\n- nginx_vts_server, nginx_vts_filter\n  - requests\n  - request_time\n  - in_bytes\n  - out_bytes\n  - response_1xx_count\n  - response_2xx_count\n  - response_3xx_count\n  - response_4xx_count\n  - response_5xx_count\n  - cache_miss\n  - cache_bypass\n  - cache_expired\n  - cache_stale\n  - cache_updating\n  - cache_revalidated\n  - cache_hit\n  - cache_scarce\n- nginx_vts_upstream\n  - requests\n  - request_time\n  - response_time\n  - in_bytes\n  - out_bytes\n  - response_1xx_count\n  - response_2xx_count\n  - response_3xx_count\n  - response_4xx_count\n  - response_5xx_count\n  - weight\n  - max_fails\n  - fail_timeout\n  - backup\n  - down\n- nginx_vts_cache\n  - max_bytes\n  - used_bytes\n  - in_bytes\n  - out_bytes\n  - miss\n  - bypass\n  - expired\n  - stale\n  - updating\n  - revalidated\n  - hit\n  - scarce\n\n### Tags\n\n- nginx_vts_connections\n  - source\n  - port\n- nginx_vts_server\n  - source\n  - port\n  - zone\n- nginx_vts_filter\n  - source\n  - port\n  - filter_name\n  - filter_key\n- nginx_vts_upstream\n  - source\n  - port\n  - upstream\n  - upstream_address\n- nginx_vts_cache\n  - source\n  - port\n  - zone\n\n## Example Output\n\nUsing this configuration:\n\n```toml\n[[inputs.nginx_vts]]\n  ## An array of Nginx status URIs to gather stats.\n  urls = [\"http://localhost/status\"]\n```\n\nWhen run with:\n\n```sh\n./telegraf -config telegraf.conf -input-filter nginx_vts -test\n```\n\nIt produces:\n\n```shell\nnginx_vts_connections,source=localhost,port=80,host=localhost waiting=30i,accepted=295333i,handled=295333i,requests=6833487i,active=33i,reading=0i,writing=3i 1518341521000000000\nnginx_vts_server,zone=example.com,port=80,host=localhost,source=localhost cache_hit=158915i,in_bytes=1935528964i,out_bytes=6531366419i,response_2xx_count=809994i,response_4xx_count=16664i,cache_bypass=0i,cache_stale=0i,cache_revalidated=0i,requests=2187977i,response_1xx_count=0i,response_3xx_count=1360390i,cache_miss=2249i,cache_updating=0i,cache_scarce=0i,request_time=13i,response_5xx_count=929i,cache_expired=0i 1518341521000000000\nnginx_vts_server,host=localhost,source=localhost,port=80,zone=* requests=6775284i,in_bytes=5003242389i,out_bytes=36858233827i,cache_expired=318881i,cache_updating=0i,request_time=51i,response_1xx_count=0i,response_2xx_count=4385916i,response_4xx_count=83680i,response_5xx_count=1186i,cache_bypass=0i,cache_revalidated=0i,cache_hit=1972222i,cache_scarce=0i,response_3xx_count=2304502i,cache_miss=408251i,cache_stale=0i 1518341521000000000\nnginx_vts_filter,filter_key=FI,filter_name=country,port=80,host=localhost,source=localhost request_time=0i,in_bytes=139701i,response_3xx_count=0i,out_bytes=2644495i,response_1xx_count=0i,cache_expired=0i,cache_scarce=0i,requests=179i,cache_miss=0i,cache_bypass=0i,cache_stale=0i,cache_updating=0i,cache_revalidated=0i,cache_hit=0i,response_2xx_count=177i,response_4xx_count=2i,response_5xx_count=0i 1518341521000000000\nnginx_vts_upstream,port=80,host=localhost,upstream=backend_cluster,upstream_address=127.0.0.1:6000,source=localhost fail_timeout=10i,backup=false,request_time=31i,response_5xx_count=1081i,response_2xx_count=1877498i,max_fails=1i,in_bytes=2763336289i,out_bytes=19470265071i,weight=1i,down=false,response_time=31i,response_1xx_count=0i,response_4xx_count=76125i,requests=3379232i,response_3xx_count=1424528i 1518341521000000000\nnginx_vts_cache,source=localhost,port=80,host=localhost,zone=example stale=0i,used_bytes=64334336i,miss=394573i,bypass=0i,expired=318788i,updating=0i,revalidated=0i,hit=689883i,scarce=0i,max_bytes=9223372036854775296i,in_bytes=1111161581i,out_bytes=19175548290i 1518341521000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nginx_vts/nginx_vts.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nginx_vts\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NginxVTS struct {\n\tUrls []string        `toml:\"urls\"`\n\tLog  telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n}\n\nfunc (*NginxVTS) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NginxVTS) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\t// Create an HTTP client that is re-used for each\n\t// collection interval\n\n\tif n.client == nil {\n\t\tclient, err := n.createHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.client = client\n\t}\n\n\tfor _, u := range n.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NginxVTS) createHTTPClient() (*http.Client, error) {\n\tif n.HTTPClientConfig.ResponseHeaderTimeout < config.Duration(time.Second) {\n\t\tn.HTTPClientConfig.ResponseHeaderTimeout = config.Duration(time.Second * 5)\n\t}\n\n\t// Create the client\n\tctx := context.Background()\n\tclient, err := n.HTTPClientConfig.CreateClient(ctx, n.Log)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating client failed: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\nfunc (n *NginxVTS) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tresp, err := n.client.Get(addr.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", addr.String(), err)\n\t}\n\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\tcontentType := strings.Split(resp.Header.Get(\"Content-Type\"), \";\")[0]\n\tswitch contentType {\n\tcase \"application/json\":\n\t\treturn gatherStatusURL(bufio.NewReader(resp.Body), getTags(addr), acc)\n\tdefault:\n\t\treturn fmt.Errorf(\"%s returned unexpected content type %s\", addr.String(), contentType)\n\t}\n}\n\ntype nginxVTSResponse struct {\n\tConnections struct {\n\t\tActive   uint64 `json:\"active\"`\n\t\tReading  uint64 `json:\"reading\"`\n\t\tWriting  uint64 `json:\"writing\"`\n\t\tWaiting  uint64 `json:\"waiting\"`\n\t\tAccepted uint64 `json:\"accepted\"`\n\t\tHandled  uint64 `json:\"handled\"`\n\t\tRequests uint64 `json:\"requests\"`\n\t} `json:\"connections\"`\n\tServerZones   map[string]server            `json:\"serverZones\"`\n\tFilterZones   map[string]map[string]server `json:\"filterZones\"`\n\tUpstreamZones map[string][]upstream        `json:\"upstreamZones\"`\n\tCacheZones    map[string]cache             `json:\"cacheZones\"`\n}\n\ntype server struct {\n\tRequestCounter uint64 `json:\"requestCounter\"`\n\tInBytes        uint64 `json:\"inBytes\"`\n\tOutBytes       uint64 `json:\"outBytes\"`\n\tRequestMsec    uint64 `json:\"requestMsec\"`\n\tResponses      struct {\n\t\tOneXx       uint64 `json:\"1xx\"`\n\t\tTwoXx       uint64 `json:\"2xx\"`\n\t\tThreeXx     uint64 `json:\"3xx\"`\n\t\tFourXx      uint64 `json:\"4xx\"`\n\t\tFiveXx      uint64 `json:\"5xx\"`\n\t\tMiss        uint64 `json:\"miss\"`\n\t\tBypass      uint64 `json:\"bypass\"`\n\t\tExpired     uint64 `json:\"expired\"`\n\t\tStale       uint64 `json:\"stale\"`\n\t\tUpdating    uint64 `json:\"updating\"`\n\t\tRevalidated uint64 `json:\"revalidated\"`\n\t\tHit         uint64 `json:\"hit\"`\n\t\tScarce      uint64 `json:\"scarce\"`\n\t} `json:\"responses\"`\n}\n\ntype upstream struct {\n\tServer         string `json:\"server\"`\n\tRequestCounter uint64 `json:\"requestCounter\"`\n\tInBytes        uint64 `json:\"inBytes\"`\n\tOutBytes       uint64 `json:\"outBytes\"`\n\tResponses      struct {\n\t\tOneXx   uint64 `json:\"1xx\"`\n\t\tTwoXx   uint64 `json:\"2xx\"`\n\t\tThreeXx uint64 `json:\"3xx\"`\n\t\tFourXx  uint64 `json:\"4xx\"`\n\t\tFiveXx  uint64 `json:\"5xx\"`\n\t} `json:\"responses\"`\n\tResponseMsec uint64 `json:\"responseMsec\"`\n\tRequestMsec  uint64 `json:\"requestMsec\"`\n\tWeight       uint64 `json:\"weight\"`\n\tMaxFails     uint64 `json:\"maxFails\"`\n\tFailTimeout  uint64 `json:\"failTimeout\"`\n\tBackup       bool   `json:\"backup\"`\n\tDown         bool   `json:\"down\"`\n}\n\ntype cache struct {\n\tMaxSize   uint64 `json:\"maxSize\"`\n\tUsedSize  uint64 `json:\"usedSize\"`\n\tInBytes   uint64 `json:\"inBytes\"`\n\tOutBytes  uint64 `json:\"outBytes\"`\n\tResponses struct {\n\t\tMiss        uint64 `json:\"miss\"`\n\t\tBypass      uint64 `json:\"bypass\"`\n\t\tExpired     uint64 `json:\"expired\"`\n\t\tStale       uint64 `json:\"stale\"`\n\t\tUpdating    uint64 `json:\"updating\"`\n\t\tRevalidated uint64 `json:\"revalidated\"`\n\t\tHit         uint64 `json:\"hit\"`\n\t\tScarce      uint64 `json:\"scarce\"`\n\t} `json:\"responses\"`\n}\n\nfunc gatherStatusURL(r *bufio.Reader, tags map[string]string, acc telegraf.Accumulator) error {\n\tdec := json.NewDecoder(r)\n\tstatus := &nginxVTSResponse{}\n\tif err := dec.Decode(status); err != nil {\n\t\treturn errors.New(\"error while decoding JSON response\")\n\t}\n\n\tacc.AddFields(\"nginx_vts_connections\", map[string]interface{}{\n\t\t\"active\":   status.Connections.Active,\n\t\t\"reading\":  status.Connections.Reading,\n\t\t\"writing\":  status.Connections.Writing,\n\t\t\"waiting\":  status.Connections.Waiting,\n\t\t\"accepted\": status.Connections.Accepted,\n\t\t\"handled\":  status.Connections.Handled,\n\t\t\"requests\": status.Connections.Requests,\n\t}, tags)\n\n\tfor zoneName, zone := range status.ServerZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\n\t\tacc.AddFields(\"nginx_vts_server\", map[string]interface{}{\n\t\t\t\"requests\":     zone.RequestCounter,\n\t\t\t\"request_time\": zone.RequestMsec,\n\t\t\t\"in_bytes\":     zone.InBytes,\n\t\t\t\"out_bytes\":    zone.OutBytes,\n\n\t\t\t\"response_1xx_count\": zone.Responses.OneXx,\n\t\t\t\"response_2xx_count\": zone.Responses.TwoXx,\n\t\t\t\"response_3xx_count\": zone.Responses.ThreeXx,\n\t\t\t\"response_4xx_count\": zone.Responses.FourXx,\n\t\t\t\"response_5xx_count\": zone.Responses.FiveXx,\n\n\t\t\t\"cache_miss\":        zone.Responses.Miss,\n\t\t\t\"cache_bypass\":      zone.Responses.Bypass,\n\t\t\t\"cache_expired\":     zone.Responses.Expired,\n\t\t\t\"cache_stale\":       zone.Responses.Stale,\n\t\t\t\"cache_updating\":    zone.Responses.Updating,\n\t\t\t\"cache_revalidated\": zone.Responses.Revalidated,\n\t\t\t\"cache_hit\":         zone.Responses.Hit,\n\t\t\t\"cache_scarce\":      zone.Responses.Scarce,\n\t\t}, zoneTags)\n\t}\n\n\tfor filterName, filters := range status.FilterZones {\n\t\tfor filterKey, upstream := range filters {\n\t\t\tfilterTags := make(map[string]string, len(tags)+2)\n\t\t\tfor k, v := range tags {\n\t\t\t\tfilterTags[k] = v\n\t\t\t}\n\t\t\tfilterTags[\"filter_key\"] = filterKey\n\t\t\tfilterTags[\"filter_name\"] = filterName\n\n\t\t\tacc.AddFields(\"nginx_vts_filter\", map[string]interface{}{\n\t\t\t\t\"requests\":     upstream.RequestCounter,\n\t\t\t\t\"request_time\": upstream.RequestMsec,\n\t\t\t\t\"in_bytes\":     upstream.InBytes,\n\t\t\t\t\"out_bytes\":    upstream.OutBytes,\n\n\t\t\t\t\"response_1xx_count\": upstream.Responses.OneXx,\n\t\t\t\t\"response_2xx_count\": upstream.Responses.TwoXx,\n\t\t\t\t\"response_3xx_count\": upstream.Responses.ThreeXx,\n\t\t\t\t\"response_4xx_count\": upstream.Responses.FourXx,\n\t\t\t\t\"response_5xx_count\": upstream.Responses.FiveXx,\n\n\t\t\t\t\"cache_miss\":        upstream.Responses.Miss,\n\t\t\t\t\"cache_bypass\":      upstream.Responses.Bypass,\n\t\t\t\t\"cache_expired\":     upstream.Responses.Expired,\n\t\t\t\t\"cache_stale\":       upstream.Responses.Stale,\n\t\t\t\t\"cache_updating\":    upstream.Responses.Updating,\n\t\t\t\t\"cache_revalidated\": upstream.Responses.Revalidated,\n\t\t\t\t\"cache_hit\":         upstream.Responses.Hit,\n\t\t\t\t\"cache_scarce\":      upstream.Responses.Scarce,\n\t\t\t}, filterTags)\n\t\t}\n\t}\n\n\tfor upstreamName, upstreams := range status.UpstreamZones {\n\t\tfor _, upstream := range upstreams {\n\t\t\tupstreamServerTags := make(map[string]string, len(tags)+2)\n\t\t\tfor k, v := range tags {\n\t\t\t\tupstreamServerTags[k] = v\n\t\t\t}\n\t\t\tupstreamServerTags[\"upstream\"] = upstreamName\n\t\t\tupstreamServerTags[\"upstream_address\"] = upstream.Server\n\t\t\tacc.AddFields(\"nginx_vts_upstream\", map[string]interface{}{\n\t\t\t\t\"requests\":      upstream.RequestCounter,\n\t\t\t\t\"request_time\":  upstream.RequestMsec,\n\t\t\t\t\"response_time\": upstream.ResponseMsec,\n\t\t\t\t\"in_bytes\":      upstream.InBytes,\n\t\t\t\t\"out_bytes\":     upstream.OutBytes,\n\n\t\t\t\t\"response_1xx_count\": upstream.Responses.OneXx,\n\t\t\t\t\"response_2xx_count\": upstream.Responses.TwoXx,\n\t\t\t\t\"response_3xx_count\": upstream.Responses.ThreeXx,\n\t\t\t\t\"response_4xx_count\": upstream.Responses.FourXx,\n\t\t\t\t\"response_5xx_count\": upstream.Responses.FiveXx,\n\n\t\t\t\t\"weight\":       upstream.Weight,\n\t\t\t\t\"max_fails\":    upstream.MaxFails,\n\t\t\t\t\"fail_timeout\": upstream.FailTimeout,\n\t\t\t\t\"backup\":       upstream.Backup,\n\t\t\t\t\"down\":         upstream.Down,\n\t\t\t}, upstreamServerTags)\n\t\t}\n\t}\n\n\tfor zoneName, zone := range status.CacheZones {\n\t\tzoneTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tzoneTags[k] = v\n\t\t}\n\t\tzoneTags[\"zone\"] = zoneName\n\n\t\tacc.AddFields(\"nginx_vts_cache\", map[string]interface{}{\n\t\t\t\"max_bytes\":  zone.MaxSize,\n\t\t\t\"used_bytes\": zone.UsedSize,\n\t\t\t\"in_bytes\":   zone.InBytes,\n\t\t\t\"out_bytes\":  zone.OutBytes,\n\n\t\t\t\"miss\":        zone.Responses.Miss,\n\t\t\t\"bypass\":      zone.Responses.Bypass,\n\t\t\t\"expired\":     zone.Responses.Expired,\n\t\t\t\"stale\":       zone.Responses.Stale,\n\t\t\t\"updating\":    zone.Responses.Updating,\n\t\t\t\"revalidated\": zone.Responses.Revalidated,\n\t\t\t\"hit\":         zone.Responses.Hit,\n\t\t\t\"scarce\":      zone.Responses.Scarce,\n\t\t}, zoneTags)\n\t}\n\n\treturn nil\n}\n\n// Get tag(s) for the nginx plugin\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"source\": host, \"port\": port}\n}\n\nfunc init() {\n\tinputs.Add(\"nginx_vts\", func() telegraf.Input {\n\t\treturn &NginxVTS{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_vts/nginx_vts_test.go",
    "content": "package nginx_vts\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleStatusResponse = `\n{\n    \"hostName\": \"test.example.com\",\n    \"nginxVersion\": \"1.12.2\",\n    \"loadMsec\": 1518180328331,\n    \"nowMsec\": 1518256058416,\n    \"connections\": {\n        \"active\": 111,\n        \"reading\": 222,\n        \"writing\": 333,\n        \"waiting\": 444,\n        \"accepted\": 555,\n        \"handled\": 666,\n        \"requests\": 777\n    },\n    \"serverZones\": {\n        \"example.com\": {\n            \"requestCounter\": 1415887,\n            \"inBytes\": 1296356607,\n            \"outBytes\": 4404939605,\n            \"responses\": {\n                \"1xx\": 100,\n                \"2xx\": 200,\n                \"3xx\": 300,\n                \"4xx\": 400,\n                \"5xx\": 500,\n                \"miss\": 14,\n                \"bypass\": 15,\n                \"expired\": 16,\n                \"stale\": 17,\n                \"updating\": 18,\n                \"revalidated\": 19,\n                \"hit\": 20,\n                \"scarce\": 21\n            },\n            \"requestMsec\": 13\n        },\n        \"other.example.com\": {\n            \"requestCounter\": 505,\n            \"inBytes\": 171388,\n            \"outBytes\": 1273382,\n            \"responses\": {\n                \"1xx\": 101,\n                \"2xx\": 201,\n                \"3xx\": 301,\n                \"4xx\": 401,\n                \"5xx\": 501,\n                \"miss\": 22,\n                \"bypass\": 23,\n                \"expired\": 24,\n                \"stale\": 25,\n                \"updating\": 26,\n                \"revalidated\": 27,\n                \"hit\": 28,\n                \"scarce\": 29\n            },\n            \"requestMsec\": 12\n        }\n    },\n\t\"filterZones\": {\n\t\t\"country\": {\n\t\t\t\"FI\": {\n\t\t\t\t\"requestCounter\": 60,\n\t\t\t\t\"inBytes\": 2570,\n\t\t\t\t\"outBytes\": 53597,\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"1xx\": 106,\n\t\t\t\t\t\"2xx\": 206,\n\t\t\t\t\t\"3xx\": 306,\n\t\t\t\t\t\"4xx\": 406,\n\t\t\t\t\t\"5xx\": 506,\n\t\t\t\t\t\"miss\": 61,\n\t\t\t\t\t\"bypass\": 62,\n\t\t\t\t\t\"expired\": 63,\n\t\t\t\t\t\"stale\": 64,\n\t\t\t\t\t\"updating\": 65,\n\t\t\t\t\t\"revalidated\": 66,\n\t\t\t\t\t\"hit\": 67,\n\t\t\t\t\t\"scarce\": 68\n\t\t\t\t},\n\t\t\t\t\"requestMsec\": 69\n\t\t\t}\n\t\t}\n\t},\n    \"upstreamZones\": {\n        \"backend_cluster\": [\n            {\n                \"server\": \"127.0.0.1:6000\",\n                \"requestCounter\": 2103849,\n                \"inBytes\": 1774680141,\n                \"outBytes\": 11727669190,\n                \"responses\": {\n                    \"1xx\": 103,\n                    \"2xx\": 203,\n                    \"3xx\": 303,\n                    \"4xx\": 403,\n                    \"5xx\": 503\n                },\n                \"requestMsec\": 30,\n                \"responseMsec\": 31,\n                \"weight\": 32,\n                \"maxFails\": 33,\n                \"failTimeout\": 34,\n                \"backup\": false,\n                \"down\": false\n\t\t\t}\n        ],\n        \"::nogroups\": [\n            {\n                \"server\": \"127.0.0.1:4433\",\n                \"requestCounter\": 8,\n                \"inBytes\": 5013,\n                \"outBytes\": 487585,\n                \"responses\": {\n                    \"1xx\": 104,\n                    \"2xx\": 204,\n                    \"3xx\": 304,\n                    \"4xx\": 404,\n                    \"5xx\": 504\n                },\n                \"requestMsec\": 34,\n                \"responseMsec\": 35,\n                \"weight\": 36,\n                \"maxFails\": 37,\n                \"failTimeout\": 38,\n                \"backup\": true,\n                \"down\": false\n            },\n            {\n                \"server\": \"127.0.0.1:8080\",\n                \"requestCounter\": 7,\n                \"inBytes\": 2926,\n                \"outBytes\": 3846638,\n                \"responses\": {\n                    \"1xx\": 105,\n                    \"2xx\": 205,\n                    \"3xx\": 305,\n                    \"4xx\": 405,\n                    \"5xx\": 505\n                },\n                \"requestMsec\": 39,\n                \"responseMsec\": 40,\n                \"weight\": 41,\n                \"maxFails\": 42,\n                \"failTimeout\": 43,\n                \"backup\": true,\n                \"down\": true\n            }\n        ]\n    },\n    \"cacheZones\": {\n        \"example\": {\n            \"maxSize\": 9223372036854776000,\n            \"usedSize\": 68639232,\n            \"inBytes\": 697138673,\n            \"outBytes\": 11305044106,\n            \"responses\": {\n                \"miss\": 44,\n                \"bypass\": 45,\n                \"expired\": 46,\n                \"stale\": 47,\n                \"updating\": 48,\n                \"revalidated\": 49,\n                \"hit\": 50,\n                \"scarce\": 51\n            }\n        },\n        \"static\": {\n            \"maxSize\": 9223372036854776000,\n            \"usedSize\": 569856,\n            \"inBytes\": 551652333,\n            \"outBytes\": 1114889271,\n            \"responses\": {\n                \"miss\": 52,\n                \"bypass\": 53,\n                \"expired\": 54,\n                \"stale\": 55,\n                \"updating\": 56,\n                \"revalidated\": 57,\n                \"hit\": 58,\n                \"scarce\": 59\n            }\n        }\n    }\n}`\n\nfunc TestNginxPlusGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/status\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/status\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\tif _, err := fmt.Fprintln(w, sampleStatusResponse); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &NginxVTS{\n\t\tUrls: []string{ts.URL + \"/status\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := n.Gather(&acc)\n\trequire.NoError(t, err)\n\n\taddr, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_connections\",\n\t\tmap[string]interface{}{\n\t\t\t\"accepted\": uint64(555),\n\t\t\t\"active\":   uint64(111),\n\t\t\t\"handled\":  uint64(666),\n\t\t\t\"reading\":  uint64(222),\n\t\t\t\"requests\": uint64(777),\n\t\t\t\"waiting\":  uint64(444),\n\t\t\t\"writing\":  uint64(333),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_server\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":     uint64(1415887),\n\t\t\t\"request_time\": uint64(13),\n\t\t\t\"in_bytes\":     uint64(1296356607),\n\t\t\t\"out_bytes\":    uint64(4404939605),\n\n\t\t\t\"response_1xx_count\": uint64(100),\n\t\t\t\"response_2xx_count\": uint64(200),\n\t\t\t\"response_3xx_count\": uint64(300),\n\t\t\t\"response_4xx_count\": uint64(400),\n\t\t\t\"response_5xx_count\": uint64(500),\n\n\t\t\t\"cache_miss\":        uint64(14),\n\t\t\t\"cache_bypass\":      uint64(15),\n\t\t\t\"cache_expired\":     uint64(16),\n\t\t\t\"cache_stale\":       uint64(17),\n\t\t\t\"cache_updating\":    uint64(18),\n\t\t\t\"cache_revalidated\": uint64(19),\n\t\t\t\"cache_hit\":         uint64(20),\n\t\t\t\"cache_scarce\":      uint64(21),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"example.com\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_filter\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":     uint64(60),\n\t\t\t\"request_time\": uint64(69),\n\t\t\t\"in_bytes\":     uint64(2570),\n\t\t\t\"out_bytes\":    uint64(53597),\n\n\t\t\t\"response_1xx_count\": uint64(106),\n\t\t\t\"response_2xx_count\": uint64(206),\n\t\t\t\"response_3xx_count\": uint64(306),\n\t\t\t\"response_4xx_count\": uint64(406),\n\t\t\t\"response_5xx_count\": uint64(506),\n\n\t\t\t\"cache_miss\":        uint64(61),\n\t\t\t\"cache_bypass\":      uint64(62),\n\t\t\t\"cache_expired\":     uint64(63),\n\t\t\t\"cache_stale\":       uint64(64),\n\t\t\t\"cache_updating\":    uint64(65),\n\t\t\t\"cache_revalidated\": uint64(66),\n\t\t\t\"cache_hit\":         uint64(67),\n\t\t\t\"cache_scarce\":      uint64(68),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":      host,\n\t\t\t\"port\":        port,\n\t\t\t\"filter_key\":  \"FI\",\n\t\t\t\"filter_name\": \"country\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_server\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":     uint64(505),\n\t\t\t\"request_time\": uint64(12),\n\t\t\t\"in_bytes\":     uint64(171388),\n\t\t\t\"out_bytes\":    uint64(1273382),\n\n\t\t\t\"response_1xx_count\": uint64(101),\n\t\t\t\"response_2xx_count\": uint64(201),\n\t\t\t\"response_3xx_count\": uint64(301),\n\t\t\t\"response_4xx_count\": uint64(401),\n\t\t\t\"response_5xx_count\": uint64(501),\n\n\t\t\t\"cache_miss\":        uint64(22),\n\t\t\t\"cache_bypass\":      uint64(23),\n\t\t\t\"cache_expired\":     uint64(24),\n\t\t\t\"cache_stale\":       uint64(25),\n\t\t\t\"cache_updating\":    uint64(26),\n\t\t\t\"cache_revalidated\": uint64(27),\n\t\t\t\"cache_hit\":         uint64(28),\n\t\t\t\"cache_scarce\":      uint64(29),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"other.example.com\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":      uint64(2103849),\n\t\t\t\"request_time\":  uint64(30),\n\t\t\t\"response_time\": uint64(31),\n\t\t\t\"in_bytes\":      uint64(1774680141),\n\t\t\t\"out_bytes\":     uint64(11727669190),\n\n\t\t\t\"response_1xx_count\": uint64(103),\n\t\t\t\"response_2xx_count\": uint64(203),\n\t\t\t\"response_3xx_count\": uint64(303),\n\t\t\t\"response_4xx_count\": uint64(403),\n\t\t\t\"response_5xx_count\": uint64(503),\n\n\t\t\t\"weight\":       uint64(32),\n\t\t\t\"max_fails\":    uint64(33),\n\t\t\t\"fail_timeout\": uint64(34),\n\t\t\t\"backup\":       bool(false),\n\t\t\t\"down\":         bool(false),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"backend_cluster\",\n\t\t\t\"upstream_address\": \"127.0.0.1:6000\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":      uint64(8),\n\t\t\t\"request_time\":  uint64(34),\n\t\t\t\"response_time\": uint64(35),\n\t\t\t\"in_bytes\":      uint64(5013),\n\t\t\t\"out_bytes\":     uint64(487585),\n\n\t\t\t\"response_1xx_count\": uint64(104),\n\t\t\t\"response_2xx_count\": uint64(204),\n\t\t\t\"response_3xx_count\": uint64(304),\n\t\t\t\"response_4xx_count\": uint64(404),\n\t\t\t\"response_5xx_count\": uint64(504),\n\n\t\t\t\"weight\":       uint64(36),\n\t\t\t\"max_fails\":    uint64(37),\n\t\t\t\"fail_timeout\": uint64(38),\n\t\t\t\"backup\":       bool(true),\n\t\t\t\"down\":         bool(false),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"::nogroups\",\n\t\t\t\"upstream_address\": \"127.0.0.1:4433\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_upstream\",\n\t\tmap[string]interface{}{\n\t\t\t\"requests\":      uint64(7),\n\t\t\t\"request_time\":  uint64(39),\n\t\t\t\"response_time\": uint64(40),\n\t\t\t\"in_bytes\":      uint64(2926),\n\t\t\t\"out_bytes\":     uint64(3846638),\n\n\t\t\t\"response_1xx_count\": uint64(105),\n\t\t\t\"response_2xx_count\": uint64(205),\n\t\t\t\"response_3xx_count\": uint64(305),\n\t\t\t\"response_4xx_count\": uint64(405),\n\t\t\t\"response_5xx_count\": uint64(505),\n\n\t\t\t\"weight\":       uint64(41),\n\t\t\t\"max_fails\":    uint64(42),\n\t\t\t\"fail_timeout\": uint64(43),\n\t\t\t\"backup\":       bool(true),\n\t\t\t\"down\":         bool(true),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\":           host,\n\t\t\t\"port\":             port,\n\t\t\t\"upstream\":         \"::nogroups\",\n\t\t\t\"upstream_address\": \"127.0.0.1:8080\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_cache\",\n\t\tmap[string]interface{}{\n\t\t\t\"max_bytes\":  uint64(9223372036854776000),\n\t\t\t\"used_bytes\": uint64(68639232),\n\t\t\t\"in_bytes\":   uint64(697138673),\n\t\t\t\"out_bytes\":  uint64(11305044106),\n\n\t\t\t\"miss\":        uint64(44),\n\t\t\t\"bypass\":      uint64(45),\n\t\t\t\"expired\":     uint64(46),\n\t\t\t\"stale\":       uint64(47),\n\t\t\t\"updating\":    uint64(48),\n\t\t\t\"revalidated\": uint64(49),\n\t\t\t\"hit\":         uint64(50),\n\t\t\t\"scarce\":      uint64(51),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"example\",\n\t\t})\n\n\tacc.AssertContainsTaggedFields(\n\t\tt,\n\t\t\"nginx_vts_cache\",\n\t\tmap[string]interface{}{\n\t\t\t\"max_bytes\":  uint64(9223372036854776000),\n\t\t\t\"used_bytes\": uint64(569856),\n\t\t\t\"in_bytes\":   uint64(551652333),\n\t\t\t\"out_bytes\":  uint64(1114889271),\n\n\t\t\t\"miss\":        uint64(52),\n\t\t\t\"bypass\":      uint64(53),\n\t\t\t\"expired\":     uint64(54),\n\t\t\t\"stale\":       uint64(55),\n\t\t\t\"updating\":    uint64(56),\n\t\t\t\"revalidated\": uint64(57),\n\t\t\t\"hit\":         uint64(58),\n\t\t\t\"scarce\":      uint64(59),\n\t\t},\n\t\tmap[string]string{\n\t\t\t\"source\": host,\n\t\t\t\"port\":   port,\n\t\t\t\"zone\":   \"static\",\n\t\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nginx_vts/sample.conf",
    "content": "# Read Nginx virtual host traffic status module information (nginx-module-vts)\n[[inputs.nginx_vts]]\n  ## An array of ngx_http_status_module or status URI to gather stats.\n  urls = [\"http://localhost/status\", \"http+unix:///var/run/nginx.sock:/status\"]\n\n  ## HTTP response timeout (default: 5s)\n  response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nomad/README.md",
    "content": "# Hashicorp Nomad Input Plugin\n\nThis plugin collects metrics from every [Nomad agent][nomad] of the specified\ncluster. Telegraf may be present in every node and connect to the agent locally.\n\n⭐ Telegraf v1.22.0\n🏷️ server\n💻 all\n\n[nomad]: https://www.nomadproject.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from the Nomad API\n[[inputs.nomad]]\n  ## URL for the Nomad agent\n  # url = \"http://127.0.0.1:4646\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n```\n\n## Metrics\n\nBoth Nomad servers and agents collect various metrics. For every details, please\nhave a look at [Nomad metrics][metrics] and [Nomad telemetry][telemetry]\nocumentation.\n\n[metrics]: https://www.nomadproject.io/docs/operations/metrics\n[telemetry]: https://www.nomadproject.io/docs/operations/telemetry\n\n## Example Output\n\nThere is no predefined metric format, so output depends on plugin input.\n"
  },
  {
    "path": "plugins/inputs/nomad/nomad.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nomad\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst timeLayout = \"2006-01-02 15:04:05 -0700 MST\"\n\ntype Nomad struct {\n\tURL             string          `toml:\"url\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\ttls.ClientConfig\n\n\troundTripper http.RoundTripper\n}\n\nfunc (*Nomad) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Nomad) Init() error {\n\tif n.URL == \"\" {\n\t\tn.URL = \"http://127.0.0.1:4646\"\n\t}\n\n\ttlsCfg, err := n.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"setting up TLS configuration failed: %w\", err)\n\t}\n\n\tn.roundTripper = &http.Transport{\n\t\tTLSHandshakeTimeout:   5 * time.Second,\n\t\tTLSClientConfig:       tlsCfg,\n\t\tResponseHeaderTimeout: time.Duration(n.ResponseTimeout),\n\t}\n\n\treturn nil\n}\n\nfunc (n *Nomad) Gather(acc telegraf.Accumulator) error {\n\tsummaryMetrics := &metricsSummary{}\n\terr := n.loadJSON(n.URL+\"/v1/metrics\", summaryMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = buildNomadMetrics(acc, summaryMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (n *Nomad) loadJSON(url string, v interface{}) error {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := n.roundTripper.RoundTrip(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", url, resp.Status)\n\t}\n\n\terr = json.NewDecoder(resp.Body).Decode(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing json response: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// buildNomadMetrics, it builds all the metrics and adds them to the accumulator)\nfunc buildNomadMetrics(acc telegraf.Accumulator, summaryMetrics *metricsSummary) error {\n\tt, err := internal.ParseTimestamp(timeLayout, summaryMetrics.Timestamp, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing time: %w\", err)\n\t}\n\n\tfor _, counters := range summaryMetrics.Counters {\n\t\ttags := counters.DisplayLabels\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"count\": counters.Count,\n\t\t\t\"rate\":  counters.Rate,\n\t\t\t\"sum\":   counters.Sum,\n\t\t\t\"sumsq\": counters.SumSq,\n\t\t\t\"min\":   counters.Min,\n\t\t\t\"max\":   counters.Max,\n\t\t\t\"mean\":  counters.Mean,\n\t\t}\n\t\tacc.AddCounter(counters.Name, fields, tags, t)\n\t}\n\n\tfor _, gauges := range summaryMetrics.Gauges {\n\t\ttags := gauges.DisplayLabels\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": gauges.Value,\n\t\t}\n\n\t\tacc.AddGauge(gauges.Name, fields, tags, t)\n\t}\n\n\tfor _, points := range summaryMetrics.Points {\n\t\ttags := make(map[string]string)\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"value\": points.Points,\n\t\t}\n\n\t\tacc.AddFields(points.Name, fields, tags, t)\n\t}\n\n\tfor _, samples := range summaryMetrics.Samples {\n\t\ttags := samples.DisplayLabels\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"count\":  samples.Count,\n\t\t\t\"rate\":   samples.Rate,\n\t\t\t\"sum\":    samples.Sum,\n\t\t\t\"stddev\": samples.Stddev,\n\t\t\t\"sumsq\":  samples.SumSq,\n\t\t\t\"min\":    samples.Min,\n\t\t\t\"max\":    samples.Max,\n\t\t\t\"mean\":   samples.Mean,\n\t\t}\n\t\tacc.AddCounter(samples.Name, fields, tags, t)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"nomad\", func() telegraf.Input {\n\t\treturn &Nomad{\n\t\t\tResponseTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nomad/nomad_metrics.go",
    "content": "package nomad\n\nimport (\n\t\"time\"\n)\n\ntype metricsSummary struct {\n\tTimestamp string         `json:\"timestamp\"`\n\tGauges    []gaugeValue   `json:\"gauges\"`\n\tPoints    []pointValue   `json:\"points\"`\n\tCounters  []sampledValue `json:\"counters\"`\n\tSamples   []sampledValue `json:\"samples\"`\n}\n\ntype gaugeValue struct {\n\tName  string  `json:\"name\"`\n\tHash  string  `json:\"-\"`\n\tValue float32 `json:\"value\"`\n\n\tLabels        []label           `json:\"-\"`\n\tDisplayLabels map[string]string `json:\"Labels\"`\n}\n\ntype pointValue struct {\n\tName   string    `json:\"name\"`\n\tPoints []float32 `json:\"points\"`\n}\n\ntype sampledValue struct {\n\tName string `json:\"name\"`\n\tHash string `json:\"-\"`\n\t*AggregateSample\n\tMean   float64 `json:\"mean\"`\n\tStddev float64 `json:\"stddev\"`\n\n\tLabels        []label           `json:\"-\"`\n\tDisplayLabels map[string]string `json:\"Labels\"`\n}\n\n// AggregateSample needs to be exported, because JSON decode cannot set embedded pointer to unexported struct\ntype AggregateSample struct {\n\tCount       int       `json:\"count\"`\n\tRate        float64   `json:\"rate\"`\n\tSum         float64   `json:\"sum\"`\n\tSumSq       float64   `json:\"-\"`\n\tMin         float64   `json:\"min\"`\n\tMax         float64   `json:\"max\"`\n\tLastUpdated time.Time `json:\"-\"`\n}\n\ntype label struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n"
  },
  {
    "path": "plugins/inputs/nomad/nomad_test.go",
    "content": "package nomad\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNomadStats(t *testing.T) {\n\tvar applyTests = []struct {\n\t\tname     string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"Metrics\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nomad.nomad.rpc.query\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"host\": \"node1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\": int(7),\n\t\t\t\t\t\t\"max\":   float64(1),\n\t\t\t\t\t\t\"min\":   float64(1),\n\t\t\t\t\t\t\"mean\":  float64(1),\n\t\t\t\t\t\t\"rate\":  float64(0.7),\n\t\t\t\t\t\t\"sum\":   float64(7),\n\t\t\t\t\t\t\"sumsq\": float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1636843140, 0),\n\t\t\t\t\t1,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nomad.client.allocated.cpu\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"node_scheduling_eligibility\": \"eligible\",\n\t\t\t\t\t\t\"host\":                        \"node1\",\n\t\t\t\t\t\t\"node_id\":                     \"2bbff078-8473-a9de-6c5e-42b4e053e12f\",\n\t\t\t\t\t\t\"datacenter\":                  \"dc1\",\n\t\t\t\t\t\t\"node_class\":                  \"none\",\n\t\t\t\t\t\t\"node_status\":                 \"ready\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"value\": float32(500),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1636843140, 0),\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nomad.memberlist.gossip\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"host\": \"node1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"count\":  int(20),\n\t\t\t\t\t\t\"max\":    float64(0.03747599944472313),\n\t\t\t\t\t\t\"mean\":   float64(0.013159099989570678),\n\t\t\t\t\t\t\"min\":    float64(0.003459000028669834),\n\t\t\t\t\t\t\"rate\":   float64(0.026318199979141355),\n\t\t\t\t\t\t\"stddev\": float64(0.009523742715522742),\n\t\t\t\t\t\t\"sum\":    float64(0.26318199979141355),\n\t\t\t\t\t\t\"sumsq\":  float64(0),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1636843140, 0),\n\t\t\t\t\t1,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range applyTests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif r.RequestURI == \"/v1/metrics\" {\n\t\t\t\t\tresponseKeyMetrics, err := os.ReadFile(\"testdata/response_key_metrics.json\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tif _, err = fmt.Fprintln(w, string(responseKeyMetrics)); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Nomad{\n\t\t\t\tURL: ts.URL,\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tacc := testutil.Accumulator{}\n\t\t\terr = plugin.Gather(&acc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/nomad/sample.conf",
    "content": "# Read metrics from the Nomad API\n[[inputs.nomad]]\n  ## URL for the Nomad agent\n  # url = \"http://127.0.0.1:4646\"\n\n  ## Set response_timeout (default 5 seconds)\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n"
  },
  {
    "path": "plugins/inputs/nomad/testdata/response_key_metrics.json",
    "content": "{\n\t\"Counters\": [\n\t\t{\n\t\t\t\"Count\": 7,\n\t\t\t\"Labels\": {\n\t\t\t\t\"host\": \"node1\"\n\t\t\t},\n\t\t\t\"Max\": 1,\n\t\t\t\"Mean\": 1,\n\t\t\t\"Min\": 1,\n\t\t\t\"Name\": \"nomad.nomad.rpc.query\",\n\t\t\t\"Rate\": 0.7,\n\t\t\t\"Stddev\": 0,\n\t\t\t\"Sum\": 7\n\t\t}\n\t],\n\t\"Gauges\": [\n\t\t{\n\t\t\t\"Labels\": {\n\t\t\t\t\"node_scheduling_eligibility\": \"eligible\",\n\t\t\t\t\"host\": \"node1\",\n\t\t\t\t\"node_id\": \"2bbff078-8473-a9de-6c5e-42b4e053e12f\",\n\t\t\t\t\"datacenter\": \"dc1\",\n\t\t\t\t\"node_class\": \"none\",\n\t\t\t\t\"node_status\": \"ready\"\n\t\t\t},\n\t\t\t\"Name\": \"nomad.client.allocated.cpu\",\n\t\t\t\"Value\": 500\n\t\t}\n\t],\n\t\"Points\": [],\n\t\"Samples\": [\n\t\t{\n\t\t\t\"Count\": 20,\n\t\t\t\"Labels\": {\n\t\t\t\t\"host\": \"node1\"\n\t\t\t},\n\t\t\t\"Max\": 0.03747599944472313,\n\t\t\t\"Mean\": 0.013159099989570678,\n\t\t\t\"Min\": 0.003459000028669834,\n\t\t\t\"Name\": \"nomad.memberlist.gossip\",\n\t\t\t\"Rate\": 0.026318199979141355,\n\t\t\t\"Stddev\": 0.009523742715522742,\n\t\t\t\"Sum\": 0.26318199979141355\n\t\t}\n\t],\n\t\"Timestamp\": \"2021-11-13 22:39:00 +0000 UTC\"\n}\n"
  },
  {
    "path": "plugins/inputs/nsd/README.md",
    "content": "# NLnet Labs Name Server Daemon Input Plugin\n\nThis plugin gathers statistics from a [NLnet Labs Name Server Daemon][nsd], an\nauthoritative DNS name server.\n\n⭐ Telegraf v1.0.0\n🏷️ server\n💻 all\n\n[nsd]: https://www.nlnetlabs.nl/projects/nsd/about\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# A plugin to collect stats from the NSD DNS resolver\n[[inputs.nsd]]\n  ## Address of server to connect to, optionally ':port'. Defaults to the\n  ## address in the nsd config file.\n  server = \"127.0.0.1:8953\"\n\n  ## If running as a restricted user you can prepend sudo for additional access:\n  # use_sudo = false\n\n  ## The default location of the nsd-control binary can be overridden with:\n  # binary = \"/usr/sbin/nsd-control\"\n\n  ## The default location of the nsd config file can be overridden with:\n  # config_file = \"/etc/nsd/nsd.conf\"\n\n  ## The default timeout of 1s can be overridden with:\n  # timeout = \"1s\"\n```\n\n### Permissions\n\nIt's important to note that this plugin references nsd-control, which may\nrequire additional permissions to execute successfully.  Depending on the\nuser/group permissions of the telegraf user executing this plugin, you may\nneed to alter the group membership, set facls, or use sudo.\n\n**Group membership (Recommended)**:\n\n```bash\n$ groups telegraf\ntelegraf : telegraf\n\n$ usermod -a -G nsd telegraf\n\n$ groups telegraf\ntelegraf : telegraf nsd\n```\n\n**Sudo privileges**:\nIf you use this method, you will need the following in your telegraf config:\n\n```toml\n[[inputs.nsd]]\n  use_sudo = true\n```\n\nYou will also need to update your sudoers file:\n\n```bash\n$ visudo\n# Add the following line:\nCmnd_Alias NSDCONTROLCTL = /usr/sbin/nsd-control\ntelegraf  ALL=(ALL) NOPASSWD: NSDCONTROLCTL\nDefaults!NSDCONTROLCTL !logfile, !syslog, !pam_session\n```\n\nPlease use the solution you see as most appropriate.\n\n## Metrics\n\nThis is the full list of stats provided by nsd-control. In the output, the\ndots in the nsd-control stat name are replaced by underscores (see\n<https://www.nlnetlabs.nl/documentation/nsd/nsd-control/> for details).\n\n- nsd\n  - fields:\n    - num_queries\n    - time_boot\n    - time_elapsed\n    - size_db_disk\n    - size_db_mem\n    - size_xfrd_mem\n    - size_config_disk\n    - size_config_mem\n    - num_type_TYPE0\n    - num_type_A\n    - num_type_NS\n    - num_type_MD\n    - num_type_MF\n    - num_type_CNAME\n    - num_type_SOA\n    - num_type_MB\n    - num_type_MG\n    - num_type_MR\n    - num_type_NULL\n    - num_type_WKS\n    - num_type_PTR\n    - num_type_HINFO\n    - num_type_MINFO\n    - num_type_MX\n    - num_type_TXT\n    - num_type_RP\n    - num_type_AFSDB\n    - num_type_X25\n    - num_type_ISDN\n    - num_type_RT\n    - num_type_NSAP\n    - num_type_SIG\n    - num_type_KEY\n    - num_type_PX\n    - num_type_AAAA\n    - num_type_LOC\n    - num_type_NXT\n    - num_type_SRV\n    - num_type_NAPTR\n    - num_type_KX\n    - num_type_CERT\n    - num_type_DNAME\n    - num_type_OPT\n    - num_type_APL\n    - num_type_DS\n    - num_type_SSHFP\n    - num_type_IPSECKEY\n    - num_type_RRSIG\n    - num_type_NSEC\n    - num_type_DNSKEY\n    - num_type_DHCID\n    - num_type_NSEC3\n    - num_type_NSEC3PARAM\n    - num_type_TLSA\n    - num_type_SMIMEA\n    - num_type_CDS\n    - num_type_CDNSKEY\n    - num_type_OPENPGPKEY\n    - num_type_CSYNC\n    - num_type_SPF\n    - num_type_NID\n    - num_type_L32\n    - num_type_L64\n    - num_type_LP\n    - num_type_EUI48\n    - num_type_EUI64\n    - num_type_TYPE252\n    - num_type_TYPE253\n    - num_type_TYPE255\n    - num_opcode_QUERY\n    - num_opcode_NOTIFY\n    - num_class_CLASS0\n    - num_class_IN\n    - num_class_CH\n    - num_rcode_NOERROR\n    - num_rcode_FORMERR\n    - num_rcode_SERVFAIL\n    - num_rcode_NXDOMAIN\n    - num_rcode_NOTIMP\n    - num_rcode_REFUSED\n    - num_rcode_YXDOMAIN\n    - num_rcode_NOTAUTH\n    - num_edns\n    - num_ednserr\n    - num_udp\n    - num_udp6\n    - num_tcp\n    - num_tcp6\n    - num_tls\n    - num_tls6\n    - num_answer_wo_aa\n    - num_rxerr\n    - num_txerr\n    - num_raxfr\n    - num_truncated\n    - num_dropped\n    - zone_master\n    - zone_slave\n\n- nsd_servers\n  - tags:\n    - server\n  - fields:\n    - queries\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/nsd/nsd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nsd\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultBinary  = \"/usr/sbin/nsd-control\"\n\tdefaultTimeout = config.Duration(time.Second)\n)\n\ntype NSD struct {\n\tBinary     string          `toml:\"binary\"`\n\tTimeout    config.Duration `toml:\"timeout\"`\n\tUseSudo    bool            `toml:\"use_sudo\"`\n\tServer     string          `toml:\"server\"`\n\tConfigFile string          `toml:\"config_file\"`\n\n\trun runner\n}\n\ntype runner func(cmdName string, timeout config.Duration, useSudo bool, Server string, ConfigFile string) (*bytes.Buffer, error)\n\nfunc (*NSD) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *NSD) Gather(acc telegraf.Accumulator) error {\n\tout, err := s.run(s.Binary, s.Timeout, s.UseSudo, s.Server, s.ConfigFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error gathering metrics: %w\", err)\n\t}\n\n\t// Process values\n\tfields := make(map[string]interface{})\n\tfieldsServers := make(map[string]map[string]interface{})\n\n\tscanner := bufio.NewScanner(out)\n\tfor scanner.Scan() {\n\t\tcols := strings.Split(scanner.Text(), \"=\")\n\n\t\t// Check split correctness\n\t\tif len(cols) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tstat := cols[0]\n\t\tvalue := cols[1]\n\n\t\tfieldValue, err := strconv.ParseFloat(value, 64)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"expected a numerical value for %s = %v\",\n\t\t\t\tstat, value))\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(stat, \"server\") {\n\t\t\tstatTokens := strings.Split(stat, \".\")\n\t\t\tif len(statTokens) > 1 {\n\t\t\t\tserverID := strings.TrimPrefix(statTokens[0], \"server\")\n\t\t\t\tif _, err := strconv.Atoi(serverID); err == nil {\n\t\t\t\t\tserverTokens := statTokens[1:]\n\t\t\t\t\tfield := strings.Join(serverTokens[:], \"_\")\n\t\t\t\t\tif fieldsServers[serverID] == nil {\n\t\t\t\t\t\tfieldsServers[serverID] = make(map[string]interface{})\n\t\t\t\t\t}\n\t\t\t\t\tfieldsServers[serverID][field] = fieldValue\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfield := strings.ReplaceAll(stat, \".\", \"_\")\n\t\t\tfields[field] = fieldValue\n\t\t}\n\t}\n\n\tacc.AddFields(\"nsd\", fields, nil)\n\tfor thisServerID, thisServerFields := range fieldsServers {\n\t\tthisServerTag := map[string]string{\"server\": thisServerID}\n\t\tacc.AddFields(\"nsd_servers\", thisServerFields, thisServerTag)\n\t}\n\n\treturn nil\n}\n\n// Shell out to nsd_stat and return the output\nfunc nsdRunner(cmdName string, timeout config.Duration, useSudo bool, server, configFile string) (*bytes.Buffer, error) {\n\tcmdArgs := []string{\"stats_noreset\"}\n\n\tif server != \"\" {\n\t\thost, port, err := net.SplitHostPort(server)\n\t\tif err == nil {\n\t\t\tserver = host + \"@\" + port\n\t\t}\n\n\t\tcmdArgs = append([]string{\"-s\", server}, cmdArgs...)\n\t}\n\n\tif configFile != \"\" {\n\t\tcmdArgs = append([]string{\"-c\", configFile}, cmdArgs...)\n\t}\n\n\tcmd := exec.Command(cmdName, cmdArgs...)\n\n\tif useSudo {\n\t\tcmdArgs = append([]string{cmdName}, cmdArgs...)\n\t\tcmd = exec.Command(\"sudo\", cmdArgs...)\n\t}\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn &out, fmt.Errorf(\"error running nsd-control: %w (%s %v)\", err, cmdName, cmdArgs)\n\t}\n\n\treturn &out, nil\n}\n\nfunc init() {\n\tinputs.Add(\"nsd\", func() telegraf.Input {\n\t\treturn &NSD{\n\t\t\trun:        nsdRunner,\n\t\t\tBinary:     defaultBinary,\n\t\t\tTimeout:    defaultTimeout,\n\t\t\tUseSudo:    false,\n\t\t\tServer:     \"\",\n\t\t\tConfigFile: \"\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nsd/nsd_test.go",
    "content": "package nsd\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc nsdControl(output string) func(string, config.Duration, bool, string, string) (*bytes.Buffer, error) {\n\treturn func(string, config.Duration, bool, string, string) (*bytes.Buffer, error) {\n\t\treturn bytes.NewBufferString(output), nil\n\t}\n}\n\nfunc TestParseFullOutput(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &NSD{\n\t\trun: nsdControl(fullOutput),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasMeasurement(\"nsd\"))\n\trequire.True(t, acc.HasMeasurement(\"nsd_servers\"))\n\n\trequire.Len(t, acc.Metrics, 2)\n\trequire.Equal(t, 99, acc.NFields())\n\n\tacc.AssertContainsFields(t, \"nsd\", parsedFullOutput)\n\tacc.AssertContainsFields(t, \"nsd_servers\", parsedFullOutputServerAsTag)\n}\n\nvar parsedFullOutputServerAsTag = map[string]interface{}{\n\t\"queries\": float64(75576),\n}\n\nvar parsedFullOutput = map[string]interface{}{\n\t\"num_queries\":         float64(75557),\n\t\"time_boot\":           float64(2944405.500253),\n\t\"time_elapsed\":        float64(2944405.500253),\n\t\"size_db_disk\":        float64(98304),\n\t\"size_db_mem\":         float64(22784),\n\t\"size_xfrd_mem\":       float64(83956312),\n\t\"size_config_disk\":    float64(0),\n\t\"size_config_mem\":     float64(6088),\n\t\"num_type_TYPE0\":      float64(6),\n\t\"num_type_A\":          float64(46311),\n\t\"num_type_NS\":         float64(478),\n\t\"num_type_MD\":         float64(0),\n\t\"num_type_MF\":         float64(0),\n\t\"num_type_CNAME\":      float64(272),\n\t\"num_type_SOA\":        float64(596),\n\t\"num_type_MB\":         float64(0),\n\t\"num_type_MG\":         float64(0),\n\t\"num_type_MR\":         float64(0),\n\t\"num_type_NULL\":       float64(0),\n\t\"num_type_WKS\":        float64(0),\n\t\"num_type_PTR\":        float64(83),\n\t\"num_type_HINFO\":      float64(1),\n\t\"num_type_MINFO\":      float64(0),\n\t\"num_type_MX\":         float64(296),\n\t\"num_type_TXT\":        float64(794),\n\t\"num_type_RP\":         float64(0),\n\t\"num_type_AFSDB\":      float64(0),\n\t\"num_type_X25\":        float64(0),\n\t\"num_type_ISDN\":       float64(0),\n\t\"num_type_RT\":         float64(0),\n\t\"num_type_NSAP\":       float64(0),\n\t\"num_type_SIG\":        float64(0),\n\t\"num_type_KEY\":        float64(1),\n\t\"num_type_PX\":         float64(0),\n\t\"num_type_AAAA\":       float64(22736),\n\t\"num_type_LOC\":        float64(2),\n\t\"num_type_NXT\":        float64(0),\n\t\"num_type_SRV\":        float64(93),\n\t\"num_type_NAPTR\":      float64(5),\n\t\"num_type_KX\":         float64(0),\n\t\"num_type_CERT\":       float64(0),\n\t\"num_type_DNAME\":      float64(0),\n\t\"num_type_OPT\":        float64(0),\n\t\"num_type_APL\":        float64(0),\n\t\"num_type_DS\":         float64(0),\n\t\"num_type_SSHFP\":      float64(0),\n\t\"num_type_IPSECKEY\":   float64(0),\n\t\"num_type_RRSIG\":      float64(21),\n\t\"num_type_NSEC\":       float64(0),\n\t\"num_type_DNSKEY\":     float64(325),\n\t\"num_type_DHCID\":      float64(0),\n\t\"num_type_NSEC3\":      float64(0),\n\t\"num_type_NSEC3PARAM\": float64(0),\n\t\"num_type_TLSA\":       float64(35),\n\t\"num_type_SMIMEA\":     float64(0),\n\t\"num_type_CDS\":        float64(0),\n\t\"num_type_CDNSKEY\":    float64(0),\n\t\"num_type_OPENPGPKEY\": float64(0),\n\t\"num_type_CSYNC\":      float64(0),\n\t\"num_type_SPF\":        float64(16),\n\t\"num_type_NID\":        float64(0),\n\t\"num_type_L32\":        float64(0),\n\t\"num_type_L64\":        float64(0),\n\t\"num_type_LP\":         float64(0),\n\t\"num_type_EUI48\":      float64(0),\n\t\"num_type_EUI64\":      float64(0),\n\t\"num_type_TYPE252\":    float64(962),\n\t\"num_type_TYPE253\":    float64(2),\n\t\"num_type_TYPE255\":    float64(1840),\n\t\"num_opcode_QUERY\":    float64(75527),\n\t\"num_opcode_NOTIFY\":   float64(6),\n\t\"num_class_CLASS0\":    float64(6),\n\t\"num_class_IN\":        float64(75395),\n\t\"num_class_CH\":        float64(132),\n\t\"num_rcode_NOERROR\":   float64(65541),\n\t\"num_rcode_FORMERR\":   float64(8),\n\t\"num_rcode_SERVFAIL\":  float64(0),\n\t\"num_rcode_NXDOMAIN\":  float64(6642),\n\t\"num_rcode_NOTIMP\":    float64(18),\n\t\"num_rcode_REFUSED\":   float64(3341),\n\t\"num_rcode_YXDOMAIN\":  float64(0),\n\t\"num_rcode_NOTAUTH\":   float64(2),\n\t\"num_edns\":            float64(71398),\n\t\"num_ednserr\":         float64(0),\n\t\"num_udp\":             float64(34111),\n\t\"num_udp6\":            float64(40429),\n\t\"num_tcp\":             float64(1015),\n\t\"num_tcp6\":            float64(2),\n\t\"num_tls\":             float64(0),\n\t\"num_tls6\":            float64(0),\n\t\"num_answer_wo_aa\":    float64(13),\n\t\"num_rxerr\":           float64(0),\n\t\"num_txerr\":           float64(0),\n\t\"num_raxfr\":           float64(954),\n\t\"num_truncated\":       float64(1),\n\t\"num_dropped\":         float64(5),\n\t\"zone_master\":         float64(2),\n\t\"zone_slave\":          float64(1),\n}\n\nvar fullOutput = `server0.queries=75576\nnum.queries=75557\ntime.boot=2944405.500253\ntime.elapsed=2944405.500253\nsize.db.disk=98304\nsize.db.mem=22784\nsize.xfrd.mem=83956312\nsize.config.disk=0\nsize.config.mem=6088\nnum.type.TYPE0=6\nnum.type.A=46311\nnum.type.NS=478\nnum.type.MD=0\nnum.type.MF=0\nnum.type.CNAME=272\nnum.type.SOA=596\nnum.type.MB=0\nnum.type.MG=0\nnum.type.MR=0\nnum.type.NULL=0\nnum.type.WKS=0\nnum.type.PTR=83\nnum.type.HINFO=1\nnum.type.MINFO=0\nnum.type.MX=296\nnum.type.TXT=794\nnum.type.RP=0\nnum.type.AFSDB=0\nnum.type.X25=0\nnum.type.ISDN=0\nnum.type.RT=0\nnum.type.NSAP=0\nnum.type.SIG=0\nnum.type.KEY=1\nnum.type.PX=0\nnum.type.AAAA=22736\nnum.type.LOC=2\nnum.type.NXT=0\nnum.type.SRV=93\nnum.type.NAPTR=5\nnum.type.KX=0\nnum.type.CERT=0\nnum.type.DNAME=0\nnum.type.OPT=0\nnum.type.APL=0\nnum.type.DS=0\nnum.type.SSHFP=0\nnum.type.IPSECKEY=0\nnum.type.RRSIG=21\nnum.type.NSEC=0\nnum.type.DNSKEY=325\nnum.type.DHCID=0\nnum.type.NSEC3=0\nnum.type.NSEC3PARAM=0\nnum.type.TLSA=35\nnum.type.SMIMEA=0\nnum.type.CDS=0\nnum.type.CDNSKEY=0\nnum.type.OPENPGPKEY=0\nnum.type.CSYNC=0\nnum.type.SPF=16\nnum.type.NID=0\nnum.type.L32=0\nnum.type.L64=0\nnum.type.LP=0\nnum.type.EUI48=0\nnum.type.EUI64=0\nnum.type.TYPE252=962\nnum.type.TYPE253=2\nnum.type.TYPE255=1840\nnum.opcode.QUERY=75527\nnum.opcode.NOTIFY=6\nnum.class.CLASS0=6\nnum.class.IN=75395\nnum.class.CH=132\nnum.rcode.NOERROR=65541\nnum.rcode.FORMERR=8\nnum.rcode.SERVFAIL=0\nnum.rcode.NXDOMAIN=6642\nnum.rcode.NOTIMP=18\nnum.rcode.REFUSED=3341\nnum.rcode.YXDOMAIN=0\nnum.rcode.NOTAUTH=2\nnum.edns=71398\nnum.ednserr=0\nnum.udp=34111\nnum.udp6=40429\nnum.tcp=1015\nnum.tcp6=2\nnum.tls=0\nnum.tls6=0\nnum.answer_wo_aa=13\nnum.rxerr=0\nnum.txerr=0\nnum.raxfr=954\nnum.truncated=1\nnum.dropped=5\nzone.master=2\nzone.slave=1`\n"
  },
  {
    "path": "plugins/inputs/nsd/sample.conf",
    "content": "# A plugin to collect stats from the NSD DNS resolver\n[[inputs.nsd]]\n  ## Address of server to connect to, optionally ':port'. Defaults to the\n  ## address in the nsd config file.\n  server = \"127.0.0.1:8953\"\n\n  ## If running as a restricted user you can prepend sudo for additional access:\n  # use_sudo = false\n\n  ## The default location of the nsd-control binary can be overridden with:\n  # binary = \"/usr/sbin/nsd-control\"\n\n  ## The default location of the nsd config file can be overridden with:\n  # config_file = \"/etc/nsd/nsd.conf\"\n\n  ## The default timeout of 1s can be overridden with:\n  # timeout = \"1s\"\n"
  },
  {
    "path": "plugins/inputs/nsdp/README.md",
    "content": "# Netgear Switch Discovery Protocol Input Plugin\n\nThis plugin gathers metrics from devices via the\n[Netgear Switch Discovery Protocol][nsdp] for all available switches and ports.\n\n⭐ Telegraf v1.34.0\n🏷️ network\n💻 all\n\n[nsdp]: https://en.wikipedia.org/wiki/Netgear_Switch_Discovery_Protocol\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather Netgear Switch Discovery Protocol status\n[[inputs.nsdp]]\n  ## The target address to use for status gathering. Either Broadcast (default)\n  ## or the address of a single well-known device.\n  # address = \"255.255.255.255:63322\"\n\n  ## The maximum number of device responses to wait for. 0 means no limit.\n  ## NSDP works asynchronously. Without a limit (0) the plugin always waits\n  ## the amount given in timeout for possible responses. By setting this\n  ## option to the known number of devices, the plugin completes\n  ## processing as soon as the last device has answered.\n  # device_limit = 0\n\n  ## The maximum duration to wait for device responses.\n  # timeout = \"2s\"\n```\n\n## Metrics\n\n- `nsdp_device_port`\n  - tags\n    - `device` - The device identifier (MAC/HW address)\n    - `device_ip` - The device's IP address\n    - `device_name` - The device's name\n    - `device_model` - The device's model\n    - `device_port` - The port id the fields are referring to\n  - fields\n    - `bytes_sent` (uint) - Number of bytes sent via this port\n    - `bytes_recv` (uint) - Number of bytes received via this port\n    - `packets_total` (uint) - Total number of packets processed on this port\n    - `broadcasts_total` (uint) - Total number of broadcasts processed on this port\n    - `multicasts_total` (uint) - Total number of multicasts processed on this port\n    - `errors_total` (uint) - Total number of errors encountered on this port\n\n## Example Output\n\n```text\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=1 broadcasts_total=0u,bytes_recv=3879427866u,bytes_sent=506548796u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014578000\n```\n"
  },
  {
    "path": "plugins/inputs/nsdp/nsdp.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nsdp\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/tdrn-org/go-nsdp\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NSDP struct {\n\tAddress     string          `toml:\"address\"`\n\tDeviceLimit uint            `toml:\"device_limit\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\n\tconn *nsdp.Conn\n}\n\nfunc (*NSDP) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NSDP) Init() error {\n\tif n.Address == \"\" {\n\t\tn.Address = nsdp.IPv4BroadcastTarget\n\t}\n\tif n.Timeout <= 0 {\n\t\treturn errors.New(\"timeout must be greater than zero\")\n\t}\n\treturn nil\n}\n\nfunc (n *NSDP) Start(telegraf.Accumulator) error {\n\tconn, err := nsdp.NewConn(n.Address, n.Log.Level().Includes(telegraf.Trace))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create connection to address %s: %w\", n.Address, err)\n\t}\n\tconn.ReceiveDeviceLimit = n.DeviceLimit\n\tconn.ReceiveTimeout = time.Duration(n.Timeout)\n\tn.conn = conn\n\treturn nil\n}\n\nfunc (n *NSDP) Stop() {\n\tif n.conn == nil {\n\t\treturn\n\t}\n\tn.conn.Close()\n\tn.conn = nil\n}\n\nfunc (n *NSDP) Gather(acc telegraf.Accumulator) error {\n\tif n.conn == nil {\n\t\tif err := n.Start(nil); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Send request to query devices including infos (model, name, IP) and status (port statistics)\n\trequest := nsdp.NewMessage(nsdp.ReadRequest)\n\trequest.AppendTLV(nsdp.EmptyDeviceModel())\n\trequest.AppendTLV(nsdp.EmptyDeviceName())\n\trequest.AppendTLV(nsdp.EmptyDeviceIP())\n\trequest.AppendTLV(nsdp.EmptyPortStatistic())\n\tresponses, err := n.conn.SendReceiveMessage(request)\n\tif err != nil {\n\t\t// Close malfunctioning connection and re-connect on next Gather call\n\t\tn.Stop()\n\t\treturn fmt.Errorf(\"failed to query address %s: %w\", n.Address, err)\n\t}\n\n\t// Create metrics for each responding device\n\tfor device, response := range responses {\n\t\tn.Log.Tracef(\"Processing device: %s\", device)\n\t\tgatherDevice(acc, device, response)\n\t}\n\treturn nil\n}\n\nfunc gatherDevice(acc telegraf.Accumulator, device string, response *nsdp.Message) {\n\tvar deviceModel string\n\tvar deviceName string\n\tvar deviceIP net.IP\n\tportStats := make(map[uint8]*nsdp.PortStatistic, 0)\n\tfor _, tlv := range response.Body {\n\t\tswitch tlv.Type() {\n\t\tcase nsdp.TypeDeviceModel:\n\t\t\tdeviceModel = tlv.(*nsdp.DeviceModel).Model\n\t\tcase nsdp.TypeDeviceName:\n\t\t\tdeviceName = tlv.(*nsdp.DeviceName).Name\n\t\tcase nsdp.TypeDeviceIP:\n\t\t\tdeviceIP = tlv.(*nsdp.DeviceIP).IP\n\t\tcase nsdp.TypePortStatistic:\n\t\t\tportStat := tlv.(*nsdp.PortStatistic)\n\t\t\tportStats[portStat.Port] = portStat\n\t\t}\n\t}\n\tfor port, stat := range portStats {\n\t\ttags := map[string]string{\n\t\t\t\"device\":       device,\n\t\t\t\"device_ip\":    deviceIP.String(),\n\t\t\t\"device_name\":  deviceName,\n\t\t\t\"device_model\": deviceModel,\n\t\t\t\"device_port\":  strconv.FormatUint(uint64(port), 10),\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"bytes_sent\":       stat.Sent,\n\t\t\t\"bytes_recv\":       stat.Received,\n\t\t\t\"packets_total\":    stat.Packets,\n\t\t\t\"broadcasts_total\": stat.Broadcasts,\n\t\t\t\"multicasts_total\": stat.Multicasts,\n\t\t\t\"errors_total\":     stat.Errors,\n\t\t}\n\t\tacc.AddCounter(\"nsdp_device_port\", fields, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"nsdp\", func() telegraf.Input {\n\t\treturn &NSDP{Timeout: config.Duration(2 * time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nsdp/nsdp_test.go",
    "content": "package nsdp\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tdrn-org/go-nsdp\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestLoadConfig(t *testing.T) {\n\t// Verify plugin can be loaded from config\n\tconf := config.NewConfig()\n\trequire.NoError(t, conf.LoadConfig(\"testdata/conf/nsdp.conf\"))\n\trequire.Len(t, conf.Inputs, 1)\n\tplugin, ok := conf.Inputs[0].Input.(*NSDP)\n\trequire.True(t, ok)\n\n\t// Verify successful Init\n\trequire.NoError(t, plugin.Init())\n\n\t// Verify everything is setup according to config file\n\trequire.Equal(t, \"127.0.0.1:63322\", plugin.Address)\n\trequire.Equal(t, uint(1), plugin.DeviceLimit)\n\trequire.Equal(t, config.Duration(5*time.Second), plugin.Timeout)\n}\n\nfunc TestInvalidTimeoutConfig(t *testing.T) {\n\tplugin := &NSDP{\n\t\tTimeout: config.Duration(0 * time.Second),\n\t}\n\n\t// Verify failing Init\n\trequire.EqualError(t, plugin.Init(), \"timeout must be greater than zero\")\n}\n\nfunc TestGather(t *testing.T) {\n\t// Setup and start test responder\n\tresponder, err := nsdp.NewTestResponder(\"localhost:0\")\n\trequire.NoError(t, err)\n\tdefer responder.Stop() //nolint:errcheck // ignore error\n\tresponder.AddResponses(\n\t\t\"0102000000000000bcd07432b8dc123456789abc000037b94e53445000000000\"+\n\t\t\t\"0001000847533130384576330003000773776974636832000600040a01000410\"+\n\t\t\t\"0000310100000000e73b5f1a000000001e31523c000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000100000310200000000152d5e\"+\n\t\t\t\"ae0000000052ea11ea0000000000000000000000000000000000000000000000\"+\n\t\t\t\"000000000000000000100000310300000000068561aa00000000bcc8cb350000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000001000\"+\n\t\t\t\"0031040000000002d5fe00000000002b37dad900000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000010000031050000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000100000310600000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000100000\"+\n\t\t\t\"3107000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000001000003108000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"00000000000000ffff0000\",\n\t\t\"0102000000000000bcd07432b8dccba987654321000037b94e53445000000000\"+\n\t\t\t\"0001000847533130384576330003000773776974636831000600040a01000310\"+\n\t\t\t\"00003101000000059a9d833200000000303e8eb5000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000100000310200000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000001000003103000000000d9a35e4000000026523c6660000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000001000\"+\n\t\t\t\"003104000000000041c7530000000002cd94ba00000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000010000031050000000021b9ca41\"+\n\t\t\t\"000000031a9bff61000000000000000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000100000310600000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000100000\"+\n\t\t\t\"3107000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000001000003108000000000000000000\"+\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\"+\n\t\t\t\"00000000000000ffff0000\",\n\t)\n\trequire.NoError(t, responder.Start())\n\n\t// Setup the plugin to target the test responder\n\tplugin := &NSDP{\n\t\tAddress:     responder.Target(),\n\t\tDeviceLimit: 2,\n\t\tTimeout:     config.Duration(2 * time.Second),\n\t\tLog:         testutil.Logger{Name: \"nsdp\"},\n\t}\n\n\t// Verify successful Init\n\trequire.NoError(t, plugin.Init())\n\n\t// Verify successfull Gather\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\t// Verify collected metrics are as expected\n\texpectedMetrics := loadExpectedMetrics(t, \"testdata/metrics/nsdp_device_port.txt\", telegraf.Counter)\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc loadExpectedMetrics(t *testing.T, file string, vt telegraf.ValueType) []telegraf.Metric {\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\texpectedMetrics, err := testutil.ParseMetricsFromFile(file, parser)\n\trequire.NoError(t, err)\n\tfor index := range expectedMetrics {\n\t\texpectedMetrics[index].SetType(vt)\n\t}\n\treturn expectedMetrics\n}\n"
  },
  {
    "path": "plugins/inputs/nsdp/sample.conf",
    "content": "# Gather Netgear Switch Discovery Protocol status\n[[inputs.nsdp]]\n  ## The target address to use for status gathering. Either Broadcast (default)\n  ## or the address of a single well-known device.\n  # address = \"255.255.255.255:63322\"\n\n  ## The maximum number of device responses to wait for. 0 means no limit.\n  ## NSDP works asynchronously. Without a limit (0) the plugin always waits\n  ## the amount given in timeout for possible responses. By setting this\n  ## option to the known number of devices, the plugin completes\n  ## processing as soon as the last device has answered.\n  # device_limit = 0\n\n  ## The maximum duration to wait for device responses.\n  # timeout = \"2s\"\n"
  },
  {
    "path": "plugins/inputs/nsdp/testdata/conf/nsdp.conf",
    "content": "# Gather Netgear Switch Discovery Protocol status\n[[inputs.nsdp]]\n  ## The target address to use for status gathering. Either Broadcast (default)\n  ## or the address of a single well-known device.\n  address = \"127.0.0.1:63322\"\n\n  ## The maximum number of device responses to wait for. 0 means no limit.\n  ## NSDP works asynchronously. Without a limit (0) the plugin always waits\n  ## the amount given in timeout for possible responses. By setting this\n  ## option to the known number of devices, the plugin completes\n  ## processing as soon as the last device has answered.\n  device_limit = 1\n\n  ## The maximum duration to wait for device responses.\n  timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/nsdp/testdata/metrics/nsdp_device_port.txt",
    "content": "nsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=1 broadcasts_total=0u,bytes_recv=3879427866u,bytes_sent=506548796u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014578000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=2 broadcasts_total=0u,bytes_recv=355294894u,bytes_sent=1391071722u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014606000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=3 broadcasts_total=0u,bytes_recv=109404586u,bytes_sent=3167275829u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014615000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=4 broadcasts_total=0u,bytes_recv=47578624u,bytes_sent=725080793u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=5 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=6 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=7 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000\nnsdp_device_port,device=12:34:56:78:9a:bc,device_ip=10.1.0.4,device_model=GS108Ev3,device_name=switch2,device_port=8 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014624000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=1 broadcasts_total=0u,bytes_recv=24068850482u,bytes_sent=809406133u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014647000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=2 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=3 broadcasts_total=0u,bytes_recv=228210148u,bytes_sent=10286777958u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014657000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=4 broadcasts_total=0u,bytes_recv=4310867u,bytes_sent=47027386u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014668000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=5 broadcasts_total=0u,bytes_recv=565824065u,bytes_sent=13331332961u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=6 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=7 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000\nnsdp_device_port,device=cb:a9:87:65:43:21,device_ip=10.1.0.3,device_model=GS108Ev3,device_name=switch1,device_port=8 broadcasts_total=0u,bytes_recv=0u,bytes_sent=0u,errors_total=0u,multicasts_total=0u,packets_total=0u 1737152505014676000\n"
  },
  {
    "path": "plugins/inputs/nsq/README.md",
    "content": "# NSQ Input Plugin\n\nThis plugin gathers metrics from [NSQ][nsq] realtime distributed messaging\nplatform instances using the [NSQD API][api].\n\n⭐ Telegraf v1.16.0\n🏷️ server\n💻 all\n\n[nsq]: https://nsq.io/\n[api]: https://nsq.io/components/nsqd.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read NSQ topic and channel statistics.\n[[inputs.nsq]]\n  ## An array of NSQD HTTP API endpoints\n  endpoints  = [\"http://localhost:4151\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- `nsq_server`:\n  - tags:\n    - `server_host`\n    - `server_version`\n  - fields:\n    - `server_count`\n    - `topic_count`\n- `nsq_topic`:\n  - tags:\n    - `server_host`\n    - `server_version`\n    - `topic`\n  - fields:\n    - `backend_depth`\n    - `channel_count`\n    - `depth`\n    - `message_count`\n- `nsq_channel`:\n  - tags:\n    - `server_host`\n    - `server_version`\n    - `topic`\n    - `channel`\n  - fields:\n    - `backend_depth`\n    - `client_count`\n    - `depth`\n    - `deferred_count`\n    - `inflight_count`\n    - `message_count`\n    - `requeue_count`\n    - `timeout_count`\n- `nsq_client`:\n  - tags:\n    - `channel`\n    - `client_address`\n    - `client_hostname`\n    - `client_id`\n    - `client_name`\n    - `client_user_agent`\n    - `client_deflate`\n    - `client_snappy`\n    - `client_tls`\n    - `client_version`\n    - `server_host`\n    - `server_version`\n    - `topic`\n  - fields:\n    - `finish_count`\n    - `inflight_count`\n    - `message_count`\n    - `ready_count`\n    - `requeue_count`\n\n## Example Output\n\n```text\nnsq_server,server_host=127.0.0.1:35871,server_version=0.3.6 server_count=1i,topic_count=2i 1742836824386224245\nnsq_topic,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t1 backend_depth=13i,channel_count=1i,depth=12i,message_count=14i 1742836824386235365\nnsq_channel,channel=c1,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t1 backend_depth=1i,client_count=1i,deferred_count=3i,depth=0i,inflight_count=2i,message_count=4i,requeue_count=5i,timeout_count=6i 1742836824386241985\nnsq_client,channel=c1,client_address=172.17.0.11:35560,client_deflate=false,client_hostname=373a715cd990,client_id=373a715cd990,client_name=373a715cd990,client_snappy=false,client_tls=false,client_user_agent=nsq_to_nsq/0.3.6\\ go-nsq/1.0.5,client_version=V2,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t1 finish_count=9i,inflight_count=7i,message_count=8i,ready_count=200i,requeue_count=10i 1742836824386252905\nnsq_topic,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t2 backend_depth=29i,channel_count=1i,depth=28i,message_count=30i 1742836824386263806\nnsq_channel,channel=c2,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t2 backend_depth=16i,client_count=1i,deferred_count=18i,depth=15i,inflight_count=17i,message_count=19i,requeue_count=20i,timeout_count=21i 1742836824386270026\nnsq_client,channel=c2,client_address=172.17.0.8:48145,client_deflate=true,client_hostname=377569bd462b,client_id=377569bd462b,client_name=377569bd462b,client_snappy=true,client_tls=true,client_user_agent=go-nsq/1.0.5,client_version=V2,server_host=127.0.0.1:35871,server_version=0.3.6,topic=t2 finish_count=25i,inflight_count=23i,message_count=24i,ready_count=22i,requeue_count=26i 1742836824386277926\n```\n"
  },
  {
    "path": "plugins/inputs/nsq/nsq.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n// The MIT License (MIT)\n//\n// Copyright (c) 2015 Jeff Nickoloff (jeff@allingeek.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\npackage nsq\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\trequestPattern = `%s/stats?format=json`\n)\n\ntype NSQ struct {\n\tEndpoints []string `toml:\"endpoints\"`\n\n\ttls.ClientConfig\n\thttpClient *http.Client\n}\n\nfunc (*NSQ) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NSQ) Gather(acc telegraf.Accumulator) error {\n\tvar err error\n\n\tif n.httpClient == nil {\n\t\tn.httpClient, err = n.getHTTPClient()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, e := range n.Endpoints {\n\t\twg.Add(1)\n\t\tgo func(e string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(n.gatherEndpoint(e, acc))\n\t\t}(e)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *NSQ) getHTTPClient() (*http.Client, error) {\n\ttlsConfig, err := n.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttr := &http.Transport{\n\t\tTLSClientConfig: tlsConfig,\n\t}\n\thttpClient := &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   4 * time.Second,\n\t}\n\treturn httpClient, nil\n}\n\nfunc (n *NSQ) gatherEndpoint(e string, acc telegraf.Accumulator) error {\n\tu, err := buildURL(e)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr, err := n.httpClient.Get(u.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error while polling %s: %w\", u.String(), err)\n\t}\n\tdefer r.Body.Close()\n\n\tif r.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", u.String(), r.Status)\n\t}\n\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(`error reading body: %w`, err)\n\t}\n\n\tdata := &nsqStatsData{}\n\terr = json.Unmarshal(body, data)\n\tif err != nil {\n\t\treturn fmt.Errorf(`error parsing response: %w`, err)\n\t}\n\t// Data was not parsed correctly attempt to use old format.\n\tif len(data.Version) < 1 {\n\t\twrapper := &nsqStats{}\n\t\terr = json.Unmarshal(body, wrapper)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(`error parsing response: %w`, err)\n\t\t}\n\t\tdata = &wrapper.Data\n\t}\n\n\ttags := map[string]string{\n\t\t`server_host`:    u.Host,\n\t\t`server_version`: data.Version,\n\t}\n\n\tfields := make(map[string]interface{})\n\tif data.Health == `OK` {\n\t\tfields[\"server_count\"] = int64(1)\n\t} else {\n\t\tfields[\"server_count\"] = int64(0)\n\t}\n\tfields[\"topic_count\"] = int64(len(data.Topics))\n\n\tacc.AddFields(\"nsq_server\", fields, tags)\n\tfor _, t := range data.Topics {\n\t\tgatherTopicStats(t, acc, u.Host, data.Version)\n\t}\n\n\treturn nil\n}\n\nfunc buildURL(e string) (*url.URL, error) {\n\tu := fmt.Sprintf(requestPattern, e)\n\taddr, err := url.Parse(u)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to parse address %q: %w\", u, err)\n\t}\n\treturn addr, nil\n}\n\nfunc gatherTopicStats(t topicStats, acc telegraf.Accumulator, host, version string) {\n\t// per topic overall (tag: name, paused, channel count)\n\ttags := map[string]string{\n\t\t\"server_host\":    host,\n\t\t\"server_version\": version,\n\t\t\"topic\":          t.Name,\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"depth\":         t.Depth,\n\t\t\"backend_depth\": t.BackendDepth,\n\t\t\"message_count\": t.MessageCount,\n\t\t\"channel_count\": int64(len(t.Channels)),\n\t}\n\tacc.AddFields(\"nsq_topic\", fields, tags)\n\n\tfor _, c := range t.Channels {\n\t\tgatherChannelStats(c, acc, host, version, t.Name)\n\t}\n}\n\nfunc gatherChannelStats(c channelStats, acc telegraf.Accumulator, host, version, topic string) {\n\ttags := map[string]string{\n\t\t\"server_host\":    host,\n\t\t\"server_version\": version,\n\t\t\"topic\":          topic,\n\t\t\"channel\":        c.Name,\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"depth\":          c.Depth,\n\t\t\"backend_depth\":  c.BackendDepth,\n\t\t\"inflight_count\": c.InFlightCount,\n\t\t\"deferred_count\": c.DeferredCount,\n\t\t\"message_count\":  c.MessageCount,\n\t\t\"requeue_count\":  c.RequeueCount,\n\t\t\"timeout_count\":  c.TimeoutCount,\n\t\t\"client_count\":   int64(len(c.Clients)),\n\t}\n\n\tacc.AddFields(\"nsq_channel\", fields, tags)\n\tfor _, cl := range c.Clients {\n\t\tgatherClientStats(cl, acc, host, version, topic, c.Name)\n\t}\n}\n\nfunc gatherClientStats(c clientStats, acc telegraf.Accumulator, host, version, topic, channel string) {\n\ttags := map[string]string{\n\t\t\"server_host\":       host,\n\t\t\"server_version\":    version,\n\t\t\"topic\":             topic,\n\t\t\"channel\":           channel,\n\t\t\"client_id\":         c.ID,\n\t\t\"client_hostname\":   c.Hostname,\n\t\t\"client_version\":    c.Version,\n\t\t\"client_address\":    c.RemoteAddress,\n\t\t\"client_user_agent\": c.UserAgent,\n\t\t\"client_tls\":        strconv.FormatBool(c.TLS),\n\t\t\"client_snappy\":     strconv.FormatBool(c.Snappy),\n\t\t\"client_deflate\":    strconv.FormatBool(c.Deflate),\n\t}\n\tif len(c.Name) > 0 {\n\t\ttags[\"client_name\"] = c.Name\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"ready_count\":    c.ReadyCount,\n\t\t\"inflight_count\": c.InFlightCount,\n\t\t\"message_count\":  c.MessageCount,\n\t\t\"finish_count\":   c.FinishCount,\n\t\t\"requeue_count\":  c.RequeueCount,\n\t}\n\tacc.AddFields(\"nsq_client\", fields, tags)\n}\n\ntype nsqStats struct {\n\tCode int64        `json:\"status_code\"`\n\tTxt  string       `json:\"status_txt\"`\n\tData nsqStatsData `json:\"data\"`\n}\n\ntype nsqStatsData struct {\n\tVersion   string       `json:\"version\"`\n\tHealth    string       `json:\"health\"`\n\tStartTime int64        `json:\"start_time\"`\n\tTopics    []topicStats `json:\"topics\"`\n}\n\n// e2e_processing_latency is not modeled\ntype topicStats struct {\n\tName         string         `json:\"topic_name\"`\n\tDepth        int64          `json:\"depth\"`\n\tBackendDepth int64          `json:\"backend_depth\"`\n\tMessageCount int64          `json:\"message_count\"`\n\tPaused       bool           `json:\"paused\"`\n\tChannels     []channelStats `json:\"channels\"`\n}\n\n// e2e_processing_latency is not modeled\ntype channelStats struct {\n\tName          string        `json:\"channel_name\"`\n\tDepth         int64         `json:\"depth\"`\n\tBackendDepth  int64         `json:\"backend_depth\"`\n\tInFlightCount int64         `json:\"in_flight_count\"`\n\tDeferredCount int64         `json:\"deferred_count\"`\n\tMessageCount  int64         `json:\"message_count\"`\n\tRequeueCount  int64         `json:\"requeue_count\"`\n\tTimeoutCount  int64         `json:\"timeout_count\"`\n\tPaused        bool          `json:\"paused\"`\n\tClients       []clientStats `json:\"clients\"`\n}\n\ntype clientStats struct {\n\tName                          string `json:\"name\"` // DEPRECATED 1.x+, still here as the structs are currently being shared for parsing v3.x and 1.x\n\tID                            string `json:\"client_id\"`\n\tHostname                      string `json:\"hostname\"`\n\tVersion                       string `json:\"version\"`\n\tRemoteAddress                 string `json:\"remote_address\"`\n\tState                         int64  `json:\"state\"`\n\tReadyCount                    int64  `json:\"ready_count\"`\n\tInFlightCount                 int64  `json:\"in_flight_count\"`\n\tMessageCount                  int64  `json:\"message_count\"`\n\tFinishCount                   int64  `json:\"finish_count\"`\n\tRequeueCount                  int64  `json:\"requeue_count\"`\n\tConnectTime                   int64  `json:\"connect_ts\"`\n\tSampleRate                    int64  `json:\"sample_rate\"`\n\tDeflate                       bool   `json:\"deflate\"`\n\tSnappy                        bool   `json:\"snappy\"`\n\tUserAgent                     string `json:\"user_agent\"`\n\tTLS                           bool   `json:\"tls\"`\n\tTLSCipherSuite                string `json:\"tls_cipher_suite\"`\n\tTLSVersion                    string `json:\"tls_version\"`\n\tTLSNegotiatedProtocol         string `json:\"tls_negotiated_protocol\"`\n\tTLSNegotiatedProtocolIsMutual bool   `json:\"tls_negotiated_protocol_is_mutual\"`\n}\n\nfunc newNSQ() *NSQ {\n\treturn &NSQ{}\n}\n\nfunc init() {\n\tinputs.Add(\"nsq\", func() telegraf.Input {\n\t\treturn newNSQ()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nsq/nsq_test.go",
    "content": "package nsq\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestNSQStatsV1(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, responseV1); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\tn := newNSQ()\n\tn.Endpoints = []string{ts.URL}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(n.Gather)\n\trequire.NoError(t, err)\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\thost := u.Host\n\n\t// actually validate the tests\n\ttests := []struct {\n\t\tm string\n\t\tf map[string]interface{}\n\t\tg map[string]string\n\t}{\n\t\t{\n\t\t\t\"nsq_server\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"server_count\": int64(1),\n\t\t\t\t\"topic_count\":  int64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"1.0.0-compat\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_topic\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":         int64(12),\n\t\t\t\t\"backend_depth\": int64(13),\n\t\t\t\t\"message_count\": int64(14),\n\t\t\t\t\"channel_count\": int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\":          \"t1\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_channel\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":          int64(0),\n\t\t\t\t\"backend_depth\":  int64(1),\n\t\t\t\t\"inflight_count\": int64(2),\n\t\t\t\t\"deferred_count\": int64(3),\n\t\t\t\t\"message_count\":  int64(4),\n\t\t\t\t\"requeue_count\":  int64(5),\n\t\t\t\t\"timeout_count\":  int64(6),\n\t\t\t\t\"client_count\":   int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\":          \"t1\",\n\t\t\t\t\"channel\":        \"c1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_client\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ready_count\":    int64(200),\n\t\t\t\t\"inflight_count\": int64(7),\n\t\t\t\t\"message_count\":  int64(8),\n\t\t\t\t\"finish_count\":   int64(9),\n\t\t\t\t\"requeue_count\":  int64(10),\n\t\t\t},\n\t\t\tmap[string]string{\"server_host\": host, \"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\": \"t1\", \"channel\": \"c1\",\n\t\t\t\t\"client_id\": \"373a715cd990\", \"client_hostname\": \"373a715cd990\",\n\t\t\t\t\"client_version\": \"V2\", \"client_address\": \"172.17.0.11:35560\",\n\t\t\t\t\"client_tls\": \"false\", \"client_snappy\": \"false\",\n\t\t\t\t\"client_deflate\":    \"false\",\n\t\t\t\t\"client_user_agent\": \"nsq_to_nsq/0.3.6 go-nsq/1.0.5\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_topic\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":         int64(28),\n\t\t\t\t\"backend_depth\": int64(29),\n\t\t\t\t\"message_count\": int64(30),\n\t\t\t\t\"channel_count\": int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\":          \"t2\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_channel\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":          int64(15),\n\t\t\t\t\"backend_depth\":  int64(16),\n\t\t\t\t\"inflight_count\": int64(17),\n\t\t\t\t\"deferred_count\": int64(18),\n\t\t\t\t\"message_count\":  int64(19),\n\t\t\t\t\"requeue_count\":  int64(20),\n\t\t\t\t\"timeout_count\":  int64(21),\n\t\t\t\t\"client_count\":   int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\":          \"t2\",\n\t\t\t\t\"channel\":        \"c2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_client\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ready_count\":    int64(22),\n\t\t\t\t\"inflight_count\": int64(23),\n\t\t\t\t\"message_count\":  int64(24),\n\t\t\t\t\"finish_count\":   int64(25),\n\t\t\t\t\"requeue_count\":  int64(26),\n\t\t\t},\n\t\t\tmap[string]string{\"server_host\": host, \"server_version\": \"1.0.0-compat\",\n\t\t\t\t\"topic\": \"t2\", \"channel\": \"c2\",\n\t\t\t\t\"client_id\": \"377569bd462b\", \"client_hostname\": \"377569bd462b\",\n\t\t\t\t\"client_version\": \"V2\", \"client_address\": \"172.17.0.8:48145\",\n\t\t\t\t\"client_user_agent\": \"go-nsq/1.0.5\", \"client_tls\": \"true\",\n\t\t\t\t\"client_snappy\": \"true\", \"client_deflate\": \"true\"},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tacc.AssertContainsTaggedFields(t, test.m, test.f, test.g)\n\t}\n}\n\n// v1 version of localhost/stats?format=json response body\nvar responseV1 = `\n{\n    \"version\": \"1.0.0-compat\",\n    \"health\": \"OK\",\n    \"start_time\": 1452021674,\n    \"topics\": [\n      {\n        \"topic_name\": \"t1\",\n        \"channels\": [\n          {\n            \"channel_name\": \"c1\",\n            \"depth\": 0,\n            \"backend_depth\": 1,\n            \"in_flight_count\": 2,\n            \"deferred_count\": 3,\n            \"message_count\": 4,\n            \"requeue_count\": 5,\n            \"timeout_count\": 6,\n            \"clients\": [\n              {\n                \"client_id\": \"373a715cd990\",\n                \"hostname\": \"373a715cd990\",\n                \"version\": \"V2\",\n                \"remote_address\": \"172.17.0.11:35560\",\n                \"state\": 3,\n                \"ready_count\": 200,\n                \"in_flight_count\": 7,\n                \"message_count\": 8,\n                \"finish_count\": 9,\n                \"requeue_count\": 10,\n                \"connect_ts\": 1452021675,\n                \"sample_rate\": 11,\n                \"deflate\": false,\n                \"snappy\": false,\n                \"user_agent\": \"nsq_to_nsq\\/0.3.6 go-nsq\\/1.0.5\",\n                \"tls\": false,\n                \"tls_cipher_suite\": \"\",\n                \"tls_version\": \"\",\n                \"tls_negotiated_protocol\": \"\",\n                \"tls_negotiated_protocol_is_mutual\": false\n              }\n            ],\n            \"paused\": false,\n            \"e2e_processing_latency\": {\n              \"count\": 0,\n              \"percentiles\": null\n            }\n          }\n        ],\n        \"depth\": 12,\n        \"backend_depth\": 13,\n        \"message_count\": 14,\n        \"paused\": false,\n        \"e2e_processing_latency\": {\n          \"count\": 0,\n          \"percentiles\": null\n        }\n      },\n      {\n        \"topic_name\": \"t2\",\n        \"channels\": [\n          {\n            \"channel_name\": \"c2\",\n            \"depth\": 15,\n            \"backend_depth\": 16,\n            \"in_flight_count\": 17,\n            \"deferred_count\": 18,\n            \"message_count\": 19,\n            \"requeue_count\": 20,\n            \"timeout_count\": 21,\n            \"clients\": [\n              {\n                \"client_id\": \"377569bd462b\",\n                \"hostname\": \"377569bd462b\",\n                \"version\": \"V2\",\n                \"remote_address\": \"172.17.0.8:48145\",\n                \"state\": 3,\n                \"ready_count\": 22,\n                \"in_flight_count\": 23,\n                \"message_count\": 24,\n                \"finish_count\": 25,\n                \"requeue_count\": 26,\n                \"connect_ts\": 1452021678,\n                \"sample_rate\": 27,\n                \"deflate\": true,\n                \"snappy\": true,\n                \"user_agent\": \"go-nsq\\/1.0.5\",\n                \"tls\": true,\n                \"tls_cipher_suite\": \"\",\n                \"tls_version\": \"\",\n                \"tls_negotiated_protocol\": \"\",\n                \"tls_negotiated_protocol_is_mutual\": false\n              }\n            ],\n            \"paused\": false,\n            \"e2e_processing_latency\": {\n              \"count\": 0,\n              \"percentiles\": null\n            }\n          }\n        ],\n        \"depth\": 28,\n        \"backend_depth\": 29,\n        \"message_count\": 30,\n        \"paused\": false,\n        \"e2e_processing_latency\": {\n          \"count\": 0,\n          \"percentiles\": null\n        }\n      }\n    ]\n  }\n\n`\n\n// TestNSQStatsPreV1 is for backwards compatibility with nsq versions < 1.0\nfunc TestNSQStatsPreV1(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, responsePreV1); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\tn := newNSQ()\n\tn.Endpoints = []string{ts.URL}\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(n.Gather)\n\trequire.NoError(t, err)\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\thost := u.Host\n\n\t// actually validate the tests\n\ttests := []struct {\n\t\tm string\n\t\tf map[string]interface{}\n\t\tg map[string]string\n\t}{\n\t\t{\n\t\t\t\"nsq_server\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"server_count\": int64(1),\n\t\t\t\t\"topic_count\":  int64(2),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"0.3.6\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_topic\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":         int64(12),\n\t\t\t\t\"backend_depth\": int64(13),\n\t\t\t\t\"message_count\": int64(14),\n\t\t\t\t\"channel_count\": int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\":          \"t1\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_channel\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":          int64(0),\n\t\t\t\t\"backend_depth\":  int64(1),\n\t\t\t\t\"inflight_count\": int64(2),\n\t\t\t\t\"deferred_count\": int64(3),\n\t\t\t\t\"message_count\":  int64(4),\n\t\t\t\t\"requeue_count\":  int64(5),\n\t\t\t\t\"timeout_count\":  int64(6),\n\t\t\t\t\"client_count\":   int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\":          \"t1\",\n\t\t\t\t\"channel\":        \"c1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_client\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ready_count\":    int64(200),\n\t\t\t\t\"inflight_count\": int64(7),\n\t\t\t\t\"message_count\":  int64(8),\n\t\t\t\t\"finish_count\":   int64(9),\n\t\t\t\t\"requeue_count\":  int64(10),\n\t\t\t},\n\t\t\tmap[string]string{\"server_host\": host, \"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\": \"t1\", \"channel\": \"c1\", \"client_name\": \"373a715cd990\",\n\t\t\t\t\"client_id\": \"373a715cd990\", \"client_hostname\": \"373a715cd990\",\n\t\t\t\t\"client_version\": \"V2\", \"client_address\": \"172.17.0.11:35560\",\n\t\t\t\t\"client_tls\": \"false\", \"client_snappy\": \"false\",\n\t\t\t\t\"client_deflate\":    \"false\",\n\t\t\t\t\"client_user_agent\": \"nsq_to_nsq/0.3.6 go-nsq/1.0.5\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_topic\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":         int64(28),\n\t\t\t\t\"backend_depth\": int64(29),\n\t\t\t\t\"message_count\": int64(30),\n\t\t\t\t\"channel_count\": int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\":          \"t2\"},\n\t\t},\n\t\t{\n\t\t\t\"nsq_channel\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"depth\":          int64(15),\n\t\t\t\t\"backend_depth\":  int64(16),\n\t\t\t\t\"inflight_count\": int64(17),\n\t\t\t\t\"deferred_count\": int64(18),\n\t\t\t\t\"message_count\":  int64(19),\n\t\t\t\t\"requeue_count\":  int64(20),\n\t\t\t\t\"timeout_count\":  int64(21),\n\t\t\t\t\"client_count\":   int64(1),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"server_host\":    host,\n\t\t\t\t\"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\":          \"t2\",\n\t\t\t\t\"channel\":        \"c2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"nsq_client\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"ready_count\":    int64(22),\n\t\t\t\t\"inflight_count\": int64(23),\n\t\t\t\t\"message_count\":  int64(24),\n\t\t\t\t\"finish_count\":   int64(25),\n\t\t\t\t\"requeue_count\":  int64(26),\n\t\t\t},\n\t\t\tmap[string]string{\"server_host\": host, \"server_version\": \"0.3.6\",\n\t\t\t\t\"topic\": \"t2\", \"channel\": \"c2\", \"client_name\": \"377569bd462b\",\n\t\t\t\t\"client_id\": \"377569bd462b\", \"client_hostname\": \"377569bd462b\",\n\t\t\t\t\"client_version\": \"V2\", \"client_address\": \"172.17.0.8:48145\",\n\t\t\t\t\"client_user_agent\": \"go-nsq/1.0.5\", \"client_tls\": \"true\",\n\t\t\t\t\"client_snappy\": \"true\", \"client_deflate\": \"true\"},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tacc.AssertContainsTaggedFields(t, test.m, test.f, test.g)\n\t}\n}\n\nvar responsePreV1 = `\n{\n  \"status_code\": 200,\n  \"status_txt\": \"OK\",\n  \"data\": {\n    \"version\": \"0.3.6\",\n    \"health\": \"OK\",\n    \"start_time\": 1452021674,\n    \"topics\": [\n      {\n        \"topic_name\": \"t1\",\n        \"channels\": [\n          {\n            \"channel_name\": \"c1\",\n            \"depth\": 0,\n            \"backend_depth\": 1,\n            \"in_flight_count\": 2,\n            \"deferred_count\": 3,\n            \"message_count\": 4,\n            \"requeue_count\": 5,\n            \"timeout_count\": 6,\n            \"clients\": [\n              {\n                \"name\": \"373a715cd990\",\n                \"client_id\": \"373a715cd990\",\n                \"hostname\": \"373a715cd990\",\n                \"version\": \"V2\",\n                \"remote_address\": \"172.17.0.11:35560\",\n                \"state\": 3,\n                \"ready_count\": 200,\n                \"in_flight_count\": 7,\n                \"message_count\": 8,\n                \"finish_count\": 9,\n                \"requeue_count\": 10,\n                \"connect_ts\": 1452021675,\n                \"sample_rate\": 11,\n                \"deflate\": false,\n                \"snappy\": false,\n                \"user_agent\": \"nsq_to_nsq\\/0.3.6 go-nsq\\/1.0.5\",\n                \"tls\": false,\n                \"tls_cipher_suite\": \"\",\n                \"tls_version\": \"\",\n                \"tls_negotiated_protocol\": \"\",\n                \"tls_negotiated_protocol_is_mutual\": false\n              }\n            ],\n            \"paused\": false,\n            \"e2e_processing_latency\": {\n              \"count\": 0,\n              \"percentiles\": null\n            }\n          }\n        ],\n        \"depth\": 12,\n        \"backend_depth\": 13,\n        \"message_count\": 14,\n        \"paused\": false,\n        \"e2e_processing_latency\": {\n          \"count\": 0,\n          \"percentiles\": null\n        }\n      },\n      {\n        \"topic_name\": \"t2\",\n        \"channels\": [\n          {\n            \"channel_name\": \"c2\",\n            \"depth\": 15,\n            \"backend_depth\": 16,\n            \"in_flight_count\": 17,\n            \"deferred_count\": 18,\n            \"message_count\": 19,\n            \"requeue_count\": 20,\n            \"timeout_count\": 21,\n            \"clients\": [\n              {\n                \"name\": \"377569bd462b\",\n                \"client_id\": \"377569bd462b\",\n                \"hostname\": \"377569bd462b\",\n                \"version\": \"V2\",\n                \"remote_address\": \"172.17.0.8:48145\",\n                \"state\": 3,\n                \"ready_count\": 22,\n                \"in_flight_count\": 23,\n                \"message_count\": 24,\n                \"finish_count\": 25,\n                \"requeue_count\": 26,\n                \"connect_ts\": 1452021678,\n                \"sample_rate\": 27,\n                \"deflate\": true,\n                \"snappy\": true,\n                \"user_agent\": \"go-nsq\\/1.0.5\",\n                \"tls\": true,\n                \"tls_cipher_suite\": \"\",\n                \"tls_version\": \"\",\n                \"tls_negotiated_protocol\": \"\",\n                \"tls_negotiated_protocol_is_mutual\": false\n              }\n            ],\n            \"paused\": false,\n            \"e2e_processing_latency\": {\n              \"count\": 0,\n              \"percentiles\": null\n            }\n          }\n        ],\n        \"depth\": 28,\n        \"backend_depth\": 29,\n        \"message_count\": 30,\n        \"paused\": false,\n        \"e2e_processing_latency\": {\n          \"count\": 0,\n          \"percentiles\": null\n        }\n      }\n    ]\n  }\n}\n`\n"
  },
  {
    "path": "plugins/inputs/nsq/sample.conf",
    "content": "# Read NSQ topic and channel statistics.\n[[inputs.nsq]]\n  ## An array of NSQD HTTP API endpoints\n  endpoints  = [\"http://localhost:4151\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/nsq_consumer/README.md",
    "content": "# NSQ Consumer Input Plugin\n\nThis service plugin consumes messages from [NSQ][nsq] realtime distributed\nmessaging platform brokers in one of the supported [data formats][data_formats].\n\n⭐ Telegraf v0.10.1\n🏷️ messaging\n💻 all\n\n[nsq]: https://nsq.io/\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from NSQD topic(s)\n[[inputs.nsq_consumer]]\n  ## An array representing the NSQD TCP HTTP Endpoints\n  nsqd = [\"localhost:4150\"]\n\n  ## An array representing the NSQLookupd HTTP Endpoints\n  nsqlookupd = [\"localhost:4161\"]\n  topic = \"telegraf\"\n  channel = \"consumer\"\n  max_in_flight = 100\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n```\n\n## Metrics\n\nThe plugin accepts arbitrary input and parses it according to the `data_format`\nsetting. There is no predefined metric format.\n\n## Example Output\n\nThere is no predefined metric format, so output depends on plugin input.\n"
  },
  {
    "path": "plugins/inputs/nsq_consumer/nsq_consumer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nsq_consumer\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"sync\"\n\n\t\"github.com/nsqio/go-nsq\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultMaxUndeliveredMessages = 1000\n)\n\ntype NSQConsumer struct {\n\tNsqd                   []string        `toml:\"nsqd\"`\n\tNsqlookupd             []string        `toml:\"nsqlookupd\"`\n\tTopic                  string          `toml:\"topic\"`\n\tChannel                string          `toml:\"channel\"`\n\tMaxInFlight            int             `toml:\"max_in_flight\"`\n\tMaxUndeliveredMessages int             `toml:\"max_undelivered_messages\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\n\tparser   telegraf.Parser\n\tconsumer *nsq.Consumer\n\n\tmu       sync.Mutex\n\tmessages map[telegraf.TrackingID]*nsq.Message\n\twg       sync.WaitGroup\n\tcancel   context.CancelFunc\n}\n\ntype (\n\tempty     struct{}\n\tsemaphore chan empty\n)\n\ntype logger struct {\n\tlog telegraf.Logger\n}\n\n// Output writes log messages from the NSQ library to the Telegraf logger.\nfunc (l *logger) Output(_ int, s string) error {\n\tl.log.Debug(s)\n\treturn nil\n}\n\nfunc (*NSQConsumer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NSQConsumer) Init() error {\n\t// Check if we have anything to connect to\n\tif len(n.Nsqlookupd) == 0 && len(n.Nsqd) == 0 {\n\t\treturn errors.New(\"either 'nsqd' or 'nsqlookupd' needs to be specified\")\n\t}\n\n\treturn nil\n}\n\n// SetParser takes the data_format from the config and finds the right parser for that format\nfunc (n *NSQConsumer) SetParser(parser telegraf.Parser) {\n\tn.parser = parser\n}\n\nfunc (n *NSQConsumer) Start(ac telegraf.Accumulator) error {\n\tacc := ac.WithTracking(n.MaxUndeliveredMessages)\n\tsem := make(semaphore, n.MaxUndeliveredMessages)\n\tn.messages = make(map[telegraf.TrackingID]*nsq.Message, n.MaxUndeliveredMessages)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tn.cancel = cancel\n\n\tif err := n.connect(); err != nil {\n\t\treturn err\n\t}\n\tn.consumer.SetLogger(&logger{log: n.Log}, nsq.LogLevelInfo)\n\tn.consumer.AddHandler(nsq.HandlerFunc(func(message *nsq.Message) error {\n\t\tmetrics, err := n.parser.Parse(message.Body)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\t// Remove the message from the queue\n\t\t\tmessage.Finish()\n\t\t\treturn nil\n\t\t}\n\t\tif len(metrics) == 0 {\n\t\t\tmessage.Finish()\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase sem <- empty{}:\n\t\t\tbreak\n\t\t}\n\n\t\tn.mu.Lock()\n\t\tid := acc.AddTrackingMetricGroup(metrics)\n\t\tn.messages[id] = message\n\t\tn.mu.Unlock()\n\t\tmessage.DisableAutoResponse()\n\t\treturn nil\n\t}))\n\n\tif len(n.Nsqlookupd) > 0 {\n\t\terr := n.consumer.ConnectToNSQLookupds(n.Nsqlookupd)\n\t\tif err != nil && !errors.Is(err, nsq.ErrAlreadyConnected) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif len(n.Nsqd) > 0 {\n\t\terr := n.consumer.ConnectToNSQDs(n.Nsqd)\n\t\tif err != nil && !errors.Is(err, nsq.ErrAlreadyConnected) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tn.wg.Add(1)\n\tgo func() {\n\t\tdefer n.wg.Done()\n\t\tn.onDelivery(ctx, acc, sem)\n\t}()\n\treturn nil\n}\n\nfunc (*NSQConsumer) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (n *NSQConsumer) Stop() {\n\tn.cancel()\n\tn.wg.Wait()\n\tn.consumer.Stop()\n\t<-n.consumer.StopChan\n}\n\nfunc (n *NSQConsumer) onDelivery(ctx context.Context, acc telegraf.TrackingAccumulator, sem semaphore) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase info := <-acc.Delivered():\n\t\t\tn.mu.Lock()\n\t\t\tmsg, ok := n.messages[info.ID()]\n\t\t\tif !ok {\n\t\t\t\tn.mu.Unlock()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t<-sem\n\t\t\tdelete(n.messages, info.ID())\n\t\t\tn.mu.Unlock()\n\n\t\t\tif info.Delivered() {\n\t\t\t\tmsg.Finish()\n\t\t\t} else {\n\t\t\t\tmsg.Requeue(-1)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (n *NSQConsumer) connect() error {\n\tif n.consumer == nil {\n\t\tconfig := nsq.NewConfig()\n\t\tconfig.MaxInFlight = n.MaxInFlight\n\t\tconsumer, err := nsq.NewConsumer(n.Topic, n.Channel, config)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn.consumer = consumer\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"nsq_consumer\", func() telegraf.Input {\n\t\treturn &NSQConsumer{\n\t\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nsq_consumer/nsq_consumer_test.go",
    "content": "package nsq_consumer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nsqio/go-nsq\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// This test is modeled after the kafka consumer integration test\nfunc TestReadsMetricsFromNSQ(t *testing.T) {\n\tmsgID := nsq.MessageID{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 's', 'd', 'f', 'g', 'h'}\n\tmsg := nsq.NewMessage(msgID, []byte(\"cpu_load_short,direction=in,host=server01,region=us-west value=23422.0 1422568543702900257\\n\"))\n\n\tframeMsg, err := frameMessage(msg)\n\trequire.NoError(t, err)\n\n\tscript := []instruction{\n\t\t// SUB\n\t\t{0, nsq.FrameTypeResponse, []byte(\"OK\")},\n\t\t// IDENTIFY\n\t\t{0, nsq.FrameTypeResponse, []byte(\"OK\")},\n\t\t{20 * time.Millisecond, nsq.FrameTypeMessage, frameMsg},\n\t\t// needed to exit test\n\t\t{100 * time.Millisecond, -1, []byte(\"exit\")},\n\t}\n\n\taddr, err := net.ResolveTCPAddr(\"tcp\", \"127.0.0.1:4155\")\n\trequire.NoError(t, err)\n\tnewMockNSQD(t, script, addr.String())\n\n\tconsumer := &NSQConsumer{\n\t\tLog:                    testutil.Logger{},\n\t\tTopic:                  \"telegraf\",\n\t\tChannel:                \"consume\",\n\t\tMaxInFlight:            1,\n\t\tMaxUndeliveredMessages: defaultMaxUndeliveredMessages,\n\t\tNsqd:                   []string{\"127.0.0.1:4155\"},\n\t}\n\trequire.NoError(t, consumer.Init())\n\n\tp := &influx.Parser{}\n\trequire.NoError(t, p.Init())\n\tconsumer.SetParser(p)\n\tvar acc testutil.Accumulator\n\trequire.Empty(t, acc.Metrics, \"There should not be any points\")\n\trequire.NoError(t, consumer.Start(&acc))\n\n\twaitForPoint(&acc, t)\n\n\trequire.Len(t, acc.Metrics, 1, \"No points found in accumulator, expected 1\")\n\n\tpoint := acc.Metrics[0]\n\trequire.Equal(t, \"cpu_load_short\", point.Measurement)\n\trequire.Equal(t, map[string]interface{}{\"value\": 23422.0}, point.Fields)\n\trequire.Equal(t, map[string]string{\n\t\t\"host\":      \"server01\",\n\t\t\"direction\": \"in\",\n\t\t\"region\":    \"us-west\",\n\t}, point.Tags)\n\trequire.Equal(t, time.Unix(0, 1422568543702900257).Unix(), point.Time.Unix())\n}\n\n// Waits for the metric that was sent to the kafka broker to arrive at the kafka\n// consumer\nfunc waitForPoint(acc *testutil.Accumulator, t *testing.T) {\n\t// Give the kafka container up to 2 seconds to get the point to the consumer\n\tticker := time.NewTicker(5 * time.Millisecond)\n\tdefer ticker.Stop()\n\tcounter := 0\n\n\t//nolint:staticcheck // for-select used on purpose\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tcounter++\n\t\t\tif counter > 1000 {\n\t\t\t\tt.Fatal(\"Waited for 5s, point never arrived to consumer\")\n\t\t\t} else if acc.NFields() == 1 {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc newMockNSQD(t *testing.T, script []instruction, addr string) *mockNSQD {\n\tn := &mockNSQD{\n\t\tscript:   script,\n\t\texitChan: make(chan int),\n\t}\n\n\ttcpListener, err := net.Listen(\"tcp\", addr)\n\trequire.NoError(t, err, \"listen (%s) failed\", n.tcpAddr.String())\n\n\tn.tcpListener = tcpListener\n\tn.tcpAddr = tcpListener.Addr().(*net.TCPAddr)\n\n\tgo n.listen()\n\n\treturn n\n}\n\n// The code below allows us to mock the interactions with nsqd. This is taken from:\n// https://github.com/nsqio/go-nsq/blob/master/mock_test.go\ntype instruction struct {\n\tdelay     time.Duration\n\tframeType int32\n\tbody      []byte\n}\n\ntype mockNSQD struct {\n\tscript      []instruction\n\tgot         [][]byte\n\ttcpAddr     *net.TCPAddr\n\ttcpListener net.Listener\n\texitChan    chan int\n}\n\nfunc (n *mockNSQD) listen() {\n\tfor {\n\t\tconn, err := n.tcpListener.Accept()\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tgo n.handle(conn)\n\t}\n\tclose(n.exitChan)\n}\n\nfunc (n *mockNSQD) handle(conn net.Conn) {\n\tvar idx int\n\tbuf := make([]byte, 4)\n\t_, err := io.ReadFull(conn, buf)\n\tif err != nil {\n\t\t//nolint:revive // log.Fatalf called intentionally\n\t\tlog.Fatalf(\"ERROR: failed to read protocol version - %s\", err)\n\t}\n\n\treadChan := make(chan []byte)\n\treadDoneChan := make(chan int)\n\tscriptTime := time.After(n.script[0].delay)\n\trdr := bufio.NewReader(conn)\n\n\tgo func() {\n\t\tfor {\n\t\t\tline, err := rdr.ReadBytes('\\n')\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// trim the '\\n'\n\t\t\tline = line[:len(line)-1]\n\t\t\treadChan <- line\n\t\t\t<-readDoneChan\n\t\t}\n\t}()\n\n\tvar rdyCount int\n\tfor idx < len(n.script) {\n\t\tselect {\n\t\tcase line := <-readChan:\n\t\t\tn.got = append(n.got, line)\n\t\t\tparams := bytes.Split(line, []byte(\" \"))\n\t\t\tswitch {\n\t\t\tcase bytes.Equal(params[0], []byte(\"IDENTIFY\")):\n\t\t\t\tl := make([]byte, 4)\n\t\t\t\t_, err := io.ReadFull(rdr, l)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Print(err.Error())\n\t\t\t\t\tgoto exit\n\t\t\t\t}\n\t\t\t\tsize := int32(binary.BigEndian.Uint32(l))\n\t\t\t\tb := make([]byte, size)\n\t\t\t\t_, err = io.ReadFull(rdr, b)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Print(err.Error())\n\t\t\t\t\tgoto exit\n\t\t\t\t}\n\t\t\tcase bytes.Equal(params[0], []byte(\"RDY\")):\n\t\t\t\trdy, err := strconv.Atoi(string(params[1]))\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Print(err.Error())\n\t\t\t\t\tgoto exit\n\t\t\t\t}\n\t\t\t\trdyCount = rdy\n\t\t\tcase bytes.Equal(params[0], []byte(\"FIN\")):\n\t\t\tcase bytes.Equal(params[0], []byte(\"REQ\")):\n\t\t\t}\n\t\t\treadDoneChan <- 1\n\t\tcase <-scriptTime:\n\t\t\tinst := n.script[idx]\n\t\t\tif bytes.Equal(inst.body, []byte(\"exit\")) {\n\t\t\t\tgoto exit\n\t\t\t}\n\t\t\tif inst.frameType == nsq.FrameTypeMessage {\n\t\t\t\tif rdyCount == 0 {\n\t\t\t\t\tscriptTime = time.After(n.script[idx+1].delay)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trdyCount--\n\t\t\t}\n\t\t\tbuf := framedResponse(inst.frameType, inst.body)\n\t\t\t_, err = conn.Write(buf)\n\t\t\tif err != nil {\n\t\t\t\tlog.Print(err.Error())\n\t\t\t\tgoto exit\n\t\t\t}\n\t\t\tscriptTime = time.After(n.script[idx+1].delay)\n\t\t\tidx++\n\t\t}\n\t}\n\nexit:\n\tn.tcpListener.Close()\n\tconn.Close()\n}\n\nfunc framedResponse(frameType int32, data []byte) []byte {\n\tvar w bytes.Buffer\n\n\tbeBuf := make([]byte, 4)\n\tsize := uint32(len(data)) + 4\n\n\tbinary.BigEndian.PutUint32(beBuf, size)\n\tw.Write(beBuf)\n\n\tbinary.BigEndian.PutUint32(beBuf, uint32(frameType))\n\tw.Write(beBuf)\n\n\tw.Write(data)\n\treturn w.Bytes()\n}\n\nfunc frameMessage(m *nsq.Message) ([]byte, error) {\n\tvar b bytes.Buffer\n\t_, err := m.WriteTo(&b)\n\treturn b.Bytes(), err\n}\n"
  },
  {
    "path": "plugins/inputs/nsq_consumer/sample.conf",
    "content": "# Read metrics from NSQD topic(s)\n[[inputs.nsq_consumer]]\n  ## An array representing the NSQD TCP HTTP Endpoints\n  nsqd = [\"localhost:4150\"]\n\n  ## An array representing the NSQLookupd HTTP Endpoints\n  nsqlookupd = [\"localhost:4161\"]\n  topic = \"telegraf\"\n  channel = \"consumer\"\n  max_in_flight = 100\n\n  ## Max undelivered messages\n  ## This plugin uses tracking metrics, which ensure messages are read to\n  ## outputs before acknowledging them to the original broker to ensure data\n  ## is not lost. This option sets the maximum messages to read from the\n  ## broker that have not been written by an output.\n  ##\n  ## This value needs to be picked with awareness of the agent's\n  ## metric_batch_size value as well. Setting max undelivered messages too high\n  ## can result in a constant stream of data batches to the output. While\n  ## setting it too low may never flush the broker's messages.\n  # max_undelivered_messages = 1000\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/nstat/README.md",
    "content": "# Kernel Network Statistics Input Plugin\n\nThis plugin collects network metrics from `/proc/net/netstat`, `/proc/net/snmp`\nand `/proc/net/snmp6` files\n\n⭐ Telegraf v0.13.1\n🏷️ network, system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collect kernel snmp counters and network interface statistics\n[[inputs.nstat]]\n  ## file paths for proc files. If empty default paths will be used:\n  ##    /proc/net/netstat, /proc/net/snmp, /proc/net/snmp6\n  ## These can also be overridden with env variables, see README.\n  proc_net_netstat = \"/proc/net/netstat\"\n  proc_net_snmp = \"/proc/net/snmp\"\n  proc_net_snmp6 = \"/proc/net/snmp6\"\n  ## dump metrics with 0 values too\n  dump_zeros       = true\n```\n\nThe plugin firstly tries to read file paths from config values if it is empty,\nthen it reads from env variables.\n\n* `PROC_NET_NETSTAT`\n* `PROC_NET_SNMP`\n* `PROC_NET_SNMP6`\n\nIf these variables are also not set,\nthen it tries to read the proc root from env - `PROC_ROOT`,\nand sets `/proc` as a root path if `PROC_ROOT` is also empty.\n\nThen appends default file paths:\n\n* `/net/netstat`\n* `/net/snmp`\n* `/net/snmp6`\n\nSo if nothing is given, no paths in config and in env vars, the plugin takes the\ndefault paths.\n\n* `/proc/net/netstat`\n* `/proc/net/snmp`\n* `/proc/net/snmp6`\n\nIn case that `proc_net_snmp6` path doesn't exist (e.g. IPv6 is not enabled) no\nerror would be raised.\n\n## Metrics\n\n* nstat\n  * Icmp6InCsumErrors\n  * Icmp6InDestUnreachs\n  * Icmp6InEchoReplies\n  * Icmp6InEchos\n  * Icmp6InErrors\n  * Icmp6InGroupMembQueries\n  * Icmp6InGroupMembReductions\n  * Icmp6InGroupMembResponses\n  * Icmp6InMLDv2Reports\n  * Icmp6InMsgs\n  * Icmp6InNeighborAdvertisements\n  * Icmp6InNeighborSolicits\n  * Icmp6InParmProblems\n  * Icmp6InPktTooBigs\n  * Icmp6InRedirects\n  * Icmp6InRouterAdvertisements\n  * Icmp6InRouterSolicits\n  * Icmp6InTimeExcds\n  * Icmp6OutDestUnreachs\n  * Icmp6OutEchoReplies\n  * Icmp6OutEchos\n  * Icmp6OutErrors\n  * Icmp6OutGroupMembQueries\n  * Icmp6OutGroupMembReductions\n  * Icmp6OutGroupMembResponses\n  * Icmp6OutMLDv2Reports\n  * Icmp6OutMsgs\n  * Icmp6OutNeighborAdvertisements\n  * Icmp6OutNeighborSolicits\n  * Icmp6OutParmProblems\n  * Icmp6OutPktTooBigs\n  * Icmp6OutRedirects\n  * Icmp6OutRouterAdvertisements\n  * Icmp6OutRouterSolicits\n  * Icmp6OutTimeExcds\n  * Icmp6OutType133\n  * Icmp6OutType135\n  * Icmp6OutType143\n  * IcmpInAddrMaskReps\n  * IcmpInAddrMasks\n  * IcmpInCsumErrors\n  * IcmpInDestUnreachs\n  * IcmpInEchoReps\n  * IcmpInEchos\n  * IcmpInErrors\n  * IcmpInMsgs\n  * IcmpInParmProbs\n  * IcmpInRedirects\n  * IcmpInSrcQuenchs\n  * IcmpInTimeExcds\n  * IcmpInTimestampReps\n  * IcmpInTimestamps\n  * IcmpMsgInType3\n  * IcmpMsgOutType3\n  * IcmpOutAddrMaskReps\n  * IcmpOutAddrMasks\n  * IcmpOutDestUnreachs\n  * IcmpOutEchoReps\n  * IcmpOutEchos\n  * IcmpOutErrors\n  * IcmpOutMsgs\n  * IcmpOutParmProbs\n  * IcmpOutRedirects\n  * IcmpOutSrcQuenchs\n  * IcmpOutTimeExcds\n  * IcmpOutTimestampReps\n  * IcmpOutTimestamps\n  * Ip6FragCreates\n  * Ip6FragFails\n  * Ip6FragOKs\n  * Ip6InAddrErrors\n  * Ip6InBcastOctets\n  * Ip6InCEPkts\n  * Ip6InDelivers\n  * Ip6InDiscards\n  * Ip6InECT0Pkts\n  * Ip6InECT1Pkts\n  * Ip6InHdrErrors\n  * Ip6InMcastOctets\n  * Ip6InMcastPkts\n  * Ip6InNoECTPkts\n  * Ip6InNoRoutes\n  * Ip6InOctets\n  * Ip6InReceives\n  * Ip6InTooBigErrors\n  * Ip6InTruncatedPkts\n  * Ip6InUnknownProtos\n  * Ip6OutBcastOctets\n  * Ip6OutDiscards\n  * Ip6OutForwDatagrams\n  * Ip6OutMcastOctets\n  * Ip6OutMcastPkts\n  * Ip6OutNoRoutes\n  * Ip6OutOctets\n  * Ip6OutRequests\n  * Ip6ReasmFails\n  * Ip6ReasmOKs\n  * Ip6ReasmReqds\n  * Ip6ReasmTimeout\n  * IpDefaultTTL\n  * IpExtInBcastOctets\n  * IpExtInBcastPkts\n  * IpExtInCEPkts\n  * IpExtInCsumErrors\n  * IpExtInECT0Pkts\n  * IpExtInECT1Pkts\n  * IpExtInMcastOctets\n  * IpExtInMcastPkts\n  * IpExtInNoECTPkts\n  * IpExtInNoRoutes\n  * IpExtInOctets\n  * IpExtInTruncatedPkts\n  * IpExtOutBcastOctets\n  * IpExtOutBcastPkts\n  * IpExtOutMcastOctets\n  * IpExtOutMcastPkts\n  * IpExtOutOctets\n  * IpForwDatagrams\n  * IpForwarding\n  * IpFragCreates\n  * IpFragFails\n  * IpFragOKs\n  * IpInAddrErrors\n  * IpInDelivers\n  * IpInDiscards\n  * IpInHdrErrors\n  * IpInReceives\n  * IpInUnknownProtos\n  * IpOutDiscards\n  * IpOutNoRoutes\n  * IpOutRequests\n  * IpReasmFails\n  * IpReasmOKs\n  * IpReasmReqds\n  * IpReasmTimeout\n  * TcpActiveOpens\n  * TcpAttemptFails\n  * TcpCurrEstab\n  * TcpEstabResets\n  * TcpExtArpFilter\n  * TcpExtBusyPollRxPackets\n  * TcpExtDelayedACKLocked\n  * TcpExtDelayedACKLost\n  * TcpExtDelayedACKs\n  * TcpExtEmbryonicRsts\n  * TcpExtIPReversePathFilter\n  * TcpExtListenDrops\n  * TcpExtListenOverflows\n  * TcpExtLockDroppedIcmps\n  * TcpExtOfoPruned\n  * TcpExtOutOfWindowIcmps\n  * TcpExtPAWSActive\n  * TcpExtPAWSEstab\n  * TcpExtPAWSPassive\n  * TcpExtPruneCalled\n  * TcpExtRcvPruned\n  * TcpExtSyncookiesFailed\n  * TcpExtSyncookiesRecv\n  * TcpExtSyncookiesSent\n  * TcpExtTCPACKSkippedChallenge\n  * TcpExtTCPACKSkippedFinWait2\n  * TcpExtTCPACKSkippedPAWS\n  * TcpExtTCPACKSkippedSeq\n  * TcpExtTCPACKSkippedSynRecv\n  * TcpExtTCPACKSkippedTimeWait\n  * TcpExtTCPAbortFailed\n  * TcpExtTCPAbortOnClose\n  * TcpExtTCPAbortOnData\n  * TcpExtTCPAbortOnLinger\n  * TcpExtTCPAbortOnMemory\n  * TcpExtTCPAbortOnTimeout\n  * TcpExtTCPAutoCorking\n  * TcpExtTCPBacklogDrop\n  * TcpExtTCPChallengeACK\n  * TcpExtTCPDSACKIgnoredNoUndo\n  * TcpExtTCPDSACKIgnoredOld\n  * TcpExtTCPDSACKOfoRecv\n  * TcpExtTCPDSACKOfoSent\n  * TcpExtTCPDSACKOldSent\n  * TcpExtTCPDSACKRecv\n  * TcpExtTCPDSACKUndo\n  * TcpExtTCPDeferAcceptDrop\n  * TcpExtTCPDirectCopyFromBacklog\n  * TcpExtTCPDirectCopyFromPrequeue\n  * TcpExtTCPFACKReorder\n  * TcpExtTCPFastOpenActive\n  * TcpExtTCPFastOpenActiveFail\n  * TcpExtTCPFastOpenCookieReqd\n  * TcpExtTCPFastOpenListenOverflow\n  * TcpExtTCPFastOpenPassive\n  * TcpExtTCPFastOpenPassiveFail\n  * TcpExtTCPFastRetrans\n  * TcpExtTCPForwardRetrans\n  * TcpExtTCPFromZeroWindowAdv\n  * TcpExtTCPFullUndo\n  * TcpExtTCPHPAcks\n  * TcpExtTCPHPHits\n  * TcpExtTCPHPHitsToUser\n  * TcpExtTCPHystartDelayCwnd\n  * TcpExtTCPHystartDelayDetect\n  * TcpExtTCPHystartTrainCwnd\n  * TcpExtTCPHystartTrainDetect\n  * TcpExtTCPKeepAlive\n  * TcpExtTCPLossFailures\n  * TcpExtTCPLossProbeRecovery\n  * TcpExtTCPLossProbes\n  * TcpExtTCPLossUndo\n  * TcpExtTCPLostRetransmit\n  * TcpExtTCPMD5NotFound\n  * TcpExtTCPMD5Unexpected\n  * TcpExtTCPMTUPFail\n  * TcpExtTCPMTUPSuccess\n  * TcpExtTCPMemoryPressures\n  * TcpExtTCPMinTTLDrop\n  * TcpExtTCPOFODrop\n  * TcpExtTCPOFOMerge\n  * TcpExtTCPOFOQueue\n  * TcpExtTCPOrigDataSent\n  * TcpExtTCPPartialUndo\n  * TcpExtTCPPrequeueDropped\n  * TcpExtTCPPrequeued\n  * TcpExtTCPPureAcks\n  * TcpExtTCPRcvCoalesce\n  * TcpExtTCPRcvCollapsed\n  * TcpExtTCPRenoFailures\n  * TcpExtTCPRenoRecovery\n  * TcpExtTCPRenoRecoveryFail\n  * TcpExtTCPRenoReorder\n  * TcpExtTCPReqQFullDoCookies\n  * TcpExtTCPReqQFullDrop\n  * TcpExtTCPRetransFail\n  * TcpExtTCPSACKDiscard\n  * TcpExtTCPSACKReneging\n  * TcpExtTCPSACKReorder\n  * TcpExtTCPSYNChallenge\n  * TcpExtTCPSackFailures\n  * TcpExtTCPSackMerged\n  * TcpExtTCPSackRecovery\n  * TcpExtTCPSackRecoveryFail\n  * TcpExtTCPSackShiftFallback\n  * TcpExtTCPSackShifted\n  * TcpExtTCPSchedulerFailed\n  * TcpExtTCPSlowStartRetrans\n  * TcpExtTCPSpuriousRTOs\n  * TcpExtTCPSpuriousRtxHostQueues\n  * TcpExtTCPSynRetrans\n  * TcpExtTCPTSReorder\n  * TcpExtTCPTimeWaitOverflow\n  * TcpExtTCPTimeouts\n  * TcpExtTCPToZeroWindowAdv\n  * TcpExtTCPWantZeroWindowAdv\n  * TcpExtTCPWinProbe\n  * TcpExtTW\n  * TcpExtTWKilled\n  * TcpExtTWRecycled\n  * TcpInCsumErrors\n  * TcpInErrs\n  * TcpInSegs\n  * TcpMaxConn\n  * TcpOutRsts\n  * TcpOutSegs\n  * TcpPassiveOpens\n  * TcpRetransSegs\n  * TcpRtoAlgorithm\n  * TcpRtoMax\n  * TcpRtoMin\n  * Udp6IgnoredMulti\n  * Udp6InCsumErrors\n  * Udp6InDatagrams\n  * Udp6InErrors\n  * Udp6NoPorts\n  * Udp6OutDatagrams\n  * Udp6RcvbufErrors\n  * Udp6SndbufErrors\n  * UdpIgnoredMulti\n  * UdpInCsumErrors\n  * UdpInDatagrams\n  * UdpInErrors\n  * UdpLite6InCsumErrors\n  * UdpLite6InDatagrams\n  * UdpLite6InErrors\n  * UdpLite6NoPorts\n  * UdpLite6OutDatagrams\n  * UdpLite6RcvbufErrors\n  * UdpLite6SndbufErrors\n  * UdpLiteIgnoredMulti\n  * UdpLiteInCsumErrors\n  * UdpLiteInDatagrams\n  * UdpLiteInErrors\n  * UdpLiteNoPorts\n  * UdpLiteOutDatagrams\n  * UdpLiteRcvbufErrors\n  * UdpLiteSndbufErrors\n  * UdpNoPorts\n  * UdpOutDatagrams\n  * UdpRcvbufErrors\n  * UdpSndbufErrors\n\n### Tags\n\n* All measurements have the following tags\n  * host (host of the system)\n  * name (the type of the metric: snmp, snmp6 or netstat)\n\n## Example Output\n\n```text\n> nstat,host=Hugin,name=netstat IpExtInBcastOctets=2142i,IpExtInBcastPkts=1i,IpExtInCEPkts=0i,IpExtInCsumErrors=0i,IpExtInECT0Pkts=0i,IpExtInECT1Pkts=0i,IpExtInMcastOctets=2636i,IpExtInMcastPkts=14i,IpExtInNoECTPkts=234065i,IpExtInNoRoutes=2i,IpExtInOctets=135040263i,IpExtInTruncatedPkts=0i,IpExtOutBcastOctets=2162i,IpExtOutBcastPkts=2i,IpExtOutMcastOctets=3196i,IpExtOutMcastPkts=28i,IpExtOutOctets=45962238i,IpExtReasmOverlaps=0i,MPTcpExtAddAddr=0i,MPTcpExtAddAddrDrop=0i,MPTcpExtAddAddrTx=0i,MPTcpExtAddAddrTxDrop=0i,MPTcpExtBlackhole=0i,MPTcpExtDSSCorruptionFallback=0i,MPTcpExtDSSCorruptionReset=0i,MPTcpExtDSSNoMatchTCP=0i,MPTcpExtDSSNotMatching=0i,MPTcpExtDataCsumErr=0i,MPTcpExtDuplicateData=0i,MPTcpExtEchoAdd=0i,MPTcpExtEchoAddTx=0i,MPTcpExtEchoAddTxDrop=0i,MPTcpExtInfiniteMapRx=0i,MPTcpExtInfiniteMapTx=0i,MPTcpExtMPCapableACKRX=0i,MPTcpExtMPCapableEndpAttempt=0i,MPTcpExtMPCapableFallbackACK=0i,MPTcpExtMPCapableFallbackSYNACK=0i,MPTcpExtMPCapableSYNACKRX=0i,MPTcpExtMPCapableSYNRX=0i,MPTcpExtMPCapableSYNTX=0i,MPTcpExtMPCapableSYNTXDisabled=0i,MPTcpExtMPCapableSYNTXDrop=0i,MPTcpExtMPCurrEstab=0i,MPTcpExtMPFailRx=0i,MPTcpExtMPFailTx=0i,MPTcpExtMPFallbackTokenInit=0i,MPTcpExtMPFastcloseRx=0i,MPTcpExtMPFastcloseTx=0i,MPTcpExtMPJoinAckHMacFailure=0i,MPTcpExtMPJoinAckRx=0i,MPTcpExtMPJoinNoTokenFound=0i,MPTcpExtMPJoinPortAckRx=0i,MPTcpExtMPJoinPortSynAckRx=0i,MPTcpExtMPJoinPortSynRx=0i,MPTcpExtMPJoinSynAckBackupRx=0i,MPTcpExtMPJoinSynAckHMacFailure=0i,MPTcpExtMPJoinSynAckRx=0i,MPTcpExtMPJoinSynBackupRx=0i,MPTcpExtMPJoinSynRx=0i,MPTcpExtMPJoinSynTx=0i,MPTcpExtMPJoinSynTxBindErr=0i,MPTcpExtMPJoinSynTxConnectErr=0i,MPTcpExtMPJoinSynTxCreatSkErr=0i,MPTcpExtMPPrioRx=0i,MPTcpExtMPPrioTx=0i,MPTcpExtMPRstRx=0i,MPTcpExtMPRstTx=0i,MPTcpExtMPTCPRetrans=0i,MPTcpExtMismatchPortAckRx=0i,MPTcpExtMismatchPortSynRx=0i,MPTcpExtNoDSSInWindow=0i,MPTcpExtOFOMerge=0i,MPTcpExtOFOQueue=0i,MPTcpExtOFOQueueTail=0i,MPTcpExtPortAdd=0i,MPTcpExtRcvPruned=0i,MPTcpExtRcvWndConflict=0i,MPTcpExtRcvWndConflictUpdate=0i,MPTcpExtRcvWndShared=0i,MPTcpExtRmAddr=0i,MPTcpExtRmAddrDrop=0i,MPTcpExtRmAddrTx=0i,MPTcpExtRmAddrTxDrop=0i,MPTcpExtRmSubflow=0i,MPTcpExtSndWndShared=0i,MPTcpExtSubflowRecover=0i,MPTcpExtSubflowStale=0i,TcpExtArpFilter=0i,TcpExtBusyPollRxPackets=0i,TcpExtDelayedACKLocked=1i,TcpExtDelayedACKLost=123i,TcpExtDelayedACKs=1313i,TcpExtEmbryonicRsts=0i,TcpExtIPReversePathFilter=0i,TcpExtListenDrops=0i,TcpExtListenOverflows=0i,TcpExtLockDroppedIcmps=0i,TcpExtOfoPruned=0i,TcpExtOutOfWindowIcmps=0i,TcpExtPAWSActive=0i,TcpExtPAWSEstab=0i,TcpExtPFMemallocDrop=0i,TcpExtPruneCalled=0i,TcpExtRcvPruned=0i,TcpExtSyncookiesFailed=0i,TcpExtSyncookiesRecv=0i,TcpExtSyncookiesSent=0i,TcpExtTCPACKSkippedChallenge=0i,TcpExtTCPACKSkippedFinWait2=0i,TcpExtTCPACKSkippedPAWS=0i,TcpExtTCPACKSkippedSeq=1i,TcpExtTCPACKSkippedSynRecv=0i,TcpExtTCPACKSkippedTimeWait=0i,TcpExtTCPAOBad=0i,TcpExtTCPAODroppedIcmps=0i,TcpExtTCPAOGood=0i,TcpExtTCPAOKeyNotFound=0i,TcpExtTCPAORequired=0i,TcpExtTCPAbortFailed=0i,TcpExtTCPAbortOnClose=132i,TcpExtTCPAbortOnData=457i,TcpExtTCPAbortOnLinger=0i,TcpExtTCPAbortOnMemory=0i,TcpExtTCPAbortOnTimeout=0i,TcpExtTCPAckCompressed=15i,TcpExtTCPAutoCorking=1471i,TcpExtTCPBacklogCoalesce=113i,TcpExtTCPBacklogDrop=0i,TcpExtTCPChallengeACK=0i,TcpExtTCPDSACKIgnoredDubious=0i,TcpExtTCPDSACKIgnoredNoUndo=65i,TcpExtTCPDSACKIgnoredOld=0i,TcpExtTCPDSACKOfoRecv=0i,TcpExtTCPDSACKOfoSent=0i,TcpExtTCPDSACKOldSent=123i,TcpExtTCPDSACKRecv=78i,TcpExtTCPDSACKRecvSegs=78i,TcpExtTCPDSACKUndo=0i,TcpExtTCPDeferAcceptDrop=0i,TcpExtTCPDelivered=95905i,TcpExtTCPDeliveredCE=0i,TcpExtTCPFastOpenActive=0i,TcpExtTCPFastOpenActiveFail=0i,TcpExtTCPFastOpenBlackhole=0i,TcpExtTCPFastOpenCookieReqd=0i,TcpExtTCPFastOpenListenOverflow=0i,TcpExtTCPFastOpenPassive=0i,TcpExtTCPFastOpenPassiveAltKey=0i,TcpExtTCPFastOpenPassiveFail=0i,TcpExtTCPFastRetrans=3i,TcpExtTCPFromZeroWindowAdv=1i,TcpExtTCPFullUndo=2i,TcpExtTCPHPAcks=40380i,TcpExtTCPHPHits=46243i,TcpExtTCPHystartDelayCwnd=81i,TcpExtTCPHystartDelayDetect=3i,TcpExtTCPHystartTrainCwnd=0i,TcpExtTCPHystartTrainDetect=0i,TcpExtTCPKeepAlive=2816i,TcpExtTCPLossFailures=0i,TcpExtTCPLossProbeRecovery=0i,TcpExtTCPLossProbes=85i,TcpExtTCPLossUndo=0i,TcpExtTCPLostRetransmit=0i,TcpExtTCPMD5Failure=0i,TcpExtTCPMD5NotFound=0i,TcpExtTCPMD5Unexpected=0i,TcpExtTCPMTUPFail=0i,TcpExtTCPMTUPSuccess=0i,TcpExtTCPMemoryPressures=0i,TcpExtTCPMemoryPressuresChrono=0i,TcpExtTCPMigrateReqFailure=0i,TcpExtTCPMigrateReqSuccess=0i,TcpExtTCPMinTTLDrop=0i,TcpExtTCPOFODrop=0i,TcpExtTCPOFOMerge=0i,TcpExtTCPOFOQueue=509i,TcpExtTCPOrigDataSent=89707i,TcpExtTCPPLBRehash=0i,TcpExtTCPPartialUndo=1i,TcpExtTCPPureAcks=35929i,TcpExtTCPRcvCoalesce=9070i,TcpExtTCPRcvCollapsed=0i,TcpExtTCPRcvQDrop=0i,TcpExtTCPRenoFailures=0i,TcpExtTCPRenoRecovery=0i,TcpExtTCPRenoRecoveryFail=0i,TcpExtTCPRenoReorder=0i,TcpExtTCPReqQFullDoCookies=0i,TcpExtTCPReqQFullDrop=0i,TcpExtTCPRetransFail=0i,TcpExtTCPSACKDiscard=0i,TcpExtTCPSACKReneging=0i,TcpExtTCPSACKReorder=79i,TcpExtTCPSYNChallenge=0i,TcpExtTCPSackFailures=0i,TcpExtTCPSackMerged=3i,TcpExtTCPSackRecovery=3i,TcpExtTCPSackRecoveryFail=0i,TcpExtTCPSackShiftFallback=116i,TcpExtTCPSackShifted=2i,TcpExtTCPSlowStartRetrans=0i,TcpExtTCPSpuriousRTOs=0i,TcpExtTCPSpuriousRtxHostQueues=0i,TcpExtTCPSynRetrans=1i,TcpExtTCPTSReorder=1i,TcpExtTCPTimeWaitOverflow=0i,TcpExtTCPTimeouts=1i,TcpExtTCPToZeroWindowAdv=1i,TcpExtTCPWantZeroWindowAdv=4i,TcpExtTCPWinProbe=0i,TcpExtTCPWqueueTooBig=0i,TcpExtTCPZeroWindowDrop=0i,TcpExtTW=7592i,TcpExtTWKilled=0i,TcpExtTWRecycled=0i,TcpExtTcpDuplicateDataRehash=0i,TcpExtTcpTimeoutRehash=1i 1742837823000000000\n2025-03-24T17:37:03Z D! [agent] Stopping service inputs\n> nstat,host=Hugin,name=snmp IcmpInAddrMaskReps=0i,IcmpInAddrMasks=0i,IcmpInCsumErrors=0i,IcmpInDestUnreachs=1i,IcmpInEchoReps=0i,IcmpInEchos=0i,IcmpInErrors=0i,IcmpInMsgs=1i,IcmpInParmProbs=0i,IcmpInRedirects=0i,IcmpInSrcQuenchs=0i,IcmpInTimeExcds=0i,IcmpInTimestampReps=0i,IcmpInTimestamps=0i,IcmpMsgInType3=1i,IcmpMsgOutType3=1i,IcmpOutAddrMaskReps=0i,IcmpOutAddrMasks=0i,IcmpOutDestUnreachs=1i,IcmpOutEchoReps=0i,IcmpOutEchos=0i,IcmpOutErrors=0i,IcmpOutMsgs=1i,IcmpOutParmProbs=0i,IcmpOutRateLimitGlobal=0i,IcmpOutRateLimitHost=0i,IcmpOutRedirects=0i,IcmpOutSrcQuenchs=0i,IcmpOutTimeExcds=0i,IcmpOutTimestampReps=0i,IcmpOutTimestamps=0i,IpDefaultTTL=64i,IpForwDatagrams=12i,IpForwarding=1i,IpFragCreates=2i,IpFragFails=0i,IpFragOKs=1i,IpInAddrErrors=0i,IpInDelivers=227088i,IpInDiscards=0i,IpInHdrErrors=0i,IpInReceives=227102i,IpInUnknownProtos=0i,IpOutDiscards=0i,IpOutNoRoutes=44i,IpOutRequests=194901i,IpOutTransmits=194914i,IpReasmFails=0i,IpReasmOKs=0i,IpReasmReqds=0i,IpReasmTimeout=0i,TcpActiveOpens=12453i,TcpAttemptFails=4005i,TcpCurrEstab=9i,TcpEstabResets=2312i,TcpInCsumErrors=0i,TcpInErrs=0i,TcpInSegs=206125i,TcpMaxConn=-1i,TcpOutRsts=6928i,TcpOutSegs=189170i,TcpPassiveOpens=7628i,TcpRetransSegs=86i,TcpRtoAlgorithm=1i,TcpRtoMax=120000i,TcpRtoMin=200i,UdpIgnoredMulti=0i,UdpInCsumErrors=0i,UdpInDatagrams=27391i,UdpInErrors=0i,UdpLiteIgnoredMulti=0i,UdpLiteInCsumErrors=0i,UdpLiteInDatagrams=0i,UdpLiteInErrors=0i,UdpLiteMemErrors=0i,UdpLiteNoPorts=0i,UdpLiteOutDatagrams=0i,UdpLiteRcvbufErrors=0i,UdpLiteSndbufErrors=0i,UdpMemErrors=0i,UdpNoPorts=1i,UdpOutDatagrams=14308i,UdpRcvbufErrors=0i,UdpSndbufErrors=0i 1742837823000000000\n2025-03-24T17:37:03Z D! [agent] Input channel closed\n2025-03-24T17:37:03Z D! [agent] Stopped Successfully\n> nstat,host=Hugin,name=snmp6 Icmp6InCsumErrors=0i,Icmp6InDestUnreachs=0i,Icmp6InEchoReplies=0i,Icmp6InEchos=0i,Icmp6InErrors=0i,Icmp6InGroupMembQueries=0i,Icmp6InGroupMembReductions=0i,Icmp6InGroupMembResponses=0i,Icmp6InMLDv2Reports=0i,Icmp6InMsgs=0i,Icmp6InNeighborAdvertisements=0i,Icmp6InNeighborSolicits=0i,Icmp6InParmProblems=0i,Icmp6InPktTooBigs=0i,Icmp6InRedirects=0i,Icmp6InRouterAdvertisements=0i,Icmp6InRouterSolicits=0i,Icmp6InTimeExcds=0i,Icmp6OutDestUnreachs=0i,Icmp6OutEchoReplies=0i,Icmp6OutEchos=0i,Icmp6OutErrors=0i,Icmp6OutGroupMembQueries=0i,Icmp6OutGroupMembReductions=0i,Icmp6OutGroupMembResponses=0i,Icmp6OutMLDv2Reports=271i,Icmp6OutMsgs=430i,Icmp6OutNeighborAdvertisements=0i,Icmp6OutNeighborSolicits=62i,Icmp6OutParmProblems=0i,Icmp6OutPktTooBigs=0i,Icmp6OutRateLimitHost=0i,Icmp6OutRedirects=0i,Icmp6OutRouterAdvertisements=0i,Icmp6OutRouterSolicits=97i,Icmp6OutTimeExcds=0i,Icmp6OutType133=97i,Icmp6OutType135=62i,Icmp6OutType143=271i,Ip6FragCreates=0i,Ip6FragFails=0i,Ip6FragOKs=0i,Ip6InAddrErrors=0i,Ip6InBcastOctets=0i,Ip6InCEPkts=0i,Ip6InDelivers=6433i,Ip6InDiscards=0i,Ip6InECT0Pkts=0i,Ip6InECT1Pkts=0i,Ip6InHdrErrors=0i,Ip6InMcastOctets=2652i,Ip6InMcastPkts=11i,Ip6InNoECTPkts=6433i,Ip6InNoRoutes=0i,Ip6InOctets=763395i,Ip6InReceives=6433i,Ip6InTooBigErrors=0i,Ip6InTruncatedPkts=0i,Ip6InUnknownProtos=0i,Ip6OutBcastOctets=0i,Ip6OutDiscards=12i,Ip6OutForwDatagrams=0i,Ip6OutMcastOctets=35016i,Ip6OutMcastPkts=453i,Ip6OutNoRoutes=4652i,Ip6OutOctets=795759i,Ip6OutRequests=6875i,Ip6OutTransmits=6875i,Ip6ReasmFails=0i,Ip6ReasmOKs=0i,Ip6ReasmReqds=0i,Ip6ReasmTimeout=0i,Udp6IgnoredMulti=0i,Udp6InCsumErrors=0i,Udp6InDatagrams=45i,Udp6InErrors=0i,Udp6MemErrors=0i,Udp6NoPorts=0i,Udp6OutDatagrams=24i,Udp6RcvbufErrors=0i,Udp6SndbufErrors=0i,UdpLite6InCsumErrors=0i,UdpLite6InDatagrams=0i,UdpLite6InErrors=0i,UdpLite6MemErrors=0i,UdpLite6NoPorts=0i,UdpLite6OutDatagrams=0i,UdpLite6RcvbufErrors=0i,UdpLite6SndbufErrors=0i 1742837823000000000\n```\n"
  },
  {
    "path": "plugins/inputs/nstat/nstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nstat\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tzeroByte    = []byte(\"0\")\n\tnewLineByte = []byte(\"\\n\")\n\tcolonByte   = []byte(\":\")\n)\n\nconst (\n\t// default file paths\n\tnetNetstat = \"/net/netstat\"\n\tnetSnmp    = \"/net/snmp\"\n\tnetSnmp6   = \"/net/snmp6\"\n\tnetProc    = \"/proc\"\n\n\t// env variable names\n\tenvNetstat = \"PROC_NET_NETSTAT\"\n\tenvSnmp    = \"PROC_NET_SNMP\"\n\tenvSnmp6   = \"PROC_NET_SNMP6\"\n\tenvRoot    = \"PROC_ROOT\"\n)\n\ntype Nstat struct {\n\tProcNetNetstat string `toml:\"proc_net_netstat\"`\n\tProcNetSNMP    string `toml:\"proc_net_snmp\"`\n\tProcNetSNMP6   string `toml:\"proc_net_snmp6\"`\n\tDumpZeros      bool   `toml:\"dump_zeros\"`\n}\n\nfunc (*Nstat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ns *Nstat) Gather(acc telegraf.Accumulator) error {\n\t// load paths, get from env if config values are empty\n\tns.loadPaths()\n\n\tnetstat, err := os.ReadFile(ns.ProcNetNetstat)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// collect netstat data\n\tns.gatherNetstat(netstat, acc)\n\n\t// collect SNMP data\n\tsnmp, err := os.ReadFile(ns.ProcNetSNMP)\n\tif err != nil {\n\t\treturn err\n\t}\n\tns.gatherSNMP(snmp, acc)\n\n\t// collect SNMP6 data, if SNMP6 directory exists (IPv6 enabled)\n\tsnmp6, err := os.ReadFile(ns.ProcNetSNMP6)\n\tif err == nil {\n\t\tns.gatherSNMP6(snmp6, acc)\n\t} else if !os.IsNotExist(err) {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (ns *Nstat) gatherNetstat(data []byte, acc telegraf.Accumulator) {\n\tmetrics := ns.loadUglyTable(data)\n\ttags := map[string]string{\n\t\t\"name\": \"netstat\",\n\t}\n\tacc.AddFields(\"nstat\", metrics, tags)\n}\n\nfunc (ns *Nstat) gatherSNMP(data []byte, acc telegraf.Accumulator) {\n\tmetrics := ns.loadUglyTable(data)\n\ttags := map[string]string{\n\t\t\"name\": \"snmp\",\n\t}\n\tacc.AddFields(\"nstat\", metrics, tags)\n}\n\nfunc (ns *Nstat) gatherSNMP6(data []byte, acc telegraf.Accumulator) {\n\tmetrics := ns.loadGoodTable(data)\n\ttags := map[string]string{\n\t\t\"name\": \"snmp6\",\n\t}\n\tacc.AddFields(\"nstat\", metrics, tags)\n}\n\n// loadPaths can be used to read paths firstly from config\n// if it is empty then try read from env variables\nfunc (ns *Nstat) loadPaths() {\n\tif ns.ProcNetNetstat == \"\" {\n\t\tns.ProcNetNetstat = proc(envNetstat, netNetstat)\n\t}\n\tif ns.ProcNetSNMP == \"\" {\n\t\tns.ProcNetSNMP = proc(envSnmp, netSnmp)\n\t}\n\tif ns.ProcNetSNMP6 == \"\" {\n\t\tns.ProcNetSNMP6 = proc(envSnmp6, netSnmp6)\n\t}\n}\n\n// loadGoodTable can be used to parse string heap that\n// headers and values are arranged in right order\nfunc (ns *Nstat) loadGoodTable(table []byte) map[string]interface{} {\n\tentries := make(map[string]interface{})\n\tfields := bytes.Fields(table)\n\tvar value int64\n\tvar err error\n\t// iterate over two values each time\n\t// first value is header, second is value\n\tfor i := 0; i < len(fields); i = i + 2 {\n\t\t// counter is zero\n\t\tif bytes.Equal(fields[i+1], zeroByte) {\n\t\t\tif !ns.DumpZeros {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tentries[string(fields[i])] = int64(0)\n\t\t\tcontinue\n\t\t}\n\t\t// the counter is not zero, so parse it.\n\t\tvalue, err = strconv.ParseInt(string(fields[i+1]), 10, 64)\n\t\tif err == nil {\n\t\t\tentries[string(fields[i])] = value\n\t\t}\n\t}\n\treturn entries\n}\n\n// loadUglyTable can be used to parse string heap that\n// the headers and values are split with a newline\nfunc (ns *Nstat) loadUglyTable(table []byte) map[string]interface{} {\n\tentries := make(map[string]interface{})\n\t// split the lines by newline\n\tlines := bytes.Split(table, newLineByte)\n\tvar value int64\n\tvar err error\n\t// iterate over lines, take 2 lines each time\n\t// first line contains header names\n\t// second line contains values\n\tfor i := 0; i < len(lines); i = i + 2 {\n\t\tif len(lines[i]) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\theaders := bytes.Fields(lines[i])\n\t\tprefix := bytes.TrimSuffix(headers[0], colonByte)\n\t\tmetrics := bytes.Fields(lines[i+1])\n\n\t\tfor j := 1; j < len(headers); j++ {\n\t\t\t// counter is zero\n\t\t\tif bytes.Equal(metrics[j], zeroByte) {\n\t\t\t\tif !ns.DumpZeros {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tentries[string(append(prefix, headers[j]...))] = int64(0)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// the counter is not zero, so parse it.\n\t\t\tvalue, err = strconv.ParseInt(string(metrics[j]), 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tentries[string(append(prefix, headers[j]...))] = value\n\t\t\t}\n\t\t}\n\t}\n\treturn entries\n}\n\n// proc can be used to read file paths from env\nfunc proc(env, path string) string {\n\t// try to read full file path\n\tif p := os.Getenv(env); p != \"\" {\n\t\treturn p\n\t}\n\t// try to read root path, or use default root path\n\troot := os.Getenv(envRoot)\n\tif root == \"\" {\n\t\troot = netProc\n\t}\n\treturn root + path\n}\n\nfunc init() {\n\tinputs.Add(\"nstat\", func() telegraf.Input {\n\t\treturn &Nstat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nstat/nstat_test.go",
    "content": "package nstat\n\nimport \"testing\"\n\nfunc TestLoadUglyTable(t *testing.T) {\n\tuglyStr := `IpExt: InNoRoutes InTruncatedPkts InMcastPkts InCEPkts\n\tIpExt: 332 433718 0 2660494435`\n\tparsed := map[string]interface{}{\n\t\t\"IpExtInNoRoutes\":      int64(332),\n\t\t\"IpExtInTruncatedPkts\": int64(433718),\n\t\t\"IpExtInMcastPkts\":     int64(0),\n\t\t\"IpExtInCEPkts\":        int64(2660494435),\n\t}\n\n\tn := Nstat{DumpZeros: true}\n\tgot := n.loadUglyTable([]byte(uglyStr))\n\tif len(got) == 0 {\n\t\tt.Fatalf(\"want %+v, got %+v\", parsed, got)\n\t}\n\n\tfor key := range parsed {\n\t\tif parsed[key].(int64) != got[key].(int64) {\n\t\t\tt.Fatalf(\"want %+v, got %+v\", parsed[key], got[key])\n\t\t}\n\t}\n}\n\nfunc TestLoadGoodTable(t *testing.T) {\n\tgoodStr := `Ip6InReceives                   \t11707\n\t\t\t\tIp6InTooBigErrors               \t0\n\t\t\t\tIp6InDelivers                   \t62\n\t\t\t\tIp6InMcastOctets                \t1242966`\n\n\tparsed := map[string]interface{}{\n\t\t\"Ip6InReceives\":     int64(11707),\n\t\t\"Ip6InTooBigErrors\": int64(0),\n\t\t\"Ip6InDelivers\":     int64(62),\n\t\t\"Ip6InMcastOctets\":  int64(1242966),\n\t}\n\tn := Nstat{DumpZeros: true}\n\tgot := n.loadGoodTable([]byte(goodStr))\n\tif len(got) == 0 {\n\t\tt.Fatalf(\"want %+v, got %+v\", parsed, got)\n\t}\n\n\tfor key := range parsed {\n\t\tif parsed[key].(int64) != got[key].(int64) {\n\t\t\tt.Fatalf(\"want %+v, got %+v\", parsed[key], got[key])\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/nstat/sample.conf",
    "content": "# Collect kernel snmp counters and network interface statistics\n[[inputs.nstat]]\n  ## file paths for proc files. If empty default paths will be used:\n  ##    /proc/net/netstat, /proc/net/snmp, /proc/net/snmp6\n  ## These can also be overridden with env variables, see README.\n  proc_net_netstat = \"/proc/net/netstat\"\n  proc_net_snmp = \"/proc/net/snmp\"\n  proc_net_snmp6 = \"/proc/net/snmp6\"\n  ## dump metrics with 0 values too\n  dump_zeros       = true\n"
  },
  {
    "path": "plugins/inputs/ntpq/README.md",
    "content": "# Network Time Protocol Query Input Plugin\n\nThis plugin gathers metrics about [Network Time Protocol][ntp] queries.\n\n> [!IMPORTANT]\n> This plugin requires the `ntpq` executable to be installed on the system.\n\n⭐ Telegraf v0.11.0\n🏷️ network\n💻 all\n\n[ntp]: https://ntp.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## Options to pass to the ntpq command.\n  # options = \"-p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n```\n\nYou can pass arbitrary options accepted by the `ntpq` command using the\n`options` setting. In case you want to skip DNS lookups use\n\n```toml\n  options = \"-p -n\"\n```\n\nfor example.\n\nBelow is the documentation of the various headers returned from the NTP query\ncommand when running `ntpq -p`.\n\n- `remote` – The remote peer or server being synced to. “LOCAL” is this local\n    host (included in case there are no remote peers or servers available);\n- `refid` – Where or what the remote peer or server is itself synchronised to;\n- `st` (stratum) – The remote peer or server Stratum\n- `t` (type) – Type (u: unicast or manycast client, b: broadcast or multicast\n    client, l: local reference clock, s: symmetric peer, A: manycast server,\n    B: broadcast server, M: multicast server, see “Automatic Server Discovery“);\n- `when` – When last polled (seconds ago, “h” hours ago, or “d” days ago);\n- `poll` – Polling frequency: rfc5905 suggests this ranges in NTPv4 from 4 (16s)\n    to 17 (36h) (log2 seconds), however observation suggests the actual\n    displayed value is seconds for a much smaller range of 64 (26) to 1024\n    (210) seconds;\n- `reach` – An 8-bit left-shift shift register value recording polls\n    (bit set = successful, bit reset = fail) displayed in octal;\n- `delay` – Round trip communication delay to the remote peer or server\n    (milliseconds);\n- `offset` – Mean offset (phase) in the times reported between this local host\n    and the remote peer or server (RMS, milliseconds);\n- `jitter` – Mean deviation (jitter) in the time reported for that remote peer\n    or server (RMS of difference of multiple time samples, milliseconds);\n\n## Metrics\n\n- `ntpq`\n  - delay (float, milliseconds)\n  - jitter (float, milliseconds)\n  - offset (float, milliseconds)\n  - poll (int, seconds)\n  - reach (int)\n  - when (int, seconds)\n\n### Tags\n\nAll measurements have the following tags:\n\n- refid\n- remote\n- type\n- stratum\n\nIn case you are specifying `servers`, the measurement has an\nadditional `source` tag.\n\n## Example Output\n\n```text\nntpq,refid=.GPSs.,remote=*time.apple.com,stratum=1,type=u delay=91.797,jitter=3.735,offset=12.841,poll=64i,reach=377i,when=35i 1457960478909556134\n```\n"
  },
  {
    "path": "plugins/inputs/ntpq/ntpq.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ntpq\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"math/bits\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/kballard/go-shellquote\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// Due to problems with a parsing, we have to use regexp expression in order\n// to remove string that starts from '(' and ends with space\n// see: https://github.com/influxdata/telegraf/issues/2386\nvar reBrackets = regexp.MustCompile(`\\s+\\([\\S]*`)\n\ntype elementType int64\n\nconst (\n\tnone elementType = iota\n\ttag\n\tfieldFloat\n\tfieldDuration\n\tfieldIntDecimal\n\tfieldIntOctal\n\tfieldIntRatio8\n\tfieldIntBits\n)\n\ntype NTPQ struct {\n\tOptions     string   `toml:\"options\"`\n\tServers     []string `toml:\"servers\"`\n\tReachFormat string   `toml:\"reach_format\"`\n\n\trunQ func(string) ([]byte, error)\n}\n\ntype column struct {\n\tname  string\n\tetype elementType\n}\n\n// Mapping of ntpq header names to tag keys\nvar tagHeaders = map[string]string{\n\t\"remote\": \"remote\",\n\t\"refid\":  \"refid\",\n\t\"st\":     \"stratum\",\n\t\"t\":      \"type\",\n}\n\n// Mapping of fields\nvar fieldElements = map[string]elementType{\n\t\"delay\":  fieldFloat,\n\t\"jitter\": fieldFloat,\n\t\"offset\": fieldFloat,\n\t\"reach\":  fieldIntDecimal,\n\t\"poll\":   fieldDuration,\n\t\"when\":   fieldDuration,\n}\n\nfunc (*NTPQ) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *NTPQ) Init() error {\n\tif len(n.Servers) == 0 {\n\t\tn.Servers = []string{\"\"}\n\t}\n\n\tif n.runQ == nil {\n\t\toptions, err := shellquote.Split(n.Options)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"splitting options failed: %w\", err)\n\t\t}\n\t\tif !slices.Contains(options, \"-p\") {\n\t\t\toptions = append(options, \"-p\")\n\t\t}\n\n\t\tn.runQ = func(server string) ([]byte, error) {\n\t\t\tbin, err := exec.LookPath(\"ntpq\")\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\t// Needs to be last argument\n\t\t\targs := make([]string, 0, len(options)+1)\n\t\t\targs = append(args, options...)\n\t\t\tif server != \"\" {\n\t\t\t\targs = append(args, server)\n\t\t\t}\n\t\t\tcmd := exec.Command(bin, args...)\n\t\t\treturn cmd.Output()\n\t\t}\n\t}\n\n\tswitch n.ReachFormat {\n\tcase \"\", \"octal\":\n\t\tn.ReachFormat = \"octal\"\n\t\t// Interpret the field as decimal integer returning\n\t\t// the raw (octal) representation\n\t\tfieldElements[\"reach\"] = fieldIntDecimal\n\tcase \"decimal\":\n\t\t// Interpret the field as octal integer returning\n\t\t// decimal number representation\n\t\tfieldElements[\"reach\"] = fieldIntOctal\n\tcase \"count\":\n\t\t// Interpret the field as bits set returning\n\t\t// the number of bits set\n\t\tfieldElements[\"reach\"] = fieldIntBits\n\tcase \"ratio\":\n\t\t// Interpret the field as ratio between the number of\n\t\t// bits set and the maximum available bits set (8).\n\t\tfieldElements[\"reach\"] = fieldIntRatio8\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown 'reach_format' %q\", n.ReachFormat)\n\t}\n\n\treturn nil\n}\n\nfunc (n *NTPQ) Gather(acc telegraf.Accumulator) error {\n\tfor _, server := range n.Servers {\n\t\tn.gatherServer(acc, server)\n\t}\n\treturn nil\n}\n\nfunc (n *NTPQ) gatherServer(acc telegraf.Accumulator, server string) {\n\tvar msgPrefix string\n\tif server != \"\" {\n\t\tmsgPrefix = fmt.Sprintf(\"[%s] \", server)\n\t}\n\tout, err := n.runQ(server)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"%s%w\", msgPrefix, err))\n\t\treturn\n\t}\n\n\tscanner := bufio.NewScanner(bytes.NewReader(out))\n\n\t// Look for the header\n\tvar columns []column\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t_, elements := processLine(line)\n\t\tif len(elements) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, el := range elements {\n\t\t\t// Check if the element is a tag\n\t\t\tif name, isTag := tagHeaders[el]; isTag {\n\t\t\t\tcolumns = append(columns, column{\n\t\t\t\t\tname:  name,\n\t\t\t\t\tetype: tag,\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Add a field\n\t\t\tif etype, isField := fieldElements[el]; isField {\n\t\t\t\tcolumns = append(columns, column{\n\t\t\t\t\tname:  el,\n\t\t\t\t\tetype: etype,\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Skip the column if not found\n\t\t\tcolumns = append(columns, column{etype: none})\n\t\t}\n\t\tbreak\n\t}\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tprefix, elements := processLine(line)\n\t\tif len(elements) != len(columns) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := make(map[string]string)\n\t\tfields := make(map[string]interface{})\n\n\t\tif prefix != \"\" {\n\t\t\ttags[\"state_prefix\"] = prefix\n\t\t}\n\t\tif server != \"\" {\n\t\t\ttags[\"source\"] = server\n\t\t}\n\n\t\tfor i, raw := range elements {\n\t\t\tcol := columns[i]\n\n\t\t\t// Handle tags, empty or invalid entries\n\t\t\tswitch col.etype {\n\t\t\tcase none:\n\t\t\t\tcontinue\n\t\t\tcase tag:\n\t\t\t\ttags[col.name] = raw\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\t// Common validation for all field types to detect misalignment\n\t\t\t\tif raw == col.name {\n\t\t\t\t\t// Field misalignment detected - skip this field\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%sfield misalignment detected: got column name %q instead of value\", msgPrefix, raw))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle empty or whitespace-only values\n\t\t\tif strings.TrimSpace(raw) == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Type-specific parsing\n\t\t\tswitch col.etype {\n\t\t\tcase fieldFloat:\n\t\t\t\tvalue, err := strconv.ParseFloat(raw, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as float failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = value\n\t\t\tcase fieldDuration:\n\t\t\t\t// Ignore fields only containing a minus\n\t\t\t\tif raw == \"-\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfactor := int64(1)\n\t\t\t\tsuffix := raw[len(raw)-1:]\n\t\t\t\tswitch suffix {\n\t\t\t\tcase \"d\":\n\t\t\t\t\tfactor = 24 * 3600\n\t\t\t\tcase \"h\":\n\t\t\t\t\tfactor = 3600\n\t\t\t\tcase \"m\":\n\t\t\t\t\tfactor = 60\n\t\t\t\tdefault:\n\t\t\t\t\tsuffix = \"\"\n\t\t\t\t}\n\t\t\t\tvalue, err := strconv.ParseInt(strings.TrimSuffix(raw, suffix), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as duration failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = value * factor\n\t\t\tcase fieldIntDecimal:\n\t\t\t\tvalue, err := strconv.ParseInt(raw, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as int failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = value\n\t\t\tcase fieldIntOctal:\n\t\t\t\tvalue, err := strconv.ParseInt(raw, 8, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as int failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = value\n\t\t\tcase fieldIntBits:\n\t\t\t\tvalue, err := strconv.ParseUint(raw, 8, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as int failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = bits.OnesCount64(value)\n\t\t\tcase fieldIntRatio8:\n\t\t\t\tvalue, err := strconv.ParseUint(raw, 8, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmsg := fmt.Sprintf(\"%sparsing %q (%v) as int failed\", msgPrefix, col.name, raw)\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", msg, err))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[col.name] = float64(bits.OnesCount64(value)) / float64(8)\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"ntpq\", fields, tags)\n\t}\n}\n\nfunc processLine(line string) (string, []string) {\n\t// if there is an ntpq state prefix, remove it and make it it's own tag\n\t// see https://github.com/influxdata/telegraf/issues/1161\n\tvar prefix string\n\tif strings.ContainsAny(string(line[0]), \"*#o+x.-\") {\n\t\tprefix = string(line[0])\n\t\tline = strings.TrimLeft(line, \"*#o+x.-\")\n\t}\n\tline = reBrackets.ReplaceAllString(line, \"\")\n\n\treturn prefix, strings.Fields(line)\n}\n\nfunc init() {\n\tinputs.Add(\"ntpq\", func() telegraf.Input {\n\t\treturn &NTPQ{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ntpq/ntpq_test.go",
    "content": "package ntpq\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInitInvalid(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *NTPQ\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"invalid reach_format\",\n\t\t\tplugin:   &NTPQ{ReachFormat: \"garbage\"},\n\t\t\texpected: `unknown 'reach_format' \"garbage\"`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.EqualError(t, tt.plugin.Init(), tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"ntpq\", func() telegraf.Input {\n\t\treturn &NTPQ{}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tinputData, inputErrors, err := readInputData(testcasePath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Fake the reading\n\t\t\tplugin := cfg.Inputs[0].Input.(*NTPQ)\n\t\t\tplugin.runQ = func(server string) ([]byte, error) {\n\t\t\t\treturn inputData[server], inputErrors[server]\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tactualErrorMsgs := make([]string, 0, len(acc.Errors))\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\t\t\t}\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc readInputData(path string) (map[string][]byte, map[string]error, error) {\n\t// Get all elements in the testcase directory\n\tentries, err := os.ReadDir(path)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tdata := make(map[string][]byte)\n\terrs := make(map[string]error)\n\tfor _, e := range entries {\n\t\tif e.IsDir() || !strings.HasPrefix(e.Name(), \"input\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilename := filepath.Join(path, e.Name())\n\t\text := filepath.Ext(e.Name())\n\t\tserver := strings.TrimPrefix(e.Name(), \"input\")\n\t\tserver = strings.TrimPrefix(server, \"_\") // This needs to be separate for non-server cases\n\t\tserver = strings.TrimSuffix(server, ext)\n\n\t\tswitch ext {\n\t\tcase \".txt\":\n\t\t\t// Read the input data\n\t\t\td, err := os.ReadFile(filename)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"reading %q failed: %w\", filename, err)\n\t\t\t}\n\t\t\tdata[server] = d\n\t\tcase \".err\":\n\t\t\t// Read the input error message\n\t\t\tmsgs, err := testutil.ParseLinesFromFile(filename)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"reading error %q failed: %w\", filename, err)\n\t\t\t}\n\t\t\tif len(msgs) != 1 {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"unexpected number of errors: %d\", len(msgs))\n\t\t\t}\n\t\t\terrs[server] = errors.New(msgs[0])\n\t\tdefault:\n\t\t\treturn nil, nil, fmt.Errorf(\"unexpected input %q\", filename)\n\t\t}\n\t}\n\n\treturn data, errs, nil\n}\n"
  },
  {
    "path": "plugins/inputs/ntpq/sample.conf",
    "content": "# Get standard NTP query metrics, requires ntpq executable.\n[[inputs.ntpq]]\n  ## Servers to query with ntpq.\n  ## If no server is given, the local machine is queried.\n  # servers = []\n\n  ## Options to pass to the ntpq command.\n  # options = \"-p\"\n\n  ## Output format for the 'reach' field.\n  ## Available values are\n  ##   octal   --  output as is in octal representation e.g. 377 (default)\n  ##   decimal --  convert value to decimal representation e.g. 371 -> 249\n  ##   count   --  count the number of bits in the value. This represents\n  ##               the number of successful reaches, e.g. 37 -> 5\n  ##   ratio   --  output the ratio of successful attempts e.g. 37 -> 5/8 = 0.625\n  # reach_format = \"octal\"\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_float_parse/expected.err",
    "content": "parsing \"offset\" (foobar) as float failed: strconv.ParseFloat: parsing \"foobar\": invalid syntax"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_float_parse/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=2i,poll=256i,reach=37i,delay=51.016,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_float_parse/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  2  256   37   51.016  foobar  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_float_parse/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_header/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,type=u when=101i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_header/input.txt",
    "content": "remote      refid   foobar t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_header/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_int_parse/expected.err",
    "content": "parsing \"poll\" (foobar) as duration failed: strconv.ParseInt: parsing \"foobar\": invalid syntax"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_int_parse/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_int_parse/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  foobar   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_int_parse/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_when/expected.err",
    "content": "parsing \"when\" (2q) as duration failed: strconv.ParseInt: parsing \"2q\": invalid syntax"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_when/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_when/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  2q  256   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/bad_when/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/days/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=172800i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/days/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  2d  256   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/days/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/failed/expected.err",
    "content": "test failure"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/failed/input.err",
    "content": "test failure"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/failed/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/failed/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/hours/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=7200i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/hours/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  2h  256   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/hours/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/issue_2386/expected.out",
    "content": "ntpq,remote=SHM(0),state_prefix=*,refid=.PPS.,stratum=1,type=u when=60i,poll=64i,reach=377i,delay=0.0,offset=0.045,jitter=1.012 0\nntpq,remote=SHM(1),state_prefix=-,refid=.GPS.,stratum=1,type=u when=121i,poll=128i,reach=377i,delay=0.0,offset=10.105,jitter=2.012 0\nntpq,remote=37.58.57.238,state_prefix=+,refid=192.53.103.103,stratum=2,type=u when=10i,poll=1024i,reach=377i,delay=1.748,offset=0.373,jitter=0.101 0\nntpq,remote=37.58.57.238,state_prefix=+,refid=192.53.103.103,stratum=2,type=u when=10i,poll=1024i,reach=377i,delay=1.748,offset=0.373,jitter=0.101 0\nntpq,remote=37.58.57.238,state_prefix=+,refid=192.53.103.103,stratum=2,type=u when=10i,poll=1024i,reach=377i,delay=1.748,offset=0.373,jitter=0.101 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/issue_2386/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*SHM(0)          .PPS.                          1 u   60  64   377    0.000    0.045   1.012\n+37.58.57.238 (d 192.53.103.103\t\t\t2 u   10 1024  377    1.748    0.373   0.101\n+37.58.57.238 (domain) 192.53.103.103   2 u   10 1024  377    1.748    0.373   0.101\n+37.58.57.238 ( 192.53.103.103\t\t\t2 u   10 1024  377    1.748    0.373   0.101\n-SHM(1)          .GPS.                          1 u   121 128  377    0.000   10.105   2.012\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/issue_2386/telegraf.conf",
    "content": "# Test related to\n#   https://github.com/influxdata/telegraf/issues/2386\n[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/long_poll/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=-,refid=10.177.80.46,stratum=3,type=u when=617i,poll=4080i,reach=377i,delay=9.145,offset=2.849,jitter=1.192 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/long_poll/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n-uschi5-ntp-002. 10.177.80.46     3 u  617 68m 377 9.145 +2.849 1.192"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/long_poll/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/minutes/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=120i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/minutes/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  2m  256   37   51.016  233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/minutes/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/missing_delay_column/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,type=u when=101i,poll=256i,reach=37i,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/missing_delay_column/input.txt",
    "content": "remote      refid   foobar t when poll reach   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   233.010  17.462"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/missing_delay_column/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/multi/expected.out",
    "content": "ntpq,refid=10.177.80.37,remote=83.137.98.96,stratum=2,type=u delay=54.033,offset=243.426,jitter=449514,when=740i,poll=1024i,reach=377i 0\nntpq,refid=10.177.80.37,remote=81.7.16.52,stratum=2,type=u reach=377i,delay=60.785,offset=232.597,jitter=449539,when=739i,poll=1024i 0\nntpq,refid=10.177.80.37,remote=131.188.3.221,stratum=2,type=u when=783i,poll=1024i,reach=377i,delay=111.82,offset=261.921,jitter=449528 0\nntpq,refid=10.177.80.37,remote=5.9.29.107,stratum=2,type=u reach=377i,delay=205.704,offset=160.406,jitter=449602,when=703i,poll=1024i 0\nntpq,refid=10.177.80.37,remote=91.189.94.4,stratum=2,type=u offset=274.726,jitter=449445,when=673i,poll=1024i,reach=377i,delay=143.047 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/multi/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n 83.137.98.96    10.177.80.37     2 u  740 1024  377   54.033  243.426 449514.\n 81.7.16.52      10.177.80.37     2 u  739 1024  377   60.785  232.597 449539.\n 131.188.3.221   10.177.80.37     2 u  783 1024  377  111.820  261.921 449528.\n 5.9.29.107      10.177.80.37     2 u  703 1024  377  205.704  160.406 449602.\n 91.189.94.4     10.177.80.37     2 u  673 1024  377  143.047  274.726 449445.\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/multi/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/no_ref_id/expected.out",
    "content": "ntpq,remote=83.137.98.96,refid=10.177.80.37,stratum=2,type=u when=740i,poll=1024i,reach=377i,delay=54.033,offset=243.426,jitter=449514 0\nntpq,remote=131.188.3.221,refid=10.177.80.37,stratum=2,type=u when=783i,poll=1024i,reach=377i,delay=111.820,offset=261.921,jitter=449528 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/no_ref_id/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n 83.137.98.96    10.177.80.37     2 u  740 1024  377   54.033  243.426 449514.\n 91.189.94.4                      2 u  673 1024  377  143.047  274.726 449445.\n 131.188.3.221   10.177.80.37     2 u  783 1024  377  111.820  261.921 449528.\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/no_ref_id/telegraf.conf",
    "content": "# It is possible for the output of ntqp to be missing the refid column.  This\n# is believed to be http://bugs.ntp.org/show_bug.cgi?id=3484 which is fixed\n# in ntp-4.2.8p12 (included first in Debian Buster).\n[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_headers_as_data/expected.err",
    "content": "field misalignment detected: got column name \"when\" instead of value\nfield misalignment detected: got column name \"poll\" instead of value\nfield misalignment detected: got column name \"reach\" instead of value\nfield misalignment detected: got column name \"delay\" instead of value\nfield misalignment detected: got column name \"offset\" instead of value\nfield misalignment detected: got column name \"jitter\" instead of value"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_headers_as_data/expected.out",
    "content": "ntpq,remote=hostname,refid=.POOL.,stratum=16,type=p poll=64i,reach=0i,delay=0.0,offset=0.0,jitter=0.0 0"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_headers_as_data/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n     remote           refid      st t when poll reach   delay   offset  jitter\n hostname            .POOL.     16 p    -   64    0    0.000   0.000   0.000"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_headers_as_data/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_minus/expected.out",
    "content": "ntpq,remote=0.eu.pool.ntp.o,refid=.POOL.,stratum=16,type=p poll=64i,reach=0i,delay=0.0,offset=0.0,jitter=0.0 0\nntpq,remote=195.201.19.162,refid=187.182.182.166,stratum=3,type=u poll=64i,reach=1i,delay=12.692,offset=1.283,jitter=0.0 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_minus/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n 0.eu.pool.ntp.o .POOL.          16 p    -   64    0    0.000   +0.000   0.000\n 195.201.19.162  187.182.182.166  3 u    -   64    1   12.692   +1.283   0.000\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/pool_when_minus/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers/expected.out",
    "content": "ntpq,source=serverA,refid=10.177.80.46,remote=uschi5-ntp-002.,state_prefix=*,stratum=2,type=u when=101i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\nntpq,source=serverB,refid=10.177.80.37,remote=83.137.98.96,stratum=2,type=u delay=54.033,offset=243.426,jitter=449514,when=740i,poll=1024i,reach=377i 0\nntpq,source=serverB,refid=10.177.80.37,remote=81.7.16.52,stratum=2,type=u reach=377i,delay=60.785,offset=232.597,jitter=449539,when=739i,poll=1024i 0\nntpq,source=serverB,refid=10.177.80.37,remote=131.188.3.221,stratum=2,type=u when=783i,poll=1024i,reach=377i,delay=111.82,offset=261.921,jitter=449528 0\nntpq,source=serverB,refid=10.177.80.37,remote=5.9.29.107,stratum=2,type=u reach=377i,delay=205.704,offset=160.406,jitter=449602,when=703i,poll=1024i 0\nntpq,source=serverB,refid=10.177.80.37,remote=91.189.94.4,stratum=2,type=u offset=274.726,jitter=449445,when=673i,poll=1024i,reach=377i,delay=143.047 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers/input_serverA.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers/input_serverB.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n 83.137.98.96    10.177.80.37     2 u  740 1024  377   54.033  243.426 449514.\n 81.7.16.52      10.177.80.37     2 u  739 1024  377   60.785  232.597 449539.\n 131.188.3.221   10.177.80.37     2 u  783 1024  377  111.820  261.921 449528.\n 5.9.29.107      10.177.80.37     2 u  703 1024  377  205.704  160.406 449602.\n 91.189.94.4     10.177.80.37     2 u  673 1024  377  143.047  274.726 449445.\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    servers = [\"serverA\", \"serverB\"]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/expected.err",
    "content": "[serverC] not authorized"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/expected.out",
    "content": "ntpq,source=serverA,refid=10.177.80.46,remote=uschi5-ntp-002.,state_prefix=*,stratum=2,type=u when=101i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\nntpq,source=serverB,refid=10.177.80.37,remote=83.137.98.96,stratum=2,type=u delay=54.033,offset=243.426,jitter=449514,when=740i,poll=1024i,reach=377i 0\nntpq,source=serverB,refid=10.177.80.37,remote=81.7.16.52,stratum=2,type=u reach=377i,delay=60.785,offset=232.597,jitter=449539,when=739i,poll=1024i 0\nntpq,source=serverB,refid=10.177.80.37,remote=131.188.3.221,stratum=2,type=u when=783i,poll=1024i,reach=377i,delay=111.82,offset=261.921,jitter=449528 0\nntpq,source=serverB,refid=10.177.80.37,remote=5.9.29.107,stratum=2,type=u reach=377i,delay=205.704,offset=160.406,jitter=449602,when=703i,poll=1024i 0\nntpq,source=serverB,refid=10.177.80.37,remote=91.189.94.4,stratum=2,type=u offset=274.726,jitter=449445,when=673i,poll=1024i,reach=377i,delay=143.047 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/input_serverA.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/input_serverB.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n 83.137.98.96    10.177.80.37     2 u  740 1024  377   54.033  243.426 449514.\n 81.7.16.52      10.177.80.37     2 u  739 1024  377   60.785  232.597 449539.\n 131.188.3.221   10.177.80.37     2 u  783 1024  377  111.820  261.921 449528.\n 5.9.29.107      10.177.80.37     2 u  703 1024  377  205.704  160.406 449602.\n 91.189.94.4     10.177.80.37     2 u  673 1024  377  143.047  274.726 449445.\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/input_serverC.err",
    "content": "not authorized"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/servers_one_fail/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    servers = [\"serverA\", \"serverB\", \"serverC\"]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single/telegraf.conf",
    "content": "[[inputs.ntpq]]"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_count/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,poll=256i,reach=5i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_count/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_count/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    reach_format = \"count\""
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_decimal/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,poll=256i,reach=31i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_decimal/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_decimal/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    reach_format = \"decimal\""
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_octal/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,poll=256i,reach=37i,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_octal/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_octal/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    reach_format = \"octal\""
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_ratio/expected.out",
    "content": "ntpq,remote=uschi5-ntp-002.,state_prefix=*,refid=10.177.80.46,stratum=2,type=u when=101i,poll=256i,reach=0.625,delay=51.016,offset=233.010,jitter=17.462 0\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_ratio/input.txt",
    "content": "     remote           refid      st t when poll reach   delay   offset  jitter\n==============================================================================\n*uschi5-ntp-002. 10.177.80.46     2 u  101  256   37   51.016  233.010  17.462\n"
  },
  {
    "path": "plugins/inputs/ntpq/testcases/single_reach_ratio/telegraf.conf",
    "content": "[[inputs.ntpq]]\n    reach_format = \"ratio\""
  },
  {
    "path": "plugins/inputs/nvidia_smi/README.md",
    "content": "# Nvidia System Management Interface (SMI) Input Plugin\n\nThis plugin collects metrics for [NVIDIA GPUs][nvidia] including memory and\nGPU usage, temperature and other, using the\n[NVIDIA System Management Interface][smi].\n\n> [!IMPORTANT]\n> This plugin requires the `nvidia-smi` binary to be installed on the system.\n\n⭐ Telegraf v1.7.0\n🏷️ system, hardware\n💻 all\n\n[nvidia]: https://www.nvidia.com/\n[smi]: https://developer.nvidia.com/nvidia-system-management-interface\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  NOT AVAILABLE\n- `probe`:  Telegraf will call the `Probe() error` method, if available. If the\n            method returns an error, Telegraf disables the plugin but continues\n            processing for all other plugins.\n\n## Configuration\n\n```toml @sample.conf\n# Pulls statistics from nvidia GPUs attached to the host\n[[inputs.nvidia_smi]]\n  ## Optional: path to nvidia-smi binary, defaults \"/usr/bin/nvidia-smi\"\n  ## We will first try to locate the nvidia-smi binary with the explicitly specified value (or default value),\n  ## if it is not found, we will try to locate it on PATH(exec.LookPath), if it is still not found, an error will be returned\n  # bin_path = \"/usr/bin/nvidia-smi\"\n\n  ## Optional: timeout for GPU polling\n  # timeout = \"5s\"\n```\n\n### Linux\n\nOn Linux, `nvidia-smi` is generally located at `/usr/bin/nvidia-smi`\n\n### Windows\n\nOn Windows, `nvidia-smi` is generally located at `C:\\Program Files\\NVIDIA\nCorporation\\NVSMI\\nvidia-smi.exe` On Windows 10, you may also find this located\nhere `C:\\Windows\\System32\\nvidia-smi.exe`\n\nYou'll need to escape the `\\` within the `telegraf.conf` like this: `C:\\\\Program\nFiles\\\\NVIDIA Corporation\\\\NVSMI\\\\nvidia-smi.exe`\n\n## Troubleshooting\n\nCheck the full output by running `nvidia-smi` binary manually.\n\nLinux:\n\n```sh\nsudo -u telegraf -- /usr/bin/nvidia-smi -q -x\n```\n\nWindows:\n\n```sh\n\"C:\\Program Files\\NVIDIA Corporation\\NVSMI\\nvidia-smi.exe\" -q -x\n```\n\nPlease include the output of this command if opening an GitHub issue.\n\n## Metrics\n\n- measurement: `nvidia_smi`\n  - tags\n    - `name` (type of GPU e.g. `GeForce GTX 1070 Ti`)\n    - `compute_mode` (The compute mode of the GPU e.g. `Default`)\n    - `index` (Port index where the GPU is connected to the motherboard e.g. `1`)\n    - `pstate` (Overclocking state for the GPU e.g. `P0`)\n    - `uuid` (A unique identifier for the GPU e.g. `GPU-f9ba66fc-a7f5-94c5-da19-019ef2f9c665`)\n  - fields\n    - `fan_speed` (integer, percentage)\n    - `fbc_stats_session_count` (integer)\n    - `fbc_stats_average_fps` (integer)\n    - `fbc_stats_average_latency` (integer)\n    - `memory_free` (integer, MiB)\n    - `memory_used` (integer, MiB)\n    - `memory_total` (integer, MiB)\n    - `memory_reserved` (integer, MiB)\n    - `retired_pages_multiple_single_bit` (integer)\n    - `retired_pages_double_bit` (integer)\n    - `retired_pages_blacklist` (string)\n    - `retired_pages_pending` (string)\n    - `remapped_rows_correctable` (int)\n    - `remapped_rows_uncorrectable` (int)\n    - `remapped_rows_pending` (string)\n    - `remapped_rows_pending` (string)\n    - `remapped_rows_failure` (string)\n    - `power_draw` (float, W)\n    - `temperature_gpu` (integer, degrees C)\n    - `utilization_gpu` (integer, percentage)\n    - `utilization_memory` (integer, percentage)\n    - `utilization_encoder` (integer, percentage)\n    - `utilization_decoder` (integer, percentage)\n    - `pcie_link_gen_current` (integer)\n    - `pcie_link_width_current` (integer)\n    - `encoder_stats_session_count` (integer)\n    - `encoder_stats_average_fps` (integer)\n    - `encoder_stats_average_latency` (integer)\n    - `clocks_current_graphics` (integer, MHz)\n    - `clocks_current_sm` (integer, MHz)\n    - `clocks_current_memory` (integer, MHz)\n    - `clocks_current_video` (integer, MHz)\n    - `driver_version` (string)\n    - `cuda_version` (string)\n\n## Example Output\n\n```text\nnvidia_smi,compute_mode=Default,host=8218cf,index=0,name=GeForce\\ GTX\\ 1070,pstate=P2,uuid=GPU-823bc202-6279-6f2c-d729-868a30f14d96 fan_speed=100i,memory_free=7563i,memory_total=8112i,memory_used=549i,temperature_gpu=53i,utilization_gpu=100i,utilization_memory=90i 1523991122000000000\nnvidia_smi,compute_mode=Default,host=8218cf,index=1,name=GeForce\\ GTX\\ 1080,pstate=P2,uuid=GPU-f9ba66fc-a7f5-94c5-da19-019ef2f9c665 fan_speed=100i,memory_free=7557i,memory_total=8114i,memory_used=557i,temperature_gpu=50i,utilization_gpu=100i,utilization_memory=85i 1523991122000000000\nnvidia_smi,compute_mode=Default,host=8218cf,index=2,name=GeForce\\ GTX\\ 1080,pstate=P2,uuid=GPU-d4cfc28d-0481-8d07-b81a-ddfc63d74adf fan_speed=100i,memory_free=7557i,memory_total=8114i,memory_used=557i,temperature_gpu=58i,utilization_gpu=100i,utilization_memory=86i 1523991122000000000\n```\n\n## Limitations\n\nNote that there seems to be an issue with getting current memory clock values\nwhen the memory is overclocked.  This may or may not apply to everyone but it's\nconfirmed to be an issue on an EVGA 2080 Ti.\n\n**NOTE:** For use with docker either generate your own custom docker image based\non nvidia/cuda which also installs a telegraf package or use [volume mount\nbinding](https://docs.docker.com/storage/bind-mounts/) to inject the required\nbinary into the docker container. In particular you will need to pass through\nthe /dev/nvidia* devices, the nvidia-smi binary and the nvidia libraries.\nAn minimal docker-compose example of how to do this is:\n\n```yaml\n  telegraf:\n    image: telegraf\n    runtime: nvidia\n    devices:\n      - /dev/nvidiactl:/dev/nvidiactl\n      - /dev/nvidia0:/dev/nvidia0\n    volumes:\n      - ./telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro\n      - /usr/bin/nvidia-smi:/usr/bin/nvidia-smi:ro\n      - /usr/lib/x86_64-linux-gnu/nvidia:/usr/lib/x86_64-linux-gnu/nvidia:ro\n    environment:\n      - LD_PRELOAD=/usr/lib/x86_64-linux-gnu/nvidia/current/libnvidia-ml.so\n```\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/common/setters.go",
    "content": "package common\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// SetTagIfUsed sets those tags whose value is different from empty string.\nfunc SetTagIfUsed(m map[string]string, k, v string) {\n\tif v != \"\" {\n\t\tm[k] = v\n\t}\n}\n\n// SetIfUsed sets those fields whose value is different from empty string.\nfunc SetIfUsed(t string, m map[string]interface{}, k, v string) {\n\tvals := strings.Fields(v)\n\tif len(vals) < 1 {\n\t\treturn\n\t}\n\n\tval := vals[0]\n\tif k == \"pcie_link_width_current\" {\n\t\tval = strings.TrimSuffix(vals[0], \"x\")\n\t}\n\n\tswitch t {\n\tcase \"float\":\n\t\tif val != \"\" {\n\t\t\tf, err := strconv.ParseFloat(val, 64)\n\t\t\tif err == nil {\n\t\t\t\tm[k] = f\n\t\t\t}\n\t\t}\n\tcase \"int\":\n\t\tif val != \"\" && val != \"N/A\" {\n\t\t\ti, err := strconv.Atoi(val)\n\t\t\tif err == nil {\n\t\t\t\tm[k] = i\n\t\t\t}\n\t\t}\n\tcase \"str\":\n\t\tif val != \"\" && val != \"N/A\" {\n\t\t\tm[k] = val\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/nvidia_smi.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage nvidia_smi\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/schema_v11\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/schema_v12\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype NvidiaSMI struct {\n\tBinPath string          `toml:\"bin_path\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tLog     telegraf.Logger `toml:\"-\"`\n\n\tnvidiaSMIArgs []string\n\tignorePlugin  bool\n\tonce          sync.Once\n}\n\nfunc (*NvidiaSMI) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (smi *NvidiaSMI) Start(telegraf.Accumulator) error {\n\tif _, err := os.Stat(smi.BinPath); os.IsNotExist(err) {\n\t\tbinPath, err := exec.LookPath(\"nvidia-smi\")\n\t\tif err != nil {\n\t\t\treturn &internal.StartupError{Err: err}\n\t\t}\n\t\tsmi.BinPath = binPath\n\t}\n\n\treturn nil\n}\n\nfunc (*NvidiaSMI) Stop() {}\n\nfunc (smi *NvidiaSMI) Probe() error {\n\t// Construct and execute metrics query\n\t_, err := internal.CombinedOutputTimeout(exec.Command(smi.BinPath, smi.nvidiaSMIArgs...), time.Duration(smi.Timeout))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"calling %q failed: %w\", smi.BinPath, err)\n\t}\n\treturn nil\n}\n\nfunc (smi *NvidiaSMI) Gather(acc telegraf.Accumulator) error {\n\tif smi.ignorePlugin {\n\t\treturn nil\n\t}\n\n\t// Construct and execute metrics query\n\tdata, err := internal.CombinedOutputTimeout(exec.Command(smi.BinPath, smi.nvidiaSMIArgs...), time.Duration(smi.Timeout))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"calling %q failed: %w\", smi.BinPath, err)\n\t}\n\n\t// Parse the output\n\treturn smi.parse(acc, data)\n}\n\nfunc (smi *NvidiaSMI) parse(acc telegraf.Accumulator, data []byte) error {\n\tschema := \"v11\"\n\n\tbuf := bytes.NewBuffer(data)\n\tdecoder := xml.NewDecoder(buf)\n\tfor {\n\t\ttoken, err := decoder.Token()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"reading token failed: %w\", err)\n\t\t}\n\t\td, ok := token.(xml.Directive)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tdirective := string(d)\n\t\tif !strings.HasPrefix(directive, \"DOCTYPE\") {\n\t\t\tcontinue\n\t\t}\n\t\tparts := strings.Split(directive, \" \")\n\t\ts := strings.Trim(parts[len(parts)-1], \"\\\" \")\n\t\tif strings.HasPrefix(s, \"nvsmi_device_\") && strings.HasSuffix(s, \".dtd\") {\n\t\t\tschema = strings.TrimSuffix(strings.TrimPrefix(s, \"nvsmi_device_\"), \".dtd\")\n\t\t} else {\n\t\t\tsmi.Log.Debugf(\"Cannot find schema version in %q\", directive)\n\t\t}\n\t\tbreak\n\t}\n\tsmi.Log.Debugf(\"Using schema version in %s\", schema)\n\n\tswitch schema {\n\tcase \"v10\", \"v11\":\n\t\treturn schema_v11.Parse(acc, data)\n\tcase \"v12\":\n\t\treturn schema_v12.Parse(acc, data)\n\t}\n\n\tsmi.once.Do(func() {\n\t\tsmi.Log.Warnf(`Unknown schema version %q, using latest know schema for parsing.\n\t\tPlease report this as an issue to https://github.com/influxdata/telegraf together\n\t\twith a sample output of 'nvidia_smi -q -x'!`, schema)\n\t})\n\treturn schema_v12.Parse(acc, data)\n}\n\nfunc init() {\n\tinputs.Add(\"nvidia_smi\", func() telegraf.Input {\n\t\treturn &NvidiaSMI{\n\t\t\tBinPath:       \"/usr/bin/nvidia-smi\",\n\t\t\tTimeout:       config.Duration(5 * time.Second),\n\t\t\tnvidiaSMIArgs: []string{\"-q\", \"-x\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/nvidia_smi_test.go",
    "content": "package nvidia_smi\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestProbe(t *testing.T) {\n\tvar binPath string\n\tvar nvidiaSMIArgsPrefix []string\n\tif runtime.GOOS == \"windows\" {\n\t\tbinPath = `C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`\n\t\tnvidiaSMIArgsPrefix = []string{\"-Command\"}\n\t} else {\n\t\tbinPath = \"/bin/bash\"\n\t\tnvidiaSMIArgsPrefix = []string{\"-c\"}\n\t}\n\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\targs        string\n\t\texpectError bool\n\t}{\n\t\t{\n\t\t\tname:        \"probe success\",\n\t\t\targs:        \"exit 0\",\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname:        \"probe error\",\n\t\t\targs:        \"exit 1\",\n\t\t\texpectError: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &NvidiaSMI{\n\t\t\t\tBinPath:       binPath,\n\t\t\t\tnvidiaSMIArgs: append(nvidiaSMIArgsPrefix, tt.args),\n\t\t\t\tLog:           &testutil.Logger{},\n\t\t\t\tTimeout:       config.Duration(5 * time.Second),\n\t\t\t}\n\t\t\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\t\t\tName:                 \"nvidia_smi\",\n\t\t\t\tStartupErrorBehavior: \"probe\",\n\t\t\t})\n\t\t\terr := model.Probe()\n\t\t\tif tt.expectError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestErrorBehaviorDefault(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &NvidiaSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName: \"nvidia_smi\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorError(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &NvidiaSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"nvidia_smi\",\n\t\tStartupErrorBehavior: \"error\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorRetry(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &NvidiaSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"nvidia_smi\",\n\t\tStartupErrorBehavior: \"retry\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.NotErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestErrorBehaviorIgnore(t *testing.T) {\n\t// make sure we can't find nvidia-smi in $PATH somewhere\n\tos.Unsetenv(\"PATH\")\n\tplugin := &NvidiaSMI{\n\t\tBinPath: \"/random/non-existent/path\",\n\t\tLog:     &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(plugin, &models.InputConfig{\n\t\tName:                 \"nvidia_smi\",\n\t\tStartupErrorBehavior: \"ignore\",\n\t})\n\trequire.NoError(t, model.Init())\n\n\tvar acc testutil.Accumulator\n\tvar ferr *internal.FatalError\n\trequire.ErrorAs(t, model.Start(&acc), &ferr)\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n}\n\nfunc TestGatherValidXML(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tfilename string\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname:     \"GeForce GTX 1070 Ti\",\n\t\t\tfilename: \"gtx-1070-ti.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\":         \"GeForce GTX 1070 Ti\",\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-f9ba66fc-a7f5-94c5-da19-019ef2f9c665\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       135,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             135,\n\t\t\t\t\t\t\"clocks_current_video\":          405,\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fan_speed\":                     100,\n\t\t\t\t\t\t\"memory_free\":                   4054,\n\t\t\t\t\t\t\"memory_total\":                  4096,\n\t\t\t\t\t\t\"memory_used\":                   42,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"temperature_gpu\":               39,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"GeForce GTX 1660 Ti\",\n\t\t\tfilename: \"gtx-1660-ti.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"Graphics Device\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-304a277d-3545-63b8-3a36-dfde3c992989\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       300,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             300,\n\t\t\t\t\t\t\"clocks_current_video\":          540,\n\t\t\t\t\t\t\"cuda_version\":                  \"10.1\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"418.43\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     0,\n\t\t\t\t\t\t\"memory_free\":                   5912,\n\t\t\t\t\t\t\"memory_total\":                  5912,\n\t\t\t\t\t\t\"memory_used\":                   0,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"power_draw\":                    8.93,\n\t\t\t\t\t\t\"power_limit\":                   130.0,\n\t\t\t\t\t\t\"temperature_gpu\":               40,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            1,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"vbios_version\":                 \"90.16.25.00.4C\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Quadro P400\",\n\t\t\tfilename: \"quadro-p400.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"Quadro P400\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-8f750be4-dfbc-23b9-b33f-da729a536494\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       139,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             139,\n\t\t\t\t\t\t\"clocks_current_video\":          544,\n\t\t\t\t\t\t\"cuda_version\":                  \"10.1\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"418.43\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     34,\n\t\t\t\t\t\t\"memory_free\":                   1998,\n\t\t\t\t\t\t\"memory_total\":                  1998,\n\t\t\t\t\t\t\"memory_used\":                   0,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"serial\":                        \"0424418054852\",\n\t\t\t\t\t\t\"temperature_gpu\":               33,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            3,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"vbios_version\":                 \"86.07.3B.00.4A\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Quadro P2000\",\n\t\t\tfilename: \"quadro-p2000-v12.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"arch\":         \"Pascal\",\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"Quadro P2000\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-396caaed-39ca-3199-2e68-717cdb786ec6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\n\t\t\t\t\t\t\"clocks_current_graphics\":       139,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             139,\n\t\t\t\t\t\t\"clocks_current_video\":          544,\n\t\t\t\t\t\t\"cuda_version\":                  \"12.0\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"525.125.06\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     46,\n\t\t\t\t\t\t\"memory_free\":                   5051,\n\t\t\t\t\t\t\"memory_reserved\":               66,\n\t\t\t\t\t\t\"memory_total\":                  5120,\n\t\t\t\t\t\t\"memory_used\":                   1,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       8,\n\t\t\t\t\t\t\"power_draw\":                    4.61,\n\t\t\t\t\t\t\"power_limit\":                   75.0,\n\t\t\t\t\t\t\"serial\":                        \"0322218049033\",\n\t\t\t\t\t\t\"temperature_gpu\":               34,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            0,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"vbios_version\":                 \"86.06.3F.00.30\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"Tesla T4\",\n\t\t\tfilename: \"tesla-t4.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"Tesla T4\",\n\t\t\t\t\t\t\"pstate\":       \"P0\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-d37e67a5-91dd-3774-a5cb-99096249601a\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":           585,\n\t\t\t\t\t\t\"clocks_current_memory\":             5000,\n\t\t\t\t\t\t\"clocks_current_sm\":                 585,\n\t\t\t\t\t\t\"clocks_current_video\":              810,\n\t\t\t\t\t\t\"cuda_version\":                      \"11.7\",\n\t\t\t\t\t\t\"current_ecc\":                       \"Enabled\",\n\t\t\t\t\t\t\"display_active\":                    \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                      \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                    \"515.105.01\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":         0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\":     0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":       0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":             0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":         0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":           0,\n\t\t\t\t\t\t\"power_draw\":                        26.78,\n\t\t\t\t\t\t\"power_limit\":                       70.0,\n\t\t\t\t\t\t\"memory_free\":                       13939,\n\t\t\t\t\t\t\"memory_total\":                      15360,\n\t\t\t\t\t\t\"memory_used\":                       1032,\n\t\t\t\t\t\t\"memory_reserved\":                   388,\n\t\t\t\t\t\t\"retired_pages_multiple_single_bit\": 0,\n\t\t\t\t\t\t\"retired_pages_double_bit\":          0,\n\t\t\t\t\t\t\"retired_pages_blacklist\":           \"No\",\n\t\t\t\t\t\t\"retired_pages_pending\":             \"No\",\n\t\t\t\t\t\t\"pcie_link_gen_current\":             3,\n\t\t\t\t\t\t\"pcie_link_width_current\":           8,\n\t\t\t\t\t\t\"serial\":                            \"0000000000000\",\n\t\t\t\t\t\t\"temperature_gpu\":                   40,\n\t\t\t\t\t\t\"utilization_gpu\":                   0,\n\t\t\t\t\t\t\"utilization_memory\":                0,\n\t\t\t\t\t\t\"utilization_encoder\":               0,\n\t\t\t\t\t\t\"utilization_decoder\":               0,\n\t\t\t\t\t\t\"vbios_version\":                     \"90.04.84.00.06\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"A10G\",\n\t\t\tfilename: \"a10g.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"NVIDIA A10G\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-9a9a6c50-2a47-2f51-a902-b82c3b127e94\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       210,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             210,\n\t\t\t\t\t\t\"clocks_current_video\":          555,\n\t\t\t\t\t\t\"cuda_version\":                  \"11.7\",\n\t\t\t\t\t\t\"current_ecc\":                   \"Enabled\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"515.105.01\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     0,\n\t\t\t\t\t\t\"power_draw\":                    25.58,\n\t\t\t\t\t\t\"power_limit\":                   300.0,\n\t\t\t\t\t\t\"memory_free\":                   22569,\n\t\t\t\t\t\t\"memory_total\":                  23028,\n\t\t\t\t\t\t\"memory_used\":                   22,\n\t\t\t\t\t\t\"memory_reserved\":               435,\n\t\t\t\t\t\t\"remapped_rows_correctable\":     0,\n\t\t\t\t\t\t\"remapped_rows_uncorrectable\":   0,\n\t\t\t\t\t\t\"remapped_rows_pending\":         \"No\",\n\t\t\t\t\t\t\"remapped_rows_failure\":         \"No\",\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       8,\n\t\t\t\t\t\t\"serial\":                        \"0000000000000\",\n\t\t\t\t\t\t\"temperature_gpu\":               17,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            0,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"vbios_version\":                 \"94.02.75.00.01\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"RTC 3060 schema v12\",\n\t\t\tfilename: \"rtx-3060-v12.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"NVIDIA GeForce RTX 3060\",\n\t\t\t\t\t\t\"arch\":         \"Ampere\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-d6889ff6-2523-9142-ca3c-1ca3f396a625\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       210,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             210,\n\t\t\t\t\t\t\"clocks_current_video\":          555,\n\t\t\t\t\t\t\"cuda_version\":                  \"12.8\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"570.124.04\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     0,\n\t\t\t\t\t\t\"power_draw\":                    11.63,\n\t\t\t\t\t\t\"memory_free\":                   11806,\n\t\t\t\t\t\t\"memory_total\":                  12288,\n\t\t\t\t\t\t\"memory_used\":                   116,\n\t\t\t\t\t\t\"memory_reserved\":               368,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"temperature_gpu\":               42,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_jpeg\":              0,\n\t\t\t\t\t\t\"utilization_memory\":            0,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"utilization_ofa\":               0,\n\t\t\t\t\t\t\"vbios_version\":                 \"94.04.71.00.69\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"RTC 3080 schema v12\",\n\t\t\tfilename: \"rtx-3080-v12.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"NVIDIA GeForce RTX 3080\",\n\t\t\t\t\t\t\"arch\":         \"Ampere\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-19d6d965-2acc-f646-00f8-4c76979aabb4\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       210,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             210,\n\t\t\t\t\t\t\"clocks_current_video\":          555,\n\t\t\t\t\t\t\"cuda_version\":                  \"12.2\",\n\t\t\t\t\t\t\"display_active\":                \"Enabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Enabled\",\n\t\t\t\t\t\t\"driver_version\":                \"536.40\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     0,\n\t\t\t\t\t\t\"power_draw\":                    22.78,\n\t\t\t\t\t\t\"memory_free\":                   8938,\n\t\t\t\t\t\t\"memory_total\":                  10240,\n\t\t\t\t\t\t\"memory_used\":                   1128,\n\t\t\t\t\t\t\"memory_reserved\":               173,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         4,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"temperature_gpu\":               31,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_jpeg\":              0,\n\t\t\t\t\t\t\"utilization_memory\":            37,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"utilization_ofa\":               0,\n\t\t\t\t\t\t\"vbios_version\":                 \"94.02.71.40.72\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\": \"/usr/lib/Xorg\",\n\t\t\t\t\t\t\"type\": \"G\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid\":         int64(835),\n\t\t\t\t\t\t\"used_memory\": int64(550),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\": \"/usr/bin/gnome-shell\",\n\t\t\t\t\t\t\"type\": \"G\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid\":         int64(1481),\n\t\t\t\t\t\t\"used_memory\": int64(18),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\": \"/opt/microsoft/msedge/msedge --type=gpu-process \" +\n\t\t\t\t\t\t\t\"--crashpad-handler-pid=2176 --enable-crash-reporter=, \" +\n\t\t\t\t\t\t\t\"--change-stack-guard-on-fork=enable --gpu-preferences=\" +\n\t\t\t\t\t\t\t\"WAAAAAAAAAAgAAAEAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAAAAA\" +\n\t\t\t\t\t\t\t\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAGAAAAAAAAAAYAA\" +\n\t\t\t\t\t\t\t\"AAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== --shared-files \" +\n\t\t\t\t\t\t\t\"--field-trial-handle=0,i,3110290512380155730,\" +\n\t\t\t\t\t\t\t\"7457693378709978105,262144 --variations-seed-version\",\n\t\t\t\t\t\t\"type\": \"G\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid\":         int64(2214),\n\t\t\t\t\t\t\"used_memory\": int64(79),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\": \"/usr/lib/firefox/firefox\",\n\t\t\t\t\t\t\"type\": \"G\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid\":         int64(4044),\n\t\t\t\t\t\t\"used_memory\": int64(541),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_process\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"name\": \"/opt/visual-studio-code/code --type=gpu-process \" +\n\t\t\t\t\t\t\t\"--enable-crash-reporter=6f39585a-ecc4-42e2-b899-9456cbe56b44\" +\n\t\t\t\t\t\t\t\",no_channel --user-data-dir=/home/powersj/.config/Code \" +\n\t\t\t\t\t\t\t\"--gpu-preferences=WAAAAAAAAAAgAAAEAAAAAAAAAAAAAAAAAABg\" +\n\t\t\t\t\t\t\t\"AAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\" +\n\t\t\t\t\t\t\t\"ABAAAAGAAAAAAAAAAYAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== \" +\n\t\t\t\t\t\t\t\"--shared-files --field-trial-handle=0,i,685715063932313394,\" +\n\t\t\t\t\t\t\t\"4769839452661094675,262144 --disable-features=\" +\n\t\t\t\t\t\t\t\"CalculateNativeWinOcclusion,SpareRendererForSitePerProcess\",\n\t\t\t\t\t\t\"type\": \"G\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid\":         int64(42416),\n\t\t\t\t\t\t\"used_memory\": int64(159),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"RTC 3090 schema v12\",\n\t\t\tfilename: \"rtx-3090-v12.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"NVIDIA GeForce RTX 3090\",\n\t\t\t\t\t\t\"arch\":         \"Ampere\",\n\t\t\t\t\t\t\"pstate\":       \"P8\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-12345678-aaaa-bbbb-cccc-0123456789ab\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       0,\n\t\t\t\t\t\t\"clocks_current_memory\":         405,\n\t\t\t\t\t\t\"clocks_current_sm\":             0,\n\t\t\t\t\t\t\"clocks_current_video\":          555,\n\t\t\t\t\t\t\"cuda_version\":                  \"12.0\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Disabled\",\n\t\t\t\t\t\t\"driver_version\":                \"525.147.05\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"fan_speed\":                     0,\n\t\t\t\t\t\t\"power_draw\":                    27.23,\n\t\t\t\t\t\t\"power_limit\":                   200.0,\n\t\t\t\t\t\t\"memory_free\":                   24258,\n\t\t\t\t\t\t\"memory_total\":                  24576,\n\t\t\t\t\t\t\"memory_used\":                   1,\n\t\t\t\t\t\t\"memory_reserved\":               316,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         1,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"temperature_gpu\":               37,\n\t\t\t\t\t\t\"utilization_gpu\":               0,\n\t\t\t\t\t\t\"utilization_memory\":            0,\n\t\t\t\t\t\t\"utilization_encoder\":           0,\n\t\t\t\t\t\t\"utilization_decoder\":           0,\n\t\t\t\t\t\t\"vbios_version\":                 \"94.02.71.40.72\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"A100-SXM4 schema v12\",\n\t\t\tfilename: \"a100-sxm4-v12.xml\",\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\": \"Default\",\n\t\t\t\t\t\t\"index\":        \"0\",\n\t\t\t\t\t\t\"name\":         \"NVIDIA A100-SXM4-80GB\",\n\t\t\t\t\t\t\"arch\":         \"Ampere\",\n\t\t\t\t\t\t\"pstate\":       \"P0\",\n\t\t\t\t\t\t\"uuid\":         \"GPU-513536b6-7d19-9063-b049-1e69664bb298\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"clocks_current_graphics\":       1275,\n\t\t\t\t\t\t\"clocks_current_memory\":         1593,\n\t\t\t\t\t\t\"clocks_current_sm\":             1275,\n\t\t\t\t\t\t\"clocks_current_video\":          1275,\n\t\t\t\t\t\t\"cuda_version\":                  \"12.2\",\n\t\t\t\t\t\t\"current_ecc\":                   \"Enabled\",\n\t\t\t\t\t\t\"display_active\":                \"Disabled\",\n\t\t\t\t\t\t\"display_mode\":                  \"Enabled\",\n\t\t\t\t\t\t\"driver_version\":                \"535.54.03\",\n\t\t\t\t\t\t\"encoder_stats_average_fps\":     0,\n\t\t\t\t\t\t\"encoder_stats_average_latency\": 0,\n\t\t\t\t\t\t\"encoder_stats_session_count\":   0,\n\t\t\t\t\t\t\"fbc_stats_average_fps\":         0,\n\t\t\t\t\t\t\"fbc_stats_average_latency\":     0,\n\t\t\t\t\t\t\"fbc_stats_session_count\":       0,\n\t\t\t\t\t\t\"power_draw\":                    67.03,\n\t\t\t\t\t\t\"memory_free\":                   80999,\n\t\t\t\t\t\t\"memory_total\":                  81920,\n\t\t\t\t\t\t\"memory_used\":                   50,\n\t\t\t\t\t\t\"memory_reserved\":               869,\n\t\t\t\t\t\t\"pcie_link_gen_current\":         4,\n\t\t\t\t\t\t\"pcie_link_width_current\":       16,\n\t\t\t\t\t\t\"serial\":                        \"1650522003820\",\n\t\t\t\t\t\t\"temperature_gpu\":               27,\n\t\t\t\t\t\t\"vbios_version\":                 \"92.00.36.00.02\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_mig\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\":  \"Default\",\n\t\t\t\t\t\t\"index\":         \"0\",\n\t\t\t\t\t\t\"name\":          \"NVIDIA A100-SXM4-80GB\",\n\t\t\t\t\t\t\"arch\":          \"Ampere\",\n\t\t\t\t\t\t\"pstate\":        \"P0\",\n\t\t\t\t\t\t\"uuid\":          \"GPU-513536b6-7d19-9063-b049-1e69664bb298\",\n\t\t\t\t\t\t\"compute_index\": \"0\",\n\t\t\t\t\t\t\"gpu_index\":     \"3\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"memory_bar1_free\":   32767,\n\t\t\t\t\t\t\"memory_bar1_total\":  32767,\n\t\t\t\t\t\t\"memory_bar1_used\":   0,\n\t\t\t\t\t\t\"memory_fb_free\":     19955,\n\t\t\t\t\t\t\"memory_fb_reserved\": 0,\n\t\t\t\t\t\t\"memory_fb_total\":    19968,\n\t\t\t\t\t\t\"memory_fb_used\":     12,\n\t\t\t\t\t\t\"sram_uncorrectable\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_mig\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\":  \"Default\",\n\t\t\t\t\t\t\"index\":         \"1\",\n\t\t\t\t\t\t\"name\":          \"NVIDIA A100-SXM4-80GB\",\n\t\t\t\t\t\t\"arch\":          \"Ampere\",\n\t\t\t\t\t\t\"pstate\":        \"P0\",\n\t\t\t\t\t\t\"uuid\":          \"GPU-513536b6-7d19-9063-b049-1e69664bb298\",\n\t\t\t\t\t\t\"compute_index\": \"0\",\n\t\t\t\t\t\t\"gpu_index\":     \"4\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"memory_bar1_free\":   32767,\n\t\t\t\t\t\t\"memory_bar1_total\":  32767,\n\t\t\t\t\t\t\"memory_bar1_used\":   0,\n\t\t\t\t\t\t\"memory_fb_free\":     19955,\n\t\t\t\t\t\t\"memory_fb_reserved\": 0,\n\t\t\t\t\t\t\"memory_fb_total\":    19968,\n\t\t\t\t\t\t\"memory_fb_used\":     12,\n\t\t\t\t\t\t\"sram_uncorrectable\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_mig\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\":  \"Default\",\n\t\t\t\t\t\t\"index\":         \"2\",\n\t\t\t\t\t\t\"name\":          \"NVIDIA A100-SXM4-80GB\",\n\t\t\t\t\t\t\"arch\":          \"Ampere\",\n\t\t\t\t\t\t\"pstate\":        \"P0\",\n\t\t\t\t\t\t\"uuid\":          \"GPU-513536b6-7d19-9063-b049-1e69664bb298\",\n\t\t\t\t\t\t\"compute_index\": \"0\",\n\t\t\t\t\t\t\"gpu_index\":     \"5\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"memory_bar1_free\":   32767,\n\t\t\t\t\t\t\"memory_bar1_total\":  32767,\n\t\t\t\t\t\t\"memory_bar1_used\":   0,\n\t\t\t\t\t\t\"memory_fb_free\":     19955,\n\t\t\t\t\t\t\"memory_fb_reserved\": 0,\n\t\t\t\t\t\t\"memory_fb_total\":    19968,\n\t\t\t\t\t\t\"memory_fb_used\":     12,\n\t\t\t\t\t\t\"sram_uncorrectable\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"nvidia_smi_mig\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"compute_mode\":  \"Default\",\n\t\t\t\t\t\t\"index\":         \"3\",\n\t\t\t\t\t\t\"name\":          \"NVIDIA A100-SXM4-80GB\",\n\t\t\t\t\t\t\"arch\":          \"Ampere\",\n\t\t\t\t\t\t\"pstate\":        \"P0\",\n\t\t\t\t\t\t\"uuid\":          \"GPU-513536b6-7d19-9063-b049-1e69664bb298\",\n\t\t\t\t\t\t\"compute_index\": \"0\",\n\t\t\t\t\t\t\"gpu_index\":     \"6\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"memory_bar1_free\":   32767,\n\t\t\t\t\t\t\"memory_bar1_total\":  32767,\n\t\t\t\t\t\t\"memory_bar1_used\":   0,\n\t\t\t\t\t\t\"memory_fb_free\":     19955,\n\t\t\t\t\t\t\"memory_fb_reserved\": 0,\n\t\t\t\t\t\t\"memory_fb_total\":    19968,\n\t\t\t\t\t\t\"memory_fb_used\":     12,\n\t\t\t\t\t\t\"sram_uncorrectable\": 0,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1689872450, 0)),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\toctets, err := os.ReadFile(filepath.Join(\"testdata\", tt.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tplugin := &NvidiaSMI{Log: &testutil.Logger{}}\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.parse(&acc, octets))\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/sample.conf",
    "content": "# Pulls statistics from nvidia GPUs attached to the host\n[[inputs.nvidia_smi]]\n  ## Optional: path to nvidia-smi binary, defaults \"/usr/bin/nvidia-smi\"\n  ## We will first try to locate the nvidia-smi binary with the explicitly specified value (or default value),\n  ## if it is not found, we will try to locate it on PATH(exec.LookPath), if it is still not found, an error will be returned\n  # bin_path = \"/usr/bin/nvidia-smi\"\n\n  ## Optional: timeout for GPU polling\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/schema_v11/parser.go",
    "content": "package schema_v11\n\nimport (\n\t\"encoding/xml\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/common\"\n)\n\n// Parse parses the XML-encoded data from nvidia-smi and adds measurements.\nfunc Parse(acc telegraf.Accumulator, buf []byte) error {\n\tvar s smi\n\tif err := xml.Unmarshal(buf, &s); err != nil {\n\t\treturn err\n\t}\n\n\tfor i := range s.GPU {\n\t\tgpu := &s.GPU[i]\n\n\t\ttags := map[string]string{\n\t\t\t\"index\": strconv.Itoa(i),\n\t\t}\n\t\tfields := make(map[string]interface{}, 39)\n\n\t\tcommon.SetTagIfUsed(tags, \"pstate\", gpu.PState)\n\t\tcommon.SetTagIfUsed(tags, \"name\", gpu.ProdName)\n\t\tcommon.SetTagIfUsed(tags, \"uuid\", gpu.UUID)\n\t\tcommon.SetTagIfUsed(tags, \"compute_mode\", gpu.ComputeMode)\n\n\t\tcommon.SetIfUsed(\"str\", fields, \"driver_version\", s.DriverVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"cuda_version\", s.CUDAVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"serial\", gpu.Serial)\n\t\tcommon.SetIfUsed(\"str\", fields, \"vbios_version\", gpu.VbiosVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"display_active\", gpu.DisplayActive)\n\t\tcommon.SetIfUsed(\"str\", fields, \"display_mode\", gpu.DisplayMode)\n\t\tcommon.SetIfUsed(\"str\", fields, \"current_ecc\", gpu.EccMode.CurrentEcc)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fan_speed\", gpu.FanSpeed)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_total\", gpu.Memory.Total)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_used\", gpu.Memory.Used)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_free\", gpu.Memory.Free)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_reserved\", gpu.Memory.Reserved)\n\t\tcommon.SetIfUsed(\"int\", fields, \"retired_pages_multiple_single_bit\", gpu.RetiredPages.MultipleSingleBit.Count)\n\t\tcommon.SetIfUsed(\"int\", fields, \"retired_pages_double_bit\", gpu.RetiredPages.DoubleBit.Count)\n\t\tcommon.SetIfUsed(\"str\", fields, \"retired_pages_blacklist\", gpu.RetiredPages.PendingBlacklist)\n\t\tcommon.SetIfUsed(\"str\", fields, \"retired_pages_pending\", gpu.RetiredPages.PendingRetirement)\n\t\tcommon.SetIfUsed(\"int\", fields, \"remapped_rows_correctable\", gpu.RemappedRows.Correctable)\n\t\tcommon.SetIfUsed(\"int\", fields, \"remapped_rows_uncorrectable\", gpu.RemappedRows.Uncorrectable)\n\t\tcommon.SetIfUsed(\"str\", fields, \"remapped_rows_pending\", gpu.RemappedRows.Pending)\n\t\tcommon.SetIfUsed(\"str\", fields, \"remapped_rows_failure\", gpu.RemappedRows.Failure)\n\t\tcommon.SetIfUsed(\"int\", fields, \"temperature_gpu\", gpu.Temp.GPUTemp)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_gpu\", gpu.Utilization.GPU)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_memory\", gpu.Utilization.Memory)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_encoder\", gpu.Utilization.Encoder)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_decoder\", gpu.Utilization.Decoder)\n\t\tcommon.SetIfUsed(\"int\", fields, \"pcie_link_gen_current\", gpu.PCI.LinkInfo.PCIEGen.CurrentLinkGen)\n\t\tcommon.SetIfUsed(\"int\", fields, \"pcie_link_width_current\", gpu.PCI.LinkInfo.LinkWidth.CurrentLinkWidth)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_session_count\", gpu.Encoder.SessionCount)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_average_fps\", gpu.Encoder.AverageFPS)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_average_latency\", gpu.Encoder.AverageLatency)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_session_count\", gpu.FBC.SessionCount)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_average_fps\", gpu.FBC.AverageFPS)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_average_latency\", gpu.FBC.AverageLatency)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_graphics\", gpu.Clocks.Graphics)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_sm\", gpu.Clocks.SM)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_memory\", gpu.Clocks.Memory)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_video\", gpu.Clocks.Video)\n\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_draw\", gpu.Power.PowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_limit\", gpu.Power.PowerLimit)\n\t\tacc.AddFields(\"nvidia_smi\", fields, tags)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/schema_v11/types.go",
    "content": "package schema_v11\n\n// smi defines the structure for the output of _nvidia-smi -q -x_.\ntype smi struct {\n\tGPU           []gpu  `xml:\"gpu\"`\n\tDriverVersion string `xml:\"driver_version\"`\n\tCUDAVersion   string `xml:\"cuda_version\"`\n}\n\n// gpu defines the structure of the GPU portion of the smi output.\ntype gpu struct {\n\tClocks        clockStats         `xml:\"clocks\"`\n\tComputeMode   string             `xml:\"compute_mode\"`\n\tDisplayActive string             `xml:\"display_active\"`\n\tDisplayMode   string             `xml:\"display_mode\"`\n\tEccMode       eccMode            `xml:\"ecc_mode\"`\n\tEncoder       encoderStats       `xml:\"encoder_stats\"`\n\tFanSpeed      string             `xml:\"fan_speed\"` // int\n\tFBC           fbcStats           `xml:\"fbc_stats\"`\n\tMemory        memoryStats        `xml:\"fb_memory_usage\"`\n\tPCI           pic                `xml:\"pci\"`\n\tPower         powerReadings      `xml:\"power_readings\"`\n\tProdName      string             `xml:\"product_name\"`\n\tPState        string             `xml:\"performance_state\"`\n\tRemappedRows  memoryRemappedRows `xml:\"remapped_rows\"`\n\tRetiredPages  memoryRetiredPages `xml:\"retired_pages\"`\n\tSerial        string             `xml:\"serial\"`\n\tTemp          tempStats          `xml:\"temperature\"`\n\tUtilization   utilizationStats   `xml:\"utilization\"`\n\tUUID          string             `xml:\"uuid\"`\n\tVbiosVersion  string             `xml:\"vbios_version\"`\n}\n\n// eccMode defines the structure of the ecc portions in the smi output.\ntype eccMode struct {\n\tCurrentEcc string `xml:\"current_ecc\"` // Enabled, Disabled, N/A\n\tPendingEcc string `xml:\"pending_ecc\"` // Enabled, Disabled, N/A\n}\n\n// memoryStats defines the structure of the memory portions in the smi output.\ntype memoryStats struct {\n\tTotal    string `xml:\"total\"`    // int\n\tUsed     string `xml:\"used\"`     // int\n\tFree     string `xml:\"free\"`     // int\n\tReserved string `xml:\"reserved\"` // int\n}\n\n// memoryRetiredPages defines the structure of the retired pages portions in the smi output.\ntype memoryRetiredPages struct {\n\tMultipleSingleBit struct {\n\t\tCount string `xml:\"retired_count\"` // int\n\t} `xml:\"multiple_single_bit_retirement\"`\n\tDoubleBit struct {\n\t\tCount string `xml:\"retired_count\"` // int\n\t} `xml:\"double_bit_retirement\"`\n\tPendingBlacklist  string `xml:\"pending_blacklist\"`  // Yes/No\n\tPendingRetirement string `xml:\"pending_retirement\"` // Yes/No\n}\n\n// memoryRemappedRows defines the structure of the remapped rows portions in the smi output.\ntype memoryRemappedRows struct {\n\tCorrectable   string `xml:\"remapped_row_corr\"`    // int\n\tUncorrectable string `xml:\"remapped_row_unc\"`     // int\n\tPending       string `xml:\"remapped_row_pending\"` // Yes/No\n\tFailure       string `xml:\"remapped_row_failure\"` // Yes/No\n}\n\n// tempStats defines the structure of the temperature portion of the smi output.\ntype tempStats struct {\n\tGPUTemp string `xml:\"gpu_temp\"` // int\n}\n\n// utilizationStats defines the structure of the utilization portion of the smi output.\ntype utilizationStats struct {\n\tGPU     string `xml:\"gpu_util\"`     // int\n\tMemory  string `xml:\"memory_util\"`  // int\n\tEncoder string `xml:\"encoder_util\"` // int\n\tDecoder string `xml:\"decoder_util\"` // int\n}\n\n// powerReadings defines the structure of the power_readings portion of the smi output.\ntype powerReadings struct {\n\tPowerDraw  string `xml:\"power_draw\"`  // float\n\tPowerLimit string `xml:\"power_limit\"` // float\n}\n\n// pic defines the structure of the pci portion of the smi output.\ntype pic struct {\n\tLinkInfo struct {\n\t\tPCIEGen struct {\n\t\t\tCurrentLinkGen string `xml:\"current_link_gen\"` // int\n\t\t} `xml:\"pcie_gen\"`\n\t\tLinkWidth struct {\n\t\t\tCurrentLinkWidth string `xml:\"current_link_width\"` // int\n\t\t} `xml:\"link_widths\"`\n\t} `xml:\"pci_gpu_link_info\"`\n}\n\n// encoderStats defines the structure of the encoder_stats portion of the smi output.\ntype encoderStats struct {\n\tSessionCount   string `xml:\"session_count\"`   // int\n\tAverageFPS     string `xml:\"average_fps\"`     // int\n\tAverageLatency string `xml:\"average_latency\"` // int\n}\n\n// fbcStats defines the structure of the fbc_stats portion of the smi output.\ntype fbcStats struct {\n\tSessionCount   string `xml:\"session_count\"`   // int\n\tAverageFPS     string `xml:\"average_fps\"`     // int\n\tAverageLatency string `xml:\"average_latency\"` // int\n}\n\n// clockStats defines the structure of the clocks portion of the smi output.\ntype clockStats struct {\n\tGraphics string `xml:\"graphics_clock\"` // int\n\tSM       string `xml:\"sm_clock\"`       // int\n\tMemory   string `xml:\"mem_clock\"`      // int\n\tVideo    string `xml:\"video_clock\"`    // int\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/schema_v12/parser.go",
    "content": "package schema_v12\n\nimport (\n\t\"encoding/xml\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/nvidia_smi/common\"\n)\n\n// Parse parses the XML-encoded data from nvidia-smi and adds measurements.\nfunc Parse(acc telegraf.Accumulator, buf []byte) error {\n\tvar s smi\n\tif err := xml.Unmarshal(buf, &s); err != nil {\n\t\treturn err\n\t}\n\n\ttimestamp := time.Now()\n\tif s.Timestamp != \"\" {\n\t\tif t, err := time.ParseInLocation(time.ANSIC, s.Timestamp, time.Local); err == nil {\n\t\t\ttimestamp = t\n\t\t}\n\t}\n\n\tfor i := range s.Gpu {\n\t\tgpu := &s.Gpu[i]\n\n\t\ttags := map[string]string{\n\t\t\t\"index\": strconv.Itoa(i),\n\t\t}\n\t\tfields := make(map[string]interface{}, 44)\n\n\t\tcommon.SetTagIfUsed(tags, \"pstate\", gpu.PerformanceState)\n\t\tcommon.SetTagIfUsed(tags, \"name\", gpu.ProductName)\n\t\tcommon.SetTagIfUsed(tags, \"arch\", gpu.ProductArchitecture)\n\t\tcommon.SetTagIfUsed(tags, \"uuid\", gpu.UUID)\n\t\tcommon.SetTagIfUsed(tags, \"compute_mode\", gpu.ComputeMode)\n\n\t\tcommon.SetIfUsed(\"str\", fields, \"driver_version\", s.DriverVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"cuda_version\", s.CudaVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"serial\", gpu.Serial)\n\t\tcommon.SetIfUsed(\"str\", fields, \"vbios_version\", gpu.VbiosVersion)\n\t\tcommon.SetIfUsed(\"str\", fields, \"display_active\", gpu.DisplayActive)\n\t\tcommon.SetIfUsed(\"str\", fields, \"display_mode\", gpu.DisplayMode)\n\t\tcommon.SetIfUsed(\"str\", fields, \"current_ecc\", gpu.EccMode.CurrentEcc)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fan_speed\", gpu.FanSpeed)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_total\", gpu.FbMemoryUsage.Total)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_used\", gpu.FbMemoryUsage.Used)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_free\", gpu.FbMemoryUsage.Free)\n\t\tcommon.SetIfUsed(\"int\", fields, \"memory_reserved\", gpu.FbMemoryUsage.Reserved)\n\t\tcommon.SetIfUsed(\"int\", fields, \"retired_pages_multiple_single_bit\", gpu.RetiredPages.MultipleSingleBitRetirement.RetiredCount)\n\t\tcommon.SetIfUsed(\"int\", fields, \"retired_pages_double_bit\", gpu.RetiredPages.DoubleBitRetirement.RetiredCount)\n\t\tcommon.SetIfUsed(\"str\", fields, \"retired_pages_blacklist\", gpu.RetiredPages.PendingBlacklist)\n\t\tcommon.SetIfUsed(\"str\", fields, \"retired_pages_pending\", gpu.RetiredPages.PendingRetirement)\n\t\tcommon.SetIfUsed(\"int\", fields, \"remapped_rows_correctable\", gpu.RemappedRows.Correctable)\n\t\tcommon.SetIfUsed(\"int\", fields, \"remapped_rows_uncorrectable\", gpu.RemappedRows.Uncorrectable)\n\t\tcommon.SetIfUsed(\"str\", fields, \"remapped_rows_pending\", gpu.RemappedRows.Pending)\n\t\tcommon.SetIfUsed(\"str\", fields, \"remapped_rows_failure\", gpu.RemappedRows.Failure)\n\t\tcommon.SetIfUsed(\"int\", fields, \"temperature_gpu\", gpu.Temperature.GpuTemp)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_gpu\", gpu.Utilization.GpuUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_memory\", gpu.Utilization.MemoryUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_encoder\", gpu.Utilization.EncoderUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_decoder\", gpu.Utilization.DecoderUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_jpeg\", gpu.Utilization.JpegUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"utilization_ofa\", gpu.Utilization.OfaUtil)\n\t\tcommon.SetIfUsed(\"int\", fields, \"pcie_link_gen_current\", gpu.Pci.PciGpuLinkInfo.PcieGen.CurrentLinkGen)\n\t\tcommon.SetIfUsed(\"int\", fields, \"pcie_link_width_current\", gpu.Pci.PciGpuLinkInfo.LinkWidths.CurrentLinkWidth)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_session_count\", gpu.EncoderStats.SessionCount)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_average_fps\", gpu.EncoderStats.AverageFps)\n\t\tcommon.SetIfUsed(\"int\", fields, \"encoder_stats_average_latency\", gpu.EncoderStats.AverageLatency)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_session_count\", gpu.FbcStats.SessionCount)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_average_fps\", gpu.FbcStats.AverageFps)\n\t\tcommon.SetIfUsed(\"int\", fields, \"fbc_stats_average_latency\", gpu.FbcStats.AverageLatency)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_graphics\", gpu.Clocks.GraphicsClock)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_sm\", gpu.Clocks.SmClock)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_memory\", gpu.Clocks.MemClock)\n\t\tcommon.SetIfUsed(\"int\", fields, \"clocks_current_video\", gpu.Clocks.VideoClock)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_draw\", gpu.PowerReadings.PowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_draw\", gpu.PowerReadings.InstantPowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_limit\", gpu.PowerReadings.PowerLimit)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_draw\", gpu.GpuPowerReadings.PowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_draw\", gpu.GpuPowerReadings.InstantPowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"power_limit\", gpu.GpuPowerReadings.PowerLimit)\n\t\tcommon.SetIfUsed(\"float\", fields, \"module_power_draw\", gpu.ModulePowerReadings.PowerDraw)\n\t\tcommon.SetIfUsed(\"float\", fields, \"module_power_draw\", gpu.ModulePowerReadings.InstantPowerDraw)\n\t\tacc.AddFields(\"nvidia_smi\", fields, tags, timestamp)\n\n\t\tfor _, device := range gpu.MigDevices.MigDevice {\n\t\t\ttags := make(map[string]string, 8)\n\t\t\tcommon.SetTagIfUsed(tags, \"index\", device.Index)\n\t\t\tcommon.SetTagIfUsed(tags, \"gpu_index\", device.GpuInstanceID)\n\t\t\tcommon.SetTagIfUsed(tags, \"compute_index\", device.ComputeInstanceID)\n\t\t\tcommon.SetTagIfUsed(tags, \"pstate\", gpu.PerformanceState)\n\t\t\tcommon.SetTagIfUsed(tags, \"name\", gpu.ProductName)\n\t\t\tcommon.SetTagIfUsed(tags, \"arch\", gpu.ProductArchitecture)\n\t\t\tcommon.SetTagIfUsed(tags, \"uuid\", gpu.UUID)\n\t\t\tcommon.SetTagIfUsed(tags, \"compute_mode\", gpu.ComputeMode)\n\n\t\t\tfields := make(map[string]interface{}, 8)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"sram_uncorrectable\", device.EccErrorCount.VolatileCount.SramUncorrectable)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_fb_total\", device.FbMemoryUsage.Total)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_fb_reserved\", device.FbMemoryUsage.Reserved)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_fb_used\", device.FbMemoryUsage.Used)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_fb_free\", device.FbMemoryUsage.Free)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_bar1_total\", device.Bar1MemoryUsage.Total)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_bar1_used\", device.Bar1MemoryUsage.Used)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"memory_bar1_free\", device.Bar1MemoryUsage.Free)\n\n\t\t\tacc.AddFields(\"nvidia_smi_mig\", fields, tags, timestamp)\n\t\t}\n\n\t\tfor _, process := range gpu.Processes.ProcessInfo {\n\t\t\ttags := make(map[string]string, 2)\n\t\t\tcommon.SetTagIfUsed(tags, \"name\", process.ProcessName)\n\t\t\tcommon.SetTagIfUsed(tags, \"type\", process.Type)\n\n\t\t\tfields := make(map[string]interface{}, 2)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"pid\", process.Pid)\n\t\t\tcommon.SetIfUsed(\"int\", fields, \"used_memory\", process.UsedMemory)\n\n\t\t\tacc.AddFields(\"nvidia_smi_process\", fields, tags, timestamp)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/schema_v12/types.go",
    "content": "package schema_v12\n\n// Generated by https://github.com/twpayne/go-xmlstruct with some type corrections.\ntype smi struct {\n\tAttachedGpus  string `xml:\"attached_gpus\"`\n\tCudaVersion   string `xml:\"cuda_version\"`\n\tDriverVersion string `xml:\"driver_version\"`\n\tGpu           []struct {\n\t\tID                       string   `xml:\"id,attr\"`\n\t\tAccountedProcesses       struct{} `xml:\"accounted_processes\"`\n\t\tAccountingMode           string   `xml:\"accounting_mode\"`\n\t\tAccountingModeBufferSize string   `xml:\"accounting_mode_buffer_size\"`\n\t\tAddressingMode           string   `xml:\"addressing_mode\"`\n\t\tApplicationsClocks       struct {\n\t\t\tGraphicsClock string `xml:\"graphics_clock\"`\n\t\t\tMemClock      string `xml:\"mem_clock\"`\n\t\t} `xml:\"applications_clocks\"`\n\t\tBar1MemoryUsage struct {\n\t\t\tFree  string `xml:\"free\"`\n\t\t\tTotal string `xml:\"total\"`\n\t\t\tUsed  string `xml:\"used\"`\n\t\t} `xml:\"bar1_memory_usage\"`\n\t\tBoardID                string `xml:\"board_id\"`\n\t\tBoardPartNumber        string `xml:\"board_part_number\"`\n\t\tCcProtectedMemoryUsage struct {\n\t\t\tFree  string `xml:\"free\"`\n\t\t\tTotal string `xml:\"total\"`\n\t\t\tUsed  string `xml:\"used\"`\n\t\t} `xml:\"cc_protected_memory_usage\"`\n\t\tClockPolicy struct {\n\t\t\tAutoBoost        string `xml:\"auto_boost\"`\n\t\t\tAutoBoostDefault string `xml:\"auto_boost_default\"`\n\t\t} `xml:\"clock_policy\"`\n\t\tClocks struct {\n\t\t\tGraphicsClock string `xml:\"graphics_clock\"`\n\t\t\tMemClock      string `xml:\"mem_clock\"`\n\t\t\tSmClock       string `xml:\"sm_clock\"`\n\t\t\tVideoClock    string `xml:\"video_clock\"`\n\t\t} `xml:\"clocks\"`\n\t\tClocksEventReasons struct {\n\t\t\tClocksEventReasonApplicationsClocksSetting string `xml:\"clocks_event_reason_applications_clocks_setting\"`\n\t\t\tClocksEventReasonDisplayClocksSetting      string `xml:\"clocks_event_reason_display_clocks_setting\"`\n\t\t\tClocksEventReasonGpuIdle                   string `xml:\"clocks_event_reason_gpu_idle\"`\n\t\t\tClocksEventReasonHwPowerBrakeSlowdown      string `xml:\"clocks_event_reason_hw_power_brake_slowdown\"`\n\t\t\tClocksEventReasonHwSlowdown                string `xml:\"clocks_event_reason_hw_slowdown\"`\n\t\t\tClocksEventReasonHwThermalSlowdown         string `xml:\"clocks_event_reason_hw_thermal_slowdown\"`\n\t\t\tClocksEventReasonSwPowerCap                string `xml:\"clocks_event_reason_sw_power_cap\"`\n\t\t\tClocksEventReasonSwThermalSlowdown         string `xml:\"clocks_event_reason_sw_thermal_slowdown\"`\n\t\t\tClocksEventReasonSyncBoost                 string `xml:\"clocks_event_reason_sync_boost\"`\n\t\t} `xml:\"clocks_event_reasons\"`\n\t\tComputeMode               string `xml:\"compute_mode\"`\n\t\tDefaultApplicationsClocks struct {\n\t\t\tGraphicsClock string `xml:\"graphics_clock\"`\n\t\t\tMemClock      string `xml:\"mem_clock\"`\n\t\t} `xml:\"default_applications_clocks\"`\n\t\tDeferredClocks struct {\n\t\t\tMemClock string `xml:\"mem_clock\"`\n\t\t} `xml:\"deferred_clocks\"`\n\t\tDisplayActive string `xml:\"display_active\"`\n\t\tDisplayMode   string `xml:\"display_mode\"`\n\t\tDriverModel   struct {\n\t\t\tCurrentDm string `xml:\"current_dm\"`\n\t\t\tPendingDm string `xml:\"pending_dm\"`\n\t\t} `xml:\"driver_model\"`\n\t\tEccErrors struct {\n\t\t\tAggregate struct {\n\t\t\t\tDramCorrectable   string `xml:\"dram_correctable\"`\n\t\t\t\tDramUncorrectable string `xml:\"dram_uncorrectable\"`\n\t\t\t\tSramCorrectable   string `xml:\"sram_correctable\"`\n\t\t\t\tSramUncorrectable string `xml:\"sram_uncorrectable\"`\n\t\t\t} `xml:\"aggregate\"`\n\t\t\tVolatile struct {\n\t\t\t\tDramCorrectable   string `xml:\"dram_correctable\"`\n\t\t\t\tDramUncorrectable string `xml:\"dram_uncorrectable\"`\n\t\t\t\tSramCorrectable   string `xml:\"sram_correctable\"`\n\t\t\t\tSramUncorrectable string `xml:\"sram_uncorrectable\"`\n\t\t\t} `xml:\"volatile\"`\n\t\t} `xml:\"ecc_errors\"`\n\t\tEccMode struct {\n\t\t\tCurrentEcc string `xml:\"current_ecc\"`\n\t\t\tPendingEcc string `xml:\"pending_ecc\"`\n\t\t} `xml:\"ecc_mode\"`\n\t\tEncoderStats struct {\n\t\t\tAverageFps     string `xml:\"average_fps\"`\n\t\t\tAverageLatency string `xml:\"average_latency\"`\n\t\t\tSessionCount   string `xml:\"session_count\"`\n\t\t} `xml:\"encoder_stats\"`\n\t\tFabric struct {\n\t\t\tState  string `xml:\"state\"`\n\t\t\tStatus string `xml:\"status\"`\n\t\t} `xml:\"fabric\"`\n\t\tFanSpeed      string `xml:\"fan_speed\"`\n\t\tFbMemoryUsage struct {\n\t\t\tFree     string `xml:\"free\"`\n\t\t\tReserved string `xml:\"reserved\"`\n\t\t\tTotal    string `xml:\"total\"`\n\t\t\tUsed     string `xml:\"used\"`\n\t\t} `xml:\"fb_memory_usage\"`\n\t\tFbcStats struct {\n\t\t\tAverageFps     string `xml:\"average_fps\"`\n\t\t\tAverageLatency string `xml:\"average_latency\"`\n\t\t\tSessionCount   string `xml:\"session_count\"`\n\t\t} `xml:\"fbc_stats\"`\n\t\tGpuFruPartNumber string `xml:\"gpu_fru_part_number\"`\n\t\tGpuModuleID      string `xml:\"gpu_module_id\"`\n\t\tGpuOperationMode struct {\n\t\t\tCurrentGom string `xml:\"current_gom\"`\n\t\t\tPendingGom string `xml:\"pending_gom\"`\n\t\t} `xml:\"gpu_operation_mode\"`\n\t\tGpuPartNumber    string `xml:\"gpu_part_number\"`\n\t\tGpuPowerReadings struct {\n\t\t\tCurrentPowerLimit   string `xml:\"current_power_limit\"`\n\t\t\tDefaultPowerLimit   string `xml:\"default_power_limit\"`\n\t\t\tMaxPowerLimit       string `xml:\"max_power_limit\"`\n\t\t\tMinPowerLimit       string `xml:\"min_power_limit\"`\n\t\t\tPowerDraw           string `xml:\"power_draw\"`\n\t\t\tAveragePowerDraw    string `xml:\"average_power_draw\"`\n\t\t\tInstantPowerDraw    string `xml:\"instant_power_draw\"`\n\t\t\tPowerLimit          string `xml:\"power_limit\"`\n\t\t\tPowerState          string `xml:\"power_state\"`\n\t\t\tRequestedPowerLimit string `xml:\"requested_power_limit\"`\n\t\t} `xml:\"gpu_power_readings\"`\n\t\tGpuResetStatus struct {\n\t\t\tDrainAndResetRecommended string `xml:\"drain_and_reset_recommended\"`\n\t\t\tResetRequired            string `xml:\"reset_required\"`\n\t\t} `xml:\"gpu_reset_status\"`\n\t\tGpuVirtualizationMode struct {\n\t\t\tHostVgpuMode       string `xml:\"host_vgpu_mode\"`\n\t\t\tVirtualizationMode string `xml:\"virtualization_mode\"`\n\t\t} `xml:\"gpu_virtualization_mode\"`\n\t\tGspFirmwareVersion string `xml:\"gsp_firmware_version\"`\n\t\tIbmnpu             struct {\n\t\t\tRelaxedOrderingMode string `xml:\"relaxed_ordering_mode\"`\n\t\t} `xml:\"ibmnpu\"`\n\t\tInforomVersion struct {\n\t\t\tEccObject  string `xml:\"ecc_object\"`\n\t\t\tImgVersion string `xml:\"img_version\"`\n\t\t\tOemObject  string `xml:\"oem_object\"`\n\t\t\tPwrObject  string `xml:\"pwr_object\"`\n\t\t} `xml:\"inforom_version\"`\n\t\tMaxClocks struct {\n\t\t\tGraphicsClock string `xml:\"graphics_clock\"`\n\t\t\tMemClock      string `xml:\"mem_clock\"`\n\t\t\tSmClock       string `xml:\"sm_clock\"`\n\t\t\tVideoClock    string `xml:\"video_clock\"`\n\t\t} `xml:\"max_clocks\"`\n\t\tMaxCustomerBoostClocks struct {\n\t\t\tGraphicsClock string `xml:\"graphics_clock\"`\n\t\t} `xml:\"max_customer_boost_clocks\"`\n\t\tMigDevices struct {\n\t\t\tMigDevice []struct {\n\t\t\t\tIndex             string `xml:\"index\"`\n\t\t\t\tGpuInstanceID     string `xml:\"gpu_instance_id\"`\n\t\t\t\tComputeInstanceID string `xml:\"compute_instance_id\"`\n\t\t\t\tEccErrorCount     struct {\n\t\t\t\t\tText          string `xml:\",chardata\" json:\"text\"`\n\t\t\t\t\tVolatileCount struct {\n\t\t\t\t\t\tSramUncorrectable string `xml:\"sram_uncorrectable\"`\n\t\t\t\t\t} `xml:\"volatile_count\" json:\"volatile_count\"`\n\t\t\t\t} `xml:\"ecc_error_count\" json:\"ecc_error_count\"`\n\t\t\t\tFbMemoryUsage struct {\n\t\t\t\t\tTotal    string `xml:\"total\"`\n\t\t\t\t\tReserved string `xml:\"reserved\"`\n\t\t\t\t\tUsed     string `xml:\"used\"`\n\t\t\t\t\tFree     string `xml:\"free\"`\n\t\t\t\t} `xml:\"fb_memory_usage\" json:\"fb_memory_usage\"`\n\t\t\t\tBar1MemoryUsage struct {\n\t\t\t\t\tTotal string `xml:\"total\"`\n\t\t\t\t\tUsed  string `xml:\"used\"`\n\t\t\t\t\tFree  string `xml:\"free\"`\n\t\t\t\t} `xml:\"bar1_memory_usage\" json:\"bar1_memory_usage\"`\n\t\t\t} `xml:\"mig_device\" json:\"mig_device\"`\n\t\t} `xml:\"mig_devices\" json:\"mig_devices\"`\n\t\tMigMode struct {\n\t\t\tCurrentMig string `xml:\"current_mig\"`\n\t\t\tPendingMig string `xml:\"pending_mig\"`\n\t\t} `xml:\"mig_mode\"`\n\t\tMinorNumber         string `xml:\"minor_number\"`\n\t\tModulePowerReadings struct {\n\t\t\tCurrentPowerLimit   string `xml:\"current_power_limit\"`\n\t\t\tDefaultPowerLimit   string `xml:\"default_power_limit\"`\n\t\t\tMaxPowerLimit       string `xml:\"max_power_limit\"`\n\t\t\tMinPowerLimit       string `xml:\"min_power_limit\"`\n\t\t\tPowerDraw           string `xml:\"power_draw\"`\n\t\t\tAveragePowerDraw    string `xml:\"average_power_draw\"`\n\t\t\tInstantPowerDraw    string `xml:\"instant_power_draw\"`\n\t\t\tPowerState          string `xml:\"power_state\"`\n\t\t\tRequestedPowerLimit string `xml:\"requested_power_limit\"`\n\t\t} `xml:\"module_power_readings\"`\n\t\tMultigpuBoard string `xml:\"multigpu_board\"`\n\t\tPci           struct {\n\t\t\tAtomicCapsInbound  string `xml:\"atomic_caps_inbound\"`\n\t\t\tAtomicCapsOutbound string `xml:\"atomic_caps_outbound\"`\n\t\t\tPciBridgeChip      struct {\n\t\t\t\tBridgeChipFw   string `xml:\"bridge_chip_fw\"`\n\t\t\t\tBridgeChipType string `xml:\"bridge_chip_type\"`\n\t\t\t} `xml:\"pci_bridge_chip\"`\n\t\t\tPciBus         string `xml:\"pci_bus\"`\n\t\t\tPciBusID       string `xml:\"pci_bus_id\"`\n\t\t\tPciDevice      string `xml:\"pci_device\"`\n\t\t\tPciDeviceID    string `xml:\"pci_device_id\"`\n\t\t\tPciDomain      string `xml:\"pci_domain\"`\n\t\t\tPciGpuLinkInfo struct {\n\t\t\t\tLinkWidths struct {\n\t\t\t\t\tCurrentLinkWidth string `xml:\"current_link_width\"`\n\t\t\t\t\tMaxLinkWidth     string `xml:\"max_link_width\"`\n\t\t\t\t} `xml:\"link_widths\"`\n\t\t\t\tPcieGen struct {\n\t\t\t\t\tCurrentLinkGen       string `xml:\"current_link_gen\"`\n\t\t\t\t\tDeviceCurrentLinkGen string `xml:\"device_current_link_gen\"`\n\t\t\t\t\tMaxDeviceLinkGen     string `xml:\"max_device_link_gen\"`\n\t\t\t\t\tMaxHostLinkGen       string `xml:\"max_host_link_gen\"`\n\t\t\t\t\tMaxLinkGen           string `xml:\"max_link_gen\"`\n\t\t\t\t} `xml:\"pcie_gen\"`\n\t\t\t} `xml:\"pci_gpu_link_info\"`\n\t\t\tPciSubSystemID        string `xml:\"pci_sub_system_id\"`\n\t\t\tReplayCounter         string `xml:\"replay_counter\"`\n\t\t\tReplayRolloverCounter string `xml:\"replay_rollover_counter\"`\n\t\t\tRxUtil                string `xml:\"rx_util\"`\n\t\t\tTxUtil                string `xml:\"tx_util\"`\n\t\t} `xml:\"pci\"`\n\t\tPerformanceState string `xml:\"performance_state\"`\n\t\tPersistenceMode  string `xml:\"persistence_mode\"`\n\t\tPowerReadings    struct {\n\t\t\tPowerState         string `xml:\"power_state\"`\n\t\t\tPowerManagement    string `xml:\"power_management\"`\n\t\t\tPowerDraw          string `xml:\"power_draw\"`\n\t\t\tAveragePowerDraw   string `xml:\"average_power_draw\"`\n\t\t\tInstantPowerDraw   string `xml:\"instant_power_draw\"`\n\t\t\tPowerLimit         string `xml:\"power_limit\"`\n\t\t\tDefaultPowerLimit  string `xml:\"default_power_limit\"`\n\t\t\tEnforcedPowerLimit string `xml:\"enforced_power_limit\"`\n\t\t\tMinPowerLimit      string `xml:\"min_power_limit\"`\n\t\t\tMaxPowerLimit      string `xml:\"max_power_limit\"`\n\t\t} `xml:\"power_readings\"`\n\t\tProcesses struct {\n\t\t\tProcessInfo []struct {\n\t\t\t\tPid         string `xml:\"pid\"`\n\t\t\t\tType        string `xml:\"type\"`\n\t\t\t\tProcessName string `xml:\"process_name\"`\n\t\t\t\tUsedMemory  string `xml:\"used_memory\"`\n\t\t\t} `xml:\"process_info\"`\n\t\t} `xml:\"processes\"`\n\t\tProductArchitecture string `xml:\"product_architecture\"`\n\t\tProductBrand        string `xml:\"product_brand\"`\n\t\tProductName         string `xml:\"product_name\"`\n\t\tRemappedRows        struct {\n\t\t\t// Manually added\n\t\t\tCorrectable   string `xml:\"remapped_row_corr\"`\n\t\t\tUncorrectable string `xml:\"remapped_row_unc\"`\n\t\t\tPending       string `xml:\"remapped_row_pending\"`\n\t\t\tFailure       string `xml:\"remapped_row_failure\"`\n\t\t} `xml:\"remapped_rows\"`\n\t\tRetiredPages struct {\n\t\t\tDoubleBitRetirement struct {\n\t\t\t\tRetiredCount    string `xml:\"retired_count\"`\n\t\t\t\tRetiredPagelist string `xml:\"retired_pagelist\"`\n\t\t\t} `xml:\"double_bit_retirement\"`\n\t\t\tMultipleSingleBitRetirement struct {\n\t\t\t\tRetiredCount    string `xml:\"retired_count\"`\n\t\t\t\tRetiredPagelist string `xml:\"retired_pagelist\"`\n\t\t\t} `xml:\"multiple_single_bit_retirement\"`\n\t\t\tPendingBlacklist  string `xml:\"pending_blacklist\"`\n\t\t\tPendingRetirement string `xml:\"pending_retirement\"`\n\t\t} `xml:\"retired_pages\"`\n\t\tSerial          string `xml:\"serial\"`\n\t\tSupportedClocks struct {\n\t\t\tSupportedMemClock []struct {\n\t\t\t\tSupportedGraphicsClock []string `xml:\"supported_graphics_clock\"`\n\t\t\t\tValue                  string   `xml:\"value\"`\n\t\t\t} `xml:\"supported_mem_clock\"`\n\t\t} `xml:\"supported_clocks\"`\n\t\tSupportedGpuTargetTemp struct {\n\t\t\tGpuTargetTempMax string `xml:\"gpu_target_temp_max\"`\n\t\t\tGpuTargetTempMin string `xml:\"gpu_target_temp_min\"`\n\t\t} `xml:\"supported_gpu_target_temp\"`\n\t\tTemperature struct {\n\t\t\tGpuTargetTemperature   string `xml:\"gpu_target_temperature\"`\n\t\t\tGpuTemp                string `xml:\"gpu_temp\"`\n\t\t\tGpuTempMaxGpuThreshold string `xml:\"gpu_temp_max_gpu_threshold\"`\n\t\t\tGpuTempMaxMemThreshold string `xml:\"gpu_temp_max_mem_threshold\"`\n\t\t\tGpuTempMaxThreshold    string `xml:\"gpu_temp_max_threshold\"`\n\t\t\tGpuTempSlowThreshold   string `xml:\"gpu_temp_slow_threshold\"`\n\t\t\tGpuTempTlimit          string `xml:\"gpu_temp_tlimit\"`\n\t\t\tMemoryTemp             string `xml:\"memory_temp\"`\n\t\t} `xml:\"temperature\"`\n\t\tUtilization struct {\n\t\t\tDecoderUtil string `xml:\"decoder_util\"`\n\t\t\tEncoderUtil string `xml:\"encoder_util\"`\n\t\t\tGpuUtil     string `xml:\"gpu_util\"`\n\t\t\tJpegUtil    string `xml:\"jpeg_util\"`\n\t\t\tMemoryUtil  string `xml:\"memory_util\"`\n\t\t\tOfaUtil     string `xml:\"ofa_util\"`\n\t\t} `xml:\"utilization\"`\n\t\tUUID         string `xml:\"uuid\"`\n\t\tVbiosVersion string `xml:\"vbios_version\"`\n\t\tVoltage      struct {\n\t\t\tGraphicsVolt string `xml:\"graphics_volt\"`\n\t\t} `xml:\"voltage\"`\n\t} `xml:\"gpu\"`\n\tTimestamp string `xml:\"timestamp\"`\n}\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/a100-sxm4-v12.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v12.dtd\">\n<nvidia_smi_log>\n    <timestamp>Fri Aug  4 11:44:30 2023</timestamp>\n    <driver_version>535.54.03</driver_version>\n    <cuda_version>12.2</cuda_version>\n    <attached_gpus>4</attached_gpus>\n    <gpu id=\"00000000:01:00.0\">\n        <product_name>NVIDIA A100-SXM4-80GB</product_name>\n        <product_brand>NVIDIA</product_brand>\n        <product_architecture>Ampere</product_architecture>\n        <display_mode>Enabled</display_mode>\n        <display_active>Disabled</display_active>\n        <persistence_mode>Disabled</persistence_mode>\n        <addressing_mode>None</addressing_mode>\n        <mig_mode>\n            <current_mig>Enabled</current_mig>\n            <pending_mig>Enabled</pending_mig>\n        </mig_mode>\n        <mig_devices>\n            <mig_device>\n                <index>0</index>\n                <gpu_instance_id>3</gpu_instance_id>\n                <compute_instance_id>0</compute_instance_id>\n                <device_attributes>\n                    <shared>\n                        <multiprocessor_count>14</multiprocessor_count>\n                        <copy_engine_count>1</copy_engine_count>\n                        <encoder_count>0</encoder_count>\n                        <decoder_count>1</decoder_count>\n                        <ofa_count>0</ofa_count>\n                        <jpg_count>0</jpg_count>\n                    </shared>\n                </device_attributes>\n                <ecc_error_count>\n                    <volatile_count>\n                        <sram_uncorrectable>0</sram_uncorrectable>\n                    </volatile_count>\n                </ecc_error_count>\n                <fb_memory_usage>\n                    <total>19968 MiB</total>\n                    <reserved>0 MiB</reserved>\n                    <used>12 MiB</used>\n                    <free>19955 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                    <total>32767 MiB</total>\n                    <used>0 MiB</used>\n                    <free>32767 MiB</free>\n                </bar1_memory_usage>\n            </mig_device>\n            <mig_device>\n                <index>1</index>\n                <gpu_instance_id>4</gpu_instance_id>\n                <compute_instance_id>0</compute_instance_id>\n                <device_attributes>\n                    <shared>\n                        <multiprocessor_count>14</multiprocessor_count>\n                        <copy_engine_count>1</copy_engine_count>\n                        <encoder_count>0</encoder_count>\n                        <decoder_count>1</decoder_count>\n                        <ofa_count>0</ofa_count>\n                        <jpg_count>0</jpg_count>\n                    </shared>\n                </device_attributes>\n                <ecc_error_count>\n                    <volatile_count>\n                        <sram_uncorrectable>0</sram_uncorrectable>\n                    </volatile_count>\n                </ecc_error_count>\n                <fb_memory_usage>\n                    <total>19968 MiB</total>\n                    <reserved>0 MiB</reserved>\n                    <used>12 MiB</used>\n                    <free>19955 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                    <total>32767 MiB</total>\n                    <used>0 MiB</used>\n                    <free>32767 MiB</free>\n                </bar1_memory_usage>\n            </mig_device>\n            <mig_device>\n                <index>2</index>\n                <gpu_instance_id>5</gpu_instance_id>\n                <compute_instance_id>0</compute_instance_id>\n                <device_attributes>\n                    <shared>\n                        <multiprocessor_count>14</multiprocessor_count>\n                        <copy_engine_count>1</copy_engine_count>\n                        <encoder_count>0</encoder_count>\n                        <decoder_count>1</decoder_count>\n                        <ofa_count>0</ofa_count>\n                        <jpg_count>0</jpg_count>\n                    </shared>\n                </device_attributes>\n                <ecc_error_count>\n                    <volatile_count>\n                        <sram_uncorrectable>0</sram_uncorrectable>\n                    </volatile_count>\n                </ecc_error_count>\n                <fb_memory_usage>\n                    <total>19968 MiB</total>\n                    <reserved>0 MiB</reserved>\n                    <used>12 MiB</used>\n                    <free>19955 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                    <total>32767 MiB</total>\n                    <used>0 MiB</used>\n                    <free>32767 MiB</free>\n                </bar1_memory_usage>\n            </mig_device>\n            <mig_device>\n                <index>3</index>\n                <gpu_instance_id>6</gpu_instance_id>\n                <compute_instance_id>0</compute_instance_id>\n                <device_attributes>\n                    <shared>\n                        <multiprocessor_count>14</multiprocessor_count>\n                        <copy_engine_count>1</copy_engine_count>\n                        <encoder_count>0</encoder_count>\n                        <decoder_count>1</decoder_count>\n                        <ofa_count>0</ofa_count>\n                        <jpg_count>0</jpg_count>\n                    </shared>\n                </device_attributes>\n                <ecc_error_count>\n                    <volatile_count>\n                        <sram_uncorrectable>0</sram_uncorrectable>\n                    </volatile_count>\n                </ecc_error_count>\n                <fb_memory_usage>\n                    <total>19968 MiB</total>\n                    <reserved>0 MiB</reserved>\n                    <used>12 MiB</used>\n                    <free>19955 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                    <total>32767 MiB</total>\n                    <used>0 MiB</used>\n                    <free>32767 MiB</free>\n                </bar1_memory_usage>\n            </mig_device>\n        </mig_devices>\n        <accounting_mode>Disabled</accounting_mode>\n        <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n        <driver_model>\n            <current_dm>N/A</current_dm>\n            <pending_dm>N/A</pending_dm>\n        </driver_model>\n        <serial>1650522003820</serial>\n        <uuid>GPU-513536b6-7d19-9063-b049-1e69664bb298</uuid>\n        <minor_number>1</minor_number>\n        <vbios_version>92.00.36.00.02</vbios_version>\n        <multigpu_board>No</multigpu_board>\n        <board_id>0x100</board_id>\n        <board_part_number>692-2G506-0212-002</board_part_number>\n        <gpu_part_number>20B2-895-A1</gpu_part_number>\n        <gpu_fru_part_number>N/A</gpu_fru_part_number>\n        <gpu_module_id>4</gpu_module_id>\n        <inforom_version>\n            <img_version>G506.0212.00.01</img_version>\n            <oem_object>2.0</oem_object>\n            <ecc_object>6.16</ecc_object>\n            <pwr_object>N/A</pwr_object>\n        </inforom_version>\n        <gpu_operation_mode>\n            <current_gom>N/A</current_gom>\n            <pending_gom>N/A</pending_gom>\n        </gpu_operation_mode>\n        <gsp_firmware_version>535.54.03</gsp_firmware_version>\n        <gpu_virtualization_mode>\n            <virtualization_mode>None</virtualization_mode>\n            <host_vgpu_mode>N/A</host_vgpu_mode>\n        </gpu_virtualization_mode>\n        <gpu_reset_status>\n            <reset_required>No</reset_required>\n            <drain_and_reset_recommended>No</drain_and_reset_recommended>\n        </gpu_reset_status>\n        <ibmnpu>\n            <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n        </ibmnpu>\n        <pci>\n            <pci_bus>01</pci_bus>\n            <pci_device>00</pci_device>\n            <pci_domain>0000</pci_domain>\n            <pci_device_id>20B210DE</pci_device_id>\n            <pci_bus_id>00000000:01:00.0</pci_bus_id>\n            <pci_sub_system_id>147F10DE</pci_sub_system_id>\n            <pci_gpu_link_info>\n                <pcie_gen>\n                    <max_link_gen>4</max_link_gen>\n                    <current_link_gen>4</current_link_gen>\n                    <device_current_link_gen>4</device_current_link_gen>\n                    <max_device_link_gen>4</max_device_link_gen>\n                    <max_host_link_gen>4</max_host_link_gen>\n                </pcie_gen>\n                <link_widths>\n                    <max_link_width>16x</max_link_width>\n                    <current_link_width>16x</current_link_width>\n                </link_widths>\n            </pci_gpu_link_info>\n            <pci_bridge_chip>\n                <bridge_chip_type>N/A</bridge_chip_type>\n                <bridge_chip_fw>N/A</bridge_chip_fw>\n            </pci_bridge_chip>\n            <replay_counter>0</replay_counter>\n            <replay_rollover_counter>0</replay_rollover_counter>\n            <tx_util>4000 KB/s</tx_util>\n            <rx_util>0 KB/s</rx_util>\n            <atomic_caps_inbound>N/A</atomic_caps_inbound>\n            <atomic_caps_outbound>N/A</atomic_caps_outbound>\n        </pci>\n        <fan_speed>N/A</fan_speed>\n        <performance_state>P0</performance_state>\n        <clocks_event_reasons>\n            <clocks_event_reason_gpu_idle>Not Active</clocks_event_reason_gpu_idle>\n            <clocks_event_reason_applications_clocks_setting>Not Active</clocks_event_reason_applications_clocks_setting>\n            <clocks_event_reason_sw_power_cap>Not Active</clocks_event_reason_sw_power_cap>\n            <clocks_event_reason_hw_slowdown>Not Active</clocks_event_reason_hw_slowdown>\n            <clocks_event_reason_hw_thermal_slowdown>Not Active</clocks_event_reason_hw_thermal_slowdown>\n            <clocks_event_reason_hw_power_brake_slowdown>Not Active</clocks_event_reason_hw_power_brake_slowdown>\n            <clocks_event_reason_sync_boost>Not Active</clocks_event_reason_sync_boost>\n            <clocks_event_reason_sw_thermal_slowdown>Not Active</clocks_event_reason_sw_thermal_slowdown>\n            <clocks_event_reason_display_clocks_setting>Not Active</clocks_event_reason_display_clocks_setting>\n        </clocks_event_reasons>\n        <fb_memory_usage>\n            <total>81920 MiB</total>\n            <reserved>869 MiB</reserved>\n            <used>50 MiB</used>\n            <free>80999 MiB</free>\n        </fb_memory_usage>\n        <bar1_memory_usage>\n            <total>131072 MiB</total>\n            <used>1 MiB</used>\n            <free>131071 MiB</free>\n        </bar1_memory_usage>\n        <cc_protected_memory_usage>\n            <total>0 MiB</total>\n            <used>0 MiB</used>\n            <free>0 MiB</free>\n        </cc_protected_memory_usage>\n        <compute_mode>Default</compute_mode>\n        <utilization>\n            <gpu_util>N/A</gpu_util>\n            <memory_util>N/A</memory_util>\n            <encoder_util>N/A</encoder_util>\n            <decoder_util>N/A</decoder_util>\n            <jpeg_util>N/A</jpeg_util>\n            <ofa_util>N/A</ofa_util>\n        </utilization>\n        <encoder_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </encoder_stats>\n        <fbc_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </fbc_stats>\n        <ecc_mode>\n            <current_ecc>Enabled</current_ecc>\n            <pending_ecc>Enabled</pending_ecc>\n        </ecc_mode>\n        <ecc_errors>\n            <volatile>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </volatile>\n            <aggregate>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </aggregate>\n        </ecc_errors>\n        <retired_pages>\n            <multiple_single_bit_retirement>\n                <retired_count>N/A</retired_count>\n                <retired_pagelist>N/A</retired_pagelist>\n            </multiple_single_bit_retirement>\n            <double_bit_retirement>\n                <retired_count>N/A</retired_count>\n                <retired_pagelist>N/A</retired_pagelist>\n            </double_bit_retirement>\n            <pending_blacklist>N/A</pending_blacklist>\n            <pending_retirement>N/A</pending_retirement>\n        </retired_pages>\n        <remapped_rows>N/A</remapped_rows>\n        <temperature>\n            <gpu_temp>27 C</gpu_temp>\n            <gpu_temp_tlimit>N/A</gpu_temp_tlimit>\n            <gpu_temp_max_threshold>92 C</gpu_temp_max_threshold>\n            <gpu_temp_slow_threshold>89 C</gpu_temp_slow_threshold>\n            <gpu_temp_max_gpu_threshold>85 C</gpu_temp_max_gpu_threshold>\n            <gpu_target_temperature>N/A</gpu_target_temperature>\n            <memory_temp>44 C</memory_temp>\n            <gpu_temp_max_mem_threshold>95 C</gpu_temp_max_mem_threshold>\n        </temperature>\n        <supported_gpu_target_temp>\n            <gpu_target_temp_min>N/A</gpu_target_temp_min>\n            <gpu_target_temp_max>N/A</gpu_target_temp_max>\n        </supported_gpu_target_temp>\n        <gpu_power_readings>\n            <power_state>P0</power_state>\n            <power_draw>67.03 W</power_draw>\n            <current_power_limit>500.00 W</current_power_limit>\n            <requested_power_limit>500.00 W</requested_power_limit>\n            <default_power_limit>500.00 W</default_power_limit>\n            <min_power_limit>100.00 W</min_power_limit>\n            <max_power_limit>500.00 W</max_power_limit>\n        </gpu_power_readings>\n        <module_power_readings>\n            <power_state>P0</power_state>\n            <power_draw>N/A</power_draw>\n            <current_power_limit>N/A</current_power_limit>\n            <requested_power_limit>N/A</requested_power_limit>\n            <default_power_limit>N/A</default_power_limit>\n            <min_power_limit>N/A</min_power_limit>\n            <max_power_limit>N/A</max_power_limit>\n        </module_power_readings>\n        <clocks>\n            <graphics_clock>1275 MHz</graphics_clock>\n            <sm_clock>1275 MHz</sm_clock>\n            <mem_clock>1593 MHz</mem_clock>\n            <video_clock>1275 MHz</video_clock>\n        </clocks>\n        <applications_clocks>\n            <graphics_clock>1275 MHz</graphics_clock>\n            <mem_clock>1593 MHz</mem_clock>\n        </applications_clocks>\n        <default_applications_clocks>\n            <graphics_clock>1275 MHz</graphics_clock>\n            <mem_clock>1593 MHz</mem_clock>\n        </default_applications_clocks>\n        <deferred_clocks>\n            <mem_clock>N/A</mem_clock>\n        </deferred_clocks>\n        <max_clocks>\n            <graphics_clock>1410 MHz</graphics_clock>\n            <sm_clock>1410 MHz</sm_clock>\n            <mem_clock>1593 MHz</mem_clock>\n            <video_clock>1290 MHz</video_clock>\n        </max_clocks>\n        <max_customer_boost_clocks>\n            <graphics_clock>1410 MHz</graphics_clock>\n        </max_customer_boost_clocks>\n        <clock_policy>\n            <auto_boost>N/A</auto_boost>\n            <auto_boost_default>N/A</auto_boost_default>\n        </clock_policy>\n        <voltage>\n            <graphics_volt>912.500 mV</graphics_volt>\n        </voltage>\n        <fabric>\n            <state>N/A</state>\n            <status>N/A</status>\n        </fabric>\n        <supported_clocks>\n            <supported_mem_clock>\n                <value>1593 MHz</value>\n                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n            </supported_mem_clock>\n        </supported_clocks>\n        <processes />\n        <accounted_processes />\n    </gpu>\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/a10g.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v11.dtd\">\n<nvidia_smi_log>\n    <timestamp>Mon Apr 24 16:11:51 2023</timestamp>\n    <driver_version>515.105.01</driver_version>\n    <cuda_version>11.7</cuda_version>\n    <attached_gpus>1</attached_gpus>\n    <gpu id=\"00000000:00:1E.0\">\n        <product_name>NVIDIA A10G</product_name>\n        <product_brand>NVIDIA</product_brand>\n        <product_architecture>Ampere</product_architecture>\n        <display_mode>Disabled</display_mode>\n        <display_active>Disabled</display_active>\n        <persistence_mode>Disabled</persistence_mode>\n        <mig_mode>\n            <current_mig>N/A</current_mig>\n            <pending_mig>N/A</pending_mig>\n        </mig_mode>\n        <mig_devices>\n            None\n        </mig_devices>\n        <accounting_mode>Disabled</accounting_mode>\n        <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n        <driver_model>\n            <current_dm>N/A</current_dm>\n            <pending_dm>N/A</pending_dm>\n        </driver_model>\n        <serial>0000000000000</serial>\n        <uuid>GPU-9a9a6c50-2a47-2f51-a902-b82c3b127e94</uuid>\n        <minor_number>0</minor_number>\n        <vbios_version>94.02.75.00.01</vbios_version>\n        <multigpu_board>No</multigpu_board>\n        <board_id>0x1e</board_id>\n        <gpu_part_number>000-00000-0000-000</gpu_part_number>\n        <gpu_module_id>0</gpu_module_id>\n        <inforom_version>\n            <img_version>G133.0210.00.04</img_version>\n            <oem_object>2.0</oem_object>\n            <ecc_object>6.16</ecc_object>\n            <pwr_object>N/A</pwr_object>\n        </inforom_version>\n        <gpu_operation_mode>\n            <current_gom>N/A</current_gom>\n            <pending_gom>N/A</pending_gom>\n        </gpu_operation_mode>\n        <gsp_firmware_version>515.105.01</gsp_firmware_version>\n        <gpu_virtualization_mode>\n            <virtualization_mode>Pass-Through</virtualization_mode>\n            <host_vgpu_mode>N/A</host_vgpu_mode>\n        </gpu_virtualization_mode>\n        <ibmnpu>\n            <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n        </ibmnpu>\n        <pci>\n            <pci_bus>00</pci_bus>\n            <pci_device>1E</pci_device>\n            <pci_domain>0000</pci_domain>\n            <pci_device_id>000000DE</pci_device_id>\n            <pci_bus_id>00000000:00:1E.0</pci_bus_id>\n            <pci_sub_system_id>000000DE</pci_sub_system_id>\n            <pci_gpu_link_info>\n                <pcie_gen>\n                    <max_link_gen>4</max_link_gen>\n                    <current_link_gen>1</current_link_gen>\n                </pcie_gen>\n                <link_widths>\n                    <max_link_width>16x</max_link_width>\n                    <current_link_width>8x</current_link_width>\n                </link_widths>\n            </pci_gpu_link_info>\n            <pci_bridge_chip>\n                <bridge_chip_type>N/A</bridge_chip_type>\n                <bridge_chip_fw>N/A</bridge_chip_fw>\n            </pci_bridge_chip>\n            <replay_counter>0</replay_counter>\n            <replay_rollover_counter>0</replay_rollover_counter>\n            <tx_util>0 KB/s</tx_util>\n            <rx_util>0 KB/s</rx_util>\n        </pci>\n        <fan_speed>0 %</fan_speed>\n        <performance_state>P8</performance_state>\n        <clocks_throttle_reasons>\n            <clocks_throttle_reason_gpu_idle>Active</clocks_throttle_reason_gpu_idle>\n            <clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n            <clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n            <clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n            <clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n            <clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n            <clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n            <clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n            <clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n        </clocks_throttle_reasons>\n        <fb_memory_usage>\n            <total>23028 MiB</total>\n            <reserved>435 MiB</reserved>\n            <used>22 MiB</used>\n            <free>22569 MiB</free>\n        </fb_memory_usage>\n        <bar1_memory_usage>\n            <total>32768 MiB</total>\n            <used>1 MiB</used>\n            <free>32767 MiB</free>\n        </bar1_memory_usage>\n        <compute_mode>Default</compute_mode>\n        <utilization>\n            <gpu_util>0 %</gpu_util>\n            <memory_util>0 %</memory_util>\n            <encoder_util>0 %</encoder_util>\n            <decoder_util>0 %</decoder_util>\n        </utilization>\n        <encoder_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </encoder_stats>\n        <fbc_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </fbc_stats>\n        <ecc_mode>\n            <current_ecc>Enabled</current_ecc>\n            <pending_ecc>Enabled</pending_ecc>\n        </ecc_mode>\n        <ecc_errors>\n            <volatile>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </volatile>\n            <aggregate>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </aggregate>\n        </ecc_errors>\n        <retired_pages>\n            <multiple_single_bit_retirement>\n                <retired_count>N/A</retired_count>\n                <retired_pagelist>N/A</retired_pagelist>\n            </multiple_single_bit_retirement>\n            <double_bit_retirement>\n                <retired_count>N/A</retired_count>\n                <retired_pagelist>N/A</retired_pagelist>\n            </double_bit_retirement>\n            <pending_blacklist>N/A</pending_blacklist>\n            <pending_retirement>N/A</pending_retirement>\n        </retired_pages>\n        <remapped_rows>\n            <remapped_row_corr>0</remapped_row_corr>\n            <remapped_row_unc>0</remapped_row_unc>\n            <remapped_row_pending>No</remapped_row_pending>\n            <remapped_row_failure>No</remapped_row_failure>\n            <row_remapper_histogram>\n                <row_remapper_histogram_max>192 bank(s)</row_remapper_histogram_max>\n                <row_remapper_histogram_high>0 bank(s)</row_remapper_histogram_high>\n                <row_remapper_histogram_partial>0 bank(s)</row_remapper_histogram_partial>\n                <row_remapper_histogram_low>0 bank(s)</row_remapper_histogram_low>\n                <row_remapper_histogram_none>0 bank(s)</row_remapper_histogram_none>\n            </row_remapper_histogram>\n        </remapped_rows>\n        <temperature>\n            <gpu_temp>17 C</gpu_temp>\n            <gpu_temp_max_threshold>98 C</gpu_temp_max_threshold>\n            <gpu_temp_slow_threshold>95 C</gpu_temp_slow_threshold>\n            <gpu_temp_max_gpu_threshold>88 C</gpu_temp_max_gpu_threshold>\n            <gpu_target_temperature>N/A</gpu_target_temperature>\n            <memory_temp>N/A</memory_temp>\n            <gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n        </temperature>\n        <supported_gpu_target_temp>\n            <gpu_target_temp_min>N/A</gpu_target_temp_min>\n            <gpu_target_temp_max>N/A</gpu_target_temp_max>\n        </supported_gpu_target_temp>\n        <power_readings>\n            <power_state>P8</power_state>\n            <power_management>Supported</power_management>\n            <power_draw>25.58 W</power_draw>\n            <power_limit>300.00 W</power_limit>\n            <default_power_limit>300.00 W</default_power_limit>\n            <enforced_power_limit>300.00 W</enforced_power_limit>\n            <min_power_limit>100.00 W</min_power_limit>\n            <max_power_limit>300.00 W</max_power_limit>\n        </power_readings>\n        <clocks>\n            <graphics_clock>210 MHz</graphics_clock>\n            <sm_clock>210 MHz</sm_clock>\n            <mem_clock>405 MHz</mem_clock>\n            <video_clock>555 MHz</video_clock>\n        </clocks>\n        <applications_clocks>\n            <graphics_clock>1710 MHz</graphics_clock>\n            <mem_clock>6251 MHz</mem_clock>\n        </applications_clocks>\n        <default_applications_clocks>\n            <graphics_clock>1710 MHz</graphics_clock>\n            <mem_clock>6251 MHz</mem_clock>\n        </default_applications_clocks>\n        <max_clocks>\n            <graphics_clock>1710 MHz</graphics_clock>\n            <sm_clock>1710 MHz</sm_clock>\n            <mem_clock>6251 MHz</mem_clock>\n            <video_clock>1500 MHz</video_clock>\n        </max_clocks>\n        <max_customer_boost_clocks>\n            <graphics_clock>1710 MHz</graphics_clock>\n        </max_customer_boost_clocks>\n        <clock_policy>\n            <auto_boost>N/A</auto_boost>\n            <auto_boost_default>N/A</auto_boost_default>\n        </clock_policy>\n        <voltage>\n            <graphics_volt>693.750 mV</graphics_volt>\n        </voltage>\n        <supported_clocks>\n            <supported_mem_clock>\n                <value>6251 MHz</value>\n                <supported_graphics_clock>1710 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1695 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1680 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1665 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1650 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1635 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1620 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1605 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n            </supported_mem_clock>\n            <supported_mem_clock>\n                <value>405 MHz</value>\n                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n            </supported_mem_clock>\n        </supported_clocks>\n        <processes>\n            <process_info>\n                <gpu_instance_id>N/A</gpu_instance_id>\n                <compute_instance_id>N/A</compute_instance_id>\n                <pid>725</pid>\n                <type>G</type>\n                <process_name>/usr/lib/xorg/Xorg</process_name>\n                <used_memory>22 MiB</used_memory>\n            </process_info>\n        </processes>\n        <accounted_processes>\n        </accounted_processes>\n    </gpu>\n\n</nvidia_smi_log>"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/gtx-1070-ti.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v10.dtd\">\n<nvidia_smi_log>\n        <gpu id=\"00000000:01:00.0\">\n                <product_name>GeForce GTX 1070 Ti</product_name>\n                <uuid>GPU-f9ba66fc-a7f5-94c5-da19-019ef2f9c665</uuid>\n                <pci>\n                        <pci_gpu_link_info>\n                                <pcie_gen>\n                                        <current_link_gen>1</current_link_gen>\n                                </pcie_gen>\n                                <link_widths>\n                                        <current_link_width>16x</current_link_width>\n                                </link_widths>\n                        </pci_gpu_link_info>\n                </pci>\n                <fan_speed>100 %</fan_speed>\n                <performance_state>P8</performance_state>\n                <fb_memory_usage>\n                        <total>4096 MiB</total>\n                        <used>42 MiB</used>\n                        <free>4054 MiB</free>\n                </fb_memory_usage>\n                <compute_mode>Default</compute_mode>\n                <utilization>\n                        <gpu_util>0 %</gpu_util>\n                        <memory_util>0 %</memory_util>\n                </utilization>\n                <encoder_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </encoder_stats>\n                <temperature>\n                        <gpu_temp>39 C</gpu_temp>\n                </temperature>\n                <power_readings>\n                        <power_draw>N/A</power_draw>\n                </power_readings>\n                <clocks>\n                        <graphics_clock>135 MHz</graphics_clock>\n                        <sm_clock>135 MHz</sm_clock>\n                        <mem_clock>405 MHz</mem_clock>\n                        <video_clock>405 MHz</video_clock>\n                </clocks>\n        </gpu>\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/gtx-1660-ti.xml",
    "content": "<?xml version=\"1.0\" ?>\n<nvidia_smi_log>\n        <timestamp>Fri Mar 29 19:19:44 2019</timestamp>\n        <driver_version>418.43</driver_version>\n        <cuda_version>10.1</cuda_version>\n        <attached_gpus>1</attached_gpus>\n        <gpu id=\"00000000:43:00.0\">\n                <product_name>Graphics Device</product_name>\n                <product_brand>GeForce</product_brand>\n                <display_mode>Disabled</display_mode>\n                <display_active>Disabled</display_active>\n                <persistence_mode>Disabled</persistence_mode>\n                <accounting_mode>Disabled</accounting_mode>\n                <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n                <driver_model>\n                        <current_dm>N/A</current_dm>\n                        <pending_dm>N/A</pending_dm>\n                </driver_model>\n                <serial>N/A</serial>\n                <uuid>GPU-304a277d-3545-63b8-3a36-dfde3c992989</uuid>\n                <minor_number>0</minor_number>\n                <vbios_version>90.16.25.00.4C</vbios_version>\n                <multigpu_board>No</multigpu_board>\n                <board_id>0x4300</board_id>\n                <gpu_part_number>N/A</gpu_part_number>\n                <inforom_version>\n                        <img_version>G001.0000.02.04</img_version>\n                        <oem_object>1.1</oem_object>\n                        <ecc_object>N/A</ecc_object>\n                        <pwr_object>N/A</pwr_object>\n                </inforom_version>\n                <gpu_operation_mode>\n                        <current_gom>N/A</current_gom>\n                        <pending_gom>N/A</pending_gom>\n                </gpu_operation_mode>\n                <gpu_virtualization_mode>\n                        <virtualization_mode>None</virtualization_mode>\n                </gpu_virtualization_mode>\n                <ibmnpu>\n                        <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n                </ibmnpu>\n                <pci>\n                        <pci_bus>43</pci_bus>\n                        <pci_device>00</pci_device>\n                        <pci_domain>0000</pci_domain>\n                        <pci_device_id>218410DE</pci_device_id>\n                        <pci_bus_id>00000000:43:00.0</pci_bus_id>\n                        <pci_sub_system_id>3FC81458</pci_sub_system_id>\n                        <pci_gpu_link_info>\n                                <pcie_gen>\n                                        <max_link_gen>3</max_link_gen>\n                                        <current_link_gen>1</current_link_gen>\n                                </pcie_gen>\n                                <link_widths>\n                                        <max_link_width>16x</max_link_width>\n                                        <current_link_width>16x</current_link_width>\n                                </link_widths>\n                        </pci_gpu_link_info>\n                        <pci_bridge_chip>\n                                <bridge_chip_type>N/A</bridge_chip_type>\n                                <bridge_chip_fw>N/A</bridge_chip_fw>\n                        </pci_bridge_chip>\n                        <replay_counter>0</replay_counter>\n                        <replay_rollover_counter>0</replay_rollover_counter>\n                        <tx_util>0 KB/s</tx_util>\n                        <rx_util>0 KB/s</rx_util>\n                </pci>\n                <fan_speed>0 %</fan_speed>\n                <performance_state>P8</performance_state>\n                <clocks_throttle_reasons>\n                        <clocks_throttle_reason_gpu_idle>Active</clocks_throttle_reason_gpu_idle>\n                        <clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n                        <clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n                        <clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n                        <clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n                        <clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n                        <clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n                        <clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n                        <clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n                </clocks_throttle_reasons>\n                <fb_memory_usage>\n                        <total>5912 MiB</total>\n                        <used>0 MiB</used>\n                        <free>5912 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                        <total>256 MiB</total>\n                        <used>2 MiB</used>\n                        <free>254 MiB</free>\n                </bar1_memory_usage>\n                <compute_mode>Default</compute_mode>\n                <utilization>\n                        <gpu_util>0 %</gpu_util>\n                        <memory_util>1 %</memory_util>\n                        <encoder_util>0 %</encoder_util>\n                        <decoder_util>0 %</decoder_util>\n                </utilization>\n                <encoder_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </encoder_stats>\n                <fbc_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </fbc_stats>\n                <ecc_mode>\n                        <current_ecc>N/A</current_ecc>\n                        <pending_ecc>N/A</pending_ecc>\n                </ecc_mode>\n                <ecc_errors>\n                        <volatile>\n                                <sram_correctable>N/A</sram_correctable>\n                                <sram_uncorrectable>N/A</sram_uncorrectable>\n                                <dram_correctable>N/A</dram_correctable>\n                                <dram_uncorrectable>N/A</dram_uncorrectable>\n                        </volatile>\n                        <aggregate>\n                                <sram_correctable>N/A</sram_correctable>\n                                <sram_uncorrectable>N/A</sram_uncorrectable>\n                                <dram_correctable>N/A</dram_correctable>\n                                <dram_uncorrectable>N/A</dram_uncorrectable>\n                        </aggregate>\n                </ecc_errors>\n                <retired_pages>\n                        <multiple_single_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </multiple_single_bit_retirement>\n                        <double_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </double_bit_retirement>\n                        <pending_retirement>N/A</pending_retirement>\n                </retired_pages>\n                <temperature>\n                        <gpu_temp>40 C</gpu_temp>\n                        <gpu_temp_max_threshold>96 C</gpu_temp_max_threshold>\n                        <gpu_temp_slow_threshold>93 C</gpu_temp_slow_threshold>\n                        <gpu_temp_max_gpu_threshold>91 C</gpu_temp_max_gpu_threshold>\n                        <memory_temp>N/A</memory_temp>\n                        <gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n                </temperature>\n                <power_readings>\n                        <power_state>P8</power_state>\n                        <power_management>Supported</power_management>\n                        <power_draw>8.93 W</power_draw>\n                        <power_limit>130.00 W</power_limit>\n                        <default_power_limit>130.00 W</default_power_limit>\n                        <enforced_power_limit>130.00 W</enforced_power_limit>\n                        <min_power_limit>70.00 W</min_power_limit>\n                        <max_power_limit>130.00 W</max_power_limit>\n                </power_readings>\n                <clocks>\n                        <graphics_clock>300 MHz</graphics_clock>\n                        <sm_clock>300 MHz</sm_clock>\n                        <mem_clock>405 MHz</mem_clock>\n                        <video_clock>540 MHz</video_clock>\n                </clocks>\n                <applications_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                        <mem_clock>N/A</mem_clock>\n                </applications_clocks>\n                <default_applications_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                        <mem_clock>N/A</mem_clock>\n                </default_applications_clocks>\n                <max_clocks>\n                        <graphics_clock>2145 MHz</graphics_clock>\n                        <sm_clock>2145 MHz</sm_clock>\n                        <mem_clock>4001 MHz</mem_clock>\n                        <video_clock>1950 MHz</video_clock>\n                </max_clocks>\n                <max_customer_boost_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                </max_customer_boost_clocks>\n                <clock_policy>\n                        <auto_boost>N/A</auto_boost>\n                        <auto_boost_default>N/A</auto_boost_default>\n                </clock_policy>\n                <supported_clocks>N/A</supported_clocks>\n                <processes>\n                </processes>\n                <accounted_processes>\n                </accounted_processes>\n        </gpu>\n\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/quadro-p2000-v12.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v12.dtd\">\n<nvidia_smi_log>\n\t<timestamp>Wed Sep 20 09:37:38 2023</timestamp>\n\t<driver_version>525.125.06</driver_version>\n\t<cuda_version>12.0</cuda_version>\n\t<attached_gpus>1</attached_gpus>\n\t<gpu id=\"00000000:17:00.0\">\n\t\t<product_name>Quadro P2000</product_name>\n\t\t<product_brand>Quadro</product_brand>\n\t\t<product_architecture>Pascal</product_architecture>\n\t\t<display_mode>Disabled</display_mode>\n\t\t<display_active>Disabled</display_active>\n\t\t<persistence_mode>Enabled</persistence_mode>\n\t\t<mig_mode>\n\t\t\t<current_mig>N/A</current_mig>\n\t\t\t<pending_mig>N/A</pending_mig>\n\t\t</mig_mode>\n\t\t<mig_devices>\n\t\t\tNone\n\t\t</mig_devices>\n\t\t<accounting_mode>Disabled</accounting_mode>\n\t\t<accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n\t\t<driver_model>\n\t\t\t<current_dm>N/A</current_dm>\n\t\t\t<pending_dm>N/A</pending_dm>\n\t\t</driver_model>\n\t\t<serial>0322218049033</serial>\n\t\t<uuid>GPU-396caaed-39ca-3199-2e68-717cdb786ec6</uuid>\n\t\t<minor_number>0</minor_number>\n\t\t<vbios_version>86.06.3F.00.30</vbios_version>\n\t\t<multigpu_board>No</multigpu_board>\n\t\t<board_id>0x1700</board_id>\n\t\t<board_part_number>900-5G410-0100-000</board_part_number>\n\t\t<gpu_part_number>1C30-875-A1</gpu_part_number>\n\t\t<gpu_module_id>1</gpu_module_id>\n\t\t<inforom_version>\n\t\t\t<img_version>G410.0502.00.02</img_version>\n\t\t\t<oem_object>1.1</oem_object>\n\t\t\t<ecc_object>N/A</ecc_object>\n\t\t\t<pwr_object>N/A</pwr_object>\n\t\t</inforom_version>\n\t\t<gpu_operation_mode>\n\t\t\t<current_gom>N/A</current_gom>\n\t\t\t<pending_gom>N/A</pending_gom>\n\t\t</gpu_operation_mode>\n\t\t<gsp_firmware_version>N/A</gsp_firmware_version>\n\t\t<gpu_virtualization_mode>\n\t\t\t<virtualization_mode>None</virtualization_mode>\n\t\t\t<host_vgpu_mode>N/A</host_vgpu_mode>\n\t\t</gpu_virtualization_mode>\n\t\t<ibmnpu>\n\t\t\t<relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n\t\t</ibmnpu>\n\t\t<pci>\n\t\t\t<pci_bus>17</pci_bus>\n\t\t\t<pci_device>00</pci_device>\n\t\t\t<pci_domain>0000</pci_domain>\n\t\t\t<pci_device_id>1C3010DE</pci_device_id>\n\t\t\t<pci_bus_id>00000000:17:00.0</pci_bus_id>\n\t\t\t<pci_sub_system_id>11B31028</pci_sub_system_id>\n\t\t\t<pci_gpu_link_info>\n\t\t\t\t<pcie_gen>\n\t\t\t\t\t<max_link_gen>3</max_link_gen>\n\t\t\t\t\t<current_link_gen>1</current_link_gen>\n\t\t\t\t\t<device_current_link_gen>1</device_current_link_gen>\n\t\t\t\t\t<max_device_link_gen>3</max_device_link_gen>\n\t\t\t\t\t<max_host_link_gen>3</max_host_link_gen>\n\t\t\t\t</pcie_gen>\n\t\t\t\t<link_widths>\n\t\t\t\t\t<max_link_width>16x</max_link_width>\n\t\t\t\t\t<current_link_width>8x</current_link_width>\n\t\t\t\t</link_widths>\n\t\t\t</pci_gpu_link_info>\n\t\t\t<pci_bridge_chip>\n\t\t\t\t<bridge_chip_type>N/A</bridge_chip_type>\n\t\t\t\t<bridge_chip_fw>N/A</bridge_chip_fw>\n\t\t\t</pci_bridge_chip>\n\t\t\t<replay_counter>0</replay_counter>\n\t\t\t<replay_rollover_counter>0</replay_rollover_counter>\n\t\t\t<tx_util>0 KB/s</tx_util>\n\t\t\t<rx_util>0 KB/s</rx_util>\n\t\t\t<atomic_caps_inbound>N/A</atomic_caps_inbound>\n\t\t\t<atomic_caps_outbound>N/A</atomic_caps_outbound>\n\t\t</pci>\n\t\t<fan_speed>46 %</fan_speed>\n\t\t<performance_state>P8</performance_state>\n\t\t<clocks_throttle_reasons>\n\t\t\t<clocks_throttle_reason_gpu_idle>Active</clocks_throttle_reason_gpu_idle>\n\t\t\t<clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n\t\t\t<clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n\t\t\t<clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n\t\t\t<clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n\t\t\t<clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n\t\t\t<clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n\t\t\t<clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n\t\t\t<clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n\t\t</clocks_throttle_reasons>\n\t\t<fb_memory_usage>\n\t\t\t<total>5120 MiB</total>\n\t\t\t<reserved>66 MiB</reserved>\n\t\t\t<used>1 MiB</used>\n\t\t\t<free>5051 MiB</free>\n\t\t</fb_memory_usage>\n\t\t<bar1_memory_usage>\n\t\t\t<total>256 MiB</total>\n\t\t\t<used>5 MiB</used>\n\t\t\t<free>251 MiB</free>\n\t\t</bar1_memory_usage>\n\t\t<compute_mode>Default</compute_mode>\n\t\t<utilization>\n\t\t\t<gpu_util>0 %</gpu_util>\n\t\t\t<memory_util>0 %</memory_util>\n\t\t\t<encoder_util>0 %</encoder_util>\n\t\t\t<decoder_util>0 %</decoder_util>\n\t\t</utilization>\n\t\t<encoder_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</encoder_stats>\n\t\t<fbc_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</fbc_stats>\n\t\t<ecc_mode>\n\t\t\t<current_ecc>N/A</current_ecc>\n\t\t\t<pending_ecc>N/A</pending_ecc>\n\t\t</ecc_mode>\n\t\t<ecc_errors>\n\t\t\t<volatile>\n\t\t\t\t<single_bit>\n\t\t\t\t\t<device_memory>N/A</device_memory>\n\t\t\t\t\t<register_file>N/A</register_file>\n\t\t\t\t\t<l1_cache>N/A</l1_cache>\n\t\t\t\t\t<l2_cache>N/A</l2_cache>\n\t\t\t\t\t<texture_memory>N/A</texture_memory>\n\t\t\t\t\t<texture_shm>N/A</texture_shm>\n\t\t\t\t\t<cbu>N/A</cbu>\n\t\t\t\t\t<total>N/A</total>\n\t\t\t\t</single_bit>\n\t\t\t\t<double_bit>\n\t\t\t\t\t<device_memory>N/A</device_memory>\n\t\t\t\t\t<register_file>N/A</register_file>\n\t\t\t\t\t<l1_cache>N/A</l1_cache>\n\t\t\t\t\t<l2_cache>N/A</l2_cache>\n\t\t\t\t\t<texture_memory>N/A</texture_memory>\n\t\t\t\t\t<texture_shm>N/A</texture_shm>\n\t\t\t\t\t<cbu>N/A</cbu>\n\t\t\t\t\t<total>N/A</total>\n\t\t\t\t</double_bit>\n\t\t\t</volatile>\n\t\t\t<aggregate>\n\t\t\t\t<single_bit>\n\t\t\t\t\t<device_memory>N/A</device_memory>\n\t\t\t\t\t<register_file>N/A</register_file>\n\t\t\t\t\t<l1_cache>N/A</l1_cache>\n\t\t\t\t\t<l2_cache>N/A</l2_cache>\n\t\t\t\t\t<texture_memory>N/A</texture_memory>\n\t\t\t\t\t<texture_shm>N/A</texture_shm>\n\t\t\t\t\t<cbu>N/A</cbu>\n\t\t\t\t\t<total>N/A</total>\n\t\t\t\t</single_bit>\n\t\t\t\t<double_bit>\n\t\t\t\t\t<device_memory>N/A</device_memory>\n\t\t\t\t\t<register_file>N/A</register_file>\n\t\t\t\t\t<l1_cache>N/A</l1_cache>\n\t\t\t\t\t<l2_cache>N/A</l2_cache>\n\t\t\t\t\t<texture_memory>N/A</texture_memory>\n\t\t\t\t\t<texture_shm>N/A</texture_shm>\n\t\t\t\t\t<cbu>N/A</cbu>\n\t\t\t\t\t<total>N/A</total>\n\t\t\t\t</double_bit>\n\t\t\t</aggregate>\n\t\t</ecc_errors>\n\t\t<retired_pages>\n\t\t\t<multiple_single_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</multiple_single_bit_retirement>\n\t\t\t<double_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</double_bit_retirement>\n\t\t\t<pending_blacklist>N/A</pending_blacklist>\n\t\t\t<pending_retirement>N/A</pending_retirement>\n\t\t</retired_pages>\n\t\t<remapped_rows>N/A</remapped_rows>\n\t\t<temperature>\n\t\t\t<gpu_temp>34 C</gpu_temp>\n\t\t\t<gpu_temp_tlimit>N/A</gpu_temp_tlimit>\n\t\t\t<gpu_temp_max_threshold>104 C</gpu_temp_max_threshold>\n\t\t\t<gpu_temp_slow_threshold>101 C</gpu_temp_slow_threshold>\n\t\t\t<gpu_temp_max_gpu_threshold>N/A</gpu_temp_max_gpu_threshold>\n\t\t\t<gpu_target_temperature>83 C</gpu_target_temperature>\n\t\t\t<memory_temp>N/A</memory_temp>\n\t\t\t<gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n\t\t</temperature>\n\t\t<supported_gpu_target_temp>\n\t\t\t<gpu_target_temp_min>65 C</gpu_target_temp_min>\n\t\t\t<gpu_target_temp_max>98 C</gpu_target_temp_max>\n\t\t</supported_gpu_target_temp>\n\t\t<power_readings>\n\t\t\t<power_state>P8</power_state>\n\t\t\t<power_management>Supported</power_management>\n\t\t\t<power_draw>4.61 W</power_draw>\n\t\t\t<power_limit>75.00 W</power_limit>\n\t\t\t<default_power_limit>75.00 W</default_power_limit>\n\t\t\t<enforced_power_limit>75.00 W</enforced_power_limit>\n\t\t\t<min_power_limit>75.00 W</min_power_limit>\n\t\t\t<max_power_limit>75.00 W</max_power_limit>\n\t\t</power_readings>\n\t\t<clocks>\n\t\t\t<graphics_clock>139 MHz</graphics_clock>\n\t\t\t<sm_clock>139 MHz</sm_clock>\n\t\t\t<mem_clock>405 MHz</mem_clock>\n\t\t\t<video_clock>544 MHz</video_clock>\n\t\t</clocks>\n\t\t<applications_clocks>\n\t\t\t<graphics_clock>1075 MHz</graphics_clock>\n\t\t\t<mem_clock>3504 MHz</mem_clock>\n\t\t</applications_clocks>\n\t\t<default_applications_clocks>\n\t\t\t<graphics_clock>1075 MHz</graphics_clock>\n\t\t\t<mem_clock>3504 MHz</mem_clock>\n\t\t</default_applications_clocks>\n\t\t<deferred_clocks>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</deferred_clocks>\n\t\t<max_clocks>\n\t\t\t<graphics_clock>1721 MHz</graphics_clock>\n\t\t\t<sm_clock>1721 MHz</sm_clock>\n\t\t\t<mem_clock>3504 MHz</mem_clock>\n\t\t\t<video_clock>1556 MHz</video_clock>\n\t\t</max_clocks>\n\t\t<max_customer_boost_clocks>\n\t\t\t<graphics_clock>1721 MHz</graphics_clock>\n\t\t</max_customer_boost_clocks>\n\t\t<clock_policy>\n\t\t\t<auto_boost>N/A</auto_boost>\n\t\t\t<auto_boost_default>N/A</auto_boost_default>\n\t\t</clock_policy>\n\t\t<voltage>\n\t\t\t<graphics_volt>N/A</graphics_volt>\n\t\t</voltage>\n\t\t<fabric>\n\t\t\t<state>N/A</state>\n\t\t\t<status>N/A</status>\n\t\t</fabric>\n\t\t<supported_clocks>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>3504 MHz</value>\n\t\t\t\t<supported_graphics_clock>1721 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1708 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1683 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1670 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1657 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1632 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1607 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1594 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1582 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1569 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1556 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1544 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1531 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1518 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1506 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1493 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1468 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1442 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1430 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1417 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1404 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1392 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1379 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1366 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1354 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1341 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1328 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1316 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1303 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1278 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1265 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1252 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1227 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1202 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1189 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1177 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1164 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1151 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1139 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1126 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1113 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1101 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1088 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1075 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1063 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1037 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1012 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>999 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>987 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>974 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>961 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>949 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>936 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>923 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>911 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>898 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>873 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>847 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>835 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>822 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>797 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>784 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>772 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>759 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>746 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>734 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>721 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>708 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>696 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>683 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>670 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>658 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>632 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>607 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>594 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>582 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>569 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>556 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>544 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>531 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>518 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>506 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>493 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>468 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>442 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>430 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>417 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>392 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>379 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>367 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>354 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>341 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>329 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>316 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>303 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>291 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>278 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>265 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>253 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>227 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>202 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>189 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>177 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>164 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>151 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>139 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>810 MHz</value>\n\t\t\t\t<supported_graphics_clock>1721 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1708 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1683 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1670 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1657 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1632 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1607 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1594 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1582 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1569 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1556 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1544 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1531 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1518 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1506 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1493 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1468 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1442 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1430 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1417 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1404 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1392 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1379 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1366 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1354 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1341 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1328 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1316 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1303 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1278 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1265 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1252 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1227 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1202 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1189 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1177 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1164 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1151 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1139 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1126 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1113 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1101 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1088 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1075 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1063 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1037 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1012 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>999 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>987 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>974 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>961 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>949 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>936 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>923 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>911 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>898 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>873 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>847 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>835 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>822 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>797 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>784 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>772 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>759 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>746 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>734 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>721 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>708 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>696 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>683 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>670 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>658 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>632 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>607 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>594 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>582 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>569 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>556 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>544 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>531 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>518 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>506 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>493 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>468 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>442 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>430 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>417 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>392 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>379 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>367 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>354 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>341 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>329 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>316 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>303 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>291 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>278 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>265 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>253 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>227 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>202 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>189 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>177 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>164 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>151 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>139 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>405 MHz</value>\n\t\t\t\t<supported_graphics_clock>607 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>594 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>582 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>569 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>556 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>544 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>531 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>518 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>506 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>493 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>468 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>442 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>430 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>417 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>392 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>379 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>367 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>354 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>341 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>329 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>316 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>303 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>291 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>278 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>265 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>253 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>227 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>202 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>189 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>177 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>164 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>151 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>139 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t</supported_clocks>\n\t\t<processes>\n\t\t</processes>\n\t\t<accounted_processes>\n\t\t</accounted_processes>\n\t</gpu>\n\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/quadro-p400.xml",
    "content": "<?xml version=\"1.0\" ?>\n<nvidia_smi_log>\n        <timestamp>Mon Mar 11 17:03:27 2019</timestamp>\n        <driver_version>418.43</driver_version>\n        <cuda_version>10.1</cuda_version>\n        <attached_gpus>1</attached_gpus>\n        <gpu id=\"00000000:43:00.0\">\n                <product_name>Quadro P400</product_name>\n                <product_brand>Quadro</product_brand>\n                <display_mode>Disabled</display_mode>\n                <display_active>Disabled</display_active>\n                <persistence_mode>Disabled</persistence_mode>\n                <accounting_mode>Disabled</accounting_mode>\n                <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n                <driver_model>\n                        <current_dm>N/A</current_dm>\n                        <pending_dm>N/A</pending_dm>\n                </driver_model>\n                <serial>0424418054852</serial>\n                <uuid>GPU-8f750be4-dfbc-23b9-b33f-da729a536494</uuid>\n                <minor_number>0</minor_number>\n                <vbios_version>86.07.3B.00.4A</vbios_version>\n                <multigpu_board>No</multigpu_board>\n                <board_id>0x4300</board_id>\n                <gpu_part_number>900-5G212-1701-000</gpu_part_number>\n                <inforom_version>\n                        <img_version>G212.0500.00.01</img_version>\n                        <oem_object>1.1</oem_object>\n                        <ecc_object>N/A</ecc_object>\n                        <pwr_object>N/A</pwr_object>\n                </inforom_version>\n                <gpu_operation_mode>\n                        <current_gom>N/A</current_gom>\n                        <pending_gom>N/A</pending_gom>\n                </gpu_operation_mode>\n                <gpu_virtualization_mode>\n                        <virtualization_mode>None</virtualization_mode>\n                </gpu_virtualization_mode>\n                <ibmnpu>\n                        <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n                </ibmnpu>\n                <pci>\n                        <pci_bus>43</pci_bus>\n                        <pci_device>00</pci_device>\n                        <pci_domain>0000</pci_domain>\n                        <pci_device_id>1CB310DE</pci_device_id>\n                        <pci_bus_id>00000000:43:00.0</pci_bus_id>\n                        <pci_sub_system_id>11BE10DE</pci_sub_system_id>\n                        <pci_gpu_link_info>\n                                <pcie_gen>\n                                        <max_link_gen>3</max_link_gen>\n                                        <current_link_gen>1</current_link_gen>\n                                </pcie_gen>\n                                <link_widths>\n                                        <max_link_width>16x</max_link_width>\n                                        <current_link_width>16x</current_link_width>\n                                </link_widths>\n                        </pci_gpu_link_info>\n                        <pci_bridge_chip>\n                                <bridge_chip_type>N/A</bridge_chip_type>\n                                <bridge_chip_fw>N/A</bridge_chip_fw>\n                        </pci_bridge_chip>\n                        <replay_counter>0</replay_counter>\n                        <replay_rollover_counter>0</replay_rollover_counter>\n                        <tx_util>0 KB/s</tx_util>\n                        <rx_util>0 KB/s</rx_util>\n                </pci>\n                <fan_speed>34 %</fan_speed>\n                <performance_state>P8</performance_state>\n                <clocks_throttle_reasons>\n                        <clocks_throttle_reason_gpu_idle>Active</clocks_throttle_reason_gpu_idle>\n                        <clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n                        <clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n                        <clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n                        <clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n                        <clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n                        <clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n                        <clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n                        <clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n                </clocks_throttle_reasons>\n                <fb_memory_usage>\n                        <total>1998 MiB</total>\n                        <used>0 MiB</used>\n                        <free>1998 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                        <total>256 MiB</total>\n                        <used>2 MiB</used>\n                        <free>254 MiB</free>\n                </bar1_memory_usage>\n                <compute_mode>Default</compute_mode>\n                <utilization>\n                        <gpu_util>0 %</gpu_util>\n                        <memory_util>3 %</memory_util>\n                        <encoder_util>0 %</encoder_util>\n                        <decoder_util>0 %</decoder_util>\n                </utilization>\n                <encoder_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </encoder_stats>\n                <fbc_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </fbc_stats>\n                <ecc_mode>\n                        <current_ecc>N/A</current_ecc>\n                        <pending_ecc>N/A</pending_ecc>\n                </ecc_mode>\n                <ecc_errors>\n                        <volatile>\n                                <single_bit>\n                                        <device_memory>N/A</device_memory>\n                                        <register_file>N/A</register_file>\n                                        <l1_cache>N/A</l1_cache>\n                                        <l2_cache>N/A</l2_cache>\n                                        <texture_memory>N/A</texture_memory>\n                                        <texture_shm>N/A</texture_shm>\n                                        <cbu>N/A</cbu>\n                                        <total>N/A</total>\n                                </single_bit>\n                                <double_bit>\n                                        <device_memory>N/A</device_memory>\n                                        <register_file>N/A</register_file>\n                                        <l1_cache>N/A</l1_cache>\n                                        <l2_cache>N/A</l2_cache>\n                                        <texture_memory>N/A</texture_memory>\n                                        <texture_shm>N/A</texture_shm>\n                                        <cbu>N/A</cbu>\n                                        <total>N/A</total>\n                                </double_bit>\n                        </volatile>\n                        <aggregate>\n                                <single_bit>\n                                        <device_memory>N/A</device_memory>\n                                        <register_file>N/A</register_file>\n                                        <l1_cache>N/A</l1_cache>\n                                        <l2_cache>N/A</l2_cache>\n                                        <texture_memory>N/A</texture_memory>\n                                        <texture_shm>N/A</texture_shm>\n                                        <cbu>N/A</cbu>\n                                        <total>N/A</total>\n                                </single_bit>\n                                <double_bit>\n                                        <device_memory>N/A</device_memory>\n                                        <register_file>N/A</register_file>\n                                        <l1_cache>N/A</l1_cache>\n                                        <l2_cache>N/A</l2_cache>\n                                        <texture_memory>N/A</texture_memory>\n                                        <texture_shm>N/A</texture_shm>\n                                        <cbu>N/A</cbu>\n                                        <total>N/A</total>\n                                </double_bit>\n                        </aggregate>\n                </ecc_errors>\n                <retired_pages>\n                        <multiple_single_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </multiple_single_bit_retirement>\n                        <double_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </double_bit_retirement>\n                        <pending_retirement>N/A</pending_retirement>\n                </retired_pages>\n                <temperature>\n                        <gpu_temp>33 C</gpu_temp>\n                        <gpu_temp_max_threshold>103 C</gpu_temp_max_threshold>\n                        <gpu_temp_slow_threshold>100 C</gpu_temp_slow_threshold>\n                        <gpu_temp_max_gpu_threshold>N/A</gpu_temp_max_gpu_threshold>\n                        <memory_temp>N/A</memory_temp>\n                        <gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n                </temperature>\n                <power_readings>\n                        <power_state>P8</power_state>\n                        <power_management>N/A</power_management>\n                        <power_draw>N/A</power_draw>\n                        <power_limit>N/A</power_limit>\n                        <default_power_limit>N/A</default_power_limit>\n                        <enforced_power_limit>N/A</enforced_power_limit>\n                        <min_power_limit>N/A</min_power_limit>\n                        <max_power_limit>N/A</max_power_limit>\n                </power_readings>\n                <clocks>\n                        <graphics_clock>139 MHz</graphics_clock>\n                        <sm_clock>139 MHz</sm_clock>\n                        <mem_clock>405 MHz</mem_clock>\n                        <video_clock>544 MHz</video_clock>\n                </clocks>\n                <applications_clocks>\n                        <graphics_clock>1227 MHz</graphics_clock>\n                        <mem_clock>2005 MHz</mem_clock>\n                </applications_clocks>\n                <default_applications_clocks>\n                        <graphics_clock>1227 MHz</graphics_clock>\n                        <mem_clock>2005 MHz</mem_clock>\n                </default_applications_clocks>\n                <max_clocks>\n                        <graphics_clock>1252 MHz</graphics_clock>\n                        <sm_clock>1252 MHz</sm_clock>\n                        <mem_clock>2005 MHz</mem_clock>\n                        <video_clock>1126 MHz</video_clock>\n                </max_clocks>\n                <max_customer_boost_clocks>\n                        <graphics_clock>1252 MHz</graphics_clock>\n                </max_customer_boost_clocks>\n                <clock_policy>\n                        <auto_boost>N/A</auto_boost>\n                        <auto_boost_default>N/A</auto_boost_default>\n                </clock_policy>\n                <supported_clocks>\n                        <supported_mem_clock>\n                                <value>2005 MHz</value>\n                                <supported_graphics_clock>1252 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1227 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1202 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1189 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1177 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1164 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1151 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1139 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1126 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1113 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1101 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1088 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1075 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1063 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1037 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1012 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>999 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>987 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>974 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>961 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>949 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>936 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>923 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>911 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>898 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>873 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>847 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>835 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>822 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>797 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>784 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>772 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>759 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>746 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>734 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>721 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>708 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>696 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>683 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>670 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>658 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>632 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>607 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>594 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>582 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>569 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>556 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>544 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>531 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>518 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>506 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>493 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>468 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>442 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>430 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>417 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>392 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>379 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>367 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>354 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>341 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>329 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>316 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>303 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>291 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>278 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>265 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>253 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>227 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>202 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>189 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>177 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>164 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>151 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>139 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>810 MHz</value>\n                                <supported_graphics_clock>1252 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1227 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1202 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1189 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1177 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1164 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1151 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1139 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1126 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1113 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1101 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1088 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1075 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1063 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1037 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1012 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>999 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>987 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>974 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>961 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>949 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>936 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>923 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>911 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>898 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>873 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>847 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>835 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>822 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>797 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>784 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>772 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>759 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>746 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>734 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>721 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>708 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>696 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>683 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>670 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>658 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>632 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>607 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>594 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>582 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>569 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>556 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>544 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>531 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>518 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>506 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>493 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>468 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>442 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>430 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>417 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>392 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>379 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>367 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>354 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>341 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>329 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>316 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>303 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>291 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>278 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>265 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>253 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>227 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>202 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>189 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>177 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>164 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>151 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>139 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>405 MHz</value>\n                                <supported_graphics_clock>607 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>594 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>582 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>569 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>556 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>544 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>531 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>518 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>506 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>493 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>468 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>442 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>430 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>417 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>392 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>379 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>367 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>354 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>341 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>329 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>316 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>303 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>291 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>278 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>265 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>253 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>227 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>202 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>189 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>177 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>164 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>151 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>139 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                </supported_clocks>\n                <processes>\n                </processes>\n                <accounted_processes>\n                </accounted_processes>\n        </gpu>\n\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/rtx-3060-v12.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v12.dtd\">\n<nvidia_smi_log>\n\t<timestamp>Sun Mar 2 15:02:02 2025</timestamp>\n\t<driver_version>570.124.04</driver_version>\n\t<cuda_version>12.8</cuda_version>\n\t<attached_gpus>1</attached_gpus>\n\t<gpu id=\"00000000:2D:00.0\">\n\t\t<product_name>NVIDIA GeForce RTX 3060</product_name>\n\t\t<product_brand>GeForce</product_brand>\n\t\t<product_architecture>Ampere</product_architecture>\n\t\t<display_mode>Disabled</display_mode>\n\t\t<display_active>Disabled</display_active>\n\t\t<persistence_mode>Enabled</persistence_mode>\n\t\t<addressing_mode>None</addressing_mode>\n\t\t<mig_mode>\n\t\t\t<current_mig>N/A</current_mig>\n\t\t\t<pending_mig>N/A</pending_mig>\n\t\t</mig_mode>\n\t\t<mig_devices>\n\t\t\tNone\n\t\t</mig_devices>\n\t\t<accounting_mode>Disabled</accounting_mode>\n\t\t<accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n\t\t<driver_model>\n\t\t\t<current_dm>N/A</current_dm>\n\t\t\t<pending_dm>N/A</pending_dm>\n\t\t</driver_model>\n\t\t<serial>N/A</serial>\n\t\t<uuid>GPU-d6889ff6-2523-9142-ca3c-1ca3f396a625</uuid>\n\t\t<minor_number>0</minor_number>\n\t\t<vbios_version>94.04.71.00.69</vbios_version>\n\t\t<multigpu_board>No</multigpu_board>\n\t\t<board_id>0x2d00</board_id>\n\t\t<board_part_number>N/A</board_part_number>\n\t\t<gpu_part_number>2487-150-A1</gpu_part_number>\n\t\t<gpu_fru_part_number>N/A</gpu_fru_part_number>\n\t\t<platformInfo>\n\t\t\t<chassis_serial_number>N/A</chassis_serial_number>\n\t\t\t<slot_number>N/A</slot_number>\n\t\t\t<tray_index>N/A</tray_index>\n\t\t\t<host_id>N/A</host_id>\n\t\t\t<peer_type>N/A</peer_type>\n\t\t\t<module_id>1</module_id>\n\t\t\t<gpu_fabric_guid>N/A</gpu_fabric_guid>\n\t\t</platformInfo>\n\t\t<inforom_version>\n\t\t\t<img_version>G001.0000.03.03</img_version>\n\t\t\t<oem_object>2.0</oem_object>\n\t\t\t<ecc_object>N/A</ecc_object>\n\t\t\t<pwr_object>N/A</pwr_object>\n\t\t</inforom_version>\n\t\t<inforom_bbx_flush>\n\t\t\t<latest_timestamp>N/A</latest_timestamp>\n\t\t\t<latest_duration>N/A</latest_duration>\n\t\t</inforom_bbx_flush>\n\t\t<gpu_operation_mode>\n\t\t\t<current_gom>N/A</current_gom>\n\t\t\t<pending_gom>N/A</pending_gom>\n\t\t</gpu_operation_mode>\n\t\t<c2c_mode>N/A</c2c_mode>\n\t\t<gpu_virtualization_mode>\n\t\t\t<virtualization_mode>None</virtualization_mode>\n\t\t\t<host_vgpu_mode>N/A</host_vgpu_mode>\n\t\t\t<vgpu_heterogeneous_mode>N/A</vgpu_heterogeneous_mode>\n\t\t</gpu_virtualization_mode>\n\t\t<gpu_reset_status>\n\t\t\t<reset_required>Requested functionality has been deprecated</reset_required>\n\t\t\t<drain_and_reset_recommended>Requested functionality has been deprecated</drain_and_reset_recommended>\n\t\t</gpu_reset_status>\n\t\t<gpu_recovery_action>None</gpu_recovery_action>\n\t\t<gsp_firmware_version>570.124.04</gsp_firmware_version>\n\t\t<ibmnpu>\n\t\t\t<relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n\t\t</ibmnpu>\n\t\t<pci>\n\t\t\t<pci_bus>2D</pci_bus>\n\t\t\t<pci_device>00</pci_device>\n\t\t\t<pci_domain>0000</pci_domain>\n\t\t\t<pci_base_class>3</pci_base_class>\n\t\t\t<pci_sub_class>0</pci_sub_class>\n\t\t\t<pci_device_id>248710DE</pci_device_id>\n\t\t\t<pci_bus_id>00000000:2D:00.0</pci_bus_id>\n\t\t\t<pci_sub_system_id>36583842</pci_sub_system_id>\n\t\t\t<pci_gpu_link_info>\n\t\t\t\t<pcie_gen>\n\t\t\t\t\t<max_link_gen>4</max_link_gen>\n\t\t\t\t\t<current_link_gen>1</current_link_gen>\n\t\t\t\t\t<device_current_link_gen>1</device_current_link_gen>\n\t\t\t\t\t<max_device_link_gen>4</max_device_link_gen>\n\t\t\t\t\t<max_host_link_gen>4</max_host_link_gen>\n\t\t\t\t</pcie_gen>\n\t\t\t\t<link_widths>\n\t\t\t\t\t<max_link_width>16x</max_link_width>\n\t\t\t\t\t<current_link_width>16x</current_link_width>\n\t\t\t\t</link_widths>\n\t\t\t</pci_gpu_link_info>\n\t\t\t<pci_bridge_chip>\n\t\t\t\t<bridge_chip_type>N/A</bridge_chip_type>\n\t\t\t\t<bridge_chip_fw>N/A</bridge_chip_fw>\n\t\t\t</pci_bridge_chip>\n\t\t\t<replay_counter>0</replay_counter>\n\t\t\t<replay_rollover_counter>0</replay_rollover_counter>\n\t\t\t<tx_util>550 KB/s</tx_util>\n\t\t\t<rx_util>500 KB/s</rx_util>\n\t\t\t<atomic_caps_outbound>N/A</atomic_caps_outbound>\n\t\t\t<atomic_caps_inbound>N/A</atomic_caps_inbound>\n\t\t</pci>\n\t\t<fan_speed>0 %</fan_speed>\n\t\t<performance_state>P8</performance_state>\n\t\t<clocks_event_reasons>\n\t\t\t<clocks_event_reason_gpu_idle>Active</clocks_event_reason_gpu_idle>\n\t\t\t<clocks_event_reason_applications_clocks_setting>Not Active</clocks_event_reason_applications_clocks_setting>\n\t\t\t<clocks_event_reason_sw_power_cap>Not Active</clocks_event_reason_sw_power_cap>\n\t\t\t<clocks_event_reason_hw_slowdown>Not Active</clocks_event_reason_hw_slowdown>\n\t\t\t<clocks_event_reason_hw_thermal_slowdown>Not Active</clocks_event_reason_hw_thermal_slowdown>\n\t\t\t<clocks_event_reason_hw_power_brake_slowdown>Not Active</clocks_event_reason_hw_power_brake_slowdown>\n\t\t\t<clocks_event_reason_sync_boost>Not Active</clocks_event_reason_sync_boost>\n\t\t\t<clocks_event_reason_sw_thermal_slowdown>Not Active</clocks_event_reason_sw_thermal_slowdown>\n\t\t\t<clocks_event_reason_display_clocks_setting>Not Active</clocks_event_reason_display_clocks_setting>\n\t\t</clocks_event_reasons>\n\t\t<sparse_operation_mode>N/A</sparse_operation_mode>\n\t\t<fb_memory_usage>\n\t\t\t<total>12288 MiB</total>\n\t\t\t<reserved>368 MiB</reserved>\n\t\t\t<used>116 MiB</used>\n\t\t\t<free>11806 MiB</free>\n\t\t</fb_memory_usage>\n\t\t<bar1_memory_usage>\n\t\t\t<total>256 MiB</total>\n\t\t\t<used>5 MiB</used>\n\t\t\t<free>251 MiB</free>\n\t\t</bar1_memory_usage>\n\t\t<cc_protected_memory_usage>\n\t\t\t<total>0 MiB</total>\n\t\t\t<used>0 MiB</used>\n\t\t\t<free>0 MiB</free>\n\t\t</cc_protected_memory_usage>\n\t\t<compute_mode>Default</compute_mode>\n\t\t<utilization>\n\t\t\t<gpu_util>0 %</gpu_util>\n\t\t\t<memory_util>0 %</memory_util>\n\t\t\t<encoder_util>0 %</encoder_util>\n\t\t\t<decoder_util>0 %</decoder_util>\n\t\t\t<jpeg_util>0 %</jpeg_util>\n\t\t\t<ofa_util>0 %</ofa_util>\n\t\t</utilization>\n\t\t<encoder_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</encoder_stats>\n\t\t<fbc_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</fbc_stats>\n\t\t<dram_encryption_mode>\n\t\t\t<current_dram_encryption>N/A</current_dram_encryption>\n\t\t\t<pending_dram_encryption>N/A</pending_dram_encryption>\n\t\t</dram_encryption_mode>\n\t\t<ecc_mode>\n\t\t\t<current_ecc>N/A</current_ecc>\n\t\t\t<pending_ecc>N/A</pending_ecc>\n\t\t</ecc_mode>\n\t\t<ecc_errors>\n\t\t\t<volatile>\n\t\t\t\t<sram_correctable>N/A</sram_correctable>\n\t\t\t\t<sram_uncorrectable_parity>N/A</sram_uncorrectable_parity>\n\t\t\t\t<sram_uncorrectable_secded>N/A</sram_uncorrectable_secded>\n\t\t\t\t<dram_correctable>N/A</dram_correctable>\n\t\t\t\t<dram_uncorrectable>N/A</dram_uncorrectable>\n\t\t\t</volatile>\n\t\t\t<aggregate>\n\t\t\t\t<sram_correctable>N/A</sram_correctable>\n\t\t\t\t<sram_uncorrectable_parity>N/A</sram_uncorrectable_parity>\n\t\t\t\t<sram_uncorrectable_secded>N/A</sram_uncorrectable_secded>\n\t\t\t\t<dram_correctable>N/A</dram_correctable>\n\t\t\t\t<dram_uncorrectable>N/A</dram_uncorrectable>\n\t\t\t\t<sram_threshold_exceeded>N/A</sram_threshold_exceeded>\n\t\t\t</aggregate>\n\t\t\t<aggregate_uncorrectable_sram_sources>\n\t\t\t\t<sram_l2>N/A</sram_l2>\n\t\t\t\t<sram_sm>N/A</sram_sm>\n\t\t\t\t<sram_microcontroller>N/A</sram_microcontroller>\n\t\t\t\t<sram_pcie>N/A</sram_pcie>\n\t\t\t\t<sram_other>N/A</sram_other>\n\t\t\t</aggregate_uncorrectable_sram_sources>\n\t\t</ecc_errors>\n\t\t<retired_pages>\n\t\t\t<multiple_single_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</multiple_single_bit_retirement>\n\t\t\t<double_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</double_bit_retirement>\n\t\t\t<pending_blacklist>N/A</pending_blacklist>\n\t\t\t<pending_retirement>N/A</pending_retirement>\n\t\t</retired_pages>\n\t\t<remapped_rows>N/A</remapped_rows>\n\t\t<temperature>\n\t\t\t<gpu_temp>42 C</gpu_temp>\n\t\t\t<gpu_temp_tlimit>N/A</gpu_temp_tlimit>\n\t\t\t<gpu_temp_max_threshold>98 C</gpu_temp_max_threshold>\n\t\t\t<gpu_temp_slow_threshold>95 C</gpu_temp_slow_threshold>\n\t\t\t<gpu_temp_max_gpu_threshold>93 C</gpu_temp_max_gpu_threshold>\n\t\t\t<gpu_target_temperature>83 C</gpu_target_temperature>\n\t\t\t<memory_temp>N/A</memory_temp>\n\t\t\t<gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n\t\t</temperature>\n\t\t<supported_gpu_target_temp>\n\t\t\t<gpu_target_temp_min>65 C</gpu_target_temp_min>\n\t\t\t<gpu_target_temp_max>90 C</gpu_target_temp_max>\n\t\t</supported_gpu_target_temp>\n\t\t<gpu_power_readings>\n\t\t\t<power_state>P8</power_state>\n\t\t\t<average_power_draw>11.60 W</average_power_draw>\n\t\t\t<instant_power_draw>11.63 W</instant_power_draw>\n\t\t\t<current_power_limit>170.00 W</current_power_limit>\n\t\t\t<requested_power_limit>170.00 W</requested_power_limit>\n\t\t\t<default_power_limit>170.00 W</default_power_limit>\n\t\t\t<min_power_limit>100.00 W</min_power_limit>\n\t\t\t<max_power_limit>190.00 W</max_power_limit>\n\t\t</gpu_power_readings>\n\t\t<gpu_memory_power_readings>\n\t\t\t<average_power_draw>N/A</average_power_draw>\n\t\t\t<instant_power_draw>N/A</instant_power_draw>\n\t\t</gpu_memory_power_readings>\n\t\t<module_power_readings>\n\t\t\t<power_state>P8</power_state>\n\t\t\t<average_power_draw>N/A</average_power_draw>\n\t\t\t<instant_power_draw>N/A</instant_power_draw>\n\t\t\t<current_power_limit>N/A</current_power_limit>\n\t\t\t<requested_power_limit>N/A</requested_power_limit>\n\t\t\t<default_power_limit>N/A</default_power_limit>\n\t\t\t<min_power_limit>N/A</min_power_limit>\n\t\t\t<max_power_limit>N/A</max_power_limit>\n\t\t</module_power_readings>\n\t\t<power_smoothing>N/A</power_smoothing>\n\t\t<power_profiles>\n\t\t\t<power_profile_requested_profiles>N/A</power_profile_requested_profiles>\n\t\t\t<power_profile_enforced_profiles>N/A</power_profile_enforced_profiles>\n\t\t</power_profiles>\n\t\t<clocks>\n\t\t\t<graphics_clock>210 MHz</graphics_clock>\n\t\t\t<sm_clock>210 MHz</sm_clock>\n\t\t\t<mem_clock>405 MHz</mem_clock>\n\t\t\t<video_clock>555 MHz</video_clock>\n\t\t</clocks>\n\t\t<applications_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</applications_clocks>\n\t\t<default_applications_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</default_applications_clocks>\n\t\t<deferred_clocks>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</deferred_clocks>\n\t\t<max_clocks>\n\t\t\t<graphics_clock>2145 MHz</graphics_clock>\n\t\t\t<sm_clock>2145 MHz</sm_clock>\n\t\t\t<mem_clock>7501 MHz</mem_clock>\n\t\t\t<video_clock>1995 MHz</video_clock>\n\t\t</max_clocks>\n\t\t<max_customer_boost_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t</max_customer_boost_clocks>\n\t\t<clock_policy>\n\t\t\t<auto_boost>N/A</auto_boost>\n\t\t\t<auto_boost_default>N/A</auto_boost_default>\n\t\t</clock_policy>\n\t\t<voltage>\n\t\t\t<graphics_volt>N/A</graphics_volt>\n\t\t</voltage>\n\t\t<fabric>\n\t\t\t<state>N/A</state>\n\t\t\t<status>N/A</status>\n\t\t\t<cliqueId>N/A</cliqueId>\n\t\t\t<clusterUuid>N/A</clusterUuid>\n\t\t\t<health>\n\t\t\t\t<bandwidth>N/A</bandwidth>\n\t\t\t\t<route_recovery_in_progress>N/A</route_recovery_in_progress>\n\t\t\t\t<route_unhealthy>N/A</route_unhealthy>\n\t\t\t\t<access_timeout_recovery>N/A</access_timeout_recovery>\n\t\t\t</health>\n\t\t</fabric>\n\t\t<supported_clocks>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>7501 MHz</value>\n\t\t\t\t<supported_graphics_clock>2145 MHz</supported_graphics_clock>\n\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>7301 MHz</value>\n\t\t\t\t<supported_graphics_clock>2145 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>5001 MHz</value>\n\t\t\t\t<supported_graphics_clock>2145 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>810 MHz</value>\n\t\t\t\t<supported_graphics_clock>2100 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t</supported_clocks>\n\t\t<processes>\n\t\t</processes>\n\t\t<accounted_processes>\n\t\t</accounted_processes>\n\t\t<capabilities>\n\t\t\t<egm>disabled</egm>\n\t\t</capabilities>\n\t</gpu>\n\n</nvidia_smi_log>"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v12.dtd\">\n<nvidia_smi_log>\n\t<timestamp>Thu Jul 20 17:00:50 2023</timestamp>\n\t<driver_version>536.40</driver_version>\n\t<cuda_version>12.2</cuda_version>\n\t<attached_gpus>1</attached_gpus>\n\t<gpu id=\"00000000:04:00.0\">\n\t\t<product_name>NVIDIA GeForce RTX 3080</product_name>\n\t\t<product_brand>GeForce</product_brand>\n\t\t<product_architecture>Ampere</product_architecture>\n\t\t<display_mode>Enabled</display_mode>\n\t\t<display_active>Enabled</display_active>\n\t\t<persistence_mode>N/A</persistence_mode>\n\t\t<addressing_mode>N/A</addressing_mode>\n\t\t<mig_mode>\n\t\t\t<current_mig>N/A</current_mig>\n\t\t\t<pending_mig>N/A</pending_mig>\n\t\t</mig_mode>\n\t\t<mig_devices>\n\t\t\tNone\n\t\t</mig_devices>\n\t\t<accounting_mode>Disabled</accounting_mode>\n\t\t<accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n\t\t<driver_model>\n\t\t\t<current_dm>WDDM</current_dm>\n\t\t\t<pending_dm>WDDM</pending_dm>\n\t\t</driver_model>\n\t\t<serial>N/A</serial>\n\t\t<uuid>GPU-19d6d965-2acc-f646-00f8-4c76979aabb4</uuid>\n\t\t<minor_number>N/A</minor_number>\n\t\t<vbios_version>94.02.71.40.72</vbios_version>\n\t\t<multigpu_board>No</multigpu_board>\n\t\t<board_id>0x400</board_id>\n\t\t<board_part_number>N/A</board_part_number>\n\t\t<gpu_part_number>2216-202-A1</gpu_part_number>\n\t\t<gpu_fru_part_number>N/A</gpu_fru_part_number>\n\t\t<gpu_module_id>1</gpu_module_id>\n\t\t<inforom_version>\n\t\t\t<img_version>G001.0000.03.03</img_version>\n\t\t\t<oem_object>2.0</oem_object>\n\t\t\t<ecc_object>N/A</ecc_object>\n\t\t\t<pwr_object>N/A</pwr_object>\n\t\t</inforom_version>\n\t\t<gpu_operation_mode>\n\t\t\t<current_gom>N/A</current_gom>\n\t\t\t<pending_gom>N/A</pending_gom>\n\t\t</gpu_operation_mode>\n\t\t<gsp_firmware_version>N/A</gsp_firmware_version>\n\t\t<gpu_virtualization_mode>\n\t\t\t<virtualization_mode>Pass-Through</virtualization_mode>\n\t\t\t<host_vgpu_mode>N/A</host_vgpu_mode>\n\t\t</gpu_virtualization_mode>\n\t\t<gpu_reset_status>\n\t\t\t<reset_required>No</reset_required>\n\t\t\t<drain_and_reset_recommended>N/A</drain_and_reset_recommended>\n\t\t</gpu_reset_status>\n\t\t<ibmnpu>\n\t\t\t<relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n\t\t</ibmnpu>\n\t\t<pci>\n\t\t\t<pci_bus>04</pci_bus>\n\t\t\t<pci_device>00</pci_device>\n\t\t\t<pci_domain>0000</pci_domain>\n\t\t\t<pci_device_id>221610DE</pci_device_id>\n\t\t\t<pci_bus_id>00000000:04:00.0</pci_bus_id>\n\t\t\t<pci_sub_system_id>161219DA</pci_sub_system_id>\n\t\t\t<pci_gpu_link_info>\n\t\t\t\t<pcie_gen>\n\t\t\t\t\t<max_link_gen>4</max_link_gen>\n\t\t\t\t\t<current_link_gen>4</current_link_gen>\n\t\t\t\t\t<device_current_link_gen>4</device_current_link_gen>\n\t\t\t\t\t<max_device_link_gen>4</max_device_link_gen>\n\t\t\t\t\t<max_host_link_gen>N/A</max_host_link_gen>\n\t\t\t\t</pcie_gen>\n\t\t\t\t<link_widths>\n\t\t\t\t\t<max_link_width>16x</max_link_width>\n\t\t\t\t\t<current_link_width>16x</current_link_width>\n\t\t\t\t</link_widths>\n\t\t\t</pci_gpu_link_info>\n\t\t\t<pci_bridge_chip>\n\t\t\t\t<bridge_chip_type>N/A</bridge_chip_type>\n\t\t\t\t<bridge_chip_fw>N/A</bridge_chip_fw>\n\t\t\t</pci_bridge_chip>\n\t\t\t<replay_counter>0</replay_counter>\n\t\t\t<replay_rollover_counter>0</replay_rollover_counter>\n\t\t\t<tx_util>1000 KB/s</tx_util>\n\t\t\t<rx_util>6000 KB/s</rx_util>\n\t\t\t<atomic_caps_inbound>N/A</atomic_caps_inbound>\n\t\t\t<atomic_caps_outbound>N/A</atomic_caps_outbound>\n\t\t</pci>\n\t\t<fan_speed>0 %</fan_speed>\n\t\t<performance_state>P8</performance_state>\n\t\t<clocks_event_reasons>\n\t\t\t<clocks_event_reason_gpu_idle>Active</clocks_event_reason_gpu_idle>\n\t\t\t<clocks_event_reason_applications_clocks_setting>Not Active</clocks_event_reason_applications_clocks_setting>\n\t\t\t<clocks_event_reason_sw_power_cap>Not Active</clocks_event_reason_sw_power_cap>\n\t\t\t<clocks_event_reason_hw_slowdown>Not Active</clocks_event_reason_hw_slowdown>\n\t\t\t<clocks_event_reason_hw_thermal_slowdown>Not Active</clocks_event_reason_hw_thermal_slowdown>\n\t\t\t<clocks_event_reason_hw_power_brake_slowdown>Not Active</clocks_event_reason_hw_power_brake_slowdown>\n\t\t\t<clocks_event_reason_sync_boost>Not Active</clocks_event_reason_sync_boost>\n\t\t\t<clocks_event_reason_sw_thermal_slowdown>Not Active</clocks_event_reason_sw_thermal_slowdown>\n\t\t\t<clocks_event_reason_display_clocks_setting>Not Active</clocks_event_reason_display_clocks_setting>\n\t\t</clocks_event_reasons>\n\t\t<fb_memory_usage>\n\t\t\t<total>10240 MiB</total>\n\t\t\t<reserved>173 MiB</reserved>\n\t\t\t<used>1128 MiB</used>\n\t\t\t<free>8938 MiB</free>\n\t\t</fb_memory_usage>\n\t\t<bar1_memory_usage>\n\t\t\t<total>16384 MiB</total>\n\t\t\t<used>1 MiB</used>\n\t\t\t<free>16383 MiB</free>\n\t\t</bar1_memory_usage>\n\t\t<cc_protected_memory_usage>\n\t\t\t<total>N/A</total>\n\t\t\t<used>N/A</used>\n\t\t\t<free>N/A</free>\n\t\t</cc_protected_memory_usage>\n\t\t<compute_mode>Default</compute_mode>\n\t\t<utilization>\n\t\t\t<gpu_util>0 %</gpu_util>\n\t\t\t<memory_util>37 %</memory_util>\n\t\t\t<encoder_util>0 %</encoder_util>\n\t\t\t<decoder_util>0 %</decoder_util>\n\t\t\t<jpeg_util>0 %</jpeg_util>\n\t\t\t<ofa_util>0 %</ofa_util>\n\t\t</utilization>\n\t\t<encoder_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</encoder_stats>\n\t\t<fbc_stats>\n\t\t\t<session_count>0</session_count>\n\t\t\t<average_fps>0</average_fps>\n\t\t\t<average_latency>0</average_latency>\n\t\t</fbc_stats>\n\t\t<ecc_mode>\n\t\t\t<current_ecc>N/A</current_ecc>\n\t\t\t<pending_ecc>N/A</pending_ecc>\n\t\t</ecc_mode>\n\t\t<ecc_errors>\n\t\t\t<volatile>\n\t\t\t\t<sram_correctable>N/A</sram_correctable>\n\t\t\t\t<sram_uncorrectable>N/A</sram_uncorrectable>\n\t\t\t\t<dram_correctable>N/A</dram_correctable>\n\t\t\t\t<dram_uncorrectable>N/A</dram_uncorrectable>\n\t\t\t</volatile>\n\t\t\t<aggregate>\n\t\t\t\t<sram_correctable>N/A</sram_correctable>\n\t\t\t\t<sram_uncorrectable>N/A</sram_uncorrectable>\n\t\t\t\t<dram_correctable>N/A</dram_correctable>\n\t\t\t\t<dram_uncorrectable>N/A</dram_uncorrectable>\n\t\t\t</aggregate>\n\t\t</ecc_errors>\n\t\t<retired_pages>\n\t\t\t<multiple_single_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</multiple_single_bit_retirement>\n\t\t\t<double_bit_retirement>\n\t\t\t\t<retired_count>N/A</retired_count>\n\t\t\t\t<retired_pagelist>N/A</retired_pagelist>\n\t\t\t</double_bit_retirement>\n\t\t\t<pending_blacklist>N/A</pending_blacklist>\n\t\t\t<pending_retirement>N/A</pending_retirement>\n\t\t</retired_pages>\n\t\t<remapped_rows>N/A</remapped_rows>\n\t\t<temperature>\n\t\t\t<gpu_temp>31 C</gpu_temp>\n\t\t\t<gpu_temp_tlimit>N/A</gpu_temp_tlimit>\n\t\t\t<gpu_temp_max_threshold>98 C</gpu_temp_max_threshold>\n\t\t\t<gpu_temp_slow_threshold>95 C</gpu_temp_slow_threshold>\n\t\t\t<gpu_temp_max_gpu_threshold>93 C</gpu_temp_max_gpu_threshold>\n\t\t\t<gpu_target_temperature>91 C</gpu_target_temperature>\n\t\t\t<memory_temp>N/A</memory_temp>\n\t\t\t<gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n\t\t</temperature>\n\t\t<supported_gpu_target_temp>\n\t\t\t<gpu_target_temp_min>65 C</gpu_target_temp_min>\n\t\t\t<gpu_target_temp_max>91 C</gpu_target_temp_max>\n\t\t</supported_gpu_target_temp>\n\t\t<gpu_power_readings>\n\t\t\t<power_state>P8</power_state>\n\t\t\t<power_draw>22.78 W</power_draw>\n\t\t\t<current_power_limit>336.00 W</current_power_limit>\n\t\t\t<requested_power_limit>336.00 W</requested_power_limit>\n\t\t\t<default_power_limit>320.00 W</default_power_limit>\n\t\t\t<min_power_limit>100.00 W</min_power_limit>\n\t\t\t<max_power_limit>336.00 W</max_power_limit>\n\t\t</gpu_power_readings>\n\t\t<module_power_readings>\n\t\t\t<power_state>P8</power_state>\n\t\t\t<power_draw>N/A</power_draw>\n\t\t\t<current_power_limit>N/A</current_power_limit>\n\t\t\t<requested_power_limit>N/A</requested_power_limit>\n\t\t\t<default_power_limit>N/A</default_power_limit>\n\t\t\t<min_power_limit>N/A</min_power_limit>\n\t\t\t<max_power_limit>N/A</max_power_limit>\n\t\t</module_power_readings>\n\t\t<clocks>\n\t\t\t<graphics_clock>210 MHz</graphics_clock>\n\t\t\t<sm_clock>210 MHz</sm_clock>\n\t\t\t<mem_clock>405 MHz</mem_clock>\n\t\t\t<video_clock>555 MHz</video_clock>\n\t\t</clocks>\n\t\t<applications_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</applications_clocks>\n\t\t<default_applications_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</default_applications_clocks>\n\t\t<deferred_clocks>\n\t\t\t<mem_clock>N/A</mem_clock>\n\t\t</deferred_clocks>\n\t\t<max_clocks>\n\t\t\t<graphics_clock>2100 MHz</graphics_clock>\n\t\t\t<sm_clock>2100 MHz</sm_clock>\n\t\t\t<mem_clock>9501 MHz</mem_clock>\n\t\t\t<video_clock>1950 MHz</video_clock>\n\t\t</max_clocks>\n\t\t<max_customer_boost_clocks>\n\t\t\t<graphics_clock>N/A</graphics_clock>\n\t\t</max_customer_boost_clocks>\n\t\t<clock_policy>\n\t\t\t<auto_boost>N/A</auto_boost>\n\t\t\t<auto_boost_default>N/A</auto_boost_default>\n\t\t</clock_policy>\n\t\t<voltage>\n\t\t\t<graphics_volt>750.000 mV</graphics_volt>\n\t\t</voltage>\n\t\t<fabric>\n\t\t\t<state>N/A</state>\n\t\t\t<status>N/A</status>\n\t\t</fabric>\n\t\t<supported_clocks>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>9501 MHz</value>\n\t\t\t\t<supported_graphics_clock>2100 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2085 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2070 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2055 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2040 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2010 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1995 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1980 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1965 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1950 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1935 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1920 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1905 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1890 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1875 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1845 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1830 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1815 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1800 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1785 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1770 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1755 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1740 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1725 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1710 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1680 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1665 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1650 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1635 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1605 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1590 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1575 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1560 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1545 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1530 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1485 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1470 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1440 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1425 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1410 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1395 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1380 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1365 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1350 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1335 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1320 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1305 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1275 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1260 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1245 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1230 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1200 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1185 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1170 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1155 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1140 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1125 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1110 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1095 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1080 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1065 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1035 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1020 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1005 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>990 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>975 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>960 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>945 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>930 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>915 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>900 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>870 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>855 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>840 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>825 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>795 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>780 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>765 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>750 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>735 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>720 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>705 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>690 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>675 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>660 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>630 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>615 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>600 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>585 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>570 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>555 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>540 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>525 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>510 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>495 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>465 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>450 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>435 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>420 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>390 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>375 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>360 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>345 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>330 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>315 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>300 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>285 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>270 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>255 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>225 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>210 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>9251 MHz</value>\n\t\t\t\t<supported_graphics_clock>2100 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2085 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2070 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2055 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2040 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2010 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1995 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1980 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1965 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1950 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1935 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1920 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1905 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1890 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1875 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1845 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1830 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1815 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1800 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1785 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1770 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1755 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1740 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1725 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1710 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1680 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1665 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1650 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1635 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1605 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1590 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1575 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1560 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1545 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1530 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1515 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1500 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1485 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1470 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1440 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1425 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1410 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1395 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1380 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1365 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1350 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1335 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1320 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1305 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1275 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1260 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1245 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1230 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1200 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1185 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1170 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1155 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1140 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1125 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1110 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1095 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1080 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1065 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1035 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1020 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1005 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>990 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>975 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>960 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>945 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>930 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>915 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>900 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>870 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>855 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>840 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>825 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>795 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>780 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>765 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>750 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>735 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>720 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>705 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>690 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>675 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>660 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>630 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>615 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>600 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>585 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>570 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>555 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>540 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>525 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>510 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>495 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>465 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>450 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>435 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>420 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>390 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>375 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>360 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>345 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>330 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>315 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>300 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>285 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>270 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>255 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>225 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>210 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>5001 MHz</value>\n\t\t\t\t<supported_graphics_clock>2100 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2085 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2070 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2055 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2040 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2010 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1995 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1980 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1965 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1950 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1935 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1920 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1905 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1890 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1875 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1845 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1830 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1815 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1800 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1785 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1770 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1755 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1740 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1725 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1710 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1680 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1665 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1650 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1635 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1605 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1590 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1575 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1560 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1545 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1530 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1515 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1500 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1485 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1470 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1440 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1425 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1410 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1395 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1380 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1365 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1350 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1335 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1320 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1305 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1275 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1260 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1245 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1230 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1200 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1185 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1170 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1155 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1140 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1125 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1110 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1095 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1080 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1065 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1035 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1020 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1005 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>990 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>975 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>960 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>945 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>930 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>915 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>900 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>870 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>855 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>840 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>825 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>795 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>780 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>765 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>750 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>735 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>720 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>705 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>690 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>675 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>660 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>630 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>615 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>600 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>585 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>570 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>555 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>540 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>525 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>510 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>495 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>465 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>450 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>435 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>420 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>390 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>375 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>360 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>345 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>330 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>315 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>300 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>285 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>270 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>255 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>225 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>210 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>810 MHz</value>\n\t\t\t\t<supported_graphics_clock>2100 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2085 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2070 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2055 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2040 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2025 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>2010 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1995 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1980 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1965 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1950 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1935 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1920 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1905 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1890 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1875 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1860 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1845 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1830 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1815 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1800 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1785 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1770 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1755 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1740 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1725 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1710 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1695 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1680 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1665 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1650 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1635 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1620 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1605 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1590 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1575 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1560 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1545 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1530 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1515 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1500 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1485 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1470 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1455 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1440 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1425 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1410 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1395 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1380 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1365 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1350 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1335 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1320 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1305 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1290 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1275 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1260 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1245 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1230 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1215 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1200 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1185 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1170 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1155 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1140 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1125 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1110 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1095 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1080 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1065 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1050 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1035 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1020 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>1005 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>990 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>975 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>960 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>945 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>930 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>915 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>900 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>885 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>870 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>855 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>840 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>825 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>810 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>795 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>780 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>765 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>750 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>735 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>720 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>705 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>690 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>675 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>660 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>645 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>630 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>615 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>600 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>585 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>570 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>555 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>540 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>525 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>510 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>495 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>480 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>465 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>450 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>435 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>420 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>390 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>375 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>360 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>345 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>330 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>315 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>300 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>285 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>270 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>255 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>225 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>210 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t\t<supported_mem_clock>\n\t\t\t\t<value>405 MHz</value>\n\t\t\t\t<supported_graphics_clock>420 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>405 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>390 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>375 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>360 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>345 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>330 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>315 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>300 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>285 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>270 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>255 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>240 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>225 MHz</supported_graphics_clock>\n\t\t\t\t<supported_graphics_clock>210 MHz</supported_graphics_clock>\n\t\t\t</supported_mem_clock>\n\t\t</supported_clocks>\n\t\t<processes>\n\t\t\t<process_info>\n\t\t\t\t<gpu_instance_id>N/A</gpu_instance_id>\n\t\t\t\t<compute_instance_id>N/A</compute_instance_id>\n\t\t\t\t<pid>835</pid>\n\t\t\t\t<type>G</type>\n\t\t\t\t<process_name>/usr/lib/Xorg</process_name>\n\t\t\t\t<used_memory>550 MiB</used_memory>\n\t\t\t</process_info>\n\t\t\t<process_info>\n\t\t\t\t<gpu_instance_id>N/A</gpu_instance_id>\n\t\t\t\t<compute_instance_id>N/A</compute_instance_id>\n\t\t\t\t<pid>1481</pid>\n\t\t\t\t<type>G</type>\n\t\t\t\t<process_name>/usr/bin/gnome-shell</process_name>\n\t\t\t\t<used_memory>18 MiB</used_memory>\n\t\t\t</process_info>\n\t\t\t<process_info>\n\t\t\t\t<gpu_instance_id>N/A</gpu_instance_id>\n\t\t\t\t<compute_instance_id>N/A</compute_instance_id>\n\t\t\t\t<pid>2214</pid>\n\t\t\t\t<type>G</type>\n\t\t\t\t<process_name>/opt/microsoft/msedge/msedge --type=gpu-process --crashpad-handler-pid=2176 --enable-crash-reporter=, --change-stack-guard-on-fork=enable --gpu-preferences=WAAAAAAAAAAgAAAEAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAGAAAAAAAAAAYAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== --shared-files --field-trial-handle=0,i,3110290512380155730,7457693378709978105,262144 --variations-seed-version</process_name>\n\t\t\t\t<used_memory>79 MiB</used_memory>\n\t\t\t</process_info>\n\t\t\t<process_info>\n\t\t\t\t<gpu_instance_id>N/A</gpu_instance_id>\n\t\t\t\t<compute_instance_id>N/A</compute_instance_id>\n\t\t\t\t<pid>4044</pid>\n\t\t\t\t<type>G</type>\n\t\t\t\t<process_name>/usr/lib/firefox/firefox</process_name>\n\t\t\t\t<used_memory>541 MiB</used_memory>\n\t\t\t</process_info>\n\t\t\t<process_info>\n\t\t\t\t<gpu_instance_id>N/A</gpu_instance_id>\n\t\t\t\t<compute_instance_id>N/A</compute_instance_id>\n\t\t\t\t<pid>42416</pid>\n\t\t\t\t<type>G</type>\n\t\t\t\t<process_name>/opt/visual-studio-code/code --type=gpu-process --enable-crash-reporter=6f39585a-ecc4-42e2-b899-9456cbe56b44,no_channel --user-data-dir=/home/powersj/.config/Code --gpu-preferences=WAAAAAAAAAAgAAAEAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAGAAAAAAAAAAYAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== --shared-files --field-trial-handle=0,i,685715063932313394,4769839452661094675,262144 --disable-features=CalculateNativeWinOcclusion,SpareRendererForSitePerProcess</process_name>\n\t\t\t\t<used_memory>159 MiB</used_memory>\n\t\t\t</process_info>\n\t\t</processes>\n\t\t<accounted_processes>\n\t\t</accounted_processes>\n\t</gpu>\n\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/rtx-3090-v12.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v12.dtd\">\n<nvidia_smi_log>\n        <timestamp>Fri May  3 11:54:37 2024</timestamp>\n        <driver_version>525.147.05</driver_version>\n        <cuda_version>12.0</cuda_version>\n        <attached_gpus>1</attached_gpus>\n        <gpu id=\"00000000:00:10.0\">\n                <product_name>NVIDIA GeForce RTX 3090</product_name>\n                <product_brand>GeForce</product_brand>\n                <product_architecture>Ampere</product_architecture>\n                <display_mode>Disabled</display_mode>\n                <display_active>Disabled</display_active>\n                <persistence_mode>Enabled</persistence_mode>\n                <mig_mode>\n                        <current_mig>N/A</current_mig>\n                        <pending_mig>N/A</pending_mig>\n                </mig_mode>\n                <mig_devices>\n                        None\n                </mig_devices>\n                <accounting_mode>Disabled</accounting_mode>\n                <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n                <driver_model>\n                        <current_dm>N/A</current_dm>\n                        <pending_dm>N/A</pending_dm>\n                </driver_model>\n                <serial>N/A</serial>\n                <uuid>GPU-12345678-aaaa-bbbb-cccc-0123456789ab</uuid>\n                <minor_number>0</minor_number>\n                <vbios_version>94.02.71.40.72</vbios_version>\n                <multigpu_board>No</multigpu_board>\n                <board_id>0x10</board_id>\n                <board_part_number>N/A</board_part_number>\n                <gpu_part_number>[REDACTED]</gpu_part_number>\n                <gpu_module_id>1</gpu_module_id>\n                <inforom_version>\n                        <img_version>[REDACTED]</img_version>\n                        <oem_object>2.0</oem_object>\n                        <ecc_object>N/A</ecc_object>\n                        <pwr_object>N/A</pwr_object>\n                </inforom_version>\n                <gpu_operation_mode>\n                        <current_gom>N/A</current_gom>\n                        <pending_gom>N/A</pending_gom>\n                </gpu_operation_mode>\n                <gsp_firmware_version>N/A</gsp_firmware_version>\n                <gpu_virtualization_mode>\n                        <virtualization_mode>Pass-Through</virtualization_mode>\n                        <host_vgpu_mode>N/A</host_vgpu_mode>\n                </gpu_virtualization_mode>\n                <ibmnpu>\n                        <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n                </ibmnpu>\n                <pci>\n                        <pci_bus>00</pci_bus>\n                        <pci_device>10</pci_device>\n                        <pci_domain>0000</pci_domain>\n                        <pci_device_id>[REDACTED]</pci_device_id>\n                        <pci_bus_id>00000000:00:10.0</pci_bus_id>\n                        <pci_sub_system_id>[REDACTED]</pci_sub_system_id>\n                        <pci_gpu_link_info>\n                                <pcie_gen>\n                                        <max_link_gen>4</max_link_gen>\n                                        <current_link_gen>1</current_link_gen>\n                                        <device_current_link_gen>1</device_current_link_gen>\n                                        <max_device_link_gen>4</max_device_link_gen>\n                                        <max_host_link_gen>N/A</max_host_link_gen>\n                                </pcie_gen>\n                                <link_widths>\n                                        <max_link_width>16x</max_link_width>\n                                        <current_link_width>16x</current_link_width>\n                                </link_widths>\n                        </pci_gpu_link_info>\n                        <pci_bridge_chip>\n                                <bridge_chip_type>N/A</bridge_chip_type>\n                                <bridge_chip_fw>N/A</bridge_chip_fw>\n                        </pci_bridge_chip>\n                        <replay_counter>0</replay_counter>\n                        <replay_rollover_counter>0</replay_rollover_counter>\n                        <tx_util>0 KB/s</tx_util>\n                        <rx_util>0 KB/s</rx_util>\n                        <atomic_caps_inbound>N/A</atomic_caps_inbound>\n                        <atomic_caps_outbound>N/A</atomic_caps_outbound>\n                </pci>\n                <fan_speed>0 %</fan_speed>\n                <performance_state>P8</performance_state>\n                <clocks_throttle_reasons>\n                        <clocks_throttle_reason_gpu_idle>Active</clocks_throttle_reason_gpu_idle>\n                        <clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n                        <clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n                        <clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n                        <clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n                        <clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n                        <clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n                        <clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n                        <clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n                </clocks_throttle_reasons>\n                <fb_memory_usage>\n                        <total>24576 MiB</total>\n                        <reserved>316 MiB</reserved>\n                        <used>1 MiB</used>\n                        <free>24258 MiB</free>\n                </fb_memory_usage>\n                <bar1_memory_usage>\n                        <total>32768 MiB</total>\n                        <used>2 MiB</used>\n                        <free>32766 MiB</free>\n                </bar1_memory_usage>\n                <compute_mode>Default</compute_mode>\n                <utilization>\n                        <gpu_util>0 %</gpu_util>\n                        <memory_util>0 %</memory_util>\n                        <encoder_util>0 %</encoder_util>\n                        <decoder_util>0 %</decoder_util>\n                </utilization>\n                <encoder_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </encoder_stats>\n                <fbc_stats>\n                        <session_count>0</session_count>\n                        <average_fps>0</average_fps>\n                        <average_latency>0</average_latency>\n                </fbc_stats>\n                <ecc_mode>\n                        <current_ecc>N/A</current_ecc>\n                        <pending_ecc>N/A</pending_ecc>\n                </ecc_mode>\n                <ecc_errors>\n                        <volatile>\n                                <sram_correctable>N/A</sram_correctable>\n                                <sram_uncorrectable>N/A</sram_uncorrectable>\n                                <dram_correctable>N/A</dram_correctable>\n                                <dram_uncorrectable>N/A</dram_uncorrectable>\n                        </volatile>\n                        <aggregate>\n                                <sram_correctable>N/A</sram_correctable>\n                                <sram_uncorrectable>N/A</sram_uncorrectable>\n                                <dram_correctable>N/A</dram_correctable>\n                                <dram_uncorrectable>N/A</dram_uncorrectable>\n                        </aggregate>\n                </ecc_errors>\n                <retired_pages>\n                        <multiple_single_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </multiple_single_bit_retirement>\n                        <double_bit_retirement>\n                                <retired_count>N/A</retired_count>\n                                <retired_pagelist>N/A</retired_pagelist>\n                        </double_bit_retirement>\n                        <pending_blacklist>N/A</pending_blacklist>\n                        <pending_retirement>N/A</pending_retirement>\n                </retired_pages>\n                <remapped_rows>N/A</remapped_rows>\n                <temperature>\n                        <gpu_temp>37 C</gpu_temp>\n                        <gpu_temp_tlimit>N/A</gpu_temp_tlimit>\n                        <gpu_temp_max_threshold>98 C</gpu_temp_max_threshold>\n                        <gpu_temp_slow_threshold>95 C</gpu_temp_slow_threshold>\n                        <gpu_temp_max_gpu_threshold>93 C</gpu_temp_max_gpu_threshold>\n                        <gpu_target_temperature>83 C</gpu_target_temperature>\n                        <memory_temp>N/A</memory_temp>\n                        <gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n                </temperature>\n                <supported_gpu_target_temp>\n                        <gpu_target_temp_min>65 C</gpu_target_temp_min>\n                        <gpu_target_temp_max>91 C</gpu_target_temp_max>\n                </supported_gpu_target_temp>\n                <power_readings>\n                        <power_state>P8</power_state>\n                        <power_management>Supported</power_management>\n                        <power_draw>27.23 W</power_draw>\n                        <power_limit>200.00 W</power_limit>\n                        <default_power_limit>350.00 W</default_power_limit>\n                        <enforced_power_limit>200.00 W</enforced_power_limit>\n                        <min_power_limit>100.00 W</min_power_limit>\n                        <max_power_limit>375.00 W</max_power_limit>\n                </power_readings>\n                <clocks>\n                        <graphics_clock>0 MHz</graphics_clock>\n                        <sm_clock>0 MHz</sm_clock>\n                        <mem_clock>405 MHz</mem_clock>\n                        <video_clock>555 MHz</video_clock>\n                </clocks>\n                <applications_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                        <mem_clock>N/A</mem_clock>\n                </applications_clocks>\n                <default_applications_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                        <mem_clock>N/A</mem_clock>\n                </default_applications_clocks>\n                <deferred_clocks>\n                        <mem_clock>N/A</mem_clock>\n                </deferred_clocks>\n                <max_clocks>\n                        <graphics_clock>2100 MHz</graphics_clock>\n                        <sm_clock>2100 MHz</sm_clock>\n                        <mem_clock>9751 MHz</mem_clock>\n                        <video_clock>1950 MHz</video_clock>\n                </max_clocks>\n                <max_customer_boost_clocks>\n                        <graphics_clock>N/A</graphics_clock>\n                </max_customer_boost_clocks>\n                <clock_policy>\n                        <auto_boost>N/A</auto_boost>\n                        <auto_boost_default>N/A</auto_boost_default>\n                </clock_policy>\n                <voltage>\n                        <graphics_volt>0.000 mV</graphics_volt>\n                </voltage>\n                <fabric>\n                        <state>N/A</state>\n                        <status>N/A</status>\n                </fabric>\n                <supported_clocks>\n                        <supported_mem_clock>\n                                <value>9751 MHz</value>\n                                <supported_graphics_clock>2100 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2085 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2070 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2055 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2040 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2010 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1995 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1980 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1965 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1950 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1935 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1920 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1905 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1890 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1875 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1845 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1830 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1815 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1800 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1785 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1770 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1755 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1740 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1725 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1710 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1695 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1680 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1665 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1650 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1635 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1605 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>9501 MHz</value>\n                                <supported_graphics_clock>2100 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2085 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2070 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2055 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2040 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2010 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1995 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1980 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1965 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1950 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1935 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1920 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1905 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1890 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1875 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1845 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1830 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1815 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1800 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1785 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1770 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1755 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1740 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1725 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1710 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1695 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1680 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1665 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1650 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1635 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1605 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>5001 MHz</value>\n                                <supported_graphics_clock>2100 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2085 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2070 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2055 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2040 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2010 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1995 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1980 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1965 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1950 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1935 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1920 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1905 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1890 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1875 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1845 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1830 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1815 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1800 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1785 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1770 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1755 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1740 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1725 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1710 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1695 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1680 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1665 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1650 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1635 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1605 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>810 MHz</value>\n                                <supported_graphics_clock>2100 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2085 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2070 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2055 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2040 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2025 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>2010 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1995 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1980 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1965 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1950 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1935 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1920 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1905 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1890 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1875 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1860 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1845 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1830 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1815 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1800 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1785 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1770 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1755 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1740 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1725 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1710 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1695 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1680 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1665 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1650 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1635 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1620 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1605 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                        <supported_mem_clock>\n                                <value>405 MHz</value>\n                                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>285 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>270 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>255 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>240 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>225 MHz</supported_graphics_clock>\n                                <supported_graphics_clock>210 MHz</supported_graphics_clock>\n                        </supported_mem_clock>\n                </supported_clocks>\n                <processes>\n                </processes>\n                <accounted_processes>\n                </accounted_processes>\n        </gpu>\n\n</nvidia_smi_log>\n"
  },
  {
    "path": "plugins/inputs/nvidia_smi/testdata/tesla-t4.xml",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE nvidia_smi_log SYSTEM \"nvsmi_device_v11.dtd\">\n<nvidia_smi_log>\n    <timestamp>Mon Apr 24 16:22:39 2023</timestamp>\n    <driver_version>515.105.01</driver_version>\n    <cuda_version>11.7</cuda_version>\n    <attached_gpus>1</attached_gpus>\n    <gpu id=\"00000000:00:1E.0\">\n        <product_name>Tesla T4</product_name>\n        <product_brand>NVIDIA</product_brand>\n        <product_architecture>Turing</product_architecture>\n        <display_mode>Disabled</display_mode>\n        <display_active>Disabled</display_active>\n        <persistence_mode>Disabled</persistence_mode>\n        <mig_mode>\n            <current_mig>N/A</current_mig>\n            <pending_mig>N/A</pending_mig>\n        </mig_mode>\n        <mig_devices>\n            None\n        </mig_devices>\n        <accounting_mode>Disabled</accounting_mode>\n        <accounting_mode_buffer_size>4000</accounting_mode_buffer_size>\n        <driver_model>\n            <current_dm>N/A</current_dm>\n            <pending_dm>N/A</pending_dm>\n        </driver_model>\n        <serial>0000000000000</serial>\n        <uuid>GPU-d37e67a5-91dd-3774-a5cb-99096249601a</uuid>\n        <minor_number>0</minor_number>\n        <vbios_version>90.04.84.00.06</vbios_version>\n        <multigpu_board>No</multigpu_board>\n        <board_id>0x1e</board_id>\n        <gpu_part_number>900-2G183-0000-001</gpu_part_number>\n        <gpu_module_id>0</gpu_module_id>\n        <inforom_version>\n            <img_version>G183.0200.00.02</img_version>\n            <oem_object>1.1</oem_object>\n            <ecc_object>5.0</ecc_object>\n            <pwr_object>N/A</pwr_object>\n        </inforom_version>\n        <gpu_operation_mode>\n            <current_gom>N/A</current_gom>\n            <pending_gom>N/A</pending_gom>\n        </gpu_operation_mode>\n        <gsp_firmware_version>515.105.01</gsp_firmware_version>\n        <gpu_virtualization_mode>\n            <virtualization_mode>Pass-Through</virtualization_mode>\n            <host_vgpu_mode>N/A</host_vgpu_mode>\n        </gpu_virtualization_mode>\n        <ibmnpu>\n            <relaxed_ordering_mode>N/A</relaxed_ordering_mode>\n        </ibmnpu>\n        <pci>\n            <pci_bus>00</pci_bus>\n            <pci_device>1E</pci_device>\n            <pci_domain>0000</pci_domain>\n            <pci_device_id>1EB810DE</pci_device_id>\n            <pci_bus_id>00000000:00:1E.0</pci_bus_id>\n            <pci_sub_system_id>12A210DE</pci_sub_system_id>\n            <pci_gpu_link_info>\n                <pcie_gen>\n                    <max_link_gen>3</max_link_gen>\n                    <current_link_gen>3</current_link_gen>\n                </pcie_gen>\n                <link_widths>\n                    <max_link_width>16x</max_link_width>\n                    <current_link_width>8x</current_link_width>\n                </link_widths>\n            </pci_gpu_link_info>\n            <pci_bridge_chip>\n                <bridge_chip_type>N/A</bridge_chip_type>\n                <bridge_chip_fw>N/A</bridge_chip_fw>\n            </pci_bridge_chip>\n            <replay_counter>0</replay_counter>\n            <replay_rollover_counter>0</replay_rollover_counter>\n            <tx_util>0 KB/s</tx_util>\n            <rx_util>0 KB/s</rx_util>\n        </pci>\n        <fan_speed>N/A</fan_speed>\n        <performance_state>P0</performance_state>\n        <clocks_throttle_reasons>\n            <clocks_throttle_reason_gpu_idle>Not Active</clocks_throttle_reason_gpu_idle>\n            <clocks_throttle_reason_applications_clocks_setting>Not Active</clocks_throttle_reason_applications_clocks_setting>\n            <clocks_throttle_reason_sw_power_cap>Not Active</clocks_throttle_reason_sw_power_cap>\n            <clocks_throttle_reason_hw_slowdown>Not Active</clocks_throttle_reason_hw_slowdown>\n            <clocks_throttle_reason_hw_thermal_slowdown>Not Active</clocks_throttle_reason_hw_thermal_slowdown>\n            <clocks_throttle_reason_hw_power_brake_slowdown>Not Active</clocks_throttle_reason_hw_power_brake_slowdown>\n            <clocks_throttle_reason_sync_boost>Not Active</clocks_throttle_reason_sync_boost>\n            <clocks_throttle_reason_sw_thermal_slowdown>Not Active</clocks_throttle_reason_sw_thermal_slowdown>\n            <clocks_throttle_reason_display_clocks_setting>Not Active</clocks_throttle_reason_display_clocks_setting>\n        </clocks_throttle_reasons>\n        <fb_memory_usage>\n            <total>15360 MiB</total>\n            <reserved>388 MiB</reserved>\n            <used>1032 MiB</used>\n            <free>13939 MiB</free>\n        </fb_memory_usage>\n        <bar1_memory_usage>\n            <total>256 MiB</total>\n            <used>5 MiB</used>\n            <free>251 MiB</free>\n        </bar1_memory_usage>\n        <compute_mode>Default</compute_mode>\n        <utilization>\n            <gpu_util>0 %</gpu_util>\n            <memory_util>0 %</memory_util>\n            <encoder_util>0 %</encoder_util>\n            <decoder_util>0 %</decoder_util>\n        </utilization>\n        <encoder_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </encoder_stats>\n        <fbc_stats>\n            <session_count>0</session_count>\n            <average_fps>0</average_fps>\n            <average_latency>0</average_latency>\n        </fbc_stats>\n        <ecc_mode>\n            <current_ecc>Enabled</current_ecc>\n            <pending_ecc>Enabled</pending_ecc>\n        </ecc_mode>\n        <ecc_errors>\n            <volatile>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </volatile>\n            <aggregate>\n                <sram_correctable>0</sram_correctable>\n                <sram_uncorrectable>0</sram_uncorrectable>\n                <dram_correctable>0</dram_correctable>\n                <dram_uncorrectable>0</dram_uncorrectable>\n            </aggregate>\n        </ecc_errors>\n        <retired_pages>\n            <multiple_single_bit_retirement>\n                <retired_count>0</retired_count>\n                <retired_pagelist>\n                </retired_pagelist>\n            </multiple_single_bit_retirement>\n            <double_bit_retirement>\n                <retired_count>0</retired_count>\n                <retired_pagelist>\n                </retired_pagelist>\n            </double_bit_retirement>\n            <pending_blacklist>No</pending_blacklist>\n            <pending_retirement>No</pending_retirement>\n        </retired_pages>\n        <remapped_rows>N/A</remapped_rows>\n        <temperature>\n            <gpu_temp>40 C</gpu_temp>\n            <gpu_temp_max_threshold>96 C</gpu_temp_max_threshold>\n            <gpu_temp_slow_threshold>93 C</gpu_temp_slow_threshold>\n            <gpu_temp_max_gpu_threshold>85 C</gpu_temp_max_gpu_threshold>\n            <gpu_target_temperature>N/A</gpu_target_temperature>\n            <memory_temp>N/A</memory_temp>\n            <gpu_temp_max_mem_threshold>N/A</gpu_temp_max_mem_threshold>\n        </temperature>\n        <supported_gpu_target_temp>\n            <gpu_target_temp_min>N/A</gpu_target_temp_min>\n            <gpu_target_temp_max>N/A</gpu_target_temp_max>\n        </supported_gpu_target_temp>\n        <power_readings>\n            <power_state>P0</power_state>\n            <power_management>Supported</power_management>\n            <power_draw>26.78 W</power_draw>\n            <power_limit>70.00 W</power_limit>\n            <default_power_limit>70.00 W</default_power_limit>\n            <enforced_power_limit>70.00 W</enforced_power_limit>\n            <min_power_limit>60.00 W</min_power_limit>\n            <max_power_limit>70.00 W</max_power_limit>\n        </power_readings>\n        <clocks>\n            <graphics_clock>585 MHz</graphics_clock>\n            <sm_clock>585 MHz</sm_clock>\n            <mem_clock>5000 MHz</mem_clock>\n            <video_clock>810 MHz</video_clock>\n        </clocks>\n        <applications_clocks>\n            <graphics_clock>585 MHz</graphics_clock>\n            <mem_clock>5001 MHz</mem_clock>\n        </applications_clocks>\n        <default_applications_clocks>\n            <graphics_clock>585 MHz</graphics_clock>\n            <mem_clock>5001 MHz</mem_clock>\n        </default_applications_clocks>\n        <max_clocks>\n            <graphics_clock>1590 MHz</graphics_clock>\n            <sm_clock>1590 MHz</sm_clock>\n            <mem_clock>5001 MHz</mem_clock>\n            <video_clock>1470 MHz</video_clock>\n        </max_clocks>\n        <max_customer_boost_clocks>\n            <graphics_clock>1590 MHz</graphics_clock>\n        </max_customer_boost_clocks>\n        <clock_policy>\n            <auto_boost>N/A</auto_boost>\n            <auto_boost_default>N/A</auto_boost_default>\n        </clock_policy>\n        <voltage>\n            <graphics_volt>N/A</graphics_volt>\n        </voltage>\n        <supported_clocks>\n            <supported_mem_clock>\n                <value>5001 MHz</value>\n                <supported_graphics_clock>1590 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1575 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1560 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1545 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1530 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1515 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1500 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1485 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1470 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1455 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1440 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1425 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1410 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1395 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1380 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1365 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1350 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1335 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1320 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1305 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1290 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1275 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1260 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1245 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1230 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1215 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1200 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1185 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1170 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1155 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1140 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1125 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1110 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1095 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1080 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1065 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1050 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1035 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1020 MHz</supported_graphics_clock>\n                <supported_graphics_clock>1005 MHz</supported_graphics_clock>\n                <supported_graphics_clock>990 MHz</supported_graphics_clock>\n                <supported_graphics_clock>975 MHz</supported_graphics_clock>\n                <supported_graphics_clock>960 MHz</supported_graphics_clock>\n                <supported_graphics_clock>945 MHz</supported_graphics_clock>\n                <supported_graphics_clock>930 MHz</supported_graphics_clock>\n                <supported_graphics_clock>915 MHz</supported_graphics_clock>\n                <supported_graphics_clock>900 MHz</supported_graphics_clock>\n                <supported_graphics_clock>885 MHz</supported_graphics_clock>\n                <supported_graphics_clock>870 MHz</supported_graphics_clock>\n                <supported_graphics_clock>855 MHz</supported_graphics_clock>\n                <supported_graphics_clock>840 MHz</supported_graphics_clock>\n                <supported_graphics_clock>825 MHz</supported_graphics_clock>\n                <supported_graphics_clock>810 MHz</supported_graphics_clock>\n                <supported_graphics_clock>795 MHz</supported_graphics_clock>\n                <supported_graphics_clock>780 MHz</supported_graphics_clock>\n                <supported_graphics_clock>765 MHz</supported_graphics_clock>\n                <supported_graphics_clock>750 MHz</supported_graphics_clock>\n                <supported_graphics_clock>735 MHz</supported_graphics_clock>\n                <supported_graphics_clock>720 MHz</supported_graphics_clock>\n                <supported_graphics_clock>705 MHz</supported_graphics_clock>\n                <supported_graphics_clock>690 MHz</supported_graphics_clock>\n                <supported_graphics_clock>675 MHz</supported_graphics_clock>\n                <supported_graphics_clock>660 MHz</supported_graphics_clock>\n                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n            </supported_mem_clock>\n            <supported_mem_clock>\n                <value>405 MHz</value>\n                <supported_graphics_clock>645 MHz</supported_graphics_clock>\n                <supported_graphics_clock>630 MHz</supported_graphics_clock>\n                <supported_graphics_clock>615 MHz</supported_graphics_clock>\n                <supported_graphics_clock>600 MHz</supported_graphics_clock>\n                <supported_graphics_clock>585 MHz</supported_graphics_clock>\n                <supported_graphics_clock>570 MHz</supported_graphics_clock>\n                <supported_graphics_clock>555 MHz</supported_graphics_clock>\n                <supported_graphics_clock>540 MHz</supported_graphics_clock>\n                <supported_graphics_clock>525 MHz</supported_graphics_clock>\n                <supported_graphics_clock>510 MHz</supported_graphics_clock>\n                <supported_graphics_clock>495 MHz</supported_graphics_clock>\n                <supported_graphics_clock>480 MHz</supported_graphics_clock>\n                <supported_graphics_clock>465 MHz</supported_graphics_clock>\n                <supported_graphics_clock>450 MHz</supported_graphics_clock>\n                <supported_graphics_clock>435 MHz</supported_graphics_clock>\n                <supported_graphics_clock>420 MHz</supported_graphics_clock>\n                <supported_graphics_clock>405 MHz</supported_graphics_clock>\n                <supported_graphics_clock>390 MHz</supported_graphics_clock>\n                <supported_graphics_clock>375 MHz</supported_graphics_clock>\n                <supported_graphics_clock>360 MHz</supported_graphics_clock>\n                <supported_graphics_clock>345 MHz</supported_graphics_clock>\n                <supported_graphics_clock>330 MHz</supported_graphics_clock>\n                <supported_graphics_clock>315 MHz</supported_graphics_clock>\n                <supported_graphics_clock>300 MHz</supported_graphics_clock>\n            </supported_mem_clock>\n        </supported_clocks>\n        <processes>\n            <process_info>\n                <gpu_instance_id>N/A</gpu_instance_id>\n                <compute_instance_id>N/A</compute_instance_id>\n                <pid>675</pid>\n                <type>G</type>\n                <process_name>/usr/lib/xorg/Xorg</process_name>\n                <used_memory>22 MiB</used_memory>\n            </process_info>\n            <process_info>\n                <gpu_instance_id>N/A</gpu_instance_id>\n                <compute_instance_id>N/A</compute_instance_id>\n                <pid>5762</pid>\n                <type>C</type>\n                <process_name>python</process_name>\n                <used_memory>1005 MiB</used_memory>\n            </process_info>\n        </processes>\n        <accounted_processes>\n        </accounted_processes>\n    </gpu>\n\n</nvidia_smi_log>"
  },
  {
    "path": "plugins/inputs/opcua/README.md",
    "content": "# OPC UA Client Reader Input Plugin\n\nThis plugin gathers data from an [OPC UA][opcua] server by subscribing to the\nconfigured nodes.\n\n⭐ Telegraf v1.16.0\n🏷️ iot\n💻 all\n\n[opcua]: https://opcfoundation.org/about/opc-technologies/opc-ua/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Retrieve data from OPCUA devices\n[[inputs.opcua]]\n  ## Metric name\n  # name = \"opcua\"\n\n  ## OPC UA Endpoint URL\n  # endpoint = \"opc.tcp://localhost:4840\"\n\n  ## Maximum time allowed to establish a connect to the endpoint.\n  # connect_timeout = \"10s\"\n\n  ## Maximum time allowed for a request over the established connection.\n  # request_timeout = \"5s\"\n\n  ## Maximum time that a session shall remain open without activity.\n  # session_timeout = \"20m\"\n\n  ## Retry options for failing reads e.g. due to invalid sessions\n  ## If the retry count is zero, the read will fail after the initial attempt.\n  # read_retry_timeout = \"100ms\"\n  # read_retry_count = 0\n\n  ## Number of consecutive errors before forcing a reconnection\n  ## If set to 1 (default), the client will reconnect after a single failed read\n  # reconnect_error_threshold = 1\n\n  ## Security policy, one of \"None\", \"Basic128Rsa15\", \"Basic256\",\n  ## \"Basic256Sha256\", or \"auto\"\n  # security_policy = \"auto\"\n\n  ## Security mode, one of \"None\", \"Sign\", \"SignAndEncrypt\", or \"auto\"\n  # security_mode = \"auto\"\n\n  ## Path to client certificate and private key files, must be specified together.\n  ## If none of the options are specified, a temporary self-signed certificate\n  ## will be created. If the options are specified but the files do not exist, a\n  ## self-signed certificate will be created and stored permanently at the\n  ## given locations.\n  # certificate = \"/etc/telegraf/cert.pem\"\n  # private_key = \"/etc/telegraf/key.pem\"\n\n  ## Path to additional, explicitly trusted certificate for the remote endpoint\n  # remote_certificate = \"/etc/telegraf/opcua_server_cert.pem\"\n\n  ## Authentication Method, one of \"Certificate\", \"UserName\", or \"Anonymous\".  To\n  ## authenticate using a specific ID, select 'Certificate' or 'UserName'\n  # auth_method = \"Anonymous\"\n\n  ## Username and password required for auth_method = \"UserName\"\n  # username = \"\"\n  # password = \"\"\n\n  ## Option to select the metric timestamp to use. Valid options are:\n  ##     \"gather\" -- uses the time of receiving the data in telegraf\n  ##     \"server\" -- uses the timestamp provided by the server\n  ##     \"source\" -- uses the timestamp provided by the source\n  # timestamp = \"gather\"\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the OPCUA\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Include additional Fields in each metric\n  ## Available options are:\n  ##   DataType -- OPC-UA Data Type (string)\n  # optional_fields = []\n\n  ## Node ID configuration\n  ## name              - field name to use in the output\n  ## id                - OPC UA node ID string (e.g., \"ns=0;i=2262\" or \"nsu=http://...;s=Name\")\n  ## namespace         - OPC UA namespace of the node (integer value 0 thru 3)\n  ## namespace_uri     - OPC UA namespace URI (alternative to namespace for stable references)\n  ## identifier_type   - OPC UA ID type (s=string, i=numeric, g=guid, b=opaque)\n  ## identifier        - OPC UA ID (tag as shown in opcua browser)\n  ## default_tags      - extra tags to be added to the output metric (optional)\n  ##\n  ## Use EITHER 'id' OR the combination of 'namespace/namespace_uri' + 'identifier_type' + 'identifier'\n  ## Use either the inline notation or the bracketed notation, not both.\n\n  ## Inline notation using id string (recommended for simplicity)\n  # nodes = [\n  #   {name=\"ProductUri\", id=\"ns=0;i=2262\"},\n  #   {name=\"ServerState\", id=\"ns=0;i=2259\"},\n  # ]\n\n  ## Inline notation using individual fields (default_tags not supported yet)\n  # nodes = [\n  #   {name=\"\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  # ]\n\n  ## Bracketed notation using id string\n  # [[inputs.opcua.nodes]]\n  #   name = \"ProductUri\"\n  #   id = \"ns=0;i=2262\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n\n  ## Bracketed notation using individual fields\n  # [[inputs.opcua.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  # [[inputs.opcua.nodes]]\n  #   name = \"node3\"\n  #   namespace_uri = \"http://opcfoundation.org/UA/\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n\n  ## Node Group\n  ## Sets defaults so they aren't required in every node.\n  ## Default values can be set for:\n  ## * Metric name\n  ## * OPC UA namespace\n  ## * Identifier\n  ## * Default tags\n  ##\n  ## Multiple node groups are allowed\n  #[[inputs.opcua.group]]\n  ## Group Metric name. Overrides the top level name.  If unset, the\n  ## top level name is used.\n  # name =\n\n  ## Group default namespace. If a node in the group doesn't set its\n  ## namespace, this is used.\n  # namespace =\n\n  ## Group default namespace URI. Alternative to namespace for stable references.\n  ## If a node in the group doesn't set its namespace_uri, this is used.\n  # namespace_uri =\n\n  ## Group default identifier type. If a node in the group doesn't set its\n  ## identifier_type, this is used.\n  # identifier_type =\n\n  ## Default tags that are applied to every node in this group. Can be\n  ## overwritten in a node by setting a different value for the tag name.\n  ##   example: default_tags = { tag1 = \"value1\" }\n  # default_tags = {}\n\n  ## Node ID Configuration. Array of nodes with the same settings as above.\n  ## Use either the inline notation or the bracketed notation, not both.\n\n  ## Inline notation (default_tags not supported yet)\n  # nodes = [\n  #  {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #  {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #]\n\n  ## Bracketed notation\n  # [[inputs.opcua.group.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"override1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua.group.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.opcua.workarounds]\n  #   ## Set additional valid status codes, StatusOK (0x0) is always considered valid\n  #   # additional_valid_status_codes = [\"0xC0\"]\n\n  # [inputs.opcua.request_workarounds]\n  #   ## Use unregistered reads instead of registered reads\n  #   # use_unregistered_reads = false\n```\n\n### Client Certificate Configuration\n\nWhen using security modes other than \"None\", Telegraf acts as an OPC UA client\nand requires a client certificate to authenticate itself to the server. The\nplugin supports three certificate management approaches:\n\n#### Temporary Self-Signed Certificates (Default)\n\nIf both `certificate` and `private_key` options are left empty or commented\nout, Telegraf will automatically generate a self-signed certificate in a\ntemporary directory on each startup.\n\n> [!NOTE]\n> These certificates are recreated on every Telegraf restart, requiring\n> re-authorization by the OPC UA server each time. This is suitable for testing\n> but not recommended for production environments.\n\n#### Persistent Self-Signed Certificates (Recommended for Testing)\n\nTo maintain the same client identity across restarts, specify paths for both\n`certificate` and `private_key`. If the files don't exist, Telegraf will\ngenerate them at the specified locations and reuse them on subsequent restarts.\n\n> [!IMPORTANT]\n> Ensure Telegraf has write permissions to the specified paths. On first run,\n> Telegraf will generate the certificates and log their locations. On subsequent\n> restarts, Telegraf will reuse the existing certificates, preventing the need\n> to re-authorize the client in the server's trust store.\n\n#### Manual Certificate Management (Production)\n\nFor production environments, manually generate and deploy certificates using\nyour organization's PKI infrastructure. Place the certificate and private key\nfiles at the configured paths before starting Telegraf. If both files exist,\nTelegraf will use them without modification.\n\n#### Certificate Validation Rules\n\n- Both `certificate` and `private_key` must be specified together, or both\n  must be empty\n- If one file exists but the other doesn't, Telegraf will return an error\n\n## Node Configuration\n\nAn OPC UA node ID may resemble: \"ns=3;s=Temperature\". In this example:\n\n- ns=3 is indicating the `namespace` is 3\n- s=Temperature is indicting that the `identifier_type` is a string and\n  `identifier` value is 'Temperature'\n- This example temperature node has a value of 79.0\n\n### Using `id` String (Recommended)\n\nYou can specify nodes using the standard OPC UA node ID string format directly:\n\n```text\n{name=\"temp\", id=\"ns=3;s=Temperature\"},\n```\n\nThis is simpler and matches the format shown in OPC UA browsers.\n\n### Using Individual Fields\n\nAlternatively, you can specify each component separately:\n\n```text\n{name=\"temp\", namespace=\"3\", identifier_type=\"s\", identifier=\"Temperature\"},\n```\n\n> [!NOTE]\n> Use either `id` OR the combination of\n> `namespace`/`namespace_uri` + `identifier_type` + `identifier`.\n> Do not mix both formats for the same node.\n\nThis node configuration produces a metric like this:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp=79.0,Quality=\"OK (0x0)\" 1597820490000000000\n```\n\nWith 'DataType' entered in Additional Metrics, this node configuration\nproduces a metric like this:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp=79.0,Quality=\"OK (0x0)\",DataType=\"Float\" 1597820490000000000\n```\n\nIf the value is an array, each element is unpacked into a field\nusing indexed keys. For example:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp[0]=79.0,temp[1]=38.9,Quality=\"OK (0x0)\",DataType=\"Float\" 1597820490000000000\n```\n\n### Namespace Index vs Namespace URI\n\nOPC UA supports two ways to specify namespaces:\n\n1. **Namespace Index** (`namespace`): An integer (0-3 or higher) that references\n   a position in the server's namespace array. This is simpler but can change if\n   the server is restarted or reconfigured.\n\n2. **Namespace URI** (`namespace_uri`): A string URI that uniquely identifies\n   the namespace. This is more stable across server restarts but requires the\n   plugin to fetch the namespace array from the server to resolve the URI to an\n   index.\n\n**When to use namespace index:**\n\n- For standard OPC UA namespaces (0 = OPC UA, 1 = Local Server)\n- When namespace stability is not a concern\n- For simpler configuration\n\n**When to use namespace URI:**\n\n- When you need consistent node references across server restarts\n- For production environments where namespace indices might change\n- When working with vendor-specific namespaces\n\n**Example using namespace URI:**\n\n```toml\n[[inputs.opcua.nodes]]\n  name = \"ServerStatus\"\n  namespace_uri = \"http://opcfoundation.org/UA/\"\n  identifier_type = \"i\"\n  identifier = \"2256\"\n```\n\nThis produces the same node ID internally as:\n\n```toml\n[[inputs.opcua.nodes]]\n  name = \"ServerStatus\"\n  namespace = \"0\"\n  identifier_type = \"i\"\n  identifier = \"2256\"\n```\n\nNote: You must specify either `namespace` or `namespace_uri`, not both.\n\n## Group Configuration\n\nGroups can set default values for the namespace (index or URI), identifier type,\nand tags settings. The default values apply to all the nodes in the group. If a\ndefault is set, a node may omit the setting altogether. This simplifies node\nconfiguration, especially when many nodes share the same namespace or identifier\ntype.\n\nThe output metric will include tags set in the group and the node.  If\na tag with the same name is set in both places, the tag value from the\nnode is used.\n\nThis example group configuration has three groups with two nodes each:\n\n```toml\n  # Group 1\n  [[inputs.opcua.group]]\n    name = \"group1_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group1_tag = \"val1\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"name\"\n      identifier = \"1001\"\n      default_tags = { node1_tag = \"val2\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"name\"\n      identifier = \"1002\"\n      default_tags = {node1_tag = \"val3\"}\n\n  # Group 2\n  [[inputs.opcua.group]]\n    name = \"group2_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group2_tag = \"val3\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"saw\"\n      identifier = \"1003\"\n      default_tags = { node2_tag = \"val4\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"sin\"\n      identifier = \"1004\"\n\n  # Group 3\n  [[inputs.opcua.group]]\n    name = \"group3_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group3_tag = \"val5\" }\n    nodes = [\n      {name=\"name\", identifier=\"1001\"},\n      {name=\"name\", identifier=\"1002\"},\n    ]\n```\n\n### Server Certificate Trust\n\nWhen connecting to OPC UA servers with self-signed certificates using\nsecure modes (Sign or SignAndEncrypt), you need to explicitly trust the\nserver's certificate. Use the `remote_certificate` option to specify the\npath to the server's certificate file.\n\nMost OPC UA servers provide their certificate through their management interface\nor configuration directory. Consult your OPC UA server's documentation to locate\nthe certificate, typically found in the server's PKI (Public Key Infrastructure)\ndirectory. Alternatively, you can export the certificate using OPC UA client tools.\n\n## Connection Service\n\nThis plugin actively reads to retrieve data from the OPC server.\nThis is done every `interval`.\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the\nconfigured `nodes` and `group`.\n\n## Example Output\n\n```text\ngroup1_metric_name,group1_tag=val1,id=ns\\=3;i\\=1001,node1_tag=val2 name=0,Quality=\"OK (0x0)\" 1606893246000000000\ngroup1_metric_name,group1_tag=val1,id=ns\\=3;i\\=1002,node1_tag=val3 name=-1.389117,Quality=\"OK (0x0)\" 1606893246000000000\ngroup2_metric_name,group2_tag=val3,id=ns\\=3;i\\=1003,node2_tag=val4 Quality=\"OK (0x0)\",saw=-1.6 1606893246000000000\ngroup2_metric_name,group2_tag=val3,id=ns\\=3;i\\=1004 sin=1.902113,Quality=\"OK (0x0)\" 1606893246000000000\n```\n"
  },
  {
    "path": "plugins/inputs/opcua/opcua.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage opcua\n\nimport (\n\t_ \"embed\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype OpcUA struct {\n\treadClientConfig\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient *readClient\n\n\t// Add a consecutive error counter to potentially force reconnection\n\tconsecutiveErrors uint64\n}\n\nfunc (*OpcUA) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *OpcUA) Init() (err error) {\n\to.client, err = o.readClientConfig.createReadClient(o.Log)\n\treturn err\n}\n\nfunc (o *OpcUA) Gather(acc telegraf.Accumulator) error {\n\t// Force reconnection every time if a threshold is 0\n\tif o.client.ReconnectErrorThreshold == 0 {\n\t\to.client.forceReconnect = true\n\t}\n\n\t// Will (re)connect if the client is disconnected\n\tmetrics, err := o.client.currentValues()\n\tif err != nil {\n\t\to.consecutiveErrors++\n\n\t\t// Force reconnection based on an error threshold: if threshold > 0, reconnect after\n\t\t// reaching the specified number of consecutive errors; if a threshold = 0, we already\n\t\t// force the reconnection above, so skip this check\n\t\tif o.client.ReconnectErrorThreshold > 0 && o.consecutiveErrors >= o.client.ReconnectErrorThreshold {\n\t\t\to.client.forceReconnect = true\n\t\t}\n\t\treturn err\n\t}\n\n\t// Reset error counter on success\n\to.consecutiveErrors = 0\n\n\t// Parse the resulting data into metrics\n\tfor _, m := range metrics {\n\t\tacc.AddMetric(m)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"opcua\", func() telegraf.Input {\n\t\treturn &OpcUA{\n\t\t\treadClientConfig: readClientConfig{\n\t\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\t\t\tSecurityPolicy: \"auto\",\n\t\t\t\t\t\tSecurityMode:   \"auto\",\n\t\t\t\t\t\tCertificate:    \"/etc/telegraf/cert.pem\",\n\t\t\t\t\t\tPrivateKey:     \"/etc/telegraf/key.pem\",\n\t\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\t\tConnectTimeout: config.Duration(5 * time.Second),\n\t\t\t\t\t\tRequestTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t\tMetricName: \"opcua\",\n\t\t\t\t\tTimestamp:  input.TimestampSourceTelegraf,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/opcua/opcua_test.go",
    "content": "package opcua\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst servicePort = \"4840\"\n\ntype opcTags struct {\n\tname           string\n\tnamespace      string\n\tidentifierType string\n\tidentifier     string\n\twant           interface{}\n}\n\nfunc mapOPCTag(tags opcTags) (out input.NodeSettings) {\n\tout.FieldName = tags.name\n\tout.Namespace = tags.namespace\n\tout.IdentifierType = tags.identifierType\n\tout.Identifier = tags.identifier\n\treturn out\n}\n\nfunc TestGetDataBadNodeContainerIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"1\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t}\n\n\treadConfig := readClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t}\n\n\tg := input.NodeGroupSettings{\n\t\tMetricName:  \"anodic_current\",\n\t\tDefaultTags: map[string]string{\"pot\": \"2002\"},\n\t}\n\n\tfor _, tags := range testopctags {\n\t\tg.Nodes = append(g.Nodes, mapOPCTag(tags))\n\t}\n\treadConfig.Groups = append(readConfig.Groups, g)\n\n\tlogger := &testutil.CaptureLogger{}\n\treadClient, err := readConfig.createReadClient(logger)\n\trequire.NoError(t, err)\n\terr = readClient.connect()\n\trequire.NoError(t, err)\n}\n\nfunc TestReadClientIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t\t{\"badnode\", \"1\", \"i\", \"1337\", nil},\n\t\t{\"goodnode\", \"1\", \"s\", \"the.answer\", int32(42)},\n\t\t{\"DateTime\", \"1\", \"i\", \"51037\", \"0001-01-01T00:00:00Z\"},\n\t}\n\n\treadConfig := readClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t}\n\n\tfor _, tags := range testopctags {\n\t\treadConfig.RootNodes = append(readConfig.RootNodes, mapOPCTag(tags))\n\t}\n\n\tclient, err := readConfig.createReadClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\terr = client.connect()\n\trequire.NoError(t, err)\n\n\tfor i, v := range client.LastReceivedData {\n\t\trequire.Equal(t, testopctags[i].want, v.Value)\n\t}\n}\n\nfunc TestReadClientIntegrationAdditionalFields(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t\t{\"badnode\", \"1\", \"i\", \"1337\", nil},\n\t\t{\"goodnode\", \"1\", \"s\", \"the.answer\", int32(42)},\n\t\t{\"DateTime\", \"1\", \"i\", \"51037\", \"0001-01-01T00:00:00Z\"},\n\t}\n\ttestopctypes := []string{\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"Null\",\n\t\t\"Int32\",\n\t\t\"DateTime\",\n\t}\n\ttestopcquality := []string{\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"User does not have permission to perform the requested operation. StatusBadUserAccessDenied (0x801F0000)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t}\n\texpectedopcmetrics := make([]telegraf.Metric, 0, len(testopctags))\n\tfor i, x := range testopctags {\n\t\tnow := time.Now()\n\t\ttags := map[string]string{\n\t\t\t\"id\": fmt.Sprintf(\"ns=%s;%s=%s\", x.namespace, x.identifierType, x.identifier),\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\tx.name:     x.want,\n\t\t\t\"Quality\":  testopcquality[i],\n\t\t\t\"DataType\": testopctypes[i],\n\t\t}\n\t\texpectedopcmetrics = append(expectedopcmetrics, metric.New(\"testing\", tags, fields, now))\n\t}\n\n\treadConfig := readClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t\tOptionalFields: []string{\"DataType\"},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t}\n\n\tfor _, tags := range testopctags {\n\t\treadConfig.RootNodes = append(readConfig.RootNodes, mapOPCTag(tags))\n\t}\n\n\tclient, err := readConfig.createReadClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, client.connect())\n\n\tactualopcmetrics := make([]telegraf.Metric, 0, len(client.LastReceivedData))\n\tfor i := range client.LastReceivedData {\n\t\tactualopcmetrics = append(actualopcmetrics, client.MetricForNode(i))\n\t}\n\ttestutil.RequireMetricsEqual(t, expectedopcmetrics, actualopcmetrics, testutil.IgnoreTime())\n}\n\nfunc TestReadClientIntegrationWithPasswordAuth(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tEntrypoint:   []string{\"/opt/open62541/build/bin/examples/access_control_server\"},\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t}\n\n\treadConfig := readClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tUsername:       config.NewSecret([]byte(\"peter\")),\n\t\t\t\tPassword:       config.NewSecret([]byte(\"peter123\")),\n\t\t\t\tAuthMethod:     \"UserName\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t}\n\n\tfor _, tags := range testopctags {\n\t\treadConfig.RootNodes = append(readConfig.RootNodes, mapOPCTag(tags))\n\t}\n\n\tclient, err := readConfig.createReadClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\terr = client.connect()\n\trequire.NoError(t, err)\n\n\tfor i, v := range client.LastReceivedData {\n\t\trequire.Equal(t, testopctags[i].want, v.Value)\n\t}\n}\n\nfunc TestReadClientConfig(t *testing.T) {\n\ttoml := `\n[[inputs.opcua]]\nname = \"localhost\"\nendpoint = \"opc.tcp://localhost:4840\"\nconnect_timeout = \"10s\"\nrequest_timeout = \"5s\"\nsecurity_policy = \"auto\"\nsecurity_mode = \"auto\"\ncertificate = \"/etc/telegraf/cert.pem\"\nprivate_key = \"/etc/telegraf/key.pem\"\nauth_method = \"Anonymous\"\nusername = \"\"\npassword = \"\"\n\noptional_fields = [\"DataType\"]\n\n[[inputs.opcua.nodes]]\n  name = \"name\"\n  namespace = \"1\"\n  identifier_type = \"s\"\n  identifier=\"one\"\n  default_tags = { tag0 = \"val0\" }\n\n[[inputs.opcua.nodes]]\n  name=\"name2\"\n  namespace=\"2\"\n  identifier_type=\"s\"\n  identifier=\"two\"\n  default_tags={tag6=\"val6\"}\n\n[[inputs.opcua.group]]\nname = \"foo\"\nnamespace = \"3\"\nidentifier_type = \"i\"\ndefault_tags = { tag1 = \"val1\", tag2 = \"val2\"}\n[[inputs.opcua.group.nodes]]\n  name = \"name3\"\n  identifier = \"3000\"\n  default_tags = { tag3 = \"val3\" }\n\n[[inputs.opcua.group]]\nname = \"bar\"\nnamespace = \"0\"\nidentifier_type = \"i\"\ndefault_tags = { tag1 = \"val1\", tag2 = \"val2\"}\n[[inputs.opcua.group.nodes]]\n  name = \"name4\"\n  identifier = \"4000\"\n  default_tags = { tag1 = \"override\" }\n\n[[inputs.opcua.group.nodes]]\n  name = \"name5\"\n  identifier = \"4001\"\n\n[inputs.opcua.workarounds]\nadditional_valid_status_codes = [\"0xC0\"]\n\n[inputs.opcua.request_workarounds]\nuse_unregistered_reads = true\n\n`\n\n\tc := config.NewConfig()\n\terr := c.LoadConfigData([]byte(toml), config.EmptySourcePath)\n\trequire.NoError(t, err)\n\n\trequire.Len(t, c.Inputs, 1)\n\n\to, ok := c.Inputs[0].Input.(*OpcUA)\n\trequire.True(t, ok)\n\n\trequire.Equal(t, \"localhost\", o.readClientConfig.MetricName)\n\trequire.Equal(t, \"opc.tcp://localhost:4840\", o.readClientConfig.Endpoint)\n\trequire.Equal(t, config.Duration(10*time.Second), o.readClientConfig.ConnectTimeout)\n\trequire.Equal(t, config.Duration(5*time.Second), o.readClientConfig.RequestTimeout)\n\trequire.Equal(t, \"auto\", o.readClientConfig.SecurityPolicy)\n\trequire.Equal(t, \"auto\", o.readClientConfig.SecurityMode)\n\trequire.Equal(t, \"/etc/telegraf/cert.pem\", o.readClientConfig.Certificate)\n\trequire.Equal(t, \"/etc/telegraf/key.pem\", o.readClientConfig.PrivateKey)\n\trequire.Equal(t, \"Anonymous\", o.readClientConfig.AuthMethod)\n\trequire.True(t, o.readClientConfig.Username.Empty())\n\trequire.True(t, o.readClientConfig.Password.Empty())\n\trequire.Equal(t, []input.NodeSettings{\n\t\t{\n\t\t\tFieldName:      \"name\",\n\t\t\tNamespace:      \"1\",\n\t\t\tIdentifierType: \"s\",\n\t\t\tIdentifier:     \"one\",\n\t\t\tDefaultTags:    map[string]string{\"tag0\": \"val0\"},\n\t\t},\n\t\t{\n\t\t\tFieldName:      \"name2\",\n\t\t\tNamespace:      \"2\",\n\t\t\tIdentifierType: \"s\",\n\t\t\tIdentifier:     \"two\",\n\t\t\tDefaultTags:    map[string]string{\"tag6\": \"val6\"},\n\t\t},\n\t}, o.readClientConfig.RootNodes)\n\trequire.Equal(t, []input.NodeGroupSettings{\n\t\t{\n\t\t\tMetricName:     \"foo\",\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tDefaultTags:    map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"},\n\t\t\tNodes: []input.NodeSettings{{\n\t\t\t\tFieldName:   \"name3\",\n\t\t\t\tIdentifier:  \"3000\",\n\t\t\t\tDefaultTags: map[string]string{\"tag3\": \"val3\"},\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\tMetricName:     \"bar\",\n\t\t\tNamespace:      \"0\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tDefaultTags:    map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"},\n\t\t\tNodes: []input.NodeSettings{{\n\t\t\t\tFieldName:   \"name4\",\n\t\t\t\tIdentifier:  \"4000\",\n\t\t\t\tDefaultTags: map[string]string{\"tag1\": \"override\"},\n\t\t\t}, {\n\t\t\t\tFieldName:  \"name5\",\n\t\t\t\tIdentifier: \"4001\",\n\t\t\t}},\n\t\t},\n\t}, o.readClientConfig.Groups)\n\trequire.Equal(t, opcua.OpcUAWorkarounds{AdditionalValidStatusCodes: []string{\"0xC0\"}}, o.readClientConfig.Workarounds)\n\trequire.Equal(t, readClientWorkarounds{UseUnregisteredReads: true}, o.readClientConfig.ReadClientWorkarounds)\n\trequire.Equal(t, []string{\"DataType\"}, o.readClientConfig.OptionalFields)\n\terr = o.Init()\n\trequire.NoError(t, err)\n\trequire.Len(t, o.client.NodeMetricMapping, 5, \"incorrect number of nodes\")\n\trequire.EqualValues(t, map[string]string{\"tag0\": \"val0\"}, o.client.NodeMetricMapping[0].MetricTags)\n\trequire.EqualValues(t, map[string]string{\"tag6\": \"val6\"}, o.client.NodeMetricMapping[1].MetricTags)\n\trequire.EqualValues(t, map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\", \"tag3\": \"val3\"}, o.client.NodeMetricMapping[2].MetricTags)\n\trequire.EqualValues(t, map[string]string{\"tag1\": \"override\", \"tag2\": \"val2\"}, o.client.NodeMetricMapping[3].MetricTags)\n\trequire.EqualValues(t, map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"}, o.client.NodeMetricMapping[4].MetricTags)\n}\n\nfunc TestUnregisteredReadsAndSessionRecoveryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t}\n\n\treadConfig := readClientConfig{\n\t\tReadRetries: 1, // Set low to make tests faster\n\t\tReadClientWorkarounds: readClientWorkarounds{\n\t\t\tUseUnregisteredReads: true, // Enable unregistered reads\n\t\t},\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t}\n\n\tfor _, tags := range testopctags {\n\t\treadConfig.RootNodes = append(readConfig.RootNodes, mapOPCTag(tags))\n\t}\n\n\t// Create logger to capture logs\n\tlogger := &testutil.CaptureLogger{}\n\tclient, err := readConfig.createReadClient(logger)\n\trequire.NoError(t, err)\n\n\t// First connection\n\trequire.NoError(t, client.connect())\n\n\t// Verify initial data read was successful\n\trequire.Len(t, client.LastReceivedData, 2)\n\tfor i, v := range client.LastReceivedData {\n\t\trequire.Equal(t, testopctags[i].want, v.Value)\n\t}\n\n\t// Get initial metrics to compare later\n\tinitialMetrics, err := client.currentValues()\n\trequire.NoError(t, err)\n\trequire.Len(t, initialMetrics, 2)\n\n\t// Now simulate session invalidation as would happen in the real world\n\tclient.forceReconnect = true\n\n\t// Get metrics again - this should force a reconnection\n\trecoveredMetrics, err := client.currentValues()\n\trequire.NoError(t, err, \"Should recover from session invalidation\")\n\trequire.Len(t, recoveredMetrics, 2)\n\n\t// Verify data consistency after reconnect\n\tfor i := range recoveredMetrics {\n\t\trequire.Equal(t,\n\t\t\tinitialMetrics[i].Fields()[testopctags[i].name],\n\t\t\trecoveredMetrics[i].Fields()[testopctags[i].name],\n\t\t\t\"Data should be consistent after session recovery\")\n\t}\n\n\t// Verify we're using unregistered reads by checking log messages\n\t// In a real scenario, the error message would say \"unregistered nodes\"\n\t// But since we're simulating, we need to verify the flag is set correctly\n\trequire.True(t, client.Workarounds.UseUnregisteredReads,\n\t\t\"UseUnregisteredReads flag should be properly set\")\n}\n\nfunc TestConsecutiveSessionErrorRecoveryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Create a test OpcUA instance with threshold = 2 to test multiple errors\n\tthreshold := uint64(2)\n\to := &OpcUA{\n\t\treadClientConfig: readClientConfig{\n\t\t\tReadRetries:             1,\n\t\t\tReconnectErrorThreshold: &threshold, // Set to 2 for this test\n\t\t\tReadClientWorkarounds: readClientWorkarounds{\n\t\t\t\tUseUnregisteredReads: true,\n\t\t\t},\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"testing\",\n\t\t\t\tRootNodes: []input.NodeSettings{\n\t\t\t\t\tmapOPCTag(opcTags{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\t// Initialize the plugin\n\trequire.NoError(t, o.Init())\n\n\t// Create an accumulator\n\tacc := &testutil.Accumulator{}\n\n\t// First gather should succeed\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n\n\t// Simulate a session error\n\to.client.forceReconnect = true\n\n\t// The next gather should force a reconnection internally and succeed\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors, \"Should reset consecutive errors after successful gather\")\n\n\t// Simulate multiple consecutive errors with bad endpoint\n\toriginalEndpoint := o.client.OpcUAClient.Config.Endpoint\n\to.client.OpcUAClient.Config.Endpoint = \"opc.tcp://invalid-endpoint:4840\"\n\trequire.NoError(t, o.client.Disconnect(t.Context()))\n\n\t// First failure should NOT trigger forceReconnect yet (threshold = 2)\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(1), o.consecutiveErrors)\n\trequire.False(t, o.client.forceReconnect, \"Session should not be invalidated yet with threshold=2\")\n\n\t// Second failure should trigger forceReconnect (threshold = 2)\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(2), o.consecutiveErrors)\n\trequire.True(t, o.client.forceReconnect, \"Should force session invalidation after reaching threshold\")\n\n\t// Restore endpoint to allow recovery\n\to.client.OpcUAClient.Config.Endpoint = originalEndpoint\n\n\t// Next gather should succeed and reset error counter\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors, \"Should reset consecutive errors after recovery\")\n}\n\nfunc TestReconnectErrorThresholdDefaultIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Test Case 1: Config not set - should use default of 1\n\to := &OpcUA{\n\t\treadClientConfig: readClientConfig{\n\t\t\t// ReconnectErrorThreshold not set (nil pointer)\n\t\t\tReadRetries: 1,\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"testing\",\n\t\t\t\tRootNodes: []input.NodeSettings{\n\t\t\t\t\tmapOPCTag(opcTags{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\trequire.NoError(t, o.Init())\n\trequire.Equal(t, uint64(1), o.client.ReconnectErrorThreshold, \"Should use default of 1 when not configured\")\n\n\tacc := &testutil.Accumulator{}\n\n\t// First gather should succeed\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n\trequire.False(t, o.client.forceReconnect)\n\n\t// Simulate connection failure by using invalid endpoint\n\toriginalEndpoint := o.client.OpcUAClient.Config.Endpoint\n\to.client.OpcUAClient.Config.Endpoint = \"opc.tcp://invalid-endpoint:4840\"\n\trequire.NoError(t, o.client.Disconnect(t.Context()))\n\n\t// First error should trigger forceReconnect (threshold = 1)\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(1), o.consecutiveErrors)\n\trequire.True(t, o.client.forceReconnect, \"Should force reconnection after 1 error (default threshold)\")\n\n\t// Restore endpoint\n\to.client.OpcUAClient.Config.Endpoint = originalEndpoint\n\n\t// Recovery should work\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n}\n\nfunc TestReconnectErrorThresholdZeroIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Test Case 2: Config set to 0 - should force reconnection every gather\n\tthreshold := uint64(0)\n\to := &OpcUA{\n\t\treadClientConfig: readClientConfig{\n\t\t\tReconnectErrorThreshold: &threshold, // Explicitly set to 0\n\t\t\tReadRetries:             1,\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"testing\",\n\t\t\t\tRootNodes: []input.NodeSettings{\n\t\t\t\t\tmapOPCTag(opcTags{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\trequire.NoError(t, o.Init())\n\trequire.Equal(t, uint64(0), o.client.ReconnectErrorThreshold, \"Should use explicit value of 0\")\n\n\tacc := &testutil.Accumulator{}\n\n\t// First gather should succeed but forceReconnect should be set due to threshold=0\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n\n\t// Second gather should also succeed and forceReconnect should be set again\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n\n\t// Verify that forceReconnect is set at the beginning of each gather when threshold=0\n\t// We can check this by monitoring the behavior - with threshold=0, every gather should\n\t// start with forceReconnect=true (set by the Gather function)\n\n\t// Simulate one more gather to confirm consistent behavior\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n}\n\nfunc TestReconnectErrorThresholdThreeIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Test Case 3: Config set to 3 - should reconnect after 3 consecutive errors\n\tthreshold := uint64(3)\n\to := &OpcUA{\n\t\treadClientConfig: readClientConfig{\n\t\t\tReconnectErrorThreshold: &threshold, // Explicitly set to 3\n\t\t\tReadRetries:             1,\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"testing\",\n\t\t\t\tRootNodes: []input.NodeSettings{\n\t\t\t\t\tmapOPCTag(opcTags{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\n\trequire.NoError(t, o.Init())\n\trequire.Equal(t, uint64(3), o.client.ReconnectErrorThreshold, \"Should use explicit value of 3\")\n\n\tacc := &testutil.Accumulator{}\n\n\t// First gather should succeed\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors)\n\trequire.False(t, o.client.forceReconnect)\n\n\t// Simulate connection failures by using invalid endpoint\n\toriginalEndpoint := o.client.OpcUAClient.Config.Endpoint\n\to.client.OpcUAClient.Config.Endpoint = \"opc.tcp://invalid-endpoint:4840\"\n\trequire.NoError(t, o.client.Disconnect(t.Context()))\n\n\t// First error - should NOT trigger forceReconnect yet\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(1), o.consecutiveErrors)\n\trequire.False(t, o.client.forceReconnect, \"Should NOT force reconnection after 1 error (threshold=3)\")\n\n\t// Second error - should NOT trigger forceReconnect yet\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(2), o.consecutiveErrors)\n\trequire.False(t, o.client.forceReconnect, \"Should NOT force reconnection after 2 errors (threshold=3)\")\n\n\t// Third error - should trigger forceReconnect\n\tacc.ClearMetrics()\n\trequire.Error(t, o.Gather(acc))\n\trequire.Equal(t, uint64(3), o.consecutiveErrors)\n\trequire.True(t, o.client.forceReconnect, \"Should force reconnection after 3 errors (threshold=3)\")\n\n\t// Restore endpoint to allow recovery\n\to.client.OpcUAClient.Config.Endpoint = originalEndpoint\n\n\t// Recovery should work and reset error counter\n\tacc.ClearMetrics()\n\trequire.NoError(t, o.Gather(acc))\n\trequire.Len(t, acc.Metrics, 1)\n\trequire.Equal(t, uint64(0), o.consecutiveErrors, \"Should reset consecutive errors after recovery\")\n}\n"
  },
  {
    "path": "plugins/inputs/opcua/read_client.go",
    "content": "package opcua\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua/ua\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n\t\"github.com/influxdata/telegraf/selfstat\"\n)\n\ntype readClientWorkarounds struct {\n\tUseUnregisteredReads bool `toml:\"use_unregistered_reads\"`\n}\n\ntype readClientConfig struct {\n\tReconnectErrorThreshold *uint64               `toml:\"reconnect_error_threshold\"`\n\tReadRetryTimeout        config.Duration       `toml:\"read_retry_timeout\"`\n\tReadRetries             uint64                `toml:\"read_retry_count\"`\n\tReadClientWorkarounds   readClientWorkarounds `toml:\"request_workarounds\"`\n\tinput.InputClientConfig\n}\n\n// readClient Requests the current values from the required nodes when gather is called.\ntype readClient struct {\n\t*input.OpcUAInputClient\n\n\tReconnectErrorThreshold uint64\n\tReadRetryTimeout        time.Duration\n\tReadRetries             uint64\n\tReadSuccess             selfstat.Stat\n\tReadError               selfstat.Stat\n\tWorkarounds             readClientWorkarounds\n\n\t// internal values\n\treqIDs []*ua.ReadValueID\n\tctx    context.Context\n\n\t// Track last session error to force reconnection\n\tforceReconnect bool\n}\n\nfunc (rc *readClientConfig) createReadClient(log telegraf.Logger) (*readClient, error) {\n\tinputClient, err := rc.InputClientConfig.CreateInputClient(log)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttags := map[string]string{\n\t\t\"endpoint\": inputClient.Config.OpcUAClientConfig.Endpoint,\n\t}\n\n\tif rc.ReadRetryTimeout == 0 {\n\t\trc.ReadRetryTimeout = config.Duration(100 * time.Millisecond)\n\t}\n\n\t// Set default for ReconnectErrorThreshold if not configured\n\t// Use the default value of reconnect after every error and\n\t// allow the user to override that setting including forcing\n\t// a reconnect after every cycle by setting zero.\n\treconnectThreshold := uint64(1)\n\tif rc.ReconnectErrorThreshold != nil {\n\t\treconnectThreshold = *rc.ReconnectErrorThreshold\n\t}\n\n\treturn &readClient{\n\t\tOpcUAInputClient:        inputClient,\n\t\tReconnectErrorThreshold: reconnectThreshold,\n\t\tReadRetryTimeout:        time.Duration(rc.ReadRetryTimeout),\n\t\tReadRetries:             rc.ReadRetries,\n\t\tReadSuccess:             selfstat.Register(\"opcua\", \"read_success\", tags),\n\t\tReadError:               selfstat.Register(\"opcua\", \"read_error\", tags),\n\t\tWorkarounds:             rc.ReadClientWorkarounds,\n\t}, nil\n}\n\nfunc (o *readClient) connect() error {\n\to.ctx = context.Background()\n\to.forceReconnect = false\n\n\tif err := o.OpcUAClient.Connect(o.ctx); err != nil {\n\t\treturn fmt.Errorf(\"connect failed: %w\", err)\n\t}\n\n\t// Fetch namespace array for namespace URI support\n\tif err := o.OpcUAClient.UpdateNamespaceArray(o.ctx); err != nil {\n\t\to.Log.Warnf(\"Failed to fetch namespace array: %v\", err)\n\t\t// Continue anyway - this is only needed if using namespace URIs\n\t}\n\n\t// Make sure we setup the node-ids correctly after reconnect\n\t// as the server might be restarted and IDs changed\n\tif err := o.OpcUAInputClient.InitNodeIDs(); err != nil {\n\t\treturn fmt.Errorf(\"initializing node IDs failed: %w\", err)\n\t}\n\n\to.reqIDs = make([]*ua.ReadValueID, 0, len(o.NodeIDs))\n\tif o.Workarounds.UseUnregisteredReads {\n\t\tfor _, nid := range o.NodeIDs {\n\t\t\to.reqIDs = append(o.reqIDs, &ua.ReadValueID{NodeID: nid})\n\t\t}\n\t} else {\n\t\tregResp, err := o.Client.RegisterNodes(o.ctx, &ua.RegisterNodesRequest{\n\t\t\tNodesToRegister: o.NodeIDs,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"registering nodes failed: %w\", err)\n\t\t}\n\n\t\tfor _, v := range regResp.RegisteredNodeIDs {\n\t\t\to.reqIDs = append(o.reqIDs, &ua.ReadValueID{NodeID: v})\n\t\t}\n\t}\n\n\tif err := o.read(); err != nil {\n\t\treturn fmt.Errorf(\"get data failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (o *readClient) ensureConnected() error {\n\t// Force reconnection if we had a session error in the previous cycle\n\tif o.forceReconnect || o.State() == opcua.Disconnected || o.State() == opcua.Closed {\n\t\t// If we're forcing a reconnection, but we're not in Disconnected state,\n\t\t// explicitly disconnect first\n\t\tif o.State() != opcua.Disconnected && o.State() != opcua.Closed {\n\t\t\tif err := o.Disconnect(context.Background()); err != nil {\n\t\t\t\to.Log.Debug(\"Error while disconnecting: \", err)\n\t\t\t}\n\t\t}\n\t\treturn o.connect()\n\t}\n\treturn nil\n}\n\nfunc (o *readClient) currentValues() ([]telegraf.Metric, error) {\n\tif err := o.ensureConnected(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif state := o.State(); state != opcua.Connected {\n\t\treturn nil, fmt.Errorf(\"not connected, in state %q\", state)\n\t}\n\n\tif err := o.read(); err != nil {\n\t\t// We do not return the disconnect error, as this would mask the\n\t\t// original problem, but we do log it\n\t\tif derr := o.Disconnect(context.Background()); derr != nil {\n\t\t\to.Log.Debug(\"Error while disconnecting: \", derr)\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tmetrics := make([]telegraf.Metric, 0, len(o.NodeMetricMapping))\n\t// Parse the resulting data into metrics\n\tfor i := range o.NodeIDs {\n\t\tif !o.StatusCodeOK(o.LastReceivedData[i].Quality) {\n\t\t\tcontinue\n\t\t}\n\n\t\tmetrics = append(metrics, o.MetricForNode(i))\n\t}\n\n\treturn metrics, nil\n}\n\nfunc (o *readClient) read() error {\n\treq := &ua.ReadRequest{\n\t\tMaxAge:             2000,\n\t\tTimestampsToReturn: ua.TimestampsToReturnBoth,\n\t\tNodesToRead:        o.reqIDs,\n\t}\n\n\tvar count uint64\n\n\tfor {\n\t\tcount++\n\n\t\t// Try to update the values for all registered nodes\n\t\tresp, err := o.Client.Read(o.ctx, req)\n\t\tif err == nil {\n\t\t\t// Success, update the node values and exit\n\t\t\to.ReadSuccess.Incr(1)\n\t\t\to.forceReconnect = false\n\t\t\tfor i, d := range resp.Results {\n\t\t\t\to.UpdateNodeValue(i, d)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\to.ReadError.Incr(1)\n\n\t\tisSessionError := errors.Is(err, ua.StatusBadSessionIDInvalid) ||\n\t\t\terrors.Is(err, ua.StatusBadSessionNotActivated) ||\n\t\t\terrors.Is(err, ua.StatusBadSecureChannelIDInvalid)\n\n\t\t// Flag session error for next cycle if encountered\n\t\tif isSessionError {\n\t\t\to.forceReconnect = true\n\t\t}\n\n\t\tswitch {\n\t\tcase count > o.ReadRetries:\n\t\t\t// We exceeded the number of retries and should exit\n\t\t\treturn fmt.Errorf(\"reading %s nodes failed after %d attempts: %w\",\n\t\t\t\tnodeTypeLabel(o.Workarounds.UseUnregisteredReads), count, err)\n\t\tcase isSessionError:\n\t\t\t// Retry after the defined period as session and channels should be refreshed\n\t\t\to.Log.Debugf(\"reading failed with %v, retry %d / %d...\", err, count, o.ReadRetries)\n\t\t\ttime.Sleep(o.ReadRetryTimeout)\n\t\tdefault:\n\t\t\t// Non-retryable error, there is nothing we can do\n\t\t\treturn fmt.Errorf(\"reading %s nodes failed: %w\",\n\t\t\t\tnodeTypeLabel(o.Workarounds.UseUnregisteredReads), err)\n\t\t}\n\t}\n}\n\n// Helper function to provide more accurate error messages\nfunc nodeTypeLabel(useUnregistered bool) string {\n\tif useUnregistered {\n\t\treturn \"unregistered\"\n\t}\n\treturn \"registered\"\n}\n"
  },
  {
    "path": "plugins/inputs/opcua/sample.conf",
    "content": "# Retrieve data from OPCUA devices\n[[inputs.opcua]]\n  ## Metric name\n  # name = \"opcua\"\n\n  ## OPC UA Endpoint URL\n  # endpoint = \"opc.tcp://localhost:4840\"\n\n  ## Maximum time allowed to establish a connect to the endpoint.\n  # connect_timeout = \"10s\"\n\n  ## Maximum time allowed for a request over the established connection.\n  # request_timeout = \"5s\"\n\n  ## Maximum time that a session shall remain open without activity.\n  # session_timeout = \"20m\"\n\n  ## Retry options for failing reads e.g. due to invalid sessions\n  ## If the retry count is zero, the read will fail after the initial attempt.\n  # read_retry_timeout = \"100ms\"\n  # read_retry_count = 0\n\n  ## Number of consecutive errors before forcing a reconnection\n  ## If set to 1 (default), the client will reconnect after a single failed read\n  # reconnect_error_threshold = 1\n\n  ## Security policy, one of \"None\", \"Basic128Rsa15\", \"Basic256\",\n  ## \"Basic256Sha256\", or \"auto\"\n  # security_policy = \"auto\"\n\n  ## Security mode, one of \"None\", \"Sign\", \"SignAndEncrypt\", or \"auto\"\n  # security_mode = \"auto\"\n\n  ## Path to client certificate and private key files, must be specified together.\n  ## If none of the options are specified, a temporary self-signed certificate\n  ## will be created. If the options are specified but the files do not exist, a\n  ## self-signed certificate will be created and stored permanently at the\n  ## given locations.\n  # certificate = \"/etc/telegraf/cert.pem\"\n  # private_key = \"/etc/telegraf/key.pem\"\n\n  ## Path to additional, explicitly trusted certificate for the remote endpoint\n  # remote_certificate = \"/etc/telegraf/opcua_server_cert.pem\"\n\n  ## Authentication Method, one of \"Certificate\", \"UserName\", or \"Anonymous\".  To\n  ## authenticate using a specific ID, select 'Certificate' or 'UserName'\n  # auth_method = \"Anonymous\"\n\n  ## Username and password required for auth_method = \"UserName\"\n  # username = \"\"\n  # password = \"\"\n\n  ## Option to select the metric timestamp to use. Valid options are:\n  ##     \"gather\" -- uses the time of receiving the data in telegraf\n  ##     \"server\" -- uses the timestamp provided by the server\n  ##     \"source\" -- uses the timestamp provided by the source\n  # timestamp = \"gather\"\n\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the OPCUA\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n\n  ## Include additional Fields in each metric\n  ## Available options are:\n  ##   DataType -- OPC-UA Data Type (string)\n  # optional_fields = []\n\n  ## Node ID configuration\n  ## name              - field name to use in the output\n  ## id                - OPC UA node ID string (e.g., \"ns=0;i=2262\" or \"nsu=http://...;s=Name\")\n  ## namespace         - OPC UA namespace of the node (integer value 0 thru 3)\n  ## namespace_uri     - OPC UA namespace URI (alternative to namespace for stable references)\n  ## identifier_type   - OPC UA ID type (s=string, i=numeric, g=guid, b=opaque)\n  ## identifier        - OPC UA ID (tag as shown in opcua browser)\n  ## default_tags      - extra tags to be added to the output metric (optional)\n  ##\n  ## Use EITHER 'id' OR the combination of 'namespace/namespace_uri' + 'identifier_type' + 'identifier'\n  ## Use either the inline notation or the bracketed notation, not both.\n\n  ## Inline notation using id string (recommended for simplicity)\n  # nodes = [\n  #   {name=\"ProductUri\", id=\"ns=0;i=2262\"},\n  #   {name=\"ServerState\", id=\"ns=0;i=2259\"},\n  # ]\n\n  ## Inline notation using individual fields (default_tags not supported yet)\n  # nodes = [\n  #   {name=\"\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  # ]\n\n  ## Bracketed notation using id string\n  # [[inputs.opcua.nodes]]\n  #   name = \"ProductUri\"\n  #   id = \"ns=0;i=2262\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n\n  ## Bracketed notation using individual fields\n  # [[inputs.opcua.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  # [[inputs.opcua.nodes]]\n  #   name = \"node3\"\n  #   namespace_uri = \"http://opcfoundation.org/UA/\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n\n  ## Node Group\n  ## Sets defaults so they aren't required in every node.\n  ## Default values can be set for:\n  ## * Metric name\n  ## * OPC UA namespace\n  ## * Identifier\n  ## * Default tags\n  ##\n  ## Multiple node groups are allowed\n  #[[inputs.opcua.group]]\n  ## Group Metric name. Overrides the top level name.  If unset, the\n  ## top level name is used.\n  # name =\n\n  ## Group default namespace. If a node in the group doesn't set its\n  ## namespace, this is used.\n  # namespace =\n\n  ## Group default namespace URI. Alternative to namespace for stable references.\n  ## If a node in the group doesn't set its namespace_uri, this is used.\n  # namespace_uri =\n\n  ## Group default identifier type. If a node in the group doesn't set its\n  ## identifier_type, this is used.\n  # identifier_type =\n\n  ## Default tags that are applied to every node in this group. Can be\n  ## overwritten in a node by setting a different value for the tag name.\n  ##   example: default_tags = { tag1 = \"value1\" }\n  # default_tags = {}\n\n  ## Node ID Configuration. Array of nodes with the same settings as above.\n  ## Use either the inline notation or the bracketed notation, not both.\n\n  ## Inline notation (default_tags not supported yet)\n  # nodes = [\n  #  {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #  {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #]\n\n  ## Bracketed notation\n  # [[inputs.opcua.group.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"override1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua.group.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.opcua.workarounds]\n  #   ## Set additional valid status codes, StatusOK (0x0) is always considered valid\n  #   # additional_valid_status_codes = [\"0xC0\"]\n\n  # [inputs.opcua.request_workarounds]\n  #   ## Use unregistered reads instead of registered reads\n  #   # use_unregistered_reads = false\n"
  },
  {
    "path": "plugins/inputs/opcua_listener/README.md",
    "content": "# OPC UA Client Listener Input Plugin\n\nThis service plugin receives data from an [OPC UA][opcua] server by subscribing\nto nodes and events.\n\n⭐ Telegraf v1.25.0\n🏷️ iot\n💻 all\n\n[opcua]: https://opcfoundation.org/about/opc-technologies/opc-ua/\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Retrieve data from OPCUA devices\n[[inputs.opcua_listener]]\n  ## Metric name\n  # name = \"opcua_listener\"\n  #\n  ## OPC UA Endpoint URL\n  # endpoint = \"opc.tcp://localhost:4840\"\n  #\n  ## Maximum time allowed to establish a connect to the endpoint.\n  # connect_timeout = \"10s\"\n  #\n  ## Behavior when we fail to connect to the endpoint on initialization. Valid options are:\n  ##     \"error\": throw an error and exits Telegraf\n  ##     \"ignore\": ignore this plugin if errors are encountered\n  #      \"retry\": retry connecting at each interval\n  # connect_fail_behavior = \"error\"\n  #\n  ## Maximum time allowed for a request over the established connection.\n  # request_timeout = \"5s\"\n  #\n  # Maximum time that a session shall remain open without activity.\n  # session_timeout = \"20m\"\n  #\n  ## The interval at which the server should at least update its monitored items.\n  ## Please note that the OPC UA server might reject the specified interval if it cannot meet the required update rate.\n  ## Therefore, always refer to the hardware/software documentation of your server to ensure the specified interval is supported.\n  # subscription_interval = \"100ms\"\n  #\n  ## Security policy, one of \"None\", \"Basic128Rsa15\", \"Basic256\",\n  ## \"Basic256Sha256\", or \"auto\"\n  # security_policy = \"auto\"\n  #\n  ## Security mode, one of \"None\", \"Sign\", \"SignAndEncrypt\", or \"auto\"\n  # security_mode = \"auto\"\n  #\n  ## Path to cert.pem. Required when security mode or policy isn't \"None\".\n  ## If cert path is not supplied, self-signed cert and key will be generated.\n  # certificate = \"/etc/telegraf/cert.pem\"\n  #\n  ## Path to private key.pem. Required when security mode or policy isn't \"None\".\n  ## If key path is not supplied, self-signed cert and key will be generated.\n  # private_key = \"/etc/telegraf/key.pem\"\n\n  ## Path to additional, explicitly trusted certificate for the remote endpoint\n  # remote_certificate = \"/etc/telegraf/opcua_server_cert.pem\"\n\n  ## Authentication Method, one of \"Certificate\", \"UserName\", or \"Anonymous\".  To\n  ## authenticate using a specific ID, select 'Certificate' or 'UserName'\n  # auth_method = \"Anonymous\"\n  #\n  ## Username. Required for auth_method = \"UserName\"\n  # username = \"\"\n  #\n  ## Password. Required for auth_method = \"UserName\"\n  # password = \"\"\n  #\n  ## Option to select the metric timestamp to use. Valid options are:\n  ##     \"gather\" -- uses the time of receiving the data in telegraf\n  ##     \"server\" -- uses the timestamp provided by the server\n  ##     \"source\" -- uses the timestamp provided by the source\n  # timestamp = \"gather\"\n  #\n  ## The default timetsamp format is RFC3339Nano\n  # Other timestamp layouts can be configured using the Go language time\n  # layout specification from https://golang.org/pkg/time/#Time.Format\n  # e.g.: json_timestamp_format = \"2006-01-02T15:04:05Z07:00\"\n  #timestamp_format = \"\"\n  #\n  #\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the OPCUA\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n  #\n  ## Include additional Fields in each metric\n  ## Available options are:\n  ##   DataType -- OPC-UA Data Type (string)\n  # optional_fields = []\n  #\n  ## Node ID configuration\n  ## name              - field name to use in the output\n  ## id                - OPC UA node ID string (e.g., \"ns=0;i=2262\" or \"nsu=http://...;s=Name\")\n  ## namespace         - OPC UA namespace of the node (integer value 0 thru 3)\n  ## namespace_uri     - OPC UA namespace URI (alternative to namespace for stable references)\n  ## identifier_type   - OPC UA ID type (s=string, i=numeric, g=guid, b=opaque)\n  ## identifier        - OPC UA ID (tag as shown in opcua browser)\n  ## default_tags      - extra tags to be added to the output metric (optional)\n  ## monitoring_params - additional settings for the monitored node (optional)\n  ##\n  ## Use EITHER 'id' OR the combination of 'namespace/namespace_uri' + 'identifier_type' + 'identifier'\n  ##\n  ## Monitoring parameters\n  ## sampling_interval  - interval at which the server should check for data\n  ##                      changes (default: 0s)\n  ## queue_size         - size of the notification queue (default: 10)\n  ## discard_oldest     - how notifications should be handled in case of full\n  ##                      notification queues, possible values:\n  ##                      true: oldest value added to queue gets replaced with new\n  ##                            (default)\n  ##                      false: last value added to queue gets replaced with new\n  ## data_change_filter - defines the condition under which a notification should\n  ##                      be reported\n  ##\n  ## Data change filter\n  ## trigger        - specify the conditions under which a data change notification\n  ##                  should be reported, possible values:\n  ##                  \"Status\": only report notifications if the status changes\n  ##                            (default if parameter is omitted)\n  ##                  \"StatusValue\": report notifications if either status or value\n  ##                                 changes\n  ##                  \"StatusValueTimestamp\": report notifications if either status,\n  ##                                          value or timestamp changes\n  ## deadband_type  - type of the deadband filter to be applied, possible values:\n  ##                  \"None\": no deadband filter is applied\n  ##                  \"Absolute\": absolute change in a data value to report a notification\n  ##                  \"Percent\": works only with nodes that have an EURange property set\n  ##                             and is defined as: send notification if\n  ##                             (last value - current value) >\n  ##                             (deadband_value/100.0) * ((high–low) of EURange)\n  ## deadband_value - value to deadband_type, must be a float value, no filter is set\n  ##                  for negative values\n  ##\n  ## Use either the inline notation or the bracketed notation, not both.\n  #\n  ## Inline notation using id string (recommended for simplicity)\n  # nodes = [\n  #   {name=\"ProductUri\", id=\"ns=0;i=2262\"},\n  #   {name=\"ServerState\", id=\"ns=0;i=2259\"}\n  # ]\n  #\n  ## Inline notation using individual fields (default_tags and monitoring_params not supported yet)\n  # nodes = [\n  #   {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #   {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"}\n  # ]\n  #\n  ## Bracketed notation using id string\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"ProductUri\"\n  #   id = \"ns=0;i=2262\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n\n  ## Bracketed notation using individual fields\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  #   [inputs.opcua_listener.nodes.monitoring_params]\n  #     sampling_interval = \"0s\"\n  #     queue_size = 10\n  #     discard_oldest = true\n  #\n  #     [inputs.opcua_listener.nodes.monitoring_params.data_change_filter]\n  #       trigger = \"Status\"\n  #       deadband_type = \"Absolute\"\n  #       deadband_value = 0.0\n  #\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node3\"\n  #   namespace_uri = \"http://opcfoundation.org/UA/\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  ## Node Group\n  ## Sets defaults so they aren't required in every node.\n  ## Default values can be set for:\n  ## * Metric name\n  ## * OPC UA namespace\n  ## * Identifier\n  ## * Default tags\n  ## * Sampling interval\n  ##\n  ## Multiple node groups are allowed\n  #[[inputs.opcua_listener.group]]\n  ## Group Metric name. Overrides the top level name.  If unset, the\n  ## top level name is used.\n  # name =\n  #\n  ## Group default namespace. If a node in the group doesn't set its\n  ## namespace, this is used.\n  # namespace =\n  #\n  ## Group default namespace URI. Alternative to namespace for stable references.\n  ## If a node in the group doesn't set its namespace_uri, this is used.\n  # namespace_uri =\n  #\n  ## Group default identifier type. If a node in the group doesn't set its\n  ## identifier_type, this is used.\n  # identifier_type =\n  #\n  ## Default tags that are applied to every node in this group. Can be\n  ## overwritten in a node by setting a different value for the tag name.\n  ##   example: default_tags = { tag1 = \"value1\" }\n  # default_tags = {}\n  #\n  ## Group default sampling interval. If a node in the group doesn't set its\n  ## sampling interval, this is used.\n  # sampling_interval = \"0s\"\n  #\n  ## Node ID Configuration.  Array of nodes with the same settings as above.\n  ## Use either the inline notation or the bracketed notation, not both.\n  #\n  ## Inline notation (default_tags and monitoring_params not supported yet)\n  # nodes = [\n  #  {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #  {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"}\n  #]\n  #\n  ## Bracketed notation\n  # [[inputs.opcua_listener.group.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"override1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua_listener.group.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  #   [inputs.opcua_listener.group.nodes.monitoring_params]\n  #     sampling_interval = \"0s\"\n  #     queue_size = 10\n  #     discard_oldest = true\n  #\n  #     [inputs.opcua_listener.group.nodes.monitoring_params.data_change_filter]\n  #       trigger = \"Status\"\n  #       deadband_type = \"Absolute\"\n  #       deadband_value = 0.0\n  #\n\n  ## Multiple event groups are allowed.\n  ## Event nodes support both 'id' string format and individual fields.\n  # [[inputs.opcua_listener.events]]\n  #   ## Polling interval for data collection\n  #   # sampling_interval = \"10s\"\n  #   ## Size of the notification queue\n  #   # queue_size = 10\n  #   ## Node parameter defaults for node definitions below (used when id is not specified)\n  #   # namespace = \"\"\n  #   # identifier_type = \"\"\n  #   ## Specifies OPCUA Event sources to filter on\n  #   # source_names = [\"SourceName1\", \"SourceName2\"]\n  #   ## Fields to capture from event notifications\n  #   fields = [\"Severity\", \"Message\", \"Time\"]\n  #\n  #   ## Type or level of events to capture from the monitored nodes.\n  #   ## Use 'id' string OR individual fields (namespace/identifier_type/identifier)\n  #   [inputs.opcua_listener.events.event_type_node]\n  #     id = \"ns=0;i=2041\"\n  #     # Or use individual fields:\n  #     # namespace = \"\"\n  #     # identifier_type = \"\"\n  #     # identifier = \"\"\n  #\n  #   ## Nodes to monitor for event notifications associated with the defined\n  #   ## event type. Use 'id' string OR individual fields.\n  #   [[inputs.opcua_listener.events.node_ids]]\n  #     id = \"ns=2;s=EventSource1\"\n  #     # Or use individual fields:\n  #     # namespace = \"\"\n  #     # identifier_type = \"\"\n  #     # identifier = \"\"\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.opcua_listener.workarounds]\n  #  ## Set additional valid status codes, StatusOK (0x0) is always considered valid\n  #  # additional_valid_status_codes = [\"0xC0\"]\n  #  ## Use unregistered reads instead of registered reads\n  #  # use_unregistered_reads = false\n```\n\n### Node Configuration\n\nAn OPC UA node ID may resemble: \"ns=3;s=Temperature\". In this example:\n\n- ns=3 is indicating the `namespace` is 3\n- s=Temperature is indicting that the `identifier_type` is a string and\n  `identifier` value is 'Temperature'\n- This example temperature node has a value of 79.0\n\n#### Using `id` String (Recommended)\n\nYou can specify nodes using the standard OPC UA node ID string format directly:\n\n```text\n{name=\"temp\", id=\"ns=3;s=Temperature\"},\n```\n\nThis is simpler and matches the format shown in OPC UA browsers.\n\n#### Using Individual Fields\n\nAlternatively, you can specify each component separately:\n\n```text\n{name=\"temp\", namespace=\"3\", identifier_type=\"s\", identifier=\"Temperature\"},\n```\n\n> [!NOTE]\n> Use either `id` OR the combination of\n> `namespace`/`namespace_uri` + `identifier_type` + `identifier`.\n> Do not mix both formats for the same node.\n\nThis node configuration produces a metric like this:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp=79.0,Quality=\"OK (0x0)\" 1597820490000000000\n```\n\nWith 'DataType' entered in Additional Metrics, this node configuration\nproduces a metric like this:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp=79.0,Quality=\"OK (0x0)\",DataType=\"Float\" 1597820490000000000\n```\n\nIf the value is an array, each element is unpacked into a field\nusing indexed keys. For example:\n\n```text\nopcua,id=ns\\=3;s\\=Temperature temp[0]=79.0,temp[1]=38.9,Quality=\"OK (0x0)\",DataType=\"Float\" 1597820490000000000\n```\n\n#### Namespace Index vs Namespace URI\n\nOPC UA supports two ways to specify namespaces:\n\n1. **Namespace Index** (`namespace`): An integer (0-3 or higher) that references\n   a position in the server's namespace array. This is simpler but can change if\n   the server is restarted or reconfigured.\n\n2. **Namespace URI** (`namespace_uri`): A string URI that uniquely identifies\n   the namespace. This is more stable across server restarts but requires the\n   plugin to fetch the namespace array from the server to resolve the URI to an\n   index.\n\n**When to use namespace index:**\n\n- For standard OPC UA namespaces (0 = OPC UA, 1 = Local Server)\n- When namespace stability is not a concern\n- For simpler configuration\n\n**When to use namespace URI:**\n\n- When you need consistent node references across server restarts\n- For production environments where namespace indices might change\n- When working with vendor-specific namespaces\n\n**Example using namespace URI:**\n\n```toml\n[[inputs.opcua_listener.nodes]]\n  name = \"ServerStatus\"\n  namespace_uri = \"http://opcfoundation.org/UA/\"\n  identifier_type = \"i\"\n  identifier = \"2256\"\n```\n\nThis produces the same node ID internally as:\n\n```toml\n[[inputs.opcua_listener.nodes]]\n  name = \"ServerStatus\"\n  namespace = \"0\"\n  identifier_type = \"i\"\n  identifier = \"2256\"\n```\n\nNote: You must specify either `namespace` or `namespace_uri`, not both.\n\n#### Group Configuration\n\nGroups can set default values for the namespace (index or URI), identifier type,\ntags settings and sampling interval. The default values apply to all the nodes\nin the group. If a default is set, a node may omit the setting altogether. This\nsimplifies node configuration, especially when many nodes share the same\nnamespace or identifier type.\n\nThe output metric will include tags set in the group and the node.  If\na tag with the same name is set in both places, the tag value from the\nnode is used.\n\nThis example group configuration has three groups with two nodes each:\n\n```toml\n  # Group 1\n  [[inputs.opcua_listener.group]]\n    name = \"group1_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group1_tag = \"val1\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"name\"\n      identifier = \"1001\"\n      default_tags = { node1_tag = \"val2\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"name\"\n      identifier = \"1002\"\n      default_tags = {node1_tag = \"val3\"}\n\n  # Group 2\n  [[inputs.opcua_listener.group]]\n    name = \"group2_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group2_tag = \"val3\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"saw\"\n      identifier = \"1003\"\n      default_tags = { node2_tag = \"val4\" }\n    [[inputs.opcua.group.nodes]]\n      name = \"sin\"\n      identifier = \"1004\"\n\n  # Group 3\n  [[inputs.opcua_listener.group]]\n    name = \"group3_metric_name\"\n    namespace = \"3\"\n    identifier_type = \"i\"\n    default_tags = { group3_tag = \"val5\" }\n    nodes = [\n      {name=\"name\", identifier=\"1001\"},\n      {name=\"name\", identifier=\"1002\"},\n    ]\n```\n\n### Event Configuration\n\nDefining events allows subscribing to events with the specific node IDs and\nfiltering criteria based on the event type and source. The plugin subscribes to\nthe specified `event_type` Node-IDs and collects events that meet the defined\ncriteria. The `node_ids` parameter specifies the nodes to monitor for events\n(monitored items). However, the actual subscription is based on the\n`event_type_node` determining the events to capture.\n\n#### Event Group Configuration\n\nYou can define multiple groups for the event streaming to subscribe to different\nevent types. Each group allows to specify defaults for `namespace` and\n`identifier_type` being overwritten by settings in `node_ids`. The group\ndefaults for node information will not affected the `event_type_node` setting\nand all paramters must be set in this section.\n\nThis example group configuration shows how to use group settings:\n\n```toml\n# Group 1\n[[inputs.opcua_listener.events]]\n   sampling_interval = \"10s\"\n   queue_size = \"100\"\n   source_names = [\"SourceName1\", \"SourceName2\"]\n   fields = [\"Severity\", \"Message\", \"Time\"]\n\n   [inputs.opcua_listener.events.event_type_node]\n     namespace = \"1\"\n     identifier_type = \"i\"\n     identifier = \"1234\"\n\n   [[inputs.opcua_listener.events.node_ids]]\n     namespace = \"2\"\n     identifier_type = \"i\"\n     identifier = \"2345\"\n\n# Group 2\n[[inputs.opcua_listener.events]]\n   sampling_interval = \"10s\"\n   queue_size = \"100\"\n   namespace = \"3\"\n   identifier_type = \"s\"\n   source_names = [\"SourceName1\", \"SourceName2\"]\n   fields = [\"Severity\", \"Message\", \"Time\"]\n\n   [inputs.opcua_listener.events.event_type_node]\n     namespace = \"1\"\n     identifier_type = \"i\"\n     identifier = \"5678\"\n\n    node_ids = [\n      {identifier=\"Sensor1\"}, // default values will be used for namespace and identifier_type\n      {namespace=\"2\", identifier=\"TemperatureSensor\"}, // default values will be used for identifier_type\n      {namespace=\"5\", identifier_type=\"i\", identifier=\"2002\"} // no default values will be used\n    ]\n```\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the configured\n`nodes`, `events` and the corresponding groups.\n\n## Example Output\n\n```text\ngroup1_metric_name,group1_tag=val1,id=ns\\=3;i\\=1001,node1_tag=val2 name=0,Quality=\"OK (0x0)\" 1606893246000000000\ngroup1_metric_name,group1_tag=val1,id=ns\\=3;i\\=1002,node1_tag=val3 name=-1.389117,Quality=\"OK (0x0)\" 1606893246000000000\ngroup2_metric_name,group2_tag=val3,id=ns\\=3;i\\=1003,node2_tag=val4 Quality=\"OK (0x0)\",saw=-1.6 1606893246000000000\ngroup2_metric_name,group2_tag=val3,id=ns\\=3;i\\=1004 sin=1.902113,Quality=\"OK (0x0)\" 1606893246000000000\n```\n"
  },
  {
    "path": "plugins/inputs/opcua_listener/opcua_listener.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage opcua_listener\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype OpcUaListener struct {\n\tsubscribeClientConfig\n\tclient *subscribeClient\n\tLog    telegraf.Logger `toml:\"-\"`\n}\n\n//go:embed sample.conf\nvar sampleConfig string\n\nfunc (*OpcUaListener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *OpcUaListener) Init() (err error) {\n\tswitch o.ConnectFailBehavior {\n\tcase \"\":\n\t\to.ConnectFailBehavior = \"error\"\n\tcase \"error\", \"ignore\", \"retry\":\n\t\t// Do nothing as these are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown setting %q for 'connect_fail_behavior'\", o.ConnectFailBehavior)\n\t}\n\to.client, err = o.subscribeClientConfig.createSubscribeClient(o.Log)\n\treturn err\n}\n\nfunc (o *OpcUaListener) Start(acc telegraf.Accumulator) error {\n\treturn o.connect(acc)\n}\n\nfunc (o *OpcUaListener) Gather(acc telegraf.Accumulator) error {\n\tif o.client.State() == opcua.Connected || o.subscribeClientConfig.ConnectFailBehavior == \"ignore\" {\n\t\treturn nil\n\t}\n\treturn o.connect(acc)\n}\n\nfunc (o *OpcUaListener) Stop() {\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tselect {\n\tcase <-o.client.stop(ctx):\n\t\to.Log.Infof(\"Unsubscribed OPC UA successfully\")\n\tcase <-ctx.Done(): // Timeout context\n\t\to.Log.Warn(\"Timeout while stopping OPC UA subscription\")\n\t}\n\tcancel()\n}\n\nfunc (o *OpcUaListener) connect(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\tch, err := o.client.startMonitoring(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgo func() {\n\t\tfor {\n\t\t\tm, ok := <-ch\n\t\t\tif !ok {\n\t\t\t\to.Log.Debug(\"Metric collection stopped due to closed channel\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"opcua_listener\", func() telegraf.Input {\n\t\treturn &OpcUaListener{\n\t\t\tsubscribeClientConfig: subscribeClientConfig{\n\t\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\t\t\tSecurityPolicy: \"auto\",\n\t\t\t\t\t\tSecurityMode:   \"auto\",\n\t\t\t\t\t\tCertificate:    \"/etc/telegraf/cert.pem\",\n\t\t\t\t\t\tPrivateKey:     \"/etc/telegraf/key.pem\",\n\t\t\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\t\t\tConnectTimeout: config.Duration(5 * time.Second),\n\t\t\t\t\t\tRequestTimeout: config.Duration(10 * time.Second),\n\t\t\t\t\t},\n\t\t\t\t\tMetricName: \"opcua\",\n\t\t\t\t\tTimestamp:  input.TimestampSourceTelegraf,\n\t\t\t\t},\n\t\t\t\tSubscriptionInterval: config.Duration(100 * time.Millisecond),\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/opcua_listener/opcua_listener_test.go",
    "content": "package opcua_listener\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/gopcua/opcua/ua\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst servicePort = \"4840\"\n\ntype opcTags struct {\n\tname           string\n\tnamespace      string\n\tidentifierType string\n\tidentifier     string\n\twant           interface{}\n}\n\nfunc mapOPCTag(tags opcTags) (out input.NodeSettings) {\n\tout.FieldName = tags.name\n\tout.Namespace = tags.namespace\n\tout.IdentifierType = tags.identifierType\n\tout.Identifier = tags.identifier\n\treturn out\n}\n\nfunc TestInitPluginWithBadConnectFailBehaviorValue(t *testing.T) {\n\tplugin := OpcUaListener{\n\t\tsubscribeClientConfig: subscribeClientConfig{\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       \"opc.tcp://notarealserver:4840\",\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tConnectTimeout: config.Duration(5 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(10 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tTimestamp:  input.TimestampSourceTelegraf,\n\t\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\t},\n\t\t\tConnectFailBehavior:  \"notanoption\",\n\t\t\tSubscriptionInterval: config.Duration(100 * time.Millisecond),\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\terr := plugin.Init()\n\trequire.ErrorContains(t, err, \"unknown setting \\\"notanoption\\\" for 'connect_fail_behavior'\")\n}\n\nfunc TestStartPlugin(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\tplugin := OpcUaListener{\n\t\tsubscribeClientConfig: subscribeClientConfig{\n\t\t\tInputClientConfig: input.InputClientConfig{\n\t\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\t\tEndpoint:       \"opc.tcp://notarealserver:4840\",\n\t\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\t\tConnectTimeout: config.Duration(5 * time.Second),\n\t\t\t\t\tRequestTimeout: config.Duration(10 * time.Second),\n\t\t\t\t},\n\t\t\t\tMetricName: \"opcua\",\n\t\t\t\tTimestamp:  input.TimestampSourceTelegraf,\n\t\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\t},\n\t\t\tSubscriptionInterval: config.Duration(100 * time.Millisecond),\n\t\t},\n\t\tLog: testutil.Logger{},\n\t}\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t}\n\tfor _, tags := range testopctags {\n\t\tplugin.subscribeClientConfig.RootNodes = append(plugin.subscribeClientConfig.RootNodes, mapOPCTag(tags))\n\t}\n\trequire.NoError(t, plugin.Init())\n\terr := plugin.Start(acc)\n\trequire.ErrorContains(t, err, \"could not resolve address\")\n\n\tplugin.subscribeClientConfig.ConnectFailBehavior = \"ignore\"\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(acc))\n\trequire.Equal(t, opcua.Disconnected, plugin.client.OpcUAClient.State())\n\tplugin.Stop()\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\tplugin.subscribeClientConfig.ConnectFailBehavior = \"retry\"\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(acc))\n\trequire.Equal(t, opcua.Disconnected, plugin.client.OpcUAClient.State())\n\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\n\tdefer container.Terminate()\n\tnewEndpoint := fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort])\n\tplugin.client.Config.Endpoint = newEndpoint\n\tplugin.client.OpcUAClient.Config.Endpoint = newEndpoint\n\terr = plugin.Gather(acc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, opcua.Connected, plugin.client.OpcUAClient.State())\n}\n\nfunc TestSubscribeClientIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t\t{\"badnode\", \"1\", \"i\", \"1337\", nil},\n\t\t{\"goodnode\", \"1\", \"s\", \"the.answer\", int32(42)},\n\t\t{\"DateTime\", \"1\", \"i\", \"51037\", \"0001-01-01T00:00:00Z\"},\n\t}\n\ttagsRemaining := make([]string, 0, len(testopctags))\n\tfor i, tag := range testopctags {\n\t\tif tag.want != nil {\n\t\t\ttagsRemaining = append(tagsRemaining, testopctags[i].name)\n\t\t}\n\t}\n\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tfor _, tags := range testopctags {\n\t\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, mapOPCTag(tags))\n\t}\n\to, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\t// give initial setup a couple extra attempts, as on CircleCI this can be\n\t// attempted to soon\n\trequire.Eventually(t, func() bool {\n\t\treturn o.SetupOptions() == nil\n\t}, 5*time.Second, 10*time.Millisecond)\n\n\terr = o.connect()\n\trequire.NoError(t, err, \"Connection failed\")\n\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second*10)\n\tdefer cancel()\n\tres, err := o.startMonitoring(ctx)\n\trequire.Equal(t, opcua.Connected, o.State())\n\trequire.NoError(t, err)\n\n\tfor {\n\t\tselect {\n\t\tcase m := <-res:\n\t\t\tfor fieldName, fieldValue := range m.Fields() {\n\t\t\t\tfor _, tag := range testopctags {\n\t\t\t\t\tif fieldName != tag.name {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif tag.want == nil {\n\t\t\t\t\t\tt.Errorf(\"Tag: %s has value: %v\", tag.name, fieldValue)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\trequire.Equal(t, tag.want, fieldValue)\n\n\t\t\t\t\tnewRemaining := make([]string, 0, len(tagsRemaining))\n\t\t\t\t\tfor _, remainingTag := range tagsRemaining {\n\t\t\t\t\t\tif fieldName != remainingTag {\n\t\t\t\t\t\t\tnewRemaining = append(newRemaining, remainingTag)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(newRemaining) == 0 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\ttagsRemaining = newRemaining\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase <-ctx.Done():\n\t\t\tvar sb strings.Builder\n\t\t\tfor _, tag := range tagsRemaining {\n\t\t\t\tsb.WriteString(tag)\n\t\t\t\tsb.WriteString(\", \")\n\t\t\t}\n\t\t\tt.Errorf(\"Tags %s are remaining without a received value\", sb.String())\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestSubscribeClientIntegrationAdditionalFields(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"open62541/open62541\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\twait.ForLog(\"TCP network layer listening on opc.tcp://\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\ttestopctags := []opcTags{\n\t\t{\"ProductName\", \"0\", \"i\", \"2261\", \"open62541 OPC UA Server\"},\n\t\t{\"ProductUri\", \"0\", \"i\", \"2262\", \"http://open62541.org\"},\n\t\t{\"ManufacturerName\", \"0\", \"i\", \"2263\", \"open62541\"},\n\t\t{\"badnode\", \"1\", \"i\", \"1337\", nil},\n\t\t{\"goodnode\", \"1\", \"s\", \"the.answer\", int32(42)},\n\t\t{\"DateTime\", \"1\", \"i\", \"51037\", \"0001-01-01T00:00:00Z\"},\n\t}\n\ttestopctypes := []string{\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"Null\",\n\t\t\"Int32\",\n\t\t\"DateTime\",\n\t}\n\ttestopcquality := []string{\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"User does not have permission to perform the requested operation. StatusBadUserAccessDenied (0x801F0000)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t\t\"The operation succeeded. StatusGood (0x0)\",\n\t}\n\texpectedopcmetrics := make([]telegraf.Metric, 0, len(testopctags))\n\tfor i, x := range testopctags {\n\t\tnow := time.Now()\n\t\ttags := map[string]string{\n\t\t\t\"id\": fmt.Sprintf(\"ns=%s;%s=%s\", x.namespace, x.identifierType, x.identifier),\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\tx.name:     x.want,\n\t\t\t\"Quality\":  testopcquality[i],\n\t\t\t\"DataType\": testopctypes[i],\n\t\t}\n\t\texpectedopcmetrics = append(expectedopcmetrics, metric.New(\"testing\", tags, fields, now))\n\t}\n\n\ttagsRemaining := make([]string, 0, len(testopctags))\n\tfor i, tag := range testopctags {\n\t\tif tag.want != nil {\n\t\t\ttagsRemaining = append(tagsRemaining, testopctags[i].name)\n\t\t}\n\t}\n\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       fmt.Sprintf(\"opc.tcp://%s:%s\", container.Address, container.Ports[servicePort]),\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t\tOptionalFields: []string{\"DataType\"},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tfor _, tags := range testopctags {\n\t\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, mapOPCTag(tags))\n\t}\n\to, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\t// give initial setup a couple extra attempts, as on CircleCI this can be\n\t// attempted to soon\n\trequire.Eventually(t, func() bool {\n\t\treturn o.SetupOptions() == nil\n\t}, 5*time.Second, 10*time.Millisecond)\n\n\trequire.NoError(t, o.connect(), \"Connection failed\")\n\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second*10)\n\tdefer cancel()\n\tres, err := o.startMonitoring(ctx)\n\trequire.NoError(t, err)\n\n\tfor {\n\t\tselect {\n\t\tcase m := <-res:\n\t\t\tfor fieldName, fieldValue := range m.Fields() {\n\t\t\t\tfor _, tag := range testopctags {\n\t\t\t\t\tif fieldName != tag.name {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\t// nil-value tags should not be sent from server, error if one does\n\t\t\t\t\tif tag.want == nil {\n\t\t\t\t\t\tt.Errorf(\"Tag: %s has value: %v\", tag.name, fieldValue)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tnewRemaining := make([]string, 0, len(tagsRemaining))\n\t\t\t\t\tfor _, remainingTag := range tagsRemaining {\n\t\t\t\t\t\tif fieldName != remainingTag {\n\t\t\t\t\t\t\tnewRemaining = append(newRemaining, remainingTag)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(newRemaining) == 0 {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\t// Test if the received metric matches one of the expected\n\t\t\t\t\ttestutil.RequireMetricsSubset(t, []telegraf.Metric{m}, expectedopcmetrics, testutil.IgnoreTime())\n\t\t\t\t\ttagsRemaining = newRemaining\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase <-ctx.Done():\n\t\t\tvar sb strings.Builder\n\t\t\tfor _, tag := range tagsRemaining {\n\t\t\t\tsb.WriteString(tag)\n\t\t\t\tsb.WriteString(\", \")\n\t\t\t}\n\t\t\tt.Errorf(\"Tags %s are remaining without a received value\", sb.String())\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestSubscribeClientConfig(t *testing.T) {\n\ttoml := `\n[[inputs.opcua_listener]]\nname = \"localhost\"\nendpoint = \"opc.tcp://localhost:4840\"\nconnect_timeout = \"10s\"\nrequest_timeout = \"5s\"\nsubscription_interval = \"200ms\"\nconnect_fail_behavior = \"error\"\nsecurity_policy = \"auto\"\nsecurity_mode = \"auto\"\ncertificate = \"/etc/telegraf/cert.pem\"\nprivate_key = \"/etc/telegraf/key.pem\"\nauth_method = \"Anonymous\"\ntimestamp_format = \"2006-01-02T15:04:05Z07:00\"\nusername = \"\"\npassword = \"\"\n\noptional_fields = [\"DataType\"]\n\nnodes = [\n  {name=\"name\",  namespace=\"1\", identifier_type=\"s\", identifier=\"one\"},\n  {name=\"name2\", namespace=\"2\", identifier_type=\"s\", identifier=\"two\"},\n]\n\n[[inputs.opcua_listener.group]]\nname = \"foo\"\nnamespace = \"3\"\nidentifier_type = \"i\"\ndefault_tags = {tag1=\"val1\", tag2=\"val2\"}\n[[inputs.opcua_listener.group.nodes]]\n  name = \"name3\"\n  identifier = \"3000\"\n  default_tags = {tag3=\"val3\"}\n\n[[inputs.opcua_listener.group]]\nname = \"bar\"\nnamespace = \"0\"\nidentifier_type = \"i\"\ndefault_tags = {tag1=\"val1\", tag2=\"val2\"}\n[[inputs.opcua_listener.group.nodes]]\n  name = \"name4\"\n  identifier = \"4000\"\n  default_tags = {tag1=\"override\"}\n\n[inputs.opcua_listener.workarounds]\nadditional_valid_status_codes = [\"0xC0\"]\n`\n\n\tc := config.NewConfig()\n\terr := c.LoadConfigData([]byte(toml), config.EmptySourcePath)\n\trequire.NoError(t, err)\n\n\trequire.Len(t, c.Inputs, 1)\n\n\to, ok := c.Inputs[0].Input.(*OpcUaListener)\n\trequire.True(t, ok)\n\n\trequire.Equal(t, \"localhost\", o.subscribeClientConfig.MetricName)\n\trequire.Equal(t, \"opc.tcp://localhost:4840\", o.subscribeClientConfig.Endpoint)\n\trequire.Equal(t, config.Duration(10*time.Second), o.subscribeClientConfig.ConnectTimeout)\n\trequire.Equal(t, config.Duration(5*time.Second), o.subscribeClientConfig.RequestTimeout)\n\trequire.Equal(t, config.Duration(200*time.Millisecond), o.subscribeClientConfig.SubscriptionInterval)\n\trequire.Equal(t, \"error\", o.subscribeClientConfig.ConnectFailBehavior)\n\trequire.Equal(t, \"auto\", o.subscribeClientConfig.SecurityPolicy)\n\trequire.Equal(t, \"auto\", o.subscribeClientConfig.SecurityMode)\n\trequire.Equal(t, \"/etc/telegraf/cert.pem\", o.subscribeClientConfig.Certificate)\n\trequire.Equal(t, \"/etc/telegraf/key.pem\", o.subscribeClientConfig.PrivateKey)\n\trequire.Equal(t, \"Anonymous\", o.subscribeClientConfig.AuthMethod)\n\trequire.True(t, o.subscribeClientConfig.Username.Empty())\n\trequire.True(t, o.subscribeClientConfig.Password.Empty())\n\trequire.Equal(t, []input.NodeSettings{\n\t\t{\n\t\t\tFieldName:      \"name\",\n\t\t\tNamespace:      \"1\",\n\t\t\tIdentifierType: \"s\",\n\t\t\tIdentifier:     \"one\",\n\t\t},\n\t\t{\n\t\t\tFieldName:      \"name2\",\n\t\t\tNamespace:      \"2\",\n\t\t\tIdentifierType: \"s\",\n\t\t\tIdentifier:     \"two\",\n\t\t},\n\t}, o.subscribeClientConfig.RootNodes)\n\trequire.Equal(t, []input.NodeGroupSettings{\n\t\t{\n\t\t\tMetricName:     \"foo\",\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tDefaultTags:    map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"},\n\t\t\tNodes: []input.NodeSettings{{\n\t\t\t\tFieldName:   \"name3\",\n\t\t\t\tIdentifier:  \"3000\",\n\t\t\t\tDefaultTags: map[string]string{\"tag3\": \"val3\"},\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\tMetricName:     \"bar\",\n\t\t\tNamespace:      \"0\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tDefaultTags:    map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"},\n\t\t\tNodes: []input.NodeSettings{{\n\t\t\t\tFieldName:   \"name4\",\n\t\t\t\tIdentifier:  \"4000\",\n\t\t\t\tDefaultTags: map[string]string{\"tag1\": \"override\"},\n\t\t\t}},\n\t\t},\n\t}, o.subscribeClientConfig.Groups)\n\trequire.Equal(t, opcua.OpcUAWorkarounds{AdditionalValidStatusCodes: []string{\"0xC0\"}}, o.subscribeClientConfig.Workarounds)\n\trequire.Equal(t, []string{\"DataType\"}, o.subscribeClientConfig.OptionalFields)\n}\n\nfunc TestSubscribeClientConfigWithMonitoringParams(t *testing.T) {\n\ttoml := `\n[[inputs.opcua_listener]]\nname = \"localhost\"\nendpoint = \"opc.tcp://localhost:4840\"\nsubscription_interval = \"200ms\"\n\n[[inputs.opcua_listener.group]]\nname = \"foo\"\nnamespace = \"3\"\nidentifier_type = \"i\"\ndefault_tags = {tag1=\"val1\", tag2=\"val2\"}\n[[inputs.opcua_listener.group.nodes]]\n  name = \"name3\"\n  identifier = \"3000\"\n  default_tags = {tag3=\"val3\"}\n\n[inputs.opcua_listener.group.nodes.monitoring_params]\nsampling_interval = \"50ms\"\nqueue_size = 10\ndiscard_oldest = true\n\n[inputs.opcua_listener.group.nodes.monitoring_params.data_change_filter]\ntrigger = \"StatusValue\"\ndeadband_type = \"Absolute\"\ndeadband_value = 100.0\n`\n\n\tc := config.NewConfig()\n\terr := c.LoadConfigData([]byte(toml), config.EmptySourcePath)\n\trequire.NoError(t, err)\n\n\trequire.Len(t, c.Inputs, 1)\n\n\to, ok := c.Inputs[0].Input.(*OpcUaListener)\n\trequire.True(t, ok)\n\n\tqueueSize := uint32(10)\n\tdiscardOldest := true\n\tdeadbandValue := 100.0\n\trequire.Equal(t, []input.NodeGroupSettings{\n\t\t{\n\t\t\tMetricName:     \"foo\",\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tDefaultTags:    map[string]string{\"tag1\": \"val1\", \"tag2\": \"val2\"},\n\t\t\tNodes: []input.NodeSettings{{\n\t\t\t\tFieldName:   \"name3\",\n\t\t\t\tIdentifier:  \"3000\",\n\t\t\t\tDefaultTags: map[string]string{\"tag3\": \"val3\"},\n\t\t\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\t\t\tSamplingInterval: 50000000,\n\t\t\t\t\tQueueSize:        &queueSize,\n\t\t\t\t\tDiscardOldest:    &discardOldest,\n\t\t\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\t\t\tTrigger:       \"StatusValue\",\n\t\t\t\t\t\tDeadbandType:  \"Absolute\",\n\t\t\t\t\t\tDeadbandValue: &deadbandValue,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t}, o.subscribeClientConfig.Groups)\n}\n\nfunc TestSubscribeClientConfigInvalidTrigger(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger: \"not_valid\",\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"trigger 'not_valid' not supported, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigMissingTrigger(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tDeadbandType: \"Absolute\",\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"trigger '' not supported, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigInvalidDeadbandType(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:      \"Status\",\n\t\t\t\tDeadbandType: \"not_valid\",\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"deadband_type 'not_valid' not supported, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigMissingDeadbandType(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger: \"Status\",\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"deadband_type '' not supported, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigInvalidDeadbandValue(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tdeadbandValue := -1.0\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:       \"Status\",\n\t\t\t\tDeadbandType:  \"Absolute\",\n\t\t\t\tDeadbandValue: &deadbandValue,\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"negative deadband_value not supported, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigMissingDeadbandValue(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:      \"Status\",\n\t\t\t\tDeadbandType: \"Absolute\",\n\t\t\t},\n\t\t},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"deadband_value was not set, node 'ns=3;i=1'\")\n}\n\nfunc TestSubscribeClientConfigValidMonitoringParams(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\n\tvar queueSize uint32 = 10\n\tdiscardOldest := true\n\tdeadbandValue := 10.0\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tSamplingInterval: 50000000,\n\t\t\tQueueSize:        &queueSize,\n\t\t\tDiscardOldest:    &discardOldest,\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:       \"Status\",\n\t\t\t\tDeadbandType:  \"Absolute\",\n\t\t\t\tDeadbandValue: &deadbandValue,\n\t\t\t},\n\t\t},\n\t})\n\n\tsubClient, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\trequire.Equal(t, &ua.MonitoringParameters{\n\t\tSamplingInterval: 50,\n\t\tQueueSize:        queueSize,\n\t\tDiscardOldest:    discardOldest,\n\t\tFilter: ua.NewExtensionObject(\n\t\t\t&ua.DataChangeFilter{\n\t\t\t\tTrigger:       ua.DataChangeTriggerStatus,\n\t\t\t\tDeadbandType:  uint32(ua.DeadbandTypeAbsolute),\n\t\t\t\tDeadbandValue: deadbandValue,\n\t\t\t},\n\t\t),\n\t}, subClient.monitoredItemsReqs[0].RequestedParameters)\n}\n\nfunc TestSubscribeClientConfigValidMonitoringParamsNoDeadband(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName: \"testing\",\n\t\t\tRootNodes:  make([]input.NodeSettings, 0),\n\t\t\tGroups:     make([]input.NodeGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\n\tvar queueSize uint32 = 10\n\tdiscardOldest := true\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tSamplingInterval: 50000000,\n\t\t\tQueueSize:        &queueSize,\n\t\t\tDiscardOldest:    &discardOldest,\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:      \"Status\",\n\t\t\t\tDeadbandType: \"None\",\n\t\t\t},\n\t\t},\n\t})\n\n\tsubClient, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\trequire.Equal(t, &ua.MonitoringParameters{\n\t\tSamplingInterval: 50,\n\t\tQueueSize:        queueSize,\n\t\tDiscardOldest:    discardOldest,\n\t\tFilter: ua.NewExtensionObject(\n\t\t\t&ua.DataChangeFilter{\n\t\t\t\tTrigger:       ua.DataChangeTriggerStatus,\n\t\t\t\tDeadbandType:  uint32(ua.DeadbandTypeNone),\n\t\t\t\tDeadbandValue: 0,\n\t\t\t},\n\t\t),\n\t}, subClient.monitoredItemsReqs[0].RequestedParameters)\n}\n\nfunc TestSubscribeClientConfigValidMonitoringAndEventParams(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://localhost:4840\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tRootNodes:   make([]input.NodeSettings, 0),\n\t\t\tGroups:      make([]input.NodeGroupSettings, 0),\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\n\tvar queueSize uint32 = 10\n\tdiscardOldest := true\n\tdeadbandValue := 10.0\n\tsubscribeConfig.RootNodes = append(subscribeConfig.RootNodes, input.NodeSettings{\n\t\tFieldName:      \"foo\",\n\t\tNamespace:      \"3\",\n\t\tIdentifier:     \"1\",\n\t\tIdentifierType: \"i\",\n\t\tMonitoringParams: input.MonitoringParameters{\n\t\t\tSamplingInterval: 50000000,\n\t\t\tQueueSize:        &queueSize,\n\t\t\tDiscardOldest:    &discardOldest,\n\t\t\tDataChangeFilter: &input.DataChangeFilter{\n\t\t\t\tTrigger:       \"Status\",\n\t\t\t\tDeadbandType:  \"Absolute\",\n\t\t\t\tDeadbandValue: &deadbandValue,\n\t\t\t},\n\t\t},\n\t})\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"13\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\tsubClient, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\trequire.Equal(t, &ua.MonitoringParameters{\n\t\tSamplingInterval: 50,\n\t\tQueueSize:        queueSize,\n\t\tDiscardOldest:    discardOldest,\n\t\tFilter: ua.NewExtensionObject(\n\t\t\t&ua.DataChangeFilter{\n\t\t\t\tTrigger:       ua.DataChangeTriggerStatus,\n\t\t\t\tDeadbandType:  uint32(ua.DeadbandTypeAbsolute),\n\t\t\t\tDeadbandValue: deadbandValue,\n\t\t\t},\n\t\t),\n\t}, subClient.monitoredItemsReqs[0].RequestedParameters)\n}\n\nfunc TestSubscribeClientConfigValidEventStreamingParams(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"13\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n}\n\nfunc TestSubscribeClientConfigEventInputMissingSamplingInterval(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n}\n\nfunc TestSubscribeClientConfigEventInputMissingEventType(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tNamespace:        \"3\",\n\t\tIdentifierType:   \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"invalid event_type_node_settings\")\n}\n\nfunc TestSubscribeClientConfigEventMissingEventTypeNamespace(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"must specify either 'namespace' or 'namespace_uri'\")\n}\n\nfunc TestSubscribeClientConfigEventMissingEventTypeIdentifierType(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:  \"3\",\n\t\t\tIdentifier: \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"identifier_type must be set\")\n}\n\nfunc TestSubscribeClientConfigEventMissingEventTypeIdentifier(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"identifier must be set\")\n}\n\nfunc TestSubscribeClientConfigEventInputMissingNodeIDs(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tSourceNames:    []string{\"SensorXYZ\"},\n\t\tFields:         []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"at least one node_id must be specified\")\n}\n\nfunc TestSubscribeClientConfigEventInputMissingFields(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"at least one Field must be specified\")\n}\n\nfunc TestSubscribeClientConfigEventInputInvalidFields(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tNamespace:      \"3\",\n\t\t\t\tIdentifierType: \"i\",\n\t\t\t\tIdentifier:     \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"Fieldname\", \"\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.ErrorContains(t, err, \"empty field name in fields stanza\")\n}\n\nfunc TestSubscribeClientConfigValidEventStreamingDefaultNodeParams(t *testing.T) {\n\tsubscribeConfig := subscribeClientConfig{\n\t\tInputClientConfig: input.InputClientConfig{\n\t\t\tOpcUAClientConfig: opcua.OpcUAClientConfig{\n\t\t\t\tEndpoint:       \"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer\",\n\t\t\t\tSecurityPolicy: \"None\",\n\t\t\t\tSecurityMode:   \"None\",\n\t\t\t\tAuthMethod:     \"Anonymous\",\n\t\t\t\tConnectTimeout: config.Duration(10 * time.Second),\n\t\t\t\tRequestTimeout: config.Duration(1 * time.Second),\n\t\t\t\tWorkarounds:    opcua.OpcUAWorkarounds{},\n\t\t\t},\n\t\t\tMetricName:  \"testing\",\n\t\t\tEventGroups: make([]input.EventGroupSettings, 0),\n\t\t},\n\t\tSubscriptionInterval: 0,\n\t}\n\tsubscribeConfig.EventGroups = append(subscribeConfig.EventGroups, input.EventGroupSettings{\n\t\tSamplingInterval: 1.0,\n\t\tEventTypeNode: input.EventNodeSettings{\n\t\t\tNamespace:      \"3\",\n\t\t\tIdentifierType: \"i\",\n\t\t\tIdentifier:     \"1234\",\n\t\t},\n\t\tNamespace:      \"3\",\n\t\tIdentifierType: \"i\",\n\t\tNodeIDSettings: []input.EventNodeSettings{\n\t\t\t{\n\t\t\t\tIdentifier: \"12\",\n\t\t\t},\n\t\t},\n\t\tSourceNames: []string{\"SensorXYZ\"},\n\t\tFields:      []string{\"PressureValue\"},\n\t})\n\n\t_, err := subscribeConfig.createSubscribeClient(testutil.Logger{})\n\trequire.NoError(t, err)\n\n\to := subscribeConfig.InputClientConfig.EventGroups[0].NodeIDSettings[0]\n\trequire.Equal(t, \"i\", o.IdentifierType)\n\trequire.Equal(t, \"3\", o.Namespace)\n}\n"
  },
  {
    "path": "plugins/inputs/opcua_listener/sample.conf",
    "content": "# Retrieve data from OPCUA devices\n[[inputs.opcua_listener]]\n  ## Metric name\n  # name = \"opcua_listener\"\n  #\n  ## OPC UA Endpoint URL\n  # endpoint = \"opc.tcp://localhost:4840\"\n  #\n  ## Maximum time allowed to establish a connect to the endpoint.\n  # connect_timeout = \"10s\"\n  #\n  ## Behavior when we fail to connect to the endpoint on initialization. Valid options are:\n  ##     \"error\": throw an error and exits Telegraf\n  ##     \"ignore\": ignore this plugin if errors are encountered\n  #      \"retry\": retry connecting at each interval\n  # connect_fail_behavior = \"error\"\n  #\n  ## Maximum time allowed for a request over the established connection.\n  # request_timeout = \"5s\"\n  #\n  # Maximum time that a session shall remain open without activity.\n  # session_timeout = \"20m\"\n  #\n  ## The interval at which the server should at least update its monitored items.\n  ## Please note that the OPC UA server might reject the specified interval if it cannot meet the required update rate.\n  ## Therefore, always refer to the hardware/software documentation of your server to ensure the specified interval is supported.\n  # subscription_interval = \"100ms\"\n  #\n  ## Security policy, one of \"None\", \"Basic128Rsa15\", \"Basic256\",\n  ## \"Basic256Sha256\", or \"auto\"\n  # security_policy = \"auto\"\n  #\n  ## Security mode, one of \"None\", \"Sign\", \"SignAndEncrypt\", or \"auto\"\n  # security_mode = \"auto\"\n  #\n  ## Path to cert.pem. Required when security mode or policy isn't \"None\".\n  ## If cert path is not supplied, self-signed cert and key will be generated.\n  # certificate = \"/etc/telegraf/cert.pem\"\n  #\n  ## Path to private key.pem. Required when security mode or policy isn't \"None\".\n  ## If key path is not supplied, self-signed cert and key will be generated.\n  # private_key = \"/etc/telegraf/key.pem\"\n\n  ## Path to additional, explicitly trusted certificate for the remote endpoint\n  # remote_certificate = \"/etc/telegraf/opcua_server_cert.pem\"\n\n  ## Authentication Method, one of \"Certificate\", \"UserName\", or \"Anonymous\".  To\n  ## authenticate using a specific ID, select 'Certificate' or 'UserName'\n  # auth_method = \"Anonymous\"\n  #\n  ## Username. Required for auth_method = \"UserName\"\n  # username = \"\"\n  #\n  ## Password. Required for auth_method = \"UserName\"\n  # password = \"\"\n  #\n  ## Option to select the metric timestamp to use. Valid options are:\n  ##     \"gather\" -- uses the time of receiving the data in telegraf\n  ##     \"server\" -- uses the timestamp provided by the server\n  ##     \"source\" -- uses the timestamp provided by the source\n  # timestamp = \"gather\"\n  #\n  ## The default timetsamp format is RFC3339Nano\n  # Other timestamp layouts can be configured using the Go language time\n  # layout specification from https://golang.org/pkg/time/#Time.Format\n  # e.g.: json_timestamp_format = \"2006-01-02T15:04:05Z07:00\"\n  #timestamp_format = \"\"\n  #\n  #\n  ## Client trace messages\n  ## When set to true, and debug mode enabled in the agent settings, the OPCUA\n  ## client's messages are included in telegraf logs. These messages are very\n  ## noisey, but essential for debugging issues.\n  # client_trace = false\n  #\n  ## Include additional Fields in each metric\n  ## Available options are:\n  ##   DataType -- OPC-UA Data Type (string)\n  # optional_fields = []\n  #\n  ## Node ID configuration\n  ## name              - field name to use in the output\n  ## id                - OPC UA node ID string (e.g., \"ns=0;i=2262\" or \"nsu=http://...;s=Name\")\n  ## namespace         - OPC UA namespace of the node (integer value 0 thru 3)\n  ## namespace_uri     - OPC UA namespace URI (alternative to namespace for stable references)\n  ## identifier_type   - OPC UA ID type (s=string, i=numeric, g=guid, b=opaque)\n  ## identifier        - OPC UA ID (tag as shown in opcua browser)\n  ## default_tags      - extra tags to be added to the output metric (optional)\n  ## monitoring_params - additional settings for the monitored node (optional)\n  ##\n  ## Use EITHER 'id' OR the combination of 'namespace/namespace_uri' + 'identifier_type' + 'identifier'\n  ##\n  ## Monitoring parameters\n  ## sampling_interval  - interval at which the server should check for data\n  ##                      changes (default: 0s)\n  ## queue_size         - size of the notification queue (default: 10)\n  ## discard_oldest     - how notifications should be handled in case of full\n  ##                      notification queues, possible values:\n  ##                      true: oldest value added to queue gets replaced with new\n  ##                            (default)\n  ##                      false: last value added to queue gets replaced with new\n  ## data_change_filter - defines the condition under which a notification should\n  ##                      be reported\n  ##\n  ## Data change filter\n  ## trigger        - specify the conditions under which a data change notification\n  ##                  should be reported, possible values:\n  ##                  \"Status\": only report notifications if the status changes\n  ##                            (default if parameter is omitted)\n  ##                  \"StatusValue\": report notifications if either status or value\n  ##                                 changes\n  ##                  \"StatusValueTimestamp\": report notifications if either status,\n  ##                                          value or timestamp changes\n  ## deadband_type  - type of the deadband filter to be applied, possible values:\n  ##                  \"None\": no deadband filter is applied\n  ##                  \"Absolute\": absolute change in a data value to report a notification\n  ##                  \"Percent\": works only with nodes that have an EURange property set\n  ##                             and is defined as: send notification if\n  ##                             (last value - current value) >\n  ##                             (deadband_value/100.0) * ((high–low) of EURange)\n  ## deadband_value - value to deadband_type, must be a float value, no filter is set\n  ##                  for negative values\n  ##\n  ## Use either the inline notation or the bracketed notation, not both.\n  #\n  ## Inline notation using id string (recommended for simplicity)\n  # nodes = [\n  #   {name=\"ProductUri\", id=\"ns=0;i=2262\"},\n  #   {name=\"ServerState\", id=\"ns=0;i=2259\"}\n  # ]\n  #\n  ## Inline notation using individual fields (default_tags and monitoring_params not supported yet)\n  # nodes = [\n  #   {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #   {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"}\n  # ]\n  #\n  ## Bracketed notation using id string\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"ProductUri\"\n  #   id = \"ns=0;i=2262\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n\n  ## Bracketed notation using individual fields\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"value1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  #   [inputs.opcua_listener.nodes.monitoring_params]\n  #     sampling_interval = \"0s\"\n  #     queue_size = 10\n  #     discard_oldest = true\n  #\n  #     [inputs.opcua_listener.nodes.monitoring_params.data_change_filter]\n  #       trigger = \"Status\"\n  #       deadband_type = \"Absolute\"\n  #       deadband_value = 0.0\n  #\n  # [[inputs.opcua_listener.nodes]]\n  #   name = \"node3\"\n  #   namespace_uri = \"http://opcfoundation.org/UA/\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  ## Node Group\n  ## Sets defaults so they aren't required in every node.\n  ## Default values can be set for:\n  ## * Metric name\n  ## * OPC UA namespace\n  ## * Identifier\n  ## * Default tags\n  ## * Sampling interval\n  ##\n  ## Multiple node groups are allowed\n  #[[inputs.opcua_listener.group]]\n  ## Group Metric name. Overrides the top level name.  If unset, the\n  ## top level name is used.\n  # name =\n  #\n  ## Group default namespace. If a node in the group doesn't set its\n  ## namespace, this is used.\n  # namespace =\n  #\n  ## Group default namespace URI. Alternative to namespace for stable references.\n  ## If a node in the group doesn't set its namespace_uri, this is used.\n  # namespace_uri =\n  #\n  ## Group default identifier type. If a node in the group doesn't set its\n  ## identifier_type, this is used.\n  # identifier_type =\n  #\n  ## Default tags that are applied to every node in this group. Can be\n  ## overwritten in a node by setting a different value for the tag name.\n  ##   example: default_tags = { tag1 = \"value1\" }\n  # default_tags = {}\n  #\n  ## Group default sampling interval. If a node in the group doesn't set its\n  ## sampling interval, this is used.\n  # sampling_interval = \"0s\"\n  #\n  ## Node ID Configuration.  Array of nodes with the same settings as above.\n  ## Use either the inline notation or the bracketed notation, not both.\n  #\n  ## Inline notation (default_tags and monitoring_params not supported yet)\n  # nodes = [\n  #  {name=\"node1\", namespace=\"\", identifier_type=\"\", identifier=\"\"},\n  #  {name=\"node2\", namespace=\"\", identifier_type=\"\", identifier=\"\"}\n  #]\n  #\n  ## Bracketed notation\n  # [[inputs.opcua_listener.group.nodes]]\n  #   name = \"node1\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #   default_tags = { tag1 = \"override1\", tag2 = \"value2\" }\n  #\n  # [[inputs.opcua_listener.group.nodes]]\n  #   name = \"node2\"\n  #   namespace = \"\"\n  #   identifier_type = \"\"\n  #   identifier = \"\"\n  #\n  #   [inputs.opcua_listener.group.nodes.monitoring_params]\n  #     sampling_interval = \"0s\"\n  #     queue_size = 10\n  #     discard_oldest = true\n  #\n  #     [inputs.opcua_listener.group.nodes.monitoring_params.data_change_filter]\n  #       trigger = \"Status\"\n  #       deadband_type = \"Absolute\"\n  #       deadband_value = 0.0\n  #\n\n  ## Multiple event groups are allowed.\n  ## Event nodes support both 'id' string format and individual fields.\n  # [[inputs.opcua_listener.events]]\n  #   ## Polling interval for data collection\n  #   # sampling_interval = \"10s\"\n  #   ## Size of the notification queue\n  #   # queue_size = 10\n  #   ## Node parameter defaults for node definitions below (used when id is not specified)\n  #   # namespace = \"\"\n  #   # identifier_type = \"\"\n  #   ## Specifies OPCUA Event sources to filter on\n  #   # source_names = [\"SourceName1\", \"SourceName2\"]\n  #   ## Fields to capture from event notifications\n  #   fields = [\"Severity\", \"Message\", \"Time\"]\n  #\n  #   ## Type or level of events to capture from the monitored nodes.\n  #   ## Use 'id' string OR individual fields (namespace/identifier_type/identifier)\n  #   [inputs.opcua_listener.events.event_type_node]\n  #     id = \"ns=0;i=2041\"\n  #     # Or use individual fields:\n  #     # namespace = \"\"\n  #     # identifier_type = \"\"\n  #     # identifier = \"\"\n  #\n  #   ## Nodes to monitor for event notifications associated with the defined\n  #   ## event type. Use 'id' string OR individual fields.\n  #   [[inputs.opcua_listener.events.node_ids]]\n  #     id = \"ns=2;s=EventSource1\"\n  #     # Or use individual fields:\n  #     # namespace = \"\"\n  #     # identifier_type = \"\"\n  #     # identifier = \"\"\n\n  ## Enable workarounds required by some devices to work correctly\n  # [inputs.opcua_listener.workarounds]\n  #  ## Set additional valid status codes, StatusOK (0x0) is always considered valid\n  #  # additional_valid_status_codes = [\"0xC0\"]\n  #  ## Use unregistered reads instead of registered reads\n  #  # use_unregistered_reads = false\n"
  },
  {
    "path": "plugins/inputs/opcua_listener/subscribe_client.go",
    "content": "package opcua_listener\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gopcua/opcua\"\n\t\"github.com/gopcua/opcua/ua\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\topcuaclient \"github.com/influxdata/telegraf/plugins/common/opcua\"\n\t\"github.com/influxdata/telegraf/plugins/common/opcua/input\"\n)\n\ntype subscribeClientConfig struct {\n\tinput.InputClientConfig\n\tSubscriptionInterval config.Duration `toml:\"subscription_interval\"`\n\tConnectFailBehavior  string          `toml:\"connect_fail_behavior\"`\n}\n\ntype subscribeClient struct {\n\t*input.OpcUAInputClient\n\tConfig subscribeClientConfig\n\n\tsub                *opcua.Subscription\n\tmonitoredItemsReqs []*ua.MonitoredItemCreateRequest\n\teventItemsReqs     []*ua.MonitoredItemCreateRequest\n\tdataNotifications  chan *opcua.PublishNotificationData\n\tmetrics            chan telegraf.Metric\n\n\tctx    context.Context\n\tcancel context.CancelFunc\n}\n\nfunc checkDataChangeFilterParameters(params *input.DataChangeFilter) error {\n\tswitch {\n\tcase params.Trigger != input.Status &&\n\t\tparams.Trigger != input.StatusValue &&\n\t\tparams.Trigger != input.StatusValueTimestamp:\n\t\treturn fmt.Errorf(\"trigger '%s' not supported\", params.Trigger)\n\tcase params.DeadbandType != input.None &&\n\t\tparams.DeadbandType != input.Absolute &&\n\t\tparams.DeadbandType != input.Percent:\n\t\treturn fmt.Errorf(\"deadband_type '%s' not supported\", params.DeadbandType)\n\tcase params.DeadbandType != input.None && params.DeadbandValue == nil:\n\t\treturn errors.New(\"deadband_value was not set\")\n\tcase params.DeadbandValue != nil && *params.DeadbandValue < 0:\n\t\treturn errors.New(\"negative deadband_value not supported\")\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc assignConfigValuesToRequest(req *ua.MonitoredItemCreateRequest, monParams *input.MonitoringParameters) error {\n\treq.RequestedParameters.SamplingInterval = float64(time.Duration(monParams.SamplingInterval) / time.Millisecond)\n\n\tif monParams.QueueSize != nil {\n\t\treq.RequestedParameters.QueueSize = *monParams.QueueSize\n\t}\n\n\tif monParams.DiscardOldest != nil {\n\t\treq.RequestedParameters.DiscardOldest = *monParams.DiscardOldest\n\t}\n\n\tif monParams.DataChangeFilter != nil {\n\t\tif err := checkDataChangeFilterParameters(monParams.DataChangeFilter); err != nil {\n\t\t\treturn fmt.Errorf(err.Error()+\", node '%s'\", req.ItemToMonitor.NodeID)\n\t\t}\n\n\t\tvar deadbandValue float64\n\n\t\tif monParams.DataChangeFilter.DeadbandValue != nil {\n\t\t\tdeadbandValue = *monParams.DataChangeFilter.DeadbandValue\n\t\t}\n\n\t\treq.RequestedParameters.Filter = ua.NewExtensionObject(\n\t\t\t&ua.DataChangeFilter{\n\t\t\t\tTrigger:       ua.DataChangeTriggerFromString(string(monParams.DataChangeFilter.Trigger)),\n\t\t\t\tDeadbandType:  uint32(ua.DeadbandTypeFromString(string(monParams.DataChangeFilter.DeadbandType))),\n\t\t\t\tDeadbandValue: deadbandValue,\n\t\t\t},\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (sc *subscribeClientConfig) createSubscribeClient(log telegraf.Logger) (*subscribeClient, error) {\n\tclient, err := sc.InputClientConfig.CreateInputClient(log)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Initialize node IDs (namespace URI resolution will happen during connect if needed)\n\tif err := client.InitNodeIDs(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := client.InitEventNodeIDs(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprocessingCtx, processingCancel := context.WithCancel(context.Background())\n\n\tsubClient := &subscribeClient{\n\t\tOpcUAInputClient:   client,\n\t\tConfig:             *sc,\n\t\tmonitoredItemsReqs: make([]*ua.MonitoredItemCreateRequest, len(client.NodeIDs)),\n\t\teventItemsReqs:     make([]*ua.MonitoredItemCreateRequest, len(client.EventNodeMetricMapping)),\n\t\t// 100 was chosen to make sure that the channels will not block when multiple changes come in at the same time.\n\t\t// The channel size should be increased if reports come in on Telegraf blocking when many changes come in at\n\t\t// the same time. It could be made dependent on the number of nodes subscribed to and the subscription interval.\n\t\tdataNotifications: make(chan *opcua.PublishNotificationData, 100),\n\t\tmetrics:           make(chan telegraf.Metric, 100),\n\t\tctx:               processingCtx,\n\t\tcancel:            processingCancel,\n\t}\n\n\tlog.Debugf(\"Creating monitored items\")\n\tfor i, nodeID := range client.NodeIDs {\n\t\t// The node id index (i) is used as the handle for the monitored item\n\t\treq := opcua.NewMonitoredItemCreateRequestWithDefaults(nodeID, ua.AttributeIDValue, uint32(i))\n\t\tif err := assignConfigValuesToRequest(req, &client.NodeMetricMapping[i].Tag.MonitoringParams); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubClient.monitoredItemsReqs[i] = req\n\t}\n\n\tlog.Debugf(\"Creating event streaming items\")\n\tfor i, node := range client.EventNodeMetricMapping {\n\t\treq := opcua.NewMonitoredItemCreateRequestWithDefaults(node.NodeID, ua.AttributeIDEventNotifier, uint32(i))\n\t\tif node.SamplingInterval != nil {\n\t\t\treq.RequestedParameters.SamplingInterval = float64(time.Duration(*node.SamplingInterval) / time.Millisecond)\n\t\t}\n\t\tif node.QueueSize != nil {\n\t\t\treq.RequestedParameters.QueueSize = *node.QueueSize\n\t\t}\n\n\t\tfilterExtObj, err := node.CreateEventFilter()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create event filter: %w\", err)\n\t\t}\n\t\treq.RequestedParameters.Filter = filterExtObj\n\t\tsubClient.eventItemsReqs[i] = req\n\t}\n\treturn subClient, nil\n}\n\nfunc (o *subscribeClient) connect() error {\n\terr := o.OpcUAClient.Connect(o.ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Fetch namespace array for namespace URI support\n\t// This is needed if any nodes use nsu= format instead of ns= format\n\tif err := o.OpcUAClient.UpdateNamespaceArray(o.ctx); err != nil {\n\t\to.Log.Warnf(\"Failed to fetch namespace array: %v\", err)\n\t\t// Continue anyway - this is only needed if using namespace URIs\n\t}\n\n\to.Log.Debugf(\"Creating OPC UA subscription\")\n\to.sub, err = o.Client.Subscribe(o.ctx, &opcua.SubscriptionParameters{\n\t\tInterval: time.Duration(o.Config.SubscriptionInterval),\n\t}, o.dataNotifications)\n\tif err != nil {\n\t\to.Log.Error(\"Failed to create subscription\")\n\t\treturn err\n\t}\n\n\to.Log.Debugf(\"Subscribed with subscription ID %d\", o.sub.SubscriptionID)\n\treturn nil\n}\n\nfunc (o *subscribeClient) stop(ctx context.Context) <-chan struct{} {\n\to.Log.Debugf(\"Stopping OPC subscription...\")\n\tif o.State() != opcuaclient.Connected {\n\t\treturn nil\n\t}\n\tif o.sub != nil {\n\t\tif err := o.sub.Cancel(ctx); err != nil {\n\t\t\to.Log.Warn(\"Cancelling OPC UA subscription failed with error \", err)\n\t\t}\n\t}\n\tclosing := o.OpcUAInputClient.Stop(ctx)\n\to.cancel()\n\treturn closing\n}\n\nfunc (o *subscribeClient) startMonitoring(ctx context.Context) (<-chan telegraf.Metric, error) {\n\terr := o.connect()\n\tif err != nil {\n\t\tswitch o.Config.ConnectFailBehavior {\n\t\tcase \"retry\":\n\t\t\to.Log.Warnf(\"Failed to connect to OPC UA server %s. Will attempt to connect again at the next interval: %s\", o.Config.Endpoint, err)\n\t\t\treturn nil, nil\n\t\tcase \"ignore\":\n\t\t\to.Log.Errorf(\"Failed to connect to OPC UA server %s. Will not retry: %s\", o.Config.Endpoint, err)\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tif len(o.monitoredItemsReqs) != 0 {\n\t\tresp, err := o.sub.Monitor(ctx, ua.TimestampsToReturnBoth, o.monitoredItemsReqs...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to start monitoring items: %w\", err)\n\t\t}\n\t\to.Log.Debug(\"Monitoring items\")\n\n\t\tfor idx, res := range resp.Results {\n\t\t\tif !o.StatusCodeOK(res.StatusCode) {\n\t\t\t\t// Verify NodeIDs array has been built before trying to get item; otherwise show '?' for node id\n\t\t\t\tif len(o.OpcUAInputClient.NodeIDs) > idx {\n\t\t\t\t\to.Log.Debugf(\"Failed to create monitored item for node %v (%v)\",\n\t\t\t\t\t\to.OpcUAInputClient.NodeMetricMapping[idx].Tag.FieldName, o.OpcUAInputClient.NodeIDs[idx].String())\n\t\t\t\t} else {\n\t\t\t\t\to.Log.Debugf(\"Failed to create monitored item for node %v (%v)\", o.OpcUAInputClient.NodeMetricMapping[idx].Tag.FieldName, '?')\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"creating monitored item failed with status code: %w\", res.StatusCode)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(o.eventItemsReqs) != 0 {\n\t\tresp, err := o.sub.Monitor(ctx, ua.TimestampsToReturnBoth, o.eventItemsReqs...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to start monitoring event stream: %w\", err)\n\t\t}\n\t\to.Log.Debug(\"Monitoring events\")\n\n\t\tfor _, res := range resp.Results {\n\t\t\tif !o.StatusCodeOK(res.StatusCode) {\n\t\t\t\treturn nil, fmt.Errorf(\"creating monitored event streaming item failed with status code: %w\", res.StatusCode)\n\t\t\t}\n\t\t}\n\t}\n\n\tgo o.processReceivedNotifications()\n\n\treturn o.metrics, nil\n}\n\nfunc (o *subscribeClient) processReceivedNotifications() {\n\tfor {\n\t\tselect {\n\t\tcase <-o.ctx.Done():\n\t\t\to.Log.Debug(\"Processing received notifications stopped\")\n\t\t\treturn\n\n\t\tcase res, ok := <-o.dataNotifications:\n\t\t\tif !ok {\n\t\t\t\to.Log.Debugf(\"Data notification channel closed. Processing of received notifications stopped\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif res.Error != nil {\n\t\t\t\to.Log.Error(res.Error)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif res.Value == nil {\n\t\t\t\to.Log.Error(\"Received nil notification\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch notif := res.Value.(type) {\n\t\t\tcase *ua.DataChangeNotification:\n\t\t\t\to.Log.Debugf(\"Received data change notification with %d items\", len(notif.MonitoredItems))\n\t\t\t\t// It is assumed the notifications are ordered chronologically\n\t\t\t\tfor _, monitoredItemNotif := range notif.MonitoredItems {\n\t\t\t\t\ti := int(monitoredItemNotif.ClientHandle)\n\t\t\t\t\toldValue := o.LastReceivedData[i].Value\n\t\t\t\t\to.UpdateNodeValue(i, monitoredItemNotif.Value)\n\t\t\t\t\to.Log.Debugf(\"Data change notification: node %q value changed from %v to %v\",\n\t\t\t\t\t\to.NodeIDs[i].String(), oldValue, o.LastReceivedData[i].Value)\n\t\t\t\t\to.metrics <- o.MetricForNode(i)\n\t\t\t\t}\n\t\t\tcase *ua.EventNotificationList:\n\t\t\t\to.Log.Debugf(\"Processing event notification with %d events\", len(notif.Events))\n\t\t\t\t// It is assumed the events are ordered chronologically\n\t\t\t\tfor _, event := range notif.Events {\n\t\t\t\t\ti := int(event.ClientHandle)\n\t\t\t\t\tif m := o.MetricForEvent(i, event); m != nil {\n\t\t\t\t\t\to.metrics <- m\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\to.Log.Warnf(\"Received notification has unexpected type %s\", reflect.TypeOf(res.Value))\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/openldap/README.md",
    "content": "# OpenLDAP Input Plugin\n\nThis plugin gathers metrics from [OpenLDAP][openldap]'s `cn=Monitor` backend.\nTo use this plugin you must enable the [slapd monitoring][slapd_docs] backend.\n\n> [!NOTE]\n> It is recommended to use the newer [`ldap` input plugin][ldap_plugin] instead.\n\n⭐ Telegraf v1.4.0\n🏷️ server, network\n💻 all\n\n[openldap]: https://www.openldap.org/\n[slapd_docs]: https://www.openldap.org/devel/admin/monitoringslapd.html\n[ldap_plugin]: /plugins/inputs/ldap/README.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# OpenLDAP cn=Monitor plugin\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 389\n\n  # ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.\n  # note that port will likely need to be changed to 636 for ldaps\n  # valid options: \"\" | \"starttls\" | \"ldaps\"\n  tls = \"\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Path to PEM-encoded Root certificate to use to verify server certificate\n  tls_ca = \"/etc/ssl/certs.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  # reverse metric names so they sort more naturally\n  # Defaults to false if unset, but is set to true when generating a new config\n  reverse_metric_names = true\n```\n\n## Metrics\n\nAll `monitorCounter`, `monitoredInfo`, `monitorOpInitiated`, and\n`monitorOpCompleted` attributes are gathered based on this LDAP query:\n\n```text\n(|(objectClass=monitorCounterObject)(objectClass=monitorOperation)(objectClass=monitoredObject))\n```\n\nMetric names are based on their entry DN with the cn=Monitor base removed. If\n`reverse_metric_names` is not set, metrics are based on their DN. If\n`reverse_metric_names` is set to `true`, the names are reversed. This is\nrecommended as it allows the names to sort more naturally.\n\nMetrics for the `monitorOp*` attributes have `_initiated` and `_completed` added\nto the base name as appropriate.\n\nAn OpenLDAP 2.4 server will provide these metrics:\n\n- openldap\n  - tags:\n    - server\n    - port\n  - fields:\n    - connections_current\n    - connections_max_file_descriptors\n    - connections_total\n    - operations_abandon_completed\n    - operations_abandon_initiated\n    - operations_add_completed\n    - operations_add_initiated\n    - operations_bind_completed\n    - operations_bind_initiated\n    - operations_compare_completed\n    - operations_compare_initiated\n    - operations_delete_completed\n    - operations_delete_initiated\n    - operations_extended_completed\n    - operations_extended_initiated\n    - operations_modify_completed\n    - operations_modify_initiated\n    - operations_modrdn_completed\n    - operations_modrdn_initiated\n    - operations_search_completed\n    - operations_search_initiated\n    - operations_unbind_completed\n    - operations_unbind_initiated\n    - statistics_bytes\n    - statistics_entries\n    - statistics_pdu\n    - statistics_referrals\n    - threads_active\n    - threads_backload\n    - threads_max\n    - threads_max_pending\n    - threads_open\n    - threads_pending\n    - threads_starting\n    - time_uptime\n    - waiters_read\n    - waiters_write\n\n## Example Output\n\n```text\nopenldap,server=localhost,port=389,host=niska.ait.psu.edu operations_bind_initiated=10i,operations_unbind_initiated=6i,operations_modrdn_completed=0i,operations_delete_initiated=0i,operations_add_completed=2i,operations_delete_completed=0i,operations_abandon_completed=0i,statistics_entries=1516i,threads_open=2i,threads_active=1i,waiters_read=1i,operations_modify_completed=0i,operations_extended_initiated=4i,threads_pending=0i,operations_search_initiated=36i,operations_compare_initiated=0i,connections_max_file_descriptors=4096i,operations_modify_initiated=0i,operations_modrdn_initiated=0i,threads_max=16i,time_uptime=6017i,connections_total=1037i,connections_current=1i,operations_add_initiated=2i,statistics_bytes=162071i,operations_unbind_completed=6i,operations_abandon_initiated=0i,statistics_pdu=1566i,threads_max_pending=0i,threads_backload=1i,waiters_write=0i,operations_bind_completed=10i,operations_search_completed=35i,operations_compare_completed=0i,operations_extended_completed=4i,statistics_referrals=0i,threads_starting=0i 1516912070000000000\n```\n"
  },
  {
    "path": "plugins/inputs/openldap/openldap.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage openldap\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/go-ldap/ldap/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tsearchBase    = \"cn=Monitor\"\n\tsearchFilter  = \"(|(objectClass=monitorCounterObject)(objectClass=monitorOperation)(objectClass=monitoredObject))\"\n\tsearchAttrs   = []string{\"monitorCounter\", \"monitorOpInitiated\", \"monitorOpCompleted\", \"monitoredInfo\"}\n\tattrTranslate = map[string]string{\n\t\t\"monitorCounter\":     \"\",\n\t\t\"monitoredInfo\":      \"\",\n\t\t\"monitorOpInitiated\": \"_initiated\",\n\t\t\"monitorOpCompleted\": \"_completed\",\n\t\t\"olmMDBPagesMax\":     \"_mdb_pages_max\",\n\t\t\"olmMDBPagesUsed\":    \"_mdb_pages_used\",\n\t\t\"olmMDBPagesFree\":    \"_mdb_pages_free\",\n\t\t\"olmMDBReadersMax\":   \"_mdb_readers_max\",\n\t\t\"olmMDBReadersUsed\":  \"_mdb_readers_used\",\n\t\t\"olmMDBEntries\":      \"_mdb_entries\",\n\t}\n)\n\ntype Openldap struct {\n\tHost               string `toml:\"host\"`\n\tPort               int    `toml:\"port\"`\n\tTLS                string `toml:\"tls\"`\n\tInsecureSkipVerify bool   `toml:\"insecure_skip_verify\"`\n\tTLSCA              string `toml:\"tls_ca\"`\n\tBindDn             string `toml:\"bind_dn\"`\n\tBindPassword       string `toml:\"bind_password\"`\n\tReverseMetricNames bool   `toml:\"reverse_metric_names\"`\n}\n\nfunc (*Openldap) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *Openldap) Gather(acc telegraf.Accumulator) error {\n\tvar err error\n\tvar l *ldap.Conn\n\tif o.TLS != \"\" {\n\t\t// build tls config\n\t\tclientTLSConfig := tls.ClientConfig{\n\t\t\tTLSCA:              o.TLSCA,\n\t\t\tInsecureSkipVerify: o.InsecureSkipVerify,\n\t\t}\n\t\ttlsConfig, err := clientTLSConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\treturn nil\n\t\t}\n\n\t\tswitch o.TLS {\n\t\tcase \"ldaps\":\n\t\t\tl, err = ldap.DialURL(fmt.Sprintf(\"ldaps://%s:%d\", o.Host, o.Port), ldap.DialWithTLSConfig(tlsConfig))\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase \"starttls\":\n\t\t\tl, err = ldap.DialURL(fmt.Sprintf(\"ldap://%s:%d\", o.Host, o.Port))\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\terr = l.StartTLS(tlsConfig)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\tdefault:\n\t\t\tacc.AddError(fmt.Errorf(\"invalid setting for tls: %s\", o.TLS))\n\t\t\treturn nil\n\t\t}\n\t} else {\n\t\tl, err = ldap.DialURL(fmt.Sprintf(\"ldap://%s:%d\", o.Host, o.Port))\n\t}\n\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn nil\n\t}\n\tdefer l.Close()\n\n\t// username/password bind\n\tif o.BindDn != \"\" && o.BindPassword != \"\" {\n\t\terr = l.Bind(o.BindDn, o.BindPassword)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tsearchRequest := ldap.NewSearchRequest(\n\t\tsearchBase,\n\t\tldap.ScopeWholeSubtree,\n\t\tldap.NeverDerefAliases,\n\t\t0,\n\t\t0,\n\t\tfalse,\n\t\tsearchFilter,\n\t\tsearchAttrs,\n\t\tnil,\n\t)\n\n\tsr, err := l.Search(searchRequest)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn nil\n\t}\n\n\tgatherSearchResult(sr, o, acc)\n\n\treturn nil\n}\n\nfunc gatherSearchResult(sr *ldap.SearchResult, o *Openldap, acc telegraf.Accumulator) {\n\tfields := make(map[string]interface{})\n\ttags := map[string]string{\n\t\t\"server\": o.Host,\n\t\t\"port\":   strconv.Itoa(o.Port),\n\t}\n\tfor _, entry := range sr.Entries {\n\t\tmetricName := dnToMetric(entry.DN, o)\n\t\tfor _, attr := range entry.Attributes {\n\t\t\tif len(attr.Values[0]) >= 1 {\n\t\t\t\tif v, err := strconv.ParseInt(attr.Values[0], 10, 64); err == nil {\n\t\t\t\t\tfields[metricName+attrTranslate[attr.Name]] = v\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"openldap\", fields, tags)\n}\n\n// Convert a DN to metric name, eg cn=Read,cn=Waiters,cn=Monitor becomes waiters_read\n// Assumes the last part of the DN is cn=Monitor and we want to drop it\nfunc dnToMetric(dn string, o *Openldap) string {\n\tif o.ReverseMetricNames {\n\t\tvar metricParts []string\n\n\t\tdn = strings.Trim(dn, \" \")\n\t\tdn = strings.ReplaceAll(dn, \" \", \"_\")\n\t\tdn = strings.ReplaceAll(dn, \"cn=\", \"\")\n\t\tdn = strings.ToLower(dn)\n\t\tmetricParts = strings.Split(dn, \",\")\n\t\tfor i, j := 0, len(metricParts)-1; i < j; i, j = i+1, j-1 {\n\t\t\tmetricParts[i], metricParts[j] = metricParts[j], metricParts[i]\n\t\t}\n\t\treturn strings.Join(metricParts[1:], \"_\")\n\t}\n\n\tmetricName := strings.Trim(dn, \" \")\n\tmetricName = strings.ReplaceAll(metricName, \" \", \"_\")\n\tmetricName = strings.ToLower(metricName)\n\tmetricName = strings.TrimPrefix(metricName, \"cn=\")\n\tmetricName = strings.ReplaceAll(metricName, strings.ToLower(\"cn=Monitor\"), \"\")\n\tmetricName = strings.ReplaceAll(metricName, \"cn=\", \"_\")\n\treturn strings.ReplaceAll(metricName, \",\", \"\")\n}\n\nfunc newOpenldap() *Openldap {\n\treturn &Openldap{\n\t\tHost:               \"localhost\",\n\t\tPort:               389,\n\t\tTLS:                \"\",\n\t\tInsecureSkipVerify: false,\n\t\tTLSCA:              \"\",\n\t\tBindDn:             \"\",\n\t\tBindPassword:       \"\",\n\t\tReverseMetricNames: false,\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"openldap\", func() telegraf.Input { return newOpenldap() })\n}\n"
  },
  {
    "path": "plugins/inputs/openldap/openldap_test.go",
    "content": "package openldap\n\nimport (\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/go-ldap/ldap/v3\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tservicePort       = \"1389\"\n\tservicePortSecure = \"1636\"\n)\n\nfunc TestOpenldapMockResult(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tmockSearchResult := ldap.SearchResult{\n\t\tEntries: []*ldap.Entry{\n\t\t\t{\n\t\t\t\tDN:         \"cn=Total,cn=Connections,cn=Monitor\",\n\t\t\t\tAttributes: []*ldap.EntryAttribute{{Name: \"monitorCounter\", Values: []string{\"1\"}}},\n\t\t\t},\n\t\t},\n\t}\n\n\to := &Openldap{\n\t\tHost: \"localhost\",\n\t\tPort: 389,\n\t}\n\n\tgatherSearchResult(&mockSearchResult, o, &acc)\n\tcommonTests(t, o, &acc)\n}\n\nfunc TestOpenldapNoConnectionIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\to := &Openldap{\n\t\tHost: \"nosuchhost\",\n\t\tPort: 389,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr := o.Gather(&acc)\n\trequire.NoError(t, err)         // test that we didn't return an error\n\trequire.Zero(t, acc.NFields())  // test that we didn't return any fields\n\trequire.NotEmpty(t, acc.Errors) // test that we set an error\n}\n\nfunc TestOpenldapGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:         container.Address,\n\t\tPort:         port,\n\t\tBindDn:       \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword: \"secret\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)\n\tcommonTests(t, o, &acc)\n}\n\nfunc TestOpenldapStartTLSIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tpki := testutil.NewPKI(\"../../../testutil/pki\")\n\n\ttlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath())\n\trequire.NoError(t, err)\n\ttlsCert, err := filepath.Abs(pki.ServerCertPath())\n\trequire.NoError(t, err)\n\ttlsKey, err := filepath.Abs(pki.ServerKeyPath())\n\trequire.NoError(t, err)\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t\t\"LDAP_ENABLE_TLS\":     \"yes\",\n\t\t\t\"LDAP_TLS_CA_FILE\":    \"server.pem\",\n\t\t\t\"LDAP_TLS_CERT_FILE\":  \"server.crt\",\n\t\t\t\"LDAP_TLS_KEY_FILE\":   \"server.key\",\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/server.pem\": tlsPem,\n\t\t\t\"/server.crt\": tlsCert,\n\t\t\t\"/server.key\": tlsKey,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\tcert, err := filepath.Abs(pki.ClientCertPath())\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:               container.Address,\n\t\tPort:               port,\n\t\tTLS:                \"starttls\",\n\t\tInsecureSkipVerify: true,\n\t\tBindDn:             \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword:       \"secret\",\n\t\tTLSCA:              cert,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)\n\tcommonTests(t, o, &acc)\n}\n\nfunc TestOpenldapLDAPSIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tpki := testutil.NewPKI(\"../../../testutil/pki\")\n\n\ttlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath())\n\trequire.NoError(t, err)\n\ttlsCert, err := filepath.Abs(pki.ServerCertPath())\n\trequire.NoError(t, err)\n\ttlsKey, err := filepath.Abs(pki.ServerKeyPath())\n\trequire.NoError(t, err)\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortSecure},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t\t\"LDAP_ENABLE_TLS\":     \"yes\",\n\t\t\t\"LDAP_TLS_CA_FILE\":    \"server.pem\",\n\t\t\t\"LDAP_TLS_CERT_FILE\":  \"server.crt\",\n\t\t\t\"LDAP_TLS_KEY_FILE\":   \"server.key\",\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/server.pem\": tlsPem,\n\t\t\t\"/server.crt\": tlsCert,\n\t\t\t\"/server.key\": tlsKey,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortSecure)),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePortSecure])\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:               container.Address,\n\t\tPort:               port,\n\t\tTLS:                \"ldaps\",\n\t\tInsecureSkipVerify: true,\n\t\tBindDn:             \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword:       \"secret\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)\n\tcommonTests(t, o, &acc)\n}\n\nfunc TestOpenldapInvalidTLSIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tpki := testutil.NewPKI(\"../../../testutil/pki\")\n\ttlsPem, err := filepath.Abs(pki.ServerCertAndKeyPath())\n\trequire.NoError(t, err)\n\ttlsCert, err := filepath.Abs(pki.ServerCertPath())\n\trequire.NoError(t, err)\n\ttlsKey, err := filepath.Abs(pki.ServerKeyPath())\n\trequire.NoError(t, err)\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePortSecure},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t\t\"LDAP_ENABLE_TLS\":     \"yes\",\n\t\t\t\"LDAP_TLS_CA_FILE\":    \"server.pem\",\n\t\t\t\"LDAP_TLS_CERT_FILE\":  \"server.crt\",\n\t\t\t\"LDAP_TLS_KEY_FILE\":   \"server.key\",\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/server.pem\": tlsPem,\n\t\t\t\"/server.crt\": tlsCert,\n\t\t\t\"/server.key\": tlsKey,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePortSecure)),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePortSecure])\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:               container.Address,\n\t\tPort:               port,\n\t\tTLS:                \"invalid\",\n\t\tInsecureSkipVerify: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)         // test that we didn't return an error\n\trequire.Zero(t, acc.NFields())  // test that we didn't return any fields\n\trequire.NotEmpty(t, acc.Errors) // test that we set an error\n}\n\nfunc TestOpenldapBindIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:               container.Address,\n\t\tPort:               port,\n\t\tTLS:                \"\",\n\t\tInsecureSkipVerify: true,\n\t\tBindDn:             \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword:       \"secret\",\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)\n\tcommonTests(t, o, &acc)\n}\n\nfunc commonTests(t *testing.T, o *Openldap, acc *testutil.Accumulator) {\n\t// helpful local commands to run:\n\t// ldapwhoami -D \"CN=manager,DC=example,DC=org\" -H ldap://localhost:1389 -w secret\n\t// ldapsearch -D \"CN=manager,DC=example,DC=org\" -H \"ldap://localhost:1389\" -b cn=Monitor -w secret\n\trequire.Empty(t, acc.Errors, \"accumulator had no errors\")\n\trequire.True(t, acc.HasMeasurement(\"openldap\"), \"Has a measurement called 'openldap'\")\n\trequire.Equal(t, o.Host, acc.TagValue(\"openldap\", \"server\"), \"Has a tag value of server=o.Host\")\n\trequire.Equal(t, strconv.Itoa(o.Port), acc.TagValue(\"openldap\", \"port\"), \"Has a tag value of port=o.Port\")\n\trequire.True(t, acc.HasInt64Field(\"openldap\", \"total_connections\"), \"Has an integer field called total_connections\")\n}\n\nfunc TestOpenldapReverseMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"bitnamilegacy/openldap\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"LDAP_ADMIN_USERNAME\": \"manager\",\n\t\t\t\"LDAP_ADMIN_PASSWORD\": \"secret\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"slapd starting\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport, err := strconv.Atoi(container.Ports[servicePort])\n\trequire.NoError(t, err)\n\n\to := &Openldap{\n\t\tHost:               container.Address,\n\t\tPort:               port,\n\t\tTLS:                \"\",\n\t\tInsecureSkipVerify: true,\n\t\tBindDn:             \"CN=manager,DC=example,DC=org\",\n\t\tBindPassword:       \"secret\",\n\t\tReverseMetricNames: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = o.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasInt64Field(\"openldap\", \"connections_total\"), \"Has an integer field called connections_total\")\n}\n"
  },
  {
    "path": "plugins/inputs/openldap/sample.conf",
    "content": "# OpenLDAP cn=Monitor plugin\n[[inputs.openldap]]\n  host = \"localhost\"\n  port = 389\n\n  # ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.\n  # note that port will likely need to be changed to 636 for ldaps\n  # valid options: \"\" | \"starttls\" | \"ldaps\"\n  tls = \"\"\n\n  # skip peer certificate verification. Default is false.\n  insecure_skip_verify = false\n\n  # Path to PEM-encoded Root certificate to use to verify server certificate\n  tls_ca = \"/etc/ssl/certs.pem\"\n\n  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.\n  bind_dn = \"\"\n  bind_password = \"\"\n\n  # reverse metric names so they sort more naturally\n  # Defaults to false if unset, but is set to true when generating a new config\n  reverse_metric_names = true\n"
  },
  {
    "path": "plugins/inputs/openntpd/README.md",
    "content": "# OpenNTPD Input Plugin\n\nThis plugin gathers metrics from [OpenNTPD][openntpd] using the `ntpctl`\ncommand.\n\n> [!NOTE]\n> The `ntpctl` binary must be present on the system and executable by Telegraf.\n> The plugin supports using `sudo` for execution.\n\n⭐ Telegraf v1.12.0\n🏷️ server, network\n💻 all\n\n[openntpd]: http://www.openntpd.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get standard NTP query metrics from OpenNTPD.\n[[inputs.openntpd]]\n  ## Run ntpctl binary with sudo.\n  # use_sudo = false\n\n  ## Location of the ntpctl binary.\n  # binary = \"/usr/sbin/ntpctl\"\n\n  ## Maximum time the ntpctl binary is allowed to run.\n  # timeout = \"5s\"\n```\n\n### Permissions\n\nIt's important to note that this plugin references `ntpctl`, which may require\nadditional permissions to execute successfully. Depending on the user/group\npermissions of the telegraf user executing this plugin, you may need to alter\nthe group membership, set facls, or use sudo.\n\n#### Group membership (recommended)\n\n```bash\n$ groups telegraf\ntelegraf : telegraf\n\n$ usermod -a -G ntpd telegraf\n\n$ groups telegraf\ntelegraf : telegraf ntpd\n```\n\n#### Sudo privileges\n\nIf you use this method, you will need the following in your telegraf config:\n\n```toml\n[[inputs.openntpd]]\n  use_sudo = true\n```\n\nYou will also need to update your sudoers file:\n\n```bash\n$ visudo\n# Add the following lines:\nCmnd_Alias NTPCTL = /usr/sbin/ntpctl\ntelegraf ALL=(ALL) NOPASSWD: NTPCTL\nDefaults!NTPCTL !logfile, !syslog, !pam_session\n```\n\nPlease use the solution you see as most appropriate.\n\n## Metrics\n\n- ntpctl\n  - tags:\n    - remote (remote peer for synchorization)\n    - stratum (remote peer stratum)\n  - fields:\n    - delay (round trip delay to the remote peer in milliseconds; `float`)\n    - jitter (mean deviation (jitter) for remote peer; `float`)\n    - offset (mean offset (phase) to remote peer in milliseconds; `float`)\n    - poll (polling interval in seconds; `int`)\n    - next (number of seconds until the next poll; `int`)\n    - wt (peer weight; `int`)\n    - tl (peer trust level; `int`)\n\n## Example Output\n\n```text\nopenntpd,remote=194.57.169.1,stratum=2,host=localhost tl=10i,poll=1007i,\noffset=2.295,jitter=3.896,delay=53.766,next=266i,wt=1i 1514454299000000000\n```\n"
  },
  {
    "path": "plugins/inputs/openntpd/openntpd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage openntpd\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultBinary  = \"/usr/sbin/ntpctl\"\n\tdefaultTimeout = config.Duration(5 * time.Second)\n\n\t// Mapping of the ntpctl tag key to the index in the command output\n\ttagI = map[string]int{\n\t\t\"stratum\": 2,\n\t}\n\t// Mapping of float metrics to their index in the command output\n\tfloatI = map[string]int{\n\t\t\"offset\": 5,\n\t\t\"delay\":  6,\n\t\t\"jitter\": 7,\n\t}\n\t// Mapping of int metrics to their index in the command output\n\tintI = map[string]int{\n\t\t\"wt\":   0,\n\t\t\"tl\":   1,\n\t\t\"next\": 3,\n\t\t\"poll\": 4,\n\t}\n)\n\ntype Openntpd struct {\n\tBinary  string          `toml:\"binary\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tUseSudo bool            `toml:\"use_sudo\"`\n\n\trun runner\n}\n\ntype runner func(cmdName string, timeout config.Duration, useSudo bool) (*bytes.Buffer, error)\n\nfunc (*Openntpd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *Openntpd) Gather(acc telegraf.Accumulator) error {\n\tout, err := n.run(n.Binary, n.Timeout, n.UseSudo)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error gathering metrics: %w\", err)\n\t}\n\n\tlineCounter := 0\n\tscanner := bufio.NewScanner(out)\n\tfor scanner.Scan() {\n\t\t// skip first (peer) and second (field list) line\n\t\tif lineCounter < 2 {\n\t\t\tlineCounter++\n\t\t\tcontinue\n\t\t}\n\n\t\tline := scanner.Text()\n\n\t\tfields := strings.Fields(line)\n\n\t\tmFields := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\n\t\t// Even line ---> ntp server info\n\t\tif lineCounter%2 == 0 {\n\t\t\t// DNS resolution error ---> keep DNS name as remote name\n\t\t\tif fields[0] != \"not\" {\n\t\t\t\ttags[\"remote\"] = fields[0]\n\t\t\t} else {\n\t\t\t\ttags[\"remote\"] = fields[len(fields)-1]\n\t\t\t}\n\t\t}\n\n\t\t// Read next line - Odd line ---> ntp server stats\n\t\tscanner.Scan()\n\t\tline = scanner.Text()\n\t\tlineCounter++\n\n\t\tfields = strings.Fields(line)\n\n\t\t// if there is an ntpctl state prefix, remove it and make it it's own tag\n\t\tif strings.ContainsAny(fields[0], \"*\") {\n\t\t\ttags[\"state_prefix\"] = fields[0]\n\t\t\tfields = fields[1:]\n\t\t}\n\n\t\t// Get tags from output\n\t\tfor key, index := range tagI {\n\t\t\tif index >= len(fields) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttags[key] = fields[index]\n\t\t}\n\n\t\t// Get integer metrics from output\n\t\tfor key, index := range intI {\n\t\t\tif index >= len(fields) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif fields[index] == \"-\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif key == \"next\" || key == \"poll\" {\n\t\t\t\tm, err := strconv.ParseInt(strings.TrimSuffix(fields[index], \"s\"), 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"integer value expected, got: %s\", fields[index]))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmFields[key] = m\n\t\t\t} else {\n\t\t\t\tm, err := strconv.ParseInt(fields[index], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"integer value expected, got: %s\", fields[index]))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmFields[key] = m\n\t\t\t}\n\t\t}\n\n\t\t// get float metrics from output\n\t\tfor key, index := range floatI {\n\t\t\tif len(fields) <= index {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif fields[index] == \"-\" || fields[index] == \"----\" || fields[index] == \"peer\" || fields[index] == \"not\" || fields[index] == \"valid\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif key == \"offset\" || key == \"delay\" || key == \"jitter\" {\n\t\t\t\tm, err := strconv.ParseFloat(strings.TrimSuffix(fields[index], \"ms\"), 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"float value expected, got: %s\", fields[index]))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmFields[key] = m\n\t\t\t} else {\n\t\t\t\tm, err := strconv.ParseFloat(fields[index], 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"float value expected, got: %s\", fields[index]))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmFields[key] = m\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"openntpd\", mFields, tags)\n\n\t\tlineCounter++\n\t}\n\treturn nil\n}\n\n// Shell out to ntpctl and return the output\nfunc openntpdRunner(cmdName string, timeout config.Duration, useSudo bool) (*bytes.Buffer, error) {\n\tcmdArgs := []string{\"-s\", \"peers\"}\n\n\tcmd := exec.Command(cmdName, cmdArgs...)\n\n\tif useSudo {\n\t\tcmdArgs = append([]string{cmdName}, cmdArgs...)\n\t\tcmd = exec.Command(\"sudo\", cmdArgs...)\n\t}\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn &out, fmt.Errorf(\"error running ntpctl: %w\", err)\n\t}\n\n\treturn &out, nil\n}\n\nfunc init() {\n\tinputs.Add(\"openntpd\", func() telegraf.Input {\n\t\treturn &Openntpd{\n\t\t\trun:     openntpdRunner,\n\t\t\tBinary:  defaultBinary,\n\t\t\tTimeout: defaultTimeout,\n\t\t\tUseSudo: false,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/openntpd/openntpd_test.go",
    "content": "package openntpd\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc openntpdCTL(output string) func(string, config.Duration, bool) (*bytes.Buffer, error) {\n\treturn func(string, config.Duration, bool) (*bytes.Buffer, error) {\n\t\treturn bytes.NewBufferString(output), nil\n\t}\n}\n\nfunc TestParseSimpleOutput(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(simpleOutput),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 7, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"wt\":     int64(1),\n\t\t\"tl\":     int64(10),\n\t\t\"next\":   int64(56),\n\t\t\"poll\":   int64(63),\n\t\t\"offset\": float64(9.271),\n\t\t\"delay\":  float64(44.662),\n\t\t\"jitter\": float64(2.678),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":  \"212.129.9.36\",\n\t\t\"stratum\": \"3\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n}\n\nfunc TestParseSimpleOutputwithStatePrefix(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(simpleOutputwithStatePrefix),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 7, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"wt\":     int64(1),\n\t\t\"tl\":     int64(10),\n\t\t\"next\":   int64(45),\n\t\t\"poll\":   int64(980),\n\t\t\"offset\": float64(-9.901),\n\t\t\"delay\":  float64(67.573),\n\t\t\"jitter\": float64(29.350),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":       \"92.243.6.5\",\n\t\t\"stratum\":      \"2\",\n\t\t\"state_prefix\": \"*\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n}\n\nfunc TestParseSimpleOutputInvalidPeer(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(simpleOutputInvalidPeer),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 4, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"wt\":   int64(1),\n\t\t\"tl\":   int64(2),\n\t\t\"next\": int64(203),\n\t\t\"poll\": int64(300),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":  \"178.33.111.49\",\n\t\t\"stratum\": \"-\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n}\n\nfunc TestParseSimpleOutputServersDNSError(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(simpleOutputServersDNSError),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 4, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"next\": int64(2),\n\t\t\"poll\": int64(15),\n\t\t\"wt\":   int64(1),\n\t\t\"tl\":   int64(2),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":  \"pool.nl.ntp.org\",\n\t\t\"stratum\": \"-\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n\n\tsecondpeerfields := map[string]interface{}{\n\t\t\"next\": int64(2),\n\t\t\"poll\": int64(15),\n\t\t\"wt\":   int64(1),\n\t\t\"tl\":   int64(2),\n\t}\n\n\tsecondpeertags := map[string]string{\n\t\t\"remote\":  \"pool.nl.ntp.org\",\n\t\t\"stratum\": \"-\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", secondpeerfields, secondpeertags)\n}\n\nfunc TestParseSimpleOutputServerDNSError(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(simpleOutputServerDNSError),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 4, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"next\": int64(12),\n\t\t\"poll\": int64(15),\n\t\t\"wt\":   int64(1),\n\t\t\"tl\":   int64(2),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":  \"pool.fr.ntp.org\",\n\t\t\"stratum\": \"-\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n}\n\nfunc TestParseFullOutput(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Openntpd{\n\t\trun: openntpdCTL(fullOutput),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"openntpd\"))\n\trequire.Equal(t, uint64(20), acc.NMetrics())\n\n\trequire.Equal(t, 113, acc.NFields())\n\n\tfirstpeerfields := map[string]interface{}{\n\t\t\"wt\":     int64(1),\n\t\t\"tl\":     int64(10),\n\t\t\"next\":   int64(56),\n\t\t\"poll\":   int64(63),\n\t\t\"offset\": float64(9.271),\n\t\t\"delay\":  float64(44.662),\n\t\t\"jitter\": float64(2.678),\n\t}\n\n\tfirstpeertags := map[string]string{\n\t\t\"remote\":  \"212.129.9.36\",\n\t\t\"stratum\": \"3\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", firstpeerfields, firstpeertags)\n\n\tsecondpeerfields := map[string]interface{}{\n\t\t\"wt\":     int64(1),\n\t\t\"tl\":     int64(10),\n\t\t\"next\":   int64(21),\n\t\t\"poll\":   int64(64),\n\t\t\"offset\": float64(-0.103),\n\t\t\"delay\":  float64(53.199),\n\t\t\"jitter\": float64(9.046),\n\t}\n\n\tsecondpeertags := map[string]string{\n\t\t\"remote\":  \"163.172.25.19\",\n\t\t\"stratum\": \"2\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", secondpeerfields, secondpeertags)\n\n\tthirdpeerfields := map[string]interface{}{\n\t\t\"wt\":     int64(1),\n\t\t\"tl\":     int64(10),\n\t\t\"next\":   int64(45),\n\t\t\"poll\":   int64(980),\n\t\t\"offset\": float64(-9.901),\n\t\t\"delay\":  float64(67.573),\n\t\t\"jitter\": float64(29.350),\n\t}\n\n\tthirdpeertags := map[string]string{\n\t\t\"remote\":       \"92.243.6.5\",\n\t\t\"stratum\":      \"2\",\n\t\t\"state_prefix\": \"*\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", thirdpeerfields, thirdpeertags)\n\n\tfourthpeerfields := map[string]interface{}{\n\t\t\"wt\":   int64(1),\n\t\t\"tl\":   int64(2),\n\t\t\"next\": int64(203),\n\t\t\"poll\": int64(300),\n\t}\n\n\tfourthpeertags := map[string]string{\n\t\t\"remote\":  \"178.33.111.49\",\n\t\t\"stratum\": \"-\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"openntpd\", fourthpeerfields, fourthpeertags)\n}\n\nvar simpleOutput = `peer\nwt tl st  next  poll          offset       delay      jitter\n212.129.9.36 from pool 0.debian.pool.ntp.org\n1 10  3   56s   63s         9.271ms    44.662ms     2.678ms`\n\nvar simpleOutputwithStatePrefix = `peer\nwt tl st  next  poll          offset       delay      jitter\n92.243.6.5 from pool 0.debian.pool.ntp.org\n*  1 10  2   45s  980s        -9.901ms    67.573ms    29.350ms`\n\nvar simpleOutputInvalidPeer = `peer\nwt tl st  next  poll          offset       delay      jitter\n178.33.111.49 from pool 0.debian.pool.ntp.org\n1  2  -  203s  300s             ---- peer not valid ----`\n\nvar simpleOutputServersDNSError = `peer\nwt tl st  next  poll          offset       delay      jitter\nnot resolved from pool pool.nl.ntp.org\n1  2  -    2s   15s             ---- peer not valid ----\n`\nvar simpleOutputServerDNSError = `peer\nwt tl st  next  poll          offset       delay      jitter\nnot resolved pool.fr.ntp.org\n1  2  -   12s   15s             ---- peer not valid ----\n`\n\nvar fullOutput = `peer\nwt tl st  next  poll          offset       delay      jitter\n212.129.9.36 from pool 0.debian.pool.ntp.org\n1 10  3   56s   63s         9.271ms    44.662ms     2.678ms\n163.172.25.19 from pool 0.debian.pool.ntp.org\n1 10  2   21s   64s        -0.103ms    53.199ms     9.046ms\n92.243.6.5 from pool 0.debian.pool.ntp.org\n*  1 10  2   45s  980s        -9.901ms    67.573ms    29.350ms\n178.33.111.49 from pool 0.debian.pool.ntp.org\n1  2  -  203s  300s             ---- peer not valid ----\n62.210.122.129 from pool 1.debian.pool.ntp.org\n1 10  3    4s   60s         5.372ms    53.690ms    14.700ms\n163.172.225.159 from pool 1.debian.pool.ntp.org\n1 10  3   38s   61s        12.276ms    40.631ms     1.282ms\n5.196.192.58 from pool 1.debian.pool.ntp.org\n1  2  -    0s  300s             ---- peer not valid ----\n129.250.35.250 from pool 1.debian.pool.ntp.org\n1 10  2   28s   63s        11.236ms    43.874ms     1.381ms\n2001:41d0:a:5a7::1 from pool 2.debian.pool.ntp.org\n1  2  -    5s   15s             ---- peer not valid ----\n2001:41d0:8:188d::16 from pool 2.debian.pool.ntp.org\n1  2  -    3s   15s             ---- peer not valid ----\n2001:4b98:dc0:41:216:3eff:fe69:46e3 from pool 2.debian.pool.ntp.org\n1  2  -   14s   15s             ---- peer not valid ----\n2a01:e0d:1:3:58bf:fa61:0:1 from pool 2.debian.pool.ntp.org\n1  2  -    9s   15s             ---- peer not valid ----\n163.172.179.38 from pool 2.debian.pool.ntp.org\n1 10  2   51s   65s       -19.229ms    85.404ms    48.734ms\n5.135.3.88 from pool 2.debian.pool.ntp.org\n1  2  -  173s  300s             ---- peer not valid ----\n195.154.41.195 from pool 2.debian.pool.ntp.org\n1 10  2   84s 1004s        -3.956ms    54.549ms    13.658ms\n62.210.81.130 from pool 2.debian.pool.ntp.org\n1 10  2  158s 1043s       -42.593ms   124.353ms    94.230ms\n149.202.97.123 from pool 3.debian.pool.ntp.org\n1  2  -  205s  300s             ---- peer not valid ----\n51.15.175.224 from pool 3.debian.pool.ntp.org\n1 10  2    9s   64s         8.861ms    46.640ms     0.668ms\n37.187.5.167 from pool 3.debian.pool.ntp.org\n1  2  -  105s  300s             ---- peer not valid ----\n194.57.169.1 from pool 3.debian.pool.ntp.org\n1 10  2   32s   63s         6.589ms    52.051ms     2.057ms`\n"
  },
  {
    "path": "plugins/inputs/openntpd/sample.conf",
    "content": "# Get standard NTP query metrics from OpenNTPD.\n[[inputs.openntpd]]\n  ## Run ntpctl binary with sudo.\n  # use_sudo = false\n\n  ## Location of the ntpctl binary.\n  # binary = \"/usr/sbin/ntpctl\"\n\n  ## Maximum time the ntpctl binary is allowed to run.\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/README.md",
    "content": "# OpenSearch Query Input Plugin\n\nThis plugin queries [OpenSearch][opensearch] endpoints to derive metrics from\ndata stored in an OpenSearch cluster like the number of hits for a search query,\nstatistics on numeric fields, document counts, etc.\n\n> [!NOTE]\n> This plugins is tested against OpenSearch 2.5.0 and 1.3.7 but newer version\n> should also work.\n\n⭐ Telegraf v1.26.0\n🏷️ datastore\n💻 all\n\n[opensearch]: https://opensearch.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Derive metrics from aggregating OpenSearch query results\n[[inputs.opensearch_query]]\n  ## OpenSearch cluster endpoint(s). Multiple urls can be specified as part\n  ## of the same cluster.  Only one successful call will be made per interval.\n  urls = [ \"https://node1.os.example.com:9200\" ] # required.\n\n  ## OpenSearch client timeout, defaults to \"5s\".\n  # timeout = \"5s\"\n\n  ## HTTP basic authentication details\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Skip TLS validation.  Useful for local testing and self-signed certs.\n  # insecure_skip_verify = false\n\n  [[inputs.opensearch_query.aggregation]]\n    ## measurement name for the results of the aggregation query\n    measurement_name = \"measurement\"\n\n    ## OpenSearch index or index pattern to search\n    index = \"index-*\"\n\n    ## The date/time field in the OpenSearch index (mandatory).\n    date_field = \"@timestamp\"\n\n    ## If the field used for the date/time field in OpenSearch is also using\n    ## a custom date/time format it may be required to provide the format to\n    ## correctly parse the field.\n    ##\n    ## If using one of the built in OpenSearch formats this is not required.\n    ## https://opensearch.org/docs/2.4/opensearch/supported-field-types/date/#built-in-formats\n    # date_field_custom_format = \"\"\n\n    ## Time window to query (eg. \"1m\" to query documents from last minute).\n    ## Normally should be set to same as collection interval\n    query_period = \"1m\"\n\n    ## Lucene query to filter results\n    # filter_query = \"*\"\n\n    ## Fields to aggregate values (must be numeric fields)\n    # metric_fields = [\"metric\"]\n\n    ## Aggregation function to use on the metric fields\n    ## Must be set if 'metric_fields' is set\n    ## Valid values are: avg, sum, min, max, sum\n    # metric_function = \"avg\"\n\n    ## Fields to be used as tags.  Must be text, non-analyzed fields. Metric\n    ## aggregations are performed per tag\n    # tags = [\"field.keyword\", \"field2.keyword\"]\n\n    ## Set to true to not ignore documents when the tag(s) above are missing\n    # include_missing_tag = false\n\n    ## String value of the tag when the tag does not exist\n    ## Required when include_missing_tag is true\n    # missing_tag_value = \"null\"\n```\n\n### Supported queries\n\nThe following queries are supported:\n\n- return number of hits for a search query\n- calculate the `avg`/`max`/`min`/`sum` for a numeric field, filtered by a query,\n  aggregated per tag\n- `value_count` returns the number of documents for a particular field\n- `stats` (returns `sum`, `min`, `max`, `avg`, and `value_count` in one query)\n- extended_stats (`stats` plus stats such as sum of squares, variance, and standard\n  deviation)\n- `percentiles` returns the 1st, 5th, 25th, 50th, 75th, 95th, and 99th percentiles\n\n### Required parameters\n\n- `measurement_name`: The target measurement to be stored the results of the\n  aggregation query.\n- `index`: The index name to query on OpenSearch\n- `query_period`: The time window to query (eg. \"1m\" to query documents from\n  last minute). Normally should be set to same as collection\n- `date_field`: The date/time field in the OpenSearch index\n\n### Optional parameters\n\n- `date_field_custom_format`: Not needed if using one of the built in date/time\n  formats of OpenSearch, but may be required if using a custom date/time\n  format. The format syntax uses the [Joda date format][joda].\n- `filter_query`: Lucene query to filter the results (default: \"\\*\")\n- `metric_fields`: The list of fields to perform metric aggregation (these must\n  be indexed as numeric fields)\n- `metric_function`: The single-value metric aggregation function to be performed\n  on the `metric_fields` defined. Currently supported aggregations are \"avg\",\n  \"min\", \"max\", \"sum\", \"value_count\", \"stats\", \"extended_stats\", \"percentiles\".\n  (see the [aggregation docs][agg])\n- `tags`: The list of fields to be used as tags (these must be indexed as\n  non-analyzed fields). A \"terms aggregation\" will be done per tag defined\n- `include_missing_tag`: Set to true to not ignore documents where the tag(s)\n  specified above does not exist. (If false, documents without the specified tag\n  field will be ignored in `doc_count` and in the metric aggregation)\n- `missing_tag_value`: The value of the tag that will be set for documents in\n  which the tag field does not exist. Only used when `include_missing_tag` is\n  set to `true`.\n\n[joda]: https://opensearch.org/docs/2.4/opensearch/supported-field-types/date/#custom-formats\n[agg]: https://opensearch.org/docs/2.4/opensearch/aggregations/\n\n### Example configurations\n\n#### Search the average response time, per URI and per response status code\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"my-index-*\"\n  filter_query = \"*\"\n  metric_fields = [\"response_time\"]\n  metric_function = \"avg\"\n  tags = [\"URI.keyword\", \"response.keyword\"]\n  include_missing_tag = true\n  missing_tag_value = \"null\"\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n#### Search the maximum response time per method and per URI\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"my-index-*\"\n  filter_query = \"*\"\n  metric_fields = [\"response_time\"]\n  metric_function = \"max\"\n  tags = [\"method.keyword\",\"URI.keyword\"]\n  include_missing_tag = false\n  missing_tag_value = \"null\"\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n#### Search number of documents matching a filter query in all indices\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"*\"\n  filter_query = \"product_1 AND HEAD\"\n  query_period = \"1m\"\n  date_field = \"@timestamp\"\n```\n\n#### Search number of documents matching a filter query, returning per response status code\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"*\"\n  filter_query = \"downloads\"\n  tags = [\"response.keyword\"]\n  include_missing_tag = false\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n#### Search all documents and generate common statistics, returning per response status code\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n  measurement_name = \"http_logs\"\n  index = \"*\"\n  tags = [\"response.keyword\"]\n  include_missing_tag = false\n  date_field = \"@timestamp\"\n  query_period = \"1m\"\n```\n\n## Metrics\n\nAll metrics derive from aggregating OpenSearch query results.  Queries must\nconform to appropriate OpenSearch\n[Aggregations](https://opensearch.org/docs/latest/opensearch/aggregations/)\nfor more information.\n\nMetric names are composed of a combination of the field name, metric aggregation\nfunction, and the result field name.\n\nFor simple metrics, the result field name is `value`, and so getting the `avg`\non a field named `size` would produce the result `size_value_avg`.\n\nFor functions with multiple metrics, we use the resulting field.  For example,\nthe `stats` function returns five different results, so for a field `size`,\nwe would see five metric fields, named `size_stats_min`,\n`size_stats_max`, `size_stats_sum`, `size_stats_avg`, and `size_stats_count`.\n\nNested results will build on their parent field names, for example, results for\npercentile take the form:\n\n```json\n{\n  \"aggregations\" : {\n  \"size_percentiles\" : {\n    \"values\" : {\n      \"1.0\" : 21.984375,\n      \"5.0\" : 27.984375,\n      \"25.0\" : 44.96875,\n      \"50.0\" : 64.22061688311689,\n      \"75.0\" : 93.0,\n      \"95.0\" : 156.0,\n      \"99.0\" : 222.0\n    }\n  }\n }\n}\n```\n\nThus, our results would take the form `size_percentiles_values_1.0`.  This\nstructure applies to `percentiles` and `extended_stats` functions.\n\nNote: `extended_stats` is currently limited to 2 standard deviations only.\n\n## Example Output\n\n```toml\n[[inputs.opensearch_query.aggregation]]\n    measurement_name = \"bytes_stats\"\n    index = \"opensearch_dashboards_sample_data_logs\"\n    date_field = \"timestamp\"\n    query_period = \"10m\"\n    filter_query = \"*\"\n    metric_fields = [\"bytes\"]\n    metric_function = \"stats\"\n    tags = [\"response.keyword\"]\n```\n\n```text\nbytes_stats,host=localhost,response_keyword=200 bytes_stats_sum=22231,doc_count=4i,bytes_stats_count=4,bytes_stats_min=941,bytes_stats_max=9544,bytes_stats_avg=5557.75 1672327840000000000\nbytes_stats,host=localhost,response_keyword=404 bytes_stats_min=5330,bytes_stats_max=5330,bytes_stats_avg=5330,doc_count=1i,bytes_stats_sum=5330,bytes_stats_count=1 1672327840000000000\n```\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/aggregation.bucket.go",
    "content": "package opensearch_query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype bucketAggregationRequest map[string]*aggregationFunction\n\nfunc (b bucketAggregationRequest) addAggregation(name, aggType, field string) error {\n\tswitch aggType {\n\tcase \"terms\":\n\tdefault:\n\t\treturn fmt.Errorf(\"aggregation function %q not supported\", aggType)\n\t}\n\n\tb[name] = &aggregationFunction{\n\t\taggType: aggType,\n\t\tfield:   field,\n\t}\n\n\treturn nil\n}\n\nfunc (b bucketAggregationRequest) addNestedAggregation(name string, a aggregationRequest) {\n\tb[name].nested = a\n}\n\nfunc (b bucketAggregationRequest) bucketSize(name string, size int) error {\n\tif size <= 0 {\n\t\treturn errors.New(\"invalid size; must be integer value > 0\")\n\t}\n\n\tif _, ok := b[name]; !ok {\n\t\treturn fmt.Errorf(\"aggregation %q not found\", name)\n\t}\n\n\tb[name].setSize(size)\n\n\treturn nil\n}\n\nfunc (b bucketAggregationRequest) missing(name, missing string) {\n\tb[name].setMissing(missing)\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/aggregation.go",
    "content": "package opensearch_query\n\nimport (\n\t\"encoding/json\"\n)\n\ntype aggregationRequest interface {\n\taddAggregation(string, string, string) error\n}\n\ntype aggregationFunction struct {\n\taggType string\n\tfield   string\n\tsize    int\n\tmissing string\n\n\tnested aggregationRequest\n}\n\n// MarshalJSON serializes the aggregationFunction into JSON format.\nfunc (a *aggregationFunction) MarshalJSON() ([]byte, error) {\n\tagg := make(map[string]interface{})\n\tfield := map[string]interface{}{\"field\": a.field}\n\tif t := getAggregationFunctionType(a.aggType); t == \"bucket\" {\n\t\t// We'll use the default size of 10 if it hasn't been set; size == 0 is illegal in a bucket aggregation\n\t\tif a.size == 0 {\n\t\t\ta.size = 10\n\t\t}\n\t\tfield[\"size\"] = a.size\n\t}\n\tif a.missing != \"\" {\n\t\tfield[\"missing\"] = a.missing\n\t}\n\n\tagg[a.aggType] = field\n\n\tif a.nested != nil {\n\t\tagg[\"aggregations\"] = a.nested\n\t}\n\treturn json.Marshal(agg)\n}\n\nfunc (a *aggregationFunction) setSize(size int) {\n\ta.size = size\n}\n\nfunc (a *aggregationFunction) setMissing(missing string) {\n\ta.missing = missing\n}\n\nfunc getAggregationFunctionType(field string) string {\n\tswitch field {\n\tcase \"avg\", \"sum\", \"min\", \"max\", \"value_count\", \"stats\", \"extended_stats\", \"percentiles\":\n\t\treturn \"metric\"\n\tcase \"terms\":\n\t\treturn \"bucket\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/aggregation.metric.go",
    "content": "package opensearch_query\n\nimport \"fmt\"\n\ntype metricAggregationRequest map[string]*aggregationFunction\n\nfunc (m metricAggregationRequest) addAggregation(name, aggType, field string) error {\n\tif t := getAggregationFunctionType(aggType); t != \"metric\" {\n\t\treturn fmt.Errorf(\"aggregation function %q not supported\", aggType)\n\t}\n\n\tm[name] = &aggregationFunction{\n\t\taggType: aggType,\n\t\tfield:   field,\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/aggregation.response.go",
    "content": "package opensearch_query\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype aggregationResponse struct {\n\tHits         *searchHits  `json:\"hits\"`\n\tAggregations *aggregation `json:\"aggregations\"`\n}\n\ntype searchHits struct {\n\tTotalHits *totalHits `json:\"total,omitempty\"`\n}\n\ntype totalHits struct {\n\tRelation string `json:\"relation\"`\n\tValue    int64  `json:\"value\"`\n}\n\ntype metricAggregation map[string]interface{}\n\ntype aggregateValue struct {\n\tmetrics metricAggregation\n\tbuckets []bucketData\n}\n\ntype aggregation map[string]aggregateValue\n\ntype bucketData struct {\n\tDocumentCount int64  `json:\"doc_count\"`\n\tKey           string `json:\"key\"`\n\n\tsubaggregation aggregation\n}\n\nfunc (a *aggregationResponse) getMetrics(acc telegraf.Accumulator, measurement string) error {\n\t// Simple case (no aggregations)\n\tif a.Aggregations == nil {\n\t\ttags := make(map[string]string)\n\t\tfields := map[string]interface{}{\n\t\t\t\"doc_count\": a.Hits.TotalHits.Value,\n\t\t}\n\t\tacc.AddFields(measurement, fields, tags)\n\t\treturn nil\n\t}\n\n\treturn a.Aggregations.getMetrics(acc, measurement, a.Hits.TotalHits.Value, make(map[string]string))\n}\n\nfunc (a *aggregation) getMetrics(acc telegraf.Accumulator, measurement string, docCount int64, tags map[string]string) error {\n\tvar err error\n\tfields := make(map[string]interface{})\n\tfor name, agg := range *a {\n\t\tif agg.isAggregation() {\n\t\t\tfor _, bucket := range agg.buckets {\n\t\t\t\ttt := map[string]string{name: bucket.Key}\n\t\t\t\tfor k, v := range tags {\n\t\t\t\t\ttt[k] = v\n\t\t\t\t}\n\t\t\t\terr = bucket.subaggregation.getMetrics(acc, measurement, bucket.DocumentCount, tt)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tfor metric, value := range agg.metrics {\n\t\t\tswitch value := value.(type) {\n\t\t\tcase map[string]interface{}:\n\t\t\t\tfor k, v := range value {\n\t\t\t\t\tfields[name+\"_\"+metric+\"_\"+k] = v\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tfields[name+\"_\"+metric] = value\n\t\t\t}\n\t\t}\n\t}\n\n\tfields[\"doc_count\"] = docCount\n\tacc.AddFields(measurement, fields, tags)\n\n\treturn nil\n}\n\n// UnmarshalJSON is a custom JSON unmarshaler for the aggregateValue struct.\nfunc (a *aggregateValue) UnmarshalJSON(bytes []byte) error {\n\tvar partial map[string]json.RawMessage\n\terr := json.Unmarshal(bytes, &partial)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// We'll continue to unmarshal if we have buckets\n\tif b, found := partial[\"buckets\"]; found {\n\t\treturn json.Unmarshal(b, &a.buckets)\n\t}\n\n\t// Use the remaining bytes as metrics\n\treturn json.Unmarshal(bytes, &a.metrics)\n}\n\nfunc (a *aggregateValue) isAggregation() bool {\n\treturn a.buckets != nil\n}\n\n// UnmarshalJSON is a custom JSON unmarshaler for the bucketData struct.\nfunc (b *bucketData) UnmarshalJSON(bytes []byte) error {\n\tvar partial map[string]json.RawMessage\n\tvar err error\n\n\terr = json.Unmarshal(bytes, &partial)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(partial[\"doc_count\"], &b.DocumentCount)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdelete(partial, \"doc_count\")\n\n\terr = json.Unmarshal(partial[\"key\"], &b.Key)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdelete(partial, \"key\")\n\n\tif b.subaggregation == nil {\n\t\tb.subaggregation = make(aggregation)\n\t}\n\n\tfor name, message := range partial {\n\t\tvar subaggregation aggregateValue\n\t\terr = json.Unmarshal(message, &subaggregation)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb.subaggregation[name] = subaggregation\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/opensearch_query.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage opensearch_query\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/opensearch-project/opensearch-go/v2\"\n\t\"github.com/opensearch-project/opensearch-go/v2/opensearchapi\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype OpensearchQuery struct {\n\tURLs                []string        `toml:\"urls\"`\n\tUsername            config.Secret   `toml:\"username\"`\n\tPassword            config.Secret   `toml:\"password\"`\n\tEnableSniffer       bool            `toml:\"enable_sniffer\"`\n\tTimeout             config.Duration `toml:\"timeout\"`\n\tHealthCheckInterval config.Duration `toml:\"health_check_interval\"`\n\tAggregations        []osAggregation `toml:\"aggregation\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tcommon_tls.ClientConfig\n\tosClient *opensearch.Client\n}\n\ntype osAggregation struct {\n\tIndex             string          `toml:\"index\"`\n\tMeasurementName   string          `toml:\"measurement_name\"`\n\tDateField         string          `toml:\"date_field\"`\n\tDateFieldFormat   string          `toml:\"date_field_custom_format\"`\n\tQueryPeriod       config.Duration `toml:\"query_period\"`\n\tFilterQuery       string          `toml:\"filter_query\"`\n\tMetricFields      []string        `toml:\"metric_fields\"`\n\tMetricFunction    string          `toml:\"metric_function\"`\n\tTags              []string        `toml:\"tags\"`\n\tIncludeMissingTag bool            `toml:\"include_missing_tag\"`\n\tMissingTagValue   string          `toml:\"missing_tag_value\"`\n\tmapMetricFields   map[string]string\n\n\taggregation aggregationRequest\n}\n\nfunc (*OpensearchQuery) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *OpensearchQuery) Init() error {\n\tif o.URLs == nil {\n\t\treturn errors.New(\"no urls defined\")\n\t}\n\n\terr := o.newClient()\n\tif err != nil {\n\t\to.Log.Errorf(\"Error creating OpenSearch client: %v\", err)\n\t}\n\n\tfor i, agg := range o.Aggregations {\n\t\tif agg.MeasurementName == \"\" {\n\t\t\treturn errors.New(\"field 'measurement_name' is not set\")\n\t\t}\n\t\tif agg.DateField == \"\" {\n\t\t\treturn errors.New(\"field 'date_field' is not set\")\n\t\t}\n\t\terr = o.initAggregation(agg, i)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *OpensearchQuery) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, agg := range o.Aggregations {\n\t\twg.Add(1)\n\t\tgo func(agg osAggregation) {\n\t\t\tdefer wg.Done()\n\t\t\terr := o.osAggregationQuery(acc, agg)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"opensearch query aggregation %q: %w \", agg.MeasurementName, err))\n\t\t\t}\n\t\t}(agg)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (o *OpensearchQuery) newClient() error {\n\tusername, err := o.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tdefer username.Destroy()\n\n\tpassword, err := o.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer password.Destroy()\n\n\tclientConfig := opensearch.Config{\n\t\tAddresses: o.URLs,\n\t\tUsername:  username.String(),\n\t\tPassword:  password.String(),\n\t}\n\n\tif o.InsecureSkipVerify {\n\t\tclientConfig.Transport = &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{InsecureSkipVerify: true},\n\t\t}\n\t}\n\n\tclient, err := opensearch.NewClient(clientConfig)\n\to.osClient = client\n\n\treturn err\n}\n\nfunc (o *OpensearchQuery) initAggregation(agg osAggregation, i int) (err error) {\n\tfor _, metricField := range agg.MetricFields {\n\t\tif _, ok := agg.mapMetricFields[metricField]; !ok {\n\t\t\treturn fmt.Errorf(\"metric field %q not found on index %q\", metricField, agg.Index)\n\t\t}\n\t}\n\n\terr = agg.buildAggregationQuery()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building aggregation: %w\", err)\n\t}\n\n\to.Aggregations[i] = agg\n\treturn nil\n}\n\nfunc (o *OpensearchQuery) osAggregationQuery(acc telegraf.Accumulator, aggregation osAggregation) error {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Timeout))\n\tdefer cancel()\n\n\tsearchResult, err := o.runAggregationQuery(ctx, aggregation)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn searchResult.getMetrics(acc, aggregation.MeasurementName)\n}\n\nfunc (o *OpensearchQuery) runAggregationQuery(ctx context.Context, aggregation osAggregation) (*aggregationResponse, error) {\n\tnow := time.Now().UTC()\n\tfrom := now.Add(time.Duration(-aggregation.QueryPeriod))\n\tfilterQuery := aggregation.FilterQuery\n\tif filterQuery == \"\" {\n\t\tfilterQuery = \"*\"\n\t}\n\n\taq := &query{\n\t\tSize:         0,\n\t\tAggregations: aggregation.aggregation,\n\t\tQuery:        nil,\n\t}\n\n\tboolQuery := &boolQuery{\n\t\tFilterQueryString: filterQuery,\n\t\tTimestampField:    aggregation.DateField,\n\t\tTimeRangeFrom:     from,\n\t\tTimeRangeTo:       now,\n\t\tDateFieldFormat:   aggregation.DateFieldFormat,\n\t}\n\n\taq.Query = boolQuery\n\treq, err := json.Marshal(aq)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\n\tsearchRequest := &opensearchapi.SearchRequest{\n\t\tBody:    strings.NewReader(string(req)),\n\t\tIndex:   []string{aggregation.Index},\n\t\tTimeout: time.Duration(o.Timeout),\n\t}\n\n\tresp, err := searchRequest.Do(ctx, o.osClient)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.IsError() {\n\t\treturn nil, fmt.Errorf(\"opensearch SearchRequest failure: [%d] %s\", resp.StatusCode, resp.Status())\n\t}\n\tdefer resp.Body.Close()\n\n\tvar searchResult aggregationResponse\n\n\tdecoder := json.NewDecoder(resp.Body)\n\terr = decoder.Decode(&searchResult)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &searchResult, nil\n}\n\nfunc (aggregation *osAggregation) buildAggregationQuery() error {\n\tvar agg aggregationRequest\n\tagg = &metricAggregationRequest{}\n\n\t// create one aggregation per metric field found & function defined for numeric fields\n\tfor k, v := range aggregation.mapMetricFields {\n\t\tswitch v {\n\t\tcase \"long\", \"float\", \"integer\", \"short\", \"double\", \"scaled_float\":\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\terr := agg.addAggregation(strings.ReplaceAll(k, \".\", \"_\")+\"_\"+aggregation.MetricFunction, aggregation.MetricFunction, k)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// create a terms aggregation per tag\n\tfor _, term := range aggregation.Tags {\n\t\tbucket := &bucketAggregationRequest{}\n\t\tname := strings.ReplaceAll(term, \".\", \"_\")\n\t\terr := bucket.addAggregation(name, \"terms\", term)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = bucket.bucketSize(name, 1000)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif aggregation.IncludeMissingTag && aggregation.MissingTagValue != \"\" {\n\t\t\tbucket.missing(name, aggregation.MissingTagValue)\n\t\t}\n\n\t\tbucket.addNestedAggregation(name, agg)\n\n\t\tagg = bucket\n\t}\n\n\taggregation.aggregation = agg\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"opensearch_query\", func() telegraf.Input {\n\t\treturn &OpensearchQuery{\n\t\t\tTimeout:             config.Duration(time.Second * 5),\n\t\t\tHealthCheckInterval: config.Duration(time.Second * 10),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/opensearch_query_test.go",
    "content": "package opensearch_query\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/opensearch-project/opensearch-go/v2/opensearchutil\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst (\n\tservicePort = \"9200\"\n\ttestindex   = \"test-opensearch\"\n)\n\ntype osAggregationQueryTest struct {\n\tqueryName                 string\n\ttestAggregationQueryInput osAggregation\n\texpectedMetrics           []telegraf.Metric\n\twantQueryResErr           bool\n\twantInitErr               bool\n}\n\nvar queryPeriod = config.Duration(time.Second * 600)\n\nfunc testData() []osAggregationQueryTest {\n\treturn []osAggregationQueryTest{\n\t\t{\n\t\t\tqueryName: \"query 1 (avg)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement1\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"product_1\",\n\t\t\t\tMetricFunction:  \"avg\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement1\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\"size_avg_value\": float64(202.30038022813687), \"doc_count\": int64(263)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 2 (avg)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement2\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"max\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement2\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\"size_max_value\": float64(3301), \"doc_count\": int64(263)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement2\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\"size_max_value\": float64(3318), \"doc_count\": int64(237)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 3 (sum)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement3\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"sum\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"response.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement3\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\"},\n\t\t\t\t\tmap[string]interface{}{\"size_sum_value\": float64(22790), \"doc_count\": int64(22)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement3\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"304\"},\n\t\t\t\t\tmap[string]interface{}{\"size_sum_value\": float64(0), \"doc_count\": int64(219)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement3\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"404\"},\n\t\t\t\t\tmap[string]interface{}{\"size_sum_value\": float64(86932), \"doc_count\": int64(259)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 4 (min, 2 fields, 3 tags)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:             testindex,\n\t\t\t\tMeasurementName:   \"measurement4\",\n\t\t\t\tMetricFields:      []string{\"size\", \"response_time\"},\n\t\t\t\tFilterQuery:       \"downloads\",\n\t\t\t\tMetricFunction:    \"min\",\n\t\t\t\tDateField:         \"@timestamp\",\n\t\t\t\tQueryPeriod:       queryPeriod,\n\t\t\t\tIncludeMissingTag: true,\n\t\t\t\tMissingTagValue:   \"missing\",\n\t\t\t\tTags:              []string{\"response.keyword\", \"URI.keyword\", \"method.keyword\"},\n\t\t\t\tmapMetricFields:   map[string]string{\"size\": \"long\", \"response_time\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"404\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(318), \"response_time_min_value\": float64(126), \"doc_count\": int64(146)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"304\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(0), \"response_time_min_value\": float64(71), \"doc_count\": int64(113)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(490), \"response_time_min_value\": float64(1514), \"doc_count\": int64(3)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"404\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(318), \"response_time_min_value\": float64(237), \"doc_count\": int64(113)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"304\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(0), \"response_time_min_value\": float64(134), \"doc_count\": int64(106)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"GET\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(490), \"response_time_min_value\": float64(2), \"doc_count\": int64(13)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\", \"method_keyword\": \"HEAD\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(0), \"response_time_min_value\": float64(8479), \"doc_count\": int64(1)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement4\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\", \"method_keyword\": \"HEAD\"},\n\t\t\t\t\tmap[string]interface{}{\"size_min_value\": float64(0), \"response_time_min_value\": float64(1059), \"doc_count\": int64(5)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 5 (no fields)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement5\",\n\t\t\t\tFilterQuery:     \"product_2\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement5\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\"doc_count\": int64(237)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 6 (no fields, to tags)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement6\",\n\t\t\t\tFilterQuery:     \"response: 200\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\", \"response.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement6\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\"doc_count\": int64(4)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement6\",\n\t\t\t\t\tmap[string]string{\"response_keyword\": \"200\", \"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\"doc_count\": int64(18)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 7 (simple query)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement7\",\n\t\t\t\tFilterQuery:     \"response: 200\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement7\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"doc_count\": int64(22)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 8 (max, no tags)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement8\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"max\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement8\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"size_max_value\": float64(3318), \"doc_count\": int64(500)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 9 (invalid function)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement9\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"average\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\twantInitErr: true,\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 10 (non-existing metric field)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement10\",\n\t\t\t\tMetricFields:    []string{\"none\"},\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\twantQueryResErr: true,\n\t\t\twantInitErr:     true,\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 11 (non-existing index field)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           \"notanindex\",\n\t\t\t\tMeasurementName: \"measurement11\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\twantQueryResErr: true,\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 12 (non-existing timestamp field)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement12\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tMetricFunction:  \"avg\",\n\t\t\t\tDateField:       \"@notatimestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement12\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"doc_count\": int64(0)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 13 (non-existing tag field)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:             testindex,\n\t\t\t\tMeasurementName:   \"measurement13\",\n\t\t\t\tMetricFields:      []string{\"size\"},\n\t\t\t\tMetricFunction:    \"avg\",\n\t\t\t\tDateField:         \"@timestamp\",\n\t\t\t\tQueryPeriod:       queryPeriod,\n\t\t\t\tIncludeMissingTag: false,\n\t\t\t\tTags:              []string{\"nothere\"},\n\t\t\t\tmapMetricFields:   map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 14 (non-existing custom date/time format)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement14\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tDateFieldFormat: \"yyyy\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tmapMetricFields: map[string]string{},\n\t\t\t},\n\t\t\twantQueryResErr: true,\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 15 (stats)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement15\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"stats\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement15\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_stats_sum\":   float64(53205),\n\t\t\t\t\t\t\"size_stats_min\":   float64(0),\n\t\t\t\t\t\t\"size_stats_max\":   float64(3301),\n\t\t\t\t\t\t\"size_stats_avg\":   float64(202.30038022813687),\n\t\t\t\t\t\t\"size_stats_count\": float64(263),\n\t\t\t\t\t\t\"doc_count\":        int64(263)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement15\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_stats_sum\":   float64(56517),\n\t\t\t\t\t\t\"size_stats_min\":   float64(0),\n\t\t\t\t\t\t\"size_stats_max\":   float64(3318),\n\t\t\t\t\t\t\"size_stats_avg\":   float64(238.46835443037975),\n\t\t\t\t\t\t\"size_stats_count\": float64(237),\n\t\t\t\t\t\t\"doc_count\":        int64(237)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 16 (extended_stats)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement16\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"extended_stats\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement16\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_extended_stats_avg\":                                   float64(202.30038022813687),\n\t\t\t\t\t\t\"size_extended_stats_count\":                                 float64(263),\n\t\t\t\t\t\t\"size_extended_stats_max\":                                   float64(3301),\n\t\t\t\t\t\t\"size_extended_stats_min\":                                   float64(0),\n\t\t\t\t\t\t\"size_extended_stats_sum\":                                   float64(53205),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation\":                         float64(254.33673728231705),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_population\":              float64(254.33673728231705),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_sampling\":                float64(254.8216504723906),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper\":            float64(710.9738547927709),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower\":            float64(-306.3730943364972),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper_population\": float64(710.9738547927709),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower_population\": float64(-306.3730943364972),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper_sampling\":   float64(711.9436811729181),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower_sampling\":   float64(-307.3429207166443),\n\t\t\t\t\t\t\"size_extended_stats_variance\":                              float64(64687.17593141436),\n\t\t\t\t\t\t\"size_extended_stats_variance_sampling\":                     float64(64934.07354947319),\n\t\t\t\t\t\t\"size_extended_stats_variance_population\":                   float64(64687.17593141436),\n\t\t\t\t\t\t\"size_extended_stats_sum_of_squares\":                        float64(27776119),\n\t\t\t\t\t\t\"doc_count\":                                                 int64(263)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement16\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_extended_stats_avg\":                                   float64(238.46835443037975),\n\t\t\t\t\t\t\"size_extended_stats_count\":                                 float64(237),\n\t\t\t\t\t\t\"size_extended_stats_max\":                                   float64(3318),\n\t\t\t\t\t\t\"size_extended_stats_min\":                                   float64(0),\n\t\t\t\t\t\t\"size_extended_stats_sum\":                                   float64(56517),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation\":                         float64(411.39122310768215),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_population\":              float64(411.39122310768215),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_sampling\":                float64(412.2618933368743),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper\":            float64(1061.250800645744),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower\":            float64(-584.3140917849846),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper_population\": float64(1061.250800645744),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower_population\": float64(-584.3140917849846),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_upper_sampling\":   float64(1062.9921411041285),\n\t\t\t\t\t\t\"size_extended_stats_std_deviation_bounds_lower_sampling\":   float64(-586.0554322433688),\n\t\t\t\t\t\t\"size_extended_stats_variance\":                              float64(169242.7384500347),\n\t\t\t\t\t\t\"size_extended_stats_variance_sampling\":                     float64(169959.86869770434),\n\t\t\t\t\t\t\"size_extended_stats_variance_population\":                   float64(169242.7384500347),\n\t\t\t\t\t\t\"size_extended_stats_sum_of_squares\":                        float64(53588045),\n\t\t\t\t\t\t\"doc_count\":                                                 int64(237)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tqueryName: \"query 17 (percentiles)\",\n\t\t\ttestAggregationQueryInput: osAggregation{\n\t\t\t\tIndex:           testindex,\n\t\t\t\tMeasurementName: \"measurement16\",\n\t\t\t\tMetricFields:    []string{\"size\"},\n\t\t\t\tFilterQuery:     \"downloads\",\n\t\t\t\tMetricFunction:  \"percentiles\",\n\t\t\t\tDateField:       \"@timestamp\",\n\t\t\t\tQueryPeriod:     queryPeriod,\n\t\t\t\tTags:            []string{\"URI.keyword\"},\n\t\t\t\tmapMetricFields: map[string]string{\"size\": \"long\"},\n\t\t\t},\n\t\t\texpectedMetrics: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement16\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_1\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_percentiles_values_1.0\":  float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_5.0\":  float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_25.0\": float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_50.0\": float64(324),\n\t\t\t\t\t\t\"size_percentiles_values_75.0\": float64(337),\n\t\t\t\t\t\t\"size_percentiles_values_95.0\": float64(341),\n\t\t\t\t\t\t\"size_percentiles_values_99.0\": float64(471.28000000000065),\n\t\t\t\t\t\t\"doc_count\":                    int64(263)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"measurement16\",\n\t\t\t\t\tmap[string]string{\"URI_keyword\": \"/downloads/product_2\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"size_percentiles_values_1.0\":  float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_5.0\":  float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_25.0\": float64(0),\n\t\t\t\t\t\t\"size_percentiles_values_50.0\": float64(324),\n\t\t\t\t\t\t\"size_percentiles_values_75.0\": float64(339),\n\t\t\t\t\t\t\"size_percentiles_values_95.0\": float64(490),\n\t\t\t\t\t\t\"size_percentiles_values_99.0\": float64(2677.419999999997),\n\t\t\t\t\t\t\"doc_count\":                    int64(237)},\n\t\t\t\t\ttime.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc opensearchTestImages() []string {\n\treturn []string{\"opensearchproject/opensearch:2.5.0\", \"opensearchproject/opensearch:1.3.7\"}\n}\n\nfunc newOpensearchQuery(url string) *OpensearchQuery {\n\treturn &OpensearchQuery{\n\t\tURLs:         []string{url},\n\t\tTimeout:      config.Duration(time.Second * 30),\n\t\tLog:          testutil.Logger{},\n\t\tUsername:     config.NewSecret([]byte(\"admin\")),\n\t\tPassword:     config.NewSecret([]byte(\"admin\")),\n\t\tClientConfig: tls.ClientConfig{InsecureSkipVerify: true},\n\t}\n}\n\nfunc setupIntegrationTest(t *testing.T, image string) (*testutil.Container, *OpensearchQuery, error) {\n\tvar err error\n\n\ttype nginxlog struct {\n\t\tIPaddress    string    `json:\"IP\"`\n\t\tTimestamp    time.Time `json:\"@timestamp\"`\n\t\tMethod       string    `json:\"method\"`\n\t\tURI          string    `json:\"URI\"`\n\t\tHttpversion  string    `json:\"http_version\"`\n\t\tResponse     string    `json:\"response\"`\n\t\tSize         float64   `json:\"size\"`\n\t\tResponseTime float64   `json:\"response_time\"`\n\t}\n\n\tcontainer := testutil.Container{\n\t\tImage:        image,\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"discovery.type\":                         \"single-node\",\n\t\t\t\"DISABLE_PERFORMANCE_ANALYZER_AGENT_CLI\": \"true\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\".opendistro_security is used as internal security index.\"),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\n\turl := fmt.Sprintf(\"https://%s:%s\", container.Address, container.Ports[servicePort])\n\n\to := newOpensearchQuery(url)\n\n\terr = o.newClient()\n\tif err != nil {\n\t\treturn &container, o, err\n\t}\n\n\t// parse and build query\n\tfile, err := os.Open(\"testdata/nginx_logs\")\n\tif err != nil {\n\t\treturn &container, o, err\n\t}\n\tdefer func(file *os.File) {\n\t\t_ = file.Close()\n\t}(file)\n\n\tindexer, err := opensearchutil.NewBulkIndexer(opensearchutil.BulkIndexerConfig{\n\t\tClient:  o.osClient,\n\t\tIndex:   testindex,\n\t\tRefresh: \"true\",\n\t})\n\tif err != nil {\n\t\treturn &container, o, err\n\t}\n\n\tscanner := bufio.NewScanner(file)\n\n\tfor scanner.Scan() {\n\t\tparts := strings.Split(scanner.Text(), \" \")\n\t\tsize, err := strconv.Atoi(parts[9])\n\t\trequire.NoError(t, err)\n\t\tresponseTime, err := strconv.Atoi(parts[len(parts)-1])\n\t\trequire.NoError(t, err)\n\n\t\tlogline := nginxlog{\n\t\t\tIPaddress:    parts[0],\n\t\t\tTimestamp:    time.Now().UTC(),\n\t\t\tMethod:       strings.ReplaceAll(parts[5], `\"`, \"\"),\n\t\t\tURI:          parts[6],\n\t\t\tHttpversion:  strings.ReplaceAll(parts[7], `\"`, \"\"),\n\t\t\tResponse:     parts[8],\n\t\t\tSize:         float64(size),\n\t\t\tResponseTime: float64(responseTime),\n\t\t}\n\n\t\tbody, e := json.Marshal(logline)\n\t\tif e != nil {\n\t\t\treturn &container, o, e\n\t\t}\n\n\t\te = indexer.Add(\n\t\t\tt.Context(),\n\t\t\topensearchutil.BulkIndexerItem{\n\t\t\t\tIndex:  testindex,\n\t\t\t\tAction: \"index\",\n\t\t\t\tBody:   strings.NewReader(string(body)),\n\t\t\t})\n\t\tif e != nil {\n\t\t\treturn &container, o, e\n\t\t}\n\t}\n\n\tif scanner.Err() != nil {\n\t\treturn &container, o, err\n\t}\n\n\tif err := indexer.Close(t.Context()); err != nil {\n\t\treturn &container, o, err\n\t}\n\n\treturn &container, o, nil\n}\n\nfunc TestOpensearchQueryIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tfor _, image := range opensearchTestImages() {\n\t\tfunc() {\n\t\t\tcontainer, o, err := setupIntegrationTest(t, image)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer container.Terminate()\n\n\t\t\tfor _, tt := range testData() {\n\t\t\t\tt.Run(tt.queryName, func(t *testing.T) {\n\t\t\t\t\tvar err error\n\t\t\t\t\tvar acc testutil.Accumulator\n\n\t\t\t\t\to.Aggregations = []osAggregation{tt.testAggregationQueryInput}\n\t\t\t\t\terr = o.Init()\n\t\t\t\t\tif (err != nil) != tt.wantInitErr {\n\t\t\t\t\t\tt.Errorf(\"OpensearchQuery.Init() error = %v, wantInitErr %v\", err, tt.wantInitErr)\n\t\t\t\t\t\treturn\n\t\t\t\t\t} else if err != nil {\n\t\t\t\t\t\t// Init() failures mean we're done\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\terr = o.Gather(&acc)\n\t\t\t\t\tif (len(acc.Errors) > 0) != tt.wantQueryResErr {\n\t\t\t\t\t\tfor _, err = range acc.Errors {\n\t\t\t\t\t\t\tt.Errorf(\"OpensearchQuery.Gather() error: %v, wantQueryResErr %v\", err, tt.wantQueryResErr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\ttestutil.RequireMetricsEqual(t, tt.expectedMetrics, acc.GetTelegrafMetrics(), testutil.SortMetrics(), testutil.IgnoreTime())\n\t\t\t\t})\n\t\t\t}\n\t\t}()\n\t}\n}\n\nfunc TestMetricAggregationMarshal(t *testing.T) {\n\tagg := &metricAggregationRequest{}\n\terr := agg.addAggregation(\"sum_taxful_total_price\", \"sum\", \"taxful_total_price\")\n\trequire.NoError(t, err)\n\n\t_, err = json.Marshal(agg)\n\trequire.NoError(t, err)\n\n\tbucket := &bucketAggregationRequest{}\n\terr = bucket.addAggregation(\"terms_by_currency\", \"terms\", \"currency\")\n\trequire.NoError(t, err)\n\n\tbucket.addNestedAggregation(\"terms_by_currency\", agg)\n\t_, err = json.Marshal(bucket)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/query.go",
    "content": "package opensearch_query\n\nimport (\n\t\"encoding/json\"\n\t\"time\"\n)\n\ntype query struct {\n\tSize         int                `json:\"size\"`\n\tAggregations aggregationRequest `json:\"aggregations\"`\n\tQuery        interface{}        `json:\"query,omitempty\"`\n}\n\ntype boolQuery struct {\n\tFilterQueryString string\n\tTimestampField    string\n\tTimeRangeFrom     time.Time\n\tTimeRangeTo       time.Time\n\tDateFieldFormat   string\n}\n\n// MarshalJSON customizes the JSON marshaling for boolQuery.\nfunc (b *boolQuery) MarshalJSON() ([]byte, error) {\n\t// Construct range\n\tdateTimeRange := map[string]interface{}{\n\t\t\"from\":          b.TimeRangeFrom,\n\t\t\"to\":            b.TimeRangeTo,\n\t\t\"include_lower\": true,\n\t\t\"include_upper\": true,\n\t}\n\tif b.DateFieldFormat != \"\" {\n\t\tdateTimeRange[\"format\"] = b.DateFieldFormat\n\t}\n\trangeFilter := map[string]map[string]interface{}{\"range\": {b.TimestampField: dateTimeRange}}\n\n\t// Construct Filter\n\tqueryFilter := map[string]map[string]interface{}{\n\t\t\"query_string\": {\"query\": b.FilterQueryString},\n\t}\n\n\t// Construct boolean query\n\tbq := map[string]map[string]interface{}{\"bool\": {\"filter\": []interface{}{rangeFilter, queryFilter}}}\n\n\treturn json.Marshal(&bq)\n}\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/sample.conf",
    "content": "# Derive metrics from aggregating OpenSearch query results\n[[inputs.opensearch_query]]\n  ## OpenSearch cluster endpoint(s). Multiple urls can be specified as part\n  ## of the same cluster.  Only one successful call will be made per interval.\n  urls = [ \"https://node1.os.example.com:9200\" ] # required.\n\n  ## OpenSearch client timeout, defaults to \"5s\".\n  # timeout = \"5s\"\n\n  ## HTTP basic authentication details\n  # username = \"admin\"\n  # password = \"admin\"\n\n  ## Skip TLS validation.  Useful for local testing and self-signed certs.\n  # insecure_skip_verify = false\n\n  [[inputs.opensearch_query.aggregation]]\n    ## measurement name for the results of the aggregation query\n    measurement_name = \"measurement\"\n\n    ## OpenSearch index or index pattern to search\n    index = \"index-*\"\n\n    ## The date/time field in the OpenSearch index (mandatory).\n    date_field = \"@timestamp\"\n\n    ## If the field used for the date/time field in OpenSearch is also using\n    ## a custom date/time format it may be required to provide the format to\n    ## correctly parse the field.\n    ##\n    ## If using one of the built in OpenSearch formats this is not required.\n    ## https://opensearch.org/docs/2.4/opensearch/supported-field-types/date/#built-in-formats\n    # date_field_custom_format = \"\"\n\n    ## Time window to query (eg. \"1m\" to query documents from last minute).\n    ## Normally should be set to same as collection interval\n    query_period = \"1m\"\n\n    ## Lucene query to filter results\n    # filter_query = \"*\"\n\n    ## Fields to aggregate values (must be numeric fields)\n    # metric_fields = [\"metric\"]\n\n    ## Aggregation function to use on the metric fields\n    ## Must be set if 'metric_fields' is set\n    ## Valid values are: avg, sum, min, max, sum\n    # metric_function = \"avg\"\n\n    ## Fields to be used as tags.  Must be text, non-analyzed fields. Metric\n    ## aggregations are performed per tag\n    # tags = [\"field.keyword\", \"field2.keyword\"]\n\n    ## Set to true to not ignore documents when the tag(s) above are missing\n    # include_missing_tag = false\n\n    ## String value of the tag when the tag does not exist\n    ## Required when include_missing_tag is true\n    # missing_tag_value = \"null\"\n"
  },
  {
    "path": "plugins/inputs/opensearch_query/testdata/nginx_logs",
    "content": "93.180.71.3 - - [17/May/2015:08:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 12060\n93.180.71.3 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 12355\n80.91.33.133 - - [17/May/2015:08:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26272\n217.168.17.5 - - [17/May/2015:08:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 1514\n217.168.17.5 - - [17/May/2015:08:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 2204\n93.180.71.3 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 6012\n217.168.17.5 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 11220\n217.168.17.5 - - [17/May/2015:08:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 17843\n80.91.33.133 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 22599\n93.180.71.3 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 24828\n217.168.17.5 - - [17/May/2015:08:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 3316 \"-\" \"-\" 6947\n188.138.60.101 - - [17/May/2015:08:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28288\n80.91.33.133 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23182\n46.4.66.76 - - [17/May/2015:08:05:45 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16302\n93.180.71.3 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16102\n91.234.194.89 - - [17/May/2015:08:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20268\n80.91.33.133 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 2794\n37.26.93.214 - - [17/May/2015:08:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 319 \"-\" \"Go 1.1 package http\" 22809\n188.138.60.101 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8807\n93.180.71.3 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30172\n46.4.66.76 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 1973\n62.75.198.179 - - [17/May/2015:08:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10182\n80.91.33.133 - - [17/May/2015:08:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14307\n173.203.139.108 - - [17/May/2015:08:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10828\n210.245.80.75 - - [17/May/2015:08:05:32 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 21956\n46.4.83.163 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5726\n91.234.194.89 - - [17/May/2015:08:05:18 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10841\n31.22.86.126 - - [17/May/2015:08:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18132\n217.168.17.5 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 3301 \"-\" \"-\" 10094\n80.91.33.133 - - [17/May/2015:08:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12355\n173.203.139.108 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27325\n80.91.33.133 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14101\n5.83.131.103 - - [17/May/2015:08:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20175\n80.91.33.133 - - [17/May/2015:08:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21384\n200.6.73.40 - - [17/May/2015:08:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6570\n80.91.33.133 - - [17/May/2015:08:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26145\n93.180.71.3 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 32705\n62.75.198.179 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18865\n50.57.209.92 - - [17/May/2015:08:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21639\n188.138.60.101 - - [17/May/2015:08:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31242\n46.4.66.76 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 5910\n50.57.209.92 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22900\n91.239.186.133 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23919\n173.203.139.108 - - [17/May/2015:08:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25169\n80.91.33.133 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24395\n93.190.71.150 - - [17/May/2015:08:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25750\n91.234.194.89 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26673\n46.4.83.163 - - [17/May/2015:08:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32509\n173.203.139.108 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32714\n54.187.216.43 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 5016\n50.57.209.92 - - [17/May/2015:08:05:59 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14449\n80.91.33.133 - - [17/May/2015:08:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13183\n173.203.139.108 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 7791\n5.83.131.103 - - [17/May/2015:08:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 586\n173.203.139.108 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5036\n80.91.33.133 - - [17/May/2015:08:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20358\n50.57.209.92 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2106\n80.91.33.133 - - [17/May/2015:08:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9757\n37.26.93.214 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 3318 \"-\" \"Go 1.1 package http\" 6222\n23.23.226.37 - - [17/May/2015:08:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 2578 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 9523\n93.180.71.3 - - [17/May/2015:08:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 7228\n173.203.139.108 - - [17/May/2015:08:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31464\n62.75.198.179 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22462\n31.22.86.126 - - [17/May/2015:08:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29906\n50.57.209.92 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16217\n91.239.186.133 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18335\n46.4.66.76 - - [17/May/2015:08:05:00 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 27375\n200.6.73.40 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32073\n173.203.139.108 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31071\n93.190.71.150 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1200\n91.234.194.89 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13143\n173.203.139.108 - - [17/May/2015:08:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16138\n80.91.33.133 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21432\n217.168.17.5 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 1419\n46.4.83.163 - - [17/May/2015:08:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28449\n80.91.33.133 - - [17/May/2015:08:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25906\n50.57.209.92 - - [17/May/2015:08:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27099\n173.203.139.108 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32238\n188.138.60.101 - - [17/May/2015:08:05:04 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 237\n80.91.33.133 - - [17/May/2015:08:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7103\n134.119.20.172 - - [17/May/2015:08:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5423\n173.203.139.108 - - [17/May/2015:08:05:29 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6373\n80.91.33.133 - - [17/May/2015:08:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22230\n91.121.161.213 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14196\n80.91.33.133 - - [17/May/2015:08:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17820\n80.91.33.133 - - [17/May/2015:08:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9097\n37.26.93.214 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 490 \"-\" \"Go 1.1 package http\" 27632\n5.83.131.103 - - [17/May/2015:08:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14609\n50.57.209.92 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21926\n173.203.139.108 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4915\n54.64.16.235 - - [17/May/2015:08:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 12816\n93.180.71.3 - - [17/May/2015:08:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30742\n202.143.95.26 - - [17/May/2015:08:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24544\n202.143.95.26 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25819\n202.143.95.26 - - [17/May/2015:08:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26831\n80.91.33.133 - - [17/May/2015:08:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 1344\n91.239.186.133 - - [17/May/2015:08:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4987\n173.203.139.108 - - [17/May/2015:08:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 328 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13419\n80.91.33.133 - - [17/May/2015:08:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12879\n87.233.156.242 - - [17/May/2015:08:05:37 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20611\n62.75.198.179 - - [17/May/2015:08:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1387\n50.57.209.92 - - [17/May/2015:08:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31286\n80.91.33.133 - - [17/May/2015:08:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15247\n93.190.71.150 - - [17/May/2015:08:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 134\n46.4.66.76 - - [17/May/2015:08:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 23909\n80.91.33.133 - - [17/May/2015:08:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15771\n91.234.194.89 - - [17/May/2015:08:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4641\n217.168.17.5 - - [17/May/2015:08:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 6382\n46.4.83.163 - - [17/May/2015:08:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14599\n50.57.209.92 - - [17/May/2015:08:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8263\n200.6.73.40 - - [17/May/2015:08:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23514\n91.121.161.213 - - [17/May/2015:08:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29473\n80.91.33.133 - - [17/May/2015:08:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26659\n188.138.60.101 - - [17/May/2015:08:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5147\n144.76.151.58 - - [17/May/2015:08:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21698\n134.119.20.172 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21077\n80.91.33.133 - - [17/May/2015:09:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 7173\n80.91.33.133 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1878\n5.83.131.103 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24451\n93.180.71.3 - - [17/May/2015:09:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 30170\n80.91.33.133 - - [17/May/2015:09:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13156\n50.57.209.92 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 306\n5.83.131.103 - - [17/May/2015:09:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 345 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24862\n62.75.167.106 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10227\n37.26.93.214 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Go 1.1 package http\" 28504\n93.64.134.186 - - [17/May/2015:09:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27681\n87.233.156.242 - - [17/May/2015:09:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 1502\n80.91.33.133 - - [17/May/2015:09:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18177\n80.91.33.133 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7934\n54.193.30.212 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 2\n62.75.198.179 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23920\n91.239.186.133 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9333\n83.161.14.106 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19640\n80.91.33.133 - - [17/May/2015:09:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11061\n80.91.33.133 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 24501\n93.190.71.150 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15895\n50.57.209.92 - - [17/May/2015:09:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20558\n80.91.33.133 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 2338\n80.91.33.133 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12192\n217.168.17.5 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 9824\n80.91.33.133 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2246\n54.191.136.177 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 7239\n80.91.33.133 - - [17/May/2015:09:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 21154\n91.234.194.89 - - [17/May/2015:09:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2966\n80.91.33.133 - - [17/May/2015:09:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 10715\n80.91.33.133 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 14856\n46.4.83.163 - - [17/May/2015:09:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17717\n91.121.161.213 - - [17/May/2015:09:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 346 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9951\n188.138.60.101 - - [17/May/2015:09:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 25787\n144.76.151.58 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4930\n195.154.77.170 - - [17/May/2015:09:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21921\n50.57.209.92 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29773\n31.22.86.126 - - [17/May/2015:09:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7593\n54.64.16.235 - - [17/May/2015:09:05:51 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 26867\n202.143.95.26 - - [17/May/2015:09:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31361\n202.143.95.26 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13167\n87.233.156.242 - - [17/May/2015:09:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22554\n62.75.167.106 - - [17/May/2015:09:05:37 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29795\n152.90.220.17 - - [17/May/2015:09:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18753\n80.91.33.133 - - [17/May/2015:09:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 27083\n93.180.71.3 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 28187\n80.91.33.133 - - [17/May/2015:09:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25595\n5.83.131.103 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 26070\n5.83.131.103 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27724\n200.6.73.40 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8086\n46.4.88.134 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 4853\n50.57.209.92 - - [17/May/2015:09:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9464\n93.64.134.186 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 12194\n80.91.33.133 - - [17/May/2015:09:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 26621\n62.75.198.180 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29857\n80.91.33.133 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 20514\n80.91.33.133 - - [17/May/2015:09:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 5526\n62.75.198.179 - - [17/May/2015:09:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14143\n80.91.33.133 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 20873\n91.239.186.133 - - [17/May/2015:09:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23230\n80.91.33.133 - - [17/May/2015:09:05:25 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25246\n83.161.14.106 - - [17/May/2015:09:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19052\n80.91.33.133 - - [17/May/2015:09:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12362\n195.154.77.170 - - [17/May/2015:09:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10153\n93.190.71.150 - - [17/May/2015:09:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22418\n80.91.33.133 - - [17/May/2015:09:05:43 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 6565\n80.91.33.133 - - [17/May/2015:09:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9883\n144.76.160.62 - - [17/May/2015:09:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 2564\n91.121.161.213 - - [17/May/2015:09:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17140\n46.4.83.163 - - [17/May/2015:09:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22794\n91.234.194.89 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17718\n50.57.209.92 - - [17/May/2015:09:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5434\n188.138.60.101 - - [17/May/2015:09:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 573\n210.245.80.75 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 28482\n144.76.151.58 - - [17/May/2015:09:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31161\n80.91.33.133 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24151\n144.76.117.56 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 6185\n80.91.33.133 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 6276\n31.22.86.126 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 27127\n80.91.33.133 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 9549\n62.75.167.106 - - [17/May/2015:09:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21397\n87.233.156.242 - - [17/May/2015:09:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 10781\n152.90.220.18 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19773\n93.180.71.3 - - [17/May/2015:09:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 11889\n80.91.33.133 - - [17/May/2015:09:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14111\n31.22.86.126 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 319 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17787\n50.57.209.92 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18330\n5.83.131.103 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8993\n46.4.88.134 - - [17/May/2015:09:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17460\n80.91.33.133 - - [17/May/2015:09:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 32412\n80.91.33.133 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12639\n62.75.198.180 - - [17/May/2015:09:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32511\n80.91.33.133 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29012\n80.91.33.133 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9767\n5.83.131.103 - - [17/May/2015:09:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 12212\n5.83.131.103 - - [17/May/2015:09:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2440\n5.83.131.103 - - [17/May/2015:09:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8157\n195.154.77.170 - - [17/May/2015:09:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16242\n202.143.95.26 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22261\n93.64.134.186 - - [17/May/2015:09:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15048\n85.214.47.178 - - [17/May/2015:09:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27105\n83.161.14.106 - - [17/May/2015:09:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 32234\n80.70.214.71 - - [17/May/2015:09:05:20 +0000] \"HEAD /downloads/product_1 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 8479\n87.233.156.242 - - [17/May/2015:09:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20831\n54.64.16.235 - - [17/May/2015:09:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 18289\n50.57.209.92 - - [17/May/2015:09:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9858\n91.239.186.133 - - [17/May/2015:09:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20442\n91.121.161.213 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9004\n200.6.73.40 - - [17/May/2015:09:05:30 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13221\n62.75.198.179 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 954\n93.190.71.150 - - [17/May/2015:09:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26398\n80.91.33.133 - - [17/May/2015:09:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22775\n80.91.33.133 - - [17/May/2015:09:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13886\n80.91.33.133 - - [17/May/2015:09:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19340\n144.76.160.62 - - [17/May/2015:09:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17157\n80.91.33.133 - - [17/May/2015:09:05:59 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9971\n217.168.17.5 - - [17/May/2015:09:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 26268\n80.91.33.133 - - [17/May/2015:09:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 5983\n80.91.33.133 - - [17/May/2015:09:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15296\n144.76.117.56 - - [17/May/2015:09:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 13922\n144.76.151.58 - - [17/May/2015:09:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10692\n80.91.33.133 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 22550\n62.75.167.106 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20757\n80.91.33.133 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25956\n37.187.238.39 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16674\n80.70.214.71 - - [17/May/2015:10:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 327 \"-\" \"Wget/1.13.4 (linux-gnu)\" 15327\n91.234.194.89 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21807\n80.91.33.133 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 20469\n188.138.60.101 - - [17/May/2015:10:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10122\n80.91.33.133 - - [17/May/2015:10:05:01 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1971\n80.91.33.133 - - [17/May/2015:10:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7263\n93.180.71.3 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 953\n46.4.88.134 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 23703\n80.91.33.133 - - [17/May/2015:10:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 126\n62.210.138.59 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 19171\n31.22.86.126 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 335 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31107\n80.91.33.133 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 8252\n54.86.157.236 - - [17/May/2015:10:05:24 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 25651\n195.154.233.202 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 318 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 3446\n54.86.157.236 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 20770\n80.91.33.133 - - [17/May/2015:10:05:14 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27979\n94.23.21.169 - - [17/May/2015:10:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28723\n54.86.157.236 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 13439\n195.154.77.170 - - [17/May/2015:10:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22432\n54.86.157.236 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 1572\n85.214.47.178 - - [17/May/2015:10:05:57 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27196\n5.83.131.103 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9637\n5.83.131.103 - - [17/May/2015:10:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 18830\n5.83.131.103 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 844\n5.83.131.103 - - [17/May/2015:10:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20882\n80.91.33.133 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1325\n80.91.33.133 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11125\n84.53.65.28 - - [17/May/2015:10:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10771\n80.91.33.133 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24891\n54.86.157.236 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23541\n217.168.17.5 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.10.3)\" 22323\n91.121.161.213 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29114\n80.70.214.71 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 329 \"-\" \"Wget/1.13.4 (linux-gnu)\" 13629\n144.76.160.62 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32440\n54.86.157.236 - - [17/May/2015:10:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 20402\n93.64.134.186 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5113\n93.190.71.150 - - [17/May/2015:10:05:41 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 31729\n87.233.156.242 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 28958\n80.91.33.133 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15630\n91.239.186.133 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 7488\n62.75.198.179 - - [17/May/2015:10:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9316\n144.76.117.56 - - [17/May/2015:10:05:46 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9965\n178.32.54.253 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2881\n37.187.238.39 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17544\n83.161.14.106 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11419\n54.86.157.236 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 16406\n91.194.188.90 - - [17/May/2015:10:05:51 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 28324\n83.161.14.106 - - [17/May/2015:10:05:13 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 1893\n80.91.33.133 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14697\n93.180.71.3 - - [17/May/2015:10:05:34 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16168\n62.210.138.59 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 663\n46.4.88.134 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 27962\n202.143.95.26 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18539\n202.143.95.26 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 13495\n202.143.95.26 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3192\n62.75.198.180 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4349\n144.76.137.134 - - [17/May/2015:10:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1395\n80.91.33.133 - - [17/May/2015:10:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12898\n54.86.157.236 - - [17/May/2015:10:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 26930\n80.70.214.71 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 326 \"-\" \"Wget/1.13.4 (linux-gnu)\" 16662\n91.234.194.89 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9445\n188.138.60.101 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18804\n80.91.33.133 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 22429\n195.154.233.202 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 8456\n94.23.21.169 - - [17/May/2015:10:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32187\n144.76.151.58 - - [17/May/2015:10:05:10 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29276\n80.91.33.133 - - [17/May/2015:10:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 9700\n62.75.167.106 - - [17/May/2015:10:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10078\n80.91.33.133 - - [17/May/2015:10:05:41 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7600\n50.57.209.92 - - [17/May/2015:10:05:16 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8540\n202.143.95.26 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24400\n200.6.73.40 - - [17/May/2015:10:05:38 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29363\n195.154.77.170 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17025\n54.187.216.43 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 27997\n80.91.33.133 - - [17/May/2015:10:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 1806\n80.91.33.133 - - [17/May/2015:10:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 28234\n54.86.157.236 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 19286\n202.143.95.26 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 325 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19522\n202.143.95.26 - - [17/May/2015:10:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23841\n54.86.157.236 - - [17/May/2015:10:05:02 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 31135\n80.91.33.133 - - [17/May/2015:10:05:50 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 21510\n80.91.33.133 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26977\n80.91.33.133 - - [17/May/2015:10:05:55 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 1078\n80.91.33.133 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7473\n84.53.65.28 - - [17/May/2015:10:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28347\n92.50.100.22 - - [17/May/2015:10:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8699\n85.214.47.178 - - [17/May/2015:10:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2078\n80.91.33.133 - - [17/May/2015:10:05:08 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 7013\n54.86.157.236 - - [17/May/2015:10:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 29440\n5.83.131.103 - - [17/May/2015:10:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 24206\n37.187.238.39 - - [17/May/2015:10:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 5674\n80.91.33.133 - - [17/May/2015:10:05:04 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 15781\n195.210.47.239 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 1462\n80.91.33.133 - - [17/May/2015:10:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9446\n54.64.16.235 - - [17/May/2015:10:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23687\n178.32.54.253 - - [17/May/2015:10:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17314\n144.92.16.161 - - [17/May/2015:10:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 4021\n54.86.157.236 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 13168\n87.233.156.242 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 8142\n31.22.86.126 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 332 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 28923\n80.91.33.133 - - [17/May/2015:10:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 17021\n91.121.161.213 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 711\n80.91.33.133 - - [17/May/2015:10:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15815\n50.57.209.92 - - [17/May/2015:10:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 12290\n91.239.186.133 - - [17/May/2015:10:05:15 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9172\n144.76.117.56 - - [17/May/2015:10:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 27106\n144.76.160.62 - - [17/May/2015:10:05:47 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 2607\n62.210.138.59 - - [17/May/2015:10:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26922\n54.86.157.236 - - [17/May/2015:10:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 2045\n62.75.198.179 - - [17/May/2015:10:05:14 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14090\n93.190.71.150 - - [17/May/2015:10:05:07 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2233\n144.76.117.56 - - [17/May/2015:10:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14988\n94.23.21.169 - - [17/May/2015:10:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11645\n91.194.188.90 - - [17/May/2015:10:05:05 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 28064\n93.64.134.186 - - [17/May/2015:10:05:51 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16583\n54.86.157.236 - - [17/May/2015:10:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 23208\n80.70.214.71 - - [17/May/2015:10:05:23 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 1059\n93.180.71.3 - - [17/May/2015:10:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 16367\n195.154.233.202 - - [17/May/2015:10:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26788\n193.192.58.163 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6753\n144.76.137.134 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18307\n54.86.157.236 - - [17/May/2015:11:05:22 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 10520\n83.161.14.106 - - [17/May/2015:11:05:09 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 5640\n144.76.151.58 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9992\n144.92.16.161 - - [17/May/2015:11:05:06 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 3262\n195.154.77.170 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 17687\n62.75.198.180 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18911\n91.234.194.89 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22038\n80.91.33.133 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 2238\n188.138.60.101 - - [17/May/2015:11:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10581\n62.75.167.106 - - [17/May/2015:11:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14869\n46.4.88.134 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 6669\n80.91.33.133 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12780\n80.91.33.133 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24133\n84.53.65.28 - - [17/May/2015:11:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 14350\n152.90.220.17 - - [17/May/2015:11:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23513\n80.91.33.133 - - [17/May/2015:11:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31695\n80.91.33.133 - - [17/May/2015:11:05:21 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 12243\n178.32.54.253 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2641\n54.72.39.202 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 951 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 27639\n91.120.61.154 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21180\n37.187.238.39 - - [17/May/2015:11:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 30661\n85.214.47.178 - - [17/May/2015:11:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 20380\n80.91.33.133 - - [17/May/2015:11:05:47 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11957\n5.83.131.103 - - [17/May/2015:11:05:10 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 19230\n200.6.73.40 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4087\n5.83.131.103 - - [17/May/2015:11:05:45 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 16383\n91.121.161.213 - - [17/May/2015:11:05:08 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11487\n91.239.186.133 - - [17/May/2015:11:05:40 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 11774\n50.57.209.92 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28472\n80.91.33.133 - - [17/May/2015:11:05:18 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 24011\n144.92.16.161 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 26633\n87.233.156.242 - - [17/May/2015:11:05:33 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 16170\n94.23.21.169 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 15992\n5.83.131.103 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20999\n80.91.33.133 - - [17/May/2015:11:05:40 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 23097\n202.143.95.26 - - [17/May/2015:11:05:30 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3282\n202.143.95.26 - - [17/May/2015:11:05:44 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 4869\n80.91.33.133 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 9310\n80.91.33.133 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 23547\n80.91.33.133 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 5516\n80.91.33.133 - - [17/May/2015:11:05:13 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 26601\n62.210.138.59 - - [17/May/2015:11:05:23 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 26830\n144.76.160.62 - - [17/May/2015:11:05:06 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 15405\n93.190.71.150 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16982\n80.91.33.133 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 6019\n202.143.95.26 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3822\n193.192.58.163 - - [17/May/2015:11:05:54 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13461\n195.154.233.202 - - [17/May/2015:11:05:46 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32439\n80.70.214.71 - - [17/May/2015:11:05:59 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 31402\n62.75.198.179 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 452\n80.91.33.133 - - [17/May/2015:11:05:51 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25508\n144.92.16.161 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 29252\n195.154.77.170 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19649\n50.57.209.92 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 24457\n144.76.117.56 - - [17/May/2015:11:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 10519\n80.91.33.133 - - [17/May/2015:11:05:36 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 6815\n144.76.137.134 - - [17/May/2015:11:05:07 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 798\n188.138.60.101 - - [17/May/2015:11:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19441\n54.172.198.124 - - [17/May/2015:11:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 200 2582 \"-\" \"urlgrabber/3.9.1 yum/3.4.3\" 17903\n37.187.238.39 - - [17/May/2015:11:05:27 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 3443\n178.32.54.253 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9634\n62.75.198.180 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5417\n62.75.167.106 - - [17/May/2015:11:05:26 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1055\n195.210.47.239 - - [17/May/2015:11:05:36 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 4218\n91.234.194.89 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23355\n31.22.86.126 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 29547\n91.194.188.90 - - [17/May/2015:11:05:42 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Wget/1.13.4 (linux-gnu)\" 26988\n92.50.100.22 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 13600\n144.76.151.58 - - [17/May/2015:11:05:45 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 18988\n93.64.134.186 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2281\n85.214.47.178 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 16054\n94.23.21.169 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 21647\n80.91.33.133 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 31277\n80.91.33.133 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 19500\n91.121.161.213 - - [17/May/2015:11:05:03 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 29579\n83.161.14.106 - - [17/May/2015:11:05:52 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 1080\n54.64.16.235 - - [17/May/2015:11:05:43 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.20.1)\" 15057\n84.53.65.28 - - [17/May/2015:11:05:31 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5805\n80.91.33.133 - - [17/May/2015:11:05:09 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 32764\n50.57.209.92 - - [17/May/2015:11:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 334 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 28248\n91.239.186.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 32046\n144.92.16.161 - - [17/May/2015:11:05:30 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 31342\n62.210.138.59 - - [17/May/2015:11:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22861\n210.245.80.75 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 32649\n80.91.33.133 - - [17/May/2015:11:05:12 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 11268\n83.161.14.106 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8233\n87.233.156.242 - - [17/May/2015:11:05:02 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 10052\n5.83.131.103 - - [17/May/2015:11:05:49 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 20084\n80.91.33.133 - - [17/May/2015:11:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 9007\n91.120.61.154 - - [17/May/2015:11:05:48 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8410\n195.154.233.202 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 20582\n80.91.33.133 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 8327\n193.192.58.163 - - [17/May/2015:11:05:58 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4041\n93.190.71.150 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 26973\n144.76.160.62 - - [17/May/2015:11:05:20 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 24342\n50.57.209.92 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 27744\n62.75.198.179 - - [17/May/2015:11:05:19 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2455\n193.192.59.41 - - [17/May/2015:11:05:55 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 19596\n195.154.77.170 - - [17/May/2015:11:05:35 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23424\n80.91.33.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 4171\n200.6.73.40 - - [17/May/2015:11:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8274\n188.138.60.101 - - [17/May/2015:11:05:56 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2949\n80.91.33.133 - - [17/May/2015:11:05:53 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 5641\n80.91.33.133 - - [17/May/2015:11:05:42 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 28746\n80.91.33.133 - - [17/May/2015:11:05:17 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 18396\n80.91.33.133 - - [17/May/2015:11:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 17638\n80.91.33.133 - - [17/May/2015:11:05:23 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)\" 7865\n144.76.137.134 - - [17/May/2015:11:05:57 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 4280\n80.70.214.71 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Wget/1.13.4 (linux-gnu)\" 32436\n144.76.117.56 - - [17/May/2015:11:05:28 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 30048\n94.23.21.169 - - [17/May/2015:11:05:21 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6186\n198.61.216.151 - - [17/May/2015:11:05:16 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 21567\n80.91.33.133 - - [17/May/2015:11:05:11 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 674\n91.194.188.90 - - [17/May/2015:11:05:32 +0000] \"HEAD /downloads/product_2 HTTP/1.1\" 200 0 \"-\" \"Wget/1.13.4 (linux-gnu)\" 5354\n62.75.198.180 - - [17/May/2015:11:05:39 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 5345\n80.91.33.133 - - [17/May/2015:11:05:52 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 2326\n31.22.86.126 - - [17/May/2015:12:05:15 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 331 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 3114\n84.53.65.28 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 337 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 9036\n144.92.16.161 - - [17/May/2015:12:05:32 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 324 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)\" 9410\n50.57.209.92 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 2039\n5.83.131.103 - - [17/May/2015:12:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 14852\n5.83.131.103 - - [17/May/2015:12:05:27 +0000] \"GET /downloads/product_1 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 71\n62.75.167.106 - - [17/May/2015:12:05:01 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 6439\n178.32.54.253 - - [17/May/2015:12:05:26 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8721\n91.121.161.213 - - [17/May/2015:12:05:00 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 1795\n91.234.194.89 - - [17/May/2015:12:05:11 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 8556\n37.187.238.39 - - [17/May/2015:12:05:29 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 17627\n91.239.186.133 - - [17/May/2015:12:05:38 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 10970\n87.233.156.242 - - [17/May/2015:12:05:34 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 409\n202.143.95.26 - - [17/May/2015:12:05:22 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 10283\n144.76.151.58 - - [17/May/2015:12:05:25 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 333 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 22461\n62.210.138.59 - - [17/May/2015:12:05:12 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 340 \"-\" \"Debian APT-HTTP/1.3 (1.0.1ubuntu2)\" 22736\n80.91.33.133 - - [17/May/2015:12:05:05 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 336 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 21014\n83.161.14.106 - - [17/May/2015:12:05:48 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 18047\n80.91.33.133 - - [17/May/2015:12:05:31 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 341 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 25206\n5.83.131.103 - - [17/May/2015:12:05:21 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 15330\n80.91.33.133 - - [17/May/2015:12:05:54 +0000] \"GET /downloads/product_1 HTTP/1.1\" 404 339 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.16)\" 8763\n198.61.216.151 - - [17/May/2015:12:05:59 +0000] \"GET /downloads/product_2 HTTP/1.1\" 304 0 \"-\" \"Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.22)\" 11132\n195.154.77.170 - - [17/May/2015:12:05:05 +0000] \"GET /downloads/product_2 HTTP/1.1\" 404 338 \"-\" \"Debian APT-HTTP/1.3 (0.9.7.9)\" 23768\n"
  },
  {
    "path": "plugins/inputs/opensmtpd/README.md",
    "content": "# OpenSMTPD Input Plugin\n\nThis plugin gathers statistics from [OpenSMTPD][opensmtp] using the `smtpctl`\nbinary.\n\n> [!NOTE]\n> The `smtpctl` binary must be present on the system and executable by Telegraf.\n> The plugin supports using `sudo` for execution.\n\n⭐ Telegraf v1.5.0\n🏷️ server, network\n💻 all\n\n[opensmtp]: https://www.opensmtpd.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# A plugin to collect stats from Opensmtpd - a validating, recursive, and caching DNS resolver\n [[inputs.opensmtpd]]\n   ## If running as a restricted user you can prepend sudo for additional access:\n   #use_sudo = false\n\n   ## The default location of the smtpctl binary can be overridden with:\n   binary = \"/usr/sbin/smtpctl\"\n\n   # The default timeout of 1s can be overridden with:\n   #timeout = \"1s\"\n```\n\n### Permissions\n\nIt's important to note that this plugin references `smtpctl`, which may require\nadditional permissions to execute successfully. Depending on the user/group\npermissions of the telegraf user executing this plugin, you may need to alter\nthe group membership, set facls, or use sudo.\n\n#### Group membership (recommended)\n\n```bash\n$ groups telegraf\ntelegraf : telegraf\n\n$ usermod -a -G opensmtpd telegraf\n\n$ groups telegraf\ntelegraf : telegraf opensmtpd\n```\n\n#### Sudo privileges\n\nIf you use this method, you will need the following in your telegraf config:\n\n```toml\n[[inputs.opensmtpd]]\n  use_sudo = true\n```\n\nYou will also need to update your sudoers file:\n\n```bash\n$ visudo\n# Add the following line:\nCmnd_Alias SMTPCTL = /usr/sbin/smtpctl\ntelegraf  ALL=(ALL) NOPASSWD: SMTPCTL\nDefaults!SMTPCTL !logfile, !syslog, !pam_session\n```\n\nPlease use the solution you see as most appropriate.\n\n## Metrics\n\nThis is the full list of statistics provided by smtpctl and potentially\ncollected by telegraf depending of your smtpctl configuration.\n\n- smtpctl\n    bounce_envelope\n    bounce_message\n    bounce_session\n    control_session\n    mda_envelope\n    mda_pending\n    mda_running\n    mda_user\n    mta_connector\n    mta_domain\n    mta_envelope\n    mta_host\n    mta_relay\n    mta_route\n    mta_session\n    mta_source\n    mta_task\n    mta_task_running\n    queue_bounce\n    queue_evpcache_load_hit\n    queue_evpcache_size\n    queue_evpcache_update_hit\n    scheduler_delivery_ok\n    scheduler_delivery_permfail\n    scheduler_delivery_tempfail\n    scheduler_envelope\n    scheduler_envelope_expired\n    scheduler_envelope_incoming\n    scheduler_envelope_inflight\n    scheduler_ramqueue_envelope\n    scheduler_ramqueue_message\n    scheduler_ramqueue_update\n    smtp_session\n    smtp_session_inet4\n    smtp_session_local\n    uptime\n\n## Example Output\n\n```text\nopensmtpd,host=localhost scheduler_delivery_tempfail=822,mta_host=10,mta_task_running=4,queue_bounce=13017,scheduler_delivery_permfail=51022,mta_relay=7,queue_evpcache_size=2,scheduler_envelope_expired=26,bounce_message=0,mta_domain=7,queue_evpcache_update_hit=848,smtp_session_local=12294,bounce_envelope=0,queue_evpcache_load_hit=4389703,scheduler_ramqueue_update=0,mta_route=3,scheduler_delivery_ok=2149489,smtp_session_inet4=2131997,control_session=1,scheduler_envelope_incoming=0,uptime=10346728,scheduler_ramqueue_envelope=2,smtp_session=0,bounce_session=0,mta_envelope=2,mta_session=6,mta_task=2,scheduler_ramqueue_message=2,mta_connector=7,mta_source=1,scheduler_envelope=2,scheduler_envelope_inflight=2 1510220300000000000\n```\n"
  },
  {
    "path": "plugins/inputs/opensmtpd/opensmtpd.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage opensmtpd\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tdefaultBinary  = \"/usr/sbin/smtpctl\"\n\tdefaultTimeout = config.Duration(time.Second)\n)\n\ntype Opensmtpd struct {\n\tBinary  string          `toml:\"binary\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tUseSudo bool            `toml:\"use_sudo\"`\n\n\trun runner\n}\n\ntype runner func(cmdName string, timeout config.Duration, useSudo bool) (*bytes.Buffer, error)\n\nfunc (*Opensmtpd) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Opensmtpd) Gather(acc telegraf.Accumulator) error {\n\t// All the dots in stat name will be replaced by underscores.\n\t// Histogram statistics will not be collected.\n\n\t// Always exclude uptime.human statistics\n\tstatExcluded := []string{\"uptime.human\"}\n\tfilterExcluded, err := filter.Compile(statExcluded)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tout, err := s.run(s.Binary, s.Timeout, s.UseSudo)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error gathering metrics: %w\", err)\n\t}\n\n\t// Process values\n\tfields := make(map[string]interface{})\n\tscanner := bufio.NewScanner(out)\n\tfor scanner.Scan() {\n\t\tcols := strings.Split(scanner.Text(), \"=\")\n\n\t\t// Check split correctness\n\t\tif len(cols) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tstat := cols[0]\n\t\tvalue := cols[1]\n\n\t\t// Filter value\n\t\tif filterExcluded.Match(stat) {\n\t\t\tcontinue\n\t\t}\n\n\t\tfield := strings.ReplaceAll(stat, \".\", \"_\")\n\n\t\tfields[field], err = strconv.ParseFloat(value, 64)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"expected a numerical value for %s = %v\", stat, value))\n\t\t}\n\t}\n\n\tacc.AddFields(\"opensmtpd\", fields, nil)\n\n\treturn nil\n}\n\n// Shell out to opensmtpd_stat and return the output\nfunc opensmtpdRunner(cmdName string, timeout config.Duration, useSudo bool) (*bytes.Buffer, error) {\n\tcmdArgs := []string{\"show\", \"stats\"}\n\n\tcmd := exec.Command(cmdName, cmdArgs...)\n\n\tif useSudo {\n\t\tcmdArgs = append([]string{cmdName}, cmdArgs...)\n\t\tcmd = exec.Command(\"sudo\", cmdArgs...)\n\t}\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn &out, fmt.Errorf(\"error running smtpctl: %w\", err)\n\t}\n\n\treturn &out, nil\n}\n\nfunc init() {\n\tinputs.Add(\"opensmtpd\", func() telegraf.Input {\n\t\treturn &Opensmtpd{\n\t\t\trun:     opensmtpdRunner,\n\t\t\tBinary:  defaultBinary,\n\t\t\tTimeout: defaultTimeout,\n\t\t\tUseSudo: false,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/opensmtpd/opensmtpd_test.go",
    "content": "package opensmtpd\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc smtpCTL(output string) func(string, config.Duration, bool) (*bytes.Buffer, error) {\n\treturn func(string, config.Duration, bool) (*bytes.Buffer, error) {\n\t\treturn bytes.NewBufferString(output), nil\n\t}\n}\n\nfunc TestFilterSomeStats(t *testing.T) {\n\tacc := &testutil.Accumulator{}\n\tv := &Opensmtpd{\n\t\trun: smtpCTL(fullOutput),\n\t}\n\terr := v.Gather(acc)\n\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"opensmtpd\"))\n\trequire.Equal(t, uint64(1), acc.NMetrics())\n\n\trequire.Equal(t, 36, acc.NFields())\n\tacc.AssertContainsFields(t, \"opensmtpd\", parsedFullOutput)\n}\n\nvar parsedFullOutput = map[string]interface{}{\n\t\"bounce_envelope\":             float64(0),\n\t\"bounce_message\":              float64(0),\n\t\"bounce_session\":              float64(0),\n\t\"control_session\":             float64(1),\n\t\"mda_envelope\":                float64(0),\n\t\"mda_pending\":                 float64(0),\n\t\"mda_running\":                 float64(0),\n\t\"mda_user\":                    float64(0),\n\t\"mta_connector\":               float64(1),\n\t\"mta_domain\":                  float64(1),\n\t\"mta_envelope\":                float64(0),\n\t\"mta_host\":                    float64(6),\n\t\"mta_relay\":                   float64(1),\n\t\"mta_route\":                   float64(1),\n\t\"mta_session\":                 float64(1),\n\t\"mta_source\":                  float64(1),\n\t\"mta_task\":                    float64(0),\n\t\"mta_task_running\":            float64(5),\n\t\"queue_bounce\":                float64(11495),\n\t\"queue_evpcache_load_hit\":     float64(3927539),\n\t\"queue_evpcache_size\":         float64(0),\n\t\"queue_evpcache_update_hit\":   float64(508),\n\t\"scheduler_delivery_ok\":       float64(1922951),\n\t\"scheduler_delivery_permfail\": float64(45967),\n\t\"scheduler_delivery_tempfail\": float64(493),\n\t\"scheduler_envelope\":          float64(0),\n\t\"scheduler_envelope_expired\":  float64(17),\n\t\"scheduler_envelope_incoming\": float64(0),\n\t\"scheduler_envelope_inflight\": float64(0),\n\t\"scheduler_ramqueue_envelope\": float64(0),\n\t\"scheduler_ramqueue_message\":  float64(0),\n\t\"scheduler_ramqueue_update\":   float64(0),\n\t\"smtp_session\":                float64(0),\n\t\"smtp_session_inet4\":          float64(1903412),\n\t\"smtp_session_local\":          float64(10827),\n\t\"uptime\":                      float64(9253995),\n}\n\nvar fullOutput = `bounce.envelope=0\nbounce.message=0\nbounce.session=0\ncontrol.session=1\nmda.envelope=0\nmda.pending=0\nmda.running=0\nmda.user=0\nmta.connector=1\nmta.domain=1\nmta.envelope=0\nmta.host=6\nmta.relay=1\nmta.route=1\nmta.session=1\nmta.source=1\nmta.task=0\nmta.task.running=5\nqueue.bounce=11495\nqueue.evpcache.load.hit=3927539\nqueue.evpcache.size=0\nqueue.evpcache.update.hit=508\nscheduler.delivery.ok=1922951\nscheduler.delivery.permfail=45967\nscheduler.delivery.tempfail=493\nscheduler.envelope=0\nscheduler.envelope.expired=17\nscheduler.envelope.incoming=0\nscheduler.envelope.inflight=0\nscheduler.ramqueue.envelope=0\nscheduler.ramqueue.message=0\nscheduler.ramqueue.update=0\nsmtp.session=0\nsmtp.session.inet4=1903412\nsmtp.session.local=10827\nuptime=9253995\nuptime.human=107d2h33m15s`\n"
  },
  {
    "path": "plugins/inputs/opensmtpd/sample.conf",
    "content": "# A plugin to collect stats from Opensmtpd - a validating, recursive, and caching DNS resolver\n [[inputs.opensmtpd]]\n   ## If running as a restricted user you can prepend sudo for additional access:\n   #use_sudo = false\n\n   ## The default location of the smtpctl binary can be overridden with:\n   binary = \"/usr/sbin/smtpctl\"\n\n   # The default timeout of 1s can be overridden with:\n   #timeout = \"1s\"\n"
  },
  {
    "path": "plugins/inputs/openstack/README.md",
    "content": "# OpenStack Input Plugin\n\nThis plugin collects metrics about services from [OpenStack][openstack]\nendpoints.\n\n> [!CAUTION]\n> Due to the large number of unique tags generated by the plugin it is\n> **highly recommended** to use [metric filtering][metric_filtering] like\n> `taginclude` and `tagexclude` to reduce cardinality.\n\n⭐ Telegraf v1.21.0\n🏷️ server, cloud\n💻 all\n\n[openstack]: https://www.openstack.org/\n[metric_filtering]: /docs/CONFIGURATION.md#modifiers\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Collects performance metrics from OpenStack services\n[[inputs.openstack]]\n  ## The recommended interval to poll is '30m'\n\n  ## The identity endpoint to authenticate against and get the service catalog from.\n  authentication_endpoint = \"https://my.openstack.cloud:5000\"\n\n  ## The domain to authenticate against when using a V3 identity endpoint.\n  # domain = \"default\"\n\n  ## The project to authenticate as.\n  # project = \"admin\"\n\n  ## User authentication credentials. Must have admin rights.\n  username = \"admin\"\n  password = \"password\"\n\n  ## Available services are:\n  ## \"agents\", \"aggregates\", \"cinder_services\", \"flavors\", \"hypervisors\",\n  ## \"networks\", \"nova_services\", \"ports\", \"projects\", \"servers\",\n  ## \"serverdiagnostics\", \"services\", \"stacks\", \"storage_pools\", \"subnets\",\n  ## \"volumes\"\n  # enabled_services = [\"services\", \"projects\", \"hypervisors\", \"flavors\", \"networks\", \"volumes\"]\n\n  ## Query all instances of all tenants for the volumes and server services\n  ## NOTE: Usually this is only permitted for administrators!\n  # query_all_tenants = true\n\n  ## output secrets (such as adminPass(for server) and UserID(for volume)).\n  # output_secrets = false\n\n  ## Amount of time allowed to complete the HTTP(s) request.\n  # timeout = \"5s\"\n\n  ## HTTP Proxy support\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Options for tags received from Openstack\n  # tag_prefix = \"openstack_tag_\"\n  # tag_value = \"true\"\n\n  ## Timestamp format for timestamp data received from Openstack.\n  ## If false format is unix nanoseconds.\n  # human_readable_timestamps = false\n\n  ## Measure Openstack call duration\n  # measure_openstack_requests = false\n```\n\n### Available services to collect\n\nThis plugin allows to collects metrics from following services:\n\n- CINDER(Block Storage)\n- GLANCE(Image service)\n- HEAT(Orchestration)\n- KEYSTONE(Identity service)\n- NEUTRON(Networking)\n- NOVA(Compute Service)\n\n### API requirements\n\nAt present this plugin requires the following APIs:\n\n- blockstorage  v3\n- compute  v2\n- identity  v3\n- networking  v2\n- orchestration  v1\n\n### Recommendations\n\nDue to the large number of unique tags generated by the plugin it is\n**highly recommended** to use [metric filtering][metric_filtering] like\n`taginclude` and `tagexclude` to reduce cardinality.\n\nFor deployments with only a small number of VMs and hosts, a small polling\ninterval (e.g. seconds-minutes) is acceptable. For larger deployments, polling a\nlarge number of systems will impact performance. Use the `interval` option to\nchange how often the plugin is run.\n\nAlso, consider polling OpenStack services at different intervals depending on\nyour requirements. This will help with load and cardinality as well.\n\n```toml\n[[inputs.openstack]]\n  interval = \"5m\"\n  ....\n  authentication_endpoint = \"https://my.openstack.cloud:5000\"\n  ...\n  enabled_services = [\"nova_services\"]\n  ....\n\n[[inputs.openstack]]\n  interval = \"30m\"\n  ....\n  authentication_endpoint = \"https://my.openstack.cloud:5000\"\n  ...\n  enabled_services = [\"services\", \"projects\", \"hypervisors\", \"flavors\", \"networks\", \"volumes\"]\n  ....\n```\n\n## Metrics\n\n- openstack_aggregate\n  - name\n  - aggregate_host  [string]\n  - aggregate_hosts  [integer]\n  - created_at  [string]\n  - deleted  [boolean]\n  - deleted_at  [string]\n  - id  [integer]\n  - updated_at  [string]\n- openstack_flavor\n  - is_public\n  - name\n  - disk  [integer]\n  - ephemeral  [integer]\n  - id  [string]\n  - ram  [integer]\n  - rxtx_factor  [float]\n  - swap  [integer]\n  - vcpus  [integer]\n- openstack_hypervisor\n  - cpu_arch\n  - cpu_feature_tsc\n  - cpu_feature_tsc-deadline\n  - cpu_feature_tsc_adjust\n  - cpu_feature_tsx-ctrl\n  - cpu_feature_vme\n  - cpu_feature_vmx\n  - cpu_feature_x2apic\n  - cpu_feature_xgetbv1\n  - cpu_feature_xsave\n  - cpu_model\n  - cpu_vendor\n  - hypervisor_hostname\n  - hypervisor_type\n  - hypervisor_version\n  - service_host\n  - service_id\n  - state\n  - status\n  - cpu_topology_cores  [integer]\n  - cpu_topology_sockets  [integer]\n  - cpu_topology_threads  [integer]\n  - current_workload  [integer]\n  - disk_available_least  [integer]\n  - free_disk_gb  [integer]\n  - free_ram_mb  [integer]\n  - host_ip  [string]\n  - id  [string]\n  - local_gb  [integer]\n  - local_gb_used  [integer]\n  - memory_mb  [integer]\n  - memory_mb_used  [integer]\n  - running_vms  [integer]\n  - vcpus  [integer]\n  - vcpus_used  [integer]\n- openstack_identity\n  - description\n  - domain_id\n  - name\n  - parent_id\n  - enabled   boolean\n  - id        string\n  - is_domain boolean\n  - projects  integer\n- openstack_network\n  - name\n  - openstack_tags_xyz\n  - project_id\n  - status\n  - tenant_id\n  - admin_state_up  [boolean]\n  - availability_zone_hints  [string]\n  - created_at  [string]\n  - id  [string]\n  - shared  [boolean]\n  - subnet_id  [string]\n  - subnets  [integer]\n  - updated_at  [string]\n- openstack_neutron_agent\n  - agent_host\n  - agent_type\n  - availability_zone\n  - binary\n  - topic\n  - admin_state_up  [boolean]\n  - alive  [boolean]\n  - created_at  [string]\n  - heartbeat_timestamp  [string]\n  - id  [string]\n  - resources_synced  [boolean]\n  - started_at  [string]\n- openstack_nova_service\n  - host_machine\n  - name\n  - state\n  - status\n  - zone\n  - disabled_reason  [string]\n  - forced_down  [boolean]\n  - id  [string]\n  - updated_at  [string]\n- openstack_port\n  - device_id\n  - device_owner\n  - name\n  - network_id\n  - project_id\n  - status\n  - tenant_id\n  - admin_state_up  [boolean]\n  - allowed_address_pairs  [integer]\n  - fixed_ips  [integer]\n  - id  [string]\n  - ip_address  [string]\n  - mac_address  [string]\n  - security_groups  [string]\n  - subnet_id  [string]\n- openstack_request_duration\n  - agents  [integer]\n  - aggregates  [integer]\n  - flavors  [integer]\n  - hypervisors  [integer]\n  - networks  [integer]\n  - nova_services  [integer]\n  - ports  [integer]\n  - projects  [integer]\n  - servers  [integer]\n  - stacks  [integer]\n  - storage_pools  [integer]\n  - subnets  [integer]\n  - volumes  [integer]\n- openstack_server\n  - flavor\n  - host_id\n  - host_name\n  - image\n  - key_name\n  - name\n  - project\n  - status\n  - tenant_id\n  - user_id\n  - accessIPv4  [string]\n  - accessIPv6  [string]\n  - addresses  [integer]\n  - adminPass  [string]\n  - created  [string]\n  - disk_gb  [integer]\n  - fault_code  [integer]\n  - fault_created  [string]\n  - fault_details  [string]\n  - fault_message  [string]\n  - id  [string]\n  - progress  [integer]\n  - ram_mb  [integer]\n  - security_groups  [integer]\n  - updated  [string]\n  - vcpus  [integer]\n  - volume_id  [string]\n  - volumes_attached  [integer]\n- openstack_server_diagnostics\n  - disk_name\n  - no_of_disks\n  - no_of_ports\n  - port_name\n  - server_id\n  - cpu0_time  [float]\n  - cpu1_time  [float]\n  - cpu2_time  [float]\n  - cpu3_time  [float]\n  - cpu4_time  [float]\n  - cpu5_time  [float]\n  - cpu6_time  [float]\n  - cpu7_time  [float]\n  - disk_errors  [float]\n  - disk_read  [float]\n  - disk_read_req  [float]\n  - disk_write  [float]\n  - disk_write_req  [float]\n  - memory  [float]\n  - memory-actual  [float]\n  - memory-rss  [float]\n  - memory-swap_in  [float]\n  - port_rx  [float]\n  - port_rx_drop  [float]\n  - port_rx_errors  [float]\n  - port_rx_packets  [float]\n  - port_tx  [float]\n  - port_tx_drop  [float]\n  - port_tx_errors  [float]\n  - port_tx_packets  [float]\n- openstack_service\n  - name\n  - service_enabled  [boolean]\n  - service_id  [string]\n- openstack_storage_pool\n  - driver_version\n  - name\n  - storage_protocol\n  - vendor_name\n  - volume_backend_name\n  - free_capacity_gb  [float]\n  - total_capacity_gb  [float]\n- openstack_subnet\n  - cidr\n  - gateway_ip\n  - ip_version\n  - name\n  - network_id\n  - openstack_tags_subnet_type_PRV\n  - project_id\n  - tenant_id\n  - allocation_pools  [string]\n  - dhcp_enabled  [boolean]\n  - dns_nameservers  [string]\n  - id  [string]\n- openstack_volume\n  - attachment_attachment_id\n  - attachment_device\n  - attachment_host_name\n  - availability_zone\n  - bootable\n  - description\n  - name\n  - status\n  - user_id\n  - volume_type\n  - attachment_attached_at  [string]\n  - attachment_server_id  [string]\n  - created_at  [string]\n  - encrypted  [boolean]\n  - id  [string]\n  - multiattach  [boolean]\n  - size  [integer]\n  - total_attachments  [integer]\n  - updated_at  [string]\n\n## Example Output\n\n```text\nopenstack_neutron_agent,agent_host=vim2,agent_type=DHCP\\ agent,availability_zone=nova,binary=neutron-dhcp-agent,host=telegraf_host,topic=dhcp_agent admin_state_up=true,alive=true,created_at=\"2021-01-07T03:40:53Z\",heartbeat_timestamp=\"2021-10-14T07:46:40Z\",id=\"17e1e446-d7da-4656-9e32-67d3690a306f\",resources_synced=false,started_at=\"2021-07-02T21:47:42Z\" 1634197616000000000\nopenstack_aggregate,host=telegraf_host,name=non-dpdk aggregate_host=\"vim3\",aggregate_hosts=2i,created_at=\"2021-02-01T18:28:00Z\",deleted=false,deleted_at=\"0001-01-01T00:00:00Z\",id=3i,updated_at=\"0001-01-01T00:00:00Z\" 1634197617000000000\nopenstack_flavor,host=telegraf_host,is_public=true,name=hwflavor disk=20i,ephemeral=0i,id=\"f89785c0-6b9f-47f5-a02e-f0fcbb223163\",ram=8192i,rxtx_factor=1,swap=0i,vcpus=8i 1634197617000000000\nopenstack_hypervisor,cpu_arch=x86_64,cpu_feature_3dnowprefetch=true,cpu_feature_abm=true,cpu_feature_acpi=true,cpu_feature_adx=true,cpu_feature_aes=true,cpu_feature_apic=true,cpu_feature_xtpr=true,cpu_model=C-Server,cpu_vendor=xyz,host=telegraf_host,hypervisor_hostname=vim3,hypervisor_type=QEMU,hypervisor_version=4002000,service_host=vim3,service_id=192,state=up,status=enabled cpu_topology_cores=28i,cpu_topology_sockets=1i,cpu_topology_threads=2i,current_workload=0i,disk_available_least=2596i,free_disk_gb=2744i,free_ram_mb=374092i,host_ip=\"xx:xx:xx:x::xxx\",id=\"12\",local_gb=3366i,local_gb_used=622i,memory_mb=515404i,memory_mb_used=141312i,running_vms=15i,vcpus=0i,vcpus_used=72i 1634197618000000000\nopenstack_network,host=telegraf_host,name=Network\\ 2,project_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,status=active,tenant_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx admin_state_up=true,availability_zone_hints=\"\",created_at=\"2021-07-29T15:58:25Z\",id=\"f5af5e71-e890-4245-a377-d4d86273c319\",shared=false,subnet_id=\"2f7341c6-074d-42aa-9abc-71c662d9b336\",subnets=1i,updated_at=\"2021-09-02T16:46:48Z\" 1634197618000000000\nopenstack_nova_service,host=telegraf_host,host_machine=vim3,name=nova-compute,state=up,status=enabled,zone=nova disabled_reason=\"\",forced_down=false,id=\"192\",updated_at=\"2021-10-14T07:46:52Z\" 1634197619000000000\nopenstack_port,device_id=a043b8b3-2831-462a-bba8-19088f3db45a,device_owner=compute:nova,host=telegraf_host,name=offload-port1,network_id=6b40d744-9a48-43f2-a4c8-2e0ccb45ac96,project_id=71f9bc44621234f8af99a3949258fc7b,status=ACTIVE,tenant_id=71f9bc44621234f8af99a3949258fc7b admin_state_up=true,allowed_address_pairs=0i,fixed_ips=1i,id=\"fb64626a-07e1-4d78-a70d-900e989537cc\",ip_address=\"1.1.1.5\",mac_address=\"xx:xx:xx:xx:xx:xx\",security_groups=\"\",subnet_id=\"eafa1eca-b318-4746-a55a-682478466689\" 1634197620000000000\nopenstack_identity,domain_id=default,host=telegraf_host,name=service,parent_id=default enabled=true,id=\"a0877dd2ed1d4b5f952f5689bc04b0cb\",is_domain=false,projects=7i 1634197621000000000\nopenstack_server,flavor=0d438971-56cf-4f86-801f-7b04b29384cb,host=telegraf_host,host_id=c0fe05b14261d35cf8748a3f5aae1234b88c2fd62b69fe24ca4a27e9,host_name=vim1,image=b295f1f3-1w23-470c-8734-197676eedd16,name=test-VM7,project=admin,status=active,tenant_id=80ac889731f540498fb1dc78e4bcd5ed,user_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx accessIPv4=\"\",accessIPv6=\"\",addresses=1i,adminPass=\"\",created=\"2021-09-07T14:40:11Z\",disk_gb=8i,fault_code=0i,fault_created=\"0001-01-01T00:00:00Z\",fault_details=\"\",fault_message=\"\",id=\"db92ee0d-459b-458e-9fe3-2be5ec7c87e1\",progress=0i,ram_mb=16384i,security_groups=1i,updated=\"2021-09-07T14:40:19Z\",vcpus=4i,volumes_attached=0i 1634197656000000000\nopenstack_service,host=telegraf_host,name=identity service_enabled=true,service_id=\"ad605eff92444a158d0f78768f2c4668\" 1634197656000000000\nopenstack_storage_pool,driver_version=1.0.0,host=telegraf_host,name=storage_bloack_1,storage_protocol=nfs,vendor_name=xyz,volume_backend_name=abc free_capacity_gb=4847.54,total_capacity_gb=4864 1634197658000000000\nopenstack_subnet,cidr=10.10.20.10/28,gateway_ip=10.10.20.17,host=telegraf_host,ip_version=4,name=IPv4_Subnet_2,network_id=73c6e1d3-f522-4a3f-8e3c-762a0c06d68b,openstack_tags_lab=True,project_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,tenant_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx allocation_pools=\"10.10.20.11-10.10.20.30\",dhcp_enabled=true,dns_nameservers=\"\",id=\"db69fbb2-9ca1-4370-8c78-82a27951c94b\" 1634197660000000000\nopenstack_volume,attachment_attachment_id=c83ca0d6-c467-44a0-ac1f-f87d769c0c65,attachment_device=/dev/vda,attachment_host_name=vim1,availability_zone=nova,bootable=true,host=telegraf_host,status=in-use,user_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,volume_type=storage_bloack_1 attachment_attached_at=\"2021-01-12T21:02:04Z\",attachment_server_id=\"c0c6b4af-0d26-4a0b-a6b4-4ea41fa3bb4a\",created_at=\"2021-01-12T21:01:47Z\",encrypted=false,id=\"d4204f1b-b1ae-1233-b25c-a57d91d2846e\",multiattach=false,size=80i,total_attachments=1i,updated_at=\"2021-01-12T21:02:04Z\" 1634197660000000000\nopenstack_request_duration,host=telegraf_host networks=703214354i 1634197660000000000\nopenstack_server_diagnostics,disk_name=vda,host=telegraf_host,no_of_disks=1,no_of_ports=2,port_name=vhu1234566c-9c,server_id=fdddb58c-bbb9-1234-894b-7ae140178909 cpu0_time=4924220000000,cpu1_time=218809610000000,cpu2_time=218624300000000,cpu3_time=220505700000000,disk_errors=-1,disk_read=619156992,disk_read_req=35423,disk_write=8432728064,disk_write_req=882445,memory=8388608,memory-actual=8388608,memory-rss=37276,memory-swap_in=0,port_rx=410516469288,port_rx_drop=13373626,port_rx_errors=-1,port_rx_packets=52140392,port_tx=417312195654,port_tx_drop=0,port_tx_errors=0,port_tx_packets=321385978 1634197660000000000\n```\n"
  },
  {
    "path": "plugins/inputs/openstack/openstack.go",
    "content": "// Package openstack implements an OpenStack input plugin for Telegraf\n//\n// The OpenStack input plug is a simple two phase metric collector.  In the first\n// pass a set of gatherers are run against the API to cache collections of resources.\n// In the second phase the gathered resources are combined and emitted as metrics.\n//\n// No aggregation is performed by the input plugin, instead queries to InfluxDB should\n// be used to gather global totals of things such as tag frequency.\n//\n//go:generate ../../../tools/readme_config_includer/generator\npackage openstack\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gophercloud/gophercloud/v2\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/schedulerstats\"\n\tcinder_services \"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/services\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/diagnostics\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers\"\n\tnova_services \"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/services\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/projects\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/services\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/agents\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets\"\n\t\"github.com/gophercloud/gophercloud/v2/openstack/orchestration/v1/stacks\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\ttypePort    = regexp.MustCompile(`_rx$|_rx_drop$|_rx_errors$|_rx_packets$|_tx$|_tx_drop$|_tx_errors$|_tx_packets$`)\n\ttypeCPU     = regexp.MustCompile(`cpu[0-9]{1,2}_time$`)\n\ttypeStorage = regexp.MustCompile(`_errors$|_read$|_read_req$|_write$|_write_req$`)\n)\n\ntype OpenStack struct {\n\t// Configuration variables\n\tIdentityEndpoint string          `toml:\"authentication_endpoint\"`\n\tDomain           string          `toml:\"domain\"`\n\tProject          string          `toml:\"project\"`\n\tUsername         string          `toml:\"username\"`\n\tPassword         string          `toml:\"password\"`\n\tEnabledServices  []string        `toml:\"enabled_services\"`\n\tServerDiagnotics bool            `toml:\"server_diagnotics\" deprecated:\"1.32.0;1.40.0;add 'serverdiagnostics' to 'enabled_services' instead\"`\n\tOutputSecrets    bool            `toml:\"output_secrets\"`\n\tTagPrefix        string          `toml:\"tag_prefix\"`\n\tTagValue         string          `toml:\"tag_value\"`\n\tHumanReadableTS  bool            `toml:\"human_readable_timestamps\"`\n\tMeasureRequest   bool            `toml:\"measure_openstack_requests\"`\n\tAllTenants       bool            `toml:\"query_all_tenants\"`\n\tLog              telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient *http.Client\n\n\t// Locally cached clients\n\tidentity *gophercloud.ServiceClient\n\tcompute  *gophercloud.ServiceClient\n\tvolume   *gophercloud.ServiceClient\n\tnetwork  *gophercloud.ServiceClient\n\tstack    *gophercloud.ServiceClient\n\n\t// Locally cached resources\n\topenstackFlavors  map[string]flavors.Flavor\n\topenstackProjects map[string]projects.Project\n\topenstackServices map[string]services.Service\n\n\tservices map[string]bool\n}\n\nfunc (*OpenStack) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *OpenStack) Init() error {\n\tif len(o.EnabledServices) == 0 {\n\t\to.EnabledServices = []string{\"services\", \"projects\", \"hypervisors\", \"flavors\", \"networks\", \"volumes\"}\n\t}\n\tsort.Strings(o.EnabledServices)\n\tif o.Username == \"\" || o.Password == \"\" {\n\t\treturn errors.New(\"username or password can not be empty string\")\n\t}\n\tif o.TagValue == \"\" {\n\t\treturn errors.New(\"tag_value option can not be empty string\")\n\t}\n\n\t// For backward compatibility\n\tif o.ServerDiagnotics && !slices.Contains(o.EnabledServices, \"serverdiagnostics\") {\n\t\to.EnabledServices = append(o.EnabledServices, \"serverdiagnostics\")\n\t}\n\n\t// Check the enabled services\n\to.services = make(map[string]bool, len(o.EnabledServices))\n\tfor _, service := range o.EnabledServices {\n\t\tswitch service {\n\t\tcase \"agents\", \"aggregates\", \"cinder_services\", \"flavors\", \"hypervisors\",\n\t\t\t\"networks\", \"nova_services\", \"ports\", \"projects\", \"servers\",\n\t\t\t\"serverdiagnostics\", \"services\", \"stacks\", \"storage_pools\",\n\t\t\t\"subnets\", \"volumes\":\n\t\t\to.services[service] = true\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid service %q\", service)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpenStack) Start(telegraf.Accumulator) error {\n\t// Authenticate against Keystone and get a token provider\n\tprovider, err := openstack.NewClient(o.IdentityEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create client for OpenStack endpoint: %w\", err)\n\t}\n\n\tctx := context.Background()\n\tclient, err := o.HTTPClientConfig.CreateClient(ctx, o.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to.client = client\n\tprovider.HTTPClient = *o.client\n\n\t// Authenticate to the endpoint\n\tauthOption := gophercloud.AuthOptions{\n\t\tIdentityEndpoint: o.IdentityEndpoint,\n\t\tDomainName:       o.Domain,\n\t\tTenantName:       o.Project,\n\t\tUsername:         o.Username,\n\t\tPassword:         o.Password,\n\t\tAllowReauth:      true,\n\t}\n\tif err := openstack.Authenticate(ctx, provider, authOption); err != nil {\n\t\treturn fmt.Errorf(\"unable to authenticate OpenStack user: %w\", err)\n\t}\n\n\t// Create required clients and attach to the OpenStack struct\n\to.identity, err = openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create V3 identity client: %w\", err)\n\t}\n\to.compute, err = openstack.NewComputeV2(provider, gophercloud.EndpointOpts{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create V2 compute client: %w\", err)\n\t}\n\to.network, err = openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create V2 network client: %w\", err)\n\t}\n\n\t// Check if we got a v3 authentication as we can skip the service listing\n\t// in this case and extract the services from the authentication response.\n\t// Otherwise we are falling back to the \"services\" API.\n\tif success, err := o.availableServicesFromAuth(provider); !success || err != nil {\n\t\tif err != nil {\n\t\t\to.Log.Warnf(\"failed to get services from v3 authentication: %v; falling back to services API\", err)\n\t\t}\n\t\t// Determine the services available at the endpoint\n\t\tif err := o.availableServices(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get resource openstack services: %w\", err)\n\t\t}\n\t}\n\n\t// Setup the optional services\n\tvar hasOrchestration bool\n\tvar hasBlockStorage bool\n\tfor _, available := range o.openstackServices {\n\t\tswitch available.Type {\n\t\tcase \"orchestration\":\n\t\t\to.stack, err = openstack.NewOrchestrationV1(provider, gophercloud.EndpointOpts{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to create V1 stack client: %w\", err)\n\t\t\t}\n\t\t\thasOrchestration = true\n\t\tcase \"volumev3\":\n\t\t\to.volume, err = openstack.NewBlockStorageV3(provider, gophercloud.EndpointOpts{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to create V3 volume client: %w\", err)\n\t\t\t}\n\t\t\thasBlockStorage = true\n\t\t}\n\t}\n\n\t// Check if we need to disable services that are enabled by the user\n\tif !hasOrchestration {\n\t\tif o.services[\"stacks\"] {\n\t\t\to.Log.Warn(\"Disabling \\\"stacks\\\" service because orchestration is not available at the endpoint!\")\n\t\t\tdelete(o.services, \"stacks\")\n\t\t}\n\t}\n\tif !hasBlockStorage {\n\t\tfor _, s := range []string{\"cinder_services\", \"storage_pools\", \"volumes\"} {\n\t\t\tif o.services[s] {\n\t\t\t\to.Log.Warnf(\"Disabling %q service because block-storage is not available at the endpoint!\", s)\n\t\t\t\tdelete(o.services, s)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Prepare cross-dependency information\n\to.openstackFlavors = make(map[string]flavors.Flavor)\n\to.openstackProjects = make(map[string]projects.Project)\n\tif slices.Contains(o.EnabledServices, \"servers\") {\n\t\t// We need the flavors to output machine details for servers\n\t\tpage, err := flavors.ListDetail(o.compute, nil).AllPages(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to list flavors: %w\", err)\n\t\t}\n\t\textractedflavors, err := flavors.ExtractFlavors(page)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to extract flavors: %w\", err)\n\t\t}\n\t\tfor _, flavor := range extractedflavors {\n\t\t\to.openstackFlavors[flavor.ID] = flavor\n\t\t}\n\n\t\t// We need the project to deliver a human readable name in servers\n\t\tpage, err = projects.ListAvailable(o.identity).AllPages(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to list projects: %w\", err)\n\t\t}\n\t\textractedProjects, err := projects.ExtractProjects(page)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to extract projects: %w\", err)\n\t\t}\n\t\tfor _, project := range extractedProjects {\n\t\t\to.openstackProjects[project.ID] = project\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpenStack) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\tcallDuration := make(map[string]interface{}, len(o.services))\n\n\tfor service := range o.services {\n\t\tvar err error\n\n\t\tstart := time.Now()\n\t\tswitch service {\n\t\tcase \"services\":\n\t\t\t// As Services are already gathered in Init(), using this to accumulate them.\n\t\t\tfor _, service := range o.openstackServices {\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"name\": service.Type,\n\t\t\t\t}\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"service_id\":      service.ID,\n\t\t\t\t\t\"service_enabled\": service.Enabled,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"openstack_service\", fields, tags)\n\t\t\t}\n\t\t\tcontinue\n\t\tcase \"projects\":\n\t\t\terr = o.gatherProjects(ctx, acc)\n\t\tcase \"hypervisors\":\n\t\t\terr = o.gatherHypervisors(ctx, acc)\n\t\tcase \"flavors\":\n\t\t\terr = o.gatherFlavors(ctx, acc)\n\t\tcase \"volumes\":\n\t\t\terr = o.gatherVolumes(ctx, acc)\n\t\tcase \"storage_pools\":\n\t\t\terr = o.gatherStoragePools(ctx, acc)\n\t\tcase \"subnets\":\n\t\t\terr = o.gatherSubnets(ctx, acc)\n\t\tcase \"ports\":\n\t\t\terr = o.gatherPorts(ctx, acc)\n\t\tcase \"networks\":\n\t\t\terr = o.gatherNetworks(ctx, acc)\n\t\tcase \"aggregates\":\n\t\t\terr = o.gatherAggregates(ctx, acc)\n\t\tcase \"nova_services\":\n\t\t\terr = o.gatherNovaServices(ctx, acc)\n\t\tcase \"cinder_services\":\n\t\t\terr = o.gatherCinderServices(ctx, acc)\n\t\tcase \"agents\":\n\t\t\terr = o.gatherAgents(ctx, acc)\n\t\tcase \"servers\":\n\t\t\terr = o.gatherServers(ctx, acc)\n\t\tcase \"serverdiagnostics\":\n\t\t\terr = o.gatherServerDiagnostics(ctx, acc)\n\t\tcase \"stacks\":\n\t\t\terr = o.gatherStacks(ctx, acc)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid service %q\", service)\n\t\t}\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to get resource %q: %w\", service, err))\n\t\t}\n\t\tcallDuration[service] = time.Since(start).Nanoseconds()\n\t}\n\n\tif o.MeasureRequest {\n\t\tfor service, duration := range callDuration {\n\t\t\tacc.AddFields(\"openstack_request_duration\", map[string]interface{}{service: duration}, make(map[string]string))\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpenStack) Stop() {\n\tif o.client != nil {\n\t\to.client.CloseIdleConnections()\n\t}\n}\n\nfunc (o *OpenStack) availableServicesFromAuth(provider *gophercloud.ProviderClient) (bool, error) {\n\tauthResult := provider.GetAuthResult()\n\tif authResult == nil {\n\t\treturn false, nil\n\t}\n\n\tresultV3, ok := authResult.(tokens.CreateResult)\n\tif !ok {\n\t\treturn false, nil\n\t}\n\tcatalog, err := resultV3.ExtractServiceCatalog()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif len(catalog.Entries) == 0 {\n\t\treturn false, nil\n\t}\n\n\to.openstackServices = make(map[string]services.Service, len(catalog.Entries))\n\tfor _, entry := range catalog.Entries {\n\t\to.openstackServices[entry.ID] = services.Service{\n\t\t\tID:      entry.ID,\n\t\t\tType:    entry.Type,\n\t\t\tEnabled: true,\n\t\t}\n\t}\n\n\treturn true, nil\n}\n\n// availableServices collects the available endpoint services via API\nfunc (o *OpenStack) availableServices(ctx context.Context) error {\n\tpage, err := services.List(o.identity, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list services: %w\", err)\n\t}\n\textractedServices, err := services.ExtractServices(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract services: %w\", err)\n\t}\n\n\to.openstackServices = make(map[string]services.Service, len(extractedServices))\n\tfor _, service := range extractedServices {\n\t\to.openstackServices[service.ID] = service\n\t}\n\n\treturn nil\n}\n\n// gatherStacks collects and accumulates stacks data from the OpenStack API.\nfunc (o *OpenStack) gatherStacks(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := stacks.List(o.stack, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list stacks: %w\", err)\n\t}\n\textractedStacks, err := stacks.ExtractStacks(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract stacks: %w\", err)\n\t}\n\tfor _, stack := range extractedStacks {\n\t\ttags := map[string]string{\n\t\t\t\"description\": stack.Description,\n\t\t\t\"name\":        stack.Name,\n\t\t}\n\t\tfor _, stackTag := range stack.Tags {\n\t\t\ttags[o.TagPrefix+stackTag] = o.TagValue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"status\":        strings.ToLower(stack.Status),\n\t\t\t\"id\":            stack.ID,\n\t\t\t\"status_reason\": stack.StatusReason,\n\t\t\t\"creation_time\": o.convertTimeFormat(stack.CreationTime),\n\t\t\t\"updated_time\":  o.convertTimeFormat(stack.UpdatedTime),\n\t\t}\n\t\tacc.AddFields(\"openstack_stack\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// gatherNovaServices collects and accumulates nova_services data from the OpenStack API.\nfunc (o *OpenStack) gatherNovaServices(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := nova_services.List(o.compute, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list nova_services: %w\", err)\n\t}\n\tnovaServices, err := nova_services.ExtractServices(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract nova_services: %w\", err)\n\t}\n\tfor _, novaService := range novaServices {\n\t\ttags := map[string]string{\n\t\t\t\"name\":         novaService.Binary,\n\t\t\t\"host_machine\": novaService.Host,\n\t\t\t\"state\":        novaService.State,\n\t\t\t\"status\":       strings.ToLower(novaService.Status),\n\t\t\t\"zone\":         novaService.Zone,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":              novaService.ID,\n\t\t\t\"disabled_reason\": novaService.DisabledReason,\n\t\t\t\"forced_down\":     novaService.ForcedDown,\n\t\t\t\"updated_at\":      o.convertTimeFormat(novaService.UpdatedAt),\n\t\t}\n\t\tacc.AddFields(\"openstack_nova_service\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// gatherCinderServices collects and accumulates cinder_services data from the OpenStack API.\nfunc (o *OpenStack) gatherCinderServices(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := cinder_services.List(o.volume, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list cinder_services: %w\", err)\n\t}\n\tcinderServices, err := cinder_services.ExtractServices(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract cinder_services: %w\", err)\n\t}\n\tfor _, cinderService := range cinderServices {\n\t\ttags := map[string]string{\n\t\t\t\"name\":         cinderService.Binary,\n\t\t\t\"cluster\":      cinderService.Cluster,\n\t\t\t\"host_machine\": cinderService.Host,\n\t\t\t\"state\":        cinderService.State,\n\t\t\t\"status\":       strings.ToLower(cinderService.Status),\n\t\t\t\"zone\":         cinderService.Zone,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                 cinderService.ActiveBackendID,\n\t\t\t\"disabled_reason\":    cinderService.DisabledReason,\n\t\t\t\"frozen\":             cinderService.Frozen,\n\t\t\t\"replication_status\": cinderService.ReplicationStatus,\n\t\t\t\"updated_at\":         o.convertTimeFormat(cinderService.UpdatedAt),\n\t\t}\n\t\tacc.AddFields(\"openstack_cinder_service\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// gatherSubnets collects and accumulates subnets data from the OpenStack API.\nfunc (o *OpenStack) gatherSubnets(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := subnets.List(o.network, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list subnets: %w\", err)\n\t}\n\textractedSubnets, err := subnets.ExtractSubnets(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract subnets: %w\", err)\n\t}\n\tfor _, subnet := range extractedSubnets {\n\t\tallocationPools := make([]string, 0, len(subnet.AllocationPools))\n\t\tfor _, pool := range subnet.AllocationPools {\n\t\t\tallocationPools = append(allocationPools, pool.Start+\"-\"+pool.End)\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"network_id\":        subnet.NetworkID,\n\t\t\t\"name\":              subnet.Name,\n\t\t\t\"description\":       subnet.Description,\n\t\t\t\"ip_version\":        strconv.Itoa(subnet.IPVersion),\n\t\t\t\"cidr\":              subnet.CIDR,\n\t\t\t\"gateway_ip\":        subnet.GatewayIP,\n\t\t\t\"tenant_id\":         subnet.TenantID,\n\t\t\t\"project_id\":        subnet.ProjectID,\n\t\t\t\"ipv6_address_mode\": subnet.IPv6AddressMode,\n\t\t\t\"ipv6_ra_mode\":      subnet.IPv6RAMode,\n\t\t\t\"subnet_pool_id\":    subnet.SubnetPoolID,\n\t\t}\n\t\tfor _, subnetTag := range subnet.Tags {\n\t\t\ttags[o.TagPrefix+subnetTag] = o.TagValue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":               subnet.ID,\n\t\t\t\"dhcp_enabled\":     subnet.EnableDHCP,\n\t\t\t\"dns_nameservers\":  strings.Join(subnet.DNSNameservers[:], \",\"),\n\t\t\t\"allocation_pools\": strings.Join(allocationPools[:], \",\"),\n\t\t}\n\t\tacc.AddFields(\"openstack_subnet\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherPorts collects and accumulates ports data from the OpenStack API.\nfunc (o *OpenStack) gatherPorts(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := ports.List(o.network, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list ports: %w\", err)\n\t}\n\textractedPorts, err := ports.ExtractPorts(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract ports: %w\", err)\n\t}\n\tfor _, port := range extractedPorts {\n\t\ttags := map[string]string{\n\t\t\t\"network_id\":   port.NetworkID,\n\t\t\t\"name\":         port.Name,\n\t\t\t\"description\":  port.Description,\n\t\t\t\"status\":       strings.ToLower(port.Status),\n\t\t\t\"tenant_id\":    port.TenantID,\n\t\t\t\"project_id\":   port.ProjectID,\n\t\t\t\"device_owner\": port.DeviceOwner,\n\t\t\t\"device_id\":    port.DeviceID,\n\t\t}\n\t\tfor _, portTag := range port.Tags {\n\t\t\ttags[o.TagPrefix+portTag] = o.TagValue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                    port.ID,\n\t\t\t\"mac_address\":           port.MACAddress,\n\t\t\t\"admin_state_up\":        port.AdminStateUp,\n\t\t\t\"fixed_ips\":             len(port.FixedIPs),\n\t\t\t\"allowed_address_pairs\": len(port.AllowedAddressPairs),\n\t\t\t\"security_groups\":       strings.Join(port.SecurityGroups[:], \",\"),\n\t\t}\n\t\tif len(port.FixedIPs) > 0 {\n\t\t\tfor _, ip := range port.FixedIPs {\n\t\t\t\tfields[\"subnet_id\"] = ip.SubnetID\n\t\t\t\tfields[\"ip_address\"] = ip.IPAddress\n\t\t\t\tacc.AddFields(\"openstack_port\", fields, tags)\n\t\t\t}\n\t\t} else {\n\t\t\tacc.AddFields(\"openstack_port\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherNetworks collects and accumulates networks data from the OpenStack API.\nfunc (o *OpenStack) gatherNetworks(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := networks.List(o.network, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list networks: %w\", err)\n\t}\n\textractedNetworks, err := networks.ExtractNetworks(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract networks: %w\", err)\n\t}\n\tfor _, network := range extractedNetworks {\n\t\ttags := map[string]string{\n\t\t\t\"name\":        network.Name,\n\t\t\t\"description\": network.Description,\n\t\t\t\"status\":      strings.ToLower(network.Status),\n\t\t\t\"tenant_id\":   network.TenantID,\n\t\t\t\"project_id\":  network.ProjectID,\n\t\t}\n\t\tfor _, networkTag := range network.Tags {\n\t\t\ttags[o.TagPrefix+networkTag] = o.TagValue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                      network.ID,\n\t\t\t\"admin_state_up\":          network.AdminStateUp,\n\t\t\t\"subnets\":                 len(network.Subnets),\n\t\t\t\"shared\":                  network.Shared,\n\t\t\t\"availability_zone_hints\": strings.Join(network.AvailabilityZoneHints[:], \",\"),\n\t\t\t\"updated_at\":              o.convertTimeFormat(network.UpdatedAt),\n\t\t\t\"created_at\":              o.convertTimeFormat(network.CreatedAt),\n\t\t}\n\t\tif len(network.Subnets) > 0 {\n\t\t\tfor _, subnet := range network.Subnets {\n\t\t\t\tfields[\"subnet_id\"] = subnet\n\t\t\t\tacc.AddFields(\"openstack_network\", fields, tags)\n\t\t\t}\n\t\t} else {\n\t\t\tacc.AddFields(\"openstack_network\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherAgents collects and accumulates agents data from the OpenStack API.\nfunc (o *OpenStack) gatherAgents(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := agents.List(o.network, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list neutron agents: %w\", err)\n\t}\n\textractedAgents, err := agents.ExtractAgents(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract neutron agents: %w\", err)\n\t}\n\tfor _, agent := range extractedAgents {\n\t\ttags := map[string]string{\n\t\t\t\"agent_type\":        agent.AgentType,\n\t\t\t\"availability_zone\": agent.AvailabilityZone,\n\t\t\t\"binary\":            agent.Binary,\n\t\t\t\"description\":       agent.Description,\n\t\t\t\"agent_host\":        agent.Host,\n\t\t\t\"topic\":             agent.Topic,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                  agent.ID,\n\t\t\t\"admin_state_up\":      agent.AdminStateUp,\n\t\t\t\"alive\":               agent.Alive,\n\t\t\t\"resources_synced\":    agent.ResourcesSynced,\n\t\t\t\"created_at\":          o.convertTimeFormat(agent.CreatedAt),\n\t\t\t\"started_at\":          o.convertTimeFormat(agent.StartedAt),\n\t\t\t\"heartbeat_timestamp\": o.convertTimeFormat(agent.HeartbeatTimestamp),\n\t\t}\n\t\tacc.AddFields(\"openstack_neutron_agent\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherAggregates collects and accumulates aggregates data from the OpenStack API.\nfunc (o *OpenStack) gatherAggregates(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := aggregates.List(o.compute).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list aggregates: %w\", err)\n\t}\n\textractedAggregates, err := aggregates.ExtractAggregates(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract aggregates: %w\", err)\n\t}\n\tfor _, aggregate := range extractedAggregates {\n\t\ttags := map[string]string{\n\t\t\t\"availability_zone\": aggregate.AvailabilityZone,\n\t\t\t\"name\":              aggregate.Name,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":              aggregate.ID,\n\t\t\t\"aggregate_hosts\": len(aggregate.Hosts),\n\t\t\t\"deleted\":         aggregate.Deleted,\n\t\t\t\"created_at\":      o.convertTimeFormat(aggregate.CreatedAt),\n\t\t\t\"updated_at\":      o.convertTimeFormat(aggregate.UpdatedAt),\n\t\t\t\"deleted_at\":      o.convertTimeFormat(aggregate.DeletedAt),\n\t\t}\n\t\tif len(aggregate.Hosts) > 0 {\n\t\t\tfor _, host := range aggregate.Hosts {\n\t\t\t\tfields[\"aggregate_host\"] = host\n\t\t\t\tacc.AddFields(\"openstack_aggregate\", fields, tags)\n\t\t\t}\n\t\t} else {\n\t\t\tacc.AddFields(\"openstack_aggregate\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherProjects collects and accumulates projects data from the OpenStack API.\nfunc (o *OpenStack) gatherProjects(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := projects.List(o.identity, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list projects: %w\", err)\n\t}\n\textractedProjects, err := projects.ExtractProjects(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract projects: %w\", err)\n\t}\n\tfor _, project := range extractedProjects {\n\t\to.openstackProjects[project.ID] = project\n\t\ttags := map[string]string{\n\t\t\t\"description\": project.Description,\n\t\t\t\"domain_id\":   project.DomainID,\n\t\t\t\"name\":        project.Name,\n\t\t\t\"parent_id\":   project.ParentID,\n\t\t}\n\t\tfor _, projectTag := range project.Tags {\n\t\t\ttags[o.TagPrefix+projectTag] = o.TagValue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":        project.ID,\n\t\t\t\"is_domain\": project.IsDomain,\n\t\t\t\"enabled\":   project.Enabled,\n\t\t\t\"projects\":  len(extractedProjects),\n\t\t}\n\t\tacc.AddFields(\"openstack_identity\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherHypervisors collects and accumulates hypervisors data from the OpenStack API.\nfunc (o *OpenStack) gatherHypervisors(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := hypervisors.List(o.compute, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list hypervisors: %w\", err)\n\t}\n\textractedHypervisors, err := hypervisors.ExtractHypervisors(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract hypervisors: %w\", err)\n\t}\n\n\tfor _, hypervisor := range extractedHypervisors {\n\t\ttags := map[string]string{\n\t\t\t\"cpu_vendor\":              hypervisor.CPUInfo.Vendor,\n\t\t\t\"cpu_arch\":                hypervisor.CPUInfo.Arch,\n\t\t\t\"cpu_model\":               hypervisor.CPUInfo.Model,\n\t\t\t\"status\":                  strings.ToLower(hypervisor.Status),\n\t\t\t\"state\":                   hypervisor.State,\n\t\t\t\"hypervisor_hostname\":     hypervisor.HypervisorHostname,\n\t\t\t\"hypervisor_type\":         hypervisor.HypervisorType,\n\t\t\t\"hypervisor_version\":      strconv.Itoa(hypervisor.HypervisorVersion),\n\t\t\t\"service_host\":            hypervisor.Service.Host,\n\t\t\t\"service_id\":              hypervisor.Service.ID,\n\t\t\t\"service_disabled_reason\": hypervisor.Service.DisabledReason,\n\t\t}\n\t\tfor _, cpuFeature := range hypervisor.CPUInfo.Features {\n\t\t\ttags[\"cpu_feature_\"+cpuFeature] = \"true\"\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                   hypervisor.ID,\n\t\t\t\"host_ip\":              hypervisor.HostIP,\n\t\t\t\"cpu_topology_sockets\": hypervisor.CPUInfo.Topology.Sockets,\n\t\t\t\"cpu_topology_cores\":   hypervisor.CPUInfo.Topology.Cores,\n\t\t\t\"cpu_topology_threads\": hypervisor.CPUInfo.Topology.Threads,\n\t\t\t\"current_workload\":     hypervisor.CurrentWorkload,\n\t\t\t\"disk_available_least\": hypervisor.DiskAvailableLeast,\n\t\t\t\"free_disk_gb\":         hypervisor.FreeDiskGB,\n\t\t\t\"free_ram_mb\":          hypervisor.FreeRamMB,\n\t\t\t\"local_gb\":             hypervisor.LocalGB,\n\t\t\t\"local_gb_used\":        hypervisor.LocalGBUsed,\n\t\t\t\"memory_mb\":            hypervisor.MemoryMB,\n\t\t\t\"memory_mb_used\":       hypervisor.MemoryMBUsed,\n\t\t\t\"running_vms\":          hypervisor.RunningVMs,\n\t\t\t\"vcpus\":                hypervisor.VCPUs,\n\t\t\t\"vcpus_used\":           hypervisor.VCPUsUsed,\n\t\t}\n\t\tacc.AddFields(\"openstack_hypervisor\", fields, tags)\n\t}\n\n\treturn nil\n}\n\n// gatherFlavors collects and accumulates flavors data from the OpenStack API.\nfunc (o *OpenStack) gatherFlavors(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := flavors.ListDetail(o.compute, nil).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list flavors: %w\", err)\n\t}\n\textractedflavors, err := flavors.ExtractFlavors(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract flavors: %w\", err)\n\t}\n\tfor _, flavor := range extractedflavors {\n\t\to.openstackFlavors[flavor.ID] = flavor\n\t\ttags := map[string]string{\n\t\t\t\"name\":      flavor.Name,\n\t\t\t\"is_public\": strconv.FormatBool(flavor.IsPublic),\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":          flavor.ID,\n\t\t\t\"disk\":        flavor.Disk,\n\t\t\t\"ram\":         flavor.RAM,\n\t\t\t\"rxtx_factor\": flavor.RxTxFactor,\n\t\t\t\"swap\":        flavor.Swap,\n\t\t\t\"vcpus\":       flavor.VCPUs,\n\t\t\t\"ephemeral\":   flavor.Ephemeral,\n\t\t}\n\t\tacc.AddFields(\"openstack_flavor\", fields, tags)\n\t}\n\treturn nil\n}\n\n// gatherVolumes collects and accumulates volumes data from the OpenStack API.\nfunc (o *OpenStack) gatherVolumes(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := volumes.List(o.volume, &volumes.ListOpts{AllTenants: o.AllTenants}).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list volumes: %w\", err)\n\t}\n\textractedVolumes, err := volumes.ExtractVolumes(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract volumes: %w\", err)\n\t}\n\tfor _, volume := range extractedVolumes {\n\t\ttags := map[string]string{\n\t\t\t\"status\":               strings.ToLower(volume.Status),\n\t\t\t\"availability_zone\":    volume.AvailabilityZone,\n\t\t\t\"name\":                 volume.Name,\n\t\t\t\"description\":          volume.Description,\n\t\t\t\"volume_type\":          volume.VolumeType,\n\t\t\t\"snapshot_id\":          volume.SnapshotID,\n\t\t\t\"source_volid\":         volume.SourceVolID,\n\t\t\t\"bootable\":             volume.Bootable,\n\t\t\t\"replication_status\":   strings.ToLower(volume.ReplicationStatus),\n\t\t\t\"consistency_group_id\": volume.ConsistencyGroupID,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":                volume.ID,\n\t\t\t\"size\":              volume.Size,\n\t\t\t\"total_attachments\": len(volume.Attachments),\n\t\t\t\"encrypted\":         volume.Encrypted,\n\t\t\t\"multiattach\":       volume.Multiattach,\n\t\t\t\"created_at\":        o.convertTimeFormat(volume.CreatedAt),\n\t\t\t\"updated_at\":        o.convertTimeFormat(volume.UpdatedAt),\n\t\t}\n\t\tif o.OutputSecrets {\n\t\t\ttags[\"user_id\"] = volume.UserID\n\t\t}\n\t\tif len(volume.Attachments) > 0 {\n\t\t\tfor _, attachment := range volume.Attachments {\n\t\t\t\tif !o.HumanReadableTS {\n\t\t\t\t\tfields[\"attachment_attached_at\"] = attachment.AttachedAt.UnixNano()\n\t\t\t\t} else {\n\t\t\t\t\tfields[\"attachment_attached_at\"] = attachment.AttachedAt.Format(\"2006-01-02T15:04:05.999999999Z07:00\")\n\t\t\t\t}\n\t\t\t\ttags[\"attachment_attachment_id\"] = attachment.AttachmentID\n\t\t\t\ttags[\"attachment_device\"] = attachment.Device\n\t\t\t\ttags[\"attachment_host_name\"] = attachment.HostName\n\t\t\t\tfields[\"attachment_server_id\"] = attachment.ServerID\n\t\t\t\tacc.AddFields(\"openstack_volume\", fields, tags)\n\t\t\t}\n\t\t} else {\n\t\t\tacc.AddFields(\"openstack_volume\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// gatherStoragePools collects and accumulates storage pools data from the OpenStack API.\nfunc (o *OpenStack) gatherStoragePools(ctx context.Context, acc telegraf.Accumulator) error {\n\tresults, err := schedulerstats.List(o.volume, &schedulerstats.ListOpts{Detail: true}).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list storage pools: %w\", err)\n\t}\n\tstoragePools, err := schedulerstats.ExtractStoragePools(results)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract storage pools: %w\", err)\n\t}\n\tfor _, storagePool := range storagePools {\n\t\ttags := map[string]string{\n\t\t\t\"name\":                storagePool.Capabilities.VolumeBackendName,\n\t\t\t\"driver_version\":      storagePool.Capabilities.DriverVersion,\n\t\t\t\"storage_protocol\":    storagePool.Capabilities.StorageProtocol,\n\t\t\t\"vendor_name\":         storagePool.Capabilities.VendorName,\n\t\t\t\"volume_backend_name\": storagePool.Capabilities.VolumeBackendName,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"total_capacity_gb\": storagePool.Capabilities.TotalCapacityGB,\n\t\t\t\"free_capacity_gb\":  storagePool.Capabilities.FreeCapacityGB,\n\t\t}\n\t\tacc.AddFields(\"openstack_storage_pool\", fields, tags)\n\t}\n\treturn nil\n}\n\nfunc (o *OpenStack) gatherServers(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := servers.List(o.compute, &servers.ListOpts{AllTenants: o.AllTenants}).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list servers: %w\", err)\n\t}\n\textractedServers, err := servers.ExtractServers(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract servers: %w\", err)\n\t}\n\n\tfor i := range extractedServers {\n\t\tserver := &extractedServers[i]\n\n\t\t// Try derive the associated project\n\t\tproject := \"unknown\"\n\t\tif p, ok := o.openstackProjects[server.TenantID]; ok {\n\t\t\tproject = p.Name\n\t\t}\n\n\t\t// Try to derive the hostname\n\t\tvar hostname string\n\t\tif server.Host != \"\" {\n\t\t\thostname = server.Host\n\t\t} else if server.Hostname != nil && *server.Hostname != \"\" {\n\t\t\thostname = *server.Hostname\n\t\t} else if server.HypervisorHostname != \"\" {\n\t\t\thostname = server.HypervisorHostname\n\t\t} else {\n\t\t\thostname = server.HostID\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"tenant_id\": server.TenantID,\n\t\t\t\"name\":      server.Name,\n\t\t\t\"host_id\":   server.HostID,\n\t\t\t\"status\":    strings.ToLower(server.Status),\n\t\t\t\"key_name\":  server.KeyName,\n\t\t\t\"host_name\": hostname,\n\t\t\t\"project\":   project,\n\t\t}\n\n\t\t// Extract the flavor details to avoid joins (ignore errors and leave as zero values)\n\t\tvar vcpus, ram, disk int\n\t\tif flavorIDInterface, found := server.Flavor[\"id\"]; found {\n\t\t\tif flavorID, ok := flavorIDInterface.(string); ok {\n\t\t\t\ttags[\"flavor\"] = flavorID\n\t\t\t\tif flavor, ok := o.openstackFlavors[flavorID]; ok {\n\t\t\t\t\tvcpus = flavor.VCPUs\n\t\t\t\t\tram = flavor.RAM\n\t\t\t\t\tdisk = flavor.Disk\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif imageIDInterface, found := server.Image[\"id\"]; found {\n\t\t\tif imageID, ok := imageIDInterface.(string); ok {\n\t\t\t\ttags[\"image\"] = imageID\n\t\t\t}\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"id\":               server.ID,\n\t\t\t\"progress\":         server.Progress,\n\t\t\t\"accessIPv4\":       server.AccessIPv4,\n\t\t\t\"accessIPv6\":       server.AccessIPv6,\n\t\t\t\"addresses\":        len(server.Addresses),\n\t\t\t\"security_groups\":  len(server.SecurityGroups),\n\t\t\t\"volumes_attached\": len(server.AttachedVolumes),\n\t\t\t\"fault_code\":       server.Fault.Code,\n\t\t\t\"fault_details\":    server.Fault.Details,\n\t\t\t\"fault_message\":    server.Fault.Message,\n\t\t\t\"vcpus\":            vcpus,\n\t\t\t\"ram_mb\":           ram,\n\t\t\t\"disk_gb\":          disk,\n\t\t\t\"fault_created\":    o.convertTimeFormat(server.Fault.Created),\n\t\t\t\"updated\":          o.convertTimeFormat(server.Updated),\n\t\t\t\"created\":          o.convertTimeFormat(server.Created),\n\t\t}\n\t\tif o.OutputSecrets {\n\t\t\ttags[\"user_id\"] = server.UserID\n\t\t\tfields[\"adminPass\"] = server.AdminPass\n\t\t}\n\t\tif len(server.AttachedVolumes) == 0 {\n\t\t\tacc.AddFields(\"openstack_server\", fields, tags)\n\t\t} else {\n\t\t\tfor _, AttachedVolume := range server.AttachedVolumes {\n\t\t\t\tfields[\"volume_id\"] = AttachedVolume.ID\n\t\t\t\tacc.AddFields(\"openstack_server\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *OpenStack) gatherServerDiagnostics(ctx context.Context, acc telegraf.Accumulator) error {\n\tpage, err := servers.List(o.compute, &servers.ListOpts{AllTenants: o.AllTenants}).AllPages(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to list servers: %w\", err)\n\t}\n\textractedServers, err := servers.ExtractServers(page)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to extract servers: %w\", err)\n\t}\n\n\tfor i := range extractedServers {\n\t\tserver := &extractedServers[i]\n\t\tif server.Status != \"ACTIVE\" {\n\t\t\tcontinue\n\t\t}\n\t\tdiagnostic, err := diagnostics.Get(ctx, o.compute, server.ID).Extract()\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to get diagnostics for server %q: %w\", server.ID, err))\n\t\t\tcontinue\n\t\t}\n\n\t\tportName := make(map[string]bool)\n\t\tstorageName := make(map[string]bool)\n\t\tmemoryStats := make(map[string]interface{})\n\t\tcpus := make(map[string]interface{})\n\t\tfor k, v := range diagnostic {\n\t\t\tif typePort.MatchString(k) {\n\t\t\t\tportName[strings.Split(k, \"_\")[0]] = true\n\t\t\t} else if typeCPU.MatchString(k) {\n\t\t\t\tcpus[k] = v\n\t\t\t} else if typeStorage.MatchString(k) {\n\t\t\t\tstorageName[strings.Split(k, \"_\")[0]] = true\n\t\t\t} else {\n\t\t\t\tmemoryStats[k] = v\n\t\t\t}\n\t\t}\n\t\tnPorts := strconv.Itoa(len(portName))\n\t\tnDisks := strconv.Itoa(len(storageName))\n\n\t\t// Add metrics for disks\n\t\tfields := map[string]interface{}{\n\t\t\t\"memory\":         memoryStats[\"memory\"],\n\t\t\t\"memory-actual\":  memoryStats[\"memory-actual\"],\n\t\t\t\"memory-rss\":     memoryStats[\"memory-rss\"],\n\t\t\t\"memory-swap_in\": memoryStats[\"memory-swap_in\"],\n\t\t}\n\t\tfor k, v := range cpus {\n\t\t\tfields[k] = v\n\t\t}\n\t\tfor key := range storageName {\n\t\t\tfields[\"disk_errors\"] = diagnostic[key+\"_errors\"]\n\t\t\tfields[\"disk_read\"] = diagnostic[key+\"_read\"]\n\t\t\tfields[\"disk_read_req\"] = diagnostic[key+\"_read_req\"]\n\t\t\tfields[\"disk_write\"] = diagnostic[key+\"_write\"]\n\t\t\tfields[\"disk_write_req\"] = diagnostic[key+\"_write_req\"]\n\t\t\ttags := map[string]string{\n\t\t\t\t\"server_id\":   server.ID,\n\t\t\t\t\"no_of_ports\": nPorts,\n\t\t\t\t\"no_of_disks\": nDisks,\n\t\t\t\t\"disk_name\":   key,\n\t\t\t}\n\t\t\tacc.AddFields(\"openstack_server_diagnostics\", fields, tags)\n\t\t}\n\n\t\t// Add metrics for network ports\n\t\tfields = map[string]interface{}{\n\t\t\t\"memory\":         memoryStats[\"memory\"],\n\t\t\t\"memory-actual\":  memoryStats[\"memory-actual\"],\n\t\t\t\"memory-rss\":     memoryStats[\"memory-rss\"],\n\t\t\t\"memory-swap_in\": memoryStats[\"memory-swap_in\"],\n\t\t}\n\t\tfor k, v := range cpus {\n\t\t\tfields[k] = v\n\t\t}\n\t\tfor key := range portName {\n\t\t\tfields[\"port_rx\"] = diagnostic[key+\"_rx\"]\n\t\t\tfields[\"port_rx_drop\"] = diagnostic[key+\"_rx_drop\"]\n\t\t\tfields[\"port_rx_errors\"] = diagnostic[key+\"_rx_errors\"]\n\t\t\tfields[\"port_rx_packets\"] = diagnostic[key+\"_rx_packets\"]\n\t\t\tfields[\"port_tx\"] = diagnostic[key+\"_tx\"]\n\t\t\tfields[\"port_tx_drop\"] = diagnostic[key+\"_tx_drop\"]\n\t\t\tfields[\"port_tx_errors\"] = diagnostic[key+\"_tx_errors\"]\n\t\t\tfields[\"port_tx_packets\"] = diagnostic[key+\"_tx_packets\"]\n\t\t\ttags := map[string]string{\n\t\t\t\t\"server_id\":   server.ID,\n\t\t\t\t\"no_of_ports\": nPorts,\n\t\t\t\t\"no_of_disks\": nDisks,\n\t\t\t\t\"port_name\":   key,\n\t\t\t}\n\t\t\tacc.AddFields(\"openstack_server_diagnostics\", fields, tags)\n\t\t}\n\t}\n\treturn nil\n}\n\n// convertTimeFormat, to convert time format based on HumanReadableTS\nfunc (o *OpenStack) convertTimeFormat(t time.Time) interface{} {\n\tif o.HumanReadableTS {\n\t\treturn t.Format(\"2006-01-02T15:04:05.999999999Z07:00\")\n\t}\n\treturn t.UnixNano()\n}\n\nfunc init() {\n\tinputs.Add(\"openstack\", func() telegraf.Input {\n\t\treturn &OpenStack{\n\t\t\tDomain:     \"default\",\n\t\t\tProject:    \"admin\",\n\t\t\tTagPrefix:  \"openstack_tag_\",\n\t\t\tTagValue:   \"true\",\n\t\t\tAllTenants: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/openstack/sample.conf",
    "content": "# Collects performance metrics from OpenStack services\n[[inputs.openstack]]\n  ## The recommended interval to poll is '30m'\n\n  ## The identity endpoint to authenticate against and get the service catalog from.\n  authentication_endpoint = \"https://my.openstack.cloud:5000\"\n\n  ## The domain to authenticate against when using a V3 identity endpoint.\n  # domain = \"default\"\n\n  ## The project to authenticate as.\n  # project = \"admin\"\n\n  ## User authentication credentials. Must have admin rights.\n  username = \"admin\"\n  password = \"password\"\n\n  ## Available services are:\n  ## \"agents\", \"aggregates\", \"cinder_services\", \"flavors\", \"hypervisors\",\n  ## \"networks\", \"nova_services\", \"ports\", \"projects\", \"servers\",\n  ## \"serverdiagnostics\", \"services\", \"stacks\", \"storage_pools\", \"subnets\",\n  ## \"volumes\"\n  # enabled_services = [\"services\", \"projects\", \"hypervisors\", \"flavors\", \"networks\", \"volumes\"]\n\n  ## Query all instances of all tenants for the volumes and server services\n  ## NOTE: Usually this is only permitted for administrators!\n  # query_all_tenants = true\n\n  ## output secrets (such as adminPass(for server) and UserID(for volume)).\n  # output_secrets = false\n\n  ## Amount of time allowed to complete the HTTP(s) request.\n  # timeout = \"5s\"\n\n  ## HTTP Proxy support\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Options for tags received from Openstack\n  # tag_prefix = \"openstack_tag_\"\n  # tag_value = \"true\"\n\n  ## Timestamp format for timestamp data received from Openstack.\n  ## If false format is unix nanoseconds.\n  # human_readable_timestamps = false\n\n  ## Measure Openstack call duration\n  # measure_openstack_requests = false\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/README.md",
    "content": "# OpenTelemetry Input Plugin\n\nThis service plugin receives traces, metrics, logs and profiles from\n[OpenTelemetry][opentelemetry] clients and compatible agents via gRPC.\n\n> [!NOTE]\n> Telegraf v1.32 through v1.35 support the Profiles signal using the v1\n> experimental API.\n> Telegraf v1.36 supports the Profiles signal using the v1 development API\n> before v0.1.0.\n> Telegraf v1.37+ supports the Profiles signal using the v1 development API\n> v0.2.0.\n\n⭐ Telegraf v1.19.0\n🏷️ logging, messaging\n💻 all\n\n[opentelemetry]: https://opentelemetry.io\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Receive OpenTelemetry traces, metrics, and logs over gRPC\n[[inputs.opentelemetry]]\n  ## Override the default (0.0.0.0:4317) destination OpenTelemetry gRPC service\n  ## address:port\n  # service_address = \"0.0.0.0:4317\"\n\n  ## Override the default (5s) new connection timeout\n  # timeout = \"5s\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Override the default span attributes to be used as line protocol tags.\n  ## These are always included as tags:\n  ## - trace ID\n  ## - span ID\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  # span_dimensions = [\"service.name\", \"span.name\"]\n\n  ## Override the default log record attributes to be used as line protocol tags.\n  ## These are always included as tags, if available:\n  ## - trace ID\n  ## - span ID\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  ## When using InfluxDB for both logs and traces, be certain that log_record_dimensions\n  ## matches the span_dimensions value.\n  # log_record_dimensions = [\"service.name\"]\n\n  ## Override the default profile attributes to be used as line protocol tags.\n  ## These are always included as tags, if available:\n  ## - profile_id\n  ## - address\n  ## - sample\n  ## - sample_name\n  ## - sample_unit\n  ## - sample_type\n  ## - sample_type_unit\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  # profile_dimensions = []\n\n  ## Override the default (prometheus-v1) metrics schema.\n  ## Supports: \"prometheus-v1\", \"prometheus-v2\"\n  ## For more information about the alternatives, read the Prometheus input\n  ## plugin notes.\n  # metrics_schema = \"prometheus-v1\"\n\n  ## Optional TLS Config.\n  ## For advanced options: https://github.com/influxdata/telegraf/blob/v1.18.3/docs/TLS.md\n  ##\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections.\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n  ## Add service certificate and key.\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n```\n\n### Schema\n\nThe OpenTelemetry->InfluxDB conversion [schema][1] and [implementation][2] are\nhosted at <https://github.com/influxdata/influxdb-observability> .\n\nSpans are stored in measurement `spans`.\nLogs are stored in measurement `logs`.\n\nFor metrics, two output schemata exist.  Metrics received with\n`metrics_schema=prometheus-v1` are assigned measurement from the OTel field\n`Metric.name`.  Metrics received with `metrics_schema=prometheus-v2` are stored\nin measurement `prometheus`.\n\nAlso see the OpenTelemetry output plugin for Telegraf.\n\n[1]: https://github.com/influxdata/influxdb-observability/blob/main/docs/index.md\n\n[2]: https://github.com/influxdata/influxdb-observability/tree/main/otel2influx\n\n## Example Output\n\n### Tracing Spans\n\n```text\nspans end_time_unix_nano=\"2021-02-19 20:50:25.6893952 +0000 UTC\",instrumentation_library_name=\"tracegen\",kind=\"SPAN_KIND_INTERNAL\",name=\"okey-dokey\",net.peer.ip=\"1.2.3.4\",parent_span_id=\"d5270e78d85f570f\",peer.service=\"tracegen-client\",service.name=\"tracegen\",span.kind=\"server\",span_id=\"4c28227be6a010e1\",status_code=\"STATUS_CODE_OK\",trace_id=\"7d4854815225332c9834e6dbf85b9380\" 1613767825689169000\nspans end_time_unix_nano=\"2021-02-19 20:50:25.6893952 +0000 UTC\",instrumentation_library_name=\"tracegen\",kind=\"SPAN_KIND_INTERNAL\",name=\"lets-go\",net.peer.ip=\"1.2.3.4\",peer.service=\"tracegen-server\",service.name=\"tracegen\",span.kind=\"client\",span_id=\"d5270e78d85f570f\",status_code=\"STATUS_CODE_OK\",trace_id=\"7d4854815225332c9834e6dbf85b9380\" 1613767825689135000\nspans end_time_unix_nano=\"2021-02-19 20:50:25.6895667 +0000 UTC\",instrumentation_library_name=\"tracegen\",kind=\"SPAN_KIND_INTERNAL\",name=\"okey-dokey\",net.peer.ip=\"1.2.3.4\",parent_span_id=\"b57e98af78c3399b\",peer.service=\"tracegen-client\",service.name=\"tracegen\",span.kind=\"server\",span_id=\"a0643a156d7f9f7f\",status_code=\"STATUS_CODE_OK\",trace_id=\"fd6b8bb5965e726c94978c644962cdc8\" 1613767825689388000\nspans end_time_unix_nano=\"2021-02-19 20:50:25.6895667 +0000 UTC\",instrumentation_library_name=\"tracegen\",kind=\"SPAN_KIND_INTERNAL\",name=\"lets-go\",net.peer.ip=\"1.2.3.4\",peer.service=\"tracegen-server\",service.name=\"tracegen\",span.kind=\"client\",span_id=\"b57e98af78c3399b\",status_code=\"STATUS_CODE_OK\",trace_id=\"fd6b8bb5965e726c94978c644962cdc8\" 1613767825689303300\nspans end_time_unix_nano=\"2021-02-19 20:50:25.6896741 +0000 UTC\",instrumentation_library_name=\"tracegen\",kind=\"SPAN_KIND_INTERNAL\",name=\"okey-dokey\",net.peer.ip=\"1.2.3.4\",parent_span_id=\"6a8e6a0edcc1c966\",peer.service=\"tracegen-client\",service.name=\"tracegen\",span.kind=\"server\",span_id=\"d68f7f3b41eb8075\",status_code=\"STATUS_CODE_OK\",trace_id=\"651dadde186b7834c52b13a28fc27bea\" 1613767825689480300\n```\n\n## Metrics\n\n### `prometheus-v1`\n\n```text\ncpu_temp,foo=bar gauge=87.332\nhttp_requests_total,method=post,code=200 counter=1027\nhttp_requests_total,method=post,code=400 counter=3\nhttp_request_duration_seconds 0.05=24054,0.1=33444,0.2=100392,0.5=129389,1=133988,sum=53423,count=144320\nrpc_duration_seconds 0.01=3102,0.05=3272,0.5=4773,0.9=9001,0.99=76656,sum=1.7560473e+07,count=2693\n```\n\n### `prometheus-v2`\n\n```text\nprometheus,foo=bar cpu_temp=87.332\nprometheus,method=post,code=200 http_requests_total=1027\nprometheus,method=post,code=400 http_requests_total=3\nprometheus,le=0.05 http_request_duration_seconds_bucket=24054\nprometheus,le=0.1  http_request_duration_seconds_bucket=33444\nprometheus,le=0.2  http_request_duration_seconds_bucket=100392\nprometheus,le=0.5  http_request_duration_seconds_bucket=129389\nprometheus,le=1    http_request_duration_seconds_bucket=133988\nprometheus         http_request_duration_seconds_count=144320,http_request_duration_seconds_sum=53423\nprometheus,quantile=0.01 rpc_duration_seconds=3102\nprometheus,quantile=0.05 rpc_duration_seconds=3272\nprometheus,quantile=0.5  rpc_duration_seconds=4773\nprometheus,quantile=0.9  rpc_duration_seconds=9001\nprometheus,quantile=0.99 rpc_duration_seconds=76656\nprometheus               rpc_duration_seconds_count=1.7560473e+07,rpc_duration_seconds_sum=2693\n```\n\n### Logs\n\n```text\nlogs fluent.tag=\"fluent.info\",pid=18i,ppid=9i,worker=0i 1613769568895331700\nlogs fluent.tag=\"fluent.debug\",instance=1720i,queue_size=0i,stage_size=0i 1613769568895697200\nlogs fluent.tag=\"fluent.info\",worker=0i 1613769568896515100\n```\n\n### Profiles\n\n```text\nprofiles,address=95210353,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=0,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"fab9b8c848218405738c11a7ec4982e9\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename=\"chromium\",frame_type=\"native\",location=\"\",memory_limit=250413056u,memory_start=18698240u,stack_trace_id=\"hYmAzQVF8vy8MWbzsKpQNw\",start_time_unix_nano=1721306050081621681u,value=1i 1721306048731622020\nprofiles,address=15945263,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"7dab4a2e0005d025e75cc72191f8d6bf\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename=\"dockerd\",frame_type=\"native\",location=\"\",memory_limit=47255552u,memory_start=15638528u,stack_trace_id=\"4N3KEcGylb5Qoi2905c1ZA\",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725\nprofiles,address=15952400,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"7dab4a2e0005d025e75cc72191f8d6bf\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename=\"dockerd\",frame_type=\"native\",location=\"\",memory_limit=47255552u,memory_start=15638528u,stack_trace_id=\"4N3KEcGylb5Qoi2905c1ZA\",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725\nprofiles,address=15953899,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"7dab4a2e0005d025e75cc72191f8d6bf\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename=\"dockerd\",frame_type=\"native\",location=\"\",memory_limit=47255552u,memory_start=15638528u,stack_trace_id=\"4N3KEcGylb5Qoi2905c1ZA\",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725\nprofiles,address=16148175,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"7dab4a2e0005d025e75cc72191f8d6bf\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename=\"dockerd\",frame_type=\"native\",location=\"\",memory_limit=47255552u,memory_start=15638528u,stack_trace_id=\"4N3KEcGylb5Qoi2905c1ZA\",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725\nprofiles,address=4770577,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"cfc3dc7d1638c1284a6b62d4b5c0d74e\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename=\"\",frame_type=\"kernel\",location=\"do_epoll_wait\",memory_limit=0u,memory_start=0u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\nprofiles,address=4773632,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"cfc3dc7d1638c1284a6b62d4b5c0d74e\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename=\"\",frame_type=\"kernel\",location=\"__x64_sys_epoll_wait\",memory_limit=0u,memory_start=0u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\nprofiles,address=14783666,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"cfc3dc7d1638c1284a6b62d4b5c0d74e\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename=\"\",frame_type=\"kernel\",location=\"do_syscall_64\",memory_limit=0u,memory_start=0u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\nprofiles,address=16777518,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"cfc3dc7d1638c1284a6b62d4b5c0d74e\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename=\"\",frame_type=\"kernel\",location=\"entry_SYSCALL_64_after_hwframe\",memory_limit=0u,memory_start=0u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\nprofiles,address=1139937,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"982ed6c7a77f99f0ae746be0187953bf\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=147456u,filename=\"libc.so.6\",frame_type=\"native\",location=\"\",memory_limit=1638400u,memory_start=147456u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\nprofiles,address=117834912,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id=\"fab9b8c848218405738c11a7ec4982e9\",build_id_type=\"BUILD_ID_BINARY_HASH\",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename=\"chromium\",frame_type=\"native\",location=\"\",memory_limit=250413056u,memory_start=18698240u,stack_trace_id=\"UaO9bysJnAYXFYobSdHXqg\",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681\n```\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/grpc_service_profile.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tservice \"go.opentelemetry.io/proto/otlp/collector/profiles/v1development\"\n\totlp \"go.opentelemetry.io/proto/otlp/profiles/v1development\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/filter\"\n)\n\ntype profileService struct {\n\tservice.UnimplementedProfilesServiceServer\n\n\tacc    telegraf.Accumulator\n\tfilter filter.Filter\n\tlogger telegraf.Logger\n}\n\nfunc newProfileService(acc telegraf.Accumulator, logger telegraf.Logger, dimensions []string) (*profileService, error) {\n\t// Check for duplicate dimensions\n\tseen := make(map[string]bool, len(dimensions))\n\tduplicates := make([]string, 0)\n\tdims := make([]string, 0, len(dimensions))\n\tfor _, d := range dimensions {\n\t\tif seen[d] {\n\t\t\tduplicates = append(duplicates, d)\n\t\t\tcontinue\n\t\t}\n\t\tdims = append(dims, d)\n\t\tseen[d] = true\n\t}\n\tif len(duplicates) > 0 {\n\t\treturn nil, fmt.Errorf(\"duplicate profile dimension(s) configured: %s\", strings.Join(duplicates, \",\"))\n\t}\n\tf, err := filter.Compile(dims)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"compiling dimensions filter failed: %w\", err)\n\t}\n\n\treturn &profileService{\n\t\tacc:    acc,\n\t\tfilter: f,\n\t\tlogger: logger,\n\t}, nil\n}\n\n// Export processes and exports the received profile data.\nfunc (s *profileService) Export(_ context.Context, req *service.ExportProfilesServiceRequest) (*service.ExportProfilesServiceResponse, error) {\n\t// Output the received message for debugging\n\tbuf, err := protojson.Marshal(req)\n\tif err != nil {\n\t\ts.logger.Errorf(\"marshalling received profile failed: %v\", err)\n\t} else {\n\t\ts.logger.Debugf(\"received profile: %s\", string(buf))\n\t}\n\n\tpd := req.Dictionary\n\n\tfor _, rp := range req.ResourceProfiles {\n\t\t// Extract the requested attributes that should be added as tags\n\t\tattrtags := make(map[string]string)\n\t\tfor _, attr := range rp.Resource.Attributes {\n\t\t\tif s.filter.Match(attr.Key) {\n\t\t\t\tattrtags[attr.Key] = attr.GetValue().GetStringValue()\n\t\t\t}\n\t\t}\n\n\t\tfor _, sp := range rp.ScopeProfiles {\n\t\t\tfor _, p := range sp.Profiles {\n\t\t\t\tfor i, sample := range p.Samples {\n\t\t\t\t\tstack := pd.StackTable[sample.StackIndex]\n\t\t\t\t\tfor _, locIdx := range stack.LocationIndices {\n\t\t\t\t\t\tfor validx, value := range sample.Values {\n\t\t\t\t\t\t\tloc := pd.LocationTable[locIdx]\n\t\t\t\t\t\t\tlocations := make([]string, 0, len(loc.Lines))\n\t\t\t\t\t\t\tfor _, line := range loc.Lines {\n\t\t\t\t\t\t\t\tf := pd.FunctionTable[line.FunctionIndex]\n\t\t\t\t\t\t\t\tfileloc := pd.StringTable[f.FilenameStrindex]\n\t\t\t\t\t\t\t\tif f.StartLine > 0 {\n\t\t\t\t\t\t\t\t\tif fileloc != \"\" {\n\t\t\t\t\t\t\t\t\t\tfileloc += \" \"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tfileloc += \"line \" + strconv.FormatInt(f.StartLine, 10)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tl := pd.StringTable[f.NameStrindex]\n\t\t\t\t\t\t\t\tif fileloc != \"\" {\n\t\t\t\t\t\t\t\t\tl += \"(\" + fileloc + \")\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlocations = append(locations, l)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmapping := &otlp.Mapping{}\n\t\t\t\t\t\t\t// MappingIndex of 0 means unknown or unapplicable mapping, as the\n\t\t\t\t\t\t\t// first entry in the  mapping table is always a null mapping.\n\t\t\t\t\t\t\tif loc.MappingIndex != 0 {\n\t\t\t\t\t\t\t\tmapping = pd.MappingTable[loc.MappingIndex]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\t\t\t\"profile_id\":       hex.EncodeToString(p.ProfileId),\n\t\t\t\t\t\t\t\t\"sample\":           strconv.Itoa(i),\n\t\t\t\t\t\t\t\t\"sample_name\":      pd.StringTable[p.PeriodType.TypeStrindex],\n\t\t\t\t\t\t\t\t\"sample_unit\":      pd.StringTable[p.PeriodType.UnitStrindex],\n\t\t\t\t\t\t\t\t\"sample_type\":      pd.StringTable[p.SampleType.TypeStrindex],\n\t\t\t\t\t\t\t\t\"sample_type_unit\": pd.StringTable[p.SampleType.UnitStrindex],\n\t\t\t\t\t\t\t\t\"address\":          \"0x\" + strconv.FormatUint(loc.Address, 16),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor k, v := range attrtags {\n\t\t\t\t\t\t\t\ttags[k] = v\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\t\t\t\"start_time_unix_nano\": int64(p.TimeUnixNano),\n\t\t\t\t\t\t\t\t\"end_time_unix_nano\":   int64(p.TimeUnixNano + p.DurationNano),\n\t\t\t\t\t\t\t\t\"location\":             strings.Join(locations, \",\"),\n\t\t\t\t\t\t\t\t\"memory_start\":         mapping.MemoryStart,\n\t\t\t\t\t\t\t\t\"memory_limit\":         mapping.MemoryLimit,\n\t\t\t\t\t\t\t\t\"filename\":             pd.StringTable[mapping.FilenameStrindex],\n\t\t\t\t\t\t\t\t\"file_offset\":          mapping.FileOffset,\n\t\t\t\t\t\t\t\t\"value\":                value,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor _, idx := range sample.AttributeIndices {\n\t\t\t\t\t\t\t\tattr := pd.AttributeTable[idx]\n\t\t\t\t\t\t\t\tkey := pd.StringTable[attr.KeyStrindex]\n\t\t\t\t\t\t\t\tfields[key] = attr.GetValue().Value\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tts := sample.TimestampsUnixNano[validx]\n\t\t\t\t\t\t\ts.acc.AddFields(\"profiles\", fields, tags, time.Unix(0, int64(ts)))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn &service.ExportProfilesServiceResponse{}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/grpc_services.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/influxdata/influxdb-observability/common\"\n\t\"github.com/influxdata/influxdb-observability/otel2influx\"\n\t\"go.opentelemetry.io/collector/pdata/plog/plogotlp\"\n\t\"go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp\"\n\t\"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp\"\n)\n\ntype traceService struct {\n\tptraceotlp.UnimplementedGRPCServer\n\texporter *otel2influx.OtelTracesToLineProtocol\n}\n\nvar _ ptraceotlp.GRPCServer = (*traceService)(nil)\n\nfunc newTraceService(logger common.Logger, writer *writeToAccumulator, spanDimensions []string) (*traceService, error) {\n\texpConfig := otel2influx.DefaultOtelTracesToLineProtocolConfig()\n\texpConfig.Logger = logger\n\texpConfig.Writer = writer\n\texpConfig.SpanDimensions = spanDimensions\n\texp, err := otel2influx.NewOtelTracesToLineProtocol(expConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &traceService{\n\t\texporter: exp,\n\t}, nil\n}\n\n// Export processes and exports the trace data received in the request.\nfunc (s *traceService) Export(ctx context.Context, req ptraceotlp.ExportRequest) (ptraceotlp.ExportResponse, error) {\n\terr := s.exporter.WriteTraces(ctx, req.Traces())\n\treturn ptraceotlp.NewExportResponse(), err\n}\n\ntype metricsService struct {\n\tpmetricotlp.UnimplementedGRPCServer\n\texporter *otel2influx.OtelMetricsToLineProtocol\n}\n\nvar _ pmetricotlp.GRPCServer = (*metricsService)(nil)\n\nvar metricsSchemata = map[string]common.MetricsSchema{\n\t\"prometheus-v1\": common.MetricsSchemaTelegrafPrometheusV1,\n\t\"prometheus-v2\": common.MetricsSchemaTelegrafPrometheusV2,\n}\n\nfunc newMetricsService(logger common.Logger, writer *writeToAccumulator, schema string) (*metricsService, error) {\n\tms, found := metricsSchemata[schema]\n\tif !found {\n\t\treturn nil, fmt.Errorf(\"schema %q not recognized\", schema)\n\t}\n\n\texpConfig := otel2influx.DefaultOtelMetricsToLineProtocolConfig()\n\texpConfig.Logger = logger\n\texpConfig.Writer = writer\n\texpConfig.Schema = ms\n\texp, err := otel2influx.NewOtelMetricsToLineProtocol(expConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &metricsService{\n\t\texporter: exp,\n\t}, nil\n}\n\n// Export processes and exports the metrics data received in the request.\nfunc (s *metricsService) Export(ctx context.Context, req pmetricotlp.ExportRequest) (pmetricotlp.ExportResponse, error) {\n\terr := s.exporter.WriteMetrics(ctx, req.Metrics())\n\treturn pmetricotlp.NewExportResponse(), err\n}\n\ntype logsService struct {\n\tplogotlp.UnimplementedGRPCServer\n\tconverter *otel2influx.OtelLogsToLineProtocol\n}\n\nvar _ plogotlp.GRPCServer = (*logsService)(nil)\n\nfunc newLogsService(logger common.Logger, writer *writeToAccumulator, logRecordDimensions []string) (*logsService, error) {\n\texpConfig := otel2influx.DefaultOtelLogsToLineProtocolConfig()\n\texpConfig.Logger = logger\n\texpConfig.Writer = writer\n\texpConfig.LogRecordDimensions = logRecordDimensions\n\texp, err := otel2influx.NewOtelLogsToLineProtocol(expConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &logsService{\n\t\tconverter: exp,\n\t}, nil\n}\n\n// Export processes and exports the logs data received in the request.\nfunc (s *logsService) Export(ctx context.Context, req plogotlp.ExportRequest) (plogotlp.ExportResponse, error) {\n\terr := s.converter.WriteLogs(ctx, req.Logs())\n\treturn plogotlp.NewExportResponse(), err\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/logger.go",
    "content": "package opentelemetry\n\nimport (\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype otelLogger struct {\n\ttelegraf.Logger\n}\n\n// Debug logs a debug message, patterned after log.Print.\nfunc (l otelLogger) Debug(msg string, kv ...interface{}) {\n\tformat := msg + strings.Repeat(\" %s=%q\", len(kv)/2)\n\tl.Logger.Debugf(format, kv...)\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/opentelemetry.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage opentelemetry\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/influxdb-observability/otel2influx\"\n\t\"go.opentelemetry.io/collector/pdata/plog/plogotlp\"\n\t\"go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp\"\n\t\"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp\"\n\tpprofileotlp \"go.opentelemetry.io/proto/otlp/collector/profiles/v1development\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype OpenTelemetry struct {\n\tServiceAddress      string          `toml:\"service_address\"`\n\tSpanDimensions      []string        `toml:\"span_dimensions\"`\n\tLogRecordDimensions []string        `toml:\"log_record_dimensions\"`\n\tProfileDimensions   []string        `toml:\"profile_dimensions\"`\n\tMetricsSchema       string          `toml:\"metrics_schema\"`\n\tMaxMsgSize          config.Size     `toml:\"max_msg_size\"`\n\tTimeout             config.Duration `toml:\"timeout\"`\n\tLog                 telegraf.Logger `toml:\"-\"`\n\ttls.ServerConfig\n\n\tlistener   net.Listener // overridden in tests\n\tgrpcServer *grpc.Server\n\n\twg sync.WaitGroup\n}\n\nfunc (*OpenTelemetry) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (o *OpenTelemetry) Init() error {\n\tif o.ServiceAddress == \"\" {\n\t\to.ServiceAddress = \"0.0.0.0:4317\"\n\t}\n\tswitch o.MetricsSchema {\n\tcase \"\": // Set default\n\t\to.MetricsSchema = \"prometheus-v1\"\n\tcase \"prometheus-v1\", \"prometheus-v2\": // Valid values\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid metric schema %q\", o.MetricsSchema)\n\t}\n\n\treturn nil\n}\n\nfunc (o *OpenTelemetry) Start(acc telegraf.Accumulator) error {\n\tvar grpcOptions []grpc.ServerOption\n\tif tlsConfig, err := o.ServerConfig.TLSConfig(); err != nil {\n\t\treturn err\n\t} else if tlsConfig != nil {\n\t\tgrpcOptions = append(grpcOptions, grpc.Creds(credentials.NewTLS(tlsConfig)))\n\t}\n\tif o.Timeout > 0 {\n\t\tgrpcOptions = append(grpcOptions, grpc.ConnectionTimeout(time.Duration(o.Timeout)))\n\t}\n\tif o.MaxMsgSize > 0 {\n\t\tgrpcOptions = append(grpcOptions, grpc.MaxRecvMsgSize(int(o.MaxMsgSize)))\n\t}\n\n\tlogger := &otelLogger{o.Log}\n\tinfluxWriter := &writeToAccumulator{acc}\n\to.grpcServer = grpc.NewServer(grpcOptions...)\n\n\ttraceSvc, err := newTraceService(logger, influxWriter, o.SpanDimensions)\n\tif err != nil {\n\t\treturn err\n\t}\n\tptraceotlp.RegisterGRPCServer(o.grpcServer, traceSvc)\n\n\tmetricsSvc, err := newMetricsService(logger, influxWriter, o.MetricsSchema)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpmetricotlp.RegisterGRPCServer(o.grpcServer, metricsSvc)\n\n\tlogsSvc, err := newLogsService(logger, influxWriter, o.LogRecordDimensions)\n\tif err != nil {\n\t\treturn err\n\t}\n\tplogotlp.RegisterGRPCServer(o.grpcServer, logsSvc)\n\n\tprofileSvc, err := newProfileService(acc, o.Log, o.ProfileDimensions)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpprofileotlp.RegisterProfilesServiceServer(o.grpcServer, profileSvc)\n\n\to.listener, err = net.Listen(\"tcp\", o.ServiceAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to.wg.Add(1)\n\tgo func() {\n\t\tdefer o.wg.Done()\n\t\tif err := o.grpcServer.Serve(o.listener); err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"failed to stop OpenTelemetry gRPC service: %w\", err))\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (*OpenTelemetry) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (o *OpenTelemetry) Stop() {\n\tif o.grpcServer != nil {\n\t\to.grpcServer.Stop()\n\t}\n\to.listener = nil\n\n\to.wg.Wait()\n}\n\nfunc init() {\n\tinputs.Add(\"opentelemetry\", func() telegraf.Input {\n\t\treturn &OpenTelemetry{\n\t\t\tSpanDimensions:      otel2influx.DefaultOtelTracesToLineProtocolConfig().SpanDimensions,\n\t\t\tLogRecordDimensions: otel2influx.DefaultOtelLogsToLineProtocolConfig().LogRecordDimensions,\n\t\t\tTimeout:             config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/opentelemetry_test.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/influxdata/influxdb-observability/otel2influx\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\t\"go.opentelemetry.io/otel/sdk/metric/metricdata\"\n\totlplogs \"go.opentelemetry.io/proto/otlp/collector/logs/v1\"\n\totlpmetrics \"go.opentelemetry.io/proto/otlp/collector/metrics/v1\"\n\totlpprofiles \"go.opentelemetry.io/proto/otlp/collector/profiles/v1development\"\n\totlptrace \"go.opentelemetry.io/proto/otlp/collector/trace/v1\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestOpenTelemetry(t *testing.T) {\n\t// Setup and start the plugin\n\tplugin := &OpenTelemetry{\n\t\tMetricsSchema: \"prometheus-v1\",\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Setup the OpenTelemetry exporter\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second)\n\tdefer cancel()\n\n\texporter, err := otlpmetricgrpc.New(ctx,\n\t\totlpmetricgrpc.WithInsecure(),\n\t\totlpmetricgrpc.WithDialOption(\n\t\t\tgrpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {\n\t\t\t\treturn net.Dial(\"tcp\", plugin.listener.Addr().String())\n\t\t\t})),\n\t)\n\trequire.NoError(t, err)\n\tdefer exporter.Shutdown(ctx) //nolint:errcheck // We cannot do anything if the shutdown fails\n\n\t// Setup the metric to send\n\treader := metric.NewManualReader()\n\tdefer reader.Shutdown(ctx) //nolint:errcheck // We cannot do anything if the shutdown fails\n\n\tprovider := metric.NewMeterProvider(metric.WithReader(reader))\n\tmeter := provider.Meter(\"library-name\")\n\tcounter, err := meter.Int64Counter(\"measurement-counter\")\n\trequire.NoError(t, err)\n\tcounter.Add(ctx, 7)\n\n\t// Write the OpenTelemetry metrics\n\tvar rm metricdata.ResourceMetrics\n\trequire.NoError(t, reader.Collect(ctx, &rm))\n\trequire.NoError(t, exporter.Export(ctx, &rm))\n\n\t// Shutdown\n\trequire.NoError(t, reader.Shutdown(ctx))\n\trequire.NoError(t, exporter.Shutdown(ctx))\n\tplugin.Stop()\n\n\t// Check\n\trequire.Empty(t, acc.Errors)\n\n\tvar exesuffix string\n\tif runtime.GOOS == \"windows\" {\n\t\texesuffix = \".exe\"\n\t}\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"measurement-counter\",\n\t\t\tmap[string]string{\n\t\t\t\t\"otel.library.name\":      \"library-name\",\n\t\t\t\t\"service.name\":           \"unknown_service:opentelemetry.test\" + exesuffix,\n\t\t\t\t\"telemetry.sdk.language\": \"go\",\n\t\t\t\t\"telemetry.sdk.name\":     \"opentelemetry\",\n\t\t\t\t\"telemetry.sdk.version\":  \"1.27.0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"counter\": 7,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.IgnoreFields(\"start_time_unix_nano\"),\n\t\ttestutil.IgnoreTags(\"telemetry.sdk.version\"),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"opentelemetry\", func() telegraf.Input {\n\t\treturn &OpenTelemetry{\n\t\t\tServiceAddress:      \"127.0.0.1:0\",\n\t\t\tSpanDimensions:      otel2influx.DefaultOtelTracesToLineProtocolConfig().SpanDimensions,\n\t\t\tLogRecordDimensions: otel2influx.DefaultOtelLogsToLineProtocolConfig().LogRecordDimensions,\n\t\t\tProfileDimensions:   []string{\"host.name\"},\n\t\t\tTimeout:             config.Duration(5 * time.Second),\n\t\t}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\tinputFiles := filepath.Join(testcasePath, \"*.json\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t\ttestutil.IgnoreFields(\"start_time_unix_nano\"),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tinputs := make(map[string][][]byte)\n\t\t\tmatches, err := filepath.Glob(inputFiles)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, matches)\n\t\t\tsort.Strings(matches)\n\t\t\tfor _, fn := range matches {\n\t\t\t\tbuf, err := os.ReadFile(fn)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tkey := strings.TrimSuffix(filepath.Base(fn), \".json\")\n\t\t\t\tkey, _, _ = strings.Cut(key, \"_\")\n\t\t\t\tinputs[key] = append(inputs[key], buf)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup and start the plugin\n\t\t\tplugin := cfg.Inputs[0].Input.(*OpenTelemetry)\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Send all data to the plugin\n\t\t\taddr := plugin.listener.Addr().String()\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tgrpcClient, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer grpcClient.Close()\n\t\t\tfor msgtype, messages := range inputs {\n\t\t\t\tswitch msgtype {\n\t\t\t\tcase \"logs\":\n\t\t\t\t\tclient := otlplogs.NewLogsServiceClient(grpcClient)\n\t\t\t\t\tfor _, buf := range messages {\n\t\t\t\t\t\tvar msg otlplogs.ExportLogsServiceRequest\n\t\t\t\t\t\trequire.NoError(t, protojson.Unmarshal(buf, &msg))\n\t\t\t\t\t\t_, err := client.Export(ctx, &msg)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\tcase \"metrics\":\n\t\t\t\t\tclient := otlpmetrics.NewMetricsServiceClient(grpcClient)\n\t\t\t\t\tfor _, buf := range messages {\n\t\t\t\t\t\tvar msg otlpmetrics.ExportMetricsServiceRequest\n\t\t\t\t\t\trequire.NoError(t, protojson.Unmarshal(buf, &msg))\n\t\t\t\t\t\t_, err := client.Export(ctx, &msg)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\tcase \"profiles\":\n\t\t\t\t\tclient := otlpprofiles.NewProfilesServiceClient(grpcClient)\n\t\t\t\t\tfor _, buf := range messages {\n\t\t\t\t\t\tvar msg otlpprofiles.ExportProfilesServiceRequest\n\t\t\t\t\t\trequire.NoError(t, protojson.Unmarshal(buf, &msg))\n\t\t\t\t\t\t_, err := client.Export(ctx, &msg)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\tcase \"traces\":\n\t\t\t\t\tclient := otlptrace.NewTraceServiceClient(grpcClient)\n\t\t\t\t\tfor _, buf := range messages {\n\t\t\t\t\t\tvar msg otlptrace.ExportTraceServiceRequest\n\t\t\t\t\t\trequire.NoError(t, protojson.Unmarshal(buf, &msg))\n\t\t\t\t\t\t_, err := client.Export(ctx, &msg)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Close the plugin to make sure all data is flushed\n\t\t\trequire.NoError(t, grpcClient.Close())\n\t\t\tplugin.Stop()\n\n\t\t\t// Check the metrics\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond)\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/sample.conf",
    "content": "# Receive OpenTelemetry traces, metrics, and logs over gRPC\n[[inputs.opentelemetry]]\n  ## Override the default (0.0.0.0:4317) destination OpenTelemetry gRPC service\n  ## address:port\n  # service_address = \"0.0.0.0:4317\"\n\n  ## Override the default (5s) new connection timeout\n  # timeout = \"5s\"\n\n  ## gRPC Maximum Message Size\n  # max_msg_size = \"4MB\"\n\n  ## Override the default span attributes to be used as line protocol tags.\n  ## These are always included as tags:\n  ## - trace ID\n  ## - span ID\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  # span_dimensions = [\"service.name\", \"span.name\"]\n\n  ## Override the default log record attributes to be used as line protocol tags.\n  ## These are always included as tags, if available:\n  ## - trace ID\n  ## - span ID\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  ## When using InfluxDB for both logs and traces, be certain that log_record_dimensions\n  ## matches the span_dimensions value.\n  # log_record_dimensions = [\"service.name\"]\n\n  ## Override the default profile attributes to be used as line protocol tags.\n  ## These are always included as tags, if available:\n  ## - profile_id\n  ## - address\n  ## - sample\n  ## - sample_name\n  ## - sample_unit\n  ## - sample_type\n  ## - sample_type_unit\n  ## Common attributes can be found here:\n  ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv\n  # profile_dimensions = []\n\n  ## Override the default (prometheus-v1) metrics schema.\n  ## Supports: \"prometheus-v1\", \"prometheus-v2\"\n  ## For more information about the alternatives, read the Prometheus input\n  ## plugin notes.\n  # metrics_schema = \"prometheus-v1\"\n\n  ## Optional TLS Config.\n  ## For advanced options: https://github.com/influxdata/telegraf/blob/v1.18.3/docs/TLS.md\n  ##\n  ## Set one or more allowed client CA certificate file names to\n  ## enable mutually authenticated TLS connections.\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n  ## Add service certificate and key.\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/testcases/profiles/expected.out",
    "content": "profiles,address=0x5accb71,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=0,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds location=\"\",memory_start=18698240u,memory_limit=250413056u,filename=\"chromium\",file_offset=18694144u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i 1721306048731622020\nprofiles,address=0xf34e2f,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds end_time_unix_nano=1721306050081621681i,location=\"\",memory_start=15638528u,memory_limit=47255552u,filename=\"dockerd\",file_offset=15638528u,value=1i,start_time_unix_nano=1721306050081621681i 1721306049831718725\nprofiles,address=0xf36a10,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds file_offset=15638528u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"\",memory_start=15638528u,memory_limit=47255552u,filename=\"dockerd\" 1721306049831718725\nprofiles,address=0xf36feb,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds location=\"\",memory_start=15638528u,memory_limit=47255552u,filename=\"dockerd\",file_offset=15638528u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i 1721306049831718725\nprofiles,address=0xf666cf,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"\",memory_start=15638528u,memory_limit=47255552u,filename=\"dockerd\",file_offset=15638528u 1721306049831718725\nprofiles,address=0x48cb11,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds filename=\"\",file_offset=0u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"do_epoll_wait\",memory_start=0u,memory_limit=0u 1721306050081621681\nprofiles,address=0x48d700,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds memory_limit=0u,filename=\"\",file_offset=0u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"__x64_sys_epoll_wait\",memory_start=0u 1721306050081621681\nprofiles,address=0xe194b2,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds file_offset=0u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"do_syscall_64\",memory_start=0u,memory_limit=0u,filename=\"\" 1721306050081621681\nprofiles,address=0x100012e,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds file_offset=0u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"entry_SYSCALL_64_after_hwframe\",memory_start=0u,memory_limit=0u,filename=\"\" 1721306050081621681\nprofiles,address=0x1164e1,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i,location=\"\",memory_start=147456u,memory_limit=1638400u,filename=\"libc.so.6\",file_offset=147456u,value=1i 1721306050081621681\nprofiles,address=0x70604a0,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds location=\"\",memory_start=18698240u,memory_limit=250413056u,filename=\"chromium\",file_offset=18694144u,value=1i,start_time_unix_nano=1721306050081621681i,end_time_unix_nano=1721306050081621681i 1721306050081621681\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/testcases/profiles/profiles.json",
    "content": "{\n  \"resourceProfiles\": [\n    {\n      \"resource\": {\n        \"attributes\": [\n          {\n            \"key\": \"profiling.agent.start_time\",\n            \"value\": {\n              \"stringValue\": \"1721306026320\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.env_https_proxy\",\n            \"value\": {\n              \"stringValue\": \"\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.tracers\",\n            \"value\": {\n              \"stringValue\": \"all\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.ca_address\",\n            \"value\": {\n              \"stringValue\": \"127.0.0.1:11000\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L2-kbytes\",\n            \"value\": {\n              \"stringValue\": \"512\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.kernel_version\",\n            \"value\": {\n              \"stringValue\": \"6.9.9-arch1-1\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.verbose\",\n            \"value\": {\n              \"stringValue\": \"false\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/vendor/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cores-per-socket\",\n            \"value\": {\n              \"stringValue\": \"8\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.sysctl.kernel.unprivileged_bpf_disabled\",\n            \"value\": {\n              \"stringValue\": \"2\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.revision\",\n            \"value\": {\n              \"stringValue\": \"main-172652de\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-governor\",\n            \"value\": {\n              \"stringValue\": \"schedutil\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L3-kbytes\",\n            \"value\": {\n              \"stringValue\": \"16384\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/min-mhz\",\n            \"value\": {\n              \"stringValue\": \"2200\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-cur-freq-mhz\",\n            \"value\": {\n              \"stringValue\": \"2226\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cpus\",\n            \"value\": {\n              \"stringValue\": \"16\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/min-mhz/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L2-kbytes/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.machine\",\n            \"value\": {\n              \"stringValue\": \"x86_64\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.version\",\n            \"value\": {\n              \"stringValue\": \"v0.0.0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/max-mhz/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/flags\",\n            \"value\": {\n              \"stringValue\": \"3dnowprefetch,abm,adx,aes,aperfmperf,apic,arat,avic,avx,avx2,bmi1,bmi2,bpext,cat_l3,cdp_l3,clflush,clflushopt,clwb,clzero,cmov,cmp_legacy,constant_tsc,cpb,cpuid,cqm,cqm_llc,cqm_mbm_local,cqm_mbm_total,cqm_occup_llc,cr8_legacy,cx16,cx8,de,decodeassists,extapic,extd_apicid,f16c,flushbyasid,fma,fpu,fsgsbase,fxsr,fxsr_opt,ht,hw_pstate,ibpb,ibs,irperf,lahf_lm,lbrv,lm,mba,mca,mce,misalignsse,mmx,mmxext,monitor,movbe,msr,mtrr,mwaitx,nonstop_tsc,nopl,npt,nrip_save,nx,osvw,overflow_recov,pae,pat,pausefilter,pclmulqdq,pdpe1gb,perfctr_core,perfctr_llc,perfctr_nb,pfthreshold,pge,pni,popcnt,pse,pse36,rapl,rdpid,rdpru,rdrand,rdseed,rdt_a,rdtscp,rep_good,sep,sev,sev_es,sha_ni,skinit,smap,smca,smep,ssbd,sse,sse2,sse4_1,sse4_2,sse4a,ssse3,stibp,succor,svm,svm_lock,syscall,tce,topoext,tsc,tsc_scale,umip,v_spec_ctrl,v_vmsave_vmload,vgif,vmcb_clean,vme,vmmcall,wbnoinvd,wdt,x2apic,xgetbv1,xsave,xsavec,xsaveerptr,xsaveopt,xtopology\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.max_elements_per_interval\",\n            \"value\": {\n              \"stringValue\": \"1600\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/model/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-governor/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.known_traces_entries\",\n            \"value\": {\n              \"stringValue\": \"65536\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.probabilistic_threshold\",\n            \"value\": {\n              \"stringValue\": \"100\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L1i-kbytes/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/stepping\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.probabilistic_interval\",\n            \"value\": {\n              \"stringValue\": \"1m0s\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.map_scale_factor\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cpus/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/bugs/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-driver/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L3-kbytes/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cores-per-socket/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-cur-freq-mhz/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.name\",\n            \"value\": {\n              \"stringValue\": \"Hugin\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/max-mhz\",\n            \"value\": {\n              \"stringValue\": \"4426\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.sysctl.net.core.bpf_jit_enable\",\n            \"value\": {\n              \"stringValue\": \"1\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.bpf_log_size\",\n            \"value\": {\n              \"stringValue\": \"65536\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.present_cpu_cores\",\n            \"value\": {\n              \"stringValue\": \"16\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.build_timestamp\",\n            \"value\": {\n              \"stringValue\": \"1721228980\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.kernel_proc_version\",\n            \"value\": {\n              \"stringValue\": \"Linux version 6.9.9-arch1-1 (linux@archlinux) (gcc (GCC) 14.1.1 20240522, GNU ld (GNU Binutils) 2.42.0) #1 SMP PREEMPT_DYNAMIC Fri, 12 Jul 2024 00:06:53 +0000\\n\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/threads-per-core/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L1d-kbytes/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.file\",\n            \"value\": {\n              \"stringValue\": \"/etc/otel/profiling-agent/agent.conf\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.disable_tls\",\n            \"value\": {\n              \"stringValue\": \"true\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.sysctl.kernel.bpf_stats_enabled\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.tags\",\n            \"value\": {\n              \"stringValue\": \"\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/clock/scaling-driver\",\n            \"value\": {\n              \"stringValue\": \"acpi-cpufreq\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/online/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L1d-kbytes\",\n            \"value\": {\n              \"stringValue\": \"32\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.bpf_log_level\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/model-name/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host.arch\",\n            \"value\": {\n              \"stringValue\": \"amd64\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/bugs\",\n            \"value\": {\n              \"stringValue\": \"retbleed,smt_rsb,spec_store_bypass,spectre_v1,spectre_v2,srso,sysret_ss_attrs\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/threads-per-core\",\n            \"value\": {\n              \"stringValue\": \"2\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/online\",\n            \"value\": {\n              \"stringValue\": \"0-15\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/stepping/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/model-name\",\n            \"value\": {\n              \"stringValue\": \"AMD Ryzen 7 3700X 8-Core Processor\"\n            }\n          },\n          {\n            \"key\": \"profiling.host.ip\",\n            \"value\": {\n              \"stringValue\": \"127.0.0.1\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.cache_directory\",\n            \"value\": {\n              \"stringValue\": \"/var/cache/otel/profiling-agent\"\n            }\n          },\n          {\n            \"key\": \"profiling.agent.config.no_kernel_version_check\",\n            \"value\": {\n              \"stringValue\": \"false\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/model\",\n            \"value\": {\n              \"stringValue\": \"113\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/vendor\",\n            \"value\": {\n              \"stringValue\": \"AuthenticAMD\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/flags/socketIDs\",\n            \"value\": {\n              \"stringValue\": \"0\"\n            }\n          },\n          {\n            \"key\": \"host:cpu/cache/L1i-kbytes\",\n            \"value\": {\n              \"stringValue\": \"32\"\n            }\n          },\n          {\n            \"key\": \"profiling.project.id\",\n            \"value\": {\n              \"stringValue\": \"1\"\n            }\n          },\n          {\n            \"key\": \"host.id\",\n            \"value\": {\n              \"stringValue\": \"1693958027216639598\"\n            }\n          },\n          {\n            \"key\": \"host.ip\",\n            \"value\": {\n              \"stringValue\": \"127.0.0.1\"\n            }\n          },\n          {\n            \"key\": \"host.name\",\n            \"value\": {\n              \"stringValue\": \"Hugin\"\n            }\n          },\n          {\n            \"key\": \"service.version\",\n            \"value\": {\n              \"stringValue\": \"\"\n            }\n          },\n          {\n            \"key\": \"os.kernel\",\n            \"value\": {\n              \"stringValue\": \"6.9.9-arch1-1\"\n            }\n          }\n        ]\n      },\n      \"scopeProfiles\": [\n        {\n          \"scope\": {},\n          \"profiles\": [\n            {\n              \"sampleType\": {\n                \"typeStrindex\": 1,\n                \"unitStrindex\": 2\n              },\n              \"samples\": [\n                {\n                  \"stackIndex\": 0,\n                  \"values\": [\n                    \"1\"\n                  ],\n                  \"timestampsUnixNano\": [\n                    \"1721306048731622020\"\n                  ]\n                },\n                {\n                  \"stackIndex\": 1,\n                  \"values\": [\n                    \"1\"\n                  ],\n                  \"timestampsUnixNano\": [\n                    \"1721306049831718725\"\n                  ]\n                },\n                {\n                  \"stackIndex\": 2,\n                  \"values\": [\n                    \"1\"\n                  ],\n                  \"timestampsUnixNano\": [\n                    \"1721306050081621681\"\n                  ]\n                }\n              ],\n              \"timeUnixNano\": \"1721306050081621681\",\n              \"periodType\": {\n                \"typeStrindex\": 3,\n                \"unitStrindex\": 4\n              },\n              \"period\": \"50000000\",\n              \"profileId\": \"YYCY0pps79akwOqAaIDCqA==\"\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"dictionary\": {\n    \"mappingTable\": [\n      {},\n      {\n        \"memoryStart\": \"18698240\",\n        \"memoryLimit\": \"250413056\",\n        \"fileOffset\": \"18694144\",\n        \"filenameStrindex\": 7\n      },\n      {\n        \"memoryStart\": \"15638528\",\n        \"memoryLimit\": \"47255552\",\n        \"fileOffset\": \"15638528\",\n        \"filenameStrindex\": 10\n      },\n      {},\n      {\n        \"memoryStart\": \"147456\",\n        \"memoryLimit\": \"1638400\",\n        \"fileOffset\": \"147456\",\n        \"filenameStrindex\": 15\n      }\n    ],\n    \"locationTable\": [\n      {\n        \"mappingIndex\": 1,\n        \"address\": \"95210353\"\n      },\n      {\n        \"mappingIndex\": 2,\n        \"address\": \"15945263\"\n      },\n      {\n        \"mappingIndex\": 2,\n        \"address\": \"15952400\"\n      },\n      {\n        \"mappingIndex\": 2,\n        \"address\": \"15953899\"\n      },\n      {\n        \"mappingIndex\": 2,\n        \"address\": \"16148175\"\n      },\n      {\n        \"mappingIndex\": 3,\n        \"address\": \"4770577\",\n        \"lines\": [\n          {\n            \"functionIndex\": 1\n          }\n        ]\n      },\n      {\n        \"mappingIndex\": 3,\n        \"address\": \"4773632\",\n        \"lines\": [\n          {\n            \"functionIndex\": 2\n          }\n        ]\n      },\n      {\n        \"mappingIndex\": 3,\n        \"address\": \"14783666\",\n        \"lines\": [\n          {\n            \"functionIndex\": 3\n          }\n        ]\n      },\n      {\n        \"mappingIndex\": 3,\n        \"address\": \"16777518\",\n        \"lines\": [\n          {\n            \"functionIndex\": 4\n          }\n        ]\n      },\n      {\n        \"mappingIndex\": 4,\n        \"address\": \"1139937\"\n      },\n      {\n        \"mappingIndex\": 1,\n        \"address\": \"117834912\"\n      }\n    ],\n    \"functionTable\": [\n      {},\n      {\n        \"nameStrindex\": 20\n      },\n      {\n        \"nameStrindex\": 17\n      },\n      {\n        \"nameStrindex\": 18\n      },\n      {\n        \"nameStrindex\": 19\n      }\n    ],\n    \"stringTable\": [\n      \"\",\n      \"samples\",\n      \"count\",\n      \"cpu\",\n      \"nanoseconds\",\n      \"hYmAzQVF8vy8MWbzsKpQNw\",\n      \"native\",\n      \"chromium\",\n      \"fab9b8c848218405738c11a7ec4982e9\",\n      \"4N3KEcGylb5Qoi2905c1ZA\",\n      \"dockerd\",\n      \"7dab4a2e0005d025e75cc72191f8d6bf\",\n      \"UaO9bysJnAYXFYobSdHXqg\",\n      \"kernel\",\n      \"cfc3dc7d1638c1284a6b62d4b5c0d74e\",\n      \"libc.so.6\",\n      \"982ed6c7a77f99f0ae746be0187953bf\",\n      \"__x64_sys_epoll_wait\",\n      \"do_syscall_64\",\n      \"entry_SYSCALL_64_after_hwframe\",\n      \"do_epoll_wait\",\n      \"thread.name\"\n    ],\n    \"attributeTable\": [\n      {\n        \"keyStrindex\": 21,\n        \"value\": {\n          \"stringValue\": \"chromium\"\n        }\n      },\n      {\n        \"keyStrindex\": 21,\n        \"value\": {\n          \"stringValue\": \"dockerd\"\n        }\n      },\n      {\n        \"keyStrindex\": 21,\n        \"value\": {\n          \"stringValue\": \"ThreadPoolServi\"\n        }\n      }\n    ],\n    \"stackTable\": [\n      {\n        \"locationIndices\": [\n          0\n        ]\n      },\n      {\n        \"locationIndices\": [\n          1,\n          2,\n          3,\n          4\n        ]\n      },\n      {\n        \"locationIndices\": [\n          5,\n          6,\n          7,\n          8,\n          9,\n          10\n        ]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/testcases/profiles/telegraf.conf",
    "content": "[[inputs.opentelemetry]]\n"
  },
  {
    "path": "plugins/inputs/opentelemetry/writer.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/influxdb-observability/common\"\n\t\"github.com/influxdata/influxdb-observability/otel2influx\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\nvar (\n\t_ otel2influx.InfluxWriter      = (*writeToAccumulator)(nil)\n\t_ otel2influx.InfluxWriterBatch = (*writeToAccumulator)(nil)\n)\n\ntype writeToAccumulator struct {\n\taccumulator telegraf.Accumulator\n}\n\n// NewBatch creates a new batch for writing telemetry data.\nfunc (w *writeToAccumulator) NewBatch() otel2influx.InfluxWriterBatch {\n\treturn w\n}\n\n// EnqueuePoint adds a telemetry data point to the accumulator.\nfunc (w *writeToAccumulator) EnqueuePoint(\n\t_ context.Context,\n\tmeasurement string,\n\ttags map[string]string,\n\tfields map[string]interface{},\n\tts time.Time,\n\tvType common.InfluxMetricValueType,\n) error {\n\tswitch vType {\n\tcase common.InfluxMetricValueTypeUntyped:\n\t\tw.accumulator.AddFields(measurement, fields, tags, ts)\n\tcase common.InfluxMetricValueTypeGauge:\n\t\tw.accumulator.AddGauge(measurement, fields, tags, ts)\n\tcase common.InfluxMetricValueTypeSum:\n\t\tw.accumulator.AddCounter(measurement, fields, tags, ts)\n\tcase common.InfluxMetricValueTypeHistogram:\n\t\tw.accumulator.AddHistogram(measurement, fields, tags, ts)\n\tcase common.InfluxMetricValueTypeSummary:\n\t\tw.accumulator.AddSummary(measurement, fields, tags, ts)\n\tdefault:\n\t\treturn fmt.Errorf(\"unrecognized InfluxMetricValueType %q\", vType)\n\t}\n\treturn nil\n}\n\n// WriteBatch does nothing.\nfunc (*writeToAccumulator) WriteBatch(context.Context) error {\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/README.md",
    "content": "# OpenWeatherMap Input Plugin\n\nThis plugin collects weather and forecast data from the\n[OpenWeatherMap][openweathermap] service.\n\n> [!IMPORTANT]\n> To use this plugin you will need an [APP-ID][api_key] to work.\n\n⭐ Telegraf v1.11.0\n🏷️ applications, web\n💻 all\n\n[openweathermap]: https://openweathermap.org\n[api_key]: https://openweathermap.org/appid\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read current weather and forecasts data from openweathermap.org\n[[inputs.openweathermap]]\n  ## OpenWeatherMap API key.\n  app_id = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n\n  ## City ID's to collect weather data from.\n  city_id = [\"5391959\"]\n\n  ## Language of the description field. Can be one of \"ar\", \"bg\",\n  ## \"ca\", \"cz\", \"de\", \"el\", \"en\", \"fa\", \"fi\", \"fr\", \"gl\", \"hr\", \"hu\",\n  ## \"it\", \"ja\", \"kr\", \"la\", \"lt\", \"mk\", \"nl\", \"pl\", \"pt\", \"ro\", \"ru\",\n  ## \"se\", \"sk\", \"sl\", \"es\", \"tr\", \"ua\", \"vi\", \"zh_cn\", \"zh_tw\"\n  # lang = \"en\"\n\n  ## APIs to fetch; can contain \"weather\" or \"forecast\".\n  # fetch = [\"weather\", \"forecast\"]\n\n  ## OpenWeatherMap base URL\n  # base_url = \"https://api.openweathermap.org/\"\n\n  ## Timeout for HTTP response.\n  # response_timeout = \"5s\"\n\n  ## Preferred unit system for temperature and wind speed. Can be one of\n  ## \"metric\", \"imperial\", or \"standard\".\n  ## The default is \"metric\" if not specified.\n  # units = \"metric\"\n\n  ## Style to query the current weather; available options\n  ##   batch      -- query multiple cities at once using the \"group\" endpoint\n  ##   individual -- query each city individually using the \"weather\" endpoint\n  ## You should use \"individual\" here as it is documented and provides more\n  ## frequent updates. The default is \"batch\" for backward compatibility.\n  # query_style = \"batch\"\n\n  ## Query interval to fetch data.\n  ## By default the global 'interval' setting is used. You should override the\n  ## interval here if the global setting is shorter than 10 minutes as\n  ## OpenWeatherMap weather data is only updated every 10 minutes.\n  # interval = \"10m\"\n```\n\nCity identifiers can be found in the [city list file][city_list] or you search\nyour city by name on the [OpenWeatherMap website][openweathermap] and use the\nnumeric last element of the resulting URL.\nLanguage identifiers can be found in the [API documentation][languages].\n\n[city_list]: http://bulk.openweathermap.org/sample/city.list.json.gz\n[languages]: https://openweathermap.org/current#multi\n\n## Metrics\n\n- weather\n  - tags:\n    - city_id\n    - forecast\n    - condition_id\n    - condition_main\n  - fields:\n    - cloudiness            (int, percent)\n    - humidity              (int, percent)\n    - pressure              (float)       - atmospheric pressure hPa\n    - rain                  (float)       - rain volume in mm for the last 1-3h\n                                            (depending on API response)\n    - snow                  (float)       - snow volume in mm for the last 1-3h\n                                            (depending on API response)\n    - sunrise               (int)         - nanoseconds since unix epoch\n    - sunset                (int)         - nanoseconds since unix epoch\n    - temperature           (float, degrees)\n    - feels_like            (float, degrees)\n    - visibility            (int, meters) - not available on forecast data\n    - wind_degrees          (float)       - wind direction in degrees\n    - wind_speed            (float)       - wind speed in meters/sec or miles/sec\n    - condition_description (string, localized long description)\n    - condition_icon\n\nDocumentation for condition ID, icon, and main is can be found in the\n[documentation][weather_conditions].\n\n[weather_conditions]: https://openweathermap.org/weather-conditions\n\n## Example Output\n\n```text\nweather,city=San\\ Francisco,city_id=5391959,condition_id=803,condition_main=Clouds,country=US,forecast=114h,host=robot pressure=1027,temperature=10.09,wind_degrees=34,wind_speed=1.24,condition_description=\"broken clouds\",cloudiness=80i,humidity=67i,rain=0,feels_like=8.9,condition_icon=\"04n\" 1645952400000000000\nweather,city=San\\ Francisco,city_id=5391959,condition_id=804,condition_main=Clouds,country=US,forecast=117h,host=robot humidity=65i,rain=0,temperature=10.12,wind_degrees=31,cloudiness=90i,pressure=1026,feels_like=8.88,wind_speed=1.31,condition_description=\"overcast clouds\",condition_icon=\"04n\" 1645963200000000000\nweather,city=San\\ Francisco,city_id=5391959,condition_id=804,condition_main=Clouds,country=US,forecast=120h,host=robot cloudiness=100i,humidity=61i,rain=0,temperature=10.28,wind_speed=1.94,condition_icon=\"04d\",pressure=1027,feels_like=8.96,wind_degrees=16,condition_description=\"overcast clouds\" 1645974000000000000\n```\n"
  },
  {
    "path": "plugins/inputs/openweathermap/openweathermap.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage openweathermap\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// https://openweathermap.org/current#severalid\n// Limit for the number of city IDs per request.\nconst maxIDsPerBatch int = 20\n\ntype OpenWeatherMap struct {\n\tAppID           string          `toml:\"app_id\"`\n\tCityID          []string        `toml:\"city_id\"`\n\tLang            string          `toml:\"lang\"`\n\tFetch           []string        `toml:\"fetch\"`\n\tBaseURL         string          `toml:\"base_url\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\tUnits           string          `toml:\"units\"`\n\tQueryStyle      string          `toml:\"query_style\"`\n\n\tclient        *http.Client\n\tcityIDBatches []string\n\tbaseParsedURL *url.URL\n}\n\nfunc (*OpenWeatherMap) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (n *OpenWeatherMap) Init() error {\n\t// Set the default for the base-URL if not given\n\tif n.BaseURL == \"\" {\n\t\tn.BaseURL = \"https://api.openweathermap.org/\"\n\t}\n\n\t// Check the query-style setting\n\tswitch n.QueryStyle {\n\tcase \"\":\n\t\tn.QueryStyle = \"batch\"\n\tcase \"batch\", \"individual\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown query-style: %s\", n.QueryStyle)\n\t}\n\n\t// Check the unit setting\n\tswitch n.Units {\n\tcase \"\":\n\t\tn.Units = \"metric\"\n\tcase \"imperial\", \"standard\", \"metric\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown units: %s\", n.Units)\n\t}\n\n\t// Check the language setting\n\tswitch n.Lang {\n\tcase \"\":\n\t\tn.Lang = \"en\"\n\tcase \"ar\", \"bg\", \"ca\", \"cz\", \"de\", \"el\", \"en\", \"fa\", \"fi\", \"fr\", \"gl\",\n\t\t\"hr\", \"hu\", \"it\", \"ja\", \"kr\", \"la\", \"lt\", \"mk\", \"nl\", \"pl\",\n\t\t\"pt\", \"ro\", \"ru\", \"se\", \"sk\", \"sl\", \"es\", \"tr\", \"ua\", \"vi\",\n\t\t\"zh_cn\", \"zh_tw\":\n\t\t// Do nothing, those are valid\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown language: %s\", n.Lang)\n\t}\n\n\t// Check the properties to fetch\n\tif len(n.Fetch) == 0 {\n\t\tn.Fetch = []string{\"weather\", \"forecast\"}\n\t}\n\tfor _, fetch := range n.Fetch {\n\t\tswitch fetch {\n\t\tcase \"forecast\", \"weather\":\n\t\t\t// Do nothing, those are valid\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown property to fetch: %s\", fetch)\n\t\t}\n\t}\n\n\t// Split the city IDs into batches smaller than the maximum size\n\tnBatches := len(n.CityID) / maxIDsPerBatch\n\tif len(n.CityID)%maxIDsPerBatch != 0 {\n\t\tnBatches++\n\t}\n\tbatches := make([][]string, nBatches)\n\tfor i, id := range n.CityID {\n\t\tbatch := i / maxIDsPerBatch\n\t\tbatches[batch] = append(batches[batch], id)\n\t}\n\tn.cityIDBatches = make([]string, 0, nBatches)\n\tfor _, batch := range batches {\n\t\tn.cityIDBatches = append(n.cityIDBatches, strings.Join(batch, \",\"))\n\t}\n\n\t// Parse the base-URL used later to construct the property API endpoint\n\tu, err := url.Parse(n.BaseURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tn.baseParsedURL = u\n\n\t// Create an HTTP client to be used in each collection interval\n\tn.client = &http.Client{\n\t\tTransport: &http.Transport{},\n\t\tTimeout:   time.Duration(n.ResponseTimeout),\n\t}\n\n\treturn nil\n}\n\nfunc (n *OpenWeatherMap) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, fetch := range n.Fetch {\n\t\tswitch fetch {\n\t\tcase \"forecast\":\n\t\t\tfor _, cityID := range n.CityID {\n\t\t\t\twg.Add(1)\n\t\t\t\tgo func(city string) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\tacc.AddError(n.gatherForecast(acc, city))\n\t\t\t\t}(cityID)\n\t\t\t}\n\t\tcase \"weather\":\n\t\t\tswitch n.QueryStyle {\n\t\t\tcase \"individual\":\n\t\t\t\tfor _, cityID := range n.CityID {\n\t\t\t\t\twg.Add(1)\n\t\t\t\t\tgo func(city string) {\n\t\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\t\tacc.AddError(n.gatherWeather(acc, city))\n\t\t\t\t\t}(cityID)\n\t\t\t\t}\n\t\t\tcase \"batch\":\n\t\t\t\tfor _, cityIDs := range n.cityIDBatches {\n\t\t\t\t\twg.Add(1)\n\t\t\t\t\tgo func(cities string) {\n\t\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\t\tacc.AddError(n.gatherWeatherBatch(acc, cities))\n\t\t\t\t\t}(cityIDs)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (n *OpenWeatherMap) gatherWeather(acc telegraf.Accumulator, city string) error {\n\t// Query the data and decode the response\n\taddr := n.formatURL(\"/data/2.5/weather\", city)\n\tbuf, err := n.gatherURL(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", addr, err)\n\t}\n\n\tvar e weatherEntry\n\tif err := json.Unmarshal(buf, &e); err != nil {\n\t\treturn fmt.Errorf(\"parsing JSON response failed: %w\", err)\n\t}\n\n\t// Construct the metric\n\ttm := time.Unix(e.Dt, 0)\n\n\tfields := map[string]interface{}{\n\t\t\"cloudiness\":   e.Clouds.All,\n\t\t\"humidity\":     e.Main.Humidity,\n\t\t\"pressure\":     e.Main.Pressure,\n\t\t\"rain\":         e.rain(),\n\t\t\"snow\":         e.snow(),\n\t\t\"sunrise\":      time.Unix(e.Sys.Sunrise, 0).UnixNano(),\n\t\t\"sunset\":       time.Unix(e.Sys.Sunset, 0).UnixNano(),\n\t\t\"temperature\":  e.Main.Temp,\n\t\t\"feels_like\":   e.Main.Feels,\n\t\t\"visibility\":   e.Visibility,\n\t\t\"wind_degrees\": e.Wind.Deg,\n\t\t\"wind_speed\":   e.Wind.Speed,\n\t}\n\ttags := map[string]string{\n\t\t\"city\":     e.Name,\n\t\t\"city_id\":  strconv.FormatInt(e.ID, 10),\n\t\t\"country\":  e.Sys.Country,\n\t\t\"forecast\": \"*\",\n\t}\n\n\tif len(e.Weather) > 0 {\n\t\tfields[\"condition_description\"] = e.Weather[0].Description\n\t\tfields[\"condition_icon\"] = e.Weather[0].Icon\n\t\ttags[\"condition_id\"] = strconv.FormatInt(e.Weather[0].ID, 10)\n\t\ttags[\"condition_main\"] = e.Weather[0].Main\n\t}\n\n\tacc.AddFields(\"weather\", fields, tags, tm)\n\n\treturn nil\n}\n\nfunc (n *OpenWeatherMap) gatherWeatherBatch(acc telegraf.Accumulator, cities string) error {\n\t// Query the data and decode the response\n\taddr := n.formatURL(\"/data/2.5/group\", cities)\n\tbuf, err := n.gatherURL(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", addr, err)\n\t}\n\n\tvar status status\n\tif err := json.Unmarshal(buf, &status); err != nil {\n\t\treturn fmt.Errorf(\"parsing JSON response failed: %w\", err)\n\t}\n\n\t// Construct the metrics\n\tfor _, e := range status.List {\n\t\ttm := time.Unix(e.Dt, 0)\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"cloudiness\":   e.Clouds.All,\n\t\t\t\"humidity\":     e.Main.Humidity,\n\t\t\t\"pressure\":     e.Main.Pressure,\n\t\t\t\"rain\":         e.rain(),\n\t\t\t\"snow\":         e.snow(),\n\t\t\t\"sunrise\":      time.Unix(e.Sys.Sunrise, 0).UnixNano(),\n\t\t\t\"sunset\":       time.Unix(e.Sys.Sunset, 0).UnixNano(),\n\t\t\t\"temperature\":  e.Main.Temp,\n\t\t\t\"feels_like\":   e.Main.Feels,\n\t\t\t\"visibility\":   e.Visibility,\n\t\t\t\"wind_degrees\": e.Wind.Deg,\n\t\t\t\"wind_speed\":   e.Wind.Speed,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"city\":     e.Name,\n\t\t\t\"city_id\":  strconv.FormatInt(e.ID, 10),\n\t\t\t\"country\":  e.Sys.Country,\n\t\t\t\"forecast\": \"*\",\n\t\t}\n\n\t\tif len(e.Weather) > 0 {\n\t\t\tfields[\"condition_description\"] = e.Weather[0].Description\n\t\t\tfields[\"condition_icon\"] = e.Weather[0].Icon\n\t\t\ttags[\"condition_id\"] = strconv.FormatInt(e.Weather[0].ID, 10)\n\t\t\ttags[\"condition_main\"] = e.Weather[0].Main\n\t\t}\n\n\t\tacc.AddFields(\"weather\", fields, tags, tm)\n\t}\n\n\treturn nil\n}\n\nfunc (n *OpenWeatherMap) gatherForecast(acc telegraf.Accumulator, city string) error {\n\t// Query the data and decode the response\n\taddr := n.formatURL(\"/data/2.5/forecast\", city)\n\tbuf, err := n.gatherURL(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", addr, err)\n\t}\n\n\tvar status status\n\tif err := json.Unmarshal(buf, &status); err != nil {\n\t\treturn fmt.Errorf(\"parsing JSON response failed: %w\", err)\n\t}\n\n\t// Construct the metric\n\ttags := map[string]string{\n\t\t\"city_id\":  strconv.FormatInt(status.City.ID, 10),\n\t\t\"forecast\": \"*\",\n\t\t\"city\":     status.City.Name,\n\t\t\"country\":  status.City.Country,\n\t}\n\tfor i, e := range status.List {\n\t\ttm := time.Unix(e.Dt, 0)\n\t\tfields := map[string]interface{}{\n\t\t\t\"cloudiness\":   e.Clouds.All,\n\t\t\t\"humidity\":     e.Main.Humidity,\n\t\t\t\"pressure\":     e.Main.Pressure,\n\t\t\t\"rain\":         e.rain(),\n\t\t\t\"snow\":         e.snow(),\n\t\t\t\"temperature\":  e.Main.Temp,\n\t\t\t\"feels_like\":   e.Main.Feels,\n\t\t\t\"wind_degrees\": e.Wind.Deg,\n\t\t\t\"wind_speed\":   e.Wind.Speed,\n\t\t}\n\t\tif len(e.Weather) > 0 {\n\t\t\tfields[\"condition_description\"] = e.Weather[0].Description\n\t\t\tfields[\"condition_icon\"] = e.Weather[0].Icon\n\t\t\ttags[\"condition_id\"] = strconv.FormatInt(e.Weather[0].ID, 10)\n\t\t\ttags[\"condition_main\"] = e.Weather[0].Main\n\t\t}\n\t\ttags[\"forecast\"] = fmt.Sprintf(\"%dh\", (i+1)*3)\n\t\tacc.AddFields(\"weather\", fields, tags, tm)\n\t}\n\n\treturn nil\n}\n\nfunc (n *OpenWeatherMap) formatURL(path, city string) string {\n\tv := url.Values{\n\t\t\"id\":    []string{city},\n\t\t\"APPID\": []string{n.AppID},\n\t\t\"lang\":  []string{n.Lang},\n\t\t\"units\": []string{n.Units},\n\t}\n\n\trelative := &url.URL{\n\t\tPath:     path,\n\t\tRawQuery: v.Encode(),\n\t}\n\n\treturn n.baseParsedURL.ResolveReference(relative).String()\n}\n\nfunc (n *OpenWeatherMap) gatherURL(addr string) ([]byte, error) {\n\tresp, err := n.client.Get(addr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error making HTTP request to %q: %w\", addr, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"%s returned HTTP status %s\", addr, resp.Status)\n\t}\n\n\tmediaType, _, err := mime.ParseMediaType(resp.Header.Get(\"Content-Type\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif mediaType != \"application/json\" {\n\t\treturn nil, fmt.Errorf(\"%s returned unexpected content type %s\", addr, mediaType)\n\t}\n\n\treturn io.ReadAll(resp.Body)\n}\n\nfunc init() {\n\tinputs.Add(\"openweathermap\", func() telegraf.Input {\n\t\treturn &OpenWeatherMap{\n\t\t\tResponseTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/openweathermap_test.go",
    "content": "package openweathermap\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestFormatURL(t *testing.T) {\n\tn := &OpenWeatherMap{\n\t\tAppID:   \"appid\",\n\t\tUnits:   \"metric\",\n\t\tLang:    \"de\",\n\t\tBaseURL: \"http://foo.com\",\n\t}\n\trequire.NoError(t, n.Init())\n\n\trequire.Equal(t,\n\t\t\"http://foo.com/data/2.5/forecast?APPID=appid&id=12345&lang=de&units=metric\",\n\t\tn.formatURL(\"/data/2.5/forecast\", \"12345\"))\n}\n\nfunc TestDefaultUnits(t *testing.T) {\n\tn := &OpenWeatherMap{}\n\trequire.NoError(t, n.Init())\n\n\trequire.Equal(t, \"metric\", n.Units)\n}\n\nfunc TestDefaultLang(t *testing.T) {\n\tn := &OpenWeatherMap{}\n\trequire.NoError(t, n.Init())\n\n\trequire.Equal(t, \"en\", n.Lang)\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"openweathermap\", func() telegraf.Input {\n\t\treturn &OpenWeatherMap{\n\t\t\tResponseTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n\n\t// Prepare the influx parser for expectations\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\t// Read the input data\n\t\t\tinput, err := readInputData(testcasePath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Start the test-server\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Lookup the response\n\t\t\t\tkey := strings.TrimPrefix(r.URL.Path, \"/data/2.5/\")\n\t\t\t\tif resp, found := input[key]; found {\n\t\t\t\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\t\t\t\tif _, err := w.Write(resp); err != nil {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Try to append the key and find the response\n\t\t\t\tids := strings.Split(r.URL.Query().Get(\"id\"), \",\")\n\t\t\t\tif len(ids) > 1 {\n\t\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif len(ids) == 1 {\n\t\t\t\t\tkey += \"_\" + ids[0]\n\t\t\t\t\tif resp, found := input[key]; found {\n\t\t\t\t\t\tw.Header()[\"Content-Type\"] = []string{\"application/json\"}\n\t\t\t\t\t\tif _, err := w.Write(resp); err != nil {\n\t\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\t\tt.Error(err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Fake the reading\n\t\t\tplugin := cfg.Inputs[0].Input.(*OpenWeatherMap)\n\t\t\tplugin.BaseURL = server.URL\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tif len(acc.Errors) > 0 {\n\t\t\t\tactualErrorMsgs := make([]string, 0, len(acc.Errors))\n\t\t\t\tfor _, err := range acc.Errors {\n\t\t\t\t\tactualErrorMsgs = append(actualErrorMsgs, err.Error())\n\t\t\t\t}\n\t\t\t\trequire.ElementsMatch(t, actualErrorMsgs, expectedErrors)\n\t\t\t}\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc readInputData(path string) (map[string][]byte, error) {\n\tpattern := filepath.Join(path, \"response_*.json\")\n\tmatches, err := filepath.Glob(pattern)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Iterate over the response_*.json files and read the into the data map\n\tdata := make(map[string][]byte, len(matches))\n\tfor _, filename := range matches {\n\t\tresp, err := os.ReadFile(filename)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"reading response %q failed: %w\", filename, err)\n\t\t}\n\t\tkey := filepath.Base(filename)\n\t\tkey = strings.TrimPrefix(key, \"response_\")\n\t\tkey = strings.TrimSuffix(key, \".json\")\n\t\tdata[key] = resp\n\t}\n\treturn data, nil\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/sample.conf",
    "content": "# Read current weather and forecasts data from openweathermap.org\n[[inputs.openweathermap]]\n  ## OpenWeatherMap API key.\n  app_id = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n\n  ## City ID's to collect weather data from.\n  city_id = [\"5391959\"]\n\n  ## Language of the description field. Can be one of \"ar\", \"bg\",\n  ## \"ca\", \"cz\", \"de\", \"el\", \"en\", \"fa\", \"fi\", \"fr\", \"gl\", \"hr\", \"hu\",\n  ## \"it\", \"ja\", \"kr\", \"la\", \"lt\", \"mk\", \"nl\", \"pl\", \"pt\", \"ro\", \"ru\",\n  ## \"se\", \"sk\", \"sl\", \"es\", \"tr\", \"ua\", \"vi\", \"zh_cn\", \"zh_tw\"\n  # lang = \"en\"\n\n  ## APIs to fetch; can contain \"weather\" or \"forecast\".\n  # fetch = [\"weather\", \"forecast\"]\n\n  ## OpenWeatherMap base URL\n  # base_url = \"https://api.openweathermap.org/\"\n\n  ## Timeout for HTTP response.\n  # response_timeout = \"5s\"\n\n  ## Preferred unit system for temperature and wind speed. Can be one of\n  ## \"metric\", \"imperial\", or \"standard\".\n  ## The default is \"metric\" if not specified.\n  # units = \"metric\"\n\n  ## Style to query the current weather; available options\n  ##   batch      -- query multiple cities at once using the \"group\" endpoint\n  ##   individual -- query each city individually using the \"weather\" endpoint\n  ## You should use \"individual\" here as it is documented and provides more\n  ## frequent updates. The default is \"batch\" for backward compatibility.\n  # query_style = \"batch\"\n\n  ## Query interval to fetch data.\n  ## By default the global 'interval' setting is used. You should override the\n  ## interval here if the global setting is shorter than 10 minutes as\n  ## OpenWeatherMap weather data is only updated every 10 minutes.\n  # interval = \"10m\"\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/forecast/expected.out",
    "content": "weather,city=Paris,city_id=2988507,condition_id=500,condition_main=Rain,country=FR,forecast=3h cloudiness=88i,condition_description=\"light rain\",condition_icon=\"10n\",feels_like=5.71,humidity=91i,pressure=1018.65,rain=0.035,snow=0,temperature=6.71,wind_degrees=228.501,wind_speed=3.76 1543622400000000000\nweather,city=Paris,city_id=2988507,condition_id=500,condition_main=Rain,country=FR,forecast=6h cloudiness=92i,condition_description=\"light rain\",condition_icon=\"10n\",feels_like=5.38,humidity=98i,pressure=1032.18,rain=0.049999999999997,snow=0,temperature=6.38,wind_degrees=335.005,wind_speed=2.66 1544043600000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/forecast/response_forecast.json",
    "content": "{\n    \"city\": {\n        \"coord\": {\n            \"lat\": 48.8534,\n            \"lon\": 2.3488\n        },\n        \"country\": \"FR\",\n        \"id\": 2988507,\n        \"name\": \"Paris\"\n    },\n    \"cnt\": 40,\n    \"cod\": \"200\",\n    \"list\": [\n        {\n            \"clouds\": {\n                \"all\": 88\n            },\n            \"dt\": 1543622400,\n            \"dt_txt\": \"2018-12-01 00:00:00\",\n            \"main\": {\n                \"grnd_level\": 1018.65,\n                \"humidity\": 91,\n                \"pressure\": 1018.65,\n                \"sea_level\": 1030.99,\n                \"temp\": 6.71,\n                \"feels_like\": 5.71,\n                \"temp_kf\": -2.14\n            },\n            \"rain\": {\n                \"3h\": 0.035\n            },\n            \"sys\": {\n                \"pod\": \"n\"\n            },\n            \"weather\": [\n                {\n                    \"description\": \"light rain\",\n                    \"icon\": \"10n\",\n                    \"id\": 500,\n                    \"main\": \"Rain\"\n                }\n            ],\n            \"wind\": {\n                \"deg\": 228.501,\n                \"speed\": 3.76\n            }\n        },\n        {\n            \"clouds\": {\n                \"all\": 92\n            },\n            \"dt\": 1544043600,\n            \"dt_txt\": \"2018-12-05 21:00:00\",\n            \"main\": {\n                \"grnd_level\": 1032.18,\n                \"humidity\": 98,\n                \"pressure\": 1032.18,\n                \"sea_level\": 1044.78,\n                \"temp\": 6.38,\n                \"feels_like\": 5.38,\n                \"temp_kf\": 0\n            },\n            \"rain\": {\n                \"3h\": 0.049999999999997\n            },\n            \"sys\": {\n                \"pod\": \"n\"\n            },\n            \"weather\": [\n                {\n                    \"description\": \"light rain\",\n                    \"icon\": \"10n\",\n                    \"id\": 500,\n                    \"main\": \"Rain\"\n                }\n            ],\n            \"wind\": {\n                \"deg\": 335.005,\n                \"speed\": 2.66\n            }\n        }\n    ],\n    \"message\": 0.0025\n}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/forecast/response_group.json",
    "content": "{}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/forecast/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"2988507\"]\n  fetch = [\"weather\", \"forecast\"]\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/rain_batch/expected.out",
    "content": "weather,city=Paris,city_id=111,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=1,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=222,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=3,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=333,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=1.3,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=444,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/rain_batch/response_group.json",
    "content": "{\n    \"cnt\": 2,\n    \"list\": [{\n        \"dt\": 1544194800,\n        \"id\": 111,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"rain\": {\n            \"1h\": 1.000\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 222,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"rain\": {\n            \"3h\": 3.000\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 333,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"rain\": {\n            \"1h\": 1.300,\n            \"3h\": 999\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 444,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    }]\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/rain_batch/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"111\", \"222\", \"333\", \"444\"]\n  fetch = [\"weather\"]\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/snow_batch/expected.out",
    "content": "weather,city=Paris,city_id=111,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=1,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=222,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=3,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=333,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=1.3,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\nweather,city=Paris,city_id=444,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/snow_batch/response_group.json",
    "content": "{\n    \"cnt\": 2,\n    \"list\": [{\n        \"dt\": 1544194800,\n        \"id\": 111,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"snow\": {\n            \"1h\": 1.000\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 222,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"snow\": {\n            \"3h\": 3.000\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 333,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"snow\": {\n            \"1h\": 1.300,\n            \"3h\": 999\n        },\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    },\n    {\n        \"dt\": 1544194800,\n        \"id\": 444,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    }]\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/snow_batch/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"111\", \"222\", \"333\", \"444\"]\n  fetch = [\"weather\"]\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather/expected.out",
    "content": "weather,city=Paris,city_id=2988507,condition_id=300,condition_main=Drizzle,country=FR,forecast=* cloudiness=0i,condition_description=\"light intensity drizzle\",condition_icon=\"09d\",feels_like=8.25,humidity=87i,pressure=1007,rain=0,snow=0,sunrise=1544167818000000000i,sunset=1544198047000000000i,temperature=9.25,visibility=10000i,wind_degrees=290,wind_speed=8.7 1544194800000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather/response_group.json",
    "content": "{\n    \"cnt\": 1,\n    \"list\": [{\n        \"clouds\": {\n            \"all\": 0\n        },\n        \"coord\": {\n            \"lat\": 48.85,\n            \"lon\": 2.35\n        },\n        \"dt\": 1544194800,\n        \"id\": 2988507,\n        \"main\": {\n            \"humidity\": 87,\n            \"pressure\": 1007,\n            \"temp\": 9.25,\n            \"feels_like\": 8.25\n        },\n        \"name\": \"Paris\",\n        \"sys\": {\n            \"country\": \"FR\",\n            \"id\": 6550,\n            \"message\": 0.002,\n            \"sunrise\": 1544167818,\n            \"sunset\": 1544198047,\n            \"type\": 1\n        },\n        \"visibility\": 10000,\n        \"weather\": [\n            {\n                \"description\": \"light intensity drizzle\",\n                \"icon\": \"09d\",\n                \"id\": 300,\n                \"main\": \"Drizzle\"\n            }\n        ],\n        \"wind\": {\n            \"deg\": 290,\n            \"speed\": 8.7\n        }\n    }]\n}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"2988507\"]\n  fetch = [\"weather\"]\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_batch/expected.out",
    "content": "weather,city=Moscow,city_id=524901,condition_id=802,condition_main=Clouds,country=RU,forecast=* cloudiness=40i,condition_description=\"scattered clouds\",condition_icon=\"03d\",feels_like=8.57,humidity=46i,pressure=1014,rain=0,snow=0,sunrise=1556416455000000000i,sunset=1556470779000000000i,temperature=9.57,visibility=10000i,wind_degrees=60,wind_speed=5 1556444155000000000\nweather,city=Kiev,city_id=703448,condition_id=520,condition_main=Rain,country=UA,forecast=* cloudiness=0i,condition_description=\"light intensity shower rain\",condition_icon=\"09d\",feels_like=18.29,humidity=63i,pressure=1009,rain=0,snow=0,sunrise=1556419155000000000i,sunset=1556471486000000000i,temperature=19.29,visibility=10000i,wind_degrees=0,wind_speed=1 1556444155000000000\nweather,city=London,city_id=2643743,condition_id=803,condition_main=Clouds,country=GB,forecast=* cloudiness=75i,condition_description=\"broken clouds\",condition_icon=\"04d\",feels_like=9.62,humidity=66i,pressure=1019,rain=0.072,snow=0,sunrise=1556426319000000000i,sunset=1556479032000000000i,temperature=10.62,visibility=10000i,wind_degrees=290,wind_speed=6.2 1556444155000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_batch/response_forecast.json",
    "content": "{}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_batch/response_group.json",
    "content": "{\n\t\"cnt\": 3,\n\t\"list\": [{\n\t\t\"coord\": {\n\t\t\t\"lon\": 37.62,\n\t\t\t\"lat\": 55.75\n\t\t},\n\t\t\"sys\": {\n\t\t\t\"type\": 1,\n\t\t\t\"id\": 9029,\n\t\t\t\"message\": 0.0061,\n\t\t\t\"country\": \"RU\",\n\t\t\t\"sunrise\": 1556416455,\n\t\t\t\"sunset\": 1556470779\n\t\t},\n\t\t\"weather\": [{\n\t\t\t\"id\": 802,\n\t\t\t\"main\": \"Clouds\",\n\t\t\t\"description\": \"scattered clouds\",\n\t\t\t\"icon\": \"03d\"\n\t\t}],\n\t\t\"main\": {\n\t\t\t\"temp\": 9.57,\n\t\t\t\"feels_like\": 8.57,\n\t\t\t\"pressure\": 1014,\n\t\t\t\"humidity\": 46\n\t\t},\n\t\t\"visibility\": 10000,\n\t\t\"wind\": {\n\t\t\t\"speed\": 5,\n\t\t\t\"deg\": 60\n\t\t},\n\t\t\"clouds\": {\n\t\t\t\"all\": 40\n\t\t},\n\t\t\"dt\": 1556444155,\n\t\t\"id\": 524901,\n\t\t\"name\": \"Moscow\"\n\t}, {\n\t\t\"coord\": {\n\t\t\t\"lon\": 30.52,\n\t\t\t\"lat\": 50.43\n\t\t},\n\t\t\"sys\": {\n\t\t\t\"type\": 1,\n\t\t\t\"id\": 8903,\n\t\t\t\"message\": 0.0076,\n\t\t\t\"country\": \"UA\",\n\t\t\t\"sunrise\": 1556419155,\n\t\t\t\"sunset\": 1556471486\n\t\t},\n\t\t\"weather\": [{\n\t\t\t\"id\": 520,\n\t\t\t\"main\": \"Rain\",\n\t\t\t\"description\": \"light intensity shower rain\",\n\t\t\t\"icon\": \"09d\"\n\t\t}],\n\t\t\"main\": {\n\t\t\t\"temp\": 19.29,\n\t\t\t\"feels_like\": 18.29,\n\t\t\t\"pressure\": 1009,\n\t\t\t\"humidity\": 63\n\t\t},\n\t\t\"visibility\": 10000,\n\t\t\"wind\": {\n\t\t\t\"speed\": 1\n\t\t},\n\t\t\"clouds\": {\n\t\t\t\"all\": 0\n\t\t},\n\t\t\"dt\": 1556444155,\n\t\t\"id\": 703448,\n\t\t\"name\": \"Kiev\"\n\t}, {\n\t\t\"coord\": {\n\t\t\t\"lon\": -0.13,\n\t\t\t\"lat\": 51.51\n\t\t},\n\t\t\"sys\": {\n\t\t\t\"type\": 1,\n\t\t\t\"id\": 1414,\n\t\t\t\"message\": 0.0088,\n\t\t\t\"country\": \"GB\",\n\t\t\t\"sunrise\": 1556426319,\n\t\t\t\"sunset\": 1556479032\n\t\t},\n\t\t\"weather\": [{\n\t\t\t\"id\": 803,\n\t\t\t\"main\": \"Clouds\",\n\t\t\t\"description\": \"broken clouds\",\n\t\t\t\"icon\": \"04d\"\n\t\t}],\n\t\t\"main\": {\n\t\t\t\"temp\": 10.62,\n\t\t\t\"feels_like\": 9.62,\n\t\t\t\"pressure\": 1019,\n\t\t\t\"humidity\": 66\n\t\t},\n\t\t\"visibility\": 10000,\n\t\t\"wind\": {\n\t\t\t\"speed\": 6.2,\n\t\t\t\"deg\": 290\n\t\t},\n\t\t\"rain\": {\n\t\t\t\"3h\": 0.072\n\t\t},\n\t\t\"clouds\": {\n\t\t\t\"all\": 75\n\t\t},\n\t\t\"dt\": 1556444155,\n\t\t\"id\": 2643743,\n\t\t\"name\": \"London\"\n\t}]\n}\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_batch/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"524901\", \"703448\", \"2643743\"]\n  fetch = [\"weather\", \"forecast\"]\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/expected.out",
    "content": "weather,city=Moscow,city_id=524901,condition_id=802,condition_main=Clouds,country=RU,forecast=* cloudiness=40i,condition_description=\"scattered clouds\",condition_icon=\"03d\",feels_like=8.57,humidity=46i,pressure=1014,rain=0,snow=0,sunrise=1556416455000000000i,sunset=1556470779000000000i,temperature=9.57,visibility=10000i,wind_degrees=60,wind_speed=5 1556444155000000000\nweather,city=Kiev,city_id=703448,condition_id=520,condition_main=Rain,country=UA,forecast=* cloudiness=0i,condition_description=\"light intensity shower rain\",condition_icon=\"09d\",feels_like=18.29,humidity=63i,pressure=1009,rain=0,snow=0,sunrise=1556419155000000000i,sunset=1556471486000000000i,temperature=19.29,visibility=10000i,wind_degrees=0,wind_speed=1 1556444155000000000\nweather,city=London,city_id=2643743,condition_id=804,condition_main=Clouds,country=GB,forecast=* cloudiness=100i,condition_description=\"overcast clouds\",condition_icon=\"04n\",feels_like=7.91,humidity=90i,pressure=997,rain=0,snow=0,sunrise=1698648577000000000i,sunset=1698683914000000000i,temperature=8.94,visibility=10000i,wind_degrees=250,wind_speed=2.06 1556444155000000000\n"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/response_forecast.json",
    "content": "{}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/response_weather_2643743.json",
    "content": "{\n\t\"coord\": {\n\t\t\"lon\": -0.1257,\n\t\t\"lat\": 51.5085\n\t},\n\t\"weather\": [\n\t\t{\n\t\t\t\"id\": 804,\n\t\t\t\"main\": \"Clouds\",\n\t\t\t\"description\": \"overcast clouds\",\n\t\t\t\"icon\": \"04n\"\n\t\t}\n\t],\n\t\"base\": \"stations\",\n\t\"main\": {\n\t\t\"temp\": 8.94,\n\t\t\"feels_like\": 7.91,\n\t\t\"temp_min\": 7.38,\n\t\t\"temp_max\": 9.98,\n\t\t\"pressure\": 997,\n\t\t\"humidity\": 90\n\t},\n\t\"visibility\": 10000,\n\t\"wind\": {\n\t\t\"speed\": 2.06,\n\t\t\"deg\": 250\n\t},\n\t\"clouds\": {\n\t\t\"all\": 100\n\t},\n\t\"dt\": 1556444155,\n\t\"sys\": {\n\t\t\"type\": 2,\n\t\t\"id\": 2006068,\n\t\t\"country\": \"GB\",\n\t\t\"sunrise\": 1698648577,\n\t\t\"sunset\": 1698683914\n\t},\n\t\"timezone\": 0,\n\t\"id\": 2643743,\n\t\"name\": \"London\",\n\t\"cod\": 200\n}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/response_weather_524901.json",
    "content": "{\n\t\"coord\": {\n\t\t\"lon\": 37.62,\n\t\t\"lat\": 55.75\n\t},\n\t\"sys\": {\n\t\t\"type\": 1,\n\t\t\"id\": 9029,\n\t\t\"message\": 0.0061,\n\t\t\"country\": \"RU\",\n\t\t\"sunrise\": 1556416455,\n\t\t\"sunset\": 1556470779\n\t},\n\t\"weather\": [\n\t\t{\n\t\t\t\"id\": 802,\n\t\t\t\"main\": \"Clouds\",\n\t\t\t\"description\": \"scattered clouds\",\n\t\t\t\"icon\": \"03d\"\n\t\t}\n\t],\n\t\"main\": {\n\t\t\"temp\": 9.57,\n\t\t\"feels_like\": 8.57,\n\t\t\"pressure\": 1014,\n\t\t\"humidity\": 46\n\t},\n\t\"visibility\": 10000,\n\t\"wind\": {\n\t\t\"speed\": 5,\n\t\t\"deg\": 60\n\t},\n\t\"clouds\": {\n\t\t\"all\": 40\n\t},\n\t\"dt\": 1556444155,\n\t\"id\": 524901,\n\t\"name\": \"Moscow\"\n}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/response_weather_703448.json",
    "content": "{\n\t\"coord\": {\n\t\t\"lon\": 30.52,\n\t\t\"lat\": 50.43\n\t},\n\t\"sys\": {\n\t\t\"type\": 1,\n\t\t\"id\": 8903,\n\t\t\"message\": 0.0076,\n\t\t\"country\": \"UA\",\n\t\t\"sunrise\": 1556419155,\n\t\t\"sunset\": 1556471486\n\t},\n\t\"weather\": [\n\t\t{\n\t\t\t\"id\": 520,\n\t\t\t\"main\": \"Rain\",\n\t\t\t\"description\": \"light intensity shower rain\",\n\t\t\t\"icon\": \"09d\"\n\t\t}\n\t],\n\t\"main\": {\n\t\t\"temp\": 19.29,\n\t\t\"feels_like\": 18.29,\n\t\t\"pressure\": 1009,\n\t\t\"humidity\": 63\n\t},\n\t\"visibility\": 10000,\n\t\"wind\": {\n\t\t\"speed\": 1\n\t},\n\t\"clouds\": {\n\t\t\"all\": 0\n\t},\n\t\"dt\": 1556444155,\n\t\"id\": 703448,\n\t\"name\": \"Kiev\"\n}"
  },
  {
    "path": "plugins/inputs/openweathermap/testcases/weather_single/telegraf.conf",
    "content": "[[inputs.openweathermap]]\n  app_id = \"noappid\"\n  city_id = [\"524901\", \"703448\", \"2643743\"]\n  fetch = [\"weather\", \"forecast\"]\n  query_style = \"individual\"\n"
  },
  {
    "path": "plugins/inputs/openweathermap/types.go",
    "content": "package openweathermap\n\ntype weatherEntry struct {\n\tDt     int64 `json:\"dt\"`\n\tClouds struct {\n\t\tAll int64 `json:\"all\"`\n\t} `json:\"clouds\"`\n\tMain struct {\n\t\tHumidity int64   `json:\"humidity\"`\n\t\tPressure float64 `json:\"pressure\"`\n\t\tTemp     float64 `json:\"temp\"`\n\t\tFeels    float64 `json:\"feels_like\"`\n\t} `json:\"main\"`\n\tRain struct {\n\t\tRain1 float64 `json:\"1h\"`\n\t\tRain3 float64 `json:\"3h\"`\n\t} `json:\"rain\"`\n\tSnow struct {\n\t\tSnow1 float64 `json:\"1h\"`\n\t\tSnow3 float64 `json:\"3h\"`\n\t} `json:\"snow\"`\n\tSys struct {\n\t\tCountry string `json:\"country\"`\n\t\tSunrise int64  `json:\"sunrise\"`\n\t\tSunset  int64  `json:\"sunset\"`\n\t} `json:\"sys\"`\n\tWind struct {\n\t\tDeg   float64 `json:\"deg\"`\n\t\tSpeed float64 `json:\"speed\"`\n\t} `json:\"wind\"`\n\tID    int64  `json:\"id\"`\n\tName  string `json:\"name\"`\n\tCoord struct {\n\t\tLat float64 `json:\"lat\"`\n\t\tLon float64 `json:\"lon\"`\n\t} `json:\"coord\"`\n\tVisibility int64 `json:\"visibility\"`\n\tWeather    []struct {\n\t\tID          int64  `json:\"id\"`\n\t\tMain        string `json:\"main\"`\n\t\tDescription string `json:\"description\"`\n\t\tIcon        string `json:\"icon\"`\n\t} `json:\"weather\"`\n}\n\nfunc (e weatherEntry) snow() float64 {\n\tif e.Snow.Snow1 > 0 {\n\t\treturn e.Snow.Snow1\n\t}\n\treturn e.Snow.Snow3\n}\n\nfunc (e weatherEntry) rain() float64 {\n\tif e.Rain.Rain1 > 0 {\n\t\treturn e.Rain.Rain1\n\t}\n\treturn e.Rain.Rain3\n}\n\ntype status struct {\n\tCity struct {\n\t\tCoord struct {\n\t\t\tLat float64 `json:\"lat\"`\n\t\t\tLon float64 `json:\"lon\"`\n\t\t} `json:\"coord\"`\n\t\tCountry string `json:\"country\"`\n\t\tID      int64  `json:\"id\"`\n\t\tName    string `json:\"name\"`\n\t} `json:\"city\"`\n\tList []weatherEntry `json:\"list\"`\n}\n"
  },
  {
    "path": "plugins/inputs/p4runtime/README.md",
    "content": "# P4 Runtime Input Plugin\n\nThis plugin collects metrics from the data plane of network devices, such as\nProgrammable Switches or Programmable Network Interface Cards by reading the\n`Counter` values of the [P4 program][p4lang] running on the device.\nMetrics are collected through a gRPC connection with the [P4 runtime][p4runtime]\nserver.\n\n> [!TIP]\n> If you want to gather information about the program name, please follow the\n> instruction in [6.2.1. Annotating P4 code with PkgInfo][p4annotation] to\n> modify your P4 program.\n\n⭐ Telegraf v1.26.0\n🏷️ network, applications\n💻 all\n\n[p4lang]: https://p4.org\n[p4runtime]: https://github.com/p4lang/p4runtime\n[p4annotation]: https://p4.org/p4-spec/p4runtime/main/P4Runtime-Spec.html#sec-annotating-p4-code-with-pkginfo\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# P4Runtime telemetry input plugin\n[[inputs.p4runtime]]\n  ## Define the endpoint of P4Runtime gRPC server to collect metrics.\n  # endpoint = \"127.0.0.1:9559\"\n  ## Set DeviceID required for Client Arbitration.\n  ## https://p4.org/p4-spec/p4runtime/main/P4Runtime-Spec.html#sec-client-arbitration-and-controller-replication\n  # device_id = 1\n  ## Filter counters by their names that should be observed.\n  ## Example: counter_names_include=[\"ingressCounter\", \"egressCounter\"]\n  # counter_names_include = []\n\n  ## Optional TLS Config.\n  ## Enable client-side TLS and define CA to authenticate the device.\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.crt\"\n  ## Set minimal TLS version to accept by the client.\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification.\n  # insecure_skip_verify = true\n\n  ## Define client-side TLS certificate & key to authenticate to the device.\n  # tls_cert = \"/etc/telegraf/client.crt\"\n  # tls_key = \"/etc/telegraf/client.key\"\n```\n\n## Metrics\n\nThe P4 runtime server communicates using the\n[P4 Protocol Buffer definition][p4proto].  Static information about the program\nloaded into programmable switch are collected by\n`GetForwardingPipelineConfigRequest` message. The plugin gathers dynamic metrics\nusing the `Read` method. `Readrequest` is defined with single `Entity` of type\n`CounterEntry`. Since a P4 Counter is an array type, the plugin collects values\nof every cell of array by [wildcard queries][wildcards].\n\nCounters defined in a P4 Program have a unique ID and name. The `counter_index`\ndefines which cell value of the counter array is used in the metric.\n\nTags are constructed in given manner:\n\n- `p4program_name`: P4 program name provided by user.\n- `counter_name`: Name of given counter in P4 program.\n- `counter_type`: Type of counter (BYTES, PACKETS, BOTH).\n\nFields are constructed in given manner:\n\n- `bytes`: Number of bytes gathered in counter.\n- `packets` Number of packets gathered in counter.\n- `counter_index`: Index at which metrics are collected in P4 counter.\n\n## Example Output\n\n```text\np4_runtime,counter_name=MyIngress.egressTunnelCounter,counter_type=BOTH,host=p4 bytes=408i,packets=4i,counter_index=200i 1675175030000000000\n```\n\n[p4proto]: https://github.com/p4lang/p4runtime/blob/main/proto/p4/v1/p4runtime.proto\n[wildcards]: https://github.com/p4lang/p4runtime/blob/main/proto/p4/v1/p4runtime.proto#L379\n"
  },
  {
    "path": "plugins/inputs/p4runtime/p4runtime.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage p4runtime\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"sync\"\n\n\tp4_config \"github.com/p4lang/p4runtime/go/p4/config/v1\"\n\tp4 \"github.com/p4lang/p4runtime/go/p4/v1\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/influxdata/telegraf\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultDeviceID = 1\n\tdefaultEndpoint = \"127.0.0.1:9559\"\n)\n\ntype P4runtime struct {\n\tEndpoint            string          `toml:\"endpoint\"`\n\tDeviceID            uint64          `toml:\"device_id\"`\n\tCounterNamesInclude []string        `toml:\"counter_names_include\"`\n\tLog                 telegraf.Logger `toml:\"-\"`\n\tEnableTLS           bool            `toml:\"enable_tls\"`\n\tcommon_tls.ClientConfig\n\n\tconn   *grpc.ClientConn\n\tclient p4.P4RuntimeClient\n\twg     sync.WaitGroup\n}\n\nfunc (*P4runtime) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *P4runtime) Init() error {\n\tif p.Endpoint == \"\" {\n\t\tp.Log.Debugf(\"Using default Endpoint: %v\", defaultEndpoint)\n\t\tp.Endpoint = defaultEndpoint\n\t}\n\n\treturn p.newP4RuntimeClient()\n}\n\nfunc (p *P4runtime) Gather(acc telegraf.Accumulator) error {\n\tp4Info, err := p.getP4Info()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(p4Info.Counters) == 0 {\n\t\tp.Log.Warn(\"No counters available in P4 Program!\")\n\t\treturn nil\n\t}\n\n\tfilteredCounters := filterCounters(p4Info.Counters, p.CounterNamesInclude)\n\tif len(filteredCounters) == 0 {\n\t\tp.Log.Warn(\"No filtered counters available in P4 Program!\")\n\t\treturn nil\n\t}\n\n\tfor _, counter := range filteredCounters {\n\t\tp.wg.Add(1)\n\t\tgo func(counter *p4_config.Counter) {\n\t\t\tdefer p.wg.Done()\n\t\t\tentries, err := p.readAllEntries(counter.Preamble.Id)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(\n\t\t\t\t\tfmt.Errorf(\n\t\t\t\t\t\t\"reading counter entries with ID=%v failed with error: %w\",\n\t\t\t\t\t\tcounter.Preamble.Id,\n\t\t\t\t\t\terr,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor _, entry := range entries {\n\t\t\t\tce := entry.GetCounterEntry()\n\n\t\t\t\tif ce == nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"reading counter entry from entry %v failed\", entry))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif ce.Data.ByteCount == 0 && ce.Data.PacketCount == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"bytes\":         ce.Data.ByteCount,\n\t\t\t\t\t\"packets\":       ce.Data.PacketCount,\n\t\t\t\t\t\"counter_index\": ce.Index.Index,\n\t\t\t\t}\n\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"p4program_name\": p4Info.PkgInfo.Name,\n\t\t\t\t\t\"counter_name\":   counter.Preamble.Name,\n\t\t\t\t\t\"counter_type\":   counter.Spec.Unit.String(),\n\t\t\t\t}\n\n\t\t\t\tacc.AddFields(\"p4_runtime\", fields, tags)\n\t\t\t}\n\t\t}(counter)\n\t}\n\tp.wg.Wait()\n\treturn nil\n}\n\nfunc (p *P4runtime) Stop() {\n\tp.conn.Close()\n\tp.wg.Wait()\n}\n\nfunc initConnection(endpoint string, tlscfg *tls.Config) (*grpc.ClientConn, error) {\n\tvar creds credentials.TransportCredentials\n\tif tlscfg != nil {\n\t\tcreds = credentials.NewTLS(tlscfg)\n\t} else {\n\t\tcreds = insecure.NewCredentials()\n\t}\n\treturn grpc.NewClient(endpoint, grpc.WithTransportCredentials(creds))\n}\n\nfunc (p *P4runtime) getP4Info() (*p4_config.P4Info, error) {\n\treq := &p4.GetForwardingPipelineConfigRequest{\n\t\tDeviceId:     p.DeviceID,\n\t\tResponseType: p4.GetForwardingPipelineConfigRequest_ALL,\n\t}\n\tresp, err := p.client.GetForwardingPipelineConfig(context.Background(), req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error when retrieving forwarding pipeline config: %w\", err)\n\t}\n\n\tconfig := resp.GetConfig()\n\tif config == nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"error when retrieving config from forwarding pipeline - pipeline doesn't have a config yet: %w\",\n\t\t\terr,\n\t\t)\n\t}\n\n\tp4info := config.GetP4Info()\n\tif p4info == nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"error when retrieving P4Info from config - config doesn't have a P4Info: %w\",\n\t\t\terr,\n\t\t)\n\t}\n\n\treturn p4info, nil\n}\n\nfunc filterCounters(counters []*p4_config.Counter, counterNamesInclude []string) []*p4_config.Counter {\n\tif len(counterNamesInclude) == 0 {\n\t\treturn counters\n\t}\n\n\tvar filteredCounters []*p4_config.Counter\n\tfor _, counter := range counters {\n\t\tif counter == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif slices.Contains(counterNamesInclude, counter.Preamble.Name) {\n\t\t\tfilteredCounters = append(filteredCounters, counter)\n\t\t}\n\t}\n\treturn filteredCounters\n}\n\nfunc (p *P4runtime) newP4RuntimeClient() error {\n\tvar tlscfg *tls.Config\n\tvar err error\n\n\tif p.EnableTLS {\n\t\tif tlscfg, err = p.ClientConfig.TLSConfig(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tconn, err := initConnection(p.Endpoint, tlscfg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot connect to the server: %w\", err)\n\t}\n\tp.conn = conn\n\tp.client = p4.NewP4RuntimeClient(conn)\n\treturn nil\n}\n\nfunc (p *P4runtime) readAllEntries(counterID uint32) ([]*p4.Entity, error) {\n\treadRequest := &p4.ReadRequest{\n\t\tDeviceId: p.DeviceID,\n\t\tEntities: []*p4.Entity{{\n\t\t\tEntity: &p4.Entity_CounterEntry{\n\t\t\t\tCounterEntry: &p4.CounterEntry{\n\t\t\t\t\tCounterId: counterID}}}}}\n\n\tstream, err := p.client.Read(context.Background(), readRequest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trep, err := stream.Recv()\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, err\n\t}\n\n\treturn rep.Entities, nil\n}\n\nfunc init() {\n\tinputs.Add(\"p4runtime\", func() telegraf.Input {\n\t\tp4runtime := &P4runtime{\n\t\t\tDeviceID: defaultDeviceID,\n\t\t}\n\t\treturn p4runtime\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/p4runtime/p4runtime_fake_client_test.go",
    "content": "package p4runtime\n\nimport (\n\t\"context\"\n\n\tp4 \"github.com/p4lang/p4runtime/go/p4/v1\"\n\t\"google.golang.org/grpc\"\n)\n\ntype fakeP4RuntimeClient struct {\n\twriteFn func(\n\t\tctx context.Context,\n\t\tin *p4.WriteRequest,\n\t\topts ...grpc.CallOption,\n\t) (*p4.WriteResponse, error)\n\n\treadFn func(\n\t\tin *p4.ReadRequest,\n\t) (p4.P4Runtime_ReadClient, error)\n\n\tsetForwardingPipelineConfigFn func(\n\t\tctx context.Context,\n\t\tin *p4.SetForwardingPipelineConfigRequest,\n\t\topts ...grpc.CallOption,\n\t) (*p4.SetForwardingPipelineConfigResponse, error)\n\n\tgetForwardingPipelineConfigFn func() (*p4.GetForwardingPipelineConfigResponse, error)\n\n\tstreamChannelFn func(\n\t\tctx context.Context,\n\t\topts ...grpc.CallOption,\n\t) (p4.P4Runtime_StreamChannelClient, error)\n\n\tcapabilitiesFn func(\n\t\tctx context.Context,\n\t\tin *p4.CapabilitiesRequest,\n\t\topts ...grpc.CallOption,\n\t) (*p4.CapabilitiesResponse, error)\n}\n\n// fakeP4RuntimeClient implements the v1.P4RuntimeClient interface\nvar _ p4.P4RuntimeClient = &fakeP4RuntimeClient{}\n\nfunc (c *fakeP4RuntimeClient) Write(\n\tctx context.Context,\n\tin *p4.WriteRequest,\n\topts ...grpc.CallOption,\n) (*p4.WriteResponse, error) {\n\tif c.writeFn == nil {\n\t\tpanic(\"No mock defined for Write RPC\")\n\t}\n\treturn c.writeFn(ctx, in, opts...)\n}\n\nfunc (c *fakeP4RuntimeClient) Read(\n\t_ context.Context,\n\tin *p4.ReadRequest,\n\t_ ...grpc.CallOption,\n) (p4.P4Runtime_ReadClient, error) {\n\tif c.readFn == nil {\n\t\tpanic(\"No mock defined for Read RPC\")\n\t}\n\treturn c.readFn(in)\n}\n\nfunc (c *fakeP4RuntimeClient) SetForwardingPipelineConfig(\n\tctx context.Context,\n\tin *p4.SetForwardingPipelineConfigRequest,\n\topts ...grpc.CallOption,\n) (*p4.SetForwardingPipelineConfigResponse, error) {\n\tif c.setForwardingPipelineConfigFn == nil {\n\t\tpanic(\"No mock defined for SetForwardingPipelineConfig RPC\")\n\t}\n\treturn c.setForwardingPipelineConfigFn(ctx, in, opts...)\n}\n\nfunc (c *fakeP4RuntimeClient) GetForwardingPipelineConfig(\n\tcontext.Context,\n\t*p4.GetForwardingPipelineConfigRequest,\n\t...grpc.CallOption,\n) (*p4.GetForwardingPipelineConfigResponse, error) {\n\tif c.getForwardingPipelineConfigFn == nil {\n\t\tpanic(\"No mock defined for GetForwardingPipelineConfig RPC\")\n\t}\n\treturn c.getForwardingPipelineConfigFn()\n}\n\nfunc (c *fakeP4RuntimeClient) StreamChannel(\n\tctx context.Context,\n\topts ...grpc.CallOption,\n) (p4.P4Runtime_StreamChannelClient, error) {\n\tif c.streamChannelFn == nil {\n\t\tpanic(\"No mock defined for StreamChannel\")\n\t}\n\treturn c.streamChannelFn(ctx, opts...)\n}\n\nfunc (c *fakeP4RuntimeClient) Capabilities(\n\tctx context.Context,\n\tin *p4.CapabilitiesRequest,\n\topts ...grpc.CallOption,\n) (*p4.CapabilitiesResponse, error) {\n\tif c.capabilitiesFn == nil {\n\t\tpanic(\"No mock defined for Capabilities RPC\")\n\t}\n\treturn c.capabilitiesFn(ctx, in, opts...)\n}\n\ntype fakeP4RuntimeReadClient struct {\n\tgrpc.ClientStream\n\trecvFn func() (*p4.ReadResponse, error)\n}\n\n// fakeP4RuntimeReadClient implements the v1.P4Runtime_ReadClient interface\nvar _ p4.P4Runtime_ReadClient = &fakeP4RuntimeReadClient{}\n\nfunc (c *fakeP4RuntimeReadClient) Recv() (*p4.ReadResponse, error) {\n\tif c.recvFn == nil {\n\t\tpanic(\"No mock provided for Recv function\")\n\t}\n\treturn c.recvFn()\n}\n"
  },
  {
    "path": "plugins/inputs/p4runtime/p4runtime_test.go",
    "content": "package p4runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\tp4_config \"github.com/p4lang/p4runtime/go/p4/config/v1\"\n\tp4 \"github.com/p4lang/p4runtime/go/p4/v1\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// CounterSpec available here https://github.com/p4lang/p4runtime/blob/main/proto/p4/config/v1/p4info.proto#L289\nfunc createCounter(\n\tname string,\n\tid uint32,\n\tunit p4_config.CounterSpec_Unit,\n) *p4_config.Counter {\n\treturn &p4_config.Counter{\n\t\tPreamble: &p4_config.Preamble{Name: name, Id: id},\n\t\tSpec:     &p4_config.CounterSpec{Unit: unit},\n\t}\n}\n\nfunc createEntityCounterEntry(\n\tcounterID uint32,\n\tindex int64,\n\tdata *p4.CounterData,\n) *p4.Entity_CounterEntry {\n\treturn &p4.Entity_CounterEntry{\n\t\tCounterEntry: &p4.CounterEntry{\n\t\t\tCounterId: counterID,\n\t\t\tIndex:     &p4.Index{Index: index},\n\t\t\tData:      data,\n\t\t},\n\t}\n}\n\nfunc newTestP4RuntimeClient(\n\tp4RuntimeClient *fakeP4RuntimeClient,\n\taddr string,\n\tt *testing.T,\n) *P4runtime {\n\tconn, err := grpc.NewClient(\n\t\taddr,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t)\n\trequire.NoError(t, err)\n\treturn &P4runtime{\n\t\tEndpoint: addr,\n\t\tDeviceID: uint64(1),\n\t\tLog:      testutil.Logger{},\n\t\tconn:     conn,\n\t\tclient:   p4RuntimeClient,\n\t}\n}\n\nfunc TestInitDefault(t *testing.T) {\n\tplugin := &P4runtime{Log: testutil.Logger{}}\n\trequire.NoError(t, plugin.Init())\n\trequire.Equal(t, \"127.0.0.1:9559\", plugin.Endpoint)\n\trequire.Equal(t, uint64(0), plugin.DeviceID)\n\trequire.Empty(t, plugin.CounterNamesInclude)\n\trequire.False(t, plugin.EnableTLS)\n}\n\nfunc TestErrorGetP4Info(t *testing.T) {\n\tresponses := []struct {\n\t\tgetForwardingPipelineConfigResponse      *p4.GetForwardingPipelineConfigResponse\n\t\tgetForwardingPipelineConfigResponseError error\n\t}{\n\t\t{\n\t\t\tgetForwardingPipelineConfigResponse:      nil,\n\t\t\tgetForwardingPipelineConfigResponseError: errors.New(\"error when retrieving forwarding pipeline config\"),\n\t\t}, {\n\t\t\tgetForwardingPipelineConfigResponse: &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: nil,\n\t\t\t},\n\t\t\tgetForwardingPipelineConfigResponseError: nil,\n\t\t}, {\n\t\t\tgetForwardingPipelineConfigResponse: &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: &p4.ForwardingPipelineConfig{P4Info: nil},\n\t\t\t},\n\t\t\tgetForwardingPipelineConfigResponseError: nil,\n\t\t},\n\t}\n\n\tfor _, response := range responses {\n\t\tp4RtClient := &fakeP4RuntimeClient{\n\t\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\t\treturn response.getForwardingPipelineConfigResponse, response.getForwardingPipelineConfigResponseError\n\t\t\t},\n\t\t}\n\n\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\trequire.NoError(t, err)\n\n\t\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\t\tvar acc testutil.Accumulator\n\t\trequire.Error(t, plugin.Gather(&acc))\n\t}\n}\n\nfunc TestOneCounterRead(t *testing.T) {\n\ttests := []struct {\n\t\tforwardingPipelineConfig *p4.ForwardingPipelineConfig\n\t\tEntityCounterEntry       *p4.Entity_CounterEntry\n\t\texpected                 []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tforwardingPipelineConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\tcreateCounter(\"foo\", 1111, p4_config.CounterSpec_BOTH),\n\t\t\t\t\t},\n\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tEntityCounterEntry: createEntityCounterEntry(\n\t\t\t\t1111,\n\t\t\t\t5,\n\t\t\t\t&p4.CounterData{ByteCount: 5, PacketCount: 1},\n\t\t\t),\n\t\t\texpected: []telegraf.Metric{testutil.MustMetric(\n\t\t\t\t\"p4_runtime\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"p4program_name\": \"P4Program\",\n\t\t\t\t\t\"counter_name\":   \"foo\",\n\t\t\t\t\t\"counter_type\":   \"BOTH\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"bytes\":         int64(5),\n\t\t\t\t\t\"packets\":       int64(1),\n\t\t\t\t\t\"counter_index\": 5},\n\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t}, {\n\t\t\tforwardingPipelineConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\tcreateCounter(\n\t\t\t\t\t\t\t\"foo\",\n\t\t\t\t\t\t\t2222,\n\t\t\t\t\t\t\tp4_config.CounterSpec_BYTES,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tEntityCounterEntry: createEntityCounterEntry(\n\t\t\t\t2222,\n\t\t\t\t5,\n\t\t\t\t&p4.CounterData{ByteCount: 5},\n\t\t\t),\n\t\t\texpected: []telegraf.Metric{testutil.MustMetric(\n\t\t\t\t\"p4_runtime\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"p4program_name\": \"P4Program\",\n\t\t\t\t\t\"counter_name\":   \"foo\",\n\t\t\t\t\t\"counter_type\":   \"BYTES\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"bytes\":         int64(5),\n\t\t\t\t\t\"packets\":       int64(0),\n\t\t\t\t\t\"counter_index\": 5},\n\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t}, {\n\t\t\tforwardingPipelineConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\tcreateCounter(\n\t\t\t\t\t\t\t\"foo\",\n\t\t\t\t\t\t\t3333,\n\t\t\t\t\t\t\tp4_config.CounterSpec_PACKETS,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tEntityCounterEntry: createEntityCounterEntry(\n\t\t\t\t3333,\n\t\t\t\t5,\n\t\t\t\t&p4.CounterData{PacketCount: 1},\n\t\t\t),\n\t\t\texpected: []telegraf.Metric{testutil.MustMetric(\n\t\t\t\t\"p4_runtime\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"p4program_name\": \"P4Program\",\n\t\t\t\t\t\"counter_name\":   \"foo\",\n\t\t\t\t\t\"counter_type\":   \"PACKETS\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"bytes\":         int64(0),\n\t\t\t\t\t\"packets\":       int64(1),\n\t\t\t\t\t\"counter_index\": 5},\n\t\t\t\ttime.Unix(0, 0)),\n\t\t\t},\n\t\t}, {\n\t\t\tforwardingPipelineConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\tcreateCounter(\"foo\", 4444, p4_config.CounterSpec_BOTH),\n\t\t\t\t\t},\n\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tEntityCounterEntry: createEntityCounterEntry(\n\t\t\t\t4444,\n\t\t\t\t5,\n\t\t\t\t&p4.CounterData{},\n\t\t\t),\n\t\t\texpected: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tp4RtReadClient := &fakeP4RuntimeReadClient{\n\t\t\trecvFn: func() (*p4.ReadResponse, error) {\n\t\t\t\treturn &p4.ReadResponse{\n\t\t\t\t\tEntities: []*p4.Entity{{Entity: tt.EntityCounterEntry}},\n\t\t\t\t}, nil\n\t\t\t},\n\t\t}\n\n\t\tp4RtClient := &fakeP4RuntimeClient{\n\t\t\treadFn: func(*p4.ReadRequest) (p4.P4Runtime_ReadClient, error) {\n\t\t\t\treturn p4RtReadClient, nil\n\t\t\t},\n\t\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\t\tConfig: tt.forwardingPipelineConfig,\n\t\t\t\t}, nil\n\t\t\t},\n\t\t}\n\n\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\trequire.NoError(t, err)\n\n\t\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\t\tvar acc testutil.Accumulator\n\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\ttestutil.RequireMetricsEqual(\n\t\t\tt,\n\t\t\ttt.expected,\n\t\t\tacc.GetTelegrafMetrics(),\n\t\t\ttestutil.IgnoreTime(),\n\t\t)\n\t}\n}\n\nfunc TestMultipleEntitiesSingleCounterRead(t *testing.T) {\n\ttotalNumOfEntriesArr := [3]int{2, 10, 100}\n\n\tfor _, totalNumOfEntries := range totalNumOfEntriesArr {\n\t\tvar expected []telegraf.Metric\n\n\t\tfmt.Println(\n\t\t\t\"Running TestMultipleEntitiesSingleCounterRead with \",\n\t\t\ttotalNumOfEntries,\n\t\t\t\"totalNumOfCounters\",\n\t\t)\n\t\tentities := make([]*p4.Entity, 0, totalNumOfEntries)\n\t\tp4InfoCounters := make([]*p4_config.Counter, 0, totalNumOfEntries)\n\t\tp4InfoCounters = append(\n\t\t\tp4InfoCounters,\n\t\t\tcreateCounter(\"foo\", 0, p4_config.CounterSpec_BOTH),\n\t\t)\n\n\t\tfor i := 0; i < totalNumOfEntries; i++ {\n\t\t\tcounterEntry := &p4.Entity{\n\t\t\t\tEntity: createEntityCounterEntry(\n\t\t\t\t\t0,\n\t\t\t\t\tint64(i),\n\t\t\t\t\t&p4.CounterData{\n\t\t\t\t\t\tByteCount:   int64(10),\n\t\t\t\t\t\tPacketCount: int64(10),\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t}\n\n\t\t\tentities = append(entities, counterEntry)\n\t\t\texpected = append(expected, testutil.MustMetric(\n\t\t\t\t\"p4_runtime\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"p4program_name\": \"P4Program\",\n\t\t\t\t\t\"counter_name\":   \"foo\",\n\t\t\t\t\t\"counter_type\":   \"BOTH\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"bytes\":         int64(10),\n\t\t\t\t\t\"packets\":       int64(10),\n\t\t\t\t\t\"counter_index\": i,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t))\n\t\t}\n\n\t\tforwardingPipelineConfig := &p4.ForwardingPipelineConfig{\n\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\tCounters: p4InfoCounters,\n\t\t\t\tPkgInfo:  &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t},\n\t\t}\n\n\t\tp4RtReadClient := &fakeP4RuntimeReadClient{\n\t\t\trecvFn: func() (*p4.ReadResponse, error) {\n\t\t\t\treturn &p4.ReadResponse{Entities: entities}, nil\n\t\t\t},\n\t\t}\n\n\t\tp4RtClient := &fakeP4RuntimeClient{\n\t\t\treadFn: func(*p4.ReadRequest) (p4.P4Runtime_ReadClient, error) {\n\t\t\t\treturn p4RtReadClient, nil\n\t\t\t},\n\t\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\t\tConfig: forwardingPipelineConfig,\n\t\t\t\t}, nil\n\t\t\t},\n\t\t}\n\n\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\trequire.NoError(t, err)\n\n\t\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\t\tvar acc testutil.Accumulator\n\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\tacc.Wait(totalNumOfEntries)\n\n\t\ttestutil.RequireMetricsEqual(\n\t\t\tt,\n\t\t\texpected,\n\t\t\tacc.GetTelegrafMetrics(),\n\t\t\ttestutil.IgnoreTime(),\n\t\t)\n\t}\n}\n\nfunc TestSingleEntitiesMultipleCounterRead(t *testing.T) {\n\ttotalNumOfCountersArr := [3]int{2, 10, 100}\n\n\tfor _, totalNumOfCounters := range totalNumOfCountersArr {\n\t\tvar expected []telegraf.Metric\n\n\t\tfmt.Println(\n\t\t\t\"Running TestSingleEntitiesMultipleCounterRead with \",\n\t\t\ttotalNumOfCounters,\n\t\t\t\"totalNumOfCounters\",\n\t\t)\n\t\tp4InfoCounters := make([]*p4_config.Counter, 0, totalNumOfCounters)\n\n\t\tfor i := 1; i <= totalNumOfCounters; i++ {\n\t\t\tcounterName := fmt.Sprintf(\"foo%v\", i)\n\t\t\tp4InfoCounters = append(\n\t\t\t\tp4InfoCounters,\n\t\t\t\tcreateCounter(\n\t\t\t\t\tcounterName,\n\t\t\t\t\tuint32(i),\n\t\t\t\t\tp4_config.CounterSpec_BOTH,\n\t\t\t\t),\n\t\t\t)\n\n\t\t\texpected = append(expected, testutil.MustMetric(\n\t\t\t\t\"p4_runtime\",\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"p4program_name\": \"P4Program\",\n\t\t\t\t\t\"counter_name\":   counterName,\n\t\t\t\t\t\"counter_type\":   \"BOTH\",\n\t\t\t\t},\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"bytes\":         int64(10),\n\t\t\t\t\t\"packets\":       int64(10),\n\t\t\t\t\t\"counter_index\": 1,\n\t\t\t\t},\n\t\t\t\ttime.Unix(0, 0),\n\t\t\t))\n\t\t}\n\n\t\tforwardingPipelineConfig := &p4.ForwardingPipelineConfig{\n\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\tCounters: p4InfoCounters,\n\t\t\t\tPkgInfo:  &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t},\n\t\t}\n\n\t\tp4RtClient := &fakeP4RuntimeClient{\n\t\t\treadFn: func(in *p4.ReadRequest) (p4.P4Runtime_ReadClient, error) {\n\t\t\t\tcounterID := in.Entities[0].GetCounterEntry().CounterId\n\t\t\t\treturn &fakeP4RuntimeReadClient{\n\t\t\t\t\trecvFn: func() (*p4.ReadResponse, error) {\n\t\t\t\t\t\treturn &p4.ReadResponse{\n\t\t\t\t\t\t\tEntities: []*p4.Entity{{\n\t\t\t\t\t\t\t\tEntity: createEntityCounterEntry(\n\t\t\t\t\t\t\t\t\tcounterID,\n\t\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\t&p4.CounterData{\n\t\t\t\t\t\t\t\t\t\tByteCount:   10,\n\t\t\t\t\t\t\t\t\t\tPacketCount: 10,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t}, nil\n\t\t\t\t\t},\n\t\t\t\t}, nil\n\t\t\t},\n\t\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\t\tConfig: forwardingPipelineConfig,\n\t\t\t\t}, nil\n\t\t\t},\n\t\t}\n\n\t\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\t\trequire.NoError(t, err)\n\n\t\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\t\tvar acc testutil.Accumulator\n\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\tacc.Wait(totalNumOfCounters)\n\n\t\ttestutil.RequireMetricsEqual(\n\t\t\tt,\n\t\t\texpected,\n\t\t\tacc.GetTelegrafMetrics(),\n\t\t\ttestutil.SortMetrics(),\n\t\t\ttestutil.IgnoreTime(),\n\t\t)\n\t}\n}\n\nfunc TestNoCountersAvailable(t *testing.T) {\n\tforwardingPipelineConfig := &p4.ForwardingPipelineConfig{\n\t\tP4Info: &p4_config.P4Info{Counters: make([]*p4_config.Counter, 0)},\n\t}\n\n\tp4RtClient := &fakeP4RuntimeClient{\n\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: forwardingPipelineConfig,\n\t\t\t}, nil\n\t\t},\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n}\n\nfunc TestFilterCounters(t *testing.T) {\n\tforwardingPipelineConfig := &p4.ForwardingPipelineConfig{\n\t\tP4Info: &p4_config.P4Info{\n\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\tcreateCounter(\"foo\", 1, p4_config.CounterSpec_BOTH),\n\t\t\t},\n\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t},\n\t}\n\n\tp4RtClient := &fakeP4RuntimeClient{\n\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: forwardingPipelineConfig,\n\t\t\t}, nil\n\t\t},\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\tplugin.CounterNamesInclude = []string{\"oof\"}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\ttestutil.RequireMetricsEqual(\n\t\tt,\n\t\tnil,\n\t\tacc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t)\n}\n\nfunc TestFailReadCounterEntryFromEntry(t *testing.T) {\n\tp4RtReadClient := &fakeP4RuntimeReadClient{\n\t\trecvFn: func() (*p4.ReadResponse, error) {\n\t\t\treturn &p4.ReadResponse{\n\t\t\t\tEntities: []*p4.Entity{{\n\t\t\t\t\tEntity: &p4.Entity_TableEntry{\n\t\t\t\t\t\tTableEntry: &p4.TableEntry{},\n\t\t\t\t\t}}}}, nil\n\t\t},\n\t}\n\n\tp4RtClient := &fakeP4RuntimeClient{\n\t\treadFn: func(*p4.ReadRequest) (p4.P4Runtime_ReadClient, error) {\n\t\t\treturn p4RtReadClient, nil\n\t\t},\n\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\t\tcreateCounter(\n\t\t\t\t\t\t\t\t\"foo\",\n\t\t\t\t\t\t\t\t1111,\n\t\t\t\t\t\t\t\tp4_config.CounterSpec_BOTH,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Equal(\n\t\tt,\n\t\terrors.New(\"reading counter entry from entry table_entry:{} failed\"),\n\t\tacc.Errors[0],\n\t)\n\ttestutil.RequireMetricsEqual(\n\t\tt,\n\t\tnil,\n\t\tacc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t)\n}\n\nfunc TestFailReadAllEntries(t *testing.T) {\n\tp4RtClient := &fakeP4RuntimeClient{\n\t\treadFn: func(*p4.ReadRequest) (p4.P4Runtime_ReadClient, error) {\n\t\t\treturn nil, errors.New(\"connection error\")\n\t\t},\n\t\tgetForwardingPipelineConfigFn: func() (*p4.GetForwardingPipelineConfigResponse, error) {\n\t\t\treturn &p4.GetForwardingPipelineConfigResponse{\n\t\t\t\tConfig: &p4.ForwardingPipelineConfig{\n\t\t\t\t\tP4Info: &p4_config.P4Info{\n\t\t\t\t\t\tCounters: []*p4_config.Counter{\n\t\t\t\t\t\t\tcreateCounter(\n\t\t\t\t\t\t\t\t\"foo\",\n\t\t\t\t\t\t\t\t1111,\n\t\t\t\t\t\t\t\tp4_config.CounterSpec_BOTH,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPkgInfo: &p4_config.PkgInfo{Name: \"P4Program\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}, nil\n\t\t},\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tplugin := newTestP4RuntimeClient(p4RtClient, listener.Addr().String(), t)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Equal(\n\t\tt,\n\t\tacc.Errors[0],\n\t\tfmt.Errorf(\"reading counter entries with ID=1111 failed with error: %w\", errors.New(\"connection error\")),\n\t)\n\ttestutil.RequireMetricsEqual(\n\t\tt,\n\t\tnil,\n\t\tacc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime(),\n\t)\n}\n\nfunc TestFilterCounterNamesInclude(t *testing.T) {\n\tcounters := []*p4_config.Counter{\n\t\tcreateCounter(\"foo\", 1, p4_config.CounterSpec_BOTH),\n\t\tcreateCounter(\"bar\", 2, p4_config.CounterSpec_BOTH),\n\t\tnil,\n\t\tcreateCounter(\"\", 3, p4_config.CounterSpec_BOTH),\n\t}\n\n\tcounterNamesInclude := []string{\"bar\"}\n\n\tfilteredCounters := filterCounters(counters, counterNamesInclude)\n\trequire.Equal(\n\t\tt,\n\t\t[]*p4_config.Counter{\n\t\t\tcreateCounter(\"bar\", 2, p4_config.CounterSpec_BOTH),\n\t\t}, filteredCounters,\n\t)\n}\n"
  },
  {
    "path": "plugins/inputs/p4runtime/sample.conf",
    "content": "# P4Runtime telemetry input plugin\n[[inputs.p4runtime]]\n  ## Define the endpoint of P4Runtime gRPC server to collect metrics.\n  # endpoint = \"127.0.0.1:9559\"\n  ## Set DeviceID required for Client Arbitration.\n  ## https://p4.org/p4-spec/p4runtime/main/P4Runtime-Spec.html#sec-client-arbitration-and-controller-replication\n  # device_id = 1\n  ## Filter counters by their names that should be observed.\n  ## Example: counter_names_include=[\"ingressCounter\", \"egressCounter\"]\n  # counter_names_include = []\n\n  ## Optional TLS Config.\n  ## Enable client-side TLS and define CA to authenticate the device.\n  # enable_tls = false\n  # tls_ca = \"/etc/telegraf/ca.crt\"\n  ## Set minimal TLS version to accept by the client.\n  # tls_min_version = \"TLS12\"\n  ## Use TLS but skip chain & host verification.\n  # insecure_skip_verify = true\n\n  ## Define client-side TLS certificate & key to authenticate to the device.\n  # tls_cert = \"/etc/telegraf/client.crt\"\n  # tls_key = \"/etc/telegraf/client.key\"\n"
  },
  {
    "path": "plugins/inputs/passenger/README.md",
    "content": "# Passenger Input Plugin\n\nThis plugin gathers metrics from the [Phusion Passenger][phusion] service.\n\n> [!WARNING]\n> Depending on your environment, this plugin can create a high number of series\n> which can cause high load on your database. Please use\n> [measurement filtering][metric_filtering] to manage your series cardinality!\n\nThe plugin uses the `passenger-status` command line tool.\n\n> [!NOTE]\n> This plugin requires the `passenger-status` binary to be installed on the\n> system and to be executable by Telegraf.\n\n⭐ Telegraf v0.10.1\n🏷️ web\n💻 all\n\n[phusion]: https://www.phusionpassenger.com/\n[metric_filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics of passenger using passenger-status\n[[inputs.passenger]]\n  ## Path of passenger-status.\n  ##\n  ## Plugin gather metric via parsing XML output of passenger-status\n  ## More information about the tool:\n  ##   https://www.phusionpassenger.com/library/admin/apache/overall_status_report.html\n  ##\n  ## If no path is specified, then the plugin simply execute passenger-status\n  ## hopefully it can be found in your PATH\n  command = \"passenger-status -v --show=xml\"\n```\n\n### Permissions\n\nTelegraf must have permission to execute the `passenger-status` command.  On\nmost systems, Telegraf runs as the `telegraf` user.\n\n### Series Cardinality\n\nDepending on your environment, this `passenger_process` measurement of this\nplugin can quickly create a high number of series which, when unchecked, can\ncause high load on your database.  You can use the following techniques to\nmanage your series cardinality:\n\n- Use the\n  [measurement filtering](https://docs.influxdata.com/telegraf/latest/administration/configuration/#measurement-filtering)\n  options to exclude unneeded tags.  In some environments, you may wish to use\n  `tagexclude` to remove the `pid` and `process_group_id` tags.\n- Write to a database with an appropriate\n  [retention policy](https://docs.influxdata.com/influxdb/latest/guides/downsampling_and_retention/).\n- Consider using the\n  [Time Series Index](https://docs.influxdata.com/influxdb/latest/concepts/time-series-index/).\n- Monitor your databases\n  [series cardinality](https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality).\n\n## Metrics\n\n- passenger\n  - tags:\n    - passenger_version\n  - fields:\n    - process_count\n    - max\n    - capacity_used\n    - get_wait_list_size\n\n- passenger_supergroup\n  - tags:\n    - name\n  - fields:\n    - get_wait_list_size\n    - capacity_used\n\n- passenger_group\n  - tags:\n    - name\n    - app_root\n    - app_type\n  - fields:\n    - get_wait_list_size\n    - capacity_used\n    - processes_being_spawned\n\n- passenger_process\n  - tags:\n    - group_name\n    - app_root\n    - supergroup_name\n    - pid\n    - code_revision\n    - life_status\n    - process_group_id\n  - fields:\n    - concurrency\n    - sessions\n    - busyness\n    - processed\n    - spawner_creation_time\n    - spawn_start_time\n    - spawn_end_time\n    - last_used\n    - uptime\n    - cpu\n    - rss\n    - pss\n    - private_dirty\n    - swap\n    - real_memory\n    - vmsize\n\n## Example Output\n\n```text\npassenger,passenger_version=5.0.17 capacity_used=23i,get_wait_list_size=0i,max=23i,process_count=23i 1452984112799414257\npassenger_supergroup,name=/var/app/current/public capacity_used=23i,get_wait_list_size=0i 1452984112799496977\npassenger_group,app_root=/var/app/current,app_type=rack,name=/var/app/current/public capacity_used=23i,get_wait_list_size=0i,processes_being_spawned=0i 1452984112799527021\npassenger_process,app_root=/var/app/current,code_revision=899ac7f,group_name=/var/app/current/public,life_status=ALIVE,pid=11553,process_group_id=13608,supergroup_name=/var/app/current/public busyness=0i,concurrency=1i,cpu=58i,last_used=1452747071764940i,private_dirty=314900i,processed=951i,pss=319391i,real_memory=314900i,rss=418548i,sessions=0i,spawn_end_time=1452746845013365i,spawn_start_time=1452746844946982i,spawner_creation_time=1452746835922747i,swap=0i,uptime=226i,vmsize=1563580i 1452984112799571490\npassenger_process,app_root=/var/app/current,code_revision=899ac7f,group_name=/var/app/current/public,life_status=ALIVE,pid=11563,process_group_id=13608,supergroup_name=/var/app/current/public busyness=2147483647i,concurrency=1i,cpu=47i,last_used=1452747071709179i,private_dirty=309240i,processed=756i,pss=314036i,real_memory=309240i,rss=418296i,sessions=1i,spawn_end_time=1452746845172460i,spawn_start_time=1452746845136882i,spawner_creation_time=1452746835922747i,swap=0i,uptime=226i,vmsize=1563608i 1452984112799638581\n```\n"
  },
  {
    "path": "plugins/inputs/passenger/passenger.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage passenger\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html/charset\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Passenger struct {\n\tCommand string `toml:\"command\"`\n}\n\ntype info struct {\n\tPassengerVersion string `xml:\"passenger_version\"`\n\tProcessCount     int    `xml:\"process_count\"`\n\tCapacityUsed     int    `xml:\"capacity_used\"`\n\tGetWaitListSize  int    `xml:\"get_wait_list_size\"`\n\tMax              int    `xml:\"max\"`\n\tSupergroups      struct {\n\t\tSupergroup []struct {\n\t\t\tName            string `xml:\"name\"`\n\t\t\tGetWaitListSize int    `xml:\"get_wait_list_size\"`\n\t\t\tCapacityUsed    int    `xml:\"capacity_used\"`\n\t\t\tGroup           []struct {\n\t\t\t\tName                  string `xml:\"name\"`\n\t\t\t\tAppRoot               string `xml:\"app_root\"`\n\t\t\t\tAppType               string `xml:\"app_type\"`\n\t\t\t\tEnabledProcessCount   int    `xml:\"enabled_process_count\"`\n\t\t\t\tDisablingProcessCount int    `xml:\"disabling_process_count\"`\n\t\t\t\tDisabledProcessCount  int    `xml:\"disabled_process_count\"`\n\t\t\t\tCapacityUsed          int    `xml:\"capacity_used\"`\n\t\t\t\tGetWaitListSize       int    `xml:\"get_wait_list_size\"`\n\t\t\t\tProcessesBeingSpawned int    `xml:\"processes_being_spawned\"`\n\t\t\t\tProcesses             struct {\n\t\t\t\t\tProcess []*process `xml:\"process\"`\n\t\t\t\t} `xml:\"processes\"`\n\t\t\t} `xml:\"group\"`\n\t\t} `xml:\"supergroup\"`\n\t} `xml:\"supergroups\"`\n}\n\ntype process struct {\n\tPid                 int    `xml:\"pid\"`\n\tConcurrency         int    `xml:\"concurrency\"`\n\tSessions            int    `xml:\"sessions\"`\n\tBusyness            int    `xml:\"busyness\"`\n\tProcessed           int    `xml:\"processed\"`\n\tSpawnerCreationTime int64  `xml:\"spawner_creation_time\"`\n\tSpawnStartTime      int64  `xml:\"spawn_start_time\"`\n\tSpawnEndTime        int64  `xml:\"spawn_end_time\"`\n\tLastUsed            int64  `xml:\"last_used\"`\n\tUptime              string `xml:\"uptime\"`\n\tCodeRevision        string `xml:\"code_revision\"`\n\tLifeStatus          string `xml:\"life_status\"`\n\tEnabled             string `xml:\"enabled\"`\n\tHasMetrics          bool   `xml:\"has_metrics\"`\n\tCPU                 int64  `xml:\"cpu\"`\n\tRss                 int64  `xml:\"rss\"`\n\tPss                 int64  `xml:\"pss\"`\n\tPrivateDirty        int64  `xml:\"private_dirty\"`\n\tSwap                int64  `xml:\"swap\"`\n\tRealMemory          int64  `xml:\"real_memory\"`\n\tVmsize              int64  `xml:\"vmsize\"`\n\tProcessGroupID      string `xml:\"process_group_id\"`\n}\n\nfunc (*Passenger) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Passenger) Gather(acc telegraf.Accumulator) error {\n\tif p.Command == \"\" {\n\t\tp.Command = \"passenger-status -v --show=xml\"\n\t}\n\n\tcmd, args := p.parseCommand()\n\tout, err := exec.Command(cmd, args...).Output()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn importMetric(out, acc)\n}\n\nfunc (p *Passenger) parseCommand() (string, []string) {\n\tvar arguments []string\n\tif !strings.Contains(p.Command, \" \") {\n\t\treturn p.Command, arguments\n\t}\n\n\targuments = strings.Split(p.Command, \" \")\n\tif len(arguments) == 1 {\n\t\treturn arguments[0], arguments[1:]\n\t}\n\n\treturn arguments[0], arguments[1:]\n}\n\nfunc (p *process) getUptime() int64 {\n\tif p.Uptime == \"\" {\n\t\treturn 0\n\t}\n\n\ttimeSlice := strings.Split(p.Uptime, \" \")\n\tvar uptime int64\n\tuptime = 0\n\tfor _, v := range timeSlice {\n\t\tswitch {\n\t\tcase strings.HasSuffix(v, \"d\"):\n\t\t\tiValue := strings.TrimSuffix(v, \"d\")\n\t\t\tvalue, err := strconv.ParseInt(iValue, 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tuptime += value * (24 * 60 * 60)\n\t\t\t}\n\t\tcase strings.HasSuffix(v, \"h\"):\n\t\t\tiValue := strings.TrimSuffix(v, \"h\")\n\t\t\tvalue, err := strconv.ParseInt(iValue, 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tuptime += value * (60 * 60)\n\t\t\t}\n\t\tcase strings.HasSuffix(v, \"m\"):\n\t\t\tiValue := strings.TrimSuffix(v, \"m\")\n\t\t\tvalue, err := strconv.ParseInt(iValue, 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tuptime += value * 60\n\t\t\t}\n\t\tcase strings.HasSuffix(v, \"s\"):\n\t\t\tiValue := strings.TrimSuffix(v, \"s\")\n\t\t\tvalue, err := strconv.ParseInt(iValue, 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tuptime += value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn uptime\n}\n\nfunc importMetric(stat []byte, acc telegraf.Accumulator) error {\n\tvar p info\n\n\tdecoder := xml.NewDecoder(bytes.NewReader(stat))\n\tdecoder.CharsetReader = charset.NewReaderLabel\n\tif err := decoder.Decode(&p); err != nil {\n\t\treturn fmt.Errorf(\"cannot parse input with error: %w\", err)\n\t}\n\n\ttags := map[string]string{\n\t\t\"passenger_version\": p.PassengerVersion,\n\t}\n\tfields := map[string]interface{}{\n\t\t\"process_count\":      p.ProcessCount,\n\t\t\"max\":                p.Max,\n\t\t\"capacity_used\":      p.CapacityUsed,\n\t\t\"get_wait_list_size\": p.GetWaitListSize,\n\t}\n\tacc.AddFields(\"passenger\", fields, tags)\n\n\tfor _, sg := range p.Supergroups.Supergroup {\n\t\ttags := map[string]string{\n\t\t\t\"name\": sg.Name,\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"get_wait_list_size\": sg.GetWaitListSize,\n\t\t\t\"capacity_used\":      sg.CapacityUsed,\n\t\t}\n\t\tacc.AddFields(\"passenger_supergroup\", fields, tags)\n\n\t\tfor _, group := range sg.Group {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"name\":     group.Name,\n\t\t\t\t\"app_root\": group.AppRoot,\n\t\t\t\t\"app_type\": group.AppType,\n\t\t\t}\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"get_wait_list_size\":      group.GetWaitListSize,\n\t\t\t\t\"capacity_used\":           group.CapacityUsed,\n\t\t\t\t\"processes_being_spawned\": group.ProcessesBeingSpawned,\n\t\t\t}\n\t\t\tacc.AddFields(\"passenger_group\", fields, tags)\n\n\t\t\tfor _, process := range group.Processes.Process {\n\t\t\t\ttags := map[string]string{\n\t\t\t\t\t\"group_name\":       group.Name,\n\t\t\t\t\t\"app_root\":         group.AppRoot,\n\t\t\t\t\t\"supergroup_name\":  sg.Name,\n\t\t\t\t\t\"pid\":              strconv.Itoa(process.Pid),\n\t\t\t\t\t\"code_revision\":    process.CodeRevision,\n\t\t\t\t\t\"life_status\":      process.LifeStatus,\n\t\t\t\t\t\"process_group_id\": process.ProcessGroupID,\n\t\t\t\t}\n\t\t\t\tfields := map[string]interface{}{\n\t\t\t\t\t\"concurrency\":           process.Concurrency,\n\t\t\t\t\t\"sessions\":              process.Sessions,\n\t\t\t\t\t\"busyness\":              process.Busyness,\n\t\t\t\t\t\"processed\":             process.Processed,\n\t\t\t\t\t\"spawner_creation_time\": process.SpawnerCreationTime,\n\t\t\t\t\t\"spawn_start_time\":      process.SpawnStartTime,\n\t\t\t\t\t\"spawn_end_time\":        process.SpawnEndTime,\n\t\t\t\t\t\"last_used\":             process.LastUsed,\n\t\t\t\t\t\"uptime\":                process.getUptime(),\n\t\t\t\t\t\"cpu\":                   process.CPU,\n\t\t\t\t\t\"rss\":                   process.Rss,\n\t\t\t\t\t\"pss\":                   process.Pss,\n\t\t\t\t\t\"private_dirty\":         process.PrivateDirty,\n\t\t\t\t\t\"swap\":                  process.Swap,\n\t\t\t\t\t\"real_memory\":           process.RealMemory,\n\t\t\t\t\t\"vmsize\":                process.Vmsize,\n\t\t\t\t}\n\t\t\t\tacc.AddFields(\"passenger_process\", fields, tags)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"passenger\", func() telegraf.Input {\n\t\treturn &Passenger{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/passenger/passenger_test.go",
    "content": "package passenger\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc fakePassengerStatus(stat string) (string, error) {\n\tvar fileExtension, content string\n\tif runtime.GOOS == \"windows\" {\n\t\tfileExtension = \".bat\"\n\t\tvar sb strings.Builder\n\t\tsb.WriteString(\"@echo off\\n\")\n\t\tfor _, line := range strings.Split(strings.TrimSuffix(stat, \"\\n\"), \"\\n\") {\n\t\t\tsb.WriteString(\"for /f \\\"delims=\\\" %%A in (\\\"\")\n\t\t\tsb.WriteString(line)\n\t\t\tsb.WriteString(\"\\\") do echo %%~A\\n\")\n\t\t}\n\t\tcontent = sb.String()\n\t} else {\n\t\tcontent = fmt.Sprintf(\"#!/bin/sh\\ncat << EOF\\n%s\\nEOF\", stat)\n\t}\n\n\ttempFilePath := filepath.Join(os.TempDir(), \"passenger-status\"+fileExtension)\n\t//nolint:gosec // G306: Expect WriteFile permissions to be 0640 or less - this file needs to be executed\n\tif err := os.WriteFile(tempFilePath, []byte(content), 0700); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn tempFilePath, nil\n}\n\nfunc teardown(tempFilePath string) {\n\tos.Remove(tempFilePath)\n}\n\nfunc Test_Invalid_Passenger_Status_Cli(t *testing.T) {\n\tr := &Passenger{\n\t\tCommand: \"an-invalid-command passenger-status\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := r.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), `exec: \"an-invalid-command\": executable file not found in `)\n}\n\nfunc Test_Invalid_Xml(t *testing.T) {\n\ttempFilePath, err := fakePassengerStatus(\"invalid xml\")\n\trequire.NoError(t, err)\n\tdefer teardown(tempFilePath)\n\n\tr := &Passenger{\n\t\tCommand: tempFilePath,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr = r.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Equal(t, \"cannot parse input with error: EOF\", err.Error())\n}\n\n// We test this by ensure that the error message match the path of default cli\nfunc Test_Default_Config_Load_Default_Command(t *testing.T) {\n\ttempFilePath, err := fakePassengerStatus(\"invalid xml\")\n\trequire.NoError(t, err)\n\tdefer teardown(tempFilePath)\n\n\tr := &Passenger{}\n\n\tvar acc testutil.Accumulator\n\n\terr = r.Gather(&acc)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"exec: \\\"passenger-status\\\": executable file not found in \")\n}\n\nfunc TestPassengerGenerateMetric(t *testing.T) {\n\ttempFilePath, err := fakePassengerStatus(sampleStat)\n\trequire.NoError(t, err)\n\tdefer teardown(tempFilePath)\n\n\t// Now we tested again above server, with our authentication data\n\tr := &Passenger{\n\t\tCommand: tempFilePath,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, r.Gather(&acc))\n\n\ttags := map[string]string{\n\t\t\"passenger_version\": \"5.0.17\",\n\t}\n\tfields := map[string]interface{}{\n\t\t\"process_count\":      23,\n\t\t\"max\":                23,\n\t\t\"capacity_used\":      23,\n\t\t\"get_wait_list_size\": 3,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"passenger\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"name\":     \"/var/app/current/public\",\n\t\t\"app_root\": \"/var/app/current\",\n\t\t\"app_type\": \"rack\",\n\t}\n\tfields = map[string]interface{}{\n\t\t\"processes_being_spawned\": 2,\n\t\t\"capacity_used\":           23,\n\t\t\"get_wait_list_size\":      3,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"passenger_group\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"name\": \"/var/app/current/public\",\n\t}\n\n\tfields = map[string]interface{}{\n\t\t\"capacity_used\":      23,\n\t\t\"get_wait_list_size\": 3,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"passenger_supergroup\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"app_root\":         \"/var/app/current\",\n\t\t\"group_name\":       \"/var/app/current/public\",\n\t\t\"supergroup_name\":  \"/var/app/current/public\",\n\t\t\"pid\":              \"11553\",\n\t\t\"code_revision\":    \"899ac7f\",\n\t\t\"life_status\":      \"ALIVE\",\n\t\t\"process_group_id\": \"13608\",\n\t}\n\tfields = map[string]interface{}{\n\t\t\"concurrency\":           1,\n\t\t\"sessions\":              0,\n\t\t\"busyness\":              0,\n\t\t\"processed\":             951,\n\t\t\"spawner_creation_time\": int64(1452746835922747),\n\t\t\"spawn_start_time\":      int64(1452746844946982),\n\t\t\"spawn_end_time\":        int64(1452746845013365),\n\t\t\"last_used\":             int64(1452747071764940),\n\t\t\"uptime\":                int64(191026), // in seconds of 2d 5h 3m 46s\n\t\t\"cpu\":                   int64(58),\n\t\t\"rss\":                   int64(418548),\n\t\t\"pss\":                   int64(319391),\n\t\t\"private_dirty\":         int64(314900),\n\t\t\"swap\":                  int64(0),\n\t\t\"real_memory\":           int64(314900),\n\t\t\"vmsize\":                int64(1563580),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"passenger_process\", fields, tags)\n}\n\nvar sampleStat = `\n<?xml version=\"1.0\" encoding=\"iso8859-1\" ?>\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<info version=\"3\">\n  <passenger_version>5.0.17</passenger_version>\n  <group_count>1</group_count>\n  <process_count>23</process_count>\n  <max>23</max>\n  <capacity_used>23</capacity_used>\n  <get_wait_list_size>3</get_wait_list_size>\n  <get_wait_list />\n  <supergroups>\n    <supergroup>\n      <name>/var/app/current/public</name>\n      <state>READY</state>\n      <get_wait_list_size>3</get_wait_list_size>\n      <capacity_used>23</capacity_used>\n      <secret>foo</secret>\n      <group default=\"true\">\n        <name>/var/app/current/public</name>\n        <component_name>/var/app/current/public</component_name>\n        <app_root>/var/app/current</app_root>\n        <app_type>rack</app_type>\n        <environment>production</environment>\n        <uuid>QQUrbCVYxbJYpfgyDOwJ</uuid>\n        <enabled_process_count>23</enabled_process_count>\n        <disabling_process_count>0</disabling_process_count>\n        <disabled_process_count>0</disabled_process_count>\n        <capacity_used>23</capacity_used>\n        <get_wait_list_size>3</get_wait_list_size>\n        <disable_wait_list_size>0</disable_wait_list_size>\n        <processes_being_spawned>2</processes_being_spawned>\n        <secret>foo</secret>\n        <api_key>foo</api_key>\n        <life_status>ALIVE</life_status>\n        <user>axcoto</user>\n        <uid>1001</uid>\n        <group>axcoto</group>\n        <gid>1001</gid>\n        <options>\n          <app_root>/var/app/current</app_root>\n          <app_group_name>/var/app/current/public</app_group_name>\n          <app_type>rack</app_type>\n          <start_command>/var/app/.rvm/gems/ruby-2.2.0-p645/gems/passenger-5.0.17/helper-scripts/rack-loader.rb</start_command>\n          <startup_file>config.ru</startup_file>\n          <process_title>Passenger RubyApp</process_title>\n          <log_level>3</log_level>\n          <start_timeout>90000</start_timeout>\n          <environment>production</environment>\n          <base_uri>/</base_uri>\n          <spawn_method>smart</spawn_method>\n          <default_user>nobody</default_user>\n          <default_group>nogroup</default_group>\n          <ruby>/var/app/.rvm/gems/ruby-2.2.0-p645/wrappers/ruby</ruby>\n          <python>python</python>\n          <nodejs>node</nodejs>\n          <ust_router_address>unix:/tmp/passenger.eKFdvdC/agents.s/ust_router</ust_router_address>\n          <ust_router_username>logging</ust_router_username>\n          <ust_router_password>foo</ust_router_password>\n          <debugger>false</debugger>\n          <analytics>false</analytics>\n          <api_key>foo</api_key>\n          <min_processes>22</min_processes>\n          <max_processes>0</max_processes>\n          <max_preloader_idle_time>300</max_preloader_idle_time>\n          <max_out_of_band_work_instances>1</max_out_of_band_work_instances>\n        </options>\n        <processes>\n          <process>\n            <pid>11553</pid>\n            <sticky_session_id>378579907</sticky_session_id>\n            <gupid>17173df-PoNT3J9HCf</gupid>\n            <concurrency>1</concurrency>\n            <sessions>0</sessions>\n            <busyness>0</busyness>\n            <processed>951</processed>\n            <spawner_creation_time>1452746835922747</spawner_creation_time>\n            <spawn_start_time>1452746844946982</spawn_start_time>\n            <spawn_end_time>1452746845013365</spawn_end_time>\n            <last_used>1452747071764940</last_used>\n            <last_used_desc>0s ago</last_used_desc>\n            <uptime>2d 5h 3m 46s</uptime>\n            <code_revision>899ac7f</code_revision>\n            <life_status>ALIVE</life_status>\n            <enabled>ENABLED</enabled>\n            <has_metrics>true</has_metrics>\n            <cpu>58</cpu>\n            <rss>418548</rss>\n            <pss>319391</pss>\n            <private_dirty>314900</private_dirty>\n            <swap>0</swap>\n            <real_memory>314900</real_memory>\n            <vmsize>1563580</vmsize>\n            <process_group_id>13608</process_group_id>\n            <command>Passenger RubyApp: /var/app/current/public</command>\n            <sockets>\n              <socket>\n                <name>main</name>\n                <address>unix:/tmp/passenger.eKFdvdC/apps.s/ruby.UWF6zkRJ71aoMXPxpknpWVfC1POFqgWZzbEsdz5v0G46cSSMxJ3GHLFhJaUrK2I</address>\n                <protocol>session</protocol>\n                <concurrency>1</concurrency>\n                <sessions>0</sessions>\n              </socket>\n              <socket>\n                <name>http</name>\n                <address>tcp://127.0.0.1:49888</address>\n                <protocol>http</protocol>\n                <concurrency>1</concurrency>\n                <sessions>0</sessions>\n              </socket>\n            </sockets>\n          </process>\n          <process>\n            <pid>11563</pid>\n            <sticky_session_id>1549681201</sticky_session_id>\n            <gupid>17173df-pX5iJOipd8</gupid>\n            <concurrency>1</concurrency>\n            <sessions>1</sessions>\n            <busyness>2147483647</busyness>\n            <processed>756</processed>\n            <spawner_creation_time>1452746835922747</spawner_creation_time>\n            <spawn_start_time>1452746845136882</spawn_start_time>\n            <spawn_end_time>1452746845172460</spawn_end_time>\n            <last_used>1452747071709179</last_used>\n            <last_used_desc>0s ago</last_used_desc>\n            <uptime>2d 5h 3m 46s</uptime>\n            <code_revision>899ac7f</code_revision>\n            <life_status>ALIVE</life_status>\n            <enabled>ENABLED</enabled>\n            <has_metrics>true</has_metrics>\n            <cpu>47</cpu>\n            <rss>418296</rss>\n            <pss>314036</pss>\n            <private_dirty>309240</private_dirty>\n            <swap>0</swap>\n            <real_memory>309240</real_memory>\n            <vmsize>1563608</vmsize>\n            <process_group_id>13608</process_group_id>\n            <command>Passenger RubyApp: /var/app/current/public</command>\n            <sockets>\n              <socket>\n                <name>main</name>\n                <address>unix:/tmp/passenger.eKFdvdC/apps.s/ruby.PVCh7TmvCi9knqhba2vG5qXrlHGEIwhGrxnUvRbIAD6SPz9m0G7YlJ8HEsREHY3</address>\n                <protocol>session</protocol>\n                <concurrency>1</concurrency>\n                <sessions>1</sessions>\n              </socket>\n              <socket>\n                <name>http</name>\n                <address>tcp://127.0.0.1:52783</address>\n                <protocol>http</protocol>\n                <concurrency>1</concurrency>\n                <sessions>0</sessions>\n              </socket>\n            </sockets>\n          </process>\n        </processes>\n      </group>\n    </supergroup>\n  </supergroups>\n</info>`\n"
  },
  {
    "path": "plugins/inputs/passenger/sample.conf",
    "content": "# Read metrics of passenger using passenger-status\n[[inputs.passenger]]\n  ## Path of passenger-status.\n  ##\n  ## Plugin gather metric via parsing XML output of passenger-status\n  ## More information about the tool:\n  ##   https://www.phusionpassenger.com/library/admin/apache/overall_status_report.html\n  ##\n  ## If no path is specified, then the plugin simply execute passenger-status\n  ## hopefully it can be found in your PATH\n  command = \"passenger-status -v --show=xml\"\n"
  },
  {
    "path": "plugins/inputs/pf/README.md",
    "content": "# PF Input Plugin\n\nThis plugin gathers information from the FreeBSD or OpenBSD pf firewall like\nthe number of current entries in the table, counters for the number of searches,\ninserts, and removals to tables using the `pfctl` command.\n\n> [!NOTE]\n> This plugin requires the `pfctl` binary to be executable by Telegraf. It\n> requires read access to the device file `/dev/pf`.\n\n⭐ Telegraf v1.5.0\n🏷️ system, network\n💻 freebsd\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather counters from PF\n[[inputs.pf]]\n  ## PF require root access on most systems.\n  ## Setting 'use_sudo' to true will make use of sudo to run pfctl.\n  ## Users must configure sudo to allow telegraf user to run pfctl with no password.\n  ## pfctl can be restricted to only list command \"pfctl -s info\".\n  use_sudo = false\n```\n\n### Permissions\n\nYou have several options to grant Telegraf the permissions to run `pfctl`:\n\n- Run telegraf as root. This is strongly discouraged.\n- Change the ownership and permissions for `/dev/pf` to allow being read by the\n  Telegraf user. This is discouraged.\n- Configure sudo to allow running `pfctl` as root by the Telegraf user.\n  This is the most restrictive option, but require sudo setup.\n- Add the Telegraf user to the `proxy` group as `/dev/pf`.\n\nFor the `sudo` option you may add the following to the sudo configuration:\n\n```sudo\ntelegraf ALL=(root) NOPASSWD: /sbin/pfctl -s info\n```\n\n## Metrics\n\n- pf\n  - entries (integer, count)\n  - searches (integer, count)\n  - inserts (integer, count)\n  - removals (integer, count)\n  - match (integer, count)\n  - bad-offset (integer, count)\n  - fragment (integer, count)\n  - short (integer, count)\n  - normalize (integer, count)\n  - memory (integer, count)\n  - bad-timestamp (integer, count)\n  - congestion (integer, count)\n  - ip-option (integer, count)\n  - proto-cksum (integer, count)\n  - state-mismatch (integer, count)\n  - state-insert (integer, count)\n  - state-limit (integer, count)\n  - src-limit (integer, count)\n  - synproxy (integer, count)\n\n## Example Output\n\n```shell\n> pfctl -s info\nStatus: Enabled for 0 days 00:26:05           Debug: Urgent\n\nState Table                          Total             Rate\n  current entries                        2\n  searches                           11325            7.2/s\n  inserts                                5            0.0/s\n  removals                               3            0.0/s\nCounters\n  match                              11226            7.2/s\n  bad-offset                             0            0.0/s\n  fragment                               0            0.0/s\n  short                                  0            0.0/s\n  normalize                              0            0.0/s\n  memory                                 0            0.0/s\n  bad-timestamp                          0            0.0/s\n  congestion                             0            0.0/s\n  ip-option                              0            0.0/s\n  proto-cksum                            0            0.0/s\n  state-mismatch                         0            0.0/s\n  state-insert                           0            0.0/s\n  state-limit                            0            0.0/s\n  src-limit                              0            0.0/s\n  synproxy                               0            0.0/s\n```\n\n```text\npf,host=columbia entries=3i,searches=2668i,inserts=12i,removals=9i 1510941775000000000\n```\n"
  },
  {
    "path": "plugins/inputs/pf/pf.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage pf\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\terrParseHeader     = fmt.Errorf(\"cannot find header in %s output\", pfctlCommand)\n\tanyTableHeaderRE   = regexp.MustCompile(\"^[A-Z]\")\n\tstateTableRE       = regexp.MustCompile(`^  (.*?)\\s+(\\d+)`)\n\tcounterTableRE     = regexp.MustCompile(`^  (.*?)\\s+(\\d+)`)\n\texecLookPath       = exec.LookPath\n\texecCommand        = exec.Command\n\tpfctlOutputStanzas = []*pfctlOutputStanza{\n\t\t{\n\t\t\theaderRE:  regexp.MustCompile(\"^State Table\"),\n\t\t\tparseFunc: parseStateTable,\n\t\t},\n\t\t{\n\t\t\theaderRE:  regexp.MustCompile(\"^Counters\"),\n\t\t\tparseFunc: parseCounterTable,\n\t\t},\n\t}\n\tstateTable = []*entry{\n\t\t{\"entries\", \"current entries\", -1},\n\t\t{\"searches\", \"searches\", -1},\n\t\t{\"inserts\", \"inserts\", -1},\n\t\t{\"removals\", \"removals\", -1},\n\t}\n\tcounterTable = []*entry{\n\t\t{\"match\", \"match\", -1},\n\t\t{\"bad-offset\", \"bad-offset\", -1},\n\t\t{\"fragment\", \"fragment\", -1},\n\t\t{\"short\", \"short\", -1},\n\t\t{\"normalize\", \"normalize\", -1},\n\t\t{\"memory\", \"memory\", -1},\n\t\t{\"bad-timestamp\", \"bad-timestamp\", -1},\n\t\t{\"congestion\", \"congestion\", -1},\n\t\t{\"ip-option\", \"ip-option\", -1},\n\t\t{\"proto-cksum\", \"proto-cksum\", -1},\n\t\t{\"state-mismatch\", \"state-mismatch\", -1},\n\t\t{\"state-insert\", \"state-insert\", -1},\n\t\t{\"state-limit\", \"state-limit\", -1},\n\t\t{\"src-limit\", \"src-limit\", -1},\n\t\t{\"synproxy\", \"synproxy\", -1},\n\t}\n)\n\nconst (\n\tmeasurement  = \"pf\"\n\tpfctlCommand = \"pfctl\"\n)\n\ntype PF struct {\n\tUseSudo bool `toml:\"use_sudo\"`\n\n\tpfctlCommand string\n\tpfctlArgs    []string\n\tinfoFunc     func() (string, error)\n}\n\ntype pfctlOutputStanza struct {\n\theaderRE  *regexp.Regexp\n\tparseFunc func([]string, map[string]interface{}) error\n\tfound     bool\n}\n\ntype entry struct {\n\tfield      string\n\tpfctlTitle string\n\tvalue      int64\n}\n\nfunc (*PF) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (pf *PF) Gather(acc telegraf.Accumulator) error {\n\tif pf.pfctlCommand == \"\" {\n\t\tvar err error\n\t\tif pf.pfctlCommand, pf.pfctlArgs, err = pf.buildPfctlCmd(); err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"can't construct pfctl commandline: %w\", err))\n\t\t\treturn nil\n\t\t}\n\t}\n\n\to, err := pf.infoFunc()\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn nil\n\t}\n\n\tif perr := parsePfctlOutput(o, acc); perr != nil {\n\t\tacc.AddError(perr)\n\t}\n\treturn nil\n}\n\nfunc errMissingData(tag string) error {\n\treturn fmt.Errorf(\"struct data for tag %q not found in %s output\", tag, pfctlCommand)\n}\n\nfunc parsePfctlOutput(pfoutput string, acc telegraf.Accumulator) error {\n\tfields := make(map[string]interface{})\n\tscanner := bufio.NewScanner(strings.NewReader(pfoutput))\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tfor _, s := range pfctlOutputStanzas {\n\t\t\tif s.headerRE.MatchString(line) {\n\t\t\t\tvar stanzaLines []string\n\t\t\t\tscanner.Scan()\n\t\t\t\tline = scanner.Text()\n\t\t\t\tfor !anyTableHeaderRE.MatchString(line) {\n\t\t\t\t\tstanzaLines = append(stanzaLines, line)\n\t\t\t\t\tmore := scanner.Scan()\n\t\t\t\t\tif !more {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tline = scanner.Text()\n\t\t\t\t}\n\t\t\t\tif perr := s.parseFunc(stanzaLines, fields); perr != nil {\n\t\t\t\t\treturn perr\n\t\t\t\t}\n\t\t\t\ts.found = true\n\t\t\t}\n\t\t}\n\t}\n\tfor _, s := range pfctlOutputStanzas {\n\t\tif !s.found {\n\t\t\treturn errParseHeader\n\t\t}\n\t}\n\n\tacc.AddFields(measurement, fields, make(map[string]string))\n\treturn nil\n}\n\nfunc parseStateTable(lines []string, fields map[string]interface{}) error {\n\treturn storeFieldValues(lines, stateTableRE, fields, stateTable)\n}\n\nfunc parseCounterTable(lines []string, fields map[string]interface{}) error {\n\treturn storeFieldValues(lines, counterTableRE, fields, counterTable)\n}\n\nfunc storeFieldValues(lines []string, regex *regexp.Regexp, fields map[string]interface{}, entryTable []*entry) error {\n\tfor _, v := range lines {\n\t\tentries := regex.FindStringSubmatch(v)\n\t\tif entries != nil {\n\t\t\tfor _, f := range entryTable {\n\t\t\t\tif f.pfctlTitle == entries[1] {\n\t\t\t\t\tvar err error\n\t\t\t\t\tif f.value, err = strconv.ParseInt(entries[2], 10, 64); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, v := range entryTable {\n\t\tif v.value == -1 {\n\t\t\treturn errMissingData(v.pfctlTitle)\n\t\t}\n\t\tfields[v.field] = v.value\n\t}\n\n\treturn nil\n}\n\nfunc (pf *PF) callPfctl() (string, error) {\n\tcmd := execCommand(pf.pfctlCommand, pf.pfctlArgs...)\n\tout, oerr := cmd.Output()\n\tif oerr != nil {\n\t\tvar ee *exec.ExitError\n\t\tif !errors.As(oerr, &ee) {\n\t\t\treturn string(out), fmt.Errorf(\"error running %q: %w: (unable to get stderr)\", pfctlCommand, oerr)\n\t\t}\n\t\treturn string(out), fmt.Errorf(\"error running %q: %w - %s\", pfctlCommand, oerr, ee.Stderr)\n\t}\n\treturn string(out), oerr\n}\n\nfunc (pf *PF) buildPfctlCmd() (string, []string, error) {\n\tcmd, err := execLookPath(pfctlCommand)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"can't locate %q: %w\", pfctlCommand, err)\n\t}\n\targs := []string{\"-s\", \"info\"}\n\tif pf.UseSudo {\n\t\targs = append([]string{cmd}, args...)\n\t\tcmd, err = execLookPath(\"sudo\")\n\t\tif err != nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"can't locate sudo: %w\", err)\n\t\t}\n\t}\n\treturn cmd, args, nil\n}\n\nfunc init() {\n\tinputs.Add(\"pf\", func() telegraf.Input {\n\t\tpf := &PF{}\n\t\tpf.infoFunc = pf.callPfctl\n\t\treturn pf\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/pf/pf_test.go",
    "content": "package pf\n\nimport (\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype measurementResult struct {\n\ttags   map[string]string\n\tfields map[string]interface{}\n}\n\nfunc TestPfctlInvocation(t *testing.T) {\n\ttype pfctlInvocationTestCase struct {\n\t\tconfig PF\n\t\tcmd    string\n\t\targs   []string\n\t}\n\n\tvar testCases = []pfctlInvocationTestCase{\n\t\t// 0: no sudo\n\t\t{\n\t\t\tconfig: PF{UseSudo: false},\n\t\t\tcmd:    \"fakepfctl\",\n\t\t\targs:   []string{\"-s\", \"info\"},\n\t\t},\n\t\t// 1: with sudo\n\t\t{\n\t\t\tconfig: PF{UseSudo: true},\n\t\t\tcmd:    \"fakesudo\",\n\t\t\targs:   []string{\"fakepfctl\", \"-s\", \"info\"},\n\t\t},\n\t}\n\n\tfor i, tt := range testCases {\n\t\texecLookPath = func(cmd string) (string, error) { return \"fake\" + cmd, nil }\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tlog.Printf(\"running #%d\\n\", i)\n\t\t\tcmd, args, err := tt.config.buildPfctlCmd()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"error when running buildPfctlCmd: %s\", err)\n\t\t\t}\n\t\t\tif tt.cmd != cmd || !reflect.DeepEqual(tt.args, args) {\n\t\t\t\tt.Errorf(\"%d: expected %s - %#v got %s - %#v\", i, tt.cmd, tt.args, cmd, args)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPfMeasurements(t *testing.T) {\n\ttype pfTestCase struct {\n\t\tTestInput    string\n\t\terr          error\n\t\tmeasurements []measurementResult\n\t}\n\n\ttestCases := []pfTestCase{\n\t\t// 0: nil input should raise an error\n\t\t{TestInput: \"\", err: errParseHeader},\n\t\t// 1: changes to pfctl output should raise an error\n\t\t{TestInput: `Status: Enabled for 161 days 21:24:45         Debug: Urgent\n\nInterface Stats for re1               IPv4             IPv6\n  Bytes In                   2585823744614    1059233657221\n  Bytes Out                  1227266932673    3274698578875\n  Packets In\n    Passed                      2289953086       1945437219\n    Blocked                      392835739            48609\n  Packets Out\n    Passed                      1649146326       2605569054\n    Blocked                            107                0\n\nState Table                          Total             Rate\n  Current Entrys                       649\n  searches                     18421725761         1317.0/s\n  inserts                        156762508           11.2/s\n  removals                       156761859           11.2/s\nCounters\n  match                          473002784           33.8/s\n  bad-offset                             0            0.0/s\n  fragment                            2729            0.0/s\n  short                                107            0.0/s\n  normalize                           1685            0.0/s\n  memory                               101            0.0/s\n  bad-timestamp                          0            0.0/s\n  congestion                             0            0.0/s\n  ip-option                         152301            0.0/s\n  proto-cksum                          108            0.0/s\n  state-mismatch                     24393            0.0/s\n  state-insert                          92            0.0/s\n  state-limit                            0            0.0/s\n  src-limit                              0            0.0/s\n  synproxy                               0            0.0/s\n`,\n\t\t\terr: errMissingData(\"current entries\"),\n\t\t},\n\t\t// 2: bad numbers should raise an error\n\t\t{TestInput: `Status: Enabled for 0 days 00:26:05           Debug: Urgent\n\nState Table                          Total             Rate\n  current entries                      -23\n  searches                           11325            7.2/s\n  inserts                                5            0.0/s\n  removals                               3            0.0/s\nCounters\n  match                              11226            7.2/s\n  bad-offset                             0            0.0/s\n  fragment                               0            0.0/s\n  short                                  0            0.0/s\n  normalize                              0            0.0/s\n  memory                                 0            0.0/s\n  bad-timestamp                          0            0.0/s\n  congestion                             0            0.0/s\n  ip-option                              0            0.0/s\n  proto-cksum                            0            0.0/s\n  state-mismatch                         0            0.0/s\n  state-insert                           0            0.0/s\n  state-limit                            0            0.0/s\n  src-limit                              0            0.0/s\n  synproxy                               0            0.0/s\n`,\n\t\t\terr: errMissingData(\"current entries\"),\n\t\t},\n\t\t{TestInput: `Status: Enabled for 0 days 00:26:05           Debug: Urgent\n\nState Table                          Total             Rate\n  current entries                        2\n  searches                           11325            7.2/s\n  inserts                                5            0.0/s\n  removals                               3            0.0/s\nCounters\n  match                              11226            7.2/s\n  bad-offset                             0            0.0/s\n  fragment                               0            0.0/s\n  short                                  0            0.0/s\n  normalize                              0            0.0/s\n  memory                                 0            0.0/s\n  bad-timestamp                          0            0.0/s\n  congestion                             0            0.0/s\n  ip-option                              0            0.0/s\n  proto-cksum                            0            0.0/s\n  state-mismatch                         0            0.0/s\n  state-insert                           0            0.0/s\n  state-limit                            0            0.0/s\n  src-limit                              0            0.0/s\n  synproxy                               0            0.0/s\n`,\n\t\t\tmeasurements: []measurementResult{\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"entries\":        int64(2),\n\t\t\t\t\t\t\"searches\":       int64(11325),\n\t\t\t\t\t\t\"inserts\":        int64(5),\n\t\t\t\t\t\t\"removals\":       int64(3),\n\t\t\t\t\t\t\"match\":          int64(11226),\n\t\t\t\t\t\t\"bad-offset\":     int64(0),\n\t\t\t\t\t\t\"fragment\":       int64(0),\n\t\t\t\t\t\t\"short\":          int64(0),\n\t\t\t\t\t\t\"normalize\":      int64(0),\n\t\t\t\t\t\t\"memory\":         int64(0),\n\t\t\t\t\t\t\"bad-timestamp\":  int64(0),\n\t\t\t\t\t\t\"congestion\":     int64(0),\n\t\t\t\t\t\t\"ip-option\":      int64(0),\n\t\t\t\t\t\t\"proto-cksum\":    int64(0),\n\t\t\t\t\t\t\"state-mismatch\": int64(0),\n\t\t\t\t\t\t\"state-insert\":   int64(0),\n\t\t\t\t\t\t\"state-limit\":    int64(0),\n\t\t\t\t\t\t\"src-limit\":      int64(0),\n\t\t\t\t\t\t\"synproxy\":       int64(0)},\n\t\t\t\t\ttags: map[string]string{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{TestInput: `Status: Enabled for 161 days 21:24:45         Debug: Urgent\n\nInterface Stats for re1               IPv4             IPv6\n  Bytes In                   2585823744614    1059233657221\n  Bytes Out                  1227266932673    3274698578875\n  Packets In\n    Passed                      2289953086       1945437219\n    Blocked                      392835739            48609\n  Packets Out\n    Passed                      1649146326       2605569054\n    Blocked                            107                0\n\nState Table                          Total             Rate\n  current entries                      649\n  searches                     18421725761         1317.0/s\n  inserts                        156762508           11.2/s\n  removals                       156761859           11.2/s\nCounters\n  match                          473002784           33.8/s\n  bad-offset                             0            0.0/s\n  fragment                            2729            0.0/s\n  short                                107            0.0/s\n  normalize                           1685            0.0/s\n  memory                               101            0.0/s\n  bad-timestamp                          0            0.0/s\n  congestion                             0            0.0/s\n  ip-option                         152301            0.0/s\n  proto-cksum                          108            0.0/s\n  state-mismatch                     24393            0.0/s\n  state-insert                          92            0.0/s\n  state-limit                            0            0.0/s\n  src-limit                              0            0.0/s\n  synproxy                               0            0.0/s\n`,\n\t\t\tmeasurements: []measurementResult{\n\t\t\t\t{\n\t\t\t\t\tfields: map[string]interface{}{\n\t\t\t\t\t\t\"entries\":        int64(649),\n\t\t\t\t\t\t\"searches\":       int64(18421725761),\n\t\t\t\t\t\t\"inserts\":        int64(156762508),\n\t\t\t\t\t\t\"removals\":       int64(156761859),\n\t\t\t\t\t\t\"match\":          int64(473002784),\n\t\t\t\t\t\t\"bad-offset\":     int64(0),\n\t\t\t\t\t\t\"fragment\":       int64(2729),\n\t\t\t\t\t\t\"short\":          int64(107),\n\t\t\t\t\t\t\"normalize\":      int64(1685),\n\t\t\t\t\t\t\"memory\":         int64(101),\n\t\t\t\t\t\t\"bad-timestamp\":  int64(0),\n\t\t\t\t\t\t\"congestion\":     int64(0),\n\t\t\t\t\t\t\"ip-option\":      int64(152301),\n\t\t\t\t\t\t\"proto-cksum\":    int64(108),\n\t\t\t\t\t\t\"state-mismatch\": int64(24393),\n\t\t\t\t\t\t\"state-insert\":   int64(92),\n\t\t\t\t\t\t\"state-limit\":    int64(0),\n\t\t\t\t\t\t\"src-limit\":      int64(0),\n\t\t\t\t\t\t\"synproxy\":       int64(0)},\n\t\t\t\t\ttags: map[string]string{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i, tt := range testCases {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tlog.Printf(\"running #%d\\n\", i)\n\t\t\tpf := &PF{\n\t\t\t\tinfoFunc: func() (string, error) {\n\t\t\t\t\treturn tt.TestInput, nil\n\t\t\t\t},\n\t\t\t}\n\t\t\tacc := new(testutil.Accumulator)\n\t\t\terr := acc.GatherError(pf.Gather)\n\t\t\tif !reflect.DeepEqual(tt.err, err) {\n\t\t\t\tt.Errorf(\"%d: expected error '%#v' got '%#v'\", i, tt.err, err)\n\t\t\t}\n\t\t\tn := 0\n\t\t\tfor j, v := range tt.measurements {\n\t\t\t\tif len(acc.Metrics) < n+1 {\n\t\t\t\t\tt.Errorf(\"%d: expected at least %d values got %d\", i, n+1, len(acc.Metrics))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tm := acc.Metrics[n]\n\t\t\t\tif !reflect.DeepEqual(m.Measurement, measurement) {\n\t\t\t\t\tt.Errorf(\"%d %d: expected measurement '%#v' got '%#v'\\n\", i, j, measurement, m.Measurement)\n\t\t\t\t}\n\t\t\t\tif !reflect.DeepEqual(m.Tags, v.tags) {\n\t\t\t\t\tt.Errorf(\"%d %d: expected tags\\n%#v got\\n%#v\\n\", i, j, v.tags, m.Tags)\n\t\t\t\t}\n\t\t\t\tif !reflect.DeepEqual(m.Fields, v.fields) {\n\t\t\t\t\tt.Errorf(\"%d %d: expected fields\\n%#v got\\n%#v\\n\", i, j, v.fields, m.Fields)\n\t\t\t\t}\n\t\t\t\tn++\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/pf/sample.conf",
    "content": "# Gather counters from PF\n[[inputs.pf]]\n  ## PF require root access on most systems.\n  ## Setting 'use_sudo' to true will make use of sudo to run pfctl.\n  ## Users must configure sudo to allow telegraf user to run pfctl with no password.\n  ## pfctl can be restricted to only list command \"pfctl -s info\".\n  use_sudo = false\n"
  },
  {
    "path": "plugins/inputs/pgbouncer/README.md",
    "content": "# PgBouncer Input Plugin\n\nThis plugin collects metrics from a [PgBouncer load balancer][pgbouncer]\ninstance. Check the [documentation][metric_docs] for available metrics and their\nmeaning.\n\n> [!NOTE]\n> This plugin requires PgBouncer v1.5+.\n\n⭐ Telegraf v1.8.0\n🏷️ server, web\n💻 all\n\n[pgbouncer]: https://pgbouncer.github.io\n[metric_docs]: https://pgbouncer.github.io/usage.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many pgbouncer servers\n[[inputs.pgbouncer]]\n  ## specify address via a url matching:\n  ##   postgres://[pqgotest[:password]]@host:port[/dbname]\\\n  ##       ?sslmode=[disable|verify-ca|verify-full]\n  ## or a simple string:\n  ##   host=localhost port=5432 user=pqgotest password=... sslmode=... dbname=app_production\n  ##\n  ## All connection parameters are optional.\n  ##\n  address = \"host=localhost user=pgbouncer sslmode=disable\"\n\n  ## Specify which \"show\" commands to gather metrics for.\n  ## Choose from: \"stats\", \"pools\", \"lists\", \"databases\"\n  # show_commands = [\"stats\", \"pools\"]\n```\n\nTo specify the `address` use either a PostgreSQL connection string:\n\n```text\nhost=/run/postgresql port=6432 user=telegraf database=pgbouncer\n```\n\nor via an URL of the following form:\n\n```text\npostgres://[pqgotest[:password]]@host:port[/dbname]?sslmode=[disable|verify-ca|verify-full]\n```\n\nAll connection parameters are optional.\n\nWithout the `dbname` parameter, the driver will default to a database with the\nsame name as the user. The `dbname` is for instantiating a connection with the\nserver only and doesn't restrict access to the databases queried.\n\n## Metrics\n\n- pgbouncer\n  - tags:\n    - db\n    - server\n  - fields:\n    - avg_query_count\n    - avg_query_time\n    - avg_wait_time\n    - avg_xact_count\n    - avg_xact_time\n    - total_query_count\n    - total_query_time\n    - total_received\n    - total_sent\n    - total_wait_time\n    - total_xact_count\n    - total_xact_time\n\n- pgbouncer_pools\n  - tags:\n    - db\n    - pool_mode\n    - server\n    - user\n  - fields:\n    - cl_active\n    - cl_waiting\n    - maxwait\n    - maxwait_us\n    - sv_active\n    - sv_idle\n    - sv_login\n    - sv_tested\n    - sv_used\n\n- pgbouncer_lists\n  - tags:\n    - db\n    - server\n    - user\n  - fields:\n    - databases\n    - users\n    - pools\n    - free_clients\n    - used_clients\n    - login_clients\n    - free_servers\n    - used_servers\n    - dns_names\n    - dns_zones\n    - dns_queries\n\n- pgbouncer_databases\n  - tags:\n    - db\n    - pg_dbname\n    - server\n    - user\n  - fields:\n    - current_connections\n    - pool_size\n    - min_pool_size\n    - reserve_pool\n    - max_connections\n    - paused\n    - disabled\n\n## Example Output\n\n```text\npgbouncer,db=pgbouncer,server=host\\=debian-buster-postgres\\ user\\=dbn\\ port\\=6432\\ dbname\\=pgbouncer\\  avg_query_count=0i,avg_query_time=0i,avg_wait_time=0i,avg_xact_count=0i,avg_xact_time=0i,total_query_count=26i,total_query_time=0i,total_received=0i,total_sent=0i,total_wait_time=0i,total_xact_count=26i,total_xact_time=0i 1581569936000000000\npgbouncer_pools,db=pgbouncer,pool_mode=statement,server=host\\=debian-buster-postgres\\ user\\=dbn\\ port\\=6432\\ dbname\\=pgbouncer\\ ,user=pgbouncer cl_active=1i,cl_waiting=0i,maxwait=0i,maxwait_us=0i,sv_active=0i,sv_idle=0i,sv_login=0i,sv_tested=0i,sv_used=0i 1581569936000000000\npgbouncer_lists,db=pgbouncer,server=host\\=debian-buster-postgres\\ user\\=dbn\\ port\\=6432\\ dbname\\=pgbouncer\\ ,user=pgbouncer databases=1i,dns_names=0i,dns_queries=0i,dns_zones=0i,free_clients=47i,free_servers=0i,login_clients=0i,pools=1i,used_clients=3i,used_servers=0i,users=4i 1581569936000000000\npgbouncer_databases,db=pgbouncer,pg_dbname=pgbouncer,server=host\\=debian-buster-postgres\\ user\\=dbn\\ port\\=6432\\ dbname\\=pgbouncer\\ name=pgbouncer disabled=0i,pool_size=2i,current_connections=0i,min_pool_size=0i,reserve_pool=0i,max_connections=0i,paused=0i 1581569936000000000\npgbouncer_databases,db=postgres,pg_dbname=postgres,server=host\\=debian-buster-postgres\\ user\\=dbn\\ port\\=6432\\ dbname\\=pgbouncer\\ name=postgres current_connections=0i,disabled=0i,pool_size=20i,min_pool_size=0i,reserve_pool=0i,paused=0i,max_connections=0i 1581569936000000000\n```\n"
  },
  {
    "path": "plugins/inputs/pgbouncer/pgbouncer.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage pgbouncer\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar ignoredColumns = map[string]bool{\"user\": true, \"database\": true, \"pool_mode\": true,\n\t\"avg_req\": true, \"avg_recv\": true, \"avg_sent\": true, \"avg_query\": true,\n\t\"force_user\": true, \"host\": true, \"port\": true, \"name\": true,\n}\n\ntype PgBouncer struct {\n\tShowCommands []string `toml:\"show_commands\"`\n\tpostgresql.Config\n\n\tservice *postgresql.Service\n}\n\nfunc (*PgBouncer) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *PgBouncer) Init() error {\n\t// Set defaults and check settings\n\tif len(p.ShowCommands) == 0 {\n\t\tp.ShowCommands = []string{\"stats\", \"pools\"}\n\t}\n\tfor _, cmd := range p.ShowCommands {\n\t\tswitch cmd {\n\t\tcase \"stats\", \"pools\", \"lists\", \"databases\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid setting %q for 'show_command'\", cmd)\n\t\t}\n\t}\n\n\t// Create a postgres service for the queries\n\tservice, err := p.Config.CreateService()\n\tif err != nil {\n\t\treturn err\n\t}\n\tp.service = service\n\treturn nil\n}\n\nfunc (p *PgBouncer) Start(_ telegraf.Accumulator) error {\n\treturn p.service.Start()\n}\n\nfunc (p *PgBouncer) Gather(acc telegraf.Accumulator) error {\n\tfor _, cmd := range p.ShowCommands {\n\t\tswitch cmd {\n\t\tcase \"stats\":\n\t\t\tif err := p.showStats(acc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase \"pools\":\n\t\t\tif err := p.showPools(acc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase \"lists\":\n\t\t\tif err := p.showLists(acc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase \"databases\":\n\t\t\tif err := p.showDatabase(acc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *PgBouncer) Stop() {\n\tp.service.Stop()\n}\n\nfunc (p *PgBouncer) accRow(row *sql.Rows, columns []string) (map[string]string, map[string]*interface{}, error) {\n\tvar dbname bytes.Buffer\n\n\t// this is where we'll store the column name with its *interface{}\n\tcolumnMap := make(map[string]*interface{})\n\tfor _, column := range columns {\n\t\tcolumnMap[column] = new(interface{})\n\t}\n\n\tcolumnVars := make([]interface{}, 0, len(columnMap))\n\t// populate the array of interface{} with the pointers in the right order\n\tfor i := 0; i < len(columnMap); i++ {\n\t\tcolumnVars = append(columnVars, columnMap[columns[i]])\n\t}\n\n\t// deconstruct array of variables and send to Scan\n\terr := row.Scan(columnVars...)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"couldn't copy the data: %w\", err)\n\t}\n\tif columnMap[\"database\"] != nil {\n\t\t// extract the database name from the column map\n\t\tname, ok := (*columnMap[\"database\"]).(string)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"database not a string, but %T\", *columnMap[\"database\"])\n\t\t}\n\t\tdbname.WriteString(name)\n\t} else {\n\t\tdbname.WriteString(\"pgbouncer\")\n\t}\n\n\t// Return basic tags and the mapped columns\n\treturn map[string]string{\"server\": p.service.SanitizedAddress, \"db\": dbname.String()}, columnMap, nil\n}\n\nfunc (p *PgBouncer) showStats(acc telegraf.Accumulator) error {\n\t// STATS\n\trows, err := p.service.DB.Query(`SHOW STATS`)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"execution error 'show stats': %w\", err)\n\t}\n\n\tdefer rows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"don't get column names 'show stats': %w\", err)\n\t}\n\n\tfor rows.Next() {\n\t\ttags, columnMap, err := p.accRow(rows, columns)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfor col, val := range columnMap {\n\t\t\t_, ignore := ignoredColumns[col]\n\t\t\tif ignore {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch v := (*val).(type) {\n\t\t\tcase int64:\n\t\t\t\t// Integer fields are returned in pgbouncer 1.5 through 1.9\n\t\t\t\tfields[col] = v\n\t\t\tcase string:\n\t\t\t\t// Integer fields are returned in pgbouncer 1.12\n\t\t\t\tinteger, err := strconv.ParseInt(v, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"couldn't convert metrics 'show stats': %w\", err)\n\t\t\t\t}\n\n\t\t\t\tfields[col] = integer\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"pgbouncer\", fields, tags)\n\t}\n\n\treturn rows.Err()\n}\n\nfunc (p *PgBouncer) showPools(acc telegraf.Accumulator) error {\n\t// POOLS\n\tpoolRows, err := p.service.DB.Query(`SHOW POOLS`)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"execution error 'show pools': %w\", err)\n\t}\n\n\tdefer poolRows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := poolRows.Columns()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"don't get column names 'show pools': %w\", err)\n\t}\n\n\tfor poolRows.Next() {\n\t\ttags, columnMap, err := p.accRow(poolRows, columns)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif user, ok := columnMap[\"user\"]; ok {\n\t\t\tif s, ok := (*user).(string); ok && s != \"\" {\n\t\t\t\ttags[\"user\"] = s\n\t\t\t}\n\t\t}\n\n\t\tif poolMode, ok := columnMap[\"pool_mode\"]; ok {\n\t\t\tif s, ok := (*poolMode).(string); ok && s != \"\" {\n\t\t\t\ttags[\"pool_mode\"] = s\n\t\t\t}\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfor col, val := range columnMap {\n\t\t\t_, ignore := ignoredColumns[col]\n\t\t\tif !ignore {\n\t\t\t\tfields[col] = *val\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"pgbouncer_pools\", fields, tags)\n\t}\n\n\treturn poolRows.Err()\n}\n\nfunc (p *PgBouncer) showLists(acc telegraf.Accumulator) error {\n\t// LISTS\n\trows, err := p.service.DB.Query(`SHOW LISTS`)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"execution error 'show lists': %w\", err)\n\t}\n\n\tdefer rows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"don't get column names 'show lists': %w\", err)\n\t}\n\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\tfor rows.Next() {\n\t\ttag, columnMap, err := p.accRow(rows, columns)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tname, ok := (*columnMap[\"list\"]).(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"metric name(show lists) not a string, but %T\", *columnMap[\"list\"])\n\t\t}\n\t\tif name != \"dns_pending\" {\n\t\t\tvalue, ok := (*columnMap[\"items\"]).(int64)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"metric value(show lists) not a int64, but %T\", *columnMap[\"items\"])\n\t\t\t}\n\t\t\tfields[name] = value\n\t\t\ttags = tag\n\t\t}\n\t}\n\tacc.AddFields(\"pgbouncer_lists\", fields, tags)\n\n\treturn rows.Err()\n}\n\nfunc (p *PgBouncer) showDatabase(acc telegraf.Accumulator) error {\n\t// DATABASES\n\trows, err := p.service.DB.Query(`SHOW DATABASES`)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"execution error 'show database': %w\", err)\n\t}\n\tdefer rows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"don't get column names 'show database': %w\", err)\n\t}\n\n\tfor rows.Next() {\n\t\ttags, columnMap, err := p.accRow(rows, columns)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// SHOW DATABASES displays pgbouncer database name under name column,\n\t\t// while using database column to store Postgres database name.\n\t\tif database, ok := columnMap[\"database\"]; ok {\n\t\t\tif s, ok := (*database).(string); ok && s != \"\" {\n\t\t\t\ttags[\"pg_dbname\"] = s\n\t\t\t}\n\t\t}\n\n\t\t// pass it under db tag to be compatible with the rest of the measurements\n\t\tif name, ok := columnMap[\"name\"]; ok {\n\t\t\tif s, ok := (*name).(string); ok && s != \"\" {\n\t\t\t\ttags[\"db\"] = s\n\t\t\t}\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfor col, val := range columnMap {\n\t\t\t_, ignore := ignoredColumns[col]\n\t\t\tif !ignore {\n\t\t\t\tfields[col] = *val\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"pgbouncer_databases\", fields, tags)\n\t}\n\treturn rows.Err()\n}\n\nfunc init() {\n\tinputs.Add(\"pgbouncer\", func() telegraf.Input {\n\t\treturn &PgBouncer{\n\t\t\tConfig: postgresql.Config{\n\t\t\t\tMaxIdle:     1,\n\t\t\t\tMaxOpen:     1,\n\t\t\t\tIsPgBouncer: true,\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/pgbouncer/pgbouncer_test.go",
    "content": "package pgbouncer\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestPgBouncerGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tpostgresServicePort := \"5432\"\n\tpgBouncerServicePort := \"6432\"\n\n\tbackend := testutil.Container{\n\t\tImage:        \"postgres:alpine\",\n\t\tExposedPorts: []string{postgresServicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n\t\t},\n\t\tWaitingFor: wait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t}\n\trequire.NoError(t, backend.Start(), \"failed to start container\")\n\tdefer backend.Terminate()\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"z9pascal/pgbouncer-container:1.24.1-latest\",\n\t\tExposedPorts: []string{pgBouncerServicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"PG_ENV_POSTGRESQL_USER\": \"pgbouncer\",\n\t\t\t\"PG_ENV_POSTGRESQL_PASS\": \"pgbouncer\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(pgBouncerServicePort)),\n\t\t\twait.ForLog(\"LOG process up\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s user=pgbouncer password=pgbouncer dbname=pgbouncer port=%s sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[pgBouncerServicePort],\n\t)\n\n\tp := &PgBouncer{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:     config.NewSecret([]byte(addr)),\n\t\t\tIsPgBouncer: true,\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tintMetricsPgBouncer := []string{\n\t\t\"total_received\",\n\t\t\"total_sent\",\n\t\t\"total_query_time\",\n\t\t\"avg_query_count\",\n\t\t\"avg_query_time\",\n\t\t\"avg_wait_time\",\n\t}\n\n\tintMetricsPgBouncerPools := []string{\n\t\t\"cl_active\",\n\t\t\"cl_waiting\",\n\t\t\"sv_active\",\n\t\t\"sv_idle\",\n\t\t\"sv_used\",\n\t\t\"sv_tested\",\n\t\t\"sv_login\",\n\t\t\"maxwait\",\n\t}\n\n\tmetricsCounted := 0\n\n\tfor _, metric := range intMetricsPgBouncer {\n\t\trequire.True(t, acc.HasInt64Field(\"pgbouncer\", metric))\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range intMetricsPgBouncerPools {\n\t\trequire.True(t, acc.HasInt64Field(\"pgbouncer_pools\", metric))\n\t\tmetricsCounted++\n\t}\n\n\trequire.Positive(t, metricsCounted)\n\trequire.Equal(t, len(intMetricsPgBouncer)+len(intMetricsPgBouncerPools), metricsCounted)\n}\n\nfunc TestPgBouncerGeneratesMetricsIntegrationShowCommands(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tpostgresServicePort := \"5432\"\n\tpgBouncerServicePort := \"6432\"\n\n\tbackend := testutil.Container{\n\t\tImage:        \"postgres:alpine\",\n\t\tExposedPorts: []string{postgresServicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n\t\t},\n\t\tWaitingFor: wait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t}\n\terr := backend.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer backend.Terminate()\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"z9pascal/pgbouncer-container:1.24.1-latest\",\n\t\tExposedPorts: []string{pgBouncerServicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"PG_ENV_POSTGRESQL_USER\": \"pgbouncer\",\n\t\t\t\"PG_ENV_POSTGRESQL_PASS\": \"pgbouncer\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForListeningPort(nat.Port(pgBouncerServicePort)),\n\t\t\twait.ForLog(\"LOG process up\"),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s user=pgbouncer password=pgbouncer dbname=pgbouncer port=%s sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[pgBouncerServicePort],\n\t)\n\n\tp := &PgBouncer{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:     config.NewSecret([]byte(addr)),\n\t\t\tIsPgBouncer: true,\n\t\t},\n\t\tShowCommands: []string{\"pools\", \"lists\", \"databases\"},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tintMetricsPgBouncerPools := []string{\n\t\t\"cl_active\",\n\t\t\"cl_waiting\",\n\t\t\"sv_active\",\n\t\t\"sv_idle\",\n\t\t\"sv_used\",\n\t\t\"sv_tested\",\n\t\t\"sv_login\",\n\t\t\"maxwait\",\n\t}\n\n\tintMetricsPgBouncerLists := []string{\n\t\t\"databases\",\n\t\t\"users\",\n\t\t\"pools\",\n\t\t\"free_clients\",\n\t\t\"used_clients\",\n\t\t\"login_clients\",\n\t\t\"free_servers\",\n\t\t\"used_servers\",\n\t\t\"dns_names\",\n\t\t\"dns_zones\",\n\t\t\"dns_queries\",\n\t}\n\n\tintMetricsPgBouncerDatabases := []string{\n\t\t\"pool_size\",\n\t\t\"min_pool_size\",\n\t\t\"reserve_pool_size\",\n\t\t\"max_connections\",\n\t\t\"current_connections\",\n\t\t\"paused\",\n\t\t\"disabled\",\n\t}\n\n\tmetricsCounted := 0\n\n\tfor _, metric := range intMetricsPgBouncerPools {\n\t\trequire.True(t, acc.HasInt64Field(\"pgbouncer_pools\", metric))\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range intMetricsPgBouncerLists {\n\t\trequire.True(t, acc.HasInt64Field(\"pgbouncer_lists\", metric))\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range intMetricsPgBouncerDatabases {\n\t\trequire.True(t, acc.HasInt64Field(\"pgbouncer_databases\", metric))\n\t\tmetricsCounted++\n\t}\n\n\trequire.Positive(t, metricsCounted)\n\trequire.Equal(t, len(intMetricsPgBouncerPools)+len(intMetricsPgBouncerLists)+len(intMetricsPgBouncerDatabases), metricsCounted)\n}\n"
  },
  {
    "path": "plugins/inputs/pgbouncer/sample.conf",
    "content": "# Read metrics from one or many pgbouncer servers\n[[inputs.pgbouncer]]\n  ## specify address via a url matching:\n  ##   postgres://[pqgotest[:password]]@host:port[/dbname]\\\n  ##       ?sslmode=[disable|verify-ca|verify-full]\n  ## or a simple string:\n  ##   host=localhost port=5432 user=pqgotest password=... sslmode=... dbname=app_production\n  ##\n  ## All connection parameters are optional.\n  ##\n  address = \"host=localhost user=pgbouncer sslmode=disable\"\n\n  ## Specify which \"show\" commands to gather metrics for.\n  ## Choose from: \"stats\", \"pools\", \"lists\", \"databases\"\n  # show_commands = [\"stats\", \"pools\"]\n"
  },
  {
    "path": "plugins/inputs/phpfpm/README.md",
    "content": "# PHP-FPM Input Plugin\n\nThis plugin gathers statistics of the [PHP FastCGI Process Manager][phpfpm]\nusing either the HTTP status page or the fpm socket.\n\n⭐ Telegraf v0.1.10\n🏷️ server, web\n💻 all\n\n[phpfpm]: https://www.php.net/manual/en/install.fpm.php\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics of phpfpm, via HTTP status page or socket\n[[inputs.phpfpm]]\n  ## An array of addresses to gather stats about. Specify an ip or hostname\n  ## with optional port and path\n  ##\n  ## Plugin can be configured in three modes (either can be used):\n  ##   - http: the URL must start with http:// or https://, ie:\n  ##       \"http://localhost/status\"\n  ##       \"http://192.168.130.1/status?full\"\n  ##\n  ##   - unixsocket: path to fpm socket, ie:\n  ##       \"/var/run/php5-fpm.sock\"\n  ##      or using a custom fpm status path:\n  ##       \"/var/run/php5-fpm.sock:fpm-custom-status-path\"\n  ##      glob patterns are also supported:\n  ##       \"/var/run/php*.sock\"\n  ##\n  ##   - fcgi: the URL must start with fcgi:// or cgi://, and port must be present, ie:\n  ##       \"fcgi://10.0.0.12:9000/status\"\n  ##       \"cgi://10.0.10.12:9001/status\"\n  ##\n  ## Example of multiple gathering from local socket and remote host\n  ## urls = [\"http://192.168.1.20/status\", \"/tmp/fpm.sock\"]\n  urls = [\"http://localhost/status\"]\n\n  ## Format of stats to parse, set to \"status\" or \"json\"\n  ## If the user configures the URL to return JSON (e.g.\n  ## http://localhost/status?json), set to JSON. Otherwise, will attempt to\n  ## parse line-by-line. The JSON mode will produce additional metrics.\n  # format = \"status\"\n\n  ## Duration allowed to complete HTTP requests.\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\nWhen using `unixsocket`, you have to ensure that telegraf runs on same\nhost, and socket path is accessible to telegraf user.\n\n## Metrics\n\n- phpfpm\n  - tags:\n    - pool\n    - url\n  - fields:\n    - accepted_conn\n    - listen_queue\n    - max_listen_queue\n    - listen_queue_len\n    - idle_processes\n    - active_processes\n    - total_processes\n    - max_active_processes\n    - max_children_reached\n    - slow_requests\n- phpfpm_process\n  - tags:\n    - pool\n    - request method\n    - request uri\n    - script\n    - url\n    - user\n  - fields:\n    - pid\n    - content length\n    - last request cpu\n    - last request memory\n    - request duration\n    - requests\n    - start time\n    - start since\n    - state\n\n## Example Output\n\n```text\nphpfpm,pool=www accepted_conn=13i,active_processes=2i,idle_processes=1i,listen_queue=0i,listen_queue_len=0i,max_active_processes=2i,max_children_reached=0i,max_listen_queue=0i,slow_requests=0i,total_processes=3i 1453011293083331187\nphpfpm,pool=www2 accepted_conn=12i,active_processes=1i,idle_processes=2i,listen_queue=0i,listen_queue_len=0i,max_active_processes=2i,max_children_reached=0i,max_listen_queue=0i,slow_requests=0i,total_processes=3i 1453011293083691422\nphpfpm,pool=www3 accepted_conn=11i,active_processes=1i,idle_processes=2i,listen_queue=0i,listen_queue_len=0i,max_active_processes=2i,max_children_reached=0i,max_listen_queue=0i,slow_requests=0i,total_processes=3i 1453011293083691658\n```\n\nWith the JSON output, additional metrics around processes are generated:\n\n```text\nphpfpm,pool=www,url=http://127.0.0.1:44637?full&json accepted_conn=3879i,active_processes=1i,idle_processes=9i,listen_queue=0i,listen_queue_len=0i,max_active_processes=3i,max_children_reached=0i,max_listen_queue=0i,slow_requests=0i,start_since=4901i,total_processes=10i\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status?json&full,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=583i,last_request_cpu=0,last_request_memory=0,request_duration=159i,requests=386i,start_time=1702044927i,state=\"Running\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=584i,last_request_cpu=0,last_request_memory=2097152,request_duration=174i,requests=390i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=585i,last_request_cpu=104.93,last_request_memory=2097152,request_duration=9530i,requests=389i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=586i,last_request_cpu=0,last_request_memory=2097152,request_duration=127i,requests=399i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=587i,last_request_cpu=0,last_request_memory=2097152,request_duration=9713i,requests=382i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=588i,last_request_cpu=0,last_request_memory=2097152,request_duration=133i,requests=383i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status?json,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=589i,last_request_cpu=0,last_request_memory=2097152,request_duration=154i,requests=381i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=590i,last_request_cpu=0,last_request_memory=2097152,request_duration=108i,requests=397i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=591i,last_request_cpu=110.28,last_request_memory=2097152,request_duration=9068i,requests=381i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=592i,last_request_cpu=64.27,last_request_memory=2097152,request_duration=15559i,requests=391i,start_time=1702044927i,state=\"Idle\"\n```\n"
  },
  {
    "path": "plugins/inputs/phpfpm/child.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage phpfpm\n\n// This file implements FastCGI from the perspective of a child process.\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/cgi\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n// request holds the state for an in-progress request. As soon as it's complete,\n// it's converted to an http.Request.\ntype request struct {\n\tpw        *io.PipeWriter\n\treqID     uint16\n\tparams    map[string]string\n\tbuf       [1024]byte\n\trawParams []byte\n\tkeepConn  bool\n}\n\nfunc newRequest(reqID uint16, flags uint8) *request {\n\tr := &request{\n\t\treqID:    reqID,\n\t\tparams:   make(map[string]string),\n\t\tkeepConn: flags&flagKeepConn != 0,\n\t}\n\tr.rawParams = r.buf[:0]\n\treturn r\n}\n\n// parseParams reads an encoded []byte into Params.\nfunc (r *request) parseParams() {\n\ttext := r.rawParams\n\tr.rawParams = nil\n\tfor len(text) > 0 {\n\t\tkeyLen, n := readSize(text)\n\t\tif n == 0 {\n\t\t\treturn\n\t\t}\n\t\ttext = text[n:]\n\t\tvalLen, n := readSize(text)\n\t\tif n == 0 {\n\t\t\treturn\n\t\t}\n\t\ttext = text[n:]\n\t\tif int(keyLen)+int(valLen) > len(text) {\n\t\t\treturn\n\t\t}\n\t\tkey := readString(text, keyLen)\n\t\ttext = text[keyLen:]\n\t\tval := readString(text, valLen)\n\t\ttext = text[valLen:]\n\t\tr.params[key] = val\n\t}\n}\n\n// response implements http.ResponseWriter.\ntype response struct {\n\treq         *request\n\theader      http.Header\n\tw           *bufWriter\n\twroteHeader bool\n}\n\nfunc newResponse(c *child, req *request) *response {\n\treturn &response{\n\t\treq:    req,\n\t\theader: http.Header{},\n\t\tw:      newWriter(c.conn, typeStdout, req.reqID),\n\t}\n}\n\n// Header returns the HTTP headers for the response.\nfunc (r *response) Header() http.Header {\n\treturn r.header\n}\n\nfunc (r *response) Write(data []byte) (int, error) {\n\tif !r.wroteHeader {\n\t\tr.WriteHeader(http.StatusOK)\n\t}\n\treturn r.w.Write(data)\n}\n\n// WriteHeader sends an HTTP response header with the provided status code.\nfunc (r *response) WriteHeader(code int) {\n\tif r.wroteHeader {\n\t\treturn\n\t}\n\tr.wroteHeader = true\n\tif code == http.StatusNotModified {\n\t\t// Must not have body.\n\t\tr.header.Del(\"Content-Type\")\n\t\tr.header.Del(\"Content-Length\")\n\t\tr.header.Del(\"Transfer-Encoding\")\n\t} else if r.header.Get(\"Content-Type\") == \"\" {\n\t\tr.header.Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t}\n\n\tif r.header.Get(\"Date\") == \"\" {\n\t\tr.header.Set(\"Date\", time.Now().UTC().Format(http.TimeFormat))\n\t}\n\n\tfmt.Fprintf(r.w, \"Status: %d %s\\r\\n\", code, http.StatusText(code))\n\t//nolint:errcheck // unable to propagate\n\tr.header.Write(r.w)\n\t//nolint:errcheck // unable to propagate\n\tr.w.WriteString(\"\\r\\n\")\n}\n\n// Flush sends any buffered data to the client.\nfunc (r *response) Flush() {\n\tif !r.wroteHeader {\n\t\tr.WriteHeader(http.StatusOK)\n\t}\n\t_ = r.w.Flush()\n}\n\n// Close closes the connection or resource associated with the response.\n// It ensures proper cleanup of resources.\nfunc (r *response) Close() error {\n\tr.Flush()\n\treturn r.w.Close()\n}\n\ntype child struct {\n\tconn    *conn\n\thandler http.Handler\n\n\tmu       sync.Mutex          // protects requests:\n\trequests map[uint16]*request // keyed by request ID\n}\n\nfunc newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {\n\treturn &child{\n\t\tconn:     newConn(rwc),\n\t\thandler:  handler,\n\t\trequests: make(map[uint16]*request),\n\t}\n}\n\nfunc (c *child) serve() {\n\tdefer c.conn.Close()\n\tdefer c.cleanUp()\n\tvar rec record\n\tfor {\n\t\tif err := rec.read(c.conn.rwc); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err := c.handleRecord(&rec); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nvar errCloseConn = errors.New(\"fcgi: connection should be closed\")\n\nvar emptyBody = io.NopCloser(strings.NewReader(\"\"))\n\n// errRequestAborted is returned by Read when a handler attempts to read the\n// body of a request that has been aborted by the web server.\nvar errRequestAborted = errors.New(\"fcgi: request aborted by web server\")\n\n// errConnClosed is returned by Read when a handler attempts to read the body of\n// a request after the connection to the web server has been closed.\nvar errConnClosed = errors.New(\"fcgi: connection to web server closed\")\n\nfunc (c *child) handleRecord(rec *record) error {\n\tc.mu.Lock()\n\treq, ok := c.requests[rec.h.ID]\n\tc.mu.Unlock()\n\tif !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {\n\t\t// The spec says to ignore unknown request IDs.\n\t\treturn nil\n\t}\n\n\tswitch rec.h.Type {\n\tcase typeBeginRequest:\n\t\tif req != nil {\n\t\t\t// The server is trying to begin a request with the same ID\n\t\t\t// as an in-progress request. This is an error.\n\t\t\treturn errors.New(\"fcgi: received ID that is already in-flight\")\n\t\t}\n\n\t\tvar br beginRequest\n\t\tif err := br.read(rec.content()); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif br.role != roleResponder {\n\t\t\treturn c.conn.writeEndRequest(rec.h.ID, 0, statusUnknownRole)\n\t\t}\n\t\treq = newRequest(rec.h.ID, br.flags)\n\t\tc.mu.Lock()\n\t\tc.requests[rec.h.ID] = req\n\t\tc.mu.Unlock()\n\t\treturn nil\n\tcase typeParams:\n\t\t// NOTE(eds): Technically a key-value pair can straddle the boundary\n\t\t// between two packets. We buffer until we've received all parameters.\n\t\tif len(rec.content()) > 0 {\n\t\t\treq.rawParams = append(req.rawParams, rec.content()...)\n\t\t\treturn nil\n\t\t}\n\t\treq.parseParams()\n\t\treturn nil\n\tcase typeStdin:\n\t\tcontent := rec.content()\n\t\tif req.pw == nil {\n\t\t\tvar body io.ReadCloser\n\t\t\tif len(content) > 0 {\n\t\t\t\t// body could be an io.LimitReader, but it shouldn't matter\n\t\t\t\t// as long as both sides are behaving.\n\t\t\t\tbody, req.pw = io.Pipe()\n\t\t\t} else {\n\t\t\t\tbody = emptyBody\n\t\t\t}\n\t\t\tgo c.serveRequest(req, body)\n\t\t}\n\t\tif len(content) > 0 {\n\t\t\t// TODO(eds): This blocks until the handler reads from the pipe.\n\t\t\t// If the handler takes a long time, it might be a problem.\n\t\t\tif _, err := req.pw.Write(content); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if req.pw != nil {\n\t\t\tif err := req.pw.Close(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase typeGetValues:\n\t\tvalues := map[string]string{\"FCGI_MPXS_CONNS\": \"1\"}\n\t\treturn c.conn.writePairs(typeGetValuesResult, 0, values)\n\tcase typeData:\n\t\t// If the filter role is implemented, read the data stream here.\n\t\treturn nil\n\tcase typeAbortRequest:\n\t\tc.mu.Lock()\n\t\tdelete(c.requests, rec.h.ID)\n\t\tc.mu.Unlock()\n\t\tif err := c.conn.writeEndRequest(rec.h.ID, 0, statusRequestComplete); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif req.pw != nil {\n\t\t\treq.pw.CloseWithError(errRequestAborted)\n\t\t}\n\t\tif !req.keepConn {\n\t\t\t// connection will close upon return\n\t\t\treturn errCloseConn\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\tb := make([]byte, 8)\n\t\tb[0] = byte(rec.h.Type)\n\t\treturn c.conn.writeRecord(typeUnknownType, 0, b)\n\t}\n}\n\nfunc (c *child) serveRequest(req *request, body io.ReadCloser) {\n\tr := newResponse(c, req)\n\thttpReq, err := cgi.RequestFromMap(req.params)\n\tif err != nil {\n\t\t// there was an error reading the request\n\t\tr.WriteHeader(http.StatusInternalServerError)\n\t\tif err := c.conn.writeRecord(typeStderr, req.reqID, []byte(err.Error())); err != nil {\n\t\t\treturn\n\t\t}\n\t} else {\n\t\thttpReq.Body = body\n\t\tc.handler.ServeHTTP(r, httpReq)\n\t}\n\tr.Close()\n\tc.mu.Lock()\n\tdelete(c.requests, req.reqID)\n\tc.mu.Unlock()\n\tif err := c.conn.writeEndRequest(req.reqID, 0, statusRequestComplete); err != nil {\n\t\treturn\n\t}\n\n\t// Consume the entire body, so the host isn't still writing to\n\t// us when we close the socket below in the !keepConn case,\n\t// otherwise we'd send a RST. (golang.org/issue/4183)\n\t// TODO(bradfitz): also bound this copy in time. Or send\n\t// some sort of abort request to the host, so the host\n\t// can properly cut off the client sending all the data.\n\t// For now just bound it a little and\n\tio.CopyN(io.Discard, body, 100<<20) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\tbody.Close()\n\n\tif !req.keepConn {\n\t\tc.conn.Close()\n\t}\n}\n\nfunc (c *child) cleanUp() {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tfor _, req := range c.requests {\n\t\tif req.pw != nil {\n\t\t\t// race with call to Close in c.serveRequest doesn't matter because\n\t\t\t// Pipe(Reader|Writer).Close are idempotent\n\t\t\treq.pw.CloseWithError(errConnClosed)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/fcgi.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// Package phpfpm implements the FastCGI protocol.\n// Currently only the responder role is supported.\n// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22\npackage phpfpm\n\n// This file defines the raw protocol and some utilities used by the child and\n// the host.\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n)\n\n// recType is a record type, as defined by\n// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8\ntype recType uint8\n\nconst (\n\ttypeBeginRequest    recType = 1\n\ttypeAbortRequest    recType = 2\n\ttypeEndRequest      recType = 3\n\ttypeParams          recType = 4\n\ttypeStdin           recType = 5\n\ttypeStdout          recType = 6\n\ttypeStderr          recType = 7\n\ttypeData            recType = 8\n\ttypeGetValues       recType = 9\n\ttypeGetValuesResult recType = 10\n\ttypeUnknownType     recType = 11\n)\n\n// keep the connection between web-server and responder open after request\nconst flagKeepConn = 1\n\nconst (\n\tmaxWrite = 65535 // maximum record body\n\tmaxPad   = 255\n)\n\nconst (\n\troleResponder = iota + 1 // only Responders are implemented.\n\troleAuthorizer\n\troleFilter\n)\n\nconst (\n\tstatusRequestComplete = iota\n\tstatusCantMultiplex\n\tstatusOverloaded\n\tstatusUnknownRole\n)\n\ntype header struct {\n\tVersion       uint8\n\tType          recType\n\tID            uint16\n\tContentLength uint16\n\tPaddingLength uint8\n\tReserved      uint8\n}\n\ntype beginRequest struct {\n\trole     uint16\n\tflags    uint8\n\treserved [5]uint8 //nolint:unused // Memory reservation\n}\n\nfunc (br *beginRequest) read(content []byte) error {\n\tif len(content) != 8 {\n\t\treturn errors.New(\"fcgi: invalid begin request record\")\n\t}\n\tbr.role = binary.BigEndian.Uint16(content)\n\tbr.flags = content[2]\n\treturn nil\n}\n\n// for padding so we don't have to allocate all the time\n// not synchronized because we don't care what the contents are\nvar pad [maxPad]byte\n\nfunc (h *header) init(recType recType, reqID uint16, contentLength int) {\n\th.Version = 1\n\th.Type = recType\n\th.ID = reqID\n\th.ContentLength = uint16(contentLength)\n\th.PaddingLength = uint8(-contentLength & 7)\n}\n\n// conn sends records over rwc\ntype conn struct {\n\tmutex sync.Mutex\n\trwc   io.ReadWriteCloser\n\n\t// to avoid allocations\n\tbuf bytes.Buffer\n\th   header\n}\n\nfunc newConn(rwc io.ReadWriteCloser) *conn {\n\treturn &conn{rwc: rwc}\n}\n\n// Close closes the FastCGI connection and releases resources.\nfunc (c *conn) Close() error {\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\treturn c.rwc.Close()\n}\n\ntype record struct {\n\th   header\n\tbuf [maxWrite + maxPad]byte\n}\n\nfunc (rec *record) read(r io.Reader) (err error) {\n\tif err := binary.Read(r, binary.BigEndian, &rec.h); err != nil {\n\t\treturn err\n\t}\n\tif rec.h.Version != 1 {\n\t\treturn errors.New(\"fcgi: invalid header version\")\n\t}\n\tn := int(rec.h.ContentLength) + int(rec.h.PaddingLength)\n\tif _, err = io.ReadFull(r, rec.buf[:n]); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (rec *record) content() []byte {\n\treturn rec.buf[:rec.h.ContentLength]\n}\n\n// writeRecord writes and sends a single record.\nfunc (c *conn) writeRecord(recType recType, reqID uint16, b []byte) error {\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tc.buf.Reset()\n\tc.h.init(recType, reqID, len(b))\n\tif err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {\n\t\treturn err\n\t}\n\tc.buf.Write(b)\n\tc.buf.Write(pad[:c.h.PaddingLength])\n\t_, err := c.rwc.Write(c.buf.Bytes())\n\treturn err\n}\n\nfunc (c *conn) writeBeginRequest(reqID, role uint16, flags uint8) error {\n\tb := [8]byte{byte(role >> 8), byte(role), flags}\n\treturn c.writeRecord(typeBeginRequest, reqID, b[:])\n}\n\nfunc (c *conn) writeEndRequest(reqID uint16, appStatus int, protocolStatus uint8) error {\n\tb := make([]byte, 8)\n\tbinary.BigEndian.PutUint32(b, uint32(appStatus))\n\tb[4] = protocolStatus\n\treturn c.writeRecord(typeEndRequest, reqID, b)\n}\n\nfunc (c *conn) writePairs(recType recType, reqID uint16, pairs map[string]string) error {\n\tw := newWriter(c, recType, reqID)\n\tb := make([]byte, 8)\n\tfor k, v := range pairs {\n\t\tn := encodeSize(b, uint32(len(k)))\n\t\tn += encodeSize(b[n:], uint32(len(v)))\n\t\tif _, err := w.Write(b[:n]); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := w.WriteString(k); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := w.WriteString(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn w.Close()\n}\n\nfunc readSize(s []byte) (uint32, int) {\n\tif len(s) == 0 {\n\t\treturn 0, 0\n\t}\n\tsize, n := uint32(s[0]), 1\n\tif size&(1<<7) != 0 {\n\t\tif len(s) < 4 {\n\t\t\treturn 0, 0\n\t\t}\n\t\tn = 4\n\t\tsize = binary.BigEndian.Uint32(s)\n\t\tsize &^= 1 << 31\n\t}\n\treturn size, n\n}\n\nfunc readString(s []byte, size uint32) string {\n\tif size > uint32(len(s)) {\n\t\treturn \"\"\n\t}\n\treturn string(s[:size])\n}\n\nfunc encodeSize(b []byte, size uint32) int {\n\tif size > 127 {\n\t\tsize |= 1 << 31\n\t\tbinary.BigEndian.PutUint32(b, size)\n\t\treturn 4\n\t}\n\t//nolint:gosec // G602: False positive — all callers allocate b with length >= 1 (e.g., make([]byte,4) or make([]byte,8)), so indexing b[0] is safe.\n\tb[0] = byte(size)\n\treturn 1\n}\n\n// bufWriter encapsulates bufio.Writer but also closes the underlying stream when\n// Closed.\ntype bufWriter struct {\n\tcloser io.Closer\n\t*bufio.Writer\n}\n\n// Close flushes any buffered data to the underlying writer and releases resources.\nfunc (w *bufWriter) Close() error {\n\tif err := w.Writer.Flush(); err != nil {\n\t\tw.closer.Close()\n\t\treturn err\n\t}\n\treturn w.closer.Close()\n}\n\nfunc newWriter(c *conn, recType recType, reqID uint16) *bufWriter {\n\ts := &streamWriter{c: c, recType: recType, reqID: reqID}\n\tw := bufio.NewWriterSize(s, maxWrite)\n\treturn &bufWriter{s, w}\n}\n\n// streamWriter abstracts out the separation of a stream into discrete records.\n// It only writes maxWrite bytes at a time.\ntype streamWriter struct {\n\tc       *conn\n\trecType recType\n\treqID   uint16\n}\n\nfunc (w *streamWriter) Write(p []byte) (int, error) {\n\tnn := 0\n\tfor len(p) > 0 {\n\t\tn := len(p)\n\t\tif n > maxWrite {\n\t\t\tn = maxWrite\n\t\t}\n\t\tif err := w.c.writeRecord(w.recType, w.reqID, p[:n]); err != nil {\n\t\t\treturn nn, err\n\t\t}\n\t\tnn += n\n\t\tp = p[n:]\n\t}\n\treturn nn, nil\n}\n\n// Close closes the underlying stream and releases resources.\nfunc (w *streamWriter) Close() error {\n\t// send empty record to close the stream\n\treturn w.c.writeRecord(w.recType, w.reqID, nil)\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/fcgi_client.go",
    "content": "package phpfpm\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Create an fcgi client\nfunc newFcgiClient(timeout time.Duration, h string, args ...interface{}) (*conn, error) {\n\tvar con net.Conn\n\tif len(args) != 1 {\n\t\treturn nil, errors.New(\"fcgi: not enough params\")\n\t}\n\n\tvar err error\n\tswitch args[0].(type) {\n\tcase int:\n\t\taddr := h + \":\" + strconv.FormatInt(int64(args[0].(int)), 10)\n\t\tif timeout == 0 {\n\t\t\tcon, err = net.Dial(\"tcp\", addr)\n\t\t} else {\n\t\t\tcon, err = net.DialTimeout(\"tcp\", addr, timeout)\n\t\t}\n\tcase string:\n\t\tladdr := net.UnixAddr{Name: args[0].(string), Net: h}\n\t\tcon, err = net.DialUnix(h, nil, &laddr)\n\tdefault:\n\t\treturn nil, errors.New(\"fcgi: we only accept int (port) or string (socket) params\")\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif timeout != 0 {\n\t\tif err := con.SetDeadline(time.Now().Add(timeout)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &conn{rwc: con}, nil\n}\n\nfunc (c *conn) request(env map[string]string, requestData string) (retout, reterr []byte, err error) {\n\tdefer c.rwc.Close()\n\tvar reqID uint16 = 1\n\n\terr = c.writeBeginRequest(reqID, uint16(roleResponder), 0)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\terr = c.writePairs(typeParams, reqID, env)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif len(requestData) > 0 {\n\t\tif err := c.writeRecord(typeStdin, reqID, []byte(requestData)); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\trec := &record{}\n\tvar err1 error\n\n\t// receive until EOF or FCGI_END_REQUEST\nREAD_LOOP:\n\tfor {\n\t\terr1 = rec.read(c.rwc)\n\t\tif err1 != nil && strings.Contains(err1.Error(), \"use of closed network connection\") {\n\t\t\tif !errors.Is(err1, io.EOF) {\n\t\t\t\terr = err1\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tif err1 != nil && strings.Contains(err1.Error(), \"i/o timeout\") {\n\t\t\tif !errors.Is(err1, io.EOF) {\n\t\t\t\terr = err1\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tswitch rec.h.Type {\n\t\tcase typeStdout:\n\t\t\tretout = append(retout, rec.content()...)\n\t\tcase typeStderr:\n\t\t\treterr = append(reterr, rec.content()...)\n\t\tcase typeEndRequest:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tbreak READ_LOOP\n\t\t}\n\t}\n\n\treturn retout, reterr, err\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/fcgi_test.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage phpfpm\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n)\n\nconst requestID uint16 = 1\n\nvar sizeTests = []struct {\n\tsize  uint32\n\tbytes []byte\n}{\n\t{0, []byte{0x00}},\n\t{127, []byte{0x7F}},\n\t{128, []byte{0x80, 0x00, 0x00, 0x80}},\n\t{1000, []byte{0x80, 0x00, 0x03, 0xE8}},\n\t{33554431, []byte{0x81, 0xFF, 0xFF, 0xFF}},\n}\n\nfunc TestSize(t *testing.T) {\n\tb := make([]byte, 4)\n\tfor i, test := range sizeTests {\n\t\tn := encodeSize(b, test.size)\n\t\tif !bytes.Equal(b[:n], test.bytes) {\n\t\t\tt.Errorf(\"%d expected %x, encoded %x\", i, test.bytes, b)\n\t\t}\n\t\tsize, n := readSize(test.bytes)\n\t\tif size != test.size {\n\t\t\tt.Errorf(\"%d expected %d, read %d\", i, test.size, size)\n\t\t}\n\t\tif len(test.bytes) != n {\n\t\t\tt.Errorf(\"%d did not consume all the bytes\", i)\n\t\t}\n\t}\n}\n\nvar streamTests = []struct {\n\tdesc    string\n\trecType recType\n\treqID   uint16\n\tcontent []byte\n\traw     []byte\n}{\n\t{\"single record\", typeStdout, 1, nil,\n\t\t[]byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0},\n\t},\n\t// this data will have to be split into two records\n\t{\"two records\", typeStdin, 300, make([]byte, 66000),\n\t\tbytes.Join([][]byte{\n\t\t\t// header for the first record\n\t\t\t{1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0},\n\t\t\tmake([]byte, 65536),\n\t\t\t// header for the second\n\t\t\t{1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0},\n\t\t\tmake([]byte, 472),\n\t\t\t// header for the empty record\n\t\t\t{1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0},\n\t\t},\n\t\t\tnil),\n\t},\n}\n\ntype nilCloser struct {\n\tio.ReadWriter\n}\n\nfunc (*nilCloser) Close() error { return nil }\n\nfunc TestStreams(t *testing.T) {\n\tvar rec record\nouter:\n\tfor _, test := range streamTests {\n\t\tbuf := bytes.NewBuffer(test.raw)\n\t\tvar content []byte\n\t\tfor buf.Len() > 0 {\n\t\t\tif err := rec.read(buf); err != nil {\n\t\t\t\tt.Errorf(\"%s: error reading record: %v\", test.desc, err)\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t\tcontent = append(content, rec.content()...)\n\t\t}\n\t\tif rec.h.Type != test.recType {\n\t\t\tt.Errorf(\"%s: got type %d expected %d\", test.desc, rec.h.Type, test.recType)\n\t\t\tcontinue\n\t\t}\n\t\tif rec.h.ID != test.reqID {\n\t\t\tt.Errorf(\"%s: got request ID %d expected %d\", test.desc, rec.h.ID, test.reqID)\n\t\t\tcontinue\n\t\t}\n\t\tif !bytes.Equal(content, test.content) {\n\t\t\tt.Errorf(\"%s: read wrong content\", test.desc)\n\t\t\tcontinue\n\t\t}\n\t\tbuf.Reset()\n\t\tc := newConn(&nilCloser{buf})\n\t\tw := newWriter(c, test.recType, test.reqID)\n\t\tif _, err := w.Write(test.content); err != nil {\n\t\t\tt.Errorf(\"%s: error writing record: %v\", test.desc, err)\n\t\t\tcontinue\n\t\t}\n\t\tif err := w.Close(); err != nil {\n\t\t\tt.Errorf(\"%s: error closing stream: %v\", test.desc, err)\n\t\t\tcontinue\n\t\t}\n\t\tif !bytes.Equal(buf.Bytes(), test.raw) {\n\t\t\tt.Errorf(\"%s: wrote wrong content\", test.desc)\n\t\t}\n\t}\n}\n\ntype writeOnlyConn struct {\n\tbuf []byte\n}\n\nfunc (c *writeOnlyConn) Write(p []byte) (int, error) {\n\tc.buf = append(c.buf, p...)\n\treturn len(p), nil\n}\n\nfunc (*writeOnlyConn) Read([]byte) (int, error) {\n\treturn 0, errors.New(\"conn is write-only\")\n}\n\nfunc (*writeOnlyConn) Close() error {\n\treturn nil\n}\n\nfunc TestGetValues(t *testing.T) {\n\tvar rec record\n\trec.h.Type = typeGetValues\n\n\twc := new(writeOnlyConn)\n\tc := newChild(wc, nil)\n\terr := c.handleRecord(&rec)\n\tif err != nil {\n\t\tt.Fatalf(\"handleRecord: %v\", err)\n\t}\n\n\tconst want = \"\\x01\\n\\x00\\x00\\x00\\x12\\x06\\x00\" +\n\t\t\"\\x0f\\x01FCGI_MPXS_CONNS1\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\n\\x00\\x00\\x00\\x00\\x00\\x00\"\n\tif got := string(wc.buf); got != want {\n\t\tt.Errorf(\" got: %q\\nwant: %q\\n\", got, want)\n\t}\n}\n\nfunc nameValuePair11(nameData, valueData string) []byte {\n\treturn bytes.Join(\n\t\t[][]byte{\n\t\t\t{byte(len(nameData)), byte(len(valueData))},\n\t\t\t[]byte(nameData),\n\t\t\t[]byte(valueData),\n\t\t},\n\t\tnil,\n\t)\n}\n\nfunc makeRecord(\n\trecordType recType,\n\tcontentData []byte,\n) []byte {\n\trequestIDB1 := byte(requestID >> 8)\n\trequestIDB0 := byte(requestID)\n\n\tcontentLength := len(contentData)\n\tcontentLengthB1 := byte(contentLength >> 8)\n\tcontentLengthB0 := byte(contentLength)\n\treturn bytes.Join([][]byte{\n\t\t{1, byte(recordType), requestIDB1, requestIDB0, contentLengthB1,\n\t\t\tcontentLengthB0, 0, 0},\n\t\tcontentData,\n\t},\n\t\tnil)\n}\n\n// a series of FastCGI records that start a request and begin sending the\n// request body\nvar streamBeginTypeStdin = bytes.Join([][]byte{\n\t// set up request 1\n\tmakeRecord(typeBeginRequest, []byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}),\n\t// add required parameters to request 1\n\tmakeRecord(typeParams, nameValuePair11(\"REQUEST_METHOD\", \"GET\")),\n\tmakeRecord(typeParams, nameValuePair11(\"SERVER_PROTOCOL\", \"HTTP/1.1\")),\n\tmakeRecord(typeParams, nil),\n\t// begin sending body of request 1\n\tmakeRecord(typeStdin, []byte(\"0123456789abcdef\")),\n},\n\tnil)\n\nvar cleanUpTests = []struct {\n\tinput []byte\n\terr   error\n}{\n\t// confirm that child.handleRecord closes req.pw after aborting req\n\t{\n\t\tbytes.Join([][]byte{\n\t\t\tstreamBeginTypeStdin,\n\t\t\tmakeRecord(typeAbortRequest, nil),\n\t\t},\n\t\t\tnil),\n\t\terrRequestAborted,\n\t},\n\t// confirm that child.serve closes all pipes after error reading record\n\t{\n\t\tbytes.Join([][]byte{\n\t\t\tstreamBeginTypeStdin,\n\t\t\tnil,\n\t\t},\n\t\t\tnil),\n\t\terrConnClosed,\n\t},\n}\n\ntype nopWriteCloser struct {\n\tio.ReadWriter\n}\n\nfunc (nopWriteCloser) Close() error {\n\treturn nil\n}\n\n// Test that child.serve closes the bodies of aborted requests and closes the\n// bodies of all requests before returning. Causes deadlock if either condition\n// isn't met. See issue 6934.\nfunc TestChildServeCleansUp(t *testing.T) {\n\tfor _, tt := range cleanUpTests {\n\t\tinput := make([]byte, len(tt.input))\n\t\tcopy(input, tt.input)\n\t\trc := nopWriteCloser{bytes.NewBuffer(input)}\n\t\tdone := make(chan bool)\n\t\tc := newChild(rc, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t// block on reading body of request\n\t\t\t_, err := io.Copy(io.Discard, r.Body)\n\t\t\tif !errors.Is(err, tt.err) {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Errorf(\"Not equal, expected: %v, actual: %v\", tt.err, err)\n\t\t\t}\n\t\t\t// not reached if body of request isn't closed\n\t\t\tdone <- true\n\t\t}))\n\t\tgo c.serve()\n\t\t// wait for body of request to be closed or all goroutines to block\n\t\t<-done\n\t}\n}\n\ntype rwNopCloser struct {\n\tio.Reader\n\tio.Writer\n}\n\nfunc (rwNopCloser) Close() error {\n\treturn nil\n}\n\n// Verifies it doesn't crash. \tIssue 11824.\nfunc TestMalformedParams(_ *testing.T) {\n\tinput := []byte{\n\t\t// beginRequest, requestId=1, contentLength=8, role=1, keepConn=1\n\t\t1, 1, 0, 1, 0, 8, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,\n\t\t// params, requestId=1, contentLength=10, k1Len=50, v1Len=50 (malformed, wrong length)\n\t\t1, 4, 0, 1, 0, 10, 0, 0, 50, 50, 3, 4, 5, 6, 7, 8, 9, 10,\n\t\t// end of params\n\t\t1, 4, 0, 1, 0, 0, 0, 0,\n\t}\n\trw := rwNopCloser{bytes.NewReader(input), io.Discard}\n\tc := newChild(rw, http.DefaultServeMux)\n\tc.serve()\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/phpfpm.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage phpfpm\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/globpath\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tpfPool               = \"pool\"\n\tpfStartSince         = \"start since\"\n\tpfAcceptedConn       = \"accepted conn\"\n\tpfListenQueue        = \"listen queue\"\n\tpfMaxListenQueue     = \"max listen queue\"\n\tpfListenQueueLen     = \"listen queue len\"\n\tpfIdleProcesses      = \"idle processes\"\n\tpfActiveProcesses    = \"active processes\"\n\tpfTotalProcesses     = \"total processes\"\n\tpfMaxActiveProcesses = \"max active processes\"\n\tpfMaxChildrenReached = \"max children reached\"\n\tpfSlowRequests       = \"slow requests\"\n)\n\ntype Phpfpm struct {\n\tFormat  string          `toml:\"format\"`\n\tTimeout config.Duration `toml:\"timeout\"`\n\tUrls    []string        `toml:\"urls\"`\n\tLog     telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\tclient *http.Client\n}\n\ntype jsonMetrics struct {\n\tPool               string `json:\"pool\"`\n\tProcessManager     string `json:\"process manager\"`\n\tStartTime          int    `json:\"start time\"`\n\tStartSince         int    `json:\"start since\"`\n\tAcceptedConn       int    `json:\"accepted conn\"`\n\tListenQueue        int    `json:\"listen queue\"`\n\tMaxListenQueue     int    `json:\"max listen queue\"`\n\tListenQueueLen     int    `json:\"listen queue len\"`\n\tIdleProcesses      int    `json:\"idle processes\"`\n\tActiveProcesses    int    `json:\"active processes\"`\n\tTotalProcesses     int    `json:\"total processes\"`\n\tMaxActiveProcesses int    `json:\"max active processes\"`\n\tMaxChildrenReached int    `json:\"max children reached\"`\n\tSlowRequests       int    `json:\"slow requests\"`\n\tProcesses          []struct {\n\t\tPid               int     `json:\"pid\"`\n\t\tState             string  `json:\"state\"`\n\t\tStartTime         int     `json:\"start time\"`\n\t\tStartSince        int     `json:\"start since\"`\n\t\tRequests          int     `json:\"requests\"`\n\t\tRequestDuration   int     `json:\"request duration\"`\n\t\tRequestMethod     string  `json:\"request method\"`\n\t\tRequestURI        string  `json:\"request uri\"`\n\t\tContentLength     int     `json:\"content length\"`\n\t\tUser              string  `json:\"user\"`\n\t\tScript            string  `json:\"script\"`\n\t\tLastRequestCPU    float64 `json:\"last request cpu\"`\n\t\tLastRequestMemory float64 `json:\"last request memory\"`\n\t} `json:\"processes\"`\n}\n\ntype metricStat map[string]int64\ntype poolStat map[string]metricStat\n\nfunc (*Phpfpm) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Phpfpm) Init() error {\n\tif len(p.Urls) == 0 {\n\t\tp.Urls = []string{\"http://127.0.0.1/status\"}\n\t}\n\n\ttlsCfg, err := p.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswitch p.Format {\n\tcase \"\":\n\t\tp.Format = \"status\"\n\tcase \"status\", \"json\":\n\t\t// both valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid format: %s\", p.Format)\n\t}\n\n\tp.client = &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(p.Timeout),\n\t}\n\treturn nil\n}\n\nfunc (p *Phpfpm) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, serv := range expandUrls(acc, p.Urls) {\n\t\twg.Add(1)\n\t\tgo func(serv string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(p.gatherServer(serv, acc))\n\t\t}(serv)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\n// Request status page to get stat raw data and import it\nfunc (p *Phpfpm) gatherServer(addr string, acc telegraf.Accumulator) error {\n\tif strings.HasPrefix(addr, \"http://\") || strings.HasPrefix(addr, \"https://\") {\n\t\treturn p.gatherHTTP(addr, acc)\n\t}\n\n\tvar (\n\t\tfcgi       *conn\n\t\tsocketPath string\n\t\tstatusPath string\n\t)\n\n\tvar err error\n\tif strings.HasPrefix(addr, \"fcgi://\") || strings.HasPrefix(addr, \"cgi://\") {\n\t\tu, err := url.Parse(addr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable parse server address %q: %w\", addr, err)\n\t\t}\n\t\tsocketAddr := strings.Split(u.Host, \":\")\n\t\tif len(socketAddr) < 2 {\n\t\t\treturn fmt.Errorf(\"url does not follow required 'address:port' format: %s\", u.Host)\n\t\t}\n\t\tfcgiIP := socketAddr[0]\n\t\tfcgiPort, err := strconv.Atoi(socketAddr[1])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse server port %q: %w\", socketAddr[1], err)\n\t\t}\n\t\tfcgi, err = newFcgiClient(time.Duration(p.Timeout), fcgiIP, fcgiPort)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(u.Path) > 1 {\n\t\t\tstatusPath = strings.Trim(u.Path, \"/\")\n\t\t} else {\n\t\t\tstatusPath = \"status\"\n\t\t}\n\t} else {\n\t\tsocketPath, statusPath = unixSocketPaths(addr)\n\t\tif statusPath == \"\" {\n\t\t\tstatusPath = \"status\"\n\t\t}\n\t\tfcgi, err = newFcgiClient(time.Duration(p.Timeout), \"unix\", socketPath)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn p.gatherFcgi(fcgi, statusPath, acc, addr)\n}\n\n// Gather stat using fcgi protocol\nfunc (p *Phpfpm) gatherFcgi(fcgi *conn, statusPath string, acc telegraf.Accumulator, addr string) error {\n\tfpmOutput, fpmErr, err := fcgi.request(map[string]string{\n\t\t\"SCRIPT_NAME\":     \"/\" + statusPath,\n\t\t\"SCRIPT_FILENAME\": statusPath,\n\t\t\"REQUEST_METHOD\":  \"GET\",\n\t\t\"CONTENT_LENGTH\":  \"0\",\n\t\t\"SERVER_PROTOCOL\": \"HTTP/1.0\",\n\t\t\"SERVER_SOFTWARE\": \"go / fcgiclient \",\n\t\t\"REMOTE_ADDR\":     \"127.0.0.1\",\n\t}, \"/\"+statusPath)\n\n\tif len(fpmErr) == 0 && err == nil {\n\t\tp.importMetric(bytes.NewReader(fpmOutput), acc, addr)\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"unable parse phpfpm status, error: %s; %w\", string(fpmErr), err)\n}\n\n// Gather stat using http protocol\nfunc (p *Phpfpm) gatherHTTP(addr string, acc telegraf.Accumulator) error {\n\tu, err := url.Parse(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable parse server address %q: %w\", addr, err)\n\t}\n\n\treq, err := http.NewRequest(\"GET\", u.String(), nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create new request %q: %w\", addr, err)\n\t}\n\n\tres, err := p.client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to phpfpm status page %q: %w\", addr, err)\n\t}\n\tdefer res.Body.Close()\n\n\tif res.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"unable to get valid stat result from %q: %w\", addr, err)\n\t}\n\n\tp.importMetric(res.Body, acc, addr)\n\treturn nil\n}\n\n// Import stat data into Telegraf system\nfunc (p *Phpfpm) importMetric(r io.Reader, acc telegraf.Accumulator, addr string) {\n\tif p.Format == \"json\" {\n\t\tp.parseJSON(r, acc, addr)\n\t} else {\n\t\tparseLines(r, acc, addr)\n\t}\n}\n\nfunc parseLines(r io.Reader, acc telegraf.Accumulator, addr string) {\n\tstats := make(poolStat)\n\tvar currentPool string\n\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tstatLine := scanner.Text()\n\t\tkeyvalue := strings.Split(statLine, \":\")\n\n\t\tif len(keyvalue) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tfieldName := strings.Trim(keyvalue[0], \" \")\n\t\t// We start to gather data for a new pool here\n\t\tif fieldName == pfPool {\n\t\t\tcurrentPool = strings.Trim(keyvalue[1], \" \")\n\t\t\tstats[currentPool] = make(metricStat)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Start to parse metric for current pool\n\t\tswitch fieldName {\n\t\tcase pfStartSince,\n\t\t\tpfAcceptedConn,\n\t\t\tpfListenQueue,\n\t\t\tpfMaxListenQueue,\n\t\t\tpfListenQueueLen,\n\t\t\tpfIdleProcesses,\n\t\t\tpfActiveProcesses,\n\t\t\tpfTotalProcesses,\n\t\t\tpfMaxActiveProcesses,\n\t\t\tpfMaxChildrenReached,\n\t\t\tpfSlowRequests:\n\t\t\tfieldValue, err := strconv.ParseInt(strings.Trim(keyvalue[1], \" \"), 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tstats[currentPool][fieldName] = fieldValue\n\t\t\t}\n\t\t}\n\t}\n\n\t// Finally, we push the pool metric\n\tfor pool := range stats {\n\t\ttags := map[string]string{\n\t\t\t\"pool\": pool,\n\t\t\t\"url\":  addr,\n\t\t}\n\t\tfields := make(map[string]interface{})\n\t\tfor k, v := range stats[pool] {\n\t\t\tfields[strings.ReplaceAll(k, \" \", \"_\")] = v\n\t\t}\n\t\tacc.AddFields(\"phpfpm\", fields, tags)\n\t}\n}\n\nfunc (p *Phpfpm) parseJSON(r io.Reader, acc telegraf.Accumulator, addr string) {\n\tvar metrics jsonMetrics\n\tif err := json.NewDecoder(r).Decode(&metrics); err != nil {\n\t\tp.Log.Errorf(\"Unable to decode JSON response: %s\", err)\n\t\treturn\n\t}\n\ttimestamp := time.Now()\n\n\ttags := map[string]string{\n\t\t\"pool\": metrics.Pool,\n\t\t\"url\":  addr,\n\t}\n\tfields := map[string]any{\n\t\t\"start_since\":          metrics.StartSince,\n\t\t\"accepted_conn\":        metrics.AcceptedConn,\n\t\t\"listen_queue\":         metrics.ListenQueue,\n\t\t\"max_listen_queue\":     metrics.MaxListenQueue,\n\t\t\"listen_queue_len\":     metrics.ListenQueueLen,\n\t\t\"idle_processes\":       metrics.IdleProcesses,\n\t\t\"active_processes\":     metrics.ActiveProcesses,\n\t\t\"total_processes\":      metrics.TotalProcesses,\n\t\t\"max_active_processes\": metrics.MaxActiveProcesses,\n\t\t\"max_children_reached\": metrics.MaxChildrenReached,\n\t\t\"slow_requests\":        metrics.SlowRequests,\n\t}\n\tacc.AddFields(\"phpfpm\", fields, tags, timestamp)\n\n\tfor _, process := range metrics.Processes {\n\t\ttags := map[string]string{\n\t\t\t\"pool\":           metrics.Pool,\n\t\t\t\"url\":            addr,\n\t\t\t\"user\":           process.User,\n\t\t\t\"request_uri\":    process.RequestURI,\n\t\t\t\"request_method\": process.RequestMethod,\n\t\t\t\"script\":         process.Script,\n\t\t}\n\t\tfields := map[string]any{\n\t\t\t\"pid\":                 process.Pid,\n\t\t\t\"state\":               process.State,\n\t\t\t\"start_time\":          process.StartTime,\n\t\t\t\"requests\":            process.Requests,\n\t\t\t\"request_duration\":    process.RequestDuration,\n\t\t\t\"content_length\":      process.ContentLength,\n\t\t\t\"last_request_cpu\":    process.LastRequestCPU,\n\t\t\t\"last_request_memory\": process.LastRequestMemory,\n\t\t}\n\t\tacc.AddFields(\"phpfpm_process\", fields, tags, timestamp)\n\t}\n}\n\nfunc expandUrls(acc telegraf.Accumulator, urls []string) []string {\n\taddrs := make([]string, 0, len(urls))\n\tfor _, address := range urls {\n\t\tif isNetworkURL(address) {\n\t\t\taddrs = append(addrs, address)\n\t\t\tcontinue\n\t\t}\n\t\tpaths, err := globUnixSocket(address)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\t\taddrs = append(addrs, paths...)\n\t}\n\treturn addrs\n}\n\nfunc globUnixSocket(address string) ([]string, error) {\n\tpattern, status := unixSocketPaths(address)\n\tglob, err := globpath.Compile(pattern)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not compile glob %q: %w\", pattern, err)\n\t}\n\tpaths := glob.Match()\n\tif len(paths) == 0 {\n\t\treturn nil, fmt.Errorf(\"socket doesn't exist %q\", pattern)\n\t}\n\n\taddresses := make([]string, 0, len(paths))\n\tfor _, path := range paths {\n\t\tif status != \"\" {\n\t\t\tpath = path + \":\" + status\n\t\t}\n\t\taddresses = append(addresses, path)\n\t}\n\n\treturn addresses, nil\n}\n\nfunc unixSocketPaths(addr string) (socketPath, statusPath string) {\n\tsocketAddr := strings.Split(addr, \":\")\n\tif len(socketAddr) >= 2 {\n\t\tsocketPath = socketAddr[0]\n\t\tstatusPath = socketAddr[1]\n\t} else {\n\t\tsocketPath = socketAddr[0]\n\t\tstatusPath = \"\"\n\t}\n\n\treturn socketPath, statusPath\n}\n\nfunc isNetworkURL(addr string) bool {\n\treturn strings.HasPrefix(addr, \"http://\") || strings.HasPrefix(addr, \"https://\") || strings.HasPrefix(addr, \"fcgi://\") || strings.HasPrefix(addr, \"cgi://\")\n}\n\nfunc init() {\n\tinputs.Add(\"phpfpm\", func() telegraf.Input {\n\t\treturn &Phpfpm{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/phpfpm_test.go",
    "content": "//go:build !windows\n\n// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows\n// https://github.com/influxdata/telegraf/issues/6248\n\npackage phpfpm\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/fcgi\"\n\t\"net/http/httptest\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype statServer struct{}\n\n// We create a fake server to return test data\nfunc (statServer) ServeHTTP(w http.ResponseWriter, _ *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(outputSample)))\n\tfmt.Fprint(w, outputSample)\n}\n\nfunc TestPhpFpmGeneratesMetrics_From_Http(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Query().Get(\"test\") != \"ok\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Not equal, expected: %q, actual: %q\", \"ok\", r.URL.Query().Get(\"test\"))\n\t\t\treturn\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", \"text/plain\")\n\t\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(outputSample)))\n\t\tif _, err := fmt.Fprint(w, outputSample); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\turl := ts.URL + \"?test=ok\"\n\tr := &Phpfpm{\n\t\tUrls: []string{url},\n\t\tLog:  &testutil.Logger{},\n\t}\n\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, acc.GatherError(r.Gather))\n\n\ttags := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  url,\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"start_since\":          int64(1991),\n\t\t\"accepted_conn\":        int64(3),\n\t\t\"listen_queue\":         int64(1),\n\t\t\"max_listen_queue\":     int64(0),\n\t\t\"listen_queue_len\":     int64(0),\n\t\t\"idle_processes\":       int64(1),\n\t\t\"active_processes\":     int64(1),\n\t\t\"total_processes\":      int64(2),\n\t\t\"max_active_processes\": int64(1),\n\t\t\"max_children_reached\": int64(2),\n\t\t\"slow_requests\":        int64(1),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags)\n}\n\nfunc TestPhpFpmGeneratesJSONMetrics_From_Http(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/json\")\n\t\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(outputSampleJSON)))\n\t\tif _, err := fmt.Fprint(w, string(outputSampleJSON)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\tparser := &influx.Parser{}\n\trequire.NoError(t, parser.Init())\n\texpected, err := testutil.ParseMetricsFromFile(\"testdata/expected.out\", parser)\n\trequire.NoError(t, err)\n\n\tinput := &Phpfpm{\n\t\tUrls:   []string{server.URL + \"?full&json\"},\n\t\tFormat: \"json\",\n\t\tLog:    &testutil.Logger{},\n\t}\n\trequire.NoError(t, input.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(input.Gather))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.IgnoreTags(\"url\"))\n}\n\nfunc TestPhpFpmGeneratesMetrics_From_Fcgi(t *testing.T) {\n\t// Let OS find an available port\n\ttcp, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err, \"Cannot initialize test server\")\n\tdefer tcp.Close()\n\n\ts := statServer{}\n\tgo fcgi.Serve(tcp, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\n\t// Now we tested again above server\n\tr := &Phpfpm{\n\t\tUrls: []string{\"fcgi://\" + tcp.Addr().String() + \"/status\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(r.Gather))\n\n\ttags := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  r.Urls[0],\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"start_since\":          int64(1991),\n\t\t\"accepted_conn\":        int64(3),\n\t\t\"listen_queue\":         int64(1),\n\t\t\"max_listen_queue\":     int64(0),\n\t\t\"listen_queue_len\":     int64(0),\n\t\t\"idle_processes\":       int64(1),\n\t\t\"active_processes\":     int64(1),\n\t\t\"total_processes\":      int64(2),\n\t\t\"max_active_processes\": int64(1),\n\t\t\"max_children_reached\": int64(2),\n\t\t\"slow_requests\":        int64(1),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags)\n}\n\nfunc TestPhpFpmTimeout_From_Fcgi(t *testing.T) {\n\t// Let OS find an available port\n\ttcp, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err, \"Cannot initialize test server\")\n\tdefer tcp.Close()\n\n\tconst timeout = 200 * time.Millisecond\n\n\tgo func() {\n\t\tconn, err := tcp.Accept()\n\t\tif err != nil {\n\t\t\treturn // ignore the returned error as we cannot do anything about it anyway\n\t\t}\n\t\tdefer conn.Close()\n\n\t\t// Sleep longer than the timeout\n\t\ttime.Sleep(2 * timeout)\n\t}()\n\n\t// Now we tested again above server\n\tr := &Phpfpm{\n\t\tUrls:    []string{\"fcgi://\" + tcp.Addr().String() + \"/status\"},\n\t\tTimeout: config.Duration(timeout),\n\t\tLog:     &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tstart := time.Now()\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, acc.GatherError(r.Gather))\n\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\trequire.GreaterOrEqual(t, time.Since(start), timeout)\n}\n\n// TestPhpFpmCrashWithTimeout_From_Fcgi show issue #15175: when timeout is enabled\n// and nothing is listening on specified port, a nil pointer was dereferenced.\nfunc TestPhpFpmCrashWithTimeout_From_Fcgi(t *testing.T) {\n\ttcp, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err, \"Cannot initialize test server\")\n\n\ttcpAddress := tcp.Addr().String()\n\n\t// Yes close the tcp port now. The listenner is only used to find a free\n\t// port and then make it free. This test hope that nothing will re-use the\n\t// port in meantime.\n\ttcp.Close()\n\n\tconst timeout = 200 * time.Millisecond\n\n\t// Now we tested again above server\n\tr := &Phpfpm{\n\t\tUrls:    []string{\"fcgi://\" + tcpAddress + \"/status\"},\n\t\tTimeout: config.Duration(timeout),\n\t\tLog:     &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, acc.GatherError(r.Gather))\n\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n}\n\nfunc TestPhpFpmGeneratesMetrics_From_Socket(t *testing.T) {\n\t// Create a socket in /tmp because we always have write permission and if the\n\t// removing of socket fail when system restart /tmp is clear so\n\t// we don't have junk files around\n\tvar randomNumber int64\n\trequire.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))\n\ttcp, err := net.Listen(\"unix\", fmt.Sprintf(\"/tmp/test-fpm%d.sock\", randomNumber))\n\trequire.NoError(t, err, \"Cannot initialize server on port \")\n\n\tdefer tcp.Close()\n\ts := statServer{}\n\tgo fcgi.Serve(tcp, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\n\tr := &Phpfpm{\n\t\tUrls: []string{tcp.Addr().String()},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(r.Gather))\n\n\ttags := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  r.Urls[0],\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"start_since\":          int64(1991),\n\t\t\"accepted_conn\":        int64(3),\n\t\t\"listen_queue\":         int64(1),\n\t\t\"max_listen_queue\":     int64(0),\n\t\t\"listen_queue_len\":     int64(0),\n\t\t\"idle_processes\":       int64(1),\n\t\t\"active_processes\":     int64(1),\n\t\t\"total_processes\":      int64(2),\n\t\t\"max_active_processes\": int64(1),\n\t\t\"max_children_reached\": int64(2),\n\t\t\"slow_requests\":        int64(1),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags)\n}\n\nfunc TestPhpFpmGeneratesMetrics_From_Multiple_Sockets_With_Glob(t *testing.T) {\n\t// Create a socket in /tmp because we always have write permission and if the\n\t// removing of socket fail when system restart /tmp is clear so\n\t// we don't have junk files around\n\tvar randomNumber int64\n\trequire.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))\n\tsocket1 := fmt.Sprintf(\"/tmp/test-fpm%d.sock\", randomNumber)\n\ttcp1, err := net.Listen(\"unix\", socket1)\n\trequire.NoError(t, err, \"Cannot initialize server on port \")\n\tdefer tcp1.Close()\n\n\trequire.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))\n\tsocket2 := fmt.Sprintf(\"/tmp/test-fpm%d.sock\", randomNumber)\n\ttcp2, err := net.Listen(\"unix\", socket2)\n\trequire.NoError(t, err, \"Cannot initialize server on port \")\n\tdefer tcp2.Close()\n\n\ts := statServer{}\n\tgo fcgi.Serve(tcp1, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\tgo fcgi.Serve(tcp2, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\n\tr := &Phpfpm{\n\t\tUrls: []string{\"/tmp/test-fpm[\\\\-0-9]*.sock\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc1, acc2 testutil.Accumulator\n\trequire.NoError(t, acc1.GatherError(r.Gather))\n\trequire.NoError(t, acc2.GatherError(r.Gather))\n\n\ttags1 := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  socket1,\n\t}\n\n\ttags2 := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  socket2,\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"start_since\":          int64(1991),\n\t\t\"accepted_conn\":        int64(3),\n\t\t\"listen_queue\":         int64(1),\n\t\t\"max_listen_queue\":     int64(0),\n\t\t\"listen_queue_len\":     int64(0),\n\t\t\"idle_processes\":       int64(1),\n\t\t\"active_processes\":     int64(1),\n\t\t\"total_processes\":      int64(2),\n\t\t\"max_active_processes\": int64(1),\n\t\t\"max_children_reached\": int64(2),\n\t\t\"slow_requests\":        int64(1),\n\t}\n\n\tacc1.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags1)\n\tacc2.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags2)\n}\n\nfunc TestPhpFpmGeneratesMetrics_From_Socket_Custom_Status_Path(t *testing.T) {\n\t// Create a socket in /tmp because we always have write permission. If the\n\t// removing of socket fail we won't have junk files around. Cuz when system\n\t// restart, it clears out /tmp\n\tvar randomNumber int64\n\trequire.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))\n\ttcp, err := net.Listen(\"unix\", fmt.Sprintf(\"/tmp/test-fpm%d.sock\", randomNumber))\n\trequire.NoError(t, err, \"Cannot initialize server on port \")\n\n\tdefer tcp.Close()\n\ts := statServer{}\n\tgo fcgi.Serve(tcp, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\n\tr := &Phpfpm{\n\t\tUrls: []string{tcp.Addr().String() + \":custom-status-path\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(r.Gather))\n\n\ttags := map[string]string{\n\t\t\"pool\": \"www\",\n\t\t\"url\":  r.Urls[0],\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"start_since\":          int64(1991),\n\t\t\"accepted_conn\":        int64(3),\n\t\t\"listen_queue\":         int64(1),\n\t\t\"max_listen_queue\":     int64(0),\n\t\t\"listen_queue_len\":     int64(0),\n\t\t\"idle_processes\":       int64(1),\n\t\t\"active_processes\":     int64(1),\n\t\t\"total_processes\":      int64(2),\n\t\t\"max_active_processes\": int64(1),\n\t\t\"max_children_reached\": int64(2),\n\t\t\"slow_requests\":        int64(1),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"phpfpm\", fields, tags)\n}\n\n// When not passing server config, we default to localhost\n// We just want to make sure we did request stat from localhost\nfunc TestPhpFpmDefaultGetFromLocalhost(t *testing.T) {\n\tr := &Phpfpm{\n\t\tUrls: []string{\"http://bad.localhost:62001/status\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, acc.GatherError(r.Gather), \"/status\")\n}\n\nfunc TestPhpFpmGeneratesMetrics_Throw_Error_When_Fpm_Status_Is_Not_Responding(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping long test in short mode\")\n\t}\n\n\tr := &Phpfpm{\n\t\tUrls: []string{\"http://aninvalidone\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\terr := acc.GatherError(r.Gather)\n\trequire.ErrorContains(t, err, `unable to connect to phpfpm status page \"http://aninvalidone\"`)\n\trequire.ErrorContains(t, err, `lookup aninvalidone`)\n}\n\nfunc TestPhpFpmGeneratesMetrics_Throw_Error_When_Socket_Path_Is_Invalid(t *testing.T) {\n\tr := &Phpfpm{\n\t\tUrls: []string{\"/tmp/invalid.sock\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, acc.GatherError(r.Gather), `socket doesn't exist \"/tmp/invalid.sock\"`)\n}\n\nconst outputSample = `\npool:                 www\nprocess manager:      dynamic\nstart time:           11/Oct/2015:23:38:51 +0000\nstart since:          1991\naccepted conn:        3\nlisten queue:         1\nmax listen queue:     0\nlisten queue len:     0\nidle processes:       1\nactive processes:     1\ntotal processes:      2\nmax active processes: 1\nmax children reached: 2\nslow requests:        1\n`\n\n//go:embed testdata/phpfpm.json\nvar outputSampleJSON []byte\n\nfunc TestPhpFpmParseJSON_Log_Error_Without_Panic_When_When_JSON_Is_Invalid(t *testing.T) {\n\t// Capture the logging output for checking\n\tlogger := &testutil.CaptureLogger{Name: \"inputs.phpfpm\"}\n\tplugin := &Phpfpm{Log: logger}\n\trequire.NoError(t, plugin.Init())\n\n\t// parse valid JSON without panic and without log output\n\tvalidJSON := outputSampleJSON\n\trequire.NotPanics(t, func() { plugin.parseJSON(bytes.NewReader(validJSON), &testutil.NopAccumulator{}, \"\") })\n\trequire.Empty(t, logger.NMessages())\n\n\t// parse invalid JSON without panic but with log output\n\tinvalidJSON := []byte(\"X\")\n\trequire.NotPanics(t, func() { plugin.parseJSON(bytes.NewReader(invalidJSON), &testutil.NopAccumulator{}, \"\") })\n\trequire.Contains(t, logger.Errors(), \"E! [inputs.phpfpm] Unable to decode JSON response: invalid character 'X' looking for beginning of value\")\n}\n\nfunc TestGatherDespiteUnavailable(t *testing.T) {\n\t// Let OS find an available port\n\ttcp, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err, \"Cannot initialize test server\")\n\tdefer tcp.Close()\n\n\ts := statServer{}\n\tgo fcgi.Serve(tcp, s) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\n\t// Now we tested again above server\n\tr := &Phpfpm{\n\t\tUrls: []string{\"fcgi://\" + tcp.Addr().String() + \"/status\", \"/lala\"},\n\t\tLog:  &testutil.Logger{},\n\t}\n\trequire.NoError(t, r.Init())\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"phpfpm\",\n\t\t\tmap[string]string{\n\t\t\t\t\"pool\": \"www\",\n\t\t\t\t\"url\":  r.Urls[0],\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"start_since\":          int64(1991),\n\t\t\t\t\"accepted_conn\":        int64(3),\n\t\t\t\t\"listen_queue\":         int64(1),\n\t\t\t\t\"max_listen_queue\":     int64(0),\n\t\t\t\t\"listen_queue_len\":     int64(0),\n\t\t\t\t\"idle_processes\":       int64(1),\n\t\t\t\t\"active_processes\":     int64(1),\n\t\t\t\t\"total_processes\":      int64(2),\n\t\t\t\t\"max_active_processes\": int64(1),\n\t\t\t\t\"max_children_reached\": int64(2),\n\t\t\t\t\"slow_requests\":        int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, acc.GatherError(r.Gather), \"socket doesn't exist\")\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/phpfpm/sample.conf",
    "content": "# Read metrics of phpfpm, via HTTP status page or socket\n[[inputs.phpfpm]]\n  ## An array of addresses to gather stats about. Specify an ip or hostname\n  ## with optional port and path\n  ##\n  ## Plugin can be configured in three modes (either can be used):\n  ##   - http: the URL must start with http:// or https://, ie:\n  ##       \"http://localhost/status\"\n  ##       \"http://192.168.130.1/status?full\"\n  ##\n  ##   - unixsocket: path to fpm socket, ie:\n  ##       \"/var/run/php5-fpm.sock\"\n  ##      or using a custom fpm status path:\n  ##       \"/var/run/php5-fpm.sock:fpm-custom-status-path\"\n  ##      glob patterns are also supported:\n  ##       \"/var/run/php*.sock\"\n  ##\n  ##   - fcgi: the URL must start with fcgi:// or cgi://, and port must be present, ie:\n  ##       \"fcgi://10.0.0.12:9000/status\"\n  ##       \"cgi://10.0.10.12:9001/status\"\n  ##\n  ## Example of multiple gathering from local socket and remote host\n  ## urls = [\"http://192.168.1.20/status\", \"/tmp/fpm.sock\"]\n  urls = [\"http://localhost/status\"]\n\n  ## Format of stats to parse, set to \"status\" or \"json\"\n  ## If the user configures the URL to return JSON (e.g.\n  ## http://localhost/status?json), set to JSON. Otherwise, will attempt to\n  ## parse line-by-line. The JSON mode will produce additional metrics.\n  # format = \"status\"\n\n  ## Duration allowed to complete HTTP requests.\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/phpfpm/testdata/expected.out",
    "content": "phpfpm,pool=www,url=http://127.0.0.1:44637?full&json accepted_conn=3879i,active_processes=1i,idle_processes=9i,listen_queue=0i,listen_queue_len=0i,max_active_processes=3i,max_children_reached=0i,max_listen_queue=0i,slow_requests=0i,start_since=4901i,total_processes=10i\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status?json&full,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=583i,last_request_cpu=0,last_request_memory=0,request_duration=159i,requests=386i,start_time=1702044927i,state=\"Running\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=584i,last_request_cpu=0,last_request_memory=2097152,request_duration=174i,requests=390i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=585i,last_request_cpu=104.93,last_request_memory=2097152,request_duration=9530i,requests=389i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=586i,last_request_cpu=0,last_request_memory=2097152,request_duration=127i,requests=399i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=587i,last_request_cpu=0,last_request_memory=2097152,request_duration=9713i,requests=382i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=588i,last_request_cpu=0,last_request_memory=2097152,request_duration=133i,requests=383i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/fpm-status?json,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=589i,last_request_cpu=0,last_request_memory=2097152,request_duration=154i,requests=381i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/ping,script=-,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=590i,last_request_cpu=0,last_request_memory=2097152,request_duration=108i,requests=397i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=591i,last_request_cpu=110.28,last_request_memory=2097152,request_duration=9068i,requests=381i,start_time=1702044927i,state=\"Idle\"\nphpfpm_process,pool=www,request_method=GET,request_uri=/index.php,script=script.php,url=http://127.0.0.1:44637?full&json,user=- content_length=0i,pid=592i,last_request_cpu=64.27,last_request_memory=2097152,request_duration=15559i,requests=391i,start_time=1702044927i,state=\"Idle\"\n"
  },
  {
    "path": "plugins/inputs/phpfpm/testdata/phpfpm.json",
    "content": "{\n  \"pool\": \"www\",\n  \"process manager\": \"static\",\n  \"start time\": 1702044927,\n  \"start since\": 4901,\n  \"accepted conn\": 3879,\n  \"listen queue\": 0,\n  \"max listen queue\": 0,\n  \"listen queue len\": 0,\n  \"idle processes\": 9,\n  \"active processes\": 1,\n  \"total processes\": 10,\n  \"max active processes\": 3,\n  \"max children reached\": 0,\n  \"slow requests\": 0,\n  \"processes\": [\n    {\n      \"pid\": 583,\n      \"state\": \"Running\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 386,\n      \"request duration\": 159,\n      \"request method\": \"GET\",\n      \"request uri\": \"/fpm-status?json&full\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 0\n    },\n    {\n      \"pid\": 584,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 390,\n      \"request duration\": 174,\n      \"request method\": \"GET\",\n      \"request uri\": \"/fpm-status\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 585,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 389,\n      \"request duration\": 9530,\n      \"request method\": \"GET\",\n      \"request uri\": \"/index.php\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"script.php\",\n      \"last request cpu\": 104.93,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 586,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 399,\n      \"request duration\": 127,\n      \"request method\": \"GET\",\n      \"request uri\": \"/ping\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 587,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 382,\n      \"request duration\": 9713,\n      \"request method\": \"GET\",\n      \"request uri\": \"/index.php\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"script.php\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 588,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 383,\n      \"request duration\": 133,\n      \"request method\": \"GET\",\n      \"request uri\": \"/ping\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 589,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 381,\n      \"request duration\": 154,\n      \"request method\": \"GET\",\n      \"request uri\": \"/fpm-status?json\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 590,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 397,\n      \"request duration\": 108,\n      \"request method\": \"GET\",\n      \"request uri\": \"/ping\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"-\",\n      \"last request cpu\": 0,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 591,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 381,\n      \"request duration\": 9068,\n      \"request method\": \"GET\",\n      \"request uri\": \"/index.php\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"script.php\",\n      \"last request cpu\": 110.28,\n      \"last request memory\": 2097152\n    },\n    {\n      \"pid\": 592,\n      \"state\": \"Idle\",\n      \"start time\": 1702044927,\n      \"start since\": 4901,\n      \"requests\": 391,\n      \"request duration\": 15559,\n      \"request method\": \"GET\",\n      \"request uri\": \"/index.php\",\n      \"content length\": 0,\n      \"user\": \"-\",\n      \"script\": \"script.php\",\n      \"last request cpu\": 64.27,\n      \"last request memory\": 2097152\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ping/README.md",
    "content": "# Ping Input Plugin\n\nThis plugin collects metrics on ICMP ping packets including the round-trip time,\nresponse times and other packet statistics.\n\n> [!NOTE]\n> When using the `exec` method the `ping` command must be available on the\n> systems and executable by Telegraf.\n\n⭐ Telegraf v0.1.8\n🏷️ network\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Ping given url(s) and return statistics\n[[inputs.ping]]\n  ## Hosts to send ping packets to.\n  urls = [\"example.org\"]\n\n  ## Method used for sending pings, can be either \"exec\" or \"native\".  When set\n  ## to \"exec\" the systems ping command will be executed.  When set to \"native\"\n  ## the plugin will send pings directly.\n  ##\n  ## While the default is \"exec\" for backwards compatibility, new deployments\n  ## are encouraged to use the \"native\" method for improved compatibility and\n  ## performance.\n  # method = \"exec\"\n\n  ## Number of ping packets to send per interval.  Corresponds to the \"-c\"\n  ## option of the ping command.\n  # count = 1\n\n  ## Time to wait between sending ping packets in seconds.  Operates like the\n  ## \"-i\" option of the ping command.\n  # ping_interval = 1.0\n\n  ## If set, the time to wait for a ping response in seconds.  Operates like\n  ## the \"-W\" option of the ping command (for \"exec\" method only)\n  # timeout = 1.0\n\n  ## If set, the total ping deadline, in seconds. Operates like the \"-w\"\n  ## option of the ping command.  Use this option to control timeout behavior\n  ## when using the \"native\" method.\n  # deadline = 10\n\n  ## Interface or source address to send ping from.  Operates like the -I or -S\n  ## option of the ping command.\n  # interface = \"\"\n\n  ## Percentiles to calculate. This only works with the native method.\n  # percentiles = [50, 95, 99]\n\n  ## Specify the ping executable binary.\n  # binary = \"ping\"\n\n  ## Arguments for ping command. When arguments is not empty, the command from\n  ## the binary option will be used and other options (ping_interval, timeout,\n  ## etc) will be ignored.\n  # arguments = [\"-c\", \"3\"]\n\n  ## Use only IPv4 addresses when resolving a hostname. By default, both IPv4\n  ## and IPv6 can be used.\n  # ipv4 = false\n\n  ## Use only IPv6 addresses when resolving a hostname. By default, both IPv4\n  ## and IPv6 can be used.\n  # ipv6 = false\n\n  ## Number of data bytes to be sent. Corresponds to the \"-s\"\n  ## option of the ping command. This only works with the native method.\n  # size = 56\n```\n\n### Ping methods\n\nThis plugin has two main methods of operation, the `exec` and `native` mode.\nThe latter is the recommended method as it provides better system compatibility\nand performance. However, for backwards compatibility the `exec` method is the\ndefault.\n\nWhen using the `exec` method, most ping command implementations are supported,\none notable exception being the GNU `inetutils` ping. You may instead use the\niputils-ping implementation:\n\n```sh\napt-get install iputils-ping\n```\n\nFor the `native` method a corresponding ICMP packet is sent and the results are\nreported in native Go by the Telegraf process, eliminating the need to execute\nthe system `ping` command. Therefore, this method doesn't have external\ndependencies.\n\nWith `method = \"native\"`, the `timeout` option is ignored. Use `deadline` to\ncontrol the total runtime instead.\n\n### File Limit\n\nSince this plugin runs the ping command, it may need to open multiple files per\nhost.  The number of files used is lessened with the `native` option but still\nmany files are used.  With a large host list you may receive a `too many open\nfiles` error.\n\nTo increase this limit on platforms using systemd the recommended method is to\nuse the \"drop-in directory\", usually located at\n`/etc/systemd/system/telegraf.service.d`.\n\nYou can create or edit a drop-in file in the correct location using:\n\n```sh\nsystemctl edit telegraf\n```\n\nIncrease the number of open files:\n\n```ini\n[Service]\nLimitNOFILE=8192\n```\n\nRestart Telegraf:\n\n```sh\nsystemctl restart telegraf\n```\n\n### Linux Permissions\n\nWhen using the `native` method, Telegraf will attempt to use privileged raw ICMP\nsockets. On most systems, doing so requires `CAP_NET_RAW` capabilities or for\nTelegraf to be run as root.\n\nWith systemd:\n\n```sh\nsystemctl edit telegraf\n```\n\n```ini\n[Service]\nCapabilityBoundingSet=CAP_NET_RAW\nAmbientCapabilities=CAP_NET_RAW\n```\n\n```sh\nsystemctl restart telegraf\n```\n\nWithout systemd:\n\n```sh\nsetcap cap_net_raw=eip /usr/bin/telegraf\n```\n\nReference [`man 7 capabilities`][man 7 capabilities] for more information about\nsetting capabilities.\n\n[man 7 capabilities]: http://man7.org/linux/man-pages/man7/capabilities.7.html\n\n### Other OS Permissions\n\nWhen using `method = \"native\"`, you will need permissions similar to the\nexecutable ping program for your OS.\n\n## Metrics\n\n- ping\n  - tags:\n    - url\n  - fields:\n    - packets_transmitted (integer)\n    - packets_received (integer)\n    - percent_packet_loss (float)\n    - ttl (integer, Not available on Windows)\n    - average_response_ms (float)\n    - minimum_response_ms (float)\n    - maximum_response_ms (float)\n    - standard_deviation_ms (float, Available on Windows only with method = \"native\")\n    - percentile\\<N\\>_ms (float, Where `<N>` is the percentile specified in\n     `percentiles`. Available with method = \"native\" only)\n    - errors (float, Windows only)\n    - reply_received (integer, Windows with method = \"exec\" only)\n    - percent_reply_loss (float, Windows with method = \"exec\" only)\n    - result_code (int, success = 0, no such host = 1, ping error = 2)\n\n### reply_received vs packets_received\n\nOn Windows systems with `method = \"exec\"`, the \"Destination net unreachable\"\nreply will increment `packets_received` but not `reply_received`*.\n\n### ttl\n\nThere is currently no support for TTL on windows with `\"native\"`; track\nprogress at <https://github.com/golang/go/issues/7175> and\n<https://github.com/golang/go/issues/7174>\n\n## Example Output\n\n```text\nping,url=example.org average_response_ms=23.066,ttl=63,maximum_response_ms=24.64,minimum_response_ms=22.451,packets_received=5i,packets_transmitted=5i,percent_packet_loss=0,result_code=0i,standard_deviation_ms=0.809 1535747258000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ping/ping.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ping\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tping \"github.com/prometheus-community/pro-bing\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultPingDataBytesSize = 56\n)\n\ntype Ping struct {\n\tUrls         []string `toml:\"urls\"`          // URLs to ping\n\tMethod       string   `toml:\"method\"`        // Method defines how to ping (native or exec)\n\tCount        int      `toml:\"count\"`         // Number of pings to send (ping -c <COUNT>)\n\tPingInterval float64  `toml:\"ping_interval\"` // Interval at which to ping (ping -i <INTERVAL>)\n\tTimeout      float64  `toml:\"timeout\"`       // Per-ping timeout in seconds for the exec method. 0 means no timeout (ping -W <TIMEOUT>)\n\tDeadline     int      `toml:\"deadline\"`      // Total ping deadline in seconds. 0 means no deadline (ping -w <DEADLINE>)\n\tInterface    string   `toml:\"interface\"`     // Interface or source address to send ping from (ping -I/-S <INTERFACE/SRC_ADDR>)\n\tPercentiles  []int    `toml:\"percentiles\"`   // Calculate the given percentiles when using native method\n\tBinary       string   `toml:\"binary\"`        // Ping executable binary\n\t// Arguments for ping command. When arguments are not empty, system binary will be used and other options (ping_interval, timeout, etc.) will be ignored\n\tArguments []string        `toml:\"arguments\"`\n\tIPv4      bool            `toml:\"ipv4\"` // Whether to resolve addresses using ipv4 or not.\n\tIPv6      bool            `toml:\"ipv6\"` // Whether to resolve addresses using ipv6 or not.\n\tSize      *int            `toml:\"size\"` // Packet size\n\tLog       telegraf.Logger `toml:\"-\"`\n\n\twg             sync.WaitGroup // wg is used to wait for ping with multiple URLs\n\tcalcInterval   time.Duration  // Pre-calculated interval and timeout\n\tcalcTimeout    time.Duration\n\tsourceAddress  string\n\tpingHost       hostPingerFunc // host ping function\n\tnativePingFunc nativePingFunc\n}\n\n// hostPingerFunc is a function that runs the \"ping\" function using a list of\n// passed arguments. This can be easily switched with a mocked ping function\n// for unit test purposes (see ping_test.go)\ntype hostPingerFunc func(binary string, timeout float64, args ...string) (string, error)\n\ntype nativePingFunc func(destination string) (*pingStats, error)\n\ntype durationSlice []time.Duration\n\ntype pingStats struct {\n\tping.Statistics\n\tttl int\n}\n\nfunc (*Ping) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Ping) Init() error {\n\tif p.Count < 1 {\n\t\treturn errors.New(\"bad number of packets to transmit\")\n\t}\n\n\t// The interval cannot be below 0.2 seconds, matching ping implementation: https://linux.die.net/man/8/ping\n\tif p.PingInterval < 0.2 {\n\t\tp.calcInterval = time.Duration(.2 * float64(time.Second))\n\t} else {\n\t\tp.calcInterval = time.Duration(p.PingInterval * float64(time.Second))\n\t}\n\n\tif p.Method == \"native\" && p.Timeout > 0 {\n\t\tp.Log.Warn(`\"timeout\" is ignored when method = \"native\"; use \"deadline\" to control the total runtime`)\n\t} else if p.Timeout == 0 {\n\t\tp.calcTimeout = time.Duration(1) * time.Second\n\t} else {\n\t\tp.calcTimeout = time.Duration(p.Timeout) * time.Second\n\t}\n\n\treturn nil\n}\n\nfunc (p *Ping) Gather(acc telegraf.Accumulator) error {\n\tfor _, host := range p.Urls {\n\t\tp.wg.Add(1)\n\t\tgo func(host string) {\n\t\t\tdefer p.wg.Done()\n\n\t\t\tswitch p.Method {\n\t\t\tcase \"native\":\n\t\t\t\tp.pingToURLNative(host, acc)\n\t\t\tdefault:\n\t\t\t\tp.pingToURL(host, acc)\n\t\t\t}\n\t\t}(host)\n\t}\n\n\tp.wg.Wait()\n\n\treturn nil\n}\n\nfunc (p *Ping) nativePing(destination string) (*pingStats, error) {\n\tps := &pingStats{}\n\n\tpinger, err := ping.NewPinger(destination)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create new pinger: %w\", err)\n\t}\n\n\tpinger.SetPrivileged(true)\n\n\tif p.IPv4 && p.IPv6 {\n\t\tpinger.SetNetwork(\"ip\")\n\t} else if p.IPv4 {\n\t\tpinger.SetNetwork(\"ip4\")\n\t} else if p.IPv6 {\n\t\tpinger.SetNetwork(\"ip6\")\n\t}\n\n\tif p.Method == \"native\" {\n\t\tpinger.Size = defaultPingDataBytesSize\n\t\tif p.Size != nil {\n\t\t\tpinger.Size = *p.Size\n\t\t}\n\t}\n\n\t// Support either an IP address or interface name\n\tif p.Interface != \"\" && p.sourceAddress == \"\" {\n\t\tif addr := net.ParseIP(p.Interface); addr != nil {\n\t\t\tp.sourceAddress = p.Interface\n\t\t} else {\n\t\t\ti, err := net.InterfaceByName(p.Interface)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get interface: %w\", err)\n\t\t\t}\n\t\t\taddrs, err := i.Addrs()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get the address of interface: %w\", err)\n\t\t\t}\n\t\t\tif len(addrs) == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"no address found for interface %s\", p.Interface)\n\t\t\t}\n\t\t\tp.sourceAddress = addrs[0].(*net.IPNet).IP.String()\n\t\t}\n\t}\n\n\tpinger.Source = p.sourceAddress\n\tpinger.Interval = p.calcInterval\n\n\tif p.Deadline > 0 {\n\t\tpinger.Timeout = time.Duration(p.Deadline) * time.Second\n\t}\n\n\t// Get Time to live (TTL) of first response, matching original implementation\n\tonce := &sync.Once{}\n\tpinger.OnRecv = func(pkt *ping.Packet) {\n\t\tonce.Do(func() {\n\t\t\tps.ttl = pkt.TTL\n\t\t})\n\t}\n\n\tpinger.Count = p.Count\n\terr = pinger.Run()\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"operation not permitted\") {\n\t\t\tif runtime.GOOS == \"linux\" {\n\t\t\t\treturn nil, errors.New(\"permission changes required, enable CAP_NET_RAW capabilities (refer to the ping plugin's README.md for more info)\")\n\t\t\t}\n\n\t\t\treturn nil, errors.New(\"permission changes required, refer to the ping plugin's README.md for more info\")\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tps.Statistics = *pinger.Statistics()\n\n\treturn ps, nil\n}\n\nfunc (p *Ping) pingToURLNative(destination string, acc telegraf.Accumulator) {\n\ttags := map[string]string{\"url\": destination}\n\n\tstats, err := p.nativePingFunc(destination)\n\tif err != nil {\n\t\tp.Log.Errorf(\"ping failed: %s\", err.Error())\n\t\tfields := make(map[string]interface{}, 1)\n\t\tif strings.Contains(err.Error(), \"unknown\") {\n\t\t\tfields[\"result_code\"] = 1\n\t\t} else {\n\t\t\tfields[\"result_code\"] = 2\n\t\t}\n\t\tacc.AddFields(\"ping\", fields, tags)\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"result_code\":         0,\n\t\t\"packets_transmitted\": stats.PacketsSent,\n\t\t\"packets_received\":    stats.PacketsRecv,\n\t}\n\n\tif stats.PacketsSent == 0 {\n\t\tp.Log.Debug(\"no packets sent\")\n\t\tfields[\"result_code\"] = 2\n\t\tacc.AddFields(\"ping\", fields, tags)\n\t\treturn\n\t}\n\n\tif stats.PacketsRecv == 0 {\n\t\tp.Log.Debug(\"no packets received\")\n\t\tfields[\"result_code\"] = 1\n\t\tfields[\"percent_packet_loss\"] = float64(100)\n\t\tacc.AddFields(\"ping\", fields, tags)\n\t\treturn\n\t}\n\n\tsort.Sort(durationSlice(stats.Rtts))\n\tfor _, perc := range p.Percentiles {\n\t\tvar value = percentile(stats.Rtts, perc)\n\t\tvar field = fmt.Sprintf(\"percentile%v_ms\", perc)\n\t\tfields[field] = float64(value.Nanoseconds()) / float64(time.Millisecond)\n\t}\n\n\t// Set TTL only on supported platform. See golang.org/x/net/ipv4/payload_cmsg.go\n\tswitch runtime.GOOS {\n\tcase \"aix\", \"darwin\", \"dragonfly\", \"freebsd\", \"linux\", \"netbsd\", \"openbsd\", \"solaris\":\n\t\tfields[\"ttl\"] = stats.ttl\n\t}\n\n\tfields[\"percent_packet_loss\"] = float64(stats.PacketLoss)\n\tfields[\"minimum_response_ms\"] = float64(stats.MinRtt) / float64(time.Millisecond)\n\tfields[\"average_response_ms\"] = float64(stats.AvgRtt) / float64(time.Millisecond)\n\tfields[\"maximum_response_ms\"] = float64(stats.MaxRtt) / float64(time.Millisecond)\n\tfields[\"standard_deviation_ms\"] = float64(stats.StdDevRtt) / float64(time.Millisecond)\n\n\tacc.AddFields(\"ping\", fields, tags)\n}\n\nfunc (p durationSlice) Len() int { return len(p) }\n\nfunc (p durationSlice) Less(i, j int) bool { return p[i] < p[j] }\n\nfunc (p durationSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n\n// R7 from Hyndman and Fan (1996), which matches Excel\nfunc percentile(values durationSlice, perc int) time.Duration {\n\tif len(values) == 0 {\n\t\treturn 0\n\t}\n\tif perc < 0 {\n\t\tperc = 0\n\t}\n\tif perc > 100 {\n\t\tperc = 100\n\t}\n\tvar percFloat = float64(perc) / 100.0\n\n\tvar count = len(values)\n\tvar rank = percFloat * float64(count-1)\n\tvar rankInteger = int(rank)\n\tvar rankFraction = rank - math.Floor(rank)\n\n\tif rankInteger >= count-1 {\n\t\treturn values[count-1]\n\t}\n\n\tupper := values[rankInteger+1]\n\tlower := values[rankInteger]\n\treturn lower + time.Duration(rankFraction*float64(upper-lower))\n}\n\nfunc hostPinger(binary string, timeout float64, args ...string) (string, error) {\n\tbin, err := exec.LookPath(binary)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tc := exec.Command(bin, args...)\n\tout, err := internal.CombinedOutputTimeout(c,\n\t\ttime.Second*time.Duration(timeout+5))\n\treturn string(out), err\n}\n\nfunc init() {\n\tinputs.Add(\"ping\", func() telegraf.Input {\n\t\tp := &Ping{\n\t\t\tpingHost:     hostPinger,\n\t\t\tPingInterval: 1.0,\n\t\t\tCount:        1,\n\t\t\tDeadline:     10,\n\t\t\tMethod:       \"exec\",\n\t\t\tBinary:       \"ping\",\n\t\t\tArguments:    make([]string, 0),\n\t\t\tPercentiles:  make([]int, 0),\n\t\t}\n\t\tp.nativePingFunc = p.nativePing\n\t\treturn p\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ping/ping_notwindows.go",
    "content": "//go:build !windows\n\npackage ping\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype roundTripTimeStats struct {\n\tmin    float64\n\tavg    float64\n\tmax    float64\n\tstddev float64\n}\n\ntype statistics struct {\n\tpacketsTransmitted int\n\tpacketsReceived    int\n\tttl                int\n\troundTripTimeStats\n}\n\nfunc (p *Ping) pingToURL(u string, acc telegraf.Accumulator) {\n\ttags := map[string]string{\"url\": u}\n\tfields := map[string]interface{}{\"result_code\": 0}\n\n\tout, err := p.pingHost(p.Binary, 60.0, p.args(u, runtime.GOOS)...)\n\tif err != nil {\n\t\t// Some implementations of ping return a non-zero exit code on\n\t\t// timeout, if this occurs we will not exit and try to parse\n\t\t// the output.\n\t\t// Linux iputils-ping returns 1, BSD-derived ping returns 2.\n\t\tstatus := -1\n\t\tvar exitError *exec.ExitError\n\t\tif errors.As(err, &exitError) {\n\t\t\tif ws, ok := exitError.Sys().(syscall.WaitStatus); ok {\n\t\t\t\tstatus = ws.ExitStatus()\n\t\t\t\tfields[\"result_code\"] = status\n\t\t\t}\n\t\t}\n\n\t\tvar timeoutExitCode int\n\t\tswitch runtime.GOOS {\n\t\tcase \"freebsd\", \"netbsd\", \"openbsd\", \"darwin\":\n\t\t\ttimeoutExitCode = 2\n\t\tcase \"linux\":\n\t\t\ttimeoutExitCode = 1\n\t\tdefault:\n\t\t\ttimeoutExitCode = 1\n\t\t}\n\n\t\tif status != timeoutExitCode {\n\t\t\t// Combine go err + stderr output\n\t\t\tout = strings.TrimSpace(out)\n\t\t\tif len(out) > 0 {\n\t\t\t\tacc.AddError(fmt.Errorf(\"host %q: %w - %s\", u, err, out))\n\t\t\t} else {\n\t\t\t\tacc.AddError(fmt.Errorf(\"host %q: %w\", u, err))\n\t\t\t}\n\t\t\tfields[\"result_code\"] = 2\n\t\t\tacc.AddFields(\"ping\", fields, tags)\n\t\t\treturn\n\t\t}\n\t}\n\tstats, err := processPingOutput(out)\n\tif err != nil {\n\t\t// fatal error\n\t\tacc.AddError(fmt.Errorf(\"%q: %w\", u, err))\n\t\tfields[\"result_code\"] = 2\n\t\tacc.AddFields(\"ping\", fields, tags)\n\t\treturn\n\t}\n\n\t// Calculate packet loss percentage\n\tpercentPacketLoss := float64(stats.packetsTransmitted-stats.packetsReceived) / float64(stats.packetsTransmitted) * 100.0\n\n\tfields[\"packets_transmitted\"] = stats.packetsTransmitted\n\tfields[\"packets_received\"] = stats.packetsReceived\n\tfields[\"percent_packet_loss\"] = percentPacketLoss\n\tif stats.ttl >= 0 {\n\t\tfields[\"ttl\"] = stats.ttl\n\t}\n\tif stats.min >= 0 {\n\t\tfields[\"minimum_response_ms\"] = stats.min\n\t}\n\tif stats.avg >= 0 {\n\t\tfields[\"average_response_ms\"] = stats.avg\n\t}\n\tif stats.max >= 0 {\n\t\tfields[\"maximum_response_ms\"] = stats.max\n\t}\n\tif stats.stddev >= 0 {\n\t\tfields[\"standard_deviation_ms\"] = stats.stddev\n\t}\n\tacc.AddFields(\"ping\", fields, tags)\n}\n\n// args returns the arguments for the 'ping' executable\nfunc (p *Ping) args(url, system string) []string {\n\tif len(p.Arguments) > 0 {\n\t\treturn append(p.Arguments, url)\n\t}\n\n\t// build the ping command args based on toml config\n\targs := []string{\"-c\", strconv.Itoa(p.Count), \"-n\", \"-s\", \"16\"}\n\tif p.PingInterval > 0 {\n\t\targs = append(args, \"-i\", strconv.FormatFloat(p.PingInterval, 'f', -1, 64))\n\t}\n\tif p.Timeout > 0 {\n\t\tswitch system {\n\t\tcase \"darwin\":\n\t\t\targs = append(args, \"-W\", strconv.FormatFloat(p.Timeout*1000, 'f', -1, 64))\n\t\tcase \"freebsd\":\n\t\t\tif strings.Contains(p.Binary, \"ping6\") && freeBSDMajorVersion() <= 12 {\n\t\t\t\targs = append(args, \"-x\", strconv.FormatFloat(p.Timeout*1000, 'f', -1, 64))\n\t\t\t} else {\n\t\t\t\targs = append(args, \"-W\", strconv.FormatFloat(p.Timeout*1000, 'f', -1, 64))\n\t\t\t}\n\t\tcase \"netbsd\", \"openbsd\":\n\t\t\targs = append(args, \"-W\", strconv.FormatFloat(p.Timeout*1000, 'f', -1, 64))\n\t\tcase \"linux\":\n\t\t\targs = append(args, \"-W\", strconv.FormatFloat(p.Timeout, 'f', -1, 64))\n\t\tdefault:\n\t\t\t// Not sure the best option here, just assume GNU ping?\n\t\t\targs = append(args, \"-W\", strconv.FormatFloat(p.Timeout, 'f', -1, 64))\n\t\t}\n\t}\n\tif p.Deadline > 0 {\n\t\tswitch system {\n\t\tcase \"freebsd\":\n\t\t\tif strings.Contains(p.Binary, \"ping6\") && freeBSDMajorVersion() <= 12 {\n\t\t\t\targs = append(args, \"-X\", strconv.Itoa(p.Deadline))\n\t\t\t} else {\n\t\t\t\targs = append(args, \"-t\", strconv.Itoa(p.Deadline))\n\t\t\t}\n\t\tcase \"darwin\", \"netbsd\", \"openbsd\":\n\t\t\targs = append(args, \"-t\", strconv.Itoa(p.Deadline))\n\t\tcase \"linux\":\n\t\t\targs = append(args, \"-w\", strconv.Itoa(p.Deadline))\n\t\tdefault:\n\t\t\t// not sure the best option here, just assume gnu ping?\n\t\t\targs = append(args, \"-w\", strconv.Itoa(p.Deadline))\n\t\t}\n\t}\n\tif p.Interface != \"\" {\n\t\tswitch system {\n\t\tcase \"darwin\":\n\t\t\targs = append(args, \"-I\", p.Interface)\n\t\tcase \"freebsd\", \"netbsd\", \"openbsd\":\n\t\t\targs = append(args, \"-S\", p.Interface)\n\t\tcase \"linux\":\n\t\t\targs = append(args, \"-I\", p.Interface)\n\t\tdefault:\n\t\t\t// not sure the best option here, just assume gnu ping?\n\t\t\targs = append(args, \"-i\", p.Interface)\n\t\t}\n\t}\n\targs = append(args, url)\n\treturn args\n}\n\n// processPingOutput takes in a string output from the ping command, like:\n//\n//\tping www.google.com (173.194.115.84): 56 data bytes\n//\t64 bytes from 173.194.115.84: icmp_seq=0 ttl=54 time=52.172 ms\n//\t64 bytes from 173.194.115.84: icmp_seq=1 ttl=54 time=34.843 ms\n//\n//\t--- www.google.com ping statistics ---\n//\t2 packets transmitted, 2 packets received, 0.0% packet loss\n//\tround-trip min/avg/max/stddev = 34.843/43.508/52.172/8.664 ms\n//\n// It returns (<transmitted packets>, <received packets>, <average response>)\nfunc processPingOutput(out string) (statistics, error) {\n\tstats := statistics{\n\t\tpacketsTransmitted: 0,\n\t\tpacketsReceived:    0,\n\t\tttl:                -1,\n\t\troundTripTimeStats: roundTripTimeStats{\n\t\t\tmin:    -1.0,\n\t\t\tavg:    -1.0,\n\t\t\tmax:    -1.0,\n\t\t\tstddev: -1.0,\n\t\t},\n\t}\n\n\t// Set this error to nil if we find a 'transmitted' line\n\terr := errors.New(\"fatal error processing ping output\")\n\tlines := strings.Split(out, \"\\n\")\n\tfor _, line := range lines {\n\t\t// Reading only first TTL, ignoring other TTL messages\n\t\tif stats.ttl == -1 && (strings.Contains(line, \"ttl=\") || strings.Contains(line, \"hlim=\")) {\n\t\t\tstats.ttl, err = getTTL(line)\n\t\t} else if strings.Contains(line, \"transmitted\") && strings.Contains(line, \"received\") {\n\t\t\tstats.packetsTransmitted, stats.packetsReceived, err = getPacketStats(line)\n\t\t\tif err != nil {\n\t\t\t\treturn stats, err\n\t\t\t}\n\t\t} else if strings.Contains(line, \"min/avg/max\") {\n\t\t\tstats.roundTripTimeStats, err = checkRoundTripTimeStats(line)\n\t\t\tif err != nil {\n\t\t\t\treturn stats, err\n\t\t\t}\n\t\t}\n\t}\n\treturn stats, err\n}\n\nfunc getPacketStats(line string) (trans, recv int, err error) {\n\trecv = 0\n\n\tstats := strings.Split(line, \", \")\n\t// Transmitted packets\n\ttrans, err = strconv.Atoi(strings.Split(stats[0], \" \")[0])\n\tif err != nil {\n\t\treturn trans, recv, err\n\t}\n\t// Received packets\n\trecv, err = strconv.Atoi(strings.Split(stats[1], \" \")[0])\n\treturn trans, recv, err\n}\n\nfunc getTTL(line string) (int, error) {\n\tttlLine := regexp.MustCompile(`(ttl|hlim)=(\\d+)`)\n\tttlMatch := ttlLine.FindStringSubmatch(line)\n\treturn strconv.Atoi(ttlMatch[2])\n}\n\nfunc checkRoundTripTimeStats(line string) (roundTripTimeStats, error) {\n\troundTripTimeStats := roundTripTimeStats{\n\t\tmin:    -1.0,\n\t\tavg:    -1.0,\n\t\tmax:    -1.0,\n\t\tstddev: -1.0,\n\t}\n\n\tstats := strings.Split(line, \" \")[3]\n\tdata := strings.Split(stats, \"/\")\n\n\tvar err error\n\troundTripTimeStats.min, err = strconv.ParseFloat(data[0], 64)\n\tif err != nil {\n\t\treturn roundTripTimeStats, err\n\t}\n\troundTripTimeStats.avg, err = strconv.ParseFloat(data[1], 64)\n\tif err != nil {\n\t\treturn roundTripTimeStats, err\n\t}\n\troundTripTimeStats.max, err = strconv.ParseFloat(data[2], 64)\n\tif err != nil {\n\t\treturn roundTripTimeStats, err\n\t}\n\tif len(data) == 4 {\n\t\troundTripTimeStats.stddev, err = strconv.ParseFloat(data[3], 64)\n\t\tif err != nil {\n\t\t\treturn roundTripTimeStats, err\n\t\t}\n\t}\n\treturn roundTripTimeStats, err\n}\n\n// Due to different behavior in version of freebsd, get the major\n// version number. In the event of an error we assume we return a low number\n// to avoid changing behavior.\nfunc freeBSDMajorVersion() int {\n\tout, err := exec.Command(\"freebsd-version\", \"-u\").Output()\n\tif err != nil {\n\t\treturn -1\n\t}\n\n\tmajorVersionStr := strings.Split(string(out), \".\")[0]\n\tmajorVersion, err := strconv.Atoi(majorVersionStr)\n\tif err != nil {\n\t\treturn -1\n\t}\n\n\treturn majorVersion\n}\n"
  },
  {
    "path": "plugins/inputs/ping/ping_test.go",
    "content": "//go:build !windows\n\npackage ping\n\nimport (\n\t\"errors\"\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\tping \"github.com/prometheus-community/pro-bing\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// BSD/Darwin ping output\nvar bsdPingOutput = `\nPING www.google.com (216.58.217.36): 56 data bytes\n64 bytes from 216.58.217.36: icmp_seq=0 ttl=55 time=15.087 ms\n64 bytes from 216.58.217.36: icmp_seq=1 ttl=55 time=21.564 ms\n64 bytes from 216.58.217.36: icmp_seq=2 ttl=55 time=27.263 ms\n64 bytes from 216.58.217.36: icmp_seq=3 ttl=55 time=18.828 ms\n64 bytes from 216.58.217.36: icmp_seq=4 ttl=55 time=18.378 ms\n\n--- www.google.com ping statistics ---\n5 packets transmitted, 5 packets received, 0.0% packet loss\nround-trip min/avg/max/stddev = 15.087/20.224/27.263/4.076 ms\n`\n\n// FreeBSD ping6 output\nvar freebsdPing6Output = `\nPING6(64=40+8+16 bytes) 2001:db8::1 --> 2a00:1450:4001:824::2004\n24 bytes from 2a00:1450:4001:824::2004, icmp_seq=0 hlim=117 time=93.870 ms\n24 bytes from 2a00:1450:4001:824::2004, icmp_seq=1 hlim=117 time=40.278 ms\n24 bytes from 2a00:1450:4001:824::2004, icmp_seq=2 hlim=120 time=59.077 ms\n24 bytes from 2a00:1450:4001:824::2004, icmp_seq=3 hlim=117 time=37.102 ms\n24 bytes from 2a00:1450:4001:824::2004, icmp_seq=4 hlim=117 time=35.727 ms\n\n--- www.google.com ping6 statistics ---\n5 packets transmitted, 5 packets received, 0.0% packet loss\nround-trip min/avg/max/std-dev = 35.727/53.211/93.870/22.000 ms\n`\n\n// Linux ping output\nvar linuxPingOutput = `\nPING www.google.com (216.58.218.164) 56(84) bytes of data.\n64 bytes from host.net (216.58.218.164): icmp_seq=1 ttl=63 time=35.2 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=2 ttl=63 time=42.3 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=3 ttl=63 time=45.1 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=4 ttl=63 time=43.5 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=5 ttl=63 time=51.8 ms\n\n--- www.google.com ping statistics ---\n5 packets transmitted, 5 received, 0% packet loss, time 4010ms\nrtt min/avg/max/mdev = 35.225/43.628/51.806/5.325 ms\n`\n\n// BusyBox v1.24.1 (2017-02-28 03:28:13 CET) multi-call binary\nvar busyBoxPingOutput = `\nPING 8.8.8.8 (8.8.8.8): 56 data bytes\n64 bytes from 8.8.8.8: seq=0 ttl=56 time=22.559 ms\n64 bytes from 8.8.8.8: seq=1 ttl=56 time=15.810 ms\n64 bytes from 8.8.8.8: seq=2 ttl=56 time=16.262 ms\n64 bytes from 8.8.8.8: seq=3 ttl=56 time=15.815 ms\n\n--- 8.8.8.8 ping statistics ---\n4 packets transmitted, 4 packets received, 0% packet loss\nround-trip min/avg/max = 15.810/17.611/22.559 ms\n`\n\n// Fatal ping output (invalid argument)\nvar fatalPingOutput = `\nping: -i interval too short: Operation not permitted\n`\n\n// Test that ping command output is processed properly\nfunc TestProcessPingOutput(t *testing.T) {\n\tstats, err := processPingOutput(bsdPingOutput)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 55, stats.ttl, \"ttl value is 55\")\n\trequire.Equal(t, 5, stats.packetsTransmitted, \"5 packets were transmitted\")\n\trequire.Equal(t, 5, stats.packetsReceived, \"5 packets were received\")\n\trequire.InDelta(t, 15.087, stats.min, testutil.DefaultDelta)\n\trequire.InDelta(t, 20.224, stats.avg, testutil.DefaultDelta)\n\trequire.InDelta(t, 27.263, stats.max, testutil.DefaultDelta)\n\trequire.InDelta(t, 4.076, stats.stddev, testutil.DefaultDelta)\n\n\tstats, err = processPingOutput(freebsdPing6Output)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 117, stats.ttl, \"ttl value is 117\")\n\trequire.Equal(t, 5, stats.packetsTransmitted, \"5 packets were transmitted\")\n\trequire.Equal(t, 5, stats.packetsReceived, \"5 packets were received\")\n\trequire.InDelta(t, 35.727, stats.min, testutil.DefaultDelta)\n\trequire.InDelta(t, 53.211, stats.avg, testutil.DefaultDelta)\n\trequire.InDelta(t, 93.870, stats.max, testutil.DefaultDelta)\n\trequire.InDelta(t, 22.000, stats.stddev, testutil.DefaultDelta)\n\n\tstats, err = processPingOutput(linuxPingOutput)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 63, stats.ttl, \"ttl value is 63\")\n\trequire.Equal(t, 5, stats.packetsTransmitted, \"5 packets were transmitted\")\n\trequire.Equal(t, 5, stats.packetsReceived, \"5 packets were received\")\n\trequire.InDelta(t, 35.225, stats.min, testutil.DefaultDelta)\n\trequire.InDelta(t, 43.628, stats.avg, testutil.DefaultDelta)\n\trequire.InDelta(t, 51.806, stats.max, testutil.DefaultDelta)\n\trequire.InDelta(t, 5.325, stats.stddev, testutil.DefaultDelta)\n\n\tstats, err = processPingOutput(busyBoxPingOutput)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 56, stats.ttl, \"ttl value is 56\")\n\trequire.Equal(t, 4, stats.packetsTransmitted, \"4 packets were transmitted\")\n\trequire.Equal(t, 4, stats.packetsReceived, \"4 packets were received\")\n\trequire.InDelta(t, 15.810, stats.min, testutil.DefaultDelta)\n\trequire.InDelta(t, 17.611, stats.avg, testutil.DefaultDelta)\n\trequire.InDelta(t, 22.559, stats.max, testutil.DefaultDelta)\n\trequire.InDelta(t, -1.0, stats.stddev, testutil.DefaultDelta)\n}\n\n// Linux ping output with varying TTL\nvar linuxPingOutputWithVaryingTTL = `\nPING www.google.com (216.58.218.164) 56(84) bytes of data.\n64 bytes from host.net (216.58.218.164): icmp_seq=1 ttl=63 time=35.2 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=2 ttl=255 time=42.3 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=3 ttl=64 time=45.1 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=4 ttl=64 time=43.5 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=5 ttl=255 time=51.8 ms\n\n--- www.google.com ping statistics ---\n5 packets transmitted, 5 received, 0% packet loss, time 4010ms\nrtt min/avg/max/mdev = 35.225/43.628/51.806/5.325 ms\n`\n\n// Test that ping command output is processed properly\nfunc TestProcessPingOutputWithVaryingTTL(t *testing.T) {\n\tstats, err := processPingOutput(linuxPingOutputWithVaryingTTL)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 63, stats.ttl, \"ttl value is 63\")\n\trequire.Equal(t, 5, stats.packetsTransmitted, \"5 packets were transmitted\")\n\trequire.Equal(t, 5, stats.packetsReceived, \"5 packets were transmitted\")\n\trequire.InDelta(t, 35.225, stats.min, testutil.DefaultDelta)\n\trequire.InDelta(t, 43.628, stats.avg, testutil.DefaultDelta)\n\trequire.InDelta(t, 51.806, stats.max, testutil.DefaultDelta)\n\trequire.InDelta(t, 5.325, stats.stddev, testutil.DefaultDelta)\n}\n\n// Test that processPingOutput returns an error when 'ping' fails to run, such\n// as when an invalid argument is provided\nfunc TestErrorProcessPingOutput(t *testing.T) {\n\t_, err := processPingOutput(fatalPingOutput)\n\trequire.Error(t, err, \"Error was expected from processPingOutput\")\n}\n\n// Test that default arg lists are created correctly\nfunc TestArgs(t *testing.T) {\n\tp := Ping{\n\t\tCount:        2,\n\t\tInterface:    \"eth0\",\n\t\tTimeout:      12.0,\n\t\tDeadline:     24,\n\t\tPingInterval: 1.2,\n\t}\n\n\tvar systemCases = []struct {\n\t\tsystem string\n\t\toutput []string\n\t}{\n\t\t{\"darwin\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-W\", \"12000\", \"-t\", \"24\", \"-I\", \"eth0\", \"www.google.com\"}},\n\t\t{\"linux\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-W\", \"12\", \"-w\", \"24\", \"-I\", \"eth0\", \"www.google.com\"}},\n\t\t{\"anything else\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-W\", \"12\", \"-w\", \"24\", \"-i\", \"eth0\", \"www.google.com\"}},\n\t}\n\tfor i := range systemCases {\n\t\tactual := p.args(\"www.google.com\", systemCases[i].system)\n\t\texpected := systemCases[i].output\n\t\tsort.Strings(actual)\n\t\tsort.Strings(expected)\n\t\trequire.Equal(t, expected, actual)\n\t}\n}\n\n// Test that default arg lists for ping6 are created correctly\nfunc TestArgs6(t *testing.T) {\n\tp := Ping{\n\t\tCount:        2,\n\t\tInterface:    \"eth0\",\n\t\tTimeout:      12.0,\n\t\tDeadline:     24,\n\t\tPingInterval: 1.2,\n\t\tBinary:       \"ping6\",\n\t}\n\n\tvar systemCases = []struct {\n\t\tsystem string\n\t\toutput []string\n\t}{\n\t\t{\"freebsd\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-x\", \"12000\", \"-X\", \"24\", \"-S\", \"eth0\", \"www.google.com\"}},\n\t\t{\"linux\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-W\", \"12\", \"-w\", \"24\", \"-I\", \"eth0\", \"www.google.com\"}},\n\t\t{\"anything else\", []string{\"-c\", \"2\", \"-n\", \"-s\", \"16\", \"-i\", \"1.2\", \"-W\", \"12\", \"-w\", \"24\", \"-i\", \"eth0\", \"www.google.com\"}},\n\t}\n\tfor i := range systemCases {\n\t\tactual := p.args(\"www.google.com\", systemCases[i].system)\n\t\texpected := systemCases[i].output\n\t\tsort.Strings(actual)\n\t\tsort.Strings(expected)\n\t\trequire.Equal(t, expected, actual)\n\t}\n}\n\nfunc TestArguments(t *testing.T) {\n\targuments := []string{\"-c\", \"3\"}\n\texpected := append(arguments, \"www.google.com\")\n\tp := Ping{\n\t\tCount:        2,\n\t\tInterface:    \"eth0\",\n\t\tTimeout:      12.0,\n\t\tDeadline:     24,\n\t\tPingInterval: 1.2,\n\t\tArguments:    arguments,\n\t}\n\n\tfor _, system := range []string{\"darwin\", \"linux\", \"anything else\"} {\n\t\tactual := p.args(\"www.google.com\", system)\n\t\trequire.Equal(t, expected, actual)\n\t}\n}\n\nfunc mockHostPinger(string, float64, ...string) (string, error) {\n\treturn linuxPingOutput, nil\n}\n\n// Test that Gather function works on a normal ping\nfunc TestPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:     []string{\"localhost\", \"influxdata.com\"},\n\t\tpingHost: mockHostPinger,\n\t}\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttags := map[string]string{\"url\": \"localhost\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\":   5,\n\t\t\"packets_received\":      5,\n\t\t\"percent_packet_loss\":   0.0,\n\t\t\"ttl\":                   63,\n\t\t\"minimum_response_ms\":   35.225,\n\t\t\"average_response_ms\":   43.628,\n\t\t\"maximum_response_ms\":   51.806,\n\t\t\"standard_deviation_ms\": 5.325,\n\t\t\"result_code\":           0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n\n\ttags = map[string]string{\"url\": \"influxdata.com\"}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\nfunc TestPingGatherIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode, retrieves systems ping utility\")\n\t}\n\n\tvar acc testutil.Accumulator\n\tp, ok := inputs.Inputs[\"ping\"]().(*Ping)\n\tp.Log = testutil.Logger{}\n\trequire.True(t, ok)\n\tp.Urls = []string{\"localhost\", \"influxdata.com\"}\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\trequire.Equal(t, 0, acc.Metrics[0].Fields[\"result_code\"])\n\trequire.Equal(t, 0, acc.Metrics[1].Fields[\"result_code\"])\n}\n\nvar lossyPingOutput = `\nPING www.google.com (216.58.218.164) 56(84) bytes of data.\n64 bytes from host.net (216.58.218.164): icmp_seq=1 ttl=63 time=35.2 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=3 ttl=63 time=45.1 ms\n64 bytes from host.net (216.58.218.164): icmp_seq=5 ttl=63 time=51.8 ms\n\n--- www.google.com ping statistics ---\n5 packets transmitted, 3 received, 40% packet loss, time 4010ms\nrtt min/avg/max/mdev = 35.225/44.033/51.806/5.325 ms\n`\n\nfunc mockLossyHostPinger(string, float64, ...string) (string, error) {\n\treturn lossyPingOutput, nil\n}\n\n// Test that Gather works on a ping with lossy packets\nfunc TestLossyPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:     []string{\"www.google.com\"},\n\t\tpingHost: mockLossyHostPinger,\n\t}\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttags := map[string]string{\"url\": \"www.google.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\":   5,\n\t\t\"packets_received\":      3,\n\t\t\"percent_packet_loss\":   40.0,\n\t\t\"ttl\":                   63,\n\t\t\"minimum_response_ms\":   35.225,\n\t\t\"average_response_ms\":   44.033,\n\t\t\"maximum_response_ms\":   51.806,\n\t\t\"standard_deviation_ms\": 5.325,\n\t\t\"result_code\":           0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\nvar errorPingOutput = `\nPING www.amazon.com (176.32.98.166): 56 data bytes\nRequest timeout for icmp_seq 0\n\n--- www.amazon.com ping statistics ---\n2 packets transmitted, 0 packets received, 100.0% packet loss\n`\n\nfunc mockErrorHostPinger(string, float64, ...string) (string, error) {\n\t// This error will not trigger correct error paths\n\treturn errorPingOutput, nil\n}\n\n// Test that Gather works on a ping with no transmitted packets, even though the\n// command returns an error\nfunc TestBadPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:     []string{\"www.amazon.com\"},\n\t\tpingHost: mockErrorHostPinger,\n\t}\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttags := map[string]string{\"url\": \"www.amazon.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 2,\n\t\t\"packets_received\":    0,\n\t\t\"percent_packet_loss\": 100.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\nfunc mockFatalHostPinger(string, float64, ...string) (string, error) {\n\treturn fatalPingOutput, errors.New(\"so very bad\")\n}\n\n// Test that a fatal ping command does not gather any statistics.\nfunc TestFatalPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:     []string{\"www.amazon.com\"},\n\t\tpingHost: mockFatalHostPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.Error(t, err)\n\trequire.EqualValues(t, \"host \\\"www.amazon.com\\\": so very bad - ping: -i interval too short: Operation not permitted\", err.Error())\n\trequire.False(t, acc.HasMeasurement(\"packets_transmitted\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"packets_received\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"percent_packet_loss\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"ttl\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"minimum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"average_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasMeasurement(\"maximum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n}\n\nfunc TestErrorWithHostNamePingGather(t *testing.T) {\n\tparams := []struct {\n\t\tout   string\n\t\terror error\n\t}{\n\t\t{\"\", errors.New(\"host \\\"www.amazon.com\\\": so very bad\")},\n\t\t{\"so bad\", errors.New(\"host \\\"www.amazon.com\\\": so very bad\")},\n\t}\n\n\tfor _, param := range params {\n\t\tvar acc testutil.Accumulator\n\t\tp := Ping{\n\t\t\tUrls: []string{\"www.amazon.com\"},\n\t\t\tpingHost: func(string, float64, ...string) (string, error) {\n\t\t\t\treturn param.out, errors.New(\"so very bad\")\n\t\t\t},\n\t\t}\n\t\trequire.Error(t, acc.GatherError(p.Gather))\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.Contains(t, acc.Errors[0].Error(), param.error.Error())\n\t}\n}\n\nfunc TestPingBinary(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:   []string{\"www.google.com\"},\n\t\tBinary: \"ping6\",\n\t\tpingHost: func(binary string, _ float64, _ ...string) (string, error) {\n\t\t\trequire.Equal(t, \"ping6\", binary)\n\t\t\treturn \"\", nil\n\t\t},\n\t}\n\terr := acc.GatherError(p.Gather)\n\trequire.Error(t, err)\n\trequire.EqualValues(t, \"\\\"www.google.com\\\": fatal error processing ping output\", err.Error())\n}\n\n// Test that Gather function works using native ping\nfunc TestPingGatherNative(t *testing.T) {\n\ttype test struct {\n\t\tP *Ping\n\t}\n\n\tfakePingFunc := func(string) (*pingStats, error) {\n\t\ts := &pingStats{\n\t\t\tStatistics: ping.Statistics{\n\t\t\t\tPacketsSent: 5,\n\t\t\t\tPacketsRecv: 5,\n\t\t\t\tRtts: []time.Duration{\n\t\t\t\t\t3 * time.Millisecond,\n\t\t\t\t\t4 * time.Millisecond,\n\t\t\t\t\t1 * time.Millisecond,\n\t\t\t\t\t5 * time.Millisecond,\n\t\t\t\t\t2 * time.Millisecond,\n\t\t\t\t},\n\t\t\t},\n\t\t\tttl: 1,\n\t\t}\n\n\t\treturn s, nil\n\t}\n\n\ttests := []test{\n\t\t{\n\t\t\tP: &Ping{\n\t\t\t\tUrls:           []string{\"localhost\", \"127.0.0.2\"},\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\tMethod:         \"native\",\n\t\t\t\tCount:          5,\n\t\t\t\tPercentiles:    []int{50, 95, 99},\n\t\t\t\tnativePingFunc: fakePingFunc,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tP: &Ping{\n\t\t\t\tUrls:           []string{\"localhost\", \"127.0.0.2\"},\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\tMethod:         \"native\",\n\t\t\t\tCount:          5,\n\t\t\t\tPingInterval:   1,\n\t\t\t\tPercentiles:    []int{50, 95, 99},\n\t\t\t\tnativePingFunc: fakePingFunc,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tvar acc testutil.Accumulator\n\t\trequire.NoError(t, tc.P.Init())\n\t\trequire.NoError(t, acc.GatherError(tc.P.Gather))\n\t\trequire.True(t, acc.HasPoint(\"ping\", map[string]string{\"url\": \"localhost\"}, \"packets_transmitted\", 5))\n\t\trequire.True(t, acc.HasPoint(\"ping\", map[string]string{\"url\": \"localhost\"}, \"packets_received\", 5))\n\t\trequire.True(t, acc.HasField(\"ping\", \"percentile50_ms\"))\n\t\trequire.InDelta(t, float64(3), acc.Metrics[0].Fields[\"percentile50_ms\"], testutil.DefaultDelta)\n\t\trequire.True(t, acc.HasField(\"ping\", \"percentile95_ms\"))\n\t\trequire.InDelta(t, float64(4.799999), acc.Metrics[0].Fields[\"percentile95_ms\"], testutil.DefaultDelta)\n\t\trequire.True(t, acc.HasField(\"ping\", \"percentile99_ms\"))\n\t\trequire.InDelta(t, float64(4.96), acc.Metrics[0].Fields[\"percentile99_ms\"], testutil.DefaultDelta)\n\t\trequire.True(t, acc.HasField(\"ping\", \"percent_packet_loss\"))\n\t\trequire.True(t, acc.HasField(\"ping\", \"minimum_response_ms\"))\n\t\trequire.True(t, acc.HasField(\"ping\", \"average_response_ms\"))\n\t\trequire.True(t, acc.HasField(\"ping\", \"maximum_response_ms\"))\n\t\trequire.True(t, acc.HasField(\"ping\", \"standard_deviation_ms\"))\n\t}\n}\n\nfunc TestInitWarnsForNativeTimeout(t *testing.T) {\n\tlogger := &testutil.CaptureLogger{Name: \"ping\"}\n\tp := &Ping{\n\t\tLog:      logger,\n\t\tMethod:   \"native\",\n\t\tCount:    1,\n\t\tTimeout:  2.0,\n\t\tDeadline: 10,\n\t}\n\n\trequire.NoError(t, p.Init())\n\twarnings := logger.Warnings()\n\trequire.Len(t, warnings, 1)\n\trequire.Contains(t, warnings[0], `\"timeout\" is ignored when method = \"native\"`)\n\trequire.Contains(t, warnings[0], `\"deadline\"`)\n}\n\nfunc TestNoPacketsSent(t *testing.T) {\n\tp := &Ping{\n\t\tLog:         testutil.Logger{},\n\t\tUrls:        []string{\"localhost\", \"127.0.0.2\"},\n\t\tMethod:      \"native\",\n\t\tCount:       5,\n\t\tPercentiles: []int{50, 95, 99},\n\t\tnativePingFunc: func(string) (*pingStats, error) {\n\t\t\ts := &pingStats{\n\t\t\t\tStatistics: ping.Statistics{\n\t\t\t\t\tPacketsSent: 0,\n\t\t\t\t\tPacketsRecv: 0,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\treturn s, nil\n\t\t},\n\t}\n\n\tvar testAcc testutil.Accumulator\n\trequire.NoError(t, p.Init())\n\n\tp.pingToURLNative(\"localhost\", &testAcc)\n\trequire.Zero(t, testAcc.Errors)\n\trequire.True(t, testAcc.HasField(\"ping\", \"result_code\"))\n\trequire.Equal(t, 2, testAcc.Metrics[0].Fields[\"result_code\"])\n}\n\n// Test failed DNS resolutions\nfunc TestDNSLookupError(t *testing.T) {\n\tp := &Ping{\n\t\tCount:  1,\n\t\tLog:    testutil.Logger{},\n\t\tUrls:   []string{\"localhost\"},\n\t\tMethod: \"native\",\n\t\tIPv6:   false,\n\t\tnativePingFunc: func(string) (*pingStats, error) {\n\t\t\treturn nil, errors.New(\"unknown\")\n\t\t},\n\t}\n\n\tvar testAcc testutil.Accumulator\n\trequire.NoError(t, p.Init())\n\n\tp.pingToURLNative(\"localhost\", &testAcc)\n\trequire.Zero(t, testAcc.Errors)\n\trequire.True(t, testAcc.HasField(\"ping\", \"result_code\"))\n\trequire.Equal(t, 1, testAcc.Metrics[0].Fields[\"result_code\"])\n}\n"
  },
  {
    "path": "plugins/inputs/ping/ping_windows.go",
    "content": "//go:build windows\n\npackage ping\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype roundTripTimeStats struct {\n\tmin int\n\tavg int\n\tmax int\n}\n\ntype statistics struct {\n\tpacketsTransmitted int\n\treplyReceived      int\n\tpacketsReceived    int\n\troundTripTimeStats\n}\n\nfunc (p *Ping) pingToURL(host string, acc telegraf.Accumulator) {\n\ttags := map[string]string{\"url\": host}\n\tfields := map[string]interface{}{\"result_code\": 0}\n\n\targs := p.args(host)\n\ttotalTimeout := 60.0\n\tif len(p.Arguments) == 0 {\n\t\ttotalTimeout = p.timeout() * float64(p.Count)\n\t}\n\n\tout, err := p.pingHost(p.Binary, totalTimeout, args...)\n\t// ping host return exitcode != 0 also when there was no response from host but command was executed successfully\n\tvar pendingError error\n\tif err != nil {\n\t\t// Combine go err + stderr output\n\t\tpendingError = errors.New(strings.TrimSpace(out) + \", \" + err.Error())\n\t}\n\tstats, err := processPingOutput(out)\n\tif err != nil {\n\t\t// fatal error\n\t\tif pendingError != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", host, pendingError))\n\t\t} else {\n\t\t\tacc.AddError(fmt.Errorf(\"%s: %w\", host, err))\n\t\t}\n\n\t\tfields[\"result_code\"] = 2\n\t\tfields[\"errors\"] = 100.0\n\t\tacc.AddFields(\"ping\", fields, tags)\n\t\treturn\n\t}\n\t// Calculate packet loss percentage\n\tlossReply := float64(stats.packetsTransmitted-stats.replyReceived) / float64(stats.packetsTransmitted) * 100.0\n\tlossPackets := float64(stats.packetsTransmitted-stats.packetsReceived) / float64(stats.packetsTransmitted) * 100.0\n\n\tfields[\"packets_transmitted\"] = stats.packetsTransmitted\n\tfields[\"reply_received\"] = stats.replyReceived\n\tfields[\"packets_received\"] = stats.packetsReceived\n\tfields[\"percent_packet_loss\"] = lossPackets\n\tfields[\"percent_reply_loss\"] = lossReply\n\tif stats.avg >= 0 {\n\t\tfields[\"average_response_ms\"] = float64(stats.avg)\n\t}\n\tif stats.min >= 0 {\n\t\tfields[\"minimum_response_ms\"] = float64(stats.min)\n\t}\n\tif stats.max >= 0 {\n\t\tfields[\"maximum_response_ms\"] = float64(stats.max)\n\t}\n\tacc.AddFields(\"ping\", fields, tags)\n}\n\n// args returns the arguments for the 'ping' executable\nfunc (p *Ping) args(url string) []string {\n\tif len(p.Arguments) > 0 {\n\t\treturn p.Arguments\n\t}\n\n\targs := []string{\"-n\", strconv.Itoa(p.Count)}\n\n\tif p.Timeout > 0 {\n\t\targs = append(args, \"-w\", strconv.FormatFloat(p.Timeout*1000, 'f', 0, 64))\n\t}\n\n\targs = append(args, url)\n\n\treturn args\n}\n\n// processPingOutput takes in a string output from the ping command\n// based on linux implementation but using regex (multi-language support)\n// It returns (<transmitted packets>, <received reply>, <received packet>, <average response>, <min response>, <max response>)\nfunc processPingOutput(out string) (statistics, error) {\n\t// So find a line contain 3 numbers except reply lines\n\tvar statsLine, approxs []string = nil, nil\n\terr := errors.New(\"fatal error processing ping output\")\n\tstat := regexp.MustCompile(`=\\W*(\\d+)\\D*=\\W*(\\d+)\\D*=\\W*(\\d+)`)\n\tapprox := regexp.MustCompile(`=\\W*(\\d+)\\D*ms\\D*=\\W*(\\d+)\\D*ms\\D*=\\W*(\\d+)\\D*ms`)\n\ttttLine := regexp.MustCompile(`TTL=\\d+`)\n\tlines := strings.Split(out, \"\\n\")\n\tvar replyReceived = 0\n\tfor _, line := range lines {\n\t\tif tttLine.MatchString(line) {\n\t\t\treplyReceived++\n\t\t} else {\n\t\t\tif statsLine == nil {\n\t\t\t\tstatsLine = stat.FindStringSubmatch(line)\n\t\t\t}\n\t\t\tif statsLine != nil && approxs == nil {\n\t\t\t\tapproxs = approx.FindStringSubmatch(line)\n\t\t\t}\n\t\t}\n\t}\n\n\tstats := statistics{\n\t\tpacketsTransmitted: 0,\n\t\treplyReceived:      0,\n\t\tpacketsReceived:    0,\n\t\troundTripTimeStats: roundTripTimeStats{\n\t\t\tmin: -1,\n\t\t\tavg: -1,\n\t\t\tmax: -1,\n\t\t},\n\t}\n\n\t// statsLine data should contain 4 members: entireExpression + ( Send, Receive, Lost )\n\tif len(statsLine) != 4 {\n\t\treturn stats, err\n\t}\n\tpacketsTransmitted, err := strconv.Atoi(statsLine[1])\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tpacketsReceived, err := strconv.Atoi(statsLine[2])\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\n\tstats.packetsTransmitted = packetsTransmitted\n\tstats.replyReceived = replyReceived\n\tstats.packetsReceived = packetsReceived\n\n\t// approxs data should contain 4 members: entireExpression + ( min, max, avg )\n\tif len(approxs) != 4 {\n\t\treturn stats, err\n\t}\n\tlow, err := strconv.Atoi(approxs[1])\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\thigh, err := strconv.Atoi(approxs[2])\n\tif err != nil {\n\t\treturn stats, err\n\t}\n\tavg, err := strconv.Atoi(approxs[3])\n\tif err != nil {\n\t\treturn statistics{}, err\n\t}\n\n\tstats.avg = avg\n\tstats.min = low\n\tstats.max = high\n\n\treturn stats, err\n}\n\nfunc (p *Ping) timeout() float64 {\n\t// According to MSDN, default ping timeout for windows is 4 second\n\t// Add also one second interval\n\n\tif p.Timeout > 0 {\n\t\treturn p.Timeout + 1\n\t}\n\treturn 4 + 1\n}\n"
  },
  {
    "path": "plugins/inputs/ping/ping_windows_test.go",
    "content": "//go:build windows\n\npackage ping\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// Windows ping format ( should support multilanguage ?)\nvar winPLPingOutput = `\nBadanie 8.8.8.8 z 32 bajtami danych:\nOdpowiedz z 8.8.8.8: bajtow=32 czas=49ms TTL=43\nOdpowiedz z 8.8.8.8: bajtow=32 czas=46ms TTL=43\nOdpowiedz z 8.8.8.8: bajtow=32 czas=48ms TTL=43\nOdpowiedz z 8.8.8.8: bajtow=32 czas=57ms TTL=43\n\nStatystyka badania ping dla 8.8.8.8:\n    Pakiety: Wyslane = 4, Odebrane = 4, Utracone = 0\n             (0% straty),\nSzacunkowy czas bladzenia pakietww w millisekundach:\n    Minimum = 46 ms, Maksimum = 57 ms, Czas sredni = 50 ms\n`\n\n// Windows ping format ( should support multilanguage ?)\nvar winENPingOutput = `\nPinging 8.8.8.8 with 32 bytes of data:\nReply from 8.8.8.8: bytes=32 time=52ms TTL=43\nReply from 8.8.8.8: bytes=32 time=50ms TTL=43\nReply from 8.8.8.8: bytes=32 time=50ms TTL=43\nReply from 8.8.8.8: bytes=32 time=51ms TTL=43\n\nPing statistics for 8.8.8.8:\n    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),\nApproximate round trip times in milli-seconds:\n    Minimum = 50ms, Maximum = 52ms, Average = 50ms\n`\n\nfunc TestHost(t *testing.T) {\n\tstats, err := processPingOutput(winPLPingOutput)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 4, stats.packetsTransmitted, \"4 packets were transmitted\")\n\trequire.Equal(t, 4, stats.replyReceived, \"4 packets were reply\")\n\trequire.Equal(t, 4, stats.packetsReceived, \"4 packets were received\")\n\trequire.Equal(t, 50, stats.avg, \"Average 50\")\n\trequire.Equal(t, 46, stats.min, \"Min 46\")\n\trequire.Equal(t, 57, stats.max, \"max 57\")\n\n\tstats, err = processPingOutput(winENPingOutput)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 4, stats.packetsTransmitted, \"4 packets were transmitted\")\n\trequire.Equal(t, 4, stats.replyReceived, \"4 packets were reply\")\n\trequire.Equal(t, 4, stats.packetsReceived, \"4 packets were received\")\n\trequire.Equal(t, 50, stats.avg, \"Average 50\")\n\trequire.Equal(t, 50, stats.min, \"Min 50\")\n\trequire.Equal(t, 52, stats.max, \"Max 52\")\n}\n\nfunc mockHostPinger(string, float64, ...string) (string, error) {\n\treturn winENPingOutput, nil\n}\n\n// Test that Gather function works on a normal ping\nfunc TestPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tUrls:     []string{\"www.google.com\", \"www.reddit.com\"},\n\t\tpingHost: mockHostPinger,\n\t}\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttags := map[string]string{\"url\": \"www.google.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 4,\n\t\t\"packets_received\":    4,\n\t\t\"reply_received\":      4,\n\t\t\"percent_packet_loss\": 0.0,\n\t\t\"percent_reply_loss\":  0.0,\n\t\t\"average_response_ms\": 50.0,\n\t\t\"minimum_response_ms\": 50.0,\n\t\t\"maximum_response_ms\": 52.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n\n\ttags = map[string]string{\"url\": \"www.reddit.com\"}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\nvar errorPingOutput = `\nBadanie nask.pl [195.187.242.157] z 32 bajtami danych:\nUpłynął limit czasu żądania.\nUpłynął limit czasu żądania.\nUpłynął limit czasu żądania.\nUpłynął limit czasu żądania.\n\nStatystyka badania ping dla 195.187.242.157:\n    Pakiety: Wysłane = 4, Odebrane = 0, Utracone = 4\n             (100% straty),\n`\n\nfunc mockErrorHostPinger(string, float64, ...string) (string, error) {\n\treturn errorPingOutput, errors.New(\"no packets received\")\n}\n\n// Test that Gather works on a ping with no transmitted packets, even though the\n// command returns an error\nfunc TestBadPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:      testutil.Logger{},\n\t\tUrls:     []string{\"www.amazon.com\"},\n\t\tpingHost: mockErrorHostPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\"url\": \"www.amazon.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 4,\n\t\t\"packets_received\":    0,\n\t\t\"reply_received\":      0,\n\t\t\"percent_packet_loss\": 100.0,\n\t\t\"percent_reply_loss\":  100.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\nfunc TestArguments(t *testing.T) {\n\targuments := []string{\"-c\", \"3\"}\n\tp := Ping{\n\t\tLog:       testutil.Logger{},\n\t\tCount:     2,\n\t\tTimeout:   12.0,\n\t\tArguments: arguments,\n\t}\n\n\tactual := p.args(\"www.google.com\")\n\trequire.Equal(t, actual, arguments)\n}\n\nvar lossyPingOutput = `\nBadanie thecodinglove.com [66.6.44.4] z 9800 bajtami danych:\nUpłynął limit czasu żądania.\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=118ms TTL=48\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48\nUpłynął limit czasu żądania.\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=119ms TTL=48\nOdpowiedź z 66.6.44.4: bajtów=9800 czas=116ms TTL=48\n\nStatystyka badania ping dla 66.6.44.4:\n    Pakiety: Wysłane = 9, Odebrane = 7, Utracone = 2\n             (22% straty),\nSzacunkowy czas błądzenia pakietów w millisekundach:\n    Minimum = 114 ms, Maksimum = 119 ms, Czas średni = 115 ms\n`\n\nfunc mockLossyHostPinger(string, float64, ...string) (string, error) {\n\treturn lossyPingOutput, nil\n}\n\n// Test that Gather works on a ping with lossy packets\nfunc TestLossyPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:      testutil.Logger{},\n\t\tUrls:     []string{\"www.google.com\"},\n\t\tpingHost: mockLossyHostPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\"url\": \"www.google.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 9,\n\t\t\"packets_received\":    7,\n\t\t\"reply_received\":      7,\n\t\t\"percent_packet_loss\": 22.22222222222222,\n\t\t\"percent_reply_loss\":  22.22222222222222,\n\t\t\"average_response_ms\": 115.0,\n\t\t\"minimum_response_ms\": 114.0,\n\t\t\"maximum_response_ms\": 119.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n}\n\n// Fatal ping output (invalid argument)\nvar fatalPingOutput = `\nBad option -d.\n\n\nUsage: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]\n            [-r count] [-s count] [[-j host-list] | [-k host-list]]\n            [-w timeout] [-R] [-S srcaddr] [-4] [-6] target_name\n\nOptions:\n    -t             Ping the specified host until stopped.\n                   To see statistics and continue - type Control-Break;\n                   To stop - type Control-C.\n    -a             Resolve addresses to hostnames.\n    -n count       Number of echo requests to send.\n    -l size        Send buffer size.\n    -f             Set Don't Fragment flag in packet (IPv4-only).\n    -i TTL         Time To Live.\n    -v TOS         Type Of Service (IPv4-only. This setting has been deprecated\n                   and has no effect on the type of service field in the IP Header).\n    -r count       Record route for count hops (IPv4-only).\n    -s count       Timestamp for count hops (IPv4-only).\n    -j host-list   Loose source route along host-list (IPv4-only).\n    -k host-list   Strict source route along host-list (IPv4-only).\n    -w timeout     Timeout in milliseconds to wait for each reply.\n    -R             Use routing header to test reverse route also (IPv6-only).\n    -S srcaddr     Source address to use.\n    -4             Force using IPv4.\n    -6             Force using IPv6.\n\n`\n\nfunc mockFatalHostPinger(string, float64, ...string) (string, error) {\n\treturn fatalPingOutput, errors.New(\"so very bad\")\n}\n\n// Test that a fatal ping command does not gather any statistics.\nfunc TestFatalPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:      testutil.Logger{},\n\t\tUrls:     []string{\"www.amazon.com\"},\n\t\tpingHost: mockFatalHostPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.Error(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"ping\", \"errors\"),\n\t\t\"Fatal ping should have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"packets_transmitted\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"packets_received\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasFloatField(\"ping\", \"percent_packet_loss\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasFloatField(\"ping\", \"percent_reply_loss\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"average_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"maximum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"minimum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n}\n\nvar unreachablePingOutput = `\nPinging www.google.pl [8.8.8.8] with 32 bytes of data:\nRequest timed out.\nRequest timed out.\nReply from 194.204.175.50: Destination net unreachable.\nRequest timed out.\n\nPing statistics for 8.8.8.8:\n    Packets: Sent = 4, Received = 1, Lost = 3 (75% loss),\n`\n\nfunc mockUnreachableHostPinger(string, float64, ...string) (string, error) {\n\treturn unreachablePingOutput, errors.New(\"so very bad\")\n}\n\n// Reply from 185.28.251.217: TTL expired in transit.\n\n// in case 'Destination net unreachable' ping app return receive packet which is not what we need\n// it's not contain valid metric so treat it as lost one\nfunc TestUnreachablePingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:      testutil.Logger{},\n\t\tUrls:     []string{\"www.google.com\"},\n\t\tpingHost: mockUnreachableHostPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\"url\": \"www.google.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 4,\n\t\t\"packets_received\":    1,\n\t\t\"reply_received\":      0,\n\t\t\"percent_packet_loss\": 75.0,\n\t\t\"percent_reply_loss\":  100.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n\n\trequire.False(t, acc.HasFloatField(\"ping\", \"errors\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"average_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"maximum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"minimum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n}\n\nvar ttlExpiredPingOutput = `\nPinging www.google.pl [8.8.8.8] with 32 bytes of data:\nRequest timed out.\nRequest timed out.\nReply from 185.28.251.217: TTL expired in transit.\nRequest timed out.\n\nPing statistics for 8.8.8.8:\n    Packets: Sent = 4, Received = 1, Lost = 3 (75% loss),\n`\n\nfunc mockTTLExpiredPinger(string, float64, ...string) (string, error) {\n\treturn ttlExpiredPingOutput, errors.New(\"so very bad\")\n}\n\n// in case 'Destination net unreachable' ping app return receive packet which is not what we need\n// it's not contain valid metric so treat it as lost one\nfunc TestTTLExpiredPingGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:      testutil.Logger{},\n\t\tUrls:     []string{\"www.google.com\"},\n\t\tpingHost: mockTTLExpiredPinger,\n\t}\n\n\terr := acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\ttags := map[string]string{\"url\": \"www.google.com\"}\n\tfields := map[string]interface{}{\n\t\t\"packets_transmitted\": 4,\n\t\t\"packets_received\":    1,\n\t\t\"reply_received\":      0,\n\t\t\"percent_packet_loss\": 75.0,\n\t\t\"percent_reply_loss\":  100.0,\n\t\t\"result_code\":         0,\n\t}\n\tacc.AssertContainsTaggedFields(t, \"ping\", fields, tags)\n\n\trequire.False(t, acc.HasFloatField(\"ping\", \"errors\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"average_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"maximum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n\trequire.False(t, acc.HasInt64Field(\"ping\", \"minimum_response_ms\"),\n\t\t\"Fatal ping should not have packet measurements\")\n}\n\nfunc TestPingBinary(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tp := Ping{\n\t\tLog:    testutil.Logger{},\n\t\tUrls:   []string{\"www.google.com\"},\n\t\tBinary: \"ping6\",\n\t\tpingHost: func(binary string, _ float64, _ ...string) (string, error) {\n\t\t\trequire.Equal(t, \"ping6\", binary)\n\t\t\treturn \"\", nil\n\t\t},\n\t}\n\terr := acc.GatherError(p.Gather)\n\trequire.Error(t, err)\n\trequire.EqualValues(t, \"www.google.com: fatal error processing ping output\", err.Error())\n}\n"
  },
  {
    "path": "plugins/inputs/ping/sample.conf",
    "content": "# Ping given url(s) and return statistics\n[[inputs.ping]]\n  ## Hosts to send ping packets to.\n  urls = [\"example.org\"]\n\n  ## Method used for sending pings, can be either \"exec\" or \"native\".  When set\n  ## to \"exec\" the systems ping command will be executed.  When set to \"native\"\n  ## the plugin will send pings directly.\n  ##\n  ## While the default is \"exec\" for backwards compatibility, new deployments\n  ## are encouraged to use the \"native\" method for improved compatibility and\n  ## performance.\n  # method = \"exec\"\n\n  ## Number of ping packets to send per interval.  Corresponds to the \"-c\"\n  ## option of the ping command.\n  # count = 1\n\n  ## Time to wait between sending ping packets in seconds.  Operates like the\n  ## \"-i\" option of the ping command.\n  # ping_interval = 1.0\n\n  ## If set, the time to wait for a ping response in seconds.  Operates like\n  ## the \"-W\" option of the ping command (for \"exec\" method only)\n  # timeout = 1.0\n\n  ## If set, the total ping deadline, in seconds. Operates like the \"-w\"\n  ## option of the ping command.  Use this option to control timeout behavior\n  ## when using the \"native\" method.\n  # deadline = 10\n\n  ## Interface or source address to send ping from.  Operates like the -I or -S\n  ## option of the ping command.\n  # interface = \"\"\n\n  ## Percentiles to calculate. This only works with the native method.\n  # percentiles = [50, 95, 99]\n\n  ## Specify the ping executable binary.\n  # binary = \"ping\"\n\n  ## Arguments for ping command. When arguments is not empty, the command from\n  ## the binary option will be used and other options (ping_interval, timeout,\n  ## etc) will be ignored.\n  # arguments = [\"-c\", \"3\"]\n\n  ## Use only IPv4 addresses when resolving a hostname. By default, both IPv4\n  ## and IPv6 can be used.\n  # ipv4 = false\n\n  ## Use only IPv6 addresses when resolving a hostname. By default, both IPv4\n  ## and IPv6 can be used.\n  # ipv6 = false\n\n  ## Number of data bytes to be sent. Corresponds to the \"-s\"\n  ## option of the ping command. This only works with the native method.\n  # size = 56\n"
  },
  {
    "path": "plugins/inputs/postfix/README.md",
    "content": "# Postfix Input Plugin\n\nThis plugin collects metrics on a local [Postfix][postfix] instance reporting\nthe length, size and age of the active, hold, incoming, maildrop, and deferred\n[queues][queues].\n\n⭐ Telegraf v1.5.0\n🏷️ server\n💻 freebsd, linux, macos, solaris\n\n[postfix]: https://www.postfix.org/\n[queues]: https://www.postfix.org/QSHAPE_README.html#queues\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Measure postfix queue statistics\n# This plugin ONLY supports non-Windows\n[[inputs.postfix]]\n  ## Postfix queue directory. If not provided, telegraf will try to use\n  ## 'postconf -h queue_directory' to determine it.\n  # queue_directory = \"/var/spool/postfix\"\n```\n\n### Permissions\n\nTelegraf will need read access to the files in the queue directory.  You may\nneed to alter the permissions of these directories to provide access to the\ntelegraf user.\n\nThis can be setup either using standard unix permissions or with Posix ACLs,\nyou will only need to use one method:\n\nUnix permissions:\n\n```sh\nsudo chgrp -R telegraf /var/spool/postfix/{active,hold,incoming,deferred}\nsudo chmod -R g+rXs /var/spool/postfix/{active,hold,incoming,deferred}\nsudo usermod -a -G postdrop telegraf\nsudo chmod g+r /var/spool/postfix/maildrop\n```\n\nPosix ACL:\n\n```sh\nsudo setfacl -Rm g:telegraf:rX /var/spool/postfix/\nsudo setfacl -dm g:telegraf:rX /var/spool/postfix/\n```\n\n## Metrics\n\n- postfix_queue\n  - tags:\n    - queue\n  - fields:\n    - length (integer)\n    - size (integer, bytes)\n    - age (integer, seconds)\n\n## Example Output\n\n```text\npostfix_queue,queue=active length=3,size=12345,age=9\npostfix_queue,queue=hold length=0,size=0,age=0\npostfix_queue,queue=maildrop length=1,size=2000,age=2\npostfix_queue,queue=incoming length=1,size=1020,age=0\npostfix_queue,queue=deferred length=400,size=76543210,age=3600\n```\n"
  },
  {
    "path": "plugins/inputs/postfix/postfix.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !windows\n\n// postfix doesn't aim for Windows\n\npackage postfix\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Postfix struct {\n\tQueueDirectory string `toml:\"queue_directory\"`\n}\n\nfunc (*Postfix) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Postfix) Gather(acc telegraf.Accumulator) error {\n\tif p.QueueDirectory == \"\" {\n\t\tvar err error\n\t\tp.QueueDirectory, err = getQueueDirectory()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to determine queue directory: %w\", err)\n\t\t}\n\t}\n\n\tfor _, q := range []string{\"active\", \"hold\", \"incoming\", \"maildrop\", \"deferred\"} {\n\t\tfields, err := qScan(filepath.Join(p.QueueDirectory, q), acc)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error scanning queue %q: %w\", q, err))\n\t\t\tcontinue\n\t\t}\n\n\t\tacc.AddFields(\"postfix_queue\", fields, map[string]string{\"queue\": q})\n\t}\n\n\treturn nil\n}\n\nfunc getQueueDirectory() (string, error) {\n\tqd, err := exec.Command(\"postconf\", \"-h\", \"queue_directory\").Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.TrimSpace(string(qd)), nil\n}\n\nfunc qScan(path string, acc telegraf.Accumulator) (map[string]interface{}, error) {\n\tvar length, size int64\n\tvar oldest time.Time\n\n\terr := filepath.Walk(path, func(_ string, finfo os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"error scanning %q: %w\", path, err))\n\t\t\treturn nil\n\t\t}\n\t\tif finfo.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tlength++\n\t\tsize += finfo.Size()\n\n\t\tctime := statCTime(finfo.Sys())\n\t\tif ctime.IsZero() {\n\t\t\treturn nil\n\t\t}\n\t\tif oldest.IsZero() || ctime.Before(oldest) {\n\t\t\toldest = ctime\n\t\t}\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar age int64\n\tif !oldest.IsZero() {\n\t\tage = int64(time.Since(oldest) / time.Second)\n\t} else if length != 0 {\n\t\t// system doesn't support ctime\n\t\tage = -1\n\t}\n\n\tfields := map[string]interface{}{\"length\": length, \"size\": size}\n\tif age != -1 {\n\t\tfields[\"age\"] = age\n\t}\n\n\treturn fields, nil\n}\n\nfunc init() {\n\tinputs.Add(\"postfix\", func() telegraf.Input {\n\t\treturn &Postfix{\n\t\t\tQueueDirectory: \"/var/spool/postfix\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/postfix/postfix_test.go",
    "content": "//go:build !windows\n\npackage postfix\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\ttd := t.TempDir()\n\n\tfor _, q := range []string{\"active\", \"hold\", \"incoming\", \"maildrop\", \"deferred/0/0\", \"deferred/F/F\"} {\n\t\trequire.NoError(t, os.MkdirAll(filepath.FromSlash(td+\"/\"+q), 0750))\n\t}\n\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/active/01\"), []byte(\"abc\"), 0640))\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/active/02\"), []byte(\"defg\"), 0640))\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/hold/01\"), []byte(\"abc\"), 0640))\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/incoming/01\"), []byte(\"abcd\"), 0640))\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/deferred/0/0/01\"), []byte(\"abc\"), 0640))\n\trequire.NoError(t, os.WriteFile(filepath.FromSlash(td+\"/deferred/F/F/F1\"), []byte(\"abc\"), 0640))\n\n\tp := Postfix{\n\t\tQueueDirectory: td,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\tmetrics := map[string]*testutil.Metric{}\n\tfor _, m := range acc.Metrics {\n\t\tmetrics[m.Tags[\"queue\"]] = m\n\t}\n\n\trequire.Equal(t, int64(2), metrics[\"active\"].Fields[\"length\"])\n\trequire.Equal(t, int64(7), metrics[\"active\"].Fields[\"size\"])\n\trequire.InDelta(t, 0, metrics[\"active\"].Fields[\"age\"], 10)\n\n\trequire.Equal(t, int64(1), metrics[\"hold\"].Fields[\"length\"])\n\trequire.Equal(t, int64(3), metrics[\"hold\"].Fields[\"size\"])\n\n\trequire.Equal(t, int64(1), metrics[\"incoming\"].Fields[\"length\"])\n\trequire.Equal(t, int64(4), metrics[\"incoming\"].Fields[\"size\"])\n\n\trequire.Equal(t, int64(0), metrics[\"maildrop\"].Fields[\"length\"])\n\trequire.Equal(t, int64(0), metrics[\"maildrop\"].Fields[\"size\"])\n\trequire.Equal(t, int64(0), metrics[\"maildrop\"].Fields[\"age\"])\n\n\trequire.Equal(t, int64(2), metrics[\"deferred\"].Fields[\"length\"])\n\trequire.Equal(t, int64(6), metrics[\"deferred\"].Fields[\"size\"])\n}\n"
  },
  {
    "path": "plugins/inputs/postfix/postfix_windows.go",
    "content": "//go:build windows\n\npackage postfix\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Postfix struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Postfix) SampleConfig() string { return sampleConfig }\n\nfunc (p *Postfix) Init() error {\n\tp.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Postfix) Gather(_ telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"postfix\", func() telegraf.Input {\n\t\treturn &Postfix{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/postfix/sample.conf",
    "content": "# Measure postfix queue statistics\n# This plugin ONLY supports non-Windows\n[[inputs.postfix]]\n  ## Postfix queue directory. If not provided, telegraf will try to use\n  ## 'postconf -h queue_directory' to determine it.\n  # queue_directory = \"/var/spool/postfix\"\n"
  },
  {
    "path": "plugins/inputs/postfix/stat_ctim.go",
    "content": "//go:build dragonfly || linux || netbsd || openbsd || solaris\n\npackage postfix\n\nimport (\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc statCTime(sys interface{}) time.Time {\n\tstat, ok := sys.(*syscall.Stat_t)\n\tif !ok {\n\t\treturn time.Time{}\n\t}\n\treturn time.Unix(stat.Ctim.Unix())\n}\n"
  },
  {
    "path": "plugins/inputs/postfix/stat_ctimespec.go",
    "content": "//go:build darwin || freebsd\n\npackage postfix\n\nimport (\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc statCTime(sys interface{}) time.Time {\n\tstat, ok := sys.(*syscall.Stat_t)\n\tif !ok {\n\t\treturn time.Time{}\n\t}\n\treturn time.Unix(stat.Ctimespec.Unix())\n}\n"
  },
  {
    "path": "plugins/inputs/postgresql/README.md",
    "content": "# PostgreSQL Input Plugin\n\nThis plugin provides metrics for a [PostgreSQL][postgres] Server instance.\nRecorded metrics are lightweight and use Dynamic Management Views supplied\nby PostgreSQL.\n\n⭐ Telegraf v0.10.3\n🏷️ datastore\n💻 all\n\n[postgres]: https://www.postgresql.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `address` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many postgresql servers\n[[inputs.postgresql]]\n  ## Specify address via a url matching:\n  ##   postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full]&statement_timeout=...\n  ## or a simple string:\n  ##   host=localhost user=pqgotest password=... sslmode=... dbname=app_production\n  ## Users can pass the path to the socket as the host value to use a socket\n  ## connection (e.g. `/var/run/postgresql`).\n  ##\n  ## All connection parameters are optional.\n  ##\n  ## Without the dbname parameter, the driver will default to a database\n  ## with the same name as the user. This dbname is just for instantiating a\n  ## connection with the server and doesn't restrict the databases we are trying\n  ## to grab metrics for.\n  ##\n  address = \"host=localhost user=postgres sslmode=disable\"\n\n  ## A custom name for the database that will be used as the \"server\" tag in the\n  ## measurement output. If not specified, a default one generated from\n  ## the connection address is used.\n  # outputaddress = \"db01\"\n\n  ## connection configuration.\n  ## maxlifetime - specify the maximum lifetime of a connection.\n  ## default is forever (0s)\n  ##\n  ## Note that this does not interrupt queries, the lifetime will not be enforced\n  ## whilst a query is running\n  # max_lifetime = \"0s\"\n\n  ## A  list of databases to explicitly ignore.  If not specified, metrics for all\n  ## databases are gathered.  Do NOT use with the 'databases' option.\n  # ignored_databases = [\"postgres\", \"template0\", \"template1\"]\n\n  ## A list of databases to pull metrics about. If not specified, metrics for all\n  ## databases are gathered.  Do NOT use with the 'ignored_databases' option.\n  # databases = [\"app_production\", \"testing\"]\n\n  ## Whether to use prepared statements when connecting to the database.\n  ## This should be set to false when connecting through a PgBouncer instance\n  ## with pool_mode set to transaction.\n  prepared_statements = true\n```\n\nSpecify address via a postgresql connection string:\n\n```text\nhost=localhost port=5432 user=telegraf database=telegraf\n```\n\nOr via an url matching:\n\n```text\npostgres://[pqgotest[:password]]@host:port[/dbname]?sslmode=[disable|verify-ca|verify-full]\n```\n\nUsers can pass the path to the socket as the host value to use a socket\nconnection (e.g. `/var/run/postgresql`).\n\nIt is also possible to specify a query timeout maximum execution time (in ms)\nfor any individual statement passed over the connection\n\n```text\npostgres://[pqgotest[:password]]@host:port[/dbname]?sslmode=[disable|verify-ca|verify-full]&statement_timeout=10000\n```\n\nAll connection parameters are optional. Without the dbname parameter, the driver\nwill default to a database with the same name as the user. This dbname is just\nfor instantiating a connection with the server and doesn't restrict the\ndatabases we are trying to grab metrics for.\n\nA list of databases to explicitly ignore.  If not specified, metrics for all\ndatabases are gathered.  Do NOT use with the 'databases' option.\n\n```text\nignored_databases = [\"postgres\", \"template0\", \"template1\"]`\n```\n\nA list of databases to pull metrics about. If not specified, metrics for all\ndatabases are gathered.  Do NOT use with the 'ignored_databases' option.\n\n```text\ndatabases = [\"app_production\", \"testing\"]`\n```\n\n### Permissions\n\nThe plugins gathers metrics from the `pg_stat_database` and `pg_stat_bgwriter`\nviews. To grant a user access to the views run:\n\n```sql\nGRANT pg_read_all_stats TO user;\n```\n\nSee the [PostgreSQL docs][] for more information on the predefined roles.\n\n[PostgreSQL docs]: https://www.postgresql.org/docs/current/predefined-roles.html\n\n### TLS Configuration\n\nAdd the `sslkey`, `sslcert` and `sslrootcert` options to your DSN:\n\n```shell\nhost=localhost user=pgotest dbname=app_production sslmode=require sslkey=/etc/telegraf/key.pem sslcert=/etc/telegraf/cert.pem sslrootcert=/etc/telegraf/ca.pem\n```\n\n## Metrics\n\nThis postgresql plugin provides metrics for your postgres database. It currently\nworks with postgres versions 8.1+. It uses data from the built in\n_pg_stat_database_ and pg_stat_bgwriter views. The metrics recorded depend on\nyour version of postgres. See table:\n\n```sh\npg version      9.2+   9.1   8.3-9.0   8.1-8.2   7.4-8.0(unsupported)\n---             ---    ---   -------   -------   -------\ndatid            x      x       x         x\ndatname          x      x       x         x\nnumbackends      x      x       x         x         x\nxact_commit      x      x       x         x         x\nxact_rollback    x      x       x         x         x\nblks_read        x      x       x         x         x\nblks_hit         x      x       x         x         x\ntup_returned     x      x       x\ntup_fetched      x      x       x\ntup_inserted     x      x       x\ntup_updated      x      x       x\ntup_deleted      x      x       x\nconflicts        x      x\ntemp_files       x\ntemp_bytes       x\ndeadlocks        x\nblk_read_time    x\nblk_write_time   x\nstats_reset*     x      x\n```\n\n_* value ignored and therefore not recorded._\n\nMore information about the meaning of these metrics can be found in the\n[PostgreSQL Documentation][1].\n\n[1]: http://www.postgresql.org/docs/9.2/static/monitoring-stats.html#PG-STAT-DATABASE-VIEW\n\n## Example Output\n\n```text\npostgresql,db=postgres_global,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres tup_fetched=1271i,tup_updated=5i,session_time=1451414320768.855,xact_rollback=2i,conflicts=0i,blk_write_time=0,temp_bytes=0i,datid=0i,sessions_fatal=0i,tup_returned=1339i,sessions_abandoned=0i,blk_read_time=0,blks_read=88i,idle_in_transaction_time=0,sessions=0i,active_time=0,tup_inserted=24i,tup_deleted=0i,temp_files=0i,numbackends=0i,xact_commit=4i,sessions_killed=0i,blks_hit=5616i,deadlocks=0i 1672399790000000000\npostgresql,db=postgres,host=oss_cluster_host,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres conflicts=0i,sessions_abandoned=2i,active_time=460340.823,tup_returned=119382i,tup_deleted=0i,blk_write_time=0,xact_commit=305i,blks_hit=16358i,deadlocks=0i,sessions=12i,numbackends=1i,temp_files=0i,xact_rollback=5i,sessions_fatal=0i,datname=\"postgres\",blk_read_time=0,idle_in_transaction_time=0,temp_bytes=0i,tup_inserted=3i,tup_updated=0i,blks_read=299i,datid=5i,session_time=469056.613,sessions_killed=0i,tup_fetched=5550i 1672399790000000000\npostgresql,db=template1,host=oss_cluster_host,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres active_time=0,idle_in_transaction_time=0,blks_read=1352i,sessions_abandoned=0i,tup_fetched=28544i,session_time=0,sessions_killed=0i,temp_bytes=0i,tup_returned=188541i,xact_commit=1168i,blk_read_time=0,sessions_fatal=0i,datid=1i,datname=\"template1\",conflicts=0i,xact_rollback=0i,numbackends=0i,deadlocks=0i,sessions=0i,tup_inserted=17520i,temp_files=0i,tup_updated=743i,blk_write_time=0,blks_hit=99487i,tup_deleted=34i 1672399790000000000\npostgresql,db=template0,host=oss_cluster_host,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres sessions=0i,datid=4i,tup_updated=0i,sessions_abandoned=0i,blk_write_time=0,numbackends=0i,blks_read=0i,blks_hit=0i,sessions_fatal=0i,temp_files=0i,deadlocks=0i,conflicts=0i,xact_commit=0i,xact_rollback=0i,session_time=0,datname=\"template0\",tup_returned=0i,tup_inserted=0i,idle_in_transaction_time=0,tup_fetched=0i,active_time=0,temp_bytes=0i,tup_deleted=0i,blk_read_time=0,sessions_killed=0i 1672399790000000000\npostgresql,db=postgres,host=oss_cluster_host,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres buffers_clean=0i,buffers_alloc=426i,checkpoints_req=1i,buffers_checkpoint=50i,buffers_backend_fsync=0i,checkpoint_write_time=5053,checkpoints_timed=26i,checkpoint_sync_time=26,maxwritten_clean=0i,buffers_backend=9i 1672399790000000000\n```\n"
  },
  {
    "path": "plugins/inputs/postgresql/postgresql.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage postgresql\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar ignoredColumns = map[string]bool{\"stats_reset\": true}\n\ntype Postgresql struct {\n\tDatabases          []string `toml:\"databases\"`\n\tIgnoredDatabases   []string `toml:\"ignored_databases\"`\n\tPreparedStatements bool     `toml:\"prepared_statements\"`\n\tpostgresql.Config\n\n\tservice *postgresql.Service\n}\n\nfunc (*Postgresql) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Postgresql) Init() error {\n\tp.IsPgBouncer = !p.PreparedStatements\n\n\tservice, err := p.Config.CreateService()\n\tif err != nil {\n\t\treturn err\n\t}\n\tp.service = service\n\n\treturn nil\n}\n\nfunc (p *Postgresql) Start(_ telegraf.Accumulator) error {\n\treturn p.service.Start()\n}\n\nfunc (p *Postgresql) Gather(acc telegraf.Accumulator) error {\n\tvar query string\n\tif len(p.Databases) == 0 && len(p.IgnoredDatabases) == 0 {\n\t\tquery = `SELECT * FROM pg_stat_database`\n\t} else if len(p.IgnoredDatabases) != 0 {\n\t\tquery = fmt.Sprintf(`SELECT * FROM pg_stat_database WHERE datname NOT IN ('%s')`,\n\t\t\tstrings.Join(p.IgnoredDatabases, \"','\"))\n\t} else {\n\t\tquery = fmt.Sprintf(`SELECT * FROM pg_stat_database WHERE datname IN ('%s')`,\n\t\t\tstrings.Join(p.Databases, \"','\"))\n\t}\n\n\trows, err := p.service.DB.Query(query)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor rows.Next() {\n\t\terr = p.accRow(rows, acc, columns)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tquery = `SELECT * FROM pg_stat_bgwriter`\n\n\tbgWriterRow, err := p.service.DB.Query(query)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer bgWriterRow.Close()\n\n\t// grab the column information from the result\n\tif columns, err = bgWriterRow.Columns(); err != nil {\n\t\treturn err\n\t}\n\n\tfor bgWriterRow.Next() {\n\t\tif err := p.accRow(bgWriterRow, acc, columns); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn bgWriterRow.Err()\n}\n\nfunc (p *Postgresql) Stop() {\n\tp.service.Stop()\n}\n\nfunc (p *Postgresql) accRow(row *sql.Rows, acc telegraf.Accumulator, columns []string) error {\n\tvar dbname bytes.Buffer\n\n\t// this is where we'll store the column name with its *interface{}\n\tcolumnMap := make(map[string]*interface{})\n\n\tfor _, column := range columns {\n\t\tcolumnMap[column] = new(interface{})\n\t}\n\n\tcolumnVars := make([]interface{}, 0, len(columnMap))\n\t// populate the array of interface{} with the pointers in the right order\n\tfor i := 0; i < len(columnMap); i++ {\n\t\tcolumnVars = append(columnVars, columnMap[columns[i]])\n\t}\n\n\t// deconstruct array of variables and send to Scan\n\tif err := row.Scan(columnVars...); err != nil {\n\t\treturn err\n\t}\n\tif columnMap[\"datname\"] != nil {\n\t\t// extract the database name from the column map\n\t\tif dbNameStr, ok := (*columnMap[\"datname\"]).(string); ok {\n\t\t\tdbname.WriteString(dbNameStr)\n\t\t} else {\n\t\t\t// PG 12 adds tracking of global objects to pg_stat_database\n\t\t\tdbname.WriteString(\"postgres_global\")\n\t\t}\n\t} else {\n\t\tdbname.WriteString(p.service.ConnectionDatabase)\n\t}\n\n\ttagAddress := p.service.SanitizedAddress\n\ttags := map[string]string{\"server\": tagAddress, \"db\": dbname.String()}\n\n\tfields := make(map[string]interface{})\n\tfor col, val := range columnMap {\n\t\t_, ignore := ignoredColumns[col]\n\t\tif !ignore {\n\t\t\tfields[col] = *val\n\t\t}\n\t}\n\tacc.AddFields(\"postgresql\", fields, tags)\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"postgresql\", func() telegraf.Input {\n\t\treturn &Postgresql{\n\t\t\tConfig: postgresql.Config{\n\t\t\t\tMaxIdle: 1,\n\t\t\t\tMaxOpen: 1,\n\t\t\t},\n\t\t\tPreparedStatements: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/postgresql/postgresql_test.go",
    "content": "package postgresql\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst servicePort = \"5432\"\n\nfunc launchTestContainer(t *testing.T) *testutil.Container {\n\tcontainer := testutil.Container{\n\t\tImage:        \"postgres:alpine\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\t// the database comes up twice, once right away, then again a second\n\t\t\t// time after the docker entrypoint starts configuration\n\t\t\twait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\n\treturn &container\n}\n\nfunc TestPostgresqlGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:     config.NewSecret([]byte(addr)),\n\t\t\tIsPgBouncer: false,\n\t\t},\n\t\tDatabases: []string{\"postgres\"},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tintMetrics := []string{\n\t\t\"xact_commit\",\n\t\t\"xact_rollback\",\n\t\t\"blks_read\",\n\t\t\"blks_hit\",\n\t\t\"tup_returned\",\n\t\t\"tup_fetched\",\n\t\t\"tup_inserted\",\n\t\t\"tup_updated\",\n\t\t\"tup_deleted\",\n\t\t\"conflicts\",\n\t\t\"temp_files\",\n\t\t\"temp_bytes\",\n\t\t\"deadlocks\",\n\t\t\"buffers_alloc\",\n\t\t\"buffers_clean\",\n\t\t\"maxwritten_clean\",\n\t\t\"datid\",\n\t\t\"numbackends\",\n\t\t\"sessions\",\n\t\t\"sessions_killed\",\n\t\t\"sessions_fatal\",\n\t\t\"sessions_abandoned\",\n\t}\n\n\tvar int32Metrics []string\n\n\tfloatMetrics := []string{\n\t\t\"blk_read_time\",\n\t\t\"blk_write_time\",\n\t\t\"active_time\",\n\t\t\"idle_in_transaction_time\",\n\t\t\"session_time\",\n\t}\n\n\tstringMetrics := []string{\n\t\t\"datname\",\n\t}\n\n\tmetricsCounted := 0\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"postgresql\", metric), \"%q not found in int metrics\", metric)\n\t\tmetricsCounted++\n\t}\n\n\t//nolint:gosec // G602: False positive — this is a safe range iteration over a slice (it may be empty)\n\tfor _, metric := range int32Metrics {\n\t\trequire.True(t, acc.HasInt32Field(\"postgresql\", metric), \"%q not found in int32 metrics\", metric)\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range floatMetrics {\n\t\trequire.True(t, acc.HasFloatField(\"postgresql\", metric), \"%q not found in float metrics\", metric)\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range stringMetrics {\n\t\trequire.True(t, acc.HasStringField(\"postgresql\", metric), \"%q not found in string metrics\", metric)\n\t\tmetricsCounted++\n\t}\n\n\trequire.Positive(t, metricsCounted)\n\trequire.Equal(t, len(floatMetrics)+len(intMetrics)+len(int32Metrics)+len(stringMetrics), metricsCounted)\n}\n\nfunc TestPostgresqlTagsMetricsWithDatabaseNameIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t\tDatabases: []string{\"postgres\"},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tpoint, ok := acc.Get(\"postgresql\")\n\trequire.True(t, ok)\n\n\trequire.Equal(t, \"postgres\", point.Tags[\"db\"])\n}\n\nfunc TestPostgresqlDefaultsToAllDatabasesIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tvar found bool\n\n\tfor _, pnt := range acc.Metrics {\n\t\tif pnt.Measurement == \"postgresql\" {\n\t\t\tif pnt.Tags[\"db\"] == \"postgres\" {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.True(t, found)\n}\n\nfunc TestPostgresqlIgnoresUnwantedColumnsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tfor col := range ignoredColumns {\n\t\trequire.False(t, acc.HasMeasurement(col))\n\t}\n}\n\nfunc TestPostgresqlDatabaseWhitelistTestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t\tDatabases: []string{\"template0\"},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tvar foundTemplate0 = false\n\tvar foundTemplate1 = false\n\n\tfor _, pnt := range acc.Metrics {\n\t\tif pnt.Measurement == \"postgresql\" {\n\t\t\tif pnt.Tags[\"db\"] == \"template0\" {\n\t\t\t\tfoundTemplate0 = true\n\t\t\t}\n\t\t}\n\t\tif pnt.Measurement == \"postgresql\" {\n\t\t\tif pnt.Tags[\"db\"] == \"template1\" {\n\t\t\t\tfoundTemplate1 = true\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.True(t, foundTemplate0)\n\trequire.False(t, foundTemplate1)\n}\n\nfunc TestPostgresqlDatabaseBlacklistTestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tcontainer := launchTestContainer(t)\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t\tIgnoredDatabases: []string{\"template0\"},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, p.Gather(&acc))\n\n\tvar foundTemplate0 = false\n\tvar foundTemplate1 = false\n\n\tfor _, pnt := range acc.Metrics {\n\t\tif pnt.Measurement == \"postgresql\" {\n\t\t\tif pnt.Tags[\"db\"] == \"template0\" {\n\t\t\t\tfoundTemplate0 = true\n\t\t\t}\n\t\t}\n\t\tif pnt.Measurement == \"postgresql\" {\n\t\t\tif pnt.Tags[\"db\"] == \"template1\" {\n\t\t\t\tfoundTemplate1 = true\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.False(t, foundTemplate0)\n\trequire.True(t, foundTemplate1)\n}\n\nfunc TestInitialConnectivityIssueIntegration(t *testing.T) {\n\t// Test case for https://github.com/influxdata/telegraf/issues/8586\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Startup the container\n\tcontainer := testutil.Container{\n\t\tImage:        \"postgres:alpine\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\t// the database comes up twice, once right away, then again a second\n\t\t\t// time after the docker entrypoint starts configuration\n\t\t\twait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Pause the container to simulate connectivity issues\n\trequire.NoError(t, container.Pause())\n\n\t// Setup and start the plugin. This should work as the SQL framework will\n\t// not connect immediately but on the first query/access to the server\n\taddr := fmt.Sprintf(\"host=%s port=%s user=postgres sslmode=disable connect_timeout=1\", container.Address, container.Ports[servicePort])\n\tplugin := &Postgresql{\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t\tIgnoredDatabases: []string{\"template0\"},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\t// Startup the plugin\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// This should fail because we cannot connect\n\trequire.ErrorContains(t, acc.GatherError(plugin.Gather), \"failed to connect\")\n\n\t// Unpause the container, now gather should succeed\n\trequire.NoError(t, container.Resume())\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\trequire.NotEmpty(t, acc.GetTelegrafMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/postgresql/sample.conf",
    "content": "# Read metrics from one or many postgresql servers\n[[inputs.postgresql]]\n  ## Specify address via a url matching:\n  ##   postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full]&statement_timeout=...\n  ## or a simple string:\n  ##   host=localhost user=pqgotest password=... sslmode=... dbname=app_production\n  ## Users can pass the path to the socket as the host value to use a socket\n  ## connection (e.g. `/var/run/postgresql`).\n  ##\n  ## All connection parameters are optional.\n  ##\n  ## Without the dbname parameter, the driver will default to a database\n  ## with the same name as the user. This dbname is just for instantiating a\n  ## connection with the server and doesn't restrict the databases we are trying\n  ## to grab metrics for.\n  ##\n  address = \"host=localhost user=postgres sslmode=disable\"\n\n  ## A custom name for the database that will be used as the \"server\" tag in the\n  ## measurement output. If not specified, a default one generated from\n  ## the connection address is used.\n  # outputaddress = \"db01\"\n\n  ## connection configuration.\n  ## maxlifetime - specify the maximum lifetime of a connection.\n  ## default is forever (0s)\n  ##\n  ## Note that this does not interrupt queries, the lifetime will not be enforced\n  ## whilst a query is running\n  # max_lifetime = \"0s\"\n\n  ## A  list of databases to explicitly ignore.  If not specified, metrics for all\n  ## databases are gathered.  Do NOT use with the 'databases' option.\n  # ignored_databases = [\"postgres\", \"template0\", \"template1\"]\n\n  ## A list of databases to pull metrics about. If not specified, metrics for all\n  ## databases are gathered.  Do NOT use with the 'ignored_databases' option.\n  # databases = [\"app_production\", \"testing\"]\n\n  ## Whether to use prepared statements when connecting to the database.\n  ## This should be set to false when connecting through a PgBouncer instance\n  ## with pool_mode set to transaction.\n  prepared_statements = true\n"
  },
  {
    "path": "plugins/inputs/postgresql_extensible/README.md",
    "content": "# PostgreSQL Extensible Input Plugin\n\nThis plugin queries a [PostgreSQL][postgres] server and provides metrics for\nthe returned result. This is useful when using PostgreSQL extensions to collect\nadditional metrics.\n\n> [!TIP]\n> Please also check the more generic [sql input plugin][inputs_sql].\n\n⭐ Telegraf v0.12.0\n🏷️ datastore\n💻 all\n\n[postgres]: https://www.postgresql.org/\n[inputs_sql]: /plugins/inputs/sql/README.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `address` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many postgresql servers\n[[inputs.postgresql_extensible]]\n  # specify address via a url matching:\n  # postgres://[pqgotest[:password]]@host:port[/dbname]?sslmode=...&statement_timeout=...\n  # or a simple string:\n  #   host=localhost port=5432 user=pqgotest password=... sslmode=... dbname=app_production\n  #\n  # All connection parameters are optional.\n  # Without the dbname parameter, the driver will default to a database\n  # with the same name as the user. This dbname is just for instantiating a\n  # connection with the server and doesn't restrict the databases we are trying\n  # to grab metrics for.\n  #\n  address = \"host=localhost user=postgres sslmode=disable\"\n\n  ## Whether to use prepared statements when connecting to the database.\n  ## This should be set to false when connecting through a PgBouncer instance\n  ## with pool_mode set to transaction.\n  prepared_statements = true\n\n  # Define the toml config where the sql queries are stored\n  # The script option can be used to specify the .sql file path.\n  # If script and sqlquery options specified at same time, sqlquery will be used\n  #\n  # the measurement field defines measurement name for metrics produced\n  # by the query. Default is \"postgresql\".\n  #\n  # the tagvalue field is used to define custom tags (separated by comas).\n  # the query is expected to return columns which match the names of the\n  # defined tags. The values in these columns must be of a string-type,\n  # a number-type or a blob-type.\n  #\n  # The timestamp field is used to override the data points timestamp value. By\n  # default, all rows inserted with current time. By setting a timestamp column,\n  # the row will be inserted with that column's value.\n  #\n  # The min_version field specifies minimal database version this query\n  # will run on.\n  #\n  # The max_version field when set specifies maximal database version\n  # this query will NOT run on.\n  #\n  # Database version in `minversion` and `maxversion` is represented as\n  # a single integer without last component, for example:\n  # 9.6.2 -> 906\n  # 15.2 -> 1500\n  #\n  # Structure :\n  # [[inputs.postgresql_extensible.query]]\n  #   measurement string\n  #   sqlquery string\n  #   min_version int\n  #   max_version int\n  #   withdbname boolean\n  #   tagvalue string (coma separated)\n  #   timestamp string\n  [[inputs.postgresql_extensible.query]]\n    measurement=\"pg_stat_database\"\n    sqlquery=\"SELECT * FROM pg_stat_database WHERE datname\"\n    min_version=901\n    tagvalue=\"\"\n  [[inputs.postgresql_extensible.query]]\n    script=\"your_sql-filepath.sql\"\n    min_version=901\n    max_version=1300\n    tagvalue=\"\"\n```\n\nThe system can be easily extended using homemade metrics collection tools or\nusing the postgresql extensions [pg_stat_statements][pg_stat_statements],\n[pg_proctab][pg_proctab] or [powa][powa].\n\n[pg_stat_statements]: http://www.postgresql.org/docs/current/static/pgstatstatements.html\n[pg_proctab]: https://github.com/markwkm/pg_proctab\n[powa]: http://dalibo.github.io/powa/\n\n### Sample Queries\n\n* telegraf.conf postgresql_extensible queries (assuming that you have configured\n correctly your connection)\n\n```toml\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"SELECT * FROM pg_stat_database\"\n  version=901\n  withdbname=false\n  tagvalue=\"\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"SELECT * FROM pg_stat_bgwriter\"\n  version=901\n  withdbname=false\n  tagvalue=\"\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"select * from sessions\"\n  version=901\n  withdbname=false\n  tagvalue=\"db,username,state\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"select setting as max_connections from pg_settings where \\\n  name='max_connections'\"\n  version=801\n  withdbname=false\n  tagvalue=\"\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"select * from pg_stat_kcache\"\n  version=901\n  withdbname=false\n  tagvalue=\"\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"select setting as shared_buffers from pg_settings where \\\n  name='shared_buffers'\"\n  version=801\n  withdbname=false\n  tagvalue=\"\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"SELECT db, count( distinct blocking_pid ) AS num_blocking_sessions,\\\n  count( distinct blocked_pid) AS num_blocked_sessions FROM \\\n  public.blocking_procs group by db\"\n  version=901\n  withdbname=false\n  tagvalue=\"db\"\n[[inputs.postgresql_extensible.query]]\n  sqlquery=\"\"\"\n    SELECT type, (enabled || '') AS enabled, COUNT(*)\n      FROM application_users\n      GROUP BY type, enabled\n  \"\"\"\n  version=901\n  withdbname=false\n  tagvalue=\"type,enabled\"\n```\n\n### Postgresql Side\n\npostgresql.conf :\n\n```sql\nshared_preload_libraries = 'pg_stat_statements,pg_stat_kcache'\n```\n\nPlease follow the requirements to setup those extensions.\n\nIn the database (can be a specific monitoring db)\n\n```sql\ncreate extension pg_stat_statements;\ncreate extension pg_stat_kcache;\ncreate extension pg_proctab;\n```\n\n(assuming that the extension is installed on the OS Layer)\n\n* pg_stat_kcache is available on the postgresql.org yum repo\n* pg_proctab is available at : <https://github.com/markwkm/pg_proctab>\n\n### Views\n\n* Blocking sessions\n\n```sql\nCREATE OR REPLACE VIEW public.blocking_procs AS\n SELECT a.datname AS db,\n    kl.pid AS blocking_pid,\n    ka.usename AS blocking_user,\n    ka.query AS blocking_query,\n    bl.pid AS blocked_pid,\n    a.usename AS blocked_user,\n    a.query AS blocked_query,\n    to_char(age(now(), a.query_start), 'HH24h:MIm:SSs'::text) AS age\n   FROM pg_locks bl\n     JOIN pg_stat_activity a ON bl.pid = a.pid\n     JOIN pg_locks kl ON bl.locktype = kl.locktype AND NOT bl.database IS\n     DISTINCT FROM kl.database AND NOT bl.relation IS DISTINCT FROM kl.relation\n     AND NOT bl.page IS DISTINCT FROM kl.page AND NOT bl.tuple IS DISTINCT FROM\n     kl.tuple AND NOT bl.virtualxid IS DISTINCT FROM kl.virtualxid AND NOT\n     bl.transactionid IS DISTINCT FROM kl.transactionid AND NOT bl.classid IS\n     DISTINCT FROM kl.classid AND NOT bl.objid IS DISTINCT FROM kl.objid AND\n      NOT bl.objsubid IS DISTINCT FROM kl.objsubid AND bl.pid <> kl.pid\n     JOIN pg_stat_activity ka ON kl.pid = ka.pid\n  WHERE kl.granted AND NOT bl.granted\n  ORDER BY a.query_start;\n```\n\n* Sessions Statistics\n\n```sql\nCREATE OR REPLACE VIEW public.sessions AS\n WITH proctab AS (\n         SELECT pg_proctab.pid,\n                CASE\n                    WHEN pg_proctab.state::text = 'R'::bpchar::text\n                      THEN 'running'::text\n                    WHEN pg_proctab.state::text = 'D'::bpchar::text\n                      THEN 'sleep-io'::text\n                    WHEN pg_proctab.state::text = 'S'::bpchar::text\n                      THEN 'sleep-waiting'::text\n                    WHEN pg_proctab.state::text = 'Z'::bpchar::text\n                      THEN 'zombie'::text\n                    WHEN pg_proctab.state::text = 'T'::bpchar::text\n                      THEN 'stopped'::text\n                    ELSE NULL::text\n                END AS proc_state,\n            pg_proctab.ppid,\n            pg_proctab.utime,\n            pg_proctab.stime,\n            pg_proctab.vsize,\n            pg_proctab.rss,\n            pg_proctab.processor,\n            pg_proctab.rchar,\n            pg_proctab.wchar,\n            pg_proctab.syscr,\n            pg_proctab.syscw,\n            pg_proctab.reads,\n            pg_proctab.writes,\n            pg_proctab.cwrites\n           FROM pg_proctab() pg_proctab(pid, comm, fullcomm, state, ppid, pgrp,\n             session, tty_nr, tpgid, flags, minflt, cminflt, majflt, cmajflt,\n             utime, stime, cutime, cstime, priority, nice, num_threads,\n             itrealvalue, starttime, vsize, rss, exit_signal, processor,\n             rt_priority, policy, delayacct_blkio_ticks, uid, username, rchar,\n             wchar, syscr, syscw, reads, writes, cwrites)\n        ), stat_activity AS (\n         SELECT pg_stat_activity.datname,\n            pg_stat_activity.pid,\n            pg_stat_activity.usename,\n                CASE\n                    WHEN pg_stat_activity.query IS NULL THEN 'no query'::text\n                    WHEN pg_stat_activity.query IS NOT NULL AND\n                    pg_stat_activity.state = 'idle'::text THEN 'no query'::text\n                    ELSE regexp_replace(pg_stat_activity.query, '[\\n\\r]+'::text,\n                       ' '::text, 'g'::text)\n                END AS query\n           FROM pg_stat_activity\n        )\n SELECT stat.datname::name AS db,\n    stat.usename::name AS username,\n    stat.pid,\n    proc.proc_state::text AS state,\n('\"'::text || stat.query) || '\"'::text AS query,\n    (proc.utime/1000)::bigint AS session_usertime,\n    (proc.stime/1000)::bigint AS session_systemtime,\n    proc.vsize AS session_virtual_memory_size,\n    proc.rss AS session_resident_memory_size,\n    proc.processor AS session_processor_number,\n    proc.rchar AS session_bytes_read,\n    proc.rchar-proc.reads AS session_logical_bytes_read,\n    proc.wchar AS session_bytes_written,\n    proc.wchar-proc.writes AS session_logical_bytes_writes,\n    proc.syscr AS session_read_io,\n    proc.syscw AS session_write_io,\n    proc.reads AS session_physical_reads,\n    proc.writes AS session_physical_writes,\n    proc.cwrites AS session_cancel_writes\n   FROM proctab proc,\n    stat_activity stat\n  WHERE proc.pid = stat.pid;\n```\n\n## Example Output\n\nThe example out below was taken by running the query\n\n```sql\nselect count(*)*100 / (select cast(nullif(setting, '') AS integer) from pg_settings where name='max_connections') as percentage_of_used_cons from pg_stat_activity\n```\n\nWhich generates the following\n\n```text\npostgresql,db=postgres,server=dbname\\=postgres\\ host\\=localhost\\ port\\=5432\\ statement_timeout\\=10000\\ user\\=postgres percentage_of_used_cons=6i 1672400531000000000\n```\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the configured query.\n\nBy default, the following format will be used\n\n* postgresql\n  * tags:\n    * db\n    * server\n"
  },
  {
    "path": "plugins/inputs/postgresql_extensible/postgresql_extensible.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage postgresql_extensible\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t// Required for SQL framework driver\n\t_ \"github.com/jackc/pgx/v4/stdlib\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar ignoredColumns = map[string]bool{\"stats_reset\": true}\n\ntype Postgresql struct {\n\tDatabases          []string        `deprecated:\"1.22.4;use the sqlquery option to specify database to use\"`\n\tQuery              []query         `toml:\"query\"`\n\tPreparedStatements bool            `toml:\"prepared_statements\"`\n\tLog                telegraf.Logger `toml:\"-\"`\n\tpostgresql.Config\n\n\tservice *postgresql.Service\n}\n\ntype query struct {\n\tSqlquery    string `toml:\"sqlquery\"`\n\tScript      string `toml:\"script\"`\n\tVersion     int    `deprecated:\"1.28.0;use minVersion to specify minimal DB version this query supports\"`\n\tMinVersion  int    `toml:\"min_version\"`\n\tMaxVersion  int    `toml:\"max_version\"`\n\tWithdbname  bool   `deprecated:\"1.22.4;use the sqlquery option to specify database to use\"`\n\tTagvalue    string `toml:\"tagvalue\"`\n\tMeasurement string `toml:\"measurement\"`\n\tTimestamp   string `toml:\"timestamp\"`\n\n\tadditionalTags map[string]bool\n}\n\ntype scanner interface {\n\tScan(dest ...interface{}) error\n}\n\nfunc (*Postgresql) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Postgresql) Init() error {\n\t// Set defaults for the queries\n\tfor i, q := range p.Query {\n\t\tif q.Sqlquery == \"\" {\n\t\t\tquery, err := os.ReadFile(q.Script)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tq.Sqlquery = string(query)\n\t\t}\n\t\tif q.MinVersion == 0 {\n\t\t\tq.MinVersion = q.Version\n\t\t}\n\t\tif q.Measurement == \"\" {\n\t\t\tq.Measurement = \"postgresql\"\n\t\t}\n\n\t\tvar queryAddon string\n\t\tif q.Withdbname {\n\t\t\tif len(p.Databases) != 0 {\n\t\t\t\tqueryAddon = fmt.Sprintf(` IN ('%s')`, strings.Join(p.Databases, \"','\"))\n\t\t\t} else {\n\t\t\t\tqueryAddon = \" is not null\"\n\t\t\t}\n\t\t}\n\t\tq.Sqlquery += queryAddon\n\n\t\tq.additionalTags = make(map[string]bool)\n\t\tif q.Tagvalue != \"\" {\n\t\t\tfor _, tag := range strings.Split(q.Tagvalue, \",\") {\n\t\t\t\tq.additionalTags[tag] = true\n\t\t\t}\n\t\t}\n\t\tp.Query[i] = q\n\t}\n\tp.Config.IsPgBouncer = !p.PreparedStatements\n\n\t// Create a service to access the PostgreSQL server\n\tservice, err := p.Config.CreateService()\n\tif err != nil {\n\t\treturn err\n\t}\n\tp.service = service\n\n\treturn nil\n}\n\nfunc (p *Postgresql) Start(_ telegraf.Accumulator) error {\n\treturn p.service.Start()\n}\n\nfunc (p *Postgresql) Gather(acc telegraf.Accumulator) error {\n\t// Retrieving the database version\n\tquery := `SELECT setting::integer / 100 AS version FROM pg_settings WHERE name = 'server_version_num'`\n\tvar dbVersion int\n\tif err := p.service.DB.QueryRow(query).Scan(&dbVersion); err != nil {\n\t\tdbVersion = 0\n\t}\n\n\t// set default timestamp to Now and use for all generated metrics during\n\t// the same Gather call\n\ttimestamp := time.Now()\n\n\t// We loop in order to process each query\n\t// Query is not run if Database version does not match the query version.\n\tfor _, q := range p.Query {\n\t\tif q.MinVersion <= dbVersion && (q.MaxVersion == 0 || q.MaxVersion > dbVersion) {\n\t\t\tacc.AddError(p.gatherMetricsFromQuery(acc, q, timestamp))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (p *Postgresql) Stop() {\n\tp.service.Stop()\n}\n\nfunc (p *Postgresql) gatherMetricsFromQuery(acc telegraf.Accumulator, q query, timestamp time.Time) error {\n\trows, err := p.service.DB.Query(q.Sqlquery)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rows.Close()\n\n\t// grab the column information from the result\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor rows.Next() {\n\t\tif err := p.accRow(acc, rows, columns, q, timestamp); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (p *Postgresql) accRow(acc telegraf.Accumulator, row scanner, columns []string, q query, timestamp time.Time) error {\n\t// this is where we'll store the column name with its *interface{}\n\tcolumnMap := make(map[string]*interface{})\n\n\tfor _, column := range columns {\n\t\tcolumnMap[column] = new(interface{})\n\t}\n\n\tcolumnVars := make([]interface{}, 0, len(columnMap))\n\t// populate the array of interface{} with the pointers in the right order\n\tfor i := 0; i < len(columnMap); i++ {\n\t\tcolumnVars = append(columnVars, columnMap[columns[i]])\n\t}\n\n\t// deconstruct array of variables and send to Scan\n\tif err := row.Scan(columnVars...); err != nil {\n\t\treturn err\n\t}\n\n\tvar dbname bytes.Buffer\n\tif c, ok := columnMap[\"datname\"]; ok && *c != nil {\n\t\t// extract the database name from the column map\n\t\tswitch datname := (*c).(type) {\n\t\tcase string:\n\t\t\tdbname.WriteString(datname)\n\t\tdefault:\n\t\t\tdbname.WriteString(p.service.ConnectionDatabase)\n\t\t}\n\t} else {\n\t\tdbname.WriteString(p.service.ConnectionDatabase)\n\t}\n\n\t// Process the additional tags\n\ttags := map[string]string{\n\t\t\"server\": p.service.SanitizedAddress,\n\t\t\"db\":     dbname.String(),\n\t}\n\n\tfields := make(map[string]interface{})\n\tfor col, val := range columnMap {\n\t\tp.Log.Debugf(\"Column: %s = %T: %v\\n\", col, *val, *val)\n\t\t_, ignore := ignoredColumns[col]\n\t\tif ignore || *val == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif col == q.Timestamp {\n\t\t\tif v, ok := (*val).(time.Time); ok {\n\t\t\t\ttimestamp = v\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif q.additionalTags[col] {\n\t\t\tv, err := internal.ToString(*val)\n\t\t\tif err != nil {\n\t\t\t\tp.Log.Debugf(\"Failed to add %q as additional tag: %v\", col, err)\n\t\t\t} else {\n\t\t\t\ttags[col] = v\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif v, ok := (*val).([]byte); ok {\n\t\t\tfields[col] = string(v)\n\t\t} else {\n\t\t\tfields[col] = *val\n\t\t}\n\t}\n\tacc.AddFields(q.Measurement, fields, tags, timestamp)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"postgresql_extensible\", func() telegraf.Input {\n\t\treturn &Postgresql{\n\t\t\tConfig: postgresql.Config{\n\t\t\t\tMaxIdle: 1,\n\t\t\t\tMaxOpen: 1,\n\t\t\t},\n\t\t\tPreparedStatements: true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/postgresql_extensible/postgresql_extensible_test.go",
    "content": "package postgresql_extensible\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/postgresql\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc queryRunner(t *testing.T, q []query) *testutil.Accumulator {\n\tservicePort := \"5432\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"postgres:alpine\",\n\t\tExposedPorts: []string{servicePort},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_HOST_AUTH_METHOD\": \"trust\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t),\n\t}\n\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s port=%s user=postgres sslmode=disable\",\n\t\tcontainer.Address,\n\t\tcontainer.Ports[servicePort],\n\t)\n\n\tp := &Postgresql{\n\t\tLog: testutil.Logger{},\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:     config.NewSecret([]byte(addr)),\n\t\t\tIsPgBouncer: false,\n\t\t},\n\t\tDatabases: []string{\"postgres\"},\n\t\tQuery:     q,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\treturn &acc\n}\n\nfunc TestPostgresqlGeneratesMetricsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tacc := queryRunner(t, []query{{\n\t\tSqlquery:   \"select * from pg_stat_database\",\n\t\tMinVersion: 901,\n\t\tWithdbname: false,\n\t\tTagvalue:   \"\",\n\t}})\n\ttestutil.PrintMetrics(acc.GetTelegrafMetrics())\n\n\tintMetrics := []string{\n\t\t\"xact_commit\",\n\t\t\"xact_rollback\",\n\t\t\"blks_read\",\n\t\t\"blks_hit\",\n\t\t\"tup_returned\",\n\t\t\"tup_fetched\",\n\t\t\"tup_inserted\",\n\t\t\"tup_updated\",\n\t\t\"tup_deleted\",\n\t\t\"conflicts\",\n\t\t\"temp_files\",\n\t\t\"temp_bytes\",\n\t\t\"deadlocks\",\n\t\t\"numbackends\",\n\t\t\"datid\",\n\t}\n\n\tvar int32Metrics []string\n\n\tfloatMetrics := []string{\n\t\t\"blk_read_time\",\n\t\t\"blk_write_time\",\n\t}\n\n\tstringMetrics := []string{\n\t\t\"datname\",\n\t}\n\n\tmetricsCounted := 0\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"postgresql\", metric))\n\t\tmetricsCounted++\n\t}\n\n\t//nolint:gosec // G602: False positive — this is a safe range iteration over a slice (it may be empty)\n\tfor _, metric := range int32Metrics {\n\t\trequire.True(t, acc.HasInt32Field(\"postgresql\", metric))\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range floatMetrics {\n\t\trequire.True(t, acc.HasFloatField(\"postgresql\", metric))\n\t\tmetricsCounted++\n\t}\n\n\tfor _, metric := range stringMetrics {\n\t\trequire.True(t, acc.HasStringField(\"postgresql\", metric))\n\t\tmetricsCounted++\n\t}\n\n\trequire.Positive(t, metricsCounted)\n\trequire.Equal(t, len(floatMetrics)+len(intMetrics)+len(int32Metrics)+len(stringMetrics), metricsCounted)\n}\n\nfunc TestPostgresqlQueryOutputTestsIntegration(t *testing.T) {\n\tconst measurement = \"postgresql\"\n\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\texamples := map[string]func(*testutil.Accumulator){\n\t\t\"SELECT 10.0::float AS myvalue\": func(acc *testutil.Accumulator) {\n\t\t\tv, found := acc.FloatField(measurement, \"myvalue\")\n\t\t\trequire.True(t, found)\n\t\t\trequire.InDelta(t, 10.0, v, testutil.DefaultDelta)\n\t\t},\n\t\t\"SELECT 10.0 AS myvalue\": func(acc *testutil.Accumulator) {\n\t\t\tv, found := acc.StringField(measurement, \"myvalue\")\n\t\t\trequire.True(t, found)\n\t\t\trequire.Equal(t, \"10.0\", v)\n\t\t},\n\t\t\"SELECT 'hello world' AS myvalue\": func(acc *testutil.Accumulator) {\n\t\t\tv, found := acc.StringField(measurement, \"myvalue\")\n\t\t\trequire.True(t, found)\n\t\t\trequire.Equal(t, \"hello world\", v)\n\t\t},\n\t\t\"SELECT true AS myvalue\": func(acc *testutil.Accumulator) {\n\t\t\tv, found := acc.BoolField(measurement, \"myvalue\")\n\t\t\trequire.True(t, found)\n\t\t\trequire.True(t, v)\n\t\t},\n\t\t\"SELECT timestamp'1980-07-23' as ts, true AS myvalue\": func(acc *testutil.Accumulator) {\n\t\t\texpectedTime := time.Date(1980, 7, 23, 0, 0, 0, 0, time.UTC)\n\t\t\tv, found := acc.BoolField(measurement, \"myvalue\")\n\t\t\trequire.True(t, found)\n\t\t\trequire.True(t, v)\n\t\t\trequire.True(t, acc.HasTimestamp(measurement, expectedTime))\n\t\t},\n\t}\n\n\tfor q, assertions := range examples {\n\t\tacc := queryRunner(t, []query{{\n\t\t\tSqlquery:   q,\n\t\t\tMinVersion: 901,\n\t\t\tWithdbname: false,\n\t\t\tTagvalue:   \"\",\n\t\t\tTimestamp:  \"ts\",\n\t\t}})\n\t\tassertions(acc)\n\t}\n}\n\nfunc TestPostgresqlFieldOutputIntegration(t *testing.T) {\n\tconst measurement = \"postgresql\"\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tacc := queryRunner(t, []query{{\n\t\tSqlquery:   \"select * from pg_stat_database\",\n\t\tMinVersion: 901,\n\t\tWithdbname: false,\n\t\tTagvalue:   \"\",\n\t}})\n\n\tintMetrics := []string{\n\t\t\"xact_commit\",\n\t\t\"xact_rollback\",\n\t\t\"blks_read\",\n\t\t\"blks_hit\",\n\t\t\"tup_returned\",\n\t\t\"tup_fetched\",\n\t\t\"tup_inserted\",\n\t\t\"tup_updated\",\n\t\t\"tup_deleted\",\n\t\t\"conflicts\",\n\t\t\"temp_files\",\n\t\t\"temp_bytes\",\n\t\t\"deadlocks\",\n\t\t\"numbackends\",\n\t\t\"datid\",\n\t}\n\n\tvar int32Metrics []string\n\n\tfloatMetrics := []string{\n\t\t\"blk_read_time\",\n\t\t\"blk_write_time\",\n\t}\n\n\tstringMetrics := []string{\n\t\t\"datname\",\n\t}\n\n\tfor _, field := range intMetrics {\n\t\t_, found := acc.Int64Field(measurement, field)\n\t\trequire.Truef(t, found, \"expected %s to be an integer\", field)\n\t}\n\n\t//nolint:gosec // G602: False positive — this is a safe range iteration over a slice (it may be empty)\n\tfor _, field := range int32Metrics {\n\t\t_, found := acc.Int32Field(measurement, field)\n\t\trequire.Truef(t, found, \"expected %s to be an int32\", field)\n\t}\n\n\tfor _, field := range floatMetrics {\n\t\t_, found := acc.FloatField(measurement, field)\n\t\trequire.Truef(t, found, \"expected %s to be a float64\", field)\n\t}\n\n\tfor _, field := range stringMetrics {\n\t\t_, found := acc.StringField(measurement, field)\n\t\trequire.Truef(t, found, \"expected %s to be a str\", field)\n\t}\n}\n\nfunc TestPostgresqlSqlScript(t *testing.T) {\n\tq := []query{{\n\t\tScript:     \"testdata/test.sql\",\n\t\tMinVersion: 901,\n\t\tWithdbname: false,\n\t\tTagvalue:   \"\",\n\t}}\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s user=postgres sslmode=disable\",\n\t\ttestutil.GetLocalHost(),\n\t)\n\n\tp := &Postgresql{\n\t\tLog: testutil.Logger{},\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:     config.NewSecret([]byte(addr)),\n\t\t\tIsPgBouncer: false,\n\t\t},\n\t\tDatabases: []string{\"postgres\"},\n\t\tQuery:     q,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, acc.GatherError(p.Gather))\n}\n\nfunc TestPostgresqlIgnoresUnwantedColumnsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\taddr := fmt.Sprintf(\n\t\t\"host=%s user=postgres sslmode=disable\",\n\t\ttestutil.GetLocalHost(),\n\t)\n\n\tp := &Postgresql{\n\t\tLog: testutil.Logger{},\n\t\tConfig: postgresql.Config{\n\t\t\tAddress: config.NewSecret([]byte(addr)),\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Start(&acc))\n\tdefer p.Stop()\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\trequire.NotEmpty(t, ignoredColumns)\n\tfor col := range ignoredColumns {\n\t\trequire.False(t, acc.HasMeasurement(col))\n\t}\n}\n\nfunc TestAccRow(t *testing.T) {\n\tp := Postgresql{\n\t\tLog: testutil.Logger{},\n\t\tConfig: postgresql.Config{\n\t\t\tAddress:       config.NewSecret(nil),\n\t\t\tOutputAddress: \"server\",\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\tcolumns := []string{\"datname\", \"cat\"}\n\n\ttests := []struct {\n\t\tfields fakeRow\n\t\tdbName string\n\t\tserver string\n\t}{\n\t\t{\n\t\t\tfields: fakeRow{\n\t\t\t\tfields: []interface{}{1, \"gato\"},\n\t\t\t},\n\t\t\tdbName: \"postgres\",\n\t\t\tserver: \"server\",\n\t\t},\n\t\t{\n\t\t\tfields: fakeRow{\n\t\t\t\tfields: []interface{}{nil, \"gato\"},\n\t\t\t},\n\t\t\tdbName: \"postgres\",\n\t\t\tserver: \"server\",\n\t\t},\n\t\t{\n\t\t\tfields: fakeRow{\n\t\t\t\tfields: []interface{}{\"name\", \"gato\"},\n\t\t\t},\n\t\t\tdbName: \"name\",\n\t\t\tserver: \"server\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tq := query{Measurement: \"pgTEST\", additionalTags: make(map[string]bool)}\n\t\trequire.NoError(t, p.accRow(&acc, tt.fields, columns, q, time.Now()))\n\t\trequire.Len(t, acc.Metrics, 1)\n\t\tmetric := acc.Metrics[0]\n\t\trequire.Equal(t, tt.dbName, metric.Tags[\"db\"])\n\t\trequire.Equal(t, tt.server, metric.Tags[\"server\"])\n\t\tacc.ClearMetrics()\n\t}\n}\n\ntype fakeRow struct {\n\tfields []interface{}\n}\n\nfunc (f fakeRow) Scan(dest ...interface{}) error {\n\tif len(f.fields) != len(dest) {\n\t\treturn errors.New(\"nada matchy buddy\")\n\t}\n\n\tfor i, d := range dest {\n\t\tswitch d := d.(type) {\n\t\tcase *interface{}:\n\t\t\t*d = f.fields[i]\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"bad type %T\", d)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/postgresql_extensible/sample.conf",
    "content": "# Read metrics from one or many postgresql servers\n[[inputs.postgresql_extensible]]\n  # specify address via a url matching:\n  # postgres://[pqgotest[:password]]@host:port[/dbname]?sslmode=...&statement_timeout=...\n  # or a simple string:\n  #   host=localhost port=5432 user=pqgotest password=... sslmode=... dbname=app_production\n  #\n  # All connection parameters are optional.\n  # Without the dbname parameter, the driver will default to a database\n  # with the same name as the user. This dbname is just for instantiating a\n  # connection with the server and doesn't restrict the databases we are trying\n  # to grab metrics for.\n  #\n  address = \"host=localhost user=postgres sslmode=disable\"\n\n  ## Whether to use prepared statements when connecting to the database.\n  ## This should be set to false when connecting through a PgBouncer instance\n  ## with pool_mode set to transaction.\n  prepared_statements = true\n\n  # Define the toml config where the sql queries are stored\n  # The script option can be used to specify the .sql file path.\n  # If script and sqlquery options specified at same time, sqlquery will be used\n  #\n  # the measurement field defines measurement name for metrics produced\n  # by the query. Default is \"postgresql\".\n  #\n  # the tagvalue field is used to define custom tags (separated by comas).\n  # the query is expected to return columns which match the names of the\n  # defined tags. The values in these columns must be of a string-type,\n  # a number-type or a blob-type.\n  #\n  # The timestamp field is used to override the data points timestamp value. By\n  # default, all rows inserted with current time. By setting a timestamp column,\n  # the row will be inserted with that column's value.\n  #\n  # The min_version field specifies minimal database version this query\n  # will run on.\n  #\n  # The max_version field when set specifies maximal database version\n  # this query will NOT run on.\n  #\n  # Database version in `minversion` and `maxversion` is represented as\n  # a single integer without last component, for example:\n  # 9.6.2 -> 906\n  # 15.2 -> 1500\n  #\n  # Structure :\n  # [[inputs.postgresql_extensible.query]]\n  #   measurement string\n  #   sqlquery string\n  #   min_version int\n  #   max_version int\n  #   withdbname boolean\n  #   tagvalue string (coma separated)\n  #   timestamp string\n  [[inputs.postgresql_extensible.query]]\n    measurement=\"pg_stat_database\"\n    sqlquery=\"SELECT * FROM pg_stat_database WHERE datname\"\n    min_version=901\n    tagvalue=\"\"\n  [[inputs.postgresql_extensible.query]]\n    script=\"your_sql-filepath.sql\"\n    min_version=901\n    max_version=1300\n    tagvalue=\"\"\n"
  },
  {
    "path": "plugins/inputs/postgresql_extensible/testdata/test.sql",
    "content": "select * from pg_stat_database"
  },
  {
    "path": "plugins/inputs/powerdns/README.md",
    "content": "# PowerDNS Input Plugin\n\nThis plugin gathers metrics from [PowerDNS][powerdns] servers using unix\nsockets.\n\n> [!NOTE]\n> This plugin will need access to the powerdns control socket.\n\n⭐ Telegraf v0.10.2\n🏷️ server\n💻 all\n\n[powerdns]: https://www.powerdns.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many PowerDNS servers\n[[inputs.powerdns]]\n  # An array of sockets to gather stats about.\n  # Specify a path to unix socket.\n  #\n  # If no servers are specified, then '/var/run/pdns.controlsocket' is used as the path.\n  unix_sockets = [\"/var/run/pdns.controlsocket\"]\n```\n\n### Permissions\n\nTelegraf will need access to the powerdns control socket. On many systems this\ncan be accomplished by adding the `telegraf` user to the `pdns` group:\n\n```sh\nusermod telegraf -a -G pdns\n```\n\nAdditionally, telegraf may need additional permissions. Look at the\n`socket-mode` PowerDNS option to set permissions on the socket.\n\n## Metrics\n\n- powerdns\n  - corrupt-packets\n  - deferred-cache-inserts\n  - deferred-cache-lookup\n  - dnsupdate-answers\n  - dnsupdate-changes\n  - dnsupdate-queries\n  - dnsupdate-refused\n  - packetcache-hit\n  - packetcache-miss\n  - packetcache-size\n  - query-cache-hit\n  - query-cache-miss\n  - rd-queries\n  - recursing-answers\n  - recursing-questions\n  - recursion-unanswered\n  - security-status\n  - servfail-packets\n  - signatures\n  - tcp-answers\n  - tcp-queries\n  - timedout-packets\n  - udp-answers\n  - udp-answers-bytes\n  - udp-do-queries\n  - udp-queries\n  - udp4-answers\n  - udp4-queries\n  - udp6-answers\n  - udp6-queries\n  - key-cache-size\n  - latency\n  - meta-cache-size\n  - qsize-q\n  - signature-cache-size\n  - sys-msec\n  - uptime\n  - user-msec\n\n## Tags\n\n- tags: `server=socket`\n\n## Example Output\n\n```text\npowerdns,server=/var/run/pdns.controlsocket corrupt-packets=0i,deferred-cache-inserts=0i,deferred-cache-lookup=0i,dnsupdate-answers=0i,dnsupdate-changes=0i,dnsupdate-queries=0i,dnsupdate-refused=0i,key-cache-size=0i,latency=26i,meta-cache-size=0i,packetcache-hit=0i,packetcache-miss=1i,packetcache-size=0i,qsize-q=0i,query-cache-hit=0i,query-cache-miss=6i,rd-queries=1i,recursing-answers=0i,recursing-questions=0i,recursion-unanswered=0i,security-status=3i,servfail-packets=0i,signature-cache-size=0i,signatures=0i,sys-msec=4349i,tcp-answers=0i,tcp-queries=0i,timedout-packets=0i,udp-answers=1i,udp-answers-bytes=50i,udp-do-queries=0i,udp-queries=0i,udp4-answers=1i,udp4-queries=1i,udp6-answers=0i,udp6-queries=0i,uptime=166738i,user-msec=3036i 1454078624932715706\n```\n"
  },
  {
    "path": "plugins/inputs/powerdns/powerdns.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage powerdns\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultTimeout = 5 * time.Second\n\ntype Powerdns struct {\n\tUnixSockets []string        `toml:\"unix_sockets\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Powerdns) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Powerdns) Gather(acc telegraf.Accumulator) error {\n\tif len(p.UnixSockets) == 0 {\n\t\treturn p.gatherServer(\"/var/run/pdns.controlsocket\", acc)\n\t}\n\n\tfor _, serverSocket := range p.UnixSockets {\n\t\tif err := p.gatherServer(serverSocket, acc); err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Powerdns) gatherServer(address string, acc telegraf.Accumulator) error {\n\tconn, err := net.DialTimeout(\"unix\", address, defaultTimeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close()\n\n\tif err := conn.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\t// Read and write buffer\n\trw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))\n\n\t// Send command\n\tif _, err := fmt.Fprint(conn, \"show * \\n\"); err != nil {\n\t\treturn err\n\t}\n\tif err := rw.Flush(); err != nil {\n\t\treturn err\n\t}\n\n\t// Read data\n\tbuf := make([]byte, 0, 4096)\n\ttmp := make([]byte, 1024)\n\tfor {\n\t\tn, err := rw.Read(tmp)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, io.EOF) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t\tbuf = append(buf, tmp[:n]...)\n\t}\n\n\tmetrics := string(buf)\n\n\t// Process data\n\tfields := p.parseResponse(metrics)\n\n\t// Add server socket as a tag\n\ttags := map[string]string{\"server\": address}\n\n\tacc.AddFields(\"powerdns\", fields, tags)\n\n\treturn nil\n}\n\nfunc (p *Powerdns) parseResponse(metrics string) map[string]interface{} {\n\tvalues := make(map[string]interface{})\n\n\ts := strings.Split(metrics, \",\")\n\n\tfor _, metric := range s[:len(s)-1] {\n\t\tm := strings.Split(metric, \"=\")\n\t\tif len(m) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\ti, err := strconv.ParseInt(m[1], 10, 64)\n\t\tif err != nil {\n\t\t\tp.Log.Errorf(\"error parsing integer for metric %q: %s\", metric, err.Error())\n\t\t\tcontinue\n\t\t}\n\t\tvalues[m[0]] = i\n\t}\n\n\treturn values\n}\n\nfunc init() {\n\tinputs.Add(\"powerdns\", func() telegraf.Input {\n\t\treturn &Powerdns{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns/powerdns_linux_test.go",
    "content": "//go:build !windows\n\npackage powerdns\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc serverSocket(l net.Listener) {\n\tfor {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tgo func(c net.Conn) {\n\t\t\tbuf := make([]byte, 1024)\n\t\t\tn, _ := c.Read(buf) //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\n\t\t\tdata := buf[:n]\n\t\t\tif string(data) == \"show * \\n\" {\n\t\t\t\tc.Write([]byte(metrics)) //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\t\t\t\tc.Close()\n\t\t\t}\n\t\t}(conn)\n\t}\n}\n\nfunc TestPowerdnsGeneratesMetrics(t *testing.T) {\n\t// We create a fake server to return test data\n\trandomNumber := int64(5239846799706671610)\n\tsockname := filepath.Join(t.TempDir(), fmt.Sprintf(\"pdns%d.controlsocket\", randomNumber))\n\tsocket, err := net.Listen(\"unix\", sockname)\n\tif err != nil {\n\t\tt.Fatal(\"Cannot initialize server on port \")\n\t}\n\n\tdefer socket.Close()\n\n\tgo serverSocket(socket)\n\n\tp := &Powerdns{\n\t\tUnixSockets: []string{sockname},\n\t}\n\n\tvar acc testutil.Accumulator\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\tintMetrics := []string{\"corrupt-packets\", \"deferred-cache-inserts\",\n\t\t\"deferred-cache-lookup\", \"dnsupdate-answers\", \"dnsupdate-changes\",\n\t\t\"dnsupdate-queries\", \"dnsupdate-refused\", \"packetcache-hit\",\n\t\t\"packetcache-miss\", \"packetcache-size\", \"query-cache-hit\", \"query-cache-miss\",\n\t\t\"rd-queries\", \"recursing-answers\", \"recursing-questions\",\n\t\t\"recursion-unanswered\", \"security-status\", \"servfail-packets\", \"signatures\",\n\t\t\"tcp-answers\", \"tcp-queries\", \"timedout-packets\", \"udp-answers\",\n\t\t\"udp-answers-bytes\", \"udp-do-queries\", \"udp-queries\", \"udp4-answers\",\n\t\t\"udp4-queries\", \"udp6-answers\", \"udp6-queries\", \"key-cache-size\", \"latency\",\n\t\t\"meta-cache-size\", \"qsize-q\", \"signature-cache-size\", \"sys-msec\", \"uptime\", \"user-msec\"}\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"powerdns\", metric), metric)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns/powerdns_test.go",
    "content": "package powerdns\n\nimport (\n\t\"testing\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar metrics = \"corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,\" +\n\t\"dnsupdate-answers=0,dnsupdate-changes=0,dnsupdate-queries=0,\" +\n\t\"dnsupdate-refused=0,packetcache-hit=0,packetcache-miss=1,packetcache-size=0,\" +\n\t\"query-cache-hit=0,query-cache-miss=6,rd-queries=1,recursing-answers=0,\" +\n\t\"recursing-questions=0,recursion-unanswered=0,security-status=3,\" +\n\t\"servfail-packets=0,signatures=0,tcp-answers=0,tcp-queries=0,\" +\n\t\"timedout-packets=0,udp-answers=1,udp-answers-bytes=50,udp-do-queries=0,\" +\n\t\"udp-queries=0,udp4-answers=1,udp4-queries=1,udp6-answers=0,udp6-queries=0,\" +\n\t\"key-cache-size=0,latency=26,meta-cache-size=0,qsize-q=0,\" +\n\t\"signature-cache-size=0,sys-msec=2889,uptime=86317,user-msec=2167,\"\n\n// first metric has no \"=\"\nvar corruptMetrics = \"corrupt-packets--0,deferred-cache-inserts=0,deferred-cache-lookup=0,\" +\n\t\"dnsupdate-answers=0,dnsupdate-changes=0,dnsupdate-queries=0,\" +\n\t\"dnsupdate-refused=0,packetcache-hit=0,packetcache-miss=1,packetcache-size=0,\" +\n\t\"query-cache-hit=0,query-cache-miss=6,rd-queries=1,recursing-answers=0,\" +\n\t\"recursing-questions=0,recursion-unanswered=0,security-status=3,\" +\n\t\"servfail-packets=0,signatures=0,tcp-answers=0,tcp-queries=0,\" +\n\t\"timedout-packets=0,udp-answers=1,udp-answers-bytes=50,udp-do-queries=0,\" +\n\t\"udp-queries=0,udp4-answers=1,udp4-queries=1,udp6-answers=0,udp6-queries=0,\" +\n\t\"key-cache-size=0,latency=26,meta-cache-size=0,qsize-q=0,\" +\n\t\"signature-cache-size=0,sys-msec=2889,uptime=86317,user-msec=2167,\"\n\n// integer overflow\nvar intOverflowMetrics = \"corrupt-packets=18446744073709550195,deferred-cache-inserts=0,deferred-cache-lookup=0,\" +\n\t\"dnsupdate-answers=0,dnsupdate-changes=0,dnsupdate-queries=0,\" +\n\t\"dnsupdate-refused=0,packetcache-hit=0,packetcache-miss=1,packetcache-size=0,\" +\n\t\"query-cache-hit=0,query-cache-miss=6,rd-queries=1,recursing-answers=0,\" +\n\t\"recursing-questions=0,recursion-unanswered=0,security-status=3,\" +\n\t\"servfail-packets=0,signatures=0,tcp-answers=0,tcp-queries=0,\" +\n\t\"timedout-packets=0,udp-answers=1,udp-answers-bytes=50,udp-do-queries=0,\" +\n\t\"udp-queries=0,udp4-answers=1,udp4-queries=1,udp6-answers=0,udp6-queries=0,\" +\n\t\"key-cache-size=0,latency=26,meta-cache-size=0,qsize-q=0,\" +\n\t\"signature-cache-size=0,sys-msec=2889,uptime=86317,user-msec=2167,\"\n\nfunc TestPowerdnsParseMetrics(t *testing.T) {\n\tp := &Powerdns{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tvalues := p.parseResponse(metrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"corrupt-packets\", 0},\n\t\t{\"deferred-cache-inserts\", 0},\n\t\t{\"deferred-cache-lookup\", 0},\n\t\t{\"dnsupdate-answers\", 0},\n\t\t{\"dnsupdate-changes\", 0},\n\t\t{\"dnsupdate-queries\", 0},\n\t\t{\"dnsupdate-refused\", 0},\n\t\t{\"packetcache-hit\", 0},\n\t\t{\"packetcache-miss\", 1},\n\t\t{\"packetcache-size\", 0},\n\t\t{\"query-cache-hit\", 0},\n\t\t{\"query-cache-miss\", 6},\n\t\t{\"rd-queries\", 1},\n\t\t{\"recursing-answers\", 0},\n\t\t{\"recursing-questions\", 0},\n\t\t{\"recursion-unanswered\", 0},\n\t\t{\"security-status\", 3},\n\t\t{\"servfail-packets\", 0},\n\t\t{\"signatures\", 0},\n\t\t{\"tcp-answers\", 0},\n\t\t{\"tcp-queries\", 0},\n\t\t{\"timedout-packets\", 0},\n\t\t{\"udp-answers\", 1},\n\t\t{\"udp-answers-bytes\", 50},\n\t\t{\"udp-do-queries\", 0},\n\t\t{\"udp-queries\", 0},\n\t\t{\"udp4-answers\", 1},\n\t\t{\"udp4-queries\", 1},\n\t\t{\"udp6-answers\", 0},\n\t\t{\"udp6-queries\", 0},\n\t\t{\"key-cache-size\", 0},\n\t\t{\"latency\", 26},\n\t\t{\"meta-cache-size\", 0},\n\t\t{\"qsize-q\", 0},\n\t\t{\"signature-cache-size\", 0},\n\t\t{\"sys-msec\", 2889},\n\t\t{\"uptime\", 86317},\n\t\t{\"user-msec\", 2167},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\tif !ok {\n\t\t\tt.Errorf(\"Did not find key for metric %s in values\", test.key)\n\t\t\tcontinue\n\t\t}\n\t\tif value != test.value {\n\t\t\tt.Errorf(\"Metric: %s, Expected: %d, actual: %d\",\n\t\t\t\ttest.key, test.value, value)\n\t\t}\n\t}\n}\n\nfunc TestPowerdnsParseCorruptMetrics(t *testing.T) {\n\tp := &Powerdns{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tvalues := p.parseResponse(corruptMetrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"deferred-cache-inserts\", 0},\n\t\t{\"deferred-cache-lookup\", 0},\n\t\t{\"dnsupdate-answers\", 0},\n\t\t{\"dnsupdate-changes\", 0},\n\t\t{\"dnsupdate-queries\", 0},\n\t\t{\"dnsupdate-refused\", 0},\n\t\t{\"packetcache-hit\", 0},\n\t\t{\"packetcache-miss\", 1},\n\t\t{\"packetcache-size\", 0},\n\t\t{\"query-cache-hit\", 0},\n\t\t{\"query-cache-miss\", 6},\n\t\t{\"rd-queries\", 1},\n\t\t{\"recursing-answers\", 0},\n\t\t{\"recursing-questions\", 0},\n\t\t{\"recursion-unanswered\", 0},\n\t\t{\"security-status\", 3},\n\t\t{\"servfail-packets\", 0},\n\t\t{\"signatures\", 0},\n\t\t{\"tcp-answers\", 0},\n\t\t{\"tcp-queries\", 0},\n\t\t{\"timedout-packets\", 0},\n\t\t{\"udp-answers\", 1},\n\t\t{\"udp-answers-bytes\", 50},\n\t\t{\"udp-do-queries\", 0},\n\t\t{\"udp-queries\", 0},\n\t\t{\"udp4-answers\", 1},\n\t\t{\"udp4-queries\", 1},\n\t\t{\"udp6-answers\", 0},\n\t\t{\"udp6-queries\", 0},\n\t\t{\"key-cache-size\", 0},\n\t\t{\"latency\", 26},\n\t\t{\"meta-cache-size\", 0},\n\t\t{\"qsize-q\", 0},\n\t\t{\"signature-cache-size\", 0},\n\t\t{\"sys-msec\", 2889},\n\t\t{\"uptime\", 86317},\n\t\t{\"user-msec\", 2167},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\tif !ok {\n\t\t\tt.Errorf(\"Did not find key for metric %s in values\", test.key)\n\t\t\tcontinue\n\t\t}\n\t\tif value != test.value {\n\t\t\tt.Errorf(\"Metric: %s, Expected: %d, actual: %d\",\n\t\t\t\ttest.key, test.value, value)\n\t\t}\n\t}\n}\n\nfunc TestPowerdnsParseIntOverflowMetrics(t *testing.T) {\n\tp := &Powerdns{\n\t\tLog: testutil.Logger{},\n\t}\n\n\tvalues := p.parseResponse(intOverflowMetrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"deferred-cache-inserts\", 0},\n\t\t{\"deferred-cache-lookup\", 0},\n\t\t{\"dnsupdate-answers\", 0},\n\t\t{\"dnsupdate-changes\", 0},\n\t\t{\"dnsupdate-queries\", 0},\n\t\t{\"dnsupdate-refused\", 0},\n\t\t{\"packetcache-hit\", 0},\n\t\t{\"packetcache-miss\", 1},\n\t\t{\"packetcache-size\", 0},\n\t\t{\"query-cache-hit\", 0},\n\t\t{\"query-cache-miss\", 6},\n\t\t{\"rd-queries\", 1},\n\t\t{\"recursing-answers\", 0},\n\t\t{\"recursing-questions\", 0},\n\t\t{\"recursion-unanswered\", 0},\n\t\t{\"security-status\", 3},\n\t\t{\"servfail-packets\", 0},\n\t\t{\"signatures\", 0},\n\t\t{\"tcp-answers\", 0},\n\t\t{\"tcp-queries\", 0},\n\t\t{\"timedout-packets\", 0},\n\t\t{\"udp-answers\", 1},\n\t\t{\"udp-answers-bytes\", 50},\n\t\t{\"udp-do-queries\", 0},\n\t\t{\"udp-queries\", 0},\n\t\t{\"udp4-answers\", 1},\n\t\t{\"udp4-queries\", 1},\n\t\t{\"udp6-answers\", 0},\n\t\t{\"udp6-queries\", 0},\n\t\t{\"key-cache-size\", 0},\n\t\t{\"latency\", 26},\n\t\t{\"meta-cache-size\", 0},\n\t\t{\"qsize-q\", 0},\n\t\t{\"signature-cache-size\", 0},\n\t\t{\"sys-msec\", 2889},\n\t\t{\"uptime\", 86317},\n\t\t{\"user-msec\", 2167},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\tif !ok {\n\t\t\tt.Errorf(\"Did not find key for metric %s in values\", test.key)\n\t\t\tcontinue\n\t\t}\n\t\tif value != test.value {\n\t\t\tt.Errorf(\"Metric: %s, Expected: %d, actual: %d\",\n\t\t\t\ttest.key, test.value, value)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns/sample.conf",
    "content": "# Read metrics from one or many PowerDNS servers\n[[inputs.powerdns]]\n  # An array of sockets to gather stats about.\n  # Specify a path to unix socket.\n  #\n  # If no servers are specified, then '/var/run/pdns.controlsocket' is used as the path.\n  unix_sockets = [\"/var/run/pdns.controlsocket\"]\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/README.md",
    "content": "# PowerDNS Recursor Input Plugin\n\nThis plugin gathers metrics from [PowerDNS Recursor][powerdns_recursor]\ninstances using the unix control-sockets.\n\n> [!NOTE]\n> Telegraf will need read and write access to the control socket and the\n> `socket_dir`.\n\n⭐ Telegraf v1.11.0\n🏷️ server\n💻 all\n\n[powerdns_recursor]: https://www.powerdns.com/powerdns-recursor\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many PowerDNS Recursor servers\n[[inputs.powerdns_recursor]]\n  ## Path to the Recursor control socket.\n  unix_sockets = [\"/var/run/pdns_recursor.controlsocket\"]\n\n  ## Directory to create receive socket.  This default is likely not writable,\n  ## please reference the full plugin documentation for a recommended setup.\n  # socket_dir = \"/var/run/\"\n  ## Socket permissions for the receive socket.\n  # socket_mode = \"0666\"\n\n  ## The version of the PowerDNS control protocol to use. You will have to\n  ## change this based on your PowerDNS Recursor version, see below:\n  ## Version 1: PowerDNS <4.5.0\n  ## Version 2: PowerDNS 4.5.0 - 4.5.11\n  ## Version 3: PowerDNS >=4.6.0\n  ## By default this is set to 1.\n  # control_protocol_version = 1\n\n```\n\n### Newer PowerDNS Recursor versions\n\nBy default, this plugin is compatible with PowerDNS Recursor versions older\nthan `4.5.0`. If you are using a newer version then you'll need to adjust the\n`control_protocol_version` configuration option based on your version. For\nversions between `4.5.0` and `4.5.11` set it to `2` and for versions `4.6.0`\nand newer set it to `3`. If you don't, you will get an `i/o timeout` or a\n`protocol wrong type for socket` error.\n\n### Permissions\n\nTelegraf will need read/write access to the control socket and to the\n`socket_dir`.  PowerDNS will need to be able to write to the `socket_dir`.\n\nThe setup described below was tested on a Debian Stretch system and may need\nadapted for other systems.\n\nFirst change permissions on the controlsocket in the PowerDNS recursor\nconfiguration, usually in `/etc/powerdns/recursor.conf`:\n\n```sh\nsocket-mode = 660\n```\n\nThen place the `telegraf` user into the `pdns` group:\n\n```sh\nusermod telegraf -a -G pdns\n```\n\nSince `telegraf` cannot write to to the default `/var/run` socket directory,\ncreate a subdirectory and adjust permissions for this directory so that both\nusers can access it.\n\n```sh\nmkdir /var/run/pdns\nchown root:pdns /var/run/pdns\nchmod 770 /var/run/pdns\n```\n\n## Metrics\n\n- powerdns_recursor\n  - tags:\n    - server\n  - fields:\n    - all-outqueries\n    - answers-slow\n    - answers0-1\n    - answers1-10\n    - answers10-100\n    - answers100-1000\n    - auth-zone-queries\n    - auth4-answers-slow\n    - auth4-answers0-1\n    - auth4-answers1-10\n    - auth4-answers10-100\n    - auth4-answers100-1000\n    - auth6-answers-slow\n    - auth6-answers0-1\n    - auth6-answers1-10\n    - auth6-answers10-100\n    - auth6-answers100-1000\n    - cache-entries\n    - cache-hits\n    - cache-misses\n    - case-mismatches\n    - chain-resends\n    - client-parse-errors\n    - concurrent-queries\n    - dlg-only-drops\n    - dnssec-queries\n    - dnssec-result-bogus\n    - dnssec-result-indeterminate\n    - dnssec-result-insecure\n    - dnssec-result-nta\n    - dnssec-result-secure\n    - dnssec-validations\n    - dont-outqueries\n    - ecs-queries\n    - ecs-responses\n    - edns-ping-matches\n    - edns-ping-mismatches\n    - failed-host-entries\n    - fd-usage\n    - ignored-packets\n    - ipv6-outqueries\n    - ipv6-questions\n    - malloc-bytes\n    - max-cache-entries\n    - max-mthread-stack\n    - max-packetcache-entries\n    - negcache-entries\n    - no-packet-error\n    - noedns-outqueries\n    - noerror-answers\n    - noping-outqueries\n    - nsset-invalidations\n    - nsspeeds-entries\n    - nxdomain-answers\n    - outgoing-timeouts\n    - outgoing4-timeouts\n    - outgoing6-timeouts\n    - over-capacity-drops\n    - packetcache-entries\n    - packetcache-hits\n    - packetcache-misses\n    - policy-drops\n    - policy-result-custom\n    - policy-result-drop\n    - policy-result-noaction\n    - policy-result-nodata\n    - policy-result-nxdomain\n    - policy-result-truncate\n    - qa-latency\n    - query-pipe-full-drops\n    - questions\n    - real-memory-usage\n    - resource-limits\n    - security-status\n    - server-parse-errors\n    - servfail-answers\n    - spoof-prevents\n    - sys-msec\n    - tcp-client-overflow\n    - tcp-clients\n    - tcp-outqueries\n    - tcp-questions\n    - throttle-entries\n    - throttled-out\n    - throttled-outqueries\n    - too-old-drops\n    - udp-in-errors\n    - udp-noport-errors\n    - udp-recvbuf-errors\n    - udp-sndbuf-errors\n    - unauthorized-tcp\n    - unauthorized-udp\n    - unexpected-packets\n    - unreachables\n    - uptime\n    - user-msec\n    - x-our-latency\n    - x-ourtime-slow\n    - x-ourtime0-1\n    - x-ourtime1-2\n    - x-ourtime16-32\n    - x-ourtime2-4\n    - x-ourtime4-8\n    - x-ourtime8-16\n\n## Example Output\n\n```text\npowerdns_recursor,server=/var/run/pdns_recursor.controlsocket all-outqueries=3631810i,answers-slow=36863i,answers0-1=179612i,answers1-10=1223305i,answers10-100=1252199i,answers100-1000=408357i,auth-zone-queries=4i,auth4-answers-slow=44758i,auth4-answers0-1=59721i,auth4-answers1-10=1766787i,auth4-answers10-100=1329638i,auth4-answers100-1000=430372i,auth6-answers-slow=0i,auth6-answers0-1=0i,auth6-answers1-10=0i,auth6-answers10-100=0i,auth6-answers100-1000=0i,cache-entries=296689i,cache-hits=150654i,cache-misses=2949682i,case-mismatches=0i,chain-resends=420004i,client-parse-errors=0i,concurrent-queries=0i,dlg-only-drops=0i,dnssec-queries=152970i,dnssec-result-bogus=0i,dnssec-result-indeterminate=0i,dnssec-result-insecure=0i,dnssec-result-nta=0i,dnssec-result-secure=47i,dnssec-validations=47i,dont-outqueries=62i,ecs-queries=0i,ecs-responses=0i,edns-ping-matches=0i,edns-ping-mismatches=0i,failed-host-entries=21i,fd-usage=32i,ignored-packets=0i,ipv6-outqueries=0i,ipv6-questions=0i,malloc-bytes=0i,max-cache-entries=1000000i,max-mthread-stack=33747i,max-packetcache-entries=500000i,negcache-entries=100019i,no-packet-error=0i,noedns-outqueries=73341i,noerror-answers=25453808i,noping-outqueries=0i,nsset-invalidations=2398i,nsspeeds-entries=3966i,nxdomain-answers=3341302i,outgoing-timeouts=44384i,outgoing4-timeouts=44384i,outgoing6-timeouts=0i,over-capacity-drops=0i,packetcache-entries=78258i,packetcache-hits=25999027i,packetcache-misses=3100179i,policy-drops=0i,policy-result-custom=0i,policy-result-drop=0i,policy-result-noaction=3100336i,policy-result-nodata=0i,policy-result-nxdomain=0i,policy-result-truncate=0i,qa-latency=6553i,query-pipe-full-drops=0i,questions=29099363i,real-memory-usage=280494080i,resource-limits=0i,security-status=1i,server-parse-errors=0i,servfail-answers=304253i,spoof-prevents=0i,sys-msec=1312600i,tcp-client-overflow=0i,tcp-clients=0i,tcp-outqueries=116i,tcp-questions=133i,throttle-entries=21i,throttled-out=13296i,throttled-outqueries=13296i,too-old-drops=2i,udp-in-errors=4i,udp-noport-errors=2918i,udp-recvbuf-errors=0i,udp-sndbuf-errors=0i,unauthorized-tcp=0i,unauthorized-udp=0i,unexpected-packets=0i,unreachables=1708i,uptime=167482i,user-msec=1282640i,x-our-latency=19i,x-ourtime-slow=642i,x-ourtime0-1=3095566i,x-ourtime1-2=3401i,x-ourtime16-32=201i,x-ourtime2-4=304i,x-ourtime4-8=198i,x-ourtime8-16=24i 1533903879000000000\n```\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/powerdns_recursor.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage powerdns_recursor\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst defaultTimeout = 5 * time.Second\n\ntype PowerdnsRecursor struct {\n\tUnixSockets            []string `toml:\"unix_sockets\"`\n\tSocketDir              string   `toml:\"socket_dir\"`\n\tSocketMode             string   `toml:\"socket_mode\"`\n\tControlProtocolVersion int      `toml:\"control_protocol_version\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tmode             uint32\n\tgatherFromServer func(address string, acc telegraf.Accumulator) error\n}\n\nfunc (*PowerdnsRecursor) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *PowerdnsRecursor) Init() error {\n\tif p.SocketMode != \"\" {\n\t\tmode, err := strconv.ParseUint(p.SocketMode, 8, 32)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not parse socket_mode: %w\", err)\n\t\t}\n\n\t\tp.mode = uint32(mode)\n\t}\n\n\tif p.SocketDir == \"\" {\n\t\tp.SocketDir = \"/var/run\"\n\t}\n\n\tswitch p.ControlProtocolVersion {\n\t// We treat 0 the same as 1 since it's the default value if a user doesn't explicitly specify one.\n\tcase 0, 1:\n\t\tp.gatherFromServer = p.gatherFromV1Server\n\tcase 2:\n\t\tp.gatherFromServer = p.gatherFromV2Server\n\tcase 3:\n\t\tp.gatherFromServer = gatherFromV3Server\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown control protocol version '%d', allowed values are 1, 2, 3\", p.ControlProtocolVersion)\n\t}\n\n\tif len(p.UnixSockets) == 0 {\n\t\tp.UnixSockets = []string{\"/var/run/pdns_recursor.controlsocket\"}\n\t}\n\n\treturn nil\n}\n\nfunc (p *PowerdnsRecursor) Gather(acc telegraf.Accumulator) error {\n\tfor _, serverSocket := range p.UnixSockets {\n\t\tif err := p.gatherFromServer(serverSocket, acc); err != nil {\n\t\t\tacc.AddError(err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"powerdns_recursor\", func() telegraf.Input {\n\t\treturn &PowerdnsRecursor{\n\t\t\tmode: uint32(0666),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/powerdns_recursor_test.go",
    "content": "package powerdns_recursor\n\nimport (\n\t\"net\"\n\t\"os\"\n\t\"runtime\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar metrics = \"all-outqueries\\t3591637\\nanswers-slow\\t36451\\nanswers0-1\\t177297\\nanswers1-10\\t1209328\\n\" +\n\t\"answers10-100\\t1238786\\nanswers100-1000\\t402917\\nauth-zone-queries\\t4\\nauth4-answers-slow\\t44248\\n\" +\n\t\"auth4-answers0-1\\t59169\\nauth4-answers1-10\\t1747403\\nauth4-answers10-100\\t1315621\\n\" +\n\t\"auth4-answers100-1000\\t424683\\nauth6-answers-slow\\t0\\nauth6-answers0-1\\t0\\nauth6-answers1-10\\t0\\n\" +\n\t\"auth6-answers10-100\\t0\\nauth6-answers100-1000\\t0\\ncache-entries\\t295917\\ncache-hits\\t148630\\n\" +\n\t\"cache-misses\\t2916149\\ncase-mismatches\\t0\\nchain-resends\\t418602\\nclient-parse-errors\\t0\\n\" +\n\t\"concurrent-queries\\t0\\ndlg-only-drops\\t0\\ndnssec-queries\\t151536\\ndnssec-result-bogus\\t0\\n\" +\n\t\"dnssec-result-indeterminate\\t0\\ndnssec-result-insecure\\t0\\ndnssec-result-nta\\t0\\n\" +\n\t\"dnssec-result-secure\\t46\\ndnssec-validations\\t46\\ndont-outqueries\\t62\\necs-queries\\t0\\n\" +\n\t\"ecs-responses\\t0\\nedns-ping-matches\\t0\\nedns-ping-mismatches\\t0\\nfailed-host-entries\\t33\\n\" +\n\t\"fd-usage\\t32\\nignored-packets\\t0\\nipv6-outqueries\\t0\\nipv6-questions\\t0\\nmalloc-bytes\\t0\\n\" +\n\t\"max-cache-entries\\t1000000\\nmax-mthread-stack\\t33747\\nmax-packetcache-entries\\t500000\\n\" +\n\t\"negcache-entries\\t100070\\nno-packet-error\\t0\\nnoedns-outqueries\\t72409\\nnoerror-answers\\t25155259\\n\" +\n\t\"noping-outqueries\\t0\\nnsset-invalidations\\t2385\\nnsspeeds-entries\\t3571\\nnxdomain-answers\\t3307768\\n\" +\n\t\"outgoing-timeouts\\t43876\\noutgoing4-timeouts\\t43876\\noutgoing6-timeouts\\t0\\nover-capacity-drops\\t0\\n\" +\n\t\"packetcache-entries\\t80756\\npacketcache-hits\\t25698497\\npacketcache-misses\\t3064625\\npolicy-drops\\t0\\n\" +\n\t\"policy-result-custom\\t0\\npolicy-result-drop\\t0\\npolicy-result-noaction\\t3064779\\npolicy-result-nodata\\t0\\n\" +\n\t\"policy-result-nxdomain\\t0\\npolicy-result-truncate\\t0\\nqa-latency\\t6587\\nquery-pipe-full-drops\\t0\\n\" +\n\t\"questions\\t28763276\\nreal-memory-usage\\t280465408\\nresource-limits\\t0\\nsecurity-status\\t1\\n\" +\n\t\"server-parse-errors\\t0\\nservfail-answers\\t300249\\nspoof-prevents\\t0\\nsys-msec\\t1296588\\n\" +\n\t\"tcp-client-overflow\\t0\\ntcp-clients\\t0\\ntcp-outqueries\\t116\\ntcp-questions\\t130\\nthrottle-entries\\t33\\n\" +\n\t\"throttled-out\\t13187\\nthrottled-outqueries\\t13187\\ntoo-old-drops\\t2\\nudp-in-errors\\t4\\n\" +\n\t\"udp-noport-errors\\t2908\\nudp-recvbuf-errors\\t0\\nudp-sndbuf-errors\\t0\\nunauthorized-tcp\\t0\\n\" +\n\t\"unauthorized-udp\\t0\\nunexpected-packets\\t0\\nunreachables\\t1695\\nuptime\\t165725\\nuser-msec\\t1266384\\n\" +\n\t\"x-our-latency\\t19\\nx-ourtime-slow\\t632\\nx-ourtime0-1\\t3060079\\nx-ourtime1-2\\t3351\\nx-ourtime16-32\\t197\\n\" +\n\t\"x-ourtime2-4\\t302\\nx-ourtime4-8\\t194\\nx-ourtime8-16\\t24\\n\"\n\n// first metric has no \"\\t\"\nvar corruptMetrics = \"all-outqueries3591637\\nanswers-slow\\t36451\\nanswers0-1\\t177297\\nanswers1-10\\t1209328\\n\" +\n\t\"answers10-100\\t1238786\\nanswers100-1000\\t402917\\nauth-zone-queries\\t4\\nauth4-answers-slow\\t44248\\n\" +\n\t\"auth4-answers0-1\\t59169\\nauth4-answers1-10\\t1747403\\nauth4-answers10-100\\t1315621\\n\" +\n\t\"auth4-answers100-1000\\t424683\\nauth6-answers-slow\\t0\\nauth6-answers0-1\\t0\\nauth6-answers1-10\\t0\\n\" +\n\t\"auth6-answers10-100\\t0\\nauth6-answers100-1000\\t0\\ncache-entries\\t295917\\ncache-hits\\t148630\\n\" +\n\t\"cache-misses\\t2916149\\ncase-mismatches\\t0\\nchain-resends\\t418602\\nclient-parse-errors\\t0\\n\" +\n\t\"concurrent-queries\\t0\\ndlg-only-drops\\t0\\ndnssec-queries\\t151536\\ndnssec-result-bogus\\t0\\n\" +\n\t\"dnssec-result-indeterminate\\t0\\ndnssec-result-insecure\\t0\\ndnssec-result-nta\\t0\\n\" +\n\t\"dnssec-result-secure\\t46\\ndnssec-validations\\t46\\ndont-outqueries\\t62\\necs-queries\\t0\\n\" +\n\t\"ecs-responses\\t0\\nedns-ping-matches\\t0\\nedns-ping-mismatches\\t0\\nfailed-host-entries\\t33\\n\" +\n\t\"fd-usage\\t32\\nignored-packets\\t0\\nipv6-outqueries\\t0\\nipv6-questions\\t0\\nmalloc-bytes\\t0\\n\" +\n\t\"max-cache-entries\\t1000000\\nmax-mthread-stack\\t33747\\nmax-packetcache-entries\\t500000\\n\" +\n\t\"negcache-entries\\t100070\\nno-packet-error\\t0\\nnoedns-outqueries\\t72409\\nnoerror-answers\\t25155259\\n\" +\n\t\"noping-outqueries\\t0\\nnsset-invalidations\\t2385\\nnsspeeds-entries\\t3571\\nnxdomain-answers\\t3307768\\n\" +\n\t\"outgoing-timeouts\\t43876\\noutgoing4-timeouts\\t43876\\noutgoing6-timeouts\\t0\\nover-capacity-drops\\t0\\n\" +\n\t\"packetcache-entries\\t80756\\npacketcache-hits\\t25698497\\npacketcache-misses\\t3064625\\npolicy-drops\\t0\\n\" +\n\t\"policy-result-custom\\t0\\npolicy-result-drop\\t0\\npolicy-result-noaction\\t3064779\\npolicy-result-nodata\\t0\\n\" +\n\t\"policy-result-nxdomain\\t0\\npolicy-result-truncate\\t0\\nqa-latency\\t6587\\nquery-pipe-full-drops\\t0\\n\" +\n\t\"questions\\t28763276\\nreal-memory-usage\\t280465408\\nresource-limits\\t0\\nsecurity-status\\t1\\n\" +\n\t\"server-parse-errors\\t0\\nservfail-answers\\t300249\\nspoof-prevents\\t0\\nsys-msec\\t1296588\\n\" +\n\t\"tcp-client-overflow\\t0\\ntcp-clients\\t0\\ntcp-outqueries\\t116\\ntcp-questions\\t130\\nthrottle-entries\\t33\\n\" +\n\t\"throttled-out\\t13187\\nthrottled-outqueries\\t13187\\ntoo-old-drops\\t2\\nudp-in-errors\\t4\\n\" +\n\t\"udp-noport-errors\\t2908\\nudp-recvbuf-errors\\t0\\nudp-sndbuf-errors\\t0\\nunauthorized-tcp\\t0\\n\" +\n\t\"unauthorized-udp\\t0\\nunexpected-packets\\t0\\nunreachables\\t1695\\nuptime\\t165725\\nuser-msec\\t1266384\\n\" +\n\t\"x-our-latency\\t19\\nx-ourtime-slow\\t632\\nx-ourtime0-1\\t3060079\\nx-ourtime1-2\\t3351\\nx-ourtime16-32\\t197\\n\" +\n\t\"x-ourtime2-4\\t302\\nx-ourtime4-8\\t194\\nx-ourtime8-16\\t24\\n\"\n\n// integer overflow\nvar intOverflowMetrics = \"all-outqueries\\t18446744073709550195\\nanswers-slow\\t36451\\nanswers0-1\\t177297\\nanswers1-10\\t1209328\\n\" +\n\t\"answers10-100\\t1238786\\nanswers100-1000\\t402917\\nauth-zone-queries\\t4\\nauth4-answers-slow\\t44248\\n\" +\n\t\"auth4-answers0-1\\t59169\\nauth4-answers1-10\\t1747403\\nauth4-answers10-100\\t1315621\\n\" +\n\t\"auth4-answers100-1000\\t424683\\nauth6-answers-slow\\t0\\nauth6-answers0-1\\t0\\nauth6-answers1-10\\t0\\n\" +\n\t\"auth6-answers10-100\\t0\\nauth6-answers100-1000\\t0\\ncache-entries\\t295917\\ncache-hits\\t148630\\n\" +\n\t\"cache-misses\\t2916149\\ncase-mismatches\\t0\\nchain-resends\\t418602\\nclient-parse-errors\\t0\\n\" +\n\t\"concurrent-queries\\t0\\ndlg-only-drops\\t0\\ndnssec-queries\\t151536\\ndnssec-result-bogus\\t0\\n\" +\n\t\"dnssec-result-indeterminate\\t0\\ndnssec-result-insecure\\t0\\ndnssec-result-nta\\t0\\n\" +\n\t\"dnssec-result-secure\\t46\\ndnssec-validations\\t46\\ndont-outqueries\\t62\\necs-queries\\t0\\n\" +\n\t\"ecs-responses\\t0\\nedns-ping-matches\\t0\\nedns-ping-mismatches\\t0\\nfailed-host-entries\\t33\\n\" +\n\t\"fd-usage\\t32\\nignored-packets\\t0\\nipv6-outqueries\\t0\\nipv6-questions\\t0\\nmalloc-bytes\\t0\\n\" +\n\t\"max-cache-entries\\t1000000\\nmax-mthread-stack\\t33747\\nmax-packetcache-entries\\t500000\\n\" +\n\t\"negcache-entries\\t100070\\nno-packet-error\\t0\\nnoedns-outqueries\\t72409\\nnoerror-answers\\t25155259\\n\" +\n\t\"noping-outqueries\\t0\\nnsset-invalidations\\t2385\\nnsspeeds-entries\\t3571\\nnxdomain-answers\\t3307768\\n\" +\n\t\"outgoing-timeouts\\t43876\\noutgoing4-timeouts\\t43876\\noutgoing6-timeouts\\t0\\nover-capacity-drops\\t0\\n\" +\n\t\"packetcache-entries\\t80756\\npacketcache-hits\\t25698497\\npacketcache-misses\\t3064625\\npolicy-drops\\t0\\n\" +\n\t\"policy-result-custom\\t0\\npolicy-result-drop\\t0\\npolicy-result-noaction\\t3064779\\npolicy-result-nodata\\t0\\n\" +\n\t\"policy-result-nxdomain\\t0\\npolicy-result-truncate\\t0\\nqa-latency\\t6587\\nquery-pipe-full-drops\\t0\\n\" +\n\t\"questions\\t28763276\\nreal-memory-usage\\t280465408\\nresource-limits\\t0\\nsecurity-status\\t1\\n\" +\n\t\"server-parse-errors\\t0\\nservfail-answers\\t300249\\nspoof-prevents\\t0\\nsys-msec\\t1296588\\n\" +\n\t\"tcp-client-overflow\\t0\\ntcp-clients\\t0\\ntcp-outqueries\\t116\\ntcp-questions\\t130\\nthrottle-entries\\t33\\n\" +\n\t\"throttled-out\\t13187\\nthrottled-outqueries\\t13187\\ntoo-old-drops\\t2\\nudp-in-errors\\t4\\n\" +\n\t\"udp-noport-errors\\t2908\\nudp-recvbuf-errors\\t0\\nudp-sndbuf-errors\\t0\\nunauthorized-tcp\\t0\\n\" +\n\t\"unauthorized-udp\\t0\\nunexpected-packets\\t0\\nunreachables\\t1695\\nuptime\\t165725\\nuser-msec\\t1266384\\n\" +\n\t\"x-our-latency\\t19\\nx-ourtime-slow\\t632\\nx-ourtime0-1\\t3060079\\nx-ourtime1-2\\t3351\\nx-ourtime16-32\\t197\\n\" +\n\t\"x-ourtime2-4\\t302\\nx-ourtime4-8\\t194\\nx-ourtime8-16\\t24\\n\"\n\nfunc TestV1PowerdnsRecursorGeneratesMetrics(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping on windows and darwin, as unixgram sockets are not supported\")\n\t}\n\t// We create a fake server to return test data\n\tcontrolSocket := \"/tmp/pdns5724354148158589552.controlsocket\"\n\tdefer os.Remove(controlSocket)\n\taddr, err := net.ResolveUnixAddr(\"unixgram\", controlSocket)\n\trequire.NoError(t, err, \"Cannot parse unix socket\")\n\tsocket, err := net.ListenUnixgram(\"unixgram\", addr)\n\trequire.NoError(t, err, \"Cannot initialize server on port\")\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tsocket.Close()\n\t\t\tos.Remove(controlSocket)\n\t\t\twg.Done()\n\t\t}()\n\n\t\tfor {\n\t\t\tbuf := make([]byte, 1024)\n\t\t\tn, remote, err := socket.ReadFromUnix(buf)\n\t\t\tif err != nil {\n\t\t\t\tsocket.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdata := buf[:n]\n\t\t\tif string(data) == \"get-all\\n\" {\n\t\t\t\tsocket.WriteToUnix([]byte(metrics), remote) //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\t\t\t\tsocket.Close()\n\t\t\t}\n\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}()\n\n\tp := &PowerdnsRecursor{\n\t\tUnixSockets: []string{controlSocket},\n\t\tSocketDir:   \"/tmp\",\n\t\tSocketMode:  \"0666\",\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\twg.Wait()\n\n\ttestReturnedMetrics(t, &acc)\n}\n\nfunc TestV2PowerdnsRecursorGeneratesMetrics(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping on windows and darwin, as unixgram sockets are not supported\")\n\t}\n\t// We create a fake server to return test data\n\tcontrolSocket := \"/tmp/pdns-v2-5724354148158589552.controlsocket\"\n\tdefer os.Remove(controlSocket)\n\taddr, err := net.ResolveUnixAddr(\"unixgram\", controlSocket)\n\trequire.NoError(t, err, \"Cannot parse unix socket\")\n\tsocket, err := net.ListenUnixgram(\"unixgram\", addr)\n\trequire.NoError(t, err, \"Cannot initialize server on port\")\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tsocket.Close()\n\t\t\tos.Remove(controlSocket)\n\t\t\twg.Done()\n\t\t}()\n\n\t\tfor {\n\t\t\tstatus := make([]byte, 4)\n\t\t\tn, _, err := socket.ReadFromUnix(status)\n\t\t\tif err != nil || n != 4 {\n\t\t\t\tsocket.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbuf := make([]byte, 1024)\n\t\t\tn, remote, err := socket.ReadFromUnix(buf)\n\t\t\tif err != nil {\n\t\t\t\tsocket.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdata := buf[:n]\n\t\t\tif string(data) == \"get-all\" {\n\t\t\t\tsocket.WriteToUnix([]byte{0, 0, 0, 0}, remote) //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\t\t\t\tsocket.WriteToUnix([]byte(metrics), remote)    //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\t\t\t\tsocket.Close()\n\t\t\t}\n\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}()\n\n\tp := &PowerdnsRecursor{\n\t\tUnixSockets:            []string{controlSocket},\n\t\tSocketDir:              \"/tmp\",\n\t\tSocketMode:             \"0666\",\n\t\tControlProtocolVersion: 2,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\twg.Wait()\n\n\ttestReturnedMetrics(t, &acc)\n}\n\nfunc TestV3PowerdnsRecursorGeneratesMetrics(t *testing.T) {\n\tif runtime.GOOS == \"darwin\" || runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping on windows and darwin, as unixgram sockets are not supported\")\n\t}\n\t// We create a fake server to return test data\n\tcontrolSocket := \"/tmp/pdns-v3-5724354148158589552.controlsocket\"\n\tdefer os.Remove(controlSocket)\n\tsocket, err := net.Listen(\"unix\", controlSocket)\n\trequire.NoError(t, err, \"Cannot initialize server on port\")\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tsocket.Close()\n\t\t\tos.Remove(controlSocket)\n\t\t\twg.Done()\n\t\t}()\n\n\t\tfor {\n\t\t\tconn, err := socket.Accept()\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tstatus := make([]byte, 4)\n\t\t\tn, err := conn.Read(status)\n\t\t\tif err != nil || n != 4 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdataLen, err := readNativeUIntFromConn(conn)\n\t\t\tif err != nil || dataLen == 0 || dataLen >= 16384 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbuf := make([]byte, dataLen)\n\t\t\tn, err = conn.Read(buf)\n\t\t\tif err != nil || uint(n) != dataLen {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif string(buf) == \"get-all\" {\n\t\t\t\tconn.Write([]byte{0, 0, 0, 0}) //nolint:errcheck // ignore the returned error as we need to close the socket anyway\n\t\t\t\tmetrics := []byte(metrics)\n\t\t\t\twriteNativeUIntToConn(conn, uint(len(metrics))) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\t\t\t\tconn.Write(metrics)                             //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway\n\t\t\t\tsocket.Close()\n\t\t\t}\n\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}()\n\n\tp := &PowerdnsRecursor{\n\t\tUnixSockets:            []string{controlSocket},\n\t\tSocketDir:              \"/tmp\",\n\t\tSocketMode:             \"0666\",\n\t\tControlProtocolVersion: 3,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\twg.Wait()\n\n\ttestReturnedMetrics(t, &acc)\n}\n\nfunc testReturnedMetrics(t *testing.T, acc *testutil.Accumulator) {\n\tintMetrics := []string{\"all-outqueries\", \"answers-slow\", \"answers0-1\", \"answers1-10\",\n\t\t\"answers10-100\", \"answers100-1000\", \"auth-zone-queries\", \"auth4-answers-slow\",\n\t\t\"auth4-answers0-1\", \"auth4-answers1-10\", \"auth4-answers10-100\", \"auth4-answers100-1000\",\n\t\t\"auth6-answers-slow\", \"auth6-answers0-1\", \"auth6-answers1-10\", \"auth6-answers10-100\",\n\t\t\"auth6-answers100-1000\", \"cache-entries\", \"cache-hits\", \"cache-misses\", \"case-mismatches\",\n\t\t\"chain-resends\", \"client-parse-errors\", \"concurrent-queries\", \"dlg-only-drops\", \"dnssec-queries\",\n\t\t\"dnssec-result-bogus\", \"dnssec-result-indeterminate\", \"dnssec-result-insecure\", \"dnssec-result-nta\",\n\t\t\"dnssec-result-secure\", \"dnssec-validations\", \"dont-outqueries\", \"ecs-queries\", \"ecs-responses\",\n\t\t\"edns-ping-matches\", \"edns-ping-mismatches\", \"failed-host-entries\", \"fd-usage\", \"ignored-packets\",\n\t\t\"ipv6-outqueries\", \"ipv6-questions\", \"malloc-bytes\", \"max-cache-entries\", \"max-mthread-stack\",\n\t\t\"max-packetcache-entries\", \"negcache-entries\", \"no-packet-error\", \"noedns-outqueries\",\n\t\t\"noerror-answers\", \"noping-outqueries\", \"nsset-invalidations\", \"nsspeeds-entries\",\n\t\t\"nxdomain-answers\", \"outgoing-timeouts\", \"outgoing4-timeouts\", \"outgoing6-timeouts\",\n\t\t\"over-capacity-drops\", \"packetcache-entries\", \"packetcache-hits\", \"packetcache-misses\",\n\t\t\"policy-drops\", \"policy-result-custom\", \"policy-result-drop\", \"policy-result-noaction\",\n\t\t\"policy-result-nodata\", \"policy-result-nxdomain\", \"policy-result-truncate\", \"qa-latency\",\n\t\t\"query-pipe-full-drops\", \"questions\", \"real-memory-usage\", \"resource-limits\", \"security-status\",\n\t\t\"server-parse-errors\", \"servfail-answers\", \"spoof-prevents\", \"sys-msec\", \"tcp-client-overflow\",\n\t\t\"tcp-clients\", \"tcp-outqueries\", \"tcp-questions\", \"throttle-entries\", \"throttled-out\", \"throttled-outqueries\",\n\t\t\"too-old-drops\", \"udp-in-errors\", \"udp-noport-errors\", \"udp-recvbuf-errors\", \"udp-sndbuf-errors\",\n\t\t\"unauthorized-tcp\", \"unauthorized-udp\", \"unexpected-packets\", \"unreachables\", \"uptime\", \"user-msec\",\n\t\t\"x-our-latency\", \"x-ourtime-slow\", \"x-ourtime0-1\", \"x-ourtime1-2\", \"x-ourtime16-32\",\n\t\t\"x-ourtime2-4\", \"x-ourtime4-8\", \"x-ourtime8-16\"}\n\n\tfor _, metric := range intMetrics {\n\t\trequire.True(t, acc.HasInt64Field(\"powerdns_recursor\", metric), metric)\n\t}\n}\n\nfunc TestPowerdnsRecursorParseMetrics(t *testing.T) {\n\tvalues := parseResponse(metrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"all-outqueries\", 3591637},\n\t\t{\"answers-slow\", 36451},\n\t\t{\"answers0-1\", 177297},\n\t\t{\"answers1-10\", 1209328},\n\t\t{\"answers10-100\", 1238786},\n\t\t{\"answers100-1000\", 402917},\n\t\t{\"auth-zone-queries\", 4},\n\t\t{\"auth4-answers-slow\", 44248},\n\t\t{\"auth4-answers0-1\", 59169},\n\t\t{\"auth4-answers1-10\", 1747403},\n\t\t{\"auth4-answers10-100\", 1315621},\n\t\t{\"auth4-answers100-1000\", 424683},\n\t\t{\"auth6-answers-slow\", 0},\n\t\t{\"auth6-answers0-1\", 0},\n\t\t{\"auth6-answers1-10\", 0},\n\t\t{\"auth6-answers10-100\", 0},\n\t\t{\"auth6-answers100-1000\", 0},\n\t\t{\"cache-entries\", 295917},\n\t\t{\"cache-hits\", 148630},\n\t\t{\"cache-misses\", 2916149},\n\t\t{\"case-mismatches\", 0},\n\t\t{\"chain-resends\", 418602},\n\t\t{\"client-parse-errors\", 0},\n\t\t{\"concurrent-queries\", 0},\n\t\t{\"dlg-only-drops\", 0},\n\t\t{\"dnssec-queries\", 151536},\n\t\t{\"dnssec-result-bogus\", 0},\n\t\t{\"dnssec-result-indeterminate\", 0},\n\t\t{\"dnssec-result-insecure\", 0},\n\t\t{\"dnssec-result-nta\", 0},\n\t\t{\"dnssec-result-secure\", 46},\n\t\t{\"dnssec-validations\", 46},\n\t\t{\"dont-outqueries\", 62},\n\t\t{\"ecs-queries\", 0},\n\t\t{\"ecs-responses\", 0},\n\t\t{\"edns-ping-matches\", 0},\n\t\t{\"edns-ping-mismatches\", 0},\n\t\t{\"failed-host-entries\", 33},\n\t\t{\"fd-usage\", 32},\n\t\t{\"ignored-packets\", 0},\n\t\t{\"ipv6-outqueries\", 0},\n\t\t{\"ipv6-questions\", 0},\n\t\t{\"malloc-bytes\", 0},\n\t\t{\"max-cache-entries\", 1000000},\n\t\t{\"max-mthread-stack\", 33747},\n\t\t{\"max-packetcache-entries\", 500000},\n\t\t{\"negcache-entries\", 100070},\n\t\t{\"no-packet-error\", 0},\n\t\t{\"noedns-outqueries\", 72409},\n\t\t{\"noerror-answers\", 25155259},\n\t\t{\"noping-outqueries\", 0},\n\t\t{\"nsset-invalidations\", 2385},\n\t\t{\"nsspeeds-entries\", 3571},\n\t\t{\"nxdomain-answers\", 3307768},\n\t\t{\"outgoing-timeouts\", 43876},\n\t\t{\"outgoing4-timeouts\", 43876},\n\t\t{\"outgoing6-timeouts\", 0},\n\t\t{\"over-capacity-drops\", 0},\n\t\t{\"packetcache-entries\", 80756},\n\t\t{\"packetcache-hits\", 25698497},\n\t\t{\"packetcache-misses\", 3064625},\n\t\t{\"policy-drops\", 0},\n\t\t{\"policy-result-custom\", 0},\n\t\t{\"policy-result-drop\", 0},\n\t\t{\"policy-result-noaction\", 3064779},\n\t\t{\"policy-result-nodata\", 0},\n\t\t{\"policy-result-nxdomain\", 0},\n\t\t{\"policy-result-truncate\", 0},\n\t\t{\"qa-latency\", 6587},\n\t\t{\"query-pipe-full-drops\", 0},\n\t\t{\"questions\", 28763276},\n\t\t{\"real-memory-usage\", 280465408},\n\t\t{\"resource-limits\", 0},\n\t\t{\"security-status\", 1},\n\t\t{\"server-parse-errors\", 0},\n\t\t{\"servfail-answers\", 300249},\n\t\t{\"spoof-prevents\", 0},\n\t\t{\"sys-msec\", 1296588},\n\t\t{\"tcp-client-overflow\", 0},\n\t\t{\"tcp-clients\", 0},\n\t\t{\"tcp-outqueries\", 116},\n\t\t{\"tcp-questions\", 130},\n\t\t{\"throttle-entries\", 33},\n\t\t{\"throttled-out\", 13187},\n\t\t{\"throttled-outqueries\", 13187},\n\t\t{\"too-old-drops\", 2},\n\t\t{\"udp-in-errors\", 4},\n\t\t{\"udp-noport-errors\", 2908},\n\t\t{\"udp-recvbuf-errors\", 0},\n\t\t{\"udp-sndbuf-errors\", 0},\n\t\t{\"unauthorized-tcp\", 0},\n\t\t{\"unauthorized-udp\", 0},\n\t\t{\"unexpected-packets\", 0},\n\t\t{\"unreachables\", 1695},\n\t\t{\"uptime\", 165725},\n\t\t{\"user-msec\", 1266384},\n\t\t{\"x-our-latency\", 19},\n\t\t{\"x-ourtime-slow\", 632},\n\t\t{\"x-ourtime0-1\", 3060079},\n\t\t{\"x-ourtime1-2\", 3351},\n\t\t{\"x-ourtime16-32\", 197},\n\t\t{\"x-ourtime2-4\", 302},\n\t\t{\"x-ourtime4-8\", 194},\n\t\t{\"x-ourtime8-16\", 24},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\trequire.Truef(t, ok, \"Did not find key for metric %s in values\", test.key)\n\t\trequire.EqualValuesf(t, value, test.value, \"Metric: %s, Expected: %d, actual: %d\", test.key, test.value, value)\n\t}\n}\n\nfunc TestPowerdnsRecursorParseCorruptMetrics(t *testing.T) {\n\tvalues := parseResponse(corruptMetrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"answers-slow\", 36451},\n\t\t{\"answers0-1\", 177297},\n\t\t{\"answers1-10\", 1209328},\n\t\t{\"answers10-100\", 1238786},\n\t\t{\"answers100-1000\", 402917},\n\t\t{\"auth-zone-queries\", 4},\n\t\t{\"auth4-answers-slow\", 44248},\n\t\t{\"auth4-answers0-1\", 59169},\n\t\t{\"auth4-answers1-10\", 1747403},\n\t\t{\"auth4-answers10-100\", 1315621},\n\t\t{\"auth4-answers100-1000\", 424683},\n\t\t{\"auth6-answers-slow\", 0},\n\t\t{\"auth6-answers0-1\", 0},\n\t\t{\"auth6-answers1-10\", 0},\n\t\t{\"auth6-answers10-100\", 0},\n\t\t{\"auth6-answers100-1000\", 0},\n\t\t{\"cache-entries\", 295917},\n\t\t{\"cache-hits\", 148630},\n\t\t{\"cache-misses\", 2916149},\n\t\t{\"case-mismatches\", 0},\n\t\t{\"chain-resends\", 418602},\n\t\t{\"client-parse-errors\", 0},\n\t\t{\"concurrent-queries\", 0},\n\t\t{\"dlg-only-drops\", 0},\n\t\t{\"dnssec-queries\", 151536},\n\t\t{\"dnssec-result-bogus\", 0},\n\t\t{\"dnssec-result-indeterminate\", 0},\n\t\t{\"dnssec-result-insecure\", 0},\n\t\t{\"dnssec-result-nta\", 0},\n\t\t{\"dnssec-result-secure\", 46},\n\t\t{\"dnssec-validations\", 46},\n\t\t{\"dont-outqueries\", 62},\n\t\t{\"ecs-queries\", 0},\n\t\t{\"ecs-responses\", 0},\n\t\t{\"edns-ping-matches\", 0},\n\t\t{\"edns-ping-mismatches\", 0},\n\t\t{\"failed-host-entries\", 33},\n\t\t{\"fd-usage\", 32},\n\t\t{\"ignored-packets\", 0},\n\t\t{\"ipv6-outqueries\", 0},\n\t\t{\"ipv6-questions\", 0},\n\t\t{\"malloc-bytes\", 0},\n\t\t{\"max-cache-entries\", 1000000},\n\t\t{\"max-mthread-stack\", 33747},\n\t\t{\"max-packetcache-entries\", 500000},\n\t\t{\"negcache-entries\", 100070},\n\t\t{\"no-packet-error\", 0},\n\t\t{\"noedns-outqueries\", 72409},\n\t\t{\"noerror-answers\", 25155259},\n\t\t{\"noping-outqueries\", 0},\n\t\t{\"nsset-invalidations\", 2385},\n\t\t{\"nsspeeds-entries\", 3571},\n\t\t{\"nxdomain-answers\", 3307768},\n\t\t{\"outgoing-timeouts\", 43876},\n\t\t{\"outgoing4-timeouts\", 43876},\n\t\t{\"outgoing6-timeouts\", 0},\n\t\t{\"over-capacity-drops\", 0},\n\t\t{\"packetcache-entries\", 80756},\n\t\t{\"packetcache-hits\", 25698497},\n\t\t{\"packetcache-misses\", 3064625},\n\t\t{\"policy-drops\", 0},\n\t\t{\"policy-result-custom\", 0},\n\t\t{\"policy-result-drop\", 0},\n\t\t{\"policy-result-noaction\", 3064779},\n\t\t{\"policy-result-nodata\", 0},\n\t\t{\"policy-result-nxdomain\", 0},\n\t\t{\"policy-result-truncate\", 0},\n\t\t{\"qa-latency\", 6587},\n\t\t{\"query-pipe-full-drops\", 0},\n\t\t{\"questions\", 28763276},\n\t\t{\"real-memory-usage\", 280465408},\n\t\t{\"resource-limits\", 0},\n\t\t{\"security-status\", 1},\n\t\t{\"server-parse-errors\", 0},\n\t\t{\"servfail-answers\", 300249},\n\t\t{\"spoof-prevents\", 0},\n\t\t{\"sys-msec\", 1296588},\n\t\t{\"tcp-client-overflow\", 0},\n\t\t{\"tcp-clients\", 0},\n\t\t{\"tcp-outqueries\", 116},\n\t\t{\"tcp-questions\", 130},\n\t\t{\"throttle-entries\", 33},\n\t\t{\"throttled-out\", 13187},\n\t\t{\"throttled-outqueries\", 13187},\n\t\t{\"too-old-drops\", 2},\n\t\t{\"udp-in-errors\", 4},\n\t\t{\"udp-noport-errors\", 2908},\n\t\t{\"udp-recvbuf-errors\", 0},\n\t\t{\"udp-sndbuf-errors\", 0},\n\t\t{\"unauthorized-tcp\", 0},\n\t\t{\"unauthorized-udp\", 0},\n\t\t{\"unexpected-packets\", 0},\n\t\t{\"unreachables\", 1695},\n\t\t{\"uptime\", 165725},\n\t\t{\"user-msec\", 1266384},\n\t\t{\"x-our-latency\", 19},\n\t\t{\"x-ourtime-slow\", 632},\n\t\t{\"x-ourtime0-1\", 3060079},\n\t\t{\"x-ourtime1-2\", 3351},\n\t\t{\"x-ourtime16-32\", 197},\n\t\t{\"x-ourtime2-4\", 302},\n\t\t{\"x-ourtime4-8\", 194},\n\t\t{\"x-ourtime8-16\", 24},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\trequire.Truef(t, ok, \"Did not find key for metric %s in values\", test.key)\n\t\trequire.EqualValuesf(t, value, test.value, \"Metric: %s, Expected: %d, actual: %d\", test.key, test.value, value)\n\t}\n}\n\nfunc TestPowerdnsRecursorParseIntOverflowMetrics(t *testing.T) {\n\tvalues := parseResponse(intOverflowMetrics)\n\n\ttests := []struct {\n\t\tkey   string\n\t\tvalue int64\n\t}{\n\t\t{\"answers-slow\", 36451},\n\t\t{\"answers0-1\", 177297},\n\t\t{\"answers1-10\", 1209328},\n\t\t{\"answers10-100\", 1238786},\n\t\t{\"answers100-1000\", 402917},\n\t\t{\"auth-zone-queries\", 4},\n\t\t{\"auth4-answers-slow\", 44248},\n\t\t{\"auth4-answers0-1\", 59169},\n\t\t{\"auth4-answers1-10\", 1747403},\n\t\t{\"auth4-answers10-100\", 1315621},\n\t\t{\"auth4-answers100-1000\", 424683},\n\t\t{\"auth6-answers-slow\", 0},\n\t\t{\"auth6-answers0-1\", 0},\n\t\t{\"auth6-answers1-10\", 0},\n\t\t{\"auth6-answers10-100\", 0},\n\t\t{\"auth6-answers100-1000\", 0},\n\t\t{\"cache-entries\", 295917},\n\t\t{\"cache-hits\", 148630},\n\t\t{\"cache-misses\", 2916149},\n\t\t{\"case-mismatches\", 0},\n\t\t{\"chain-resends\", 418602},\n\t\t{\"client-parse-errors\", 0},\n\t\t{\"concurrent-queries\", 0},\n\t\t{\"dlg-only-drops\", 0},\n\t\t{\"dnssec-queries\", 151536},\n\t\t{\"dnssec-result-bogus\", 0},\n\t\t{\"dnssec-result-indeterminate\", 0},\n\t\t{\"dnssec-result-insecure\", 0},\n\t\t{\"dnssec-result-nta\", 0},\n\t\t{\"dnssec-result-secure\", 46},\n\t\t{\"dnssec-validations\", 46},\n\t\t{\"dont-outqueries\", 62},\n\t\t{\"ecs-queries\", 0},\n\t\t{\"ecs-responses\", 0},\n\t\t{\"edns-ping-matches\", 0},\n\t\t{\"edns-ping-mismatches\", 0},\n\t\t{\"failed-host-entries\", 33},\n\t\t{\"fd-usage\", 32},\n\t\t{\"ignored-packets\", 0},\n\t\t{\"ipv6-outqueries\", 0},\n\t\t{\"ipv6-questions\", 0},\n\t\t{\"malloc-bytes\", 0},\n\t\t{\"max-cache-entries\", 1000000},\n\t\t{\"max-mthread-stack\", 33747},\n\t\t{\"max-packetcache-entries\", 500000},\n\t\t{\"negcache-entries\", 100070},\n\t\t{\"no-packet-error\", 0},\n\t\t{\"noedns-outqueries\", 72409},\n\t\t{\"noerror-answers\", 25155259},\n\t\t{\"noping-outqueries\", 0},\n\t\t{\"nsset-invalidations\", 2385},\n\t\t{\"nsspeeds-entries\", 3571},\n\t\t{\"nxdomain-answers\", 3307768},\n\t\t{\"outgoing-timeouts\", 43876},\n\t\t{\"outgoing4-timeouts\", 43876},\n\t\t{\"outgoing6-timeouts\", 0},\n\t\t{\"over-capacity-drops\", 0},\n\t\t{\"packetcache-entries\", 80756},\n\t\t{\"packetcache-hits\", 25698497},\n\t\t{\"packetcache-misses\", 3064625},\n\t\t{\"policy-drops\", 0},\n\t\t{\"policy-result-custom\", 0},\n\t\t{\"policy-result-drop\", 0},\n\t\t{\"policy-result-noaction\", 3064779},\n\t\t{\"policy-result-nodata\", 0},\n\t\t{\"policy-result-nxdomain\", 0},\n\t\t{\"policy-result-truncate\", 0},\n\t\t{\"qa-latency\", 6587},\n\t\t{\"query-pipe-full-drops\", 0},\n\t\t{\"questions\", 28763276},\n\t\t{\"real-memory-usage\", 280465408},\n\t\t{\"resource-limits\", 0},\n\t\t{\"security-status\", 1},\n\t\t{\"server-parse-errors\", 0},\n\t\t{\"servfail-answers\", 300249},\n\t\t{\"spoof-prevents\", 0},\n\t\t{\"sys-msec\", 1296588},\n\t\t{\"tcp-client-overflow\", 0},\n\t\t{\"tcp-clients\", 0},\n\t\t{\"tcp-outqueries\", 116},\n\t\t{\"tcp-questions\", 130},\n\t\t{\"throttle-entries\", 33},\n\t\t{\"throttled-out\", 13187},\n\t\t{\"throttled-outqueries\", 13187},\n\t\t{\"too-old-drops\", 2},\n\t\t{\"udp-in-errors\", 4},\n\t\t{\"udp-noport-errors\", 2908},\n\t\t{\"udp-recvbuf-errors\", 0},\n\t\t{\"udp-sndbuf-errors\", 0},\n\t\t{\"unauthorized-tcp\", 0},\n\t\t{\"unauthorized-udp\", 0},\n\t\t{\"unexpected-packets\", 0},\n\t\t{\"unreachables\", 1695},\n\t\t{\"uptime\", 165725},\n\t\t{\"user-msec\", 1266384},\n\t\t{\"x-our-latency\", 19},\n\t\t{\"x-ourtime-slow\", 632},\n\t\t{\"x-ourtime0-1\", 3060079},\n\t\t{\"x-ourtime1-2\", 3351},\n\t\t{\"x-ourtime16-32\", 197},\n\t\t{\"x-ourtime2-4\", 302},\n\t\t{\"x-ourtime4-8\", 194},\n\t\t{\"x-ourtime8-16\", 24},\n\t}\n\n\tfor _, test := range tests {\n\t\tvalue, ok := values[test.key]\n\t\trequire.Truef(t, ok, \"Did not find key for metric %s in values\", test.key)\n\t\trequire.EqualValuesf(t, value, test.value, \"Metric: %s, Expected: %d, actual: %d\", test.key, test.value, value)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/protocol_commons.go",
    "content": "package powerdns_recursor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc parseResponse(metrics string) map[string]interface{} {\n\tvalues := make(map[string]interface{})\n\n\ts := strings.Split(metrics, \"\\n\")\n\n\tif len(s) < 1 {\n\t\treturn values\n\t}\n\n\tfor _, metric := range s[:len(s)-1] {\n\t\tm := strings.Split(metric, \"\\t\")\n\t\tif len(m) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\ti, err := strconv.ParseInt(m[1], 10, 64)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tvalues[m[0]] = i\n\t}\n\n\treturn values\n}\n\n// This below is generally unsafe but necessary in this case\n// since the powerdns protocol encoding is host dependent.\n// The C implementation uses size_t as the size type for the\n// command length. The size and endianness of size_t change\n// depending on the platform the program is being run on.\n// Using the target architecture endianness and the known\n// integer size, we can \"recreate\" the corresponding C\n// behavior in an effort to maintain compatibility. Of course\n// in cases where one program is compiled for i386 and the\n// other for amd64 (and similar), this method will fail.\n\nconst uintSizeInBytes = strconv.IntSize / 8\n\nfunc writeNativeUIntToConn(conn net.Conn, value uint) error {\n\tintData := make([]byte, uintSizeInBytes)\n\n\tswitch uintSizeInBytes {\n\tcase 4:\n\t\tinternal.HostEndianness.PutUint32(intData, uint32(value))\n\tcase 8:\n\t\tinternal.HostEndianness.PutUint64(intData, uint64(value))\n\tdefault:\n\t\treturn errors.New(\"unsupported system configuration\")\n\t}\n\n\t_, err := conn.Write(intData)\n\treturn err\n}\n\nfunc readNativeUIntFromConn(conn net.Conn) (uint, error) {\n\tintData := make([]byte, uintSizeInBytes)\n\n\tn, err := conn.Read(intData)\n\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif n != uintSizeInBytes {\n\t\treturn 0, fmt.Errorf(\"did not read enough data for native uint: read '%v' bytes, expected '%v'\", n, uintSizeInBytes)\n\t}\n\n\tswitch uintSizeInBytes {\n\tcase 4:\n\t\treturn uint(internal.HostEndianness.Uint32(intData)), nil\n\tcase 8:\n\t\treturn uint(internal.HostEndianness.Uint64(intData)), nil\n\tdefault:\n\t\treturn 0, errors.New(\"unsupported system configuration\")\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/protocol_v1.go",
    "content": "package powerdns_recursor\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// V1 (before 4.5.0) Protocol:\n// Unix datagram socket\n// Synchronous request / response, individual datagrams\n// Structure:\n// data: byte[]\n// The `data` field contains a list of commands to execute with\n// the \\n character after every command.\nfunc (p *PowerdnsRecursor) gatherFromV1Server(address string, acc telegraf.Accumulator) error {\n\trecvSocket := filepath.Join(p.SocketDir, \"pdns_recursor_telegraf\"+uuid.New().String())\n\n\tladdr, err := net.ResolveUnixAddr(\"unixgram\", recvSocket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer os.Remove(recvSocket)\n\n\traddr, err := net.ResolveUnixAddr(\"unixgram\", address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err := net.DialUnix(\"unixgram\", laddr, raddr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close()\n\n\tif err := os.Chmod(recvSocket, os.FileMode(p.mode)); err != nil {\n\t\treturn err\n\t}\n\n\tif err := conn.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\t// Then send the get-all command.\n\tcommand := \"get-all\\n\"\n\n\t_, err = conn.Write([]byte(command))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Read the response data.\n\tbuf := make([]byte, 16_384)\n\tn, err := conn.Read(buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif n == 0 {\n\t\treturn errors.New(\"no data received\")\n\t}\n\n\tmetrics := string(buf)\n\n\t// Process data\n\tfields := parseResponse(metrics)\n\n\t// Add server socket as a tag\n\ttags := map[string]string{\"server\": address}\n\n\tacc.AddFields(\"powerdns_recursor\", fields, tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/protocol_v2.go",
    "content": "package powerdns_recursor\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// V2 (4.5.0 - 4.5.9) Protocol:\n// Unix datagram socket\n// Synchronous request / response, individual datagrams\n// Datagram 1 => status: uint32\n// Datagram 2 => data: byte[] (max 16_384 bytes)\nfunc (p *PowerdnsRecursor) gatherFromV2Server(address string, acc telegraf.Accumulator) error {\n\trecvSocket := filepath.Join(p.SocketDir, \"pdns_recursor_telegraf\"+uuid.New().String())\n\n\tladdr, err := net.ResolveUnixAddr(\"unixgram\", recvSocket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer os.Remove(recvSocket)\n\n\traddr, err := net.ResolveUnixAddr(\"unixgram\", address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err := net.DialUnix(\"unixgram\", laddr, raddr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close()\n\n\tif err := os.Chmod(recvSocket, os.FileMode(p.mode)); err != nil {\n\t\treturn err\n\t}\n\n\tif err := conn.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\t// First send a 0 status code.\n\t_, err = conn.Write([]byte{0, 0, 0, 0})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Then send the get-all command.\n\tcommand := \"get-all\"\n\n\t_, err = conn.Write([]byte(command))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Read the response status code.\n\tstatus := make([]byte, 4)\n\tn, err := conn.Read(status)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif n == 0 {\n\t\treturn errors.New(\"no status code received\")\n\t}\n\n\t// Read the response data.\n\tbuf := make([]byte, 16_384)\n\tn, err = conn.Read(buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif n == 0 {\n\t\treturn errors.New(\"no data received\")\n\t}\n\n\tmetrics := string(buf)\n\n\t// Process data\n\tfields := parseResponse(metrics)\n\n\t// Add server socket as a tag\n\ttags := map[string]string{\"server\": address}\n\n\tacc.AddFields(\"powerdns_recursor\", fields, tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/protocol_v3.go",
    "content": "package powerdns_recursor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\n// V3 (4.6.0+) Protocol:\n// Standard unix stream socket\n// Synchronous request / response\n// Data structure:\n// status: uint32\n// dataLength: size_t\n// data: byte[dataLength]\nfunc gatherFromV3Server(address string, acc telegraf.Accumulator) error {\n\tconn, err := net.Dial(\"unix\", address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close()\n\n\tif err := conn.SetDeadline(time.Now().Add(defaultTimeout)); err != nil {\n\t\treturn err\n\t}\n\n\t// Write 4-byte response code.\n\tif _, err = conn.Write([]byte{0, 0, 0, 0}); err != nil {\n\t\treturn err\n\t}\n\n\tcommand := []byte(\"get-all\")\n\n\tif err := writeNativeUIntToConn(conn, uint(len(command))); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err = conn.Write(command); err != nil {\n\t\treturn err\n\t}\n\n\t// Now read the response.\n\tstatus := make([]byte, 4)\n\tn, err := conn.Read(status)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif n == 0 {\n\t\treturn errors.New(\"no status code received\")\n\t}\n\n\tresponseLength, err := readNativeUIntFromConn(conn)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif responseLength == 0 {\n\t\treturn errors.New(\"received data length was '0'\")\n\t}\n\n\t// Don't allow more than 64kb of data to prevent DOS / issues\n\t// with architecture mismatch. V2 protocol allowed for up to\n\t// 16kb, so 64kb should give us a pretty good margin for anything\n\t// that has been added since.\n\tif responseLength > 64*1024 {\n\t\treturn fmt.Errorf(\"received data length was '%d', we only allow up to '%d'\", responseLength, 64*1024)\n\t}\n\n\tdata := make([]byte, responseLength)\n\tn, err = conn.Read(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif uint(n) != responseLength {\n\t\treturn fmt.Errorf(\"no data received, expected '%v' bytes but got '%v'\", responseLength, n)\n\t}\n\n\t// Process data\n\tmetrics := string(data)\n\tfields := parseResponse(metrics)\n\n\t// Add server socket as a tag\n\ttags := map[string]string{\"server\": address}\n\n\tacc.AddFields(\"powerdns_recursor\", fields, tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/powerdns_recursor/sample.conf",
    "content": "# Read metrics from one or many PowerDNS Recursor servers\n[[inputs.powerdns_recursor]]\n  ## Path to the Recursor control socket.\n  unix_sockets = [\"/var/run/pdns_recursor.controlsocket\"]\n\n  ## Directory to create receive socket.  This default is likely not writable,\n  ## please reference the full plugin documentation for a recommended setup.\n  # socket_dir = \"/var/run/\"\n  ## Socket permissions for the receive socket.\n  # socket_mode = \"0666\"\n\n  ## The version of the PowerDNS control protocol to use. You will have to\n  ## change this based on your PowerDNS Recursor version, see below:\n  ## Version 1: PowerDNS <4.5.0\n  ## Version 2: PowerDNS 4.5.0 - 4.5.11\n  ## Version 3: PowerDNS >=4.6.0\n  ## By default this is set to 1.\n  # control_protocol_version = 1\n\n"
  },
  {
    "path": "plugins/inputs/processes/README.md",
    "content": "# Processes Input Plugin\n\nThis plugin gathers info about the total number of processes and groups them by\nstatus (zombie, sleeping, running, etc.)\n\n> [!NOTE]\n> On Linux this plugin requires access to procfs (/proc), on other operating\n> systems the plugin must be able to execute the `ps` command.\n\n⭐ Telegraf v0.11.0\n🏷️ system\n💻 freebsd, linux, macos\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get the number of processes and group them by status\n# This plugin ONLY supports non-Windows\n[[inputs.processes]]\n  ## Use sudo to run ps command on *BSD systems. Linux systems will read\n  ## /proc, so this does not apply there.\n  # use_sudo = false\n```\n\nAnother possible configuration is to define an alternative path for resolving\nthe /proc location.  Using the environment variable `HOST_PROC` the plugin will\nretrieve process information from the specified location.\n\n`docker run -v /proc:/rootfs/proc:ro -e HOST_PROC=/rootfs/proc`\n\n### Using sudo\n\nLinux systems will read from `/proc`, while BSD systems will use the `ps`\ncommand. The `ps` command generally does not require elevated permissions.\nHowever, if a user wants to collect system-wide stats, elevated permissions are\nrequired. If the user has configured sudo with the ability to run this\ncommand, then set the `use_sudo` to true.\n\nIf your account does not already have the ability to run commands with\npasswordless sudo then updates to the sudoers file are required. Below is an\nexample to allow the requires ps commands:\n\nFirst, use the `visudo` command to start editing the sudoers file. Then add\nthe following content, where `<username>` is the username of the user that\nneeds this access:\n\n```text\nCmnd_Alias PS = /bin/ps\n<username> ALL=(root) NOPASSWD: PS\nDefaults!PS !logfile, !syslog, !pam_session\n```\n\n## Metrics\n\n- processes\n  - fields:\n    - blocked (aka disk sleep or uninterruptible sleep)\n    - running\n    - sleeping\n    - stopped\n    - total\n    - zombie\n    - dead\n    - wait (freebsd only)\n    - idle (bsd and Linux 4+ only)\n    - paging (linux only)\n    - parked (linux only)\n    - total_threads (linux only)\n\nDifferent OSes use slightly different State codes for their processes, these\nstate codes are documented in `man ps`, and I will give a mapping of what major\nOS state codes correspond to in telegraf metrics:\n\n```text\nLinux  FreeBSD  Darwin  meaning\n  R       R       R     running\n  S       S       S     sleeping\n  Z       Z       Z     zombie\n  X      none    none   dead\n  T       T       T     stopped\n  I       I       I     idle (sleeping for longer than about 20 seconds)\n  D      D,L      U     blocked (waiting in uninterruptible sleep, or locked)\n  W       W      none   paging (linux kernel < 2.6 only), wait (freebsd)\n```\n\n## Example Output\n\n```text\nprocesses blocked=8i,running=1i,sleeping=265i,stopped=0i,total=274i,zombie=0i,dead=0i,paging=0i,total_threads=687i 1457478636980905042\n```\n"
  },
  {
    "path": "plugins/inputs/processes/processes.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage processes\n\nimport _ \"embed\"\n\n//go:embed sample.conf\nvar sampleConfig string\n\nfunc (*Processes) SampleConfig() string {\n\treturn sampleConfig\n}\n"
  },
  {
    "path": "plugins/inputs/processes/processes_notwindows.go",
    "content": "//go:build !windows\n\npackage processes\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype Processes struct {\n\tUseSudo bool            `toml:\"use_sudo\"`\n\tLog     telegraf.Logger `toml:\"-\"`\n\n\texecPS       func(UseSudo bool) ([]byte, error)\n\treadProcFile func(filename string) ([]byte, error)\n\tforcePS      bool\n\tforceProc    bool\n}\n\nfunc (p *Processes) Gather(acc telegraf.Accumulator) error {\n\t// Get an empty map of metric fields\n\tfields := getEmptyFields()\n\n\t// Decide if we will use 'ps' to get stats (use procfs otherwise)\n\tusePS := true\n\tif runtime.GOOS == \"linux\" {\n\t\tusePS = false\n\t}\n\tif p.forcePS {\n\t\tusePS = true\n\t} else if p.forceProc {\n\t\tusePS = false\n\t}\n\n\t// Gather stats from 'ps' or procfs\n\tif usePS {\n\t\tif err := p.gatherFromPS(fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tif err := p.gatherFromProc(fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tacc.AddGauge(\"processes\", fields, nil)\n\treturn nil\n}\n\n// Gets empty fields of metrics based on the OS\nfunc getEmptyFields() map[string]interface{} {\n\tfields := map[string]interface{}{\n\t\t\"blocked\":  int64(0),\n\t\t\"zombies\":  int64(0),\n\t\t\"stopped\":  int64(0),\n\t\t\"running\":  int64(0),\n\t\t\"sleeping\": int64(0),\n\t\t\"total\":    int64(0),\n\t\t\"unknown\":  int64(0),\n\t}\n\tswitch runtime.GOOS {\n\tcase \"freebsd\":\n\t\tfields[\"idle\"] = int64(0)\n\t\tfields[\"wait\"] = int64(0)\n\tcase \"darwin\":\n\t\tfields[\"idle\"] = int64(0)\n\tcase \"openbsd\":\n\t\tfields[\"idle\"] = int64(0)\n\tcase \"linux\":\n\t\tfields[\"dead\"] = int64(0)\n\t\tfields[\"paging\"] = int64(0)\n\t\tfields[\"total_threads\"] = int64(0)\n\t\tfields[\"idle\"] = int64(0)\n\t}\n\treturn fields\n}\n\n// exec `ps` to get all process states\nfunc (p *Processes) gatherFromPS(fields map[string]interface{}) error {\n\tout, err := p.execPS(p.UseSudo)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i, status := range bytes.Fields(out) {\n\t\tif i == 0 && string(status) == \"STAT\" {\n\t\t\t// This is a header, skip it\n\t\t\tcontinue\n\t\t}\n\t\tswitch status[0] {\n\t\tcase 'W':\n\t\t\tfields[\"wait\"] = fields[\"wait\"].(int64) + int64(1)\n\t\tcase 'U', 'D', 'L':\n\t\t\t// Also known as uninterruptible sleep or disk sleep\n\t\t\tfields[\"blocked\"] = fields[\"blocked\"].(int64) + int64(1)\n\t\tcase 'Z':\n\t\t\tfields[\"zombies\"] = fields[\"zombies\"].(int64) + int64(1)\n\t\tcase 'X':\n\t\t\tfields[\"dead\"] = fields[\"dead\"].(int64) + int64(1)\n\t\tcase 'T':\n\t\t\tfields[\"stopped\"] = fields[\"stopped\"].(int64) + int64(1)\n\t\tcase 'R':\n\t\t\tfields[\"running\"] = fields[\"running\"].(int64) + int64(1)\n\t\tcase 'S':\n\t\t\tfields[\"sleeping\"] = fields[\"sleeping\"].(int64) + int64(1)\n\t\tcase 'I':\n\t\t\tfields[\"idle\"] = fields[\"idle\"].(int64) + int64(1)\n\t\tcase '?':\n\t\t\tfields[\"unknown\"] = fields[\"unknown\"].(int64) + int64(1)\n\t\tdefault:\n\t\t\tp.Log.Infof(\"Unknown state %q from ps\", string(status[0]))\n\t\t}\n\t\tfields[\"total\"] = fields[\"total\"].(int64) + int64(1)\n\t}\n\treturn nil\n}\n\n// get process states from /proc/(pid)/stat files\nfunc (p *Processes) gatherFromProc(fields map[string]interface{}) error {\n\tfilenames, err := filepath.Glob(internal.GetProcPath() + \"/[0-9]*/stat\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, filename := range filenames {\n\t\tdata, err := p.readProcFile(filename)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif data == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse out data after (<cmd name>)\n\t\ti := bytes.LastIndex(data, []byte(\")\"))\n\t\tif i == -1 {\n\t\t\tcontinue\n\t\t}\n\t\tdata = data[i+2:]\n\n\t\tstats := bytes.Fields(data)\n\t\tif len(stats) < 3 {\n\t\t\treturn fmt.Errorf(\"something is terribly wrong with %s\", filename)\n\t\t}\n\t\tswitch stats[0][0] {\n\t\tcase 'R':\n\t\t\tfields[\"running\"] = fields[\"running\"].(int64) + int64(1)\n\t\tcase 'S':\n\t\t\tfields[\"sleeping\"] = fields[\"sleeping\"].(int64) + int64(1)\n\t\tcase 'D':\n\t\t\tfields[\"blocked\"] = fields[\"blocked\"].(int64) + int64(1)\n\t\tcase 'Z':\n\t\t\tfields[\"zombies\"] = fields[\"zombies\"].(int64) + int64(1)\n\t\tcase 'X':\n\t\t\tfields[\"dead\"] = fields[\"dead\"].(int64) + int64(1)\n\t\tcase 'T', 't':\n\t\t\tfields[\"stopped\"] = fields[\"stopped\"].(int64) + int64(1)\n\t\tcase 'W':\n\t\t\tfields[\"paging\"] = fields[\"paging\"].(int64) + int64(1)\n\t\tcase 'I':\n\t\t\tfields[\"idle\"] = fields[\"idle\"].(int64) + int64(1)\n\t\tcase 'P':\n\t\t\tif _, ok := fields[\"parked\"]; ok {\n\t\t\t\tfields[\"parked\"] = fields[\"parked\"].(int64) + int64(1)\n\t\t\t}\n\t\t\tfields[\"parked\"] = int64(1)\n\t\tdefault:\n\t\t\tp.Log.Infof(\"Unknown state %q in file %q\", string(stats[0][0]), filename)\n\t\t}\n\t\tfields[\"total\"] = fields[\"total\"].(int64) + int64(1)\n\n\t\tthreads, err := strconv.Atoi(string(stats[17]))\n\t\tif err != nil {\n\t\t\tp.Log.Infof(\"Error parsing thread count: %s\", err.Error())\n\t\t\tcontinue\n\t\t}\n\t\tfields[\"total_threads\"] = fields[\"total_threads\"].(int64) + int64(threads)\n\t}\n\treturn nil\n}\n\nfunc readProcFile(filename string) ([]byte, error) {\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\t// Reading from /proc/<PID> fails with ESRCH if the process has\n\t\t// been terminated between open() and read().\n\t\tvar perr *os.PathError\n\t\tif errors.As(err, &perr) && errors.Is(perr.Err, syscall.ESRCH) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc execPS(useSudo bool) ([]byte, error) {\n\tbin, err := exec.LookPath(\"ps\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcmd := []string{bin, \"axo\", \"state\"}\n\tif useSudo {\n\t\tcmd = append([]string{\"sudo\", \"-n\"}, cmd...)\n\t}\n\n\tout, err := exec.Command(cmd[0], cmd[1:]...).Output()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn out, err\n}\n\nfunc init() {\n\tinputs.Add(\"processes\", func() telegraf.Input {\n\t\treturn &Processes{\n\t\t\texecPS:       execPS,\n\t\t\treadProcFile: readProcFile,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/processes/processes_test.go",
    "content": "//go:build !windows\n\npackage processes\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestProcesses(t *testing.T) {\n\ttester := tester{}\n\tprocesses := &Processes{\n\t\tLog: testutil.Logger{},\n\t\texecPS: testExecPS(\n\t\t\t\"STAT\\n\t\tSs  \\n\t\tS   \\n\t\tZ   \\n\t\tR   \\n\t\tS<  \\n\t\tSNs \\n\t\tSs+ \\n\t\t\\n\t\t\\n\",\n\t\t),\n\t\treadProcFile: tester.testProcFile,\n\t}\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, processes.Gather(&acc))\n\n\trequire.True(t, acc.HasInt64Field(\"processes\", \"running\"))\n\trequire.True(t, acc.HasInt64Field(\"processes\", \"sleeping\"))\n\trequire.True(t, acc.HasInt64Field(\"processes\", \"stopped\"))\n\trequire.True(t, acc.HasInt64Field(\"processes\", \"total\"))\n\ttotal, ok := acc.Get(\"processes\")\n\trequire.True(t, ok)\n\trequire.Positive(t, total.Fields[\"total\"])\n}\n\nfunc TestFromPS(t *testing.T) {\n\tprocesses := &Processes{\n\t\tLog:     testutil.Logger{},\n\t\texecPS:  testExecPS(\"\\nSTAT\\nD\\nI\\nL\\nR\\nR+\\nS\\nS+\\nSNs\\nSs\\nU\\nZ\\n\"),\n\t\tforcePS: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, processes.Gather(&acc))\n\n\tfields := getEmptyFields()\n\tfields[\"blocked\"] = int64(3)\n\tfields[\"zombies\"] = int64(1)\n\tfields[\"running\"] = int64(2)\n\tfields[\"sleeping\"] = int64(4)\n\tfields[\"idle\"] = int64(1)\n\tfields[\"total\"] = int64(11)\n\n\tacc.AssertContainsTaggedFields(t, \"processes\", fields, map[string]string{})\n}\n\nfunc TestFromPSError(t *testing.T) {\n\tprocesses := &Processes{\n\t\tLog:     testutil.Logger{},\n\t\texecPS:  testExecPSError,\n\t\tforcePS: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, processes.Gather(&acc))\n}\n\nfunc TestFromProcFiles(t *testing.T) {\n\tif runtime.GOOS != \"linux\" {\n\t\tt.Skip(\"This test only runs on linux\")\n\t}\n\ttester := tester{}\n\tprocesses := &Processes{\n\t\tLog:          testutil.Logger{},\n\t\treadProcFile: tester.testProcFile,\n\t\tforceProc:    true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, processes.Gather(&acc))\n\n\tfields := getEmptyFields()\n\tfields[\"sleeping\"] = tester.calls\n\tfields[\"total_threads\"] = tester.calls * 2\n\tfields[\"total\"] = tester.calls\n\n\tacc.AssertContainsTaggedFields(t, \"processes\", fields, map[string]string{})\n}\n\nfunc TestFromProcFilesWithSpaceInCmd(t *testing.T) {\n\tif runtime.GOOS != \"linux\" {\n\t\tt.Skip(\"This test only runs on linux\")\n\t}\n\ttester := tester{}\n\tprocesses := &Processes{\n\t\tLog:          testutil.Logger{},\n\t\treadProcFile: tester.testProcFile2,\n\t\tforceProc:    true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, processes.Gather(&acc))\n\n\tfields := getEmptyFields()\n\tfields[\"sleeping\"] = tester.calls\n\tfields[\"total_threads\"] = tester.calls * 2\n\tfields[\"total\"] = tester.calls\n\n\tacc.AssertContainsTaggedFields(t, \"processes\", fields, map[string]string{})\n}\n\n// Based on `man 5 proc`, parked processes an be found in a\n// limited range of Linux versions:\n//\n// >    P  Parked (Linux 3.9 to 3.13 only)\n//\n// However, we have had reports of this process state on Ubuntu\n// Bionic w/ Linux 4.15 (#6270)\nfunc TestParkedProcess(t *testing.T) {\n\tif runtime.GOOS != \"linux\" {\n\t\tt.Skip(\"Parked process test only relevant on linux\")\n\t}\n\tprocstat := `88 (watchdog/13) P 2 0 0 0 -1 69238848 0 0 0 0 0 0 0 0 20 0 1 0 20 0 0 18446744073709551615 0 0 0 0 0 0 0 ` +\n\t\t`2147483647 0 1 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n`\n\tplugin := &Processes{\n\t\tLog: testutil.Logger{},\n\t\treadProcFile: func(string) ([]byte, error) {\n\t\t\treturn []byte(procstat), nil\n\t\t},\n\t\tforceProc: true,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"processes\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"blocked\":  0,\n\t\t\t\t\"dead\":     0,\n\t\t\t\t\"idle\":     0,\n\t\t\t\t\"paging\":   0,\n\t\t\t\t\"parked\":   1,\n\t\t\t\t\"running\":  0,\n\t\t\t\t\"sleeping\": 0,\n\t\t\t\t\"stopped\":  0,\n\t\t\t\t\"unknown\":  0,\n\t\t\t\t\"zombies\":  0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.IgnoreFields(\"total\", \"total_threads\"),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), options...)\n}\n\nfunc testExecPS(out string) func(_ bool) ([]byte, error) {\n\treturn func(_ bool) ([]byte, error) { return []byte(out), nil }\n}\n\n// struct for counting calls to testProcFile\ntype tester struct {\n\tcalls int64\n}\n\nfunc (t *tester) testProcFile(_ string) ([]byte, error) {\n\tt.calls++\n\treturn []byte(fmt.Sprintf(testProcStat, \"S\", \"2\")), nil\n}\n\nfunc (t *tester) testProcFile2(_ string) ([]byte, error) {\n\tt.calls++\n\treturn []byte(fmt.Sprintf(testProcStat2, \"S\", \"2\")), nil\n}\n\nfunc testExecPSError(_ bool) ([]byte, error) {\n\treturn []byte(\"\\nSTAT\\nD\\nI\\nL\\nR\\nR+\\nS\\nS+\\nSNs\\nSs\\nU\\nZ\\n\"), errors.New(\"error\")\n}\n\nconst testProcStat = `10 (rcuob/0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 ` +\n\t`2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n`\n\nconst testProcStat2 = `10 (rcuob 0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 ` +\n\t`2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n`\n"
  },
  {
    "path": "plugins/inputs/processes/processes_windows.go",
    "content": "//go:build windows\n\npackage processes\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\ntype Processes struct {\n\tLog telegraf.Logger\n}\n\nfunc (e *Processes) Init() error {\n\te.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Processes) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"processes\", func() telegraf.Input {\n\t\treturn &Processes{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/processes/sample.conf",
    "content": "# Get the number of processes and group them by status\n# This plugin ONLY supports non-Windows\n[[inputs.processes]]\n  ## Use sudo to run ps command on *BSD systems. Linux systems will read\n  ## /proc, so this does not apply there.\n  # use_sudo = false\n"
  },
  {
    "path": "plugins/inputs/procstat/README.md",
    "content": "# Procstat Input Plugin\n\nThis plugin allows to monitor the system resource usage of one or more\nprocesses. The plugin provides metrics about the individual processes as well as\naccumulated metrics on the number of PIDs returned on a search. Processes can\nbe filtered e.g. by regular expressions on the command, the user owning the\nprocess or the service that started the process.\n\n⭐ Telegraf v0.2.0\n🏷️ system\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  # supervisor_units = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the given information tag instead of a field\n  ## This allows to create unique metrics/series when collecting processes with\n  ## otherwise identical tags. However, please be careful as this can easily\n  ## result in a large number of series, especially with short-lived processes,\n  ## creating high cardinality at the output.\n  ## Available options are:\n  ##   cmdline   -- full commandline\n  ##   pid       -- ID of the process\n  ##   ppid      -- ID of the process' parent\n  ##   status    -- state of the process\n  ##   user      -- username owning the process\n  ## socket only options:\n  ##   protocol  -- protocol type of the process socket\n  ##   state     -- state of the process socket\n  ##   src       -- source address of the process socket (non-unix sockets)\n  ##   src_port  -- source port of the process socket (non-unix sockets)\n  ##   dest      -- destination address of the process socket (non-unix sockets)\n  ##   dest_port -- destination port of the process socket (non-unix sockets)\n  ##   name      -- name of the process socket (unix sockets only)\n  ## Available for procstat_lookup:\n  ##   level     -- level of the process filtering\n  # tag_with = []\n\n  ## Properties to collect\n  ## Available options are\n  ##   cpu     -- CPU usage statistics\n  ##   limits  -- set resource limits\n  ##   memory  -- memory usage statistics\n  ##   mmap    -- mapped memory usage statistics (caution: can cause high load)\n  ##   sockets -- socket statistics for protocols in 'socket_protocols'\n  # properties = [\"cpu\", \"limits\", \"memory\", \"mmap\"]\n\n  ## Protocol filter for the sockets property\n  ## Available options are\n  ##   all  -- all of the protocols below\n  ##   tcp4 -- TCP socket statistics for IPv4\n  ##   tcp6 -- TCP socket statistics for IPv6\n  ##   udp4 -- UDP socket statistics for IPv4\n  ##   udp6 -- UDP socket statistics for IPv6\n  ##   unix -- Unix socket statistics\n  # socket_protocols = [\"all\"]\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n\n  ## New-style filtering configuration (multiple filter sections are allowed)\n  # [[inputs.procstat.filter]]\n  #    ## Name of the filter added as 'filter' tag\n  #    name = \"shell\"\n  #\n  #    ## Service filters, only one is allowed\n  #    ## Systemd unit names (wildcards are supported)\n  #    # systemd_units = []\n  #    ## CGroup name or path (wildcards are supported)\n  #    # cgroups = []\n  #    ## Supervisor service names of hypervisorctl management\n  #    # supervisor_units = []\n  #    ## Windows service names\n  #    # win_service = []\n  #\n  #    ## Process filters, multiple are allowed\n  #    ## Regular expressions to use for matching against the full command\n  #    # patterns = ['.*']\n  #    ## List of users owning the process (wildcards are supported)\n  #    # users = ['*']\n  #    ## List of executable paths of the process (wildcards are supported)\n  #    # executables = ['*']\n  #    ## List of process names (wildcards are supported)\n  #    # process_names = ['*']\n  #    ## Recursion depth for determining children of the matched processes\n  #    ## A negative value means all children with infinite depth\n  #    # recursion_depth = 0\n```\n\n### Windows support\n\nThe plugin reports process information on Windows, however if you need more\nin-depth information about the process you may prefer using the\n`win_perf_counters` or `win_wmi` input plugins.\n\n### Darwin specifics\n\nIf you use this plugin with `supervisor_units` *and* `pattern` on Darwin, you\n**have to** use the `pgrep` finder as the underlying library relies on `pgrep`.\n\n### Permissions\n\nSome files or directories may require elevated permissions. As such a user may\nneed to provide telegraf with higher levels of permissions to access and produce\nmetrics.\n\n### Remote users on Posix systems\n\nTo resolve usernames of processes owned by remote users e.g. LDAP or NIS the\nplugin relies on the `id` command. This command must be available on the system,\nin the PATH and executable by Telegraf, otherwise the username cannot be\nresolved and the user-ID is used instead.\n\n## Metrics\n\nFor descriptions of these tags and fields, consider reading one of the\nfollowing:\n\n- [Linux Kernel /proc Filesystem][kernel /proc]\n- [proc manpage][manpage]\n\n[kernel /proc]: https://www.kernel.org/doc/html/latest/filesystems/proc.html\n[manpage]: https://man7.org/linux/man-pages/man5/proc.5.html\n\nBelow are an example set of tags and fields:\n\n- procstat\n  - tags:\n    - pid (if requested)\n    - cmdline (if requested)\n    - process_name\n    - pidfile (when defined)\n    - exe (when defined)\n    - pattern (when defined)\n    - user (when selected)\n    - systemd_unit (when defined)\n    - cgroup (when defined)\n    - cgroup_full (when cgroup or systemd_unit is used with glob)\n    - supervisor_unit (when defined)\n    - win_service (when defined)\n    - parent_pid (for child processes)\n    - child_level (for child processes)\n  - fields:\n    - child_major_faults (int)\n    - child_minor_faults (int)\n    - created_at (int) [epoch in nanoseconds]\n    - cpu_time (int)\n    - cpu_time_iowait (float) (zero for all OSes except Linux)\n    - cpu_time_system (float)\n    - cpu_time_user (float)\n    - cpu_usage (float)\n    - disk_read_bytes (int, Linux only, *telegraf* may need to be ran as **root**)\n    - disk_write_bytes (int, Linux only, *telegraf* may need to be ran as **root**)\n    - involuntary_context_switches (int)\n    - major_faults (int)\n    - memory_anonymous (int)\n    - memory_private_clean (int)\n    - memory_private_dirty (int)\n    - memory_pss (int)\n    - memory_referenced (int)\n    - memory_rss (int)\n    - memory_shared_clean (int)\n    - memory_shared_dirty (int)\n    - memory_size (int)\n    - memory_swap (int)\n    - memory_usage (float)\n    - memory_vms (int)\n    - minor_faults (int)\n    - nice_priority (int)\n    - num_fds (int, *telegraf* may need to be ran as **root**)\n    - num_threads (int)\n    - pid (int)\n    - ppid (int)\n    - status (string)\n    - read_bytes (int, *telegraf* may need to be ran as **root**)\n    - read_count (int, *telegraf* may need to be ran as **root**)\n    - realtime_priority (int)\n    - rlimit_cpu_time_hard (int)\n    - rlimit_cpu_time_soft (int)\n    - rlimit_file_locks_hard (int)\n    - rlimit_file_locks_soft (int)\n    - rlimit_memory_data_hard (int)\n    - rlimit_memory_data_soft (int)\n    - rlimit_memory_locked_hard (int)\n    - rlimit_memory_locked_soft (int)\n    - rlimit_memory_rss_hard (int)\n    - rlimit_memory_rss_soft (int)\n    - rlimit_memory_stack_hard (int)\n    - rlimit_memory_stack_soft (int)\n    - rlimit_memory_vms_hard (int)\n    - rlimit_memory_vms_soft (int)\n    - rlimit_nice_priority_hard (int)\n    - rlimit_nice_priority_soft (int)\n    - rlimit_num_fds_hard (int)\n    - rlimit_num_fds_soft (int)\n    - rlimit_realtime_priority_hard (int)\n    - rlimit_realtime_priority_soft (int)\n    - rlimit_signals_pending_hard (int)\n    - rlimit_signals_pending_soft (int)\n    - signals_pending (int)\n    - voluntary_context_switches (int)\n    - write_bytes (int, *telegraf* may need to be ran as **root**)\n    - write_count (int, *telegraf* may need to be ran as **root**)\n- procstat_lookup\n  - tags:\n    - exe\n    - pid_finder\n    - pid_file\n    - pattern\n    - prefix\n    - user\n    - systemd_unit\n    - cgroup\n    - supervisor_unit\n    - win_service\n    - result\n  - fields:\n    - pid_count (int)\n    - running (int)\n    - result_code (int, success = 0, lookup_error = 1)\n- procstat_socket (if configured, Linux only)\n  - tags:\n    - pid (if requested)\n    - protocol (if requested)\n    - cmdline (if requested)\n    - process_name\n    - pidfile (when defined)\n    - exe (when defined)\n    - pattern (when defined)\n    - user (when selected)\n    - systemd_unit (when defined)\n    - cgroup (when defined)\n    - cgroup_full (when cgroup or systemd_unit is used with glob)\n    - supervisor_unit (when defined)\n    - win_service (when defined)\n  - fields:\n    - protocol\n    - state\n    - pid\n    - src\n    - src_port (tcp and udp sockets only)\n    - dest (tcp and udp sockets only)\n    - dest_port (tcp and udp sockets only)\n    - bytes_received (tcp sockets only)\n    - bytes_sent (tcp sockets only)\n    - lost (tcp sockets only)\n    - retransmits (tcp sockets only)\n    - rx_queue\n    - tx_queue\n    - inode (unix sockets only)\n\n*NOTE: Resource limit > 2147483647 will be reported as 2147483647.*\n\n## Example Output\n\n```text\nprocstat_lookup,host=prash-laptop,pattern=influxd,pid_finder=pgrep,result=success pid_count=1i,running=1i,result_code=0i 1582089700000000000\nprocstat,host=prash-laptop,pattern=influxd,process_name=influxd,user=root involuntary_context_switches=151496i,child_minor_faults=1061i,child_major_faults=8i,cpu_time_user=2564.81,pid=32025i,major_faults=8609i,created_at=1580107536000000000i,voluntary_context_switches=1058996i,cpu_time_system=616.98,memory_swap=0i,memory_locked=0i,memory_usage=1.7797634601593018,num_threads=18i,cpu_time_iowait=0,memory_rss=148643840i,memory_vms=1435688960i,memory_data=0i,memory_stack=0i,minor_faults=1856550i 1582089700000000000\nprocstat_socket,host=prash-laptop,process_name=browser,protocol=tcp4 bytes_received=826987i,bytes_sent=32869i,dest=\"192.168.0.2\",dest_port=443i,lost=0i,pid=32025i,retransmits=0i,rx_queue=0i,src=\"192.168.0.1\",src_port=52106i,state=\"established\",tx_queue=0i 1582089700000000000\n```\n"
  },
  {
    "path": "plugins/inputs/procstat/filter.go",
    "content": "package procstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\n\t\"github.com/influxdata/telegraf\"\n\ttelegraf_filter \"github.com/influxdata/telegraf/filter\"\n)\n\ntype filter struct {\n\tName            string          `toml:\"name\"`\n\tPidFiles        []string        `toml:\"pid_files\"`\n\tSystemdUnits    []string        `toml:\"systemd_units\"`\n\tSupervisorUnits []string        `toml:\"supervisor_units\"`\n\tWinService      []string        `toml:\"win_services\"`\n\tCGroups         []string        `toml:\"cgroups\"`\n\tPatterns        []string        `toml:\"patterns\"`\n\tUsers           []string        `toml:\"users\"`\n\tExecutables     []string        `toml:\"executables\"`\n\tProcessNames    []string        `toml:\"process_names\"`\n\tRecursionDepth  int             `toml:\"recursion_depth\"`\n\tLog             telegraf.Logger `toml:\"-\"`\n\n\tfilterSupervisorUnit string\n\tfilterCmds           []*regexp.Regexp\n\tfilterUser           telegraf_filter.Filter\n\tfilterExecutable     telegraf_filter.Filter\n\tfilterProcessName    telegraf_filter.Filter\n\tfinder               *processFinder\n}\n\nfunc (f *filter) init() error {\n\tif f.Name == \"\" {\n\t\treturn errors.New(\"filter must be named\")\n\t}\n\n\t// Check for only one service selector being active\n\tvar active []string\n\tif len(f.PidFiles) > 0 {\n\t\tactive = append(active, \"pid_files\")\n\t}\n\tif len(f.CGroups) > 0 {\n\t\tactive = append(active, \"cgroups\")\n\t}\n\tif len(f.SystemdUnits) > 0 {\n\t\tactive = append(active, \"systemd_units\")\n\t}\n\tif len(f.SupervisorUnits) > 0 {\n\t\tactive = append(active, \"supervisor_units\")\n\t}\n\tif len(f.WinService) > 0 {\n\t\tactive = append(active, \"win_services\")\n\t}\n\tif len(active) > 1 {\n\t\treturn fmt.Errorf(\"cannot select multiple services %q\", strings.Join(active, \", \"))\n\t}\n\n\t// Prepare the filters\n\tf.filterCmds = make([]*regexp.Regexp, 0, len(f.Patterns))\n\tfor _, p := range f.Patterns {\n\t\tre, err := regexp.Compile(p)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"compiling pattern %q of filter %q failed: %w\", p, f.Name, err)\n\t\t}\n\t\tf.filterCmds = append(f.filterCmds, re)\n\t}\n\n\tf.filterSupervisorUnit = strings.TrimSpace(strings.Join(f.SupervisorUnits, \" \"))\n\n\tvar err error\n\tif f.filterUser, err = telegraf_filter.Compile(f.Users); err != nil {\n\t\treturn fmt.Errorf(\"compiling users filter for %q failed: %w\", f.Name, err)\n\t}\n\tif f.filterExecutable, err = telegraf_filter.Compile(f.Executables); err != nil {\n\t\treturn fmt.Errorf(\"compiling executables filter for %q failed: %w\", f.Name, err)\n\t}\n\tif f.filterProcessName, err = telegraf_filter.Compile(f.ProcessNames); err != nil {\n\t\treturn fmt.Errorf(\"compiling process-names filter for %q failed: %w\", f.Name, err)\n\t}\n\n\t// Setup the process finder\n\tf.finder = newProcessFinder(f.Log)\n\treturn nil\n}\n\nfunc (f *filter) applyFilter() ([]processGroup, error) {\n\t// Determine processes on service level. if there is no constraint on the\n\t// services, use all processes for matching.\n\tvar groups []processGroup\n\tswitch {\n\tcase len(f.PidFiles) > 0:\n\t\tg, err := f.finder.findByPidFiles(f.PidFiles)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, g...)\n\tcase len(f.CGroups) > 0:\n\t\tg, err := findByCgroups(f.CGroups)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, g...)\n\tcase len(f.SystemdUnits) > 0:\n\t\tg, err := findBySystemdUnits(f.SystemdUnits)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, g...)\n\tcase f.filterSupervisorUnit != \"\":\n\t\tg, err := findBySupervisorUnits(f.filterSupervisorUnit)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, g...)\n\tcase len(f.WinService) > 0:\n\t\tg, err := findByWindowsServices(f.WinService)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, g...)\n\tdefault:\n\t\tprocs, err := gopsprocess.Processes()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroups = append(groups, processGroup{processes: procs, tags: make(map[string]string)})\n\t}\n\n\t// Filter by additional properties such as users, patterns etc\n\tresult := make([]processGroup, 0, len(groups))\n\tfor _, g := range groups {\n\t\tvar matched []*gopsprocess.Process\n\t\tfor _, p := range g.processes {\n\t\t\t// Users\n\t\t\tif f.filterUser != nil {\n\t\t\t\tif username := username(p); username == \"\" || !f.filterUser.Match(username) {\n\t\t\t\t\t// This can happen if we don't have permissions or the process no longer exists\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Executables\n\t\t\tif f.filterExecutable != nil {\n\t\t\t\tif exe, err := p.Exe(); err != nil || !f.filterExecutable.Match(exe) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process names\n\t\t\tif f.filterProcessName != nil {\n\t\t\t\tif name, err := p.Name(); err != nil || !f.filterProcessName.Match(name) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Patterns\n\t\t\tif len(f.filterCmds) > 0 {\n\t\t\t\tcmd, err := p.Cmdline()\n\t\t\t\tif err != nil {\n\t\t\t\t\t// This can happen if we don't have permissions or the process no longer exists\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvar found bool\n\t\t\t\tfor _, re := range f.filterCmds {\n\t\t\t\t\tif re.MatchString(cmd) {\n\t\t\t\t\t\tfound = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif !found {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmatched = append(matched, p)\n\t\t}\n\t\tresult = append(result, processGroup{processes: matched, tags: g.tags})\n\t}\n\n\t// Resolve children down to the requested depth\n\tprevious := result\n\tfor depth := 0; depth < f.RecursionDepth || f.RecursionDepth < 0; depth++ {\n\t\tchildren := make([]processGroup, 0, len(previous))\n\t\tfor _, group := range previous {\n\t\t\tfor _, p := range group.processes {\n\t\t\t\tc, err := getChildren(p)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"unable to get children of process %d: %w\", p.Pid, err)\n\t\t\t\t}\n\t\t\t\tif len(c) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ttags := make(map[string]string, len(group.tags)+1)\n\t\t\t\tfor k, v := range group.tags {\n\t\t\t\t\ttags[k] = v\n\t\t\t\t}\n\t\t\t\ttags[\"parent_pid\"] = strconv.FormatInt(int64(p.Pid), 10)\n\n\t\t\t\tchildren = append(children, processGroup{\n\t\t\t\t\tprocesses: c,\n\t\t\t\t\ttags:      tags,\n\t\t\t\t\tlevel:     depth + 1,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tif len(children) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tresult = append(result, children...)\n\t\tprevious = children\n\t}\n\n\treturn result, nil\n}\n\nfunc getChildren(p *gopsprocess.Process) ([]*gopsprocess.Process, error) {\n\tchildren, err := p.Children()\n\t// Check for cases that do not really mean error but rather means that there\n\t// is no match.\n\tswitch {\n\tcase err == nil,\n\t\terrors.Is(err, gopsprocess.ErrorNoChildren),\n\t\tstrings.Contains(err.Error(), \"exit status 1\"):\n\t\treturn children, nil\n\t}\n\treturn nil, fmt.Errorf(\"unable to get children of process %d: %w\", p.Pid, err)\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/native_finder.go",
    "content": "package procstat\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n)\n\n// NativeFinder uses gopsutil to find processes\ntype NativeFinder struct{}\n\n// Uid will return all pids for the given user\nfunc (*NativeFinder) uid(user string) ([]pid, error) {\n\tvar dst []pid\n\tprocs, err := gopsprocess.Processes()\n\tif err != nil {\n\t\treturn dst, err\n\t}\n\tfor _, p := range procs {\n\t\t// Skip this process if we cannot determine the username e.g. due\n\t\t// to the fact that the process no longer exists.\n\t\tif username := username(p); username != \"\" && username == user {\n\t\t\tdst = append(dst, pid(p.Pid))\n\t\t}\n\t}\n\treturn dst, nil\n}\n\n// PidFile returns the pid from the pid file given.\nfunc (*NativeFinder) pidFile(path string) ([]pid, error) {\n\tpidString, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read pidfile %q: %w\", path, err)\n\t}\n\tprocessID, err := strconv.ParseInt(strings.TrimSpace(string(pidString)), 10, 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []pid{pid(processID)}, nil\n}\n\n// FullPattern matches on the command line when the process was executed\nfunc (*NativeFinder) fullPattern(pattern string) ([]pid, error) {\n\tvar pids []pid\n\tregxPattern, err := regexp.Compile(pattern)\n\tif err != nil {\n\t\treturn pids, err\n\t}\n\tprocs, err := fastProcessList()\n\tif err != nil {\n\t\treturn pids, err\n\t}\n\tfor _, p := range procs {\n\t\tcmd, err := p.Cmdline()\n\t\tif err != nil {\n\t\t\t// skip, this can be caused by the pid no longer exists, or you don't have permissions to access it\n\t\t\tcontinue\n\t\t}\n\t\tif regxPattern.MatchString(cmd) {\n\t\t\tpids = append(pids, pid(p.Pid))\n\t\t}\n\t}\n\treturn pids, err\n}\n\n// Children matches children pids on the command line when the process was executed\nfunc (*NativeFinder) children(processID pid) ([]pid, error) {\n\t// Get all running processes\n\tp, err := gopsprocess.NewProcess(int32(processID))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting process %d failed: %w\", processID, err)\n\t}\n\n\t// Get all children of the current process\n\tchildren, err := p.Children()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to get children of process %d: %w\", p.Pid, err)\n\t}\n\tpids := make([]pid, 0, len(children))\n\tfor _, child := range children {\n\t\tpids = append(pids, pid(child.Pid))\n\t}\n\n\treturn pids, err\n}\n\nfunc fastProcessList() ([]*gopsprocess.Process, error) {\n\tpids, err := gopsprocess.Pids()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]*gopsprocess.Process, 0, len(pids))\n\tfor _, pid := range pids {\n\t\tresult = append(result, &gopsprocess.Process{Pid: pid})\n\t}\n\treturn result, nil\n}\n\n// Pattern matches on the process name\nfunc (*NativeFinder) pattern(pattern string) ([]pid, error) {\n\tvar pids []pid\n\tregxPattern, err := regexp.Compile(pattern)\n\tif err != nil {\n\t\treturn pids, err\n\t}\n\tprocs, err := fastProcessList()\n\tif err != nil {\n\t\treturn pids, err\n\t}\n\tfor _, p := range procs {\n\t\tname, err := processName(p)\n\t\tif err != nil {\n\t\t\t// skip, this can be caused by the pid no longer exists, or you don't have permissions to access it\n\t\t\tcontinue\n\t\t}\n\t\tif regxPattern.MatchString(name) {\n\t\t\tpids = append(pids, pid(p.Pid))\n\t\t}\n\t}\n\treturn pids, err\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/native_finder_test.go",
    "content": "package procstat\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc BenchmarkPattern(b *testing.B) {\n\tfinder := &NativeFinder{}\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := finder.pattern(\".*\")\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc BenchmarkFullPattern(b *testing.B) {\n\tfinder := &NativeFinder{}\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := finder.fullPattern(\".*\")\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc TestChildPattern(t *testing.T) {\n\tif runtime.GOOS == \"windows\" || runtime.GOOS == \"darwin\" {\n\t\tt.Skip(\"Skipping test on unsupported platform\")\n\t}\n\n\t// Get our own process name\n\tparentName, err := os.Executable()\n\trequire.NoError(t, err)\n\n\t// Spawn two child processes and get their PIDs\n\texpected := make([]pid, 0, 2)\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\t// First process\n\tcmd1 := exec.CommandContext(ctx, \"/bin/sh\")\n\trequire.NoError(t, cmd1.Start(), \"starting first command failed\")\n\texpected = append(expected, pid(cmd1.Process.Pid))\n\n\t// Second process\n\tcmd2 := exec.CommandContext(ctx, \"/bin/sh\")\n\trequire.NoError(t, cmd2.Start(), \"starting first command failed\")\n\texpected = append(expected, pid(cmd2.Process.Pid))\n\n\t// Use the plugin to find the children\n\tfinder := &NativeFinder{}\n\tparent, err := finder.pattern(parentName)\n\trequire.NoError(t, err)\n\trequire.Len(t, parent, 1)\n\tchildren, err := finder.children(parent[0])\n\trequire.NoError(t, err)\n\trequire.ElementsMatch(t, expected, children)\n}\n\nfunc TestGather_RealPatternIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\tpg := &NativeFinder{}\n\tpids, err := pg.pattern(`procstat`)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, pids)\n}\n\nfunc TestGather_RealFullPatternIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\tif runtime.GOOS != \"windows\" {\n\t\tt.Skip(\"Skipping integration test on Non-Windows OS\")\n\t}\n\tpg := &NativeFinder{}\n\tpids, err := pg.fullPattern(`%procstat%`)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, pids)\n}\n\nfunc TestGather_RealUserIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\tcurrentUser, err := user.Current()\n\trequire.NoError(t, err)\n\n\tpg := &NativeFinder{}\n\tpids, err := pg.uid(currentUser.Username)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, pids)\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/os_linux.go",
    "content": "//go:build linux\n\npackage procstat\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/coreos/go-systemd/v22/dbus\"\n\t\"github.com/prometheus/procfs\"\n\tgopsnet \"github.com/shirou/gopsutil/v4/net\"\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\t\"github.com/vishvananda/netlink\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc processName(p *gopsprocess.Process) (string, error) {\n\treturn p.Exe()\n}\n\nfunc username(p *gopsprocess.Process) string {\n\t// Use the local lookup\n\tn, err := p.Username()\n\tif err == nil {\n\t\treturn n\n\t}\n\n\t// Exit on errors other than unknown user-ID\n\tvar uerr user.UnknownUserIdError\n\tif !errors.As(err, &uerr) {\n\t\treturn \"\"\n\t}\n\n\t// Try to run the `id` command on the UID of the process to resolve remote\n\t// users such as LDAP or NIS.\n\tuid := strconv.Itoa(int(uerr))\n\tbuf, err := exec.Command(\"id\", \"-nu\", uid).Output()\n\tif n := strings.TrimSpace(string(buf)); err == nil && n != \"\" {\n\t\treturn n\n\t}\n\n\t// We were either not able to run the command or the user cannot be\n\t// resolved so just return the user ID instead.\n\treturn uid\n}\n\nfunc queryPidWithWinServiceName(_ string) (uint32, error) {\n\treturn 0, errors.New(\"os not supporting win_service option\")\n}\n\nfunc collectMemmap(proc process, prefix string, fields map[string]any) {\n\tmemMapStats, err := proc.MemoryMaps(true)\n\tif err == nil && len(*memMapStats) == 1 {\n\t\tmemMap := (*memMapStats)[0]\n\t\tfields[prefix+\"memory_size\"] = memMap.Size\n\t\tfields[prefix+\"memory_pss\"] = memMap.Pss\n\t\tfields[prefix+\"memory_shared_clean\"] = memMap.SharedClean\n\t\tfields[prefix+\"memory_shared_dirty\"] = memMap.SharedDirty\n\t\tfields[prefix+\"memory_private_clean\"] = memMap.PrivateClean\n\t\tfields[prefix+\"memory_private_dirty\"] = memMap.PrivateDirty\n\t\tfields[prefix+\"memory_referenced\"] = memMap.Referenced\n\t\tfields[prefix+\"memory_anonymous\"] = memMap.Anonymous\n\t\tfields[prefix+\"memory_swap\"] = memMap.Swap\n\t}\n}\n\nfunc findBySystemdUnits(units []string) ([]processGroup, error) {\n\tctx := context.Background()\n\tconn, err := dbus.NewSystemConnectionContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect to systemd: %w\", err)\n\t}\n\tdefer conn.Close()\n\n\tsdunits, err := conn.ListUnitFilesByPatternsContext(ctx, []string{\"enabled\", \"disabled\", \"static\"}, units)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list units: %w\", err)\n\t}\n\n\tgroups := make([]processGroup, 0, len(sdunits))\n\tfor _, u := range sdunits {\n\t\tname := path.Base(u.Path)\n\t\tprop, err := conn.GetUnitTypePropertyContext(ctx, name, \"Service\", \"MainPID\")\n\t\tif err != nil {\n\t\t\t// This unit might not be a service or similar\n\t\t\tcontinue\n\t\t}\n\t\traw := prop.Value.Value()\n\t\tpid, ok := raw.(uint32)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse PID %v of unit %q: invalid type %T\", raw, u, raw)\n\t\t}\n\t\tp, err := gopsprocess.NewProcess(int32(pid))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to find process for PID %d of unit %q: %w\", pid, u, err)\n\t\t}\n\t\tgroups = append(groups, processGroup{\n\t\t\tprocesses: []*gopsprocess.Process{p},\n\t\t\ttags:      map[string]string{\"systemd_unit\": name},\n\t\t})\n\t}\n\n\treturn groups, nil\n}\n\nfunc findByWindowsServices(_ []string) ([]processGroup, error) {\n\treturn nil, nil\n}\n\nfunc collectTotalReadWrite(proc process) (r, w uint64, err error) {\n\tprocPath := internal.GetProcPath()\n\tfs, err := procfs.NewFS(procPath)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\tp, err := fs.Proc(int(proc.pid()))\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\tstat, err := p.IO()\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\treturn stat.RChar, stat.WChar, nil\n}\n\n/* Socket statistics functions */\nfunc socketStateName(s uint8) string {\n\tswitch s {\n\tcase unix.BPF_TCP_ESTABLISHED:\n\t\treturn \"established\"\n\tcase unix.BPF_TCP_SYN_SENT:\n\t\treturn \"syn-sent\"\n\tcase unix.BPF_TCP_SYN_RECV:\n\t\treturn \"syn-recv\"\n\tcase unix.BPF_TCP_FIN_WAIT1:\n\t\treturn \"fin-wait1\"\n\tcase unix.BPF_TCP_FIN_WAIT2:\n\t\treturn \"fin-wait2\"\n\tcase unix.BPF_TCP_TIME_WAIT:\n\t\treturn \"time-wait\"\n\tcase unix.BPF_TCP_CLOSE:\n\t\treturn \"closed\"\n\tcase unix.BPF_TCP_CLOSE_WAIT:\n\t\treturn \"close-wait\"\n\tcase unix.BPF_TCP_LAST_ACK:\n\t\treturn \"last-ack\"\n\tcase unix.BPF_TCP_LISTEN:\n\t\treturn \"listen\"\n\tcase unix.BPF_TCP_CLOSING:\n\t\treturn \"closing\"\n\tcase unix.BPF_TCP_NEW_SYN_RECV:\n\t\treturn \"sync-recv\"\n\t}\n\n\treturn \"unknown\"\n}\n\nfunc socketTypeName(t uint8) string {\n\tswitch t {\n\tcase syscall.SOCK_STREAM:\n\t\treturn \"stream\"\n\tcase syscall.SOCK_DGRAM:\n\t\treturn \"dgram\"\n\tcase syscall.SOCK_RAW:\n\t\treturn \"raw\"\n\tcase syscall.SOCK_RDM:\n\t\treturn \"rdm\"\n\tcase syscall.SOCK_SEQPACKET:\n\t\treturn \"seqpacket\"\n\tcase syscall.SOCK_DCCP:\n\t\treturn \"dccp\"\n\tcase syscall.SOCK_PACKET:\n\t\treturn \"packet\"\n\t}\n\n\treturn \"unknown\"\n}\n\nfunc mapFdToInode(pid int32, fd uint32) (uint32, error) {\n\troot := internal.GetProcPath()\n\tfn := fmt.Sprintf(\"%s/%d/fd/%d\", root, pid, fd)\n\tlink, err := os.Readlink(fn)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"reading link failed: %w\", err)\n\t}\n\ttarget := strings.TrimPrefix(link, \"socket:[\")\n\ttarget = strings.TrimSuffix(target, \"]\")\n\tinode, err := strconv.ParseUint(target, 10, 32)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"parsing link %q: %w\", link, err)\n\t}\n\n\treturn uint32(inode), nil\n}\n\nfunc statsTCP(conns []gopsnet.ConnectionStat, family uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// For TCP we need the inode for each connection to relate the connection\n\t// statistics to the actual process socket. Therefore, map the\n\t// file-descriptors to inodes using the /proc/<pid>/fd entries.\n\tinodes := make(map[uint32]gopsnet.ConnectionStat, len(conns))\n\tfor _, c := range conns {\n\t\tinode, err := mapFdToInode(c.Pid, c.Fd)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"mapping fd %d of pid %d failed: %w\", c.Fd, c.Pid, err)\n\t\t}\n\t\tinodes[inode] = c\n\t}\n\n\t// Get the TCP socket statistics from the netlink socket.\n\tresponses, err := netlink.SocketDiagTCPInfo(family)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"connecting to diag socket failed: %w\", err)\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0)\n\tfor _, r := range responses {\n\t\tc, found := inodes[r.InetDiagMsg.INode]\n\t\tif !found {\n\t\t\t// The inode does not belong to the process.\n\t\t\tcontinue\n\t\t}\n\n\t\tvar proto string\n\t\tswitch r.InetDiagMsg.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"tcp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"tcp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":       proto,\n\t\t\t\"state\":          socketStateName(r.InetDiagMsg.State),\n\t\t\t\"pid\":            c.Pid,\n\t\t\t\"src\":            r.InetDiagMsg.ID.Source.String(),\n\t\t\t\"src_port\":       r.InetDiagMsg.ID.SourcePort,\n\t\t\t\"dest\":           r.InetDiagMsg.ID.Destination.String(),\n\t\t\t\"dest_port\":      r.InetDiagMsg.ID.DestinationPort,\n\t\t\t\"bytes_received\": r.TCPInfo.Bytes_received,\n\t\t\t\"bytes_sent\":     r.TCPInfo.Bytes_sent,\n\t\t\t\"lost\":           r.TCPInfo.Lost,\n\t\t\t\"retransmits\":    r.TCPInfo.Retransmits,\n\t\t\t\"rx_queue\":       r.InetDiagMsg.RQueue,\n\t\t\t\"tx_queue\":       r.InetDiagMsg.WQueue,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUDP(conns []gopsnet.ConnectionStat, family uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// For UDP we need the inode for each connection to relate the connection\n\t// statistics to the actual process socket. Therefore, map the\n\t// file-descriptors to inodes using the /proc/<pid>/fd entries.\n\tinodes := make(map[uint32]gopsnet.ConnectionStat, len(conns))\n\tfor _, c := range conns {\n\t\tinode, err := mapFdToInode(c.Pid, c.Fd)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"mapping fd %d of pid %d failed: %w\", c.Fd, c.Pid, err)\n\t\t}\n\t\tinodes[inode] = c\n\t}\n\n\t// Get the UDP socket statistics from the netlink socket.\n\tresponses, err := netlink.SocketDiagUDPInfo(family)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"connecting to diag socket failed: %w\", err)\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0)\n\tfor _, r := range responses {\n\t\tc, found := inodes[r.InetDiagMsg.INode]\n\t\tif !found {\n\t\t\t// The inode does not belong to the process.\n\t\t\tcontinue\n\t\t}\n\n\t\tvar proto string\n\t\tswitch r.InetDiagMsg.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"udp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"udp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":  proto,\n\t\t\t\"state\":     socketStateName(r.InetDiagMsg.State),\n\t\t\t\"pid\":       c.Pid,\n\t\t\t\"src\":       r.InetDiagMsg.ID.Source.String(),\n\t\t\t\"src_port\":  r.InetDiagMsg.ID.SourcePort,\n\t\t\t\"dest\":      r.InetDiagMsg.ID.Destination.String(),\n\t\t\t\"dest_port\": r.InetDiagMsg.ID.DestinationPort,\n\t\t\t\"rx_queue\":  r.InetDiagMsg.RQueue,\n\t\t\t\"tx_queue\":  r.InetDiagMsg.WQueue,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUnix(conns []gopsnet.ConnectionStat) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// We need to read the inode for each connection to relate the connection\n\t// statistics to the actual process socket. Therefore, map the\n\t// file-descriptors to inodes using the /proc/<pid>/fd entries.\n\tinodes := make(map[uint32]gopsnet.ConnectionStat, len(conns))\n\tfor _, c := range conns {\n\t\tinode, err := mapFdToInode(c.Pid, c.Fd)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"mapping fd %d of pid %d failed: %w\", c.Fd, c.Pid, err)\n\t\t}\n\t\tinodes[inode] = c\n\t}\n\n\t// Get the UDP socket statistics from the netlink socket.\n\tresponses, err := netlink.UnixSocketDiagInfo()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"connecting to diag socket failed: %w\", err)\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0)\n\tfor _, r := range responses {\n\t\t// Check if the inode belongs to the process and skip otherwise\n\t\tc, found := inodes[r.DiagMsg.INode]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := c.Laddr.IP\n\t\tif name == \"\" {\n\t\t\tname = fmt.Sprintf(\"inode-%d\", r.DiagMsg.INode)\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\": \"unix\",\n\t\t\t\"type\":     \"stream\",\n\t\t\t\"state\":    socketStateName(r.DiagMsg.State),\n\t\t\t\"pid\":      c.Pid,\n\t\t\t\"name\":     name,\n\t\t\t\"rx_queue\": r.Queue.RQueue,\n\t\t\t\"tx_queue\": r.Queue.WQueue,\n\t\t\t\"inode\":    r.DiagMsg.INode,\n\t\t}\n\t\tif r.Peer != nil {\n\t\t\tfields[\"peer\"] = *r.Peer\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\t// Diagnosis only works for stream sockets, so add all non-stream sockets\n\t// of the process without further data\n\tfor inode, c := range inodes {\n\t\tif c.Type == syscall.SOCK_STREAM {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := c.Laddr.IP\n\t\tif name == \"\" {\n\t\t\tname = fmt.Sprintf(\"inode-%d\", inode)\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\": \"unix\",\n\t\t\t\"type\":     socketTypeName(uint8(c.Type)),\n\t\t\t\"state\":    \"close\",\n\t\t\t\"pid\":      c.Pid,\n\t\t\t\"name\":     name,\n\t\t\t\"rx_queue\": uint32(0),\n\t\t\t\"tx_queue\": uint32(0),\n\t\t\t\"inode\":    inode,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/os_others.go",
    "content": "//go:build !linux && !windows\n\npackage procstat\n\nimport (\n\t\"errors\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\tgopsnet \"github.com/shirou/gopsutil/v4/net\"\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n)\n\nfunc processName(p *gopsprocess.Process) (string, error) {\n\treturn p.Exe()\n}\n\nfunc username(p *gopsprocess.Process) string {\n\t// Use the local lookup\n\tn, err := p.Username()\n\tif err == nil {\n\t\treturn n\n\t}\n\n\t// Exit on errors other than unknown user-ID\n\tvar uerr user.UnknownUserIdError\n\tif !errors.As(err, &uerr) {\n\t\treturn \"\"\n\t}\n\n\t// Try to run the `id` command on the UID of the process to resolve remote\n\t// users such as LDAP or NIS.\n\tuid := strconv.Itoa(int(uerr))\n\tbuf, err := exec.Command(\"id\", \"-nu\", uid).Output()\n\tif n := strings.TrimSpace(string(buf)); err == nil && n != \"\" {\n\t\treturn n\n\t}\n\n\t// We were either not able to run the command or the user cannot be\n\t// resolved so just return the user ID instead.\n\treturn uid\n}\n\nfunc queryPidWithWinServiceName(string) (uint32, error) {\n\treturn 0, errors.New(\"os not supporting win_service option\")\n}\n\nfunc collectMemmap(process, string, map[string]any) {}\n\nfunc findBySystemdUnits([]string) ([]processGroup, error) {\n\treturn nil, nil\n}\n\nfunc findByWindowsServices([]string) ([]processGroup, error) {\n\treturn nil, nil\n}\n\nfunc collectTotalReadWrite(process) (r, w uint64, err error) {\n\treturn 0, 0, errors.ErrUnsupported\n}\n\nfunc statsTCP(conns []gopsnet.ConnectionStat, _ uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0, len(conns))\n\tfor _, c := range conns {\n\t\tvar proto string\n\t\tswitch c.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"tcp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"tcp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":  proto,\n\t\t\t\"state\":     c.Status,\n\t\t\t\"pid\":       c.Pid,\n\t\t\t\"src\":       c.Laddr.IP,\n\t\t\t\"src_port\":  c.Laddr.Port,\n\t\t\t\"dest\":      c.Raddr.IP,\n\t\t\t\"dest_port\": c.Raddr.Port,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUDP(conns []gopsnet.ConnectionStat, _ uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0, len(conns))\n\tfor _, c := range conns {\n\t\tvar proto string\n\t\tswitch c.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"udp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"udp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":  proto,\n\t\t\t\"state\":     c.Status,\n\t\t\t\"pid\":       c.Pid,\n\t\t\t\"src\":       c.Laddr.IP,\n\t\t\t\"src_port\":  c.Laddr.Port,\n\t\t\t\"dest\":      c.Raddr.IP,\n\t\t\t\"dest_port\": c.Raddr.Port,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUnix([]gopsnet.ConnectionStat) ([]map[string]interface{}, error) {\n\treturn nil, errors.ErrUnsupported\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/os_windows.go",
    "content": "//go:build windows\n\npackage procstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\tgopsnet \"github.com/shirou/gopsutil/v4/net\"\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/svc/mgr\"\n)\n\nfunc processName(p *gopsprocess.Process) (string, error) {\n\treturn p.Name()\n}\n\nfunc username(p *gopsprocess.Process) string {\n\tif n, err := p.Username(); err == nil {\n\t\treturn n\n\t}\n\treturn \"\"\n}\n\nfunc getService(name string) (*mgr.Service, error) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer m.Disconnect()\n\n\tsrv, err := m.OpenService(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn srv, nil\n}\n\nfunc queryPidWithWinServiceName(winServiceName string) (uint32, error) {\n\tsrv, err := getService(winServiceName)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar p *windows.SERVICE_STATUS_PROCESS\n\tvar bytesNeeded uint32\n\tvar buf []byte\n\n\terr = windows.QueryServiceStatusEx(srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded)\n\tif !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {\n\t\treturn 0, err\n\t}\n\n\tbuf = make([]byte, bytesNeeded)\n\tp = (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])) //nolint:gosec // G103: Valid use of unsafe call to create SERVICE_STATUS_PROCESS\n\tif err := windows.QueryServiceStatusEx(srv.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn p.ProcessId, nil\n}\n\nfunc collectMemmap(process, string, map[string]any) {}\n\nfunc findBySystemdUnits([]string) ([]processGroup, error) {\n\treturn nil, nil\n}\n\nfunc findByWindowsServices(services []string) ([]processGroup, error) {\n\tgroups := make([]processGroup, 0, len(services))\n\tfor _, service := range services {\n\t\tpid, err := queryPidWithWinServiceName(service)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to query PID of service %q: %w\", service, err)\n\t\t}\n\n\t\tp, err := gopsprocess.NewProcess(int32(pid))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to find process for PID %d of service %q: %w\", pid, service, err)\n\t\t}\n\n\t\tgroups = append(groups, processGroup{\n\t\t\tprocesses: []*gopsprocess.Process{p},\n\t\t\ttags:      map[string]string{\"win_service\": service},\n\t\t})\n\t}\n\n\treturn groups, nil\n}\n\nfunc collectTotalReadWrite(process) (r, w uint64, err error) {\n\treturn 0, 0, errors.ErrUnsupported\n}\n\nfunc statsTCP(conns []gopsnet.ConnectionStat, _ uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0, len(conns))\n\tfor _, c := range conns {\n\t\tvar proto string\n\t\tswitch c.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"tcp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"tcp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":  proto,\n\t\t\t\"state\":     c.Status,\n\t\t\t\"pid\":       c.Pid,\n\t\t\t\"src\":       c.Laddr.IP,\n\t\t\t\"src_port\":  c.Laddr.Port,\n\t\t\t\"dest\":      c.Raddr.IP,\n\t\t\t\"dest_port\": c.Raddr.Port,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUDP(conns []gopsnet.ConnectionStat, _ uint8) ([]map[string]interface{}, error) {\n\tif len(conns) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Filter the responses via the inodes belonging to the process\n\tfieldslist := make([]map[string]interface{}, 0, len(conns))\n\tfor _, c := range conns {\n\t\tvar proto string\n\t\tswitch c.Family {\n\t\tcase syscall.AF_INET:\n\t\t\tproto = \"udp4\"\n\t\tcase syscall.AF_INET6:\n\t\t\tproto = \"udp6\"\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"protocol\":  proto,\n\t\t\t\"state\":     c.Status,\n\t\t\t\"pid\":       c.Pid,\n\t\t\t\"src\":       c.Laddr.IP,\n\t\t\t\"src_port\":  c.Laddr.Port,\n\t\t\t\"dest\":      c.Raddr.IP,\n\t\t\t\"dest_port\": c.Raddr.Port,\n\t\t}\n\t\tfieldslist = append(fieldslist, fields)\n\t}\n\n\treturn fieldslist, nil\n}\n\nfunc statsUnix([]gopsnet.ConnectionStat) ([]map[string]interface{}, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/pgrep.go",
    "content": "package procstat\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// Implementation of PIDGatherer that execs pgrep to find processes\ntype pgrep struct {\n\tpath string\n}\n\nfunc newPgrepFinder() (pidFinder, error) {\n\tpath, err := exec.LookPath(\"pgrep\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not find pgrep binary: %w\", err)\n\t}\n\treturn &pgrep{path}, nil\n}\n\nfunc (*pgrep) pidFile(path string) ([]pid, error) {\n\tpidString, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read pidfile %q: %w\",\n\t\t\tpath, err)\n\t}\n\tprocessID, err := strconv.ParseInt(strings.TrimSpace(string(pidString)), 10, 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []pid{pid(processID)}, nil\n}\n\nfunc (pg *pgrep) pattern(pattern string) ([]pid, error) {\n\targs := []string{pattern}\n\treturn pg.find(args)\n}\n\nfunc (pg *pgrep) uid(user string) ([]pid, error) {\n\targs := []string{\"-u\", user}\n\treturn pg.find(args)\n}\n\nfunc (pg *pgrep) fullPattern(pattern string) ([]pid, error) {\n\targs := []string{\"-f\", pattern}\n\treturn pg.find(args)\n}\n\nfunc (pg *pgrep) children(pid pid) ([]pid, error) {\n\targs := []string{\"-P\", strconv.FormatInt(int64(pid), 10)}\n\treturn pg.find(args)\n}\n\nfunc (pg *pgrep) find(args []string) ([]pid, error) {\n\t// Execute pgrep with the given arguments\n\tbuf, err := exec.Command(pg.path, args...).Output()\n\tif err != nil {\n\t\t// Exit code 1 means \"no processes found\" so we should not return\n\t\t// an error in this case.\n\t\tif status, _ := internal.ExitStatus(err); status == 1 {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error running %q: %w\", pg.path, err)\n\t}\n\tout := string(buf)\n\n\t// Parse the command output to extract the PIDs\n\tfields := strings.Fields(out)\n\tpids := make([]pid, 0, len(fields))\n\tfor _, field := range fields {\n\t\tprocessID, err := strconv.ParseInt(field, 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpids = append(pids, pid(processID))\n\t}\n\treturn pids, nil\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/process.go",
    "content": "package procstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"syscall\"\n\t\"time\"\n\n\tgopsnet \"github.com/shirou/gopsutil/v4/net\"\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\ntype process interface {\n\tName() (string, error)\n\tMemoryMaps(bool) (*[]gopsprocess.MemoryMapsStat, error)\n\tpid() pid\n\tsetTag(string, string)\n\tmetrics(string, *collectionConfig, time.Time) ([]telegraf.Metric, error)\n}\n\ntype pidFinder interface {\n\tpidFile(path string) ([]pid, error)\n\tpattern(pattern string) ([]pid, error)\n\tuid(user string) ([]pid, error)\n\tfullPattern(path string) ([]pid, error)\n\tchildren(pid pid) ([]pid, error)\n}\n\ntype proc struct {\n\thasCPUTimes bool\n\ttags        map[string]string\n\t*gopsprocess.Process\n}\n\nfunc newProc(pid pid) (process, error) {\n\tp, err := gopsprocess.NewProcess(int32(pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tproc := &proc{\n\t\tProcess:     p,\n\t\thasCPUTimes: false,\n\t\ttags:        make(map[string]string),\n\t}\n\treturn proc, nil\n}\n\nfunc (p *proc) pid() pid {\n\treturn pid(p.Process.Pid)\n}\n\nfunc (p *proc) setTag(k, v string) {\n\tp.tags[k] = v\n}\n\nfunc (p *proc) percent(_ time.Duration) (float64, error) {\n\tcpuPerc, err := p.Process.Percent(time.Duration(0))\n\tif !p.hasCPUTimes && err == nil {\n\t\tp.hasCPUTimes = true\n\t\treturn 0, errors.New(\"must call Percent twice to compute percent cpu\")\n\t}\n\treturn cpuPerc, err\n}\n\n// Add metrics a single process\nfunc (p *proc) metrics(prefix string, cfg *collectionConfig, t time.Time) ([]telegraf.Metric, error) {\n\tif prefix != \"\" {\n\t\tprefix += \"_\"\n\t}\n\n\tfields := make(map[string]interface{})\n\tnumThreads, err := p.NumThreads()\n\tif err == nil {\n\t\tfields[prefix+\"num_threads\"] = numThreads\n\t}\n\n\tfds, err := p.NumFDs()\n\tif err == nil {\n\t\tfields[prefix+\"num_fds\"] = fds\n\t}\n\n\tctx, err := p.NumCtxSwitches()\n\tif err == nil {\n\t\tfields[prefix+\"voluntary_context_switches\"] = ctx.Voluntary\n\t\tfields[prefix+\"involuntary_context_switches\"] = ctx.Involuntary\n\t}\n\n\tfaults, err := p.PageFaults()\n\tif err == nil {\n\t\tfields[prefix+\"minor_faults\"] = faults.MinorFaults\n\t\tfields[prefix+\"major_faults\"] = faults.MajorFaults\n\t\tfields[prefix+\"child_minor_faults\"] = faults.ChildMinorFaults\n\t\tfields[prefix+\"child_major_faults\"] = faults.ChildMajorFaults\n\t}\n\n\tio, err := p.IOCounters()\n\tif err == nil {\n\t\tfields[prefix+\"read_count\"] = io.ReadCount\n\t\tfields[prefix+\"write_count\"] = io.WriteCount\n\t\tfields[prefix+\"read_bytes\"] = io.ReadBytes\n\t\tfields[prefix+\"write_bytes\"] = io.WriteBytes\n\t}\n\n\t// Linux fixup for gopsutils exposing the disk-only-IO instead of the total\n\t// I/O as for example on Windows\n\tif rc, wc, err := collectTotalReadWrite(p); err == nil {\n\t\tfields[prefix+\"read_bytes\"] = rc\n\t\tfields[prefix+\"write_bytes\"] = wc\n\t\tif runtime.GOOS == \"linux\" {\n\t\t\tfields[prefix+\"disk_read_bytes\"] = io.DiskReadBytes\n\t\t\tfields[prefix+\"disk_write_bytes\"] = io.DiskWriteBytes\n\t\t} else {\n\t\t\tfields[prefix+\"disk_read_bytes\"] = io.ReadBytes\n\t\t\tfields[prefix+\"disk_write_bytes\"] = io.WriteBytes\n\t\t}\n\t}\n\n\tcreatedAt, err := p.CreateTime() // returns epoch in ms\n\tif err == nil {\n\t\tfields[prefix+\"created_at\"] = createdAt * 1000000 // ms to ns\n\t}\n\n\tif cfg.features[\"cpu\"] {\n\t\tcpuTime, err := p.Times()\n\t\tif err == nil {\n\t\t\tfields[prefix+\"cpu_time_user\"] = cpuTime.User\n\t\t\tfields[prefix+\"cpu_time_system\"] = cpuTime.System\n\t\t\tfields[prefix+\"cpu_time_iowait\"] = cpuTime.Iowait // only reported on Linux\n\t\t}\n\n\t\tcpuPerc, err := p.percent(time.Duration(0))\n\t\tif err == nil {\n\t\t\tif cfg.solarisMode {\n\t\t\t\tfields[prefix+\"cpu_usage\"] = cpuPerc / float64(runtime.NumCPU())\n\t\t\t} else {\n\t\t\t\tfields[prefix+\"cpu_usage\"] = cpuPerc\n\t\t\t}\n\t\t}\n\t}\n\n\t// This only returns values for RSS and VMS\n\tif cfg.features[\"memory\"] {\n\t\tmem, err := p.MemoryInfo()\n\t\tif err == nil {\n\t\t\tfields[prefix+\"memory_rss\"] = mem.RSS\n\t\t\tfields[prefix+\"memory_vms\"] = mem.VMS\n\t\t}\n\n\t\tmemPerc, err := p.MemoryPercent()\n\t\tif err == nil {\n\t\t\tfields[prefix+\"memory_usage\"] = memPerc\n\t\t}\n\t}\n\n\tif cfg.features[\"mmap\"] {\n\t\tcollectMemmap(p, prefix, fields)\n\t}\n\n\tif cfg.features[\"limits\"] {\n\t\trlims, err := p.RlimitUsage(true)\n\t\tif err == nil {\n\t\t\tfor _, rlim := range rlims {\n\t\t\t\tvar name string\n\t\t\t\tswitch rlim.Resource {\n\t\t\t\tcase gopsprocess.RLIMIT_CPU:\n\t\t\t\t\tname = \"cpu_time\"\n\t\t\t\tcase gopsprocess.RLIMIT_DATA:\n\t\t\t\t\tname = \"memory_data\"\n\t\t\t\tcase gopsprocess.RLIMIT_STACK:\n\t\t\t\t\tname = \"memory_stack\"\n\t\t\t\tcase gopsprocess.RLIMIT_RSS:\n\t\t\t\t\tname = \"memory_rss\"\n\t\t\t\tcase gopsprocess.RLIMIT_NOFILE:\n\t\t\t\t\tname = \"num_fds\"\n\t\t\t\tcase gopsprocess.RLIMIT_MEMLOCK:\n\t\t\t\t\tname = \"memory_locked\"\n\t\t\t\tcase gopsprocess.RLIMIT_AS:\n\t\t\t\t\tname = \"memory_vms\"\n\t\t\t\tcase gopsprocess.RLIMIT_LOCKS:\n\t\t\t\t\tname = \"file_locks\"\n\t\t\t\tcase gopsprocess.RLIMIT_SIGPENDING:\n\t\t\t\t\tname = \"signals_pending\"\n\t\t\t\tcase gopsprocess.RLIMIT_NICE:\n\t\t\t\t\tname = \"nice_priority\"\n\t\t\t\tcase gopsprocess.RLIMIT_RTPRIO:\n\t\t\t\t\tname = \"realtime_priority\"\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfields[prefix+\"rlimit_\"+name+\"_soft\"] = rlim.Soft\n\t\t\t\tfields[prefix+\"rlimit_\"+name+\"_hard\"] = rlim.Hard\n\t\t\t\tif name != \"file_locks\" { // gopsutil doesn't currently track the used file locks count\n\t\t\t\t\tfields[prefix+name] = rlim.Used\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add the tags as requested by the user\n\tcmdline, err := p.Cmdline()\n\tif err == nil {\n\t\tif cfg.tagging[\"cmdline\"] {\n\t\t\tp.tags[\"cmdline\"] = cmdline\n\t\t} else {\n\t\t\tfields[prefix+\"cmdline\"] = cmdline\n\t\t}\n\t}\n\n\tif cfg.tagging[\"pid\"] {\n\t\tp.tags[\"pid\"] = strconv.Itoa(int(p.Pid))\n\t} else {\n\t\tfields[\"pid\"] = p.Pid\n\t}\n\n\tppid, err := p.Ppid()\n\tif err == nil {\n\t\tif cfg.tagging[\"ppid\"] {\n\t\t\tp.tags[\"ppid\"] = strconv.Itoa(int(ppid))\n\t\t} else {\n\t\t\tfields[prefix+\"ppid\"] = ppid\n\t\t}\n\t}\n\n\tstatus, err := p.Status()\n\tif err == nil {\n\t\tif cfg.tagging[\"status\"] {\n\t\t\tp.tags[\"status\"] = status[0]\n\t\t} else {\n\t\t\tfields[prefix+\"status\"] = status[0]\n\t\t}\n\t}\n\n\tif user := username(p.Process); user != \"\" {\n\t\tif cfg.tagging[\"user\"] {\n\t\t\tp.tags[\"user\"] = user\n\t\t} else {\n\t\t\tfields[prefix+\"user\"] = user\n\t\t}\n\t}\n\n\tif _, exists := p.tags[\"process_name\"]; !exists {\n\t\tname, err := p.Name()\n\t\tif err == nil {\n\t\t\tp.tags[\"process_name\"] = name\n\t\t}\n\t}\n\n\tmetrics := []telegraf.Metric{metric.New(\"procstat\", p.tags, fields, t)}\n\n\t// Collect the socket statistics if requested\n\tif cfg.features[\"sockets\"] {\n\t\tfor _, protocol := range cfg.socketProtos {\n\t\t\t// Get the requested connections for the PID\n\t\t\tvar fieldlist []map[string]interface{}\n\t\t\tswitch protocol {\n\t\t\tcase \"all\":\n\t\t\t\tconns, err := gopsnet.ConnectionsPid(protocol, p.Pid)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get connections for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\t\tvar connsTCPv4, connsTCPv6, connsUDPv4, connsUDPv6, connsUnix []gopsnet.ConnectionStat\n\t\t\t\tfor _, c := range conns {\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase c.Family == syscall.AF_INET && c.Type == syscall.SOCK_STREAM:\n\t\t\t\t\t\tconnsTCPv4 = append(connsTCPv4, c)\n\t\t\t\t\tcase c.Family == syscall.AF_INET6 && c.Type == syscall.SOCK_STREAM:\n\t\t\t\t\t\tconnsTCPv6 = append(connsTCPv6, c)\n\t\t\t\t\tcase c.Family == syscall.AF_INET && c.Type == syscall.SOCK_DGRAM:\n\t\t\t\t\t\tconnsUDPv4 = append(connsUDPv4, c)\n\t\t\t\t\tcase c.Family == syscall.AF_INET6 && c.Type == syscall.SOCK_DGRAM:\n\t\t\t\t\t\tconnsUDPv6 = append(connsUDPv6, c)\n\t\t\t\t\tcase c.Family == syscall.AF_UNIX:\n\t\t\t\t\t\tconnsUnix = append(connsUnix, c)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfl, err := statsTCP(connsTCPv4, syscall.AF_INET)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for \\\"tcp4\\\" of PID %d\", p.Pid)\n\t\t\t\t}\n\t\t\t\tfieldlist = append(fieldlist, fl...)\n\n\t\t\t\tfl, err = statsTCP(connsTCPv6, syscall.AF_INET6)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for \\\"tcp6\\\" of PID %d\", p.Pid)\n\t\t\t\t}\n\t\t\t\tfieldlist = append(fieldlist, fl...)\n\n\t\t\t\tfl, err = statsUDP(connsUDPv4, syscall.AF_INET)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for \\\"udp4\\\" of PID %d\", p.Pid)\n\t\t\t\t}\n\t\t\t\tfieldlist = append(fieldlist, fl...)\n\n\t\t\t\tfl, err = statsUDP(connsUDPv6, syscall.AF_INET6)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for \\\"udp6\\\" of PID %d\", p.Pid)\n\t\t\t\t}\n\t\t\t\tfieldlist = append(fieldlist, fl...)\n\n\t\t\t\tfl, err = statsUnix(connsUnix)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for \\\"unix\\\" of PID %d\", p.Pid)\n\t\t\t\t}\n\t\t\t\tfieldlist = append(fieldlist, fl...)\n\t\t\tcase \"tcp4\", \"tcp6\":\n\t\t\t\tfamily := uint8(syscall.AF_INET)\n\t\t\t\tif protocol == \"tcp6\" {\n\t\t\t\t\tfamily = syscall.AF_INET6\n\t\t\t\t}\n\t\t\t\tconns, err := gopsnet.ConnectionsPid(protocol, p.Pid)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get connections for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\t\tif fieldlist, err = statsTCP(conns, family); err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\tcase \"udp4\", \"udp6\":\n\t\t\t\tfamily := uint8(syscall.AF_INET)\n\t\t\t\tif protocol == \"udp6\" {\n\t\t\t\t\tfamily = syscall.AF_INET6\n\t\t\t\t}\n\t\t\t\tconns, err := gopsnet.ConnectionsPid(protocol, p.Pid)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get connections for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\t\tif fieldlist, err = statsUDP(conns, family); err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\tcase \"unix\":\n\t\t\t\tconns, err := gopsnet.ConnectionsPid(protocol, p.Pid)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get connections for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\t\tif fieldlist, err = statsUnix(conns); err != nil {\n\t\t\t\t\treturn metrics, fmt.Errorf(\"cannot get statistics for %q of PID %d\", protocol, p.Pid)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, fields := range fieldlist {\n\t\t\t\tif cfg.tagging[\"protocol\"] {\n\t\t\t\t\tp.tags[\"protocol\"] = fields[\"protocol\"].(string)\n\t\t\t\t\tdelete(fields, \"protocol\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"state\"] {\n\t\t\t\t\tp.tags[\"state\"] = fields[\"state\"].(string)\n\t\t\t\t\tdelete(fields, \"state\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"src\"] && fields[\"src\"] != nil {\n\t\t\t\t\tp.tags[\"src\"] = fields[\"src\"].(string)\n\t\t\t\t\tdelete(fields, \"src\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"src_port\"] && fields[\"src_port\"] != nil {\n\t\t\t\t\tport, err := internal.ToString(fields[\"src_port\"])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn metrics, fmt.Errorf(\"converting source port to tag failed: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tp.tags[\"src_port\"] = port\n\t\t\t\t\tdelete(fields, \"src_port\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"dest\"] && fields[\"dest\"] != nil {\n\t\t\t\t\tp.tags[\"dest\"] = fields[\"dest\"].(string)\n\t\t\t\t\tdelete(fields, \"dest\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"dest_port\"] && fields[\"dest_port\"] != nil {\n\t\t\t\t\tport, err := internal.ToString(fields[\"dest_port\"])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn metrics, fmt.Errorf(\"converting destination port to tag failed: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tp.tags[\"dest_port\"] = port\n\t\t\t\t\tdelete(fields, \"dest_port\")\n\t\t\t\t}\n\t\t\t\tif cfg.tagging[\"name\"] && fields[\"name\"] != nil {\n\t\t\t\t\tp.tags[\"name\"] = fields[\"name\"].(string)\n\t\t\t\t\tdelete(fields, \"name\")\n\t\t\t\t}\n\n\t\t\t\tmetrics = append(metrics, metric.New(\"procstat_socket\", p.tags, fields, t))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn metrics, nil\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/procstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage procstat\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// execCommand is so tests can mock out exec.Command usage.\nvar execCommand = exec.Command\n\ntype pid int32\n\ntype Procstat struct {\n\tPidFinder              string          `toml:\"pid_finder\"`\n\tPidFile                string          `toml:\"pid_file\"`\n\tExe                    string          `toml:\"exe\"`\n\tPattern                string          `toml:\"pattern\"`\n\tPrefix                 string          `toml:\"prefix\"`\n\tCmdLineTag             bool            `toml:\"cmdline_tag\" deprecated:\"1.29.0;1.40.0;use 'tag_with' instead\"`\n\tProcessName            string          `toml:\"process_name\"`\n\tUser                   string          `toml:\"user\"`\n\tSystemdUnit            string          `toml:\"systemd_unit\"`\n\tSupervisorUnit         []string        `toml:\"supervisor_unit\" deprecated:\"1.29.0;1.40.0;use 'supervisor_units' instead\"`\n\tSupervisorUnits        []string        `toml:\"supervisor_units\"`\n\tIncludeSystemdChildren bool            `toml:\"include_systemd_children\"`\n\tCGroup                 string          `toml:\"cgroup\"`\n\tPidTag                 bool            `toml:\"pid_tag\" deprecated:\"1.29.0;1.40.0;use 'tag_with' instead\"`\n\tWinService             string          `toml:\"win_service\"`\n\tMode                   string          `toml:\"mode\"`\n\tProperties             []string        `toml:\"properties\"`\n\tSocketProtocols        []string        `toml:\"socket_protocols\"`\n\tTagWith                []string        `toml:\"tag_with\"`\n\tFilter                 []filter        `toml:\"filter\"`\n\tLog                    telegraf.Logger `toml:\"-\"`\n\n\tfinder    pidFinder\n\tprocesses map[string]map[pid]process\n\tcfg       collectionConfig\n\toldMode   bool\n\n\tcreateProcess func(pid) (process, error)\n}\n\ntype collectionConfig struct {\n\tsolarisMode  bool\n\ttagging      map[string]bool\n\tfeatures     map[string]bool\n\tsocketProtos []string\n}\n\ntype pidsTags struct {\n\tPIDs []pid\n\tTags map[string]string\n}\n\ntype processGroup struct {\n\tprocesses []*gopsprocess.Process\n\ttags      map[string]string\n\tlevel     int\n}\n\nfunc (*Procstat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Procstat) Init() error {\n\t// Keep the old settings for compatibility\n\tif p.PidTag && !choice.Contains(\"pid\", p.TagWith) {\n\t\tp.TagWith = append(p.TagWith, \"pid\")\n\t}\n\tif p.CmdLineTag && !choice.Contains(\"cmdline\", p.TagWith) {\n\t\tp.TagWith = append(p.TagWith, \"cmdline\")\n\t}\n\n\t// Configure metric collection features\n\tp.cfg.solarisMode = strings.EqualFold(p.Mode, \"solaris\")\n\n\t// Convert tagging settings\n\tp.cfg.tagging = make(map[string]bool, len(p.TagWith))\n\tfor _, tag := range p.TagWith {\n\t\tswitch tag {\n\t\tcase \"cmdline\", \"pid\", \"ppid\", \"status\", \"user\", \"child_level\", \"parent_pid\", \"level\":\n\t\tcase \"protocol\", \"state\", \"src\", \"src_port\", \"dest\", \"dest_port\", \"name\": // socket only\n\t\t\tif !slices.Contains(p.Properties, \"sockets\") {\n\t\t\t\treturn fmt.Errorf(\"socket tagging option %q specified without sockets enabled\", tag)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid 'tag_with' setting %q\", tag)\n\t\t}\n\t\tp.cfg.tagging[tag] = true\n\t}\n\n\t// Convert collection properties\n\tp.cfg.features = make(map[string]bool, len(p.Properties))\n\tfor _, prop := range p.Properties {\n\t\tswitch prop {\n\t\tcase \"cpu\", \"limits\", \"memory\", \"mmap\":\n\t\tcase \"sockets\":\n\t\t\tif len(p.SocketProtocols) == 0 {\n\t\t\t\tp.SocketProtocols = []string{\"all\"}\n\t\t\t}\n\t\t\tprotos := make(map[string]bool, len(p.SocketProtocols))\n\t\t\tfor _, proto := range p.SocketProtocols {\n\t\t\t\tswitch proto {\n\t\t\t\tcase \"all\":\n\t\t\t\t\tif len(protos) > 0 || len(p.SocketProtocols) > 1 {\n\t\t\t\t\t\treturn errors.New(\"additional 'socket_protocol' settings besides 'all' are not allowed\")\n\t\t\t\t\t}\n\t\t\t\tcase \"tcp4\", \"tcp6\", \"udp4\", \"udp6\", \"unix\":\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"invalid 'socket_protocol' setting %q\", proto)\n\t\t\t\t}\n\t\t\t\tif protos[proto] {\n\t\t\t\t\treturn fmt.Errorf(\"duplicate %q in 'socket_protocol' setting\", proto)\n\t\t\t\t}\n\t\t\t\tprotos[proto] = true\n\t\t\t\tp.cfg.socketProtos = append(p.cfg.socketProtos, proto)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid 'properties' setting %q\", prop)\n\t\t}\n\t\tp.cfg.features[prop] = true\n\t}\n\n\t// Check if we got any new-style configuration options and determine\n\t// operation mode.\n\tp.oldMode = len(p.Filter) == 0\n\tif p.oldMode {\n\t\t// Keep the old settings for compatibility\n\t\tfor _, u := range p.SupervisorUnit {\n\t\t\tif !choice.Contains(u, p.SupervisorUnits) {\n\t\t\t\tp.SupervisorUnits = append(p.SupervisorUnits, u)\n\t\t\t}\n\t\t}\n\n\t\t// Check filtering\n\t\tswitch {\n\t\tcase len(p.SupervisorUnits) > 0, p.SystemdUnit != \"\", p.WinService != \"\",\n\t\t\tp.CGroup != \"\", p.PidFile != \"\", p.Exe != \"\", p.Pattern != \"\",\n\t\t\tp.User != \"\":\n\t\t\t// Do nothing as those are valid settings\n\t\tdefault:\n\t\t\treturn errors.New(\"require filter option but none set\")\n\t\t}\n\n\t\t// Instantiate the finder\n\t\tswitch p.PidFinder {\n\t\tcase \"\", \"pgrep\":\n\t\t\tp.PidFinder = \"pgrep\"\n\t\t\tfinder, err := newPgrepFinder()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"creating pgrep finder failed: %w\", err)\n\t\t\t}\n\t\t\tp.finder = finder\n\t\tcase \"native\":\n\t\t\t// gopsutil relies on pgrep when looking up children on darwin\n\t\t\t// see https://github.com/shirou/gopsutil/blob/v3.23.10/process/process_darwin.go#L235\n\t\t\trequiresChildren := len(p.SupervisorUnits) > 0 && p.Pattern != \"\"\n\t\t\tif requiresChildren && runtime.GOOS == \"darwin\" {\n\t\t\t\treturn errors.New(\"configuration requires 'pgrep' finder on your OS\")\n\t\t\t}\n\t\t\tp.finder = &NativeFinder{}\n\t\tcase \"test\":\n\t\t\tp.Log.Warn(\"running in test mode\")\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown pid_finder %q\", p.PidFinder)\n\t\t}\n\t} else {\n\t\t// Check for mixed mode\n\t\tswitch {\n\t\tcase p.PidFile != \"\", p.Exe != \"\", p.Pattern != \"\", p.User != \"\",\n\t\t\tp.SystemdUnit != \"\", len(p.SupervisorUnit) > 0,\n\t\t\tlen(p.SupervisorUnits) > 0, p.CGroup != \"\", p.WinService != \"\":\n\t\t\treturn errors.New(\"cannot operate in mixed mode with filters and old-style config\")\n\t\t}\n\n\t\t// New-style operations\n\t\tfor i := range p.Filter {\n\t\t\tp.Filter[i].Log = p.Log\n\t\t\tif err := p.Filter[i].init(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"initializing filter %d failed: %w\", i, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize the running process cache\n\tp.processes = make(map[string]map[pid]process)\n\n\treturn nil\n}\n\nfunc (p *Procstat) Gather(acc telegraf.Accumulator) error {\n\tif p.oldMode {\n\t\treturn p.gatherOld(acc)\n\t}\n\n\treturn p.gatherNew(acc)\n}\n\nfunc (p *Procstat) gatherOld(acc telegraf.Accumulator) error {\n\tnow := time.Now()\n\tresults, err := p.findPids()\n\tif err != nil {\n\t\t// Add lookup error-metric\n\t\tfields := map[string]interface{}{\n\t\t\t\"pid_count\":   0,\n\t\t\t\"running\":     0,\n\t\t\t\"result_code\": 1,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"pid_finder\": p.PidFinder,\n\t\t\t\"result\":     \"lookup_error\",\n\t\t}\n\t\tfor _, pidTag := range results {\n\t\t\tfor key, value := range pidTag.Tags {\n\t\t\t\ttags[key] = value\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"procstat_lookup\", fields, tags, now)\n\t\treturn err\n\t}\n\n\t// Use empty string as filter key for old mode (single implicit filter)\n\tconst oldModeKey = \"\"\n\tif p.processes[oldModeKey] == nil {\n\t\tp.processes[oldModeKey] = make(map[pid]process)\n\t}\n\tprocs := p.processes[oldModeKey]\n\n\tvar count int\n\trunning := make(map[pid]bool)\n\tfor _, r := range results {\n\t\tif len(r.PIDs) < 1 && len(p.SupervisorUnits) > 0 {\n\t\t\tcontinue\n\t\t}\n\t\tcount += len(r.PIDs)\n\t\tfor _, pid := range r.PIDs {\n\t\t\t// Check if the process is still running\n\t\t\tproc, err := p.createProcess(pid)\n\t\t\tif err != nil {\n\t\t\t\t// No problem; process may have ended after we found it or it\n\t\t\t\t// might be delivered from a non-checking source like a PID file\n\t\t\t\t// of a dead process.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Use the cached processes as we need the existing instances\n\t\t\t// to compute delta-metrics (e.g. cpu-usage).\n\t\t\tif cached, found := procs[pid]; found {\n\t\t\t\tproc = cached\n\t\t\t} else {\n\t\t\t\t// We've found a process that was not recorded before so add it\n\t\t\t\t// to the list of processes\n\n\t\t\t\t//nolint:errcheck // Assumption: if a process has no name, it probably does not exist\n\t\t\t\tif name, _ := proc.Name(); name == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Add initial tags\n\t\t\t\tfor k, v := range r.Tags {\n\t\t\t\t\tproc.setTag(k, v)\n\t\t\t\t}\n\n\t\t\t\tif p.ProcessName != \"\" {\n\t\t\t\t\tproc.setTag(\"process_name\", p.ProcessName)\n\t\t\t\t}\n\t\t\t\tprocs[pid] = proc\n\t\t\t}\n\t\t\trunning[pid] = true\n\t\t\tmetrics, err := proc.metrics(p.Prefix, &p.cfg, now)\n\t\t\tif err != nil {\n\t\t\t\t// Continue after logging an error as there might still be\n\t\t\t\t// metrics available\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\tfor _, m := range metrics {\n\t\t\t\tacc.AddMetric(m)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Cleanup processes that are not running anymore\n\tfor pid := range procs {\n\t\tif !running[pid] {\n\t\t\tdelete(procs, pid)\n\t\t}\n\t}\n\n\t// Add lookup statistics-metric\n\tfields := map[string]interface{}{\n\t\t\"pid_count\":   count,\n\t\t\"running\":     len(running),\n\t\t\"result_code\": 0,\n\t}\n\ttags := map[string]string{\n\t\t\"pid_finder\": p.PidFinder,\n\t\t\"result\":     \"success\",\n\t}\n\tfor _, pidTag := range results {\n\t\tfor key, value := range pidTag.Tags {\n\t\t\ttags[key] = value\n\t\t}\n\t}\n\tif len(p.SupervisorUnits) > 0 {\n\t\ttags[\"supervisor_unit\"] = strings.Join(p.SupervisorUnits, \";\")\n\t}\n\tacc.AddFields(\"procstat_lookup\", fields, tags, now)\n\n\treturn nil\n}\n\nfunc (p *Procstat) gatherNew(acc telegraf.Accumulator) error {\n\tnow := time.Now()\n\tfor _, f := range p.Filter {\n\t\tgroups, err := f.applyFilter()\n\t\tif err != nil {\n\t\t\t// Add lookup error-metric\n\t\t\tacc.AddFields(\n\t\t\t\t\"procstat_lookup\",\n\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\"pid_count\":   0,\n\t\t\t\t\t\"running\":     0,\n\t\t\t\t\t\"result_code\": 1,\n\t\t\t\t},\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"filter\": f.Name,\n\t\t\t\t\t\"result\": \"lookup_error\",\n\t\t\t\t},\n\t\t\t\tnow,\n\t\t\t)\n\t\t\tacc.AddError(fmt.Errorf(\"applying filter %q failed: %w\", f.Name, err))\n\t\t\tcontinue\n\t\t}\n\n\t\t// Initialize the process cache for this filter if needed\n\t\tif p.processes[f.Name] == nil {\n\t\t\tp.processes[f.Name] = make(map[pid]process)\n\t\t}\n\t\tfilterProcs := p.processes[f.Name]\n\n\t\t// Track running processes for this filter to clean up stale entries\n\t\trunning := make(map[pid]bool)\n\n\t\tvar count int\n\t\tfor _, g := range groups {\n\t\t\tcount += len(g.processes)\n\t\t\tlevel := strconv.Itoa(g.level)\n\t\t\tfor _, gp := range g.processes {\n\t\t\t\t// Skip over non-running processes\n\t\t\t\tif isRunning, err := gp.IsRunning(); err != nil || !isRunning {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Use the cached processes as we need the existing instances\n\t\t\t\t// to compute delta-metrics (e.g. cpu-usage).\n\t\t\t\tpid := pid(gp.Pid)\n\t\t\t\tprocess, found := filterProcs[pid]\n\t\t\t\tif !found {\n\t\t\t\t\t//nolint:errcheck // Assumption: if a process has no name, it probably does not exist\n\t\t\t\t\tif name, _ := gp.Name(); name == \"\" {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// We've found a process that was not recorded before so add it\n\t\t\t\t\t// to the list of processes\n\t\t\t\t\ttags := make(map[string]string, len(g.tags)+2)\n\t\t\t\t\tfor k, v := range g.tags {\n\t\t\t\t\t\ttags[k] = v\n\t\t\t\t\t}\n\t\t\t\t\tif p.ProcessName != \"\" {\n\t\t\t\t\t\ttags[\"process_name\"] = p.ProcessName\n\t\t\t\t\t}\n\t\t\t\t\ttags[\"filter\"] = f.Name\n\t\t\t\t\tif p.cfg.tagging[\"level\"] {\n\t\t\t\t\t\ttags[\"level\"] = level\n\t\t\t\t\t}\n\n\t\t\t\t\tprocess = &proc{\n\t\t\t\t\t\tProcess:     gp,\n\t\t\t\t\t\thasCPUTimes: false,\n\t\t\t\t\t\ttags:        tags,\n\t\t\t\t\t}\n\t\t\t\t\tfilterProcs[pid] = process\n\t\t\t\t}\n\t\t\t\trunning[pid] = true\n\t\t\t\tmetrics, err := process.metrics(p.Prefix, &p.cfg, now)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// Continue after logging an error as there might still be\n\t\t\t\t\t// metrics available\n\t\t\t\t\tacc.AddError(err)\n\t\t\t\t}\n\t\t\t\tfor _, m := range metrics {\n\t\t\t\t\tacc.AddMetric(m)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif p.cfg.tagging[\"level\"] {\n\t\t\t\t// Add lookup statistics-metric\n\t\t\t\tacc.AddFields(\n\t\t\t\t\t\"procstat_lookup\",\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"pid_count\":   len(g.processes),\n\t\t\t\t\t\t\"running\":     len(running),\n\t\t\t\t\t\t\"result_code\": 0,\n\t\t\t\t\t\t\"level\":       g.level,\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"filter\": f.Name,\n\t\t\t\t\t\t\"result\": \"success\",\n\t\t\t\t\t},\n\t\t\t\t\tnow,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// Cleanup processes that are not running anymore for this filter\n\t\tfor pid := range filterProcs {\n\t\t\tif !running[pid] {\n\t\t\t\tdelete(filterProcs, pid)\n\t\t\t}\n\t\t}\n\n\t\t// Add lookup statistics-metric\n\t\tacc.AddFields(\n\t\t\t\"procstat_lookup\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"pid_count\":   count,\n\t\t\t\t\"running\":     len(running),\n\t\t\t\t\"result_code\": 0,\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"filter\": f.Name,\n\t\t\t\t\"result\": \"success\",\n\t\t\t},\n\t\t\tnow,\n\t\t)\n\t}\n\n\treturn nil\n}\n\n// Get matching PIDs and their initial tags\nfunc (p *Procstat) findPids() ([]pidsTags, error) {\n\tswitch {\n\tcase len(p.SupervisorUnits) > 0:\n\t\treturn p.findSupervisorUnits()\n\tcase p.SystemdUnit != \"\":\n\t\treturn p.systemdUnitPIDs()\n\tcase p.WinService != \"\":\n\t\tpids, err := p.winServicePIDs()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"win_service\": p.WinService}\n\t\treturn []pidsTags{{pids, tags}}, nil\n\tcase p.CGroup != \"\":\n\t\treturn p.cgroupPIDs()\n\tcase p.PidFile != \"\":\n\t\tpids, err := p.finder.pidFile(p.PidFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"pidfile\": p.PidFile}\n\t\treturn []pidsTags{{pids, tags}}, nil\n\tcase p.Exe != \"\":\n\t\tpids, err := p.finder.pattern(p.Exe)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"exe\": p.Exe}\n\t\treturn []pidsTags{{pids, tags}}, nil\n\tcase p.Pattern != \"\":\n\t\tpids, err := p.finder.fullPattern(p.Pattern)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"pattern\": p.Pattern}\n\t\treturn []pidsTags{{pids, tags}}, nil\n\tcase p.User != \"\":\n\t\tpids, err := p.finder.uid(p.User)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"user\": p.User}\n\t\treturn []pidsTags{{pids, tags}}, nil\n\t}\n\treturn nil, errors.New(\"no filter option set\")\n}\n\nfunc (p *Procstat) findSupervisorUnits() ([]pidsTags, error) {\n\tgroups, groupsTags, err := p.supervisorPIDs()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting supervisor PIDs failed: %w\", err)\n\t}\n\n\t// According to the PID, find the system process number and get the child processes\n\tpidTags := make([]pidsTags, 0, len(groups))\n\tfor _, group := range groups {\n\t\tgrppid := groupsTags[group][\"pid\"]\n\t\tif grppid == \"\" {\n\t\t\tpidTags = append(pidTags, pidsTags{nil, groupsTags[group]})\n\t\t\tcontinue\n\t\t}\n\n\t\tprocessID, err := strconv.ParseInt(grppid, 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"converting PID %q failed: %w\", grppid, err)\n\t\t}\n\n\t\t// Get all children of the supervisor unit\n\t\tpids, err := p.finder.children(pid(processID))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting children for %d failed: %w\", processID, err)\n\t\t}\n\t\ttags := map[string]string{\"pattern\": p.Pattern, \"parent_pid\": p.Pattern}\n\n\t\t// Handle situations where the PID does not exist\n\t\tif len(pids) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Merge tags map\n\t\tfor k, v := range groupsTags[group] {\n\t\t\t_, ok := tags[k]\n\t\t\tif !ok {\n\t\t\t\ttags[k] = v\n\t\t\t}\n\t\t}\n\t\t// Remove duplicate pid tags\n\t\tdelete(tags, \"pid\")\n\t\tpidTags = append(pidTags, pidsTags{pids, tags})\n\t}\n\treturn pidTags, nil\n}\n\nfunc (p *Procstat) supervisorPIDs() ([]string, map[string]map[string]string, error) {\n\tout, err := execCommand(\"supervisorctl\", \"status\", strings.Join(p.SupervisorUnits, \" \")).Output()\n\tif err != nil {\n\t\tif !strings.Contains(err.Error(), \"exit status 3\") {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\t// Get the PID, running status, running time and boot time of the main process:\n\t// pid 11779, uptime 17:41:16\n\t// Exited too quickly (process log may have details)\n\tmainPids := make(map[string]map[string]string)\n\tfor _, line := range lines {\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tkv := strings.Fields(line)\n\t\tif len(kv) < 2 {\n\t\t\t// Not a key-value pair\n\t\t\tcontinue\n\t\t}\n\t\tname := kv[0]\n\n\t\tstatusMap := map[string]string{\n\t\t\t\"supervisor_unit\": name,\n\t\t\t\"status\":          kv[1],\n\t\t}\n\n\t\tswitch kv[1] {\n\t\tcase \"FATAL\", \"EXITED\", \"BACKOFF\", \"STOPPING\":\n\t\t\tstatusMap[\"error\"] = strings.Join(kv[2:], \" \")\n\t\tcase \"RUNNING\":\n\t\t\tstatusMap[\"pid\"] = strings.ReplaceAll(kv[3], \",\", \"\")\n\t\t\tstatusMap[\"uptimes\"] = kv[5]\n\t\tcase \"STOPPED\", \"UNKNOWN\", \"STARTING\":\n\t\t\t// No additional info\n\t\t}\n\t\tmainPids[name] = statusMap\n\t}\n\n\treturn p.SupervisorUnits, mainPids, nil\n}\n\nfunc (p *Procstat) systemdUnitPIDs() ([]pidsTags, error) {\n\tif p.IncludeSystemdChildren {\n\t\t// Adapt the path for newer versions of systemd\n\t\tp.CGroup = \"systemd/system.slice/\" + p.SystemdUnit\n\t\tif _, err := os.Stat(\"/sys/fs/cgroup/systemd/system.slice\"); errors.Is(err, os.ErrNotExist) {\n\t\t\tp.CGroup = \"system.slice/\" + p.SystemdUnit\n\t\t}\n\t\treturn p.cgroupPIDs()\n\t}\n\n\tpids, err := p.simpleSystemdUnitPIDs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttags := map[string]string{\"systemd_unit\": p.SystemdUnit}\n\treturn []pidsTags{{pids, tags}}, nil\n}\n\nfunc (p *Procstat) simpleSystemdUnitPIDs() ([]pid, error) {\n\tout, err := execCommand(\"systemctl\", \"show\", p.SystemdUnit).Output()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := bytes.Split(out, []byte{'\\n'})\n\tpids := make([]pid, 0, len(lines))\n\tfor _, line := range lines {\n\t\tkv := bytes.SplitN(line, []byte{'='}, 2)\n\t\tif len(kv) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tif !bytes.Equal(kv[0], []byte(\"MainPID\")) {\n\t\t\tcontinue\n\t\t}\n\t\tif len(kv[1]) == 0 || bytes.Equal(kv[1], []byte(\"0\")) {\n\t\t\treturn nil, nil\n\t\t}\n\t\tprocessID, err := strconv.ParseInt(string(kv[1]), 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid pid %q\", kv[1])\n\t\t}\n\t\tpids = append(pids, pid(processID))\n\t}\n\n\treturn pids, nil\n}\n\nfunc (p *Procstat) cgroupPIDs() ([]pidsTags, error) {\n\tprocsPath := p.CGroup\n\tif procsPath[0] != '/' {\n\t\tprocsPath = \"/sys/fs/cgroup/\" + procsPath\n\t}\n\n\titems, err := filepath.Glob(procsPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"glob failed: %w\", err)\n\t}\n\n\tpidTags := make([]pidsTags, 0, len(items))\n\tfor _, item := range items {\n\t\tpids, err := singleCgroupPIDs(item)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttags := map[string]string{\"cgroup\": p.CGroup, \"cgroup_full\": item}\n\t\tpidTags = append(pidTags, pidsTags{pids, tags})\n\t}\n\n\treturn pidTags, nil\n}\n\nfunc singleCgroupPIDs(path string) ([]pid, error) {\n\tok, err := isDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"not a directory %s\", path)\n\t}\n\tprocsPath := filepath.Join(path, \"cgroup.procs\")\n\tout, err := os.ReadFile(procsPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := bytes.Split(out, []byte{'\\n'})\n\tpids := make([]pid, 0, len(lines))\n\tfor _, pidBS := range lines {\n\t\tif len(pidBS) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tprocessID, err := strconv.ParseInt(string(pidBS), 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid pid %q\", pidBS)\n\t\t}\n\t\tpids = append(pids, pid(processID))\n\t}\n\n\treturn pids, nil\n}\n\nfunc isDir(path string) (bool, error) {\n\tresult, err := os.Stat(path)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn result.IsDir(), nil\n}\n\nfunc (p *Procstat) winServicePIDs() ([]pid, error) {\n\tprocessID, err := queryPidWithWinServiceName(p.WinService)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn []pid{pid(processID)}, nil\n}\n\nfunc init() {\n\tinputs.Add(\"procstat\", func() telegraf.Input {\n\t\treturn &Procstat{\n\t\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\t\tcreateProcess: newProc,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/procstat_test.go",
    "content": "package procstat\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc init() {\n\texecCommand = mockExecCommand\n}\nfunc mockExecCommand(arg0 string, args ...string) *exec.Cmd {\n\targs = append([]string{\"-test.run=TestMockExecCommand\", \"--\", arg0}, args...)\n\tcmd := exec.Command(os.Args[0], args...)\n\tcmd.Stderr = os.Stderr\n\treturn cmd\n}\nfunc TestMockExecCommand(_ *testing.T) {\n\tvar cmd []string //nolint:prealloc // Pre-allocated this slice would break the algorithm\n\tfor _, arg := range os.Args {\n\t\tif arg == \"--\" {\n\t\t\tcmd = make([]string, 0)\n\t\t\tcontinue\n\t\t}\n\t\tif cmd == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcmd = append(cmd, arg)\n\t}\n\tif cmd == nil {\n\t\treturn\n\t}\n\tcmdline := strings.Join(cmd, \" \")\n\n\tif cmdline == \"systemctl show TestGather_systemdUnitPIDs\" {\n\t\tfmt.Printf(`PIDFile=\nGuessMainPID=yes\nMainPID=11408\nControlPID=0\nExecMainPID=11408\n`)\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(0)\n\t}\n\n\tif cmdline == \"supervisorctl status TestGather_supervisorUnitPIDs\" {\n\t\tfmt.Printf(`TestGather_supervisorUnitPIDs                             RUNNING   pid 7311, uptime 0:00:19\n`)\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(0)\n\t}\n\n\tif cmdline == \"supervisorctl status TestGather_STARTINGsupervisorUnitPIDs TestGather_FATALsupervisorUnitPIDs\" {\n\t\tfmt.Printf(`TestGather_FATALsupervisorUnitPIDs                       FATAL     Exited too quickly (process log may have details)\nTestGather_STARTINGsupervisorUnitPIDs                          STARTING`)\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(0)\n\t}\n\n\tfmt.Printf(\"command not found\\n\")\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(1)\n}\n\ntype testPgrep struct {\n\tpids []pid\n\terr  error\n}\n\nfunc newTestFinder(pids []pid) pidFinder {\n\treturn &testPgrep{\n\t\tpids: pids,\n\t\terr:  nil,\n\t}\n}\n\nfunc (pg *testPgrep) pidFile(_ string) ([]pid, error) {\n\treturn pg.pids, pg.err\n}\n\nfunc (pg *testPgrep) pattern(_ string) ([]pid, error) {\n\treturn pg.pids, pg.err\n}\n\nfunc (pg *testPgrep) uid(_ string) ([]pid, error) {\n\treturn pg.pids, pg.err\n}\n\nfunc (pg *testPgrep) fullPattern(_ string) ([]pid, error) {\n\treturn pg.pids, pg.err\n}\n\nfunc (pg *testPgrep) children(_ pid) ([]pid, error) {\n\tpids := []pid{7311, 8111, 8112}\n\treturn pids, pg.err\n}\n\ntype testProc struct {\n\tprocID pid\n\ttags   map[string]string\n}\n\nfunc newTestProc(pid pid) (process, error) {\n\tproc := &testProc{\n\t\tprocID: pid,\n\t\ttags:   make(map[string]string),\n\t}\n\treturn proc, nil\n}\n\nfunc (p *testProc) pid() pid {\n\treturn p.procID\n}\n\nfunc (*testProc) Name() (string, error) {\n\treturn \"test_proc\", nil\n}\n\nfunc (p *testProc) setTag(k, v string) {\n\tp.tags[k] = v\n}\n\nfunc (*testProc) MemoryMaps(bool) (*[]gopsprocess.MemoryMapsStat, error) {\n\tstats := make([]gopsprocess.MemoryMapsStat, 0)\n\treturn &stats, nil\n}\n\nfunc (p *testProc) metrics(prefix string, cfg *collectionConfig, t time.Time) ([]telegraf.Metric, error) {\n\tif prefix != \"\" {\n\t\tprefix += \"_\"\n\t}\n\n\tfields := map[string]interface{}{\n\t\tprefix + \"num_fds\":                      int32(0),\n\t\tprefix + \"num_threads\":                  int32(0),\n\t\tprefix + \"voluntary_context_switches\":   int64(0),\n\t\tprefix + \"involuntary_context_switches\": int64(0),\n\t\tprefix + \"minor_faults\":                 uint64(0),\n\t\tprefix + \"major_faults\":                 uint64(0),\n\t\tprefix + \"child_major_faults\":           uint64(0),\n\t\tprefix + \"child_minor_faults\":           uint64(0),\n\t\tprefix + \"read_bytes\":                   uint64(0),\n\t\tprefix + \"read_count\":                   uint64(0),\n\t\tprefix + \"write_bytes\":                  uint64(0),\n\t\tprefix + \"write_count\":                  uint64(0),\n\t\tprefix + \"created_at\":                   int64(0),\n\t}\n\tif cfg.features[\"cpu\"] {\n\t\tfields[prefix+\"cpu_time_user\"] = float64(0)\n\t\tfields[prefix+\"cpu_time_system\"] = float64(0)\n\t\tfields[prefix+\"cpu_time_iowait\"] = float64(0)\n\t\tfields[prefix+\"cpu_usage\"] = float64(0)\n\t}\n\tif cfg.features[\"memory\"] {\n\t\tfields[prefix+\"memory_rss\"] = uint64(0)\n\t\tfields[prefix+\"memory_vms\"] = uint64(0)\n\t\tfields[prefix+\"memory_usage\"] = float32(0)\n\t}\n\n\ttags := map[string]string{\n\t\t\"process_name\": \"test_proc\",\n\t}\n\tfor k, v := range p.tags {\n\t\ttags[k] = v\n\t}\n\n\t// Add the tags as requested by the user\n\tif cfg.tagging[\"cmdline\"] {\n\t\ttags[\"cmdline\"] = \"test_proc\"\n\t} else {\n\t\tfields[prefix+\"cmdline\"] = \"test_proc\"\n\t}\n\n\tif cfg.tagging[\"pid\"] {\n\t\ttags[\"pid\"] = strconv.Itoa(int(p.procID))\n\t} else {\n\t\tfields[\"pid\"] = int32(p.procID)\n\t}\n\n\tif cfg.tagging[\"ppid\"] {\n\t\ttags[\"ppid\"] = \"0\"\n\t} else {\n\t\tfields[prefix+\"ppid\"] = int32(0)\n\t}\n\n\tif cfg.tagging[\"status\"] {\n\t\ttags[\"status\"] = \"running\"\n\t} else {\n\t\tfields[prefix+\"status\"] = \"running\"\n\t}\n\n\tif cfg.tagging[\"user\"] {\n\t\ttags[\"user\"] = \"testuser\"\n\t} else {\n\t\tfields[prefix+\"user\"] = \"testuser\"\n\t}\n\n\treturn []telegraf.Metric{metric.New(\"procstat\", tags, fields, t)}, nil\n}\n\nvar processID = pid(42)\nvar exe = \"foo\"\n\nfunc TestInitInvalidFinder(t *testing.T) {\n\tplugin := Procstat{\n\t\tPidFinder:     \"foo\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.Error(t, plugin.Init())\n}\n\nfunc TestInitRequiresChildDarwin(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" {\n\t\tt.Skip(\"Skipping test on non-darwin platform\")\n\t}\n\n\tp := Procstat{\n\t\tPattern:         \"somepattern\",\n\t\tSupervisorUnits: []string{\"a_unit\"},\n\t\tPidFinder:       \"native\",\n\t\tProperties:      []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:             testutil.Logger{},\n\t}\n\trequire.ErrorContains(t, p.Init(), \"requires 'pgrep' finder\")\n}\n\nfunc TestInitMissingPidMethod(t *testing.T) {\n\tp := Procstat{\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.ErrorContains(t, p.Init(), \"require filter option but none set\")\n}\n\nfunc TestGather_CreateProcessErrorOk(t *testing.T) {\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"procstat_lookup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"exe\":        \"foo\",\n\t\t\t\t\"pid_finder\": \"test\",\n\t\t\t\t\"result\":     \"success\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"pid_count\":   int64(1),\n\t\t\t\t\"result_code\": int64(0),\n\t\t\t\t\"running\":     int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\tp := Procstat{\n\t\tExe:        exe,\n\t\tPidFinder:  \"test\",\n\t\tProperties: []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:        testutil.Logger{},\n\t\tfinder:     newTestFinder([]pid{processID}),\n\t\tcreateProcess: func(pid) (process, error) {\n\t\t\treturn nil, errors.New(\"createProcess error\")\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGather_ProcessName(t *testing.T) {\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"procstat\",\n\t\t\tmap[string]string{\n\t\t\t\t\"exe\":          \"foo\",\n\t\t\t\t\"process_name\": \"custom_name\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"child_major_faults\":           uint64(0),\n\t\t\t\t\"child_minor_faults\":           uint64(0),\n\t\t\t\t\"cmdline\":                      \"test_proc\",\n\t\t\t\t\"cpu_time_iowait\":              float64(0),\n\t\t\t\t\"cpu_time_system\":              float64(0),\n\t\t\t\t\"cpu_time_user\":                float64(0),\n\t\t\t\t\"cpu_usage\":                    float64(0),\n\t\t\t\t\"created_at\":                   int64(0),\n\t\t\t\t\"involuntary_context_switches\": int64(0),\n\t\t\t\t\"major_faults\":                 uint64(0),\n\t\t\t\t\"memory_rss\":                   uint64(0),\n\t\t\t\t\"memory_usage\":                 float32(0),\n\t\t\t\t\"memory_vms\":                   uint64(0),\n\t\t\t\t\"minor_faults\":                 uint64(0),\n\t\t\t\t\"num_fds\":                      int32(0),\n\t\t\t\t\"num_threads\":                  int32(0),\n\t\t\t\t\"pid\":                          int32(42),\n\t\t\t\t\"ppid\":                         int32(0),\n\t\t\t\t\"read_bytes\":                   uint64(0),\n\t\t\t\t\"read_count\":                   uint64(0),\n\t\t\t\t\"status\":                       \"running\",\n\t\t\t\t\"user\":                         \"testuser\",\n\t\t\t\t\"voluntary_context_switches\":   int64(0),\n\t\t\t\t\"write_bytes\":                  uint64(0),\n\t\t\t\t\"write_count\":                  uint64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"procstat_lookup\",\n\t\t\tmap[string]string{\n\t\t\t\t\"exe\":        \"foo\",\n\t\t\t\t\"pid_finder\": \"test\",\n\t\t\t\t\"result\":     \"success\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"pid_count\":   int64(1),\n\t\t\t\t\"result_code\": int64(0),\n\t\t\t\t\"running\":     int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tProcessName:   \"custom_name\",\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\trequire.Equal(t, \"custom_name\", acc.TagValue(\"procstat\", \"process_name\"))\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGather_NoProcessNameUsesReal(t *testing.T) {\n\tprocessID := pid(os.Getpid())\n\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.True(t, acc.HasTag(\"procstat\", \"process_name\"))\n}\n\nfunc TestGather_NoPidTag(t *testing.T) {\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.True(t, acc.HasInt64Field(\"procstat\", \"pid\"))\n\trequire.False(t, acc.HasTag(\"procstat\", \"pid\"))\n}\n\nfunc TestGather_PidTag(t *testing.T) {\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tPidTag:        true,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.Equal(t, \"42\", acc.TagValue(\"procstat\", \"pid\"))\n\trequire.False(t, acc.HasInt32Field(\"procstat\", \"pid\"))\n}\n\nfunc TestGather_Prefix(t *testing.T) {\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tPrefix:        \"custom_prefix\",\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.True(t, acc.HasInt64Field(\"procstat\", \"custom_prefix_num_fds\"))\n}\n\nfunc TestGather_Exe(t *testing.T) {\n\tp := Procstat{\n\t\tExe:           exe,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.Equal(t, exe, acc.TagValue(\"procstat\", \"exe\"))\n}\n\nfunc TestGather_User(t *testing.T) {\n\tuser := \"ada\"\n\n\tp := Procstat{\n\t\tUser:          user,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.Equal(t, user, acc.TagValue(\"procstat\", \"user\"))\n}\n\nfunc TestGather_Pattern(t *testing.T) {\n\tpattern := \"foo\"\n\n\tp := Procstat{\n\t\tPattern:       pattern,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.Equal(t, pattern, acc.TagValue(\"procstat\", \"pattern\"))\n}\n\nfunc TestGather_PidFile(t *testing.T) {\n\tpidfile := \"/path/to/pidfile\"\n\n\tp := Procstat{\n\t\tPidFile:       pidfile,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.Equal(t, pidfile, acc.TagValue(\"procstat\", \"pidfile\"))\n}\n\nfunc TestGather_PercentFirstPass(t *testing.T) {\n\tprocessID := pid(os.Getpid())\n\n\tp := Procstat{\n\t\tPattern:       \"foo\",\n\t\tPidTag:        true,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.True(t, acc.HasFloatField(\"procstat\", \"cpu_time_user\"))\n\trequire.False(t, acc.HasFloatField(\"procstat\", \"cpu_usage\"))\n}\n\nfunc TestGather_PercentSecondPass(t *testing.T) {\n\tprocessID := pid(os.Getpid())\n\n\tp := Procstat{\n\t\tPattern:       \"foo\",\n\t\tPidTag:        true,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\trequire.NoError(t, p.Gather(&acc))\n\n\trequire.True(t, acc.HasFloatField(\"procstat\", \"cpu_time_user\"))\n\trequire.True(t, acc.HasFloatField(\"procstat\", \"cpu_usage\"))\n}\n\nfunc TestGather_systemdUnitPIDs(t *testing.T) {\n\tp := Procstat{\n\t\tSystemdUnit: \"TestGather_systemdUnitPIDs\",\n\t\tPidFinder:   \"test\",\n\t\tProperties:  []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:         testutil.Logger{},\n\t\tfinder:      newTestFinder([]pid{processID}),\n\t}\n\trequire.NoError(t, p.Init())\n\n\tpidsTags, err := p.findPids()\n\trequire.NoError(t, err)\n\n\tfor _, pidsTag := range pidsTags {\n\t\trequire.Equal(t, []pid{11408}, pidsTag.PIDs)\n\t\trequire.Equal(t, \"TestGather_systemdUnitPIDs\", pidsTag.Tags[\"systemd_unit\"])\n\t}\n}\n\nfunc TestGather_cgroupPIDs(t *testing.T) {\n\t// no cgroups in windows\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"no cgroups in windows\")\n\t}\n\ttd := t.TempDir()\n\terr := os.WriteFile(filepath.Join(td, \"cgroup.procs\"), []byte(\"1234\\n5678\\n\"), 0640)\n\trequire.NoError(t, err)\n\n\tp := Procstat{\n\t\tCGroup:     td,\n\t\tPidFinder:  \"test\",\n\t\tProperties: []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:        testutil.Logger{},\n\t\tfinder:     newTestFinder([]pid{processID}),\n\t}\n\trequire.NoError(t, p.Init())\n\n\tpidsTags, err := p.findPids()\n\trequire.NoError(t, err)\n\tfor _, pidsTag := range pidsTags {\n\t\trequire.Equal(t, []pid{1234, 5678}, pidsTag.PIDs)\n\t\trequire.Equal(t, td, pidsTag.Tags[\"cgroup\"])\n\t}\n}\n\nfunc TestProcstatLookupMetric(t *testing.T) {\n\tp := Procstat{\n\t\tExe:           \"-Gsys\",\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{543}),\n\t\tcreateProcess: newProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\trequire.NotEmpty(t, acc.GetTelegrafMetrics())\n}\n\nfunc TestGather_SameTimestamps(t *testing.T) {\n\tpidfile := \"/path/to/pidfile\"\n\n\tp := Procstat{\n\t\tPidFile:       pidfile,\n\t\tPidFinder:     \"test\",\n\t\tProperties:    []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:           testutil.Logger{},\n\t\tfinder:        newTestFinder([]pid{processID}),\n\t\tcreateProcess: newTestProc,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\tprocstat, _ := acc.Get(\"procstat\")\n\tprocstatLookup, _ := acc.Get(\"procstat_lookup\")\n\n\trequire.Equal(t, procstat.Time, procstatLookup.Time)\n}\n\nfunc TestGather_supervisorUnitPIDs(t *testing.T) {\n\tp := Procstat{\n\t\tSupervisorUnits: []string{\"TestGather_supervisorUnitPIDs\"},\n\t\tPidFinder:       \"test\",\n\t\tProperties:      []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:             testutil.Logger{},\n\t\tfinder:          newTestFinder([]pid{processID}),\n\t}\n\trequire.NoError(t, p.Init())\n\n\tpidsTags, err := p.findPids()\n\trequire.NoError(t, err)\n\tfor _, pidsTag := range pidsTags {\n\t\trequire.Equal(t, []pid{7311, 8111, 8112}, pidsTag.PIDs)\n\t\trequire.Equal(t, \"TestGather_supervisorUnitPIDs\", pidsTag.Tags[\"supervisor_unit\"])\n\t}\n}\n\nfunc TestGather_MoresupervisorUnitPIDs(t *testing.T) {\n\tp := Procstat{\n\t\tSupervisorUnits: []string{\"TestGather_STARTINGsupervisorUnitPIDs\", \"TestGather_FATALsupervisorUnitPIDs\"},\n\t\tPidFinder:       \"test\",\n\t\tProperties:      []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:             testutil.Logger{},\n\t\tfinder:          newTestFinder([]pid{processID}),\n\t}\n\trequire.NoError(t, p.Init())\n\n\tpidsTags, err := p.findPids()\n\trequire.NoError(t, err)\n\tfor _, pidsTag := range pidsTags {\n\t\trequire.Empty(t, pidsTag.PIDs)\n\t\tswitch pidsTag.Tags[\"supervisor_unit\"] {\n\t\tcase \"TestGather_STARTINGsupervisorUnitPIDs\":\n\t\t\trequire.Equal(t, \"STARTING\", pidsTag.Tags[\"status\"])\n\t\tcase \"TestGather_FATALsupervisorUnitPIDs\":\n\t\t\trequire.Equal(t, \"FATAL\", pidsTag.Tags[\"status\"])\n\t\t\trequire.Equal(t, \"Exited too quickly (process log may have details)\", pidsTag.Tags[\"error\"])\n\t\tdefault:\n\t\t\tt.Fatalf(\"unexpected value for tag 'supervisor_unit': %q\", pidsTag.Tags[\"supervisor_unit\"])\n\t\t}\n\t}\n}\n\nfunc TestGather_MultipleFiltersMatchingSameProcess(t *testing.T) {\n\t// This test verifies that when multiple filters match the same process (PID),\n\t// each filter produces metrics with its own unique filter tag.\n\t// This is a regression test for https://github.com/influxdata/telegraf/issues/18041\n\tprocessID := pid(os.Getpid())\n\tprocessName, err := gopsprocess.NewProcess(int32(processID))\n\trequire.NoError(t, err)\n\tname, err := processName.Name()\n\trequire.NoError(t, err)\n\n\tp := Procstat{\n\t\tProperties: []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:        testutil.Logger{},\n\t\tFilter: []filter{\n\t\t\t{\n\t\t\t\tName:         \"filter_one\",\n\t\t\t\tProcessNames: []string{\"*\" + name}, // Match current process\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:         \"filter_two\",\n\t\t\t\tProcessNames: []string{\"*\" + name}, // Same pattern matches same process\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\t// Collect all procstat metrics and their filter tags\n\tfilterTagsFound := make(map[string]int)\n\tfor _, m := range acc.GetTelegrafMetrics() {\n\t\tif m.Name() == \"procstat\" {\n\t\t\tfilterTag, ok := m.GetTag(\"filter\")\n\t\t\trequire.True(t, ok, \"procstat metric should have a filter tag\")\n\t\t\tfilterTagsFound[filterTag]++\n\t\t}\n\t}\n\n\t// Verify that we got metrics from both filters with their respective tags\n\trequire.Contains(t, filterTagsFound, \"filter_one\", \"should have metrics with filter=filter_one\")\n\trequire.Contains(t, filterTagsFound, \"filter_two\", \"should have metrics with filter=filter_two\")\n\n\t// Both filters should produce at least one metric for the matching process\n\trequire.GreaterOrEqual(t, filterTagsFound[\"filter_one\"], 1, \"filter_one should produce at least 1 metric\")\n\trequire.GreaterOrEqual(t, filterTagsFound[\"filter_two\"], 1, \"filter_two should produce at least 1 metric\")\n}\n\nfunc TestGather_MultipleFiltersProcessCacheIsolation(t *testing.T) {\n\t// This test verifies that the process cache is correctly isolated per filter.\n\t// Each filter should maintain its own process cache for CPU usage calculations.\n\t// This is a regression test for https://github.com/influxdata/telegraf/issues/18041\n\tprocessID := pid(os.Getpid())\n\tprocessName, err := gopsprocess.NewProcess(int32(processID))\n\trequire.NoError(t, err)\n\tname, err := processName.Name()\n\trequire.NoError(t, err)\n\n\tp := Procstat{\n\t\tProperties: []string{\"cpu\", \"memory\", \"mmap\"},\n\t\tLog:        testutil.Logger{},\n\t\tFilter: []filter{\n\t\t\t{\n\t\t\t\tName:         \"first\",\n\t\t\t\tProcessNames: []string{\"*\" + name},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:         \"second\",\n\t\t\t\tProcessNames: []string{\"*\" + name},\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, p.Init())\n\n\t// First gather - should create process entries for both filters\n\tvar acc1 testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc1))\n\n\t// Verify process cache has entries for both filters\n\trequire.Contains(t, p.processes, \"first\", \"process cache should have 'first' filter\")\n\trequire.Contains(t, p.processes, \"second\", \"process cache should have 'second' filter\")\n\n\t// Both filters should have the same PID in their cache\n\trequire.Contains(t, p.processes[\"first\"], processID, \"first filter should cache current process\")\n\trequire.Contains(t, p.processes[\"second\"], processID, \"second filter should cache current process\")\n\n\t// The cached process objects should be different instances\n\tproc1 := p.processes[\"first\"][processID]\n\tproc2 := p.processes[\"second\"][processID]\n\trequire.NotSame(t, proc1, proc2, \"each filter should have its own process instance\")\n\n\t// Second gather - should reuse cached processes for delta calculations\n\tvar acc2 testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc2))\n\n\t// Count metrics per filter\n\tfilterCounts := make(map[string]int)\n\tfor _, m := range acc2.GetTelegrafMetrics() {\n\t\tif m.Name() == \"procstat\" {\n\t\t\tif filterTag, ok := m.GetTag(\"filter\"); ok {\n\t\t\t\tfilterCounts[filterTag]++\n\t\t\t}\n\t\t}\n\t}\n\n\t// Both filters should still produce metrics\n\trequire.GreaterOrEqual(t, filterCounts[\"first\"], 1, \"first filter should produce metrics on second gather\")\n\trequire.GreaterOrEqual(t, filterCounts[\"second\"], 1, \"second filter should produce metrics on second gather\")\n}\n"
  },
  {
    "path": "plugins/inputs/procstat/sample.conf",
    "content": "# Monitor process cpu and memory usage\n[[inputs.procstat]]\n  ## PID file to monitor process\n  pid_file = \"/var/run/nginx.pid\"\n  ## executable name (ie, pgrep <exe>)\n  # exe = \"nginx\"\n  ## pattern as argument for pgrep (ie, pgrep -f <pattern>)\n  # pattern = \"nginx\"\n  ## user as argument for pgrep (ie, pgrep -u <user>)\n  # user = \"nginx\"\n  ## Systemd unit name, supports globs when include_systemd_children is set to true\n  # systemd_unit = \"nginx.service\"\n  # include_systemd_children = false\n  ## CGroup name or path, supports globs\n  # cgroup = \"systemd/system.slice/nginx.service\"\n  ## Supervisor service names of hypervisorctl management\n  # supervisor_units = [\"webserver\", \"proxy\"]\n\n  ## Windows service name\n  # win_service = \"\"\n\n  ## override for process_name\n  ## This is optional; default is sourced from /proc/<pid>/status\n  # process_name = \"bar\"\n\n  ## Field name prefix\n  # prefix = \"\"\n\n  ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'.\n  # mode = \"irix\"\n\n  ## Add the given information tag instead of a field\n  ## This allows to create unique metrics/series when collecting processes with\n  ## otherwise identical tags. However, please be careful as this can easily\n  ## result in a large number of series, especially with short-lived processes,\n  ## creating high cardinality at the output.\n  ## Available options are:\n  ##   cmdline   -- full commandline\n  ##   pid       -- ID of the process\n  ##   ppid      -- ID of the process' parent\n  ##   status    -- state of the process\n  ##   user      -- username owning the process\n  ## socket only options:\n  ##   protocol  -- protocol type of the process socket\n  ##   state     -- state of the process socket\n  ##   src       -- source address of the process socket (non-unix sockets)\n  ##   src_port  -- source port of the process socket (non-unix sockets)\n  ##   dest      -- destination address of the process socket (non-unix sockets)\n  ##   dest_port -- destination port of the process socket (non-unix sockets)\n  ##   name      -- name of the process socket (unix sockets only)\n  ## Available for procstat_lookup:\n  ##   level     -- level of the process filtering\n  # tag_with = []\n\n  ## Properties to collect\n  ## Available options are\n  ##   cpu     -- CPU usage statistics\n  ##   limits  -- set resource limits\n  ##   memory  -- memory usage statistics\n  ##   mmap    -- mapped memory usage statistics (caution: can cause high load)\n  ##   sockets -- socket statistics for protocols in 'socket_protocols'\n  # properties = [\"cpu\", \"limits\", \"memory\", \"mmap\"]\n\n  ## Protocol filter for the sockets property\n  ## Available options are\n  ##   all  -- all of the protocols below\n  ##   tcp4 -- TCP socket statistics for IPv4\n  ##   tcp6 -- TCP socket statistics for IPv6\n  ##   udp4 -- UDP socket statistics for IPv4\n  ##   udp6 -- UDP socket statistics for IPv6\n  ##   unix -- Unix socket statistics\n  # socket_protocols = [\"all\"]\n\n  ## Method to use when finding process IDs.  Can be one of 'pgrep', or\n  ## 'native'.  The pgrep finder calls the pgrep executable in the PATH while\n  ## the native finder performs the search directly in a manor dependent on the\n  ## platform.  Default is 'pgrep'\n  # pid_finder = \"pgrep\"\n\n  ## New-style filtering configuration (multiple filter sections are allowed)\n  # [[inputs.procstat.filter]]\n  #    ## Name of the filter added as 'filter' tag\n  #    name = \"shell\"\n  #\n  #    ## Service filters, only one is allowed\n  #    ## Systemd unit names (wildcards are supported)\n  #    # systemd_units = []\n  #    ## CGroup name or path (wildcards are supported)\n  #    # cgroups = []\n  #    ## Supervisor service names of hypervisorctl management\n  #    # supervisor_units = []\n  #    ## Windows service names\n  #    # win_service = []\n  #\n  #    ## Process filters, multiple are allowed\n  #    ## Regular expressions to use for matching against the full command\n  #    # patterns = ['.*']\n  #    ## List of users owning the process (wildcards are supported)\n  #    # users = ['*']\n  #    ## List of executable paths of the process (wildcards are supported)\n  #    # executables = ['*']\n  #    ## List of process names (wildcards are supported)\n  #    # process_names = ['*']\n  #    ## Recursion depth for determining children of the matched processes\n  #    ## A negative value means all children with infinite depth\n  #    # recursion_depth = 0\n"
  },
  {
    "path": "plugins/inputs/procstat/service_finders.go",
    "content": "package procstat\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\tgopsprocess \"github.com/shirou/gopsutil/v4/process\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype processFinder struct {\n\terrPidFiles map[string]bool\n\tlog         telegraf.Logger\n}\n\nfunc newProcessFinder(log telegraf.Logger) *processFinder {\n\treturn &processFinder{\n\t\terrPidFiles: make(map[string]bool),\n\t\tlog:         log,\n\t}\n}\n\nfunc (f *processFinder) findByPidFiles(paths []string) ([]processGroup, error) {\n\tgroups := make([]processGroup, 0, len(paths))\n\tfor _, path := range paths {\n\t\tbuf, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read pidfile %q: %w\", path, err)\n\t\t}\n\t\tpid, err := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse PID in file %q: %w\", path, err)\n\t\t}\n\n\t\tp, err := gopsprocess.NewProcess(int32(pid))\n\t\tif err != nil && !f.errPidFiles[path] {\n\t\t\tf.log.Errorf(\"failed to find process for PID %d of file %q: %v\", pid, path, err)\n\t\t\tf.errPidFiles[path] = true\n\t\t}\n\t\tgroups = append(groups, processGroup{\n\t\t\tprocesses: []*gopsprocess.Process{p},\n\t\t\ttags:      map[string]string{\"pidfile\": path},\n\t\t})\n\t}\n\n\treturn groups, nil\n}\n\nfunc findByCgroups(cgroups []string) ([]processGroup, error) {\n\tgroups := make([]processGroup, 0, len(cgroups))\n\tfor _, cgroup := range cgroups {\n\t\tpath := cgroup\n\t\tif !filepath.IsAbs(cgroup) {\n\t\t\tpath = filepath.Join(\"sys\", \"fs\", \"cgroup\"+cgroup)\n\t\t}\n\n\t\tfiles, err := filepath.Glob(path)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to determine files for cgroup %q: %w\", cgroup, err)\n\t\t}\n\n\t\tfor _, fpath := range files {\n\t\t\tif f, err := os.Stat(fpath); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"accessing %q failed: %w\", fpath, err)\n\t\t\t} else if !f.IsDir() {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is not a directory\", fpath)\n\t\t\t}\n\n\t\t\tfn := filepath.Join(fpath, \"cgroup.procs\")\n\t\t\tbuf, err := os.ReadFile(fn)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tlines := bytes.Split(buf, []byte{'\\n'})\n\t\t\tprocs := make([]*gopsprocess.Process, 0, len(lines))\n\t\t\tfor _, l := range lines {\n\t\t\t\tl := strings.TrimSpace(string(l))\n\t\t\t\tif len(l) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tpid, err := strconv.ParseInt(l, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to parse PID %q in file %q\", l, fpath)\n\t\t\t\t}\n\t\t\t\tp, err := gopsprocess.NewProcess(int32(pid))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to find process for PID %d of %q: %w\", pid, fpath, err)\n\t\t\t\t}\n\t\t\t\tprocs = append(procs, p)\n\t\t\t}\n\n\t\t\tgroups = append(groups, processGroup{\n\t\t\t\tprocesses: procs,\n\t\t\t\ttags:      map[string]string{\"cgroup\": cgroup, \"cgroup_full\": fpath}})\n\t\t}\n\t}\n\n\treturn groups, nil\n}\n\nfunc findBySupervisorUnits(units string) ([]processGroup, error) {\n\tbuf, err := execCommand(\"supervisorctl\", \"status\", units, \" \").Output()\n\tif err != nil && !strings.Contains(err.Error(), \"exit status 3\") {\n\t\t// Exit 3 means at least on process is in one of the \"STOPPED\" states\n\t\treturn nil, fmt.Errorf(\"failed to execute 'supervisorctl': %w\", err)\n\t}\n\tlines := strings.Split(string(buf), \"\\n\")\n\n\t// Get the PID, running status, running time and boot time of the main process:\n\t// pid 11779, uptime 17:41:16\n\t// Exited too quickly (process log may have details)\n\tgroups := make([]processGroup, 0, len(lines))\n\tfor _, line := range lines {\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tkv := strings.Fields(line)\n\t\tif len(kv) < 2 {\n\t\t\t// Not a key-value pair\n\t\t\tcontinue\n\t\t}\n\t\tname, status := kv[0], kv[1]\n\t\ttags := map[string]string{\n\t\t\t\"supervisor_unit\": name,\n\t\t\t\"status\":          status,\n\t\t}\n\n\t\tvar procs []*gopsprocess.Process\n\t\tswitch status {\n\t\tcase \"FATAL\", \"EXITED\", \"BACKOFF\", \"STOPPING\":\n\t\t\ttags[\"error\"] = strings.Join(kv[2:], \" \")\n\t\tcase \"RUNNING\":\n\t\t\ttags[\"uptimes\"] = kv[5]\n\t\t\trawpid := strings.ReplaceAll(kv[3], \",\", \"\")\n\t\t\tgrouppid, err := strconv.ParseInt(rawpid, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse group PID %q: %w\", rawpid, err)\n\t\t\t}\n\t\t\tp, err := gopsprocess.NewProcess(int32(grouppid))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to find process for PID %d of unit %q: %w\", grouppid, name, err)\n\t\t\t}\n\t\t\t// Get all children of the supervisor unit\n\t\t\tprocs, err = p.Children()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get children for PID %d of unit %q: %w\", grouppid, name, err)\n\t\t\t}\n\t\t\ttags[\"parent_pid\"] = rawpid\n\t\tcase \"STOPPED\", \"UNKNOWN\", \"STARTING\":\n\t\t\t// No additional info\n\t\t}\n\n\t\tgroups = append(groups, processGroup{\n\t\t\tprocesses: procs,\n\t\t\ttags:      tags,\n\t\t})\n\t}\n\n\treturn groups, nil\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/README.md",
    "content": "# Prometheus Input Plugin\n\nThis plugin gathers metrics from [Prometheus][prometheus] metric endpoints such\nas applications implementing such an endpoint or node-exporter instances. This\nplugin also supports various service-discovery methods.\n\n⭐ Telegraf v0.1.5\n🏷️ applications, server\n💻 all\n\n[prometheus]: https://prometheus.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username`, `password`\nand `bearer_token_string` option. See the\n[secret-store documentation][SECRETSTORE] for more details on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many prometheus clients\n[[inputs.prometheus]]\n  ## An array of urls to scrape metrics from.\n  urls = [\"http://localhost:9100/metrics\"]\n\n  ## Metric version controls the mapping from Prometheus metrics into Telegraf metrics.\n  ## See \"Metric Format Configuration\" in plugins/inputs/prometheus/README.md for details.\n  ## Valid options: 1, 2\n  # metric_version = 1\n\n  ## Url tag name (tag containing scrapped url. optional, default is \"url\")\n  # url_tag = \"url\"\n\n  ## Whether the timestamp of the scraped metrics will be ignored.\n  ## If set to true, the gather time will be used.\n  # ignore_timestamp = false\n\n  ## Override content-type of the returned message\n  ## Available options are for prometheus:\n  ##   text, protobuf-delimiter, protobuf-compact, protobuf-text,\n  ## and for openmetrics:\n  ##   openmetrics-text, openmetrics-protobuf\n  ## By default the content-type of the response is used.\n  # content_type_override = \"\"\n\n  ## An array of Kubernetes services to scrape metrics from.\n  # kubernetes_services = [\"http://my-service-dns.my-namespace:9100/metrics\"]\n\n  ## Kubernetes config file to create client from.\n  # kube_config = \"/path/to/kubernetes.config\"\n\n  ## Scrape Pods\n  ## Enable scraping of k8s pods. Further settings as to which pods to scape\n  ## are determiend by the 'method' option below. When enabled, the default is\n  ## to use annotations to determine whether to scrape or not.\n  # monitor_kubernetes_pods = false\n\n  ## Scrape Pods Method\n  ## annotations: default, looks for specific pod annotations documented below\n  ## settings: only look for pods matching the settings provided, not\n  ##   annotations\n  ## settings+annotations: looks at pods that match annotations using the user\n  ##   defined settings\n  # monitor_kubernetes_pods_method = \"annotations\"\n\n  ## Scrape Pods 'annotations' method options\n  ## If set method is set to 'annotations' or 'settings+annotations', these\n  ## annotation flags are looked for:\n  ## - prometheus.io/scrape: Required to enable scraping for this pod. Can also\n  ##     use 'prometheus.io/scrape=false' annotation to opt-out entirely.\n  ## - prometheus.io/scheme: If the metrics endpoint is secured then you will\n  ##     need to set this to 'https' & most likely set the tls config\n  ## - prometheus.io/path: If the metrics path is not /metrics, define it with\n  ##     this annotation\n  ## - prometheus.io/port: If port is not 9102 use this annotation\n\n  ## Scrape Pods 'settings' method options\n  ## When using 'settings' or 'settings+annotations', the default values for\n  ## annotations can be modified using with the following options:\n  # monitor_kubernetes_pods_scheme = \"http\"\n  # monitor_kubernetes_pods_port = \"9102\"\n  # monitor_kubernetes_pods_path = \"/metrics\"\n\n  ## Get the list of pods to scrape with either the scope of\n  ## - cluster: the kubernetes watch api (default, no need to specify)\n  ## - node: the local cadvisor api; for scalability. Note that the config node_ip or the environment variable NODE_IP must be set to the host IP.\n  # pod_scrape_scope = \"cluster\"\n\n  ## Only for node scrape scope: node IP of the node that telegraf is running on.\n  ## Either this config or the environment variable NODE_IP must be set.\n  # node_ip = \"10.180.1.1\"\n\n  ## Only for node scrape scope: interval in seconds for how often to get updated pod list for scraping.\n  ## Default is 60 seconds.\n  # pod_scrape_interval = 60\n\n  ## Content length limit\n  ## When set, telegraf will drop responses with length larger than the configured value.\n  ## Default is \"0KB\" which means unlimited.\n  # content_length_limit = \"0KB\"\n\n  ## Restricts Kubernetes monitoring to a single namespace\n  ##   ex: monitor_kubernetes_pods_namespace = \"default\"\n  # monitor_kubernetes_pods_namespace = \"\"\n  ## The name of the label for the pod that is being scraped.\n  ## Default is 'namespace' but this can conflict with metrics that have the label 'namespace'\n  # pod_namespace_label_name = \"namespace\"\n  # label selector to target pods which have the label\n  # kubernetes_label_selector = \"env=dev,app=nginx\"\n  # field selector to target pods\n  # eg. To scrape pods on a specific node\n  # kubernetes_field_selector = \"spec.nodeName=$HOSTNAME\"\n\n  ## Filter which pod annotations and labels will be added to metric tags\n  #\n  # pod_annotation_include = [\"annotation-key-1\"]\n  # pod_annotation_exclude = [\"exclude-me\"]\n  # pod_label_include = [\"label-key-1\"]\n  # pod_label_exclude = [\"exclude-me\"]\n\n  # cache refresh interval to set the interval for re-sync of pods list.\n  # Default is 60 minutes.\n  # cache_refresh_interval = 60\n\n  ## Use bearer token for authorization. ('bearer_token' takes priority)\n  # bearer_token = \"/path/to/bearer/token\"\n  ## OR\n  # bearer_token_string = \"abc_123\"\n\n  ## HTTP Basic Authentication username and password. ('bearer_token' and\n  ## 'bearer_token_string' take priority)\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional custom HTTP headers\n  # http_headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Specify timeout duration for slower prometheus clients (default is 5s)\n  # timeout = \"5s\"\n\n  ## This option is now used by the HTTP client to set the header response\n  ## timeout, not the overall HTTP timeout.\n  # response_timeout = \"5s\"\n\n  ## HTTP Proxy support\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"myhost.example.org\"\n\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## Enable/disable TLS\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable = true\n\n  ## This option allows you to report the status of prometheus requests.\n  # enable_request_metrics = false\n\n  ## Scrape Services available in Consul Catalog\n  # [inputs.prometheus.consul]\n  #   enabled = true\n  #   agent = \"http://localhost:8500\"\n  #   query_interval = \"5m\"\n\n  #   [[inputs.prometheus.consul.query]]\n  #     name = \"a service name\"\n  #     tag = \"a service tag\"\n  #     url = 'http://{{if ne .ServiceAddress \"\"}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}'\n  #     [inputs.prometheus.consul.query.tags]\n  #       host = \"{{.Node}}\"\n\n  ## Scrape Hosts available with http service discovery\n  # [inputs.prometheus.http_service_discovery]\n  #   enabled = false\n  #   url = \"http://localhost:9000/service-discovery\"\n  #   query_interval = \"5m\"\n\n  ## Control pod scraping based on pod namespace annotations\n  ## Pass and drop here act like tagpass and tagdrop, but instead\n  ## of filtering metrics they filters pod candidates for scraping\n  #[inputs.prometheus.namespace_annotation_pass]\n  # annotation_key = [\"value1\", \"value2\"]\n  #[inputs.prometheus.namespace_annotation_drop]\n  # some_annotation_key = [\"dont-scrape\"]\n```\n\n`urls` can contain a unix socket as well. If a different path is required\n(default is `/metrics` for both http[s] and unix) for a unix socket, add `path`\nas a query parameter as follows:\n`unix:///var/run/prometheus.sock?path=/custom/metrics`\n\n### Metric Format Configuration\n\nThe `metric_version` setting controls how telegraf translates prometheus format\nmetrics to telegraf metrics. There are two options.\n\nWith `metric_version = 1`, the prometheus metric name becomes the telegraf\nmetric name. Prometheus labels become telegraf tags. Prometheus values become\ntelegraf field values. The fields have generic keys based on the type of the\nprometheus metric. This option produces metrics that are dense (not\nsparse). Denseness is a useful property for some outputs, including those that\nare more efficient with row-oriented data.\n\n`metric_version = 2` differs in a few ways. The prometheus metric name becomes a\ntelegraf field key. Metrics hold more than one value and the field keys aren't\ngeneric. The resulting metrics are sparse, but for some outputs they may be\neasier to process or query, including those that are more efficient with\ncolumn-oriented data. The telegraf metric name is the same for all metrics in\nthe input instance. It can be set with the `name_override` setting and defaults\nto \"prometheus\". To have multiple metric names, you can use multiple instances\nof the plugin, each with its own `name_override`.\n\n`metric_version = 2` uses the same histogram format as the [histogram\naggregator](../../aggregators/histogram/README.md)\n\nThe Example Outputs sections shows examples for both options.\n\nWhen using this plugin along with the prometheus_client output, use the same\noption in both to ensure metrics are round-tripped without modification.\n\n### Kubernetes Service Discovery\n\nURLs listed in the `kubernetes_services` parameter will be expanded by looking\nup all A records assigned to the hostname as described in [Kubernetes DNS\nservice discovery][serv-disc].\n\nThis method can be used to locate all [Kubernetes headless services][headless].\n\n[serv-disc]: https://kubernetes.io/docs/concepts/services-networking/service/#dns\n\n[headless]: https://kubernetes.io/docs/concepts/services-networking/service/#headless-services\n\n### Kubernetes scraping\n\nEnabling this option will allow the plugin to scrape for prometheus annotation\non Kubernetes pods. Currently, you can run this plugin in your kubernetes\ncluster, or we use the kubeconfig file to determine where to monitor.  Currently\nthe following annotation are supported:\n\n* `prometheus.io/scrape` Enable scraping for this pod.\n* `prometheus.io/scheme` If the metrics endpoint is secured then you will need\n                         to set this to `https` & most likely set the tls config.\n                        (default 'http')\n* `prometheus.io/path`  Override the path for the metrics endpoint on the service.\n                        (default '/metrics')\n* `prometheus.io/port`  Used to override the port. (default 9102)\n\nUsing the `monitor_kubernetes_pods_namespace` option allows you to limit which\npods you are scraping.\n\nThe setting `pod_namespace_label_name` allows you to change the label name for\nthe namespace of the pod you are scraping. The default is `namespace`, but this\nwill overwrite a label with the name `namespace` from a metric scraped.\n\nUsing `pod_scrape_scope = \"node\"` allows more scalable scraping for pods which\nwill scrape pods only in the node that telegraf is running. It will fetch the\npod list locally from the node's kubelet. This will require running Telegraf in\nevery node of the cluster. Note that either `node_ip` must be specified in the\nconfig or the environment variable `NODE_IP` must be set to the host IP. ThisThe\nlatter can be done in the yaml of the pod running telegraf:\n\n```sh\nenv:\n  - name: NODE_IP\n    valueFrom:\n      fieldRef:\n        fieldPath: status.hostIP\n ```\n\nIf using node level scrape scope, `pod_scrape_interval` specifies how often (in\nseconds) the pod list for scraping should updated. If not specified, the default\nis 60 seconds.\n\nThe pod running telegraf will need to have the proper rbac configuration in\norder to be allowed to call the k8s api to discover and watch pods in the\ncluster.  A typical configuration will create a service account, a cluster role\nwith the appropriate rules and a cluster role binding to tie the cluster role to\nthe service account.  Example of configuration for cluster level discovery:\n\n```yaml\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: telegraf-k8s-role-{{.Release.Name}}\nrules:\n- apiGroups: [\"\"]\n  resources:\n  - nodes\n  - nodes/proxy\n  - services\n  - endpoints\n  - pods\n  verbs: [\"get\", \"list\", \"watch\"]\n---\n# Rolebinding for namespace to cluster-admin\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: telegraf-k8s-role-{{.Release.Name}}\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: telegraf-k8s-role-{{.Release.Name}}\nsubjects:\n- kind: ServiceAccount\n  name: telegraf-k8s-{{ .Release.Name }}\n  namespace: {{ .Release.Namespace }}\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: telegraf-k8s-{{ .Release.Name }}\n```\n\n### Consul Service Discovery\n\nEnabling this option and configuring consul `agent` url will allow the plugin to\nquery consul catalog for available services. Using `query_interval` the plugin\nwill periodically query the consul catalog for services with `name` and `tag`\nand refresh the list of scraped urls.  It can use the information from the\ncatalog to build the scraped url and additional tags from a template.\n\nMultiple consul queries can be configured, each for different service.\nThe following example fields can be used in url or tag templates:\n\n* Node\n* Address\n* NodeMeta\n* ServicePort\n* ServiceAddress\n* ServiceTags\n* ServiceMeta\n\nFor full list of available fields and their type see struct CatalogService in\n<https://github.com/hashicorp/consul/blob/master/api/catalog.go>\n\n### HTTP Service Discovery\n\nEnabling this option and configuring `url` will allow the plugin to\nquery a given http service discovery endpoint for available hosts. Using\n`query_interval` the plugin will periodically query the endpoint for services\nand refresh the list of scraped urls.  It can use the information from the\nresponse to build the scraped url and additional tags.\n\nMore information on the format of http service discovery is found in the\n[prometheus documentation][http_sd].\n\n[http_sd]: https://prometheus.io/docs/prometheus/latest/http_sd\n\n### Bearer Token\n\nIf set, the file specified by the `bearer_token` parameter will be read on\neach interval and its contents will be appended to the Bearer string in the\nAuthorization header.\n\n## Usage for Caddy HTTP server\n\nSteps to monitor Caddy with Telegraf's Prometheus input plugin:\n\n* Download [Caddy](https://caddyserver.com/download)\n* Download Prometheus and set up [monitoring Caddy with Prometheus metrics](https://caddyserver.com/docs/metrics#monitoring-caddy-with-prometheus-metrics)\n* Restart Caddy\n* Configure Telegraf to fetch metrics on it:\n\n```toml\n[[inputs.prometheus]]\n#   ## An array of urls to scrape metrics from.\n  urls = [\"http://localhost:2019/metrics\"]\n```\n\n> This is the default URL where Caddy will send data.\n> For more details, please read the [Caddy Prometheus documentation](https://github.com/miekg/caddy-prometheus/blob/master/README.md).\n\n## Metrics\n\nMeasurement names are based on the Metric Family and tags are created for each\nlabel.  The value is added to a field named based on the metric type.\n\nAll metrics receive the `url` tag indicating the related URL specified in the\nTelegraf configuration. If using Kubernetes service discovery the `address`\ntag is also added indicating the discovered ip address.\n\n* prometheus_request\n  * tags:\n    * url\n    * address\n  * fields:\n    * response_time (float, seconds)\n    * content_length (int, response body length)\n\n## Example Output\n\n### Source\n\n```shell\n# HELP go_gc_duration_seconds A summary of the GC invocation durations.\n# TYPE go_gc_duration_seconds summary\ngo_gc_duration_seconds{quantile=\"0\"} 7.4545e-05\ngo_gc_duration_seconds{quantile=\"0.25\"} 7.6999e-05\ngo_gc_duration_seconds{quantile=\"0.5\"} 0.000277935\ngo_gc_duration_seconds{quantile=\"0.75\"} 0.000706591\ngo_gc_duration_seconds{quantile=\"1\"} 0.000706591\ngo_gc_duration_seconds_sum 0.00113607\ngo_gc_duration_seconds_count 4\n# HELP go_goroutines Number of goroutines that currently exist.\n# TYPE go_goroutines gauge\ngo_goroutines 15\n# HELP cpu_usage_user Telegraf collected metric\n# TYPE cpu_usage_user gauge\ncpu_usage_user{cpu=\"cpu0\"} 1.4112903225816156\ncpu_usage_user{cpu=\"cpu1\"} 0.702106318955865\ncpu_usage_user{cpu=\"cpu2\"} 2.0161290322588776\ncpu_usage_user{cpu=\"cpu3\"} 1.5045135406226022\n```\n\n### Output\n\n```text\ngo_gc_duration_seconds,url=http://example.org:9273/metrics 1=0.001336611,count=14,sum=0.004527551,0=0.000057965,0.25=0.000083812,0.5=0.000286537,0.75=0.000365303 1505776733000000000\ngo_goroutines,url=http://example.org:9273/metrics gauge=21 1505776695000000000\ncpu_usage_user,cpu=cpu0,url=http://example.org:9273/metrics gauge=1.513622603430151 1505776751000000000\ncpu_usage_user,cpu=cpu1,url=http://example.org:9273/metrics gauge=5.829145728641773 1505776751000000000\ncpu_usage_user,cpu=cpu2,url=http://example.org:9273/metrics gauge=2.119071644805144 1505776751000000000\ncpu_usage_user,cpu=cpu3,url=http://example.org:9273/metrics gauge=1.5228426395944945 1505776751000000000\nprometheus_request,result=success,url=http://example.org:9273/metrics content_length=179013i,http_response_code=200i,response_time=0.051521601 1505776751000000000\n```\n\n### Output (when metric_version = 2)\n\n```text\nprometheus,quantile=1,url=http://example.org:9273/metrics go_gc_duration_seconds=0.005574303 1556075100000000000\nprometheus,quantile=0.75,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0001046 1556075100000000000\nprometheus,quantile=0.5,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000719 1556075100000000000\nprometheus,quantile=0.25,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000579 1556075100000000000\nprometheus,quantile=0,url=http://example.org:9273/metrics go_gc_duration_seconds=0.0000349 1556075100000000000\nprometheus,url=http://example.org:9273/metrics go_gc_duration_seconds_count=324,go_gc_duration_seconds_sum=0.091340353 1556075100000000000\nprometheus,url=http://example.org:9273/metrics go_goroutines=15 1556075100000000000\nprometheus,cpu=cpu0,url=http://example.org:9273/metrics cpu_usage_user=1.513622603430151 1505776751000000000\nprometheus,cpu=cpu1,url=http://example.org:9273/metrics cpu_usage_user=5.829145728641773 1505776751000000000\nprometheus,cpu=cpu2,url=http://example.org:9273/metrics cpu_usage_user=2.119071644805144 1505776751000000000\nprometheus,cpu=cpu3,url=http://example.org:9273/metrics cpu_usage_user=1.5228426395944945 1505776751000000000\nprometheus_request,result=success,url=http://example.org:9273/metrics content_length=179013i,http_response_code=200i,response_time=0.051521601 1505776751000000000\n```\n\n### Output with timestamp included\n\nBelow is an example of a Prometheus metric which includes a timestamp:\n\n```text\n# TYPE test_counter counter\ntest_counter{label=\"test\"} 1 1685443805885\n```\n\nTelegraf will generate the following metric:\n\n```text\ntest_counter,address=127.0.0.1,label=test counter=1 1685443805885000000\n```\n\nusing the standard configuration\n\n```toml\n[[inputs.prometheus]]\n  ## An array of urls to scrape metrics from.\n  urls = [\"http://localhost:2019/metrics\"]\n```\n\n**Please note:** Metrics generated by Prometheus endpoints are generated with\n*millisecond precision*. The default Telegraf agent level precision setting\nreduces this to seconds. Change the `precision` setting at agent or plugin level\nto milliseconds or smaller to report metric timestamps with full precision.\n"
  },
  {
    "path": "plugins/inputs/prometheus/consul.go",
    "content": "package prometheus\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/hashicorp/consul/api\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype consulConfig struct {\n\t// Address of the Consul agent. The address must contain a hostname or an IP address\n\t// and optionally a port (format: \"host:port\").\n\tEnabled       bool            `toml:\"enabled\"`\n\tAgent         string          `toml:\"agent\"`\n\tQueryInterval config.Duration `toml:\"query_interval\"`\n\tQueries       []*consulQuery  `toml:\"query\"`\n}\n\n// One Consul service discovery query\ntype consulQuery struct {\n\t// A name of the searched services (not ID)\n\tServiceName string `toml:\"name\"`\n\n\t// A tag of the searched services\n\tServiceTag string `toml:\"tag\"`\n\n\t// A DC of the searched services\n\tServiceDc string `toml:\"dc\"`\n\n\t// A template URL of the Prometheus gathering interface. The hostname part\n\t// of the URL will be replaced by discovered address and port.\n\tServiceURL string `toml:\"url\"`\n\n\t// Extra tags to add to metrics found in Consul\n\tServiceExtraTags map[string]string `toml:\"tags\"`\n\n\tserviceURLTemplate       *template.Template\n\tserviceExtraTagsTemplate map[string]*template.Template\n\n\t// Store last error status and change log level depending on repeated occurrence\n\tlastQueryFailed bool\n}\n\nfunc (p *Prometheus) startConsul(ctx context.Context) error {\n\tconsulAPIConfig := api.DefaultConfig()\n\tif p.ConsulConfig.Agent != \"\" {\n\t\tconsulAPIConfig.Address = p.ConsulConfig.Agent\n\t}\n\n\tconsul, err := api.NewClient(consulAPIConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot connect to the Consul agent: %w\", err)\n\t}\n\n\t// Parse the template for metrics URL, drop queries with template parse errors\n\ti := 0\n\tfor _, q := range p.ConsulConfig.Queries {\n\t\tserviceURLTemplate, err := template.New(\"URL\").Parse(q.ServiceURL)\n\t\tif err != nil {\n\t\t\tp.Log.Errorf(\"Could not parse the Consul query URL template (%s), skipping it. Error: %s\", q.ServiceURL, err)\n\t\t\tcontinue\n\t\t}\n\t\tq.serviceURLTemplate = serviceURLTemplate\n\n\t\t// Allow to use join function in tags\n\t\ttemplateFunctions := template.FuncMap{\"join\": strings.Join}\n\t\t// Parse the tag value templates\n\t\tq.serviceExtraTagsTemplate = make(map[string]*template.Template)\n\t\tfor tagName, tagTemplateString := range q.ServiceExtraTags {\n\t\t\ttagTemplate, err := template.New(tagName).Funcs(templateFunctions).Parse(tagTemplateString)\n\t\t\tif err != nil {\n\t\t\t\tp.Log.Errorf(\"Could not parse the Consul query Extra Tag template (%s), skipping it. Error: %s\", tagTemplateString, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tq.serviceExtraTagsTemplate[tagName] = tagTemplate\n\t\t}\n\t\tp.ConsulConfig.Queries[i] = q\n\t\ti++\n\t}\n\t// Prevent memory leak by erasing truncated values\n\tfor j := i; j < len(p.ConsulConfig.Queries); j++ {\n\t\tp.ConsulConfig.Queries[j] = nil\n\t}\n\tp.ConsulConfig.Queries = p.ConsulConfig.Queries[:i]\n\n\tcatalog := consul.Catalog()\n\n\tp.wg.Add(1)\n\tgo func() {\n\t\t// Store last error status and change log level depending on repeated occurrence\n\t\tvar refreshFailed = false\n\t\tdefer p.wg.Done()\n\t\terr := p.refreshConsulServices(catalog)\n\t\tif err != nil {\n\t\t\trefreshFailed = true\n\t\t\tp.Log.Errorf(\"Unable to refresh Consul services: %v\", err)\n\t\t}\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-time.After(time.Duration(p.ConsulConfig.QueryInterval)):\n\t\t\t\terr := p.refreshConsulServices(catalog)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmessage := fmt.Sprintf(\"Unable to refresh Consul services: %v\", err)\n\t\t\t\t\tif refreshFailed {\n\t\t\t\t\t\tp.Log.Debug(message)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.Log.Warn(message)\n\t\t\t\t\t}\n\t\t\t\t\trefreshFailed = true\n\t\t\t\t} else if refreshFailed {\n\t\t\t\t\trefreshFailed = false\n\t\t\t\t\tp.Log.Info(\"Successfully refreshed Consul services after previous errors\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (p *Prometheus) refreshConsulServices(c *api.Catalog) error {\n\tconsulServiceURLs := make(map[string]urlAndAddress)\n\n\tp.Log.Debugf(\"Refreshing Consul services\")\n\n\tfor _, q := range p.ConsulConfig.Queries {\n\t\tqueryOptions := api.QueryOptions{}\n\t\tif q.ServiceDc != \"\" {\n\t\t\tqueryOptions.Datacenter = q.ServiceDc\n\t\t}\n\n\t\t// Request services from Consul\n\t\tconsulServices, _, err := c.Service(q.ServiceName, q.ServiceTag, &queryOptions)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(consulServices) == 0 {\n\t\t\tp.Log.Debugf(\"Queried Consul for Service (%s, %s) but did not find any instances\", q.ServiceName, q.ServiceTag)\n\t\t\tcontinue\n\t\t}\n\t\tp.Log.Debugf(\"Queried Consul for Service (%s, %s) and found %d instances\", q.ServiceName, q.ServiceTag, len(consulServices))\n\n\t\tfor _, consulService := range consulServices {\n\t\t\tuaa, err := p.getConsulServiceURL(q, consulService)\n\t\t\tif err != nil {\n\t\t\t\tmessage := fmt.Sprintf(\"Unable to get scrape URLs from Consul for Service (%s, %s): %s\", q.ServiceName, q.ServiceTag, err)\n\t\t\t\tif q.lastQueryFailed {\n\t\t\t\t\tp.Log.Debug(message)\n\t\t\t\t} else {\n\t\t\t\t\tp.Log.Warn(message)\n\t\t\t\t}\n\t\t\t\tq.lastQueryFailed = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif q.lastQueryFailed {\n\t\t\t\tp.Log.Infof(\"Created scrape URLs from Consul for Service (%s, %s)\", q.ServiceName, q.ServiceTag)\n\t\t\t}\n\t\t\tq.lastQueryFailed = false\n\t\t\tp.Log.Debugf(\"Adding scrape URL from Consul for Service (%s, %s): %s\", q.ServiceName, q.ServiceTag, uaa.url.String())\n\t\t\tconsulServiceURLs[uaa.url.String()] = *uaa\n\t\t}\n\t}\n\n\tp.lock.Lock()\n\tp.consulServices = consulServiceURLs\n\tp.lock.Unlock()\n\n\treturn nil\n}\n\nfunc (p *Prometheus) getConsulServiceURL(q *consulQuery, s *api.CatalogService) (*urlAndAddress, error) {\n\tvar buffer bytes.Buffer\n\tbuffer.Reset()\n\terr := q.serviceURLTemplate.Execute(&buffer, s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tserviceURL, err := url.Parse(buffer.String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\textraTags := make(map[string]string)\n\tfor tagName, tagTemplate := range q.serviceExtraTagsTemplate {\n\t\tbuffer.Reset()\n\t\terr = tagTemplate.Execute(&buffer, s)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\textraTags[tagName] = buffer.String()\n\t}\n\n\tp.Log.Debugf(\"Will scrape metrics from Consul Service %s\", serviceURL.String())\n\n\treturn &urlAndAddress{\n\t\turl:         serviceURL,\n\t\toriginalURL: serviceURL,\n\t\ttags:        extraTags,\n\t}, nil\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/http_service_discovery.go",
    "content": "package prometheus\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype HTTPSDConfig struct {\n\tEnabled       bool            `toml:\"enabled\"`\n\tURL           string          `toml:\"url\"`\n\tQueryInterval config.Duration `toml:\"query_interval\"`\n}\n\n// standard output for http service discovery is here https://prometheus.io/docs/prometheus/latest/http_sd/#http_sd-format\ntype httpSDOutput struct {\n\tTargets []string          `json:\"targets\"`\n\tLabels  map[string]string `json:\"labels\"`\n}\n\nfunc (p *Prometheus) startHTTPSD(ctx context.Context) error {\n\t// default settings\n\tvar queryInterval time.Duration\n\tif p.HTTPSDConfig.QueryInterval == 0 {\n\t\tqueryInterval = time.Duration(5) * time.Minute\n\t} else {\n\t\tqueryInterval = time.Duration(p.HTTPSDConfig.QueryInterval)\n\t}\n\n\tif p.HTTPSDConfig.URL == \"\" {\n\t\tp.HTTPSDConfig.URL = \"http://localhost:9000/service-discovery\"\n\t}\n\n\ttlsCfg, err := p.HTTPClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.wg.Add(1)\n\tgo func() {\n\t\tdefer p.wg.Done()\n\t\tclient := &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tTLSClientConfig:   tlsCfg,\n\t\t\t\tDisableKeepAlives: true,\n\t\t\t},\n\t\t}\n\t\tdefer client.CloseIdleConnections()\n\t\tif err := p.refreshHTTPServices(p.HTTPSDConfig.URL, client); err != nil {\n\t\t\tp.Log.Errorf(\"Unable to refresh HTTP scraped services: %v\", err)\n\t\t}\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-time.After(queryInterval):\n\t\t\t\terr := p.refreshHTTPServices(p.HTTPSDConfig.URL, client)\n\t\t\t\tif err != nil {\n\t\t\t\t\tp.Log.Errorf(\"Unable to refresh HTTP scraped services: %v\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (p *Prometheus) refreshHTTPServices(sdURL string, client *http.Client) error {\n\tservices := make(map[string]urlAndAddress)\n\treq, err := http.NewRequest(\"GET\", sdURL, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"discovery failed with status %q\", resp.Status)\n\t}\n\n\tvar body []byte\n\tbody, err = io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading response body failed: %w\", err)\n\t}\n\n\tvar result []httpSDOutput\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn fmt.Errorf(\"unmarshalling JSON failed: %w\", err)\n\t}\n\n\t// Validate the response\n\tif len(result) == 0 {\n\t\tp.Log.Warnf(\"Service discovery returned no results\")\n\t}\n\n\tfor _, sdOutputItem := range result {\n\t\tfor _, targetValue := range sdOutputItem.Targets {\n\t\t\tif !strings.HasPrefix(targetValue, \"http://\") && !strings.HasPrefix(targetValue, \"https://\") {\n\t\t\t\ttargetValue = \"http://\" + targetValue\n\t\t\t}\n\n\t\t\ttargetURL, err := url.Parse(targetValue)\n\t\t\tif err != nil {\n\t\t\t\tp.Log.Warnf(\"Failed to parse target %q\", targetValue)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tservice := urlAndAddress{\n\t\t\t\turl:         targetURL,\n\t\t\t\toriginalURL: targetURL,\n\t\t\t\t// in this case target labels should just be added to the tags\n\t\t\t\ttags: sdOutputItem.Labels,\n\t\t\t}\n\t\t\tservices[service.url.String()] = service\n\t\t}\n\t}\n\n\tp.lock.Lock()\n\tp.httpServices = services\n\tp.lock.Unlock()\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/http_service_discovery_test.go",
    "content": "package prometheus\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n)\n\nfunc TestHttpSD(t *testing.T) {\n\ttestcasePath := filepath.Join(\"testcases\", \"service_discovery\")\n\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\texpectedResult := filepath.Join(testcasePath, \"http-services.json\")\n\n\t// read expected result\n\tresult, err := os.ReadFile(expectedResult)\n\trequire.NoError(t, err)\n\n\t// Create a fake API server\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Verify it's a GET request\n\t\tif r.Method != http.MethodGet {\n\t\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif _, err := w.Write(result); err != nil {\n\t\t\tt.Errorf(\"Failed to write response: %v\", err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\t// Load the configuration\n\tcfg := config.NewConfig()\n\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\trequire.Len(t, cfg.Inputs, 1)\n\n\t// Setup and start the plugin\n\tplugin := cfg.Inputs[0].Input.(*Prometheus)\n\tplugin.HTTPSDConfig.URL = server.URL\n\trequire.NoError(t, plugin.Init())\n\n\t// refresh http services\n\tclient := &http.Client{}\n\tdefer client.CloseIdleConnections()\n\trequire.NoError(t, plugin.refreshHTTPServices(server.URL, client))\n\n\tplugin.lock.Lock()\n\tdefer plugin.lock.Unlock()\n\t// check we have 8 http services\n\trequire.Len(t, plugin.httpServices, 8)\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/kubernetes.go",
    "content": "package prometheus\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n\t\"k8s.io/apimachinery/pkg/util/wait\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/cache\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/models\"\n)\n\ntype podMetadata struct {\n\tResourceVersion string `json:\"resourceVersion\"`\n\tSelfLink        string `json:\"selfLink\"`\n}\n\ntype podResponse struct {\n\tKind       string        `json:\"kind\"`\n\tAPIVersion string        `json:\"apiVersion\"`\n\tMetadata   podMetadata   `json:\"metadata\"`\n\tItems      []*corev1.Pod `json:\"items,omitempty\"`\n}\n\nconst cAdvisorPodListDefaultInterval = 60\n\n// loadConfig parses a kubeconfig from a file and returns a Kubernetes rest.Config\nfunc loadConfig(kubeconfigPath string) (*rest.Config, error) {\n\tif kubeconfigPath == \"\" {\n\t\treturn rest.InClusterConfig()\n\t}\n\n\treturn clientcmd.BuildConfigFromFlags(\"\", kubeconfigPath)\n}\n\nfunc (p *Prometheus) startK8s(ctx context.Context) error {\n\tconfig, err := loadConfig(p.KubeConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get rest.Config from %q: %w\", p.KubeConfig, err)\n\t}\n\n\tclient, err := kubernetes.NewForConfig(config)\n\tif err != nil {\n\t\tu, err := user.Current()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get current user: %w\", err)\n\t\t}\n\n\t\tkubeconfig := filepath.Join(u.HomeDir, \".kube\", \"config\")\n\n\t\tconfig, err = loadConfig(kubeconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get rest.Config from %q: %w\", kubeconfig, err)\n\t\t}\n\n\t\tclient, err = kubernetes.NewForConfig(config)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get kubernetes client: %w\", err)\n\t\t}\n\t}\n\n\tif !p.isNodeScrapeScope {\n\t\terr = p.watchPod(ctx, client)\n\t\tif err != nil {\n\t\t\tp.Log.Warnf(\"Error while attempting to watch pod: %s\", err.Error())\n\t\t}\n\t}\n\n\tp.wg.Add(1)\n\tgo func() {\n\t\tdefer p.wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-time.After(time.Second):\n\t\t\t\tif p.isNodeScrapeScope {\n\t\t\t\t\tbearerToken := config.BearerToken\n\t\t\t\t\tif config.BearerTokenFile != \"\" {\n\t\t\t\t\t\tbearerTokenBytes, err := os.ReadFile(config.BearerTokenFile)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tp.Log.Errorf(\"Error reading bearer token file hence falling back to BearerToken: %s\", err.Error())\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbearerToken = string(bearerTokenBytes)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\terr = p.cAdvisor(ctx, bearerToken)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tp.Log.Errorf(\"Unable to monitor pods with node scrape scope: %s\", err.Error())\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t<-ctx.Done()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc shouldScrapePod(pod *corev1.Pod, p *Prometheus) bool {\n\tisCandidate := podReady(pod) &&\n\t\tpodHasMatchingNamespace(pod, p) &&\n\t\tpodHasMatchingLabelSelector(pod, p.podLabelSelector) &&\n\t\tpodHasMatchingFieldSelector(pod, p.podFieldSelector)\n\n\tvar shouldScrape bool\n\tswitch p.MonitorKubernetesPodsMethod {\n\tcase monitorMethodAnnotations: // must have 'true' annotation to be scraped\n\t\tshouldScrape = pod.Annotations != nil && pod.Annotations[\"prometheus.io/scrape\"] == \"true\"\n\tcase monitorMethodSettings: // will be scraped regardless of annotation\n\t\tshouldScrape = true\n\tcase monitorMethodSettingsAndAnnotations: // will be scraped unless opts out with 'false' annotation\n\t\tshouldScrape = pod.Annotations == nil || pod.Annotations[\"prometheus.io/scrape\"] != \"false\"\n\t}\n\n\treturn isCandidate && shouldScrape\n}\n\n// Share informer per namespace across all instances of this plugin.\n// Access must be protected by informerfactoryMu since multiple plugin\n// instances may Start/Stop concurrently.\nvar (\n\tinformerfactory     map[string]informers.SharedInformerFactory\n\tinformerfactoryRefs map[string]int\n\tinformerfactoryMu   sync.Mutex\n)\n\n// An edge case exists if a pod goes offline at the same time a new pod is created\n// (without the scrape annotations). K8s may re-assign the old pod ip to the non-scrape\n// pod, causing errors in the logs. This is only true if the pod going offline is not\n// directed to do so by K8s.\nfunc (p *Prometheus) watchPod(ctx context.Context, clientset *kubernetes.Clientset) error {\n\tvar resyncinterval time.Duration\n\n\tif p.CacheRefreshInterval != 0 {\n\t\tresyncinterval = time.Duration(p.CacheRefreshInterval) * time.Minute\n\t} else {\n\t\tresyncinterval = 60 * time.Minute\n\t}\n\n\tinformerfactoryMu.Lock()\n\tif informerfactory == nil {\n\t\tinformerfactory = make(map[string]informers.SharedInformerFactory)\n\t\tinformerfactoryRefs = make(map[string]int)\n\t}\n\n\tvar f informers.SharedInformerFactory\n\tvar ok bool\n\tif f, ok = informerfactory[p.PodNamespace]; !ok {\n\t\tvar informerOptions []informers.SharedInformerOption\n\t\tif p.PodNamespace != \"\" {\n\t\t\tinformerOptions = append(informerOptions, informers.WithNamespace(p.PodNamespace))\n\t\t}\n\t\tf = informers.NewSharedInformerFactoryWithOptions(clientset, resyncinterval, informerOptions...)\n\t\tinformerfactory[p.PodNamespace] = f\n\t}\n\tinformerfactoryRefs[p.PodNamespace]++\n\tinformerfactoryMu.Unlock()\n\n\tif p.nsAnnotationPass != nil || p.nsAnnotationDrop != nil {\n\t\tp.nsStore = f.Core().V1().Namespaces().Informer().GetStore()\n\t}\n\n\tpodinformer := f.Core().V1().Pods()\n\t_, err := podinformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc: func(newObj interface{}) {\n\t\t\tnewPod, ok := newObj.(*corev1.Pod)\n\t\t\tif !ok {\n\t\t\t\tp.Log.Errorf(\"[BUG] received unexpected object: %v\", newObj)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif shouldScrapePod(newPod, p) {\n\t\t\t\tregisterPod(newPod, p)\n\t\t\t}\n\t\t},\n\t\t// On Pod status updates and regular reList by Informer\n\t\tUpdateFunc: func(_, newObj interface{}) {\n\t\t\tnewPod, ok := newObj.(*corev1.Pod)\n\t\t\tif !ok {\n\t\t\t\tp.Log.Errorf(\"[BUG] received unexpected object: %v\", newObj)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tkey, err := cache.DeletionHandlingMetaNamespaceKeyFunc(newObj)\n\t\t\tif err != nil {\n\t\t\t\tp.Log.Errorf(\"getting key from cache %s\", err.Error())\n\t\t\t}\n\t\t\tpodID := podID(key)\n\t\t\tif shouldScrapePod(newPod, p) {\n\t\t\t\t// When Informers re-Lists, pod might already be registered,\n\t\t\t\t// do nothing if it is, register otherwise\n\t\t\t\tif _, ok = p.kubernetesPods[podID]; !ok {\n\t\t\t\t\tregisterPod(newPod, p)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Pods are largely immutable, but it's readiness status can change, unregister then\n\t\t\t\tunregisterPod(podID, p)\n\t\t\t}\n\t\t},\n\t\tDeleteFunc: func(oldObj interface{}) {\n\t\t\tkey, err := cache.DeletionHandlingMetaNamespaceKeyFunc(oldObj)\n\t\t\tif err == nil {\n\t\t\t\tunregisterPod(podID(key), p)\n\t\t\t}\n\t\t},\n\t})\n\n\tf.Start(ctx.Done())\n\tf.WaitForCacheSync(wait.NeverStop)\n\treturn err\n}\n\nfunc (p *Prometheus) cAdvisor(ctx context.Context, bearerToken string) error {\n\t// The request will be the same each time\n\tpodsURL := fmt.Sprintf(\"https://%s:10250/pods\", p.NodeIP)\n\treq, err := http.NewRequest(\"GET\", podsURL, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error when creating request to %s to get pod list: %w\", podsURL, err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+bearerToken)\n\treq.Header.Add(\"Accept\", \"application/json\")\n\n\t// Update right away so code is not waiting the length of the specified scrape interval initially\n\terr = updateCadvisorPodList(p, req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initially updating pod list: %w\", err)\n\t}\n\n\tscrapeInterval := cAdvisorPodListDefaultInterval\n\tif p.PodScrapeInterval != 0 {\n\t\tscrapeInterval = p.PodScrapeInterval\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-time.After(time.Duration(scrapeInterval) * time.Second):\n\t\t\terr := updateCadvisorPodList(p, req)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating pod list: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc updateCadvisorPodList(p *Prometheus, req *http.Request) error {\n\thttp.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}\n\thttpClient := http.Client{}\n\n\tresp, err := httpClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error when making request for pod list: %w\", err)\n\t}\n\n\t// If err is nil, still check response code\n\tif resp.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"error when making request for pod list with status %s\", resp.Status)\n\t}\n\n\tdefer resp.Body.Close()\n\n\tcadvisorPodsResponse := podResponse{}\n\n\t// Will have expected type errors for some parts of corev1.Pod struct for some unused fields\n\t// Instead have nil checks for every used field in case of incorrect decoding\n\tif err := json.NewDecoder(resp.Body).Decode(&cadvisorPodsResponse); err != nil {\n\t\treturn fmt.Errorf(\"decoding response failed: %w\", err)\n\t}\n\tpods := cadvisorPodsResponse.Items\n\n\t// Updating pod list to be latest cadvisor response\n\tp.lock.Lock()\n\tp.kubernetesPods = make(map[podID]urlAndAddress)\n\n\t// Register pod only if it has an annotation to scrape, if it is ready,\n\t// and if namespace and selectors are specified and match\n\tfor _, pod := range pods {\n\t\tif necessaryPodFieldsArePresent(pod) && shouldScrapePod(pod, p) {\n\t\t\tregisterPod(pod, p)\n\t\t}\n\t}\n\tp.lock.Unlock()\n\n\t// No errors\n\treturn nil\n}\n\nfunc necessaryPodFieldsArePresent(pod *corev1.Pod) bool {\n\treturn pod.Annotations != nil &&\n\t\tpod.Labels != nil &&\n\t\tpod.Status.ContainerStatuses != nil\n}\n\n/* See the docs on kubernetes label selectors:\n * https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors\n */\nfunc podHasMatchingLabelSelector(pod *corev1.Pod, labelSelector labels.Selector) bool {\n\tif labelSelector == nil {\n\t\treturn true\n\t}\n\n\tvar labelsSet labels.Set = pod.Labels\n\treturn labelSelector.Matches(labelsSet)\n}\n\n/* See ToSelectableFields() for list of fields that are selectable:\n * https://github.com/kubernetes/kubernetes/release-1.20/pkg/registry/core/pod/strategy.go\n * See docs on kubernetes field selectors:\n * https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/\n */\nfunc podHasMatchingFieldSelector(pod *corev1.Pod, fieldSelector fields.Selector) bool {\n\tif fieldSelector == nil {\n\t\treturn true\n\t}\n\n\tfieldsSet := make(fields.Set)\n\tfieldsSet[\"spec.nodeName\"] = pod.Spec.NodeName\n\tfieldsSet[\"spec.restartPolicy\"] = string(pod.Spec.RestartPolicy)\n\tfieldsSet[\"spec.schedulerName\"] = pod.Spec.SchedulerName\n\tfieldsSet[\"spec.serviceAccountName\"] = pod.Spec.ServiceAccountName\n\tfieldsSet[\"status.phase\"] = string(pod.Status.Phase)\n\tfieldsSet[\"status.podIP\"] = pod.Status.PodIP\n\tfieldsSet[\"status.nominatedNodeName\"] = pod.Status.NominatedNodeName\n\n\treturn fieldSelector.Matches(fieldsSet)\n}\n\n// Get corev1.Namespace object by name\nfunc getNamespaceObject(name string, p *Prometheus) *corev1.Namespace {\n\tnsObj, exists, err := p.nsStore.GetByKey(name)\n\tif err != nil {\n\t\tp.Log.Errorf(\"Err fetching namespace '%s': %v\", name, err)\n\t\treturn nil\n\t} else if !exists {\n\t\treturn nil // can't happen\n\t}\n\tns, ok := nsObj.(*corev1.Namespace)\n\tif !ok {\n\t\tp.Log.Errorf(\"[BUG] received unexpected object: %v\", nsObj)\n\t\treturn nil\n\t}\n\treturn ns\n}\n\nfunc namespaceAnnotationMatch(nsName string, p *Prometheus) bool {\n\t// In case of no filtering or any issues with acquiring namespace information\n\t// just let it pass trough...\n\tif (p.nsAnnotationPass == nil && p.nsAnnotationDrop == nil) || p.nsStore == nil {\n\t\treturn true\n\t}\n\tns := getNamespaceObject(nsName, p)\n\tif ns == nil {\n\t\treturn true\n\t}\n\n\ttags := make([]*telegraf.Tag, 0, len(ns.Annotations))\n\tfor k, v := range ns.Annotations {\n\t\ttags = append(tags, &telegraf.Tag{Key: k, Value: v})\n\t}\n\treturn models.ShouldTagsPass(p.nsAnnotationPass, p.nsAnnotationDrop, tags)\n}\n\n/*\n * If a namespace is specified and the pod doesn't have that namespace, return false\n * Else return true\n */\nfunc podHasMatchingNamespace(pod *corev1.Pod, p *Prometheus) bool {\n\treturn p.PodNamespace == \"\" || pod.Namespace == p.PodNamespace\n}\n\nfunc podReady(pod *corev1.Pod) bool {\n\tfor _, cond := range pod.Status.Conditions {\n\t\tif cond.Type == corev1.PodReady {\n\t\t\treturn pod.Status.Phase == corev1.PodRunning\n\t\t}\n\t}\n\treturn false\n}\n\nfunc registerPod(pod *corev1.Pod, p *Prometheus) {\n\ttargetURL, err := getScrapeURL(pod, p)\n\tif err != nil {\n\t\tp.Log.Errorf(\"could not parse URL: %s\", err)\n\t\treturn\n\t} else if targetURL == nil {\n\t\treturn\n\t}\n\n\tp.Log.Debugf(\"will scrape metrics from %q\", targetURL.String())\n\ttags := make(map[string]string, len(pod.Annotations)+len(pod.Labels)+2)\n\n\t// add annotation as metrics tags, subject to include/exclude filters\n\tfor k, v := range pod.Annotations {\n\t\tif models.ShouldPassFilters(p.podAnnotationIncludeFilter, p.podAnnotationExcludeFilter, k) {\n\t\t\ttags[k] = v\n\t\t}\n\t}\n\n\ttags[\"pod_name\"] = pod.Name\n\tpodNamespace := \"namespace\"\n\tif p.PodNamespaceLabelName != \"\" {\n\t\tpodNamespace = p.PodNamespaceLabelName\n\t}\n\ttags[podNamespace] = pod.Namespace\n\n\t// add labels as metrics tags, subject to include/exclude filters\n\tfor k, v := range pod.Labels {\n\t\tif models.ShouldPassFilters(p.podLabelIncludeFilter, p.podLabelExcludeFilter, k) {\n\t\t\ttags[k] = v\n\t\t}\n\t}\n\tpodURL := addressToURL(targetURL, targetURL.Hostname())\n\n\t// Locks earlier if using cAdvisor calls - makes a new list each time\n\t// rather than updating and removing from the same list\n\tif !p.isNodeScrapeScope {\n\t\tp.lock.Lock()\n\t\tdefer p.lock.Unlock()\n\t}\n\tp.kubernetesPods[podID(pod.GetNamespace()+\"/\"+pod.GetName())] = urlAndAddress{\n\t\turl:         podURL,\n\t\taddress:     targetURL.Hostname(),\n\t\toriginalURL: targetURL,\n\t\ttags:        tags,\n\t\tnamespace:   pod.GetNamespace(),\n\t}\n}\n\nfunc getScrapeURL(pod *corev1.Pod, p *Prometheus) (*url.URL, error) {\n\tip := pod.Status.PodIP\n\tif ip == \"\" {\n\t\t// return as if scrape was disabled, we will be notified again once the pod\n\t\t// has an IP\n\t\treturn nil, nil\n\t}\n\n\tvar scheme, pathAndQuery, port string\n\n\tif p.MonitorKubernetesPodsMethod == monitorMethodSettings ||\n\t\tp.MonitorKubernetesPodsMethod == monitorMethodSettingsAndAnnotations {\n\t\tscheme = p.MonitorKubernetesPodsScheme\n\t\tpathAndQuery = p.MonitorKubernetesPodsPath\n\t\tport = strconv.Itoa(p.MonitorKubernetesPodsPort)\n\t}\n\n\tif p.MonitorKubernetesPodsMethod == monitorMethodAnnotations ||\n\t\tp.MonitorKubernetesPodsMethod == monitorMethodSettingsAndAnnotations {\n\t\tif ann := pod.Annotations[\"prometheus.io/scheme\"]; ann != \"\" {\n\t\t\tscheme = ann\n\t\t}\n\t\tif ann := pod.Annotations[\"prometheus.io/path\"]; ann != \"\" {\n\t\t\tpathAndQuery = ann\n\t\t}\n\t\tif ann := pod.Annotations[\"prometheus.io/port\"]; ann != \"\" {\n\t\t\tport = ann\n\t\t}\n\t}\n\n\tif scheme == \"\" {\n\t\tscheme = \"http\"\n\t}\n\n\tif port == \"\" || port == \"0\" {\n\t\tport = \"9102\"\n\t}\n\n\tif pathAndQuery == \"\" {\n\t\tpathAndQuery = \"/metrics\"\n\t}\n\n\tbase, err := url.Parse(pathAndQuery)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbase.Scheme = scheme\n\tbase.Host = net.JoinHostPort(ip, port)\n\n\treturn base, nil\n}\n\nfunc unregisterPod(podID podID, p *Prometheus) {\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\tif v, ok := p.kubernetesPods[podID]; ok {\n\t\tp.Log.Debugf(\"registered a delete request for %s\", podID)\n\t\tdelete(p.kubernetesPods, podID)\n\t\tp.Log.Debugf(\"will stop scraping for %q\", v.url.String())\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/kubernetes_test.go",
    "content": "package prometheus\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/tools/cache\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc initPrometheus() *Prometheus {\n\tprom := &Prometheus{Log: testutil.Logger{}}\n\tprom.MonitorKubernetesPodsScheme = \"http\"\n\tprom.MonitorKubernetesPodsPort = 9102\n\tprom.MonitorKubernetesPodsPath = \"/metrics\"\n\tprom.MonitorKubernetesPodsMethod = monitorMethodAnnotations\n\tprom.kubernetesPods = map[podID]urlAndAddress{}\n\treturn prom\n}\n\nfunc TestScrapeURLNoAnnotations(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}}\n\tp := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}}\n\tp.Annotations = map[string]string{}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Nil(t, url)\n}\n\nfunc TestScrapeURLNoAnnotationsScrapeConfig(t *testing.T) {\n\tprom := initPrometheus()\n\tprom.MonitorKubernetesPodsMethod = monitorMethodSettingsAndAnnotations\n\n\tp := pod()\n\tp.Annotations = map[string]string{}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/metrics\", url.String())\n}\n\nfunc TestScrapeURLScrapeConfigCustom(t *testing.T) {\n\tprom := initPrometheus()\n\tprom.MonitorKubernetesPodsMethod = monitorMethodSettingsAndAnnotations\n\n\tprom.MonitorKubernetesPodsScheme = \"https\"\n\tprom.MonitorKubernetesPodsPort = 9999\n\tprom.MonitorKubernetesPodsPath = \"/svc/metrics\"\n\tp := pod()\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"https://127.0.0.1:9999/svc/metrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotations(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}}\n\tp := pod()\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/metrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsScrapeConfig(t *testing.T) {\n\tprom := initPrometheus()\n\tprom.MonitorKubernetesPodsMethod = monitorMethodSettingsAndAnnotations\n\tp := pod()\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/metrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPort(t *testing.T) {\n\tprom := initPrometheus()\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/port\": \"9000\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9000/metrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPortScrapeConfig(t *testing.T) {\n\tprom := initPrometheus()\n\tprom.MonitorKubernetesPodsMethod = monitorMethodSettingsAndAnnotations\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/port\": \"9000\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9000/metrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPath(t *testing.T) {\n\tprom := initPrometheus()\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/path\": \"mymetrics\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/mymetrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPathWithSep(t *testing.T) {\n\tprom := initPrometheus()\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/path\": \"/mymetrics\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/mymetrics\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPathWithQueryParameters(t *testing.T) {\n\tprom := initPrometheus()\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/path\": \"/v1/agent/metrics?format=prometheus\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/v1/agent/metrics?format=prometheus\", url.String())\n}\n\nfunc TestScrapeURLAnnotationsCustomPathWithFragment(t *testing.T) {\n\tprom := initPrometheus()\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/path\": \"/v1/agent/metrics#prometheus\"}\n\turl, err := getScrapeURL(p, prom)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"http://127.0.0.1:9102/v1/agent/metrics#prometheus\", url.String())\n}\n\nfunc TestAddPod(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\trequire.Len(t, prom.kubernetesPods, 1)\n}\n\nfunc TestAddPodScrapeConfig(t *testing.T) {\n\tprom := initPrometheus()\n\tprom.MonitorKubernetesPodsMethod = monitorMethodSettingsAndAnnotations\n\n\tp := pod()\n\tp.Annotations = map[string]string{}\n\tregisterPod(p, prom)\n\trequire.Len(t, prom.kubernetesPods, 1)\n}\n\nfunc TestAddMultipleDuplicatePods(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\tp.Name = \"Pod2\"\n\tregisterPod(p, prom)\n\n\turls, err := prom.getAllURLs()\n\trequire.NoError(t, err)\n\trequire.Len(t, urls, 1)\n}\n\nfunc TestAddMultiplePods(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\tp.Name = \"Pod2\"\n\tp.Status.PodIP = \"127.0.0.2\"\n\tregisterPod(p, prom)\n\trequire.Len(t, prom.kubernetesPods, 2)\n}\n\nfunc TestDeletePods(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\n\tid, err := cache.MetaNamespaceKeyFunc(p)\n\trequire.NoError(t, err)\n\tunregisterPod(podID(id), prom)\n\trequire.Empty(t, prom.kubernetesPods)\n}\n\nfunc TestKeepDefaultNamespaceLabelName(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\n\tid, err := cache.MetaNamespaceKeyFunc(p)\n\trequire.NoError(t, err)\n\ttags := prom.kubernetesPods[podID(id)].tags\n\trequire.Equal(t, \"default\", tags[\"namespace\"])\n}\n\nfunc TestChangeNamespaceLabelName(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, PodNamespaceLabelName: \"pod_namespace\", kubernetesPods: map[podID]urlAndAddress{}}\n\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tregisterPod(p, prom)\n\n\tid, err := cache.MetaNamespaceKeyFunc(p)\n\trequire.NoError(t, err)\n\ttags := prom.kubernetesPods[podID(id)].tags\n\trequire.Equal(t, \"default\", tags[\"pod_namespace\"])\n\trequire.Empty(t, tags[\"namespace\"])\n}\n\nfunc TestPodHasMatchingNamespace(t *testing.T) {\n\tprom := &Prometheus{Log: testutil.Logger{}, PodNamespace: \"default\"}\n\n\tpod := pod()\n\tpod.Name = \"Pod1\"\n\tpod.Namespace = \"default\"\n\tshouldMatch := podHasMatchingNamespace(pod, prom)\n\trequire.True(t, shouldMatch)\n\n\tpod.Name = \"Pod2\"\n\tpod.Namespace = \"namespace\"\n\tshouldNotMatch := podHasMatchingNamespace(pod, prom)\n\trequire.False(t, shouldNotMatch)\n}\n\nfunc TestPodHasMatchingLabelSelector(t *testing.T) {\n\tlabelSelectorString := \"label0==label0,label1=label1,label2!=label,label3 in (label1,label2, label3),label4 notin (label1, label2,label3),label5,!label6\"\n\tprom := &Prometheus{Log: testutil.Logger{}, KubernetesLabelSelector: labelSelectorString}\n\n\tpod := pod()\n\tpod.Labels = make(map[string]string)\n\tpod.Labels[\"label0\"] = \"label0\"\n\tpod.Labels[\"label1\"] = \"label1\"\n\tpod.Labels[\"label2\"] = \"label2\"\n\tpod.Labels[\"label3\"] = \"label3\"\n\tpod.Labels[\"label4\"] = \"label4\"\n\tpod.Labels[\"label5\"] = \"label5\"\n\n\tlabelSelector, err := labels.Parse(prom.KubernetesLabelSelector)\n\trequire.NoError(t, err)\n\trequire.True(t, podHasMatchingLabelSelector(pod, labelSelector))\n}\n\nfunc TestPodHasMatchingFieldSelector(t *testing.T) {\n\tfieldSelectorString := \"status.podIP=127.0.0.1,spec.restartPolicy=Always,spec.NodeName!=nodeName\"\n\tprom := &Prometheus{Log: testutil.Logger{}, KubernetesFieldSelector: fieldSelectorString}\n\tpod := pod()\n\tpod.Spec.RestartPolicy = \"Always\"\n\tpod.Spec.NodeName = \"node1000\"\n\n\tfieldSelector, err := fields.ParseSelector(prom.KubernetesFieldSelector)\n\trequire.NoError(t, err)\n\trequire.True(t, podHasMatchingFieldSelector(pod, fieldSelector))\n}\n\nfunc TestInvalidFieldSelector(t *testing.T) {\n\tfieldSelectorString := \"status.podIP=127.0.0.1,spec.restartPolicy=Always,spec.NodeName!=nodeName,spec.nodeName\"\n\tprom := &Prometheus{Log: testutil.Logger{}, KubernetesFieldSelector: fieldSelectorString}\n\tpod := pod()\n\tpod.Spec.RestartPolicy = \"Always\"\n\tpod.Spec.NodeName = \"node1000\"\n\n\t_, err := fields.ParseSelector(prom.KubernetesFieldSelector)\n\trequire.Error(t, err)\n}\n\nfunc TestAnnotationFilters(t *testing.T) {\n\tp := pod()\n\tp.Annotations = map[string]string{\n\t\t\"prometheus.io/scrape\": \"true\",\n\t\t\"includeme\":            \"true\",\n\t\t\"excludeme\":            \"true\",\n\t\t\"neutral\":              \"true\",\n\t}\n\n\tcases := []struct {\n\t\tdesc         string\n\t\tinclude      []string\n\t\texclude      []string\n\t\texpectedTags []string\n\t}{\n\t\t{\"Just include\",\n\t\t\t[]string{\"includeme\"},\n\t\t\tnil,\n\t\t\t[]string{\"includeme\"}},\n\t\t{\"Just exclude\",\n\t\t\tnil,\n\t\t\t[]string{\"excludeme\"},\n\t\t\t[]string{\"includeme\", \"neutral\"}},\n\t\t{\"Include & exclude\",\n\t\t\t[]string{\"includeme\"},\n\t\t\t[]string{\"exludeme\"},\n\t\t\t[]string{\"includeme\"}},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.desc, func(t *testing.T) {\n\t\t\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\t\t\tprom.PodAnnotationInclude = tc.include\n\t\t\tprom.PodAnnotationExclude = tc.exclude\n\t\t\trequire.NoError(t, prom.initFilters())\n\t\t\tregisterPod(p, prom)\n\t\t\tfor _, pd := range prom.kubernetesPods {\n\t\t\t\tfor _, tagKey := range tc.expectedTags {\n\t\t\t\t\trequire.Contains(t, pd.tags, tagKey)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestLabelFilters(t *testing.T) {\n\tp := pod()\n\tp.Annotations = map[string]string{\"prometheus.io/scrape\": \"true\"}\n\tp.Labels = map[string]string{\n\t\t\"includeme\": \"true\",\n\t\t\"excludeme\": \"true\",\n\t\t\"neutral\":   \"true\",\n\t}\n\n\tcases := []struct {\n\t\tdesc         string\n\t\tinclude      []string\n\t\texclude      []string\n\t\texpectedTags []string\n\t}{\n\t\t{\"Just include\",\n\t\t\t[]string{\"includeme\"},\n\t\t\tnil,\n\t\t\t[]string{\"includeme\"}},\n\t\t{\"Just exclude\",\n\t\t\tnil,\n\t\t\t[]string{\"excludeme\"},\n\t\t\t[]string{\"includeme\", \"neutral\"}},\n\t\t{\"Include & exclude\",\n\t\t\t[]string{\"includeme\"},\n\t\t\t[]string{\"exludeme\"},\n\t\t\t[]string{\"includeme\"}},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.desc, func(t *testing.T) {\n\t\t\tprom := &Prometheus{Log: testutil.Logger{}, kubernetesPods: map[podID]urlAndAddress{}}\n\t\t\tprom.PodLabelInclude = tc.include\n\t\t\tprom.PodLabelExclude = tc.exclude\n\t\t\trequire.NoError(t, prom.initFilters())\n\t\t\tregisterPod(p, prom)\n\t\t\tfor _, pd := range prom.kubernetesPods {\n\t\t\t\tfor _, tagKey := range tc.expectedTags {\n\t\t\t\t\trequire.Contains(t, pd.tags, tagKey)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInformerFactoryRefCounting(t *testing.T) {\n\tresetInformerFactoryState(t)\n\n\tvar shutdownCalled atomic.Int32\n\tmock := &mockSharedInformerFactory{\n\t\tonShutdown: func() { shutdownCalled.Add(1) },\n\t}\n\n\t// Simulate two instances registered for the same namespace\n\tinformerfactoryMu.Lock()\n\tinformerfactory = map[string]informers.SharedInformerFactory{\"default\": mock}\n\tinformerfactoryRefs = map[string]int{\"default\": 2}\n\tinformerfactoryMu.Unlock()\n\n\t// First Stop — should decrement ref count but not shutdown\n\t_, cancel1 := context.WithCancel(context.Background())\n\tp1 := &Prometheus{\n\t\tMonitorPods:  true,\n\t\tPodNamespace: \"default\",\n\t\tcancel:       cancel1,\n\t}\n\tp1.Stop()\n\n\t// Read under lock, assert outside to avoid deadlock if assertion fails\n\tinformerfactoryMu.Lock()\n\trefCount := informerfactoryRefs[\"default\"]\n\t_, exists := informerfactory[\"default\"]\n\tinformerfactoryMu.Unlock()\n\trequire.Equal(t, 1, refCount)\n\trequire.True(t, exists)\n\trequire.Equal(t, int32(0), shutdownCalled.Load())\n\n\t// Second Stop — should shutdown and remove\n\t_, cancel2 := context.WithCancel(context.Background())\n\tp2 := &Prometheus{\n\t\tMonitorPods:  true,\n\t\tPodNamespace: \"default\",\n\t\tcancel:       cancel2,\n\t}\n\tp2.Stop()\n\n\tinformerfactoryMu.Lock()\n\t_, refsExist := informerfactoryRefs[\"default\"]\n\t_, factoryExist := informerfactory[\"default\"]\n\tinformerfactoryMu.Unlock()\n\trequire.False(t, refsExist)\n\trequire.False(t, factoryExist)\n\trequire.Equal(t, int32(1), shutdownCalled.Load())\n}\n\nfunc TestInformerFactoryMultipleNamespaces(t *testing.T) {\n\tresetInformerFactoryState(t)\n\n\tvar shutdownA, shutdownB atomic.Int32\n\tmockA := &mockSharedInformerFactory{\n\t\tonShutdown: func() { shutdownA.Add(1) },\n\t}\n\tmockB := &mockSharedInformerFactory{\n\t\tonShutdown: func() { shutdownB.Add(1) },\n\t}\n\n\tinformerfactoryMu.Lock()\n\tinformerfactory = map[string]informers.SharedInformerFactory{\n\t\t\"ns-a\": mockA,\n\t\t\"ns-b\": mockB,\n\t}\n\tinformerfactoryRefs = map[string]int{\n\t\t\"ns-a\": 1,\n\t\t\"ns-b\": 1,\n\t}\n\tinformerfactoryMu.Unlock()\n\n\t// Stop instance in ns-a — should shutdown ns-a only\n\t_, cancelA := context.WithCancel(context.Background())\n\tpa := &Prometheus{\n\t\tMonitorPods:  true,\n\t\tPodNamespace: \"ns-a\",\n\t\tcancel:       cancelA,\n\t}\n\tpa.Stop()\n\n\tinformerfactoryMu.Lock()\n\t_, nsAExists := informerfactory[\"ns-a\"]\n\t_, nsBExists := informerfactory[\"ns-b\"]\n\tinformerfactoryMu.Unlock()\n\trequire.False(t, nsAExists)\n\trequire.True(t, nsBExists)\n\trequire.Equal(t, int32(1), shutdownA.Load())\n\trequire.Equal(t, int32(0), shutdownB.Load())\n\n\t// Stop instance in ns-b — should shutdown ns-b\n\t_, cancelB := context.WithCancel(context.Background())\n\tpb := &Prometheus{\n\t\tMonitorPods:  true,\n\t\tPodNamespace: \"ns-b\",\n\t\tcancel:       cancelB,\n\t}\n\tpb.Stop()\n\n\tinformerfactoryMu.Lock()\n\t_, nsBStillExists := informerfactory[\"ns-b\"]\n\tinformerfactoryMu.Unlock()\n\trequire.False(t, nsBStillExists)\n\trequire.Equal(t, int32(1), shutdownB.Load())\n}\n\nfunc TestInformerFactoryConcurrentStop(t *testing.T) {\n\tresetInformerFactoryState(t)\n\n\tvar shutdownCount atomic.Int32\n\tmock := &mockSharedInformerFactory{\n\t\tonShutdown: func() { shutdownCount.Add(1) },\n\t}\n\n\tconst numInstances = 10\n\tinformerfactoryMu.Lock()\n\tinformerfactory = map[string]informers.SharedInformerFactory{\"default\": mock}\n\tinformerfactoryRefs = map[string]int{\"default\": numInstances}\n\tinformerfactoryMu.Unlock()\n\n\t// Stop all instances concurrently — race detector verifies thread safety\n\tvar wg sync.WaitGroup\n\tfor range numInstances {\n\t\twg.Go(func() {\n\t\t\t_, cancel := context.WithCancel(context.Background())\n\t\t\tp := &Prometheus{\n\t\t\t\tMonitorPods:  true,\n\t\t\t\tPodNamespace: \"default\",\n\t\t\t\tcancel:       cancel,\n\t\t\t}\n\t\t\tp.Stop()\n\t\t})\n\t}\n\twg.Wait()\n\n\tinformerfactoryMu.Lock()\n\t_, refsExist := informerfactoryRefs[\"default\"]\n\t_, factoryExist := informerfactory[\"default\"]\n\tinformerfactoryMu.Unlock()\n\trequire.False(t, refsExist)\n\trequire.False(t, factoryExist)\n\trequire.Equal(t, int32(1), shutdownCount.Load())\n}\n\nfunc pod() *corev1.Pod {\n\tp := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}, Status: corev1.PodStatus{}, Spec: corev1.PodSpec{}}\n\tp.Status.PodIP = \"127.0.0.1\"\n\tp.Name = \"myPod\"\n\tp.Namespace = \"default\"\n\treturn p\n}\n\ntype mockSharedInformerFactory struct {\n\tinformers.SharedInformerFactory\n\tonShutdown func()\n}\n\nfunc (m *mockSharedInformerFactory) Shutdown() {\n\tif m.onShutdown != nil {\n\t\tm.onShutdown()\n\t}\n}\n\nfunc resetInformerFactoryState(t *testing.T) {\n\tt.Helper()\n\tinformerfactoryMu.Lock()\n\tinformerfactory = nil\n\tinformerfactoryRefs = nil\n\tinformerfactoryMu.Unlock()\n\tt.Cleanup(func() {\n\t\tinformerfactoryMu.Lock()\n\t\tinformerfactory = nil\n\t\tinformerfactoryRefs = nil\n\t\tinformerfactoryMu.Unlock()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/prometheus.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage prometheus\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/prometheus/common/expfmt\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/tools/cache\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/openmetrics\"\n\tparsers_prometheus \"github.com/influxdata/telegraf/plugins/parsers/prometheus\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tacceptHeader = `application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.7,text/plain;version=0.0.4;q=0.3`\n\n\tmonitorMethodNone                   monitorMethod = \"\"\n\tmonitorMethodAnnotations            monitorMethod = \"annotations\"\n\tmonitorMethodSettings               monitorMethod = \"settings\"\n\tmonitorMethodSettingsAndAnnotations monitorMethod = \"settings+annotations\"\n)\n\ntype Prometheus struct {\n\tURLs                 []string          `toml:\"urls\"`\n\tBearerToken          string            `toml:\"bearer_token\"`\n\tBearerTokenString    config.Secret     `toml:\"bearer_token_string\"`\n\tUsername             config.Secret     `toml:\"username\"`\n\tPassword             config.Secret     `toml:\"password\"`\n\tHTTPHeaders          map[string]string `toml:\"http_headers\"`\n\tContentLengthLimit   config.Size       `toml:\"content_length_limit\"`\n\tContentTypeOverride  string            `toml:\"content_type_override\"`\n\tEnableRequestMetrics bool              `toml:\"enable_request_metrics\"`\n\tMetricVersion        int               `toml:\"metric_version\"`\n\tURLTag               string            `toml:\"url_tag\"`\n\tIgnoreTimestamp      bool              `toml:\"ignore_timestamp\"`\n\n\t// Kubernetes service discovery\n\tMonitorPods                 bool                `toml:\"monitor_kubernetes_pods\"`\n\tPodScrapeScope              string              `toml:\"pod_scrape_scope\"`\n\tNodeIP                      string              `toml:\"node_ip\"`\n\tPodScrapeInterval           int                 `toml:\"pod_scrape_interval\"`\n\tPodNamespace                string              `toml:\"monitor_kubernetes_pods_namespace\"`\n\tPodNamespaceLabelName       string              `toml:\"pod_namespace_label_name\"`\n\tKubernetesServices          []string            `toml:\"kubernetes_services\"`\n\tKubeConfig                  string              `toml:\"kube_config\"`\n\tKubernetesLabelSelector     string              `toml:\"kubernetes_label_selector\"`\n\tKubernetesFieldSelector     string              `toml:\"kubernetes_field_selector\"`\n\tMonitorKubernetesPodsMethod monitorMethod       `toml:\"monitor_kubernetes_pods_method\"`\n\tMonitorKubernetesPodsScheme string              `toml:\"monitor_kubernetes_pods_scheme\"`\n\tMonitorKubernetesPodsPath   string              `toml:\"monitor_kubernetes_pods_path\"`\n\tMonitorKubernetesPodsPort   int                 `toml:\"monitor_kubernetes_pods_port\"`\n\tNamespaceAnnotationPass     map[string][]string `toml:\"namespace_annotation_pass\"`\n\tNamespaceAnnotationDrop     map[string][]string `toml:\"namespace_annotation_drop\"`\n\tPodAnnotationInclude        []string            `toml:\"pod_annotation_include\"`\n\tPodAnnotationExclude        []string            `toml:\"pod_annotation_exclude\"`\n\tPodLabelInclude             []string            `toml:\"pod_label_include\"`\n\tPodLabelExclude             []string            `toml:\"pod_label_exclude\"`\n\tCacheRefreshInterval        int                 `toml:\"cache_refresh_interval\"`\n\n\t// Consul discovery\n\tConsulConfig consulConfig `toml:\"consul\"`\n\n\t// HTTP service discovery\n\tHTTPSDConfig HTTPSDConfig `toml:\"http_service_discovery\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\tcommon_http.HTTPClientConfig\n\n\tclient      *http.Client\n\theaders     map[string]string\n\tcontentType string\n\n\tnsStore          cache.Store\n\tnsAnnotationPass []models.TagFilter\n\tnsAnnotationDrop []models.TagFilter\n\n\t// Should we scrape Kubernetes services for prometheus annotations\n\tlock           sync.Mutex\n\tkubernetesPods map[podID]urlAndAddress\n\tcancel         context.CancelFunc\n\twg             sync.WaitGroup\n\n\t// Only for monitor_kubernetes_pods=true and pod_scrape_scope=\"node\"\n\tpodLabelSelector           labels.Selector\n\tpodFieldSelector           fields.Selector\n\tisNodeScrapeScope          bool\n\tpodAnnotationIncludeFilter filter.Filter\n\tpodAnnotationExcludeFilter filter.Filter\n\tpodLabelIncludeFilter      filter.Filter\n\tpodLabelExcludeFilter      filter.Filter\n\n\t// List of consul services to scrape\n\tconsulServices map[string]urlAndAddress\n\n\t// list of http services to scrape\n\thttpServices map[string]urlAndAddress\n}\n\ntype urlAndAddress struct {\n\toriginalURL *url.URL\n\turl         *url.URL\n\taddress     string\n\ttags        map[string]string\n\tnamespace   string\n}\n\ntype monitorMethod string\n\ntype podID string\n\nfunc (*Prometheus) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *Prometheus) Init() error {\n\t// Setup content-type override if requested\n\tswitch p.ContentTypeOverride {\n\tcase \"\": // No override\n\tcase \"text\":\n\t\tp.contentType = string(expfmt.NewFormat(expfmt.TypeTextPlain))\n\tcase \"protobuf-delimiter\":\n\t\tp.contentType = string(expfmt.NewFormat(expfmt.TypeProtoDelim))\n\tcase \"protobuf-compact\":\n\t\tp.contentType = string(expfmt.NewFormat(expfmt.TypeProtoCompact))\n\tcase \"protobuf-text\":\n\t\tp.contentType = string(expfmt.NewFormat(expfmt.TypeProtoText))\n\tcase \"openmetrics-text\":\n\t\tf, err := expfmt.NewOpenMetricsFormat(expfmt.OpenMetricsVersion_1_0_0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tp.contentType = string(f)\n\tcase \"openmetrics-protobuf\":\n\t\tp.contentType = \"application/openmetrics-protobuf;version=1.0.0\"\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid 'content_type_override' setting %q\", p.ContentTypeOverride)\n\t}\n\n\t// Config processing for node scrape scope for monitor_kubernetes_pods\n\tp.isNodeScrapeScope = strings.EqualFold(p.PodScrapeScope, \"node\")\n\tif p.isNodeScrapeScope {\n\t\t// Need node IP to make cAdvisor call for pod list. Check if set in config and valid IP address\n\t\tif p.NodeIP == \"\" || net.ParseIP(p.NodeIP) == nil {\n\t\t\tp.Log.Infof(\"The config node_ip is empty or invalid. Using NODE_IP env var as default.\")\n\n\t\t\t// Check if set as env var and is valid IP address\n\t\t\tenvVarNodeIP := os.Getenv(\"NODE_IP\")\n\t\t\tif envVarNodeIP == \"\" || net.ParseIP(envVarNodeIP) == nil {\n\t\t\t\treturn errors.New(\"the node_ip config and the environment variable NODE_IP are not set or invalid; \" +\n\t\t\t\t\t\"cannot get pod list for monitor_kubernetes_pods using node scrape scope\")\n\t\t\t}\n\n\t\t\tp.NodeIP = envVarNodeIP\n\t\t}\n\t\tp.Log.Infof(\"Using pod scrape scope at node level to get pod list using cAdvisor.\")\n\t}\n\n\tif p.MonitorKubernetesPodsMethod == monitorMethodNone {\n\t\tp.MonitorKubernetesPodsMethod = monitorMethodAnnotations\n\t}\n\n\t// Parse label and field selectors - will be used to filter pods after cAdvisor call\n\tvar err error\n\tp.podLabelSelector, err = labels.Parse(p.KubernetesLabelSelector)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing the specified label selector(s): %w\", err)\n\t}\n\tp.podFieldSelector, err = fields.ParseSelector(p.KubernetesFieldSelector)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing the specified field selector(s): %w\", err)\n\t}\n\tisValid, invalidSelector := fieldSelectorIsSupported(p.podFieldSelector)\n\tif !isValid {\n\t\treturn fmt.Errorf(\"the field selector %q is not supported for pods\", invalidSelector)\n\t}\n\n\tif p.KubernetesLabelSelector != \"\" {\n\t\tp.Log.Debugf(\"Using the label selector: %v\", p.podLabelSelector)\n\t}\n\tif p.KubernetesFieldSelector != \"\" {\n\t\tp.Log.Debugf(\"Using the field selector: %v\", p.podFieldSelector)\n\t}\n\n\tfor k, vs := range p.NamespaceAnnotationPass {\n\t\ttagFilter := models.TagFilter{}\n\t\ttagFilter.Name = k\n\t\ttagFilter.Values = append(tagFilter.Values, vs...)\n\t\tif err := tagFilter.Compile(); err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'namespace_annotation_pass', %w\", err)\n\t\t}\n\t\tp.nsAnnotationPass = append(p.nsAnnotationPass, tagFilter)\n\t}\n\n\tfor k, vs := range p.NamespaceAnnotationDrop {\n\t\ttagFilter := models.TagFilter{}\n\t\ttagFilter.Name = k\n\t\ttagFilter.Values = append(tagFilter.Values, vs...)\n\t\tif err := tagFilter.Compile(); err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'namespace_annotation_drop', %w\", err)\n\t\t}\n\t\tp.nsAnnotationDrop = append(p.nsAnnotationDrop, tagFilter)\n\t}\n\n\tif err := p.initFilters(); err != nil {\n\t\treturn err\n\t}\n\n\tif p.MetricVersion == 0 {\n\t\tp.MetricVersion = 1\n\t}\n\n\tctx := context.Background()\n\n\tclient, err := p.HTTPClientConfig.CreateClient(ctx, p.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\tp.client = client\n\tif p.HTTPClientConfig.ResponseHeaderTimeout != 0 {\n\t\tp.Log.Warn(\n\t\t\t\"Config option response_timeout was set to non-zero value. This option's behavior was \" +\n\t\t\t\t\"changed in Telegraf 1.30.2 and now controls the HTTP client's header timeout and \" +\n\t\t\t\t\"not the Prometheus timeout. Users can ignore this warning if that was the intention. \" +\n\t\t\t\t\"Otherwise, please use the timeout config option for the Prometheus timeout.\",\n\t\t)\n\t}\n\n\tp.headers = map[string]string{\n\t\t\"User-Agent\": internal.ProductToken(),\n\t\t\"Accept\":     acceptHeader,\n\t}\n\n\tp.kubernetesPods = make(map[podID]urlAndAddress)\n\n\treturn nil\n}\n\n// Start will start the Kubernetes and/or Consul scraping if enabled in the configuration\nfunc (p *Prometheus) Start(_ telegraf.Accumulator) error {\n\tvar ctx context.Context\n\tp.wg = sync.WaitGroup{}\n\tctx, p.cancel = context.WithCancel(context.Background())\n\n\tif p.ConsulConfig.Enabled && len(p.ConsulConfig.Queries) > 0 {\n\t\tif err := p.startConsul(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif p.MonitorPods {\n\t\tif err := p.startK8s(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif p.HTTPSDConfig.Enabled {\n\t\tif err := p.startHTTPSD(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (p *Prometheus) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tallURLs, err := p.getAllURLs()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, URL := range allURLs {\n\t\twg.Add(1)\n\t\tgo func(serviceURL urlAndAddress) {\n\t\t\tdefer wg.Done()\n\t\t\trequestFields, tags, err := p.gatherURL(serviceURL, acc)\n\t\t\tacc.AddError(err)\n\n\t\t\t// Add metrics\n\t\t\tif p.EnableRequestMetrics {\n\t\t\t\tacc.AddFields(\"prometheus_request\", requestFields, tags)\n\t\t\t}\n\t\t}(URL)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (p *Prometheus) Stop() {\n\tp.cancel()\n\tp.wg.Wait()\n\n\tif p.MonitorPods && !p.isNodeScrapeScope {\n\t\tvar factoryToShutdown informers.SharedInformerFactory\n\t\tinformerfactoryMu.Lock()\n\t\tif informerfactoryRefs != nil {\n\t\t\tinformerfactoryRefs[p.PodNamespace]--\n\t\t\tif informerfactoryRefs[p.PodNamespace] <= 0 {\n\t\t\t\tfactoryToShutdown = informerfactory[p.PodNamespace]\n\t\t\t\tdelete(informerfactory, p.PodNamespace)\n\t\t\t\tdelete(informerfactoryRefs, p.PodNamespace)\n\t\t\t}\n\t\t}\n\t\tinformerfactoryMu.Unlock()\n\t\t// Shutdown outside the lock because it blocks until all informer\n\t\t// goroutines terminate. Holding the mutex during that wait would\n\t\t// serialise all plugin Start/Stop operations behind a potentially\n\t\t// slow network teardown.\n\t\tif factoryToShutdown != nil {\n\t\t\tfactoryToShutdown.Shutdown()\n\t\t}\n\t}\n\n\tif p.client != nil {\n\t\tp.client.CloseIdleConnections()\n\t}\n}\n\nfunc (p *Prometheus) initFilters() error {\n\tif p.PodAnnotationExclude != nil {\n\t\tpodAnnotationExclude, err := filter.Compile(p.PodAnnotationExclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'pod_annotation_exclude': %w\", err)\n\t\t}\n\t\tp.podAnnotationExcludeFilter = podAnnotationExclude\n\t}\n\tif p.PodAnnotationInclude != nil {\n\t\tpodAnnotationInclude, err := filter.Compile(p.PodAnnotationInclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'pod_annotation_include': %w\", err)\n\t\t}\n\t\tp.podAnnotationIncludeFilter = podAnnotationInclude\n\t}\n\tif p.PodLabelExclude != nil {\n\t\tpodLabelExclude, err := filter.Compile(p.PodLabelExclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'pod_label_exclude': %w\", err)\n\t\t}\n\t\tp.podLabelExcludeFilter = podLabelExclude\n\t}\n\tif p.PodLabelInclude != nil {\n\t\tpodLabelInclude, err := filter.Compile(p.PodLabelInclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling 'pod_label_include': %w\", err)\n\t\t}\n\t\tp.podLabelIncludeFilter = podLabelInclude\n\t}\n\treturn nil\n}\n\nfunc addressToURL(u *url.URL, address string) *url.URL {\n\thost := address\n\tif u.Port() != \"\" {\n\t\thost = address + \":\" + u.Port()\n\t}\n\treconstructedURL := &url.URL{\n\t\tScheme:     u.Scheme,\n\t\tOpaque:     u.Opaque,\n\t\tUser:       u.User,\n\t\tPath:       u.Path,\n\t\tRawPath:    u.RawPath,\n\t\tForceQuery: u.ForceQuery,\n\t\tRawQuery:   u.RawQuery,\n\t\tFragment:   u.Fragment,\n\t\tHost:       host,\n\t}\n\treturn reconstructedURL\n}\n\nfunc (p *Prometheus) getAllURLs() (map[string]urlAndAddress, error) {\n\tallURLs := make(map[string]urlAndAddress, len(p.URLs)+len(p.consulServices)+len(p.kubernetesPods)+len(p.httpServices))\n\tfor _, u := range p.URLs {\n\t\taddress, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tp.Log.Errorf(\"Could not parse %q, skipping it. Error: %s\", u, err.Error())\n\t\t\tcontinue\n\t\t}\n\t\tallURLs[address.String()] = urlAndAddress{url: address, originalURL: address}\n\t}\n\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\t// add all services collected from consul\n\tfor k, v := range p.consulServices {\n\t\tallURLs[k] = v\n\t}\n\t// add all services collected from http service discovery\n\tfor k, v := range p.httpServices {\n\t\tallURLs[k] = v\n\t}\n\t// loop through all pods scraped via the prometheus annotation on the pods\n\tfor _, v := range p.kubernetesPods {\n\t\tif namespaceAnnotationMatch(v.namespace, p) {\n\t\t\tallURLs[v.url.String()] = v\n\t\t}\n\t}\n\n\tfor _, service := range p.KubernetesServices {\n\t\taddress, err := url.Parse(service)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresolvedAddresses, err := net.LookupHost(address.Hostname())\n\t\tif err != nil {\n\t\t\tp.Log.Errorf(\"Could not resolve %q, skipping it. Error: %s\", address.Host, err.Error())\n\t\t\tcontinue\n\t\t}\n\t\tfor _, resolved := range resolvedAddresses {\n\t\t\tserviceURL := addressToURL(address, resolved)\n\t\t\tallURLs[serviceURL.String()] = urlAndAddress{\n\t\t\t\turl:         serviceURL,\n\t\t\t\taddress:     resolved,\n\t\t\t\toriginalURL: address,\n\t\t\t}\n\t\t}\n\t}\n\treturn allURLs, nil\n}\n\nfunc (p *Prometheus) gatherURL(u urlAndAddress, acc telegraf.Accumulator) (map[string]interface{}, map[string]string, error) {\n\tvar req *http.Request\n\tvar uClient *http.Client\n\trequestFields := make(map[string]interface{})\n\ttags := make(map[string]string, len(u.tags)+2)\n\tif p.URLTag != \"\" {\n\t\ttags[p.URLTag] = u.originalURL.String()\n\t}\n\tif u.address != \"\" {\n\t\ttags[\"address\"] = u.address\n\t}\n\tfor k, v := range u.tags {\n\t\ttags[k] = v\n\t}\n\n\tif u.url.Scheme == \"unix\" {\n\t\tpath := u.url.Query().Get(\"path\")\n\t\tif path == \"\" {\n\t\t\tpath = \"/metrics\"\n\t\t}\n\n\t\tvar err error\n\t\taddr := \"http://localhost\" + path\n\t\treq, err = http.NewRequest(\"GET\", addr, nil)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"unable to create new request %q: %w\", addr, err)\n\t\t}\n\n\t\t//nolint:errcheck // ignore error because it's been handled before getting here\n\t\ttlsCfg, _ := p.HTTPClientConfig.TLSConfig()\n\t\tuClient = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tTLSClientConfig:   tlsCfg,\n\t\t\t\tDisableKeepAlives: true,\n\t\t\t\tDial: func(string, string) (net.Conn, error) {\n\t\t\t\t\tc, err := net.Dial(\"unix\", u.url.Path)\n\t\t\t\t\treturn c, err\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t} else {\n\t\tif u.url.Path == \"\" {\n\t\t\tu.url.Path = \"/metrics\"\n\t\t}\n\t\tvar err error\n\t\treq, err = http.NewRequest(\"GET\", u.url.String(), nil)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"unable to create new request %q: %w\", u.url.String(), err)\n\t\t}\n\t}\n\n\tp.addHeaders(req)\n\n\tif p.BearerToken != \"\" {\n\t\ttoken, err := os.ReadFile(p.BearerToken)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+string(token))\n\t} else if !p.BearerTokenString.Empty() {\n\t\ttoken, err := p.BearerTokenString.Get()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"getting token secret failed: %w\", err)\n\t\t}\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+token.String())\n\t\ttoken.Destroy()\n\t} else if !p.Username.Empty() || !p.Password.Empty() {\n\t\tusername, err := p.Username.Get()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"getting username secret failed: %w\", err)\n\t\t}\n\t\tpassword, err := p.Password.Get()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"getting password secret failed: %w\", err)\n\t\t}\n\t\treq.SetBasicAuth(username.String(), password.String())\n\t\tusername.Destroy()\n\t\tpassword.Destroy()\n\t}\n\n\tfor key, value := range p.HTTPHeaders {\n\t\tif strings.EqualFold(key, \"host\") {\n\t\t\treq.Host = value\n\t\t} else {\n\t\t\treq.Header.Set(key, value)\n\t\t}\n\t}\n\n\tvar err error\n\tvar resp *http.Response\n\tvar start time.Time\n\tif u.url.Scheme != \"unix\" {\n\t\tstart = time.Now()\n\t\tresp, err = p.client.Do(req)\n\t} else {\n\t\tstart = time.Now()\n\t\tresp, err = uClient.Do(req)\n\t}\n\tend := time.Since(start).Seconds()\n\tif err != nil {\n\t\treturn requestFields, tags, fmt.Errorf(\"error making HTTP request to %q: %w\", u.url, err)\n\t}\n\trequestFields[\"response_time\"] = end\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn requestFields, tags, fmt.Errorf(\"%q returned HTTP status %q\", u.url, resp.Status)\n\t}\n\n\tvar body []byte\n\tif p.ContentLengthLimit != 0 {\n\t\tlimit := int64(p.ContentLengthLimit)\n\n\t\t// To determine whether io.ReadAll() ended due to EOF or reached the specified limit,\n\t\t// read up to the specified limit plus one extra byte, and then make a decision based\n\t\t// on the length of the result.\n\t\tlr := io.LimitReader(resp.Body, limit+1)\n\n\t\tbody, err = io.ReadAll(lr)\n\t\tif err != nil {\n\t\t\treturn requestFields, tags, fmt.Errorf(\"error reading body: %w\", err)\n\t\t}\n\t\tif int64(len(body)) > limit {\n\t\t\tp.Log.Infof(\"skipping %s: content length exceeded maximum body size (%d)\", u.url, limit)\n\t\t\treturn requestFields, tags, nil\n\t\t}\n\t} else {\n\t\tbody, err = io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn requestFields, tags, fmt.Errorf(\"error reading body: %w\", err)\n\t\t}\n\t}\n\trequestFields[\"content_length\"] = len(body)\n\n\t// Override the response format if the user requested it\n\tif p.contentType != \"\" {\n\t\tresp.Header.Set(\"Content-Type\", p.contentType)\n\t}\n\n\t// Parse the metrics\n\tvar metricParser telegraf.Parser\n\tif openmetrics.AcceptsContent(resp.Header) {\n\t\tmetricParser = &openmetrics.Parser{\n\t\t\tHeader:          resp.Header,\n\t\t\tMetricVersion:   p.MetricVersion,\n\t\t\tIgnoreTimestamp: p.IgnoreTimestamp,\n\t\t\tLog:             p.Log,\n\t\t}\n\t} else {\n\t\tmetricParser = &parsers_prometheus.Parser{\n\t\t\tHeader:          resp.Header,\n\t\t\tMetricVersion:   p.MetricVersion,\n\t\t\tIgnoreTimestamp: p.IgnoreTimestamp,\n\t\t\tLog:             p.Log,\n\t\t}\n\t}\n\tmetrics, err := metricParser.Parse(body)\n\tif err != nil {\n\t\treturn requestFields, tags, fmt.Errorf(\"error reading metrics for %q: %w\", u.url, err)\n\t}\n\n\tfor _, metric := range metrics {\n\t\ttags := metric.Tags()\n\t\t// strip user and password from URL\n\t\tu.originalURL.User = nil\n\t\tif p.URLTag != \"\" {\n\t\t\ttags[p.URLTag] = u.originalURL.String()\n\t\t}\n\t\tif u.address != \"\" {\n\t\t\ttags[\"address\"] = u.address\n\t\t}\n\t\tfor k, v := range u.tags {\n\t\t\ttags[k] = v\n\t\t}\n\n\t\tswitch metric.Type() {\n\t\tcase telegraf.Counter:\n\t\t\tacc.AddCounter(metric.Name(), metric.Fields(), tags, metric.Time())\n\t\tcase telegraf.Gauge:\n\t\t\tacc.AddGauge(metric.Name(), metric.Fields(), tags, metric.Time())\n\t\tcase telegraf.Summary:\n\t\t\tacc.AddSummary(metric.Name(), metric.Fields(), tags, metric.Time())\n\t\tcase telegraf.Histogram:\n\t\t\tacc.AddHistogram(metric.Name(), metric.Fields(), tags, metric.Time())\n\t\tdefault:\n\t\t\tacc.AddFields(metric.Name(), metric.Fields(), tags, metric.Time())\n\t\t}\n\t}\n\n\treturn requestFields, tags, nil\n}\n\nfunc (p *Prometheus) addHeaders(req *http.Request) {\n\tfor header, value := range p.headers {\n\t\treq.Header.Add(header, value)\n\t}\n}\n\n/* Check if the field selector specified is valid.\n * See ToSelectableFields() for list of fields that are selectable:\n * https://github.com/kubernetes/kubernetes/release-1.20/pkg/registry/core/pod/strategy.go\n */\nfunc fieldSelectorIsSupported(fieldSelector fields.Selector) (bool, string) {\n\tsupportedFieldsToSelect := map[string]bool{\n\t\t\"spec.nodeName\":            true,\n\t\t\"spec.restartPolicy\":       true,\n\t\t\"spec.schedulerName\":       true,\n\t\t\"spec.serviceAccountName\":  true,\n\t\t\"status.phase\":             true,\n\t\t\"status.podIP\":             true,\n\t\t\"status.nominatedNodeName\": true,\n\t}\n\n\tfor _, requirement := range fieldSelector.Requirements() {\n\t\tif !supportedFieldsToSelect[requirement.Field] {\n\t\t\treturn false, requirement.Field\n\t\t}\n\t}\n\n\treturn true, \"\"\n}\n\nfunc init() {\n\tinputs.Add(\"prometheus\", func() telegraf.Input {\n\t\treturn &Prometheus{\n\t\t\tkubernetesPods: make(map[podID]urlAndAddress),\n\t\t\tconsulServices: make(map[string]urlAndAddress),\n\t\t\thttpServices:   make(map[string]urlAndAddress),\n\t\t\tURLTag:         \"url\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/prometheus_test.go",
    "content": "package prometheus\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleTextFormat = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.\n# TYPE go_gc_duration_seconds summary\ngo_gc_duration_seconds{quantile=\"0\"} 0.00010425500000000001\ngo_gc_duration_seconds{quantile=\"0.25\"} 0.000139108\ngo_gc_duration_seconds{quantile=\"0.5\"} 0.00015749400000000002\ngo_gc_duration_seconds{quantile=\"0.75\"} 0.000331463\ngo_gc_duration_seconds{quantile=\"1\"} 0.000667154\ngo_gc_duration_seconds_sum 0.0018183950000000002\ngo_gc_duration_seconds_count 7\n# HELP go_goroutines Number of goroutines that currently exist.\n# TYPE go_goroutines gauge\ngo_goroutines 15\n# HELP test_metric An untyped metric with a timestamp\n# TYPE test_metric untyped\ntest_metric{label=\"value\"} 1.0 1490802350000`\n\nconst sampleSummaryTextFormat = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.\n# TYPE go_gc_duration_seconds summary\ngo_gc_duration_seconds{quantile=\"0\"} 0.00010425500000000001\ngo_gc_duration_seconds{quantile=\"0.25\"} 0.000139108\ngo_gc_duration_seconds{quantile=\"0.5\"} 0.00015749400000000002\ngo_gc_duration_seconds{quantile=\"0.75\"} 0.000331463\ngo_gc_duration_seconds{quantile=\"1\"} 0.000667154\ngo_gc_duration_seconds_sum 0.0018183950000000002\ngo_gc_duration_seconds_count 7`\n\nconst sampleGaugeTextFormat = `\n# HELP go_goroutines Number of goroutines that currently exist.\n# TYPE go_goroutines gauge\ngo_goroutines 15 1490802350000`\n\nfunc TestPrometheusGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:    testutil.Logger{},\n\t\tURLs:   []string{ts.URL},\n\t\tURLTag: \"url\",\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"go_gc_duration_seconds\", \"count\"))\n\trequire.True(t, acc.HasFloatField(\"go_goroutines\", \"gauge\"))\n\trequire.True(t, acc.HasFloatField(\"test_metric\", \"value\"))\n\trequire.True(t, acc.HasTimestamp(\"test_metric\", time.Unix(1490802350, 0)))\n\trequire.False(t, acc.HasTag(\"test_metric\", \"address\"))\n\trequire.Equal(t, ts.URL+\"/metrics\", acc.TagValue(\"test_metric\", \"url\"))\n}\n\nfunc TestPrometheusCustomHeader(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.Header.Get(\"accept\") {\n\t\tcase \"application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.7,text/plain;version=0.0.4;q=0.3\":\n\t\t\tif _, err := fmt.Fprintln(w, \"proto 15 1490802540000\"); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"text/plain\":\n\t\t\tif _, err := fmt.Fprintln(w, \"plain 42 1490802380000\"); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tif _, err := fmt.Fprintln(w, \"other 44 1490802420000\"); err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\ttests := []struct {\n\t\tname                    string\n\t\theaders                 map[string]string\n\t\texpectedMeasurementName string\n\t}{\n\t\t{\n\t\t\t\"default\",\n\t\t\tmap[string]string{},\n\t\t\t\"proto\",\n\t\t},\n\t\t{\n\t\t\t\"plain text\",\n\t\t\tmap[string]string{\n\t\t\t\t\"accept\": \"text/plain\",\n\t\t\t},\n\t\t\t\"plain\",\n\t\t},\n\t\t{\n\t\t\t\"other\",\n\t\t\tmap[string]string{\n\t\t\t\t\"accept\": \"fakeACCEPTitem\",\n\t\t\t},\n\t\t\t\"other\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tp := &Prometheus{\n\t\t\tLog:         testutil.Logger{},\n\t\t\tURLs:        []string{ts.URL},\n\t\t\tURLTag:      \"url\",\n\t\t\tHTTPHeaders: test.headers,\n\t\t}\n\t\terr := p.Init()\n\t\trequire.NoError(t, err)\n\n\t\tvar acc testutil.Accumulator\n\t\trequire.NoError(t, acc.GatherError(p.Gather))\n\t\trequire.Equal(t, test.expectedMeasurementName, acc.Metrics[0].Measurement)\n\t}\n}\n\nfunc TestPrometheusGeneratesMetricsWithHostNameTag(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                testutil.Logger{},\n\t\tKubernetesServices: []string{ts.URL},\n\t\tURLTag:             \"url\",\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\ttsAddress := u.Hostname()\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"go_gc_duration_seconds\", \"count\"))\n\trequire.True(t, acc.HasFloatField(\"go_goroutines\", \"gauge\"))\n\trequire.True(t, acc.HasFloatField(\"test_metric\", \"value\"))\n\trequire.True(t, acc.HasTimestamp(\"test_metric\", time.Unix(1490802350, 0)))\n\trequire.Equal(t, tsAddress, acc.TagValue(\"test_metric\", \"address\"))\n\trequire.Equal(t, ts.URL, acc.TagValue(\"test_metric\", \"url\"))\n}\n\nfunc TestPrometheusWithTimestamp(t *testing.T) {\n\tprommetric := `# HELP test_counter A sample test counter.\n# TYPE test_counter counter\ntest_counter{label=\"test\"} 1 1685443805885`\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, prommetric); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                testutil.Logger{},\n\t\tKubernetesServices: []string{ts.URL},\n\t}\n\trequire.NoError(t, p.Init())\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\ttsAddress := u.Hostname()\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test_counter\",\n\t\t\tmap[string]string{\"address\": tsAddress, \"label\": \"test\"},\n\t\t\tmap[string]interface{}{\"counter\": float64(1.0)},\n\t\t\ttime.UnixMilli(1685443805885),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttestutil.RequireMetricsSubset(t, expected, acc.GetTelegrafMetrics())\n}\n\nfunc TestPrometheusGeneratesMetricsAlthoughFirstDNSFailsIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                testutil.Logger{},\n\t\tURLs:               []string{ts.URL},\n\t\tKubernetesServices: []string{\"http://random.telegraf.local:88/metrics\"},\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"go_gc_duration_seconds\", \"count\"))\n\trequire.True(t, acc.HasFloatField(\"go_goroutines\", \"gauge\"))\n\trequire.True(t, acc.HasFloatField(\"test_metric\", \"value\"))\n\trequire.True(t, acc.HasTimestamp(\"test_metric\", time.Unix(1490802350, 0)))\n}\n\nfunc TestPrometheusGeneratesMetricsSlowEndpoint(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(4 * time.Second)\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:    testutil.Logger{},\n\t\tURLs:   []string{ts.URL},\n\t\tURLTag: \"url\",\n\t\tclient: &http.Client{\n\t\t\tTimeout: time.Second * 5,\n\t\t},\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"go_gc_duration_seconds\", \"count\"))\n\trequire.True(t, acc.HasFloatField(\"go_goroutines\", \"gauge\"))\n\trequire.True(t, acc.HasFloatField(\"test_metric\", \"value\"))\n\trequire.True(t, acc.HasTimestamp(\"test_metric\", time.Unix(1490802350, 0)))\n\trequire.False(t, acc.HasTag(\"test_metric\", \"address\"))\n\trequire.Equal(t, acc.TagValue(\"test_metric\", \"url\"), ts.URL+\"/metrics\")\n}\n\nfunc TestPrometheusGeneratesMetricsSlowEndpointHitTheTimeout(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(6 * time.Second)\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:    testutil.Logger{},\n\t\tURLs:   []string{ts.URL},\n\t\tURLTag: \"url\",\n\t\tclient: &http.Client{\n\t\t\tTimeout: time.Second * 5,\n\t\t},\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\terrMessage := fmt.Sprintf(\"error making HTTP request to \\\"%s/metrics\\\": Get \\\"%s/metrics\\\": \"+\n\t\t\"context deadline exceeded (Client.Timeout exceeded while awaiting headers)\", ts.URL, ts.URL)\n\terrExpected := errors.New(errMessage)\n\trequire.Error(t, err)\n\trequire.Equal(t, errExpected.Error(), err.Error())\n}\n\nfunc TestPrometheusGeneratesMetricsSlowEndpointNewConfigParameter(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(4 * time.Second)\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:    testutil.Logger{},\n\t\tURLs:   []string{ts.URL},\n\t\tURLTag: \"url\",\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\tp.client.Timeout = time.Second * 5\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"go_gc_duration_seconds\", \"count\"))\n\trequire.True(t, acc.HasFloatField(\"go_goroutines\", \"gauge\"))\n\trequire.True(t, acc.HasFloatField(\"test_metric\", \"value\"))\n\trequire.True(t, acc.HasTimestamp(\"test_metric\", time.Unix(1490802350, 0)))\n\trequire.False(t, acc.HasTag(\"test_metric\", \"address\"))\n\trequire.Equal(t, acc.TagValue(\"test_metric\", \"url\"), ts.URL+\"/metrics\")\n}\n\nfunc TestPrometheusGeneratesMetricsSlowEndpointHitTheTimeoutNewConfigParameter(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(6 * time.Second)\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:    testutil.Logger{},\n\t\tURLs:   []string{ts.URL},\n\t\tURLTag: \"url\",\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\tp.client.Timeout = time.Second * 5\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.ErrorContains(t, err, \"error making HTTP request to \\\"\"+ts.URL+\"/metrics\\\"\")\n}\n\nfunc TestPrometheusContentLengthLimit(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                testutil.Logger{},\n\t\tURLs:               []string{ts.URL},\n\t\tURLTag:             \"url\",\n\t\tContentLengthLimit: 1,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\trequire.Empty(t, acc.Metrics)\n}\n\nfunc TestPrometheusGeneratesSummaryMetricsV2(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleSummaryTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:           &testutil.Logger{},\n\t\tURLs:          []string{ts.URL},\n\t\tURLTag:        \"url\",\n\t\tMetricVersion: 2,\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"0\", acc.TagSetValue(\"prometheus\", \"quantile\"))\n\trequire.True(t, acc.HasFloatField(\"prometheus\", \"go_gc_duration_seconds_sum\"))\n\trequire.True(t, acc.HasFloatField(\"prometheus\", \"go_gc_duration_seconds_count\"))\n\trequire.Equal(t, acc.TagValue(\"prometheus\", \"url\"), ts.URL+\"/metrics\")\n}\n\nfunc TestSummaryMayContainNaN(t *testing.T) {\n\tconst data = `# HELP go_gc_duration_seconds A summary of the GC invocation durations.\n# TYPE go_gc_duration_seconds summary\ngo_gc_duration_seconds{quantile=\"0\"} NaN\ngo_gc_duration_seconds{quantile=\"1\"} NaN\ngo_gc_duration_seconds_sum 42.0\ngo_gc_duration_seconds_count 42`\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                  &testutil.Logger{},\n\t\tURLs:                 []string{ts.URL},\n\t\tURLTag:               \"\",\n\t\tMetricVersion:        2,\n\t\tEnableRequestMetrics: true,\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = p.Gather(&acc)\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"prometheus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"quantile\": \"0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"go_gc_duration_seconds\": math.NaN(),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Summary,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"prometheus\",\n\t\t\tmap[string]string{\n\t\t\t\t\"quantile\": \"1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"go_gc_duration_seconds\": math.NaN(),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Summary,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"prometheus\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"go_gc_duration_seconds_sum\":   float64(42.0),\n\t\t\t\t\"go_gc_duration_seconds_count\": float64(42)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Summary,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"prometheus_request\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"content_length\": int64(1),\n\t\t\t\t\"response_time\":  float64(0)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime(), testutil.SortMetrics(), testutil.IgnoreFields(\"content_length\", \"response_time\"))\n}\n\nfunc TestPrometheusGeneratesGaugeMetricsV2(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleGaugeTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:           &testutil.Logger{},\n\t\tURLs:          []string{ts.URL},\n\t\tURLTag:        \"url\",\n\t\tMetricVersion: 2,\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(p.Gather)\n\trequire.NoError(t, err)\n\n\trequire.True(t, acc.HasFloatField(\"prometheus\", \"go_goroutines\"))\n\trequire.Equal(t, acc.TagValue(\"prometheus\", \"url\"), ts.URL+\"/metrics\")\n\trequire.True(t, acc.HasTimestamp(\"prometheus\", time.Unix(1490802350, 0)))\n}\n\nfunc TestPrometheusGeneratesMetricsWithIgnoreTimestamp(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, sampleTextFormat); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:             testutil.Logger{},\n\t\tURLs:            []string{ts.URL},\n\t\tURLTag:          \"url\",\n\t\tIgnoreTimestamp: true,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\n\tm, found := acc.Get(\"test_metric\")\n\trequire.True(t, found)\n\trequire.NotNil(t, m)\n\trequire.WithinDuration(t, time.Now(), m.Time, 5*time.Second)\n}\n\nfunc TestUnsupportedFieldSelector(t *testing.T) {\n\tfieldSelectorString := \"spec.containerName=container\"\n\tprom := &Prometheus{Log: testutil.Logger{}, KubernetesFieldSelector: fieldSelectorString}\n\n\tfieldSelector, err := fields.ParseSelector(prom.KubernetesFieldSelector)\n\trequire.NoError(t, err)\n\tisValid, invalidSelector := fieldSelectorIsSupported(fieldSelector)\n\trequire.False(t, isValid)\n\trequire.Equal(t, \"spec.containerName\", invalidSelector)\n}\n\nfunc TestInitConfigErrors(t *testing.T) {\n\tp := &Prometheus{\n\t\tMetricVersion:     2,\n\t\tLog:               testutil.Logger{},\n\t\tURLs:              nil,\n\t\tURLTag:            \"url\",\n\t\tMonitorPods:       true,\n\t\tPodScrapeScope:    \"node\",\n\t\tPodScrapeInterval: 60,\n\t}\n\n\t// Both invalid IP addresses\n\tt.Run(\"Both invalid IP addresses\", func(t *testing.T) {\n\t\tp.NodeIP = \"10.240.0.0.0\"\n\t\tt.Setenv(\"NODE_IP\", \"10.000.0.0.0\")\n\t\terr := p.Init()\n\t\trequire.Error(t, err)\n\t\texpectedMessage := \"the node_ip config and the environment variable NODE_IP are not set or invalid; \" +\n\t\t\t\"cannot get pod list for monitor_kubernetes_pods using node scrape scope\"\n\t\trequire.Equal(t, expectedMessage, err.Error())\n\t})\n\n\tt.Run(\"Valid IP address\", func(t *testing.T) {\n\t\tt.Setenv(\"NODE_IP\", \"10.000.0.0\")\n\n\t\tp.KubernetesLabelSelector = \"label0==label0, label0 in (=)\"\n\t\terr := p.Init()\n\t\texpectedMessage := \"error parsing the specified label selector(s): unable to parse requirement: found '=', expected: ',', ')' or identifier\"\n\t\trequire.Error(t, err, expectedMessage)\n\t\tp.KubernetesLabelSelector = \"label0==label\"\n\n\t\tp.KubernetesFieldSelector = \"field,\"\n\t\terr = p.Init()\n\t\texpectedMessage = \"error parsing the specified field selector(s): invalid selector: 'field,'; can't understand 'field'\"\n\t\trequire.Error(t, err, expectedMessage)\n\n\t\tp.KubernetesFieldSelector = \"spec.containerNames=containerNames\"\n\t\terr = p.Init()\n\t\texpectedMessage = \"the field selector spec.containerNames is not supported for pods\"\n\t\trequire.Error(t, err, expectedMessage)\n\t})\n}\n\nfunc TestInitConfigSelectors(t *testing.T) {\n\tp := &Prometheus{\n\t\tMetricVersion:               2,\n\t\tLog:                         testutil.Logger{},\n\t\tURLs:                        nil,\n\t\tURLTag:                      \"url\",\n\t\tMonitorPods:                 true,\n\t\tMonitorKubernetesPodsMethod: monitorMethodSettings,\n\t\tPodScrapeInterval:           60,\n\t\tKubernetesLabelSelector:     \"app=test\",\n\t\tKubernetesFieldSelector:     \"spec.nodeName=node-0\",\n\t}\n\terr := p.Init()\n\trequire.NoError(t, err)\n\n\trequire.NotNil(t, p.podLabelSelector)\n\trequire.NotNil(t, p.podFieldSelector)\n}\n\nfunc TestPrometheusInternalOk(t *testing.T) {\n\tprommetric := `# HELP test_counter A sample test counter.\n# TYPE test_counter counter\ntest_counter{label=\"test\"} 1 1685443805885`\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, prommetric); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                  testutil.Logger{},\n\t\tKubernetesServices:   []string{ts.URL},\n\t\tEnableRequestMetrics: true,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\ttsAddress := u.Hostname()\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"prometheus_request\",\n\t\t\tmap[string]string{\n\t\t\t\t\"address\": tsAddress},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"content_length\": int64(1),\n\t\t\t\t\"response_time\":  float64(0)},\n\t\t\ttime.UnixMilli(0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\ttestutil.PrintMetrics(acc.GetTelegrafMetrics())\n\n\trequire.NoError(t, acc.GatherError(p.Gather))\n\ttestutil.RequireMetricsSubset(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreFields(\"content_length\", \"response_time\"), testutil.IgnoreTime())\n}\n\nfunc TestPrometheusInternalContentBadFormat(t *testing.T) {\n\tprommetric := `# HELP test_counter A sample test counter.\n# TYPE test_counter counter\n<body>Flag test</body>`\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, prommetric); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                  testutil.Logger{},\n\t\tKubernetesServices:   []string{ts.URL},\n\t\tEnableRequestMetrics: true,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\ttsAddress := u.Hostname()\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"prometheus_request\",\n\t\t\tmap[string]string{\n\t\t\t\t\"address\": tsAddress},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"content_length\": int64(94),\n\t\t\t\t\"response_time\":  float64(0)},\n\t\t\ttime.UnixMilli(0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.Error(t, acc.GatherError(p.Gather))\n\ttestutil.RequireMetricsSubset(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreFields(\"content_length\", \"response_time\"), testutil.IgnoreTime())\n}\n\nfunc TestPrometheusInternalNoWeb(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(404)\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                  testutil.Logger{},\n\t\tKubernetesServices:   []string{ts.URL},\n\t\tEnableRequestMetrics: true,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\ttsAddress := u.Hostname()\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"prometheus_request\",\n\t\t\tmap[string]string{\n\t\t\t\t\"address\": tsAddress},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"content_length\": int64(94),\n\t\t\t\t\"response_time\":  float64(0)},\n\t\t\ttime.UnixMilli(0),\n\t\t\ttelegraf.Untyped,\n\t\t),\n\t}\n\n\tvar acc testutil.Accumulator\n\ttestutil.PrintMetrics(acc.GetTelegrafMetrics())\n\n\trequire.Error(t, acc.GatherError(p.Gather))\n\ttestutil.RequireMetricsSubset(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreFields(\"content_length\", \"response_time\"), testutil.IgnoreTime())\n}\n\nfunc TestOpenmetricsText(t *testing.T) {\n\tconst data = `\n# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.\n# TYPE go_memstats_gc_cpu_fraction gauge\ngo_memstats_gc_cpu_fraction -0.00014404354379774563\n# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.\n# TYPE go_memstats_gc_sys_bytes gauge\ngo_memstats_gc_sys_bytes 6.0936192e+07\n# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.\n# TYPE go_memstats_heap_alloc_bytes gauge\ngo_memstats_heap_alloc_bytes 1.581062048e+09\n# EOF\n`\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Content-Type\", \"application/openmetrics-text;version=1.0.0\")\n\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:           &testutil.Logger{},\n\t\tURLs:          []string{ts.URL},\n\t\tURLTag:        \"\",\n\t\tMetricVersion: 2,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_cpu_fraction\": float64(-0.00014404354379774563)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_sys_bytes\": 6.0936192e+07},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_heap_alloc_bytes\": 1.581062048e+09},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestOpenmetricsProtobuf(t *testing.T) {\n\tdata, err := os.ReadFile(filepath.Join(\"testdata\", \"openmetric-proto.bin\"))\n\trequire.NoError(t, err)\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Content-Type\", \"application/openmetrics-protobuf;version=1.0.0\")\n\t\tif _, err := w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:           &testutil.Logger{},\n\t\tURLs:          []string{ts.URL},\n\t\tURLTag:        \"\",\n\t\tMetricVersion: 2,\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_cpu_fraction\": float64(-0.00014404354379774563)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_sys_bytes\": 6.0936192e+07},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_heap_alloc_bytes\": 1.581062048e+09},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestContentTypeOverride(t *testing.T) {\n\tconst data = `\n# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.\n# TYPE go_memstats_gc_cpu_fraction gauge\ngo_memstats_gc_cpu_fraction -0.00014404354379774563\n# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.\n# TYPE go_memstats_gc_sys_bytes gauge\ngo_memstats_gc_sys_bytes 6.0936192e+07\n# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.\n# TYPE go_memstats_heap_alloc_bytes gauge\ngo_memstats_heap_alloc_bytes 1.581062048e+09\n# EOF\n`\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t// Provide a wrong version\n\t\tw.Header().Add(\"Content-Type\", \"application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited\")\n\t\tif _, err := w.Write([]byte(data)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tp := &Prometheus{\n\t\tLog:                 &testutil.Logger{},\n\t\tURLs:                []string{ts.URL},\n\t\tURLTag:              \"\",\n\t\tMetricVersion:       2,\n\t\tContentTypeOverride: \"openmetrics-text\",\n\t}\n\trequire.NoError(t, p.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, p.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_cpu_fraction\": float64(-0.00014404354379774563)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_gc_sys_bytes\": 6.0936192e+07},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"openmetric\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"go_memstats_heap_alloc_bytes\": 1.581062048e+09},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n"
  },
  {
    "path": "plugins/inputs/prometheus/sample.conf",
    "content": "# Read metrics from one or many prometheus clients\n[[inputs.prometheus]]\n  ## An array of urls to scrape metrics from.\n  urls = [\"http://localhost:9100/metrics\"]\n\n  ## Metric version controls the mapping from Prometheus metrics into Telegraf metrics.\n  ## See \"Metric Format Configuration\" in plugins/inputs/prometheus/README.md for details.\n  ## Valid options: 1, 2\n  # metric_version = 1\n\n  ## Url tag name (tag containing scrapped url. optional, default is \"url\")\n  # url_tag = \"url\"\n\n  ## Whether the timestamp of the scraped metrics will be ignored.\n  ## If set to true, the gather time will be used.\n  # ignore_timestamp = false\n\n  ## Override content-type of the returned message\n  ## Available options are for prometheus:\n  ##   text, protobuf-delimiter, protobuf-compact, protobuf-text,\n  ## and for openmetrics:\n  ##   openmetrics-text, openmetrics-protobuf\n  ## By default the content-type of the response is used.\n  # content_type_override = \"\"\n\n  ## An array of Kubernetes services to scrape metrics from.\n  # kubernetes_services = [\"http://my-service-dns.my-namespace:9100/metrics\"]\n\n  ## Kubernetes config file to create client from.\n  # kube_config = \"/path/to/kubernetes.config\"\n\n  ## Scrape Pods\n  ## Enable scraping of k8s pods. Further settings as to which pods to scape\n  ## are determiend by the 'method' option below. When enabled, the default is\n  ## to use annotations to determine whether to scrape or not.\n  # monitor_kubernetes_pods = false\n\n  ## Scrape Pods Method\n  ## annotations: default, looks for specific pod annotations documented below\n  ## settings: only look for pods matching the settings provided, not\n  ##   annotations\n  ## settings+annotations: looks at pods that match annotations using the user\n  ##   defined settings\n  # monitor_kubernetes_pods_method = \"annotations\"\n\n  ## Scrape Pods 'annotations' method options\n  ## If set method is set to 'annotations' or 'settings+annotations', these\n  ## annotation flags are looked for:\n  ## - prometheus.io/scrape: Required to enable scraping for this pod. Can also\n  ##     use 'prometheus.io/scrape=false' annotation to opt-out entirely.\n  ## - prometheus.io/scheme: If the metrics endpoint is secured then you will\n  ##     need to set this to 'https' & most likely set the tls config\n  ## - prometheus.io/path: If the metrics path is not /metrics, define it with\n  ##     this annotation\n  ## - prometheus.io/port: If port is not 9102 use this annotation\n\n  ## Scrape Pods 'settings' method options\n  ## When using 'settings' or 'settings+annotations', the default values for\n  ## annotations can be modified using with the following options:\n  # monitor_kubernetes_pods_scheme = \"http\"\n  # monitor_kubernetes_pods_port = \"9102\"\n  # monitor_kubernetes_pods_path = \"/metrics\"\n\n  ## Get the list of pods to scrape with either the scope of\n  ## - cluster: the kubernetes watch api (default, no need to specify)\n  ## - node: the local cadvisor api; for scalability. Note that the config node_ip or the environment variable NODE_IP must be set to the host IP.\n  # pod_scrape_scope = \"cluster\"\n\n  ## Only for node scrape scope: node IP of the node that telegraf is running on.\n  ## Either this config or the environment variable NODE_IP must be set.\n  # node_ip = \"10.180.1.1\"\n\n  ## Only for node scrape scope: interval in seconds for how often to get updated pod list for scraping.\n  ## Default is 60 seconds.\n  # pod_scrape_interval = 60\n\n  ## Content length limit\n  ## When set, telegraf will drop responses with length larger than the configured value.\n  ## Default is \"0KB\" which means unlimited.\n  # content_length_limit = \"0KB\"\n\n  ## Restricts Kubernetes monitoring to a single namespace\n  ##   ex: monitor_kubernetes_pods_namespace = \"default\"\n  # monitor_kubernetes_pods_namespace = \"\"\n  ## The name of the label for the pod that is being scraped.\n  ## Default is 'namespace' but this can conflict with metrics that have the label 'namespace'\n  # pod_namespace_label_name = \"namespace\"\n  # label selector to target pods which have the label\n  # kubernetes_label_selector = \"env=dev,app=nginx\"\n  # field selector to target pods\n  # eg. To scrape pods on a specific node\n  # kubernetes_field_selector = \"spec.nodeName=$HOSTNAME\"\n\n  ## Filter which pod annotations and labels will be added to metric tags\n  #\n  # pod_annotation_include = [\"annotation-key-1\"]\n  # pod_annotation_exclude = [\"exclude-me\"]\n  # pod_label_include = [\"label-key-1\"]\n  # pod_label_exclude = [\"exclude-me\"]\n\n  # cache refresh interval to set the interval for re-sync of pods list.\n  # Default is 60 minutes.\n  # cache_refresh_interval = 60\n\n  ## Use bearer token for authorization. ('bearer_token' takes priority)\n  # bearer_token = \"/path/to/bearer/token\"\n  ## OR\n  # bearer_token_string = \"abc_123\"\n\n  ## HTTP Basic Authentication username and password. ('bearer_token' and\n  ## 'bearer_token_string' take priority)\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional custom HTTP headers\n  # http_headers = {\"X-Special-Header\" = \"Special-Value\"}\n\n  ## Specify timeout duration for slower prometheus clients (default is 5s)\n  # timeout = \"5s\"\n\n  ## This option is now used by the HTTP client to set the header response\n  ## timeout, not the overall HTTP timeout.\n  # response_timeout = \"5s\"\n\n  ## HTTP Proxy support\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS Config\n  # tls_ca = /path/to/cafile\n  # tls_cert = /path/to/certfile\n  # tls_key = /path/to/keyfile\n\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Use the given name as the SNI server name on each URL\n  # tls_server_name = \"myhost.example.org\"\n\n  ## TLS renegotiation method, choose from \"never\", \"once\", \"freely\"\n  # tls_renegotiation_method = \"never\"\n\n  ## Enable/disable TLS\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable = true\n\n  ## This option allows you to report the status of prometheus requests.\n  # enable_request_metrics = false\n\n  ## Scrape Services available in Consul Catalog\n  # [inputs.prometheus.consul]\n  #   enabled = true\n  #   agent = \"http://localhost:8500\"\n  #   query_interval = \"5m\"\n\n  #   [[inputs.prometheus.consul.query]]\n  #     name = \"a service name\"\n  #     tag = \"a service tag\"\n  #     url = 'http://{{if ne .ServiceAddress \"\"}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}'\n  #     [inputs.prometheus.consul.query.tags]\n  #       host = \"{{.Node}}\"\n\n  ## Scrape Hosts available with http service discovery\n  # [inputs.prometheus.http_service_discovery]\n  #   enabled = false\n  #   url = \"http://localhost:9000/service-discovery\"\n  #   query_interval = \"5m\"\n\n  ## Control pod scraping based on pod namespace annotations\n  ## Pass and drop here act like tagpass and tagdrop, but instead\n  ## of filtering metrics they filters pod candidates for scraping\n  #[inputs.prometheus.namespace_annotation_pass]\n  # annotation_key = [\"value1\", \"value2\"]\n  #[inputs.prometheus.namespace_annotation_drop]\n  # some_annotation_key = [\"dont-scrape\"]\n"
  },
  {
    "path": "plugins/inputs/prometheus/testcases/service_discovery/http-services.json",
    "content": "[\n  {\n    \"targets\": [\"10.0.10.2:9100\", \"10.0.10.3:9100\", \"10.0.10.4:9100\", \"10.0.10.5:9100\"],\n    \"labels\": {\n      \"__meta_datacenter\": \"london\",\n      \"__meta_prometheus_job\": \"node\"\n    }\n  },\n  {\n    \"targets\": [\"10.0.40.2:9100\", \"10.0.40.3:9100\"],\n    \"labels\": {\n      \"__meta_datacenter\": \"london\",\n      \"__meta_prometheus_job\": \"alertmanager\"\n    }\n  },\n  {\n    \"targets\": [\"10.0.40.2:9093\", \"10.0.40.3:9093\"],\n    \"labels\": {\n      \"__meta_datacenter\": \"newyork\",\n      \"__meta_prometheus_job\": \"alertmanager\"\n    }\n  }\n]"
  },
  {
    "path": "plugins/inputs/prometheus/testcases/service_discovery/telegraf.conf",
    "content": "[[inputs.prometheus]]\n  [inputs.prometheus.http_service_discovery]\n     enabled = true\n     url = \"dummy\""
  },
  {
    "path": "plugins/inputs/promql/README.md",
    "content": "# PromQL Input Plugin\n\nThis plugin gathers metrics from a [Prometheus][prometheus] endpoint using\n[PromQL queries][promql] via the [HTTP API][http_api].\n\n⭐ Telegraf v1.37.0\n🏷️ datastore\n💻 all\n\n[prometheus]: https://prometheus.io/\n[promql]: https://prometheus.io/docs/prometheus/latest/querying/basics/\n[http_api]: https://prometheus.io/docs/prometheus/latest/querying/api/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username`, `password`\nand `token` option. See the [secret-store documentation][SECRETSTORE] for\nmore details on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Query prometheus endpoints using PromQL\n[[inputs.promql]]\n  ## URL of the prometheus endpoint\n  url = \"http://localhost:9090\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.promql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total'\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.promql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total{job=\"prometheus\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   step = \"1m\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n```\n\n> [!NOTE]\n> You can either use no authentication _or_ basic authentication _or_ Bearer\n> token based authentication. Uncommenting both basic and Bearer token based\n> authentication will fail.\n\n## Metrics\n\nThe metrics collected by this input plugin will depend on the specified queries.\nHowever, the resulting metrics will have the following structure for the\nreturned results.\n\n### Scalar and String Results\n\nA scalar or string result will produce single metrics named after the value of\nthe Prometheus `__name__` label. Other labels will be kept as tags. The\nresulting metric uses the Prometheus timestamp and will have the value stored in\na `value` field.\n\n### Vector and Matrix Results\n\nA vector result will produce one or more metrics with the metric named after the\nvalue of the Prometheus `__name__` label for each element of the vector. Other\nlabels will be kept as tags. All metrics will use the Prometheus timestamp.\n\nNon-histogram results will have the value stored in a `value` field. Histogram\nresults will contain multiple fields with the field name being the upper bound\nof the bin and a value with the bin count. Additionally, the metric will have a\n`count` and a `sum` field.\n\n## Example Output\n\nFor example, a range-query for\n`prometheus_http_requests_total{job=\"prometheus\", handler=\"/api/v1/query\"}`\nstarting 5 minutes in the past with 1 minute stepping returns\n\n```text\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806201000000000\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806261000000000\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806321000000000\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806381000000000\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806441000000000\nprometheus_http_requests_total,app=prometheus,code=200,handler=/api/v1/query,instance=localhost:9090,job=prometheus value=28 1758806501000000000\n```\n"
  },
  {
    "path": "plugins/inputs/promql/client.go",
    "content": "package promql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/prometheus/client_golang/api\"\n\tapiv1 \"github.com/prometheus/client_golang/api/prometheus/v1\"\n\tpromcfg \"github.com/prometheus/common/config\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n)\n\ntype client struct {\n\turl      string\n\tusername config.Secret\n\tpassword config.Secret\n\ttoken    config.Secret\n\tcfg      common_http.TransportConfig\n\n\tclient api.Client\n\tapiv1.API\n}\n\nfunc (c *client) init() (*client, error) {\n\t// Create a round-tripper suitable for the given configuration based on the\n\t// http-client transport...\n\ttransport, err := c.cfg.CreateTransport()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating transport failed: %w\", err)\n\t}\n\trt := promcfg.NewUserAgentRoundTripper(internal.ProductToken(), transport)\n\tif !c.username.Empty() {\n\t\trt = promcfg.NewBasicAuthRoundTripper(\n\t\t\t&secretReader{\"username\", &c.username},\n\t\t\t&secretReader{\"password\", &c.password},\n\t\t\trt,\n\t\t)\n\t} else if !c.token.Empty() {\n\t\trt = promcfg.NewAuthorizationCredentialsRoundTripper(\n\t\t\t\"Bearer\",\n\t\t\t&secretReader{\"token\", &c.token},\n\t\t\trt,\n\t\t)\n\t}\n\n\t// Create API client\n\tapiClient, err := api.NewClient(api.Config{\n\t\tAddress:      c.url,\n\t\tRoundTripper: rt,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating API client failed: %w\", err)\n\t}\n\tc.client = apiClient\n\tc.API = apiv1.NewAPI(c.client)\n\n\treturn c, nil\n}\n\nfunc (c *client) close() {\n\tif c.client != nil {\n\t\tif c, ok := c.client.(api.CloseIdler); ok {\n\t\t\tc.CloseIdleConnections()\n\t\t}\n\t}\n}\n\n// Wrapper for reading secrets from Prometheus API client\ntype secretReader struct {\n\tdesc   string\n\tsecret *config.Secret\n}\n\n// Fetch implements the Prometheus secret-reader API\nfunc (r *secretReader) Fetch(context.Context) (string, error) {\n\traw, err := r.secret.Get()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting %s failed: %w\", r.desc, err)\n\t}\n\ts := raw.String()\n\traw.Destroy()\n\n\treturn s, nil\n}\n\n// Description implements the Prometheus secret-reader API\nfunc (r *secretReader) Description() string {\n\treturn r.desc\n}\n\n// Immutable implements the Prometheus secret-reader API\nfunc (*secretReader) Immutable() bool {\n\treturn true\n}\n"
  },
  {
    "path": "plugins/inputs/promql/promql.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage promql\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\tapiv1 \"github.com/prometheus/client_golang/api/prometheus/v1\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\tcommon_http \"github.com/influxdata/telegraf/plugins/common/http\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype PromQL struct {\n\tURL            string          `toml:\"url\"`\n\tUsername       config.Secret   `toml:\"username\"`\n\tPassword       config.Secret   `toml:\"password\"`\n\tToken          config.Secret   `toml:\"token\"`\n\tTimeout        config.Duration `toml:\"timeout\"`\n\tInstantQueries []InstantQuery  `toml:\"instant\"`\n\tRangeQueries   []RangeQuery    `toml:\"range\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\tcommon_http.TransportConfig\n\n\tclient *client\n}\n\nfunc (*PromQL) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (p *PromQL) Init() error {\n\t// Check settings\n\tif p.URL == \"\" {\n\t\treturn errors.New(\"'url' cannot be empty\")\n\t}\n\n\tif p.Username.Empty() && !p.Password.Empty() {\n\t\treturn errors.New(\"expecting username for basic authentication\")\n\t}\n\n\tif !p.Username.Empty() && !p.Token.Empty() {\n\t\treturn errors.New(\"cannot use both basic and bearer authentication\")\n\t}\n\n\tif len(p.InstantQueries)+len(p.RangeQueries) == 0 {\n\t\treturn errors.New(\"no queries configured\")\n\t}\n\n\t// Setup the API client\n\tp.client = &client{\n\t\turl:      p.URL,\n\t\tusername: p.Username,\n\t\tpassword: p.Password,\n\t\ttoken:    p.Token,\n\t\tcfg:      p.TransportConfig,\n\t}\n\n\tvar opts []apiv1.Option\n\tif p.Timeout > 0 {\n\t\topts = append(opts, apiv1.WithTimeout(time.Duration(p.Timeout)))\n\t}\n\n\t// Setup queries\n\tfor i := range p.InstantQueries {\n\t\tif err := p.InstantQueries[i].init(p.client, p.Log, opts...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := range p.RangeQueries {\n\t\tif err := p.RangeQueries[i].init(p.client, p.Log, opts...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *PromQL) Start(telegraf.Accumulator) error {\n\t// Initialize the API client\n\tc, err := p.client.init()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"initializing API client failed: %w\", err)\n\t}\n\tp.client = c\n\n\treturn nil\n}\n\nfunc (p *PromQL) Stop() {\n\tif p.client != nil {\n\t\tp.client.close()\n\t}\n}\n\nfunc (p *PromQL) Gather(acc telegraf.Accumulator) error {\n\tctx := context.Background()\n\tif p.Timeout > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, time.Duration(p.Timeout))\n\t\tdefer cancel()\n\t}\n\n\tt := time.Now()\n\n\t// Do the queries\n\tfor _, q := range p.InstantQueries {\n\t\tacc.AddError(q.execute(ctx, acc, t))\n\t}\n\tfor _, q := range p.RangeQueries {\n\t\tacc.AddError(q.execute(ctx, acc, t))\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"promql\", func() telegraf.Input {\n\t\treturn &PromQL{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/promql/promql_test.go",
    "content": "package promql\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/prometheus/common/model\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/serializers/prometheusremotewrite\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestInitSuccess(t *testing.T) {\n\tusername := config.NewSecret([]byte(\"john\"))\n\tpassword := config.NewSecret([]byte(\"secret\"))\n\ttoken := config.NewSecret([]byte(\"a token\"))\n\tdefer username.Destroy()\n\tdefer password.Destroy()\n\tdefer token.Destroy()\n\n\ttests := []struct {\n\t\tname   string\n\t\tplugin *PromQL\n\t}{\n\t\t{\n\t\t\tname: \"no authentication\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic auth without password\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tUsername:       username,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic auth with password\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tUsername:       username,\n\t\t\t\tPassword:       password,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"token auth\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tToken:          token,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, tt.plugin.Init())\n\t\t})\n\t}\n}\n\nfunc TestInitFail(t *testing.T) {\n\tusername := config.NewSecret([]byte(\"john\"))\n\tpassword := config.NewSecret([]byte(\"secret\"))\n\ttoken := config.NewSecret([]byte(\"a token\"))\n\tdefer username.Destroy()\n\tdefer password.Destroy()\n\tdefer token.Destroy()\n\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *PromQL\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"all empty\",\n\t\t\tplugin:   &PromQL{},\n\t\t\texpected: \"'url' cannot be empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"no queries\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL: \"http://localhost:9090\",\n\t\t\t},\n\t\t\texpected: \"no queries configured\",\n\t\t},\n\t\t{\n\t\t\tname: \"password without username\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tPassword:       password,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t\texpected: \"expecting username for basic authentication\",\n\t\t},\n\t\t{\n\t\t\tname: \"basic and token auth\",\n\t\t\tplugin: &PromQL{\n\t\t\t\tURL:            \"http://localhost:9090\",\n\t\t\t\tUsername:       username,\n\t\t\t\tToken:          token,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"prometheus_http_requests_total\"}}},\n\t\t\t},\n\t\t\texpected: \"cannot use both basic and bearer authentication\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.plugin.Log = testutil.Logger{}\n\t\t\trequire.ErrorContains(t, tt.plugin.Init(), tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestInstantQueries(t *testing.T) {\n\tts := int64(1758808909)\n\n\ttests := []struct {\n\t\tname     string\n\t\tdata     model.Value\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"scalar\",\n\t\t\tdata: &model.Scalar{\n\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t/*\n\t\t\t * NOT SUPPORTED by the Prometheus Go library yet\n\t\t\t * see https://github.com/prometheus/common/issues/423\n\t\t\t{\n\t\t\t\tname: \"string\",\n\t\t\t\tdata: &model.String{\n\t\t\t\t\tValue:     \"foobar\",\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\texpected: []telegraf.Metric{\n\t\t\t\t\tmetric.New(\n\t\t\t\t\t\t\"promql\",\n\t\t\t\t\t\tmap[string]string{},\n\t\t\t\t\t\tmap[string]interface{}{\"value\": \"foobar\"},\n\t\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t},\n\t\t*/\n\t\t{\n\t\t\tname: \"vector sample\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector multiple samples\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"staging\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(23.0),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"production\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(42.42),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"staging\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(23.0)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"production\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(42.42)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector histogram\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t/*\n\t\t * Mixed vector responses with both sample value AND histograms are not\n\t\t * possible according to https://prometheus.io/docs/prometheus/latest/querying/api/#instant-vectors\n\t\t */\n\t\t{\n\t\t\tname: \"matrix samples\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix multiple streams\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"staging\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"production\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"staging\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"production\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix histograms\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix mixed within stream\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"sampling\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix mixed streams\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"sampling\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"result without name property\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"job\": \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Construct the response\n\t\t\tresponse := map[string]interface{}{\n\t\t\t\t\"status\": \"success\",\n\t\t\t\t\"data\": map[string]interface{}{\n\t\t\t\t\t\"resultType\": tt.data.Type().String(),\n\t\t\t\t\t\"result\":     tt.data,\n\t\t\t\t},\n\t\t\t}\n\t\t\tbuf, err := json.Marshal(response)\n\t\t\trequire.NoError(t, err, \"marshalling response\")\n\n\t\t\t// Setup the mocked Prometheus endpoint\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Check the expected request properties\n\t\t\t\tif r.Method != http.MethodPost {\n\t\t\t\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\t\t\tt.Errorf(\"Unexpected method %q\", r.Method)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"User-Agent\"); h != internal.ProductToken() {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Unexpected user agent %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"Content-Type\"); h != \"application/x-www-form-urlencoded\" {\n\t\t\t\t\tw.WriteHeader(http.StatusUnsupportedMediaType)\n\t\t\t\t\tt.Errorf(\"Unexpected content type %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Only support queries\n\t\t\t\tif r.URL.Path != \"/api/v1/query\" {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Construct the response and write it\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Writing response failed: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Setup the plugin and start it\n\t\t\tplugin := &PromQL{\n\t\t\t\tURL:            server.URL,\n\t\t\t\tInstantQueries: []InstantQuery{{query: query{Query: \"dummy\"}}},\n\t\t\t\tTimeout:        config.Duration(1 * time.Second),\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(nil))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Call gather and check for errors and metrics\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond)\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc TestRangeQueries(t *testing.T) {\n\tts := int64(1758808909)\n\n\ttests := []struct {\n\t\tname     string\n\t\tdata     model.Value\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"scalar\",\n\t\t\tdata: &model.Scalar{\n\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t/*\n\t\t\t * NOT SUPPORTED by the Prometheus Go library yet\n\t\t\t * see https://github.com/prometheus/common/issues/423\n\t\t\t{\n\t\t\t\tname: \"string\",\n\t\t\t\tdata: &model.String{\n\t\t\t\t\tValue:     \"foobar\",\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\texpected: []telegraf.Metric{\n\t\t\t\t\tmetric.New(\n\t\t\t\t\t\t\"promql\",\n\t\t\t\t\t\tmap[string]string{},\n\t\t\t\t\t\tmap[string]interface{}{\"value\": \"foobar\"},\n\t\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t},\n\t\t*/\n\t\t{\n\t\t\tname: \"vector sample\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector multiple samples\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"staging\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(23.0),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"production\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(42.42),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"staging\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(23.0)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"production\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(42.42)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector histogram\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t/*\n\t\t * Mixed vector responses with both sample value AND histograms are not\n\t\t * possible according to https://prometheus.io/docs/prometheus/latest/querying/api/#instant-vectors\n\t\t */\n\t\t{\n\t\t\tname: \"matrix samples\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix multiple streams\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"staging\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"production\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"staging\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"production\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix histograms\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix mixed within stream\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"sampling\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix mixed streams\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"sampling\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tHistograms: []model.SampleHistogramPair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      10.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      20.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      30.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      40.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      100.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 5,\n\t\t\t\t\t\t\t\tSum:   100.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      2.0,\n\t\t\t\t\t\t\t\t\t\tCount:      110.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      2.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      4.0,\n\t\t\t\t\t\t\t\t\t\tCount:      120.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      4.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      6.0,\n\t\t\t\t\t\t\t\t\t\tCount:      130.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      6.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      8.0,\n\t\t\t\t\t\t\t\t\t\tCount:      140.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      8.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      190.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t\tHistogram: &model.SampleHistogram{\n\t\t\t\t\t\t\t\tCount: 4,\n\t\t\t\t\t\t\t\tSum:   10.0,\n\t\t\t\t\t\t\t\tBuckets: model.HistogramBuckets{\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      0.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      5.0,\n\t\t\t\t\t\t\t\t\t\tCount:      210.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      5.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      10.0,\n\t\t\t\t\t\t\t\t\t\tCount:      220.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      10.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      15.0,\n\t\t\t\t\t\t\t\t\t\tCount:      230.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&model.HistogramBucket{\n\t\t\t\t\t\t\t\t\t\tBoundaries: 2,\n\t\t\t\t\t\t\t\t\t\tLower:      15.0,\n\t\t\t\t\t\t\t\t\t\tUpper:      20.0,\n\t\t\t\t\t\t\t\t\t\tCount:      240.0,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"sampling\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(10),\n\t\t\t\t\t\t\"4\":  float64(20),\n\t\t\t\t\t\t\"6\":  float64(30),\n\t\t\t\t\t\t\"8\":  float64(40),\n\t\t\t\t\t\t\"10\": float64(100),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"2\":  float64(110),\n\t\t\t\t\t\t\"4\":  float64(120),\n\t\t\t\t\t\t\"6\":  float64(130),\n\t\t\t\t\t\t\"8\":  float64(140),\n\t\t\t\t\t\t\"10\": float64(190),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"5\":  float64(210),\n\t\t\t\t\t\t\"10\": float64(220),\n\t\t\t\t\t\t\"15\": float64(230),\n\t\t\t\t\t\t\"20\": float64(240),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Histogram,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Construct the response\n\t\t\tresponse := map[string]interface{}{\n\t\t\t\t\"status\": \"success\",\n\t\t\t\t\"data\": map[string]interface{}{\n\t\t\t\t\t\"resultType\": tt.data.Type().String(),\n\t\t\t\t\t\"result\":     tt.data,\n\t\t\t\t},\n\t\t\t}\n\t\t\tbuf, err := json.Marshal(response)\n\t\t\trequire.NoError(t, err, \"marshalling response\")\n\n\t\t\t// Setup the mocked Prometheus endpoint\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Check the expected request properties\n\t\t\t\tif r.Method != http.MethodPost {\n\t\t\t\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\t\t\tt.Errorf(\"Unexpected method %q\", r.Method)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"User-Agent\"); h != internal.ProductToken() {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Unexpected user agent %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"Content-Type\"); h != \"application/x-www-form-urlencoded\" {\n\t\t\t\t\tw.WriteHeader(http.StatusUnsupportedMediaType)\n\t\t\t\t\tt.Errorf(\"Unexpected content type %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Only support queries\n\t\t\t\tif r.URL.Path != \"/api/v1/query_range\" {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Check the submitted parameters\n\t\t\t\tbody, err := io.ReadAll(r.Body)\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Reading request body failed: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tparams := make(map[string]time.Time, 2)\n\t\t\t\tfor _, e := range strings.Split(string(body), \"&\") {\n\t\t\t\t\tkey, value, found := strings.Cut(e, \"=\")\n\t\t\t\t\tif !found {\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Errorf(\"Malformed parameter %q\", e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tswitch key {\n\t\t\t\t\tcase \"start\", \"end\":\n\t\t\t\t\t\tx, err := strconv.ParseFloat(value, 64)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\t\tt.Errorf(\"Parsing %q failed: %v\", e, err)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tparams[key] = time.Unix(0, int64(x*1e9))\n\t\t\t\t\tcase \"step\":\n\t\t\t\t\t\tif value != \"60\" {\n\t\t\t\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\t\t\t\tt.Errorf(\"Invalid stepping %q\", value)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\tcase \"query\":\n\t\t\t\t\t\tif value != \"dummy\" {\n\t\t\t\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\t\t\t\tt.Errorf(\"Invalid query %q\", value)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\tcase \"timeout\":\n\t\t\t\t\t\tif value != \"1s\" {\n\t\t\t\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\t\t\t\tt.Errorf(\"Invalid timeout %q\", value)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\t\tt.Errorf(\"Invalid  paramter %q\", e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif diff := params[\"end\"].Sub(params[\"start\"]); diff != 5*time.Minute {\n\t\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\t\tt.Errorf(\"Invalid time range %v -> %v\", params, diff)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Construct the response and write it\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Writing response failed: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Setup the plugin and start it\n\t\t\tplugin := &PromQL{\n\t\t\t\tURL: server.URL,\n\t\t\t\tRangeQueries: []RangeQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tquery: query{Query: \"dummy\"},\n\t\t\t\t\t\tStart: config.Duration(6 * time.Minute),\n\t\t\t\t\t\tEnd:   config.Duration(1 * time.Minute),\n\t\t\t\t\t\tStep:  config.Duration(1 * time.Minute),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTimeout: config.Duration(1 * time.Second),\n\t\t\t\tLog:     testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(nil))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Call gather and check for errors and metrics\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond)\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc TestMetricNameOverride(t *testing.T) {\n\tts := int64(1758808909)\n\n\ttests := []struct {\n\t\tname      string\n\t\tqueryName string\n\t\tdata      model.Value\n\t\texpected  []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"scalar with default query name\",\n\t\t\tdata: &model.Scalar{\n\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"scalar with query name\",\n\t\t\tqueryName: \"foobar\",\n\t\t\tdata: &model.Scalar{\n\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"foobar\",\n\t\t\t\t\tmap[string]string{},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector with default query name and result name\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"vector with default query name and no result name\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"job\": \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"vector with query name and result name\",\n\t\t\tqueryName: \"foobar\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"vector_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"vector_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"vector with query name and no result name\",\n\t\t\tqueryName: \"foobar\",\n\t\t\tdata: &model.Vector{\n\t\t\t\t&model.Sample{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"job\": \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"foobar\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.14)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix with default query name and result name\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"matrix with default query name and no result name\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"job\": \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"promql\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"matrix with query name and result name\",\n\t\t\tqueryName: \"foobar\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"__name__\": model.LabelValue(\"matrix_metric\"),\n\t\t\t\t\t\t\"job\":      \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"matrix_metric\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"matrix with query name and no result name\",\n\t\t\tqueryName: \"foobar\",\n\t\t\tdata: &model.Matrix{\n\t\t\t\t&model.SampleStream{\n\t\t\t\t\tMetric: model.Metric{\n\t\t\t\t\t\t\"job\": \"testing\",\n\t\t\t\t\t},\n\t\t\t\t\tValues: []model.SamplePair{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(1.1),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(2.2),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(1 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tValue:     model.SampleValue(3.3),\n\t\t\t\t\t\t\tTimestamp: model.TimeFromUnix(ts).Add(2 * time.Second),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"foobar\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(1.1)},\n\t\t\t\t\ttime.Unix(ts, 0),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"foobar\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(2.2)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(1*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"foobar\",\n\t\t\t\t\tmap[string]string{\"job\": \"testing\"},\n\t\t\t\t\tmap[string]interface{}{\"value\": float64(3.3)},\n\t\t\t\t\ttime.Unix(ts, 0).Add(2*time.Second),\n\t\t\t\t\ttelegraf.Gauge,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Construct the response\n\t\t\tresponse := map[string]interface{}{\n\t\t\t\t\"status\": \"success\",\n\t\t\t\t\"data\": map[string]interface{}{\n\t\t\t\t\t\"resultType\": tt.data.Type().String(),\n\t\t\t\t\t\"result\":     tt.data,\n\t\t\t\t},\n\t\t\t}\n\t\t\tbuf, err := json.Marshal(response)\n\t\t\trequire.NoError(t, err, \"marshalling response\")\n\n\t\t\t// Setup the mocked Prometheus endpoint\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t// Check the expected request properties\n\t\t\t\tif r.Method != http.MethodPost {\n\t\t\t\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\t\t\tt.Errorf(\"Unexpected method %q\", r.Method)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"User-Agent\"); h != internal.ProductToken() {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Unexpected user agent %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif h := r.Header.Get(\"Content-Type\"); h != \"application/x-www-form-urlencoded\" {\n\t\t\t\t\tw.WriteHeader(http.StatusUnsupportedMediaType)\n\t\t\t\t\tt.Errorf(\"Unexpected content type %q\", h)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Only support queries\n\t\t\t\tif r.URL.Path != \"/api/v1/query\" {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Construct the response and write it\n\t\t\t\tif _, err := w.Write(buf); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Writing response failed: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer server.Close()\n\n\t\t\t// Setup the plugin and start it\n\t\t\tplugin := &PromQL{\n\t\t\t\tURL: server.URL,\n\t\t\t\tInstantQueries: []InstantQuery{\n\t\t\t\t\t{\n\t\t\t\t\t\tquery: query{\n\t\t\t\t\t\t\tQuery: \"dummy\",\n\t\t\t\t\t\t\tName:  tt.queryName,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTimeout: config.Duration(1 * time.Second),\n\t\t\t\tLog:     testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(nil))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Call gather and check for errors and metrics\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond)\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc TestWarnings(t *testing.T) {\n\t// Construct the response\n\tresponse := map[string]interface{}{\n\t\t\"status\": \"success\",\n\t\t\"data\": map[string]interface{}{\n\t\t\t\"resultType\": \"scalar\",\n\t\t\t\"result\": &model.Scalar{\n\t\t\t\tValue:     model.SampleValue(3.14),\n\t\t\t\tTimestamp: model.Now(),\n\t\t\t},\n\t\t},\n\t\t\"warnings\": []string{\n\t\t\t\"element A is not queryable\",\n\t\t\t\"node B cannot be scraped\",\n\t\t},\n\t}\n\tbuf, err := json.Marshal(response)\n\trequire.NoError(t, err, \"marshalling response\")\n\n\t// Setup the mocked Prometheus endpoint\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := w.Write(buf); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Writing response failed: %v\", err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer server.Close()\n\n\t// Setup the plugin and start it\n\tlogger := &testutil.CaptureLogger{Name: \"inputs.promql\"}\n\tplugin := &PromQL{\n\t\tURL:            server.URL,\n\t\tInstantQueries: []InstantQuery{{query: query{Query: \"dummy\"}}},\n\t\tTimeout:        config.Duration(1 * time.Second),\n\t\tLog:            logger,\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(nil))\n\tdefer plugin.Stop()\n\n\t// Define the expected warnings\n\texpected := []string{\n\t\t`W! [inputs.promql] query \"dummy\" produced warning: element A is not queryable`,\n\t\t`W! [inputs.promql] query \"dummy\" produced warning: node B cannot be scraped`,\n\t}\n\n\t// Call gather and check for errors and metrics\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= 1\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\trequire.Eventually(t, func() bool {\n\t\treturn len(logger.Warnings()) >= len(expected)\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\trequire.ElementsMatch(t, expected, logger.Warnings(), \"warnings do not match\")\n}\n\nfunc TestIntegrationInstant(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Setup container with prometheus server\n\tcontainer := testutil.Container{\n\t\tImage:        \"prom/prometheus\",\n\t\tExposedPorts: []string{\"9090\"},\n\t\tCmd: []string{\n\t\t\t\"--config.file=/etc/prometheus/prometheus.yml\",\n\t\t\t\"--storage.tsdb.path=/prometheus\",\n\t\t\t\"--web.enable-remote-write-receiver\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForMappedPort(nat.Port(\"9090\")),\n\t\t\twait.ForLog(\"Server is ready to receive web requests.\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := \"http://\" + container.Address + \":\" + container.Ports[\"9090\"]\n\n\t// Define the input and expected metrics structure\n\tts := time.Now()\n\tinput := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 1440},\n\t\t\tts.Add(-300*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 890},\n\t\t\tts.Add(-270*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 550},\n\t\t\tts.Add(-240*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 340},\n\t\t\tts.Add(-210*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 210},\n\t\t\tts.Add(-180*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 130},\n\t\t\tts.Add(-150*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 80},\n\t\t\tts.Add(-120*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 50},\n\t\t\tts.Add(-90*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 30},\n\t\t\tts.Add(-60*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 20},\n\t\t\tts.Add(-30*time.Second),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 10},\n\t\t\tts,\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 5},\n\t\t\tts.Add(-5*time.Minute),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 2},\n\t\t\tts.Add(-4*time.Minute),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 3},\n\t\t\tts.Add(-3*time.Minute),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 2},\n\t\t\tts.Add(-2*time.Minute),\n\t\t\ttelegraf.Counter,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests_total\": 1},\n\t\t\tts,\n\t\t\ttelegraf.Counter,\n\t\t),\n\t}\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test_http_requests_total\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(10)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests_total\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(1)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\t// Write the expected metrics to the Prometheus instance using remote-write\n\tw := newWriter(addr)\n\trequire.NoError(t, w.write(input))\n\n\t// Setup the plugin and start it\n\tplugin := &PromQL{\n\t\tURL: addr,\n\t\tInstantQueries: []InstantQuery{\n\t\t\t{\n\t\t\t\tquery: query{Query: `test_http_requests_total`},\n\t\t\t},\n\t\t},\n\t\tTimeout: config.Duration(5 * time.Second),\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\trequire.NoError(t, plugin.Start(nil))\n\tdefer plugin.Stop()\n\n\t// Collect the metrics\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Check the returned metric\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestIntegrationRange(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Setup container with prometheus server\n\tcontainer := testutil.Container{\n\t\tImage:        \"prom/prometheus\",\n\t\tExposedPorts: []string{\"9090\"},\n\t\tCmd: []string{\n\t\t\t\"--config.file=/etc/prometheus/prometheus.yml\",\n\t\t\t\"--storage.tsdb.path=/prometheus\",\n\t\t\t\"--web.enable-remote-write-receiver\",\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForMappedPort(nat.Port(\"9090\")),\n\t\t\twait.ForLog(\"Server is ready to receive web requests.\"),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := \"http://\" + container.Address + \":\" + container.Ports[\"9090\"]\n\n\t// Define the input and expected metrics structure\n\tts := time.Now()\n\tinput := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 1440},\n\t\t\tts.Add(-300*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 890},\n\t\t\tts.Add(-270*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 550},\n\t\t\tts.Add(-240*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 340},\n\t\t\tts.Add(-210*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 210},\n\t\t\tts.Add(-180*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 130},\n\t\t\tts.Add(-150*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 80},\n\t\t\tts.Add(-120*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 50},\n\t\t\tts.Add(-90*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 30},\n\t\t\tts.Add(-60*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 20},\n\t\t\tts.Add(-30*time.Second),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"requests\": 10},\n\t\t\tts,\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests\": 5},\n\t\t\tts.Add(-5*time.Minute),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests\": 2},\n\t\t\tts.Add(-4*time.Minute),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests\": 3},\n\t\t\tts.Add(-3*time.Minute),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests\": 2},\n\t\t\tts.Add(-2*time.Minute),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"requests\": 1},\n\t\t\tts,\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(10)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(30)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(80)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(210)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(550)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"localhost\"},\n\t\t\tmap[string]interface{}{\"value\": float64(1440)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(1)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(2)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(2)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(2)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(3)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test_http_requests\",\n\t\t\tmap[string]string{\"instance\": \"remote\"},\n\t\t\tmap[string]interface{}{\"value\": float64(5)},\n\t\t\ttime.Unix(0, 0),\n\t\t\ttelegraf.Gauge,\n\t\t),\n\t}\n\n\t// Write the expected metrics to the Prometheus instance using remote-write\n\tw := newWriter(addr)\n\tfor _, m := range input {\n\t\trequire.NoError(t, w.writeSingle(m))\n\t}\n\n\t// Setup the plugin and start it\n\tplugin := &PromQL{\n\t\tURL: addr,\n\t\tRangeQueries: []RangeQuery{\n\t\t\t{\n\t\t\t\tquery: query{Query: `test_http_requests`},\n\t\t\t\tStart: config.Duration(6 * time.Minute),\n\t\t\t\tStep:  config.Duration(1 * time.Minute),\n\t\t\t},\n\t\t},\n\t\tTimeout: config.Duration(5 * time.Second),\n\t\tLog:     testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\trequire.NoError(t, plugin.Start(nil))\n\tdefer plugin.Stop()\n\n\t// Collect the metrics\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.Empty(t, acc.Errors, \"found accumulated errors\")\n\n\trequire.Eventually(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\t// Check the returned metric\n\t// We have to ignore the timestamp as it will be relative to the query\n\t// timing.\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\n// Internal implementations\ntype writer struct {\n\taddr       string\n\tserializer *prometheusremotewrite.Serializer\n}\n\nfunc newWriter(addr string) *writer {\n\treturn &writer{\n\t\taddr:       strings.TrimRight(addr, \"/\") + \"/api/v1/write\",\n\t\tserializer: &prometheusremotewrite.Serializer{Log: testutil.Logger{Name: \"serializer\"}},\n\t}\n}\n\nfunc (w *writer) write(metrics []telegraf.Metric) error {\n\tbuf, err := w.serializer.SerializeBatch(metrics)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"serializing metrics failed: %w\", err)\n\t}\n\n\treturn w.send(buf)\n}\n\nfunc (w *writer) writeSingle(m telegraf.Metric) error {\n\tbuf, err := w.serializer.Serialize(m)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"serializing metrics failed: %w\", err)\n\t}\n\n\treturn w.send(buf)\n}\n\nfunc (w *writer) send(buf []byte) error {\n\t// Setup HTTP request with the required headers\n\treq, err := http.NewRequest(http.MethodPost, w.addr, bytes.NewBuffer(buf))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating request failed: %w\", err)\n\t}\n\n\treq.Header.Add(\"Content-Encoding\", \"snappy\")\n\treq.Header.Set(\"Content-Type\", \"application/x-protobuf\")\n\treq.Header.Set(\"User-Agent\", \"Telegraf test writer\")\n\treq.Header.Add(\"X-Prometheus-Remote-Write-Version\", \"0.1.0\")\n\n\t// Do the request\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"executing request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode < 200 || resp.StatusCode > 299 {\n\t\treturn fmt.Errorf(\"received status %s \", resp.Status)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/promql/query.go",
    "content": "package promql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\tapiv1 \"github.com/prometheus/client_golang/api/prometheus/v1\"\n\t\"github.com/prometheus/common/model\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n)\n\ntype query struct {\n\tName  string `toml:\"name\"`\n\tQuery string `toml:\"query\"`\n\tLimit uint64 `toml:\"limit\"`\n\n\tclient  *client\n\toptions []apiv1.Option\n\tlog     telegraf.Logger\n}\n\nfunc (q *query) init(c *client, log telegraf.Logger, options ...apiv1.Option) error {\n\tif q.Query == \"\" {\n\t\treturn fmt.Errorf(\"'query' cannot be empty for %q\", q.client.url)\n\t}\n\n\tq.client = c\n\tif q.Limit > 0 {\n\t\tq.options = append(options, apiv1.WithLimit(q.Limit))\n\t}\n\tq.log = log\n\n\treturn nil\n}\n\ntype InstantQuery struct {\n\tquery\n}\n\nfunc (q *InstantQuery) init(c *client, log telegraf.Logger, options ...apiv1.Option) error {\n\treturn q.query.init(c, log, options...)\n}\n\nfunc (q *InstantQuery) execute(ctx context.Context, acc telegraf.Accumulator, t time.Time) error {\n\tresults, warnings, err := q.client.Query(ctx, q.Query, t, q.options...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", q.client.url, err)\n\t}\n\tfor _, w := range warnings {\n\t\tq.log.Warnf(\"query %q produced warning: %s\", q.Query, w)\n\t}\n\n\treturn q.convertModelValue(acc, results)\n}\n\ntype RangeQuery struct {\n\tquery\n\tStart config.Duration `toml:\"start\"`\n\tEnd   config.Duration `toml:\"end\"`\n\tStep  config.Duration `toml:\"step\"`\n}\n\nfunc (q *RangeQuery) init(c *client, log telegraf.Logger, options ...apiv1.Option) error {\n\tif err := q.query.init(c, log, options...); err != nil {\n\t\treturn err\n\t}\n\n\tif q.Start >= 0 && q.Start <= q.End {\n\t\treturn fmt.Errorf(\"invalid range %v to %v for query %q\", q.Start, q.End, q.Query)\n\t}\n\tif q.Start < 0 && q.Start >= q.End {\n\t\treturn fmt.Errorf(\"invalid range %v to %v for query %q\", q.Start, q.End, q.Query)\n\t}\n\n\tif q.Step <= 0 {\n\t\treturn fmt.Errorf(\"'step' must be positive for query %q\", q.query.Query)\n\t}\n\treturn nil\n}\n\nfunc (q *RangeQuery) execute(ctx context.Context, acc telegraf.Accumulator, t time.Time) error {\n\tr := apiv1.Range{\n\t\tStart: t.Add(-time.Duration(q.Start)),\n\t\tEnd:   t.Add(-time.Duration(q.End)),\n\t\tStep:  time.Duration(q.Step),\n\t}\n\tresults, warnings, err := q.client.QueryRange(ctx, q.Query, r, q.options...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying %q failed: %w\", q.client.url, err)\n\t}\n\tfor _, w := range warnings {\n\t\tq.log.Warnf(\"query %q produced warning: %s\", q.Query, w)\n\t}\n\treturn q.convertModelValue(acc, results)\n}\n\nfunc (q *query) convertModelValue(acc telegraf.Accumulator, results model.Value) error {\n\t// Determine the default name\n\tname := \"promql\"\n\tif q.Name != \"\" {\n\t\tname = q.Name\n\t}\n\n\tswitch result := results.(type) {\n\tcase *model.Scalar:\n\t\ttags := make(map[string]string)\n\t\tfields := map[string]interface{}{\"value\": float64(result.Value)}\n\t\tacc.AddGauge(name, fields, tags, result.Timestamp.Time())\n\tcase *model.String:\n\t\ttags := make(map[string]string)\n\t\tfields := map[string]interface{}{\"value\": result.Value}\n\t\tacc.AddFields(name, fields, tags, result.Timestamp.Time())\n\tcase model.Vector:\n\t\tif result.Len() == 0 {\n\t\t\tq.log.Debugf(\"Query %q returned no result\", q.Query)\n\t\t\treturn nil\n\t\t}\n\t\tfor _, sample := range result {\n\t\t\ttags := make(map[string]string, len(sample.Metric))\n\t\t\tfor k, v := range sample.Metric {\n\t\t\t\tif k == \"__name__\" {\n\t\t\t\t\tname = string(v)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttags[string(k)] = string(v)\n\t\t\t}\n\t\t\tif sample.Histogram != nil {\n\t\t\t\thist := sample.Histogram\n\t\t\t\tfields := make(map[string]interface{}, 2+len(hist.Buckets))\n\t\t\t\tfields[\"count\"] = hist.Count\n\t\t\t\tfields[\"sum\"] = hist.Sum\n\t\t\t\tfor _, b := range hist.Buckets {\n\t\t\t\t\tfields[strconv.FormatFloat(float64(b.Upper), 'g', -1, 64)] = float64(b.Count)\n\t\t\t\t}\n\t\t\t\tacc.AddHistogram(name, fields, tags, sample.Timestamp.Time())\n\t\t\t} else {\n\t\t\t\tfields := map[string]interface{}{\"value\": float64(sample.Value)}\n\t\t\t\tacc.AddGauge(name, fields, tags, sample.Timestamp.Time())\n\t\t\t}\n\t\t}\n\tcase model.Matrix:\n\t\tif result.Len() == 0 {\n\t\t\tq.log.Debugf(\"Query %q returned no result\", q.Query)\n\t\t\treturn nil\n\t\t}\n\t\tfor _, stream := range result {\n\t\t\ttags := make(map[string]string, len(stream.Metric))\n\t\t\tfor k, v := range stream.Metric {\n\t\t\t\tif k == \"__name__\" {\n\t\t\t\t\tname = string(v)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttags[string(k)] = string(v)\n\t\t\t}\n\t\t\tfor _, v := range stream.Values {\n\t\t\t\tfields := map[string]interface{}{\"value\": float64(v.Value)}\n\t\t\t\tacc.AddGauge(name, fields, tags, v.Timestamp.Time())\n\t\t\t}\n\t\t\tfor _, h := range stream.Histograms {\n\t\t\t\thist := h.Histogram\n\t\t\t\tfields := make(map[string]interface{}, 2+len(hist.Buckets))\n\t\t\t\tfields[\"count\"] = hist.Count\n\t\t\t\tfields[\"sum\"] = hist.Sum\n\t\t\t\tfor _, b := range hist.Buckets {\n\t\t\t\t\tfields[strconv.FormatFloat(float64(b.Upper), 'g', -1, 64)] = float64(b.Count)\n\t\t\t\t}\n\t\t\t\tacc.AddHistogram(name, fields, tags, h.Timestamp.Time())\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown result type %T\", result)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/promql/sample.conf",
    "content": "# Query prometheus endpoints using PromQL\n[[inputs.promql]]\n  ## URL of the prometheus endpoint\n  url = \"http://localhost:9090\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n  ## HTTP connection settings\n  # idle_conn_timeout = \"0s\"\n  # max_idle_conn = 0\n  # max_idle_conn_per_host = 0\n  # response_timeout = \"0s\"\n\n  ## Use the local address for connecting, assigned by the OS by default\n  # local_address = \"\"\n\n  ## Optional proxy settings\n  # use_system_proxy = false\n  # http_proxy_url = \"\"\n\n  ## Optional TLS settings\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.promql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total'\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.promql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total{job=\"prometheus\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   step = \"1m\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n"
  },
  {
    "path": "plugins/inputs/promql/sample.conf.in",
    "content": "# Query prometheus endpoints using PromQL\n[[inputs.promql]]\n  ## URL of the prometheus endpoint\n  url = \"http://localhost:9090\"\n\n  ## Basic authentication properties\n  # username = \"\"\n  # password = \"\"\n\n  ## Bearer token based authentication\n  # token = \"\"\n\n  ## Timeout for executing queries with zero meaning no timeout\n  # timeout = \"5s\"\n\n{{template \"/plugins/common/http/transport.conf\"}}\n\n  ## Instant queries, multiple instances are allowed\n  # [[inputs.promql.instant]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total'\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n\n  ## Range queries, multiple instances are allowed\n  # [[inputs.promql.range]]\n  #   ## Fallback name of the resulting metrics to use as metric name in case\n  #   ## the __name__ property of the query results is empty.\n  #   # name = \"promql\"\n  #\n  #   ## Query to execute\n  #   query = 'prometheus_http_requests_total{job=\"prometheus\"}'\n  #\n  #   ## Range parameters relative to the gathering time with positive values\n  #   ## refer to BEFORE and negative to AFTER the gathering time\n  #   start = \"5m\"\n  #   # end = \"0s\"\n  #   step = \"1m\"\n  #\n  #   ## Limit for the number of results returned by the server with zero\n  #   ## meaning no limit\n  #   # limit = 0\n"
  },
  {
    "path": "plugins/inputs/proxmox/README.md",
    "content": "# Proxmox Input Plugin\n\nThis plugin gathers metrics about containers and VMs running on a\n[Proxmox][proxmox] instance using the Proxmox API.\n\n⭐ Telegraf v1.16.0\n🏷️ server\n💻 all\n\n[proxmox]: https://www.proxmox.com\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Provides metrics from Proxmox nodes (Proxmox Virtual Environment > 6.2).\n[[inputs.proxmox]]\n  ## API connection configuration. The API token was introduced in Proxmox v6.2.\n  ## Required permissions for user and token: PVEAuditor role on /.\n  base_url = \"https://localhost:8006/api2/json\"\n  api_token = \"USER@REALM!TOKENID=UUID\"\n\n  ## Node name, defaults to OS hostname\n  ## Unless Telegraf is on the same host as Proxmox, setting this is required.\n  # node_name = \"\"\n\n  ## Additional tags of the VM stats data to add as a tag\n  ## Supported values are \"vmid\" and \"status\"\n  # additional_vmstats_tags = []\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP response timeout (default: 5s)\n  # response_timeout = \"5s\"\n```\n\n### Permissions\n\nThe plugin will need to have access to the Proxmox API. In Proxmox API tokens\nare a subset of the corresponding user. This means an API token cannot execute\ncommands that the user cannot either.\n\nFor Telegraf, an API token and user must be provided with at least the\nPVEAuditor role on /. Below is an example of creating a telegraf user and token\nand then ensuring the user and token have the correct role:\n\n```s\n## Create a influx user with PVEAuditor role\npveum user add influx@pve\npveum acl modify / -role PVEAuditor -user influx@pve\n## Create a token with the PVEAuditor role\npveum user token add influx@pve monitoring -privsep 1\npveum acl modify / -role PVEAuditor -token 'influx@pve!monitoring'\n```\n\nSee this [Proxmox docs example][docs] for further details.\n\n[docs]: https://pve.proxmox.com/wiki/User_Management#_limited_api_token_for_monitoring\n\n## Metrics\n\n- proxmox\n  - tags:\n    - node_fqdn - FQDN of the node telegraf is running on\n    - vm_name - Name of the VM/container\n    - vm_fqdn - FQDN of the VM/container\n    - vm_type - Type of the VM/container (lxc, qemu)\n    - vm_id - ID of the VM/container\n  - fields:\n    - status\n    - uptime\n    - cpuload\n    - mem_used\n    - mem_total\n    - mem_free\n    - mem_used_percentage\n    - swap_used\n    - swap_total\n    - swap_free\n    - swap_used_percentage\n    - disk_used\n    - disk_total\n    - disk_free\n    - disk_used_percentage\n\n## Example Output\n\n```text\nproxmox,host=pxnode,node_fqdn=pxnode.example.com,vm_fqdn=vm1.example.com,vm_id=112,vm_name=vm1,vm_type=lxc cpuload=0.147998116735236,disk_free=4461129728i,disk_total=5217320960i,disk_used=756191232i,disk_used_percentage=14,mem_free=1046827008i,mem_total=1073741824i,mem_used=26914816i,mem_used_percentage=2,status=\"running\",swap_free=536698880i,swap_total=536870912i,swap_used=172032i,swap_used_percentage=0,uptime=1643793i 1595457277000000000\n```\n"
  },
  {
    "path": "plugins/inputs/proxmox/proxmox.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage proxmox\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Proxmox struct {\n\tBaseURL               string          `toml:\"base_url\"`\n\tAPIToken              string          `toml:\"api_token\"`\n\tResponseTimeout       config.Duration `toml:\"response_timeout\"`\n\tNodeName              string          `toml:\"node_name\"`\n\tAdditionalVmstatsTags []string        `toml:\"additional_vmstats_tags\"`\n\tLog                   telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\thttpClient       *http.Client\n\tnodeSearchDomain string\n\n\trequestFunction func(apiUrl string, method string, data url.Values) ([]byte, error)\n}\n\nfunc (*Proxmox) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (px *Proxmox) Init() error {\n\t// Check parameters\n\tfor _, v := range px.AdditionalVmstatsTags {\n\t\tswitch v {\n\t\tcase \"vmid\", \"status\":\n\t\t\t// Do nothing as those are valid values\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid additional vmstats tag %q\", v)\n\t\t}\n\t}\n\n\t// Set hostname as default node name for backwards compatibility\n\tif px.NodeName == \"\" {\n\t\t//nolint:errcheck // best attempt setting of NodeName\n\t\thostname, _ := os.Hostname()\n\t\tpx.NodeName = hostname\n\t}\n\n\ttlsCfg, err := px.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\tpx.httpClient = &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(px.ResponseTimeout),\n\t}\n\n\tpx.requestFunction = px.performRequest\n\n\treturn nil\n}\n\nfunc (px *Proxmox) Gather(acc telegraf.Accumulator) error {\n\tif err := px.getNodeSearchDomain(); err != nil {\n\t\treturn fmt.Errorf(\"getting search domain failed: %w\", err)\n\t}\n\n\tpx.gatherVMData(acc, lxc)\n\tpx.gatherVMData(acc, qemu)\n\n\treturn nil\n}\n\nfunc (px *Proxmox) getNodeSearchDomain() error {\n\tapiURL := \"/nodes/\" + px.NodeName + \"/dns\"\n\tjsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"requesting data failed: %w\", err)\n\t}\n\n\tvar nodeDNS nodeDNS\n\tif err := json.Unmarshal(jsonData, &nodeDNS); err != nil {\n\t\treturn fmt.Errorf(\"decoding message failed: %w\", err)\n\t}\n\tpx.nodeSearchDomain = nodeDNS.Data.Searchdomain\n\n\treturn nil\n}\n\nfunc (px *Proxmox) performRequest(apiURL, method string, data url.Values) ([]byte, error) {\n\trequest, err := http.NewRequest(method, px.BaseURL+apiURL, strings.NewReader(data.Encode()))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trequest.Header.Add(\"Authorization\", \"PVEAPIToken=\"+px.APIToken)\n\n\tresp, err := px.httpClient.Do(request)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tresponseBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn responseBody, nil\n}\n\nfunc (px *Proxmox) gatherVMData(acc telegraf.Accumulator, rt resourceType) {\n\tvmStats, err := px.getVMStats(rt)\n\tif err != nil {\n\t\tpx.Log.Errorf(\"Error getting VM stats: %v\", err)\n\t\treturn\n\t}\n\n\tfor _, vmStat := range vmStats.Data {\n\t\tvmConfig, err := px.getVMConfig(vmStat.ID, rt)\n\t\tif err != nil {\n\t\t\tpx.Log.Errorf(\"Error getting VM config: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tif vmConfig.Data.Template == 1 {\n\t\t\tpx.Log.Debugf(\"Ignoring template VM %s (%s)\", vmStat.ID, vmStat.Name)\n\t\t\tcontinue\n\t\t}\n\n\t\tcurrentVMStatus, err := px.getCurrentVMStatus(rt, vmStat.ID)\n\t\tif err != nil {\n\t\t\tpx.Log.Errorf(\"Error getting VM current VM status: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tvmFQDN := vmConfig.Data.Hostname\n\t\tif vmFQDN == \"\" {\n\t\t\tvmFQDN = vmStat.Name\n\t\t}\n\t\tdomain := vmConfig.Data.Searchdomain\n\t\tif domain == \"\" {\n\t\t\tdomain = px.nodeSearchDomain\n\t\t}\n\t\tif domain != \"\" {\n\t\t\tvmFQDN += \".\" + domain\n\t\t}\n\n\t\tnodeFQDN := px.NodeName\n\t\tif px.nodeSearchDomain != \"\" {\n\t\t\tnodeFQDN += \".\" + domain\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"node_fqdn\": nodeFQDN,\n\t\t\t\"vm_name\":   vmStat.Name,\n\t\t\t\"vm_fqdn\":   vmFQDN,\n\t\t\t\"vm_type\":   string(rt),\n\t\t}\n\t\tif slices.Contains(px.AdditionalVmstatsTags, \"vmid\") {\n\t\t\ttags[\"vm_id\"] = vmStat.ID.String()\n\t\t}\n\t\tif slices.Contains(px.AdditionalVmstatsTags, \"status\") {\n\t\t\ttags[\"status\"] = currentVMStatus.Status\n\t\t}\n\n\t\tmemMetrics := getByteMetrics(currentVMStatus.TotalMem, currentVMStatus.UsedMem)\n\t\tswapMetrics := getByteMetrics(currentVMStatus.TotalSwap, currentVMStatus.UsedSwap)\n\t\tdiskMetrics := getByteMetrics(currentVMStatus.TotalDisk, currentVMStatus.UsedDisk)\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"status\":               currentVMStatus.Status,\n\t\t\t\"uptime\":               jsonNumberToInt64(currentVMStatus.Uptime),\n\t\t\t\"cpuload\":              jsonNumberToFloat64(currentVMStatus.CPULoad),\n\t\t\t\"mem_used\":             memMetrics.used,\n\t\t\t\"mem_total\":            memMetrics.total,\n\t\t\t\"mem_free\":             memMetrics.free,\n\t\t\t\"mem_used_percentage\":  memMetrics.usedPercentage,\n\t\t\t\"swap_used\":            swapMetrics.used,\n\t\t\t\"swap_total\":           swapMetrics.total,\n\t\t\t\"swap_free\":            swapMetrics.free,\n\t\t\t\"swap_used_percentage\": swapMetrics.usedPercentage,\n\t\t\t\"disk_used\":            diskMetrics.used,\n\t\t\t\"disk_total\":           diskMetrics.total,\n\t\t\t\"disk_free\":            diskMetrics.free,\n\t\t\t\"disk_used_percentage\": diskMetrics.usedPercentage,\n\t\t}\n\t\tacc.AddFields(\"proxmox\", fields, tags)\n\t}\n}\n\nfunc (px *Proxmox) getCurrentVMStatus(rt resourceType, id json.Number) (vmStat, error) {\n\tapiURL := \"/nodes/\" + px.NodeName + \"/\" + string(rt) + \"/\" + string(id) + \"/status/current\"\n\tjsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)\n\tif err != nil {\n\t\treturn vmStat{}, err\n\t}\n\n\tvar currentVMStatus vmCurrentStats\n\terr = json.Unmarshal(jsonData, &currentVMStatus)\n\tif err != nil {\n\t\treturn vmStat{}, err\n\t}\n\n\treturn currentVMStatus.Data, nil\n}\n\nfunc (px *Proxmox) getVMStats(rt resourceType) (vmStats, error) {\n\tapiURL := \"/nodes/\" + px.NodeName + \"/\" + string(rt)\n\tjsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)\n\tif err != nil {\n\t\treturn vmStats{}, err\n\t}\n\n\tvar vmStatistics vmStats\n\terr = json.Unmarshal(jsonData, &vmStatistics)\n\tif err != nil {\n\t\treturn vmStats{}, err\n\t}\n\n\treturn vmStatistics, nil\n}\n\nfunc (px *Proxmox) getVMConfig(vmID json.Number, rt resourceType) (vmConfig, error) {\n\tapiURL := \"/nodes/\" + px.NodeName + \"/\" + string(rt) + \"/\" + string(vmID) + \"/config\"\n\tjsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)\n\tif err != nil {\n\t\treturn vmConfig{}, err\n\t}\n\n\tvar vmCfg vmConfig\n\terr = json.Unmarshal(jsonData, &vmCfg)\n\tif err != nil {\n\t\treturn vmConfig{}, err\n\t}\n\n\treturn vmCfg, nil\n}\n\nfunc getByteMetrics(total, used json.Number) metrics {\n\tint64Total := jsonNumberToInt64(total)\n\tint64Used := jsonNumberToInt64(used)\n\tint64Free := int64Total - int64Used\n\tusedPercentage := 0.0\n\tif int64Total != 0 {\n\t\tusedPercentage = float64(int64Used) * 100 / float64(int64Total)\n\t}\n\n\treturn metrics{\n\t\ttotal:          int64Total,\n\t\tused:           int64Used,\n\t\tfree:           int64Free,\n\t\tusedPercentage: usedPercentage,\n\t}\n}\n\nfunc jsonNumberToInt64(value json.Number) int64 {\n\tint64Value, err := value.Int64()\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn int64Value\n}\n\nfunc jsonNumberToFloat64(value json.Number) float64 {\n\tfloat64Value, err := value.Float64()\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn float64Value\n}\n\nfunc init() {\n\tinputs.Add(\"proxmox\", func() telegraf.Input {\n\t\treturn &Proxmox{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/proxmox/proxmox_test.go",
    "content": "package proxmox\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar nodeSearchDomainTestData = `{\"data\":{\"search\":\"test.example.com\",\"dns1\":\"1.0.0.1\"}}`\nvar qemuTestData = `{\"data\":[{\"name\":\"qemu1\",\"status\":\"running\",\"maxdisk\":10737418240,\"cpu\":0.029336643550795,\"vmid\":\"113\",\"uptime\":2159739,` +\n\t`\"disk\":0,\"maxmem\":2147483648,\"mem\":1722451796}]}`\nvar qemuConfigTestData = `{\"data\":{\"hostname\":\"qemu1\",\"searchdomain\":\"test.example.com\"}}`\nvar lxcTestData = `{\"data\":[{\"vmid\":\"111\",\"type\":\"lxc\",\"uptime\":2078164,\"swap\":9412608,\"disk\":\"744189952\",\"maxmem\":536870912,\"mem\":98500608,` +\n\t`\"maxswap\":536870912,\"cpu\":0.00371567669193613,\"status\":\"running\",\"maxdisk\":\"5217320960\",\"name\":\"container1\"},{\"vmid\":112,\"type\":\"lxc\",` +\n\t`\"uptime\":2078164,\"swap\":9412608,\"disk\":\"744189952\",\"maxmem\":536870912,\"mem\":98500608,\"maxswap\":536870912,\"cpu\":0.00371567669193613,` +\n\t`\"status\":\"running\",\"maxdisk\":\"5217320960\",\"name\":\"container2\"}]}`\nvar lxcConfigTestData = `{\"data\":{\"hostname\":\"container1\",\"searchdomain\":\"test.example.com\"}}`\nvar lxcCurrentStatusTestData = `{\"data\":{\"vmid\":\"111\",\"type\":\"lxc\",\"uptime\":2078164,\"swap\":9412608,\"disk\":\"744189952\",\"maxmem\":536870912,` +\n\t`\"mem\":98500608,\"maxswap\":536870912,\"cpu\":0.00371567669193613,\"status\":\"running\",\"maxdisk\":\"5217320960\",\"name\":\"container1\"}}`\nvar qemuCurrentStatusTestData = `{\"data\":{\"name\":\"qemu1\",\"status\":\"running\",\"maxdisk\":10737418240,\"cpu\":0.029336643550795,\"vmid\":\"113\",` +\n\t`\"uptime\":2159739,\"disk\":0,\"maxmem\":2147483648,\"mem\":1722451796}}`\n\nfunc performTestRequest(apiURL, _ string, _ url.Values) ([]byte, error) {\n\tvar bytedata = []byte(\"\")\n\n\tif strings.HasSuffix(apiURL, \"dns\") {\n\t\tbytedata = []byte(nodeSearchDomainTestData)\n\t} else if strings.HasSuffix(apiURL, \"qemu\") {\n\t\tbytedata = []byte(qemuTestData)\n\t} else if strings.HasSuffix(apiURL, \"113/config\") {\n\t\tbytedata = []byte(qemuConfigTestData)\n\t} else if strings.HasSuffix(apiURL, \"lxc\") {\n\t\tbytedata = []byte(lxcTestData)\n\t} else if strings.HasSuffix(apiURL, \"111/config\") {\n\t\tbytedata = []byte(lxcConfigTestData)\n\t} else if strings.HasSuffix(apiURL, \"111/status/current\") {\n\t\tbytedata = []byte(lxcCurrentStatusTestData)\n\t} else if strings.HasSuffix(apiURL, \"113/status/current\") {\n\t\tbytedata = []byte(qemuCurrentStatusTestData)\n\t}\n\n\treturn bytedata, nil\n}\n\nfunc TestGetNodeSearchDomain(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName: \"testnode\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\trequire.NoError(t, px.getNodeSearchDomain())\n\trequire.Equal(t, \"test.example.com\", px.nodeSearchDomain)\n}\n\nfunc TestGatherLxcData(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName:         \"testnode\",\n\t\tLog:              testutil.Logger{},\n\t\tnodeSearchDomain: \"test.example.com\",\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\tvar acc testutil.Accumulator\n\tpx.gatherVMData(&acc, lxc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"proxmox\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node_fqdn\": \"testnode.test.example.com\",\n\t\t\t\t\"vm_name\":   \"container1\",\n\t\t\t\t\"vm_fqdn\":   \"container1.test.example.com\",\n\t\t\t\t\"vm_type\":   \"lxc\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\":               \"running\",\n\t\t\t\t\"uptime\":               int64(2078164),\n\t\t\t\t\"cpuload\":              float64(0.00371567669193613),\n\t\t\t\t\"mem_used\":             int64(98500608),\n\t\t\t\t\"mem_total\":            int64(536870912),\n\t\t\t\t\"mem_free\":             int64(438370304),\n\t\t\t\t\"mem_used_percentage\":  float64(18.34716796875),\n\t\t\t\t\"swap_used\":            int64(9412608),\n\t\t\t\t\"swap_total\":           int64(536870912),\n\t\t\t\t\"swap_free\":            int64(527458304),\n\t\t\t\t\"swap_used_percentage\": float64(1.75323486328125),\n\t\t\t\t\"disk_used\":            int64(744189952),\n\t\t\t\t\"disk_total\":           int64(5217320960),\n\t\t\t\t\"disk_free\":            int64(4473131008),\n\t\t\t\t\"disk_used_percentage\": float64(14.26383306117322),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherQemuData(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName:         \"testnode\",\n\t\tLog:              testutil.Logger{},\n\t\tnodeSearchDomain: \"test.example.com\",\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\tvar acc testutil.Accumulator\n\tpx.gatherVMData(&acc, qemu)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"proxmox\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node_fqdn\": \"testnode.test.example.com\",\n\t\t\t\t\"vm_name\":   \"qemu1\",\n\t\t\t\t\"vm_fqdn\":   \"qemu1.test.example.com\",\n\t\t\t\t\"vm_type\":   \"qemu\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\":               \"running\",\n\t\t\t\t\"uptime\":               int64(2159739),\n\t\t\t\t\"cpuload\":              float64(0.029336643550795),\n\t\t\t\t\"mem_used\":             int64(1722451796),\n\t\t\t\t\"mem_total\":            int64(2147483648),\n\t\t\t\t\"mem_free\":             int64(425031852),\n\t\t\t\t\"mem_used_percentage\":  float64(80.20791206508875),\n\t\t\t\t\"swap_used\":            int64(0),\n\t\t\t\t\"swap_total\":           int64(0),\n\t\t\t\t\"swap_free\":            int64(0),\n\t\t\t\t\"swap_used_percentage\": float64(0),\n\t\t\t\t\"disk_used\":            int64(0),\n\t\t\t\t\"disk_total\":           int64(10737418240),\n\t\t\t\t\"disk_free\":            int64(10737418240),\n\t\t\t\t\"disk_used_percentage\": float64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherLxcDataWithID(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName:              \"testnode\",\n\t\tAdditionalVmstatsTags: []string{\"vmid\"},\n\t\tLog:                   testutil.Logger{},\n\t\tnodeSearchDomain:      \"test.example.com\",\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\tvar acc testutil.Accumulator\n\tpx.gatherVMData(&acc, lxc)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"proxmox\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node_fqdn\": \"testnode.test.example.com\",\n\t\t\t\t\"vm_name\":   \"container1\",\n\t\t\t\t\"vm_fqdn\":   \"container1.test.example.com\",\n\t\t\t\t\"vm_type\":   \"lxc\",\n\t\t\t\t\"vm_id\":     \"111\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\":               \"running\",\n\t\t\t\t\"uptime\":               int64(2078164),\n\t\t\t\t\"cpuload\":              float64(0.00371567669193613),\n\t\t\t\t\"mem_used\":             int64(98500608),\n\t\t\t\t\"mem_total\":            int64(536870912),\n\t\t\t\t\"mem_free\":             int64(438370304),\n\t\t\t\t\"mem_used_percentage\":  float64(18.34716796875),\n\t\t\t\t\"swap_used\":            int64(9412608),\n\t\t\t\t\"swap_total\":           int64(536870912),\n\t\t\t\t\"swap_free\":            int64(527458304),\n\t\t\t\t\"swap_used_percentage\": float64(1.75323486328125),\n\t\t\t\t\"disk_used\":            int64(744189952),\n\t\t\t\t\"disk_total\":           int64(5217320960),\n\t\t\t\t\"disk_free\":            int64(4473131008),\n\t\t\t\t\"disk_used_percentage\": float64(14.26383306117322),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherQemuDataWithID(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName:              \"testnode\",\n\t\tAdditionalVmstatsTags: []string{\"vmid\"},\n\t\tLog:                   testutil.Logger{},\n\t\tnodeSearchDomain:      \"test.example.com\",\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\tvar acc testutil.Accumulator\n\tpx.gatherVMData(&acc, qemu)\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"proxmox\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node_fqdn\": \"testnode.test.example.com\",\n\t\t\t\t\"vm_name\":   \"qemu1\",\n\t\t\t\t\"vm_fqdn\":   \"qemu1.test.example.com\",\n\t\t\t\t\"vm_type\":   \"qemu\",\n\t\t\t\t\"vm_id\":     \"113\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"status\":               \"running\",\n\t\t\t\t\"uptime\":               int64(2159739),\n\t\t\t\t\"cpuload\":              float64(0.029336643550795),\n\t\t\t\t\"mem_used\":             int64(1722451796),\n\t\t\t\t\"mem_total\":            int64(2147483648),\n\t\t\t\t\"mem_free\":             int64(425031852),\n\t\t\t\t\"mem_used_percentage\":  float64(80.20791206508875),\n\t\t\t\t\"swap_used\":            int64(0),\n\t\t\t\t\"swap_total\":           int64(0),\n\t\t\t\t\"swap_free\":            int64(0),\n\t\t\t\t\"swap_used_percentage\": float64(0),\n\t\t\t\t\"disk_used\":            int64(0),\n\t\t\t\t\"disk_total\":           int64(10737418240),\n\t\t\t\t\"disk_free\":            int64(10737418240),\n\t\t\t\t\"disk_used_percentage\": float64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGather(t *testing.T) {\n\tpx := &Proxmox{\n\t\tNodeName: \"testnode\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, px.Init())\n\tpx.requestFunction = performTestRequest\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, px.Gather(&acc))\n\n\t// Results from both tests above\n\trequire.Equal(t, 30, acc.NFields())\n}\n"
  },
  {
    "path": "plugins/inputs/proxmox/sample.conf",
    "content": "# Provides metrics from Proxmox nodes (Proxmox Virtual Environment > 6.2).\n[[inputs.proxmox]]\n  ## API connection configuration. The API token was introduced in Proxmox v6.2.\n  ## Required permissions for user and token: PVEAuditor role on /.\n  base_url = \"https://localhost:8006/api2/json\"\n  api_token = \"USER@REALM!TOKENID=UUID\"\n\n  ## Node name, defaults to OS hostname\n  ## Unless Telegraf is on the same host as Proxmox, setting this is required.\n  # node_name = \"\"\n\n  ## Additional tags of the VM stats data to add as a tag\n  ## Supported values are \"vmid\" and \"status\"\n  # additional_vmstats_tags = []\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## HTTP response timeout (default: 5s)\n  # response_timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/proxmox/structs.go",
    "content": "package proxmox\n\nimport (\n\t\"encoding/json\"\n)\n\nvar (\n\tqemu resourceType = \"qemu\"\n\tlxc  resourceType = \"lxc\"\n)\n\ntype resourceType string\n\ntype vmStats struct {\n\tData []vmStat `json:\"data\"`\n}\n\ntype vmCurrentStats struct {\n\tData vmStat `json:\"data\"`\n}\n\ntype vmStat struct {\n\tID        json.Number `json:\"vmid\"`\n\tName      string      `json:\"name\"`\n\tStatus    string      `json:\"status\"`\n\tUsedMem   json.Number `json:\"mem\"`\n\tTotalMem  json.Number `json:\"maxmem\"`\n\tUsedDisk  json.Number `json:\"disk\"`\n\tTotalDisk json.Number `json:\"maxdisk\"`\n\tUsedSwap  json.Number `json:\"swap\"`\n\tTotalSwap json.Number `json:\"maxswap\"`\n\tUptime    json.Number `json:\"uptime\"`\n\tCPULoad   json.Number `json:\"cpu\"`\n}\n\ntype vmConfig struct {\n\tData struct {\n\t\tSearchdomain string `json:\"searchdomain\"`\n\t\tHostname     string `json:\"hostname\"`\n\t\tTemplate     int    `json:\"template\"`\n\t} `json:\"data\"`\n}\n\ntype nodeDNS struct {\n\tData struct {\n\t\tSearchdomain string `json:\"search\"`\n\t} `json:\"data\"`\n}\n\ntype metrics struct {\n\ttotal          int64\n\tused           int64\n\tfree           int64\n\tusedPercentage float64\n}\n"
  },
  {
    "path": "plugins/inputs/puppetagent/README.md",
    "content": "# Puppet Agent Input Plugin\n\nThis plugin gathers metrics of a [Puppet agent][puppet] by parsing variables\nfrom the local last-run-summary file.\n\n⭐ Telegraf v0.2.0\n🏷️ system\n💻 all\n\n[puppet]: https://www.puppet.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Reads last_run_summary.yaml file and converts to measurements\n[[inputs.puppetagent]]\n  ## Location of puppet last run summary file\n  location = \"/var/lib/puppet/state/last_run_summary.yaml\"\n```\n\n## Metrics\n\n### PuppetAgent int64 measurements\n\nMeta:\n\n- units: int64\n- tags: ``\n\nMeasurement names:\n\n- puppetagent_changes_total\n- puppetagent_events_failure\n- puppetagent_events_total\n- puppetagent_events_success\n- puppetagent_resources_changed\n- puppetagent_resources_corrective_change\n- puppetagent_resources_failed\n- puppetagent_resources_failedtorestart\n- puppetagent_resources_outofsync\n- puppetagent_resources_restarted\n- puppetagent_resources_scheduled\n- puppetagent_resources_skipped\n- puppetagent_resources_total\n- puppetagent_time_service\n- puppetagent_time_lastrun\n- puppetagent_version_config\n\n### PuppetAgent float64 measurements\n\nMeta:\n\n- units: float64\n- tags: ``\n\nMeasurement names:\n\n- puppetagent_time_anchor\n- puppetagent_time_catalogapplication\n- puppetagent_time_configretrieval\n- puppetagent_time_convertcatalog\n- puppetagent_time_cron\n- puppetagent_time_exec\n- puppetagent_time_factgeneration\n- puppetagent_time_file\n- puppetagent_time_filebucket\n- puppetagent_time_group\n- puppetagent_time_lastrun\n- puppetagent_time_noderetrieval\n- puppetagent_time_notify\n- puppetagent_time_package\n- puppetagent_time_pluginsync\n- puppetagent_time_schedule\n- puppetagent_time_sshauthorizedkey\n- puppetagent_time_total\n- puppetagent_time_transactionevaluation\n- puppetagent_time_user\n- puppetagent_version_config\n\n### PuppetAgent string measurements\n\nMeta:\n\n- units: string\n- tags: ``\n\nMeasurement names:\n\n- puppetagent_version_puppet\n\n## Example Output\n\n```text\npuppetagent,location=last_run_summary.yaml changes_total=0i,events_failure=0i,events_noop=0i,events_success=0i,events_total=0i,resources_changed=0i,resources_correctivechange=0i,resources_failed=0i,resources_failedtorestart=0i,resources_outofsync=0i,resources_restarted=0i,resources_scheduled=0i,resources_skipped=0i,resources_total=109i,time_anchor=0.000555,time_catalogapplication=0.010555,time_configretrieval=4.75567007064819,time_convertcatalog=1.3,time_cron=0.000584,time_exec=0.508123,time_factgeneration=0.34,time_file=0.441472,time_filebucket=0.000353,time_group=0,time_lastrun=1444936531i,time_noderetrieval=1.235,time_notify=0.00035,time_package=1.325788,time_pluginsync=0.325788,time_schedule=0.001123,time_service=1.807795,time_sshauthorizedkey=0.000764,time_total=8.85354707064819,time_transactionevaluation=4.69765,time_user=0.004331,version_configstring=\"environment:d6018ce\",version_puppet=\"3.7.5\" 1747757240432097335\n```\n"
  },
  {
    "path": "plugins/inputs/puppetagent/last_run_summary.yaml",
    "content": "---\n  events:\n    failure: 0\n    noop: 0\n    total: 0\n    success: 0\n  resources:\n    changed: 0\n    corrective_change: 0\n    failed: 0\n    failed_to_restart: 0\n    out_of_sync: 0\n    restarted: 0\n    scheduled: 0\n    skipped: 0\n    total: 109\n  changes:\n    total: 0\n  time:\n    anchor: 0.000555\n    catalog_application: 0.010555\n    config_retrieval: 4.75567007064819\n    convert_catalog: 1.3\n    cron: 0.000584\n    exec: 0.508123\n    fact_generation: 0.34\n    file: 0.441472\n    filebucket: 0.000353\n    last_run: 1444936531\n    node_retrieval: 1.235\n    notify: 0.00035\n    package: 1.325788\n    plugin_sync: 0.325788\n    schedule: 0.001123\n    service: 1.807795\n    ssh_authorized_key: 0.000764\n    total: 8.85354707064819\n    transaction_evaluation: 4.69765\n    user: 0.004331\n    yumrepo: 0.006989\n  version:\n    config: \"environment:d6018ce\"\n    puppet: \"3.7.5\"\n"
  },
  {
    "path": "plugins/inputs/puppetagent/puppetagent.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage puppetagent\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype PuppetAgent struct {\n\tLocation string `toml:\"location\"`\n}\n\ntype state struct {\n\tEvents    event\n\tResources resource\n\tChanges   change\n\tTime      time\n\tVersion   version\n}\n\ntype event struct {\n\tFailure int64 `yaml:\"failure\"`\n\tNoop    int64 `yaml:\"noop\"`\n\tTotal   int64 `yaml:\"total\"`\n\tSuccess int64 `yaml:\"success\"`\n}\n\ntype resource struct {\n\tChanged          int64 `yaml:\"changed\"`\n\tCorrectiveChange int64 `yaml:\"corrective_change\"`\n\tFailed           int64 `yaml:\"failed\"`\n\tFailedToRestart  int64 `yaml:\"failed_to_restart\"`\n\tOutOfSync        int64 `yaml:\"out_of_sync\"`\n\tRestarted        int64 `yaml:\"restarted\"`\n\tScheduled        int64 `yaml:\"scheduled\"`\n\tSkipped          int64 `yaml:\"skipped\"`\n\tTotal            int64 `yaml:\"total\"`\n}\n\ntype change struct {\n\tTotal int64 `yaml:\"total\"`\n}\n\ntype time struct {\n\tAnchor                float64 `yaml:\"anchor\"`\n\tCataLogApplication    float64 `yaml:\"catalog_application\"`\n\tConfigRetrieval       float64 `yaml:\"config_retrieval\"`\n\tConvertCatalog        float64 `yaml:\"convert_catalog\"`\n\tCron                  float64 `yaml:\"cron\"`\n\tExec                  float64 `yaml:\"exec\"`\n\tFactGeneration        float64 `yaml:\"fact_generation\"`\n\tFile                  float64 `yaml:\"file\"`\n\tFileBucket            float64 `yaml:\"filebucket\"`\n\tGroup                 float64 `yaml:\"group\"`\n\tLastRun               int64   `yaml:\"last_run\"`\n\tNodeRetrieval         float64 `yaml:\"node_retrieval\"`\n\tNotify                float64 `yaml:\"notify\"`\n\tPackage               float64 `yaml:\"package\"`\n\tPluginSync            float64 `yaml:\"plugin_sync\"`\n\tSchedule              float64 `yaml:\"schedule\"`\n\tService               float64 `yaml:\"service\"`\n\tSSHAuthorizedKey      float64 `yaml:\"ssh_authorized_key\"`\n\tTotal                 float64 `yaml:\"total\"`\n\tTransactionEvaluation float64 `yaml:\"transaction_evaluation\"`\n\tUser                  float64 `yaml:\"user\"`\n}\n\ntype version struct {\n\tConfigString string `yaml:\"config\"`\n\tPuppet       string `yaml:\"puppet\"`\n}\n\nfunc (*PuppetAgent) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (pa *PuppetAgent) Gather(acc telegraf.Accumulator) error {\n\tif len(pa.Location) == 0 {\n\t\tpa.Location = \"/var/lib/puppet/state/last_run_summary.yaml\"\n\t}\n\n\tif _, err := os.Stat(pa.Location); err != nil {\n\t\treturn err\n\t}\n\n\tfh, err := os.ReadFile(pa.Location)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar puppetState state\n\n\terr = yaml.Unmarshal(fh, &puppetState)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := map[string]string{\"location\": pa.Location}\n\tstructPrinter(&puppetState, acc, tags)\n\n\treturn nil\n}\n\nfunc structPrinter(s *state, acc telegraf.Accumulator, tags map[string]string) {\n\te := reflect.ValueOf(s).Elem()\n\n\tfields := make(map[string]interface{})\n\tfor tLevelFNum := 0; tLevelFNum < e.NumField(); tLevelFNum++ {\n\t\tname := e.Type().Field(tLevelFNum).Name\n\t\tnameNumField := e.FieldByName(name).NumField()\n\n\t\tfor sLevelFNum := 0; sLevelFNum < nameNumField; sLevelFNum++ {\n\t\t\tsName := e.FieldByName(name).Type().Field(sLevelFNum).Name\n\t\t\tsValue := e.FieldByName(name).Field(sLevelFNum).Interface()\n\n\t\t\tlname := strings.ToLower(name)\n\t\t\tlsName := strings.ToLower(sName)\n\t\t\tfields[fmt.Sprintf(\"%s_%s\", lname, lsName)] = sValue\n\t\t}\n\t}\n\tacc.AddFields(\"puppetagent\", fields, tags)\n}\n\nfunc init() {\n\tinputs.Add(\"puppetagent\", func() telegraf.Input {\n\t\treturn &PuppetAgent{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/puppetagent/puppetagent_test.go",
    "content": "package puppetagent\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGather(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tpa := PuppetAgent{\n\t\tLocation: \"last_run_summary.yaml\",\n\t}\n\trequire.NoError(t, pa.Gather(&acc))\n\n\ttags := map[string]string{\"location\": \"last_run_summary.yaml\"}\n\tfields := map[string]interface{}{\n\t\t\"events_failure\":             int64(0),\n\t\t\"events_noop\":                int64(0),\n\t\t\"events_success\":             int64(0),\n\t\t\"events_total\":               int64(0),\n\t\t\"resources_changed\":          int64(0),\n\t\t\"resources_correctivechange\": int64(0),\n\t\t\"resources_failed\":           int64(0),\n\t\t\"resources_failedtorestart\":  int64(0),\n\t\t\"resources_outofsync\":        int64(0),\n\t\t\"resources_restarted\":        int64(0),\n\t\t\"resources_scheduled\":        int64(0),\n\t\t\"resources_skipped\":          int64(0),\n\t\t\"resources_total\":            int64(109),\n\t\t\"changes_total\":              int64(0),\n\t\t\"time_anchor\":                float64(0.000555),\n\t\t\"time_catalogapplication\":    float64(0.010555),\n\t\t\"time_configretrieval\":       float64(4.75567007064819),\n\t\t\"time_convertcatalog\":        float64(1.3),\n\t\t\"time_cron\":                  float64(0.000584),\n\t\t\"time_exec\":                  float64(0.508123),\n\t\t\"time_factgeneration\":        float64(0.34),\n\t\t\"time_file\":                  float64(0.441472),\n\t\t\"time_filebucket\":            float64(0.000353),\n\t\t\"time_group\":                 float64(0),\n\t\t\"time_lastrun\":               int64(1444936531),\n\t\t\"time_noderetrieval\":         float64(1.235),\n\t\t\"time_notify\":                float64(0.00035),\n\t\t\"time_package\":               float64(1.325788),\n\t\t\"time_pluginsync\":            float64(0.325788),\n\t\t\"time_schedule\":              float64(0.001123),\n\t\t\"time_service\":               float64(1.807795),\n\t\t\"time_sshauthorizedkey\":      float64(0.000764),\n\t\t\"time_total\":                 float64(8.85354707064819),\n\t\t\"time_transactionevaluation\": float64(4.69765),\n\t\t\"time_user\":                  float64(0.004331),\n\t\t\"version_configstring\":       \"environment:d6018ce\",\n\t\t\"version_puppet\":             \"3.7.5\",\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"puppetagent\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/puppetagent/sample.conf",
    "content": "# Reads last_run_summary.yaml file and converts to measurements\n[[inputs.puppetagent]]\n  ## Location of puppet last run summary file\n  location = \"/var/lib/puppet/state/last_run_summary.yaml\"\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/README.md",
    "content": "# RabbitMQ Input Plugin\n\nThis plugin gathers statistics from [RabbitMQ][rabbitmq] servers via the\n[Management Plugin][mgmnt_plugin].\n\n⭐ Telegraf v0.1.5\n🏷️ server\n💻 all\n\n[rabbitmq]: https://www.rabbitmq.com\n[mgmnt_plugin]: https://www.rabbitmq.com/management.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Reads metrics from RabbitMQ servers via the Management Plugin\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  # url = \"http://localhost:15672\"\n\n  ## Credentials\n  # username = \"guest\"\n  # password = \"guest\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional request timeouts\n  ##\n  ## ResponseHeaderTimeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  # header_timeout = \"3s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  # client_timeout = \"4s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement. If not\n  ## specified, metrics for all nodes are gathered.\n  # nodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement. If not\n  ## specified, metrics for all exchanges are gathered.\n  # exchanges = [\"telegraf\"]\n\n  ## Metrics to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all metrics\n  ## Currently the following metrics are supported: \"exchange\", \"federation\", \"node\", \"overview\", \"queue\"\n  # metric_include = []\n  # metric_exclude = []\n\n  ## Queues to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all queues\n  # queue_name_include = []\n  # queue_name_exclude = []\n\n  ## Federation upstreams to include and exclude specified as an array of glob\n  ## pattern strings.  Federation links can also be limited by the queue and\n  ## exchange filters.\n  # federation_upstream_include = []\n  # federation_upstream_exclude = []\n\n  ## Include queue type as a tag. When enabled, adds a \"type\" tag to queue metrics\n  ## with the queue type returned by RabbitMQ (e.g., \"classic\", \"quorum\", \"stream\").\n  ## Defaults to \"classic\" if empty.\n  # include_queue_type_tag = false\n```\n\n## Metrics\n\n- rabbitmq_overview\n  - tags:\n    - url\n    - name\n  - fields:\n    - channels (int, channels)\n    - connections (int, connections)\n    - consumers (int, consumers)\n    - exchanges (int, exchanges)\n    - messages (int, messages)\n    - messages_acked (int, messages)\n    - messages_delivered (int, messages)\n    - messages_delivered_get (int, messages)\n    - messages_published (int, messages)\n    - messages_ready (int, messages)\n    - messages_unacked (int, messages)\n    - queues (int, queues)\n    - clustering_listeners (int, cluster nodes)\n    - amqp_listeners (int, amqp nodes up)\n    - return_unroutable (int, number of unroutable messages)\n    - return_unroutable_rate (float, number of unroutable messages per second)\n\n- rabbitmq_node\n  - tags:\n    - url\n    - node\n    - url\n  - fields:\n    - disk_free (int, bytes)\n    - disk_free_limit (int, bytes)\n    - disk_free_alarm (int, disk alarm)\n    - fd_total (int, file descriptors)\n    - fd_used (int, file descriptors)\n    - mem_limit (int, bytes)\n    - mem_used (int, bytes)\n    - mem_alarm (int, memory a)\n    - proc_total (int, erlang processes)\n    - proc_used (int, erlang processes)\n    - run_queue (int, erlang processes)\n    - sockets_total (int, sockets)\n    - sockets_used (int, sockets)\n    - running (int, node up)\n    - uptime (int, milliseconds)\n    - mnesia_disk_tx_count (int, number of disk transaction)\n    - mnesia_ram_tx_count (int, number of ram transaction)\n    - mnesia_disk_tx_count_rate (float, number of disk transaction per second)\n    - mnesia_ram_tx_count_rate (float, number of ram transaction per second)\n    - gc_num (int, number of garbage collection)\n    - gc_bytes_reclaimed (int, bytes)\n    - gc_num_rate (float, number of garbage collection per second)\n    - gc_bytes_reclaimed_rate (float, bytes per second)\n    - io_read_avg_time (float, number of read operations)\n    - io_read_avg_time_rate (int, number of read operations per second)\n    - io_read_bytes (int, bytes)\n    - io_read_bytes_rate (float, bytes per second)\n    - io_write_avg_time (int, milliseconds)\n    - io_write_avg_time_rate (float, milliseconds per second)\n    - io_write_bytes (int, bytes)\n    - io_write_bytes_rate (float, bytes per second)\n    - mem_connection_readers (int, bytes)\n    - mem_connection_writers (int, bytes)\n    - mem_connection_channels (int, bytes)\n    - mem_connection_other (int, bytes)\n    - mem_queue_procs (int, bytes)\n    - mem_queue_slave_procs (int, bytes)\n    - mem_plugins (int, bytes)\n    - mem_other_proc (int, bytes)\n    - mem_metrics (int, bytes)\n    - mem_mgmt_db (int, bytes)\n    - mem_mnesia (int, bytes)\n    - mem_other_ets (int, bytes)\n    - mem_binary (int, bytes)\n    - mem_msg_index (int, bytes)\n    - mem_code (int, bytes)\n    - mem_atom (int, bytes)\n    - mem_other_system (int, bytes)\n    - mem_allocated_unused (int, bytes)\n    - mem_reserved_unallocated (int, bytes)\n    - mem_total (int, bytes)\n\n- rabbitmq_queue\n  - tags:\n    - url\n    - queue\n    - vhost\n    - node\n    - durable\n    - auto_delete\n    - type (queue type as returned by RabbitMQ, if empty it defaults to\n      \"classic\"; only included when include_queue_type_tag = true)\n  - fields:\n    - consumer_utilisation (float, percent)\n    - consumers (int, int)\n    - idle_since (string, time - e.g., \"2006-01-02 15:04:05\")\n    - head_message_timestamp (int, unix timestamp - only emitted if available)\n    - memory (int, bytes)\n    - message_bytes (int, bytes)\n    - message_bytes_persist (int, bytes)\n    - message_bytes_ram (int, bytes)\n    - message_bytes_ready (int, bytes)\n    - message_bytes_unacked (int, bytes)\n    - messages (int, count)\n    - messages_ack (int, count)\n    - messages_ack_rate (float, messages per second)\n    - messages_deliver (int, count)\n    - messages_deliver_rate (float, messages per second)\n    - messages_deliver_get (int, count)\n    - messages_deliver_get_rate (float, messages per second)\n    - messages_publish (int, count)\n    - messages_publish_rate (float, messages per second)\n    - messages_ready (int, count)\n    - messages_redeliver (int, count)\n    - messages_redeliver_rate (float, messages per second)\n    - messages_unack (int, count)\n    - slave_nodes (int, count)\n    - synchronised_slave_nodes (int, count)\n\n- rabbitmq_exchange\n  - tags:\n    - url\n    - exchange\n    - type\n    - vhost\n    - internal\n    - durable\n    - auto_delete\n  - fields:\n    - messages_publish_in (int, count)\n    - messages_publish_in_rate (int, messages per second)\n    - messages_publish_out (int, count)\n    - messages_publish_out_rate (int, messages per second)\n\n- rabbitmq_federation\n  - tags:\n    - url\n    - vhost\n    - type\n    - upstream\n    - exchange\n    - upstream_exchange\n    - queue\n    - upstream_queue\n  - fields:\n    - acks_uncommitted (int, count)\n    - consumers (int, count)\n    - messages_unacknowledged (int, count)\n    - messages_uncommitted (int, count)\n    - messages_unconfirmed (int, count)\n    - messages_confirm (int, count)\n    - messages_publish (int, count)\n    - messages_return_unroutable (int, count)\n\n## Example Output\n\n```text\nrabbitmq_queue,url=http://amqp.example.org:15672,queue=telegraf,vhost=influxdb,node=rabbit@amqp.example.org,durable=true,auto_delete=false,type=classic,host=amqp.example.org head_message_timestamp=1493684017,messages_deliver_get=0i,messages_publish=329i,messages_publish_rate=0.2,messages_redeliver_rate=0,message_bytes_ready=0i,message_bytes_unacked=0i,messages_deliver=329i,messages_unack=0i,consumers=1i,idle_since=\"\",messages=0i,messages_deliver_rate=0.2,messages_deliver_get_rate=0.2,messages_redeliver=0i,memory=43032i,message_bytes_ram=0i,messages_ack=329i,messages_ready=0i,messages_ack_rate=0.2,consumer_utilisation=1,message_bytes=0i,message_bytes_persist=0i 1493684035000000000\nrabbitmq_overview,url=http://amqp.example.org:15672,host=amqp.example.org channels=2i,consumers=1i,exchanges=17i,messages_acked=329i,messages=0i,messages_ready=0i,messages_unacked=0i,connections=2i,queues=1i,messages_delivered=329i,messages_published=329i,clustering_listeners=2i,amqp_listeners=1i 1493684035000000000\nrabbitmq_node,url=http://amqp.example.org:15672,node=rabbit@amqp.example.org,host=amqp.example.org fd_total=1024i,fd_used=32i,mem_limit=8363329126i,sockets_total=829i,disk_free=8175935488i,disk_free_limit=50000000i,mem_used=58771080i,proc_total=1048576i,proc_used=267i,run_queue=0i,sockets_used=2i,running=1i 149368403500000000\nrabbitmq_exchange,url=http://amqp.example.org:15672,exchange=telegraf,type=fanout,vhost=influxdb,internal=false,durable=true,auto_delete=false,host=amqp.example.org messages_publish_in=2i,messages_publish_out=1i 149368403500000000\n```\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/rabbitmq.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage rabbitmq\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultUsername              = \"guest\"\n\tdefaultPassword              = \"guest\"\n\tdefaultURL                   = \"http://localhost:15672\"\n\tdefaultResponseHeaderTimeout = 3\n\tdefaultClientTimeout         = 4\n)\n\n// RabbitMQ defines the configuration necessary for gathering metrics,\n// see the sample config for further details\ntype RabbitMQ struct {\n\tURL      string        `toml:\"url\"`\n\tUsername config.Secret `toml:\"username\"`\n\tPassword config.Secret `toml:\"password\"`\n\ttls.ClientConfig\n\n\tResponseHeaderTimeout config.Duration `toml:\"header_timeout\"`\n\tClientTimeout         config.Duration `toml:\"client_timeout\"`\n\n\tNodes     []string `toml:\"nodes\"`\n\tExchanges []string `toml:\"exchanges\"`\n\n\tMetricInclude             []string `toml:\"metric_include\"`\n\tMetricExclude             []string `toml:\"metric_exclude\"`\n\tQueueInclude              []string `toml:\"queue_name_include\"`\n\tQueueExclude              []string `toml:\"queue_name_exclude\"`\n\tFederationUpstreamInclude []string `toml:\"federation_upstream_include\"`\n\tFederationUpstreamExclude []string `toml:\"federation_upstream_exclude\"`\n\n\tIncludeQueueTypeTag bool `toml:\"include_queue_type_tag\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient            *http.Client\n\texcludeEveryQueue bool\n\tmetricFilter      filter.Filter\n\tqueueFilter       filter.Filter\n\tupstreamFilter    filter.Filter\n}\n\ntype overviewResponse struct {\n\tMessageStats *messageStats `json:\"message_stats\"`\n\tObjectTotals *objectTotals `json:\"object_totals\"`\n\tQueueTotals  *queueTotals  `json:\"queue_totals\"`\n\tListeners    []listeners   `json:\"listeners\"`\n}\n\ntype listeners struct {\n\tProtocol string `json:\"protocol\"`\n}\n\ntype details struct {\n\tRate float64 `json:\"rate\"`\n}\n\ntype messageStats struct {\n\tAck                     int64\n\tAckDetails              details `json:\"ack_details\"`\n\tDeliver                 int64\n\tDeliverDetails          details `json:\"deliver_details\"`\n\tDeliverGet              int64   `json:\"deliver_get\"`\n\tDeliverGetDetails       details `json:\"deliver_get_details\"`\n\tPublish                 int64\n\tPublishDetails          details `json:\"publish_details\"`\n\tRedeliver               int64\n\tRedeliverDetails        details `json:\"redeliver_details\"`\n\tPublishIn               int64   `json:\"publish_in\"`\n\tPublishInDetails        details `json:\"publish_in_details\"`\n\tPublishOut              int64   `json:\"publish_out\"`\n\tPublishOutDetails       details `json:\"publish_out_details\"`\n\tReturnUnroutable        int64   `json:\"return_unroutable\"`\n\tReturnUnroutableDetails details `json:\"return_unroutable_details\"`\n}\n\ntype objectTotals struct {\n\tChannels    int64\n\tConnections int64\n\tConsumers   int64\n\tExchanges   int64\n\tQueues      int64\n}\n\ntype queueTotals struct {\n\tMessages                   int64\n\tMessagesReady              int64 `json:\"messages_ready\"`\n\tMessagesUnacknowledged     int64 `json:\"messages_unacknowledged\"`\n\tMessageBytes               int64 `json:\"message_bytes\"`\n\tMessageBytesReady          int64 `json:\"message_bytes_ready\"`\n\tMessageBytesUnacknowledged int64 `json:\"message_bytes_unacknowledged\"`\n\tMessageRAM                 int64 `json:\"message_bytes_ram\"`\n\tMessagePersistent          int64 `json:\"message_bytes_persistent\"`\n}\n\ntype queue struct {\n\tqueueTotals            // just to not repeat the same code\n\tmessageStats           `json:\"message_stats\"`\n\tMemory                 int64\n\tConsumers              int64\n\tConsumerUtilisation    float64 `json:\"consumer_utilisation\"`\n\tName                   string\n\tNode                   string\n\tVhost                  string\n\tType                   string\n\tDurable                bool\n\tAutoDelete             bool     `json:\"auto_delete\"`\n\tIdleSince              string   `json:\"idle_since\"`\n\tSlaveNodes             []string `json:\"slave_nodes\"`\n\tSynchronisedSlaveNodes []string `json:\"synchronised_slave_nodes\"`\n\tHeadMessageTimestamp   *int64   `json:\"head_message_timestamp\"`\n}\n\ntype node struct {\n\tName string\n\n\tDiskFree                 int64   `json:\"disk_free\"`\n\tDiskFreeLimit            int64   `json:\"disk_free_limit\"`\n\tDiskFreeAlarm            bool    `json:\"disk_free_alarm\"`\n\tFdTotal                  int64   `json:\"fd_total\"`\n\tFdUsed                   int64   `json:\"fd_used\"`\n\tMemLimit                 int64   `json:\"mem_limit\"`\n\tMemUsed                  int64   `json:\"mem_used\"`\n\tMemAlarm                 bool    `json:\"mem_alarm\"`\n\tProcTotal                int64   `json:\"proc_total\"`\n\tProcUsed                 int64   `json:\"proc_used\"`\n\tRunQueue                 int64   `json:\"run_queue\"`\n\tSocketsTotal             int64   `json:\"sockets_total\"`\n\tSocketsUsed              int64   `json:\"sockets_used\"`\n\tRunning                  bool    `json:\"running\"`\n\tUptime                   int64   `json:\"uptime\"`\n\tMnesiaDiskTxCount        int64   `json:\"mnesia_disk_tx_count\"`\n\tMnesiaDiskTxCountDetails details `json:\"mnesia_disk_tx_count_details\"`\n\tMnesiaRAMTxCount         int64   `json:\"mnesia_ram_tx_count\"`\n\tMnesiaRAMTxCountDetails  details `json:\"mnesia_ram_tx_count_details\"`\n\tGcNum                    int64   `json:\"gc_num\"`\n\tGcNumDetails             details `json:\"gc_num_details\"`\n\tGcBytesReclaimed         int64   `json:\"gc_bytes_reclaimed\"`\n\tGcBytesReclaimedDetails  details `json:\"gc_bytes_reclaimed_details\"`\n\tIoReadAvgTime            float64 `json:\"io_read_avg_time\"`\n\tIoReadAvgTimeDetails     details `json:\"io_read_avg_time_details\"`\n\tIoReadBytes              int64   `json:\"io_read_bytes\"`\n\tIoReadBytesDetails       details `json:\"io_read_bytes_details\"`\n\tIoWriteAvgTime           float64 `json:\"io_write_avg_time\"`\n\tIoWriteAvgTimeDetails    details `json:\"io_write_avg_time_details\"`\n\tIoWriteBytes             int64   `json:\"io_write_bytes\"`\n\tIoWriteBytesDetails      details `json:\"io_write_bytes_details\"`\n}\n\ntype exchange struct {\n\tName         string\n\tmessageStats `json:\"message_stats\"`\n\tType         string\n\tInternal     bool\n\tVhost        string\n\tDurable      bool\n\tAutoDelete   bool `json:\"auto_delete\"`\n}\n\ntype federationLinkChannelMessageStats struct {\n\tConfirm                 int64   `json:\"confirm\"`\n\tConfirmDetails          details `json:\"confirm_details\"`\n\tPublish                 int64   `json:\"publish\"`\n\tPublishDetails          details `json:\"publish_details\"`\n\tReturnUnroutable        int64   `json:\"return_unroutable\"`\n\tReturnUnroutableDetails details `json:\"return_unroutable_details\"`\n}\n\ntype federationLinkChannel struct {\n\tAcksUncommitted        int64                             `json:\"acks_uncommitted\"`\n\tConsumerCount          int64                             `json:\"consumer_count\"`\n\tMessagesUnacknowledged int64                             `json:\"messages_unacknowledged\"`\n\tMessagesUncommitted    int64                             `json:\"messages_uncommitted\"`\n\tMessagesUnconfirmed    int64                             `json:\"messages_unconfirmed\"`\n\tMessageStats           federationLinkChannelMessageStats `json:\"message_stats\"`\n}\n\ntype federationLink struct {\n\tType             string                `json:\"type\"`\n\tQueue            string                `json:\"queue\"`\n\tUpstreamQueue    string                `json:\"upstream_queue\"`\n\tExchange         string                `json:\"exchange\"`\n\tUpstreamExchange string                `json:\"upstream_exchange\"`\n\tVhost            string                `json:\"vhost\"`\n\tUpstream         string                `json:\"upstream\"`\n\tLocalChannel     federationLinkChannel `json:\"local_channel\"`\n}\n\ntype memoryResponse struct {\n\tMemory *memory `json:\"memory\"`\n}\n\n// memory details\ntype memory struct {\n\tConnectionReaders   int64       `json:\"connection_readers\"`\n\tConnectionWriters   int64       `json:\"connection_writers\"`\n\tConnectionChannels  int64       `json:\"connection_channels\"`\n\tConnectionOther     int64       `json:\"connection_other\"`\n\tQueueProcs          int64       `json:\"queue_procs\"`\n\tQueueSlaveProcs     int64       `json:\"queue_slave_procs\"`\n\tPlugins             int64       `json:\"plugins\"`\n\tOtherProc           int64       `json:\"other_proc\"`\n\tMetrics             int64       `json:\"metrics\"`\n\tMgmtDB              int64       `json:\"mgmt_db\"`\n\tMnesia              int64       `json:\"mnesia\"`\n\tOtherEts            int64       `json:\"other_ets\"`\n\tBinary              int64       `json:\"binary\"`\n\tMsgIndex            int64       `json:\"msg_index\"`\n\tCode                int64       `json:\"code\"`\n\tAtom                int64       `json:\"atom\"`\n\tOtherSystem         int64       `json:\"other_system\"`\n\tAllocatedUnused     int64       `json:\"allocated_unused\"`\n\tReservedUnallocated int64       `json:\"reserved_unallocated\"`\n\tTotal               interface{} `json:\"total\"`\n}\n\ntype errorResponse struct {\n\tError  string `json:\"error\"`\n\tReason string `json:\"reason\"`\n}\n\ntype gatherFunc func(r *RabbitMQ, acc telegraf.Accumulator)\n\nvar gatherFunctions = map[string]gatherFunc{\n\t\"exchange\":   gatherExchanges,\n\t\"federation\": gatherFederationLinks,\n\t\"node\":       gatherNodes,\n\t\"overview\":   gatherOverview,\n\t\"queue\":      gatherQueues,\n}\n\nfunc boolToInt(b bool) int64 {\n\tif b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\nfunc (*RabbitMQ) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *RabbitMQ) Init() error {\n\tvar err error\n\n\t// Create gather filters\n\tif err := r.createQueueFilter(); err != nil {\n\t\treturn err\n\t}\n\tif err := r.createUpstreamFilter(); err != nil {\n\t\treturn err\n\t}\n\n\t// Create a filter for the metrics\n\tif r.metricFilter, err = filter.NewIncludeExcludeFilter(r.MetricInclude, r.MetricExclude); err != nil {\n\t\treturn err\n\t}\n\n\ttlsCfg, err := r.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\ttr := &http.Transport{\n\t\tResponseHeaderTimeout: time.Duration(r.ResponseHeaderTimeout),\n\t\tTLSClientConfig:       tlsCfg,\n\t}\n\tr.client = &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   time.Duration(r.ClientTimeout),\n\t}\n\n\treturn nil\n}\n\nfunc (r *RabbitMQ) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor name, f := range gatherFunctions {\n\t\t// Query only metrics that are supported\n\t\tif !r.metricFilter.Match(name) {\n\t\t\tcontinue\n\t\t}\n\t\twg.Add(1)\n\t\tgo func(gf gatherFunc) {\n\t\t\tdefer wg.Done()\n\t\t\tgf(r, acc)\n\t\t}(f)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (r *RabbitMQ) requestEndpoint(u string) ([]byte, error) {\n\tif r.URL == \"\" {\n\t\tr.URL = defaultURL\n\t}\n\tendpoint := r.URL + u\n\tr.Log.Debugf(\"Requesting %q...\", endpoint)\n\n\treq, err := http.NewRequest(\"GET\", endpoint, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tusername := defaultUsername\n\tif !r.Username.Empty() {\n\t\tusernameSecret, err := r.Username.Get()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer usernameSecret.Destroy()\n\t\tusername = usernameSecret.String()\n\t}\n\n\tpassword := defaultPassword\n\tif !r.Password.Empty() {\n\t\tpasswordSecret, err := r.Password.Get()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer passwordSecret.Destroy()\n\t\tpassword = passwordSecret.String()\n\t}\n\n\treq.SetBasicAuth(username, password)\n\n\tresp, err := r.client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tr.Log.Debugf(\"HTTP status code: %v %v\", resp.StatusCode, http.StatusText(resp.StatusCode))\n\tif resp.StatusCode < 200 || resp.StatusCode > 299 {\n\t\treturn nil, fmt.Errorf(\"getting %q failed: %v %v\", u, resp.StatusCode, http.StatusText(resp.StatusCode))\n\t}\n\n\treturn io.ReadAll(resp.Body)\n}\n\nfunc (r *RabbitMQ) requestJSON(u string, target interface{}) error {\n\tbuf, err := r.requestEndpoint(u)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := json.Unmarshal(buf, target); err != nil {\n\t\tvar jsonErr *json.UnmarshalTypeError\n\t\tif errors.As(err, &jsonErr) {\n\t\t\t// Try to get the error reason from the response\n\t\t\tvar errResponse errorResponse\n\t\t\tif json.Unmarshal(buf, &errResponse) == nil && errResponse.Error != \"\" {\n\t\t\t\t// Return the error reason in the response\n\t\t\t\treturn fmt.Errorf(\"error response trying to get %q: %q (reason: %q)\", u, errResponse.Error, errResponse.Reason)\n\t\t\t}\n\t\t}\n\n\t\treturn fmt.Errorf(\"decoding answer from %q failed: %w\", u, err)\n\t}\n\n\treturn nil\n}\n\nfunc gatherOverview(r *RabbitMQ, acc telegraf.Accumulator) {\n\toverview := &overviewResponse{}\n\n\terr := r.requestJSON(\"/api/overview\", &overview)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tif overview.QueueTotals == nil || overview.ObjectTotals == nil || overview.MessageStats == nil {\n\t\tacc.AddError(errors.New(\"wrong answer from rabbitmq, probably auth issue\"))\n\t\treturn\n\t}\n\n\tvar clusteringListeners, amqpListeners int64 = 0, 0\n\tfor _, listener := range overview.Listeners {\n\t\tif listener.Protocol == \"clustering\" {\n\t\t\tclusteringListeners++\n\t\t} else if listener.Protocol == \"amqp\" {\n\t\t\tamqpListeners++\n\t\t}\n\t}\n\n\ttags := map[string]string{\"url\": r.URL}\n\tfields := map[string]interface{}{\n\t\t\"messages\":               overview.QueueTotals.Messages,\n\t\t\"messages_ready\":         overview.QueueTotals.MessagesReady,\n\t\t\"messages_unacked\":       overview.QueueTotals.MessagesUnacknowledged,\n\t\t\"channels\":               overview.ObjectTotals.Channels,\n\t\t\"connections\":            overview.ObjectTotals.Connections,\n\t\t\"consumers\":              overview.ObjectTotals.Consumers,\n\t\t\"exchanges\":              overview.ObjectTotals.Exchanges,\n\t\t\"queues\":                 overview.ObjectTotals.Queues,\n\t\t\"messages_acked\":         overview.MessageStats.Ack,\n\t\t\"messages_delivered\":     overview.MessageStats.Deliver,\n\t\t\"messages_delivered_get\": overview.MessageStats.DeliverGet,\n\t\t\"messages_published\":     overview.MessageStats.Publish,\n\t\t\"clustering_listeners\":   clusteringListeners,\n\t\t\"amqp_listeners\":         amqpListeners,\n\t\t\"return_unroutable\":      overview.MessageStats.ReturnUnroutable,\n\t\t\"return_unroutable_rate\": overview.MessageStats.ReturnUnroutableDetails.Rate,\n\t}\n\tacc.AddFields(\"rabbitmq_overview\", fields, tags)\n}\n\nfunc gatherNodes(r *RabbitMQ, acc telegraf.Accumulator) {\n\tallNodes := make([]*node, 0)\n\n\terr := r.requestJSON(\"/api/nodes\", &allNodes)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tnodes := allNodes[:0]\n\tfor _, singleNode := range allNodes {\n\t\tif r.shouldGatherNode(singleNode) {\n\t\t\tnodes = append(nodes, singleNode)\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, singleNode := range nodes {\n\t\twg.Add(1)\n\t\tgo func(singleNode *node) {\n\t\t\tdefer wg.Done()\n\n\t\t\ttags := map[string]string{\"url\": r.URL}\n\t\t\ttags[\"node\"] = singleNode.Name\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"disk_free\":                 singleNode.DiskFree,\n\t\t\t\t\"disk_free_limit\":           singleNode.DiskFreeLimit,\n\t\t\t\t\"disk_free_alarm\":           boolToInt(singleNode.DiskFreeAlarm),\n\t\t\t\t\"fd_total\":                  singleNode.FdTotal,\n\t\t\t\t\"fd_used\":                   singleNode.FdUsed,\n\t\t\t\t\"mem_limit\":                 singleNode.MemLimit,\n\t\t\t\t\"mem_used\":                  singleNode.MemUsed,\n\t\t\t\t\"mem_alarm\":                 boolToInt(singleNode.MemAlarm),\n\t\t\t\t\"proc_total\":                singleNode.ProcTotal,\n\t\t\t\t\"proc_used\":                 singleNode.ProcUsed,\n\t\t\t\t\"run_queue\":                 singleNode.RunQueue,\n\t\t\t\t\"sockets_total\":             singleNode.SocketsTotal,\n\t\t\t\t\"sockets_used\":              singleNode.SocketsUsed,\n\t\t\t\t\"uptime\":                    singleNode.Uptime,\n\t\t\t\t\"mnesia_disk_tx_count\":      singleNode.MnesiaDiskTxCount,\n\t\t\t\t\"mnesia_disk_tx_count_rate\": singleNode.MnesiaDiskTxCountDetails.Rate,\n\t\t\t\t\"mnesia_ram_tx_count\":       singleNode.MnesiaRAMTxCount,\n\t\t\t\t\"mnesia_ram_tx_count_rate\":  singleNode.MnesiaRAMTxCountDetails.Rate,\n\t\t\t\t\"gc_num\":                    singleNode.GcNum,\n\t\t\t\t\"gc_num_rate\":               singleNode.GcNumDetails.Rate,\n\t\t\t\t\"gc_bytes_reclaimed\":        singleNode.GcBytesReclaimed,\n\t\t\t\t\"gc_bytes_reclaimed_rate\":   singleNode.GcBytesReclaimedDetails.Rate,\n\t\t\t\t\"io_read_avg_time\":          singleNode.IoReadAvgTime,\n\t\t\t\t\"io_read_avg_time_rate\":     singleNode.IoReadAvgTimeDetails.Rate,\n\t\t\t\t\"io_read_bytes\":             singleNode.IoReadBytes,\n\t\t\t\t\"io_read_bytes_rate\":        singleNode.IoReadBytesDetails.Rate,\n\t\t\t\t\"io_write_avg_time\":         singleNode.IoWriteAvgTime,\n\t\t\t\t\"io_write_avg_time_rate\":    singleNode.IoWriteAvgTimeDetails.Rate,\n\t\t\t\t\"io_write_bytes\":            singleNode.IoWriteBytes,\n\t\t\t\t\"io_write_bytes_rate\":       singleNode.IoWriteBytesDetails.Rate,\n\t\t\t\t\"running\":                   boolToInt(singleNode.Running),\n\t\t\t}\n\n\t\t\tvar memory memoryResponse\n\t\t\terr = r.requestJSON(\"/api/nodes/\"+singleNode.Name+\"/memory\", &memory)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif memory.Memory != nil {\n\t\t\t\tfields[\"mem_connection_readers\"] = memory.Memory.ConnectionReaders\n\t\t\t\tfields[\"mem_connection_writers\"] = memory.Memory.ConnectionWriters\n\t\t\t\tfields[\"mem_connection_channels\"] = memory.Memory.ConnectionChannels\n\t\t\t\tfields[\"mem_connection_other\"] = memory.Memory.ConnectionOther\n\t\t\t\tfields[\"mem_queue_procs\"] = memory.Memory.QueueProcs\n\t\t\t\tfields[\"mem_queue_slave_procs\"] = memory.Memory.QueueSlaveProcs\n\t\t\t\tfields[\"mem_plugins\"] = memory.Memory.Plugins\n\t\t\t\tfields[\"mem_other_proc\"] = memory.Memory.OtherProc\n\t\t\t\tfields[\"mem_metrics\"] = memory.Memory.Metrics\n\t\t\t\tfields[\"mem_mgmt_db\"] = memory.Memory.MgmtDB\n\t\t\t\tfields[\"mem_mnesia\"] = memory.Memory.Mnesia\n\t\t\t\tfields[\"mem_other_ets\"] = memory.Memory.OtherEts\n\t\t\t\tfields[\"mem_binary\"] = memory.Memory.Binary\n\t\t\t\tfields[\"mem_msg_index\"] = memory.Memory.MsgIndex\n\t\t\t\tfields[\"mem_code\"] = memory.Memory.Code\n\t\t\t\tfields[\"mem_atom\"] = memory.Memory.Atom\n\t\t\t\tfields[\"mem_other_system\"] = memory.Memory.OtherSystem\n\t\t\t\tfields[\"mem_allocated_unused\"] = memory.Memory.AllocatedUnused\n\t\t\t\tfields[\"mem_reserved_unallocated\"] = memory.Memory.ReservedUnallocated\n\t\t\t\tswitch v := memory.Memory.Total.(type) {\n\t\t\t\tcase float64:\n\t\t\t\t\tfields[\"mem_total\"] = int64(v)\n\t\t\t\tcase map[string]interface{}:\n\t\t\t\t\tvar foundEstimator bool\n\t\t\t\t\tfor _, estimator := range []string{\"rss\", \"allocated\", \"erlang\"} {\n\t\t\t\t\t\tif x, found := v[estimator]; found {\n\t\t\t\t\t\t\tif total, ok := x.(float64); ok {\n\t\t\t\t\t\t\t\tfields[\"mem_total\"] = int64(total)\n\t\t\t\t\t\t\t\tfoundEstimator = true\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tacc.AddError(fmt.Errorf(\"unknown type %T for %q total memory\", x, estimator))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif !foundEstimator {\n\t\t\t\t\t\tacc.AddError(fmt.Errorf(\"no known memory estimation in %v\", v))\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"unknown type %T for total memory\", memory.Memory.Total))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tacc.AddFields(\"rabbitmq_node\", fields, tags)\n\t\t}(singleNode)\n\t}\n\n\twg.Wait()\n}\n\nfunc gatherQueues(r *RabbitMQ, acc telegraf.Accumulator) {\n\tif r.excludeEveryQueue {\n\t\treturn\n\t}\n\t// Gather information about queues\n\tqueues := make([]queue, 0)\n\terr := r.requestJSON(\"/api/queues\", &queues)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, queue := range queues {\n\t\tif !r.queueFilter.Match(queue.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"url\":         r.URL,\n\t\t\t\"queue\":       queue.Name,\n\t\t\t\"vhost\":       queue.Vhost,\n\t\t\t\"node\":        queue.Node,\n\t\t\t\"durable\":     strconv.FormatBool(queue.Durable),\n\t\t\t\"auto_delete\": strconv.FormatBool(queue.AutoDelete),\n\t\t}\n\n\t\tif r.IncludeQueueTypeTag {\n\t\t\tif queue.Type == \"\" {\n\t\t\t\ttags[\"type\"] = \"classic\"\n\t\t\t} else {\n\t\t\t\ttags[\"type\"] = queue.Type\n\t\t\t}\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t// common information\n\t\t\t\"consumers\":                queue.Consumers,\n\t\t\t\"consumer_utilisation\":     queue.ConsumerUtilisation,\n\t\t\t\"idle_since\":               queue.IdleSince,\n\t\t\t\"slave_nodes\":              len(queue.SlaveNodes),\n\t\t\t\"synchronised_slave_nodes\": len(queue.SynchronisedSlaveNodes),\n\t\t\t\"memory\":                   queue.Memory,\n\t\t\t// messages information\n\t\t\t\"message_bytes\":             queue.MessageBytes,\n\t\t\t\"message_bytes_ready\":       queue.MessageBytesReady,\n\t\t\t\"message_bytes_unacked\":     queue.MessageBytesUnacknowledged,\n\t\t\t\"message_bytes_ram\":         queue.MessageRAM,\n\t\t\t\"message_bytes_persist\":     queue.MessagePersistent,\n\t\t\t\"messages\":                  queue.Messages,\n\t\t\t\"messages_ready\":            queue.MessagesReady,\n\t\t\t\"messages_unack\":            queue.MessagesUnacknowledged,\n\t\t\t\"messages_ack\":              queue.messageStats.Ack,\n\t\t\t\"messages_ack_rate\":         queue.messageStats.AckDetails.Rate,\n\t\t\t\"messages_deliver\":          queue.messageStats.Deliver,\n\t\t\t\"messages_deliver_rate\":     queue.messageStats.DeliverDetails.Rate,\n\t\t\t\"messages_deliver_get\":      queue.messageStats.DeliverGet,\n\t\t\t\"messages_deliver_get_rate\": queue.messageStats.DeliverGetDetails.Rate,\n\t\t\t\"messages_publish\":          queue.messageStats.Publish,\n\t\t\t\"messages_publish_rate\":     queue.messageStats.PublishDetails.Rate,\n\t\t\t\"messages_redeliver\":        queue.messageStats.Redeliver,\n\t\t\t\"messages_redeliver_rate\":   queue.messageStats.RedeliverDetails.Rate,\n\t\t}\n\n\t\tif queue.HeadMessageTimestamp != nil {\n\t\t\tfields[\"head_message_timestamp\"] = *queue.HeadMessageTimestamp\n\t\t}\n\n\t\tacc.AddFields(\n\t\t\t\"rabbitmq_queue\",\n\t\t\tfields,\n\t\t\ttags,\n\t\t)\n\t}\n}\n\nfunc gatherExchanges(r *RabbitMQ, acc telegraf.Accumulator) {\n\t// Gather information about exchanges\n\texchanges := make([]exchange, 0)\n\terr := r.requestJSON(\"/api/exchanges\", &exchanges)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, exchange := range exchanges {\n\t\tif !r.shouldGatherExchange(exchange.Name) {\n\t\t\tcontinue\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"url\":         r.URL,\n\t\t\t\"exchange\":    exchange.Name,\n\t\t\t\"type\":        exchange.Type,\n\t\t\t\"vhost\":       exchange.Vhost,\n\t\t\t\"internal\":    strconv.FormatBool(exchange.Internal),\n\t\t\t\"durable\":     strconv.FormatBool(exchange.Durable),\n\t\t\t\"auto_delete\": strconv.FormatBool(exchange.AutoDelete),\n\t\t}\n\n\t\tacc.AddFields(\n\t\t\t\"rabbitmq_exchange\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       exchange.messageStats.PublishIn,\n\t\t\t\t\"messages_publish_in_rate\":  exchange.messageStats.PublishInDetails.Rate,\n\t\t\t\t\"messages_publish_out\":      exchange.messageStats.PublishOut,\n\t\t\t\t\"messages_publish_out_rate\": exchange.messageStats.PublishOutDetails.Rate,\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n}\n\nfunc gatherFederationLinks(r *RabbitMQ, acc telegraf.Accumulator) {\n\t// Gather information about federation links\n\tfederationLinks := make([]federationLink, 0)\n\terr := r.requestJSON(\"/api/federation-links\", &federationLinks)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, link := range federationLinks {\n\t\tif !r.shouldGatherFederationLink(link) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"url\":      r.URL,\n\t\t\t\"type\":     link.Type,\n\t\t\t\"vhost\":    link.Vhost,\n\t\t\t\"upstream\": link.Upstream,\n\t\t}\n\n\t\tif link.Type == \"exchange\" {\n\t\t\ttags[\"exchange\"] = link.Exchange\n\t\t\ttags[\"upstream_exchange\"] = link.UpstreamExchange\n\t\t} else {\n\t\t\ttags[\"queue\"] = link.Queue\n\t\t\ttags[\"upstream_queue\"] = link.UpstreamQueue\n\t\t}\n\n\t\tacc.AddFields(\n\t\t\t\"rabbitmq_federation\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"acks_uncommitted\":           link.LocalChannel.AcksUncommitted,\n\t\t\t\t\"consumers\":                  link.LocalChannel.ConsumerCount,\n\t\t\t\t\"messages_unacknowledged\":    link.LocalChannel.MessagesUnacknowledged,\n\t\t\t\t\"messages_uncommitted\":       link.LocalChannel.MessagesUncommitted,\n\t\t\t\t\"messages_unconfirmed\":       link.LocalChannel.MessagesUnconfirmed,\n\t\t\t\t\"messages_confirm\":           link.LocalChannel.MessageStats.Confirm,\n\t\t\t\t\"messages_publish\":           link.LocalChannel.MessageStats.Publish,\n\t\t\t\t\"messages_return_unroutable\": link.LocalChannel.MessageStats.ReturnUnroutable,\n\t\t\t},\n\t\t\ttags,\n\t\t)\n\t}\n}\n\nfunc (r *RabbitMQ) shouldGatherNode(node *node) bool {\n\tif len(r.Nodes) == 0 {\n\t\treturn true\n\t}\n\n\tfor _, name := range r.Nodes {\n\t\tif name == node.Name {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (r *RabbitMQ) createQueueFilter() error {\n\tqueueFilter, err := filter.NewIncludeExcludeFilter(r.QueueInclude, r.QueueExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr.queueFilter = queueFilter\n\n\tfor _, q := range r.QueueExclude {\n\t\tif q == \"*\" {\n\t\t\tr.excludeEveryQueue = true\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (r *RabbitMQ) createUpstreamFilter() error {\n\tupstreamFilter, err := filter.NewIncludeExcludeFilter(r.FederationUpstreamInclude, r.FederationUpstreamExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\tr.upstreamFilter = upstreamFilter\n\n\treturn nil\n}\n\nfunc (r *RabbitMQ) shouldGatherExchange(exchangeName string) bool {\n\tif len(r.Exchanges) == 0 {\n\t\treturn true\n\t}\n\n\tfor _, name := range r.Exchanges {\n\t\tif name == exchangeName {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (r *RabbitMQ) shouldGatherFederationLink(link federationLink) bool {\n\tif !r.upstreamFilter.Match(link.Upstream) {\n\t\treturn false\n\t}\n\n\tswitch link.Type {\n\tcase \"exchange\":\n\t\treturn r.shouldGatherExchange(link.Exchange)\n\tcase \"queue\":\n\t\treturn r.queueFilter.Match(link.Queue)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"rabbitmq\", func() telegraf.Input {\n\t\treturn &RabbitMQ{\n\t\t\tResponseHeaderTimeout: config.Duration(defaultResponseHeaderTimeout * time.Second),\n\t\t\tClientTimeout:         config.Duration(defaultClientTimeout * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/rabbitmq_test.go",
    "content": "package rabbitmq\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRabbitMQGeneratesMetricsSet1(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/api/overview\":\n\t\t\tjsonFilePath = \"testdata/set1/overview.json\"\n\t\tcase \"/api/nodes\":\n\t\t\tjsonFilePath = \"testdata/set1/nodes.json\"\n\t\tcase \"/api/queues\":\n\t\t\tjsonFilePath = \"testdata/set1/queues.json\"\n\t\tcase \"/api/exchanges\":\n\t\t\tjsonFilePath = \"testdata/set1/exchanges.json\"\n\t\tcase \"/api/federation-links\":\n\t\t\tjsonFilePath = \"testdata/set1/federation-links.json\"\n\t\tcase \"/api/nodes/rabbit@vagrant-ubuntu-trusty-64/memory\":\n\t\t\tjsonFilePath = \"testdata/set1/memory.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"unknown path %q\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Define test cases\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"rabbitmq_overview\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\": ts.URL,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages\":               int64(50),\n\t\t\t\t\"messages_ready\":         int64(72),\n\t\t\t\t\"messages_unacked\":       int64(94),\n\t\t\t\t\"messages_acked\":         int64(5246),\n\t\t\t\t\"messages_delivered\":     int64(5234),\n\t\t\t\t\"messages_delivered_get\": int64(3333),\n\t\t\t\t\"messages_published\":     int64(5258),\n\t\t\t\t\"channels\":               int64(44),\n\t\t\t\t\"connections\":            int64(44),\n\t\t\t\t\"consumers\":              int64(70),\n\t\t\t\t\"exchanges\":              int64(43),\n\t\t\t\t\"queues\":                 int64(66),\n\t\t\t\t\"clustering_listeners\":   int64(2),\n\t\t\t\t\"amqp_listeners\":         int64(2),\n\t\t\t\t\"return_unroutable\":      int64(10),\n\t\t\t\t\"return_unroutable_rate\": float64(3.3),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n\t\t\t\t\"queue\":       \"reply_a716f0523cd44941ad2ea6ce4a3869c3\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"sorandomsorandom\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(3),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"head_message_timestamp\":    int64(1446362534),\n\t\t\t\t\"memory\":                    int64(143776),\n\t\t\t\t\"message_bytes\":             int64(3),\n\t\t\t\t\"message_bytes_ready\":       int64(4),\n\t\t\t\t\"message_bytes_unacked\":     int64(5),\n\t\t\t\t\"message_bytes_ram\":         int64(6),\n\t\t\t\t\"message_bytes_persist\":     int64(7),\n\t\t\t\t\"messages\":                  int64(44),\n\t\t\t\t\"messages_ready\":            int64(32),\n\t\t\t\t\"messages_unack\":            int64(44),\n\t\t\t\t\"messages_ack\":              int64(3457),\n\t\t\t\t\"messages_ack_rate\":         float64(9.9),\n\t\t\t\t\"messages_deliver\":          int64(22222),\n\t\t\t\t\"messages_deliver_rate\":     float64(333.4),\n\t\t\t\t\"messages_deliver_get\":      int64(3457),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.2),\n\t\t\t\t\"messages_publish\":          int64(3457),\n\t\t\t\t\"messages_publish_rate\":     float64(11.2),\n\t\t\t\t\"messages_redeliver\":        int64(33),\n\t\t\t\t\"messages_redeliver_rate\":   float64(2.5),\n\t\t\t\t\"idle_since\":                \"2015-11-01 8:22:14\",\n\t\t\t\t\"slave_nodes\":               int64(1),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"node\":        \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n\t\t\t\t\"queue\":       \"stream_queue_example\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"sorandomsorandom\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(2),\n\t\t\t\t\"consumer_utilisation\":      float64(0.8),\n\t\t\t\t\"head_message_timestamp\":    int64(1446366000),\n\t\t\t\t\"memory\":                    int64(95000),\n\t\t\t\t\"message_bytes\":             int64(1),\n\t\t\t\t\"message_bytes_ready\":       int64(2),\n\t\t\t\t\"message_bytes_unacked\":     int64(3),\n\t\t\t\t\"message_bytes_ram\":         int64(4),\n\t\t\t\t\"message_bytes_persist\":     int64(5),\n\t\t\t\t\"messages\":                  int64(25),\n\t\t\t\t\"messages_ready\":            int64(20),\n\t\t\t\t\"messages_unack\":            int64(25),\n\t\t\t\t\"messages_ack\":              int64(1500),\n\t\t\t\t\"messages_ack_rate\":         float64(5.5),\n\t\t\t\t\"messages_deliver\":          int64(10000),\n\t\t\t\t\"messages_deliver_rate\":     float64(200.0),\n\t\t\t\t\"messages_deliver_get\":      int64(1500),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.1),\n\t\t\t\t\"messages_publish\":          int64(1500),\n\t\t\t\t\"messages_publish_rate\":     float64(8.5),\n\t\t\t\t\"messages_redeliver\":        int64(15),\n\t\t\t\t\"messages_redeliver_rate\":   float64(1.2),\n\t\t\t\t\"idle_since\":                \"2015-11-01 9:15:30\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"node\":        \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n\t\t\t\t\"queue\":       \"no-type-queue\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"sorandomsorandom\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(0.9),\n\t\t\t\t\"head_message_timestamp\":    int64(1446372000),\n\t\t\t\t\"memory\":                    int64(50000),\n\t\t\t\t\"message_bytes\":             int64(1),\n\t\t\t\t\"message_bytes_ready\":       int64(1),\n\t\t\t\t\"message_bytes_unacked\":     int64(1),\n\t\t\t\t\"message_bytes_ram\":         int64(1),\n\t\t\t\t\"message_bytes_persist\":     int64(2),\n\t\t\t\t\"messages\":                  int64(10),\n\t\t\t\t\"messages_ready\":            int64(8),\n\t\t\t\t\"messages_unack\":            int64(10),\n\t\t\t\t\"messages_ack\":              int64(500),\n\t\t\t\t\"messages_ack_rate\":         float64(2.0),\n\t\t\t\t\"messages_deliver\":          int64(2000),\n\t\t\t\t\"messages_deliver_rate\":     float64(50.0),\n\t\t\t\t\"messages_deliver_get\":      int64(500),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.1),\n\t\t\t\t\"messages_publish\":          int64(500),\n\t\t\t\t\"messages_publish_rate\":     float64(3.0),\n\t\t\t\t\"messages_redeliver\":        int64(5),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.5),\n\t\t\t\t\"idle_since\":                \"2015-11-01 10:30:00\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"node\":        \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n\t\t\t\t\"queue\":       \"invalid-type-queue\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"sorandomsorandom\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(2),\n\t\t\t\t\"consumer_utilisation\":      float64(0.85),\n\t\t\t\t\"head_message_timestamp\":    int64(1446375000),\n\t\t\t\t\"memory\":                    int64(75000),\n\t\t\t\t\"message_bytes\":             int64(1),\n\t\t\t\t\"message_bytes_ready\":       int64(1),\n\t\t\t\t\"message_bytes_unacked\":     int64(2),\n\t\t\t\t\"message_bytes_ram\":         int64(2),\n\t\t\t\t\"message_bytes_persist\":     int64(3),\n\t\t\t\t\"messages\":                  int64(15),\n\t\t\t\t\"messages_ready\":            int64(12),\n\t\t\t\t\"messages_unack\":            int64(15),\n\t\t\t\t\"messages_ack\":              int64(750),\n\t\t\t\t\"messages_ack_rate\":         float64(3.0),\n\t\t\t\t\"messages_deliver\":          int64(3000),\n\t\t\t\t\"messages_deliver_rate\":     float64(75.0),\n\t\t\t\t\"messages_deliver_get\":      int64(750),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.1),\n\t\t\t\t\"messages_publish\":          int64(750),\n\t\t\t\t\"messages_publish_rate\":     float64(4.5),\n\t\t\t\t\"messages_redeliver\":        int64(8),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.8),\n\t\t\t\t\"idle_since\":                \"2015-11-01 11:45:00\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_node\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node\": \"rabbit@vagrant-ubuntu-trusty-64\",\n\t\t\t\t\"url\":  ts.URL,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"disk_free\":                 int64(3776),\n\t\t\t\t\"disk_free_limit\":           int64(50000000),\n\t\t\t\t\"disk_free_alarm\":           int64(0),\n\t\t\t\t\"fd_total\":                  int64(1024),\n\t\t\t\t\"fd_used\":                   int64(63),\n\t\t\t\t\"mem_limit\":                 int64(2503),\n\t\t\t\t\"mem_used\":                  int64(159707080),\n\t\t\t\t\"mem_alarm\":                 int64(1),\n\t\t\t\t\"proc_total\":                int64(1048576),\n\t\t\t\t\"proc_used\":                 int64(783),\n\t\t\t\t\"run_queue\":                 int64(0),\n\t\t\t\t\"sockets_total\":             int64(829),\n\t\t\t\t\"sockets_used\":              int64(45),\n\t\t\t\t\"uptime\":                    int64(7464827),\n\t\t\t\t\"running\":                   int64(1),\n\t\t\t\t\"mnesia_disk_tx_count\":      int64(16),\n\t\t\t\t\"mnesia_ram_tx_count\":       int64(296),\n\t\t\t\t\"mnesia_disk_tx_count_rate\": float64(1.1),\n\t\t\t\t\"mnesia_ram_tx_count_rate\":  float64(2.2),\n\t\t\t\t\"gc_num\":                    int64(57280132),\n\t\t\t\t\"gc_bytes_reclaimed\":        int64(2533),\n\t\t\t\t\"gc_num_rate\":               float64(274.2),\n\t\t\t\t\"gc_bytes_reclaimed_rate\":   float64(16490856.3),\n\t\t\t\t\"io_read_avg_time\":          float64(983.0),\n\t\t\t\t\"io_read_avg_time_rate\":     float64(88.77),\n\t\t\t\t\"io_read_bytes\":             int64(1111),\n\t\t\t\t\"io_read_bytes_rate\":        float64(99.99),\n\t\t\t\t\"io_write_avg_time\":         float64(134.0),\n\t\t\t\t\"io_write_avg_time_rate\":    float64(4.32),\n\t\t\t\t\"io_write_bytes\":            int64(823),\n\t\t\t\t\"io_write_bytes_rate\":       float64(32.8),\n\t\t\t\t\"mem_connection_readers\":    int64(1234),\n\t\t\t\t\"mem_connection_writers\":    int64(5678),\n\t\t\t\t\"mem_connection_channels\":   int64(1133),\n\t\t\t\t\"mem_connection_other\":      int64(2840),\n\t\t\t\t\"mem_queue_procs\":           int64(2840),\n\t\t\t\t\"mem_queue_slave_procs\":     int64(0),\n\t\t\t\t\"mem_plugins\":               int64(1755976),\n\t\t\t\t\"mem_other_proc\":            int64(23056584),\n\t\t\t\t\"mem_metrics\":               int64(196536),\n\t\t\t\t\"mem_mgmt_db\":               int64(491272),\n\t\t\t\t\"mem_mnesia\":                int64(115600),\n\t\t\t\t\"mem_other_ets\":             int64(2121872),\n\t\t\t\t\"mem_binary\":                int64(418848),\n\t\t\t\t\"mem_msg_index\":             int64(42848),\n\t\t\t\t\"mem_code\":                  int64(25179322),\n\t\t\t\t\"mem_atom\":                  int64(1041593),\n\t\t\t\t\"mem_other_system\":          int64(14741981),\n\t\t\t\t\"mem_allocated_unused\":      int64(38208528),\n\t\t\t\t\"mem_reserved_unallocated\":  int64(0),\n\t\t\t\t\"mem_total\":                 int64(83025920),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"true\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"exchange\":    \"reply_a716f0523cd44941ad2ea6ce4a3869c3\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"direct\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"sorandomsorandom\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(3678),\n\t\t\t\t\"messages_publish_in_rate\":  float64(3.2),\n\t\t\t\t\"messages_publish_out\":      int64(3677),\n\t\t\t\t\"messages_publish_out_rate\": float64(5.1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_federation\",\n\t\t\tmap[string]string{\n\t\t\t\t\"queue\":          \"exampleLocalQueue\",\n\t\t\t\t\"type\":           \"queue\",\n\t\t\t\t\"upstream\":       \"ExampleFederationUpstream\",\n\t\t\t\t\"upstream_queue\": \"exampleUpstreamQueue\",\n\t\t\t\t\"url\":            ts.URL,\n\t\t\t\t\"vhost\":          \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"acks_uncommitted\":           int64(1),\n\t\t\t\t\"consumers\":                  int64(2),\n\t\t\t\t\"messages_unacknowledged\":    int64(3),\n\t\t\t\t\"messages_uncommitted\":       int64(4),\n\t\t\t\t\"messages_unconfirmed\":       int64(5),\n\t\t\t\t\"messages_confirm\":           int64(67),\n\t\t\t\t\"messages_publish\":           int64(890),\n\t\t\t\t\"messages_return_unroutable\": int64(1),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Run the test\n\tplugin := &RabbitMQ{\n\t\tURL: ts.URL,\n\t\tLog: testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tacc.Wait(len(expected))\n\trequire.Empty(t, acc.Errors)\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestRabbitMQGeneratesMetricsSet2(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/api/overview\":\n\t\t\tjsonFilePath = \"testdata/set2/overview.json\"\n\t\tcase \"/api/nodes\":\n\t\t\tjsonFilePath = \"testdata/set2/nodes.json\"\n\t\tcase \"/api/queues\":\n\t\t\tjsonFilePath = \"testdata/set2/queues.json\"\n\t\tcase \"/api/exchanges\":\n\t\t\tjsonFilePath = \"testdata/set2/exchanges.json\"\n\t\tcase \"/api/federation-links\":\n\t\t\tjsonFilePath = \"testdata/set2/federation-links.json\"\n\t\tcase \"/api/nodes/rabbit@rmqserver/memory\":\n\t\t\tjsonFilePath = \"testdata/set2/memory.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"unknown path %q\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Define test cases\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\"rabbitmq_overview\",\n\t\t\tmap[string]string{\n\t\t\t\t\"url\": ts.URL,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages\":               int64(30),\n\t\t\t\t\"messages_ready\":         int64(30),\n\t\t\t\t\"messages_unacked\":       int64(0),\n\t\t\t\t\"messages_acked\":         int64(3736443),\n\t\t\t\t\"messages_delivered\":     int64(3736446),\n\t\t\t\t\"messages_delivered_get\": int64(3736446),\n\t\t\t\t\"messages_published\":     int64(770025),\n\t\t\t\t\"channels\":               int64(43),\n\t\t\t\t\"connections\":            int64(43),\n\t\t\t\t\"consumers\":              int64(40),\n\t\t\t\t\"exchanges\":              int64(8),\n\t\t\t\t\"queues\":                 int64(37),\n\t\t\t\t\"clustering_listeners\":   int64(1),\n\t\t\t\t\"amqp_listeners\":         int64(2),\n\t\t\t\t\"return_unroutable\":      int64(0),\n\t\t\t\t\"return_unroutable_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqserver\",\n\t\t\t\t\"queue\":       \"39fd2caf-63e5-41e3-c15a-ba8fa11434b2\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"memory\":                    int64(15840),\n\t\t\t\t\"message_bytes\":             int64(0),\n\t\t\t\t\"message_bytes_ready\":       int64(0),\n\t\t\t\t\"message_bytes_unacked\":     int64(0),\n\t\t\t\t\"message_bytes_ram\":         int64(0),\n\t\t\t\t\"message_bytes_persist\":     int64(0),\n\t\t\t\t\"messages\":                  int64(0),\n\t\t\t\t\"messages_ready\":            int64(0),\n\t\t\t\t\"messages_unack\":            int64(0),\n\t\t\t\t\"messages_ack\":              int64(180),\n\t\t\t\t\"messages_ack_rate\":         float64(0.0),\n\t\t\t\t\"messages_deliver\":          int64(180),\n\t\t\t\t\"messages_deliver_rate\":     float64(0.0),\n\t\t\t\t\"messages_deliver_get\":      int64(180),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.0),\n\t\t\t\t\"messages_publish\":          int64(180),\n\t\t\t\t\"messages_publish_rate\":     float64(0.0),\n\t\t\t\t\"messages_redeliver\":        int64(0),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.0),\n\t\t\t\t\"idle_since\":                \"2021-06-28 15:54:14\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqserver\",\n\t\t\t\t\"queue\":       \"39fd2cb4-aa2d-c08b-457a-62d0893523a1\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"memory\":                    int64(15600),\n\t\t\t\t\"message_bytes\":             int64(0),\n\t\t\t\t\"message_bytes_ready\":       int64(0),\n\t\t\t\t\"message_bytes_unacked\":     int64(0),\n\t\t\t\t\"message_bytes_ram\":         int64(0),\n\t\t\t\t\"message_bytes_persist\":     int64(0),\n\t\t\t\t\"messages\":                  int64(0),\n\t\t\t\t\"messages_ready\":            int64(0),\n\t\t\t\t\"messages_unack\":            int64(0),\n\t\t\t\t\"messages_ack\":              int64(177),\n\t\t\t\t\"messages_ack_rate\":         float64(0.0),\n\t\t\t\t\"messages_deliver\":          int64(177),\n\t\t\t\t\"messages_deliver_rate\":     float64(0.0),\n\t\t\t\t\"messages_deliver_get\":      int64(177),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.0),\n\t\t\t\t\"messages_publish\":          int64(177),\n\t\t\t\t\"messages_publish_rate\":     float64(0.0),\n\t\t\t\t\"messages_redeliver\":        int64(0),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.0),\n\t\t\t\t\"idle_since\":                \"2021-06-28 15:54:14\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqserver\",\n\t\t\t\t\"queue\":       \"39fd2cb5-3820-e01b-6e20-ba29d5553fc3\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"memory\":                    int64(15584),\n\t\t\t\t\"message_bytes\":             int64(0),\n\t\t\t\t\"message_bytes_ready\":       int64(0),\n\t\t\t\t\"message_bytes_unacked\":     int64(0),\n\t\t\t\t\"message_bytes_ram\":         int64(0),\n\t\t\t\t\"message_bytes_persist\":     int64(0),\n\t\t\t\t\"messages\":                  int64(0),\n\t\t\t\t\"messages_ready\":            int64(0),\n\t\t\t\t\"messages_unack\":            int64(0),\n\t\t\t\t\"messages_ack\":              int64(175),\n\t\t\t\t\"messages_ack_rate\":         float64(0.0),\n\t\t\t\t\"messages_deliver\":          int64(175),\n\t\t\t\t\"messages_deliver_rate\":     float64(0.0),\n\t\t\t\t\"messages_deliver_get\":      int64(175),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.0),\n\t\t\t\t\"messages_publish\":          int64(175),\n\t\t\t\t\"messages_publish_rate\":     float64(0.0),\n\t\t\t\t\"messages_redeliver\":        int64(0),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.0),\n\t\t\t\t\"idle_since\":                \"2021-06-28 15:54:15\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_node\",\n\t\t\tmap[string]string{\n\t\t\t\t\"node\": \"rabbit@rmqserver\",\n\t\t\t\t\"url\":  ts.URL,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"disk_free\":                 int64(25086496768),\n\t\t\t\t\"disk_free_limit\":           int64(50000000),\n\t\t\t\t\"disk_free_alarm\":           int64(0),\n\t\t\t\t\"fd_total\":                  int64(65536),\n\t\t\t\t\"fd_used\":                   int64(78),\n\t\t\t\t\"mem_limit\":                 int64(1717546188),\n\t\t\t\t\"mem_used\":                  int64(387645440),\n\t\t\t\t\"mem_alarm\":                 int64(0),\n\t\t\t\t\"proc_total\":                int64(1048576),\n\t\t\t\t\"proc_used\":                 int64(1128),\n\t\t\t\t\"run_queue\":                 int64(1),\n\t\t\t\t\"sockets_total\":             int64(58893),\n\t\t\t\t\"sockets_used\":              int64(43),\n\t\t\t\t\"uptime\":                    int64(4150152129),\n\t\t\t\t\"running\":                   int64(1),\n\t\t\t\t\"mnesia_disk_tx_count\":      int64(103),\n\t\t\t\t\"mnesia_ram_tx_count\":       int64(2257),\n\t\t\t\t\"mnesia_disk_tx_count_rate\": float64(0.0),\n\t\t\t\t\"mnesia_ram_tx_count_rate\":  float64(0.0),\n\t\t\t\t\"gc_num\":                    int64(329526389),\n\t\t\t\t\"gc_bytes_reclaimed\":        int64(13660012170840),\n\t\t\t\t\"gc_num_rate\":               float64(125.2),\n\t\t\t\t\"gc_bytes_reclaimed_rate\":   float64(6583379.2),\n\t\t\t\t\"io_read_avg_time\":          float64(0.0),\n\t\t\t\t\"io_read_avg_time_rate\":     float64(0.0),\n\t\t\t\t\"io_read_bytes\":             int64(1),\n\t\t\t\t\"io_read_bytes_rate\":        float64(0.0),\n\t\t\t\t\"io_write_avg_time\":         float64(0.0),\n\t\t\t\t\"io_write_avg_time_rate\":    float64(0.0),\n\t\t\t\t\"io_write_bytes\":            int64(193066),\n\t\t\t\t\"io_write_bytes_rate\":       float64(0.0),\n\t\t\t\t\"mem_connection_readers\":    int64(1246768),\n\t\t\t\t\"mem_connection_writers\":    int64(72108),\n\t\t\t\t\"mem_connection_channels\":   int64(308588),\n\t\t\t\t\"mem_connection_other\":      int64(4883596),\n\t\t\t\t\"mem_queue_procs\":           int64(780996),\n\t\t\t\t\"mem_queue_slave_procs\":     int64(0),\n\t\t\t\t\"mem_plugins\":               int64(11932828),\n\t\t\t\t\"mem_other_proc\":            int64(39203520),\n\t\t\t\t\"mem_metrics\":               int64(626932),\n\t\t\t\t\"mem_mgmt_db\":               int64(3341264),\n\t\t\t\t\"mem_mnesia\":                int64(396016),\n\t\t\t\t\"mem_other_ets\":             int64(3771384),\n\t\t\t\t\"mem_binary\":                int64(209324208),\n\t\t\t\t\"mem_msg_index\":             int64(32648),\n\t\t\t\t\"mem_code\":                  int64(32810827),\n\t\t\t\t\"mem_atom\":                  int64(1458513),\n\t\t\t\t\"mem_other_system\":          int64(14284124),\n\t\t\t\t\"mem_allocated_unused\":      int64(61026048),\n\t\t\t\t\"mem_reserved_unallocated\":  int64(0),\n\t\t\t\t\"mem_total\":                 int64(385548288),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqserver\",\n\t\t\t\t\"queue\":       \"no-type-queue-set2\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"memory\":                    int64(12000),\n\t\t\t\t\"message_bytes\":             int64(0),\n\t\t\t\t\"message_bytes_ready\":       int64(0),\n\t\t\t\t\"message_bytes_unacked\":     int64(0),\n\t\t\t\t\"message_bytes_ram\":         int64(0),\n\t\t\t\t\"message_bytes_persist\":     int64(0),\n\t\t\t\t\"messages\":                  int64(0),\n\t\t\t\t\"messages_ready\":            int64(0),\n\t\t\t\t\"messages_unack\":            int64(0),\n\t\t\t\t\"messages_ack\":              int64(100),\n\t\t\t\t\"messages_ack_rate\":         float64(0.0),\n\t\t\t\t\"messages_deliver\":          int64(100),\n\t\t\t\t\"messages_deliver_rate\":     float64(0.0),\n\t\t\t\t\"messages_deliver_get\":      int64(100),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.0),\n\t\t\t\t\"messages_publish\":          int64(100),\n\t\t\t\t\"messages_publish_rate\":     float64(0.0),\n\t\t\t\t\"messages_redeliver\":        int64(0),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.0),\n\t\t\t\t\"idle_since\":                \"2021-06-28 15:54:17\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_queue\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"node\":        \"rabbit@rmqserver\",\n\t\t\t\t\"queue\":       \"invalid-type-queue-set2\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"consumers\":                 int64(1),\n\t\t\t\t\"consumer_utilisation\":      float64(1.0),\n\t\t\t\t\"memory\":                    int64(15000),\n\t\t\t\t\"message_bytes\":             int64(0),\n\t\t\t\t\"message_bytes_ready\":       int64(0),\n\t\t\t\t\"message_bytes_unacked\":     int64(0),\n\t\t\t\t\"message_bytes_ram\":         int64(0),\n\t\t\t\t\"message_bytes_persist\":     int64(0),\n\t\t\t\t\"messages\":                  int64(0),\n\t\t\t\t\"messages_ready\":            int64(0),\n\t\t\t\t\"messages_unack\":            int64(0),\n\t\t\t\t\"messages_ack\":              int64(200),\n\t\t\t\t\"messages_ack_rate\":         float64(0.0),\n\t\t\t\t\"messages_deliver\":          int64(200),\n\t\t\t\t\"messages_deliver_rate\":     float64(0.0),\n\t\t\t\t\"messages_deliver_get\":      int64(200),\n\t\t\t\t\"messages_deliver_get_rate\": float64(0.0),\n\t\t\t\t\"messages_publish\":          int64(200),\n\t\t\t\t\"messages_publish_rate\":     float64(0.0),\n\t\t\t\t\"messages_redeliver\":        int64(0),\n\t\t\t\t\"messages_redeliver_rate\":   float64(0.0),\n\t\t\t\t\"idle_since\":                \"2021-06-28 16:30:45\",\n\t\t\t\t\"slave_nodes\":               int64(0),\n\t\t\t\t\"synchronised_slave_nodes\":  int64(0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"direct\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(284725),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(284572),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.direct\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"direct\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.fanout\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"fanout\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.headers\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"headers\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.match\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"headers\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.rabbitmq.trace\",\n\t\t\t\t\"internal\":    \"true\",\n\t\t\t\t\"type\":        \"topic\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"false\",\n\t\t\t\t\"durable\":     \"true\",\n\t\t\t\t\"exchange\":    \"amq.topic\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"topic\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(0),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(0),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\"rabbitmq_exchange\",\n\t\t\tmap[string]string{\n\t\t\t\t\"auto_delete\": \"true\",\n\t\t\t\t\"durable\":     \"false\",\n\t\t\t\t\"exchange\":    \"Exchange\",\n\t\t\t\t\"internal\":    \"false\",\n\t\t\t\t\"type\":        \"topic\",\n\t\t\t\t\"url\":         ts.URL,\n\t\t\t\t\"vhost\":       \"/\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"messages_publish_in\":       int64(18006),\n\t\t\t\t\"messages_publish_in_rate\":  float64(0.0),\n\t\t\t\t\"messages_publish_out\":      int64(60798),\n\t\t\t\t\"messages_publish_out_rate\": float64(0.0),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\texpectedErrors := []error{\n\t\terrors.New(\"error response trying to get \\\"/api/federation-links\\\": \\\"Object Not Found\\\" (reason: \\\"Not Found\\\")\"),\n\t}\n\n\t// Run the test\n\tplugin := &RabbitMQ{\n\t\tURL: ts.URL,\n\t\tLog: testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tacc.Wait(len(expected))\n\trequire.Len(t, acc.Errors, len(expectedErrors))\n\trequire.ElementsMatch(t, expectedErrors, acc.Errors)\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime(), testutil.SortMetrics())\n}\n\nfunc TestRabbitMQMetricFilerts(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Error(w, fmt.Sprintf(\"unknown path %q\", r.URL.Path), http.StatusNotFound)\n\t}))\n\tdefer ts.Close()\n\n\tmetricErrors := map[string]error{\n\t\t\"exchange\":   errors.New(\"getting \\\"/api/exchanges\\\" failed: 404 Not Found\"),\n\t\t\"federation\": errors.New(\"getting \\\"/api/federation-links\\\" failed: 404 Not Found\"),\n\t\t\"node\":       errors.New(\"getting \\\"/api/nodes\\\" failed: 404 Not Found\"),\n\t\t\"overview\":   errors.New(\"getting \\\"/api/overview\\\" failed: 404 Not Found\"),\n\t\t\"queue\":      errors.New(\"getting \\\"/api/queues\\\" failed: 404 Not Found\"),\n\t}\n\n\t// Include test\n\tfor name, expected := range metricErrors {\n\t\tplugin := &RabbitMQ{\n\t\t\tURL:           ts.URL,\n\t\t\tLog:           testutil.Logger{},\n\t\t\tMetricInclude: []string{name},\n\t\t}\n\t\trequire.NoError(t, plugin.Init())\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, plugin.Gather(acc))\n\t\trequire.Len(t, acc.Errors, 1)\n\t\trequire.ElementsMatch(t, []error{expected}, acc.Errors)\n\t}\n\n\t// Exclude test\n\tfor name := range metricErrors {\n\t\t// Exclude the current metric error from the list of expected errors\n\t\tvar expected []error\n\t\tfor n, e := range metricErrors {\n\t\t\tif n != name {\n\t\t\t\texpected = append(expected, e)\n\t\t\t}\n\t\t}\n\t\tplugin := &RabbitMQ{\n\t\t\tURL:           ts.URL,\n\t\t\tLog:           testutil.Logger{},\n\t\t\tMetricExclude: []string{name},\n\t\t}\n\t\trequire.NoError(t, plugin.Init())\n\n\t\tacc := &testutil.Accumulator{}\n\t\trequire.NoError(t, plugin.Gather(acc))\n\t\trequire.Len(t, acc.Errors, len(expected))\n\t\trequire.ElementsMatch(t, expected, acc.Errors)\n\t}\n}\n\nfunc TestRabbitMQQueueTypeTag(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/api/overview\":\n\t\t\tjsonFilePath = \"testdata/set1/overview.json\"\n\t\tcase \"/api/nodes\":\n\t\t\tjsonFilePath = \"testdata/set1/nodes.json\"\n\t\tcase \"/api/queues\":\n\t\t\tjsonFilePath = \"testdata/set1/queues.json\"\n\t\tcase \"/api/exchanges\":\n\t\t\tjsonFilePath = \"testdata/set1/exchanges.json\"\n\t\tcase \"/api/federation-links\":\n\t\t\tjsonFilePath = \"testdata/set1/federation-links.json\"\n\t\tcase \"/api/nodes/rabbit@vagrant-ubuntu-trusty-64/memory\":\n\t\t\tjsonFilePath = \"testdata/set1/memory.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"unknown path %q\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\t// Test with IncludeQueueTypeTag = false (default)\n\tplugin := &RabbitMQ{\n\t\tURL: ts.URL,\n\t\tLog: testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tacc := &testutil.Accumulator{}\n\trequire.NoError(t, plugin.Gather(acc))\n\n\tacc.Wait(4)\n\trequire.Empty(t, acc.Errors)\n\n\t// Check that queue metrics don't have type tag when disabled\n\tqueueMetrics := acc.GetTelegrafMetrics()\n\tfor _, metric := range queueMetrics {\n\t\tif metric.Name() == \"rabbitmq_queue\" {\n\t\t\trequire.False(t, metric.HasTag(\"type\"), \"Queue metric should not have type tag when IncludeQueueTypeTag is false\")\n\t\t}\n\t}\n\n\t// Test with IncludeQueueTypeTag = true\n\tpluginWithType := &RabbitMQ{\n\t\tURL:                 ts.URL,\n\t\tIncludeQueueTypeTag: true,\n\t\tLog:                 testutil.Logger{},\n\t}\n\trequire.NoError(t, pluginWithType.Init())\n\n\taccWithType := &testutil.Accumulator{}\n\trequire.NoError(t, pluginWithType.Gather(accWithType))\n\n\taccWithType.Wait(4)\n\trequire.Empty(t, accWithType.Errors)\n\n\t// Check that queue metrics have type tag when enabled and verify specific queue types\n\tqueueMetricsWithType := accWithType.GetTelegrafMetrics()\n\tqueueTypeMap := make(map[string]string) // queue name -> queue type\n\n\tfor _, metric := range queueMetricsWithType {\n\t\tif metric.Name() == \"rabbitmq_queue\" {\n\t\t\trequire.True(t, metric.HasTag(\"type\"), \"Queue metric should have type tag when IncludeQueueTypeTag is true\")\n\n\t\t\tqueueName, _ := metric.GetTag(\"queue\")\n\t\t\tqueueType, _ := metric.GetTag(\"type\")\n\t\t\tqueueTypeMap[queueName] = queueType\n\t\t}\n\t}\n\n\trequire.Len(t, queueTypeMap, 4, \"Should have metrics for all 4 queues in test data\")\n\trequire.Equal(t, \"quorum\", queueTypeMap[\"reply_a716f0523cd44941ad2ea6ce4a3869c3\"], \"Quorum queue should have type 'quorum'\")\n\trequire.Equal(t, \"stream\", queueTypeMap[\"stream_queue_example\"], \"Stream queue should have type 'stream'\")\n\trequire.Equal(t, \"classic\", queueTypeMap[\"no-type-queue\"], \"Queue without type field should default to 'classic'\")\n\trequire.Equal(t, \"invalid_type\", queueTypeMap[\"invalid-type-queue\"], \"Queue with invalid type should preserve the invalid type\")\n}\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/sample.conf",
    "content": "# Reads metrics from RabbitMQ servers via the Management Plugin\n[[inputs.rabbitmq]]\n  ## Management Plugin url. (default: http://localhost:15672)\n  # url = \"http://localhost:15672\"\n\n  ## Credentials\n  # username = \"guest\"\n  # password = \"guest\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n\n  ## Optional request timeouts\n  ##\n  ## ResponseHeaderTimeout, if non-zero, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request.\n  # header_timeout = \"3s\"\n  ##\n  ## client_timeout specifies a time limit for requests made by this client.\n  ## Includes connection time, any redirects, and reading the response body.\n  # client_timeout = \"4s\"\n\n  ## A list of nodes to gather as the rabbitmq_node measurement. If not\n  ## specified, metrics for all nodes are gathered.\n  # nodes = [\"rabbit@node1\", \"rabbit@node2\"]\n\n  ## A list of exchanges to gather as the rabbitmq_exchange measurement. If not\n  ## specified, metrics for all exchanges are gathered.\n  # exchanges = [\"telegraf\"]\n\n  ## Metrics to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all metrics\n  ## Currently the following metrics are supported: \"exchange\", \"federation\", \"node\", \"overview\", \"queue\"\n  # metric_include = []\n  # metric_exclude = []\n\n  ## Queues to include and exclude. Globs accepted.\n  ## Note that an empty array for both will include all queues\n  # queue_name_include = []\n  # queue_name_exclude = []\n\n  ## Federation upstreams to include and exclude specified as an array of glob\n  ## pattern strings.  Federation links can also be limited by the queue and\n  ## exchange filters.\n  # federation_upstream_include = []\n  # federation_upstream_exclude = []\n\n  ## Include queue type as a tag. When enabled, adds a \"type\" tag to queue metrics\n  ## with the queue type returned by RabbitMQ (e.g., \"classic\", \"quorum\", \"stream\").\n  ## Defaults to \"classic\" if empty.\n  # include_queue_type_tag = false\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/exchanges.json",
    "content": "[\n  {\n    \"message_stats\": {\n      \"publish_in_details\": {\n        \"rate\": 3.2\n      },\n      \"publish_in\": 3678,\n      \"publish_out_details\": {\n        \"rate\": 5.1\n      },\n      \"publish_out\": 3677\n    },\n    \"user_who_performed_action\": \"mistral_testuser_1\",\n    \"arguments\": {},\n    \"internal\": false,\n    \"auto_delete\": true,\n    \"durable\": false,\n    \"type\": \"direct\",\n    \"vhost\": \"sorandomsorandom\",\n    \"name\": \"reply_a716f0523cd44941ad2ea6ce4a3869c3\"\n  }\n]"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/federation-links.json",
    "content": "[\n  {\n    \"node\": \"rabbit@rmqlocal\",\n    \"queue\": \"exampleLocalQueue\",\n    \"upstream_queue\": \"exampleUpstreamQueue\",\n    \"type\": \"queue\",\n    \"vhost\": \"/\",\n    \"upstream\": \"ExampleFederationUpstream\",\n    \"id\": \"8ba5218f\",\n    \"status\": \"running\",\n    \"local_connection\": \"<rabbit@somehost>\",\n    \"uri\": \"amqp://appsv03\",\n    \"timestamp\": \"2019-08-19 15:34:15\",\n    \"local_channel\": {\n      \"acks_uncommitted\": 1,\n      \"confirm\": true,\n      \"connection_details\": {\n        \"name\": \"<rabbit@somehost>\",\n        \"peer_host\": \"undefined\",\n        \"peer_port\": \"undefined\"\n      },\n      \"consumer_count\": 2,\n      \"garbage_collection\": {\n        \"fullsweep_after\": 65535,\n        \"max_heap_size\": 0,\n        \"min_bin_vheap_size\": 46422,\n        \"min_heap_size\": 233,\n        \"minor_gcs\": 203\n      },\n      \"global_prefetch_count\": 0,\n      \"message_stats\": {\n        \"confirm\": 67,\n        \"confirm_details\": {\n          \"rate\": 2\n        },\n        \"publish\": 890,\n        \"publish_details\": {\n          \"rate\": 2\n        },\n        \"return_unroutable\": 1,\n        \"return_unroutable_details\": {\n          \"rate\": 0.1\n        }\n      },\n      \"messages_unacknowledged\": 3,\n      \"messages_uncommitted\": 4,\n      \"messages_unconfirmed\": 5,\n      \"name\": \"<rabbit@somehost>\",\n      \"node\": \"rabbit@rmqlocal\",\n      \"number\": 1,\n      \"prefetch_count\": 0,\n      \"reductions\": 1926653,\n      \"reductions_details\": {\n        \"rate\": 1068\n      },\n      \"state\": \"running\",\n      \"transactional\": false,\n      \"user\": \"none\",\n      \"user_who_performed_action\": \"none\",\n      \"vhost\": \"sorandomsorandom\"\n    }\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/memory.json",
    "content": "{\n    \"memory\": {\n        \"connection_readers\": 1234,\n        \"connection_writers\": 5678,\n        \"connection_channels\": 1133,\n        \"connection_other\": 2840,\n        \"queue_procs\": 2840,\n        \"queue_slave_procs\": 0,\n        \"plugins\": 1755976,\n        \"other_proc\": 23056584,\n        \"metrics\": 196536,\n        \"mgmt_db\": 491272,\n        \"mnesia\": 115600,\n        \"other_ets\": 2121872,\n        \"binary\": 418848,\n        \"msg_index\": 42848,\n        \"code\": 25179322,\n        \"atom\": 1041593,\n        \"other_system\": 14741981,\n        \"allocated_unused\": 38208528,\n        \"reserved_unallocated\": 0,\n        \"total\": 83025920\n    }\n}"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/nodes.json",
    "content": "[\n  {\n    \"db_dir\": \"/var/lib/rabbitmq/mnesia/rabbit@vagrant-ubuntu-trusty-64\",\n    \"disk_free\": 3776,\n    \"disk_free_alarm\": false,\n    \"disk_free_details\": {\n      \"rate\": 0.0\n    },\n    \"disk_free_limit\": 50000000,\n    \"enabled_plugins\": [\n      \"rabbitmq_management\"\n    ],\n    \"gc_num\": 57280132,\n    \"gc_num_details\": {\n      \"rate\": 274.2\n    },\n    \"gc_bytes_reclaimed\": 2533,\n    \"gc_bytes_reclaimed_details\": {\n      \"rate\": 16490856.3\n    },\n    \"fd_total\": 1024,\n    \"fd_used\": 63,\n    \"fd_used_details\": {\n      \"rate\": 0.0\n    },\n    \"io_read_avg_time\": 983,\n    \"io_read_avg_time_details\": {\n      \"rate\": 88.77\n    },\n    \"io_read_bytes\": 1111,\n    \"io_read_bytes_details\": {\n      \"rate\": 99.99\n    },\n    \"io_read_count\": 1,\n    \"io_read_count_details\": {\n      \"rate\": 0.0\n    },\n    \"io_sync_avg_time\": 0,\n    \"io_sync_avg_time_details\": {\n      \"rate\": 0.0\n    },\n    \"io_write_avg_time\": 134,\n    \"io_write_avg_time_details\": {\n      \"rate\": 4.32\n    },\n    \"io_write_bytes\": 823,\n    \"io_write_bytes_details\": {\n      \"rate\": 32.8\n    },\n    \"log_file\": \"/var/log/rabbitmq/rabbit@vagrant-ubuntu-trusty-64.log\",\n    \"mem_alarm\": true,\n    \"mem_limit\": 2503,\n    \"mem_used\": 159707080,\n    \"mem_used_details\": {\n      \"rate\": 15185.6\n    },\n    \"mnesia_disk_tx_count\": 16,\n    \"mnesia_disk_tx_count_details\": {\n      \"rate\": 1.1\n    },\n    \"mnesia_ram_tx_count\": 296,\n    \"mnesia_ram_tx_count_details\": {\n      \"rate\": 2.2\n    },\n    \"name\": \"rabbit@vagrant-ubuntu-trusty-64\",\n    \"net_ticktime\": 60,\n    \"os_pid\": \"14244\",\n    \"partitions\": [],\n    \"proc_total\": 1048576,\n    \"proc_used\": 783,\n    \"proc_used_details\": {\n      \"rate\": 0.0\n    },\n    \"processors\": 1,\n    \"rates_mode\": \"basic\",\n    \"run_queue\": 0,\n    \"running\": true,\n    \"sasl_log_file\": \"/var/log/rabbitmq/rabbit@vagrant-ubuntu-trusty-64-sasl.log\",\n    \"sockets_total\": 829,\n    \"sockets_used\": 45,\n    \"sockets_used_details\": {\n      \"rate\": 0.0\n    },\n    \"type\": \"disc\",\n    \"uptime\": 7464827\n  }\n]"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/overview.json",
    "content": "{\n  \"message_stats\": {\n    \"ack\": 5246,\n    \"ack_details\": {\n      \"rate\": 0.0\n    },\n    \"deliver\": 5234,\n    \"deliver_details\": {\n      \"rate\": 0.0\n    },\n    \"deliver_get\": 3333,\n    \"deliver_get_details\": {\n      \"rate\": 0.0\n    },\n    \"publish\": 5258,\n    \"publish_details\": {\n      \"rate\": 0.0\n    },\n    \"return_unroutable\": 10,\n    \"return_unroutable_details\": {\n      \"rate\": 3.3\n    }\n  },\n  \"object_totals\": {\n    \"channels\": 44,\n    \"connections\": 44,\n    \"consumers\": 70,\n    \"exchanges\": 43,\n    \"queues\": 66\n  },\n  \"queue_totals\": {\n    \"messages\": 50,\n    \"messages_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_ready\": 72,\n    \"messages_ready_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_unacknowledged\": 94,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0.0\n    }\n  },\n  \"listeners\": [\n    {\n      \"name\": \"rabbit@node-a\",\n      \"protocol\": \"amqp\"\n    },\n    {\n      \"name\": \"rabbit@node-b\",\n      \"protocol\": \"amqp\"\n    },\n    {\n      \"name\": \"rabbit@node-a\",\n      \"protocol\": \"clustering\"\n    },\n    {\n      \"name\": \"rabbit@node-b\",\n      \"protocol\": \"clustering\"\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set1/queues.json",
    "content": "[\n  {\n    \"messages_details\": {\n      \"rate\": 0.0\n    },\n    \"messages\": 44,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_unacknowledged\": 44,\n    \"messages_ready_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_ready\": 32,\n    \"reductions_details\": {\n      \"rate\": 223.0\n    },\n    \"reductions\": 15875433,\n    \"message_stats\": {\n      \"deliver_get_details\": {\n        \"rate\": 0.2\n      },\n      \"deliver_get\": 3457,\n      \"ack_details\": {\n        \"rate\": 9.9\n      },\n      \"ack\": 3457,\n      \"redeliver_details\": {\n        \"rate\": 2.5\n      },\n      \"redeliver\": 33,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_details\": {\n        \"rate\": 333.4\n      },\n      \"deliver\": 22222,\n      \"get_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"get_no_ack\": 0,\n      \"get_details\": {\n        \"rate\": 0.0\n      },\n      \"get\": 0,\n      \"publish_details\": {\n        \"rate\": 11.2\n      },\n      \"publish\": 3457\n    },\n    \"node\": \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n    \"arguments\": {\n      \"x-expires\": 1800000,\n      \"x-ha-policy\": \"all\"\n    },\n    \"exclusive\": false,\n    \"auto_delete\": false,\n    \"durable\": false,\n    \"vhost\": \"sorandomsorandom\",\n    \"name\": \"reply_a716f0523cd44941ad2ea6ce4a3869c3\",\n    \"message_bytes_paged_out\": 0,\n    \"messages_paged_out\": 0,\n    \"idle_since\": \"2015-11-01 8:22:14\",\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0.2374460025857711,\n      \"avg_ack_ingress_rate\": 0.2374460025857711,\n      \"avg_egress_rate\": 0.2374460025857711,\n      \"avg_ingress_rate\": 0.2374460025857711,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 3457,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": 0\n    },\n    \"head_message_timestamp\": 1446362534,\n    \"message_bytes_persistent\": 7,\n    \"message_bytes_ram\": 6,\n    \"message_bytes_unacknowledged\": 5,\n    \"message_bytes_ready\": 4,\n    \"message_bytes\": 3,\n    \"messages_persistent\": 0,\n    \"messages_unacknowledged_ram\": 0,\n    \"messages_ready_ram\": 0,\n    \"messages_ram\": 0,\n    \"garbage_collection\": {\n      \"minor_gcs\": 314,\n      \"fullsweep_after\": 65535,\n      \"min_heap_size\": 233,\n      \"min_bin_vheap_size\": 46422,\n      \"max_heap_size\": 0\n    },\n    \"state\": \"running\",\n    \"type\": \"quorum\",\n    \"recoverable_slaves\": null,\n    \"memory\": 143776,\n    \"consumer_utilisation\": 1.0,\n    \"consumers\": 3,\n    \"exclusive_consumer_tag\": null,\n    \"effective_policy_definition\": [],\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"slave_nodes\": [\n      \"rabbit@ip-10-1-2-118\"\n    ],\n    \"synchronised_slave_nodes\": [\n      \"rabbit@ip-10-1-2-118\"\n    ]\n  },\n  {\n    \"messages_details\": {\n      \"rate\": 0.0\n    },\n    \"messages\": 25,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_unacknowledged\": 25,\n    \"messages_ready_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_ready\": 20,\n    \"reductions_details\": {\n      \"rate\": 150.0\n    },\n    \"reductions\": 8000000,\n    \"message_stats\": {\n      \"deliver_get_details\": {\n        \"rate\": 0.1\n      },\n      \"deliver_get\": 1500,\n      \"ack_details\": {\n        \"rate\": 5.5\n      },\n      \"ack\": 1500,\n      \"redeliver_details\": {\n        \"rate\": 1.2\n      },\n      \"redeliver\": 15,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_details\": {\n        \"rate\": 200.0\n      },\n      \"deliver\": 10000,\n      \"get_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"get_no_ack\": 0,\n      \"get_details\": {\n        \"rate\": 0.0\n      },\n      \"get\": 0,\n      \"publish_details\": {\n        \"rate\": 8.5\n      },\n      \"publish\": 1500\n    },\n    \"node\": \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n    \"arguments\": {\n      \"x-expires\": 1800000\n    },\n    \"exclusive\": false,\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"vhost\": \"sorandomsorandom\",\n    \"name\": \"stream_queue_example\",\n    \"message_bytes_paged_out\": 0,\n    \"messages_paged_out\": 0,\n    \"idle_since\": \"2015-11-01 9:15:30\",\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0.1,\n      \"avg_ack_ingress_rate\": 0.1,\n      \"avg_egress_rate\": 0.1,\n      \"avg_ingress_rate\": 0.1,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 1500,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": 0\n    },\n    \"head_message_timestamp\": 1446366000,\n    \"message_bytes_persistent\": 5,\n    \"message_bytes_ram\": 4,\n    \"message_bytes_unacknowledged\": 3,\n    \"message_bytes_ready\": 2,\n    \"message_bytes\": 1,\n    \"messages_persistent\": 0,\n    \"messages_unacknowledged_ram\": 0,\n    \"messages_ready_ram\": 0,\n    \"messages_ram\": 0,\n    \"garbage_collection\": {\n      \"minor_gcs\": 200,\n      \"fullsweep_after\": 65535,\n      \"min_heap_size\": 233,\n      \"min_bin_vheap_size\": 46422,\n      \"max_heap_size\": 0\n    },\n    \"state\": \"running\",\n    \"type\": \"stream\",\n    \"recoverable_slaves\": null,\n    \"memory\": 95000,\n    \"consumer_utilisation\": 0.8,\n    \"consumers\": 2,\n    \"exclusive_consumer_tag\": null,\n    \"effective_policy_definition\": [],\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"slave_nodes\": [],\n    \"synchronised_slave_nodes\": []\n  },\n  {\n    \"messages_details\": {\n      \"rate\": 0.0\n    },\n    \"messages\": 10,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_unacknowledged\": 10,\n    \"messages_ready_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_ready\": 8,\n    \"reductions_details\": {\n      \"rate\": 50.0\n    },\n    \"reductions\": 2000000,\n    \"message_stats\": {\n      \"deliver_get_details\": {\n        \"rate\": 0.1\n      },\n      \"deliver_get\": 500,\n      \"ack_details\": {\n        \"rate\": 2.0\n      },\n      \"ack\": 500,\n      \"redeliver_details\": {\n        \"rate\": 0.5\n      },\n      \"redeliver\": 5,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_details\": {\n        \"rate\": 50.0\n      },\n      \"deliver\": 2000,\n      \"get_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"get_no_ack\": 0,\n      \"get_details\": {\n        \"rate\": 0.0\n      },\n      \"get\": 0,\n      \"publish_details\": {\n        \"rate\": 3.0\n      },\n      \"publish\": 500\n    },\n    \"node\": \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n    \"arguments\": {\n      \"x-expires\": 1800000\n    },\n    \"exclusive\": false,\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"vhost\": \"sorandomsorandom\",\n    \"name\": \"no-type-queue\",\n    \"message_bytes_paged_out\": 0,\n    \"messages_paged_out\": 0,\n    \"idle_since\": \"2015-11-01 10:30:00\",\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0.05,\n      \"avg_ack_ingress_rate\": 0.05,\n      \"avg_egress_rate\": 0.05,\n      \"avg_ingress_rate\": 0.05,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 500,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": 0\n    },\n    \"head_message_timestamp\": 1446372000,\n    \"message_bytes_persistent\": 2,\n    \"message_bytes_ram\": 1,\n    \"message_bytes_unacknowledged\": 1,\n    \"message_bytes_ready\": 1,\n    \"message_bytes\": 1,\n    \"messages_persistent\": 0,\n    \"messages_unacknowledged_ram\": 0,\n    \"messages_ready_ram\": 0,\n    \"messages_ram\": 0,\n    \"garbage_collection\": {\n      \"minor_gcs\": 100,\n      \"fullsweep_after\": 65535,\n      \"min_heap_size\": 233,\n      \"min_bin_vheap_size\": 46422,\n      \"max_heap_size\": 0\n    },\n    \"state\": \"running\",\n    \"recoverable_slaves\": null,\n    \"memory\": 50000,\n    \"consumer_utilisation\": 0.9,\n    \"consumers\": 1,\n    \"exclusive_consumer_tag\": null,\n    \"effective_policy_definition\": [],\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"slave_nodes\": [],\n    \"synchronised_slave_nodes\": []\n  },\n  {\n    \"messages_details\": {\n      \"rate\": 0.0\n    },\n    \"messages\": 15,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_unacknowledged\": 15,\n    \"messages_ready_details\": {\n      \"rate\": 0.0\n    },\n    \"messages_ready\": 12,\n    \"reductions_details\": {\n      \"rate\": 75.0\n    },\n    \"reductions\": 3000000,\n    \"message_stats\": {\n      \"deliver_get_details\": {\n        \"rate\": 0.1\n      },\n      \"deliver_get\": 750,\n      \"ack_details\": {\n        \"rate\": 3.0\n      },\n      \"ack\": 750,\n      \"redeliver_details\": {\n        \"rate\": 0.8\n      },\n      \"redeliver\": 8,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_details\": {\n        \"rate\": 75.0\n      },\n      \"deliver\": 3000,\n      \"get_no_ack_details\": {\n        \"rate\": 0.0\n      },\n      \"get_no_ack\": 0,\n      \"get_details\": {\n        \"rate\": 0.0\n      },\n      \"get\": 0,\n      \"publish_details\": {\n        \"rate\": 4.5\n      },\n      \"publish\": 750\n    },\n    \"node\": \"rabbit@rmqlocal-0.rmqlocal.ankorabbitstatefulset3.svc.cluster.local\",\n    \"arguments\": {\n      \"x-expires\": 1800000\n    },\n    \"exclusive\": false,\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"vhost\": \"sorandomsorandom\",\n    \"name\": \"invalid-type-queue\",\n    \"message_bytes_paged_out\": 0,\n    \"messages_paged_out\": 0,\n    \"idle_since\": \"2015-11-01 11:45:00\",\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0.08,\n      \"avg_ack_ingress_rate\": 0.08,\n      \"avg_egress_rate\": 0.08,\n      \"avg_ingress_rate\": 0.08,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 750,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": 0\n    },\n    \"head_message_timestamp\": 1446375000,\n    \"message_bytes_persistent\": 3,\n    \"message_bytes_ram\": 2,\n    \"message_bytes_unacknowledged\": 2,\n    \"message_bytes_ready\": 1,\n    \"message_bytes\": 1,\n    \"messages_persistent\": 0,\n    \"messages_unacknowledged_ram\": 0,\n    \"messages_ready_ram\": 0,\n    \"messages_ram\": 0,\n    \"garbage_collection\": {\n      \"minor_gcs\": 150,\n      \"fullsweep_after\": 65535,\n      \"min_heap_size\": 233,\n      \"min_bin_vheap_size\": 46422,\n      \"max_heap_size\": 0\n    },\n    \"state\": \"running\",\n    \"type\": \"invalid_type\",\n    \"recoverable_slaves\": null,\n    \"memory\": 75000,\n    \"consumer_utilisation\": 0.85,\n    \"consumers\": 2,\n    \"exclusive_consumer_tag\": null,\n    \"effective_policy_definition\": [],\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"slave_nodes\": [],\n    \"synchronised_slave_nodes\": []\n  }\n]"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/exchanges.json",
    "content": "[\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"message_stats\": {\n      \"publish_in\": 284725,\n      \"publish_in_details\": {\n        \"rate\": 0\n      },\n      \"publish_out\": 284572,\n      \"publish_out_details\": {\n        \"rate\": 0\n      }\n    },\n    \"name\": \"\",\n    \"type\": \"direct\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": true,\n    \"durable\": false,\n    \"internal\": false,\n    \"message_stats\": {\n      \"publish_in\": 18006,\n      \"publish_in_details\": {\n        \"rate\": 0\n      },\n      \"publish_out\": 60798,\n      \"publish_out_details\": {\n        \"rate\": 0\n      }\n    },\n    \"name\": \"Exchange\",\n    \"type\": \"topic\",\n    \"user_who_performed_action\": \"user\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"name\": \"amq.direct\",\n    \"type\": \"direct\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"name\": \"amq.fanout\",\n    \"type\": \"fanout\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"name\": \"amq.headers\",\n    \"type\": \"headers\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"name\": \"amq.match\",\n    \"type\": \"headers\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": true,\n    \"name\": \"amq.rabbitmq.trace\",\n    \"type\": \"topic\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {},\n    \"auto_delete\": false,\n    \"durable\": true,\n    \"internal\": false,\n    \"name\": \"amq.topic\",\n    \"type\": \"topic\",\n    \"user_who_performed_action\": \"rmq-internal\",\n    \"vhost\": \"/\"\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/federation-links.json",
    "content": "{\"error\":\"Object Not Found\",\"reason\":\"Not Found\"}\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/memory.json",
    "content": "{\n  \"memory\": {\n    \"connection_readers\": 1246768,\n    \"connection_writers\": 72108,\n    \"connection_channels\": 308588,\n    \"connection_other\": 4883596,\n    \"queue_procs\": 780996,\n    \"queue_slave_procs\": 0,\n    \"quorum_queue_procs\": 0,\n    \"plugins\": 11932828,\n    \"other_proc\": 39203520,\n    \"metrics\": 626932,\n    \"mgmt_db\": 3341264,\n    \"mnesia\": 396016,\n    \"quorum_ets\": 47920,\n    \"other_ets\": 3771384,\n    \"binary\": 209324208,\n    \"msg_index\": 32648,\n    \"code\": 32810827,\n    \"atom\": 1458513,\n    \"other_system\": 14284124,\n    \"allocated_unused\": 61026048,\n    \"reserved_unallocated\": 0,\n    \"strategy\": \"rss\",\n    \"total\": {\n      \"erlang\": 324522240,\n      \"rss\": 385548288,\n      \"allocated\": 385548288\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/nodes.json",
    "content": "[\n  {\n    \"partitions\": [],\n    \"os_pid\": \"8268\",\n    \"fd_total\": 65536,\n    \"sockets_total\": 58893,\n    \"mem_limit\": 1717546188,\n    \"mem_alarm\": false,\n    \"disk_free_limit\": 50000000,\n    \"disk_free_alarm\": false,\n    \"proc_total\": 1048576,\n    \"rates_mode\": \"basic\",\n    \"uptime\": 4150152129,\n    \"run_queue\": 1,\n    \"processors\": 4,\n    \"exchange_types\": [\n      {\n        \"name\": \"topic\",\n        \"description\": \"AMQP topic exchange, as per the AMQP specification\",\n        \"enabled\": true\n      },\n      {\n        \"name\": \"fanout\",\n        \"description\": \"AMQP fanout exchange, as per the AMQP specification\",\n        \"enabled\": true\n      },\n      {\n        \"name\": \"direct\",\n        \"description\": \"AMQP direct exchange, as per the AMQP specification\",\n        \"enabled\": true\n      },\n      {\n        \"name\": \"headers\",\n        \"description\": \"AMQP headers exchange, as per the AMQP specification\",\n        \"enabled\": true\n      }\n    ],\n    \"auth_mechanisms\": [\n      {\n        \"name\": \"PLAIN\",\n        \"description\": \"SASL PLAIN authentication mechanism\",\n        \"enabled\": true\n      },\n      {\n        \"name\": \"AMQPLAIN\",\n        \"description\": \"QPid AMQPLAIN mechanism\",\n        \"enabled\": true\n      },\n      {\n        \"name\": \"RABBIT-CR-DEMO\",\n        \"description\": \"RabbitMQ Demo challenge-response authentication mechanism\",\n        \"enabled\": false\n      }\n    ],\n    \"applications\": [\n      {\n        \"name\": \"amqp_client\",\n        \"description\": \"RabbitMQ AMQP Client\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"asn1\",\n        \"description\": \"The Erlang ASN1 compiler version 5.0.14\",\n        \"version\": \"5.0.14\"\n      },\n      {\n        \"name\": \"aten\",\n        \"description\": \"Erlang node failure detector\",\n        \"version\": \"0.5.5\"\n      },\n      {\n        \"name\": \"compiler\",\n        \"description\": \"ERTS  CXC 138 10\",\n        \"version\": \"7.6.6\"\n      },\n      {\n        \"name\": \"cowboy\",\n        \"description\": \"Small, fast, modern HTTP server.\",\n        \"version\": \"2.8.0\"\n      },\n      {\n        \"name\": \"cowlib\",\n        \"description\": \"Support library for manipulating Web protocols.\",\n        \"version\": \"2.9.1\"\n      },\n      {\n        \"name\": \"credentials_obfuscation\",\n        \"description\": \"Helper library that obfuscates sensitive values in process state\",\n        \"version\": \"2.4.0\"\n      },\n      {\n        \"name\": \"crypto\",\n        \"description\": \"CRYPTO\",\n        \"version\": \"4.8.3\"\n      },\n      {\n        \"name\": \"cuttlefish\",\n        \"description\": \"cuttlefish configuration abstraction\",\n        \"version\": \"2.6.0\"\n      },\n      {\n        \"name\": \"gen_batch_server\",\n        \"description\": \"Generic batching server\",\n        \"version\": \"0.8.4\"\n      },\n      {\n        \"name\": \"goldrush\",\n        \"description\": \"Erlang event stream processor\",\n        \"version\": \"0.1.9\"\n      },\n      {\n        \"name\": \"inets\",\n        \"description\": \"INETS  CXC 138 49\",\n        \"version\": \"7.3.2\"\n      },\n      {\n        \"name\": \"jsx\",\n        \"description\": \"a streaming, evented json parsing toolkit\",\n        \"version\": \"2.11.0\"\n      },\n      {\n        \"name\": \"kernel\",\n        \"description\": \"ERTS  CXC 138 10\",\n        \"version\": \"7.2.1\"\n      },\n      {\n        \"name\": \"lager\",\n        \"description\": \"Erlang logging framework\",\n        \"version\": \"3.8.2\"\n      },\n      {\n        \"name\": \"mnesia\",\n        \"description\": \"MNESIA  CXC 138 12\",\n        \"version\": \"4.18.1\"\n      },\n      {\n        \"name\": \"observer_cli\",\n        \"description\": \"Visualize Erlang Nodes On The Command Line\",\n        \"version\": \"1.6.1\"\n      },\n      {\n        \"name\": \"os_mon\",\n        \"description\": \"CPO  CXC 138 46\",\n        \"version\": \"2.6.1\"\n      },\n      {\n        \"name\": \"public_key\",\n        \"description\": \"Public key infrastructure\",\n        \"version\": \"1.9.2\"\n      },\n      {\n        \"name\": \"ra\",\n        \"description\": \"Raft library\",\n        \"version\": \"1.1.8\"\n      },\n      {\n        \"name\": \"rabbit\",\n        \"description\": \"RabbitMQ\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"rabbit_common\",\n        \"description\": \"Modules shared by rabbitmq-server and rabbitmq-erlang-client\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"rabbitmq_management\",\n        \"description\": \"RabbitMQ Management Console\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"rabbitmq_management_agent\",\n        \"description\": \"RabbitMQ Management Agent\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"rabbitmq_prelaunch\",\n        \"description\": \"RabbitMQ prelaunch setup\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"rabbitmq_web_dispatch\",\n        \"description\": \"RabbitMQ Web Dispatcher\",\n        \"version\": \"3.8.14\"\n      },\n      {\n        \"name\": \"ranch\",\n        \"description\": \"Socket acceptor pool for TCP protocols.\",\n        \"version\": \"1.7.1\"\n      },\n      {\n        \"name\": \"recon\",\n        \"description\": \"Diagnostic tools for production use\",\n        \"version\": \"2.5.1\"\n      },\n      {\n        \"name\": \"sasl\",\n        \"description\": \"SASL  CXC 138 11\",\n        \"version\": \"4.0.1\"\n      },\n      {\n        \"name\": \"ssl\",\n        \"description\": \"Erlang/OTP SSL application\",\n        \"version\": \"10.2.4\"\n      },\n      {\n        \"name\": \"stdlib\",\n        \"description\": \"ERTS  CXC 138 10\",\n        \"version\": \"3.14\"\n      },\n      {\n        \"name\": \"stdout_formatter\",\n        \"description\": \"Tools to format paragraphs, lists and tables as plain text\",\n        \"version\": \"0.2.4\"\n      },\n      {\n        \"name\": \"syntax_tools\",\n        \"description\": \"Syntax tools\",\n        \"version\": \"2.4\"\n      },\n      {\n        \"name\": \"sysmon_handler\",\n        \"description\": \"Rate-limiting system_monitor event handler\",\n        \"version\": \"1.3.0\"\n      },\n      {\n        \"name\": \"tools\",\n        \"description\": \"DEVTOOLS  CXC 138 16\",\n        \"version\": \"3.4.3\"\n      },\n      {\n        \"name\": \"xmerl\",\n        \"description\": \"XML parser\",\n        \"version\": \"1.3.26\"\n      }\n    ],\n    \"contexts\": [\n      {\n        \"description\": \"RabbitMQ Management\",\n        \"path\": \"/\",\n        \"cowboy_opts\": \"[{sendfile,false}]\",\n        \"port\": \"15672\"\n      }\n    ],\n    \"log_files\": [\n      \"c:/Users/user/AppData/Roaming/RabbitMQ/log/rabbit@rmqserver.log\",\n      \"c:/Users/user/AppData/Roaming/RabbitMQ/log/rabbit@rmqserver_upgrade.log\"\n    ],\n    \"db_dir\": \"c:/Users/user/AppData/Roaming/RabbitMQ/db/rabbit@rmqserver-mnesia\",\n    \"config_files\": [\n      \"c:/Users/user/AppData/Roaming/RabbitMQ/advanced.config\"\n    ],\n    \"net_ticktime\": 60,\n    \"enabled_plugins\": [\n      \"rabbitmq_management\"\n    ],\n    \"mem_calculation_strategy\": \"rss\",\n    \"ra_open_file_metrics\": {\n      \"ra_log_wal\": 1,\n      \"ra_log_segment_writer\": 0\n    },\n    \"name\": \"rabbit@rmqserver\",\n    \"type\": \"disc\",\n    \"running\": true,\n    \"mem_used\": 387645440,\n    \"mem_used_details\": {\n      \"rate\": 419430.4\n    },\n    \"fd_used\": 78,\n    \"fd_used_details\": {\n      \"rate\": 0\n    },\n    \"sockets_used\": 43,\n    \"sockets_used_details\": {\n      \"rate\": 0\n    },\n    \"proc_used\": 1128,\n    \"proc_used_details\": {\n      \"rate\": 0\n    },\n    \"disk_free\": 25086496768,\n    \"disk_free_details\": {\n      \"rate\": -118784\n    },\n    \"gc_num\": 329526389,\n    \"gc_num_details\": {\n      \"rate\": 125.2\n    },\n    \"gc_bytes_reclaimed\": 13660012170840,\n    \"gc_bytes_reclaimed_details\": {\n      \"rate\": 6583379.2\n    },\n    \"context_switches\": 974149754,\n    \"context_switches_details\": {\n      \"rate\": 270\n    },\n    \"io_read_count\": 1,\n    \"io_read_count_details\": {\n      \"rate\": 0\n    },\n    \"io_read_bytes\": 1,\n    \"io_read_bytes_details\": {\n      \"rate\": 0\n    },\n    \"io_read_avg_time\": 0,\n    \"io_read_avg_time_details\": {\n      \"rate\": 0\n    },\n    \"io_write_count\": 45,\n    \"io_write_count_details\": {\n      \"rate\": 0\n    },\n    \"io_write_bytes\": 193066,\n    \"io_write_bytes_details\": {\n      \"rate\": 0\n    },\n    \"io_write_avg_time\": 0,\n    \"io_write_avg_time_details\": {\n      \"rate\": 0\n    },\n    \"io_sync_count\": 45,\n    \"io_sync_count_details\": {\n      \"rate\": 0\n    },\n    \"io_sync_avg_time\": 0,\n    \"io_sync_avg_time_details\": {\n      \"rate\": 0\n    },\n    \"io_seek_count\": 31,\n    \"io_seek_count_details\": {\n      \"rate\": 0\n    },\n    \"io_seek_avg_time\": 0,\n    \"io_seek_avg_time_details\": {\n      \"rate\": 0\n    },\n    \"io_reopen_count\": 0,\n    \"io_reopen_count_details\": {\n      \"rate\": 0\n    },\n    \"mnesia_ram_tx_count\": 2257,\n    \"mnesia_ram_tx_count_details\": {\n      \"rate\": 0\n    },\n    \"mnesia_disk_tx_count\": 103,\n    \"mnesia_disk_tx_count_details\": {\n      \"rate\": 0\n    },\n    \"msg_store_read_count\": 0,\n    \"msg_store_read_count_details\": {\n      \"rate\": 0\n    },\n    \"msg_store_write_count\": 1,\n    \"msg_store_write_count_details\": {\n      \"rate\": 0\n    },\n    \"queue_index_journal_write_count\": 165,\n    \"queue_index_journal_write_count_details\": {\n      \"rate\": 0\n    },\n    \"queue_index_write_count\": 0,\n    \"queue_index_write_count_details\": {\n      \"rate\": 0\n    },\n    \"queue_index_read_count\": 0,\n    \"queue_index_read_count_details\": {\n      \"rate\": 0\n    },\n    \"io_file_handle_open_attempt_count\": 882,\n    \"io_file_handle_open_attempt_count_details\": {\n      \"rate\": 0\n    },\n    \"io_file_handle_open_attempt_avg_time\": 0.05442176870748299,\n    \"io_file_handle_open_attempt_avg_time_details\": {\n      \"rate\": 0\n    },\n    \"connection_created\": 2310,\n    \"connection_created_details\": {\n      \"rate\": 0\n    },\n    \"connection_closed\": 2268,\n    \"connection_closed_details\": {\n      \"rate\": 0\n    },\n    \"channel_created\": 2310,\n    \"channel_created_details\": {\n      \"rate\": 0\n    },\n    \"channel_closed\": 2267,\n    \"channel_closed_details\": {\n      \"rate\": 0\n    },\n    \"queue_declared\": 144281,\n    \"queue_declared_details\": {\n      \"rate\": 0\n    },\n    \"queue_created\": 663,\n    \"queue_created_details\": {\n      \"rate\": 0\n    },\n    \"queue_deleted\": 629,\n    \"queue_deleted_details\": {\n      \"rate\": 0\n    },\n    \"cluster_links\": [],\n    \"metrics_gc_queue_length\": {\n      \"connection_closed\": 0,\n      \"channel_closed\": 0,\n      \"consumer_deleted\": 0,\n      \"exchange_deleted\": 0,\n      \"queue_deleted\": 0,\n      \"vhost_deleted\": 0,\n      \"node_node_deleted\": 0,\n      \"channel_consumer_deleted\": 0\n    }\n  }\n]\n"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/overview.json",
    "content": "{\n    \"management_version\": \"3.8.14\",\n    \"rates_mode\": \"basic\",\n    \"sample_retention_policies\": {\n        \"global\": [\n            600,\n            3600,\n            28800,\n            86400\n        ],\n        \"basic\": [\n            600,\n            3600\n        ],\n        \"detailed\": [\n            600\n        ]\n    },\n    \"exchange_types\": [\n        {\n            \"name\": \"direct\",\n            \"description\": \"AMQP direct exchange, as per the AMQP specification\",\n            \"enabled\": true\n        },\n        {\n            \"name\": \"fanout\",\n            \"description\": \"AMQP fanout exchange, as per the AMQP specification\",\n            \"enabled\": true\n        },\n        {\n            \"name\": \"headers\",\n            \"description\": \"AMQP headers exchange, as per the AMQP specification\",\n            \"enabled\": true\n        },\n        {\n            \"name\": \"topic\",\n            \"description\": \"AMQP topic exchange, as per the AMQP specification\",\n            \"enabled\": true\n        }\n    ],\n    \"product_version\": \"3.8.14\",\n    \"product_name\": \"RabbitMQ\",\n    \"rabbitmq_version\": \"3.8.14\",\n    \"cluster_name\": \"rabbit@rmqserver\",\n    \"erlang_version\": \"23.2.7\",\n    \"erlang_full_version\": \"Erlang/OTP 23 [erts-11.1.8] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1]\",\n    \"disable_stats\": false,\n    \"enable_queue_totals\": false,\n    \"message_stats\": {\n        \"ack\": 3736443,\n        \"ack_details\": {\n            \"rate\": 0.0\n        },\n        \"confirm\": 0,\n        \"confirm_details\": {\n            \"rate\": 0.0\n        },\n        \"deliver\": 3736446,\n        \"deliver_details\": {\n            \"rate\": 0.0\n        },\n        \"deliver_get\": 3736446,\n        \"deliver_get_details\": {\n            \"rate\": 0.0\n        },\n        \"deliver_no_ack\": 0,\n        \"deliver_no_ack_details\": {\n            \"rate\": 0.0\n        },\n        \"disk_reads\": 0,\n        \"disk_reads_details\": {\n            \"rate\": 0.0\n        },\n        \"disk_writes\": 55,\n        \"disk_writes_details\": {\n            \"rate\": 0.0\n        },\n        \"drop_unroutable\": 0,\n        \"drop_unroutable_details\": {\n            \"rate\": 0.0\n        },\n        \"get\": 0,\n        \"get_details\": {\n            \"rate\": 0.0\n        },\n        \"get_empty\": 0,\n        \"get_empty_details\": {\n            \"rate\": 0.0\n        },\n        \"get_no_ack\": 0,\n        \"get_no_ack_details\": {\n            \"rate\": 0.0\n        },\n        \"publish\": 770025,\n        \"publish_details\": {\n            \"rate\": 0.0\n        },\n        \"redeliver\": 1,\n        \"redeliver_details\": {\n            \"rate\": 0.0\n        },\n        \"return_unroutable\": 0,\n        \"return_unroutable_details\": {\n            \"rate\": 0.0\n        }\n    },\n    \"churn_rates\": {\n        \"channel_closed\": 2267,\n        \"channel_closed_details\": {\n            \"rate\": 0.0\n        },\n        \"channel_created\": 2310,\n        \"channel_created_details\": {\n            \"rate\": 0.0\n        },\n        \"connection_closed\": 2268,\n        \"connection_closed_details\": {\n            \"rate\": 0.0\n        },\n        \"connection_created\": 2310,\n        \"connection_created_details\": {\n            \"rate\": 0.0\n        },\n        \"queue_created\": 663,\n        \"queue_created_details\": {\n            \"rate\": 0.0\n        },\n        \"queue_declared\": 144281,\n        \"queue_declared_details\": {\n            \"rate\": 0.0\n        },\n        \"queue_deleted\": 629,\n        \"queue_deleted_details\": {\n            \"rate\": 0.0\n        }\n    },\n    \"queue_totals\": {\n        \"messages\": 30,\n        \"messages_details\": {\n            \"rate\": 0.0\n        },\n        \"messages_ready\": 30,\n        \"messages_ready_details\": {\n            \"rate\": 0.0\n        },\n        \"messages_unacknowledged\": 0,\n        \"messages_unacknowledged_details\": {\n            \"rate\": 0.0\n        }\n    },\n    \"object_totals\": {\n        \"channels\": 43,\n        \"connections\": 43,\n        \"consumers\": 40,\n        \"exchanges\": 8,\n        \"queues\": 37\n    },\n    \"statistics_db_event_queue\": 0,\n    \"node\": \"rabbit@rmqserver\",\n    \"listeners\": [\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"amqp\",\n            \"ip_address\": \"0.0.0.0\",\n            \"port\": 5672,\n            \"socket_opts\": {\n                \"backlog\": 128,\n                \"nodelay\": true,\n                \"linger\": [\n                    true,\n                    0\n                ],\n                \"exit_on_close\": false\n            }\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"amqp\",\n            \"ip_address\": \"::\",\n            \"port\": 5672,\n            \"socket_opts\": {\n                \"backlog\": 128,\n                \"nodelay\": true,\n                \"linger\": [\n                    true,\n                    0\n                ],\n                \"exit_on_close\": false\n            }\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"amqp/ssl\",\n            \"ip_address\": \"0.0.0.0\",\n            \"port\": 5671,\n            \"socket_opts\": {\n                \"backlog\": 128,\n                \"nodelay\": true,\n                \"linger\": [\n                    true,\n                    0\n                ],\n                \"exit_on_close\": false,\n                \"versions\": [\n                    \"tlsv1.3\",\n                    \"tlsv1.2\",\n                    \"tlsv1.1\",\n                    \"tlsv1\"\n                ],\n                \"cacertfile\": \"C:\\\\ProgramData\\\\Chain.pem\",\n                \"certfile\": \"C:\\\\ProgramData\\\\server.crt\",\n                \"keyfile\": \"C:\\\\ProgramData\\\\server.key\",\n                \"verify\": \"verify_peer\",\n                \"depth\": 3,\n                \"fail_if_no_peer_cert\": false\n            }\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"amqp/ssl\",\n            \"ip_address\": \"::\",\n            \"port\": 5671,\n            \"socket_opts\": {\n                \"backlog\": 128,\n                \"nodelay\": true,\n                \"linger\": [\n                    true,\n                    0\n                ],\n                \"exit_on_close\": false,\n                \"versions\": [\n                    \"tlsv1.3\",\n                    \"tlsv1.2\",\n                    \"tlsv1.1\",\n                    \"tlsv1\"\n                ],\n                \"cacertfile\": \"C:\\\\ProgramData\\\\Chain.pem\",\n                \"certfile\": \"C:\\\\ProgramData\\\\server.crt\",\n                \"keyfile\": \"C:\\\\ProgramData\\\\server.key\",\n                \"verify\": \"verify_peer\",\n                \"depth\": 3,\n                \"fail_if_no_peer_cert\": false\n            }\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"clustering\",\n            \"ip_address\": \"::\",\n            \"port\": 25672,\n            \"socket_opts\": []\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"http\",\n            \"ip_address\": \"0.0.0.0\",\n            \"port\": 15672,\n            \"socket_opts\": {\n                \"cowboy_opts\": {\n                    \"sendfile\": false\n                },\n                \"port\": 15672\n            }\n        },\n        {\n            \"node\": \"rabbit@rmqserver\",\n            \"protocol\": \"http\",\n            \"ip_address\": \"::\",\n            \"port\": 15672,\n            \"socket_opts\": {\n                \"cowboy_opts\": {\n                    \"sendfile\": false\n                },\n                \"port\": 15672\n            }\n        }\n    ],\n    \"contexts\": [\n        {\n            \"ssl_opts\": [],\n            \"node\": \"rabbit@rmqserver\",\n            \"description\": \"RabbitMQ Management\",\n            \"path\": \"/\",\n            \"cowboy_opts\": \"[{sendfile,false}]\",\n            \"port\": \"15672\"\n        }\n    ]\n}"
  },
  {
    "path": "plugins/inputs/rabbitmq/testdata/set2/queues.json",
    "content": "[\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": false,\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0,\n      \"avg_ack_ingress_rate\": 0,\n      \"avg_egress_rate\": 0,\n      \"avg_ingress_rate\": 0,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 180,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": \"infinity\"\n    },\n    \"consumer_capacity\": 1,\n    \"consumer_utilisation\": 1,\n    \"consumers\": 1,\n    \"durable\": false,\n    \"effective_policy_definition\": {},\n    \"exclusive\": false,\n    \"exclusive_consumer_tag\": null,\n    \"garbage_collection\": {\n      \"fullsweep_after\": 65535,\n      \"max_heap_size\": 0,\n      \"min_bin_vheap_size\": 46422,\n      \"min_heap_size\": 233,\n      \"minor_gcs\": 16174\n    },\n    \"head_message_timestamp\": null,\n    \"idle_since\": \"2021-06-28 15:54:14\",\n    \"memory\": 15840,\n    \"message_bytes\": 0,\n    \"message_bytes_paged_out\": 0,\n    \"message_bytes_persistent\": 0,\n    \"message_bytes_ram\": 0,\n    \"message_bytes_ready\": 0,\n    \"message_bytes_unacknowledged\": 0,\n    \"message_stats\": {\n      \"ack\": 180,\n      \"ack_details\": {\n        \"rate\": 0\n      },\n      \"deliver\": 180,\n      \"deliver_details\": {\n        \"rate\": 0\n      },\n      \"deliver_get\": 180,\n      \"deliver_get_details\": {\n        \"rate\": 0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"get\": 0,\n      \"get_details\": {\n        \"rate\": 0\n      },\n      \"get_empty\": 0,\n      \"get_empty_details\": {\n        \"rate\": 0\n      },\n      \"get_no_ack\": 0,\n      \"get_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"publish\": 180,\n      \"publish_details\": {\n        \"rate\": 0\n      },\n      \"redeliver\": 0,\n      \"redeliver_details\": {\n        \"rate\": 0\n      }\n    },\n    \"messages\": 0,\n    \"messages_details\": {\n      \"rate\": 0\n    },\n    \"messages_paged_out\": 0,\n    \"messages_persistent\": 0,\n    \"messages_ram\": 0,\n    \"messages_ready\": 0,\n    \"messages_ready_details\": {\n      \"rate\": 0\n    },\n    \"messages_ready_ram\": 0,\n    \"messages_unacknowledged\": 0,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0\n    },\n    \"messages_unacknowledged_ram\": 0,\n    \"name\": \"39fd2caf-63e5-41e3-c15a-ba8fa11434b2\",\n    \"node\": \"rabbit@rmqserver\",\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"recoverable_slaves\": null,\n    \"reductions\": 11766294,\n    \"reductions_details\": {\n      \"rate\": 0\n    },\n    \"single_active_consumer_tag\": null,\n    \"state\": \"running\",\n    \"type\": \"classic\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": false,\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0,\n      \"avg_ack_ingress_rate\": 0,\n      \"avg_egress_rate\": 0,\n      \"avg_ingress_rate\": 0,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 177,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": \"infinity\"\n    },\n    \"consumer_capacity\": 1,\n    \"consumer_utilisation\": 1,\n    \"consumers\": 1,\n    \"durable\": false,\n    \"effective_policy_definition\": {},\n    \"exclusive\": false,\n    \"exclusive_consumer_tag\": null,\n    \"garbage_collection\": {\n      \"fullsweep_after\": 65535,\n      \"max_heap_size\": 0,\n      \"min_bin_vheap_size\": 46422,\n      \"min_heap_size\": 233,\n      \"minor_gcs\": 16205\n    },\n    \"head_message_timestamp\": null,\n    \"idle_since\": \"2021-06-28 15:54:14\",\n    \"memory\": 15600,\n    \"message_bytes\": 0,\n    \"message_bytes_paged_out\": 0,\n    \"message_bytes_persistent\": 0,\n    \"message_bytes_ram\": 0,\n    \"message_bytes_ready\": 0,\n    \"message_bytes_unacknowledged\": 0,\n    \"message_stats\": {\n      \"ack\": 177,\n      \"ack_details\": {\n        \"rate\": 0\n      },\n      \"deliver\": 177,\n      \"deliver_details\": {\n        \"rate\": 0\n      },\n      \"deliver_get\": 177,\n      \"deliver_get_details\": {\n        \"rate\": 0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"get\": 0,\n      \"get_details\": {\n        \"rate\": 0\n      },\n      \"get_empty\": 0,\n      \"get_empty_details\": {\n        \"rate\": 0\n      },\n      \"get_no_ack\": 0,\n      \"get_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"publish\": 177,\n      \"publish_details\": {\n        \"rate\": 0\n      },\n      \"redeliver\": 0,\n      \"redeliver_details\": {\n        \"rate\": 0\n      }\n    },\n    \"messages\": 0,\n    \"messages_details\": {\n      \"rate\": 0\n    },\n    \"messages_paged_out\": 0,\n    \"messages_persistent\": 0,\n    \"messages_ram\": 0,\n    \"messages_ready\": 0,\n    \"messages_ready_details\": {\n      \"rate\": 0\n    },\n    \"messages_ready_ram\": 0,\n    \"messages_unacknowledged\": 0,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0\n    },\n    \"messages_unacknowledged_ram\": 0,\n    \"name\": \"39fd2cb4-aa2d-c08b-457a-62d0893523a1\",\n    \"node\": \"rabbit@rmqserver\",\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"recoverable_slaves\": null,\n    \"reductions\": 11706656,\n    \"reductions_details\": {\n      \"rate\": 0\n    },\n    \"single_active_consumer_tag\": null,\n    \"state\": \"running\",\n    \"type\": \"classic\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": false,\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0,\n      \"avg_ack_ingress_rate\": 0,\n      \"avg_egress_rate\": 0,\n      \"avg_ingress_rate\": 0,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 175,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": \"infinity\"\n    },\n    \"consumer_capacity\": 1,\n    \"consumer_utilisation\": 1,\n    \"consumers\": 1,\n    \"durable\": false,\n    \"effective_policy_definition\": {},\n    \"exclusive\": false,\n    \"exclusive_consumer_tag\": null,\n    \"garbage_collection\": {\n      \"fullsweep_after\": 65535,\n      \"max_heap_size\": 0,\n      \"min_bin_vheap_size\": 46422,\n      \"min_heap_size\": 233,\n      \"minor_gcs\": 16183\n    },\n    \"head_message_timestamp\": null,\n    \"idle_since\": \"2021-06-28 15:54:15\",\n    \"memory\": 15584,\n    \"message_bytes\": 0,\n    \"message_bytes_paged_out\": 0,\n    \"message_bytes_persistent\": 0,\n    \"message_bytes_ram\": 0,\n    \"message_bytes_ready\": 0,\n    \"message_bytes_unacknowledged\": 0,\n    \"message_stats\": {\n      \"ack\": 175,\n      \"ack_details\": {\n        \"rate\": 0\n      },\n      \"deliver\": 175,\n      \"deliver_details\": {\n        \"rate\": 0\n      },\n      \"deliver_get\": 175,\n      \"deliver_get_details\": {\n        \"rate\": 0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"get\": 0,\n      \"get_details\": {\n        \"rate\": 0\n      },\n      \"get_empty\": 0,\n      \"get_empty_details\": {\n        \"rate\": 0\n      },\n      \"get_no_ack\": 0,\n      \"get_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"publish\": 175,\n      \"publish_details\": {\n        \"rate\": 0\n      },\n      \"redeliver\": 0,\n      \"redeliver_details\": {\n        \"rate\": 0\n      }\n    },\n    \"messages\": 0,\n    \"messages_details\": {\n      \"rate\": 0\n    },\n    \"messages_paged_out\": 0,\n    \"messages_persistent\": 0,\n    \"messages_ram\": 0,\n    \"messages_ready\": 0,\n    \"messages_ready_details\": {\n      \"rate\": 0\n    },\n    \"messages_ready_ram\": 0,\n    \"messages_unacknowledged\": 0,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0\n    },\n    \"messages_unacknowledged_ram\": 0,\n    \"name\": \"39fd2cb5-3820-e01b-6e20-ba29d5553fc3\",\n    \"node\": \"rabbit@rmqserver\",\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"recoverable_slaves\": null,\n    \"reductions\": 11649471,\n    \"reductions_details\": {\n      \"rate\": 0\n    },\n    \"single_active_consumer_tag\": null,\n    \"state\": \"running\",\n    \"type\": \"classic\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": false,\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0,\n      \"avg_ack_ingress_rate\": 0,\n      \"avg_egress_rate\": 0,\n      \"avg_ingress_rate\": 0,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 100,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": \"infinity\"\n    },\n    \"consumer_capacity\": 1,\n    \"consumer_utilisation\": 1,\n    \"consumers\": 1,\n    \"durable\": false,\n    \"effective_policy_definition\": {},\n    \"exclusive\": false,\n    \"exclusive_consumer_tag\": null,\n    \"garbage_collection\": {\n      \"fullsweep_after\": 65535,\n      \"max_heap_size\": 0,\n      \"min_bin_vheap_size\": 46422,\n      \"min_heap_size\": 233,\n      \"minor_gcs\": 1000\n    },\n    \"head_message_timestamp\": null,\n    \"idle_since\": \"2021-06-28 15:54:17\",\n    \"memory\": 12000,\n    \"message_bytes\": 0,\n    \"message_bytes_paged_out\": 0,\n    \"message_bytes_persistent\": 0,\n    \"message_bytes_ram\": 0,\n    \"message_bytes_ready\": 0,\n    \"message_bytes_unacknowledged\": 0,\n    \"message_stats\": {\n      \"ack\": 100,\n      \"ack_details\": {\n        \"rate\": 0\n      },\n      \"deliver\": 100,\n      \"deliver_details\": {\n        \"rate\": 0\n      },\n      \"deliver_get\": 100,\n      \"deliver_get_details\": {\n        \"rate\": 0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"get\": 0,\n      \"get_details\": {\n        \"rate\": 0\n      },\n      \"get_empty\": 0,\n      \"get_empty_details\": {\n        \"rate\": 0\n      },\n      \"get_no_ack\": 0,\n      \"get_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"publish\": 100,\n      \"publish_details\": {\n        \"rate\": 0\n      },\n      \"redeliver\": 0,\n      \"redeliver_details\": {\n        \"rate\": 0\n      }\n    },\n    \"messages\": 0,\n    \"messages_details\": {\n      \"rate\": 0\n    },\n    \"messages_paged_out\": 0,\n    \"messages_persistent\": 0,\n    \"messages_ram\": 0,\n    \"messages_ready\": 0,\n    \"messages_ready_details\": {\n      \"rate\": 0\n    },\n    \"messages_ready_ram\": 0,\n    \"messages_unacknowledged\": 0,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0\n    },\n    \"messages_unacknowledged_ram\": 0,\n    \"name\": \"no-type-queue-set2\",\n    \"node\": \"rabbit@rmqserver\",\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"recoverable_slaves\": null,\n    \"reductions\": 5000000,\n    \"reductions_details\": {\n      \"rate\": 0\n    },\n    \"single_active_consumer_tag\": null,\n    \"state\": \"running\",\n    \"type\": \"\",\n    \"vhost\": \"/\"\n  },\n  {\n    \"arguments\": {\n      \"x-expires\": 300000\n    },\n    \"auto_delete\": false,\n    \"backing_queue_status\": {\n      \"avg_ack_egress_rate\": 0,\n      \"avg_ack_ingress_rate\": 0,\n      \"avg_egress_rate\": 0,\n      \"avg_ingress_rate\": 0,\n      \"delta\": [\n        \"delta\",\n        \"undefined\",\n        0,\n        0,\n        \"undefined\"\n      ],\n      \"len\": 0,\n      \"mode\": \"default\",\n      \"next_seq_id\": 200,\n      \"q1\": 0,\n      \"q2\": 0,\n      \"q3\": 0,\n      \"q4\": 0,\n      \"target_ram_count\": \"infinity\"\n    },\n    \"consumer_capacity\": 1,\n    \"consumer_utilisation\": 1,\n    \"consumers\": 1,\n    \"durable\": false,\n    \"effective_policy_definition\": {},\n    \"exclusive\": false,\n    \"exclusive_consumer_tag\": null,\n    \"garbage_collection\": {\n      \"fullsweep_after\": 65535,\n      \"max_heap_size\": 0,\n      \"min_bin_vheap_size\": 46422,\n      \"min_heap_size\": 233,\n      \"minor_gcs\": 2000\n    },\n    \"head_message_timestamp\": null,\n    \"idle_since\": \"2021-06-28 16:30:45\",\n    \"memory\": 15000,\n    \"message_bytes\": 0,\n    \"message_bytes_paged_out\": 0,\n    \"message_bytes_persistent\": 0,\n    \"message_bytes_ram\": 0,\n    \"message_bytes_ready\": 0,\n    \"message_bytes_unacknowledged\": 0,\n    \"message_stats\": {\n      \"ack\": 200,\n      \"ack_details\": {\n        \"rate\": 0\n      },\n      \"deliver\": 200,\n      \"deliver_details\": {\n        \"rate\": 0\n      },\n      \"deliver_get\": 200,\n      \"deliver_get_details\": {\n        \"rate\": 0\n      },\n      \"deliver_no_ack\": 0,\n      \"deliver_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"get\": 0,\n      \"get_details\": {\n        \"rate\": 0\n      },\n      \"get_empty\": 0,\n      \"get_empty_details\": {\n        \"rate\": 0\n      },\n      \"get_no_ack\": 0,\n      \"get_no_ack_details\": {\n        \"rate\": 0\n      },\n      \"publish\": 200,\n      \"publish_details\": {\n        \"rate\": 0\n      },\n      \"redeliver\": 0,\n      \"redeliver_details\": {\n        \"rate\": 0\n      }\n    },\n    \"messages\": 0,\n    \"messages_details\": {\n      \"rate\": 0\n    },\n    \"messages_paged_out\": 0,\n    \"messages_persistent\": 0,\n    \"messages_ram\": 0,\n    \"messages_ready\": 0,\n    \"messages_ready_details\": {\n      \"rate\": 0\n    },\n    \"messages_ready_ram\": 0,\n    \"messages_unacknowledged\": 0,\n    \"messages_unacknowledged_details\": {\n      \"rate\": 0\n    },\n    \"messages_unacknowledged_ram\": 0,\n    \"name\": \"invalid-type-queue-set2\",\n    \"node\": \"rabbit@rmqserver\",\n    \"operator_policy\": null,\n    \"policy\": null,\n    \"recoverable_slaves\": null,\n    \"reductions\": 10000000,\n    \"reductions_details\": {\n      \"rate\": 0\n    },\n    \"single_active_consumer_tag\": null,\n    \"state\": \"running\",\n    \"type\": \"unknown_type\",\n    \"vhost\": \"/\"\n  }\n]"
  },
  {
    "path": "plugins/inputs/radius/README.md",
    "content": "# Radius Input Plugin\n\nThis plugin collects response times for [Radius][rfc2865] authentication\nrequests.\n\n⭐ Telegraf v1.26.0\n🏷️ server\n💻 all\n\n[rfc2865]: https://datatracker.ietf.org/doc/html/rfc2865\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username`, `password`\nand `secret` option. See the\n[secret-store documentation][SECRETSTORE] for more details on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n[[inputs.radius]]\n  ## An array of Server IPs and ports to gather from. If none specified, defaults to localhost.\n  servers = [\"127.0.0.1:1812\",\"hostname.domain.com:1812\"]\n\n  ## Credentials for radius authentication.\n  username = \"myuser\"\n  password = \"mypassword\"\n  secret = \"mysecret\"\n\n  ## Request source server IP, normally the server running telegraf.\n  ## This corresponds to Radius' NAS-IP-Address.\n  # request_ip = \"127.0.0.1\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n```\n\n## Metrics\n\n- radius\n  - tags:\n    - response_code\n    - source\n    - source_port\n  - fields:\n    - responsetime_ms (int64)\n\n## Example Output\n\n```text\nradius,response_code=Access-Accept,source=hostname.com,source_port=1812 responsetime_ms=311i 1677526200000000000\n```\n"
  },
  {
    "path": "plugins/inputs/radius/radius.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage radius\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"layeh.com/radius\"\n\t\"layeh.com/radius/rfc2865\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Radius struct {\n\tServers         []string        `toml:\"servers\"`\n\tUsername        config.Secret   `toml:\"username\"`\n\tPassword        config.Secret   `toml:\"password\"`\n\tSecret          config.Secret   `toml:\"secret\"`\n\tResponseTimeout config.Duration `toml:\"response_timeout\"`\n\tRequestIP       string          `toml:\"request_ip\"`\n\tLog             telegraf.Logger `toml:\"-\"`\n\tclient          radius.Client\n}\n\nfunc (*Radius) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Radius) Init() error {\n\tif len(r.Servers) == 0 {\n\t\tr.Servers = []string{\"127.0.0.1:1812\"}\n\t}\n\n\tr.client = radius.Client{\n\t\tRetry: 0,\n\t}\n\n\tif r.RequestIP == \"\" {\n\t\tr.RequestIP = \"127.0.0.1\"\n\t}\n\tif net.ParseIP(r.RequestIP) == nil {\n\t\treturn fmt.Errorf(\"invalid ip address provided for request_ip: %s\", r.RequestIP)\n\t}\n\n\treturn nil\n}\n\nfunc (r *Radius) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, server := range r.Servers {\n\t\twg.Add(1)\n\t\tgo func(server string) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(r.pollServer(acc, server))\n\t\t}(server)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\nfunc (r *Radius) pollServer(acc telegraf.Accumulator, server string) error {\n\t// Create the fields for this metric\n\thost, port, err := net.SplitHostPort(server)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"splitting host and port failed: %w\", err)\n\t}\n\ttags := map[string]string{\"source\": host, \"source_port\": port}\n\tfields := make(map[string]interface{})\n\n\tsecret, err := r.Secret.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting secret failed: %w\", err)\n\t}\n\tdefer secret.Destroy()\n\n\tusername, err := r.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tdefer username.Destroy()\n\n\tpassword, err := r.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tdefer password.Destroy()\n\n\t// Create the radius packet with PAP authentication\n\tpacket := radius.New(radius.CodeAccessRequest, secret.Bytes())\n\tif err := rfc2865.UserName_Set(packet, username.Bytes()); err != nil {\n\t\treturn fmt.Errorf(\"setting username for radius auth failed: %w\", err)\n\t}\n\n\t// The radius client requires the password in a buffer with capacity being\n\t// a multiple of 16 for internal operations. To not expose the password we\n\t// grow the (potentially protected) buffer to the required capacity.\n\tcapacity := password.Size()\n\tif capacity%16 != 0 {\n\t\tpassword.Grow(capacity + 16 - capacity%16)\n\t}\n\n\tif err := rfc2865.UserPassword_Set(packet, password.Bytes()[:capacity]); err != nil {\n\t\treturn fmt.Errorf(\"setting password for radius auth failed: %w\", err)\n\t}\n\n\tif r.RequestIP != \"\" {\n\t\tif err := rfc2865.NASIPAddress_Set(packet, net.ParseIP(r.RequestIP)); err != nil {\n\t\t\treturn fmt.Errorf(\"setting NAS IP address for radius auth failed: %w\", err)\n\t\t}\n\t}\n\n\t// Do the radius request\n\tctx := context.Background()\n\tif r.ResponseTimeout > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, time.Duration(r.ResponseTimeout))\n\t\tdefer cancel()\n\t}\n\n\tstartTime := time.Now()\n\tresponse, err := r.client.Exchange(ctx, packet, server)\n\tduration := time.Since(startTime)\n\n\tif err != nil {\n\t\tif !errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn err\n\t\t}\n\t\tfields[\"responsetime_ms\"] = time.Duration(r.ResponseTimeout).Milliseconds()\n\t\ttags[\"response_code\"] = \"timeout\"\n\t} else if response.Code != radius.CodeAccessAccept {\n\t\tfields[\"responsetime_ms\"] = time.Duration(r.ResponseTimeout).Milliseconds()\n\t\ttags[\"response_code\"] = response.Code.String()\n\t} else {\n\t\tfields[\"responsetime_ms\"] = duration.Milliseconds()\n\t\ttags[\"response_code\"] = response.Code.String()\n\t}\n\n\tacc.AddFields(\"radius\", fields, tags)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"radius\", func() telegraf.Input {\n\t\treturn &Radius{ResponseTimeout: config.Duration(time.Second * 5)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/radius/radius_test.go",
    "content": "package radius\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\t\"layeh.com/radius\"\n\t\"layeh.com/radius/rfc2865\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRadiusLocal(t *testing.T) {\n\thandler := func(w radius.ResponseWriter, r *radius.Request) {\n\t\tusername := rfc2865.UserName_GetString(r.Packet)\n\t\tpassword := rfc2865.UserPassword_GetString(r.Packet)\n\n\t\tvar code radius.Code\n\t\tif username == \"testusername\" && password == \"testpassword\" {\n\t\t\tcode = radius.CodeAccessAccept\n\t\t} else {\n\t\t\tcode = radius.CodeAccessReject\n\t\t}\n\t\tif err := w.Write(r.Response(code)); err != nil {\n\t\t\trequire.NoError(t, err, \"failed writing radius server response\")\n\t\t}\n\t}\n\n\t// Setup a connection to be able to get a random port\n\tconn, err := net.ListenPacket(\"udp4\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\tdefer conn.Close()\n\taddr := conn.LocalAddr().String()\n\thost, port, err := net.SplitHostPort(addr)\n\trequire.NoError(t, err)\n\n\tserver := radius.PacketServer{\n\t\tHandler:      radius.HandlerFunc(handler),\n\t\tSecretSource: radius.StaticSecretSource([]byte(`testsecret`)),\n\t\tAddr:         addr,\n\t}\n\n\tgo func() {\n\t\tif err := server.Serve(conn); err != nil {\n\t\t\tif !errors.Is(err, radius.ErrServerShutdown) {\n\t\t\t\tt.Errorf(\"Local radius server failed: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tplugin := &Radius{\n\t\tServers:  []string{addr},\n\t\tUsername: config.NewSecret([]byte(`testusername`)),\n\t\tPassword: config.NewSecret([]byte(`testpassword`)),\n\t\tSecret:   config.NewSecret([]byte(`testsecret`)),\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\tif !acc.HasMeasurement(\"radius\") {\n\t\tt.Errorf(\"acc.HasMeasurement: expected radius\")\n\t}\n\trequire.True(t, acc.HasTag(\"radius\", \"source\"))\n\trequire.True(t, acc.HasTag(\"radius\", \"source_port\"))\n\trequire.True(t, acc.HasTag(\"radius\", \"response_code\"))\n\trequire.Equal(t, host, acc.TagValue(\"radius\", \"source\"))\n\trequire.Equal(t, port, acc.TagValue(\"radius\", \"source_port\"))\n\trequire.Equal(t, radius.CodeAccessAccept.String(), acc.TagValue(\"radius\", \"response_code\"))\n\trequire.True(t, acc.HasInt64Field(\"radius\", \"responsetime_ms\"))\n\n\tif err := server.Shutdown(t.Context()); err != nil {\n\t\trequire.NoError(t, err, \"failed to properly shutdown local radius server\")\n\t}\n}\n\nfunc TestRadiusNASIP(t *testing.T) {\n\thandler := func(w radius.ResponseWriter, r *radius.Request) {\n\t\tusername := rfc2865.UserName_GetString(r.Packet)\n\t\tpassword := rfc2865.UserPassword_GetString(r.Packet)\n\t\tip := rfc2865.NASIPAddress_Get(r.Packet)\n\n\t\tvar code radius.Code\n\t\tif username == \"testusername\" && password == \"testpassword\" &&\n\t\t\tip.Equal(net.ParseIP(\"127.0.0.1\")) {\n\t\t\tcode = radius.CodeAccessAccept\n\t\t} else {\n\t\t\tcode = radius.CodeAccessReject\n\t\t}\n\t\tif err := w.Write(r.Response(code)); err != nil {\n\t\t\trequire.NoError(t, err, \"failed writing radius server response\")\n\t\t}\n\t}\n\n\t// Setup a connection to be able to get a random port\n\tconn, err := net.ListenPacket(\"udp4\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\tdefer conn.Close()\n\taddr := conn.LocalAddr().String()\n\thost, port, err := net.SplitHostPort(addr)\n\trequire.NoError(t, err)\n\n\tserver := radius.PacketServer{\n\t\tHandler:      radius.HandlerFunc(handler),\n\t\tSecretSource: radius.StaticSecretSource([]byte(`testsecret`)),\n\t\tAddr:         addr,\n\t}\n\n\tgo func() {\n\t\tif err := server.Serve(conn); err != nil {\n\t\t\tif !errors.Is(err, radius.ErrServerShutdown) {\n\t\t\t\tt.Errorf(\"Local radius server failed: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tplugin := &Radius{\n\t\tServers:   []string{addr},\n\t\tUsername:  config.NewSecret([]byte(`testusername`)),\n\t\tPassword:  config.NewSecret([]byte(`testpassword`)),\n\t\tSecret:    config.NewSecret([]byte(`testsecret`)),\n\t\tLog:       testutil.Logger{},\n\t\tRequestIP: \"127.0.0.1\",\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\tif !acc.HasMeasurement(\"radius\") {\n\t\tt.Errorf(\"acc.HasMeasurement: expected radius\")\n\t}\n\trequire.True(t, acc.HasTag(\"radius\", \"source\"))\n\trequire.True(t, acc.HasTag(\"radius\", \"source_port\"))\n\trequire.True(t, acc.HasTag(\"radius\", \"response_code\"))\n\trequire.Equal(t, host, acc.TagValue(\"radius\", \"source\"))\n\trequire.Equal(t, port, acc.TagValue(\"radius\", \"source_port\"))\n\trequire.Equal(t, radius.CodeAccessAccept.String(), acc.TagValue(\"radius\", \"response_code\"))\n\trequire.True(t, acc.HasInt64Field(\"radius\", \"responsetime_ms\"))\n\n\tif err := server.Shutdown(t.Context()); err != nil {\n\t\trequire.NoError(t, err, \"failed to properly shutdown local radius server\")\n\t}\n}\n\nfunc TestInvalidRequestIP(t *testing.T) {\n\tplugin := &Radius{\n\t\tServers:   []string{\"127.0.0.1\"},\n\t\tUsername:  config.NewSecret([]byte(`testusername`)),\n\t\tPassword:  config.NewSecret([]byte(`testpassword`)),\n\t\tSecret:    config.NewSecret([]byte(`testsecret`)),\n\t\tLog:       testutil.Logger{},\n\t\tRequestIP: \"foobar\",\n\t}\n\trequire.Error(t, plugin.Init())\n}\n\nfunc TestRadiusIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\ttestdata, err := filepath.Abs(\"testdata/raddb/clients.conf\")\n\trequire.NoError(t, err, \"determining absolute path of test-data clients.conf failed\")\n\ttestdataa, err := filepath.Abs(\"testdata/raddb/mods-config/files/authorize\")\n\trequire.NoError(t, err, \"determining absolute path of test-data authorize failed\")\n\ttestdataaa, err := filepath.Abs(\"testdata/raddb/radiusd.conf\")\n\trequire.NoError(t, err, \"determining absolute path of test-data radiusd.conf failed\")\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"freeradius/freeradius-server\",\n\t\tExposedPorts: []string{\"1812/udp\"},\n\t\tFiles: map[string]string{\n\t\t\t\"/etc/raddb/clients.conf\":                testdata,\n\t\t\t\"/etc/raddb/mods-config/files/authorize\": testdataa,\n\t\t\t\"/etc/raddb/radiusd.conf\":                testdataaa,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"Ready to process requests\"),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport := container.Ports[\"1812\"]\n\n\t// Define the testset\n\tvar testset = []struct {\n\t\tname               string\n\t\ttestingTimeout     config.Duration\n\t\texpectedSource     string\n\t\texpectedSourcePort string\n\t\tserverToTest       string\n\t\texpectSuccess      bool\n\t\tusedPassword       string\n\t}{\n\t\t{\n\t\t\tname:               \"timeout_5s\",\n\t\t\ttestingTimeout:     config.Duration(time.Second * 5),\n\t\t\texpectedSource:     container.Address,\n\t\t\texpectedSourcePort: port,\n\t\t\tserverToTest:       container.Address + \":\" + port,\n\t\t\texpectSuccess:      true,\n\t\t\tusedPassword:       \"testpassword\",\n\t\t},\n\t\t{\n\t\t\tname:               \"timeout_0s\",\n\t\t\ttestingTimeout:     config.Duration(0),\n\t\t\texpectedSource:     container.Address,\n\t\t\texpectedSourcePort: port,\n\t\t\tserverToTest:       container.Address + \":\" + port,\n\t\t\texpectSuccess:      true,\n\t\t\tusedPassword:       \"testpassword\",\n\t\t},\n\t\t{\n\t\t\tname:               \"wrong_pw\",\n\t\t\ttestingTimeout:     config.Duration(time.Second * 5),\n\t\t\texpectedSource:     container.Address,\n\t\t\texpectedSourcePort: port,\n\t\t\tserverToTest:       container.Address + \":\" + port,\n\t\t\texpectSuccess:      false,\n\t\t\tusedPassword:       \"wrongpass\",\n\t\t},\n\t\t{\n\t\t\tname:               \"unreachable\",\n\t\t\ttestingTimeout:     config.Duration(5),\n\t\t\texpectedSource:     \"unreachable.unreachable.com\",\n\t\t\texpectedSourcePort: \"7777\",\n\t\t\tserverToTest:       \"unreachable.unreachable.com:7777\",\n\t\t\texpectSuccess:      false,\n\t\t\tusedPassword:       \"testpassword\",\n\t\t},\n\t}\n\n\tfor _, tt := range testset {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin-under-test\n\t\t\tplugin := &Radius{\n\t\t\t\tResponseTimeout: tt.testingTimeout,\n\t\t\t\tServers:         []string{tt.serverToTest},\n\t\t\t\tUsername:        config.NewSecret([]byte(`testusername`)),\n\t\t\t\tPassword:        config.NewSecret([]byte(tt.usedPassword)),\n\t\t\t\tSecret:          config.NewSecret([]byte(`testsecret`)),\n\t\t\t\tLog:             testutil.Logger{},\n\t\t\t}\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\t// Startup the plugin\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Gather\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\tif !acc.HasMeasurement(\"radius\") {\n\t\t\t\tt.Errorf(\"acc.HasMeasurement: expected radius\")\n\t\t\t}\n\t\t\trequire.True(t, acc.HasTag(\"radius\", \"source\"))\n\t\t\trequire.True(t, acc.HasTag(\"radius\", \"source_port\"))\n\t\t\trequire.True(t, acc.HasTag(\"radius\", \"response_code\"))\n\t\t\trequire.Equal(t, tt.expectedSource, acc.TagValue(\"radius\", \"source\"))\n\t\t\trequire.Equal(t, tt.expectedSourcePort, acc.TagValue(\"radius\", \"source_port\"))\n\t\t\trequire.True(t, acc.HasInt64Field(\"radius\", \"responsetime_ms\"), true)\n\t\t\tif tt.expectSuccess {\n\t\t\t\trequire.Equal(t, radius.CodeAccessAccept.String(), acc.TagValue(\"radius\", \"response_code\"))\n\t\t\t} else {\n\t\t\t\trequire.NotEqual(t, radius.CodeAccessAccept.String(), acc.TagValue(\"radius\", \"response_code\"))\n\t\t\t}\n\n\t\t\tif tt.name == \"unreachable\" {\n\t\t\t\trequire.Equal(t, time.Duration(tt.testingTimeout).Milliseconds(), acc.Metrics[0].Fields[\"responsetime_ms\"])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRadiusIntegrationInvalidSourceIP(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tclients, err := filepath.Abs(\"testdata/invalidSourceIP/clients.conf\")\n\trequire.NoError(t, err, \"determining absolute path of test-data clients.conf failed\")\n\tauthorize, err := filepath.Abs(\"testdata/invalidSourceIP/mods-config/files/authorize\")\n\trequire.NoError(t, err, \"determining absolute path of test-data authorize failed\")\n\tradiusd, err := filepath.Abs(\"testdata/invalidSourceIP/radiusd.conf\")\n\trequire.NoError(t, err, \"determining absolute path of test-data radiusd.conf failed\")\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"freeradius/freeradius-server\",\n\t\tExposedPorts: []string{\"1812/udp\"},\n\t\tFiles: map[string]string{\n\t\t\t\"/etc/raddb/clients.conf\":                clients,\n\t\t\t\"/etc/raddb/mods-config/files/authorize\": authorize,\n\t\t\t\"/etc/raddb/radiusd.conf\":                radiusd,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"Ready to process requests\"),\n\t\t),\n\t}\n\terr = container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\tport := container.Ports[\"1812\"]\n\tplugin := &Radius{\n\t\tResponseTimeout: config.Duration(time.Second * 1),\n\t\tServers:         []string{container.Address + \":\" + port},\n\t\tUsername:        config.NewSecret([]byte(`testusername`)),\n\t\tPassword:        config.NewSecret([]byte(`testpassword`)),\n\t\tSecret:          config.NewSecret([]byte(`testsecret`)),\n\t\tLog:             testutil.Logger{},\n\t}\n\n\texpected := testutil.MustMetric(\n\t\t\"radius\",\n\t\tmap[string]string{\n\t\t\t\"source\":        container.Address,\n\t\t\t\"source_port\":   port,\n\t\t\t\"response_code\": \"timeout\",\n\t\t},\n\t\tmap[string]interface{}{\n\t\t\t\"responsetime_ms\": 1000,\n\t\t},\n\t\ttime.Time{},\n\t)\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Gather(&acc))\n\tmetrics := acc.GetTelegrafMetrics()\n\trequire.Len(t, metrics, 1)\n\ttestutil.RequireMetricEqual(t, expected, metrics[0], testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/radius/sample.conf",
    "content": "[[inputs.radius]]\n  ## An array of Server IPs and ports to gather from. If none specified, defaults to localhost.\n  servers = [\"127.0.0.1:1812\",\"hostname.domain.com:1812\"]\n\n  ## Credentials for radius authentication.\n  username = \"myuser\"\n  password = \"mypassword\"\n  secret = \"mysecret\"\n\n  ## Request source server IP, normally the server running telegraf.\n  ## This corresponds to Radius' NAS-IP-Address.\n  # request_ip = \"127.0.0.1\"\n\n  ## Maximum time to receive response.\n  # response_timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/invalidSourceIP/clients.conf",
    "content": "client localtest {\n\tipaddr = 10.123.123.0/24\n\tsecret = testsecret\n}\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/invalidSourceIP/mods-config/files/authorize",
    "content": "testusername\tCleartext-Password := \"testpassword\"\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/invalidSourceIP/radiusd.conf",
    "content": "prefix = /usr\nexec_prefix = /usr\nsysconfdir = /etc\nlocalstatedir = /var\nsbindir = ${exec_prefix}/sbin\nlogdir = /var/log/freeradius\nraddbdir = /etc/freeradius\nradacctdir = ${logdir}/radacct\n\nname = freeradius\n\nconfdir = ${raddbdir}\nmodconfdir = ${confdir}/mods-config\ncertdir = ${confdir}/certs\ncadir   = ${confdir}/certs\nrun_dir = ${localstatedir}/run/${name}\n\ndb_dir = ${raddbdir}\n\nlibdir = /usr/lib/freeradius\n\npidfile = ${run_dir}/${name}.pid\n\n\nmax_request_time = 30\n\ncleanup_delay = 5\n\nmax_requests = 16384\n\nhostname_lookups = no\n\n\nlog {\n\tdestination = stdout\n\n\tcolourise = yes\n\n\tfile = ${logdir}/radius.log\n\n\tsyslog_facility = daemon\n\n\tstripped_names = no\n\n\tauth = yes\n\n\n\n\tauth_badpass = yes\n\tauth_goodpass = yes\n\n\n\tmsg_denied = \"You are already logged in - access denied\"\n\n}\n\ncheckrad = ${sbindir}/checkrad\n\nENV {\n\n\n}\n\nsecurity {\n\n\tuser = freerad\n\tgroup = freerad\n\n\tallow_core_dumps = no\n\n\tmax_attributes = 200\n\n\treject_delay = 1\n\n\tstatus_server = yes\n\n\n}\n\nproxy_requests  = yes\n$INCLUDE proxy.conf\n\n\n\n$INCLUDE clients.conf\n\n\nthread pool {\n\tstart_servers = 5\n\n\tmax_servers = 32\n\n\tmin_spare_servers = 3\n\tmax_spare_servers = 10\n\n\n\tmax_requests_per_server = 0\n\n\n\tauto_limit_acct = no\n}\n\n\nmodules {\n\n\n\t$INCLUDE mods-enabled/\n}\n\ninstantiate {\n\n}\n\npolicy {\n\t$INCLUDE policy.d/\n}\n\n$INCLUDE sites-enabled/\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/raddb/clients.conf",
    "content": "client localtest {\n\tipaddr = 0.0.0.0/0\n\tsecret = testsecret\n}\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/raddb/mods-config/files/authorize",
    "content": "testusername\tCleartext-Password := \"testpassword\"\n"
  },
  {
    "path": "plugins/inputs/radius/testdata/raddb/radiusd.conf",
    "content": "prefix = /usr\nexec_prefix = /usr\nsysconfdir = /etc\nlocalstatedir = /var\nsbindir = ${exec_prefix}/sbin\nlogdir = /var/log/freeradius\nraddbdir = /etc/freeradius\nradacctdir = ${logdir}/radacct\n\nname = freeradius\n\nconfdir = ${raddbdir}\nmodconfdir = ${confdir}/mods-config\ncertdir = ${confdir}/certs\ncadir   = ${confdir}/certs\nrun_dir = ${localstatedir}/run/${name}\n\ndb_dir = ${raddbdir}\n\nlibdir = /usr/lib/freeradius\n\npidfile = ${run_dir}/${name}.pid\n\n\nmax_request_time = 30\n\ncleanup_delay = 5\n\nmax_requests = 16384\n\nhostname_lookups = no\n\n\nlog {\n\tdestination = stdout \n\n\tcolourise = yes\n\n\tfile = ${logdir}/radius.log\n\n\tsyslog_facility = daemon\n\n\tstripped_names = no\n\n\tauth = yes\n\n\n\n\tauth_badpass = yes\n\tauth_goodpass = yes\n\n\n\tmsg_denied = \"You are already logged in - access denied\"\n\n}\n\ncheckrad = ${sbindir}/checkrad\n\nENV {\n\n\n}\n\nsecurity {\n\n\tuser = freerad\n\tgroup = freerad\n\n\tallow_core_dumps = no\n\n\tmax_attributes = 200\n\n\treject_delay = 1\n\n\tstatus_server = yes\n\n\n}\n\nproxy_requests  = yes\n$INCLUDE proxy.conf\n\n\n\n$INCLUDE clients.conf\n\n\nthread pool {\n\tstart_servers = 5\n\n\tmax_servers = 32\n\n\tmin_spare_servers = 3\n\tmax_spare_servers = 10\n\n\n\tmax_requests_per_server = 0\n\n\n\tauto_limit_acct = no\n}\n\n\nmodules {\n\n\n\t$INCLUDE mods-enabled/\n}\n\ninstantiate {\n\n}\n\npolicy {\n\t$INCLUDE policy.d/\n}\n\n$INCLUDE sites-enabled/\n"
  },
  {
    "path": "plugins/inputs/raindrops/README.md",
    "content": "# Raindrops Middleware Input Plugin\n\nThis plugin collects statistics for [Raindrops middleware][raindrops] instances.\n\n⭐ Telegraf v0.10.3\n🏷️ server\n💻 all\n\n[raindrops]: http://raindrops.bogomips.org/Raindrops/Middleware.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read raindrops stats (raindrops - real-time stats for preforking Rack servers)\n[[inputs.raindrops]]\n  ## An array of raindrops middleware URI to gather stats.\n  urls = [\"http://localhost:8080/_raindrops\"]\n```\n\n## Metrics\n\n- raindrops\n  - tags:\n    - server\n    - port\n  - fields:\n    - calling (integer, count)\n    - writing (integer, count)\n- raindrops_listen\n  - tags:\n    - ip   (IP only)\n    - port (IP only)\n    - socket (unix socket only)\n  - fields:\n    - active (integer, bytes)\n    - queued (integer, bytes)\n\n## Example Output\n\n```text\nraindrops,port=8080,server=localhost calling=0i,writing=0i 1455479896806238204\nraindrops_listen,ip=0.0.0.0,port=8080 active=0i,queued=0i 1455479896806561938\nraindrops_listen,ip=0.0.0.0,port=8081 active=1i,queued=0i 1455479896806605749\nraindrops_listen,ip=127.0.0.1,port=8082 active=0i,queued=0i 1455479896806646315\nraindrops_listen,ip=0.0.0.0,port=8083 active=0i,queued=0i 1455479896806683252\nraindrops_listen,ip=0.0.0.0,port=8084 active=0i,queued=0i 1455479896806712025\nraindrops_listen,ip=0.0.0.0,port=3000 active=0i,queued=0i 1455479896806779197\nraindrops_listen,socket=/tmp/listen.me active=0i,queued=0i 1455479896806813907\n```\n"
  },
  {
    "path": "plugins/inputs/raindrops/raindrops.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage raindrops\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Raindrops struct {\n\tUrls       []string `toml:\"urls\"`\n\thttpClient *http.Client\n}\n\nfunc (*Raindrops) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Raindrops) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, u := range r.Urls {\n\t\taddr, err := url.Parse(u)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse address %q: %w\", u, err))\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(addr *url.URL) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(r.gatherURL(addr, acc))\n\t\t}(addr)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (r *Raindrops) gatherURL(addr *url.URL, acc telegraf.Accumulator) error {\n\tresp, err := r.httpClient.Get(addr.String())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error making HTTP request to %q: %w\", addr.String(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s\", addr.String(), resp.Status)\n\t}\n\tbuf := bufio.NewReader(resp.Body)\n\n\t// Calling\n\t_, err = buf.ReadString(':')\n\tif err != nil {\n\t\treturn err\n\t}\n\tline, err := buf.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\tcalling, err := strconv.ParseUint(strings.TrimSpace(line), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Writing\n\t_, err = buf.ReadString(':')\n\tif err != nil {\n\t\treturn err\n\t}\n\tline, err = buf.ReadString('\\n')\n\tif err != nil {\n\t\treturn err\n\t}\n\twriting, err := strconv.ParseUint(strings.TrimSpace(line), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttags := getTags(addr)\n\tfields := map[string]interface{}{\n\t\t\"calling\": calling,\n\t\t\"writing\": writing,\n\t}\n\tacc.AddFields(\"raindrops\", fields, tags)\n\n\titerate := true\n\tvar queuedLineStr string\n\tvar activeLineStr string\n\tvar activeErr error\n\tvar queuedErr error\n\n\tfor iterate {\n\t\t// Listen\n\t\tvar tags map[string]string\n\n\t\tlis := map[string]interface{}{\n\t\t\t\"active\": 0,\n\t\t\t\"queued\": 0,\n\t\t}\n\t\tactiveLineStr, activeErr = buf.ReadString('\\n')\n\t\tif activeErr != nil {\n\t\t\tbreak\n\t\t}\n\t\tif strings.Compare(activeLineStr, \"\\n\") == 0 {\n\t\t\tbreak\n\t\t}\n\t\tqueuedLineStr, queuedErr = buf.ReadString('\\n')\n\t\tif queuedErr != nil {\n\t\t\titerate = false\n\t\t}\n\t\tactiveLine := strings.Split(activeLineStr, \" \")\n\t\tlistenName := activeLine[0]\n\n\t\tactive, err := strconv.ParseUint(strings.TrimSpace(activeLine[2]), 10, 64)\n\t\tif err != nil {\n\t\t\tactive = 0\n\t\t}\n\t\tlis[\"active\"] = active\n\n\t\tqueuedLine := strings.Split(queuedLineStr, \" \")\n\t\tqueued, err := strconv.ParseUint(strings.TrimSpace(queuedLine[2]), 10, 64)\n\t\tif err != nil {\n\t\t\tqueued = 0\n\t\t}\n\t\tlis[\"queued\"] = queued\n\t\tif strings.Contains(listenName, \":\") {\n\t\t\tlistener := strings.Split(listenName, \":\")\n\t\t\ttags = map[string]string{\n\t\t\t\t\"ip\":   listener[0],\n\t\t\t\t\"port\": listener[1],\n\t\t\t}\n\t\t} else {\n\t\t\ttags = map[string]string{\n\t\t\t\t\"socket\": listenName,\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"raindrops_listen\", lis, tags)\n\t}\n\treturn nil\n}\n\n// Get tag(s) for the raindrops calling/writing plugin\nfunc getTags(addr *url.URL) map[string]string {\n\th := addr.Host\n\thost, port, err := net.SplitHostPort(h)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\treturn map[string]string{\"server\": host, \"port\": port}\n}\n\nfunc init() {\n\tinputs.Add(\"raindrops\", func() telegraf.Input {\n\t\treturn &Raindrops{httpClient: &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t\t},\n\t\t\tTimeout: 4 * time.Second,\n\t\t}}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/raindrops/raindrops_test.go",
    "content": "package raindrops\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst sampleResponse = `\ncalling: 100\nwriting: 200\n0.0.0.0:8080 active: 1\n0.0.0.0:8080 queued: 2\n0.0.0.0:8081 active: 3\n0.0.0.0:8081 queued: 4\n127.0.0.1:8082 active: 5\n127.0.0.1:8082 queued: 6\n0.0.0.0:8083 active: 7\n0.0.0.0:8083 queued: 8\n0.0.0.0:8084 active: 9\n0.0.0.0:8084 queued: 10\n0.0.0.0:3000 active: 11\n0.0.0.0:3000 queued: 12\n/tmp/listen.me active: 13\n/tmp/listen.me queued: 14`\n\n// Verify that raindrops tags are properly parsed based on the server\nfunc TestRaindropsTags(t *testing.T) {\n\turls := []string{\"http://localhost/_raindrops\", \"http://localhost:80/_raindrops\"}\n\tfor _, url1 := range urls {\n\t\taddr, err := url.Parse(url1)\n\t\trequire.NoError(t, err)\n\t\ttagMap := getTags(addr)\n\t\trequire.Contains(t, tagMap[\"server\"], \"localhost\")\n\t}\n}\n\nfunc TestRaindropsGeneratesMetrics(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.Path != \"/_raindrops\" {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request, expected: %q, actual: %q\", \"/_raindrops\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err := fmt.Fprintln(w, sampleResponse); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tn := &Raindrops{\n\t\tUrls: []string{ts.URL + \"/_raindrops\"},\n\t\thttpClient: &http.Client{Transport: &http.Transport{\n\t\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t}},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr := acc.GatherError(n.Gather)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\t\"calling\": uint64(100),\n\t\t\"writing\": uint64(200),\n\t}\n\taddr, err := url.Parse(ts.URL)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\thost, port, err := net.SplitHostPort(addr.Host)\n\tif err != nil {\n\t\thost = addr.Host\n\t\tif addr.Scheme == \"http\" {\n\t\t\tport = \"80\"\n\t\t} else if addr.Scheme == \"https\" {\n\t\t\tport = \"443\"\n\t\t} else {\n\t\t\tport = \"\"\n\t\t}\n\t}\n\n\ttags := map[string]string{\"server\": host, \"port\": port}\n\tacc.AssertContainsTaggedFields(t, \"raindrops\", fields, tags)\n\n\ttags = map[string]string{\n\t\t\"port\": \"8081\",\n\t\t\"ip\":   \"0.0.0.0\",\n\t}\n\tfields = map[string]interface{}{\n\t\t\"active\": uint64(3),\n\t\t\"queued\": uint64(4),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"raindrops_listen\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/raindrops/sample.conf",
    "content": "# Read raindrops stats (raindrops - real-time stats for preforking Rack servers)\n[[inputs.raindrops]]\n  ## An array of raindrops middleware URI to gather stats.\n  urls = [\"http://localhost:8080/_raindrops\"]\n"
  },
  {
    "path": "plugins/inputs/ras/README.md",
    "content": "# RAS Daemon Input Plugin\n\nThis plugin gathers statistics and error counts provided by the local\n[RAS (reliability, availability and serviceability)][ras] daemon.\n\n> [!NOTE]\n> This plugin requires access to SQLite3 database from `RASDaemon`. Please make\n> sure the Telegraf user has the required permissions to this database!\n\n⭐ Telegraf v1.16.0\n🏷️ server\n💻 linux\n\n[ras]: https://github.com/mchehab/rasdaemon\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# RAS plugin exposes counter metrics for Machine Check Errors provided by RASDaemon (sqlite3 output is required).\n# This plugin ONLY supports Linux on 386, amd64, arm, and arm64\n[[inputs.ras]]\n  ## Optional path to RASDaemon sqlite3 database.\n  ## Default: /var/lib/rasdaemon/ras-mc_event.db\n  # db_path = \"\"\n```\n\nIn addition `RASDaemon` runs, by default, with `--enable-sqlite3` flag. In case\nof problems with SQLite3 database please verify this is still a default option.\n\n## Metrics\n\n- ras\n  - tags:\n    - socket_id\n  - fields:\n    - memory_read_corrected_errors\n    - memory_read_uncorrectable_errors\n    - memory_write_corrected_errors\n    - memory_write_uncorrectable_errors\n    - cache_l0_l1_errors\n    - tlb_instruction_errors\n    - cache_l2_errors\n    - upi_errors\n    - processor_base_errors\n    - processor_bus_errors\n    - internal_timer_errors\n    - smm_handler_code_access_violation_errors\n    - internal_parity_errors\n    - frc_errors\n    - external_mce_errors\n    - microcode_rom_parity_errors\n    - unclassified_mce_errors\n\nPlease note that `processor_base_errors` is aggregate counter measuring the\nfollowing MCE events:\n\n- internal_timer_errors\n- smm_handler_code_access_violation_errors\n- internal_parity_errors\n- frc_errors\n- external_mce_errors\n- microcode_rom_parity_errors\n- unclassified_mce_errors\n\n## Example Output\n\n```text\nras,host=ubuntu,socket_id=0 external_mce_base_errors=1i,frc_errors=1i,instruction_tlb_errors=5i,internal_parity_errors=1i,internal_timer_errors=1i,l0_and_l1_cache_errors=7i,memory_read_corrected_errors=25i,memory_read_uncorrectable_errors=0i,memory_write_corrected_errors=5i,memory_write_uncorrectable_errors=0i,microcode_rom_parity_errors=1i,processor_base_errors=7i,processor_bus_errors=1i,smm_handler_code_access_violation_errors=1i,unclassified_mce_base_errors=1i 1598867393000000000\nras,host=ubuntu level_2_cache_errors=0i,upi_errors=0i 1598867393000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ras/ras.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux && (386 || amd64 || arm || arm64)\n\npackage ras\n\nimport (\n\t\"database/sql\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t// Required for SQL framework driver\n\t_ \"modernc.org/sqlite\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmceQuery = `\n\t\tSELECT\n\t\t\tid, timestamp, error_msg, mcistatus_msg, socketid\n\t\tFROM mce_record\n\t\tWHERE timestamp > ?\n\t\t`\n\tdefaultDBPath          = \"/var/lib/rasdaemon/ras-mc_event.db\"\n\tdateLayout             = \"2006-01-02 15:04:05 -0700\"\n\tmemoryReadCorrected    = \"memory_read_corrected_errors\"\n\tmemoryReadUncorrected  = \"memory_read_uncorrectable_errors\"\n\tmemoryWriteCorrected   = \"memory_write_corrected_errors\"\n\tmemoryWriteUncorrected = \"memory_write_uncorrectable_errors\"\n\tinstructionCache       = \"cache_l0_l1_errors\"\n\tinstructionTLB         = \"tlb_instruction_errors\"\n\tlevelTwoCache          = \"cache_l2_errors\"\n\tupi                    = \"upi_errors\"\n\tprocessorBase          = \"processor_base_errors\"\n\tprocessorBus           = \"processor_bus_errors\"\n\tinternalTimer          = \"internal_timer_errors\"\n\tsmmHandlerCode         = \"smm_handler_code_access_violation_errors\"\n\tinternalParity         = \"internal_parity_errors\"\n\tfrc                    = \"frc_errors\"\n\texternalMCEBase        = \"external_mce_errors\"\n\tmicrocodeROMParity     = \"microcode_rom_parity_errors\"\n\tunclassifiedMCEBase    = \"unclassified_mce_errors\"\n)\n\ntype Ras struct {\n\tDBPath string          `toml:\"db_path\"`\n\tLog    telegraf.Logger `toml:\"-\"`\n\n\tdb                *sql.DB\n\tlatestTimestamp   time.Time\n\tcpuSocketCounters map[int]metricCounters\n\tserverCounters    metricCounters\n}\n\ntype machineCheckError struct {\n\tid           int\n\ttimestamp    string\n\tsocketID     int\n\terrorMsg     string\n\tmciStatusMsg string\n}\n\ntype metricCounters map[string]int64\n\nfunc (*Ras) SampleConfig() string {\n\treturn sampleConfig\n}\n\n// Start initializes connection to DB, metrics are gathered in Gather\nfunc (r *Ras) Start(telegraf.Accumulator) error {\n\terr := validateDBPath(r.DBPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.db, err = connectToDB(r.DBPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Gather reads the stats provided by RASDaemon and writes it to the Accumulator.\nfunc (r *Ras) Gather(acc telegraf.Accumulator) error {\n\trows, err := r.db.Query(mceQuery, r.latestTimestamp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\n\tfor rows.Next() {\n\t\tmcError, err := fetchMachineCheckError(rows)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttsErr := r.updateLatestTimestamp(mcError.timestamp)\n\t\tif tsErr != nil {\n\t\t\treturn err\n\t\t}\n\t\tr.updateCounters(mcError)\n\t}\n\n\taddCPUSocketMetrics(acc, r.cpuSocketCounters)\n\taddServerMetrics(acc, r.serverCounters)\n\n\treturn nil\n}\n\n// Stop closes any existing DB connection\nfunc (r *Ras) Stop() {\n\tif r.db != nil {\n\t\terr := r.db.Close()\n\t\tif err != nil {\n\t\t\tr.Log.Errorf(\"Error appeared during closing DB (%s): %v\", r.DBPath, err)\n\t\t}\n\t}\n}\n\nfunc (r *Ras) updateLatestTimestamp(timestamp string) error {\n\tts, err := parseDate(timestamp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ts.After(r.latestTimestamp) {\n\t\tr.latestTimestamp = ts\n\t}\n\n\treturn nil\n}\n\nfunc (r *Ras) updateCounters(mcError *machineCheckError) {\n\tif strings.Contains(mcError.errorMsg, \"No Error\") {\n\t\treturn\n\t}\n\n\tr.initializeCPUMetricDataIfRequired(mcError.socketID)\n\tr.updateSocketCounters(mcError)\n\tr.updateServerCounters(mcError)\n}\n\nfunc newMetricCounters() *metricCounters {\n\treturn &metricCounters{\n\t\tmemoryReadCorrected:    0,\n\t\tmemoryReadUncorrected:  0,\n\t\tmemoryWriteCorrected:   0,\n\t\tmemoryWriteUncorrected: 0,\n\t\tinstructionCache:       0,\n\t\tinstructionTLB:         0,\n\t\tprocessorBase:          0,\n\t\tprocessorBus:           0,\n\t\tinternalTimer:          0,\n\t\tsmmHandlerCode:         0,\n\t\tinternalParity:         0,\n\t\tfrc:                    0,\n\t\texternalMCEBase:        0,\n\t\tmicrocodeROMParity:     0,\n\t\tunclassifiedMCEBase:    0,\n\t}\n}\n\nfunc (r *Ras) updateServerCounters(mcError *machineCheckError) {\n\tif strings.Contains(mcError.errorMsg, \"CACHE Level-2\") && strings.Contains(mcError.errorMsg, \"Error\") {\n\t\tr.serverCounters[levelTwoCache]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"UPI:\") {\n\t\tr.serverCounters[upi]++\n\t}\n}\n\nfunc validateDBPath(dbPath string) error {\n\tpathInfo, err := os.Stat(dbPath)\n\tif os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"provided db_path does not exist: [%s]\", dbPath)\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get system information for db_path file %q: %w\", dbPath, err)\n\t}\n\n\tif mode := pathInfo.Mode(); !mode.IsRegular() {\n\t\treturn fmt.Errorf(\"provided db_path does not point to a regular file: [%s]\", dbPath)\n\t}\n\n\treturn nil\n}\n\nfunc connectToDB(dbPath string) (*sql.DB, error) {\n\treturn sql.Open(\"sqlite\", dbPath)\n}\n\nfunc (r *Ras) initializeCPUMetricDataIfRequired(socketID int) {\n\tif _, ok := r.cpuSocketCounters[socketID]; !ok {\n\t\tr.cpuSocketCounters[socketID] = *newMetricCounters()\n\t}\n}\n\nfunc (r *Ras) updateSocketCounters(mcError *machineCheckError) {\n\tr.updateMemoryCounters(mcError)\n\tr.updateProcessorBaseCounters(mcError)\n\n\tif strings.Contains(mcError.errorMsg, \"Instruction TLB\") && strings.Contains(mcError.errorMsg, \"Error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][instructionTLB]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"BUS\") && strings.Contains(mcError.errorMsg, \"Error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][processorBus]++\n\t}\n\n\tif (strings.Contains(mcError.errorMsg, \"CACHE Level-0\") ||\n\t\tstrings.Contains(mcError.errorMsg, \"CACHE Level-1\")) &&\n\t\tstrings.Contains(mcError.errorMsg, \"Error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][instructionCache]++\n\t}\n}\n\nfunc (r *Ras) updateProcessorBaseCounters(mcError *machineCheckError) {\n\tif strings.Contains(mcError.errorMsg, \"Internal Timer error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][internalTimer]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"SMM Handler Code Access Violation\") {\n\t\tr.cpuSocketCounters[mcError.socketID][smmHandlerCode]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"Internal parity error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][internalParity]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"FRC error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][frc]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"External error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][externalMCEBase]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"Microcode ROM parity error\") {\n\t\tr.cpuSocketCounters[mcError.socketID][microcodeROMParity]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n\n\tif strings.Contains(mcError.errorMsg, \"Unclassified\") || strings.Contains(mcError.errorMsg, \"Internal unclassified\") {\n\t\tr.cpuSocketCounters[mcError.socketID][unclassifiedMCEBase]++\n\t\tr.cpuSocketCounters[mcError.socketID][processorBase]++\n\t}\n}\n\nfunc (r *Ras) updateMemoryCounters(mcError *machineCheckError) {\n\tif strings.Contains(mcError.errorMsg, \"Memory read error\") {\n\t\tif strings.Contains(mcError.mciStatusMsg, \"Corrected_error\") {\n\t\t\tr.cpuSocketCounters[mcError.socketID][memoryReadCorrected]++\n\t\t} else {\n\t\t\tr.cpuSocketCounters[mcError.socketID][memoryReadUncorrected]++\n\t\t}\n\t}\n\tif strings.Contains(mcError.errorMsg, \"Memory write error\") {\n\t\tif strings.Contains(mcError.mciStatusMsg, \"Corrected_error\") {\n\t\t\tr.cpuSocketCounters[mcError.socketID][memoryWriteCorrected]++\n\t\t} else {\n\t\t\tr.cpuSocketCounters[mcError.socketID][memoryWriteUncorrected]++\n\t\t}\n\t}\n}\n\nfunc addCPUSocketMetrics(acc telegraf.Accumulator, cpuSocketCounters map[int]metricCounters) {\n\tfor socketID, data := range cpuSocketCounters {\n\t\ttags := map[string]string{\n\t\t\t\"socket_id\": strconv.Itoa(socketID),\n\t\t}\n\t\tfields := make(map[string]interface{})\n\n\t\tfor errorName, count := range data {\n\t\t\tfields[errorName] = count\n\t\t}\n\n\t\tacc.AddCounter(\"ras\", fields, tags)\n\t}\n}\n\nfunc addServerMetrics(acc telegraf.Accumulator, counters map[string]int64) {\n\tfields := make(map[string]interface{})\n\tfor errorName, count := range counters {\n\t\tfields[errorName] = count\n\t}\n\n\tacc.AddCounter(\"ras\", fields, make(map[string]string))\n}\n\nfunc fetchMachineCheckError(rows *sql.Rows) (*machineCheckError, error) {\n\tmcError := &machineCheckError{}\n\terr := rows.Scan(&mcError.id, &mcError.timestamp, &mcError.errorMsg, &mcError.mciStatusMsg, &mcError.socketID)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn mcError, nil\n}\n\nfunc parseDate(date string) (time.Time, error) {\n\treturn time.Parse(dateLayout, date)\n}\n\nfunc init() {\n\tinputs.Add(\"ras\", func() telegraf.Input {\n\t\t//nolint:errcheck // known timestamp\n\t\tdefaultTimestamp, _ := parseDate(\"1970-01-01 00:00:01 -0700\")\n\t\treturn &Ras{\n\t\t\tDBPath:          defaultDBPath,\n\t\t\tlatestTimestamp: defaultTimestamp,\n\t\t\tcpuSocketCounters: map[int]metricCounters{\n\t\t\t\t0: *newMetricCounters(),\n\t\t\t},\n\t\t\tserverCounters: map[string]int64{\n\t\t\t\tlevelTwoCache: 0,\n\t\t\t\tupi:           0,\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ras/ras_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux || (linux && !386 && !amd64 && !arm && !arm64)\n\npackage ras\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Ras struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Ras) SampleConfig() string { return sampleConfig }\n\nfunc (r *Ras) Init() error {\n\tr.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Ras) Gather(telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"ras\", func() telegraf.Input {\n\t\treturn &Ras{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ras/ras_test.go",
    "content": "//go:build linux && (386 || amd64 || arm || arm64)\n\npackage ras\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestUpdateCounters(t *testing.T) {\n\tras := newRas()\n\tfor i := range testData {\n\t\tras.updateCounters(&testData[i])\n\t}\n\n\trequire.Len(t, ras.cpuSocketCounters, 1, \"Should contain counters only for single socket\")\n\n\tfor metric, value := range ras.cpuSocketCounters[0] {\n\t\tif metric == processorBase {\n\t\t\t// processor_base_errors is sum of other seven errors: internal_timer_errors, smm_handler_code_access_violation_errors,\n\t\t\t// internal_parity_errors, frc_errors, external_mce_errors, microcode_rom_parity_errors and unclassified_mce_errors\n\t\t\trequire.Equal(t, int64(7), value, processorBase+\" should have value of 7\")\n\t\t} else {\n\t\t\trequire.Equal(t, int64(1), value, metric+\" should have value of 1\")\n\t\t}\n\t}\n\n\tfor metric, value := range ras.serverCounters {\n\t\trequire.Equal(t, int64(1), value, metric+\" should have value of 1\")\n\t}\n}\n\nfunc TestUpdateLatestTimestamp(t *testing.T) {\n\tras := newRas()\n\tts := \"2020-08-01 15:13:27 +0200\"\n\ttestData = append(testData, []machineCheckError{\n\t\t{\n\t\t\ttimestamp:    \"2019-05-20 08:25:55 +0200\",\n\t\t\tsocketID:     0,\n\t\t\terrorMsg:     \"\",\n\t\t\tmciStatusMsg: \"\",\n\t\t},\n\t\t{\n\t\t\ttimestamp:    \"2018-02-21 12:27:22 +0200\",\n\t\t\tsocketID:     0,\n\t\t\terrorMsg:     \"\",\n\t\t\tmciStatusMsg: \"\",\n\t\t},\n\t\t{\n\t\t\ttimestamp:    ts,\n\t\t\tsocketID:     0,\n\t\t\terrorMsg:     \"\",\n\t\t\tmciStatusMsg: \"\",\n\t\t},\n\t}...)\n\tfor _, mce := range testData {\n\t\terr := ras.updateLatestTimestamp(mce.timestamp)\n\t\trequire.NoError(t, err)\n\t}\n\trequire.Equal(t, ts, ras.latestTimestamp.Format(dateLayout))\n}\n\nfunc TestMultipleSockets(t *testing.T) {\n\tras := newRas()\n\tcacheL2 := \"Instruction CACHE Level-2 Generic Error\"\n\toverflow := \"Error_overflow Corrected_error\"\n\ttestData = []machineCheckError{\n\t\t{\n\t\t\ttimestamp:    \"2019-05-20 08:25:55 +0200\",\n\t\t\tsocketID:     0,\n\t\t\terrorMsg:     cacheL2,\n\t\t\tmciStatusMsg: overflow,\n\t\t},\n\t\t{\n\t\t\ttimestamp:    \"2018-02-21 12:27:22 +0200\",\n\t\t\tsocketID:     1,\n\t\t\terrorMsg:     cacheL2,\n\t\t\tmciStatusMsg: overflow,\n\t\t},\n\t\t{\n\t\t\ttimestamp:    \"2020-03-21 14:17:28 +0200\",\n\t\t\tsocketID:     2,\n\t\t\terrorMsg:     cacheL2,\n\t\t\tmciStatusMsg: overflow,\n\t\t},\n\t\t{\n\t\t\ttimestamp:    \"2020-03-21 17:24:18 +0200\",\n\t\t\tsocketID:     3,\n\t\t\terrorMsg:     cacheL2,\n\t\t\tmciStatusMsg: overflow,\n\t\t},\n\t}\n\tfor i := range testData {\n\t\tras.updateCounters(&testData[i])\n\t}\n\trequire.Len(t, ras.cpuSocketCounters, 4, \"Should contain counters for four sockets\")\n\n\tfor _, metricData := range ras.cpuSocketCounters {\n\t\tfor metric, value := range metricData {\n\t\t\tif metric == levelTwoCache {\n\t\t\t\trequire.Equal(t, int64(1), value, levelTwoCache+\" should have value of 1\")\n\t\t\t} else {\n\t\t\t\trequire.Equal(t, int64(0), value, metric+\" should have value of 0\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestMissingDatabase(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tras := newRas()\n\tras.DBPath = \"/nonexistent/ras.db\"\n\terr := ras.Start(&acc)\n\trequire.Error(t, err)\n}\n\nfunc TestEmptyDatabase(t *testing.T) {\n\tras := newRas()\n\n\trequire.Len(t, ras.cpuSocketCounters, 1, \"Should contain default counters for one socket\")\n\trequire.Len(t, ras.serverCounters, 2, \"Should contain default counters for server\")\n\n\tfor metric, value := range ras.cpuSocketCounters[0] {\n\t\trequire.Equal(t, int64(0), value, metric+\" should have value of 0\")\n\t}\n\n\tfor metric, value := range ras.serverCounters {\n\t\trequire.Equal(t, int64(0), value, metric+\" should have value of 0\")\n\t}\n}\n\nfunc newRas() *Ras {\n\t//nolint:errcheck // known timestamp\n\tdefaultTimestamp, _ := parseDate(\"1970-01-01 00:00:01 -0700\")\n\treturn &Ras{\n\t\tDBPath:          defaultDBPath,\n\t\tlatestTimestamp: defaultTimestamp,\n\t\tcpuSocketCounters: map[int]metricCounters{\n\t\t\t0: *newMetricCounters(),\n\t\t},\n\t\tserverCounters: map[string]int64{\n\t\t\tlevelTwoCache: 0,\n\t\t\tupi:           0,\n\t\t},\n\t}\n}\n\nvar testData = []machineCheckError{\n\t{\n\t\ttimestamp:    \"2020-05-20 07:34:53 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 07:35:11 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"MEMORY CONTROLLER RD_CHANNEL0_ERR Transaction: Memory read error\",\n\t\tmciStatusMsg: \"Uncorrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 07:37:50 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"MEMORY CONTROLLER RD_CHANNEL2_ERR Transaction: Memory write error\",\n\t\tmciStatusMsg: \"Uncorrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:14:51 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"MEMORY CONTROLLER WR_CHANNEL2_ERR Transaction: Memory write error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:15:31 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"corrected filtering (some unreported errors in same region) Instruction CACHE Level-0 Read Error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:16:32 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Instruction TLB Level-0 Error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:16:56 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"No Error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:17:24 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Unclassified\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:17:41 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Microcode ROM parity error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:17:48 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"FRC error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:18:18 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Internal parity error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:18:34 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"SMM Handler Code Access Violation\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:18:54 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Internal Timer error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:21:23 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"BUS Level-3 Generic Generic IO Request-did-not-timeout Error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:23:23 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"External error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:25:31 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"UPI: COR LL Rx detected CRC error - successful LLR without Phy Reinit\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n\t{\n\t\ttimestamp:    \"2020-05-20 08:25:55 +0200\",\n\t\tsocketID:     0,\n\t\terrorMsg:     \"Instruction CACHE Level-2 Generic Error\",\n\t\tmciStatusMsg: \"Error_overflow Corrected_error\",\n\t},\n}\n"
  },
  {
    "path": "plugins/inputs/ras/sample.conf",
    "content": "# RAS plugin exposes counter metrics for Machine Check Errors provided by RASDaemon (sqlite3 output is required).\n# This plugin ONLY supports Linux on 386, amd64, arm, and arm64\n[[inputs.ras]]\n  ## Optional path to RASDaemon sqlite3 database.\n  ## Default: /var/lib/rasdaemon/ras-mc_event.db\n  # db_path = \"\"\n"
  },
  {
    "path": "plugins/inputs/ravendb/README.md",
    "content": "# RavenDB Input Plugin\n\nThis plugin gathers metrics from [RavenDB][ravendb] servers via the monitoring\nAPI.\n\n> [!NOTE]\n> This plugin requires RavenDB Server v5.2+.\n\n⭐ Telegraf v1.18.0\n🏷️ server\n💻 all\n\n[ravendb]: https://ravendb.net/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Reads metrics from RavenDB servers via the Monitoring Endpoints\n[[inputs.ravendb]]\n  ## Node URL and port that RavenDB is listening on. By default,\n  ## attempts to connect securely over HTTPS, however, if the user\n  ## is running a local unsecure development cluster users can use\n  ## HTTP via a URL like \"http://localhost:8080\"\n  url = \"https://localhost:4433\"\n\n  ## RavenDB X509 client certificate setup\n  # tls_cert = \"/etc/telegraf/raven.crt\"\n  # tls_key = \"/etc/telegraf/raven.key\"\n\n  ## Optional request timeout\n  ##\n  ## Timeout, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request and\n  ## time limit for requests made by this client\n  # timeout = \"5s\"\n\n  ## List of statistics which are collected\n  # At least one is required\n  # Allowed values: server, databases, indexes, collections\n  #\n  # stats_include = [\"server\", \"databases\", \"indexes\", \"collections\"]\n\n  ## List of db where database stats are collected\n  ## If empty, all db are concerned\n  # db_stats_dbs = []\n\n  ## List of db where index status are collected\n  ## If empty, all indexes from all db are concerned\n  # index_stats_dbs = []\n\n  ## List of db where collection status are collected\n  ## If empty, all collections from all db are concerned\n  # collection_stats_dbs = []\n```\n\n> [!NOTE]\n> The client certificate should have `Operator` permissions on the cluster.\n\n## Metrics\n\n- ravendb_server\n  - tags:\n    - url\n    - node_tag\n    - cluster_id\n    - public_server_url (optional)\n  - fields:\n    - backup_current_number_of_running_backups\n    - backup_max_number_of_concurrent_backups\n    - certificate_server_certificate_expiration_left_in_sec (optional)\n    - certificate_well_known_admin_certificates (optional, separated by ';')\n    - cluster_current_term\n    - cluster_index\n    - cluster_node_state\n      - 0 -> Passive\n      - 1 -> Candidate\n      - 2 -> Follower\n      - 3 -> LeaderElect\n      - 4 -> Leader\n    - config_public_tcp_server_urls (optional, separated by ';')\n    - config_server_urls\n    - config_tcp_server_urls (optional, separated by ';')\n    - cpu_assigned_processor_count\n    - cpu_machine_usage\n    - cpu_machine_io_wait (optional)\n    - cpu_process_usage\n    - cpu_processor_count\n    - cpu_thread_pool_available_worker_threads\n    - cpu_thread_pool_available_completion_port_threads\n    - databases_loaded_count\n    - databases_total_count\n    - disk_remaining_storage_space_percentage\n    - disk_system_store_used_data_file_size_in_mb\n    - disk_system_store_total_data_file_size_in_mb\n    - disk_total_free_space_in_mb\n    - license_expiration_left_in_sec (optional)\n    - license_max_cores\n    - license_type\n    - license_utilized_cpu_cores\n    - memory_allocated_in_mb\n    - memory_installed_in_mb\n    - memory_low_memory_severity\n      - 0 -> None\n      - 1 -> Low\n      - 2 -> Extremely Low\n    - memory_physical_in_mb\n    - memory_total_dirty_in_mb\n    - memory_total_swap_size_in_mb\n    - memory_total_swap_usage_in_mb\n    - memory_working_set_swap_usage_in_mb\n    - network_concurrent_requests_count\n    - network_last_authorized_non_cluster_admin_request_time_in_sec (optional)\n    - network_last_request_time_in_sec (optional)\n    - network_requests_per_sec\n    - network_tcp_active_connections\n    - network_total_requests\n    - server_full_version\n    - server_process_id\n    - server_version\n    - uptime_in_sec\n\n- ravendb_databases\n  - tags:\n    - url\n    - database_name\n    - database_id\n    - node_tag\n    - public_server_url (optional)\n  - fields:\n    - counts_alerts\n    - counts_attachments\n    - counts_documents\n    - counts_performance_hints\n    - counts_rehabs\n    - counts_replication_factor\n    - counts_revisions\n    - counts_unique_attachments\n    - statistics_doc_puts_per_sec\n    - statistics_map_index_indexes_per_sec\n    - statistics_map_reduce_index_mapped_per_sec\n    - statistics_map_reduce_index_reduced_per_sec\n    - statistics_request_average_duration_in_ms\n    - statistics_requests_count\n    - statistics_requests_per_sec\n    - indexes_auto_count\n    - indexes_count\n    - indexes_disabled_count\n    - indexes_errors_count\n    - indexes_errored_count\n    - indexes_idle_count\n    - indexes_stale_count\n    - indexes_static_count\n    - storage_documents_allocated_data_file_in_mb\n    - storage_documents_used_data_file_in_mb\n    - storage_indexes_allocated_data_file_in_mb\n    - storage_indexes_used_data_file_in_mb\n    - storage_total_allocated_storage_file_in_mb\n    - storage_total_free_space_in_mb\n    - storage_io_read_operations (optional, Linux only)\n    - storage_io_write_operations (optional, Linux only)\n    - storage_read_throughput_in_kb (optional, Linux only)\n    - storage_write_throughput_in_kb (optional, Linux only)\n    - storage_queue_length (optional, Linux only)\n    - time_since_last_backup_in_sec (optional)\n    - uptime_in_sec\n\n- ravendb_indexes\n  - tags:\n    - database_name\n    - index_name\n    - node_tag\n    - public_server_url (optional)\n    - url\n  - fields\n    - errors\n    - is_invalid\n    - lock_mode\n      - Unlock\n      - LockedIgnore\n      - LockedError\n    - mapped_per_sec\n    - priority\n      - Low\n      - Normal\n      - High\n    - reduced_per_sec\n    - state\n      - Normal\n      - Disabled\n      - Idle\n      - Error\n    - status\n      - Running\n      - Paused\n      - Disabled\n    - time_since_last_indexing_in_sec (optional)\n    - time_since_last_query_in_sec (optional)\n    - type\n      - None\n      - AutoMap\n      - AutoMapReduce\n      - Map\n      - MapReduce\n      - Faulty\n      - JavaScriptMap\n      - JavaScriptMapReduce\n\n- ravendb_collections\n  - tags:\n    - collection_name\n    - database_name\n    - node_tag\n    - public_server_url (optional)\n    - url\n  - fields\n    - documents_count\n    - documents_size_in_bytes\n    - revisions_size_in_bytes\n    - tombstones_size_in_bytes\n    - total_size_in_bytes\n\n## Example Output\n\n```text\nravendb_server,cluster_id=07aecc42-9194-4181-999c-1c42450692c9,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 backup_current_number_of_running_backups=0i,backup_max_number_of_concurrent_backups=4i,certificate_server_certificate_expiration_left_in_sec=-1,cluster_current_term=2i,cluster_index=10i,cluster_node_state=4i,config_server_urls=\"http://127.0.0.1:8080\",cpu_assigned_processor_count=8i,cpu_machine_usage=19.09944089456869,cpu_process_usage=0.16977205323024872,cpu_processor_count=8i,cpu_thread_pool_available_completion_port_threads=1000i,cpu_thread_pool_available_worker_threads=32763i,databases_loaded_count=1i,databases_total_count=1i,disk_remaining_storage_space_percentage=18i,disk_system_store_total_data_file_size_in_mb=35184372088832i,disk_system_store_used_data_file_size_in_mb=31379031064576i,disk_total_free_space_in_mb=42931i,license_expiration_left_in_sec=24079222.8772186,license_max_cores=256i,license_type=\"Enterprise\",license_utilized_cpu_cores=8i,memory_allocated_in_mb=205i,memory_installed_in_mb=16384i,memory_low_memory_severity=0i,memory_physical_in_mb=16250i,memory_total_dirty_in_mb=0i,memory_total_swap_size_in_mb=0i,memory_total_swap_usage_in_mb=0i,memory_working_set_swap_usage_in_mb=0i,network_concurrent_requests_count=1i,network_last_request_time_in_sec=0.0058717,network_requests_per_sec=0.09916543455308825,network_tcp_active_connections=128i,network_total_requests=10i,server_full_version=\"5.2.0-custom-52\",server_process_id=31044i,server_version=\"5.2\",uptime_in_sec=56i 1613027977000000000\nravendb_databases,database_id=ced0edba-8f80-48b8-8e81-c3d2c6748ec3,database_name=db1,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 counts_alerts=0i,counts_attachments=17i,counts_documents=1059i,counts_performance_hints=0i,counts_rehabs=0i,counts_replication_factor=1i,counts_revisions=5475i,counts_unique_attachments=17i,indexes_auto_count=0i,indexes_count=7i,indexes_disabled_count=0i,indexes_errored_count=0i,indexes_errors_count=0i,indexes_idle_count=0i,indexes_stale_count=0i,indexes_static_count=7i,statistics_doc_puts_per_sec=0,statistics_map_index_indexes_per_sec=0,statistics_map_reduce_index_mapped_per_sec=0,statistics_map_reduce_index_reduced_per_sec=0,statistics_request_average_duration_in_ms=0,statistics_requests_count=0i,statistics_requests_per_sec=0,storage_documents_allocated_data_file_in_mb=140737488355328i,storage_documents_used_data_file_in_mb=74741020884992i,storage_indexes_allocated_data_file_in_mb=175921860444160i,storage_indexes_used_data_file_in_mb=120722940755968i,storage_total_allocated_storage_file_in_mb=325455441821696i,storage_total_free_space_in_mb=42931i,uptime_in_sec=54 1613027977000000000\nravendb_indexes,database_name=db1,host=DESKTOP-2OISR6D,index_name=Orders/Totals,node_tag=A,url=http://localhost:8080 errors=0i,is_invalid=false,lock_mode=\"Unlock\",mapped_per_sec=0,priority=\"Normal\",reduced_per_sec=0,state=\"Normal\",status=\"Running\",time_since_last_indexing_in_sec=45.4256655,time_since_last_query_in_sec=45.4304202,type=\"Map\" 1613027977000000000\nravendb_collections,collection_name=@hilo,database_name=db1,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 documents_count=8i,documents_size_in_bytes=122880i,revisions_size_in_bytes=0i,tombstones_size_in_bytes=122880i,total_size_in_bytes=245760i 1613027977000000000\n```\n"
  },
  {
    "path": "plugins/inputs/ravendb/ravendb.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage ravendb\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultURL     = \"http://localhost:8080\"\n\tdefaultTimeout = 5\n)\n\ntype RavenDB struct {\n\tURL  string `toml:\"url\"`\n\tName string `toml:\"name\"`\n\n\tTimeout config.Duration `toml:\"timeout\"`\n\n\tStatsInclude       []string `toml:\"stats_include\"`\n\tDBStatsDBs         []string `toml:\"db_stats_dbs\"`\n\tIndexStatsDBs      []string `toml:\"index_stats_dbs\"`\n\tCollectionStatsDBs []string `toml:\"collection_stats_dbs\"`\n\n\ttls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclient               *http.Client\n\trequestURLServer     string\n\trequestURLDatabases  string\n\trequestURLIndexes    string\n\trequestURLCollection string\n}\n\nfunc (*RavenDB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *RavenDB) Init() error {\n\tif r.URL == \"\" {\n\t\tr.URL = defaultURL\n\t}\n\n\tr.requestURLServer = r.URL + \"/admin/monitoring/v1/server\"\n\tr.requestURLDatabases = r.URL + \"/admin/monitoring/v1/databases\" + prepareDBNamesURLPart(r.DBStatsDBs)\n\tr.requestURLIndexes = r.URL + \"/admin/monitoring/v1/indexes\" + prepareDBNamesURLPart(r.IndexStatsDBs)\n\tr.requestURLCollection = r.URL + \"/admin/monitoring/v1/collections\" + prepareDBNamesURLPart(r.IndexStatsDBs)\n\n\terr := choice.CheckSlice(r.StatsInclude, []string{\"server\", \"databases\", \"indexes\", \"collections\"})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = r.ensureClient()\n\tif nil != err {\n\t\tr.Log.Errorf(\"Error with Client %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (r *RavenDB) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, statToCollect := range r.StatsInclude {\n\t\twg.Add(1)\n\n\t\tswitch statToCollect {\n\t\tcase \"server\":\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tr.gatherServer(acc)\n\t\t\t}()\n\t\tcase \"databases\":\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tr.gatherDatabases(acc)\n\t\t\t}()\n\t\tcase \"indexes\":\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tr.gatherIndexes(acc)\n\t\t\t}()\n\t\tcase \"collections\":\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tr.gatherCollections(acc)\n\t\t\t}()\n\t\t}\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (r *RavenDB) ensureClient() error {\n\tif r.client != nil {\n\t\treturn nil\n\t}\n\n\ttlsCfg, err := r.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\ttr := &http.Transport{\n\t\tResponseHeaderTimeout: time.Duration(r.Timeout),\n\t\tTLSClientConfig:       tlsCfg,\n\t}\n\tr.client = &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   time.Duration(r.Timeout),\n\t}\n\n\treturn nil\n}\n\nfunc (r *RavenDB) requestJSON(u string, target interface{}) error {\n\treq, err := http.NewRequest(\"GET\", u, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := r.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer resp.Body.Close()\n\n\tr.Log.Debugf(\"%s: %s\", u, resp.Status)\n\tif resp.StatusCode >= 400 {\n\t\treturn fmt.Errorf(\"invalid response code to request %q: %d - %s\", r.URL, resp.StatusCode, resp.Status)\n\t}\n\n\treturn json.NewDecoder(resp.Body).Decode(target)\n}\n\nfunc (r *RavenDB) gatherServer(acc telegraf.Accumulator) {\n\tserverResponse := &serverMetricsResponse{}\n\n\terr := r.requestJSON(r.requestURLServer, &serverResponse)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\ttags := map[string]string{\n\t\t\"cluster_id\": serverResponse.Cluster.ID,\n\t\t\"node_tag\":   serverResponse.Cluster.NodeTag,\n\t\t\"url\":        r.URL,\n\t}\n\n\tif serverResponse.Config.PublicServerURL != nil {\n\t\ttags[\"public_server_url\"] = *serverResponse.Config.PublicServerURL\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"backup_current_number_of_running_backups\":                      serverResponse.Backup.CurrentNumberOfRunningBackups,\n\t\t\"backup_max_number_of_concurrent_backups\":                       serverResponse.Backup.MaxNumberOfConcurrentBackups,\n\t\t\"certificate_server_certificate_expiration_left_in_sec\":         serverResponse.Certificate.ServerCertificateExpirationLeftInSec,\n\t\t\"cluster_current_term\":                                          serverResponse.Cluster.CurrentTerm,\n\t\t\"cluster_index\":                                                 serverResponse.Cluster.Index,\n\t\t\"cluster_node_state\":                                            serverResponse.Cluster.NodeState,\n\t\t\"config_server_urls\":                                            strings.Join(serverResponse.Config.ServerUrls, \";\"),\n\t\t\"cpu_assigned_processor_count\":                                  serverResponse.CPU.AssignedProcessorCount,\n\t\t\"cpu_machine_io_wait\":                                           serverResponse.CPU.MachineIoWait,\n\t\t\"cpu_machine_usage\":                                             serverResponse.CPU.MachineUsage,\n\t\t\"cpu_process_usage\":                                             serverResponse.CPU.ProcessUsage,\n\t\t\"cpu_processor_count\":                                           serverResponse.CPU.ProcessorCount,\n\t\t\"cpu_thread_pool_available_worker_threads\":                      serverResponse.CPU.ThreadPoolAvailableWorkerThreads,\n\t\t\"cpu_thread_pool_available_completion_port_threads\":             serverResponse.CPU.ThreadPoolAvailableCompletionPortThreads,\n\t\t\"databases_loaded_count\":                                        serverResponse.Databases.LoadedCount,\n\t\t\"databases_total_count\":                                         serverResponse.Databases.TotalCount,\n\t\t\"disk_remaining_storage_space_percentage\":                       serverResponse.Disk.RemainingStorageSpacePercentage,\n\t\t\"disk_system_store_used_data_file_size_in_mb\":                   serverResponse.Disk.SystemStoreUsedDataFileSizeInMb,\n\t\t\"disk_system_store_total_data_file_size_in_mb\":                  serverResponse.Disk.SystemStoreTotalDataFileSizeInMb,\n\t\t\"disk_total_free_space_in_mb\":                                   serverResponse.Disk.TotalFreeSpaceInMb,\n\t\t\"license_expiration_left_in_sec\":                                serverResponse.License.ExpirationLeftInSec,\n\t\t\"license_max_cores\":                                             serverResponse.License.MaxCores,\n\t\t\"license_type\":                                                  serverResponse.License.Type,\n\t\t\"license_utilized_cpu_cores\":                                    serverResponse.License.UtilizedCPUCores,\n\t\t\"memory_allocated_in_mb\":                                        serverResponse.Memory.AllocatedMemoryInMb,\n\t\t\"memory_installed_in_mb\":                                        serverResponse.Memory.InstalledMemoryInMb,\n\t\t\"memory_low_memory_severity\":                                    serverResponse.Memory.LowMemorySeverity,\n\t\t\"memory_physical_in_mb\":                                         serverResponse.Memory.PhysicalMemoryInMb,\n\t\t\"memory_total_dirty_in_mb\":                                      serverResponse.Memory.TotalDirtyInMb,\n\t\t\"memory_total_swap_size_in_mb\":                                  serverResponse.Memory.TotalSwapSizeInMb,\n\t\t\"memory_total_swap_usage_in_mb\":                                 serverResponse.Memory.TotalSwapUsageInMb,\n\t\t\"memory_working_set_swap_usage_in_mb\":                           serverResponse.Memory.WorkingSetSwapUsageInMb,\n\t\t\"network_concurrent_requests_count\":                             serverResponse.Network.ConcurrentRequestsCount,\n\t\t\"network_last_authorized_non_cluster_admin_request_time_in_sec\": serverResponse.Network.LastAuthorizedNonClusterAdminRequestTimeInSec,\n\t\t\"network_last_request_time_in_sec\":                              serverResponse.Network.LastRequestTimeInSec,\n\t\t\"network_requests_per_sec\":                                      serverResponse.Network.RequestsPerSec,\n\t\t\"network_tcp_active_connections\":                                serverResponse.Network.TCPActiveConnections,\n\t\t\"network_total_requests\":                                        serverResponse.Network.TotalRequests,\n\t\t\"server_full_version\":                                           serverResponse.ServerFullVersion,\n\t\t\"server_process_id\":                                             serverResponse.ServerProcessID,\n\t\t\"server_version\":                                                serverResponse.ServerVersion,\n\t\t\"uptime_in_sec\":                                                 serverResponse.UpTimeInSec,\n\t}\n\n\tif serverResponse.Config.TCPServerURLs != nil {\n\t\tfields[\"config_tcp_server_urls\"] = strings.Join(serverResponse.Config.TCPServerURLs, \";\")\n\t}\n\n\tif serverResponse.Config.PublicTCPServerURLs != nil {\n\t\tfields[\"config_public_tcp_server_urls\"] = strings.Join(serverResponse.Config.PublicTCPServerURLs, \";\")\n\t}\n\n\tif serverResponse.Certificate.WellKnownAdminCertificates != nil {\n\t\tfields[\"certificate_well_known_admin_certificates\"] = strings.Join(serverResponse.Certificate.WellKnownAdminCertificates, \";\")\n\t}\n\n\tacc.AddFields(\"ravendb_server\", fields, tags)\n}\n\nfunc (r *RavenDB) gatherDatabases(acc telegraf.Accumulator) {\n\tdatabasesResponse := &databasesMetricResponse{}\n\n\terr := r.requestJSON(r.requestURLDatabases, &databasesResponse)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, dbResponse := range databasesResponse.Results {\n\t\ttags := map[string]string{\n\t\t\t\"database_id\":   dbResponse.DatabaseID,\n\t\t\t\"database_name\": dbResponse.DatabaseName,\n\t\t\t\"node_tag\":      databasesResponse.NodeTag,\n\t\t\t\"url\":           r.URL,\n\t\t}\n\n\t\tif databasesResponse.PublicServerURL != nil {\n\t\t\ttags[\"public_server_url\"] = *databasesResponse.PublicServerURL\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"counts_alerts\":                               dbResponse.Counts.Alerts,\n\t\t\t\"counts_attachments\":                          dbResponse.Counts.Attachments,\n\t\t\t\"counts_documents\":                            dbResponse.Counts.Documents,\n\t\t\t\"counts_performance_hints\":                    dbResponse.Counts.PerformanceHints,\n\t\t\t\"counts_rehabs\":                               dbResponse.Counts.Rehabs,\n\t\t\t\"counts_replication_factor\":                   dbResponse.Counts.ReplicationFactor,\n\t\t\t\"counts_revisions\":                            dbResponse.Counts.Revisions,\n\t\t\t\"counts_unique_attachments\":                   dbResponse.Counts.UniqueAttachments,\n\t\t\t\"indexes_auto_count\":                          dbResponse.Indexes.AutoCount,\n\t\t\t\"indexes_count\":                               dbResponse.Indexes.Count,\n\t\t\t\"indexes_errored_count\":                       dbResponse.Indexes.ErroredCount,\n\t\t\t\"indexes_errors_count\":                        dbResponse.Indexes.ErrorsCount,\n\t\t\t\"indexes_disabled_count\":                      dbResponse.Indexes.DisabledCount,\n\t\t\t\"indexes_idle_count\":                          dbResponse.Indexes.IdleCount,\n\t\t\t\"indexes_stale_count\":                         dbResponse.Indexes.StaleCount,\n\t\t\t\"indexes_static_count\":                        dbResponse.Indexes.StaticCount,\n\t\t\t\"statistics_doc_puts_per_sec\":                 dbResponse.Statistics.DocPutsPerSec,\n\t\t\t\"statistics_map_index_indexes_per_sec\":        dbResponse.Statistics.MapIndexIndexesPerSec,\n\t\t\t\"statistics_map_reduce_index_mapped_per_sec\":  dbResponse.Statistics.MapReduceIndexMappedPerSec,\n\t\t\t\"statistics_map_reduce_index_reduced_per_sec\": dbResponse.Statistics.MapReduceIndexReducedPerSec,\n\t\t\t\"statistics_request_average_duration_in_ms\":   dbResponse.Statistics.RequestAverageDurationInMs,\n\t\t\t\"statistics_requests_count\":                   dbResponse.Statistics.RequestsCount,\n\t\t\t\"statistics_requests_per_sec\":                 dbResponse.Statistics.RequestsPerSec,\n\t\t\t\"storage_documents_allocated_data_file_in_mb\": dbResponse.Storage.DocumentsAllocatedDataFileInMb,\n\t\t\t\"storage_documents_used_data_file_in_mb\":      dbResponse.Storage.DocumentsUsedDataFileInMb,\n\t\t\t\"storage_indexes_allocated_data_file_in_mb\":   dbResponse.Storage.IndexesAllocatedDataFileInMb,\n\t\t\t\"storage_indexes_used_data_file_in_mb\":        dbResponse.Storage.IndexesUsedDataFileInMb,\n\t\t\t\"storage_total_allocated_storage_file_in_mb\":  dbResponse.Storage.TotalAllocatedStorageFileInMb,\n\t\t\t\"storage_total_free_space_in_mb\":              dbResponse.Storage.TotalFreeSpaceInMb,\n\t\t\t\"storage_io_read_operations\":                  dbResponse.Storage.IoReadOperations,\n\t\t\t\"storage_io_write_operations\":                 dbResponse.Storage.IoWriteOperations,\n\t\t\t\"storage_read_throughput_in_kb\":               dbResponse.Storage.ReadThroughputInKb,\n\t\t\t\"storage_write_throughput_in_kb\":              dbResponse.Storage.WriteThroughputInKb,\n\t\t\t\"storage_queue_length\":                        dbResponse.Storage.QueueLength,\n\t\t\t\"time_since_last_backup_in_sec\":               dbResponse.TimeSinceLastBackupInSec,\n\t\t\t\"uptime_in_sec\":                               dbResponse.UptimeInSec,\n\t\t}\n\n\t\tacc.AddFields(\"ravendb_databases\", fields, tags)\n\t}\n}\n\nfunc (r *RavenDB) gatherIndexes(acc telegraf.Accumulator) {\n\tindexesResponse := &indexesMetricResponse{}\n\n\terr := r.requestJSON(r.requestURLIndexes, &indexesResponse)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, perDBIndexResponse := range indexesResponse.Results {\n\t\tfor _, indexResponse := range perDBIndexResponse.Indexes {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"database_name\": perDBIndexResponse.DatabaseName,\n\t\t\t\t\"index_name\":    indexResponse.IndexName,\n\t\t\t\t\"node_tag\":      indexesResponse.NodeTag,\n\t\t\t\t\"url\":           r.URL,\n\t\t\t}\n\n\t\t\tif indexesResponse.PublicServerURL != nil {\n\t\t\t\ttags[\"public_server_url\"] = *indexesResponse.PublicServerURL\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"errors\":                          indexResponse.Errors,\n\t\t\t\t\"is_invalid\":                      indexResponse.IsInvalid,\n\t\t\t\t\"lock_mode\":                       indexResponse.LockMode,\n\t\t\t\t\"mapped_per_sec\":                  indexResponse.MappedPerSec,\n\t\t\t\t\"priority\":                        indexResponse.Priority,\n\t\t\t\t\"reduced_per_sec\":                 indexResponse.ReducedPerSec,\n\t\t\t\t\"state\":                           indexResponse.State,\n\t\t\t\t\"status\":                          indexResponse.Status,\n\t\t\t\t\"time_since_last_indexing_in_sec\": indexResponse.TimeSinceLastIndexingInSec,\n\t\t\t\t\"time_since_last_query_in_sec\":    indexResponse.TimeSinceLastQueryInSec,\n\t\t\t\t\"type\":                            indexResponse.Type,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"ravendb_indexes\", fields, tags)\n\t\t}\n\t}\n}\n\nfunc (r *RavenDB) gatherCollections(acc telegraf.Accumulator) {\n\tcollectionsResponse := &collectionsMetricResponse{}\n\n\terr := r.requestJSON(r.requestURLCollection, &collectionsResponse)\n\tif err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tfor _, perDBCollectionMetrics := range collectionsResponse.Results {\n\t\tfor _, collectionMetrics := range perDBCollectionMetrics.Collections {\n\t\t\ttags := map[string]string{\n\t\t\t\t\"collection_name\": collectionMetrics.CollectionName,\n\t\t\t\t\"database_name\":   perDBCollectionMetrics.DatabaseName,\n\t\t\t\t\"node_tag\":        collectionsResponse.NodeTag,\n\t\t\t\t\"url\":             r.URL,\n\t\t\t}\n\n\t\t\tif collectionsResponse.PublicServerURL != nil {\n\t\t\t\ttags[\"public_server_url\"] = *collectionsResponse.PublicServerURL\n\t\t\t}\n\n\t\t\tfields := map[string]interface{}{\n\t\t\t\t\"documents_count\":          collectionMetrics.DocumentsCount,\n\t\t\t\t\"documents_size_in_bytes\":  collectionMetrics.DocumentsSizeInBytes,\n\t\t\t\t\"revisions_size_in_bytes\":  collectionMetrics.RevisionsSizeInBytes,\n\t\t\t\t\"tombstones_size_in_bytes\": collectionMetrics.TombstonesSizeInBytes,\n\t\t\t\t\"total_size_in_bytes\":      collectionMetrics.TotalSizeInBytes,\n\t\t\t}\n\n\t\t\tacc.AddFields(\"ravendb_collections\", fields, tags)\n\t\t}\n\t}\n}\n\nfunc prepareDBNamesURLPart(dbNames []string) string {\n\tif len(dbNames) == 0 {\n\t\treturn \"\"\n\t}\n\tvar b strings.Builder\n\tb.WriteString(\"?\")\n\tb.WriteString(dbNames[0])\n\tfor _, db := range dbNames[1:] {\n\t\tb.WriteString(\"&name=\")\n\t\tb.WriteString(url.QueryEscape(db))\n\t}\n\n\treturn b.String()\n}\n\nfunc init() {\n\tinputs.Add(\"ravendb\", func() telegraf.Input {\n\t\treturn &RavenDB{\n\t\t\tTimeout:      config.Duration(defaultTimeout * time.Second),\n\t\t\tStatsInclude: []string{\"server\", \"databases\", \"indexes\", \"collections\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/ravendb_dto.go",
    "content": "package ravendb\n\ntype serverMetricsResponse struct {\n\tServerVersion     string               `json:\"ServerVersion\"`\n\tServerFullVersion string               `json:\"ServerFullVersion\"`\n\tUpTimeInSec       int32                `json:\"UpTimeInSec\"`\n\tServerProcessID   int32                `json:\"ServerProcessId\"`\n\tBackup            backupMetrics        `json:\"Backup\"`\n\tConfig            configurationMetrics `json:\"Config\"`\n\tCPU               cpuMetrics           `json:\"Cpu\"`\n\tMemory            memoryMetrics        `json:\"Memory\"`\n\tDisk              diskMetrics          `json:\"Disk\"`\n\tLicense           licenseMetrics       `json:\"License\"`\n\tNetwork           networkMetrics       `json:\"Network\"`\n\tCertificate       certificateMetrics   `json:\"Certificate\"`\n\tCluster           clusterMetrics       `json:\"Cluster\"`\n\tDatabases         allDatabasesMetrics  `json:\"Databases\"`\n}\n\ntype backupMetrics struct {\n\tCurrentNumberOfRunningBackups int32 `json:\"CurrentNumberOfRunningBackups\"`\n\tMaxNumberOfConcurrentBackups  int32 `json:\"MaxNumberOfConcurrentBackups\"`\n}\n\ntype configurationMetrics struct {\n\tServerUrls          []string `json:\"ServerUrls\"`\n\tPublicServerURL     *string  `json:\"PublicServerUrl\"`\n\tTCPServerURLs       []string `json:\"TcpServerUrls\"`\n\tPublicTCPServerURLs []string `json:\"PublicTcpServerUrls\"`\n}\n\ntype cpuMetrics struct {\n\tProcessUsage                             float64  `json:\"ProcessUsage\"`\n\tMachineUsage                             float64  `json:\"MachineUsage\"`\n\tMachineIoWait                            *float64 `json:\"MachineIoWait\"`\n\tProcessorCount                           int32    `json:\"ProcessorCount\"`\n\tAssignedProcessorCount                   int32    `json:\"AssignedProcessorCount\"`\n\tThreadPoolAvailableWorkerThreads         int32    `json:\"ThreadPoolAvailableWorkerThreads\"`\n\tThreadPoolAvailableCompletionPortThreads int32    `json:\"ThreadPoolAvailableCompletionPortThreads\"`\n}\n\ntype memoryMetrics struct {\n\tAllocatedMemoryInMb     int64  `json:\"AllocatedMemoryInMb\"`\n\tPhysicalMemoryInMb      int64  `json:\"PhysicalMemoryInMb\"`\n\tInstalledMemoryInMb     int64  `json:\"InstalledMemoryInMb\"`\n\tLowMemorySeverity       string `json:\"LowMemorySeverity\"`\n\tTotalSwapSizeInMb       int64  `json:\"TotalSwapSizeInMb\"`\n\tTotalSwapUsageInMb      int64  `json:\"TotalSwapUsageInMb\"`\n\tWorkingSetSwapUsageInMb int64  `json:\"WorkingSetSwapUsageInMb\"`\n\tTotalDirtyInMb          int64  `json:\"TotalDirtyInMb\"`\n}\n\ntype diskMetrics struct {\n\tSystemStoreUsedDataFileSizeInMb  int64 `json:\"SystemStoreUsedDataFileSizeInMb\"`\n\tSystemStoreTotalDataFileSizeInMb int64 `json:\"SystemStoreTotalDataFileSizeInMb\"`\n\tTotalFreeSpaceInMb               int64 `json:\"TotalFreeSpaceInMb\"`\n\tRemainingStorageSpacePercentage  int64 `json:\"RemainingStorageSpacePercentage\"`\n}\n\ntype licenseMetrics struct {\n\tType                string   `json:\"Type\"`\n\tExpirationLeftInSec *float64 `json:\"ExpirationLeftInSec\"`\n\tUtilizedCPUCores    int32    `json:\"UtilizedCpuCores\"`\n\tMaxCores            int32    `json:\"MaxCores\"`\n}\n\ntype networkMetrics struct {\n\tTCPActiveConnections                          int64    `json:\"TcpActiveConnections\"`\n\tConcurrentRequestsCount                       int64    `json:\"ConcurrentRequestsCount\"`\n\tTotalRequests                                 int64    `json:\"TotalRequests\"`\n\tRequestsPerSec                                float64  `json:\"RequestsPerSec\"`\n\tLastRequestTimeInSec                          *float64 `json:\"LastRequestTimeInSec\"`\n\tLastAuthorizedNonClusterAdminRequestTimeInSec *float64 `json:\"LastAuthorizedNonClusterAdminRequestTimeInSec\"`\n}\n\ntype certificateMetrics struct {\n\tServerCertificateExpirationLeftInSec *float64 `json:\"ServerCertificateExpirationLeftInSec\"`\n\tWellKnownAdminCertificates           []string `json:\"WellKnownAdminCertificates\"`\n}\n\ntype clusterMetrics struct {\n\tNodeTag     string `json:\"NodeTag\"`\n\tNodeState   string `json:\"NodeState\"`\n\tCurrentTerm int64  `json:\"CurrentTerm\"`\n\tIndex       int64  `json:\"Index\"`\n\tID          string `json:\"Id\"`\n}\n\ntype allDatabasesMetrics struct {\n\tTotalCount  int32 `json:\"TotalCount\"`\n\tLoadedCount int32 `json:\"LoadedCount\"`\n}\n\ntype databasesMetricResponse struct {\n\tResults         []*databaseMetrics `json:\"Results\"`\n\tPublicServerURL *string            `json:\"PublicServerUrl\"`\n\tNodeTag         string             `json:\"NodeTag\"`\n}\n\ntype databaseMetrics struct {\n\tDatabaseName             string   `json:\"DatabaseName\"`\n\tDatabaseID               string   `json:\"DatabaseId\"`\n\tUptimeInSec              float64  `json:\"UptimeInSec\"`\n\tTimeSinceLastBackupInSec *float64 `json:\"TimeSinceLastBackupInSec\"`\n\n\tCounts     databaseCounts     `json:\"Counts\"`\n\tStatistics databaseStatistics `json:\"Statistics\"`\n\n\tIndexes databaseIndexesMetrics `json:\"Indexes\"`\n\tStorage databaseStorageMetrics `json:\"Storage\"`\n}\n\ntype databaseCounts struct {\n\tDocuments         int64 `json:\"Documents\"`\n\tRevisions         int64 `json:\"Revisions\"`\n\tAttachments       int64 `json:\"Attachments\"`\n\tUniqueAttachments int64 `json:\"UniqueAttachments\"`\n\tAlerts            int64 `json:\"Alerts\"`\n\tRehabs            int32 `json:\"Rehabs\"`\n\tPerformanceHints  int64 `json:\"PerformanceHints\"`\n\tReplicationFactor int32 `json:\"ReplicationFactor\"`\n}\n\ntype databaseStatistics struct {\n\tDocPutsPerSec               float64 `json:\"DocPutsPerSec\"`\n\tMapIndexIndexesPerSec       float64 `json:\"MapIndexIndexesPerSec\"`\n\tMapReduceIndexMappedPerSec  float64 `json:\"MapReduceIndexMappedPerSec\"`\n\tMapReduceIndexReducedPerSec float64 `json:\"MapReduceIndexReducedPerSec\"`\n\tRequestsPerSec              float64 `json:\"RequestsPerSec\"`\n\tRequestsCount               int32   `json:\"RequestsCount\"`\n\tRequestAverageDurationInMs  float64 `json:\"RequestAverageDurationInMs\"`\n}\n\ntype databaseIndexesMetrics struct {\n\tCount         int64 `json:\"Count\"`\n\tStaleCount    int32 `json:\"StaleCount\"`\n\tErrorsCount   int64 `json:\"ErrorsCount\"`\n\tStaticCount   int32 `json:\"StaticCount\"`\n\tAutoCount     int32 `json:\"AutoCount\"`\n\tIdleCount     int32 `json:\"IdleCount\"`\n\tDisabledCount int32 `json:\"DisabledCount\"`\n\tErroredCount  int32 `json:\"ErroredCount\"`\n}\n\ntype databaseStorageMetrics struct {\n\tDocumentsAllocatedDataFileInMb int64    `json:\"DocumentsAllocatedDataFileInMb\"`\n\tDocumentsUsedDataFileInMb      int64    `json:\"DocumentsUsedDataFileInMb\"`\n\tIndexesAllocatedDataFileInMb   int64    `json:\"IndexesAllocatedDataFileInMb\"`\n\tIndexesUsedDataFileInMb        int64    `json:\"IndexesUsedDataFileInMb\"`\n\tTotalAllocatedStorageFileInMb  int64    `json:\"TotalAllocatedStorageFileInMb\"`\n\tTotalFreeSpaceInMb             int64    `json:\"TotalFreeSpaceInMb\"`\n\tIoReadOperations               *float64 `json:\"IoReadOperations\"`\n\tIoWriteOperations              *float64 `json:\"IoWriteOperations\"`\n\tReadThroughputInKb             *int64   `json:\"ReadThroughputInKb\"`\n\tWriteThroughputInKb            *int64   `json:\"WriteThroughputInKb\"`\n\tQueueLength                    *int64   `json:\"QueueLength\"`\n}\n\ntype indexesMetricResponse struct {\n\tResults         []*perDatabaseIndexMetrics `json:\"Results\"`\n\tPublicServerURL *string                    `json:\"PublicServerUrl\"`\n\tNodeTag         string                     `json:\"NodeTag\"`\n}\n\ntype perDatabaseIndexMetrics struct {\n\tDatabaseName string          `json:\"DatabaseName\"`\n\tIndexes      []*indexMetrics `json:\"Indexes\"`\n}\n\ntype indexMetrics struct {\n\tIndexName                  string   `json:\"IndexName\"`\n\tPriority                   string   `json:\"Priority\"`\n\tState                      string   `json:\"State\"`\n\tErrors                     int32    `json:\"Errors\"`\n\tTimeSinceLastQueryInSec    *float64 `json:\"TimeSinceLastQueryInSec\"`\n\tTimeSinceLastIndexingInSec *float64 `json:\"TimeSinceLastIndexingInSec\"`\n\tLockMode                   string   `json:\"LockMode\"`\n\tIsInvalid                  bool     `json:\"IsInvalid\"`\n\tStatus                     string   `json:\"Status\"`\n\tMappedPerSec               float64  `json:\"MappedPerSec\"`\n\tReducedPerSec              float64  `json:\"ReducedPerSec\"`\n\tType                       string   `json:\"Type\"`\n\tEntriesCount               int32    `json:\"EntriesCount\"`\n}\n\ntype collectionsMetricResponse struct {\n\tResults         []*perDatabaseCollectionMetrics `json:\"Results\"`\n\tPublicServerURL *string                         `json:\"PublicServerUrl\"`\n\tNodeTag         string                          `json:\"NodeTag\"`\n}\n\ntype perDatabaseCollectionMetrics struct {\n\tDatabaseName string               `json:\"DatabaseName\"`\n\tCollections  []*collectionMetrics `json:\"Collections\"`\n}\n\ntype collectionMetrics struct {\n\tCollectionName        string `json:\"CollectionName\"`\n\tDocumentsCount        int64  `json:\"DocumentsCount\"`\n\tTotalSizeInBytes      int64  `json:\"TotalSizeInBytes\"`\n\tDocumentsSizeInBytes  int64  `json:\"DocumentsSizeInBytes\"`\n\tTombstonesSizeInBytes int64  `json:\"TombstonesSizeInBytes\"`\n\tRevisionsSizeInBytes  int64  `json:\"RevisionsSizeInBytes\"`\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/ravendb_test.go",
    "content": "package ravendb\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\n// Test against fully filled data\nfunc TestRavenDBGeneratesMetricsFull(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/admin/monitoring/v1/databases\":\n\t\t\tjsonFilePath = \"testdata/databases_full.json\"\n\t\tcase \"/admin/monitoring/v1/server\":\n\t\t\tjsonFilePath = \"testdata/server_full.json\"\n\t\tcase \"/admin/monitoring/v1/indexes\":\n\t\t\tjsonFilePath = \"testdata/indexes_full.json\"\n\t\tcase \"/admin/monitoring/v1/collections\":\n\t\t\tjsonFilePath = \"testdata/collections_full.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request for uri %s\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &RavenDB{\n\t\tURL:          ts.URL,\n\t\tStatsInclude: []string{\"server\", \"databases\", \"indexes\", \"collections\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\trequire.NoError(t, r.Init())\n\n\tacc := &testutil.Accumulator{}\n\n\terr := acc.GatherError(r.Gather)\n\trequire.NoError(t, err)\n\n\tserverFields := map[string]interface{}{\n\t\t\"server_version\":                                                \"5.1\",\n\t\t\"server_full_version\":                                           \"5.1.1-custom-51\",\n\t\t\"uptime_in_sec\":                                                 int64(30),\n\t\t\"server_process_id\":                                             26360,\n\t\t\"config_server_urls\":                                            \"http://127.0.0.1:8080;http://192.168.0.1:8080\",\n\t\t\"config_tcp_server_urls\":                                        \"tcp://127.0.0.1:3888;tcp://192.168.0.1:3888\",\n\t\t\"config_public_tcp_server_urls\":                                 \"tcp://2.3.4.5:3888;tcp://6.7.8.9:3888\",\n\t\t\"backup_max_number_of_concurrent_backups\":                       4,\n\t\t\"backup_current_number_of_running_backups\":                      2,\n\t\t\"cpu_process_usage\":                                             6.28,\n\t\t\"cpu_machine_usage\":                                             41.05,\n\t\t\"cpu_machine_io_wait\":                                           2.55,\n\t\t\"cpu_processor_count\":                                           8,\n\t\t\"cpu_assigned_processor_count\":                                  7,\n\t\t\"cpu_thread_pool_available_worker_threads\":                      32766,\n\t\t\"cpu_thread_pool_available_completion_port_threads\":             1000,\n\t\t\"memory_allocated_in_mb\":                                        235,\n\t\t\"memory_installed_in_mb\":                                        16384,\n\t\t\"memory_physical_in_mb\":                                         16250,\n\t\t\"memory_low_memory_severity\":                                    \"None\",\n\t\t\"memory_total_swap_size_in_mb\":                                  1024,\n\t\t\"memory_total_swap_usage_in_mb\":                                 456,\n\t\t\"memory_working_set_swap_usage_in_mb\":                           89,\n\t\t\"memory_total_dirty_in_mb\":                                      1,\n\t\t\"disk_system_store_used_data_file_size_in_mb\":                   28,\n\t\t\"disk_system_store_total_data_file_size_in_mb\":                  32,\n\t\t\"disk_total_free_space_in_mb\":                                   52078,\n\t\t\"disk_remaining_storage_space_percentage\":                       22,\n\t\t\"license_type\":                                                  \"Enterprise\",\n\t\t\"license_expiration_left_in_sec\":                                25466947.5,\n\t\t\"license_utilized_cpu_cores\":                                    8,\n\t\t\"license_max_cores\":                                             256,\n\t\t\"network_tcp_active_connections\":                                84,\n\t\t\"network_concurrent_requests_count\":                             1,\n\t\t\"network_total_requests\":                                        3,\n\t\t\"network_requests_per_sec\":                                      0.03322,\n\t\t\"network_last_request_time_in_sec\":                              0.0264977,\n\t\t\"network_last_authorized_non_cluster_admin_request_time_in_sec\": 0.04,\n\t\t\"certificate_server_certificate_expiration_left_in_sec\":         float64(104),\n\t\t\"certificate_well_known_admin_certificates\":                     \"a909502dd82ae41433e6f83886b00d4277a32a7b;4444444444444444444444444444444444444444\",\n\t\t\"cluster_node_state\":                                            \"Leader\",\n\t\t\"cluster_current_term\":                                          28,\n\t\t\"cluster_index\":                                                 104,\n\t\t\"databases_total_count\":                                         25,\n\t\t\"databases_loaded_count\":                                        2,\n\t}\n\n\tserverTags := map[string]string{\n\t\t\"url\":               ts.URL,\n\t\t\"node_tag\":          \"A\",\n\t\t\"cluster_id\":        \"6b535a18-558f-4e53-a479-a514efc16aab\",\n\t\t\"public_server_url\": \"http://raven1:8080\",\n\t}\n\n\tdefaultTime := time.Unix(0, 0)\n\n\tdbFields := map[string]interface{}{\n\t\t\"uptime_in_sec\":                               float64(1396),\n\t\t\"time_since_last_backup_in_sec\":               104.3,\n\t\t\"counts_documents\":                            425189,\n\t\t\"counts_revisions\":                            429605,\n\t\t\"counts_attachments\":                          17,\n\t\t\"counts_unique_attachments\":                   16,\n\t\t\"counts_alerts\":                               2,\n\t\t\"counts_rehabs\":                               3,\n\t\t\"counts_performance_hints\":                    5,\n\t\t\"counts_replication_factor\":                   2,\n\t\t\"statistics_doc_puts_per_sec\":                 23.4,\n\t\t\"statistics_map_index_indexes_per_sec\":        82.5,\n\t\t\"statistics_map_reduce_index_mapped_per_sec\":  50.3,\n\t\t\"statistics_map_reduce_index_reduced_per_sec\": 85.2,\n\t\t\"statistics_requests_per_sec\":                 22.5,\n\t\t\"statistics_requests_count\":                   809,\n\t\t\"statistics_request_average_duration_in_ms\":   0.55,\n\t\t\"indexes_count\":                               7,\n\t\t\"indexes_stale_count\":                         1,\n\t\t\"indexes_errors_count\":                        2,\n\t\t\"indexes_static_count\":                        7,\n\t\t\"indexes_auto_count\":                          3,\n\t\t\"indexes_idle_count\":                          4,\n\t\t\"indexes_disabled_count\":                      5,\n\t\t\"indexes_errored_count\":                       6,\n\t\t\"storage_documents_allocated_data_file_in_mb\": 1024,\n\t\t\"storage_documents_used_data_file_in_mb\":      942,\n\t\t\"storage_indexes_allocated_data_file_in_mb\":   464,\n\t\t\"storage_indexes_used_data_file_in_mb\":        278,\n\t\t\"storage_total_allocated_storage_file_in_mb\":  1496,\n\t\t\"storage_total_free_space_in_mb\":              52074,\n\t\t\"storage_io_read_operations\":                  0.5,\n\t\t\"storage_io_write_operations\":                 0.7,\n\t\t\"storage_read_throughput_in_kb\":               2137,\n\t\t\"storage_write_throughput_in_kb\":              2115,\n\t\t\"storage_queue_length\":                        15,\n\t}\n\n\tdbTags := map[string]string{\n\t\t\"url\":               ts.URL,\n\t\t\"node_tag\":          \"A\",\n\t\t\"database_name\":     \"db2\",\n\t\t\"database_id\":       \"06eefe8b-d720-4a8d-a809-2c5af9a4abb5\",\n\t\t\"public_server_url\": \"http://myhost:8080\",\n\t}\n\n\tindexFields := map[string]interface{}{\n\t\t\"priority\":                        \"Normal\",\n\t\t\"state\":                           \"Normal\",\n\t\t\"errors\":                          0,\n\t\t\"time_since_last_query_in_sec\":    3.4712567,\n\t\t\"time_since_last_indexing_in_sec\": 3.4642612,\n\t\t\"lock_mode\":                       \"Unlock\",\n\t\t\"is_invalid\":                      true,\n\t\t\"status\":                          \"Running\",\n\t\t\"mapped_per_sec\":                  102.34,\n\t\t\"reduced_per_sec\":                 593.23,\n\t\t\"type\":                            \"MapReduce\",\n\t}\n\n\tindexTags := map[string]string{\n\t\t\"url\":               ts.URL,\n\t\t\"node_tag\":          \"A\",\n\t\t\"public_server_url\": \"http://localhost:8080\",\n\t\t\"database_name\":     \"db1\",\n\t\t\"index_name\":        \"Product/Rating\",\n\t}\n\n\tcollectionFields := map[string]interface{}{\n\t\t\"documents_count\":          830,\n\t\t\"total_size_in_bytes\":      2744320,\n\t\t\"documents_size_in_bytes\":  868352,\n\t\t\"tombstones_size_in_bytes\": 122880,\n\t\t\"revisions_size_in_bytes\":  1753088,\n\t}\n\n\tcollectionTags := map[string]string{\n\t\t\"url\":               ts.URL,\n\t\t\"node_tag\":          \"A\",\n\t\t\"database_name\":     \"db1\",\n\t\t\"collection_name\":   \"Orders\",\n\t\t\"public_server_url\": \"http://localhost:8080\",\n\t}\n\n\tserverExpected := testutil.MustMetric(\"ravendb_server\", serverTags, serverFields, defaultTime)\n\tdbExpected := testutil.MustMetric(\"ravendb_databases\", dbTags, dbFields, defaultTime)\n\tindexExpected := testutil.MustMetric(\"ravendb_indexes\", indexTags, indexFields, defaultTime)\n\tcollectionsExpected := testutil.MustMetric(\"ravendb_collections\", collectionTags, collectionFields, defaultTime)\n\n\tfor _, metric := range acc.GetTelegrafMetrics() {\n\t\tswitch metric.Name() {\n\t\tcase \"ravendb_server\":\n\t\t\ttestutil.RequireMetricEqual(t, serverExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_databases\":\n\t\t\ttestutil.RequireMetricEqual(t, dbExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_indexes\":\n\t\t\ttestutil.RequireMetricEqual(t, indexExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_collections\":\n\t\t\ttestutil.RequireMetricEqual(t, collectionsExpected, metric, testutil.IgnoreTime())\n\t\t}\n\t}\n}\n\n// Test against minimum filled data\nfunc TestRavenDBGeneratesMetricsMin(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar jsonFilePath string\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/admin/monitoring/v1/databases\":\n\t\t\tjsonFilePath = \"testdata/databases_min.json\"\n\t\tcase \"/admin/monitoring/v1/server\":\n\t\t\tjsonFilePath = \"testdata/server_min.json\"\n\t\tcase \"/admin/monitoring/v1/indexes\":\n\t\t\tjsonFilePath = \"testdata/indexes_min.json\"\n\t\tcase \"/admin/monitoring/v1/collections\":\n\t\t\tjsonFilePath = \"testdata/collections_min.json\"\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Cannot handle request for uri %s\", r.URL.Path)\n\t\t\treturn\n\t\t}\n\n\t\tdata, err := os.ReadFile(jsonFilePath)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Errorf(\"Could not read from data file %q: %v\", jsonFilePath, err)\n\t\t\treturn\n\t\t}\n\n\t\tif _, err = w.Write(data); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &RavenDB{\n\t\tURL:          ts.URL,\n\t\tStatsInclude: []string{\"server\", \"databases\", \"indexes\", \"collections\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\trequire.NoError(t, r.Init())\n\n\tacc := &testutil.Accumulator{}\n\n\terr := acc.GatherError(r.Gather)\n\trequire.NoError(t, err)\n\n\tserverFields := map[string]interface{}{\n\t\t\"server_version\":                                    \"5.1\",\n\t\t\"server_full_version\":                               \"5.1.1-custom-51\",\n\t\t\"uptime_in_sec\":                                     30,\n\t\t\"server_process_id\":                                 26360,\n\t\t\"config_server_urls\":                                \"http://127.0.0.1:8080\",\n\t\t\"backup_max_number_of_concurrent_backups\":           4,\n\t\t\"backup_current_number_of_running_backups\":          2,\n\t\t\"cpu_process_usage\":                                 6.28,\n\t\t\"cpu_machine_usage\":                                 41.07,\n\t\t\"cpu_processor_count\":                               8,\n\t\t\"cpu_assigned_processor_count\":                      7,\n\t\t\"cpu_thread_pool_available_worker_threads\":          32766,\n\t\t\"cpu_thread_pool_available_completion_port_threads\": 1000,\n\t\t\"memory_allocated_in_mb\":                            235,\n\t\t\"memory_installed_in_mb\":                            16384,\n\t\t\"memory_physical_in_mb\":                             16250,\n\t\t\"memory_low_memory_severity\":                        \"Low\",\n\t\t\"memory_total_swap_size_in_mb\":                      1024,\n\t\t\"memory_total_swap_usage_in_mb\":                     456,\n\t\t\"memory_working_set_swap_usage_in_mb\":               89,\n\t\t\"memory_total_dirty_in_mb\":                          1,\n\t\t\"disk_system_store_used_data_file_size_in_mb\":       28,\n\t\t\"disk_system_store_total_data_file_size_in_mb\":      32,\n\t\t\"disk_total_free_space_in_mb\":                       52078,\n\t\t\"disk_remaining_storage_space_percentage\":           22,\n\t\t\"license_type\":                                      \"Enterprise\",\n\t\t\"license_utilized_cpu_cores\":                        8,\n\t\t\"license_max_cores\":                                 256,\n\t\t\"network_tcp_active_connections\":                    84,\n\t\t\"network_concurrent_requests_count\":                 1,\n\t\t\"network_total_requests\":                            3,\n\t\t\"network_requests_per_sec\":                          0.03322,\n\t\t\"cluster_node_state\":                                \"Leader\",\n\t\t\"cluster_current_term\":                              28,\n\t\t\"cluster_index\":                                     104,\n\t\t\"databases_total_count\":                             25,\n\t\t\"databases_loaded_count\":                            2,\n\t}\n\n\tserverTags := map[string]string{\n\t\t\"url\":        ts.URL,\n\t\t\"node_tag\":   \"A\",\n\t\t\"cluster_id\": \"6b535a18-558f-4e53-a479-a514efc16aab\",\n\t}\n\n\tdbFields := map[string]interface{}{\n\t\t\"uptime_in_sec\":                               float64(1396),\n\t\t\"counts_documents\":                            425189,\n\t\t\"counts_revisions\":                            429605,\n\t\t\"counts_attachments\":                          17,\n\t\t\"counts_unique_attachments\":                   16,\n\t\t\"counts_alerts\":                               2,\n\t\t\"counts_rehabs\":                               3,\n\t\t\"counts_performance_hints\":                    5,\n\t\t\"counts_replication_factor\":                   2,\n\t\t\"statistics_doc_puts_per_sec\":                 23.4,\n\t\t\"statistics_map_index_indexes_per_sec\":        82.5,\n\t\t\"statistics_map_reduce_index_mapped_per_sec\":  50.3,\n\t\t\"statistics_map_reduce_index_reduced_per_sec\": 85.2,\n\t\t\"statistics_requests_per_sec\":                 22.5,\n\t\t\"statistics_requests_count\":                   809,\n\t\t\"statistics_request_average_duration_in_ms\":   0.55,\n\t\t\"indexes_count\":                               7,\n\t\t\"indexes_stale_count\":                         1,\n\t\t\"indexes_errors_count\":                        2,\n\t\t\"indexes_static_count\":                        7,\n\t\t\"indexes_auto_count\":                          3,\n\t\t\"indexes_idle_count\":                          4,\n\t\t\"indexes_disabled_count\":                      5,\n\t\t\"indexes_errored_count\":                       6,\n\t\t\"storage_documents_allocated_data_file_in_mb\": 1024,\n\t\t\"storage_documents_used_data_file_in_mb\":      942,\n\t\t\"storage_indexes_allocated_data_file_in_mb\":   464,\n\t\t\"storage_indexes_used_data_file_in_mb\":        278,\n\t\t\"storage_total_allocated_storage_file_in_mb\":  1496,\n\t\t\"storage_total_free_space_in_mb\":              52074,\n\t}\n\n\tdbTags := map[string]string{\n\t\t\"url\":           ts.URL,\n\t\t\"node_tag\":      \"A\",\n\t\t\"database_name\": \"db2\",\n\t\t\"database_id\":   \"06eefe8b-d720-4a8d-a809-2c5af9a4abb5\",\n\t}\n\n\tindexFields := map[string]interface{}{\n\t\t\"priority\":        \"Normal\",\n\t\t\"state\":           \"Normal\",\n\t\t\"errors\":          0,\n\t\t\"lock_mode\":       \"Unlock\",\n\t\t\"is_invalid\":      false,\n\t\t\"status\":          \"Running\",\n\t\t\"mapped_per_sec\":  102.34,\n\t\t\"reduced_per_sec\": 593.23,\n\t\t\"type\":            \"MapReduce\",\n\t}\n\n\tindexTags := map[string]string{\n\t\t\"url\":           ts.URL,\n\t\t\"node_tag\":      \"A\",\n\t\t\"database_name\": \"db1\",\n\t\t\"index_name\":    \"Product/Rating\",\n\t}\n\n\tcollectionFields := map[string]interface{}{\n\t\t\"documents_count\":          830,\n\t\t\"total_size_in_bytes\":      2744320,\n\t\t\"documents_size_in_bytes\":  868352,\n\t\t\"tombstones_size_in_bytes\": 122880,\n\t\t\"revisions_size_in_bytes\":  1753088,\n\t}\n\n\tcollectionTags := map[string]string{\n\t\t\"url\":             ts.URL,\n\t\t\"node_tag\":        \"A\",\n\t\t\"database_name\":   \"db1\",\n\t\t\"collection_name\": \"Orders\",\n\t}\n\n\tdefaultTime := time.Unix(0, 0)\n\n\tserverExpected := testutil.MustMetric(\"ravendb_server\", serverTags, serverFields, defaultTime)\n\tdbExpected := testutil.MustMetric(\"ravendb_databases\", dbTags, dbFields, defaultTime)\n\tindexExpected := testutil.MustMetric(\"ravendb_indexes\", indexTags, indexFields, defaultTime)\n\tcollectionsExpected := testutil.MustMetric(\"ravendb_collections\", collectionTags, collectionFields, defaultTime)\n\n\tfor _, metric := range acc.GetTelegrafMetrics() {\n\t\tswitch metric.Name() {\n\t\tcase \"ravendb_server\":\n\t\t\ttestutil.RequireMetricEqual(t, serverExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_databases\":\n\t\t\ttestutil.RequireMetricEqual(t, dbExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_indexes\":\n\t\t\ttestutil.RequireMetricEqual(t, indexExpected, metric, testutil.IgnoreTime())\n\t\tcase \"ravendb_collections\":\n\t\t\ttestutil.RequireMetricEqual(t, collectionsExpected, metric, testutil.IgnoreTime())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/sample.conf",
    "content": "# Reads metrics from RavenDB servers via the Monitoring Endpoints\n[[inputs.ravendb]]\n  ## Node URL and port that RavenDB is listening on. By default,\n  ## attempts to connect securely over HTTPS, however, if the user\n  ## is running a local unsecure development cluster users can use\n  ## HTTP via a URL like \"http://localhost:8080\"\n  url = \"https://localhost:4433\"\n\n  ## RavenDB X509 client certificate setup\n  # tls_cert = \"/etc/telegraf/raven.crt\"\n  # tls_key = \"/etc/telegraf/raven.key\"\n\n  ## Optional request timeout\n  ##\n  ## Timeout, specifies the amount of time to wait\n  ## for a server's response headers after fully writing the request and\n  ## time limit for requests made by this client\n  # timeout = \"5s\"\n\n  ## List of statistics which are collected\n  # At least one is required\n  # Allowed values: server, databases, indexes, collections\n  #\n  # stats_include = [\"server\", \"databases\", \"indexes\", \"collections\"]\n\n  ## List of db where database stats are collected\n  ## If empty, all db are concerned\n  # db_stats_dbs = []\n\n  ## List of db where index status are collected\n  ## If empty, all indexes from all db are concerned\n  # index_stats_dbs = []\n\n  ## List of db where collection status are collected\n  ## If empty, all collections from all db are concerned\n  # collection_stats_dbs = []\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/collections_full.json",
    "content": "{\n  \"PublicServerUrl\": \"http://localhost:8080\",\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db1\",\n      \"Collections\": [\n        {\n          \"CollectionName\": \"Orders\",\n          \"DocumentsCount\": 830,\n          \"TotalSizeInBytes\": 2744320,\n          \"DocumentsSizeInBytes\": 868352,\n          \"TombstonesSizeInBytes\": 122880,\n          \"RevisionsSizeInBytes\": 1753088\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/collections_min.json",
    "content": "{\n  \"PublicServerUrl\": null,\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db1\",\n      \"Collections\": [\n        {\n          \"CollectionName\": \"Orders\",\n          \"DocumentsCount\": 830,\n          \"TotalSizeInBytes\": 2744320,\n          \"DocumentsSizeInBytes\": 868352,\n          \"TombstonesSizeInBytes\": 122880,\n          \"RevisionsSizeInBytes\": 1753088\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/databases_full.json",
    "content": "{\n  \"PublicServerUrl\": \"http://myhost:8080\",\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db2\",\n      \"DatabaseId\": \"06eefe8b-d720-4a8d-a809-2c5af9a4abb5\",\n      \"UptimeInSec\": 1396,\n      \"TimeSinceLastBackupInSec\": 104.3,\n      \"Counts\": {\n        \"Documents\": 425189,\n        \"Revisions\": 429605,\n        \"Attachments\": 17,\n        \"UniqueAttachments\": 16,\n        \"Alerts\": 2,\n        \"Rehabs\": 3,\n        \"PerformanceHints\": 5,\n        \"ReplicationFactor\": 2\n      },\n      \"Statistics\": {\n        \"DocPutsPerSec\": 23.4,\n        \"MapIndexIndexesPerSec\": 82.5,\n        \"MapReduceIndexMappedPerSec\": 50.3,\n        \"MapReduceIndexReducedPerSec\": 85.2,\n        \"RequestsPerSec\": 22.5,\n        \"RequestsCount\": 809,\n        \"RequestAverageDurationInMs\": 0.55\n      },\n      \"Indexes\": {\n        \"Count\": 7,\n        \"StaleCount\": 1,\n        \"ErrorsCount\": 2,\n        \"StaticCount\": 7,\n        \"AutoCount\": 3,\n        \"IdleCount\": 4,\n        \"DisabledCount\": 5,\n        \"ErroredCount\": 6\n      },\n      \"Storage\": {\n        \"DocumentsAllocatedDataFileInMb\": 1024,\n        \"DocumentsUsedDataFileInMb\": 942,\n        \"IndexesAllocatedDataFileInMb\": 464,\n        \"IndexesUsedDataFileInMb\": 278,\n        \"TotalAllocatedStorageFileInMb\": 1496,\n        \"TotalFreeSpaceInMb\": 52074,\n        \"IoReadOperations\": 0.5,\n        \"IoWriteOperations\": 0.7,\n        \"ReadThroughputInKb\": 2137,\n        \"WriteThroughputInKb\": 2115,\n        \"QueueLength\": 15\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/databases_min.json",
    "content": "{\n  \"PublicServerUrl\": null,\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db2\",\n      \"DatabaseId\": \"06eefe8b-d720-4a8d-a809-2c5af9a4abb5\",\n      \"UptimeInSec\": 1396,\n      \"TimeSinceLastBackupInSec\": null,\n      \"Counts\": {\n        \"Documents\": 425189,\n        \"Revisions\": 429605,\n        \"Attachments\": 17,\n        \"UniqueAttachments\": 16,\n        \"Alerts\": 2,\n        \"Rehabs\": 3,\n        \"PerformanceHints\": 5,\n        \"ReplicationFactor\": 2\n      },\n      \"Statistics\": {\n        \"DocPutsPerSec\": 23.4,\n        \"MapIndexIndexesPerSec\": 82.5,\n        \"MapReduceIndexMappedPerSec\": 50.3,\n        \"MapReduceIndexReducedPerSec\": 85.2,\n        \"RequestsPerSec\": 22.5,\n        \"RequestsCount\": 809,\n        \"RequestAverageDurationInMs\": 0.55\n      },\n      \"Indexes\": {\n        \"Count\": 7,\n        \"StaleCount\": 1,\n        \"ErrorsCount\": 2,\n        \"StaticCount\": 7,\n        \"AutoCount\": 3,\n        \"IdleCount\": 4,\n        \"DisabledCount\": 5,\n        \"ErroredCount\": 6\n      },\n      \"Storage\": {\n        \"DocumentsAllocatedDataFileInMb\": 1024,\n        \"DocumentsUsedDataFileInMb\": 942,\n        \"IndexesAllocatedDataFileInMb\": 464,\n        \"IndexesUsedDataFileInMb\": 278,\n        \"TotalAllocatedStorageFileInMb\": 1496,\n        \"TotalFreeSpaceInMb\": 52074\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/indexes_full.json",
    "content": "{\n  \"PublicServerUrl\": \"http://localhost:8080\",\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db1\",\n      \"Indexes\": [\n        {\n          \"IndexName\": \"Product/Rating\",\n          \"Priority\": \"Normal\",\n          \"State\": \"Normal\",\n          \"Errors\": 0,\n          \"TimeSinceLastQueryInSec\": 3.4712567,\n          \"TimeSinceLastIndexingInSec\": 3.4642612,\n          \"LockMode\": \"Unlock\",\n          \"IsInvalid\": true,\n          \"Status\": \"Running\",\n          \"MappedPerSec\": 102.34,\n          \"ReducedPerSec\": 593.23,\n          \"Type\": \"MapReduce\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/indexes_min.json",
    "content": "{\n  \"PublicServerUrl\": null,\n  \"NodeTag\": \"A\",\n  \"Results\": [\n    {\n      \"DatabaseName\": \"db1\",\n      \"Indexes\": [\n        {\n          \"IndexName\": \"Product/Rating\",\n          \"Priority\": \"Normal\",\n          \"State\": \"Normal\",\n          \"Errors\": 0,\n          \"TimeSinceLastQueryInSec\": null,\n          \"TimeSinceLastIndexingInSec\": null,\n          \"LockMode\": \"Unlock\",\n          \"IsInvalid\": false,\n          \"Status\": \"Running\",\n          \"MappedPerSec\": 102.34,\n          \"ReducedPerSec\": 593.23,\n          \"Type\": \"MapReduce\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/server_full.json",
    "content": "{\n  \"ServerVersion\": \"5.1\",\n  \"ServerFullVersion\": \"5.1.1-custom-51\",\n  \"UpTimeInSec\": 30,\n  \"ServerProcessId\": 26360,\n  \"Config\": {\n    \"ServerUrls\": [\n      \"http://127.0.0.1:8080\",\n      \"http://192.168.0.1:8080\"\n    ],\n    \"PublicServerUrl\": \"http://raven1:8080\",\n    \"TcpServerUrls\": [\"tcp://127.0.0.1:3888\", \"tcp://192.168.0.1:3888\"],\n    \"PublicTcpServerUrls\": [\"tcp://2.3.4.5:3888\", \"tcp://6.7.8.9:3888\"]\n  },\n  \"Backup\": {\n    \"CurrentNumberOfRunningBackups\": 2,\n    \"MaxNumberOfConcurrentBackups\": 4\n  },\n  \"Cpu\": {\n    \"ProcessUsage\": 6.28,\n    \"MachineUsage\": 41.05,\n    \"MachineIoWait\": 2.55,\n    \"ProcessorCount\": 8,\n    \"AssignedProcessorCount\": 7,\n    \"ThreadPoolAvailableWorkerThreads\": 32766,\n    \"ThreadPoolAvailableCompletionPortThreads\": 1000\n  },\n  \"Memory\": {\n    \"AllocatedMemoryInMb\": 235,\n    \"PhysicalMemoryInMb\": 16250,\n    \"InstalledMemoryInMb\": 16384,\n    \"LowMemorySeverity\": \"None\",\n    \"TotalSwapSizeInMb\": 1024,\n    \"TotalSwapUsageInMb\": 456,\n    \"WorkingSetSwapUsageInMb\": 89,\n    \"TotalDirtyInMb\": 1\n  },\n  \"Disk\": {\n    \"SystemStoreUsedDataFileSizeInMb\": 28,\n    \"SystemStoreTotalDataFileSizeInMb\": 32,\n    \"TotalFreeSpaceInMb\": 52078,\n    \"RemainingStorageSpacePercentage\": 22\n  },\n  \"License\": {\n    \"Type\": \"Enterprise\",\n    \"ExpirationLeftInSec\": 25466947.5,\n    \"UtilizedCpuCores\": 8,\n    \"MaxCores\": 256\n  },\n  \"Network\": {\n    \"TcpActiveConnections\": 84,\n    \"ConcurrentRequestsCount\": 1,\n    \"TotalRequests\": 3,\n    \"RequestsPerSec\": 0.03322,\n    \"LastRequestTimeInSec\": 0.0264977,\n    \"LastAuthorizedNonClusterAdminRequestTimeInSec\": 0.04\n  },\n  \"Certificate\": {\n    \"ServerCertificateExpirationLeftInSec\": 104,\n    \"WellKnownAdminCertificates\": [\"a909502dd82ae41433e6f83886b00d4277a32a7b\", \"4444444444444444444444444444444444444444\"]\n  },\n  \"Cluster\": {\n    \"NodeTag\": \"A\",\n    \"NodeState\": \"Leader\",\n    \"CurrentTerm\": 28,\n    \"Index\": 104,\n    \"Id\": \"6b535a18-558f-4e53-a479-a514efc16aab\"\n  },\n  \"Databases\": {\n    \"TotalCount\": 25,\n    \"LoadedCount\": 2\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/ravendb/testdata/server_min.json",
    "content": "{\n  \"ServerVersion\": \"5.1\",\n  \"ServerFullVersion\": \"5.1.1-custom-51\",\n  \"UpTimeInSec\": 30,\n  \"ServerProcessId\": 26360,\n  \"Config\": {\n    \"ServerUrls\": [\n      \"http://127.0.0.1:8080\"\n    ],\n    \"PublicServerUrl\": null,\n    \"TcpServerUrls\": null,\n    \"PublicTcpServerUrls\": null\n  },\n  \"Backup\": {\n    \"CurrentNumberOfRunningBackups\": 2,\n    \"MaxNumberOfConcurrentBackups\": 4\n  },\n  \"Cpu\": {\n    \"ProcessUsage\": 6.28,\n    \"MachineUsage\": 41.07,\n    \"MachineIoWait\": null,\n    \"ProcessorCount\": 8,\n    \"AssignedProcessorCount\": 7,\n    \"ThreadPoolAvailableWorkerThreads\": 32766,\n    \"ThreadPoolAvailableCompletionPortThreads\": 1000\n  },\n  \"Memory\": {\n    \"AllocatedMemoryInMb\": 235,\n    \"PhysicalMemoryInMb\": 16250,\n    \"InstalledMemoryInMb\": 16384,\n    \"LowMemorySeverity\": \"Low\",\n    \"TotalSwapSizeInMb\": 1024,\n    \"TotalSwapUsageInMb\": 456,\n    \"WorkingSetSwapUsageInMb\": 89,\n    \"TotalDirtyInMb\": 1\n  },\n  \"Disk\": {\n    \"SystemStoreUsedDataFileSizeInMb\": 28,\n    \"SystemStoreTotalDataFileSizeInMb\": 32,\n    \"TotalFreeSpaceInMb\": 52078,\n    \"RemainingStorageSpacePercentage\": 22\n  },\n  \"License\": {\n    \"Type\": \"Enterprise\",\n    \"ExpirationLeftInSec\": null,\n    \"UtilizedCpuCores\": 8,\n    \"MaxCores\": 256\n  },\n  \"Network\": {\n    \"TcpActiveConnections\": 84,\n    \"ConcurrentRequestsCount\": 1,\n    \"TotalRequests\": 3,\n    \"RequestsPerSec\": 0.03322,\n    \"LastRequestTimeInSec\": null,\n    \"LastAuthorizedNonClusterAdminRequestTimeInSec\": null\n  },\n  \"Certificate\": {\n    \"ServerCertificateExpirationLeftInSec\": null,\n    \"WellKnownAdminCertificates\": null\n  },\n  \"Cluster\": {\n    \"NodeTag\": \"A\",\n    \"NodeState\": \"Leader\",\n    \"CurrentTerm\": 28,\n    \"Index\": 104,\n    \"Id\": \"6b535a18-558f-4e53-a479-a514efc16aab\"\n  },\n  \"Databases\": {\n    \"TotalCount\": 25,\n    \"LoadedCount\": 2\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/README.md",
    "content": "# Redfish Input Plugin\n\nThis plugin gathers metrics and status information of server hardware with\nenabled [DMTF's Redfish][redfish] support.\n\n⭐ Telegraf v1.15.0\n🏷️ server\n💻 all\n\n[redfish]: https://redfish.dmtf.org/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` options. See the [secret-store documentation][SECRETSTORE] for more\ndetails on how to use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read CPU, Fans, Powersupply and Voltage metrics of hardware server through redfish APIs\n[[inputs.redfish]]\n  ## Redfish API Base URL.\n  address = \"https://127.0.0.1:5000\"\n\n  ## Credentials for the Redfish API. Can also use secrets.\n  username = \"root\"\n  password = \"password123456\"\n\n  ## System Id to collect data for in Redfish APIs.\n  computer_system_id=\"System.Embedded.1\"\n\n  ## Metrics to collect\n  ## The metric collects to gather. Choose from \"power\" and \"thermal\".\n  # include_metrics = [\"power\", \"thermal\"]\n\n  ## Tag sets allow you to include redfish OData link parent data\n  ## For Example.\n  ## Thermal data is an OData link with parent Chassis which has a link of Location.\n  ## For more info see the Redfish Resource and Schema Guide at DMTFs website.\n  ## Available sets are: \"chassis.location\" and \"chassis\"\n  # include_tag_sets = [\"chassis.location\"]\n\n  ## Workarounds\n  ## Defines workarounds for certain hardware vendors. Choose from:\n  ## * ilo4-thermal - Do not pass 0Data-Version header to Thermal endpoint\n  # workarounds = []\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\n- redfish_thermal_temperatures\n  - tags:\n    - source\n    - member_id\n    - address\n    - name\n    - state\n    - health\n  - fields:\n    - reading_celsius\n    - upper_threshold_critical\n    - upper_threshold_fatal\n    - lower_threshold_critical\n    - lower_threshold_fatal\n\n- redfish_thermal_fans\n  - tags:\n    - source\n    - member_id\n    - address\n    - name\n    - state\n    - health\n  - fields:\n    - reading_rpm (or) reading_percent\n    - upper_threshold_critical\n    - upper_threshold_fatal\n    - lower_threshold_critical\n    - lower_threshold_fatal\n\n- redfish_power_powersupplies\n  - tags:\n    - source\n    - member_id\n    - address\n    - name\n    - state\n    - health\n  - fields:\n    - last_power_output_watts\n    - line_input_voltage\n    - power_capacity_watts\n    - power_input_watts\n    - power_output_watts\n\n- redfish_power_voltages (available only if voltage data is found)\n  - tags:\n    - source\n    - member_id\n    - address\n    - name\n    - state\n    - health\n  - fields:\n    - reading_volts\n    - upper_threshold_critical\n    - upper_threshold_fatal\n    - lower_threshold_critical\n    - lower_threshold_fatal\n\n### Tag Sets\n\n- chassis.location\n  - tags:\n    - datacenter (available only if location data is found)\n    - rack (available only if location data is found)\n    - room (available only if location data is found)\n    - row (available only if location data is found)\n\n- chassis\n  - tags:\n    - chassis_chassistype\n    - chassis_manufacturer\n    - chassis_model\n    - chassis_partnumber\n    - chassis_powerstate\n    - chassis_sku\n    - chassis_serialnumber\n    - chassis_state\n    - chassis_health\n\n## Example Output\n\n```text\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=0,name=CPU1\\ Temp,rack=WEB43,row=North,source=web483,state=Enabled reading_celsius=41,upper_threshold_critical=45,upper_threshold_fatal=48 1691270160000000000\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,member_id=1,name=CPU2\\ Temp,rack=WEB43,row=North,source=web483,state=Disabled upper_threshold_critical=45,upper_threshold_fatal=48 1691270160000000000\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=2,name=Chassis\\ Intake\\ Temp,rack=WEB43,row=North,source=web483,state=Enabled upper_threshold_critical=40,upper_threshold_fatal=50,lower_threshold_critical=5,lower_threshold_fatal=0,reading_celsius=25 1691270160000000000\nredfish_thermal_fans,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=0,name=BaseBoard\\ System\\ Fan,rack=WEB43,row=North,source=web483,state=Enabled lower_threshold_fatal=0i,reading_rpm=2100i 1691270160000000000\nredfish_thermal_fans,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=1,name=BaseBoard\\ System\\ Fan\\ Backup,rack=WEB43,row=North,source=web483,state=Enabled lower_threshold_fatal=0i,reading_rpm=2050i 1691270160000000000\nredfish_power_powersupplies,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=Warning,member_id=0,name=Power\\ Supply\\ Bay,rack=WEB43,row=North,source=web483,state=Enabled line_input_voltage=120,last_power_output_watts=325,power_capacity_watts=800 1691270160000000000\nredfish_power_voltages,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=0,name=VRM1\\ Voltage,rack=WEB43,row=North,source=web483,state=Enabled upper_threshold_fatal=15,lower_threshold_critical=11,lower_threshold_fatal=10,reading_volts=12,upper_threshold_critical=13 1691270160000000000\nredfish_power_voltages,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=1,name=VRM2\\ Voltage,rack=WEB43,row=North,source=web483,state=Enabled reading_volts=5,upper_threshold_critical=7,lower_threshold_critical=4.5 1691270160000000000\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=0,name=CPU1\\ Temp,rack=WEB43,row=North,source=web483,state=Enabled upper_threshold_critical=45,upper_threshold_fatal=48,reading_celsius=41 1691270170000000000\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,member_id=1,name=CPU2\\ Temp,rack=WEB43,row=North,source=web483,state=Disabled upper_threshold_critical=45,upper_threshold_fatal=48 1691270170000000000\nredfish_thermal_temperatures,address=127.0.0.1,chassis_chassistype=RackMount,chassis_health=OK,chassis_manufacturer=Contoso,chassis_model=3500RX,chassis_partnumber=224071-J23,chassis_powerstate=On,chassis_serialnumber=437XR1138R2,chassis_sku=8675309,chassis_state=Enabled,health=OK,member_id=2,name=Chassis\\ Intake\\ Temp,rack=WEB43,row=North,source=web483,state=Enabled lower_threshold_critical=5,lower_threshold_fatal=0,reading_celsius=25,upper_threshold_critical=40,upper_threshold_fatal=50 1691270170000000000\n```\n"
  },
  {
    "path": "plugins/inputs/redfish/redfish.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage redfish\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\t// tag sets used for including redfish OData link parent data\n\ttagSetChassisLocation = \"chassis.location\"\n\ttagSetChassis         = \"chassis\"\n)\n\ntype Redfish struct {\n\tAddress          string          `toml:\"address\"`\n\tUsername         config.Secret   `toml:\"username\"`\n\tPassword         config.Secret   `toml:\"password\"`\n\tComputerSystemID string          `toml:\"computer_system_id\"`\n\tIncludeMetrics   []string        `toml:\"include_metrics\"`\n\tIncludeTagSets   []string        `toml:\"include_tag_sets\"`\n\tWorkarounds      []string        `toml:\"workarounds\"`\n\tTimeout          config.Duration `toml:\"timeout\"`\n\n\ttagSet map[string]bool\n\tclient http.Client\n\ttls.ClientConfig\n\tbaseURL *url.URL\n}\n\ntype system struct {\n\tHostname string `json:\"hostname\"`\n\tLinks    struct {\n\t\tChassis []struct {\n\t\t\tRef string `json:\"@odata.id\"`\n\t\t}\n\t}\n}\n\ntype chassis struct {\n\tChassisType  string\n\tLocation     *location\n\tManufacturer string\n\tModel        string\n\tPartNumber   string\n\tPower        struct {\n\t\tRef string `json:\"@odata.id\"`\n\t}\n\tPowerState   string\n\tSKU          string\n\tSerialNumber string\n\tStatus       status\n\tThermal      struct {\n\t\tRef string `json:\"@odata.id\"`\n\t}\n}\n\ntype power struct {\n\tPowerControl []struct {\n\t\tName                string\n\t\tMemberID            string\n\t\tPowerAllocatedWatts *float64\n\t\tPowerAvailableWatts *float64\n\t\tPowerCapacityWatts  *float64\n\t\tPowerConsumedWatts  *float64\n\t\tPowerRequestedWatts *float64\n\t\tPowerMetrics        struct {\n\t\t\tAverageConsumedWatts *float64\n\t\t\tIntervalInMin        int\n\t\t\tMaxConsumedWatts     *float64\n\t\t\tMinConsumedWatts     *float64\n\t\t}\n\t}\n\tPowerSupplies []struct {\n\t\tName                 string\n\t\tMemberID             string\n\t\tPowerInputWatts      *float64\n\t\tPowerCapacityWatts   *float64\n\t\tPowerOutputWatts     *float64\n\t\tLastPowerOutputWatts *float64\n\t\tStatus               status\n\t\tLineInputVoltage     *float64\n\t}\n\tVoltages []struct {\n\t\tName                   string\n\t\tMemberID               string\n\t\tReadingVolts           *float64\n\t\tUpperThresholdCritical *float64\n\t\tUpperThresholdFatal    *float64\n\t\tLowerThresholdCritical *float64\n\t\tLowerThresholdFatal    *float64\n\t\tStatus                 status\n\t}\n}\n\ntype thermal struct {\n\tFans []struct {\n\t\tName                   string\n\t\tMemberID               string\n\t\tFanName                string\n\t\tCurrentReading         *int64\n\t\tReading                *int64\n\t\tReadingUnits           *string\n\t\tUpperThresholdCritical *int64\n\t\tUpperThresholdFatal    *int64\n\t\tLowerThresholdCritical *int64\n\t\tLowerThresholdFatal    *int64\n\t\tStatus                 status\n\t}\n\tTemperatures []struct {\n\t\tName                   string\n\t\tMemberID               string\n\t\tReadingCelsius         *float64\n\t\tUpperThresholdCritical *float64\n\t\tUpperThresholdFatal    *float64\n\t\tLowerThresholdCritical *float64\n\t\tLowerThresholdFatal    *float64\n\t\tStatus                 status\n\t}\n}\n\ntype location struct {\n\tPostalAddress struct {\n\t\tDataCenter string\n\t\tRoom       string\n\t}\n\tPlacement struct {\n\t\tRack string\n\t\tRow  string\n\t}\n}\n\ntype status struct {\n\tState  string\n\tHealth string\n}\n\nfunc (*Redfish) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Redfish) Init() error {\n\tif r.Address == \"\" {\n\t\treturn errors.New(\"did not provide IP\")\n\t}\n\n\tif r.Username.Empty() && r.Password.Empty() {\n\t\treturn errors.New(\"did not provide username and password\")\n\t}\n\n\tif r.ComputerSystemID == \"\" {\n\t\treturn errors.New(\"did not provide the computer system ID of the resource\")\n\t}\n\n\tif len(r.IncludeMetrics) == 0 {\n\t\treturn errors.New(\"no metrics specified to collect\")\n\t}\n\tfor _, metric := range r.IncludeMetrics {\n\t\tswitch metric {\n\t\tcase \"thermal\", \"power\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown metric requested: %s\", metric)\n\t\t}\n\t}\n\n\tfor _, workaround := range r.Workarounds {\n\t\tswitch workaround {\n\t\tcase \"ilo4-thermal\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown workaround requested: %s\", workaround)\n\t\t}\n\t}\n\tr.tagSet = make(map[string]bool, len(r.IncludeTagSets))\n\tfor _, setLabel := range r.IncludeTagSets {\n\t\tr.tagSet[setLabel] = true\n\t}\n\n\tvar err error\n\tr.baseURL, err = url.Parse(r.Address)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttlsCfg, err := r.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.client = http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t\tProxy:           http.ProxyFromEnvironment,\n\t\t},\n\t\tTimeout: time.Duration(r.Timeout),\n\t}\n\n\treturn nil\n}\n\nfunc (r *Redfish) Gather(acc telegraf.Accumulator) error {\n\taddress, _, err := net.SplitHostPort(r.baseURL.Host)\n\tif err != nil {\n\t\taddress = r.baseURL.Host\n\t}\n\n\tsystem, err := r.getComputerSystem(r.ComputerSystemID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, link := range system.Links.Chassis {\n\t\tchassis, err := r.getChassis(link.Ref)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, metric := range r.IncludeMetrics {\n\t\t\tvar err error\n\t\t\tswitch metric {\n\t\t\tcase \"thermal\":\n\t\t\t\terr = r.gatherThermal(acc, address, system, chassis)\n\t\t\tcase \"power\":\n\t\t\t\terr = r.gatherPower(acc, address, system, chassis)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown metric requested: %s\", metric)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *Redfish) getData(address string, payload interface{}) error {\n\treq, err := http.NewRequest(\"GET\", address, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tusername, err := r.Username.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t}\n\tuser := username.String()\n\tusername.Destroy()\n\n\tpassword, err := r.Password.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t}\n\tpass := password.String()\n\tpassword.Destroy()\n\n\treq.SetBasicAuth(user, pass)\n\treq.Header.Set(\"Accept\", \"application/json\")\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"OData-Version\", \"4.0\")\n\n\t// workaround for iLO4 thermal data\n\tif slices.Contains(r.Workarounds, \"ilo4-thermal\") && strings.Contains(address, \"/Thermal\") {\n\t\treq.Header.Del(\"OData-Version\")\n\t}\n\n\tresp, err := r.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"received status code %d (%s) for address %s, expected 200\",\n\t\t\tresp.StatusCode,\n\t\t\thttp.StatusText(resp.StatusCode),\n\t\t\taddress)\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(body, &payload)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing input: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *Redfish) getComputerSystem(id string) (*system, error) {\n\tloc := r.baseURL.ResolveReference(&url.URL{Path: path.Join(\"/redfish/v1/Systems/\", id)})\n\tsystem := &system{}\n\terr := r.getData(loc.String(), system)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn system, nil\n}\n\nfunc (r *Redfish) getChassis(ref string) (*chassis, error) {\n\tloc := r.baseURL.ResolveReference(&url.URL{Path: ref})\n\tchassis := &chassis{}\n\terr := r.getData(loc.String(), chassis)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn chassis, nil\n}\n\nfunc (r *Redfish) getPower(ref string) (*power, error) {\n\tloc := r.baseURL.ResolveReference(&url.URL{Path: ref})\n\tpower := &power{}\n\terr := r.getData(loc.String(), power)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn power, nil\n}\n\nfunc (r *Redfish) getThermal(ref string) (*thermal, error) {\n\tloc := r.baseURL.ResolveReference(&url.URL{Path: ref})\n\tthermal := &thermal{}\n\terr := r.getData(loc.String(), thermal)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn thermal, nil\n}\n\nfunc setChassisTags(chassis *chassis, tags map[string]string) {\n\ttags[\"chassis_chassistype\"] = chassis.ChassisType\n\ttags[\"chassis_manufacturer\"] = chassis.Manufacturer\n\ttags[\"chassis_model\"] = chassis.Model\n\ttags[\"chassis_partnumber\"] = chassis.PartNumber\n\ttags[\"chassis_powerstate\"] = chassis.PowerState\n\ttags[\"chassis_sku\"] = chassis.SKU\n\ttags[\"chassis_serialnumber\"] = chassis.SerialNumber\n\ttags[\"chassis_state\"] = chassis.Status.State\n\ttags[\"chassis_health\"] = chassis.Status.Health\n}\n\nfunc (r *Redfish) gatherThermal(acc telegraf.Accumulator, address string, system *system, chassis *chassis) error {\n\tthermal, err := r.getThermal(chassis.Thermal.Ref)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, j := range thermal.Temperatures {\n\t\ttags := make(map[string]string, 19)\n\t\ttags[\"member_id\"] = j.MemberID\n\t\ttags[\"address\"] = address\n\t\ttags[\"name\"] = j.Name\n\t\ttags[\"source\"] = system.Hostname\n\t\ttags[\"state\"] = j.Status.State\n\t\ttags[\"health\"] = j.Status.Health\n\t\tif _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {\n\t\t\ttags[\"datacenter\"] = chassis.Location.PostalAddress.DataCenter\n\t\t\ttags[\"room\"] = chassis.Location.PostalAddress.Room\n\t\t\ttags[\"rack\"] = chassis.Location.Placement.Rack\n\t\t\ttags[\"row\"] = chassis.Location.Placement.Row\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassis]; ok {\n\t\t\tsetChassisTags(chassis, tags)\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"reading_celsius\"] = j.ReadingCelsius\n\t\tfields[\"upper_threshold_critical\"] = j.UpperThresholdCritical\n\t\tfields[\"upper_threshold_fatal\"] = j.UpperThresholdFatal\n\t\tfields[\"lower_threshold_critical\"] = j.LowerThresholdCritical\n\t\tfields[\"lower_threshold_fatal\"] = j.LowerThresholdFatal\n\t\tacc.AddFields(\"redfish_thermal_temperatures\", fields, tags)\n\t}\n\n\tfor _, j := range thermal.Fans {\n\t\ttags := make(map[string]string, 20)\n\t\tfields := make(map[string]interface{}, 5)\n\t\ttags[\"member_id\"] = j.MemberID\n\t\ttags[\"address\"] = address\n\t\ttags[\"name\"] = j.Name\n\t\tif j.FanName != \"\" {\n\t\t\ttags[\"name\"] = j.FanName\n\t\t}\n\t\ttags[\"source\"] = system.Hostname\n\t\ttags[\"state\"] = j.Status.State\n\t\ttags[\"health\"] = j.Status.Health\n\t\tif _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {\n\t\t\ttags[\"datacenter\"] = chassis.Location.PostalAddress.DataCenter\n\t\t\ttags[\"room\"] = chassis.Location.PostalAddress.Room\n\t\t\ttags[\"rack\"] = chassis.Location.Placement.Rack\n\t\t\ttags[\"row\"] = chassis.Location.Placement.Row\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassis]; ok {\n\t\t\tsetChassisTags(chassis, tags)\n\t\t}\n\n\t\tif j.ReadingUnits != nil && *j.ReadingUnits == \"RPM\" {\n\t\t\tfields[\"upper_threshold_critical\"] = j.UpperThresholdCritical\n\t\t\tfields[\"upper_threshold_fatal\"] = j.UpperThresholdFatal\n\t\t\tfields[\"lower_threshold_critical\"] = j.LowerThresholdCritical\n\t\t\tfields[\"lower_threshold_fatal\"] = j.LowerThresholdFatal\n\t\t\tfields[\"reading_rpm\"] = j.Reading\n\t\t} else if j.CurrentReading != nil {\n\t\t\tfields[\"reading_percent\"] = j.CurrentReading\n\t\t} else {\n\t\t\tfields[\"reading_percent\"] = j.Reading\n\t\t}\n\t\tacc.AddFields(\"redfish_thermal_fans\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc (r *Redfish) gatherPower(acc telegraf.Accumulator, address string, system *system, chassis *chassis) error {\n\tpower, err := r.getPower(chassis.Power.Ref)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, j := range power.PowerControl {\n\t\ttags := map[string]string{\n\t\t\t\"member_id\": j.MemberID,\n\t\t\t\"address\":   address,\n\t\t\t\"name\":      j.Name,\n\t\t\t\"source\":    system.Hostname,\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {\n\t\t\ttags[\"datacenter\"] = chassis.Location.PostalAddress.DataCenter\n\t\t\ttags[\"room\"] = chassis.Location.PostalAddress.Room\n\t\t\ttags[\"rack\"] = chassis.Location.Placement.Rack\n\t\t\ttags[\"row\"] = chassis.Location.Placement.Row\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassis]; ok {\n\t\t\tsetChassisTags(chassis, tags)\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"power_allocated_watts\":  j.PowerAllocatedWatts,\n\t\t\t\"power_available_watts\":  j.PowerAvailableWatts,\n\t\t\t\"power_capacity_watts\":   j.PowerCapacityWatts,\n\t\t\t\"power_consumed_watts\":   j.PowerConsumedWatts,\n\t\t\t\"power_requested_watts\":  j.PowerRequestedWatts,\n\t\t\t\"average_consumed_watts\": j.PowerMetrics.AverageConsumedWatts,\n\t\t\t\"interval_in_min\":        j.PowerMetrics.IntervalInMin,\n\t\t\t\"max_consumed_watts\":     j.PowerMetrics.MaxConsumedWatts,\n\t\t\t\"min_consumed_watts\":     j.PowerMetrics.MinConsumedWatts,\n\t\t}\n\n\t\tacc.AddFields(\"redfish_power_powercontrol\", fields, tags)\n\t}\n\n\tfor _, j := range power.PowerSupplies {\n\t\ttags := make(map[string]string, 19)\n\t\ttags[\"member_id\"] = j.MemberID\n\t\ttags[\"address\"] = address\n\t\ttags[\"name\"] = j.Name\n\t\ttags[\"source\"] = system.Hostname\n\t\ttags[\"state\"] = j.Status.State\n\t\ttags[\"health\"] = j.Status.Health\n\t\tif _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {\n\t\t\ttags[\"datacenter\"] = chassis.Location.PostalAddress.DataCenter\n\t\t\ttags[\"room\"] = chassis.Location.PostalAddress.Room\n\t\t\ttags[\"rack\"] = chassis.Location.Placement.Rack\n\t\t\ttags[\"row\"] = chassis.Location.Placement.Row\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassis]; ok {\n\t\t\tsetChassisTags(chassis, tags)\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"power_input_watts\"] = j.PowerInputWatts\n\t\tfields[\"power_output_watts\"] = j.PowerOutputWatts\n\t\tfields[\"line_input_voltage\"] = j.LineInputVoltage\n\t\tfields[\"last_power_output_watts\"] = j.LastPowerOutputWatts\n\t\tfields[\"power_capacity_watts\"] = j.PowerCapacityWatts\n\t\tacc.AddFields(\"redfish_power_powersupplies\", fields, tags)\n\t}\n\n\tfor _, j := range power.Voltages {\n\t\ttags := make(map[string]string, 19)\n\t\ttags[\"member_id\"] = j.MemberID\n\t\ttags[\"address\"] = address\n\t\ttags[\"name\"] = j.Name\n\t\ttags[\"source\"] = system.Hostname\n\t\ttags[\"state\"] = j.Status.State\n\t\ttags[\"health\"] = j.Status.Health\n\t\tif _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {\n\t\t\ttags[\"datacenter\"] = chassis.Location.PostalAddress.DataCenter\n\t\t\ttags[\"room\"] = chassis.Location.PostalAddress.Room\n\t\t\ttags[\"rack\"] = chassis.Location.Placement.Rack\n\t\t\ttags[\"row\"] = chassis.Location.Placement.Row\n\t\t}\n\t\tif _, ok := r.tagSet[tagSetChassis]; ok {\n\t\t\tsetChassisTags(chassis, tags)\n\t\t}\n\n\t\tfields := make(map[string]interface{})\n\t\tfields[\"reading_volts\"] = j.ReadingVolts\n\t\tfields[\"upper_threshold_critical\"] = j.UpperThresholdCritical\n\t\tfields[\"upper_threshold_fatal\"] = j.UpperThresholdFatal\n\t\tfields[\"lower_threshold_critical\"] = j.LowerThresholdCritical\n\t\tfields[\"lower_threshold_fatal\"] = j.LowerThresholdFatal\n\t\tacc.AddFields(\"redfish_power_voltages\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"redfish\", func() telegraf.Input {\n\t\treturn &Redfish{\n\t\t\t// default tag set of chassis.location required for backwards compatibility\n\t\t\tIncludeTagSets: []string{tagSetChassisLocation},\n\t\t\tIncludeMetrics: []string{\"power\", \"thermal\"},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/redfish_test.go",
    "content": "package redfish\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestDellApis(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_thermal.json\")\n\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Power\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_power.json\")\n\t\tcase \"/redfish/v1/Chassis/System.Embedded.1\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_chassis.json\")\n\t\tcase \"/redfish/v1/Systems/System.Embedded.1\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_systems.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\taddress, _, err := net.SplitHostPort(u.Host)\n\trequire.NoError(t, err)\n\n\texpectedMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":      \"CPU1 Temp\",\n\t\t\t\t\"member_id\": \"iDRAC.Embedded.1#CPU1Temp\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 3.0,\n\t\t\t\t\"lower_threshold_fatal\":    3.0,\n\t\t\t\t\"reading_celsius\":          40.0,\n\t\t\t\t\"upper_threshold_critical\": 93.0,\n\t\t\t\t\"upper_threshold_fatal\":    93.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan1A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.1A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_rpm\":              17760,\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan1B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.1B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15360,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan2A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.2A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              17880,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan2B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.2B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15120,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan3A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.3A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              18000,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan3B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.3B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15600,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan4A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.4A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              17280,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan4B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.4B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15360,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan5A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.5A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              17640,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan5B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.5B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15600,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan6A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.6A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              17760,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan6B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.6B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15600,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan7A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.7A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              17400,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan7B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.7B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15720,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan8A\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.8A\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              18000,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board Fan8B\",\n\t\t\t\t\"member_id\": \"0x17||Fan.Embedded.8B\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"lower_threshold_critical\": 600,\n\t\t\t\t\"lower_threshold_fatal\":    600,\n\t\t\t\t\"reading_rpm\":              15840,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powercontrol\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Power Control\",\n\t\t\t\t\"member_id\": \"PowerControl\",\n\t\t\t\t\"address\":   address,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"average_consumed_watts\": 426.0,\n\t\t\t\t\"interval_in_min\":        int64(1),\n\t\t\t\t\"max_consumed_watts\":     436.0,\n\t\t\t\t\"min_consumed_watts\":     425.0,\n\t\t\t\t\"power_allocated_watts\":  1628.0,\n\t\t\t\t\"power_available_watts\":  0.0,\n\t\t\t\t\"power_capacity_watts\":   1628.0,\n\t\t\t\t\"power_consumed_watts\":   429.0,\n\t\t\t\t\"power_requested_watts\":  704.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powersupplies\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"PS1 Status\",\n\t\t\t\t\"member_id\": \"PSU.Slot.1\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_capacity_watts\": 750.00,\n\t\t\t\t\"power_input_watts\":    900.0,\n\t\t\t\t\"power_output_watts\":   203.0,\n\t\t\t\t\"line_input_voltage\":   206.00,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_voltages\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board DIMM PG\",\n\t\t\t\t\"member_id\": \"iDRAC.Embedded.1#SystemBoardDIMMPG\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_volts\": 1.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_voltages\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board NDC PG\",\n\t\t\t\t\"member_id\": \"iDRAC.Embedded.1#SystemBoardNDCPG\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_volts\": 1.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_voltages\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"System Board PS1 PG FAIL\",\n\t\t\t\t\"member_id\": \"iDRAC.Embedded.1#SystemBoardPS1PGFAIL\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_volts\": 1.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\tplugin := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\tComputerSystemID: \"System.Embedded.1\",\n\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t}\n\trequire.NoError(t, plugin.Init())\n\tvar acc testutil.Accumulator\n\n\terr = plugin.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.True(t, acc.HasMeasurement(\"redfish_thermal_temperatures\"))\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, acc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime())\n}\n\nfunc TestHPApis(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_thermal.json\")\n\t\tcase \"/redfish/v1/Chassis/1/Power\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_power.json\")\n\t\tcase \"/redfish/v1/Systems/1\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_systems.json\")\n\t\tcase \"/redfish/v1/Chassis/1/\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_chassis.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\taddress, _, err := net.SplitHostPort(u.Host)\n\trequire.NoError(t, err)\n\n\texpectedMetricsHp := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":      \"01-Inlet Ambient\",\n\t\t\t\t\"member_id\": \"0\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          19.0,\n\t\t\t\t\"upper_threshold_critical\": 42.0,\n\t\t\t\t\"upper_threshold_fatal\":    47.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":      \"44-P/S 2 Zone\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"member_id\": \"42\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          34.0,\n\t\t\t\t\"upper_threshold_critical\": 75.0,\n\t\t\t\t\"upper_threshold_fatal\":    80.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"Fan 1\",\n\t\t\t\t\"member_id\": \"0\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"Fan 2\",\n\t\t\t\t\"member_id\": \"1\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"Fan 3\",\n\t\t\t\t\"member_id\": \"2\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powercontrol\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"\",\n\t\t\t\t\"member_id\": \"0\",\n\t\t\t\t\"address\":   address,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"average_consumed_watts\": 221.0,\n\t\t\t\t\"interval_in_min\":        int64(20),\n\t\t\t\t\"max_consumed_watts\":     252.0,\n\t\t\t\t\"min_consumed_watts\":     220.0,\n\t\t\t\t\"power_capacity_watts\":   1600.0,\n\t\t\t\t\"power_consumed_watts\":   221.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powersupplies\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"HpeServerPowerSupply\",\n\t\t\t\t\"member_id\": \"0\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_capacity_watts\":    800.0,\n\t\t\t\t\"line_input_voltage\":      205.0,\n\t\t\t\t\"last_power_output_watts\": 0.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powersupplies\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"name\":      \"HpeServerPowerSupply\",\n\t\t\t\t\"member_id\": \"1\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_capacity_watts\":    800.0,\n\t\t\t\t\"line_input_voltage\":      205.0,\n\t\t\t\t\"last_power_output_watts\": 90.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\thpPlugin := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\tComputerSystemID: \"1\",\n\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t}\n\trequire.NoError(t, hpPlugin.Init())\n\tvar hpAcc testutil.Accumulator\n\n\terr = hpPlugin.Gather(&hpAcc)\n\trequire.NoError(t, err)\n\trequire.True(t, hpAcc.HasMeasurement(\"redfish_thermal_temperatures\"))\n\ttestutil.RequireMetricsEqual(t, expectedMetricsHp, hpAcc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime())\n}\n\nfunc TestHPilo4Apis(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_thermal_ilo4.json\")\n\t\tcase \"/redfish/v1/Chassis/1/Power\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_power.json\")\n\t\tcase \"/redfish/v1/Systems/1\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_systems.json\")\n\t\tcase \"/redfish/v1/Chassis/1/\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_chassis.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\taddress, _, err := net.SplitHostPort(u.Host)\n\trequire.NoError(t, err)\n\n\texpectedMetricsHp := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":      \"01-Inlet Ambient\",\n\t\t\t\t\"member_id\": \"0\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          19.0,\n\t\t\t\t\"upper_threshold_critical\": 42.0,\n\t\t\t\t\"upper_threshold_fatal\":    47.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":      \"44-P/S 2 Zone\",\n\t\t\t\t\"member_id\": \"42\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          34.0,\n\t\t\t\t\"upper_threshold_critical\": 75.0,\n\t\t\t\t\"upper_threshold_fatal\":    80.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"address\":   address,\n\t\t\t\t\"health\":    \"OK\",\n\t\t\t\t\"member_id\": \"\",\n\t\t\t\t\"name\":      \"Fan 1\",\n\t\t\t\t\"source\":    \"tpa-hostname\",\n\t\t\t\t\"state\":     \"Enabled\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 17,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\thpPlugin := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\tComputerSystemID: \"1\",\n\t\tIncludeMetrics:   []string{\"thermal\"},\n\t}\n\trequire.NoError(t, hpPlugin.Init())\n\tvar hpAcc testutil.Accumulator\n\n\terr = hpPlugin.Gather(&hpAcc)\n\trequire.NoError(t, err)\n\trequire.True(t, hpAcc.HasMeasurement(\"redfish_thermal_temperatures\"))\n\ttestutil.RequireMetricsEqual(t, expectedMetricsHp, hpAcc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime())\n}\n\nfunc checkAuth(r *http.Request, username, password string) bool {\n\tuser, pass, ok := r.BasicAuth()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn user == username && pass == password\n}\n\nfunc TestInvalidUsernameorPassword(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"testing\", \"testing\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_thermal.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\tComputerSystemID: \"System.Embedded.1\",\n\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, r.Init())\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\terr = r.Gather(&acc)\n\trequire.EqualError(t, err, \"received status code 401 (Unauthorized) for address http://\"+u.Host+\"/redfish/v1/Systems/System.Embedded.1, expected 200\")\n}\nfunc TestNoUsernameorPasswordConfiguration(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"testing\", \"testing\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/dell_thermal.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tdefer ts.Close()\n\n\tr := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tComputerSystemID: \"System.Embedded.1\",\n\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t}\n\n\terr := r.Init()\n\trequire.Error(t, err)\n\trequire.EqualError(t, err, \"did not provide username and password\")\n}\n\nfunc TestInvalidDellJSON(t *testing.T) {\n\ttests := []struct {\n\t\tname             string\n\t\tthermalfilename  string\n\t\tpowerfilename    string\n\t\tchassisfilename  string\n\t\thostnamefilename string\n\t}{\n\t\t{\n\t\t\tname:             \"check Thermal\",\n\t\t\tthermalfilename:  \"testdata/dell_thermalinvalid.json\",\n\t\t\tpowerfilename:    \"testdata/dell_power.json\",\n\t\t\tchassisfilename:  \"testdata/dell_chassis.json\",\n\t\t\thostnamefilename: \"testdata/dell_systems.json\",\n\t\t},\n\t\t{\n\t\t\tname:             \"check Power\",\n\t\t\tthermalfilename:  \"testdata/dell_thermal.json\",\n\t\t\tpowerfilename:    \"testdata/dell_powerinvalid.json\",\n\t\t\tchassisfilename:  \"testdata/dell_chassis.json\",\n\t\t\thostnamefilename: \"testdata/dell_systems.json\",\n\t\t},\n\t\t{\n\t\t\tname:             \"check Location\",\n\t\t\tthermalfilename:  \"testdata/dell_thermal.json\",\n\t\t\tpowerfilename:    \"testdata/dell_power.json\",\n\t\t\tchassisfilename:  \"testdata/dell_chassisinvalid.json\",\n\t\t\thostnamefilename: \"testdata/dell_systems.json\",\n\t\t},\n\t\t{\n\t\t\tname:             \"check Hostname\",\n\t\t\tthermalfilename:  \"testdata/dell_thermal.json\",\n\t\t\tpowerfilename:    \"testdata/dell_power.json\",\n\t\t\tchassisfilename:  \"testdata/dell_chassis.json\",\n\t\t\thostnamefilename: \"testdata/dell_systemsinvalid.json\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Thermal\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.thermalfilename)\n\t\t\t\tcase \"/redfish/v1/Chassis/System.Embedded.1/Power\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.powerfilename)\n\t\t\t\tcase \"/redfish/v1/Chassis/System.Embedded.1\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.chassisfilename)\n\t\t\t\tcase \"/redfish/v1/Systems/System.Embedded.1\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.hostnamefilename)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Redfish{\n\t\t\t\tAddress:          ts.URL,\n\t\t\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\t\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\t\t\tComputerSystemID: \"System.Embedded.1\",\n\t\t\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr := plugin.Gather(&acc)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"error parsing input:\")\n\t\t})\n\t}\n}\n\nfunc TestInvalidHPJSON(t *testing.T) {\n\ttests := []struct {\n\t\tname             string\n\t\tthermalfilename  string\n\t\tpowerfilename    string\n\t\thostnamefilename string\n\t\tchassisfilename  string\n\t}{\n\t\t{\n\t\t\tname:             \"check Thermal\",\n\t\t\tthermalfilename:  \"testdata/hp_thermalinvalid.json\",\n\t\t\tpowerfilename:    \"testdata/hp_power.json\",\n\t\t\thostnamefilename: \"testdata/hp_systems.json\",\n\t\t\tchassisfilename:  \"testdata/hp_chassis.json\",\n\t\t},\n\t\t{\n\t\t\tname:             \"check Power\",\n\t\t\tthermalfilename:  \"testdata/hp_thermal.json\",\n\t\t\tpowerfilename:    \"testdata/hp_powerinvalid.json\",\n\t\t\thostnamefilename: \"testdata/hp_systems.json\",\n\t\t\tchassisfilename:  \"testdata/hp_chassis.json\",\n\t\t},\n\t\t{\n\t\t\tname:             \"check Hostname\",\n\t\t\tthermalfilename:  \"testdata/hp_thermal.json\",\n\t\t\tpowerfilename:    \"testdata/hp_power.json\",\n\t\t\thostnamefilename: \"testdata/hp_systemsinvalid.json\",\n\t\t\tchassisfilename:  \"testdata/hp_chassis.json\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tswitch r.URL.Path {\n\t\t\t\tcase \"/redfish/v1/Chassis/1/Thermal\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.thermalfilename)\n\t\t\t\tcase \"/redfish/v1/Chassis/1/Power\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.powerfilename)\n\t\t\t\tcase \"/redfish/v1/Chassis/1/\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.chassisfilename)\n\t\t\t\tcase \"/redfish/v1/Systems/System.Embedded.2\":\n\t\t\t\t\thttp.ServeFile(w, r, tt.hostnamefilename)\n\t\t\t\tdefault:\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t}\n\t\t\t}))\n\t\t\tdefer ts.Close()\n\n\t\t\tplugin := &Redfish{\n\t\t\t\tAddress:          ts.URL,\n\t\t\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\t\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\t\t\tComputerSystemID: \"System.Embedded.2\",\n\t\t\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\terr := plugin.Gather(&acc)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), \"error parsing input:\")\n\t\t})\n\t}\n}\n\nfunc TestIncludeTagSetsConfiguration(t *testing.T) {\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !checkAuth(r, \"test\", \"test\") {\n\t\t\thttp.Error(w, \"Unauthorized.\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\n\t\tswitch r.URL.Path {\n\t\tcase \"/redfish/v1/Chassis/1/Thermal\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_thermal.json\")\n\t\tcase \"/redfish/v1/Chassis/1/Power\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_power.json\")\n\t\tcase \"/redfish/v1/Systems/1\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_systems.json\")\n\t\tcase \"/redfish/v1/Chassis/1/\":\n\t\t\thttp.ServeFile(w, r, \"testdata/hp_chassis.json\")\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\taddress, _, err := net.SplitHostPort(u.Host)\n\trequire.NoError(t, err)\n\n\texpectedMetricsHp := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":                 \"01-Inlet Ambient\",\n\t\t\t\t\"member_id\":            \"0\",\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          19.0,\n\t\t\t\t\"upper_threshold_critical\": 42.0,\n\t\t\t\t\"upper_threshold_fatal\":    47.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_temperatures\",\n\t\t\tmap[string]string{\n\t\t\t\t\"name\":                 \"44-P/S 2 Zone\",\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"member_id\":            \"42\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_celsius\":          34.0,\n\t\t\t\t\"upper_threshold_critical\": 75.0,\n\t\t\t\t\"upper_threshold_fatal\":    80.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"Fan 1\",\n\t\t\t\t\"member_id\":            \"0\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"Fan 2\",\n\t\t\t\t\"member_id\":            \"1\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_thermal_fans\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"Fan 3\",\n\t\t\t\t\"member_id\":            \"2\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"reading_percent\": 23,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powercontrol\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"\",\n\t\t\t\t\"member_id\":            \"0\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"average_consumed_watts\": 221.0,\n\t\t\t\t\"interval_in_min\":        int64(20),\n\t\t\t\t\"max_consumed_watts\":     252.0,\n\t\t\t\t\"min_consumed_watts\":     220.0,\n\t\t\t\t\"power_capacity_watts\":   1600.0,\n\t\t\t\t\"power_consumed_watts\":   221.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powersupplies\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"HpeServerPowerSupply\",\n\t\t\t\t\"member_id\":            \"0\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_capacity_watts\":    800.0,\n\t\t\t\t\"line_input_voltage\":      205.0,\n\t\t\t\t\"last_power_output_watts\": 0.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"redfish_power_powersupplies\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":               \"tpa-hostname\",\n\t\t\t\t\"name\":                 \"HpeServerPowerSupply\",\n\t\t\t\t\"member_id\":            \"1\",\n\t\t\t\t\"address\":              address,\n\t\t\t\t\"health\":               \"OK\",\n\t\t\t\t\"state\":                \"Enabled\",\n\t\t\t\t\"rack\":                 \"\",\n\t\t\t\t\"room\":                 \"\",\n\t\t\t\t\"row\":                  \"\",\n\t\t\t\t\"datacenter\":           \"\",\n\t\t\t\t\"chassis_chassistype\":  \"RackMount\",\n\t\t\t\t\"chassis_manufacturer\": \"HP\",\n\t\t\t\t\"chassis_model\":        \"Proliant Gen10\",\n\t\t\t\t\"chassis_partnumber\":   \"CT6NWPYZ\",\n\t\t\t\t\"chassis_powerstate\":   \"On\",\n\t\t\t\t\"chassis_sku\":          \"CLFYTTWP\",\n\t\t\t\t\"chassis_serialnumber\": \"QWEVC007C99803\",\n\t\t\t\t\"chassis_state\":        \"Enabled\",\n\t\t\t\t\"chassis_health\":       \"OK\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_capacity_watts\":    800.0,\n\t\t\t\t\"line_input_voltage\":      205.0,\n\t\t\t\t\"last_power_output_watts\": 90.0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\thpPlugin := &Redfish{\n\t\tAddress:          ts.URL,\n\t\tUsername:         config.NewSecret([]byte(\"test\")),\n\t\tPassword:         config.NewSecret([]byte(\"test\")),\n\t\tComputerSystemID: \"1\",\n\t\tIncludeTagSets:   []string{\"chassis\", \"chassis.location\"},\n\t\tIncludeMetrics:   []string{\"thermal\", \"power\"},\n\t}\n\trequire.NoError(t, hpPlugin.Init())\n\tvar hpAcc testutil.Accumulator\n\n\terr = hpPlugin.Gather(&hpAcc)\n\trequire.NoError(t, err)\n\trequire.True(t, hpAcc.HasMeasurement(\"redfish_thermal_temperatures\"))\n\ttestutil.RequireMetricsEqual(t, expectedMetricsHp, hpAcc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/sample.conf",
    "content": "# Read CPU, Fans, Powersupply and Voltage metrics of hardware server through redfish APIs\n[[inputs.redfish]]\n  ## Redfish API Base URL.\n  address = \"https://127.0.0.1:5000\"\n\n  ## Credentials for the Redfish API. Can also use secrets.\n  username = \"root\"\n  password = \"password123456\"\n\n  ## System Id to collect data for in Redfish APIs.\n  computer_system_id=\"System.Embedded.1\"\n\n  ## Metrics to collect\n  ## The metric collects to gather. Choose from \"power\" and \"thermal\".\n  # include_metrics = [\"power\", \"thermal\"]\n\n  ## Tag sets allow you to include redfish OData link parent data\n  ## For Example.\n  ## Thermal data is an OData link with parent Chassis which has a link of Location.\n  ## For more info see the Redfish Resource and Schema Guide at DMTFs website.\n  ## Available sets are: \"chassis.location\" and \"chassis\"\n  # include_tag_sets = [\"chassis.location\"]\n\n  ## Workarounds\n  ## Defines workarounds for certain hardware vendors. Choose from:\n  ## * ilo4-thermal - Do not pass 0Data-Version header to Thermal endpoint\n  # workarounds = []\n\n  ## Amount of time allowed to complete the HTTP request\n  # timeout = \"5s\"\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_chassis.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Chassis.Chassis\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\",\n  \"@odata.type\": \"#Chassis.v1_6_0.Chassis\",\n  \"Actions\": {\n    \"#Chassis.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\"\n      ],\n      \"target\": \"/redfish/v1/Chassis/System.Embedded.1/Actions/Chassis.Reset\"\n    }\n  },\n  \"Assembly\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n  },\n  \"AssetTag\": null,\n  \"ChassisType\": \"RackMount\",\n  \"Description\": \"It represents the properties for physical components for any system.It represent racks, rackmount servers, blades, standalone, modular systems,enclosures, and all other containers.The non-cpu/device centric parts of the schema are all accessed either directly or indirectly through this resource.\",\n  \"Id\": \"System.Embedded.1\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"ComputerSystems\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\"\n      }\n    ],\n    \"ComputerSystems@odata.count\": 1,\n    \"Contains\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/Enclosure.Internal.0-1:RAID.Integrated.1-1\"\n      }\n    ],\n    \"Contains@odata.count\": 1,\n    \"CooledBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\"\n      }\n    ],\n    \"CooledBy@odata.count\": 16,\n    \"Drives\": [],\n    \"Drives@odata.count\": 0,\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagedBy@odata.count\": 1,\n    \"ManagersInChassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagersInChassis@odata.count\": 1,\n    \"PCIeDevices\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/216-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-31\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-17\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/3-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-28\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-23\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/25-0\"\n      }\n    ],\n    \"PCIeDevices@odata.count\": 8,\n    \"PoweredBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2\"\n      }\n    ],\n    \"PoweredBy@odata.count\": 2,\n    \"Storage\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.2-1\"\n      }\n    ],\n    \"Storage@odata.count\": 3\n  },\n  \"Location\": {\n    \"Info\": \";;;;1\",\n    \"InfoFormat\": \"DataCenter;RoomName;Aisle;RackName;RackSlot\",\n    \"Placement\": {\n      \"Rack\": \"\",\n      \"Row\": \"\"\n    },\n    \"PostalAddress\": {\n      \"Building\": \"\",\n      \"Room\": \"\"\n    }\n  },\n  \"Manufacturer\": \"Dell Inc.\",\n  \"Model\": \"PowerEdge R640\",\n  \"Name\": \"Computer System Chassis\",\n  \"NetworkAdapters\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/NetworkAdapters\"\n  },\n  \"PartNumber\": \"0CRT1GA05\",\n  \"PhysicalSecurity\": {\n    \"IntrusionSensor\": \"Normal\",\n    \"IntrusionSensorNumber\": 115,\n    \"IntrusionSensorReArm\": \"Manual\"\n  },\n  \"Power\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power\"\n  },\n  \"PowerState\": \"On\",\n  \"SKU\": \"CLFV7M2\",\n  \"SerialNumber\": \"CNIVC007CV0803\",\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"HealthRollup\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Thermal\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_chassisinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Chassis.Chassis\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\",\n  \"@odata.type\": \"#Chassis.v1_6_0.Chassis\",\n  \"Actions\": {\n    \"#Chassis.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\"\n      ],\n      \"target\": \"/redfish/v1/Chassis/System.Embedded.1/Actions/Chassis.Reset\"\n    }\n  },\n  \"Assembly\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n  },\n  \"AssetTag\": null,\n  \"ChassisType\": \"RackMount\",\n  \"Description\": \"It represents the properties for physical components for any system.It represent racks, rackmount servers, blades, standalone, modular systems,enclosures, and all other containers.The non-cpu/device centric parts of the schema are all accessed either directly or indirectly through this resource.\",\n  \"Id\": \"System.Embedded.1\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"ComputerSystems\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\"\n      }\n    ],\n    \"ComputerSystems@odata.count\": 1,\n    \"Contains\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/Enclosure.Internal.0-1:RAID.Integrated.1-1\"\n      }\n    ],\n    \"Contains@odata.count\": 1,\n    \"CooledBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\"\n      }\n    ],\n    \"CooledBy@odata.count\": 16,\n    \"Drives\": [],\n    \"Drives@odata.count\": 0,\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagedBy@odata.count\": 1,\n    \"ManagersInChassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagersInChassis@odata.count\": 1,\n    \"PCIeDevices\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/216-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-31\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-17\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/3-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-28\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-0\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-23\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/25-0\"\n      }\n    ],\n    \"PCIeDevices@odata.count\": 8,\n    \"PoweredBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2\"\n      }\n    ],\n    \"PoweredBy@odata.count\": 2,\n    \"Storage\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.2-1\"\n      }\n    ],\n    \"Storage@odata.count\": 3\n  },\n  \"Location\": {\n    \"Info\": \";;;;1\",\n    \"InfoFormat\": \"DataCenter;RoomName;Aisle;RackName;RackSlot\",\n    \"Placement\": {\n      \"Rack\": \"\",\n      \"Row\": \"\"\n    },\n    \"PostalAddress\": {\n      \"Building\": \"\",\n      \"Room\": \"\"\n    }\n  },\n  \"Manufacturer\": \"Dell Inc.\",\n  \"Model\": \"PowerEdge R640\",\n  \"Name\": \"Computer System Chassis\",\n  \"NetworkAdapters\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/NetworkAdapters\"\n  },\n  \"PartNumber\": \"0CRT1GA05\",\n  \"PhysicalSecurity\": {\n    \"IntrusionSensor\": \"Normal\",\n    \"IntrusionSensorNumber\": 115,\n    \"IntrusionSensorReArm\": \"Manual\"\n  },\n  \"Power\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power\"\n  },\n  \"PowerState\": \"On\",\n  \"SKU\": \"CLFV7M2\",\n  \"SerialNumber\": \"CNIVC007CV0803\",\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"HealthRollup\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Thermal\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal\"\n  }\n}\n{\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_power.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power\",\n  \"@odata.type\": \"#Power.v1_5_0.Power\",\n  \"Description\": \"Power\",\n  \"Id\": \"Power\",\n  \"Name\": \"Power\",\n  \"PowerControl\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerControl\",\n      \"@odata.type\": \"#Power.v1_4_0.PowerControl\",\n      \"MemberId\": \"PowerControl\",\n      \"Name\": \"System Power Control\",\n      \"PowerAllocatedWatts\": 1628,\n      \"PowerAvailableWatts\": 0,\n      \"PowerCapacityWatts\": 1628,\n      \"PowerConsumedWatts\": 429,\n      \"PowerLimit\": {\n        \"CorrectionInMs\": 0,\n        \"LimitException\": \"HardPowerOff\",\n        \"LimitInWatts\": 348\n      },\n      \"PowerMetrics\": {\n        \"AverageConsumedWatts\": 426,\n        \"IntervalInMin\": 1,\n        \"MaxConsumedWatts\": 436,\n        \"MinConsumedWatts\": 425\n      },\n      \"PowerRequestedWatts\": 704,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        },\n        {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 2\n    }\n  ],\n  \"PowerControl@odata.count\": 1,\n  \"PowerSupplies\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\",\n      \"@odata.type\": \"#Power.v1_5_0.PowerSupply\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"EfficiencyPercent\": 0.9100000262260437,\n      \"FirmwareVersion\": \"00.1B.53\",\n      \"HotPluggable\": true,\n      \"InputRanges\": [\n        {\n          \"InputType\": \"AC\",\n          \"MaximumFrequencyHz\": 63,\n          \"MaximumVoltage\": 264,\n          \"MinimumFrequencyHz\": 47,\n          \"MinimumVoltage\": 90,\n          \"OutputWattage\": 750\n        }\n      ],\n      \"InputRanges@odata.count\": 1,\n      \"LastPowerOutputWatts\": null,\n      \"LineInputVoltage\": 206,\n      \"LineInputVoltageType\": \"AC240V\",\n      \"Manufacturer\": \"Dell\",\n      \"MemberId\": \"PSU.Slot.1\",\n      \"Model\": \"PWR SPLY,750W,RDNT,ARTESYN    \",\n      \"Name\": \"PS1 Status\",\n      \"Oem\": {\n        \"Dell\": {\n          \"DellPowerSupply\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#DellPowerSupply.DellPowerSupply\",\n            \"@odata.id\": \"/redfish/v1/Dell/Chassis/System.Embedded.1/Power/PowerSupplies/DellPowerSupply/PSU.Slot.1\",\n            \"@odata.type\": \"#DellPowerSupply.v1_0_0.DellPowerSupply\",\n            \"IsSwitchingSupply\": true,\n            \"Links\": {\n              \"DellPSNumericSensorCollection\": [\n                {\n                  \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellPSNumericSensor/iDRAC.Embedded.1%23PS1Current1\"\n                }\n              ]\n            }\n          },\n          \"DellPowerSupplyView\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#DellPowerSupplyView.DellPowerSupplyView\",\n            \"@odata.id\": \"/redfish/v1/Dell/Chassis/System.Embedded.1/Power/PowerSupplies/DellPowerSupplyView/PSU.Slot.1\",\n            \"@odata.type\": \"#DellPowerSupplyView.v1_0_0.DellPowerSupplyView\",\n            \"DetailedState\": \"Presence Detected\",\n            \"Range1MaxInputPowerWatts\": 900\n          }\n        }\n      },\n      \"PartNumber\": \"0PJMDNA01\",\n      \"PowerCapacityWatts\": 750,\n      \"PowerInputWatts\": 900,\n      \"PowerOutputWatts\": 203,\n      \"PowerSupplyType\": \"AC\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SerialNumber\": \"PHARP0079G0049\",\n      \"SparePartNumber\": \"0PJMDNA01\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"PowerSupplies@odata.count\": 1,\n  \"Redundancy\": [],\n  \"Redundancy@odata.count\": 0,\n  \"Voltages\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardDIMMPG\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 0,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardDIMMPG\",\n      \"MinReadingRange\": 0,\n      \"Name\": \"System Board DIMM PG\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 7,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardNDCPG\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 197,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardNDCPG\",\n      \"MinReadingRange\": 139,\n      \"Name\": \"System Board NDC PG\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 8,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardPS1PGFAIL\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 197,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardPS1PGFAIL\",\n      \"MinReadingRange\": 139,\n      \"Name\": \"System Board PS1 PG FAIL\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 9,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Voltages@odata.count\": 4\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_powerinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power\",\n  \"@odata.type\": \"#Power.v1_5_0.Power\",\n  \"Description\": \"Power\",\n  \"Id\": \"Power\",\n  \"Name\": \"Power\",\n  \"PowerControl\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerControl\",\n      \"@odata.type\": \"#Power.v1_4_0.PowerControl\",\n      \"MemberId\": \"PowerControl\",\n      \"Name\": \"System Power Control\",\n      \"PowerAllocatedWatts\": 1628,\n      \"PowerAvailableWatts\": 0,\n      \"PowerCapacityWatts\": 1628,\n      \"PowerConsumedWatts\": 429,\n      \"PowerLimit\": {\n        \"CorrectionInMs\": 0,\n        \"LimitException\": \"HardPowerOff\",\n        \"LimitInWatts\": 348\n      },\n      \"PowerMetrics\": {\n        \"AverageConsumedWatts\": 426,\n        \"IntervalInMin\": 1,\n        \"MaxConsumedWatts\": 436,\n        \"MinConsumedWatts\": 425\n      },\n      \"PowerRequestedWatts\": 704,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        },\n        {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 2\n    }\n  ],\n  \"PowerControl@odata.count\": 1,\n  \"PowerSupplies\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\",\n      \"@odata.type\": \"#Power.v1_5_0.PowerSupply\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"EfficiencyPercent\": 0.9100000262260437,\n      \"FirmwareVersion\": \"00.1B.53\",\n      \"HotPluggable\": true,\n      \"InputRanges\": [\n        {\n          \"InputType\": \"AC\",\n          \"MaximumFrequencyHz\": 63,\n          \"MaximumVoltage\": 264,\n          \"MinimumFrequencyHz\": 47,\n          \"MinimumVoltage\": 90,\n          \"OutputWattage\": 750\n        }\n      ],\n      \"InputRanges@odata.count\": 1,\n      \"LastPowerOutputWatts\": null,\n      \"LineInputVoltage\": 206,\n      \"LineInputVoltageType\": \"AC240V\",\n      \"Manufacturer\": \"Dell\",\n      \"MemberId\": \"PSU.Slot.1\",\n      \"Model\": \"PWR SPLY,750W,RDNT,ARTESYN    \",\n      \"Name\": PS1 Status,\n      \"Oem\": {\n        \"Dell\": {\n          \"DellPowerSupply\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#DellPowerSupply.DellPowerSupply\",\n            \"@odata.id\": \"/redfish/v1/Dell/Chassis/System.Embedded.1/Power/PowerSupplies/DellPowerSupply/PSU.Slot.1\",\n            \"@odata.type\": \"#DellPowerSupply.v1_0_0.DellPowerSupply\",\n            \"IsSwitchingSupply\": true,\n            \"Links\": {\n              \"DellPSNumericSensorCollection\": [\n                {\n                  \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellPSNumericSensor/iDRAC.Embedded.1%23PS1Current1\"\n                }\n              ]\n            }\n          },\n          \"DellPowerSupplyView\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#DellPowerSupplyView.DellPowerSupplyView\",\n            \"@odata.id\": \"/redfish/v1/Dell/Chassis/System.Embedded.1/Power/PowerSupplies/DellPowerSupplyView/PSU.Slot.1\",\n            \"@odata.type\": \"#DellPowerSupplyView.v1_0_0.DellPowerSupplyView\",\n            \"DetailedState\": \"Presence Detected\",\n            \"Range1MaxInputPowerWatts\": 900\n          }\n        }\n      },\n      \"PartNumber\": \"0PJMDNA01\",\n      \"PowerCapacityWatts\": 750,\n      \"PowerInputWatts\": 900,\n      \"PowerOutputWatts\": 203,\n      \"PowerSupplyType\": \"AC\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SerialNumber\": \"PHARP0079G0049\",\n      \"SparePartNumber\": \"0PJMDNA01\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"PowerSupplies@odata.count\": 1,\n  \"Redundancy\": [],\n  \"Redundancy@odata.count\": 0,\n  \"Voltages\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardDIMMPG\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 0,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardDIMMPG\",\n      \"MinReadingRange\": 0,\n      \"Name\": \"System Board DIMM PG\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 7,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardNDCPG\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 197,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardNDCPG\",\n      \"MinReadingRange\": 139,\n      \"Name\": \"System Board NDC PG\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 8,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Voltages/iDRAC.Embedded.1%23SystemBoardPS1PGFAIL\",\n      \"@odata.type\": \"#Power.v1_3_0.Voltage\",\n      \"LowerThresholdCritical\": null,\n      \"LowerThresholdFatal\": null,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRange\": 197,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardPS1PGFAIL\",\n      \"MinReadingRange\": 139,\n      \"Name\": \"System Board PS1 PG FAIL\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"ReadingVolts\": 1,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 9,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Voltages@odata.count\": 4\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_systems.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n  \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\",\n  \"@odata.type\": \"#ComputerSystem.v1_5_0.ComputerSystem\",\n  \"Actions\": {\n    \"#ComputerSystem.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\",\n        \"ForceRestart\",\n        \"GracefulShutdown\",\n        \"PushPowerButton\",\n        \"Nmi\"\n      ],\n      \"target\": \"/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset\"\n    }\n  },\n  \"AssetTag\": \"\",\n  \"Bios\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Bios\"\n  },\n  \"BiosVersion\": \"2.3.10\",\n  \"Boot\": {\n    \"BootOptions\": {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/BootOptions\"\n    },\n    \"BootOrder\": [\n      \"Boot0002\",\n      \"Boot0003\",\n      \"Boot0005\",\n      \"Boot0004\"\n    ],\n    \"BootOrder@odata.count\": 4,\n    \"BootSourceOverrideEnabled\": \"Once\",\n    \"BootSourceOverrideMode\": \"UEFI\",\n    \"BootSourceOverrideTarget\": \"None\",\n    \"BootSourceOverrideTarget@Redfish.AllowableValues\": [\n      \"None\",\n      \"Pxe\",\n      \"Floppy\",\n      \"Cd\",\n      \"Hdd\",\n      \"BiosSetup\",\n      \"Utilities\",\n      \"UefiTarget\",\n      \"SDCard\",\n      \"UefiHttp\"\n    ],\n    \"UefiTargetBootSourceOverride\": \"\"\n  },\n  \"Description\": \"Computer System which represents a machine (physical or virtual) and the local resources such as memory, cpu and other devices that can be accessed from that machine.\",\n  \"EthernetInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/EthernetInterfaces\"\n  },\n  \"HostName\": \"tpa-hostname\",\n  \"HostWatchdogTimer\": {\n    \"FunctionEnabled\": true,\n    \"Status\": {\n      \"State\": \"Enabled\"\n    },\n    \"TimeoutAction\": \"None\"\n  },\n  \"HostingRoles\": [],\n  \"HostingRoles@odata.count\": 0,\n  \"Id\": \"System.Embedded.1\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"Chassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n      }\n    ],\n    \"Chassis@odata.count\": 1,\n    \"CooledBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\"\n      }\n    ],\n    \"CooledBy@odata.count\": 16,\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagedBy@odata.count\": 1,\n    \"Oem\": {\n      \"Dell\": {\n        \"BootOrder\": {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/BootSources\"\n        },\n        \"DellNumericSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellNumericSensorCollection\"\n        },\n        \"DellOSDeploymentService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellOSDeploymentService\"\n        },\n        \"DellPresenceAndStatusSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellPresenceAndStatusSensorCollection\"\n        },\n        \"DellRaidService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellRaidService\"\n        },\n        \"DellSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSensorCollection\"\n        },\n        \"DellSoftwareInstallationService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSoftwareInstallationService\"\n        }\n      }\n    },\n    \"PoweredBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2\"\n      }\n    ],\n    \"PoweredBy@odata.count\": 2\n  },\n  \"Manufacturer\": \"Dell Inc.\",\n  \"Memory\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Memory\"\n  },\n  \"MemorySummary\": {\n    \"MemoryMirroring\": \"System\",\n    \"Status\": {\n      \"Health\": \"OK\",\n      \"HealthRollup\": \"OK\",\n      \"State\": \"Enabled\"\n    },\n    \"TotalSystemMemoryGiB\": 476.837376\n  },\n  \"Model\": \"PowerEdge R640\",\n  \"Name\": \"System\",\n  \"NetworkInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/NetworkInterfaces\"\n  },\n  \"Oem\": {\n    \"Dell\": {\n      \"DellSystem\": {\n        \"@odata.context\": \"/redfish/v1/$metadata#DellSystem.DellSystem\",\n        \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSystem/System.Embedded.1\",\n        \"@odata.type\": \"#DellSystem.v1_0_0.DellSystem\",\n        \"BIOSReleaseDate\": \"08/15/2019\",\n        \"BaseBoardChassisSlot\": \"NA\",\n        \"BatteryRollupStatus\": \"OK\",\n        \"BladeGeometry\": \"NotApplicable\",\n        \"CMCIP\": null,\n        \"CPURollupStatus\": \"OK\",\n        \"ChassisServiceTag\": \"CLFV7M2\",\n        \"ExpressServiceCode\": \"27417828170\",\n        \"FanRollupStatus\": \"OK\",\n        \"IntrusionRollupStatus\": \"OK\",\n        \"LicensingRollupStatus\": \"OK\",\n        \"MaxDIMMSlots\": 24,\n        \"MaxPCIeSlots\": 3,\n        \"NodeID\": \"CLFV7M2\",\n        \"PSRollupStatus\": \"OK\",\n        \"PowerCapEnabledState\": \"Disabled\",\n        \"StorageRollupStatus\": \"OK\",\n        \"SysMemPrimaryStatus\": \"OK\",\n        \"SystemGeneration\": \"14G Monolithic\",\n        \"SystemID\": 1814,\n        \"TempRollupStatus\": \"OK\",\n        \"UUID\": \"4c4c4544-004c-4610-8056-c3c04f374d32\",\n        \"VoltRollupStatus\": \"OK\"\n      }\n    }\n  },\n  \"PCIeDevices\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/216-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-31\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-17\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/3-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-28\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-23\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/25-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/24-0\"\n    }\n  ],\n  \"PCIeDevices@odata.count\": 9,\n  \"PCIeFunctions\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/216-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/216-0-1\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-31-4\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-17-5\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-31-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/3-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-28-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-23-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-28-4\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/25-0-1\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/25-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/24-0-0\"\n    }\n  ],\n  \"PCIeFunctions@odata.count\": 13,\n  \"PartNumber\": \"0CRT1GA05\",\n  \"PowerState\": \"On\",\n  \"ProcessorSummary\": {\n    \"Count\": 2,\n    \"LogicalProcessorCount\": 80,\n    \"Model\": \"Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz\",\n    \"Status\": {\n      \"Health\": \"OK\",\n      \"HealthRollup\": \"OK\",\n      \"State\": \"Enabled\"\n    }\n  },\n  \"Processors\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Processors\"\n  },\n  \"SKU\": \"CLFV7M2\",\n  \"SecureBoot\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/SecureBoot\"\n  },\n  \"SerialNumber\": \"CNIVC007CV0803\",\n  \"SimpleStorage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/SimpleStorage/Controllers\"\n  },\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"HealthRollup\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Storage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage\"\n  },\n  \"SystemType\": \"Physical\",\n  \"TrustedModules\": [\n    {\n      \"FirmwareVersion\": \"Unknown\",\n      \"Status\": {\n        \"State\": \"Disabled\"\n      }\n    }\n  ],\n  \"UUID\": \"4c4c4544-004c-4610-8056-c3c04f374d32\"\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_systemsinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n  \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1\",\n  \"@odata.type\": \"#ComputerSystem.v1_5_0.ComputerSystem\",\n  \"Actions\": {\n    \"#ComputerSystem.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\",\n        \"ForceRestart\",\n        \"GracefulShutdown\",\n        \"PushPowerButton\",\n        \"Nmi\"\n      ],\n      \"target\": \"/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset\"\n    }\n  },\n  \"AssetTag\": \"\",\n  \"Bios\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Bios\"\n  },\n  \"BiosVersion\": \"2.3.10\",\n  \"Boot\": {\n    \"BootOptions\": {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/BootOptions\"\n    },\n    \"BootOrder\": [\n      \"Boot0002\",\n      \"Boot0003\",\n      \"Boot0005\",\n      \"Boot0004\"\n    ],\n    \"BootOrder@odata.count\": 4,\n    \"BootSourceOverrideEnabled\": \"Once\",\n    \"BootSourceOverrideMode\": \"UEFI\",\n    \"BootSourceOverrideTarget\": \"None\",\n    \"BootSourceOverrideTarget@Redfish.AllowableValues\": [\n      \"None\",\n      \"Pxe\",\n      \"Floppy\",\n      \"Cd\",\n      \"Hdd\",\n      \"BiosSetup\",\n      \"Utilities\",\n      \"UefiTarget\",\n      \"SDCard\",\n      \"UefiHttp\"\n    ],\n    \"UefiTargetBootSourceOverride\": \"\"\n  },\n  \"Description\": \"Computer System which represents a machine (physical or virtual) and the local resources such as memory, cpu and other devices that can be accessed from that machine.\",\n  \"EthernetInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/EthernetInterfaces\"\n  }\n  \"HostName\": \"tpa-hostname\",\n  \"HostWatchdogTimer\": {\n    \"FunctionEnabled\": true,\n    \"Status\": {\n      \"State\": \"Enabled\"\n    },\n    \"TimeoutAction\": \"None\"\n  },\n  \"HostingRoles\": [],\n  \"HostingRoles@odata.count\": 0,\n  \"Id\": \"System.Embedded.1\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"Chassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n      }\n    ],\n    \"Chassis@odata.count\": 1,\n    \"CooledBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\"\n      }\n    ],\n    \"CooledBy@odata.count\": 16,\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1\"\n      }\n    ],\n    \"ManagedBy@odata.count\": 1,\n    \"Oem\": {\n      \"Dell\": {\n        \"BootOrder\": {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/BootSources\"\n        },\n        \"DellNumericSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellNumericSensorCollection\"\n        },\n        \"DellOSDeploymentService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellOSDeploymentService\"\n        },\n        \"DellPresenceAndStatusSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellPresenceAndStatusSensorCollection\"\n        },\n        \"DellRaidService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellRaidService\"\n        },\n        \"DellSensorCollection\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSensorCollection\"\n        },\n        \"DellSoftwareInstallationService\": {\n          \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSoftwareInstallationService\"\n        }\n      }\n    },\n    \"PoweredBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.1\"\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Power/PowerSupplies/PSU.Slot.2\"\n      }\n    ],\n    \"PoweredBy@odata.count\": 2\n  },\n  \"Manufacturer\": \"Dell Inc.\",\n  \"Memory\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Memory\"\n  },\n  \"MemorySummary\": {\n    \"MemoryMirroring\": \"System\",\n    \"Status\": {\n      \"Health\": \"OK\",\n      \"HealthRollup\": \"OK\",\n      \"State\": \"Enabled\"\n    },\n    \"TotalSystemMemoryGiB\": 476.837376\n  },\n  \"Model\": \"PowerEdge R640\",\n  \"Name\": \"System\",\n  \"NetworkInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/NetworkInterfaces\"\n  },\n  \"Oem\": {\n    \"Dell\": {\n      \"DellSystem\": {\n        \"@odata.context\": \"/redfish/v1/$metadata#DellSystem.DellSystem\",\n        \"@odata.id\": \"/redfish/v1/Dell/Systems/System.Embedded.1/DellSystem/System.Embedded.1\",\n        \"@odata.type\": \"#DellSystem.v1_0_0.DellSystem\",\n        \"BIOSReleaseDate\": \"08/15/2019\",\n        \"BaseBoardChassisSlot\": \"NA\",\n        \"BatteryRollupStatus\": \"OK\",\n        \"BladeGeometry\": \"NotApplicable\",\n        \"CMCIP\": null,\n        \"CPURollupStatus\": \"OK\",\n        \"ChassisServiceTag\": \"CLFV7M2\",\n        \"ExpressServiceCode\": \"27417828170\",\n        \"FanRollupStatus\": \"OK\",\n        \"IntrusionRollupStatus\": \"OK\",\n        \"LicensingRollupStatus\": \"OK\",\n        \"MaxDIMMSlots\": 24,\n        \"MaxPCIeSlots\": 3,\n        \"NodeID\": \"CLFV7M2\",\n        \"PSRollupStatus\": \"OK\",\n        \"PowerCapEnabledState\": \"Disabled\",\n        \"StorageRollupStatus\": \"OK\",\n        \"SysMemPrimaryStatus\": \"OK\",\n        \"SystemGeneration\": \"14G Monolithic\",\n        \"SystemID\": 1814,\n        \"TempRollupStatus\": \"OK\",\n        \"UUID\": \"4c4c4544-004c-4610-8056-c3c04f374d32\",\n        \"VoltRollupStatus\": \"OK\"\n      }\n    }\n  },\n  \"PCIeDevices\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/216-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-31\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-17\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/3-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-28\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/0-23\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/25-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeDevice/24-0\"\n    }\n  ],\n  \"PCIeDevices@odata.count\": 9,\n  \"PCIeFunctions\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/216-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/216-0-1\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-31-4\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-17-5\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-31-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/3-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-28-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-23-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/0-28-4\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/25-0-1\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/25-0-0\"\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/PCIeFunction/24-0-0\"\n    }\n  ],\n  \"PCIeFunctions@odata.count\": 13,\n  \"PartNumber\": \"0CRT1GA05\",\n  \"PowerState\": \"On\",\n  \"ProcessorSummary\": {\n    \"Count\": 2,\n    \"LogicalProcessorCount\": 80,\n    \"Model\": \"Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz\",\n    \"Status\": {\n      \"Health\": \"OK\",\n      \"HealthRollup\": \"OK\",\n      \"State\": \"Enabled\"\n    }\n  },\n  \"Processors\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Processors\"\n  },\n  \"SKU\": \"CLFV7M2\",\n  \"SecureBoot\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/SecureBoot\"\n  },\n  \"SerialNumber\": \"CNIVC007CV0803\",\n  \"SimpleStorage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/SimpleStorage/Controllers\"\n  },\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"HealthRollup\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Storage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Storage\"\n  },\n  \"SystemType\": \"Physical\",\n  \"TrustedModules\": [\n    {\n      \"FirmwareVersion\": \"Unknown\",\n      \"Status\": {\n        \"State\": \"Disabled\"\n      }\n    }\n  ],\n  \"UUID\": \"4c4c4544-004c-4610-8056-c3c04f374d32\"\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_thermal.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal\",\n  \"@odata.type\": \"#Thermal.v1_4_0.Thermal\",\n  \"Description\": \"Represents the properties for Temperature and Cooling\",\n  \"Fans\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan1A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.1A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan1A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17760,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan1B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.1B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan1B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15360,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan2A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.2A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan2A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17880,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan2B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.2B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan2B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15120,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan3A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.3A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan3A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 18000,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan3B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.3B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan3B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan4A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.4A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan4A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17280,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan4B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.4B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan4B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15360,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan5A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.5A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan5A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17640,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan5B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.5B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan5B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan6A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.6A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan6A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17760,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan6B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.6B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan6B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan7A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.7A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan7A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17400,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan7B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.7B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan7B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15720,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan8A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.8A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan8A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 18000,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan8B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.8B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan8B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15840,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Fans@odata.count\": 16,\n  \"Id\": \"Thermal\",\n  \"Name\": \"Thermal\",\n  \"Redundancy\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal/Redundancy/iDRAC.Embedded.1%23SystemBoardFanRedundancy\",\n      \"@odata.type\": \"#Redundancy.v1_3_0.Redundancy\",\n      \"MaxNumSupported\": 0,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardFanRedundancy\",\n      \"MinNumNeeded\": 0,\n      \"Mode\": \"N+m\",\n      \"Name\": \"System Board Fan Redundancy\",\n      \"RedundancyEnabled\": true,\n      \"RedundancySet\": [],\n      \"RedundancySet@odata.count\": 0,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Redundancy@odata.count\": 1,\n  \"Temperatures\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Temperatures/iDRAC.Embedded.1%23CPU1Temp\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Temperature\",\n      \"LowerThresholdCritical\": 3,\n      \"LowerThresholdFatal\": 3,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRangeTemp\": 93,\n      \"MemberId\": \"iDRAC.Embedded.1#CPU1Temp\",\n      \"MinReadingRangeTemp\": 3,\n      \"Name\": \"CPU1 Temp\",\n      \"PhysicalContext\": \"CPU\",\n      \"ReadingCelsius\": 40,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Processors/CPU.Socket.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 93,\n      \"UpperThresholdFatal\": 93,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Temperatures@odata.count\": 4\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/dell_thermalinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n  \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal\",\n  \"@odata.type\": \"#Thermal.v1_4_0.Thermal\",\n  \"Description\": \"Represents the properties for Temperature and Cooling\",\n  \"Fans\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan1A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.1A\",\n      \"MinReadingRange\": 600,\n      \"Name\": System Board Fan1A,\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17760,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.1B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan1B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.1B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan1B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15360,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan2A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.2A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan2A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17880,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.2B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan2B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.2B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan2B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15120,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan3A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.3A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan3A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 18000,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.3B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan3B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.3B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan3B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan4A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.4A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan4A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17280,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.4B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan4B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.4B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan4B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15360,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan5A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.5A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan5A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17640,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.5B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan5B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.5B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan5B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan6A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.6A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan6A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17760,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.6B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan6B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.6B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan6B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15600,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan7A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.7A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan7A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 17400,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.7B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan7B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.7B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan7B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15720,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8A\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan8A\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.8A\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan8A\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 18000,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Fans/0x17%7C%7CFan.Embedded.8B\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Fan\",\n      \"Assembly\": {\n        \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Assembly\"\n      },\n      \"FanName\": \"System Board Fan8B\",\n      \"LowerThresholdCritical\": 600,\n      \"LowerThresholdFatal\": 600,\n      \"LowerThresholdNonCritical\": 960,\n      \"MaxReadingRange\": null,\n      \"MemberId\": \"0x17||Fan.Embedded.8B\",\n      \"MinReadingRange\": 600,\n      \"Name\": \"System Board Fan8B\",\n      \"PhysicalContext\": \"SystemBoard\",\n      \"Reading\": 15840,\n      \"ReadingUnits\": \"RPM\",\n      \"Redundancy\": [],\n      \"Redundancy@odata.count\": 0,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": null,\n      \"UpperThresholdFatal\": null,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Fans@odata.count\": 16,\n  \"Id\": \"Thermal\",\n  \"Name\": \"Thermal\",\n  \"Redundancy\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Thermal/Redundancy/iDRAC.Embedded.1%23SystemBoardFanRedundancy\",\n      \"@odata.type\": \"#Redundancy.v1_3_0.Redundancy\",\n      \"MaxNumSupported\": 0,\n      \"MemberId\": \"iDRAC.Embedded.1#SystemBoardFanRedundancy\",\n      \"MinNumNeeded\": 0,\n      \"Mode\": \"N+m\",\n      \"Name\": \"System Board Fan Redundancy\",\n      \"RedundancyEnabled\": true,\n      \"RedundancySet\": [],\n      \"RedundancySet@odata.count\": 0,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Redundancy@odata.count\": 1,\n  \"Temperatures\": [\n    {\n      \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n      \"@odata.id\": \"/redfish/v1/Chassis/System.Embedded.1/Sensors/Temperatures/iDRAC.Embedded.1%23CPU1Temp\",\n      \"@odata.type\": \"#Thermal.v1_4_0.Temperature\",\n      \"LowerThresholdCritical\": 3,\n      \"LowerThresholdFatal\": 3,\n      \"LowerThresholdNonCritical\": null,\n      \"MaxReadingRangeTemp\": 93,\n      \"MemberId\": \"iDRAC.Embedded.1#CPU1Temp\",\n      \"MinReadingRangeTemp\": 3,\n      \"Name\": \"CPU1 Temp\",\n      \"PhysicalContext\": \"CPU\",\n      \"ReadingCelsius\": 40,\n      \"RelatedItem\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Processors/CPU.Socket.1\"\n        }\n      ],\n      \"RelatedItem@odata.count\": 1,\n      \"SensorNumber\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 93,\n      \"UpperThresholdFatal\": 93,\n      \"UpperThresholdNonCritical\": null\n    }\n  ],\n  \"Temperatures@odata.count\": 4\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_chassis.json",
    "content": "{\n  \"ChassisType\": \"RackMount\",\n  \"Location\": {\n    \"Info\": \";;;;1\",\n    \"InfoFormat\": \"DataCenter;RoomName;Aisle;RackName;RackSlot\",\n    \"Placement\": {\n      \"Rack\": \"\",\n      \"Row\": \"\"\n    },\n    \"PostalAddress\": {\n      \"Building\": \"\",\n      \"Room\": \"\"\n    }\n  },\n  \"Manufacturer\": \"HP\",\n  \"Model\": \"Proliant Gen10\",\n  \"PartNumber\": \"CT6NWPYZ\",\n  \"Power\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/1/Power\"\n  },\n  \"PowerState\": \"On\",\n  \"SKU\": \"CLFYTTWP\",\n  \"SerialNumber\": \"QWEVC007C99803\",\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Thermal\": {\n    \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal\"\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_power.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n  \"@odata.etag\": \"W/\\\"2E43EED0\\\"\",\n  \"@odata.id\": \"/redfish/v1/Chassis/1/Power\",\n  \"@odata.type\": \"#Power.v1_3_0.Power\",\n  \"Id\": \"Power\",\n  \"Name\": \"PowerMetrics\",\n  \"Oem\": {\n    \"Hpe\": {\n      \"@odata.context\": \"/redfish/v1/$metadata#HpePowerMetricsExt.HpePowerMetricsExt\",\n      \"@odata.type\": \"#HpePowerMetricsExt.v2_2_0.HpePowerMetricsExt\",\n      \"BrownoutRecoveryEnabled\": true,\n      \"HasCpuPowerMetering\": true,\n      \"HasDimmPowerMetering\": true,\n      \"HasGpuPowerMetering\": false,\n      \"HasPowerMetering\": true,\n      \"HighEfficiencyMode\": \"Balanced\",\n      \"Links\": {\n        \"PowerMeter\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/PowerMeter\"\n        },\n        \"FastPowerMeter\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/FastPowerMeter\"\n        },\n        \"FederatedGroupCapping\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/FederatedGroupCapping\"\n        }\n      },\n      \"MinimumSafelyAchievableCap\": null,\n      \"MinimumSafelyAchievableCapValid\": false,\n      \"SNMPPowerThresholdAlert\": {\n        \"DurationInMin\": 0,\n        \"ThresholdWatts\": 0,\n        \"Trigger\": \"Disabled\"\n      }\n    }\n  },\n  \"PowerControl\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerControl/0\",\n      \"MemberId\": \"0\",\n      \"PowerCapacityWatts\": 1600,\n      \"PowerConsumedWatts\": 221,\n      \"PowerMetrics\": {\n        \"AverageConsumedWatts\": 221,\n        \"IntervalInMin\": 20,\n        \"MaxConsumedWatts\": 252,\n        \"MinConsumedWatts\": 220\n      }\n    }\n  ],\n  \"PowerSupplies\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/0\",\n      \"FirmwareVersion\": \"1.02\",\n      \"LastPowerOutputWatts\": 0,\n      \"LineInputVoltage\": 205,\n      \"LineInputVoltageType\": \"ACHighLine\",\n      \"Manufacturer\": \"CHCNY\",\n      \"MemberId\": \"0\",\n      \"Model\": \"865414-B21\",\n      \"Name\": \"HpeServerPowerSupply\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerPowerSupply.HpeServerPowerSupply\",\n          \"@odata.type\": \"#HpeServerPowerSupply.v2_0_0.HpeServerPowerSupply\",\n          \"AveragePowerOutputWatts\": 0,\n          \"BayNumber\": 1,\n          \"HotplugCapable\": true,\n          \"MaxPowerOutputWatts\": 143,\n          \"Mismatched\": false,\n          \"PowerSupplyStatus\": {\n            \"State\": \"Ok\"\n          },\n          \"iPDUCapable\": false\n        }\n      },\n      \"PowerCapacityWatts\": 800,\n      \"PowerSupplyType\": \"AC\",\n      \"SerialNumber\": \"5WEBP0B8JAQ2K9\",\n      \"SparePartNumber\": \"866730-001\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/1\",\n      \"FirmwareVersion\": \"1.02\",\n      \"LastPowerOutputWatts\": 90,\n      \"LineInputVoltage\": 205,\n      \"LineInputVoltageType\": \"ACHighLine\",\n      \"Manufacturer\": \"CHCNY\",\n      \"MemberId\": \"1\",\n      \"Model\": \"865414-B21\",\n      \"Name\": \"HpeServerPowerSupply\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerPowerSupply.HpeServerPowerSupply\",\n          \"@odata.type\": \"#HpeServerPowerSupply.v2_0_0.HpeServerPowerSupply\",\n          \"AveragePowerOutputWatts\": 90,\n          \"BayNumber\": 2,\n          \"HotplugCapable\": true,\n          \"MaxPowerOutputWatts\": 99,\n          \"Mismatched\": false,\n          \"PowerSupplyStatus\": {\n            \"State\": \"Ok\"\n          },\n          \"iPDUCapable\": false\n        }\n      },\n      \"PowerCapacityWatts\": 800,\n      \"PowerSupplyType\": \"AC\",\n      \"SerialNumber\": \"5WEBP0B8JAQ2KL\",\n      \"SparePartNumber\": \"866730-001\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Redundancy\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#Redundancy/0\",\n      \"MaxNumSupported\": 2,\n      \"MemberId\": \"0\",\n      \"MinNumNeeded\": 2,\n      \"Mode\": \"Failover\",\n      \"Name\": \"PowerSupply Redundancy Group 1\",\n      \"RedundancySet\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/0\"\n        },\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/1\"\n        }\n      ],\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_powerinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Power.Power\",\n  \"@odata.etag\": \"W/\\\"2E43EED0\\\"\",\n  \"@odata.id\": \"/redfish/v1/Chassis/1/Power\",\n  \"@odata.type\": \"#Power.v1_3_0.Power\",\n  \"Id\": \"Power\",\n  \"Name\": \"PowerMetrics\",\n  \"Oem\": {\n    \"Hpe\": {\n      \"@odata.context\": \"/redfish/v1/$metadata#HpePowerMetricsExt.HpePowerMetricsExt\",\n      \"@odata.type\": \"#HpePowerMetricsExt.v2_2_0.HpePowerMetricsExt\",\n      \"BrownoutRecoveryEnabled\": true,\n      \"HasCpuPowerMetering\": true,\n      \"HasDimmPowerMetering\": true,\n      \"HasGpuPowerMetering\": false,\n      \"HasPowerMetering\": true,\n      \"HighEfficiencyMode\": \"Balanced\",\n      \"Links\": {\n        \"PowerMeter\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/PowerMeter\"\n        },\n        \"FastPowerMeter\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/FastPowerMeter\"\n        },\n        \"FederatedGroupCapping\": {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power/FederatedGroupCapping\"\n        }\n      },\n      \"MinimumSafelyAchievableCap\": null,\n      \"MinimumSafelyAchievableCapValid\": false,\n      \"SNMPPowerThresholdAlert\": {\n        \"DurationInMin\": 0,\n        \"ThresholdWatts\": 0,\n        \"Trigger\": \"Disabled\"\n      }\n    }\n  },\n  \"PowerControl\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerControl/0\",\n      \"MemberId\": \"0\",\n      \"PowerCapacityWatts\": 1600,\n      \"PowerConsumedWatts\": 221,\n      \"PowerMetrics\": {\n        \"AverageConsumedWatts\": 221,\n        \"IntervalInMin\": 20,\n        \"MaxConsumedWatts\": 252,\n        \"MinConsumedWatts\": 220\n      }\n    }\n  ],\n  \"PowerSupplies\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/0\",\n      \"FirmwareVersion\": \"1.02\",\n      \"LastPowerOutputWatts\": 0,\n      \"LineInputVoltage\": 205,\n      \"LineInputVoltageType\": \"ACHighLine\",\n      \"Manufacturer\": \"CHCNY\",\n      \"MemberId\": \"0\",\n      \"Model\": \"865414-B21\",\n      \"Name\": \"HpeServerPowerSupply\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerPowerSupply.HpeServerPowerSupply\",\n          \"@odata.type\": \"#HpeServerPowerSupply.v2_0_0.HpeServerPowerSupply\",\n          \"AveragePowerOutputWatts\": 0,\n          \"BayNumber\": 1,\n          \"HotplugCapable\": true,\n          \"MaxPowerOutputWatts\": 143,\n          \"Mismatched\": false,\n          \"PowerSupplyStatus\": {\n            \"State\": \"Ok\"\n          },\n          \"iPDUCapable\": false\n        }\n      },\n      \"PowerCapacityWatts\": 800,\n      \"PowerSupplyType\": \"AC\",\n      \"SerialNumber\": \"5WEBP0B8JAQ2K9\",\n      \"SparePartNumber\": \"866730-001\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/1\",\n      \"FirmwareVersion\": \"1.02\",\n      \"LastPowerOutputWatts\": 90,\n      \"LineInputVoltage\": 205,\n      \"LineInputVoltageType\": \"ACHighLine\",\n      \"Manufacturer\": \"CHCNY\",\n      \"MemberId\": \"1\",\n      \"Model\": \"865414-B21\",\n      \"Name\": \"HpeServerPowerSupply\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerPowerSupply.HpeServerPowerSupply\",\n          \"@odata.type\": \"#HpeServerPowerSupply.v2_0_0.HpeServerPowerSupply\",\n          \"AveragePowerOutputWatts\": 90,\n          \"BayNumber\": 2,\n          \"HotplugCapable\": true,\n          \"MaxPowerOutputWatts\": 99,\n          \"Mismatched\": false,\n          \"PowerSupplyStatus\": {\n            \"State\": \"Ok\"\n          },\n          \"iPDUCapable\": false\n        }\n      },\n      \"PowerCapacityWatts\": 800,\n      \"PowerSupplyType\": \"AC\",\n      \"SerialNumber\": \"5WEBP0B8JAQ2KL\",\n      \"SparePartNumber\": \"866730-001\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Redundancy\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Power#Redundancy/0\",\n      \"MaxNumSupported\": 2,\n      \"MemberId\": \"0\",\n      \"MinNumNeeded\": 2,\n      \"Mode\": \"Failover\",\n      \"Name\": \"PowerSupply Redundancy Group 1\",\n      \"RedundancySet\": [\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/0\"\n        },\n        {\n          \"@odata.id\": \"/redfish/v1/Chassis/1/Power#PowerSupplies/1\"\n        }\n      ],\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ]\n}\n{\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_systems.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n  \"@odata.etag\": \"W/\\\"43E302D1\\\"\",\n  \"@odata.id\": \"/redfish/v1/Systems/1/\",\n  \"@odata.type\": \"#ComputerSystem.v1_4_0.ComputerSystem\",\n  \"Id\": \"1\",\n  \"Actions\": {\n    \"#ComputerSystem.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\",\n        \"ForceRestart\",\n        \"Nmi\",\n        \"PushPowerButton\"\n      ],\n      \"target\": \"/redfish/v1/Systems/1/Actions/ComputerSystem.Reset/\"\n    }\n  },\n  \"AssetTag\": \"\",\n  \"Bios\": {\n    \"@odata.id\": \"/redfish/v1/systems/1/bios/\"\n  },\n  \"BiosVersion\": \"U32 v2.10 (05/21/2019)\",\n  \"Boot\": {\n    \"BootSourceOverrideEnabled\": \"Disabled\",\n    \"BootSourceOverrideMode\": \"UEFI\",\n    \"BootSourceOverrideTarget\": \"None\",\n    \"BootSourceOverrideTarget@Redfish.AllowableValues\": [\n      \"None\",\n      \"Cd\",\n      \"Hdd\",\n      \"Usb\",\n      \"SDCard\",\n      \"Utilities\",\n      \"Diags\",\n      \"BiosSetup\",\n      \"Pxe\",\n      \"UefiShell\",\n      \"UefiHttp\",\n      \"UefiTarget\"\n    ],\n    \"UefiTargetBootSourceOverride\": \"None\",\n    \"UefiTargetBootSourceOverride@Redfish.AllowableValues\": [\n      \"HD(1,GPT,0E3A0969-7AFC-4B55-8B24-AEFA09F33D2D,0x800,0x12C000)/\\\\EFI\\\\redhat\\\\shimx64.efi\",\n      \"UsbClass(0xFFFF,0xFFFF,0xFF,0xFF,0xFF)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x0)/Pci(0x14,0x0)/USB(0x13,0x0)\",\n      \"PciRoot(0x3)/Pci(0x0,0x0)/Pci(0x0,0x0)/Scsi(0x0,0x0)\"\n    ]\n  },\n  \"EthernetInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/EthernetInterfaces/\"\n  },\n  \"HostName\": \"tpa-hostname\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/1/\"\n      }\n    ],\n    \"Chassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/1/\"\n      }\n    ]\n  },\n  \"LogServices\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/LogServices/\"\n  },\n  \"Manufacturer\": \"HPE\",\n  \"Memory\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Memory/\"\n  },\n  \"MemoryDomains\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/MemoryDomains/\"\n  },\n  \"MemorySummary\": {\n    \"Status\": {\n      \"HealthRollup\": \"OK\"\n    },\n    \"TotalSystemMemoryGiB\": 384,\n    \"TotalSystemPersistentMemoryGiB\": 0\n  },\n  \"Model\": \"ProLiant DL360 Gen10\",\n  \"Name\": \"Computer System\",\n  \"NetworkInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/NetworkInterfaces/\"\n  },\n  \"Oem\": {\n    \"Hpe\": {\n      \"@odata.context\": \"/redfish/v1/$metadata#HpeComputerSystemExt.HpeComputerSystemExt\",\n      \"@odata.type\": \"#HpeComputerSystemExt.v2_6_1.HpeComputerSystemExt\",\n      \"Actions\": {\n        \"#HpeComputerSystemExt.PowerButton\": {\n          \"PushType@Redfish.AllowableValues\": [\n            \"Press\",\n            \"PressAndHold\"\n          ],\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.PowerButton/\"\n        },\n        \"#HpeComputerSystemExt.SecureSystemErase\": {\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SecureSystemErase/\"\n        },\n        \"#HpeComputerSystemExt.SystemReset\": {\n          \"ResetType@Redfish.AllowableValues\": [\n            \"ColdBoot\",\n            \"AuxCycle\"\n          ],\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SystemReset/\"\n        }\n      },\n      \"AggregateHealthStatus\": {\n        \"AgentlessManagementService\": \"Unavailable\",\n        \"BiosOrHardwareHealth\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"FanRedundancy\": \"Redundant\",\n        \"Fans\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Memory\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Network\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"PowerSupplies\": {\n          \"PowerSuppliesMismatch\": false,\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"PowerSupplyRedundancy\": \"Redundant\",\n        \"Processors\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"SmartStorageBattery\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Storage\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Temperatures\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        }\n      },\n      \"Bios\": {\n        \"Backup\": {\n          \"Date\": \"05/21/2019\",\n          \"Family\": \"U32\",\n          \"VersionString\": \"U32 v2.10 (05/21/2019)\"\n        },\n        \"Current\": {\n          \"Date\": \"05/21/2019\",\n          \"Family\": \"U32\",\n          \"VersionString\": \"U32 v2.10 (05/21/2019)\"\n        },\n        \"UefiClass\": 2\n      },\n      \"CurrentPowerOnTimeSeconds\": 29290,\n      \"DeviceDiscoveryComplete\": {\n        \"AMSDeviceDiscovery\": \"NoAMS\",\n        \"DeviceDiscovery\": \"vMainDeviceDiscoveryComplete\",\n        \"SmartArrayDiscovery\": \"Complete\"\n      },\n      \"ElapsedEraseTimeInMinutes\": 0,\n      \"EndOfPostDelaySeconds\": null,\n      \"EstimatedEraseTimeInMinutes\": 0,\n      \"IntelligentProvisioningAlwaysOn\": true,\n      \"IntelligentProvisioningIndex\": 9,\n      \"IntelligentProvisioningLocation\": \"System Board\",\n      \"IntelligentProvisioningVersion\": \"3.30.213\",\n      \"IsColdBooting\": false,\n      \"Links\": {\n        \"PCIDevices\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/PCIDevices/\"\n        },\n        \"PCISlots\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/PCISlots/\"\n        },\n        \"NetworkAdapters\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/BaseNetworkAdapters/\"\n        },\n        \"SmartStorage\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/SmartStorage/\"\n        },\n        \"USBPorts\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/USBPorts/\"\n        },\n        \"USBDevices\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/USBDevices/\"\n        },\n        \"EthernetInterfaces\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/EthernetInterfaces/\"\n        },\n        \"WorkloadPerformanceAdvisor\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/WorkloadPerformanceAdvisor/\"\n        }\n      },\n      \"PCAPartNumber\": \"847479-002\",\n      \"PCASerialNumber\": \"PWUFL0ARHCF3KR\",\n      \"PostDiscoveryCompleteTimeStamp\": \"2020-02-24T02:43:43Z\",\n      \"PostDiscoveryMode\": null,\n      \"PostMode\": null,\n      \"PostState\": \"FinishedPost\",\n      \"PowerAllocationLimit\": 1600,\n      \"PowerAutoOn\": \"Restore\",\n      \"PowerOnDelay\": \"Minimum\",\n      \"PowerOnMinutes\": 95715,\n      \"PowerRegulatorMode\": \"Max\",\n      \"PowerRegulatorModesSupported\": [\n        \"OSControl\",\n        \"Dynamic\",\n        \"Max\",\n        \"Min\"\n      ],\n      \"ProcessorJitterControl\": {\n        \"ConfiguredFrequencyLimitMHz\": 0,\n        \"Mode\": \"Disabled\"\n      },\n      \"SMBIOS\": {\n        \"extref\": \"/smbios\"\n      },\n      \"ServerFQDN\": \"TPAVCPAR088S4.vici.verizon.com\",\n      \"SmartStorageConfig\": [\n        {\n          \"@odata.id\": \"/redfish/v1/systems/1/smartstorageconfig/\"\n        }\n      ],\n      \"SystemROMAndiLOEraseComponentStatus\": {\n        \"BIOSSettingsEraseStatus\": \"Idle\",\n        \"iLOSettingsEraseStatus\": \"Idle\"\n      },\n      \"SystemROMAndiLOEraseStatus\": \"Idle\",\n      \"SystemUsage\": {\n        \"AvgCPU0Freq\": 0,\n        \"AvgCPU1Freq\": 6,\n        \"CPU0Power\": 50,\n        \"CPU1Power\": 51,\n        \"CPUICUtil\": 0,\n        \"CPUUtil\": 0,\n        \"IOBusUtil\": 0,\n        \"JitterCount\": 35,\n        \"MemoryBusUtil\": 0\n      },\n      \"UserDataEraseComponentStatus\": {},\n      \"UserDataEraseStatus\": \"Idle\",\n      \"VirtualProfile\": \"Inactive\"\n    }\n  },\n  \"PowerState\": \"On\",\n  \"ProcessorSummary\": {\n    \"Count\": 2,\n    \"Model\": \"Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz\",\n    \"Status\": {\n      \"HealthRollup\": \"OK\"\n    }\n  },\n  \"Processors\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Processors/\"\n  },\n  \"SKU\": \"867959-B21\",\n  \"SecureBoot\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/SecureBoot/\"\n  },\n  \"SerialNumber\": \"MXQ93003RB\",\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Storage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Storage/\"\n  },\n  \"SystemType\": \"Physical\",\n  \"TrustedModules\": [\n    {\n      \"FirmwareVersion\": \"73.0\",\n      \"InterfaceType\": \"TPM1_2\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeTrustedModuleExt.HpeTrustedModuleExt\",\n          \"@odata.type\": \"#HpeTrustedModuleExt.v2_0_0.HpeTrustedModuleExt\",\n          \"VendorName\": \"STMicro\"\n        }\n      },\n      \"Status\": {\n        \"State\": \"Disabled\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_systemsinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n  \"@odata.etag\": \"W/\\\"43E302D1\\\"\",\n  \"@odata.id\": \"/redfish/v1/Systems/1/\",\n  \"@odata.type\": \"#ComputerSystem.v1_4_0.ComputerSystem\",\n  \"Id\": \"1\",\n  \"Actions\": {\n    \"#ComputerSystem.Reset\": {\n      \"ResetType@Redfish.AllowableValues\": [\n        \"On\",\n        \"ForceOff\",\n        \"ForceRestart\",\n        \"Nmi\",\n        \"PushPowerButton\"\n      ],\n      \"target\": \"/redfish/v1/Systems/1/Actions/ComputerSystem.Reset/\"\n    }\n  },\n  \"AssetTag\": \"\",\n  \"Bios\": {\n    \"@odata.id\": \"/redfish/v1/systems/1/bios/\"\n  },\n  \"BiosVersion\": \"U32 v2.10 (05/21/2019)\",\n  \"Boot\": {\n    \"BootSourceOverrideEnabled\": \"Disabled\",\n    \"BootSourceOverrideMode\": \"UEFI\",\n    \"BootSourceOverrideTarget\": \"None\",\n    \"BootSourceOverrideTarget@Redfish.AllowableValues\": [\n      \"None\",\n      \"Cd\",\n      \"Hdd\",\n      \"Usb\",\n      \"SDCard\",\n      \"Utilities\",\n      \"Diags\",\n      \"BiosSetup\",\n      \"Pxe\",\n      \"UefiShell\",\n      \"UefiHttp\",\n      \"UefiTarget\"\n    ],\n    \"UefiTargetBootSourceOverride\": \"None\",\n    \"UefiTargetBootSourceOverride@Redfish.AllowableValues\": [\n      \"HD(1,GPT,0E3A0969-7AFC-4B55-8B24-AEFA09F33D2D,0x800,0x12C000)/\\\\EFI\\\\redhat\\\\shimx64.efi\",\n      \"UsbClass(0xFFFF,0xFFFF,0xFF,0xFF,0xFF)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)/MAC(48DF37959430,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)/MAC(8030E0421B1C,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv4(0.0.0.0)/Uri()\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv4(0.0.0.0)\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)/Uri()\",\n      \"PciRoot(0x9)/Pci(0x0,0x0)/Pci(0x0,0x0)/MAC(B88303866AE8,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)\",\n      \"PciRoot(0x0)/Pci(0x14,0x0)/USB(0x13,0x0)\",\n      \"PciRoot(0x3)/Pci(0x0,0x0)/Pci(0x0,0x0)/Scsi(0x0,0x0)\"\n    ]\n  },\n  \"EthernetInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/EthernetInterfaces/\"\n  },\n  \"HostName\": \"tpa-hostname\",\n  \"IndicatorLED\": \"Off\",\n  \"Links\": {\n    \"ManagedBy\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Managers/1/\"\n      }\n    ],\n    \"Chassis\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/1/\"\n      }\n    ]\n  },\n  \"LogServices\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/LogServices/\"\n  },\n  \"Manufacturer\": \"HPE\",\n  \"Memory\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Memory/\"\n  },\n  \"MemoryDomains\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/MemoryDomains/\"\n  },\n  \"MemorySummary\": {\n    \"Status\": {\n      \"HealthRollup\": \"OK\"\n    },\n    \"TotalSystemMemoryGiB\": 384,\n    \"TotalSystemPersistentMemoryGiB\": 0\n  },\n  \"Model\": \"ProLiant DL360 Gen10\",\n  \"Name\": \"Computer System\",\n  \"NetworkInterfaces\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/NetworkInterfaces/\"\n  },\n  \"Oem\": {\n    \"Hpe\": {\n      \"@odata.context\": \"/redfish/v1/$metadata#HpeComputerSystemExt.HpeComputerSystemExt\",\n      \"@odata.type\": \"#HpeComputerSystemExt.v2_6_1.HpeComputerSystemExt\",\n      \"Actions\": {\n        \"#HpeComputerSystemExt.PowerButton\": {\n          \"PushType@Redfish.AllowableValues\": [\n            \"Press\",\n            \"PressAndHold\"\n          ],\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.PowerButton/\"\n        },\n        \"#HpeComputerSystemExt.SecureSystemErase\": {\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SecureSystemErase/\"\n        },\n        \"#HpeComputerSystemExt.SystemReset\": {\n          \"ResetType@Redfish.AllowableValues\": [\n            \"ColdBoot\",\n            \"AuxCycle\"\n          ],\n          \"target\": \"/redfish/v1/Systems/1/Actions/Oem/Hpe/HpeComputerSystemExt.SystemReset/\"\n        }\n      },\n      \"AggregateHealthStatus\": {\n        \"AgentlessManagementService\": \"Unavailable\",\n        \"BiosOrHardwareHealth\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"FanRedundancy\": \"Redundant\",\n        \"Fans\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Memory\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Network\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"PowerSupplies\": {\n          \"PowerSuppliesMismatch\": false,\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"PowerSupplyRedundancy\": \"Redundant\",\n        \"Processors\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"SmartStorageBattery\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Storage\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        },\n        \"Temperatures\": {\n          \"Status\": {\n            \"Health\": \"OK\"\n          }\n        }\n      },\n      \"Bios\": {\n        \"Backup\": {\n          \"Date\": \"05/21/2019\",\n          \"Family\": \"U32\",\n          \"VersionString\": \"U32 v2.10 (05/21/2019)\"\n        },\n        \"Current\": {\n          \"Date\": \"05/21/2019\",\n          \"Family\": \"U32\",\n          \"VersionString\": \"U32 v2.10 (05/21/2019)\"\n        },\n        \"UefiClass\": 2\n      },\n      \"CurrentPowerOnTimeSeconds\": 29290,\n      \"DeviceDiscoveryComplete\": {\n        \"AMSDeviceDiscovery\": \"NoAMS\",\n        \"DeviceDiscovery\": \"vMainDeviceDiscoveryComplete\",\n        \"SmartArrayDiscovery\": \"Complete\"\n      },\n      \"ElapsedEraseTimeInMinutes\": 0,\n      \"EndOfPostDelaySeconds\": null,\n      \"EstimatedEraseTimeInMinutes\": 0,\n      \"IntelligentProvisioningAlwaysOn\": true,\n      \"IntelligentProvisioningIndex\": 9,\n      \"IntelligentProvisioningLocation\": \"System Board\",\n      \"IntelligentProvisioningVersion\": \"3.30.213\",\n      \"IsColdBooting\": false,\n      \"Links\": {\n        \"PCIDevices\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/PCIDevices/\"\n        },\n        \"PCISlots\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/PCISlots/\"\n        },\n        \"NetworkAdapters\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/BaseNetworkAdapters/\"\n        },\n        \"SmartStorage\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/SmartStorage/\"\n        },\n        \"USBPorts\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/USBPorts/\"\n        },\n        \"USBDevices\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/USBDevices/\"\n        },\n        \"EthernetInterfaces\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/EthernetInterfaces/\"\n        },\n        \"WorkloadPerformanceAdvisor\": {\n          \"@odata.id\": \"/redfish/v1/Systems/1/WorkloadPerformanceAdvisor/\"\n        }\n      },\n      \"PCAPartNumber\": \"847479-002\",\n      \"PCASerialNumber\": \"PWUFL0ARHCF3KR\",\n      \"PostDiscoveryCompleteTimeStamp\": \"2020-02-24T02:43:43Z\",\n      \"PostDiscoveryMode\": null,\n      \"PostMode\": null,\n      \"PostState\": \"FinishedPost\",\n      \"PowerAllocationLimit\": 1600,\n      \"PowerAutoOn\": \"Restore\",\n      \"PowerOnDelay\": \"Minimum\",\n      \"PowerOnMinutes\": 95715,\n      \"PowerRegulatorMode\": \"Max\",\n      \"PowerRegulatorModesSupported\": [\n        \"OSControl\",\n        \"Dynamic\",\n        \"Max\",\n        \"Min\"\n      ],\n      \"ProcessorJitterControl\": {\n        \"ConfiguredFrequencyLimitMHz\": 0,\n        \"Mode\": \"Disabled\"\n      },\n      \"SMBIOS\": {\n        \"extref\": \"/smbios\"\n      },\n      \"ServerFQDN\": \"TPAVCPAR088S4.vici.verizon.com\",\n      \"SmartStorageConfig\": [\n        {\n          \"@odata.id\": \"/redfish/v1/systems/1/smartstorageconfig/\"\n        }\n      ],\n      \"SystemROMAndiLOEraseComponentStatus\": {\n        \"BIOSSettingsEraseStatus\": \"Idle\",\n        \"iLOSettingsEraseStatus\": \"Idle\"\n      },\n      \"SystemROMAndiLOEraseStatus\": \"Idle\",\n      \"SystemUsage\": {\n        \"AvgCPU0Freq\": 0,\n        \"AvgCPU1Freq\": 6,\n        \"CPU0Power\": 50,\n        \"CPU1Power\": 51,\n        \"CPUICUtil\": 0,\n        \"CPUUtil\": 0,\n        \"IOBusUtil\": 0,\n        \"JitterCount\": 35,\n        \"MemoryBusUtil\": 0\n      },\n      \"UserDataEraseComponentStatus\": {},\n      \"UserDataEraseStatus\": \"Idle\",\n      \"VirtualProfile\": \"Inactive\"\n    }\n  },\n  \"PowerState\": \"On\",\n  \"ProcessorSummary\": {\n    \"Count\": 2,\n    \"Model\": \"Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz\",\n    \"Status\": {\n      \"HealthRollup\": \"OK\"\n    }\n  },\n  \"Processors\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Processors/\"\n  },\n  \"SKU\": \"867959-B21\",\n  \"SecureBoot\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/SecureBoot/\"\n  },\n  \"SerialNumber\": \"MXQ93003RB\",\n  \"Status\": {\n    \"Health\": \"OK\",\n    \"State\": \"Enabled\"\n  },\n  \"Storage\": {\n    \"@odata.id\": \"/redfish/v1/Systems/1/Storage/\"\n  },\n  \"SystemType\": \"Physical\",\n  \"TrustedModules\": [\n    {\n      \"FirmwareVersion\": \"73.0\",\n      \"InterfaceType\": \"TPM1_2\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeTrustedModuleExt.HpeTrustedModuleExt\",\n          \"@odata.type\": \"#HpeTrustedModuleExt.v2_0_0.HpeTrustedModuleExt\",\n          \"VendorName\": \"STMicro\"\n        }\n      },\n      \"Status\": {\n        \"State\": \"Disabled\"\n      }\n    }\n  ]\n}\n{\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_thermal.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n  \"@odata.etag\": \"W/\\\"14E8662D\\\"\",\n  \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal\",\n  \"@odata.type\": \"#Thermal.v1_1_0.Thermal\",\n  \"Id\": \"Thermal\",\n  \"Fans\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/0\",\n      \"MemberId\": \"0\",\n      \"Name\": \"Fan 1\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/1\",\n      \"MemberId\": \"1\",\n      \"Name\": \"Fan 2\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/2\",\n      \"MemberId\": \"2\",\n      \"Name\": \"Fan 3\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Name\": \"Thermal\",\n  \"Temperatures\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/0\",\n      \"MemberId\": \"0\",\n      \"Name\": \"01-Inlet Ambient\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n          \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n          \"LocationXmm\": 15,\n          \"LocationYmm\": 0\n        }\n      },\n      \"PhysicalContext\": \"Intake\",\n      \"ReadingCelsius\": 19,\n      \"SensorNumber\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 42,\n      \"UpperThresholdFatal\": 47\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/42\",\n      \"MemberId\": \"42\",\n      \"Name\": \"44-P/S 2 Zone\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n          \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n          \"LocationXmm\": 4,\n          \"LocationYmm\": 7\n        }\n      },\n      \"PhysicalContext\": \"PowerSupply\",\n      \"ReadingCelsius\": 34,\n      \"SensorNumber\": 43,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 75,\n      \"UpperThresholdFatal\": 80\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_thermal_ilo4.json",
    "content": "{\n    \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n    \"@odata.etag\": \"W/\\\"14E8662D\\\"\",\n    \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal\",\n    \"@odata.type\": \"#Thermal.v1_1_0.Thermal\",\n    \"Id\": \"Thermal\",\n    \"Fans\": [\n        {\n            \"CurrentReading\": 17,\n            \"FanName\": \"Fan 1\",\n            \"Oem\": {\n                \"Hp\": {\n                    \"@odata.type\": \"#HpServerFan.1.0.0.HpServerFan\",\n                    \"Location\": \"System\",\n                    \"Type\": \"HpServerFan.1.0.0\"\n                }\n            },\n            \"Status\": {\n                \"Health\": \"OK\",\n                \"State\": \"Enabled\"\n            },\n            \"Units\": \"Percent\"\n        }\n    ],\n    \"Name\": \"Thermal\",\n    \"Temperatures\": [\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/0\",\n        \"MemberId\": \"0\",\n        \"Name\": \"01-Inlet Ambient\",\n        \"Oem\": {\n          \"Hpe\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n            \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n            \"LocationXmm\": 15,\n            \"LocationYmm\": 0\n          }\n        },\n        \"PhysicalContext\": \"Intake\",\n        \"ReadingCelsius\": 19,\n        \"SensorNumber\": 1,\n        \"Status\": {\n          \"Health\": \"OK\",\n          \"State\": \"Enabled\"\n        },\n        \"UpperThresholdCritical\": 42,\n        \"UpperThresholdFatal\": 47\n      },\n      {\n        \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/42\",\n        \"MemberId\": \"42\",\n        \"Name\": \"44-P/S 2 Zone\",\n        \"Oem\": {\n          \"Hpe\": {\n            \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n            \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n            \"LocationXmm\": 4,\n            \"LocationYmm\": 7\n          }\n        },\n        \"PhysicalContext\": \"PowerSupply\",\n        \"ReadingCelsius\": 34,\n        \"SensorNumber\": 43,\n        \"Status\": {\n          \"Health\": \"OK\",\n          \"State\": \"Enabled\"\n        },\n        \"UpperThresholdCritical\": 75,\n        \"UpperThresholdFatal\": 80\n      }\n    ]\n  }\n"
  },
  {
    "path": "plugins/inputs/redfish/testdata/hp_thermalinvalid.json",
    "content": "{\n  \"@odata.context\": \"/redfish/v1/$metadata#Thermal.Thermal\",\n  \"@odata.etag\": \"W/\\\"14E8662D\\\"\",\n  \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal\",\n  \"@odata.type\": \"#Thermal.v1_1_0.Thermal\",\n  \"Id\": \"Thermal\",\n  \"Fans\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/0\",\n      \"MemberId\": \"0\",\n      \"Name\": \"Fan 1\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/1\",\n      \"MemberId\": \"1\",\n      \"Name\": \"Fan 2\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Fans/2\",\n      \"MemberId\": \"2\",\n      \"Name\": \"Fan 3\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeServerFan.HpeServerFan\",\n          \"@odata.type\": \"#HpeServerFan.v2_0_0.HpeServerFan\",\n          \"HotPluggable\": true,\n          \"Location\": \"System\",\n          \"Redundant\": true\n        }\n      },\n      \"Reading\": 23,\n      \"ReadingUnits\": \"Percent\",\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      }\n    }\n  ],\n  \"Name\": \"Thermal\",\n  \"Temperatures\": [\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/0\",\n      \"MemberId\": \"0\",\n      \"Name\": \"01-Inlet Ambient\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n          \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n          \"LocationXmm\": 15,\n          \"LocationYmm\": 0\n        }\n      },\n      \"PhysicalContext\": \"Intake\",\n      \"ReadingCelsius\": 19,\n      \"SensorNumber\": 1,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 42,\n      \"UpperThresholdFatal\": 47\n    },\n    {\n      \"@odata.id\": \"/redfish/v1/Chassis/1/Thermal#Temperatures/42\",\n      \"MemberId\": \"42\",\n      \"Name\": \"44-P/S 2 Zone\",\n      \"Oem\": {\n        \"Hpe\": {\n          \"@odata.context\": \"/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors\",\n          \"@odata.type\": \"#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors\",\n          \"LocationXmm\": 4,\n          \"LocationYmm\": 7\n        }\n      },\n      \"PhysicalContext\": \"PowerSupply\",\n      \"ReadingCelsius\": 34,\n      \"SensorNumber\": 43,\n      \"Status\": {\n        \"Health\": \"OK\",\n        \"State\": \"Enabled\"\n      },\n      \"UpperThresholdCritical\": 75,\n      \"UpperThresholdFatal\": 80\n    }\n  ]\n}\n{\n"
  },
  {
    "path": "plugins/inputs/redis/README.md",
    "content": "# Redis Input Plugin\n\nThis plugin gathers metrics from [Redis][redis] servers.\n\n⭐ Telegraf v0.1.1\n🏷️ server\n💻 all\n\n[redis]: https://redis.io/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many redis servers\n[[inputs.redis]]\n  ## specify servers via a url matching:\n  ##  [protocol://][username:password]@address[:port]\n  ##  e.g.\n  ##    tcp://localhost:6379\n  ##    tcp://username:password@192.168.99.100\n  ##    unix:///var/run/redis.sock\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no port is specified, 6379 is used\n  servers = [\"tcp://localhost:6379\"]\n\n  ## Optional. Specify redis commands to retrieve values\n  # [[inputs.redis.commands]]\n  #   # The command to run where each argument is a separate element\n  #   command = [\"get\", \"sample-key\"]\n  #   # The field to store the result in\n  #   field = \"sample-key-value\"\n  #   # The type of the result\n  #   # Can be \"string\", \"integer\", or \"float\"\n  #   type = \"string\"\n\n  ## Specify username and password for ACL auth (Redis 6.0+). You can add this\n  ## to the server URI above or specify it here. The values here take\n  ## precedence.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  ## Check tls/config.go ClientConfig for more options\n  # tls_enable = true\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n```\n\n## Metrics\n\nThe plugin gathers the results of the [INFO](https://redis.io/commands/info)\nredis command.  There are two separate measurements: _redis_ and\n_redis\\_keyspace_, the latter is used for gathering database related statistics.\n\nAdditionally the plugin also calculates the hit/miss ratio (keyspace\\_hitrate)\nand the elapsed time since the last rdb save (rdb\\_last\\_save\\_time\\_elapsed).\n\n- redis\n  - keyspace_hitrate(float, number)\n  - rdb_last_save_time_elapsed(int, seconds)\n\n    **Server**\n  - uptime(int, seconds)\n  - lru_clock(int, number)\n  - redis_version(string)\n\n    **Clients**\n  - clients(int, number)\n  - client_longest_output_list(int, number)\n  - client_biggest_input_buf(int, number)\n  - blocked_clients(int, number)\n\n    **Memory**\n  - used_memory(int, bytes)\n  - used_memory_rss(int, bytes)\n  - used_memory_peak(int, bytes)\n  - total_system_memory(int, bytes)\n  - used_memory_lua(int, bytes)\n  - maxmemory(int, bytes)\n  - maxmemory_policy(string)\n  - mem_fragmentation_ratio(float, number)\n\n    **Persistence**\n  - loading(int,flag)\n  - rdb_changes_since_last_save(int, number)\n  - rdb_bgsave_in_progress(int, flag)\n  - rdb_last_save_time(int, seconds)\n  - rdb_last_bgsave_status(string)\n  - rdb_last_bgsave_time_sec(int, seconds)\n  - rdb_current_bgsave_time_sec(int, seconds)\n  - aof_enabled(int, flag)\n  - aof_rewrite_in_progress(int, flag)\n  - aof_rewrite_scheduled(int, flag)\n  - aof_last_rewrite_time_sec(int, seconds)\n  - aof_current_rewrite_time_sec(int, seconds)\n  - aof_last_bgrewrite_status(string)\n  - aof_last_write_status(string)\n\n    **Stats**\n  - total_connections_received(int, number)\n  - total_commands_processed(int, number)\n  - instantaneous_ops_per_sec(int, number)\n  - total_net_input_bytes(int, bytes)\n  - total_net_output_bytes(int, bytes)\n  - instantaneous_input_kbps(float, KB/sec)\n  - instantaneous_output_kbps(float, KB/sec)\n  - rejected_connections(int, number)\n  - sync_full(int, number)\n  - sync_partial_ok(int, number)\n  - sync_partial_err(int, number)\n  - expired_keys(int, number)\n  - evicted_keys(int, number)\n  - keyspace_hits(int, number)\n  - keyspace_misses(int, number)\n  - pubsub_channels(int, number)\n  - pubsub_patterns(int, number)\n  - latest_fork_usec(int, microseconds)\n  - migrate_cached_sockets(int, number)\n\n    **Replication**\n  - connected_slaves(int, number)\n  - master_link_down_since_seconds(int, number)\n  - master_link_status(string)\n  - master_repl_offset(int, number)\n  - second_repl_offset(int, number)\n  - repl_backlog_active(int, number)\n  - repl_backlog_size(int, bytes)\n  - repl_backlog_first_byte_offset(int, number)\n  - repl_backlog_histlen(int, bytes)\n\n    **CPU**\n  - used_cpu_sys(float, number)\n  - used_cpu_user(float, number)\n  - used_cpu_sys_children(float, number)\n  - used_cpu_user_children(float, number)\n\n    **Cluster**\n  - cluster_enabled(int, flag)\n\n- redis_keyspace\n  - keys(int, number)\n  - expires(int, number)\n  - avg_ttl(int, number)\n\n- redis_cmdstat\n    Every Redis used command could have the following fields:\n  - calls(int, number)\n  - failed_calls(int, number)\n  - rejected_calls(int, number)\n  - usec(int, mircoseconds)\n  - usec_per_call(float, microseconds)\n\n- redis_latency_percentiles_usec\n  - fields:\n    - p50(float, microseconds)\n    - p99(float, microseconds)\n    - p99.9(float, microseconds)\n\n- redis_replication\n  - tags:\n    - replication_role\n    - replica_ip\n    - replica_port\n    - state (either \"online\", \"wait_bgsave\", or \"send_bulk\")\n\n  - fields:\n    - lag(int, number)\n    - offset(int, number)\n\n- redis_errorstat\n  - tags:\n    - err\n  - fields:\n    - total (int, number)\n\nAll measurements have the following tags:\n\n- port\n- server\n- replication_role\n\nThe `redis_keyspace` measurement has an additional `database` tag.\n\nThe `redis_cmdstat` and `redis_latency_percentiles_usec` measurements have an\nadditional `command` tag.\n\n## Example Output\n\nThe following configuration\n\n```toml\n[[inputs.redis]]\n  ## specify servers via a url matching:\n  ##  [protocol://][:password]@address[:port]\n  ##  e.g.\n  ##    tcp://localhost:6379\n  ##    tcp://:password@192.168.99.100\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no port is specified, 6379 is used\n  servers = [\"tcp://localhost:6379\"]\n```\n\nproduces these metrics:\n\n```text\nredis,server=localhost,port=6379,replication_role=master,host=host keyspace_hitrate=1,clients=2i,blocked_clients=0i,instantaneous_input_kbps=0,sync_full=0i,pubsub_channels=0i,pubsub_patterns=0i,total_net_output_bytes=6659253i,used_memory=842448i,total_system_memory=8351916032i,aof_current_rewrite_time_sec=-1i,rdb_changes_since_last_save=0i,sync_partial_err=0i,latest_fork_usec=508i,instantaneous_output_kbps=0,expired_keys=0i,used_memory_peak=843416i,aof_rewrite_in_progress=0i,aof_last_bgrewrite_status=\"ok\",migrate_cached_sockets=0i,connected_slaves=0i,maxmemory_policy=\"noeviction\",aof_rewrite_scheduled=0i,total_net_input_bytes=3125i,used_memory_rss=9564160i,repl_backlog_histlen=0i,rdb_last_bgsave_status=\"ok\",aof_last_rewrite_time_sec=-1i,keyspace_misses=0i,client_biggest_input_buf=5i,used_cpu_user=1.33,maxmemory=0i,rdb_current_bgsave_time_sec=-1i,total_commands_processed=271i,repl_backlog_size=1048576i,used_cpu_sys=3,uptime=2822i,lru_clock=16706281i,used_memory_lua=37888i,rejected_connections=0i,sync_partial_ok=0i,evicted_keys=0i,rdb_last_save_time_elapsed=1922i,rdb_last_save_time=1493099368i,instantaneous_ops_per_sec=0i,used_cpu_user_children=0,client_longest_output_list=0i,master_repl_offset=0i,repl_backlog_active=0i,keyspace_hits=2i,used_cpu_sys_children=0,cluster_enabled=0i,rdb_last_bgsave_time_sec=0i,aof_last_write_status=\"ok\",total_connections_received=263i,aof_enabled=0i,repl_backlog_first_byte_offset=0i,mem_fragmentation_ratio=11.35,loading=0i,rdb_bgsave_in_progress=0i 1493101290000000000\nredis_keyspace,database=db1,host=host,server=localhost,port=6379,replication_role=master keys=1i,expires=0i,avg_ttl=0i 1493101350000000000\nredis_cmdstat,command=publish,host=host,port=6379,replication_role=master,server=localhost calls=569514i,failed_calls=0i,rejected_calls=0i,usec=9916334i,usec_per_call=17.41 1559227136000000000\nredis_latency_percentiles_usec,command=zadd,host=host,port=6379,replication_role=master,server=localhost p50=9.023,p99=28.031,p99.9=43.007 1559227136000000000\nredis_errorstat,err=MOVED,host=host,port=6379,replication_role=master,server=localhost total=4284 1691119309000000000\n```\n"
  },
  {
    "path": "plugins/inputs/redis/redis.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage redis\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-redis/redis/v8\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\treplicationSlaveMetricPrefix = regexp.MustCompile(`^slave\\d+`)\n\ttracking                     = map[string]string{\n\t\t\"uptime_in_seconds\": \"uptime\",\n\t\t\"connected_clients\": \"clients\",\n\t\t\"role\":              \"replication_role\",\n\t}\n)\n\ntype Redis struct {\n\tCommands []*redisCommand `toml:\"commands\"`\n\tServers  []string        `toml:\"servers\"`\n\tUsername string          `toml:\"username\"`\n\tPassword string          `toml:\"password\"`\n\n\ttls.ClientConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tclients   []client\n\tconnected bool\n}\n\ntype redisCommand struct {\n\tCommand []interface{} `toml:\"command\"`\n\tField   string        `toml:\"field\"`\n\tType    string        `toml:\"type\"`\n}\n\ntype redisClient struct {\n\tclient *redis.Client\n\ttags   map[string]string\n}\n\n// redisFieldTypes defines the types expected for each of the fields redis reports on\ntype redisFieldTypes struct {\n\tActiveDefragHits            int64   `json:\"active_defrag_hits\"`\n\tActiveDefragKeyHits         int64   `json:\"active_defrag_key_hits\"`\n\tActiveDefragKeyMisses       int64   `json:\"active_defrag_key_misses\"`\n\tActiveDefragMisses          int64   `json:\"active_defrag_misses\"`\n\tActiveDefragRunning         int64   `json:\"active_defrag_running\"`\n\tAllocatorActive             int64   `json:\"allocator_active\"`\n\tAllocatorAllocated          int64   `json:\"allocator_allocated\"`\n\tAllocatorFragBytes          float64 `json:\"allocator_frag_bytes\"` // for historical reasons this was left as float although redis reports it as an int\n\tAllocatorFragRatio          float64 `json:\"allocator_frag_ratio\"`\n\tAllocatorResident           int64   `json:\"allocator_resident\"`\n\tAllocatorRssBytes           int64   `json:\"allocator_rss_bytes\"`\n\tAllocatorRssRatio           float64 `json:\"allocator_rss_ratio\"`\n\tAofCurrentRewriteTimeSec    int64   `json:\"aof_current_rewrite_time_sec\"`\n\tAofEnabled                  int64   `json:\"aof_enabled\"`\n\tAofLastBgrewriteStatus      string  `json:\"aof_last_bgrewrite_status\"`\n\tAofLastCowSize              int64   `json:\"aof_last_cow_size\"`\n\tAofLastRewriteTimeSec       int64   `json:\"aof_last_rewrite_time_sec\"`\n\tAofLastWriteStatus          string  `json:\"aof_last_write_status\"`\n\tAofRewriteInProgress        int64   `json:\"aof_rewrite_in_progress\"`\n\tAofRewriteScheduled         int64   `json:\"aof_rewrite_scheduled\"`\n\tBlockedClients              int64   `json:\"blocked_clients\"`\n\tClientRecentMaxInputBuffer  int64   `json:\"client_recent_max_input_buffer\"`\n\tClientRecentMaxOutputBuffer int64   `json:\"client_recent_max_output_buffer\"`\n\tClients                     int64   `json:\"clients\"`\n\tClientsInTimeoutTable       int64   `json:\"clients_in_timeout_table\"`\n\tClusterEnabled              int64   `json:\"cluster_enabled\"`\n\tConnectedSlaves             int64   `json:\"connected_slaves\"`\n\tEvictedKeys                 int64   `json:\"evicted_keys\"`\n\tExpireCycleCPUMilliseconds  int64   `json:\"expire_cycle_cpu_milliseconds\"`\n\tExpiredKeys                 int64   `json:\"expired_keys\"`\n\tExpiredStalePerc            float64 `json:\"expired_stale_perc\"`\n\tExpiredTimeCapReachedCount  int64   `json:\"expired_time_cap_reached_count\"`\n\tInstantaneousInputKbps      float64 `json:\"instantaneous_input_kbps\"`\n\tInstantaneousOpsPerSec      int64   `json:\"instantaneous_ops_per_sec\"`\n\tInstantaneousOutputKbps     float64 `json:\"instantaneous_output_kbps\"`\n\tIoThreadedReadsProcessed    int64   `json:\"io_threaded_reads_processed\"`\n\tIoThreadedWritesProcessed   int64   `json:\"io_threaded_writes_processed\"`\n\tKeyspaceHits                int64   `json:\"keyspace_hits\"`\n\tKeyspaceMisses              int64   `json:\"keyspace_misses\"`\n\tLatestForkUsec              int64   `json:\"latest_fork_usec\"`\n\tLazyfreePendingObjects      int64   `json:\"lazyfree_pending_objects\"`\n\tLoading                     int64   `json:\"loading\"`\n\tLruClock                    int64   `json:\"lru_clock\"`\n\tMasterReplOffset            int64   `json:\"master_repl_offset\"`\n\tMaxMemory                   int64   `json:\"maxmemory\"`\n\tMaxMemoryPolicy             string  `json:\"maxmemory_policy\"`\n\tMemAofBuffer                int64   `json:\"mem_aof_buffer\"`\n\tMemClientsNormal            int64   `json:\"mem_clients_normal\"`\n\tMemClientsSlaves            int64   `json:\"mem_clients_slaves\"`\n\tMemFragmentationBytes       int64   `json:\"mem_fragmentation_bytes\"`\n\tMemFragmentationRatio       float64 `json:\"mem_fragmentation_ratio\"`\n\tMemNotCountedForEvict       int64   `json:\"mem_not_counted_for_evict\"`\n\tMemReplicationBacklog       int64   `json:\"mem_replication_backlog\"`\n\tMigrateCachedSockets        int64   `json:\"migrate_cached_sockets\"`\n\tModuleForkInProgress        int64   `json:\"module_fork_in_progress\"`\n\tModuleForkLastCowSize       int64   `json:\"module_fork_last_cow_size\"`\n\tNumberOfCachedScripts       int64   `json:\"number_of_cached_scripts\"`\n\tPubsubChannels              int64   `json:\"pubsub_channels\"`\n\tPubsubPatterns              int64   `json:\"pubsub_patterns\"`\n\tRdbBgsaveInProgress         int64   `json:\"rdb_bgsave_in_progress\"`\n\tRdbChangesSinceLastSave     int64   `json:\"rdb_changes_since_last_save\"`\n\tRdbCurrentBgsaveTimeSec     int64   `json:\"rdb_current_bgsave_time_sec\"`\n\tRdbLastBgsaveStatus         string  `json:\"rdb_last_bgsave_status\"`\n\tRdbLastBgsaveTimeSec        int64   `json:\"rdb_last_bgsave_time_sec\"`\n\tRdbLastCowSize              int64   `json:\"rdb_last_cow_size\"`\n\tRdbLastSaveTime             int64   `json:\"rdb_last_save_time\"`\n\tRdbLastSaveTimeElapsed      int64   `json:\"rdb_last_save_time_elapsed\"`\n\tRedisVersion                string  `json:\"redis_version\"`\n\tRejectedConnections         int64   `json:\"rejected_connections\"`\n\tReplBacklogActive           int64   `json:\"repl_backlog_active\"`\n\tReplBacklogFirstByteOffset  int64   `json:\"repl_backlog_first_byte_offset\"`\n\tReplBacklogHistlen          int64   `json:\"repl_backlog_histlen\"`\n\tReplBacklogSize             int64   `json:\"repl_backlog_size\"`\n\tRssOverheadBytes            int64   `json:\"rss_overhead_bytes\"`\n\tRssOverheadRatio            float64 `json:\"rss_overhead_ratio\"`\n\tSecondReplOffset            int64   `json:\"second_repl_offset\"`\n\tSlaveExpiresTrackedKeys     int64   `json:\"slave_expires_tracked_keys\"`\n\tSyncFull                    int64   `json:\"sync_full\"`\n\tSyncPartialErr              int64   `json:\"sync_partial_err\"`\n\tSyncPartialOk               int64   `json:\"sync_partial_ok\"`\n\tTotalCommandsProcessed      int64   `json:\"total_commands_processed\"`\n\tTotalConnectionsReceived    int64   `json:\"total_connections_received\"`\n\tTotalNetInputBytes          int64   `json:\"total_net_input_bytes\"`\n\tTotalNetOutputBytes         int64   `json:\"total_net_output_bytes\"`\n\tTotalReadsProcessed         int64   `json:\"total_reads_processed\"`\n\tTotalSystemMemory           int64   `json:\"total_system_memory\"`\n\tTotalWritesProcessed        int64   `json:\"total_writes_processed\"`\n\tTrackingClients             int64   `json:\"tracking_clients\"`\n\tTrackingTotalItems          int64   `json:\"tracking_total_items\"`\n\tTrackingTotalKeys           int64   `json:\"tracking_total_keys\"`\n\tTrackingTotalPrefixes       int64   `json:\"tracking_total_prefixes\"`\n\tUnexpectedErrorReplies      int64   `json:\"unexpected_error_replies\"`\n\tUptime                      int64   `json:\"uptime\"`\n\tUsedCPUSys                  float64 `json:\"used_cpu_sys\"`\n\tUsedCPUSysChildren          float64 `json:\"used_cpu_sys_children\"`\n\tUsedCPUUser                 float64 `json:\"used_cpu_user\"`\n\tUsedCPUUserChildren         float64 `json:\"used_cpu_user_children\"`\n\tUsedMemory                  int64   `json:\"used_memory\"`\n\tUsedMemoryDataset           int64   `json:\"used_memory_dataset\"`\n\tUsedMemoryDatasetPerc       float64 `json:\"used_memory_dataset_perc\"`\n\tUsedMemoryLua               int64   `json:\"used_memory_lua\"`\n\tUsedMemoryOverhead          int64   `json:\"used_memory_overhead\"`\n\tUsedMemoryPeak              int64   `json:\"used_memory_peak\"`\n\tUsedMemoryPeakPerc          float64 `json:\"used_memory_peak_perc\"`\n\tUsedMemoryRss               int64   `json:\"used_memory_rss\"`\n\tUsedMemoryScripts           int64   `json:\"used_memory_scripts\"`\n\tUsedMemoryStartup           int64   `json:\"used_memory_startup\"`\n}\n\ntype client interface {\n\tdo(returnType string, args ...interface{}) (interface{}, error)\n\tinfo() *redis.StringCmd\n\tbaseTags() map[string]string\n\tclose() error\n}\n\nfunc (*Redis) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Redis) Init() error {\n\tfor _, command := range r.Commands {\n\t\tif command.Type != \"string\" && command.Type != \"integer\" && command.Type != \"float\" {\n\t\t\treturn fmt.Errorf(`unknown result type: expected one of \"string\", \"integer\", \"float\"; got %q`, command.Type)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (*Redis) Start(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (r *Redis) Gather(acc telegraf.Accumulator) error {\n\tif !r.connected {\n\t\terr := r.connect()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\n\tfor _, cl := range r.clients {\n\t\twg.Add(1)\n\t\tgo func(client client) {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(gatherServer(client, acc))\n\t\t\tacc.AddError(r.gatherCommandValues(client, acc))\n\t\t}(cl)\n\t}\n\n\twg.Wait()\n\treturn nil\n}\n\n// Stop close the client through ServiceInput interface Start/Stop methods impl.\nfunc (r *Redis) Stop() {\n\tfor _, c := range r.clients {\n\t\terr := c.close()\n\t\tif err != nil {\n\t\t\tr.Log.Errorf(\"error closing client: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (r *Redis) connect() error {\n\tif r.connected {\n\t\treturn nil\n\t}\n\n\tif len(r.Servers) == 0 {\n\t\tr.Servers = []string{\"tcp://localhost:6379\"}\n\t}\n\n\tr.clients = make([]client, 0, len(r.Servers))\n\tfor _, serv := range r.Servers {\n\t\tif !strings.HasPrefix(serv, \"tcp://\") && !strings.HasPrefix(serv, \"unix://\") {\n\t\t\tr.Log.Warn(\"Server URL found without scheme; please update your configuration file\")\n\t\t\tserv = \"tcp://\" + serv\n\t\t}\n\n\t\tu, err := url.Parse(serv)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse to address %q: %w\", serv, err)\n\t\t}\n\n\t\tusername := \"\"\n\t\tpassword := \"\"\n\t\tif u.User != nil {\n\t\t\tusername = u.User.Username()\n\t\t\tpw, ok := u.User.Password()\n\t\t\tif ok {\n\t\t\t\tpassword = pw\n\t\t\t}\n\t\t}\n\t\tif len(r.Username) > 0 {\n\t\t\tusername = r.Username\n\t\t}\n\t\tif len(r.Password) > 0 {\n\t\t\tpassword = r.Password\n\t\t}\n\n\t\tvar address string\n\t\tif u.Scheme == \"unix\" {\n\t\t\taddress = u.Path\n\t\t} else {\n\t\t\taddress = u.Host\n\t\t}\n\n\t\ttlsConfig, err := r.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tclient := redis.NewClient(\n\t\t\t&redis.Options{\n\t\t\t\tAddr:      address,\n\t\t\t\tUsername:  username,\n\t\t\t\tPassword:  password,\n\t\t\t\tNetwork:   u.Scheme,\n\t\t\t\tPoolSize:  1,\n\t\t\t\tTLSConfig: tlsConfig,\n\t\t\t},\n\t\t)\n\n\t\ttags := make(map[string]string, 2)\n\t\tif u.Scheme == \"unix\" {\n\t\t\ttags[\"socket\"] = u.Path\n\t\t} else {\n\t\t\ttags[\"server\"] = u.Hostname()\n\t\t\ttags[\"port\"] = u.Port()\n\t\t}\n\n\t\tr.clients = append(r.clients, &redisClient{\n\t\t\tclient: client,\n\t\t\ttags:   tags,\n\t\t})\n\t}\n\n\tr.connected = true\n\treturn nil\n}\n\nfunc (r *Redis) gatherCommandValues(client client, acc telegraf.Accumulator) error {\n\tfields := make(map[string]interface{})\n\tfor _, command := range r.Commands {\n\t\tval, err := client.do(command.Type, command.Command...)\n\t\tif err != nil {\n\t\t\tif strings.Contains(err.Error(), \"unexpected type=\") {\n\t\t\t\treturn fmt.Errorf(\"could not get command result: %w\", err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tfields[command.Field] = val\n\t}\n\n\tacc.AddFields(\"redis_commands\", fields, client.baseTags())\n\n\treturn nil\n}\n\nfunc (r *redisClient) do(returnType string, args ...interface{}) (interface{}, error) {\n\trawVal := r.client.Do(context.Background(), args...)\n\n\tswitch returnType {\n\tcase \"integer\":\n\t\treturn rawVal.Int64()\n\tcase \"string\":\n\t\treturn rawVal.Text()\n\tcase \"float\":\n\t\treturn rawVal.Float64()\n\tdefault:\n\t\treturn rawVal.Text()\n\t}\n}\n\nfunc (r *redisClient) info() *redis.StringCmd {\n\treturn r.client.Info(context.Background(), \"ALL\")\n}\n\nfunc (r *redisClient) baseTags() map[string]string {\n\ttags := make(map[string]string)\n\tfor k, v := range r.tags {\n\t\ttags[k] = v\n\t}\n\treturn tags\n}\n\nfunc (r *redisClient) close() error {\n\treturn r.client.Close()\n}\n\nfunc gatherServer(client client, acc telegraf.Accumulator) error {\n\tinfo, err := client.info().Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trdr := strings.NewReader(info)\n\treturn gatherInfoOutput(rdr, acc, client.baseTags())\n}\n\nfunc gatherInfoOutput(rdr io.Reader, acc telegraf.Accumulator, tags map[string]string) error {\n\tvar section string\n\tvar keyspaceHits, keyspaceMisses int64\n\n\tscanner := bufio.NewScanner(rdr)\n\tfields := make(map[string]interface{})\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif len(line) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif line[0] == '#' {\n\t\t\tif len(line) > 2 {\n\t\t\t\tsection = line[2:]\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tparts := strings.SplitN(line, \":\", 2)\n\t\tif len(parts) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tname := parts[0]\n\n\t\tif section == \"Server\" {\n\t\t\tif name != \"lru_clock\" && name != \"uptime_in_seconds\" && name != \"redis_version\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif strings.HasPrefix(name, \"master_replid\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tif name == \"mem_allocator\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasSuffix(name, \"_human\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tmetric, ok := tracking[name]\n\t\tif !ok {\n\t\t\tif section == \"Keyspace\" {\n\t\t\t\tkline := strings.TrimSpace(parts[1])\n\t\t\t\tgatherKeyspaceLine(name, kline, acc, tags)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif section == \"Commandstats\" {\n\t\t\t\tkline := strings.TrimSpace(parts[1])\n\t\t\t\tgatherCommandStateLine(name, kline, acc, tags)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif section == \"Latencystats\" {\n\t\t\t\tkline := strings.TrimSpace(parts[1])\n\t\t\t\tgatherLatencyStatsLine(name, kline, acc, tags)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif section == \"Replication\" && replicationSlaveMetricPrefix.MatchString(name) {\n\t\t\t\tkline := strings.TrimSpace(parts[1])\n\t\t\t\tgatherReplicationLine(name, kline, acc, tags)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif section == \"Errorstats\" {\n\t\t\t\tkline := strings.TrimSpace(parts[1])\n\t\t\t\tgatherErrorStatsLine(name, kline, acc, tags)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmetric = name\n\t\t}\n\n\t\tval := strings.TrimSpace(parts[1])\n\n\t\t// Some percentage values have a \"%\" suffix that we need to get rid of before int/float conversion\n\t\tval = strings.TrimSuffix(val, \"%\")\n\n\t\t// Try parsing as int\n\t\tif ival, err := strconv.ParseInt(val, 10, 64); err == nil {\n\t\t\tswitch name {\n\t\t\tcase \"keyspace_hits\":\n\t\t\t\tkeyspaceHits = ival\n\t\t\tcase \"keyspace_misses\":\n\t\t\t\tkeyspaceMisses = ival\n\t\t\tcase \"rdb_last_save_time\":\n\t\t\t\t// influxdb can't calculate this, so we have to do it\n\t\t\t\tfields[\"rdb_last_save_time_elapsed\"] = time.Now().Unix() - ival\n\t\t\t}\n\t\t\tfields[metric] = ival\n\t\t\tcontinue\n\t\t}\n\n\t\t// Try parsing as a float\n\t\tif fval, err := strconv.ParseFloat(val, 64); err == nil {\n\t\t\tfields[metric] = fval\n\t\t\tcontinue\n\t\t}\n\n\t\t// Treat it as a string\n\n\t\tif name == \"role\" {\n\t\t\ttags[\"replication_role\"] = val\n\t\t\tcontinue\n\t\t}\n\n\t\tfields[metric] = val\n\t}\n\tvar keyspaceHitrate float64\n\tif keyspaceHits != 0 || keyspaceMisses != 0 {\n\t\tkeyspaceHitrate = float64(keyspaceHits) / float64(keyspaceHits+keyspaceMisses)\n\t}\n\tfields[\"keyspace_hitrate\"] = keyspaceHitrate\n\n\to := redisFieldTypes{}\n\n\tsetStructFieldsFromObject(fields, &o)\n\tsetExistingFieldsFromStruct(fields, &o)\n\n\tacc.AddFields(\"redis\", fields, tags)\n\treturn nil\n}\n\n// Parse the special Keyspace line at end of redis stats\n// This is a special line that looks something like:\n//\n//\tdb0:keys=2,expires=0,avg_ttl=0\n//\n// And there is one for each db on the redis instance\nfunc gatherKeyspaceLine(name, line string, acc telegraf.Accumulator, globalTags map[string]string) {\n\tif strings.Contains(line, \"keys=\") {\n\t\tfields := make(map[string]interface{})\n\t\ttags := make(map[string]string)\n\t\tfor k, v := range globalTags {\n\t\t\ttags[k] = v\n\t\t}\n\t\ttags[\"database\"] = name\n\t\tdbparts := strings.Split(line, \",\")\n\t\tfor _, dbp := range dbparts {\n\t\t\tkv := strings.Split(dbp, \"=\")\n\t\t\tival, err := strconv.ParseInt(kv[1], 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tfields[kv[0]] = ival\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(\"redis_keyspace\", fields, tags)\n\t}\n}\n\n// Parse the special cmdstat lines.\n// Example:\n//\n//\tcmdstat_publish:calls=33791,usec=208789,usec_per_call=6.18\n//\n// Tag: command=publish; Fields: calls=33791i,usec=208789i,usec_per_call=6.18\nfunc gatherCommandStateLine(name, line string, acc telegraf.Accumulator, globalTags map[string]string) {\n\tif !strings.HasPrefix(name, \"cmdstat\") {\n\t\treturn\n\t}\n\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\tfor k, v := range globalTags {\n\t\ttags[k] = v\n\t}\n\ttags[\"command\"] = strings.TrimPrefix(name, \"cmdstat_\")\n\tparts := strings.Split(line, \",\")\n\tfor _, part := range parts {\n\t\tkv := strings.Split(part, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch kv[0] {\n\t\tcase \"calls\":\n\t\t\tfallthrough\n\t\tcase \"usec\", \"rejected_calls\", \"failed_calls\":\n\t\t\tival, err := strconv.ParseInt(kv[1], 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tfields[kv[0]] = ival\n\t\t\t}\n\t\tcase \"usec_per_call\":\n\t\t\tfval, err := strconv.ParseFloat(kv[1], 64)\n\t\t\tif err == nil {\n\t\t\t\tfields[kv[0]] = fval\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"redis_cmdstat\", fields, tags)\n}\n\n// Parse the special latency_percentiles_usec lines.\n// Example:\n//\n//\tlatency_percentiles_usec_zadd:p50=9.023,p99=28.031,p99.9=43.007\n//\n// Tag: command=zadd; Fields: p50=9.023,p99=28.031,p99.9=43.007\nfunc gatherLatencyStatsLine(name, line string, acc telegraf.Accumulator, globalTags map[string]string) {\n\tif !strings.HasPrefix(name, \"latency_percentiles_usec\") {\n\t\treturn\n\t}\n\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\tfor k, v := range globalTags {\n\t\ttags[k] = v\n\t}\n\ttags[\"command\"] = strings.TrimPrefix(name, \"latency_percentiles_usec_\")\n\tparts := strings.Split(line, \",\")\n\tfor _, part := range parts {\n\t\tkv := strings.Split(part, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch kv[0] {\n\t\tcase \"p50\", \"p99\", \"p99.9\":\n\t\t\tfval, err := strconv.ParseFloat(kv[1], 64)\n\t\t\tif err == nil {\n\t\t\t\tfields[kv[0]] = fval\n\t\t\t}\n\t\t}\n\t}\n\tacc.AddFields(\"redis_latency_percentiles_usec\", fields, tags)\n}\n\n// Parse the special Replication line\n// Example:\n//\n//\tslave0:ip=127.0.0.1,port=7379,state=online,offset=4556468,lag=0\n//\n// This line will only be visible when a node has a replica attached.\nfunc gatherReplicationLine(name, line string, acc telegraf.Accumulator, globalTags map[string]string) {\n\tfields := make(map[string]interface{})\n\ttags := make(map[string]string)\n\tfor k, v := range globalTags {\n\t\ttags[k] = v\n\t}\n\n\ttags[\"replica_id\"] = strings.TrimLeft(name, \"slave\")\n\ttags[\"replication_role\"] = \"slave\"\n\n\tparts := strings.Split(line, \",\")\n\tfor _, part := range parts {\n\t\tkv := strings.Split(part, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch kv[0] {\n\t\tcase \"ip\":\n\t\t\ttags[\"replica_ip\"] = kv[1]\n\t\tcase \"port\":\n\t\t\ttags[\"replica_port\"] = kv[1]\n\t\tcase \"state\":\n\t\t\ttags[kv[0]] = kv[1]\n\t\tdefault:\n\t\t\tival, err := strconv.ParseInt(kv[1], 10, 64)\n\t\t\tif err == nil {\n\t\t\t\tfields[kv[0]] = ival\n\t\t\t}\n\t\t}\n\t}\n\n\tacc.AddFields(\"redis_replication\", fields, tags)\n}\n\n// Parse the special Errorstats lines.\n// Example:\n//\n// errorstat_ERR:count=37\n// errorstat_MOVED:count=3626\nfunc gatherErrorStatsLine(name, line string, acc telegraf.Accumulator, globalTags map[string]string) {\n\ttags := make(map[string]string, len(globalTags)+1)\n\tfor k, v := range globalTags {\n\t\ttags[k] = v\n\t}\n\ttags[\"err\"] = strings.TrimPrefix(name, \"errorstat_\")\n\tkv := strings.Split(line, \"=\")\n\tif len(kv) < 2 {\n\t\tacc.AddError(fmt.Errorf(\"invalid line for %q: %s\", name, line))\n\t\treturn\n\t}\n\tival, err := strconv.ParseInt(kv[1], 10, 64)\n\tif err != nil {\n\t\tacc.AddError(fmt.Errorf(\"parsing value in line %q failed: %w\", line, err))\n\t\treturn\n\t}\n\n\tfields := map[string]interface{}{\"total\": ival}\n\tacc.AddFields(\"redis_errorstat\", fields, tags)\n}\n\nfunc setExistingFieldsFromStruct(fields map[string]interface{}, o *redisFieldTypes) {\n\tval := reflect.ValueOf(o).Elem()\n\ttyp := val.Type()\n\n\tfor key := range fields {\n\t\tif _, exists := fields[key]; exists {\n\t\t\tfor i := 0; i < typ.NumField(); i++ {\n\t\t\t\tf := typ.Field(i)\n\t\t\t\tjsonFieldName := f.Tag.Get(\"json\")\n\t\t\t\tif jsonFieldName == key {\n\t\t\t\t\tfields[key] = val.Field(i).Interface()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc setStructFieldsFromObject(fields map[string]interface{}, o *redisFieldTypes) {\n\tval := reflect.ValueOf(o).Elem()\n\ttyp := val.Type()\n\n\tfor key, value := range fields {\n\t\tif _, exists := fields[key]; exists {\n\t\t\tfor i := 0; i < typ.NumField(); i++ {\n\t\t\t\tf := typ.Field(i)\n\t\t\t\tjsonFieldName := f.Tag.Get(\"json\")\n\t\t\t\tif jsonFieldName == key {\n\t\t\t\t\tstructFieldValue := val.Field(i)\n\t\t\t\t\tstructFieldValue.Set(coerceType(value, structFieldValue.Type()))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc coerceType(value interface{}, typ reflect.Type) reflect.Value {\n\tswitch sourceType := value.(type) {\n\tcase bool:\n\t\tswitch typ.Kind() {\n\t\tcase reflect.String:\n\t\t\tif sourceType {\n\t\t\t\tvalue = \"true\"\n\t\t\t} else {\n\t\t\t\tvalue = \"false\"\n\t\t\t}\n\t\tcase reflect.Int64:\n\t\t\tif sourceType {\n\t\t\t\tvalue = int64(1)\n\t\t\t} else {\n\t\t\t\tvalue = int64(0)\n\t\t\t}\n\t\tcase reflect.Float64:\n\t\t\tif sourceType {\n\t\t\t\tvalue = float64(1)\n\t\t\t} else {\n\t\t\t\tvalue = float64(0)\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unhandled destination type \" + typ.Kind().String())\n\t\t}\n\tcase int, int8, int16, int32, int64:\n\t\tswitch typ.Kind() {\n\t\tcase reflect.String:\n\t\t\tvalue = fmt.Sprintf(\"%d\", value)\n\t\tcase reflect.Int64:\n\t\t\t// types match\n\t\tcase reflect.Float64:\n\t\t\tvalue = float64(reflect.ValueOf(sourceType).Int())\n\t\tdefault:\n\t\t\tpanic(\"unhandled destination type \" + typ.Kind().String())\n\t\t}\n\tcase uint, uint8, uint16, uint32, uint64:\n\t\tswitch typ.Kind() {\n\t\tcase reflect.String:\n\t\t\tvalue = fmt.Sprintf(\"%d\", value)\n\t\tcase reflect.Int64:\n\t\t\t// types match\n\t\tcase reflect.Float64:\n\t\t\tvalue = float64(reflect.ValueOf(sourceType).Uint())\n\t\tdefault:\n\t\t\tpanic(\"unhandled destination type \" + typ.Kind().String())\n\t\t}\n\tcase float32, float64:\n\t\tswitch typ.Kind() {\n\t\tcase reflect.String:\n\t\t\tvalue = fmt.Sprintf(\"%f\", value)\n\t\tcase reflect.Int64:\n\t\t\tvalue = int64(reflect.ValueOf(sourceType).Float())\n\t\tcase reflect.Float64:\n\t\t\t// types match\n\t\tdefault:\n\t\t\tpanic(\"unhandled destination type \" + typ.Kind().String())\n\t\t}\n\tcase string:\n\t\tswitch typ.Kind() {\n\t\tcase reflect.String:\n\t\t\t// types match\n\t\tcase reflect.Int64:\n\t\t\t//nolint:errcheck // no way to propagate, shouldn't panic\n\t\t\tvalue, _ = strconv.ParseInt(value.(string), 10, 64)\n\t\tcase reflect.Float64:\n\t\t\t//nolint:errcheck // no way to propagate, shouldn't panic\n\t\t\tvalue, _ = strconv.ParseFloat(value.(string), 64)\n\t\tdefault:\n\t\t\tpanic(\"unhandled destination type \" + typ.Kind().String())\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unhandled source type %T\", sourceType))\n\t}\n\treturn reflect.ValueOf(value)\n}\n\nfunc init() {\n\tinputs.Add(\"redis\", func() telegraf.Input {\n\t\treturn &Redis{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/redis/redis_test.go",
    "content": "package redis\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/go-redis/redis/v8\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype testClient struct{}\n\nfunc (*testClient) baseTags() map[string]string {\n\treturn map[string]string{\"host\": \"redis.net\"}\n}\n\nfunc (*testClient) info() *redis.StringCmd {\n\treturn nil\n}\n\nfunc (*testClient) do(string, ...interface{}) (interface{}, error) {\n\treturn 2, nil\n}\n\nfunc (*testClient) close() error {\n\treturn nil\n}\n\nfunc TestRedisConnectIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tservicePort := \"6379\"\n\tcontainer := testutil.Container{\n\t\tImage:        \"redis:alpine\",\n\t\tExposedPorts: []string{servicePort},\n\t\tWaitingFor:   wait.ForListeningPort(nat.Port(servicePort)),\n\t}\n\terr := container.Start()\n\trequire.NoError(t, err, \"failed to start container\")\n\tdefer container.Terminate()\n\n\taddr := fmt.Sprintf(\"%s:%s\", container.Address, container.Ports[servicePort])\n\n\tr := &Redis{\n\t\tLog:     testutil.Logger{},\n\t\tServers: []string{addr},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\terr = acc.GatherError(r.Gather)\n\trequire.NoError(t, err)\n}\n\nfunc TestRedis_Commands(t *testing.T) {\n\tconst redisListKey = \"test-list-length\"\n\tvar acc testutil.Accumulator\n\n\ttc := &testClient{}\n\n\trc := &redisCommand{\n\t\tCommand: []interface{}{\"llen\", \"test-list\"},\n\t\tField:   redisListKey,\n\t\tType:    \"integer\",\n\t}\n\n\tr := &Redis{\n\t\tCommands: []*redisCommand{rc},\n\t\tclients:  []client{tc},\n\t}\n\n\terr := r.gatherCommandValues(tc, &acc)\n\trequire.NoError(t, err)\n\n\tfields := map[string]interface{}{\n\t\tredisListKey: 2,\n\t}\n\n\tacc.AssertContainsFields(t, \"redis_commands\", fields)\n}\n\nfunc TestRedis_ParseMetrics(t *testing.T) {\n\tvar acc testutil.Accumulator\n\ttags := map[string]string{\"host\": \"redis.net\"}\n\trdr := bufio.NewReader(strings.NewReader(testOutput))\n\n\terr := gatherInfoOutput(rdr, &acc, tags)\n\trequire.NoError(t, err)\n\n\ttags = map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\"}\n\tfields := map[string]interface{}{\n\t\t\"uptime\":                          int64(238),\n\t\t\"lru_clock\":                       int64(2364819),\n\t\t\"clients\":                         int64(1),\n\t\t\"client_longest_output_list\":      int64(0),\n\t\t\"client_biggest_input_buf\":        int64(0),\n\t\t\"blocked_clients\":                 int64(0),\n\t\t\"used_memory\":                     int64(1003936),\n\t\t\"used_memory_rss\":                 int64(811008),\n\t\t\"used_memory_peak\":                int64(1003936),\n\t\t\"used_memory_lua\":                 int64(33792),\n\t\t\"used_memory_peak_perc\":           float64(93.58),\n\t\t\"used_memory_dataset_perc\":        float64(20.27),\n\t\t\"mem_fragmentation_ratio\":         float64(0.81),\n\t\t\"loading\":                         int64(0),\n\t\t\"rdb_changes_since_last_save\":     int64(0),\n\t\t\"rdb_bgsave_in_progress\":          int64(0),\n\t\t\"rdb_last_save_time\":              int64(1428427941),\n\t\t\"rdb_last_bgsave_status\":          \"ok\",\n\t\t\"rdb_last_bgsave_time_sec\":        int64(-1),\n\t\t\"rdb_current_bgsave_time_sec\":     int64(-1),\n\t\t\"aof_enabled\":                     int64(0),\n\t\t\"aof_rewrite_in_progress\":         int64(0),\n\t\t\"aof_rewrite_scheduled\":           int64(0),\n\t\t\"aof_last_rewrite_time_sec\":       int64(-1),\n\t\t\"aof_current_rewrite_time_sec\":    int64(-1),\n\t\t\"aof_last_bgrewrite_status\":       \"ok\",\n\t\t\"aof_last_write_status\":           \"ok\",\n\t\t\"total_connections_received\":      int64(2),\n\t\t\"total_commands_processed\":        int64(1),\n\t\t\"instantaneous_ops_per_sec\":       int64(0),\n\t\t\"instantaneous_input_kbps\":        float64(876.16),\n\t\t\"instantaneous_output_kbps\":       float64(3010.23),\n\t\t\"rejected_connections\":            int64(0),\n\t\t\"sync_full\":                       int64(0),\n\t\t\"sync_partial_ok\":                 int64(0),\n\t\t\"sync_partial_err\":                int64(0),\n\t\t\"expired_keys\":                    int64(0),\n\t\t\"evicted_keys\":                    int64(0),\n\t\t\"keyspace_hits\":                   int64(1),\n\t\t\"keyspace_misses\":                 int64(1),\n\t\t\"pubsub_channels\":                 int64(0),\n\t\t\"pubsub_patterns\":                 int64(0),\n\t\t\"latest_fork_usec\":                int64(0),\n\t\t\"connected_slaves\":                int64(2),\n\t\t\"master_repl_offset\":              int64(0),\n\t\t\"repl_backlog_active\":             int64(0),\n\t\t\"repl_backlog_size\":               int64(1048576),\n\t\t\"repl_backlog_first_byte_offset\":  int64(0),\n\t\t\"repl_backlog_histlen\":            int64(0),\n\t\t\"second_repl_offset\":              int64(-1),\n\t\t\"used_cpu_sys\":                    float64(0.14),\n\t\t\"used_cpu_user\":                   float64(0.05),\n\t\t\"used_cpu_sys_children\":           float64(0.00),\n\t\t\"used_cpu_user_children\":          float64(0.00),\n\t\t\"keyspace_hitrate\":                float64(0.50),\n\t\t\"redis_version\":                   \"6.0.9\",\n\t\t\"active_defrag_hits\":              int64(0),\n\t\t\"active_defrag_key_hits\":          int64(0),\n\t\t\"active_defrag_key_misses\":        int64(0),\n\t\t\"active_defrag_misses\":            int64(0),\n\t\t\"active_defrag_running\":           int64(0),\n\t\t\"allocator_active\":                int64(1022976),\n\t\t\"allocator_allocated\":             int64(1019632),\n\t\t\"allocator_frag_bytes\":            float64(3344),\n\t\t\"allocator_frag_ratio\":            float64(1.00),\n\t\t\"allocator_resident\":              int64(1022976),\n\t\t\"allocator_rss_bytes\":             int64(0),\n\t\t\"allocator_rss_ratio\":             float64(1.00),\n\t\t\"aof_last_cow_size\":               int64(0),\n\t\t\"client_recent_max_input_buffer\":  int64(16),\n\t\t\"client_recent_max_output_buffer\": int64(0),\n\t\t\"clients_in_timeout_table\":        int64(0),\n\t\t\"cluster_enabled\":                 int64(0),\n\t\t\"expire_cycle_cpu_milliseconds\":   int64(669),\n\t\t\"expired_stale_perc\":              float64(0.00),\n\t\t\"expired_time_cap_reached_count\":  int64(0),\n\t\t\"io_threaded_reads_processed\":     int64(0),\n\t\t\"io_threaded_writes_processed\":    int64(0),\n\t\t\"total_reads_processed\":           int64(31),\n\t\t\"total_writes_processed\":          int64(17),\n\t\t\"lazyfree_pending_objects\":        int64(0),\n\t\t\"maxmemory\":                       int64(0),\n\t\t\"maxmemory_policy\":                \"noeviction\",\n\t\t\"mem_aof_buffer\":                  int64(0),\n\t\t\"mem_clients_normal\":              int64(17440),\n\t\t\"mem_clients_slaves\":              int64(0),\n\t\t\"mem_fragmentation_bytes\":         int64(41232),\n\t\t\"mem_not_counted_for_evict\":       int64(0),\n\t\t\"mem_replication_backlog\":         int64(0),\n\t\t\"rss_overhead_bytes\":              int64(37888),\n\t\t\"rss_overhead_ratio\":              float64(1.04),\n\t\t\"total_system_memory\":             int64(17179869184),\n\t\t\"used_memory_dataset\":             int64(47088),\n\t\t\"used_memory_overhead\":            int64(1019152),\n\t\t\"used_memory_scripts\":             int64(0),\n\t\t\"used_memory_startup\":             int64(1001712),\n\t\t\"migrate_cached_sockets\":          int64(0),\n\t\t\"module_fork_in_progress\":         int64(0),\n\t\t\"module_fork_last_cow_size\":       int64(0),\n\t\t\"number_of_cached_scripts\":        int64(0),\n\t\t\"rdb_last_cow_size\":               int64(0),\n\t\t\"slave_expires_tracked_keys\":      int64(0),\n\t\t\"unexpected_error_replies\":        int64(0),\n\t\t\"total_net_input_bytes\":           int64(381),\n\t\t\"total_net_output_bytes\":          int64(71521),\n\t\t\"tracking_clients\":                int64(0),\n\t\t\"tracking_total_items\":            int64(0),\n\t\t\"tracking_total_keys\":             int64(0),\n\t\t\"tracking_total_prefixes\":         int64(0),\n\t}\n\n\t// We have to test rdb_last_save_time_offset manually because the value is based on the time when gathered\n\tfor _, m := range acc.Metrics {\n\t\tfor k, v := range m.Fields {\n\t\t\tif k == \"rdb_last_save_time_elapsed\" {\n\t\t\t\tfields[k] = v\n\t\t\t}\n\t\t}\n\t}\n\trequire.InDelta(t,\n\t\ttime.Now().Unix()-fields[\"rdb_last_save_time\"].(int64),\n\t\tfields[\"rdb_last_save_time_elapsed\"].(int64),\n\t\t2) // allow for 2 seconds worth of offset\n\n\tkeyspaceTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"database\": \"db0\"}\n\tkeyspaceFields := map[string]interface{}{\n\t\t\"avg_ttl\": int64(0),\n\t\t\"expires\": int64(0),\n\t\t\"keys\":    int64(2),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis\", fields, tags)\n\tacc.AssertContainsTaggedFields(t, \"redis_keyspace\", keyspaceFields, keyspaceTags)\n\n\tcmdstatSetTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"command\": \"set\"}\n\tcmdstatSetFields := map[string]interface{}{\n\t\t\"calls\":         int64(261265),\n\t\t\"usec\":          int64(1634157),\n\t\t\"usec_per_call\": float64(6.25),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis_cmdstat\", cmdstatSetFields, cmdstatSetTags)\n\n\tcmdstatCommandTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"command\": \"command\"}\n\tcmdstatCommandFields := map[string]interface{}{\n\t\t\"calls\":         int64(1),\n\t\t\"usec\":          int64(990),\n\t\t\"usec_per_call\": float64(990.0),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis_cmdstat\", cmdstatCommandFields, cmdstatCommandTags)\n\n\tcmdstatPublishTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"command\": \"publish\"}\n\tcmdstatPublishFields := map[string]interface{}{\n\t\t\"calls\":          int64(488662),\n\t\t\"usec\":           int64(8573493),\n\t\t\"usec_per_call\":  float64(17.54),\n\t\t\"rejected_calls\": int64(0),\n\t\t\"failed_calls\":   int64(0),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis_cmdstat\", cmdstatPublishFields, cmdstatPublishTags)\n\n\tlatencyZaddTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"command\": \"zadd\"}\n\tlatencyZaddFields := map[string]interface{}{\n\t\t\"p50\":   float64(9.023),\n\t\t\"p99\":   float64(28.031),\n\t\t\"p99.9\": float64(43.007),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis_latency_percentiles_usec\", latencyZaddFields, latencyZaddTags)\n\n\tlatencyHgetallTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"command\": \"hgetall\"}\n\tlatencyHgetallFields := map[string]interface{}{\n\t\t\"p50\":   float64(11.007),\n\t\t\"p99\":   float64(34.047),\n\t\t\"p99.9\": float64(66.047),\n\t}\n\tacc.AssertContainsTaggedFields(t, \"redis_latency_percentiles_usec\", latencyHgetallFields, latencyHgetallTags)\n\n\treplicationTags := map[string]string{\n\t\t\"host\":             \"redis.net\",\n\t\t\"replication_role\": \"slave\",\n\t\t\"replica_id\":       \"0\",\n\t\t\"replica_ip\":       \"127.0.0.1\",\n\t\t\"replica_port\":     \"7379\",\n\t\t\"state\":            \"online\",\n\t}\n\treplicationFields := map[string]interface{}{\n\t\t\"lag\":    int64(0),\n\t\t\"offset\": int64(4556468),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"redis_replication\", replicationFields, replicationTags)\n\n\treplicationTags = map[string]string{\n\t\t\"host\":             \"redis.net\",\n\t\t\"replication_role\": \"slave\",\n\t\t\"replica_id\":       \"1\",\n\t\t\"replica_ip\":       \"127.0.0.1\",\n\t\t\"replica_port\":     \"8379\",\n\t\t\"state\":            \"send_bulk\",\n\t}\n\treplicationFields = map[string]interface{}{\n\t\t\"lag\":    int64(1),\n\t\t\"offset\": int64(0),\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"redis_replication\", replicationFields, replicationTags)\n\n\terrorStatsTags := map[string]string{\"host\": \"redis.net\", \"replication_role\": \"master\", \"err\": \"MOVED\"}\n\terrorStatsFields := map[string]interface{}{\"total\": int64(3628)}\n\n\tacc.AssertContainsTaggedFields(t, \"redis_errorstat\", errorStatsFields, errorStatsTags)\n}\n\nfunc TestRedis_ParseFloatOnInts(t *testing.T) {\n\tvar acc testutil.Accumulator\n\ttags := map[string]string{\"host\": \"redis.net\"}\n\trdr := bufio.NewReader(strings.NewReader(strings.Replace(testOutput, \"mem_fragmentation_ratio:0.81\", \"mem_fragmentation_ratio:1\", 1)))\n\terr := gatherInfoOutput(rdr, &acc, tags)\n\trequire.NoError(t, err)\n\tvar m *testutil.Metric\n\tfor i := range acc.Metrics {\n\t\tif _, ok := acc.Metrics[i].Fields[\"mem_fragmentation_ratio\"]; ok {\n\t\t\tm = acc.Metrics[i]\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.NotNil(t, m)\n\tfragRatio, ok := m.Fields[\"mem_fragmentation_ratio\"]\n\trequire.True(t, ok)\n\trequire.IsType(t, float64(0.0), fragRatio)\n}\n\nfunc TestRedis_ParseIntOnFloats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\ttags := map[string]string{\"host\": \"redis.net\"}\n\trdr := bufio.NewReader(strings.NewReader(strings.Replace(testOutput, \"clients_in_timeout_table:0\", \"clients_in_timeout_table:0.0\", 1)))\n\terr := gatherInfoOutput(rdr, &acc, tags)\n\trequire.NoError(t, err)\n\tvar m *testutil.Metric\n\tfor i := range acc.Metrics {\n\t\tif _, ok := acc.Metrics[i].Fields[\"clients_in_timeout_table\"]; ok {\n\t\t\tm = acc.Metrics[i]\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.NotNil(t, m)\n\tclientsInTimeout, ok := m.Fields[\"clients_in_timeout_table\"]\n\trequire.True(t, ok)\n\trequire.IsType(t, int64(0), clientsInTimeout)\n}\n\nfunc TestRedis_ParseStringOnInts(t *testing.T) {\n\tvar acc testutil.Accumulator\n\ttags := map[string]string{\"host\": \"redis.net\"}\n\trdr := bufio.NewReader(strings.NewReader(strings.Replace(testOutput, \"maxmemory_policy:no-eviction\", \"maxmemory_policy:1\", 1)))\n\terr := gatherInfoOutput(rdr, &acc, tags)\n\trequire.NoError(t, err)\n\tvar m *testutil.Metric\n\tfor i := range acc.Metrics {\n\t\tif _, ok := acc.Metrics[i].Fields[\"maxmemory_policy\"]; ok {\n\t\t\tm = acc.Metrics[i]\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.NotNil(t, m)\n\tmaxmemoryPolicy, ok := m.Fields[\"maxmemory_policy\"]\n\trequire.True(t, ok)\n\trequire.IsType(t, string(\"\"), maxmemoryPolicy)\n}\n\nfunc TestRedis_ParseIntOnString(t *testing.T) {\n\tvar acc testutil.Accumulator\n\ttags := map[string]string{\"host\": \"redis.net\"}\n\trdr := bufio.NewReader(strings.NewReader(strings.Replace(testOutput, \"clients_in_timeout_table:0\", `clients_in_timeout_table:\"\"`, 1)))\n\terr := gatherInfoOutput(rdr, &acc, tags)\n\trequire.NoError(t, err)\n\tvar m *testutil.Metric\n\tfor i := range acc.Metrics {\n\t\tif _, ok := acc.Metrics[i].Fields[\"clients_in_timeout_table\"]; ok {\n\t\t\tm = acc.Metrics[i]\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.NotNil(t, m)\n\tclientsInTimeout, ok := m.Fields[\"clients_in_timeout_table\"]\n\trequire.True(t, ok)\n\trequire.IsType(t, int64(0), clientsInTimeout)\n}\n\nfunc TestRedis_GatherErrorstatsLine(t *testing.T) {\n\tvar acc testutil.Accumulator\n\tglobalTags := map[string]string{}\n\n\tgatherErrorStatsLine(\"FOO\", \"BAR\", &acc, globalTags)\n\trequire.Len(t, acc.Errors, 1)\n\trequire.Equal(t, \"invalid line for \\\"FOO\\\": BAR\", acc.Errors[0].Error())\n\n\tacc = testutil.Accumulator{}\n\tgatherErrorStatsLine(\"FOO\", \"BAR=a\", &acc, globalTags)\n\trequire.Len(t, acc.Errors, 1)\n\trequire.Equal(t, \"parsing value in line \\\"BAR=a\\\" failed: strconv.ParseInt: parsing \\\"a\\\": invalid syntax\", acc.Errors[0].Error())\n\n\tacc = testutil.Accumulator{}\n\tgatherErrorStatsLine(\"FOO\", \"BAR=77\", &acc, globalTags)\n\trequire.Empty(t, acc.Errors)\n}\n\nconst testOutput = `# Server\nredis_version:6.0.9\nredis_git_sha1:00000000\nredis_git_dirty:0\nredis_build_id:26c3229b35eb3beb\nredis_mode:standalone\nos:Darwin 19.6.0 x86_64\narch_bits:64\nmultiplexing_api:kqueue\natomicvar_api:atomic-builtin\ngcc_version:4.2.1\nprocess_id:46677\nrun_id:5d6bf38087b23e48f1a59b7aca52e2b55438b02f\ntcp_port:6379\nuptime_in_seconds:238\nuptime_in_days:0\nhz:10\nconfigured_hz:10\nlru_clock:2364819\nexecutable:/usr/local/opt/redis/bin/redis-server\nconfig_file:/usr/local/etc/redis.conf\nio_threads_active:0\n\n# Clients\nclient_recent_max_input_buffer:16\nclient_recent_max_output_buffer:0\ntracking_clients:0\nclients_in_timeout_table:0\nconnected_clients:1\nclient_longest_output_list:0\nclient_biggest_input_buf:0\nblocked_clients:0\n\n# Memory\nused_memory:1003936\nused_memory_human:980.41K\nused_memory_rss:811008\nused_memory_rss_human:1.01M\nused_memory_peak:1003936\nused_memory_peak_human:980.41K\nused_memory_peak_perc:93.58%\nused_memory_overhead:1019152\nused_memory_startup:1001712\nused_memory_dataset:47088\nused_memory_dataset_perc:20.27%\nallocator_allocated:1019632\nallocator_active:1022976\nallocator_resident:1022976\ntotal_system_memory:17179869184\ntotal_system_memory_human:16.00G\nused_memory_lua:33792\nused_memory_lua_human:37.00K\nused_memory_scripts:0\nused_memory_scripts_human:0B\nnumber_of_cached_scripts:0\nmaxmemory:0\nmaxmemory_human:0B\nmaxmemory_policy:noeviction\nallocator_frag_ratio:1.00\nallocator_frag_bytes:3344\nallocator_rss_ratio:1.00\nallocator_rss_bytes:0\nrss_overhead_ratio:1.04\nrss_overhead_bytes:37888\nmem_fragmentation_ratio:0.81\nmem_fragmentation_bytes:41232\nmem_not_counted_for_evict:0\nmem_replication_backlog:0\nmem_clients_slaves:0\nmem_clients_normal:17440\nmem_aof_buffer:0\nmem_allocator:libc\nactive_defrag_running:0\nlazyfree_pending_objects:0\n\n# Persistence\nloading:0\nrdb_changes_since_last_save:0\nrdb_bgsave_in_progress:0\nrdb_last_save_time:1428427941\nrdb_last_bgsave_status:ok\nrdb_last_bgsave_time_sec:-1\nrdb_current_bgsave_time_sec:-1\nrdb_last_cow_size:0\naof_enabled:0\naof_rewrite_in_progress:0\naof_rewrite_scheduled:0\naof_last_rewrite_time_sec:-1\naof_current_rewrite_time_sec:-1\naof_last_bgrewrite_status:ok\naof_last_write_status:ok\naof_last_cow_size:0\nmodule_fork_in_progress:0\nmodule_fork_last_cow_size:0\n\n# Stats\ntotal_connections_received:2\ntotal_commands_processed:1\ninstantaneous_ops_per_sec:0\ntotal_net_input_bytes:381\ntotal_net_output_bytes:71521\ninstantaneous_input_kbps:876.16\ninstantaneous_output_kbps:3010.23\nrejected_connections:0\nsync_full:0\nsync_partial_ok:0\nsync_partial_err:0\nexpired_keys:0\nexpired_stale_perc:0.00\nexpired_time_cap_reached_count:0\nexpire_cycle_cpu_milliseconds:669\nevicted_keys:0\nkeyspace_hits:1\nkeyspace_misses:1\npubsub_channels:0\npubsub_patterns:0\nlatest_fork_usec:0\nmigrate_cached_sockets:0\nslave_expires_tracked_keys:0\nactive_defrag_hits:0\nactive_defrag_misses:0\nactive_defrag_key_hits:0\nactive_defrag_key_misses:0\ntracking_total_keys:0\ntracking_total_items:0\ntracking_total_prefixes:0\nunexpected_error_replies:0\ntotal_reads_processed:31\ntotal_writes_processed:17\nio_threaded_reads_processed:0\nio_threaded_writes_processed:0\n\n# Replication\nrole:master\nconnected_slaves:2\nslave0:ip=127.0.0.1,port=7379,state=online,offset=4556468,lag=0\nslave1:ip=127.0.0.1,port=8379,state=send_bulk,offset=0,lag=1\nmaster_replid:8c4d7b768b26826825ceb20ff4a2c7c54616350b\nmaster_replid2:0000000000000000000000000000000000000000\nmaster_repl_offset:0\nsecond_repl_offset:-1\nrepl_backlog_active:0\nrepl_backlog_size:1048576\nrepl_backlog_first_byte_offset:0\nrepl_backlog_histlen:0\n\n# CPU\nused_cpu_sys:0.14\nused_cpu_user:0.05\nused_cpu_sys_children:0.00\nused_cpu_user_children:0.00\n\n# Cluster\ncluster_enabled:0\n\n# Commandstats\ncmdstat_set:calls=261265,usec=1634157,usec_per_call=6.25\ncmdstat_command:calls=1,usec=990,usec_per_call=990.00\ncmdstat_publish:calls=488662,usec=8573493,usec_per_call=17.54,rejected_calls=0,failed_calls=0\n\n# Errorstats\nerrorstat_CLUSTERDOWN:count=8\nerrorstat_CROSSSLOT:count=3\nerrorstat_ERR:count=172\nerrorstat_LOADING:count=4284\nerrorstat_MASTERDOWN:count=102\nerrorstat_MOVED:count=3628\nerrorstat_NOSCRIPT:count=4\nerrorstat_WRONGPASS:count=2\nerrorstat_WRONGTYPE:count=30\n\n# Latencystats\nlatency_percentiles_usec_zadd:p50=9.023,p99=28.031,p99.9=43.007\nlatency_percentiles_usec_hgetall:p50=11.007,p99=34.047,p99.9=66.047\n\n# Keyspace\ndb0:keys=2,expires=0,avg_ttl=0\n\n(error) ERR unknown command 'eof'`\n"
  },
  {
    "path": "plugins/inputs/redis/sample.conf",
    "content": "# Read metrics from one or many redis servers\n[[inputs.redis]]\n  ## specify servers via a url matching:\n  ##  [protocol://][username:password]@address[:port]\n  ##  e.g.\n  ##    tcp://localhost:6379\n  ##    tcp://username:password@192.168.99.100\n  ##    unix:///var/run/redis.sock\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no port is specified, 6379 is used\n  servers = [\"tcp://localhost:6379\"]\n\n  ## Optional. Specify redis commands to retrieve values\n  # [[inputs.redis.commands]]\n  #   # The command to run where each argument is a separate element\n  #   command = [\"get\", \"sample-key\"]\n  #   # The field to store the result in\n  #   field = \"sample-key-value\"\n  #   # The type of the result\n  #   # Can be \"string\", \"integer\", or \"float\"\n  #   type = \"string\"\n\n  ## Specify username and password for ACL auth (Redis 6.0+). You can add this\n  ## to the server URI above or specify it here. The values here take\n  ## precedence.\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config\n  ## Check tls/config.go ClientConfig for more options\n  # tls_enable = true\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/README.md",
    "content": "# Redis Sentinel Input Plugin\n\nThis plugin collects metrics for [Redis Sentinel][sentinel] instances monitoring\nRedis servers and replicas.\n\n⭐ Telegraf v1.22.0\n🏷️ server\n💻 all\n\n[sentinel]: https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many redis-sentinel servers\n[[inputs.redis_sentinel]]\n  ## specify servers via a url matching:\n  ##  [protocol://][username:password]@address[:port]\n  ##  e.g.\n  ##    tcp://localhost:26379\n  ##    tcp://username:password@192.168.99.100\n  ##    unix:///var/run/redis-sentinel.sock\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no port is specified, 26379 is used\n  # servers = [\"tcp://localhost:26379\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n```\n\n## Metrics\n\nThe plugin gathers the results of these commands and measurements:\n\n* `sentinel masters` - `redis_sentinel_masters`\n* `sentinel sentinels` - `redis_sentinels`\n* `sentinel replicas` - `redis_replicas`\n* `info all` - `redis_sentinel`\n\nThe `has_quorum` field in `redis_sentinel_masters` is from calling the command\n`sentinels ckquorum`.\n\nThere are 5 remote network requests made for each server listed in the config.\n\n* redis_sentinel_masters\n  * tags:\n    * host\n    * master\n    * port\n    * source\n\n  * fields:\n    * config_epoch (int)\n    * down_after_milliseconds (int)\n    * failover_timeout (int)\n    * flags (string)\n    * has_quorum (bool)\n    * info_refresh (int)\n    * ip (string)\n    * last_ok_ping_reply (int)\n    * last_ping_reply (int)\n    * last_ping_sent (int)\n    * link_pending_commands (int)\n    * link_refcount (int)\n    * num_other_sentinels (int)\n    * num_slaves (int)\n    * parallel_syncs (int)\n    * port (int)\n    * quorum (int)\n    * role_reported (string)\n    * role_reported_time (int)\n\n* redis_sentinel_sentinels\n  * tags:\n    * host\n    * master\n    * port\n    * sentinel_ip\n    * sentinel_port\n    * source\n\n  * fields:\n    * down_after_milliseconds (int)\n    * flags (string)\n    * last_hello_message (int)\n    * last_ok_ping_reply (int)\n    * last_ping_reply (int)\n    * last_ping_sent (int)\n    * link_pending_commands (int)\n    * link_refcount (int)\n    * name (string)\n    * voted_leader (string)\n    * voted_leader_epoch (int)\n\n* redis_sentinel_replicas\n  * tags:\n    * host\n    * master\n    * port\n    * replica_ip\n    * replica_port\n    * source\n\n  * fields:\n    * down_after_milliseconds (int)\n    * flags (string)\n    * info_refresh (int)\n    * last_ok_ping_reply (int)\n    * last_ping_reply (int)\n    * last_ping_sent (int)\n    * link_pending_commands (int)\n    * link_refcount (int)\n    * master_host (string)\n    * master_link_down_time (int)\n    * master_link_status (string)\n    * master_port (int)\n    * name (string)\n    * role_reported (string)\n    * role_reported_time (int)\n    * slave_priority (int)\n    * slave_repl_offset (int)\n\n* redis_sentinel\n  * tags:\n    * host\n    * port\n    * source\n\n  * fields:\n    * active_defrag_hits (int)\n    * active_defrag_key_hits (int)\n    * active_defrag_key_misses (int)\n    * active_defrag_misses (int)\n    * blocked_clients (int)\n    * client_recent_max_input_buffer (int)\n    * client_recent_max_output_buffer (int)\n    * clients (int)\n    * evicted_keys (int)\n    * expired_keys (int)\n    * expired_stale_perc (float)\n    * expired_time_cap_reached_count (int)\n    * instantaneous_input_kbps (float)\n    * instantaneous_ops_per_sec (int)\n    * instantaneous_output_kbps (float)\n    * keyspace_hits (int)\n    * keyspace_misses (int)\n    * latest_fork_usec (int)\n    * lru_clock (int)\n    * migrate_cached_sockets (int)\n    * pubsub_channels (int)\n    * pubsub_patterns (int)\n    * redis_version (string)\n    * rejected_connections (int)\n    * sentinel_masters (int)\n    * sentinel_running_scripts (int)\n    * sentinel_scripts_queue_length (int)\n    * sentinel_simulate_failure_flags (int)\n    * sentinel_tilt (int)\n    * slave_expires_tracked_keys (int)\n    * sync_full (int)\n    * sync_partial_err (int)\n    * sync_partial_ok (int)\n    * total_commands_processed (int)\n    * total_connections_received (int)\n    * total_net_input_bytes (int)\n    * total_net_output_bytes (int)\n    * uptime_ns (int, nanoseconds)\n    * used_cpu_sys (float)\n    * used_cpu_sys_children (float)\n    * used_cpu_user (float)\n    * used_cpu_user_children (float)\n\n## Example Output\n\nAn example of 2 Redis Sentinel instances monitoring a single master and\nreplica. It produces:\n\n### redis_sentinel_masters\n\n```text\nredis_sentinel_masters,host=somehostname,master=mymaster,port=26380,source=localhost config_epoch=0i,down_after_milliseconds=30000i,failover_timeout=180000i,flags=\"master\",has_quorum=1i,info_refresh=110i,ip=\"127.0.0.1\",last_ok_ping_reply=819i,last_ping_reply=819i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,num_other_sentinels=1i,num_slaves=1i,parallel_syncs=1i,port=6379i,quorum=2i,role_reported=\"master\",role_reported_time=311248i 1570207377000000000\nredis_sentinel_masters,host=somehostname,master=mymaster,port=26379,source=localhost config_epoch=0i,down_after_milliseconds=30000i,failover_timeout=180000i,flags=\"master\",has_quorum=1i,info_refresh=1650i,ip=\"127.0.0.1\",last_ok_ping_reply=1003i,last_ping_reply=1003i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,num_other_sentinels=1i,num_slaves=1i,parallel_syncs=1i,port=6379i,quorum=2i,role_reported=\"master\",role_reported_time=302990i 1570207377000000000\n```\n\n### redis_sentinel_sentinels\n\n```text\nredis_sentinel_sentinels,host=somehostname,master=mymaster,port=26380,sentinel_ip=127.0.0.1,sentinel_port=26379,source=localhost down_after_milliseconds=30000i,flags=\"sentinel\",last_hello_message=1337i,last_ok_ping_reply=566i,last_ping_reply=566i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,name=\"fd7444de58ecc00f2685cd89fc11ff96c72f0569\",voted_leader=\"?\",voted_leader_epoch=0i 1570207377000000000\nredis_sentinel_sentinels,host=somehostname,master=mymaster,port=26379,sentinel_ip=127.0.0.1,sentinel_port=26380,source=localhost down_after_milliseconds=30000i,flags=\"sentinel\",last_hello_message=1510i,last_ok_ping_reply=1004i,last_ping_reply=1004i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,name=\"d06519438fe1b35692cb2ea06d57833c959f9114\",voted_leader=\"?\",voted_leader_epoch=0i 1570207377000000000\n```\n\n### redis_sentinel_replicas\n\n```text\nredis_sentinel_replicas,host=somehostname,master=mymaster,port=26379,replica_ip=127.0.0.1,replica_port=6380,source=localhost down_after_milliseconds=30000i,flags=\"slave\",info_refresh=1651i,last_ok_ping_reply=1005i,last_ping_reply=1005i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,master_host=\"127.0.0.1\",master_link_down_time=0i,master_link_status=\"ok\",master_port=6379i,name=\"127.0.0.1:6380\",role_reported=\"slave\",role_reported_time=302983i,slave_priority=100i,slave_repl_offset=40175i 1570207377000000000\nredis_sentinel_replicas,host=somehostname,master=mymaster,port=26380,replica_ip=127.0.0.1,replica_port=6380,source=localhost down_after_milliseconds=30000i,flags=\"slave\",info_refresh=111i,last_ok_ping_reply=821i,last_ping_reply=821i,last_ping_sent=0i,link_pending_commands=0i,link_refcount=1i,master_host=\"127.0.0.1\",master_link_down_time=0i,master_link_status=\"ok\",master_port=6379i,name=\"127.0.0.1:6380\",role_reported=\"slave\",role_reported_time=311243i,slave_priority=100i,slave_repl_offset=40441i 1570207377000000000\n```\n\n### redis_sentinel\n\n```text\nredis_sentinel,host=somehostname,port=26379,source=localhost active_defrag_hits=0i,active_defrag_key_hits=0i,active_defrag_key_misses=0i,active_defrag_misses=0i,blocked_clients=0i,client_recent_max_input_buffer=2i,client_recent_max_output_buffer=0i,clients=3i,evicted_keys=0i,expired_keys=0i,expired_stale_perc=0,expired_time_cap_reached_count=0i,instantaneous_input_kbps=0.01,instantaneous_ops_per_sec=0i,instantaneous_output_kbps=0,keyspace_hits=0i,keyspace_misses=0i,latest_fork_usec=0i,lru_clock=9926289i,migrate_cached_sockets=0i,pubsub_channels=0i,pubsub_patterns=0i,redis_version=\"5.0.5\",rejected_connections=0i,sentinel_masters=1i,sentinel_running_scripts=0i,sentinel_scripts_queue_length=0i,sentinel_simulate_failure_flags=0i,sentinel_tilt=0i,slave_expires_tracked_keys=0i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=459i,total_connections_received=6i,total_net_input_bytes=24517i,total_net_output_bytes=14864i,uptime_ns=303000000000i,used_cpu_sys=0.404,used_cpu_sys_children=0,used_cpu_user=0.436,used_cpu_user_children=0 1570207377000000000\nredis_sentinel,host=somehostname,port=26380,source=localhost active_defrag_hits=0i,active_defrag_key_hits=0i,active_defrag_key_misses=0i,active_defrag_misses=0i,blocked_clients=0i,client_recent_max_input_buffer=2i,client_recent_max_output_buffer=0i,clients=2i,evicted_keys=0i,expired_keys=0i,expired_stale_perc=0,expired_time_cap_reached_count=0i,instantaneous_input_kbps=0.01,instantaneous_ops_per_sec=0i,instantaneous_output_kbps=0,keyspace_hits=0i,keyspace_misses=0i,latest_fork_usec=0i,lru_clock=9926289i,migrate_cached_sockets=0i,pubsub_channels=0i,pubsub_patterns=0i,redis_version=\"5.0.5\",rejected_connections=0i,sentinel_masters=1i,sentinel_running_scripts=0i,sentinel_scripts_queue_length=0i,sentinel_simulate_failure_flags=0i,sentinel_tilt=0i,slave_expires_tracked_keys=0i,sync_full=0i,sync_partial_err=0i,sync_partial_ok=0i,total_commands_processed=442i,total_connections_received=2i,total_net_input_bytes=23861i,total_net_output_bytes=4443i,uptime_ns=312000000000i,used_cpu_sys=0.46,used_cpu_sys_children=0,used_cpu_user=0.416,used_cpu_user_children=0 1570207377000000000\n```\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/redis_sentinel.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage redis_sentinel\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/go-redis/redis/v7\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmeasurementMasters   = \"redis_sentinel_masters\"\n\tmeasurementSentinel  = \"redis_sentinel\"\n\tmeasurementSentinels = \"redis_sentinel_sentinels\"\n\tmeasurementReplicas  = \"redis_sentinel_replicas\"\n)\n\ntype RedisSentinel struct {\n\tServers []string `toml:\"servers\"`\n\ttls.ClientConfig\n\n\tclients []*redisSentinelClient\n}\n\ntype redisSentinelClient struct {\n\tsentinel *redis.SentinelClient\n\ttags     map[string]string\n}\n\nfunc (*RedisSentinel) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *RedisSentinel) Init() error {\n\tif len(r.Servers) == 0 {\n\t\tr.Servers = []string{\"tcp://localhost:26379\"}\n\t}\n\n\ttlsConfig, err := r.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.clients = make([]*redisSentinelClient, 0, len(r.Servers))\n\tfor _, serv := range r.Servers {\n\t\tu, err := url.Parse(serv)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse to address %q: %w\", serv, err)\n\t\t}\n\n\t\tusername := \"\"\n\t\tpassword := \"\"\n\t\tif u.User != nil {\n\t\t\tusername = u.User.Username()\n\t\t\tpw, ok := u.User.Password()\n\t\t\tif ok {\n\t\t\t\tpassword = pw\n\t\t\t}\n\t\t}\n\n\t\tvar address string\n\t\ttags := make(map[string]string, 2)\n\t\tswitch u.Scheme {\n\t\tcase \"tcp\":\n\t\t\taddress = u.Host\n\t\t\ttags[\"source\"] = u.Hostname()\n\t\t\ttags[\"port\"] = u.Port()\n\t\tcase \"unix\":\n\t\t\taddress = u.Path\n\t\t\ttags[\"socket\"] = u.Path\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid scheme %q, expected tcp or unix\", u.Scheme)\n\t\t}\n\n\t\tsentinel := redis.NewSentinelClient(\n\t\t\t&redis.Options{\n\t\t\t\tAddr:      address,\n\t\t\t\tUsername:  username,\n\t\t\t\tPassword:  password,\n\t\t\t\tNetwork:   u.Scheme,\n\t\t\t\tPoolSize:  1,\n\t\t\t\tTLSConfig: tlsConfig,\n\t\t\t},\n\t\t)\n\n\t\tr.clients = append(r.clients, &redisSentinelClient{\n\t\t\tsentinel: sentinel,\n\t\t\ttags:     tags,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (r *RedisSentinel) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\n\tfor _, client := range r.clients {\n\t\twg.Add(1)\n\n\t\tgo func(acc telegraf.Accumulator, client *redisSentinelClient) {\n\t\t\tdefer wg.Done()\n\n\t\t\tmasters, err := client.gatherMasterStats(acc)\n\t\t\tacc.AddError(err)\n\n\t\t\tfor _, master := range masters {\n\t\t\t\tacc.AddError(client.gatherReplicaStats(acc, master))\n\t\t\t\tacc.AddError(client.gatherSentinelStats(acc, master))\n\t\t\t}\n\n\t\t\tacc.AddError(client.gatherInfoStats(acc))\n\t\t}(acc, client)\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\n// Redis list format has string key/values adjacent, so convert to a map for easier use\nfunc toMap(vals []interface{}) map[string]string {\n\tm := make(map[string]string)\n\n\tfor idx := 0; idx < len(vals)-1; idx += 2 {\n\t\tkey, keyOk := vals[idx].(string)\n\t\tvalue, valueOk := vals[idx+1].(string)\n\n\t\tif keyOk && valueOk {\n\t\t\tm[key] = value\n\t\t}\n\t}\n\n\treturn m\n}\n\nfunc castFieldValue(value string, fieldType configFieldType) (interface{}, error) {\n\tvar castedValue interface{}\n\tvar err error\n\n\tswitch fieldType {\n\tcase configFieldTypeFloat:\n\t\tcastedValue, err = strconv.ParseFloat(value, 64)\n\tcase configFieldTypeInteger:\n\t\tcastedValue, err = strconv.ParseInt(value, 10, 64)\n\tcase configFieldTypeString:\n\t\tcastedValue = value\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported field type %v\", fieldType)\n\t}\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"casting value %q failed: %w\", value, err)\n\t}\n\n\treturn castedValue, nil\n}\n\nfunc prepareFieldValues(fields map[string]string, typeMap map[string]configFieldType) (map[string]interface{}, error) {\n\tpreparedFields := make(map[string]interface{})\n\n\tfor key, val := range fields {\n\t\tkey = strings.ReplaceAll(key, \"-\", \"_\")\n\n\t\tvalType, ok := typeMap[key]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tcastedVal, err := castFieldValue(val, valType)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tpreparedFields[key] = castedVal\n\t}\n\n\treturn preparedFields, nil\n}\n\nfunc (client *redisSentinelClient) gatherInfoStats(acc telegraf.Accumulator) error {\n\tinfoCmd := redis.NewStringCmd(\"info\", \"all\")\n\tif err := client.sentinel.Process(infoCmd); err != nil {\n\t\treturn err\n\t}\n\n\tinfo, err := infoCmd.Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trdr := strings.NewReader(info)\n\tinfoTags, infoFields, err := convertSentinelInfoOutput(client.tags, rdr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddFields(measurementSentinel, infoFields, infoTags)\n\n\treturn nil\n}\n\nfunc (client *redisSentinelClient) gatherMasterStats(acc telegraf.Accumulator) ([]string, error) {\n\tmastersCmd := redis.NewSliceCmd(\"sentinel\", \"masters\")\n\tif err := client.sentinel.Process(mastersCmd); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmasters, err := mastersCmd.Result()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Break out of the loop if one of the items comes out malformed\n\t// It's safe to assume that if we fail parsing one item that the rest will fail too\n\t// This is because we are iterating over a single server response\n\tmasterNames := make([]string, 0, len(masters))\n\tfor _, master := range masters {\n\t\tmaster, ok := master.([]interface{})\n\t\tif !ok {\n\t\t\treturn masterNames, errors.New(\"unable to process master response\")\n\t\t}\n\n\t\tm := toMap(master)\n\n\t\tmasterName, ok := m[\"name\"]\n\t\tif !ok {\n\t\t\treturn masterNames, errors.New(\"unable to resolve master name\")\n\t\t}\n\t\tmasterNames = append(masterNames, masterName)\n\n\t\tquorumCmd := redis.NewStringCmd(\"sentinel\", \"ckquorum\", masterName)\n\t\tquorumErr := client.sentinel.Process(quorumCmd)\n\n\t\tsentinelMastersTags, sentinelMastersFields, err := convertSentinelMastersOutput(client.tags, m, quorumErr)\n\t\tif err != nil {\n\t\t\treturn masterNames, err\n\t\t}\n\t\tacc.AddFields(measurementMasters, sentinelMastersFields, sentinelMastersTags)\n\t}\n\n\treturn masterNames, nil\n}\n\nfunc (client *redisSentinelClient) gatherReplicaStats(acc telegraf.Accumulator, masterName string) error {\n\treplicasCmd := redis.NewSliceCmd(\"sentinel\", \"replicas\", masterName)\n\tif err := client.sentinel.Process(replicasCmd); err != nil {\n\t\treturn err\n\t}\n\n\treplicas, err := replicasCmd.Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Break out of the loop if one of the items comes out malformed\n\t// It's safe to assume that if we fail parsing one item that the rest will fail too\n\t// This is because we are iterating over a single server response\n\tfor _, replica := range replicas {\n\t\treplica, ok := replica.([]interface{})\n\t\tif !ok {\n\t\t\treturn errors.New(\"unable to process replica response\")\n\t\t}\n\n\t\trm := toMap(replica)\n\t\treplicaTags, replicaFields, err := convertSentinelReplicaOutput(client.tags, masterName, rm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tacc.AddFields(measurementReplicas, replicaFields, replicaTags)\n\t}\n\n\treturn nil\n}\n\nfunc (client *redisSentinelClient) gatherSentinelStats(acc telegraf.Accumulator, masterName string) error {\n\tsentinelsCmd := redis.NewSliceCmd(\"sentinel\", \"sentinels\", masterName)\n\tif err := client.sentinel.Process(sentinelsCmd); err != nil {\n\t\treturn err\n\t}\n\n\tsentinels, err := sentinelsCmd.Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Break out of the loop if one of the items comes out malformed\n\t// It's safe to assume that if we fail parsing one item that the rest will fail too\n\t// This is because we are iterating over a single server response\n\tfor _, sentinel := range sentinels {\n\t\tsentinel, ok := sentinel.([]interface{})\n\t\tif !ok {\n\t\t\treturn errors.New(\"unable to process sentinel response\")\n\t\t}\n\n\t\tsm := toMap(sentinel)\n\t\tsentinelTags, sentinelFields, err := convertSentinelSentinelsOutput(client.tags, masterName, sm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tacc.AddFields(measurementSentinels, sentinelFields, sentinelTags)\n\t}\n\n\treturn nil\n}\n\n// converts `sentinel masters <name>` output to tags and fields\nfunc convertSentinelMastersOutput(globalTags, master map[string]string, quorumErr error) (map[string]string, map[string]interface{}, error) {\n\ttags := globalTags\n\n\ttags[\"master\"] = master[\"name\"]\n\n\tfields, err := prepareFieldValues(master, measurementMastersFields)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tfields[\"has_quorum\"] = quorumErr == nil\n\n\treturn tags, fields, nil\n}\n\n// converts `sentinel sentinels <name>` output to tags and fields\nfunc convertSentinelSentinelsOutput(\n\tglobalTags map[string]string,\n\tmasterName string,\n\tsentinelMaster map[string]string,\n) (map[string]string, map[string]interface{}, error) {\n\ttags := globalTags\n\n\ttags[\"sentinel_ip\"] = sentinelMaster[\"ip\"]\n\ttags[\"sentinel_port\"] = sentinelMaster[\"port\"]\n\ttags[\"master\"] = masterName\n\n\tfields, err := prepareFieldValues(sentinelMaster, measurementSentinelsFields)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn tags, fields, nil\n}\n\n// converts `sentinel replicas <name>` output to tags and fields\nfunc convertSentinelReplicaOutput(\n\tglobalTags map[string]string,\n\tmasterName string,\n\treplica map[string]string,\n) (map[string]string, map[string]interface{}, error) {\n\ttags := globalTags\n\n\ttags[\"replica_ip\"] = replica[\"ip\"]\n\ttags[\"replica_port\"] = replica[\"port\"]\n\ttags[\"master\"] = masterName\n\n\tfields, err := prepareFieldValues(replica, measurementReplicasFields)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn tags, fields, nil\n}\n\n// convertSentinelInfoOutput parses `INFO` command output\n// Largely copied from the Redis input plugin's gatherInfoOutput()\nfunc convertSentinelInfoOutput(globalTags map[string]string, rdr io.Reader) (map[string]string, map[string]interface{}, error) {\n\tscanner := bufio.NewScanner(rdr)\n\trawFields := make(map[string]string)\n\n\ttags := globalTags\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif len(line) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Redis denotes configuration sections with a hashtag\n\t\t// Example of the section header: # Clients\n\t\tif line[0] == '#' {\n\t\t\t// Nothing interesting here\n\t\t\tcontinue\n\t\t}\n\n\t\tparts := strings.SplitN(line, \":\", 2)\n\t\tif len(parts) < 2 {\n\t\t\t// Not a valid configuration option\n\t\t\tcontinue\n\t\t}\n\n\t\tkey := strings.TrimSpace(parts[0])\n\t\tval := strings.TrimSpace(parts[1])\n\n\t\trawFields[key] = val\n\t}\n\n\tfields, err := prepareFieldValues(rawFields, measurementSentinelFields)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Rename the field and convert it to nanoseconds\n\tsecs, ok := fields[\"uptime_in_seconds\"].(int64)\n\tif !ok {\n\t\treturn nil, nil, fmt.Errorf(\"uptime type %T is not int64\", fields[\"uptime_in_seconds\"])\n\t}\n\tfields[\"uptime_ns\"] = secs * 1000_000_000\n\tdelete(fields, \"uptime_in_seconds\")\n\n\t// Rename in order to match the \"redis\" input plugin\n\tfields[\"clients\"] = fields[\"connected_clients\"]\n\tdelete(fields, \"connected_clients\")\n\n\treturn tags, fields, nil\n}\n\nfunc init() {\n\tinputs.Add(\"redis_sentinel\", func() telegraf.Input {\n\t\treturn &RedisSentinel{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/redis_sentinel_test.go",
    "content": "package redis_sentinel\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/network\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nconst masterName = \"mymaster\"\nconst sentinelServicePort = \"26379\"\n\nfunc TestRedisSentinelConnectIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tnet, err := network.New(t.Context())\n\trequire.NoError(t, err)\n\tdefer func() {\n\t\trequire.NoError(t, net.Remove(t.Context()), \"terminating network failed\")\n\t}()\n\n\tredis := createRedisContainer(net.Name)\n\trequire.NoError(t, redis.Start(), \"failed to start container\")\n\tdefer redis.Terminate()\n\n\tfirstSentinel := createSentinelContainer(redis.Name, net.Name, wait.ForAll(\n\t\twait.ForLog(\"+monitor master\"),\n\t\twait.ForListeningPort(nat.Port(sentinelServicePort)),\n\t))\n\trequire.NoError(t, firstSentinel.Start(), \"failed to start container\")\n\tdefer firstSentinel.Terminate()\n\n\tsecondSentinel := createSentinelContainer(redis.Name, net.Name, wait.ForAll(\n\t\twait.ForLog(\"+sentinel sentinel\"),\n\t\twait.ForListeningPort(nat.Port(sentinelServicePort)),\n\t))\n\trequire.NoError(t, secondSentinel.Start(), \"failed to start container\")\n\tdefer secondSentinel.Terminate()\n\n\taddr := fmt.Sprintf(\"tcp://%s:%s\", secondSentinel.Address, secondSentinel.Ports[sentinelServicePort])\n\n\tr := &RedisSentinel{\n\t\tServers: []string{addr},\n\t}\n\trequire.NoError(t, r.Init(), \"failed to run Init function\")\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(r.Gather))\n\n\trequire.True(t, acc.HasMeasurement(\"redis_sentinel_masters\"), \"redis_sentinel_masters measurement is missing\")\n\trequire.True(t, acc.HasMeasurement(\"redis_sentinel_sentinels\"), \"redis_sentinel_sentinels measurement is missing\")\n\trequire.True(t, acc.HasMeasurement(\"redis_sentinel\"), \"redis_sentinel measurement is missing\")\n}\n\nfunc TestRedisSentinelMasters(t *testing.T) {\n\tnow := time.Now()\n\n\tglobalTags := map[string]string{\n\t\t\"port\":   \"6379\",\n\t\t\"source\": \"redis.io\",\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"port\":   \"6379\",\n\t\t\"source\": \"redis.io\",\n\t\t\"master\": masterName,\n\t}\n\n\t// has_quorum is a custom field\n\texpectedFields := map[string]interface{}{\n\t\t\"config_epoch\":            0,\n\t\t\"down_after_milliseconds\": 30000,\n\t\t\"failover_timeout\":        180000,\n\t\t\"flags\":                   \"master\",\n\t\t\"info_refresh\":            8819,\n\t\t\"ip\":                      \"127.0.0.1\",\n\t\t\"last_ok_ping_reply\":      174,\n\t\t\"last_ping_reply\":         174,\n\t\t\"last_ping_sent\":          0,\n\t\t\"link_pending_commands\":   0,\n\t\t\"link_refcount\":           1,\n\t\t\"num_other_sentinels\":     1,\n\t\t\"num_slaves\":              0,\n\t\t\"parallel_syncs\":          1,\n\t\t\"port\":                    6379,\n\t\t\"quorum\":                  2,\n\t\t\"role_reported\":           \"master\",\n\t\t\"role_reported_time\":      83138826,\n\t\t\"has_quorum\":              true,\n\t}\n\n\texpectedMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementMasters, expectedTags, expectedFields, now),\n\t}\n\n\tsentinelMastersOutput := map[string]string{\n\t\t\"config_epoch\":            \"0\",\n\t\t\"down_after_milliseconds\": \"30000\",\n\t\t\"failover_timeout\":        \"180000\",\n\t\t\"flags\":                   \"master\",\n\t\t\"info_refresh\":            \"8819\",\n\t\t\"ip\":                      \"127.0.0.1\",\n\t\t\"last_ok_ping_reply\":      \"174\",\n\t\t\"last_ping_reply\":         \"174\",\n\t\t\"last_ping_sent\":          \"0\",\n\t\t\"link_pending_commands\":   \"0\",\n\t\t\"link_refcount\":           \"1\",\n\t\t\"name\":                    \"mymaster\",\n\t\t\"num_other_sentinels\":     \"1\",\n\t\t\"num_slaves\":              \"0\",\n\t\t\"parallel_syncs\":          \"1\",\n\t\t\"port\":                    \"6379\",\n\t\t\"quorum\":                  \"2\",\n\t\t\"role_reported\":           \"master\",\n\t\t\"role_reported_time\":      \"83138826\",\n\t\t\"runid\":                   \"ff3dadd1cfea3043de4d25711d93f01a564562f7\",\n\t}\n\n\tsentinelTags, sentinelFields, sentinelErr := convertSentinelMastersOutput(globalTags, sentinelMastersOutput, nil)\n\trequire.NoErrorf(t, sentinelErr, \"failed converting output: %v\", sentinelErr)\n\n\tactualMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementMasters, sentinelTags, sentinelFields, now),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, actualMetrics, testutil.IgnoreTime())\n}\n\nfunc TestRedisSentinels(t *testing.T) {\n\tnow := time.Now()\n\n\tglobalTags := make(map[string]string)\n\n\texpectedTags := map[string]string{\n\t\t\"sentinel_ip\":   \"127.0.0.1\",\n\t\t\"sentinel_port\": \"26380\",\n\t\t\"master\":        masterName,\n\t}\n\texpectedFields := map[string]interface{}{\n\t\t\"name\":                    \"adfd343f6b6ecc77e2b9636de6d9f28d4b827521\",\n\t\t\"flags\":                   \"sentinel\",\n\t\t\"link_pending_commands\":   0,\n\t\t\"link_refcount\":           1,\n\t\t\"last_ping_sent\":          0,\n\t\t\"last_ok_ping_reply\":      516,\n\t\t\"last_ping_reply\":         516,\n\t\t\"down_after_milliseconds\": 30000,\n\t\t\"last_hello_message\":      1905,\n\t\t\"voted_leader\":            \"?\",\n\t\t\"voted_leader_epoch\":      0,\n\t}\n\n\texpectedMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementSentinels, expectedTags, expectedFields, now),\n\t}\n\n\tsentinelsOutput := map[string]string{\n\t\t\"name\":                    \"adfd343f6b6ecc77e2b9636de6d9f28d4b827521\",\n\t\t\"ip\":                      \"127.0.0.1\",\n\t\t\"port\":                    \"26380\",\n\t\t\"runid\":                   \"adfd343f6b6ecc77e2b9636de6d9f28d4b827521\",\n\t\t\"flags\":                   \"sentinel\",\n\t\t\"link_pending_commands\":   \"0\",\n\t\t\"link_refcount\":           \"1\",\n\t\t\"last_ping_sent\":          \"0\",\n\t\t\"last_ok_ping_reply\":      \"516\",\n\t\t\"last_ping_reply\":         \"516\",\n\t\t\"down_after_milliseconds\": \"30000\",\n\t\t\"last_hello_message\":      \"1905\",\n\t\t\"voted_leader\":            \"?\",\n\t\t\"voted_leader_epoch\":      \"0\",\n\t}\n\n\tsentinelTags, sentinelFields, sentinelErr := convertSentinelSentinelsOutput(globalTags, masterName, sentinelsOutput)\n\trequire.NoErrorf(t, sentinelErr, \"failed converting output: %v\", sentinelErr)\n\n\tactualMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementSentinels, sentinelTags, sentinelFields, now),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, actualMetrics)\n}\n\nfunc TestRedisSentinelReplicas(t *testing.T) {\n\tnow := time.Now()\n\n\tglobalTags := make(map[string]string)\n\n\texpectedTags := map[string]string{\n\t\t\"replica_ip\":   \"127.0.0.1\",\n\t\t\"replica_port\": \"6380\",\n\t\t\"master\":       masterName,\n\t}\n\texpectedFields := map[string]interface{}{\n\t\t\"down_after_milliseconds\": 30000,\n\t\t\"flags\":                   \"slave\",\n\t\t\"info_refresh\":            8476,\n\t\t\"last_ok_ping_reply\":      987,\n\t\t\"last_ping_reply\":         987,\n\t\t\"last_ping_sent\":          0,\n\t\t\"link_pending_commands\":   0,\n\t\t\"link_refcount\":           1,\n\t\t\"master_host\":             \"127.0.0.1\",\n\t\t\"master_link_down_time\":   0,\n\t\t\"master_link_status\":      \"ok\",\n\t\t\"master_port\":             6379,\n\t\t\"name\":                    \"127.0.0.1:6380\",\n\t\t\"role_reported\":           \"slave\",\n\t\t\"role_reported_time\":      10267432,\n\t\t\"slave_priority\":          100,\n\t\t\"slave_repl_offset\":       1392400,\n\t}\n\n\texpectedMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementReplicas, expectedTags, expectedFields, now),\n\t}\n\n\treplicasOutput := map[string]string{\n\t\t\"down_after_milliseconds\": \"30000\",\n\t\t\"flags\":                   \"slave\",\n\t\t\"info_refresh\":            \"8476\",\n\t\t\"ip\":                      \"127.0.0.1\",\n\t\t\"last_ok_ping_reply\":      \"987\",\n\t\t\"last_ping_reply\":         \"987\",\n\t\t\"last_ping_sent\":          \"0\",\n\t\t\"link_pending_commands\":   \"0\",\n\t\t\"link_refcount\":           \"1\",\n\t\t\"master_host\":             \"127.0.0.1\",\n\t\t\"master_link_down_time\":   \"0\",\n\t\t\"master_link_status\":      \"ok\",\n\t\t\"master_port\":             \"6379\",\n\t\t\"name\":                    \"127.0.0.1:6380\",\n\t\t\"port\":                    \"6380\",\n\t\t\"role_reported\":           \"slave\",\n\t\t\"role_reported_time\":      \"10267432\",\n\t\t\"runid\":                   \"70e07dad9e450e2d35f1b75338e0a5341b59d710\",\n\t\t\"slave_priority\":          \"100\",\n\t\t\"slave_repl_offset\":       \"1392400\",\n\t}\n\n\tsentinelTags, sentinelFields, sentinelErr := convertSentinelReplicaOutput(globalTags, masterName, replicasOutput)\n\trequire.NoErrorf(t, sentinelErr, \"failed converting output: %v\", sentinelErr)\n\n\tactualMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementReplicas, sentinelTags, sentinelFields, now),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, actualMetrics)\n}\n\nfunc TestRedisSentinelInfoAll(t *testing.T) {\n\tnow := time.Now()\n\n\tglobalTags := map[string]string{\n\t\t\"port\":   \"6379\",\n\t\t\"source\": \"redis.io\",\n\t}\n\n\texpectedTags := map[string]string{\n\t\t\"port\":   \"6379\",\n\t\t\"source\": \"redis.io\",\n\t}\n\n\texpectedFields := map[string]interface{}{\n\t\t\"lru_clock\":     int64(15585808),\n\t\t\"uptime_ns\":     int64(901000000000),\n\t\t\"redis_version\": \"5.0.5\",\n\n\t\t\"clients\":                         int64(2),\n\t\t\"client_recent_max_input_buffer\":  int64(2),\n\t\t\"client_recent_max_output_buffer\": int64(0),\n\t\t\"blocked_clients\":                 int64(0),\n\n\t\t\"used_cpu_sys\":           float64(0.786872),\n\t\t\"used_cpu_user\":          float64(0.939455),\n\t\t\"used_cpu_sys_children\":  float64(0.000000),\n\t\t\"used_cpu_user_children\": float64(0.000000),\n\n\t\t\"total_connections_received\":     int64(2),\n\t\t\"total_commands_processed\":       int64(6),\n\t\t\"instantaneous_ops_per_sec\":      int64(0),\n\t\t\"total_net_input_bytes\":          int64(124),\n\t\t\"total_net_output_bytes\":         int64(10148),\n\t\t\"instantaneous_input_kbps\":       float64(0.00),\n\t\t\"instantaneous_output_kbps\":      float64(0.00),\n\t\t\"rejected_connections\":           int64(0),\n\t\t\"sync_full\":                      int64(0),\n\t\t\"sync_partial_ok\":                int64(0),\n\t\t\"sync_partial_err\":               int64(0),\n\t\t\"expired_keys\":                   int64(0),\n\t\t\"expired_stale_perc\":             float64(0.00),\n\t\t\"expired_time_cap_reached_count\": int64(0),\n\t\t\"evicted_keys\":                   int64(0),\n\t\t\"keyspace_hits\":                  int64(0),\n\t\t\"keyspace_misses\":                int64(0),\n\t\t\"pubsub_channels\":                int64(0),\n\t\t\"pubsub_patterns\":                int64(0),\n\t\t\"latest_fork_usec\":               int64(0),\n\t\t\"migrate_cached_sockets\":         int64(0),\n\t\t\"slave_expires_tracked_keys\":     int64(0),\n\t\t\"active_defrag_hits\":             int64(0),\n\t\t\"active_defrag_misses\":           int64(0),\n\t\t\"active_defrag_key_hits\":         int64(0),\n\t\t\"active_defrag_key_misses\":       int64(0),\n\n\t\t\"sentinel_masters\":                int64(2),\n\t\t\"sentinel_running_scripts\":        int64(0),\n\t\t\"sentinel_scripts_queue_length\":   int64(0),\n\t\t\"sentinel_simulate_failure_flags\": int64(0),\n\t\t\"sentinel_tilt\":                   int64(0),\n\t}\n\n\texpectedMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementSentinel, expectedTags, expectedFields, now),\n\t}\n\n\tsentinelInfoResponse, err := os.ReadFile(\"testdata/sentinel.info.response\")\n\trequire.NoErrorf(t, err, \"could not init fixture: %v\", err)\n\n\trdr := bufio.NewReader(bytes.NewReader(sentinelInfoResponse))\n\n\tsentinelTags, sentinelFields, sentinelErr := convertSentinelInfoOutput(globalTags, rdr)\n\trequire.NoErrorf(t, sentinelErr, \"failed converting output: %v\", sentinelErr)\n\n\tactualMetrics := []telegraf.Metric{\n\t\ttestutil.MustMetric(measurementSentinel, sentinelTags, sentinelFields, now),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expectedMetrics, actualMetrics)\n}\n\nfunc createRedisContainer(networkName string) testutil.Container {\n\treturn testutil.Container{\n\t\tImage:        \"redis:7.0-alpine\",\n\t\tName:         \"telegraf-test-redis-sentinel-redis\",\n\t\tNetworks:     []string{networkName},\n\t\tExposedPorts: []string{\"6379\"},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"Ready to accept connections\"),\n\t\t\twait.ForListeningPort(nat.Port(\"6379\")),\n\t\t),\n\t}\n}\n\nfunc createSentinelContainer(redisAddress, networkName string, waitingFor wait.Strategy) testutil.Container {\n\treturn testutil.Container{\n\t\tImage:        \"bitnamilegacy/redis-sentinel:7.0\",\n\t\tExposedPorts: []string{sentinelServicePort},\n\t\tNetworks:     []string{networkName},\n\t\tEnv: map[string]string{\n\t\t\t\"REDIS_MASTER_HOST\": redisAddress,\n\t\t},\n\t\tWaitingFor: waitingFor,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/redis_sentinel_types.go",
    "content": "package redis_sentinel\n\ntype configFieldType int32\n\nconst (\n\tconfigFieldTypeInteger configFieldType = iota\n\tconfigFieldTypeString\n\tconfigFieldTypeFloat\n)\n\n// Supported fields for \"redis_sentinel_masters\"\nvar measurementMastersFields = map[string]configFieldType{\n\t\"config_epoch\":            configFieldTypeInteger,\n\t\"down_after_milliseconds\": configFieldTypeInteger,\n\t\"failover_timeout\":        configFieldTypeInteger,\n\t\"flags\":                   configFieldTypeString,\n\t\"info_refresh\":            configFieldTypeInteger,\n\t\"ip\":                      configFieldTypeString,\n\t\"last_ok_ping_reply\":      configFieldTypeInteger,\n\t\"last_ping_reply\":         configFieldTypeInteger,\n\t\"last_ping_sent\":          configFieldTypeInteger,\n\t\"link_pending_commands\":   configFieldTypeInteger,\n\t\"link_refcount\":           configFieldTypeInteger,\n\t\"num_other_sentinels\":     configFieldTypeInteger,\n\t\"num_slaves\":              configFieldTypeInteger,\n\t\"parallel_syncs\":          configFieldTypeInteger,\n\t\"port\":                    configFieldTypeInteger,\n\t\"quorum\":                  configFieldTypeInteger,\n\t\"role_reported\":           configFieldTypeString,\n\t\"role_reported_time\":      configFieldTypeInteger,\n}\n\n// Supported fields for \"redis_sentinel\"\nvar measurementSentinelFields = map[string]configFieldType{\n\t\"active_defrag_hits\":              configFieldTypeInteger,\n\t\"active_defrag_key_hits\":          configFieldTypeInteger,\n\t\"active_defrag_key_misses\":        configFieldTypeInteger,\n\t\"active_defrag_misses\":            configFieldTypeInteger,\n\t\"blocked_clients\":                 configFieldTypeInteger,\n\t\"client_recent_max_input_buffer\":  configFieldTypeInteger,\n\t\"client_recent_max_output_buffer\": configFieldTypeInteger,\n\t\"connected_clients\":               configFieldTypeInteger, // Renamed to \"clients\"\n\t\"evicted_keys\":                    configFieldTypeInteger,\n\t\"expired_keys\":                    configFieldTypeInteger,\n\t\"expired_stale_perc\":              configFieldTypeFloat,\n\t\"expired_time_cap_reached_count\":  configFieldTypeInteger,\n\t\"instantaneous_input_kbps\":        configFieldTypeFloat,\n\t\"instantaneous_ops_per_sec\":       configFieldTypeInteger,\n\t\"instantaneous_output_kbps\":       configFieldTypeFloat,\n\t\"keyspace_hits\":                   configFieldTypeInteger,\n\t\"keyspace_misses\":                 configFieldTypeInteger,\n\t\"latest_fork_usec\":                configFieldTypeInteger,\n\t\"lru_clock\":                       configFieldTypeInteger,\n\t\"migrate_cached_sockets\":          configFieldTypeInteger,\n\t\"pubsub_channels\":                 configFieldTypeInteger,\n\t\"pubsub_patterns\":                 configFieldTypeInteger,\n\t\"redis_version\":                   configFieldTypeString,\n\t\"rejected_connections\":            configFieldTypeInteger,\n\t\"sentinel_masters\":                configFieldTypeInteger,\n\t\"sentinel_running_scripts\":        configFieldTypeInteger,\n\t\"sentinel_scripts_queue_length\":   configFieldTypeInteger,\n\t\"sentinel_simulate_failure_flags\": configFieldTypeInteger,\n\t\"sentinel_tilt\":                   configFieldTypeInteger,\n\t\"slave_expires_tracked_keys\":      configFieldTypeInteger,\n\t\"sync_full\":                       configFieldTypeInteger,\n\t\"sync_partial_err\":                configFieldTypeInteger,\n\t\"sync_partial_ok\":                 configFieldTypeInteger,\n\t\"total_commands_processed\":        configFieldTypeInteger,\n\t\"total_connections_received\":      configFieldTypeInteger,\n\t\"total_net_input_bytes\":           configFieldTypeInteger,\n\t\"total_net_output_bytes\":          configFieldTypeInteger,\n\t\"uptime_in_seconds\":               configFieldTypeInteger, // Renamed to \"uptime_ns\"\n\t\"used_cpu_sys\":                    configFieldTypeFloat,\n\t\"used_cpu_sys_children\":           configFieldTypeFloat,\n\t\"used_cpu_user\":                   configFieldTypeFloat,\n\t\"used_cpu_user_children\":          configFieldTypeFloat,\n}\n\n// Supported fields for \"redis_sentinel_sentinels\"\nvar measurementSentinelsFields = map[string]configFieldType{\n\t\"down_after_milliseconds\": configFieldTypeInteger,\n\t\"flags\":                   configFieldTypeString,\n\t\"last_hello_message\":      configFieldTypeInteger,\n\t\"last_ok_ping_reply\":      configFieldTypeInteger,\n\t\"last_ping_reply\":         configFieldTypeInteger,\n\t\"last_ping_sent\":          configFieldTypeInteger,\n\t\"link_pending_commands\":   configFieldTypeInteger,\n\t\"link_refcount\":           configFieldTypeInteger,\n\t\"name\":                    configFieldTypeString,\n\t\"voted_leader\":            configFieldTypeString,\n\t\"voted_leader_epoch\":      configFieldTypeInteger,\n}\n\n// Supported fields for \"redis_sentinel_replicas\"\nvar measurementReplicasFields = map[string]configFieldType{\n\t\"down_after_milliseconds\": configFieldTypeInteger,\n\t\"flags\":                   configFieldTypeString,\n\t\"info_refresh\":            configFieldTypeInteger,\n\t\"last_ok_ping_reply\":      configFieldTypeInteger,\n\t\"last_ping_reply\":         configFieldTypeInteger,\n\t\"last_ping_sent\":          configFieldTypeInteger,\n\t\"link_pending_commands\":   configFieldTypeInteger,\n\t\"link_refcount\":           configFieldTypeInteger,\n\t\"master_host\":             configFieldTypeString,\n\t\"master_link_down_time\":   configFieldTypeInteger,\n\t\"master_link_status\":      configFieldTypeString,\n\t\"master_port\":             configFieldTypeInteger,\n\t\"name\":                    configFieldTypeString,\n\t\"role_reported\":           configFieldTypeString,\n\t\"role_reported_time\":      configFieldTypeInteger,\n\t\"slave_priority\":          configFieldTypeInteger,\n\t\"slave_repl_offset\":       configFieldTypeInteger,\n}\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/sample.conf",
    "content": "# Read metrics from one or many redis-sentinel servers\n[[inputs.redis_sentinel]]\n  ## specify servers via a url matching:\n  ##  [protocol://][username:password]@address[:port]\n  ##  e.g.\n  ##    tcp://localhost:26379\n  ##    tcp://username:password@192.168.99.100\n  ##    unix:///var/run/redis-sentinel.sock\n  ##\n  ## If no servers are specified, then localhost is used as the host.\n  ## If no port is specified, 26379 is used\n  # servers = [\"tcp://localhost:26379\"]\n\n  ## Optional TLS Config\n  # tls_ca = \"/etc/telegraf/ca.pem\"\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key = \"/etc/telegraf/key.pem\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = true\n"
  },
  {
    "path": "plugins/inputs/redis_sentinel/testdata/sentinel.info.response",
    "content": "# Server\nredis_version:5.0.5\nredis_git_sha1:00000000\nredis_git_dirty:0\nredis_build_id:78473e0efb96880a\nredis_mode:sentinel\nos:Linux 5.1.3-arch1-1-ARCH x86_64\narch_bits:64\nmultiplexing_api:epoll\natomicvar_api:atomic-builtin\ngcc_version:8.3.0\nprocess_id:2837\nrun_id:ecbbb2ca0035a532b03748fbec9f3f8ca1967536\ntcp_port:26379\nuptime_in_seconds:901\nuptime_in_days:0\nhz:10\nconfigured_hz:10\nlru_clock:15585808\nexecutable:/home/adam/redis-sentinel\nconfig_file:/home/adam/rs1.conf\n\n# Clients\nconnected_clients:2\nclient_recent_max_input_buffer:2\nclient_recent_max_output_buffer:0\nblocked_clients:0\n\n# CPU\nused_cpu_sys:0.786872\nused_cpu_user:0.939455\nused_cpu_sys_children:0.000000\nused_cpu_user_children:0.000000\n\n# Stats\ntotal_connections_received:2\ntotal_commands_processed:6\ninstantaneous_ops_per_sec:0\ntotal_net_input_bytes:124\ntotal_net_output_bytes:10148\ninstantaneous_input_kbps:0.00\ninstantaneous_output_kbps:0.00\nrejected_connections:0\nsync_full:0\nsync_partial_ok:0\nsync_partial_err:0\nexpired_keys:0\nexpired_stale_perc:0.00\nexpired_time_cap_reached_count:0\nevicted_keys:0\nkeyspace_hits:0\nkeyspace_misses:0\npubsub_channels:0\npubsub_patterns:0\nlatest_fork_usec:0\nmigrate_cached_sockets:0\nslave_expires_tracked_keys:0\nactive_defrag_hits:0\nactive_defrag_misses:0\nactive_defrag_key_hits:0\nactive_defrag_key_misses:0\n\n# Sentinel\nsentinel_masters:2\nsentinel_tilt:0\nsentinel_running_scripts:0\nsentinel_scripts_queue_length:0\nsentinel_simulate_failure_flags:0\nmaster0:name=myothermaster,status=ok,address=127.0.0.1:6380,slaves=1,sentinels=2\nmaster0:name=myothermaster,status=ok,address=127.0.0.1:6381,slaves=1,sentinels=2\nmaster1:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=1,sentinels=1\n"
  },
  {
    "path": "plugins/inputs/registry.go",
    "content": "package inputs\n\nimport \"github.com/influxdata/telegraf\"\n\n// Creator is a function type that creates a new instance of a telegraf.Input.\ntype Creator func() telegraf.Input\n\n// Inputs is a map that holds all registered input plugins by their name.\nvar Inputs = make(map[string]Creator)\n\n// Add registers a new input plugin with the given name and creator function.\nfunc Add(name string, creator Creator) {\n\tInputs[name] = creator\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/README.md",
    "content": "# RethinkDB Input Plugin\n\nThis plugin collects metrics from [RethinkDB][rethinkdb] servers.\n\n⭐ Telegraf v0.1.3\n🏷️ server\n💻 all\n\n[rethinkdb]: https://www.rethinkdb.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from one or many RethinkDB servers\n[[inputs.rethinkdb]]\n  ## An array of URI to gather stats about. Specify an ip or hostname\n  ## with optional port add password. ie,\n  ##   rethinkdb://user:auth_key@10.10.3.30:28105,\n  ##   rethinkdb://10.10.3.33:18832,\n  ## For rethinkdb v2.3.0+ with username/password authorization you should use\n  ##   rethinkdb2://username:password@127.0.0.1:28015\"\n  servers = [\"127.0.0.1:28015\"]\n```\n\n## Metrics\n\n- rethinkdb\n  - tags:\n    - type\n    - ns\n    - rethinkdb_host\n    - rethinkdb_hostname\n  - fields:\n    - cache_bytes_in_use (integer, bytes)\n    - disk_read_bytes_per_sec (integer, reads)\n    - disk_read_bytes_total (integer, bytes)\n    - disk_written_bytes_per_sec (integer, bytes)\n    - disk_written_bytes_total (integer, bytes)\n    - disk_usage_data_bytes (integer, bytes)\n    - disk_usage_garbage_bytes (integer, bytes)\n    - disk_usage_metadata_bytes (integer, bytes)\n    - disk_usage_preallocated_bytes (integer, bytes)\n\n- rethinkdb_engine\n  - tags:\n    - type\n    - ns\n    - rethinkdb_host\n    - rethinkdb_hostname\n  - fields:\n    - active_clients (integer, clients)\n    - clients (integer, clients)\n    - queries_per_sec (integer, queries)\n    - total_queries (integer, queries)\n    - read_docs_per_sec (integer, reads)\n    - total_reads (integer, reads)\n    - written_docs_per_sec (integer, writes)\n    - total_writes (integer, writes)\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage rethinkdb\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"gopkg.in/gorethink/gorethink.v3\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar localhost = &server{url: &url.URL{Host: \"127.0.0.1:28015\"}}\n\ntype RethinkDB struct {\n\tServers []string `toml:\"servers\"`\n}\n\nfunc (*RethinkDB) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *RethinkDB) Gather(acc telegraf.Accumulator) error {\n\tif len(r.Servers) == 0 {\n\t\treturn gatherServer(localhost, acc)\n\t}\n\n\tvar wg sync.WaitGroup\n\n\tfor _, serv := range r.Servers {\n\t\tu, err := url.Parse(serv)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"unable to parse to address %q: %w\", serv, err))\n\t\t\tcontinue\n\t\t} else if u.Scheme == \"\" {\n\t\t\t// fallback to simple string based address (i.e. \"10.0.0.1:10000\")\n\t\t\tu.Host = serv\n\t\t}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tacc.AddError(gatherServer(&server{url: u}, acc))\n\t\t}()\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc gatherServer(server *server, acc telegraf.Accumulator) error {\n\tvar err error\n\tconnectOpts := gorethink.ConnectOpts{\n\t\tAddress:       server.url.Host,\n\t\tDiscoverHosts: false,\n\t}\n\tif server.url.User != nil {\n\t\tpwd, set := server.url.User.Password()\n\t\tif set && pwd != \"\" {\n\t\t\tconnectOpts.AuthKey = pwd\n\t\t\tconnectOpts.HandshakeVersion = gorethink.HandshakeV0_4\n\t\t}\n\t}\n\tif server.url.Scheme == \"rethinkdb2\" && server.url.User != nil {\n\t\tpwd, set := server.url.User.Password()\n\t\tif set && pwd != \"\" {\n\t\t\tconnectOpts.Username = server.url.User.Username()\n\t\t\tconnectOpts.Password = pwd\n\t\t\tconnectOpts.HandshakeVersion = gorethink.HandshakeV1_0\n\t\t}\n\t}\n\n\tserver.session, err = gorethink.Connect(connectOpts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to RethinkDB: %w\", err)\n\t}\n\tdefer server.session.Close()\n\n\treturn server.gatherData(acc)\n}\n\nfunc init() {\n\tinputs.Add(\"rethinkdb\", func() telegraf.Input {\n\t\treturn &RethinkDB{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb_data.go",
    "content": "package rethinkdb\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype serverStatus struct {\n\tID      string `gorethink:\"id\"`\n\tNetwork struct {\n\t\tAddresses  []address `gorethink:\"canonical_addresses\"`\n\t\tHostname   string    `gorethink:\"hostname\"`\n\t\tDriverPort int       `gorethink:\"reql_port\"`\n\t} `gorethink:\"network\"`\n\tProcess struct {\n\t\tVersion      string    `gorethink:\"version\"`\n\t\tRunningSince time.Time `gorethink:\"time_started\"`\n\t} `gorethink:\"process\"`\n}\n\ntype address struct {\n\tHost string `gorethink:\"host\"`\n\tPort int    `gorethink:\"port\"`\n}\n\ntype stats struct {\n\tEngine engine `gorethink:\"query_engine\"`\n}\n\ntype engine struct {\n\tClientConns   int64 `gorethink:\"client_connections,omitempty\"`\n\tClientActive  int64 `gorethink:\"clients_active,omitempty\"`\n\tQueriesPerSec int64 `gorethink:\"queries_per_sec,omitempty\"`\n\tTotalQueries  int64 `gorethink:\"queries_total,omitempty\"`\n\tReadsPerSec   int64 `gorethink:\"read_docs_per_sec,omitempty\"`\n\tTotalReads    int64 `gorethink:\"read_docs_total,omitempty\"`\n\tWritesPerSec  int64 `gorethink:\"written_docs_per_sec,omitempty\"`\n\tTotalWrites   int64 `gorethink:\"written_docs_total,omitempty\"`\n}\n\ntype tableStatus struct {\n\tID   string `gorethink:\"id\"`\n\tDB   string `gorethink:\"db\"`\n\tName string `gorethink:\"name\"`\n}\n\ntype tableStats struct {\n\tEngine  engine  `gorethink:\"query_engine\"`\n\tStorage storage `gorethink:\"storage_engine\"`\n}\n\ntype storage struct {\n\tCache cache `gorethink:\"cache\"`\n\tDisk  disk  `gorethink:\"disk\"`\n}\n\ntype cache struct {\n\tBytesInUse int64 `gorethink:\"in_use_bytes\"`\n}\n\ntype disk struct {\n\tReadBytesPerSec  int64      `gorethink:\"read_bytes_per_sec\"`\n\tReadBytesTotal   int64      `gorethink:\"read_bytes_total\"`\n\tWriteBytesPerSec int64      `gorethik:\"written_bytes_per_sec\"`\n\tWriteBytesTotal  int64      `gorethink:\"written_bytes_total\"`\n\tSpaceUsage       spaceUsage `gorethink:\"space_usage\"`\n}\n\ntype spaceUsage struct {\n\tData     int64 `gorethink:\"data_bytes\"`\n\tGarbage  int64 `gorethink:\"garbage_bytes\"`\n\tMetadata int64 `gorethink:\"metadata_bytes\"`\n\tPrealloc int64 `gorethink:\"preallocated_bytes\"`\n}\n\nvar engineStats = map[string]string{\n\t\"active_clients\":       \"ClientActive\",\n\t\"clients\":              \"ClientConns\",\n\t\"queries_per_sec\":      \"QueriesPerSec\",\n\t\"total_queries\":        \"TotalQueries\",\n\t\"read_docs_per_sec\":    \"ReadsPerSec\",\n\t\"total_reads\":          \"TotalReads\",\n\t\"written_docs_per_sec\": \"WritesPerSec\",\n\t\"total_writes\":         \"TotalWrites\",\n}\n\nfunc (e *engine) addEngineStats(keys []string, acc telegraf.Accumulator, tags map[string]string) {\n\tengine := reflect.ValueOf(e).Elem()\n\tfields := make(map[string]interface{})\n\tfor _, key := range keys {\n\t\tfields[key] = engine.FieldByName(engineStats[key]).Interface()\n\t}\n\tacc.AddFields(\"rethinkdb_engine\", fields, tags)\n}\n\nfunc (s *storage) addStats(acc telegraf.Accumulator, tags map[string]string) {\n\tfields := map[string]interface{}{\n\t\t\"cache_bytes_in_use\":            s.Cache.BytesInUse,\n\t\t\"disk_read_bytes_per_sec\":       s.Disk.ReadBytesPerSec,\n\t\t\"disk_read_bytes_total\":         s.Disk.ReadBytesTotal,\n\t\t\"disk_written_bytes_per_sec\":    s.Disk.WriteBytesPerSec,\n\t\t\"disk_written_bytes_total\":      s.Disk.WriteBytesTotal,\n\t\t\"disk_usage_data_bytes\":         s.Disk.SpaceUsage.Data,\n\t\t\"disk_usage_garbage_bytes\":      s.Disk.SpaceUsage.Garbage,\n\t\t\"disk_usage_metadata_bytes\":     s.Disk.SpaceUsage.Metadata,\n\t\t\"disk_usage_preallocated_bytes\": s.Disk.SpaceUsage.Prealloc,\n\t}\n\tacc.AddFields(\"rethinkdb\", fields, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb_data_test.go",
    "content": "package rethinkdb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar tags = make(map[string]string)\n\nfunc TestAddEngineStats(t *testing.T) {\n\tengine := &engine{\n\t\tClientConns:   0,\n\t\tClientActive:  0,\n\t\tQueriesPerSec: 0,\n\t\tTotalQueries:  0,\n\t\tReadsPerSec:   0,\n\t\tTotalReads:    0,\n\t\tWritesPerSec:  0,\n\t\tTotalWrites:   0,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tkeys := []string{\n\t\t\"active_clients\",\n\t\t\"clients\",\n\t\t\"queries_per_sec\",\n\t\t\"total_queries\",\n\t\t\"read_docs_per_sec\",\n\t\t\"total_reads\",\n\t\t\"written_docs_per_sec\",\n\t\t\"total_writes\",\n\t}\n\tengine.addEngineStats(keys, &acc, tags)\n\n\tfor _, metric := range keys {\n\t\trequire.True(t, acc.HasInt64Field(\"rethinkdb_engine\", metric))\n\t}\n}\n\nfunc TestAddEngineStatsPartial(t *testing.T) {\n\tengine := &engine{\n\t\tClientConns:   0,\n\t\tClientActive:  0,\n\t\tQueriesPerSec: 0,\n\t\tReadsPerSec:   0,\n\t\tWritesPerSec:  0,\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tkeys := []string{\n\t\t\"active_clients\",\n\t\t\"clients\",\n\t\t\"queries_per_sec\",\n\t\t\"read_docs_per_sec\",\n\t\t\"written_docs_per_sec\",\n\t}\n\n\tmissingKeys := []string{\n\t\t\"total_queries\",\n\t\t\"total_reads\",\n\t\t\"total_writes\",\n\t}\n\tengine.addEngineStats(keys, &acc, tags)\n\n\tfor _, metric := range missingKeys {\n\t\trequire.False(t, acc.HasInt64Field(\"rethinkdb\", metric))\n\t}\n}\n\nfunc TestAddStorageStats(t *testing.T) {\n\tstorage := &storage{\n\t\tCache: cache{\n\t\t\tBytesInUse: 0,\n\t\t},\n\t\tDisk: disk{\n\t\t\tReadBytesPerSec:  0,\n\t\t\tReadBytesTotal:   0,\n\t\t\tWriteBytesPerSec: 0,\n\t\t\tWriteBytesTotal:  0,\n\t\t\tSpaceUsage: spaceUsage{\n\t\t\t\tData:     0,\n\t\t\t\tGarbage:  0,\n\t\t\t\tMetadata: 0,\n\t\t\t\tPrealloc: 0,\n\t\t\t},\n\t\t},\n\t}\n\n\tvar acc testutil.Accumulator\n\n\tkeys := []string{\n\t\t\"cache_bytes_in_use\",\n\t\t\"disk_read_bytes_per_sec\",\n\t\t\"disk_read_bytes_total\",\n\t\t\"disk_written_bytes_per_sec\",\n\t\t\"disk_written_bytes_total\",\n\t\t\"disk_usage_data_bytes\",\n\t\t\"disk_usage_garbage_bytes\",\n\t\t\"disk_usage_metadata_bytes\",\n\t\t\"disk_usage_preallocated_bytes\",\n\t}\n\n\tstorage.addStats(&acc, tags)\n\n\tfor _, metric := range keys {\n\t\trequire.True(t, acc.HasInt64Field(\"rethinkdb\", metric))\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb_server.go",
    "content": "package rethinkdb\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gopkg.in/gorethink/gorethink.v3\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype server struct {\n\turl          *url.URL\n\tsession      *gorethink.Session\n\tserverStatus serverStatus\n}\n\nfunc (s *server) gatherData(acc telegraf.Accumulator) error {\n\tif err := s.getServerStatus(); err != nil {\n\t\treturn fmt.Errorf(\"failed to get server_status: %w\", err)\n\t}\n\n\tif err := s.validateVersion(); err != nil {\n\t\treturn fmt.Errorf(\"failed version validation: %w\", err)\n\t}\n\n\tif err := s.addClusterStats(acc); err != nil {\n\t\treturn fmt.Errorf(\"error adding cluster stats: %w\", err)\n\t}\n\n\tif err := s.addMemberStats(acc); err != nil {\n\t\treturn fmt.Errorf(\"error adding member stats: %w\", err)\n\t}\n\n\tif err := s.addTablesStats(acc); err != nil {\n\t\treturn fmt.Errorf(\"error adding table stats: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (s *server) validateVersion() error {\n\tif s.serverStatus.Process.Version == \"\" {\n\t\treturn errors.New(\"could not determine the RethinkDB server version: process.version key missing\")\n\t}\n\n\tversionRegexp := regexp.MustCompile(`\\d.\\d.\\d`)\n\tversionString := versionRegexp.FindString(s.serverStatus.Process.Version)\n\tif versionString == \"\" {\n\t\treturn fmt.Errorf(\"could not determine the RethinkDB server version: malformed version string (%v)\", s.serverStatus.Process.Version)\n\t}\n\n\tmajorVersion, err := strconv.Atoi(strings.Split(versionString, \"\")[0])\n\tif err != nil || majorVersion < 2 {\n\t\treturn fmt.Errorf(\"unsupported major version %s\", versionString)\n\t}\n\treturn nil\n}\n\nfunc (s *server) getServerStatus() error {\n\tcursor, err := gorethink.DB(\"rethinkdb\").Table(\"server_status\").Run(s.session)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cursor.IsNil() {\n\t\treturn errors.New(\"could not determine the RethinkDB server version: no rows returned from the server_status table\")\n\t}\n\tdefer cursor.Close()\n\tvar serverStatuses []serverStatus\n\terr = cursor.All(&serverStatuses)\n\tif err != nil {\n\t\treturn errors.New(\"could not parse server_status results\")\n\t}\n\thost, port, err := net.SplitHostPort(s.url.Host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to determine provided hostname from %s\", s.url.Host)\n\t}\n\tdriverPort, err := strconv.Atoi(port)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to parse port from %s: %w\", port, err)\n\t}\n\tfor _, ss := range serverStatuses {\n\t\tfor _, address := range ss.Network.Addresses {\n\t\t\tif address.Host == host && ss.Network.DriverPort == driverPort {\n\t\t\t\ts.serverStatus = ss\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"unable to determine host id from server_status with %s\", s.url.Host)\n}\n\nfunc (s *server) getDefaultTags() map[string]string {\n\ttags := make(map[string]string)\n\ttags[\"rethinkdb_host\"] = s.url.Host\n\ttags[\"rethinkdb_hostname\"] = s.serverStatus.Network.Hostname\n\treturn tags\n}\n\nvar clusterTracking = []string{\n\t\"active_clients\",\n\t\"clients\",\n\t\"queries_per_sec\",\n\t\"read_docs_per_sec\",\n\t\"written_docs_per_sec\",\n}\n\nfunc (s *server) addClusterStats(acc telegraf.Accumulator) error {\n\tcursor, err := gorethink.DB(\"rethinkdb\").Table(\"stats\").Get([]string{\"cluster\"}).Run(s.session)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cluster stats query error: %w\", err)\n\t}\n\tdefer cursor.Close()\n\tvar clusterStats stats\n\tif err := cursor.One(&clusterStats); err != nil {\n\t\treturn fmt.Errorf(\"failure to parse cluster stats: %w\", err)\n\t}\n\n\ttags := s.getDefaultTags()\n\ttags[\"type\"] = \"cluster\"\n\tclusterStats.Engine.addEngineStats(clusterTracking, acc, tags)\n\treturn nil\n}\n\nvar memberTracking = []string{\n\t\"active_clients\",\n\t\"clients\",\n\t\"queries_per_sec\",\n\t\"total_queries\",\n\t\"read_docs_per_sec\",\n\t\"total_reads\",\n\t\"written_docs_per_sec\",\n\t\"total_writes\",\n}\n\nfunc (s *server) addMemberStats(acc telegraf.Accumulator) error {\n\tcursor, err := gorethink.DB(\"rethinkdb\").Table(\"stats\").Get([]string{\"server\", s.serverStatus.ID}).Run(s.session)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"member stats query error: %w\", err)\n\t}\n\tdefer cursor.Close()\n\tvar memberStats stats\n\tif err := cursor.One(&memberStats); err != nil {\n\t\treturn fmt.Errorf(\"failure to parse member stats: %w\", err)\n\t}\n\n\ttags := s.getDefaultTags()\n\ttags[\"type\"] = \"member\"\n\tmemberStats.Engine.addEngineStats(memberTracking, acc, tags)\n\treturn nil\n}\n\nvar tableTracking = []string{\n\t\"read_docs_per_sec\",\n\t\"total_reads\",\n\t\"written_docs_per_sec\",\n\t\"total_writes\",\n}\n\nfunc (s *server) addTablesStats(acc telegraf.Accumulator) error {\n\ttablesCursor, err := gorethink.DB(\"rethinkdb\").Table(\"table_status\").Run(s.session)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"table stats query error: %w\", err)\n\t}\n\n\tdefer tablesCursor.Close()\n\tvar tables []tableStatus\n\terr = tablesCursor.All(&tables)\n\tif err != nil {\n\t\treturn errors.New(\"could not parse table_status results\")\n\t}\n\tfor _, table := range tables {\n\t\terr = s.addTableStats(acc, table)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *server) addTableStats(acc telegraf.Accumulator, table tableStatus) error {\n\tcursor, err := gorethink.DB(\"rethinkdb\").Table(\"stats\").\n\t\tGet([]string{\"table_server\", table.ID, s.serverStatus.ID}).\n\t\tRun(s.session)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"table stats query error: %w\", err)\n\t}\n\tdefer cursor.Close()\n\n\tvar ts tableStats\n\tif err := cursor.One(&ts); err != nil {\n\t\treturn fmt.Errorf(\"failure to parse table stats: %w\", err)\n\t}\n\n\ttags := s.getDefaultTags()\n\ttags[\"type\"] = \"data\"\n\ttags[\"ns\"] = fmt.Sprintf(\"%s.%s\", table.DB, table.Name)\n\tts.Engine.addEngineStats(tableTracking, acc, tags)\n\tts.Storage.addStats(acc, tags)\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb_server_test.go",
    "content": "//go:build integration\n\npackage rethinkdb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestValidateVersion(t *testing.T) {\n\terr := server.validateVersion()\n\trequire.NoError(t, err)\n}\n\nfunc TestGetDefaultTags(t *testing.T) {\n\tvar tagTests = []struct {\n\t\tin  string\n\t\tout string\n\t}{\n\t\t{\"rethinkdb_host\", server.Url.Host},\n\t\t{\"rethinkdb_hostname\", server.serverStatus.Network.Hostname},\n\t}\n\tdefaultTags := server.getDefaultTags()\n\tfor _, tt := range tagTests {\n\t\tif defaultTags[tt.in] != tt.out {\n\t\t\tt.Errorf(\"expected %q, got %q\", tt.out, defaultTags[tt.in])\n\t\t}\n\t}\n}\n\nfunc TestAddClusterStats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\terr := server.addClusterStats(&acc)\n\trequire.NoError(t, err)\n\n\tfor _, metric := range clusterTracking {\n\t\trequire.True(t, acc.HasIntValue(metric))\n\t}\n}\n\nfunc TestAddMemberStats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\terr := server.addMemberStats(&acc)\n\trequire.NoError(t, err)\n\n\tfor _, metric := range memberTracking {\n\t\trequire.True(t, acc.HasIntValue(metric))\n\t}\n}\n\nfunc TestAddTableStats(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\terr := server.addTableStats(&acc)\n\trequire.NoError(t, err)\n\n\tfor _, metric := range tableTracking {\n\t\trequire.True(t, acc.HasIntValue(metric))\n\t}\n\n\tkeys := []string{\n\t\t\"cache_bytes_in_use\",\n\t\t\"disk_read_bytes_per_sec\",\n\t\t\"disk_read_bytes_total\",\n\t\t\"disk_written_bytes_per_sec\",\n\t\t\"disk_written_bytes_total\",\n\t\t\"disk_usage_data_bytes\",\n\t\t\"disk_usage_garbage_bytes\",\n\t\t\"disk_usage_metadata_bytes\",\n\t\t\"disk_usage_preallocated_bytes\",\n\t}\n\n\tfor _, metric := range keys {\n\t\trequire.True(t, acc.HasIntValue(metric))\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/rethinkdb_test.go",
    "content": "//go:build integration\n\npackage rethinkdb\n\nimport (\n\t\"log\"\n\t\"math/rand\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"gopkg.in/gorethink/gorethink.v3\"\n)\n\nvar connect_url, authKey, username, password string\nvar server *server\n\nfunc init() {\n\tconnect_url = os.Getenv(\"RETHINKDB_URL\")\n\tif connect_url == \"\" {\n\t\tconnect_url = \"127.0.0.1:28015\"\n\t}\n\tauthKey = os.Getenv(\"RETHINKDB_AUTHKEY\")\n\tusername = os.Getenv(\"RETHINKDB_USERNAME\")\n\tpassword = os.Getenv(\"RETHINKDB_PASSWORD\")\n}\n\nfunc testSetup(m *testing.M) {\n\tvar err error\n\tserver = &server{url: &url.URL{Host: connect_url}}\n\n\tif authKey {\n\t\tserver.session, _ = gorethink.Connect(gorethink.ConnectOpts{\n\t\t\tAddress:          server.url.Host,\n\t\t\tAuthKey:          authKey,\n\t\t\tHandshakeVersion: gorethink.HandshakeV0_4,\n\t\t\tDiscoverHosts:    false,\n\t\t})\n\t} else {\n\t\tserver.session, _ = gorethink.Connect(gorethink.ConnectOpts{\n\t\t\tAddress:          server.url.Host,\n\t\t\tUsername:         username,\n\t\t\tPassword:         password,\n\t\t\tHandshakeVersion: gorethink.HandshakeV1_0,\n\t\t\tDiscoverHosts:    false,\n\t\t})\n\t}\n\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n\n\terr = server.getServerStatus()\n\tif err != nil {\n\t\tlog.Fatalln(err.Error())\n\t}\n}\n\nfunc testTeardown(m *testing.M) {\n\tserver.session.Close()\n}\n\nfunc TestMain(m *testing.M) {\n\t// seed randomness for use with tests\n\trand.Seed(time.Now().UTC().UnixNano())\n\n\ttestSetup(m)\n\tres := m.Run()\n\ttestTeardown(m)\n\n\tos.Exit(res)\n}\n"
  },
  {
    "path": "plugins/inputs/rethinkdb/sample.conf",
    "content": "# Read metrics from one or many RethinkDB servers\n[[inputs.rethinkdb]]\n  ## An array of URI to gather stats about. Specify an ip or hostname\n  ## with optional port add password. ie,\n  ##   rethinkdb://user:auth_key@10.10.3.30:28105,\n  ##   rethinkdb://10.10.3.33:18832,\n  ## For rethinkdb v2.3.0+ with username/password authorization you should use\n  ##   rethinkdb2://username:password@127.0.0.1:28015\"\n  servers = [\"127.0.0.1:28015\"]\n"
  },
  {
    "path": "plugins/inputs/riak/README.md",
    "content": "# Riak Input Plugin\n\nThis plugin gathers metrics from [Riak][riak] instances.\n\n⭐ Telegraf v0.10.4\n🏷️ server\n💻 all\n\n[riak]: https://riak.com/\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics one or many Riak servers\n[[inputs.riak]]\n  # Specify a list of one or more riak http servers\n  servers = [\"http://localhost:8098\"]\n```\n\n## Metrics\n\n- riak:\n  - tags:\n    - server   (host:port of the given server address)\n    - nodename (internal node name received)\n  - fields\n    - cpu_avg1\n    - cpu_avg15\n    - cpu_avg5\n    - memory_code\n    - memory_ets\n    - memory_processes\n    - memory_system\n    - memory_total\n    - node_get_fsm_objsize_100\n    - node_get_fsm_objsize_95\n    - node_get_fsm_objsize_99\n    - node_get_fsm_objsize_mean\n    - node_get_fsm_objsize_median\n    - node_get_fsm_siblings_100\n    - node_get_fsm_siblings_95\n    - node_get_fsm_siblings_99\n    - node_get_fsm_siblings_mean\n    - node_get_fsm_siblings_median\n    - node_get_fsm_time_100\n    - node_get_fsm_time_95\n    - node_get_fsm_time_99\n    - node_get_fsm_time_mean\n    - node_get_fsm_time_median\n    - node_gets\n    - node_gets_total\n    - node_put_fsm_time_100\n    - node_put_fsm_time_95\n    - node_put_fsm_time_99\n    - node_put_fsm_time_mean\n    - node_put_fsm_time_median\n    - node_puts\n    - node_puts_total\n    - pbc_active\n    - pbc_connects\n    - pbc_connects_total\n    - vnode_gets\n    - vnode_gets_total\n    - vnode_index_reads\n    - vnode_index_reads_total\n    - vnode_index_writes\n    - vnode_index_writes_total\n    - vnode_puts\n    - vnode_puts_total\n    - read_repairs\n    - read_repairs_total\n\nTime fields such as `node_get_fsm_time_mean` are measured in nanoseconds.\n\n## Example Output\n\n```text\nriak,nodename=riak@127.0.0.1,server=localhost:8098 cpu_avg1=31i,cpu_avg15=69i,cpu_avg5=51i,memory_code=11563738i,memory_ets=5925872i,memory_processes=30236069i,memory_system=93074971i,memory_total=123311040i,node_get_fsm_objsize_100=0i,node_get_fsm_objsize_95=0i,node_get_fsm_objsize_99=0i,node_get_fsm_objsize_mean=0i,node_get_fsm_objsize_median=0i,node_get_fsm_siblings_100=0i,node_get_fsm_siblings_95=0i,node_get_fsm_siblings_99=0i,node_get_fsm_siblings_mean=0i,node_get_fsm_siblings_median=0i,node_get_fsm_time_100=0i,node_get_fsm_time_95=0i,node_get_fsm_time_99=0i,node_get_fsm_time_mean=0i,node_get_fsm_time_median=0i,node_gets=0i,node_gets_total=19i,node_put_fsm_time_100=0i,node_put_fsm_time_95=0i,node_put_fsm_time_99=0i,node_put_fsm_time_mean=0i,node_put_fsm_time_median=0i,node_puts=0i,node_puts_total=0i,pbc_active=0i,pbc_connects=0i,pbc_connects_total=20i,vnode_gets=0i,vnode_gets_total=57i,vnode_index_reads=0i,vnode_index_reads_total=0i,vnode_index_writes=0i,vnode_index_writes_total=0i,vnode_puts=0i,vnode_puts_total=0i,read_repair=0i,read_repairs_total=0i 1455913392622482332\n```\n"
  },
  {
    "path": "plugins/inputs/riak/riak.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage riak\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Riak struct {\n\t// Servers is a slice of servers as http addresses (ex. http://127.0.0.1:8098)\n\tServers []string `toml:\"servers\"`\n\n\tclient *http.Client\n}\n\n// Type riakStats represents the data received from Riak\ntype riakStats struct {\n\tCPUAvg1                  int64  `json:\"cpu_avg1\"`\n\tCPUAvg15                 int64  `json:\"cpu_avg15\"`\n\tCPUAvg5                  int64  `json:\"cpu_avg5\"`\n\tMemoryCode               int64  `json:\"memory_code\"`\n\tMemoryEts                int64  `json:\"memory_ets\"`\n\tMemoryProcesses          int64  `json:\"memory_processes\"`\n\tMemorySystem             int64  `json:\"memory_system\"`\n\tMemoryTotal              int64  `json:\"memory_total\"`\n\tNodeGetFsmObjsize100     int64  `json:\"node_get_fsm_objsize_100\"`\n\tNodeGetFsmObjsize95      int64  `json:\"node_get_fsm_objsize_95\"`\n\tNodeGetFsmObjsize99      int64  `json:\"node_get_fsm_objsize_99\"`\n\tNodeGetFsmObjsizeMean    int64  `json:\"node_get_fsm_objsize_mean\"`\n\tNodeGetFsmObjsizeMedian  int64  `json:\"node_get_fsm_objsize_median\"`\n\tNodeGetFsmSiblings100    int64  `json:\"node_get_fsm_siblings_100\"`\n\tNodeGetFsmSiblings95     int64  `json:\"node_get_fsm_siblings_95\"`\n\tNodeGetFsmSiblings99     int64  `json:\"node_get_fsm_siblings_99\"`\n\tNodeGetFsmSiblingsMean   int64  `json:\"node_get_fsm_siblings_mean\"`\n\tNodeGetFsmSiblingsMedian int64  `json:\"node_get_fsm_siblings_median\"`\n\tNodeGetFsmTime100        int64  `json:\"node_get_fsm_time_100\"`\n\tNodeGetFsmTime95         int64  `json:\"node_get_fsm_time_95\"`\n\tNodeGetFsmTime99         int64  `json:\"node_get_fsm_time_99\"`\n\tNodeGetFsmTimeMean       int64  `json:\"node_get_fsm_time_mean\"`\n\tNodeGetFsmTimeMedian     int64  `json:\"node_get_fsm_time_median\"`\n\tNodeGets                 int64  `json:\"node_gets\"`\n\tNodeGetsTotal            int64  `json:\"node_gets_total\"`\n\tNodename                 string `json:\"nodename\"`\n\tNodePutFsmTime100        int64  `json:\"node_put_fsm_time_100\"`\n\tNodePutFsmTime95         int64  `json:\"node_put_fsm_time_95\"`\n\tNodePutFsmTime99         int64  `json:\"node_put_fsm_time_99\"`\n\tNodePutFsmTimeMean       int64  `json:\"node_put_fsm_time_mean\"`\n\tNodePutFsmTimeMedian     int64  `json:\"node_put_fsm_time_median\"`\n\tNodePuts                 int64  `json:\"node_puts\"`\n\tNodePutsTotal            int64  `json:\"node_puts_total\"`\n\tPbcActive                int64  `json:\"pbc_active\"`\n\tPbcConnects              int64  `json:\"pbc_connects\"`\n\tPbcConnectsTotal         int64  `json:\"pbc_connects_total\"`\n\tVnodeGets                int64  `json:\"vnode_gets\"`\n\tVnodeGetsTotal           int64  `json:\"vnode_gets_total\"`\n\tVnodeIndexReads          int64  `json:\"vnode_index_reads\"`\n\tVnodeIndexReadsTotal     int64  `json:\"vnode_index_reads_total\"`\n\tVnodeIndexWrites         int64  `json:\"vnode_index_writes\"`\n\tVnodeIndexWritesTotal    int64  `json:\"vnode_index_writes_total\"`\n\tVnodePuts                int64  `json:\"vnode_puts\"`\n\tVnodePutsTotal           int64  `json:\"vnode_puts_total\"`\n\tReadRepairs              int64  `json:\"read_repairs\"`\n\tReadRepairsTotal         int64  `json:\"read_repairs_total\"`\n}\n\nfunc (*Riak) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (r *Riak) Gather(acc telegraf.Accumulator) error {\n\t// Default to a single server at localhost (default port) if none specified\n\tif len(r.Servers) == 0 {\n\t\tr.Servers = []string{\"http://127.0.0.1:8098\"}\n\t}\n\n\t// Range over all servers, gathering stats. Returns early in case of any error.\n\tfor _, s := range r.Servers {\n\t\tacc.AddError(r.gatherServer(s, acc))\n\t}\n\n\treturn nil\n}\n\nfunc (r *Riak) gatherServer(s string, acc telegraf.Accumulator) error {\n\t// Parse the given URL to extract the server tag\n\tu, err := url.Parse(s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"riak unable to parse given server URL %q: %w\", s, err)\n\t}\n\n\t// Perform the GET request to the riak /stats endpoint\n\tresp, err := r.client.Get(s + \"/stats\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\t// Successful responses will always return status code 200\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"riak responded with unexpected status code %d\", resp.StatusCode)\n\t}\n\n\t// Decode the response JSON into a new stats struct\n\tstats := &riakStats{}\n\tif err := json.NewDecoder(resp.Body).Decode(stats); err != nil {\n\t\treturn fmt.Errorf(\"unable to decode riak response: %w\", err)\n\t}\n\n\t// Build a map of tags\n\ttags := map[string]string{\n\t\t\"nodename\": stats.Nodename,\n\t\t\"server\":   u.Host,\n\t}\n\n\t// Build a map of field values\n\tfields := map[string]interface{}{\n\t\t\"cpu_avg1\":                     stats.CPUAvg1,\n\t\t\"cpu_avg15\":                    stats.CPUAvg15,\n\t\t\"cpu_avg5\":                     stats.CPUAvg5,\n\t\t\"memory_code\":                  stats.MemoryCode,\n\t\t\"memory_ets\":                   stats.MemoryEts,\n\t\t\"memory_processes\":             stats.MemoryProcesses,\n\t\t\"memory_system\":                stats.MemorySystem,\n\t\t\"memory_total\":                 stats.MemoryTotal,\n\t\t\"node_get_fsm_objsize_100\":     stats.NodeGetFsmObjsize100,\n\t\t\"node_get_fsm_objsize_95\":      stats.NodeGetFsmObjsize95,\n\t\t\"node_get_fsm_objsize_99\":      stats.NodeGetFsmObjsize99,\n\t\t\"node_get_fsm_objsize_mean\":    stats.NodeGetFsmObjsizeMean,\n\t\t\"node_get_fsm_objsize_median\":  stats.NodeGetFsmObjsizeMedian,\n\t\t\"node_get_fsm_siblings_100\":    stats.NodeGetFsmSiblings100,\n\t\t\"node_get_fsm_siblings_95\":     stats.NodeGetFsmSiblings95,\n\t\t\"node_get_fsm_siblings_99\":     stats.NodeGetFsmSiblings99,\n\t\t\"node_get_fsm_siblings_mean\":   stats.NodeGetFsmSiblingsMean,\n\t\t\"node_get_fsm_siblings_median\": stats.NodeGetFsmSiblingsMedian,\n\t\t\"node_get_fsm_time_100\":        stats.NodeGetFsmTime100,\n\t\t\"node_get_fsm_time_95\":         stats.NodeGetFsmTime95,\n\t\t\"node_get_fsm_time_99\":         stats.NodeGetFsmTime99,\n\t\t\"node_get_fsm_time_mean\":       stats.NodeGetFsmTimeMean,\n\t\t\"node_get_fsm_time_median\":     stats.NodeGetFsmTimeMedian,\n\t\t\"node_gets\":                    stats.NodeGets,\n\t\t\"node_gets_total\":              stats.NodeGetsTotal,\n\t\t\"node_put_fsm_time_100\":        stats.NodePutFsmTime100,\n\t\t\"node_put_fsm_time_95\":         stats.NodePutFsmTime95,\n\t\t\"node_put_fsm_time_99\":         stats.NodePutFsmTime99,\n\t\t\"node_put_fsm_time_mean\":       stats.NodePutFsmTimeMean,\n\t\t\"node_put_fsm_time_median\":     stats.NodePutFsmTimeMedian,\n\t\t\"node_puts\":                    stats.NodePuts,\n\t\t\"node_puts_total\":              stats.NodePutsTotal,\n\t\t\"pbc_active\":                   stats.PbcActive,\n\t\t\"pbc_connects\":                 stats.PbcConnects,\n\t\t\"pbc_connects_total\":           stats.PbcConnectsTotal,\n\t\t\"vnode_gets\":                   stats.VnodeGets,\n\t\t\"vnode_gets_total\":             stats.VnodeGetsTotal,\n\t\t\"vnode_index_reads\":            stats.VnodeIndexReads,\n\t\t\"vnode_index_reads_total\":      stats.VnodeIndexReadsTotal,\n\t\t\"vnode_index_writes\":           stats.VnodeIndexWrites,\n\t\t\"vnode_index_writes_total\":     stats.VnodeIndexWritesTotal,\n\t\t\"vnode_puts\":                   stats.VnodePuts,\n\t\t\"vnode_puts_total\":             stats.VnodePutsTotal,\n\t\t\"read_repairs\":                 stats.ReadRepairs,\n\t\t\"read_repairs_total\":           stats.ReadRepairsTotal,\n\t}\n\n\t// Accumulate the tags and values\n\tacc.AddFields(\"riak\", fields, tags)\n\n\treturn nil\n}\n\n// newRiak return a new instance of Riak with a default http client\nfunc newRiak() *Riak {\n\ttr := &http.Transport{ResponseHeaderTimeout: 3 * time.Second}\n\tclient := &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   4 * time.Second,\n\t}\n\treturn &Riak{client: client}\n}\n\nfunc init() {\n\tinputs.Add(\"riak\", func() telegraf.Input {\n\t\treturn newRiak()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/riak/riak_test.go",
    "content": "package riak\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestRiak(t *testing.T) {\n\t// Create a test server with the const response JSON\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tif _, err := fmt.Fprintln(w, response); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer ts.Close()\n\n\t// Parse the URL of the test server, used to verify the expected host\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\t// Create a new Riak instance with our given test server\n\triak := newRiak()\n\triak.Servers = []string{ts.URL}\n\n\t// Create a test accumulator\n\tacc := &testutil.Accumulator{}\n\n\t// Gather data from the test server\n\trequire.NoError(t, riak.Gather(acc))\n\n\t// Expect the correct values for all known keys\n\texpectFields := map[string]interface{}{\n\t\t\"cpu_avg1\":                     int64(504),\n\t\t\"cpu_avg15\":                    int64(294),\n\t\t\"cpu_avg5\":                     int64(325),\n\t\t\"memory_code\":                  int64(12329143),\n\t\t\"memory_ets\":                   int64(17330176),\n\t\t\"memory_processes\":             int64(58454730),\n\t\t\"memory_system\":                int64(120401678),\n\t\t\"memory_total\":                 int64(178856408),\n\t\t\"node_get_fsm_objsize_100\":     int64(73596),\n\t\t\"node_get_fsm_objsize_95\":      int64(36663),\n\t\t\"node_get_fsm_objsize_99\":      int64(51552),\n\t\t\"node_get_fsm_objsize_mean\":    int64(13241),\n\t\t\"node_get_fsm_objsize_median\":  int64(10365),\n\t\t\"node_get_fsm_siblings_100\":    int64(1),\n\t\t\"node_get_fsm_siblings_95\":     int64(1),\n\t\t\"node_get_fsm_siblings_99\":     int64(1),\n\t\t\"node_get_fsm_siblings_mean\":   int64(1),\n\t\t\"node_get_fsm_siblings_median\": int64(1),\n\t\t\"node_get_fsm_time_100\":        int64(230445),\n\t\t\"node_get_fsm_time_95\":         int64(24259),\n\t\t\"node_get_fsm_time_99\":         int64(96653),\n\t\t\"node_get_fsm_time_mean\":       int64(6851),\n\t\t\"node_get_fsm_time_median\":     int64(2368),\n\t\t\"node_gets\":                    int64(1116),\n\t\t\"node_gets_total\":              int64(1026058217),\n\t\t\"node_put_fsm_time_100\":        int64(267390),\n\t\t\"node_put_fsm_time_95\":         int64(38286),\n\t\t\"node_put_fsm_time_99\":         int64(84422),\n\t\t\"node_put_fsm_time_mean\":       int64(10832),\n\t\t\"node_put_fsm_time_median\":     int64(4085),\n\t\t\"read_repairs\":                 int64(2),\n\t\t\"read_repairs_total\":           int64(7918375),\n\t\t\"node_puts\":                    int64(1155),\n\t\t\"node_puts_total\":              int64(444895769),\n\t\t\"pbc_active\":                   int64(360),\n\t\t\"pbc_connects\":                 int64(120),\n\t\t\"pbc_connects_total\":           int64(66793268),\n\t\t\"vnode_gets\":                   int64(14629),\n\t\t\"vnode_gets_total\":             int64(3748432761),\n\t\t\"vnode_index_reads\":            int64(20),\n\t\t\"vnode_index_reads_total\":      int64(3438296),\n\t\t\"vnode_index_writes\":           int64(4293),\n\t\t\"vnode_index_writes_total\":     int64(1515986619),\n\t\t\"vnode_puts\":                   int64(4308),\n\t\t\"vnode_puts_total\":             int64(1519062272),\n\t}\n\n\t// Expect the correct values for all tags\n\texpectTags := map[string]string{\n\t\t\"nodename\": \"riak@127.0.0.1\",\n\t\t\"server\":   u.Host,\n\t}\n\n\tacc.AssertContainsTaggedFields(t, \"riak\", expectFields, expectTags)\n}\n\nvar response = `\n{\n  \"riak_kv_stat_ts\": 1455908558,\n  \"vnode_gets\": 14629,\n  \"vnode_gets_total\": 3748432761,\n  \"vnode_puts\": 4308,\n  \"vnode_puts_total\": 1519062272,\n  \"vnode_index_refreshes\": 0,\n  \"vnode_index_refreshes_total\": 0,\n  \"vnode_index_reads\": 20,\n  \"vnode_index_reads_total\": 3438296,\n  \"vnode_index_writes\": 4293,\n  \"vnode_index_writes_total\": 1515986619,\n  \"vnode_index_writes_postings\": 1,\n  \"vnode_index_writes_postings_total\": 265613,\n  \"vnode_index_deletes\": 0,\n  \"vnode_index_deletes_total\": 0,\n  \"vnode_index_deletes_postings\": 0,\n  \"vnode_index_deletes_postings_total\": 1,\n  \"node_gets\": 1116,\n  \"node_gets_total\": 1026058217,\n  \"node_get_fsm_siblings_mean\": 1,\n  \"node_get_fsm_siblings_median\": 1,\n  \"node_get_fsm_siblings_95\": 1,\n  \"node_get_fsm_siblings_99\": 1,\n  \"node_get_fsm_siblings_100\": 1,\n  \"node_get_fsm_objsize_mean\": 13241,\n  \"node_get_fsm_objsize_median\": 10365,\n  \"node_get_fsm_objsize_95\": 36663,\n  \"node_get_fsm_objsize_99\": 51552,\n  \"node_get_fsm_objsize_100\": 73596,\n  \"node_get_fsm_time_mean\": 6851,\n  \"node_get_fsm_time_median\": 2368,\n  \"node_get_fsm_time_95\": 24259,\n  \"node_get_fsm_time_99\": 96653,\n  \"node_get_fsm_time_100\": 230445,\n  \"node_puts\": 1155,\n  \"node_puts_total\": 444895769,\n  \"node_put_fsm_time_mean\": 10832,\n  \"node_put_fsm_time_median\": 4085,\n  \"node_put_fsm_time_95\": 38286,\n  \"node_put_fsm_time_99\": 84422,\n  \"node_put_fsm_time_100\": 267390,\n  \"read_repairs\": 2,\n  \"read_repairs_total\": 7918375,\n  \"coord_redirs_total\": 118238575,\n  \"executing_mappers\": 0,\n  \"precommit_fail\": 0,\n  \"postcommit_fail\": 0,\n  \"index_fsm_create\": 0,\n  \"index_fsm_create_error\": 0,\n  \"index_fsm_active\": 0,\n  \"list_fsm_create\": 0,\n  \"list_fsm_create_error\": 0,\n  \"list_fsm_active\": 0,\n  \"pbc_active\": 360,\n  \"pbc_connects\": 120,\n  \"pbc_connects_total\": 66793268,\n  \"late_put_fsm_coordinator_ack\": 152,\n  \"node_get_fsm_active\": 1,\n  \"node_get_fsm_active_60s\": 1029,\n  \"node_get_fsm_in_rate\": 21,\n  \"node_get_fsm_out_rate\": 21,\n  \"node_get_fsm_rejected\": 0,\n  \"node_get_fsm_rejected_60s\": 0,\n  \"node_get_fsm_rejected_total\": 0,\n  \"node_put_fsm_active\": 69,\n  \"node_put_fsm_active_60s\": 1053,\n  \"node_put_fsm_in_rate\": 30,\n  \"node_put_fsm_out_rate\": 31,\n  \"node_put_fsm_rejected\": 0,\n  \"node_put_fsm_rejected_60s\": 0,\n  \"node_put_fsm_rejected_total\": 0,\n  \"read_repairs_primary_outofdate_one\": 4,\n  \"read_repairs_primary_outofdate_count\": 14761552,\n  \"read_repairs_primary_notfound_one\": 0,\n  \"read_repairs_primary_notfound_count\": 65879,\n  \"read_repairs_fallback_outofdate_one\": 0,\n  \"read_repairs_fallback_outofdate_count\": 23761,\n  \"read_repairs_fallback_notfound_one\": 0,\n  \"read_repairs_fallback_notfound_count\": 455697,\n  \"leveldb_read_block_error\": 0,\n  \"riak_pipe_stat_ts\": 1455908558,\n  \"pipeline_active\": 0,\n  \"pipeline_create_count\": 0,\n  \"pipeline_create_one\": 0,\n  \"pipeline_create_error_count\": 0,\n  \"pipeline_create_error_one\": 0,\n  \"cpu_nprocs\": 362,\n  \"cpu_avg1\": 504,\n  \"cpu_avg5\": 325,\n  \"cpu_avg15\": 294,\n  \"mem_total\": 33695432704,\n  \"mem_allocated\": 33454874624,\n  \"nodename\": \"riak@127.0.0.1\",\n  \"connected_nodes\": [],\n  \"sys_driver_version\": \"2.0\",\n  \"sys_global_heaps_size\": 0,\n  \"sys_heap_type\": \"private\",\n  \"sys_logical_processors\": 8,\n  \"sys_otp_release\": \"R15B01\",\n  \"sys_process_count\": 2201,\n  \"sys_smp_support\": true,\n  \"sys_system_version\": \"Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:8:8] [async-threads:64] [kernel-poll:true]\",\n  \"sys_system_architecture\": \"x86_64-unknown-linux-gnu\",\n  \"sys_threads_enabled\": true,\n  \"sys_thread_pool_size\": 64,\n  \"sys_wordsize\": 8,\n  \"ring_members\": [\n    \"riak@127.0.0.1\"\n  ],\n  \"ring_num_partitions\": 256,\n  \"ring_ownership\": \"[{'riak@127.0.0.1',256}]\",\n  \"ring_creation_size\": 256,\n  \"storage_backend\": \"riak_kv_eleveldb_backend\",\n  \"erlydtl_version\": \"0.7.0\",\n  \"riak_control_version\": \"1.4.12-0-g964c5db\",\n  \"cluster_info_version\": \"1.2.4\",\n  \"riak_search_version\": \"1.4.12-0-g7fe0e00\",\n  \"merge_index_version\": \"1.3.2-0-gcb38ee7\",\n  \"riak_kv_version\": \"1.4.12-0-gc6bbd66\",\n  \"sidejob_version\": \"0.2.0\",\n  \"riak_api_version\": \"1.4.12-0-gd9e1cc8\",\n  \"riak_pipe_version\": \"1.4.12-0-g986a226\",\n  \"riak_core_version\": \"1.4.10\",\n  \"bitcask_version\": \"1.6.8-0-gea14cb0\",\n  \"basho_stats_version\": \"1.0.3\",\n  \"webmachine_version\": \"1.10.4-0-gfcff795\",\n  \"mochiweb_version\": \"1.5.1p6\",\n  \"inets_version\": \"5.9\",\n  \"erlang_js_version\": \"1.2.2\",\n  \"runtime_tools_version\": \"1.8.8\",\n  \"os_mon_version\": \"2.2.9\",\n  \"riak_sysmon_version\": \"1.1.3\",\n  \"ssl_version\": \"5.0.1\",\n  \"public_key_version\": \"0.15\",\n  \"crypto_version\": \"2.1\",\n  \"sasl_version\": \"2.2.1\",\n  \"lager_version\": \"2.0.1\",\n  \"goldrush_version\": \"0.1.5\",\n  \"compiler_version\": \"4.8.1\",\n  \"syntax_tools_version\": \"1.6.8\",\n  \"stdlib_version\": \"1.18.1\",\n  \"kernel_version\": \"2.15.1\",\n  \"memory_total\": 178856408,\n  \"memory_processes\": 58454730,\n  \"memory_processes_used\": 58371238,\n  \"memory_system\": 120401678,\n  \"memory_atom\": 586345,\n  \"memory_atom_used\": 563485,\n  \"memory_binary\": 48677920,\n  \"memory_code\": 12329143,\n  \"memory_ets\": 17330176,\n  \"riak_core_stat_ts\": 1455908559,\n  \"ignored_gossip_total\": 0,\n  \"rings_reconciled_total\": 5459,\n  \"rings_reconciled\": 0,\n  \"gossip_received\": 6,\n  \"rejected_handoffs\": 94,\n  \"handoff_timeouts\": 0,\n  \"dropped_vnode_requests_total\": 0,\n  \"converge_delay_min\": 0,\n  \"converge_delay_max\": 0,\n  \"converge_delay_mean\": 0,\n  \"converge_delay_last\": 0,\n  \"rebalance_delay_min\": 0,\n  \"rebalance_delay_max\": 0,\n  \"rebalance_delay_mean\": 0,\n  \"rebalance_delay_last\": 0,\n  \"riak_kv_vnodes_running\": 16,\n  \"riak_kv_vnodeq_min\": 0,\n  \"riak_kv_vnodeq_median\": 0,\n  \"riak_kv_vnodeq_mean\": 0,\n  \"riak_kv_vnodeq_max\": 0,\n  \"riak_kv_vnodeq_total\": 0,\n  \"riak_pipe_vnodes_running\": 16,\n  \"riak_pipe_vnodeq_min\": 0,\n  \"riak_pipe_vnodeq_median\": 0,\n  \"riak_pipe_vnodeq_mean\": 0,\n  \"riak_pipe_vnodeq_max\": 0,\n  \"riak_pipe_vnodeq_total\": 0\n}\n`\n"
  },
  {
    "path": "plugins/inputs/riak/sample.conf",
    "content": "# Read metrics one or many Riak servers\n[[inputs.riak]]\n  # Specify a list of one or more riak http servers\n  servers = [\"http://localhost:8098\"]\n"
  },
  {
    "path": "plugins/inputs/riemann_listener/README.md",
    "content": "# Riemann Listener Input Plugin\n\nThis service plugin listens for messages from [Riemann][riemann] clients using\nthe protocol buffer format.\n\n⭐ Telegraf v1.17.0\n🏷️ datastore\n💻 all\n\n[riemann]: https://riemann.io/\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Riemann protobuff listener\n[[inputs.riemann_listener]]\n  ## URL to listen on\n  ## Default is \"tcp://:5555\"\n  #  service_address = \"tcp://:8094\"\n  #  service_address = \"tcp://127.0.0.1:http\"\n  #  service_address = \"tcp4://:8094\"\n  #  service_address = \"tcp6://:8094\"\n  #  service_address = \"tcp6://[2001:db8::1]:8094\"\n\n  ## Maximum number of concurrent connections.\n  ## 0 (default) is unlimited.\n  #  max_connections = 1024\n  ## Read timeout.\n  ## 0 (default) is unlimited.\n  #  read_timeout = \"30s\"\n  ## Optional TLS configuration.\n  #  tls_cert = \"/etc/telegraf/cert.pem\"\n  #  tls_key  = \"/etc/telegraf/key.pem\"\n  ## Enables client authentication if set.\n  #  tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n  ## Maximum socket buffer size (in bytes when no unit specified).\n  #  read_buffer_size = \"64KiB\"\n  ## Period between keep alive probes.\n  ## 0 disables keep alive probes.\n  ## Defaults to the OS configuration.\n  #  keep_alive_period = \"5m\"\n```\n\nJust like Riemann the default port is 5555. This can be configured, refer\nconfiguration above.\n\nRiemann `Service` is mapped as `measurement`. `metric` and `TTL` are converted\ninto field values.  As Riemann tags as simply an array, they are converted into\nthe `influx_line` format key-value, where both key and value are the tags.\n\n## Metrics\n\n## Example Output\n"
  },
  {
    "path": "plugins/inputs/riemann_listener/riemann_listener.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage riemann_listener\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\triemann \"github.com/riemann/riemann-go-client\"\n\trieman_proto \"github.com/riemann/riemann-go-client/proto\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\tcommon_tls \"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype RiemannSocketListener struct {\n\tServiceAddress  string           `toml:\"service_address\"`\n\tMaxConnections  int              `toml:\"max_connections\"`\n\tReadBufferSize  config.Size      `toml:\"read_buffer_size\"`\n\tReadTimeout     *config.Duration `toml:\"read_timeout\"`\n\tKeepAlivePeriod *config.Duration `toml:\"keep_alive_period\"`\n\tSocketMode      string           `toml:\"socket_mode\"`\n\tcommon_tls.ServerConfig\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\twg sync.WaitGroup\n\ttelegraf.Accumulator\n}\n\ntype setReadBufferer interface {\n\tSetReadBuffer(sizeInBytes int) error\n}\n\ntype riemannListener struct {\n\tnet.Listener\n\t*RiemannSocketListener\n\n\tsockType string\n\n\tconnections    map[string]net.Conn\n\tconnectionsMtx sync.Mutex\n}\n\nfunc (*RiemannSocketListener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (rsl *RiemannSocketListener) Start(acc telegraf.Accumulator) error {\n\tctx, cancelFunc := context.WithCancel(context.Background())\n\tgo rsl.processOsSignals(cancelFunc)\n\trsl.Accumulator = acc\n\tif rsl.ServiceAddress == \"\" {\n\t\trsl.Log.Warnf(\"Using default service_address tcp://:5555\")\n\t\trsl.ServiceAddress = \"tcp://:5555\"\n\t}\n\tspl := strings.SplitN(rsl.ServiceAddress, \"://\", 2)\n\tif len(spl) != 2 {\n\t\treturn fmt.Errorf(\"invalid service address: %s\", rsl.ServiceAddress)\n\t}\n\n\tprotocol := spl[0]\n\taddr := spl[1]\n\n\tswitch protocol {\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\ttlsCfg, err := rsl.ServerConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar l net.Listener\n\t\tif tlsCfg == nil {\n\t\t\tl, err = net.Listen(protocol, addr)\n\t\t} else {\n\t\t\tl, err = tls.Listen(protocol, addr, tlsCfg)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trsl.Log.Infof(\"Listening on %s://%s\", protocol, l.Addr())\n\n\t\trsl := &riemannListener{\n\t\t\tListener:              l,\n\t\t\tRiemannSocketListener: rsl,\n\t\t\tsockType:              spl[0],\n\t\t}\n\n\t\trsl.wg = sync.WaitGroup{}\n\t\trsl.wg.Add(1)\n\t\tgo func() {\n\t\t\tdefer rsl.wg.Done()\n\t\t\trsl.listen(ctx)\n\t\t}()\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown protocol %q in %q\", protocol, rsl.ServiceAddress)\n\t}\n\n\treturn nil\n}\n\nfunc (*RiemannSocketListener) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (rsl *RiemannSocketListener) Stop() {\n\trsl.wg.Done()\n\trsl.wg.Wait()\n}\n\nfunc (rsl *riemannListener) listen(ctx context.Context) {\n\trsl.connections = make(map[string]net.Conn)\n\n\twg := sync.WaitGroup{}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\trsl.closeAllConnections()\n\t\twg.Wait()\n\t\treturn\n\tdefault:\n\t\tfor {\n\t\t\tc, err := rsl.Accept()\n\t\t\tif err != nil {\n\t\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\t\trsl.Log.Error(err.Error())\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif rsl.ReadBufferSize > 0 {\n\t\t\t\tif srb, ok := c.(setReadBufferer); ok {\n\t\t\t\t\tif err := srb.SetReadBuffer(int(rsl.ReadBufferSize)); err != nil {\n\t\t\t\t\t\trsl.Log.Warnf(\"Setting read buffer failed: %v\", err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\trsl.Log.Warnf(\"Unable to set read buffer on a %s socket\", rsl.sockType)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trsl.connectionsMtx.Lock()\n\t\t\tif rsl.MaxConnections > 0 && len(rsl.connections) >= rsl.MaxConnections {\n\t\t\t\trsl.connectionsMtx.Unlock()\n\t\t\t\tif err := c.Close(); err != nil {\n\t\t\t\t\trsl.Log.Warnf(\"Closing the connection failed: %v\", err)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\trsl.connections[c.RemoteAddr().String()] = c\n\t\t\trsl.connectionsMtx.Unlock()\n\n\t\t\tif err := rsl.setKeepAlive(c); err != nil {\n\t\t\t\trsl.Log.Errorf(\"Unable to configure keep alive %q: %s\", rsl.ServiceAddress, err.Error())\n\t\t\t}\n\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\trsl.read(c)\n\t\t\t}()\n\t\t}\n\t\trsl.closeAllConnections()\n\t\twg.Wait()\n\t}\n}\n\nfunc (rsl *riemannListener) closeAllConnections() {\n\trsl.connectionsMtx.Lock()\n\tfor _, c := range rsl.connections {\n\t\tif err := c.Close(); err != nil {\n\t\t\trsl.Log.Warnf(\"Closing the connection failed: %v\", err.Error())\n\t\t}\n\t}\n\trsl.connectionsMtx.Unlock()\n}\n\nfunc (rsl *riemannListener) setKeepAlive(c net.Conn) error {\n\tif rsl.KeepAlivePeriod == nil {\n\t\treturn nil\n\t}\n\ttcpc, ok := c.(*net.TCPConn)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot set keep alive on a %s socket\", strings.SplitN(rsl.ServiceAddress, \"://\", 2)[0])\n\t}\n\tif *rsl.KeepAlivePeriod == 0 {\n\t\treturn tcpc.SetKeepAlive(false)\n\t}\n\tif err := tcpc.SetKeepAlive(true); err != nil {\n\t\treturn err\n\t}\n\treturn tcpc.SetKeepAlivePeriod(time.Duration(*rsl.KeepAlivePeriod))\n}\n\nfunc (rsl *riemannListener) removeConnection(c net.Conn) {\n\trsl.connectionsMtx.Lock()\n\tdelete(rsl.connections, c.RemoteAddr().String())\n\trsl.connectionsMtx.Unlock()\n}\n\n/*\nreadMessages will read Riemann messages in binary format\nfrom the TCP connection. byte Array p size will depend on the size\nof the riemann  message as sent by the client\n*/\nfunc readMessages(r io.Reader, p []byte) error {\n\tfor len(p) > 0 {\n\t\tn, err := r.Read(p)\n\t\tp = p[n:]\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (rsl *riemannListener) read(conn net.Conn) {\n\tdefer rsl.removeConnection(conn)\n\tdefer conn.Close()\n\tvar err error\n\n\tfor {\n\t\tif rsl.ReadTimeout != nil && *rsl.ReadTimeout > 0 {\n\t\t\tif err := conn.SetDeadline(time.Now().Add(time.Duration(*rsl.ReadTimeout))); err != nil {\n\t\t\t\trsl.Log.Warnf(\"Setting deadline failed: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\tmessagePb := &rieman_proto.Msg{}\n\t\tvar header uint32\n\t\t// First obtain the size of the riemann event from client and acknowledge\n\t\tif err = binary.Read(conn, binary.BigEndian, &header); err != nil {\n\t\t\tif err.Error() != \"EOF\" {\n\t\t\t\trsl.Log.Debugf(\"Failed to read header\")\n\t\t\t\trsl.riemannReturnErrorResponse(conn, err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tdata := make([]byte, header)\n\n\t\tif err = readMessages(conn, data); err != nil {\n\t\t\trsl.Log.Debugf(\"Failed to read body: %s\", err.Error())\n\t\t\trsl.riemannReturnErrorResponse(conn, \"Failed to read body\")\n\t\t\treturn\n\t\t}\n\t\tif err = proto.Unmarshal(data, messagePb); err != nil {\n\t\t\trsl.Log.Debugf(\"Failed to unmarshal: %s\", err.Error())\n\t\t\trsl.riemannReturnErrorResponse(conn, \"Failed to unmarshal\")\n\t\t\treturn\n\t\t}\n\t\triemannEvents := riemann.ProtocolBuffersToEvents(messagePb.Events)\n\n\t\tfor _, m := range riemannEvents {\n\t\t\tif m.Service == \"\" {\n\t\t\t\trsl.riemannReturnErrorResponse(conn, \"No Service Name\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttags := make(map[string]string, len(m.Tags)+3)\n\t\t\tfor _, tag := range m.Tags {\n\t\t\t\ttags[strings.ReplaceAll(tag, \" \", \"_\")] = tag\n\t\t\t}\n\t\t\ttags[\"Host\"] = m.Host\n\t\t\ttags[\"Description\"] = m.Description\n\t\t\ttags[\"State\"] = m.State\n\t\t\tfieldValues := map[string]interface{}{\n\t\t\t\t\"Metric\": m.Metric,\n\t\t\t\t\"TTL\":    m.TTL.Seconds(),\n\t\t\t}\n\t\t\tsingleMetric := metric.New(m.Service, tags, fieldValues, m.Time, telegraf.Untyped)\n\t\t\trsl.AddMetric(singleMetric)\n\t\t}\n\t\trsl.riemannReturnResponse(conn)\n\t}\n}\n\nfunc (rsl *riemannListener) riemannReturnResponse(conn net.Conn) {\n\tt := true\n\tmessage := new(rieman_proto.Msg)\n\tmessage.Ok = &t\n\treturnData, err := proto.Marshal(message)\n\tif err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t\treturn\n\t}\n\tb := new(bytes.Buffer)\n\tif err = binary.Write(b, binary.BigEndian, uint32(len(returnData))); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n\t// send the msg length\n\tif _, err = conn.Write(b.Bytes()); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n\tif _, err = conn.Write(returnData); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n}\n\nfunc (rsl *riemannListener) riemannReturnErrorResponse(conn net.Conn, errorMessage string) {\n\tt := false\n\tmessage := new(rieman_proto.Msg)\n\tmessage.Ok = &t\n\tmessage.Error = &errorMessage\n\treturnData, err := proto.Marshal(message)\n\tif err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t\treturn\n\t}\n\tb := new(bytes.Buffer)\n\tif err = binary.Write(b, binary.BigEndian, uint32(len(returnData))); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n\t// send the msg length\n\tif _, err = conn.Write(b.Bytes()); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n\tif _, err = conn.Write(returnData); err != nil {\n\t\trsl.Log.Errorf(\"The error is: %v\", err)\n\t}\n}\n\n// Handle cancellations from the process\nfunc (rsl *RiemannSocketListener) processOsSignals(cancelFunc context.CancelFunc) {\n\tsignalChan := make(chan os.Signal, 1)\n\tsignal.Notify(signalChan, os.Interrupt)\n\tfor {\n\t\tsig := <-signalChan\n\t\tif sig == os.Interrupt {\n\t\t\trsl.Log.Warn(\"Signal SIGINT is received, probably due to `Ctrl-C`, exiting...\")\n\t\t\tcancelFunc()\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc newRiemannSocketListener() *RiemannSocketListener {\n\treturn &RiemannSocketListener{}\n}\n\nfunc init() {\n\tinputs.Add(\"riemann_listener\", func() telegraf.Input { return newRiemannSocketListener() })\n}\n"
  },
  {
    "path": "plugins/inputs/riemann_listener/riemann_listener_test.go",
    "content": "package riemann_listener\n\nimport (\n\t\"log\"\n\t\"testing\"\n\t\"time\"\n\n\triemanngo \"github.com/riemann/riemann-go-client\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSocketListener_tcp(t *testing.T) {\n\tlog.Println(\"Entering\")\n\n\tsl := newRiemannSocketListener()\n\tsl.Log = testutil.Logger{}\n\tsl.ServiceAddress = \"tcp://127.0.0.1:5555\"\n\tsl.ReadBufferSize = config.Size(1024)\n\n\tacc := &testutil.Accumulator{}\n\terr := sl.Start(acc)\n\trequire.NoError(t, err)\n\tdefer sl.Stop()\n\n\t// Check for stats of specific service\n\tc := riemanngo.NewTCPClient(\"127.0.0.1:5555\", 5*time.Second)\n\trequire.NoError(t, c.Connect())\n\trequire.NoError(t, err)\n\tdefer c.Close()\n\n\tresult, err := riemanngo.SendEvent(c, &riemanngo.Event{\n\t\tService: \"hello\",\n\t})\n\trequire.NoError(t, err)\n\trequire.True(t, result.GetOk())\n\n\t// Check for stats no service specified\n\tc = riemanngo.NewTCPClient(\"127.0.0.1:5555\", 5*time.Second)\n\trequire.NoError(t, c.Connect())\n\tdefer c.Close()\n\n\tresult, err = riemanngo.SendEvent(c, &riemanngo.Event{})\n\trequire.False(t, result.GetOk())\n\trequire.Equal(t, \"No Service Name\", result.GetError())\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "plugins/inputs/riemann_listener/sample.conf",
    "content": "# Riemann protobuff listener\n[[inputs.riemann_listener]]\n  ## URL to listen on\n  ## Default is \"tcp://:5555\"\n  #  service_address = \"tcp://:8094\"\n  #  service_address = \"tcp://127.0.0.1:http\"\n  #  service_address = \"tcp4://:8094\"\n  #  service_address = \"tcp6://:8094\"\n  #  service_address = \"tcp6://[2001:db8::1]:8094\"\n\n  ## Maximum number of concurrent connections.\n  ## 0 (default) is unlimited.\n  #  max_connections = 1024\n  ## Read timeout.\n  ## 0 (default) is unlimited.\n  #  read_timeout = \"30s\"\n  ## Optional TLS configuration.\n  #  tls_cert = \"/etc/telegraf/cert.pem\"\n  #  tls_key  = \"/etc/telegraf/key.pem\"\n  ## Enables client authentication if set.\n  #  tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n  ## Maximum socket buffer size (in bytes when no unit specified).\n  #  read_buffer_size = \"64KiB\"\n  ## Period between keep alive probes.\n  ## 0 disables keep alive probes.\n  ## Defaults to the OS configuration.\n  #  keep_alive_period = \"5m\"\n"
  },
  {
    "path": "plugins/inputs/s7comm/README.md",
    "content": "# Siemens S7 Input Plugin\n\nThis plugin reads metrics from Siemens PLCs via the S7 protocol.\n\n⭐ Telegraf v1.28.0\n🏷️ hardware\n💻 all\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Startup error behavior options <!-- @/docs/includes/startup_error_behavior.md -->\n\nIn addition to the plugin-specific and global configuration settings the plugin\nsupports options for specifying the behavior when experiencing startup errors\nusing the `startup_error_behavior` setting. Available values are:\n\n- `error`:  Telegraf with stop and exit in case of startup errors. This is the\n            default behavior.\n- `ignore`: Telegraf will ignore startup errors for this plugin and disables it\n            but continues processing for all other plugins.\n- `retry`:  Telegraf will try to startup the plugin in every gather or write\n            cycle in case of startup errors. The plugin is disabled until\n            the startup succeeds.\n- `probe`:  Telegraf will probe the plugin's function (if possible) and disables\n            the plugin in case probing fails. If the plugin does not support\n            probing, Telegraf will behave as if `ignore` was set instead.\n\n## Configuration\n\n```toml @sample.conf\n# Plugin for retrieving data from Siemens PLCs via the S7 protocol (RFC1006)\n[[inputs.s7comm]]\n  ## Parameters to contact the PLC (mandatory)\n  ## The server is in the <host>[:port] format where the port defaults to 102\n  ## if not explicitly specified.\n  server = \"127.0.0.1:102\"\n  rack = 0\n  slot = 0\n\n  ## Connection or drive type of S7 protocol\n  ## Available options are \"PD\" (programming  device), \"OP\" (operator panel) or \"basic\" (S7 basic communication).\n  # connection_type = \"PD\"\n\n  ## Max count of fields to be bundled in one batch-request. (PDU size)\n  # pdu_size = 20\n\n  ## Timeout for requests\n  # timeout = \"10s\"\n\n  ## Idle timeout for requests\n  # idle_timeout = \"60s\"\n\n  ## Log detailed connection messages for tracing issues\n  # log_level = \"trace\"\n\n  ## Metric definition(s)\n  [[inputs.s7comm.metric]]\n    ## Name of the measurement\n    # name = \"s7comm\"\n\n    ## Field definitions\n    ## name    - field name\n    ## address - indirect address \"<area>.<type><address>[.extra]\"\n    ##           area    - e.g. be \"DB1\" for data-block one\n    ##           type    - supported types are (uppercase)\n    ##                     X  -- bit, requires the bit-number as 'extra'\n    ##                           parameter\n    ##                     B  -- byte (8 bit)\n    ##                     C  -- character (8 bit)\n    ##                     W  -- word (16 bit)\n    ##                     DW -- double word (32 bit)\n    ##                     I  -- integer (16 bit)\n    ##                     DI -- double integer (32 bit)\n    ##                     LI -- long integer (64 bit) only S7-1200 S7-1500 suported\n    ##                     R  -- IEEE 754 real floating point number (32 bit)\n    ##                     LR -- IEEE 754 long real floating point number (64 bit) only S7-1200 S7-1500 suported\n    ##                     DT -- date-time, always converted to unix timestamp\n    ##                           with nano-second precision\n    ##                     S  -- string, requires the maximum length of the\n    ##                           string as 'extra' parameter\n    ##           address - start address to read if not specified otherwise\n    ##                     in the type field\n    ##           extra   - extra parameter e.g. for the bit and string type\n    fields = [\n      { name=\"rpm\",             address=\"DB1.R4\"    },\n      { name=\"status_ok\",       address=\"DB1.X2.1\"  },\n      { name=\"last_error\",      address=\"DB2.S1.32\" },\n      { name=\"last_error_time\", address=\"DB2.DT2\"   },\n      { name=\"long_counter\",    address=\"DB3.LR12\"  }\n    ]\n\n    ## Tags assigned to the metric\n    # [inputs.s7comm.metric.tags]\n    #   device = \"compressor\"\n    #   location = \"main building\"\n```\n\n## Example Output\n\n```text\ns7comm,host=Hugin rpm=712i,status_ok=true,last_error=\"empty slot\",last_error_time=1611319681000000000i 1611332164000000000\n```\n\n## Metrics\n\nThe format of metrics produced by this plugin depends on the metric\nconfiguration(s).\n"
  },
  {
    "path": "plugins/inputs/s7comm/s7comm.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage s7comm\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/maphash\"\n\t\"log\" //nolint:depguard // Required for tracing connection issues\n\t\"net\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/robinson/gos7\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\tregexAddr = regexp.MustCompile(addressRegexp)\n\t// Area mapping taken from https://github.com/robinson/gos7/blob/master/client.go\n\tareaMap = map[string]int{\n\t\t\"PE\": 0x81, // process inputs\n\t\t\"PA\": 0x82, // process outputs\n\t\t\"MK\": 0x83, // Merkers\n\t\t\"DB\": 0x84, // DB\n\t\t\"C\":  0x1C, // counters\n\t\t\"T\":  0x1D, // timers\n\t}\n\t// Word-length mapping taken from https://github.com/robinson/gos7/blob/master/client.go\n\twordLenMap = map[string]int{\n\t\t\"X\":  0x01, // Bit\n\t\t\"B\":  0x02, // Byte (8 bit)\n\t\t\"C\":  0x03, // Char (8 bit)\n\t\t\"S\":  0x03, // String (8 bit)\n\t\t\"W\":  0x04, // Word (16 bit)\n\t\t\"I\":  0x05, // Integer (16 bit)\n\t\t\"DW\": 0x06, // Double Word (32 bit)\n\t\t\"DI\": 0x07, // Double integer (32 bit)\n\t\t\"LI\": 0x06, // Long integer (64 bit)\n\t\t\"R\":  0x08, // IEEE 754 real (32 bit)\n\t\t\"LR\": 0x06, // IEEE 754 double (64-bit)\n\t\t// see https://support.industry.siemens.com/cs/document/36479/date_and_time-format-for-s7-?dti=0&lc=en-DE\n\t\t\"DT\": 0x0F, // Date and time (7 byte)\n\t}\n\n\tconnectionTypeMap = map[string]int{\n\t\t\"PD\":    1,\n\t\t\"OP\":    2,\n\t\t\"basic\": 3,\n\t}\n)\n\nconst addressRegexp = `^(?P<area>[A-Z]+)(?P<no>[0-9]+)\\.(?P<type>[A-Z]+)(?P<start>[0-9]+)(?:\\.(?P<extra>.*))?$`\n\ntype S7comm struct {\n\tServer          string             `toml:\"server\"`\n\tRack            int                `toml:\"rack\"`\n\tSlot            int                `toml:\"slot\"`\n\tConnectionType  string             `toml:\"connection_type\"`\n\tBatchMaxSize    int                `toml:\"pdu_size\"`\n\tTimeout         config.Duration    `toml:\"timeout\"`\n\tIdleTimeout     config.Duration    `toml:\"idle_timeout\"`\n\tDebugConnection bool               `toml:\"debug_connection\" deprecated:\"1.35.0;use 'log_level' 'trace' instead\"`\n\tConfigs         []metricDefinition `toml:\"metric\"`\n\tLog             telegraf.Logger    `toml:\"-\"`\n\n\thandler *gos7.TCPClientHandler\n\tclient  gos7.Client\n\tbatches []batch\n}\n\ntype metricDefinition struct {\n\tName   string                  `toml:\"name\"`\n\tFields []metricFieldDefinition `toml:\"fields\"`\n\tTags   map[string]string       `toml:\"tags\"`\n}\n\ntype metricFieldDefinition struct {\n\tName    string `toml:\"name\"`\n\tAddress string `toml:\"address\"`\n}\n\ntype batch struct {\n\titems    []gos7.S7DataItem\n\tmappings []fieldMapping\n}\n\ntype fieldMapping struct {\n\tmeasurement string\n\tfield       string\n\ttags        map[string]string\n\tconvert     converterFunc\n}\n\ntype converterFunc func([]byte) interface{}\n\nfunc (*S7comm) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *S7comm) Init() error {\n\t// Check settings\n\tif s.Server == \"\" {\n\t\treturn errors.New(\"'server' has to be specified\")\n\t}\n\tif s.Rack < 0 {\n\t\treturn errors.New(\"'rack' has to be specified\")\n\t}\n\tif s.Slot < 0 {\n\t\treturn errors.New(\"'slot' has to be specified\")\n\t}\n\tif s.ConnectionType == \"\" {\n\t\ts.ConnectionType = \"PD\"\n\t}\n\tif _, found := connectionTypeMap[s.ConnectionType]; !found {\n\t\treturn fmt.Errorf(\"invalid 'connection_type' %q\", s.ConnectionType)\n\t}\n\tif len(s.Configs) == 0 {\n\t\treturn errors.New(\"no metric defined\")\n\t}\n\n\t// Set default port to 102 if none is given\n\tvar nerr *net.AddrError\n\tif _, _, err := net.SplitHostPort(s.Server); errors.As(err, &nerr) {\n\t\tif !strings.Contains(nerr.Err, \"missing port\") {\n\t\t\treturn errors.New(\"invalid 'server' address\")\n\t\t}\n\t\ts.Server += \":102\"\n\t}\n\n\t// Create handler for the connection\n\ts.handler = gos7.NewTCPClientHandlerWithConnectType(s.Server, s.Rack, s.Slot, connectionTypeMap[s.ConnectionType])\n\ts.handler.Timeout = time.Duration(s.Timeout)\n\ts.handler.IdleTimeout = time.Duration(s.IdleTimeout)\n\tif s.Log.Level().Includes(telegraf.Trace) || s.DebugConnection { // for backward compatibility\n\t\ts.handler.Logger = log.New(&tracelogger{log: s.Log}, \"\", 0)\n\t}\n\n\t// Create the requests\n\treturn s.createRequests()\n}\n\nfunc (s *S7comm) Start(telegraf.Accumulator) error {\n\ts.Log.Debugf(\"Connecting to %q...\", s.Server)\n\tif err := s.handler.Connect(); err != nil {\n\t\treturn &internal.StartupError{\n\t\t\tErr:   fmt.Errorf(\"connecting to %q failed: %w\", s.Server, err),\n\t\t\tRetry: true,\n\t\t}\n\t}\n\ts.client = gos7.NewClient(s.handler)\n\n\treturn nil\n}\n\nfunc (s *S7comm) Gather(acc telegraf.Accumulator) error {\n\ttimestamp := time.Now()\n\tgrouper := metric.NewSeriesGrouper()\n\n\tfor i, b := range s.batches {\n\t\t// Read the batch\n\t\ts.Log.Debugf(\"Reading batch %d...\", i+1)\n\t\tif err := s.client.AGReadMulti(b.items, len(b.items)); err != nil {\n\t\t\t// Try to reconnect and skip this gather cycle to avoid hammering\n\t\t\t// the network if the server is down or under load.\n\t\t\ts.Log.Errorf(\"reading batch %d failed: %v; reconnecting...\", i+1, err)\n\t\t\ts.Stop()\n\t\t\treturn s.Start(acc)\n\t\t}\n\n\t\t// Dissect the received data into fields\n\t\tfor j, m := range b.mappings {\n\t\t\t// Convert the data\n\t\t\tbuf := b.items[j].Data\n\t\t\tvalue := m.convert(buf)\n\t\t\ts.Log.Debugf(\"  got %v for field %q @ %d --> %v (%T)\", buf, m.field, b.items[j].Start, value, value)\n\n\t\t\t// Group the data by series\n\t\t\tgrouper.Add(m.measurement, m.tags, timestamp, m.field, value)\n\t\t}\n\t}\n\n\t// Add the metrics grouped by series to the accumulator\n\tfor _, x := range grouper.Metrics() {\n\t\tacc.AddMetric(x)\n\t}\n\n\treturn nil\n}\n\nfunc (s *S7comm) Stop() {\n\tif s.handler != nil {\n\t\ts.Log.Debugf(\"Disconnecting from %q...\", s.handler.Address)\n\t\ts.handler.Close()\n\t}\n}\n\nfunc (s *S7comm) createRequests() error {\n\tseed := maphash.MakeSeed()\n\tseenFields := make(map[uint64]bool)\n\ts.batches = make([]batch, 0)\n\n\tcurrent := batch{}\n\tfor i, cfg := range s.Configs {\n\t\t// Set the defaults\n\t\tif cfg.Name == \"\" {\n\t\t\tcfg.Name = \"s7comm\"\n\t\t}\n\n\t\t// Check the metric definitions\n\t\tif len(cfg.Fields) == 0 {\n\t\t\treturn fmt.Errorf(\"no fields defined for metric %q\", cfg.Name)\n\t\t}\n\n\t\t// Create requests for all fields  and add it to the current slot\n\t\tfor _, f := range cfg.Fields {\n\t\t\tif f.Name == \"\" {\n\t\t\t\treturn fmt.Errorf(\"unnamed field in metric %q\", cfg.Name)\n\t\t\t}\n\n\t\t\titem, cfunc, err := handleFieldAddress(f.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"field %q of metric %q: %w\", f.Name, cfg.Name, err)\n\t\t\t}\n\t\t\tm := fieldMapping{\n\t\t\t\tmeasurement: cfg.Name,\n\t\t\t\tfield:       f.Name,\n\t\t\t\ttags:        s.Configs[i].Tags,\n\t\t\t\tconvert:     cfunc,\n\t\t\t}\n\t\t\tcurrent.items = append(current.items, *item)\n\t\t\tcurrent.mappings = append(current.mappings, m)\n\n\t\t\t// If the batch is full, start a new one\n\t\t\tif len(current.items) == s.BatchMaxSize {\n\t\t\t\ts.batches = append(s.batches, current)\n\t\t\t\tcurrent = batch{}\n\t\t\t}\n\n\t\t\t// Check for duplicate field definitions\n\t\t\tid := fieldID(seed, cfg, f)\n\t\t\tif seenFields[id] {\n\t\t\t\treturn fmt.Errorf(\"duplicate field definition field %q in metric %q\", f.Name, cfg.Name)\n\t\t\t}\n\t\t\tseenFields[id] = true\n\t\t}\n\n\t\t// Update the configuration if changed\n\t\ts.Configs[i] = cfg\n\t}\n\n\t// Add the last batch if any\n\tif len(current.items) > 0 {\n\t\ts.batches = append(s.batches, current)\n\t}\n\n\treturn nil\n}\n\nfunc handleFieldAddress(address string) (*gos7.S7DataItem, converterFunc, error) {\n\t// Parse the address into the different parts\n\tif !regexAddr.MatchString(address) {\n\t\treturn nil, nil, fmt.Errorf(\"invalid address %q\", address)\n\t}\n\tnames := regexAddr.SubexpNames()[1:]\n\tparts := regexAddr.FindStringSubmatch(address)[1:]\n\tif len(names) != len(parts) {\n\t\treturn nil, nil, fmt.Errorf(\"names %v do not match parts %v\", names, parts)\n\t}\n\tgroups := make(map[string]string, len(names))\n\tfor i, n := range names {\n\t\tgroups[n] = parts[i]\n\t}\n\n\t// Check that we do have the required entries in the address\n\tif _, found := groups[\"area\"]; !found {\n\t\treturn nil, nil, errors.New(\"area is missing from address\")\n\t}\n\n\tif _, found := groups[\"no\"]; !found {\n\t\treturn nil, nil, errors.New(\"area index is missing from address\")\n\t}\n\tif _, found := groups[\"type\"]; !found {\n\t\treturn nil, nil, errors.New(\"type is missing from address\")\n\t}\n\tif _, found := groups[\"start\"]; !found {\n\t\treturn nil, nil, errors.New(\"start address is missing from address\")\n\t}\n\tdtype := groups[\"type\"]\n\n\t// Lookup the item values from names and check the params\n\tarea, found := areaMap[groups[\"area\"]]\n\tif !found {\n\t\treturn nil, nil, errors.New(\"invalid area\")\n\t}\n\twordlen, found := wordLenMap[dtype]\n\tif !found {\n\t\treturn nil, nil, errors.New(\"unknown data type\")\n\t}\n\tareaidx, err := strconv.Atoi(groups[\"no\"])\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid area index: %w\", err)\n\t}\n\tstart, err := strconv.Atoi(groups[\"start\"])\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid start address: %w\", err)\n\t}\n\n\t// Check the amount parameter if any\n\tvar extra, bit int\n\tswitch dtype {\n\tcase \"S\":\n\t\t// We require an extra parameter\n\t\tx := groups[\"extra\"]\n\t\tif x == \"\" {\n\t\t\treturn nil, nil, errors.New(\"extra parameter required\")\n\t\t}\n\n\t\textra, err = strconv.Atoi(x)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid extra parameter: %w\", err)\n\t\t}\n\t\tif extra < 1 {\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid extra parameter %d\", extra)\n\t\t}\n\tcase \"X\":\n\t\t// We require an extra parameter\n\t\tx := groups[\"extra\"]\n\t\tif x == \"\" {\n\t\t\treturn nil, nil, errors.New(\"extra parameter required\")\n\t\t}\n\n\t\tbit, err = strconv.Atoi(x)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid extra parameter: %w\", err)\n\t\t}\n\t\tif bit < 0 || bit > 7 {\n\t\t\t// Ensure bit address is valid\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid extra parameter: bit address %d out of range\", bit)\n\t\t}\n\tdefault:\n\t\tif groups[\"extra\"] != \"\" {\n\t\t\treturn nil, nil, errors.New(\"extra parameter specified but not used\")\n\t\t}\n\t}\n\n\t// Get the required buffer size\n\tamount := 1\n\tvar buflen int\n\tswitch dtype {\n\tcase \"X\", \"B\", \"C\": // 8-bit types\n\t\tbuflen = 1\n\tcase \"W\", \"I\": // 16-bit types\n\t\tbuflen = 2\n\tcase \"DW\", \"DI\", \"R\": // 32-bit types\n\t\tbuflen = 4\n\tcase \"LR\", \"LI\": // 64-bit types\n\t\tbuflen = 8\n\t\tamount = 2\n\tcase \"DT\": // 7-byte\n\t\tbuflen = 7\n\tcase \"S\":\n\t\t// Extra bytes as the first byte is the max-length of the string and\n\t\t// the second byte is the actual length of the string.\n\t\tamount = extra + 2\n\t\tbuflen = extra + 2\n\tdefault:\n\t\treturn nil, nil, errors.New(\"invalid data type\")\n\t}\n\n\t// Setup the data item\n\titem := &gos7.S7DataItem{\n\t\tArea:     area,\n\t\tWordLen:  wordlen,\n\t\tBit:      bit,\n\t\tDBNumber: areaidx,\n\t\tStart:    start,\n\t\tAmount:   amount,\n\t\tData:     make([]byte, buflen),\n\t}\n\n\t// Determine the type converter function\n\tf := determineConversion(dtype)\n\treturn item, f, nil\n}\n\nfunc fieldID(seed maphash.Seed, def metricDefinition, field metricFieldDefinition) uint64 {\n\tvar mh maphash.Hash\n\tmh.SetSeed(seed)\n\n\tmh.WriteString(def.Name)\n\tmh.WriteByte(0)\n\tmh.WriteString(field.Name)\n\tmh.WriteByte(0)\n\n\t// Tags\n\tfor k, v := range def.Tags {\n\t\tmh.WriteString(k)\n\t\tmh.WriteByte('=')\n\t\tmh.WriteString(v)\n\t\tmh.WriteByte(':')\n\t}\n\tmh.WriteByte(0)\n\n\treturn mh.Sum64()\n}\n\n// Logger for tracing internal messages\ntype tracelogger struct {\n\tlog telegraf.Logger\n}\n\nfunc (l *tracelogger) Write(b []byte) (n int, err error) {\n\tl.log.Trace(string(b))\n\treturn len(b), nil\n}\n\n// Add this plugin to telegraf\nfunc init() {\n\tinputs.Add(\"s7comm\", func() telegraf.Input {\n\t\treturn &S7comm{\n\t\t\tRack:         -1,\n\t\t\tSlot:         -1,\n\t\t\tBatchMaxSize: 20,\n\t\t\tTimeout:      config.Duration(10 * time.Second),\n\t\t\tIdleTimeout:  config.Duration(60 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/s7comm/s7comm_test.go",
    "content": "package s7comm\n\nimport (\n\t_ \"embed\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"net\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/robinson/gos7\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/models\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSampleConfig(t *testing.T) {\n\tplugin := &S7comm{}\n\trequire.NotEmpty(t, plugin.SampleConfig())\n}\n\nfunc TestInitFail(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tserver        string\n\t\track          int\n\t\tslot          int\n\t\tconfigs       []metricDefinition\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:          \"empty settings\",\n\t\t\track:          -1, // This is the default in `init()`\n\t\t\tslot:          -1, // This is the default in `init()`\n\t\t\texpectedError: \"'server' has to be specified\",\n\t\t},\n\t\t{\n\t\t\tname:          \"missing rack\",\n\t\t\tserver:        \"127.0.0.1:102\",\n\t\t\track:          -1, // This is the default in `init()`\n\t\t\tslot:          -1, // This is the default in `init()`\n\t\t\texpectedError: \"'rack' has to be specified\",\n\t\t},\n\t\t{\n\t\t\tname:          \"missing slot\",\n\t\t\tserver:        \"127.0.0.1:102\",\n\t\t\track:          0,\n\t\t\tslot:          -1, // This is the default in `init()`\n\t\t\texpectedError: \"'slot' has to be specified\",\n\t\t},\n\t\t{\n\t\t\tname:          \"missing configs\",\n\t\t\tserver:        \"127.0.0.1:102\",\n\t\t\texpectedError: \"no metric defined\",\n\t\t},\n\t\t{\n\t\t\tname:          \"single empty metric\",\n\t\t\tserver:        \"127.0.0.1:102\",\n\t\t\tconfigs:       []metricDefinition{{}},\n\t\t\texpectedError: \"no fields defined for metric\",\n\t\t},\n\t\t{\n\t\t\tname:   \"single empty metric field\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{{}},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"unnamed field in metric\",\n\t\t},\n\t\t{\n\t\t\tname:   \"no address\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"invalid address\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address pattern\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"FOO\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"invalid address\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address area\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"FOO1.W2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"invalid area\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address area index\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB.W2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"invalid address\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address type\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.A2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"unknown data type\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address start\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.A\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"invalid address\",\n\t\t},\n\t\t{\n\t\t\tname:   \"missing extra parameter bit\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.X1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"extra parameter required\",\n\t\t},\n\t\t{\n\t\t\tname:   \"missing extra parameter string\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.S1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"extra parameter required\",\n\t\t},\n\t\t{\n\t\t\tname:   \"invalid address extra parameter\",\n\t\t\tserver: \"127.0.0.1:102\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.W1.23\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"extra parameter specified but not used\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &S7comm{\n\t\t\t\tServer:  tt.server,\n\t\t\t\tRack:    tt.rack,\n\t\t\t\tSlot:    tt.slot,\n\t\t\t\tConfigs: tt.configs,\n\t\t\t\tLog:     &testutil.Logger{},\n\t\t\t}\n\t\t\trequire.ErrorContains(t, plugin.Init(), tt.expectedError)\n\t\t})\n\t}\n}\n\nfunc TestInit(t *testing.T) {\n\tplugin := &S7comm{\n\t\tServer: \"127.0.0.1:102\",\n\t\tRack:   0,\n\t\tSlot:   0,\n\t\tConfigs: []metricDefinition{\n\t\t\t{\n\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\tAddress: \"DB1.W2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n}\n\nfunc TestFieldMappings(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tconfigs  []metricDefinition\n\t\texpected []batch\n\t}{\n\t\t{\n\t\t\tname: \"single field bit\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.X3.2\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x01,\n\t\t\t\t\t\t\tBit:      2,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return false },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field byte\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.B3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x02,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return byte(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field char\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.C3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x03,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return string([]byte{0}) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field string\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.S3.10\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x03,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   12,\n\t\t\t\t\t\t\tData:     make([]byte, 12),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert: func(b []byte) interface{} {\n\t\t\t\t\t\t\t\treturn string(b[2 : 2+b[1]])\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field word\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.W3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x04,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 2),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return uint16(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field integer\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.I3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x05,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 2),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return int16(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field double word\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.DW3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x06,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 4),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return uint32(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field double integer\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.DI3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x07,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 4),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return int32(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field float\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.R3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x08,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   1,\n\t\t\t\t\t\t\tData:     make([]byte, 4),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return float32(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field long integer\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.LI3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x06,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   2,\n\t\t\t\t\t\t\tData:     make([]byte, 8),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return int64(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single field long real\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB5.LR3\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []batch{\n\t\t\t\t{\n\t\t\t\t\titems: []gos7.S7DataItem{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tArea:     0x84,\n\t\t\t\t\t\t\tWordLen:  0x06,\n\t\t\t\t\t\t\tDBNumber: 5,\n\t\t\t\t\t\t\tStart:    3,\n\t\t\t\t\t\t\tAmount:   2,\n\t\t\t\t\t\t\tData:     make([]byte, 8),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmappings: []fieldMapping{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmeasurement: \"test\",\n\t\t\t\t\t\t\tfield:       \"foo\",\n\t\t\t\t\t\t\tconvert:     func([]byte) interface{} { return float64(0) },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &S7comm{\n\t\t\t\tServer:  \"127.0.0.1:102\",\n\t\t\t\tRack:    0,\n\t\t\t\tSlot:    2,\n\t\t\t\tConfigs: tt.configs,\n\t\t\t\tLog:     &testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Check the length\n\t\t\trequire.Len(t, plugin.batches, len(tt.expected))\n\t\t\t// Check the actual content\n\t\t\tfor i, eb := range tt.expected {\n\t\t\t\tab := plugin.batches[i]\n\t\t\t\trequire.Len(t, ab.items, len(eb.items))\n\t\t\t\trequire.Len(t, ab.mappings, len(eb.mappings))\n\t\t\t\trequire.EqualValues(t, eb.items, plugin.batches[i].items, \"different items\")\n\t\t\t\tfor j, em := range eb.mappings {\n\t\t\t\t\tam := ab.mappings[j]\n\t\t\t\t\trequire.Equal(t, em.measurement, am.measurement)\n\t\t\t\t\trequire.Equal(t, em.field, am.field)\n\t\t\t\t\tbuf := ab.items[j].Data\n\t\t\t\t\trequire.Equal(t, em.convert(buf), am.convert(buf))\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMetricCollisions(t *testing.T) {\n\ttests := []struct {\n\t\tname          string\n\t\tconfigs       []metricDefinition\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"duplicate fields same config\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.W1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"duplicate field definition\",\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate fields different config\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"duplicate field definition\",\n\t\t},\n\t\t{\n\t\t\tname: \"same fields different name\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tName: \"foo\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"bar\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"same fields different tags\",\n\t\t\tconfigs: []metricDefinition{\n\t\t\t\t{\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tTags: map[string]string{\"device\": \"foo\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"bar\",\n\t\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\t\tAddress: \"DB1.B1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tTags: map[string]string{\"device\": \"bar\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &S7comm{\n\t\t\t\tServer:  \"127.0.0.1:102\",\n\t\t\t\tRack:    0,\n\t\t\t\tSlot:    2,\n\t\t\t\tConfigs: tt.configs,\n\t\t\t\tLog:     &testutil.Logger{},\n\t\t\t}\n\t\t\terr := plugin.Init()\n\t\t\tif tt.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestConnectionLoss(t *testing.T) {\n\t// Create fake S7 comm server that can accept connects\n\tserver, err := newMockServer()\n\trequire.NoError(t, err)\n\tdefer server.close()\n\tserver.start()\n\n\t// Create the plugin and attempt a connection\n\tplugin := &S7comm{\n\t\tServer:          server.addr(),\n\t\tRack:            0,\n\t\tSlot:            2,\n\t\tDebugConnection: true,\n\t\tTimeout:         config.Duration(100 * time.Millisecond),\n\t\tConfigs: []metricDefinition{\n\t\t\t{\n\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\tAddress: \"DB1.W2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\trequire.NoError(t, plugin.Gather(&acc))\n\trequire.NoError(t, plugin.Gather(&acc))\n\tplugin.Stop()\n\tserver.close()\n\n\trequire.Equal(t, uint32(3), server.connectionAttempts.Load())\n}\n\nfunc TestStartupErrorBehaviorError(t *testing.T) {\n\t// Create fake S7 comm server that can accept connects\n\tserver, err := newMockServer()\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\t// Setup the plugin and the model to be able to use the startup retry strategy\n\tplugin := &S7comm{\n\t\tServer:          server.addr(),\n\t\tRack:            0,\n\t\tSlot:            2,\n\t\tDebugConnection: true,\n\t\tTimeout:         config.Duration(100 * time.Millisecond),\n\t\tConfigs: []metricDefinition{\n\t\t\t{\n\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\tAddress: \"DB1.W2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:  \"s7comm\",\n\t\t\tAlias: \"error-test\", // required to get a unique error stats instance\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail with an error because the server does not listen\n\tvar acc testutil.Accumulator\n\trequire.ErrorContains(t, model.Start(&acc), \"connecting to \\\"\"+server.addr()+\"\\\" failed\")\n}\n\nfunc TestStartupErrorBehaviorIgnore(t *testing.T) {\n\t// Create fake S7 comm server that can accept connects\n\tserver, err := newMockServer()\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\t// Setup the plugin and the model to be able to use the startup retry strategy\n\tplugin := &S7comm{\n\t\tServer:          server.addr(),\n\t\tRack:            0,\n\t\tSlot:            2,\n\t\tDebugConnection: true,\n\t\tTimeout:         config.Duration(100 * time.Millisecond),\n\t\tConfigs: []metricDefinition{\n\t\t\t{\n\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\tAddress: \"DB1.W2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"s7comm\",\n\t\t\tAlias:                \"ignore-test\", // required to get a unique error stats instance\n\t\t\tStartupErrorBehavior: \"ignore\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will fail because the server does not accept connections.\n\t// The model code should convert it to a fatal error for the agent to remove\n\t// the plugin.\n\tvar acc testutil.Accumulator\n\terr = model.Start(&acc)\n\trequire.ErrorContains(t, err, \"connecting to \\\"\"+server.addr()+\"\\\" failed\")\n\tvar fatalErr *internal.FatalError\n\trequire.ErrorAs(t, err, &fatalErr)\n}\n\nfunc TestStartupErrorBehaviorRetry(t *testing.T) {\n\t// Create fake S7 comm server that can accept connects\n\tserver, err := newMockServer()\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\t// Setup the plugin and the model to be able to use the startup retry strategy\n\tplugin := &S7comm{\n\t\tServer:          server.addr(),\n\t\tRack:            0,\n\t\tSlot:            2,\n\t\tDebugConnection: true,\n\t\tTimeout:         config.Duration(100 * time.Millisecond),\n\t\tConfigs: []metricDefinition{\n\t\t\t{\n\t\t\t\tFields: []metricFieldDefinition{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"foo\",\n\t\t\t\t\t\tAddress: \"DB1.W2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\tmodel := models.NewRunningInput(\n\t\tplugin,\n\t\t&models.InputConfig{\n\t\t\tName:                 \"s7comm\",\n\t\t\tAlias:                \"retry-test\", // required to get a unique error stats instance\n\t\t\tStartupErrorBehavior: \"retry\",\n\t\t},\n\t)\n\tmodel.StartupErrors.Set(0)\n\trequire.NoError(t, model.Init())\n\n\t// Starting the plugin will return no error because the plugin will\n\t// retry to connect in every gather cycle.\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, model.Start(&acc))\n\n\t// The gather should fail as the server does not accept connections (yet)\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\trequire.ErrorIs(t, model.Gather(&acc), internal.ErrNotConnected)\n\trequire.Equal(t, int64(2), model.StartupErrors.Get())\n\n\t// Allow connection in the server, now the connection should succeed\n\tserver.start()\n\tdefer model.Stop()\n\trequire.NoError(t, model.Gather(&acc))\n}\n\ntype mockServer struct {\n\tconnectionAttempts atomic.Uint32\n\tlistener           net.Listener\n}\n\nfunc newMockServer() (*mockServer, error) {\n\tl, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &mockServer{listener: l}, nil\n}\n\nfunc (s *mockServer) addr() string {\n\treturn s.listener.Addr().String()\n}\n\nfunc (s *mockServer) close() error {\n\tif s.listener != nil {\n\t\treturn s.listener.Close()\n\t}\n\treturn nil\n}\n\nfunc (s *mockServer) start() {\n\tgo func() {\n\t\tdefer s.listener.Close()\n\t\tfor {\n\t\t\tconn, err := s.listener.Accept()\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err := conn.SetDeadline(time.Now().Add(time.Second)); err != nil {\n\t\t\t\tconn.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Count the number of connection attempts\n\t\t\ts.connectionAttempts.Add(1)\n\n\t\t\tbuf := make([]byte, 4096)\n\n\t\t\t// Wait for ISO connection telegram\n\t\t\tif _, err := io.ReadAtLeast(conn, buf, 22); err != nil {\n\t\t\t\tconn.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Send fake response\n\t\t\tresponse := make([]byte, 22)\n\t\t\tresponse[5] = 0xD0\n\t\t\tbinary.BigEndian.PutUint16(response[2:4], uint16(len(response)))\n\t\t\tif _, err := conn.Write(response); err != nil {\n\t\t\t\tconn.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Wait for PDU negotiation telegram\n\t\t\tif _, err := io.ReadAtLeast(conn, buf, 25); err != nil {\n\t\t\t\tconn.Close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Send fake response\n\t\t\tresponse = make([]byte, 27)\n\t\t\tbinary.BigEndian.PutUint16(response[2:4], uint16(len(response)))\n\t\t\tbinary.BigEndian.PutUint16(response[25:27], uint16(480))\n\t\t\tif _, err := conn.Write(response); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Always close after connection is established\n\t\t\tconn.Close()\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "plugins/inputs/s7comm/sample.conf",
    "content": "# Plugin for retrieving data from Siemens PLCs via the S7 protocol (RFC1006)\n[[inputs.s7comm]]\n  ## Parameters to contact the PLC (mandatory)\n  ## The server is in the <host>[:port] format where the port defaults to 102\n  ## if not explicitly specified.\n  server = \"127.0.0.1:102\"\n  rack = 0\n  slot = 0\n\n  ## Connection or drive type of S7 protocol\n  ## Available options are \"PD\" (programming  device), \"OP\" (operator panel) or \"basic\" (S7 basic communication).\n  # connection_type = \"PD\"\n\n  ## Max count of fields to be bundled in one batch-request. (PDU size)\n  # pdu_size = 20\n\n  ## Timeout for requests\n  # timeout = \"10s\"\n\n  ## Idle timeout for requests\n  # idle_timeout = \"60s\"\n\n  ## Log detailed connection messages for tracing issues\n  # log_level = \"trace\"\n\n  ## Metric definition(s)\n  [[inputs.s7comm.metric]]\n    ## Name of the measurement\n    # name = \"s7comm\"\n\n    ## Field definitions\n    ## name    - field name\n    ## address - indirect address \"<area>.<type><address>[.extra]\"\n    ##           area    - e.g. be \"DB1\" for data-block one\n    ##           type    - supported types are (uppercase)\n    ##                     X  -- bit, requires the bit-number as 'extra'\n    ##                           parameter\n    ##                     B  -- byte (8 bit)\n    ##                     C  -- character (8 bit)\n    ##                     W  -- word (16 bit)\n    ##                     DW -- double word (32 bit)\n    ##                     I  -- integer (16 bit)\n    ##                     DI -- double integer (32 bit)\n    ##                     LI -- long integer (64 bit) only S7-1200 S7-1500 suported\n    ##                     R  -- IEEE 754 real floating point number (32 bit)\n    ##                     LR -- IEEE 754 long real floating point number (64 bit) only S7-1200 S7-1500 suported\n    ##                     DT -- date-time, always converted to unix timestamp\n    ##                           with nano-second precision\n    ##                     S  -- string, requires the maximum length of the\n    ##                           string as 'extra' parameter\n    ##           address - start address to read if not specified otherwise\n    ##                     in the type field\n    ##           extra   - extra parameter e.g. for the bit and string type\n    fields = [\n      { name=\"rpm\",             address=\"DB1.R4\"    },\n      { name=\"status_ok\",       address=\"DB1.X2.1\"  },\n      { name=\"last_error\",      address=\"DB2.S1.32\" },\n      { name=\"last_error_time\", address=\"DB2.DT2\"   },\n      { name=\"long_counter\",    address=\"DB3.LR12\"  }\n    ]\n\n    ## Tags assigned to the metric\n    # [inputs.s7comm.metric.tags]\n    #   device = \"compressor\"\n    #   location = \"main building\"\n"
  },
  {
    "path": "plugins/inputs/s7comm/type_conversions.go",
    "content": "package s7comm\n\nimport (\n\t\"encoding/binary\"\n\t\"math\"\n\n\t\"github.com/robinson/gos7\"\n)\n\nvar helper = &gos7.Helper{}\n\nfunc determineConversion(dtype string) converterFunc {\n\tswitch dtype {\n\tcase \"X\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn buf[0] != 0\n\t\t}\n\tcase \"B\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn buf[0]\n\t\t}\n\tcase \"C\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn string(buf[0])\n\t\t}\n\tcase \"S\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\tif len(buf) <= 2 {\n\t\t\t\treturn \"\"\n\t\t\t}\n\t\t\t// Get the length of the encoded string\n\t\t\tlength := int(buf[1])\n\t\t\t// Clip the string if we do not fill the whole buffer\n\t\t\tif length < len(buf)-2 {\n\t\t\t\treturn string(buf[2 : 2+length])\n\t\t\t}\n\t\t\treturn string(buf[2:])\n\t\t}\n\tcase \"W\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn binary.BigEndian.Uint16(buf)\n\t\t}\n\tcase \"I\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn int16(binary.BigEndian.Uint16(buf))\n\t\t}\n\tcase \"DW\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn binary.BigEndian.Uint32(buf)\n\t\t}\n\tcase \"DI\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn int32(binary.BigEndian.Uint32(buf))\n\t\t}\n\tcase \"LI\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn int64(binary.BigEndian.Uint64(buf))\n\t\t}\n\tcase \"R\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\tx := binary.BigEndian.Uint32(buf)\n\t\t\treturn math.Float32frombits(x)\n\t\t}\n\tcase \"LR\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\tx := binary.BigEndian.Uint64(buf)\n\t\t\treturn math.Float64frombits(x)\n\t\t}\n\tcase \"DT\":\n\t\treturn func(buf []byte) interface{} {\n\t\t\treturn helper.GetDateTimeAt(buf, 0).UnixNano()\n\t\t}\n\t}\n\n\tpanic(\"Unknown type! Please file an issue on https://github.com/influxdata/telegraf including your config.\")\n}\n"
  },
  {
    "path": "plugins/inputs/salesforce/README.md",
    "content": "# Salesforce Input Plugin\n\nThis plugin gathers metrics about the limits in your [Salesforce][salesforce]\norganization and the remaining usage using the [limits endpoint][limits] of\nSalesforce's REST API.\n\n⭐ Telegraf v1.4.0\n🏷️ server, cloud\n💻 all\n\n[salesforce]: https://salesforce.com\n[limits]: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_limits.htm\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read API usage and limits for a Salesforce organisation\n[[inputs.salesforce]]\n  ## specify your credentials\n  ##\n  username = \"your_username\"\n  password = \"your_password\"\n  ##\n  ## (optional) security token\n  # security_token = \"your_security_token\"\n  ##\n  ## (optional) environment type (sandbox or production)\n  ## default is: production\n  ##\n  # environment = \"production\"\n  ##\n  ## (optional) API version (default: \"39.0\")\n  ##\n  # version = \"39.0\"\n```\n\n## Metrics\n\nSalesforce provide one measurement named \"salesforce\".\nEach entry is converted to snake\\_case and 2 fields are created.\n\n- \\<key\\>_max represents the limit threshold\n- \\<key\\>_remaining represents the usage remaining before hitting the limit threshold\n\n- salesforce\n  - \\<key\\>_max (int)\n  - \\<key\\>_remaining (int)\n  - (...)\n\n### Tags\n\n- All measurements have the following tags:\n  - host\n  - organization_id (t18 char organisation ID)\n\n## Example Output\n\n```sh\n$./telegraf --config telegraf.conf --input-filter salesforce --test\n```\n\n```text\nsalesforce,organization_id=XXXXXXXXXXXXXXXXXX,host=xxxxx.salesforce.com daily_workflow_emails_max=546000i,hourly_time_based_workflow_max=50i,daily_async_apex_executions_remaining=250000i,daily_durable_streaming_api_events_remaining=1000000i,streaming_api_concurrent_clients_remaining=2000i,daily_bulk_api_requests_remaining=10000i,hourly_sync_report_runs_remaining=500i,daily_api_requests_max=5000000i,data_storage_mb_remaining=1073i,file_storage_mb_remaining=1069i,daily_generic_streaming_api_events_remaining=10000i,hourly_async_report_runs_remaining=1200i,hourly_time_based_workflow_remaining=50i,daily_streaming_api_events_remaining=1000000i,single_email_max=5000i,hourly_dashboard_refreshes_remaining=200i,streaming_api_concurrent_clients_max=2000i,daily_durable_generic_streaming_api_events_remaining=1000000i,daily_api_requests_remaining=4999998i,hourly_dashboard_results_max=5000i,hourly_async_report_runs_max=1200i,daily_durable_generic_streaming_api_events_max=1000000i,hourly_dashboard_results_remaining=5000i,concurrent_sync_report_runs_max=20i,durable_streaming_api_concurrent_clients_remaining=2000i,daily_workflow_emails_remaining=546000i,hourly_dashboard_refreshes_max=200i,daily_streaming_api_events_max=1000000i,hourly_sync_report_runs_max=500i,hourly_o_data_callout_max=10000i,mass_email_max=5000i,mass_email_remaining=5000i,single_email_remaining=5000i,hourly_dashboard_statuses_max=999999999i,concurrent_async_get_report_instances_max=200i,daily_durable_streaming_api_events_max=1000000i,daily_generic_streaming_api_events_max=10000i,hourly_o_data_callout_remaining=10000i,concurrent_sync_report_runs_remaining=20i,daily_bulk_api_requests_max=10000i,data_storage_mb_max=1073i,hourly_dashboard_statuses_remaining=999999999i,concurrent_async_get_report_instances_remaining=200i,daily_async_apex_executions_max=250000i,durable_streaming_api_concurrent_clients_max=2000i,file_storage_mb_max=1073i 1501565661000000000\n```\n"
  },
  {
    "path": "plugins/inputs/salesforce/salesforce.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage salesforce\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tdefaultVersion     = \"39.0\"\n\tdefaultEnvironment = \"production\"\n)\n\ntype Salesforce struct {\n\tUsername      string `toml:\"username\"`\n\tPassword      string `toml:\"password\"`\n\tSecurityToken string `toml:\"security_token\"`\n\tEnvironment   string `toml:\"environment\"`\n\tVersion       string `toml:\"version\"`\n\n\tsessionID      string\n\tserverURL      *url.URL\n\torganizationID string\n\n\tclient *http.Client\n}\n\ntype limit struct {\n\tMax       int\n\tRemaining int\n}\n\ntype limits map[string]limit\n\nfunc (*Salesforce) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Salesforce) Gather(acc telegraf.Accumulator) error {\n\tlimits, err := s.fetchLimits()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttags := map[string]string{\n\t\t\"organization_id\": s.organizationID,\n\t\t\"host\":            s.serverURL.Host,\n\t}\n\n\tfields := make(map[string]interface{})\n\tfor k, v := range limits {\n\t\tkey := internal.SnakeCase(k)\n\t\tfields[key+\"_max\"] = v.Max\n\t\tfields[key+\"_remaining\"] = v.Remaining\n\t}\n\n\tacc.AddFields(\"salesforce\", fields, tags)\n\treturn nil\n}\n\n// query the limits endpoint\nfunc (s *Salesforce) queryLimits() (*http.Response, error) {\n\tendpoint := fmt.Sprintf(\"%s://%s/services/data/v%s/limits\", s.serverURL.Scheme, s.serverURL.Host, s.Version)\n\treq, err := http.NewRequest(http.MethodGet, endpoint, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Add(\"Accept\", \"encoding/json\")\n\treq.Header.Add(\"Authorization\", \"Bearer \"+s.sessionID)\n\treturn s.client.Do(req)\n}\n\nfunc (s *Salesforce) isAuthenticated() bool {\n\treturn s.sessionID != \"\"\n}\n\nfunc (s *Salesforce) fetchLimits() (limits, error) {\n\tvar l limits\n\tif !s.isAuthenticated() {\n\t\tif err := s.login(); err != nil {\n\t\t\treturn l, err\n\t\t}\n\t}\n\n\tresp, err := s.queryLimits()\n\tif err != nil {\n\t\treturn l, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusUnauthorized {\n\t\tif err := s.login(); err != nil {\n\t\t\treturn l, err\n\t\t}\n\t\tresp, err = s.queryLimits()\n\t\tif err != nil {\n\t\t\treturn l, err\n\t\t}\n\t\tdefer resp.Body.Close()\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn l, fmt.Errorf(\"salesforce responded with unexpected status code %d\", resp.StatusCode)\n\t}\n\n\tl = make(limits)\n\terr = json.NewDecoder(resp.Body).Decode(&l)\n\treturn l, err\n}\n\nfunc (s *Salesforce) getLoginEndpoint() (string, error) {\n\tswitch s.Environment {\n\tcase \"sandbox\":\n\t\treturn fmt.Sprintf(\"https://test.salesforce.com/services/Soap/c/%s/\", s.Version), nil\n\tcase \"production\":\n\t\treturn fmt.Sprintf(\"https://login.salesforce.com/services/Soap/c/%s/\", s.Version), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown environment type: %s\", s.Environment)\n\t}\n}\n\n// Authenticate with Salesforce\nfunc (s *Salesforce) login() error {\n\tif s.Username == \"\" || s.Password == \"\" {\n\t\treturn errors.New(\"missing username or password\")\n\t}\n\n\tbody := fmt.Sprintf(`<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\t\t<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n\t\t  xmlns:urn=\"urn:enterprise.soap.sforce.com\">\n\t\t  <soapenv:Body>\n\t\t\t<urn:login>\n\t\t\t  <urn:username>%s</urn:username>\n\t\t\t  <urn:password>%s%s</urn:password>\n\t\t\t</urn:login>\n\t\t  </soapenv:Body>\n\t\t</soapenv:Envelope>`,\n\t\ts.Username, s.Password, s.SecurityToken)\n\n\tloginEndpoint, err := s.getLoginEndpoint()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq, err := http.NewRequest(http.MethodPost, loginEndpoint, strings.NewReader(body))\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Add(\"Content-Type\", \"text/xml\")\n\treq.Header.Add(\"SOAPAction\", \"login\")\n\n\tresp, err := s.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\t//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 200))\n\t\treturn fmt.Errorf(\"%s returned HTTP status %s: %q\", loginEndpoint, resp.Status, body)\n\t}\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsoapFault := struct {\n\t\tCode    string `xml:\"Body>Fault>faultcode\"`\n\t\tMessage string `xml:\"Body>Fault>faultstring\"`\n\t}{}\n\n\terr = xml.Unmarshal(respBody, &soapFault)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif soapFault.Code != \"\" {\n\t\treturn fmt.Errorf(\"login failed: %s\", soapFault.Message)\n\t}\n\n\tloginResult := struct {\n\t\tServerURL      string `xml:\"Body>loginResponse>result>serverUrl\"`\n\t\tSessionID      string `xml:\"Body>loginResponse>result>sessionId\"`\n\t\tOrganizationID string `xml:\"Body>loginResponse>result>userInfo>organizationId\"`\n\t}{}\n\n\terr = xml.Unmarshal(respBody, &loginResult)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.sessionID = loginResult.SessionID\n\ts.organizationID = loginResult.OrganizationID\n\ts.serverURL, err = url.Parse(loginResult.ServerURL)\n\n\treturn err\n}\n\nfunc newSalesforce() *Salesforce {\n\ttr := &http.Transport{\n\t\tResponseHeaderTimeout: 5 * time.Second,\n\t}\n\tclient := &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   10 * time.Second,\n\t}\n\treturn &Salesforce{\n\t\tclient:      client,\n\t\tVersion:     defaultVersion,\n\t\tEnvironment: defaultEnvironment}\n}\n\nfunc init() {\n\tinputs.Add(\"salesforce\", func() telegraf.Input {\n\t\treturn newSalesforce()\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/salesforce/salesforce_test.go",
    "content": "package salesforce\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc Test_Gather(t *testing.T) {\n\tfakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\tif _, err := w.Write([]byte(testJSON)); err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t}))\n\tdefer fakeServer.Close()\n\n\tplugin := newSalesforce()\n\tplugin.sessionID = \"test_session\"\n\tu, err := url.Parse(fakeServer.URL)\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tplugin.serverURL = u\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, acc.GatherError(plugin.Gather))\n\n\trequire.Len(t, acc.Metrics, 1)\n\tm := acc.Metrics[0]\n\trequire.Len(t, m.Fields, 46)\n\trequire.Len(t, m.Tags, 2)\n}\n\nvar testJSON = `{\n  \"ConcurrentAsyncGetReportInstances\" : {\n    \"Max\" : 200,\n    \"Remaining\" : 200\n  },\n  \"ConcurrentSyncReportRuns\" : {\n    \"Max\" : 20,\n    \"Remaining\" : 20\n  },\n  \"DailyApiRequests\" : {\n    \"Max\" : 25000,\n    \"Remaining\" : 24926,\n    \"AgilePoint\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Ant Migration Tool\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Axsy Server Integration\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Desktop\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Mobile for BlackBerry\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Bulk\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Partner\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"EAHelperBot\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Force.com IDE\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce (QA)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"MyU App\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SMS Magic Interact\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Chatter\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Files\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Mobile Dashboards\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Social Customer Service (SCS)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Touch\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce for Outlook\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for Android\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for iOS\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceA\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceIQ\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Workbench\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    }\n  },\n  \"DailyAsyncApexExecutions\" : {\n    \"Max\" : 250000,\n    \"Remaining\" : 250000\n  },\n  \"DailyBulkApiRequests\" : {\n    \"Max\" : 10000,\n    \"Remaining\" : 10000,\n    \"AgilePoint\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Ant Migration Tool\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Axsy Server Integration\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Desktop\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Mobile for BlackBerry\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Bulk\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Partner\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"EAHelperBot\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Force.com IDE\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce (QA)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"MyU App\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SMS Magic Interact\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Chatter\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Files\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Mobile Dashboards\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Social Customer Service (SCS)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Touch\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce for Outlook\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for Android\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for iOS\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceA\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceIQ\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Workbench\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    }\n  },\n  \"DailyDurableGenericStreamingApiEvents\" : {\n    \"Max\" : 10000,\n    \"Remaining\" : 10000\n  },\n  \"DailyDurableStreamingApiEvents\" : {\n    \"Max\" : 10000,\n    \"Remaining\" : 10000\n  },\n  \"DailyGenericStreamingApiEvents\" : {\n    \"Max\" : 10000,\n    \"Remaining\" : 10000,\n    \"AgilePoint\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Ant Migration Tool\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Axsy Server Integration\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Desktop\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Mobile for BlackBerry\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Bulk\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Partner\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"EAHelperBot\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Force.com IDE\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce (QA)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"MyU App\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SMS Magic Interact\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Chatter\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Files\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Mobile Dashboards\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Social Customer Service (SCS)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Touch\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce for Outlook\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for Android\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for iOS\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceA\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceIQ\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Workbench\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    }\n  },\n  \"DailyStreamingApiEvents\" : {\n    \"Max\" : 20000,\n    \"Remaining\" : 20000,\n    \"AgilePoint\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Ant Migration Tool\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Axsy Server Integration\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Desktop\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Chatter Mobile for BlackBerry\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Bulk\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Dataloader Partner\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"EAHelperBot\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Force.com IDE\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"LiveText for Salesforce (QA)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"MyU App\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SMS Magic Interact\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Chatter\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Files\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Mobile Dashboards\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Social Customer Service (SCS)\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce Touch\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce for Outlook\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for Android\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Salesforce1 for iOS\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceA\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"SalesforceIQ\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    },\n    \"Workbench\" : {\n      \"Max\" : 0,\n      \"Remaining\" : 0\n    }\n  },\n  \"DailyWorkflowEmails\" : {\n    \"Max\" : 20000,\n    \"Remaining\" : 20000\n  },\n  \"DataStorageMB\" : {\n    \"Max\" : 209,\n    \"Remaining\" : 207\n  },\n  \"DurableStreamingApiConcurrentClients\" : {\n    \"Max\" : 20,\n    \"Remaining\" : 20\n  },\n  \"FileStorageMB\" : {\n    \"Max\" : 209,\n    \"Remaining\" : 206\n  },\n  \"HourlyAsyncReportRuns\" : {\n    \"Max\" : 1200,\n    \"Remaining\" : 1200\n  },\n  \"HourlyDashboardRefreshes\" : {\n    \"Max\" : 200,\n    \"Remaining\" : 200\n  },\n  \"HourlyDashboardResults\" : {\n    \"Max\" : 5000,\n    \"Remaining\" : 5000\n  },\n  \"HourlyDashboardStatuses\" : {\n    \"Max\" : 999999999,\n    \"Remaining\" : 999999999\n  },\n  \"HourlyODataCallout\" : {\n    \"Max\" : 20000,\n    \"Remaining\" : 19998\n  },\n  \"HourlySyncReportRuns\" : {\n    \"Max\" : 500,\n    \"Remaining\" : 500\n  },\n  \"HourlyTimeBasedWorkflow\" : {\n    \"Max\" : 50,\n    \"Remaining\" : 50\n  },\n  \"MassEmail\" : {\n    \"Max\" : 5000,\n    \"Remaining\" : 5000\n  },\n  \"SingleEmail\" : {\n    \"Max\" : 5000,\n    \"Remaining\" : 5000\n  },\n  \"StreamingApiConcurrentClients\" : {\n    \"Max\" : 20,\n    \"Remaining\" : 20\n  }\n}`\n"
  },
  {
    "path": "plugins/inputs/salesforce/sample.conf",
    "content": "# Read API usage and limits for a Salesforce organisation\n[[inputs.salesforce]]\n  ## specify your credentials\n  ##\n  username = \"your_username\"\n  password = \"your_password\"\n  ##\n  ## (optional) security token\n  # security_token = \"your_security_token\"\n  ##\n  ## (optional) environment type (sandbox or production)\n  ## default is: production\n  ##\n  # environment = \"production\"\n  ##\n  ## (optional) API version (default: \"39.0\")\n  ##\n  # version = \"39.0\"\n"
  },
  {
    "path": "plugins/inputs/sensors/README.md",
    "content": "# LM Sensors Input Plugin\n\nThis plugin collects metrics from hardware sensors using\n[lm-sensors][lmsensors].\n\n> [!NOTE]\n> This plugin requires the lm-sensors package to be installed on the system\n> and `sensors` to be executable from Telegraf.\n\n⭐ Telegraf v0.10.1\n🏷️ hardware, system\n💻 linux\n\n[lmsensors]: https://en.wikipedia.org/wiki/Lm_sensors\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Monitor sensors, requires lm-sensors package\n# This plugin ONLY supports Linux\n[[inputs.sensors]]\n  ## Remove numbers from field names.\n  ## If true, a field name like 'temp1_input' will be changed to 'temp_input'.\n  # remove_numbers = true\n\n  ## Timeout is the maximum amount of time that the sensors command can run.\n  # timeout = \"5s\"\n```\n\n## Metrics\n\nFields are created dynamically depending on the sensors. All fields are float.\n\n- sensors:\n  - tags:\n    - chip\n    - feature\n  - fields:\n    - depending on the available sensor information (float)\n\n## Example Output\n\n### Default\n\n```text\nsensors,chip=power_meter-acpi-0,feature=power1 power_average=0,power_average_interval=300 1466751326000000000\nsensors,chip=k10temp-pci-00c3,feature=temp1 temp_crit=70,temp_crit_hyst=65,temp_input=29,temp_max=70 1466751326000000000\nsensors,chip=k10temp-pci-00cb,feature=temp1 temp_input=29,temp_max=70 1466751326000000000\nsensors,chip=k10temp-pci-00d3,feature=temp1 temp_input=27.5,temp_max=70 1466751326000000000\nsensors,chip=k10temp-pci-00db,feature=temp1 temp_crit=70,temp_crit_hyst=65,temp_input=29.5,temp_max=70 1466751326000000000\n```\n\n### With remove_numbers=false\n\n```text\nsensors,chip=power_meter-acpi-0,feature=power1 power1_average=0,power1_average_interval=300 1466753424000000000\nsensors,chip=k10temp-pci-00c3,feature=temp1 temp1_crit=70,temp1_crit_hyst=65,temp1_input=29.125,temp1_max=70 1466753424000000000\nsensors,chip=k10temp-pci-00cb,feature=temp1 temp1_input=29,temp1_max=70 1466753424000000000\nsensors,chip=k10temp-pci-00d3,feature=temp1 temp1_input=29.5,temp1_max=70 1466753424000000000\nsensors,chip=k10temp-pci-00db,feature=temp1 temp1_crit=70,temp1_crit_hyst=65,temp1_input=30,temp1_max=70 1466753424000000000\n```\n"
  },
  {
    "path": "plugins/inputs/sensors/sample.conf",
    "content": "# Monitor sensors, requires lm-sensors package\n# This plugin ONLY supports Linux\n[[inputs.sensors]]\n  ## Remove numbers from field names.\n  ## If true, a field name like 'temp1_input' will be changed to 'temp_input'.\n  # remove_numbers = true\n\n  ## Timeout is the maximum amount of time that the sensors command can run.\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/sensors/sensors.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage sensors\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\texecCommand    = exec.Command // execCommand is used to mock commands in tests.\n\tnumberRegp     = regexp.MustCompile(\"[0-9]+\")\n\tdefaultTimeout = config.Duration(5 * time.Second)\n)\n\nconst cmd = \"sensors\"\n\ntype Sensors struct {\n\tRemoveNumbers bool            `toml:\"remove_numbers\"`\n\tTimeout       config.Duration `toml:\"timeout\"`\n\tpath          string\n}\n\nfunc (*Sensors) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Sensors) Init() error {\n\t// Set defaults\n\tif s.path == \"\" {\n\t\tpath, err := exec.LookPath(cmd)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"looking up %q failed: %w\", cmd, err)\n\t\t}\n\t\ts.path = path\n\t}\n\n\t// Check parameters\n\tif s.path == \"\" {\n\t\treturn fmt.Errorf(\"no path specified for %q\", cmd)\n\t}\n\n\treturn nil\n}\n\nfunc (s *Sensors) Gather(acc telegraf.Accumulator) error {\n\tif len(s.path) == 0 {\n\t\treturn errors.New(\"sensors not found: verify that lm-sensors package is installed and that sensors is in your PATH\")\n\t}\n\n\treturn s.parse(acc)\n}\n\n// parse forks the command:\n//\n//\tsensors -u -A\n//\n// and parses the output to add it to the telegraf.Accumulator.\nfunc (s *Sensors) parse(acc telegraf.Accumulator) error {\n\ttags := make(map[string]string)\n\tfields := make(map[string]interface{})\n\tchip := \"\"\n\tcmd := execCommand(s.path, \"-A\", \"-u\")\n\tout, err := internal.StdOutputTimeout(cmd, time.Duration(s.Timeout))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to run command %q: %w - %s\", strings.Join(cmd.Args, \" \"), err, string(out))\n\t}\n\tlines := strings.Split(strings.TrimSpace(string(out)), \"\\n\")\n\tfor _, line := range lines {\n\t\tif len(line) == 0 {\n\t\t\tacc.AddFields(\"sensors\", fields, tags)\n\t\t\tchip = \"\"\n\t\t\ttags = make(map[string]string)\n\t\t\tfields = make(map[string]interface{})\n\t\t\tcontinue\n\t\t}\n\t\tif len(chip) == 0 {\n\t\t\tchip = line\n\t\t\ttags[\"chip\"] = chip\n\t\t\tcontinue\n\t\t}\n\t\tif !strings.HasPrefix(line, \"  \") {\n\t\t\tif len(tags) > 1 {\n\t\t\t\tacc.AddFields(\"sensors\", fields, tags)\n\t\t\t}\n\t\t\tfields = make(map[string]interface{})\n\t\t\ttags = map[string]string{\n\t\t\t\t\"chip\":    chip,\n\t\t\t\t\"feature\": strings.TrimRight(snake(line), \":\"),\n\t\t\t}\n\t\t} else {\n\t\t\tsplitted := strings.Split(line, \":\")\n\t\t\tfieldName := strings.TrimSpace(splitted[0])\n\t\t\tif s.RemoveNumbers {\n\t\t\t\tfieldName = numberRegp.ReplaceAllString(fieldName, \"\")\n\t\t\t}\n\t\t\tfieldValue, err := strconv.ParseFloat(strings.TrimSpace(splitted[1]), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfields[fieldName] = fieldValue\n\t\t}\n\t}\n\tacc.AddFields(\"sensors\", fields, tags)\n\treturn nil\n}\n\n// snake converts string to snake case\nfunc snake(input string) string {\n\treturn strings.ToLower(strings.ReplaceAll(strings.TrimSpace(input), \" \", \"_\"))\n}\n\nfunc init() {\n\tinputs.Add(\"sensors\", func() telegraf.Input {\n\t\treturn &Sensors{\n\t\t\tRemoveNumbers: true,\n\t\t\tTimeout:       defaultTimeout,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/sensors/sensors_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage sensors\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Sensors struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Sensors) SampleConfig() string { return sampleConfig }\n\nfunc (s *Sensors) Init() error {\n\ts.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Sensors) Gather(telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"sensors\", func() telegraf.Input {\n\t\treturn &Sensors{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/sensors/sensors_test.go",
    "content": "//go:build linux\n\npackage sensors\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGatherDefault(t *testing.T) {\n\ts := Sensors{\n\t\tRemoveNumbers: true,\n\t\tTimeout:       defaultTimeout,\n\t\tpath:          \"sensors\",\n\t}\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommand\n\tdefer func() { execCommand = exec.Command }()\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, s.Init())\n\trequire.NoError(t, s.Gather(&acc))\n\n\tvar tests = []struct {\n\t\ttags   map[string]string\n\t\tfields map[string]interface{}\n\t}{\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"acpitz-virtual-0\",\n\t\t\t\t\"feature\": \"temp1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\": 8.3,\n\t\t\t\t\"temp_crit\":  31.3,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"power_meter-acpi-0\",\n\t\t\t\t\"feature\": \"power1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power_average\":          0.0,\n\t\t\t\t\"power_average_interval\": 300.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"physical_id_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      77.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"core_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      75.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"core_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      77.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"physical_id_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      70.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"core_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      66.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"core_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp_input\":      70.0,\n\t\t\t\t\"temp_max\":        82.0,\n\t\t\t\t\"temp_crit\":       92.0,\n\t\t\t\t\"temp_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"atk0110-acpi-0\",\n\t\t\t\t\"feature\": \"vcore_voltage\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_input\": 1.136,\n\t\t\t\t\"in_min\":   0.800,\n\t\t\t\t\"in_max\":   1.600,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"atk0110-acpi-0\",\n\t\t\t\t\"feature\": \"+3.3_voltage\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in_input\": 3.360,\n\t\t\t\t\"in_min\":   2.970,\n\t\t\t\t\"in_max\":   3.630,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tacc.AssertContainsTaggedFields(t, \"sensors\", test.fields, test.tags)\n\t}\n}\n\nfunc TestGatherNotRemoveNumbers(t *testing.T) {\n\ts := Sensors{\n\t\tRemoveNumbers: false,\n\t\tTimeout:       defaultTimeout,\n\t\tpath:          \"sensors\",\n\t}\n\t// overwriting exec commands with mock commands\n\texecCommand = fakeExecCommand\n\tdefer func() { execCommand = exec.Command }()\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, s.Init())\n\trequire.NoError(t, s.Gather(&acc))\n\n\tvar tests = []struct {\n\t\ttags   map[string]string\n\t\tfields map[string]interface{}\n\t}{\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"acpitz-virtual-0\",\n\t\t\t\t\"feature\": \"temp1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp1_input\": 8.3,\n\t\t\t\t\"temp1_crit\":  31.3,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"power_meter-acpi-0\",\n\t\t\t\t\"feature\": \"power1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"power1_average\":          0.0,\n\t\t\t\t\"power1_average_interval\": 300.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"physical_id_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp1_input\":      77.0,\n\t\t\t\t\"temp1_max\":        82.0,\n\t\t\t\t\"temp1_crit\":       92.0,\n\t\t\t\t\"temp1_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"core_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp2_input\":      75.0,\n\t\t\t\t\"temp2_max\":        82.0,\n\t\t\t\t\"temp2_crit\":       92.0,\n\t\t\t\t\"temp2_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0000\",\n\t\t\t\t\"feature\": \"core_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp3_input\":      77.0,\n\t\t\t\t\"temp3_max\":        82.0,\n\t\t\t\t\"temp3_crit\":       92.0,\n\t\t\t\t\"temp3_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"physical_id_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp1_input\":      70.0,\n\t\t\t\t\"temp1_max\":        82.0,\n\t\t\t\t\"temp1_crit\":       92.0,\n\t\t\t\t\"temp1_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"core_0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp2_input\":      66.0,\n\t\t\t\t\"temp2_max\":        82.0,\n\t\t\t\t\"temp2_crit\":       92.0,\n\t\t\t\t\"temp2_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"coretemp-isa-0001\",\n\t\t\t\t\"feature\": \"core_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"temp3_input\":      70.0,\n\t\t\t\t\"temp3_max\":        82.0,\n\t\t\t\t\"temp3_crit\":       92.0,\n\t\t\t\t\"temp3_crit_alarm\": 0.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"atk0110-acpi-0\",\n\t\t\t\t\"feature\": \"vcore_voltage\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in0_input\": 1.136,\n\t\t\t\t\"in0_min\":   0.800,\n\t\t\t\t\"in0_max\":   1.600,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\n\t\t\t\t\"chip\":    \"atk0110-acpi-0\",\n\t\t\t\t\"feature\": \"+3.3_voltage\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"in1_input\": 3.360,\n\t\t\t\t\"in1_min\":   2.970,\n\t\t\t\t\"in1_max\":   3.630,\n\t\t\t},\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tacc.AssertContainsTaggedFields(t, \"sensors\", test.fields, test.tags)\n\t}\n}\n\n// fakeExecCommand is a helper function that mock\n// the exec.Command call (and call the test binary)\nfunc fakeExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := []string{\"-test.run=TestHelperProcess\", \"--\", command}\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\n// TestHelperProcess isn't a real test. It's used to mock exec.Command\n// For example, if you run:\n// GO_WANT_HELPER_PROCESS=1 go test -test.run=TestHelperProcess -- chrony tracking\n// it returns below mockData.\nfunc TestHelperProcess(*testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\n\tmockData := `acpitz-virtual-0\ntemp1:\n  temp1_input: 8.300\n  temp1_crit: 31.300\n\npower_meter-acpi-0\npower1:\n  power1_average: 0.000\n  power1_average_interval: 300.000\n\ncoretemp-isa-0000\nPhysical id 0:\n  temp1_input: 77.000\n  temp1_max: 82.000\n  temp1_crit: 92.000\n  temp1_crit_alarm: 0.000\nCore 0:\n  temp2_input: 75.000\n  temp2_max: 82.000\n  temp2_crit: 92.000\n  temp2_crit_alarm: 0.000\nCore 1:\n  temp3_input: 77.000\n  temp3_max: 82.000\n  temp3_crit: 92.000\n  temp3_crit_alarm: 0.000\n\ncoretemp-isa-0001\nPhysical id 1:\n  temp1_input: 70.000\n  temp1_max: 82.000\n  temp1_crit: 92.000\n  temp1_crit_alarm: 0.000\nCore 0:\n  temp2_input: 66.000\n  temp2_max: 82.000\n  temp2_crit: 92.000\n  temp2_crit_alarm: 0.000\nCore 1:\n  temp3_input: 70.000\n  temp3_max: 82.000\n  temp3_crit: 92.000\n  temp3_crit_alarm: 0.000\n\natk0110-acpi-0\nVcore Voltage:\n  in0_input: 1.136\n  in0_min: 0.800\n  in0_max: 1.600\n +3.3 Voltage:\n  in1_input: 3.360\n  in1_min: 2.970\n  in1_max: 3.630\n`\n\n\targs := os.Args\n\n\t// Previous arguments are tests stuff, that looks like :\n\t// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --\n\tcmd, _ := args[3], args[4:]\n\n\tif cmd != \"sensors\" {\n\t\tfmt.Fprint(os.Stdout, \"command not found\")\n\t\t//nolint:revive // error code is important for this \"test\"\n\t\tos.Exit(1)\n\t}\n\n\tfmt.Fprint(os.Stdout, mockData)\n\t//nolint:revive // error code is important for this \"test\"\n\tos.Exit(0)\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/README.md",
    "content": "# SFlow Input Plugin\n\nThis service plugin produces metrics from information received by acting as a\n[SFlow V5][sflow_v5] collector. Currently, the plugin can collect Flow Samples\nof Ethernet / IPv4, IPv4 TCP and UDP headers. Counters and other header samples\nare ignored. Please use the [netflow plugin][netflow] for a more modern and\nsophisticated implementation.\n\n> [!CRITICAL]\n> This plugin produces high cardinality data, which when not controlled for will\n> cause high load on your database. Please make sure to [filter][filtering] the\n> produced metrics or configure your database to avoid cardinality issues!\n\n⭐ Telegraf v1.14.0\n🏷️ network\n💻 all\n\n[sflow_v5]: https://sflow.org/sflow_version_5.txt\n[netflow]: /plugins/inputs/netflow/README.md\n[filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# SFlow V5 Protocol Listener\n[[inputs.sflow]]\n  ## Address to listen for sFlow packets.\n  ##   example: service_address = \"udp://:6343\"\n  ##            service_address = \"udp4://:6343\"\n  ##            service_address = \"udp6://:6343\"\n  service_address = \"udp://:6343\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  # read_buffer_size = \"\"\n```\n\n## Metrics\n\n- sflow\n  - tags:\n    - agent_address      - IP address of the agent obtaining the sflow sample and\n                           sent it to this collector\n    - source_id_type     - type of flow_sample or flow_sample_expanded structures\n    - source_id_index    - index of flow_sample or flow_sample_expanded structures\n    - input_ifindex      - input value of flow_sample or flow_sample_expanded structures\n    - output_ifindex     - output value of flow_sample or flow_sample_expanded structures\n    - sample_direction   - source_id_index, netif_index_in and netif_index_out\n    - header_protocol    - header_protocol field of sampled_header structures\n    - ether_type         - ethernet type of an ETHERNET-ISO88023 header\n    - src_ip             - source IP address of IPv4 or IPv6 structures\n    - src_port           - source port of TCP or UDP structures\n    - src_port_name      - name of the source port\n    - src_mac            - source MAC address of an ETHERNET-ISO88023 header\n    - src_vlan           - source VLAN of extended_switch structure\n    - src_priority       - source priority of extended_switch structure\n    - src_mask_len       - length of source mask of extended_router structure\n    - dst_ip             - destination IP address of IPv4 or IPv6 structures\n    - dst_port           - destination port of TCP or UDP structures\n    - dst_port_name      - name of the destination port\n    - dst_mac            - destination MAC address of an ETHERNET-ISO88023 header\n    - dst_vlan           - destination VLAN of extended_switch structure\n    - dst_priority       - destination priority extended_switch structure\n    - dst_mask_len       - length of destinationd mask of extended_router structure\n    - next_hop           - next hop of extended_router structure\n    - ip_version         - IP version of IPv4 or IPv6 structures\n    - ip_protocol        - IP protocol of IPv4 or IPv6 structures\n    - ip_dscp            - IP DSCP of IPv4 or IPv6 structures\n    - ip_ecn             - IP ECN of IPv4 or IPv6 structures\n    - tcp_urgent_pointer - urgent pointer of TCP structure\n  - fields:\n    - bytes              (int) - product of frame length and packets\n    - drops              (int) - drops field of flow_sample or\n                                 flow_sample_expanded structures\n    - packets            (int) - sampling_rate field of flow_sample or\n                                 flow_sample_expanded structures\n    - frame_length       (int) - frame_length field of sampled_header structures\n    - header_size        (int) - header_size field of sampled_header structures\n    - ip_fragment_offset (int) - ip_ver field of IPv4 structures\n    - ip_header_length   (int) - ip_ver field of IPv4 structures\n    - ip_total_length    (int) - ip_total_len field of IPv4 structures\n    - ip_ttl             (int) - ip_ttl field of IPv4 structures or\n                                 ip_hop_limit field IPv6 structures\n    - tcp_header_length  (int) - size field of TCP structure. This value is\n                                 specified in 32-bit words. It must be multiplied\n                                 by 4 to produce a valuein bytes.\n    - tcp_window_size    (int) - window_size field of TCP structure\n    - udp_length         (int) - length field of UDP structures\n    - ip_flags           (int) - ip_ver field of IPv4 structures\n    - tcp_flags          (int) - TCP flags of TCP IP header (IPv4 or IPv6)\n\n## Troubleshooting\n\nThe [sflowtool][] utility can be used to print sFlow packets, and compared\nagainst the metrics produced by Telegraf.\n\n```sh\nsflowtool -p 6343\n```\n\nIf opening an issue, in addition to the output of sflowtool it will also be\nhelpful to collect a packet capture.  Adjust the interface, host and port as\nneeded:\n\n```sh\nsudo tcpdump -s 0 -i eth0 -w telegraf-sflow.pcap host 127.0.0.1 and port 6343\n```\n\n[sflowtool]: https://github.com/sflow/sflowtool\n\n## Example Output\n\n```text\nsflow,agent_address=0.0.0.0,dst_ip=10.0.0.2,dst_mac=ff:ff:ff:ff:ff:ff,dst_port=40042,ether_type=IPv4,header_protocol=ETHERNET-ISO88023,input_ifindex=6,ip_dscp=27,ip_ecn=0,output_ifindex=1073741823,source_id_index=3,source_id_type=0,src_ip=10.0.0.1,src_mac=ff:ff:ff:ff:ff:ff,src_port=443 bytes=1570i,drops=0i,frame_length=157i,header_length=128i,ip_flags=2i,ip_fragment_offset=0i,ip_total_length=139i,ip_ttl=42i,sampling_rate=10i,tcp_header_length=0i,tcp_urgent_pointer=0i,tcp_window_size=14i 1584473704793580447\n```\n"
  },
  {
    "path": "plugins/inputs/sflow/binaryio/minreader.go",
    "content": "package binaryio\n\nimport \"io\"\n\n// MinimumReader is the implementation for MinReader.\ntype MinimumReader struct {\n\treader                 io.Reader\n\tminNumberOfBytesToRead int64 // Min number of bytes we need to read from the reader\n}\n\n// MinReader reads from the reader but ensures there is at least N bytes read from the reader.\n// The reader should call Close() when they are done reading.\n// Closing the MinReader will read and discard any unread bytes up to minNumberOfBytesToRead.\n// CLosing the MinReader does NOT close the underlying reader.\n// The underlying implementation is a MinimumReader, which implements ReaderCloser.\nfunc MinReader(r io.Reader, minNumberOfBytesToRead int64) *MinimumReader {\n\treturn &MinimumReader{\n\t\treader:                 r,\n\t\tminNumberOfBytesToRead: minNumberOfBytesToRead,\n\t}\n}\n\nfunc (r *MinimumReader) Read(p []byte) (n int, err error) {\n\tn, err = r.reader.Read(p)\n\tr.minNumberOfBytesToRead -= int64(n)\n\treturn n, err\n}\n\n// Close does not close the underlying reader, only the MinimumReader\nfunc (r *MinimumReader) Close() error {\n\tif r.minNumberOfBytesToRead > 0 {\n\t\tb := make([]byte, r.minNumberOfBytesToRead)\n\t\t_, err := r.reader.Read(b)\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/binaryio/minreader_test.go",
    "content": "package binaryio\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestMinReader(t *testing.T) {\n\tb := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}\n\tr := bytes.NewBuffer(b)\n\n\tmr := MinReader(r, 10)\n\n\ttoRead := make([]byte, 5)\n\tn, err := mr.Read(toRead)\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tif n != 5 {\n\t\tt.Error(\"Expected n to be 5, but was \", n)\n\t}\n\tif !bytes.Equal(toRead, []byte{1, 2, 3, 4, 5}) {\n\t\tt.Error(\"expected 5 specific bytes to be read\")\n\t}\n\terr = mr.Close()\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tn, err = r.Read(toRead) // read from the outer stream\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tif n != 5 {\n\t\tt.Error(\"Expected n to be 5, but was \", n)\n\t}\n\tif !bytes.Equal(toRead, []byte{11, 12, 13, 14, 15}) {\n\t\tt.Error(\"expected the last 5 bytes to be read\")\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/decoder_test.go",
    "content": "package sflow\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestIPv4SW(t *testing.T) {\n\tstr := `00000005` + // version\n\t\t`00000001` + // address type\n\t\t`c0a80102` + // ip address\n\t\t`00000010` + // sub agent id\n\t\t`0000f3d4` + // sequence number\n\t\t`0bfa047f` + // uptime\n\t\t`00000002` + // sample count\n\t\t`00000001` + // sample type\n\t\t`000000d0` + // sample data length\n\t\t`0001210a` + // sequence number\n\t\t`000001fe` + // source id 00 = source id type, 0001fe = source id index\n\t\t`00000400` + // sampling rate.. apparently this should be input if index????\n\t\t`04842400` + // sample pool\n\t\t`00000000` + // drops\n\t\t`000001fe` + // input if index\n\t\t`00000200` + // output if index\n\t\t`00000002` + // flow records count\n\t\t`00000001` + // FlowFormat\n\t\t`00000090` + // flow length\n\t\t`00000001` + // header protocol\n\t\t`0000010b` + // Frame length\n\t\t`00000004` + // stripped octets\n\t\t`00000080` + // header length\n\t\t`000c2936d3d6` + // dest mac\n\t\t`94c691aa9760` + // source mac\n\t\t`0800` + // etype code: ipv4\n\t\t`4500` + // dscp + ecn\n\t\t`00f9` + // total length\n\t\t`f190` + // identification\n\t\t`4000` + // fragment offset + flags\n\t\t`40` + // ttl\n\t\t`11` + // protocol\n\t\t`b4f5` + // header checksum\n\t\t`c0a80913` + // source ip\n\t\t`c0a8090a` + // dest ip\n\t\t`00a1` + // source port\n\t\t`ba05` + // dest port\n\t\t`00e5` + // udp length\n\t\t// rest of header/flowSample we ignore\n\t\t`641f3081da02010104066d6f746f6770a281cc02047b46462e0201000201003081bd3012060d2b06010201190501010281dc710201003013060d2b060` +\n\t\t`10201190501010281e66802025acc3012060d2b0601020119050101` +\n\t\t// next flow record - ignored\n\t\t`000003e90000001000000009000000000000000900000000` +\n\t\t// next sample\n\t\t`00000001000000d00000e3cc000002100000400048eb74000000000000000210000002000000000200000001000000900000000100000097000000040` +\n\t\t`0000080000c2936d3d6fcecda44008f81000009080045000081186440003f119098c0a80815c0a8090a9a690202006d23083c33303e41707220313120` +\n\t\t`30393a33333a3031206b6e6f64653120736e6d70645b313039385d3a20436f6e6e656374696f6e2066726f6d205544503a205b3139322e3136382e392` +\n\t\t`e31305d3a34393233362d000003e90000001000000009000000000000000900000000`\n\tpacket, err := hex.DecodeString(str)\n\trequire.NoError(t, err)\n\n\tactual := make([]telegraf.Metric, 0)\n\tdc := newDecoder()\n\tdc.onPacket(func(p *v5Format) {\n\t\tmetrics := makeMetrics(p)\n\t\tactual = append(actual, metrics...)\n\t})\n\tbuf := bytes.NewReader(packet)\n\terr = dc.decode(buf)\n\trequire.NoError(t, err)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"192.168.1.2\",\n\t\t\t\t\"dst_ip\":           \"192.168.9.10\",\n\t\t\t\t\"dst_mac\":          \"00:0c:29:36:d3:d6\",\n\t\t\t\t\"dst_port\":         \"47621\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"510\",\n\t\t\t\t\"output_ifindex\":   \"512\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"510\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.9.19\",\n\t\t\t\t\"src_mac\":          \"94:c6:91:aa:97:60\",\n\t\t\t\t\"src_port\":         \"161\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x042c00),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x010b),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0xf9),\n\t\t\t\t\"ip_ttl\":             uint64(0x40),\n\t\t\t\t\"sampling_rate\":      uint64(0x0400),\n\t\t\t\t\"udp_length\":         uint64(0xe5),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"192.168.1.2\",\n\t\t\t\t\"dst_ip\":           \"192.168.9.10\",\n\t\t\t\t\"dst_mac\":          \"00:0c:29:36:d3:d6\",\n\t\t\t\t\"dst_port\":         \"514\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"528\",\n\t\t\t\t\"output_ifindex\":   \"512\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"528\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.8.21\",\n\t\t\t\t\"src_mac\":          \"fc:ec:da:44:00:8f\",\n\t\t\t\t\"src_port\":         \"39529\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x25c000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x97),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x81),\n\t\t\t\t\"ip_ttl\":             uint64(0x3f),\n\t\t\t\t\"sampling_rate\":      uint64(0x4000),\n\t\t\t\t\"udp_length\":         uint64(0x6d),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc BenchmarkDecodeIPv4SW(b *testing.B) {\n\tpacket, err := hex.DecodeString(\n\t\t\"0000000500000001c0a80102000000100000f3d40bfa047f0000000200000001000000d00001210a000001fe000004000484240000000000000001fe0\" +\n\t\t\t\"0000200000000020000000100000090000000010000010b0000000400000080000c2936d3d694c691aa97600800450000f9f19040004011b4f5c0a80\" +\n\t\t\t\"913c0a8090a00a1ba0500e5641f3081da02010104066d6f746f6770a281cc02047b46462e0201000201003081bd3012060d2b0601020119050101028\" +\n\t\t\t\"1dc710201003013060d2b06010201190501010281e66802025acc3012060d2b0601020119050101000003e9000000100000000900000000000000090\" +\n\t\t\t\"000000000000001000000d00000e3cc000002100000400048eb740000000000000002100000020000000002000000010000009000000001000000970\" +\n\t\t\t\"000000400000080000c2936d3d6fcecda44008f81000009080045000081186440003f119098c0a80815c0a8090a9a690202006d23083c33303e41707\" +\n\t\t\t\"22031312030393a33333a3031206b6e6f64653120736e6d70645b313039385d3a20436f6e6e656374696f6e2066726f6d205544503a205b3139322e3\" +\n\t\t\t\"136382e392e31305d3a34393233362d000003e90000001000000009000000000000000900000000\",\n\t)\n\trequire.NoError(b, err)\n\n\tdc := newDecoder()\n\trequire.NoError(b, err)\n\n\tb.ResetTimer()\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err = dc.decodeOnePacket(bytes.NewBuffer(packet))\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\nfunc TestExpandFlow(t *testing.T) {\n\tpacket, err := hex.DecodeString(\n\t\t\"00000005000000010a00015000000000000f58998ae119780000000300000003000000c4000b62a90000000000100c840000040024fb7e1e000000000\" +\n\t\t\t\"0000000001017840000000000100c8400000001000000010000009000000001000005bc0000000400000080001b17000130001201f58d44810023710\" +\n\t\t\t\"800450205a6305440007e06ee92ac100016d94d52f505997e701fa1e17aff62574a50100200355f000000ffff00000b004175746f72697a7a6174610\" +\n\t\t\t\"400008040ffff000400008040050031303030320500313030302004000000000868a200000000000000000860a200000000000000000003000000c40\" +\n\t\t\t\"003cecf000000000010170400004000a168ac1c000000000000000000101784000000000010170400000001000000010000009000000001000005f20\" +\n\t\t\t\"0000004000000800024e8324338d4ae52aa0b54810020060800450005dc5420400080061397c0a8060cc0a806080050efcfbb25bad9a21c839a50100\" +\n\t\t\t\"0fff54000008a55f70975a0ff88b05735597ae274bd81fcba17e6e9206b8ea0fb07d05fc27dad06cfe3fdba5d2fc4d057b0add711e596cbe5e9b4bbe\" +\n\t\t\t\"8be59cd77537b7a89f7414a628b736d00000003000000c0000c547a0000000000100c04000004005bc3c3b5000000000000000000101784000000000\" +\n\t\t\t\"0100c0400000001000000010000008c000000010000007e000000040000007a001b17000130001201f58d448100237108004500006824ea4000ff32c\" +\n\t\t\t\"326d94d5105501018f02e88d003000001dd39b1d025d1c68689583b2ab21522d5b5a959642243804f6d51e63323091cc04544285433eb3f6b29e1046\" +\n\t\t\t\"a6a2fa7806319d62041d8fa4bd25b7cd85b8db54202054a077ac11de84acbe37a550004\",\n\t)\n\trequire.NoError(t, err)\n\n\tdc := newDecoder()\n\tp, err := dc.decodeOnePacket(bytes.NewBuffer(packet))\n\trequire.NoError(t, err)\n\tactual := makeMetrics(p)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"217.77.82.245\",\n\t\t\t\t\"dst_mac\":          \"00:1b:17:00:01:30\",\n\t\t\t\t\"dst_port\":         \"32368\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1054596\",\n\t\t\t\t\"output_ifindex\":   \"1051780\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1051780\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"172.16.0.22\",\n\t\t\t\t\"src_mac\":          \"00:12:01:f5:8d:44\",\n\t\t\t\t\"src_port\":         \"1433\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x16f000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x05bc),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x05a6),\n\t\t\t\t\"ip_ttl\":             uint64(0x7e),\n\t\t\t\t\"sampling_rate\":      uint64(0x0400),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0x0200),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"2\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"192.168.6.8\",\n\t\t\t\t\"dst_mac\":          \"00:24:e8:32:43:38\",\n\t\t\t\t\"dst_port\":         \"61391\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1054596\",\n\t\t\t\t\"output_ifindex\":   \"1054468\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1054468\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.6.12\",\n\t\t\t\t\"src_mac\":          \"d4:ae:52:aa:0b:54\",\n\t\t\t\t\"src_port\":         \"80\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x017c8000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x05f2),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x05dc),\n\t\t\t\t\"ip_ttl\":             uint64(0x80),\n\t\t\t\t\"sampling_rate\":      uint64(0x4000),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0xff),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"80.16.24.240\",\n\t\t\t\t\"dst_mac\":          \"00:1b:17:00:01:30\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1054596\",\n\t\t\t\t\"output_ifindex\":   \"1051652\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1051652\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"217.77.81.5\",\n\t\t\t\t\"src_mac\":          \"00:12:01:f5:8d:44\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x01f800),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x7e),\n\t\t\t\t\"header_length\":      uint64(0x7a),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x68),\n\t\t\t\t\"ip_ttl\":             uint64(0xff),\n\t\t\t\t\"sampling_rate\":      uint64(0x0400),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestIPv4SWRT(t *testing.T) {\n\tpacket, err := hex.DecodeString(\n\t\t\"000000050000000189dd4f010000000000003d4f21151ad40000000600000001000000bc354b97090000020c000013b175792bea000000000000028f0\" +\n\t\t\t\"000020c0000000300000001000000640000000100000058000000040000005408b2587a57624c16fc0b61a5080045000046c3e440003a1118a0052aa\" +\n\t\t\t\"da7569e5ab367a6e35b0032d7bbf1f2fb2eb2490a97f87abc31e135834be367000002590000ffffffffffffffff02add830d51e0aec14cf000003e90\" +\n\t\t\t\"000001000000000000000000000000000000000000003ea0000001000000001c342e32a000000160000000b00000001000000a88b8ffb57000002a20\" +\n\t\t\t\"00013b12e344fd800000000000002a20000028f0000000300000001000000500000000100000042000000040000003e4c16fc0b6202c03e0fdecafe0\" +\n\t\t\t\"80045000030108000007d11fe45575185a718693996f0570e8c001c20614ad602003fd6d4afa6a6d18207324000271169b00000000003e9000000100\" +\n\t\t\t\"0000000000000000000000000000000000003ea000000100000000189dd4f210000000f0000001800000001000000e8354b970a0000020c000013b17\" +\n\t\t\t\"5793f9b000000000000028f0000020c00000003000000010000009000000001000001a500000004000000800231466d0b2c4c16fc0b61a5080045000\" +\n\t\t\t\"193198f40003a114b75052aae1f5f94c778678ef24d017f50ea7622287c30799e1f7d45932d01ca92c46d930000927c0000ffffffffffffffff02ad0\" +\n\t\t\t\"eea6498953d1c7ebb6dbdf0525c80e1a9a62bacfea92f69b7336c2f2f60eba0593509e14eef167eb37449f05ad70b8241c1a46d000003e9000000100\" +\n\t\t\t\"0000000000000000000000000000000000003ea0000001000000001c342e1fd000000160000001000000001000000e8354b970b0000020c000013b17\" +\n\t\t\t\"579534c000000000000028f0000020c00000003000000010000009000000001000000b500000004000000800231466d0b2c4c16fc0b61a5080045000\" +\n\t\t\t\"0a327c240003606fd67b93c706a021ff365045fe8a0976d624df8207083501800edb31b0000485454502f312e3120323030204f4b0d0a53657276657\" +\n\t\t\t\"23a2050726f746f636f6c20485454500d0a436f6e74656e742d4c656e6774683a20313430340d0a436f6e6e656374696f6e3a20000003e9000000100\" +\n\t\t\t\"0000000000000000000000000000000000003ea0000001000000001c342e1fd000000170000001000000001000000e8354b970c0000020c000013b17\" +\n\t\t\t\"57966fd000000000000028f0000020c000000030000000100000090000000010000018e00000004000000800231466d0b2c4c16fc0b61a5080045000\" +\n\t\t\t\"17c7d2c40003a116963052abd8d021c940e67e7e0d501682342dbe7936bd47ef487dee5591ec1b24d83622e000072250000ffffffffffffffff02ad0\" +\n\t\t\t\"039d8ba86a90017071d76b177de4d8c4e23bcaaaf4d795f77b032f959e0fb70234d4c28922d4e08dd3330c66e34bff51cc8ade5000003e9000000100\" +\n\t\t\t\"0000000000000000000000000000000000003ea0000001000000001c342e1fd000000160000001000000001000000e80d6146ac000002a1000013b17\" +\n\t\t\t\"880b49d00000000000002a10000028f00000003000000010000009000000001000005ee00000004000000804c16fc0b6201d8b122766a2c080045000\" +\n\t\t\t\"5dc04574000770623a11fcd80a218691d4cf2fe01bbd4f47482065fd63a5010fabd7987000052a20002c8c43ea91ca1eaa115663f5218a37fbb409df\" +\n\t\t\t\"bbedff54731ef41199b35535905ac2366a05a803146ced544abf45597f3714327d59f99e30c899c39fc5a4b67d12087bf8db2bc000003e9000000100\" +\n\t\t\t\"0000000000000000000000000000000000003ea000000100000000189dd4f210000001000000018\",\n\t)\n\trequire.NoError(t, err)\n\n\tdc := newDecoder()\n\tp, err := dc.decodeOnePacket(bytes.NewBuffer(packet))\n\trequire.NoError(t, err)\n\tactual := makeMetrics(p)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"86.158.90.179\",\n\t\t\t\t\"dst_mac\":          \"08:b2:58:7a:57:62\",\n\t\t\t\t\"dst_port\":         \"58203\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"655\",\n\t\t\t\t\"output_ifindex\":   \"524\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"524\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"5.42.173.167\",\n\t\t\t\t\"src_mac\":          \"4c:16:fc:0b:61:a5\",\n\t\t\t\t\"src_port\":         \"26534\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x06c4d8),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x58),\n\t\t\t\t\"header_length\":      uint64(0x54),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x46),\n\t\t\t\t\"ip_ttl\":             uint64(0x3a),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"udp_length\":         uint64(0x32),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"24.105.57.150\",\n\t\t\t\t\"dst_mac\":          \"4c:16:fc:0b:62:02\",\n\t\t\t\t\"dst_port\":         \"3724\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"674\",\n\t\t\t\t\"output_ifindex\":   \"655\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"674\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"87.81.133.167\",\n\t\t\t\t\"src_mac\":          \"c0:3e:0f:de:ca:fe\",\n\t\t\t\t\"src_port\":         \"61527\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x0513a2),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x42),\n\t\t\t\t\"header_length\":      uint64(0x3e),\n\t\t\t\t\"ip_flags\":           uint64(0x00),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x30),\n\t\t\t\t\"ip_ttl\":             uint64(0x7d),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"udp_length\":         uint64(0x1c),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"95.148.199.120\",\n\t\t\t\t\"dst_mac\":          \"02:31:46:6d:0b:2c\",\n\t\t\t\t\"dst_port\":         \"62029\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"655\",\n\t\t\t\t\"output_ifindex\":   \"524\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"524\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"5.42.174.31\",\n\t\t\t\t\"src_mac\":          \"4c:16:fc:0b:61:a5\",\n\t\t\t\t\"src_port\":         \"26510\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x206215),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x01a5),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x0193),\n\t\t\t\t\"ip_ttl\":             uint64(0x3a),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"udp_length\":         uint64(0x017f),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"2.31.243.101\",\n\t\t\t\t\"dst_mac\":          \"02:31:46:6d:0b:2c\",\n\t\t\t\t\"dst_port\":         \"59552\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"655\",\n\t\t\t\t\"output_ifindex\":   \"524\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"524\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"185.60.112.106\",\n\t\t\t\t\"src_mac\":          \"4c:16:fc:0b:61:a5\",\n\t\t\t\t\"src_port\":         \"1119\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x0dec25),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0xb5),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0xa3),\n\t\t\t\t\"ip_ttl\":             uint64(0x36),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0xed),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"2.28.148.14\",\n\t\t\t\t\"dst_mac\":          \"02:31:46:6d:0b:2c\",\n\t\t\t\t\"dst_port\":         \"57557\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"655\",\n\t\t\t\t\"output_ifindex\":   \"524\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"524\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"5.42.189.141\",\n\t\t\t\t\"src_mac\":          \"4c:16:fc:0b:61:a5\",\n\t\t\t\t\"src_port\":         \"26599\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x1e9d2e),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x018e),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x017c),\n\t\t\t\t\"ip_ttl\":             uint64(0x3a),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"udp_length\":         uint64(0x0168),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"137.221.79.1\",\n\t\t\t\t\"dst_ip\":           \"24.105.29.76\",\n\t\t\t\t\"dst_mac\":          \"4c:16:fc:0b:62:01\",\n\t\t\t\t\"dst_port\":         \"443\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"673\",\n\t\t\t\t\"output_ifindex\":   \"655\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"673\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"31.205.128.162\",\n\t\t\t\t\"src_mac\":          \"d8:b1:22:76:6a:2c\",\n\t\t\t\t\"src_port\":         \"62206\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x74c38e),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x05ee),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x05dc),\n\t\t\t\t\"ip_ttl\":             uint64(0x77),\n\t\t\t\t\"sampling_rate\":      uint64(0x13b1),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0xfabd),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestIPv6SW(t *testing.T) {\n\tpacket, err := hex.DecodeString(\n\t\t\"00000005000000010ae0648100000002000093d824ac82340000000100000001000000d000019f94000001010000100019f9400000000000000001010\" +\n\t\t\t\"0000000000000020000000100000090000000010000058c00000008000000800008e3fffc10d4f4be04612486dd60000000054e113a2607f8b040020\" +\n\t\t\t\"0140000000000000008262000edc000e804a25e30c581af36fa01bbfa6f054e249810b584bcbf12926c2e29a779c26c72db483e8191524fe2288bfda\" +\n\t\t\t\"ceaf9d2e724d04305706efcfdef70db86873bbacf29698affe4e7d6faa21d302f9b4b023291a05a000003e90000001000000001000000000000000100000000\",\n\t)\n\trequire.NoError(t, err)\n\n\tdc := newDecoder()\n\tp, err := dc.decodeOnePacket(bytes.NewBuffer(packet))\n\trequire.NoError(t, err)\n\tactual := makeMetrics(p)\n\n\texpected := []telegraf.Metric{\n\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.224.100.129\",\n\t\t\t\t\"dst_ip\":           \"2620:ed:c000:e804:a25e:30c5:81af:36fa\",\n\t\t\t\t\"dst_mac\":          \"00:08:e3:ff:fc:10\",\n\t\t\t\t\"dst_port\":         \"64111\",\n\t\t\t\t\"ether_type\":       \"IPv6\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"257\",\n\t\t\t\t\"output_ifindex\":   \"0\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"257\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"2607:f8b0:4002:14::8\",\n\t\t\t\t\"src_mac\":          \"d4:f4:be:04:61:24\",\n\t\t\t\t\"src_port\":         \"443\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":          uint64(0x58c000),\n\t\t\t\t\"drops\":          uint64(0x00),\n\t\t\t\t\"frame_length\":   uint64(0x058c),\n\t\t\t\t\"header_length\":  uint64(0x80),\n\t\t\t\t\"sampling_rate\":  uint64(0x1000),\n\t\t\t\t\"payload_length\": uint64(0x054e),\n\t\t\t\t\"udp_length\":     uint64(0x054e),\n\t\t\t\t\"ip_dscp\":        \"0\",\n\t\t\t\t\"ip_ecn\":         \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestExpandFlowCounter(t *testing.T) {\n\tpacket, err := hex.DecodeString(\n\t\t\"00000005000000010a00015000000000000f58898ae0fa380000000700000004000000ec00006ece00000000001017840000000300000002000000340\" +\n\t\t\t\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000580\" +\n\t\t\t\"01017840000000600000002540be400000000010000000300007b8ebd37b97e61ff94860803e8e908ffb2b500000000000000000000000000018e7c3\" +\n\t\t\t\"1ee7ba4195f041874579ff021ba936300000000000000000000000100000007000000380011223344550003f8b15645e7e7d6960000002fe2fc02fc0\" +\n\t\t\t\"1edbf580000000000000000000000000000000001dcb9cf000000000000000000000004000000ec00006ece000000000010018400000003000000020\" +\n\t\t\t\"000003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010\" +\n\t\t\t\"0000058001001840000000600000002540be400000000010000000300000841131d1fd9f850bfb103617cb401e659890000000000000000000000000\" +\n\t\t\t\"0000bec1902e5da9212e3e96d7996e922513250000000000000000000000001000000070000003800112233445500005c260acbddb3000100000003e\" +\n\t\t\t\"2fc02fc01ee414f0000000000000000000000000000000001dccdd30000000000000000000000030000008400004606000000000010030400004000a\" +\n\t\t\t\"d9dc19b0000000000000000001017840000000000100304000000010000000100000050000000010000004400000004000000400012815116c400151\" +\n\t\t\t\"7cf426d8100200608004500002895da40008006d74bc0a8060ac0a8064f04ef04aab1797122cf7eaf4f5010ffff77270000000000000000000000030\" +\n\t\t\t\"00000b0001bd698000000000010148400000400700b180f000000000000000000101504000000000010148400000001000000010000007c000000010\" +\n\t\t\t\"000006f000000040000006b001b17000131f0f755b9afc081000439080045000059045340005206920c1f0d4703d94d52e201bbf14977d1e9f15498a\" +\n\t\t\t\"f36801800417f1100000101080afdf3c70400e043871503010020ff268cfe2e2fd5fffe1d3d704a91d57b895f174c4b4428c66679d80a307294303f0\" +\n\t\t\t\"0000003000000c40003ceca000000000010170400004000a166aa7a00000000000000000010178400000000001017040000000100000001000000900\" +\n\t\t\t\"0000001000005f200000004000000800024e8369e2bd4ae52aa0b54810020060800450005dc4c71400080061b45c0a8060cc0a806090050f855692a7\" +\n\t\t\t\"a94a1154ae1801001046b6a00000101080a6869a48d151016d046a84a7aa1c6743fa05179f7ecbd4e567150cb6f2077ff89480ae730637d26d2237c0\" +\n\t\t\t\"8548806f672c7476eb1b5a447b42cb9ce405994d152fa3e000000030000008c001bd699000000000010148400000400700b180f00000000000000000\" +\n\t\t\t\"01015040000000000101484000000010000000100000058000000010000004a0000000400000046001b17000131f0f755b9afc081000439080045000\" +\n\t\t\t\"0340ce040003a06bea5c1ce8793d94d528f00504c3b08b18f275b83d5df8010054586ad00000101050a5b83d5de5b83d5df11d800000003000000c40\" +\n\t\t\t\"0004e07000000000010028400004000c7ec97f2000000000000000000100784000000000010028400000001000000010000009000000001000005f20\" +\n\t\t\t\"00000040000008000005e0001ff005056800dd18100000a0800450005dc5a42400040066ef70a000ac8c0a8967201bbe17c81597908caf8a05f50100\" +\n\t\t\t\"10328610000f172263da0ba5d6223c079b8238bc841256bf17c4ffb08ad11c4fbff6f87ae1624a6b057b8baa9342114e5f5b46179083020cb560c4e9\" +\n\t\t\t\"eadcec6dfd83e102ddbc27024803eb5\",\n\t)\n\trequire.NoError(t, err)\n\n\tdc := newDecoder()\n\tp, err := dc.decodeOnePacket(bytes.NewBuffer(packet))\n\trequire.NoError(t, err)\n\tactual := makeMetrics(p)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"192.168.6.79\",\n\t\t\t\t\"dst_mac\":          \"00:12:81:51:16:c4\",\n\t\t\t\t\"dst_port\":         \"1194\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1054596\",\n\t\t\t\t\"output_ifindex\":   \"1049348\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1049348\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.6.10\",\n\t\t\t\t\"src_mac\":          \"00:15:17:cf:42:6d\",\n\t\t\t\t\"src_port\":         \"1263\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x110000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x44),\n\t\t\t\t\"header_length\":      uint64(0x40),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x28),\n\t\t\t\t\"ip_ttl\":             uint64(0x80),\n\t\t\t\t\"sampling_rate\":      uint64(0x4000),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0xffff),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"217.77.82.226\",\n\t\t\t\t\"dst_mac\":          \"00:1b:17:00:01:31\",\n\t\t\t\t\"dst_port\":         \"61769\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1053956\",\n\t\t\t\t\"output_ifindex\":   \"1053828\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1053828\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"31.13.71.3\",\n\t\t\t\t\"src_mac\":          \"f0:f7:55:b9:af:c0\",\n\t\t\t\t\"src_port\":         \"443\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x01bc00),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x6f),\n\t\t\t\t\"header_length\":      uint64(0x6b),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x59),\n\t\t\t\t\"ip_ttl\":             uint64(0x52),\n\t\t\t\t\"sampling_rate\":      uint64(0x0400),\n\t\t\t\t\"tcp_header_length\":  uint64(0x20),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0x41),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"192.168.6.9\",\n\t\t\t\t\"dst_mac\":          \"00:24:e8:36:9e:2b\",\n\t\t\t\t\"dst_port\":         \"63573\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1054596\",\n\t\t\t\t\"output_ifindex\":   \"1054468\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1054468\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.6.12\",\n\t\t\t\t\"src_mac\":          \"d4:ae:52:aa:0b:54\",\n\t\t\t\t\"src_port\":         \"80\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x017c8000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x05f2),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x05dc),\n\t\t\t\t\"ip_ttl\":             uint64(0x80),\n\t\t\t\t\"sampling_rate\":      uint64(0x4000),\n\t\t\t\t\"tcp_header_length\":  uint64(0x20),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0x0104),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"217.77.82.143\",\n\t\t\t\t\"dst_mac\":          \"00:1b:17:00:01:31\",\n\t\t\t\t\"dst_port\":         \"19515\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1053956\",\n\t\t\t\t\"output_ifindex\":   \"1053828\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1053828\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"193.206.135.147\",\n\t\t\t\t\"src_mac\":          \"f0:f7:55:b9:af:c0\",\n\t\t\t\t\"src_port\":         \"80\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x012800),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x4a),\n\t\t\t\t\"header_length\":      uint64(0x46),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x34),\n\t\t\t\t\"ip_ttl\":             uint64(0x3a),\n\t\t\t\t\"sampling_rate\":      uint64(0x0400),\n\t\t\t\t\"tcp_header_length\":  uint64(0x20),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0x0545),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"10.0.1.80\",\n\t\t\t\t\"dst_ip\":           \"192.168.150.114\",\n\t\t\t\t\"dst_mac\":          \"00:00:5e:00:01:ff\",\n\t\t\t\t\"dst_port\":         \"57724\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"1050500\",\n\t\t\t\t\"output_ifindex\":   \"1049220\",\n\t\t\t\t\"sample_direction\": \"egress\",\n\t\t\t\t\"source_id_index\":  \"1049220\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"10.0.10.200\",\n\t\t\t\t\"src_mac\":          \"00:50:56:80:0d:d1\",\n\t\t\t\t\"src_port\":         \"443\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(0x017c8000),\n\t\t\t\t\"drops\":              uint64(0x00),\n\t\t\t\t\"frame_length\":       uint64(0x05f2),\n\t\t\t\t\"header_length\":      uint64(0x80),\n\t\t\t\t\"ip_flags\":           uint64(0x02),\n\t\t\t\t\"ip_fragment_offset\": uint64(0x00),\n\t\t\t\t\"ip_total_length\":    uint64(0x05dc),\n\t\t\t\t\"ip_ttl\":             uint64(0x40),\n\t\t\t\t\"sampling_rate\":      uint64(0x4000),\n\t\t\t\t\"tcp_header_length\":  uint64(0x14),\n\t\t\t\t\"tcp_urgent_pointer\": uint64(0x00),\n\t\t\t\t\"tcp_window_size\":    uint64(0x0103),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestFlowExpandCounter(t *testing.T) {\n\tpacket, err := hex.DecodeString(\n\t\t\"00000005000000010a000150000000000006d14d8ae0fe200000000200000004000000ac00006d15000000004b00ca000000000200000002000000340\" +\n\t\t\t\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000584\" +\n\t\t\t\"b00ca0000000001000000000000000000000001000000010000308ae33bb950eb92a8a3004d0bb406899571000000000000000000000000000012f7e\" +\n\t\t\t\"d9c9db8c24ed90604eaf0bd04636edb00000000000000000000000100000004000000ac00006d15000000004b0054000000000200000002000000340\" +\n\t\t\t\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000584\" +\n\t\t\t\"b00540000000001000000003b9aca000000000100000003000067ba8e64fd23fa65f26d0215ec4a0021086600000000000000000000000000002002c\" +\n\t\t\t\"3b21045c2378ad3001fb2f300061872000000000000000000000001\",\n\t)\n\trequire.NoError(t, err)\n\n\tdc := newDecoder()\n\tp, err := dc.decodeOnePacket(bytes.NewBuffer(packet))\n\trequire.NoError(t, err)\n\tactual := makeMetrics(p)\n\n\t// we don't do anything with samples yet\n\texpected := make([]telegraf.Metric, 0)\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/metricencoder.go",
    "content": "package sflow\n\nimport (\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/metric\"\n)\n\nfunc makeMetrics(p *v5Format) []telegraf.Metric {\n\tnow := time.Now()\n\tmetrics := make([]telegraf.Metric, 0)\n\ttags := map[string]string{\n\t\t\"agent_address\": p.agentAddress.String(),\n\t}\n\tfields := make(map[string]interface{}, 2)\n\tfor _, sample := range p.samples {\n\t\ttags[\"input_ifindex\"] = strconv.FormatUint(uint64(sample.smplData.inputIfIndex), 10)\n\t\ttags[\"output_ifindex\"] = strconv.FormatUint(uint64(sample.smplData.outputIfIndex), 10)\n\t\ttags[\"sample_direction\"] = sample.smplData.sampleDirection\n\t\ttags[\"source_id_index\"] = strconv.FormatUint(uint64(sample.smplData.sourceIDIndex), 10)\n\t\ttags[\"source_id_type\"] = strconv.FormatUint(uint64(sample.smplData.sourceIDType), 10)\n\t\tfields[\"drops\"] = sample.smplData.drops\n\t\tfields[\"sampling_rate\"] = sample.smplData.samplingRate\n\n\t\tfor _, flowRecord := range sample.smplData.flowRecords {\n\t\t\tif flowRecord.flowData != nil {\n\t\t\t\ttags2 := flowRecord.flowData.getTags()\n\t\t\t\tfields2 := flowRecord.flowData.getFields()\n\t\t\t\tfor k, v := range tags {\n\t\t\t\t\ttags2[k] = v\n\t\t\t\t}\n\t\t\t\tfor k, v := range fields {\n\t\t\t\t\tfields2[k] = v\n\t\t\t\t}\n\t\t\t\tm := metric.New(\"sflow\", tags2, fields2, now)\n\t\t\t\tmetrics = append(metrics, m)\n\t\t\t}\n\t\t}\n\t}\n\treturn metrics\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/packetdecoder.go",
    "content": "package sflow\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs/sflow/binaryio\"\n)\n\ntype packetDecoder struct {\n\tonPacketF func(p *v5Format)\n\tLog       telegraf.Logger\n}\n\nfunc newDecoder() *packetDecoder {\n\treturn &packetDecoder{}\n}\n\nfunc (d *packetDecoder) debug(args ...interface{}) {\n\tif d.Log != nil {\n\t\td.Log.Debug(args...)\n\t}\n}\n\nfunc (d *packetDecoder) onPacket(f func(p *v5Format)) {\n\td.onPacketF = f\n}\n\nfunc (d *packetDecoder) decode(r io.Reader) error {\n\tvar err error\n\tvar packet *v5Format\n\tfor err == nil {\n\t\tpacket, err = d.decodeOnePacket(r)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\td.onPacketF(packet)\n\t}\n\tif err != nil && errors.Is(err, io.EOF) {\n\t\treturn nil\n\t}\n\treturn err\n}\n\ntype addressType uint32 // must be uint32\n\nconst (\n\taddressTypeUnknown addressType = 0\n\taddressTypeIPV4    addressType = 1\n\taddressTypeIPV6    addressType = 2\n)\n\nfunc (d *packetDecoder) decodeOnePacket(r io.Reader) (*v5Format, error) {\n\tp := &v5Format{}\n\terr := read(r, &p.version, \"version\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif p.version != 5 {\n\t\treturn nil, fmt.Errorf(\"version %d not supported, only version 5\", p.version)\n\t}\n\tvar addressIPType addressType\n\tif err := read(r, &addressIPType, \"address ip type\"); err != nil {\n\t\treturn nil, err\n\t}\n\tswitch addressIPType {\n\tcase addressTypeUnknown:\n\t\tp.agentAddress.IP = make([]byte, 0)\n\tcase addressTypeIPV4:\n\t\tp.agentAddress.IP = make([]byte, 4)\n\tcase addressTypeIPV6:\n\t\tp.agentAddress.IP = make([]byte, 16)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown address IP type %d\", addressIPType)\n\t}\n\tif err := read(r, &p.agentAddress.IP, \"Agent Address IP\"); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := read(r, &p.subAgentID, \"SubAgentID\"); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := read(r, &p.sequenceNumber, \"SequenceNumber\"); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := read(r, &p.uptime, \"Uptime\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tp.samples, err = d.decodeSamples(r)\n\treturn p, err\n}\n\nfunc (d *packetDecoder) decodeSamples(r io.Reader) ([]sample, error) {\n\t// # of samples\n\tvar numOfSamples uint32\n\tif err := read(r, &numOfSamples, \"sample count\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]sample, 0, numOfSamples)\n\tfor i := 0; i < int(numOfSamples); i++ {\n\t\tsam, err := d.decodeSample(r)\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = append(result, sam)\n\t}\n\n\treturn result, nil\n}\n\nfunc (d *packetDecoder) decodeSample(r io.Reader) (sample, error) {\n\tvar err error\n\tsam := sample{}\n\tif err := read(r, &sam.smplType, \"sampleType\"); err != nil {\n\t\treturn sam, err\n\t}\n\tsampleDataLen := uint32(0)\n\tif err := read(r, &sampleDataLen, \"Sample data length\"); err != nil {\n\t\treturn sam, err\n\t}\n\tmr := binaryio.MinReader(r, int64(sampleDataLen))\n\tdefer mr.Close()\n\n\tswitch sam.smplType {\n\tcase sampleTypeFlowSample:\n\t\tsam.smplData, err = d.decodeFlowSample(mr)\n\tcase sampleTypeFlowSampleExpanded:\n\t\tsam.smplData, err = d.decodeFlowSampleExpanded(mr)\n\tdefault:\n\t\td.debug(\"Unknown sample type: \", sam.smplType)\n\t}\n\treturn sam, err\n}\n\nfunc (d *packetDecoder) decodeFlowSample(r io.Reader) (t sampleDataFlowSampleExpanded, err error) {\n\tif err := read(r, &t.sequenceNumber, \"SequenceNumber\"); err != nil {\n\t\treturn t, err\n\t}\n\tvar sourceID uint32\n\tif err := read(r, &sourceID, \"SourceID\"); err != nil { // source_id sflow_version_5.txt line: 1622\n\t\treturn t, err\n\t}\n\t// split source id to source id type and source id index\n\tt.sourceIDIndex = sourceID & 0x00ffffff // sflow_version_5.txt line: 1468\n\tt.sourceIDType = sourceID >> 24         // source_id_type sflow_version_5.txt Line 1465\n\tif err := read(r, &t.samplingRate, \"SamplingRate\"); err != nil {\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.samplePool, \"SamplePool\"); err != nil {\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.drops, \"Drops\"); err != nil { // sflow_version_5.txt line 1636\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.inputIfIndex, \"InputIfIndex\"); err != nil {\n\t\treturn t, err\n\t}\n\tt.inputIfFormat = t.inputIfIndex >> 30\n\tt.inputIfIndex = t.inputIfIndex & 0x3FFFFFFF\n\n\tif err := read(r, &t.outputIfIndex, \"OutputIfIndex\"); err != nil {\n\t\treturn t, err\n\t}\n\tt.outputIfFormat = t.outputIfIndex >> 30\n\tt.outputIfIndex = t.outputIfIndex & 0x3FFFFFFF\n\n\tswitch t.sourceIDIndex {\n\tcase t.outputIfIndex:\n\t\tt.sampleDirection = \"egress\"\n\tcase t.inputIfIndex:\n\t\tt.sampleDirection = \"ingress\"\n\t}\n\n\tt.flowRecords, err = d.decodeFlowRecords(r, t.samplingRate)\n\treturn t, err\n}\n\nfunc (d *packetDecoder) decodeFlowSampleExpanded(r io.Reader) (t sampleDataFlowSampleExpanded, err error) {\n\tif err := read(r, &t.sequenceNumber, \"SequenceNumber\"); err != nil { // sflow_version_5.txt line 1701\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.sourceIDType, \"SourceIDType\"); err != nil { // sflow_version_5.txt line: 1706 + 16878\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.sourceIDIndex, \"SourceIDIndex\"); err != nil { // sflow_version_5.txt line: 1689\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.samplingRate, \"SamplingRate\"); err != nil { // sflow_version_5.txt line: 1707\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.samplePool, \"SamplePool\"); err != nil { // sflow_version_5.txt line: 1708\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.drops, \"Drops\"); err != nil { // sflow_version_5.txt line: 1712\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.inputIfFormat, \"InputIfFormat\"); err != nil { // sflow_version_5.txt line: 1727\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.inputIfIndex, \"InputIfIndex\"); err != nil {\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.outputIfFormat, \"OutputIfFormat\"); err != nil { // sflow_version_5.txt line: 1728\n\t\treturn t, err\n\t}\n\tif err := read(r, &t.outputIfIndex, \"OutputIfIndex\"); err != nil {\n\t\treturn t, err\n\t}\n\n\tswitch t.sourceIDIndex {\n\tcase t.outputIfIndex:\n\t\tt.sampleDirection = \"egress\"\n\tcase t.inputIfIndex:\n\t\tt.sampleDirection = \"ingress\"\n\t}\n\n\tt.flowRecords, err = d.decodeFlowRecords(r, t.samplingRate)\n\treturn t, err\n}\n\nfunc (d *packetDecoder) decodeFlowRecords(r io.Reader, samplingRate uint32) (recs []flowRecord, err error) {\n\tvar flowDataLen uint32\n\tvar count uint32\n\tif err := read(r, &count, \"FlowRecord count\"); err != nil {\n\t\treturn recs, err\n\t}\n\tfor i := uint32(0); i < count; i++ {\n\t\tfr := flowRecord{}\n\t\tif err := read(r, &fr.flowFormat, \"FlowFormat\"); err != nil { // sflow_version_5.txt line 1597\n\t\t\treturn recs, err\n\t\t}\n\t\tif err := read(r, &flowDataLen, \"Flow data length\"); err != nil {\n\t\t\treturn recs, err\n\t\t}\n\n\t\tmr := binaryio.MinReader(r, int64(flowDataLen))\n\n\t\tswitch fr.flowFormat {\n\t\tcase flowFormatTypeRawPacketHeader: // sflow_version_5.txt line 1938\n\t\t\tfr.flowData, err = d.decodeRawPacketHeaderFlowData(mr, samplingRate)\n\t\tdefault:\n\t\t\td.debug(\"Unknown flow format: \", fr.flowFormat)\n\t\t}\n\t\tif err != nil {\n\t\t\tmr.Close()\n\t\t\treturn recs, err\n\t\t}\n\n\t\trecs = append(recs, fr)\n\t\tmr.Close()\n\t}\n\n\treturn recs, err\n}\n\nfunc (d *packetDecoder) decodeRawPacketHeaderFlowData(r io.Reader, samplingRate uint32) (h rawPacketHeaderFlowData, err error) {\n\tif err := read(r, &h.headerProtocol, \"HeaderProtocol\"); err != nil { // sflow_version_5.txt line 1940\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.frameLength, \"FrameLength\"); err != nil { // sflow_version_5.txt line 1942\n\t\treturn h, err\n\t}\n\th.bytes = h.frameLength * samplingRate\n\n\tif err := read(r, &h.strippedOctets, \"StrippedOctets\"); err != nil { // sflow_version_5.txt line 1967\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.headerLength, \"HeaderLength\"); err != nil {\n\t\treturn h, err\n\t}\n\n\tmr := binaryio.MinReader(r, int64(h.headerLength))\n\tdefer mr.Close()\n\n\tswitch h.headerProtocol {\n\tcase headerProtocolTypeEthernetISO88023:\n\t\th.header, err = d.decodeEthHeader(mr)\n\tdefault:\n\t\td.debug(\"Unknown header protocol type: \", h.headerProtocol)\n\t}\n\n\treturn h, err\n}\n\n// ethHeader answers a decode Directive that will decode an ethernet frame header\n// according to https://en.wikipedia.org/wiki/Ethernet_frame\nfunc (d *packetDecoder) decodeEthHeader(r io.Reader) (h ethHeader, err error) {\n\t// we may have to read out StrippedOctets bytes and throw them away first?\n\tif err := read(r, &h.destinationMAC, \"DestinationMAC\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.sourceMAC, \"SourceMAC\"); err != nil {\n\t\treturn h, err\n\t}\n\tvar tagOrEType uint16\n\tif err := read(r, &tagOrEType, \"tagOrEtype\"); err != nil {\n\t\treturn h, err\n\t}\n\tswitch tagOrEType {\n\tcase 0x8100: // could be?\n\t\tvar discard uint16\n\t\tif err := read(r, &discard, \"unknown\"); err != nil {\n\t\t\treturn h, err\n\t\t}\n\t\tif err := read(r, &h.etherTypeCode, \"EtherTypeCode\"); err != nil {\n\t\t\treturn h, err\n\t\t}\n\tdefault:\n\t\th.etherTypeCode = tagOrEType\n\t}\n\th.etherType = eTypeMap[h.etherTypeCode]\n\tswitch h.etherType {\n\tcase \"IPv4\":\n\t\th.ipHeader, err = d.decodeIPv4Header(r)\n\tcase \"IPv6\":\n\t\th.ipHeader, err = d.decodeIPv6Header(r)\n\tdefault:\n\t}\n\tif err != nil {\n\t\treturn h, err\n\t}\n\treturn h, err\n}\n\n// https://en.wikipedia.org/wiki/IPv4#Header\nfunc (d *packetDecoder) decodeIPv4Header(r io.Reader) (h ipV4Header, err error) {\n\tif err := read(r, &h.version, \"Version\"); err != nil {\n\t\treturn h, err\n\t}\n\th.internetHeaderLength = h.version & 0x0F\n\th.version = h.version & 0xF0\n\tif err := read(r, &h.dscp, \"DSCP\"); err != nil {\n\t\treturn h, err\n\t}\n\th.ecn = h.dscp & 0x03\n\th.dscp = h.dscp >> 2\n\tif err := read(r, &h.totalLength, \"TotalLength\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.identification, \"Identification\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.fragmentOffset, \"FragmentOffset\"); err != nil {\n\t\treturn h, err\n\t}\n\th.flags = uint8(h.fragmentOffset >> 13)\n\th.fragmentOffset = h.fragmentOffset & 0x1FFF\n\tif err := read(r, &h.ttl, \"TTL\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.protocol, \"Protocol\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.headerChecksum, \"HeaderChecksum\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.sourceIP, \"SourceIP\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.destIP, \"DestIP\"); err != nil {\n\t\treturn h, err\n\t}\n\tswitch h.protocol {\n\tcase ipProtocolTCP:\n\t\th.protocolHeader, err = decodeTCPHeader(r)\n\tcase ipProtocolUDP:\n\t\th.protocolHeader, err = decodeUDPHeader(r)\n\tdefault:\n\t\td.debug(\"Unknown IP protocol: \", h.protocol)\n\t}\n\treturn h, err\n}\n\n// https://en.wikipedia.org/wiki/IPv6_packet\nfunc (d *packetDecoder) decodeIPv6Header(r io.Reader) (h ipV6Header, err error) {\n\tvar fourByteBlock uint32\n\tif err := read(r, &fourByteBlock, \"IPv6 header octet 0\"); err != nil {\n\t\treturn h, err\n\t}\n\tversion := fourByteBlock >> 28\n\tif version != 0x6 {\n\t\treturn h, fmt.Errorf(\"unexpected IPv6 header version 0x%x\", version)\n\t}\n\th.dscp = uint8((fourByteBlock & 0xFC00000) >> 22)\n\th.ecn = uint8((fourByteBlock & 0x300000) >> 20)\n\n\t// The flowLabel is available via fourByteBlock & 0xFFFFF\n\tif err := read(r, &h.payloadLength, \"PayloadLength\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.nextHeaderProto, \"NextHeaderProto\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.hopLimit, \"HopLimit\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.sourceIP, \"SourceIP\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.destIP, \"DestIP\"); err != nil {\n\t\treturn h, err\n\t}\n\tswitch h.nextHeaderProto {\n\tcase ipProtocolTCP:\n\t\th.protocolHeader, err = decodeTCPHeader(r)\n\tcase ipProtocolUDP:\n\t\th.protocolHeader, err = decodeUDPHeader(r)\n\tdefault:\n\t\t// not handled\n\t\td.debug(\"Unknown IP protocol: \", h.nextHeaderProto)\n\t}\n\treturn h, err\n}\n\n// https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure\nfunc decodeTCPHeader(r io.Reader) (h tcpHeader, err error) {\n\tif err := read(r, &h.sourcePort, \"SourcePort\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.destinationPort, \"DestinationPort\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.sequence, \"Sequence\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.ackNumber, \"AckNumber\"); err != nil {\n\t\treturn h, err\n\t}\n\t// Next up: bit reading!\n\t// \t data offset 4 bits\n\t// \t reserved 3 bits\n\t// \t flags 9 bits\n\tvar dataOffsetAndReservedAndFlags uint16\n\tif err := read(r, &dataOffsetAndReservedAndFlags, \"TCP Header Octet offset 12\"); err != nil {\n\t\treturn h, err\n\t}\n\th.tcpHeaderLength = uint8((dataOffsetAndReservedAndFlags >> 12) * 4)\n\th.flags = dataOffsetAndReservedAndFlags & 0x1FF\n\t// done bit reading\n\n\tif err := read(r, &h.tcpWindowSize, \"TCPWindowSize\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.checksum, \"Checksum\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.tcpUrgentPointer, \"TCPUrgentPointer\"); err != nil {\n\t\treturn h, err\n\t}\n\n\treturn h, err\n}\n\nfunc decodeUDPHeader(r io.Reader) (h udpHeader, err error) {\n\tif err := read(r, &h.sourcePort, \"SourcePort\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.destinationPort, \"DestinationPort\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.udpLength, \"UDPLength\"); err != nil {\n\t\treturn h, err\n\t}\n\tif err := read(r, &h.checksum, \"Checksum\"); err != nil {\n\t\treturn h, err\n\t}\n\treturn h, err\n}\n\nfunc read(r io.Reader, data interface{}, name string) error {\n\terr := binary.Read(r, binary.BigEndian, data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read %q: %w\", name, err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/packetdecoder_test.go",
    "content": "package sflow\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestUDPHeader(t *testing.T) {\n\toctets := bytes.NewBuffer([]byte{\n\t\t0x00, 0x01, // src_port\n\t\t0x00, 0x02, // dst_port\n\t\t0x00, 0x03, // udp_length\n\t\t0x00, 0x00, // checksum\n\t})\n\n\tactual, err := decodeUDPHeader(octets)\n\trequire.NoError(t, err)\n\n\texpected := udpHeader{\n\t\tsourcePort:      1,\n\t\tdestinationPort: 2,\n\t\tudpLength:       3,\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc BenchmarkUDPHeader(b *testing.B) {\n\toctets := bytes.NewBuffer([]byte{\n\t\t0x00, 0x01, // src_port\n\t\t0x00, 0x02, // dst_port\n\t\t0x00, 0x03, // udp_length\n\t\t0x00, 0x00, // checksum\n\t})\n\n\tb.ResetTimer()\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := decodeUDPHeader(octets)\n\t\trequire.NoError(b, err)\n\t}\n}\n\nfunc TestIPv4Header(t *testing.T) {\n\toctets := bytes.NewBuffer(\n\t\t[]byte{\n\t\t\t0x45,       // version + IHL\n\t\t\t0x00,       // ip_dscp + ip_ecn\n\t\t\t0x00, 0x00, // total length\n\t\t\t0x00, 0x00, // identification\n\t\t\t0x00, 0x00, // flags + frag offset\n\t\t\t0x00,       // ttl\n\t\t\t0x11,       // protocol udp (0x11)\n\t\t\t0x00, 0x00, // header checksum\n\t\t\t0x7f, 0x00, 0x00, 0x01, // src ip\n\t\t\t0x7f, 0x00, 0x00, 0x02, // dst ip\n\t\t\t0x00, 0x01, // src_port\n\t\t\t0x00, 0x02, // dst_port\n\t\t\t0x00, 0x03, // udp_length\n\t\t\t0x00, 0x00, // checksum\n\t\t},\n\t)\n\tdc := newDecoder()\n\tactual, err := dc.decodeIPv4Header(octets)\n\trequire.NoError(t, err)\n\n\texpected := ipV4Header{\n\t\tversion:              0x40,\n\t\tinternetHeaderLength: 0x05,\n\t\tdscp:                 0,\n\t\tecn:                  0,\n\t\ttotalLength:          0,\n\t\tidentification:       0,\n\t\tflags:                0,\n\t\tfragmentOffset:       0,\n\t\tttl:                  0,\n\t\tprotocol:             0x11,\n\t\theaderChecksum:       0,\n\t\tsourceIP:             [4]byte{127, 0, 0, 1},\n\t\tdestIP:               [4]byte{127, 0, 0, 2},\n\t\tprotocolHeader: udpHeader{\n\t\t\tsourcePort:      1,\n\t\t\tdestinationPort: 2,\n\t\t\tudpLength:       3,\n\t\t\tchecksum:        0,\n\t\t},\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\n// Using the same Directive instance, prior paths through the parse tree should\n// not affect the latest parse.\nfunc TestIPv4HeaderSwitch(t *testing.T) {\n\toctets := bytes.NewBuffer(\n\t\t[]byte{\n\t\t\t0x45,       // version + IHL\n\t\t\t0x00,       // ip_dscp + ip_ecn\n\t\t\t0x00, 0x00, // total length\n\t\t\t0x00, 0x00, // identification\n\t\t\t0x00, 0x00, // flags + frag offset\n\t\t\t0x00,       // ttl\n\t\t\t0x11,       // protocol udp (0x11)\n\t\t\t0x00, 0x00, // header checksum\n\t\t\t0x7f, 0x00, 0x00, 0x01, // src ip\n\t\t\t0x7f, 0x00, 0x00, 0x02, // dst ip\n\t\t\t0x00, 0x01, // src_port\n\t\t\t0x00, 0x02, // dst_port\n\t\t\t0x00, 0x03, // udp_length\n\t\t\t0x00, 0x00, // checksum\n\t\t},\n\t)\n\tdc := newDecoder()\n\t_, err := dc.decodeIPv4Header(octets)\n\trequire.NoError(t, err)\n\n\toctets = bytes.NewBuffer(\n\t\t[]byte{\n\t\t\t0x45,       // version + IHL\n\t\t\t0x00,       // ip_dscp + ip_ecn\n\t\t\t0x00, 0x00, // total length\n\t\t\t0x00, 0x00, // identification\n\t\t\t0x00, 0x00, // flags + frag offset\n\t\t\t0x00,       // ttl\n\t\t\t0x06,       // protocol tcp (0x06)\n\t\t\t0x00, 0x00, // header checksum\n\t\t\t0x7f, 0x00, 0x00, 0x01, // src ip\n\t\t\t0x7f, 0x00, 0x00, 0x02, // dst ip\n\t\t\t0x00, 0x01, // src_port\n\t\t\t0x00, 0x02, // dst_port\n\t\t\t0x00, 0x00, 0x00, 0x00, // sequence\n\t\t\t0x00, 0x00, 0x00, 0x00, // ack_number\n\t\t\t0x00, 0x00, // tcp_header_length\n\t\t\t0x00, 0x00, // tcp_window_size\n\t\t\t0x00, 0x00, // checksum\n\t\t\t0x00, 0x00, // tcp_urgent_pointer\n\t\t},\n\t)\n\tdc = newDecoder()\n\tactual, err := dc.decodeIPv4Header(octets)\n\trequire.NoError(t, err)\n\n\texpected := ipV4Header{\n\t\tversion:              64,\n\t\tinternetHeaderLength: 5,\n\t\tprotocol:             6,\n\t\tsourceIP:             [4]byte{127, 0, 0, 1},\n\t\tdestIP:               [4]byte{127, 0, 0, 2},\n\t\tprotocolHeader: tcpHeader{\n\t\t\tsourcePort:      1,\n\t\t\tdestinationPort: 2,\n\t\t},\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc TestUnknownProtocol(t *testing.T) {\n\toctets := bytes.NewBuffer(\n\t\t[]byte{\n\t\t\t0x45,       // version + IHL\n\t\t\t0x00,       // ip_dscp + ip_ecn\n\t\t\t0x00, 0x00, // total length\n\t\t\t0x00, 0x00, // identification\n\t\t\t0x00, 0x00, // flags + frag offset\n\t\t\t0x00,       // ttl\n\t\t\t0x99,       // protocol\n\t\t\t0x00, 0x00, // header checksum\n\t\t\t0x7f, 0x00, 0x00, 0x01, // src ip\n\t\t\t0x7f, 0x00, 0x00, 0x02, // dst ip\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t\t0x00,\n\t\t},\n\t)\n\tdc := newDecoder()\n\tactual, err := dc.decodeIPv4Header(octets)\n\trequire.NoError(t, err)\n\n\texpected := ipV4Header{\n\t\tversion:              64,\n\t\tinternetHeaderLength: 5,\n\t\tprotocol:             153,\n\t\tsourceIP:             [4]byte{127, 0, 0, 1},\n\t\tdestIP:               [4]byte{127, 0, 0, 2},\n\t}\n\n\trequire.Equal(t, expected, actual)\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/sample.conf",
    "content": "# SFlow V5 Protocol Listener\n[[inputs.sflow]]\n  ## Address to listen for sFlow packets.\n  ##   example: service_address = \"udp://:6343\"\n  ##            service_address = \"udp4://:6343\"\n  ##            service_address = \"udp6://:6343\"\n  service_address = \"udp://:6343\"\n\n  ## Set the size of the operating system's receive buffer.\n  ##   example: read_buffer_size = \"64KiB\"\n  # read_buffer_size = \"\"\n"
  },
  {
    "path": "plugins/inputs/sflow/sflow.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage sflow\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst (\n\tmaxPacketSize = 64 * 1024\n)\n\ntype SFlow struct {\n\tServiceAddress string      `toml:\"service_address\"`\n\tReadBufferSize config.Size `toml:\"read_buffer_size\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\taddr    net.Addr\n\tdecoder *packetDecoder\n\tcloser  io.Closer\n\twg      sync.WaitGroup\n}\n\nfunc (*SFlow) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *SFlow) Init() error {\n\ts.decoder = newDecoder()\n\ts.decoder.Log = s.Log\n\treturn nil\n}\n\n// Start starts this sFlow listener listening on the configured network for sFlow packets\nfunc (s *SFlow) Start(acc telegraf.Accumulator) error {\n\ts.decoder.onPacket(func(p *v5Format) {\n\t\tmetrics := makeMetrics(p)\n\t\tfor _, m := range metrics {\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t})\n\n\tu, err := url.Parse(s.ServiceAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err := listenUDP(u.Scheme, u.Host)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.closer = conn\n\ts.addr = conn.LocalAddr()\n\n\tif s.ReadBufferSize > 0 {\n\t\tif err := conn.SetReadBuffer(int(s.ReadBufferSize)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\ts.Log.Infof(\"Listening on %s://%s\", s.addr.Network(), s.addr.String())\n\n\ts.wg.Add(1)\n\tgo func() {\n\t\tdefer s.wg.Done()\n\t\ts.read(acc, conn)\n\t}()\n\n\treturn nil\n}\n\n// Gather is a NOOP for sFlow as it receives, asynchronously, sFlow network packets\nfunc (*SFlow) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (s *SFlow) Stop() {\n\tif s.closer != nil {\n\t\ts.closer.Close()\n\t}\n\ts.wg.Wait()\n}\n\nfunc (s *SFlow) address() net.Addr {\n\treturn s.addr\n}\n\nfunc (s *SFlow) read(acc telegraf.Accumulator, conn net.PacketConn) {\n\tbuf := make([]byte, maxPacketSize)\n\tfor {\n\t\tn, _, err := conn.ReadFrom(buf)\n\t\tif err != nil {\n\t\t\tif !strings.HasSuffix(err.Error(), \": use of closed network connection\") {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\ts.process(acc, buf[:n])\n\t}\n}\n\nfunc (s *SFlow) process(acc telegraf.Accumulator, buf []byte) {\n\tif err := s.decoder.decode(bytes.NewBuffer(buf)); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"unable to parse incoming packet: %w\", err))\n\t}\n}\n\nfunc listenUDP(network, address string) (*net.UDPConn, error) {\n\tswitch network {\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\taddr, err := net.ResolveUDPAddr(network, address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn net.ListenUDP(network, addr)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported network type: %s\", network)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"sflow\", func() telegraf.Input {\n\t\treturn &SFlow{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/sflow_test.go",
    "content": "package sflow\n\nimport (\n\t\"encoding/hex\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSFlow(t *testing.T) {\n\tsflow := &SFlow{\n\t\tServiceAddress: \"udp://127.0.0.1:0\",\n\t\tLog:            testutil.Logger{},\n\t}\n\terr := sflow.Init()\n\trequire.NoError(t, err)\n\n\tvar acc testutil.Accumulator\n\terr = sflow.Start(&acc)\n\trequire.NoError(t, err)\n\tdefer sflow.Stop()\n\n\tclient, err := net.Dial(sflow.address().Network(), sflow.address().String())\n\trequire.NoError(t, err)\n\n\tpacketBytes, err := hex.DecodeString(\n\t\t\"0000000500000001c0a80102000000100000f3d40bfa047f0000000200000001000000d00001210a000001fe000004000484240000000000000001fe\" +\n\t\t\t\"00000200000000020000000100000090000000010000010b0000000400000080000c2936d3d694c691aa97600800450000f9f19040004011b4f5c0a\" +\n\t\t\t\"80913c0a8090a00a1ba0500e5641f3081da02010104066d6f746f6770a281cc02047b46462e0201000201003081bd3012060d2b0601020119050101\" +\n\t\t\t\"0281dc710201003013060d2b06010201190501010281e66802025acc3012060d2b0601020119050101000003e900000010000000090000000000000\" +\n\t\t\t\"0090000000000000001000000d00000e3cc000002100000400048eb7400000000000000021000000200000000020000000100000090000000010000\" +\n\t\t\t\"00970000000400000080000c2936d3d6fcecda44008f81000009080045000081186440003f119098c0a80815c0a8090a9a690202006d23083c33303\" +\n\t\t\t\"e4170722031312030393a33333a3031206b6e6f64653120736e6d70645b313039385d3a20436f6e6e656374696f6e2066726f6d205544503a205b31\" +\n\t\t\t\"39322e3136382e392e31305d3a34393233362d000003e90000001000000009000000000000000900000000\",\n\t)\n\trequire.NoError(t, err)\n\t_, err = client.Write(packetBytes)\n\trequire.NoError(t, err)\n\n\tacc.Wait(2)\n\n\texpected := []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"192.168.1.2\",\n\t\t\t\t\"dst_ip\":           \"192.168.9.10\",\n\t\t\t\t\"dst_mac\":          \"00:0c:29:36:d3:d6\",\n\t\t\t\t\"dst_port\":         \"47621\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"510\",\n\t\t\t\t\"output_ifindex\":   \"512\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"510\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.9.19\",\n\t\t\t\t\"src_mac\":          \"94:c6:91:aa:97:60\",\n\t\t\t\t\"src_port\":         \"161\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(273408),\n\t\t\t\t\"drops\":              uint64(0),\n\t\t\t\t\"frame_length\":       uint64(267),\n\t\t\t\t\"header_length\":      uint64(128),\n\t\t\t\t\"ip_flags\":           uint64(2),\n\t\t\t\t\"ip_fragment_offset\": uint64(0),\n\t\t\t\t\"ip_total_length\":    uint64(249),\n\t\t\t\t\"ip_ttl\":             uint64(64),\n\t\t\t\t\"sampling_rate\":      uint64(1024),\n\t\t\t\t\"udp_length\":         uint64(229),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"sflow\",\n\t\t\tmap[string]string{\n\t\t\t\t\"agent_address\":    \"192.168.1.2\",\n\t\t\t\t\"dst_ip\":           \"192.168.9.10\",\n\t\t\t\t\"dst_mac\":          \"00:0c:29:36:d3:d6\",\n\t\t\t\t\"dst_port\":         \"514\",\n\t\t\t\t\"ether_type\":       \"IPv4\",\n\t\t\t\t\"header_protocol\":  \"ETHERNET-ISO88023\",\n\t\t\t\t\"input_ifindex\":    \"528\",\n\t\t\t\t\"output_ifindex\":   \"512\",\n\t\t\t\t\"sample_direction\": \"ingress\",\n\t\t\t\t\"source_id_index\":  \"528\",\n\t\t\t\t\"source_id_type\":   \"0\",\n\t\t\t\t\"src_ip\":           \"192.168.8.21\",\n\t\t\t\t\"src_mac\":          \"fc:ec:da:44:00:8f\",\n\t\t\t\t\"src_port\":         \"39529\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"bytes\":              uint64(2473984),\n\t\t\t\t\"drops\":              uint64(0),\n\t\t\t\t\"frame_length\":       uint64(151),\n\t\t\t\t\"header_length\":      uint64(128),\n\t\t\t\t\"ip_flags\":           uint64(2),\n\t\t\t\t\"ip_fragment_offset\": uint64(0),\n\t\t\t\t\"ip_total_length\":    uint64(129),\n\t\t\t\t\"ip_ttl\":             uint64(63),\n\t\t\t\t\"sampling_rate\":      uint64(16384),\n\t\t\t\t\"udp_length\":         uint64(109),\n\t\t\t\t\"ip_dscp\":            \"0\",\n\t\t\t\t\"ip_ecn\":             \"0\",\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(),\n\t\ttestutil.IgnoreTime())\n}\n\nfunc BenchmarkSFlow(b *testing.B) {\n\tsflow := &SFlow{\n\t\tServiceAddress: \"udp://127.0.0.1:0\",\n\t\tLog:            testutil.Logger{},\n\t}\n\terr := sflow.Init()\n\trequire.NoError(b, err)\n\n\tvar acc testutil.Accumulator\n\terr = sflow.Start(&acc)\n\trequire.NoError(b, err)\n\tdefer sflow.Stop()\n\n\tclient, err := net.Dial(sflow.address().Network(), sflow.address().String())\n\trequire.NoError(b, err)\n\n\tpacketBytes, err := hex.DecodeString(\n\t\t\"0000000500000001c0a80102000000100000f3d40bfa047f0000000200000001000000d00001210a000001fe000004000484240000000000000001fe0\" +\n\t\t\t\"0000200000000020000000100000090000000010000010b0000000400000080000c2936d3d694c691aa97600800450000f9f19040004011b4f5c0a80\" +\n\t\t\t\"913c0a8090a00a1ba0500e5641f3081da02010104066d6f746f6770a281cc02047b46462e0201000201003081bd3012060d2b0601020119050101028\" +\n\t\t\t\"1dc710201003013060d2b06010201190501010281e66802025acc3012060d2b0601020119050101000003e9000000100000000900000000000000090\" +\n\t\t\t\"000000000000001000000d00000e3cc000002100000400048eb740000000000000002100000020000000002000000010000009000000001000000970\" +\n\t\t\t\"000000400000080000c2936d3d6fcecda44008f81000009080045000081186440003f119098c0a80815c0a8090a9a690202006d23083c33303e41707\" +\n\t\t\t\"22031312030393a33333a3031206b6e6f64653120736e6d70645b313039385d3a20436f6e6e656374696f6e2066726f6d205544503a205b3139322e3\" +\n\t\t\t\"136382e392e31305d3a34393233362d000003e90000001000000009000000000000000900000000\",\n\t)\n\trequire.NoError(b, err)\n\n\tb.ResetTimer()\n\tfor n := 0; n < b.N; n++ {\n\t\t_, err := client.Write(packetBytes)\n\t\trequire.NoError(b, err)\n\t\tacc.Wait(2)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/types.go",
    "content": "package sflow\n\nimport (\n\t\"net\"\n\t\"strconv\"\n)\n\nconst (\n\tipProtocolTCP uint8 = 6\n\tipProtocolUDP uint8 = 17\n)\n\nvar eTypeMap = map[uint16]string{\n\t0x0800: \"IPv4\",\n\t0x86DD: \"IPv6\",\n}\n\ntype containsMetricData interface {\n\tgetTags() map[string]string\n\tgetFields() map[string]interface{}\n}\n\n// v5Format answers and decoder.Directive capable of decoding sFlow v5 packets in accordance\n// with SFlow v5 specification at https://sflow.org/sflow_version_5.txt\ntype v5Format struct {\n\tversion        uint32\n\tagentAddress   net.IPAddr\n\tsubAgentID     uint32\n\tsequenceNumber uint32\n\tuptime         uint32\n\tsamples        []sample\n}\n\ntype sampleType uint32\n\nconst (\n\tsampleTypeFlowSample         sampleType = 1 // sflow_version_5.txt line: 1614\n\tsampleTypeFlowSampleExpanded sampleType = 3 // sflow_version_5.txt line: 1698\n)\n\ntype sample struct {\n\tsmplType sampleType\n\tsmplData sampleDataFlowSampleExpanded\n}\n\ntype sampleDataFlowSampleExpanded struct {\n\tsequenceNumber  uint32\n\tsourceIDType    uint32\n\tsourceIDIndex   uint32\n\tsamplingRate    uint32\n\tsamplePool      uint32\n\tdrops           uint32\n\tsampleDirection string // ingress/egress\n\tinputIfFormat   uint32\n\tinputIfIndex    uint32\n\toutputIfFormat  uint32\n\toutputIfIndex   uint32\n\tflowRecords     []flowRecord\n}\n\ntype flowFormatType uint32\n\nconst (\n\tflowFormatTypeRawPacketHeader flowFormatType = 1 // sflow_version_5.txt line: 1938\n)\n\ntype flowData containsMetricData\n\ntype flowRecord struct {\n\tflowFormat flowFormatType\n\tflowData   flowData\n}\n\ntype headerProtocolType uint32\n\nconst (\n\theaderProtocolTypeEthernetISO88023  headerProtocolType = 1\n\theaderProtocolTypeISO88024TokenBus  headerProtocolType = 2\n\theaderProtocolTypeISO88025TokenRing headerProtocolType = 3\n\theaderProtocolTypeFDDI              headerProtocolType = 4\n\theaderProtocolTypeFrameRelay        headerProtocolType = 5\n\theaderProtocolTypeX25               headerProtocolType = 6\n\theaderProtocolTypePPP               headerProtocolType = 7\n\theaderProtocolTypeSMDS              headerProtocolType = 8\n\theaderProtocolTypeAAL5              headerProtocolType = 9\n\theaderProtocolTypeAAL5IP            headerProtocolType = 10 /* e.g. Cisco AAL5 mux */\n\theaderProtocolTypeIPv4              headerProtocolType = 11\n\theaderProtocolTypeIPv6              headerProtocolType = 12\n\theaderProtocolTypeMPLS              headerProtocolType = 13\n\theaderProtocolTypePOS               headerProtocolType = 14 /* RFC 1662, 2615 */\n)\n\nvar headerProtocolMap = map[headerProtocolType]string{\n\theaderProtocolTypeEthernetISO88023: \"ETHERNET-ISO88023\", // sflow_version_5.txt line: 1920\n}\n\ntype header containsMetricData\n\ntype rawPacketHeaderFlowData struct {\n\theaderProtocol headerProtocolType\n\tframeLength    uint32\n\tbytes          uint32\n\tstrippedOctets uint32\n\theaderLength   uint32\n\theader         header\n}\n\nfunc (h rawPacketHeaderFlowData) getTags() map[string]string {\n\tvar t map[string]string\n\tif h.header != nil {\n\t\tt = h.header.getTags()\n\t} else {\n\t\tt = make(map[string]string, 1)\n\t}\n\tt[\"header_protocol\"] = headerProtocolMap[h.headerProtocol]\n\treturn t\n}\n\nfunc (h rawPacketHeaderFlowData) getFields() map[string]interface{} {\n\tvar f map[string]interface{}\n\tif h.header != nil {\n\t\tf = h.header.getFields()\n\t} else {\n\t\tf = make(map[string]interface{}, 3)\n\t}\n\tf[\"bytes\"] = h.bytes\n\tf[\"frame_length\"] = h.frameLength\n\tf[\"header_length\"] = h.headerLength\n\treturn f\n}\n\ntype ipHeader containsMetricData\n\ntype ethHeader struct {\n\tdestinationMAC        [6]byte\n\tsourceMAC             [6]byte\n\ttagProtocolIdentifier uint16\n\ttagControlInformation uint16\n\tetherTypeCode         uint16\n\tetherType             string\n\tipHeader              ipHeader\n}\n\nfunc (h ethHeader) getTags() map[string]string {\n\tvar t map[string]string\n\tif h.ipHeader != nil {\n\t\tt = h.ipHeader.getTags()\n\t} else {\n\t\tt = make(map[string]string, 3)\n\t}\n\tt[\"src_mac\"] = net.HardwareAddr(h.sourceMAC[:]).String()\n\tt[\"dst_mac\"] = net.HardwareAddr(h.destinationMAC[:]).String()\n\tt[\"ether_type\"] = h.etherType\n\treturn t\n}\n\nfunc (h ethHeader) getFields() map[string]interface{} {\n\tif h.ipHeader != nil {\n\t\treturn h.ipHeader.getFields()\n\t}\n\treturn make(map[string]interface{})\n}\n\ntype protocolHeader containsMetricData\n\n// https://en.wikipedia.org/wiki/IPv4#Header\ntype ipV4Header struct {\n\tversion              uint8 // 4 bit\n\tinternetHeaderLength uint8 // 4 bit\n\tdscp                 uint8\n\tecn                  uint8\n\ttotalLength          uint16\n\tidentification       uint16\n\tflags                uint8\n\tfragmentOffset       uint16\n\tttl                  uint8\n\tprotocol             uint8 // https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers\n\theaderChecksum       uint16\n\tsourceIP             [4]byte\n\tdestIP               [4]byte\n\tprotocolHeader       protocolHeader\n}\n\nfunc (h ipV4Header) getTags() map[string]string {\n\tvar t map[string]string\n\tif h.protocolHeader != nil {\n\t\tt = h.protocolHeader.getTags()\n\t} else {\n\t\tt = make(map[string]string, 2)\n\t}\n\tt[\"src_ip\"] = net.IP(h.sourceIP[:]).String()\n\tt[\"dst_ip\"] = net.IP(h.destIP[:]).String()\n\treturn t\n}\n\nfunc (h ipV4Header) getFields() map[string]interface{} {\n\tvar f map[string]interface{}\n\tif h.protocolHeader != nil {\n\t\tf = h.protocolHeader.getFields()\n\t} else {\n\t\tf = make(map[string]interface{}, 6)\n\t}\n\tf[\"ip_dscp\"] = strconv.FormatUint(uint64(h.dscp), 10)\n\tf[\"ip_ecn\"] = strconv.FormatUint(uint64(h.ecn), 10)\n\tf[\"ip_flags\"] = h.flags\n\tf[\"ip_fragment_offset\"] = h.fragmentOffset\n\tf[\"ip_total_length\"] = h.totalLength\n\tf[\"ip_ttl\"] = h.ttl\n\treturn f\n}\n\n// https://en.wikipedia.org/wiki/IPv6_packet\ntype ipV6Header struct {\n\tdscp            uint8\n\tecn             uint8\n\tpayloadLength   uint16\n\tnextHeaderProto uint8 // tcp/udp?\n\thopLimit        uint8\n\tsourceIP        [16]byte\n\tdestIP          [16]byte\n\tprotocolHeader  protocolHeader\n}\n\nfunc (h ipV6Header) getTags() map[string]string {\n\tvar t map[string]string\n\tif h.protocolHeader != nil {\n\t\tt = h.protocolHeader.getTags()\n\t} else {\n\t\tt = make(map[string]string, 2)\n\t}\n\tt[\"src_ip\"] = net.IP(h.sourceIP[:]).String()\n\tt[\"dst_ip\"] = net.IP(h.destIP[:]).String()\n\treturn t\n}\n\nfunc (h ipV6Header) getFields() map[string]interface{} {\n\tvar f map[string]interface{}\n\tif h.protocolHeader != nil {\n\t\tf = h.protocolHeader.getFields()\n\t} else {\n\t\tf = make(map[string]interface{}, 3)\n\t}\n\tf[\"ip_dscp\"] = strconv.FormatUint(uint64(h.dscp), 10)\n\tf[\"ip_ecn\"] = strconv.FormatUint(uint64(h.ecn), 10)\n\tf[\"payload_length\"] = h.payloadLength\n\treturn f\n}\n\n// https://en.wikipedia.org/wiki/Transmission_Control_Protocol\ntype tcpHeader struct {\n\tsourcePort       uint16\n\tdestinationPort  uint16\n\tsequence         uint32\n\tackNumber        uint32\n\ttcpHeaderLength  uint8\n\tflags            uint16\n\ttcpWindowSize    uint16\n\tchecksum         uint16\n\ttcpUrgentPointer uint16\n}\n\nfunc (h tcpHeader) getTags() map[string]string {\n\tt := map[string]string{\n\t\t\"dst_port\": strconv.FormatUint(uint64(h.destinationPort), 10),\n\t\t\"src_port\": strconv.FormatUint(uint64(h.sourcePort), 10),\n\t}\n\treturn t\n}\n\nfunc (h tcpHeader) getFields() map[string]interface{} {\n\treturn map[string]interface{}{\n\t\t\"tcp_header_length\":  h.tcpHeaderLength,\n\t\t\"tcp_urgent_pointer\": h.tcpUrgentPointer,\n\t\t\"tcp_window_size\":    h.tcpWindowSize,\n\t}\n}\n\ntype udpHeader struct {\n\tsourcePort      uint16\n\tdestinationPort uint16\n\tudpLength       uint16\n\tchecksum        uint16\n}\n\nfunc (h udpHeader) getTags() map[string]string {\n\tt := map[string]string{\n\t\t\"dst_port\": strconv.FormatUint(uint64(h.destinationPort), 10),\n\t\t\"src_port\": strconv.FormatUint(uint64(h.sourcePort), 10),\n\t}\n\treturn t\n}\n\nfunc (h udpHeader) getFields() map[string]interface{} {\n\treturn map[string]interface{}{\n\t\t\"udp_length\": h.udpLength,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/sflow/types_test.go",
    "content": "package sflow\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRawPacketHeaderFlowData(t *testing.T) {\n\th := rawPacketHeaderFlowData{\n\t\theaderProtocol: headerProtocolTypeEthernetISO88023,\n\t\tframeLength:    64,\n\t\tbytes:          64,\n\t\tstrippedOctets: 0,\n\t\theaderLength:   0,\n\t\theader:         nil,\n\t}\n\ttags := h.getTags()\n\tfields := h.getFields()\n\n\trequire.NotNil(t, fields)\n\trequire.NotNil(t, tags)\n\trequire.Contains(t, tags, \"header_protocol\")\n\trequire.Len(t, tags, 1)\n}\n\n// process a raw ethernet packet without any encapsulated protocol\nfunc TestEthHeader(t *testing.T) {\n\th := ethHeader{\n\t\tdestinationMAC:        [6]byte{0xca, 0xff, 0xee, 0xff, 0xe, 0x0},\n\t\tsourceMAC:             [6]byte{0xde, 0xad, 0xbe, 0xef, 0x0, 0x0},\n\t\ttagProtocolIdentifier: 0x88B5, // IEEE Std 802 - Local Experimental Ethertype\n\t\ttagControlInformation: 0,\n\t\tetherTypeCode:         0,\n\t\tetherType:             \"\",\n\t\tipHeader:              nil,\n\t}\n\ttags := h.getTags()\n\tfields := h.getFields()\n\n\trequire.NotNil(t, fields)\n\trequire.NotNil(t, tags)\n}\n"
  },
  {
    "path": "plugins/inputs/sip/README.md",
    "content": "# SIP Input Plugin\n\nThis plugin gathers metrics about the health and availability of\n[SIP (Session Initiation Protocol)][sip] servers such as PBX systems, SIP\nproxies, registrars, and VoIP service providers. It sends SIP requests\n(typically OPTIONS) and measures response times and status codes.\n\n⭐ Telegraf v1.38.0\n🏷️ network\n💻 all\n\n[sip]: https://datatracker.ietf.org/doc/html/rfc3261\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `username` and\n`password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# SIP (Session Initiation Protocol) health check plugin\n[[inputs.sip]]\n  ## SIP server address to monitor\n  ## Format: sip://host[:port] or sips://host[:port]\n  ##   sip://  - Standard SIP (default port 5060)\n  ##   sips:// - Secure SIP with TLS (default port 5061)\n  server = \"sip://sip.example.com:5060\"\n\n  ## Transport protocol\n  ## Valid values: udp, tcp, ws, wss\n  # transport = \"udp\"\n\n  ## SIP method to use for health checks\n  ## Valid values: OPTIONS, INVITE, MESSAGE\n  # method = \"OPTIONS\"\n\n  ## Request timeout\n  # timeout = \"5s\"\n\n  ## From user as it appears in SIP header\n  # from_user = \"telegraf\"\n\n  ## From domain (domain part of From header)\n  ## If not specified, uses the server hostname\n  # from_domain = \"\"\n\n  ## To user as it appears in SIP header\n  ## If not specified, uses the same value as from_user\n  # to_user = \"\"\n\n  ## Local address to use for outgoing requests\n  # local_address = \"\"\n\n  ## SIP digest authentication credentials\n  ## Leave empty to use no authentication\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config (only used for sips:// URLs or transport=tls/wss)\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n### SIP Methods\n\nThe plugin supports the following SIP methods:\n\n- **OPTIONS** (recommended): Standard SIP method for health checks. Queries\n  server capabilities without establishing a session.\n- **INVITE**: Initiates a session. Use with caution as it may create call\n  records.\n- **MESSAGE**: Sends an instant message. Useful for testing messaging\n  infrastructure.\n\n## Troubleshooting\n\n### Permission Issues\n\nSome SIP implementations may require specific network permissions. If you\nencounter permission errors, ensure Telegraf has appropriate network access.\n\n### Firewall Configuration\n\nEnsure that:\n\n- Outbound connections to SIP ports (typically 5060/5061) are allowed\n- If using UDP, firewall allows UDP packets\n- Return traffic is permitted for the transaction\n\n### Timeout Issues\n\nIf experiencing frequent timeouts:\n\n- Increase the `timeout` value\n- Verify network connectivity to the SIP server\n- Check if the SIP server is configured to respond to the chosen method\n- Ensure the correct transport protocol is selected\n\n### Response Codes\n\nDifferent SIP servers may respond with different status codes to OPTIONS requests:\n\n- `200 OK` - Server is operational and responding\n- `404 Not Found` - User or resource doesn't exist (may still indicate healthy server)\n- `401 Unauthorized` / `407 Proxy Authentication Required` - Authentication required\n\n## Metrics\n\n- sip\n  - tags:\n    - source (the SIP server address)\n    - method (the SIP method used, lowercase: options, invite, message)\n    - transport (the transport protocol: udp, tcp, ws, wss)\n    - status_code (the SIP response status code, e.g., \"200\", \"404\"; not always present, e.g. on timeout)\n  - fields:\n    - response_time_s (float, seconds) - Time taken to receive response\n      (for timeouts, this equals the configured timeout value)\n    - result (string) - The outcome of the request: the SIP reason phrase when\n      a response is received (e.g. \"OK\", \"Not Found\", \"Unauthorized\"), or a\n      sentinel value when no valid response is received (`Timeout`, `Error`,\n      `No Response`)\n    - server_agent (string, optional) - Value of the `Server` header from the\n      SIP response, identifying the remote server software\n\n## Example Output\n\n```text\nsip,host=telegraf-host,method=options,source=sip://sip.example.com:5060,status_code=200,transport=udp response_time_s=0.023,result=\"OK\" 1640000000000000000\nsip,host=telegraf-host,method=options,source=sip://unreachable.example.com:5060,transport=udp response_time_s=5.0,result=\"Timeout\" 1640000000000000000\nsip,host=telegraf-host,method=options,source=sip://sip.provider.com:5060,status_code=404,transport=udp response_time_s=0.045,result=\"Not Found\" 1640000000000000000\nsip,host=telegraf-host,method=options,source=sips://secure.voip.example.com:5061,status_code=200,transport=tcp response_time_s=0.067,result=\"OK\",server_agent=\"Asterisk PBX 18.15.0\" 1640000000000000000\n```\n"
  },
  {
    "path": "plugins/inputs/sip/sample.conf",
    "content": "# SIP (Session Initiation Protocol) health check plugin\n[[inputs.sip]]\n  ## SIP server address to monitor\n  ## Format: sip://host[:port] or sips://host[:port]\n  ##   sip://  - Standard SIP (default port 5060)\n  ##   sips:// - Secure SIP with TLS (default port 5061)\n  server = \"sip://sip.example.com:5060\"\n\n  ## Transport protocol\n  ## Valid values: udp, tcp, ws, wss\n  # transport = \"udp\"\n\n  ## SIP method to use for health checks\n  ## Valid values: OPTIONS, INVITE, MESSAGE\n  # method = \"OPTIONS\"\n\n  ## Request timeout\n  # timeout = \"5s\"\n\n  ## From user as it appears in SIP header\n  # from_user = \"telegraf\"\n\n  ## From domain (domain part of From header)\n  ## If not specified, uses the server hostname\n  # from_domain = \"\"\n\n  ## To user as it appears in SIP header\n  ## If not specified, uses the same value as from_user\n  # to_user = \"\"\n\n  ## Local address to use for outgoing requests\n  # local_address = \"\"\n\n  ## SIP digest authentication credentials\n  ## Leave empty to use no authentication\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config (only used for sips:// URLs or transport=tls/wss)\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/sip/sample.conf.in",
    "content": "# SIP (Session Initiation Protocol) health check plugin\n[[inputs.sip]]\n  ## SIP server address to monitor\n  ## Format: sip://host[:port] or sips://host[:port]\n  ##   sip://  - Standard SIP (default port 5060)\n  ##   sips:// - Secure SIP with TLS (default port 5061)\n  server = \"sip://sip.example.com:5060\"\n\n  ## Transport protocol\n  ## Valid values: udp, tcp, ws, wss\n  # transport = \"udp\"\n\n  ## SIP method to use for health checks\n  ## Valid values: OPTIONS, INVITE, MESSAGE\n  # method = \"OPTIONS\"\n\n  ## Request timeout\n  # timeout = \"5s\"\n\n  ## From user as it appears in SIP header\n  # from_user = \"telegraf\"\n\n  ## From domain (domain part of From header)\n  ## If not specified, uses the server hostname\n  # from_domain = \"\"\n\n  ## To user as it appears in SIP header\n  ## If not specified, uses the same value as from_user\n  # to_user = \"\"\n\n  ## Local address to use for outgoing requests\n  # local_address = \"\"\n\n  ## SIP digest authentication credentials\n  ## Leave empty to use no authentication\n  # username = \"\"\n  # password = \"\"\n\n  ## Optional TLS Config (only used for sips:// URLs or transport=wss)\n{{template \"/plugins/common/tls/client.conf\"}}\n"
  },
  {
    "path": "plugins/inputs/sip/sip.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage sip\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/emiago/sipgo\"\n\t\"github.com/emiago/sipgo/sip\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype serverInfo struct {\n\thost      string\n\tport      int\n\ttransport string\n\tsecure    bool\n}\n\ntype SIP struct {\n\tServer       string          `toml:\"server\"`\n\tTransport    string          `toml:\"transport\"`\n\tMethod       string          `toml:\"method\"`\n\tTimeout      config.Duration `toml:\"timeout\"`\n\tFromUser     string          `toml:\"from_user\"`\n\tFromDomain   string          `toml:\"from_domain\"`\n\tToUser       string          `toml:\"to_user\"`\n\tLocalAddress string          `toml:\"local_address\"`\n\tUsername     config.Secret   `toml:\"username\"`\n\tPassword     config.Secret   `toml:\"password\"`\n\tLog          telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\tua         *sipgo.UserAgent\n\tclient     *sipgo.Client\n\tserverInfo *serverInfo\n\tuaOpts     []sipgo.UserAgentOption\n\n\t// Cached request components\n\trequestURI sip.Uri\n\theaders    []sip.Header\n}\n\nfunc (*SIP) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *SIP) Init() error {\n\t// Set defaults\n\tif s.FromUser == \"\" {\n\t\ts.FromUser = \"telegraf\"\n\t}\n\tif s.ToUser == \"\" {\n\t\ts.ToUser = s.FromUser\n\t}\n\n\t// Validate server\n\tif s.Server == \"\" {\n\t\treturn errors.New(\"server must be specified\")\n\t}\n\n\t// Validate method\n\tswitch s.Method {\n\tcase \"\":\n\t\ts.Method = \"OPTIONS\"\n\tcase \"OPTIONS\", \"INVITE\", \"MESSAGE\":\n\t\t// valid\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid SIP method %q\", s.Method)\n\t}\n\n\tif s.Timeout < 0 {\n\t\treturn fmt.Errorf(\"timeout %s must not be negative\", time.Duration(s.Timeout))\n\t}\n\n\t// Validate server URL scheme and transport combination\n\t// Note: \"tls\" transport is deprecated per RFC 3261. Use sips:// scheme instead.\n\tu, err := url.Parse(s.Server)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid server URL: %w\", err)\n\t}\n\n\tswitch u.Scheme {\n\tcase \"sip\":\n\t\t// sip:// requires non-secure transport (udp, tcp, ws)\n\t\tswitch s.Transport {\n\t\tcase \"\":\n\t\t\ts.Transport = \"udp\"\n\t\tcase \"udp\", \"tcp\", \"ws\":\n\t\t\t// valid\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid transport %q for sip:// scheme\", s.Transport)\n\t\t}\n\tcase \"sips\":\n\t\t// sips:// requires secure transport (tcp or wss for TLS)\n\t\tswitch s.Transport {\n\t\tcase \"\":\n\t\t\ts.Transport = \"tcp\"\n\t\tcase \"tcp\", \"wss\":\n\t\t\t// valid\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid transport %q for sips:// scheme\", s.Transport)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"server URL must use sip:// or sips:// scheme, got %q\", u.Scheme)\n\t}\n\n\t// Parse server info\n\ts.serverInfo = &serverInfo{\n\t\tsecure:    u.Scheme == \"sips\",\n\t\ttransport: s.Transport,\n\t\thost:      u.Hostname(),\n\t}\n\n\tif s.serverInfo.host == \"\" {\n\t\treturn errors.New(\"server URL must specify a host\")\n\t}\n\n\tportStr := u.Port()\n\tif portStr != \"\" {\n\t\tport, err := strconv.Atoi(portStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid port %q: %w\", portStr, err)\n\t\t}\n\t\ts.serverInfo.port = port\n\t} else if s.serverInfo.secure {\n\t\ts.serverInfo.port = 5061\n\t} else {\n\t\ts.serverInfo.port = 5060\n\t}\n\n\t// Set FromDomain default after serverInfo is available\n\tif s.FromDomain == \"\" {\n\t\ts.FromDomain = s.serverInfo.host\n\t}\n\n\t// Setup TLS configuration if secure (sips:// scheme)\n\tif s.serverInfo.secure {\n\t\t// Force TLS connection even though no TLS properties are given. This will\n\t\t// use the system's TLS configuration (CA etc) if properties are empty.\n\t\tif s.ClientConfig.Enable == nil {\n\t\t\ts.ClientConfig.Enable = &s.serverInfo.secure\n\t\t}\n\t\ttlsConfig, err := s.ClientConfig.TLSConfig()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating TLS config failed: %w\", err)\n\t\t}\n\t\ts.uaOpts = append(s.uaOpts, sipgo.WithUserAgenTLSConfig(tlsConfig))\n\t}\n\n\t// Build cached request components\n\ts.requestURI = sip.Uri{\n\t\tScheme: u.Scheme,\n\t\tUser:   s.ToUser,\n\t\tHost:   s.serverInfo.host,\n\t\tPort:   s.serverInfo.port,\n\t}\n\n\ts.requestURI.UriParams = sip.NewParams()\n\ts.requestURI.UriParams.Add(\"transport\", s.serverInfo.transport)\n\n\t// Build cached headers (To, User-Agent, Contact)\n\t// Note: From header has a dynamic tag per request, so it cannot be cached\n\ts.headers = []sip.Header{\n\t\t&sip.ToHeader{Address: s.requestURI},\n\t\tsip.NewHeader(\"User-Agent\", internal.ProductToken()),\n\t}\n\n\tif s.LocalAddress != \"\" {\n\t\ts.headers = append(s.headers, &sip.ContactHeader{\n\t\t\tAddress: sip.Uri{\n\t\t\t\tScheme: u.Scheme,\n\t\t\t\tUser:   s.FromUser,\n\t\t\t\tHost:   s.LocalAddress,\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (s *SIP) Start(telegraf.Accumulator) error {\n\tua, err := sipgo.NewUA(s.uaOpts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating SIP user agent failed: %w\", err)\n\t}\n\ts.ua = ua\n\n\t// Create SIP client\n\tclient, err := sipgo.NewClient(ua)\n\tif err != nil {\n\t\ts.Stop()\n\t\treturn fmt.Errorf(\"creating SIP client failed: %w\", err)\n\t}\n\ts.client = client\n\n\treturn nil\n}\n\nfunc (s *SIP) Stop() {\n\tif s.ua != nil {\n\t\ts.ua.Close()\n\t}\n\ts.ua = nil\n\ts.client = nil\n}\n\nfunc (s *SIP) Gather(acc telegraf.Accumulator) error {\n\tfields := make(map[string]any)\n\ttags := map[string]string{\n\t\t\"source\":    s.Server,\n\t\t\"method\":    strings.ToLower(s.Method),\n\t\t\"transport\": s.serverInfo.transport,\n\t}\n\n\t// Create SIP request using cached requestURI\n\treq := sip.NewRequest(sip.RequestMethod(s.Method), s.requestURI)\n\n\t// Add From header (has dynamic tag per request, so cannot be cached)\n\tfrom := &sip.FromHeader{\n\t\tAddress: sip.Uri{\n\t\t\tScheme: s.requestURI.Scheme,\n\t\t\tUser:   s.FromUser,\n\t\t\tHost:   s.FromDomain,\n\t\t},\n\t\tParams: sip.NewParams(),\n\t}\n\tfrom.Params.Add(\"tag\", sip.GenerateTagN(16))\n\treq.AppendHeader(from)\n\n\t// Add cached headers (To, User-Agent, Contact)\n\tfor _, header := range s.headers {\n\t\treq.AppendHeader(header)\n\t}\n\n\t// Send request and measure response time\n\tstart := time.Now()\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.Timeout))\n\tdefer cancel()\n\n\t// Send request\n\tres, err := s.client.Do(ctx, req)\n\tif err != nil {\n\t\t// Check if it's a timeout\n\t\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t\tfields[\"result\"] = \"Timeout\"\n\t\t\tfields[\"response_time_s\"] = time.Duration(s.Timeout).Seconds()\n\t\t\tacc.AddFields(\"sip\", fields, tags)\n\t\t\treturn nil\n\t\t}\n\t\t// Handle other errors inline\n\t\ts.Log.Debugf(\"unauthenticated request to %q failed with: %v\", s.Server, err)\n\t\tfields[\"result\"] = \"Error\"\n\t\tfields[\"response_time_s\"] = time.Since(start).Seconds()\n\t\tacc.AddFields(\"sip\", fields, tags)\n\t\treturn nil\n\t}\n\n\t// Handle digest authentication challenge (RFC 8760)\n\t// SIP digest auth requires the server's challenge first to obtain the nonce,\n\t// so we cannot pre-authenticate on the first request.\n\tif (res.StatusCode == 401 || res.StatusCode == 407) && !s.Username.Empty() {\n\t\t// Get credentials\n\t\tusernameRaw, err := s.Username.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting username failed: %w\", err)\n\t\t}\n\t\tusername := usernameRaw.String()\n\t\tusernameRaw.Destroy()\n\n\t\tpasswordRaw, err := s.Password.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting password failed: %w\", err)\n\t\t}\n\t\tpassword := passwordRaw.String()\n\t\tpasswordRaw.Destroy()\n\n\t\tres, err = s.client.DoDigestAuth(ctx, req, res, sipgo.DigestAuth{\n\t\t\tUsername: username,\n\t\t\tPassword: password,\n\t\t})\n\t\tif err != nil {\n\t\t\ts.Log.Debugf(\"authenticated request to %q failed with: %v\", s.Server, err)\n\t\t\tfields[\"result\"] = \"Error\"\n\t\t\tfields[\"response_time_s\"] = time.Since(start).Seconds()\n\t\t\tacc.AddFields(\"sip\", fields, tags)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Record response time\n\tfields[\"response_time_s\"] = time.Since(start).Seconds()\n\n\t// Process response\n\tif res != nil {\n\t\ttags[\"status_code\"] = strconv.Itoa(res.StatusCode)\n\t\tfields[\"result\"] = res.Reason\n\t\tif serverAgent := res.GetHeader(\"Server\"); serverAgent != nil {\n\t\t\tfields[\"server_agent\"] = serverAgent.Value()\n\t\t}\n\t} else {\n\t\tfields[\"result\"] = \"No Response\"\n\t\ts.Log.Debugf(\"no response from %q\", s.Server)\n\t}\n\n\tacc.AddFields(\"sip\", fields, tags)\n\treturn nil\n}\n\nfunc init() {\n\tinputs.Add(\"sip\", func() telegraf.Input {\n\t\treturn &SIP{\n\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/sip/sip_test.go",
    "content": "package sip\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/emiago/sipgo\"\n\t\"github.com/emiago/sipgo/sip\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSampleConfig(t *testing.T) {\n\tplugin := &SIP{}\n\trequire.NotEmpty(t, plugin.SampleConfig())\n}\n\nfunc TestInitDefaults(t *testing.T) {\n\tplugin := &SIP{\n\t\tServer:  \"sip://sip.example.com:5060\",\n\t\tTimeout: config.Duration(5 * time.Second),\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\t// Check defaults\n\trequire.Equal(t, \"OPTIONS\", plugin.Method)\n\trequire.Equal(t, \"telegraf\", plugin.FromUser)\n\trequire.Equal(t, \"telegraf\", plugin.ToUser)\n\trequire.Equal(t, \"udp\", plugin.Transport)\n}\n\nfunc TestInitErrors(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tplugin   *SIP\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no_server\",\n\t\t\tplugin:   &SIP{},\n\t\t\texpected: \"server must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid_method\",\n\t\t\tplugin: &SIP{\n\t\t\t\tServer:  \"sip://sip.example.com:5060\",\n\t\t\t\tMethod:  \"INVALID\",\n\t\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\t},\n\t\t\texpected: \"invalid SIP method\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid_transport\",\n\t\t\tplugin: &SIP{\n\t\t\t\tServer:    \"sip://sip.example.com:5060\",\n\t\t\t\tTransport: \"invalid\",\n\t\t\t\tTimeout:   config.Duration(5 * time.Second),\n\t\t\t},\n\t\t\texpected: \"invalid transport\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire.ErrorContains(t, tt.plugin.Init(), tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestInitValidMethods(t *testing.T) {\n\tvalidMethods := []string{\"OPTIONS\", \"INVITE\", \"MESSAGE\"}\n\n\tfor _, method := range validMethods {\n\t\tt.Run(method, func(t *testing.T) {\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:  \"sip://sip.example.com:5060\",\n\t\t\t\tMethod:  method,\n\t\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.Equal(t, method, plugin.Method)\n\t\t})\n\t}\n}\n\nfunc TestInitInvalidMethodCase(t *testing.T) {\n\tinvalidCaseMethods := []string{\"options\", \"invite\", \"message\", \"OpTiOnS\"}\n\n\tfor _, method := range invalidCaseMethods {\n\t\tt.Run(method, func(t *testing.T) {\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:  \"sip://sip.example.com:5060\",\n\t\t\t\tMethod:  method,\n\t\t\t\tTimeout: config.Duration(5 * time.Second),\n\t\t\t}\n\n\t\t\trequire.ErrorContains(t, plugin.Init(), \"invalid SIP method\")\n\t\t})\n\t}\n}\n\nfunc TestInitValidTransports(t *testing.T) {\n\tvalidTransports := []struct {\n\t\tname      string\n\t\tserver    string\n\t\ttransport string\n\t}{\n\t\t{\"udp\", \"sip://sip.example.com:5060\", \"udp\"},\n\t\t{\"tcp\", \"sip://sip.example.com:5060\", \"tcp\"},\n\t\t{\"ws\", \"sip://sip.example.com:5060\", \"ws\"},\n\t\t{\"wss\", \"sips://sip.example.com:5061\", \"wss\"},\n\t}\n\n\tfor _, tt := range validTransports {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:    tt.server,\n\t\t\t\tTransport: tt.transport,\n\t\t\t\tTimeout:   config.Duration(5 * time.Second),\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.Equal(t, tt.transport, plugin.Transport)\n\t\t})\n\t}\n}\n\nfunc TestParseServer(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tserver    string\n\t\ttransport string\n\t\twant      serverInfo\n\t}{\n\t\t{\n\t\t\tname:      \"sip:// URL with UDP transport\",\n\t\t\tserver:    \"sip://sip.example.com:5060\",\n\t\t\ttransport: \"udp\",\n\t\t\twant:      serverInfo{host: \"sip.example.com\", port: 5060, transport: \"udp\", secure: false},\n\t\t},\n\t\t{\n\t\t\tname:      \"sips:// URL with TCP transport\",\n\t\t\tserver:    \"sips://sip.example.com:5061\",\n\t\t\ttransport: \"tcp\",\n\t\t\twant:      serverInfo{host: \"sip.example.com\", port: 5061, transport: \"tcp\", secure: true},\n\t\t},\n\t\t{\n\t\t\tname:      \"sip:// with TCP transport\",\n\t\t\tserver:    \"sip://sip.example.com:5060\",\n\t\t\ttransport: \"tcp\",\n\t\t\twant:      serverInfo{host: \"sip.example.com\", port: 5060, transport: \"tcp\", secure: false},\n\t\t},\n\t\t{\n\t\t\tname:      \"sip:// without port defaults to 5060\",\n\t\t\tserver:    \"sip://sip.example.com\",\n\t\t\ttransport: \"udp\",\n\t\t\twant:      serverInfo{host: \"sip.example.com\", port: 5060, transport: \"udp\", secure: false},\n\t\t},\n\t\t{\n\t\t\tname:      \"sips:// without port defaults to 5061\",\n\t\t\tserver:    \"sips://secure.example.com\",\n\t\t\ttransport: \"tcp\",\n\t\t\twant:      serverInfo{host: \"secure.example.com\", port: 5061, transport: \"tcp\", secure: true},\n\t\t},\n\t\t{\n\t\t\tname:      \"IP address with port\",\n\t\t\tserver:    \"sip://192.168.1.100:5070\",\n\t\t\ttransport: \"udp\",\n\t\t\twant:      serverInfo{host: \"192.168.1.100\", port: 5070, transport: \"udp\", secure: false},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:    tt.server,\n\t\t\t\tTransport: tt.transport,\n\t\t\t\tTimeout:   config.Duration(5 * time.Second),\n\t\t\t}\n\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.Equal(t, tt.want, *plugin.serverInfo)\n\t\t})\n\t}\n}\n\nfunc TestStartStop(t *testing.T) {\n\tplugin := &SIP{\n\t\tServer:  \"sip://sip.example.com:5060\",\n\t\tTimeout: config.Duration(5 * time.Second),\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\n\t// Test Start\n\trequire.NoError(t, plugin.Start(&acc))\n\n\t// Ensure user agent is created\n\trequire.NotNil(t, plugin.ua)\n\n\t// Test Stop\n\tplugin.Stop()\n\n\t// Ensure user agent is cleaned up\n\trequire.Nil(t, plugin.ua)\n}\n\nfunc TestTLSConfiguration(t *testing.T) {\n\ttests := []struct {\n\t\tname               string\n\t\tserver             string\n\t\ttransport          string\n\t\tinsecureSkipVerify bool\n\t\tshouldInitTLS      bool\n\t}{\n\t\t{\n\t\t\tname:          \"TLS via sips:// scheme\",\n\t\t\tserver:        \"sips://sip.example.com:5061\",\n\t\t\ttransport:     \"tcp\",\n\t\t\tshouldInitTLS: true,\n\t\t},\n\t\t{\n\t\t\tname:               \"TLS with skip verify\",\n\t\t\tserver:             \"sips://sip.example.com:5061\",\n\t\t\ttransport:          \"tcp\",\n\t\t\tinsecureSkipVerify: true,\n\t\t\tshouldInitTLS:      true,\n\t\t},\n\t\t{\n\t\t\tname:          \"WSS transport\",\n\t\t\tserver:        \"sips://sip.example.com:5061\",\n\t\t\ttransport:     \"wss\",\n\t\t\tshouldInitTLS: true,\n\t\t},\n\t\t{\n\t\t\tname:          \"UDP transport (no TLS)\",\n\t\t\tserver:        \"sip://sip.example.com:5060\",\n\t\t\ttransport:     \"udp\",\n\t\t\tshouldInitTLS: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:    tt.server,\n\t\t\t\tTransport: tt.transport,\n\t\t\t\tMethod:    \"OPTIONS\",\n\t\t\t\tTimeout:   config.Duration(5 * time.Second),\n\t\t\t\tFromUser:  \"telegraf\",\n\t\t\t\tLog:       testutil.Logger{},\n\t\t\t}\n\n\t\t\tplugin.ClientConfig.InsecureSkipVerify = tt.insecureSkipVerify\n\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tif tt.shouldInitTLS {\n\t\t\t\trequire.NotEmpty(t, plugin.uaOpts, \"uaOpts should contain TLS options\")\n\t\t\t} else {\n\t\t\t\trequire.Empty(t, plugin.uaOpts, \"uaOpts should be empty for non-TLS\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTLSServerName(t *testing.T) {\n\tplugin := &SIP{\n\t\tServer:    \"sips://192.168.1.100:5061\",\n\t\tTransport: \"tcp\",\n\t\tMethod:    \"OPTIONS\",\n\t\tTimeout:   config.Duration(5 * time.Second),\n\t\tFromUser:  \"telegraf\",\n\t\tLog:       testutil.Logger{},\n\t}\n\n\tplugin.ClientConfig.ServerName = \"sip.example.com\"\n\n\trequire.NoError(t, plugin.Init())\n\trequire.NotEmpty(t, plugin.uaOpts, \"uaOpts should contain TLS options for sips://\")\n}\n\nfunc TestInitRejectsDeprecatedTLSTransport(t *testing.T) {\n\tplugin := &SIP{\n\t\tServer:    \"sip://sip.example.com:5060\",\n\t\tTransport: \"tls\",\n\t\tTimeout:   config.Duration(5 * time.Second),\n\t}\n\n\trequire.ErrorContains(t, plugin.Init(), \"invalid transport\")\n}\n\nfunc TestSecureProtocolWithoutTLSConfig(t *testing.T) {\n\t// Test that sips:// works with default TLS config\n\tplugin := &SIP{\n\t\tServer:   \"sips://sip.example.com:5061\",\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(5 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\trequire.NotEmpty(t, plugin.uaOpts, \"uaOpts should contain TLS options for sips://\")\n}\n\nfunc TestSIPServerSuccess(t *testing.T) {\n\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\tres := sip.NewResponseFromRequest(req, 200, \"OK\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"200\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"OK\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n}\n\nfunc TestSIPServerErrorResponse(t *testing.T) {\n\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\tres := sip.NewResponseFromRequest(req, 404, \"Not Found\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"404\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"Not Found\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n}\n\nfunc TestSIPServerTimeout(t *testing.T) {\n\tserver, err := newMockServer(sip.OPTIONS, func(_ *sip.Request, _ sip.ServerTransaction) {\n\t\t// Intentionally no response to trigger timeout\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(100 * time.Millisecond),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Use RequireMetricsEqual for tags (no status_code on timeout)\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":    \"sip://\" + server.addr,\n\t\t\t\t\"method\":    \"options\",\n\t\t\t\t\"transport\": \"udp\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"Timeout\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n\n\t// Additionally verify response_time_s equals timeout value\n\trequire.Len(t, acc.Metrics, 1)\n\trt, ok := acc.FloatField(\"sip\", \"response_time_s\")\n\trequire.True(t, ok)\n\trequire.InDelta(t, 0.1, rt, 0.01, \"response_time_s should equal timeout value\")\n}\n\nfunc TestSIPServerDelayedResponse(t *testing.T) {\n\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tres := sip.NewResponseFromRequest(req, 200, \"OK\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(200 * time.Millisecond),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Use RequireMetricsEqual for tags and fields structure\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"200\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"OK\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n\n\t// Additionally verify response time is within expected range\n\trequire.Len(t, acc.Metrics, 1)\n\trt, ok := acc.FloatField(\"sip\", \"response_time_s\")\n\trequire.True(t, ok)\n\trequire.Greater(t, rt, 0.05, \"response time should be at least 50ms\")\n\trequire.Less(t, rt, 0.2, \"response time should be less than timeout\")\n}\n\nfunc TestSIPDifferentStatusCodes(t *testing.T) {\n\ttests := []struct {\n\t\tname       string\n\t\tstatusCode int\n\t\treason     string\n\t}{\n\t\t{\n\t\t\tname:       \"200_ok\",\n\t\t\tstatusCode: 200,\n\t\t\treason:     \"OK\",\n\t\t},\n\t\t{\n\t\t\tname:       \"404_not_found\",\n\t\t\tstatusCode: 404,\n\t\t\treason:     \"Not Found\",\n\t\t},\n\t\t{\n\t\t\tname:       \"503_service_unavailable\",\n\t\t\tstatusCode: 503,\n\t\t\treason:     \"Service Unavailable\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\t\t\tres := sip.NewResponseFromRequest(req, tt.statusCode, tt.reason, nil)\n\t\t\t\trequire.NoError(t, tx.Respond(res))\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer server.close()\n\n\t\t\tplugin := &SIP{\n\t\t\t\tServer:   \"sip://\" + server.addr,\n\t\t\t\tMethod:   \"OPTIONS\",\n\t\t\t\tTimeout:  config.Duration(2 * time.Second),\n\t\t\t\tFromUser: \"telegraf\",\n\t\t\t\tLog:      testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\texpected := []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"sip\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\t\t\"status_code\": strconv.Itoa(tt.statusCode),\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\t\t\"result\":          tt.reason,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Now(),\n\t\t\t\t),\n\t\t\t}\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n\t\t})\n\t}\n}\n\nfunc TestSIPAuthenticationRequired(t *testing.T) {\n\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\t// Respond with 401 Unauthorized to require authentication\n\t\tres := sip.NewResponseFromRequest(req, 401, \"Unauthorized\", nil)\n\t\t// Add WWW-Authenticate header (required for digest auth)\n\t\tres.AppendHeader(sip.NewHeader(\"WWW-Authenticate\", `Digest realm=\"test\", nonce=\"abc123\"`))\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\t// Test without credentials - should get auth_required\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"401\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"Unauthorized\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n}\n\nfunc TestSIPAuthenticationSuccess(t *testing.T) {\n\tconst (\n\t\tvalidUsername = \"alice\"\n\t\tvalidPassword = \"secret123\"\n\t)\n\n\tvar attemptCount atomic.Int32\n\tserver, err := newMockServer(sip.OPTIONS, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\tattemptCount.Add(1)\n\n\t\t// Check if Authorization header is present\n\t\tauthHeader := req.GetHeader(\"Authorization\")\n\n\t\tif authHeader == nil {\n\t\t\t// First attempt without auth - send 401 challenge\n\t\t\tres := sip.NewResponseFromRequest(req, 401, \"Unauthorized\", nil)\n\t\t\tres.AppendHeader(sip.NewHeader(\"WWW-Authenticate\", `Digest realm=\"test\", nonce=\"abc123\", algorithm=MD5`))\n\t\t\trequire.NoError(t, tx.Respond(res))\n\t\t\treturn\n\t\t}\n\n\t\t// Second attempt with auth - validate it exists and respond with 200\n\t\tres := sip.NewResponseFromRequest(req, 200, \"OK\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\t// Create plugin with valid credentials\n\tusername := config.NewSecret([]byte(validUsername))\n\tpassword := config.NewSecret([]byte(validPassword))\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"OPTIONS\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tUsername: username,\n\t\tPassword: password,\n\t\tLog:      testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\t// Verify server was called twice (initial request + auth retry)\n\trequire.EqualValues(t, 2, attemptCount.Load(), \"server should be called twice: initial + auth retry\")\n\n\t// Verify successful authentication\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"options\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"200\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"OK\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n\n\t// SECURITY: Verify credentials never appear in tags or fields\n\trequire.Len(t, acc.Metrics, 1)\n\tm := acc.Metrics[0]\n\tfor k, v := range m.Tags {\n\t\trequire.NotContains(t, v, validUsername, \"tag %s must not contain username\", k)\n\t\trequire.NotContains(t, v, validPassword, \"tag %s must not contain password\", k)\n\t}\n\tfor k, v := range m.Fields {\n\t\ts := fmt.Sprintf(\"%v\", v)\n\t\trequire.NotContains(t, s, validUsername, \"field %s must not contain username\", k)\n\t\trequire.NotContains(t, s, validPassword, \"field %s must not contain password\", k)\n\t}\n}\n\nfunc TestSIPMethodINVITE(t *testing.T) {\n\tserver, err := newMockServer(sip.INVITE, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\t// Verify we received an INVITE request\n\t\trequire.Equal(t, \"INVITE\", req.Method.String())\n\n\t\t// INVITE typically gets a 200 OK or 180 Ringing\n\t\tres := sip.NewResponseFromRequest(req, 200, \"OK\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"INVITE\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"invite\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"200\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"OK\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n}\n\nfunc TestSIPMethodMESSAGE(t *testing.T) {\n\tserver, err := newMockServer(sip.MESSAGE, func(req *sip.Request, tx sip.ServerTransaction) {\n\t\t// Verify we received a MESSAGE request\n\t\trequire.Equal(t, \"MESSAGE\", req.Method.String())\n\n\t\t// MESSAGE typically gets a 200 OK or 202 Accepted\n\t\tres := sip.NewResponseFromRequest(req, 200, \"OK\", nil)\n\t\trequire.NoError(t, tx.Respond(res))\n\t})\n\trequire.NoError(t, err)\n\tdefer server.close()\n\n\tplugin := &SIP{\n\t\tServer:   \"sip://\" + server.addr,\n\t\tMethod:   \"MESSAGE\",\n\t\tTimeout:  config.Duration(2 * time.Second),\n\t\tFromUser: \"telegraf\",\n\t\tLog:      testutil.Logger{},\n\t}\n\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\trequire.NoError(t, plugin.Gather(&acc))\n\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"sip\",\n\t\t\tmap[string]string{\n\t\t\t\t\"source\":      \"sip://\" + server.addr,\n\t\t\t\t\"method\":      \"message\",\n\t\t\t\t\"transport\":   \"udp\",\n\t\t\t\t\"status_code\": \"200\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"response_time_s\": float64(0),\n\t\t\t\t\"result\":          \"OK\",\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields(\"response_time_s\"))\n}\n\n// Mock server utilities\n\ntype mockServer struct {\n\tua     *sipgo.UserAgent\n\tserver *sipgo.Server\n\taddr   string\n}\n\nfunc newMockServer(method sip.RequestMethod, handler func(*sip.Request, sip.ServerTransaction)) (*mockServer, error) {\n\tua, err := sipgo.NewUA(\n\t\tsipgo.WithUserAgent(\"Test SIP Server\"),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating user agent: %w\", err)\n\t}\n\n\tserver, err := sipgo.NewServer(ua)\n\tif err != nil {\n\t\t_ = ua.Close()\n\t\treturn nil, fmt.Errorf(\"creating server: %w\", err)\n\t}\n\n\t// Register handler for the specified method\n\tserver.OnRequest(method, handler)\n\n\t// Create UDP listener ourselves to know the address before serving.\n\t// This avoids a data race in sipgo where GetListenPort reads the\n\t// transport layer map without holding the lock.\n\tudpConn, err := net.ListenPacket(\"udp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\t_ = server.Close()\n\t\t_ = ua.Close()\n\t\treturn nil, fmt.Errorf(\"listening udp: %w\", err)\n\t}\n\taddr := udpConn.LocalAddr().String()\n\n\tgo func() {\n\t\t//nolint:errcheck // Background server for testing, errors are not critical\n\t\tserver.ServeUDP(udpConn)\n\t}()\n\n\treturn &mockServer{\n\t\tua:     ua,\n\t\tserver: server,\n\t\taddr:   addr,\n\t}, nil\n}\n\nfunc (s *mockServer) close() {\n\t_ = s.server.Close()\n\t_ = s.ua.Close()\n}\n"
  },
  {
    "path": "plugins/inputs/slab/README.md",
    "content": "# Slab Input Plugin\n\nThis plugin collects details on memory consumption of [Slab cache][slab] entries\nby parsing the `/proc/slabinfo` file respecting the `HOST_PROC` environment\nvariable.\n\n> [!NOTE]\n> This plugin requires `/proc/slabinfo` to be readable by the Telegraf user.\n\n⭐ Telegraf v1.23.0\n🏷️ system\n💻 linux\n\n[slab]: https://www.kernel.org/doc/gorman/html/understand/understand011.html\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Get slab statistics from procfs\n# This plugin ONLY supports Linux\n[[inputs.slab]]\n  # no configuration - please see the plugin's README for steps to configure\n  # sudo properly\n```\n\n### Sudo configuration\n\nSince the slabinfo file is only readable by root, the plugin runs\n`sudo /bin/cat` to read the file.\n\nSudo can be configured to allow telegraf to run just the command needed to read\nthe slabinfo file. For example, if telegraf is running as the user `telegraf`\nand `HOST_PROC` is not used, add this to the sudoers file\n\n```text\ntelegraf ALL = (root) NOPASSWD: /bin/cat /proc/slabinfo\n```\n\n## Metrics\n\nMetrics include generic ones such as `kmalloc_*` as well as those of kernel\nsubsystems and drivers used by the system such as `xfs_inode`.\nEach field with `_size` suffix indicates memory consumption in bytes.\n\n- mem\n  - tags:\n  - fields:\n    - kmalloc_8_size (integer)\n    - kmalloc_16_size (integer)\n    - kmalloc_32_size (integer)\n    - kmalloc_64_size (integer)\n    - kmalloc_96_size (integer)\n    - kmalloc_128_size (integer)\n    - kmalloc_256_size (integer)\n    - kmalloc_512_size (integer)\n    - xfs_ili_size (integer)\n    - xfs_inode_size (integer)\n\n## Example Output\n\n```text\nslab kmalloc_1024_size=239927296i,kmalloc_512_size=5582848i 1651049129000000000\n```\n"
  },
  {
    "path": "plugins/inputs/slab/sample.conf",
    "content": "# Get slab statistics from procfs\n# This plugin ONLY supports Linux\n[[inputs.slab]]\n  # no configuration - please see the plugin's README for steps to configure\n  # sudo properly\n"
  },
  {
    "path": "plugins/inputs/slab/slab.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build linux\n\npackage slab\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Slab struct {\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tstatFile string\n\tuseSudo  bool\n}\n\nfunc (*Slab) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ss *Slab) Gather(acc telegraf.Accumulator) error {\n\tfields, err := ss.getSlabStats()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tacc.AddGauge(\"slab\", fields, nil)\n\treturn nil\n}\n\nfunc (ss *Slab) getSlabStats() (map[string]interface{}, error) {\n\tout, err := ss.runCmd(\"/bin/cat\", []string{ss.statFile})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbytesReader := bytes.NewReader(out)\n\tscanner := bufio.NewScanner(bytesReader)\n\n\t// Read header rows\n\tscanner.Scan() // for \"slabinfo - version: 2.1\"\n\tscanner.Scan() // for \"# name <active_objs> <num_objs> <objsize> ...\"\n\n\tfields := make(map[string]interface{})\n\t// Read data rows\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tcols := strings.Fields(line)\n\n\t\tif len(cols) < 4 {\n\t\t\treturn nil, errors.New(\"the content of /proc/slabinfo is invalid\")\n\t\t}\n\n\t\tvar numObj, sizObj int\n\n\t\tnumObj, err = strconv.Atoi(cols[2])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tsizObj, err = strconv.Atoi(cols[3])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfields[normalizeName(cols[0])] = numObj * sizObj\n\t}\n\treturn fields, nil\n}\n\nfunc (ss *Slab) runCmd(cmd string, args []string) ([]byte, error) {\n\texecCmd := exec.Command(cmd, args...)\n\tif os.Geteuid() != 0 && ss.useSudo {\n\t\texecCmd = exec.Command(\"sudo\", append([]string{\"-n\", cmd}, args...)...)\n\t}\n\n\tout, err := internal.StdOutputTimeout(execCmd, 5*time.Second)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to run command %q: %w - %v\", execCmd.Args, err, out)\n\t}\n\n\treturn out, nil\n}\n\nfunc normalizeName(name string) string {\n\treturn strings.ReplaceAll(strings.ToLower(name), \"-\", \"_\") + \"_size\"\n}\n\nfunc init() {\n\tinputs.Add(\"slab\", func() telegraf.Input {\n\t\treturn &Slab{\n\t\t\tstatFile: path.Join(internal.GetProcPath(), \"slabinfo\"),\n\t\t\tuseSudo:  true,\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/slab/slab_notlinux.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !linux\n\npackage slab\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Slab struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Slab) SampleConfig() string { return sampleConfig }\n\nfunc (s *Slab) Init() error {\n\ts.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Slab) Gather(telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"slab\", func() telegraf.Input {\n\t\treturn &Slab{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/slab/slab_test.go",
    "content": "//go:build linux\n\npackage slab\n\nimport (\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSlab(t *testing.T) {\n\tslabStats := Slab{\n\t\tstatFile: path.Join(\"testdata\", \"slabinfo\"),\n\t\tuseSudo:  false,\n\t}\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, slabStats.Gather(&acc))\n\n\tfields := map[string]interface{}{\n\t\t\"ext4_allocation_context_size\": int(16384),\n\t\t\"ext4_extent_status_size\":      int(8160),\n\t\t\"ext4_free_data_size\":          int(0),\n\t\t\"ext4_inode_cache_size\":        int(491520),\n\t\t\"ext4_io_end_size\":             int(4032),\n\t\t\"ext4_xattr_size\":              int(0),\n\t\t\"kmalloc_1024_size\":            int(239927296),\n\t\t\"kmalloc_128_size\":             int(5586944),\n\t\t\"kmalloc_16_size\":              int(17002496),\n\t\t\"kmalloc_192_size\":             int(4015872),\n\t\t\"kmalloc_2048_size\":            int(3309568),\n\t\t\"kmalloc_256_size\":             int(5423104),\n\t\t\"kmalloc_32_size\":              int(3657728),\n\t\t\"kmalloc_4096_size\":            int(2359296),\n\t\t\"kmalloc_512_size\":             int(41435136),\n\t\t\"kmalloc_64_size\":              int(8536064),\n\t\t\"kmalloc_8_size\":               int(229376),\n\t\t\"kmalloc_8192_size\":            int(1048576),\n\t\t\"kmalloc_96_size\":              int(12378240),\n\t\t\"kmem_cache_size\":              int(81920),\n\t\t\"kmem_cache_node_size\":         int(36864),\n\t}\n\n\tacc.AssertContainsFields(t, \"slab\", fields)\n}\n"
  },
  {
    "path": "plugins/inputs/slab/testdata/slabinfo",
    "content": "slabinfo - version: 2.1\n# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>\next4_inode_cache     480    480   1024   32    8 : tunables    0    0    0 : slabdata     15     15      0\next4_xattr             0      0     88   46    1 : tunables    0    0    0 : slabdata      0      0      0\next4_free_data         0      0     64   64    1 : tunables    0    0    0 : slabdata      0      0      0\next4_allocation_context    128    128    128   32    1 : tunables    0    0    0 : slabdata      4      4      0\next4_io_end           56     56     72   56    1 : tunables    0    0    0 : slabdata      1      1      0\next4_extent_status    204    204     40  102    1 : tunables    0    0    0 : slabdata      2      2      0\nkmalloc-8192         106    128   8192    4    8 : tunables    0    0    0 : slabdata     32     32      0\nkmalloc-4096         486    576   4096    8    8 : tunables    0    0    0 : slabdata     72     72      0\nkmalloc-2048        1338   1616   2048   16    8 : tunables    0    0    0 : slabdata    101    101      0\nkmalloc-1024      155845 234304   1024   32    8 : tunables    0    0    0 : slabdata   7329   7329      0\nkmalloc-512        18995  80928    512   32    4 : tunables    0    0    0 : slabdata   2529   2529      0\nkmalloc-256        16366  21184    256   32    2 : tunables    0    0    0 : slabdata    662    662      0\nkmalloc-192        18835  20916    192   21    1 : tunables    0    0    0 : slabdata    996    996      0\nkmalloc-128        23600  43648    128   32    1 : tunables    0    0    0 : slabdata   1364   1364      0\nkmalloc-96         95106 128940     96   42    1 : tunables    0    0    0 : slabdata   3070   3070      0\nkmalloc-64         82432 133376     64   64    1 : tunables    0    0    0 : slabdata   2084   2084      0\nkmalloc-32         78477 114304     32  128    1 : tunables    0    0    0 : slabdata    893    893      0\nkmalloc-16        885605 1062656     16  256    1 : tunables    0    0    0 : slabdata   4151   4151      0\nkmalloc-8          28672  28672      8  512    1 : tunables    0    0    0 : slabdata     56     56      0\nkmem_cache_node      576    576     64   64    1 : tunables    0    0    0 : slabdata      9      9      0\nkmem_cache           320    320    256   32    2 : tunables    0    0    0 : slabdata     10     10      0"
  },
  {
    "path": "plugins/inputs/slurm/README.md",
    "content": "# SLURM Input Plugin\n\nThis plugin gather diagnoses, jobs, nodes, partitions and reservation metrics\nfor a [SLURM][slurm] instance using the REST API provided by the `slurmrestd`\ndaemon.\n\n> [!NOTE]\n> This plugin supports the [REST API v0.0.38][api] which must be enabled in the\n> `slurmrestd` daemon. For more information, check the [documentation][config].\n\n⭐ Telegraf v1.32.0\n🏷️ server\n💻 all\n\n[slurm]: https://slurm.schedmd.com\n[api]: https://slurm.schedmd.com/rest.html\n[config]: https://slurm.schedmd.com/rest_quickstart.html#customization\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather SLURM metrics\n[[inputs.slurm]]\n  ## Slurmrestd URL. Both http and https can be used as schemas.\n  url = \"http://127.0.0.1:6820\"\n\n  ## Credentials for JWT-based authentication.\n  # username = \"foo\"\n  # token = \"topSecret\"\n\n  ## Enabled endpoints\n  ## List of endpoints a user can acquire data from.\n  ## Available values are: diag, jobs, nodes, partitions, reservations.\n  # enabled_endpoints = [\"diag\", \"jobs\", \"nodes\", \"partitions\", \"reservations\"]\n\n  ## Maximum time to receive a response. If set to 0s, the\n  ## request will not time out.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config. Note these options will only\n  ## be taken into account when the scheme specififed on\n  ## the URL parameter is https. They will be silently\n  ## ignored otherwise.\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n```\n\n## Metrics\n\nGiven the great deal of metrics offered by SLURM's API, an attempt has been\ndone to strike a balance between verbosity and usefulness in terms of the\ngathered information.\n\n- slurm_diag\n  - tags:\n    - source\n  - fields:\n    - server_thread_count\n    - jobs_canceled\n    - jobs_submitted\n    - jobs_started\n    - jobs_completed\n    - jobs_failed\n    - jobs_pending\n    - jobs_running\n    - schedule_cycle_last\n    - schedule_cycle_mean\n    - bf_queue_len\n    - bf_queue_len_mean\n    - bf_active\n- slurm_jobs\n  - tags:\n    - source\n    - name\n    - job_id\n  - fields:\n    - state\n    - state_reason\n    - partition\n    - nodes\n    - node_count\n    - priority\n    - nice\n    - group_id\n    - command\n    - standard_output\n    - standard_error\n    - standard_input\n    - current_working_directory\n    - submit_time\n    - start_time\n    - cpus\n    - tasks\n    - time_limit\n    - tres_cpu\n    - tres_mem\n    - tres_node\n    - tres_billing\n- slurm_nodes\n  - tags:\n    - source\n    - name\n  - fields:\n    - state\n    - cores\n    - cpus\n    - cpu_load\n    - alloc_cpu\n    - real_memory\n    - free_memory\n    - alloc_memory\n    - tres_cpu\n    - tres_mem\n    - tres_billing\n    - tres_used_cpu\n    - tres_used_mem\n    - weight\n    - slurmd_version\n    - architecture\n- slurm_partitions\n  - tags:\n    - source\n    - name\n  - fields:\n    - state\n    - total_cpu\n    - total_nodes\n    - nodes\n    - tres_cpu\n    - tres_mem\n    - tres_node\n    - tres_billing\n- slurm_reservations\n  - tags:\n    - source\n    - name\n  - fields:\n    - core_count\n    - core_spec_count\n    - groups\n    - users\n    - start_time\n    - partition\n    - accounts\n    - node_count\n    - node_list\n\n## Example Output\n\n```text\nslurm_diag,host=hoth,source=slurm_primary.example.net bf_active=false,bf_queue_len=1i,bf_queue_len_mean=1i,jobs_canceled=0i,jobs_completed=137i,jobs_failed=0i,jobs_pending=0i,jobs_running=100i,jobs_started=137i,jobs_submitted=137i,schedule_cycle_last=27i,schedule_cycle_mean=86i,server_thread_count=3i 1723466497000000000\nslurm_jobs,host=hoth,job_id=23160,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.11BCgQ\",cpus=2i,current_working_directory=\"/home/sessiondir/7CQODmQ3uw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmG9JKDmILUkln\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo225\",partition=\"atlas\",priority=4294878569i,standard_error=\"/home/sessiondir/7CQODmQ3uw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmG9JKDmILUkln.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/7CQODmQ3uw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmG9JKDmILUkln.comment\",start_time=1723354525i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723354525i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=2000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23365,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.yRcFYL\",cpus=2i,current_working_directory=\"/home/sessiondir/LgwNDmTLAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm2BKKDm8bFZsm\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo224\",partition=\"atlas\",priority=4294878364i,standard_error=\"/home/sessiondir/LgwNDmTLAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm2BKKDm8bFZsm.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/LgwNDmTLAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm2BKKDm8bFZsm.comment\",start_time=1723376763i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723376761i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23366,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.5Y9Ngb\",cpus=2i,current_working_directory=\"/home/sessiondir/HFYKDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm3BKKDmiyK3em\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo225\",partition=\"atlas\",priority=4294878363i,standard_error=\"/home/sessiondir/HFYKDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm3BKKDmiyK3em.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/HFYKDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm3BKKDmiyK3em.comment\",start_time=1723376883i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723376882i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23367,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.NmOqMU\",cpus=2i,current_working_directory=\"/home/sessiondir/nnLLDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm4BKKDmfhjFPn\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo225\",partition=\"atlas\",priority=4294878362i,standard_error=\"/home/sessiondir/nnLLDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm4BKKDmfhjFPn.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/nnLLDmULAx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm4BKKDmfhjFPn.comment\",start_time=1723376883i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723376882i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23385,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.NNsI08\",cpus=2i,current_working_directory=\"/home/sessiondir/PWvNDmH7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmz7JKDmqgKyRo\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo225\",partition=\"atlas\",priority=4294878344i,standard_error=\"/home/sessiondir/PWvNDmH7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmz7JKDmqgKyRo.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/PWvNDmH7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmz7JKDmqgKyRo.comment\",start_time=1723378725i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723378725i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23386,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.bcmS4h\",cpus=2i,current_working_directory=\"/home/sessiondir/ZNHMDmI7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm27JKDm3Ve66n\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo224\",partition=\"atlas\",priority=4294878343i,standard_error=\"/home/sessiondir/ZNHMDmI7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm27JKDm3Ve66n.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/ZNHMDmI7tw5nKG01gq4B3BRpm7wtQmABFKDmbnHPDm27JKDm3Ve66n.comment\",start_time=1723379206i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723379205i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23387,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.OgpoQZ\",cpus=2i,current_working_directory=\"/home/sessiondir/qohNDmUqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmMCKKDmzM4Yhn\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo222\",partition=\"atlas\",priority=4294878342i,standard_error=\"/home/sessiondir/qohNDmUqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmMCKKDmzM4Yhn.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/qohNDmUqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmMCKKDmzM4Yhn.comment\",start_time=1723379246i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723379245i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23388,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.xYbxSe\",cpus=2i,current_working_directory=\"/home/sessiondir/u9HODmXqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmWCKKDmRlccYn\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo224\",partition=\"atlas\",priority=4294878341i,standard_error=\"/home/sessiondir/u9HODmXqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmWCKKDmRlccYn.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/u9HODmXqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmWCKKDmRlccYn.comment\",start_time=1723379326i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723379326i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23389,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.QHtIIm\",cpus=2i,current_working_directory=\"/home/sessiondir/ZLvKDmYqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXCKKDmjp19km\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo227\",partition=\"atlas\",priority=4294878340i,standard_error=\"/home/sessiondir/ZLvKDmYqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXCKKDmjp19km.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/ZLvKDmYqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXCKKDmjp19km.comment\",start_time=1723379326i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723379326i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_jobs,host=hoth,job_id=23393,name=gridjob,source=slurm_primary.example.net command=\"/tmp/SLURM_job_script.IH19bN\",cpus=2i,current_working_directory=\"/home/sessiondir/YdPODmVqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmSCKKDmrYDOwm\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo224\",partition=\"atlas\",priority=4294878336i,standard_error=\"/home/sessiondir/YdPODmVqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmSCKKDmrYDOwm.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/YdPODmVqBx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmSCKKDmrYDOwm.comment\",start_time=1723379767i,state=\"RUNNING\",state_reason=\"None\",submit_time=1723379766i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=1000,tres_node=1 1723466497000000000\nslurm_nodes,host=hoth,name=naboo145,source=slurm_primary.example.net alloc_cpu=0i,alloc_memory=0i,architecture=\"x86_64\",cores=18i,cpu_load=0i,cpus=36i,free_memory=86450i,real_memory=94791i,slurmd_version=\"22.05.9\",state=\"idle\",tres_billing=36,tres_cpu=36,tres_mem=94791,weight=1i 1723466497000000000\nslurm_nodes,host=hoth,name=naboo146,source=slurm_primary.example.net alloc_cpu=0i,alloc_memory=0i,architecture=\"x86_64\",cores=18i,cpu_load=0i,cpus=36i,free_memory=92148i,real_memory=94791i,slurmd_version=\"22.05.9\",state=\"idle\",tres_billing=36,tres_cpu=36,tres_mem=94791,weight=1i 1723466497000000000\nslurm_nodes,host=hoth,name=naboo147,source=slurm_primary.example.net alloc_cpu=36i,alloc_memory=45000i,architecture=\"x86_64\",cores=18i,cpu_load=3826i,cpus=36i,free_memory=1607i,real_memory=94793i,slurmd_version=\"22.05.9\",state=\"allocated\",tres_billing=36,tres_cpu=36,tres_mem=94793,tres_used_cpu=36,tres_used_mem=45000,weight=1i 1723466497000000000\nslurm_nodes,host=hoth,name=naboo216,source=slurm_primary.example.net alloc_cpu=8i,alloc_memory=8000i,architecture=\"x86_64\",cores=4i,cpu_load=891i,cpus=8i,free_memory=17972i,real_memory=31877i,slurmd_version=\"22.05.9\",state=\"allocated\",tres_billing=8,tres_cpu=8,tres_mem=31877,tres_used_cpu=8,tres_used_mem=8000,weight=1i 1723466497000000000\nslurm_nodes,host=hoth,name=naboo219,source=slurm_primary.example.net alloc_cpu=16i,alloc_memory=16000i,architecture=\"x86_64\",cores=4i,cpu_load=1382i,cpus=16i,free_memory=15645i,real_memory=31875i,slurmd_version=\"22.05.9\",state=\"allocated\",tres_billing=16,tres_cpu=16,tres_mem=31875,tres_used_cpu=16,tres_used_mem=16000,weight=1i 1723466497000000000\nslurm_partitions,host=hoth,name=atlas,source=slurm_primary.example.net nodes=\"naboo145,naboo146,naboo147,naboo216,naboo219,naboo222,naboo224,naboo225,naboo227,naboo228,naboo229,naboo234,naboo235,naboo236,naboo237,naboo238,naboo239,naboo240,naboo241,naboo242,naboo243\",state=\"UP\",total_cpu=632i,total_nodes=21i,tres_billing=632,tres_cpu=632,tres_mem=1415207,tres_node=21 1723466497000000000\n```\n"
  },
  {
    "path": "plugins/inputs/slurm/sample.conf",
    "content": "# Gather SLURM metrics\n[[inputs.slurm]]\n  ## Slurmrestd URL. Both http and https can be used as schemas.\n  url = \"http://127.0.0.1:6820\"\n\n  ## Credentials for JWT-based authentication.\n  # username = \"foo\"\n  # token = \"topSecret\"\n\n  ## Enabled endpoints\n  ## List of endpoints a user can acquire data from.\n  ## Available values are: diag, jobs, nodes, partitions, reservations.\n  # enabled_endpoints = [\"diag\", \"jobs\", \"nodes\", \"partitions\", \"reservations\"]\n\n  ## Maximum time to receive a response. If set to 0s, the\n  ## request will not time out.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config. Note these options will only\n  ## be taken into account when the scheme specififed on\n  ## the URL parameter is https. They will be silently\n  ## ignored otherwise.\n  ## Set to true/false to enforce TLS being enabled/disabled. If not set,\n  ## enable TLS only if any of the other options are specified.\n  # tls_enable =\n  ## Trusted root certificates for server\n  # tls_ca = \"/path/to/cafile\"\n  ## Used for TLS client certificate authentication\n  # tls_cert = \"/path/to/certfile\"\n  ## Used for TLS client certificate authentication\n  # tls_key = \"/path/to/keyfile\"\n  ## Password for the key file if it is encrypted\n  # tls_key_pwd = \"\"\n  ## Send the specified TLS server name via SNI\n  # tls_server_name = \"kubernetes.example.com\"\n  ## Minimal TLS version to accept by the client\n  # tls_min_version = \"TLS12\"\n  ## List of ciphers to accept, by default all secure ciphers will be accepted\n  ## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.\n  ## Use \"all\", \"secure\" and \"insecure\" to add all support ciphers, secure\n  ## suites or insecure suites respectively.\n  # tls_cipher_suites = [\"secure\"]\n  ## Renegotiation method, \"never\", \"once\" or \"freely\"\n  # tls_renegotiation_method = \"never\"\n  ## Use TLS but skip chain & host verification\n  # insecure_skip_verify = false\n"
  },
  {
    "path": "plugins/inputs/slurm/sample.conf.in",
    "content": "# Gather SLURM metrics\n[[inputs.slurm]]\n  ## Slurmrestd URL. Both http and https can be used as schemas.\n  url = \"http://127.0.0.1:6820\"\n\n  ## Credentials for JWT-based authentication.\n  # username = \"foo\"\n  # token = \"topSecret\"\n\n  ## Enabled endpoints\n  ## List of endpoints a user can acquire data from.\n  ## Available values are: diag, jobs, nodes, partitions, reservations.\n  # enabled_endpoints = [\"diag\", \"jobs\", \"nodes\", \"partitions\", \"reservations\"]\n\n  ## Maximum time to receive a response. If set to 0s, the\n  ## request will not time out.\n  # response_timeout = \"5s\"\n\n  ## Optional TLS Config. Note these options will only\n  ## be taken into account when the scheme specififed on\n  ## the URL parameter is https. They will be silently\n  ## ignored otherwise.\n{{template \"/plugins/common/tls/client.conf\"}}\n"
  },
  {
    "path": "plugins/inputs/slurm/slurm.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage slurm\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tgoslurm \"github.com/pcolladosoto/goslurm/v0038\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/tls\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Slurm struct {\n\tURL              string          `toml:\"url\"`\n\tUsername         string          `toml:\"username\"`\n\tToken            string          `toml:\"token\"`\n\tEnabledEndpoints []string        `toml:\"enabled_endpoints\"`\n\tResponseTimeout  config.Duration `toml:\"response_timeout\"`\n\tLog              telegraf.Logger `toml:\"-\"`\n\ttls.ClientConfig\n\n\tclient      *goslurm.APIClient\n\tbaseURL     *url.URL\n\tendpointMap map[string]bool\n}\n\nfunc (*Slurm) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Slurm) Init() error {\n\tif len(s.EnabledEndpoints) == 0 {\n\t\ts.EnabledEndpoints = []string{\"diag\", \"jobs\", \"nodes\", \"partitions\", \"reservations\"}\n\t}\n\n\ts.endpointMap = make(map[string]bool, len(s.EnabledEndpoints))\n\tfor _, endpoint := range s.EnabledEndpoints {\n\t\tswitch e := strings.ToLower(endpoint); e {\n\t\tcase \"diag\", \"jobs\", \"nodes\", \"partitions\", \"reservations\":\n\t\t\ts.endpointMap[e] = true\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown endpoint %q\", endpoint)\n\t\t}\n\t}\n\n\tif s.URL == \"\" {\n\t\treturn errors.New(\"empty URL provided\")\n\t}\n\n\tu, err := url.Parse(s.URL)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif u.Hostname() == \"\" {\n\t\treturn fmt.Errorf(\"empty hostname for url %q\", s.URL)\n\t}\n\n\ts.baseURL = u\n\n\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"invalid scheme %q\", u.Scheme)\n\t}\n\n\ttlsCfg, err := s.ClientConfig.TLSConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif u.Scheme == \"http\" && tlsCfg != nil {\n\t\ts.Log.Warn(\"non-empty TLS configuration for a URL with an http scheme. Ignoring it...\")\n\t\ttlsCfg = nil\n\t}\n\n\tconfiguration := goslurm.NewConfiguration()\n\tconfiguration.Host = u.Host\n\tconfiguration.Scheme = u.Scheme\n\tconfiguration.UserAgent = internal.ProductToken()\n\tconfiguration.HTTPClient = &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: tlsCfg,\n\t\t},\n\t\tTimeout: time.Duration(s.ResponseTimeout),\n\t}\n\n\ts.client = goslurm.NewAPIClient(configuration)\n\n\treturn nil\n}\n\nfunc (s *Slurm) Gather(acc telegraf.Accumulator) (err error) {\n\tauth := context.WithValue(\n\t\tcontext.Background(),\n\t\tgoslurm.ContextAPIKeys,\n\t\tmap[string]goslurm.APIKey{\n\t\t\t\"user\":  {Key: s.Username},\n\t\t\t\"token\": {Key: s.Token},\n\t\t},\n\t)\n\n\tif s.endpointMap[\"diag\"] {\n\t\tdiagResp, respRaw, err := s.client.SlurmAPI.SlurmV0038Diag(auth).Execute()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting diag: %w\", err)\n\t\t}\n\t\tif diag, ok := diagResp.GetStatisticsOk(); ok {\n\t\t\ts.gatherDiagMetrics(acc, diag)\n\t\t}\n\t\trespRaw.Body.Close()\n\t}\n\n\tif s.endpointMap[\"jobs\"] {\n\t\tjobsResp, respRaw, err := s.client.SlurmAPI.SlurmV0038GetJobs(auth).Execute()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting jobs: %w\", err)\n\t\t}\n\t\tif jobs, ok := jobsResp.GetJobsOk(); ok {\n\t\t\ts.gatherJobsMetrics(acc, jobs)\n\t\t}\n\t\trespRaw.Body.Close()\n\t}\n\n\tif s.endpointMap[\"nodes\"] {\n\t\tnodesResp, respRaw, err := s.client.SlurmAPI.SlurmV0038GetNodes(auth).Execute()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting nodes: %w\", err)\n\t\t}\n\t\tif nodes, ok := nodesResp.GetNodesOk(); ok {\n\t\t\ts.gatherNodesMetrics(acc, nodes)\n\t\t}\n\t\trespRaw.Body.Close()\n\t}\n\n\tif s.endpointMap[\"partitions\"] {\n\t\tpartitionsResp, respRaw, err := s.client.SlurmAPI.SlurmV0038GetPartitions(auth).Execute()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting partitions: %w\", err)\n\t\t}\n\t\tif partitions, ok := partitionsResp.GetPartitionsOk(); ok {\n\t\t\ts.gatherPartitionsMetrics(acc, partitions)\n\t\t}\n\t\trespRaw.Body.Close()\n\t}\n\n\tif s.endpointMap[\"reservations\"] {\n\t\treservationsResp, respRaw, err := s.client.SlurmAPI.SlurmV0038GetReservations(auth).Execute()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting reservations: %w\", err)\n\t\t}\n\t\tif reservations, ok := reservationsResp.GetReservationsOk(); ok {\n\t\t\ts.gatherReservationsMetrics(acc, reservations)\n\t\t}\n\t\trespRaw.Body.Close()\n\t}\n\n\treturn nil\n}\n\nfunc parseTres(tres string) map[string]interface{} {\n\ttresKVs := strings.Split(tres, \",\")\n\tparsedValues := make(map[string]interface{}, len(tresKVs))\n\n\tfor _, tresVal := range tresKVs {\n\t\tparsedTresVal := strings.Split(tresVal, \"=\")\n\t\tif len(parsedTresVal) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttag := parsedTresVal[0]\n\t\tval := parsedTresVal[1]\n\t\tvar factor float64 = 1\n\n\t\tif tag == \"mem\" {\n\t\t\tvar ok bool\n\t\t\tfactor, ok = map[string]float64{\n\t\t\t\t\"K\": 1.0 / 1024.0,\n\t\t\t\t\"M\": 1,\n\t\t\t\t\"G\": 1024,\n\t\t\t\t\"T\": 1024 * 1024,\n\t\t\t\t\"P\": 1024 * 1024 * 1024,\n\t\t\t}[strings.ToUpper(val[len(val)-1:])]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tval = val[:len(val)-1]\n\t\t}\n\n\t\tparsedFloat, err := strconv.ParseFloat(val, 64)\n\t\tif err == nil {\n\t\t\tparsedValues[tag] = parsedFloat * factor\n\t\t\tcontinue\n\t\t}\n\t\tparsedValues[tag] = val\n\t}\n\n\treturn parsedValues\n}\n\nfunc (s *Slurm) gatherDiagMetrics(acc telegraf.Accumulator, diag *goslurm.V0038DiagStatistics) {\n\trecords := make(map[string]interface{}, 13)\n\ttags := map[string]string{\"source\": s.baseURL.Hostname()}\n\n\tif int32Ptr, ok := diag.GetServerThreadCountOk(); ok {\n\t\trecords[\"server_thread_count\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsCanceledOk(); ok {\n\t\trecords[\"jobs_canceled\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsSubmittedOk(); ok {\n\t\trecords[\"jobs_submitted\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsStartedOk(); ok {\n\t\trecords[\"jobs_started\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsCompletedOk(); ok {\n\t\trecords[\"jobs_completed\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsFailedOk(); ok {\n\t\trecords[\"jobs_failed\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsPendingOk(); ok {\n\t\trecords[\"jobs_pending\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetJobsRunningOk(); ok {\n\t\trecords[\"jobs_running\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetScheduleCycleLastOk(); ok {\n\t\trecords[\"schedule_cycle_last\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetScheduleCycleMeanOk(); ok {\n\t\trecords[\"schedule_cycle_mean\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetBfQueueLenOk(); ok {\n\t\trecords[\"bf_queue_len\"] = *int32Ptr\n\t}\n\tif int32Ptr, ok := diag.GetBfQueueLenMeanOk(); ok {\n\t\trecords[\"bf_queue_len_mean\"] = *int32Ptr\n\t}\n\tif boolPtr, ok := diag.GetBfActiveOk(); ok {\n\t\trecords[\"bf_active\"] = *boolPtr\n\t}\n\n\tacc.AddFields(\"slurm_diag\", records, tags)\n}\n\nfunc (s *Slurm) gatherJobsMetrics(acc telegraf.Accumulator, jobs []goslurm.V0038JobResponseProperties) {\n\tfor i := range jobs {\n\t\trecords := make(map[string]interface{}, 19)\n\t\ttags := make(map[string]string, 3)\n\n\t\ttags[\"source\"] = s.baseURL.Hostname()\n\t\tif strPtr, ok := jobs[i].GetNameOk(); ok {\n\t\t\ttags[\"name\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetJobIdOk(); ok {\n\t\t\ttags[\"job_id\"] = strconv.Itoa(int(*int32Ptr))\n\t\t}\n\n\t\tif strPtr, ok := jobs[i].GetJobStateOk(); ok {\n\t\t\trecords[\"state\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetStateReasonOk(); ok {\n\t\t\trecords[\"state_reason\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetPartitionOk(); ok {\n\t\t\trecords[\"partition\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetNodesOk(); ok {\n\t\t\trecords[\"nodes\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetNodeCountOk(); ok {\n\t\t\trecords[\"node_count\"] = *int32Ptr\n\t\t}\n\t\tif int64Ptr, ok := jobs[i].GetPriorityOk(); ok {\n\t\t\trecords[\"priority\"] = *int64Ptr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetNiceOk(); ok {\n\t\t\trecords[\"nice\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetGroupIdOk(); ok {\n\t\t\trecords[\"group_id\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetCommandOk(); ok {\n\t\t\trecords[\"command\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetStandardOutputOk(); ok {\n\t\t\trecords[\"standard_output\"] = strings.ReplaceAll(*strPtr, \"\\\\\", \"\")\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetStandardErrorOk(); ok {\n\t\t\trecords[\"standard_error\"] = strings.ReplaceAll(*strPtr, \"\\\\\", \"\")\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetStandardInputOk(); ok {\n\t\t\trecords[\"standard_input\"] = strings.ReplaceAll(*strPtr, \"\\\\\", \"\")\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetCurrentWorkingDirectoryOk(); ok {\n\t\t\trecords[\"current_working_directory\"] = strings.ReplaceAll(*strPtr, \"\\\\\", \"\")\n\t\t}\n\t\tif int64Ptr, ok := jobs[i].GetSubmitTimeOk(); ok {\n\t\t\trecords[\"submit_time\"] = *int64Ptr\n\t\t}\n\t\tif int64Ptr, ok := jobs[i].GetStartTimeOk(); ok {\n\t\t\trecords[\"start_time\"] = *int64Ptr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetCpusOk(); ok {\n\t\t\trecords[\"cpus\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := jobs[i].GetTasksOk(); ok {\n\t\t\trecords[\"tasks\"] = *int32Ptr\n\t\t}\n\t\tif int64Ptr, ok := jobs[i].GetTimeLimitOk(); ok {\n\t\t\trecords[\"time_limit\"] = *int64Ptr\n\t\t}\n\t\tif strPtr, ok := jobs[i].GetTresReqStrOk(); ok {\n\t\t\tfor k, v := range parseTres(*strPtr) {\n\t\t\t\trecords[\"tres_\"+k] = v\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"slurm_jobs\", records, tags)\n\t}\n}\n\nfunc (s *Slurm) gatherNodesMetrics(acc telegraf.Accumulator, nodes []goslurm.V0038Node) {\n\tfor _, node := range nodes {\n\t\trecords := make(map[string]interface{}, 13)\n\t\ttags := make(map[string]string, 2)\n\n\t\ttags[\"source\"] = s.baseURL.Hostname()\n\t\tif strPtr, ok := node.GetNameOk(); ok {\n\t\t\ttags[\"name\"] = *strPtr\n\t\t}\n\n\t\tif strPtr, ok := node.GetStateOk(); ok {\n\t\t\trecords[\"state\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := node.GetCoresOk(); ok {\n\t\t\trecords[\"cores\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := node.GetCpusOk(); ok {\n\t\t\trecords[\"cpus\"] = *int32Ptr\n\t\t}\n\t\tif int64Ptr, ok := node.GetCpuLoadOk(); ok {\n\t\t\trecords[\"cpu_load\"] = *int64Ptr\n\t\t}\n\t\tif int64Ptr, ok := node.GetAllocCpusOk(); ok {\n\t\t\trecords[\"alloc_cpu\"] = *int64Ptr\n\t\t}\n\t\tif int32Ptr, ok := node.GetRealMemoryOk(); ok {\n\t\t\trecords[\"real_memory\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := node.GetFreeMemoryOk(); ok {\n\t\t\trecords[\"free_memory\"] = *int32Ptr\n\t\t}\n\t\tif int64Ptr, ok := node.GetAllocMemoryOk(); ok {\n\t\t\trecords[\"alloc_memory\"] = *int64Ptr\n\t\t}\n\t\tif strPtr, ok := node.GetTresOk(); ok {\n\t\t\tfor k, v := range parseTres(*strPtr) {\n\t\t\t\trecords[\"tres_\"+k] = v\n\t\t\t}\n\t\t}\n\t\tif strPtr, ok := node.GetTresUsedOk(); ok {\n\t\t\tfor k, v := range parseTres(*strPtr) {\n\t\t\t\trecords[\"tres_used_\"+k] = v\n\t\t\t}\n\t\t}\n\t\tif int32Ptr, ok := node.GetWeightOk(); ok {\n\t\t\trecords[\"weight\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := node.GetSlurmdVersionOk(); ok {\n\t\t\trecords[\"slurmd_version\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := node.GetArchitectureOk(); ok {\n\t\t\trecords[\"architecture\"] = *strPtr\n\t\t}\n\n\t\tacc.AddFields(\"slurm_nodes\", records, tags)\n\t}\n}\n\nfunc (s *Slurm) gatherPartitionsMetrics(acc telegraf.Accumulator, partitions []goslurm.V0038Partition) {\n\tfor _, partition := range partitions {\n\t\trecords := make(map[string]interface{}, 5)\n\t\ttags := make(map[string]string, 2)\n\n\t\ttags[\"source\"] = s.baseURL.Hostname()\n\t\tif strPtr, ok := partition.GetNameOk(); ok {\n\t\t\ttags[\"name\"] = *strPtr\n\t\t}\n\n\t\tif strPtr, ok := partition.GetStateOk(); ok {\n\t\t\trecords[\"state\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := partition.GetTotalCpusOk(); ok {\n\t\t\trecords[\"total_cpu\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := partition.GetTotalNodesOk(); ok {\n\t\t\trecords[\"total_nodes\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := partition.GetNodesOk(); ok {\n\t\t\trecords[\"nodes\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := partition.GetTresOk(); ok {\n\t\t\tfor k, v := range parseTres(*strPtr) {\n\t\t\t\trecords[\"tres_\"+k] = v\n\t\t\t}\n\t\t}\n\n\t\tacc.AddFields(\"slurm_partitions\", records, tags)\n\t}\n}\n\nfunc (s *Slurm) gatherReservationsMetrics(acc telegraf.Accumulator, reservations []goslurm.V0038Reservation) {\n\tfor _, reservation := range reservations {\n\t\trecords := make(map[string]interface{}, 9)\n\t\ttags := make(map[string]string, 2)\n\n\t\ttags[\"source\"] = s.baseURL.Hostname()\n\t\tif strPtr, ok := reservation.GetNameOk(); ok {\n\t\t\ttags[\"name\"] = *strPtr\n\t\t}\n\n\t\tif int32Ptr, ok := reservation.GetCoreCountOk(); ok {\n\t\t\trecords[\"core_count\"] = *int32Ptr\n\t\t}\n\t\tif int32Ptr, ok := reservation.GetCoreSpecCntOk(); ok {\n\t\t\trecords[\"core_spec_count\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := reservation.GetGroupsOk(); ok {\n\t\t\trecords[\"groups\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := reservation.GetUsersOk(); ok {\n\t\t\trecords[\"users\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := reservation.GetStartTimeOk(); ok {\n\t\t\trecords[\"start_time\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := reservation.GetPartitionOk(); ok {\n\t\t\trecords[\"partition\"] = *strPtr\n\t\t}\n\t\tif strPtr, ok := reservation.GetAccountsOk(); ok {\n\t\t\trecords[\"accounts\"] = *strPtr\n\t\t}\n\t\tif int32Ptr, ok := reservation.GetNodeCountOk(); ok {\n\t\t\trecords[\"node_count\"] = *int32Ptr\n\t\t}\n\t\tif strPtr, ok := reservation.GetNodeListOk(); ok {\n\t\t\trecords[\"node_list\"] = *strPtr\n\t\t}\n\n\t\tacc.AddFields(\"slurm_reservations\", records, tags)\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"slurm\", func() telegraf.Input {\n\t\treturn &Slurm{\n\t\t\tResponseTimeout: config.Duration(5 * time.Second),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/slurm_test.go",
    "content": "package slurm\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGoodURLs(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\turl  string\n\t}{\n\t\t{\"http\", \"http://example.com:6820\"},\n\t\t{\"https\", \"https://example.com:6820\"},\n\t\t{\"http no port\", \"http://example.com\"},\n\t\t{\"https no port\", \"https://example.com\"},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Slurm{\n\t\t\t\tURL: tt.url,\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t})\n\t}\n}\n\nfunc TestWrongURLs(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\turl  string\n\t}{\n\t\t{\"wrong http scheme\", \"httpp://example.com:6820\"},\n\t\t{\"wrong https scheme\", \"httpss://example.com:6820\"},\n\t\t{\"empty url\", \"\"},\n\t\t{\"empty hostname\", \"http://:6820\"},\n\t\t{\"only scheme\", \"http://\"},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Slurm{\n\t\t\t\tURL: tt.url,\n\t\t\t}\n\t\t\trequire.Error(t, plugin.Init())\n\t\t})\n\t}\n}\n\nfunc TestWrongEndpoints(t *testing.T) {\n\ttests := []struct {\n\t\tname             string\n\t\tenabledEndpoints []string\n\t}{\n\t\t{\"empty endpoint\", []string{\"diag\", \"\", \"jobs\"}},\n\t\t{\"mistyped endpoint\", []string{\"diagg\", \"jobs\", \"partitions\"}},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tplugin := Slurm{\n\t\t\t\tURL:              \"http://example.net\",\n\t\t\t\tEnabledEndpoints: tt.enabledEndpoints,\n\t\t\t}\n\t\t\trequire.Error(t, plugin.Init())\n\t\t})\n\t}\n}\n\nfunc TestCases(t *testing.T) {\n\tentries, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\tfor _, entry := range entries {\n\t\tif !entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(entry.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", entry.Name())\n\t\t\tresponsesPath := filepath.Join(testcasePath, \"responses\")\n\t\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\n\t\t\tresponses, err := os.ReadDir(responsesPath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tpathToResponse := map[string][]byte{}\n\t\t\tfor _, response := range responses {\n\t\t\t\tif response.IsDir() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfName := response.Name()\n\t\t\t\tbuf, err := os.ReadFile(filepath.Join(responsesPath, fName))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tpathToResponse[strings.TrimSuffix(fName, filepath.Ext(fName))] = buf\n\t\t\t}\n\n\t\t\t// Prepare the influx parser for expectations\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Read expected values, if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tts := httptest.NewServer(http.NotFoundHandler())\n\t\t\tdefer ts.Close()\n\n\t\t\tts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tresp, ok := pathToResponse[strings.TrimPrefix(r.URL.Path, \"/slurm/v0.0.38/\")]\n\t\t\t\tif !ok {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Errorf(\"Expected to have path to response: %s\", r.URL.Path)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\n\t\t\t\tif _, err := w.Write(resp); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t})\n\n\t\t\t// Load the test-specific configuration\n\t\t\tcfg := config.NewConfig()\n\t\t\tcfg.Agent.Quiet = true\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Instantiate the plugin. As seen on NewConfig's documentation,\n\t\t\t// parsing the configuration will instantiate the plugins, so that\n\t\t\t// we only need to assert the plugin's type!\n\t\t\tplugin := cfg.Inputs[0].Input.(*Slurm)\n\t\t\tplugin.URL = \"http://\" + ts.Listener.Addr().String()\n\t\t\tplugin.Log = testutil.Logger{}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/expected.out",
    "content": "slurm_diag,source=127.0.0.1 bf_active=false,bf_queue_len=1i,bf_queue_len_mean=1i,jobs_canceled=0i,jobs_completed=287i,jobs_failed=1i,jobs_pending=0i,jobs_running=100i,jobs_started=287i,jobs_submitted=287i,schedule_cycle_last=298i,schedule_cycle_mean=137i,server_thread_count=3i 1723464650000000000\n\nslurm_jobs,job_id=20464,name=gridjob,source=127.0.0.1 command=\"/tmp/SLURM_job_script.OjQEIH\",cpus=2i,current_working_directory=\"/home/sessiondir/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo222\",partition=\"atlas\",priority=4294881265i,standard_error=\"/home/sessiondir/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm.comment\",start_time=1722989851i,state=\"RUNNING\",state_reason=\"None\",submit_time=1722989851i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=2000,tres_node=1 1723464650000000000\nslurm_jobs,job_id=20468,name=gridjob,source=127.0.0.1 command=\"/tmp/SLURM_job_script.XTwtdj\",cpus=2i,current_working_directory=\"/home/sessiondir/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo222\",partition=\"atlas\",priority=4294881261i,standard_error=\"/home/sessiondir/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n.comment\",start_time=1722990772i,state=\"RUNNING\",state_reason=\"None\",submit_time=1722990772i,tasks=1i,time_limit=3600i,tres_billing=1,tres_cpu=1,tres_mem=2000,tres_node=1 1723464650000000000\nslurm_jobs,job_id=23772,name=gridjob,source=127.0.0.1 command=\"/tmp/SLURM_job_script.8PMmVe\",cpus=8i,current_working_directory=\"/home/sessiondir/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm\",group_id=2005i,nice=50i,node_count=1i,nodes=\"naboo147\",partition=\"atlas\",priority=4294877957i,standard_error=\"/home/sessiondir/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm.comment\",standard_input=\"/dev/null\",standard_output=\"/home/sessiondir/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm.comment\",start_time=1723457333i,state=\"COMPLETED\",state_reason=\"None\",submit_time=1723457333i,tasks=8i,time_limit=3600i,tres_billing=8,tres_cpu=8,tres_mem=16000,tres_node=1 1723464650000000000\n\nslurm_nodes,name=naboo145,source=127.0.0.1 alloc_cpu=0i,alloc_memory=0i,architecture=\"x86_64\",cores=18i,cpu_load=27i,cpus=36i,free_memory=86423i,real_memory=94791i,slurmd_version=\"22.05.9\",state=\"idle\",tres_billing=36,tres_cpu=36,tres_mem=94791,weight=1i 1723464650000000000\nslurm_nodes,name=naboo146,source=127.0.0.1 alloc_cpu=0i,alloc_memory=0i,architecture=\"x86_64\",cores=18i,cpu_load=0i,cpus=36i,free_memory=92151i,real_memory=94791i,slurmd_version=\"22.05.9\",state=\"idle\",tres_billing=36,tres_cpu=36,tres_mem=94791,weight=1i 1723464650000000000\nslurm_nodes,name=naboo147,source=127.0.0.1 alloc_cpu=36i,alloc_memory=56000i,architecture=\"x86_64\",cores=18i,cpu_load=2969i,cpus=36i,free_memory=10908i,real_memory=94793i,slurmd_version=\"22.05.9\",state=\"allocated\",tres_billing=36,tres_cpu=36,tres_mem=94793,tres_used_cpu=36,tres_used_mem=56000,weight=1i 1723464650000000000\n\nslurm_partitions,name=atlas,source=127.0.0.1 nodes=\"naboo145,naboo146,naboo147,naboo216,naboo219,naboo222,naboo224,naboo225,naboo227,naboo228,naboo229,naboo234,naboo235,naboo236,naboo237,naboo238,naboo239,naboo240,naboo241,naboo242,naboo243\",state=\"UP\",total_cpu=632i,total_nodes=21i,tres_billing=632,tres_cpu=632,tres_mem=1415207,tres_node=21 1723464650000000000\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/responses/diag.json",
    "content": "{\n  \"meta\": {\n    \"plugin\": {\n      \"type\": \"openapi\\/v0.0.38\",\n      \"name\": \"Slurm OpenAPI v0.0.38\"\n    },\n    \"Slurm\": {\n      \"version\": {\n        \"major\": 22,\n        \"micro\": 9,\n        \"minor\": 5\n      },\n      \"release\": \"22.05.9\"\n    }\n  },\n  \"errors\": [\n  ],\n  \"statistics\": {\n    \"rpcs_by_message_type\": [\n      {\n        \"message_type\": \"REQUEST_JOB_INFO\",\n        \"type_id\": 2003,\n        \"count\": 73587,\n        \"average_time\": 658,\n        \"total_time\": 48479000\n      },\n      {\n        \"message_type\": \"REQUEST_PARTITION_INFO\",\n        \"type_id\": 2009,\n        \"count\": 158967,\n        \"average_time\": 101,\n        \"total_time\": 16185440\n      },\n      {\n        \"message_type\": \"MESSAGE_NODE_REGISTRATION_STATUS\",\n        \"type_id\": 1002,\n        \"count\": 18690,\n        \"average_time\": 137,\n        \"total_time\": 2566758\n      },\n      {\n        \"message_type\": \"REQUEST_COMPLETE_BATCH_SCRIPT\",\n        \"type_id\": 5018,\n        \"count\": 12233,\n        \"average_time\": 486,\n        \"total_time\": 5946490\n      },\n      {\n        \"message_type\": \"REQUEST_AUTH_TOKEN\",\n        \"type_id\": 5039,\n        \"count\": 36,\n        \"average_time\": 291,\n        \"total_time\": 10489\n      },\n      {\n        \"message_type\": \"REQUEST_BUILD_INFO\",\n        \"type_id\": 2001,\n        \"count\": 28201,\n        \"average_time\": 194,\n        \"total_time\": 5486061\n      },\n      {\n        \"message_type\": \"REQUEST_PING\",\n        \"type_id\": 1008,\n        \"count\": 28201,\n        \"average_time\": 103,\n        \"total_time\": 2925195\n      },\n      {\n        \"message_type\": \"REQUEST_NODE_INFO\",\n        \"type_id\": 2007,\n        \"count\": 85379,\n        \"average_time\": 175,\n        \"total_time\": 15007960\n      },\n      {\n        \"message_type\": \"REQUEST_FED_INFO\",\n        \"type_id\": 2049,\n        \"count\": 24466,\n        \"average_time\": 109,\n        \"total_time\": 2681655\n      },\n      {\n        \"message_type\": \"REQUEST_JOB_INFO_SINGLE\",\n        \"type_id\": 2021,\n        \"count\": 24466,\n        \"average_time\": 121,\n        \"total_time\": 2963320\n      },\n      {\n        \"message_type\": \"REQUEST_SUBMIT_BATCH_JOB\",\n        \"type_id\": 4003,\n        \"count\": 12233,\n        \"average_time\": 6504,\n        \"total_time\": 79574600\n      },\n      {\n        \"message_type\": \"REQUEST_STATS_INFO\",\n        \"type_id\": 2035,\n        \"count\": 1040,\n        \"average_time\": 61,\n        \"total_time\": 64431\n      },\n      {\n        \"message_type\": \"MESSAGE_EPILOG_COMPLETE\",\n        \"type_id\": 6012,\n        \"count\": 40,\n        \"average_time\": 86,\n        \"total_time\": 3455\n      },\n      {\n        \"message_type\": \"REQUEST_RESERVATION_INFO\",\n        \"type_id\": 2024,\n        \"count\": 1017,\n        \"average_time\": 47,\n        \"total_time\": 48788\n      },\n      {\n        \"message_type\": \"REQUEST_LICENSE_INFO\",\n        \"type_id\": 1021,\n        \"count\": 42,\n        \"average_time\": 43,\n        \"total_time\": 1823\n      },\n      {\n        \"message_type\": \"REQUEST_UPDATE_NODE\",\n        \"type_id\": 3002,\n        \"count\": 2,\n        \"average_time\": 415,\n        \"total_time\": 830\n      }\n    ],\n    \"rpcs_by_user\": [\n      {\n        \"user\": \"root\",\n        \"user_id\": 0,\n        \"count\": 456365,\n        \"average_time\": 224,\n        \"total_time\": 102371523\n      },\n      {\n        \"user\": \"atl001\",\n        \"user_id\": 2006,\n        \"count\": 11699,\n        \"average_time\": 6611,\n        \"total_time\": 77353396\n      },\n      {\n        \"user\": \"atl002\",\n        \"user_id\": 2007,\n        \"count\": 120,\n        \"average_time\": 3684,\n        \"total_time\": 442106\n      },\n      {\n        \"user\": \"ops001\",\n        \"user_id\": 18006,\n        \"count\": 298,\n        \"average_time\": 4447,\n        \"total_time\": 1325496\n      },\n      {\n        \"user\": \"ops003\",\n        \"user_id\": 18008,\n        \"count\": 58,\n        \"average_time\": 3732,\n        \"total_time\": 216488\n      },\n      {\n        \"user\": \"ops002\",\n        \"user_id\": 18007,\n        \"count\": 58,\n        \"average_time\": 4088,\n        \"total_time\": 237114\n      },\n      {\n        \"user\": \"99\",\n        \"user_id\": 99,\n        \"count\": 2,\n        \"average_time\": 86,\n        \"total_time\": 172\n      }\n    ],\n    \"parts_packed\": 1,\n    \"req_time\": 1723103198,\n    \"req_time_start\": 1723075200,\n    \"server_thread_count\": 3,\n    \"agent_queue_size\": 0,\n    \"agent_count\": 0,\n    \"agent_thread_count\": 0,\n    \"dbd_agent_queue_size\": 0,\n    \"gettimeofday_latency\": 21,\n    \"schedule_cycle_max\": 1116,\n    \"schedule_cycle_last\": 298,\n    \"schedule_cycle_total\": 960,\n    \"schedule_cycle_mean\": 137,\n    \"schedule_cycle_mean_depth\": 0,\n    \"schedule_cycle_per_minute\": 2,\n    \"schedule_queue_length\": 1,\n    \"jobs_submitted\": 287,\n    \"jobs_started\": 287,\n    \"jobs_completed\": 287,\n    \"jobs_canceled\": 0,\n    \"jobs_failed\": 1,\n    \"jobs_pending\": 0,\n    \"jobs_running\": 100,\n    \"job_states_ts\": 1723103172,\n    \"bf_backfilled_jobs\": 1626,\n    \"bf_last_backfilled_jobs\": 14,\n    \"bf_backfilled_het_jobs\": 0,\n    \"bf_cycle_counter\": 12,\n    \"bf_cycle_mean\": 440,\n    \"bf_depth_mean\": 1,\n    \"bf_depth_mean_try\": 1,\n    \"bf_cycle_last\": 387,\n    \"bf_cycle_max\": 811,\n    \"bf_queue_len\": 1,\n    \"bf_queue_len_mean\": 1,\n    \"bf_table_size\": 1,\n    \"bf_table_size_mean\": 1,\n    \"bf_when_last_cycle\": 1723102514,\n    \"bf_active\": false\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/responses/jobs.json",
    "content": "{\n  \"meta\": {\n    \"plugin\": {\n      \"type\": \"openapi\\/v0.0.38\",\n      \"name\": \"Slurm OpenAPI v0.0.38\"\n    },\n    \"Slurm\": {\n      \"version\": {\n        \"major\": 22,\n        \"micro\": 9,\n        \"minor\": 5\n      },\n      \"release\": \"22.05.9\"\n    }\n  },\n  \"errors\": [\n  ],\n  \"jobs\": [\n    {\n      \"account\": \"\",\n      \"accrue_time\": 1722989851,\n      \"admin_comment\": \"\",\n      \"array_job_id\": 0,\n      \"array_task_id\": null,\n      \"array_max_tasks\": 0,\n      \"array_task_string\": \"\",\n      \"association_id\": 0,\n      \"batch_features\": \"\",\n      \"batch_flag\": true,\n      \"batch_host\": \"naboo222\",\n      \"flags\": [\n        \"JOB_WAS_RUNNING\",\n        \"JOB_MEM_SET\"\n      ],\n      \"burst_buffer\": \"\",\n      \"burst_buffer_state\": \"\",\n      \"cluster\": \"local\",\n      \"cluster_features\": \"\",\n      \"command\": \"\\/tmp\\/SLURM_job_script.OjQEIH\",\n      \"comment\": \"\",\n      \"container\": \"\",\n      \"contiguous\": false,\n      \"core_spec\": null,\n      \"thread_spec\": null,\n      \"cores_per_socket\": null,\n      \"billable_tres\": 2.0,\n      \"cpus_per_task\": null,\n      \"cpu_frequency_minimum\": null,\n      \"cpu_frequency_maximum\": null,\n      \"cpu_frequency_governor\": null,\n      \"cpus_per_tres\": \"\",\n      \"deadline\": 0,\n      \"delay_boot\": 0,\n      \"dependency\": \"\",\n      \"derived_exit_code\": 0,\n      \"eligible_time\": 1722989851,\n      \"end_time\": 1723205851,\n      \"excluded_nodes\": \"\",\n      \"exit_code\": 0,\n      \"features\": \"\",\n      \"federation_origin\": \"\",\n      \"federation_siblings_active\": \"\",\n      \"federation_siblings_viable\": \"\",\n      \"gres_detail\": [\n      ],\n      \"group_id\": 2005,\n      \"group_name\": \"atlas\",\n      \"job_id\": 20464,\n      \"job_resources\": {\n        \"nodes\": \"naboo222\",\n        \"allocated_hosts\": 1,\n        \"allocated_nodes\": [\n          {\n            \"sockets\": {\n              \"0\": {\n                \"cores\": {\n                  \"0\": \"allocated\"\n                }\n              }\n            },\n            \"nodename\": \"naboo222\",\n            \"cpus_used\": 0,\n            \"memory_used\": 0,\n            \"memory_allocated\": 4000\n          }\n        ]\n      },\n      \"job_state\": \"RUNNING\",\n      \"last_sched_evaluation\": 1722989851,\n      \"licenses\": \"\",\n      \"max_cpus\": 0,\n      \"max_nodes\": 0,\n      \"mcs_label\": \"\",\n      \"memory_per_tres\": \"\",\n      \"name\": \"gridjob\",\n      \"nodes\": \"naboo222\",\n      \"nice\": 50,\n      \"tasks_per_core\": null,\n      \"tasks_per_node\": 0,\n      \"tasks_per_socket\": null,\n      \"tasks_per_board\": 0,\n      \"cpus\": 2,\n      \"node_count\": 1,\n      \"tasks\": 1,\n      \"het_job_id\": 0,\n      \"het_job_id_set\": \"\",\n      \"het_job_offset\": 0,\n      \"partition\": \"atlas\",\n      \"prefer\": \"\",\n      \"memory_per_node\": null,\n      \"memory_per_cpu\": 2000,\n      \"minimum_cpus_per_node\": 1,\n      \"minimum_tmp_disk_per_node\": 0,\n      \"preempt_time\": 0,\n      \"pre_sus_time\": 0,\n      \"priority\": 4294881265,\n      \"profile\": null,\n      \"qos\": \"\",\n      \"reboot\": false,\n      \"required_nodes\": \"\",\n      \"requeue\": false,\n      \"resize_time\": 0,\n      \"restart_cnt\": 0,\n      \"resv_name\": \"\",\n      \"shared\": null,\n      \"show_flags\": [\n        \"SHOW_ALL\",\n        \"SHOW_DETAIL\",\n        \"SHOW_LOCAL\"\n      ],\n      \"sockets_per_board\": 0,\n      \"sockets_per_node\": null,\n      \"start_time\": 1722989851,\n      \"state_description\": \"\",\n      \"state_reason\": \"None\",\n      \"standard_error\": \"\\/home\\/sessiondir\\/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm.comment\",\n      \"standard_input\": \"\\/dev\\/null\",\n      \"standard_output\": \"\\/home\\/sessiondir\\/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm.comment\",\n      \"submit_time\": 1722989851,\n      \"suspend_time\": 0,\n      \"system_comment\": \"\",\n      \"time_limit\": 3600,\n      \"time_minimum\": 0,\n      \"threads_per_core\": null,\n      \"tres_bind\": \"\",\n      \"tres_freq\": \"\",\n      \"tres_per_job\": \"\",\n      \"tres_per_node\": \"\",\n      \"tres_per_socket\": \"\",\n      \"tres_per_task\": \"\",\n      \"tres_req_str\": \"cpu=1,mem=2000M,node=1,billing=1\",\n      \"tres_alloc_str\": \"cpu=2,mem=4000M,node=1,billing=2\",\n      \"user_id\": 2006,\n      \"user_name\": \"atl001\",\n      \"wckey\": \"\",\n      \"current_working_directory\": \"\\/home\\/sessiondir\\/zv6NDmqNcv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmXSJKDmFRYcQm\"\n    },\n    {\n      \"account\": \"\",\n      \"accrue_time\": 1722990772,\n      \"admin_comment\": \"\",\n      \"array_job_id\": 0,\n      \"array_task_id\": null,\n      \"array_max_tasks\": 0,\n      \"array_task_string\": \"\",\n      \"association_id\": 0,\n      \"batch_features\": \"\",\n      \"batch_flag\": true,\n      \"batch_host\": \"naboo222\",\n      \"flags\": [\n        \"JOB_WAS_RUNNING\",\n        \"JOB_MEM_SET\"\n      ],\n      \"burst_buffer\": \"\",\n      \"burst_buffer_state\": \"\",\n      \"cluster\": \"local\",\n      \"cluster_features\": \"\",\n      \"command\": \"\\/tmp\\/SLURM_job_script.XTwtdj\",\n      \"comment\": \"\",\n      \"container\": \"\",\n      \"contiguous\": false,\n      \"core_spec\": null,\n      \"thread_spec\": null,\n      \"cores_per_socket\": null,\n      \"billable_tres\": 2.0,\n      \"cpus_per_task\": null,\n      \"cpu_frequency_minimum\": null,\n      \"cpu_frequency_maximum\": null,\n      \"cpu_frequency_governor\": null,\n      \"cpus_per_tres\": \"\",\n      \"deadline\": 0,\n      \"delay_boot\": 0,\n      \"dependency\": \"\",\n      \"derived_exit_code\": 0,\n      \"eligible_time\": 1722990772,\n      \"end_time\": 1723206772,\n      \"excluded_nodes\": \"\",\n      \"exit_code\": 0,\n      \"features\": \"\",\n      \"federation_origin\": \"\",\n      \"federation_siblings_active\": \"\",\n      \"federation_siblings_viable\": \"\",\n      \"gres_detail\": [\n      ],\n      \"group_id\": 2005,\n      \"group_name\": \"atlas\",\n      \"job_id\": 20468,\n      \"job_resources\": {\n        \"nodes\": \"naboo222\",\n        \"allocated_hosts\": 1,\n        \"allocated_nodes\": [\n          {\n            \"sockets\": {\n              \"1\": {\n                \"cores\": {\n                  \"2\": \"allocated\"\n                }\n              }\n            },\n            \"nodename\": \"naboo222\",\n            \"cpus_used\": 0,\n            \"memory_used\": 0,\n            \"memory_allocated\": 4000\n          }\n        ]\n      },\n      \"job_state\": \"RUNNING\",\n      \"last_sched_evaluation\": 1722990772,\n      \"licenses\": \"\",\n      \"max_cpus\": 0,\n      \"max_nodes\": 0,\n      \"mcs_label\": \"\",\n      \"memory_per_tres\": \"\",\n      \"name\": \"gridjob\",\n      \"nodes\": \"naboo222\",\n      \"nice\": 50,\n      \"tasks_per_core\": null,\n      \"tasks_per_node\": 0,\n      \"tasks_per_socket\": null,\n      \"tasks_per_board\": 0,\n      \"cpus\": 2,\n      \"node_count\": 1,\n      \"tasks\": 1,\n      \"het_job_id\": 0,\n      \"het_job_id_set\": \"\",\n      \"het_job_offset\": 0,\n      \"partition\": \"atlas\",\n      \"prefer\": \"\",\n      \"memory_per_node\": null,\n      \"memory_per_cpu\": 2000,\n      \"minimum_cpus_per_node\": 1,\n      \"minimum_tmp_disk_per_node\": 0,\n      \"preempt_time\": 0,\n      \"pre_sus_time\": 0,\n      \"priority\": 4294881261,\n      \"profile\": null,\n      \"qos\": \"\",\n      \"reboot\": false,\n      \"required_nodes\": \"\",\n      \"requeue\": false,\n      \"resize_time\": 0,\n      \"restart_cnt\": 0,\n      \"resv_name\": \"\",\n      \"shared\": null,\n      \"show_flags\": [\n        \"SHOW_ALL\",\n        \"SHOW_DETAIL\",\n        \"SHOW_LOCAL\"\n      ],\n      \"sockets_per_board\": 0,\n      \"sockets_per_node\": null,\n      \"start_time\": 1722990772,\n      \"state_description\": \"\",\n      \"state_reason\": \"None\",\n      \"standard_error\": \"\\/home\\/sessiondir\\/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n.comment\",\n      \"standard_input\": \"\\/dev\\/null\",\n      \"standard_output\": \"\\/home\\/sessiondir\\/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n.comment\",\n      \"submit_time\": 1722990772,\n      \"suspend_time\": 0,\n      \"system_comment\": \"\",\n      \"time_limit\": 3600,\n      \"time_minimum\": 0,\n      \"threads_per_core\": null,\n      \"tres_bind\": \"\",\n      \"tres_freq\": \"\",\n      \"tres_per_job\": \"\",\n      \"tres_per_node\": \"\",\n      \"tres_per_socket\": \"\",\n      \"tres_per_task\": \"\",\n      \"tres_req_str\": \"cpu=1,mem=2000M,node=1,billing=1\",\n      \"tres_alloc_str\": \"cpu=2,mem=4000M,node=1,billing=2\",\n      \"user_id\": 2006,\n      \"user_name\": \"atl001\",\n      \"wckey\": \"\",\n      \"current_working_directory\": \"\\/home\\/sessiondir\\/ljvLDmQccv5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmcSJKDmor4c2n\"\n    },\n    {\n      \"account\": \"\",\n      \"accrue_time\": 1723457333,\n      \"admin_comment\": \"\",\n      \"array_job_id\": 0,\n      \"array_task_id\": null,\n      \"array_max_tasks\": 0,\n      \"array_task_string\": \"\",\n      \"association_id\": 0,\n      \"batch_features\": \"\",\n      \"batch_flag\": true,\n      \"batch_host\": \"naboo147\",\n      \"flags\": [\n        \"TRES_STR_CALC\",\n        \"JOB_MEM_SET\"\n      ],\n      \"burst_buffer\": \"\",\n      \"burst_buffer_state\": \"\",\n      \"cluster\": \"local\",\n      \"cluster_features\": \"\",\n      \"command\": \"\\/tmp\\/SLURM_job_script.8PMmVe\",\n      \"comment\": \"\",\n      \"container\": \"\",\n      \"contiguous\": false,\n      \"core_spec\": null,\n      \"thread_spec\": null,\n      \"cores_per_socket\": null,\n      \"billable_tres\": 8.0,\n      \"cpus_per_task\": null,\n      \"cpu_frequency_minimum\": null,\n      \"cpu_frequency_maximum\": null,\n      \"cpu_frequency_governor\": null,\n      \"cpus_per_tres\": \"\",\n      \"deadline\": 0,\n      \"delay_boot\": 0,\n      \"dependency\": \"\",\n      \"derived_exit_code\": 0,\n      \"eligible_time\": 1723457333,\n      \"end_time\": 1723463525,\n      \"excluded_nodes\": \"\",\n      \"exit_code\": 0,\n      \"features\": \"\",\n      \"federation_origin\": \"\",\n      \"federation_siblings_active\": \"\",\n      \"federation_siblings_viable\": \"\",\n      \"gres_detail\": [\n      ],\n      \"group_id\": 2005,\n      \"group_name\": \"atlas\",\n      \"job_id\": 23772,\n      \"job_resources\": {\n        \"nodes\": \"naboo147\",\n        \"allocated_hosts\": 1,\n        \"allocated_nodes\": [\n          {\n            \"sockets\": {\n              \"0\": {\n                \"cores\": {\n                  \"3\": \"allocated\",\n                  \"10\": \"allocated\",\n                  \"12\": \"allocated\",\n                  \"13\": \"allocated\"\n                }\n              },\n              \"1\": {\n                \"cores\": {\n                  \"8\": \"allocated\",\n                  \"11\": \"allocated\",\n                  \"12\": \"allocated\",\n                  \"13\": \"allocated\"\n                }\n              }\n            },\n            \"nodename\": \"naboo147\",\n            \"cpus_used\": 0,\n            \"memory_used\": 0,\n            \"memory_allocated\": 16000\n          }\n        ]\n      },\n      \"job_state\": \"COMPLETED\",\n      \"last_sched_evaluation\": 1723457333,\n      \"licenses\": \"\",\n      \"max_cpus\": 0,\n      \"max_nodes\": 0,\n      \"mcs_label\": \"\",\n      \"memory_per_tres\": \"\",\n      \"name\": \"gridjob\",\n      \"nodes\": \"naboo147\",\n      \"nice\": 50,\n      \"tasks_per_core\": null,\n      \"tasks_per_node\": 8,\n      \"tasks_per_socket\": null,\n      \"tasks_per_board\": 0,\n      \"cpus\": 8,\n      \"node_count\": 1,\n      \"tasks\": 8,\n      \"het_job_id\": 0,\n      \"het_job_id_set\": \"\",\n      \"het_job_offset\": 0,\n      \"partition\": \"atlas\",\n      \"prefer\": \"\",\n      \"memory_per_node\": null,\n      \"memory_per_cpu\": 2000,\n      \"minimum_cpus_per_node\": 8,\n      \"minimum_tmp_disk_per_node\": 0,\n      \"preempt_time\": 0,\n      \"pre_sus_time\": 0,\n      \"priority\": 4294877957,\n      \"profile\": null,\n      \"qos\": \"\",\n      \"reboot\": false,\n      \"required_nodes\": \"\",\n      \"requeue\": false,\n      \"resize_time\": 0,\n      \"restart_cnt\": 0,\n      \"resv_name\": \"\",\n      \"shared\": null,\n      \"show_flags\": [\n        \"SHOW_ALL\",\n        \"SHOW_DETAIL\",\n        \"SHOW_LOCAL\"\n      ],\n      \"sockets_per_board\": 0,\n      \"sockets_per_node\": null,\n      \"start_time\": 1723457333,\n      \"state_description\": \"\",\n      \"state_reason\": \"None\",\n      \"standard_error\": \"\\/home\\/sessiondir\\/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm.comment\",\n      \"standard_input\": \"\\/dev\\/null\",\n      \"standard_output\": \"\\/home\\/sessiondir\\/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm.comment\",\n      \"submit_time\": 1723457333,\n      \"suspend_time\": 0,\n      \"system_comment\": \"\",\n      \"time_limit\": 3600,\n      \"time_minimum\": 0,\n      \"threads_per_core\": null,\n      \"tres_bind\": \"\",\n      \"tres_freq\": \"\",\n      \"tres_per_job\": \"\",\n      \"tres_per_node\": \"\",\n      \"tres_per_socket\": \"\",\n      \"tres_per_task\": \"\",\n      \"tres_req_str\": \"cpu=8,mem=16000M,node=1,billing=8\",\n      \"tres_alloc_str\": \"cpu=8,mem=16000M,node=1,billing=8\",\n      \"user_id\": 2006,\n      \"user_name\": \"atl001\",\n      \"wckey\": \"\",\n      \"current_working_directory\": \"\\/home\\/sessiondir\\/nN8KDmNMPx5nKG01gq4B3BRpm7wtQmABFKDmbnHPDmeIKKDml0xJjm\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/responses/nodes.json",
    "content": "{\n  \"meta\": {\n    \"plugin\": {\n      \"type\": \"openapi\\/v0.0.38\",\n      \"name\": \"Slurm OpenAPI v0.0.38\"\n    },\n    \"Slurm\": {\n      \"version\": {\n        \"major\": 22,\n        \"micro\": 9,\n        \"minor\": 5\n      },\n      \"release\": \"22.05.9\"\n    }\n  },\n  \"errors\": [\n  ],\n  \"nodes\": [\n    {\n      \"architecture\": \"x86_64\",\n      \"burstbuffer_network_address\": \"\",\n      \"boards\": 1,\n      \"boot_time\": 1719400973,\n      \"comment\": \"\",\n      \"cores\": 18,\n      \"cpu_binding\": 0,\n      \"cpu_load\": 27,\n      \"extra\": \"\",\n      \"free_memory\": 86423,\n      \"cpus\": 36,\n      \"last_busy\": 1723102876,\n      \"features\": \"\",\n      \"active_features\": \"\",\n      \"gres\": \"\",\n      \"gres_drained\": \"N\\/A\",\n      \"gres_used\": \"\",\n      \"mcs_label\": \"\",\n      \"name\": \"naboo145\",\n      \"next_state_after_reboot\": \"invalid\",\n      \"address\": \"naboo145\",\n      \"hostname\": \"naboo145\",\n      \"state\": \"idle\",\n      \"state_flags\": [\n        \"DRAIN\"\n      ],\n      \"next_state_after_reboot_flags\": [\n      ],\n      \"operating_system\": \"Linux 5.14.0-427.13.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 30 18:22:29 EDT 2024\",\n      \"owner\": null,\n      \"partitions\": [\n        \"atlas\"\n      ],\n      \"port\": 6818,\n      \"real_memory\": 94791,\n      \"reason\": \"Kill task failed\",\n      \"reason_changed_at\": 1723077306,\n      \"reason_set_by_user\": \"root\",\n      \"slurmd_start_time\": 1720394759,\n      \"sockets\": 2,\n      \"threads\": 1,\n      \"temporary_disk\": 0,\n      \"weight\": 1,\n      \"tres\": \"cpu=36,mem=94791M,billing=36\",\n      \"slurmd_version\": \"22.05.9\",\n      \"alloc_memory\": 0,\n      \"alloc_cpus\": 0,\n      \"idle_cpus\": 36,\n      \"tres_used\": null,\n      \"tres_weighted\": 0.0\n    },\n    {\n      \"architecture\": \"x86_64\",\n      \"burstbuffer_network_address\": \"\",\n      \"boards\": 1,\n      \"boot_time\": 1719400759,\n      \"comment\": \"\",\n      \"cores\": 18,\n      \"cpu_binding\": 0,\n      \"cpu_load\": 0,\n      \"extra\": \"\",\n      \"free_memory\": 92151,\n      \"cpus\": 36,\n      \"last_busy\": 1722780995,\n      \"features\": \"\",\n      \"active_features\": \"\",\n      \"gres\": \"\",\n      \"gres_drained\": \"N\\/A\",\n      \"gres_used\": \"\",\n      \"mcs_label\": \"\",\n      \"name\": \"naboo146\",\n      \"next_state_after_reboot\": \"invalid\",\n      \"address\": \"naboo146\",\n      \"hostname\": \"naboo146\",\n      \"state\": \"idle\",\n      \"state_flags\": [\n        \"DRAIN\"\n      ],\n      \"next_state_after_reboot_flags\": [\n      ],\n      \"operating_system\": \"Linux 5.14.0-427.13.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 30 18:22:29 EDT 2024\",\n      \"owner\": null,\n      \"partitions\": [\n        \"atlas\"\n      ],\n      \"port\": 6818,\n      \"real_memory\": 94791,\n      \"reason\": \"Kill task failed\",\n      \"reason_changed_at\": 1722748927,\n      \"reason_set_by_user\": \"root\",\n      \"slurmd_start_time\": 1720394759,\n      \"sockets\": 2,\n      \"threads\": 1,\n      \"temporary_disk\": 0,\n      \"weight\": 1,\n      \"tres\": \"cpu=36,mem=94791M,billing=36\",\n      \"slurmd_version\": \"22.05.9\",\n      \"alloc_memory\": 0,\n      \"alloc_cpus\": 0,\n      \"idle_cpus\": 36,\n      \"tres_used\": null,\n      \"tres_weighted\": 0.0\n    },\n    {\n      \"architecture\": \"x86_64\",\n      \"burstbuffer_network_address\": \"\",\n      \"boards\": 1,\n      \"boot_time\": 1719406605,\n      \"comment\": \"\",\n      \"cores\": 18,\n      \"cpu_binding\": 0,\n      \"cpu_load\": 2969,\n      \"extra\": \"\",\n      \"free_memory\": 10908,\n      \"cpus\": 36,\n      \"last_busy\": 1722881704,\n      \"features\": \"\",\n      \"active_features\": \"\",\n      \"gres\": \"\",\n      \"gres_drained\": \"N\\/A\",\n      \"gres_used\": \"\",\n      \"mcs_label\": \"\",\n      \"name\": \"naboo147\",\n      \"next_state_after_reboot\": \"invalid\",\n      \"address\": \"naboo147\",\n      \"hostname\": \"naboo147\",\n      \"state\": \"allocated\",\n      \"state_flags\": [\n      ],\n      \"next_state_after_reboot_flags\": [\n      ],\n      \"operating_system\": \"Linux 5.14.0-427.13.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 30 18:22:29 EDT 2024\",\n      \"owner\": null,\n      \"partitions\": [\n        \"atlas\"\n      ],\n      \"port\": 6818,\n      \"real_memory\": 94793,\n      \"reason\": \"\",\n      \"reason_changed_at\": 0,\n      \"reason_set_by_user\": null,\n      \"slurmd_start_time\": 1720394759,\n      \"sockets\": 2,\n      \"threads\": 1,\n      \"temporary_disk\": 0,\n      \"weight\": 1,\n      \"tres\": \"cpu=36,mem=94793M,billing=36\",\n      \"slurmd_version\": \"22.05.9\",\n      \"alloc_memory\": 56000,\n      \"alloc_cpus\": 36,\n      \"idle_cpus\": 0,\n      \"tres_used\": \"cpu=36,mem=56000M\",\n      \"tres_weighted\": 36.0\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/responses/partitions.json",
    "content": "{\n  \"meta\": {\n    \"plugin\": {\n      \"type\": \"openapi\\/v0.0.38\",\n      \"name\": \"Slurm OpenAPI v0.0.38\"\n    },\n    \"Slurm\": {\n      \"version\": {\n        \"major\": 22,\n        \"micro\": 9,\n        \"minor\": 5\n      },\n      \"release\": \"22.05.9\"\n    }\n  },\n  \"errors\": [\n  ],\n  \"partitions\": [\n    {\n      \"flags\": [\n        \"default\"\n      ],\n      \"preemption_mode\": [\n        \"disabled\"\n      ],\n      \"allowed_allocation_nodes\": \"\",\n      \"allowed_accounts\": \"\",\n      \"allowed_groups\": \"\",\n      \"allowed_qos\": \"\",\n      \"alternative\": \"\",\n      \"billing_weights\": \"\",\n      \"default_memory_per_cpu\": null,\n      \"default_memory_per_node\": null,\n      \"default_time_limit\": null,\n      \"denied_accounts\": \"\",\n      \"denied_qos\": \"\",\n      \"preemption_grace_time\": 0,\n      \"maximum_cpus_per_node\": -1,\n      \"maximum_memory_per_cpu\": null,\n      \"maximum_memory_per_node\": null,\n      \"maximum_nodes_per_job\": -1,\n      \"max_time_limit\": -1,\n      \"min nodes per job\": 0,\n      \"name\": \"atlas\",\n      \"nodes\": \"naboo145,naboo146,naboo147,naboo216,naboo219,naboo222,naboo224,naboo225,naboo227,naboo228,naboo229,naboo234,naboo235,naboo236,naboo237,naboo238,naboo239,naboo240,naboo241,naboo242,naboo243\",\n      \"over_time_limit\": null,\n      \"priority_job_factor\": 1,\n      \"priority_tier\": 1,\n      \"qos\": \"\",\n      \"state\": \"UP\",\n      \"total_cpus\": 632,\n      \"total_nodes\": 21,\n      \"tres\": \"cpu=632,mem=1415207M,node=21,billing=632\"\n    }\n  ]\n}"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/responses/reservations.json",
    "content": "{\n  \"meta\": {\n    \"plugin\": {\n      \"type\": \"openapi\\/v0.0.38\",\n      \"name\": \"Slurm OpenAPI v0.0.38\"\n    },\n    \"Slurm\": {\n      \"version\": {\n        \"major\": 22,\n        \"micro\": 9,\n        \"minor\": 5\n      },\n      \"release\": \"22.05.9\"\n    }\n  },\n  \"errors\": [\n  ],\n  \"reservations\": [\n  ]\n}"
  },
  {
    "path": "plugins/inputs/slurm/testcases/gather/telegraf.conf",
    "content": "[[inputs.slurm]]\n  url = \"willBeOverriden\"\n  response_timeout = \"5s\"\n  # enabled_endpoints = []\n\n  ## Credentials for JWT-based authentication\n  username = \"root\"\n  token = \"topSecret\"\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/responses/diag.json",
    "content": "{\n  \"meta\": {},\n  \"errors\": [],\n  \"statistics\": {}\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/responses/jobs.json",
    "content": "{\n  \"meta\": {},\n  \"errors\": [],\n  \"jobs\": []\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/responses/nodes.json",
    "content": "{\n  \"meta\": {},\n  \"errors\": [],\n  \"nodes\": []\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/responses/partitions.json",
    "content": "{\n  \"meta\": {},\n  \"errors\": [],\n  \"partitions\": []\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/responses/reservations.json",
    "content": "{\n  \"meta\": {},\n  \"errors\": [],\n  \"reservations\": []\n}\n"
  },
  {
    "path": "plugins/inputs/slurm/testcases/panic/telegraf.conf",
    "content": "[[inputs.slurm]]\n  url = \"willBeOverriden\"\n  response_timeout = \"5s\"\n  enabled_endpoints = []\n\n  ## Credentials for JWT-based authentication\n  username = \"root\"\n  token = \"topSecret\"\n"
  },
  {
    "path": "plugins/inputs/smart/README.md",
    "content": "# S.M.A.R.T. Input Plugin\n\nThis plugin collects [Self-Monitoring, Analysis and Reporting Technology][smart]\ninformation for storage devices information using the\n[`smartmontools`][smartmon] package. This plugin also supports NVMe devices by\nusing the [`nvme-cli`][nvmecli] package.\n\n> [!NOTE]\n> This plugin requires the [`smartmontools`][smartmon] and, for NVMe devices,\n> the [`nvme-cli`][nvmecli] packages to be installed on your system. The\n> `smartctl` and `nvme` commands must to be executable by Telegraf.\n\n⭐ Telegraf v1.5.0\n🏷️ hardware, system\n💻 all\n\n[smart]: https://en.wikipedia.org/wiki/Self-Monitoring,_Analysis_and_Reporting_Technology\n[nvmecli]: https://github.com/linux-nvme/nvme-cli\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from storage devices supporting S.M.A.R.T.\n[[inputs.smart]]\n    ## Optionally specify the path to the smartctl executable\n    # path_smartctl = \"/usr/bin/smartctl\"\n\n    ## Optionally specify the path to the nvme-cli executable\n    # path_nvme = \"/usr/bin/nvme\"\n\n    ## Optionally specify if vendor specific attributes should be propagated for NVMe disk case\n    ## [\"auto-on\"] - automatically find and enable additional vendor specific disk info\n    ## [\"vendor1\", \"vendor2\", ...] - e.g. \"Intel\" enable additional Intel specific disk info\n    # enable_extensions = [\"auto-on\"]\n\n    ## On most platforms used cli utilities requires root access.\n    ## Setting 'use_sudo' to true will make use of sudo to run smartctl or nvme-cli.\n    ## Sudo must be configured to allow the telegraf user to run smartctl or nvme-cli\n    ## without a password.\n    # use_sudo = false\n\n    ## Adds an extra tag \"device_type\", which can be used to differentiate\n    ## multiple disks behind the same controller (e.g., MegaRAID).\n    # tag_with_device_type = false\n\n    ## Skip checking disks in this power mode. Defaults to\n    ## \"standby\" to not wake up disks that have stopped rotating.\n    ## See --nocheck in the man pages for smartctl.\n    ## smartctl version 5.41 and 5.42 have faulty detection of\n    ## power mode and might require changing this value to\n    ## \"never\" depending on your disks.\n    # nocheck = \"standby\"\n\n    ## Gather all returned S.M.A.R.T. attribute metrics and the detailed\n    ## information from each drive into the 'smart_attribute' measurement.\n    # attributes = false\n\n    ## Optionally specify devices to exclude from reporting if disks auto-discovery is performed.\n    # excludes = [ \"/dev/pass6\" ]\n\n    ## Optionally specify devices and device type, if unset\n    ## a scan (smartctl --scan and smartctl --scan -d nvme) for S.M.A.R.T. devices will be done\n    ## and all found will be included except for the excluded in excludes.\n    # devices = [ \"/dev/ada0 -d atacam\", \"/dev/nvme0\"]\n\n    ## Timeout for the cli command to complete.\n    # timeout = \"30s\"\n\n    ## Optionally call smartctl and nvme-cli with a specific concurrency policy.\n    ## By default, smartctl and nvme-cli are called in separate threads (goroutines) to gather disk attributes.\n    ## Some devices (e.g. disks in RAID arrays) may have access limitations that require sequential reading of\n    ## SMART data - one individual array drive at the time. In such case please set this configuration option\n    ## to \"sequential\" to get readings for all drives.\n    ## valid options: concurrent, sequential\n    # read_method = \"concurrent\"\n```\n\n### Permissions\n\nIt's important to note that this plugin references smartctl and nvme-cli, which\nmay require additional permissions to execute successfully.  Depending on the\nuser/group permissions of the telegraf user executing this plugin, you may need\nto use sudo.\n\nYou will need the following in your telegraf config:\n\n```toml\n[[inputs.smart]]\n  use_sudo = true\n```\n\nYou will also need to update your sudoers file:\n\n```bash\n$ visudo\n# For smartctl add the following lines:\nCmnd_Alias SMARTCTL = /usr/bin/smartctl\ntelegraf  ALL=(ALL) NOPASSWD: SMARTCTL\nDefaults!SMARTCTL !logfile, !syslog, !pam_session\n\n# For nvme-cli add the following lines:\nCmnd_Alias NVME = /path/to/nvme\ntelegraf  ALL=(ALL) NOPASSWD: NVME\nDefaults!NVME !logfile, !syslog, !pam_session\n```\n\nTo run smartctl or nvme with `sudo` wrapper script can be\ncreated. `path_smartctl` or `path_nvme` in the configuration should be set to\nexecute this script.\n\n### SMART specific attributes\n\nSMART is a monitoring system included in computer hard disk drives\n(HDDs) and solid-state drives (SSDs) that detects and reports on various\nindicators of drive reliability, with the intent of enabling the anticipation of\nhardware failures.\n\nSMART information is separated between different measurements: `smart_device` is\nused for general information, while `smart_attribute` stores the detailed\nattribute information if `attributes = true` is enabled in the plugin\nconfiguration.\n\nIf no devices are specified, the plugin will scan for SMART devices via the\nfollowing command:\n\n```sh\nsmartctl --scan\n```\n\nMetrics will be reported from the following `smartctl` command:\n\n```sh\nsmartctl --info --attributes --health -n <nocheck> --format=brief <device>\n```\n\nThis plugin supports`smartmontools` version 5.41 and above, but v. 5.41 and\nv. 5.42 might require setting `nocheck`. See the comment in the sample\nconfiguration. Also, NVMe capabilities were introduced in version 6.5.\n\nTo enable SMART on a storage device run:\n\n```sh\nsmartctl -s on <device>\n```\n\n### NVMe vendor specific attributes\n\nFor NVMe disk type, plugin can use command line utility `nvme-cli`. It has a\nfeature to easy access a vendor specific attributes. This plugin supports\nnmve-cli version 1.5 and above. In case of `nvme-cli` absence NVMe vendor\nspecific metrics will not be obtained.\n\nVendor specific SMART metrics for NVMe disks may be reported from the following\n`nvme` command:\n\n```sh\nnvme <vendor> smart-log-add <device>\n```\n\nNote that vendor plugins for `nvme-cli` could require different naming\nconvention and report format.\n\nTo see installed plugin extensions, depended on the nvme-cli version, look at\nthe bottom of:\n\n```sh\nnvme help\n```\n\nTo gather disk vendor id (vid) `id-ctrl` could be used:\n\n```sh\nnvme id-ctrl <device>\n```\n\nAssociation between a vid and company can be found in the\n[membership list][members].\n\nDevices affiliation to being NVMe or non NVMe will be determined thanks to:\n\n```sh\nsmartctl --scan\n```\n\nand:\n\n```sh\nsmartctl --scan -d nvme\n```\n\n[members]: https://pcisig.com/membership/member-companies\n\n## Metrics\n\n- smart_device:\n  - tags:\n    - capacity\n    - device\n    - device_type (only emitted if `tag_with_device_type` is set to `true`)\n    - enabled\n    - model\n    - serial_no\n    - wwn\n  - fields:\n    - available_spare (NVMe)\n    - available_spare_threshold (NVMe)\n    - critical_temperature_time (NVMe)\n    - critical_warning (NVMe)\n    - error_log_entries (NVMe)\n    - exit_status\n    - health_ok\n    - media_errors (NVMe)\n    - media_wearout_indicator\n    - percent_lifetime_remain\n    - percentage_used (NVMe)\n    - power_cycle_count\n    - power_on_hours\n    - read_error_rate\n    - seek_error_rate\n    - temp_c\n    - udma_crc_errors\n    - unsafe_shutdowns (NVMe)\n    - warning_temperature_time (NVMe)\n    - wear_leveling_count\n\n- smart_attribute:\n  - tags:\n    - capacity\n    - device\n    - device_type (only emitted if `tag_with_device_type` is set to `true`)\n    - enabled\n    - fail\n    - flags\n    - id\n    - model\n    - name\n    - serial_no\n    - wwn\n  - fields:\n    - exit_status\n    - raw_value\n    - threshold\n    - value\n    - worst\n\n### Flags\n\nThe interpretation of the tag `flags` is:\n\n- `K` auto-keep\n- `C` event count\n- `R` error rate\n- `S` speed/performance\n- `O` updated online\n- `P` prefailure warning\n\n### Exit Status\n\nThe `exit_status` field captures the exit status of the used cli utilities\ncommand which is defined by a bitmask. For the interpretation of the bitmask see\nthe man page for smartctl or nvme-cli.\n\n## Device Names\n\nDevice names, e.g., `/dev/sda`, are _not persistent_, and may be\nsubject to change across reboots or system changes. Instead, you can use the\n_World Wide Name_ (WWN) or serial number to identify devices. On Linux block\ndevices can be referenced by the WWN in the following location:\n`/dev/disk/by-id/`.\n\n## Troubleshooting\n\nIf you expect to see more SMART metrics than this plugin shows, be sure to use a\nproper version of smartctl or nvme-cli utility which has the functionality to\ngather desired data. Also, check your device capability because not every SMART\nmetrics are mandatory. For example the number of temperature sensors depends on\nthe device specification.\n\nIf this plugin is not working as expected for your SMART enabled device,\nplease run these commands and include the output in a bug report:\n\nFor non NVMe devices (from smartctl version >= 7.0 this will also return NVMe\ndevices by default):\n\n```sh\nsmartctl --scan\n```\n\nFor NVMe devices:\n\n```sh\nsmartctl --scan -d nvme\n```\n\nRun the following command replacing your configuration setting for NOCHECK and\nthe DEVICE (name of the device could be taken from the previous command):\n\n```sh\nsmartctl --info --health --attributes --tolerance=verypermissive --nocheck NOCHECK --format=brief -d DEVICE\n```\n\nIf you try to gather vendor specific metrics, please provide this command\nand replace vendor and device to match your case:\n\n```sh\nnvme VENDOR smart-log-add DEVICE\n```\n\nIf you have specified devices array in configuration file, and Telegraf only\nshows data from one device, you should change the plugin configuration to\nsequentially gather disk attributes instead of collecting it in separate threads\n(goroutines). To do this find in plugin configuration read_method and change it\nto sequential:\n\n```toml\n    ## Optionally call smartctl and nvme-cli with a specific concurrency policy.\n    ## By default, smartctl and nvme-cli are called in separate threads (goroutines) to gather disk attributes.\n    ## Some devices (e.g. disks in RAID arrays) may have access limitations that require sequential reading of\n    ## SMART data - one individual array drive at the time. In such case please set this configuration option\n    ## to \"sequential\" to get readings for all drives.\n    ## valid options: concurrent, sequential\n    read_method = \"sequential\"\n```\n\n## Example Output\n\n```text\nsmart_device,enabled=Enabled,host=mbpro.local,device=rdisk0,model=APPLE\\ SSD\\ SM0512F,serial_no=S1K5NYCD964433,wwn=5002538655584d30,capacity=500277790720 udma_crc_errors=0i,exit_status=0i,health_ok=true,read_error_rate=0i,temp_c=40i 1502536854000000000\nsmart_attribute,capacity=500277790720,device=rdisk0,enabled=Enabled,fail=-,flags=-O-RC-,host=mbpro.local,id=199,model=APPLE\\ SSD\\ SM0512F,name=UDMA_CRC_Error_Count,serial_no=S1K5NYCD964433,wwn=5002538655584d30 exit_status=0i,raw_value=0i,threshold=0i,value=200i,worst=200i 1502536854000000000\nsmart_attribute,capacity=500277790720,device=rdisk0,enabled=Enabled,fail=-,flags=-O---K,host=mbpro.local,id=199,model=APPLE\\ SSD\\ SM0512F,name=Unknown_SSD_Attribute,serial_no=S1K5NYCD964433,wwn=5002538655584d30 exit_status=0i,raw_value=0i,threshold=0i,value=100i,worst=100i 1502536854000000000\n```\n"
  },
  {
    "path": "plugins/inputs/smart/sample.conf",
    "content": "# Read metrics from storage devices supporting S.M.A.R.T.\n[[inputs.smart]]\n    ## Optionally specify the path to the smartctl executable\n    # path_smartctl = \"/usr/bin/smartctl\"\n\n    ## Optionally specify the path to the nvme-cli executable\n    # path_nvme = \"/usr/bin/nvme\"\n\n    ## Optionally specify if vendor specific attributes should be propagated for NVMe disk case\n    ## [\"auto-on\"] - automatically find and enable additional vendor specific disk info\n    ## [\"vendor1\", \"vendor2\", ...] - e.g. \"Intel\" enable additional Intel specific disk info\n    # enable_extensions = [\"auto-on\"]\n\n    ## On most platforms used cli utilities requires root access.\n    ## Setting 'use_sudo' to true will make use of sudo to run smartctl or nvme-cli.\n    ## Sudo must be configured to allow the telegraf user to run smartctl or nvme-cli\n    ## without a password.\n    # use_sudo = false\n\n    ## Adds an extra tag \"device_type\", which can be used to differentiate\n    ## multiple disks behind the same controller (e.g., MegaRAID).\n    # tag_with_device_type = false\n\n    ## Skip checking disks in this power mode. Defaults to\n    ## \"standby\" to not wake up disks that have stopped rotating.\n    ## See --nocheck in the man pages for smartctl.\n    ## smartctl version 5.41 and 5.42 have faulty detection of\n    ## power mode and might require changing this value to\n    ## \"never\" depending on your disks.\n    # nocheck = \"standby\"\n\n    ## Gather all returned S.M.A.R.T. attribute metrics and the detailed\n    ## information from each drive into the 'smart_attribute' measurement.\n    # attributes = false\n\n    ## Optionally specify devices to exclude from reporting if disks auto-discovery is performed.\n    # excludes = [ \"/dev/pass6\" ]\n\n    ## Optionally specify devices and device type, if unset\n    ## a scan (smartctl --scan and smartctl --scan -d nvme) for S.M.A.R.T. devices will be done\n    ## and all found will be included except for the excluded in excludes.\n    # devices = [ \"/dev/ada0 -d atacam\", \"/dev/nvme0\"]\n\n    ## Timeout for the cli command to complete.\n    # timeout = \"30s\"\n\n    ## Optionally call smartctl and nvme-cli with a specific concurrency policy.\n    ## By default, smartctl and nvme-cli are called in separate threads (goroutines) to gather disk attributes.\n    ## Some devices (e.g. disks in RAID arrays) may have access limitations that require sequential reading of\n    ## SMART data - one individual array drive at the time. In such case please set this configuration option\n    ## to \"sequential\" to get readings for all drives.\n    ## valid options: concurrent, sequential\n    # read_method = \"concurrent\"\n"
  },
  {
    "path": "plugins/inputs/smart/smart.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage smart\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar (\n\t// Device Model:     APPLE SSD SM256E\n\t// Product:              HUH721212AL5204\n\t// Model Number: TS128GMTE850\n\tmodelInfo = regexp.MustCompile(`^(Device Model|Product|Model Number):\\s+(.*)$`)\n\t// Serial Number:    S0X5NZBC422720\n\tserialInfo = regexp.MustCompile(`(?i)^Serial Number:\\s+(.*)$`)\n\t// LU WWN Device Id: 5 002538 655584d30\n\twwnInfo = regexp.MustCompile(`^LU WWN Device Id:\\s+(.*)$`)\n\t// User Capacity:    251,000,193,024 bytes [251 GB]\n\tuserCapacityInfo = regexp.MustCompile(`^User Capacity:\\s+([0-9,]+)\\s+bytes.*$`)\n\t// SMART support is: Enabled\n\tsmartEnabledInfo = regexp.MustCompile(`^SMART support is:\\s+(\\w+)$`)\n\t// Power mode is:    ACTIVE or IDLE or Power mode was:   STANDBY\n\tpowermodeInfo = regexp.MustCompile(`^Power mode \\w+:\\s+(\\w+)`)\n\t// Device is in STANDBY mode\n\tstandbyInfo = regexp.MustCompile(`^Device is in\\s+(\\w+)`)\n\t// SMART overall-health self-assessment test result: PASSED\n\t// SMART Health Status: OK\n\t// PASSED, FAILED, UNKNOWN\n\tsmartOverallHealth = regexp.MustCompile(`^(SMART overall-health self-assessment test result|SMART Health Status):\\s+(\\w+).*$`)\n\n\t// sasNVMeAttr is a SAS or NVMe SMART attribute\n\tsasNVMeAttr = regexp.MustCompile(`^([^:]+):\\s+(.+)$`)\n\n\t// ID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n\t//   1 Raw_Read_Error_Rate     -O-RC-   200   200   000    -    0\n\t//   5 Reallocated_Sector_Ct   PO--CK   100   100   000    -    0\n\t// 192 Power-Off_Retract_Count -O--C-   097   097   000    -    14716\n\n\t// ID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n\t//   1 Raw_Read_Error_Rate     PO-RC-+  200   200   051    -    30\n\t//   5 Reallocated_Sector_Ct   POS-C-+  200   200   140    -    0\n\t// 192 Power-Off_Retract_Count -O-RCK+  200   200   000    -    4\n\tattribute = regexp.MustCompile(`^\\s*([0-9]+)\\s(\\S+)\\s+([-P][-O][-S][-R][-C][-K])[\\+]?\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9-]+)\\s+([-\\w]+)\\s+([\\w\\+\\.\\/]+).*$`)\n\n\t//  Additional Smart Log for NVME device:nvme0 namespace-id:ffffffff\n\t// nvme version 1.14+ metrics:\n\t// ID             KEY                                 Normalized     Raw\n\t// 0xab    program_fail_count                             100         0\n\n\t// nvme deprecated metric format:\n\t//\tkey                               normalized raw\n\t//\tprogram_fail_count              : 100%       0\n\n\t// REGEX pattern supports deprecated metrics (nvme-cli version below 1.14) and metrics from nvme-cli 1.14 (and above).\n\tintelExpressionPattern = regexp.MustCompile(`^([A-Za-z0-9_\\s]+)[:|\\s]+(\\d+)[%|\\s]+(.+)`)\n\n\t//\tvid     : 0x8086\n\t//\tsn      : CFGT53260XSP8011P\n\tnvmeIDCtrlExpressionPattern = regexp.MustCompile(`^([\\w\\s]+):([\\s\\w]+)`)\n\n\t// Format from nvme-cli 1.14 (and above) gives ID and KEY, this regex is for separating id from key.\n\t//  ID\t\t\t  KEY\n\t// 0xab    program_fail_count\n\tnvmeIDSeparatePattern = regexp.MustCompile(`^([A-Za-z0-9_]+)(.+)`)\n\n\tdeviceFieldIDs = map[string]string{\n\t\t\"1\":   \"read_error_rate\",\n\t\t\"5\":   \"reallocated_sectors_count\",\n\t\t\"7\":   \"seek_error_rate\",\n\t\t\"9\":   \"power_on_hours\",\n\t\t\"12\":  \"power_cycle_count\",\n\t\t\"10\":  \"spin_retry_count\",\n\t\t\"184\": \"end_to_end_error\",\n\t\t\"187\": \"uncorrectable_errors\",\n\t\t\"188\": \"command_timeout\",\n\t\t\"190\": \"temp_c\",\n\t\t\"194\": \"temp_c\",\n\t\t\"196\": \"realloc_event_count\",\n\t\t\"197\": \"pending_sector_count\",\n\t\t\"198\": \"uncorrectable_sector_count\",\n\t\t\"199\": \"udma_crc_errors\",\n\t\t\"201\": \"soft_read_error_rate\",\n\t}\n\n\t// There are some fields we're interested in which use the vendor specific device ids\n\t// so we need to be able to match on name instead\n\tdeviceFieldNames = map[string]string{\n\t\t\"Percent_Lifetime_Remain\": \"percent_lifetime_remain\",\n\t\t\"Wear_Leveling_Count\":     \"wear_leveling_count\",\n\t\t\"Media_Wearout_Indicator\": \"media_wearout_indicator\",\n\t}\n\n\t// NVMe fields to promote from smart_attribute to smart_device measurement.\n\t// Also applies to SAS attributes parsed through the sasNVMeAttributes path.\n\tnvmeDeviceFields = map[string]string{\n\t\t\"Power_Cycle_Count\":               \"power_cycle_count\",\n\t\t\"Power_On_Hours\":                  \"power_on_hours\",\n\t\t\"Unsafe_Shutdowns\":                \"unsafe_shutdowns\",\n\t\t\"Available_Spare\":                 \"available_spare\",\n\t\t\"Available_Spare_Threshold\":       \"available_spare_threshold\",\n\t\t\"Percentage_Used\":                 \"percentage_used\",\n\t\t\"Critical_Warning\":                \"critical_warning\",\n\t\t\"Media_and_Data_Integrity_Errors\": \"media_errors\",\n\t\t\"Error_Information_Log_Entries\":   \"error_log_entries\",\n\t\t\"Warning_Temperature_Time\":        \"warning_temperature_time\",\n\t\t\"Critical_Temperature_Time\":       \"critical_temperature_time\",\n\t}\n\n\t// to obtain metrics from smartctl\n\tsasNVMeAttributes = map[string]struct {\n\t\tID    string\n\t\tName  string\n\t\tParse func(fields, deviceFields map[string]interface{}, str string) error\n\t}{\n\t\t\"Accumulated start-stop cycles\": {\n\t\t\tID:   \"4\",\n\t\t\tName: \"Start_Stop_Count\",\n\t\t},\n\t\t\"Accumulated load-unload cycles\": {\n\t\t\tID:   \"193\",\n\t\t\tName: \"Load_Cycle_Count\",\n\t\t},\n\t\t\"Current Drive Temperature\": {\n\t\t\tID:    \"194\",\n\t\t\tName:  \"Temperature_Celsius\",\n\t\t\tParse: parseTemperature,\n\t\t},\n\t\t\"Temperature\": {\n\t\t\tID:    \"194\",\n\t\t\tName:  \"Temperature_Celsius\",\n\t\t\tParse: parseTemperature,\n\t\t},\n\t\t\"Power Cycles\": {\n\t\t\tID:   \"12\",\n\t\t\tName: \"Power_Cycle_Count\",\n\t\t},\n\t\t\"Power On Hours\": {\n\t\t\tID:   \"9\",\n\t\t\tName: \"Power_On_Hours\",\n\t\t},\n\t\t\"Media and Data Integrity Errors\": {\n\t\t\tName: \"Media_and_Data_Integrity_Errors\",\n\t\t},\n\t\t\"Error Information Log Entries\": {\n\t\t\tName: \"Error_Information_Log_Entries\",\n\t\t},\n\t\t\"Critical Warning\": {\n\t\t\tName: \"Critical_Warning\",\n\t\t\tParse: func(fields, _ map[string]interface{}, str string) error {\n\t\t\t\tvar value int64\n\t\t\t\tif _, err := fmt.Sscanf(str, \"0x%x\", &value); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tfields[\"raw_value\"] = value\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\t\"Available Spare\": {\n\t\t\tName:  \"Available_Spare\",\n\t\t\tParse: parsePercentageInt,\n\t\t},\n\t\t\"Available Spare Threshold\": {\n\t\t\tName:  \"Available_Spare_Threshold\",\n\t\t\tParse: parsePercentageInt,\n\t\t},\n\t\t\"Percentage Used\": {\n\t\t\tName:  \"Percentage_Used\",\n\t\t\tParse: parsePercentageInt,\n\t\t},\n\t\t\"Percentage used endurance indicator\": {\n\t\t\tName:  \"Percentage_Used\",\n\t\t\tParse: parsePercentageInt,\n\t\t},\n\t\t\"Data Units Read\": {\n\t\t\tName:  \"Data_Units_Read\",\n\t\t\tParse: parseDataUnits,\n\t\t},\n\t\t\"Data Units Written\": {\n\t\t\tName:  \"Data_Units_Written\",\n\t\t\tParse: parseDataUnits,\n\t\t},\n\t\t\"Host Read Commands\": {\n\t\t\tName:  \"Host_Read_Commands\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Host Write Commands\": {\n\t\t\tName:  \"Host_Write_Commands\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Controller Busy Time\": {\n\t\t\tName:  \"Controller_Busy_Time\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Unsafe Shutdowns\": {\n\t\t\tName:  \"Unsafe_Shutdowns\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Warning  Comp. Temperature Time\": {\n\t\t\tName:  \"Warning_Temperature_Time\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Critical Comp. Temperature Time\": {\n\t\t\tName:  \"Critical_Temperature_Time\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Thermal Temp. 1 Transition Count\": {\n\t\t\tName:  \"Thermal_Management_T1_Trans_Count\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Thermal Temp. 2 Transition Count\": {\n\t\t\tName:  \"Thermal_Management_T2_Trans_Count\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Thermal Temp. 1 Total Time\": {\n\t\t\tName:  \"Thermal_Management_T1_Total_Time\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Thermal Temp. 2 Total Time\": {\n\t\t\tName:  \"Thermal_Management_T2_Total_Time\",\n\t\t\tParse: parseCommaSeparatedInt,\n\t\t},\n\t\t\"Temperature Sensor 1\": {\n\t\t\tName:  \"Temperature_Sensor_1\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 2\": {\n\t\t\tName:  \"Temperature_Sensor_2\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 3\": {\n\t\t\tName:  \"Temperature_Sensor_3\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 4\": {\n\t\t\tName:  \"Temperature_Sensor_4\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 5\": {\n\t\t\tName:  \"Temperature_Sensor_5\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 6\": {\n\t\t\tName:  \"Temperature_Sensor_6\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 7\": {\n\t\t\tName:  \"Temperature_Sensor_7\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t\t\"Temperature Sensor 8\": {\n\t\t\tName:  \"Temperature_Sensor_8\",\n\t\t\tParse: parseTemperatureSensor,\n\t\t},\n\t}\n\t// To obtain Intel specific metrics from nvme-cli version 1.14 and above.\n\tintelAttributes = map[string]struct {\n\t\tID    string\n\t\tName  string\n\t\tParse func(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error\n\t}{\n\t\t\"program_fail_count\": {\n\t\t\tName: \"Program_Fail_Count\",\n\t\t},\n\t\t\"erase_fail_count\": {\n\t\t\tName: \"Erase_Fail_Count\",\n\t\t},\n\t\t\"wear_leveling_count\": { // previously: \"wear_leveling\"\n\t\t\tName: \"Wear_Leveling_Count\",\n\t\t},\n\t\t\"e2e_error_detect_count\": { // previously: \"end_to_end_error_detection_count\"\n\t\t\tName: \"End_To_End_Error_Detection_Count\",\n\t\t},\n\t\t\"crc_error_count\": {\n\t\t\tName: \"Crc_Error_Count\",\n\t\t},\n\t\t\"media_wear_percentage\": { // previously: \"timed_workload_media_wear\"\n\t\t\tName: \"Media_Wear_Percentage\",\n\t\t},\n\t\t\"host_reads\": {\n\t\t\tName: \"Host_Reads\",\n\t\t},\n\t\t\"timed_work_load\": { // previously: \"timed_workload_timer\"\n\t\t\tName: \"Timed_Workload_Timer\",\n\t\t},\n\t\t\"thermal_throttle_status\": {\n\t\t\tName: \"Thermal_Throttle_Status\",\n\t\t},\n\t\t\"retry_buff_overflow_count\": { // previously: \"retry_buffer_overflow_count\"\n\t\t\tName: \"Retry_Buffer_Overflow_Count\",\n\t\t},\n\t\t\"pll_lock_loss_counter\": { // previously: \"pll_lock_loss_count\"\n\t\t\tName: \"Pll_Lock_Loss_Count\",\n\t\t},\n\t}\n\t// to obtain Intel specific metrics from nvme-cli\n\tintelAttributesDeprecatedFormat = map[string]struct {\n\t\tID    string\n\t\tName  string\n\t\tParse func(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error\n\t}{\n\t\t\"program_fail_count\": {\n\t\t\tName: \"Program_Fail_Count\",\n\t\t},\n\t\t\"erase_fail_count\": {\n\t\t\tName: \"Erase_Fail_Count\",\n\t\t},\n\t\t\"end_to_end_error_detection_count\": {\n\t\t\tName: \"End_To_End_Error_Detection_Count\",\n\t\t},\n\t\t\"crc_error_count\": {\n\t\t\tName: \"Crc_Error_Count\",\n\t\t},\n\t\t\"retry_buffer_overflow_count\": {\n\t\t\tName: \"Retry_Buffer_Overflow_Count\",\n\t\t},\n\t\t\"wear_leveling\": {\n\t\t\tName:  \"Wear_Leveling\",\n\t\t\tParse: parseWearLeveling,\n\t\t},\n\t\t\"timed_workload_media_wear\": {\n\t\t\tName:  \"Timed_Workload_Media_Wear\",\n\t\t\tParse: parseTimedWorkload,\n\t\t},\n\t\t\"timed_workload_host_reads\": {\n\t\t\tName:  \"Timed_Workload_Host_Reads\",\n\t\t\tParse: parseTimedWorkload,\n\t\t},\n\t\t\"timed_workload_timer\": {\n\t\t\tName: \"Timed_Workload_Timer\",\n\t\t\tParse: func(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\t\t\t\treturn parseCommaSeparatedIntWithAccumulator(acc, fields, tags, strings.TrimSuffix(str, \" min\"))\n\t\t\t},\n\t\t},\n\t\t\"thermal_throttle_status\": {\n\t\t\tName:  \"Thermal_Throttle_Status\",\n\t\t\tParse: parseThermalThrottle,\n\t\t},\n\t\t\"pll_lock_loss_count\": {\n\t\t\tName: \"Pll_Lock_Loss_Count\",\n\t\t},\n\t\t\"nand_bytes_written\": {\n\t\t\tName:  \"Nand_Bytes_Written\",\n\t\t\tParse: parseBytesWritten,\n\t\t},\n\t\t\"host_bytes_written\": {\n\t\t\tName:  \"Host_Bytes_Written\",\n\t\t\tParse: parseBytesWritten,\n\t\t},\n\t}\n\n\tknownReadMethods = []string{\"concurrent\", \"sequential\"}\n\n\t// Wrap with sudo\n\trunCmd = func(timeout config.Duration, sudo bool, command string, args ...string) ([]byte, error) {\n\t\tcmd := exec.Command(command, args...)\n\t\tif sudo {\n\t\t\tcmd = exec.Command(\"sudo\", append([]string{\"-n\", command}, args...)...)\n\t\t}\n\t\treturn internal.CombinedOutputTimeout(cmd, time.Duration(timeout))\n\t}\n)\n\nconst intelVID = \"0x8086\"\n\n// Smart plugin reads metrics from storage devices supporting S.M.A.R.T.\ntype Smart struct {\n\tPathSmartctl      string          `toml:\"path_smartctl\"`\n\tPathNVMe          string          `toml:\"path_nvme\"`\n\tNocheck           string          `toml:\"nocheck\"`\n\tEnableExtensions  []string        `toml:\"enable_extensions\"`\n\tAttributes        bool            `toml:\"attributes\"`\n\tExcludes          []string        `toml:\"excludes\"`\n\tDevices           []string        `toml:\"devices\"`\n\tUseSudo           bool            `toml:\"use_sudo\"`\n\tTagWithDeviceType bool            `toml:\"tag_with_device_type\"`\n\tTimeout           config.Duration `toml:\"timeout\"`\n\tReadMethod        string          `toml:\"read_method\"`\n\tLog               telegraf.Logger `toml:\"-\"`\n}\n\ntype nvmeDevice struct {\n\tname         string\n\tvendorID     string\n\tmodel        string\n\tserialNumber string\n}\n\nfunc (*Smart) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (m *Smart) Init() error {\n\t// if `path_smartctl` is not provided in config, try to find smartctl binary in PATH\n\tif len(m.PathSmartctl) == 0 {\n\t\t//nolint:errcheck // error handled later\n\t\tm.PathSmartctl, _ = exec.LookPath(\"smartctl\")\n\t}\n\n\t// if `path_nvme` is not provided in config, try to find nvme binary in PATH\n\tif len(m.PathNVMe) == 0 {\n\t\t//nolint:errcheck // error handled later\n\t\tm.PathNVMe, _ = exec.LookPath(\"nvme\")\n\t}\n\n\tif !contains(knownReadMethods, m.ReadMethod) {\n\t\treturn fmt.Errorf(\"provided read method %q is not valid\", m.ReadMethod)\n\t}\n\n\terr := validatePath(m.PathSmartctl)\n\tif err != nil {\n\t\tm.PathSmartctl = \"\"\n\t\t// without smartctl, plugin will not be able to gather basic metrics\n\t\treturn fmt.Errorf(\"smartctl not found: verify that smartctl is installed and it is in your PATH (or specified in config): %w\", err)\n\t}\n\n\terr = validatePath(m.PathNVMe)\n\tif err != nil {\n\t\tm.PathNVMe = \"\"\n\t\t// without nvme, plugin will not be able to gather vendor specific attributes (but it can work without it)\n\t\tm.Log.Warnf(\n\t\t\t\"nvme not found: verify that nvme is installed and it is in your PATH (or specified in config) to gather vendor specific attributes: %s\",\n\t\t\terr.Error(),\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (m *Smart) Gather(acc telegraf.Accumulator) error {\n\tvar err error\n\tvar scannedNVMeDevices []string\n\tvar scannedNonNVMeDevices []string\n\n\tdevicesFromConfig := m.Devices\n\tisNVMe := len(m.PathNVMe) != 0\n\tisVendorExtension := len(m.EnableExtensions) != 0\n\n\tif len(m.Devices) != 0 {\n\t\tm.addAttributes(acc, devicesFromConfig)\n\n\t\t// if nvme-cli is present, vendor specific attributes can be gathered\n\t\tif isVendorExtension && isNVMe {\n\t\t\tscannedNVMeDevices, _, err = m.scanAllDevices(true)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tnvmeDevices := distinguishNVMeDevices(devicesFromConfig, scannedNVMeDevices)\n\n\t\t\tm.addVendorNVMeAttributes(acc, nvmeDevices)\n\t\t}\n\t\treturn nil\n\t}\n\tscannedNVMeDevices, scannedNonNVMeDevices, err = m.scanAllDevices(false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdevicesFromScan := make([]string, 0, len(scannedNVMeDevices)+len(scannedNonNVMeDevices))\n\tdevicesFromScan = append(devicesFromScan, scannedNVMeDevices...)\n\tdevicesFromScan = append(devicesFromScan, scannedNonNVMeDevices...)\n\n\tm.addAttributes(acc, devicesFromScan)\n\tif isVendorExtension && isNVMe {\n\t\tm.addVendorNVMeAttributes(acc, scannedNVMeDevices)\n\t}\n\treturn nil\n}\n\nfunc (m *Smart) scanAllDevices(ignoreExcludes bool) (nvme, nonNvme []string, err error) {\n\t// this will return all devices (including NVMe devices) for smartctl version >= 7.0\n\t// for older versions this will return non NVMe devices\n\tdevices, err := m.scanDevices(ignoreExcludes, \"--scan\")\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// this will return only NVMe devices\n\tnvmeDevices, err := m.scanDevices(ignoreExcludes, \"--scan\", \"--device=nvme\")\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// to handle all versions of smartctl this will return only non NVMe devices\n\tnonNVMeDevices := difference(devices, nvmeDevices)\n\treturn nvmeDevices, nonNVMeDevices, nil\n}\n\nfunc distinguishNVMeDevices(userDevices, availableNVMeDevices []string) []string {\n\tvar nvmeDevices []string\n\n\tfor _, userDevice := range userDevices {\n\t\tfor _, availableNVMeDevice := range availableNVMeDevices {\n\t\t\t// double check. E.g. in case when nvme0 is equal nvme0n1, will check if \"nvme0\" part is present.\n\t\t\tif strings.Contains(availableNVMeDevice, userDevice) || strings.Contains(userDevice, availableNVMeDevice) {\n\t\t\t\tnvmeDevices = append(nvmeDevices, userDevice)\n\t\t\t}\n\t\t}\n\t}\n\treturn nvmeDevices\n}\n\n// Scan for S.M.A.R.T. devices from smartctl\nfunc (m *Smart) scanDevices(ignoreExcludes bool, scanArgs ...string) ([]string, error) {\n\tout, err := runCmd(m.Timeout, m.UseSudo, m.PathSmartctl, scanArgs...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to run command '%s %s': %w - %s\", m.PathSmartctl, scanArgs, err, string(out))\n\t}\n\tvar devices []string\n\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\tdev := strings.Split(line, \" \")\n\t\tif len(dev) <= 1 {\n\t\t\tcontinue\n\t\t}\n\t\tif !ignoreExcludes {\n\t\t\tif !excludedDev(m.Excludes, strings.TrimSpace(dev[0])) {\n\t\t\t\tdevices = append(devices, strings.TrimSpace(dev[0]))\n\t\t\t}\n\t\t} else {\n\t\t\tdevices = append(devices, strings.TrimSpace(dev[0]))\n\t\t}\n\t}\n\treturn devices, nil\n}\n\nfunc excludedDev(excludes []string, deviceLine string) bool {\n\tdevice := strings.Split(deviceLine, \" \")\n\tif len(device) != 0 {\n\t\tfor _, exclude := range excludes {\n\t\t\tif device[0] == exclude {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// Add info and attributes for each S.M.A.R.T. device\nfunc (m *Smart) addAttributes(acc telegraf.Accumulator, devices []string) {\n\tvar wg sync.WaitGroup\n\twg.Add(len(devices))\n\tfor _, device := range devices {\n\t\tswitch m.ReadMethod {\n\t\tcase \"concurrent\":\n\t\t\tgo m.gatherDisk(acc, device, &wg)\n\t\tcase \"sequential\":\n\t\t\tm.gatherDisk(acc, device, &wg)\n\t\tdefault:\n\t\t\twg.Done()\n\t\t}\n\t}\n\n\twg.Wait()\n}\n\nfunc (m *Smart) addVendorNVMeAttributes(acc telegraf.Accumulator, devices []string) {\n\tnvmeDevices := getDeviceInfoForNVMeDisks(acc, devices, m.PathNVMe, m.Timeout, m.UseSudo)\n\n\tvar wg sync.WaitGroup\n\n\tfor _, device := range nvmeDevices {\n\t\tif contains(m.EnableExtensions, \"auto-on\") {\n\t\t\t//nolint:revive // one case switch on purpose to demonstrate potential extensions\n\t\t\tswitch device.vendorID {\n\t\t\tcase intelVID:\n\t\t\t\twg.Add(1)\n\t\t\t\tswitch m.ReadMethod {\n\t\t\t\tcase \"concurrent\":\n\t\t\t\t\tgo gatherIntelNVMeDisk(acc, m.Timeout, m.UseSudo, m.PathNVMe, device, &wg)\n\t\t\t\tcase \"sequential\":\n\t\t\t\t\tgatherIntelNVMeDisk(acc, m.Timeout, m.UseSudo, m.PathNVMe, device, &wg)\n\t\t\t\tdefault:\n\t\t\t\t\twg.Done()\n\t\t\t\t}\n\t\t\t}\n\t\t} else if contains(m.EnableExtensions, \"Intel\") && device.vendorID == intelVID {\n\t\t\twg.Add(1)\n\t\t\tswitch m.ReadMethod {\n\t\t\tcase \"concurrent\":\n\t\t\t\tgo gatherIntelNVMeDisk(acc, m.Timeout, m.UseSudo, m.PathNVMe, device, &wg)\n\t\t\tcase \"sequential\":\n\t\t\t\tgatherIntelNVMeDisk(acc, m.Timeout, m.UseSudo, m.PathNVMe, device, &wg)\n\t\t\tdefault:\n\t\t\t\twg.Done()\n\t\t\t}\n\t\t}\n\t}\n\twg.Wait()\n}\n\nfunc getDeviceInfoForNVMeDisks(acc telegraf.Accumulator, devices []string, nvme string, timeout config.Duration, useSudo bool) []nvmeDevice {\n\tnvmeDevices := make([]nvmeDevice, 0, len(devices))\n\tfor _, device := range devices {\n\t\tnewDevice, err := gatherNVMeDeviceInfo(nvme, device, timeout, useSudo)\n\t\tif err != nil {\n\t\t\tacc.AddError(fmt.Errorf(\"cannot find device info for %s device\", device))\n\t\t\tcontinue\n\t\t}\n\t\tnvmeDevices = append(nvmeDevices, newDevice)\n\t}\n\treturn nvmeDevices\n}\n\nfunc gatherNVMeDeviceInfo(nvme, deviceName string, timeout config.Duration, useSudo bool) (device nvmeDevice, err error) {\n\tsplitName := strings.Split(deviceName, \" \")\n\targs := make([]string, 0, len(splitName)+1)\n\targs = append(args, \"id-ctrl\")\n\targs = append(args, splitName...)\n\n\tout, err := runCmd(timeout, useSudo, nvme, args...)\n\tif err != nil {\n\t\treturn device, err\n\t}\n\toutStr := string(out)\n\tdevice, err = findNVMeDeviceInfo(outStr)\n\tif err != nil {\n\t\treturn device, err\n\t}\n\tdevice.name = deviceName\n\treturn device, nil\n}\n\nfunc findNVMeDeviceInfo(output string) (nvmeDevice, error) {\n\tscanner := bufio.NewScanner(strings.NewReader(output))\n\tvar vid, sn, mn string\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif matches := nvmeIDCtrlExpressionPattern.FindStringSubmatch(line); len(matches) > 2 {\n\t\t\tmatches[1] = strings.TrimSpace(matches[1])\n\t\t\tmatches[2] = strings.TrimSpace(matches[2])\n\t\t\tif matches[1] == \"vid\" {\n\t\t\t\tif _, err := fmt.Sscanf(matches[2], \"%s\", &vid); err != nil {\n\t\t\t\t\treturn nvmeDevice{}, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif matches[1] == \"sn\" {\n\t\t\t\tsn = matches[2]\n\t\t\t}\n\t\t\tif matches[1] == \"mn\" {\n\t\t\t\tmn = matches[2]\n\t\t\t}\n\t\t}\n\t}\n\n\tnewDevice := nvmeDevice{\n\t\tvendorID:     vid,\n\t\tmodel:        mn,\n\t\tserialNumber: sn,\n\t}\n\treturn newDevice, nil\n}\n\nfunc gatherIntelNVMeDisk(acc telegraf.Accumulator, timeout config.Duration, usesudo bool, nvme string, device nvmeDevice, wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\n\tsplitName := strings.Split(device.name, \" \")\n\targs := make([]string, 0, len(splitName)+2)\n\targs = append(args, \"intel\", \"smart-log-add\")\n\targs = append(args, splitName...)\n\n\tout, e := runCmd(timeout, usesudo, nvme, args...)\n\toutStr := string(out)\n\n\t_, er := exitStatus(e)\n\tif er != nil {\n\t\tacc.AddError(fmt.Errorf(\"failed to run command '%s %s': %w - %s\", nvme, strings.Join(args, \" \"), e, outStr))\n\t\treturn\n\t}\n\n\tscanner := bufio.NewScanner(strings.NewReader(outStr))\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tfields := make(map[string]interface{})\n\t\ttags := map[string]string{\n\t\t\t\"device\":    path.Base(device.name),\n\t\t\t\"model\":     device.model,\n\t\t\t\"serial_no\": device.serialNumber,\n\t\t}\n\n\t\t// Create struct to initialize later with intel attributes.\n\t\tvar (\n\t\t\tattr = struct {\n\t\t\t\tID    string\n\t\t\t\tName  string\n\t\t\t\tParse func(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error\n\t\t\t}{}\n\t\t\tattrExists bool\n\t\t)\n\n\t\tif matches := intelExpressionPattern.FindStringSubmatch(line); len(matches) > 3 && len(matches[1]) > 1 {\n\t\t\t// Check if nvme shows metrics in deprecated format or in format with ID.\n\t\t\t// Based on that, an attribute map with metrics is chosen.\n\t\t\t// If string has more than one character it means it has KEY there, otherwise it's empty string (\"\").\n\t\t\tif separatedIDAndKey := nvmeIDSeparatePattern.FindStringSubmatch(matches[1]); len(strings.TrimSpace(separatedIDAndKey[2])) > 1 {\n\t\t\t\tmatches[1] = strings.TrimSpace(separatedIDAndKey[2])\n\t\t\t\tattr, attrExists = intelAttributes[matches[1]]\n\t\t\t} else {\n\t\t\t\tmatches[1] = strings.TrimSpace(matches[1])\n\t\t\t\tattr, attrExists = intelAttributesDeprecatedFormat[matches[1]]\n\t\t\t}\n\n\t\t\tmatches[3] = strings.TrimSpace(matches[3])\n\n\t\t\tif attrExists {\n\t\t\t\ttags[\"name\"] = attr.Name\n\t\t\t\tif attr.ID != \"\" {\n\t\t\t\t\ttags[\"id\"] = attr.ID\n\t\t\t\t}\n\n\t\t\t\tparse := parseCommaSeparatedIntWithAccumulator\n\t\t\t\tif attr.Parse != nil {\n\t\t\t\t\tparse = attr.Parse\n\t\t\t\t}\n\n\t\t\t\tif err := parse(acc, fields, tags, matches[3]); err != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (m *Smart) gatherDisk(acc telegraf.Accumulator, device string, wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\t// smartctl 5.41 & 5.42 have are broken regarding handling of --nocheck/-n\n\tsplitDevice := strings.Split(device, \" \")\n\targs := make([]string, 0, len(splitDevice)+7)\n\targs = append(args, \"--info\", \"--health\", \"--attributes\", \"--tolerance=verypermissive\", \"-n\", m.Nocheck, \"--format=brief\")\n\targs = append(args, splitDevice...)\n\n\tout, e := runCmd(m.Timeout, m.UseSudo, m.PathSmartctl, args...)\n\toutStr := string(out)\n\n\t// Ignore all exit statuses except if it is a command line parse error\n\tcmdExitStatus, er := exitStatus(e)\n\tif er != nil {\n\t\tacc.AddError(fmt.Errorf(\"failed to run command '%s %s': %w - %s\", m.PathSmartctl, strings.Join(args, \" \"), e, outStr))\n\t\treturn\n\t}\n\n\t// Initialize device exit status with command exit status (don't assume active or standby)\n\t// Will be adjusted based on detected power mode during parsing\n\tdeviceExitStatus := cmdExitStatus\n\n\tdeviceTags := make(map[string]string)\n\tif m.TagWithDeviceType {\n\t\tdeviceNode := strings.SplitN(device, \" \", 2)\n\t\tdeviceTags[\"device\"] = path.Base(deviceNode[0])\n\t\tif len(deviceNode) == 2 && deviceNode[1] != \"\" {\n\t\t\tdeviceTags[\"device_type\"] = strings.TrimPrefix(deviceNode[1], \"-d \")\n\t\t}\n\t} else {\n\t\tdeviceNode := strings.Split(device, \" \")[0]\n\t\tdeviceTags[\"device\"] = path.Base(deviceNode)\n\t}\n\n\tdeviceFields := make(map[string]interface{})\n\n\tscanner := bufio.NewScanner(strings.NewReader(outStr))\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tmodel := modelInfo.FindStringSubmatch(line)\n\t\tif len(model) > 2 {\n\t\t\tdeviceTags[\"model\"] = model[2]\n\t\t}\n\n\t\tserial := serialInfo.FindStringSubmatch(line)\n\t\tif len(serial) > 1 {\n\t\t\tdeviceTags[\"serial_no\"] = serial[1]\n\t\t}\n\n\t\twwn := wwnInfo.FindStringSubmatch(line)\n\t\tif len(wwn) > 1 {\n\t\t\tdeviceTags[\"wwn\"] = strings.ReplaceAll(wwn[1], \" \", \"\")\n\t\t}\n\n\t\tcapacity := userCapacityInfo.FindStringSubmatch(line)\n\t\tif len(capacity) > 1 {\n\t\t\tdeviceTags[\"capacity\"] = strings.ReplaceAll(capacity[1], \",\", \"\")\n\t\t}\n\n\t\tenabled := smartEnabledInfo.FindStringSubmatch(line)\n\t\tif len(enabled) > 1 {\n\t\t\tdeviceTags[\"enabled\"] = enabled[1]\n\t\t}\n\n\t\thealth := smartOverallHealth.FindStringSubmatch(line)\n\t\tif len(health) > 2 {\n\t\t\tdeviceFields[\"health_ok\"] = health[2] == \"PASSED\" || health[2] == \"OK\"\n\t\t}\n\n\t\t// checks to see if there is a power mode to print to user\n\t\t// if not look for Device is in STANDBY which happens when\n\t\t// nocheck is set to standby (will exit to not spin up the disk)\n\t\t// otherwise nothing is found so nothing is printed (NVMe does not show power)\n\t\tif power := powermodeInfo.FindStringSubmatch(line); len(power) > 1 {\n\t\t\tdeviceTags[\"power\"] = power[1]\n\t\t\t// Override exit status based on detected power mode\n\t\t\t// Only ACTIVE or IDLE are considered operational states (exit_status = 0)\n\t\t\t// All other states (STANDBY, SLEEPING, etc.) keep the command's exit status\n\t\t\tif power[1] == \"ACTIVE\" || power[1] == \"IDLE\" {\n\t\t\t\tdeviceExitStatus = 0\n\t\t\t}\n\t\t} else {\n\t\t\t// Check for explicit standby message\n\t\t\tif power := standbyInfo.FindStringSubmatch(line); len(power) > 1 {\n\t\t\t\tdeviceTags[\"power\"] = power[1]\n\t\t\t\t// Only set exit_status=0 for explicitly known operational states\n\t\t\t\t// Keep command's exit status for STANDBY and any other states\n\t\t\t\tif power[1] == \"ACTIVE\" || power[1] == \"IDLE\" {\n\t\t\t\t\tdeviceExitStatus = 0\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttags := make(map[string]string)\n\t\tfields := make(map[string]interface{})\n\n\t\tif m.Attributes {\n\t\t\t// add power mode\n\t\t\tkeys := [...]string{\"device\", \"device_type\", \"model\", \"serial_no\", \"wwn\", \"capacity\", \"enabled\", \"power\"}\n\t\t\tfor _, key := range keys {\n\t\t\t\tif value, ok := deviceTags[key]; ok {\n\t\t\t\t\ttags[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tattr := attribute.FindStringSubmatch(line)\n\t\tif len(attr) > 1 {\n\t\t\t// attribute has been found, add it only if m.Attributes is true\n\t\t\tif m.Attributes {\n\t\t\t\ttags[\"id\"] = attr[1]\n\t\t\t\ttags[\"name\"] = attr[2]\n\t\t\t\ttags[\"flags\"] = attr[3]\n\n\t\t\t\tfields[\"exit_status\"] = deviceExitStatus\n\t\t\t\tif i, err := strconv.ParseInt(attr[4], 10, 64); err == nil {\n\t\t\t\t\tfields[\"value\"] = i\n\t\t\t\t}\n\t\t\t\tif i, err := strconv.ParseInt(attr[5], 10, 64); err == nil {\n\t\t\t\t\tfields[\"worst\"] = i\n\t\t\t\t}\n\t\t\t\tif i, err := strconv.ParseInt(attr[6], 10, 64); err == nil {\n\t\t\t\t\tfields[\"threshold\"] = i\n\t\t\t\t}\n\n\t\t\t\ttags[\"fail\"] = attr[7]\n\t\t\t\tif val, err := parseRawValue(attr[8]); err == nil {\n\t\t\t\t\tfields[\"raw_value\"] = val\n\t\t\t\t}\n\n\t\t\t\tacc.AddFields(\"smart_attribute\", fields, tags)\n\t\t\t}\n\n\t\t\t// If the attribute matches on the one in deviceFieldIDs\n\t\t\t// save the raw value to a field.\n\t\t\tif field, ok := deviceFieldIDs[attr[1]]; ok {\n\t\t\t\tif val, err := parseRawValue(attr[8]); err == nil {\n\t\t\t\t\tdeviceFields[field] = val\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(attr) > 4 {\n\t\t\t\t// If the attribute name matches on in deviceFieldNames\n\t\t\t\t// save the value to a field\n\t\t\t\tif field, ok := deviceFieldNames[attr[2]]; ok {\n\t\t\t\t\tif val, err := parseRawValue(attr[4]); err == nil {\n\t\t\t\t\t\tdeviceFields[field] = val\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// what was found is not a vendor attribute\n\t\t\tif matches := sasNVMeAttr.FindStringSubmatch(line); len(matches) > 2 {\n\t\t\t\tif attr, ok := sasNVMeAttributes[matches[1]]; ok {\n\t\t\t\t\ttags[\"name\"] = attr.Name\n\t\t\t\t\tif attr.ID != \"\" {\n\t\t\t\t\t\ttags[\"id\"] = attr.ID\n\t\t\t\t\t}\n\n\t\t\t\t\tparse := parseCommaSeparatedInt\n\t\t\t\t\tif attr.Parse != nil {\n\t\t\t\t\t\tparse = attr.Parse\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := parse(fields, deviceFields, matches[2]); err != nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif name, found := nvmeDeviceFields[attr.Name]; found {\n\t\t\t\t\t\tif v, found := fields[\"raw_value\"]; found {\n\t\t\t\t\t\t\tdeviceFields[name] = v\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// if the field is classified as an attribute, only add it\n\t\t\t\t\t// if m.Attributes is true\n\t\t\t\t\tif m.Attributes {\n\t\t\t\t\t\tacc.AddFields(\"smart_attribute\", fields, tags)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the final device exit status\n\t// - 0 if power mode is ACTIVE or IDLE\n\t// - cmdExitStatus for STANDBY or other power states\n\t// - cmdExitStatus if no power mode was detected (backward compatibility)\n\tdeviceFields[\"exit_status\"] = deviceExitStatus\n\tacc.AddFields(\"smart_device\", deviceFields, deviceTags)\n}\n\n// Command line parse errors are denoted by the exit code having the 0 bit set.\n// All other errors are drive/communication errors and should be ignored.\nfunc exitStatus(err error) (int, error) {\n\tvar exitErr *exec.ExitError\n\tif errors.As(err, &exitErr) {\n\t\tif status, ok := exitErr.Sys().(syscall.WaitStatus); ok {\n\t\t\treturn status.ExitStatus(), nil\n\t\t}\n\t}\n\treturn 0, err\n}\n\nfunc contains(args []string, element string) bool {\n\tfor _, arg := range args {\n\t\tif arg == element {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc difference(a, b []string) []string {\n\tmb := make(map[string]struct{}, len(b))\n\tfor _, x := range b {\n\t\tmb[x] = struct{}{}\n\t}\n\tvar diff []string\n\tfor _, x := range a {\n\t\tif _, found := mb[x]; !found {\n\t\t\tdiff = append(diff, x)\n\t\t}\n\t}\n\treturn diff\n}\n\nfunc parseRawValue(rawVal string) (interface{}, error) {\n\t// Integer\n\tif i, err := strconv.ParseInt(rawVal, 10, 64); err == nil {\n\t\treturn i, nil\n\t}\n\n\t// raw attribute with two values, e.g. error rate: error_count/total_count\n\tif numerator, denominator, found := strings.Cut(rawVal, \"/\"); found {\n\t\tn, nerr := strconv.ParseFloat(numerator, 64)\n\t\td, derr := strconv.ParseFloat(denominator, 64)\n\t\tif nerr == nil && derr == nil {\n\t\t\treturn n / d, nil\n\t\t}\n\t}\n\n\t// Duration: 65h+33m+09.259s\n\tunit := regexp.MustCompile(\"^(.*)([hms])$\")\n\tparts := strings.Split(rawVal, \"+\")\n\tif len(parts) == 0 {\n\t\treturn 0, fmt.Errorf(\"couldn't parse RAW_VALUE %q\", rawVal)\n\t}\n\n\tduration := int64(0)\n\tfor _, part := range parts {\n\t\ttimePart := unit.FindStringSubmatch(part)\n\t\tif len(timePart) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch timePart[2] {\n\t\tcase \"h\":\n\t\t\tduration += parseInt(timePart[1]) * int64(3600)\n\t\tcase \"m\":\n\t\t\tduration += parseInt(timePart[1]) * int64(60)\n\t\tcase \"s\":\n\t\t\t// drop fractions of seconds\n\t\t\tduration += parseInt(strings.Split(timePart[1], \".\")[0])\n\t\tdefault:\n\t\t\t// Unknown, ignore\n\t\t}\n\t}\n\treturn duration, nil\n}\n\nfunc parseBytesWritten(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\tvar value int64\n\n\tif _, err := fmt.Sscanf(str, \"sectors: %d\", &value); err != nil {\n\t\treturn err\n\t}\n\tfields[\"raw_value\"] = value\n\tacc.AddFields(\"smart_attribute\", fields, tags)\n\treturn nil\n}\n\nfunc parseThermalThrottle(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\tvar percentage float64\n\tvar count int64\n\n\tif _, err := fmt.Sscanf(str, \"%f%%, cnt: %d\", &percentage, &count); err != nil {\n\t\treturn err\n\t}\n\n\tfields[\"raw_value\"] = percentage\n\ttags[\"name\"] = \"Thermal_Throttle_Status_Prc\"\n\tacc.AddFields(\"smart_attribute\", fields, tags)\n\n\tfields[\"raw_value\"] = count\n\ttags[\"name\"] = \"Thermal_Throttle_Status_Cnt\"\n\tacc.AddFields(\"smart_attribute\", fields, tags)\n\n\treturn nil\n}\n\nfunc parseWearLeveling(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\tvar vmin, vmax, avg int64\n\n\tif _, err := fmt.Sscanf(str, \"min: %d, max: %d, avg: %d\", &vmin, &vmax, &avg); err != nil {\n\t\treturn err\n\t}\n\tvalues := []int64{vmin, vmax, avg}\n\tfor i, submetricName := range []string{\"Min\", \"Max\", \"Avg\"} {\n\t\tfields[\"raw_value\"] = values[i]\n\t\ttags[\"name\"] = \"Wear_Leveling_\" + submetricName\n\t\tacc.AddFields(\"smart_attribute\", fields, tags)\n\t}\n\n\treturn nil\n}\n\nfunc parseTimedWorkload(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\tvar value float64\n\n\tif _, err := fmt.Sscanf(str, \"%f\", &value); err != nil {\n\t\treturn err\n\t}\n\tfields[\"raw_value\"] = value\n\tacc.AddFields(\"smart_attribute\", fields, tags)\n\treturn nil\n}\n\nfunc parseInt(str string) int64 {\n\tif i, err := strconv.ParseInt(str, 10, 64); err == nil {\n\t\treturn i\n\t}\n\treturn 0\n}\n\nfunc parseCommaSeparatedInt(fields, _ map[string]interface{}, str string) error {\n\t// remove any non-utf8 values\n\t// '1\\xa0292' --> 1292\n\tvalue := strings.ToValidUTF8(strings.Join(strings.Fields(str), \"\"), \"\")\n\n\t// remove any non-alphanumeric values\n\t// '16,626,888' --> 16626888\n\t// '16 829 004' --> 16829004\n\tnumRegex, err := regexp.Compile(`[^0-9\\-]+`)\n\tif err != nil {\n\t\treturn errors.New(\"failed to compile numeric regex\")\n\t}\n\tvalue = numRegex.ReplaceAllString(value, \"\")\n\n\ti, err := strconv.ParseInt(value, 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields[\"raw_value\"] = i\n\n\treturn nil\n}\n\nfunc parsePercentageInt(fields, deviceFields map[string]interface{}, str string) error {\n\treturn parseCommaSeparatedInt(fields, deviceFields, strings.TrimSuffix(str, \"%\"))\n}\n\nfunc parseDataUnits(fields, deviceFields map[string]interface{}, str string) error {\n\t// Remove everything after '['\n\tunits := strings.Split(str, \"[\")[0]\n\treturn parseCommaSeparatedInt(fields, deviceFields, units)\n}\n\nfunc parseCommaSeparatedIntWithAccumulator(acc telegraf.Accumulator, fields map[string]interface{}, tags map[string]string, str string) error {\n\ti, err := strconv.ParseInt(strings.ReplaceAll(str, \",\", \"\"), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfields[\"raw_value\"] = i\n\tacc.AddFields(\"smart_attribute\", fields, tags)\n\treturn nil\n}\n\nfunc parseTemperature(fields, deviceFields map[string]interface{}, str string) error {\n\tvar temp int64\n\tif _, err := fmt.Sscanf(str, \"%d C\", &temp); err != nil {\n\t\treturn err\n\t}\n\n\tfields[\"raw_value\"] = temp\n\tdeviceFields[\"temp_c\"] = temp\n\n\treturn nil\n}\n\nfunc parseTemperatureSensor(fields, _ map[string]interface{}, str string) error {\n\tvar temp int64\n\tif _, err := fmt.Sscanf(str, \"%d C\", &temp); err != nil {\n\t\treturn err\n\t}\n\n\tfields[\"raw_value\"] = temp\n\n\treturn nil\n}\n\nfunc validatePath(filePath string) error {\n\tpathInfo, err := os.Stat(filePath)\n\tif os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"provided path does not exist: [%s]\", filePath)\n\t}\n\tif mode := pathInfo.Mode(); !mode.IsRegular() {\n\t\treturn fmt.Errorf(\"provided path does not point to a regular file: [%s]\", filePath)\n\t}\n\treturn nil\n}\n\nfunc newSmart() *Smart {\n\treturn &Smart{\n\t\tTimeout:    config.Duration(time.Second * 30),\n\t\tReadMethod: \"concurrent\",\n\t}\n}\n\nfunc init() {\n\t// Set LC_NUMERIC to uniform numeric output from cli tools\n\t_ = os.Setenv(\"LC_NUMERIC\", \"en_US.UTF-8\")\n\n\tinputs.Add(\"smart\", func() telegraf.Input {\n\t\tm := newSmart()\n\t\tm.Nocheck = \"standby\"\n\t\treturn m\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/smart/smart_test.go",
    "content": "package smart\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestGatherAttributes(t *testing.T) {\n\ts := newSmart()\n\ts.Attributes = true\n\n\trequire.Equal(t, time.Second*30, time.Duration(s.Timeout))\n\n\trunCmd = func(_ config.Duration, _ bool, _ string, args ...string) ([]byte, error) {\n\t\tif len(args) > 0 {\n\t\t\tif args[0] == \"--info\" && args[7] == \"/dev/ada0\" {\n\t\t\t\treturn []byte(mockInfoAttributeData), nil\n\t\t\t} else if args[0] == \"--info\" && args[7] == \"/dev/nvme0\" {\n\t\t\t\treturn []byte(smartctlNVMeInfoData), nil\n\t\t\t} else if args[0] == \"--scan\" && len(args) == 1 {\n\t\t\t\treturn []byte(mockScanData), nil\n\t\t\t} else if args[0] == \"--scan\" && len(args) >= 2 && args[1] == \"--device=nvme\" {\n\t\t\t\treturn []byte(mockScanNVMeData), nil\n\t\t\t}\n\t\t}\n\t\treturn nil, errors.New(\"command not found\")\n\t}\n\n\tt.Run(\"Wrong path to smartctl\", func(t *testing.T) {\n\t\ts.PathSmartctl = \"this_path_to_smartctl_does_not_exist\"\n\t\terr := s.Init()\n\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"Smartctl presence\", func(t *testing.T) {\n\t\ts.PathSmartctl = \"smartctl\"\n\t\ts.PathNVMe = \"\"\n\n\t\tt.Run(\"Only non NVMe device\", func(t *testing.T) {\n\t\t\ts.Devices = []string{\"/dev/ada0\"}\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\terr := s.Gather(&acc)\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, 70, acc.NFields(), \"Wrong number of fields gathered\")\n\n\t\t\tfor _, test := range testsAda0Attributes {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"smart_attribute\", test.fields, test.tags)\n\t\t\t}\n\n\t\t\tfor _, test := range testsAda0Device {\n\t\t\t\tacc.AssertContainsTaggedFields(t, \"smart_device\", test.fields, test.tags)\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Only NVMe device\", func(t *testing.T) {\n\t\t\ts.Devices = []string{\"/dev/nvme0\"}\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\terr := s.Gather(&acc)\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, 43, acc.NFields(), \"Wrong number of fields gathered\")\n\n\t\t\ttestutil.RequireMetricsEqual(t, testSmartctlNVMeAttributes, acc.GetTelegrafMetrics(),\n\t\t\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n\t\t})\n\t})\n}\n\nfunc TestGatherInParallelMode(t *testing.T) {\n\ts := newSmart()\n\ts.Attributes = true\n\ts.PathSmartctl = \"smartctl\"\n\ts.PathNVMe = \"nvmeIdentifyController\"\n\ts.EnableExtensions = append(s.EnableExtensions, \"auto-on\")\n\ts.Devices = []string{\"/dev/nvme0\"}\n\n\trunCmd = func(_ config.Duration, _ bool, _ string, args ...string) ([]byte, error) {\n\t\tif len(args) > 0 {\n\t\t\tif args[0] == \"--info\" && args[7] == \"/dev/ada0\" {\n\t\t\t\treturn []byte(mockInfoAttributeData), nil\n\t\t\t} else if args[0] == \"--info\" && args[7] == \"/dev/nvmeIdentifyController\" {\n\t\t\t\treturn []byte(smartctlNVMeInfoData), nil\n\t\t\t} else if args[0] == \"--scan\" && len(args) == 1 {\n\t\t\t\treturn []byte(mockScanData), nil\n\t\t\t} else if args[0] == \"--scan\" && len(args) >= 2 && args[1] == \"--device=nvme\" {\n\t\t\t\treturn []byte(mockScanNVMeData), nil\n\t\t\t} else if args[0] == \"intel\" && args[1] == \"smart-log-add\" {\n\t\t\t\treturn []byte(nvmeIntelInfoDataMetricsFormat), nil\n\t\t\t} else if args[0] == \"id-ctrl\" {\n\t\t\t\treturn []byte(nvmeIdentifyController), nil\n\t\t\t}\n\t\t}\n\t\treturn nil, errors.New(\"command not found\")\n\t}\n\n\tt.Run(\"Gather NVMe device info in goroutine\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\t\ts.ReadMethod = \"concurrent\"\n\n\t\terr := s.Gather(acc)\n\t\trequire.NoError(t, err)\n\n\t\tresult := acc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, testIntelNVMeNewFormatAttributes, result,\n\t\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"Gather NVMe device info sequentially\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\t\ts.ReadMethod = \"sequential\"\n\n\t\terr := s.Gather(acc)\n\t\trequire.NoError(t, err)\n\n\t\tresult := acc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, testIntelNVMeNewFormatAttributes, result,\n\t\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n\t})\n\n\tt.Run(\"Gather NVMe device info - not known read method\", func(t *testing.T) {\n\t\tacc := &testutil.Accumulator{}\n\t\ts.ReadMethod = \"horizontally\"\n\n\t\terr := s.Init()\n\t\trequire.Error(t, err)\n\n\t\terr = s.Gather(acc)\n\t\trequire.NoError(t, err)\n\n\t\tresult := acc.GetTelegrafMetrics()\n\t\trequire.Empty(t, result)\n\t})\n}\n\nfunc TestGatherNoAttributes(t *testing.T) {\n\ts := newSmart()\n\ts.Attributes = false\n\n\trequire.Equal(t, time.Second*30, time.Duration(s.Timeout))\n\n\trunCmd = func(_ config.Duration, _ bool, _ string, args ...string) ([]byte, error) {\n\t\tif len(args) > 0 {\n\t\t\tif args[0] == \"--scan\" && len(args) == 1 {\n\t\t\t\treturn []byte(mockScanData), nil\n\t\t\t} else if args[0] == \"--info\" && args[7] == \"/dev/ada0\" {\n\t\t\t\treturn []byte(mockInfoAttributeData), nil\n\t\t\t} else if args[0] == \"--info\" && args[7] == \"/dev/nvme0\" {\n\t\t\t\treturn []byte(smartctlNVMeInfoData), nil\n\t\t\t} else if args[0] == \"--scan\" && args[1] == \"--device=nvme\" {\n\t\t\t\treturn []byte(mockScanNVMeData), nil\n\t\t\t}\n\t\t}\n\t\treturn nil, errors.New(\"command not found\")\n\t}\n\n\tt.Run(\"scan for devices\", func(t *testing.T) {\n\t\tvar acc testutil.Accumulator\n\t\ts.PathSmartctl = \"smartctl\"\n\n\t\terr := s.Gather(&acc)\n\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 24, acc.NFields(), \"Wrong number of fields gathered\")\n\t\tacc.AssertDoesNotContainMeasurement(t, \"smart_attribute\")\n\n\t\tfor _, test := range testsAda0Device {\n\t\t\tacc.AssertContainsTaggedFields(t, \"smart_device\", test.fields, test.tags)\n\t\t}\n\t\tfor _, test := range testNVMeDevice {\n\t\t\tacc.AssertContainsTaggedFields(t, \"smart_device\", test.fields, test.tags)\n\t\t}\n\t})\n}\n\nfunc TestExcludedDev(t *testing.T) {\n\trequire.True(t, excludedDev([]string{\"/dev/pass6\"}, \"/dev/pass6 -d atacam\"), \"Should be excluded.\")\n\trequire.False(t, excludedDev(make([]string, 0), \"/dev/pass6 -d atacam\"), \"Shouldn't be excluded.\")\n\trequire.False(t, excludedDev([]string{\"/dev/pass6\"}, \"/dev/pass1 -d atacam\"), \"Shouldn't be excluded.\")\n}\n\nvar (\n\tsampleSmart = Smart{\n\t\tPathSmartctl: \"\",\n\t\tNocheck:      \"\",\n\t\tAttributes:   true,\n\t\tUseSudo:      true,\n\t\tTimeout:      config.Duration(time.Second * 30),\n\t}\n)\n\nfunc TestGatherSATAInfo(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(hgstSATAInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 108, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(20), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherSATAInfo65(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(hgstSATAInfoData65), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 98, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(18), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherSATAInfo75(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(seagateSATAInfoData75), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\n\trequire.Equal(t, 135, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(25), acc.NMetrics(), \"Wrong number of metrics gathered\")\n\n\tfor _, test := range testsSeagateSATADevice {\n\t\tacc.AssertContainsTaggedFields(t, \"smart_device\", test.fields, test.tags)\n\t}\n}\n\nfunc TestGatherHgstSAS(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(hgstSASInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 6, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(4), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherHtSAS(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(htSASInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\n\ttestutil.RequireMetricsEqual(t, testHtsasAtributtes, acc.GetTelegrafMetrics(), testutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherLongFormEnduranceAttrib(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(mockHGST), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 8, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(5), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherSSD(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(ssdInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 112, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(26), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherSSDRaid(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(ssdRaidInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"\", wg)\n\trequire.Equal(t, 79, acc.NFields(), \"Wrong number of fields gathered\")\n\trequire.Equal(t, uint64(15), acc.NMetrics(), \"Wrong number of metrics gathered\")\n}\n\nfunc TestGatherDeviceTypeTag(t *testing.T) {\n\trunCmd = func(_ config.Duration, _ bool, _ string, args ...string) ([]byte, error) {\n\t\tswitch args[0] {\n\t\tcase \"--scan\":\n\t\t\treturn nil, errors.New(\"scan command should not be run, since devices are provided in config\")\n\t\tcase \"--info\":\n\t\t\tswitch args[len(args)-1] {\n\t\t\tcase \"megaraid,0\":\n\t\t\t\treturn []byte(smartctlMegaraidInfo1), nil\n\t\t\tcase \"megaraid,1\":\n\t\t\t\treturn []byte(smartctlMegaraidInfo2), nil\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unexpected device type %q\", args[len(args)-1])\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unexpected command %q\", args[0])\n\t\t}\n\t}\n\n\ts := newSmart()\n\ts.Devices = []string{\"/dev/bus/0 -d megaraid,0\", \"/dev/bus/0 -d megaraid,1\"}\n\ts.TagWithDeviceType = true\n\n\tacc := testutil.Accumulator{}\n\n\terr := s.Gather(&acc)\n\trequire.NoError(t, err)\n\trequire.NoError(t, errors.Join(acc.Errors...))\n\n\tresult := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, testSmartctlDeviceTypeTag, result, testutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherNVMe(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(smartctlNVMeInfoData), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"nvme0\", wg)\n\n\ttestutil.RequireMetricsEqual(t, testSmartctlNVMeAttributes, acc.GetTelegrafMetrics(),\n\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherNVMeWindows(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(smartctlNVMeInfoDataWindows), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\twg.Add(1)\n\tsampleSmart.gatherDisk(acc, \"nvme0\", wg)\n\n\tmetrics := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, testSmartctlNVMeWindowsAttributes, metrics,\n\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherIntelNVMeMetrics(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(nvmeIntelInfoDataMetricsFormat), nil\n\t}\n\n\tvar (\n\t\tacc    = &testutil.Accumulator{}\n\t\twg     = &sync.WaitGroup{}\n\t\tdevice = nvmeDevice{\n\t\t\tname:         \"nvme0\",\n\t\t\tmodel:        mockModel,\n\t\t\tserialNumber: mockSerial,\n\t\t}\n\t)\n\n\twg.Add(1)\n\tgatherIntelNVMeDisk(acc, config.Duration(time.Second*30), true, \"\", device, wg)\n\n\tresult := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, testIntelNVMeNewFormatAttributes, result,\n\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc TestGatherIntelNVMeDeprecatedFormatMetrics(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(nvmeIntelInfoDataDeprecatedMetricsFormat), nil\n\t}\n\n\tvar (\n\t\tacc    = &testutil.Accumulator{}\n\t\twg     = &sync.WaitGroup{}\n\t\tdevice = nvmeDevice{\n\t\t\tname:         \"nvme0\",\n\t\t\tmodel:        mockModel,\n\t\t\tserialNumber: mockSerial,\n\t\t}\n\t)\n\n\twg.Add(1)\n\tgatherIntelNVMeDisk(acc, config.Duration(time.Second*30), true, \"\", device, wg)\n\n\tresult := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, testIntelNVMeAttributes, result,\n\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n}\n\nfunc Test_findVIDFromNVMeOutput(t *testing.T) {\n\tdevice, err := findNVMeDeviceInfo(nvmeIdentifyController)\n\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"0x8086\", device.vendorID)\n\trequire.Equal(t, \"CVFT5123456789ABCD\", device.serialNumber)\n\trequire.Equal(t, \"INTEL SSDPEDABCDEFG\", device.model)\n}\n\nfunc Test_checkForNVMeDevices(t *testing.T) {\n\tdevices := []string{\"sda1\", \"nvme0\", \"sda2\", \"nvme2\"}\n\texpectedNVMeDevices := []string{\"nvme0\", \"nvme2\"}\n\tresultNVMeDevices := distinguishNVMeDevices(devices, expectedNVMeDevices)\n\trequire.Equal(t, expectedNVMeDevices, resultNVMeDevices)\n}\n\nfunc Test_contains(t *testing.T) {\n\tdevices := []string{\"/dev/sda\", \"/dev/nvme1\"}\n\tdevice := \"/dev/nvme1\"\n\tdeviceNotIncluded := \"/dev/nvme5\"\n\trequire.True(t, contains(devices, device))\n\trequire.False(t, contains(devices, deviceNotIncluded))\n}\n\nfunc Test_difference(t *testing.T) {\n\tdevices := []string{\"/dev/sda\", \"/dev/nvme1\", \"/dev/nvme2\"}\n\tsecondDevices := []string{\"/dev/sda\", \"/dev/nvme1\"}\n\texpected := []string{\"/dev/nvme2\"}\n\tresult := difference(devices, secondDevices)\n\trequire.Equal(t, expected, result)\n}\n\n// mockExitError creates an exec.ExitError with the given exit status.\n// This uses the test binary itself to generate a real ExitError, avoiding platform-specific\n// shell commands.\nfunc mockExitError(exitStatus int) error {\n\texe, err := os.Executable()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get executable: %w\", err)\n\t}\n\n\tcmd := exec.Command(exe, \"-test.run=^$\", fmt.Sprintf(\"-exit-status=%d\", exitStatus))\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd.Run()\n}\n\nfunc TestExitStatusForActiveVsStandbyDrives(t *testing.T) {\n\ts := newSmart()\n\ts.Attributes = true\n\ts.PathSmartctl = \"smartctl\"\n\ts.Nocheck = \"standby\"\n\n\trunCmd = func(_ config.Duration, _ bool, _ string, args ...string) ([]byte, error) {\n\t\tdeviceArg := args[len(args)-1]\n\n\t\tif deviceArg == \"/dev/sdb\" {\n\t\t\t// Active drive - smartctl exits with 2 but drive shows as ACTIVE\n\t\t\treturn []byte(`Device Model: ST18000NT001-3NF101\nPower mode is: ACTIVE or IDLE\nSMART overall-health self-assessment test result: PASSED`), mockExitError(2)\n\t\t} else if deviceArg == \"/dev/sdc\" {\n\t\t\t// Standby drive - smartctl exits with 2 and drive shows as STANDBY\n\t\t\treturn []byte(mockStandbyData), mockExitError(2)\n\t\t}\n\t\treturn nil, errors.New(\"unexpected device\")\n\t}\n\n\tt.Run(\"Exit status should reflect drive state not command exit code\", func(t *testing.T) {\n\t\ts.Devices = []string{\"/dev/sdb\", \"/dev/sdc\"}\n\t\tvar acc testutil.Accumulator\n\n\t\terr := s.Gather(&acc)\n\t\trequire.NoError(t, err)\n\n\t\tdeviceMetrics := acc.GetTelegrafMetrics()\n\n\t\tfor _, metric := range deviceMetrics {\n\t\t\tif metric.Name() == \"smart_device\" {\n\t\t\t\tdevice, _ := metric.GetTag(\"device\")\n\t\t\t\texitStatus, ok := metric.GetField(\"exit_status\")\n\t\t\t\trequire.True(t, ok, \"exit_status field should exist\")\n\n\t\t\t\tif device == \"sdb\" {\n\t\t\t\t\t// Active drive should have exit_status=0 regardless of command exit code\n\t\t\t\t\trequire.Equal(t, int64(0), exitStatus, \"Active drive should have exit_status=0\")\n\t\t\t\t} else if device == \"sdc\" {\n\t\t\t\t\t// Standby drive should have exit_status=2\n\t\t\t\t\trequire.Equal(t, int64(2), exitStatus, \"Standby drive should have exit_status=2\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_integerOverflow(t *testing.T) {\n\trunCmd = func(config.Duration, bool, string, ...string) ([]byte, error) {\n\t\treturn []byte(smartctlNVMeInfoDataWithOverflow), nil\n\t}\n\n\tvar (\n\t\tacc = &testutil.Accumulator{}\n\t\twg  = &sync.WaitGroup{}\n\t)\n\n\tt.Run(\"If data raw_value is out of int64 range, there should be no metrics for that attribute\", func(t *testing.T) {\n\t\twg.Add(1)\n\n\t\tsampleSmart.gatherDisk(acc, \"nvme0\", wg)\n\n\t\tresult := acc.GetTelegrafMetrics()\n\t\ttestutil.RequireMetricsEqual(t, testOverflowAttributes, result,\n\t\t\ttestutil.SortMetrics(), testutil.IgnoreTime())\n\t})\n}\n\nvar (\n\ttestOverflowAttributes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"nvme0\",\n\t\t\t\t\"name\":   \"Temperature_Sensor_3\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(9223372036854775807),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"nvme0\",\n\t\t\t\t\"name\":   \"Temperature_Sensor_4\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(-9223372036854775808),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\": \"nvme0\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\": 0,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestHtsasAtributtes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \".\",\n\t\t\t\t\"serial_no\": \"PDWAR9GE\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"id\":        \"194\",\n\t\t\t\t\"model\":     \"HUC103030CSS600\",\n\t\t\t\t\"name\":      \"Temperature_Celsius\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 36,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \".\",\n\t\t\t\t\"serial_no\": \"PDWAR9GE\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"id\":        \"4\",\n\t\t\t\t\"model\":     \"HUC103030CSS600\",\n\t\t\t\t\"name\":      \"Start_Stop_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 47,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \".\",\n\t\t\t\t\"serial_no\": \"PDWAR9GE\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"model\":     \"HUC103030CSS600\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\": 0,\n\t\t\t\t\"health_ok\":   true,\n\t\t\t\t\"temp_c\":      36,\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestsAda0Attributes = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(200),\n\t\t\t\t\"worst\":       int64(200),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(0),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"1\",\n\t\t\t\t\"name\":      \"Raw_Read_Error_Rate\",\n\t\t\t\t\"flags\":     \"-O-RC-\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(100),\n\t\t\t\t\"worst\":       int64(100),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(0),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"5\",\n\t\t\t\t\"name\":      \"Reallocated_Sector_Ct\",\n\t\t\t\t\"flags\":     \"PO--CK\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(99),\n\t\t\t\t\"worst\":       int64(99),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(2988),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"9\",\n\t\t\t\t\"name\":      \"Power_On_Hours\",\n\t\t\t\t\"flags\":     \"-O--CK\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(85),\n\t\t\t\t\"worst\":       int64(85),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(14879),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"12\",\n\t\t\t\t\"name\":      \"Power_Cycle_Count\",\n\t\t\t\t\"flags\":     \"-O--CK\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(253),\n\t\t\t\t\"worst\":       int64(253),\n\t\t\t\t\"threshold\":   int64(10),\n\t\t\t\t\"raw_value\":   int64(2044932921600),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"169\",\n\t\t\t\t\"name\":      \"Unknown_Attribute\",\n\t\t\t\t\"flags\":     \"PO--C-\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(185),\n\t\t\t\t\"worst\":       int64(185),\n\t\t\t\t\"threshold\":   int64(100),\n\t\t\t\t\"raw_value\":   int64(957808640337),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"173\",\n\t\t\t\t\"name\":      \"Wear_Leveling_Count\",\n\t\t\t\t\"flags\":     \"-O--CK\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(55),\n\t\t\t\t\"worst\":       int64(40),\n\t\t\t\t\"threshold\":   int64(45),\n\t\t\t\t\"raw_value\":   int64(45),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"190\",\n\t\t\t\t\"name\":      \"Airflow_Temperature_Cel\",\n\t\t\t\t\"flags\":     \"-O---K\",\n\t\t\t\t\"fail\":      \"Past\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(97),\n\t\t\t\t\"worst\":       int64(97),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(14716),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"192\",\n\t\t\t\t\"name\":      \"Power-Off_Retract_Count\",\n\t\t\t\t\"flags\":     \"-O--C-\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(66),\n\t\t\t\t\"worst\":       int64(21),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(34),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"194\",\n\t\t\t\t\"name\":      \"Temperature_Celsius\",\n\t\t\t\t\"flags\":     \"-O---K\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(100),\n\t\t\t\t\"worst\":       int64(100),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(0),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"197\",\n\t\t\t\t\"name\":      \"Current_Pending_Sector\",\n\t\t\t\t\"flags\":     \"-O---K\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(200),\n\t\t\t\t\"worst\":       int64(200),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(0),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"199\",\n\t\t\t\t\"name\":      \"UDMA_CRC_Error_Count\",\n\t\t\t\t\"flags\":     \"-O-RC-\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"value\":       int64(100),\n\t\t\t\t\"worst\":       int64(253),\n\t\t\t\t\"threshold\":   int64(0),\n\t\t\t\t\"raw_value\":   int64(23709323),\n\t\t\t\t\"exit_status\": int(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t\t\"id\":        \"240\",\n\t\t\t\t\"name\":      \"Head_Flying_Hours\",\n\t\t\t\t\"flags\":     \"------\",\n\t\t\t\t\"fail\":      \"-\",\n\t\t\t},\n\t\t},\n\t}\n\n\tmockModel  = \"INTEL SSDPEDABCDEFG\"\n\tmockSerial = \"CVFT5123456789ABCD\"\n\n\ttestSmartctlDeviceTypeTag = []telegraf.Metric{\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"capacity\":    \"600000000000\",\n\t\t\t\t\"device\":      \"0\",\n\t\t\t\t\"device_type\": \"megaraid,0\",\n\t\t\t\t\"enabled\":     \"Enabled\",\n\t\t\t\t\"model\":       \"ST3450857SS\",\n\t\t\t\t\"power\":       \"ACTIVE\",\n\t\t\t\t\"serial_no\":   \"xxx\",\n\t\t\t},\n\t\t\tmap[string]any{\n\t\t\t\t\"exit_status\": int64(0),\n\t\t\t\t\"health_ok\":   true,\n\t\t\t\t\"temp_c\":      int64(37),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t\ttestutil.MustMetric(\n\t\t\t\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"capacity\":    \"600000000000\",\n\t\t\t\t\"device\":      \"0\",\n\t\t\t\t\"device_type\": \"megaraid,1\",\n\t\t\t\t\"enabled\":     \"Enabled\",\n\t\t\t\t\"model\":       \"ST3450857SS\",\n\t\t\t\t\"power\":       \"ACTIVE\",\n\t\t\t\t\"serial_no\":   \"xxx\",\n\t\t\t},\n\t\t\tmap[string]any{\n\t\t\t\t\"exit_status\": int64(0),\n\t\t\t\t\"health_ok\":   true,\n\t\t\t\t\"temp_c\":      int64(47),\n\t\t\t},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\ttestSmartctlNVMeAttributes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\":               0,\n\t\t\t\t\"health_ok\":                 true,\n\t\t\t\t\"temp_c\":                    38,\n\t\t\t\t\"power_on_hours\":            int64(6038),\n\t\t\t\t\"power_cycle_count\":         int64(472),\n\t\t\t\t\"unsafe_shutdowns\":          int64(355),\n\t\t\t\t\"available_spare\":           int64(100),\n\t\t\t\t\"available_spare_threshold\": int64(10),\n\t\t\t\t\"percentage_used\":           int64(16),\n\t\t\t\t\"critical_warning\":          int64(9),\n\t\t\t\t\"media_errors\":              int64(0),\n\t\t\t\t\"error_log_entries\":         int64(119699),\n\t\t\t\t\"warning_temperature_time\":  int64(11),\n\t\t\t\t\"critical_temperature_time\": int64(7),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"9\",\n\t\t\t\t\"name\":      \"Power_On_Hours\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 6038,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"12\",\n\t\t\t\t\"name\":      \"Power_Cycle_Count\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 472,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Media_and_Data_Integrity_Errors\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Error_Information_Log_Entries\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 119699,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Available_Spare\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 100,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Available_Spare_Threshold\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 10,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"194\",\n\t\t\t\t\"name\":      \"Temperature_Celsius\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 38,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Critical_Warning\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(9),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Percentage_Used\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(16),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Data_Units_Read\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(11836935),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Data_Units_Written\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(62288091),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Host_Read_Commands\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(135924188),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Host_Write_Commands\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(7715573429),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Controller_Busy_Time\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(4042),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Unsafe_Shutdowns\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(355),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Warning_Temperature_Time\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(11),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Critical_Temperature_Time\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(7),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t), testutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(57),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(50),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_3\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(44),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_4\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(43),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_5\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(57),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_6\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(50),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_7\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(44),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_8\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(43),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Thermal_Management_T1_Trans_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Thermal_Management_T2_Trans_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Thermal_Management_T1_Total_Time\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"name\":      \"Thermal_Management_T2_Total_Time\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\ttestSmartctlNVMeWindowsAttributes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"smart_device\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\":               0,\n\t\t\t\t\"health_ok\":                 true,\n\t\t\t\t\"temp_c\":                    47,\n\t\t\t\t\"power_on_hours\":            int64(1290),\n\t\t\t\t\"power_cycle_count\":         int64(10779),\n\t\t\t\t\"unsafe_shutdowns\":          int64(9),\n\t\t\t\t\"available_spare\":           int64(100),\n\t\t\t\t\"available_spare_threshold\": int64(10),\n\t\t\t\t\"percentage_used\":           int64(0),\n\t\t\t\t\"critical_warning\":          int64(0),\n\t\t\t\t\"media_errors\":              int64(0),\n\t\t\t\t\"error_log_entries\":         int64(979),\n\t\t\t\t\"warning_temperature_time\":  int64(0),\n\t\t\t\t\"critical_temperature_time\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"9\",\n\t\t\t\t\"name\":      \"Power_On_Hours\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 1290,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t\t\"name\":      \"Unsafe_Shutdowns\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 9,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"12\",\n\t\t\t\t\"name\":      \"Power_Cycle_Count\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 10779,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Media_and_Data_Integrity_Errors\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Error_Information_Log_Entries\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 979,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Available_Spare\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 100,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Available_Spare_Threshold\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 10,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"id\":        \"194\",\n\t\t\t\t\"name\":      \"Temperature_Celsius\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 47,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Critical_Warning\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Percentage_Used\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Data_Units_Read\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(16626888),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Data_Units_Written\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(16829004),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Host_Read_Commands\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(205868508),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Host_Write_Commands\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(228472943),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Controller_Busy_Time\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(686),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"name\":      \"Critical_Temperature_Time\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_1\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(47),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t\t\"name\":      \"Temperature_Sensor_2\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(68),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": \"xxx\",\n\t\t\t\t\"model\":     \"Samsung SSD 970 EVO 1TB\",\n\t\t\t\t\"name\":      \"Warning_Temperature_Time\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\ttestsAda0Device = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\":               int(0),\n\t\t\t\t\"health_ok\":                 bool(true),\n\t\t\t\t\"read_error_rate\":           int64(0),\n\t\t\t\t\"temp_c\":                    int64(34),\n\t\t\t\t\"udma_crc_errors\":           int64(0),\n\t\t\t\t\"wear_leveling_count\":       int64(185),\n\t\t\t\t\"pending_sector_count\":      int64(0),\n\t\t\t\t\"reallocated_sectors_count\": int64(0),\n\t\t\t\t\"power_cycle_count\":         int64(14879),\n\t\t\t\t\"power_on_hours\":            int64(2988),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"ada0\",\n\t\t\t\t\"model\":     \"APPLE SSD SM256E\",\n\t\t\t\t\"serial_no\": \"S0X5NZBC422720\",\n\t\t\t\t\"wwn\":       \"5002538043584d30\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"capacity\":  \"251000193024\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttestsSeagateSATADevice = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"command_timeout\":            int64(0),\n\t\t\t\t\"end_to_end_error\":           int64(0),\n\t\t\t\t\"exit_status\":                int(0),\n\t\t\t\t\"health_ok\":                  bool(true),\n\t\t\t\t\"pending_sector_count\":       int64(0),\n\t\t\t\t\"power_cycle_count\":          int64(2202),\n\t\t\t\t\"power_on_hours\":             int64(28379),\n\t\t\t\t\"read_error_rate\":            float64(0.00020959964875192315),\n\t\t\t\t\"reallocated_sectors_count\":  int64(0),\n\t\t\t\t\"seek_error_rate\":            float64(0.0015386461875674382),\n\t\t\t\t\"spin_retry_count\":           int64(0),\n\t\t\t\t\"temp_c\":                     int64(33),\n\t\t\t\t\"udma_crc_errors\":            int64(0),\n\t\t\t\t\"uncorrectable_errors\":       int64(8),\n\t\t\t\t\"uncorrectable_sector_count\": int64(0),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"capacity\":  \"2000398934016\",\n\t\t\t\t\"device\":    \".\",\n\t\t\t\t\"enabled\":   \"Enabled\",\n\t\t\t\t\"model\":     \"ST2000DM006-2DM164\",\n\t\t\t\t\"power\":     \"ACTIVE\",\n\t\t\t\t\"serial_no\": \"XXXXXXXX\",\n\t\t\t\t\"wwn\":       \"XXXXXXXX\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttestNVMeDevice = []struct {\n\t\tfields map[string]interface{}\n\t\ttags   map[string]string\n\t}{\n\t\t{\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"exit_status\":               int(0),\n\t\t\t\t\"temp_c\":                    int64(38),\n\t\t\t\t\"health_ok\":                 true,\n\t\t\t\t\"power_on_hours\":            int64(6038),\n\t\t\t\t\"power_cycle_count\":         int64(472),\n\t\t\t\t\"unsafe_shutdowns\":          int64(355),\n\t\t\t\t\"available_spare\":           int64(100),\n\t\t\t\t\"available_spare_threshold\": int64(10),\n\t\t\t\t\"percentage_used\":           int64(16),\n\t\t\t\t\"critical_warning\":          int64(9),\n\t\t\t\t\"media_errors\":              int64(0),\n\t\t\t\t\"error_log_entries\":         int64(119699),\n\t\t\t\t\"warning_temperature_time\":  int64(11),\n\t\t\t\t\"critical_temperature_time\": int64(7),\n\t\t\t},\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"model\":     \"TS128GMTE850\",\n\t\t\t\t\"serial_no\": \"D704940282?\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttestIntelNVMeAttributes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Program_Fail_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Erase_Fail_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"End_To_End_Error_Detection_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Crc_Error_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 13,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Retry_Buffer_Overflow_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Wear_Leveling_Min\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 39,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Wear_Leveling_Max\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 40,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Wear_Leveling_Avg\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 39,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Timed_Workload_Media_Wear\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": float64(0.13),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Timed_Workload_Host_Reads\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": float64(71),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Timed_Workload_Timer\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(1612952),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Thermal_Throttle_Status_Prc\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": float64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Thermal_Throttle_Status_Cnt\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Pll_Lock_Loss_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Nand_Bytes_Written\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Host_Bytes_Written\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(0),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\n\ttestIntelNVMeNewFormatAttributes = []telegraf.Metric{\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Program_Fail_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Erase_Fail_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Wear_Leveling_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(700090417315),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"End_To_End_Error_Detection_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Crc_Error_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 13,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Media_Wear_Percentage\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 552,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Host_Reads\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 73,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Timed_Workload_Timer\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": int64(2343038),\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Thermal_Throttle_Status\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Retry_Buffer_Overflow_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t\ttestutil.MustMetric(\"smart_attribute\",\n\t\t\tmap[string]string{\n\t\t\t\t\"device\":    \"nvme0\",\n\t\t\t\t\"serial_no\": mockSerial,\n\t\t\t\t\"model\":     mockModel,\n\t\t\t\t\"name\":      \"Pll_Lock_Loss_Count\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"raw_value\": 0,\n\t\t\t},\n\t\t\ttime.Now(),\n\t\t),\n\t}\n\t// smartctl --scan\n\tmockScanData = `/dev/ada0 -d atacam # /dev/ada0, ATA device`\n\n\t// smartctl --scan -d nvme\n\tmockScanNVMeData = `/dev/nvme0 -d nvme # /dev/nvme0, NVMe device`\n\n\t// smartctl --info --health --attributes --tolerance=verypermissive -n standby --format=brief [DEVICE]\n\tmockInfoAttributeData = `smartctl 6.5 2016-05-07 r4318 [Darwin 16.4.0 x86_64] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\nCHECK POWER MODE not implemented, ignoring -n option\n=== START OF INFORMATION SECTION ===\nModel Family:     Apple SD/SM/TS...E/F SSDs\nDevice Model:     APPLE SSD SM256E\nSerial Number:    S0X5NZBC422720\nLU WWN Device Id: 5 002538 043584d30\nFirmware Version: CXM09A1Q\nUser Capacity:    251,000,193,024 bytes [251 GB]\nSector Sizes:     512 bytes logical, 4096 bytes physical\nRotation Rate:    Solid State Device\nDevice is:        In smartctl database [for details use: -P show]\nATA Version is:   ATA8-ACS T13/1699-D revision 4c\nSATA Version is:  SATA 3.0, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Thu Feb  9 16:48:45 2017 CET\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\n\n=== START OF READ SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\n=== START OF READ SMART DATA SECTION ===\nSMART Attributes Data Structure revision number: 1\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n  1 Raw_Read_Error_Rate     -O-RC-   200   200   000    -    0\n  5 Reallocated_Sector_Ct   PO--CK   100   100   000    -    0\n  9 Power_On_Hours          -O--CK   099   099   000    -    2988\n 12 Power_Cycle_Count       -O--CK   085   085   000    -    14879\n169 Unknown_Attribute       PO--C-   253   253   010    -    2044932921600\n173 Wear_Leveling_Count     -O--CK   185   185   100    -    957808640337\n190 Airflow_Temperature_Cel -O---K   055   040   045    Past 45 (Min/Max 43/57 #2689)\n192 Power-Off_Retract_Count -O--C-   097   097   000    -    14716\n194 Temperature_Celsius     -O---K   066   021   000    -    34 (Min/Max 14/79)\n197 Current_Pending_Sector  -O---K   100   100   000    -    0\n199 UDMA_CRC_Error_Count    -O-RC-   200   200   000    -    0\n240 Head_Flying_Hours       ------   100   253   000    -    6585h+55m+23.234s\n                            ||||||_ K auto-keep\n                            |||||__ C event count\n                            ||||___ R error rate\n                            |||____ S speed/performance\n                            ||_____ O updated online\n                            |______ P prefailure warning\n`\n\n\tmockHGST = `\nsmartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.9.0-3-amd64] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nVendor:               HGST\nProduct:              HUSMM1640ASS200\nRevision:             A360\nCompliance:           SPC-4\nUser Capacity:        400,088,457,216 bytes [400 GB]\nLogical block size:   512 bytes\nPhysical block size:  4096 bytes\nLU is resource provisioned, LBPRZ=1\nRotation Rate:        Solid State Device\nForm Factor:          2.5 inches\nLogical Unit id:      0x5000cca04ec26364\nSerial number:        ZZZZZZZZZ\nDevice type:          disk\nTransport protocol:   SAS (SPL-3)\nLocal Time is:        Mon Nov  6 10:20:33 2017 CET\nSMART support is:     Available - device has SMART capability.\nSMART support is:     Enabled\nTemperature Warning:  Enabled\nRead Cache is:        Enabled\nWriteback Cache is:   Enabled\n\n=== START OF READ SMART DATA SECTION ===\nSMART Health Status: OK\n\nPercentage used endurance indicator: 0%\nCurrent Drive Temperature:     28 C\nDrive Trip Temperature:        70 C\n\nManufactured in week 30 of year 2017\nSpecified cycle count over device lifetime:  0\nAccumulated start-stop cycles:  0\nSpecified load-unload count over device lifetime:  0\nAccumulated load-unload cycles:  0\ndefect list format 6 unknown\nElements in grown defect list: 0\n\nVendor (Seagate) cache information\n  Blocks sent to initiator = 3400674574336\n\n`\n\n\thtSASInfoData = `smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.18-12-pve] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smar$montools.org\n\n=== START OF INFORMATION SECTION ===\nVendor:               HITACHI\nProduct:              HUC103030CSS600\nRevision:             J350\nCompliance:           SPC-4\nUser Capacity:        300,$00,000,000 bytes [300 GB]\nLogical block size:   512 bytes\nRotation Rate:        10020 rpm\nForm Factor:          2.5 inches\nLogical Unit id:      0x5000cca00a4bdbc8\nSerial number:        PDWAR9GE\nDevicetype:          disk\nTransport protocol:   SAS (SPL-3)\nLocal Time is:        Wed Apr 17 15:01:28 2019 PDT\nSMART support is:     Available - device has SMART capability.\nSMART support is:     Enabled\nTemperature Warning:  Disabled or Not Supported\n\n=== START OF READ SMART DATA SECTION ===\nSMART Health Status: OK\n\nCurrent Drive Temperature:     36 C\nDrive Trip Temperature:        85 C\n\nManufactured in $eek 52 of year 2009\nSpecified cycle count over device lifetime:  50000\nAccumulated start-stop cycles:  47\nElements in grown defect list: 0\n\nVendor (Seagate) cache information\n\tBlocks sent to initiator= 7270983270400000\n`\n\n\thgstSASInfoData = `smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.0-46-generic] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nVendor:               HGST\nProduct:              HUH721212AL5204\nRevision:             C3Q1\nCompliance:           SPC-4\nUser Capacity:        12,000,138,625,024 bytes [12.0 TB]\nLogical block size:   512 bytes\nPhysical block size:  4096 bytes\nLU is fully provisioned\nRotation Rate:        7200 rpm\nForm Factor:          3.5 inches\nLogical Unit id:      0x5000cca27076bfe8\nSerial number:        8HJ39K3H\nDevice type:          disk\nTransport protocol:   SAS (SPL-3)\nLocal Time is:        Thu Apr 18 13:25:03 2019 MSK\nSMART support is:     Available - device has SMART capability.\nSMART support is:     Enabled\nTemperature Warning:  Enabled\n\n=== START OF READ SMART DATA SECTION ===\nSMART Health Status: OK\n\nCurrent Drive Temperature:     34 C\nDrive Trip Temperature:        85 C\n\nManufactured in week 35 of year 2018\nSpecified cycle count over device lifetime:  50000\nAccumulated start-stop cycles:  7\nSpecified load-unload count over device lifetime:  600000\nAccumulated load-unload cycles:  39\nElements in grown defect list: 0\n\nVendor (Seagate) cache information\n  Blocks sent to initiator = 544135446528\n`\n\n\thgstSATAInfoData = `smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.0-46-generic] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nModel Family:     Hitachi/HGST Travelstar Z7K500\nDevice Model:     HGST HTE725050A7E630\nSerial Number:    RCE50G20G81S9S\nLU WWN Device Id: 5 000cca 90bc3a98b\nFirmware Version: GS2OA3E0\nUser Capacity:    500,107,862,016 bytes [500 GB]\nSector Sizes:     512 bytes logical, 4096 bytes physical\nRotation Rate:    7200 rpm\nForm Factor:      2.5 inches\nDevice is:        In smartctl database [for details use: -P show]\nATA Version is:   ATA8-ACS T13/1699-D revision 6\nSATA Version is:  SATA 2.6, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Thu Apr 18 13:27:51 2019 MSK\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\nPower mode is:    ACTIVE or IDLE\n\n=== START OF READ SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART Attributes Data Structure revision number: 16\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n  1 Raw_Read_Error_Rate     PO-R--   100   100   062    -    0\n  2 Throughput_Performance  P-S---   100   100   040    -    0\n  3 Spin_Up_Time            POS---   100   100   033    -    1\n  4 Start_Stop_Count        -O--C-   100   100   000    -    4\n  5 Reallocated_Sector_Ct   PO--CK   100   100   005    -    0\n  7 Seek_Error_Rate         PO-R--   100   100   067    -    0\n  8 Seek_Time_Performance   P-S---   100   100   040    -    0\n  9 Power_On_Hours          -O--C-   099   099   000    -    743\n 10 Spin_Retry_Count        PO--C-   100   100   060    -    0\n 12 Power_Cycle_Count       -O--CK   100   100   000    -    4\n191 G-Sense_Error_Rate      -O-R--   100   100   000    -    0\n192 Power-Off_Retract_Count -O--CK   100   100   000    -    2\n193 Load_Cycle_Count        -O--C-   100   100   000    -    13\n194 Temperature_Celsius     -O----   250   250   000    -    24 (Min/Max 15/29)\n196 Reallocated_Event_Count -O--CK   100   100   000    -    0\n197 Current_Pending_Sector  -O---K   100   100   000    -    0\n198 Offline_Uncorrectable   ---R--   100   100   000    -    0\n199 UDMA_CRC_Error_Count    -O-R--   200   200   000    -    0\n223 Load_Retry_Count        -O-R--   100   100   000    -    0\n                            ||||||_ K auto-keep\n                            |||||__ C event count\n                            ||||___ R error rate\n                            |||____ S speed/performance\n                            ||_____ O updated online\n                            |______ P prefailure warning\n`\n\n\thgstSATAInfoData65 = `smartctl 6.5 2016-01-24 r4214 [x86_64-linux-4.4.0-145-generic] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nModel Family:     HGST Deskstar NAS\nDevice Model:     HGST HDN724040ALE640\nSerial Number:    PK1334PEK49SBS\nLU WWN Device Id: 5 000cca 250ec3c9c\nFirmware Version: MJAOA5E0\nUser Capacity:    4,000,787,030,016 bytes [4.00 TB]\nSector Sizes:     512 bytes logical, 4096 bytes physical\nRotation Rate:    7200 rpm\nForm Factor:      3.5 inches\nDevice is:        In smartctl database [for details use: -P show]\nATA Version is:   ATA8-ACS T13/1699-D revision 4\nSATA Version is:  SATA 3.0, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Wed Apr 17 15:14:27 2019 PDT\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\nPower mode is:    ACTIVE or IDLE\n\n=== START OF READ SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART Attributes Data Structure revision number: 16\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n  1 Raw_Read_Error_Rate     PO-R--   100   100   016    -    0\n  2 Throughput_Performance  P-S---   135   135   054    -    84\n  3 Spin_Up_Time            POS---   125   125   024    -    621 (Average 619)\n  4 Start_Stop_Count        -O--C-   100   100   000    -    33\n  5 Reallocated_Sector_Ct   PO--CK   100   100   005    -    0\n  7 Seek_Error_Rate         PO-R--   100   100   067    -    0\n  8 Seek_Time_Performance   P-S---   119   119   020    -    35\n  9 Power_On_Hours          -O--C-   098   098   000    -    19371\n 10 Spin_Retry_Count        PO--C-   100   100   060    -    0\n 12 Power_Cycle_Count       -O--CK   100   100   000    -    33\n192 Power-Off_Retract_Count -O--CK   100   100   000    -    764\n193 Load_Cycle_Count        -O--C-   100   100   000    -    764\n194 Temperature_Celsius     -O----   176   176   000    -    34 (Min/Max 21/53)\n196 Reallocated_Event_Count -O--CK   100   100   000    -    0\n197 Current_Pending_Sector  -O---K   100   100   000    -    0\n198 Offline_Uncorrectable   ---R--   100   100   000    -    0\n199 UDMA_CRC_Error_Count    -O-R--   200   200   000    -    0\n                            ||||||_ K auto-keep\n                            |||||__ C event count\n                            ||||___ R error rate\n                            |||____ S speed/performance\n                            ||_____ O updated online\n                            |______ P prefailure warning\n`\n\n\tseagateSATAInfoData75 = `smartctl 7.5 2025-04-30 r5714 [x86_64-linux-6.16.4-arch1-1] (local build)\nCopyright (C) 2002-25, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nModel Family:     Seagate BarraCuda 3.5 (CMR)\nDevice Model:     ST2000DM006-2DM164\nSerial Number:    XXXXXXXX\nLU WWN Device Id: XXXXXXXX\nFirmware Version: XXXXXXXX\nUser Capacity:    2,000,398,934,016 bytes [2.00 TB]\nSector Sizes:     512 bytes logical, 4096 bytes physical\nRotation Rate:    7200 rpm\nForm Factor:      3.5 inches\nDevice is:        In smartctl database\nATA Version is:   ACS-2, ACS-3 T13/2161-D revision 3b\nSATA Version is:  SATA 3.1, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Sun Aug 31 13:47:37 2025 IST\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\nPower mode is:    ACTIVE or IDLE\n\n=== START OF READ SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART Attributes Data Structure revision number: 10\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n  1 Raw_Read_Error_Rate     POSR--   107   099   006    -    2765/13191816\n  3 Spin_Up_Time            PO----   096   095   000    -    0\n  4 Start_Stop_Count        -O--CK   098   098   020    -    2195\n  5 Reallocated_Sector_Ct   PO--CK   100   100   010    -    0\n  7 Seek_Error_Rate         POSR--   074   060   030    -    38895/25278716\n  9 Power_On_Hours          -O--CK   068   068   000    -    28379\n 10 Spin_Retry_Count        PO--C-   100   100   097    -    0\n 12 Power_Cycle_Count       -O--CK   098   098   020    -    2202\n183 Runtime_Bad_Block       -O--CK   100   100   000    -    0\n184 End-to-End_Error        -O--CK   100   100   099    -    0\n187 Reported_Uncorrect      -O--CK   092   092   000    -    8\n188 Command_Timeout         -O--CK   100   099   000    -    0 0 1\n189 High_Fly_Writes         -O-RCK   097   097   000    -    3\n190 Airflow_Temperature_Cel -O---K   067   057   045    -    33 (Min/Max 24/34)\n191 G-Sense_Error_Rate      -O--CK   100   100   000    -    0\n192 Power-Off_Retract_Count -O--CK   100   100   000    -    130\n193 Load_Cycle_Count        -O--CK   001   001   000    -    837543\n194 Temperature_Celsius     -O---K   033   043   000    -    33 (0 20 0 0 0)\n197 Current_Pending_Sector  -O--C-   100   100   000    -    0\n198 Offline_Uncorrectable   ----C-   100   100   000    -    0\n199 UDMA_CRC_Error_Count    -OSRCK   200   200   000    -    0\n240 Head_Flying_Hours       ------   100   253   000    -    25597h+17m+05.460s\n241 Total_LBAs_Written      ------   100   253   000    -    69019629695\n242 Total_LBAs_Read         ------   100   253   000    -    11937226159010\n                            ||||||_ K auto-keep\n                            |||||__ C event count\n                            ||||___ R error rate\n                            |||____ S speed/performance\n                            ||_____ O updated online\n                            |______ P prefailure warning\n\n`\n\n\tssdInfoData = `smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.0-33-generic] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nDevice Model:     SanDisk Ultra II 240GB\nSerial Number:    XXXXXXXX\nLU WWN Device Id: XXXXXXXX\nFirmware Version: XXXXXXX\nUser Capacity:    240.057.409.536 bytes [240 GB]\nSector Size:      512 bytes logical/physical\nRotation Rate:    Solid State Device\nForm Factor:      2.5 inches\nDevice is:        Not in smartctl database [for details use: -P showall]\nATA Version is:   ACS-2 T13/2015-D revision 3\nSATA Version is:  SATA 3.2, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Mon Sep 17 13:22:19 2018 CEST\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\nPower mode is:    ACTIVE or IDLE\n\n=== START OF READ SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART Attributes Data Structure revision number: 4\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n  5 Reallocated_Sector_Ct   -O--CK   100   100   ---    -    0\n  9 Power_On_Hours          -O--CK   100   100   ---    -    6383\n 12 Power_Cycle_Count       -O--CK   100   100   ---    -    19\n165 Unknown_Attribute       -O--CK   100   100   ---    -    59310806\n166 Unknown_Attribute       -O--CK   100   100   ---    -    1\n167 Unknown_Attribute       -O--CK   100   100   ---    -    57\n168 Unknown_Attribute       -O--CK   100   100   ---    -    43\n169 Unknown_Attribute       -O--CK   100   100   ---    -    221\n170 Unknown_Attribute       -O--CK   100   100   ---    -    0\n171 Unknown_Attribute       -O--CK   100   100   ---    -    0\n172 Unknown_Attribute       -O--CK   100   100   ---    -    0\n173 Unknown_Attribute       -O--CK   100   100   ---    -    13\n174 Unknown_Attribute       -O--CK   100   100   ---    -    4\n184 End-to-End_Error        -O--CK   100   100   ---    -    0\n187 Reported_Uncorrect      -O--CK   100   100   ---    -    0\n188 Command_Timeout         -O--CK   100   100   ---    -    0\n194 Temperature_Celsius     -O---K   066   065   ---    -    34 (Min/Max 19/65)\n199 UDMA_CRC_Error_Count    -O--CK   100   100   ---    -    0\n230 Unknown_SSD_Attribute   -O--CK   100   100   ---    -    2229110374919\n232 Available_Reservd_Space PO--CK   100   100   004    -    100\n233 Media_Wearout_Indicator -O--CK   100   100   ---    -    3129\n234 Unknown_Attribute       -O--CK   100   100   ---    -    7444\n241 Total_LBAs_Written      ----CK   253   253   ---    -    4812\n242 Total_LBAs_Read         ----CK   253   253   ---    -    671\n244 Unknown_Attribute       -O--CK   000   100   ---    -    0\n                            ||||||_ K auto-keep\n                            |||||__ C event count\n                            ||||___ R error rate\n                            |||____ S speed/performance\n                            ||_____ O updated online\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t|______ P prefailure warning\n`\n\tssdRaidInfoData = `smartctl 6.6 2017-11-05 r4594 [FreeBSD 11.1-RELEASE-p13 amd64] (local build)\nCopyright (C) 2002-17, Bruce Allen, Christian Franke, www.smartmontools.org\n\nCHECK POWER MODE: incomplete response, ATA output registers missing\nCHECK POWER MODE not implemented, ignoring -n option\n=== START OF INFORMATION SECTION ===\nModel Family:     Samsung based SSDs\nDevice Model:     Samsung SSD 850 PRO 256GB\nSerial Number:    S251NX0H869353L\nLU WWN Device Id: 5 002538 84027f72f\nFirmware Version: EXM02B6Q\nUser Capacity:    256 060 514 304 bytes [256 GB]\nSector Size:      512 bytes logical/physical\nRotation Rate:    Solid State Device\nDevice is:        In smartctl database [for details use: -P show]\nATA Version is:   ACS-2, ATA8-ACS T13/1699-D revision 4c\nSATA Version is:  SATA 3.1, 6.0 Gb/s (current: 6.0 Gb/s)\nLocal Time is:    Fri Sep 21 17:49:16 2018 CEST\nSMART support is: Available - device has SMART capability.\nSMART support is: Enabled\n\n=== START OF READ SMART DATA SECTION ===\nSMART Status not supported: Incomplete response, ATA output registers missing\nSMART overall-health self-assessment test result: PASSED\nWarning: This result is based on an Attribute check.\n\nGeneral SMART Values:\nOffline data collection status:  (0x00)\tOffline data collection activity\n\t\t\t\t\twas never started.\n\t\t\t\t\tAuto Offline Data Collection: Disabled.\nSelf-test execution status:      (   0)\tThe previous self-test routine completed\n\t\t\t\t\twithout error or no self-test has ever\n\t\t\t\t\tbeen run.\nTotal time to complete Offline\ndata collection: \t\t(    0) seconds.\nOffline data collection\ncapabilities: \t\t\t (0x53) SMART execute Offline immediate.\n\t\t\t\t\tAuto Offline data collection on/off support.\n\t\t\t\t\tSuspend Offline collection upon new\n\t\t\t\t\tcommand.\n\t\t\t\t\tNo Offline surface scan supported.\n\t\t\t\t\tSelf-test supported.\n\t\t\t\t\tNo Conveyance Self-test supported.\n\t\t\t\t\tSelective Self-test supported.\nSMART capabilities:            (0x0003)\tSaves SMART data before entering\n\t\t\t\t\tpower-saving mode.\n\t\t\t\t\tSupports SMART auto save timer.\nError logging capability:        (0x01)\tError logging supported.\n\t\t\t\t\tGeneral Purpose Logging supported.\nShort self-test routine\nrecommended polling time: \t (   2) minutes.\nExtended self-test routine\nrecommended polling time: \t ( 136) minutes.\nSCT capabilities: \t       (0x003d)\tSCT Status supported.\n\t\t\t\t\tSCT Error Recovery Control supported.\n\t\t\t\t\tSCT Feature Control supported.\n\t\t\t\t\tSCT Data Table supported.\n\nSMART Attributes Data Structure revision number: 1\nVendor Specific SMART Attributes with Thresholds:\nID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n\t5 Reallocated_Sector_Ct   PO--CK   099   099   010    -    1\n\t9 Power_On_Hours          -O--CK   094   094   000    -    26732\n\t12 Power_Cycle_Count       -O--CK   099   099   000    -    51\n177 Wear_Leveling_Count     PO--C-   001   001   000    -    7282\n179 Used_Rsvd_Blk_Cnt_Tot   PO--C-   099   099   010    -    1\n181 Program_Fail_Cnt_Total  -O--CK   100   100   010    -    0\n182 Erase_Fail_Count_Total  -O--CK   099   099   010    -    1\n183 Runtime_Bad_Block       PO--C-   099   099   010    -    1\n187 Uncorrectable_Error_Cnt -O--CK   100   100   000    -    0\n190 Airflow_Temperature_Cel -O--CK   081   069   000    -    19\n195 ECC_Error_Rate          -O-RC-   200   200   000    -    0\n199 CRC_Error_Count         -OSRCK   100   100   000    -    0\n235 POR_Recovery_Count      -O--C-   099   099   000    -    50\n241 Total_LBAs_Written      -O--CK   099   099   000    -    61956393677\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t||||||_ K auto-keep\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t|||||__ C event count\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t||||___ R error rate\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t|||____ S speed/performance\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t||_____ O updated online\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t|______ P prefailure warning\n\nSMART Error Log Version: 1\nNo Errors Logged\n\nSMART Self-test log structure revision number 1\nNum  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error\n# 1  Short offline       Completed without error       00%     26717         -\n# 2  Short offline       Completed without error       00%     26693         -\n# 3  Short offline       Completed without error       00%     26669         -\n# 4  Short offline       Completed without error       00%     26645         -\n# 5  Short offline       Completed without error       00%     26621         -\n# 6  Short offline       Completed without error       00%     26596         -\n# 7  Extended offline    Completed without error       00%     26574         -\n# 8  Short offline       Completed without error       00%     26572         -\n# 9  Short offline       Completed without error       00%     26548         -\n#10  Short offline       Completed without error       00%     26524         -\n#11  Short offline       Completed without error       00%     26500         -\n#12  Short offline       Completed without error       00%     26476         -\n#13  Short offline       Completed without error       00%     26452         -\n#14  Short offline       Completed without error       00%     26428         -\n#15  Extended offline    Completed without error       00%     26406         -\n#16  Short offline       Completed without error       00%     26404         -\n#17  Short offline       Completed without error       00%     26380         -\n#18  Short offline       Completed without error       00%     26356         -\n#19  Short offline       Completed without error       00%     26332         -\n#20  Short offline       Completed without error       00%     26308         -\n\nSMART Selective self-test log data structure revision number 1\n\tSPAN  MIN_LBA  MAX_LBA  CURRENT_TEST_STATUS\n\t\t1        0        0  Not_testing\n\t\t2        0        0  Not_testing\n\t\t3        0        0  Not_testing\n\t\t4        0        0  Not_testing\n\t\t5        0        0  Not_testing\nSelective self-test flags (0x0):\n\tAfter scanning selected spans, do NOT read-scan remainder of disk.\nIf Selective self-test is pending on power-up, resume after 0 minute delay.\n`\n\n\tsmartctlMegaraidInfo1 = `smartctl 7.3 2022-02-28 r5338 [x86_64-linux-6.2.16-12-pve] (local build)\nCopyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nVendor:               SEAGATE\nProduct:              ST3450857SS\nRevision:             ES12\nCompliance:           SPC-3\nUser Capacity:        600,000,000,000 bytes [600 GB]\nLogical block size:   512 bytes\nRotation Rate:        15000 rpm\nForm Factor:          3.5 inches\nLogical Unit id:      0x6000c60641d10397\nSerial number:        xxx\nDevice type:          disk\nTransport protocol:   SAS (SPL-4)\nLocal Time is:        Fri Jan 12 11:43:49 2024 CET\nSMART support is:     Available - device has SMART capability.\nSMART support is:     Enabled\nTemperature Warning:  Disabled or Not Supported\nPower mode is:        ACTIVE\n\n=== START OF READ SMART DATA SECTION ===\nSMART Health Status: OK\n\nCurrent Drive Temperature:     37 C\nDrive Trip Temperature:        63 C\n\nAccumulated power on time, hours:minutes 16003:18\nElements in grown defect list: 0\n\nVendor (Seagate Cache) information\n  Blocks sent to initiator = 3000000000\n  Blocks received from initiator = 3000000000\n  Blocks read from cache and sent to initiator = 3000000000\n  Number of read and write commands whose size <= segment size = 3000000000\n  Number of read and write commands whose size > segment size = 300\n\nVendor (Seagate/Hitachi) factory information\n  number of hours powered up = 30000.30\n  number of minutes until next internal SMART test = 7\n`\n\n\tsmartctlMegaraidInfo2 = `smartctl 7.3 2022-02-28 r5338 [x86_64-linux-6.2.16-12-pve] (local build)\nCopyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nVendor:               SEAGATE\nProduct:              ST3450857SS\nRevision:             ES12\nCompliance:           SPC-3\nUser Capacity:        600,000,000,000 bytes [600 GB]\nLogical block size:   512 bytes\nRotation Rate:        15000 rpm\nForm Factor:          3.5 inches\nLogical Unit id:      0x6000c60641d10497\nSerial number:        xxx\nDevice type:          disk\nTransport protocol:   SAS (SPL-4)\nLocal Time is:        Fri Jan 12 11:44:49 2024 CET\nSMART support is:     Available - device has SMART capability.\nSMART support is:     Enabled\nTemperature Warning:  Disabled or Not Supported\nPower mode is:        ACTIVE\n\n=== START OF READ SMART DATA SECTION ===\nSMART Health Status: OK\n\nCurrent Drive Temperature:     47 C\nDrive Trip Temperature:        64 C\n\nAccumulated power on time, hours:minutes 16004:18\nElements in grown defect list: 0\n\nVendor (Seagate Cache) information\n  Blocks sent to initiator = 4000000000\n  Blocks received from initiator = 4000000000\n  Blocks read from cache and sent to initiator = 4000000000\n  Number of read and write commands whose size <= segment size = 4000000000\n  Number of read and write commands whose size > segment size = 400\n\nVendor (Seagate/Hitachi) factory information\n  number of hours powered up = 30000.30\n  number of minutes until next internal SMART test = 7\n`\n\n\tsmartctlNVMeInfoData = `smartctl 6.5 2016-05-07 r4318 [x86_64-linux-4.1.27-gvt-yocto-standard] (local build)\nCopyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nModel Number: TS128GMTE850\nSerial Number: D704940282?\nFirmware Version: C2.3.13\nPCI Vendor/Subsystem ID: 0x126f\nIEEE OUI Identifier: 0x000000\nController ID: 1\nNumber of Namespaces: 1\nNamespace 1 Size/Capacity: 128,035,676,160 [128 GB]\nNamespace 1 Formatted LBA Size: 512\nLocal Time is: Fri Jun 15 11:41:35 2018 UTC\n\n=== START OF SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART/Health Information (NVMe Log 0x02, NSID 0xffffffff)\nCritical Warning: 0x09\nTemperature: 38 Celsius\nAvailable Spare: 100%\nAvailable Spare Threshold: 10%\nPercentage Used: 16%\nData Units Read: 11,836,935 [6.06 TB]\nData Units Written: 62,288,091 [31.8 TB]\nHost Read Commands: 135,924,188\nHost Write Commands: 7,715,573,429\nController Busy Time: 4,042\nPower Cycles: 472\nPower On Hours: 6,038\nUnsafe Shutdowns: 355\nMedia and Data Integrity Errors: 0\nError Information Log Entries: 119,699\nWarning  Comp. Temperature Time: 11\nCritical Comp. Temperature Time: 7\nThermal Temp. 1 Transition Count: 0\nThermal Temp. 2 Transition Count: 0\nThermal Temp. 1 Total Time: 0\nThermal Temp. 2 Total Time: 0\nTemperature Sensor 1: 57 C\nTemperature Sensor 2: 50 C\nTemperature Sensor 3: 44 C\nTemperature Sensor 4: 43 C\nTemperature Sensor 5: 57 C\nTemperature Sensor 6: 50 C\nTemperature Sensor 7: 44 C\nTemperature Sensor 8: 43 C\n`\n\n\tsmartctlNVMeInfoDataWindows = `smartctl 7.3 2022-02-28 r5338 [x86_64-w64-mingw32-w10-20H2] (sf-7.3-1)\nCopyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org\n\n=== START OF INFORMATION SECTION ===\nModel Number:                       Samsung SSD 970 EVO 1TB\nSerial Number:                      xxx\nFirmware Version:                   2B2QEXE7\nPCI Vendor/Subsystem ID:            0x144d\nIEEE OUI Identifier:                0x002538\nTotal NVM Capacity:                 1 000 204 886 016 [1,00 TB]\nUnallocated NVM Capacity:           0\nController ID:                      4\nNVMe Version:                       1.3\nNumber of Namespaces:               1\nNamespace 1 Size/Capacity:          1 000 204 886 016 [1,00 TB]\nNamespace 1 Utilization:            732 789 374 976 [732 GB]\nNamespace 1 Formatted LBA Size:     512\nNamespace 1 IEEE EUI-64:            002538 590141cfa4\nLocal Time is:                      Wed Mar 30 13:30:12 2022\nFirmware Updates (0x16):            3 Slots, no Reset required\nOptional Admin Commands (0x0017):   Security Format Frmw_DL Self_Test\nOptional NVM Commands (0x005f):     Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp\nLog Page Attributes (0x03):         S/H_per_NS Cmd_Eff_Lg\nMaximum Data Transfer Size:         512 Pages\nWarning  Comp. Temp. Threshold:     85 Celsius\nCritical Comp. Temp. Threshold:     85 Celsius\n\nSupported Power States\nSt Op     Max   Active     Idle   RL RT WL WT  Ent_Lat  Ex_Lat\n\t0 +     6.20W       -        -    0  0  0  0        0       0\n\t1 +     4.30W       -        -    1  1  1  1        0       0\n\t2 +     2.10W       -        -    2  2  2  2        0       0\n\t3 -   0.0400W       -        -    3  3  3  3      210    1200\n\t4 -   0.0050W       -        -    4  4  4  4     2000    8000\n\nSupported LBA Sizes (NSID 0x1)\nId Fmt  Data  Metadt  Rel_Perf\n\t0 +     512       0         0\n\n=== START OF SMART DATA SECTION ===\nSMART overall-health self-assessment test result: PASSED\n\nSMART/Health Information (NVMe Log 0x02)\nCritical Warning:                   0x00\nTemperature:                        47 Celsius\nAvailable Spare:                    100%\nAvailable Spare Threshold:          10%\nPercentage Used:                    0%\nData Units Read:                    16,626,888 [8,51 TB]\nData Units Written:                 16 829 004 [8,61 TB]\nHost Read Commands:                 205 868 508\nHost Write Commands:                228 472 943\nController Busy Time:               686\nPower Cycles:                       10�779\nPower On Hours:                     1�290\nUnsafe Shutdowns:                   9\nMedia and Data Integrity Errors:    0\nError Information Log Entries:      979\nWarning  Comp. Temperature Time:    0\nCritical Comp. Temperature Time:    0\nTemperature Sensor 1:               47 Celsius\nTemperature Sensor 2:               68 Celsius\n\nError Information (NVMe Log 0x01, 16 of 64 entries)\nNum   ErrCount  SQId   CmdId  Status  PELoc          LBA  NSID    VS\n\t0        979     0  0x002a  0x4212  0x028            0     -     -\n`\n\n\tsmartctlNVMeInfoDataWithOverflow = `\nTemperature Sensor 1: 9223372036854775808 C\nTemperature Sensor 2: -9223372036854775809 C\nTemperature Sensor 3: 9223372036854775807 C\nTemperature Sensor 4: -9223372036854775808 C\n`\n\n\tnvmeIntelInfoDataDeprecatedMetricsFormat = `Additional Smart Log for NVME device:nvme0 namespace-id:ffffffff\nkey                               normalized raw\nprogram_fail_count              : 100%       0\nerase_fail_count                : 100%       0\nwear_leveling                   : 100%       min: 39, max: 40, avg: 39\nend_to_end_error_detection_count: 100%       0\ncrc_error_count                 : 100%       13\ntimed_workload_media_wear       : 100%       0.130%\ntimed_workload_host_reads       : 100%       71%\ntimed_workload_timer            : 100%       1612952 min\nthermal_throttle_status         : 100%       0%, cnt: 0\nretry_buffer_overflow_count     : 100%       0\npll_lock_loss_count             : 100%       0\nnand_bytes_written              :   0%       sectors: 0\nhost_bytes_written              :   0%       sectors: 0\n`\n\tnvmeIntelInfoDataMetricsFormat = `Additional Smart Log for NVME device:nvme0n1 namespace-id:ffffffff\nID             KEY                                 Normalized     Raw\n0xab    program_fail_count                             100         0\n0xac    erase_fail_count                               100         0\n0xad    wear_leveling_count                            100         700090417315\n0xb8    e2e_error_detect_count                         100         0\n0xc7    crc_error_count                                100         13\n0xe2    media_wear_percentage                          100         552\n0xe3    host_reads                                     100         73\n0xe4    timed_work_load                                100         2343038\n0xea    thermal_throttle_status                        100         0\n0xf0    retry_buff_overflow_count                      100         0\n0xf3    pll_lock_loss_counter                          100         0\n`\n\n\tnvmeIdentifyController = `NVME Identify Controller:\nvid     : 0x8086\nssvid   : 0x8086\nsn      : CVFT5123456789ABCD\nmn      : INTEL SSDPEDABCDEFG\nfr      : 8DV10131\nrab     : 0\nieee    : 5cd2e4\ncmic    : 0\nmdts    : 5\ncntlid  : 0\nver     : 0\nrtd3r   : 0\nrtd3e   : 0\n<<<<<<< HEAD\noaes    : 0\nctratt  : 0\noacs    : 0x6\nacl     : 3\naerl    : 3\nfrmw    : 0x2\nlpa     : 0\nelpe    : 63\nnpss    : 0\navscc   : 0\napsta   : 0\nwctemp  : 0\ncctemp  : 0\nmtfa    : 0\nhmpre   : 0\nhmmin   : 0\ntnvmcap : 0\nunvmcap : 0\nrpmbs   : 0\nedstt   : 0\ndsto    : 0\nfwug    : 0\nkas     : 0\nhctma   : 0\nmntmt   : 0\nmxtmt   : 0\nsanicap : 0\nhmminds : 0\nhmmaxd  : 0\nsqes    : 0x66\ncqes    : 0x44\nmaxcmd  : 0\nnn      : 1\noncs    : 0x6\nfuses   : 0\nfna     : 0x7\nvwc     : 0\nawun    : 0\nawupf   : 0\nnvscc   : 0\nacwu    : 0\nsgls    : 0\nsubnqn  :\nioccsz  : 0\niorcsz  : 0\nicdoff  : 0\nctrattr : 0\nmsdbd   : 0\nps    0 : mp:25.00W operational enlat:0 exlat:0 rrt:0 rrl:0\n          rwt:0 rwl:0 idle_power:- active_power:-\n`\n\t// Mock data for standby drive\n\tmockStandbyData = `smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.12.24-Unraid] (local build)\nCopyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org\n\nDevice is in STANDBY mode, exit(2)\n`\n)\n\n// TestMain handles the test helper process for mockExitError.\n// This allows us to generate proper exec.ExitError instances with specific exit codes\n// using the test binary itself, which works cross-platform (unlike shell-specific commands).\nfunc TestMain(m *testing.M) {\n\tvar exitStatusFlag int\n\tflag.IntVar(&exitStatusFlag, \"exit-status\", 0, \"exit status for test helper\")\n\tflag.Parse()\n\n\t// If this is being run as a helper process, exit with the requested status\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") == \"1\" {\n\t\tos.Exit(exitStatusFlag)\n\t}\n\n\t// Otherwise, run the tests normally\n\tos.Exit(m.Run())\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/README.md",
    "content": "# smartctl JSON Input Plugin\n\nThis plugin collects [Self-Monitoring, Analysis and Reporting Technology][smart]\ninformation for storage devices information using the\n[`smartmontools`][smartmon] package. Contrary to the\n[smart plugin][smart_plugin], this plugin does not use the [`nvme-cli`][nvmecli]\npackage to collect additional information about NVMe devices.\n\n> [!NOTE]\n> This plugin requires [`smartmontools`][smartmon] to be installed on your\n> system. The `smartctl` command must to be executable by Telegraf and must\n> supporting JSON output. JSON output was added in v7.0 and improved in\n> subsequent releases\n\n⭐ Telegraf v1.31.0\n🏷️ hardware, system\n💻 all\n\n[smart]: https://en.wikipedia.org/wiki/Self-Monitoring,_Analysis_and_Reporting_Technology\n[smart_plugin]: /plugins/inputs/smart/README.md\n[nvmecli]: https://github.com/linux-nvme/nvme-cli\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from SMART storage devices using smartclt's JSON output\n[[inputs.smartctl]]\n    ## Optionally specify the path to the smartctl executable\n    # path = \"/usr/sbin/smartctl\"\n\n    ## Use sudo\n    ## On most platforms used, smartctl requires root access. Setting 'use_sudo'\n    ## to true will make use of sudo to run smartctl. Sudo must be configured to\n    ## allow the telegraf user to run smartctl without a password.\n    # use_sudo = false\n\n    ## Devices to include or exclude\n    ## By default, the plugin will use all devices found in the output of\n    ## `smartctl --scan-open`. Only one option is allowed at a time. If set, include\n    ## sets the specific devices to scan, while exclude omits specific devices.\n    # devices_include = []\n    # devices_exclude = []\n\n    ## Skip checking disks in specified power mode\n    ## Defaults to \"standby\" to not wake up disks that have stopped rotating.\n    ## For full details on the options here, see the --nocheck section in the\n    ## smartctl man page. Choose from:\n    ##   * never: always check the device\n    ##   * sleep: check the device unless it is in sleep mode\n    ##   * standby: check the device unless it is in sleep or standby mode\n    ##   * idle: check the device unless it is in sleep, standby, or idle mode\n    # nocheck = \"standby\"\n\n    ## Timeout for the cli command to complete\n    # timeout = \"30s\"\n```\n\n### Permissions\n\nIt is important to note that this plugin references `smartctl`, which may\nrequire additional permissions to execute successfully.  Depending on the\nuser/group permissions of the telegraf user executing this plugin, users may\nneed to use sudo.\n\nUsers need the following in the Telegraf config:\n\n```toml\n[[inputs.smart_json]]\n  use_sudo = true\n```\n\nAnd to update the `/etc/sudoers` file to allow running smartctl:\n\n```bash\n$ visudo\n# Add the following lines:\nCmnd_Alias SMARTCTL = /usr/sbin/smartctl\ntelegraf  ALL=(ALL) NOPASSWD: SMARTCTL\nDefaults!SMARTCTL !logfile, !syslog, !pam_session\n```\n\n## Troubleshooting\n\nThis plugin uses the following commands to determine devices and collect\nmetrics:\n\n- `smartctl --json --scan-open`\n- `smartctl --json --all $DEVICE --device $TYPE --nocheck=$NOCHECK`\n\nPlease include the output of the above two commands for all devices that are\nhaving issues.\n\n## Metrics\n\n- smartctl\n  - tags\n    - model (model name of the storage device)\n    - name (device id in the system)\n    - serial (serial number of the device)\n    - type (device type like SATA etc)\n    - wwn (world wide number of the device)\n  - fields\n    - depending on the device information\n\n- smartctl_attributes\n  - tags\n    - model (model name of the storage device)\n    - name (name of the attribute)\n    - serial (serial number of the device)\n    - type (device type like SATA etc)\n    - wwn (world wide number of the device)\n  - fields\n    - raw_value (integer)\n    - threshold (integer)\n    - value (integer)\n    - worst (integer)\n\n## Example Output\n\n```text\nsmartctl,model=SanDisk\\ pSSD,name=/dev/sda,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c capacity=15693664256i,firmware=\"3\",health_ok=true,logical_block_size=512i,power_on_hours=11i,temperature=0i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Reallocated_Sector_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Power_On_Hours,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=11i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Power_Cycle_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=223i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Program_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Erase_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Avg_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=3i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Unexpect_Power_Loss_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=114i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Reported_Uncorrect,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Avail_Resrvd_Space,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=5i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Write/Erase_Ct_BC,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Total_LBAs_Written,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10171055i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Total_LBAs_Read,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=94845144i,threshold=0i,value=100i,worst=100i 1711480345675066854\n```\n"
  },
  {
    "path": "plugins/inputs/smartctl/sample.conf",
    "content": "# Read metrics from SMART storage devices using smartclt's JSON output\n[[inputs.smartctl]]\n    ## Optionally specify the path to the smartctl executable\n    # path = \"/usr/sbin/smartctl\"\n\n    ## Use sudo\n    ## On most platforms used, smartctl requires root access. Setting 'use_sudo'\n    ## to true will make use of sudo to run smartctl. Sudo must be configured to\n    ## allow the telegraf user to run smartctl without a password.\n    # use_sudo = false\n\n    ## Devices to include or exclude\n    ## By default, the plugin will use all devices found in the output of\n    ## `smartctl --scan-open`. Only one option is allowed at a time. If set, include\n    ## sets the specific devices to scan, while exclude omits specific devices.\n    # devices_include = []\n    # devices_exclude = []\n\n    ## Skip checking disks in specified power mode\n    ## Defaults to \"standby\" to not wake up disks that have stopped rotating.\n    ## For full details on the options here, see the --nocheck section in the\n    ## smartctl man page. Choose from:\n    ##   * never: always check the device\n    ##   * sleep: check the device unless it is in sleep mode\n    ##   * standby: check the device unless it is in sleep or standby mode\n    ##   * idle: check the device unless it is in sleep, standby, or idle mode\n    # nocheck = \"standby\"\n\n    ## Timeout for the cli command to complete\n    # timeout = \"30s\"\n"
  },
  {
    "path": "plugins/inputs/smartctl/smartctl.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage smartctl\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\n// execCommand is used to mock commands in tests.\nvar execCommand = exec.Command\n\ntype Smartctl struct {\n\tPath           string          `toml:\"path\"`\n\tNoCheck        string          `toml:\"no_check\"`\n\tUseSudo        bool            `toml:\"use_sudo\"`\n\tTimeout        config.Duration `toml:\"timeout\"`\n\tDevicesInclude []string        `toml:\"devices_include\"`\n\tDevicesExclude []string        `toml:\"devices_exclude\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\n\tdeviceFilter filter.Filter\n}\n\nfunc (*Smartctl) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Smartctl) Init() error {\n\tif s.Path == \"\" {\n\t\ts.Path = \"/usr/sbin/smartctl\"\n\t}\n\n\tswitch s.NoCheck {\n\tcase \"never\", \"sleep\", \"standby\", \"idle\":\n\tcase \"\":\n\t\ts.NoCheck = \"standby\"\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid no_check value: %s\", s.NoCheck)\n\t}\n\n\tif s.Timeout == 0 {\n\t\ts.Timeout = config.Duration(time.Second * 30)\n\t}\n\n\tif len(s.DevicesInclude) != 0 && len(s.DevicesExclude) != 0 {\n\t\treturn errors.New(\"cannot specify both devices_include and devices_exclude\")\n\t}\n\n\tvar err error\n\ts.deviceFilter, err = filter.NewIncludeExcludeFilter(s.DevicesInclude, s.DevicesExclude)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Smartctl) Gather(acc telegraf.Accumulator) error {\n\tdevices, err := s.scan()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error while scanning system: %w\", err)\n\t}\n\n\tfor _, device := range devices {\n\t\tif err := s.scanDevice(acc, device.Name, device.Type); err != nil {\n\t\t\treturn fmt.Errorf(\"error while getting device %s: %w\", device, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\t// Set LC_NUMERIC to uniform numeric output from cli tools\n\t_ = os.Setenv(\"LC_NUMERIC\", \"en_US.UTF-8\")\n\tinputs.Add(\"smartctl\", func() telegraf.Input {\n\t\treturn &Smartctl{\n\t\t\tTimeout: config.Duration(time.Second * 30),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/smartctl_device.go",
    "content": "package smartctl\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\nfunc (s *Smartctl) scanDevice(acc telegraf.Accumulator, deviceName, deviceType string) error {\n\targs := []string{\"--json\", \"--all\", deviceName, \"--device\", deviceType, \"--nocheck=\" + s.NoCheck}\n\tcmd := execCommand(s.Path, args...)\n\tif s.UseSudo {\n\t\tcmd = execCommand(\"sudo\", append([]string{\"-n\", s.Path}, args...)...)\n\t}\n\n\tvar device smartctlDeviceJSON\n\tout, err := internal.CombinedOutputTimeout(cmd, time.Duration(s.Timeout))\n\tif err != nil {\n\t\t// Error running the command and unable to parse the JSON, then bail\n\t\tif jsonErr := json.Unmarshal(out, &device); jsonErr != nil {\n\t\t\treturn fmt.Errorf(\"error running smartctl with %s: %w\", args, err)\n\t\t}\n\n\t\t// If we were able to parse the result, then only exit if we get an error\n\t\t// as sometimes we can get warnings, that still produce data.\n\t\tif len(device.Smartctl.Messages) > 0 &&\n\t\t\tdevice.Smartctl.Messages[0].Severity == \"error\" &&\n\t\t\tdevice.Smartctl.Messages[0].String != \"\" {\n\t\t\treturn fmt.Errorf(\"error running smartctl with %s got smartctl error message: %s\", args, device.Smartctl.Messages[0].String)\n\t\t}\n\t}\n\n\tif err := json.Unmarshal(out, &device); err != nil {\n\t\treturn fmt.Errorf(\"error unable to unmarshall response %s: %w\", args, err)\n\t}\n\n\tt := time.Now()\n\n\ttags := map[string]string{\n\t\t\"name\":   device.Device.Name,\n\t\t\"type\":   device.Device.Type,\n\t\t\"serial\": device.SerialNumber,\n\t}\n\n\tif device.ModelName != \"\" {\n\t\ttags[\"model\"] = device.ModelName\n\t}\n\tif device.Vendor != \"\" {\n\t\ttags[\"vendor\"] = device.Vendor\n\t}\n\n\t// The JSON WWN is in decimal and needs to be converted to hex\n\tif device.Wwn.ID != 0 && device.Wwn.Naa != 0 && device.Wwn.Oui != 0 {\n\t\ttags[\"wwn\"] = fmt.Sprintf(\"%01x%06x%09x\", device.Wwn.Naa, device.Wwn.Oui, device.Wwn.ID)\n\t}\n\n\tfields := map[string]interface{}{\n\t\t\"capacity\":    device.UserCapacity.Bytes,\n\t\t\"health_ok\":   device.SmartStatus.Passed,\n\t\t\"temperature\": device.Temperature.Current,\n\t\t\"firmware\":    device.FirmwareVersion,\n\t}\n\n\tif device.SCSIVendor != \"\" {\n\t\tfields[\"scsi_vendor\"] = device.SCSIVendor\n\t}\n\tif device.SCSIModelName != \"\" {\n\t\tfields[\"scsi_model\"] = device.SCSIModelName\n\t}\n\tif device.SCSIRevision != \"\" {\n\t\tfields[\"scsi_revision\"] = device.SCSIRevision\n\t}\n\tif device.SCSIVersion != \"\" {\n\t\tfields[\"scsi_version\"] = device.SCSIVersion\n\t}\n\tif device.SCSITransportProtocol.Name != \"\" {\n\t\tfields[\"scsi_transport_protocol\"] = device.SCSITransportProtocol.Name\n\t}\n\tif device.SCSIProtectionType != 0 {\n\t\tfields[\"scsi_protection_type\"] = device.SCSIProtectionType\n\t}\n\tif device.SCSIProtectionIntervalBytesPerLB != 0 {\n\t\tfields[\"scsi_protection_interval_bytes_per_lb\"] = device.SCSIProtectionIntervalBytesPerLB\n\t}\n\tif device.SCSIGrownDefectList != 0 {\n\t\tfields[\"scsi_grown_defect_list\"] = device.SCSIGrownDefectList\n\t}\n\tif device.LogicalBlockSize != 0 {\n\t\tfields[\"logical_block_size\"] = device.LogicalBlockSize\n\t}\n\tif device.RotationRate != 0 {\n\t\tfields[\"rotation_rate\"] = device.RotationRate\n\t}\n\tif device.SCSIStartStopCycleCounter.SpecifiedCycleCountOverDeviceLifetime != 0 {\n\t\tfields[\"specified_cycle_count_over_device_lifetime\"] = device.SCSIStartStopCycleCounter.SpecifiedCycleCountOverDeviceLifetime\n\t}\n\tif device.SCSIStartStopCycleCounter.AccumulatedStartStopCycles != 0 {\n\t\tfields[\"accumulated_start_stop_cycles\"] = device.SCSIStartStopCycleCounter.AccumulatedStartStopCycles\n\t}\n\tif device.PowerOnTime.Hours != 0 {\n\t\tfields[\"power_on_hours\"] = device.PowerOnTime.Hours\n\t}\n\tif device.PowerOnTime.Minutes != 0 {\n\t\tfields[\"power_on_minutes\"] = device.PowerOnTime.Minutes\n\t}\n\n\t// Add NVMe specific fields\n\tif device.Device.Type == \"nvme\" {\n\t\tfields[\"critical_warning\"] = device.NvmeSmartHealthInformationLog.CriticalWarning\n\t\tfields[\"temperature\"] = device.NvmeSmartHealthInformationLog.Temperature\n\t\tfields[\"available_spare\"] = device.NvmeSmartHealthInformationLog.AvailableSpare\n\t\tfields[\"available_spare_threshold\"] = device.NvmeSmartHealthInformationLog.AvailableSpareThreshold\n\t\tfields[\"percentage_used\"] = device.NvmeSmartHealthInformationLog.PercentageUsed\n\t\tfields[\"data_units_read\"] = device.NvmeSmartHealthInformationLog.DataUnitsRead\n\t\tfields[\"data_units_written\"] = device.NvmeSmartHealthInformationLog.DataUnitsWritten\n\t\tfields[\"host_reads\"] = device.NvmeSmartHealthInformationLog.HostReads\n\t\tfields[\"host_writes\"] = device.NvmeSmartHealthInformationLog.HostWrites\n\t\tfields[\"controller_busy_time\"] = device.NvmeSmartHealthInformationLog.ControllerBusyTime\n\t\tfields[\"power_cycles\"] = device.NvmeSmartHealthInformationLog.PowerCycles\n\t\tfields[\"power_on_hours\"] = device.NvmeSmartHealthInformationLog.PowerOnHours\n\t\tfields[\"unsafe_shutdowns\"] = device.NvmeSmartHealthInformationLog.UnsafeShutdowns\n\t\tfields[\"media_errors\"] = device.NvmeSmartHealthInformationLog.MediaErrors\n\t\tfields[\"num_err_log_entries\"] = device.NvmeSmartHealthInformationLog.NumErrLogEntries\n\t\tfields[\"warning_temp_time\"] = device.NvmeSmartHealthInformationLog.WarningTempTime\n\t\tfields[\"critical_comp_time\"] = device.NvmeSmartHealthInformationLog.CriticalCompTime\n\t}\n\n\tacc.AddFields(\"smartctl\", fields, tags, t)\n\n\t// Check for ATA specific attribute fields\n\tfor _, attribute := range device.AtaSmartAttributes.Table {\n\t\tattributeTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tattributeTags[k] = v\n\t\t}\n\t\tattributeTags[\"name\"] = attribute.Name\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"raw_value\": attribute.Raw.Value,\n\t\t\t\"worst\":     attribute.Worst,\n\t\t\t\"threshold\": attribute.Thresh,\n\t\t\t\"value\":     attribute.Value,\n\t\t}\n\n\t\tacc.AddFields(\"smartctl_attributes\", fields, attributeTags, t)\n\t}\n\n\t// Check for SCSI error counter entries\n\tif device.Device.Type == \"scsi\" {\n\t\tcounterTags := make(map[string]string, len(tags)+1)\n\t\tfor k, v := range tags {\n\t\t\tcounterTags[k] = v\n\t\t}\n\n\t\tcounterTags[\"page\"] = \"read\"\n\t\tfields := map[string]interface{}{\n\t\t\t\"errors_corrected_by_eccfast\":          device.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast,\n\t\t\t\"errors_corrected_by_eccdelayed\":       device.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed,\n\t\t\t\"errors_corrected_by_rereads_rewrites\": device.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites,\n\t\t\t\"total_errors_corrected\":               device.ScsiErrorCounterLog.Read.TotalErrorsCorrected,\n\t\t\t\"correction_algorithm_invocations\":     device.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations,\n\t\t\t\"gigabytes_processed\":                  device.ScsiErrorCounterLog.Read.GigabytesProcessed,\n\t\t\t\"total_uncorrected_errors\":             device.ScsiErrorCounterLog.Read.TotalUncorrectedErrors,\n\t\t}\n\t\tacc.AddFields(\"smartctl_scsi_error_counter_log\", fields, counterTags, t)\n\n\t\tcounterTags[\"page\"] = \"write\"\n\t\tfields = map[string]interface{}{\n\t\t\t\"errors_corrected_by_eccfast\":          device.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast,\n\t\t\t\"errors_corrected_by_eccdelayed\":       device.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed,\n\t\t\t\"errors_corrected_by_rereads_rewrites\": device.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites,\n\t\t\t\"total_errors_corrected\":               device.ScsiErrorCounterLog.Write.TotalErrorsCorrected,\n\t\t\t\"correction_algorithm_invocations\":     device.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations,\n\t\t\t\"gigabytes_processed\":                  device.ScsiErrorCounterLog.Write.GigabytesProcessed,\n\t\t\t\"total_uncorrected_errors\":             device.ScsiErrorCounterLog.Write.TotalUncorrectedErrors,\n\t\t}\n\t\tacc.AddFields(\"smartctl_scsi_error_counter_log\", fields, counterTags, t)\n\n\t\tcounterTags[\"page\"] = \"verify\"\n\t\tfields = map[string]interface{}{\n\t\t\t\"errors_corrected_by_eccfast\":          device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByEccfast,\n\t\t\t\"errors_corrected_by_eccdelayed\":       device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByEccdelayed,\n\t\t\t\"errors_corrected_by_rereads_rewrites\": device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByRereadsRewrites,\n\t\t\t\"total_errors_corrected\":               device.ScsiErrorCounterLog.Verify.TotalErrorsCorrected,\n\t\t\t\"correction_algorithm_invocations\":     device.ScsiErrorCounterLog.Verify.CorrectionAlgorithmInvocations,\n\t\t\t\"gigabytes_processed\":                  device.ScsiErrorCounterLog.Verify.GigabytesProcessed,\n\t\t\t\"total_uncorrected_errors\":             device.ScsiErrorCounterLog.Verify.TotalUncorrectedErrors,\n\t\t}\n\t\tacc.AddFields(\"smartctl_scsi_error_counter_log\", fields, counterTags, t)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/smartctl_json.go",
    "content": "package smartctl\n\ntype smartctlDeviceJSON struct {\n\tJSONFormatVersion []int `json:\"json_format_version\"`\n\tSmartctl          struct {\n\t\tVersion      []int    `json:\"version\"`\n\t\tPreRelease   bool     `json:\"pre_release\"`\n\t\tSvnRevision  string   `json:\"svn_revision\"`\n\t\tPlatformInfo string   `json:\"platform_info\"`\n\t\tBuildInfo    string   `json:\"build_info\"`\n\t\tArgv         []string `json:\"argv\"`\n\t\tMessages     []struct {\n\t\t\tSeverity string `json:\"severity\"`\n\t\t\tString   string `json:\"string\"`\n\t\t} `json:\"messages\"`\n\t\tExitStatus int `json:\"exit_status\"`\n\t} `json:\"smartctl\"`\n\tDevice struct {\n\t\tName     string `json:\"name\"`\n\t\tInfoName string `json:\"info_name\"`\n\t\tType     string `json:\"type\"`\n\t\tProtocol string `json:\"protocol\"`\n\t} `json:\"device\"`\n\tVendor                           string `json:\"vendor\"`\n\tProduct                          string `json:\"product\"`\n\tModelFamily                      string `json:\"model_family\"`\n\tModelName                        string `json:\"model_name\"`\n\tSerialNumber                     string `json:\"serial_number\"`\n\tFirmwareVersion                  string `json:\"firmware_version\"`\n\tSCSIVendor                       string `json:\"scsi_vendor\"`\n\tSCSIModelName                    string `json:\"scsi_model_name\"`\n\tSCSIRevision                     string `json:\"scsi_revision\"`\n\tSCSIVersion                      string `json:\"scsi_version\"`\n\tSCSIProtectionType               int    `json:\"scsi_protection_type\"`\n\tSCSIProtectionIntervalBytesPerLB int    `json:\"scsi_protection_interval_bytes_per_lb\"`\n\tSCSIGrownDefectList              int    `json:\"scsi_grown_defect_list\"`\n\tLogicalBlockSize                 int    `json:\"logical_block_size\"`\n\tRotationRate                     int    `json:\"rotation_rate\"`\n\tSCSITransportProtocol            struct {\n\t\tName string `json:\"name\"`\n\t} `json:\"scsi_transport_protocol\"`\n\tSCSIStartStopCycleCounter struct {\n\t\tSpecifiedCycleCountOverDeviceLifetime int `json:\"specified_cycle_count_over_device_lifetime\"`\n\t\tAccumulatedStartStopCycles            int `json:\"accumulated_start_stop_cycles\"`\n\t} `json:\"scsi_start_stop_cycle_counter\"`\n\tPowerOnTime struct {\n\t\tHours   int `json:\"hours\"`\n\t\tMinutes int `json:\"minutes\"`\n\t} `json:\"power_on_time\"`\n\tWwn struct {\n\t\tNaa int   `json:\"naa\"`\n\t\tOui int   `json:\"oui\"`\n\t\tID  int64 `json:\"id\"`\n\t} `json:\"wwn\"`\n\tUserCapacity struct {\n\t\tBytes int64 `json:\"bytes\"`\n\t} `json:\"user_capacity\"`\n\tSmartStatus struct {\n\t\tPassed bool `json:\"passed\"`\n\t} `json:\"smart_status\"`\n\tNvmeSmartHealthInformationLog struct {\n\t\tCriticalWarning         int64 `json:\"critical_warning\"`\n\t\tTemperature             int64 `json:\"temperature\"`\n\t\tAvailableSpare          int64 `json:\"available_spare\"`\n\t\tAvailableSpareThreshold int64 `json:\"available_spare_threshold\"`\n\t\tPercentageUsed          int64 `json:\"percentage_used\"`\n\t\tDataUnitsRead           int64 `json:\"data_units_read\"`\n\t\tDataUnitsWritten        int64 `json:\"data_units_written\"`\n\t\tHostReads               int64 `json:\"host_reads\"`\n\t\tHostWrites              int64 `json:\"host_writes\"`\n\t\tControllerBusyTime      int64 `json:\"controller_busy_time\"`\n\t\tPowerCycles             int64 `json:\"power_cycles\"`\n\t\tPowerOnHours            int64 `json:\"power_on_hours\"`\n\t\tUnsafeShutdowns         int64 `json:\"unsafe_shutdowns\"`\n\t\tMediaErrors             int64 `json:\"media_errors\"`\n\t\tNumErrLogEntries        int64 `json:\"num_err_log_entries\"`\n\t\tWarningTempTime         int64 `json:\"warning_temp_time\"`\n\t\tCriticalCompTime        int64 `json:\"critical_comp_time\"`\n\t} `json:\"nvme_smart_health_information_log\"`\n\tTemperature struct {\n\t\tCurrent int `json:\"current\"`\n\t} `json:\"temperature\"`\n\tAtaSmartAttributes struct {\n\t\tRevision int `json:\"revision\"`\n\t\tTable    []struct {\n\t\t\tID         int64  `json:\"id\"`\n\t\t\tName       string `json:\"name\"`\n\t\t\tValue      int64  `json:\"value\"`\n\t\t\tWorst      int64  `json:\"worst\"`\n\t\t\tThresh     int64  `json:\"thresh\"`\n\t\t\tWhenFailed string `json:\"when_failed\"`\n\t\t\tFlags      struct {\n\t\t\t\tValue         int64  `json:\"value\"`\n\t\t\t\tString        string `json:\"string\"`\n\t\t\t\tPrefailure    bool   `json:\"prefailure\"`\n\t\t\t\tUpdatedOnline bool   `json:\"updated_online\"`\n\t\t\t\tPerformance   bool   `json:\"performance\"`\n\t\t\t\tErrorRate     bool   `json:\"error_rate\"`\n\t\t\t\tEventCount    bool   `json:\"event_count\"`\n\t\t\t\tAutoKeep      bool   `json:\"auto_keep\"`\n\t\t\t} `json:\"flags\"`\n\t\t\tRaw struct {\n\t\t\t\tValue  int64  `json:\"value\"`\n\t\t\t\tString string `json:\"string\"`\n\t\t\t} `json:\"raw\"`\n\t\t} `json:\"table\"`\n\t} `json:\"ata_smart_attributes\"`\n\tScsiErrorCounterLog struct {\n\t\tRead struct {\n\t\t\tErrorsCorrectedByEccfast         int    `json:\"errors_corrected_by_eccfast\"`\n\t\t\tErrorsCorrectedByEccdelayed      int    `json:\"errors_corrected_by_eccdelayed\"`\n\t\t\tErrorsCorrectedByRereadsRewrites int    `json:\"errors_corrected_by_rereads_rewrites\"`\n\t\t\tTotalErrorsCorrected             int    `json:\"total_errors_corrected\"`\n\t\t\tCorrectionAlgorithmInvocations   int    `json:\"correction_algorithm_invocations\"`\n\t\t\tGigabytesProcessed               string `json:\"gigabytes_processed\"`\n\t\t\tTotalUncorrectedErrors           int    `json:\"total_uncorrected_errors\"`\n\t\t} `json:\"read\"`\n\t\tWrite struct {\n\t\t\tErrorsCorrectedByEccfast         int    `json:\"errors_corrected_by_eccfast\"`\n\t\t\tErrorsCorrectedByEccdelayed      int    `json:\"errors_corrected_by_eccdelayed\"`\n\t\t\tErrorsCorrectedByRereadsRewrites int    `json:\"errors_corrected_by_rereads_rewrites\"`\n\t\t\tTotalErrorsCorrected             int    `json:\"total_errors_corrected\"`\n\t\t\tCorrectionAlgorithmInvocations   int    `json:\"correction_algorithm_invocations\"`\n\t\t\tGigabytesProcessed               string `json:\"gigabytes_processed\"`\n\t\t\tTotalUncorrectedErrors           int    `json:\"total_uncorrected_errors\"`\n\t\t} `json:\"write\"`\n\t\tVerify struct {\n\t\t\tErrorsCorrectedByEccfast         int    `json:\"errors_corrected_by_eccfast\"`\n\t\t\tErrorsCorrectedByEccdelayed      int    `json:\"errors_corrected_by_eccdelayed\"`\n\t\t\tErrorsCorrectedByRereadsRewrites int    `json:\"errors_corrected_by_rereads_rewrites\"`\n\t\t\tTotalErrorsCorrected             int    `json:\"total_errors_corrected\"`\n\t\t\tCorrectionAlgorithmInvocations   int    `json:\"correction_algorithm_invocations\"`\n\t\t\tGigabytesProcessed               string `json:\"gigabytes_processed\"`\n\t\t\tTotalUncorrectedErrors           int    `json:\"total_uncorrected_errors\"`\n\t\t} `json:\"verify\"`\n\t} `json:\"scsi_error_counter_log\"`\n}\n\ntype smartctlScanJSON struct {\n\tJSONFormatVersion []int `json:\"json_format_version\"`\n\tSmartctl          struct {\n\t\tVersion      []int    `json:\"version\"`\n\t\tPreRelease   bool     `json:\"pre_release\"`\n\t\tSvnRevision  string   `json:\"svn_revision\"`\n\t\tPlatformInfo string   `json:\"platform_info\"`\n\t\tBuildInfo    string   `json:\"build_info\"`\n\t\tArgv         []string `json:\"argv\"`\n\t\tExitStatus   int      `json:\"exit_status\"`\n\t} `json:\"smartctl\"`\n\tDevices []struct {\n\t\tName     string `json:\"name\"`\n\t\tInfoName string `json:\"info_name\"`\n\t\tType     string `json:\"type\"`\n\t\tProtocol string `json:\"protocol\"`\n\t} `json:\"devices\"`\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/smartctl_scan.go",
    "content": "package smartctl\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// This is here so we can override it during testing\nvar scanArgs = []string{\"--json\", \"--scan-open\"}\n\ntype scanDevice struct {\n\tName string\n\tType string\n}\n\nfunc (s *Smartctl) scan() ([]scanDevice, error) {\n\tcmd := execCommand(s.Path, scanArgs...)\n\tif s.UseSudo {\n\t\tcmd = execCommand(\"sudo\", append([]string{\"-n\", s.Path}, scanArgs...)...)\n\t}\n\tout, err := internal.CombinedOutputTimeout(cmd, time.Duration(s.Timeout))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error running smartctl with %s: %w\", scanArgs, err)\n\t}\n\n\tvar scan smartctlScanJSON\n\tif err := json.Unmarshal(out, &scan); err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling smartctl scan output: %w\", err)\n\t}\n\n\tdevices := make([]scanDevice, 0)\n\tfor _, device := range scan.Devices {\n\t\tif s.deviceFilter.Match(device.Name) {\n\t\t\tdevice := scanDevice{\n\t\t\t\tName: device.Name,\n\t\t\t\tType: device.Type,\n\t\t\t}\n\t\t\tdevices = append(devices, device)\n\t\t}\n\t}\n\n\treturn devices, nil\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/smartctl_test.go",
    "content": "package smartctl\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCasesScan(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases_scan\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"smartctl\", func() telegraf.Input {\n\t\treturn &Smartctl{}\n\t})\n\n\tfor _, f := range folders {\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases_scan\", f.Name())\n\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.toml\")\n\t\tscanFilename := filepath.Join(testcasePath, \"response.json\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected int\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedBytes, err := os.ReadFile(expectedFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\texpected, err = strconv.Atoi(strings.TrimSpace(string(expectedBytes)))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Update exec to return fake data.\n\t\t\texecCommand = fakeScanExecCommand\n\t\t\tdefer func() { execCommand = exec.Command }()\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\t\t\tplugin := cfg.Inputs[0].Input.(*Smartctl)\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tscanArgs = append(scanArgs, scanFilename)\n\t\t\tdevices, err := plugin.scan()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, devices, expected)\n\t\t})\n\t}\n}\n\nfunc fakeScanExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestScanHelperProcess\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\nfunc TestScanHelperProcess(*testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\targs := os.Args\n\n\tscanBytes, err := os.ReadFile(args[len(args)-1])\n\tif err != nil {\n\t\tfmt.Fprint(os.Stdout, \"unknown filename\")\n\t\t//nolint:revive // os.Exit called intentionally\n\t\tos.Exit(42)\n\t}\n\n\tfmt.Fprint(os.Stdout, string(scanBytes))\n\t//nolint:revive // os.Exit called intentionally\n\tos.Exit(0)\n}\n\nfunc TestCasesDevices(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases_device\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"smartctl\", func() telegraf.Input {\n\t\treturn &Smartctl{}\n\t})\n\n\tfor _, f := range folders {\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\ttestcasePath := filepath.Join(\"testcases_device\", f.Name())\n\t\tdeviceFilename := filepath.Join(testcasePath, \"device\")\n\t\tdeviceTypeFilename := filepath.Join(testcasePath, \"deviceType\")\n\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the devices to scan\n\t\t\tdeviceBytes, err := os.ReadFile(deviceFilename)\n\t\t\trequire.NoError(t, err)\n\t\t\tdeviceTypeBytes, err := os.ReadFile(deviceTypeFilename)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Update exec to return fake data.\n\t\t\texecCommand = fakeDeviceExecCommand\n\t\t\tdefer func() { execCommand = exec.Command }()\n\n\t\t\t// Configure the plugin\n\t\t\tplugin := Smartctl{}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t,\n\t\t\t\tplugin.scanDevice(\n\t\t\t\t\t&acc,\n\t\t\t\t\tstrings.TrimSpace(string(deviceBytes)),\n\t\t\t\t\tstrings.TrimSpace(string(deviceTypeBytes)),\n\t\t\t\t),\n\t\t\t)\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n\t\t\tacc.Lock()\n\t\t\tdefer acc.Unlock()\n\t\t\trequire.Empty(t, acc.Errors)\n\t\t})\n\t}\n}\n\nfunc fakeDeviceExecCommand(command string, args ...string) *exec.Cmd {\n\tcs := make([]string, 0, len(args)+3)\n\tcs = append(cs, \"-test.run=TestDeviceHelperProcess\", \"--\", command)\n\tcs = append(cs, args...)\n\tcmd := exec.Command(os.Args[0], cs...)\n\tcmd.Env = []string{\"GO_WANT_HELPER_PROCESS=1\"}\n\treturn cmd\n}\n\nfunc TestDeviceHelperProcess(t *testing.T) {\n\tif os.Getenv(\"GO_WANT_HELPER_PROCESS\") != \"1\" {\n\t\treturn\n\t}\n\targs := os.Args\n\n\tvar filename string\n\tif slices.Contains(args, \"/dev/nvme0\") {\n\t\tfilename = \"testcases_device/nvme/response.json\"\n\t} else if slices.Contains(args, \"/dev/sda\") {\n\t\tfilename = \"testcases_device/usb/response.json\"\n\t} else if slices.Contains(args, \"/dev/bus/6\") {\n\t\tfilename = \"testcases_device/megaraid/response.json\"\n\t} else if slices.Contains(args, \"/dev/sdb\") {\n\t\tfilename = \"testcases_device/scsi/response.json\"\n\t} else if slices.Contains(args, \"/dev/sdaa\") {\n\t\tfilename = \"testcases_device/scsi_extended/response.json\"\n\t} else {\n\t\tfmt.Fprint(os.Stdout, \"unknown filename\")\n\t\tos.Exit(42) //nolint:revive // os.Exit called intentionally\n\t}\n\n\tscanBytes, err := os.ReadFile(filename)\n\trequire.NoError(t, err)\n\tfmt.Fprint(os.Stdout, string(scanBytes))\n\tos.Exit(0) //nolint:revive // os.Exit called intentionally\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/megaraid/device",
    "content": "/dev/bus/6\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/megaraid/deviceType",
    "content": "megaraid,14\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/megaraid/expected.out",
    "content": "smartctl,model=ST6000NM0115-1YZ110,name=/dev/bus/6,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d capacity=6001175126016i,firmware=\"SN04\",health_ok=true,logical_block_size=512i,power_on_hours=44316i,rotation_rate=7200i,temperature=25i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Raw_Read_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=181426040i,threshold=44i,value=83i,worst=64i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Spin_Up_Time,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=91i,worst=91i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Start_Stop_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=62i,threshold=20i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Reallocated_Sector_Ct,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=10i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Seek_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=2827960730i,threshold=45i,value=95i,worst=60i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Power_On_Hours,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=44316i,threshold=0i,value=50i,worst=50i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Spin_Retry_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=97i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Power_Cycle_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=62i,threshold=20i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=End-to-End_Error,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=99i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Reported_Uncorrect,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Command_Timeout,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=High_Fly_Writes,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Airflow_Temperature_Cel,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=504627225i,threshold=40i,value=75i,worst=64i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=G-Sense_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=3295i,threshold=0i,value=99i,worst=99i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Power-Off_Retract_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=1865i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Load_Cycle_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=1894i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Temperature_Celsius,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=30064771097i,threshold=0i,value=25i,worst=40i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Hardware_ECC_Recovered,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=181426040i,threshold=0i,value=83i,worst=64i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Current_Pending_Sector,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Offline_Uncorrectable,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=UDMA_CRC_Error_Count,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=200i,worst=200i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Head_Flying_Hours,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=1265348905053451i,threshold=0i,value=100i,worst=253i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Total_LBAs_Written,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=28111553262i,threshold=0i,value=100i,worst=253i 1711726425026052398\nsmartctl_attributes,model=ST6000NM0115-1YZ110,name=Total_LBAs_Read,serial=ZAD2C11G,type=sat+megaraid\\,14,wwn=5000c500a496983d raw_value=3197497186480i,threshold=0i,value=100i,worst=253i 1711726425026052398\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/megaraid/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      1\n    ],\n    \"svn_revision\": \"5022\",\n    \"platform_info\": \"x86_64-linux-5.4.0-172-generic\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--json\",\n      \"--all\",\n      \"/dev/bus/6\",\n      \"--device\",\n      \"megaraid,14\",\n      \"--nocheck=standby\"\n    ],\n    \"messages\": [\n      {\n        \"string\": \"Warning: This result is based on an Attribute check.\",\n        \"severity\": \"warning\"\n      }\n    ],\n    \"exit_status\": 4\n  },\n  \"device\": {\n    \"name\": \"/dev/bus/6\",\n    \"info_name\": \"/dev/bus/6 [megaraid_disk_14] [SAT]\",\n    \"type\": \"sat+megaraid,14\",\n    \"protocol\": \"ATA\"\n  },\n  \"model_family\": \"Seagate Enterprise Capacity 3.5 HDD\",\n  \"model_name\": \"ST6000NM0115-1YZ110\",\n  \"serial_number\": \"ZAD2C11G\",\n  \"wwn\": {\n    \"naa\": 5,\n    \"oui\": 3152,\n    \"id\": 2761332797\n  },\n  \"firmware_version\": \"SN04\",\n  \"user_capacity\": {\n    \"blocks\": 11721045168,\n    \"bytes\": 6001175126016\n  },\n  \"logical_block_size\": 512,\n  \"physical_block_size\": 4096,\n  \"rotation_rate\": 7200,\n  \"form_factor\": {\n    \"ata_value\": 2,\n    \"name\": \"3.5 inches\"\n  },\n  \"in_smartctl_database\": true,\n  \"ata_version\": {\n    \"string\": \"ACS-3 T13/2161-D revision 5\",\n    \"major_value\": 2032,\n    \"minor_value\": 109\n  },\n  \"sata_version\": {\n    \"string\": \"SATA 3.1\",\n    \"value\": 127\n  },\n  \"interface_speed\": {\n    \"max\": {\n      \"sata_value\": 14,\n      \"string\": \"6.0 Gb/s\",\n      \"units_per_second\": 60,\n      \"bits_per_unit\": 100000000\n    },\n    \"current\": {\n      \"sata_value\": 3,\n      \"string\": \"6.0 Gb/s\",\n      \"units_per_second\": 60,\n      \"bits_per_unit\": 100000000\n    }\n  },\n  \"local_time\": {\n    \"time_t\": 1711639509,\n    \"asctime\": \"Thu Mar 28 16:25:09 2024 CET\"\n  },\n  \"smart_status\": {\n    \"passed\": true\n  },\n  \"ata_smart_data\": {\n    \"offline_data_collection\": {\n      \"status\": {\n        \"value\": 130,\n        \"string\": \"was completed without error\",\n        \"passed\": true\n      },\n      \"completion_seconds\": 567\n    },\n    \"self_test\": {\n      \"status\": {\n        \"value\": 0,\n        \"string\": \"completed without error\",\n        \"passed\": true\n      },\n      \"polling_minutes\": {\n        \"short\": 1,\n        \"extended\": 584,\n        \"conveyance\": 2\n      }\n    },\n    \"capabilities\": {\n      \"values\": [\n        123,\n        3\n      ],\n      \"exec_offline_immediate_supported\": true,\n      \"offline_is_aborted_upon_new_cmd\": false,\n      \"offline_surface_scan_supported\": true,\n      \"self_tests_supported\": true,\n      \"conveyance_self_test_supported\": true,\n      \"selective_self_test_supported\": true,\n      \"attribute_autosave_enabled\": true,\n      \"error_logging_supported\": true,\n      \"gp_logging_supported\": true\n    }\n  },\n  \"ata_sct_capabilities\": {\n    \"value\": 28861,\n    \"error_recovery_control_supported\": true,\n    \"feature_control_supported\": true,\n    \"data_table_supported\": true\n  },\n  \"ata_smart_attributes\": {\n    \"revision\": 10,\n    \"table\": [\n      {\n        \"id\": 1,\n        \"name\": \"Raw_Read_Error_Rate\",\n        \"value\": 83,\n        \"worst\": 64,\n        \"thresh\": 44,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 15,\n          \"string\": \"POSR-- \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": true,\n          \"error_rate\": true,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 181426040,\n          \"string\": \"181426040\"\n        }\n      },\n      {\n        \"id\": 3,\n        \"name\": \"Spin_Up_Time\",\n        \"value\": 91,\n        \"worst\": 91,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 3,\n          \"string\": \"PO---- \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 4,\n        \"name\": \"Start_Stop_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 20,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 62,\n          \"string\": \"62\"\n        }\n      },\n      {\n        \"id\": 5,\n        \"name\": \"Reallocated_Sector_Ct\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 10,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 51,\n          \"string\": \"PO--CK \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 7,\n        \"name\": \"Seek_Error_Rate\",\n        \"value\": 95,\n        \"worst\": 60,\n        \"thresh\": 45,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 15,\n          \"string\": \"POSR-- \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": true,\n          \"error_rate\": true,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 2827960730,\n          \"string\": \"2827960730\"\n        }\n      },\n      {\n        \"id\": 9,\n        \"name\": \"Power_On_Hours\",\n        \"value\": 50,\n        \"worst\": 50,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 44316,\n          \"string\": \"44316\"\n        }\n      },\n      {\n        \"id\": 10,\n        \"name\": \"Spin_Retry_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 97,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 19,\n          \"string\": \"PO--C- \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 12,\n        \"name\": \"Power_Cycle_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 20,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 62,\n          \"string\": \"62\"\n        }\n      },\n      {\n        \"id\": 184,\n        \"name\": \"End-to-End_Error\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 99,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 187,\n        \"name\": \"Reported_Uncorrect\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 188,\n        \"name\": \"Command_Timeout\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0 0 0\"\n        }\n      },\n      {\n        \"id\": 189,\n        \"name\": \"High_Fly_Writes\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 58,\n          \"string\": \"-O-RCK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": true,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 190,\n        \"name\": \"Airflow_Temperature_Cel\",\n        \"value\": 75,\n        \"worst\": 64,\n        \"thresh\": 40,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 34,\n          \"string\": \"-O---K \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 504627225,\n          \"string\": \"25 (Min/Max 20/30)\"\n        }\n      },\n      {\n        \"id\": 191,\n        \"name\": \"G-Sense_Error_Rate\",\n        \"value\": 99,\n        \"worst\": 99,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 3295,\n          \"string\": \"3295\"\n        }\n      },\n      {\n        \"id\": 192,\n        \"name\": \"Power-Off_Retract_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 1865,\n          \"string\": \"1865\"\n        }\n      },\n      {\n        \"id\": 193,\n        \"name\": \"Load_Cycle_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 50,\n          \"string\": \"-O--CK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 1894,\n          \"string\": \"1894\"\n        }\n      },\n      {\n        \"id\": 194,\n        \"name\": \"Temperature_Celsius\",\n        \"value\": 25,\n        \"worst\": 40,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 34,\n          \"string\": \"-O---K \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 30064771097,\n          \"string\": \"25 (0 7 0 0 0)\"\n        }\n      },\n      {\n        \"id\": 195,\n        \"name\": \"Hardware_ECC_Recovered\",\n        \"value\": 83,\n        \"worst\": 64,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 26,\n          \"string\": \"-O-RC- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": true,\n          \"event_count\": true,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 181426040,\n          \"string\": \"181426040\"\n        }\n      },\n      {\n        \"id\": 197,\n        \"name\": \"Current_Pending_Sector\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 18,\n          \"string\": \"-O--C- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 198,\n        \"name\": \"Offline_Uncorrectable\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 16,\n          \"string\": \"----C- \",\n          \"prefailure\": false,\n          \"updated_online\": false,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": true,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 199,\n        \"name\": \"UDMA_CRC_Error_Count\",\n        \"value\": 200,\n        \"worst\": 200,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 62,\n          \"string\": \"-OSRCK \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": true,\n          \"error_rate\": true,\n          \"event_count\": true,\n          \"auto_keep\": true\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 240,\n        \"name\": \"Head_Flying_Hours\",\n        \"value\": 100,\n        \"worst\": 253,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 0,\n          \"string\": \"------ \",\n          \"prefailure\": false,\n          \"updated_online\": false,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 1265348905053451,\n          \"string\": \"44299h+04m+54.612s\"\n        }\n      },\n      {\n        \"id\": 241,\n        \"name\": \"Total_LBAs_Written\",\n        \"value\": 100,\n        \"worst\": 253,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 0,\n          \"string\": \"------ \",\n          \"prefailure\": false,\n          \"updated_online\": false,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 28111553262,\n          \"string\": \"28111553262\"\n        }\n      },\n      {\n        \"id\": 242,\n        \"name\": \"Total_LBAs_Read\",\n        \"value\": 100,\n        \"worst\": 253,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 0,\n          \"string\": \"------ \",\n          \"prefailure\": false,\n          \"updated_online\": false,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 3197497186480,\n          \"string\": \"3197497186480\"\n        }\n      }\n    ]\n  },\n  \"power_on_time\": {\n    \"hours\": 44316\n  },\n  \"power_cycle_count\": 62,\n  \"temperature\": {\n    \"current\": 25\n  },\n  \"ata_smart_error_log\": {\n    \"summary\": {\n      \"revision\": 1,\n      \"count\": 0\n    }\n  },\n  \"ata_smart_self_test_log\": {\n    \"standard\": {\n      \"revision\": 1,\n      \"count\": 0\n    }\n  },\n  \"ata_smart_selective_self_test_log\": {\n    \"revision\": 1,\n    \"table\": [\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      }\n    ],\n    \"flags\": {\n      \"value\": 0,\n      \"remainder_scan_enabled\": false\n    },\n    \"power_up_scan_resume_minutes\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/nvme/device",
    "content": "/dev/nvme0\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/nvme/deviceType",
    "content": "nvme\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/nvme/expected.out",
    "content": "smartctl,model=Sabrent\\ Rocket\\ 4.0\\ 1TB,name=/dev/nvme0,serial=6D1107091C9583054511,type=nvme available_spare=100i,available_spare_threshold=5i,capacity=1000204886016i,controller_busy_time=1635i,critical_comp_time=0i,critical_warning=0i,data_units_read=28337502i,data_units_written=76471882i,firmware=\"RKT401.3\",health_ok=true,host_reads=294243226i,host_writes=733021025i,media_errors=0i,num_err_log_entries=4871i,percentage_used=4i,power_cycles=1815i,power_on_hours=8733i,temperature=48i,unsafe_shutdowns=39i,warning_temp_time=0i,logical_block_size=512i 1711480345635747372\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/nvme/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      4\n    ],\n    \"pre_release\": false,\n    \"svn_revision\": \"5530\",\n    \"platform_info\": \"x86_64-linux-6.8.1-arch1-1\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"-a\",\n      \"-d\",\n      \"nvme\",\n      \"/dev/nvme0\",\n      \"--json\"\n    ],\n    \"exit_status\": 0\n  },\n  \"local_time\": {\n    \"time_t\": 1711371013,\n    \"asctime\": \"Mon Mar 25 06:50:13 2024 MDT\"\n  },\n  \"device\": {\n    \"name\": \"/dev/nvme0\",\n    \"info_name\": \"/dev/nvme0\",\n    \"type\": \"nvme\",\n    \"protocol\": \"NVMe\"\n  },\n  \"model_name\": \"Sabrent Rocket 4.0 1TB\",\n  \"serial_number\": \"6D1107091C9583054511\",\n  \"firmware_version\": \"RKT401.3\",\n  \"nvme_pci_vendor\": {\n    \"id\": 6535,\n    \"subsystem_id\": 6535\n  },\n  \"nvme_ieee_oui_identifier\": 6584743,\n  \"nvme_total_capacity\": 1000204886016,\n  \"nvme_unallocated_capacity\": 0,\n  \"nvme_controller_id\": 1,\n  \"nvme_version\": {\n    \"string\": \"1.3\",\n    \"value\": 66304\n  },\n  \"nvme_number_of_namespaces\": 1,\n  \"nvme_namespaces\": [\n    {\n      \"id\": 1,\n      \"size\": {\n        \"blocks\": 1953525168,\n        \"bytes\": 1000204886016\n      },\n      \"capacity\": {\n        \"blocks\": 1953525168,\n        \"bytes\": 1000204886016\n      },\n      \"utilization\": {\n        \"blocks\": 1953525168,\n        \"bytes\": 1000204886016\n      },\n      \"formatted_lba_size\": 512,\n      \"eui64\": {\n        \"oui\": 6584743,\n        \"ext_id\": 268705991866\n      }\n    }\n  ],\n  \"user_capacity\": {\n    \"blocks\": 1953525168,\n    \"bytes\": 1000204886016\n  },\n  \"logical_block_size\": 512,\n  \"smart_support\": {\n    \"available\": true,\n    \"enabled\": true\n  },\n  \"smart_status\": {\n    \"passed\": true,\n    \"nvme\": {\n      \"value\": 0\n    }\n  },\n  \"nvme_smart_health_information_log\": {\n    \"critical_warning\": 0,\n    \"temperature\": 48,\n    \"available_spare\": 100,\n    \"available_spare_threshold\": 5,\n    \"percentage_used\": 4,\n    \"data_units_read\": 28337502,\n    \"data_units_written\": 76471882,\n    \"host_reads\": 294243226,\n    \"host_writes\": 733021025,\n    \"controller_busy_time\": 1635,\n    \"power_cycles\": 1815,\n    \"power_on_hours\": 8733,\n    \"unsafe_shutdowns\": 39,\n    \"media_errors\": 0,\n    \"num_err_log_entries\": 4871,\n    \"warning_temp_time\": 0,\n    \"critical_comp_time\": 0\n  },\n  \"temperature\": {\n    \"current\": 48\n  },\n  \"power_cycle_count\": 1815,\n  \"power_on_time\": {\n    \"hours\": 8733\n  },\n  \"nvme_error_information_log\": {\n    \"size\": 63,\n    \"read\": 16,\n    \"unread\": 0,\n    \"table\": [\n      {\n        \"error_count\": 4871,\n        \"submission_queue_id\": 0,\n        \"command_id\": 20495,\n        \"status_field\": {\n          \"value\": 8194,\n          \"do_not_retry\": false,\n          \"status_code_type\": 0,\n          \"status_code\": 2,\n          \"string\": \"Invalid Field in Command\"\n        },\n        \"phase_tag\": false,\n        \"parm_error_location\": 40,\n        \"lba\": {\n          \"value\": 0\n        },\n        \"nsid\": 0\n      }\n    ]\n  },\n  \"nvme_self_test_log\": {\n    \"current_self_test_operation\": {\n      \"value\": 0,\n      \"string\": \"No self-test in progress\"\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi/device",
    "content": "/dev/sdb\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi/deviceType",
    "content": "scsi\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi/expected.out",
    "content": "smartctl,model=XXXX\\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,vendor=XXXXXXX capacity=13715978077777i,firmware=\"\",health_ok=true,logical_block_size=512i,power_on_hours=32978i,power_on_minutes=46i,rotation_rate=7200i,scsi_version=\"SPC-5\",temperature=24i 1712071085987864368\nsmartctl_scsi_error_counter_log,model=XXXX\\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=read,vendor=XXXXXXX correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=1i,errors_corrected_by_rereads_rewrites=5i,gigabytes_processed=\"315926.142\",total_errors_corrected=3i,total_uncorrected_errors=0i 1712071085987864368\nsmartctl_scsi_error_counter_log,model=XXXX\\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=write,vendor=XXXXXXX correction_algorithm_invocations=20i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=0i,errors_corrected_by_rereads_rewrites=20i,gigabytes_processed=\"132513.233\",total_errors_corrected=20i,total_uncorrected_errors=0i 1712071085987864368\nsmartctl_scsi_error_counter_log,model=XXXX\\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=verify,vendor=XXXXXXX correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=12i,errors_corrected_by_rereads_rewrites=0i,gigabytes_processed=\"1437.032\",total_errors_corrected=3i,total_uncorrected_errors=0i 1712071085987864368\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      2\n    ],\n    \"svn_revision\": \"5123\",\n    \"platform_info\": \"x86_64-linux-4.12.0-1-amd64\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--json\",\n      \"--all\",\n      \"/dev/sdb\",\n      \"--device\",\n      \"scsi\"\n    ],\n    \"exit_status\": 0\n  },\n  \"device\": {\n    \"name\": \"/dev/sdb\",\n    \"info_name\": \"/dev/sdb\",\n    \"type\": \"scsi\",\n    \"protocol\": \"SCSI\"\n  },\n  \"vendor\": \"XXXXXXX\",\n  \"product\": \"XXXX000OOOO\",\n  \"model_name\": \"XXXX XX0000NM123\",\n  \"revision\": \"RSL5\",\n  \"scsi_version\": \"SPC-5\",\n  \"user_capacity\": {\n    \"blocks\": 26789019888,\n    \"bytes\": 13715978077777\n  },\n  \"logical_block_size\": 512,\n  \"physical_block_size\": 4096,\n  \"rotation_rate\": 7200,\n  \"form_factor\": {\n    \"scsi_value\": 3,\n    \"name\": \"3.5 inches\"\n  },\n  \"serial_number\": \"XXXXXXX\",\n  \"device_type\": {\n    \"scsi_value\": 0,\n    \"name\": \"disk\"\n  },\n  \"local_time\": {\n    \"time_t\": 1711977687,\n    \"asctime\": \"Sun Mar  31 13:21:27 2024 UTC\"\n  },\n  \"smart_status\": {\n    \"passed\": true\n  },\n  \"temperature\": {\n    \"current\": 24,\n    \"drive_trip\": 60\n  },\n  \"power_on_time\": {\n    \"hours\": 32978,\n    \"minutes\": 46\n  },\n  \"scsi_grown_defect_list\": 0,\n  \"scsi_error_counter_log\": {\n    \"read\": {\n      \"errors_corrected_by_eccfast\": 1,\n      \"errors_corrected_by_eccdelayed\": 0,\n      \"errors_corrected_by_rereads_rewrites\": 5,\n      \"total_errors_corrected\": 3,\n      \"correction_algorithm_invocations\": 0,\n      \"gigabytes_processed\": \"315926.142\",\n      \"total_uncorrected_errors\": 0\n    },\n    \"write\": {\n      \"errors_corrected_by_eccfast\": 0,\n      \"errors_corrected_by_eccdelayed\": 0,\n      \"errors_corrected_by_rereads_rewrites\": 20,\n      \"total_errors_corrected\": 20,\n      \"correction_algorithm_invocations\": 20,\n      \"gigabytes_processed\": \"132513.233\",\n      \"total_uncorrected_errors\": 0\n    },\n    \"verify\": {\n      \"errors_corrected_by_eccfast\": 12,\n      \"errors_corrected_by_eccdelayed\": 0,\n      \"errors_corrected_by_rereads_rewrites\": 0,\n      \"total_errors_corrected\": 3,\n      \"correction_algorithm_invocations\": 0,\n      \"gigabytes_processed\": \"1437.032\",\n      \"total_uncorrected_errors\": 0\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi_extended/device",
    "content": "/dev/sdaa\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi_extended/deviceType",
    "content": "scsi\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi_extended/expected.out",
    "content": "smartctl,name=/dev/sdaa,serial=XYZZZZ,type=scsi accumulated_start_stop_cycles=220i,capacity=13715978079776i,firmware=\"\",health_ok=true,logical_block_size=512i,power_on_hours=34222i,power_on_minutes=9i,rotation_rate=7200i,scsi_model=\"SEAGATE ST0000000\",scsi_protection_interval_bytes_per_lb=8i,scsi_protection_type=2i,scsi_revision=\"RSL5\",scsi_transport_protocol=\"SAS (SPL-4)\",scsi_vendor=\"XYZZZZZZ\",scsi_version=\"SPC-5\",specified_cycle_count_over_device_lifetime=50000i,temperature=24i 1715282104914128775\nsmartctl_scsi_error_counter_log,name=/dev/sdaa,page=read,serial=XYZZZZ,type=scsi correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=0i,errors_corrected_by_rereads_rewrites=0i,gigabytes_processed=\"316009.846\",total_errors_corrected=0i,total_uncorrected_errors=0i 1715282104914128775\nsmartctl_scsi_error_counter_log,name=/dev/sdaa,page=write,serial=XYZZZZ,type=scsi correction_algorithm_invocations=20i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=0i,errors_corrected_by_rereads_rewrites=20i,gigabytes_processed=\"132824.923\",total_errors_corrected=20i,total_uncorrected_errors=0i 1715282104914128775\nsmartctl_scsi_error_counter_log,name=/dev/sdaa,page=verify,serial=XYZZZZ,type=scsi correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=0i,errors_corrected_by_rereads_rewrites=0i,gigabytes_processed=\"1467.278\",total_errors_corrected=0i,total_uncorrected_errors=0i 1715282104914128775\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/scsi_extended/response.json",
    "content": "{\n    \"json_format_version\": [\n      1,\n      0\n    ],\n    \"smartctl\": {\n      \"version\": [\n        7,\n        4\n      ],\n      \"pre_release\": false,\n      \"svn_revision\": \"6328\",\n      \"platform_info\": \"x86_64-linux-4.14.0-1-amd64\",\n      \"build_info\": \"(local build)\",\n      \"argv\": [\n        \"smartctl\",\n        \"--json\",\n        \"--all\",\n        \"/dev/sdaa\",\n        \"--device\",\n        \"scsi\"\n      ],\n      \"exit_status\": 0\n    },\n    \"local_time\": {\n      \"time_t\": 1712853808,\n      \"asctime\": \"Thu Apr 11 16:43:28 2024 UTC\"\n    },\n    \"device\": {\n      \"name\": \"/dev/sdaa\",\n      \"info_name\": \"/dev/sdaa\",\n      \"type\": \"scsi\",\n      \"protocol\": \"SCSI\"\n    },\n    \"scsi_vendor\": \"XYZZZZZZ\",\n    \"scsi_product\": \"ST100000000\",\n    \"scsi_model_name\": \"SEAGATE ST0000000\",\n    \"scsi_revision\": \"RSL5\",\n    \"scsi_version\": \"SPC-5\",\n    \"user_capacity\": {\n      \"blocks\": 26789019748,\n      \"bytes\": 13715978079776\n    },\n    \"logical_block_size\": 512,\n    \"physical_block_size\": 4096,\n    \"scsi_protection_type\": 2,\n    \"scsi_protection_interval_bytes_per_lb\": 8,\n    \"scsi_lb_provisioning\": {\n      \"name\": \"fully provisioned\",\n      \"value\": 0,\n      \"management_enabled\": {\n        \"name\": \"LBPME\",\n        \"value\": 0\n      },\n      \"read_zeros\": {\n        \"name\": \"LBPRZ\",\n        \"value\": 0\n      }\n    },\n    \"rotation_rate\": 7200,\n    \"form_factor\": {\n      \"scsi_value\": 2,\n      \"name\": \"3.5 inches\"\n    },\n    \"logical_unit_id\": \"0x5000cb0847\",\n    \"serial_number\": \"XYZZZZ\",\n    \"device_type\": {\n      \"scsi_terminology\": \"Peripheral Device Type [PDT]\",\n      \"scsi_value\": 0,\n      \"name\": \"disk\"\n    },\n    \"scsi_transport_protocol\": {\n      \"name\": \"SAS (SPL-4)\",\n      \"value\": 6\n    },\n    \"smart_support\": {\n      \"available\": true,\n      \"enabled\": true\n    },\n    \"temperature_warning\": {\n      \"enabled\": true\n    },\n    \"smart_status\": {\n      \"passed\": true\n    },\n    \"temperature\": {\n      \"current\": 24,\n      \"drive_trip\": 60\n    },\n    \"power_on_time\": {\n      \"hours\": 34222,\n      \"minutes\": 9\n    },\n    \"scsi_start_stop_cycle_counter\": {\n      \"year_of_manufacture\": \"2019\",\n      \"week_of_manufacture\": \"35\",\n      \"specified_cycle_count_over_device_lifetime\": 50000,\n      \"accumulated_start_stop_cycles\": 220,\n      \"specified_load_unload_count_over_device_lifetime\": 600000,\n      \"accumulated_load_unload_cycles\": 1606\n    },\n    \"scsi_grown_defect_list\": 0,\n    \"seagate_farm_log\": {\n      \"supported\": true\n    },\n    \"scsi_error_counter_log\": {\n      \"read\": {\n        \"errors_corrected_by_eccfast\": 0,\n        \"errors_corrected_by_eccdelayed\": 0,\n        \"errors_corrected_by_rereads_rewrites\": 0,\n        \"total_errors_corrected\": 0,\n        \"correction_algorithm_invocations\": 0,\n        \"gigabytes_processed\": \"316009.846\",\n        \"total_uncorrected_errors\": 0\n      },\n      \"write\": {\n        \"errors_corrected_by_eccfast\": 0,\n        \"errors_corrected_by_eccdelayed\": 0,\n        \"errors_corrected_by_rereads_rewrites\": 20,\n        \"total_errors_corrected\": 20,\n        \"correction_algorithm_invocations\": 20,\n        \"gigabytes_processed\": \"132824.923\",\n        \"total_uncorrected_errors\": 0\n      },\n      \"verify\": {\n        \"errors_corrected_by_eccfast\": 0,\n        \"errors_corrected_by_eccdelayed\": 0,\n        \"errors_corrected_by_rereads_rewrites\": 0,\n        \"total_errors_corrected\": 0,\n        \"correction_algorithm_invocations\": 0,\n        \"gigabytes_processed\": \"1467.278\",\n        \"total_uncorrected_errors\": 0\n      }\n    },\n    \"scsi_self_test_0\": {\n      \"code\": {\n        \"value\": 2,\n        \"string\": \"Background long\"\n      },\n      \"result\": {\n        \"value\": 0,\n        \"string\": \"Completed\"\n      },\n      \"power_on_time\": {\n        \"hours\": 90,\n        \"aka\": \"accumulated_power_on_hours\"\n      }\n    },\n    \"scsi_self_test_1\": {\n      \"code\": {\n        \"value\": 2,\n        \"string\": \"Background long\"\n      },\n      \"result\": {\n        \"value\": 0,\n        \"string\": \"Completed\"\n      },\n      \"power_on_time\": {\n        \"hours\": 66,\n        \"aka\": \"accumulated_power_on_hours\"\n      }\n    },\n    \"scsi_self_test_2\": {\n      \"code\": {\n        \"value\": 7,\n        \"string\": \"Reserved(7)\"\n      },\n      \"result\": {\n        \"value\": 0,\n        \"string\": \"Completed\"\n      },\n      \"failed_segment\": {\n        \"value\": 80,\n        \"aka\": \"self_test_number\"\n      },\n      \"power_on_time\": {\n        \"hours\": 5,\n        \"aka\": \"accumulated_power_on_hours\"\n      }\n    },\n    \"scsi_self_test_3\": {\n      \"code\": {\n        \"value\": 1,\n        \"string\": \"Background short\"\n      },\n      \"result\": {\n        \"value\": 0,\n        \"string\": \"Completed\"\n      },\n      \"power_on_time\": {\n        \"hours\": 2,\n        \"aka\": \"accumulated_power_on_hours\"\n      }\n    },\n    \"scsi_extended_self_test_seconds\": 80400\n  }\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/usb/device",
    "content": "/dev/sda\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/usb/deviceType",
    "content": "sat\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/usb/expected.out",
    "content": "smartctl,model=SanDisk\\ pSSD,name=/dev/sda,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c capacity=15693664256i,firmware=\"3\",health_ok=true,logical_block_size=512i,power_on_hours=11i,temperature=0i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Reallocated_Sector_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Power_On_Hours,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=11i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Power_Cycle_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=223i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Program_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Erase_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Avg_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=3i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Unexpect_Power_Loss_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=114i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Reported_Uncorrect,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Avail_Resrvd_Space,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=5i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Perc_Write/Erase_Ct_BC,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Total_LBAs_Written,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10171055i,threshold=0i,value=100i,worst=100i 1711480345675066854\nsmartctl_attributes,model=SanDisk\\ pSSD,name=Total_LBAs_Read,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=94845144i,threshold=0i,value=100i,worst=100i 1711480345675066854\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_device/usb/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      4\n    ],\n    \"pre_release\": false,\n    \"svn_revision\": \"5530\",\n    \"platform_info\": \"x86_64-linux-6.8.1-arch1-1\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"-a\",\n      \"-d\",\n      \"sat\",\n      \"/dev/sda\",\n      \"--json\"\n    ],\n    \"drive_database_version\": {\n      \"string\": \"7.3/5528\"\n    },\n    \"exit_status\": 0\n  },\n  \"local_time\": {\n    \"time_t\": 1711370961,\n    \"asctime\": \"Mon Mar 25 06:49:21 2024 MDT\"\n  },\n  \"device\": {\n    \"name\": \"/dev/sda\",\n    \"info_name\": \"/dev/sda [SAT]\",\n    \"type\": \"sat\",\n    \"protocol\": \"ATA\"\n  },\n  \"model_family\": \"SanDisk based SSDs\",\n  \"model_name\": \"SanDisk pSSD\",\n  \"serial_number\": \"06c9f4c44\",\n  \"wwn\": {\n    \"naa\": 5,\n    \"oui\": 6980,\n    \"id\": 2674672716\n  },\n  \"firmware_version\": \"3\",\n  \"user_capacity\": {\n    \"blocks\": 30651688,\n    \"bytes\": 15693664256\n  },\n  \"logical_block_size\": 512,\n  \"physical_block_size\": 512,\n  \"rotation_rate\": 0,\n  \"form_factor\": {\n    \"ata_value\": 4,\n    \"name\": \"1.8 inches\"\n  },\n  \"trim\": {\n    \"supported\": true,\n    \"deterministic\": true,\n    \"zeroed\": true\n  },\n  \"in_smartctl_database\": true,\n  \"ata_version\": {\n    \"string\": \"ATA8-ACS T13/1699-D revision 2d\",\n    \"major_value\": 496,\n    \"minor_value\": 263\n  },\n  \"sata_version\": {\n    \"string\": \"SATA 2.6\",\n    \"value\": 17\n  },\n  \"interface_speed\": {\n    \"max\": {\n      \"sata_value\": 14,\n      \"string\": \"6.0 Gb/s\",\n      \"units_per_second\": 60,\n      \"bits_per_unit\": 100000000\n    },\n    \"current\": {\n      \"sata_value\": 2,\n      \"string\": \"3.0 Gb/s\",\n      \"units_per_second\": 30,\n      \"bits_per_unit\": 100000000\n    }\n  },\n  \"smart_support\": {\n    \"available\": true,\n    \"enabled\": true\n  },\n  \"smart_status\": {\n    \"passed\": true\n  },\n  \"ata_smart_data\": {\n    \"offline_data_collection\": {\n      \"status\": {\n        \"value\": 0,\n        \"string\": \"was never started\"\n      },\n      \"completion_seconds\": 120\n    },\n    \"self_test\": {\n      \"status\": {\n        \"value\": 0,\n        \"string\": \"completed without error\",\n        \"passed\": true\n      },\n      \"polling_minutes\": {\n        \"short\": 2,\n        \"extended\": 3\n      }\n    },\n    \"capabilities\": {\n      \"values\": [\n        81,\n        3\n      ],\n      \"exec_offline_immediate_supported\": true,\n      \"offline_is_aborted_upon_new_cmd\": false,\n      \"offline_surface_scan_supported\": false,\n      \"self_tests_supported\": true,\n      \"conveyance_self_test_supported\": false,\n      \"selective_self_test_supported\": true,\n      \"attribute_autosave_enabled\": true,\n      \"error_logging_supported\": true,\n      \"gp_logging_supported\": true\n    }\n  },\n  \"ata_smart_attributes\": {\n    \"revision\": 1,\n    \"table\": [\n      {\n        \"id\": 5,\n        \"name\": \"Reallocated_Sector_Ct\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 9,\n        \"name\": \"Power_On_Hours\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 11,\n          \"string\": \"11\"\n        }\n      },\n      {\n        \"id\": 12,\n        \"name\": \"Power_Cycle_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 223,\n          \"string\": \"223\"\n        }\n      },\n      {\n        \"id\": 171,\n        \"name\": \"Program_Fail_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 172,\n        \"name\": \"Erase_Fail_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 173,\n        \"name\": \"Avg_Write/Erase_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 3,\n          \"string\": \"3\"\n        }\n      },\n      {\n        \"id\": 174,\n        \"name\": \"Unexpect_Power_Loss_Ct\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 114,\n          \"string\": \"114\"\n        }\n      },\n      {\n        \"id\": 187,\n        \"name\": \"Reported_Uncorrect\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 230,\n        \"name\": \"Perc_Write/Erase_Count\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 10,\n          \"string\": \"10\"\n        }\n      },\n      {\n        \"id\": 232,\n        \"name\": \"Perc_Avail_Resrvd_Space\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 5,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 3,\n          \"string\": \"PO---- \",\n          \"prefailure\": true,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 234,\n        \"name\": \"Perc_Write/Erase_Ct_BC\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 0,\n          \"string\": \"0\"\n        }\n      },\n      {\n        \"id\": 241,\n        \"name\": \"Total_LBAs_Written\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 10171055,\n          \"string\": \"10171055\"\n        }\n      },\n      {\n        \"id\": 242,\n        \"name\": \"Total_LBAs_Read\",\n        \"value\": 100,\n        \"worst\": 100,\n        \"thresh\": 0,\n        \"when_failed\": \"\",\n        \"flags\": {\n          \"value\": 2,\n          \"string\": \"-O---- \",\n          \"prefailure\": false,\n          \"updated_online\": true,\n          \"performance\": false,\n          \"error_rate\": false,\n          \"event_count\": false,\n          \"auto_keep\": false\n        },\n        \"raw\": {\n          \"value\": 94845144,\n          \"string\": \"94845144\"\n        }\n      }\n    ]\n  },\n  \"power_on_time\": {\n    \"hours\": 11\n  },\n  \"power_cycle_count\": 223,\n  \"ata_smart_error_log\": {\n    \"summary\": {\n      \"revision\": 1,\n      \"count\": 0\n    }\n  },\n  \"ata_smart_self_test_log\": {\n    \"standard\": {\n      \"revision\": 1,\n      \"count\": 0\n    }\n  },\n  \"ata_smart_selective_self_test_log\": {\n    \"revision\": 1,\n    \"table\": [\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      },\n      {\n        \"lba_min\": 0,\n        \"lba_max\": 0,\n        \"status\": {\n          \"value\": 0,\n          \"string\": \"Not_testing\"\n        }\n      }\n    ],\n    \"flags\": {\n      \"value\": 0,\n      \"remainder_scan_enabled\": false\n    },\n    \"power_up_scan_resume_minutes\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/all/expected.out",
    "content": "3\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/all/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      4\n    ],\n    \"pre_release\": false,\n    \"svn_revision\": \"5530\",\n    \"platform_info\": \"x86_64-linux-6.8.1-arch1-1\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--scan\",\n      \"--json\"\n    ],\n    \"exit_status\": 0\n  },\n  \"devices\": [\n    {\n      \"name\": \"/dev/sda\",\n      \"info_name\": \"/dev/sda [SAT]\",\n      \"type\": \"sat\",\n      \"protocol\": \"ATA\"\n    },\n    {\n      \"name\": \"/dev/nvme0\",\n      \"info_name\": \"/dev/nvme0\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    },\n    {\n      \"name\": \"/dev/nvme1\",\n      \"info_name\": \"/dev/nvme1\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/all/telegraf.toml",
    "content": "[[inputs.smartctl]]\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/exclude/expected.out",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/exclude/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      4\n    ],\n    \"pre_release\": false,\n    \"svn_revision\": \"5530\",\n    \"platform_info\": \"x86_64-linux-6.8.1-arch1-1\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--scan\",\n      \"--json\"\n    ],\n    \"exit_status\": 0\n  },\n  \"devices\": [\n    {\n      \"name\": \"/dev/sda\",\n      \"info_name\": \"/dev/sda [SAT]\",\n      \"type\": \"sat\",\n      \"protocol\": \"ATA\"\n    },\n    {\n      \"name\": \"/dev/nvme0\",\n      \"info_name\": \"/dev/nvme0\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    },\n    {\n      \"name\": \"/dev/nvme1\",\n      \"info_name\": \"/dev/nvme1\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/exclude/telegraf.toml",
    "content": "[[inputs.smartctl]]\n    devices_exclude = [\"/dev/nvme0\", \"/dev/nvme1\"]\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/include/expected.out",
    "content": "1\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/include/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      4\n    ],\n    \"pre_release\": false,\n    \"svn_revision\": \"5530\",\n    \"platform_info\": \"x86_64-linux-6.8.1-arch1-1\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--scan\",\n      \"--json\"\n    ],\n    \"exit_status\": 0\n  },\n  \"devices\": [\n    {\n      \"name\": \"/dev/sda\",\n      \"info_name\": \"/dev/sda [SAT]\",\n      \"type\": \"sat\",\n      \"protocol\": \"ATA\"\n    },\n    {\n      \"name\": \"/dev/nvme0\",\n      \"info_name\": \"/dev/nvme0\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    },\n    {\n      \"name\": \"/dev/nvme1\",\n      \"info_name\": \"/dev/nvme1\",\n      \"type\": \"nvme\",\n      \"protocol\": \"NVMe\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/include/telegraf.toml",
    "content": "[[inputs.smartctl]]\n    devices_include = [\"/dev/sda\"]\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/megaraid/expected.out",
    "content": "10\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/megaraid/response.json",
    "content": "{\n  \"json_format_version\": [\n    1,\n    0\n  ],\n  \"smartctl\": {\n    \"version\": [\n      7,\n      1\n    ],\n    \"svn_revision\": \"5022\",\n    \"platform_info\": \"x86_64-linux-5.4.0-172-generic\",\n    \"build_info\": \"(local build)\",\n    \"argv\": [\n      \"smartctl\",\n      \"--scan\",\n      \"--json\"\n    ],\n    \"exit_status\": 0\n  },\n  \"devices\": [\n    {\n      \"name\": \"/dev/sda\",\n      \"info_name\": \"/dev/sda\",\n      \"type\": \"scsi\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/sdb\",\n      \"info_name\": \"/dev/sdb\",\n      \"type\": \"scsi\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/sdc\",\n      \"info_name\": \"/dev/sdc [SAT]\",\n      \"type\": \"sat\",\n      \"protocol\": \"ATA\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_08]\",\n      \"type\": \"megaraid,8\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_09]\",\n      \"type\": \"megaraid,9\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_10]\",\n      \"type\": \"megaraid,10\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_11]\",\n      \"type\": \"megaraid,11\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_12]\",\n      \"type\": \"megaraid,12\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_13]\",\n      \"type\": \"megaraid,13\",\n      \"protocol\": \"SCSI\"\n    },\n    {\n      \"name\": \"/dev/bus/6\",\n      \"info_name\": \"/dev/bus/6 [megaraid_disk_14]\",\n      \"type\": \"megaraid,14\",\n      \"protocol\": \"SCSI\"\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/smartctl/testcases_scan/megaraid/telegraf.toml",
    "content": "[[inputs.smartctl]]\n"
  },
  {
    "path": "plugins/inputs/snmp/README.md",
    "content": "# SNMP Input Plugin\n\nThis plugin gathers metrics by polling [SNMP][snmp] agents with individual OIDs\nor complete SNMP tables.\n\n> [!NOTE]\n> The path setting is shared between all instances of all SNMP plugin types!\n\n⭐ Telegraf v0.10.1\n🏷️ hardware, network\n💻 all\n\n[snmp]: https://datatracker.ietf.org/doc/html/rfc1157\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `auth_password` and\n`priv_password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Retrieves SNMP values from remote agents\n[[inputs.snmp]]\n  ## Agent addresses to retrieve values from.\n  ##   format:  agents = [\"<scheme://><hostname>:<port>\"]\n  ##   scheme:  optional, either udp, udp4, udp6, tcp, tcp4, tcp6.\n  ##            default is udp\n  ##   port:    optional\n  ##   example: agents = [\"udp://127.0.0.1:161\"]\n  ##            agents = [\"tcp://127.0.0.1:161\"]\n  ##            agents = [\"udp4://v4only-snmp-agent\"]\n  agents = [\"udp://127.0.0.1:161\"]\n\n  ## Timeout for each request.\n  # timeout = \"5s\"\n\n  ## Stop polling tables if polling fails on the same agent\n  # stop_on_error = false\n\n  ## SNMP version; can be 1, 2, or 3.\n  # version = 2\n\n  ## Unconnected UDP socket\n  ## When true, SNMP responses are accepted from any address not just\n  ## the requested address. This can be useful when gathering from\n  ## redundant/failover systems.\n  # unconnected_udp_socket = false\n\n  ## Path to mib files\n  ## Used by the gosmi translator.\n  ## To add paths when translating with netsnmp, use the MIBDIRS environment variable\n  # path = [\"/usr/share/snmp/mibs\"]\n\n  ## SNMP community string.\n  # community = \"public\"\n\n  ## Agent host tag; should be set to \"source\" for consistent usage across plugins\n  ##   example: agent_host_tag = \"source\"\n  ## The default value is inconsistent with other plugins. Users will get a\n  ## warning that can be ignored if this is not changed. However, to have a\n  ## consistent experience, set this to \"source\" in your config to align with\n  ## other plugins.\n  # agent_host_tag = \"agent_host\"\n\n  ## Number of retries to attempt.\n  # retries = 3\n\n  ## The GETBULK max-repetitions parameter.\n  # max_repetitions = 10\n\n  ## SNMPv3 authentication and encryption options.\n  ##\n  ## Security Name.\n  # sec_name = \"myuser\"\n  ## Authentication protocol; one of \"MD5\", \"SHA\", \"SHA224\", \"SHA256\", \"SHA384\", \"SHA512\" or \"\".\n  # auth_protocol = \"MD5\"\n  ## Authentication password.\n  # auth_password = \"pass\"\n  ## Security Level; one of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\".\n  # sec_level = \"authNoPriv\"\n  ## Context Name.\n  # context_name = \"\"\n  ## Privacy protocol used for encrypted messages; one of \"DES\", \"AES\", \"AES192\", \"AES192C\", \"AES256\", \"AES256C\", or \"\".\n  ### Protocols \"AES192\", \"AES192\", \"AES256\", and \"AES256C\" require the underlying net-snmp tools\n  ### to be compiled with --enable-blumenthal-aes (http://www.net-snmp.org/docs/INSTALL.html)\n  # priv_protocol = \"\"\n  ## Privacy password used for encrypted messages.\n  # priv_password = \"\"\n\n  ## Add fields and tables defining the variables you wish to collect.  This\n  ## example collects the system uptime and interface variables.  Reference the\n  ## full plugin documentation for configuration details.\n  [[inputs.snmp.field]]\n    oid = \"RFC1213-MIB::sysUpTime.0\"\n    name = \"sysUptime\"\n    conversion = \"float(2)\"\n\n  [[inputs.snmp.field]]\n    oid = \"RFC1213-MIB::sysName.0\"\n    name = \"sysName\"\n    is_tag = true\n\n  [[inputs.snmp.table]]\n    oid = \"IF-MIB::ifTable\"\n    name = \"interface\"\n    inherit_tags = [\"sysName\"]\n\n    [[inputs.snmp.table.field]]\n      oid = \"IF-MIB::ifDescr\"\n      name = \"ifDescr\"\n      is_tag = true\n```\n\n### SNMP backend: `gosmi` vs `netsnmp`\n\nThis plugin supports two backends to translate SNMP objects. By default,\nTelegraf will use `netsnmp`, however, this option is deprecated and it is\nencouraged to migrate to `gosmi`. If users find issues with `gosmi` that do not\noccur with `netsnmp` please open a project issue on GitHub.\n\nThe SNMP backend setting is a global-level setting that applies to all use of\nSNMP in Telegraf. Users can set this option in the `[agent]` configuration via\nthe `snmp_translator` option. See the [agent configuration][agent] for more\ndetails.\n\n[agent]: /docs/CONFIGURATION.md#agent\n\n### Configure SNMP Requests\n\nThis plugin provides two methods for configuring the SNMP requests: `fields`\nand `tables`.  Use the `field` option to gather single ad-hoc variables.\nTo collect SNMP tables, use the `table` option.\n\n#### Field\n\nUse a `field` to collect a variable by OID.  Requests specified with this\noption operate similar to the `snmpget` utility.\n\n```toml\n[[inputs.snmp]]\n  # ... snip ...\n\n  [[inputs.snmp.field]]\n    ## Object identifier of the variable as a numeric or textual OID.\n    oid = \"RFC1213-MIB::sysName.0\"\n\n    ## Name of the field or tag to create.  If not specified, it defaults to\n    ## the value of 'oid'. If 'oid' is numeric, an attempt to translate the\n    ## numeric OID into a textual OID will be made.\n    # name = \"\"\n\n    ## If true the variable will be added as a tag, otherwise a field will be\n    ## created.\n    # is_tag = false\n\n    ## Apply one of the following conversions to the variable value:\n    ##   float(X):    Convert the input value into a float and divides by the\n    ##                Xth power of 10. Effectively just moves the decimal left\n    ##                X places. For example a value of `123` with `float(2)`\n    ##                will result in `1.23`.\n    ##   float:       Convert the value into a float with no adjustment. Same\n    ##                as `float(0)`.\n    ##   int:         Convert the value into an integer.\n    ##   ipaddr:      Convert the value to an IP address.\n    ##   hex:         Convert bytes to a hex string.\n    ##   hextoint:X:Y Convert bytes to integer, where X is the endian and Y the\n    ##                bit size. For example: hextoint:LittleEndian:uint64 or\n    ##                hextoint:BigEndian:uint32. Valid options for the endian\n    ##                are: BigEndian and LittleEndian. For the bit size:\n    ##                uint16, uint32 and uint64.\n    ##   enum:        Convert the value according to its syntax in the MIB.\n    ##                (Only supported with gosmi translator)\n    ##   displayhint: Format the value according to the textual convention in the MIB.\n    ##                (Only supported with gosmi translator)\n    ##\n    # conversion = \"\"\n```\n\n#### Table\n\nUse a `table` to configure the collection of a SNMP table.  SNMP requests\nformed with this option operate similarly way to the `snmptable` command.\n\nControl the handling of specific table columns using a nested `field`.  These\nnested fields are specified similarly to a top-level `field`.\n\nBy default all columns of the SNMP table will be collected - it is not required\nto add a nested field for each column, only those which you wish to modify. To\n*only* collect certain columns, omit the `oid` from the `table` section and only\ninclude `oid` settings in `field` sections. For more complex include/exclude\ncases for columns use [metric filtering][filtering].\n\nOne metric is created for each row of the SNMP table.\n\n```toml\n[[inputs.snmp]]\n  # ... snip ...\n\n  [[inputs.snmp.table]]\n    ## Object identifier of the SNMP table as a numeric or textual OID.\n    oid = \"IF-MIB::ifTable\"\n\n    ## Name of the field or tag to create.  If not specified, it defaults to\n    ## the value of 'oid'.  If 'oid' is numeric an attempt to translate the\n    ## numeric OID into a textual OID will be made.\n    # name = \"\"\n\n    ## Which tags to inherit from the top-level config and to use in the output\n    ## of this table's measurement.\n    ## example: inherit_tags = [\"source\"]\n    # inherit_tags = []\n\n    ## Add an 'index' tag with the table row number.  Use this if the table has\n    ## no indexes or if you are excluding them.  This option is normally not\n    ## required as any index columns are automatically added as tags.\n    # index_as_tag = false\n\n    [[inputs.snmp.table.field]]\n      ## OID to get. May be a numeric or textual module-qualified OID.\n      oid = \"IF-MIB::ifDescr\"\n\n      ## Name of the field or tag to create.  If not specified, it defaults to\n      ## the value of 'oid'. If 'oid' is numeric an attempt to translate the\n      ## numeric OID into a textual OID will be made.\n      # name = \"\"\n\n      ## Output this field as a tag.\n      # is_tag = false\n\n      ## The OID sub-identifier to strip off so that the index can be matched\n      ## against other fields in the table.\n      # oid_index_suffix = \"\"\n\n      ## Specifies the length of the index after the supplied table OID (in OID\n      ## path segments). Truncates the index after this point to remove non-fixed\n      ## value or length index suffixes.\n      # oid_index_length = 0\n\n      ## Specifies if the value of given field should be snmptranslated\n      ## by default no field values are translated\n      # translate = true\n\n      ## Secondary index table allows to merge data from two tables with\n      ## different index that this filed will be used to join them. There can\n      ## be only one secondary index table.\n      # secondary_index_table = false\n\n      ## This field is using secondary index, and will be later merged with\n      ## primary index using SecondaryIndexTable. SecondaryIndexTable and\n      ## SecondaryIndexUse are exclusive.\n      # secondary_index_use = false\n\n      ## Controls if entries from secondary table should be added or not\n      ## if joining index is present or not. I set to true, means that join\n      ## is outer, and index is prepended with \"Secondary.\" for missing values\n      ## to avoid overlapping indexes from both tables. Can be set per field or\n      ## globally with SecondaryIndexTable, global true overrides per field false.\n      # secondary_outer_join = false\n```\n\n[filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n#### Two Table Join\n\nSnmp plugin can join two snmp tables that have different indexes. For this to\nwork one table should have translation field that return index of second table\nas value. Examples of such fields are:\n\n* Cisco portTable with translation field: `CISCO-STACK-MIB::portIfIndex`,\nwhich value is IfIndex from ifTable\n* Adva entityFacilityTable with translation field: `ADVA-FSPR7-MIB::entityFacilityOneIndex`,\nwhich value is IfIndex from ifTable\n* Cisco cpeExtPsePortTable with translation field: `CISCO-POWER-ETHERNET-EXT-MIB::cpeExtPsePortEntPhyIndex`,\nwhich value is index from entPhysicalTable\n\nSuch field can be used to translate index to secondary table with\n`secondary_index_table = true` and all fields from secondary table (with index\npointed from translation field), should have added option `secondary_index_use =\ntrue`. Telegraf cannot duplicate entries during join so translation must be\n1-to-1 (not 1-to-many). To add fields from secondary table with index that is\nnot present in translation table (outer join), there is a second option for\ntranslation index `secondary_outer_join = true`.\n\n##### Example configuration for table joins\n\nCISCO-POWER-ETHERNET-EXT-MIB table before join:\n\n```toml\n[[inputs.snmp.table]]\nname = \"ciscoPower\"\nindex_as_tag = true\n\n[[inputs.snmp.table.field]]\nname = \"PortPwrConsumption\"\noid = \"CISCO-POWER-ETHERNET-EXT-MIB::cpeExtPsePortPwrConsumption\"\n\n[[inputs.snmp.table.field]]\nname = \"EntPhyIndex\"\noid = \"CISCO-POWER-ETHERNET-EXT-MIB::cpeExtPsePortEntPhyIndex\"\n```\n\nPartial result (removed agent and host tags from all following outputs\nin this section):\n\n```text\n> ciscoPower,index=1.2 EntPhyIndex=1002i,PortPwrConsumption=6643i 1621460628000000000\n> ciscoPower,index=1.6 EntPhyIndex=1006i,PortPwrConsumption=10287i 1621460628000000000\n> ciscoPower,index=1.5 EntPhyIndex=1005i,PortPwrConsumption=8358i 1621460628000000000\n```\n\nNote here that EntPhyIndex column carries index from ENTITY-MIB table, config\nfor it:\n\n```toml\n[[inputs.snmp.table]]\nname = \"entityTable\"\nindex_as_tag = true\n\n[[inputs.snmp.table.field]]\nname = \"EntPhysicalName\"\noid = \"ENTITY-MIB::entPhysicalName\"\n```\n\nPartial result:\n\n```text\n> entityTable,index=1006 EntPhysicalName=\"GigabitEthernet1/6\" 1621460809000000000\n> entityTable,index=1002 EntPhysicalName=\"GigabitEthernet1/2\" 1621460809000000000\n> entityTable,index=1005 EntPhysicalName=\"GigabitEthernet1/5\" 1621460809000000000\n```\n\nNow, lets attempt to join these results into one table. EntPhyIndex matches\nindex from second table, and lets convert EntPhysicalName into tag, so second\ntable will only provide tags into result. Configuration:\n\n```toml\n[[inputs.snmp.table]]\nname = \"ciscoPowerEntity\"\nindex_as_tag = true\n\n[[inputs.snmp.table.field]]\nname = \"PortPwrConsumption\"\noid = \"CISCO-POWER-ETHERNET-EXT-MIB::cpeExtPsePortPwrConsumption\"\n\n[[inputs.snmp.table.field]]\nname = \"EntPhyIndex\"\noid = \"CISCO-POWER-ETHERNET-EXT-MIB::cpeExtPsePortEntPhyIndex\"\nsecondary_index_table = true    # enables joining\n\n[[inputs.snmp.table.field]]\nname = \"EntPhysicalName\"\noid = \"ENTITY-MIB::entPhysicalName\"\nsecondary_index_use = true      # this tag is indexed from secondary table\nis_tag = true\n```\n\nResult:\n\n```text\n> ciscoPowerEntity,EntPhysicalName=GigabitEthernet1/2,index=1.2 EntPhyIndex=1002i,PortPwrConsumption=6643i 1621461148000000000\n> ciscoPowerEntity,EntPhysicalName=GigabitEthernet1/6,index=1.6 EntPhyIndex=1006i,PortPwrConsumption=10287i 1621461148000000000\n> ciscoPowerEntity,EntPhysicalName=GigabitEthernet1/5,index=1.5 EntPhyIndex=1005i,PortPwrConsumption=8358i 1621461148000000000\n```\n\n## Troubleshooting\n\nCheck that a numeric field can be translated to a textual field:\n\n```sh\n$ snmptranslate .1.3.6.1.2.1.1.3.0\nDISMAN-EVENT-MIB::sysUpTimeInstance\n```\n\nRequest a top-level field:\n\n```sh\nsnmpget -v2c -c public 127.0.0.1 sysUpTime.0\n```\n\nRequest a table:\n\n```sh\nsnmptable -v2c -c public 127.0.0.1 ifTable\n```\n\nTo collect a packet capture, run this command in the background while running\nTelegraf or one of the above commands.  Adjust the interface, host and port as\nneeded:\n\n```sh\nsudo tcpdump -s 0 -i eth0 -w telegraf-snmp.pcap host 127.0.0.1 and port 161\n```\n\n## Metrics\n\nThe field and tags will depend on the table and fields configured.\n\n* snmp\n  * tags:\n    * agent_host (deprecated in 1.29: use `source` instead)\n\n## Example Output\n\n```text\nsnmp,agent_host=127.0.0.1,sysName=example.org uptime=113319.74 1575509815000000000\ninterface,agent_host=127.0.0.1,ifDescr=wlan0,ifIndex=3,sysName=example.org ifAdminStatus=1i,ifInDiscards=0i,ifInErrors=0i,ifInNUcastPkts=0i,ifInOctets=3436617431i,ifInUcastPkts=2717778i,ifInUnknownProtos=0i,ifLastChange=0i,ifMtu=1500i,ifOperStatus=1i,ifOutDiscards=0i,ifOutErrors=0i,ifOutNUcastPkts=0i,ifOutOctets=581368041i,ifOutQLen=0i,ifOutUcastPkts=1354338i,ifPhysAddress=\"c8:5b:76:c9:e6:8c\",ifSpecific=\".0.0\",ifSpeed=0i,ifType=6i 1575509815000000000\ninterface,agent_host=127.0.0.1,ifDescr=eth0,ifIndex=2,sysName=example.org ifAdminStatus=1i,ifInDiscards=0i,ifInErrors=0i,ifInNUcastPkts=21i,ifInOctets=3852386380i,ifInUcastPkts=3634004i,ifInUnknownProtos=0i,ifLastChange=9088763i,ifMtu=1500i,ifOperStatus=1i,ifOutDiscards=0i,ifOutErrors=0i,ifOutNUcastPkts=0i,ifOutOctets=434865441i,ifOutQLen=0i,ifOutUcastPkts=2110394i,ifPhysAddress=\"c8:5b:76:c9:e6:8c\",ifSpecific=\".0.0\",ifSpeed=1000000000i,ifType=6i 1575509815000000000\ninterface,agent_host=127.0.0.1,ifDescr=lo,ifIndex=1,sysName=example.org ifAdminStatus=1i,ifInDiscards=0i,ifInErrors=0i,ifInNUcastPkts=0i,ifInOctets=51555569i,ifInUcastPkts=339097i,ifInUnknownProtos=0i,ifLastChange=0i,ifMtu=65536i,ifOperStatus=1i,ifOutDiscards=0i,ifOutErrors=0i,ifOutNUcastPkts=0i,ifOutOctets=51555569i,ifOutQLen=0i,ifOutUcastPkts=339097i,ifSpecific=\".0.0\",ifSpeed=10000000i,ifType=24i 1575509815000000000\n```\n"
  },
  {
    "path": "plugins/inputs/snmp/sample.conf",
    "content": "# Retrieves SNMP values from remote agents\n[[inputs.snmp]]\n  ## Agent addresses to retrieve values from.\n  ##   format:  agents = [\"<scheme://><hostname>:<port>\"]\n  ##   scheme:  optional, either udp, udp4, udp6, tcp, tcp4, tcp6.\n  ##            default is udp\n  ##   port:    optional\n  ##   example: agents = [\"udp://127.0.0.1:161\"]\n  ##            agents = [\"tcp://127.0.0.1:161\"]\n  ##            agents = [\"udp4://v4only-snmp-agent\"]\n  agents = [\"udp://127.0.0.1:161\"]\n\n  ## Timeout for each request.\n  # timeout = \"5s\"\n\n  ## Stop polling tables if polling fails on the same agent\n  # stop_on_error = false\n\n  ## SNMP version; can be 1, 2, or 3.\n  # version = 2\n\n  ## Unconnected UDP socket\n  ## When true, SNMP responses are accepted from any address not just\n  ## the requested address. This can be useful when gathering from\n  ## redundant/failover systems.\n  # unconnected_udp_socket = false\n\n  ## Path to mib files\n  ## Used by the gosmi translator.\n  ## To add paths when translating with netsnmp, use the MIBDIRS environment variable\n  # path = [\"/usr/share/snmp/mibs\"]\n\n  ## SNMP community string.\n  # community = \"public\"\n\n  ## Agent host tag; should be set to \"source\" for consistent usage across plugins\n  ##   example: agent_host_tag = \"source\"\n  ## The default value is inconsistent with other plugins. Users will get a\n  ## warning that can be ignored if this is not changed. However, to have a\n  ## consistent experience, set this to \"source\" in your config to align with\n  ## other plugins.\n  # agent_host_tag = \"agent_host\"\n\n  ## Number of retries to attempt.\n  # retries = 3\n\n  ## The GETBULK max-repetitions parameter.\n  # max_repetitions = 10\n\n  ## SNMPv3 authentication and encryption options.\n  ##\n  ## Security Name.\n  # sec_name = \"myuser\"\n  ## Authentication protocol; one of \"MD5\", \"SHA\", \"SHA224\", \"SHA256\", \"SHA384\", \"SHA512\" or \"\".\n  # auth_protocol = \"MD5\"\n  ## Authentication password.\n  # auth_password = \"pass\"\n  ## Security Level; one of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\".\n  # sec_level = \"authNoPriv\"\n  ## Context Name.\n  # context_name = \"\"\n  ## Privacy protocol used for encrypted messages; one of \"DES\", \"AES\", \"AES192\", \"AES192C\", \"AES256\", \"AES256C\", or \"\".\n  ### Protocols \"AES192\", \"AES192\", \"AES256\", and \"AES256C\" require the underlying net-snmp tools\n  ### to be compiled with --enable-blumenthal-aes (http://www.net-snmp.org/docs/INSTALL.html)\n  # priv_protocol = \"\"\n  ## Privacy password used for encrypted messages.\n  # priv_password = \"\"\n\n  ## Add fields and tables defining the variables you wish to collect.  This\n  ## example collects the system uptime and interface variables.  Reference the\n  ## full plugin documentation for configuration details.\n  [[inputs.snmp.field]]\n    oid = \"RFC1213-MIB::sysUpTime.0\"\n    name = \"sysUptime\"\n    conversion = \"float(2)\"\n\n  [[inputs.snmp.field]]\n    oid = \"RFC1213-MIB::sysName.0\"\n    name = \"sysName\"\n    is_tag = true\n\n  [[inputs.snmp.table]]\n    oid = \"IF-MIB::ifTable\"\n    name = \"interface\"\n    inherit_tags = [\"sysName\"]\n\n    [[inputs.snmp.table.field]]\n      oid = \"IF-MIB::ifDescr\"\n      name = \"ifDescr\"\n      is_tag = true\n"
  },
  {
    "path": "plugins/inputs/snmp/snmp.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage snmp\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Snmp struct {\n\t// The SNMP agent to query. Format is [SCHEME://]ADDR[:PORT] (e.g.\n\t// udp://1.2.3.4:161).  If the scheme is not specified then \"udp\" is used.\n\tAgents []string `toml:\"agents\"`\n\n\t// The tag used to name the agent host\n\tAgentHostTag string `toml:\"agent_host_tag\"`\n\n\t// Stop collection when receiving errors from an agent\n\tStopOnError bool `toml:\"stop_on_error\"`\n\n\tsnmp.ClientConfig\n\n\tTables []snmp.Table `toml:\"table\"`\n\n\t// Name & Fields are the elements of a Table.\n\t// Telegraf chokes if we try to embed a Table. So instead we have to embed the\n\t// fields of a Table, and construct a Table during runtime.\n\tName   string       `toml:\"name\"`\n\tFields []snmp.Field `toml:\"field\"`\n\n\tLog telegraf.Logger `toml:\"-\"`\n\n\tconnectionCache []snmp.Connection\n\n\ttranslator snmp.Translator\n}\n\nfunc (*Snmp) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Snmp) SetTranslator(name string) {\n\ts.Translator = name\n}\n\nfunc (s *Snmp) Init() error {\n\tvar err error\n\tswitch s.Translator {\n\tcase \"gosmi\":\n\t\ts.translator, err = snmp.NewGosmiTranslator(s.Path, s.Log)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"netsnmp\":\n\t\ts.translator = snmp.NewNetsnmpTranslator(s.Log)\n\tdefault:\n\t\treturn errors.New(\"invalid translator value\")\n\t}\n\n\ts.connectionCache = make([]snmp.Connection, len(s.Agents))\n\n\tfor i := range s.Tables {\n\t\tif err := s.Tables[i].Init(s.translator); err != nil {\n\t\t\treturn fmt.Errorf(\"initializing table %s: %w\", s.Tables[i].Name, err)\n\t\t}\n\t}\n\n\tfor i := range s.Fields {\n\t\tif err := s.Fields[i].Init(s.translator); err != nil {\n\t\t\treturn fmt.Errorf(\"initializing field %s: %w\", s.Fields[i].Name, err)\n\t\t}\n\t}\n\n\tif len(s.AgentHostTag) == 0 {\n\t\ts.AgentHostTag = \"agent_host\"\n\t}\n\tif s.AgentHostTag != \"source\" {\n\t\tconfig.PrintOptionValueDeprecationNotice(\"inputs.snmp\", \"agent_host_tag\", s.AgentHostTag, telegraf.DeprecationInfo{\n\t\t\tSince:  \"1.29.0\",\n\t\t\tNotice: `set to \"source\" for consistent usage across plugins or safely ignore this message and continue to use the current value`,\n\t\t})\n\t}\n\n\ts.GosnmpDebugLogger = s.Log\n\n\treturn nil\n}\n\nfunc (s *Snmp) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor i, agent := range s.Agents {\n\t\twg.Add(1)\n\t\tgo func(i int, agent string) {\n\t\t\tdefer wg.Done()\n\t\t\tgs, err := s.getConnection(i)\n\t\t\tif err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"agent %s: %w\", agent, err))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// First is the top-level fields. We treat the fields as table prefixes with an empty index.\n\t\t\tt := snmp.Table{\n\t\t\t\tName:   s.Name,\n\t\t\t\tFields: s.Fields,\n\t\t\t}\n\t\t\ttopTags := make(map[string]string)\n\t\t\tif err := s.gatherTable(acc, gs, t, topTags, false); err != nil {\n\t\t\t\tacc.AddError(fmt.Errorf(\"agent %s: %w\", agent, err))\n\t\t\t\tif s.StopOnError {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now is the real tables.\n\t\t\tfor _, t := range s.Tables {\n\t\t\t\tif err := s.gatherTable(acc, gs, t, topTags, true); err != nil {\n\t\t\t\t\tacc.AddError(fmt.Errorf(\"agent %s: gathering table %s: %w\", agent, t.Name, err))\n\t\t\t\t\tif s.StopOnError {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(i, agent)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (s *Snmp) gatherTable(acc telegraf.Accumulator, gs snmp.Connection, t snmp.Table, topTags map[string]string, walk bool) error {\n\trt, err := t.Build(gs, walk)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, tr := range rt.Rows {\n\t\tif !walk {\n\t\t\t// top-level table. Add tags to topTags.\n\t\t\tfor k, v := range tr.Tags {\n\t\t\t\ttopTags[k] = v\n\t\t\t}\n\t\t} else {\n\t\t\t// real table. Inherit any specified tags.\n\t\t\tfor _, k := range t.InheritTags {\n\t\t\t\tif v, ok := topTags[k]; ok {\n\t\t\t\t\ttr.Tags[k] = v\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif _, ok := tr.Tags[s.AgentHostTag]; !ok {\n\t\t\ttr.Tags[s.AgentHostTag] = gs.Host()\n\t\t}\n\t\tacc.AddFields(rt.Name, tr.Fields, tr.Tags, rt.Time)\n\t}\n\n\treturn nil\n}\n\n// getConnection creates a snmpConnection (*gosnmp.GoSNMP) object and caches the\n// result using `agentIndex` as the cache key.  This is done to allow multiple\n// connections to a single address.  It is an error to use a connection in\n// more than one goroutine.\nfunc (s *Snmp) getConnection(idx int) (snmp.Connection, error) {\n\tif gs := s.connectionCache[idx]; gs != nil {\n\t\tif err := gs.Reconnect(); err != nil {\n\t\t\treturn gs, fmt.Errorf(\"reconnecting: %w\", err)\n\t\t}\n\n\t\treturn gs, nil\n\t}\n\n\tagent := s.Agents[idx]\n\n\tgs, err := snmp.NewWrapper(s.ClientConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = gs.SetAgent(agent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ts.connectionCache[idx] = gs\n\n\tif err := gs.Connect(); err != nil {\n\t\treturn nil, fmt.Errorf(\"setting up connection: %w\", err)\n\t}\n\n\treturn gs, nil\n}\n\nfunc init() {\n\tinputs.Add(\"snmp\", func() telegraf.Input {\n\t\treturn &Snmp{\n\t\t\tName: \"snmp\",\n\t\t\tClientConfig: snmp.ClientConfig{\n\t\t\t\tRetries:        3,\n\t\t\t\tMaxRepetitions: 10,\n\t\t\t\tTimeout:        config.Duration(5 * time.Second),\n\t\t\t\tVersion:        2,\n\t\t\t\tPath:           []string{\"/usr/share/snmp/mibs\"},\n\t\t\t\tCommunity:      \"public\",\n\t\t\t},\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/snmp/snmp_test.go",
    "content": "package snmp\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\ntype testSNMPConnection struct {\n\thost   string\n\tvalues map[string]interface{}\n}\n\nfunc (tsc *testSNMPConnection) Host() string {\n\treturn tsc.host\n}\n\nfunc (tsc *testSNMPConnection) Get(oids []string) (*gosnmp.SnmpPacket, error) {\n\tsp := &gosnmp.SnmpPacket{}\n\tfor _, oid := range oids {\n\t\tv, ok := tsc.values[oid]\n\t\tif !ok {\n\t\t\tsp.Variables = append(sp.Variables, gosnmp.SnmpPDU{\n\t\t\t\tName: oid,\n\t\t\t\tType: gosnmp.NoSuchObject,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tsp.Variables = append(sp.Variables, gosnmp.SnmpPDU{\n\t\t\tName:  oid,\n\t\t\tValue: v,\n\t\t})\n\t}\n\treturn sp, nil\n}\n\nfunc (tsc *testSNMPConnection) Walk(oid string, wf gosnmp.WalkFunc) error {\n\tfor void, v := range tsc.values {\n\t\tif void == oid || (len(void) > len(oid) && void[:len(oid)+1] == oid+\".\") {\n\t\t\tif err := wf(gosnmp.SnmpPDU{\n\t\t\t\tName:  void,\n\t\t\t\tValue: v,\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (*testSNMPConnection) Reconnect() error {\n\treturn nil\n}\n\nvar tsc = &testSNMPConnection{\n\thost: \"tsc\",\n\tvalues: map[string]interface{}{\n\t\t\".1.0.0.0.1.1.0\":         \"foo\",\n\t\t\".1.0.0.0.1.1.1\":         []byte(\"bar\"),\n\t\t\".1.0.0.0.1.1.2\":         []byte(\"\"),\n\t\t\".1.0.0.0.1.102\":         \"bad\",\n\t\t\".1.0.0.0.1.2.0\":         1,\n\t\t\".1.0.0.0.1.2.1\":         2,\n\t\t\".1.0.0.0.1.2.2\":         0,\n\t\t\".1.0.0.0.1.3.0\":         \"0.123\",\n\t\t\".1.0.0.0.1.3.1\":         \"0.456\",\n\t\t\".1.0.0.0.1.3.2\":         \"0.000\",\n\t\t\".1.0.0.0.1.3.3\":         \"9.999\",\n\t\t\".1.0.0.0.1.5.0\":         123456,\n\t\t\".1.0.0.0.1.6.0\":         \".1.0.0.0.1.7\",\n\t\t\".1.0.0.1.1\":             \"baz\",\n\t\t\".1.0.0.1.2\":             234,\n\t\t\".1.0.0.1.3\":             []byte(\"byte slice\"),\n\t\t\".1.0.0.2.1.5.0.9.9\":     11,\n\t\t\".1.0.0.2.1.5.1.9.9\":     22,\n\t\t\".1.0.0.3.1.1.10\":        \"instance\",\n\t\t\".1.0.0.3.1.1.11\":        \"instance2\",\n\t\t\".1.0.0.3.1.1.12\":        \"instance3\",\n\t\t\".1.0.0.3.1.2.10\":        10,\n\t\t\".1.0.0.3.1.2.11\":        20,\n\t\t\".1.0.0.3.1.2.12\":        20,\n\t\t\".1.0.0.3.1.3.10\":        1,\n\t\t\".1.0.0.3.1.3.11\":        2,\n\t\t\".1.0.0.3.1.3.12\":        3,\n\t\t\".1.3.6.1.2.1.3.1.1.1.0\": \"foo\",\n\t\t\".1.3.6.1.2.1.3.1.1.1.1\": []byte(\"bar\"),\n\t\t\".1.3.6.1.2.1.3.1.1.1.2\": []byte(\"\"),\n\t\t\".1.3.6.1.2.1.3.1.1.102\": \"bad\",\n\t\t\".1.3.6.1.2.1.3.1.1.2.0\": 1,\n\t\t\".1.3.6.1.2.1.3.1.1.2.1\": 2,\n\t\t\".1.3.6.1.2.1.3.1.1.2.2\": 0,\n\t\t\".1.3.6.1.2.1.3.1.1.3.0\": \"1.3.6.1.2.1.3.1.1.3\",\n\t\t\".1.3.6.1.2.1.3.1.1.5.0\": 123456,\n\t},\n}\n\nfunc TestSnmpInit(t *testing.T) {\n\ts := &Snmp{\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"netsnmp\",\n\t\t},\n\t}\n\n\trequire.NoError(t, s.Init())\n}\n\nfunc TestSnmpInit_noTranslate(t *testing.T) {\n\ts := &Snmp{\n\t\tFields: []snmp.Field{\n\t\t\t{Oid: \".1.1.1.1\", Name: \"one\", IsTag: true},\n\t\t\t{Oid: \".1.1.1.2\", Name: \"two\"},\n\t\t\t{Oid: \".1.1.1.3\"},\n\t\t},\n\t\tTables: []snmp.Table{\n\t\t\t{Name: \"testing\",\n\t\t\t\tFields: []snmp.Field{\n\t\t\t\t\t{Oid: \".1.1.1.4\", Name: \"four\", IsTag: true},\n\t\t\t\t\t{Oid: \".1.1.1.5\", Name: \"five\"},\n\t\t\t\t\t{Oid: \".1.1.1.6\"},\n\t\t\t\t}},\n\t\t},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"netsnmp\",\n\t\t},\n\t\tLog: testutil.Logger{Name: \"inputs.snmp\"},\n\t}\n\n\terr := s.Init()\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \".1.1.1.1\", s.Fields[0].Oid)\n\trequire.Equal(t, \"one\", s.Fields[0].Name)\n\trequire.True(t, s.Fields[0].IsTag)\n\n\trequire.Equal(t, \".1.1.1.2\", s.Fields[1].Oid)\n\trequire.Equal(t, \"two\", s.Fields[1].Name)\n\trequire.False(t, s.Fields[1].IsTag)\n\n\trequire.Equal(t, \".1.1.1.3\", s.Fields[2].Oid)\n\trequire.Equal(t, \".1.1.1.3\", s.Fields[2].Name)\n\trequire.False(t, s.Fields[2].IsTag)\n\n\trequire.Equal(t, \".1.1.1.4\", s.Tables[0].Fields[0].Oid)\n\trequire.Equal(t, \"four\", s.Tables[0].Fields[0].Name)\n\trequire.True(t, s.Tables[0].Fields[0].IsTag)\n\n\trequire.Equal(t, \".1.1.1.5\", s.Tables[0].Fields[1].Oid)\n\trequire.Equal(t, \"five\", s.Tables[0].Fields[1].Name)\n\trequire.False(t, s.Tables[0].Fields[1].IsTag)\n\n\trequire.Equal(t, \".1.1.1.6\", s.Tables[0].Fields[2].Oid)\n\trequire.Equal(t, \".1.1.1.6\", s.Tables[0].Fields[2].Name)\n\trequire.False(t, s.Tables[0].Fields[2].IsTag)\n}\n\nfunc TestSnmpInit_noName_noOid(t *testing.T) {\n\ts := &Snmp{\n\t\tTables: []snmp.Table{\n\t\t\t{Fields: []snmp.Field{\n\t\t\t\t{Oid: \".1.1.1.4\", Name: \"four\", IsTag: true},\n\t\t\t\t{Oid: \".1.1.1.5\", Name: \"five\"},\n\t\t\t\t{Oid: \".1.1.1.6\"},\n\t\t\t}},\n\t\t},\n\t}\n\n\trequire.Error(t, s.Init())\n}\n\nfunc TestGetSNMPConnection_v2(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"1.2.3.4:567\", \"1.2.3.4\", \"udp://127.0.0.1\"},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTimeout:    config.Duration(3 * time.Second),\n\t\t\tRetries:    4,\n\t\t\tVersion:    2,\n\t\t\tCommunity:  \"foo\",\n\t\t\tTranslator: \"netsnmp\",\n\t\t},\n\t}\n\trequire.NoError(t, s.Init())\n\n\tgsc, err := s.getConnection(0)\n\trequire.NoError(t, err)\n\tgs := gsc.(snmp.GosnmpWrapper)\n\trequire.Equal(t, \"1.2.3.4\", gs.Target)\n\trequire.EqualValues(t, 567, gs.Port)\n\trequire.Equal(t, gosnmp.Version2c, gs.Version)\n\trequire.Equal(t, \"foo\", gs.Community)\n\trequire.Equal(t, \"udp\", gs.Transport)\n\n\tgsc, err = s.getConnection(1)\n\trequire.NoError(t, err)\n\tgs = gsc.(snmp.GosnmpWrapper)\n\trequire.Equal(t, \"1.2.3.4\", gs.Target)\n\trequire.EqualValues(t, 161, gs.Port)\n\trequire.Equal(t, \"udp\", gs.Transport)\n\n\tgsc, err = s.getConnection(2)\n\trequire.NoError(t, err)\n\tgs = gsc.(snmp.GosnmpWrapper)\n\trequire.Equal(t, \"127.0.0.1\", gs.Target)\n\trequire.EqualValues(t, 161, gs.Port)\n\trequire.Equal(t, \"udp\", gs.Transport)\n}\n\nfunc TestGetSNMPConnectionTCP(t *testing.T) {\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\ttcpServer, err := net.ListenTCP(\"tcp\", tcpAddr)\n\trequire.NoError(t, err)\n\tdefer tcpServer.Close()\n\n\ts := &Snmp{\n\t\tAgents: []string{fmt.Sprintf(\"tcp://%s\", tcpServer.Addr())},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"netsnmp\",\n\t\t},\n\t}\n\trequire.NoError(t, s.Init())\n\n\tgsc, err := s.getConnection(0)\n\trequire.NoError(t, err)\n\tgs := gsc.(snmp.GosnmpWrapper)\n\trequire.Equal(t, \"127.0.0.1\", gs.Target)\n\trequire.Equal(t, \"tcp\", gs.Transport)\n}\n\nfunc TestGetSNMPConnection_v3(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"1.2.3.4\"},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tVersion:        3,\n\t\t\tMaxRepetitions: 20,\n\t\t\tContextName:    \"mycontext\",\n\t\t\tSecLevel:       \"authPriv\",\n\t\t\tSecName:        \"myuser\",\n\t\t\tAuthProtocol:   \"md5\",\n\t\t\tAuthPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\tPrivProtocol:   \"des\",\n\t\t\tPrivPassword:   config.NewSecret([]byte(\"321drowssap\")),\n\t\t\tEngineID:       \"myengineid\",\n\t\t\tEngineBoots:    1,\n\t\t\tEngineTime:     2,\n\t\t\tTranslator:     \"netsnmp\",\n\t\t},\n\t}\n\terr := s.Init()\n\trequire.NoError(t, err)\n\n\tgsc, err := s.getConnection(0)\n\trequire.NoError(t, err)\n\tgs := gsc.(snmp.GosnmpWrapper)\n\trequire.Equal(t, gosnmp.Version3, gs.Version)\n\tsp := gs.SecurityParameters.(*gosnmp.UsmSecurityParameters)\n\trequire.Equal(t, \"1.2.3.4\", gsc.Host())\n\trequire.EqualValues(t, 20, gs.MaxRepetitions)\n\trequire.Equal(t, \"mycontext\", gs.ContextName)\n\trequire.Equal(t, gosnmp.AuthPriv, gs.MsgFlags&gosnmp.AuthPriv)\n\trequire.Equal(t, \"myuser\", sp.UserName)\n\trequire.Equal(t, gosnmp.MD5, sp.AuthenticationProtocol)\n\trequire.Equal(t, \"password123\", sp.AuthenticationPassphrase)\n\trequire.Equal(t, gosnmp.DES, sp.PrivacyProtocol)\n\trequire.Equal(t, \"321drowssap\", sp.PrivacyPassphrase)\n\trequire.Equal(t, \"myengineid\", sp.AuthoritativeEngineID)\n\trequire.EqualValues(t, 1, sp.AuthoritativeEngineBoots)\n\trequire.EqualValues(t, 2, sp.AuthoritativeEngineTime)\n}\n\nfunc TestGetSNMPConnection_v3_blumenthal(t *testing.T) {\n\ttestCases := []struct {\n\t\tName      string\n\t\tAlgorithm gosnmp.SnmpV3PrivProtocol\n\t\tConfig    *Snmp\n\t}{\n\t\t{\n\t\t\tName:      \"AES192\",\n\t\t\tAlgorithm: gosnmp.AES192,\n\t\t\tConfig: &Snmp{\n\t\t\t\tAgents: []string{\"1.2.3.4\"},\n\t\t\t\tClientConfig: snmp.ClientConfig{\n\t\t\t\t\tVersion:        3,\n\t\t\t\t\tMaxRepetitions: 20,\n\t\t\t\t\tContextName:    \"mycontext\",\n\t\t\t\t\tSecLevel:       \"authPriv\",\n\t\t\t\t\tSecName:        \"myuser\",\n\t\t\t\t\tAuthProtocol:   \"md5\",\n\t\t\t\t\tAuthPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tPrivProtocol:   \"AES192\",\n\t\t\t\t\tPrivPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tEngineID:       \"myengineid\",\n\t\t\t\t\tEngineBoots:    1,\n\t\t\t\t\tEngineTime:     2,\n\t\t\t\t\tTranslator:     \"netsnmp\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:      \"AES192C\",\n\t\t\tAlgorithm: gosnmp.AES192C,\n\t\t\tConfig: &Snmp{\n\t\t\t\tAgents: []string{\"1.2.3.4\"},\n\t\t\t\tClientConfig: snmp.ClientConfig{\n\t\t\t\t\tVersion:        3,\n\t\t\t\t\tMaxRepetitions: 20,\n\t\t\t\t\tContextName:    \"mycontext\",\n\t\t\t\t\tSecLevel:       \"authPriv\",\n\t\t\t\t\tSecName:        \"myuser\",\n\t\t\t\t\tAuthProtocol:   \"md5\",\n\t\t\t\t\tAuthPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tPrivProtocol:   \"AES192C\",\n\t\t\t\t\tPrivPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tEngineID:       \"myengineid\",\n\t\t\t\t\tEngineBoots:    1,\n\t\t\t\t\tEngineTime:     2,\n\t\t\t\t\tTranslator:     \"netsnmp\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:      \"AES256\",\n\t\t\tAlgorithm: gosnmp.AES256,\n\t\t\tConfig: &Snmp{\n\t\t\t\tAgents: []string{\"1.2.3.4\"},\n\t\t\t\tClientConfig: snmp.ClientConfig{\n\t\t\t\t\tVersion:        3,\n\t\t\t\t\tMaxRepetitions: 20,\n\t\t\t\t\tContextName:    \"mycontext\",\n\t\t\t\t\tSecLevel:       \"authPriv\",\n\t\t\t\t\tSecName:        \"myuser\",\n\t\t\t\t\tAuthProtocol:   \"md5\",\n\t\t\t\t\tAuthPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tPrivProtocol:   \"AES256\",\n\t\t\t\t\tPrivPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tEngineID:       \"myengineid\",\n\t\t\t\t\tEngineBoots:    1,\n\t\t\t\t\tEngineTime:     2,\n\t\t\t\t\tTranslator:     \"netsnmp\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:      \"AES256C\",\n\t\t\tAlgorithm: gosnmp.AES256C,\n\t\t\tConfig: &Snmp{\n\t\t\t\tAgents: []string{\"1.2.3.4\"},\n\t\t\t\tClientConfig: snmp.ClientConfig{\n\t\t\t\t\tVersion:        3,\n\t\t\t\t\tMaxRepetitions: 20,\n\t\t\t\t\tContextName:    \"mycontext\",\n\t\t\t\t\tSecLevel:       \"authPriv\",\n\t\t\t\t\tSecName:        \"myuser\",\n\t\t\t\t\tAuthProtocol:   \"md5\",\n\t\t\t\t\tAuthPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tPrivProtocol:   \"AES256C\",\n\t\t\t\t\tPrivPassword:   config.NewSecret([]byte(\"password123\")),\n\t\t\t\t\tEngineID:       \"myengineid\",\n\t\t\t\t\tEngineBoots:    1,\n\t\t\t\t\tEngineTime:     2,\n\t\t\t\t\tTranslator:     \"netsnmp\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\ts := tc.Config\n\t\t\terr := s.Init()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgsc, err := s.getConnection(0)\n\t\t\trequire.NoError(t, err)\n\t\t\tgs := gsc.(snmp.GosnmpWrapper)\n\t\t\trequire.Equal(t, gosnmp.Version3, gs.Version)\n\t\t\tsp := gs.SecurityParameters.(*gosnmp.UsmSecurityParameters)\n\t\t\trequire.Equal(t, \"1.2.3.4\", gsc.Host())\n\t\t\trequire.EqualValues(t, 20, gs.MaxRepetitions)\n\t\t\trequire.Equal(t, \"mycontext\", gs.ContextName)\n\t\t\trequire.Equal(t, gosnmp.AuthPriv, gs.MsgFlags&gosnmp.AuthPriv)\n\t\t\trequire.Equal(t, \"myuser\", sp.UserName)\n\t\t\trequire.Equal(t, gosnmp.MD5, sp.AuthenticationProtocol)\n\t\t\trequire.Equal(t, \"password123\", sp.AuthenticationPassphrase)\n\t\t\trequire.Equal(t, tc.Algorithm, sp.PrivacyProtocol)\n\t\t\trequire.Equal(t, \"password123\", sp.PrivacyPassphrase)\n\t\t\trequire.Equal(t, \"myengineid\", sp.AuthoritativeEngineID)\n\t\t\trequire.EqualValues(t, 1, sp.AuthoritativeEngineBoots)\n\t\t\trequire.EqualValues(t, 2, sp.AuthoritativeEngineTime)\n\t\t})\n\t}\n}\n\nfunc TestGetSNMPConnection_caching(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"1.2.3.4\", \"1.2.3.5\", \"1.2.3.5\"},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"netsnmp\",\n\t\t},\n\t}\n\terr := s.Init()\n\trequire.NoError(t, err)\n\tgs1, err := s.getConnection(0)\n\trequire.NoError(t, err)\n\tgs2, err := s.getConnection(0)\n\trequire.NoError(t, err)\n\tgs3, err := s.getConnection(1)\n\trequire.NoError(t, err)\n\tgs4, err := s.getConnection(2)\n\trequire.NoError(t, err)\n\trequire.Equal(t, gs1, gs2)\n\trequire.NotEqual(t, gs2, gs3)\n\trequire.NotEqual(t, gs3, gs4)\n}\n\nfunc TestGosnmpWrapper_walk_retry(t *testing.T) {\n\tt.Skip(\"Skipping test due to random failures.\")\n\n\tsrvr, err := net.ListenUDP(\"udp4\", &net.UDPAddr{})\n\trequire.NoError(t, err)\n\tdefer srvr.Close()\n\treqCount := 0\n\t// Set up a WaitGroup to wait for the server goroutine to exit and protect\n\t// reqCount.\n\t// Even though simultaneous access is impossible because the server will be\n\t// blocked on ReadFrom, without this the race detector gets unhappy.\n\twg := sync.WaitGroup{}\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tbuf := make([]byte, 256)\n\t\tfor {\n\t\t\t_, addr, err := srvr.ReadFrom(buf)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\treqCount++\n\n\t\t\t// will cause decoding error\n\t\t\tif _, err := srvr.WriteTo([]byte{'X'}, addr); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tgs := &gosnmp.GoSNMP{\n\t\tTarget:    srvr.LocalAddr().(*net.UDPAddr).IP.String(),\n\t\tPort:      uint16(srvr.LocalAddr().(*net.UDPAddr).Port),\n\t\tVersion:   gosnmp.Version2c,\n\t\tCommunity: \"public\",\n\t\tTimeout:   time.Millisecond * 10,\n\t\tRetries:   1,\n\t}\n\terr = gs.Connect()\n\trequire.NoError(t, err)\n\tconn := gs.Conn\n\n\tgsw := snmp.GosnmpWrapper{\n\t\tGoSNMP: gs,\n\t}\n\terr = gsw.Walk(\".1.0.0\", func(gosnmp.SnmpPDU) error { return nil })\n\trequire.NoError(t, srvr.Close())\n\twg.Wait()\n\trequire.Error(t, err)\n\trequire.NotEqual(t, gs.Conn, conn)\n\trequire.Equal(t, (gs.Retries+1)*2, reqCount)\n}\n\nfunc TestGosnmpWrapper_get_retry(t *testing.T) {\n\t// TODO: Fix this test\n\tt.Skip(\"Test failing too often, skip for now and revisit later.\")\n\tsrvr, err := net.ListenUDP(\"udp4\", &net.UDPAddr{})\n\trequire.NoError(t, err)\n\tdefer srvr.Close()\n\treqCount := 0\n\t// Set up a WaitGroup to wait for the server goroutine to exit and protect\n\t// reqCount.\n\t// Even though simultaneous access is impossible because the server will be\n\t// blocked on ReadFrom, without this the race detector gets unhappy.\n\twg := sync.WaitGroup{}\n\twg.Add(1)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tbuf := make([]byte, 256)\n\t\tfor {\n\t\t\t_, addr, err := srvr.ReadFrom(buf)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\treqCount++\n\n\t\t\t// will cause decoding error\n\t\t\tif _, err := srvr.WriteTo([]byte{'X'}, addr); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tgs := &gosnmp.GoSNMP{\n\t\tTarget:    srvr.LocalAddr().(*net.UDPAddr).IP.String(),\n\t\tPort:      uint16(srvr.LocalAddr().(*net.UDPAddr).Port),\n\t\tVersion:   gosnmp.Version2c,\n\t\tCommunity: \"public\",\n\t\tTimeout:   time.Millisecond * 10,\n\t\tRetries:   1,\n\t}\n\terr = gs.Connect()\n\trequire.NoError(t, err)\n\tconn := gs.Conn\n\n\tgsw := snmp.GosnmpWrapper{\n\t\tGoSNMP: gs,\n\t}\n\t_, err = gsw.Get([]string{\".1.0.0\"})\n\trequire.NoError(t, srvr.Close())\n\twg.Wait()\n\trequire.Error(t, err)\n\trequire.NotEqual(t, gs.Conn, conn)\n\trequire.Equal(t, (gs.Retries+1)*2, reqCount)\n}\n\nfunc TestGather(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"TestGather\"},\n\t\tName:   \"mytable\",\n\t\tFields: []snmp.Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield3\",\n\t\t\t\tOid:  \"1.0.0.1.1\",\n\t\t\t},\n\t\t},\n\t\tTables: []snmp.Table{\n\t\t\t{\n\t\t\t\tName:        \"myOtherTable\",\n\t\t\t\tInheritTags: []string{\"myfield1\"},\n\t\t\t\tFields: []snmp.Field{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"myOtherField\",\n\t\t\t\t\t\tOid:  \".1.0.0.0.1.5\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\tconnectionCache: []snmp.Connection{\n\t\t\ttsc,\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\n\ttstart := time.Now()\n\trequire.NoError(t, s.Gather(acc))\n\ttstop := time.Now()\n\n\trequire.Len(t, acc.Metrics, 2)\n\n\tm := acc.Metrics[0]\n\trequire.Equal(t, \"mytable\", m.Measurement)\n\trequire.Equal(t, \"tsc\", m.Tags[s.AgentHostTag])\n\trequire.Equal(t, \"baz\", m.Tags[\"myfield1\"])\n\trequire.Len(t, m.Fields, 2)\n\trequire.Equal(t, 234, m.Fields[\"myfield2\"])\n\trequire.Equal(t, \"baz\", m.Fields[\"myfield3\"])\n\trequire.WithinRange(t, m.Time, tstart, tstop)\n\n\tm2 := acc.Metrics[1]\n\trequire.Equal(t, \"myOtherTable\", m2.Measurement)\n\trequire.Equal(t, \"tsc\", m2.Tags[s.AgentHostTag])\n\trequire.Equal(t, \"baz\", m2.Tags[\"myfield1\"])\n\trequire.Len(t, m2.Fields, 1)\n\trequire.Equal(t, 123456, m2.Fields[\"myOtherField\"])\n}\n\nfunc TestGather_host(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"TestGather\"},\n\t\tName:   \"mytable\",\n\t\tFields: []snmp.Field{\n\t\t\t{\n\t\t\t\tName:  \"host\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t},\n\n\t\tconnectionCache: []snmp.Connection{\n\t\t\ttsc,\n\t\t},\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, s.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 1)\n\tm := acc.Metrics[0]\n\trequire.Equal(t, \"baz\", m.Tags[\"host\"])\n}\n\nfunc TestSnmpInitGosmi(t *testing.T) {\n\ttestDataPath, err := filepath.Abs(\"../../common/snmp/testdata/gosmi\")\n\trequire.NoError(t, err)\n\n\ts := &Snmp{\n\t\tTables: []snmp.Table{\n\t\t\t{Oid: \"RFC1213-MIB::atTable\"},\n\t\t},\n\t\tFields: []snmp.Field{\n\t\t\t{Oid: \"RFC1213-MIB::atPhysAddress\"},\n\t\t},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tPath:       []string{testDataPath},\n\t\t\tTranslator: \"gosmi\",\n\t\t},\n\t}\n\n\trequire.NoError(t, s.Init())\n\n\trequire.Len(t, s.Tables[0].Fields, 3)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.1\", s.Tables[0].Fields[0].Oid)\n\trequire.Equal(t, \"atIfIndex\", s.Tables[0].Fields[0].Name)\n\trequire.True(t, s.Tables[0].Fields[0].IsTag)\n\trequire.Empty(t, s.Tables[0].Fields[0].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.2\", s.Tables[0].Fields[1].Oid)\n\trequire.Equal(t, \"atPhysAddress\", s.Tables[0].Fields[1].Name)\n\trequire.False(t, s.Tables[0].Fields[1].IsTag)\n\trequire.Equal(t, \"displayhint\", s.Tables[0].Fields[1].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.3\", s.Tables[0].Fields[2].Oid)\n\trequire.Equal(t, \"atNetAddress\", s.Tables[0].Fields[2].Name)\n\trequire.True(t, s.Tables[0].Fields[2].IsTag)\n\trequire.Empty(t, s.Tables[0].Fields[2].Conversion)\n\n\trequire.Equal(t, \".1.3.6.1.2.1.3.1.1.2\", s.Fields[0].Oid)\n\trequire.Equal(t, \"atPhysAddress\", s.Fields[0].Name)\n\trequire.False(t, s.Fields[0].IsTag)\n\trequire.Equal(t, \"displayhint\", s.Fields[0].Conversion)\n}\n\nfunc TestSnmpInit_noTranslateGosmi(t *testing.T) {\n\ts := &Snmp{\n\t\tFields: []snmp.Field{\n\t\t\t{Oid: \".9.1.1.1.1\", Name: \"one\", IsTag: true},\n\t\t\t{Oid: \".9.1.1.1.2\", Name: \"two\"},\n\t\t\t{Oid: \".9.1.1.1.3\"},\n\t\t},\n\t\tTables: []snmp.Table{\n\t\t\t{Name: \"testing\",\n\t\t\t\tFields: []snmp.Field{\n\t\t\t\t\t{Oid: \".9.1.1.1.4\", Name: \"four\", IsTag: true},\n\t\t\t\t\t{Oid: \".9.1.1.1.5\", Name: \"five\"},\n\t\t\t\t\t{Oid: \".9.1.1.1.6\"},\n\t\t\t\t}},\n\t\t},\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"gosmi\",\n\t\t},\n\t}\n\n\trequire.NoError(t, s.Init())\n\n\trequire.Equal(t, \".9.1.1.1.1\", s.Fields[0].Oid)\n\trequire.Equal(t, \"one\", s.Fields[0].Name)\n\trequire.True(t, s.Fields[0].IsTag)\n\n\trequire.Equal(t, \".9.1.1.1.2\", s.Fields[1].Oid)\n\trequire.Equal(t, \"two\", s.Fields[1].Name)\n\trequire.False(t, s.Fields[1].IsTag)\n\n\trequire.Equal(t, \".9.1.1.1.3\", s.Fields[2].Oid)\n\trequire.Equal(t, \".9.1.1.1.3\", s.Fields[2].Name)\n\trequire.False(t, s.Fields[2].IsTag)\n\n\trequire.Equal(t, \".9.1.1.1.4\", s.Tables[0].Fields[0].Oid)\n\trequire.Equal(t, \"four\", s.Tables[0].Fields[0].Name)\n\trequire.True(t, s.Tables[0].Fields[0].IsTag)\n\n\trequire.Equal(t, \".9.1.1.1.5\", s.Tables[0].Fields[1].Oid)\n\trequire.Equal(t, \"five\", s.Tables[0].Fields[1].Name)\n\trequire.False(t, s.Tables[0].Fields[1].IsTag)\n\n\trequire.Equal(t, \".9.1.1.1.6\", s.Tables[0].Fields[2].Oid)\n\trequire.Equal(t, \".9.1.1.1.6\", s.Tables[0].Fields[2].Name)\n\trequire.False(t, s.Tables[0].Fields[2].IsTag)\n}\n\nfunc TestGatherGosmi(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"TestGather\"},\n\t\tName:   \"mytable\",\n\t\tFields: []snmp.Field{\n\t\t\t{\n\t\t\t\tName:  \"myfield1\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield3\",\n\t\t\t\tOid:  \"1.0.0.1.1\",\n\t\t\t},\n\t\t},\n\t\tTables: []snmp.Table{\n\t\t\t{\n\t\t\t\tName:        \"myOtherTable\",\n\t\t\t\tInheritTags: []string{\"myfield1\"},\n\t\t\t\tFields: []snmp.Field{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"myOtherField\",\n\t\t\t\t\t\tOid:  \".1.0.0.0.1.5\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\tconnectionCache: []snmp.Connection{tsc},\n\n\t\tClientConfig: snmp.ClientConfig{\n\t\t\tTranslator: \"gosmi\",\n\t\t},\n\t}\n\tacc := &testutil.Accumulator{}\n\n\ttstart := time.Now()\n\trequire.NoError(t, s.Gather(acc))\n\ttstop := time.Now()\n\n\trequire.Len(t, acc.Metrics, 2)\n\n\tm := acc.Metrics[0]\n\trequire.Equal(t, \"mytable\", m.Measurement)\n\trequire.Equal(t, \"tsc\", m.Tags[s.AgentHostTag])\n\trequire.Equal(t, \"baz\", m.Tags[\"myfield1\"])\n\trequire.Len(t, m.Fields, 2)\n\trequire.Equal(t, 234, m.Fields[\"myfield2\"])\n\trequire.Equal(t, \"baz\", m.Fields[\"myfield3\"])\n\trequire.WithinRange(t, m.Time, tstart, tstop)\n\n\tm2 := acc.Metrics[1]\n\trequire.Equal(t, \"myOtherTable\", m2.Measurement)\n\trequire.Equal(t, \"tsc\", m2.Tags[s.AgentHostTag])\n\trequire.Equal(t, \"baz\", m2.Tags[\"myfield1\"])\n\trequire.Len(t, m2.Fields, 1)\n\trequire.Equal(t, 123456, m2.Fields[\"myOtherField\"])\n}\n\nfunc TestGather_hostGosmi(t *testing.T) {\n\ts := &Snmp{\n\t\tAgents: []string{\"TestGather\"},\n\t\tName:   \"mytable\",\n\t\tFields: []snmp.Field{\n\t\t\t{\n\t\t\t\tName:  \"host\",\n\t\t\t\tOid:   \".1.0.0.1.1\",\n\t\t\t\tIsTag: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"myfield2\",\n\t\t\t\tOid:  \".1.0.0.1.2\",\n\t\t\t},\n\t\t},\n\n\t\tconnectionCache: []snmp.Connection{tsc},\n\t}\n\n\tacc := &testutil.Accumulator{}\n\n\trequire.NoError(t, s.Gather(acc))\n\n\trequire.Len(t, acc.Metrics, 1)\n\tm := acc.Metrics[0]\n\trequire.Equal(t, \"baz\", m.Tags[\"host\"])\n}\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/README.md",
    "content": "# SNMP Trap Input Plugin\n\nThis service plugin listens for [SNMP][snmp] notifications like traps and inform\nrequests. Notifications are received on plain UDP with a configurable port.\n\n> [!NOTE]\n> The path setting is shared between all instances of all SNMP plugin types!\n\n⭐ Telegraf v1.13.0\n🏷️ hardware, network\n💻 all\n\n[snmp]: https://datatracker.ietf.org/doc/html/rfc1157\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `sec_name`,\n`auth_password` and `priv_password` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Receive SNMP traps\n[[inputs.snmp_trap]]\n  ## Transport, local address, and port to listen on.  Transport must\n  ## be \"udp://\".  Omit local address to listen on all interfaces.\n  ##   example: \"udp://127.0.0.1:1234\"\n  ##\n  ## Special permissions may be required to listen on a port less than\n  ## 1024.  See README.md for details\n  ##\n  # service_address = \"udp://:162\"\n  ##\n  ## Path to mib files\n  ## Used by the gosmi translator.\n  ## To add paths when translating with netsnmp, use the MIBDIRS environment variable\n  # path = [\"/usr/share/snmp/mibs\"]\n  ##\n  ## Timeout running snmptranslate command\n  ## Used by the netsnmp translator only\n  # timeout = \"5s\"\n  ## Snmp version; one of \"1\", \"2c\" or \"3\".\n  # version = \"2c\"\n  ## SNMPv3 authentication and encryption options.\n  ##\n  ## Security Name.\n  # sec_name = \"myuser\"\n  ## Authentication protocol; one of \"MD5\", \"SHA\", \"SHA224\", \"SHA256\", \"SHA384\", \"SHA512\" or \"\".\n  # auth_protocol = \"MD5\"\n  ## Authentication password.\n  # auth_password = \"pass\"\n  ## Security Level; one of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\".\n  # sec_level = \"authNoPriv\"\n  ## Privacy protocol used for encrypted messages; one of \"DES\", \"AES\", \"AES192\", \"AES192C\", \"AES256\", \"AES256C\" or \"\".\n  # priv_protocol = \"\"\n  ## Privacy password used for encrypted messages.\n  # priv_password = \"\"\n```\n\n### SNMP backend: `gosmi` vs `netsnmp`\n\nThis plugin supports two backends to translate SNMP objects. By default,\nTelegraf will use `netsnmp`, however, this option is deprecated and it is\nencouraged to migrate to `gosmi`. If users find issues with `gosmi` that do not\noccur with `netsnmp` please open a project issue on GitHub.\n\nThe SNMP backend setting is a global-level setting that applies to all use of\nSNMP in Telegraf. Users can set this option in the `[agent]` configuration via\nthe `snmp_translator` option. See the [agent configuration][agent] for more\ndetails.\n\n[agent]: /docs/CONFIGURATION.md#agent\n\n### Using a Privileged Port\n\nOn many operating systems, listening on a privileged port (a port\nnumber less than 1024) requires extra permission.  Since the default\nSNMP trap port 162 is in this category, using telegraf to receive SNMP\ntraps may need extra permission.\n\nInstructions for listening on a privileged port vary by operating\nsystem. It is not recommended to run telegraf as superuser in order to\nuse a privileged port. Instead follow the principle of least privilege\nand use a more specific operating system mechanism to allow telegraf to\nuse the port.  You may also be able to have telegraf use an\nunprivileged port and then configure a firewall port forward rule from\nthe privileged port.\n\nTo use a privileged port on Linux, you can use setcap to enable the\nCAP_NET_BIND_SERVICE capability on the telegraf binary:\n\n```shell\nsetcap cap_net_bind_service=+ep /usr/bin/telegraf\n```\n\nOn Mac OS, listening on privileged ports is unrestricted on versions\n10.14 and later.\n\n## Metrics\n\n- snmp_trap\n  - tags:\n    - source (string, IP address of trap source)\n    - name (string, value from SNMPv2-MIB::snmpTrapOID.0 PDU)\n    - mib (string, MIB from SNMPv2-MIB::snmpTrapOID.0 PDU)\n    - oid (string, OID string from SNMPv2-MIB::snmpTrapOID.0 PDU)\n    - version (string, \"1\" or \"2c\" or \"3\")\n    - context_name (string, value from v3 trap)\n    - engine_id (string, value from v3 trap)\n    - community (string, value from 1 or 2c trap)\n  - fields:\n    - Fields are mapped from variables in the trap. Field names are\n      the trap variable names after MIB lookup. Field values are trap\n      variable values.\n\n## Example Output\n\n```text\nsnmp_trap,mib=SNMPv2-MIB,name=coldStart,oid=.1.3.6.1.6.3.1.1.5.1,source=192.168.122.102,version=2c,community=public snmpTrapEnterprise.0=\"linux\",sysUpTimeInstance=1i 1574109187723429814\nsnmp_trap,mib=NET-SNMP-AGENT-MIB,name=nsNotifyShutdown,oid=.1.3.6.1.4.1.8072.4.0.2,source=192.168.122.102,version=2c,community=public sysUpTimeInstance=5803i,snmpTrapEnterprise.0=\"netSnmpNotificationPrefix\" 1574109186555115459\n```\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/gosmi.go",
    "content": "package snmp_trap\n\nimport (\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n)\n\ntype gosmiTranslator struct {\n}\n\nfunc (*gosmiTranslator) lookup(oid string) (snmp.MibEntry, error) {\n\treturn snmp.TrapLookup(oid)\n}\n\nfunc newGosmiTranslator(paths []string, log telegraf.Logger) (*gosmiTranslator, error) {\n\terr := snmp.LoadMibsFromPath(paths, log, &snmp.GosmiMibLoader{})\n\tif err == nil {\n\t\treturn &gosmiTranslator{}, nil\n\t}\n\treturn nil, err\n}\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/netsnmp.go",
    "content": "package snmp_trap\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n)\n\ntype execer func(config.Duration, string, ...string) ([]byte, error)\n\nfunc realExecCmd(timeout config.Duration, arg0 string, args ...string) ([]byte, error) {\n\tcmd := exec.Command(arg0, args...)\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out.Bytes(), nil\n}\n\ntype netsnmpTranslator struct {\n\t// Each translator has its own cache and each plugin instance has\n\t// its own translator. This is different than the snmp plugin\n\t// which has one global cache.\n\t//\n\t// We may want to change snmp_trap to\n\t// have a global cache although it's not as important for\n\t// snmp_trap to be global because there is usually only one\n\t// instance, while it's common to configure many snmp instances.\n\tcacheLock sync.Mutex\n\tcache     map[string]snmp.MibEntry\n\texecCmd   execer\n\ttimeout   config.Duration\n}\n\nfunc (s *netsnmpTranslator) lookup(oid string) (e snmp.MibEntry, err error) {\n\ts.cacheLock.Lock()\n\tdefer s.cacheLock.Unlock()\n\tvar ok bool\n\tif e, ok = s.cache[oid]; !ok {\n\t\t// cache miss.  exec snmptranslate\n\t\te, err = s.snmptranslate(oid)\n\t\tif err == nil {\n\t\t\ts.cache[oid] = e\n\t\t}\n\t\treturn e, err\n\t}\n\treturn e, nil\n}\n\nfunc (s *netsnmpTranslator) snmptranslate(oid string) (e snmp.MibEntry, err error) {\n\tvar out []byte\n\tout, err = s.execCmd(s.timeout, \"snmptranslate\", \"-Td\", \"-Ob\", \"-m\", \"all\", oid)\n\n\tif err != nil {\n\t\treturn e, err\n\t}\n\n\tscanner := bufio.NewScanner(bytes.NewBuffer(out))\n\tok := scanner.Scan()\n\tif err = scanner.Err(); !ok && err != nil {\n\t\treturn e, err\n\t}\n\n\te.OidText = scanner.Text()\n\n\ti := strings.Index(e.OidText, \"::\")\n\tif i == -1 {\n\t\treturn e, errors.New(\"not found\")\n\t}\n\te.MibName = e.OidText[:i]\n\te.OidText = e.OidText[i+2:]\n\treturn e, nil\n}\n\nfunc newNetsnmpTranslator(timeout config.Duration) *netsnmpTranslator {\n\treturn &netsnmpTranslator{\n\t\texecCmd: realExecCmd,\n\t\tcache:   make(map[string]snmp.MibEntry),\n\t\ttimeout: timeout,\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/sample.conf",
    "content": "# Receive SNMP traps\n[[inputs.snmp_trap]]\n  ## Transport, local address, and port to listen on.  Transport must\n  ## be \"udp://\".  Omit local address to listen on all interfaces.\n  ##   example: \"udp://127.0.0.1:1234\"\n  ##\n  ## Special permissions may be required to listen on a port less than\n  ## 1024.  See README.md for details\n  ##\n  # service_address = \"udp://:162\"\n  ##\n  ## Path to mib files\n  ## Used by the gosmi translator.\n  ## To add paths when translating with netsnmp, use the MIBDIRS environment variable\n  # path = [\"/usr/share/snmp/mibs\"]\n  ##\n  ## Timeout running snmptranslate command\n  ## Used by the netsnmp translator only\n  # timeout = \"5s\"\n  ## Snmp version; one of \"1\", \"2c\" or \"3\".\n  # version = \"2c\"\n  ## SNMPv3 authentication and encryption options.\n  ##\n  ## Security Name.\n  # sec_name = \"myuser\"\n  ## Authentication protocol; one of \"MD5\", \"SHA\", \"SHA224\", \"SHA256\", \"SHA384\", \"SHA512\" or \"\".\n  # auth_protocol = \"MD5\"\n  ## Authentication password.\n  # auth_password = \"pass\"\n  ## Security Level; one of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\".\n  # sec_level = \"authNoPriv\"\n  ## Privacy protocol used for encrypted messages; one of \"DES\", \"AES\", \"AES192\", \"AES192C\", \"AES256\", \"AES256C\" or \"\".\n  # priv_protocol = \"\"\n  ## Privacy password used for encrypted messages.\n  # priv_password = \"\"\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/snmp_trap.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage snmp_trap\n\nimport (\n\t_ \"embed\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\nvar defaultTimeout = config.Duration(time.Second * 5)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype SnmpTrap struct {\n\tServiceAddress string          `toml:\"service_address\"`\n\tTimeout        config.Duration `toml:\"timeout\"`\n\tVersion        string          `toml:\"version\"`\n\tPath           []string        `toml:\"path\"`\n\n\t// Settings for version 3 security\n\tSecLevel     string        `toml:\"sec_level\"`\n\tSecName      config.Secret `toml:\"sec_name\"`\n\tAuthProtocol string        `toml:\"auth_protocol\"`\n\tAuthPassword config.Secret `toml:\"auth_password\"`\n\tPrivProtocol string        `toml:\"priv_protocol\"`\n\tPrivPassword config.Secret `toml:\"priv_password\"`\n\n\tTranslator string          `toml:\"-\"`\n\tLog        telegraf.Logger `toml:\"-\"`\n\n\tacc      telegraf.Accumulator\n\tlistener *gosnmp.TrapListener\n\n\ttransl translator\n}\n\ntype translator interface {\n\tlookup(oid string) (snmp.MibEntry, error)\n}\n\nfunc (*SnmpTrap) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *SnmpTrap) SetTranslator(name string) {\n\ts.Translator = name\n}\n\nfunc (s *SnmpTrap) Init() error {\n\t// Set defaults\n\tif s.ServiceAddress == \"\" {\n\t\ts.ServiceAddress = \"udp://:162\"\n\t}\n\n\tif len(s.Path) == 0 {\n\t\ts.Path = []string{\"/usr/share/snmp/mibs\"}\n\t}\n\n\t// Check input parameters\n\tswitch s.Translator {\n\tcase \"gosmi\":\n\t\tt, err := newGosmiTranslator(s.Path, s.Log)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.transl = t\n\tcase \"netsnmp\":\n\t\ts.transl = newNetsnmpTranslator(s.Timeout)\n\tdefault:\n\t\t// Ignore the translator for testing if an instance was set\n\t\tif s.transl == nil {\n\t\t\treturn errors.New(\"invalid translator value\")\n\t\t}\n\t}\n\n\t// Setup the SNMP parameters\n\tparams := gosnmp.GoSNMP{\n\t\tPort:               gosnmp.Default.Port,\n\t\tTransport:          gosnmp.Default.Transport,\n\t\tCommunity:          gosnmp.Default.Community,\n\t\tTimeout:            gosnmp.Default.Timeout,\n\t\tRetries:            gosnmp.Default.Retries,\n\t\tExponentialTimeout: gosnmp.Default.ExponentialTimeout,\n\t\tMaxOids:            gosnmp.Default.MaxOids,\n\t\tLogger:             gosnmp.NewLogger(&snmp.Logger{Logger: s.Log}),\n\t}\n\n\tswitch s.Version {\n\tcase \"1\":\n\t\tparams.Version = gosnmp.Version1\n\tcase \"\", \"2c\":\n\t\tparams.Version = gosnmp.Version2c\n\tcase \"3\":\n\t\tparams.Version = gosnmp.Version3\n\n\t\t// Setup the security for v3\n\t\tparams.SecurityModel = gosnmp.UserSecurityModel\n\n\t\t// Set security mechanisms\n\t\tswitch strings.ToLower(s.SecLevel) {\n\t\tcase \"noauthnopriv\", \"\":\n\t\t\tparams.MsgFlags = gosnmp.NoAuthNoPriv\n\t\tcase \"authnopriv\":\n\t\t\tparams.MsgFlags = gosnmp.AuthNoPriv\n\t\tcase \"authpriv\":\n\t\t\tparams.MsgFlags = gosnmp.AuthPriv\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown security level %q\", s.SecLevel)\n\t\t}\n\n\t\t// Set authentication\n\t\tvar security gosnmp.UsmSecurityParameters\n\t\tswitch strings.ToLower(s.AuthProtocol) {\n\t\tcase \"\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.NoAuth\n\t\tcase \"md5\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.MD5\n\t\tcase \"sha\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.SHA\n\t\tcase \"sha224\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.SHA224\n\t\tcase \"sha256\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.SHA256\n\t\tcase \"sha384\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.SHA384\n\t\tcase \"sha512\":\n\t\t\tsecurity.AuthenticationProtocol = gosnmp.SHA512\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown authentication protocol %q\", s.AuthProtocol)\n\t\t}\n\n\t\t// Set privacy\n\t\tswitch strings.ToLower(s.PrivProtocol) {\n\t\tcase \"\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.NoPriv\n\t\tcase \"aes\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.AES\n\t\tcase \"des\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.DES\n\t\tcase \"aes192\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.AES192\n\t\tcase \"aes192c\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.AES192C\n\t\tcase \"aes256\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.AES256\n\t\tcase \"aes256c\":\n\t\t\tsecurity.PrivacyProtocol = gosnmp.AES256C\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown privacy protocol %q\", s.PrivProtocol)\n\t\t}\n\n\t\t// Set credentials\n\t\tsecnameSecret, err := s.SecName.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting secname failed: %w\", err)\n\t\t}\n\t\tsecurity.UserName = secnameSecret.String()\n\t\tsecnameSecret.Destroy()\n\n\t\tauthPasswdSecret, err := s.AuthPassword.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting auth-password failed: %w\", err)\n\t\t}\n\t\tsecurity.AuthenticationPassphrase = authPasswdSecret.String()\n\t\tauthPasswdSecret.Destroy()\n\n\t\tprivPasswdSecret, err := s.PrivPassword.Get()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"getting priv-password failed: %w\", err)\n\t\t}\n\t\tsecurity.PrivacyPassphrase = privPasswdSecret.String()\n\t\tprivPasswdSecret.Destroy()\n\n\t\t// Enable security settings\n\t\tparams.SecurityParameters = &security\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown version %q\", s.Version)\n\t}\n\n\t// Initialize the listener\n\ts.listener = gosnmp.NewTrapListener()\n\ts.listener.OnNewTrap = s.handler\n\ts.listener.Params = &params\n\n\treturn nil\n}\n\nfunc (s *SnmpTrap) Start(acc telegraf.Accumulator) error {\n\ts.acc = acc\n\n\tu, err := url.Parse(s.ServiceAddress)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid service address: %s\", s.ServiceAddress)\n\t}\n\n\t// The gosnmp package currently only supports UDP\n\tif u.Scheme != \"udp\" {\n\t\treturn fmt.Errorf(\"unknown protocol for service address %q\", s.ServiceAddress)\n\t}\n\n\t// If the listener immediately returns an error we need to return it\n\terrCh := make(chan error, 1)\n\tgo func() {\n\t\terrCh <- s.listener.Listen(u.Host)\n\t}()\n\n\tselect {\n\tcase <-s.listener.Listening():\n\t\ts.Log.Infof(\"Listening on %s\", s.ServiceAddress)\n\tcase err := <-errCh:\n\t\treturn fmt.Errorf(\"listening failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (*SnmpTrap) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (s *SnmpTrap) Stop() {\n\ts.listener.Close()\n}\n\nfunc setTrapOid(tags map[string]string, oid string, e snmp.MibEntry) {\n\ttags[\"oid\"] = oid\n\ttags[\"name\"] = e.OidText\n\ttags[\"mib\"] = e.MibName\n}\n\nfunc (s *SnmpTrap) handler(packet *gosnmp.SnmpPacket, addr *net.UDPAddr) {\n\ttm := time.Now()\n\tfields := make(map[string]interface{}, len(packet.Variables)+1)\n\ttags := map[string]string{\n\t\t\"version\": packet.Version.String(),\n\t\t\"source\":  addr.IP.String(),\n\t}\n\n\tif s.Log.Level().Includes(telegraf.Trace) {\n\t\tbuf, err := packet.MarshalMsg()\n\t\tif err != nil {\n\t\t\ts.Log.Debugf(\"marshaling message failed: %v\", err)\n\t\t} else {\n\t\t\ts.Log.Tracef(\"raw message: %s\", hex.EncodeToString(buf))\n\t\t}\n\t\ts.Log.Tracef(\"message: %s\", packet.SafeString())\n\t}\n\n\tif packet.Version == gosnmp.Version1 {\n\t\t// Follow the procedure described in RFC 2576 3.1 to\n\t\t// translate a v1 trap to v2.\n\t\tvar trapOid string\n\n\t\tif packet.GenericTrap >= 0 && packet.GenericTrap < 6 {\n\t\t\ttrapOid = \".1.3.6.1.6.3.1.1.5.\" + strconv.Itoa(packet.GenericTrap+1)\n\t\t} else if packet.GenericTrap == 6 {\n\t\t\ttrapOid = packet.Enterprise + \".0.\" + strconv.Itoa(packet.SpecificTrap)\n\t\t}\n\n\t\tif trapOid != \"\" {\n\t\t\te, err := s.transl.lookup(trapOid)\n\t\t\tif err != nil {\n\t\t\t\ts.Log.Errorf(\"Error resolving V1 OID, oid=%s, source=%s: %v\", trapOid, tags[\"source\"], err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tsetTrapOid(tags, trapOid, e)\n\t\t}\n\n\t\tif packet.AgentAddress != \"\" {\n\t\t\ttags[\"agent_address\"] = packet.AgentAddress\n\t\t}\n\n\t\tfields[\"sysUpTimeInstance\"] = packet.Timestamp\n\t}\n\n\tfor _, v := range packet.Variables {\n\t\tvar value interface{}\n\n\t\t// Use system mibs to resolve oids. Don't fall back to numeric oid\n\t\t// because it's not useful enough to the end user and can be difficult\n\t\t// to translate or remove from the database later.\n\t\t//\n\t\t// TODO: format the pdu value based on its snmp type and the mib's\n\t\t// textual convention. The snmp input plugin only handles textual\n\t\t// convention for ip and mac addresses\n\t\tswitch v.Type {\n\t\tcase gosnmp.ObjectIdentifier:\n\t\t\tval, ok := v.Value.(string)\n\t\t\tif !ok {\n\t\t\t\ts.Log.Errorf(\"Error getting value OID\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar e snmp.MibEntry\n\t\t\tvar err error\n\t\t\te, err = s.transl.lookup(val)\n\t\t\tif nil != err {\n\t\t\t\ts.Log.Errorf(\"Error resolving value OID, oid=%s, source=%s: %v\", val, tags[\"source\"], err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvalue = e.OidText\n\n\t\t\t// 1.3.6.1.6.3.1.1.4.1.0 is SNMPv2-MIB::snmpTrapOID.0.\n\t\t\t// If v.Name is this oid, set a tag of the trap name.\n\t\t\tif v.Name == \".1.3.6.1.6.3.1.1.4.1.0\" {\n\t\t\t\tsetTrapOid(tags, val, e)\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase gosnmp.OctetString:\n\t\t\t// OctetStrings may contain hex data that needs its own conversion\n\t\t\tif !utf8.Valid(v.Value.([]byte)[:]) {\n\t\t\t\tvalue = hex.EncodeToString(v.Value.([]byte))\n\t\t\t} else {\n\t\t\t\tvalue = v.Value\n\t\t\t}\n\t\tdefault:\n\t\t\tvalue = v.Value\n\t\t}\n\n\t\te, err := s.transl.lookup(v.Name)\n\t\tif nil != err {\n\t\t\ts.Log.Errorf(\"Error resolving OID oid=%s, source=%s: %v\", v.Name, tags[\"source\"], err)\n\t\t\treturn\n\t\t}\n\n\t\tfields[e.OidText] = value\n\t}\n\n\tif packet.Version == gosnmp.Version3 {\n\t\tif packet.ContextName != \"\" {\n\t\t\ttags[\"context_name\"] = packet.ContextName\n\t\t}\n\t\tif packet.ContextEngineID != \"\" {\n\t\t\t// SNMP RFCs like 3411 and 5343 show engine ID as a hex string\n\t\t\ttags[\"engine_id\"] = fmt.Sprintf(\"%x\", packet.ContextEngineID)\n\t\t}\n\t} else {\n\t\tif packet.Community != \"\" {\n\t\t\ttags[\"community\"] = packet.Community\n\t\t}\n\t}\n\n\ts.acc.AddFields(\"snmp_trap\", fields, tags, tm)\n}\n\nfunc init() {\n\tinputs.Add(\"snmp_trap\", func() telegraf.Input {\n\t\treturn &SnmpTrap{\n\t\t\tServiceAddress: \"udp://:162\",\n\t\t\tTimeout:        defaultTimeout,\n\t\t\tPath:           []string{\"/usr/share/snmp/mibs\"},\n\t\t\tVersion:        \"2c\",\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/snmp_trap/snmp_trap_test.go",
    "content": "package snmp_trap\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gosnmp/gosnmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/snmp\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestReceiveTrapV1(t *testing.T) {\n\tnow := uint32(123123123)\n\n\t// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will\n\t// prepend one with time.Now()\n\tvar tests = []struct {\n\t\tname string\n\n\t\t// send\n\t\ttrap gosnmp.SnmpTrap // include pdus\n\n\t\t// receive\n\t\tentries  []entry\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"trap enterprise\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.2.3.4.5\",\n\t\t\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\t\t\tValue: \"payload\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tEnterprise:   \".1.2.3\",\n\t\t\t\tAgentAddress: \"10.20.30.40\",\n\t\t\t\tGenericTrap:  6, // enterpriseSpecific\n\t\t\t\tSpecificTrap: 55,\n\t\t\t\tTimestamp:    uint(now),\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\t\".1.2.3.4.5\",\n\t\t\t\t\tsnmp.MibEntry{\n\t\t\t\t\t\tMibName: \"valueMIB\",\n\t\t\t\t\t\tOidText: \"valueOID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\".1.2.3.0.55\",\n\t\t\t\t\tsnmp.MibEntry{\n\t\t\t\t\t\tMibName: \"enterpriseMIB\",\n\t\t\t\t\t\tOidText: \"enterpriseOID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"oid\":           \".1.2.3.0.55\",\n\t\t\t\t\t\t\"name\":          \"enterpriseOID\",\n\t\t\t\t\t\t\"mib\":           \"enterpriseMIB\",\n\t\t\t\t\t\t\"version\":       \"1\",\n\t\t\t\t\t\t\"source\":        \"127.0.0.1\",\n\t\t\t\t\t\t\"agent_address\": \"10.20.30.40\",\n\t\t\t\t\t\t\"community\":     \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"sysUpTimeInstance\": uint(now),\n\t\t\t\t\t\t\"valueOID\":          \"payload\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// v1 generic trap\n\t\t{\n\t\t\tname: \"trap generic\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.2.3.4.5\",\n\t\t\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\t\t\tValue: \"payload\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.2.3.4.6\",\n\t\t\t\t\t\tType:  gosnmp.OctetString,\n\t\t\t\t\t\tValue: []byte{0x7, 0xe8, 0x1, 0x4, 0xe, 0x2, 0x19, 0x0, 0x0, 0xe, 0x2},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tEnterprise:   \".1.2.3\",\n\t\t\t\tAgentAddress: \"10.20.30.40\",\n\t\t\t\tGenericTrap:  0, // coldStart\n\t\t\t\tSpecificTrap: 0,\n\t\t\t\tTimestamp:    uint(now),\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\t\".1.2.3.4.5\",\n\t\t\t\t\tsnmp.MibEntry{\n\t\t\t\t\t\tMibName: \"valueMIB\",\n\t\t\t\t\t\tOidText: \"valueOID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\".1.2.3.4.6\",\n\t\t\t\t\tsnmp.MibEntry{\n\t\t\t\t\t\tMibName: \"valueMIB\",\n\t\t\t\t\t\tOidText: \"valueHexOID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\tsnmp.MibEntry{\n\t\t\t\t\t\tMibName: \"coldStartMIB\",\n\t\t\t\t\t\tOidText: \"coldStartOID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"oid\":           \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":          \"coldStartOID\",\n\t\t\t\t\t\t\"mib\":           \"coldStartMIB\",\n\t\t\t\t\t\t\"version\":       \"1\",\n\t\t\t\t\t\t\"source\":        \"127.0.0.1\",\n\t\t\t\t\t\t\"agent_address\": \"10.20.30.40\",\n\t\t\t\t\t\t\"community\":     \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"sysUpTimeInstance\": uint(now),\n\t\t\t\t\t\t\"valueOID\":          \"payload\",\n\t\t\t\t\t\t\"valueHexOID\":       \"07e801040e021900000e02\",\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// We would prefer to specify port 0 and let the network\n\t\t\t// stack choose an unused port for us but TrapListener\n\t\t\t// doesn't have a way to return the autoselected port.\n\t\t\t// Instead, we'll use an unusual port and hope it's\n\t\t\t// unused.\n\t\t\tconst port = 12399\n\n\t\t\t// Set up the service input plugin\n\t\t\tplugin := &SnmpTrap{\n\t\t\t\tServiceAddress: \"udp://:\" + strconv.Itoa(port),\n\t\t\t\tVersion:        \"1\",\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\ttransl:         &testTranslator{entries: tt.entries},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Start the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a v1 client and send the trap\n\t\t\tclient := &gosnmp.GoSNMP{\n\t\t\t\tPort:      port,\n\t\t\t\tVersion:   gosnmp.Version1,\n\t\t\t\tTimeout:   2 * time.Second,\n\t\t\t\tRetries:   1,\n\t\t\t\tMaxOids:   gosnmp.MaxOids,\n\t\t\t\tTarget:    \"127.0.0.1\",\n\t\t\t\tCommunity: \"public\",\n\t\t\t}\n\t\t\trequire.NoError(t, client.Connect(), \"connecting failed\")\n\t\t\tdefer client.Conn.Close()\n\t\t\t_, err := client.SendTrap(tt.trap)\n\t\t\trequire.NoError(t, err, \"sending failed\")\n\t\t\trequire.NoError(t, client.Conn.Close(), \"closing failed\")\n\n\t\t\t// Wait for trap to be received\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"timed out waiting for trap to be received\")\n\n\t\t\t// Verify plugin output\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestReceiveTrapV2c(t *testing.T) {\n\tnow := uint32(123123123)\n\n\t// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will\n\t// prepend one with time.Now()\n\tvar tests = []struct {\n\t\tname string\n\n\t\t// send\n\t\ttrap gosnmp.SnmpTrap // include pdus\n\n\t\t// receive\n\t\tentries  []entry\n\t\texpected []telegraf.Metric\n\t}{\n\t\t// ordinary v2c coldStart trap\n\t\t{\n\t\t\tname: \"v2c coldStart\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":       \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":      \"coldStart\",\n\t\t\t\t\t\t\"mib\":       \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\":   \"2c\",\n\t\t\t\t\t\t\"source\":    \"127.0.0.1\",\n\t\t\t\t\t\t\"community\": \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// We would prefer to specify port 0 and let the network\n\t\t\t// stack choose an unused port for us but TrapListener\n\t\t\t// doesn't have a way to return the autoselected port.\n\t\t\t// Instead, we'll use an unusual port and hope it's\n\t\t\t// unused.\n\t\t\tconst port = 12399\n\n\t\t\t// Set up the service input plugin\n\t\t\tplugin := &SnmpTrap{\n\t\t\t\tServiceAddress: \"udp://:\" + strconv.Itoa(port),\n\t\t\t\tVersion:        \"2c\",\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\ttransl:         &testTranslator{entries: tt.entries},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a v1 client and send the trap\n\t\t\tclient := &gosnmp.GoSNMP{\n\t\t\t\tPort:      port,\n\t\t\t\tVersion:   gosnmp.Version2c,\n\t\t\t\tTimeout:   2 * time.Second,\n\t\t\t\tRetries:   1,\n\t\t\t\tMaxOids:   gosnmp.MaxOids,\n\t\t\t\tTarget:    \"127.0.0.1\",\n\t\t\t\tCommunity: \"public\",\n\t\t\t}\n\t\t\trequire.NoError(t, client.Connect(), \"connecting failed\")\n\t\t\tdefer client.Conn.Close()\n\t\t\t_, err := client.SendTrap(tt.trap)\n\t\t\trequire.NoError(t, err, \"sending failed\")\n\t\t\trequire.NoError(t, client.Conn.Close(), \"closing failed\")\n\n\t\t\t// Wait for trap to be received\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"timed out waiting for trap to be received\")\n\n\t\t\t// Verify plugin output\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestReceiveTrapV3(t *testing.T) {\n\tnow := uint32(123123123)\n\n\t// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will\n\t// prepend one with time.Now()\n\tvar tests = []struct {\n\t\tname string\n\n\t\t// send\n\t\ttrap gosnmp.SnmpTrap // include pdus\n\n\t\t// auth and priv parameters\n\t\tsecName   string // v3 username\n\t\tsecLevel  string // v3 security level\n\t\tauthProto string // Auth protocol: \"\", MD5 or SHA\n\t\tauthPass  string // Auth passphrase\n\t\tprivProto string // Priv protocol: \"\", DES or AES\n\t\tprivPass  string // Priv passphrase\n\n\t\t// sender context\n\t\tcontextName string\n\t\tengineID    string\n\n\t\t// receive\n\t\tentries  []entry\n\t\texpected []telegraf.Metric\n\t}{\n\t\t// ordinary v3 coldStart trap no auth and no priv\n\t\t{\n\t\t\tname:        \"noAuthNoPriv\",\n\t\t\tsecName:     \"peter\",\n\t\t\tsecLevel:    \"noAuthNoPriv\",\n\t\t\tcontextName: \"foo_context_name\",\n\t\t\tengineID:    \"bar_engine_id\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":          \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":         \"coldStart\",\n\t\t\t\t\t\t\"mib\":          \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\":      \"3\",\n\t\t\t\t\t\t\"source\":       \"127.0.0.1\",\n\t\t\t\t\t\t\"context_name\": \"foo_context_name\",\n\t\t\t\t\t\t\"engine_id\":    \"6261725f656e67696e655f6964\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap SHA auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv SHA\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap SHA224 auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv SHA224\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"SHA224\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap SHA256 auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv SHA256\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"SHA256\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap SHA384 auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv SHA384\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"SHA384\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap SHA512 auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv SHA512\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"SHA512\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldstart trap MD5 auth and no priv\n\t\t{\n\t\t\tname:      \"authNoPriv MD5\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authNoPriv\",\n\t\t\tauthProto: \"MD5\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and AES priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-AES\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"AES\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and DES priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-DES\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"DES\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and AES192 priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-AES192\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"AES192\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and AES192C priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-AES192C\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"AES192C\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and AES256 priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-AES256\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"AES256\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\t// ordinary v3 coldStart SHA trap auth and AES256C priv\n\t\t{\n\t\t\tname:      \"authPriv SHA-AES256C\",\n\t\t\tsecName:   \"peter\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"SHA\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"AES256C\",\n\t\t\tprivPass:  \"passpass\",\n\t\t\ttrap: gosnmp.SnmpTrap{\n\t\t\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\t\t\tValue: now,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tentries: []entry{\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\t\t\tOidText: \"coldStart\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\t\te: snmp.MibEntry{\n\t\t\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\tmetric.New(\n\t\t\t\t\t\"snmp_trap\", // name\n\t\t\t\t\tmap[string]string{ // tags\n\t\t\t\t\t\t\"oid\":     \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\t\t\t\t\"name\":    \"coldStart\",\n\t\t\t\t\t\t\"mib\":     \"SNMPv2-MIB\",\n\t\t\t\t\t\t\"version\": \"3\",\n\t\t\t\t\t\t\"source\":  \"127.0.0.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{ // fields\n\t\t\t\t\t\t\"sysUpTimeInstance\": now,\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(0, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// We would prefer to specify port 0 and let the network\n\t\t\t// stack choose an unused port for us but TrapListener\n\t\t\t// doesn't have a way to return the autoselected port.\n\t\t\t// Instead, we'll use an unusual port and hope it's\n\t\t\t// unused.\n\t\t\tconst port = 12399\n\n\t\t\t// Set up the service input plugin\n\t\t\tplugin := &SnmpTrap{\n\t\t\t\tServiceAddress: \"udp://:\" + strconv.Itoa(port),\n\t\t\t\tVersion:        \"3\",\n\t\t\t\tSecName:        config.NewSecret([]byte(tt.secName)),\n\t\t\t\tSecLevel:       tt.secLevel,\n\t\t\t\tAuthProtocol:   tt.authProto,\n\t\t\t\tAuthPassword:   config.NewSecret([]byte(tt.authPass)),\n\t\t\t\tPrivProtocol:   tt.privProto,\n\t\t\t\tPrivPassword:   config.NewSecret([]byte(tt.privPass)),\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\ttransl:         &testTranslator{entries: tt.entries},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a v3 client and send the trap\n\t\t\tvar msgFlags gosnmp.SnmpV3MsgFlags\n\t\t\tswitch strings.ToLower(tt.secLevel) {\n\t\t\tcase \"noauthnopriv\", \"\":\n\t\t\t\tmsgFlags = gosnmp.NoAuthNoPriv\n\t\t\tcase \"authnopriv\":\n\t\t\t\tmsgFlags = gosnmp.AuthNoPriv\n\t\t\tcase \"authpriv\":\n\t\t\t\tmsgFlags = gosnmp.AuthPriv\n\t\t\tdefault:\n\t\t\t\trequire.FailNowf(t, \"unknown security level %q\", tt.secLevel)\n\t\t\t}\n\t\t\tsecurity := createSecurityParameters(tt.authProto, tt.privProto, tt.secName, tt.privPass, tt.authPass)\n\n\t\t\tclient := &gosnmp.GoSNMP{\n\t\t\t\tPort:               port,\n\t\t\t\tVersion:            gosnmp.Version3,\n\t\t\t\tTimeout:            2 * time.Second,\n\t\t\t\tRetries:            1,\n\t\t\t\tMaxOids:            gosnmp.MaxOids,\n\t\t\t\tTarget:             \"127.0.0.1\",\n\t\t\t\tSecurityParameters: security,\n\t\t\t\tSecurityModel:      gosnmp.UserSecurityModel,\n\t\t\t\tMsgFlags:           msgFlags,\n\t\t\t\tContextName:        tt.contextName,\n\t\t\t\tContextEngineID:    tt.engineID,\n\t\t\t}\n\t\t\trequire.NoError(t, client.Connect(), \"connecting failed\")\n\t\t\tdefer client.Conn.Close()\n\t\t\t_, err := client.SendTrap(tt.trap)\n\t\t\trequire.NoError(t, err, \"sending failed\")\n\t\t\trequire.NoError(t, client.Conn.Close(), \"closing failed\")\n\n\t\t\t// Wait for trap to be received\n\t\t\trequire.Eventually(t, func() bool {\n\t\t\t\treturn acc.NMetrics() >= uint64(len(tt.expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"timed out waiting for trap to be received\")\n\n\t\t\t// Verify plugin output\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())\n\t\t})\n\t}\n}\n\nfunc TestOidLookupFail(t *testing.T) {\n\tnow := uint32(123123123)\n\n\t// Check that we're not running snmptranslate to look up oids\n\t// when we shouldn't. This sends and receives a valid trap\n\t// but metric production should fail because the oids aren't in\n\t// the cache and oid lookup is intentionally mocked to fail.\n\ttrap := gosnmp.SnmpTrap{\n\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t{\n\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\tValue: now,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t},\n\t\t},\n\t}\n\n\t// We would prefer to specify port 0 and let the network\n\t// stack choose an unused port for us but TrapListener\n\t// doesn't have a way to return the autoselected port.\n\t// Instead, we'll use an unusual port and hope it's\n\t// unused.\n\tconst port = 12399\n\n\t// Set up the service input plugin\n\tlogger := &testutil.CaptureLogger{}\n\tfail := make(chan bool, 1)\n\tplugin := &SnmpTrap{\n\t\tServiceAddress: \"udp://:\" + strconv.Itoa(port),\n\t\tVersion:        \"2c\",\n\t\tLog:            logger,\n\t\ttransl:         &testTranslator{fail: fail},\n\t}\n\trequire.NoError(t, plugin.Init())\n\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\t// Create a v1 client and send the trap\n\tclient := &gosnmp.GoSNMP{\n\t\tPort:      port,\n\t\tVersion:   gosnmp.Version2c,\n\t\tTimeout:   2 * time.Second,\n\t\tRetries:   1,\n\t\tMaxOids:   gosnmp.MaxOids,\n\t\tTarget:    \"127.0.0.1\",\n\t\tCommunity: \"public\",\n\t}\n\trequire.NoError(t, client.Connect(), \"connecting failed\")\n\tdefer client.Conn.Close()\n\t_, err := client.SendTrap(trap)\n\trequire.NoError(t, err, \"sending failed\")\n\trequire.NoError(t, client.Conn.Close(), \"closing failed\")\n\n\t// Wait for lookup to fail\n\tselect {\n\tcase <-fail:\n\tcase <-time.After(time.Second):\n\t\tt.Log(\"timeout waiting for failing OID lookup\")\n\t\tt.Fail()\n\t}\n\n\t// Verify plugin output\n\trequire.Empty(t, acc.GetTelegrafMetrics())\n\n\t// Wait for the logging message to appear and check if it is the one we\n\t// expect.\n\trequire.Eventually(t, func() bool {\n\t\treturn len(logger.Errors()) > 0\n\t}, 3*time.Second, 100*time.Millisecond)\n\n\tvar found bool\n\tfor _, msg := range logger.Errors() {\n\t\tif found = strings.Contains(msg, \"unexpected oid\"); found {\n\t\t\tbreak\n\t\t}\n\t}\n\trequire.True(t, found, \"did not receive expected error message\")\n}\n\nfunc TestInvalidAuth(t *testing.T) {\n\tnow := uint32(time.Now().Unix())\n\ttrap := gosnmp.SnmpTrap{\n\t\tVariables: []gosnmp.SnmpPDU{\n\t\t\t{\n\t\t\t\tName:  \".1.3.6.1.2.1.1.3.0\",\n\t\t\t\tType:  gosnmp.TimeTicks,\n\t\t\t\tValue: now,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \".1.3.6.1.6.3.1.1.4.1.0\", // SNMPv2-MIB::snmpTrapOID.0\n\t\t\t\tType:  gosnmp.ObjectIdentifier,\n\t\t\t\tValue: \".1.3.6.1.6.3.1.1.5.1\", // coldStart\n\t\t\t},\n\t\t},\n\t}\n\ttranslator := &testTranslator{entries: []entry{\n\t\t{\n\t\t\toid: \".1.3.6.1.6.3.1.1.4.1.0\",\n\t\t\te: snmp.MibEntry{\n\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\tOidText: \"snmpTrapOID.0\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\toid: \".1.3.6.1.6.3.1.1.5.1\",\n\t\t\te: snmp.MibEntry{\n\t\t\t\tMibName: \"SNMPv2-MIB\",\n\t\t\t\tOidText: \"coldStart\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\toid: \".1.3.6.1.2.1.1.3.0\",\n\t\t\te: snmp.MibEntry{\n\t\t\t\tMibName: \"UNUSED_MIB_NAME\",\n\t\t\t\tOidText: \"sysUpTimeInstance\",\n\t\t\t},\n\t\t},\n\t},\n\t}\n\n\t// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will\n\t// prepend one with time.Now()\n\tvar tests = []struct {\n\t\tname      string\n\t\tuser      string // v3 username\n\t\tsecLevel  string // v3 security level\n\t\tauthProto string // Auth protocol: \"\", MD5 or SHA\n\t\tauthPass  string // Auth passphrase\n\t\tprivProto string // Priv protocol: \"\", DES or AES\n\t\tprivPass  string // Priv passphrase\n\t\texpected  string\n\t}{\n\t\t{\n\t\t\tname:     \"no authentication\",\n\t\t\tuser:     \"franz\",\n\t\t\tsecLevel: \"NoAuthNoPriv\",\n\t\t},\n\t\t{\n\t\t\tname:      \"wrong username\",\n\t\t\tuser:      \"foo\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"sha\",\n\t\t\tauthPass:  \"what a nice day\",\n\t\t\tprivProto: \"aes\",\n\t\t\tprivPass:  \"for my privacy\",\n\t\t},\n\t\t{\n\t\t\tname:      \"wrong password\",\n\t\t\tuser:      \"franz\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"sha\",\n\t\t\tauthPass:  \"passpass\",\n\t\t\tprivProto: \"aes\",\n\t\t\tprivPass:  \"for my privacy\",\n\t\t},\n\t\t{\n\t\t\tname:      \"wrong auth protocol\",\n\t\t\tuser:      \"franz\",\n\t\t\tsecLevel:  \"authPriv\",\n\t\t\tauthProto: \"md5\",\n\t\t\tauthPass:  \"what a nice day\",\n\t\t\tprivProto: \"aes\",\n\t\t\tprivPass:  \"for my privacy\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// We would prefer to specify port 0 and let the network\n\t\t\t// stack choose an unused port for us but TrapListener\n\t\t\t// doesn't have a way to return the autoselected port.\n\t\t\t// Instead, we'll use an unusual port and hope it's\n\t\t\t// unused.\n\t\t\tconst port = 12399\n\n\t\t\t// Set up the service input plugin\n\t\t\tplugin := &SnmpTrap{\n\t\t\t\tServiceAddress: \"udp://:\" + strconv.Itoa(port),\n\t\t\t\tVersion:        \"3\",\n\t\t\t\tSecName:        config.NewSecret([]byte(\"franz\")),\n\t\t\t\tSecLevel:       \"authPriv\",\n\t\t\t\tAuthProtocol:   \"sha\",\n\t\t\t\tAuthPassword:   config.NewSecret([]byte(\"what a nice day\")),\n\t\t\t\tPrivProtocol:   \"aes\",\n\t\t\t\tPrivPassword:   config.NewSecret([]byte(\"for my privacy\")),\n\t\t\t\tLog:            testutil.Logger{},\n\t\t\t\ttransl:         translator,\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Inject special logger\n\t\t\tfound := make(chan bool, 1)\n\t\t\tplugin.listener.Params.Logger = gosnmp.NewLogger(\n\t\t\t\t&testLogger{matcher: \"incoming packet is not authentic\", out: found},\n\t\t\t)\n\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a v3 client and send the trap\n\t\t\tvar msgFlags gosnmp.SnmpV3MsgFlags\n\t\t\tswitch strings.ToLower(tt.secLevel) {\n\t\t\tcase \"noauthnopriv\", \"\":\n\t\t\t\tmsgFlags = gosnmp.NoAuthNoPriv\n\t\t\tcase \"authnopriv\":\n\t\t\t\tmsgFlags = gosnmp.AuthNoPriv\n\t\t\tcase \"authpriv\":\n\t\t\t\tmsgFlags = gosnmp.AuthPriv\n\t\t\tdefault:\n\t\t\t\trequire.FailNowf(t, \"unknown security level %q\", tt.secLevel)\n\t\t\t}\n\t\t\tsecurity := createSecurityParameters(tt.authProto, tt.privProto, tt.user, tt.privPass, tt.authPass)\n\n\t\t\tclient := &gosnmp.GoSNMP{\n\t\t\t\tPort:               port,\n\t\t\t\tVersion:            gosnmp.Version3,\n\t\t\t\tTimeout:            2 * time.Second,\n\t\t\t\tRetries:            1,\n\t\t\t\tMaxOids:            gosnmp.MaxOids,\n\t\t\t\tTarget:             \"127.0.0.1\",\n\t\t\t\tSecurityParameters: security,\n\t\t\t\tSecurityModel:      gosnmp.UserSecurityModel,\n\t\t\t\tMsgFlags:           msgFlags,\n\t\t\t\tContextName:        \"context-name\",\n\t\t\t\tContextEngineID:    \"engine no 5\",\n\t\t\t}\n\t\t\trequire.NoError(t, client.Connect(), \"connecting failed\")\n\t\t\tdefer client.Conn.Close()\n\t\t\t_, err := client.SendTrap(trap)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, client.Conn.Close(), \"closing failed\")\n\n\t\t\t// Wait for error to be logged\n\t\t\tselect {\n\t\t\tcase <-found:\n\t\t\tcase <-time.After(3 * time.Second):\n\t\t\t\tt.Fatal(\"timed out waiting for unauthenticated log\")\n\t\t\t}\n\n\t\t\t// Verify plugin output\n\t\t\trequire.Empty(t, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc createSecurityParameters(authProto, privProto, username, privPass, authPass string) *gosnmp.UsmSecurityParameters {\n\tvar authenticationProtocol gosnmp.SnmpV3AuthProtocol\n\tswitch strings.ToLower(authProto) {\n\tcase \"md5\":\n\t\tauthenticationProtocol = gosnmp.MD5\n\tcase \"sha\":\n\t\tauthenticationProtocol = gosnmp.SHA\n\tcase \"sha224\":\n\t\tauthenticationProtocol = gosnmp.SHA224\n\tcase \"sha256\":\n\t\tauthenticationProtocol = gosnmp.SHA256\n\tcase \"sha384\":\n\t\tauthenticationProtocol = gosnmp.SHA384\n\tcase \"sha512\":\n\t\tauthenticationProtocol = gosnmp.SHA512\n\tcase \"\":\n\t\tauthenticationProtocol = gosnmp.NoAuth\n\tdefault:\n\t\tauthenticationProtocol = gosnmp.NoAuth\n\t}\n\n\tvar privacyProtocol gosnmp.SnmpV3PrivProtocol\n\tswitch strings.ToLower(privProto) {\n\tcase \"aes\":\n\t\tprivacyProtocol = gosnmp.AES\n\tcase \"des\":\n\t\tprivacyProtocol = gosnmp.DES\n\tcase \"aes192\":\n\t\tprivacyProtocol = gosnmp.AES192\n\tcase \"aes192c\":\n\t\tprivacyProtocol = gosnmp.AES192C\n\tcase \"aes256\":\n\t\tprivacyProtocol = gosnmp.AES256\n\tcase \"aes256c\":\n\t\tprivacyProtocol = gosnmp.AES256C\n\tcase \"\":\n\t\tprivacyProtocol = gosnmp.NoPriv\n\tdefault:\n\t\tprivacyProtocol = gosnmp.NoPriv\n\t}\n\n\treturn &gosnmp.UsmSecurityParameters{\n\t\tAuthoritativeEngineID:    \"deadbeef\", // has to be between 5 & 32 chars\n\t\tAuthoritativeEngineBoots: 1,\n\t\tAuthoritativeEngineTime:  1,\n\t\tUserName:                 username,\n\t\tPrivacyProtocol:          privacyProtocol,\n\t\tPrivacyPassphrase:        privPass,\n\t\tAuthenticationPassphrase: authPass,\n\t\tAuthenticationProtocol:   authenticationProtocol,\n\t}\n}\n\ntype entry struct {\n\toid string\n\te   snmp.MibEntry\n}\n\ntype testTranslator struct {\n\tentries []entry\n\tfail    chan bool\n}\n\nfunc (t *testTranslator) lookup(input string) (snmp.MibEntry, error) {\n\tfor _, entry := range t.entries {\n\t\tif input == entry.oid {\n\t\t\treturn snmp.MibEntry{MibName: entry.e.MibName, OidText: entry.e.OidText}, nil\n\t\t}\n\t}\n\tif t.fail != nil {\n\t\tt.fail <- true\n\t}\n\treturn snmp.MibEntry{}, errors.New(\"unexpected oid\")\n}\n\ntype testLogger struct {\n\tmatcher string\n\tout     chan bool\n}\n\nfunc (l *testLogger) Print(v ...interface{}) {\n\tif strings.Contains(fmt.Sprint(v...), l.matcher) {\n\t\tl.out <- true\n\t}\n}\n\nfunc (l *testLogger) Printf(format string, v ...interface{}) {\n\tif strings.Contains(fmt.Sprintf(format, v...), l.matcher) {\n\t\tl.out <- true\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/socket_listener/README.md",
    "content": "# Socket Listener Input Plugin\n\nThis service plugin listens for messages on sockets (TCP, UDP, Unix or Unixgram)\nand parses the packets received in one of the supported\n[data formats][data_formats].\n\n⭐ Telegraf v1.3.0\n🏷️ network\n💻 all\n\n[data_formats]: /docs/DATA_FORMATS_INPUT.md\n\n## Service Input <!-- @/docs/includes/service_input.md -->\n\nThis plugin is a service input. Normal plugins gather metrics determined by the\ninterval setting. Service plugins start a service to listen and wait for\nmetrics or events to occur. Service plugins have two key differences from\nnormal plugins:\n\n1. The global or plugin specific `interval` setting may not apply\n2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce\n   output for this plugin\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Generic socket listener capable of handling multiple socket types.\n[[inputs.socket_listener]]\n  ## URL to listen on\n  # service_address = \"tcp://:8094\"\n  # service_address = \"tcp://127.0.0.1:http\"\n  # service_address = \"tcp4://:8094\"\n  # service_address = \"tcp6://:8094\"\n  # service_address = \"tcp6://[2001:db8::1]:8094\"\n  # service_address = \"udp://:8094\"\n  # service_address = \"udp4://:8094\"\n  # service_address = \"udp6://:8094\"\n  # service_address = \"unix:///tmp/telegraf.sock\"\n  # service_address = \"unixgram:///tmp/telegraf.sock\"\n  # service_address = \"vsock://cid:port\"\n\n  ## Permission for unix sockets (only available on unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Maximum number of concurrent connections (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # max_connections = 0\n\n  ## Read timeout (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # read_timeout = \"0s\"\n\n  ## Optional TLS configuration (only available on stream sockets like TCP)\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key  = \"/etc/telegraf/key.pem\"\n  ## Enables client authentication if set.\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Maximum socket buffer size (in bytes when no unit specified)\n  ## For stream sockets, once the buffer fills up, the sender will start\n  ## backing up. For datagram sockets, once the buffer fills up, metrics will\n  ## start dropping. Defaults to the OS default.\n  # read_buffer_size = \"64KiB\"\n\n  ## Period between keep alive probes (only applies to TCP sockets)\n  ## Zero disables keep alive probes. Defaults to the OS configuration.\n  # keep_alive_period = \"5m\"\n\n  ## Content encoding for message payloads\n  ## Can be set to \"gzip\" for compressed payloads or \"identity\" for no encoding.\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded packet (in bytes when no unit specified)\n  # max_decompression_size = \"500MB\"\n\n  ## List of allowed source IP addresses for incoming packets/messages.\n  ## If not specified or empty, all sources are allowed.\n  # allowed_sources = []\n\n  ## Message splitting strategy and corresponding settings for stream sockets\n  ## (tcp, tcp4, tcp6, unix or unixpacket). The setting is ignored for packet\n  ## listeners such as udp.\n  ## Available strategies are:\n  ##   newline         -- split at newlines (default)\n  ##   null            -- split at null bytes\n  ##   delimiter       -- split at delimiter byte-sequence in hex-format\n  ##                      given in `splitting_delimiter`\n  ##   fixed length    -- split after number of bytes given in `splitting_length`\n  ##   variable length -- split depending on length information received in the\n  ##                      data. The length field information is specified in\n  ##                      `splitting_length_field`.\n  # splitting_strategy = \"newline\"\n\n  ## Delimiter used to split received data to messages consumed by the parser.\n  ## The delimiter is a hex byte-sequence marking the end of a message\n  ## e.g. \"0x0D0A\", \"x0d0a\" or \"0d0a\" marks a Windows line-break (CR LF).\n  ## The value is case-insensitive and can be specified with \"0x\" or \"x\" prefix\n  ## or without.\n  ## Note: This setting is only used for splitting_strategy = \"delimiter\".\n  # splitting_delimiter = \"\"\n\n  ## Fixed length of a message in bytes.\n  ## Note: This setting is only used for splitting_strategy = \"fixed length\".\n  # splitting_length = 0\n\n  ## Specification of the length field contained in the data to split messages\n  ## with variable length. The specification contains the following fields:\n  ##  offset        -- start of length field in bytes from begin of data\n  ##  bytes         -- length of length field in bytes\n  ##  endianness    -- endianness of the value, either \"be\" for big endian or\n  ##                   \"le\" for little endian\n  ##  header_length -- total length of header to be skipped when passing\n  ##                   data on to the parser. If zero (default), the header\n  ##                   is passed on to the parser together with the message.\n  ## Note: This setting is only used for splitting_strategy = \"variable length\".\n  # splitting_length_field = {offset = 0, bytes = 0, endianness = \"be\", header_length = 0}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n```\n\n### Operating System UDP Buffer Sizes\n\nThe `read_buffer_size` config option can be used to adjust the size of the\nsocket buffer, but this number is limited by OS settings. On Linux,\n`read_buffer_size` will default to `rmem_default` and will be capped by\n`rmem_max`. On BSD systems, `read_buffer_size` is capped by `maxsockbuf`, and\nthere is no OS default setting.\n\nInstructions on how to adjust these OS settings are available below.\n\nSome OSes (most notably, Linux) place very restrictive limits on the performance\nof UDP protocols. It is _highly_ recommended that you increase these OS limits\nto at least 8MB before trying to run large amounts of UDP traffic to your\ninstance.  8MB is just a recommendation, and can be adjusted higher.\n\n#### Linux\n\nCheck the current UDP/IP receive buffer limit and default by using the following\ncommands:\n\n```sh\nsysctl net.core.rmem_max\nsysctl net.core.rmem_default\n```\n\nIf the values are less than 8388608 bytes you should add the following lines to\nthe /etc/sysctl.conf file:\n\n```text\nnet.core.rmem_max=8388608\nnet.core.rmem_default=8388608\n```\n\nChanges to /etc/sysctl.conf do not take effect until reboot.\nTo update the values immediately, type the following commands as root:\n\n```sh\nsysctl -w net.core.rmem_max=8388608\nsysctl -w net.core.rmem_default=8388608\n```\n\n#### BSD/Darwin\n\nOn BSD/Darwin systems you need to add about a 15% padding to the kernel limit\nsocket buffer. Meaning if you want an 8MB buffer (8388608 bytes) you need to set\nthe kernel limit to `8388608*1.15 = 9646900`. This is not documented anywhere\nbut can be seen [in the kernel source code][kernel_source].\n\nCheck the current UDP/IP buffer limit by typing the following command:\n\n```sh\nsysctl kern.ipc.maxsockbuf\n```\n\nIf the value is less than 9646900 bytes you should add the following lines\nto the /etc/sysctl.conf file (create it if necessary):\n\n```text\nkern.ipc.maxsockbuf=9646900\n```\n\nChanges to /etc/sysctl.conf do not take effect until reboot.\nTo update the values immediately, type the following command as root:\n\n```sh\nsysctl -w kern.ipc.maxsockbuf=9646900\n```\n\n[kernel_source]: https://github.com/freebsd/freebsd/blob/master/sys/kern/uipc_sockbuf.c#L63-L64\n\n## Metrics\n\nThe plugin accepts arbitrary input and parses it according to the `data_format`\nsetting. There is no predefined metric format.\n\n## Example Output\n\nThere is no predefined metric format, so output depends on plugin input.\n"
  },
  {
    "path": "plugins/inputs/socket_listener/sample.conf",
    "content": "# Generic socket listener capable of handling multiple socket types.\n[[inputs.socket_listener]]\n  ## URL to listen on\n  # service_address = \"tcp://:8094\"\n  # service_address = \"tcp://127.0.0.1:http\"\n  # service_address = \"tcp4://:8094\"\n  # service_address = \"tcp6://:8094\"\n  # service_address = \"tcp6://[2001:db8::1]:8094\"\n  # service_address = \"udp://:8094\"\n  # service_address = \"udp4://:8094\"\n  # service_address = \"udp6://:8094\"\n  # service_address = \"unix:///tmp/telegraf.sock\"\n  # service_address = \"unixgram:///tmp/telegraf.sock\"\n  # service_address = \"vsock://cid:port\"\n\n  ## Permission for unix sockets (only available on unix sockets)\n  ## This setting may not be respected by some platforms. To safely restrict\n  ## permissions it is recommended to place the socket into a previously\n  ## created directory with the desired permissions.\n  ##   ex: socket_mode = \"777\"\n  # socket_mode = \"\"\n\n  ## Maximum number of concurrent connections (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # max_connections = 0\n\n  ## Read timeout (only available on stream sockets like TCP)\n  ## Zero means unlimited.\n  # read_timeout = \"0s\"\n\n  ## Optional TLS configuration (only available on stream sockets like TCP)\n  # tls_cert = \"/etc/telegraf/cert.pem\"\n  # tls_key  = \"/etc/telegraf/key.pem\"\n  ## Enables client authentication if set.\n  # tls_allowed_cacerts = [\"/etc/telegraf/clientca.pem\"]\n\n  ## Maximum socket buffer size (in bytes when no unit specified)\n  ## For stream sockets, once the buffer fills up, the sender will start\n  ## backing up. For datagram sockets, once the buffer fills up, metrics will\n  ## start dropping. Defaults to the OS default.\n  # read_buffer_size = \"64KiB\"\n\n  ## Period between keep alive probes (only applies to TCP sockets)\n  ## Zero disables keep alive probes. Defaults to the OS configuration.\n  # keep_alive_period = \"5m\"\n\n  ## Content encoding for message payloads\n  ## Can be set to \"gzip\" for compressed payloads or \"identity\" for no encoding.\n  # content_encoding = \"identity\"\n\n  ## Maximum size of decoded packet (in bytes when no unit specified)\n  # max_decompression_size = \"500MB\"\n\n  ## List of allowed source IP addresses for incoming packets/messages.\n  ## If not specified or empty, all sources are allowed.\n  # allowed_sources = []\n\n  ## Message splitting strategy and corresponding settings for stream sockets\n  ## (tcp, tcp4, tcp6, unix or unixpacket). The setting is ignored for packet\n  ## listeners such as udp.\n  ## Available strategies are:\n  ##   newline         -- split at newlines (default)\n  ##   null            -- split at null bytes\n  ##   delimiter       -- split at delimiter byte-sequence in hex-format\n  ##                      given in `splitting_delimiter`\n  ##   fixed length    -- split after number of bytes given in `splitting_length`\n  ##   variable length -- split depending on length information received in the\n  ##                      data. The length field information is specified in\n  ##                      `splitting_length_field`.\n  # splitting_strategy = \"newline\"\n\n  ## Delimiter used to split received data to messages consumed by the parser.\n  ## The delimiter is a hex byte-sequence marking the end of a message\n  ## e.g. \"0x0D0A\", \"x0d0a\" or \"0d0a\" marks a Windows line-break (CR LF).\n  ## The value is case-insensitive and can be specified with \"0x\" or \"x\" prefix\n  ## or without.\n  ## Note: This setting is only used for splitting_strategy = \"delimiter\".\n  # splitting_delimiter = \"\"\n\n  ## Fixed length of a message in bytes.\n  ## Note: This setting is only used for splitting_strategy = \"fixed length\".\n  # splitting_length = 0\n\n  ## Specification of the length field contained in the data to split messages\n  ## with variable length. The specification contains the following fields:\n  ##  offset        -- start of length field in bytes from begin of data\n  ##  bytes         -- length of length field in bytes\n  ##  endianness    -- endianness of the value, either \"be\" for big endian or\n  ##                   \"le\" for little endian\n  ##  header_length -- total length of header to be skipped when passing\n  ##                   data on to the parser. If zero (default), the header\n  ##                   is passed on to the parser together with the message.\n  ## Note: This setting is only used for splitting_strategy = \"variable length\".\n  # splitting_length_field = {offset = 0, bytes = 0, endianness = \"be\", header_length = 0}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/sample.conf.in",
    "content": "# Generic socket listener capable of handling multiple socket types.\n[[inputs.socket_listener]]\n  ## URL to listen on\n  # service_address = \"tcp://:8094\"\n  # service_address = \"tcp://127.0.0.1:http\"\n  # service_address = \"tcp4://:8094\"\n  # service_address = \"tcp6://:8094\"\n  # service_address = \"tcp6://[2001:db8::1]:8094\"\n  # service_address = \"udp://:8094\"\n  # service_address = \"udp4://:8094\"\n  # service_address = \"udp6://:8094\"\n  # service_address = \"unix:///tmp/telegraf.sock\"\n  # service_address = \"unixgram:///tmp/telegraf.sock\"\n  # service_address = \"vsock://cid:port\"\n\n{{template \"/plugins/common/socket/socket.conf\"}}\n\n{{template \"/plugins/common/socket/splitter.conf\"}}\n\n  ## Data format to consume.\n  ## Each data format has its own unique set of configuration options, read\n  ## more about them here:\n  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md\n  # data_format = \"influx\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/socket_listener.go",
    "content": "//go:generate ../../../tools/config_includer/generator\n//go:generate ../../../tools/readme_config_includer/generator\npackage socket_listener\n\nimport (\n\t_ \"embed\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/common/socket\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar once sync.Once\n\ntype SocketListener struct {\n\tServiceAddress string          `toml:\"service_address\"`\n\tTimeSource     string          `toml:\"time_source\"`\n\tLog            telegraf.Logger `toml:\"-\"`\n\tsocket.Config\n\tsocket.SplitConfig\n\n\tsocket *socket.Socket\n\tparser telegraf.Parser\n}\n\nfunc (*SocketListener) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (sl *SocketListener) SetParser(parser telegraf.Parser) {\n\tsl.parser = parser\n}\n\nfunc (sl *SocketListener) Init() error {\n\tsock, err := sl.Config.NewSocket(sl.ServiceAddress, &sl.SplitConfig, sl.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\tsl.socket = sock\n\n\treturn nil\n}\n\nfunc (sl *SocketListener) Start(acc telegraf.Accumulator) error {\n\t// Create the callbacks for parsing the data and recording issues\n\tonData := func(_ net.Addr, data []byte, receiveTime time.Time) {\n\t\tmetrics, err := sl.parser.Parse(data)\n\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\treturn\n\t\t}\n\n\t\tif len(metrics) == 0 {\n\t\t\tonce.Do(func() {\n\t\t\t\tsl.Log.Debug(internal.NoMetricsCreatedMsg)\n\t\t\t})\n\t\t}\n\n\t\tfor _, m := range metrics {\n\t\t\tswitch sl.TimeSource {\n\t\t\tcase \"\", \"metric\":\n\t\t\tcase \"receive_time\":\n\t\t\t\tm.SetTime(receiveTime)\n\t\t\t}\n\n\t\t\tacc.AddMetric(m)\n\t\t}\n\t}\n\tonError := func(err error) {\n\t\tacc.AddError(err)\n\t}\n\n\t// Start the listener\n\tif err := sl.socket.Setup(); err != nil {\n\t\treturn err\n\t}\n\tsl.socket.Listen(onData, onError)\n\taddr := sl.socket.Address()\n\tsl.Log.Infof(\"Listening on %s://%s\", addr.Network(), addr.String())\n\n\treturn nil\n}\n\nfunc (*SocketListener) Gather(telegraf.Accumulator) error {\n\treturn nil\n}\n\nfunc (sl *SocketListener) Stop() {\n\tif sl.socket != nil {\n\t\tsl.socket.Close()\n\t}\n}\n\nfunc init() {\n\tinputs.Add(\"socket_listener\", func() telegraf.Input {\n\t\treturn &SocketListener{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/socket_listener/socket_listener_test.go",
    "content": "package socket_listener\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/metric\"\n\t\"github.com/influxdata/telegraf/plugins/common/socket\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n\t_ \"github.com/influxdata/telegraf/plugins/parsers/all\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/value\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nvar pki = testutil.NewPKI(\"../../../testutil/pki\")\n\nfunc TestSocketListener(t *testing.T) {\n\tmessages := [][]byte{\n\t\t[]byte(\"test,foo=bar v=1i 123456789\\ntest,foo=baz v=2i 123456790\\n\"),\n\t\t[]byte(\"test,foo=zab v=3i 123456791\\n\"),\n\t}\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"bar\"},\n\t\t\tmap[string]interface{}{\"v\": int64(1)},\n\t\t\ttime.Unix(0, 123456789),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"baz\"},\n\t\t\tmap[string]interface{}{\"v\": int64(2)},\n\t\t\ttime.Unix(0, 123456790),\n\t\t),\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{\"foo\": \"zab\"},\n\t\t\tmap[string]interface{}{\"v\": int64(3)},\n\t\t\ttime.Unix(0, 123456791),\n\t\t),\n\t}\n\n\ttests := []struct {\n\t\tname       string\n\t\tschema     string\n\t\tbuffersize config.Size\n\t\tencoding   string\n\t}{\n\t\t{\n\t\t\tname:       \"TCP\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"TCP with TLS\",\n\t\t\tschema: \"tcp+tls\",\n\t\t},\n\t\t{\n\t\t\tname:       \"TCP with gzip encoding\",\n\t\t\tschema:     \"tcp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:       \"UDP with gzip encoding\",\n\t\t\tschema:     \"udp\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t\tencoding:   \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unix socket\",\n\t\t\tschema:     \"unix\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t\t{\n\t\t\tname:   \"unix socket with TLS\",\n\t\t\tschema: \"unix+tls\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unix socket with gzip encoding\",\n\t\t\tschema:   \"unix\",\n\t\t\tencoding: \"gzip\",\n\t\t},\n\t\t{\n\t\t\tname:       \"unixgram socket\",\n\t\t\tschema:     \"unixgram\",\n\t\t\tbuffersize: config.Size(1024),\n\t\t},\n\t}\n\n\tserverTLS := pki.TLSServerConfig()\n\tclientTLS := pki.TLSClientConfig()\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tproto := strings.TrimSuffix(tt.schema, \"+tls\")\n\n\t\t\t// Prepare the address and socket if needed\n\t\t\tvar serverAddr string\n\t\t\tvar tlsCfg *tls.Config\n\t\t\tswitch proto {\n\t\t\tcase \"tcp\", \"udp\":\n\t\t\t\tserverAddr = \"127.0.0.1:0\"\n\t\t\tcase \"unix\", \"unixgram\":\n\t\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\t\tt.Skip(\"Skipping on Windows, as unixgram sockets are not supported\")\n\t\t\t\t}\n\n\t\t\t\t// Create a socket\n\t\t\t\t// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases\n\t\t\t\t// (it combines test name with subtest name and some random numbers in the path).\n\t\t\t\t// Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.\n\t\t\t\t//nolint:usetesting // Ignore \"os.CreateTemp(\"\", ...) could be replaced by os.CreateTemp(t.TempDir(), ...) in TestSocketListener\" finding.\n\t\t\t\tsock, err := os.CreateTemp(\"\", \"sock-\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tdefer os.Remove(sock.Name())\n\t\t\t\tdefer sock.Close()\n\t\t\t\tserverAddr = sock.Name()\n\t\t\t}\n\n\t\t\t// Setup plugin according to test specification\n\t\t\tplugin := &SocketListener{\n\t\t\t\tServiceAddress: proto + \"://\" + serverAddr,\n\t\t\t\tConfig: socket.Config{\n\t\t\t\t\tContentEncoding: tt.encoding,\n\t\t\t\t\tReadBufferSize:  tt.buffersize,\n\t\t\t\t},\n\t\t\t\tLog: &testutil.Logger{},\n\t\t\t}\n\t\t\tif strings.HasSuffix(tt.schema, \"tls\") {\n\t\t\t\tplugin.ServerConfig = *serverTLS\n\t\t\t\tvar err error\n\t\t\t\ttlsCfg, err = clientTLS.TLSConfig()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\tplugin.SetParser(parser)\n\n\t\t\t// Start the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\taddr := plugin.socket.Address()\n\n\t\t\t// Create a noop client\n\t\t\t// Server is async, so verify no errors at the end.\n\t\t\tclient, err := createClient(plugin.ServiceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, client.Close())\n\n\t\t\t// Setup the client for submitting data\n\t\t\tclient, err = createClient(plugin.ServiceAddress, addr, tlsCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Send the data with the correct encoding\n\t\t\tencoder, err := internal.NewContentEncoder(tt.encoding)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor i, msg := range messages {\n\t\t\t\tm, err := encoder.Encode(msg)\n\t\t\t\trequire.NoErrorf(t, err, \"encoding failed for msg %d\", i)\n\t\t\t\t_, err = client.Write(m)\n\t\t\t\trequire.NoErrorf(t, err, \"sending msg %d failed\", i)\n\t\t\t}\n\n\t\t\t// Test the resulting metrics and compare against expected results\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d)\", acc.NMetrics())\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics())\n\t\t})\n\t}\n}\n\nfunc TestLargeReadBufferTCP(t *testing.T) {\n\t// Construct a buffer-size setting of 1000KiB\n\tvar bufsize config.Size\n\trequire.NoError(t, bufsize.UnmarshalText([]byte(\"1000KiB\")))\n\n\t// Setup plugin with a sufficient read buffer\n\tplugin := &SocketListener{\n\t\tServiceAddress: \"tcp://127.0.0.1:0\",\n\t\tConfig: socket.Config{\n\t\t\tReadBufferSize: bufsize,\n\t\t},\n\t\tSplitConfig: socket.SplitConfig{\n\t\t\tSplittingStrategy: \"newline\",\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\tparser := &value.Parser{\n\t\tMetricName: \"test\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a large message with the readbuffer size\n\tmessage := bytes.Repeat([]byte{'a'}, int(bufsize)-2)\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": string(message)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Start the plugin\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\taddr := plugin.socket.Address()\n\n\t// Setup the client for submitting data\n\tclient, err := createClient(plugin.ServiceAddress, addr, nil)\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\n\t_, err = client.Write(append(message, '\\n'))\n\trequire.NoError(t, err)\n\tclient.Close()\n\n\tgetError := func() error {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.FirstError()\n\t}\n\n\t// Test the resulting metrics and compare against expected results\n\trequire.Eventuallyf(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d): %v\", acc.NMetrics(), getError())\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestLargeReadBufferUnixgram(t *testing.T) {\n\t// Construct a buffer-size setting of 100KiB\n\t// Assuming that the testing environment has net.core.wmem_max set to a value greater than 100KiB\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipping on Windows, as unixgram sockets are not supported\")\n\t}\n\n\tif runtime.GOOS == \"darwin\" {\n\t\tt.Skip(\"Skipping on macOS (darwin), as unixgram write buffer size cannot be changed (default 2048 bytes)\")\n\t}\n\n\tvar bufsize config.Size\n\trequire.NoError(t, bufsize.UnmarshalText([]byte(\"100KiB\")))\n\n\t// Create a socket\n\tsock, err := os.CreateTemp(t.TempDir(), \"sock-\")\n\trequire.NoError(t, err)\n\tdefer sock.Close()\n\n\tvar serverAddr = sock.Name()\n\n\t// Setup plugin with a sufficient read buffer\n\tplugin := &SocketListener{\n\t\tServiceAddress: \"unixgram\" + \"://\" + serverAddr,\n\t\tConfig: socket.Config{\n\t\t\tReadBufferSize: bufsize,\n\t\t},\n\t\tLog: &testutil.Logger{},\n\t}\n\tparser := &value.Parser{\n\t\tMetricName: \"test\",\n\t\tDataType:   \"string\",\n\t}\n\trequire.NoError(t, parser.Init())\n\tplugin.SetParser(parser)\n\n\t// Create a large message with the readbuffer size\n\tmessage := bytes.Repeat([]byte{'a'}, int(bufsize))\n\texpected := []telegraf.Metric{\n\t\tmetric.New(\n\t\t\t\"test\",\n\t\t\tmap[string]string{},\n\t\t\tmap[string]interface{}{\"value\": string(message)},\n\t\t\ttime.Unix(0, 0),\n\t\t),\n\t}\n\n\t// Start the plugin\n\tvar acc testutil.Accumulator\n\trequire.NoError(t, plugin.Init())\n\trequire.NoError(t, plugin.Start(&acc))\n\tdefer plugin.Stop()\n\n\taddr := plugin.socket.Address()\n\n\t// Setup the client for submitting data\n\tclient, err := createClient(plugin.ServiceAddress, addr, nil)\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\n\t// Check the socket write buffer size\n\tunixConn, ok := client.(*net.UnixConn)\n\trequire.True(t, ok, \"client is not a *net.UnixConn\")\n\tif err := unixConn.SetWriteBuffer(len(message)); err != nil {\n\t\tt.Skipf(\"Failed to set write buffer size: %v. Skipping test.\", err)\n\t}\n\n\t// Write the message\n\t_, err = client.Write(message)\n\trequire.NoError(t, err)\n\tclient.Close()\n\n\tgetError := func() error {\n\t\tacc.Lock()\n\t\tdefer acc.Unlock()\n\t\treturn acc.FirstError()\n\t}\n\n\t// Test the resulting metrics and compare against expected results\n\trequire.Eventuallyf(t, func() bool {\n\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t}, time.Second, 100*time.Millisecond, \"did not receive metrics (%d): %v\", acc.NMetrics(), getError())\n\tactual := acc.GetTelegrafMetrics()\n\ttestutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())\n}\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testdata\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Register the plugin\n\tinputs.Add(\"socket_listener\", func() telegraf.Input {\n\t\treturn &SocketListener{}\n\t})\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Compare options\n\t\toptions := []cmp.Option{\n\t\t\ttestutil.IgnoreTime(),\n\t\t\ttestutil.SortMetrics(),\n\t\t}\n\n\t\tt.Run(f.Name(), func(t *testing.T) {\n\t\t\ttestcasePath := filepath.Join(\"testcases\", f.Name())\n\t\t\tconfigFilename := filepath.Join(testcasePath, \"telegraf.conf\")\n\t\t\tinputFilename := filepath.Join(testcasePath, \"sequence.json\")\n\t\t\texpectedFilename := filepath.Join(testcasePath, \"expected.out\")\n\t\t\texpectedErrorFilename := filepath.Join(testcasePath, \"expected.err\")\n\n\t\t\t// Prepare the influx parser for expectations\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\n\t\t\t// Read the input sequence\n\t\t\tsequence, err := readInputData(inputFilename)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, sequence)\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expected []telegraf.Metric\n\t\t\tif _, err := os.Stat(expectedFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Read the expected output if any\n\t\t\tvar expectedErrors []string\n\t\t\tif _, err := os.Stat(expectedErrorFilename); err == nil {\n\t\t\t\tvar err error\n\t\t\t\texpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, expectedErrors)\n\t\t\t}\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup and start the plugin\n\t\t\tvar acc testutil.Accumulator\n\t\t\tplugin := cfg.Inputs[0].Input.(*SocketListener)\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\tdefer plugin.Stop()\n\n\t\t\t// Create a client without TLS\n\t\t\taddr := plugin.socket.Address()\n\t\t\tclient, err := createClient(plugin.ServiceAddress, addr, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Write the given sequence\n\t\t\tfor i, step := range sequence {\n\t\t\t\tif step.Wait > 0 {\n\t\t\t\t\ttime.Sleep(time.Duration(step.Wait))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trequire.NotEmpty(t, step.raw, \"nothing to send\")\n\t\t\t\t_, err := client.Write(step.raw)\n\t\t\t\trequire.NoErrorf(t, err, \"writing step %d failed: %v\", i, err)\n\t\t\t}\n\t\t\trequire.NoError(t, client.Close())\n\n\t\t\tgetNErrors := func() int {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn len(acc.Errors)\n\t\t\t}\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\treturn getNErrors() >= len(expectedErrors)\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"did not receive errors (%d/%d)\", getNErrors(), len(expectedErrors))\n\n\t\t\trequire.Len(t, acc.Errors, len(expectedErrors))\n\t\t\tsort.SliceStable(acc.Errors, func(i, j int) bool {\n\t\t\t\treturn acc.Errors[i].Error() < acc.Errors[j].Error()\n\t\t\t})\n\t\t\tfor i, err := range acc.Errors {\n\t\t\t\trequire.ErrorContains(t, err, expectedErrors[i])\n\t\t\t}\n\n\t\t\trequire.Eventuallyf(t, func() bool {\n\t\t\t\tacc.Lock()\n\t\t\t\tdefer acc.Unlock()\n\t\t\t\treturn acc.NMetrics() >= uint64(len(expected))\n\t\t\t}, 3*time.Second, 100*time.Millisecond, \"did not receive metrics (%d/%d)\", acc.NMetrics(), len(expected))\n\n\t\t\t// Check the metric nevertheless as we might get some metrics despite errors.\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\n// element provides a way to configure the\n// write sequence for the socket.\ntype element struct {\n\tMessage string          `json:\"message\"`\n\tFile    string          `json:\"file\"`\n\tWait    config.Duration `json:\"wait\"`\n\traw     []byte\n}\n\nfunc readInputData(filename string) ([]element, error) {\n\tcontent, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar sequence []element\n\tif err := json.Unmarshal(content, &sequence); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor i, step := range sequence {\n\t\tif step.Message != \"\" && step.File != \"\" {\n\t\t\treturn nil, errors.New(\"both message and file set in sequence\")\n\t\t} else if step.Message != \"\" {\n\t\t\tstep.raw = []byte(step.Message)\n\t\t} else if step.File != \"\" {\n\t\t\tpath := filepath.Dir(filename)\n\t\t\tpath = filepath.Join(path, step.File)\n\t\t\tstep.raw, err = os.ReadFile(path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tsequence[i] = step\n\t}\n\n\treturn sequence, nil\n}\n\nfunc createClient(endpoint string, addr net.Addr, tlsCfg *tls.Config) (net.Conn, error) {\n\t// Determine the protocol in a crude fashion\n\tparts := strings.SplitN(endpoint, \"://\", 2)\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid endpoint %q\", endpoint)\n\t}\n\tprotocol := parts[0]\n\n\tif tlsCfg == nil {\n\t\treturn net.Dial(protocol, addr.String())\n\t}\n\n\tif protocol == \"unix\" {\n\t\ttlsCfg.InsecureSkipVerify = true\n\t}\n\treturn tls.Dial(protocol, addr.String(), tlsCfg)\n}\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/invalid_line_format/expected.err",
    "content": "metric parse error"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/invalid_line_format/expected.out",
    "content": "test,foo=bar v=1i 123456789\ntest,foo=baz v=2i 123456790\ntest,foo=zab v=3i 123456791"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/invalid_line_format/sequence.json",
    "content": "[\n    {\n        \"message\": \"test,foo=bar v=1i 123456789\\n\"\n    },\n    {\n        \"message\": \"wild boyz\\n\"\n    },\n    {\n        \"message\": \"test,foo=baz v=2i 123456790\\n\"\n    },\n    {\n        \"message\": \"test,foo=zab v=3i 123456791\\n\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/invalid_line_format/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/powerdns/dnsmessage.proto",
    "content": "/*\n * This file describes the message format used by the protobuf logging feature in PowerDNS and dnsdist.\n *\n * MIT License\n * \n * Copyright (c) 2016-now PowerDNS.COM B.V. and its contributors.\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nsyntax = \"proto2\";\n\nmessage PBDNSMessage {\n  enum Type {\n    DNSQueryType = 1;                           // Query received by the service\n    DNSResponseType = 2;                        // Response returned by the service\n    DNSOutgoingQueryType = 3;                   // Query sent out by the service to a remote server\n    DNSIncomingResponseType = 4;                // Response returned by the remote server\n  }\n  enum SocketFamily {\n    INET = 1;                                   // IPv4 (RFC 791)\n    INET6 = 2;                                  // IPv6 (RFC 2460)\n  }\n  enum SocketProtocol {\n    UDP = 1;                                    // User Datagram Protocol (RFC 768)\n    TCP = 2;                                    // Transmission Control Protocol (RFC 793)\n    DOT = 3;                                    // DNS over TLS (RFC 7858)\n    DOH = 4;                                    // DNS over HTTPS (RFC 8484)\n    DNSCryptUDP = 5;                            // DNSCrypt over UDP (https://dnscrypt.info/protocol)\n    DNSCryptTCP = 6;                            // DNSCrypt over TCP (https://dnscrypt.info/protocol)\n  }\n  enum PolicyType {\n    UNKNOWN = 1;                                // No RPZ policy applied, or unknown type\n    QNAME = 2;                                  // Policy matched on the QName\n    CLIENTIP = 3;                               // Policy matched on the client IP\n    RESPONSEIP = 4;                             // Policy matched on one of the IPs contained in the answer\n    NSDNAME = 5;                                // Policy matched on the name of one nameserver involved\n    NSIP = 6;                                   // Policy matched on the IP of one nameserver involved\n  }\n  enum PolicyKind {\n    NoAction = 1;                               // No action taken\n    Drop = 2;                                   // https://tools.ietf.org/html/draft-vixie-dns-rpz-04 3.4\n    NXDOMAIN = 3;                               // https://tools.ietf.org/html/draft-vixie-dns-rpz-04 3.1\n    NODATA = 4;                                 // https://tools.ietf.org/html/draft-vixie-dns-rpz-04 3.2\n    Truncate= 5;                                // https://tools.ietf.org/html/draft-vixie-dns-rpz-04 3.5\n    Custom = 6;                                 // https://tools.ietf.org/html/draft-vixie-dns-rpz-04 3.6\n  }\n  enum VState {\n    Indeterminate = 1;\n    Insecure = 2;\n    Secure = 3;\n    BogusNoValidDNSKEY = 4;\n    BogusInvalidDenial = 5;\n    BogusUnableToGetDSs = 6;\n    BogusUnableToGetDNSKEYs = 7;\n    BogusSelfSignedDS = 8;\n    BogusNoRRSIG = 9;\n    BogusNoValidRRSIG = 10;\n    BogusMissingNegativeIndication = 11;\n    BogusSignatureNotYetValid = 12;\n    BogusSignatureExpired = 13;\n    BogusUnsupportedDNSKEYAlgo = 14;\n    BogusUnsupportedDSDigestType = 15;\n    BogusNoZoneKeyBitSet = 16;\n    BogusRevokedDNSKEY = 17;\n    BogusInvalidDNSKEYProtocol = 18;\n  }\n  required Type type = 1;                       // Type of event\n  optional bytes messageId = 2;                 // UUID, shared by the query and the response\n  optional bytes serverIdentity = 3;            // ID of the server emitting the protobuf message\n  optional SocketFamily socketFamily = 4;\n  optional SocketProtocol socketProtocol = 5;\n  optional bytes from = 6;                      // DNS requestor (client) as 4 (IPv4) or 16 (IPv6) raw bytes in network byte order\n  optional bytes to = 7;                        // DNS responder (server) as 4 (IPv4) or 16 (IPv6) raw bytes in network byte order\n  optional uint64 inBytes = 8;                  // Size of the query or response on the wire\n  optional uint32 timeSec = 9;                  // Time of message reception (seconds since epoch)\n  optional uint32 timeUsec = 10;                // Time of message reception (additional micro-seconds)\n  optional uint32 id = 11;                      // ID of the query/response as found in the DNS header\n\n  message DNSQuestion {\n    optional string qName = 1;                  // Fully qualified DNS name (with trailing dot)\n    optional uint32 qType = 2;                  // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4\n    optional uint32 qClass = 3;                 // Typically 1 (IN), see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2\n  }\n  optional DNSQuestion question = 12;           // DNS query received from client\n\n  message DNSResponse {\n    // See exportTypes in https://docs.powerdns.com/recursor/lua-config/protobuf.html#protobufServer\n    // for the list of supported resource record types.\n    message DNSRR {\n      optional string name = 1;                 // Fully qualified DNS name (with trailing dot)\n      optional uint32 type = 2;                 // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4\n      optional uint32 class = 3;                // Typically 1 (IN), see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2\n      optional uint32 ttl = 4;                  // TTL in seconds\n      optional bytes rdata = 5;                 // raw address bytes in network byte order for A & AAAA; text representation for others, with fully qualified (trailing dot) domain names\n      optional bool  udr = 6;                   // True if this is the first time this RR has been seen for this question\n    }\n    optional uint32 rcode = 1;                  // DNS Response code, or 65536 for a network error including a timeout\n    repeated DNSRR rrs = 2;                     // DNS resource records in response\n    optional string appliedPolicy = 3;          // Filtering policy (RPZ or Lua) applied\n    repeated string tags = 4;                   // Additional tags applied\n    optional uint32 queryTimeSec = 5;           // Time of the corresponding query reception (seconds since epoch)\n    optional uint32 queryTimeUsec = 6;          // Time of the corresponding query reception (additional micro-seconds)\n    optional PolicyType appliedPolicyType = 7;  // Type of the filtering policy (RPZ or Lua) applied\n    optional string appliedPolicyTrigger = 8;   // The RPZ trigger\n    optional string appliedPolicyHit = 9;       // The value (qname or IP) that caused the hit\n    optional PolicyKind appliedPolicyKind = 10; // The Kind (RPZ action) applied by the hit\n    optional VState validationState = 11;       // The DNSSEC Validation State\n  }\n\n  optional DNSResponse response = 13;\n  optional bytes originalRequestorSubnet = 14;  // EDNS Client Subnet value (4 or 16 raw bytes in network byte order)\n  optional string requestorId = 15;             // Username of the requestor\n  optional bytes initialRequestId = 16;         // UUID of the incoming query that initiated this outgoing query or incoming response\n  optional bytes deviceId = 17;                 // Device ID of the requestor (could be mac address IP address or e.g. IMEI, format implementation dependent)\n  optional bool  newlyObservedDomain = 18;      // True if the domain has not been seen before\n  optional string deviceName = 19;              // Device name of the requestor\n  optional uint32 fromPort = 20;                // Source port of the DNS query (client)\n  optional uint32 toPort = 21;                  // Destination port of the DNS query (server)\n\n  message MetaValue {\n    repeated string stringVal = 1;\n    repeated int64 intVal = 2;\n  }\n\n  message Meta {\n    required string key = 1;                    // MUST be unique, so if you have multiple values they must be aggregated into on Meta\n    required MetaValue value = 2;\n  }\n  repeated Meta meta = 22;                      // Arbitrary meta-data - to be used in future rather than adding new fields all the time\n\n  // The well known EventTrace event numbers\n  enum EventType {\n                                                // Range 0..99: Generic events\n    CustomEvent = 0;                            // A custom event\n    ReqRecv = 1;                                // A request was received\n    PCacheCheck = 2;                            // A packet cache check was initiated or completed; value: bool cacheHit\n    AnswerSent = 3;                             // An answer was sent to the client\n\n                                                // Range 100: Recursor events\n    SyncRes = 100;                              // Recursor Syncres main function has started or completed; value: int rcode\n    LuaGetTag = 101;                            // Events below mark start or end of Lua hook calls; value: return value of hook\n    LuaGetTagFFI = 102;\n    LuaIPFilter = 103;\n    LuaPreRPZ = 104;\n    LuaPreResolve = 105;\n    LuaPreOutQuery = 106;\n    LuaPostResolve = 107;\n    LuaNoData = 108;\n    LuaNXDomain = 109;\n    LuaPostResolveFFI = 110;\n  }\n\n  message Event {\n    required int64 ts = 1;                      // Timestamp in ns relative to time of creation of event trace data structure\n    required EventType event = 2;               // Type of event\n    required bool start = 3;                    // true for \"start\" events, false for \"completed\" events\n    optional bool boolVal = 4;                  // Below are optional values associated with events\n    optional int64 intVal = 5;\n    optional string stringVal = 6;\n    optional bytes bytesVal = 7;\n    optional string custom = 8;                 // The name of the event for custom events\n  }\n  repeated Event trace = 23;\n}\n\nmessage PBDNSMessageList {\n  repeated PBDNSMessage msg = 1;\n}\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/powerdns/expected.out",
    "content": "powerdns from=\"7f000001\",fromPort=45729u,to=\"7f000001\",toPort=53u,inBytes=48u,serverIdentity=\"xxxxxxxxxxxxxxxxxxx.com\",messageId=\"943f90bea57a4eecbc5b0bea820a8aae\",qName=\"ilse.nl.\",qClass=1u,qType=1u,id=64100u,timeSec=1665050957u,timeUsec=500976u\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/powerdns/sequence.json",
    "content": "[\n    {\n        \"file\": \"powerdns_message.bin\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/powerdns/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"variable length\"\n  splitting_length_field = {offset=0, bytes=2, endianness=\"be\", header_length=2}\n\n  data_format = \"xpath_protobuf\"\n\n  xpath_native_types = true\n  xpath_protobuf_file = \"dnsmessage.proto\"\n  xpath_protobuf_type = \"PBDNSMessage\"\n  xpath_protobuf_import_paths = [\".\", \"./testcases/powerdns\"]\n\n  [[inputs.socket_listener.xpath]]\n    metric_name = \"'powerdns'\"\n    fields_bytes_as_hex = [\"from\", \"to\", \"messageId\"]\n    field_selection = \"descendant::*\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_delimiter/expected.out",
    "content": "test,foo=bar v=1i 123456789\ntest,foo=baz v=2i 123456790\ntest,foo=zab v=3i 123456791"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_delimiter/sequence.json",
    "content": "[\n    {\n        \"file\": \"message.bin\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_delimiter/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"delimiter\"\n  splitting_delimiter = \"0xBE 0xEF 0x00\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_fixed_length/expected.out",
    "content": "socket_listener value=\"foobar\"\nsocket_listener value=\"fuubar\"\nsocket_listener value=\"foobaz\"\nsocket_listener value=\"123456\""
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_fixed_length/sequence.json",
    "content": "[\n    {\n        \"message\": \"foobarfuubarfoobaz\"\n    },\n    {\n        \"message\": \"123\"\n    },\n    {\n        \"message\": \"456\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_fixed_length/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"fixed length\"\n  splitting_length = 6\n  data_format = \"value\"\n  data_type = \"string\""
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_newline/expected.out",
    "content": "test,foo=bar v=1i 123456789\ntest,foo=baz v=2i 123456790\ntest,foo=zab v=3i 123456791"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_newline/sequence.json",
    "content": "[\n    {\n        \"message\": \"test,foo=bar v=1i 123456789\\ntest,foo=baz v=2i 123456790\\ntest,foo=zab v=3i 123456791\\n\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_newline/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"newline\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_null/expected.out",
    "content": "test,foo=bar v=1i 123456789\ntest,foo=baz v=2i 123456790\ntest,foo=zab v=3i 123456791"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_null/sequence.json",
    "content": "[\n    {\n        \"file\": \"message.bin\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_null/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"null\"\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_variable_length/expected.out",
    "content": "test,foo=bar v=1i 123456789\ntest,foo=baz v=2i 123456790\ntest,foo=zab v=3i 123456791\ntest,foo=bie v=42i,temp=24.1 1665510032"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_variable_length/sequence.json",
    "content": "[\n    {\n        \"file\": \"message_1.bin\"\n    },\n    {\n        \"file\": \"message_2.bin\"\n    },\n    {\n        \"file\": \"message_3.bin\"\n    },\n    {\n        \"file\": \"message_4.bin\"\n    },\n    {\n        \"wait\": \"100ms\"\n    },\n    {\n        \"file\": \"message_5.bin\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/splitting_variable_length/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  splitting_strategy = \"variable length\"\n  splitting_length_field = {offset = 1, bytes = 2, endianness = \"be\", header_length = 3}\n"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/timeout/sequence.json",
    "content": "[\n    {\n        \"wait\": \"1s\"\n    }\n]"
  },
  {
    "path": "plugins/inputs/socket_listener/testcases/timeout/telegraf.conf",
    "content": "# Test with broken line protocol lines\n[[inputs.socket_listener]]\n  service_address = \"tcp://127.0.0.1:0\"\n  read_timeout = \"100ms\""
  },
  {
    "path": "plugins/inputs/socketstat/README.md",
    "content": "# Socket Statistics Input Plugin\n\nThis plugin gathers metrics for established network connections using\n[iproute2][iproute]'s `ss` command. The `ss` command does not require specific\nprivileges.\n\n> [!CRITICAL]\n> This plugin produces high cardinality data, which when not controlled for will\n> cause high load on your database. Please make sure to [filter][filtering] the\n> produced metrics or configure your database to avoid cardinality issues!\n\n⭐ Telegraf v1.22.0\n🏷️ network\n💻 freebsd, linux, macos\n\n[iproute]: https://github.com/iproute2/iproute2\n[filtering]: /docs/CONFIGURATION.md#metric-filtering\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather indicators from established connections, using iproute2's ss command.\n# This plugin ONLY supports non-Windows\n[[inputs.socketstat]]\n  ## ss can display information about tcp, udp, raw, unix, packet, dccp and sctp sockets\n  ## Specify here the types you want to gather\n  protocols = [ \"tcp\", \"udp\" ]\n\n  ## The default timeout of 1s for ss execution can be overridden here:\n  # timeout = \"1s\"\n```\n\n## Metrics\n\nThe measurements `socketstat` contains the following fields\n\n- state (string) (for tcp, dccp and sctp protocols)\n\nIf ss provides it (it depends on the protocol and ss version) it has the\nfollowing additional fields\n\n- bytes_acked (integer, bytes)\n- bytes_received (integer, bytes)\n- segs_out (integer, count)\n- segs_in (integer, count)\n- data_segs_out (integer, count)\n- data_segs_in (integer, count)\n\nAll measurements have the following tags:\n\n- proto\n- local_addr\n- local_port\n- remote_addr\n- remote_port\n\n## Example Output\n\n### recent `ss` version (iproute2 4.3.0 here)\n\n```sh\n./telegraf --config telegraf.conf --input-filter socketstat --test\n```\n\n```text\nsocketstat,host=ubuntu-xenial,local_addr=10.6.231.226,local_port=42716,proto=tcp,remote_addr=192.168.2.21,remote_port=80 bytes_acked=184i,bytes_received=2624519595i,recv_q=4344i,segs_in=1812580i,segs_out=661642i,send_q=0i,state=\"ESTAB\" 1606457205000000000\n```\n\n### older `ss` version (iproute2 3.12.0 here)\n\n```sh\n./telegraf --config telegraf.conf --input-filter socketstat --test\n```\n\n```text\nsocketstat,host=ubuntu-trusty,local_addr=10.6.231.163,local_port=35890,proto=tcp,remote_addr=192.168.2.21,remote_port=80 recv_q=0i,send_q=0i,state=\"ESTAB\" 1606456977000000000\n```\n"
  },
  {
    "path": "plugins/inputs/socketstat/sample.conf",
    "content": "# Gather indicators from established connections, using iproute2's ss command.\n# This plugin ONLY supports non-Windows\n[[inputs.socketstat]]\n  ## ss can display information about tcp, udp, raw, unix, packet, dccp and sctp sockets\n  ## Specify here the types you want to gather\n  protocols = [ \"tcp\", \"udp\" ]\n\n  ## The default timeout of 1s for ss execution can be overridden here:\n  # timeout = \"1s\"\n"
  },
  {
    "path": "plugins/inputs/socketstat/socketstat.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\n//go:build !windows\n\n// iproute2 doesn't exist on Windows\n\npackage socketstat\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nconst measurement = \"socketstat\"\n\ntype Socketstat struct {\n\tSocketProto []string        `toml:\"protocols\"`\n\tTimeout     config.Duration `toml:\"timeout\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\n\tisNewConnection *regexp.Regexp\n\tvalidValues     *regexp.Regexp\n\tcmdName         string\n\tlister          socketLister\n}\n\ntype socketLister func(cmdName string, proto string, timeout config.Duration) (*bytes.Buffer, error)\n\nfunc (*Socketstat) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (ss *Socketstat) Init() error {\n\tif len(ss.SocketProto) == 0 {\n\t\tss.SocketProto = []string{\"tcp\", \"udp\"}\n\t}\n\n\t// Initialize regexps to validate input data\n\tvalidFields := \"(bytes_acked|bytes_received|segs_out|segs_in|data_segs_in|data_segs_out)\"\n\tss.validValues = regexp.MustCompile(\"^\" + validFields + \":[0-9]+$\")\n\tss.isNewConnection = regexp.MustCompile(`^\\s+.*$`)\n\n\tss.lister = socketList\n\n\t// Check that ss is installed, get its path.\n\t// Do it last, because in test environments where `ss` might not be available,\n\t//   we still want the other Init() actions to be performed.\n\tssPath, err := exec.LookPath(\"ss\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tss.cmdName = ssPath\n\n\treturn nil\n}\n\nfunc (ss *Socketstat) Gather(acc telegraf.Accumulator) error {\n\t// best effort : we continue through the protocols even if an error is encountered,\n\t// but we keep track of the last error.\n\tfor _, proto := range ss.SocketProto {\n\t\tout, err := ss.lister(ss.cmdName, proto, ss.Timeout)\n\t\tif err != nil {\n\t\t\tacc.AddError(err)\n\t\t\tcontinue\n\t\t}\n\t\tss.parseAndGather(acc, out, proto)\n\t}\n\treturn nil\n}\n\nfunc socketList(cmdName, proto string, timeout config.Duration) (*bytes.Buffer, error) {\n\t// Run ss for the given protocol, return the output as bytes.Buffer\n\targs := []string{\"-in\", \"--\" + proto}\n\tcmd := exec.Command(cmdName, args...)\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := internal.RunTimeout(cmd, time.Duration(timeout))\n\tif err != nil {\n\t\treturn &out, fmt.Errorf(\"error running ss -in --%s: %w\", proto, err)\n\t}\n\treturn &out, nil\n}\n\nfunc (ss *Socketstat) parseAndGather(acc telegraf.Accumulator, data *bytes.Buffer, proto string) {\n\tscanner := bufio.NewScanner(data)\n\ttags := make(map[string]string)\n\tfields := make(map[string]interface{})\n\n\t// ss output can have blank lines, and/or socket basic info lines and more advanced\n\t// statistics lines, in turns.\n\t// In all non-empty lines, we can have metrics, so we need to group those relevant to\n\t// the same connection.\n\t// To achieve this, we're using the flushData variable which indicates if we should add\n\t// a new measurement or postpone it to a later line.\n\n\t// The first line is only headers\n\tscanner.Scan()\n\n\tflushData := false\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\twords := strings.Fields(line)\n\n\t\tif ss.isNewConnection.MatchString(line) {\n\t\t\t// A line with starting whitespace means metrics about the current connection.\n\t\t\t// We should never get 2 consecutive such lines. If we do, log a warning and in\n\t\t\t// a best effort, extend the metrics from the 1st line with the metrics of the 2nd\n\t\t\t// one, possibly overwriting.\n\t\t\tfor _, word := range words {\n\t\t\t\tif !ss.validValues.MatchString(word) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// kv will have 2 fields because it matched the regexp\n\t\t\t\tkv := strings.Split(word, \":\")\n\t\t\t\tv, err := strconv.ParseUint(kv[1], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tss.Log.Infof(\"Couldn't parse metric %q: %v\", word, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfields[kv[0]] = v\n\t\t\t}\n\t\t\tif !flushData {\n\t\t\t\tss.Log.Warnf(\"Found orphaned metrics: %s\", words)\n\t\t\t\tss.Log.Warn(\"Added them to the last known connection.\")\n\t\t\t}\n\t\t\tacc.AddFields(measurement, fields, tags)\n\t\t\tflushData = false\n\t\t\tcontinue\n\t\t}\n\t\t// A line with no starting whitespace means we're going to parse a new connection.\n\t\t// Flush what we gathered about the previous one, if any.\n\t\tif flushData {\n\t\t\tacc.AddFields(measurement, fields, tags)\n\t\t}\n\n\t\t// Delegate the real parsing to getTagsAndState, which manages various\n\t\t// formats depending on the protocol.\n\t\ttags, fields = getTagsAndState(proto, words, ss.Log)\n\n\t\t// This line contained metrics, so record that.\n\t\tflushData = true\n\t}\n\tif flushData {\n\t\tacc.AddFields(measurement, fields, tags)\n\t}\n}\n\nfunc getTagsAndState(proto string, words []string, log telegraf.Logger) (map[string]string, map[string]interface{}) {\n\ttags := map[string]string{\n\t\t\"proto\": proto,\n\t}\n\tfields := make(map[string]interface{})\n\tswitch proto {\n\tcase \"udp\", \"raw\":\n\t\twords = append([]string{\"dummy\"}, words...)\n\tcase \"tcp\", \"dccp\", \"sctp\":\n\t\tfields[\"state\"] = words[0]\n\t}\n\tswitch proto {\n\tcase \"tcp\", \"udp\", \"raw\", \"dccp\", \"sctp\":\n\t\t// Local and remote addresses are fields 3 and 4\n\t\t// Separate addresses and ports with the last ':'\n\t\tlocalIndex := strings.LastIndex(words[3], \":\")\n\t\tremoteIndex := strings.LastIndex(words[4], \":\")\n\t\ttags[\"local_addr\"] = words[3][:localIndex]\n\t\ttags[\"local_port\"] = words[3][localIndex+1:]\n\t\ttags[\"remote_addr\"] = words[4][:remoteIndex]\n\t\ttags[\"remote_port\"] = words[4][remoteIndex+1:]\n\tcase \"unix\", \"packet\":\n\t\tfields[\"netid\"] = words[0]\n\t\ttags[\"local_addr\"] = words[4]\n\t\ttags[\"local_port\"] = words[5]\n\t\ttags[\"remote_addr\"] = words[6]\n\t\ttags[\"remote_port\"] = words[7]\n\t}\n\tv, err := strconv.ParseUint(words[1], 10, 64)\n\tif err != nil {\n\t\tlog.Warnf(\"Couldn't read recv_q in %q: %v\", words, err)\n\t} else {\n\t\tfields[\"recv_q\"] = v\n\t}\n\tv, err = strconv.ParseUint(words[2], 10, 64)\n\tif err != nil {\n\t\tlog.Warnf(\"Couldn't read send_q in %q: %v\", words, err)\n\t} else {\n\t\tfields[\"send_q\"] = v\n\t}\n\treturn tags, fields\n}\n\nfunc init() {\n\tinputs.Add(\"socketstat\", func() telegraf.Input {\n\t\treturn &Socketstat{Timeout: config.Duration(time.Second)}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/socketstat/socketstat_test.go",
    "content": "//go:build !windows\n\npackage socketstat\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSocketstat_Gather(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tproto    []string\n\t\tfilename string\n\t\ttags     []map[string]string\n\t\tfields   [][]map[string]interface{}\n\t\terr      error\n\t}{\n\t\t{\n\t\t\tname:     \"tcp - no sockets => no results\",\n\t\t\tproto:    []string{\"tcp\"},\n\t\t\tfilename: \"tcp_no_sockets.txt\",\n\t\t},\n\t\t{\n\t\t\tname:     \"udp - no sockets => no results\",\n\t\t\tproto:    []string{\"udp\"},\n\t\t\tfilename: \"udp_no_sockets.txt\",\n\t\t},\n\t\t{\n\t\t\tname:     \"tcp sockets captured\",\n\t\t\tproto:    []string{\"tcp\"},\n\t\t\tfilename: \"tcp_traffic.txt\",\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"proto\": \"tcp\", \"local_addr\": \"192.168.1.21\", \"local_port\": \"6514\", \"remote_addr\": \"192.168.1.21\", \"remote_port\": \"443\"},\n\t\t\t\t{\"proto\": \"tcp\", \"local_addr\": \"192.168.122.1\", \"local_port\": \"55194\", \"remote_addr\": \"192.168.122.1\", \"remote_port\": \"6514\"},\n\t\t\t\t{\"proto\": \"tcp\", \"local_addr\": \"127.0.0.1\", \"local_port\": \"7778\", \"remote_addr\": \"127.0.0.1\", \"remote_port\": \"50378\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"state\":          \"ESTAB\",\n\t\t\t\t\t\t\"bytes_acked\":    uint64(1126),\n\t\t\t\t\t\t\"bytes_received\": uint64(532644751),\n\t\t\t\t\t\t\"segs_out\":       uint64(211249),\n\t\t\t\t\t\t\"segs_in\":        uint64(211254),\n\t\t\t\t\t\t\"data_segs_out\":  uint64(2),\n\t\t\t\t\t\t\"data_segs_in\":   uint64(211251),\n\t\t\t\t\t\t\"recv_q\":         uint64(0),\n\t\t\t\t\t\t\"send_q\":         uint64(0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"state\":          \"ESTAB\",\n\t\t\t\t\t\t\"bytes_acked\":    uint64(790782896),\n\t\t\t\t\t\t\"bytes_received\": uint64(1126),\n\t\t\t\t\t\t\"segs_out\":       uint64(333361),\n\t\t\t\t\t\t\"segs_in\":        uint64(333361),\n\t\t\t\t\t\t\"data_segs_out\":  uint64(333358),\n\t\t\t\t\t\t\"data_segs_in\":   uint64(2),\n\t\t\t\t\t\t\"recv_q\":         uint64(0),\n\t\t\t\t\t\t\"send_q\":         uint64(0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"state\":          \"ESTAB\",\n\t\t\t\t\t\t\"bytes_acked\":    uint64(19983121),\n\t\t\t\t\t\t\"bytes_received\": uint64(266383),\n\t\t\t\t\t\t\"segs_out\":       uint64(15431),\n\t\t\t\t\t\t\"segs_in\":        uint64(17633),\n\t\t\t\t\t\t\"data_segs_out\":  uint64(15119),\n\t\t\t\t\t\t\"data_segs_in\":   uint64(5098),\n\t\t\t\t\t\t\"recv_q\":         uint64(0),\n\t\t\t\t\t\t\"send_q\":         uint64(0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"udp packets captured\",\n\t\t\tproto:    []string{\"udp\"},\n\t\t\tfilename: \"udp_traffic.txt\",\n\t\t\ttags: []map[string]string{\n\t\t\t\t{\"proto\": \"udp\", \"local_addr\": \"10.10.0.4\", \"local_port\": \"33149\", \"remote_addr\": \"10.10.0.5\", \"remote_port\": \"53\"},\n\t\t\t\t{\"proto\": \"udp\", \"local_addr\": \"10.10.0.4\", \"local_port\": \"54276\", \"remote_addr\": \"10.10.0.6\", \"remote_port\": \"53\"},\n\t\t\t\t{\"proto\": \"udp\", \"local_addr\": \"10.10.0.4\", \"local_port\": \"38312\", \"remote_addr\": \"10.10.0.7\", \"remote_port\": \"53\"},\n\t\t\t},\n\t\t\tfields: [][]map[string]interface{}{\n\t\t\t\t{map[string]interface{}{\"recv_q\": uint64(0), \"send_q\": uint64(0)}},\n\t\t\t\t{map[string]interface{}{\"recv_q\": uint64(0), \"send_q\": uint64(0)}},\n\t\t\t\t{map[string]interface{}{\"recv_q\": uint64(0), \"send_q\": uint64(0)}},\n\t\t\t},\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\toctets, err := os.ReadFile(filepath.Join(\"testdata\", tt.filename))\n\t\trequire.NoError(t, err)\n\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ti++\n\t\t\tss := &Socketstat{\n\t\t\t\tSocketProto: tt.proto,\n\t\t\t}\n\t\t\tacc := new(testutil.Accumulator)\n\n\t\t\terr := ss.Init()\n\t\t\tif err != nil {\n\t\t\t\trequire.EqualError(t, err, \"exec: \\\"ss\\\": executable file not found in $PATH\")\n\t\t\t}\n\t\t\tss.lister = func(string, string, config.Duration) (*bytes.Buffer, error) {\n\t\t\t\treturn bytes.NewBuffer(octets), nil\n\t\t\t}\n\n\t\t\terr = acc.GatherError(ss.Gather)\n\t\t\trequire.ErrorIs(t, err, tt.err)\n\t\t\tif len(tt.proto) == 0 {\n\t\t\t\tn := acc.NFields()\n\t\t\t\trequire.Equalf(t, 0, n, \"%d: expected 0 values got %d\", i, n)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif len(tt.tags) == 0 {\n\t\t\t\tn := acc.NFields()\n\t\t\t\trequire.Equalf(t, 0, n, \"%d: expected 0 values got %d\", i, n)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tn := 0\n\t\t\tfor j, tags := range tt.tags {\n\t\t\t\tfor k, fields := range tt.fields[j] {\n\t\t\t\t\trequire.Greater(t, len(acc.Metrics), n)\n\t\t\t\t\tm := acc.Metrics[n]\n\t\t\t\t\trequire.Equal(t, measurement, m.Measurement, \"%d %d %d: expected measurement '%#v' got '%#v'\\n\", i, j, k, measurement, m.Measurement)\n\t\t\t\t\trequire.Equal(t, tags, m.Tags, \"%d %d %d: expected tags\\n%#v got\\n%#v\\n\", i, j, k, tags, m.Tags)\n\t\t\t\t\trequire.Equal(t, fields, m.Fields, \"%d %d %d: expected fields\\n%#v got\\n%#v\\n\", i, j, k, fields, m.Fields)\n\t\t\t\t\tn++\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSocketstat_Gather_listerError(t *testing.T) {\n\terrorMessage := \"error foobar\"\n\terrFoo := errors.New(errorMessage)\n\tss := &Socketstat{\n\t\tSocketProto: []string{\"foobar\"},\n\t}\n\tss.lister = func(string, string, config.Duration) (*bytes.Buffer, error) {\n\t\treturn new(bytes.Buffer), errFoo\n\t}\n\tacc := new(testutil.Accumulator)\n\terr := acc.GatherError(ss.Gather)\n\trequire.EqualError(t, err, errorMessage)\n}\n"
  },
  {
    "path": "plugins/inputs/socketstat/socketstat_windows.go",
    "content": "//go:build windows\n\npackage socketstat\n\nimport (\n\t_ \"embed\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Socketstat struct {\n\tLog telegraf.Logger `toml:\"-\"`\n}\n\nfunc (*Socketstat) SampleConfig() string { return sampleConfig }\n\nfunc (s *Socketstat) Init() error {\n\ts.Log.Warn(\"Current platform is not supported\")\n\treturn nil\n}\n\nfunc (*Socketstat) Gather(telegraf.Accumulator) error { return nil }\n\nfunc init() {\n\tinputs.Add(\"socketstat\", func() telegraf.Input {\n\t\treturn &Socketstat{}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/socketstat/testdata/tcp_no_sockets.txt",
    "content": "State      Recv-Q Send-Q       Local Address:Port                  Peer Address:Port\n"
  },
  {
    "path": "plugins/inputs/socketstat/testdata/tcp_traffic.txt",
    "content": "State      Recv-Q Send-Q       Local Address:Port                     Peer Address:Port\nESTAB      0      0          192.168.1.21:6514                192.168.1.21:443\n        cubic wscale:7,7 rto:204 rtt:0.057/0.033 ato:40 mss:22976 cwnd:10 bytes_acked:1126 bytes_received:532644751 segs_out:211249 segs_in:211254 data_segs_out:2 data_segs_in:211251 send 32247.0Mbps lastsnd:299082764 lastrcv:5248 lastack:5252 rcv_rtt:3.532 rcv_space:186557 minrtt:0.047\nESTAB      0      0         192.168.122.1:55194             192.168.122.1:6514\n        cubic wscale:7,7 rto:204 rtt:0.034/0.01 ato:40 mss:65483 cwnd:10 bytes_acked:790782896 bytes_received:1126 segs_out:333361 segs_in:333361 data_segs_out:333358 data_segs_in:2 send 154077.6Mbps lastsnd:5248 lastrcv:443892492 lastack:5248 rcv_rtt:250 rcv_space:43690 minrtt:0.009\nESTAB      0      0             127.0.0.1:7778                   127.0.0.1:50378\n        cubic wscale:7,7 rto:220 rtt:16.009/21.064 ato:44 mss:65483 cwnd:10 bytes_acked:19983121 bytes_received:266383 segs_out:15431 segs_in:17633 data_segs_out:15119 data_segs_in:5098 send 327.2Mbps lastsnd:9792 lastrcv:9840 lastack:9748 pacing_rate 654.4Mbps retrans:0/1 rcv_rtt:129800 rcv_space:44057 minrtt:0.043\n"
  },
  {
    "path": "plugins/inputs/socketstat/testdata/udp_no_sockets.txt",
    "content": "Recv-Q Send-Q       Local Address:Port                     Peer Address:Port\n"
  },
  {
    "path": "plugins/inputs/socketstat/testdata/udp_traffic.txt",
    "content": "Recv-Q Send-Q              Local Address:Port                             Peer Address:Port\n0      0                         10.10.0.4:33149                                 10.10.0.5:53\n0      0                         10.10.0.4:54276                                 10.10.0.6:53\n0      0                         10.10.0.4:38312                                 10.10.0.7:53\n"
  },
  {
    "path": "plugins/inputs/solr/README.md",
    "content": "# Apache Solr Input Plugin\n\nThis plugin collects statistics from [Solr][solr] instances using the\n[MBean Request Handler][mbean_request_handler]. For additional details on\nperformance statistics check the [performance statistics reference][reference].\n\n> [!NOTE]\n> This plugin requires Apache Solr v3.5+.\n\n⭐ Telegraf v1.5.0\n🏷️ server\n💻 all\n\n[solr]: http://lucene.apache.org/solr/\n[mbean_request_handler]: https://cwiki.apache.org/confluence/display/solr/MBean+Request+Handler\n[reference]: https://cwiki.apache.org/confluence/display/solr/Performance+Statistics+Reference\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Read stats from one or more Solr servers or cores\n[[inputs.solr]]\n  ## specify a list of one or more Solr servers\n  servers = [\"http://localhost:8983\"]\n\n  ## specify a list of one or more Solr cores (default - all)\n  # cores = [\"*\"]\n  \n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Timeout for HTTP requests\n  # timeout = \"5s\"\n```\n\n## Metrics\n\n- solr_core\n  - tags\n    - core\n    - handler\n  - fields\n    - num_docs (integer)\n    - max_docs (integer)\n    - deleted_docs (integer)\n- solr_queryhandler\n  - tags\n    - core\n    - handler\n  - fields\n    - depends on the handler information\n\n## Example Output\n\n```text\nsolr_core,core=main,handler=searcher,host=testhost deleted_docs=17616645i,max_docs=261848363i,num_docs=244231718i 1478214949000000000\nsolr_core,core=main,handler=core,host=testhost deleted_docs=0i,max_docs=0i,num_docs=0i 1478214949000000000\nsolr_queryhandler,core=main,handler=/replication,host=testhost 15min_rate_reqs_per_second=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444659081257,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=16.484211,95th_pc_request_time=16.484211,999th_pc_request_time=16.484211,99th_pc_request_time=16.484211,avg_requests_per_second=0.0000008443809966322143,avg_time_per_request=12.984811,errors=0i,handler_start=1474662050865i,median_request_time=11.352427,requests=3i,timeouts=0i,total_time=38.954433 1478214949000000000\nsolr_queryhandler,core=main,handler=/update/extract,host=testhost 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1478214949000000000\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.component.SearchHandler,host=testhost 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1474662050861i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1478214949000000000\nsolr_queryhandler,core=main,handler=/tvrh,host=testhost 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1478214949000000000\n```\n"
  },
  {
    "path": "plugins/inputs/solr/api.go",
    "content": "package solr\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n)\n\ntype apiConfig struct {\n\tendpointAdmin    string\n\tendpointMBeans   string\n\tkeyCore          string\n\tkeyCache         string\n\tkeyUpdateHandler string\n\tkeyQueryHandler  string\n}\n\nfunc newAPIv1Config() *apiConfig {\n\treturn &apiConfig{\n\t\tendpointAdmin:    \"/solr/admin/cores?action=STATUS&wt=json\",\n\t\tendpointMBeans:   \"/admin/mbeans?stats=true&wt=json&cat=CORE&cat=QUERYHANDLER&cat=UPDATEHANDLER&cat=CACHE\",\n\t\tkeyCore:          `\"CORE\"`,\n\t\tkeyCache:         `\"CACHE\"`,\n\t\tkeyQueryHandler:  `\"QUERYHANDLER\"`,\n\t\tkeyUpdateHandler: `\"UPDATEHANDLER\"`,\n\t}\n}\n\nfunc newAPIv2Config() *apiConfig {\n\treturn &apiConfig{\n\t\tendpointAdmin:    \"/solr/admin/cores?action=STATUS&wt=json\",\n\t\tendpointMBeans:   \"/admin/mbeans?stats=true&wt=json&cat=CORE&cat=QUERY&cat=UPDATE&cat=CACHE\",\n\t\tkeyCore:          `\"CORE\"`,\n\t\tkeyCache:         `\"CACHE\"`,\n\t\tkeyQueryHandler:  `\"QUERY\"`,\n\t\tkeyUpdateHandler: `\"UPDATE\"`,\n\t}\n}\n\nfunc (cfg *apiConfig) adminEndpoint(server string) string {\n\treturn strings.TrimSuffix(server, \"/\") + cfg.endpointAdmin\n}\n\nfunc (cfg *apiConfig) mbeansEndpoint(server, core string) string {\n\treturn strings.TrimSuffix(server, \"/\") + \"/solr/\" + strings.Trim(core, \"/\") + cfg.endpointMBeans\n}\n\nfunc (cfg *apiConfig) parseCore(acc telegraf.Accumulator, coreStr string, data *mBeansData, ts time.Time) {\n\t// Determine the core information element\n\tvar coreData json.RawMessage\n\tfor i := 0; i < len(data.SolrMbeans); i += 2 {\n\t\tif string(data.SolrMbeans[i]) == cfg.keyCore {\n\t\t\tcoreData = data.SolrMbeans[i+1]\n\t\t\tbreak\n\t\t}\n\t}\n\tif coreData == nil {\n\t\tacc.AddError(errors.New(\"no core metric data to unmarshal\"))\n\t\treturn\n\t}\n\n\tvar coreMetrics map[string]core\n\tif err := json.Unmarshal(coreData, &coreMetrics); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"unmarshalling core metrics for %q failed: %w\", coreStr, err))\n\t\treturn\n\t}\n\n\tfor name, m := range coreMetrics {\n\t\tif strings.Contains(name, \"@\") {\n\t\t\tcontinue\n\t\t}\n\t\tfields := map[string]interface{}{\n\t\t\t\"deleted_docs\": m.Stats.DeletedDocs,\n\t\t\t\"max_docs\":     m.Stats.MaxDoc,\n\t\t\t\"num_docs\":     m.Stats.NumDocs,\n\t\t}\n\t\ttags := map[string]string{\n\t\t\t\"core\":    coreStr,\n\t\t\t\"handler\": name,\n\t\t}\n\n\t\tacc.AddFields(\"solr_core\", fields, tags, ts)\n\t}\n}\n\nfunc (cfg *apiConfig) parseCache(acc telegraf.Accumulator, core string, data *mBeansData, ts time.Time) {\n\t// Determine the cache information element\n\tvar cacheData json.RawMessage\n\tfor i := 0; i < len(data.SolrMbeans); i += 2 {\n\t\tif string(data.SolrMbeans[i]) == cfg.keyCache {\n\t\t\tcacheData = data.SolrMbeans[i+1]\n\t\t\tbreak\n\t\t}\n\t}\n\tif cacheData == nil {\n\t\tacc.AddError(errors.New(\"no cache metric data to unmarshal\"))\n\t\treturn\n\t}\n\n\tvar cacheMetrics map[string]cache\n\tif err := json.Unmarshal(cacheData, &cacheMetrics); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"unmarshalling update handler for %q failed: %w\", core, err))\n\t\treturn\n\t}\n\n\tfor name, metrics := range cacheMetrics {\n\t\tfields := make(map[string]interface{}, len(metrics.Stats))\n\t\tfor key, value := range metrics.Stats {\n\t\t\tsplitKey := strings.Split(key, \".\")\n\t\t\tnewKey := splitKey[len(splitKey)-1]\n\t\t\tswitch newKey {\n\t\t\tcase \"cumulative_evictions\", \"cumulative_hits\", \"cumulative_inserts\", \"cumulative_lookups\",\n\t\t\t\t\"eviction\", \"evictions\", \"hits\", \"inserts\", \"lookups\", \"size\":\n\t\t\t\tfields[newKey] = getInt(value)\n\t\t\tcase \"hitratio\", \"cumulative_hitratio\":\n\t\t\t\tfields[newKey] = getFloat(value)\n\t\t\tcase \"warmupTime\":\n\t\t\t\tfields[\"warmup_time\"] = getInt(value)\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"core\":    core,\n\t\t\t\"handler\": name,\n\t\t}\n\n\t\tacc.AddFields(\"solr_cache\", fields, tags, ts)\n\t}\n}\n\nfunc (cfg *apiConfig) parseQueryHandler(acc telegraf.Accumulator, core string, data *mBeansData, ts time.Time) {\n\t// Determine the query-handler information element\n\tvar queryData json.RawMessage\n\tfor i := 0; i < len(data.SolrMbeans); i += 2 {\n\t\tif string(data.SolrMbeans[i]) == cfg.keyQueryHandler {\n\t\t\tqueryData = data.SolrMbeans[i+1]\n\t\t\tbreak\n\t\t}\n\t}\n\tif queryData == nil {\n\t\tacc.AddError(errors.New(\"no query handler metric data to unmarshal\"))\n\t\treturn\n\t}\n\n\tvar queryMetrics map[string]queryHandler\n\tif err := json.Unmarshal(queryData, &queryMetrics); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"unmarshalling query handler for %q failed: %w\", core, err))\n\t\treturn\n\t}\n\n\tfor name, metrics := range queryMetrics {\n\t\tif metrics.Stats == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar values map[string]interface{}\n\t\tswitch v := metrics.Stats.(type) {\n\t\tcase []interface{}:\n\t\t\tvalues = make(map[string]interface{}, len(v)/2)\n\t\t\tfor i := 0; i < len(v); i += 2 {\n\t\t\t\tkey, ok := v[i].(string)\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalues[key] = v[i+1]\n\t\t\t}\n\t\tcase map[string]interface{}:\n\t\t\tvalues = v\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"15min_rate_reqs_per_second\": getFloat(values[\"15minRateReqsPerSecond\"]),\n\t\t\t\"5min_rate_reqs_per_second\":  getFloat(values[\"5minRateReqsPerSecond\"]),\n\t\t\t\"75th_pc_request_time\":       getFloat(values[\"75thPcRequestTime\"]),\n\t\t\t\"95th_pc_request_time\":       getFloat(values[\"95thPcRequestTime\"]),\n\t\t\t\"99th_pc_request_time\":       getFloat(values[\"99thPcRequestTime\"]),\n\t\t\t\"999th_pc_request_time\":      getFloat(values[\"999thPcRequestTime\"]),\n\t\t\t\"avg_requests_per_second\":    getFloat(values[\"avgRequestsPerSecond\"]),\n\t\t\t\"avg_time_per_request\":       getFloat(values[\"avgTimePerRequest\"]),\n\t\t\t\"errors\":                     getInt(values[\"errors\"]),\n\t\t\t\"handler_start\":              getInt(values[\"handlerStart\"]),\n\t\t\t\"median_request_time\":        getFloat(values[\"medianRequestTime\"]),\n\t\t\t\"requests\":                   getInt(values[\"requests\"]),\n\t\t\t\"timeouts\":                   getInt(values[\"timeouts\"]),\n\t\t\t\"total_time\":                 getFloat(values[\"totalTime\"]),\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"core\":    core,\n\t\t\t\"handler\": name,\n\t\t}\n\t\tacc.AddFields(\"solr_queryhandler\", fields, tags, ts)\n\t}\n}\n\nfunc (cfg *apiConfig) parseUpdateHandler(acc telegraf.Accumulator, core string, data *mBeansData, ts time.Time) {\n\t// Determine the update-handler information element\n\tvar updateData json.RawMessage\n\tfor i := 0; i < len(data.SolrMbeans); i += 2 {\n\t\tif string(data.SolrMbeans[i]) == cfg.keyUpdateHandler {\n\t\t\tupdateData = data.SolrMbeans[i+1]\n\t\t\tbreak\n\t\t}\n\t}\n\tif updateData == nil {\n\t\tacc.AddError(errors.New(\"no update handler metric data to unmarshal\"))\n\t\treturn\n\t}\n\n\tvar updateMetrics map[string]updateHandler\n\tif err := json.Unmarshal(updateData, &updateMetrics); err != nil {\n\t\tacc.AddError(fmt.Errorf(\"unmarshalling update handler for %q failed: %w\", core, err))\n\t\treturn\n\t}\n\n\tfor name, metrics := range updateMetrics {\n\t\tvar autoCommitMaxTime int64\n\t\tif len(metrics.Stats.AutocommitMaxTime) > 2 {\n\t\t\ts := metrics.Stats.AutocommitMaxTime[:len(metrics.Stats.AutocommitMaxTime)-2]\n\t\t\tvar err error\n\t\t\tautoCommitMaxTime, err = strconv.ParseInt(s, 0, 64)\n\t\t\tif err != nil {\n\t\t\t\tautoCommitMaxTime = 0\n\t\t\t}\n\t\t}\n\n\t\tfields := map[string]interface{}{\n\t\t\t\"adds\":                        metrics.Stats.Adds,\n\t\t\t\"autocommit_max_docs\":         metrics.Stats.AutocommitMaxDocs,\n\t\t\t\"autocommit_max_time\":         autoCommitMaxTime,\n\t\t\t\"autocommits\":                 metrics.Stats.Autocommits,\n\t\t\t\"commits\":                     metrics.Stats.Commits,\n\t\t\t\"cumulative_adds\":             metrics.Stats.CumulativeAdds,\n\t\t\t\"cumulative_deletes_by_id\":    metrics.Stats.CumulativeDeletesByID,\n\t\t\t\"cumulative_deletes_by_query\": metrics.Stats.CumulativeDeletesByQuery,\n\t\t\t\"cumulative_errors\":           metrics.Stats.CumulativeErrors,\n\t\t\t\"deletes_by_id\":               metrics.Stats.DeletesByID,\n\t\t\t\"deletes_by_query\":            metrics.Stats.DeletesByQuery,\n\t\t\t\"docs_pending\":                metrics.Stats.DocsPending,\n\t\t\t\"errors\":                      metrics.Stats.Errors,\n\t\t\t\"expunge_deletes\":             metrics.Stats.ExpungeDeletes,\n\t\t\t\"optimizes\":                   metrics.Stats.Optimizes,\n\t\t\t\"rollbacks\":                   metrics.Stats.Rollbacks,\n\t\t\t\"soft_autocommits\":            metrics.Stats.SoftAutocommits,\n\t\t}\n\n\t\ttags := map[string]string{\n\t\t\t\"core\":    core,\n\t\t\t\"handler\": name,\n\t\t}\n\n\t\tacc.AddFields(\"solr_updatehandler\", fields, tags, ts)\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/solr/sample.conf",
    "content": "# Read stats from one or more Solr servers or cores\n[[inputs.solr]]\n  ## specify a list of one or more Solr servers\n  servers = [\"http://localhost:8983\"]\n\n  ## specify a list of one or more Solr cores (default - all)\n  # cores = [\"*\"]\n  \n  ## Optional HTTP Basic Auth Credentials\n  # username = \"username\"\n  # password = \"pa$$word\"\n\n  ## Timeout for HTTP requests\n  # timeout = \"5s\"\n"
  },
  {
    "path": "plugins/inputs/solr/solr.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage solr\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/coreos/go-semver/semver\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\ntype Solr struct {\n\tServers     []string        `toml:\"servers\"`\n\tUsername    string          `toml:\"username\"`\n\tPassword    string          `toml:\"password\"`\n\tHTTPTimeout config.Duration `toml:\"timeout\"`\n\tCores       []string        `toml:\"cores\"`\n\tLog         telegraf.Logger `toml:\"-\"`\n\n\tclient  *http.Client\n\tconfigs map[string]*apiConfig\n\tfilter  filter.Filter\n}\n\nfunc (*Solr) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *Solr) Init() error {\n\t// Setup client to do the queries\n\ts.client = &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tResponseHeaderTimeout: time.Duration(s.HTTPTimeout),\n\t\t},\n\t\tTimeout: time.Duration(s.HTTPTimeout),\n\t}\n\n\t// Prepare filter for the cores to query\n\tf, err := filter.Compile(s.Cores)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.filter = f\n\n\t// Allocate config cache\n\ts.configs = make(map[string]*apiConfig, len(s.Servers))\n\n\treturn nil\n}\n\nfunc (s *Solr) Start(telegraf.Accumulator) error {\n\tfor _, server := range s.Servers {\n\t\t// Simply fill the cache for all available servers\n\t\t_ = s.getAPIConfig(server)\n\t}\n\treturn nil\n}\n\nfunc (s *Solr) Gather(acc telegraf.Accumulator) error {\n\tvar wg sync.WaitGroup\n\tfor _, srv := range s.Servers {\n\t\twg.Add(1)\n\t\tgo func(server string) {\n\t\t\tdefer wg.Done()\n\n\t\t\t// Check the server version from cache or query one\n\t\t\tcfg := s.getAPIConfig(server)\n\t\t\ts.collect(acc, cfg, server)\n\t\t}(srv)\n\t}\n\twg.Wait()\n\n\treturn nil\n}\n\nfunc (*Solr) Stop() {}\n\nfunc (s *Solr) getAPIConfig(server string) *apiConfig {\n\tif cfg, found := s.configs[server]; found {\n\t\treturn cfg\n\t}\n\n\tversion, err := s.determineServerAPIVersion(server)\n\tif err != nil {\n\t\ts.Log.Errorf(\"Getting version for %q failed: %v\", server, err)\n\t\t// Exit early and do not fill the cache as the server might not be\n\t\t// reachable yet.\n\t\treturn newAPIv1Config()\n\t}\n\ts.Log.Debugf(\"Found API version %d for server %q...\", version, server)\n\n\tswitch version {\n\tcase 0:\n\t\ts.Log.Warn(\"Unable to determine API version! Using API v1...\")\n\t\ts.configs[server] = newAPIv1Config()\n\tcase 1:\n\t\ts.configs[server] = newAPIv1Config()\n\tcase 2:\n\t\ts.configs[server] = newAPIv2Config()\n\tdefault:\n\t\ts.Log.Warnf(\"Unknown API version %q! Using latest known\", version)\n\t\ts.configs[server] = newAPIv2Config()\n\t}\n\n\treturn s.configs[server]\n}\n\nfunc (s *Solr) collect(acc telegraf.Accumulator, cfg *apiConfig, server string) {\n\tnow := time.Now()\n\n\tvar coreStatus adminCoresStatus\n\tif err := s.query(cfg.adminEndpoint(server), &coreStatus); err != nil {\n\t\tacc.AddError(err)\n\t\treturn\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor core, metrics := range coreStatus.Status {\n\t\tfields := map[string]interface{}{\n\t\t\t\"deleted_docs\":  metrics.Index.DeletedDocs,\n\t\t\t\"max_docs\":      metrics.Index.MaxDoc,\n\t\t\t\"num_docs\":      metrics.Index.NumDocs,\n\t\t\t\"size_in_bytes\": metrics.Index.SizeInBytes,\n\t\t}\n\t\ttags := map[string]string{\"core\": core}\n\t\tacc.AddFields(\"solr_admin\", fields, tags, now)\n\n\t\tif s.filter != nil && !s.filter.Match(core) {\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(server string, core string) {\n\t\t\tdefer wg.Done()\n\n\t\t\tvar data mBeansData\n\t\t\tif err := s.query(cfg.mbeansEndpoint(server, core), &data); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcfg.parseCore(acc, core, &data, now)\n\t\t\tcfg.parseQueryHandler(acc, core, &data, now)\n\t\t\tcfg.parseUpdateHandler(acc, core, &data, now)\n\t\t\tcfg.parseCache(acc, core, &data, now)\n\t\t}(server, core)\n\t}\n\twg.Wait()\n}\n\nfunc (s *Solr) query(endpoint string, v interface{}) error {\n\treq, reqErr := http.NewRequest(http.MethodGet, endpoint, nil)\n\tif reqErr != nil {\n\t\treturn reqErr\n\t}\n\n\tif s.Username != \"\" {\n\t\treq.SetBasicAuth(s.Username, s.Password)\n\t}\n\n\treq.Header.Set(\"User-Agent\", internal.ProductToken())\n\n\tr, err := s.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Body.Close()\n\tif r.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"solr: API endpoint %q responded with %q\", endpoint, r.Status)\n\t}\n\n\treturn json.NewDecoder(r.Body).Decode(v)\n}\n\nfunc (s *Solr) determineServerAPIVersion(server string) (int, error) {\n\tendpoint := server + \"/solr/admin/info/system?wt=json\"\n\tvar info map[string]interface{}\n\tif err := s.query(endpoint, &info); err != nil {\n\t\treturn 0, err\n\t}\n\n\tlraw, found := info[\"lucene\"]\n\tif !found {\n\t\treturn 0, nil\n\t}\n\tlucene, ok := lraw.(map[string]interface{})\n\tif !ok {\n\t\treturn 0, nil\n\t}\n\tvraw, ok := lucene[\"solr-spec-version\"]\n\tif !ok {\n\t\treturn 0, nil\n\t}\n\tv, ok := vraw.(string)\n\tif !ok {\n\t\treturn 0, nil\n\t}\n\n\t// API version 1 is required until v7.x\n\tversion := semver.New(v)\n\tif version.LessThan(semver.Version{Major: 7}) {\n\t\treturn 1, nil\n\t}\n\n\t// Starting from 7.0 API version 2 has to be used to get the UPDATE and\n\t// QUERY metrics.\n\treturn 2, nil\n}\n\nfunc init() {\n\tinputs.Add(\"solr\", func() telegraf.Input {\n\t\treturn &Solr{\n\t\t\tHTTPTimeout: config.Duration(time.Second * 5),\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/solr/solr_test.go",
    "content": "package solr\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/plugins/parsers/influx\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestCases(t *testing.T) {\n\t// Get all directories in testcases\n\tfolders, err := os.ReadDir(\"testcases\")\n\trequire.NoError(t, err)\n\n\t// Make sure tests contains data\n\trequire.NotEmpty(t, folders)\n\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.SortMetrics(),\n\t}\n\n\tfor _, f := range folders {\n\t\t// Only handle folders\n\t\tif !f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfname := f.Name()\n\t\tt.Run(fname, func(t *testing.T) {\n\t\t\ttestdataPath := filepath.Join(\"testcases\", fname)\n\t\t\tconfigFilename := filepath.Join(testdataPath, \"telegraf.conf\")\n\t\t\texpectedFilename := filepath.Join(testdataPath, \"expected.out\")\n\n\t\t\t// Load the expected output\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\texpected, err := testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Load the pages for the test case\n\t\t\tpages, err := loadPages(testdataPath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Create a HTTP server that delivers all files in the test-directory\n\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tif !strings.HasPrefix(r.URL.Path, \"/solr/\") {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tpath := strings.TrimPrefix(r.URL.Path, \"/solr/\")\n\t\t\t\tpage, found := pages[path]\n\t\t\t\tif !found {\n\t\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif _, err := w.Write(page); err != nil {\n\t\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\t\tt.Error(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}))\n\t\t\trequire.NotNil(t, server)\n\t\t\tdefer server.Close()\n\n\t\t\t// Configure the plugin\n\t\t\tcfg := config.NewConfig()\n\t\t\trequire.NoError(t, cfg.LoadConfig(configFilename))\n\t\t\trequire.Len(t, cfg.Inputs, 1)\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := cfg.Inputs[0].Input.(*Solr)\n\t\t\tplugin.Servers = []string{server.URL}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Gather data and compare results\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tplugin.Stop()\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc TestIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\t// Get all integration test files in testcases\n\tresultFiles, err := filepath.Glob(filepath.Join(\"testcases\", \"*.result\"))\n\trequire.NoError(t, err)\n\n\t// Make sure tests contains data\n\trequire.NotEmpty(t, resultFiles)\n\n\toptions := []cmp.Option{\n\t\ttestutil.IgnoreTime(),\n\t\ttestutil.SortMetrics(),\n\t}\n\n\tconst servicePort = \"8983\"\n\n\tfor _, f := range resultFiles {\n\t\tfname := strings.TrimSuffix(filepath.Base(f), \".result\")\n\t\tt.Run(fname, func(t *testing.T) {\n\t\t\texpectedFilename := filepath.Join(\"testcases\", fname+\".result\")\n\n\t\t\t// Load the expected output\n\t\t\tparser := &influx.Parser{}\n\t\t\trequire.NoError(t, parser.Init())\n\t\t\texpected, err := testutil.ParseMetricsFromFile(expectedFilename, parser)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Determine container version for the integration test\n\t\t\t// The version number is the last element in the filename separated\n\t\t\t// by a dash and prefixed with a 'v'.\n\t\t\timage := \"solr\"\n\t\t\tparts := strings.Split(fname, \"-\")\n\t\t\tif len(parts) > 1 {\n\t\t\t\tversion := parts[len(parts)-1]\n\t\t\t\trequire.True(t, strings.HasPrefix(version, \"v\"))\n\t\t\t\timage += \":\" + strings.TrimPrefix(version, \"v\")\n\t\t\t}\n\n\t\t\t// Start the container\n\t\t\tcontainer := testutil.Container{\n\t\t\t\tImage:        image,\n\t\t\t\tExposedPorts: []string{servicePort},\n\t\t\t\tCmd:          []string{\"solr-precreate\", \"main\"},\n\t\t\t\tWaitingFor: wait.ForAll(\n\t\t\t\t\twait.ForListeningPort(nat.Port(servicePort)),\n\t\t\t\t\twait.ForLog(\"Registered new searcher\"),\n\t\t\t\t),\n\t\t\t}\n\t\t\trequire.NoError(t, container.Start(), \"failed to start container\")\n\t\t\tdefer container.Terminate()\n\n\t\t\tserver := []string{fmt.Sprintf(\"http://%s:%s\", container.Address, container.Ports[servicePort])}\n\n\t\t\t// Setup the plugin\n\t\t\tplugin := &Solr{\n\t\t\t\tServers:     server,\n\t\t\t\tHTTPTimeout: config.Duration(5 * time.Second),\n\t\t\t\tLog:         &testutil.Logger{},\n\t\t\t}\n\t\t\trequire.NoError(t, plugin.Init())\n\n\t\t\t// Gather data and compare results\n\t\t\tvar acc testutil.Accumulator\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\tplugin.Stop()\n\n\t\t\tactual := acc.GetTelegrafMetrics()\n\t\t\ttestutil.RequireMetricsStructureEqual(t, expected, actual, options...)\n\t\t})\n\t}\n}\n\nfunc loadPages(path string) (map[string][]byte, error) {\n\tabspath, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresponses := make(map[string][]byte)\n\terr = filepath.Walk(abspath, func(path string, info fs.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.IsDir() || !strings.HasSuffix(path, \".json\") {\n\t\t\t// Ignore directories and files not matching the expectations\n\t\t\treturn nil\n\t\t}\n\t\trelpath, err := filepath.Rel(abspath, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trelpath = strings.TrimSuffix(relpath, \".json\")\n\t\tdata, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tresponses[filepath.ToSlash(relpath)] = data\n\n\t\treturn nil\n\t})\n\n\treturn responses, err\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/integration-v6.result",
    "content": "solr_admin,core=main deleted_docs=0i,max_docs=0i,num_docs=0i,size_in_bytes=71i\nsolr_cache,core=main,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=perSegFilter cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=main,handler=searcher deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_queryhandler,core=main,handler=/browse 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146270i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146269i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/export 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146264i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146246i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/graph 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146265i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146270i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/select 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146270i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/sql 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146268i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/stream 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1690881146267i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_updatehandler,core=main,handler=/update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/csv adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=15000i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json/docs adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/integration-v7.result",
    "content": "solr_admin,core=main deleted_docs=0i,max_docs=0i,num_docs=0i,size_in_bytes=69i\nsolr_cache,core=main,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=perSegFilter cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=main,handler=searcher deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_queryhandler,core=main,handler=/browse 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/export 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/graph 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.admin.MetricsCollectorHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/select 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/sql 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/stream 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_updatehandler,core=main,handler=/update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/csv adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json/docs adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/integration-v8.result",
    "content": "solr_admin,core=main deleted_docs=0i,max_docs=0i,num_docs=0i,size_in_bytes=69i\nsolr_cache,core=main,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=perSegFilter cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=main,handler=searcher deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/export 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/graph 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.admin.MetricsCollectorHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/select 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/sql 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/stream 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_updatehandler,core=main,handler=/update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/csv adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json/docs adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/integration-v9.result",
    "content": "solr_admin,core=main deleted_docs=0i,max_docs=0i,num_docs=0i,size_in_bytes=69i\nsolr_cache,core=main,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=fieldCache size=0i\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=perSegFilter cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=1,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=main,handler=searcher deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=expand 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/export 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=facet 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=facet_module 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/graph 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=mlt 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/select 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/stream 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_updatehandler,core=main,handler=/update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=update adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/cbor adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/csv adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=/update/json/docs adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/no_core_data/admin/cores.json",
    "content": "{\n  \"status\": {\n    \"core1\": {\n      \"index\": {\n        \"size\": \"1.66 GB\",\n        \"sizeInBytes\": 1784635686,\n        \"lastModified\": \"2017-01-14T10:30:07.419Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484389807419\"\n        },\n        \"numDocs\": 7517488,\n        \"maxDoc\": 7620303,\n        \"deletedDocs\": 102815,\n        \"version\": 267485,\n        \"segmentCount\": 21,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\"\n      },\n      \"name\": \"core1\",\n      \"isDefaultCore\": false,\n      \"instanceDir\": \"solr/core1/\",\n      \"dataDir\": \"/srv/solr-core1/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.449Z\",\n      \"uptime\": 2314746645\n    },\n    \"main\": {\n      \"index\": {\n        \"size\": \"230.5 GB\",\n        \"sizeInBytes\": 247497521642,\n        \"lastModified\": \"2017-01-16T11:59:18.189Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484567958189\"\n        },\n        \"numDocs\": 168943425,\n        \"maxDoc\": 169562700,\n        \"deletedDocs\": 619275,\n        \"version\": 70688464,\n        \"segmentCount\": 33,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\"\n      },\n      \"name\": \"main\",\n      \"isDefaultCore\": true,\n      \"instanceDir\": \"solr/main/\",\n      \"dataDir\": \"/srv/solr/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.796Z\",\n      \"uptime\": 2314746294\n    }\n  },\n  \"initFailures\": {},\n  \"defaultCoreName\": \"main\",\n  \"responseHeader\": {\n    \"QTime\": 13,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/no_core_data/core1/admin/mbeans.json",
    "content": "\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/no_core_data/expected.out",
    "content": "solr_admin,core=core1 deleted_docs=102815i,max_docs=7620303i,num_docs=7517488i,size_in_bytes=1784635686i\nsolr_admin,core=main deleted_docs=619275i,max_docs=169562700i,num_docs=168943425i,size_in_bytes=247497521642i"
  },
  {
    "path": "plugins/inputs/solr/testcases/no_core_data/main/admin/mbeans.json",
    "content": "\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/no_core_data/telegraf.conf",
    "content": "[[inputs.solr]]\n  servers = [\"http://localhost:8983\"]\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v3.5/admin/cores.json",
    "content": "{\n  \"status\": {\n    \"core1\": {\n      \"index\": {\n        \"size\": \"1.66 GB\",\n        \"sizeInBytes\": 1784635686,\n        \"lastModified\": \"2017-01-14T10:30:07.419Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484389807419\"\n        },\n        \"numDocs\": 7517488,\n        \"maxDoc\": 7620303,\n        \"deletedDocs\": 102815,\n        \"version\": 267485,\n        \"segmentCount\": 21,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\"\n      },\n      \"name\": \"core1\",\n      \"isDefaultCore\": false,\n      \"instanceDir\": \"solr/core1/\",\n      \"dataDir\": \"/srv/solr-core1/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.449Z\",\n      \"uptime\": 2314746645\n    },\n    \"main\": {\n      \"index\": {\n        \"size\": \"230.5 GB\",\n        \"sizeInBytes\": 247497521642,\n        \"lastModified\": \"2017-01-16T11:59:18.189Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484567958189\"\n        },\n        \"numDocs\": 168943425,\n        \"maxDoc\": 169562700,\n        \"deletedDocs\": 619275,\n        \"version\": 70688464,\n        \"segmentCount\": 33,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\"\n      },\n      \"name\": \"main\",\n      \"isDefaultCore\": true,\n      \"instanceDir\": \"solr/main/\",\n      \"dataDir\": \"/srv/solr/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.796Z\",\n      \"uptime\": 2314746294\n    }\n  },\n  \"initFailures\": {},\n  \"defaultCoreName\": \"main\",\n  \"responseHeader\": {\n    \"QTime\": 13,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v3.5/core1/admin/mbeans.json",
    "content": "{\n  \"solr-mbeans\": [\n    \"CORE\",\n    {\n      \"searcher\": {\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\",\n        \"version\": \"1.0\",\n        \"description\": \"index searcher\",\n        \"srcId\": \"$Id: SolrIndexSearcher.java 1201291 2011-11-12 18:02:03Z simonw $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"searcherName\": \"Searcher@4eea69e8 main\",\n          \"caching\": true,\n          \"numDocs\": 117166,\n          \"maxDoc\": 117305,\n          \"reader\": \"SolrIndexReader{this=2ee29b0,r=ReadOnlyDirectoryReader@2ee29b0,refCnt=1,segments=5}\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/usr/solrData/search/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@178671d8\",\n          \"indexVersion\": 1491861981523,\n          \"openedAt\": \"2018-01-17T20:14:54.677Z\",\n          \"registeredAt\": \"2018-01-17T20:14:54.679Z\",\n          \"warmupTime\": 1\n        }\n      },\n      \"core\": {\n        \"class\": \"search\",\n        \"version\": \"1.0\",\n        \"description\": \"SolrCore\",\n        \"srcId\": \"$Id: SolrCore.java 1190108 2011-10-28 01:13:25Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/SolrCore.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"coreName\": \"search\",\n          \"startTime\": \"2018-01-16T06:15:53.152Z\",\n          \"refCount\": 2,\n          \"aliases\": [\n            \"search\"\n          ]\n        }\n      },\n      \"Searcher@4eea69e8 main\": {\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\",\n        \"version\": \"1.0\",\n        \"description\": \"index searcher\",\n        \"srcId\": \"$Id: SolrIndexSearcher.java 1201291 2011-11-12 18:02:03Z simonw $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"searcherName\": \"Searcher@4eea69e8 main\",\n          \"caching\": true,\n          \"numDocs\": 117166,\n          \"maxDoc\": 117305,\n          \"reader\": \"SolrIndexReader{this=2ee29b0,r=ReadOnlyDirectoryReader@2ee29b0,refCnt=1,segments=5}\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/usr/solrData/search/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@178671d8\",\n          \"indexVersion\": 1491861981523,\n          \"openedAt\": \"2018-01-17T20:14:54.677Z\",\n          \"registeredAt\": \"2018-01-17T20:14:54.679Z\",\n          \"warmupTime\": 1\n        }\n      }\n    },\n    \"QUERYHANDLER\",\n    {\n      \"/admin/system\": {\n        \"class\": \"org.apache.solr.handler.admin.SystemInfoHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Get System Info\",\n        \"srcId\": \"$Id: SystemInfoHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/plugins\": {\n        \"class\": \"org.apache.solr.handler.admin.PluginInfoHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Registry\",\n        \"srcId\": \"$Id: PluginInfoHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/file\": {\n        \"class\": \"org.apache.solr.handler.admin.ShowFileRequestHandler\",\n        \"version\": \"$Revision: 1146806 $\",\n        \"description\": \"Admin Get File -- view config files directly\",\n        \"srcId\": \"$Id: ShowFileRequestHandler.java 1146806 2011-07-14 17:01:37Z erick $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/javabin\": {\n        \"class\": \"org.apache.solr.handler.BinaryUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add/Update multiple documents with javabin format\",\n        \"srcId\": \"$Id: BinaryUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/BinaryUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353158,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/luke\": {\n        \"class\": \"org.apache.solr.handler.admin.LukeRequestHandler\",\n        \"version\": \"$Revision: 1201265 $\",\n        \"description\": \"Lucene Index Browser.  Inspired and modeled after Luke: http://www.getopt.org/luke/\",\n        \"srcId\": \"$Id: LukeRequestHandler.java 1201265 2011-11-12 14:09:28Z mikemccand $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java $\",\n        \"docs\": [\n          \"java.net.URL:http://wiki.apache.org/solr/LukeRequestHandler\"\n        ],\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/dataimport\": {\n        \"class\": \"org.apache.solr.handler.dataimport.DataImportHandler\",\n        \"version\": \"1.0\",\n        \"description\": \"Manage data import from databases to Solr\",\n        \"srcId\": \"$Id: DataImportHandler.java 1171306 2011-09-15 22:43:33Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java $\",\n        \"docs\": null,\n        \"stats\": [\n          \"Status\",\n          \"IDLE\",\n          \"Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:1\",\n          \"Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:351705\",\n          \"Total Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:1438\",\n          \"Total Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:876393\",\n          \"Total Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"handlerStart\",\n          1516083353155,\n          \"requests\",\n          2442,\n          \"errors\",\n          0,\n          \"timeouts\",\n          0,\n          \"totalTime\",\n          1748,\n          \"avgTimePerRequest\",\n          0.7158067,\n          \"avgRequestsPerSecond\",\n          0.017792022\n        ]\n      },\n      \"/update\": {\n        \"class\": \"org.apache.solr.handler.XmlUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add documents with XML\",\n        \"srcId\": \"$Id: XmlUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353157,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/terms\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"org.apache.solr.handler.XmlUpdateRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.XmlUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add documents with XML\",\n        \"srcId\": \"$Id: XmlUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353157,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.PingRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\",\n        \"version\": \"$Revision: 1142180 $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"srcId\": \"$Id: PingRequestHandler.java 1142180 2011-07-02 09:04:29Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/threads\": {\n        \"class\": \"org.apache.solr.handler.admin.ThreadDumpHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Thread Dump\",\n        \"srcId\": \"$Id: ThreadDumpHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.BinaryUpdateRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.BinaryUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add/Update multiple documents with javabin format\",\n        \"srcId\": \"$Id: BinaryUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/BinaryUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353158,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.dataimport.DataImportHandler\": {\n        \"class\": \"org.apache.solr.handler.dataimport.DataImportHandler\",\n        \"version\": \"1.0\",\n        \"description\": \"Manage data import from databases to Solr\",\n        \"srcId\": \"$Id: DataImportHandler.java 1171306 2011-09-15 22:43:33Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java $\",\n        \"docs\": null,\n        \"stats\": [\n          \"Status\",\n          \"IDLE\",\n          \"Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:1\",\n          \"Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:351705\",\n          \"Total Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:1438\",\n          \"Total Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:876393\",\n          \"Total Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"handlerStart\",\n          1516083353155,\n          \"requests\",\n          2442,\n          \"errors\",\n          0,\n          \"timeouts\",\n          0,\n          \"totalTime\",\n          1748,\n          \"avgTimePerRequest\",\n          0.7158067,\n          \"avgRequestsPerSecond\",\n          0.017792022\n        ]\n      },\n      \"/analysis/field\": {\n        \"class\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/browse\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.SpellCheckComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/ping\": {\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\",\n        \"version\": \"$Revision: 1142180 $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"srcId\": \"$Id: PingRequestHandler.java 1142180 2011-07-02 09:04:29Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/mbeans\": {\n        \"class\": \"org.apache.solr.handler.admin.SolrInfoMBeanHandler\",\n        \"version\": \"$Revision: 1065312 $\",\n        \"description\": \"Get Info (and statistics) about all registered SolrInfoMBeans\",\n        \"srcId\": \"$Id: SolrInfoMBeanHandler.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 1078,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 547,\n          \"avgTimePerRequest\": 0.50742114,\n          \"avgRequestsPerSecond\": 0.00785414\n        }\n      },\n      \"/analysis/document\": {\n        \"class\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"search\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/csv\": {\n        \"class\": \"Lazy[solr.CSVRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.CSVRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/update/json\": {\n        \"class\": \"Lazy[solr.JsonUpdateRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $ :: $Revision: 1102081 $\",\n        \"description\": \"Add documents with JSON\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $ :: $Id: JsonUpdateRequestHandler.java 1102081 2011-05-11 20:37:04Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\\n$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516103486630,\n          \"requests\": 2530,\n          \"errors\": 26,\n          \"timeouts\": 0,\n          \"totalTime\": 132438,\n          \"avgTimePerRequest\": 52.347034,\n          \"avgRequestsPerSecond\": 0.02160195\n        }\n      },\n      \"/admin/\": {\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\",\n        \"version\": \"$Revision: 953887 $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"srcId\": \"$Id: AdminHandlers.java 953887 2010-06-11 21:53:43Z hossman $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"docs\": null,\n        \"stats\": null\n      },\n      \"standard\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353155,\n          \"requests\": 11480,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 318753,\n          \"avgTimePerRequest\": 27.765942,\n          \"avgRequestsPerSecond\": 0.08364145\n        }\n      },\n      \"org.apache.solr.handler.admin.AdminHandlers\": {\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\",\n        \"version\": \"$Revision: 953887 $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"srcId\": \"$Id: AdminHandlers.java 953887 2010-06-11 21:53:43Z hossman $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"docs\": null,\n        \"stats\": null\n      },\n      \"tvrh\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"org.apache.solr.handler.DumpRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Dump handler (debug)\",\n        \"srcId\": \"$Id: DumpRequestHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/extract\": {\n        \"class\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/admin/properties\": {\n        \"class\": \"org.apache.solr.handler.admin.PropertiesRequestHandler\",\n        \"version\": \"$Revision: 898152 $\",\n        \"description\": \"Get System Properties\",\n        \"srcId\": \"$Id: PropertiesRequestHandler.java 898152 2010-01-12 02:19:56Z ryan $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.component.SearchHandler\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.SpellCheckComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/spell\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/debug/dump\": {\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Dump handler (debug)\",\n        \"srcId\": \"$Id: DumpRequestHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      }\n    },\n    \"UPDATEHANDLER\",\n    {\n      \"updateHandler\": {\n        \"class\": \"org.apache.solr.update.DirectUpdateHandler2\",\n        \"version\": \"1.0\",\n        \"description\": \"Update handler that efficiently directly updates the on-disk main lucene index\",\n        \"srcId\": \"$Id: DirectUpdateHandler2.java 1203770 2011-11-18 17:55:52Z mikemccand $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"commits\": 3220,\n          \"autocommits\": 0,\n          \"optimizes\": 3,\n          \"rollbacks\": 0,\n          \"expungeDeletes\": 0,\n          \"docsPending\": 0,\n          \"adds\": 0,\n          \"deletesById\": 0,\n          \"deletesByQuery\": 0,\n          \"errors\": 0,\n          \"cumulative_adds\": 354209,\n          \"cumulative_deletesById\": 0,\n          \"cumulative_deletesByQuery\": 3,\n          \"cumulative_errors\": 0\n        }\n      }\n    },\n    \"CACHE\",\n    {\n      \"queryResultCache\": {\n        \"class\": \"org.apache.solr.search.LRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"LRU Cache(maxSize=512, initialSize=512)\",\n        \"srcId\": \"$Id: LRUCache.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/LRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 4,\n          \"hits\": 2,\n          \"hitratio\": \"0.50\",\n          \"inserts\": 2,\n          \"evictions\": 0,\n          \"size\": 2,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 10630,\n          \"cumulative_hits\": 5509,\n          \"cumulative_hitratio\": \"0.51\",\n          \"cumulative_inserts\": 5626,\n          \"cumulative_evictions\": 0\n        }\n      },\n      \"fieldCache\": {\n        \"class\": \"org.apache.solr.search.SolrFieldCacheMBean\",\n        \"version\": \"1.0\",\n        \"description\": \"Provides introspection of the Lucene FieldCache, this is **NOT** a cache that is managed by Solr.\",\n        \"srcId\": \"$Id: SolrFieldCacheMBean.java 984594 2010-08-11 21:42:04Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"entries_count\": 174,\n          \"entry#0\": \"'MMapIndexInput(path=\\\"/usr/solrData/search/index/_9eir.frq\\\")'=>'latlng_0_coordinate',double,org.apache.lucene.search.FieldCache.NUMERIC_UTILS_DOUBLE_PARSER=>[D#661647869\",\n          \"insanity_count\": 1,\n          \"insanity#0\": \"SUBREADER: Found caches for descendants of ReadOnlyDirectoryReader(segments_1wo _3kl(3.5):C133115/12 _3kw(3.5):C17/2 _3kx(3.5):C6 _3ky(3.5):C1 _3kz(3.5):C2 _3l0(3.5):C2 _3l1(3.5):C1 _3l2(3.5):C1 _3l3(3.5):C1 _3l4(3.5):C1)+owner\\n\\t'ReadOnlyDirectoryReader(segments_1wo _3kl(3.5):C133115/12 _3kw(3.5):C17/2 _3kx(3.5):C6 _3ky(3.5):C1 _3kz(3.5):C2 _3l0(3.5):C2 _3l1(3.5):C1 _3l2(3.5):C1 _3l3(3.5):C1 _3l4(3.5):C1)'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#927712538\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kx.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#969886745\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kz.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#495952608\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3ky.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1581258843\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l1.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#359550090\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kl.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1748227582\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l4.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1084424163\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l3.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1116912780\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l0.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1187916045\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l2.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#62119827\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kw.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1756606907\\n\"\n        }\n      },\n      \"documentCache\": {\n        \"class\": \"org.apache.solr.search.LRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"LRU Cache(maxSize=512, initialSize=512)\",\n        \"srcId\": \"$Id: LRUCache.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/LRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 180435,\n          \"cumulative_hits\": 22584,\n          \"cumulative_hitratio\": \"0.12\",\n          \"cumulative_inserts\": 157851,\n          \"cumulative_evictions\": 40344\n        }\n      },\n      \"fieldValueCache\": {\n        \"class\": \"org.apache.solr.search.FastLRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"Concurrent LRU Cache(maxSize=10000, initialSize=10, minSize=9000, acceptableSize=9500, cleanupThread=false)\",\n        \"srcId\": \"$Id: FastLRUCache.java 1170772 2011-09-14 19:09:56Z sarowe $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 5,\n          \"hits\": 3,\n          \"hitratio\": \"0.60\",\n          \"inserts\": 1,\n          \"evictions\": 0,\n          \"size\": 1,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 8529,\n          \"cumulative_hits\": 5432,\n          \"cumulative_hitratio\": \"0.63\",\n          \"cumulative_inserts\": 1437,\n          \"cumulative_evictions\": 0,\n          \"item_parentCompanyId\": \"{field=parentCompanyId,memSize=785156,tindexSize=13056,time=136,phase1=135,nTerms=75696,bigTerms=0,termInstances=117166,uses=4}\"\n        }\n      },\n      \"filterCache\": {\n        \"class\": \"org.apache.solr.search.FastLRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"Concurrent LRU Cache(maxSize=512, initialSize=512, minSize=460, acceptableSize=486, cleanupThread=false)\",\n        \"srcId\": \"$Id: FastLRUCache.java 1170772 2011-09-14 19:09:56Z sarowe $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 2,\n          \"hits\": 2,\n          \"hitratio\": \"1.00\",\n          \"inserts\": 2,\n          \"evictions\": 0,\n          \"size\": 2,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 4041,\n          \"cumulative_hits\": 4041,\n          \"cumulative_hitratio\": \"1.00\",\n          \"cumulative_inserts\": 2828,\n          \"cumulative_evictions\": 0\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v3.5/expected.out",
    "content": "solr_admin,core=core1 deleted_docs=102815i,max_docs=7620303i,num_docs=7517488i,size_in_bytes=1784635686i\nsolr_admin,core=main deleted_docs=619275i,max_docs=169562700i,num_docs=168943425i,size_in_bytes=247497521642i\nsolr_cache,core=core1,handler=documentCache cumulative_evictions=40344i,cumulative_hitratio=0.12,cumulative_hits=22584i,cumulative_inserts=157851i,cumulative_lookups=180435i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=core1,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0.63,cumulative_hits=5432i,cumulative_inserts=1437i,cumulative_lookups=8529i,evictions=0i,hitratio=0.6,hits=3i,inserts=1i,lookups=5i,size=1i,warmup_time=0i\nsolr_cache,core=core1,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=4041i,cumulative_inserts=2828i,cumulative_lookups=4041i,evictions=0i,hitratio=1,hits=2i,inserts=2i,lookups=2i,size=2i,warmup_time=0i\nsolr_cache,core=core1,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0.51,cumulative_hits=5509i,cumulative_inserts=5626i,cumulative_lookups=10630i,evictions=0i,hitratio=0.5,hits=2i,inserts=2i,lookups=4i,size=2i,warmup_time=0i\nsolr_cache,core=main,handler=documentCache cumulative_evictions=40344i,cumulative_hitratio=0.12,cumulative_hits=22584i,cumulative_inserts=157851i,cumulative_lookups=180435i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0.63,cumulative_hits=5432i,cumulative_inserts=1437i,cumulative_lookups=8529i,evictions=0i,hitratio=0.6,hits=3i,inserts=1i,lookups=5i,size=1i,warmup_time=0i\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=1,cumulative_hits=4041i,cumulative_inserts=2828i,cumulative_lookups=4041i,evictions=0i,hitratio=1,hits=2i,inserts=2i,lookups=2i,size=2i,warmup_time=0i\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0.51,cumulative_hits=5509i,cumulative_inserts=5626i,cumulative_lookups=10630i,evictions=0i,hitratio=0.5,hits=2i,inserts=2i,lookups=4i,size=2i,warmup_time=0i\nsolr_core,core=core1,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=core1,handler=searcher deleted_docs=0i,max_docs=117305i,num_docs=117166i\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i\nsolr_core,core=main,handler=searcher deleted_docs=0i,max_docs=117305i,num_docs=117166i\nsolr_queryhandler,core=core1,handler=/admin/file 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/luke 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/mbeans 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.00785414,avg_time_per_request=0.50742114,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=1078i,timeouts=0i,total_time=547\nsolr_queryhandler,core=core1,handler=/admin/ping 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/plugins 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/properties 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/system 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/admin/threads 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/analysis/document 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/analysis/field 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/browse 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/dataimport 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.017792022,avg_time_per_request=0.7158067,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=2442i,timeouts=0i,total_time=1748\nsolr_queryhandler,core=core1,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.BinaryUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353158i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.component.SearchHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.dataimport.DataImportHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.017792022,avg_time_per_request=0.7158067,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=2442i,timeouts=0i,total_time=1748\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.DumpRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.PingRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.XmlUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353157i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=search 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/spell 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=standard 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.08364145,avg_time_per_request=27.765942,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=11480i,timeouts=0i,total_time=318753\nsolr_queryhandler,core=core1,handler=/terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=tvrh 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/update 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353157i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/update/csv 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/update/extract 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/update/javabin 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353158i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=core1,handler=/update/json 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.02160195,avg_time_per_request=52.347034,errors=26i,handler_start=1516103486630i,median_request_time=0,requests=2530i,timeouts=0i,total_time=132438\nsolr_queryhandler,core=main,handler=/admin/file 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/luke 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/mbeans 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.00785414,avg_time_per_request=0.50742114,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=1078i,timeouts=0i,total_time=547\nsolr_queryhandler,core=main,handler=/admin/ping 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/plugins 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/properties 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/system 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/admin/threads 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353227i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/analysis/document 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/analysis/field 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/browse 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/dataimport 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.017792022,avg_time_per_request=0.7158067,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=2442i,timeouts=0i,total_time=1748\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.BinaryUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353158i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.component.SearchHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.dataimport.DataImportHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.017792022,avg_time_per_request=0.7158067,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=2442i,timeouts=0i,total_time=1748\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.DumpRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.PingRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353163i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.XmlUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353157i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=search 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353156i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/spell 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=standard 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.08364145,avg_time_per_request=27.765942,errors=0i,handler_start=1516083353155i,median_request_time=0,requests=11480i,timeouts=0i,total_time=318753\nsolr_queryhandler,core=main,handler=/terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=tvrh 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/update 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353157i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/update/csv 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/update/extract 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/update/javabin 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1516083353158i,median_request_time=0,requests=0i,timeouts=0i,total_time=0\nsolr_queryhandler,core=main,handler=/update/json 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0.02160195,avg_time_per_request=52.347034,errors=26i,handler_start=1516103486630i,median_request_time=0,requests=2530i,timeouts=0i,total_time=132438\nsolr_updatehandler,core=core1,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=3220i,cumulative_adds=354209i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=3i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=3i,rollbacks=0i,soft_autocommits=0i\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=0i,autocommit_max_time=0i,autocommits=0i,commits=3220i,cumulative_adds=354209i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=3i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=3i,rollbacks=0i,soft_autocommits=0i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v3.5/main/admin/mbeans.json",
    "content": "{\n  \"solr-mbeans\": [\n    \"CORE\",\n    {\n      \"searcher\": {\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\",\n        \"version\": \"1.0\",\n        \"description\": \"index searcher\",\n        \"srcId\": \"$Id: SolrIndexSearcher.java 1201291 2011-11-12 18:02:03Z simonw $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"searcherName\": \"Searcher@4eea69e8 main\",\n          \"caching\": true,\n          \"numDocs\": 117166,\n          \"maxDoc\": 117305,\n          \"reader\": \"SolrIndexReader{this=2ee29b0,r=ReadOnlyDirectoryReader@2ee29b0,refCnt=1,segments=5}\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/usr/solrData/search/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@178671d8\",\n          \"indexVersion\": 1491861981523,\n          \"openedAt\": \"2018-01-17T20:14:54.677Z\",\n          \"registeredAt\": \"2018-01-17T20:14:54.679Z\",\n          \"warmupTime\": 1\n        }\n      },\n      \"core\": {\n        \"class\": \"search\",\n        \"version\": \"1.0\",\n        \"description\": \"SolrCore\",\n        \"srcId\": \"$Id: SolrCore.java 1190108 2011-10-28 01:13:25Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/SolrCore.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"coreName\": \"search\",\n          \"startTime\": \"2018-01-16T06:15:53.152Z\",\n          \"refCount\": 2,\n          \"aliases\": [\n            \"search\"\n          ]\n        }\n      },\n      \"Searcher@4eea69e8 main\": {\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\",\n        \"version\": \"1.0\",\n        \"description\": \"index searcher\",\n        \"srcId\": \"$Id: SolrIndexSearcher.java 1201291 2011-11-12 18:02:03Z simonw $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"searcherName\": \"Searcher@4eea69e8 main\",\n          \"caching\": true,\n          \"numDocs\": 117166,\n          \"maxDoc\": 117305,\n          \"reader\": \"SolrIndexReader{this=2ee29b0,r=ReadOnlyDirectoryReader@2ee29b0,refCnt=1,segments=5}\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/usr/solrData/search/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@178671d8\",\n          \"indexVersion\": 1491861981523,\n          \"openedAt\": \"2018-01-17T20:14:54.677Z\",\n          \"registeredAt\": \"2018-01-17T20:14:54.679Z\",\n          \"warmupTime\": 1\n        }\n      }\n    },\n    \"QUERYHANDLER\",\n    {\n      \"/admin/system\": {\n        \"class\": \"org.apache.solr.handler.admin.SystemInfoHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Get System Info\",\n        \"srcId\": \"$Id: SystemInfoHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/plugins\": {\n        \"class\": \"org.apache.solr.handler.admin.PluginInfoHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Registry\",\n        \"srcId\": \"$Id: PluginInfoHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/file\": {\n        \"class\": \"org.apache.solr.handler.admin.ShowFileRequestHandler\",\n        \"version\": \"$Revision: 1146806 $\",\n        \"description\": \"Admin Get File -- view config files directly\",\n        \"srcId\": \"$Id: ShowFileRequestHandler.java 1146806 2011-07-14 17:01:37Z erick $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/javabin\": {\n        \"class\": \"org.apache.solr.handler.BinaryUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add/Update multiple documents with javabin format\",\n        \"srcId\": \"$Id: BinaryUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/BinaryUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353158,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/luke\": {\n        \"class\": \"org.apache.solr.handler.admin.LukeRequestHandler\",\n        \"version\": \"$Revision: 1201265 $\",\n        \"description\": \"Lucene Index Browser.  Inspired and modeled after Luke: http://www.getopt.org/luke/\",\n        \"srcId\": \"$Id: LukeRequestHandler.java 1201265 2011-11-12 14:09:28Z mikemccand $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java $\",\n        \"docs\": [\n          \"java.net.URL:http://wiki.apache.org/solr/LukeRequestHandler\"\n        ],\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/dataimport\": {\n        \"class\": \"org.apache.solr.handler.dataimport.DataImportHandler\",\n        \"version\": \"1.0\",\n        \"description\": \"Manage data import from databases to Solr\",\n        \"srcId\": \"$Id: DataImportHandler.java 1171306 2011-09-15 22:43:33Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java $\",\n        \"docs\": null,\n        \"stats\": [\n          \"Status\",\n          \"IDLE\",\n          \"Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:1\",\n          \"Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:351705\",\n          \"Total Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:1438\",\n          \"Total Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:876393\",\n          \"Total Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"handlerStart\",\n          1516083353155,\n          \"requests\",\n          2442,\n          \"errors\",\n          0,\n          \"timeouts\",\n          0,\n          \"totalTime\",\n          1748,\n          \"avgTimePerRequest\",\n          0.7158067,\n          \"avgRequestsPerSecond\",\n          0.017792022\n        ]\n      },\n      \"/update\": {\n        \"class\": \"org.apache.solr.handler.XmlUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add documents with XML\",\n        \"srcId\": \"$Id: XmlUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353157,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/terms\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"org.apache.solr.handler.XmlUpdateRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.XmlUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add documents with XML\",\n        \"srcId\": \"$Id: XmlUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353157,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.PingRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\",\n        \"version\": \"$Revision: 1142180 $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"srcId\": \"$Id: PingRequestHandler.java 1142180 2011-07-02 09:04:29Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/threads\": {\n        \"class\": \"org.apache.solr.handler.admin.ThreadDumpHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Thread Dump\",\n        \"srcId\": \"$Id: ThreadDumpHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.BinaryUpdateRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.BinaryUpdateRequestHandler\",\n        \"version\": \"$Revision: 1165749 $\",\n        \"description\": \"Add/Update multiple documents with javabin format\",\n        \"srcId\": \"$Id: BinaryUpdateRequestHandler.java 1165749 2011-09-06 16:20:07Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/BinaryUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353158,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.dataimport.DataImportHandler\": {\n        \"class\": \"org.apache.solr.handler.dataimport.DataImportHandler\",\n        \"version\": \"1.0\",\n        \"description\": \"Manage data import from databases to Solr\",\n        \"srcId\": \"$Id: DataImportHandler.java 1171306 2011-09-15 22:43:33Z janhoy $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java $\",\n        \"docs\": null,\n        \"stats\": [\n          \"Status\",\n          \"IDLE\",\n          \"Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:1\",\n          \"Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:2\",\n          \"Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Processed\",\n          \"java.util.concurrent.atomic.AtomicLong:351705\",\n          \"Total Requests made to DataSource\",\n          \"java.util.concurrent.atomic.AtomicLong:1438\",\n          \"Total Rows Fetched\",\n          \"java.util.concurrent.atomic.AtomicLong:876393\",\n          \"Total Documents Deleted\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"Total Documents Skipped\",\n          \"java.util.concurrent.atomic.AtomicLong:0\",\n          \"handlerStart\",\n          1516083353155,\n          \"requests\",\n          2442,\n          \"errors\",\n          0,\n          \"timeouts\",\n          0,\n          \"totalTime\",\n          1748,\n          \"avgTimePerRequest\",\n          0.7158067,\n          \"avgRequestsPerSecond\",\n          0.017792022\n        ]\n      },\n      \"/analysis/field\": {\n        \"class\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/browse\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.SpellCheckComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/ping\": {\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\",\n        \"version\": \"$Revision: 1142180 $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"srcId\": \"$Id: PingRequestHandler.java 1142180 2011-07-02 09:04:29Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/admin/mbeans\": {\n        \"class\": \"org.apache.solr.handler.admin.SolrInfoMBeanHandler\",\n        \"version\": \"$Revision: 1065312 $\",\n        \"description\": \"Get Info (and statistics) about all registered SolrInfoMBeans\",\n        \"srcId\": \"$Id: SolrInfoMBeanHandler.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 1078,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 547,\n          \"avgTimePerRequest\": 0.50742114,\n          \"avgRequestsPerSecond\": 0.00785414\n        }\n      },\n      \"/analysis/document\": {\n        \"class\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"search\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/csv\": {\n        \"class\": \"Lazy[solr.CSVRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.CSVRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/update/json\": {\n        \"class\": \"Lazy[solr.JsonUpdateRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $ :: $Revision: 1102081 $\",\n        \"description\": \"Add documents with JSON\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $ :: $Id: JsonUpdateRequestHandler.java 1102081 2011-05-11 20:37:04Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\\n$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516103486630,\n          \"requests\": 2530,\n          \"errors\": 26,\n          \"timeouts\": 0,\n          \"totalTime\": 132438,\n          \"avgTimePerRequest\": 52.347034,\n          \"avgRequestsPerSecond\": 0.02160195\n        }\n      },\n      \"/admin/\": {\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\",\n        \"version\": \"$Revision: 953887 $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"srcId\": \"$Id: AdminHandlers.java 953887 2010-06-11 21:53:43Z hossman $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"docs\": null,\n        \"stats\": null\n      },\n      \"standard\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353155,\n          \"requests\": 11480,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 318753,\n          \"avgTimePerRequest\": 27.765942,\n          \"avgRequestsPerSecond\": 0.08364145\n        }\n      },\n      \"org.apache.solr.handler.admin.AdminHandlers\": {\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\",\n        \"version\": \"$Revision: 953887 $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"srcId\": \"$Id: AdminHandlers.java 953887 2010-06-11 21:53:43Z hossman $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"docs\": null,\n        \"stats\": null\n      },\n      \"tvrh\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"org.apache.solr.handler.DumpRequestHandler\": {\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Dump handler (debug)\",\n        \"srcId\": \"$Id: DumpRequestHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/update/extract\": {\n        \"class\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/admin/properties\": {\n        \"class\": \"org.apache.solr.handler.admin.PropertiesRequestHandler\",\n        \"version\": \"$Revision: 898152 $\",\n        \"description\": \"Get System Properties\",\n        \"srcId\": \"$Id: PropertiesRequestHandler.java 898152 2010-01-12 02:19:56Z ryan $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353227,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"org.apache.solr.handler.component.SearchHandler\": {\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\",\n        \"version\": \"$Revision: 1052938 $\",\n        \"description\": \"Search using components: org.apache.solr.handler.component.QueryComponent,org.apache.solr.handler.component.FacetComponent,org.apache.solr.handler.component.MoreLikeThisComponent,org.apache.solr.handler.component.HighlightComponent,org.apache.solr.handler.component.StatsComponent,org.apache.solr.handler.component.SpellCheckComponent,org.apache.solr.handler.component.DebugComponent,\",\n        \"srcId\": \"$Id: SearchHandler.java 1052938 2010-12-26 20:21:48Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353156,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      },\n      \"/spell\": {\n        \"class\": \"Lazy[solr.SearchHandler]\",\n        \"version\": \"$Revision: 1086822 $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"srcId\": \"$Id: RequestHandlers.java 1086822 2011-03-30 02:23:07Z koji $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        }\n      },\n      \"/debug/dump\": {\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\",\n        \"version\": \"$Revision: 1067172 $\",\n        \"description\": \"Dump handler (debug)\",\n        \"srcId\": \"$Id: DumpRequestHandler.java 1067172 2011-02-04 12:50:14Z uschindler $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"handlerStart\": 1516083353163,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgTimePerRequest\": \"NaN\",\n          \"avgRequestsPerSecond\": 0\n        }\n      }\n    },\n    \"UPDATEHANDLER\",\n    {\n      \"updateHandler\": {\n        \"class\": \"org.apache.solr.update.DirectUpdateHandler2\",\n        \"version\": \"1.0\",\n        \"description\": \"Update handler that efficiently directly updates the on-disk main lucene index\",\n        \"srcId\": \"$Id: DirectUpdateHandler2.java 1203770 2011-11-18 17:55:52Z mikemccand $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"commits\": 3220,\n          \"autocommits\": 0,\n          \"optimizes\": 3,\n          \"rollbacks\": 0,\n          \"expungeDeletes\": 0,\n          \"docsPending\": 0,\n          \"adds\": 0,\n          \"deletesById\": 0,\n          \"deletesByQuery\": 0,\n          \"errors\": 0,\n          \"cumulative_adds\": 354209,\n          \"cumulative_deletesById\": 0,\n          \"cumulative_deletesByQuery\": 3,\n          \"cumulative_errors\": 0\n        }\n      }\n    },\n    \"CACHE\",\n    {\n      \"queryResultCache\": {\n        \"class\": \"org.apache.solr.search.LRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"LRU Cache(maxSize=512, initialSize=512)\",\n        \"srcId\": \"$Id: LRUCache.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/LRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 4,\n          \"hits\": 2,\n          \"hitratio\": \"0.50\",\n          \"inserts\": 2,\n          \"evictions\": 0,\n          \"size\": 2,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 10630,\n          \"cumulative_hits\": 5509,\n          \"cumulative_hitratio\": \"0.51\",\n          \"cumulative_inserts\": 5626,\n          \"cumulative_evictions\": 0\n        }\n      },\n      \"fieldCache\": {\n        \"class\": \"org.apache.solr.search.SolrFieldCacheMBean\",\n        \"version\": \"1.0\",\n        \"description\": \"Provides introspection of the Lucene FieldCache, this is **NOT** a cache that is managed by Solr.\",\n        \"srcId\": \"$Id: SolrFieldCacheMBean.java 984594 2010-08-11 21:42:04Z yonik $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"entries_count\": 174,\n          \"entry#0\": \"'MMapIndexInput(path=\\\"/usr/solrData/search/index/_9eir.frq\\\")'=>'latlng_0_coordinate',double,org.apache.lucene.search.FieldCache.NUMERIC_UTILS_DOUBLE_PARSER=>[D#661647869\",\n          \"insanity_count\": 1,\n          \"insanity#0\": \"SUBREADER: Found caches for descendants of ReadOnlyDirectoryReader(segments_1wo _3kl(3.5):C133115/12 _3kw(3.5):C17/2 _3kx(3.5):C6 _3ky(3.5):C1 _3kz(3.5):C2 _3l0(3.5):C2 _3l1(3.5):C1 _3l2(3.5):C1 _3l3(3.5):C1 _3l4(3.5):C1)+owner\\n\\t'ReadOnlyDirectoryReader(segments_1wo _3kl(3.5):C133115/12 _3kw(3.5):C17/2 _3kx(3.5):C6 _3ky(3.5):C1 _3kz(3.5):C2 _3l0(3.5):C2 _3l1(3.5):C1 _3l2(3.5):C1 _3l3(3.5):C1 _3l4(3.5):C1)'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#927712538\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kx.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#969886745\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kz.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#495952608\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3ky.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1581258843\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l1.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#359550090\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kl.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1748227582\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l4.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1084424163\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l3.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1116912780\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l0.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1187916045\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3l2.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#62119827\\n\\t'MMapIndexInput(path=\\\"/usr/solrData/search/index/_3kw.frq\\\")'=>'owner',class org.apache.lucene.search.FieldCache$StringIndex,null=>org.apache.lucene.search.FieldCache$StringIndex#1756606907\\n\"\n        }\n      },\n      \"documentCache\": {\n        \"class\": \"org.apache.solr.search.LRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"LRU Cache(maxSize=512, initialSize=512)\",\n        \"srcId\": \"$Id: LRUCache.java 1065312 2011-01-30 16:08:25Z rmuir $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/LRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 180435,\n          \"cumulative_hits\": 22584,\n          \"cumulative_hitratio\": \"0.12\",\n          \"cumulative_inserts\": 157851,\n          \"cumulative_evictions\": 40344\n        }\n      },\n      \"fieldValueCache\": {\n        \"class\": \"org.apache.solr.search.FastLRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"Concurrent LRU Cache(maxSize=10000, initialSize=10, minSize=9000, acceptableSize=9500, cleanupThread=false)\",\n        \"srcId\": \"$Id: FastLRUCache.java 1170772 2011-09-14 19:09:56Z sarowe $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 5,\n          \"hits\": 3,\n          \"hitratio\": \"0.60\",\n          \"inserts\": 1,\n          \"evictions\": 0,\n          \"size\": 1,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 8529,\n          \"cumulative_hits\": 5432,\n          \"cumulative_hitratio\": \"0.63\",\n          \"cumulative_inserts\": 1437,\n          \"cumulative_evictions\": 0,\n          \"item_parentCompanyId\": \"{field=parentCompanyId,memSize=785156,tindexSize=13056,time=136,phase1=135,nTerms=75696,bigTerms=0,termInstances=117166,uses=4}\"\n        }\n      },\n      \"filterCache\": {\n        \"class\": \"org.apache.solr.search.FastLRUCache\",\n        \"version\": \"1.0\",\n        \"description\": \"Concurrent LRU Cache(maxSize=512, initialSize=512, minSize=460, acceptableSize=486, cleanupThread=false)\",\n        \"srcId\": \"$Id: FastLRUCache.java 1170772 2011-09-14 19:09:56Z sarowe $\",\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"docs\": null,\n        \"stats\": {\n          \"lookups\": 2,\n          \"hits\": 2,\n          \"hitratio\": \"1.00\",\n          \"inserts\": 2,\n          \"evictions\": 0,\n          \"size\": 2,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 4041,\n          \"cumulative_hits\": 4041,\n          \"cumulative_hitratio\": \"1.00\",\n          \"cumulative_inserts\": 2828,\n          \"cumulative_evictions\": 0\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v3.5/telegraf.conf",
    "content": "[[inputs.solr]]\n  servers = [\"http://localhost:8983\"]\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v4.3/admin/cores.json",
    "content": "{\n  \"status\": {\n    \"core1\": {\n      \"index\": {\n        \"size\": \"1.66 GB\",\n        \"sizeInBytes\": 1784635686,\n        \"lastModified\": \"2017-01-14T10:30:07.419Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484389807419\"\n        },\n        \"numDocs\": 7517488,\n        \"maxDoc\": 7620303,\n        \"deletedDocs\": 102815,\n        \"version\": 267485,\n        \"segmentCount\": 21,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\"\n      },\n      \"name\": \"core1\",\n      \"isDefaultCore\": false,\n      \"instanceDir\": \"solr/core1/\",\n      \"dataDir\": \"/srv/solr-core1/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.449Z\",\n      \"uptime\": 2314746645\n    },\n    \"main\": {\n      \"index\": {\n        \"size\": \"230.5 GB\",\n        \"sizeInBytes\": 247497521642,\n        \"lastModified\": \"2017-01-16T11:59:18.189Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484567958189\"\n        },\n        \"numDocs\": 168943425,\n        \"maxDoc\": 169562700,\n        \"deletedDocs\": 619275,\n        \"version\": 70688464,\n        \"segmentCount\": 33,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\"\n      },\n      \"name\": \"main\",\n      \"isDefaultCore\": true,\n      \"instanceDir\": \"solr/main/\",\n      \"dataDir\": \"/srv/solr/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.796Z\",\n      \"uptime\": 2314746294\n    }\n  },\n  \"initFailures\": {},\n  \"defaultCoreName\": \"main\",\n  \"responseHeader\": {\n    \"QTime\": 13,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v4.3/core1/admin/mbeans.json",
    "content": "{\n  \"solr-mbeans\": [\n    \"CORE\",\n    {\n      \"core\": {\n        \"stats\": {\n          \"aliases\": [\n            \"corename\"\n          ],\n          \"indexDir\": \"/srv/solr-corename/index.20160607000000124\",\n          \"refCount\": 2,\n          \"startTime\": \"2016-12-20T18:41:10.449Z\",\n          \"coreName\": \"core1\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/SolrCore.java $\",\n        \"description\": \"SolrCore\",\n        \"version\": \"1.0\",\n        \"class\": \"core1\"\n      },\n      \"Searcher@6f0833b2 main\": {\n        \"stats\": {\n          \"warmupTime\": 0,\n          \"registeredAt\": \"2017-01-14T12:00:00.209Z\",\n          \"openedAt\": \"2017-01-14T12:00:00.208Z\",\n          \"searcherName\": \"Searcher@6f0833b2 main\",\n          \"caching\": true,\n          \"numDocs\": 7517488,\n          \"maxDoc\": 7620303,\n          \"deletedDocs\": 102815,\n          \"reader\": \"StandardDirectoryReader(segments_20iv:267485:nrt _2849(4.3.1):C7517434/102330 _28e8(4.3.1):C7363/115 _28h0(4.3.1):C5430/77 _28kw(4.3.1):C5984 _28k2(4.3.1):C6510/12 _28g6(4.3.1):C4537/25 _28ha(4.3.1):C5529/25 _28i4(4.3.1):C5087/42 _28js(4.3.1):C5823/10 _28ix(4.3.1):C5627/18 _28kc(4.3.1):C6710/14 _28kl(4.3.1):C7179/10 _28hk(4.3.1):C5149/65 _28j7(4.3.1):C5643/28 _28ht(4.3.1):C5428/9 _28ji(4.3.1):C5150/15 _28gq(4.3.1):C4989/9 _28ie(4.3.1):C5460/8 _28io(4.3.1):C5165/3 _28kv(4.3.1):C51 _28kx(4.3.1):C55)\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\",\n          \"indexVersion\": 267485\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"description\": \"index searcher\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\"\n      },\n      \"searcher\": {\n        \"stats\": {\n          \"warmupTime\": 0,\n          \"registeredAt\": \"2017-01-14T12:00:00.209Z\",\n          \"openedAt\": \"2017-01-14T12:00:00.208Z\",\n          \"searcherName\": \"Searcher@6f0833b2 main\",\n          \"caching\": true,\n          \"numDocs\": 7517488,\n          \"maxDoc\": 7620303,\n          \"deletedDocs\": 102815,\n          \"reader\": \"StandardDirectoryReader(segments_20iv:267485:nrt _2849(4.3.1):C7517434/102330 _28e8(4.3.1):C7363/115 _28h0(4.3.1):C5430/77 _28kw(4.3.1):C5984 _28k2(4.3.1):C6510/12 _28g6(4.3.1):C4537/25 _28ha(4.3.1):C5529/25 _28i4(4.3.1):C5087/42 _28js(4.3.1):C5823/10 _28ix(4.3.1):C5627/18 _28kc(4.3.1):C6710/14 _28kl(4.3.1):C7179/10 _28hk(4.3.1):C5149/65 _28j7(4.3.1):C5643/28 _28ht(4.3.1):C5428/9 _28ji(4.3.1):C5150/15 _28gq(4.3.1):C4989/9 _28ie(4.3.1):C5460/8 _28io(4.3.1):C5165/3 _28kv(4.3.1):C51 _28kx(4.3.1):C55)\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\",\n          \"indexVersion\": 267485\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"description\": \"index searcher\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\"\n      }\n    },\n    \"QUERYHANDLER\",\n    {\n      \"org.apache.solr.handler.CSVRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270458,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/CSVRequestHandler.java $\",\n        \"description\": \"Add/Update multiple documents with CSV formatted rows\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.CSVRequestHandler\"\n      },\n      \"/admin/\": {\n        \"stats\": null,\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\"\n      },\n      \"/admin/mbeans\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 127.79069480400044,\n          \"99thPcRequestTime\": 9.033666420000003,\n          \"95thPcRequestTime\": 5.586449799999999,\n          \"75thPcRequestTime\": 4.68247075,\n          \"medianRequestTime\": 0.03985,\n          \"avgTimePerRequest\": 1.5857040673599807,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 230969,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 366246.89703,\n          \"avgRequestsPerSecond\": 0.09671315555928528,\n          \"5minRateReqsPerSecond\": 0.545082835587804,\n          \"15minRateReqsPerSecond\": 0.5414280756665533\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java $\",\n        \"description\": \"Get Info (and statistics) for registered SolrInfoMBeans\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.SolrInfoMBeanHandler\"\n      },\n      \"/debug/dump\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270462,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"description\": \"Dump handler (debug)\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\"\n      },\n      \"/admin/logging\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java $\",\n        \"description\": \"Logging Handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.LoggingHandler\"\n      },\n      \"/admin/plugins\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java $\",\n        \"description\": \"Registry\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.PluginInfoHandler\"\n      },\n      \"/admin/system\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java $\",\n        \"description\": \"Get System Info\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.SystemInfoHandler\"\n      },\n      \"/select\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0.518583,\n          \"99thPcRequestTime\": 0.518583,\n          \"95thPcRequestTime\": 0.518583,\n          \"75thPcRequestTime\": 0.518583,\n          \"medianRequestTime\": 0.518583,\n          \"avgTimePerRequest\": 0.518583,\n          \"handlerStart\": 1482259270455,\n          \"requests\": 1,\n          \"errors\": 1,\n          \"timeouts\": 0,\n          \"totalTime\": 0.518583,\n          \"avgRequestsPerSecond\": 4.187296521163843e-07,\n          \"5minRateReqsPerSecond\": 1.4821969375e-313,\n          \"15minRateReqsPerSecond\": 4.44659081257e-313\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,spellcheck,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/tvrh\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"org.apache.solr.handler.component.SearchHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270455,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/admin/luke\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"docs\": [\n          \"http://wiki.apache.org/solr/LukeRequestHandler\"\n        ],\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java $\",\n        \"description\": \"Lucene Index Browser.  Inspired and modeled after Luke: http://www.getopt.org/luke/\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.LukeRequestHandler\"\n      },\n      \"/update/json\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270457,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"description\": \"Add documents with JSON\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.JsonUpdateRequestHandler\"\n      },\n      \"org.apache.solr.handler.admin.AdminHandlers\": {\n        \"stats\": null,\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\"\n      },\n      \"org.apache.solr.handler.ReplicationHandler\": {\n        \"stats\": {\n          \"lastCycleBytesDownloaded\": \"2578996\",\n          \"timesIndexReplicated\": \"468\",\n          \"timesFailed\": \"2\",\n          \"replicationFailedAt\": \"Fri Feb 12 00:00:00 UTC 2016\",\n          \"indexReplicatedAt\": \"Sat Jan 14 12:00:00 UTC 2017\",\n          \"previousCycleTimeInSeconds\": \"0\",\n          \"isReplicating\": \"false\",\n          \"isPollingDisabled\": \"false\",\n          \"pollInterval\": \"12:00:00\",\n          \"masterUrl\": \"http://solr-s1:8983/solr/core1\",\n          \"isSlave\": \"true\",\n          \"isMaster\": \"false\",\n          \"indexPath\": \"/srv/solr-core1/index.20160607000000124\",\n          \"generation\": 93991,\n          \"15minRateReqsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"totalTime\": 0,\n          \"timeouts\": 0,\n          \"errors\": 0,\n          \"requests\": 0,\n          \"handlerStart\": 1482259270463,\n          \"avgTimePerRequest\": 0,\n          \"medianRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"999thPcRequestTime\": 0,\n          \"indexSize\": \"1.66 GB\",\n          \"indexVersion\": 1484389807419\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java $\",\n        \"description\": \"ReplicationHandler provides replication of index and configuration files from Master to Slaves\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.ReplicationHandler\"\n      },\n      \"org.apache.solr.handler.JsonUpdateRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270457,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"description\": \"Add documents with JSON\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.JsonUpdateRequestHandler\"\n      },\n      \"org.apache.solr.handler.DumpRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270462,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"description\": \"Dump handler (debug)\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\"\n      },\n      \"org.apache.solr.handler.RealTimeGetHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270456,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/RealTimeGetHandler.java $\",\n        \"description\": \"The realtime get handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.RealTimeGetHandler\"\n      },\n      \"/get\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270456,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/RealTimeGetHandler.java $\",\n        \"description\": \"The realtime get handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.RealTimeGetHandler\"\n      },\n      \"/admin/properties\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java $\",\n        \"description\": \"Get System Properties\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.PropertiesRequestHandler\"\n      },\n      \"/query\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270455,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/admin/threads\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java $\",\n        \"description\": \"Thread Dump\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.ThreadDumpHandler\"\n      },\n      \"/analysis/field\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.FieldAnalysisRequestHandler]\"\n      },\n      \"org.apache.solr.handler.PingRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270461,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\"\n      },\n      \"/analysis/document\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.DocumentAnalysisRequestHandler]\"\n      },\n      \"/spell\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"/update/csv\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270458,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/CSVRequestHandler.java $\",\n        \"description\": \"Add/Update multiple documents with CSV formatted rows\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.CSVRequestHandler\"\n      },\n      \"org.apache.solr.handler.UpdateRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270457,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandler.java $\",\n        \"description\": \"Add documents using XML (with XSLT), CSV, JSON, or javabin\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.UpdateRequestHandler\"\n      },\n      \"/replication\": {\n        \"stats\": {\n          \"lastCycleBytesDownloaded\": \"2578996\",\n          \"timesIndexReplicated\": \"468\",\n          \"timesFailed\": \"2\",\n          \"replicationFailedAt\": \"Fri Feb 12 00:00:00 UTC 2016\",\n          \"indexReplicatedAt\": \"Sat Jan 14 12:00:00 UTC 2017\",\n          \"previousCycleTimeInSeconds\": \"0\",\n          \"isReplicating\": \"false\",\n          \"isPollingDisabled\": \"false\",\n          \"pollInterval\": \"12:00:00\",\n          \"masterUrl\": \"http://solr-s1:8983/solr/core1\",\n          \"isSlave\": \"true\",\n          \"isMaster\": \"false\",\n          \"indexPath\": \"/srv/solr-core1/index.20160607000000124\",\n          \"generation\": 93991,\n          \"15minRateReqsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"totalTime\": 0,\n          \"timeouts\": 0,\n          \"errors\": 0,\n          \"requests\": 0,\n          \"handlerStart\": 1482259270463,\n          \"avgTimePerRequest\": 0,\n          \"medianRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"999thPcRequestTime\": 0,\n          \"indexSize\": \"1.66 GB\",\n          \"indexVersion\": 1484389807419\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java $\",\n        \"description\": \"ReplicationHandler provides replication of index and configuration files from Master to Slaves\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.ReplicationHandler\"\n      },\n      \"/admin/ping\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270461,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\"\n      },\n      \"/update\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270457,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandler.java $\",\n        \"description\": \"Add documents using XML (with XSLT), CSV, JSON, or javabin\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.UpdateRequestHandler\"\n      },\n      \"/terms\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"/admin/file\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270585,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java $\",\n        \"description\": \"Admin Get File -- view config files directly\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.ShowFileRequestHandler\"\n      },\n      \"/update/extract\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.extraction.ExtractingRequestHandler]\"\n      }\n    },\n    \"UPDATEHANDLER\",\n    {\n      \"updateHandler\": {\n        \"stats\": {\n          \"cumulative_errors\": 0,\n          \"expungeDeletes\": 0,\n          \"rollbacks\": 0,\n          \"optimizes\": 0,\n          \"soft autocommits\": 0,\n          \"autocommits\": 0,\n          \"autocommit maxTime\": \"900ms\",\n          \"autocommit maxDocs\": 500,\n          \"commits\": 0,\n          \"docsPending\": 0,\n          \"adds\": 0,\n          \"deletesById\": 0,\n          \"deletesByQuery\": 0,\n          \"errors\": 0,\n          \"cumulative_adds\": 0,\n          \"cumulative_deletesById\": 0,\n          \"cumulative_deletesByQuery\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java $\",\n        \"description\": \"Update handler that efficiently directly updates the on-disk main lucene index\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.update.DirectUpdateHandler2\"\n      }\n    },\n    \"CACHE\",\n    {\n      \"fieldCache\": {\n        \"stats\": {\n          \"insanity_count\": 0,\n          \"entries_count\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java $\",\n        \"description\": \"Provides introspection of the Lucene FieldCache, this is **NOT** a cache that is managed by Solr.\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrFieldCacheMBean\"\n      },\n      \"fieldValueCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 0,\n          \"cumulative_hitratio\": \"0.00\",\n          \"cumulative_hits\": 0,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=4096, initialSize=4096, minSize=3686, acceptableSize=3891, cleanupThread=false, autowarmCount=128, regenerator=org.apache.solr.search.SolrIndexSearcher$1@58c2e3e9)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"documentCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 0,\n          \"cumulative_hitratio\": \"0.00\",\n          \"cumulative_hits\": 0,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=32768, initialSize=32768, minSize=29491, acceptableSize=31129, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"queryResultCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 0,\n          \"cumulative_hitratio\": \"0.00\",\n          \"cumulative_hits\": 0,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=4096, initialSize=4096, minSize=3686, acceptableSize=3891, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"filterCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 0,\n          \"cumulative_hitratio\": \"0.00\",\n          \"cumulative_hits\": 0,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=512, initialSize=512, minSize=460, acceptableSize=486, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      }\n    }\n  ],\n  \"responseHeader\": {\n    \"QTime\": 5,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v4.3/expected.out",
    "content": "solr_admin,core=core1 deleted_docs=102815i,max_docs=7620303i,num_docs=7517488i,size_in_bytes=1784635686i 1690546461086689072\nsolr_admin,core=main deleted_docs=619275i,max_docs=169562700i,num_docs=168943425i,size_in_bytes=247497521642i 1690546461086689072\nsolr_cache,core=core1,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=core1,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=core1,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=core1,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=main,handler=documentCache cumulative_evictions=0i,cumulative_hitratio=0.99,cumulative_hits=2405834i,cumulative_inserts=5746i,cumulative_lookups=2411580i,evictions=0i,hitratio=0.99,hits=3733i,inserts=17i,lookups=3750i,size=17i,warmup_time=0i 1690546461086689072\nsolr_cache,core=main,handler=fieldValueCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=0i,cumulative_inserts=0i,cumulative_lookups=0i,evictions=0i,hitratio=0,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=main,handler=filterCache cumulative_evictions=0i,cumulative_hitratio=0,cumulative_hits=55i,cumulative_inserts=14i,cumulative_lookups=69i,evictions=0i,hitratio=0.01,hits=0i,inserts=0i,lookups=0i,size=0i,warmup_time=0i 1690546461086689072\nsolr_cache,core=main,handler=queryResultCache cumulative_evictions=0i,cumulative_hitratio=0.99,cumulative_hits=726607i,cumulative_inserts=2660i,cumulative_lookups=729510i,evictions=0i,hitratio=0.97,hits=1179i,inserts=27i,lookups=1206i,size=27i,warmup_time=0i 1690546461086689072\nsolr_core,core=core1,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i 1690546461086689072\nsolr_core,core=core1,handler=searcher deleted_docs=102815i,max_docs=7620303i,num_docs=7517488i 1690546461086689072\nsolr_core,core=main,handler=core deleted_docs=0i,max_docs=0i,num_docs=0i 1690546461086689072\nsolr_core,core=main,handler=searcher deleted_docs=685249i,max_docs=169647870i,num_docs=168962621i 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/file 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/logging 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/luke 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/mbeans 15min_rate_reqs_per_second=0.5414280756665533,5min_rate_reqs_per_second=0.545082835587804,75th_pc_request_time=4.68247075,95th_pc_request_time=5.586449799999999,999th_pc_request_time=127.79069480400044,99th_pc_request_time=9.033666420000003,avg_requests_per_second=0.09671315555928528,avg_time_per_request=1.5857040673599807,errors=0i,handler_start=1482259270585i,median_request_time=0.03985,requests=230969i,timeouts=0i,total_time=366246.89703 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/ping 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270461i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/plugins 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/properties 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/system 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/admin/threads 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270585i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/analysis/document 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/analysis/field 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270462i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270456i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.component.SearchHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270455i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.CSVRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270458i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.DumpRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270462i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.JsonUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270457i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.PingRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270461i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.RealTimeGetHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270456i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.ReplicationHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270463i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=org.apache.solr.handler.UpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270457i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270455i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/replication 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270463i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/select 15min_rate_reqs_per_second=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444659081257,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=0.518583,95th_pc_request_time=0.518583,999th_pc_request_time=0.518583,99th_pc_request_time=0.518583,avg_requests_per_second=0.0000004187296521163843,avg_time_per_request=0.518583,errors=1i,handler_start=1482259270455i,median_request_time=0.518583,requests=1i,timeouts=0i,total_time=0.518583 1690546461086689072\nsolr_queryhandler,core=core1,handler=/spell 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/tvrh 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/update 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270457i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/update/csv 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270458i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/update/extract 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=core1,handler=/update/json 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270457i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/file 15min_rate_reqs_per_second=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030856020161426622,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=0.38605350000000005,95th_pc_request_time=0.509739,999th_pc_request_time=0.509739,99th_pc_request_time=0.509739,avg_requests_per_second=0.0000020937536245042723,avg_time_per_request=0.2358606,errors=0i,handler_start=1482259271569i,median_request_time=0.184437,requests=5i,timeouts=0i,total_time=1.179303 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/logging 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259271569i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/luke 15min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001387107477978473,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=0.4085,95th_pc_request_time=0.4085,999th_pc_request_time=0.4085,99th_pc_request_time=0.4085,avg_requests_per_second=0.000001256252178648736,avg_time_per_request=0.3105803333333333,errors=0i,handler_start=1482259271568i,median_request_time=0.31491,requests=3i,timeouts=0i,total_time=0.931741 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/mbeans 15min_rate_reqs_per_second=0.5409225999558686,5min_rate_reqs_per_second=0.5543011916891444,75th_pc_request_time=7.423904,95th_pc_request_time=9.10313265,999th_pc_request_time=129.19901009200038,99th_pc_request_time=11.944256130000017,avg_requests_per_second=0.0967113175627352,avg_time_per_request=2.0964317122172575,errors=0i,handler_start=1482259271568i,median_request_time=0.046796000000000004,requests=230953i,timeouts=0i,total_time=484175.0968 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/ping 15min_rate_reqs_per_second=0.20000000000000234,5min_rate_reqs_per_second=0.2000000000000008,75th_pc_request_time=0.357574,95th_pc_request_time=0.4901222999999999,999th_pc_request_time=41.331967987,99th_pc_request_time=5.392157590000151,avg_requests_per_second=0.19975282659471533,avg_time_per_request=0.7749319095595372,errors=0i,handler_start=1482259270816i,median_request_time=0.3474125,requests=477021i,timeouts=0i,total_time=369658.79443 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/plugins 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259271568i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/properties 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259271568i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/system 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259271568i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/admin/threads 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259271568i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/analysis/document 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/analysis/field 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/debug/dump 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270816i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/get 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270810i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.component.SearchHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270810i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.CSVRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270814i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.DumpRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270816i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.JsonUpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270814i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.PingRequestHandler 15min_rate_reqs_per_second=0.20000000000000234,5min_rate_reqs_per_second=0.2000000000000008,75th_pc_request_time=0.357574,95th_pc_request_time=0.4901222999999999,999th_pc_request_time=41.331967987,99th_pc_request_time=5.392157590000151,avg_requests_per_second=0.19975282688134827,avg_time_per_request=0.7749319095595372,errors=0i,handler_start=1482259270816i,median_request_time=0.3474125,requests=477021i,timeouts=0i,total_time=369658.79443 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.RealTimeGetHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270810i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.ReplicationHandler 15min_rate_reqs_per_second=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043340312709959365,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=12.1924675,95th_pc_request_time=15.377019,999th_pc_request_time=15.377019,99th_pc_request_time=15.377019,avg_requests_per_second=0.0000020937529718964145,avg_time_per_request=9.9261886,errors=0i,handler_start=1482259270817i,median_request_time=8.547115,requests=5i,timeouts=0i,total_time=49.630943 1690546461086689072\nsolr_queryhandler,core=main,handler=org.apache.solr.handler.UpdateRequestHandler 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270811i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/query 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270810i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/replication 15min_rate_reqs_per_second=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043340312709959365,5min_rate_reqs_per_second=0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014821969375,75th_pc_request_time=12.1924675,95th_pc_request_time=15.377019,999th_pc_request_time=15.377019,99th_pc_request_time=15.377019,avg_requests_per_second=0.0000020937529681743243,avg_time_per_request=9.9261886,errors=0i,handler_start=1482259270817i,median_request_time=8.547115,requests=5i,timeouts=0i,total_time=49.630943 1690546461086689072\nsolr_queryhandler,core=main,handler=/select 15min_rate_reqs_per_second=0.3320899738059959,5min_rate_reqs_per_second=0.32614693588972216,75th_pc_request_time=0.12097,95th_pc_request_time=0.21192269999999988,999th_pc_request_time=145.3845197990004,99th_pc_request_time=1.404113640000005,avg_requests_per_second=0.3054827447483145,avg_time_per_request=3.0322834013981987,errors=0i,handler_start=1482259270810i,median_request_time=0.116272,requests=729510i,timeouts=9i,total_time=2212081.064154 1690546461086689072\nsolr_queryhandler,core=main,handler=/spell 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/terms 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/tvrh 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/update 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270811i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/update/csv 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270814i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/update/extract 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=0i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_queryhandler,core=main,handler=/update/json 15min_rate_reqs_per_second=0,5min_rate_reqs_per_second=0,75th_pc_request_time=0,95th_pc_request_time=0,999th_pc_request_time=0,99th_pc_request_time=0,avg_requests_per_second=0,avg_time_per_request=0,errors=0i,handler_start=1482259270814i,median_request_time=0,requests=0i,timeouts=0i,total_time=0 1690546461086689072\nsolr_updatehandler,core=core1,handler=updateHandler adds=0i,autocommit_max_docs=500i,autocommit_max_time=900i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i 1690546461086689072\nsolr_updatehandler,core=main,handler=updateHandler adds=0i,autocommit_max_docs=500i,autocommit_max_time=900i,autocommits=0i,commits=0i,cumulative_adds=0i,cumulative_deletes_by_id=0i,cumulative_deletes_by_query=0i,cumulative_errors=0i,deletes_by_id=0i,deletes_by_query=0i,docs_pending=0i,errors=0i,expunge_deletes=0i,optimizes=0i,rollbacks=0i,soft_autocommits=0i 1690546461086689072\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v4.3/main/admin/mbeans.json",
    "content": "{\n  \"solr-mbeans\": [\n    \"CORE\",\n    {\n      \"core\": {\n        \"stats\": {\n          \"aliases\": [\n            \"main\"\n          ],\n          \"indexDir\": \"/srv/solr/index.20161110090000012\",\n          \"refCount\": 2,\n          \"startTime\": \"2016-12-20T18:41:10.796Z\",\n          \"coreName\": \"main\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/SolrCore.java $\",\n        \"description\": \"SolrCore\",\n        \"version\": \"1.0\",\n        \"class\": \"main\"\n      },\n      \"searcher\": {\n        \"stats\": {\n          \"warmupTime\": 0,\n          \"registeredAt\": \"2017-01-17T09:00:03.303Z\",\n          \"openedAt\": \"2017-01-17T09:00:03.301Z\",\n          \"searcherName\": \"Searcher@62d3fac7 main\",\n          \"caching\": true,\n          \"numDocs\": 168962621,\n          \"maxDoc\": 169647870,\n          \"deletedDocs\": 685249,\n          \"reader\": \"StandardDirectoryReader(segments_jwq89:70709031:nrt _dp3n5(4.3.1):C168268689/592191 _dph0g(4.3.1):C311982/51776 _dpz3u(4.3.1):C589116/12754 _dpsbv(4.3.1):C262008/22358 _dq1e0(4.3.1):C104991/772 _dpy04(4.3.1):C24856/1389 _dq029(4.3.1):C42680/1406 _dq0rr(4.3.1):C5064/581 _dq13q(4.3.1):C4322/574 _dq165(4.3.1):C4679/364 _dq1kt(4.3.1):C8124/196 _dq1ta(4.3.1):C8138/152 _dq1x7(4.3.1):C3842/76 _dq212(4.3.1):C4934/111 _dq1wi(4.3.1):C778/145 _dq20q(4.3.1):C805/92 _dq20g(4.3.1):C1183/96 _dq21g(4.3.1):C257/58 _dq20y(4.3.1):C159/19 _dq213(4.3.1):C108/17 _dq218(4.3.1):C89/9 _dq21a(4.3.1):C213/20 _dq21d(4.3.1):C100/10 _dq21f(4.3.1):C214/16 _dq21j(4.3.1):C198/17 _dq21m(4.3.1):C112/2 _dq21n(4.3.1):C105/46 _dq21o(4.3.1):C124/2)\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\",\n          \"indexVersion\": 70709031\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"description\": \"index searcher\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\"\n      },\n      \"Searcher@62d3fac7 main\": {\n        \"stats\": {\n          \"warmupTime\": 0,\n          \"registeredAt\": \"2017-01-17T09:00:03.303Z\",\n          \"openedAt\": \"2017-01-17T09:00:03.301Z\",\n          \"searcherName\": \"Searcher@62d3fac7 main\",\n          \"caching\": true,\n          \"numDocs\": 168962621,\n          \"maxDoc\": 169647870,\n          \"deletedDocs\": 685249,\n          \"reader\": \"StandardDirectoryReader(segments_jwq89:70709031:nrt _dp3n5(4.3.1):C168268689/592191 _dph0g(4.3.1):C311982/51776 _dpz3u(4.3.1):C589116/12754 _dpsbv(4.3.1):C262008/22358 _dq1e0(4.3.1):C104991/772 _dpy04(4.3.1):C24856/1389 _dq029(4.3.1):C42680/1406 _dq0rr(4.3.1):C5064/581 _dq13q(4.3.1):C4322/574 _dq165(4.3.1):C4679/364 _dq1kt(4.3.1):C8124/196 _dq1ta(4.3.1):C8138/152 _dq1x7(4.3.1):C3842/76 _dq212(4.3.1):C4934/111 _dq1wi(4.3.1):C778/145 _dq20q(4.3.1):C805/92 _dq20g(4.3.1):C1183/96 _dq21g(4.3.1):C257/58 _dq20y(4.3.1):C159/19 _dq213(4.3.1):C108/17 _dq218(4.3.1):C89/9 _dq21a(4.3.1):C213/20 _dq21d(4.3.1):C100/10 _dq21f(4.3.1):C214/16 _dq21j(4.3.1):C198/17 _dq21m(4.3.1):C112/2 _dq21n(4.3.1):C105/46 _dq21o(4.3.1):C124/2)\",\n          \"readerDir\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\",\n          \"indexVersion\": 70709031\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java $\",\n        \"description\": \"index searcher\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrIndexSearcher\"\n      }\n    },\n    \"QUERYHANDLER\",\n    {\n      \"org.apache.solr.handler.CSVRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270814,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/CSVRequestHandler.java $\",\n        \"description\": \"Add/Update multiple documents with CSV formatted rows\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.CSVRequestHandler\"\n      },\n      \"/admin/\": {\n        \"stats\": null,\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\"\n      },\n      \"/admin/mbeans\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 129.19901009200038,\n          \"99thPcRequestTime\": 11.944256130000017,\n          \"95thPcRequestTime\": 9.10313265,\n          \"75thPcRequestTime\": 7.423904,\n          \"medianRequestTime\": 0.046796000000000004,\n          \"avgTimePerRequest\": 2.0964317122172575,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 230953,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 484175.0968,\n          \"avgRequestsPerSecond\": 0.0967113175627352,\n          \"5minRateReqsPerSecond\": 0.5543011916891444,\n          \"15minRateReqsPerSecond\": 0.5409225999558686\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java $\",\n        \"description\": \"Get Info (and statistics) for registered SolrInfoMBeans\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.SolrInfoMBeanHandler\"\n      },\n      \"/debug/dump\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270816,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"description\": \"Dump handler (debug)\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\"\n      },\n      \"/admin/logging\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259271569,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java $\",\n        \"description\": \"Logging Handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.LoggingHandler\"\n      },\n      \"/admin/plugins\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java $\",\n        \"description\": \"Registry\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.PluginInfoHandler\"\n      },\n      \"/admin/system\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java $\",\n        \"description\": \"Get System Info\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.SystemInfoHandler\"\n      },\n      \"/select\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 145.3845197990004,\n          \"99thPcRequestTime\": 1.404113640000005,\n          \"95thPcRequestTime\": 0.21192269999999988,\n          \"75thPcRequestTime\": 0.12097,\n          \"medianRequestTime\": 0.116272,\n          \"avgTimePerRequest\": 3.0322834013981987,\n          \"handlerStart\": 1482259270810,\n          \"requests\": 729510,\n          \"errors\": 0,\n          \"timeouts\": 9,\n          \"totalTime\": 2212081.064154,\n          \"avgRequestsPerSecond\": 0.3054827447483145,\n          \"5minRateReqsPerSecond\": 0.32614693588972216,\n          \"15minRateReqsPerSecond\": 0.3320899738059959\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,spellcheck,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/tvrh\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"org.apache.solr.handler.component.SearchHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270810,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/admin/luke\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0.4085,\n          \"99thPcRequestTime\": 0.4085,\n          \"95thPcRequestTime\": 0.4085,\n          \"75thPcRequestTime\": 0.4085,\n          \"medianRequestTime\": 0.31491,\n          \"avgTimePerRequest\": 0.3105803333333333,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 3,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0.931741,\n          \"avgRequestsPerSecond\": 1.256252178648736e-06,\n          \"5minRateReqsPerSecond\": 1.4821969375e-313,\n          \"15minRateReqsPerSecond\": 1.387107477978473e-152\n        },\n        \"docs\": [\n          \"http://wiki.apache.org/solr/LukeRequestHandler\"\n        ],\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java $\",\n        \"description\": \"Lucene Index Browser.  Inspired and modeled after Luke: http://www.getopt.org/luke/\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.LukeRequestHandler\"\n      },\n      \"/update/json\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270814,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"description\": \"Add documents with JSON\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.JsonUpdateRequestHandler\"\n      },\n      \"org.apache.solr.handler.admin.AdminHandlers\": {\n        \"stats\": null,\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java $\",\n        \"description\": \"Register Standard Admin Handlers\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.AdminHandlers\"\n      },\n      \"org.apache.solr.handler.ReplicationHandler\": {\n        \"stats\": {\n          \"lastCycleBytesDownloaded\": \"240149545\",\n          \"timesIndexReplicated\": \"2697\",\n          \"timesFailed\": \"1\",\n          \"replicationFailedAt\": \"Mon Jun 06 11:55:11 UTC 2016\",\n          \"indexReplicatedAt\": \"Tue Jan 17 09:00:03 UTC 2017\",\n          \"previousCycleTimeInSeconds\": \"3\",\n          \"isReplicating\": \"false\",\n          \"isPollingDisabled\": \"false\",\n          \"pollInterval\": \"03:00:00\",\n          \"masterUrl\": \"http://solr-s1:8983/solr/main\",\n          \"isSlave\": \"true\",\n          \"isMaster\": \"false\",\n          \"indexPath\": \"/srv/solr/index.20161110090000012\",\n          \"generation\": 33439689,\n          \"15minRateReqsPerSecond\": 4.3340312709959365e-152,\n          \"5minRateReqsPerSecond\": 1.4821969375e-313,\n          \"avgRequestsPerSecond\": 2.0937529718964145e-06,\n          \"totalTime\": 49.630943,\n          \"timeouts\": 0,\n          \"errors\": 0,\n          \"requests\": 5,\n          \"handlerStart\": 1482259270817,\n          \"avgTimePerRequest\": 9.9261886,\n          \"medianRequestTime\": 8.547115,\n          \"75thPcRequestTime\": 12.1924675,\n          \"95thPcRequestTime\": 15.377019,\n          \"99thPcRequestTime\": 15.377019,\n          \"999thPcRequestTime\": 15.377019,\n          \"indexSize\": \"229.77 GB\",\n          \"indexVersion\": 1484643564822\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java $\",\n        \"description\": \"ReplicationHandler provides replication of index and configuration files from Master to Slaves\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.ReplicationHandler\"\n      },\n      \"org.apache.solr.handler.JsonUpdateRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270814,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/JsonUpdateRequestHandler.java $\",\n        \"description\": \"Add documents with JSON\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.JsonUpdateRequestHandler\"\n      },\n      \"org.apache.solr.handler.DumpRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270816,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java $\",\n        \"description\": \"Dump handler (debug)\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.DumpRequestHandler\"\n      },\n      \"org.apache.solr.handler.RealTimeGetHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270810,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/RealTimeGetHandler.java $\",\n        \"description\": \"The realtime get handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.RealTimeGetHandler\"\n      },\n      \"/get\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270810,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/RealTimeGetHandler.java $\",\n        \"description\": \"The realtime get handler\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.RealTimeGetHandler\"\n      },\n      \"/admin/properties\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java $\",\n        \"description\": \"Get System Properties\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.PropertiesRequestHandler\"\n      },\n      \"/query\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270810,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java $\",\n        \"description\": \"Search using components: query,facet,mlt,highlight,stats,debug,\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.component.SearchHandler\"\n      },\n      \"/admin/threads\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259271568,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java $\",\n        \"description\": \"Thread Dump\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.ThreadDumpHandler\"\n      },\n      \"/analysis/field\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.FieldAnalysisRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.FieldAnalysisRequestHandler]\"\n      },\n      \"org.apache.solr.handler.PingRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 41.331967987,\n          \"99thPcRequestTime\": 5.392157590000151,\n          \"95thPcRequestTime\": 0.4901222999999999,\n          \"75thPcRequestTime\": 0.357574,\n          \"medianRequestTime\": 0.3474125,\n          \"avgTimePerRequest\": 0.7749319095595372,\n          \"handlerStart\": 1482259270816,\n          \"requests\": 477021,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 369658.79443,\n          \"avgRequestsPerSecond\": 0.19975282688134827,\n          \"5minRateReqsPerSecond\": 0.2000000000000008,\n          \"15minRateReqsPerSecond\": 0.20000000000000234\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\"\n      },\n      \"/analysis/document\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.DocumentAnalysisRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.DocumentAnalysisRequestHandler]\"\n      },\n      \"/spell\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"/update/csv\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270814,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/CSVRequestHandler.java $\",\n        \"description\": \"Add/Update multiple documents with CSV formatted rows\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.CSVRequestHandler\"\n      },\n      \"org.apache.solr.handler.UpdateRequestHandler\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270811,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandler.java $\",\n        \"description\": \"Add documents using XML (with XSLT), CSV, JSON, or javabin\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.UpdateRequestHandler\"\n      },\n      \"/replication\": {\n        \"stats\": {\n          \"lastCycleBytesDownloaded\": \"240149545\",\n          \"timesIndexReplicated\": \"2697\",\n          \"timesFailed\": \"1\",\n          \"replicationFailedAt\": \"Mon Jun 06 11:55:11 UTC 2016\",\n          \"indexReplicatedAt\": \"Tue Jan 17 09:00:03 UTC 2017\",\n          \"previousCycleTimeInSeconds\": \"3\",\n          \"isReplicating\": \"false\",\n          \"isPollingDisabled\": \"false\",\n          \"pollInterval\": \"03:00:00\",\n          \"masterUrl\": \"http://solr-s1:8983/solr/main\",\n          \"isSlave\": \"true\",\n          \"isMaster\": \"false\",\n          \"indexPath\": \"/srv/solr/index.20161110090000012\",\n          \"generation\": 33439689,\n          \"15minRateReqsPerSecond\": 4.3340312709959365e-152,\n          \"5minRateReqsPerSecond\": 1.4821969375e-313,\n          \"avgRequestsPerSecond\": 2.0937529681743243e-06,\n          \"totalTime\": 49.630943,\n          \"timeouts\": 0,\n          \"errors\": 0,\n          \"requests\": 5,\n          \"handlerStart\": 1482259270817,\n          \"avgTimePerRequest\": 9.9261886,\n          \"medianRequestTime\": 8.547115,\n          \"75thPcRequestTime\": 12.1924675,\n          \"95thPcRequestTime\": 15.377019,\n          \"99thPcRequestTime\": 15.377019,\n          \"999thPcRequestTime\": 15.377019,\n          \"indexSize\": \"229.77 GB\",\n          \"indexVersion\": 1484643564822\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java $\",\n        \"description\": \"ReplicationHandler provides replication of index and configuration files from Master to Slaves\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.ReplicationHandler\"\n      },\n      \"/admin/ping\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 41.331967987,\n          \"99thPcRequestTime\": 5.392157590000151,\n          \"95thPcRequestTime\": 0.4901222999999999,\n          \"75thPcRequestTime\": 0.357574,\n          \"medianRequestTime\": 0.3474125,\n          \"avgTimePerRequest\": 0.7749319095595372,\n          \"handlerStart\": 1482259270816,\n          \"requests\": 477021,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 369658.79443,\n          \"avgRequestsPerSecond\": 0.19975282659471533,\n          \"5minRateReqsPerSecond\": 0.2000000000000008,\n          \"15minRateReqsPerSecond\": 0.20000000000000234\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java $\",\n        \"description\": \"Reports application health to a load-balancer\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.PingRequestHandler\"\n      },\n      \"/update\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0,\n          \"99thPcRequestTime\": 0,\n          \"95thPcRequestTime\": 0,\n          \"75thPcRequestTime\": 0,\n          \"medianRequestTime\": 0,\n          \"avgTimePerRequest\": 0,\n          \"handlerStart\": 1482259270811,\n          \"requests\": 0,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 0,\n          \"avgRequestsPerSecond\": 0,\n          \"5minRateReqsPerSecond\": 0,\n          \"15minRateReqsPerSecond\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandler.java $\",\n        \"description\": \"Add documents using XML (with XSLT), CSV, JSON, or javabin\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.UpdateRequestHandler\"\n      },\n      \"/terms\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.SearchHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.SearchHandler]\"\n      },\n      \"/admin/file\": {\n        \"stats\": {\n          \"999thPcRequestTime\": 0.509739,\n          \"99thPcRequestTime\": 0.509739,\n          \"95thPcRequestTime\": 0.509739,\n          \"75thPcRequestTime\": 0.38605350000000005,\n          \"medianRequestTime\": 0.184437,\n          \"avgTimePerRequest\": 0.2358606,\n          \"handlerStart\": 1482259271569,\n          \"requests\": 5,\n          \"errors\": 0,\n          \"timeouts\": 0,\n          \"totalTime\": 1.179303,\n          \"avgRequestsPerSecond\": 2.0937536245042723e-06,\n          \"5minRateReqsPerSecond\": 1.4821969375e-313,\n          \"15minRateReqsPerSecond\": 3.0856020161426622e-152\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java $\",\n        \"description\": \"Admin Get File -- view config files directly\",\n        \"version\": \"4.3.1\",\n        \"class\": \"org.apache.solr.handler.admin.ShowFileRequestHandler\"\n      },\n      \"/update/extract\": {\n        \"stats\": {\n          \"note\": \"not initialized yet\"\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/core/RequestHandlers.java $\",\n        \"description\": \"Lazy[solr.extraction.ExtractingRequestHandler]\",\n        \"version\": null,\n        \"class\": \"Lazy[solr.extraction.ExtractingRequestHandler]\"\n      }\n    },\n    \"UPDATEHANDLER\",\n    {\n      \"updateHandler\": {\n        \"stats\": {\n          \"cumulative_errors\": 0,\n          \"expungeDeletes\": 0,\n          \"rollbacks\": 0,\n          \"optimizes\": 0,\n          \"soft autocommits\": 0,\n          \"autocommits\": 0,\n          \"autocommit maxTime\": \"900ms\",\n          \"autocommit maxDocs\": 500,\n          \"commits\": 0,\n          \"docsPending\": 0,\n          \"adds\": 0,\n          \"deletesById\": 0,\n          \"deletesByQuery\": 0,\n          \"errors\": 0,\n          \"cumulative_adds\": 0,\n          \"cumulative_deletesById\": 0,\n          \"cumulative_deletesByQuery\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java $\",\n        \"description\": \"Update handler that efficiently directly updates the on-disk main lucene index\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.update.DirectUpdateHandler2\"\n      }\n    },\n    \"CACHE\",\n    {\n      \"fieldCache\": {\n        \"stats\": {\n          \"insanity_count\": 0,\n          \"entries_count\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java $\",\n        \"description\": \"Provides introspection of the Lucene FieldCache, this is **NOT** a cache that is managed by Solr.\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.SolrFieldCacheMBean\"\n      },\n      \"fieldValueCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 0,\n          \"cumulative_hitratio\": \"0.00\",\n          \"cumulative_hits\": 0,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.00\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 0\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=5120, initialSize=5120, minSize=4608, acceptableSize=4864, cleanupThread=false, autowarmCount=1024, regenerator=org.apache.solr.search.SolrIndexSearcher$1@40acdd5)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"documentCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 5746,\n          \"cumulative_hitratio\": \"0.99\",\n          \"cumulative_hits\": 2405834,\n          \"lookups\": 3750,\n          \"hits\": 3733,\n          \"hitratio\": \"0.99\",\n          \"inserts\": 17,\n          \"evictions\": 0,\n          \"size\": 17,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 2411580\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=10240, initialSize=10240, minSize=9216, acceptableSize=9728, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"queryResultCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 2660,\n          \"cumulative_hitratio\": \"0.99\",\n          \"cumulative_hits\": 726607,\n          \"lookups\": 1206,\n          \"hits\": 1179,\n          \"hitratio\": \"0.97\",\n          \"inserts\": 27,\n          \"evictions\": 0,\n          \"size\": 27,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 729510\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=5120, initialSize=5120, minSize=4608, acceptableSize=4864, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      },\n      \"filterCache\": {\n        \"stats\": {\n          \"cumulative_evictions\": 0,\n          \"cumulative_inserts\": 14,\n          \"cumulative_hitratio\": 0,\n          \"cumulative_hits\": 55,\n          \"lookups\": 0,\n          \"hits\": 0,\n          \"hitratio\": \"0.01\",\n          \"inserts\": 0,\n          \"evictions\": 0,\n          \"size\": 0,\n          \"warmupTime\": 0,\n          \"cumulative_lookups\": 69\n        },\n        \"src\": \"$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_4_3/solr/core/src/java/org/apache/solr/search/FastLRUCache.java $\",\n        \"description\": \"Concurrent LRU Cache(maxSize=2560, initialSize=2560, minSize=2304, acceptableSize=2432, cleanupThread=false)\",\n        \"version\": \"1.0\",\n        \"class\": \"org.apache.solr.search.FastLRUCache\"\n      }\n    }\n  ],\n  \"responseHeader\": {\n    \"QTime\": 8,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v4.3/telegraf.conf",
    "content": "[[inputs.solr]]\n  servers = [\"http://localhost:8983\"]\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v7/admin/cores.json",
    "content": "{\n  \"status\": {\n    \"core1\": {\n      \"index\": {\n        \"size\": \"1.66 GB\",\n        \"sizeInBytes\": 1784635686,\n        \"lastModified\": \"2017-01-14T10:30:07.419Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484389807419\"\n        },\n        \"numDocs\": 7517488,\n        \"maxDoc\": 7620303,\n        \"deletedDocs\": 102815,\n        \"version\": 267485,\n        \"segmentCount\": 21,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr-core1/index.20160607000000124 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@646d42ce\"\n      },\n      \"name\": \"core1\",\n      \"isDefaultCore\": false,\n      \"instanceDir\": \"solr/core1/\",\n      \"dataDir\": \"/srv/solr-core1/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.449Z\",\n      \"uptime\": 2314746645\n    },\n    \"main\": {\n      \"index\": {\n        \"size\": \"230.5 GB\",\n        \"sizeInBytes\": 247497521642,\n        \"lastModified\": \"2017-01-16T11:59:18.189Z\",\n        \"userData\": {\n          \"commitTimeMSec\": \"1484567958189\"\n        },\n        \"numDocs\": 168943425,\n        \"maxDoc\": 169562700,\n        \"deletedDocs\": 619275,\n        \"version\": 70688464,\n        \"segmentCount\": 33,\n        \"current\": true,\n        \"hasDeletions\": true,\n        \"directory\": \"org.apache.lucene.store.MMapDirectory:org.apache.lucene.store.MMapDirectory@/srv/solr/index.20161110090000012 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@15088f05\"\n      },\n      \"name\": \"main\",\n      \"isDefaultCore\": true,\n      \"instanceDir\": \"solr/main/\",\n      \"dataDir\": \"/srv/solr/\",\n      \"config\": \"solrconfig.xml\",\n      \"schema\": \"schema.xml\",\n      \"startTime\": \"2016-12-20T18:41:10.796Z\",\n      \"uptime\": 2314746294\n    }\n  },\n  \"initFailures\": {},\n  \"defaultCoreName\": \"main\",\n  \"responseHeader\": {\n    \"QTime\": 13,\n    \"status\": 0\n  }\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v7/expected.out",
    "content": "solr_admin,core=core1 deleted_docs=102815i,max_docs=7620303i,num_docs=7517488i,size_in_bytes=1784635686i \nsolr_admin,core=main deleted_docs=619275i,max_docs=169562700i,num_docs=168943425i,size_in_bytes=247497521642i \nsolr_cache,core=main,handler=documentCache evictions=141485i,cumulative_evictions=141486i,cumulative_hitratio=0.42,cumulative_hits=115364i,cumulative_inserts=149768i,cumulative_lookups=265132i,hitratio=0.44,hits=1111i,inserts=987i,lookups=1234i,size=8192i,warmup_time=1i\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v7/main/admin/mbeans.json",
    "content": "{\n  \"responseHeader\": {\n    \"status\": 0,\n    \"QTime\": 2\n  },\n  \"solr-mbeans\": [\n    \"CORE\",\n    {\n    },\n    \"QUERYHANDLER\",\n    {\n    },\n    \"UPDATEHANDLER\",\n    {\n    },\n    \"CACHE\",\n    {\n      \"documentCache\": {\n        \"class\": \"org.apache.solr.search.LRUCache\",\n        \"description\": \"LRU Cache(maxSize=16384, initialSize=4096)\",\n        \"stats\": {\n          \"CACHE.searcher.documentCache.evictions\": 141485,\n          \"CACHE.searcher.documentCache.cumulative_lookups\": 265132,\n          \"CACHE.searcher.documentCache.hitratio\": 0.44,\n          \"CACHE.searcher.documentCache.size\": 8192,\n          \"CACHE.searcher.documentCache.cumulative_hitratio\": 0.42,\n          \"CACHE.searcher.documentCache.lookups\": 1234,\n          \"CACHE.searcher.documentCache.warmupTime\": 1,\n          \"CACHE.searcher.documentCache.inserts\": 987,\n          \"CACHE.searcher.documentCache.hits\": 1111,\n          \"CACHE.searcher.documentCache.cumulative_hits\": 115364,\n          \"CACHE.searcher.documentCache.cumulative_inserts\": 149768,\n          \"CACHE.searcher.documentCache.cumulative_evictions\": 141486\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "plugins/inputs/solr/testcases/v7/telegraf.conf",
    "content": "[[inputs.solr]]\n  servers = [\"http://localhost:8983\"]\n"
  },
  {
    "path": "plugins/inputs/solr/types.go",
    "content": "package solr\n\nimport \"encoding/json\"\n\n// adminCoresStatus is an exported type that contains a response with information about Solr cores.\ntype adminCoresStatus struct {\n\tStatus map[string]struct {\n\t\tIndex struct {\n\t\t\tSizeInBytes int64 `json:\"sizeInBytes\"`\n\t\t\tNumDocs     int64 `json:\"numDocs\"`\n\t\t\tMaxDoc      int64 `json:\"maxDoc\"`\n\t\t\tDeletedDocs int64 `json:\"deletedDocs\"`\n\t\t} `json:\"index\"`\n\t} `json:\"status\"`\n}\n\n// mBeansData is an exported type that contains a response from Solr with metrics\ntype mBeansData struct {\n\tHeaders    responseHeader    `json:\"responseHeader\"`\n\tSolrMbeans []json.RawMessage `json:\"solr-mbeans\"`\n}\n\n// responseHeader is an exported type that contains a response metrics: QTime and Status\ntype responseHeader struct {\n\tQTime  int64 `json:\"QTime\"`\n\tStatus int64 `json:\"status\"`\n}\n\n// core is an exported type that contains Core metrics\ntype core struct {\n\tStats struct {\n\t\tDeletedDocs int64 `json:\"deletedDocs\"`\n\t\tMaxDoc      int64 `json:\"maxDoc\"`\n\t\tNumDocs     int64 `json:\"numDocs\"`\n\t} `json:\"stats\"`\n}\n\n// queryHandler is an exported type that contains query handler metrics\ntype queryHandler struct {\n\tStats interface{} `json:\"stats\"`\n}\n\n// updateHandler is an exported type that contains update handler metrics\ntype updateHandler struct {\n\tStats struct {\n\t\tAdds                     int64  `json:\"adds\"`\n\t\tAutocommitMaxDocs        int64  `json:\"autocommit maxDocs\"`\n\t\tAutocommitMaxTime        string `json:\"autocommit maxTime\"`\n\t\tAutocommits              int64  `json:\"autocommits\"`\n\t\tCommits                  int64  `json:\"commits\"`\n\t\tCumulativeAdds           int64  `json:\"cumulative_adds\"`\n\t\tCumulativeDeletesByID    int64  `json:\"cumulative_deletesById\"`\n\t\tCumulativeDeletesByQuery int64  `json:\"cumulative_deletesByQuery\"`\n\t\tCumulativeErrors         int64  `json:\"cumulative_errors\"`\n\t\tDeletesByID              int64  `json:\"deletesById\"`\n\t\tDeletesByQuery           int64  `json:\"deletesByQuery\"`\n\t\tDocsPending              int64  `json:\"docsPending\"`\n\t\tErrors                   int64  `json:\"errors\"`\n\t\tExpungeDeletes           int64  `json:\"expungeDeletes\"`\n\t\tOptimizes                int64  `json:\"optimizes\"`\n\t\tRollbacks                int64  `json:\"rollbacks\"`\n\t\tSoftAutocommits          int64  `json:\"soft autocommits\"`\n\t} `json:\"stats\"`\n}\n\n// cache is an exported type that contains cache metrics\ntype cache struct {\n\tStats map[string]interface{} `json:\"stats\"`\n}\n"
  },
  {
    "path": "plugins/inputs/solr/util.go",
    "content": "package solr\n\nimport (\n\t\"math\"\n\n\t\"github.com/influxdata/telegraf/internal\"\n)\n\n// Get float64 from interface\nfunc getFloat(value interface{}) float64 {\n\tv, err := internal.ToFloat64(value)\n\tif err != nil || math.IsNaN(v) {\n\t\treturn 0\n\t}\n\treturn v\n}\n\n// Get int64 from interface\nfunc getInt(value interface{}) int64 {\n\tv, err := internal.ToInt64(value)\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn v\n}\n"
  },
  {
    "path": "plugins/inputs/sql/README.md",
    "content": "# SQL Input Plugin\n\nThis plugin reads metrics from performing [SQL][sql] queries against a SQL\nserver. Different server types are supported and their settings might differ\n(especially the connection parameters).  Please check the list of\n[supported SQL drivers][sql_drivers] for the `driver` name and options\nfor the data-source-name (`dsn`) options.\n\n⭐ Telegraf v1.19.0\n🏷️ datastore\n💻 all\n\n[sql]: https://www.iso.org/standard/76583.html\n[sql_drivers]: /docs/SQL_DRIVERS_INPUT.md\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `dsn` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from SQL queries\n[[inputs.sql]]\n  ## Database Driver\n  ## See https://github.com/influxdata/telegraf/blob/master/docs/SQL_DRIVERS_INPUT.md for\n  ## a list of supported drivers.\n  driver = \"mysql\"\n\n  ## Data source name for connecting\n  ## The syntax and supported options depends on selected driver.\n  dsn = \"username:password@tcp(mysqlserver:3307)/dbname?param=value\"\n\n  ## Timeout for any operation\n  ## Note that the timeout for queries is per query not per gather.\n  # timeout = \"5s\"\n\n  ## Connection time limits\n  ## By default the maximum idle time and maximum lifetime of a connection is unlimited.\n  ## Connections will not be closed automatically. If you specify a positive time, the connections will be closed after\n  ## idling or existing for at least that amount of time, respectively.\n  # connection_max_idle_time = \"0s\"\n  # connection_max_life_time = \"0s\"\n\n  ## Connection count limits\n  ## By default the number of open connections is not limited and the number of maximum idle connections\n  ## will be inferred from the number of queries specified. If you specify a positive number for any of the\n  ## two options, connections will be closed when reaching the specified limit. The number of idle connections\n  ## will be clipped to the maximum number of connections limit if any.\n  # connection_max_open = 0\n  # connection_max_idle = auto\n\n  ## Specifies plugin behavior regarding disconnected servers\n  ## Available choices :\n  ##   - error: telegraf will return an error on startup if one the servers is unreachable\n  ##   - ignore: telegraf will ignore unreachable servers on both startup and gather\n  # disconnected_servers_behavior = \"error\"\n\n  [[inputs.sql.query]]\n    ## Query to perform on the server\n    query=\"SELECT user,state,latency,score FROM Scoreboard WHERE application > 0\"\n    ## Alternatively to specifying the query directly you can select a file here containing the SQL query.\n    ## Only one of 'query' and 'query_script' can be specified!\n    # query_script = \"/path/to/sql/script.sql\"\n\n    ## Name of the measurement\n    ## In case both measurement and 'measurement_col' are given, the latter takes precedence.\n    # measurement = \"sql\"\n\n    ## Column name containing the name of the measurement\n    ## If given, this will take precedence over the 'measurement' setting. In case a query result\n    ## does not contain the specified column, we fall-back to the 'measurement' setting.\n    # measurement_column = \"\"\n\n    ## Column name containing the time of the measurement\n    ## If omitted, the time of the query will be used.\n    # time_column = \"\"\n\n    ## Format of the time contained in 'time_col'\n    ## The time must be 'unix', 'unix_ms', 'unix_us', 'unix_ns', or a golang time format.\n    ## See https://golang.org/pkg/time/#Time.Format for details.\n    # time_format = \"unix\"\n\n    ## Column names containing tags\n    ## An empty include list will reject all columns and an empty exclude list will not exclude any column.\n    ## I.e. by default no columns will be returned as tag and the tags are empty.\n    # tag_columns_include = []\n    # tag_columns_exclude = []\n\n    ## Column names containing fields (explicit types)\n    ## Convert the given columns to the corresponding type. Explicit type conversions take precedence over\n    ## the automatic (driver-based) conversion below.\n    ## NOTE: Columns should not be specified for multiple types or the resulting type is undefined.\n    # field_columns_float = []\n    # field_columns_int = []\n    # field_columns_uint = []\n    # field_columns_bool = []\n    # field_columns_string = []\n\n    ## Column names containing fields (automatic types)\n    ## An empty include list is equivalent to '[*]' and all returned columns will be accepted. An empty\n    ## exclude list will not exclude any column. I.e. by default all columns will be returned as fields.\n    ## NOTE: We rely on the database driver to perform automatic datatype conversion.\n    # field_columns_include = []\n    # field_columns_exclude = []\n```\n\n### Driver\n\nThe `driver` and `dsn` options specify how to connect to the database. As\nespecially the `dsn` format and values vary with the `driver` refer to the list\nof [supported SQL drivers](../../../docs/SQL_DRIVERS_INPUT.md) for possible\nvalues and more details.\n\n### Connection limits\n\nWith these options you can limit the number of connections kept open by this\nplugin. Details about the exact workings can be found in the [golang sql\ndocumentation](https://golang.org/pkg/database/sql/#DB.SetConnMaxIdleTime).\n\n### Query sections\n\nMultiple `query` sections can be specified for this plugin. Each specified query\nwill first be prepared on the server and then executed in every interval using\nthe column mappings specified. Please note that `tag` and `field` columns are\nnot exclusive (a column can be added to both). When using both `include` and\n`exclude` lists, the `exclude` list takes precedence over the `include`\nlist. For example, if you specify `foo` in both lists, `foo` will _never_ pass the\nfilter. In case any the columns specified in `measurement_col` or `time_col` are\n_not_ returned by the query, the plugin falls-back to the documented\ndefaults. Fields or tags specified in the includes of the options but missing in\nthe returned query are silently ignored.\n\n### Types\n\nThis plugin relies on the driver to do the type conversion. For the different\nproperties of the metric the following types are accepted.\n\n#### Measurement\n\nOnly columns of type `string`  are accepted.\n\n#### Time\n\nFor the metric time columns of type `time` are accepted directly. For numeric\ncolumns, `time_format` should be set to any of `unix`, `unix_ms`, `unix_ns` or\n`unix_us` accordingly. By default the a timestamp in `unix` format is\nexpected. For string columns, please specify the `time_format` accordingly.  See\nthe [golang time documentation](https://golang.org/pkg/time/#Time.Format) for\ndetails.\n\n#### Tags\n\nFor tags columns with textual values (`string` and `bytes`), signed and unsigned\nintegers (8, 16, 32 and 64 bit), floating-point (32 and 64 bit), `boolean` and\n`time` values are accepted. Those values will be converted to string.\n\n#### Fields\n\nFor fields columns with textual values (`string` and `bytes`), signed and\nunsigned integers (8, 16, 32 and 64 bit), floating-point (32 and 64 bit),\n`boolean` and `time` values are accepted. Here `bytes` will be converted to\n`string`, signed and unsigned integer values will be converted to `int64` or\n`uint64` respectively. Floating-point values are converted to `float64` and\n`time` is converted to a nanosecond timestamp of type `int64`.\n\n## Metrics\n\nThe format of metrics produced by this plugin depends on the content and data\nformat of the file.\n\n## Example Output\n\nUsing the [MariaDB sample database][maria-sample] and the configuration\n\n```toml\n[[inputs.sql]]\n  driver = \"mysql\"\n  dsn = \"root:password@/nation\"\n\n  [[inputs.sql.query]]\n    query=\"SELECT * FROM guests\"\n    measurement = \"nation\"\n    tag_columns_include = [\"name\"]\n    field_columns_exclude = [\"name\"]\n```\n\nTelegraf will output the following metrics\n\n```text\nnation,host=Hugin,name=John guest_id=1i 1611332164000000000\nnation,host=Hugin,name=Jane guest_id=2i 1611332164000000000\nnation,host=Hugin,name=Jean guest_id=3i 1611332164000000000\nnation,host=Hugin,name=Storm guest_id=4i 1611332164000000000\nnation,host=Hugin,name=Beast guest_id=5i 1611332164000000000\n```\n\n[maria-sample]: https://www.mariadbtutorial.com/getting-started/mariadb-sample-database\n"
  },
  {
    "path": "plugins/inputs/sql/drivers.go",
    "content": "package sql\n\nimport (\n\t// Blank imports to register the drivers\n\t_ \"github.com/ClickHouse/clickhouse-go/v2\"\n\t_ \"github.com/IBM/nzgo/v12\"\n\t_ \"github.com/SAP/go-hdb/driver\"\n\t_ \"github.com/apache/arrow-go/v18/arrow/flight/flightsql/driver\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t_ \"github.com/jackc/pgx/v4/stdlib\"\n\t_ \"github.com/microsoft/go-mssqldb\"\n\t_ \"github.com/sijms/go-ora/v2\"\n\t_ \"github.com/vertica/vertica-sql-go\"\n)\n"
  },
  {
    "path": "plugins/inputs/sql/drivers_sqlite.go",
    "content": "//go:build !mips && !mipsle && !mips64 && !ppc64 && !riscv64 && !loong64 && !mips64le && !(windows && (386 || arm)) && !(freebsd && (386 || arm))\n\npackage sql\n\nimport (\n\t// Blank imports to register the sqlite driver\n\t_ \"modernc.org/sqlite\"\n)\n"
  },
  {
    "path": "plugins/inputs/sql/sql.go",
    "content": "//go:generate ../../../tools/readme_config_includer/generator\npackage sql\n\nimport (\n\t\"context\"\n\tdbsql \"database/sql\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/filter\"\n\t\"github.com/influxdata/telegraf/internal\"\n\t\"github.com/influxdata/telegraf/internal/choice\"\n\t\"github.com/influxdata/telegraf/plugins/inputs\"\n)\n\n//go:embed sample.conf\nvar sampleConfig string\n\nvar disconnectedServersBehavior = []string{\"error\", \"ignore\"}\n\nconst magicIdleCount = -int(^uint(0) >> 1)\n\ntype SQL struct {\n\tDriver                      string          `toml:\"driver\"`\n\tDsn                         config.Secret   `toml:\"dsn\"`\n\tTimeout                     config.Duration `toml:\"timeout\"`\n\tMaxIdleTime                 config.Duration `toml:\"connection_max_idle_time\"`\n\tMaxLifetime                 config.Duration `toml:\"connection_max_life_time\"`\n\tMaxOpenConnections          int             `toml:\"connection_max_open\"`\n\tMaxIdleConnections          int             `toml:\"connection_max_idle\"`\n\tQueries                     []query         `toml:\"query\"`\n\tLog                         telegraf.Logger `toml:\"-\"`\n\tDisconnectedServersBehavior string          `toml:\"disconnected_servers_behavior\"`\n\n\tdriverName      string\n\tdb              *dbsql.DB\n\tserverConnected bool\n}\n\ntype query struct {\n\tQuery               string   `toml:\"query\"`\n\tScript              string   `toml:\"query_script\"`\n\tMeasurement         string   `toml:\"measurement\"`\n\tMeasurementColumn   string   `toml:\"measurement_column\"`\n\tTimeColumn          string   `toml:\"time_column\"`\n\tTimeFormat          string   `toml:\"time_format\"`\n\tTagColumnsInclude   []string `toml:\"tag_columns_include\"`\n\tTagColumnsExclude   []string `toml:\"tag_columns_exclude\"`\n\tFieldColumnsInclude []string `toml:\"field_columns_include\"`\n\tFieldColumnsExclude []string `toml:\"field_columns_exclude\"`\n\tFieldColumnsFloat   []string `toml:\"field_columns_float\"`\n\tFieldColumnsInt     []string `toml:\"field_columns_int\"`\n\tFieldColumnsUint    []string `toml:\"field_columns_uint\"`\n\tFieldColumnsBool    []string `toml:\"field_columns_bool\"`\n\tFieldColumnsString  []string `toml:\"field_columns_string\"`\n\n\tstatement         *dbsql.Stmt\n\ttagFilter         filter.Filter\n\tfieldFilter       filter.Filter\n\tfieldFilterFloat  filter.Filter\n\tfieldFilterInt    filter.Filter\n\tfieldFilterUint   filter.Filter\n\tfieldFilterBool   filter.Filter\n\tfieldFilterString filter.Filter\n}\n\nfunc (*SQL) SampleConfig() string {\n\treturn sampleConfig\n}\n\nfunc (s *SQL) Init() error {\n\t// Option handling\n\tif s.Driver == \"\" {\n\t\treturn errors.New(\"missing SQL driver option\")\n\t}\n\n\tif err := s.checkDSN(); err != nil {\n\t\treturn err\n\t}\n\n\tif s.Timeout <= 0 {\n\t\ts.Timeout = config.Duration(5 * time.Second)\n\t}\n\n\tif s.MaxIdleConnections == magicIdleCount {\n\t\t// Determine the number by the number of queries + the golang default value\n\t\ts.MaxIdleConnections = len(s.Queries) + 2\n\t}\n\n\tfor i, q := range s.Queries {\n\t\tif q.Query == \"\" && q.Script == \"\" {\n\t\t\treturn errors.New(\"neither 'query' nor 'query_script' specified\")\n\t\t}\n\n\t\tif q.Query != \"\" && q.Script != \"\" {\n\t\t\treturn errors.New(\"only one of 'query' and 'query_script' can be specified\")\n\t\t}\n\n\t\t// In case we got a script, we should read the query now.\n\t\tif q.Script != \"\" {\n\t\t\tquery, err := os.ReadFile(q.Script)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"reading script %q failed: %w\", q.Script, err)\n\t\t\t}\n\t\t\ts.Queries[i].Query = string(query)\n\t\t}\n\n\t\t// Time format\n\t\tif q.TimeFormat == \"\" {\n\t\t\ts.Queries[i].TimeFormat = \"unix\"\n\t\t}\n\n\t\t// Compile the tag-filter\n\t\ttagfilter, err := filter.NewIncludeExcludeFilterDefaults(q.TagColumnsInclude, q.TagColumnsExclude, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating tag filter failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].tagFilter = tagfilter\n\n\t\t// Compile the explicit type field-filter\n\t\tfieldfilterFloat, err := filter.NewIncludeExcludeFilterDefaults(q.FieldColumnsFloat, nil, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter for float failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilterFloat = fieldfilterFloat\n\n\t\tfieldfilterInt, err := filter.NewIncludeExcludeFilterDefaults(q.FieldColumnsInt, nil, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter for int failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilterInt = fieldfilterInt\n\n\t\tfieldfilterUint, err := filter.NewIncludeExcludeFilterDefaults(q.FieldColumnsUint, nil, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter for uint failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilterUint = fieldfilterUint\n\n\t\tfieldfilterBool, err := filter.NewIncludeExcludeFilterDefaults(q.FieldColumnsBool, nil, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter for bool failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilterBool = fieldfilterBool\n\n\t\tfieldfilterString, err := filter.NewIncludeExcludeFilterDefaults(q.FieldColumnsString, nil, false, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter for string failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilterString = fieldfilterString\n\n\t\t// Compile the field-filter\n\t\tfieldfilter, err := filter.NewIncludeExcludeFilter(q.FieldColumnsInclude, q.FieldColumnsExclude)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating field filter failed: %w\", err)\n\t\t}\n\t\ts.Queries[i].fieldFilter = fieldfilter\n\n\t\tif q.Measurement == \"\" {\n\t\t\ts.Queries[i].Measurement = \"sql\"\n\t\t}\n\t}\n\n\t// Derive the sql-framework driver name from our config name. This abstracts the actual driver\n\t// from the database-type the user wants.\n\taliases := map[string]string{\n\t\t\"cockroach\": \"pgx\",\n\t\t\"tidb\":      \"mysql\",\n\t\t\"mssql\":     \"sqlserver\",\n\t\t\"maria\":     \"mysql\",\n\t\t\"postgres\":  \"pgx\",\n\t\t\"oracle\":    \"oracle\",\n\t}\n\ts.driverName = s.Driver\n\tif driver, ok := aliases[s.Driver]; ok {\n\t\ts.driverName = driver\n\t}\n\n\tavailDrivers := dbsql.Drivers()\n\tif !choice.Contains(s.driverName, availDrivers) {\n\t\tfor d, r := range aliases {\n\t\t\tif choice.Contains(r, availDrivers) {\n\t\t\t\tavailDrivers = append(availDrivers, d)\n\t\t\t}\n\t\t}\n\n\t\t// Sort the list of drivers and make them unique\n\t\tsort.Strings(availDrivers)\n\t\tlast := 0\n\t\tfor _, d := range availDrivers {\n\t\t\tif d != availDrivers[last] {\n\t\t\t\tlast++\n\t\t\t\tavailDrivers[last] = d\n\t\t\t}\n\t\t}\n\t\tavailDrivers = availDrivers[:last+1]\n\n\t\treturn fmt.Errorf(\"driver %q not supported use one of %v\", s.Driver, availDrivers)\n\t}\n\n\tif s.DisconnectedServersBehavior == \"\" {\n\t\ts.DisconnectedServersBehavior = \"error\"\n\t}\n\n\tif !choice.Contains(s.DisconnectedServersBehavior, disconnectedServersBehavior) {\n\t\treturn fmt.Errorf(\"%q is not a valid value for disconnected_servers_behavior\", s.DisconnectedServersBehavior)\n\t}\n\n\treturn nil\n}\n\nfunc (s *SQL) Start(telegraf.Accumulator) error {\n\tif err := s.setupConnection(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.ping(); err != nil {\n\t\tif s.DisconnectedServersBehavior == \"error\" {\n\t\t\treturn err\n\t\t}\n\t\ts.Log.Errorf(\"unable to connect to database: %s\", err)\n\t}\n\tif s.serverConnected {\n\t\ts.prepareStatements()\n\t}\n\n\treturn nil\n}\n\nfunc (s *SQL) Gather(acc telegraf.Accumulator) error {\n\t// during plugin startup, it is possible that the server was not reachable.\n\t// we try pinging the server in this collection cycle.\n\t// we are only concerned with `prepareStatements` function to complete(return true), just once.\n\tif !s.serverConnected {\n\t\tif err := s.ping(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.prepareStatements()\n\t}\n\n\tvar wg sync.WaitGroup\n\ttstart := time.Now()\n\tfor _, q := range s.Queries {\n\t\twg.Add(1)\n\t\tgo func(q query) {\n\t\t\tdefer wg.Done()\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.Timeout))\n\t\t\tdefer cancel()\n\t\t\tif err := s.executeQuery(ctx, acc, q, tstart); err != nil {\n\t\t\t\tacc.AddError(err)\n\t\t\t}\n\t\t}(q)\n\t}\n\twg.Wait()\n\ts.Log.Debugf(\"Executed %d queries in %s\", len(s.Queries), time.Since(tstart).String())\n\n\treturn nil\n}\n\nfunc (s *SQL) Stop() {\n\t// Free the statements\n\tfor _, q := range s.Queries {\n\t\tif q.statement != nil {\n\t\t\tif err := q.statement.Close(); err != nil {\n\t\t\t\ts.Log.Errorf(\"closing statement for query %q failed: %v\", q.Query, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Close the connection to the server\n\tif s.db != nil {\n\t\tif err := s.db.Close(); err != nil {\n\t\t\ts.Log.Errorf(\"closing database connection failed: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (s *SQL) setupConnection() error {\n\t// Connect to the database server\n\tdsnSecret, err := s.Dsn.Get()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting DSN failed: %w\", err)\n\t}\n\tdsn := dsnSecret.String()\n\tdsnSecret.Destroy()\n\n\ts.Log.Debug(\"Connecting...\")\n\ts.db, err = dbsql.Open(s.driverName, dsn)\n\tif err != nil {\n\t\t// should return since the error is most likely with invalid DSN string format\n\t\treturn err\n\t}\n\n\t// Set the connection limits\n\t// s.db.SetConnMaxIdleTime(time.Duration(s.MaxIdleTime)) // Requires go >= 1.15\n\ts.db.SetConnMaxLifetime(time.Duration(s.MaxLifetime))\n\ts.db.SetMaxOpenConns(s.MaxOpenConnections)\n\ts.db.SetMaxIdleConns(s.MaxIdleConnections)\n\treturn nil\n}\n\nfunc (s *SQL) ping() error {\n\t// Test if the connection can be established\n\ts.Log.Debug(\"Testing connectivity...\")\n\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.Timeout))\n\terr := s.db.PingContext(ctx)\n\tcancel()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to connect to database: %w\", err)\n\t}\n\ts.serverConnected = true\n\treturn nil\n}\n\nfunc (s *SQL) prepareStatements() {\n\t// Prepare the statements\n\tfor i, q := range s.Queries {\n\t\ts.Log.Debugf(\"Preparing statement %q...\", q.Query)\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.Timeout))\n\t\tstmt, err := s.db.PrepareContext(ctx, q.Query)\n\t\tcancel()\n\t\tif err != nil {\n\t\t\t// Some database drivers or databases do not support prepare\n\t\t\t// statements and report an error here. However, we can still\n\t\t\t// execute unprepared queries for those setups so do not bail-out\n\t\t\t// here but simply do leave the `statement` with a `nil` value\n\t\t\t// indicating no prepared statement.\n\t\t\ts.Log.Warnf(\"preparing query %q failed: %s; falling back to unprepared query\", q.Query, err)\n\t\t\tcontinue\n\t\t}\n\t\ts.Queries[i].statement = stmt\n\t}\n}\n\nfunc (s *SQL) executeQuery(ctx context.Context, acc telegraf.Accumulator, q query, tquery time.Time) error {\n\t// Execute the query either prepared or unprepared\n\tvar rows *dbsql.Rows\n\tif q.statement != nil {\n\t\t// Use the previously prepared query\n\t\tvar err error\n\t\trows, err = q.statement.QueryContext(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// Fallback to unprepared query\n\t\tvar err error\n\t\trows, err = s.db.Query(q.Query)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tdefer rows.Close()\n\n\t// Handle the rows\n\tcolumnNames, err := rows.Columns()\n\tif err != nil {\n\t\treturn err\n\t}\n\trowCount, err := q.parse(acc, rows, tquery, s.Log)\n\ts.Log.Debugf(\"Received %d rows and %d columns for query %q\", rowCount, len(columnNames), q.Query)\n\n\treturn err\n}\n\nfunc (s *SQL) checkDSN() error {\n\tif s.Dsn.Empty() {\n\t\treturn errors.New(\"missing data source name (DSN) option\")\n\t}\n\treturn nil\n}\n\nfunc (q *query) parse(acc telegraf.Accumulator, rows *dbsql.Rows, t time.Time, logger telegraf.Logger) (int, error) {\n\tcolumnNames, err := rows.Columns()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// Prepare the list of datapoints according to the received row\n\tcolumnData := make([]interface{}, len(columnNames))\n\tcolumnDataPtr := make([]interface{}, len(columnNames))\n\n\tfor i := range columnData {\n\t\tcolumnDataPtr[i] = &columnData[i]\n\t}\n\n\trowCount := 0\n\tfor rows.Next() {\n\t\tmeasurement := q.Measurement\n\t\ttimestamp := t\n\t\ttags := make(map[string]string)\n\t\tfields := make(map[string]interface{}, len(columnNames))\n\n\t\t// Do the parsing with (hopefully) automatic type conversion\n\t\tif err := rows.Scan(columnDataPtr...); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tfor i, name := range columnNames {\n\t\t\tif q.MeasurementColumn != \"\" && name == q.MeasurementColumn {\n\t\t\t\tswitch raw := columnData[i].(type) {\n\t\t\t\tcase string:\n\t\t\t\t\tmeasurement = raw\n\t\t\t\tcase []byte:\n\t\t\t\t\tmeasurement = string(raw)\n\t\t\t\tdefault:\n\t\t\t\t\treturn 0, fmt.Errorf(\"measurement column type \\\"%T\\\" unsupported\", columnData[i])\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif q.TimeColumn != \"\" && name == q.TimeColumn {\n\t\t\t\tvar fieldvalue interface{}\n\t\t\t\tvar skipParsing bool\n\n\t\t\t\tswitch v := columnData[i].(type) {\n\t\t\t\tcase string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:\n\t\t\t\t\tfieldvalue = v\n\t\t\t\tcase []byte:\n\t\t\t\t\tfieldvalue = string(v)\n\t\t\t\tcase time.Time:\n\t\t\t\t\ttimestamp = v\n\t\t\t\t\tskipParsing = true\n\t\t\t\tcase fmt.Stringer:\n\t\t\t\t\tfieldvalue = v.String()\n\t\t\t\tdefault:\n\t\t\t\t\treturn 0, fmt.Errorf(\"time column %q of type \\\"%T\\\" unsupported\", name, columnData[i])\n\t\t\t\t}\n\t\t\t\tif !skipParsing {\n\t\t\t\t\tif timestamp, err = internal.ParseTimestamp(q.TimeFormat, fieldvalue, nil); err != nil {\n\t\t\t\t\t\treturn 0, fmt.Errorf(\"parsing time failed: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif q.tagFilter.Match(name) {\n\t\t\t\ttagvalue, err := internal.ToString(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, fmt.Errorf(\"converting tag column %q failed: %w\", name, err)\n\t\t\t\t}\n\t\t\t\tif v := strings.TrimSpace(tagvalue); v != \"\" {\n\t\t\t\t\ttags[name] = v\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Explicit type conversions take precedence\n\t\t\tif q.fieldFilterFloat.Match(name) {\n\t\t\t\tv, err := internal.ToFloat64(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, fmt.Errorf(\"converting field column %q to float failed: %w\", name, err)\n\t\t\t\t}\n\t\t\t\tfields[name] = v\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif q.fieldFilterInt.Match(name) {\n\t\t\t\tv, err := internal.ToInt64(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\tif !errors.Is(err, internal.ErrOutOfRange) {\n\t\t\t\t\t\treturn 0, fmt.Errorf(\"converting field column %q to int failed: %w\", name, err)\n\t\t\t\t\t}\n\t\t\t\t\tlogger.Warnf(\"field column %q: %v\", name, err)\n\t\t\t\t}\n\t\t\t\tfields[name] = v\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif q.fieldFilterUint.Match(name) {\n\t\t\t\tv, err := internal.ToUint64(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\tif !errors.Is(err, internal.ErrOutOfRange) {\n\t\t\t\t\t\treturn 0, fmt.Errorf(\"converting field column %q to uint failed: %w\", name, err)\n\t\t\t\t\t}\n\t\t\t\t\tlogger.Warnf(\"field column %q: %v\", name, err)\n\t\t\t\t}\n\t\t\t\tfields[name] = v\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif q.fieldFilterBool.Match(name) {\n\t\t\t\tv, err := internal.ToBool(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, fmt.Errorf(\"converting field column %q to bool failed: %w\", name, err)\n\t\t\t\t}\n\t\t\t\tfields[name] = v\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif q.fieldFilterString.Match(name) {\n\t\t\t\tv, err := internal.ToString(columnData[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, fmt.Errorf(\"converting field column %q to string failed: %w\", name, err)\n\t\t\t\t}\n\t\t\t\tfields[name] = v\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Try automatic conversion for all remaining fields\n\t\t\tif q.fieldFilter.Match(name) {\n\t\t\t\tvar fieldvalue interface{}\n\t\t\t\tswitch v := columnData[i].(type) {\n\t\t\t\tcase string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:\n\t\t\t\t\tfieldvalue = v\n\t\t\t\tcase []byte:\n\t\t\t\t\tfieldvalue = string(v)\n\t\t\t\tcase time.Time:\n\t\t\t\t\tfieldvalue = v.UnixNano()\n\t\t\t\tcase nil:\n\t\t\t\t\tfieldvalue = nil\n\t\t\t\tcase fmt.Stringer:\n\t\t\t\t\tfieldvalue = v.String()\n\t\t\t\tdefault:\n\t\t\t\t\treturn 0, fmt.Errorf(\"field column %q of type \\\"%T\\\" unsupported\", name, columnData[i])\n\t\t\t\t}\n\t\t\t\tif fieldvalue != nil {\n\t\t\t\t\tfields[name] = fieldvalue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tacc.AddFields(measurement, fields, tags, timestamp)\n\t\trowCount++\n\t}\n\n\tif err := rows.Err(); err != nil {\n\t\treturn rowCount, err\n\t}\n\n\treturn rowCount, nil\n}\n\nfunc init() {\n\tinputs.Add(\"sql\", func() telegraf.Input {\n\t\treturn &SQL{\n\t\t\tMaxIdleTime:        config.Duration(0), // unlimited\n\t\t\tMaxLifetime:        config.Duration(0), // unlimited\n\t\t\tMaxOpenConnections: 0,                  // unlimited\n\t\t\tMaxIdleConnections: magicIdleCount,     // will trigger auto calculation\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "plugins/inputs/sql/sql_test.go",
    "content": "package sql\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/docker/go-connections/nat\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/testcontainers/testcontainers-go/wait\"\n\n\t\"github.com/influxdata/telegraf\"\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestMariaDBIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tlogger := testutil.Logger{}\n\n\tport := \"3306\"\n\tpassword := testutil.GetRandomString(32)\n\tdatabase := \"foo\"\n\n\t// Determine the test-data mountpoint\n\ttestdata, err := filepath.Abs(\"testdata/mariadb/expected.sql\")\n\trequire.NoError(t, err, \"determining absolute path of test-data failed\")\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"mariadb\",\n\t\tExposedPorts: []string{port},\n\t\tEnv: map[string]string{\n\t\t\t\"MYSQL_ROOT_PASSWORD\": password,\n\t\t\t\"MYSQL_DATABASE\":      database,\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/docker-entrypoint-initdb.d/expected.sql\": testdata,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"mariadbd: ready for connections.\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(port)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Define the testset\n\tvar testset = []struct {\n\t\tname     string\n\t\tqueries  []query\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"metric_one\",\n\t\t\tqueries: []query{\n\t\t\t\t{\n\t\t\t\t\tQuery:               \"SELECT * FROM metric_one\",\n\t\t\t\t\tTagColumnsInclude:   []string{\"tag_*\"},\n\t\t\t\t\tFieldColumnsExclude: []string{\"tag_*\", \"timestamp\"},\n\t\t\t\t\tTimeColumn:          \"timestamp\",\n\t\t\t\t\tTimeFormat:          \"2006-01-02 15:04:05\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"sql\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"tag_one\": \"tag1\",\n\t\t\t\t\t\t\"tag_two\": \"tag2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"int64_one\": int64(1234),\n\t\t\t\t\t\t\"int64_two\": int64(2345),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2021, 5, 17, 22, 4, 45, 0, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range testset {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin-under-test\n\t\t\tdsn := fmt.Sprintf(\"root:%s@tcp(%s:%s)/%s\", password, container.Address, container.Ports[port], database)\n\t\t\tsecret := config.NewSecret([]byte(dsn))\n\t\t\tplugin := &SQL{\n\t\t\t\tDriver:  \"maria\",\n\t\t\t\tDsn:     secret,\n\t\t\t\tQueries: tt.queries,\n\t\t\t\tLog:     logger,\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\t// Startup the plugin\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\n\t\t\t// Gather\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\t// Stopping the plugin\n\t\t\tplugin.Stop()\n\n\t\t\t// Do the comparison\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc TestPostgreSQLIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tlogger := testutil.Logger{}\n\n\tport := \"5432\"\n\tpassword := testutil.GetRandomString(32)\n\tdatabase := \"foo\"\n\n\t// Determine the test-data mountpoint\n\ttestdata, err := filepath.Abs(\"testdata/postgres/expected.sql\")\n\trequire.NoError(t, err, \"determining absolute path of test-data failed\")\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"postgres\",\n\t\tExposedPorts: []string{port},\n\t\tEnv: map[string]string{\n\t\t\t\"POSTGRES_PASSWORD\": password,\n\t\t\t\"POSTGRES_DB\":       database,\n\t\t},\n\t\tFiles: map[string]string{\n\t\t\t\"/docker-entrypoint-initdb.d/expected.sql\": testdata,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.ForLog(\"database system is ready to accept connections\").WithOccurrence(2),\n\t\t\twait.ForListeningPort(nat.Port(port)),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Define the testset\n\tvar testset = []struct {\n\t\tname     string\n\t\tqueries  []query\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"metric_one\",\n\t\t\tqueries: []query{\n\t\t\t\t{\n\t\t\t\t\tQuery:               \"SELECT * FROM metric_one\",\n\t\t\t\t\tTagColumnsInclude:   []string{\"tag_*\"},\n\t\t\t\t\tFieldColumnsExclude: []string{\"tag_*\", \"timestamp\"},\n\t\t\t\t\tTimeColumn:          \"timestamp\",\n\t\t\t\t\tTimeFormat:          \"2006-01-02 15:04:05\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"sql\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"tag_one\": \"tag1\",\n\t\t\t\t\t\t\"tag_two\": \"tag2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"int64_one\": int64(1234),\n\t\t\t\t\t\t\"int64_two\": int64(2345),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Date(2021, 5, 17, 22, 4, 45, 0, time.UTC),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range testset {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin-under-test\n\t\t\tdsn := fmt.Sprintf(\"postgres://postgres:%s@%s:%s/%s\", password, container.Address, container.Ports[port], database)\n\t\t\tsecret := config.NewSecret([]byte(dsn))\n\t\t\tplugin := &SQL{\n\t\t\t\tDriver:  \"pgx\",\n\t\t\t\tDsn:     secret,\n\t\t\t\tQueries: tt.queries,\n\t\t\t\tLog:     logger,\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\t// Startup the plugin\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\n\t\t\t// Gather\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\t// Stopping the plugin\n\t\t\tplugin.Stop()\n\n\t\t\t// Do the comparison\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n\nfunc TestClickHouseIntegration(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tlogger := testutil.Logger{}\n\n\tport := \"9000\"\n\tuser := \"default\"\n\n\t// Determine the test-data mountpoint\n\ttestdata, err := filepath.Abs(\"testdata/clickhouse/expected.sql\")\n\trequire.NoError(t, err, \"determining absolute path of test-data failed\")\n\n\tcontainer := testutil.Container{\n\t\tImage:        \"yandex/clickhouse-server\",\n\t\tExposedPorts: []string{port, \"8123\"},\n\t\tFiles: map[string]string{\n\t\t\t\"/docker-entrypoint-initdb.d/expected.sql\": testdata,\n\t\t},\n\t\tWaitingFor: wait.ForAll(\n\t\t\twait.NewHTTPStrategy(\"/\").WithPort(nat.Port(\"8123\")),\n\t\t\twait.ForListeningPort(nat.Port(port)),\n\t\t\twait.ForLog(\"Saved preprocessed configuration to '/var/lib/clickhouse/preprocessed_configs/users.xml'.\").WithOccurrence(2),\n\t\t),\n\t}\n\trequire.NoError(t, container.Start(), \"failed to start container\")\n\tdefer container.Terminate()\n\n\t// Define the testset\n\tvar testset = []struct {\n\t\tname     string\n\t\tqueries  []query\n\t\texpected []telegraf.Metric\n\t}{\n\t\t{\n\t\t\tname: \"metric_one\",\n\t\t\tqueries: []query{\n\t\t\t\t{\n\t\t\t\t\tQuery:               \"SELECT * FROM default.metric_one\",\n\t\t\t\t\tTagColumnsInclude:   []string{\"tag_*\"},\n\t\t\t\t\tFieldColumnsExclude: []string{\"tag_*\", \"timestamp\"},\n\t\t\t\t\tTimeColumn:          \"timestamp\",\n\t\t\t\t\tTimeFormat:          \"unix\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []telegraf.Metric{\n\t\t\t\ttestutil.MustMetric(\n\t\t\t\t\t\"sql\",\n\t\t\t\t\tmap[string]string{\n\t\t\t\t\t\t\"tag_one\": \"tag1\",\n\t\t\t\t\t\t\"tag_two\": \"tag2\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]interface{}{\n\t\t\t\t\t\t\"int64_one\": int64(1234),\n\t\t\t\t\t\t\"int64_two\": int64(2345),\n\t\t\t\t\t},\n\t\t\t\t\ttime.Unix(1621289085, 0),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range testset {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Setup the plugin-under-test\n\t\t\tdsn := fmt.Sprintf(\"tcp://%s:%s?username=%s\", container.Address, container.Ports[port], user)\n\t\t\tsecret := config.NewSecret([]byte(dsn))\n\t\t\tplugin := &SQL{\n\t\t\t\tDriver:  \"clickhouse\",\n\t\t\t\tDsn:     secret,\n\t\t\t\tQueries: tt.queries,\n\t\t\t\tLog:     logger,\n\t\t\t}\n\n\t\t\tvar acc testutil.Accumulator\n\n\t\t\t// Startup the plugin\n\t\t\trequire.NoError(t, plugin.Init())\n\t\t\trequire.NoError(t, plugin.Start(&acc))\n\n\t\t\t// Gather\n\t\t\trequire.NoError(t, plugin.Gather(&acc))\n\t\t\trequire.Empty(t, acc.Errors)\n\n\t\t\t// Stopping the plugin\n\t\t\tplugin.Stop()\n\n\t\t\t// Do the comparison\n\t\t\ttestutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "plugins/inputs/sql/testdata/clickhouse/expected.sql",
    "content": "CREATE TABLE IF NOT EXISTS default.metric_one (\n    tag_one String,\n    tag_two String,\n    int64_one Int64,\n    int64_two Int64,\n    timestamp Int64\n) ENGINE MergeTree() ORDER BY timestamp;\n\nINSERT INTO default.metric_one (\n    tag_one,\n    tag_two,\n    int64_one,\n    int64_two,\n    timestamp\n) VALUES ('tag1', 'tag2', 1234, 2345, 1621289085);\n"
  },
  {
    "path": "plugins/inputs/sql/testdata/postgres/expected.sql",
    "content": "SET statement_timeout = 0;\nSET lock_timeout = 0;\nSET idle_in_transaction_session_timeout = 0;\nSET client_encoding = 'UTF8';\nSET standard_conforming_strings = on;\nSELECT pg_catalog.set_config('search_path', '', false);\nSET check_function_bodies = false;\nSET xmloption = content;\nSET client_min_messages = warning;\nSET row_security = off;\nSET default_tablespace = '';\nSET default_table_access_method = heap;\nCREATE TABLE public.\"metric three\" (\n    \"timestamp\" timestamp without time zone,\n    \"tag four\" text,\n    \"string two\" text\n);\nALTER TABLE public.\"metric three\" OWNER TO postgres;\nCREATE TABLE public.metric_one (\n    \"timestamp\" timestamp without time zone,\n    tag_one text,\n    tag_two text,\n    int64_one integer,\n    int64_two integer\n);\nALTER TABLE public.metric_one OWNER TO postgres;\nCREATE TABLE public.metric_two (\n    \"timestamp\" timestamp without time zone,\n    tag_three text,\n    string_one text\n);\nALTER TABLE public.metric_two OWNER TO postgres;\nCOPY public.\"metric three\" (\"timestamp\", \"tag four\", \"string two\") FROM stdin;\n2021-05-17 22:04:45\ttag4\tstring2\n\\.\nCOPY public.metric_one (\"timestamp\", tag_one, tag_two, int64_one, int64_two) FROM stdin;\n2021-05-17 22:04:45\ttag1\ttag2\t1234\t2345\n\\.\nCOPY public.metric_two (\"timestamp\", tag_three, string_one) FROM stdin;\n2021-05-17 22:04:45\ttag3\tstring1\n\\.\n"
  },
  {
    "path": "plugins/inputs/sqlserver/README.md",
    "content": "# Microsoft SQL Server Input Plugin\n\nThis plugin provides metrics for your [SQL Server][sqlserver] instance. Recorded\nmetrics are lightweight and use Dynamic Management Views supplied by SQL Server.\n\n> [!NOTE]\n> This plugin supports SQL server versions supported by Microsoft (see\n> [lifecycle dates][lifecycle]), Azure SQL Databases (Single), Azure SQL Managed\n> Instances, Azure SQL Elastic Pools and Azure Arc-enabled SQL Managed\n> Instances.\n\n⭐ Telegraf v0.10.1\n🏷️ datastore\n💻 all\n\n[sqlserver]: https://docs.microsoft.com/en-us/sql/sql-server\n[lifecycle]: https://docs.microsoft.com/en-us/sql/sql-server/end-of-support/sql-server-end-of-life-overview?view=sql-server-ver15#lifecycle-dates\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Secret-store support\n\nThis plugin supports secrets from secret-stores for the `servers` option.\nSee the [secret-store documentation][SECRETSTORE] for more details on how\nto use them.\n\n[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets\n\n## Configuration\n\n```toml @sample.conf\n# Read metrics from Microsoft SQL Server\n[[inputs.sqlserver]]\n  ## Specify instances to monitor with a list of connection strings.\n  ## All connection parameters are optional.\n  ## By default, the host is localhost, listening on default port, TCP 1433.\n  ##   for Windows, the user is the currently running AD user (SSO).\n  ##   See https://github.com/microsoft/go-mssqldb for detailed connection\n  ##   parameters, in particular, tls connections can be created like so:\n  ##   \"encrypt=true;certificate=<cert>;hostNameInCertificate=<SqlServer host fqdn>\"\n  servers = [\n    \"Server=192.168.1.10;Port=1433;User Id=<user>;Password=<pw>;app name=telegraf;log=1;\",\n  ]\n\n  ## Timeout for query execution operation\n  ## Note that the timeout for queries is per query not per gather.\n  ## 0 value means no timeout\n  # query_timeout = \"0s\"\n\n  ## Authentication method\n  ## valid methods: \"connection_string\", \"AAD\"\n  # auth_method = \"connection_string\"\n\n  ## ClientID is the is the client ID of the user assigned identity of the VM\n  ## that should be used to authenticate to the Azure SQL server.\n  # client_id = \"\"\n\n  ## \"database_type\" enables a specific set of queries depending on the database type. If specified, it replaces azuredb = true/false and query_version = 2\n  ## In the config file, the sql server plugin section should be repeated each with a set of servers for a specific database_type.\n  ## Possible values for database_type are - \"SQLServer\" or \"AzureSQLDB\" or \"AzureSQLManagedInstance\" or \"AzureSQLPool\"\n  database_type = \"SQLServer\"\n\n  ## A list of queries to include. If not specified, all the below listed queries are used.\n  include_query = []\n\n  ## A list of queries to explicitly ignore.\n  exclude_query = [\"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\"]\n\n  ## Force using the deprecated ADAL authentication method instead of the recommended\n  ## MSAL method. Setting this option is not recommended and only exists for backward\n  ## compatibility.\n  # use_deprecated_adal_authentication = false\n\n  ## Queries enabled by default for database_type = \"SQLServer\" are -\n  ## SQLServerPerformanceCounters, SQLServerWaitStatsCategorized, SQLServerDatabaseIO, SQLServerProperties, SQLServerMemoryClerks,\n  ## SQLServerSchedulers, SQLServerRequests, SQLServerVolumeSpace, SQLServerCpu, SQLServerAvailabilityReplicaStates, SQLServerDatabaseReplicaStates,\n  ## SQLServerRecentBackups\n\n  ## Queries enabled by default for database_type = \"AzureSQLDB\" are -\n  ## AzureSQLDBResourceStats, AzureSQLDBResourceGovernance, AzureSQLDBWaitStats, AzureSQLDBDatabaseIO, AzureSQLDBServerProperties,\n  ## AzureSQLDBOsWaitstats, AzureSQLDBMemoryClerks, AzureSQLDBPerformanceCounters, AzureSQLDBRequests, AzureSQLDBSchedulers\n\n  ## Queries enabled by default for database_type = \"AzureSQLManagedInstance\" are -\n  ## AzureSQLMIResourceStats, AzureSQLMIResourceGovernance, AzureSQLMIDatabaseIO, AzureSQLMIServerProperties, AzureSQLMIOsWaitstats,\n  ## AzureSQLMIMemoryClerks, AzureSQLMIPerformanceCounters, AzureSQLMIRequests, AzureSQLMISchedulers\n\n  ## Queries enabled by default for database_type = \"AzureSQLPool\" are -\n  ## AzureSQLPoolResourceStats, AzureSQLPoolResourceGovernance, AzureSQLPoolDatabaseIO, AzureSQLPoolWaitStats,\n  ## AzureSQLPoolMemoryClerks, AzureSQLPoolPerformanceCounters, AzureSQLPoolSchedulers\n\n  ## Queries enabled by default for database_type = \"AzureArcSQLManagedInstance\" are -\n  ## AzureSQLMIDatabaseIO, AzureSQLMIServerProperties, AzureSQLMIOsWaitstats,\n  ## AzureSQLMIMemoryClerks, AzureSQLMIPerformanceCounters, AzureSQLMIRequests, AzureSQLMISchedulers\n\n  ## Following are old config settings\n  ## You may use them only if you are using the earlier flavor of queries, however it is recommended to use\n  ## the new mechanism of identifying the database_type there by use it's corresponding queries\n\n  ## Optional parameter, setting this to 2 will use a new version\n  ## of the collection queries that break compatibility with the original\n  ## dashboards.\n  ## Version 2 - is compatible from SQL Server 2012 and later versions and also for SQL Azure DB\n  # query_version = 2\n\n  ## If you are using AzureDB, setting this to true will gather resource utilization metrics\n  # azuredb = false\n\n  ## Toggling this to true will emit an additional metric called \"sqlserver_telegraf_health\".\n  ## This metric tracks the count of attempted queries and successful queries for each SQL instance specified in \"servers\".\n  ## The purpose of this metric is to assist with identifying and diagnosing any connectivity or query issues.\n  ## This setting/metric is optional and is disabled by default.\n  # health_metric = false\n\n  ## Possible queries across different versions of the collectors\n  ## Queries enabled by default for specific Database Type\n\n  ## database_type =  AzureSQLDB  by default collects the following queries\n  ## - AzureSQLDBWaitStats\n  ## - AzureSQLDBResourceStats\n  ## - AzureSQLDBResourceGovernance\n  ## - AzureSQLDBDatabaseIO\n  ## - AzureSQLDBServerProperties\n  ## - AzureSQLDBOsWaitstats\n  ## - AzureSQLDBMemoryClerks\n  ## - AzureSQLDBPerformanceCounters\n  ## - AzureSQLDBRequests\n  ## - AzureSQLDBSchedulers\n\n  ## database_type =  AzureSQLManagedInstance by default collects the following queries\n  ## - AzureSQLMIResourceStats\n  ## - AzureSQLMIResourceGovernance\n  ## - AzureSQLMIDatabaseIO\n  ## - AzureSQLMIServerProperties\n  ## - AzureSQLMIOsWaitstats\n  ## - AzureSQLMIMemoryClerks\n  ## - AzureSQLMIPerformanceCounters\n  ## - AzureSQLMIRequests\n  ## - AzureSQLMISchedulers\n\n  ## database_type =  AzureSQLPool by default collects the following queries\n  ## - AzureSQLPoolResourceStats\n  ## - AzureSQLPoolResourceGovernance\n  ## - AzureSQLPoolDatabaseIO\n  ## - AzureSQLPoolOsWaitStats,\n  ## - AzureSQLPoolMemoryClerks\n  ## - AzureSQLPoolPerformanceCounters\n  ## - AzureSQLPoolSchedulers\n\n  ## database_type =  SQLServer by default collects the following queries\n  ## - SQLServerPerformanceCounters\n  ## - SQLServerWaitStatsCategorized\n  ## - SQLServerDatabaseIO\n  ## - SQLServerProperties\n  ## - SQLServerMemoryClerks\n  ## - SQLServerSchedulers\n  ## - SQLServerRequests\n  ## - SQLServerVolumeSpace\n  ## - SQLServerCpu\n  ## - SQLServerRecentBackups\n  ## and following as optional (if mentioned in the include_query list)\n  ## - SQLServerAvailabilityReplicaStates\n  ## - SQLServerDatabaseReplicaStates\n\n  ## Maximum number of open connections to the database, 0 allows the driver to decide.\n  # max_open_connections = 0\n\n  ## Maximum number of idle connections in the connection pool, 0 allows the driver to decide.\n  # max_idle_connections = 0\n```\n\nFor available options in the `servers` DSN check the [driver documentation][driver].\n\nThe plugin supports the named-pipe and LPC protocol **on Windows AMD64 and i386**\nfor connections. On other platforms those protocols are not available. See the\n[protocol configuration section][driver_protos] of the driver documentation on\nhow to specify the protocols.\n\n[driver]: https://github.com/microsoft/go-mssqldb\n[driver_protos]: https://github.com/microsoft/go-mssqldb?tab=readme-ov-file#protocol-configuration\n\n### Additional Setup\n\nYou have to create a login on every SQL Server instance or Azure SQL Managed\ninstance you want to monitor, with following script:\n\n```sql\nUSE master;\nGO\nCREATE LOGIN [telegraf] WITH PASSWORD = N'mystrongpassword';\nGO\nGRANT VIEW SERVER STATE TO [telegraf];\nGO\nGRANT VIEW ANY DEFINITION TO [telegraf];\nGO\n```\n\nFor Azure SQL Database, you require the View Database State permission\nand can create a user with a password directly in the database.\n\n```sql\nCREATE USER [telegraf] WITH PASSWORD = N'mystrongpassword';\nGO\nGRANT VIEW DATABASE STATE TO [telegraf];\nGO\n```\n\nFor Azure SQL Elastic Pool, please follow the following instructions to collect\nmetrics. On master logical database, create an SQL login 'telegraf' and assign\nit to the server-level role ##MS_ServerStateReader##.\n\n```sql\nCREATE LOGIN [telegraf] WITH PASSWORD = N'mystrongpassword';\nGO\nALTER SERVER ROLE ##MS_ServerStateReader##\n  ADD MEMBER [telegraf];\nGO\n```\n\nElastic pool metrics can be collected from any database in the pool if a user\nfor the `telegraf` login is created in that database. For collection to work,\nthis database must remain in the pool, and must not be renamed. If you plan\nto add/remove databases from this pool, create a separate database for\nmonitoring purposes that will remain in the pool.\n\n> [!NOTE]\n> To avoid duplicate monitoring data, do not collect elastic pool metrics\n> from more than one database in the same pool.\n\n```sql\nGO\nCREATE USER [telegraf] FOR LOGIN telegraf;\n```\n\nFor Service SID authentication to SQL Server (Windows service installations\nonly) check the [howto document][sid_howto]. In an administrative command prompt\nconfigure the telegraf service for use with a service SID\n\n```Batchfile\nsc.exe sidtype \"telegraf\" unrestricted\n```\n\nTo create the login for the telegraf service run the following script:\n\n```sql\nUSE master;\nGO\nCREATE LOGIN [NT SERVICE\\telegraf] FROM WINDOWS;\nGO\nGRANT VIEW SERVER STATE TO [NT SERVICE\\telegraf];\nGO\nGRANT VIEW ANY DEFINITION TO [NT SERVICE\\telegraf];\nGO\n```\n\nRemove User Id and Password keywords from the connection string in your\nconfig file to use windows authentication.\n\n```toml\n[[inputs.sqlserver]]\n  servers = [\"Server=192.168.1.10;Port=1433;app name=telegraf;log=1;\",]\n```\n\nTo set up a configurable timeout, add timeout to the connections string\nin your config file.\n\n```toml\nservers = [\n  \"Server=192.168.1.10;Port=1433;User Id=<user>;Password=<pw>;app name=telegraf;log=1;dial timeout=30\",\n]\n```\n\n[sid_howto]: https://docs.microsoft.com/en-us/sql/relational-databases/security/using-service-sids-to-grant-permissions-to-services-in-sql-server\n\n### Azure Active Directory (AAD) authentication using Managed Identity\n\nAzure SQL Database instances support two main methods of\n[authentication][auth_methods]: SQL authentication and AAD authentication. The\nrecommended practice is to use [AAD authentication][auth_aad] when possible as\nit is a more modern authentication protocol, allows for easier credential and\nrole management and can eliminate the need to include passwords in connection\nstrings.\n\nIf more then one managed identity is assigned to the VM, you need specify the\n`client_id` of the identity you wish to use to authenticate with the SQL Server.\nPlease check [SQL Server driver][driver_azure] documentation for available options.\n\n[auth_methods]: https://docs.microsoft.com/en-us/azure/azure-sql/database/security-overview#authentication\n[auth_aad]: https://docs.microsoft.com/en-us/azure/azure-sql/database/authentication-aad-overview\n[driver_azure]: https://github.com/microsoft/go-mssqldb#azure-active-directory-authentication\n\n### Azure Active Directory (AAD) authentication using MSI\n\nAAD based auth is currently only supported for Azure SQL Database and Azure SQL\nManaged Instance but not for SQL Server. To use MSI configure\n\"system-assigned managed identity\" for Azure resources on the Monitoring VM\n(the VM connecting to the SQL server/database) [using the Azure portal][portal].\nCreate a user with the name of the Monitoring VM as the principal on the\ndatabase being monitored using the below script. This might require\nallow-listing the client machine's IP address (from where the below SQL script\nis being run) on the SQL Server resource.\n\nIn case of multiple assigned identities on one VM you can use the parameter\nuser_assigned_id to specify the `client_id`.\n\n```sql\nEXECUTE ('IF EXISTS(SELECT * FROM sys.database_principals WHERE name = ''<Monitoring_VM_Name>'')\n    BEGIN\n        DROP USER [<Monitoring_VM_Name>]\n    END')\nEXECUTE ('CREATE USER [<Monitoring_VM_Name>] FROM EXTERNAL PROVIDER')\nEXECUTE ('GRANT VIEW DATABASE STATE TO [<Monitoring_VM_Name>]')\n```\n\nOn the SQL Server resource of the database(s) being monitored, go to\n\"Firewalls and Virtual Networks\" tab and allowlist the monitoring VM IP address.\nOn the Monitoring VM, update the telegraf config file with the database\nconnection string in the following format. The connection string only provides\nthe server and database name, but no password (since the VM's system-assigned\nmanaged identity would be used for authentication). The auth method must be\nset to \"AAD\"\n\n```toml\n  servers = [\n    \"Server=<Azure_SQL_Server_Name>.database.windows.net;Port=1433;Database=<Azure_SQL_Database_Name>;app name=telegraf;log=1;\",\n  ]\n  auth_method = \"AAD\"\n```\n\n[portal]: https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm\n\n## Metrics\n\nTo provide backwards compatibility, this plugin support two versions of\nmetrics queries.\n\n> [!NOTE]\n> Version 2 queries are not backwards compatible with the old queries. Any\n> dashboards or queries based on the old query format will not work with the new\n> format. The version 2 queries only report raw metrics, no math has been done\n> to calculate deltas. To graph this data you must calculate deltas in your\n> dashboarding software.\n\n### Query Version 1\n\n> [!CAUTION]\n> The `query_version` option was **deprecated** in Telegraf v1.16. All future\n> development will be under configuration option`database_type`.\n\nThe original metrics queries provide:\n\n- *Performance counters*: 1000+ metrics from `sys.dm_os_performance_counters`\n- *Performance metrics*: special performance and ratio metrics\n- *Wait stats*: wait tasks categorized from `sys.dm_os_wait_stats`\n- *Memory clerk*: memory breakdown from `sys.dm_os_memory_clerks`\n- *Database size*: databases size trend from `sys.dm_io_virtual_file_stats`\n- *Database IO*: databases I/O from `sys.dm_io_virtual_file_stats`\n- *Database latency*: databases latency from `sys.dm_io_virtual_file_stats`\n- *Database properties*: databases properties, state and recovery model, from `sys.databases`\n- *OS Volume*: available, used and total space from `sys.dm_os_volume_stats`\n- *CPU*: cpu usage from `sys.dm_os_ring_buffers`\n\nIf you are using the original queries all stats have the following tags:\n\n- `servername`:  hostname:instance\n- `type`: type of stats to easily filter measurements\n\n### Query Version 2\n\n> [!CAUTION]\n> The `query_version` option was **deprecated** in Telegraf v1.16. All future\n> development will be under configuration option`database_type`.\n\nThe new (version 2) metrics provide:\n\n- *Database IO*: IO stats from `sys.dm_io_virtual_file_stats`.\n- *Memory Clerk*: Memory clerk breakdown from `sys.dm_os_memory_clerks`, most\n                  clerks have been given a friendly name.\n- *Performance Counters*:  A select list of performance counters from\n                           `sys.dm_os_performance_counters`. Some of the\n                           important metrics included:\n  - *Activity*:            Transactions/sec/database, Batch requests/sec,\n                           blocked processes and more\n  - *Availability Groups*: Bytes sent to replica, Bytes received from replica,\n                           Log bytes received, Log send queue, transaction delay\n                           and more\n  - *Log activity*:        Log bytes flushed/sec, Log flushes/sec, Log Flush\n                           Wait Time\n  - *Memory*:              PLE, Page reads/sec, Page writes/sec and more\n  - *TempDB*:              Free space, Version store usage, Active temp tables,\n                           temp table creation rate and more\n  - *Resource Governor*:   CPU Usage, Requests/sec, Queued Requests, and Blocked\n                           tasks per workload group and more\n- *Server properties*:     Number of databases in all possible states (online,\n                           offline, suspect, etc.), cpu count, total physical\n                           memory, available physical memory, SQL Server service\n                           uptime, SQL Server SPID, and SQL Server version. In\n                           the case of Azure SQL relevant properties such as\n                           Tier, #Vcores, Memory etc.\n- *Wait stats*:            Wait time in ms, number of waiting tasks, resource\n                           wait time, signal wait time, max wait time in ms,\n                           wait type, and wait category. The waits are\n                           categorized using the same categories used in\n                           Query Store.\n- *Schedulers*:            This captures `sys.dm_os_schedulers`.\n- *SqlRequests*:           This captures a snapshot of `sys.dm_exec_requests`\n                           and `sys.dm_exec_sessions` that gives you running\n                           requests as well as wait types and blocking sessions.\n                           Telegraf's monitoring request is omitted unless it is\n                           a heading blocker. Also includes sleeping sessions\n                           with open transactions.\n- *VolumeSpace*:           uses `sys.dm_os_volume_stats` to get total, used and\n                           occupied space on every disk that contains a data or\n                           log file. (Note that even if enabled it won't get any\n                           data from Azure SQL Database or SQL Managed Instance).\n                           It is pointless to run this with high frequency\n                           (ie: every 10s), but it won't cause any problem.\n- *Cpu*:                   uses the buffer ring (`sys.dm_os_ring_buffers`) to\n                           get CPU data, the table is updated once per minute.\n                           (Note that even if enabled it won't get any data from\n                           Azure SQL Database or SQL Managed Instance).\n\n  In order to allow tracking on a per statement basis this query produces a\n  unique tag for each query.  Depending on the database workload, this may\n  result in a high cardinality series.  Reference the FAQ for tips on\n  [managing series cardinality][cardinality].\n\n- *Azure Managed Instances*\n  - Stats from `sys.server_resource_stats`\n  - Resource governance stats from `sys.dm_instance_resource_governance`\n- *Azure SQL Database* in addition to other stats\n  - Stats from `sys.dm_db_wait_stats`\n  - Resource governance stats from `sys.dm_user_db_resource_governance`\n  - Stats from `sys.dm_db_resource_stats`\n\n### Database Type \"AzureSQLDB\"\n\nThese are metrics for Azure SQL Database (single database) and are very\nsimilar to version 2 but split out for maintenance reasons, better ability\nto test,differences in DMVs:\n\n- *AzureSQLDBDatabaseIO*:          IO stats from `sys.dm_io_virtual_file_stats`\n                                   including resource governance time, RBPEX, IO\n                                   for Hyperscale.\n- *AzureSQLDBMemoryClerks*:        Memory clerk breakdown from `sys.dm_os_memory_clerks`.\n- *AzureSQLDBResourceGovernance*:  Relevant properties indicatign resource\n                                   limits from `sys.dm_user_db_resource_governance`\n- *AzureSQLDBPerformanceCounters*: A select list of performance counters from\n                                   `sys.dm_os_performance_counters` including\n                                   cloud specific counters for SQL Hyperscale.\n- *AzureSQLDBServerProperties*:    Relevant Azure SQL relevant properties from\n                                   such as Tier, #Vcores, Memory etc, storage, etc.\n- *AzureSQLDBWaitstats*:           Wait time in ms from `sys.dm_db_wait_stats`,\n                                   number of waiting tasks, resource wait time,\n                                   signal wait time, max wait time in ms, wait\n                                   type, and wait category. The waits are\n                                   categorized using the same categories used in\n                                   Query Store. These waits are collected only\n                                   as of the end of the a statement. and for a\n                                   specific database only.\n- *AzureSQLOsWaitstats*:           Wait time in ms from `sys.dm_os_wait_stats`,\n                                   number of waiting tasks, resource wait time,\n                                   signal wait time, max wait time in ms, wait\n                                   type, and wait category. The waits are\n                                   categorized using the same categories used in\n                                   Query Store. These waits are collected as\n                                   they occur and instance wide\n- *AzureSQLDBRequests*:            Requests which are blocked or have a wait\n                                   type from `sys.dm_exec_sessions` and\n                                   `sys.dm_exec_requests`. Telegraf's monitoring\n                                   request is omitted unless it is a heading blocker\n- *AzureSQLDBSchedulers*:          This captures `sys.dm_os_schedulers` snapshots.\n\n### Database Type \"AzureSQLManagedInstance\"\n\nThese are metrics for Azure SQL Managed instance, are very similar to version\n2 but split out for maintenance reasons, better ability to test, differences\nin DMVs:\n\n- *AzureSQLMIDatabaseIO*:          IO stats from `sys.dm_io_virtual_file_stats`\n                                   including resource governance time, RBPEX, IO\n                                   for Hyperscale.\n- *AzureSQLMIMemoryClerks*:        Memory clerk breakdown from `sys.dm_os_memory_clerks`.\n- *AzureSQLMIResourceGovernance*:  Relevant properties indicatign resource limits\n                                   from `sys.dm_instance_resource_governance`\n- *AzureSQLMIPerformanceCounters*: A select list of performance counters from\n                                  `sys.dm_os_performance_counters` including\n                                   cloud specific counters for SQL Hyperscale.\n- *AzureSQLMIServerProperties*:    Relevant Azure SQL relevant properties such\n                                   as Tier, #Vcores, Memory etc, storage, etc.\n- *AzureSQLMIOsWaitstats*:         Wait time in ms from `sys.dm_os_wait_stats`,\n                                   number of waiting tasks, resource wait time,\n                                   signal wait time, max wait time in ms, wait\n                                   type, and wait category. The waits are\n                                   categorized using the same categories used in\n                                   Query Store. These waits are collected as\n                                   they occur and instance wide\n- *AzureSQLMIRequests*:            Requests which are blocked or have a wait\n                                   type from `sys.dm_exec_sessions` and\n                                   `sys.dm_exec_requests`. Telegraf's monitoring\n                                   request is omitted unless it is a heading blocker\n- *AzureSQLMISchedulers*: This captures `sys.dm_os_schedulers` snapshots.\n\n### Database Type \"AzureSQLPool\"\n\nThese are metrics for Azure SQL to monitor resources usage at Elastic Pool\nlevel. These metrics require additional permissions to be collected, please\nensure to check additional setup section in this documentation.\n\n- *AzureSQLPoolResourceStats*:       Returns resource usage statistics for the\n                                     current elastic pool in a SQL Database\n                                     server. Queried from `sys.dm_resource_governor_resource_pools_history_ex`.\n- *AzureSQLPoolResourceGovernance*:  Returns actual configuration and capacity\n                                     settings used by resource governance\n                                     mechanisms in the current elastic pool.\n                                     Queried from `sys.dm_user_db_resource_governance`.\n- *AzureSQLPoolDatabaseIO*:          Returns I/O statistics for data and log\n                                     files for each database in the pool.\n                                     Queried from `sys.dm_io_virtual_file_stats`.\n- *AzureSQLPoolOsWaitStats*:         Returns information about all the waits\n                                     encountered by threads that executed.\n                                     Queried from `sys.dm_os_wait_stats`.\n- *AzureSQLPoolMemoryClerks*:        Memory clerk breakdown from `sys.dm_os_memory_clerks`.\n- *AzureSQLPoolPerformanceCounters*: A selected list of performance counters\n                                     from `sys.dm_os_performance_counters`.\n                                     Note: Performance counters where the\n                                     cntr_type column value is 537003264 are\n                                     already returned with a percentage format\n                                     between 0 and 100. For other counters,\n                                     please check [sys.dm_os_performance_counters][os_perf_counters]\n                                     documentation.\n- *AzureSQLPoolSchedulers*: This captures `sys.dm_os_schedulers` snapshots.\n\n[os_perf_counters]: https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-performance-counters-transact-sql?view=azuresqldb-current\n\n### Database Type \"SQLServer\"\n\n- *SQLServerDatabaseIO*:           IO stats from `sys.dm_io_virtual_file_stats`\n- *SQLServerMemoryClerks*:         Memory clerk breakdown from `sys.dm_os_memory_clerks`,\n                                   most clerks have been given a friendly name.\n- *SQLServerPerformanceCounters*:  A select list of performance counters from\n                                   `sys.dm_os_performance_counters`. Some of the\n                                   important metrics included:\n  - *Activity*:                    Transactions/sec/database, Batch requests/sec,\n                                   blocked processes and more\n  - *Availability Groups*:         Bytes sent to replica, Bytes received from\n                                   replica, Log bytes received, Log send queue,\n                                   transaction delay and more\n  - *Log activity*:                Log bytes flushed/sec, Log flushes/sec,\n                                   Log Flush Wait Time\n  - *Memory*:                      PLE, Page reads/sec, Page writes/sec and more\n  - *TempDB*:                      Free space, Version store usage, Active temp\n                                   tables, temp table creation rate and more\n  - *Resource Governor*:           CPU Usage, Requests/sec, Queued Requests, and\n                                   Blocked tasks per workload group and more\n- *SQLServerProperties*:           Number of databases in all possible states\n                                   (online, offline, suspect, etc.), cpu count,\n                                   total physical memory, available physical memory,\n                                   SQL Server service uptime, SQL Server SPID and\n                                   SQL Server version. In the case of Azure SQL\n                                   relevant properties such as Tier, #Vcores,\n                                   Memory etc.\n- *SQLServerWaitStatsCategorized*: Wait time in ms, number of waiting tasks,\n                                   resource wait time, signal wait time, max\n                                   wait time in ms, wait type, and wait category.\n                                   The waits are categorized using the same\n                                   categories used in Query Store.\n- *SQLServerSchedulers*:           This captures `sys.dm_os_schedulers`.\n- *SQLServerRequests*:             This captures a snapshot of `sys.dm_exec_requests`\n                                   and `sys.dm_exec_sessions` that gives you\n                                   running requests as well as wait types and\n                                   blocking sessions.\n- *SQLServerVolumeSpace*:          Uses `sys.dm_os_volume_stats` to get total,\n                                   used and occupied space on every disk that\n                                   contains a data or log file. (Note that even\n                                   if enabled it won't get any data from Azure\n                                   SQL Database or SQL Managed Instance). It is\n                                   pointless to run this with high frequency\n                                   (ie: every 10s), but it won't cause any problem.\n- SQLServerCpu:                    Uses the buffer ring (`sys.dm_os_ring_buffers`)\n                                   to get CPU data, the table is updated once\n                                   per minute. (Note that even if enabled it\n                                   won't get any data from Azure SQL Database or\n                                   SQL Managed Instance).\n- SQLServerAvailabilityReplicaStates: Collects availability replica state\n                                      information from `sys.dm_hadr_availability_replica_states`\n                                      for a High Availability / Disaster\n                                      Recovery (HADR) setup\n- SQLServerDatabaseReplicaStates:  Collects database replica state information\n                                   from `sys.dm_hadr_database_replica_states`\n                                   for a High Availability / Disaster Recovery\n                                   (HADR) setup\n- SQLServerRecentBackups:          Collects latest full, differential and\n                                   transaction log backup date and size from `msdb.dbo.backupset`\n- SQLServerPersistentVersionStore: Collects persistent version store information\n                                   from `sys.dm_tran_persistent_version_store_stats`\n                                   for databases with Accelerated Database\n                                   Recovery enabled\n\n### Output Measures\n\nThe guiding principal is that all data collected from the same primary DMV ends\nup in the same measure irrespective of database_type.\n\n- `sqlserver_database_io`       - Used by AzureSQLDBDatabaseIO,\n                                  AzureSQLMIDatabaseIO, SQLServerDatabaseIO,\n                                  DatabaseIO given the data is from `sys.dm_io_virtual_file_stats`\n- `sqlserver_waitstats`         - Used by WaitStatsCategorized,\n                                  AzureSQLDBOsWaitstats, AzureSQLMIOsWaitstats\n- `sqlserver_server_properties` - Used by SQLServerProperties,\n                                  AzureSQLDBServerProperties,\n                                  AzureSQLMIServerProperties, ServerProperties\n- `sqlserver_memory_clerks`     - Used by SQLServerMemoryClerks,\n                                  AzureSQLDBMemoryClerks, AzureSQLMIMemoryClerks,\n                                  MemoryClerk\n- `sqlserver_performance`       - Used by SQLServerPerformanceCounters,\n                                  AzureSQLDBPerformanceCounters,\n                                  AzureSQLMIPerformanceCounters, PerformanceCounters\n- `sys.dm_os_schedulers`        - Used by SQLServerSchedulers,\n                                  AzureSQLDBServerSchedulers, AzureSQLMIServerSchedulers\n\nThe following Performance counter metrics can be used directly, with no delta\ncalculations:\n\n- SQLServer:Buffer Manager\\Buffer cache hit ratio\n- SQLServer:Buffer Manager\\Page life expectancy\n- SQLServer:Buffer Node\\Page life expectancy\n- SQLServer:Database Replica\\Log Apply Pending Queue\n- SQLServer:Database Replica\\Log Apply Ready Queue\n- SQLServer:Database Replica\\Log Send Queue\n- SQLServer:Database Replica\\Recovery Queue\n- SQLServer:Databases\\Data File(s) Size (KB)\n- SQLServer:Databases\\Log File(s) Size (KB)\n- SQLServer:Databases\\Log File(s) Used Size (KB)\n- SQLServer:Databases\\XTP Memory Used (KB)\n- SQLServer:General Statistics\\Active Temp Tables\n- SQLServer:General Statistics\\Processes blocked\n- SQLServer:General Statistics\\Temp Tables For Destruction\n- SQLServer:General Statistics\\User Connections\n- SQLServer:Memory Broker Clerks\\Memory broker clerk size\n- SQLServer:Memory Manager\\Memory Grants Pending\n- SQLServer:Memory Manager\\Target Server Memory (KB)\n- SQLServer:Memory Manager\\Total Server Memory (KB)\n- SQLServer:Resource Pool Stats\\Active memory grant amount (KB)\n- SQLServer:Resource Pool Stats\\Disk Read Bytes/sec\n- SQLServer:Resource Pool Stats\\Disk Read IO Throttled/sec\n- SQLServer:Resource Pool Stats\\Disk Read IO/sec\n- SQLServer:Resource Pool Stats\\Disk Write Bytes/sec\n- SQLServer:Resource Pool Stats\\Disk Write IO Throttled/sec\n- SQLServer:Resource Pool Stats\\Disk Write IO/sec\n- SQLServer:Resource Pool Stats\\Used memory (KB)\n- SQLServer:Transactions\\Free Space in tempdb (KB)\n- SQLServer:Transactions\\Version Store Size (KB)\n- SQLServer:User Settable\\Query\n- SQLServer:Workload Group Stats\\Blocked tasks\n- SQLServer:Workload Group Stats\\CPU usage %\n- SQLServer:Workload Group Stats\\Queued requests\n- SQLServer:Workload Group Stats\\Requests completed/sec\n\nVersion 2 queries have the following tags:\n\n- `sql_instance`:  Physical host and instance name (hostname:instance)\n- `database_name`: For Azure SQLDB, database_name denotes the name of the\n                   Azure SQL Database as server name is a logical construct.\n\n### Health Metric\n\nAll collection versions (version 1, version 2, and database_type) support an\noptional plugin health metric called `sqlserver_telegraf_health`. This metric\ntracks if connections to SQL Server are succeeding or failing. Users can\nleverage this metric to detect if their SQL Server monitoring is not working\nas intended.\n\nIn the configuration file, toggling `health_metric` to `true` will enable\ncollection of this metric. By default, this value is set to `false` and\nthe metric is not collected. The health metric emits one record for each\nconnection specified by `servers` in the configuration file.\n\nThe health metric emits the following tags:\n\n- `sql_instance` -   Name of the server specified in the connection string. This\n                     value is emitted as-is in the connection string. If the\n                     server could not be parsed from the connection string, a\n                     constant placeholder value is emitted\n- `database_name` -  Name of the database or (initial catalog) specified in the\n                     connection string. This value is emitted as-is in the\n                     connection string. If the database could not be parsed from\n                     the connection string, a constant placeholder value is\n                     emitted\n\nThe health metric emits the following fields:\n\n- `attempted_queries`  - Number of queries that were attempted for this connection\n- `successful_queries` - Number of queries that completed successfully for this connection\n- `database_type`      - Type of database as specified by `database_type`.\n                         If `database_type` is empty, the `QueryVersion` and\n                         `AzureDB` fields are concatenated instead\n\nIf `attempted_queries` and `successful_queries` are not equal for\na given connection, some metrics were not successfully gathered for\nthat connection. If `successful_queries` is 0, no metrics were successfully\ngathered.\n\n[cardinality]: /docs/FAQ.md#user-content-q-how-can-i-manage-series-cardinality\n\n## Example Output\n\n```text\nsqlserver_cpu_other_process_cpu{host=\"servername\",measurement_db_type=\"SQLServer\",sql_instance=\"SERVERNAME:INST\"} 9\nsqlserver_performance{counter=\"Log File(s) Size (KB)\",counter_type=\"65792\",host=\"servername\",instance=\"instance_name\",measurement_db_type=\"SQLServer\",object=\"MSSQL$INSTANCE_NAME:Databases\",sql_instance=\"SERVERNAME:INSTANCE_NAME\"} 1.048568e+06\n```\n"
  },
  {
    "path": "plugins/inputs/sqlserver/azurearcsqlmiqueries_test.go",
    "content": "package sqlserver\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAzureSQLIntegration_ArcManaged_DatabaseIO_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIDatabaseIO\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_database_io\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"physical_filename\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"logical_filename\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"file_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"reads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"writes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_read_stall_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_write_stall_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_ServerProperties_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIServerProperties\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_server_properties\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sql_instance\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"cpu_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"server_memory\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sku\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"engine_edition\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"hardware_type\"))\n\trequire.True(t, acc.HasField(\"sqlserver_server_properties\", \"uptime\")) // Time field.\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sql_version\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sql_version_desc\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"db_online\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"db_restoring\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"db_recovering\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"db_recoveryPending\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"db_suspect\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"replica_updateability\"))\n\n\t// This query should only return one row\n\trequire.Len(t, acc.Metrics, 1)\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_OsWaitStats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIOsWaitstats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_waitstats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"waiting_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"max_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"signal_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"resource_wait_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_category\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_MemoryClerks_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIMemoryClerks\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_memory_clerks\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"clerk_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_memory_clerks\", \"size_kb\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_PerformanceCounters_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIPerformanceCounters\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_performance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"object\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"instance\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_performance\", \"value\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter_type\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_Requests_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMIRequests\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_requests\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"database_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"session_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"request_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"status\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"cpu_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"total_elapsed_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"logical_reads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"writes\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"command\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"wait_type\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"wait_resource\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"blocking_session_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"program_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"host_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"nt_user_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"login_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"open_transaction\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"transaction_isolation_level\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"granted_query_memory_pages\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_requests\", \"percent_complete\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"statement_text\"))\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"objectid\"))         // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"stmt_object_name\")) // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"stmt_db_name\"))     // Can be null.\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"query_hash\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"query_plan_hash\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"session_db_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ArcManaged_Schedulers_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_ARCMI_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_ARCMI_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureArcSQLMISchedulers\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureArcSQLManagedInstance\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_schedulers\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"scheduler_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"cpu_id\"))\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_online\")) // Bool field.\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_idle\"))   // Bool field.\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"preemptive_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"context_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"runnable_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"active_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"work_queue_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"pending_disk_io_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"load_factor\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"yield_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_cpu_usage_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_scheduler_delay_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n"
  },
  {
    "path": "plugins/inputs/sqlserver/azuresqldbqueries_test.go",
    "content": "package sqlserver\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAzureSQLIntegration_Database_ResourceStats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBResourceStats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_azure_db_resource_stats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azure_db_resource_stats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azure_db_resource_stats\", \"database_name\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_cpu_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_data_io_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_log_write_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_memory_usage_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"xtp_storage_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"max_worker_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"max_session_percent\"))\n\trequire.True(t, acc.HasField(\"sqlserver_azure_db_resource_stats\", \"dtu_limit\"))              // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_azure_db_resource_stats\", \"avg_login_rate_percent\")) // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_azure_db_resource_stats\", \"end_time\"))               // Time field.\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_instance_memory_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_azure_db_resource_stats\", \"avg_instance_cpu_percent\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azure_db_resource_stats\", \"replica_updateability\"))\n\n\t// This query should only return one row\n\trequire.Len(t, acc.Metrics, 1)\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_ResourceGovernance_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBResourceGovernance\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_db_resource_governance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_db_resource_governance\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_db_resource_governance\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_db_resource_governance\", \"slo_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"dtu_limit\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"max_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"cap_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"instance_cap_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"max_db_memory\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"max_db_max_size_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"db_file_growth_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"log_size_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"instance_max_worker_threads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_group_max_workers\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"instance_max_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_min_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_max_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_group_min_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_group_max_io\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_db_resource_governance\", \"primary_group_min_cpu\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_db_resource_governance\", \"primary_group_max_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"primary_pool_max_workers\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"pool_max_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"checkpoint_rate_mbps\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"checkpoint_rate_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_local_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_managed_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_external_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_type_local_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_type_managed_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_type_external_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_pfs_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_db_resource_governance\", \"volume_type_pfs_iops\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_db_resource_governance\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_WaitStats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBWaitStats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_azuredb_waitstats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azuredb_waitstats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azuredb_waitstats\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azuredb_waitstats\", \"wait_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_azuredb_waitstats\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_azuredb_waitstats\", \"resource_wait_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_azuredb_waitstats\", \"signal_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_azuredb_waitstats\", \"max_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_azuredb_waitstats\", \"waiting_tasks_count\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_azuredb_waitstats\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_DatabaseIO_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBDatabaseIO\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_database_io\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"database_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"database_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"file_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"reads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"writes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_read_stall_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_write_stall_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"logical_filename\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"physical_filename\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"file_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"current_size_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"space_used_mb\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_ServerProperties_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBServerProperties\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_server_properties\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"database_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"cpu_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"server_memory\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"sku\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"engine_edition\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"hardware_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"total_storage_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_server_properties\", \"available_storage_mb\"))\n\trequire.True(t, acc.HasField(\"sqlserver_server_properties\", \"uptime\")) // Time field.\n\trequire.True(t, acc.HasTag(\"sqlserver_server_properties\", \"replica_updateability\"))\n\n\t// This query should only return one row\n\trequire.Len(t, acc.Metrics, 1)\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_OsWaitstats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBOsWaitstats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_waitstats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"resource_wait_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"signal_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"max_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"waiting_tasks_count\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_category\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_MemoryClerks_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBMemoryClerks\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_memory_clerks\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"clerk_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_memory_clerks\", \"size_kb\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_PerformanceCounters_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBPerformanceCounters\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_performance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"database_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"object\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"instance\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_performance\", \"value\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter_type\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_Requests_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBRequests\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_requests\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"database_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"session_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"request_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"session_db_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"status\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"cpu_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"total_elapsed_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"logical_reads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"writes\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"command\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"wait_type\")) // Can be null.\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"wait_resource\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"blocking_session_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"program_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"host_name\"))\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"nt_user_name\")) // Can be null.\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"login_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"open_transaction\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"transaction_isolation_level\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_requests\", \"granted_query_memory_pages\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_requests\", \"percent_complete\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"statement_text\"))\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"objectid\"))         // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"stmt_object_name\")) // Can be null.\n\trequire.True(t, acc.HasField(\"sqlserver_requests\", \"stmt_db_name\"))     // Can be null.\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"query_hash\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"query_plan_hash\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_requests\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_Database_Schedulers_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_DB_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_DB_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLDBSchedulers\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLDB\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_schedulers\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"scheduler_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"cpu_id\"))\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_online\")) // Bool field.\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_idle\"))   // Bool field.\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"preemptive_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"context_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"runnable_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"active_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"work_queue_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"pending_disk_io_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"load_factor\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"yield_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_cpu_usage_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_scheduler_delay_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"replica_updateability\"))\n\n\tserver.Stop()\n}\n"
  },
  {
    "path": "plugins/inputs/sqlserver/azuresqlmanagedqueries.go",
    "content": "//nolint:lll // conditionally long lines allowed\npackage sqlserver\n\nimport (\n\t_ \"github.com/microsoft/go-mssqldb\" // go-mssqldb initialization\n)\n\n// ------------------------------------------------------------------------------------------------\n// ------------------ Azure Managed Instance ------------------------------------------------------\n// ------------------------------------------------------------------------------------------------\nconst sqlAzureMIProperties = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT TOP 1\n\t 'sqlserver_server_properties' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,[virtual_core_count] AS [cpu_count]\n\t,(SELECT [process_memory_limit_mb] FROM sys.dm_os_job_object) AS [server_memory]\n\t,[sku]\n\t,SERVERPROPERTY('EngineEdition') AS [engine_edition]\n\t,[hardware_generation] AS [hardware_type]\n\t,cast([reserved_storage_mb] as bigint) AS [total_storage_mb]\n\t,cast(([reserved_storage_mb] - [storage_space_used_mb]) as bigint) AS [available_storage_mb]\n\t,(SELECT DATEDIFF(MINUTE,[sqlserver_start_time],GETDATE()) from sys.dm_os_sys_info) as [uptime]\n\t,SERVERPROPERTY('ProductVersion') AS [sql_version]\n\t,LEFT(@@VERSION,CHARINDEX(' - ',@@VERSION)) AS [sql_version_desc]\n\t,[db_online]\n\t,[db_restoring]\n\t,[db_recovering]\n\t,[db_recoveryPending]\n\t,[db_suspect]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.server_resource_stats\nCROSS APPLY\t(\n\tSELECT\n\t\t SUM( CASE WHEN [state] = 0 THEN 1 ELSE 0 END ) AS [db_online]\n\t\t,SUM( CASE WHEN [state] = 1 THEN 1 ELSE 0 END ) AS [db_restoring]\n\t\t,SUM( CASE WHEN [state] = 2 THEN 1 ELSE 0 END ) AS [db_recovering]\n\t\t,SUM( CASE WHEN [state] = 3 THEN 1 ELSE 0 END ) AS [db_recoveryPending]\n\t\t,SUM( CASE WHEN [state] = 4 THEN 1 ELSE 0 END ) AS [db_suspect]\n\t\t,SUM( CASE WHEN [state] IN (6,10) THEN 1 ELSE 0 END ) AS [db_offline]\n\tFROM sys.databases\n) AS dbs\nORDER BY\n\t[start_time] DESC;\n`\n\nconst sqlAzureMIResourceStats = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT TOP(1)\n\t 'sqlserver_azure_db_resource_stats' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,cast([avg_cpu_percent] as float) as [avg_cpu_percent]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM\n    sys.server_resource_stats\nORDER BY\n    [end_time] DESC;\n`\n\nconst sqlAzureMIResourceGovernance string = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_instance_resource_governance' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,[instance_cap_cpu]\n\t,[instance_max_log_rate]\n\t,[instance_max_worker_threads]\n\t,[tempdb_log_file_number]\n\t,[volume_local_iops]\n\t,[volume_external_xstore_iops]\n\t,[volume_managed_xstore_iops]\n\t,[volume_type_local_iops] as [voltype_local_iops]\n\t,[volume_type_managed_xstore_iops] as [voltype_man_xtore_iops]\n\t,[volume_type_external_xstore_iops] as [voltype_ext_xtore_iops]\n\t,[volume_external_xstore_iops] as [vol_ext_xtore_iops]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.dm_instance_resource_governance;\n`\n\nconst sqlAzureMIDatabaseIO = `\nSET DEADLOCK_PRIORITY -10;\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t'sqlserver_database_io' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,DB_NAME(mf.[database_id]) AS [database_name]\n\t,COALESCE(mf.[physical_name],'RBPEX') AS [physical_filename]\t--RPBEX = Resilient Buffer Pool Extension\n\t,COALESCE(mf.[name],'RBPEX') AS [logical_filename]\t--RPBEX = Resilient Buffer Pool Extension\n\t,mf.[type_desc] AS [file_type]\n\t,vfs.[io_stall_read_ms] AS [read_latency_ms]\n\t,vfs.[num_of_reads] AS [reads]\n\t,vfs.[num_of_bytes_read] AS [read_bytes]\n\t,vfs.[io_stall_write_ms] AS [write_latency_ms]\n\t,vfs.[num_of_writes] AS [writes]\n\t,vfs.[num_of_bytes_written] AS [write_bytes]\n\t,vfs.io_stall_queued_read_ms AS [rg_read_stall_ms]\n\t,vfs.io_stall_queued_write_ms AS [rg_write_stall_ms]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs\nLEFT OUTER JOIN sys.master_files AS mf WITH (NOLOCK)\n\tON vfs.[database_id] = mf.[database_id]\n\tAND vfs.[file_id] = mf.[file_id]\nWHERE\n\tvfs.[database_id] < 32760\n`\n\nconst sqlAzureMIMemoryClerks = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_memory_clerks' AS [measurement]\n\t,REPLACE(@@SERVERNAME, '\\', ':') AS [sql_instance]\n\t,mc.[type] AS [clerk_type]\n\t,SUM(mc.[pages_kb]) AS [size_kb]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.[dm_os_memory_clerks] AS mc WITH (NOLOCK)\nGROUP BY\n\t mc.[type]\nHAVING\n\tSUM(mc.[pages_kb]) >= 1024\nOPTION(RECOMPILE);\n`\n\nconst sqlAzureMIOsWaitStats = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_waitstats' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,ws.[wait_type]\n\t,[wait_time_ms]\n\t,[wait_time_ms] - [signal_wait_time_ms] AS [resource_wait_ms]\n\t,[signal_wait_time_ms]\n\t,[max_wait_time_ms]\n\t,[waiting_tasks_count]\n\t,CASE\n\t\tWHEN ws.[wait_type] LIKE 'SOS_SCHEDULER_YIELD' then 'CPU'\n\t\tWHEN ws.[wait_type] = 'THREADPOOL' THEN 'Worker Thread'\n\t\tWHEN ws.[wait_type] LIKE 'LCK[_]%' THEN 'Lock'\n\t\tWHEN ws.[wait_type] LIKE 'LATCH[_]%' THEN 'Latch'\n\t\tWHEN ws.[wait_type] LIKE 'PAGELATCH[_]%' THEN 'Buffer Latch'\n\t\tWHEN ws.[wait_type] LIKE 'PAGEIOLATCH[_]%' THEN 'Buffer IO'\n\t\tWHEN ws.[wait_type] LIKE 'RESOURCE_SEMAPHORE_QUERY_COMPILE%' THEN 'Compilation'\n\t\tWHEN ws.[wait_type] LIKE 'CLR[_]%' or ws.[wait_type] like 'SQLCLR%' THEN 'SQL CLR'\n\t\tWHEN ws.[wait_type] LIKE 'DBMIRROR_%' THEN 'Mirroring'\n\t\tWHEN ws.[wait_type] LIKE 'DTC[_]%' or ws.[wait_type] LIKE 'DTCNEW%' or ws.[wait_type] LIKE 'TRAN_%'\n     \t\tor ws.[wait_type] LIKE 'XACT%' or ws.[wait_type] like 'MSQL_XACT%' THEN 'Transaction'\n\t\tWHEN ws.[wait_type] LIKE 'SLEEP[_]%'\n\t\t\tor ws.[wait_type] IN (\n\t\t\t\t'LAZYWRITER_SLEEP', 'SQLTRACE_BUFFER_FLUSH', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',\n\t\t\t\t'SQLTRACE_WAIT_ENTRIES', 'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT',\n\t\t\t\t'REQUEST_FOR_DEADLOCK_SEARCH', 'LOGMGR_QUEUE', 'ONDEMAND_TASK_QUEUE',\n\t\t\t\t'CHECKPOINT_QUEUE', 'XE_TIMER_EVENT') THEN 'Idle'\n\t\tWHEN ws.[wait_type] IN(\n\t\t\t'ASYNC_IO_COMPLETION','BACKUPIO','CHKPT','WRITE_COMPLETION',\n\t\t\t'IO_QUEUE_LIMIT', 'IO_RETRY') THEN 'Other Disk IO'\n\t\tWHEN ws.[wait_type] LIKE 'PREEMPTIVE_%' THEN 'Preemptive'\n\t\tWHEN ws.[wait_type] LIKE 'BROKER[_]%' THEN 'Service Broker'\n\t\tWHEN ws.[wait_type] IN (\n\t\t\t'WRITELOG','LOGBUFFER','LOGMGR_RESERVE_APPEND',\n\t\t\t'LOGMGR_FLUSH', 'LOGMGR_PMM_LOG')  THEN 'Tran Log IO'\n\t\tWHEN ws.[wait_type] LIKE 'LOG_RATE%' then 'Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'HADR_THROTTLE[_]%'\n\t\t\tor ws.[wait_type] = 'THROTTLE_LOG_RATE_LOG_STORAGE' THEN 'HADR Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'RBIO_RG%' or ws.[wait_type] like 'WAIT_RBIO_RG%' then 'VLDB Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'RBIO[_]%' or ws.[wait_type] like 'WAIT_RBIO[_]%' then 'VLDB RBIO'\n\t\tWHEN ws.[wait_type] IN(\n\t\t\t'ASYNC_NETWORK_IO','EXTERNAL_SCRIPT_NETWORK_IOF',\n\t\t\t'NET_WAITFOR_PACKET','PROXY_NETWORK_IO') THEN 'Network IO'\n\t\tWHEN ws.[wait_type] IN ( 'CXPACKET', 'CXCONSUMER')\n\t\t\tor ws.[wait_type] like 'HT%' or ws.[wait_type] like 'BMP%'\n\t\t\tor ws.[wait_type] like 'BP%' THEN 'Parallelism'\n\t\tWHEN ws.[wait_type] IN(\n\t\t\t'CMEMTHREAD','CMEMPARTITIONED','EE_PMOLOCK','EXCHANGE',\n\t\t\t'RESOURCE_SEMAPHORE','MEMORY_ALLOCATION_EXT',\n\t\t\t'RESERVED_MEMORY_ALLOCATION_EXT', 'MEMORY_GRANT_UPDATE')  THEN 'Memory'\n\t\tWHEN ws.[wait_type] IN ('WAITFOR','WAIT_FOR_RESULTS')  THEN 'User Wait'\n\t\tWHEN ws.[wait_type] LIKE 'HADR[_]%' or ws.[wait_type] LIKE 'PWAIT_HADR%'\n\t\t\tor ws.[wait_type] LIKE 'REPLICA[_]%' or ws.[wait_type] LIKE 'REPL_%'\n\t\t\tor ws.[wait_type] LIKE 'SE_REPL[_]%'\n\t\t\tor ws.[wait_type] LIKE 'FCB_REPLICA%' THEN 'Replication'\n\t\tWHEN ws.[wait_type] LIKE 'SQLTRACE[_]%'\n\t\t\tor ws.[wait_type] IN (\n\t\t\t\t'TRACEWRITE', 'SQLTRACE_LOCK', 'SQLTRACE_FILE_BUFFER', 'SQLTRACE_FILE_WRITE_IO_COMPLETION',\n\t\t\t\t'SQLTRACE_FILE_READ_IO_COMPLETION', 'SQLTRACE_PENDING_BUFFER_WRITERS', 'SQLTRACE_SHUTDOWN',\n\t\t\t\t'QUERY_TRACEOUT', 'TRACE_EVTNOTIF') THEN 'Tracing'\n\t\tWHEN ws.[wait_type] IN (\n\t\t\t'FT_RESTART_CRAWL', 'FULLTEXT GATHERER', 'MSSEARCH', 'FT_METADATA_MUTEX',\n  \t\t\t'FT_IFTSHC_MUTEX', 'FT_IFTSISM_MUTEX', 'FT_IFTS_RWLOCK', 'FT_COMPROWSET_RWLOCK',\n  \t\t\t'FT_MASTER_MERGE', 'FT_PROPERTYLIST_CACHE', 'FT_MASTER_MERGE_COORDINATOR',\n  \t\t\t'PWAIT_RESOURCE_SEMAPHORE_FT_PARALLEL_QUERY_SYNC') THEN 'Full Text Search'\n \t\tELSE 'Other'\n\tEND as [wait_category]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.dm_os_wait_stats AS ws WITH (NOLOCK)\nWHERE\n\tws.[wait_type] NOT IN (\n        N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP',\n        N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE',\n        N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE',\n        N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_QUEUE',\n        N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE',\n        N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX',\n        N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT',\n        N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE',\n        N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE',\n        N'MEMORY_ALLOCATION_EXT', N'ONDEMAND_TASK_QUEUE',\n        N'PARALLEL_REDO_WORKER_WAIT_WORK',\n        N'PREEMPTIVE_HADR_LEASE_MECHANISM', N'PREEMPTIVE_SP_SERVER_DIAGNOSTICS',\n        N'PREEMPTIVE_OS_LIBRARYOPS', N'PREEMPTIVE_OS_COMOPS', N'PREEMPTIVE_OS_CRYPTOPS',\n        N'PREEMPTIVE_OS_PIPEOPS','PREEMPTIVE_OS_GENERICOPS', N'PREEMPTIVE_OS_VERIFYTRUST',\n        N'PREEMPTIVE_OS_DEVICEOPS',\n        N'PREEMPTIVE_XE_CALLBACKEXECUTE', N'PREEMPTIVE_XE_DISPATCHER',\n        N'PREEMPTIVE_XE_GETTARGETSTATE', N'PREEMPTIVE_XE_SESSIONCOMMIT',\n        N'PREEMPTIVE_XE_TARGETINIT', N'PREEMPTIVE_XE_TARGETFINALIZE',\n        N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'PWAIT_DIRECTLOGCONSUMER_GETNEXT',\n        N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',\n        N'QDS_ASYNC_QUEUE',\n        N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH',\n        N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP',\n        N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY',\n        N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK',\n        N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP',\n\t\tN'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',\n        N'SQLTRACE_WAIT_ENTRIES',\n        N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT',\n        N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE',\n        N'XE_BUFFERMGR_ALLPROCESSED_EVENT', N'XE_DISPATCHER_JOIN',\n        N'XE_DISPATCHER_WAIT', N'XE_LIVE_TARGET_TVF', N'XE_TIMER_EVENT',\n        N'SOS_WORK_DISPATCHER','RESERVED_MEMORY_ALLOCATION_EXT','SQLTRACE_WAIT_ENTRIES',\n\t\tN'RBIO_COMM_RETRY')\nAND [waiting_tasks_count] > 10\nAND [wait_time_ms] > 100;\n`\n\nconst sqlAzureMIPerformanceCounters = `\nSET DEADLOCK_PRIORITY -10;\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nDECLARE @PCounters TABLE\n(\n\t[object_name] nvarchar(128),\n\t[counter_name] nvarchar(128),\n\t[instance_name] nvarchar(128),\n\t[cntr_value] bigint,\n\t[cntr_type] INT ,\n\tPrimary Key([object_name],[counter_name],[instance_name])\n);\n\nWITH PerfCounters AS (\n\tSELECT DISTINCT\n\t RTrim(spi.[object_name]) [object_name]\n\t,RTrim(spi.[counter_name]) [counter_name]\n\t,CASE WHEN (\n\t\t   RTRIM(spi.[object_name]) LIKE '%:Databases'\n\t\tOR RTRIM(spi.[object_name]) LIKE '%:Database Replica'\n\t\tOR RTRIM(spi.[object_name]) LIKE '%:Catalog Metadata'\n\t\tOR RTRIM(spi.[object_name]) LIKE '%:Query Store'\n\t\tOR RTRIM(spi.[object_name]) LIKE '%:Columnstore'\n\t\tOR RTRIM(spi.[object_name]) LIKE '%:Advanced Analytics')\n\t\tAND TRY_CONVERT([uniqueidentifier], spi.[instance_name]) IS NOT NULL -- for cloud only\n\t\t\tTHEN ISNULL(d.[name],RTRIM(spi.instance_name)) -- Elastic Pools counters exist for all databases but sys.databases only has current DB value\n\t\tWHEN\n\t\t\tRTRIM([object_name]) LIKE '%:Availability Replica'\n\t\t\tAND TRY_CONVERT([uniqueidentifier], spi.[instance_name]) IS NOT NULL -- for cloud only\n\t\t\t\tTHEN ISNULL(d.[name],RTRIM(spi.[instance_name])) + RTRIM(SUBSTRING(spi.[instance_name], 37, LEN(spi.[instance_name])))\n\t\tELSE RTRIM(spi.instance_name)\n\tEND AS [instance_name]\n\t,CAST(spi.[cntr_value] AS BIGINT) AS [cntr_value]\n\t,spi.[cntr_type]\n\tFROM sys.dm_os_performance_counters AS spi\n\tLEFT JOIN sys.databases AS d\n\t\tON LEFT(spi.[instance_name], 36) -- some instance_name values have an additional identifier appended after the GUID\n\t\t= CASE\n\t\t\t/*in SQL DB standalone, physical_database_name for master is the GUID of the user database*/\n\t\t\tWHEN d.[name] = 'master' AND TRY_CONVERT([uniqueidentifier], d.[physical_database_name]) IS NOT NULL\n\t\t\t\tTHEN d.[name]\n\t\t\tELSE d.[physical_database_name]\n\t\tEND\n\tWHERE\n\t\tcounter_name IN (\n\t\t\t 'SQL Compilations/sec'\n\t\t\t,'SQL Re-Compilations/sec'\n\t\t\t,'User Connections'\n\t\t\t,'Batch Requests/sec'\n\t\t\t,'Logouts/sec'\n\t\t\t,'Logins/sec'\n\t\t\t,'Processes blocked'\n\t\t\t,'Latch Waits/sec'\n\t\t\t,'Full Scans/sec'\n\t\t\t,'Index Searches/sec'\n\t\t\t,'Page Splits/sec'\n\t\t\t,'Page lookups/sec'\n\t\t\t,'Page reads/sec'\n\t\t\t,'Page writes/sec'\n\t\t\t,'Readahead pages/sec'\n\t\t\t,'Lazy writes/sec'\n\t\t\t,'Checkpoint pages/sec'\n\t\t\t,'Table Lock Escalations/sec'\n\t\t\t,'Page life expectancy'\n\t\t\t,'Log File(s) Size (KB)'\n\t\t\t,'Log File(s) Used Size (KB)'\n\t\t\t,'Data File(s) Size (KB)'\n\t\t\t,'Transactions/sec'\n\t\t\t,'Write Transactions/sec'\n\t\t\t,'Active Transactions'\n\t\t\t,'Log Growths'\n\t\t\t,'Active Temp Tables'\n\t\t\t,'Logical Connections'\n\t\t\t,'Temp Tables Creation Rate'\n\t\t\t,'Temp Tables For Destruction'\n\t\t\t,'Free Space in tempdb (KB)'\n\t\t\t,'Version Store Size (KB)'\n\t\t\t,'Memory Grants Pending'\n\t\t\t,'Memory Grants Outstanding'\n\t\t\t,'Free list stalls/sec'\n\t\t\t,'Buffer cache hit ratio'\n\t\t\t,'Buffer cache hit ratio base'\n\t\t\t,'Backup/Restore Throughput/sec'\n\t\t\t,'Total Server Memory (KB)'\n\t\t\t,'Target Server Memory (KB)'\n\t\t\t,'Log Flushes/sec'\n\t\t\t,'Log Flush Wait Time'\n\t\t\t,'Memory broker clerk size'\n\t\t\t,'Log Bytes Flushed/sec'\n\t\t\t,'Bytes Sent to Replica/sec'\n\t\t\t,'Log Send Queue'\n\t\t\t,'Bytes Sent to Transport/sec'\n\t\t\t,'Sends to Replica/sec'\n\t\t\t,'Bytes Sent to Transport/sec'\n\t\t\t,'Sends to Transport/sec'\n\t\t\t,'Bytes Received from Replica/sec'\n\t\t\t,'Receives from Replica/sec'\n\t\t\t,'Flow Control Time (ms/sec)'\n\t\t\t,'Flow Control/sec'\n\t\t\t,'Resent Messages/sec'\n\t\t\t,'Redone Bytes/sec'\n\t\t\t,'XTP Memory Used (KB)'\n\t\t\t,'Transaction Delay'\n\t\t\t,'Log Bytes Received/sec'\n\t\t\t,'Log Apply Pending Queue'\n\t\t\t,'Redone Bytes/sec'\n\t\t\t,'Recovery Queue'\n\t\t\t,'Log Apply Ready Queue'\n\t\t\t,'CPU usage %'\n\t\t\t,'CPU usage % base'\n\t\t\t,'Queued requests'\n\t\t\t,'Requests completed/sec'\n\t\t\t,'Blocked tasks'\n\t\t\t,'Active memory grant amount (KB)'\n\t\t\t,'Disk Read Bytes/sec'\n\t\t\t,'Disk Read IO Throttled/sec'\n\t\t\t,'Disk Read IO/sec'\n\t\t\t,'Disk Write Bytes/sec'\n\t\t\t,'Disk Write IO Throttled/sec'\n\t\t\t,'Disk Write IO/sec'\n\t\t\t,'Used memory (KB)'\n\t\t\t,'Forwarded Records/sec'\n\t\t\t,'Background Writer pages/sec'\n\t\t\t,'Percent Log Used'\n\t\t\t,'Log Send Queue KB'\n\t\t\t,'Redo Queue KB'\n\t\t\t,'Mirrored Write Transactions/sec'\n\t\t\t,'Group Commit Time'\n\t\t\t,'Group Commits/Sec'\n\t\t\t,'Workfiles Created/sec'\n\t\t\t,'Worktables Created/sec'\n\t\t\t,'Distributed Query'\n\t\t\t,'DTC calls'\n\t\t\t,'Query Store CPU usage'\n\t\t) OR (\n\t\t\tspi.[object_name] LIKE '%User Settable%'\n\t\t\tOR spi.[object_name] LIKE '%SQL Errors%'\n\t\t\tOR spi.[object_name] LIKE '%Batch Resp Statistics%'\n\t\t) OR (\n\t\t\tspi.[instance_name] IN ('_Total')\n\t\t\tAND spi.[counter_name] IN (\n\t\t\t\t 'Lock Timeouts/sec'\n\t\t\t\t,'Lock Timeouts (timeout > 0)/sec'\n\t\t\t\t,'Number of Deadlocks/sec'\n\t\t\t\t,'Lock Waits/sec'\n\t\t\t\t,'Latch Waits/sec'\n\t\t\t)\n\t\t)\n)\n\nINSERT INTO @PCounters select * from PerfCounters\n\nSELECT\n\t'sqlserver_performance' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,pc.[object_name] AS [object]\n\t,pc.[counter_name] AS [counter]\n\t,CASE pc.[instance_name]\n\t\tWHEN '_Total' THEN 'Total'\n\t\tELSE ISNULL(pc.[instance_name],'')\n\tEND AS [instance]\n\t,CAST(CASE WHEN pc.[cntr_type] = 537003264 AND pc1.[cntr_value] > 0 THEN (pc.[cntr_value] * 1.0) / (pc1.[cntr_value] * 1.0) * 100 ELSE pc.[cntr_value] END AS float(10)) AS [value]\n\t,cast(pc.[cntr_type] as varchar(25)) as [counter_type]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nfrom @PCounters pc\nLEFT OUTER JOIN @PCounters AS pc1\n\tON (\n\t\tpc.[counter_name] = REPLACE(pc1.[counter_name],' base','')\n\t\tOR pc.[counter_name] = REPLACE(pc1.[counter_name],' base',' (ms)')\n\t)\n\tAND pc.[object_name] = pc1.[object_name]\n\tAND pc.[instance_name] = pc1.[instance_name]\n\tAND pc1.[counter_name] LIKE '%base'\nWHERE\n\tpc.[counter_name] NOT LIKE '% base'\nOPTION (RECOMPILE);\n`\n\nconst sqlAzureMIRequests string = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\n\n\nBEGIN TRY\n\tSELECT\n\t\t [measurement],[sql_instance],[database_name],[session_id]\n\t\t,ISNULL([request_id],0) AS [request_id]\n\t\t,[blocking_session_id],[status],[cpu_time_ms]\n\t\t,[total_elapsed_time_ms],[logical_reads],[writes]\n\t\t,[command],[wait_time_ms],[wait_type]\n\t\t,[wait_resource],[program_name]\n\t\t,[host_name],[nt_user_name],[login_name]\n\t\t,[transaction_isolation_level],[granted_query_memory_pages],[percent_complete]\n\t\t,[statement_text],[objectid],[stmt_object_name]\n\t\t,[stmt_db_name],[query_hash],[query_plan_hash]\n\t\t,replica_updateability\n\t\t,[session_db_name],[open_transaction]\n\tFROM (\n\t\tSELECT\n\t\t\t'sqlserver_requests' AS [measurement]\n\t\t\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t\t\t,DB_NAME() as [database_name]\n\t\t\t,s.[session_id]\n\t\t\t,r.[request_id]\n\t\t\t,DB_NAME(COALESCE(r.[database_id], s.[database_id])) AS [session_db_name]\n\t\t\t,COALESCE(r.[status], s.[status]) AS [status]\n\t\t\t,COALESCE(r.[cpu_time], s.[cpu_time]) AS [cpu_time_ms]\n\t\t\t,COALESCE(r.[total_elapsed_time], s.[total_elapsed_time]) AS [total_elapsed_time_ms]\n\t\t\t,COALESCE(r.[logical_reads], s.[logical_reads]) AS [logical_reads]\n\t\t\t,COALESCE(r.[writes], s.[writes]) AS [writes]\n\t\t\t,r.[command]\n\t\t\t,r.[wait_time] AS [wait_time_ms]\n\t\t\t,r.[wait_type]\n\t\t\t,r.[wait_resource]\n\t\t\t,NULLIF(r.[blocking_session_id],0) AS [blocking_session_id]\n\t\t\t,s.[program_name]\n\t\t\t,s.[host_name]\n\t\t\t,s.[nt_user_name]\n\t\t\t,s.[login_name]\n\t\t\t,COALESCE(r.[open_transaction_count], s.[open_transaction_count]) AS [open_transaction]\n\t\t\t,LEFT (CASE COALESCE(r.[transaction_isolation_level], s.[transaction_isolation_level])\n\t\t\t\tWHEN 0 THEN '0-Read Committed'\n\t\t\t\tWHEN 1 THEN '1-Read Uncommitted (NOLOCK)'\n\t\t\t\tWHEN 2 THEN '2-Read Committed'\n\t\t\t\tWHEN 3 THEN '3-Repeatable Read'\n\t\t\t\tWHEN 4 THEN '4-Serializable'\n\t\t\t\tWHEN 5 THEN '5-Snapshot'\n\t\t\t\tELSE CONVERT (varchar(30), r.[transaction_isolation_level]) + '-UNKNOWN'\n\t\t\tEND, 30) AS [transaction_isolation_level]\n\t\t\t,r.[granted_query_memory] AS [granted_query_memory_pages]\n\t\t\t,r.[percent_complete]\n\t\t\t,SUBSTRING(\n\t\t\t\tqt.[text],\n\t\t\t\tr.[statement_start_offset] / 2 + 1,\n\t\t\t\t(CASE WHEN r.[statement_end_offset] = -1\n\t\t\t\t\tTHEN DATALENGTH(qt.[text])\n\t\t\t\t\tELSE r.[statement_end_offset]\n\t\t\t\tEND - r.[statement_start_offset]) / 2 + 1\n\t\t\t) AS [statement_text]\n\t\t\t,qt.[objectid]\n\t\t\t,QUOTENAME(OBJECT_SCHEMA_NAME(qt.[objectid], qt.[dbid])) + '.' +  QUOTENAME(OBJECT_NAME(qt.[objectid], qt.[dbid])) as [stmt_object_name]\n\t\t\t,DB_NAME(qt.[dbid]) AS [stmt_db_name]\n\t\t\t,CONVERT(varchar(20),r.[query_hash],1) AS [query_hash]\n\t\t\t,CONVERT(varchar(20),r.[query_plan_hash],1) AS [query_plan_hash]\n\t\t\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\n\t\t\t,s.[is_user_process]\n\t\t\t,[blocking_or_blocked] = COUNT(*) OVER(PARTITION BY ISNULL(NULLIF(r.[blocking_session_id], 0),s.[session_id]))\n\t\tFROM sys.dm_exec_sessions AS s\n\t\tLEFT OUTER JOIN sys.dm_exec_requests AS r\n\t\t\tON s.[session_id] = r.[session_id]\n\t\tOUTER APPLY sys.dm_exec_sql_text(r.[sql_handle]) AS qt\n\t) AS data\n\tWHERE\n\t\t   [blocking_or_blocked] > 1 --Always include blocking or blocked sessions/requests\n\t\tOR [open_transaction] >= 1   --Always include sessions with open transactions\n\t\tOR (\n\t\t\t[request_id] IS NOT NULL\t--A request must exists\n\t\t\tAND (\t--Always fetch user process (in any state), fetch system process only if active\n\t\t\t\t[is_user_process] = 1\n\t\t\t\tOR [status] COLLATE Latin1_General_BIN NOT IN ('background', 'sleeping')\n\t\t\t)\n\t\t\tAND [session_id] <> @@SPID\n\t\t)\n\tOPTION(MAXDOP 1);\nEND TRY\nBEGIN CATCH\n    IF (ERROR_NUMBER() <> 976) --Avoid possible errors from secondary replica\n        THROW;\nEND CATCH\n`\n\nconst sqlAzureMISchedulers string = `\nIF SERVERPROPERTY('EngineEdition') <> 8 BEGIN /*not Azure Managed Instance*/\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure Managed Instance. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_schedulers' AS [measurement]\n\t,REPLACE(@@SERVERNAME, '\\', ':') AS [sql_instance]\n\t,CAST(s.[scheduler_id] AS VARCHAR(4)) AS [scheduler_id]\n\t,CAST(s.[cpu_id] AS VARCHAR(4)) AS [cpu_id]\n\t,s.[is_online]\n\t,s.[is_idle]\n\t,s.[preemptive_switches_count]\n\t,s.[context_switches_count]\n\t,s.[current_tasks_count]\n\t,s.[runnable_tasks_count]\n\t,s.[current_workers_count]\n\t,s.[active_workers_count]\n\t,s.[work_queue_count]\n\t,s.[pending_disk_io_count]\n\t,s.[load_factor]\n\t,s.[yield_count]\n\t,s.[total_cpu_usage_ms]\n\t,s.[total_scheduler_delay_ms]\n\t,DATABASEPROPERTYEX(DB_NAME(), 'Updateability') as replica_updateability\nFROM sys.dm_os_schedulers AS s\n`\n"
  },
  {
    "path": "plugins/inputs/sqlserver/azuresqlpoolqueries.go",
    "content": "//nolint:lll // conditionally long lines allowed\npackage sqlserver\n\nimport (\n\t_ \"github.com/microsoft/go-mssqldb\" // go-mssqldb initialization\n)\n\n// ------------------------------------------------------------------------------------------------\n// ------------------ Azure Sql Elastic Pool ------------------------------------------------------\n// ------------------------------------------------------------------------------------------------\nconst sqlAzurePoolResourceStats = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT TOP(1)\n   'sqlserver_pool_resource_stats' AS [measurement]\n  ,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n  ,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n  ,[snapshot_time]\n  ,cast([cap_vcores_used_percent] as float) AS [avg_cpu_percent]\n  ,cast([avg_data_io_percent] as float) AS [avg_data_io_percent]\n  ,cast([avg_log_write_percent] as float) AS [avg_log_write_percent]\n  ,cast([avg_storage_percent] as float) AS [avg_storage_percent]\n  ,cast([max_worker_percent] as float) AS [max_worker_percent]\n  ,cast([max_session_percent] as float) AS [max_session_percent]\n  ,cast([max_data_space_kb]/1024. as int) AS [storage_limit_mb]\n  ,cast([avg_instance_cpu_percent] as float) AS [avg_instance_cpu_percent]\n  ,cast([avg_allocated_storage_percent] as float) AS [avg_allocated_storage_percent]\nFROM\n  sys.dm_resource_governor_resource_pools_history_ex\nWHERE\n  [name] = 'SloSharedPool1'\nORDER BY\n  [snapshot_time] DESC;\n`\n\nconst sqlAzurePoolResourceGovernance = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_pool_resource_governance' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n\t,[slo_name]\n\t,[dtu_limit]\n\t,[cpu_limit]\n\t,[max_cpu]\n\t,[cap_cpu]\n\t,[max_db_memory]\n\t,[max_db_max_size_in_mb]\n\t,[db_file_growth_in_mb]\n\t,[log_size_in_mb]\n\t,[instance_cap_cpu]\n\t,[instance_max_log_rate]\n\t,[instance_max_worker_threads]\n\t,[checkpoint_rate_mbps]\n\t,[checkpoint_rate_io]\n\t,[primary_group_max_workers]\n\t,[primary_min_log_rate]\n\t,[primary_max_log_rate]\n\t,[primary_group_min_io]\n\t,[primary_group_max_io]\n\t,[primary_group_min_cpu]\n\t,[primary_group_max_cpu]\n\t,[primary_pool_max_workers]\n\t,[pool_max_io]\n\t,[volume_local_iops]\n\t,[volume_managed_xstore_iops]\n\t,[volume_external_xstore_iops]\n\t,[volume_type_local_iops]\n\t,[volume_type_managed_xstore_iops]\n\t,[volume_type_external_xstore_iops]\n\t,[volume_pfs_iops]\n\t,[volume_type_pfs_iops]\nFROM\n\tsys.dm_user_db_resource_governance\nWHERE database_id = DB_ID();\n`\n\nconst sqlAzurePoolDatabaseIO = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_database_io' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n\t,CASE\n\t\tWHEN vfs.[database_id] = 1 THEN 'master'\n\t\tWHEN vfs.[database_id] = 2 THEN 'tempdb'\n\t\tWHEN vfs.[database_id] = 3 THEN 'model'\n\t\tWHEN vfs.[database_id] = 4 THEN 'msdb'\n\t\tELSE gov.[database_name]\n\t END AS [database_name]\n\t,vfs.[database_id]\n\t,vfs.[file_id]\n\t,CASE\n\t\tWHEN vfs.[file_id] = 2 THEN 'LOG'\n\t\tELSE 'ROWS'\n\t END AS [file_type]\n\t,vfs.[num_of_reads] AS [reads]\n\t,vfs.[num_of_bytes_read] AS [read_bytes]\n\t,vfs.[io_stall_read_ms] AS [read_latency_ms]\n\t,vfs.[io_stall_write_ms] AS [write_latency_ms]\n\t,vfs.[num_of_writes] AS [writes]\n\t,vfs.[num_of_bytes_written] AS [write_bytes]\n\t,vfs.[io_stall_queued_read_ms] AS [rg_read_stall_ms]\n\t,vfs.[io_stall_queued_write_ms] AS [rg_write_stall_ms]\n\t,[size_on_disk_bytes]\n\t,ISNULL([size_on_disk_bytes],0)/(1024*1024) AS [size_on_disk_mb]\nFROM\n\tsys.dm_io_virtual_file_stats(NULL,NULL) AS vfs\nLEFT OUTER JOIN\n\tsys.dm_user_db_resource_governance AS gov\nON vfs.[database_id] = gov.[database_id];\n`\n\nconst sqlAzurePoolOsWaitStats = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_waitstats' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n\t,[wait_type]\n\t,[waiting_tasks_count]\n\t,[wait_time_ms]\n\t,[max_wait_time_ms]\n\t,[signal_wait_time_ms]\n\t,[wait_time_ms]-[signal_wait_time_ms] AS [resource_wait_ms]\n\t,CASE\n\t\tWHEN ws.[wait_type] LIKE 'SOS_SCHEDULER_YIELD' THEN 'CPU'\n\t\tWHEN ws.[wait_type] = 'THREADPOOL' THEN 'Worker Thread'\n\t\tWHEN ws.[wait_type] LIKE 'LCK[_]%' THEN 'Lock'\n\t\tWHEN ws.[wait_type] LIKE 'LATCH[_]%' THEN 'Latch'\n\t\tWHEN ws.[wait_type] LIKE 'PAGELATCH[_]%' THEN 'Buffer Latch'\n\t\tWHEN ws.[wait_type] LIKE 'PAGEIOLATCH[_]%' THEN 'Buffer IO'\n\t\tWHEN ws.[wait_type] LIKE 'RESOURCE_SEMAPHORE_QUERY_COMPILE%' THEN 'Compilation'\n\t\tWHEN ws.[wait_type] LIKE 'CLR[_]%' OR ws.[wait_type] LIKE 'SQLCLR%' THEN 'SQL CLR'\n\t\tWHEN ws.[wait_type] LIKE 'DBMIRROR_%' THEN 'Mirroring'\n\t\tWHEN ws.[wait_type] LIKE 'DTC[_]%' OR ws.[wait_type] LIKE 'DTCNEW%' OR ws.[wait_type] LIKE 'TRAN_%'\n     \t\tOR ws.[wait_type] LIKE 'XACT%' OR ws.[wait_type] LIKE 'MSQL_XACT%' THEN 'Transaction'\n\t\tWHEN ws.[wait_type] LIKE 'SLEEP[_]%' OR ws.[wait_type] IN (\n\t\t\t'LAZYWRITER_SLEEP', 'SQLTRACE_BUFFER_FLUSH', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',\n\t\t\t'SQLTRACE_WAIT_ENTRIES', 'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT',\n\t\t\t'REQUEST_FOR_DEADLOCK_SEARCH', 'LOGMGR_QUEUE', 'ONDEMAND_TASK_QUEUE',\n\t\t\t'CHECKPOINT_QUEUE', 'XE_TIMER_EVENT') THEN 'Idle'\n\t\tWHEN ws.[wait_type] IN (\n\t\t\t'ASYNC_IO_COMPLETION','BACKUPIO','CHKPT','WRITE_COMPLETION',\n\t\t\t'IO_QUEUE_LIMIT', 'IO_RETRY') THEN 'Other Disk IO'\n\t\tWHEN ws.[wait_type] LIKE 'PREEMPTIVE_%' THEN 'Preemptive'\n\t\tWHEN ws.[wait_type] LIKE 'BROKER[_]%' THEN 'Service Broker'\n\t\tWHEN ws.[wait_type] IN (\n\t\t\t'WRITELOG','LOGBUFFER','LOGMGR_RESERVE_APPEND',\n\t\t\t'LOGMGR_FLUSH', 'LOGMGR_PMM_LOG')  THEN 'Tran Log IO'\n\t\tWHEN ws.[wait_type] LIKE 'LOG_RATE%' then 'Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'HADR_THROTTLE[_]%'\n\t\t\tOR ws.[wait_type] = 'THROTTLE_LOG_RATE_LOG_STORAGE' THEN 'HADR Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'RBIO_RG%' OR ws.[wait_type] LIKE 'WAIT_RBIO_RG%' THEN 'VLDB Log Rate Governor'\n\t\tWHEN ws.[wait_type] LIKE 'RBIO[_]%' OR ws.[wait_type] LIKE 'WAIT_RBIO[_]%' THEN 'VLDB RBIO'\n\t\tWHEN ws.[wait_type] IN(\n\t\t\t'ASYNC_NETWORK_IO','EXTERNAL_SCRIPT_NETWORK_IOF',\n\t\t\t'NET_WAITFOR_PACKET','PROXY_NETWORK_IO') THEN 'Network IO'\n\t\tWHEN ws.[wait_type] IN ( 'CXPACKET', 'CXCONSUMER')\n\t\t\tOR ws.[wait_type] LIKE 'HT%' or ws.[wait_type] LIKE 'BMP%'\n\t\t\tOR ws.[wait_type] LIKE 'BP%' THEN 'Parallelism'\n\t\tWHEN ws.[wait_type] IN(\n\t\t\t'CMEMTHREAD','CMEMPARTITIONED','EE_PMOLOCK','EXCHANGE',\n\t\t\t'RESOURCE_SEMAPHORE','MEMORY_ALLOCATION_EXT',\n\t\t\t'RESERVED_MEMORY_ALLOCATION_EXT', 'MEMORY_GRANT_UPDATE')  THEN 'Memory'\n\t\tWHEN ws.[wait_type] IN ('WAITFOR','WAIT_FOR_RESULTS')  THEN 'User Wait'\n\t\tWHEN ws.[wait_type] LIKE 'HADR[_]%' or ws.[wait_type] LIKE 'PWAIT_HADR%'\n\t\t\tOR ws.[wait_type] LIKE 'REPLICA[_]%' or ws.[wait_type] LIKE 'REPL_%'\n\t\t\tOR ws.[wait_type] LIKE 'SE_REPL[_]%'\n\t\t\tOR ws.[wait_type] LIKE 'FCB_REPLICA%' THEN 'Replication'\n\t\tWHEN ws.[wait_type] LIKE 'SQLTRACE[_]%'\n\t\t\tOR ws.[wait_type] IN (\n\t\t\t\t'TRACEWRITE', 'SQLTRACE_LOCK', 'SQLTRACE_FILE_BUFFER', 'SQLTRACE_FILE_WRITE_IO_COMPLETION',\n\t\t\t\t'SQLTRACE_FILE_READ_IO_COMPLETION', 'SQLTRACE_PENDING_BUFFER_WRITERS', 'SQLTRACE_SHUTDOWN',\n\t\t\t\t'QUERY_TRACEOUT', 'TRACE_EVTNOTIF') THEN 'Tracing'\n\t\tWHEN ws.[wait_type] IN (\n\t\t\t'FT_RESTART_CRAWL', 'FULLTEXT GATHERER', 'MSSEARCH', 'FT_METADATA_MUTEX',\n  \t\t\t'FT_IFTSHC_MUTEX', 'FT_IFTSISM_MUTEX', 'FT_IFTS_RWLOCK', 'FT_COMPROWSET_RWLOCK',\n  \t\t\t'FT_MASTER_MERGE', 'FT_PROPERTYLIST_CACHE', 'FT_MASTER_MERGE_COORDINATOR',\n  \t\t\t'PWAIT_RESOURCE_SEMAPHORE_FT_PARALLEL_QUERY_SYNC') THEN 'Full Text Search'\n \t\tELSE 'Other'\n\t END AS [wait_category]\nFROM sys.dm_os_wait_stats AS ws\nWHERE\n\tws.[wait_type] NOT IN (\n        N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP',\n        N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE',\n        N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE',\n        N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_QUEUE',\n        N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE',\n        N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX',\n        N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT',\n        N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE',\n        N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE',\n        N'MEMORY_ALLOCATION_EXT', N'ONDEMAND_TASK_QUEUE',\n        N'PARALLEL_REDO_WORKER_WAIT_WORK',\n        N'PREEMPTIVE_HADR_LEASE_MECHANISM', N'PREEMPTIVE_SP_SERVER_DIAGNOSTICS',\n        N'PREEMPTIVE_OS_LIBRARYOPS', N'PREEMPTIVE_OS_COMOPS', N'PREEMPTIVE_OS_CRYPTOPS',\n        N'PREEMPTIVE_OS_PIPEOPS','PREEMPTIVE_OS_GENERICOPS', N'PREEMPTIVE_OS_VERIFYTRUST',\n        N'PREEMPTIVE_OS_DEVICEOPS',\n        N'PREEMPTIVE_XE_CALLBACKEXECUTE', N'PREEMPTIVE_XE_DISPATCHER',\n        N'PREEMPTIVE_XE_GETTARGETSTATE', N'PREEMPTIVE_XE_SESSIONCOMMIT',\n        N'PREEMPTIVE_XE_TARGETINIT', N'PREEMPTIVE_XE_TARGETFINALIZE',\n        N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'PWAIT_DIRECTLOGCONSUMER_GETNEXT',\n        N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_ASYNC_QUEUE',\n        N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH',\n        N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP',\n        N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY',\n        N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK',\n        N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP',\n\t\tN'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',\n\t\tN'SQLTRACE_WAIT_ENTRIES', N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN',\n\t\tN'WAIT_XTP_HOST_WAIT', N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE',\n        N'XE_BUFFERMGR_ALLPROCESSED_EVENT', N'XE_DISPATCHER_JOIN',\n        N'XE_DISPATCHER_WAIT', N'XE_LIVE_TARGET_TVF', N'XE_TIMER_EVENT',\n        N'SOS_WORK_DISPATCHER','RESERVED_MEMORY_ALLOCATION_EXT','SQLTRACE_WAIT_ENTRIES',\n\t\tN'RBIO_COMM_RETRY')\nAND [waiting_tasks_count] > 10\nAND [wait_time_ms] > 100;\n`\n\nconst sqlAzurePoolMemoryClerks = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_memory_clerks' AS [measurement]\n\t,REPLACE(@@SERVERNAME, '\\', ':') AS [sql_instance]\n\t,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n\t,mc.[type] AS [clerk_type]\n\t,SUM(mc.[pages_kb]) AS [size_kb]\nFROM\n\tsys.dm_os_memory_clerks AS mc\nGROUP BY\n\tmc.[type]\nHAVING\n\tSUM(mc.[pages_kb]) >= 1024\nOPTION(RECOMPILE);\n`\n\n// Specific case on this query when cntr_type = 537003264 to return a percentage value between 0 and 100\n// cf. https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-performance-counters-transact-sql?view=azuresqldb-current\n// Performance counters where the cntr_type column value is 537003264 display the ratio of a subset to its set as a percentage.\n// For example, the Buffer Manager:Buffer cache hit ratio counter compares the total number of cache hits and the total number of cache lookups.\n// As such, to get a snapshot-like reading of the last second only, you must compare the delta between the current value and the base value (denominator)\n// between two collection points that are one second apart.\n// The corresponding base value is the performance counter Buffer Manager:Buffer cache hit ratio base where the cntr_type column value is 1073939712.\nconst sqlAzurePoolPerformanceCounters = `\nSET DEADLOCK_PRIORITY -10;\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nDECLARE @PCounters TABLE\n(\n\t[object_name] nvarchar(128),\n\t[counter_name] nvarchar(128),\n\t[instance_name] nvarchar(128),\n\t[cntr_value] bigint,\n\t[cntr_type] int\n\tPrimary Key([object_name],[counter_name],[instance_name])\n);\n\nWITH PerfCounters AS (\n\tSELECT DISTINCT\n\t\t RTRIM(pc.[object_name]) AS [object_name]\n\t\t,RTRIM(pc.[counter_name]) AS [counter_name]\n\t\t,ISNULL(gov.[database_name], RTRIM(pc.instance_name)) AS [instance_name]\n\t\t,pc.[cntr_value] AS [cntr_value]\n\t\t,pc.[cntr_type] AS [cntr_type]\n\tFROM sys.dm_os_performance_counters AS pc\n\tLEFT JOIN sys.dm_user_db_resource_governance AS gov\n\tON\n\t\tTRY_CONVERT([uniqueidentifier], pc.[instance_name]) = gov.[physical_database_guid]\n\tWHERE\n\t\t/*filter out unnecessary SQL DB system database counters, other than master and tempdb*/\n\t\tNOT (pc.[object_name] LIKE 'MSSQL%:Databases%' AND pc.[instance_name] IN ('model','model_masterdb','model_userdb','msdb','mssqlsystemresource'))\n\t\tAND\n\t\t(\n\t\t\tpc.[counter_name] IN (\n\t\t\t\t 'SQL Compilations/sec'\n\t\t\t\t,'SQL Re-Compilations/sec'\n\t\t\t\t,'User Connections'\n\t\t\t\t,'Batch Requests/sec'\n\t\t\t\t,'Logouts/sec'\n\t\t\t\t,'Logins/sec'\n\t\t\t\t,'Processes blocked'\n\t\t\t\t,'Latch Waits/sec'\n\t\t\t\t,'Full Scans/sec'\n\t\t\t\t,'Index Searches/sec'\n\t\t\t\t,'Page Splits/sec'\n\t\t\t\t,'Page lookups/sec'\n\t\t\t\t,'Page reads/sec'\n\t\t\t\t,'Page writes/sec'\n\t\t\t\t,'Readahead pages/sec'\n\t\t\t\t,'Lazy writes/sec'\n\t\t\t\t,'Checkpoint pages/sec'\n\t\t\t\t,'Table Lock Escalations/sec'\n\t\t\t\t,'Page life expectancy'\n\t\t\t\t,'Log File(s) Size (KB)'\n\t\t\t\t,'Log File(s) Used Size (KB)'\n\t\t\t\t,'Data File(s) Size (KB)'\n\t\t\t\t,'Transactions/sec'\n\t\t\t\t,'Write Transactions/sec'\n\t\t\t\t,'Active Transactions'\n\t\t\t\t,'Log Growths'\n\t\t\t\t,'Active Temp Tables'\n\t\t\t\t,'Logical Connections'\n\t\t\t\t,'Temp Tables Creation Rate'\n\t\t\t\t,'Temp Tables For Destruction'\n\t\t\t\t,'Free Space in tempdb (KB)'\n\t\t\t\t,'Version Store Size (KB)'\n\t\t\t\t,'Memory Grants Pending'\n\t\t\t\t,'Memory Grants Outstanding'\n\t\t\t\t,'Free list stalls/sec'\n\t\t\t\t,'Buffer cache hit ratio'\n\t\t\t\t,'Buffer cache hit ratio base'\n\t\t\t\t,'Backup/Restore Throughput/sec'\n\t\t\t\t,'Total Server Memory (KB)'\n\t\t\t\t,'Target Server Memory (KB)'\n\t\t\t\t,'Log Flushes/sec'\n\t\t\t\t,'Log Flush Wait Time'\n\t\t\t\t,'Memory broker clerk size'\n\t\t\t\t,'Log Bytes Flushed/sec'\n\t\t\t\t,'Bytes Sent to Replica/sec'\n\t\t\t\t,'Log Send Queue'\n\t\t\t\t,'Bytes Sent to Transport/sec'\n\t\t\t\t,'Sends to Replica/sec'\n\t\t\t\t,'Bytes Sent to Transport/sec'\n\t\t\t\t,'Sends to Transport/sec'\n\t\t\t\t,'Bytes Received from Replica/sec'\n\t\t\t\t,'Receives from Replica/sec'\n\t\t\t\t,'Flow Control Time (ms/sec)'\n\t\t\t\t,'Flow Control/sec'\n\t\t\t\t,'Resent Messages/sec'\n\t\t\t\t,'Redone Bytes/sec'\n\t\t\t\t,'XTP Memory Used (KB)'\n\t\t\t\t,'Transaction Delay'\n\t\t\t\t,'Log Bytes Received/sec'\n\t\t\t\t,'Log Apply Pending Queue'\n\t\t\t\t,'Redone Bytes/sec'\n\t\t\t\t,'Recovery Queue'\n\t\t\t\t,'Log Apply Ready Queue'\n\t\t\t\t,'CPU usage %'\n\t\t\t\t,'CPU usage % base'\n\t\t\t\t,'Queued requests'\n\t\t\t\t,'Requests completed/sec'\n\t\t\t\t,'Blocked tasks'\n\t\t\t\t,'Active memory grant amount (KB)'\n\t\t\t\t,'Disk Read Bytes/sec'\n\t\t\t\t,'Disk Read IO Throttled/sec'\n\t\t\t\t,'Disk Read IO/sec'\n\t\t\t\t,'Disk Write Bytes/sec'\n\t\t\t\t,'Disk Write IO Throttled/sec'\n\t\t\t\t,'Disk Write IO/sec'\n\t\t\t\t,'Used memory (KB)'\n\t\t\t\t,'Forwarded Records/sec'\n\t\t\t\t,'Background Writer pages/sec'\n\t\t\t\t,'Percent Log Used'\n\t\t\t\t,'Log Send Queue KB'\n\t\t\t\t,'Redo Queue KB'\n\t\t\t\t,'Mirrored Write Transactions/sec'\n\t\t\t\t,'Group Commit Time'\n\t\t\t\t,'Group Commits/Sec'\n\t\t\t\t,'Workfiles Created/sec'\n\t\t\t\t,'Worktables Created/sec'\n\t\t\t\t,'Query Store CPU usage'\n\t\t\t) OR (\n\t\t\t\t   pc.[object_name] LIKE '%User Settable%'\n\t\t\t\tOR pc.[object_name] LIKE '%SQL Errors%'\n\t\t\t\tOR pc.[object_name] LIKE '%Batch Resp Statistics%'\n\t\t\t) OR (\n\t\t\t\t    pc.[instance_name] IN ('_Total')\n\t\t\t\tAND pc.[counter_name] IN (\n\t\t\t\t\t 'Lock Timeouts/sec'\n\t\t\t\t\t,'Lock Timeouts (timeout > 0)/sec'\n\t\t\t\t\t,'Number of Deadlocks/sec'\n\t\t\t\t\t,'Lock Waits/sec'\n\t\t\t\t\t,'Latch Waits/sec'\n\t\t\t\t)\n\t\t\t)\n\t\t)\n)\n\nINSERT INTO @PCounters select * from PerfCounters\n\nSELECT\n\t 'sqlserver_performance' AS [measurement]\n\t,REPLACE(@@SERVERNAME,'\\',':') AS [sql_instance]\n\t,pc.[object_name] AS [object]\n\t,pc.[counter_name] AS [counter]\n\t,CASE pc.[instance_name] WHEN '_Total' THEN 'Total' ELSE ISNULL(pc.[instance_name],'') END AS [instance]\n\t,CAST(\n\t\t CASE WHEN pc.[cntr_type] = 537003264 AND base.[cntr_value] > 0\n\t\t\tTHEN (pc.[cntr_value] * 1.0) / (base.[cntr_value] * 1.0) * 100\n\t\t\tELSE pc.[cntr_value]\n\t\t END\n\t AS float) AS [value]\n\t,CAST(pc.[cntr_type] AS varchar(25)) AS [counter_type]\nFROM @PCounters AS pc\nLEFT OUTER JOIN @PCounters AS base\nON\n\tpc.[counter_name] = REPLACE(base.[counter_name],' base','')\n\tAND pc.[object_name] = base.[object_name]\n\tAND pc.[instance_name] = base.[instance_name]\n\tAND base.[cntr_type] = 1073939712\nWHERE\n\tpc.[cntr_type] <> 1073939712\nOPTION(RECOMPILE)\n`\n\nconst sqlAzurePoolSchedulers = `\nIF SERVERPROPERTY('EngineEdition') <> 5\n   OR NOT EXISTS (SELECT 1 FROM sys.database_service_objectives WHERE database_id = DB_ID() AND elastic_pool_name IS NOT NULL) BEGIN\n\tDECLARE @ErrorMessage AS nvarchar(500) = 'Telegraf - Connection string Server:'+ @@SERVERNAME + ',Database:' + DB_NAME() +' is not an Azure SQL database in an elastic pool. Check the database_type parameter in the telegraf configuration.';\n\tRAISERROR (@ErrorMessage,11,1)\n\tRETURN\nEND\n\nSELECT\n\t 'sqlserver_schedulers' AS [measurement]\n\t,REPLACE(@@SERVERNAME, '\\', ':') AS [sql_instance]\n\t,(SELECT [elastic_pool_name] FROM sys.database_service_objectives WHERE database_id = DB_ID()) AS [elastic_pool_name]\n\t,[scheduler_id]\n\t,[cpu_id]\n\t,[status]\n\t,[is_online]\n\t,[is_idle]\n\t,[preemptive_switches_count]\n\t,[context_switches_count]\n\t,[idle_switches_count]\n\t,[current_tasks_count]\n\t,[runnable_tasks_count]\n\t,[current_workers_count]\n\t,[active_workers_count]\n\t,[work_queue_count]\n\t,[pending_disk_io_count]\n\t,[load_factor]\n\t,[failed_to_create_worker]\n\t,[quantum_length_us]\n\t,[yield_count]\n\t,[total_cpu_usage_ms]\n\t,[total_cpu_idle_capped_ms]\n\t,[total_scheduler_delay_ms]\n\t,[ideal_workers_limit]\nFROM\n\tsys.dm_os_schedulers;\n`\n"
  },
  {
    "path": "plugins/inputs/sqlserver/azuresqlpoolqueries_test.go",
    "content": "package sqlserver\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestAzureSQLIntegration_ElasticPool_ResourceStats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolResourceStats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_pool_resource_stats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_pool_resource_stats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_pool_resource_stats\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasField(\"sqlserver_pool_resource_stats\", \"snapshot_time\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_cpu_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_data_io_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_log_write_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_storage_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"max_worker_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"max_session_percent\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_stats\", \"storage_limit_mb\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_instance_cpu_percent\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_stats\", \"avg_allocated_storage_percent\"))\n\n\t// This query should only return one row\n\trequire.Len(t, acc.Metrics, 1)\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_ResourceGovernance_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolResourceGovernance\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_pool_resource_governance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_pool_resource_governance\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_pool_resource_governance\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_pool_resource_governance\", \"slo_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"dtu_limit\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"cpu_limit\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"max_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"cap_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"max_db_memory\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"max_db_max_size_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"db_file_growth_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"log_size_in_mb\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"instance_cap_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"instance_max_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"instance_max_worker_threads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"checkpoint_rate_mbps\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"checkpoint_rate_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_group_max_workers\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_min_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_max_log_rate\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_group_min_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_group_max_io\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_governance\", \"primary_group_min_cpu\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_pool_resource_governance\", \"primary_group_max_cpu\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"primary_pool_max_workers\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"pool_max_io\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_local_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_managed_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_external_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_type_local_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_type_managed_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_type_external_xstore_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_pfs_iops\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_pool_resource_governance\", \"volume_type_pfs_iops\"))\n\n\t// This query should only return one row\n\trequire.Len(t, acc.Metrics, 1)\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_DatabaseIO_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolDatabaseIO\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_database_io\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"database_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"database_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"file_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_database_io\", \"file_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"reads\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"read_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_latency_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"writes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"write_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_read_stall_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"rg_write_stall_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"size_on_disk_bytes\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_database_io\", \"size_on_disk_mb\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_OsWaitStats_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolOsWaitStats\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_waitstats\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"waiting_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"max_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"signal_wait_time_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_waitstats\", \"resource_wait_ms\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_waitstats\", \"wait_category\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_MemoryClerks_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolMemoryClerks\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_memory_clerks\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_memory_clerks\", \"clerk_type\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_memory_clerks\", \"size_kb\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_PerformanceCounters_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolPerformanceCounters\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_performance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"object\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"instance\"))\n\trequire.True(t, acc.HasFloatField(\"sqlserver_performance\", \"value\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_performance\", \"counter_type\"))\n\n\tserver.Stop()\n}\n\nfunc TestAzureSQLIntegration_ElasticPool_Schedulers_Query(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\n\tconnectionString := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\tsl := config.NewSecret([]byte(connectionString))\n\n\tserver := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tIncludeQuery: []string{\"AzureSQLPoolSchedulers\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tDatabaseType: \"AzureSQLPool\",\n\t}\n\n\tvar acc testutil.Accumulator\n\n\trequire.NoError(t, server.Start(&acc))\n\trequire.NoError(t, server.Gather(&acc))\n\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_schedulers\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"sql_instance\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"elastic_pool_name\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"scheduler_id\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"cpu_id\"))\n\trequire.True(t, acc.HasTag(\"sqlserver_schedulers\", \"status\"))\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_online\"))\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"is_idle\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"preemptive_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"context_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"idle_switches_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"runnable_tasks_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"current_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"active_workers_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"work_queue_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"pending_disk_io_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"load_factor\"))\n\trequire.True(t, acc.HasField(\"sqlserver_schedulers\", \"failed_to_create_worker\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"quantum_length_us\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"yield_count\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_cpu_usage_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_cpu_idle_capped_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"total_scheduler_delay_ms\"))\n\trequire.True(t, acc.HasInt64Field(\"sqlserver_schedulers\", \"ideal_workers_limit\"))\n\n\tserver.Stop()\n}\n"
  },
  {
    "path": "plugins/inputs/sqlserver/sqlserver_test.go",
    "content": "package sqlserver\n\nimport (\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/influxdata/telegraf/config\"\n\t\"github.com/influxdata/telegraf/testutil\"\n)\n\nfunc TestSqlServer_QueriesInclusionExclusion(t *testing.T) {\n\tcases := []map[string]interface{}{\n\t\t{\n\t\t\t\"IncludeQuery\": make([]string, 0),\n\t\t\t\"ExcludeQuery\": []string{\"SQLServerWaitStatsCategorized\", \"SQLServerDatabaseIO\", \"SQLServerProperties\", \"SQLServerMemoryClerks\",\n\t\t\t\t\"SQLServerSchedulers\", \"SQLServerVolumeSpace\", \"SQLServerCpu\", \"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\",\n\t\t\t\t\"SQLServerRecentBackups\", \"SQLServerPersistentVersionStore\"},\n\t\t\t\"queries\":      []string{\"SQLServerPerformanceCounters\", \"SQLServerRequests\"},\n\t\t\t\"queriesTotal\": 2,\n\t\t},\n\t\t{\n\t\t\t\"IncludeQuery\": []string{\"SQLServerPerformanceCounters\", \"SQLServerRequests\"},\n\t\t\t\"ExcludeQuery\": []string{\"SQLServerRequests\", \"SQLServerWaitStatsCategorized\", \"SQLServerDatabaseIO\", \"SQLServerVolumeSpace\", \"SQLServerCpu\"},\n\t\t\t\"queries\":      []string{\"SQLServerPerformanceCounters\"},\n\t\t\t\"queriesTotal\": 1,\n\t\t},\n\t}\n\n\tfor _, test := range cases {\n\t\ts := SQLServer{\n\t\t\tDatabaseType: \"SQLServer\",\n\t\t\tIncludeQuery: test[\"IncludeQuery\"].([]string),\n\t\t\tExcludeQuery: test[\"ExcludeQuery\"].([]string),\n\t\t\tLog:          testutil.Logger{},\n\t\t}\n\t\trequire.NoError(t, s.initQueries())\n\t\trequire.Len(t, s.queries, test[\"queriesTotal\"].(int))\n\t\tfor _, query := range test[\"queries\"].([]string) {\n\t\t\trequire.Contains(t, s.queries, query)\n\t\t}\n\t}\n}\n\nfunc TestSqlServer_ParseMetrics(t *testing.T) {\n\tvar acc testutil.Accumulator\n\n\tqueries := make(mapQuery)\n\tqueries[\"PerformanceCounters\"] = query{ScriptName: \"PerformanceCounters\", Script: mockPerformanceCounters, ResultByRow: true}\n\tqueries[\"WaitStatsCategorized\"] = query{ScriptName: \"WaitStatsCategorized\", Script: mockWaitStatsCategorized, ResultByRow: false}\n\tqueries[\"CPUHistory\"] = query{ScriptName: \"CPUHistory\", Script: mockCPUHistory, ResultByRow: false}\n\tqueries[\"DatabaseIO\"] = query{ScriptName: \"DatabaseIO\", Script: mockDatabaseIO, ResultByRow: false}\n\tqueries[\"DatabaseSize\"] = query{ScriptName: \"DatabaseSize\", Script: mockDatabaseSize, ResultByRow: false}\n\tqueries[\"DatabaseStats\"] = query{ScriptName: \"DatabaseStats\", Script: mockDatabaseStats, ResultByRow: false}\n\tqueries[\"DatabaseProperties\"] = query{ScriptName: \"DatabaseProperties\", Script: mockDatabaseProperties, ResultByRow: false}\n\tqueries[\"VolumeSpace\"] = query{ScriptName: \"VolumeSpace\", Script: mockVolumeSpace, ResultByRow: false}\n\tqueries[\"MemoryClerk\"] = query{ScriptName: \"MemoryClerk\", Script: mockMemoryClerk, ResultByRow: false}\n\tqueries[\"PerformanceMetrics\"] = query{ScriptName: \"PerformanceMetrics\", Script: mockPerformanceMetrics, ResultByRow: false}\n\n\tvar headers, mock, row []string\n\tvar tags = make(map[string]string)\n\tvar fields = make(map[string]interface{})\n\n\tfor _, query := range queries {\n\t\tmock = strings.Split(query.Script, \"\\n\")\n\t\tidx := 0\n\n\t\tfor _, line := range mock {\n\t\t\tif idx == 0 { // headers in first line\n\t\t\t\theaders = strings.Split(line, \";\")\n\t\t\t} else {\n\t\t\t\trow = strings.Split(line, \";\")\n\n\t\t\t\tmeasurement := row[0]     // measurement\n\t\t\t\ttags[headers[1]] = row[1] // tag 'servername'\n\t\t\t\ttags[headers[2]] = row[2] // tag 'type'\n\n\t\t\t\tif query.ResultByRow {\n\t\t\t\t\t// set value by converting to float64\n\t\t\t\t\tvalue, err := strconv.ParseFloat(row[3], 64)\n\t\t\t\t\t// require\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t// add value to Accumulator\n\t\t\t\t\tacc.AddFields(measurement,\n\t\t\t\t\t\tmap[string]interface{}{\"value\": value},\n\t\t\t\t\t\ttags, time.Now())\n\t\t\t\t\t// assert\n\t\t\t\t\tacc.AssertContainsTaggedFields(t, measurement, map[string]interface{}{\"value\": value}, tags)\n\t\t\t\t} else {\n\t\t\t\t\t// set fields\n\t\t\t\t\tfor i := 3; i < len(row); i++ {\n\t\t\t\t\t\t// set value by converting to float64\n\t\t\t\t\t\tvalue, err := strconv.ParseFloat(row[i], 64)\n\t\t\t\t\t\t// require\n\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\tfields[headers[i]] = value\n\t\t\t\t\t}\n\t\t\t\t\t// add fields to Accumulator\n\t\t\t\t\tacc.AddFields(measurement, fields, tags, time.Now())\n\t\t\t\t\t// assert\n\t\t\t\t\tacc.AssertContainsTaggedFields(t, measurement, fields, tags)\n\t\t\t\t}\n\t\t\t}\n\t\t\tidx++\n\t\t}\n\t}\n}\n\nfunc TestSqlServerIntegration_MultipleInstance(t *testing.T) {\n\t// Invoke Gather() from two separate configurations and\n\t//  confirm they don't interfere with each other\n\tt.Skip(\"Skipping as unable to open tcp connection with host '127.0.0.1:1433\")\n\n\ttestServer := \"Server=127.0.0.1;Port=1433;User Id=SA;Password=ABCabc01;app name=telegraf;log=1\"\n\tsl := config.NewSecret([]byte(testServer))\n\ts := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tExcludeQuery: []string{\"MemoryClerk\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\tsl2 := config.NewSecret([]byte(testServer))\n\ts2 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2},\n\t\tExcludeQuery: []string{\"DatabaseSize\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tvar acc, acc2 testutil.Accumulator\n\trequire.NoError(t, s.Start(&acc))\n\terr := s.Gather(&acc)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, s2.Start(&acc2))\n\terr = s2.Gather(&acc2)\n\trequire.NoError(t, err)\n\n\t// acc includes size metrics, and excludes memory metrics\n\trequire.False(t, acc.HasMeasurement(\"Memory breakdown (%)\"))\n\trequire.True(t, acc.HasMeasurement(\"Log size (bytes)\"))\n\n\t// acc2 includes memory metrics, and excludes size metrics\n\trequire.True(t, acc2.HasMeasurement(\"Memory breakdown (%)\"))\n\trequire.False(t, acc2.HasMeasurement(\"Log size (bytes)\"))\n}\n\nfunc TestSqlServerIntegration_MultipleInstanceWithHealthMetric(t *testing.T) {\n\t// Invoke Gather() from two separate configurations and\n\t// confirm they don't interfere with each other.\n\t// This test is intentionally similar to TestSqlServer_MultipleInstanceIntegration.\n\t// It is separated to ensure that the health metric code does not affect other metrics\n\tt.Skip(\"Skipping as unable to open tcp connection with host '127.0.0.1:1433\")\n\n\ttestServer := \"Server=127.0.0.1;Port=1433;User Id=SA;Password=ABCabc01;app name=telegraf;log=1\"\n\tsl := config.NewSecret([]byte(testServer))\n\ts := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tDatabaseType: \"SQLServer\",\n\t\tExcludeQuery: []string{\"SQLServerMemoryClerks\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tsl2 := config.NewSecret([]byte(testServer))\n\ts2 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2},\n\t\tDatabaseType: \"SQLServer\",\n\t\tExcludeQuery: []string{\"SQLServerDatabaseIO\"},\n\t\tHealthMetric: true,\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tvar acc, acc2 testutil.Accumulator\n\trequire.NoError(t, s.Start(&acc))\n\terr := s.Gather(&acc)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, s2.Start(&acc2))\n\terr = s2.Gather(&acc2)\n\trequire.NoError(t, err)\n\n\t// acc includes size metrics, and excludes memory metrics and the health metric\n\trequire.False(t, acc.HasMeasurement(healthMetricName))\n\trequire.False(t, acc.HasMeasurement(\"Memory breakdown (%)\"))\n\trequire.True(t, acc.HasMeasurement(\"Log size (bytes)\"))\n\n\t// acc2 includes memory metrics and the health metric, and excludes size metrics\n\trequire.True(t, acc2.HasMeasurement(healthMetricName))\n\trequire.True(t, acc2.HasMeasurement(\"Memory breakdown (%)\"))\n\trequire.False(t, acc2.HasMeasurement(\"Log size (bytes)\"))\n\n\tsqlInstance, database := getConnectionIdentifiers(testServer)\n\ttags := map[string]string{healthMetricInstanceTag: sqlInstance, healthMetricDatabaseTag: database}\n\trequire.True(t, acc2.HasPoint(healthMetricName, tags, healthMetricAttemptedQueries, 9))\n\trequire.True(t, acc2.HasPoint(healthMetricName, tags, healthMetricSuccessfulQueries, 9))\n}\n\nfunc TestSqlServer_HealthMetric(t *testing.T) {\n\tfakeServer1 := \"localhost\\\\fakeinstance1;Database=fakedb1;Password=ABCabc01;\"\n\tfakeServer2 := \"localhost\\\\fakeinstance2;Database=fakedb2;Password=ABCabc01;\"\n\n\tfs1 := config.NewSecret([]byte(fakeServer1))\n\tfs2 := config.NewSecret([]byte(fakeServer2))\n\n\ts1 := &SQLServer{\n\t\tServers:      []*config.Secret{&fs1, &fs2},\n\t\tDatabaseType: \"SQLServer\",\n\t\tIncludeQuery: []string{\"SQLServerDatabaseIO\", \"SQLServerMemoryClerks\"},\n\t\tHealthMetric: true,\n\t\tAuthMethod:   \"connection_string\",\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tsl2 := config.NewSecret([]byte(fakeServer1))\n\ts2 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2},\n\t\tDatabaseType: \"SQLServer\",\n\t\tIncludeQuery: []string{\"SQLServerDatabaseIO\"},\n\t\tAuthMethod:   \"connection_string\",\n\t\tLog:          testutil.Logger{},\n\t}\n\n\t// acc1 should have the health metric because it is specified in the config\n\tvar acc1 testutil.Accumulator\n\trequire.NoError(t, s1.Start(&acc1))\n\trequire.NoError(t, s1.Gather(&acc1))\n\trequire.True(t, acc1.HasMeasurement(healthMetricName))\n\n\t// There will be 2 attempted queries (because we specified 2 queries in IncludeQuery)\n\t// Both queries should fail because the specified SQL instances do not exist\n\tsqlInstance1, database1 := getConnectionIdentifiers(fakeServer1)\n\ttags1 := map[string]string{healthMetricInstanceTag: sqlInstance1, healthMetricDatabaseTag: database1}\n\trequire.True(t, acc1.HasPoint(healthMetricName, tags1, healthMetricAttemptedQueries, 2))\n\trequire.True(t, acc1.HasPoint(healthMetricName, tags1, healthMetricSuccessfulQueries, 0))\n\n\tsqlInstance2, database2 := getConnectionIdentifiers(fakeServer2)\n\ttags2 := map[string]string{healthMetricInstanceTag: sqlInstance2, healthMetricDatabaseTag: database2}\n\trequire.True(t, acc1.HasPoint(healthMetricName, tags2, healthMetricAttemptedQueries, 2))\n\trequire.True(t, acc1.HasPoint(healthMetricName, tags2, healthMetricSuccessfulQueries, 0))\n\n\t// acc2 should not have the health metric because it is not specified in the config\n\tvar acc2 testutil.Accumulator\n\trequire.NoError(t, s2.Start(&acc2))\n\trequire.NoError(t, s2.Gather(&acc2))\n\trequire.False(t, acc2.HasMeasurement(healthMetricName))\n}\n\nfunc TestSqlServer_MultipleInit(t *testing.T) {\n\ts := &SQLServer{\n\t\tDatabaseType: \"SQLServer\",\n\t\tLog:          testutil.Logger{},\n\t}\n\ts2 := &SQLServer{\n\t\tDatabaseType: \"SQLServer\",\n\t\tExcludeQuery: []string{\"SQLServerDatabaseIO\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\trequire.NoError(t, s.initQueries())\n\t_, ok := s.queries[\"SQLServerDatabaseIO\"]\n\trequire.True(t, ok)\n\n\trequire.NoError(t, s2.initQueries())\n\t_, ok = s2.queries[\"SQLServerDatabaseIO\"]\n\trequire.False(t, ok)\n\ts.Stop()\n\ts2.Stop()\n}\n\nfunc TestSqlServer_ConnectionString(t *testing.T) {\n\t// URL format\n\tconnectionString := \"sqlserver://username:password@hostname.database.windows.net?database=databasename&connection+timeout=30\"\n\tsqlInstance, database := getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname.database.windows.net\", sqlInstance)\n\trequire.Equal(t, \"databasename\", database)\n\n\tconnectionString = \"    sqlserver://hostname2.somethingelse.net:1433?database=databasename2\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname2.somethingelse.net\", sqlInstance)\n\trequire.Equal(t, \"databasename2\", database)\n\n\tconnectionString = \"sqlserver://hostname3:1433/SqlInstanceName3?database=databasename3\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname3\\\\SqlInstanceName3\", sqlInstance)\n\trequire.Equal(t, \"databasename3\", database)\n\n\tconnectionString = \" sqlserver://hostname4/SqlInstanceName4?database=databasename4&connection%20timeout=30\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname4\\\\SqlInstanceName4\", sqlInstance)\n\trequire.Equal(t, \"databasename4\", database)\n\n\tconnectionString = \"\tsqlserver://username:password@hostname5?connection%20timeout=30\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname5\", sqlInstance)\n\trequire.Equal(t, emptyDatabaseName, database)\n\n\t// odbc format\n\tconnectionString = \"odbc:server=hostname.database.windows.net;user id=sa;database=master;Trusted_Connection=Yes;Integrated Security=true;\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname.database.windows.net\", sqlInstance)\n\trequire.Equal(t, \"master\", database)\n\n\tconnectionString = \"   odbc:server=192.168.0.1;user id=somethingelse;Integrated Security=true;Database=mydb   \"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"192.168.0.1\", sqlInstance)\n\trequire.Equal(t, \"mydb\", database)\n\n\tconnectionString = \" odbc:Server=servername\\\\instancename;Database=dbname;\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"servername\\\\instancename\", sqlInstance)\n\trequire.Equal(t, \"dbname\", database)\n\n\tconnectionString = \"server=hostname2.database.windows.net;user id=sa;Trusted_Connection=Yes;Integrated Security=true;\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname2.database.windows.net\", sqlInstance)\n\trequire.Equal(t, emptyDatabaseName, database)\n\n\tconnectionString = \"invalid connection string\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, emptySQLInstance, sqlInstance)\n\trequire.Equal(t, emptyDatabaseName, database)\n\n\t// Key/value format\n\tconnectionString = \"  server=hostname.database.windows.net;user id=sa;database=master;Trusted_Connection=Yes;Integrated Security=true\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname.database.windows.net\", sqlInstance)\n\trequire.Equal(t, \"master\", database)\n\n\tconnectionString = \" server=192.168.0.1;user id=somethingelse;Integrated Security=true;Database=mydb;\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"192.168.0.1\", sqlInstance)\n\trequire.Equal(t, \"mydb\", database)\n\n\tconnectionString = \"Server=servername\\\\instancename;Database=dbname;  \"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"servername\\\\instancename\", sqlInstance)\n\trequire.Equal(t, \"dbname\", database)\n\n\tconnectionString = \"server=hostname2.database.windows.net;user id=sa;Trusted_Connection=Yes;Integrated Security=true  \"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, \"hostname2.database.windows.net\", sqlInstance)\n\trequire.Equal(t, emptyDatabaseName, database)\n\n\tconnectionString = \"invalid connection string\"\n\tsqlInstance, database = getConnectionIdentifiers(connectionString)\n\trequire.Equal(t, emptySQLInstance, sqlInstance)\n\trequire.Equal(t, emptyDatabaseName, database)\n}\n\nfunc TestSqlServerIntegration_AGQueriesApplicableForDatabaseTypeSQLServer(t *testing.T) {\n\t// This test case checks where Availability Group (AG / HADR) queries return an output when included for processing for DatabaseType = SQLServer\n\t// And they should not be processed when DatabaseType = AzureSQLDB\n\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING\")\n\t}\n\ttestServer := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING\")\n\n\tsl := config.NewSecret([]byte(testServer))\n\ts := &SQLServer{\n\t\tServers:      []*config.Secret{&sl},\n\t\tDatabaseType: \"SQLServer\",\n\t\tIncludeQuery: []string{\"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tsl2 := config.NewSecret([]byte(testServer))\n\ts2 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2},\n\t\tDatabaseType: \"AzureSQLDB\",\n\t\tIncludeQuery: []string{\"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tvar acc, acc2 testutil.Accumulator\n\trequire.NoError(t, s.Start(&acc))\n\terr := s.Gather(&acc)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, s2.Start(&acc2))\n\terr = s2.Gather(&acc2)\n\trequire.NoError(t, err)\n\n\t// acc includes size metrics, and excludes memory metrics\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_hadr_replica_states\"))\n\trequire.True(t, acc.HasMeasurement(\"sqlserver_hadr_dbreplica_states\"))\n\n\t// acc2 includes memory metrics, and excludes size metrics\n\trequire.False(t, acc2.HasMeasurement(\"sqlserver_hadr_replica_states\"))\n\trequire.False(t, acc2.HasMeasurement(\"sqlserver_hadr_dbreplica_states\"))\n\ts.Stop()\n\ts2.Stop()\n}\n\nfunc TestSqlServerIntegration_AGQueryFieldsOutputBasedOnSQLServerVersion(t *testing.T) {\n\t// This test case checks where Availability Group (AG / HADR) queries return specific fields\n\t// supported by corresponding SQL Server version database being connected to.\n\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping integration test in short mode\")\n\t}\n\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING_2019\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING_2019\")\n\t}\n\tif os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING_2012\") == \"\" {\n\t\tt.Skip(\"Missing environment variable AZURESQL_POOL_CONNECTION_STRING_2012\")\n\t}\n\n\ttestServer2019 := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING_2019\")\n\ttestServer2012 := os.Getenv(\"AZURESQL_POOL_CONNECTION_STRING_2012\")\n\n\tsl2019 := config.NewSecret([]byte(testServer2019))\n\tsl2012 := config.NewSecret([]byte(testServer2012))\n\n\ts2019 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2019},\n\t\tDatabaseType: \"SQLServer\",\n\t\tIncludeQuery: []string{\"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\ts2012 := &SQLServer{\n\t\tServers:      []*config.Secret{&sl2012},\n\t\tDatabaseType: \"SQLServer\",\n\t\tIncludeQuery: []string{\"SQLServerAvailabilityReplicaStates\", \"SQLServerDatabaseReplicaStates\"},\n\t\tLog:          testutil.Logger{},\n\t}\n\n\tvar acc2019, acc2012 testutil.Accumulator\n\trequire.NoError(t, s2019.Start(&acc2019))\n\terr := s2019.Gather(&acc2019)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, s2012.Start(&acc2012))\n\terr = s2012.Gather(&acc2012)\n\trequire.NoError(t, err)\n\n\t// acc2019 includes new HADR query fields\n\trequire.True(t, acc2019.HasField(\"sqlserver_hadr_replica_states\", \"basic_features\"))\n\trequire.True(t, acc2019.HasField(\"sqlserver_hadr_replica_states\", \"is_distributed\"))\n\trequire.True(t, acc2019.HasField(\"sqlserver_hadr_replica_states\", \"seeding_mode\"))\n\trequire.True(t, acc2019.HasTag(\"sqlserver_hadr_replica_states\", \"seeding_mode_desc\"))\n\trequire.True(t, acc2019.HasField(\"sqlserver_hadr_dbreplica_states\", \"is_primary_replica\"))\n\trequire.True(t, acc2019.HasField(\"sqlserver_hadr_dbreplica_states\", \"secondary_lag_seconds\"))\n\n\t// acc2012 does not include new HADR query fields\n\trequire.False(t, acc2012.HasField(\"sqlserver_hadr_replica_states\", \"basic_features\"))\n\trequire.False(t, acc2012.HasField(\"sqlserver_hadr_replica_states\", \"is_distributed\"))\n\trequire.False(t, acc2012.HasField(\"sqlserver_hadr_replica_states\", \"seeding_mode\"))\n\trequire.False(t, acc2012.HasTag(\"sqlserver_hadr_replica_states\", \"seeding_mode_desc\"))\n\trequire.False(t, acc2012.HasField(\"sqlserver_hadr_dbreplica_states\", \"is_primary_replica\"))\n\trequire.False(t, acc2012.HasField(\"sqlserver_hadr_dbreplica_states\", \"secondary_lag_seconds\"))\n\ts2019.Stop()\n\ts2012.Stop()\n}\n\nconst mockPerformanceMetrics = `measurement;servername;type;Point In Time Recovery;Available physical memory (bytes);Average pending disk IO;` +\n\t`Average runnable tasks;Average tasks;Buffer pool rate (bytes/sec);Connection memory per connection (bytes);Memory grant pending;` +\n\t`Page File Usage (%);Page lookup per batch request;Page split per batch request;Readahead per page read;Signal wait (%);` +\n\t`Sql compilation per batch request;Sql recompilation per batch request;Total target memory ratio\nPerformance metrics;WIN8-DEV;Performance metrics;0;6353158144;0;0;7;2773;415061;0;25;229371;130;10;18;188;52;14`\n\nconst mockWaitStatsCategorized = `measurement;servername;type;I/O;Latch;Lock;Network;Service broker;Memory;Buffer;CLR;XEvent;Other;Total\nWait time (ms);WIN8-DEV;Wait stats;0;0;0;0;0;0;0;0;0;0;0\nWait tasks;WIN8-DEV;Wait stats;0;0;0;0;0;0;0;0;0;1;1`\n\nconst mockCPUHistory = `measurement;servername;type;SQL process;External process;SystemIdle\nCPU (%);WIN8-DEV;CPU;0;2;98`\n\nconst mockDatabaseIO = `measurement;servername;type;AdventureWorks2014;Australian;DOC.Azure;master;model;msdb;ngMon;ResumeCloud;tempdb;Total\nLog writes (bytes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;159744;159744\nRows writes (bytes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;0;0\nLog reads (bytes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;0;0\nRows reads (bytes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;6553;6553\nLog (writes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;2;2\nRows (writes/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;0;0\nLog (reads/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;0;0\nRows (reads/sec);WIN8-DEV;Database IO;0;0;0;0;0;0;0;0;0;0`\n\nconst mockDatabaseSize = `measurement;servername;type;AdventureWorks2014;Australian;DOC.Azure;master;model;msdb;ngMon;ResumeCloud;tempdb\nLog size (bytes);WIN8-DEV;Database size;538968064;1048576;786432;2359296;4325376;30212096;1048576;786432;4194304\nRows size (bytes);WIN8-DEV;Database size;2362703872;3211264;26083328;5111808;3342336;24051712;46137344;10551296;1073741824`\n\nconst mockDatabaseProperties string = `measurement;servername;type;AdventureWorks2014;Australian;DOC.Azure;master;model;msdb;ngMon;ResumeCloud;tempdb;total\nRecovery Model FULL;WIN8-DEV;Database properties;1;0;0;0;1;0;0;0;0;2\nRecovery Model BULK_LOGGED;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nRecovery Model SIMPLE;WIN8-DEV;Database properties;0;1;1;1;0;1;1;1;1;7\nState ONLINE;WIN8-DEV;Database properties;1;1;1;1;1;1;1;1;1;9\nState RESTORING;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nState RECOVERING;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nState RECOVERY_PENDING;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nState SUSPECT;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nState EMERGENCY;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0\nState OFFLINE;WIN8-DEV;Database properties;0;0;0;0;0;0;0;0;0;0`\n\nconst mockMemoryClerk = `measurement;servername;type;Buffer pool;Cache (objects);Cache (sql plans);Other\nMemory breakdown (%);WIN8-DEV;Memory clerk;31.30;0.30;14.00;54.50\nMemory breakdown (bytes);WIN8-DEV;Memory clerk;51986432.00;409600.00;23166976.00;90365952.00`\n\nconst mockDatabaseStats = `measurement;servername;type;AdventureWorks2014;Australian;DOC.Azure;master;model;msdb;ngMon;ResumeCloud;tempdb\nLog read latency (ms);WIN8-DEV;Database stats;24;20;11;15;20;46;0;0;3\nLog write latency (ms);WIN8-DEV;Database stats;3;0;0;2;0;1;0;0;0\nRows read latency (ms);WIN8-DEV;Database stats;42;23;52;31;19;29;59;50;71\nRows write latency (ms);WIN8-DEV;Database stats;0;0;0;9;0;0;0;0;0\nRows (average bytes/read);WIN8-DEV;Database stats;62580;58056;59603;63015;62968;63042;58056;58919;176703\nRows (average bytes/write);WIN8-DEV;Database stats;8192;0;0;8192;8192;0;0;0;32768\nLog (average bytes/read);WIN8-DEV;Database stats;69358;50322;74313;41642;19569;29857;45641;18432;143945\nLog (average bytes/write);WIN8-DEV;Database stats;4096;4096;0;5324;4915;4096;4096;32768;52379`\n\nconst mockVolumeSpace = `measurement;servername;type;C:;D: (DATA);L: (LOG)\nVolume total space (bytes);WIN8-DEV;OS Volume space;135338651648.00;32075874304.00;10701701120.00\nVolume available space (bytes);WIN8-DEV;OS Volume space;54297817088.00;28439674880.00;10107355136.00\nVolume used space (bytes);WIN8-DEV;OS Volume space;81040834560.00;3636199424.00;594345984.00\nVolume used space (%);WIN8-DEV;OS Volume space;60.00;11.00;6.00`\n\nconst mockPerformanceCounters = `measurement;servername;type;value\nAU cleanup batches/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nAU cleanups/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nBy-reference Lob Create Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nBy-reference Lob Use Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nCount Lob Readahead | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nCount Pull In Row | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nCount Push Off Row | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nDeferred dropped AUs | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nDeferred Dropped rowsets | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nDropped rowset cleanups/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nDropped rowsets skipped/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nExtent Deallocations/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nExtents Allocated/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;2\nFailed AU cleanup batches/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nFailed leaf page cookie | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nFailed tree page cookie | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nForwarded Records/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nFreeSpace Page Fetches/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nFreeSpace Scans/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nFull Scans/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nIndex Searches/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;1208\nInSysXact waits/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nLobHandle Create Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nLobHandle Destroy Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nLobSS Provider Create Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nLobSS Provider Destroy Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nLobSS Provider Truncation Count | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nMixed page allocations/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;10\nPage compression attempts/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nPage Deallocations/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nPage Splits/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;20\nPages Allocated/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;22\nPages compressed/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nProbe Scans/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;6\nRange Scans/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;45\nScan Point Revalidations/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nSkipped Ghosted Records/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nTable Lock Escalations/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nUsed leaf page cookie | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nUsed tree page cookie | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nWorkfiles Created/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;8\nWorktables Created/sec | SQLServer:Access Methods;WIN8-DEV;Performance counters;2\nWorktables From Cache Base | SQLServer:Access Methods;WIN8-DEV;Performance counters;0\nWorktables From Cache Ratio | SQLServer:Access Methods;WIN8-DEV;Performance counters;1\nBytes Received from Replica/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nBytes Sent to Replica/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nBytes Sent to Transport/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nFlow Control Time (ms/sec) | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nFlow Control/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nReceives from Replica/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nResent Messages/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nSends to Replica/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nSends to Transport/sec | _Total | SQLServer:Availability Replica;WIN8-DEV;Performance counters;0\nBatches >=000000ms & <000001ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;369\nBatches >=000000ms & <000001ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000000ms & <000001ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;370\nBatches >=000000ms & <000001ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000001ms & <000002ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;24\nBatches >=000001ms & <000002ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;24\nBatches >=000001ms & <000002ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;16\nBatches >=000001ms & <000002ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;16\nBatches >=000002ms & <000005ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;10\nBatches >=000002ms & <000005ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;30\nBatches >=000002ms & <000005ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;8\nBatches >=000002ms & <000005ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;23\nBatches >=000005ms & <000010ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;30\nBatches >=000005ms & <000010ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;211\nBatches >=000005ms & <000010ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;21\nBatches >=000005ms & <000010ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;148\nBatches >=000010ms & <000020ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;30\nBatches >=000010ms & <000020ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;432\nBatches >=000010ms & <000020ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;21\nBatches >=000010ms & <000020ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;305\nBatches >=000020ms & <000050ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;46\nBatches >=000020ms & <000050ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1545\nBatches >=000020ms & <000050ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;37\nBatches >=000020ms & <000050ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1261\nBatches >=000050ms & <000100ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;35\nBatches >=000050ms & <000100ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;2463\nBatches >=000050ms & <000100ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;18\nBatches >=000050ms & <000100ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1343\nBatches >=000100ms & <000200ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1\nBatches >=000100ms & <000200ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;161\nBatches >=000100ms & <000200ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;3\nBatches >=000100ms & <000200ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;373\nBatches >=000200ms & <000500ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000200ms & <000500ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000200ms & <000500ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1\nBatches >=000200ms & <000500ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;255\nBatches >=000500ms & <001000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000500ms & <001000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=000500ms & <001000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;2\nBatches >=000500ms & <001000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1291\nBatches >=001000ms & <002000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=001000ms & <002000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=001000ms & <002000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;19\nBatches >=001000ms & <002000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;21560\nBatches >=002000ms & <005000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=002000ms & <005000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=002000ms & <005000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;1\nBatches >=002000ms & <005000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;2257\nBatches >=005000ms & <010000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=005000ms & <010000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=005000ms & <010000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;19\nBatches >=005000ms & <010000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;97479\nBatches >=010000ms & <020000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=010000ms & <020000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=010000ms & <020000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=010000ms & <020000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=020000ms & <050000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=020000ms & <050000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=020000ms & <050000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=020000ms & <050000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=050000ms & <100000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=050000ms & <100000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=050000ms & <100000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=050000ms & <100000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=100000ms | CPU Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=100000ms | CPU Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=100000ms | Elapsed Time:Requests | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nBatches >=100000ms | Elapsed Time:Total(ms) | SQLServer:Batch Resp Statistics;WIN8-DEV;Performance counters;0\nStored Procedures Invoked/sec | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;0\nTask Limit Reached | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;3\nTask Limit Reached/sec | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;0\nTasks Aborted/sec | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;0\nTasks Running | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;0\nTasks Started/sec | _Total | SQLServer:Broker Activation;WIN8-DEV;Performance counters;0\nActivation Errors Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nBroker Transaction Rollbacks | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nCorrupted Messages Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nDequeued TransmissionQ Msgs/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nDialog Timer Event Count | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nDropped Messages Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Local Messages Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Local Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Messages Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P1 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P10 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P2 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P3 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P4 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P5 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P6 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P7 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P8 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued P9 Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued TransmissionQ Msgs/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Transport Msg Frag Tot | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Transport Msg Frags/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Transport Msgs Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nEnqueued Transport Msgs/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Messages Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Messages/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Msg Byte Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Msg Bytes/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Msg Discarded Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Msgs Discarded/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Pending Msg Bytes | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nForwarded Pending Msg Count | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nSQL RECEIVE Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nSQL RECEIVEs/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nSQL SEND Total | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nSQL SENDs/sec | SQLServer:Broker Statistics;WIN8-DEV;Performance counters;0\nAvg. Length of Batched Writes | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;0\nAvg. Length of Batched Writes BS | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;1\nAvg. Time Between Batches (ms) | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;2062\nAvg. Time Between Batches Base | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;1\nAvg. Time to Write Batch (ms) | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;0\nAvg. Time to Write Batch Base | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;1\nTransmission Obj Gets/Sec | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;0\nTransmission Obj Set Dirty/Sec | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;0\nTransmission Obj Writes/Sec | SQLServer:Broker TO Statistics;WIN8-DEV;Performance counters;0\nCurrent Bytes for Recv I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nCurrent Bytes for Send I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nCurrent Msg Frags for Send I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P1 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P10 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P2 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P3 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P4 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P5 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P6 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P7 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P8 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment P9 Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment Receives/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMessage Fragment Sends/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMsg Fragment Recv Size Avg | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMsg Fragment Recv Size Avg Base | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMsg Fragment Send Size Avg | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nMsg Fragment Send Size Avg Base | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nOpen Connection Count | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nPending Bytes for Recv I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nPending Bytes for Send I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nPending Msg Frags for Recv I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nPending Msg Frags for Send I/O | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nReceive I/O bytes/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nReceive I/O Len Avg | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nReceive I/O Len Avg Base | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nReceive I/Os/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nRecv I/O Buffer Copies bytes/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nRecv I/O Buffer Copies Count | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nSend I/O bytes/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nSend I/O Len Avg | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nSend I/O Len Avg Base | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nSend I/Os/sec | SQLServer:Broker/DBM Transport;WIN8-DEV;Performance counters;0\nBackground writer pages/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nBuffer cache hit ratio | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;1\nBuffer cache hit ratio base | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;2448\nCheckpoint pages/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nDatabase pages | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;6676\nExtension allocated pages | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension free pages | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension in use as percentage | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension outstanding IO counter | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension page evictions/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension page reads/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension page unreferenced time | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nExtension page writes/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nFree list stalls/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nIntegral Controller Slope | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;10\nLazy writes/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nPage life expectancy | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;29730\nPage lookups/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;2534\nPage reads/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nPage writes/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nReadahead pages/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nReadahead time/sec | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;0\nTarget pages | SQLServer:Buffer Manager;WIN8-DEV;Performance counters;16367616\nDatabase pages | 000 | SQLServer:Buffer Node;WIN8-DEV;Performance counters;6676\nLocal node page lookups/sec | 000 | SQLServer:Buffer Node;WIN8-DEV;Performance counters;0\nPage life expectancy | 000 | SQLServer:Buffer Node;WIN8-DEV;Performance counters;29730\nRemote node page lookups/sec | 000 | SQLServer:Buffer Node;WIN8-DEV;Performance counters;0\nCache Entries Count | _Total | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;2428\nCache Entries Count | mssqlsystemresource | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;2204\nCache Entries Pinned Count | _Total | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;0\nCache Entries Pinned Count | mssqlsystemresource | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;0\nCache Hit Ratio | _Total | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;1\nCache Hit Ratio | mssqlsystemresource | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;1\nCache Hit Ratio Base | _Total | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;71\nCache Hit Ratio Base | mssqlsystemresource | SQLServer:Catalog Metadata;WIN8-DEV;Performance counters;30\nCLR Execution | SQLServer:CLR;WIN8-DEV;Performance counters;327033\nActive cursors | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nActive cursors | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nActive cursors | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nActive cursors | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCached Cursor Counts | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCached Cursor Counts | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCached Cursor Counts | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCached Cursor Counts | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Cache Use Counts/sec | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Cache Use Counts/sec | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Cache Use Counts/sec | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Cache Use Counts/sec | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor memory usage | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor memory usage | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor memory usage | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor memory usage | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Requests/sec | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Requests/sec | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Requests/sec | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor Requests/sec | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor worktable usage | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor worktable usage | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor worktable usage | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nCursor worktable usage | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nNumber of active cursor plans | _Total | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nNumber of active cursor plans | API Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nNumber of active cursor plans | TSQL Global Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nNumber of active cursor plans | TSQL Local Cursor | SQLServer:Cursor Manager by Type;WIN8-DEV;Performance counters;0\nAsync population count | SQLServer:Cursor Manager Total;WIN8-DEV;Performance counters;0\nCursor conversion rate | SQLServer:Cursor Manager Total;WIN8-DEV;Performance counters;0\nCursor flushes | SQLServer:Cursor Manager Total;WIN8-DEV;Performance counters;0\nFile Bytes Received/sec | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nLog Bytes Received/sec | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nLog remaining for undo | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nLog Send Queue | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nMirrored Write Transactions/sec | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nRecovery Queue | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nRedo blocked/sec | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nRedo Bytes Remaining | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nRedone Bytes/sec | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nTotal Log requiring undo | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nTransaction Delay | _Total | SQLServer:Database Replica;WIN8-DEV;Performance counters;0\nActive Transactions | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nActive Transactions | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBackup/Restore Throughput/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBackup/Restore Throughput/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBulk Copy Rows/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBulk Copy Rows/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBulk Copy Throughput/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nBulk Copy Throughput/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nCommit table entries | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nCommit table entries | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nData File(s) Size (KB) | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;3512576\nData File(s) Size (KB) | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;40960\nDBCC Logical Scan Bytes/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nDBCC Logical Scan Bytes/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nGroup Commit Time/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nGroup Commit Time/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Bytes Flushed/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;307200\nLog Bytes Flushed/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Hit Ratio | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Hit Ratio | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Hit Ratio Base | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Hit Ratio Base | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Reads/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Cache Reads/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog File(s) Size (KB) | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;570992\nLog File(s) Size (KB) | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;1016\nLog File(s) Used Size (KB) | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;315480\nLog File(s) Used Size (KB) | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;634\nLog Flush Wait Time | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Flush Wait Time | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Flush Waits/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Flush Waits/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Flush Write Time (ms) | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;1\nLog Flush Write Time (ms) | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Flushes/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;5\nLog Flushes/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Growths | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Growths | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Cache Misses/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Cache Misses/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Disk Reads/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Disk Reads/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Requests/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Pool Requests/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Shrinks | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Shrinks | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nLog Truncations | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;5\nLog Truncations | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nPercent Log Used | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;55\nPercent Log Used | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;62\nRepl. Pending Xacts | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nRepl. Pending Xacts | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nRepl. Trans. Rate | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nRepl. Trans. Rate | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nShrink Data Movement Bytes/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nShrink Data Movement Bytes/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nTracked transactions/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nTracked transactions/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nTransactions/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;6\nTransactions/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nWrite Transactions/sec | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;3\nWrite Transactions/sec | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nXTP Memory Used (KB) | _Total | SQLServer:Databases;WIN8-DEV;Performance counters;0\nXTP Memory Used (KB) | mssqlsystemresource | SQLServer:Databases;WIN8-DEV;Performance counters;0\nUsage | '#' and '##' as the name of temporary tables and stored procedures | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | '::' function calling syntax | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | '@' and names that start with '@@' as Transact-SQL identifiers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | ADDING TAPE DEVICE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | ALL Permission | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | ALTER DATABASE WITH TORN_PAGE_DETECTION | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | ALTER LOGIN WITH SET CREDENTIAL | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | asymmetric_keys | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | asymmetric_keys.attested_by | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Azeri_Cyrillic_90 | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Azeri_Latin_90 | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | BACKUP DATABASE or LOG TO TAPE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | certificates | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | certificates.attested_by | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Create/alter SOAP endpoint | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | CREATE_DROP_DEFAULT | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | CREATE_DROP_RULE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Data types: text ntext or image | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Database compatibility level 100 | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Database compatibility level 110 | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;4\nUsage | Database compatibility level 90 | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Database Mirroring | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DATABASEPROPERTY | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DATABASEPROPERTYEX('IsFullTextEnabled') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC [UN]PINTABLE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC DBREINDEX | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC INDEXDEFRAG | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC SHOWCONTIG | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC_EXTENTINFO | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DBCC_IND | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DEFAULT keyword as a default value | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Deprecated Attested Option | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Deprecated encryption algorithm | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DESX algorithm | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.is_paused | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.previous_status | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.previous_status_description | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.row_count_in_thousands | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.status | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.status_description | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_active_catalogs.worker_count | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_memory_buffers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | dm_fts_memory_buffers.row_count | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | DROP INDEX with two-part name | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | endpoint_webmethods | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | EXTPROP_LEVEL0TYPE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | EXTPROP_LEVEL0USER | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FILE_ID | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_get_sql | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_servershareddrives | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_trace_geteventinfo | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_trace_getfilterinfo | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_trace_getinfo | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_trace_gettable | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fn_virtualservernodes | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fulltext_catalogs | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fulltext_catalogs.data_space_id | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fulltext_catalogs.file_id | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | fulltext_catalogs.path | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FULLTEXTCATALOGPROPERTY('LogSize') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FULLTEXTCATALOGPROPERTY('PopulateStatus') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FULLTEXTSERVICEPROPERTY('ConnectTimeout') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FULLTEXTSERVICEPROPERTY('DataTimeout') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | FULLTEXTSERVICEPROPERTY('ResourceUsage') | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | GROUP BY ALL | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Hindi | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | IDENTITYCOL | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | IN PATH | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Index view select list without COUNT_BIG(*) | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | INDEX_OPTION | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | INDEXKEY_PROPERTY | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Indirect TVF hints | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | INSERT NULL into TIMESTAMP columns | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | INSERT_HINTS | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Korean_Wansung_Unicode | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Lithuanian_Classic | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Macedonian | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | MODIFY FILEGROUP READONLY | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | MODIFY FILEGROUP READWRITE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | More than two-part column name | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Multiple table hints without comma | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | NOLOCK or READUNCOMMITTED in UPDATE or DELETE | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Numbered stored procedures | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | numbered_procedure_parameters | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | numbered_procedures | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | objidupdate | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Old NEAR Syntax | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | OLEDB for ad hoc connections | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | PERMISSIONS | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | READTEXT | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | REMSERVER | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | RESTORE DATABASE or LOG WITH MEDIAPASSWORD | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | RESTORE DATABASE or LOG WITH PASSWORD | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Returning results from trigger | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | ROWGUIDCOL | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET ANSI_NULLS OFF | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET ANSI_PADDING OFF | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET CONCAT_NULL_YIELDS_NULL OFF | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET ERRLVL | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET FMTONLY ON | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET OFFSETS | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET REMOTE_PROC_TRANSACTIONS | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SET ROWCOUNT | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SETUSER | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | soap_endpoints | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addapprole | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addextendedproc | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addlogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addremotelogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addrole | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addrolemember | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addserver | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addsrvrolemember | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_addtype | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_adduser | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_approlepassword | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_attach_db | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_attach_single_file_db | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_bindefault | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_bindrule | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_bindsession | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_certify_removable | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_change_users_login | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_changedbowner | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_changeobjectowner | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'affinity mask' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'affinity64 mask' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'allow updates' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'c2 audit mode' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'default trace enabled' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'disallow results from triggers' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'ft crawl bandwidth (max)' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'ft crawl bandwidth (min)' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'ft notify bandwidth (max)' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'ft notify bandwidth (min)' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'locks' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'open objects' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'priority boost' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'remote proc trans' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_configure 'set working set size' | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_control_dbmasterkey_password | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_create_removable | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_db_increased_partitions | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_db_selective_xml_index | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_db_vardecimal_storage_format | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dbcmptlevel | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dbfixedrolepermission | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dbremove | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_defaultdb | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_defaultlanguage | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_denylogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_depends | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_detach_db @keepfulltextindexfile | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dropapprole | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dropextendedproc | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_droplogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dropremotelogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_droprole | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_droprolemember | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dropsrvrolemember | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_droptype | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_dropuser | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_estimated_rowsize_reduction_for_vardecimal | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_catalog | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_column | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_database | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_service @action=clean_up | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_service @action=connect_timeout | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_service @action=data_timeout | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_service @action=resource_usage | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_fulltext_table | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_getbindtoken | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_grantdbaccess | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_grantlogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_catalog_components | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_catalogs | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_catalogs_cursor | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_columns | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_columns_cursor | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_tables | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_help_fulltext_tables_cursor | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_helpdevice | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_helpextendedproc | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_helpremotelogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_indexoption | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_lock | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_password | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_remoteoption | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_renamedb | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_resetstatus | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_revokedbaccess | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_revokelogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_srvrolepermission | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_trace_create | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_trace_getdata | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_trace_setevent | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_trace_setfilter | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_trace_setstatus | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_unbindefault | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sp_unbindrule | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | SQL_AltDiction_CP1253_CS_AS | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sql_dependencies | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | String literals as column aliases | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysaltfiles | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syscacheobjects | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syscolumns | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syscomments | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysconfigures | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysconstraints | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syscurconfigs | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysdatabases | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysdepends | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysdevices | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysfilegroups | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysfiles | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysforeignkeys | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysfulltextcatalogs | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysindexes | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysindexkeys | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syslockinfo | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syslogins | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysmembers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysmessages | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysobjects | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysoledbusers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysopentapes | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysperfinfo | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | syspermissions | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysprocesses | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysprotects | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysreferences | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysremotelogins | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysservers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | systypes | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | sysusers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Table hint without WITH | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Text in row table option | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | TEXTPTR | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | TEXTVALID | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | TIMESTAMP | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | UPDATETEXT or WRITETEXT | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | USER_ID | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Using OLEDB for linked servers | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | Vardecimal storage format | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | XMLDATA | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | XP_API | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;3\nUsage | xp_grantlogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | xp_loginconfig | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nUsage | xp_revokelogin | SQLServer:Deprecated Features;WIN8-DEV;Performance counters;0\nDistributed Query | Average execution time (ms) | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDistributed Query | Cumulative execution time (ms) per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDistributed Query | Execs in progress | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDistributed Query | Execs started per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDTC calls | Average execution time (ms) | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDTC calls | Cumulative execution time (ms) per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDTC calls | Execs in progress | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nDTC calls | Execs started per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nExtended Procedures | Average execution time (ms) | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nExtended Procedures | Cumulative execution time (ms) per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nExtended Procedures | Execs in progress | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nExtended Procedures | Execs started per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nOLEDB calls | Average execution time (ms) | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nOLEDB calls | Cumulative execution time (ms) per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nOLEDB calls | Execs in progress | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nOLEDB calls | Execs started per second | SQLServer:Exec Statistics;WIN8-DEV;Performance counters;0\nAvg time delete FileTable item | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time FileTable enumeration | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time FileTable handle kill | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time move FileTable item | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time per file I/O request | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time per file I/O response | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time rename FileTable item | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time to get FileTable item | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nAvg time update FileTable item | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable db operations/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable enumeration reqs/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable file I/O requests/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable file I/O response/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable item delete reqs/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable item get requests/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable item move reqs/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable item rename reqs/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable item update reqs/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable kill handle ops/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nFileTable table operations/sec | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime delete FileTable item BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime FileTable enumeration BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime FileTable handle kill BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime move FileTable item BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime per file I/O request BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime per file I/O response BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime rename FileTable item BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime to get FileTable item BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nTime update FileTable item BASE | SQLServer:FileTable;WIN8-DEV;Performance counters;0\nActive Temp Tables | SQLServer:General Statistics;WIN8-DEV;Performance counters;2\nConnection Reset/sec | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nEvent Notifications Delayed Drop | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nHTTP Authenticated Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nLogical Connections | SQLServer:General Statistics;WIN8-DEV;Performance counters;2\nLogins/sec | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nLogouts/sec | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nMars Deadlocks | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nNon-atomic yield rate | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nProcesses blocked | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP Empty Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP Method Invocations | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP Session Initiate Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP Session Terminate Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP SQL Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSOAP WSDL Requests | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nSQL Trace IO Provider Lock Waits | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nTemp Tables Creation Rate | SQLServer:General Statistics;WIN8-DEV;Performance counters;1\nTemp Tables For Destruction | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nTempdb recovery unit id | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nTempdb rowset id | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nTrace Event Notification Queue | SQLServer:General Statistics;WIN8-DEV;Performance counters;0\nTransactions | SQLServer:General Statistics;WIN8-DEV;Performance counters;1\nUser Connections | SQLServer:General Statistics;WIN8-DEV;Performance counters;2\nAvg. Bytes/Read | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. Bytes/Read BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. Bytes/Transfer | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. Bytes/Transfer BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. Bytes/Write | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. Bytes/Write BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Read | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Read BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Transfer | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Transfer BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Write | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAvg. microsec/Write BASE | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nHTTP Storage IO retry/sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nOutstanding HTTP Storage IO | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nRead Bytes/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nReads/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nTotal Bytes/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nTransfers/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nWrite Bytes/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nWrites/Sec | _Total | SQLServer:HTTP Storage;WIN8-DEV;Performance counters;0\nAverage Latch Wait Time (ms) | SQLServer:Latches;WIN8-DEV;Performance counters;0\nAverage Latch Wait Time Base | SQLServer:Latches;WIN8-DEV;Performance counters;0\nLatch Waits/sec | SQLServer:Latches;WIN8-DEV;Performance counters;0\nNumber of SuperLatches | SQLServer:Latches;WIN8-DEV;Performance counters;0\nSuperLatch Demotions/sec | SQLServer:Latches;WIN8-DEV;Performance counters;0\nSuperLatch Promotions/sec | SQLServer:Latches;WIN8-DEV;Performance counters;0\nTotal Latch Wait Time (ms) | SQLServer:Latches;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time (ms) | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nAverage Wait Time Base | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Requests/sec | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;381\nLock Requests/sec | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Requests/sec | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Requests/sec | Database | SQLServer:Locks;WIN8-DEV;Performance counters;27\nLock Requests/sec | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;23\nLock Requests/sec | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Requests/sec | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;1\nLock Requests/sec | Key | SQLServer:Locks;WIN8-DEV;Performance counters;133\nLock Requests/sec | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;71\nLock Requests/sec | Object | SQLServer:Locks;WIN8-DEV;Performance counters;93\nLock Requests/sec | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Requests/sec | Page | SQLServer:Locks;WIN8-DEV;Performance counters;25\nLock Requests/sec | RID | SQLServer:Locks;WIN8-DEV;Performance counters;8\nLock Requests/sec | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts (timeout > 0)/sec | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Timeouts/sec | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Wait Time (ms) | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nLock Waits/sec | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | _Total | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | AllocUnit | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Application | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Database | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Extent | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | File | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | HoBT | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Key | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Metadata | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Object | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | OIB | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | Page | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | RID | SQLServer:Locks;WIN8-DEV;Performance counters;0\nNumber of Deadlocks/sec | RowGroup | SQLServer:Locks;WIN8-DEV;Performance counters;0\nInternal benefit | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nInternal benefit | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nMemory broker clerk size | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;6676\nMemory broker clerk size | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;4\nPeriodic evictions (pages) | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nPeriodic evictions (pages) | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nPressure evictions (pages/sec) | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nPressure evictions (pages/sec) | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nSimulation benefit | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nSimulation benefit | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nSimulation size | Buffer Pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nSimulation size | Column store object pool | SQLServer:Memory Broker Clerks;WIN8-DEV;Performance counters;0\nConnection Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;1192\nDatabase Cache Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;53408\nExternal benefit of memory | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nFree Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;6552\nGranted Workspace Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nLock Blocks | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nLock Blocks Allocated | SQLServer:Memory Manager;WIN8-DEV;Performance counters;3050\nLock Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;768\nLock Owner Blocks | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nLock Owner Blocks Allocated | SQLServer:Memory Manager;WIN8-DEV;Performance counters;5550\nLog Pool Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;1296\nMaximum Workspace Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;1154160\nMemory Grants Outstanding | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nMemory Grants Pending | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nOptimizer Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;984\nReserved Server Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;0\nSQL Cache Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;2088\nStolen Server Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;173608\nTarget Server Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;1536000\nTotal Server Memory (KB) | SQLServer:Memory Manager;WIN8-DEV;Performance counters;233568\nDatabase Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;53408\nForeign Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;0\nFree Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;6552\nStolen Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;173592\nTarget Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;1535976\nTotal Node Memory (KB) | 000 | SQLServer:Memory Node;WIN8-DEV;Performance counters;233552\nCache Hit Ratio | _Total | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Hit Ratio | Bound Trees | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Hit Ratio | Extended Stored Procedures | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Hit Ratio | Object Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Hit Ratio | SQL Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Hit Ratio | Temporary Tables & Table Variables | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | _Total | SQLServer:Plan Cache;WIN8-DEV;Performance counters;6\nCache Hit Ratio Base | Bound Trees | SQLServer:Plan Cache;WIN8-DEV;Performance counters;6\nCache Hit Ratio Base | Extended Stored Procedures | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | Object Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | SQL Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Hit Ratio Base | Temporary Tables & Table Variables | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Object Counts | _Total | SQLServer:Plan Cache;WIN8-DEV;Performance counters;230\nCache Object Counts | Bound Trees | SQLServer:Plan Cache;WIN8-DEV;Performance counters;90\nCache Object Counts | Extended Stored Procedures | SQLServer:Plan Cache;WIN8-DEV;Performance counters;4\nCache Object Counts | Object Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;2\nCache Object Counts | SQL Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;134\nCache Object Counts | Temporary Tables & Table Variables | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Objects in use | _Total | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Objects in use | Bound Trees | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Objects in use | Extended Stored Procedures | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Objects in use | Object Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Objects in use | SQL Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1\nCache Objects in use | Temporary Tables & Table Variables | SQLServer:Plan Cache;WIN8-DEV;Performance counters;0\nCache Pages | _Total | SQLServer:Plan Cache;WIN8-DEV;Performance counters;5759\nCache Pages | Bound Trees | SQLServer:Plan Cache;WIN8-DEV;Performance counters;1055\nCache Pages | Extended Stored Procedures | SQLServer:Plan Cache;WIN8-DEV;Performance counters;6\nCache Pages | Object Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;50\nCache Pages | SQL Plans | SQLServer:Plan Cache;WIN8-DEV;Performance counters;4646\nCache Pages | Temporary Tables & Table Variables | SQLServer:Plan Cache;WIN8-DEV;Performance counters;2\nActive memory grant amount (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nActive memory grant amount (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nActive memory grants count | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nActive memory grants count | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Read IO (ms) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Read IO (ms) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Read IO (ms) Base | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Read IO (ms) Base | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Write IO (ms) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Write IO (ms) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Write IO (ms) Base | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nAvg Disk Write IO (ms) Base | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCache memory target (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1231200\nCache memory target (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1231200\nCompile memory target (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1231200\nCompile memory target (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1231200\nCPU control effect % | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;7\nCPU control effect % | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCPU usage % | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCPU usage % | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCPU usage % base | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCPU usage % base | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nCPU usage target % | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;7\nCPU usage target % | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read Bytes/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read Bytes/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read IO Throttled/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read IO Throttled/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read IO/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Read IO/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write Bytes/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write Bytes/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write IO Throttled/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write IO Throttled/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write IO/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nDisk Write IO/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nMax memory (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1459200\nMax memory (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1459200\nMemory grant timeouts/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nMemory grant timeouts/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nMemory grants/sec | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1\nMemory grants/sec | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nPending memory grants count | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nPending memory grants count | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;0\nQuery exec memory target (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1154160\nQuery exec memory target (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1154160\nTarget memory (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1459200\nTarget memory (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;1459200\nUsed memory (KB) | default | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;52624\nUsed memory (KB) | internal | SQLServer:Resource Pool Stats;WIN8-DEV;Performance counters;120976\nErrors/sec | _Total | SQLServer:SQL Errors;WIN8-DEV;Performance counters;0\nErrors/sec | DB Offline Errors | SQLServer:SQL Errors;WIN8-DEV;Performance counters;0\nErrors/sec | Info Errors | SQLServer:SQL Errors;WIN8-DEV;Performance counters;0\nErrors/sec | Kill Connection Errors | SQLServer:SQL Errors;WIN8-DEV;Performance counters;0\nErrors/sec | User Errors | SQLServer:SQL Errors;WIN8-DEV;Performance counters;0\nAuto-Param Attempts/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nBatch Requests/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nFailed Auto-Params/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nForced Parameterizations/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nGuided plan executions/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nMisguided plan executions/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nSafe Auto-Params/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nSQL Attention rate | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nSQL Compilations/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;1\nSQL Re-Compilations/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;1\nUnsafe Auto-Params/sec | SQLServer:SQL Statistics;WIN8-DEV;Performance counters;0\nFree Space in tempdb (KB) | SQLServer:Transactions;WIN8-DEV;Performance counters;1045504\nLongest Transaction Running Time | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nNonSnapshot Version Transactions | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nSnapshot Transactions | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nTransactions | SQLServer:Transactions;WIN8-DEV;Performance counters;14\nUpdate conflict ratio | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nUpdate conflict ratio base | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nUpdate Snapshot Transactions | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nVersion Cleanup rate (KB/s) | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nVersion Generation rate (KB/s) | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nVersion Store Size (KB) | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nVersion Store unit count | SQLServer:Transactions;WIN8-DEV;Performance counters;2\nVersion Store unit creation | SQLServer:Transactions;WIN8-DEV;Performance counters;2\nVersion Store unit truncation | SQLServer:Transactions;WIN8-DEV;Performance counters;0\nQuery | User counter 1 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 10 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 2 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 3 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 4 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 5 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 6 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 7 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 8 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nQuery | User counter 9 | SQLServer:User Settable;WIN8-DEV;Performance counters;0\nLock waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLock waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLock waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLock waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog buffer waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog buffer waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog buffer waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog buffer waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog write waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog write waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog write waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nLog write waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nMemory grant queue waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nMemory grant queue waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nMemory grant queue waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nMemory grant queue waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNetwork IO waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNetwork IO waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNetwork IO waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNetwork IO waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNon-Page latch waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNon-Page latch waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNon-Page latch waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nNon-Page latch waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage IO latch waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage IO latch waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage IO latch waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage IO latch waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage latch waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage latch waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage latch waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nPage latch waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nThread-safe memory objects waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nThread-safe memory objects waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nThread-safe memory objects waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nThread-safe memory objects waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nTransaction ownership waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nTransaction ownership waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nTransaction ownership waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nTransaction ownership waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWait for the worker | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWait for the worker | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWait for the worker | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWait for the worker | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWorkspace synchronization waits | Average wait time (ms) | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWorkspace synchronization waits | Cumulative wait time (ms) per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWorkspace synchronization waits | Waits in progress | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nWorkspace synchronization waits | Waits started per second | SQLServer:Wait Statistics;WIN8-DEV;Performance counters;0\nActive parallel threads | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nActive parallel threads | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nActive requests | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;1\nActive requests | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nBlocked tasks | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nBlocked tasks | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nCPU usage % | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nCPU usage % | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nCPU usage % base | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nCPU usage % base | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nMax request cpu time (ms) | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;161\nMax request cpu time (ms) | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nMax request memory grant (KB) | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;9816\nMax request memory grant (KB) | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nQuery optimizations/sec | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;1\nQuery optimizations/sec | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nQueued requests | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nQueued requests | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nReduced memory grants/sec | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nReduced memory grants/sec | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nRequests completed/sec | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nRequests completed/sec | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nSuboptimal plans/sec | default | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nSuboptimal plans/sec | internal | SQLServer:Workload Group Stats;WIN8-DEV;Performance counters;0\nCursor deletes/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nCursor inserts/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nCursor scans started/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nCursor unique violations/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nCursor updates/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nCursor write conflicts/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nDusty corner scan retries/sec (user-issued) | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nExpired rows removed/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nExpired rows touched/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nRows returned/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nRows touched/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nTentatively-deleted rows touched/sec | MSSQLSERVER | XTP Cursors;WIN8-DEV;Performance counters;0\nDusty corner scan retries/sec (GC-issued) | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nMain GC work items/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nParallel GC work item/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nRows processed/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nRows processed/sec (first in bucket and removed) | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nRows processed/sec (first in bucket) | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nRows processed/sec (marked for unlink) | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nRows processed/sec (no sweep needed) | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nSweep expired rows removed/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nSweep expired rows touched/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nSweep expiring rows touched/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nSweep rows touched/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nSweep scans started/sec | MSSQLSERVER | XTP Garbage Collection;WIN8-DEV;Performance counters;0\nDusty corner scan retries/sec (Phantom-issued) | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nPhantom expired rows removed/sec | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nPhantom expired rows touched/sec | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nPhantom expiring rows touched/sec | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nPhantom rows touched/sec | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nPhantom scans started/sec | MSSQLSERVER | XTP Phantom Processor;WIN8-DEV;Performance counters;0\nCheckpoints Closed | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nCheckpoints Completed | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nCore Merges Completed | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nMerge Policy Evaluations | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nMerge Requests Outstanding | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nMerges Abandoned | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nMerges Installed | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nTotal Files Merged | MSSQLSERVER | XTP Storage;WIN8-DEV;Performance counters;0\nLog bytes written/sec | MSSQLSERVER | XTP Transaction Log;WIN8-DEV;Performance counters;0\nLog records written/sec | MSSQLSERVER | XTP Transaction Log;WIN8-DEV;Performance counters;0\nCascading aborts/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nCommit dependencies taken/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nRead-only transactions prepared/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nSave point refreshes/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nSave point rollbacks/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nSave points created/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nTransaction validation failures/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nTransactions aborted by user/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nTransactions aborted/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0\nTransactions created/sec | MSSQLSERVER | XTP Transactions;WIN8-DEV;Performance counters;0`\n"
  },
  {
    "path": "plugins/inputs/stackdriver/README.md",
    "content": "# Stackdriver Google Cloud Monitoring Input Plugin\n\nThis plugin collects metrics from [Google Cloud Monitoring][gcm]\n(formerly Stackdriver) using the [Cloud Monitoring API v3][stackdriver].\n\n> [!IMPORTANT]\n> This plugin accesses APIs which are [chargeable][pricing], cost might incur.\n\n⭐ Telegraf v1.10.0\n🏷️ cloud\n💻 all\n\n[gcm]: https://cloud.google.com/monitoring\n[stackdriver]: https://cloud.google.com/monitoring/api/v3/\n[pricing]: https://cloud.google.com/stackdriver/pricing#stackdriver_monitoring_services\n\n## Global configuration options <!-- @/docs/includes/plugin_config.md -->\n\nPlugins support additional global and plugin configuration settings for tasks\nsuch as modifying metrics, tags, and fields, creating aliases, and configuring\nplugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.\n\n[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins\n\n## Configuration\n\n```toml @sample.conf\n# Gather timeseries from Google Cloud Platform v3 monitoring API\n[[inputs.stackdriver]]\n  ## GCP Project\n  project = \"erudite-bloom-151019\"\n\n  ## Include timeseries that start with the given metric type.\n  metric_type_prefix_include = [\n    \"compute.googleapis.com/\",\n  ]\n\n  ## Exclude timeseries that start with the given metric type.\n  # metric_type_prefix_exclude = []\n\n  ## Most metrics are updated no more than once per minute; it is recommended\n  ## to override the agent level interval with a value of 1m or greater.\n  interval = \"1m\"\n\n  ## Maximum number of API calls to make per second.  The quota for accounts\n  ## varies, it can be viewed on the API dashboard:\n  ##   https://cloud.google.com/monitoring/quotas#quotas_and_limits\n  # rate_limit = 14\n\n  ## The delay and window options control the number of points selected on\n  ## each gather.  When set, metrics are gathered between:\n  ##   start: now() - delay - window\n  ##   end:   now() - delay\n  #\n  ## Collection delay; if set too low metrics may not yet be available.\n  # delay = \"5m\"\n  #\n  ## If unset, the window will start at 1m and be updated dynamically to span\n  ## the time between calls (approximately the length of the plugin interval).\n  # window = \"1m\"\n\n  ## TTL for cached list of metric types.  This is the maximum amount of time\n  ## it may take to discover new metrics.\n  # cache_ttl = \"1h\"\n\n  ## If true, raw bucket counts are collected for distribution value types.\n  ## For a more lightweight collection, you may wish to disable and use\n  ## distribution_aggregation_aligners instead.\n  # gather_raw_distribution_buckets = true\n\n  ## Aggregate functions to be used for metrics whose value type is\n  ## distribution.  These aggregate values are recorded in in addition to raw\n  ## bucket counts; if they are enabled.\n  ##\n  ## For a list of aligner strings see:\n  ##   https://cloud.google.com/monitoring/api/ref_v3/rpc/google.monitoring.v3#aligner\n  # distribution_aggregation_aligners = [\n  #  \"ALIGN_PERCENTILE_99\",\n  #  \"ALIGN_PERCENTILE_95\",\n  #  \"ALIGN_PERCENTILE_50\",\n  # ]\n\n  ## Filters can be added to reduce the number of time series matched.  All\n  ## functions are supported: starts_with, ends_with, has_substring, and\n  ## one_of.  Only the '=' operator is supported.\n  ##\n  ## The logical operators when combining filters are defined statically using\n  ## the following values:\n  ##   filter ::= <resource_labels> {AND <metric_labels> AND <user_labels> AND <system_labels>}\n  ##   resource_labels ::= <resource_labels> {OR <resource_label>}\n  ##   metric_labels ::= <metric_labels> {OR <metric_label>}\n  ##   user_labels ::= <user_labels> {OR <user_label>}\n  ##   system_labels ::= <system_labels> {OR <system_label>}\n  ##\n  ## For more details, see https://cloud.google.com/monitoring/api/v3/filters\n  #\n  ## Resource labels refine the time series selection with the following expression:\n  ##   resource.labels.<key> = <value>\n  # [[inputs.stackdriver.filter.resource_labels]]\n  #   key = \"instance_name\"\n  #   value = 'starts_with(\"localhost\")'\n  #\n  ## Metric labels refine the time series selection with the following expression:\n  ##   metric.labels.<key> = <value>\n  #  [[inputs.stackdriver.filter.metric_labels]]\n  #    key = \"device_name\"\n  #    value = 'one_of(\"sda\", \"sdb\")'\n  #\n  ## User labels refine the time series selection with the following expression:\n  ##   metadata.user_labels.\"<key>\" = <value>\n  #  [[inputs.stackdriver.filter.user_labels]]\n  #    key = \"environment\"\n  #    value = 'one_of(\"prod\", \"staging\")'\n  #\n  ## System labels refine the time series selection with the following expression:\n  ##   metadata.system_labels.\"<key>\" = <value>\n  #  [[inputs.stackdriver.filter.system_labels]]\n  #    key = \"machine_type\"\n  #    value = 'starts_with(\"e2-\")'\n```\n\n### Authentication\n\nIt is recommended to use a service account to authenticate with the\nStackdriver Monitoring API.  [Getting Started with Authentication][auth].\n\n[auth]: https://cloud.google.com/docs/authentication/getting-started\n\n## Troubleshooting\n\nWhen Telegraf is ran with `--debug`, detailed information about the performed\nqueries will be logged.\n\n## Metrics\n\nMetrics are created using one of there patterns depending on if the value type\nis a scalar value, raw distribution buckets, or aligned bucket values.\n\nIn all cases, the Stackdriver metric type is split on the last component into\nthe measurement and field:\n\n```sh\ncompute.googleapis.com/instance/disk/read_bytes_count\n└──────────  measurement  ─────────┘ └──  field  ───┘\n```\n\n### Scalar Values\n\n- measurement\n  - tags:\n    - resource_labels\n    - metric_labels\n  - fields:\n    - field\n\n### Distributions\n\nDistributions are represented by a set of fields along with the bucket values\ntagged with the bucket boundary.  Buckets are cumulative: each bucket\nrepresents the total number of items less than the `lt` tag.\n\n- measurement\n  - tags:\n    - resource_labels\n    - metric_labels\n  - fields:\n    - field_count\n    - field_mean\n    - field_sum_of_squared_deviation\n    - field_range_min\n    - field_range_max\n\n- measurement\n  - tags:\n    - resource_labels\n    - metric_labels\n    - lt (less than)\n  - fields:\n    - field_bucket\n\n### Aligned Aggregations\n\n- measurement\n  - tags:\n    - resource_labels\n    - metric_labels\n  - fields:\n    - field_alignment_function\n\n## Example Output\n\nThe output depends on the defined filters and metric types.\n"
  },
  {
    "path": "plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/uevent",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/cache/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/dataset/zpool.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/zpool.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/freenas/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/unavailable/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/zdataset.txt",
    "content": ""
  },
  {
    "path": "plugins/outputs/heartbeat/testdata/telegraf.conf",
    "content": ""
  },
  {
    "path": "plugins/outputs/heartbeat/testdata/telegraf.d/inputs.conf",
    "content": ""
  },
  {
    "path": "plugins/outputs/heartbeat/testdata/telegraf.d/outputs.conf",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/bad-timestamp-format/expected.out",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/bad-timestamp-format/message.avro",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/config-both/expected.out",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/config-both/message.avro",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/config-neither/expected.out",
    "content": ""
  },
  {
    "path": "plugins/parsers/avro/testcases/config-neither/message.avro",
    "content": ""
  },
  {
    "path": "plugins/parsers/json_v2/testdata/optional/expected.out",
    "content": ""
  },
  {
    "path": "plugins/parsers/json_v2/testdata/wrong_path/expected.out",
    "content": ""
  },
  {
    "path": "plugins/parsers/parquet/testcases/empty/expected.out",
    "content": ""
  }
]